From 3b3ba999046e246cfd570e5399adea2f82df9312 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 3 Oct 2023 09:10:22 +0200 Subject: [PATCH 0001/7721] arm64: dts: qcom: sm8550: add TRNG node Add the Qualcomm True Random Number Generator node. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Acked-by: Vinod Koul Link: https://lore.kernel.org/r/20231003-topic-sm8550-rng-v4-4-255e4d0ba08e@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 7b9ddde0b2c9..7bafb3d88d69 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -1677,6 +1677,11 @@ mmss_noc: interconnect@1780000 { qcom,bcm-voters = <&apps_bcm_voter>; }; + rng: rng@10c3000 { + compatible = "qcom,sm8550-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + pcie0: pci@1c00000 { device_type = "pci"; compatible = "qcom,pcie-sm8550"; From c2c9fa136253daf6b3e25c3ea4952d9f2c4da8cf Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 3 Oct 2023 09:10:23 +0200 Subject: [PATCH 0002/7721] arm64: dts: qcom: sm8450: add TRNG node The SM8450 SoC has a True Random Number Generator, add the node with the correct compatible set. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Acked-by: Vinod Koul Link: https://lore.kernel.org/r/20231003-topic-sm8550-rng-v4-5-255e4d0ba08e@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8450.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 1783fa78bdbc..bde9c1093384 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -1739,6 +1739,11 @@ spi14: spi@a98000 { }; }; + rng: rng@10c3000 { + compatible = "qcom,sm8450-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + pcie0: pci@1c00000 { compatible = "qcom,pcie-sm8450-pcie0"; reg = <0 0x01c00000 0 0x3000>, From 2d04f31103921b8c21756ff9eeba32e3ece1a276 Mon Sep 17 00:00:00 2001 From: Om Prakash Singh Date: Mon, 16 Oct 2023 01:09:00 +0530 Subject: [PATCH 0003/7721] arm64: dts: qcom: sa8775p: add TRNG node The sa8775p SoC has a True Random Number Generator, add the node with the correct compatible set. Signed-off-by: Om Prakash Singh Link: https://lore.kernel.org/r/20231015193901.2344590-4-quic_omprsing@quicinc.com [bjorn: Padded address to 8 digits, moved hunk to maintain sort order] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index b6a93b11cbbd..4fd7dcac0903 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1487,6 +1487,11 @@ &config_noc SLAVE_QUP_3 QCOM_ICC_TAG_ALWAYS>, }; }; + rng: rng@10d2000 { + compatible = "qcom,sa8775p-trng", "qcom,trng"; + reg = <0 0x010d2000 0 0x1000>; + }; + ufs_mem_hc: ufs@1d84000 { compatible = "qcom,sa8775p-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; From d9f33f465114b8d1ecbd5d0b5a4d5f7e709094d9 Mon Sep 17 00:00:00 2001 From: Om Prakash Singh Date: Mon, 16 Oct 2023 01:09:01 +0530 Subject: [PATCH 0004/7721] arm64: dts: qcom: sc7280: add TRNG node The sc7280 SoC has a True Random Number Generator, add the node with the correct compatible set. Signed-off-by: Om Prakash Singh Link: https://lore.kernel.org/r/20231015193901.2344590-5-quic_omprsing@quicinc.com [bjorn: Padded address to 8 digits, moved hunk to maintain sort order] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 66f1eb83cca7..3585fa3c9594 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2034,6 +2034,11 @@ uart15: serial@a9c000 { }; }; + rng: rng@10d3000 { + compatible = "qcom,sc7280-trng", "qcom,trng"; + reg = <0 0x010d3000 0 0x1000>; + }; + cnoc2: interconnect@1500000 { reg = <0 0x01500000 0 0x1000>; compatible = "qcom,sc7280-cnoc2"; From e7166f2774aafefd29ff26ffbbb7f6d40ac8ea1c Mon Sep 17 00:00:00 2001 From: Nitheesh Sekar Date: Mon, 4 Sep 2023 12:06:34 +0530 Subject: [PATCH 0005/7721] arm64: dts: qcom: ipq5018: Add USB related nodes Add USB phy and controller nodes. Co-developed-by: Amandeep Singh Signed-off-by: Amandeep Singh Signed-off-by: Nitheesh Sekar Link: https://lore.kernel.org/r/20230904063635.24975-4-quic_nsekar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 38ffdc3cbdcd..340b90cc17db 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -94,6 +94,19 @@ soc: soc@0 { #size-cells = <1>; ranges = <0 0 0 0xffffffff>; + usbphy0: phy@5b000 { + compatible = "qcom,ipq5018-usb-hsphy"; + reg = <0x0005b000 0x120>; + + clocks = <&gcc GCC_USB0_PHY_CFG_AHB_CLK>; + + resets = <&gcc GCC_QUSB2_0_PHY_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + tlmm: pinctrl@1000000 { compatible = "qcom,ipq5018-tlmm"; reg = <0x01000000 0x300000>; @@ -156,6 +169,47 @@ blsp1_uart1: serial@78af000 { status = "disabled"; }; + usb: usb@8af8800 { + compatible = "qcom,ipq5018-dwc3", "qcom,dwc3"; + reg = <0x08af8800 0x400>; + + interrupts = ; + interrupt-names = "hs_phy_irq"; + + clocks = <&gcc GCC_USB0_MASTER_CLK>, + <&gcc GCC_SYS_NOC_USB0_AXI_CLK>, + <&gcc GCC_USB0_SLEEP_CLK>, + <&gcc GCC_USB0_MOCK_UTMI_CLK>; + clock-names = "core", + "iface", + "sleep", + "mock_utmi"; + + resets = <&gcc GCC_USB0_BCR>; + + qcom,select-utmi-as-pipe-clk; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + status = "disabled"; + + usb_dwc: usb@8a00000 { + compatible = "snps,dwc3"; + reg = <0x08a00000 0xe000>; + clocks = <&gcc GCC_USB0_MOCK_UTMI_CLK>; + clock-names = "ref"; + interrupts = ; + phy-names = "usb2-phy"; + phys = <&usbphy0>; + tx-fifo-resize; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + }; + }; + intc: interrupt-controller@b000000 { compatible = "qcom,msm-qgic2"; reg = <0x0b000000 0x1000>, /* GICD */ From 80a438775aa398751229bcaed15459f3acdb645f Mon Sep 17 00:00:00 2001 From: Nitheesh Sekar Date: Mon, 4 Sep 2023 12:06:35 +0530 Subject: [PATCH 0006/7721] arm64: dts: qcom: ipq5018: Enable USB Enable USB2 in host mode. Reviewed-by: Dmitry Baryshkov Co-developed-by: Amandeep Singh Signed-off-by: Amandeep Singh Signed-off-by: Nitheesh Sekar Link: https://lore.kernel.org/r/20230904063635.24975-5-quic_nsekar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts index e636a1cb9b77..8460b538eb6a 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts +++ b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts @@ -67,6 +67,18 @@ data-pins { }; }; +&usb { + status = "okay"; +}; + +&usb_dwc { + dr_mode = "host"; +}; + +&usbphy0 { + status = "okay"; +}; + &xo_board_clk { clock-frequency = <24000000>; }; From 0e8527d076cfb3fa55777a2ece735852fcf3e850 Mon Sep 17 00:00:00 2001 From: Anusha Rao Date: Wed, 27 Sep 2023 12:13:18 +0530 Subject: [PATCH 0007/7721] arm64: dts: qcom: ipq9574: Add common RDP dtsi file Add a dtsi file to include interfaces that are common across RDPs. Signed-off-by: Anusha Rao Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20230927-common-rdp-v3-1-3d07b3ff6d42@quicinc.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/ipq9574-rdp-common.dtsi | 125 ++++++++++++++++++ arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts | 63 +-------- arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts | 91 +------------ arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts | 65 +-------- arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts | 65 +-------- arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts | 66 +-------- 6 files changed, 130 insertions(+), 345 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi new file mode 100644 index 000000000000..40a7aefd0540 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * IPQ9574 RDP board common device tree source + * + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include "ipq9574.dtsi" + +/ { + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + regulator_fixed_3p3: s3300 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-name = "fixed_3p3"; + }; + + regulator_fixed_0p925: s0925 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <925000>; + regulator-boot-on; + regulator-always-on; + regulator-name = "fixed_0p925"; + }; +}; + +&blsp1_spi0 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + + flash@0 { + compatible = "micron,n25q128a11", "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + }; +}; + +&blsp1_uart2 { + pinctrl-0 = <&uart2_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-mp5496-regulators"; + + ipq9574_s1: s1 { + /* + * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. + * During regulator registration, kernel not knowing the initial voltage, + * considers it as zero and brings up the regulators with minimum supported voltage. + * Update the regulator-min-microvolt with SVS voltage of 725mV so that + * the regulators are brought up with 725mV which is sufficient for all the + * corner parts to operate at 800MHz + */ + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1075000>; + }; + + mp5496_l2: l2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&tlmm { + spi_0_pins: spi-0-state { + pins = "gpio11", "gpio12", "gpio13", "gpio14"; + function = "blsp0_spi"; + drive-strength = <8>; + bias-disable; + }; +}; + +&usb_0_dwc3 { + dr_mode = "host"; +}; + +&usb_0_qmpphy { + vdda-pll-supply = <&mp5496_l2>; + vdda-phy-supply = <®ulator_fixed_0p925>; + + status = "okay"; +}; + +&usb_0_qusbphy { + vdd-supply = <®ulator_fixed_0p925>; + vdda-pll-supply = <&mp5496_l2>; + vdda-phy-dpdm-supply = <®ulator_fixed_3p3>; + + status = "okay"; +}; + +&usb3 { + status = "okay"; +}; + +&xo_board_clk { + clock-frequency = <24000000>; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts index 2b093e02637b..f4f9199d4ab1 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts @@ -8,58 +8,12 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C2"; compatible = "qcom,ipq9574-ap-al02-c2", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; }; &sdhc_1 { @@ -74,10 +28,6 @@ &sdhc_1 { status = "okay"; }; -&sleep_clk { - clock-frequency = <32000>; -}; - &tlmm { sdc_default_state: sdc-default-state { clk-pins { @@ -110,15 +60,4 @@ rclk-pins { bias-pull-down; }; }; - - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts index 877026ccc6e2..1bb8d96c9a82 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts @@ -8,69 +8,11 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C7"; compatible = "qcom,ipq9574-ap-al02-c7", "qcom,ipq9574"; - - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - regulator_fixed_3p3: s3300 { - compatible = "regulator-fixed"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - regulator-name = "fixed_3p3"; - }; - - regulator_fixed_0p925: s0925 { - compatible = "regulator-fixed"; - regulator-min-microvolt = <925000>; - regulator-max-microvolt = <925000>; - regulator-boot-on; - regulator-always-on; - regulator-name = "fixed_0p925"; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - - mp5496_l2: l2 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - regulator-boot-on; - }; - }; }; &sdhc_1 { @@ -85,10 +27,6 @@ &sdhc_1 { status = "okay"; }; -&sleep_clk { - clock-frequency = <32000>; -}; - &tlmm { sdc_default_state: sdc-default-state { clk-pins { @@ -122,30 +60,3 @@ rclk-pins { }; }; }; - -&usb_0_dwc3 { - dr_mode = "host"; -}; - -&usb_0_qmpphy { - vdda-pll-supply = <&mp5496_l2>; - vdda-phy-supply = <®ulator_fixed_0p925>; - - status = "okay"; -}; - -&usb_0_qusbphy { - vdd-supply = <®ulator_fixed_0p925>; - vdda-pll-supply = <&mp5496_l2>; - vdda-phy-dpdm-supply = <®ulator_fixed_3p3>; - - status = "okay"; -}; - -&usb3 { - status = "okay"; -}; - -&xo_board_clk { - clock-frequency = <24000000>; -}; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts index c8fa54e1a62c..d36d1078763e 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts @@ -8,73 +8,10 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C6"; compatible = "qcom,ipq9574-ap-al02-c6", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts index f01de6628c3b..c30c9fbedf26 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts @@ -8,73 +8,10 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C8"; compatible = "qcom,ipq9574-ap-al02-c8", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts index 6efae3426cb8..0dc382f5d5ec 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts @@ -8,73 +8,9 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C9"; compatible = "qcom,ipq9574-ap-al02-c9", "qcom,ipq9574"; - - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; From 0e2f2c506f01abcec412ccf91ed39ddfafbda60a Mon Sep 17 00:00:00 2001 From: Anusha Rao Date: Wed, 27 Sep 2023 12:13:19 +0530 Subject: [PATCH 0008/7721] arm64: dts: qcom: ipq9574: Enable WPS buttons Add support for wps buttons on GPIO 37. Reviewed-by: Konrad Dybcio Signed-off-by: Anusha Rao Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20230927-common-rdp-v3-2-3d07b3ff6d42@quicinc.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/ipq9574-rdp-common.dtsi | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi index 40a7aefd0540..49c9b6478357 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi @@ -8,6 +8,8 @@ /dts-v1/; +#include +#include #include "ipq9574.dtsi" / { @@ -36,6 +38,19 @@ regulator_fixed_0p925: s0925 { regulator-always-on; regulator-name = "fixed_0p925"; }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + button-wps { + label = "wps"; + linux,code = ; + gpios = <&tlmm 37 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; }; &blsp1_spi0 { @@ -95,6 +110,13 @@ spi_0_pins: spi-0-state { drive-strength = <8>; bias-disable; }; + + gpio_keys_default: gpio-keys-default-state { + pins = "gpio37"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; }; &usb_0_dwc3 { From 1529f6a43cc4feeb78f6063ae3ae7d8003594de6 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 27 Sep 2023 11:21:40 +0200 Subject: [PATCH 0009/7721] arm64: dts: qcom: sm6375: Add UART1 Add UART1 node, generally used for the Bluetooth module. Signed-off-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20230927-topic-6375_stuff-v1-1-12243e36b45c@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6375.dtsi | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi index e7ff55443da7..2fba0e7ea4e6 100644 --- a/arch/arm64/boot/dts/qcom/sm6375.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi @@ -896,6 +896,36 @@ qup_spi0_default: qup-spi0-default-state { drive-strength = <6>; bias-disable; }; + + qup_uart1_default: qup-uart1-default-state { + cts-pins { + pins = "gpio61"; + function = "qup01"; + drive-strength = <2>; + bias-pull-down; + }; + + rts-pins { + pins = "gpio62"; + function = "qup01"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio63"; + function = "qup01"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio64"; + function = "qup01"; + drive-strength = <2>; + bias-pull-up; + }; + }; }; gcc: clock-controller@1400000 { @@ -1111,6 +1141,19 @@ spi1: spi@4a84000 { status = "disabled"; }; + uart1: serial@4a84000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x04a84000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + power-domains = <&rpmpd SM6375_VDDCX>; + operating-points-v2 = <&qup_opp_table>; + pinctrl-0 = <&qup_uart1_default>; + pinctrl-names = "default"; + status = "disabled"; + }; + i2c2: i2c@4a88000 { compatible = "qcom,geni-i2c"; reg = <0x0 0x04a88000 0x0 0x4000>; From ea6b3c61559f647d183322fc5431f2a5e78123d3 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 27 Sep 2023 11:21:41 +0200 Subject: [PATCH 0010/7721] arm64: dts: qcom: sm6375-pdx225: Enable MSS Enable the 5G modem on the Sony Xperia 10 IV. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230927-topic-6375_stuff-v1-2-12243e36b45c@linaro.org Signed-off-by: Bjorn Andersson --- .../arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts index b2f1bb1d58e9..964fe86a18ef 100644 --- a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts +++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts @@ -187,6 +187,11 @@ &remoteproc_cdsp { status = "okay"; }; +&remoteproc_mss { + firmware-name = "qcom/sm6375/Sony/murray/modem.mbn"; + status = "okay"; +}; + &rpm_requests { regulators-0 { compatible = "qcom,rpm-pm6125-regulators"; From 6ffcd65f27d7d083b9bfae56c9b5fe1a0b7500f8 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 27 Sep 2023 11:21:42 +0200 Subject: [PATCH 0011/7721] arm64: dts: qcom: sm6375-pdx225: Enable ATH10K WiFi Enable the onboard QCA Wi-Fi. HW identifiers for reference: qmi chip_id 0x320 chip_family 0x4001 board_id 0xff soc_id 0x400e0000 Firmware sources: /vendor/firmware_mnt/image/wlanmdsp.bin -> qcom/.../wlanmdsp.mbn /vendor/firmware_mnt/image/bdwlan.bXX [1] -> [2] -> ath10k/.../board-2.bin [3] -> ath10k/.../firmware-5.bin Not sure where 3 comes from on the device itself, gotta investigate that.. According to [4], it's called WCN3990_STRAIT. Enable it and tighten the relevant regulators. [1] XX = board_id printed when the file is missing or by your downstream kernel firmware loader in the dmesg; if XX=ff, use bdwlan.bin [2] https://github.com/jhugo/linux/blob/5.5rc2_wifi/README [3] https://github.com/kvalo/ath10k-firmware/blob/master/WCN3990/hw1.0/HL3.1/WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1/firmware-5.bin [4] https://git.codelinaro.org/clo/la/platform/vendor/qcom-opensource/wlan/qca-wifi-host-cmn/-/blob/LA.VENDOR.1.0.r1-20700-WAIPIO.QSSI13.0/hif/src/hif_hw_version.h#L55 Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230927-topic-6375_stuff-v1-3-12243e36b45c@linaro.org Signed-off-by: Bjorn Andersson --- .../qcom/sm6375-sony-xperia-murray-pdx225.dts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts index 964fe86a18ef..bbec7aee60be 100644 --- a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts +++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts @@ -311,7 +311,7 @@ pm6125_l20: l20 { pm6125_l21: l21 { regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3400000>; + regulator-max-microvolt = <3312000>; }; pm6125_l22: l22 { @@ -322,7 +322,7 @@ pm6125_l22: l22 { pm6125_l23: l23 { regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3400000>; + regulator-max-microvolt = <3312000>; }; pm6125_l24: l24 { @@ -345,8 +345,8 @@ pmr735a_l1: l1 { }; pmr735a_l2: l2 { - regulator-min-microvolt = <352000>; - regulator-max-microvolt = <796000>; + regulator-min-microvolt = <640000>; + regulator-max-microvolt = <640000>; }; pmr735a_l3: l3 { @@ -433,6 +433,15 @@ &usb_1_hsphy { status = "okay"; }; +&wifi { + vdd-0.8-cx-mx-supply = <&pmr735a_l2>; + vdd-1.8-xo-supply = <&pm6125_l16>; + vdd-1.3-rfa-supply = <&pm6125_l2>; + vdd-3.3-ch0-supply = <&pm6125_l23>; + vdd-3.3-ch1-supply = <&pm6125_l21>; + status = "okay"; +}; + &xo_board_clk { clock-frequency = <19200000>; }; From 2ea7de2f804432dd17bcfa97576f0ccf2054cd6e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 27 Sep 2023 11:21:43 +0200 Subject: [PATCH 0012/7721] arm64: dts: qcom: sm6375-pdx225: Add USBPHY regulators To make dtbs_check happy and the software more aware of what's going on, describe the HSUSB PHY's regulators and tighten up VDDA_PLL to match. Signed-off-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20230927-topic-6375_stuff-v1-4-12243e36b45c@linaro.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts index bbec7aee60be..0ce4fa8de8b0 100644 --- a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts +++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts @@ -243,8 +243,8 @@ pm6125_l6: l6 { }; pm6125_l7: l7 { - regulator-min-microvolt = <720000>; - regulator-max-microvolt = <1050000>; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; }; pm6125_l8: l8 { @@ -430,6 +430,9 @@ &usb_1_dwc3 { }; &usb_1_hsphy { + vdda-pll-supply = <&pm6125_l7>; + vdda18-supply = <&pm6125_l10>; + vdda33-supply = <&pmr735a_l7>; status = "okay"; }; From 2278b16f12a9cc33b95a980e05d4d8f3f8e0abfa Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 29 Sep 2023 14:51:22 +0200 Subject: [PATCH 0013/7721] arm64: dts: qcom: sc7280: Add ports subnodes in usb/dp qmpphy node Add the USB3+DP Combo QMP PHY port subnodes to facilitate the description of the connection between the hardware blocks. Put it in the SoC DTSI to avoid duplication in the device DTs. Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20230929-sc7280-qmpphy-ports-v2-1-aae7e9c286b0@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 3585fa3c9594..871beba2ffcc 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3404,6 +3404,32 @@ usb_1_qmpphy: phy@88e8000 { #clock-cells = <1>; #phy-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + }; + }; + }; }; usb_2: usb@8cf8800 { From f19a9a341d6faaf8d04bb6d9fb1f6a367ca0ed3a Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Fri, 29 Sep 2023 11:18:05 +0530 Subject: [PATCH 0014/7721] arm64: dts: qcom: sa8775p: Add RPMh sleep stats Add device node for sleep stats driver which provides various low power mode stats. Tested-by: Andrew Halaney Signed-off-by: Raghavendra Kakarla Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230929054805.27847-1-quic_rkakarla@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index 4fd7dcac0903..d55fc1cd4fbd 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1925,6 +1925,11 @@ IPCC_MPROC_SIGNAL_GLINK_QMP #clock-cells = <0>; }; + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0 0x0c3f0000 0x0 0x400>; + }; + spmi_bus: spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x0c440000 0x0 0x1100>, From 4e7870360366b79f8a37ab0809895359105e5b78 Mon Sep 17 00:00:00 2001 From: Priyansh Jain Date: Tue, 26 Sep 2023 14:29:48 +0530 Subject: [PATCH 0015/7721] arm64: dts: qcom: Enable tsens and thermal for sa8775p SoC Add tsens and thermal devicetree node for sa8775p SoC. Signed-off-by: Priyansh Jain Link: https://lore.kernel.org/r/20230926085948.23046-3-quic_priyjain@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 1096 +++++++++++++++++++++++++ 1 file changed, 1096 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index d55fc1cd4fbd..13dd44dd9ed1 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1915,6 +1915,50 @@ pdc: interrupt-controller@b220000 { interrupt-controller; }; + tsens2: thermal-sensor@c251000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c251000 0x0 0x1ff>, + <0x0 0x0c224000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <13>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens3: thermal-sensor@c252000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c252000 0x0 0x1ff>, + <0x0 0x0c225000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <13>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens0: thermal-sensor@c263000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c263000 0x0 0x1ff>, + <0x0 0x0c222000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <12>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c265000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c265000 0x0 0x1ff>, + <0x0 0x0c223000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <12>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + aoss_qmp: power-management@c300000 { compatible = "qcom,sa8775p-aoss-qmp", "qcom,aoss-qmp"; reg = <0x0 0x0c300000 0x0 0x400>; @@ -2411,6 +2455,1058 @@ ethernet0: ethernet@23040000 { }; }; + thermal-zones { + aoss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + audio-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + pcie-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-4-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-5-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + pcie-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddrss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 12>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddrss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 12>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + }; + arch_timer: timer { compatible = "arm,armv8-timer"; interrupts = , From 27c2ca90e2f34cd3c4849af996e1a96a69e700d3 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Tue, 10 Oct 2023 11:46:58 +0100 Subject: [PATCH 0016/7721] arm64: dts: qcom: qrb4210-rb2: don't force usb peripheral mode The rb2 only has a single USB controller, it can be switched between a type-c port and an internal USB hub via a DIP switch. Until dynamic role switching is available it's preferable to put the USB controller in host mode so that the type-A ports and ethernet are available. Signed-off-by: Caleb Connolly Reviewed-by: Vladimir Zapolskiy Fixes: eaa53a85748d ("arm64: dts: qcom: qrb4210-rb2: Enable USB node") Reviewed-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20231010-caleb-rb2-host-mode-v1-1-b057d443cd62@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts index a7278a9472ed..9738c0dacd58 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -518,7 +518,6 @@ &usb { &usb_dwc3 { maximum-speed = "super-speed"; - dr_mode = "peripheral"; }; &usb_hsphy { From a1f42e08f0f04b72a6597f080db4bfbb3737910c Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 4 Oct 2023 21:12:30 +0200 Subject: [PATCH 0017/7721] arm64: dts: qcom: ipq5018: add QUP1 SPI controller Add the required BAM and QUP nodes for the QUP1 SPI controller on IPQ5018. Signed-off-by: Robert Marko Reviewed-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20231004191303.331055-1-robimarko@gmail.com [bjorn: Padded address to 8 digits, fixed node sort order] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 340b90cc17db..0b739077ed70 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -159,6 +159,16 @@ sdhc_1: mmc@7804000 { status = "disabled"; }; + blsp_dma: dma-controller@7884000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x07884000 0x1d000>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; + blsp1_uart1: serial@78af000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x078af000 0x200>; @@ -169,6 +179,20 @@ blsp1_uart1: serial@78af000 { status = "disabled"; }; + blsp1_spi1: spi@78b5000 { + compatible = "qcom,spi-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x078b5000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + dmas = <&blsp_dma 4>, <&blsp_dma 5>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + usb: usb@8af8800 { compatible = "qcom,ipq5018-dwc3", "qcom,dwc3"; reg = <0x08af8800 0x400>; From 00c86efb0f78319958b7bca3391c532016acf39c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Sep 2023 05:44:01 +0200 Subject: [PATCH 0018/7721] arm64: dts: qcom: sm8150: extend the size of the PDC resource Follow the example of other platforms and extend the PDC resource region to 0x30000, so that the PDC driver can read the PDC_VERSION register. Fixes: 397ad94668c1 ("arm64: dts: qcom: sm8150: Add pdc interrupt controller node") Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20230929-topic-sm8x50-upstream-pdc-ver-v5-2-800111572104@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index b7629f145fd1..97623af13464 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3939,7 +3939,7 @@ dispcc: clock-controller@af00000 { pdc: interrupt-controller@b220000 { compatible = "qcom,sm8150-pdc", "qcom,pdc"; - reg = <0 0x0b220000 0 0x400>; + reg = <0 0x0b220000 0 0x30000>; qcom,pdc-ranges = <0 480 94>, <94 609 31>, <125 63 1>; #interrupt-cells = <2>; From 032ff6a3b39addd54427844affaf21e1e80fabc2 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Wed, 16 Aug 2023 19:04:17 -0400 Subject: [PATCH 0019/7721] arm64: dts: qcom: sdm670: add specific cpufreq compatible The bindings for the CPU frequency scaling driver require a specific compatible for the SoC. Add the compatible. Fixes: 0c665213d126 ("arm64: dts: qcom: sdm670: add cpu frequency scaling") Signed-off-by: Richard Acayan Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230816230412.76862-9-mailingradian@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index ba2043d67370..6d9843d05cb3 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1532,7 +1532,7 @@ osm_l3: interconnect@17d41000 { }; cpufreq_hw: cpufreq@17d43000 { - compatible = "qcom,cpufreq-hw"; + compatible = "qcom,sdm670-cpufreq-hw", "qcom,cpufreq-hw"; reg = <0 0x17d43000 0 0x1400>, <0 0x17d45800 0 0x1400>; reg-names = "freq-domain0", "freq-domain1"; From 62073bc9f1ecc0d91fc260e7ae380cbadd33e9fc Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:37 +0530 Subject: [PATCH 0020/7721] arm64: dts: qcom: ipq5332: populate the opp table based on the eFuse IPQ53xx have different OPPs available for the CPU based on SoC variant. This can be determined through use of an eFuse register present in the silicon. Add support to read the eFuse and populate the OPPs based on it. ------------------------------------------------ Frequency BIT2 BIT1 opp-supported-hw 1.1GHz 1.5GHz ------------------------------------------------ 1100000000 1 1 0x7 1500000000 0 1 0x3 ------------------------------------------------ Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/463f01759cedef3121767d2432aa415794036ce1.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5332.dtsi | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi index d3fef2f80a81..5a71cfccb8e0 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi @@ -91,11 +91,19 @@ memory@40000000 { }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; opp-shared; + nvmem-cells = <&cpu_speed_bin>; - opp-1488000000 { - opp-hz = /bits/ 64 <1488000000>; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; }; @@ -163,6 +171,11 @@ qfprom: efuse@a4000 { reg = <0x000a4000 0x721>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@1d { + reg = <0x1d 0x2>; + bits = <7 2>; + }; }; rng: rng@e3000 { From b36074357baf2794c825ea1c145de1d22b15380b Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:39 +0530 Subject: [PATCH 0021/7721] arm64: dts: qcom: ipq9574: populate the opp table based on the eFuse IPQ95xx SoCs have different OPPs available for the CPU based on SoC variant. This can be determined from an eFuse register present in the silicon. Add support to read the eFuse and populate the OPPs based on it. Frequency 1.2GHz 1.8GHz 1.5GHz No opp-supported-hw Limit ------------------------------------------------------------ 936000000 1 1 1 1 0xf 1104000000 1 1 1 1 0xf 1200000000 1 1 1 1 0xf 1416000000 0 1 1 1 0x7 1488000000 0 1 1 1 0x7 1800000000 0 1 0 1 0x5 2208000000 0 0 0 1 0x1 ----------------------------------------------------------- Reviewed-by: Konrad Dybcio Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/14ab08b7cfd904433ca6065fac798d4f221c9d95.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq9574.dtsi | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index 8a72ad4afd03..d4b7e215fc92 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi @@ -106,42 +106,56 @@ memory@40000000 { }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; opp-shared; + nvmem-cells = <&cpu_speed_bin>; opp-936000000 { opp-hz = /bits/ 64 <936000000>; opp-microvolt = <725000>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1104000000 { opp-hz = /bits/ 64 <1104000000>; opp-microvolt = <787500>; + opp-supported-hw = <0xf>; + clock-latency-ns = <200000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <862500>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; opp-microvolt = <862500>; + opp-supported-hw = <0x7>; clock-latency-ns = <200000>; }; opp-1488000000 { opp-hz = /bits/ 64 <1488000000>; opp-microvolt = <925000>; + opp-supported-hw = <0x7>; clock-latency-ns = <200000>; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <987500>; + opp-supported-hw = <0x5>; clock-latency-ns = <200000>; }; opp-2208000000 { opp-hz = /bits/ 64 <2208000000>; opp-microvolt = <1062500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; }; @@ -223,6 +237,11 @@ qfprom: efuse@a4000 { reg = <0x000a4000 0x5a1>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@15 { + reg = <0x15 0x2>; + bits = <7 2>; + }; }; cryptobam: dma-controller@704000 { From 80ebe63329909531afc87335f1d95c7bf8414438 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:58 +0530 Subject: [PATCH 0022/7721] arm64: dts: qcom: ipq8074: include the GPLL0 as clock provider for mailbox While the kernel is booting up, APSS clock / CPU clock will be running at 800MHz with GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be configured to the rate based on the opp table and the source also will be changed to APSS_PLL_EARLY. So allow the mailbox to consume the GPLL0, with this inclusion, CPU Freq correctly reports that CPU is running at 800MHz rather than 24MHz. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-8-c8ceb1a37680@quicinc.com [bjorn: Updated commit message, as requested by Kathiravan] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 2f275c84e566..5d05819f356d 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -708,8 +708,8 @@ apcs_glb: mailbox@b111000 { compatible = "qcom,ipq8074-apcs-apps-global", "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; - clocks = <&a53pll>, <&xo>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #clock-cells = <1>; #mbox-cells = <1>; From 0133c7af3aa0420778d106cb90db708cfa45f2c6 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:59 +0530 Subject: [PATCH 0023/7721] arm64: dts: qcom: ipq6018: include the GPLL0 as clock provider for mailbox While the kernel is booting up, APSS clock / CPU clock will be running at 800MHz with GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be configured to the rate based on the opp table and the source also will be changed to APSS_PLL_EARLY. So allow the mailbox to consume the GPLL0, with this inclusion, CPU Freq correctly reports that CPU is running at 800MHz rather than 24MHz. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-9-c8ceb1a37680@quicinc.com [bjorn: Updated commit message, as requested by Kathiravan] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index e59b9df96c7e..9aec89d5e095 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -611,8 +611,8 @@ apcs_glb: mailbox@b111000 { compatible = "qcom,ipq6018-apcs-apps-global"; reg = <0x0 0x0b111000 0x0 0x1000>; #clock-cells = <1>; - clocks = <&a53pll>, <&xo>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; From 77c726a4f3b124903db5ced7d597976d5b80dcfb Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:30:00 +0530 Subject: [PATCH 0024/7721] arm64: dts: qcom: ipq9574: include the GPLL0 as clock provider for mailbox While the kernel is booting up, APSS clock / CPU clock will be running at 800MHz with GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be configured to the rate based on the opp table and the source also will be changed to APSS_PLL_EARLY. So allow the mailbox to consume the GPLL0, with this inclusion, CPU Freq correctly reports that CPU is running at 800MHz rather than 24MHz. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-10-c8ceb1a37680@quicinc.com [bjorn: Updated commit message, as requested by Kathiravan] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq9574.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index d4b7e215fc92..5f83ee42a719 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi @@ -671,8 +671,8 @@ apcs_glb: mailbox@b111000 { "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; #clock-cells = <1>; - clocks = <&a73pll>, <&xo_board_clk>; - clock-names = "pll", "xo"; + clocks = <&a73pll>, <&xo_board_clk>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; From da528016952bf93ca810c43fafe518c699db7fa0 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:30:01 +0530 Subject: [PATCH 0025/7721] arm64: dts: qcom: ipq5332: include the GPLL0 as clock provider for mailbox While the kernel is booting up, APSS clock / CPU clock will be running at 800MHz with GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be configured to the rate based on the opp table and the source also will be changed to APSS_PLL_EARLY. So allow the mailbox to consume the GPLL0, with this inclusion, CPU Freq correctly reports that CPU is running at 800MHz rather than 24MHz. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-11-c8ceb1a37680@quicinc.com [bjorn: Updated commit message, as requested by Kathiravan] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5332.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi index 5a71cfccb8e0..42e2e48b2bc3 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi @@ -403,8 +403,8 @@ apcs_glb: mailbox@b111000 { "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; #clock-cells = <1>; - clocks = <&a53pll>, <&xo_board>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo_board>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; From e87cef6a035edc03b4ac98f88121c706b2843156 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 21 Sep 2023 20:56:04 +0200 Subject: [PATCH 0026/7721] arm64: dts: qcom: msm8916-samsung-gt5: Enable GPU Enable the GPU for the msm8916-samsung-gt58 and gt510 tablets now that they have display panels enabled in the device tree. This was missed when the GPU was disabled by default because the change was not applied yet. Fixes: 0ce5bb825d54 ("arm64: dts: qcom: msm8916/39: Disable GPU by default") Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20230921-msm8916-rmem-fixups-v1-1-34d2b6e721cf@gerhold.net Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts | 4 ++++ arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts index 75c4854ecd64..c3f1acc55078 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts @@ -112,6 +112,10 @@ touchscreen@4a { }; }; +&gpu { + status = "okay"; +}; + &mdss { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts index 11359bcc27b3..998625abd409 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts @@ -64,6 +64,10 @@ touchscreen@20 { }; }; +&gpu { + status = "okay"; +}; + &mdss { status = "okay"; }; From d63ae4a814a763a5d2d4d078073562698693a909 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 21 Sep 2023 20:56:05 +0200 Subject: [PATCH 0027/7721] arm64: dts: qcom: msm8939-longcheer-l9100: Enable wcnss_mem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable &wcnss_mem for msm8939-longcheer-l9100. This is needed now to have WCNSS working. It was missed when &wcnss_mem was disabled by default because the patch with the msm8939-longcheer-l9100 device tree was not applied yet. Fixes: 0ece6438a8c0 ("arm64: dts: qcom: msm8916/39: Disable unneeded firmware reservations") Signed-off-by: Stephan Gerhold Reviewed-by: André Apitzsch Tested-by: André Apitzsch Link: https://lore.kernel.org/r/20230921-msm8916-rmem-fixups-v1-2-34d2b6e721cf@gerhold.net Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts index 6802714fda3f..a3357513037c 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts @@ -247,6 +247,10 @@ &wcnss_iris { compatible = "qcom,wcn3620"; }; +&wcnss_mem { + status = "okay"; +}; + &tlmm { button_backlight_default: button-backlight-default-state { pins = "gpio17"; From b364cc485da1b769f1ead705dcd853e87b42f96e Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 21 Sep 2023 20:56:06 +0200 Subject: [PATCH 0028/7721] arm64: dts: qcom: msm8916-*: Fix alphabetic node order Fix a couple of instances of incorrectly sorted nodes in the MSM8916 boards. They should be ordered alphabetically for consistency. No functional change. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20230921-msm8916-rmem-fixups-v1-3-34d2b6e721cf@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-alcatel-idol347.dts | 8 ++-- .../boot/dts/qcom/msm8916-samsung-a3u-eur.dts | 10 ++--- .../dts/qcom/msm8916-samsung-gt5-common.dtsi | 38 +++++++++---------- .../boot/dts/qcom/msm8916-thwc-uf896.dts | 8 ++-- .../boot/dts/qcom/msm8916-thwc-ufi001c.dts | 8 ++-- .../boot/dts/qcom/msm8916-yiming-uz801v3.dts | 8 ++-- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts index aa4c1ab1e673..fade93c55299 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts @@ -58,10 +58,6 @@ usb_id: usb-id { }; }; -&blsp_uart2 { - status = "okay"; -}; - &blsp_i2c4 { status = "okay"; @@ -153,6 +149,10 @@ led@1 { }; }; +&blsp_uart2 { + status = "okay"; +}; + &pm8916_resin { status = "okay"; linux,code = ; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts index f5a808369518..3b934f5eba47 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts @@ -49,11 +49,6 @@ reg_key_led: regulator-key-led { }; }; -&touchkey { - vcc-supply = <®_touch_key>; - vdd-supply = <®_key_led>; -}; - &accelerometer { mount-matrix = "0", "1", "0", "1", "0", "0", @@ -108,6 +103,11 @@ &mdss_dsi0_out { remote-endpoint = <&panel_in>; }; +&touchkey { + vcc-supply = <®_touch_key>; + vdd-supply = <®_key_led>; +}; + &vibrator { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi index c19cf20d7427..6a16eb5ce07b 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi @@ -65,25 +65,6 @@ hall-sensor-switch { }; }; -&blsp_i2c4 { - status = "okay"; - - fuelgauge@36 { - compatible = "maxim,max77849-battery"; - reg = <0x36>; - - maxim,rsns-microohm = <10000>; - maxim,over-heat-temp = <600>; - maxim,over-volt = <4400>; - - interrupt-parent = <&tlmm>; - interrupts = <121 IRQ_TYPE_EDGE_FALLING>; - - pinctrl-0 = <&fuelgauge_int_default>; - pinctrl-names = "default"; - }; -}; - &blsp_i2c2 { status = "okay"; @@ -112,6 +93,25 @@ accelerometer@1d { }; }; +&blsp_i2c4 { + status = "okay"; + + fuelgauge@36 { + compatible = "maxim,max77849-battery"; + reg = <0x36>; + + maxim,rsns-microohm = <10000>; + maxim,over-heat-temp = <600>; + maxim,over-volt = <4400>; + + interrupt-parent = <&tlmm>; + interrupts = <121 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 = <&fuelgauge_int_default>; + pinctrl-names = "default"; + }; +}; + &blsp_uart2 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts index 6fe1850ba20e..f34997500891 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts @@ -13,16 +13,16 @@ &button_restart { gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; }; -&led_r { - gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; }; &button_default { diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts index 16d4a91022be..6cb3911ba1c9 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts @@ -13,16 +13,16 @@ &button_restart { gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; }; -&led_r { - gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>; }; &mpss { diff --git a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts index 5e6ba8c58bb5..a98efcfe78b7 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts @@ -13,16 +13,16 @@ &button_restart { gpios = <&tlmm 23 GPIO_ACTIVE_LOW>; }; -&led_r { - gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; }; &button_default { From 0cd080dd6d08817c9980d2069197b066636b0f23 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 29 Sep 2023 18:02:57 +0200 Subject: [PATCH 0029/7721] arm64: dts: qcom: sc8280xp-x13s: Use the correct DP PHY compatible The DP PHY needs different settings when an eDP display is used. Make sure these apply on the X13s. FWIW I could not notice any user-facing change stemming from this commit. Fixes: f48c70b111b4 ("arm64: dts: qcom: sc8280xp-x13s: enable eDP display") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230929-topic-x13s_edpphy-v1-1-ce59f9eb4226@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index 38edaf51aa34..6a4c6cc19c09 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -601,6 +601,7 @@ mdss0_dp3_out: endpoint { }; &mdss0_dp3_phy { + compatible = "qcom,sc8280xp-edp-phy"; vdda-phy-supply = <&vreg_l6b>; vdda-pll-supply = <&vreg_l3b>; From 84b160876b4d8a97dc0feccc4426fefbc396d414 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Sun, 1 Oct 2023 18:19:03 +0100 Subject: [PATCH 0030/7721] arm64: dts: qcom: sdm845-oneplus: enable flash LED Both the 6 and 6T feature a dual tone flash, enable it. Signed-off-by: Caleb Connolly Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231001-b4-sdm845-flash-dts-v1-1-275a3abb0b10@linaro.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sdm845-oneplus-common.dtsi | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi index b523b5fff702..e821103d49c0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi @@ -8,6 +8,7 @@ /dts-v1/; #include +#include #include #include #include @@ -484,6 +485,28 @@ &pmi8998_charger { status = "okay"; }; +&pmi8998_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; +}; + &q6afedai { qi2s@22 { reg = <22>; From 7eedf7d6faaf0dd0807fff2ee595433faf08d138 Mon Sep 17 00:00:00 2001 From: Joel Selvaraj Date: Sun, 1 Oct 2023 18:19:04 +0100 Subject: [PATCH 0031/7721] arm64: dts: qcom: sdm845-xiaomi-beryllium: enable flash led Configure and enable the dual-tone on the PocoPhone F1 Signed-off-by: Joel Selvaraj Signed-off-by: Caleb Connolly Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231001-b4-sdm845-flash-dts-v1-2-275a3abb0b10@linaro.org Signed-off-by: Bjorn Andersson --- .../qcom/sdm845-xiaomi-beryllium-common.dtsi | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 93b1582e807d..617b17b2d7d9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi @@ -355,6 +355,28 @@ &pmi8998_charger { status = "okay"; }; +&pmi8998_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; +}; + &pm8998_resin { linux,code = ; status = "okay"; From 0c149ca7653286496130e872f47a4b834348ea10 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 2 Oct 2023 08:55:31 +0200 Subject: [PATCH 0032/7721] arm64: dts: qcom: sc7280: Add Camera Control Interface busses Add the CCI busses found on sc7280 and their pinctrl states. Reviewed-by: Bryan O'Donoghue Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231002-sc7280-cci-v2-2-9333fda4612a@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 136 +++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 871beba2ffcc..04bf85b0399a 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3824,6 +3824,86 @@ videocc: clock-controller@aaf0000 { #power-domain-cells = <1>; }; + cci0: cci@ac4a000 { + compatible = "qcom,sc7280-cci", "qcom,msm8996-cci"; + reg = <0 0x0ac4a000 0 0x1000>; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_0_CLK>, + <&camcc CAM_CC_CCI_0_CLK_SRC>; + clock-names = "camnoc_axi", + "slow_ahb_src", + "cpas_ahb", + "cci", + "cci_src"; + pinctrl-0 = <&cci0_default &cci1_default>; + pinctrl-1 = <&cci0_sleep &cci1_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci0_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci0_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + cci1: cci@ac4b000 { + compatible = "qcom,sc7280-cci", "qcom,msm8996-cci"; + reg = <0 0x0ac4b000 0 0x1000>; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_1_CLK>, + <&camcc CAM_CC_CCI_1_CLK_SRC>; + clock-names = "camnoc_axi", + "slow_ahb_src", + "cpas_ahb", + "cci", + "cci_src"; + pinctrl-0 = <&cci2_default &cci3_default>; + pinctrl-1 = <&cci2_sleep &cci3_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci1_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci1_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + camcc: clock-controller@ad00000 { compatible = "qcom,sc7280-camcc"; reg = <0 0x0ad00000 0 0x10000>; @@ -4329,6 +4409,62 @@ tlmm: pinctrl@f100000 { gpio-ranges = <&tlmm 0 0 175>; wakeup-parent = <&pdc>; + cci0_default: cci0-default-state { + pins = "gpio69", "gpio70"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci0_sleep: cci0-sleep-state { + pins = "gpio69", "gpio70"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci1_default: cci1-default-state { + pins = "gpio71", "gpio72"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci1_sleep: cci1-sleep-state { + pins = "gpio71", "gpio72"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci2_default: cci2-default-state { + pins = "gpio73", "gpio74"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci2_sleep: cci2-sleep-state { + pins = "gpio73", "gpio74"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci3_default: cci3-default-state { + pins = "gpio75", "gpio76"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci3_sleep: cci3-sleep-state { + pins = "gpio75", "gpio76"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + dp_hot_plug_det: dp-hot-plug-det-state { pins = "gpio47"; function = "dp_hot"; From 6cd8621758004d98f7c622c2d756c116c6888127 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 2 Oct 2023 09:00:12 +0200 Subject: [PATCH 0033/7721] arm64: dts: qcom: pm7250b: Use correct node name for gpios Use gpio@ instead of pinctrl@ as that's the name expected by the qcom,spmi-pmic.yaml schema. Update it to fix dt validation. Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231002-pm7250b-gpio-fixup-v2-2-debb8b599989@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pm7250b.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pm7250b.dtsi b/arch/arm64/boot/dts/qcom/pm7250b.dtsi index df0afe82f250..3bf7cf5d1700 100644 --- a/arch/arm64/boot/dts/qcom/pm7250b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm7250b.dtsi @@ -148,7 +148,7 @@ pm7250b_adc_tm: adc-tm@3500 { status = "disabled"; }; - pm7250b_gpios: pinctrl@c000 { + pm7250b_gpios: gpio@c000 { compatible = "qcom,pm7250b-gpio", "qcom,spmi-gpio"; reg = <0xc000>; gpio-controller; From a3457cc5bc30ad053c90ae9f14e9b7723d204a98 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 3 Oct 2023 11:36:47 +0200 Subject: [PATCH 0034/7721] arm64: dts: qcom: sc8280xp-x13s: add missing camera LED pin config Add the missing pin configuration for the recently added camera indicator LED. Fixes: 1c63dd1c5fda ("arm64: dts: qcom: sc8280xp-x13s: Add camera activity LED") Cc: Konrad Dybcio Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231003093647.3840-1-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index 6a4c6cc19c09..f2055899ae7a 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -82,6 +82,9 @@ switch-lid { leds { compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_indicator_en>; + led-camera-indicator { label = "white:camera-indicator"; function = LED_FUNCTION_INDICATOR; @@ -1278,6 +1281,13 @@ hstp-sw-ctrl-pins { }; }; + cam_indicator_en: cam-indicator-en-state { + pins = "gpio28"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + edp_reg_en: edp-reg-en-state { pins = "gpio25"; function = "gpio"; From 32f963412a2d8cb65ff2737e6763f88ed15a2efb Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Tue, 3 Oct 2023 15:18:19 +0200 Subject: [PATCH 0035/7721] arm64: dts: qcom: msm8939: Add BAM-DMUX WWAN BAM DMUX is used as the network interface to the modem. This is copied as-is from msm8916.dtsi. Signed-off-by: Vincent Knecht Reviewed-by: Konrad Dybcio Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-1-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8939.dtsi | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi index 324b5d26db40..65c68e0e88d5 100644 --- a/arch/arm64/boot/dts/qcom/msm8939.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi @@ -1537,6 +1537,20 @@ spmi_bus: spmi@200f000 { #interrupt-cells = <4>; }; + bam_dmux_dma: dma-controller@4044000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x04044000 0x19000>; + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; + + num-channels = <6>; + qcom,num-ees = <1>; + qcom,powered-remotely; + + status = "disabled"; + }; + mpss: remoteproc@4080000 { compatible = "qcom,msm8916-mss-pil"; reg = <0x04080000 0x100>, <0x04020000 0x040>; @@ -1569,6 +1583,22 @@ mpss: remoteproc@4080000 { qcom,halt-regs = <&tcsr 0x18000 0x19000 0x1a000>; status = "disabled"; + bam_dmux: bam-dmux { + compatible = "qcom,bam-dmux"; + + interrupt-parent = <&hexagon_smsm>; + interrupts = <1 IRQ_TYPE_EDGE_BOTH>, <11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "pc", "pc-ack"; + + qcom,smem-states = <&apps_smsm 1>, <&apps_smsm 11>; + qcom,smem-state-names = "pc", "pc-ack"; + + dmas = <&bam_dmux_dma 4>, <&bam_dmux_dma 5>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + mba { memory-region = <&mba_mem>; }; From 861aa8e6829cf2f1a9c5a52dd9cebc722cf7ca44 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:20 +0200 Subject: [PATCH 0036/7721] arm64: dts: qcom: msm8916: Add QDSP6 MSM8916 does not have a dedicated ADSP. Instead, the audio services via APR are also implemented by the modem DSP. Audio can be either routed via the modem DSP (necessary for voice call audio etc) or directly sent to the LPASS hardware (currently used by DB410c). Bypassing QDSP6 audio is only possible with special firmware (on DB410c) or when the modem DSP is completely disabled. Add the typical nodes for QDSP6 audio to msm8916.dtsi. The apr node is disabled by default to avoid changing behavior for devices like DB410c that use the bypassed audio path. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-2-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 4f799b536a92..e8a14dd7e7c2 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include / { @@ -1989,6 +1990,54 @@ smd-edge { label = "hexagon"; + apr: apr { + compatible = "qcom,apr-v2"; + qcom,smd-channels = "apr_audio_svc"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + q6core: service@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe: service@4 { + compatible = "qcom,q6afe"; + reg = ; + + q6afedai: dais { + compatible = "qcom,q6afe-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6asm: service@7 { + compatible = "qcom,q6asm"; + reg = ; + + q6asmdai: dais { + compatible = "qcom,q6asm-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6adm: service@8 { + compatible = "qcom,q6adm"; + reg = ; + + q6routing: routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; + }; + }; + fastrpc { compatible = "qcom,fastrpc"; qcom,smd-channels = "fastrpcsmd-apps-dsp"; From 0718ff7185cf42f8e817e39552feb9d6ed901aff Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:21 +0200 Subject: [PATCH 0037/7721] arm64: dts: qcom: msm8939: Add QDSP6 MSM8939 does not have a dedicated ADSP. Instead, the audio services via APR are also implemented by the modem DSP. Audio can be either routed via the modem DSP (necessary for voice call audio etc) or directly sent to the LPASS hardware (currently used by DB410c). Bypassing QDSP6 audio is only possible with special firmware (on DB410c) or when the modem DSP is completely disabled. Add the typical nodes for QDSP6 audio to msm8939.dtsi. The apr node is disabled by default to avoid changing behavior for devices like apq8039-t2 that use the bypassed audio path. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-3-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8939.dtsi | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi index 65c68e0e88d5..95610a32750a 100644 --- a/arch/arm64/boot/dts/qcom/msm8939.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include / { @@ -1615,6 +1616,54 @@ smd-edge { qcom,remote-pid = <1>; label = "hexagon"; + + apr: apr { + compatible = "qcom,apr-v2"; + qcom,smd-channels = "apr_audio_svc"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + q6core: service@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe: service@4 { + compatible = "qcom,q6afe"; + reg = ; + + q6afedai: dais { + compatible = "qcom,q6afe-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6asm: service@7 { + compatible = "qcom,q6asm"; + reg = ; + + q6asmdai: dais { + compatible = "qcom,q6asm-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6adm: service@8 { + compatible = "qcom,q6adm"; + reg = ; + + q6routing: routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; + }; + }; }; }; From 8abbd235b2ecbfba0a445ccd400a54af8fd83bc2 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:22 +0200 Subject: [PATCH 0038/7721] arm64: dts: qcom: msm8916: Add common msm8916-modem-qdsp6.dtsi Most MSM8916/MSM8939 devices use very similar setups for the modem, because most of the device-specific details are abstracted by the modem firmware. There are several definitions (status switches, DAI links etc) that will be exactly the same for every board. Introduce a common msm8916-modem-qdsp6.dtsi include that can be used to simplify enabling the modem for such devices. By default the digital/analog codec in the SoC/PMIC is used, but boards can define additional codecs by adding additional backend DAI links. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-4-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-modem-qdsp6.dtsi | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi b/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi new file mode 100644 index 000000000000..039961622633 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * msm8916-modem-qdsp6.dtsi describes the typical modem setup on MSM8916 devices + * (or similar SoCs) with audio routed via the QDSP6 services provided by the + * modem firmware. The digital/analog codec in the SoC/PMIC is used by default, + * but boards can define additional codecs by adding additional backend DAI links. + */ + +#include +#include + +&apr { + status = "okay"; +}; + +&bam_dmux { + status = "okay"; +}; + +&bam_dmux_dma { + status = "okay"; +}; + +&lpass { + status = "reserved"; /* Controlled by QDSP6 */ +}; + +&lpass_codec { + status = "okay"; +}; + +&mba_mem { + status = "okay"; +}; + +&mpss { + status = "okay"; +}; + +&mpss_mem { + status = "okay"; +}; + +&pm8916_codec { + status = "okay"; +}; + +&q6afedai { + dai@16 { + reg = ; + qcom,sd-lines = <0 1>; + }; + dai@20 { + reg = ; + qcom,sd-lines = <0 1>; + }; +}; + +&q6asmdai { + dai@0 { + reg = <0>; + direction = ; + }; + dai@1 { + reg = <1>; + direction = ; + }; + dai@2 { + reg = <2>; + direction = ; + }; + dai@3 { + reg = <3>; + direction = ; + is-compress-dai; + }; +}; + +&sound { + compatible = "qcom,msm8916-qdsp6-sndcard"; + model = "msm8916"; + + pinctrl-0 = <&cdc_pdm_default>; + pinctrl-1 = <&cdc_pdm_sleep>; + pinctrl-names = "default", "sleep"; + + status = "okay"; + + frontend0-dai-link { + link-name = "MultiMedia1"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + frontend1-dai-link { + link-name = "MultiMedia2"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>; + }; + }; + + frontend2-dai-link { + link-name = "MultiMedia3"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>; + }; + }; + + frontend3-dai-link { + link-name = "MultiMedia4"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA4>; + }; + }; + + sound_link_backend0: backend0-dai-link { + link-name = "Primary MI2S"; + + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&pm8916_codec 0>; + }; + }; + + sound_link_backend1: backend1-dai-link { + link-name = "Tertiary MI2S"; + + cpu { + sound-dai = <&q6afedai TERTIARY_MI2S_TX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&pm8916_codec 1>; + }; + }; +}; From f276411d0f8286c7ff3e1bd6917ea7ee61152d24 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:23 +0200 Subject: [PATCH 0039/7721] arm64: dts: qcom: msm8916-samsung-a2015: Add sound and modem Enable sound and modem for the Samsung A2015 based devices (A3, A5, E5, E7, Grand Max). The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - WWAN Internet via BAM-DMUX except: - NXP TFA9895 codec for speaker on Quaternary MI2S - Samsung-specific audio jack detection (not supported yet) [Lin: Add e2015 and grandmax] Co-developed-by: "Lin, Meng-Bo" Signed-off-by: "Lin, Meng-Bo" Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-5-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../qcom/msm8916-samsung-a2015-common.dtsi | 71 +++++++++++++++++++ .../qcom/msm8916-samsung-e2015-common.dtsi | 4 ++ .../dts/qcom/msm8916-samsung-grandmax.dts | 4 ++ 3 files changed, 79 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi index 0b29132b74e1..2937495940ea 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include #include +#include / { aliases { @@ -196,6 +199,18 @@ vibrator: vibrator { }; }; +&blsp_i2c1 { + status = "okay"; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; +}; + &blsp_i2c2 { status = "okay"; @@ -243,6 +258,25 @@ &gpu { status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + &mdss { status = "okay"; }; @@ -253,6 +287,10 @@ &mdss_dsi0 { pinctrl-1 = <&mdss_sleep>; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5400000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -265,6 +303,13 @@ pm8916_l17: l17 { }; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -279,6 +324,32 @@ &sdhc_2 { cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + model = "samsung-a2015"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { status = "okay"; extcon = <&muic>, <&muic>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi index 0824ab041d80..3c49dac92d2d 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi @@ -65,6 +65,10 @@ accelerometer@1d { }; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5a00000>; +}; + ®_motor_vdd { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts index 3f145dde4059..5882b3a593b8 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts @@ -49,6 +49,10 @@ ®_touch_key { status = "disabled"; }; +&sound { + model = "samsung-gmax"; /* No secondary microphone */ +}; + &tlmm { gpio_leds_default: gpio-led-default-state { pins = "gpio60"; From 6b66abd5858e025b2715b1efb193124dd7cc17c5 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:24 +0200 Subject: [PATCH 0040/7721] arm64: dts: qcom: msm8916-samsung-serranove: Add sound and modem Enable sound and modem for the Samsung S4 Mini Value Edition. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Speaker/earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - WWAN Internet via BAM-DMUX except: - Samsung-specific audio jack detection (not supported yet) Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-6-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-samsung-serranove.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts index 68da2a2d3077..5ce8f1350abc 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts @@ -6,6 +6,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -319,6 +321,10 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5a00000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -350,6 +356,13 @@ &sdhc_2 { no-1-8-v; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { status = "okay"; extcon = <&muic>, <&muic>; From 5db767ae36255c0301ede64ee8993e0909efa73f Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 3 Oct 2023 15:18:25 +0200 Subject: [PATCH 0041/7721] arm64: dts: qcom: msm8916-wingtech-wt88047: Add sound and modem Enable sound and modem for the Xiaomi Redmi 2. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - Audio jack detection via analog codec in PM8916 - WWAN Internet via BAM-DMUX except: - Speaker amplifier is connected to HPH_R (headphones) output of the analog codec. There is a separate analog switch that allows disabling playback via the headphone jack. Reviewed-by: Konrad Dybcio Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-7-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../dts/qcom/msm8916-wingtech-wt88047.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts index 419f35c1fc92..d4b88c787e59 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts @@ -6,6 +6,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -25,6 +27,28 @@ chosen { stdout-path = "serial0"; }; + speaker_amp: audio-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; + sound-name-prefix = "Speaker Amp"; + pinctrl-0 = <&speaker_amp_default>; + pinctrl-names = "default"; + }; + + /* + * This seems to be actually an analog switch that either routes audio + * to the headphone jack or nowhere. Given that we need to enable a GPIO + * to get sound on headphones, modelling it as simple-audio-amplifier + * works just fine. + */ + headphones_switch: audio-switch { + compatible = "simple-audio-amplifier"; + enable-gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; + sound-name-prefix = "Headphones Switch"; + pinctrl-0 = <&headphones_switch_default>; + pinctrl-names = "default"; + }; + flash-led-controller { compatible = "ocs,ocp8110"; enable-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; @@ -146,6 +170,18 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5100000>; +}; + +&pm8916_codec { + qcom,micbias1-ext-cap; + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -180,6 +216,30 @@ &sdhc_2 { non-removable; }; +&sound { + /* + * Provide widgets/pin-switches to allow enabling speaker and headphones + * separately. Both are routed via the HPH_L/HPH_R pins of the codec. + */ + model = "wt88047"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker", "Headphones"; + audio-routing = + "Speaker", "Speaker Amp OUTL", + "Speaker", "Speaker Amp OUTR", + "Speaker Amp INL", "HPH_R", + "Speaker Amp INR", "HPH_R", + "Headphones", "Headphones Switch OUTL", + "Headphones", "Headphones Switch OUTR", + "Headphones Switch INL", "HPH_L", + "Headphones Switch INR", "HPH_R", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2"; + aux-devs = <&speaker_amp>, <&headphones_switch>; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -226,6 +286,13 @@ gpio_keys_default: gpio-keys-default-state { bias-pull-up; }; + headphones_switch_default: headphones-switch-default-state { + pins = "gpio8"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + imu_default: imu-default-state { pins = "gpio115"; function = "gpio"; @@ -234,6 +301,13 @@ imu_default: imu-default-state { bias-disable; }; + speaker_amp_default: speaker-amp-default-state { + pins = "gpio117"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + touchscreen_default: touchscreen-default-state { touchscreen-pins { pins = "gpio13"; From 5d1cec28fd4d09e82e028903423829f59a033965 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Tue, 3 Oct 2023 15:18:26 +0200 Subject: [PATCH 0042/7721] arm64: dts: qcom: msm8916-alcatel-idol347: Add sound and modem Enable sound and modem for the Alcatel Idol 3 (4.7"). The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Microphones via digital/analog codec in MSM8916/PM8916 - WWAN Internet via BAM-DMUX except: - Stereo NXP TFA9890 codecs for speakers on Quaternary MI2S - These are also used as earpieces at the top/bottom. - Asahi Kasei AK4375 headphone codec on Secondary MI2S -> Primary MI2S is not used for playback Signed-off-by: Vincent Knecht [Stephan: Minor refactoring, add consistent commit message] Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-8-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-alcatel-idol347.dts | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts index fade93c55299..3459145516a1 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -22,6 +24,19 @@ chosen { stdout-path = "serial0"; }; + reserved-memory { + /delete-node/ reserved@86680000; + /delete-node/ rmtfs@86700000; + + rmtfs: rmtfs@86680000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0x86680000 0x0 0x160000>; + no-map; + + qcom,client-id = <1>; + }; + }; + gpio-keys { compatible = "gpio-keys"; @@ -50,6 +65,17 @@ led-0 { }; }; + reg_headphones_avdd: regulator-headphones-avdd { + compatible = "regulator-fixed"; + regulator-name = "headphones_avdd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&tlmm 121 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&headphones_avdd_default>; + pinctrl-names = "default"; + }; + usb_id: usb-id { compatible = "linux,extcon-usb-gpio"; id-gpios = <&tlmm 69 GPIO_ACTIVE_HIGH>; @@ -58,6 +84,43 @@ usb_id: usb-id { }; }; +&blsp_i2c3 { + status = "okay"; + + headphones: audio-codec@10 { + compatible = "asahi-kasei,ak4375"; + reg = <0x10>; + avdd-supply = <®_headphones_avdd>; + tvdd-supply = <&pm8916_l6>; + pdn-gpios = <&tlmm 114 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&headphones_pdn_default>; + pinctrl-names = "default"; + #sound-dai-cells = <0>; + }; + + speaker_codec_top: audio-codec@34 { + compatible = "nxp,tfa9897"; + reg = <0x34>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&speaker_top_default>; + pinctrl-names = "default"; + sound-name-prefix = "Speaker Top"; + #sound-dai-cells = <0>; + }; + + speaker_codec_bottom: audio-codec@36 { + compatible = "nxp,tfa9897"; + reg = <0x36>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&tlmm 111 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&speaker_bottom_default>; + pinctrl-names = "default"; + sound-name-prefix = "Speaker Bottom"; + #sound-dai-cells = <0>; + }; +}; + &blsp_i2c4 { status = "okay"; @@ -153,6 +216,18 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5000000>; +}; + +&pm8916_codec { + qcom,micbias1-ext-cap; + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -169,6 +244,17 @@ &pm8916_vib { status = "okay"; }; +&q6afedai { + dai@18 { + reg = ; + qcom,sd-lines = <0>; + }; + dai@22 { + reg = ; + qcom,sd-lines = <0>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -183,6 +269,54 @@ &sdhc_2 { cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + /* Add pin switches for speakers to allow disabling them individually */ + model = "alcatel-idol3"; + widgets = + "Speaker", "Speaker Top", + "Speaker", "Speaker Bottom"; + pin-switches = "Speaker Top", "Speaker Bottom"; + audio-routing = + "Speaker Top", "Speaker Top OUT", + "Speaker Bottom", "Speaker Bottom OUT", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &pri_mi2s_default &pri_mi2s_ws_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &pri_mi2s_sleep &pri_mi2s_ws_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec_top>, <&speaker_codec_bottom>; + }; + }; +}; + +&sound_link_backend0 { + /* Primary MI2S is not used, replace with Secondary MI2S for headphones */ + link-name = "Secondary MI2S"; + + cpu { + sound-dai = <&q6afedai SECONDARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&headphones>; + }; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -212,6 +346,15 @@ &wcnss_mem { status = "okay"; }; +/* Only some of the pins are used */ +&pri_mi2s_default { + pins = "gpio113", "gpio115"; +}; + +&pri_mi2s_sleep { + pins = "gpio113", "gpio115"; +}; + &tlmm { accel_int_default: accel-int-default-state { pins = "gpio31"; @@ -245,6 +388,20 @@ gyro_int_default: gyro-int-default-state { bias-disable; }; + headphones_avdd_default: headphones-avdd-default-state { + pins = "gpio121"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + headphones_pdn_default: headphones-pdn-default-state { + pins = "gpio114"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + /* * The OEM wired an additional GPIO to be asserted so that * the si-en,sn3190 LED IC works. Since this GPIO is not @@ -291,6 +448,20 @@ sdc2_cd_default: sdc2-cd-default-state { bias-disable; }; + speaker_bottom_default: speaker-bottom-default-state { + pins = "gpio111"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + speaker_top_default: speaker-top-default-state { + pins = "gpio50"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + ts_int_reset_default: ts-int-reset-default-state { pins = "gpio13", "gpio100"; function = "gpio"; From 462cdffaa83df28d5fbd0c1771eaa85954114c77 Mon Sep 17 00:00:00 2001 From: "J.R. Divya Antony" Date: Tue, 3 Oct 2023 15:18:27 +0200 Subject: [PATCH 0043/7721] arm64: dts: qcom: msm8916-asus-z00l: Add sound and modem Enable sound and modem for the ASUS Zenfone 2 Laser. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Speakear/earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - Audio jack detection via analog codec in PM8916 - WWAN Internet via BAM-DMUX Signed-off-by: "J.R. Divya Antony" [Stephan: rebase and simplify, add consistent commit message] Reviewed-by: Konrad Dybcio Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-9-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../arm64/boot/dts/qcom/msm8916-asus-z00l.dts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts index a8be6ff66893..77618c7374df 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -130,6 +132,18 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5500000>; +}; + +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + qcom,micbias1-ext-cap; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_rpm_regulators { pm8916_l17: l17 { regulator-min-microvolt = <2850000>; @@ -151,6 +165,13 @@ &sdhc_2 { cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; From 1ab407193d38c775261d7beccd080e88f68c7243 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Tue, 3 Oct 2023 15:18:28 +0200 Subject: [PATCH 0044/7721] arm64: dts: qcom: msm8916-longcheer-l8150: Add sound and modem Enable sound and modem for the Longcheer L8150 (e.g. Wileyfox Swift). The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Speaker/earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - Audio jack detection via analog codec in PM8916 - WWAN Internet via BAM-DMUX except: - The mpss firmware region must be relocated to a different address. This is because the wcnss firmware is not relocatable for some reason. The mpss firmware is too large to avoid overlap with wcnss when placed at the default address (0x86800000). Surprisingly the vendor kernel does not handle this. The firmware regions end up overlapping there and somehow this does not explode. We try to handle this more safely by relocating the mpss region to the first higher address that is working correctly: 0x8e800000. Signed-off-by: Nikita Travkin Co-developed-by: Stephan Gerhold Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-10-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-longcheer-l8150.dts | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts index 47d1c5cb13f4..37fa55166918 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -25,17 +27,26 @@ chosen { /* * For some reason, the signed wcnss firmware is not relocatable. - * It must be loaded at 0x8b600000. All other firmware is relocatable, - * so place wcnss at the fixed address and then all other firmware - * regions will be automatically allocated at a fitting place. + * It must be loaded at 0x8b600000. Unfortunately, this also means that + * mpss_mem does not fit when loaded to the typical address at 0x86800000. + * + * Load wcnss_mem to the fixed address and relocate mpss_mem to the next + * working higher address. For some reason the modem firmware does not + * boot when placed at 0x8a800000 to 0x8e800000. */ reserved-memory { + /delete-node/ mpss@86800000; /delete-node/ wcnss; wcnss_mem: wcnss@8b600000 { reg = <0x0 0x8b600000 0x0 0x600000>; no-map; }; + + mpss_mem: mpss@8e800000 { + reg = <0x0 0x8e800000 0x0 0x5000000>; + no-map; + }; }; gpio-keys { @@ -225,6 +236,13 @@ &blsp_uart2 { status = "okay"; }; +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -254,6 +272,13 @@ &sdhc_2 { non-removable; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; +}; + &usb { status = "okay"; dr_mode = "peripheral"; From 207f4ce365819ac68b634153d074252338d00ef6 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 27 Jun 2023 21:45:13 +0200 Subject: [PATCH 0045/7721] ARM: dts: qcom: msm8974: replace incorrect indentation in interconnect The clocks definition in the interconnect nodes should use tabs (+ 1 space) for indentation instead of 9 spaces. Fix that. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230627-msm8974-sort-v1-1-75c5800a2e09@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index 0bc2e66d15b1..6cb61ef57a4f 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -1107,7 +1107,7 @@ bimc: interconnect@fc380000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; + <&rpmcc RPM_SMD_BIMC_A_CLK>; }; snoc: interconnect@fc460000 { @@ -1116,7 +1116,7 @@ snoc: interconnect@fc460000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; + <&rpmcc RPM_SMD_SNOC_A_CLK>; }; pnoc: interconnect@fc468000 { @@ -1125,7 +1125,7 @@ pnoc: interconnect@fc468000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_PNOC_CLK>, - <&rpmcc RPM_SMD_PNOC_A_CLK>; + <&rpmcc RPM_SMD_PNOC_A_CLK>; }; ocmemnoc: interconnect@fc470000 { @@ -1134,7 +1134,7 @@ ocmemnoc: interconnect@fc470000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>, - <&rpmcc RPM_SMD_OCMEMGX_A_CLK>; + <&rpmcc RPM_SMD_OCMEMGX_A_CLK>; }; mmssnoc: interconnect@fc478000 { @@ -1143,7 +1143,7 @@ mmssnoc: interconnect@fc478000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&mmcc MMSS_S0_AXI_CLK>, - <&mmcc MMSS_S0_AXI_CLK>; + <&mmcc MMSS_S0_AXI_CLK>; }; cnoc: interconnect@fc480000 { @@ -1152,7 +1152,7 @@ cnoc: interconnect@fc480000 { #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; + <&rpmcc RPM_SMD_CNOC_A_CLK>; }; tsens: thermal-sensor@fc4a9000 { From 4960e06d386ecc5307bc2e66a77d5f06df1e2a6f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 27 Jun 2023 21:45:14 +0200 Subject: [PATCH 0046/7721] ARM: dts: qcom: msm8974: sort nodes by reg Some nodes weren't sorted by reg, so fix that now. Now all nodes inside /soc should be sorted correctly. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230627-msm8974-sort-v1-2-75c5800a2e09@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 70 ++++++++++++------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index 6cb61ef57a4f..76006c3c4af2 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -346,6 +346,12 @@ apcs: syscon@f9011000 { reg = <0xf9011000 0x1000>; }; + saw_l2: power-controller@f9012000 { + compatible = "qcom,saw2"; + reg = <0xf9012000 0x1000>; + regulator; + }; + timer@f9020000 { #address-cells = <1>; #size-cells = <1>; @@ -405,52 +411,46 @@ frame@f9028000 { }; }; - saw0: power-controller@f9089000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>; - }; - - saw1: power-controller@f9099000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>; - }; - - saw2: power-controller@f90a9000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>; - }; - - saw3: power-controller@f90b9000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>; - }; - - saw_l2: power-controller@f9012000 { - compatible = "qcom,saw2"; - reg = <0xf9012000 0x1000>; - regulator; - }; - acc0: power-manager@f9088000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf9088000 0x1000>, <0xf9008000 0x1000>; }; + saw0: power-controller@f9089000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>; + }; + acc1: power-manager@f9098000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf9098000 0x1000>, <0xf9008000 0x1000>; }; + saw1: power-controller@f9099000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>; + }; + acc2: power-manager@f90a8000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf90a8000 0x1000>, <0xf9008000 0x1000>; }; + saw2: power-controller@f90a9000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>; + }; + acc3: power-manager@f90b8000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf90b8000 0x1000>, <0xf9008000 0x1000>; }; + saw3: power-controller@f90b9000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>; + }; + sdhc_1: mmc@f9824900 { compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"; reg = <0xf9824900 0x11c>, <0xf9824000 0x800>; @@ -1063,6 +1063,15 @@ kpss_out: endpoint { }; }; + bimc: interconnect@fc380000 { + reg = <0xfc380000 0x6a000>; + compatible = "qcom,msm8974-bimc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; + gcc: clock-controller@fc400000 { compatible = "qcom,gcc-msm8974"; #clock-cells = <1>; @@ -1101,15 +1110,6 @@ pronto_master_stats: sram@1f50 { }; }; - bimc: interconnect@fc380000 { - reg = <0xfc380000 0x6a000>; - compatible = "qcom,msm8974-bimc"; - #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; - }; - snoc: interconnect@fc460000 { reg = <0xfc460000 0x4000>; compatible = "qcom,msm8974-snoc"; From 836d083524888069cd358776a4e6c4ceec04962e Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 12 Jul 2023 09:52:07 +0200 Subject: [PATCH 0047/7721] ARM: dts: qcom: msm8226: provide dsi phy clocks to mmcc Some mmcc clocks have dsi0pll & dsi0pllbyte as clock parents so we should provide them in the dt, which I missed in the commit adding the mdss nodes. Fixes: d5fb01ad5eb4 ("ARM: dts: qcom: msm8226: Add mdss nodes") Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230712-msm8226-dsi-clock-fixup-v1-1-71010b0b89ca@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8226.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi index 98cc5ea637e1..0e480f824d78 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi @@ -416,8 +416,8 @@ mmcc: clock-controller@fd8c0000 { <&gcc GPLL0_VOTE>, <&gcc GPLL1_VOTE>, <&rpmcc RPM_SMD_GFX3D_CLK_SRC>, - <0>, - <0>; + <&mdss_dsi0_phy 1>, + <&mdss_dsi0_phy 0>; clock-names = "xo", "mmss_gpll0_vote", "gpll0_vote", From 2821c34a996b4a0991d33bead5caa84267e2dccd Mon Sep 17 00:00:00 2001 From: Jonathan Albrieux Date: Tue, 3 Oct 2023 15:18:29 +0200 Subject: [PATCH 0048/7721] arm64: dts: qcom: msm8916-longcheer-l8910: Add sound and modem Enable sound and modem for the Longcheer L8910 (BQ Aquaris X5). The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - Audio jack detection via analog codec in PM8916 - WWAN Internet via BAM-DMUX except: - Awinic AW8738 connected to HPH_R (headphones) output of the analog codec. Note that unlike for wingtech-wt88047 there is no analog switch that would allow disabling output via the headphone jack when the speaker is enabled. Signed-off-by: Jonathan Albrieux Co-developed-by: Stephan Gerhold Signed-off-by: Stephan Gerhold Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-11-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-longcheer-l8910.dts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts index 41cadb906b98..e64bf687ca7d 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -22,6 +24,16 @@ chosen { stdout-path = "serial0"; }; + speaker_amp: audio-amplifier { + compatible = "awinic,aw8738"; + mode-gpios = <&tlmm 114 GPIO_ACTIVE_HIGH>; + awinic,mode = <5>; + sound-name-prefix = "Speaker Amp"; + + pinctrl-0 = <&spk_ext_pa_default>; + pinctrl-names = "default"; + }; + flash-led-controller { compatible = "ocs,ocp8110"; enable-gpios = <&tlmm 49 GPIO_ACTIVE_HIGH>; @@ -107,6 +119,17 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5000000>; +}; + +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -137,6 +160,28 @@ &sdhc_2 { cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + /* + * Provide widgets/pin-switches to allow enabling speaker separately. + * The hardware does not provide a way to disable the output via the + * headphone jack when the speaker is enabled. + */ + model = "bq-paella"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; + audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + aux-devs = <&speaker_amp>; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -205,6 +250,13 @@ sdc2_cd_default: sdc2-cd-default-state { bias-disable; }; + spk_ext_pa_default: spk-ext-pa-default-state { + pins = "gpio114"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + usb_id_default: usb-id-default-state { pins = "gpio110"; function = "gpio"; From 4f6b5edbcfbaa1061c29e6259cc5653f44b673da Mon Sep 17 00:00:00 2001 From: Jasper Korten Date: Tue, 3 Oct 2023 15:18:30 +0200 Subject: [PATCH 0049/7721] arm64: dts: qcom: msm8916-samsung-gt5: Add sound and modem Enable sound and modem for the Samsung Galaxy Tab A 2015 tablets. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Headphones/microphones via digital/analog codec in MSM8916/PM8916. Earpiece exists on samsung-gt58 only. - WWAN Internet via BAM-DMUX except: - gt510: Stereo Maxim MAX98357A codecs for speaker on Quaternary MI2S - gt58: Mono NXP TFA9895 codec for speaker on Quaternary MI2S - For some reason connected to GPIOs where no hardware I2C controller is available -> need to use i2c-gpio - Samsung-specific audio jack detection (not supported yet) Signed-off-by: Jasper Korten Co-developed-by: Siddharth Manthan Signed-off-by: Siddharth Manthan Co-developed-by: Nikita Travkin Signed-off-by: Nikita Travkin [Stephan: Add consistent commit message, minor refactoring] Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-12-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../dts/qcom/msm8916-samsung-gt5-common.dtsi | 54 +++++++++++++++++++ .../boot/dts/qcom/msm8916-samsung-gt510.dts | 22 ++++++++ .../boot/dts/qcom/msm8916-samsung-gt58.dts | 42 +++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi index 6a16eb5ce07b..fbd2caf405d5 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi @@ -3,9 +3,12 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include +#include / { aliases { @@ -116,6 +119,29 @@ &blsp_uart2 { status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5400000>; +}; + &pm8916_resin { linux,code = ; status = "okay"; @@ -133,6 +159,13 @@ &pm8916_usbin { status = "okay"; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -147,6 +180,27 @@ &sdhc_2 { status = "okay"; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { dr_mode = "peripheral"; extcon = <&pm8916_usbin>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts index c3f1acc55078..5b34529b816c 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts @@ -9,6 +9,14 @@ / { compatible = "samsung,gt510", "qcom,msm8916"; chassis-type = "tablet"; + speaker_codec: audio-codec { + compatible = "maxim,max98357a"; + sdmode-gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + pinctrl-0 = <&audio_sdmode_default>; + pinctrl-names = "default"; + }; + clk_pwm: pwm { compatible = "clk-pwm"; #pwm-cells = <2>; @@ -146,7 +154,21 @@ &mdss_dsi0_out { remote-endpoint = <&panel_in>; }; +&sound { + model = "samsung-gt510"; + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; +}; + &tlmm { + audio_sdmode_default: audio-sdmode-default-state { + pins = "gpio55"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + buckbooster_en_default: buckbooster-en-default-state { pins = "gpio51"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts index 998625abd409..579312ed53ce 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts @@ -35,6 +35,26 @@ reg_vdd_tsp: regulator-vdd-tsp { pinctrl-names = "default"; }; + i2c-amplifier { + compatible = "i2c-gpio"; + sda-gpios = <&tlmm 55 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 56 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + pinctrl-0 = <&_i2c_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; + }; + vibrator { compatible = "gpio-vibrator"; enable-gpios = <&tlmm 76 GPIO_ACTIVE_HIGH>; @@ -98,7 +118,21 @@ &mdss_dsi0_out { remote-endpoint = <&panel_in>; }; +&sound { + model = "samsung-a2015"; + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default &secondary_mic_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep &secondary_mic_default>; + pinctrl-names = "default", "sleep"; +}; + &tlmm { + amp_i2c_default: amp-i2c-default-state { + pins = "gpio55", "gpio56"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + buckbooster_en_default: buckbooster-en-default-state { pins = "gpio8"; function = "gpio"; @@ -127,6 +161,14 @@ reg_tsp_en_default: reg-tsp-en-default-state { bias-disable; }; + secondary_mic_default: secondary-mic-default-state { + pins = "gpio98"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-high; + }; + tsp_int_default: tsp-int-default-state { pins = "gpio13"; function = "gpio"; From cf12268e1b632c6ac16185bd1230af6e1ca517fb Mon Sep 17 00:00:00 2001 From: "Lin, Meng-Bo" Date: Tue, 3 Oct 2023 15:18:31 +0200 Subject: [PATCH 0050/7721] arm64: dts: qcom: msm8916-samsung-j5: Add sound and modem Enable sound and modem for the Samsung J5 smartphones. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Speaker/earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - WWAN Internet via BAM-DMUX except: - There is no secondary microphone, so a different "model" is used to differentiate that in the UCM configuration. - Samsung-specific audio jack detection (not supported yet) Co-developed-by: Markuss Broks Signed-off-by: Markuss Broks Signed-off-by: "Lin, Meng-Bo" [Stephan: Add consistent commit message] Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-13-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-samsung-j5-common.dtsi | 14 ++++++++++++++ arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi index fe59be3505fe..5ca2ada266f4 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -135,6 +137,10 @@ &blsp_uart2 { status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5800000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -154,6 +160,14 @@ &sdhc_2 { cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + model = "msm8916-1mic"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { extcon = <&muic>, <&muic>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts index 58c2f5a70e78..ba8650971d6a 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts @@ -19,6 +19,10 @@ &blsp_i2c5 { status = "disabled"; }; +&pm8916_codec { + qcom,micbias1-ext-cap; +}; + &touchscreen { /* FIXME: Missing sm5703-mfd driver to power up vdd-supply */ }; From dd5ab5d2ca722110c82459a571e367df7ee6d821 Mon Sep 17 00:00:00 2001 From: "Lin, Meng-Bo" Date: Tue, 3 Oct 2023 15:18:32 +0200 Subject: [PATCH 0051/7721] arm64: dts: qcom: msm8939-samsung-a7: Add sound and modem Enable sound and modem for the Samsung A7. The setup is similar to most MSM8916 devices, i.e.: - QDSP6 audio - Earpiece/headphones/microphones via digital/analog codec in MSM8916/PM8916 - WWAN Internet via BAM-DMUX except for the same differences as the MSM8916-based Samsung A2015 devices: - NXP TFA9895 codec for speaker on Quaternary MI2S - Samsung-specific audio jack detection (not supported yet) Signed-off-by: "Lin, Meng-Bo" [Stephan: Add consistent commit message, minor refactoring] Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20231003-msm8916-modem-v2-14-61b684be55c0@gerhold.net Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8939-samsung-a7.dts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts b/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts index fccd8fec8b8f..aa6c39482a2f 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts @@ -3,10 +3,12 @@ /dts-v1/; #include "msm8939-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" #include #include #include +#include / { model = "Samsung Galaxy A7 (2015)"; @@ -287,6 +289,18 @@ muic: extcon@25 { }; }; +&blsp_i2c2 { + status = "okay"; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; +}; + &blsp_i2c5 { status = "okay"; @@ -309,6 +323,29 @@ &blsp_uart2 { status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5800000>; +}; + &pm8916_resin { linux,code = ; status = "okay"; @@ -321,6 +358,13 @@ pm8916_l17: l17 { }; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -335,6 +379,32 @@ &sdhc_2 { status = "okay"; }; +&sound { + model = "samsung-a2015"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { extcon = <&muic>, <&muic>; status = "okay"; From 5017b8cdb7ebeb32d7f12a05b34d58662e137dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Fri, 13 Oct 2023 22:51:36 +0200 Subject: [PATCH 0052/7721] arm64: dts: qcom: msm8916-longcheer-l8910: Enable RGB LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l8910 uses KTD2026 LED driver. Add it to the device tree. Tested-by: Stephan Gerhold Signed-off-by: André Apitzsch Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231013-bq_leds-v1-1-cc374369fc56@apitzsch.eu Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-longcheer-l8910.dts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts index e64bf687ca7d..3b7fdb6797a9 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts @@ -8,6 +8,7 @@ #include #include #include +#include / { model = "BQ Aquaris X5 (Longcheer L8910)"; @@ -86,6 +87,46 @@ usb_id: usb-id { }; }; +&blsp_i2c2 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + vin-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + + pinctrl-0 = <&status_led_default>; + pinctrl-names = "default"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + }; +}; + &blsp_i2c3 { status = "okay"; @@ -130,6 +171,16 @@ &pm8916_codec { qcom,hphl-jack-type-normally-open; }; +&pm8916_gpios { + status_led_default: status-led-default-state { + pins = "gpio3"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = ; + bias-disable; + output-high; + }; +}; + &pm8916_resin { status = "okay"; linux,code = ; From a21796c631734ea5cf62507e63a2479261880514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Fri, 13 Oct 2023 22:51:37 +0200 Subject: [PATCH 0053/7721] arm64: dts: qcom: msm8939-longcheer-l9100: Enable RGB LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l9100 uses KTD2026 LED driver. Add it to the device tree. Signed-off-by: André Apitzsch Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231013-bq_leds-v1-2-cc374369fc56@apitzsch.eu Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8939-longcheer-l9100.dts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts index a3357513037c..ff532fdc1826 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts @@ -8,6 +8,7 @@ #include #include #include +#include #include / { @@ -120,6 +121,46 @@ usb_id: usb-id { }; +&blsp_i2c2 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + vin-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + + pinctrl-0 = <&status_led_default>; + pinctrl-names = "default"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + }; +}; + &blsp_i2c3 { status = "okay"; @@ -184,6 +225,16 @@ &blsp_uart2 { status = "okay"; }; +&pm8916_gpios { + status_led_default: status-led-default-state { + pins = "gpio3"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = ; + bias-disable; + output-high; + }; +}; + &pm8916_mpps { pwm_out: mpp4-state { pins = "mpp4"; From c493a2b37a9e9b7864389d72dd9c67d1d39cfc61 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:07:56 +0100 Subject: [PATCH 0054/7721] dt-bindings: arm: qcom: Document MSM8x26-based Lumia phones Document MSM8226 and MSM8926 Lumias. Signed-off-by: Rayyan Ansari Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230930221323.101289-2-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 7f80f48a0954..88b84035e7b1 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -186,9 +186,19 @@ properties: - items: - enum: + - microsoft,dempsey + - microsoft,makepeace + - microsoft,moneypenny - samsung,s3ve3g - const: qcom,msm8226 + - items: + - enum: + - microsoft,superman-lte + - microsoft,tesla + - const: qcom,msm8926 + - const: qcom,msm8226 + - items: - enum: - longcheer,l9100 From 244281556a11549501eb5093e9ab0ad8a87b7d4f Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:07:57 +0100 Subject: [PATCH 0055/7721] ARM: dts: qcom: add common dt for MSM8x26 Lumias along with Nokia Lumia 630 Add a common device tree for Lumia phones based on the Qualcomm MSM8x26 family of chipsets. Currently supports: - Framebuffer - Touchscreen - Keys - Regulators - MMC - USB - UART Also add an initial device tree for the Nokia Lumia 630, codenamed "moneypenny". Co-developed-by: Dominik Kobinski Signed-off-by: Dominik Kobinski Co-developed-by: Ivaylo Ivanov Signed-off-by: Ivaylo Ivanov Co-developed-by: Jack Matthews Signed-off-by: Jack Matthews Signed-off-by: Rayyan Ansari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230930221323.101289-3-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../qcom/qcom-msm8226-microsoft-common.dtsi | 327 ++++++++++++++++++ .../qcom-msm8226-microsoft-moneypenny.dts | 23 ++ 3 files changed, 351 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 3dfb1c8cefb8..b2569059ce8d 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq4019-ap.dk07.1-c2.dtb \ qcom-ipq8064-ap148.dtb \ qcom-ipq8064-rb3011.dtb \ + qcom-msm8226-microsoft-moneypenny.dtb \ qcom-msm8226-samsung-s3ve3g.dtb \ qcom-msm8660-surf.dtb \ qcom-msm8916-samsung-e5.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi new file mode 100644 index 000000000000..a6fd3acf0bae --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Common Board Device Tree for Microsoft MSM8x26-based Lumias + * + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +#include "qcom-msm8226.dtsi" +#include "qcom-pm8226.dtsi" +#include + +/* + * Delete all generic (msm8226.dtsi) reserved + * memory mappings which are different on these devices. + */ +/delete-node/ &smem_region; + +/ { + aliases { + mmc0 = &sdhc_1; /* eMMC */ + mmc1 = &sdhc_2; /* microSD */ + display0 = &framebuffer; + }; + + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + stdout-path = "display0"; + + framebuffer: framebuffer@3200000 { + compatible = "simple-framebuffer"; + reg = <0x3200000 0x800000>; + format = "a8r8g8b8"; + width = <720>; + height = <1280>; + stride = <(720 * 4)>; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_PCLK0_CLK>, + <&mmcc MDSS_VSYNC_CLK>; + power-domains = <&mmcc MDSS_GDSC>; + }; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + label = "GPIO Buttons"; + + key-volume-up { + label = "Volume Up"; + gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + /* + * This device being a WP platform has a different + * memory layout than other Android based devices. + * This smem memory region is directly copied from + * the original UEFI firmware. + */ + reserved-memory { + display_reserved: framebuffer@3200000 { + reg = <0x03200000 0x800000>; + no-map; + }; + + smem_region: smem@fa00000 { + reg = <0x0fa00000 0x100000>; + no-map; + }; + }; +}; + +&blsp1_i2c5 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_uart3 { + status = "okay"; +}; + +&pm8226_resin { + linux,code = ; + status = "okay"; +}; + +&pm8226_vib { + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-pm8226-regulators"; + + /* These values were taken from the original firmware DSDT */ + pm8226_s1: s1 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + pm8226_s3: s3 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + }; + + pm8226_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + }; + + pm8226_s5: s5 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l3: l3 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l4: l4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l5: l5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + pm8226_l8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + pm8226_l9: l9 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l10: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l12: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l14: l14 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + }; + + pm8226_l15: l15 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l16: l16 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l17: l17 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + regulator-system-load = <200000>; + regulator-allow-set-load; + }; + + pm8226_l18: l18 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + regulator-system-load = <200000>; + regulator-allow-set-load; + }; + + pm8226_l19: l19 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l20: l20 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + pm8226_l21: l21 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l22: l22 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l23: l23 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l24: l24 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + }; + + pm8226_l25: l25 { + regulator-min-microvolt = <1775000>; + regulator-max-microvolt = <2075000>; + }; + + pm8226_l27: l27 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l28: l28 { + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <3000000>; + }; + }; +}; + +&sdhc_1 { + vmmc-supply = <&pm8226_l17>; + vqmmc-supply = <&pm8226_l6>; + + status = "okay"; +}; + +&sdhc_2 { + vmmc-supply = <&pm8226_l18>; + vqmmc-supply = <&pm8226_l21>; + + status = "okay"; +}; + +&usb { + extcon = <&smbb>; + dr_mode = "peripheral"; + + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&smbb>; + v1p8-supply = <&pm8226_l10>; + v3p3-supply = <&pm8226_l20>; +}; + +&tlmm { + gpio_keys_default: gpio-keys-default-state { + pins = "gpio106", "gpio107", "gpio108"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + touchscreen_default: touchscreen-default-state { + irq-pins { + pins = "gpio17"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; + + reset-pins { + pins = "gpio16"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + output-high; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts new file mode 100644 index 000000000000..992b7115b5f8 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Nokia Lumia 630"; + compatible = "microsoft,moneypenny", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&framebuffer { + width = <480>; + height = <854>; + stride = <(480 * 4)>; +}; From 45dbc34693e8ad30c33edfdc94acaf4672de0e24 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:07:58 +0100 Subject: [PATCH 0056/7721] ARM: dts: qcom: add device tree for Microsoft Lumia 640 Add an initial device tree for the Microsoft Lumia 640, codenamed "dempsey". Co-developed-by: Dominik Kobinski Signed-off-by: Dominik Kobinski Co-developed-by: Ivaylo Ivanov Signed-off-by: Ivaylo Ivanov Co-developed-by: Jack Matthews Signed-off-by: Jack Matthews Signed-off-by: Rayyan Ansari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230930221323.101289-4-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../dts/qcom/qcom-msm8226-microsoft-dempsey.dts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index b2569059ce8d..13896c6974f6 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq4019-ap.dk07.1-c2.dtb \ qcom-ipq8064-ap148.dtb \ qcom-ipq8064-rb3011.dtb \ + qcom-msm8226-microsoft-dempsey.dtb \ qcom-msm8226-microsoft-moneypenny.dtb \ qcom-msm8226-samsung-s3ve3g.dtb \ qcom-msm8660-surf.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts new file mode 100644 index 000000000000..2c664b5934ec --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Microsoft Lumia 640"; + compatible = "microsoft,dempsey", "qcom,msm8226"; + chassis-type = "handset"; +}; From a16f3bcf867efdab422b711b18c023089fbeb96e Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:07:59 +0100 Subject: [PATCH 0057/7721] ARM: dts: qcom: add device tree for Microsoft Lumia 640 XL Add an initial device tree for the Microsoft Lumia 640 XL, codenamed "makepeace". Co-developed-by: Dominik Kobinski Signed-off-by: Dominik Kobinski Co-developed-by: Ivaylo Ivanov Signed-off-by: Ivaylo Ivanov Co-developed-by: Jack Matthews Signed-off-by: Jack Matthews Signed-off-by: Rayyan Ansari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230930221323.101289-5-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../qcom/qcom-msm8226-microsoft-makepeace.dts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 13896c6974f6..487e0a5987ce 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -24,6 +24,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq8064-ap148.dtb \ qcom-ipq8064-rb3011.dtb \ qcom-msm8226-microsoft-dempsey.dtb \ + qcom-msm8226-microsoft-makepeace.dtb \ qcom-msm8226-microsoft-moneypenny.dtb \ qcom-msm8226-samsung-s3ve3g.dtb \ qcom-msm8660-surf.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts new file mode 100644 index 000000000000..731c5c375678 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Microsoft Lumia 640 XL"; + compatible = "microsoft,makepeace", "qcom,msm8226"; + chassis-type = "handset"; +}; From 00400a98b2c3fd5d497635747fec4b882299bc05 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:08:00 +0100 Subject: [PATCH 0058/7721] ARM: dts: qcom: add device tree for Nokia Lumia 735 Add an initial device tree for the Nokia Lumia 735, codenamed "superman-lte". Co-developed-by: Dominik Kobinski Signed-off-by: Dominik Kobinski Co-developed-by: Ivaylo Ivanov Signed-off-by: Ivaylo Ivanov Co-developed-by: Jack Matthews Signed-off-by: Jack Matthews Signed-off-by: Rayyan Ansari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230930221323.101289-6-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../qcom-msm8926-microsoft-superman-lte.dts | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 487e0a5987ce..7982620ec9f9 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8916-samsung-e7.dtb \ qcom-msm8916-samsung-grandmax.dtb \ qcom-msm8916-samsung-serranove.dtb \ + qcom-msm8926-microsoft-superman-lte.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8960-samsung-expressatt.dtb \ qcom-msm8974-lge-nexus5-hammerhead.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts new file mode 100644 index 000000000000..9b48661d69c5 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/* This device has touchscreen on i2c3 instead */ +/delete-node/ &touchscreen; + +/ { + model = "Nokia Lumia 735"; + compatible = "microsoft,superman-lte", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&blsp1_i2c3 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c5 { + status = "disabled"; +}; From 8677233e59137f78d4d578f3d5a21557c1bab342 Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Sat, 30 Sep 2023 23:08:01 +0100 Subject: [PATCH 0059/7721] ARM: dts: qcom: add device tree for Nokia Lumia 830 Add an initial device tree for the Nokia Lumia 830, codenamed "tesla". Co-developed-by: Dominik Kobinski Signed-off-by: Dominik Kobinski Co-developed-by: Ivaylo Ivanov Signed-off-by: Ivaylo Ivanov Co-developed-by: Jack Matthews Signed-off-by: Jack Matthews Signed-off-by: Rayyan Ansari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230930221323.101289-7-rayyan@ansari.sh Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../dts/qcom/qcom-msm8926-microsoft-tesla.dts | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 7982620ec9f9..a3d293e40820 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -33,6 +33,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8916-samsung-grandmax.dtb \ qcom-msm8916-samsung-serranove.dtb \ qcom-msm8926-microsoft-superman-lte.dtb \ + qcom-msm8926-microsoft-tesla.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8960-samsung-expressatt.dtb \ qcom-msm8974-lge-nexus5-hammerhead.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts new file mode 100644 index 000000000000..53a6d4e85959 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/* This device has touchscreen on i2c1 instead */ +/delete-node/ &touchscreen; + +/ { + model = "Nokia Lumia 830"; + compatible = "microsoft,tesla", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&blsp1_i2c1 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f12@12 { + reg = <0x12>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c5 { + status = "disabled"; +}; + +&gpio_keys { + key-camera-snapshot { + label = "Camera Snapshot"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + key-camera-focus { + label = "Camera Focus"; + gpios = <&tlmm 108 GPIO_ACTIVE_LOW>; + linux,code = ; + }; +}; From 501069dad5214fafe1b8ba38fa26a5d07df784c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Thu, 12 Oct 2023 10:21:57 +0300 Subject: [PATCH 0060/7721] drm/i915/display: Move releasing gem object away from fb tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a preparation for Xe we want to remove all i915_gem_object details away from frontbuffer tacking code. Due to this move releasing gem object reference to i915_gem_object_set_frontbuffer. Signed-off-by: Jouni Högander Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20231012072158.4115795-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_frontbuffer.c | 2 -- drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index ec46716b2f49..2ea37c0414a9 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -265,8 +265,6 @@ static void frontbuffer_release(struct kref *ref) spin_unlock(&intel_bo_to_i915(obj)->display.fb_tracking.lock); i915_active_fini(&front->write); - - i915_gem_object_put(obj); kfree_rcu(front, rcu); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h index e5e870b6f186..9fbf14867a2a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h @@ -89,6 +89,7 @@ i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj, if (!front) { RCU_INIT_POINTER(obj->frontbuffer, NULL); + drm_gem_object_put(intel_bo_to_drm_bo(obj)); } else if (rcu_access_pointer(obj->frontbuffer)) { cur = rcu_dereference_protected(obj->frontbuffer, true); kref_get(&cur->ref); From 3594d00b71eea66d183b310c19aa5a6bf4206e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Thu, 12 Oct 2023 10:21:58 +0300 Subject: [PATCH 0061/7721] drm/i915/display: Use intel_bo_to_drm_bo instead of obj->base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xe and i915 objects have differing implementation. Use intel_bo_to_drm_bo instead of obj->base as xe_bo doesn't have base pointer. Signed-off-by: Jouni Högander Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20231012072158.4115795-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index e7678571b0d7..e1d298efc510 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1930,10 +1930,10 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, if (!atomic_read(&front->bits)) return 0; - if (dma_resv_test_signaled(obj->base.resv, dma_resv_usage_rw(false))) + if (dma_resv_test_signaled(intel_bo_to_drm_bo(obj)->resv, dma_resv_usage_rw(false))) goto flush; - ret = dma_resv_get_singleton(obj->base.resv, dma_resv_usage_rw(false), + ret = dma_resv_get_singleton(intel_bo_to_drm_bo(obj)->resv, dma_resv_usage_rw(false), &fence); if (ret || !fence) goto flush; From f17c08a6046f0c9383a61d7009216b0ad3369db4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Oct 2023 17:27:04 +0300 Subject: [PATCH 0062/7721] drm/i915: drop gt/intel_gt.h include from skl_universal_plane.c No longer needed after commit 94bcf876cb6a ("drm/i915/mtl: Drop Wa_14017240301"). Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231011142704.985867-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/skl_universal_plane.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 245a64332cc7..49e9d40d5e67 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -21,7 +21,6 @@ #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" -#include "gt/intel_gt.h" #include "pxp/intel_pxp.h" static const u32 skl_plane_formats[] = { From 26eb4fcf2349b3dc02ee6f96925419eb7b3026d0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Oct 2023 23:15:32 +0300 Subject: [PATCH 0063/7721] drm/i915/aux: add separate register macros and functions for VLV/CHV Add separate macros for VLV/CHV registers without the implicit dev_priv, and with the display MMIO base baked in. A number of implicitly used dev_priv local variables can be removed. Signed-off-by: Jani Nikula Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231011201533.1081368-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp_aux.c | 43 +++++++++++++++---- .../gpu/drm/i915/display/intel_dp_aux_regs.h | 14 +++--- drivers/gpu/drm/i915/gvt/handlers.c | 1 - 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 4431b6290c4c..c106598a78c5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -531,9 +531,40 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return ret; } +static i915_reg_t vlv_aux_ctl_reg(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_D: + return VLV_DP_AUX_CH_CTL(aux_ch); + default: + MISSING_CASE(aux_ch); + return VLV_DP_AUX_CH_CTL(AUX_CH_B); + } +} + +static i915_reg_t vlv_aux_data_reg(struct intel_dp *intel_dp, int index) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_D: + return VLV_DP_AUX_CH_DATA(aux_ch, index); + default: + MISSING_CASE(aux_ch); + return VLV_DP_AUX_CH_DATA(AUX_CH_B, index); + } +} + static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -550,7 +581,6 @@ static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -567,7 +597,6 @@ static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -586,7 +615,6 @@ static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -605,7 +633,6 @@ static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -625,7 +652,6 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -645,7 +671,6 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -668,7 +693,6 @@ static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -757,6 +781,9 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) } else if (HAS_PCH_SPLIT(dev_priv)) { intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg; intel_dp->aux_ch_data_reg = ilk_aux_data_reg; + } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + intel_dp->aux_ch_ctl_reg = vlv_aux_ctl_reg; + intel_dp->aux_ch_data_reg = vlv_aux_data_reg; } else { intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg; intel_dp->aux_ch_data_reg = g4x_aux_data_reg; diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h index 34f6e0a48ed2..e642445364d2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h @@ -21,13 +21,14 @@ #define __xe2lpd_aux_ch_idx(aux_ch) \ (aux_ch >= AUX_CH_USBC1 ? aux_ch : AUX_CH_USBC4 + 1 + (aux_ch) - AUX_CH_A) -/* TODO: Remove implicit dev_priv */ -#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) -#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) +#define _DPA_AUX_CH_CTL 0x64010 +#define _DPB_AUX_CH_CTL 0x64110 #define _XELPDP_USBC1_AUX_CH_CTL 0x16f210 #define _XELPDP_USBC2_AUX_CH_CTL 0x16f410 #define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, \ _DPB_AUX_CH_CTL) +#define VLV_DP_AUX_CH_CTL(aux_ch) _MMIO(VLV_DISPLAY_BASE + \ + _PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)) #define _XELPDP_DP_AUX_CH_CTL(aux_ch) \ _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL, \ @@ -69,13 +70,14 @@ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK REG_GENMASK(4, 0) /* skl+ */ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) REG_FIELD_PREP(DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK, (c) - 1) -/* TODO: Remove implicit dev_priv */ -#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) -#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) +#define _DPA_AUX_CH_DATA1 0x64014 +#define _DPB_AUX_CH_DATA1 0x64114 #define _XELPDP_USBC1_AUX_CH_DATA1 0x16f214 #define _XELPDP_USBC2_AUX_CH_DATA1 0x16f414 #define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, \ _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define VLV_DP_AUX_CH_DATA(aux_ch, i) _MMIO(VLV_DISPLAY_BASE + _PORT(aux_ch, _DPA_AUX_CH_DATA1, \ + _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ #define _XELPDP_DP_AUX_CH_DATA(aux_ch, i) \ _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1, \ diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index a9f7fa9b90bd..72addd8d380f 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -2576,7 +2576,6 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt) static int init_skl_mmio_info(struct intel_gvt *gvt) { - struct drm_i915_private *dev_priv = gvt->gt->i915; int ret; MMIO_DH(FORCEWAKE_RENDER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); From fa072c0d9240233a281097f1f2a965441654eaa2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Oct 2023 23:15:33 +0300 Subject: [PATCH 0064/7721] drm/i915/aux: rename dev_priv to i915 No reason to stick to dev_priv, rename to i915. Signed-off-by: Jani Nikula Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231011201533.1081368-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp_aux.c | 58 ++++++++++----------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index c106598a78c5..2e2af71bcd5a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -74,7 +74,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp) static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (index) return 0; @@ -83,12 +83,12 @@ static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) * The clock divider is based off the hrawclk, and would like to run at * 2MHz. So, take the hrawclk value and divide by 2000 and use that */ - return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000); + return DIV_ROUND_CLOSEST(RUNTIME_INFO(i915)->rawclk_freq, 2000); } static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); u32 freq; @@ -101,18 +101,18 @@ static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) * divide by 2000 and use that */ if (dig_port->aux_ch == AUX_CH_A) - freq = dev_priv->display.cdclk.hw.cdclk; + freq = i915->display.cdclk.hw.cdclk; else - freq = RUNTIME_INFO(dev_priv)->rawclk_freq; + freq = RUNTIME_INFO(i915)->rawclk_freq; return DIV_ROUND_CLOSEST(freq, 2000); } static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) { + if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(i915)) { /* Workaround for non-ULT HSW */ switch (index) { case 0: return 63; @@ -165,12 +165,11 @@ static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp, u32 aux_clock_divider) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = - to_i915(dig_port->base.base.dev); + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); u32 timeout; /* Max timeout value on G4x-BDW: 1.6ms */ - if (IS_BROADWELL(dev_priv)) + if (IS_BROADWELL(i915)) timeout = DP_AUX_CH_CTL_TIME_OUT_600us; else timeout = DP_AUX_CH_CTL_TIME_OUT_400us; @@ -229,8 +228,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, u32 aux_send_ctl_flags) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *i915 = - to_i915(dig_port->base.base.dev); + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); enum phy phy = intel_port_to_phy(i915, dig_port->base.port); bool is_tc_port = intel_phy_is_tc(i915, phy); i915_reg_t ch_ctl, ch_data[5]; @@ -715,7 +713,7 @@ static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -726,16 +724,16 @@ static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch); + return XELPDP_DP_AUX_CH_CTL(i915, aux_ch); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_CTL(dev_priv, AUX_CH_A); + return XELPDP_DP_AUX_CH_CTL(i915, AUX_CH_A); } } static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -746,10 +744,10 @@ static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_DATA(dev_priv, aux_ch, index); + return XELPDP_DP_AUX_CH_DATA(i915, aux_ch, index); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_DATA(dev_priv, AUX_CH_A, index); + return XELPDP_DP_AUX_CH_DATA(i915, AUX_CH_A, index); } } @@ -763,25 +761,25 @@ void intel_dp_aux_fini(struct intel_dp *intel_dp) void intel_dp_aux_init(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum aux_ch aux_ch = dig_port->aux_ch; char buf[AUX_CH_NAME_BUFSIZE]; - if (DISPLAY_VER(dev_priv) >= 14) { + if (DISPLAY_VER(i915) >= 14) { intel_dp->aux_ch_ctl_reg = xelpdp_aux_ctl_reg; intel_dp->aux_ch_data_reg = xelpdp_aux_data_reg; - } else if (DISPLAY_VER(dev_priv) >= 12) { + } else if (DISPLAY_VER(i915) >= 12) { intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg; intel_dp->aux_ch_data_reg = tgl_aux_data_reg; - } else if (DISPLAY_VER(dev_priv) >= 9) { + } else if (DISPLAY_VER(i915) >= 9) { intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg; intel_dp->aux_ch_data_reg = skl_aux_data_reg; - } else if (HAS_PCH_SPLIT(dev_priv)) { + } else if (HAS_PCH_SPLIT(i915)) { intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg; intel_dp->aux_ch_data_reg = ilk_aux_data_reg; - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { intel_dp->aux_ch_ctl_reg = vlv_aux_ctl_reg; intel_dp->aux_ch_data_reg = vlv_aux_data_reg; } else { @@ -789,26 +787,26 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) intel_dp->aux_ch_data_reg = g4x_aux_data_reg; } - if (DISPLAY_VER(dev_priv) >= 9) + if (DISPLAY_VER(i915) >= 9) intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider; - else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + else if (IS_BROADWELL(i915) || IS_HASWELL(i915)) intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider; - else if (HAS_PCH_SPLIT(dev_priv)) + else if (HAS_PCH_SPLIT(i915)) intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider; else intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider; - if (DISPLAY_VER(dev_priv) >= 9) + if (DISPLAY_VER(i915) >= 9) intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl; else intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl; - intel_dp->aux.drm_dev = &dev_priv->drm; + intel_dp->aux.drm_dev = &i915->drm; drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %s/%s", - aux_ch_name(dev_priv, buf, sizeof(buf), aux_ch), + aux_ch_name(i915, buf, sizeof(buf), aux_ch), encoder->base.name); intel_dp->aux.transfer = intel_dp_aux_transfer; From a388b41a426ebd84ecd8ab12d6aaae7e06344a5b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Oct 2023 19:21:02 +0300 Subject: [PATCH 0065/7721] drm/i915: stop including i915_utils.h from intel_runtime_pm.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove an unnecessary include. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231011162102.1030354-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_runtime_pm.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index f79cda7a2503..be43614c73fd 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -11,8 +11,6 @@ #include "intel_wakeref.h" -#include "i915_utils.h" - struct device; struct drm_i915_private; struct drm_printer; From 8fa1c7cd1fe9cdfc426a603e1f1eecd3f463c487 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 19 Oct 2023 10:02:42 -0700 Subject: [PATCH 0066/7721] drm/i915/mcr: Hold GT forcewake during steering operations The steering control and semaphore registers are inside an "always on" power domain with respect to RC6. However there are some issues if higher-level platform sleep states are entering/exiting at the same time these registers are accessed. Grabbing GT forcewake and holding it over the entire lock/steer/unlock cycle ensures that those sleep states have been fully exited before we access these registers. This is expected to become a formally documented/numbered workaround soon. Note that this patch alone isn't expected to have an immediately noticeable impact on MCR (mis)behavior; an upcoming pcode firmware update will also be necessary to provide the other half of this workaround. v2: - Move the forcewake inside the Xe_LPG-specific IP version check. This should only be necessary on platforms that have a steering semaphore. Fixes: 3100240bf846 ("drm/i915/mtl: Add hardware-level lock for steering") Cc: Radhakrishna Sripada Cc: Jonathan Cavitt Signed-off-by: Matt Roper Reviewed-by: Radhakrishna Sripada Reviewed-by: Jonathan Cavitt Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231019170241.2102037-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 326c2ed1d99b..34913912d8ae 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -376,9 +376,26 @@ void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags) * driver threads, but also with hardware/firmware agents. A dedicated * locking register is used. */ - if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) { + /* + * The steering control and semaphore registers are inside an + * "always on" power domain with respect to RC6. However there + * are some issues if higher-level platform sleep states are + * entering/exiting at the same time these registers are + * accessed. Grabbing GT forcewake and holding it over the + * entire lock/steer/unlock cycle ensures that those sleep + * states have been fully exited before we access these + * registers. This wakeref will be released in the unlock + * routine. + * + * This is expected to become a formally documented/numbered + * workaround soon. + */ + intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_GT); + err = wait_for(intel_uncore_read_fw(gt->uncore, MTL_STEER_SEMAPHORE) == 0x1, 100); + } /* * Even on platforms with a hardware lock, we'll continue to grab @@ -415,8 +432,11 @@ void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags) { spin_unlock_irqrestore(>->mcr_lock, flags); - if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) { intel_uncore_write_fw(gt->uncore, MTL_STEER_SEMAPHORE, 0x1); + + intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_GT); + } } /** From 31f6a06f0c543b43a38fab10f39e5fc45ad62aa2 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Fri, 20 Oct 2023 08:24:41 -0700 Subject: [PATCH 0067/7721] drm/i915/pmu: Check if pmu is closed before stopping event When the driver unbinds, pmu is unregistered and i915->uabi_engines is set to RB_ROOT. Due to this, when i915 PMU tries to stop the engine events, it issues a warn_on because engine lookup fails. All perf hooks are taking care of this using a pmu->closed flag that is set when PMU unregisters. The stop event seems to have been left out. Check for pmu->closed in pmu_event_stop as well. Based on discussion here - https://patchwork.freedesktop.org/patch/492079/?series=105790&rev=2 v2: s/is/if/ in commit title v3: Add fixes tag and cc stable Cc: # v5.11+ Fixes: b00bccb3f0bb ("drm/i915/pmu: Handle PCI unbind") Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Tvrtko Ursulin Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231020152441.3764850-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 108b675088ba..f861863eb7c1 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -831,9 +831,18 @@ static void i915_pmu_event_start(struct perf_event *event, int flags) static void i915_pmu_event_stop(struct perf_event *event, int flags) { + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = &i915->pmu; + + if (pmu->closed) + goto out; + if (flags & PERF_EF_UPDATE) i915_pmu_event_read(event); i915_pmu_disable(event); + +out: event->hw.state = PERF_HES_STOPPED; } From bc725dc1a8317abb2403b3a906106dbe0d4d4422 Mon Sep 17 00:00:00 2001 From: Vinod Govindapillai Date: Wed, 18 Oct 2023 13:27:22 +0300 Subject: [PATCH 0068/7721] drm/i915/display: debugfs entry to list display capabilities Create a separate debugfs entry to list the display capabilities IGT can rely on this debugfs entry for tests that depend on display device and display runtime info for both xe and i915 drivers. v2: rename the entry to i915_display_capabilities (Chaitanya) Signed-off-by: Vinod Govindapillai Reviewed-by: Chaitanya Kumar Borah Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231018102723.16915-2-vinod.govindapillai@intel.com --- drivers/gpu/drm/i915/display/intel_display_debugfs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 1610c2b6a644..5d2f4fc5709b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -642,6 +642,17 @@ static int i915_display_info(struct seq_file *m, void *unused) return 0; } +static int i915_display_capabilities(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = node_to_i915(m->private); + struct drm_printer p = drm_seq_file_printer(m); + + intel_display_device_info_print(DISPLAY_INFO(i915), + DISPLAY_RUNTIME_INFO(i915), &p); + + return 0; +} + static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -1060,6 +1071,7 @@ static const struct drm_info_list intel_display_debugfs_list[] = { {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, + {"i915_display_capabilities", i915_display_capabilities, 0}, {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_ddb_info", i915_ddb_info, 0}, From 8015bee0bfec6920f2441e5adc77e6ac2b65be8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:47 +0300 Subject: [PATCH 0069/7721] drm/i915/display: Add framework to add parameters specific to display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently all module parameters are handled by i915_param.c/h. This is a problem for display parameters when Xe driver is used. Add a mechanism to add parameters specific to the display. This is mainly copied from i915_[debugfs]_params.[ch]. Parameters are not yet moved. This is done by subsequent patches. v2: - Drop unused predefinition (dentry) - Clarify need for empty INTEL_DISPLAY_PARAMS_FOR_EACH in comment Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/Makefile | 2 + .../gpu/drm/i915/display/intel_display_core.h | 2 + .../drm/i915/display/intel_display_debugfs.c | 2 + .../display/intel_display_debugfs_params.c | 176 ++++++++++++++++++ .../display/intel_display_debugfs_params.h | 13 ++ .../drm/i915/display/intel_display_device.c | 8 + .../drm/i915/display/intel_display_device.h | 1 + .../drm/i915/display/intel_display_params.c | 71 +++++++ .../drm/i915/display/intel_display_params.h | 34 ++++ drivers/gpu/drm/i915/i915_driver.c | 2 + 10 files changed, 311 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_display_debugfs_params.c create mode 100644 drivers/gpu/drm/i915/display/intel_display_debugfs_params.h create mode 100644 drivers/gpu/drm/i915/display/intel_display_params.c create mode 100644 drivers/gpu/drm/i915/display/intel_display_params.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 88b2bb005014..3b9dcb606fc1 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -95,6 +95,7 @@ i915-$(CONFIG_DEBUG_FS) += \ i915_debugfs.o \ i915_debugfs_params.o \ display/intel_display_debugfs.o \ + display/intel_display_debugfs_params.o \ display/intel_pipe_crc.o i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o @@ -257,6 +258,7 @@ i915-y += \ display/intel_display.o \ display/intel_display_driver.o \ display/intel_display_irq.o \ + display/intel_display_params.o \ display/intel_display_power.o \ display/intel_display_power_map.o \ display/intel_display_power_well.o \ diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 53e5c33e08c3..f2c84ae52217 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -19,6 +19,7 @@ #include "intel_cdclk.h" #include "intel_display_device.h" #include "intel_display_limits.h" +#include "intel_display_params.h" #include "intel_display_power.h" #include "intel_dpll_mgr.h" #include "intel_fbc.h" @@ -517,6 +518,7 @@ struct intel_display { struct intel_hotplug hotplug; struct intel_opregion opregion; struct intel_overlay *overlay; + struct intel_display_params params; struct intel_vbt_data vbt; struct intel_wm wm; }; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 5d2f4fc5709b..42bd352f9fee 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -17,6 +17,7 @@ #include "intel_de.h" #include "intel_crtc_state_dump.h" #include "intel_display_debugfs.h" +#include "intel_display_debugfs_params.h" #include "intel_display_power.h" #include "intel_display_power_well.h" #include "intel_display_types.h" @@ -1111,6 +1112,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) intel_hpd_debugfs_register(i915); intel_psr_debugfs_register(i915); intel_wm_debugfs_register(i915); + intel_display_debugfs_params(i915); } static int i915_panel_show(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c new file mode 100644 index 000000000000..b7e68eb62452 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include + +#include "intel_display_debugfs_params.h" +#include "i915_drv.h" +#include "intel_display_params.h" + +/* int param */ +static int intel_display_param_int_show(struct seq_file *m, void *data) +{ + int *value = m->private; + + seq_printf(m, "%d\n", *value); + + return 0; +} + +static int intel_display_param_int_open(struct inode *inode, struct file *file) +{ + return single_open(file, intel_display_param_int_show, inode->i_private); +} + +static ssize_t intel_display_param_int_write(struct file *file, + const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + int *value = m->private; + int ret; + + ret = kstrtoint_from_user(ubuf, len, 0, value); + if (ret) { + /* support boolean values too */ + bool b; + + ret = kstrtobool_from_user(ubuf, len, &b); + if (!ret) + *value = b; + } + + return ret ?: len; +} + +static const struct file_operations intel_display_param_int_fops = { + .owner = THIS_MODULE, + .open = intel_display_param_int_open, + .read = seq_read, + .write = intel_display_param_int_write, + .llseek = default_llseek, + .release = single_release, +}; + +static const struct file_operations intel_display_param_int_fops_ro = { + .owner = THIS_MODULE, + .open = intel_display_param_int_open, + .read = seq_read, + .llseek = default_llseek, + .release = single_release, +}; + +/* unsigned int param */ +static int intel_display_param_uint_show(struct seq_file *m, void *data) +{ + unsigned int *value = m->private; + + seq_printf(m, "%u\n", *value); + + return 0; +} + +static int intel_display_param_uint_open(struct inode *inode, struct file *file) +{ + return single_open(file, intel_display_param_uint_show, inode->i_private); +} + +static ssize_t intel_display_param_uint_write(struct file *file, + const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + unsigned int *value = m->private; + int ret; + + ret = kstrtouint_from_user(ubuf, len, 0, value); + if (ret) { + /* support boolean values too */ + bool b; + + ret = kstrtobool_from_user(ubuf, len, &b); + if (!ret) + *value = b; + } + + return ret ?: len; +} + +static const struct file_operations intel_display_param_uint_fops = { + .owner = THIS_MODULE, + .open = intel_display_param_uint_open, + .read = seq_read, + .write = intel_display_param_uint_write, + .llseek = default_llseek, + .release = single_release, +}; + +static const struct file_operations intel_display_param_uint_fops_ro = { + .owner = THIS_MODULE, + .open = intel_display_param_uint_open, + .read = seq_read, + .llseek = default_llseek, + .release = single_release, +}; + +#define RO(mode) (((mode) & 0222) == 0) + +__maybe_unused static struct dentry * +intel_display_debugfs_create_int(const char *name, umode_t mode, + struct dentry *parent, int *value) +{ + return debugfs_create_file_unsafe(name, mode, parent, value, + RO(mode) ? &intel_display_param_int_fops_ro : + &intel_display_param_int_fops); +} + +__maybe_unused static struct dentry * +intel_display_debugfs_create_uint(const char *name, umode_t mode, + struct dentry *parent, unsigned int *value) +{ + return debugfs_create_file_unsafe(name, mode, parent, value, + RO(mode) ? &intel_display_param_uint_fops_ro : + &intel_display_param_uint_fops); +} + +#define _intel_display_param_create_file(parent, name, mode, valp) \ + do { \ + if (mode) \ + _Generic(valp, \ + bool * : debugfs_create_bool, \ + int * : intel_display_debugfs_create_int, \ + unsigned int * : intel_display_debugfs_create_uint, \ + unsigned long * : debugfs_create_ulong, \ + char ** : debugfs_create_str) \ + (name, mode, parent, valp); \ + } while (0) + +/* add a subdirectory with files for each intel display param */ +void intel_display_debugfs_params(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + struct dentry *dir; + char dirname[16]; + + snprintf(dirname, sizeof(dirname), "%s_params", i915->drm.driver->name); + dir = debugfs_lookup(dirname, minor->debugfs_root); + if (!dir) + dir = debugfs_create_dir(dirname, minor->debugfs_root); + if (IS_ERR(dir)) + return; + + /* + * Note: We could create files for params needing special handling + * here. Set mode in params to 0 to skip the generic create file, or + * just let the generic create file fail silently with -EEXIST. + */ + +#define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \ + dir, #x, mode, &i915->display.params.x); + INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER); +#undef REGISTER +} diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h new file mode 100644 index 000000000000..1e9945a4044c --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_DEBUGFS_PARAMS__ +#define __INTEL_DISPLAY_DEBUGFS_PARAMS__ + +struct drm_i915_private; + +void intel_display_debugfs_params(struct drm_i915_private *i915); + +#endif /* __INTEL_DISPLAY_DEBUGFS_PARAMS__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 2b1ec23ba9c3..e80842d1e7c7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -12,6 +12,7 @@ #include "intel_de.h" #include "intel_display.h" #include "intel_display_device.h" +#include "intel_display_params.h" #include "intel_display_power.h" #include "intel_display_reg_defs.h" #include "intel_fbc.h" @@ -937,6 +938,13 @@ void intel_display_device_probe(struct drm_i915_private *i915) DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel; DISPLAY_RUNTIME_INFO(i915)->ip.step = step; } + + intel_display_params_copy(&i915->display.params); +} + +void intel_display_device_remove(struct drm_i915_private *i915) +{ + intel_display_params_free(&i915->display.params); } static void __intel_display_device_info_runtime_init(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 5b5c0e53307f..4299cc452e05 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -161,6 +161,7 @@ struct intel_display_device_info { bool intel_display_device_enabled(struct drm_i915_private *i915); void intel_display_device_probe(struct drm_i915_private *i915); +void intel_display_device_remove(struct drm_i915_private *i915); void intel_display_device_info_runtime_init(struct drm_i915_private *i915); void intel_display_device_info_print(const struct intel_display_device_info *info, diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c new file mode 100644 index 000000000000..91953ae27144 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "intel_display_params.h" +#include "i915_drv.h" + +#define intel_display_param_named(name, T, perm, desc) \ + module_param_named(name, intel_display_modparams.name, T, perm); \ + MODULE_PARM_DESC(name, desc) +#define intel_display_param_named_unsafe(name, T, perm, desc) \ + module_param_named_unsafe(name, intel_display_modparams.name, T, perm); \ + MODULE_PARM_DESC(name, desc) + +static struct intel_display_params intel_display_modparams __read_mostly = { +#define MEMBER(T, member, value, ...) .member = (value), + INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER) +#undef MEMBER +}; +/* + * Note: As a rule, keep module parameter sysfs permissions read-only + * 0400. Runtime changes are only supported through i915 debugfs. + * + * For any exceptions requiring write access and runtime changes through module + * parameter sysfs, prevent debugfs file creation by setting the parameter's + * debugfs mode to 0. + */ + +__maybe_unused static void _param_dup_charp(char **valp) +{ + *valp = kstrdup(*valp ? *valp : "", GFP_ATOMIC); +} + +__maybe_unused static void _param_nop(void *valp) +{ +} + +#define _param_dup(valp) \ + _Generic(valp, \ + char ** : _param_dup_charp, \ + default : _param_nop) \ + (valp) + +void intel_display_params_copy(struct intel_display_params *dest) +{ + *dest = intel_display_modparams; +#define DUP(T, x, ...) _param_dup(&dest->x); + INTEL_DISPLAY_PARAMS_FOR_EACH(DUP); +#undef DUP +} + +__maybe_unused static void _param_free_charp(char **valp) +{ + kfree(*valp); + *valp = NULL; +} + +#define _param_free(valp) \ + _Generic(valp, \ + char ** : _param_free_charp, \ + default : _param_nop) \ + (valp) + +/* free the allocated members, *not* the passed in params itself */ +void intel_display_params_free(struct intel_display_params *params) +{ +#define FREE(T, x, ...) _param_free(¶ms->x); + INTEL_DISPLAY_PARAMS_FOR_EACH(FREE); +#undef FREE +} diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h new file mode 100644 index 000000000000..9f4f45d410a3 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _INTEL_DISPLAY_PARAMS_H_ +#define _INTEL_DISPLAY_PARAMS_H_ + +struct drm_printer; + +/* + * Invoke param, a function-like macro, for each intel display param, with + * arguments: + * + * param(type, name, value, mode) + * + * type: parameter type, one of {bool, int, unsigned int, unsigned long, char *} + * name: name of the parameter + * value: initial/default value of the parameter + * mode: debugfs file permissions, one of {0400, 0600, 0}, use 0 to not create + * debugfs file + */ +#define INTEL_DISPLAY_PARAMS_FOR_EACH(param) /* empty define to avoid build failure */ + +#define MEMBER(T, member, ...) T member; +struct intel_display_params { + INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER); +}; +#undef MEMBER + +void intel_display_params_copy(struct intel_display_params *dest); +void intel_display_params_free(struct intel_display_params *params); + +#endif diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index f30a0861541c..3d86db5638fc 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -908,6 +908,8 @@ static void i915_driver_release(struct drm_device *dev) intel_runtime_pm_driver_release(rpm); i915_driver_late_release(dev_priv); + + intel_display_device_remove(dev_priv); } static int i915_driver_open(struct drm_device *dev, struct drm_file *file) From 7a61a6aa59e479ee22a859fe4054973d3aa6c640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:48 +0300 Subject: [PATCH 0070/7721] drm/i915/display: Dump also display parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPU error dump contained all module parameters. If we are moving display parameters to intel_display_params.[ch] they are not dumped into GPU error dump. This patch is adding moved display parameters back to GPU error dump. Display parameters are also included in i915_capabilities v2: Add parameters to i915_capabilities as well Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-3-jouni.hogander@intel.com --- .../drm/i915/display/intel_display_params.c | 57 +++++++++++++++++++ .../drm/i915/display/intel_display_params.h | 3 + drivers/gpu/drm/i915/i915_debugfs.c | 3 + drivers/gpu/drm/i915/i915_gpu_error.c | 3 + drivers/gpu/drm/i915/i915_gpu_error.h | 2 + 5 files changed, 68 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 91953ae27144..11ee73a98b5b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -27,6 +27,63 @@ static struct intel_display_params intel_display_modparams __read_mostly = { * debugfs mode to 0. */ +__maybe_unused +static void _param_print_bool(struct drm_printer *p, const char *driver_name, + const char *name, bool val) +{ + drm_printf(p, "%s.%s=%s\n", driver_name, name, str_yes_no(val)); +} + +__maybe_unused +static void _param_print_int(struct drm_printer *p, const char *driver_name, + const char *name, int val) +{ + drm_printf(p, "%s.%s=%d\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_uint(struct drm_printer *p, const char *driver_name, + const char *name, unsigned int val) +{ + drm_printf(p, "%s.%s=%u\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_ulong(struct drm_printer *p, const char *driver_name, + const char *name, unsigned long val) +{ + drm_printf(p, "%s.%s=%lu\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_charp(struct drm_printer *p, const char *driver_name, + const char *name, const char *val) +{ + drm_printf(p, "%s.%s=%s\n", driver_name, name, val); +} + +#define _param_print(p, driver_name, name, val) \ + _Generic(val, \ + bool : _param_print_bool, \ + int : _param_print_int, \ + unsigned int : _param_print_uint, \ + unsigned long : _param_print_ulong, \ + char * : _param_print_charp)(p, driver_name, name, val) + +/** + * intel_display_params_dump - dump intel display modparams + * @i915: i915 device + * @p: the &drm_printer + * + * Pretty printer for i915 modparams. + */ +void intel_display_params_dump(struct drm_i915_private *i915, struct drm_printer *p) +{ +#define PRINT(T, x, ...) _param_print(p, i915->drm.driver->name, #x, i915->display.params.x); + INTEL_DISPLAY_PARAMS_FOR_EACH(PRINT); +#undef PRINT +} + __maybe_unused static void _param_dup_charp(char **valp) { *valp = kstrdup(*valp ? *valp : "", GFP_ATOMIC); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 9f4f45d410a3..eac66042da4d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -7,6 +7,7 @@ #define _INTEL_DISPLAY_PARAMS_H_ struct drm_printer; +struct drm_i915_private; /* * Invoke param, a function-like macro, for each intel display param, with @@ -28,6 +29,8 @@ struct intel_display_params { }; #undef MEMBER +void intel_display_params_dump(struct drm_i915_private *i915, + struct drm_printer *p); void intel_display_params_copy(struct intel_display_params *dest); void intel_display_params_free(struct intel_display_params *params); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e9b79c2c37d8..af0077f6a6d0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -32,6 +32,8 @@ #include +#include "display/intel_display_params.h" + #include "gem/i915_gem_context.h" #include "gt/intel_gt.h" #include "gt/intel_gt_buffer_pool.h" @@ -74,6 +76,7 @@ static int i915_capabilities(struct seq_file *m, void *data) kernel_param_lock(THIS_MODULE); i915_params_dump(&i915->params, &p); + intel_display_params_dump(i915, &p); kernel_param_unlock(THIS_MODULE); return 0; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f4ebcfb70289..53fff687b00e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -660,6 +660,7 @@ static void err_print_params(struct drm_i915_error_state_buf *m, struct drm_printer p = i915_error_printer(m); i915_params_dump(params, &p); + intel_display_params_dump(m->i915, &p); } static void err_print_pciid(struct drm_i915_error_state_buf *m, @@ -1027,6 +1028,7 @@ static void i915_vma_coredump_free(struct i915_vma_coredump *vma) static void cleanup_params(struct i915_gpu_coredump *error) { i915_params_free(&error->params); + intel_display_params_free(&error->display_params); } static void cleanup_uc(struct intel_uc_coredump *uc) @@ -1979,6 +1981,7 @@ static void capture_gen(struct i915_gpu_coredump *error) error->suspend_count = i915->suspend_count; i915_params_copy(&error->params, &i915->params); + intel_display_params_copy(&error->display_params); memcpy(&error->device_info, INTEL_INFO(i915), sizeof(error->device_info)); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 9f5971f5e980..4ce227f7e1e1 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -15,6 +15,7 @@ #include #include "display/intel_display_device.h" +#include "display/intel_display_params.h" #include "gt/intel_engine.h" #include "gt/intel_gt_types.h" #include "gt/uc/intel_uc_fw.h" @@ -214,6 +215,7 @@ struct i915_gpu_coredump { struct intel_display_runtime_info display_runtime_info; struct intel_driver_caps driver_caps; struct i915_params params; + struct intel_display_params display_params; struct intel_overlay_error_state *overlay; From 6f4f8aef7e4220a3369b40a94f694ecc014adf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:49 +0300 Subject: [PATCH 0071/7721] drm/i915/display: Move enable_fbc module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-4-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/i9xx_wm.c | 2 +- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 3 ++- drivers/gpu/drm/i915/display/intel_fbc.c | 10 +++++----- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index af0c79a4c9a4..b37c0d02d500 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -2993,7 +2993,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv, /* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */ if (DISPLAY_VER(dev_priv) == 5 && HAS_FBC(dev_priv) && - dev_priv->params.enable_fbc && !merged->fbc_wm_enabled) { + dev_priv->display.params.enable_fbc && !merged->fbc_wm_enabled) { for (level = 2; level < num_levels; level++) { struct intel_wm_level *wm = &merged->wm[level]; diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 11ee73a98b5b..330613cd64db 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -27,6 +27,10 @@ static struct intel_display_params intel_display_modparams __read_mostly = { * debugfs mode to 0. */ +intel_display_param_named_unsafe(enable_fbc, int, 0400, + "Enable frame buffer compression for power savings " + "(default: -1 (use per-chip default))"); + __maybe_unused static void _param_print_bool(struct drm_printer *p, const char *driver_name, const char *name, bool val) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index eac66042da4d..198b03da8055 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -21,7 +21,8 @@ struct drm_i915_private; * mode: debugfs file permissions, one of {0400, 0600, 0}, use 0 to not create * debugfs file */ -#define INTEL_DISPLAY_PARAMS_FOR_EACH(param) /* empty define to avoid build failure */ +#define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ + param(int, enable_fbc, -1, 0600) \ #define MEMBER(T, member, ...) T member; struct intel_display_params { diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 4820d21cc942..bde12fe62275 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1174,7 +1174,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (!i915->params.enable_fbc) { + if (!i915->display.params.enable_fbc) { plane_state->no_fbc_reason = "disabled per module param or by default"; return 0; } @@ -1751,8 +1751,8 @@ void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *i915) */ static int intel_sanitize_fbc_option(struct drm_i915_private *i915) { - if (i915->params.enable_fbc >= 0) - return !!i915->params.enable_fbc; + if (i915->display.params.enable_fbc >= 0) + return !!i915->display.params.enable_fbc; if (!HAS_FBC(i915)) return 0; @@ -1824,9 +1824,9 @@ void intel_fbc_init(struct drm_i915_private *i915) if (need_fbc_vtd_wa(i915)) DISPLAY_RUNTIME_INFO(i915)->fbc_mask = 0; - i915->params.enable_fbc = intel_sanitize_fbc_option(i915); + i915->display.params.enable_fbc = intel_sanitize_fbc_option(i915); drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n", - i915->params.enable_fbc); + i915->display.params.enable_fbc); for_each_fbc_id(i915, fbc_id) i915->display.fbc[fbc_id] = intel_fbc_create(i915, fbc_id); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 036c4c3ed6ed..42700b854b79 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -72,10 +72,6 @@ i915_param_named_unsafe(enable_dc, int, 0400, "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); -i915_param_named_unsafe(enable_fbc, int, 0400, - "Enable frame buffer compression for power savings " - "(default: -1 (use per-chip default))"); - i915_param_named_unsafe(lvds_channel_mode, int, 0400, "Specify LVDS channel mode " "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index d5194b039aab..e674de29f92c 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -52,7 +52,6 @@ struct drm_printer; param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ - param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, enable_dpt, true, 0400) \ param(bool, psr_safest_params, false, 0400) \ From 942d654171bdaf41bc5c298857c5a342031d8154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:50 +0300 Subject: [PATCH 0072/7721] drm/i915/display: Move psr related module parameters under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move psr related module parameters under display. Also fix error in enable_psr2_sel_fetch module parameter descrtiption. It was saying disabled by default while it's vice versa. Also psr_safest_params was missing default value in description. This is now added. v2: - Fix enable_psr2_sel_fetch description. - Add default value into psr_safest_params description. Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-5-jouni.hogander@intel.com --- .../gpu/drm/i915/display/intel_display_params.c | 16 ++++++++++++++++ .../gpu/drm/i915/display/intel_display_params.h | 5 +++++ drivers/gpu/drm/i915/display/intel_psr.c | 14 +++++++------- drivers/gpu/drm/i915/i915_params.c | 15 --------------- drivers/gpu/drm/i915/i915_params.h | 3 --- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 330613cd64db..0e86d0d10bfa 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -31,6 +31,22 @@ intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); +intel_display_param_named_unsafe(enable_psr, int, 0400, + "Enable PSR " + "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " + "Default: -1 (use per-chip default)"); + +intel_display_param_named(psr_safest_params, bool, 0400, + "Replace PSR VBT parameters by the safest and not optimal ones. This " + "is helpful to detect if PSR issues are related to bad values set in " + " VBT. (0=use VBT parameters, 1=use safest parameters)" + "Default: 0"); + +intel_display_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400, + "Enable PSR2 selective fetch " + "(0=disabled, 1=enabled) " + "Default: 1"); + __maybe_unused static void _param_print_bool(struct drm_printer *p, const char *driver_name, const char *name, bool val) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 198b03da8055..45a4d38d13e7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -6,6 +6,8 @@ #ifndef _INTEL_DISPLAY_PARAMS_H_ #define _INTEL_DISPLAY_PARAMS_H_ +#include + struct drm_printer; struct drm_i915_private; @@ -23,6 +25,9 @@ struct drm_i915_private; */ #define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ param(int, enable_fbc, -1, 0600) \ + param(int, enable_psr, -1, 0600) \ + param(bool, psr_safest_params, false, 0400) \ + param(bool, enable_psr2_sel_fetch, true, 0400) \ #define MEMBER(T, member, ...) T member; struct intel_display_params { diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 4f1f31fc9529..ecd24a0b86cb 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -179,9 +179,9 @@ static bool psr_global_enabled(struct intel_dp *intel_dp) switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DEFAULT: - if (i915->params.enable_psr == -1) + if (i915->display.params.enable_psr == -1) return connector->panel.vbt.psr.enable; - return i915->params.enable_psr; + return i915->display.params.enable_psr; case I915_PSR_DEBUG_DISABLE: return false; default: @@ -198,7 +198,7 @@ static bool psr2_global_enabled(struct intel_dp *intel_dp) case I915_PSR_DEBUG_FORCE_PSR1: return false; default: - if (i915->params.enable_psr == 1) + if (i915->display.params.enable_psr == 1) return false; return true; } @@ -606,7 +606,7 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 11) val |= EDP_PSR_TP4_TIME_0us; - if (dev_priv->params.psr_safest_params) { + if (dev_priv->display.params.psr_safest_params) { val |= EDP_PSR_TP1_TIME_2500us; val |= EDP_PSR_TP2_TP3_TIME_2500us; goto check_tp3_sel; @@ -700,7 +700,7 @@ static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 val = 0; - if (dev_priv->params.psr_safest_params) + if (dev_priv->display.params.psr_safest_params) return EDP_PSR2_TP2_TIME_2500us; if (connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us >= 0 && @@ -943,7 +943,7 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (!dev_priv->params.enable_psr2_sel_fetch && + if (!dev_priv->display.params.enable_psr2_sel_fetch && intel_dp->psr.debug != I915_PSR_DEBUG_ENABLE_SEL_FETCH) { drm_dbg_kms(&dev_priv->drm, "PSR2 sel fetch not enabled, disabled by parameter\n"); @@ -1056,7 +1056,7 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, fast_wake_lines > max_wake_lines) return false; - if (i915->params.psr_safest_params) + if (i915->display.params.psr_safest_params) io_wake_lines = fast_wake_lines = max_wake_lines; /* According to Bspec lower limit should be set as 7 lines. */ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 42700b854b79..c65e3314ae48 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -102,21 +102,6 @@ i915_param_named_unsafe(enable_hangcheck, bool, 0400, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -i915_param_named_unsafe(enable_psr, int, 0400, - "Enable PSR " - "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " - "Default: -1 (use per-chip default)"); - -i915_param_named(psr_safest_params, bool, 0400, - "Replace PSR VBT parameters by the safest and not optimal ones. This " - "is helpful to detect if PSR issues are related to bad values set in " - " VBT. (0=use VBT parameters, 1=use safest parameters)"); - -i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400, - "Enable PSR2 selective fetch " - "(0=disabled, 1=enabled) " - "Default: 0"); - i915_param_named_unsafe(enable_sagv, bool, 0600, "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index e674de29f92c..47a05c4a8e89 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -52,10 +52,7 @@ struct drm_printer; param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ - param(int, enable_psr, -1, 0600) \ param(bool, enable_dpt, true, 0400) \ - param(bool, psr_safest_params, false, 0400) \ - param(bool, enable_psr2_sel_fetch, true, 0400) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ From 29292bc6cc3785d3da6b733a413e387282664f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:51 +0300 Subject: [PATCH 0073/7721] drm/i915/display: Move vbt_firmware module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-6-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_opregion.c | 2 +- drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 0e86d0d10bfa..d00ea5cda432 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -27,6 +27,9 @@ static struct intel_display_params intel_display_modparams __read_mostly = { * debugfs mode to 0. */ +intel_display_param_named_unsafe(vbt_firmware, charp, 0400, + "Load VBT from specified file under /lib/firmware"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 45a4d38d13e7..e51e8a1960eb 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -24,6 +24,7 @@ struct drm_i915_private; * debugfs file */ #define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ + param(char *, vbt_firmware, NULL, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 84078fb82b2f..1ce785db6a5e 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -841,7 +841,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) { struct intel_opregion *opregion = &dev_priv->display.opregion; const struct firmware *fw = NULL; - const char *name = dev_priv->params.vbt_firmware; + const char *name = dev_priv->display.params.vbt_firmware; int ret; if (!name || !*name) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index c65e3314ae48..9d0535d774c9 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -87,9 +87,6 @@ i915_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, i915_param_named_unsafe(reset, uint, 0400, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])"); -i915_param_named_unsafe(vbt_firmware, charp, 0400, - "Load VBT from specified file under /lib/firmware"); - #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) i915_param_named(error_capture, bool, 0400, "Record the GPU state following a hang. " diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 47a05c4a8e89..37a1d31a233c 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -46,7 +46,6 @@ struct drm_printer; * debugfs file */ #define I915_PARAMS_FOR_EACH(param) \ - param(char *, vbt_firmware, NULL, 0400) \ param(int, modeset, -1, 0400) \ param(int, lvds_channel_mode, 0, 0400) \ param(int, panel_use_ssc, -1, 0600) \ From d541697e8043b7b5d8e1f39b1c046dc140406e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:52 +0300 Subject: [PATCH 0074/7721] drm/i915/display: Move lvds_channel_mode module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-7-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_lvds.c | 4 ++-- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index d00ea5cda432..91e2b5056d63 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -30,6 +30,10 @@ static struct intel_display_params intel_display_modparams __read_mostly = { intel_display_param_named_unsafe(vbt_firmware, charp, 0400, "Load VBT from specified file under /lib/firmware"); +intel_display_param_named_unsafe(lvds_channel_mode, int, 0400, + "Specify LVDS channel mode " + "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index e51e8a1960eb..09bd6614b813 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -25,6 +25,7 @@ struct drm_i915_private; */ #define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ param(char *, vbt_firmware, NULL, 0400) \ + param(int, lvds_channel_mode, 0, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 2a4ca7e65775..4b114fde57b1 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -794,8 +794,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) unsigned int val; /* use the module option value if specified */ - if (i915->params.lvds_channel_mode > 0) - return i915->params.lvds_channel_mode == 2; + if (i915->display.params.lvds_channel_mode > 0) + return i915->display.params.lvds_channel_mode == 2; /* single channel LVDS is limited to 112 MHz */ if (fixed_mode->clock > 112999) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 9d0535d774c9..ea55cc2c4854 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -72,10 +72,6 @@ i915_param_named_unsafe(enable_dc, int, 0400, "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); -i915_param_named_unsafe(lvds_channel_mode, int, 0400, - "Specify LVDS channel mode " - "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); - i915_param_named_unsafe(panel_use_ssc, int, 0400, "Use Spread Spectrum Clock with panels [LVDS/eDP] " "(default: auto from VBT)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 37a1d31a233c..03ec2c2b589d 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, lvds_channel_mode, 0, 0400) \ param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ From 94232d1637c5675f19a434e5118d0d6718ee310a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:53 +0300 Subject: [PATCH 0075/7721] drm/i915/display: Move panel_use_ssc module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-8-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_panel.c | 4 ++-- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 91e2b5056d63..0813adfa5651 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -34,6 +34,10 @@ intel_display_param_named_unsafe(lvds_channel_mode, int, 0400, "Specify LVDS channel mode " "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); +intel_display_param_named_unsafe(panel_use_ssc, int, 0400, + "Use Spread Spectrum Clock with panels [LVDS/eDP] " + "(default: auto from VBT)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 09bd6614b813..ceed4af192c9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -26,6 +26,7 @@ struct drm_i915_private; #define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ param(char *, vbt_firmware, NULL, 0400) \ param(int, lvds_channel_mode, 0, 0400) \ + param(int, panel_use_ssc, -1, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 483beedac5b8..0d8e5320a4f8 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -46,8 +46,8 @@ bool intel_panel_use_ssc(struct drm_i915_private *i915) { - if (i915->params.panel_use_ssc >= 0) - return i915->params.panel_use_ssc != 0; + if (i915->display.params.panel_use_ssc >= 0) + return i915->display.params.panel_use_ssc != 0; return i915->display.vbt.lvds_use_ssc && !intel_has_quirk(i915, QUIRK_LVDS_SSC_DISABLE); } diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index ea55cc2c4854..4123424b2c2e 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -72,10 +72,6 @@ i915_param_named_unsafe(enable_dc, int, 0400, "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); -i915_param_named_unsafe(panel_use_ssc, int, 0400, - "Use Spread Spectrum Clock with panels [LVDS/eDP] " - "(default: auto from VBT)"); - i915_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, "Override/Ignore selection of SDVO panel mode in the VBT " "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 03ec2c2b589d..0bd365889e73 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ From 5fb2e673c76d27436b02cef6c6f9669e106c1b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:54 +0300 Subject: [PATCH 0076/7721] drm/i915/display: Move vbt_sdvo_panel_type module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-9-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 2 +- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 4e8f1e91bb08..70c0491aac42 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1116,7 +1116,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, struct drm_display_mode *panel_fixed_mode; int index; - index = i915->params.vbt_sdvo_panel_type; + index = i915->display.params.vbt_sdvo_panel_type; if (index == -2) { drm_dbg_kms(&i915->drm, "Ignore SDVO panel mode from BIOS VBT tables.\n"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 0813adfa5651..d11c74ba001e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -38,6 +38,10 @@ intel_display_param_named_unsafe(panel_use_ssc, int, 0400, "Use Spread Spectrum Clock with panels [LVDS/eDP] " "(default: auto from VBT)"); +intel_display_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, + "Override/Ignore selection of SDVO panel mode in the VBT " + "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index ceed4af192c9..03dea0ba81d1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -27,6 +27,7 @@ struct drm_i915_private; param(char *, vbt_firmware, NULL, 0400) \ param(int, lvds_channel_mode, 0, 0400) \ param(int, panel_use_ssc, -1, 0600) \ + param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 4123424b2c2e..d0abcbd526a7 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -72,10 +72,6 @@ i915_param_named_unsafe(enable_dc, int, 0400, "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); -i915_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, - "Override/Ignore selection of SDVO panel mode in the VBT " - "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); - i915_param_named_unsafe(reset, uint, 0400, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 0bd365889e73..1ea332dfbb5d 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ param(bool, enable_sagv, true, 0600) \ From 0deee706f116778429d03131efb7d29273442d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:55 +0300 Subject: [PATCH 0077/7721] drm/i915/display: Move enable_dc module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-10-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 5 +++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/i915_params.c | 5 ----- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index d11c74ba001e..60fa0bbce77d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -42,6 +42,11 @@ intel_display_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, "Override/Ignore selection of SDVO panel mode in the VBT " "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); +intel_display_param_named_unsafe(enable_dc, int, 0400, + "Enable power-saving display C-states. " + "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " + "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 03dea0ba81d1..2cca06ad7d71 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -28,6 +28,7 @@ struct drm_i915_private; param(int, lvds_channel_mode, 0, 0400) \ param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ + param(int, enable_dc, -1, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e25785ae1c20..4832eb8da080 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1020,7 +1020,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) sanitize_disable_power_well_option(dev_priv, dev_priv->params.disable_power_well); power_domains->allowed_dc_mask = - get_allowed_dc_mask(dev_priv, dev_priv->params.enable_dc); + get_allowed_dc_mask(dev_priv, dev_priv->display.params.enable_dc); power_domains->target_dc_state = sanitize_target_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index d0abcbd526a7..3d370e43df3c 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -67,11 +67,6 @@ i915_param_named(modeset, int, 0400, "Use kernel modesetting [KMS] (0=disable, " "1=on, -1=force vga console preference [default])"); -i915_param_named_unsafe(enable_dc, int, 0400, - "Enable power-saving display C-states. " - "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " - "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); - i915_param_named_unsafe(reset, uint, 0400, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 1ea332dfbb5d..c3487b9d6937 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ From 04da42b4cc9429d8fff854d144f80396cbdecb46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:56 +0300 Subject: [PATCH 0078/7721] drm/i915/display: Move enable_dpt module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-11-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_dpt.c | 6 ++++-- drivers/gpu/drm/i915/display/intel_fb.c | 2 +- drivers/gpu/drm/i915/display/skl_universal_plane.c | 2 +- drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 60fa0bbce77d..9067ffd6d2a9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -47,6 +47,9 @@ intel_display_param_named_unsafe(enable_dc, int, 0400, "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); +intel_display_param_named_unsafe(enable_dpt, bool, 0400, + "Enable display page table (DPT) (default: true)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 2cca06ad7d71..e5f139239f23 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -29,6 +29,7 @@ struct drm_i915_private; param(int, panel_use_ssc, -1, 0600) \ param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ + param(bool, enable_dpt, true, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index 48582b31b7f7..2b067cb952f0 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -332,11 +332,13 @@ void intel_dpt_configure(struct intel_crtc *crtc) intel_de_rmw(i915, PLANE_CHICKEN(pipe, plane_id), PLANE_CHICKEN_DISABLE_DPT, - i915->params.enable_dpt ? 0 : PLANE_CHICKEN_DISABLE_DPT); + i915->display.params.enable_dpt ? 0 : + PLANE_CHICKEN_DISABLE_DPT); } } else if (DISPLAY_VER(i915) == 13) { intel_de_rmw(i915, CHICKEN_MISC_2, CHICKEN_MISC_DISABLE_DPT, - i915->params.enable_dpt ? 0 : CHICKEN_MISC_DISABLE_DPT); + i915->display.params.enable_dpt ? 0 : + CHICKEN_MISC_DISABLE_DPT); } } diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index e1d298efc510..e1db7a3afd1a 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -764,7 +764,7 @@ bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) bool intel_fb_uses_dpt(const struct drm_framebuffer *fb) { - return fb && to_i915(fb->dev)->params.enable_dpt && + return fb && to_i915(fb->dev)->display.params.enable_dpt && intel_fb_modifier_uses_dpt(to_i915(fb->dev), fb->modifier); } diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 49e9d40d5e67..68035675ae3c 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -2488,7 +2488,7 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, goto error; } - if (!dev_priv->params.enable_dpt && + if (!dev_priv->display.params.enable_dpt && intel_fb_modifier_uses_dpt(dev_priv, fb->modifier)) { drm_dbg_kms(&dev_priv->drm, "DPT disabled, skipping initial FB\n"); goto error; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 3d370e43df3c..773a0a709fc6 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -95,9 +95,6 @@ i915_param_named_unsafe(disable_power_well, int, 0400, i915_param_named_unsafe(enable_ips, int, 0400, "Enable IPS (default: true)"); -i915_param_named_unsafe(enable_dpt, bool, 0400, - "Enable display page table (DPT) (default: true)"); - i915_param_named_unsafe(load_detect_test, bool, 0400, "Force-enable the VGA load detect code for testing (default:false). " "For developers only."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index c3487b9d6937..b8728990cb8b 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(bool, enable_dpt, true, 0400) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ From 5067ec645ece12421d802e0dd9510e89122efcc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:57 +0300 Subject: [PATCH 0079/7721] drm/i915/display: Move enable_sagv module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move enable_sagv module parameter under display and change the parameter permissions to non-writblase (0400) v2: Change permissions to 0400 Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-12-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/skl_watermark.c | 5 +++-- drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 9067ffd6d2a9..a98df2afc996 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -50,6 +50,9 @@ intel_display_param_named_unsafe(enable_dc, int, 0400, intel_display_param_named_unsafe(enable_dpt, bool, 0400, "Enable display page table (DPT) (default: true)"); +intel_display_param_named_unsafe(enable_sagv, bool, 0400, + "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index e5f139239f23..0a7ac416403a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -30,6 +30,7 @@ struct drm_i915_private; param(int, vbt_sdvo_panel_type, -1, 0400) \ param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ + param(bool, enable_sagv, true, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 99b8ccdc3dfa..56588d6e24ae 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -412,7 +412,7 @@ static bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); - if (!i915->params.enable_sagv) + if (!i915->display.params.enable_sagv) return false; if (DISPLAY_VER(i915) >= 12) @@ -3702,7 +3702,8 @@ static int intel_sagv_status_show(struct seq_file *m, void *unused) }; seq_printf(m, "SAGV available: %s\n", str_yes_no(intel_has_sagv(i915))); - seq_printf(m, "SAGV modparam: %s\n", str_enabled_disabled(i915->params.enable_sagv)); + seq_printf(m, "SAGV modparam: %s\n", + str_enabled_disabled(i915->display.params.enable_sagv)); seq_printf(m, "SAGV status: %s\n", sagv_status[i915->display.sagv.status]); seq_printf(m, "SAGV block time: %d usec\n", i915->display.sagv.block_time_us); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 773a0a709fc6..51e706f6e57e 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -82,9 +82,6 @@ i915_param_named_unsafe(enable_hangcheck, bool, 0400, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -i915_param_named_unsafe(enable_sagv, bool, 0600, - "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); - i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index b8728990cb8b..066f15783580 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ From bfcda58ba1555ac0596d851ae6d748cdebff1af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:58 +0300 Subject: [PATCH 0080/7721] drm/i915/display: Move disable_power_well module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-13-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_display_power.c | 12 ++++++------ drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index a98df2afc996..79a212dded80 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -53,6 +53,10 @@ intel_display_param_named_unsafe(enable_dpt, bool, 0400, intel_display_param_named_unsafe(enable_sagv, bool, 0400, "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); +intel_display_param_named_unsafe(disable_power_well, int, 0400, + "Disable display power wells when possible " + "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 0a7ac416403a..aadbef664965 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -31,6 +31,7 @@ struct drm_i915_private; param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ param(bool, enable_sagv, true, 0600) \ + param(int, disable_power_well, -1, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 4832eb8da080..e390595d7341 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -967,7 +967,7 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, DISPLAY_VER(dev_priv) >= 11 ? DC_STATE_EN_DC9 : 0; - if (!dev_priv->params.disable_power_well) + if (!dev_priv->display.params.disable_power_well) max_dc = 0; if (enable_dc >= 0 && enable_dc <= max_dc) { @@ -1016,9 +1016,9 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->display.power.domains; - dev_priv->params.disable_power_well = + dev_priv->display.params.disable_power_well = sanitize_disable_power_well_option(dev_priv, - dev_priv->params.disable_power_well); + dev_priv->display.params.disable_power_well); power_domains->allowed_dc_mask = get_allowed_dc_mask(dev_priv, dev_priv->display.params.enable_dc); @@ -1950,7 +1950,7 @@ void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume) intel_display_power_get(i915, POWER_DOMAIN_INIT); /* Disable power support if the user asked so. */ - if (!i915->params.disable_power_well) { + if (!i915->display.params.disable_power_well) { drm_WARN_ON(&i915->drm, power_domains->disable_wakeref); i915->display.power.domains.disable_wakeref = intel_display_power_get(i915, POWER_DOMAIN_INIT); @@ -1977,7 +1977,7 @@ void intel_power_domains_driver_remove(struct drm_i915_private *i915) fetch_and_zero(&i915->display.power.domains.init_wakeref); /* Remove the refcount we took to keep power well support disabled. */ - if (!i915->params.disable_power_well) + if (!i915->display.params.disable_power_well) intel_display_power_put(i915, POWER_DOMAIN_INIT, fetch_and_zero(&i915->display.power.domains.disable_wakeref)); @@ -2096,7 +2096,7 @@ void intel_power_domains_suspend(struct drm_i915_private *i915, bool s2idle) * Even if power well support was disabled we still want to disable * power wells if power domains must be deinitialized for suspend. */ - if (!i915->params.disable_power_well) + if (!i915->display.params.disable_power_well) intel_display_power_put(i915, POWER_DOMAIN_INIT, fetch_and_zero(&i915->display.power.domains.disable_wakeref)); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 51e706f6e57e..eab02f71a4e5 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -86,10 +86,6 @@ i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named_unsafe(disable_power_well, int, 0400, - "Disable display power wells when possible " - "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); - i915_param_named_unsafe(enable_ips, int, 0400, "Enable IPS (default: true)"); i915_param_named_unsafe(load_detect_test, bool, 0400, diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 066f15783580..060464df03c2 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ param(int, enable_guc, -1, 0400) \ From c39fc2aca32a93d88e4e90ec6f2148b3491ad88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:40:59 +0300 Subject: [PATCH 0081/7721] drm/i915/display: Move enable_ips module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move enable_ips module parameter under display and change it as boolean. v2: - Change enable_ip as boolean - Fix copy paste error (i915_param -> intel_display_param) Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-14-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/hsw_ips.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display_params.c | 2 ++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 2 -- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index 7dc38ac02092..611a7d6ef80c 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -193,7 +193,7 @@ bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) if (!hsw_crtc_supports_ips(crtc)) return false; - if (!i915->params.enable_ips) + if (!i915->display.params.enable_ips) return false; if (crtc_state->pipe_bpp > 24) @@ -329,7 +329,7 @@ static int hsw_ips_debugfs_status_show(struct seq_file *m, void *unused) wakeref = intel_runtime_pm_get(&i915->runtime_pm); seq_printf(m, "Enabled by kernel parameter: %s\n", - str_yes_no(i915->params.enable_ips)); + str_yes_no(i915->display.params.enable_ips)); if (DISPLAY_VER(i915) >= 8) { seq_puts(m, "Currently: unknown\n"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 79a212dded80..ce991ad20006 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -57,6 +57,8 @@ intel_display_param_named_unsafe(disable_power_well, int, 0400, "Disable display power wells when possible " "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); +intel_display_param_named_unsafe(enable_ips, bool, 0400, "Enable IPS (default: true)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index aadbef664965..8d51488e3b3e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -32,6 +32,7 @@ struct drm_i915_private; param(bool, enable_dpt, true, 0400) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ + param(bool, enable_ips, true, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index eab02f71a4e5..54dcce97da2a 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -86,8 +86,6 @@ i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named_unsafe(enable_ips, int, 0400, "Enable IPS (default: true)"); - i915_param_named_unsafe(load_detect_test, bool, 0400, "Force-enable the VGA load detect code for testing (default:false). " "For developers only."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 060464df03c2..18bb8a93e0e8 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ param(int, enable_guc, -1, 0400) \ param(int, guc_log_level, -1, 0400) \ From 5234105ea8ad0c2655b2cac398c3ae564528eff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:00 +0300 Subject: [PATCH 0082/7721] drm/i915/display: Move invert_brightness module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-15-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_backlight.c | 9 +++++---- drivers/gpu/drm/i915/display/intel_display_params.c | 7 +++++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 7 ------- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 2e8f17c04522..612d4cd9dacb 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -88,10 +88,10 @@ u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val) drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0); - if (i915->params.invert_brightness < 0) + if (i915->display.params.invert_brightness < 0) return val; - if (i915->params.invert_brightness > 0 || + if (i915->display.params.invert_brightness > 0 || intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)) { return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; } @@ -132,8 +132,9 @@ u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) drm_WARN_ON_ONCE(&i915->drm, panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); - if (i915->params.invert_brightness > 0 || - (i915->params.invert_brightness == 0 && intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS))) + if (i915->display.params.invert_brightness > 0 || + (i915->display.params.invert_brightness == 0 && + intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS))) val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min); return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max, diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index ce991ad20006..2d721afaba30 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -59,6 +59,13 @@ intel_display_param_named_unsafe(disable_power_well, int, 0400, intel_display_param_named_unsafe(enable_ips, bool, 0400, "Enable IPS (default: true)"); +intel_display_param_named_unsafe(invert_brightness, int, 0400, + "Invert backlight brightness " + "(-1 force normal, 0 machine defaults, 1 force inversion), please " + "report PCI device ID, subsystem vendor and subsystem device ID " + "to dri-devel@lists.freedesktop.org, if your machine needs it. " + "It will then be included in an upcoming module version."); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 8d51488e3b3e..4723b4522413 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -33,6 +33,7 @@ struct drm_i915_private; param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(bool, enable_ips, true, 0600) \ + param(int, invert_brightness, 0, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 54dcce97da2a..423fe54484e1 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -94,13 +94,6 @@ i915_param_named_unsafe(force_reset_modeset_test, bool, 0400, "Force a modeset during gpu reset for testing (default:false). " "For developers only."); -i915_param_named_unsafe(invert_brightness, int, 0400, - "Invert backlight brightness " - "(-1 force normal, 0 machine defaults, 1 force inversion), please " - "report PCI device ID, subsystem vendor and subsystem device ID " - "to dri-devel@lists.freedesktop.org, if your machine needs it. " - "It will then be included in an upcoming module version."); - i915_param_named(disable_display, bool, 0400, "Disable display (default: false)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 18bb8a93e0e8..ae0873443a65 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,6 @@ struct drm_printer; */ #define I915_PARAMS_FOR_EACH(param) \ param(int, modeset, -1, 0400) \ - param(int, invert_brightness, 0, 0600) \ param(int, enable_guc, -1, 0400) \ param(int, guc_log_level, -1, 0400) \ param(char *, guc_firmware_path, NULL, 0400) \ From 87706a67ad57725470a0512d26ea2aaca700e2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:01 +0300 Subject: [PATCH 0083/7721] drm/i915/display: Move edp_vswing module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-16-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display_params.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 6 ------ drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 70c0491aac42..69db1a3a1499 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1514,9 +1514,9 @@ parse_edp(struct drm_i915_private *i915, u8 vswing; /* Don't read from VBT if module parameter has valid value*/ - if (i915->params.edp_vswing) { + if (i915->display.params.edp_vswing) { panel->vbt.edp.low_vswing = - i915->params.edp_vswing == 1; + i915->display.params.edp_vswing == 1; } else { vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; panel->vbt.edp.low_vswing = vswing == 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 2d721afaba30..70a475223512 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -66,6 +66,12 @@ intel_display_param_named_unsafe(invert_brightness, int, 0400, "to dri-devel@lists.freedesktop.org, if your machine needs it. " "It will then be included in an upcoming module version."); +/* WA to get away with the default setting in VBT for early platforms.Will be removed */ +intel_display_param_named_unsafe(edp_vswing, int, 0400, + "Ignore/Override vswing pre-emph table selection from VBT " + "(0=use value from vbt [default], 1=low power swing(200mV)," + "2=default swing(400mV))"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 4723b4522413..10c79ce23063 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -34,6 +34,7 @@ struct drm_i915_private; param(int, disable_power_well, -1, 0400) \ param(bool, enable_ips, true, 0600) \ param(int, invert_brightness, 0, 0600) \ + param(int, edp_vswing, 0, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 423fe54484e1..6b9df9f9d842 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -111,12 +111,6 @@ i915_param_named(verbose_state_checks, bool, 0600, i915_param_named_unsafe(nuclear_pageflip, bool, 0400, "Force enable atomic functionality on platforms that don't have full support yet."); -/* WA to get away with the default setting in VBT for early platforms.Will be removed */ -i915_param_named_unsafe(edp_vswing, int, 0400, - "Ignore/Override vswing pre-emph table selection from VBT " - "(0=use value from vbt [default], 1=low power swing(200mV)," - "2=default swing(400mV))"); - i915_param_named_unsafe(enable_guc, int, 0400, "Enable GuC load for GuC submission and/or HuC load. " "Required functionality can be selected using bitmask values. " diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index ae0873443a65..c33edaee5032 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -55,7 +55,6 @@ struct drm_printer; param(char *, gsc_firmware_path, NULL, 0400) \ param(bool, memtest, false, 0400) \ param(int, mmio_debug, -IS_ENABLED(CONFIG_DRM_I915_DEBUG_MMIO), 0600) \ - param(int, edp_vswing, 0, 0400) \ param(unsigned int, reset, 3, 0600) \ param(unsigned int, inject_probe_failure, 0, 0) \ param(int, enable_dpcd_backlight, -1, 0600) \ From 5621e0652dc9eeb2be2f7784ceca50ddce1ff025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:02 +0300 Subject: [PATCH 0084/7721] drm/i915/display: Move enable_dpcd_backlight module parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-17-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c | 4 ++-- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 70a475223512..190ca12ce64b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -72,6 +72,10 @@ intel_display_param_named_unsafe(edp_vswing, int, 0400, "(0=use value from vbt [default], 1=low power swing(200mV)," "2=default swing(400mV))"); +intel_display_param_named(enable_dpcd_backlight, int, 0400, + "Enable support for DPCD backlight control" + "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 10c79ce23063..85d1128954e9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -35,6 +35,7 @@ struct drm_i915_private; param(bool, enable_ips, true, 0600) \ param(int, invert_brightness, 0, 0600) \ param(int, edp_vswing, 0, 0400) \ + param(int, enable_dpcd_backlight, -1, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 26ea7e9f1b89..4f58efdc688a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -146,7 +146,7 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) * HDR static metadata we need to start maintaining table of * ranges for such panels. */ - if (i915->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && + if (i915->display.params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type & BIT(HDMI_STATIC_METADATA_TYPE1))) { drm_info(&i915->drm, @@ -489,7 +489,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) /* Check the VBT and user's module parameters to figure out which * interfaces to probe */ - switch (i915->params.enable_dpcd_backlight) { + switch (i915->display.params.enable_dpcd_backlight) { case INTEL_DP_AUX_BACKLIGHT_OFF: return -ENODEV; case INTEL_DP_AUX_BACKLIGHT_AUTO: diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 6b9df9f9d842..e15cd8491c7f 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -140,10 +140,6 @@ i915_param_named_unsafe(inject_probe_failure, uint, 0400, "Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)"); #endif -i915_param_named(enable_dpcd_backlight, int, 0400, - "Enable support for DPCD backlight control" - "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); - #if IS_ENABLED(CONFIG_DRM_I915_GVT) i915_param_named(enable_gvt, bool, 0400, "Enable support for Intel GVT-g graphics virtualization host support(default:false)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index c33edaee5032..8169234338b1 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -57,7 +57,6 @@ struct drm_printer; param(int, mmio_debug, -IS_ENABLED(CONFIG_DRM_I915_DEBUG_MMIO), 0600) \ param(unsigned int, reset, 3, 0600) \ param(unsigned int, inject_probe_failure, 0, 0) \ - param(int, enable_dpcd_backlight, -1, 0600) \ param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE, 0400) \ param(unsigned int, request_timeout_ms, CONFIG_DRM_I915_REQUEST_TIMEOUT, CONFIG_DRM_I915_REQUEST_TIMEOUT ? 0600 : 0) \ param(unsigned int, lmem_size, 0, 0400) \ From 98a4784e201c22b1bab08b602ccfbe02d9108bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:03 +0300 Subject: [PATCH 0085/7721] drm/i915/display: Move load_detect_test parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-18-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_crt.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 913e5d230a4d..0e33a0523a75 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -841,7 +841,7 @@ intel_crt_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; - if (dev_priv->params.load_detect_test) { + if (dev_priv->display.params.load_detect_test) { wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); goto load_detect; @@ -901,7 +901,7 @@ intel_crt_detect(struct drm_connector *connector, else if (DISPLAY_VER(dev_priv) < 4) status = intel_crt_load_detect(crt, to_intel_crtc(connector->state->crtc)->pipe); - else if (dev_priv->params.load_detect_test) + else if (dev_priv->display.params.load_detect_test) status = connector_status_disconnected; else status = connector_status_unknown; diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 190ca12ce64b..16a30f7b96b4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -76,6 +76,10 @@ intel_display_param_named(enable_dpcd_backlight, int, 0400, "Enable support for DPCD backlight control" "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); +intel_display_param_named_unsafe(load_detect_test, bool, 0400, + "Force-enable the VGA load detect code for testing (default:false). " + "For developers only."); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 85d1128954e9..558eecaa520a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -36,6 +36,7 @@ struct drm_i915_private; param(int, invert_brightness, 0, 0600) \ param(int, edp_vswing, 0, 0400) \ param(int, enable_dpcd_backlight, -1, 0600) \ + param(bool, load_detect_test, false, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index e15cd8491c7f..cb56973a2394 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -86,10 +86,6 @@ i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named_unsafe(load_detect_test, bool, 0400, - "Force-enable the VGA load detect code for testing (default:false). " - "For developers only."); - i915_param_named_unsafe(force_reset_modeset_test, bool, 0400, "Force a modeset during gpu reset for testing (default:false). " "For developers only."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 8169234338b1..cf5448bbc087 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -63,7 +63,6 @@ struct drm_printer; param(unsigned int, lmem_bar_size, 0, 0400) \ /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ - param(bool, load_detect_test, false, 0600) \ param(bool, force_reset_modeset_test, false, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ param(bool, disable_display, false, 0400) \ From 1f3f5eb3b084e91f223d548b0646e8adeeff0779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:04 +0300 Subject: [PATCH 0086/7721] drm/i915/display: Move force_reset_modeset_test parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-19-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_display_reset.c | 2 +- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 16a30f7b96b4..a6f0dd9beb92 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -80,6 +80,10 @@ intel_display_param_named_unsafe(load_detect_test, bool, 0400, "Force-enable the VGA load detect code for testing (default:false). " "For developers only."); +intel_display_param_named_unsafe(force_reset_modeset_test, bool, 0400, + "Force a modeset during gpu reset for testing (default:false). " + "For developers only."); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 558eecaa520a..5f76dbd4b099 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -37,6 +37,7 @@ struct drm_i915_private; param(int, edp_vswing, 0, 0400) \ param(int, enable_dpcd_backlight, -1, 0600) \ param(bool, load_detect_test, false, 0600) \ + param(bool, force_reset_modeset_test, false, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_reset.c b/drivers/gpu/drm/i915/display/intel_display_reset.c index 17178d5d7788..c2c347b22448 100644 --- a/drivers/gpu/drm/i915/display/intel_display_reset.c +++ b/drivers/gpu/drm/i915/display/intel_display_reset.c @@ -29,7 +29,7 @@ void intel_display_reset_prepare(struct drm_i915_private *dev_priv) return; /* reset doesn't touch the display */ - if (!dev_priv->params.force_reset_modeset_test && + if (!dev_priv->display.params.force_reset_modeset_test && !gpu_reset_clobbers_display(dev_priv)) return; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index cb56973a2394..497e39b1dcfb 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -86,10 +86,6 @@ i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named_unsafe(force_reset_modeset_test, bool, 0400, - "Force a modeset during gpu reset for testing (default:false). " - "For developers only."); - i915_param_named(disable_display, bool, 0400, "Disable display (default: false)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index cf5448bbc087..9f3188b674e0 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -63,7 +63,6 @@ struct drm_printer; param(unsigned int, lmem_bar_size, 0, 0400) \ /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ - param(bool, force_reset_modeset_test, false, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ param(bool, disable_display, false, 0400) \ param(bool, verbose_state_checks, true, 0) \ From d3e6d002ed203d8beb66cfdf7eed948ed963ef94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:05 +0300 Subject: [PATCH 0087/7721] drm/i915/display: Move disable_display parameter under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-20-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_device.c | 3 ++- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index e80842d1e7c7..50841818fb59 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1153,5 +1153,6 @@ bool intel_display_device_enabled(struct drm_i915_private *i915) /* Only valid when HAS_DISPLAY() is true */ drm_WARN_ON(&i915->drm, !HAS_DISPLAY(i915)); - return !i915->params.disable_display && !intel_opregion_headless_sku(i915); + return !i915->display.params.disable_display && + !intel_opregion_headless_sku(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index a6f0dd9beb92..3579fa1fc5b7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -84,6 +84,9 @@ intel_display_param_named_unsafe(force_reset_modeset_test, bool, 0400, "Force a modeset during gpu reset for testing (default:false). " "For developers only."); +intel_display_param_named(disable_display, bool, 0400, + "Disable display (default: false)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 5f76dbd4b099..8c4e0f6ac3e3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -38,6 +38,7 @@ struct drm_i915_private; param(int, enable_dpcd_backlight, -1, 0600) \ param(bool, load_detect_test, false, 0600) \ param(bool, force_reset_modeset_test, false, 0600) \ + param(bool, disable_display, false, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 497e39b1dcfb..3205c6b62670 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -86,9 +86,6 @@ i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named(disable_display, bool, 0400, - "Disable display (default: false)"); - i915_param_named(memtest, bool, 0400, "Perform a read/write test of all device memory on module load (default: off)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 9f3188b674e0..8bce7d057634 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -64,7 +64,6 @@ struct drm_printer; /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ - param(bool, disable_display, false, 0400) \ param(bool, verbose_state_checks, true, 0) \ param(bool, nuclear_pageflip, false, 0400) \ param(bool, enable_dp_mst, true, 0600) \ From 514bec3387426f42e88a49bf62f9b0f5eb528b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:06 +0300 Subject: [PATCH 0088/7721] drm/i915/display: Use device parameters instead of module in I915_STATE_WARN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also make module parameter as non writable. Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-21-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 2 +- drivers/gpu/drm/i915/i915_params.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 0e5dffe8f018..ba3548f9768d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -552,7 +552,7 @@ bool assert_port_valid(struct drm_i915_private *i915, enum port port); struct drm_device *drm = &(__i915)->drm; \ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) \ - if (!drm_WARN(drm, i915_modparams.verbose_state_checks, format)) \ + if (!drm_WARN(drm, __i915->params.verbose_state_checks, format)) \ drm_err(drm, format); \ unlikely(__ret_warn_on); \ }) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 3205c6b62670..4e8c088c69fd 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -93,8 +93,7 @@ i915_param_named(mmio_debug, int, 0400, "Enable the MMIO debug code for the first N failures (default: off). " "This may negatively affect performance."); -/* Special case writable file */ -i915_param_named(verbose_state_checks, bool, 0600, +i915_param_named(verbose_state_checks, bool, 0400, "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); i915_param_named_unsafe(nuclear_pageflip, bool, 0400, From f2e71d2c6bbb9ebf3e3dfdf533ba2cab413842aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:07 +0300 Subject: [PATCH 0089/7721] drm/i915/display: Move verbose_state_checks under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Change device parameter permissions to 0400 Cc: Luca Coelho Cc: Jani Nikula Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-22-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 2 +- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index ba3548f9768d..bc95fb377386 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -552,7 +552,7 @@ bool assert_port_valid(struct drm_i915_private *i915, enum port port); struct drm_device *drm = &(__i915)->drm; \ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) \ - if (!drm_WARN(drm, __i915->params.verbose_state_checks, format)) \ + if (!drm_WARN(drm, __i915->display.params.verbose_state_checks, format)) \ drm_err(drm, format); \ unlikely(__ret_warn_on); \ }) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index 3579fa1fc5b7..cae1449e9b06 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -87,6 +87,9 @@ intel_display_param_named_unsafe(force_reset_modeset_test, bool, 0400, intel_display_param_named(disable_display, bool, 0400, "Disable display (default: false)"); +intel_display_param_named(verbose_state_checks, bool, 0400, + "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 8c4e0f6ac3e3..46ec097d43be 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -39,6 +39,7 @@ struct drm_i915_private; param(bool, load_detect_test, false, 0600) \ param(bool, force_reset_modeset_test, false, 0600) \ param(bool, disable_display, false, 0400) \ + param(bool, verbose_state_checks, true, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 4e8c088c69fd..72614c139222 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -93,9 +93,6 @@ i915_param_named(mmio_debug, int, 0400, "Enable the MMIO debug code for the first N failures (default: off). " "This may negatively affect performance."); -i915_param_named(verbose_state_checks, bool, 0400, - "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); - i915_param_named_unsafe(nuclear_pageflip, bool, 0400, "Force enable atomic functionality on platforms that don't have full support yet."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 8bce7d057634..4b543beb17ca 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -64,7 +64,6 @@ struct drm_printer; /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ - param(bool, verbose_state_checks, true, 0) \ param(bool, nuclear_pageflip, false, 0400) \ param(bool, enable_dp_mst, true, 0600) \ param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) From 192a4444abc88d0e95966a4bb5085d58bed03162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:08 +0300 Subject: [PATCH 0090/7721] drm/i915/display: Move nuclear_pageflip under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-23-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_device.c | 2 +- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 50841818fb59..0b522c6a8d6f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1113,7 +1113,7 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) } /* Disable nuclear pageflip by default on pre-g4x */ - if (!i915->params.nuclear_pageflip && + if (!i915->display.params.nuclear_pageflip && DISPLAY_VER(i915) < 5 && !IS_G4X(i915)) i915->drm.driver_features &= ~DRIVER_ATOMIC; } diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index cae1449e9b06..f82f5bed69bc 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -90,6 +90,9 @@ intel_display_param_named(disable_display, bool, 0400, intel_display_param_named(verbose_state_checks, bool, 0400, "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); +intel_display_param_named_unsafe(nuclear_pageflip, bool, 0400, + "Force enable atomic functionality on platforms that don't have full support yet."); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 46ec097d43be..40aed14d18be 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -40,6 +40,7 @@ struct drm_i915_private; param(bool, force_reset_modeset_test, false, 0600) \ param(bool, disable_display, false, 0400) \ param(bool, verbose_state_checks, true, 0400) \ + param(bool, nuclear_pageflip, false, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 72614c139222..18424873442d 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -93,9 +93,6 @@ i915_param_named(mmio_debug, int, 0400, "Enable the MMIO debug code for the first N failures (default: off). " "This may negatively affect performance."); -i915_param_named_unsafe(nuclear_pageflip, bool, 0400, - "Force enable atomic functionality on platforms that don't have full support yet."); - i915_param_named_unsafe(enable_guc, int, 0400, "Enable GuC load for GuC submission and/or HuC load. " "Required functionality can be selected using bitmask values. " diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 4b543beb17ca..c7fff571db2c 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -64,7 +64,6 @@ struct drm_printer; /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ - param(bool, nuclear_pageflip, false, 0400) \ param(bool, enable_dp_mst, true, 0600) \ param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) From 8d3265a76fcf9f5c5064ecef563ec672d60902d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 24 Oct 2023 15:41:09 +0300 Subject: [PATCH 0091/7721] drm/i915/display: Move enable_dp_mst under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jouni Högander Acked-by: Jani Nikula Reviewed-by: Luca Coelho Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-24-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_display_params.c | 3 +++ drivers/gpu/drm/i915/display/intel_display_params.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 6 +++--- drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index f82f5bed69bc..11e03cfb774d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -93,6 +93,9 @@ intel_display_param_named(verbose_state_checks, bool, 0400, intel_display_param_named_unsafe(nuclear_pageflip, bool, 0400, "Force enable atomic functionality on platforms that don't have full support yet."); +intel_display_param_named_unsafe(enable_dp_mst, bool, 0400, + "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)"); + intel_display_param_named_unsafe(enable_fbc, int, 0400, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 40aed14d18be..6206cc51df04 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -41,6 +41,7 @@ struct drm_i915_private; param(bool, disable_display, false, 0400) \ param(bool, verbose_state_checks, true, 0400) \ param(bool, nuclear_pageflip, false, 0400) \ + param(bool, enable_dp_mst, true, 0600) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6f46b6692e43..2fc0a17c45c7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3771,7 +3771,7 @@ intel_dp_can_mst(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); - return i915->params.enable_dp_mst && + return i915->display.params.enable_dp_mst && intel_dp_mst_source_support(intel_dp) && drm_dp_read_mst_cap(&intel_dp->aux, intel_dp->dpcd); } @@ -3789,13 +3789,13 @@ intel_dp_configure_mst(struct intel_dp *intel_dp) encoder->base.base.id, encoder->base.name, str_yes_no(intel_dp_mst_source_support(intel_dp)), str_yes_no(sink_can_mst), - str_yes_no(i915->params.enable_dp_mst)); + str_yes_no(i915->display.params.enable_dp_mst)); if (!intel_dp_mst_source_support(intel_dp)) return; intel_dp->is_mst = sink_can_mst && - i915->params.enable_dp_mst; + i915->display.params.enable_dp_mst; drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 18424873442d..de43048543e8 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -114,9 +114,6 @@ i915_param_named_unsafe(dmc_firmware_path, charp, 0400, i915_param_named_unsafe(gsc_firmware_path, charp, 0400, "GSC firmware path to use instead of the default one"); -i915_param_named_unsafe(enable_dp_mst, bool, 0400, - "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)"); - #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) i915_param_named_unsafe(inject_probe_failure, uint, 0400, "Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index c7fff571db2c..1315d7fac850 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -64,7 +64,6 @@ struct drm_printer; /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ - param(bool, enable_dp_mst, true, 0600) \ param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) #define MEMBER(T, member, ...) T member; From 0520b30b219053cd789909bca45b3c486ef3ee09 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Oct 2023 22:10:04 +0200 Subject: [PATCH 0092/7721] drm/i915/mtl: avoid stringop-overflow warning The newly added memset() causes a warning for some reason I could not figure out: In file included from arch/x86/include/asm/string.h:3, from drivers/gpu/drm/i915/gt/intel_rc6.c:6: In function 'rc6_res_reg_init', inlined from 'intel_rc6_init' at drivers/gpu/drm/i915/gt/intel_rc6.c:610:2: arch/x86/include/asm/string_32.h:195:29: error: '__builtin_memset' writing 16 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=] 195 | #define memset(s, c, count) __builtin_memset(s, c, count) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/gpu/drm/i915/gt/intel_rc6.c:584:9: note: in expansion of macro 'memset' 584 | memset(rc6->res_reg, INVALID_MMIO_REG.reg, sizeof(rc6->res_reg)); | ^~~~~~ In function 'intel_rc6_init': Change it to an normal initializer and an added memcpy() that does not have this problem. Fixes: 4bb9ca7ee074 ("drm/i915/mtl: C6 residency and C state type for MTL SAMedia") Signed-off-by: Arnd Bergmann Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231016201012.1022812-1-arnd@kernel.org --- drivers/gpu/drm/i915/gt/intel_rc6.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 8b67abd720be..7090e4be29cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -581,19 +581,23 @@ static void __intel_rc6_disable(struct intel_rc6 *rc6) static void rc6_res_reg_init(struct intel_rc6 *rc6) { - memset(rc6->res_reg, INVALID_MMIO_REG.reg, sizeof(rc6->res_reg)); + i915_reg_t res_reg[INTEL_RC6_RES_MAX] = { + [0 ... INTEL_RC6_RES_MAX - 1] = INVALID_MMIO_REG, + }; switch (rc6_to_gt(rc6)->type) { case GT_MEDIA: - rc6->res_reg[INTEL_RC6_RES_RC6] = MTL_MEDIA_MC6; + res_reg[INTEL_RC6_RES_RC6] = MTL_MEDIA_MC6; break; default: - rc6->res_reg[INTEL_RC6_RES_RC6_LOCKED] = GEN6_GT_GFX_RC6_LOCKED; - rc6->res_reg[INTEL_RC6_RES_RC6] = GEN6_GT_GFX_RC6; - rc6->res_reg[INTEL_RC6_RES_RC6p] = GEN6_GT_GFX_RC6p; - rc6->res_reg[INTEL_RC6_RES_RC6pp] = GEN6_GT_GFX_RC6pp; + res_reg[INTEL_RC6_RES_RC6_LOCKED] = GEN6_GT_GFX_RC6_LOCKED; + res_reg[INTEL_RC6_RES_RC6] = GEN6_GT_GFX_RC6; + res_reg[INTEL_RC6_RES_RC6p] = GEN6_GT_GFX_RC6p; + res_reg[INTEL_RC6_RES_RC6pp] = GEN6_GT_GFX_RC6pp; break; } + + memcpy(rc6->res_reg, res_reg, sizeof(res_reg)); } void intel_rc6_init(struct intel_rc6 *rc6) From a1196dac2f504f89bc7941e8c63db50f1fe713f3 Mon Sep 17 00:00:00 2001 From: Vinod Govindapillai Date: Wed, 18 Oct 2023 13:27:23 +0300 Subject: [PATCH 0093/7721] drm/i915: remove display device info from i915 capabilities Display device and display runtime info is exposed as part of i915_display_capabilities debugfs entry. Remove this information from i915_ capabilities as it is now reduntant. Signed-off-by: Vinod Govindapillai Reviewed-by: Chaitanya Kumar Borah Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231018102723.16915-3-vinod.govindapillai@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index af0077f6a6d0..bfe92d2402ea 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -69,7 +69,6 @@ static int i915_capabilities(struct seq_file *m, void *data) seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(i915)); intel_device_info_print(INTEL_INFO(i915), RUNTIME_INFO(i915), &p); - intel_display_device_info_print(DISPLAY_INFO(i915), DISPLAY_RUNTIME_INFO(i915), &p); i915_print_iommu_status(i915, &p); intel_gt_info_print(&to_gt(i915)->info, &p); intel_driver_caps_print(&i915->caps, &p); From ffc02c67bf8d4909bd9571fbd14104381fe36b21 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Mon, 23 Oct 2023 14:13:05 +0200 Subject: [PATCH 0094/7721] drm/i915/gt: Use proper priority enum instead of 0 I915_PRIORITY_NORMAL is 0 so use that instead for better readability. Cc: John Harrison Signed-off-by: Nirmoy Das Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231023121305.12560-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index 9a527e1f5be6..1a8e2b7db013 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -188,7 +188,7 @@ static void heartbeat(struct work_struct *wrk) * low latency and no jitter] the chance to naturally * complete before being preempted. */ - attr.priority = 0; + attr.priority = I915_PRIORITY_NORMAL; if (rq->sched.attr.priority >= attr.priority) attr.priority = I915_PRIORITY_HEARTBEAT; if (rq->sched.attr.priority >= attr.priority) From b662c19654ca7fdb1dadd304ca3e26024fc89635 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 16 Oct 2023 15:55:44 +0300 Subject: [PATCH 0095/7721] drm/i915/display: Reset message bus after each read/write operation Every know and then we receive the following error when running for example IGT test kms_flip. [drm] *ERROR* PHY G Read 0d80 failed after 3 retries. [drm] *ERROR* PHY G Write 0d81 failed after 3 retries. Since the error is sporadic in nature, the patch proposes to reset the message bus after every successful or unsuccessful read or write operation. v2: Add FIXME's to indicate the experimental nature of this workaround (Rodrigo) v3: Dropping the additional delay as moving reset to *_read_once() and *_write_once() functions seem unnecessary delay Signed-off-by: Mika Kahola Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231016125544.719963-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index d414f6b7f993..7516abf8dba9 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -206,6 +206,13 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port, intel_clear_response_ready_flag(i915, port, lane); + /* + * FIXME: Workaround to let HW to settle + * down and let the message bus to end up + * in a known state + */ + intel_cx0_bus_reset(i915, port, lane); + return REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, val); } @@ -285,6 +292,13 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, intel_clear_response_ready_flag(i915, port, lane); + /* + * FIXME: Workaround to let HW to settle + * down and let the message bus to end up + * in a known state + */ + intel_cx0_bus_reset(i915, port, lane); + return 0; } From 8d68a0ac9f3f308967bbdf3af37de818a6ed321d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Oct 2023 23:22:59 +0300 Subject: [PATCH 0096/7721] drm/i915/sprite: move sprite_name() to intel_sprite.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move sprite_name() where its only user is, and convert it to a function, removing the implicit dev_priv usage. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231011202259.1090131-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 1 - drivers/gpu/drm/i915/display/intel_sprite.c | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index bc95fb377386..cae2a3b12e20 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -105,7 +105,6 @@ enum i9xx_plane_id { }; #define plane_name(p) ((p) + 'A') -#define sprite_name(p, s) ((p) * DISPLAY_RUNTIME_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A') #define for_each_plane_id_on_crtc(__crtc, __p) \ for ((__p) = PLANE_PRIMARY; (__p) < I915_MAX_PLANES; (__p)++) \ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 1fb16510f750..d7b440c8caef 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -48,6 +48,11 @@ #include "intel_frontbuffer.h" #include "intel_sprite.h" +static char sprite_name(struct drm_i915_private *i915, enum pipe pipe, int sprite) +{ + return pipe * DISPLAY_RUNTIME_INFO(i915)->num_sprites[pipe] + sprite + 'A'; +} + static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ @@ -1636,7 +1641,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, 0, plane_funcs, formats, num_formats, modifiers, DRM_PLANE_TYPE_OVERLAY, - "sprite %c", sprite_name(pipe, sprite)); + "sprite %c", sprite_name(dev_priv, pipe, sprite)); kfree(modifiers); if (ret) From 171c5f641031c0eee424ba79a3db4736c32e18ca Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 21 Oct 2023 00:30:17 +0200 Subject: [PATCH 0097/7721] dt-bindings: display: ssd132x: Remove '-' before compatible enum This is a leftover from when the binding schema had the compatible string property enum as a 'oneOf' child and the '-' was not removed when 'oneOf' got dropped during the binding review process. Reported-by: Rob Herring Closes: https://lore.kernel.org/dri-devel/CAL_Jsq+h8DcnpKqhokQOODCc8+Qi3M0PrxRFKz_Y4v37yMJvvA@mail.gmail.com/ Signed-off-by: Javier Martinez Canillas Acked-by: Conor Dooley Reviewed-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231020223029.1667190-1-javierm@redhat.com --- .../devicetree/bindings/display/solomon,ssd132x.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml index 0aa41bd9ddca..37975ee61c5a 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml @@ -11,10 +11,10 @@ maintainers: properties: compatible: - - enum: - - solomon,ssd1322 - - solomon,ssd1325 - - solomon,ssd1327 + enum: + - solomon,ssd1322 + - solomon,ssd1325 + - solomon,ssd1327 required: - compatible From 9e4db199e66d427c50458f4d72734cc4f0b92948 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 21 Oct 2023 00:52:57 +0200 Subject: [PATCH 0098/7721] drm/ssd130x: Fix possible uninitialized usage of crtc_state variable Avoid a possible uninitialized use of the crtc_state variable in function ssd132x_primary_plane_atomic_check() and avoid the following Smatch warn: drivers/gpu/drm/solomon/ssd130x.c:921 ssd132x_primary_plane_atomic_check() error: uninitialized symbol 'crtc_state'. Fixes: fdd591e00a9c ("drm/ssd130x: Add support for the SSD132x OLED controller family") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/dri-devel/7dd6ca45-8263-44fe-a318-2fd9d761425d@moroto.mountain/ Signed-off-by: Javier Martinez Canillas Acked-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231020225338.1686974-1-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 32f0857aec9f..e0174f82e353 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -910,7 +910,7 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state); struct drm_crtc *crtc = plane_state->crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; const struct drm_format_info *fi; unsigned int pitch; int ret; From 6ce33a8a45496d4eca27b45ab9b8c2436c657495 Mon Sep 17 00:00:00 2001 From: Soumya Negi Date: Wed, 25 Oct 2023 21:43:08 -0700 Subject: [PATCH 0099/7721] drm/i915/gt: Remove {} from if-else In accordance to Linux coding style(Documentation/process/4.Coding.rst), remove unneeded braces from if-else block as all arms of this block contain single statements. Suggested-by: Andi Shyti Signed-off-by: Soumya Negi Acked-by: Karolina Stolarek Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026044309.17213-1-soumya.negi97@gmail.com --- drivers/gpu/drm/i915/gt/intel_ggtt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 1c93e84278a0..9f6f9e138532 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -226,16 +226,15 @@ static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) gen8_ggtt_invalidate(ggtt); list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) { - if (intel_guc_tlb_invalidation_is_available(>->uc.guc)) { + if (intel_guc_tlb_invalidation_is_available(>->uc.guc)) guc_ggtt_ct_invalidate(gt); - } else if (GRAPHICS_VER(i915) >= 12) { + else if (GRAPHICS_VER(i915) >= 12) intel_uncore_write_fw(gt->uncore, GEN12_GUC_TLB_INV_CR, GEN12_GUC_TLB_INV_CR_INVALIDATE); - } else { + else intel_uncore_write_fw(gt->uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE); - } } } From 80683bf48afcdbebbaf51057e71b2701aa07826d Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Fri, 27 Oct 2023 10:44:59 +0800 Subject: [PATCH 0100/7721] drm/atomic-helper: Fix spelling mistake "preceeding" -> "preceding" There is a typo in the kernel documentation for function drm_atomic_helper_wait_for_dependencies. Fix it. Signed-off-by: Kunwu Chan Signed-off-by: Hamza Mahfooz Link: https://patchwork.freedesktop.org/patch/msgid/20231027024459.12793-1-chentao@kylinos.cn --- drivers/gpu/drm/drm_atomic_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 71d399397107..10aadd324cc3 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2373,10 +2373,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_helper_setup_commit); /** - * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits + * drm_atomic_helper_wait_for_dependencies - wait for required preceding commits * @old_state: atomic state object with old state structures * - * This function waits for all preceeding commits that touch the same CRTC as + * This function waits for all preceding commits that touch the same CRTC as * @old_state to both be committed to the hardware (as signalled by * drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled * by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event). From 0226ba393eb1a90d63955cc407340c5d506ecacf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 20 Oct 2023 10:19:38 +0000 Subject: [PATCH 0101/7721] drm: extract closefb logic in separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_mode_rmfb performs two operations: drop the FB from the file_priv->fbs list, and make sure the FB is no longer used on a plane. In the next commit an IOCTL which only does so former will be introduced, so let's split it into a separate function. No functional change, only refactoring. v2: no change Signed-off-by: Simon Ser Cc: Hans de Goede Cc: Dennis Filder Cc: Daniel Vetter Cc: Pekka Paalanen Cc: Rob Clark Cc: Sean Paul Reviewed-by: Daniel Stone Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231020101926.145327-1-contact@emersion.fr --- drivers/gpu/drm/drm_framebuffer.c | 53 ++++++++++++++++++------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d3ba0698b84b..ef3f1e4bc334 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -394,6 +394,31 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) } } +static int drm_mode_closefb(struct drm_framebuffer *fb, + struct drm_file *file_priv) +{ + struct drm_framebuffer *fbl; + bool found = false; + + mutex_lock(&file_priv->fbs_lock); + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = true; + + if (!found) { + mutex_unlock(&file_priv->fbs_lock); + return -ENOENT; + } + + list_del_init(&fb->filp_head); + mutex_unlock(&file_priv->fbs_lock); + + /* Drop the reference that was stored in the fbs list */ + drm_framebuffer_put(fb); + + return 0; +} + /** * drm_mode_rmfb - remove an FB from the configuration * @dev: drm device @@ -410,9 +435,8 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, struct drm_file *file_priv) { - struct drm_framebuffer *fb = NULL; - struct drm_framebuffer *fbl = NULL; - int found = 0; + struct drm_framebuffer *fb; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; @@ -421,24 +445,13 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, if (!fb) return -ENOENT; - mutex_lock(&file_priv->fbs_lock); - list_for_each_entry(fbl, &file_priv->fbs, filp_head) - if (fb == fbl) - found = 1; - if (!found) { - mutex_unlock(&file_priv->fbs_lock); - goto fail_unref; + ret = drm_mode_closefb(fb, file_priv); + if (ret != 0) { + drm_framebuffer_put(fb); + return ret; } - list_del_init(&fb->filp_head); - mutex_unlock(&file_priv->fbs_lock); - - /* drop the reference we picked up in framebuffer lookup */ - drm_framebuffer_put(fb); - /* - * we now own the reference that was stored in the fbs list - * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. @@ -457,10 +470,6 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, drm_framebuffer_put(fb); return 0; - -fail_unref: - drm_framebuffer_put(fb); - return -ENOENT; } int drm_mode_rmfb_ioctl(struct drm_device *dev, From d208d875667e2a29beeec5d475f4b6b164b632fa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 20 Oct 2023 10:19:45 +0000 Subject: [PATCH 0102/7721] drm: introduce CLOSEFB IOCTL This new IOCTL allows callers to close a framebuffer without disabling planes or CRTCs. This takes inspiration from Rob Clark's unref_fb IOCTL [1] and DRM_MODE_FB_PERSIST [2]. User-space patch for wlroots available at [3]. IGT test available at [4]. v2: add an extra pad field just in case we want to extend this IOCTL in the future (Pekka, Sima). [1]: https://lore.kernel.org/dri-devel/20170509153654.23464-1-robdclark@gmail.com/ [2]: https://lore.kernel.org/dri-devel/20211006151921.312714-1-contact@emersion.fr/ [3]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4394 [4]: https://lists.freedesktop.org/archives/igt-dev/2023-October/063294.html Signed-off-by: Simon Ser Reviewed-by: Daniel Stone Acked-by: Pekka Paalanen Cc: Hans de Goede Cc: Dennis Filder Cc: Daniel Vetter Cc: Rob Clark Cc: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20231020101926.145327-2-contact@emersion.fr --- drivers/gpu/drm/drm_crtc_internal.h | 2 ++ drivers/gpu/drm/drm_framebuffer.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/drm_ioctl.c | 1 + include/uapi/drm/drm.h | 20 ++++++++++++++++++++ include/uapi/drm/drm_mode.h | 10 ++++++++++ 5 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 8556c3b3ff88..6b646e0783be 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -222,6 +222,8 @@ int drm_mode_addfb2_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_rmfb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_mode_closefb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_getfb2_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index ef3f1e4bc334..09e289fca5c3 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -480,6 +480,28 @@ int drm_mode_rmfb_ioctl(struct drm_device *dev, return drm_mode_rmfb(dev, *fb_id, file_priv); } +int drm_mode_closefb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_closefb *r = data; + struct drm_framebuffer *fb; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EOPNOTSUPP; + + if (r->pad) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id); + if (!fb) + return -ENOENT; + + ret = drm_mode_closefb(fb, file_priv); + drm_framebuffer_put(fb); + return ret; +} + /** * drm_mode_getfb - get FB info * @dev: drm device for the ioctl diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 77590b0f38fa..44fda68c28ae 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -675,6 +675,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CLOSEFB, drm_mode_closefb_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index de723566c5ae..8662b5aeea0c 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1218,6 +1218,26 @@ extern "C" { #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) +/** + * DRM_IOCTL_MODE_CLOSEFB - Close a framebuffer. + * + * This closes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL + * argument is a framebuffer object ID. + * + * This IOCTL is similar to &DRM_IOCTL_MODE_RMFB, except it doesn't disable + * planes and CRTCs. As long as the framebuffer is used by a plane, it's kept + * alive. When the plane no longer uses the framebuffer (because the + * framebuffer is replaced with another one, or the plane is disabled), the + * framebuffer is cleaned up. + * + * This is useful to implement flicker-free transitions between two processes. + * + * Depending on the threat model, user-space may want to ensure that the + * framebuffer doesn't expose any sensitive user information: closed + * framebuffers attached to a plane can be read back by the next DRM master. + */ +#define DRM_IOCTL_MODE_CLOSEFB DRM_IOWR(0xD0, struct drm_mode_closefb) + /* * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 128d09138ceb..09e7a471ee30 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -1323,6 +1323,16 @@ struct drm_mode_rect { __s32 y2; }; +/** + * struct drm_mode_closefb + * @fb_id: Framebuffer ID. + * @pad: Must be zero. + */ +struct drm_mode_closefb { + __u32 fb_id; + __u32 pad; +}; + #if defined(__cplusplus) } #endif From 81de3e296b10a13e5c9f13172825b0d8d9495c68 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 18 Oct 2023 11:38:15 +0200 Subject: [PATCH 0103/7721] drm/i915: Flush WC GGTT only on required platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen8_ggtt_invalidate() is only needed for limited set of platforms where GGTT is mapped as WC. This was added as way to fix WC based GGTT in commit 0f9b91c754b7 ("drm/i915: flush system agent TLBs on SNB") and there are no reference in HW docs that forces us to use this on non-WC backed GGTT. This can also cause unwanted side-effects on XE_HP platforms where GFX_FLSH_CNTL_GEN6 is not valid anymore. v2: Add a func to detect wc ggtt detection (Ville) v3: Improve commit log and add reference commit (Daniel) Fixes: d2eae8e98d59 ("drm/i915/dg2: Drop force_probe requirement") Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Jani Nikula Cc: Jonathan Cavitt Cc: John Harrison Cc: Andi Shyti Cc: Ville Syrjälä Cc: Daniel Vetter Cc: # v6.2+ Suggested-by: Matt Roper Signed-off-by: Nirmoy Das Reviewed-by: Matt Roper Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231018093815.1349-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gt/intel_ggtt.c | 35 +++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 9f6f9e138532..76b0ee2b906b 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -195,6 +195,21 @@ void gen6_ggtt_invalidate(struct i915_ggtt *ggtt) spin_unlock_irq(&uncore->lock); } +static bool needs_wc_ggtt_mapping(struct drm_i915_private *i915) +{ + /* + * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range + * will be dropped. For WC mappings in general we have 64 byte burst + * writes when the WC buffer is flushed, so we can't use it, but have to + * resort to an uncached mapping. The WC issue is easily caught by the + * readback check when writing GTT PTE entries. + */ + if (!IS_GEN9_LP(i915) && GRAPHICS_VER(i915) < 11) + return true; + + return false; +} + static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) { struct intel_uncore *uncore = ggtt->vm.gt->uncore; @@ -202,8 +217,12 @@ static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) /* * Note that as an uncached mmio write, this will flush the * WCB of the writes into the GGTT before it triggers the invalidate. + * + * Only perform this when GGTT is mapped as WC, see ggtt_probe_common(). */ - intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); + if (needs_wc_ggtt_mapping(ggtt->vm.i915)) + intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, + GFX_FLSH_CNTL_EN); } static void guc_ggtt_ct_invalidate(struct intel_gt *gt) @@ -1139,17 +1158,11 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) GEM_WARN_ON(pci_resource_len(pdev, GEN4_GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915); - /* - * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range - * will be dropped. For WC mappings in general we have 64 byte burst - * writes when the WC buffer is flushed, so we can't use it, but have to - * resort to an uncached mapping. The WC issue is easily caught by the - * readback check when writing GTT PTE entries. - */ - if (IS_GEN9_LP(i915) || GRAPHICS_VER(i915) >= 11) - ggtt->gsm = ioremap(phys_addr, size); - else + if (needs_wc_ggtt_mapping(i915)) ggtt->gsm = ioremap_wc(phys_addr, size); + else + ggtt->gsm = ioremap(phys_addr, size); + if (!ggtt->gsm) { drm_err(&i915->drm, "Failed to map the ggtt page table\n"); return -ENOMEM; From 88b02ebca8b6ea7457bed6809b1dd575420b7544 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 23 Oct 2023 20:36:39 +0000 Subject: [PATCH 0104/7721] drm/doc: describe PATH format for DP MST This is already uAPI, xserver parses it. It's useful to document since user-space might want to lookup the parent connector. Additionally, people (me included) have misunderstood the PATH property for being stable across reboots, but since a KMS object ID is baked in there that's not the case. So PATH shouldn't be used as-is in config files and such. Signed-off-by: Simon Ser Reviewed-by: Dmitry Baryshkov Acked-by: Pekka Paalanen Cc: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231023203629.198109-1-contact@emersion.fr --- drivers/gpu/drm/drm_connector.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index c3725086f413..b0516505f7ae 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1198,6 +1198,12 @@ static const u32 dp_colorspaces = * drm_connector_set_path_property(), in the case of DP MST with the * path property the MST manager created. Userspace cannot change this * property. + * + * In the case of DP MST, the property has the format + * ``mst:-`` where ```` is the KMS object ID of the + * parent connector and ```` is a hyphen-separated list of DP MST + * port numbers. Note, KMS object IDs are not guaranteed to be stable + * across reboots. * TILE: * Connector tile group property to indicate how a set of DRM connector * compose together into one logical screen. This is used by both high-res From bb8e97e26ce6437d2f57f37e8ba767a2b9cf0d65 Mon Sep 17 00:00:00 2001 From: Carl Vanderlip Date: Mon, 16 Oct 2023 11:00:36 -0600 Subject: [PATCH 0105/7721] accel/qaic: Enable 1 MSI fallback mode Several virtualization use-cases either don't support 32 MultiMSIs (Xen/VMware) or have significant drawbacks to their use (KVM's vIOMMU, which is required to support 32 MSI, needs to allocate an alternate system memory space for each device using vIOMMU (e.g. 8GB VM mem and 2 cards => 8 + 2 * 8 = 24GB host memory required)). Support these cases by enabling a 1 MSI fallback mode. Whenever all 32 MSIs requested are not available, a second request for a single MSI is made. Its success is the initiator of single MSI mode. This mode causes all interrupts generated by the device to be directed to the 0th MSI (firmware >=v1.10 will do this as a response to the PCIe MSI capability configuration). Likewise, all interrupt handlers for the device are registered to the 0th MSI. Since the DBC interrupt handler checks if the DBC is in use or if there is any pending changes, the 'spurious' interrupts are disregarded. If there is work to be done, the standard threaded IRQ handler is dispatched. On every interrupt, the MHI handler wakes up its threaded interrupt handler, and attempts to wake any waiters for MHI state events. Performance is within +-0.6% for test cases that typify real world use. Larger differences ([-4,+132]%, avg +47%) exist for very simple tasks (e.g. addition) compiled for single NSPs. It is assumed that the small work and many interrupts typically cause contention (e.g. 16 NSPs vs 4 CPUs), as evidenced by the standard deviation between runs also decreasing (r=-0.48 between delta(Performace_test) and delta(StdDev_test/Avg_test)) Signed-off-by: Carl Vanderlip Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231016170036.5409-1-quic_jhugo@quicinc.com --- Documentation/accel/qaic/aic100.rst | 5 +++-- Documentation/accel/qaic/qaic.rst | 23 +++++++++++++++++++ drivers/accel/qaic/mhi_controller.c | 6 ++++- drivers/accel/qaic/mhi_controller.h | 2 +- drivers/accel/qaic/qaic.h | 2 ++ drivers/accel/qaic/qaic_data.c | 25 +++++++++++++++------ drivers/accel/qaic/qaic_drv.c | 35 ++++++++++++++++++++--------- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/Documentation/accel/qaic/aic100.rst b/Documentation/accel/qaic/aic100.rst index c80d0f1307db..a5fef0869aab 100644 --- a/Documentation/accel/qaic/aic100.rst +++ b/Documentation/accel/qaic/aic100.rst @@ -36,8 +36,9 @@ AIC100 DID (0xa100). AIC100 does not implement FLR (function level reset). -AIC100 implements MSI but does not implement MSI-X. AIC100 requires 17 MSIs to -operate (1 for MHI, 16 for the DMA Bridge). +AIC100 implements MSI but does not implement MSI-X. AIC100 prefers 17 MSIs to +operate (1 for MHI, 16 for the DMA Bridge). Falling back to 1 MSI is possible in +scenarios where reserving 32 MSIs isn't feasible. As a PCIe device, AIC100 utilizes BARs to provide host interfaces to the device hardware. AIC100 provides 3, 64-bit BARs. diff --git a/Documentation/accel/qaic/qaic.rst b/Documentation/accel/qaic/qaic.rst index c88502383136..9ccbfea86f5a 100644 --- a/Documentation/accel/qaic/qaic.rst +++ b/Documentation/accel/qaic/qaic.rst @@ -10,6 +10,9 @@ accelerator products. Interrupts ========== +IRQ Storm Mitigation +-------------------- + While the AIC100 DMA Bridge hardware implements an IRQ storm mitigation mechanism, it is still possible for an IRQ storm to occur. A storm can happen if the workload is particularly quick, and the host is responsive. If the host @@ -35,6 +38,26 @@ generates 100k IRQs per second (per /proc/interrupts) is reduced to roughly 64 IRQs over 5 minutes while keeping the host system stable, and having the same workload throughput performance (within run to run noise variation). +Single MSI Mode +--------------- + +MultiMSI is not well supported on all systems; virtualized ones even less so +(circa 2023). Between hypervisors masking the PCIe MSI capability structure to +large memory requirements for vIOMMUs (required for supporting MultiMSI), it is +useful to be able to fall back to a single MSI when needed. + +To support this fallback, we allow the case where only one MSI is able to be +allocated, and share that one MSI between MHI and the DBCs. The device detects +when only one MSI has been configured and directs the interrupts for the DBCs +to the interrupt normally used for MHI. Unfortunately this means that the +interrupt handlers for every DBC and MHI wake up for every interrupt that +arrives; however, the DBC threaded irq handlers only are started when work to be +done is detected (MHI will always start its threaded handler). + +If the DBC is configured to force MSI interrupts, this can circumvent the +software IRQ storm mitigation mentioned above. Since the MSI is shared it is +never disabled, allowing each new entry to the FIFO to trigger a new interrupt. + Neural Network Control (NNC) Protocol ===================================== diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 5036e58e7235..41be3626587d 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -468,7 +468,7 @@ static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl) } struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq) + int mhi_irq, bool shared_msi) { struct mhi_controller *mhi_cntrl; int ret; @@ -500,6 +500,10 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi return ERR_PTR(-ENOMEM); mhi_cntrl->irq[0] = mhi_irq; + + if (shared_msi) /* MSI shared with data path, no IRQF_NO_SUSPEND */ + mhi_cntrl->irq_flags = IRQF_SHARED; + mhi_cntrl->fw_image = "qcom/aic100/sbl.bin"; /* use latest configured timeout */ diff --git a/drivers/accel/qaic/mhi_controller.h b/drivers/accel/qaic/mhi_controller.h index 2ae45d768e24..500e7f4af2af 100644 --- a/drivers/accel/qaic/mhi_controller.h +++ b/drivers/accel/qaic/mhi_controller.h @@ -8,7 +8,7 @@ #define MHICONTROLLERQAIC_H_ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq); + int mhi_irq, bool shared_msi); void qaic_mhi_free_controller(struct mhi_controller *mhi_cntrl, bool link_up); void qaic_mhi_start_reset(struct mhi_controller *mhi_cntrl); void qaic_mhi_reset_done(struct mhi_controller *mhi_cntrl); diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index e3f4c30f3ffd..01e9dda0cc37 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -123,6 +123,8 @@ struct qaic_device { struct srcu_struct dev_lock; /* true: Device under reset; false: Device not under reset */ bool in_reset; + /* true: single MSI is used to operate device */ + bool single_msi; /* * true: A tx MHI transaction has failed and a rx buffer is still queued * in control device. Such a buffer is considered lost rx buffer diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 4a8e43a7a6a4..ebc3cca1b094 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -1466,6 +1466,16 @@ irqreturn_t dbc_irq_handler(int irq, void *data) rcu_id = srcu_read_lock(&dbc->ch_lock); + if (datapath_polling) { + srcu_read_unlock(&dbc->ch_lock, rcu_id); + /* + * Normally datapath_polling will not have irqs enabled, but + * when running with only one MSI the interrupt is shared with + * MHI so it cannot be disabled. Return ASAP instead. + */ + return IRQ_HANDLED; + } + if (!dbc->usr) { srcu_read_unlock(&dbc->ch_lock, rcu_id); return IRQ_HANDLED; @@ -1488,7 +1498,8 @@ irqreturn_t dbc_irq_handler(int irq, void *data) return IRQ_NONE; } - disable_irq_nosync(irq); + if (!dbc->qdev->single_msi) + disable_irq_nosync(irq); srcu_read_unlock(&dbc->ch_lock, rcu_id); return IRQ_WAKE_THREAD; } @@ -1559,12 +1570,12 @@ irqreturn_t dbc_irq_threaded_fn(int irq, void *data) u32 tail; rcu_id = srcu_read_lock(&dbc->ch_lock); + qdev = dbc->qdev; head = readl(dbc->dbc_base + RSPHP_OFF); if (head == U32_MAX) /* PCI link error */ goto error_out; - qdev = dbc->qdev; read_fifo: if (!event_count) { @@ -1645,14 +1656,14 @@ irqreturn_t dbc_irq_threaded_fn(int irq, void *data) goto read_fifo; normal_out: - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) enable_irq(irq); - else + else if (unlikely(datapath_polling)) schedule_work(&dbc->poll_work); /* checking the fifo and enabling irqs is a race, missed event check */ tail = readl(dbc->dbc_base + RSPTP_OFF); if (tail != U32_MAX && head != tail) { - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) disable_irq_nosync(irq); goto read_fifo; } @@ -1661,9 +1672,9 @@ irqreturn_t dbc_irq_threaded_fn(int irq, void *data) error_out: srcu_read_unlock(&dbc->ch_lock, rcu_id); - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) enable_irq(irq); - else + else if (unlikely(datapath_polling)) schedule_work(&dbc->poll_work); return IRQ_HANDLED; diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 6f58095767df..5eba5f03d3bf 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -424,14 +424,24 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) int i; /* Managed release since we use pcim_enable_device */ - ret = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); - if (ret < 0) - return ret; + ret = pci_alloc_irq_vectors(pdev, 32, 32, PCI_IRQ_MSI); + if (ret == -ENOSPC) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) + return ret; - if (ret < 32) { - pci_err(pdev, "%s: Requested 32 MSIs. Obtained %d MSIs which is less than the 32 required.\n", - __func__, ret); - return -ENODEV; + /* + * Operate in one MSI mode. All interrupts will be directed to + * MSI0; every interrupt will wake up all the interrupt handlers + * (MHI and DBC[0-15]). Since the interrupt is now shared, it is + * not disabled during DBC threaded handler, but only one thread + * will be allowed to run per DBC, so while it can be + * interrupted, it shouldn't race with itself. + */ + qdev->single_msi = true; + pci_info(pdev, "Allocating 32 MSIs failed, operating in 1 MSI mode. Performance may be impacted.\n"); + } else if (ret < 0) { + return ret; } mhi_irq = pci_irq_vector(pdev, 0); @@ -439,15 +449,17 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) return mhi_irq; for (i = 0; i < qdev->num_dbc; ++i) { - ret = devm_request_threaded_irq(&pdev->dev, pci_irq_vector(pdev, i + 1), + ret = devm_request_threaded_irq(&pdev->dev, + pci_irq_vector(pdev, qdev->single_msi ? 0 : i + 1), dbc_irq_handler, dbc_irq_threaded_fn, IRQF_SHARED, "qaic_dbc", &qdev->dbc[i]); if (ret) return ret; if (datapath_polling) { - qdev->dbc[i].irq = pci_irq_vector(pdev, i + 1); - disable_irq_nosync(qdev->dbc[i].irq); + qdev->dbc[i].irq = pci_irq_vector(pdev, qdev->single_msi ? 0 : i + 1); + if (!qdev->single_msi) + disable_irq_nosync(qdev->dbc[i].irq); INIT_WORK(&qdev->dbc[i].poll_work, irq_polling_work); } } @@ -479,7 +491,8 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto cleanup_qdev; } - qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq); + qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, + qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); goto cleanup_qdev; From 6216fb03f8bd0b1439e9e799a306bafd5b462622 Mon Sep 17 00:00:00 2001 From: Ajit Pal Singh Date: Mon, 16 Oct 2023 11:01:13 -0600 Subject: [PATCH 0106/7721] accel/qaic: Add support for periodic timesync Device and Host have a time synchronization mechanism that happens once during boot when device is in SBL mode. After that, in mission-mode there is no timesync. In an experiment after continuous operation, device time drifted w.r.t. host by approximately 3 seconds per day. This drift leads to mismatch in timestamp of device and Host logs. To correct this implement periodic timesync in driver. This timesync is carried out via QAIC_TIMESYNC_PERIODIC MHI channel. Signed-off-by: Ajit Pal Singh Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Reviewed-by: Carl Vanderlip Reviewed-by: Pranjal Ramajor Asha Kanojiya Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231016170114.5446-2-quic_jhugo@quicinc.com --- Documentation/accel/qaic/aic100.rst | 4 + Documentation/accel/qaic/qaic.rst | 5 + drivers/accel/qaic/Makefile | 3 +- drivers/accel/qaic/mhi_controller.c | 32 ++++ drivers/accel/qaic/qaic_drv.c | 6 + drivers/accel/qaic/qaic_timesync.c | 245 ++++++++++++++++++++++++++++ drivers/accel/qaic/qaic_timesync.h | 11 ++ 7 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 drivers/accel/qaic/qaic_timesync.c create mode 100644 drivers/accel/qaic/qaic_timesync.h diff --git a/Documentation/accel/qaic/aic100.rst b/Documentation/accel/qaic/aic100.rst index a5fef0869aab..2ed32be7ae25 100644 --- a/Documentation/accel/qaic/aic100.rst +++ b/Documentation/accel/qaic/aic100.rst @@ -225,6 +225,10 @@ of the defined channels, and their uses. | | | | device side logs with the host time | | | | | source. | +----------------+---------+----------+----------------------------------------+ +| QAIC_TIMESYNC | 22 & 23 | AMSS | Used to periodically synchronize | +| _PERIODIC | | | timestamps in the device side logs with| +| | | | the host time source. | ++----------------+---------+----------+----------------------------------------+ DMA Bridge ========== diff --git a/Documentation/accel/qaic/qaic.rst b/Documentation/accel/qaic/qaic.rst index 9ccbfea86f5a..f81020736ebf 100644 --- a/Documentation/accel/qaic/qaic.rst +++ b/Documentation/accel/qaic/qaic.rst @@ -201,3 +201,8 @@ overrides this for that call. Default is 5000 (5 seconds). Sets the polling interval in microseconds (us) when datapath polling is active. Takes effect at the next polling interval. Default is 100 (100 us). + +**timesync_delay_ms (unsigned int)** + +Sets the time interval in milliseconds (ms) between two consecutive timesync +operations. Default is 1000 (1000 ms). diff --git a/drivers/accel/qaic/Makefile b/drivers/accel/qaic/Makefile index 2418418f7a50..3f7f6dfde7f2 100644 --- a/drivers/accel/qaic/Makefile +++ b/drivers/accel/qaic/Makefile @@ -9,4 +9,5 @@ qaic-y := \ mhi_controller.o \ qaic_control.o \ qaic_data.o \ - qaic_drv.o + qaic_drv.o \ + qaic_timesync.o diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 41be3626587d..705898777ec5 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -373,6 +373,38 @@ static struct mhi_channel_config aic100_channels[] = { .auto_queue = false, .wake_capable = false, }, + { + .name = "QAIC_TIMESYNC_PERIODIC", + .num = 22, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .num = 23, + .name = "QAIC_TIMESYNC_PERIODIC", + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, }; static struct mhi_event_config aic100_events[] = { diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 5eba5f03d3bf..08d940d3da46 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -27,6 +27,7 @@ #include "mhi_controller.h" #include "qaic.h" +#include "qaic_timesync.h" MODULE_IMPORT_NS(DMA_BUF); @@ -599,6 +600,10 @@ static int __init qaic_init(void) goto free_pci; } + ret = qaic_timesync_init(); + if (ret) + pr_debug("qaic: qaic_timesync_init failed %d\n", ret); + return 0; free_pci: @@ -624,6 +629,7 @@ static void __exit qaic_exit(void) * reinitializing the link_up state after the cleanup is done. */ link_up = true; + qaic_timesync_deinit(); mhi_driver_unregister(&qaic_mhi_driver); pci_unregister_driver(&qaic_pci_driver); } diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c new file mode 100644 index 000000000000..769250272c21 --- /dev/null +++ b/drivers/accel/qaic/qaic_timesync.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qaic.h" +#include "qaic_timesync.h" + +#define QTIMER_REG_OFFSET 0xa28 +#define QAIC_TIMESYNC_SIGNATURE 0x55aa +#define QAIC_CONV_QTIMER_TO_US(qtimer) (mul_u64_u32_div(qtimer, 10, 192)) + +static unsigned int timesync_delay_ms = 1000; /* 1 sec default */ +module_param(timesync_delay_ms, uint, 0600); +MODULE_PARM_DESC(timesync_delay_ms, "Delay in ms between two consecutive timesync operations"); + +enum qts_msg_type { + QAIC_TS_SYNC_REQ = 1, + QAIC_TS_ACK_TO_HOST, + QAIC_TS_MSG_TYPE_MAX +}; + +/** + * struct qts_hdr - Timesync message header structure. + * @signature: Unique signature to identify the timesync message. + * @reserved_1: Reserved for future use. + * @reserved_2: Reserved for future use. + * @msg_type: sub-type of the timesync message. + * @reserved_3: Reserved for future use. + */ +struct qts_hdr { + __le16 signature; + __le16 reserved_1; + u8 reserved_2; + u8 msg_type; + __le16 reserved_3; +} __packed; + +/** + * struct qts_timeval - Structure to carry time information. + * @tv_sec: Seconds part of the time. + * @tv_usec: uS (microseconds) part of the time. + */ +struct qts_timeval { + __le64 tv_sec; + __le64 tv_usec; +} __packed; + +/** + * struct qts_host_time_sync_msg_data - Structure to denote the timesync message. + * @header: Header of the timesync message. + * @data: Time information. + */ +struct qts_host_time_sync_msg_data { + struct qts_hdr header; + struct qts_timeval data; +} __packed; + +/** + * struct mqts_dev - MHI QAIC Timesync Control device. + * @qdev: Pointer to the root device struct driven by QAIC driver. + * @mhi_dev: Pointer to associated MHI device. + * @timer: Timer handle used for timesync. + * @qtimer_addr: Device QTimer register pointer. + * @buff_in_use: atomic variable to track if the sync_msg buffer is in use. + * @dev: Device pointer to qdev->pdev->dev stored for easy access. + * @sync_msg: Buffer used to send timesync message over MHI. + */ +struct mqts_dev { + struct qaic_device *qdev; + struct mhi_device *mhi_dev; + struct timer_list timer; + void __iomem *qtimer_addr; + atomic_t buff_in_use; + struct device *dev; + struct qts_host_time_sync_msg_data *sync_msg; +}; + +#ifdef readq +static u64 read_qtimer(const volatile void __iomem *addr) +{ + return readq(addr); +} +#else +static u64 read_qtimer(const volatile void __iomem *addr) +{ + u64 low, high; + + low = readl(addr); + high = readl(addr + sizeof(u32)); + return low | (high << 32); +} +#endif + +static void qaic_timesync_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + dev_dbg(mqtsdev->dev, "%s status: %d xfer_len: %zu\n", __func__, + mhi_result->transaction_status, mhi_result->bytes_xferd); + + atomic_set(&mqtsdev->buff_in_use, 0); +} + +static void qaic_timesync_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + dev_err(mqtsdev->dev, "%s no data expected on dl channel\n", __func__); +} + +static void qaic_timesync_timer(struct timer_list *t) +{ + struct mqts_dev *mqtsdev = from_timer(mqtsdev, t, timer); + struct qts_host_time_sync_msg_data *sync_msg; + u64 device_qtimer_us; + u64 device_qtimer; + u64 host_time_us; + u64 offset_us; + u64 host_sec; + int ret; + + if (atomic_read(&mqtsdev->buff_in_use)) { + dev_dbg(mqtsdev->dev, "%s buffer not free, schedule next cycle\n", __func__); + goto mod_timer; + } + atomic_set(&mqtsdev->buff_in_use, 1); + + sync_msg = mqtsdev->sync_msg; + sync_msg->header.signature = cpu_to_le16(QAIC_TIMESYNC_SIGNATURE); + sync_msg->header.msg_type = QAIC_TS_SYNC_REQ; + /* Read host UTC time and convert to uS*/ + host_time_us = div_u64(ktime_get_real_ns(), NSEC_PER_USEC); + device_qtimer = read_qtimer(mqtsdev->qtimer_addr); + device_qtimer_us = QAIC_CONV_QTIMER_TO_US(device_qtimer); + /* Offset between host UTC and device time */ + offset_us = host_time_us - device_qtimer_us; + + host_sec = div_u64(offset_us, USEC_PER_SEC); + sync_msg->data.tv_usec = cpu_to_le64(offset_us - host_sec * USEC_PER_SEC); + sync_msg->data.tv_sec = cpu_to_le64(host_sec); + ret = mhi_queue_buf(mqtsdev->mhi_dev, DMA_TO_DEVICE, sync_msg, sizeof(*sync_msg), MHI_EOT); + if (ret && (ret != -EAGAIN)) { + dev_err(mqtsdev->dev, "%s unable to queue to mhi:%d\n", __func__, ret); + return; + } else if (ret == -EAGAIN) { + atomic_set(&mqtsdev->buff_in_use, 0); + } + +mod_timer: + ret = mod_timer(t, jiffies + msecs_to_jiffies(timesync_delay_ms)); + if (ret) + dev_err(mqtsdev->dev, "%s mod_timer error:%d\n", __func__, ret); +} + +static int qaic_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) +{ + struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); + struct mqts_dev *mqtsdev; + struct timer_list *timer; + int ret; + + mqtsdev = kzalloc(sizeof(*mqtsdev), GFP_KERNEL); + if (!mqtsdev) { + ret = -ENOMEM; + goto out; + } + + timer = &mqtsdev->timer; + mqtsdev->mhi_dev = mhi_dev; + mqtsdev->qdev = qdev; + mqtsdev->dev = &qdev->pdev->dev; + + mqtsdev->sync_msg = kzalloc(sizeof(*mqtsdev->sync_msg), GFP_KERNEL); + if (!mqtsdev->sync_msg) { + ret = -ENOMEM; + goto free_mqts_dev; + } + atomic_set(&mqtsdev->buff_in_use, 0); + + ret = mhi_prepare_for_transfer(mhi_dev); + if (ret) + goto free_sync_msg; + + /* Qtimer register pointer */ + mqtsdev->qtimer_addr = qdev->bar_0 + QTIMER_REG_OFFSET; + timer_setup(timer, qaic_timesync_timer, 0); + timer->expires = jiffies + msecs_to_jiffies(timesync_delay_ms); + add_timer(timer); + dev_set_drvdata(&mhi_dev->dev, mqtsdev); + + return 0; + +free_sync_msg: + kfree(mqtsdev->sync_msg); +free_mqts_dev: + kfree(mqtsdev); +out: + return ret; +}; + +static void qaic_timesync_remove(struct mhi_device *mhi_dev) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + del_timer_sync(&mqtsdev->timer); + mhi_unprepare_from_transfer(mqtsdev->mhi_dev); + kfree(mqtsdev->sync_msg); + kfree(mqtsdev); +} + +static const struct mhi_device_id qaic_timesync_match_table[] = { + { .chan = "QAIC_TIMESYNC_PERIODIC"}, + {}, +}; + +MODULE_DEVICE_TABLE(mhi, qaic_timesync_match_table); + +static struct mhi_driver qaic_timesync_driver = { + .id_table = qaic_timesync_match_table, + .remove = qaic_timesync_remove, + .probe = qaic_timesync_probe, + .ul_xfer_cb = qaic_timesync_ul_xfer_cb, + .dl_xfer_cb = qaic_timesync_dl_xfer_cb, + .driver = { + .name = "qaic_timesync_periodic", + }, +}; + +int qaic_timesync_init(void) +{ + return mhi_driver_register(&qaic_timesync_driver); +} + +void qaic_timesync_deinit(void) +{ + mhi_driver_unregister(&qaic_timesync_driver); +} diff --git a/drivers/accel/qaic/qaic_timesync.h b/drivers/accel/qaic/qaic_timesync.h new file mode 100644 index 000000000000..851b7acd43bb --- /dev/null +++ b/drivers/accel/qaic/qaic_timesync.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __QAIC_TIMESYNC_H__ +#define __QAIC_TIMESYNC_H__ + +int qaic_timesync_init(void); +void qaic_timesync_deinit(void); +#endif /* __QAIC_TIMESYNC_H__ */ From 41cfbaa47fd7d94df5faf1c416801600f26270d8 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Mon, 16 Oct 2023 11:01:14 -0600 Subject: [PATCH 0107/7721] accel/qaic: Support MHI QAIC_TIMESYNC channel Use QAIC_TIMESYNC MHI channel to send UTC time to device in SBL environment. Remove support for QAIC_TIMESYNC MHI channel in AMSS environment as it is not used in that environment. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Reviewed-by: Carl Vanderlip Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231016170114.5446-3-quic_jhugo@quicinc.com --- Documentation/accel/qaic/aic100.rst | 2 +- drivers/accel/qaic/mhi_controller.c | 4 +- drivers/accel/qaic/qaic.h | 4 + drivers/accel/qaic/qaic_drv.c | 7 ++ drivers/accel/qaic/qaic_timesync.c | 154 +++++++++++++++++++++++++++- 5 files changed, 166 insertions(+), 5 deletions(-) diff --git a/Documentation/accel/qaic/aic100.rst b/Documentation/accel/qaic/aic100.rst index 2ed32be7ae25..590dae77ea12 100644 --- a/Documentation/accel/qaic/aic100.rst +++ b/Documentation/accel/qaic/aic100.rst @@ -221,7 +221,7 @@ of the defined channels, and their uses. +----------------+---------+----------+----------------------------------------+ | QAIC_DEBUG | 18 & 19 | AMSS | Not used. | +----------------+---------+----------+----------------------------------------+ -| QAIC_TIMESYNC | 20 & 21 | SBL/AMSS | Used to synchronize timestamps in the | +| QAIC_TIMESYNC | 20 & 21 | SBL | Used to synchronize timestamps in the | | | | | device side logs with the host time | | | | | source. | +----------------+---------+----------+----------------------------------------+ diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 705898777ec5..5d3cc30009cc 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -348,7 +348,7 @@ static struct mhi_channel_config aic100_channels[] = { .local_elements = 0, .event_ring = 0, .dir = DMA_TO_DEVICE, - .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS, + .ee_mask = MHI_CH_EE_SBL, .pollcfg = 0, .doorbell = MHI_DB_BRST_DISABLE, .lpm_notify = false, @@ -364,7 +364,7 @@ static struct mhi_channel_config aic100_channels[] = { .local_elements = 0, .event_ring = 0, .dir = DMA_FROM_DEVICE, - .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS, + .ee_mask = MHI_CH_EE_SBL, .pollcfg = 0, .doorbell = MHI_DB_BRST_DISABLE, .lpm_notify = false, diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 01e9dda0cc37..bc40d52dc010 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -139,6 +139,10 @@ struct qaic_device { u32 (*gen_crc)(void *msg); /* Validate the CRC of a control message */ bool (*valid_crc)(void *msg); + /* MHI "QAIC_TIMESYNC" channel device */ + struct mhi_device *qts_ch; + /* Work queue for tasks related to MHI "QAIC_TIMESYNC" channel */ + struct workqueue_struct *qts_wq; }; struct qaic_drm_device { diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 08d940d3da46..b12226385003 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -325,6 +325,7 @@ static void cleanup_qdev(struct qaic_device *qdev) cleanup_srcu_struct(&qdev->dev_lock); pci_set_drvdata(qdev->pdev, NULL); destroy_workqueue(qdev->cntl_wq); + destroy_workqueue(qdev->qts_wq); } static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) @@ -348,6 +349,12 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de if (!qdev->cntl_wq) return NULL; + qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0); + if (!qdev->qts_wq) { + destroy_workqueue(qdev->cntl_wq); + return NULL; + } + pci_set_drvdata(pdev, qdev); qdev->pdev = pdev; diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c index 769250272c21..301f4462d51b 100644 --- a/drivers/accel/qaic/qaic_timesync.c +++ b/drivers/accel/qaic/qaic_timesync.c @@ -22,7 +22,8 @@ module_param(timesync_delay_ms, uint, 0600); MODULE_PARM_DESC(timesync_delay_ms, "Delay in ms between two consecutive timesync operations"); enum qts_msg_type { - QAIC_TS_SYNC_REQ = 1, + QAIC_TS_CMD_TO_HOST, + QAIC_TS_SYNC_REQ, QAIC_TS_ACK_TO_HOST, QAIC_TS_MSG_TYPE_MAX }; @@ -83,6 +84,16 @@ struct mqts_dev { struct qts_host_time_sync_msg_data *sync_msg; }; +struct qts_resp_msg { + struct qts_hdr hdr; +} __packed; + +struct qts_resp { + struct qts_resp_msg data; + struct work_struct work; + struct qaic_device *qdev; +}; + #ifdef readq static u64 read_qtimer(const volatile void __iomem *addr) { @@ -234,12 +245,151 @@ static struct mhi_driver qaic_timesync_driver = { }, }; +static void qaic_boot_timesync_worker(struct work_struct *work) +{ + struct qts_resp *resp = container_of(work, struct qts_resp, work); + struct qts_host_time_sync_msg_data *req; + struct qts_resp_msg data = resp->data; + struct qaic_device *qdev = resp->qdev; + struct mhi_device *mhi_dev; + struct timespec64 ts; + int ret; + + mhi_dev = qdev->qts_ch; + /* Queue the response message beforehand to avoid race conditions */ + ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, &resp->data, sizeof(resp->data), MHI_EOT); + if (ret) { + kfree(resp); + dev_warn(&mhi_dev->dev, "Failed to re-queue response buffer %d\n", ret); + return; + } + + switch (data.hdr.msg_type) { + case QAIC_TS_CMD_TO_HOST: + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + break; + + req->header = data.hdr; + req->header.msg_type = QAIC_TS_SYNC_REQ; + ktime_get_real_ts64(&ts); + req->data.tv_sec = cpu_to_le64(ts.tv_sec); + req->data.tv_usec = cpu_to_le64(div_u64(ts.tv_nsec, NSEC_PER_USEC)); + + ret = mhi_queue_buf(mhi_dev, DMA_TO_DEVICE, req, sizeof(*req), MHI_EOT); + if (ret) { + kfree(req); + dev_dbg(&mhi_dev->dev, "Failed to send request message. Error %d\n", ret); + } + break; + case QAIC_TS_ACK_TO_HOST: + dev_dbg(&mhi_dev->dev, "ACK received from device\n"); + break; + default: + dev_err(&mhi_dev->dev, "Invalid message type %u.\n", data.hdr.msg_type); + } +} + +static int qaic_boot_timesync_queue_resp(struct mhi_device *mhi_dev, struct qaic_device *qdev) +{ + struct qts_resp *resp; + int ret; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return -ENOMEM; + + resp->qdev = qdev; + INIT_WORK(&resp->work, qaic_boot_timesync_worker); + + ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, &resp->data, sizeof(resp->data), MHI_EOT); + if (ret) { + kfree(resp); + dev_warn(&mhi_dev->dev, "Failed to queue response buffer %d\n", ret); + return ret; + } + + return 0; +} + +static void qaic_boot_timesync_remove(struct mhi_device *mhi_dev) +{ + struct qaic_device *qdev; + + qdev = dev_get_drvdata(&mhi_dev->dev); + mhi_unprepare_from_transfer(qdev->qts_ch); + qdev->qts_ch = NULL; +} + +static int qaic_boot_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) +{ + struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); + int ret; + + ret = mhi_prepare_for_transfer(mhi_dev); + if (ret) + return ret; + + qdev->qts_ch = mhi_dev; + dev_set_drvdata(&mhi_dev->dev, qdev); + + ret = qaic_boot_timesync_queue_resp(mhi_dev, qdev); + if (ret) { + dev_set_drvdata(&mhi_dev->dev, NULL); + qdev->qts_ch = NULL; + mhi_unprepare_from_transfer(mhi_dev); + } + + return ret; +} + +static void qaic_boot_timesync_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + kfree(mhi_result->buf_addr); +} + +static void qaic_boot_timesync_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct qts_resp *resp = container_of(mhi_result->buf_addr, struct qts_resp, data); + + if (mhi_result->transaction_status || mhi_result->bytes_xferd != sizeof(resp->data)) { + kfree(resp); + return; + } + + queue_work(resp->qdev->qts_wq, &resp->work); +} + +static const struct mhi_device_id qaic_boot_timesync_match_table[] = { + { .chan = "QAIC_TIMESYNC"}, + {}, +}; + +static struct mhi_driver qaic_boot_timesync_driver = { + .id_table = qaic_boot_timesync_match_table, + .remove = qaic_boot_timesync_remove, + .probe = qaic_boot_timesync_probe, + .ul_xfer_cb = qaic_boot_timesync_ul_xfer_cb, + .dl_xfer_cb = qaic_boot_timesync_dl_xfer_cb, + .driver = { + .name = "qaic_timesync", + }, +}; + int qaic_timesync_init(void) { - return mhi_driver_register(&qaic_timesync_driver); + int ret; + + ret = mhi_driver_register(&qaic_timesync_driver); + if (ret) + return ret; + ret = mhi_driver_register(&qaic_boot_timesync_driver); + + return ret; } void qaic_timesync_deinit(void) { + mhi_driver_unregister(&qaic_boot_timesync_driver); mhi_driver_unregister(&qaic_timesync_driver); } From 3db2420422a5912d97966e0176050bb0fc9aa63e Mon Sep 17 00:00:00 2001 From: Sheng-Liang Pan Date: Fri, 27 Oct 2023 11:04:56 +0800 Subject: [PATCH 0108/7721] drm/panel-edp: Add AUO B116XTN02, BOE NT116WHM-N21,836X2, NV116WHM-N49 V8.0 Add panel identification entry for - AUO B116XTN02 family (product ID:0x235c) - BOE NT116WHM-N21,836X2 (product ID:0x09c3) - BOE NV116WHM-N49 V8.0 (product ID:0x0979) Signed-off-by: Sheng-Liang Pan Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231027110435.1.Ia01fe9ec1c0953e0050a232eaa782fef2c037516@changeid --- drivers/gpu/drm/panel/panel-edp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index feb665df35a1..9dce4c702414 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1869,6 +1869,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), @@ -1877,8 +1878,10 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), From 33f2af42a2019da4fecde30fe144a810b485762f Mon Sep 17 00:00:00 2001 From: Gilbert Adikankwu Date: Thu, 26 Oct 2023 11:56:23 +0100 Subject: [PATCH 0109/7721] drm/i915/gt: Remove unncessary {} from if-else Fix checkpatch.pl error: WARNING: braces {} are not necessary for any arm of this statement Signed-off-by: Gilbert Adikankwu Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026105623.480172-1-gilbertadikankwu@gmail.com --- drivers/gpu/drm/i915/gt/intel_sseu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index f602895f6d0d..6a3246240e81 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -849,13 +849,12 @@ void intel_sseu_print_topology(struct drm_i915_private *i915, const struct sseu_dev_info *sseu, struct drm_printer *p) { - if (sseu->max_slices == 0) { + if (sseu->max_slices == 0) drm_printf(p, "Unavailable\n"); - } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) sseu_print_xehp_topology(sseu, p); - } else { + else sseu_print_hsw_topology(sseu, p); - } } void intel_sseu_print_ss_info(const char *type, From 10184a8a7f70d28ba6aae22142a7375a8c8c1924 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 26 Oct 2023 11:40:44 -0700 Subject: [PATCH 0110/7721] drm/i915/lnl: Extend C10/C20 phy For Lunar Lake, DDI-A is connected to C10 PHY, while TC1-TC3 are connected to C20 phy, like in Meteor Lake. Update the check in intel_is_c10phy() accordingly. This reverts the change in commit e388ae97e225 ("drm/i915/display: Eliminate IS_METEORLAKE checks") that turned that into a display engine version check. The phy <-> port connection is very SoC-specific and not related to that version. IS_LUNARLAKE() is defined to 0 in i915 as it's expected that the (upcoming) xe driver is the one defining the platform, with i915 only driving the display side. Bspec: 70818 Reviewed-by: Gustavo Sousa Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20231026184045.1015655-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 7516abf8dba9..cc87653bc476 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -31,7 +31,7 @@ bool intel_is_c10phy(struct drm_i915_private *i915, enum phy phy) { - if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0) && phy < PHY_C) + if ((IS_LUNARLAKE(i915) || IS_METEORLAKE(i915)) && phy < PHY_C) return true; return false; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 20bbad165d76..8e81974607f2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -560,6 +560,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_DG2(i915) IS_PLATFORM(i915, INTEL_DG2) #define IS_PONTEVECCHIO(i915) IS_PLATFORM(i915, INTEL_PONTEVECCHIO) #define IS_METEORLAKE(i915) IS_PLATFORM(i915, INTEL_METEORLAKE) +#define IS_LUNARLAKE(i915) 0 #define IS_DG2_G10(i915) \ IS_SUBPLATFORM(i915, INTEL_DG2, INTEL_SUBPLATFORM_G10) From 28066f38d94f846e66f4116a8b1c409b47072011 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 26 Oct 2023 11:40:45 -0700 Subject: [PATCH 0111/7721] drm/i915/lnl: Fix check for TC phy With MTL adding PICA between the port and the real phy, the path add for DG2 stopped being followed and newer platforms are simply using the older path for TC phys. LNL is no different than MTL in this aspect, so just add it to the mess. In future the phy and port designation and deciding if it's TC should better be cleaned up. To make it just a bit better, also change intel_phy_is_snps() to show this is DG2-only. Signed-off-by: Lucas De Marchi Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231026184045.1015655-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 28d85e1e858e..1caf46e3e569 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1784,31 +1784,31 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy) bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) { + /* + * DG2's "TC1", although TC-capable output, doesn't share the same flow + * as other platforms on the display engine side and rather rely on the + * SNPS PHY, that is programmed separately + */ if (IS_DG2(dev_priv)) - /* DG2's "TC1" output uses a SNPS PHY */ return false; - else if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0)) + + if (DISPLAY_VER(dev_priv) >= 13) return phy >= PHY_F && phy <= PHY_I; else if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; else if (IS_ICELAKE(dev_priv)) return phy >= PHY_C && phy <= PHY_F; - else - return false; + + return false; } bool intel_phy_is_snps(struct drm_i915_private *dev_priv, enum phy phy) { - if (phy == PHY_NONE) - return false; - else if (IS_DG2(dev_priv)) - /* - * All four "combo" ports and the TC1 port (PHY E) use - * Synopsis PHYs. - */ - return phy <= PHY_E; - - return false; + /* + * For DG2, and for DG2 only, all four "combo" ports and the TC1 port + * (PHY E) use Synopsis PHYs. See intel_phy_is_tc(). + */ + return IS_DG2(dev_priv) && phy > PHY_NONE && phy <= PHY_E; } enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port) From 685a4fffbf0fe23618f1824924e6dbb2517b446a Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 18 Oct 2023 15:28:30 -0700 Subject: [PATCH 0112/7721] drm/i915/display: Abstract C10/C20 pll hw readout intel_cx0_phy.[ch] should contain the details about C10/C20, not leaking it to the rest of the driver. Start abstracting this by exporting a single PLL hw readout that handles the differences between C20 and C10 internally to that compilation unit. Signed-off-by: Lucas De Marchi Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231018222831.4132968-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 8 +++++--- drivers/gpu/drm/i915/display/intel_ddi.c | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index cc87653bc476..6fa91acc0a25 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -1864,8 +1864,8 @@ static int intel_c10pll_calc_state(struct intel_crtc_state *crtc_state, return -EINVAL; } -void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c10pll_state *pll_state) +static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c10pll_state *pll_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 lane = INTEL_CX0_LANE0; @@ -2117,8 +2117,8 @@ static bool intel_c20_use_mplla(u32 clock) return false; } -void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c20pll_state *pll_state) +static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c20pll_state *pll_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); bool cntx; @@ -3067,3 +3067,15 @@ void intel_c10pll_state_verify(struct intel_atomic_state *state, crtc->base.base.id, crtc->base.name, mpllb_sw_state->cmn, mpllb_hw_state.cmn); } + +void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_cx0pll_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_is_c10phy(i915, phy)) + intel_c10pll_readout_hw_state(encoder, &pll_state->c10); + else + intel_c20pll_readout_hw_state(encoder, &pll_state->c20); +} diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 0e0a38dac8cd..ff7ccb7855aa 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -16,6 +16,7 @@ struct drm_i915_private; struct intel_atomic_state; struct intel_c10pll_state; struct intel_c20pll_state; +struct intel_cx0pll_state; struct intel_crtc; struct intel_crtc_state; struct intel_encoder; @@ -28,16 +29,17 @@ void intel_mtl_pll_disable(struct intel_encoder *encoder); enum icl_port_dpll_id intel_mtl_port_pll_type(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); -void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c10pll_state *pll_state); + int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder); +void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_cx0pll_state *pll_state); + void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, const struct intel_c10pll_state *hw_state); int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10pll_state *pll_state); void intel_c10pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc); -void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c20pll_state *pll_state); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, const struct intel_c20pll_state *hw_state); int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9151d5add960..80a8ab7874db 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3861,10 +3861,10 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, if (intel_tc_port_in_tbt_alt_mode(dig_port)) { crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); } else if (intel_is_c10phy(i915, phy)) { - intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); + intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { - intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); + intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); } From 0a0f7935740853ce2654a7750b84c3bd34756979 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 18 Oct 2023 15:28:31 -0700 Subject: [PATCH 0113/7721] drm/i915/display: Abstract C10/C20 pll calculation As done with the hw readout, properly abstract the C10/C20 phy details inside intel_cx0_phy.c. Signed-off-by: Lucas De Marchi Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231018222831.4132968-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 6 ++---- drivers/gpu/drm/i915/display/intel_ddi.c | 7 +------ drivers/gpu/drm/i915/display/intel_dpll.c | 7 +------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6fa91acc0a25..b2ad4c6172f6 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2392,8 +2392,8 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, BIT(0), cntx ? 0 : 1, MB_WRITE_COMMITTED); } -int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state) +static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c10pll_state *pll_state) { unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; @@ -2419,8 +2419,8 @@ int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } -int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) +static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) { unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; unsigned int multiplier, refclk = 38400; @@ -3079,3 +3079,15 @@ void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, else intel_c20pll_readout_hw_state(encoder, &pll_state->c20); } + +int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_cx0pll_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_is_c10phy(i915, phy)) + return intel_c10pll_calc_port_clock(encoder, &pll_state->c10); + + return intel_c20pll_calc_port_clock(encoder, &pll_state->c20); +} diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index ff7ccb7855aa..222aed16e739 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -33,17 +33,15 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder); void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, struct intel_cx0pll_state *pll_state); +int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_cx0pll_state *pll_state); void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, const struct intel_c10pll_state *hw_state); -int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state); void intel_c10pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, const struct intel_c20pll_state *hw_state); -int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state); void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 80a8ab7874db..c4dc1f71da4b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3854,18 +3854,13 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, static void mtl_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(i915, encoder->port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); if (intel_tc_port_in_tbt_alt_mode(dig_port)) { crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); - } else if (intel_is_c10phy(i915, phy)) { - intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); - crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); - crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state); } intel_ddi_get_config(encoder, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index d41c1dc9f66c..509b862f9e60 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1003,12 +1003,10 @@ static int dg2_crtc_compute_clock(struct intel_atomic_state *state, static int mtl_crtc_compute_clock(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); - enum phy phy = intel_port_to_phy(i915, encoder->port); int ret; ret = intel_cx0pll_calc_state(crtc_state, encoder); @@ -1016,10 +1014,7 @@ static int mtl_crtc_compute_clock(struct intel_atomic_state *state, return ret; /* TODO: Do the readback via intel_compute_shared_dplls() */ - if (intel_is_c10phy(i915, phy)) - crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); - else - crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state); crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state); From 1470acbef122c7e2e588f6346ce459c26d0568a2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 27 Oct 2023 17:26:23 +0200 Subject: [PATCH 0114/7721] accel/ivpu: avoid build failure with CONFIG_PM=n The usage count of struct dev_pm_info is an implementation detail that is only available if CONFIG_PM is enabled, so printing it in a debug message causes a build failure in configurations without PM: In file included from include/linux/device.h:15, from include/linux/pci.h:37, from drivers/accel/ivpu/ivpu_pm.c:8: drivers/accel/ivpu/ivpu_pm.c: In function 'ivpu_rpm_get_if_active': drivers/accel/ivpu/ivpu_pm.c:254:51: error: 'struct dev_pm_info' has no member named 'usage_count' 254 | atomic_read(&vdev->drm.dev->power.usage_count)); | ^ include/linux/dev_printk.h:129:48: note: in definition of macro 'dev_printk' 129 | _dev_printk(level, dev, fmt, ##__VA_ARGS__); \ | ^~~~~~~~~~~ drivers/accel/ivpu/ivpu_drv.h:75:17: note: in expansion of macro 'dev_dbg' 75 | dev_dbg((vdev)->drm.dev, "[%s] " fmt, #type, ##args); \ | ^~~~~~~ drivers/accel/ivpu/ivpu_pm.c:253:9: note: in expansion of macro 'ivpu_dbg' 253 | ivpu_dbg(vdev, RPM, "rpm_get_if_active count %d\n", | ^~~~~~~~ The print message does not seem essential, so the easiest workaround is to just remove it. Fixes: c39dc15191c4 ("accel/ivpu: Read clock rate only if device is up") Signed-off-by: Arnd Bergmann Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231027152633.528490-1-arnd@kernel.org --- drivers/accel/ivpu/ivpu_pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index d14b6fd796b4..568e4295dc56 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -250,9 +250,6 @@ int ivpu_rpm_get_if_active(struct ivpu_device *vdev) { int ret; - ivpu_dbg(vdev, RPM, "rpm_get_if_active count %d\n", - atomic_read(&vdev->drm.dev->power.usage_count)); - ret = pm_runtime_get_if_active(vdev->drm.dev, false); drm_WARN_ON(&vdev->drm, ret < 0); From a3431650f30a94b179d419ef87c21213655c28cd Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 18 Oct 2023 17:06:22 +0530 Subject: [PATCH 0115/7721] drm/i915/mtl: Support HBR3 rate with C10 phy and eDP in MTL eDP specification supports HBR3 link rate since v1.4a. Moreover, C10 phy can support HBR3 link rate for both DP and eDP. Therefore, do not clamp the supported rates for eDP at 6.75Gbps. Cc: BSpec: 70073 74224 Signed-off-by: Chaitanya Kumar Borah Reviewed-by: Mika Kahola Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231018113622.2761997-1-chaitanya.kumar.borah@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2fc0a17c45c7..ab4608dafe5d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -430,7 +430,7 @@ static int mtl_max_source_rate(struct intel_dp *intel_dp) enum phy phy = intel_port_to_phy(i915, dig_port->base.port); if (intel_is_c10phy(i915, phy)) - return intel_dp_is_edp(intel_dp) ? 675000 : 810000; + return 810000; return 2000000; } From 8c63b47412ad3f015db47b380916722299511cc3 Mon Sep 17 00:00:00 2001 From: Krystian Pradzynski Date: Sat, 28 Oct 2023 15:34:05 +0200 Subject: [PATCH 0116/7721] accel/ivpu: Update FW API Bump boot API to 4.20 Bump JSM API to 3.15 Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-2-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_jsm_msg.c | 17 ++ drivers/accel/ivpu/vpu_boot_api.h | 90 ++++++++- drivers/accel/ivpu/vpu_jsm_api.h | 309 ++++++++++++++++++++++++++++-- 3 files changed, 392 insertions(+), 24 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 0c2fe7142024..35a689475c68 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -36,6 +36,17 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_DESTROY_CMD_QUEUE); IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES); IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_ENGINE_RESUME); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); @@ -65,6 +76,12 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE); } #undef IVPU_CASE_TO_STR diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h index 6b71be92ba65..04c954258563 100644 --- a/drivers/accel/ivpu/vpu_boot_api.h +++ b/drivers/accel/ivpu/vpu_boot_api.h @@ -11,7 +11,10 @@ * The bellow values will be used to construct the version info this way: * fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) | * VPU_BOOT_API_VER_MINOR; - * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes. + * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes + * This information is collected by using vpuip_2/application/vpuFirmware/make_std_fw_image.py + * If a header is missing this info we ignore the header, if a header is missing or contains + * partial info a build error will be generated. */ /* @@ -24,12 +27,12 @@ * Minor version changes when API backward compatibility is preserved. * Resets to 0 if Major version is incremented. */ -#define VPU_BOOT_API_VER_MINOR 12 +#define VPU_BOOT_API_VER_MINOR 20 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_BOOT_API_VER_PATCH 2 +#define VPU_BOOT_API_VER_PATCH 4 /* * Index in the API version table @@ -63,6 +66,12 @@ struct vpu_firmware_header { /* Size of memory require for firmware execution */ u32 runtime_size; u32 shave_nn_fw_size; + /* Size of primary preemption buffer. */ + u32 preemption_buffer_1_size; + /* Size of secondary preemption buffer. */ + u32 preemption_buffer_2_size; + /* Space reserved for future preemption-related fields. */ + u32 preemption_reserved[6]; }; /* @@ -89,6 +98,14 @@ enum VPU_BOOT_L2_CACHE_CFG_TYPE { VPU_BOOT_L2_CACHE_CFG_NUM = 2 }; +/** VPU MCA ECC signalling mode. By default, no signalling is used */ +enum VPU_BOOT_MCA_ECC_SIGNAL_TYPE { + VPU_BOOT_MCA_ECC_NONE = 0, + VPU_BOOT_MCA_ECC_CORR = 1, + VPU_BOOT_MCA_ECC_FATAL = 2, + VPU_BOOT_MCA_ECC_BOTH = 3 +}; + /** * Logging destinations. * @@ -131,9 +148,11 @@ enum vpu_trace_destination { #define VPU_TRACE_PROC_BIT_ACT_SHV_3 22 #define VPU_TRACE_PROC_NO_OF_HW_DEVS 23 -/* KMB HW component IDs are sequential, so define first and last IDs. */ -#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_LRT -#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_SHV_15 +/* VPU 30xx HW component IDs are sequential, so define first and last IDs. */ +#define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT +#define VPU_TRACE_PROC_BIT_30XX_LAST VPU_TRACE_PROC_BIT_SHV_15 +#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_30XX_FIRST +#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_30XX_LAST struct vpu_boot_l2_cache_config { u8 use; @@ -148,6 +167,25 @@ struct vpu_warm_boot_section { u32 is_clear_op; }; +/* + * When HW scheduling mode is enabled, a present period is defined. + * It will be used by VPU to swap between normal and focus priorities + * to prevent starving of normal priority band (when implemented). + * Host must provide a valid value at boot time in + * `vpu_focus_present_timer_ms`. If the value provided by the host is not within the + * defined range a default value will be used. Here we define the min. and max. + * allowed values and the and default value of the present period. Units are milliseconds. + */ +#define VPU_PRESENT_CALL_PERIOD_MS_DEFAULT 50 +#define VPU_PRESENT_CALL_PERIOD_MS_MIN 16 +#define VPU_PRESENT_CALL_PERIOD_MS_MAX 10000 + +/** + * Macros to enable various operation modes within the VPU. + * To be defined as part of 32 bit mask. + */ +#define VPU_OP_MODE_SURVIVABILITY 0x1 + struct vpu_boot_params { u32 magic; u32 vpu_id; @@ -218,6 +256,7 @@ struct vpu_boot_params { * the threshold will not be logged); applies to every enabled logging * destination and loggable HW component. See 'mvLog_t' enum for acceptable * values. + * TODO: EISW-33556: Move log level definition (mvLog_t) to this file. */ u32 default_trace_level; u32 boot_type; @@ -249,7 +288,36 @@ struct vpu_boot_params { u32 temp_sensor_period_ms; /** PLL ratio for efficient clock frequency */ u32 pn_freq_pll_ratio; - u32 pad4[28]; + /** DVFS Mode: Default: 0, Max Performance: 1, On Demand: 2, Power Save: 3 */ + u32 dvfs_mode; + /** + * Depending on DVFS Mode: + * On-demand: Default if 0. + * Bit 0-7 - uint8_t: Highest residency percent + * Bit 8-15 - uint8_t: High residency percent + * Bit 16-23 - uint8_t: Low residency percent + * Bit 24-31 - uint8_t: Lowest residency percent + * Bit 32-35 - unsigned 4b: PLL Ratio increase amount on highest residency + * Bit 36-39 - unsigned 4b: PLL Ratio increase amount on high residency + * Bit 40-43 - unsigned 4b: PLL Ratio decrease amount on low residency + * Bit 44-47 - unsigned 4b: PLL Ratio decrease amount on lowest frequency + * Bit 48-55 - uint8_t: Period (ms) for residency decisions + * Bit 56-63 - uint8_t: Averaging windows (as multiples of period. Max: 30 decimal) + * Power Save/Max Performance: Unused + */ + u64 dvfs_param; + /** + * D0i3 delayed entry + * Bit0: Disable CPU state save on D0i2 entry flow. + * 0: Every D0i2 entry saves state. Save state IPC message ignored. + * 1: IPC message required to save state on D0i3 entry flow. + */ + u32 d0i3_delayed_entry; + /* Time spent by VPU in D0i3 state */ + u64 d0i3_residency_time_us; + /* Value of VPU perf counter at the time of entering D0i3 state . */ + u64 d0i3_entry_vpu_ts; + u32 pad4[20]; /* Warm boot information: 0x400 - 0x43F */ u32 warm_boot_sections_count; u32 warm_boot_start_address_reference; @@ -274,8 +342,12 @@ struct vpu_boot_params { u32 vpu_scheduling_mode; /* Present call period in milliseconds. */ u32 vpu_focus_present_timer_ms; - /* Unused/reserved: 0x478 - 0xFFF */ - u32 pad6[738]; + /* VPU ECC Signaling */ + u32 vpu_uses_ecc_mca_signal; + /* Values defined by VPU_OP_MODE* macros */ + u32 vpu_operation_mode; + /* Unused/reserved: 0x480 - 0xFFF */ + u32 pad6[736]; }; /* diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h index 2949ec8365bd..7da7622742be 100644 --- a/drivers/accel/ivpu/vpu_jsm_api.h +++ b/drivers/accel/ivpu/vpu_jsm_api.h @@ -22,12 +22,12 @@ /* * Minor version changes when API backward compatibility is preserved. */ -#define VPU_JSM_API_VER_MINOR 0 +#define VPU_JSM_API_VER_MINOR 15 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_JSM_API_VER_PATCH 1 +#define VPU_JSM_API_VER_PATCH 0 /* * Index in the API version table @@ -84,11 +84,13 @@ * Job flags bit masks. */ #define VPU_JOB_FLAGS_NULL_SUBMISSION_MASK 0x00000001 +#define VPU_JOB_FLAGS_PRIVATE_DATA_MASK 0xFF000000 /* * Sizes of the reserved areas in jobs, in bytes. */ -#define VPU_JOB_RESERVED_BYTES 16 +#define VPU_JOB_RESERVED_BYTES 8 + /* * Sizes of the reserved areas in job queues, in bytes. */ @@ -108,6 +110,20 @@ */ #define VPU_DYNDBG_CMD_MAX_LEN 96 +/* + * For HWS command queue scheduling, we can prioritise command queues inside the + * same process with a relative in-process priority. Valid values for relative + * priority are given below - max and min. + */ +#define VPU_HWS_COMMAND_QUEUE_MAX_IN_PROCESS_PRIORITY 7 +#define VPU_HWS_COMMAND_QUEUE_MIN_IN_PROCESS_PRIORITY -7 + +/* + * For HWS priority scheduling, we can have multiple realtime priority bands. + * They are numbered 0 to a MAX. + */ +#define VPU_HWS_MAX_REALTIME_PRIORITY_LEVEL 31U + /* * Job format. */ @@ -117,8 +133,14 @@ struct vpu_job_queue_entry { u32 flags; /**< Flags bit field, see VPU_JOB_FLAGS_* above */ u64 root_page_table_addr; /**< Address of root page table to use for this job */ u64 root_page_table_update_counter; /**< Page tables update events counter */ - u64 preemption_buffer_address; /**< Address of the preemption buffer to use for this job */ - u64 preemption_buffer_size; /**< Size of the preemption buffer to use for this job */ + u64 primary_preempt_buf_addr; + /**< Address of the primary preemption buffer to use for this job */ + u32 primary_preempt_buf_size; + /**< Size of the primary preemption buffer to use for this job */ + u32 secondary_preempt_buf_size; + /**< Size of secondary preemption buffer to use for this job */ + u64 secondary_preempt_buf_addr; + /**< Address of secondary preemption buffer to use for this job */ u8 reserved_0[VPU_JOB_RESERVED_BYTES]; }; @@ -152,6 +174,46 @@ enum vpu_trace_entity_type { VPU_TRACE_ENTITY_TYPE_HW_COMPONENT = 2, }; +/* + * HWS specific log buffer header details. + * Total size is 32 bytes. + */ +struct vpu_hws_log_buffer_header { + /* Written by VPU after adding a log entry. Initialised by host to 0. */ + u32 first_free_entry_index; + /* Incremented by VPU every time the VPU overwrites the 0th entry; + * initialised by host to 0. + */ + u32 wraparound_count; + /* + * This is the number of buffers that can be stored in the log buffer provided by the host. + * It is written by host before passing buffer to VPU. VPU should consider it read-only. + */ + u64 num_of_entries; + u64 reserved[2]; +}; + +/* + * HWS specific log buffer entry details. + * Total size is 32 bytes. + */ +struct vpu_hws_log_buffer_entry { + /* VPU timestamp must be an invariant timer tick (not impacted by DVFS) */ + u64 vpu_timestamp; + /* + * Operation type: + * 0 - context state change + * 1 - queue new work + * 2 - queue unwait sync object + * 3 - queue no more work + * 4 - queue wait sync object + */ + u32 operation_type; + u32 reserved; + /* Operation data depends on operation type */ + u64 operation_data[2]; +}; + /* * Host <-> VPU IPC messages types. */ @@ -228,6 +290,23 @@ enum vpu_ipc_msg_type { * deallocated or reassigned to another context. */ VPU_JSM_MSG_HWS_REGISTER_DB = 0x1117, + /** Control command: Log buffer setting */ + VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG = 0x1118, + /* Control command: Suspend command queue. */ + VPU_JSM_MSG_HWS_SUSPEND_CMDQ = 0x1119, + /* Control command: Resume command queue */ + VPU_JSM_MSG_HWS_RESUME_CMDQ = 0x111a, + /* Control command: Resume engine after reset */ + VPU_JSM_MSG_HWS_ENGINE_RESUME = 0x111b, + /* Control command: Enable survivability/DCT mode */ + VPU_JSM_MSG_DCT_ENABLE = 0x111c, + /* Control command: Disable survivability/DCT mode */ + VPU_JSM_MSG_DCT_DISABLE = 0x111d, + /** + * Dump VPU state. To be used for debug purposes only. + * NOTE: Please introduce new ASYNC commands before this one. * + */ + VPU_JSM_MSG_STATE_DUMP = 0x11FF, /* IPC Host -> Device, General commands */ VPU_JSM_MSG_GENERAL_CMD = 0x1200, VPU_JSM_MSG_BLOB_DEINIT = VPU_JSM_MSG_GENERAL_CMD, @@ -236,6 +315,10 @@ enum vpu_ipc_msg_type { * Linux command: `echo '' > /dynamic_debug/control`. */ VPU_JSM_MSG_DYNDBG_CONTROL = 0x1201, + /** + * Perform the save procedure for the D0i3 entry + */ + VPU_JSM_MSG_PWR_D0I3_ENTER = 0x1202, /* IPC Device -> Host, Job completion */ VPU_JSM_MSG_JOB_DONE = 0x2100, /* IPC Device -> Host, Async command completion */ @@ -304,11 +387,35 @@ enum vpu_ipc_msg_type { VPU_JSM_MSG_DESTROY_CMD_QUEUE_RSP = 0x2216, /** Response to control command: Set context scheduling properties */ VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP = 0x2217, + /** Response to control command: Log buffer setting */ + VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP = 0x2218, + /* IPC Device -> Host, HWS notify index entry of log buffer written */ + VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION = 0x2219, + /* IPC Device -> Host, HWS completion of a context suspend request */ + VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE = 0x221a, + /* Response to control command: Resume command queue */ + VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP = 0x221b, + /* Response to control command: Resume engine command response */ + VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE = 0x221c, + /* Response to control command: Enable survivability/DCT mode */ + VPU_JSM_MSG_DCT_ENABLE_DONE = 0x221d, + /* Response to control command: Disable survivability/DCT mode */ + VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e, + /** + * Response to state dump control command. + * NOTE: Please introduce new ASYNC responses before this one. * + */ + VPU_JSM_MSG_STATE_DUMP_RSP = 0x22FF, /* IPC Device -> Host, General command completion */ VPU_JSM_MSG_GENERAL_CMD_DONE = 0x2300, VPU_JSM_MSG_BLOB_DEINIT_DONE = VPU_JSM_MSG_GENERAL_CMD_DONE, /** Response to VPU_JSM_MSG_DYNDBG_CONTROL. */ VPU_JSM_MSG_DYNDBG_CONTROL_RSP = 0x2301, + /** + * Acknowledgment of completion of the save procedure initiated by + * VPU_JSM_MSG_PWR_D0I3_ENTER + */ + VPU_JSM_MSG_PWR_D0I3_ENTER_DONE = 0x2302, }; enum vpu_ipc_msg_status { VPU_JSM_MSG_FREE, VPU_JSM_MSG_ALLOCATED }; @@ -593,12 +700,12 @@ struct vpu_ipc_msg_payload_hws_priority_band_setup { * Default quantum in 100ns units for scheduling across processes * within a priority band */ - u64 process_quantum[VPU_HWS_NUM_PRIORITY_BANDS]; + u32 process_quantum[VPU_HWS_NUM_PRIORITY_BANDS]; /* * Default grace period in 100ns units for processes that preempt each * other within a priority band */ - u64 process_grace_period[VPU_HWS_NUM_PRIORITY_BANDS]; + u32 process_grace_period[VPU_HWS_NUM_PRIORITY_BANDS]; /* * For normal priority band, specifies the target VPU percentage * in situations when it's starved by the focus band. @@ -608,32 +715,51 @@ struct vpu_ipc_msg_payload_hws_priority_band_setup { u32 reserved_0; }; -/* HWS create command queue request */ +/* + * @brief HWS create command queue request. + * Host will create a command queue via this command. + * Note: Cmdq group is a handle of an object which + * may contain one or more command queues. + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE_RSP + */ struct vpu_ipc_msg_payload_hws_create_cmdq { /* Process id */ u64 process_id; /* Host SSID */ u32 host_ssid; - /* Zero Padding */ - u32 reserved; + /* Engine for which queue is being created */ + u32 engine_idx; + /* + * Cmdq group may be set to 0 or equal to + * cmdq_id while each priority band contains + * only single engine instances. + */ + u64 cmdq_group; /* Command queue id */ u64 cmdq_id; /* Command queue base */ u64 cmdq_base; /* Command queue size */ u32 cmdq_size; - /* Reserved */ + /* Zero padding */ u32 reserved_0; }; -/* HWS create command queue response */ +/* + * @brief HWS create command queue response. + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE_RSP + */ struct vpu_ipc_msg_payload_hws_create_cmdq_rsp { /* Process id */ u64 process_id; /* Host SSID */ u32 host_ssid; - /* Zero Padding */ - u32 reserved; + /* Engine for which queue is being created */ + u32 engine_idx; + /* Command queue group */ + u64 cmdq_group; /* Command queue id */ u64 cmdq_id; }; @@ -661,7 +787,7 @@ struct vpu_ipc_msg_payload_hws_set_context_sched_properties { /* Inside realtime band assigns a further priority */ u32 realtime_priority_level; /* Priority relative to other contexts in the same process */ - u32 in_process_priority; + s32 in_process_priority; /* Zero padding / Reserved */ u32 reserved_1; /* Context quantum relative to other contexts of same priority in the same process */ @@ -694,6 +820,123 @@ struct vpu_jsm_hws_register_db { u64 cmdq_size; }; +/* + * @brief Structure to set another buffer to be used for scheduling-related logging. + * The size of the logging buffer and the number of entries is defined as part of the + * buffer itself as described next. + * The log buffer received from the host is made up of; + * - header: 32 bytes in size, as shown in 'struct vpu_hws_log_buffer_header'. + * The header contains the number of log entries in the buffer. + * - log entry: 0 to n-1, each log entry is 32 bytes in size, as shown in + * 'struct vpu_hws_log_buffer_entry'. + * The entry contains the VPU timestamp, operation type and data. + * The host should provide the notify index value of log buffer to VPU. This is a + * value defined within the log buffer and when written to will generate the + * scheduling log notification. + * The host should set engine_idx and vpu_log_buffer_va to 0 to disable logging + * for a particular engine. + * VPU will handle one log buffer for each of supported engines. + * VPU should allow the logging to consume one host_ssid. + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP + * @see VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + */ +struct vpu_ipc_msg_payload_hws_set_scheduling_log { + /* Engine ordinal */ + u32 engine_idx; + /* Host SSID */ + u32 host_ssid; + /* + * VPU log buffer virtual address. + * Set to 0 to disable logging for this engine. + */ + u64 vpu_log_buffer_va; + /* + * Notify index of log buffer. VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + * is generated when an event log is written to this index. + */ + u64 notify_index; +}; + +/* + * @brief The scheduling log notification is generated by VPU when it writes + * an event into the log buffer at the notify_index. VPU notifies host with + * VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION. This is an asynchronous + * message from VPU to host. + * @see VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG + */ +struct vpu_ipc_msg_payload_hws_scheduling_log_notification { + /* Engine ordinal */ + u32 engine_idx; + /* Zero Padding */ + u32 reserved_0; +}; + +/* + * @brief HWS suspend command queue request and done structure. + * Host will request the suspend of contexts and VPU will; + * - Suspend all work on this context + * - Preempt any running work + * - Asynchronously perform the above and return success immediately once + * all items above are started successfully + * - Notify the host of completion of these operations via + * VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE + * - Reject any other context operations on a context with an in-flight + * suspend request running + * Same structure used when VPU notifies host of completion of a context suspend + * request. The ids and suspend fence value reported in this command will match + * the one in the request from the host to suspend the context. Once suspend is + * complete, VPU will not access any data relating to this command queue until + * it is resumed. + * @see VPU_JSM_MSG_HWS_SUSPEND_CMDQ + * @see VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE + */ +struct vpu_ipc_msg_payload_hws_suspend_cmdq { + /* Host SSID */ + u32 host_ssid; + /* Zero Padding */ + u32 reserved_0; + /* Command queue id */ + u64 cmdq_id; + /* + * Suspend fence value - reported by the VPU suspend context + * completed once suspend is complete. + */ + u64 suspend_fence_value; +}; + +/* + * @brief HWS Resume command queue request / response structure. + * Host will request the resume of a context; + * - VPU will resume all work on this context + * - Scheduler will allow this context to be scheduled + * @see VPU_JSM_MSG_HWS_RESUME_CMDQ + * @see VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP + */ +struct vpu_ipc_msg_payload_hws_resume_cmdq { + /* Host SSID */ + u32 host_ssid; + /* Zero Padding */ + u32 reserved_0; + /* Command queue id */ + u64 cmdq_id; +}; + +/* + * @brief HWS Resume engine request / response structure. + * After a HWS engine reset, all scheduling is stopped on VPU until a engine resume. + * Host shall send this command to resume scheduling of any valid queue. + * @see VPU_JSM_MSG_HWS_RESUME_ENGINE + * @see VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE + */ +struct vpu_ipc_msg_payload_hws_resume_engine { + /* Engine to be resumed */ + u32 engine_idx; + /* Reserved */ + u32 reserved_0; +}; + /** * Payload for VPU_JSM_MSG_TRACE_SET_CONFIG[_RSP] and * VPU_JSM_MSG_TRACE_GET_CONFIG_RSP messages. @@ -938,6 +1181,35 @@ struct vpu_ipc_msg_payload_dyndbg_control { char dyndbg_cmd[VPU_DYNDBG_CMD_MAX_LEN]; }; +/** + * Payload for VPU_JSM_MSG_PWR_D0I3_ENTER + * + * This is a bi-directional payload. + */ +struct vpu_ipc_msg_payload_pwr_d0i3_enter { + /** + * 0: VPU_JSM_MSG_PWR_D0I3_ENTER_DONE is not sent to the host driver + * The driver will poll for D0i2 Idle state transitions. + * 1: VPU_JSM_MSG_PWR_D0I3_ENTER_DONE is sent after VPU state save is complete + */ + u32 send_response; + u32 reserved_0; +}; + +/** + * Payload for VPU_JSM_MSG_DCT_ENABLE message. + * + * Default values for DCT active/inactive times are 5.3ms and 30ms respectively, + * corresponding to a 85% duty cycle. This payload allows the host to tune these + * values according to application requirements. + */ +struct vpu_ipc_msg_payload_pwr_dct_control { + /** Duty cycle active time in microseconds */ + u32 dct_active_us; + /** Duty cycle inactive time in microseconds */ + u32 dct_inactive_us; +}; + /* * Payloads union, used to define complete message format. */ @@ -974,6 +1246,13 @@ union vpu_ipc_msg_payload { struct vpu_ipc_msg_payload_hws_destroy_cmdq hws_destroy_cmdq; struct vpu_ipc_msg_payload_hws_set_context_sched_properties hws_set_context_sched_properties; + struct vpu_ipc_msg_payload_hws_set_scheduling_log hws_set_scheduling_log; + struct vpu_ipc_msg_payload_hws_scheduling_log_notification hws_scheduling_log_notification; + struct vpu_ipc_msg_payload_hws_suspend_cmdq hws_suspend_cmdq; + struct vpu_ipc_msg_payload_hws_resume_cmdq hws_resume_cmdq; + struct vpu_ipc_msg_payload_hws_resume_engine hws_resume_engine; + struct vpu_ipc_msg_payload_pwr_d0i3_enter pwr_d0i3_enter; + struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control; }; /* From 9692b1dcefe79ea47f7d5a94acff74303c6563c6 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 28 Oct 2023 15:34:06 +0200 Subject: [PATCH 0117/7721] accel/ivpu: Remove unneeded drm_driver declaration Cleanup drm_driver declaration leftover. Reviewed-by: Krystian Pradzynski Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-3-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index b6aa8893ff1c..8f5655dfd83f 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -31,8 +31,6 @@ __stringify(DRM_IVPU_DRIVER_MINOR) "." #endif -static const struct drm_driver driver; - static struct lock_class_key submitted_jobs_xa_lock_class_key; int ivpu_dbg_mask; From f13108fc7bae7085616805ed176b2114cdf4bd55 Mon Sep 17 00:00:00 2001 From: Tomasz Rusinowicz Date: Sat, 28 Oct 2023 15:34:07 +0200 Subject: [PATCH 0118/7721] accel/ivpu: Add dvfs_mode file to debugfs Add new debugfs file to set dvfs_mode FW boot parameter and restart the FW to allow experimenting with DVFS (dynamic voltage & frequency scaling). Signed-off-by: Tomasz Rusinowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-4-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_debugfs.c | 28 ++++++++++++++++++++++++++++ drivers/accel/ivpu/ivpu_fw.c | 5 +++++ drivers/accel/ivpu/ivpu_fw.h | 1 + 3 files changed, 34 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index ea453b985b49..6e0d56823024 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -115,6 +115,31 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = { {"reset_pending", reset_pending_show, 0}, }; +static ssize_t +dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + struct ivpu_fw_info *fw = vdev->fw; + u32 dvfs_mode; + int ret; + + ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); + if (ret < 0) + return ret; + + fw->dvfs_mode = dvfs_mode; + + ivpu_pm_schedule_recovery(vdev); + + return size; +} + +static const struct file_operations dvfs_mode_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = dvfs_mode_fops_write, +}; + static int fw_log_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = s->private; @@ -280,6 +305,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); + debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, + &dvfs_mode_fops); + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 6142b09cf55a..b81827540db9 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -182,6 +182,8 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; fw->trace_hw_component_mask = -1; + fw->dvfs_mode = 0; + ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n", fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size); ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n", @@ -422,6 +424,8 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->punit_telemetry_sram_size); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n", boot_params->vpu_telemetry_enable); + ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", + boot_params->dvfs_mode); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) @@ -492,6 +496,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_base = ivpu_hw_reg_telemetry_offset_get(vdev); boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); + boot_params->dvfs_mode = vdev->fw->dvfs_mode; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 10ae2847f0ef..66b60fa161b5 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -27,6 +27,7 @@ struct ivpu_fw_info { u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; + u32 dvfs_mode; }; int ivpu_fw_init(struct ivpu_device *vdev); From bacc130d4671a9568352b8d7606cfe7a50d38a56 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Sat, 28 Oct 2023 15:34:08 +0200 Subject: [PATCH 0119/7721] accel/ivpu: Remove reset from power up sequence Setting a non-zero work point resets the IP hence IP_RESET trigger is redundant. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-5-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_hw_37xx.c | 4 ---- drivers/accel/ivpu/ivpu_hw_40xx.c | 6 ------ 2 files changed, 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index e5cb9d8acb82..8340c84ed6de 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -651,10 +651,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_37xx_reset(vdev); - if (ret) - ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); - ret = ivpu_hw_37xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 4bf4c8780044..eb8218d15f01 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -811,12 +811,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_reset(vdev); - if (ret) { - ivpu_err(vdev, "Failed to reset HW: %d\n", ret); - return ret; - } - ret = ivpu_hw_40xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); From 61ab485f0eb1e5b7e2be10ec657a054d36ef5035 Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Sat, 28 Oct 2023 15:34:09 +0200 Subject: [PATCH 0120/7721] accel/ivpu: Add support for VPU_JOB_FLAGS_NULL_SUBMISSION_MASK Add test_mode = 3 that add VPU_JOB_FLAGS_NULL_SUBMISSION_MASK flag to the job send to the VPU device. Then the VPU will process the job but won't execute commands (except the command to signal the fence). This can be used to estimate job processing overhead in the host software and VPU firmware. Unlike the null hardware mode, the null submission mode will still work even if UMD uses VPU fences to track job completion. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-6-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_drv.h | 7 ++++--- drivers/accel/ivpu/ivpu_job.c | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 8f5655dfd83f..4ec8d25a120c 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw"); +MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 12a63f8a73e8..fdec8272da8c 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -147,9 +147,10 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED 0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_DISABLED 0 +#define IVPU_TEST_MODE_FW_TEST 1 +#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_NULL_SUBMISSION 3 extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 689dc0d13b8f..646b8f812901 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,6 +196,8 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; + if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; wmb(); /* Flush WC buffer for jobq header */ From 8b5cec3c2ccf0b12121cb151560c2876219d87e5 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Sat, 28 Oct 2023 15:34:10 +0200 Subject: [PATCH 0121/7721] accel/ivpu: Change test_mode module param to bitmask Change meaning of test_mode module parameter from integer value to bitmask allowing setting different test features with corresponding bits. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-7-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 4 ++-- drivers/accel/ivpu/ivpu_drv.h | 7 +++---- drivers/accel/ivpu/ivpu_job.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 4ec8d25a120c..39bac45d88b5 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); +MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); @@ -315,7 +315,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) unsigned long timeout; int ret; - if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST) + if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST) return 0; ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index fdec8272da8c..ada43ba565c4 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -147,10 +147,9 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED 0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 -#define IVPU_TEST_MODE_NULL_SUBMISSION 3 +#define IVPU_TEST_MODE_FW_TEST BIT(0) +#define IVPU_TEST_MODE_NULL_HW BIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 646b8f812901..6e96c921547d 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,7 +196,7 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; - if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; @@ -404,7 +404,7 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, job->engine_idx, cmdq->jobq->header.tail); - if (ivpu_test_mode == IVPU_TEST_MODE_NULL_HW) { + if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) { ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); cmdq->jobq->header.head = cmdq->jobq->header.tail; wmb(); /* Flush WC buffer for jobq header */ From db37a5bfe97588992c75c29c1f0e19c88d364ce5 Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Sat, 28 Oct 2023 15:34:11 +0200 Subject: [PATCH 0122/7721] accel/ivpu/40xx: Capture D0i3 entry host and device timestamps The driver needs to capture the D0i3 entry timestamp to calculate D0i3 residency time. The D0i3 residency time and the VPU timestamp are passed to the firmware at D0i3 exit (warm boot). Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-8-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_hw_40xx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index eb8218d15f01..0eb9c827f6dc 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -879,10 +879,18 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT); +} + static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); From 3de6d9597892ef899d7e90f589e23c9298013134 Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Sat, 28 Oct 2023 15:34:12 +0200 Subject: [PATCH 0123/7721] accel/ivpu: Pass D0i3 residency time to the VPU firmware The firmware needs to know the time spent in D0i3/D3 to calculate telemetry data. The D0i3/D3 residency time is calculated by the driver and passed to the firmware in the boot parameters. The driver also passes VPU perf counter value captured right before entering D0i3 - this allows the VPU firmware to generate monotonic timestamps for the logs. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-9-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_fw.c | 17 ++++++++++++++++- drivers/accel/ivpu/ivpu_hw.h | 2 ++ drivers/accel/ivpu/ivpu_hw_37xx.c | 8 ++++++++ drivers/accel/ivpu/ivpu_hw_37xx_reg.h | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index b81827540db9..383e4d9b97c8 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -426,14 +426,27 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->vpu_telemetry_enable); ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", boot_params->dvfs_mode); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", + boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", + boot_params->d0i3_entry_vpu_ts); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) { struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; - /* In case of warm boot we only have to reset the entrypoint addr */ + /* In case of warm boot only update variable params */ if (!ivpu_fw_is_cold_boot(vdev)) { + boot_params->d0i3_residency_time_us = + ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); + boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; + + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", + boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", + boot_params->d0i3_entry_vpu_ts); + boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; return; @@ -497,6 +510,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); boot_params->dvfs_mode = vdev->fw->dvfs_mode; + boot_params->d0i3_residency_time_us = 0; + boot_params->d0i3_entry_vpu_ts = 0; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index ab341237bcf9..fd4809b56168 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -57,6 +57,8 @@ struct ivpu_hw_info { u32 sku; u16 config; int dma_bits; + ktime_t d0i3_entry_host_ts; + u64 d0i3_entry_vpu_ts; }; extern const struct ivpu_hw_ops ivpu_hw_37xx_ops; diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 8340c84ed6de..451c9777b237 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -714,10 +714,18 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT); +} + static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) ivpu_err(vdev, "Failed to reset the VPU\n"); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h index 4083beb5e9db..f6fec1919202 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h @@ -240,6 +240,8 @@ #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) +#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u + #define VPU_37XX_CPU_SS_DOORBELL_0 0x06300000u #define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) From 45e45362e0955fc3b0b622e8a0d788097f3de902 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Sat, 28 Oct 2023 15:34:13 +0200 Subject: [PATCH 0124/7721] accel/ivpu: Introduce ivpu_ipc_send_receive_active() Split ivpu_ipc_send_receive() implementation to have a version that does not call pm_runtime_resume_and_get(). That implementation can be invoked when device is up and runtime resume is prohibited (for example at the end of boot sequence). The new function will be used for D0i3 entry IPC message addition in the separate change. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-10-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 33 ++++++++++++++++++++++----------- drivers/accel/ivpu/ivpu_ipc.h | 8 +++++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 6e213a5afb8c..d069d1e1f91d 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -288,23 +288,20 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req return ret; } -int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms) +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) { struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB }; struct vpu_jsm_msg hb_resp; int ret, hb_ret; - ret = ivpu_rpm_get(vdev); - if (ret < 0) - return ret; + drm_WARN_ON(&vdev->drm, + vdev->drm.dev->power.runtime_status == RPM_SUSPENDED); - ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp, - channel, timeout_ms); + ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) - goto rpm_put; + return ret; hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, @@ -314,7 +311,21 @@ int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, ivpu_pm_schedule_recovery(vdev); } -rpm_put: + return ret; +} + +int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) +{ + int ret; + + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + + ret = ivpu_ipc_send_receive_active(vdev, req, expected_resp, resp, channel, timeout_ms); + ivpu_rpm_put(vdev); return ret; } diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 68f5b6668e00..6918db23daa4 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -85,9 +85,11 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms); +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms); int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms); + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms); #endif /* __IVPU_IPC_H__ */ From cc19fedab8bdbe0f81d320ff9a6fdb3b5b01be83 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 28 Oct 2023 15:34:14 +0200 Subject: [PATCH 0125/7721] accel/ivpu/37xx: Print warning when VPUIP is not idle during power down Print warning if VPUIP is not idle during power down. Use warn log level also when we fail to enter reset state as this is not really an error but unexpected behavior. Reviewed-by: Krystian Pradzynski Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-11-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_hw_37xx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 451c9777b237..1b47d77b4c6e 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -726,8 +726,11 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); - if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) - ivpu_err(vdev, "Failed to reset the VPU\n"); + if (!ivpu_hw_37xx_is_idle(vdev)) { + ivpu_warn(vdev, "VPU not idle during power down\n"); + if (ivpu_hw_37xx_reset(vdev)) + ivpu_warn(vdev, "Failed to reset the VPU\n"); + } if (ivpu_pll_disable(vdev)) { ivpu_err(vdev, "Failed to disable PLL\n"); From 3198a62eb8f8411b605501cb78c2298c67ecee91 Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Sat, 28 Oct 2023 15:34:15 +0200 Subject: [PATCH 0126/7721] accel/ivpu: Add support for delayed D0i3 entry message Currently the VPU firmware prepares for D0i3 every time the VPU is entering D0i2 Idle state. This is not optimal as we might not enter D0i3 every time we enter D0i2 Idle and this preparation is quite costly. This optimization moves D0i3 preparation to a dedicated message sent from the host driver only when the driver is about to enter D0i3 - this reduces power consumption and latency for certain workloads, for example audio workloads that submit inference every 10 ms. The VPU needs non zero time to enter IDLE state after responding to D0i3 entry message. If the driver does not wait for the VPU to enter IDLE state it could cause warm boot failures. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-12-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.h | 10 +++++-- drivers/accel/ivpu/ivpu_fw.c | 48 +++++++++++++++++++++++++++++-- drivers/accel/ivpu/ivpu_hw.h | 6 ++++ drivers/accel/ivpu/ivpu_hw_37xx.c | 9 +++++- drivers/accel/ivpu/ivpu_hw_40xx.c | 10 +++++++ drivers/accel/ivpu/ivpu_jsm_msg.c | 21 ++++++++++++++ drivers/accel/ivpu/ivpu_jsm_msg.h | 1 + drivers/accel/ivpu/ivpu_pm.c | 11 ++++++- 8 files changed, 108 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index ada43ba565c4..1b482d1d66d9 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -87,6 +87,7 @@ struct ivpu_wa_table { bool d3hot_after_power_off; bool interrupt_clear_with_0; bool disable_clock_relinquish; + bool disable_d0i3_msg; }; struct ivpu_hw_info; @@ -125,6 +126,7 @@ struct ivpu_device { int tdr; int reschedule_suspend; int autosuspend; + int d0i3_entry_msg; } timeout; }; @@ -147,9 +149,11 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_FW_TEST BIT(0) -#define IVPU_TEST_MODE_NULL_HW BIT(1) -#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) +#define IVPU_TEST_MODE_FW_TEST BIT(0) +#define IVPU_TEST_MODE_NULL_HW BIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) +#define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) +#define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 383e4d9b97c8..4a21be3a0c59 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -33,12 +33,17 @@ #define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31) -#define IVPU_FW_CHECK_API(vdev, fw_hdr, name, min_major) \ +/* Check if FW API is compatible with the driver */ +#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \ ivpu_fw_check_api(vdev, fw_hdr, #name, \ VPU_##name##_API_VER_INDEX, \ VPU_##name##_API_VER_MAJOR, \ VPU_##name##_API_VER_MINOR, min_major) +/* Check if API version is lower that the given version */ +#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \ + ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor) + static char *ivpu_firmware; module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); MODULE_PARM_DESC(firmware, "VPU firmware binary in /lib/firmware/.."); @@ -105,6 +110,19 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw return 0; } +static bool +ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, + const char *str, int index, u16 major, u16 minor) +{ + u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16); + u16 fw_minor = (u16)(fw_hdr->api_version[index]); + + if (fw_major < major || (fw_major == major && fw_minor < minor)) + return true; + + return false; +} + static int ivpu_fw_parse(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -164,9 +182,9 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ivpu_info(vdev, "Firmware: %s, version: %s", fw->name, (const char *)fw_hdr + VPU_FW_HEADER_SIZE); - if (IVPU_FW_CHECK_API(vdev, fw_hdr, BOOT, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) return -EINVAL; - if (IVPU_FW_CHECK_API(vdev, fw_hdr, JSM, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3)) return -EINVAL; fw->runtime_addr = runtime_addr; @@ -197,6 +215,24 @@ static void ivpu_fw_release(struct ivpu_device *vdev) release_firmware(vdev->fw->file); } +/* Initialize workarounds that depend on FW version */ +static void +ivpu_fw_init_wa(struct ivpu_device *vdev) +{ + const struct vpu_firmware_header *fw_hdr = (const void *)vdev->fw->file->data; + + if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, BOOT, 3, 17) || + (ivpu_hw_gen(vdev) > IVPU_HW_37XX) || + (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_DISABLE)) + vdev->wa.disable_d0i3_msg = true; + + /* Force enable the feature for testing purposes */ + if (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_ENABLE) + vdev->wa.disable_d0i3_msg = false; + + IVPU_PRINT_WA(disable_d0i3_msg); +} + static int ivpu_fw_update_global_range(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -299,6 +335,8 @@ int ivpu_fw_init(struct ivpu_device *vdev) if (ret) goto err_fw_release; + ivpu_fw_init_wa(vdev); + ret = ivpu_fw_mem_init(vdev); if (ret) goto err_fw_release; @@ -426,6 +464,8 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->vpu_telemetry_enable); ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", boot_params->dvfs_mode); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_delayed_entry = %d\n", + boot_params->d0i3_delayed_entry); ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", boot_params->d0i3_residency_time_us); ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", @@ -510,6 +550,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); boot_params->dvfs_mode = vdev->fw->dvfs_mode; + if (!IVPU_WA(disable_d0i3_msg)) + boot_params->d0i3_delayed_entry = 1; boot_params->d0i3_residency_time_us = 0; boot_params->d0i3_entry_vpu_ts = 0; diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index fd4809b56168..b7694b1cbc02 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -14,6 +14,7 @@ struct ivpu_hw_ops { int (*boot_fw)(struct ivpu_device *vdev); int (*power_down)(struct ivpu_device *vdev); bool (*is_idle)(struct ivpu_device *vdev); + int (*wait_for_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); u32 (*reg_pll_freq_get)(struct ivpu_device *vdev); @@ -86,6 +87,11 @@ static inline bool ivpu_hw_is_idle(struct ivpu_device *vdev) return vdev->hw->ops->is_idle(vdev); }; +static inline int ivpu_hw_wait_for_idle(struct ivpu_device *vdev) +{ + return vdev->hw->ops->wait_for_idle(vdev); +}; + static inline int ivpu_hw_power_down(struct ivpu_device *vdev) { ivpu_dbg(vdev, PM, "HW power down\n"); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 1b47d77b4c6e..1c8c5715095b 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -37,7 +37,7 @@ #define TIMEOUT_US (150 * USEC_PER_MSEC) #define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC) #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC) -#define IDLE_TIMEOUT_US (500 * USEC_PER_MSEC) +#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) #define ICB_0_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \ @@ -90,6 +90,7 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = 10; + vdev->timeout.d0i3_entry_msg = 5; } static int ivpu_pll_wait_for_cmd_send(struct ivpu_device *vdev) @@ -714,6 +715,11 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_37xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) { vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); @@ -1001,6 +1007,7 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { .info_init = ivpu_hw_37xx_info_init, .power_up = ivpu_hw_37xx_power_up, .is_idle = ivpu_hw_37xx_is_idle, + .wait_for_idle = ivpu_hw_37xx_wait_for_idle, .power_down = ivpu_hw_37xx_power_down, .boot_fw = ivpu_hw_37xx_boot_fw, .wdt_disable = ivpu_hw_37xx_wdt_disable, diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 0eb9c827f6dc..6a9672f650d1 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -39,6 +39,7 @@ #define TIMEOUT_US (150 * USEC_PER_MSEC) #define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC) #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC) +#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) #define WEIGHTS_DEFAULT 0xf711f711u #define WEIGHTS_ATS_DEFAULT 0x0000f711u @@ -140,18 +141,21 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.tdr = 2000000; vdev->timeout.reschedule_suspend = 1000; vdev->timeout.autosuspend = -1; + vdev->timeout.d0i3_entry_msg = 500; } else if (ivpu_is_simics(vdev)) { vdev->timeout.boot = 50; vdev->timeout.jsm = 500; vdev->timeout.tdr = 10000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = -1; + vdev->timeout.d0i3_entry_msg = 100; } else { vdev->timeout.boot = 1000; vdev->timeout.jsm = 500; vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = 10; + vdev->timeout.d0i3_entry_msg = 5; } } @@ -879,6 +883,11 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_40xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) { vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); @@ -1168,6 +1177,7 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = { .info_init = ivpu_hw_40xx_info_init, .power_up = ivpu_hw_40xx_power_up, .is_idle = ivpu_hw_40xx_is_idle, + .wait_for_idle = ivpu_hw_40xx_wait_for_idle, .power_down = ivpu_hw_40xx_power_down, .boot_fw = ivpu_hw_40xx_boot_fw, .wdt_disable = ivpu_hw_40xx_wdt_disable, diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 35a689475c68..8cea0dd731b9 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -4,6 +4,7 @@ */ #include "ivpu_drv.h" +#include "ivpu_hw.h" #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" @@ -260,3 +261,23 @@ int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid) return ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); } + +int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev) +{ + struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_PWR_D0I3_ENTER }; + struct vpu_jsm_msg resp; + int ret; + + if (IVPU_WA(disable_d0i3_msg)) + return 0; + + req.payload.pwr_d0i3_enter.send_response = 1; + + ret = ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_PWR_D0I3_ENTER_DONE, + &resp, VPU_IPC_CHAN_GEN_CMD, + vdev->timeout.d0i3_entry_msg); + if (ret) + return ret; + + return ivpu_hw_wait_for_idle(vdev); +} diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h index 66979a948c7c..ae75e5dbcc41 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.h +++ b/drivers/accel/ivpu/ivpu_jsm_msg.h @@ -22,4 +22,5 @@ int ivpu_jsm_trace_get_capability(struct ivpu_device *vdev, u32 *trace_destinati int ivpu_jsm_trace_set_config(struct ivpu_device *vdev, u32 trace_level, u32 trace_destination_mask, u64 trace_hw_component_mask); int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid); +int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev); #endif diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 568e4295dc56..2d05fb9e3197 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -15,6 +15,7 @@ #include "ivpu_fw.h" #include "ivpu_ipc.h" #include "ivpu_job.h" +#include "ivpu_jsm_msg.h" #include "ivpu_mmu.h" #include "ivpu_pm.h" @@ -153,6 +154,8 @@ int ivpu_pm_suspend_cb(struct device *dev) } } + ivpu_jsm_pwr_d0i3_enter(vdev); + ivpu_suspend(vdev); ivpu_pm_prepare_warm_boot(vdev); @@ -188,6 +191,7 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); struct ivpu_device *vdev = to_ivpu_device(drm); + bool hw_is_idle = true; int ret; ivpu_dbg(vdev, PM, "Runtime suspend..\n"); @@ -200,11 +204,16 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) return -EAGAIN; } + if (!vdev->pm->suspend_reschedule_counter) + hw_is_idle = false; + else if (ivpu_jsm_pwr_d0i3_enter(vdev)) + hw_is_idle = false; + ret = ivpu_suspend(vdev); if (ret) ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret); - if (!vdev->pm->suspend_reschedule_counter) { + if (!hw_is_idle) { ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n"); ivpu_pm_prepare_cold_boot(vdev); } else { From 36f27350ff745bd228ab04d7845dfbffc177a889 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Fri, 27 Oct 2023 10:28:22 -0700 Subject: [PATCH 0127/7721] i915/perf: Fix NULL deref bugs with drm_dbg() calls When i915 perf interface is not available dereferencing it will lead to NULL dereferences. As returning -ENOTSUPP is pretty clear return when perf interface is not available. Fixes: 2fec539112e8 ("i915/perf: Replace DRM_DEBUG with driver specific drm_dbg call") Suggested-by: Tvrtko Ursulin Signed-off-by: Harshit Mogalapalli Reviewed-by: Tvrtko Ursulin Cc: # v6.0+ Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20231027172822.2753059-1-harshit.m.mogalapalli@oracle.com [tursulin: added stable tag] --- drivers/gpu/drm/i915/i915_perf.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 7178f298b3e6..f92c2a464ebe 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -4227,11 +4227,8 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, u32 known_open_flags; int ret; - if (!perf->i915) { - drm_dbg(&perf->i915->drm, - "i915 perf interface not available for this system\n"); + if (!perf->i915) return -ENOTSUPP; - } known_open_flags = I915_PERF_FLAG_FD_CLOEXEC | I915_PERF_FLAG_FD_NONBLOCK | @@ -4607,11 +4604,8 @@ int i915_perf_add_config_ioctl(struct drm_device *dev, void *data, struct i915_oa_reg *regs; int err, id; - if (!perf->i915) { - drm_dbg(&perf->i915->drm, - "i915 perf interface not available for this system\n"); + if (!perf->i915) return -ENOTSUPP; - } if (!perf->metrics_kobj) { drm_dbg(&perf->i915->drm, @@ -4773,11 +4767,8 @@ int i915_perf_remove_config_ioctl(struct drm_device *dev, void *data, struct i915_oa_config *oa_config; int ret; - if (!perf->i915) { - drm_dbg(&perf->i915->drm, - "i915 perf interface not available for this system\n"); + if (!perf->i915) return -ENOTSUPP; - } if (i915_perf_stream_paranoid && !perfmon_capable()) { drm_dbg(&perf->i915->drm, From 79d94360d50fcd487edcfe118a47a2881534923f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Mon, 23 Oct 2023 07:58:33 -0300 Subject: [PATCH 0128/7721] drm/v3d: wait for all jobs to finish before unregistering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we are only warning the user if the BIN or RENDER jobs don't finish before we unregister V3D. We must wait for all jobs to finish before unregistering. Therefore, warn the user if TFU or CSD jobs are not done by the time the driver is unregistered. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231023105927.101502-1-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 2e94ce788c71..afa7d170d1ff 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -1072,6 +1072,8 @@ v3d_gem_destroy(struct drm_device *dev) */ WARN_ON(v3d->bin_job); WARN_ON(v3d->render_job); + WARN_ON(v3d->tfu_job); + WARN_ON(v3d->csd_job); drm_mm_takedown(&v3d->mm); From 0db5649e9e5962cc25f813f9fca08588f97fe5b8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 26 Oct 2023 13:13:32 +0300 Subject: [PATCH 0129/7721] drm/i915: fix Makefile sort and indent Unify the line continuations and indents, and sort the build lists. Reviewed-by: Nirmoy Das Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231026101333.875406-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 169 ++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3b9dcb606fc1..d1f53dbf95f2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -47,33 +47,34 @@ subdir-ccflags-y += -I$(srctree)/$(src) # Please keep these build lists sorted! # core driver code -i915-y += i915_driver.o \ - i915_drm_client.o \ - i915_config.o \ - i915_getparam.o \ - i915_ioctl.o \ - i915_irq.o \ - i915_mitigations.o \ - i915_module.o \ - i915_params.o \ - i915_pci.o \ - i915_scatterlist.o \ - i915_suspend.o \ - i915_switcheroo.o \ - i915_sysfs.o \ - i915_utils.o \ - intel_clock_gating.o \ - intel_device_info.o \ - intel_memory_region.o \ - intel_pcode.o \ - intel_region_ttm.o \ - intel_runtime_pm.o \ - intel_sbi.o \ - intel_step.o \ - intel_uncore.o \ - intel_wakeref.o \ - vlv_sideband.o \ - vlv_suspend.o +i915-y += \ + i915_config.o \ + i915_driver.o \ + i915_drm_client.o \ + i915_getparam.o \ + i915_ioctl.o \ + i915_irq.o \ + i915_mitigations.o \ + i915_module.o \ + i915_params.o \ + i915_pci.o \ + i915_scatterlist.o \ + i915_suspend.o \ + i915_switcheroo.o \ + i915_sysfs.o \ + i915_utils.o \ + intel_clock_gating.o \ + intel_device_info.o \ + intel_memory_region.o \ + intel_pcode.o \ + intel_region_ttm.o \ + intel_runtime_pm.o \ + intel_sbi.o \ + intel_step.o \ + intel_uncore.o \ + intel_wakeref.o \ + vlv_sideband.o \ + vlv_suspend.o # core peripheral code i915-y += \ @@ -90,14 +91,16 @@ i915-y += \ i915_syncmap.o \ i915_user_extensions.o -i915-$(CONFIG_COMPAT) += i915_ioc32.o +i915-$(CONFIG_COMPAT) += \ + i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += \ i915_debugfs.o \ i915_debugfs_params.o \ display/intel_display_debugfs.o \ display/intel_display_debugfs_params.o \ display/intel_pipe_crc.o -i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o +i915-$(CONFIG_PERF_EVENTS) += \ + i915_pmu.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ @@ -154,7 +157,8 @@ gt-y += \ gt/sysfs_engines.o # x86 intel-gtt module support -gt-$(CONFIG_X86) += gt/intel_ggtt_gmch.o +gt-$(CONFIG_X86) += \ + gt/intel_ggtt_gmch.o # autogenerated null render state gt-y += \ gt/gen6_renderstate.o \ @@ -173,9 +177,9 @@ gem-y += \ gem/i915_gem_domain.o \ gem/i915_gem_execbuffer.o \ gem/i915_gem_internal.o \ - gem/i915_gem_object.o \ gem/i915_gem_lmem.o \ gem/i915_gem_mman.o \ + gem/i915_gem_object.o \ gem/i915_gem_pages.o \ gem/i915_gem_phys.o \ gem/i915_gem_pm.o \ @@ -192,57 +196,61 @@ gem-y += \ gem/i915_gem_wait.o \ gem/i915_gemfs.o i915-y += \ - $(gem-y) \ - i915_active.o \ - i915_cmd_parser.o \ - i915_deps.o \ - i915_gem_evict.o \ - i915_gem_gtt.o \ - i915_gem_ww.o \ - i915_gem.o \ - i915_query.o \ - i915_request.o \ - i915_scheduler.o \ - i915_trace_points.o \ - i915_ttm_buddy_manager.o \ - i915_vma.o \ - i915_vma_resource.o + $(gem-y) \ + i915_active.o \ + i915_cmd_parser.o \ + i915_deps.o \ + i915_gem.o \ + i915_gem_evict.o \ + i915_gem_gtt.o \ + i915_gem_ww.o \ + i915_query.o \ + i915_request.o \ + i915_scheduler.o \ + i915_trace_points.o \ + i915_ttm_buddy_manager.o \ + i915_vma.o \ + i915_vma_resource.o # general-purpose microcontroller (GuC) support i915-y += \ - gt/uc/intel_gsc_fw.o \ - gt/uc/intel_gsc_proxy.o \ - gt/uc/intel_gsc_uc.o \ - gt/uc/intel_gsc_uc_debugfs.o \ - gt/uc/intel_gsc_uc_heci_cmd_submit.o \ - gt/uc/intel_guc.o \ - gt/uc/intel_guc_ads.o \ - gt/uc/intel_guc_capture.o \ - gt/uc/intel_guc_ct.o \ - gt/uc/intel_guc_debugfs.o \ - gt/uc/intel_guc_fw.o \ - gt/uc/intel_guc_hwconfig.o \ - gt/uc/intel_guc_log.o \ - gt/uc/intel_guc_log_debugfs.o \ - gt/uc/intel_guc_rc.o \ - gt/uc/intel_guc_slpc.o \ - gt/uc/intel_guc_submission.o \ - gt/uc/intel_huc.o \ - gt/uc/intel_huc_debugfs.o \ - gt/uc/intel_huc_fw.o \ - gt/uc/intel_uc.o \ - gt/uc/intel_uc_debugfs.o \ - gt/uc/intel_uc_fw.o + gt/uc/intel_gsc_fw.o \ + gt/uc/intel_gsc_proxy.o \ + gt/uc/intel_gsc_uc.o \ + gt/uc/intel_gsc_uc_debugfs.o \ + gt/uc/intel_gsc_uc_heci_cmd_submit.o\ + gt/uc/intel_guc.o \ + gt/uc/intel_guc_ads.o \ + gt/uc/intel_guc_capture.o \ + gt/uc/intel_guc_ct.o \ + gt/uc/intel_guc_debugfs.o \ + gt/uc/intel_guc_fw.o \ + gt/uc/intel_guc_hwconfig.o \ + gt/uc/intel_guc_log.o \ + gt/uc/intel_guc_log_debugfs.o \ + gt/uc/intel_guc_rc.o \ + gt/uc/intel_guc_slpc.o \ + gt/uc/intel_guc_submission.o \ + gt/uc/intel_huc.o \ + gt/uc/intel_huc_debugfs.o \ + gt/uc/intel_huc_fw.o \ + gt/uc/intel_uc.o \ + gt/uc/intel_uc_debugfs.o \ + gt/uc/intel_uc_fw.o # graphics system controller (GSC) support -i915-y += gt/intel_gsc.o +i915-y += \ + gt/intel_gsc.o # graphics hardware monitoring (HWMON) support -i915-$(CONFIG_HWMON) += i915_hwmon.o +i915-$(CONFIG_HWMON) += \ + i915_hwmon.o # modesetting core code i915-y += \ display/hsw_ips.o \ + display/i9xx_plane.o \ + display/i9xx_wm.o \ display/intel_atomic.o \ display/intel_atomic_plane.o \ display/intel_audio.o \ @@ -289,8 +297,8 @@ i915-y += \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ display/intel_modeset_lock.o \ - display/intel_modeset_verify.o \ display/intel_modeset_setup.o \ + display/intel_modeset_verify.o \ display/intel_overlay.o \ display/intel_pch_display.o \ display/intel_pch_refclk.o \ @@ -304,8 +312,6 @@ i915-y += \ display/intel_vblank.o \ display/intel_vga.o \ display/intel_wm.o \ - display/i9xx_plane.o \ - display/i9xx_wm.o \ display/skl_scaler.o \ display/skl_universal_plane.o \ display/skl_watermark.o @@ -359,13 +365,14 @@ i915-y += \ display/vlv_dsi.o \ display/vlv_dsi_pll.o -i915-y += i915_perf.o +i915-y += \ + i915_perf.o # Protected execution platform (PXP) support. Base support is required for HuC i915-y += \ pxp/intel_pxp.o \ - pxp/intel_pxp_tee.o \ - pxp/intel_pxp_huc.o + pxp/intel_pxp_huc.o \ + pxp/intel_pxp_tee.o i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_cmd.o \ @@ -376,11 +383,11 @@ i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_session.o # Post-mortem debug and GPU hang state capture -i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o +i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += \ + i915_gpu_error.o i915-$(CONFIG_DRM_I915_SELFTEST) += \ gem/selftests/i915_gem_client_blt.o \ gem/selftests/igt_gem_utils.o \ - selftests/intel_scheduler_helpers.o \ selftests/i915_random.o \ selftests/i915_selftest.o \ selftests/igt_atomic.o \ @@ -389,10 +396,12 @@ i915-$(CONFIG_DRM_I915_SELFTEST) += \ selftests/igt_mmap.o \ selftests/igt_reset.o \ selftests/igt_spinner.o \ + selftests/intel_scheduler_helpers.o \ selftests/librapl.o # virtual gpu code -i915-y += i915_vgpu.o +i915-y += \ + i915_vgpu.o i915-$(CONFIG_DRM_I915_GVT) += \ intel_gvt.o \ From 75658332bb1052867d31c67c93bfdbd86a5f7b2a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 26 Oct 2023 13:13:33 +0300 Subject: [PATCH 0130/7721] drm/i915: move Makefile display debugfs files next to display Keep the display build lists together. v2: Rebase Reviewed-by: Nirmoy Das Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231026101333.875406-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d1f53dbf95f2..239da40a401f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -95,10 +95,7 @@ i915-$(CONFIG_COMPAT) += \ i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += \ i915_debugfs.o \ - i915_debugfs_params.o \ - display/intel_display_debugfs.o \ - display/intel_display_debugfs_params.o \ - display/intel_pipe_crc.o + i915_debugfs_params.o i915-$(CONFIG_PERF_EVENTS) += \ i915_pmu.o @@ -320,6 +317,10 @@ i915-$(CONFIG_ACPI) += \ display/intel_opregion.o i915-$(CONFIG_DRM_FBDEV_EMULATION) += \ display/intel_fbdev.o +i915-$(CONFIG_DEBUG_FS) += \ + display/intel_display_debugfs.o \ + display/intel_display_debugfs_params.o \ + display/intel_pipe_crc.o # modesetting output/encoder code i915-y += \ From b2139fb5051554a7f297e4ad584ef1bc26c76d5d Mon Sep 17 00:00:00 2001 From: Steven Price Date: Fri, 20 Oct 2023 11:44:05 +0100 Subject: [PATCH 0131/7721] drm/panfrost: Remove incorrect IS_ERR() check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sg_page_iter_page() doesn't return an error code, so the IS_ERR() check is wrong and the error path will never be executed. This also allows simplifying the code to remove the local variable 'page'. CC: Adrián Larumbe Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/376713ff-9a4f-4ea3-b097-fb5efb685d95@moroto.mountain Signed-off-by: Steven Price Reviewed-by: Adrián Larumbe Tested-by: Adrián Larumbe Link: https://patchwork.freedesktop.org/patch/msgid/20231020104405.53992-1-steven.price@arm.com --- drivers/gpu/drm/panfrost/panfrost_dump.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c index e7942ac449c6..47751302f1bc 100644 --- a/drivers/gpu/drm/panfrost/panfrost_dump.c +++ b/drivers/gpu/drm/panfrost/panfrost_dump.c @@ -220,16 +220,8 @@ void panfrost_core_dump(struct panfrost_job *job) iter.hdr->bomap.data[0] = bomap - bomap_start; - for_each_sgtable_page(bo->base.sgt, &page_iter, 0) { - struct page *page = sg_page_iter_page(&page_iter); - - if (!IS_ERR(page)) { - *bomap++ = page_to_phys(page); - } else { - dev_err(pfdev->dev, "Panfrost Dump: wrong page\n"); - *bomap++ = 0; - } - } + for_each_sgtable_page(bo->base.sgt, &page_iter, 0) + *bomap++ = page_to_phys(sg_page_iter_page(&page_iter)); iter.hdr->bomap.iova = mapping->mmnode.start << PAGE_SHIFT; From 874d6fe4a6962cc18bb0e62dfc23adbebd0abbe2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 23 Oct 2023 18:02:54 +0300 Subject: [PATCH 0132/7721] drm/i915/pmu: add pmu_to_i915() helper It's tedious to duplicate the container_of() everywhere. Add a helper. Signed-off-by: Jani Nikula Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231023150256.438331-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index f861863eb7c1..52e42d7f23ec 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -31,6 +31,11 @@ static cpumask_t i915_pmu_cpumask; static unsigned int i915_pmu_target_cpu = -1; +static struct drm_i915_private *pmu_to_i915(struct i915_pmu *pmu) +{ + return container_of(pmu, struct drm_i915_private, pmu); +} + static u8 engine_config_sample(u64 config) { return config & I915_PMU_SAMPLE_MASK; @@ -141,7 +146,7 @@ static u32 frequency_enabled_mask(void) static bool pmu_needs_timer(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); u32 enable; /* @@ -251,7 +256,7 @@ static u64 get_rc6(struct intel_gt *gt) static void init_rc6(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); struct intel_gt *gt; unsigned int i; @@ -982,7 +987,7 @@ add_pmu_attr(struct perf_pmu_events_attr *attr, const char *name, static struct attribute ** create_event_attributes(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); static const struct { unsigned int counter; const char *name; From cb476dd1b8b10a40f6ba6e230f0b408916365c1f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 23 Oct 2023 18:02:55 +0300 Subject: [PATCH 0133/7721] drm/i915/pmu: add event_to_pmu() helper It's tedious to duplicate the container_of() everywhere. Add a helper. Also do the logical steps of first getting from struct perf_event to struct i915_pmu, and then from struct i915_pmu to struct drm_i915_private if needed, instead of perf_event->i915->pmu. Not all places even need the i915 pointer. Signed-off-by: Jani Nikula Acked-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231023150256.438331-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 45 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 52e42d7f23ec..5c3c480886db 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -31,6 +31,11 @@ static cpumask_t i915_pmu_cpumask; static unsigned int i915_pmu_target_cpu = -1; +static struct i915_pmu *event_to_pmu(struct perf_event *event) +{ + return container_of(event->pmu, struct i915_pmu, base); +} + static struct drm_i915_private *pmu_to_i915(struct i915_pmu *pmu) { return container_of(pmu, struct drm_i915_private, pmu); @@ -510,8 +515,8 @@ static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) static void i915_pmu_event_destroy(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); drm_WARN_ON(&i915->drm, event->parent); @@ -577,8 +582,8 @@ config_status(struct drm_i915_private *i915, u64 config) static int engine_event_init(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); struct intel_engine_cs *engine; engine = intel_engine_lookup_user(i915, engine_event_class(event), @@ -591,9 +596,8 @@ static int engine_event_init(struct perf_event *event) static int i915_pmu_event_init(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); int ret; if (pmu->closed) @@ -633,9 +637,8 @@ static int i915_pmu_event_init(struct perf_event *event) static u64 __i915_pmu_event_read(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); u64 val = 0; if (is_engine_event(event)) { @@ -691,10 +694,8 @@ static u64 __i915_pmu_event_read(struct perf_event *event) static void i915_pmu_event_read(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); struct hw_perf_event *hwc = &event->hw; - struct i915_pmu *pmu = &i915->pmu; u64 prev, new; if (pmu->closed) { @@ -712,10 +713,9 @@ static void i915_pmu_event_read(struct perf_event *event) static void i915_pmu_enable(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); const unsigned int bit = event_bit(event); - struct i915_pmu *pmu = &i915->pmu; unsigned long flags; if (bit == -1) @@ -776,10 +776,9 @@ static void i915_pmu_enable(struct perf_event *event) static void i915_pmu_disable(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); const unsigned int bit = event_bit(event); - struct i915_pmu *pmu = &i915->pmu; unsigned long flags; if (bit == -1) @@ -823,9 +822,7 @@ static void i915_pmu_disable(struct perf_event *event) static void i915_pmu_event_start(struct perf_event *event, int flags) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); if (pmu->closed) return; @@ -853,9 +850,7 @@ static void i915_pmu_event_stop(struct perf_event *event, int flags) static int i915_pmu_event_add(struct perf_event *event, int flags) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); if (pmu->closed) return -ENODEV; From 76310edddf11a5716f324785e9caad01a90e128a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 23 Oct 2023 18:02:56 +0300 Subject: [PATCH 0134/7721] drm/i915/pmu: rearrange hrtimer pointer chasing Do the logical step of first getting from struct hrtimer to struct i915_pmu, and then from struct i915_pmu to struct drm_i915_private, instead of hrtimer->i915->pmu. Signed-off-by: Jani Nikula Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231023150256.438331-3-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 5c3c480886db..878a27e1c8ef 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -478,9 +478,8 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) { - struct drm_i915_private *i915 = - container_of(hrtimer, struct drm_i915_private, pmu.timer); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = container_of(hrtimer, struct i915_pmu, timer); + struct drm_i915_private *i915 = pmu_to_i915(pmu); unsigned int period_ns; struct intel_gt *gt; unsigned int i; From 9d0d0a2070407fbeceb8700543eb78bb1560d18f Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 17 Oct 2023 20:11:28 +0000 Subject: [PATCH 0135/7721] wifi: brcm80211: replace deprecated strncpy with strscpy Let's move away from using strncpy and instead favor a less ambiguous and more robust interface. For ifp->ndev->name, we expect ifp->ndev->name to be NUL-terminated based on its use in format strings within core.c: 67 | char *brcmf_ifname(struct brcmf_if *ifp) 68 | { 69 | if (!ifp) 70 | return ""; 71 | 72 | if (ifp->ndev) 73 | return ifp->ndev->name; 74 | 75 | return ""; 76 | } ... 288 | static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, 289 | struct net_device *ndev) { ... 330 | brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n", 331 | brcmf_ifname(ifp), head_delta); ... 336 | bphy_err(drvr, "%s: failed to expand headroom\n", 337 | brcmf_ifname(ifp)); For di->name, we expect di->name to be NUL-terminated based on its usage with format strings: | brcms_dbg_dma(di->core, | "%s: DMA64 tx doesn't have AE set\n", | di->name); Looking at its allocation we can see that it is already zero-allocated which means NUL-padding is not required: | di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); For wlc->modulecb[i].name, we expect each name in wlc->modulecb to be NUL-terminated based on their usage with strcmp(): | if (!strcmp(wlc->modulecb[i].name, name) && NUL-padding is not required as wlc is zero-allocated in: brcms_c_attach_malloc() -> | wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC); For all these cases, a suitable replacement is `strscpy` due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231017-strncpy-drivers-net-wireless-broadcom-brcm80211-brcmfmac-cfg80211-c-v3-1-af780d74ae38@google.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c | 3 +-- drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 667462369a32..133c5ea6429c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -866,7 +866,7 @@ struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); err = brcmf_net_attach(ifp, true); if (err) { bphy_err(drvr, "Registering netdevice failed\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index d4492d02e4ea..6e0c90f4718b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2334,7 +2334,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); ifp->ndev->name_assign_type = name_assign_type; err = brcmf_net_attach(ifp, true); if (err) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index b7df576bb84d..3d5c1ef8f7f2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -584,8 +584,7 @@ struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); /* make a private copy of our callers name */ - strncpy(di->name, name, MAXNAMEL); - di->name[MAXNAMEL - 1] = '\0'; + strscpy(di->name, name, sizeof(di->name)); di->dmadev = core->dma_dev; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index b3663c5ef382..34460b5815d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -5551,8 +5551,8 @@ int brcms_c_module_register(struct brcms_pub *pub, /* find an empty entry and just add, no duplication check! */ for (i = 0; i < BRCMS_MAXMODULES; i++) { if (wlc->modulecb[i].name[0] == '\0') { - strncpy(wlc->modulecb[i].name, name, - sizeof(wlc->modulecb[i].name) - 1); + strscpy(wlc->modulecb[i].name, name, + sizeof(wlc->modulecb[i].name)); wlc->modulecb[i].hdl = hdl; wlc->modulecb[i].down_fn = d_fn; return 0; From a614f95797055dd96802202af542b04fead7274f Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 17 Oct 2023 20:11:29 +0000 Subject: [PATCH 0136/7721] wifi: brcmsmac: replace deprecated strncpy with memcpy Let's move away from using strncpy and instead use the more obvious interface for this context. For wlc->pub->srom_ccode, we're just copying two bytes from ccode into wlc->pub->srom_ccode with no expectation that srom_ccode be NUL-terminated: wlc->pub->srom_ccode is only used in regulatory_hint(): 1193 | if (wl->pub->srom_ccode[0] && 1194 | regulatory_hint(wl->wiphy, wl->pub->srom_ccode)) 1195 | wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__); We can see that only index 0 and index 1 are accessed. 3307 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) 3308 | { ... | ... 3322 | request->alpha2[0] = alpha2[0]; 3323 | request->alpha2[1] = alpha2[1]; ... | ... 3332 | } Since this is just a simple byte copy with correct lengths, let's use memcpy(). There should be no functional change. In a similar boat, both wlc->country_default and wlc->autocountry_default are just simple byte copies so let's use memcpy. However, FWICT they aren't used anywhere. (they should be used or removed -- not in scope of my patch, though). Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231017-strncpy-drivers-net-wireless-broadcom-brcm80211-brcmfmac-cfg80211-c-v3-2-af780d74ae38@google.com --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index 5a6d9c86552a..f6962e558d7c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -341,7 +341,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) /* store the country code for passing up as a regulatory hint */ wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); if (brcms_c_country_valid(ccode)) - strncpy(wlc->pub->srom_ccode, ccode, ccode_len); + memcpy(wlc->pub->srom_ccode, ccode, ccode_len); /* * If no custom world domain is found in the SROM, use the @@ -354,10 +354,10 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) } /* save default country for exiting 11d regulatory mode */ - strncpy(wlc->country_default, ccode, ccode_len); + memcpy(wlc->country_default, ccode, ccode_len); /* initialize autocountry_default to driver default */ - strncpy(wlc->autocountry_default, ccode, ccode_len); + memcpy(wlc->autocountry_default, ccode, ccode_len); brcms_c_set_country(wlc_cm, wlc_cm->world_regd); From d1e6b020c32d2c02c427ab2494a7f04da45fe614 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 23 Oct 2023 12:17:04 +0300 Subject: [PATCH 0137/7721] wifi: rtlwifi: cleanup struct rtl_hal Remove unused and set but otherwise unused 'bbrf_ready', 'external_pa', 'pa_mode', 'rx_tag', 'rts_en', 'wow_enable' and 'wow_enabled' fields of 'struct rtl_hal', adjust related code. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231023091722.52509-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c | 7 ------- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 1 - drivers/net/wireless/realtek/rtlwifi/wifi.h | 8 -------- 3 files changed, 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 5a828a934fe9..fad132512a20 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -432,10 +432,8 @@ static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw) static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca; - rtlhal->rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_flag = 0; primarycca->intf_type = 0; @@ -615,13 +613,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } else if (sec_ch_offset == 1) { @@ -642,13 +638,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } @@ -660,7 +654,6 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) cur_mf_state = MF_USC_LSC; /* default */ rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_type = 0; primarycca->intf_flag = 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index ebb7abd0c9ad..d4da5cdc8414 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1320,7 +1320,6 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) err = 1; return err; } - rtlhal->rx_tag = 0; rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000); err = rtl92ee_download_fw(hw, false); if (err) { diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 31a481f43a07..1f3163296836 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1610,7 +1610,6 @@ struct rtl_hal { bool up_first_time; bool first_init; bool being_init_adapter; - bool bbrf_ready; bool mac_func_enable; bool pre_edcca_enable; struct bt_coexist_8723 hal_coex_8723; @@ -1623,9 +1622,7 @@ struct rtl_hal { u8 state; /*stop 0, start 1 */ u8 board_type; u8 package_type; - u8 external_pa; - u8 pa_mode; u8 pa_type_2g; u8 pa_type_5g; u8 lna_type_2g; @@ -1691,14 +1688,9 @@ struct rtl_hal { bool master_of_dmsp; bool slave_of_dmsp; - u16 rx_tag;/*for 92ee*/ - u8 rts_en; - /*for wowlan*/ - bool wow_enable; bool enter_pnp_sleep; bool wake_from_pnp_sleep; - bool wow_enabled; time64_t last_suspend_sec; u32 wowlan_fwsize; u8 *wowlan_firmware; From d1337ccb4477bf789a58ff50d858ffdb0e7998b4 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 23 Oct 2023 12:17:05 +0300 Subject: [PATCH 0138/7721] wifi: rtlwifi: cleanup struct rtl_phy Remove unused and read by otherwise unused 'h2c_box_num', 'rfpienable', 'reserve_0', 'reserve_1', 'iqk_in_progress', 'apk_done' and 'hw_rof_enable' fields of 'struct rtl_phy', adjust related code. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231023091722.52509-2-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c | 4 ---- drivers/net/wireless/realtek/rtlwifi/wifi.h | 7 ------- 2 files changed, 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 3d29c8dbb255..d448efe2c229 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -1487,12 +1487,8 @@ EXPORT_SYMBOL(rtl92c_phy_lc_calibrate); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - if (rtlphy->apk_done) - return; if (IS_92C_SERIAL(rtlhal->version)) _rtl92c_phy_ap_calibrate(hw, delta, true); else diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 1f3163296836..171a461cd812 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1316,7 +1316,6 @@ struct rtl_phy { u8 sw_chnl_stage; u8 sw_chnl_step; u8 current_channel; - u8 h2c_box_num; u8 set_io_inprogress; u8 lck_inprogress; @@ -1329,9 +1328,6 @@ struct rtl_phy { s32 reg_ebc; s32 reg_ec4; s32 reg_ecc; - u8 rfpienable; - u8 reserve_0; - u16 reserve_1; u32 reg_c04, reg_c08, reg_874; u32 adda_backup[16]; u32 iqk_mac_backup[IQK_MAC_REG_NUM]; @@ -1345,7 +1341,6 @@ struct rtl_phy { struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; bool rfpi_enable; - bool iqk_in_progress; u8 pwrgroup_cnt; u8 cck_high_power; @@ -1383,7 +1378,6 @@ struct rtl_phy { [MAX_RF_PATH_NUM]; u32 rfreg_chnlval[2]; - bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ u32 backup_rf_0x1a;/*92ee*/ @@ -1395,7 +1389,6 @@ struct rtl_phy { struct phy_parameters hwparam_tables[MAX_TAB]; u16 rf_pathmap; - u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ enum rt_polarity_ctl polarity_ctl; }; From 7419d8ab35087ba2164e92e8c9f1e418bc303a06 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 23 Oct 2023 12:17:06 +0300 Subject: [PATCH 0139/7721] wifi: rtlwifi: rtl92ee_dm_dynamic_primary_cca_check(): fix typo in function name For rtl8192ee, change 'rtl92ee_dm_dynamic_primary_cca_ckeck()' to 'rtl92ee_dm_dynamic_primary_cca_check()' and so adjust 'rtl92ee_dm_watchdog()' as well. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231023091722.52509-3-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index fad132512a20..17486e3f322c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -560,7 +560,7 @@ static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw, primarycca->mf_state = cur_mf_state; } -static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) +static void rtl92ee_dm_dynamic_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt; @@ -1083,7 +1083,7 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) rtl92ee_dm_refresh_rate_adaptive_mask(hw); rtl92ee_dm_check_edca_turbo(hw); rtl92ee_dm_dynamic_atc_switch(hw); - rtl92ee_dm_dynamic_primary_cca_ckeck(hw); + rtl92ee_dm_dynamic_primary_cca_check(hw); } spin_unlock(&rtlpriv->locks.rf_ps_lock); } From e416514e309f7e25e577fee45a65f246f67b2261 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 24 Oct 2023 17:31:33 +0300 Subject: [PATCH 0140/7721] wifi: rtw89: fix timeout calculation in rtw89_roc_end() Since 'rtw89_core_tx_kick_off_and_wait()' assumes timeout (actually RTW89_ROC_TX_TIMEOUT) in milliseconds, I suppose that RTW89_ROC_IDLE_TIMEOUT is in milliseconds as well. If so, 'msecs_to_jiffies()' should be used in a call to 'ieee80211_queue_delayed_work()' from 'rtw89_roc_end()'. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231024143137.30393-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw89/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3d75165e48be..a3624ebf01b7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2886,7 +2886,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (hw->conf.flags & IEEE80211_CONF_IDLE) ieee80211_queue_delayed_work(hw, &roc->roc_work, - RTW89_ROC_IDLE_TIMEOUT); + msecs_to_jiffies(RTW89_ROC_IDLE_TIMEOUT)); } void rtw89_roc_work(struct work_struct *work) From 73b479fe5f4ad5391f69502930c1f782b4c6182f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 26 Oct 2023 20:00:46 +0800 Subject: [PATCH 0141/7721] wifi: rtw89: 8922ae: add 8922AE PCI entry and basic info 8922AE is a PCIE 802.11be wireless adapter with PID 0x8922. We add basic configurations including PCI DMA mode, PCI parameters, register address to control TX/RX rings and etc. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026120049.9187-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 91 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 22 +++++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 76 ++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922ae.c diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 2f3d1ad3b0f7..907478db83ef 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -496,6 +496,31 @@ #define B_AX_CH11_BUSY BIT(1) #define B_AX_CH10_BUSY BIT(0) +#define R_BE_HAXI_DMA_STOP1 0xB010 +#define B_BE_STOP_WPDMA BIT(31) +#define B_BE_STOP_CH14 BIT(14) +#define B_BE_STOP_CH13 BIT(13) +#define B_BE_STOP_CH12 BIT(12) +#define B_BE_STOP_CH11 BIT(11) +#define B_BE_STOP_CH10 BIT(10) +#define B_BE_STOP_CH9 BIT(9) +#define B_BE_STOP_CH8 BIT(8) +#define B_BE_STOP_CH7 BIT(7) +#define B_BE_STOP_CH6 BIT(6) +#define B_BE_STOP_CH5 BIT(5) +#define B_BE_STOP_CH4 BIT(4) +#define B_BE_STOP_CH3 BIT(3) +#define B_BE_STOP_CH2 BIT(2) +#define B_BE_STOP_CH1 BIT(1) +#define B_BE_STOP_CH0 BIT(0) +#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ + B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ + B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ + B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ + B_BE_STOP_CH12) + /* Configure */ #define R_AX_PCIE_INIT_CFG2 0x1004 #define B_AX_WD_ITVL_IDLE GENMASK(27, 24) @@ -554,6 +579,72 @@ #define R_AX_PCIE_HRPWM_V1 0x30C0 #define R_AX_PCIE_CRPWM 0x30C4 +#define R_BE_PCIE_HRPWM 0x30C0 +#define R_BE_PCIE_CRPWM 0x30C4 + +#define R_BE_TXBD_RWPTR_CLR1 0xB014 +#define B_BE_CLR_CH14_IDX BIT(14) +#define B_BE_CLR_CH13_IDX BIT(13) +#define B_BE_CLR_CH12_IDX BIT(12) +#define B_BE_CLR_CH11_IDX BIT(11) +#define B_BE_CLR_CH10_IDX BIT(10) +#define B_BE_CLR_CH9_IDX BIT(9) +#define B_BE_CLR_CH8_IDX BIT(8) +#define B_BE_CLR_CH7_IDX BIT(7) +#define B_BE_CLR_CH6_IDX BIT(6) +#define B_BE_CLR_CH5_IDX BIT(5) +#define B_BE_CLR_CH4_IDX BIT(4) +#define B_BE_CLR_CH3_IDX BIT(3) +#define B_BE_CLR_CH2_IDX BIT(2) +#define B_BE_CLR_CH1_IDX BIT(1) +#define B_BE_CLR_CH0_IDX BIT(0) + +#define R_BE_RXBD_RWPTR_CLR1_V1 0xB018 +#define B_BE_CLR_ROQ1_IDX_V1 BIT(5) +#define B_BE_CLR_RPQ1_IDX_V1 BIT(4) +#define B_BE_CLR_RXQ1_IDX_V1 BIT(3) +#define B_BE_CLR_ROQ0_IDX BIT(2) +#define B_BE_CLR_RPQ0_IDX BIT(1) +#define B_BE_CLR_RXQ0_IDX BIT(0) + +#define R_BE_HAXI_DMA_BUSY1 0xB01C +#define B_BE_HAXI_MST_BUSY BIT(31) +#define B_BE_HAXI_RX_IDLE BIT(25) +#define B_BE_HAXI_TX_IDLE BIT(24) +#define B_BE_ROQ1_BUSY_V1 BIT(21) +#define B_BE_RPQ1_BUSY_V1 BIT(20) +#define B_BE_RXQ1_BUSY_V1 BIT(19) +#define B_BE_ROQ0_BUSY_V1 BIT(18) +#define B_BE_RPQ0_BUSY_V1 BIT(17) +#define B_BE_RXQ0_BUSY_V1 BIT(16) +#define B_BE_WPDMA_BUSY BIT(15) +#define B_BE_CH14_BUSY BIT(14) +#define B_BE_CH13_BUSY BIT(13) +#define B_BE_CH12_BUSY BIT(12) +#define B_BE_CH11_BUSY BIT(11) +#define B_BE_CH10_BUSY BIT(10) +#define B_BE_CH9_BUSY BIT(9) +#define B_BE_CH8_BUSY BIT(8) +#define B_BE_CH7_BUSY BIT(7) +#define B_BE_CH6_BUSY BIT(6) +#define B_BE_CH5_BUSY BIT(5) +#define B_BE_CH4_BUSY BIT(4) +#define B_BE_CH3_BUSY BIT(3) +#define B_BE_CH2_BUSY BIT(2) +#define B_BE_CH1_BUSY BIT(1) +#define B_BE_CH0_BUSY BIT(0) +#define DMA_BUSY1_CHECK_BE (B_BE_CH0_BUSY | B_BE_CH1_BUSY | B_BE_CH2_BUSY | \ + B_BE_CH3_BUSY | B_BE_CH4_BUSY | B_BE_CH5_BUSY | \ + B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \ + B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \ + B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY) + +#define R_BE_HAXI_EXP_CTRL_V1 0xB020 +#define B_BE_R_NO_SEC_ACCESS BIT(31) +#define B_BE_FORCE_EN_DMA_RX_GCLK BIT(5) +#define B_BE_FORCE_EN_DMA_TX_GCLK BIT(4) +#define B_BE_MAX_TAG_NUM_MASK GENMASK(3, 0) + #define RTW89_PCI_TXBD_NUM_MAX 256 #define RTW89_PCI_RXBD_NUM_MAX 256 #define RTW89_PCI_TXWD_NUM_MAX 512 diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ccd5481e8a3d..b509e9582ccf 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3740,6 +3740,28 @@ #define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114 #define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0) +#define R_BE_HAXI_INIT_CFG1 0xB000 +#define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) +#define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) +#define B_BE_EN_RO_IDX_UPD_BY_IO BIT(19) +#define B_BE_RST_KEEP_REG BIT(18) +#define B_BE_FLUSH_HAXI_MST BIT(17) +#define B_BE_SET_BDRAM_BOUND BIT(16) +#define B_BE_ADDRINFO_ALIGN4B_EN BIT(15) +#define B_BE_RXBD_DONE_MODE_MASK GENMASK(14, 13) +#define B_BE_RXQ_RXBD_MODE_MASK GENMASK(12, 11) +#define B_BE_DMA_MODE_MASK GENMASK(10, 8) +#define S_BE_DMA_MOD_PCIE_NO_DATA_CPU 0x0 +#define S_BE_DMA_MOD_PCIE_DATA_CPU 0x1 +#define S_BE_DMA_MOD_USB 0x4 +#define S_BE_DMA_MOD_SDIO 0x6 +#define B_BE_STOP_AXI_MST BIT(7) +#define B_BE_RXDMA_ALIGN64B_EN BIT(6) +#define B_BE_RXDMA_EN BIT(5) +#define B_BE_TXDMA_EN BIT(4) +#define B_BE_MAX_RXDMA_MASK GENMASK(3, 2) +#define B_BE_MAX_TXDMA_MASK GENMASK(1, 0) + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c new file mode 100644 index 000000000000..948015a36a80 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include +#include + +#include "pci.h" +#include "reg.h" + +static const struct rtw89_pci_info rtw8922a_pci_info = { + .txbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_mode = MAC_AX_RXBD_PKT, + .tag_mode = MAC_AX_TAG_MULTI, + .tx_burst = MAC_AX_TX_BURST_V1_256B, + .rx_burst = MAC_AX_RX_BURST_V1_128B, + .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .multi_tag_num = MAC_AX_TAG_NUM_8, + .lbc_en = MAC_AX_PCIE_ENABLE, + .lbc_tmr = MAC_AX_LBC_TMR_2MS, + .autok_en = MAC_AX_PCIE_DISABLE, + .io_rcy_en = MAC_AX_PCIE_ENABLE, + .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF, + + .init_cfg_reg = R_BE_HAXI_INIT_CFG1, + .txhci_en_bit = B_BE_TXDMA_EN, + .rxhci_en_bit = B_BE_RXDMA_EN, + .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK, + .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1, + .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK, + .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1, + .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1, + .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK}, + .dma_stop2 = {0}, + .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE}, + .dma_busy2_reg = 0, + .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1, + + .rpwm_addr = R_BE_PCIE_HRPWM, + .cpwm_addr = R_BE_PCIE_CRPWM, + .tx_dma_ch_mask = 0, + .bd_idx_addr_low_power = NULL, + .bd_ram_table = NULL, + + .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, +}; + +static const struct rtw89_driver_info rtw89_8922ae_info = { + .bus = { + .pci = &rtw8922a_pci_info, + }, +}; + +static const struct pci_device_id rtw89_8922ae_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8922), + .driver_data = (kernel_ulong_t)&rtw89_8922ae_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, rtw89_8922ae_id_table); + +static struct pci_driver rtw89_8922ae_driver = { + .name = "rtw89_8922ae", + .id_table = rtw89_8922ae_id_table, + .probe = rtw89_pci_probe, + .remove = rtw89_pci_remove, + .driver.pm = &rtw89_pm_ops, +}; +module_pci_driver(rtw89_8922ae_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922AE driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 0b79c540b13506b727fcd2b689fec99dc4fc51c6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 26 Oct 2023 20:00:47 +0800 Subject: [PATCH 0142/7721] wifi: rtw89: pci: define PCI ring address for WiFi 7 chips PCI rings are used to DMA TX/RX packets. The address of WiFi 7 chips are different from previous ones, so add them according to hardware design. Another difference is that driver doesn't need to configure BD (buffer descriptor) RAM table, which is used by hardware to fetch BD ahead before fetching whole TX data. A TX ring contains numbers of TX BD (e.g. 512): TX BD (buffer descriptor; continual memory) +---+---+---+---+ +---+ | | | | | ... | | +-|-+---+---+---+ +---+ | | point to TX WD (WiFi descriptor; metadata of a skb data) v +------+ | | | | +-|----+ | | point to a skb data v +------+ | | | | +------+ Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026120049.9187-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 66 ++++++++++++---- drivers/net/wireless/realtek/rtw89/pci.h | 75 +++++++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 3 files changed, 126 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 14ddb0d39e63..910f30a209be 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -817,6 +817,15 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) return irqret; } +#define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \ + [RTW89_TXCH_##ch_idx] = { \ + .num = R_##gen##_##txch##_TXBD_NUM ##v, \ + .idx = R_##gen##_##txch##_TXBD_IDX ##v, \ + .bdram = 0, \ + .desa_l = R_##gen##_##txch##_TXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##txch##_TXBD_DESA_H ##v, \ + } + #define DEF_TXCHADDRS_TYPE1(info, txch, v...) \ [RTW89_TXCH_##txch] = { \ .num = R_AX_##txch##_TXBD_NUM ##v, \ @@ -835,12 +844,12 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ } -#define DEF_RXCHADDRS(info, rxch, v...) \ - [RTW89_RXCH_##rxch] = { \ - .num = R_AX_##rxch##_RXBD_NUM ##v, \ - .idx = R_AX_##rxch##_RXBD_IDX ##v, \ - .desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \ - .desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \ +#define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \ + [RTW89_RXCH_##ch_idx] = { \ + .num = R_##gen##_##rxch##_RXBD_NUM ##v, \ + .idx = R_##gen##_##rxch##_RXBD_IDX ##v, \ + .desa_l = R_##gen##_##rxch##_RXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##rxch##_RXBD_DESA_H ##v, \ } const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { @@ -860,8 +869,8 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { DEF_TXCHADDRS(info, CH12), }, .rx = { - DEF_RXCHADDRS(info, RXQ), - DEF_RXCHADDRS(info, RPQ), + DEF_RXCHADDRS(AX, RXQ, RXQ), + DEF_RXCHADDRS(AX, RPQ, RPQ), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set); @@ -883,12 +892,35 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = { DEF_TXCHADDRS(info, CH12, _V1), }, .rx = { - DEF_RXCHADDRS(info, RXQ, _V1), - DEF_RXCHADDRS(info, RPQ, _V1), + DEF_RXCHADDRS(AX, RXQ, RXQ, _V1), + DEF_RXCHADDRS(AX, RPQ, RPQ, _V1), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1); +const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = { + .tx = { + DEF_TXCHADDRS_TYPE2(BE, ACH0, CH0, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH1, CH1, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH2, CH2, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH3, CH3, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH4, CH4, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH5, CH5, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH6, CH6, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH7, CH7, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH8, CH8, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH9, CH9, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH10, CH10, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH11, CH11, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH12, CH12, _V1), + }, + .rx = { + DEF_RXCHADDRS(BE, RXQ, RXQ0, _V1), + DEF_RXCHADDRS(BE, RPQ, RPQ0, _V1), + }, +}; +EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be); + #undef DEF_TXCHADDRS_TYPE1 #undef DEF_TXCHADDRS #undef DEF_RXCHADDRS @@ -1433,19 +1465,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) tx_ring = &rtwpci->tx_rings[i]; bd_ring = &tx_ring->bd_ring; - bd_ram = &bd_ram_table[i]; + bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL; addr_num = bd_ring->addr.num; addr_bdram = bd_ring->addr.bdram; addr_desa_l = bd_ring->addr.desa_l; bd_ring->wp = 0; bd_ring->rp = 0; - val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | - FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | - FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); - rtw89_write16(rtwdev, addr_num, bd_ring->len); - rtw89_write32(rtwdev, addr_bdram, val32); + if (addr_bdram && bd_ram) { + val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | + FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | + FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); + + rtw89_write32(rtwdev, addr_bdram, val32); + } rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); } diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 907478db83ef..56e1980c9882 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -521,6 +521,80 @@ B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ B_BE_STOP_CH12) +#define R_BE_CH0_TXBD_NUM_V1 0xB030 +#define R_BE_CH1_TXBD_NUM_V1 0xB032 +#define R_BE_CH2_TXBD_NUM_V1 0xB034 +#define R_BE_CH3_TXBD_NUM_V1 0xB036 +#define R_BE_CH4_TXBD_NUM_V1 0xB038 +#define R_BE_CH5_TXBD_NUM_V1 0xB03A +#define R_BE_CH6_TXBD_NUM_V1 0xB03C +#define R_BE_CH7_TXBD_NUM_V1 0xB03E +#define R_BE_CH8_TXBD_NUM_V1 0xB040 +#define R_BE_CH9_TXBD_NUM_V1 0xB042 +#define R_BE_CH10_TXBD_NUM_V1 0xB044 +#define R_BE_CH11_TXBD_NUM_V1 0xB046 +#define R_BE_CH12_TXBD_NUM_V1 0xB048 +#define R_BE_CH13_TXBD_NUM_V1 0xB04C +#define R_BE_CH14_TXBD_NUM_V1 0xB04E + +#define R_BE_RXQ0_RXBD_NUM_V1 0xB050 +#define R_BE_RPQ0_RXBD_NUM_V1 0xB052 + +#define R_BE_CH0_TXBD_IDX_V1 0xB100 +#define R_BE_CH1_TXBD_IDX_V1 0xB104 +#define R_BE_CH2_TXBD_IDX_V1 0xB108 +#define R_BE_CH3_TXBD_IDX_V1 0xB10C +#define R_BE_CH4_TXBD_IDX_V1 0xB110 +#define R_BE_CH5_TXBD_IDX_V1 0xB114 +#define R_BE_CH6_TXBD_IDX_V1 0xB118 +#define R_BE_CH7_TXBD_IDX_V1 0xB11C +#define R_BE_CH8_TXBD_IDX_V1 0xB120 +#define R_BE_CH9_TXBD_IDX_V1 0xB124 +#define R_BE_CH10_TXBD_IDX_V1 0xB128 +#define R_BE_CH11_TXBD_IDX_V1 0xB12C +#define R_BE_CH12_TXBD_IDX_V1 0xB130 +#define R_BE_CH13_TXBD_IDX_V1 0xB134 +#define R_BE_CH14_TXBD_IDX_V1 0xB138 + +#define R_BE_RXQ0_RXBD_IDX_V1 0xB160 +#define R_BE_RPQ0_RXBD_IDX_V1 0xB164 + +#define R_BE_CH0_TXBD_DESA_L_V1 0xB200 +#define R_BE_CH0_TXBD_DESA_H_V1 0xB204 +#define R_BE_CH1_TXBD_DESA_L_V1 0xB208 +#define R_BE_CH1_TXBD_DESA_H_V1 0xB20C +#define R_BE_CH2_TXBD_DESA_L_V1 0xB210 +#define R_BE_CH2_TXBD_DESA_H_V1 0xB214 +#define R_BE_CH3_TXBD_DESA_L_V1 0xB218 +#define R_BE_CH3_TXBD_DESA_H_V1 0xB21C +#define R_BE_CH4_TXBD_DESA_L_V1 0xB220 +#define R_BE_CH4_TXBD_DESA_H_V1 0xB224 +#define R_BE_CH5_TXBD_DESA_L_V1 0xB228 +#define R_BE_CH5_TXBD_DESA_H_V1 0xB22C +#define R_BE_CH6_TXBD_DESA_L_V1 0xB230 +#define R_BE_CH6_TXBD_DESA_H_V1 0xB234 +#define R_BE_CH7_TXBD_DESA_L_V1 0xB238 +#define R_BE_CH7_TXBD_DESA_H_V1 0xB23C +#define R_BE_CH8_TXBD_DESA_L_V1 0xB240 +#define R_BE_CH8_TXBD_DESA_H_V1 0xB244 +#define R_BE_CH9_TXBD_DESA_L_V1 0xB248 +#define R_BE_CH9_TXBD_DESA_H_V1 0xB24C +#define R_BE_CH10_TXBD_DESA_L_V1 0xB250 +#define R_BE_CH10_TXBD_DESA_H_V1 0xB254 +#define R_BE_CH11_TXBD_DESA_L_V1 0xB258 +#define R_BE_CH11_TXBD_DESA_H_V1 0xB25C +#define R_BE_CH12_TXBD_DESA_L_V1 0xB260 +#define R_BE_CH12_TXBD_DESA_H_V1 0xB264 +#define R_BE_CH13_TXBD_DESA_L_V1 0xB268 +#define R_BE_CH13_TXBD_DESA_H_V1 0xB26C +#define R_BE_CH14_TXBD_DESA_L_V1 0xB270 +#define R_BE_CH14_TXBD_DESA_H_V1 0xB274 + +#define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300 +#define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304 +#define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308 +#define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C + /* Configure */ #define R_AX_PCIE_INIT_CFG2 0x1004 #define B_AX_WD_ITVL_IDLE GENMASK(27, 24) @@ -1150,6 +1224,7 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; +extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 948015a36a80..ffb31784d8ca 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -42,6 +42,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .cpwm_addr = R_BE_PCIE_CRPWM, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, + .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, .bd_ram_table = NULL, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, From 0dc9324206d3856a657cb076d78c8cc015fb57c8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 26 Oct 2023 20:00:48 +0800 Subject: [PATCH 0143/7721] wifi: rtw89: pci: add new RX ring design to determine full RX ring efficiently To make hardware efficient to determine if RX ring is full, introduce new design that checks if reading and writing indices are equal. Comparing to old design, initial indices of both reading and writing indices are 0 that means empty, and hardware checks full by "writing index + 1 == reading index". The "+1" has extra cost for hardware, so new design is to avoid this. Take ring size is 256 as an example, the initial reading and writing indices are 255 and 0 respectively; the initial values mean empty. If two indices are the same, for example 5 and 5, it means ring is full. wp rp used_cnt state 255 0 0 initial (ring is empty) 255 1 1 receive 1st packet 255 2 2 receive 2nd packet 0 2 1 driver read 1st packet 1 2 0 driver read 2nd packet (ring is empty) : 5 5 255 ring is full Note: 'rp' is hardware writing index Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026120049.9187-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 48 ++++++++++++++++--- drivers/net/wireless/realtek/rtw89/pci.h | 1 + .../net/wireless/realtek/rtw89/rtw8852ae.c | 1 + .../net/wireless/realtek/rtw89/rtw8852be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ce.c | 1 + .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 6 files changed, 47 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 910f30a209be..13775c36a46b 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -41,6 +41,7 @@ static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, struct rtw89_pci_dma_ring *bd_ring, u32 cur_idx, bool tx) { + const struct rtw89_pci_info *info = rtwdev->pci_info; u32 cnt, cur_rp, wp, rp, len; rp = bd_ring->rp; @@ -48,10 +49,14 @@ static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, len = bd_ring->len; cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); - if (tx) + if (tx) { cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp); - else + } else { + if (info->rx_ring_eq_is_full) + wp += 1; + cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp); + } bd_ring->rp = cur_rp; @@ -226,6 +231,21 @@ rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, return true; } +static u32 rtw89_pci_get_rx_skb_idx(struct rtw89_dev *rtwdev, + struct rtw89_pci_dma_ring *bd_ring) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 wp = bd_ring->wp; + + if (!info->rx_ring_eq_is_full) + return wp; + + if (++wp >= bd_ring->len) + wp = 0; + + return wp; +} + static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring) { @@ -235,12 +255,14 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct sk_buff *new = rx_ring->diliver_skb; struct sk_buff *skb; u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; u32 cnt = 1; bool fs, ls; int ret; - skb = rx_ring->buf[bd_ring->wp]; + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; rtw89_pci_sync_skb_for_cpu(rtwdev, skb); ret = rtw89_pci_rxbd_info_update(rtwdev, skb); @@ -525,10 +547,12 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, u32 cnt = 0; u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt); u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; int ret; - skb = rx_ring->buf[bd_ring->wp]; + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; rtw89_pci_sync_skb_for_cpu(rtwdev, skb); ret = rtw89_pci_rxbd_info_update(rtwdev, skb); @@ -1454,6 +1478,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) struct rtw89_pci_dma_ring *bd_ring; const struct rtw89_pci_bd_ram *bd_ram; u32 addr_num; + u32 addr_idx; u32 addr_bdram; u32 addr_desa_l; u32 val32; @@ -1487,14 +1512,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rx_ring = &rtwpci->rx_rings[i]; bd_ring = &rx_ring->bd_ring; addr_num = bd_ring->addr.num; + addr_idx = bd_ring->addr.idx; addr_desa_l = bd_ring->addr.desa_l; - bd_ring->wp = 0; + if (info->rx_ring_eq_is_full) + bd_ring->wp = bd_ring->len - 1; + else + bd_ring->wp = 0; bd_ring->rp = 0; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; rtw89_write16(rtwdev, addr_num, bd_ring->len); rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + + if (info->rx_ring_eq_is_full) + rtw89_write16(rtwdev, addr_idx, bd_ring->wp); } } @@ -3060,6 +3092,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring, u32 desc_size, u32 len, u32 rxch) { + const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_pci_ch_dma_addr *rxch_addr; struct sk_buff *skb; u8 *head; @@ -3086,7 +3119,10 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, rx_ring->bd_ring.len = len; rx_ring->bd_ring.desc_size = desc_size; rx_ring->bd_ring.addr = *rxch_addr; - rx_ring->bd_ring.wp = 0; + if (info->rx_ring_eq_is_full) + rx_ring->bd_ring.wp = len - 1; + else + rx_ring->bd_ring.wp = 0; rx_ring->bd_ring.rp = 0; rx_ring->buf_sz = buf_sz; rx_ring->diliver_skb = NULL; diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 56e1980c9882..e16507a5ec5a 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -937,6 +937,7 @@ struct rtw89_pci_info { enum mac_ax_pcie_func_ctrl autok_en; enum mac_ax_pcie_func_ctrl io_rcy_en; enum mac_ax_io_rcy_tmr io_rcy_tmr; + bool rx_ring_eq_is_full; u32 init_cfg_reg; u32 txhci_en_bit; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index d835a44a1d0d..5895a7019375 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -24,6 +24,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index ecf39d2d9f81..626a00dcddb6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -24,6 +24,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 80490a5437df..5d34e56d9106 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -33,6 +33,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_HAXI_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN_V1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index ffb31784d8ca..c0c720daece1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -23,6 +23,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF, + .rx_ring_eq_is_full = true, .init_cfg_reg = R_BE_HAXI_INIT_CFG1, .txhci_en_bit = B_BE_TXDMA_EN, From 58534b3be0ca4e73a652a4e63f9f5ee80a6cf891 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 26 Oct 2023 20:00:49 +0800 Subject: [PATCH 0144/7721] wifi: rtw89: pci: generalize code of PCI control DMA IO for WiFi 7 The register to enable/disable PCI DMA IO has many variants, so define and use a field to control it accordingly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026120049.9187-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 16 ++++------------ drivers/net/wireless/realtek/rtw89/pci.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ae.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ce.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 13775c36a46b..b2de5280d934 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1750,21 +1750,13 @@ static void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - u32 reg, mask; - - if (chip_id == RTL8852C) { - reg = R_AX_HAXI_INIT_CFG1; - mask = B_AX_STOP_AXI_MST; - } else { - reg = R_AX_PCIE_DMA_STOP1; - mask = B_AX_STOP_PCIEIO; - } + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_reg_def *reg = &info->dma_io_stop; if (enable) - rtw89_write32_clr(rtwdev, reg, mask); + rtw89_write32_clr(rtwdev, reg->addr, reg->mask); else - rtw89_write32_set(rtwdev, reg, mask); + rtw89_write32_set(rtwdev, reg->addr, reg->mask); } static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index e16507a5ec5a..fe1019ae5e5b 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -947,6 +947,7 @@ struct rtw89_pci_info { u32 max_tag_num_mask; u32 rxbd_rwptr_clr_reg; u32 txbd_rwptr_clr2_reg; + struct rtw89_reg_def dma_io_stop; struct rtw89_reg_def dma_stop1; struct rtw89_reg_def dma_stop2; struct rtw89_reg_def dma_busy1; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 0f7711c50bd1..3b299778119a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -33,6 +33,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 5895a7019375..a40e87405dc8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -34,6 +34,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_PCIE_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 626a00dcddb6..9500ff9bb4aa 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -34,6 +34,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 5d34e56d9106..5c84589fd50e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -43,6 +43,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM_V1_MASK, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR_V1, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2_V1, + .dma_io_stop = {R_AX_HAXI_INIT_CFG1, B_AX_STOP_AXI_MST}, .dma_stop1 = {R_AX_HAXI_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_HAXI_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index c0c720daece1..e55f25bafc6e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -33,6 +33,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK, .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1, .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1, + .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST}, .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK}, .dma_stop2 = {0}, .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE}, From a0ddf39ac6420e9b52200973ac07b261db8e7595 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 26 Oct 2023 17:10:11 +0300 Subject: [PATCH 0145/7721] wifi: wilc1000: simplify remain on channel support For 'struct wilc_remain_ch', drop set but otherwise unused 'duration' field and adjust 'expired' callback assuming that the only data passed to it is 'struct wilc_vif *', thus making 'wilc_remain_on_channel()' a bit simpler as well. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ajay Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026141016.71407-1-dmantipov@yandex.ru --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 8 +++----- drivers/net/wireless/microchip/wilc1000/hif.c | 13 +++++-------- drivers/net/wireless/microchip/wilc1000/hif.h | 13 +++++-------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index da52f91693b5..bf2a60533506 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1094,9 +1094,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status) kfree(pv_data); } -static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) +static void wilc_wfi_remain_on_channel_expired(struct wilc_vif *vif, u64 cookie) { - struct wilc_vif *vif = data; struct wilc_priv *priv = &vif->priv; struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params; @@ -1128,9 +1127,8 @@ static int remain_on_channel(struct wiphy *wiphy, if (id == 0) id = ++priv->inc_roc_cookie; - ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value, - wilc_wfi_remain_on_channel_expired, - (void *)vif); + ret = wilc_remain_on_channel(vif, id, chan->hw_value, + wilc_wfi_remain_on_channel_expired); if (ret) return ret; diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index a28da5938481..2c42683dd5fb 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -878,7 +878,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif, if (result) return -EBUSY; - hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.vif = hif_remain_ch->vif; hif_drv->remain_on_ch.expired = hif_remain_ch->expired; hif_drv->remain_on_ch.ch = hif_remain_ch->ch; hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; @@ -915,7 +915,7 @@ static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie) } if (hif_drv->remain_on_ch.expired) { - hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, + hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif, cookie); } } else { @@ -1669,18 +1669,15 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) } } -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg) +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)) { struct wilc_remain_ch roc; int result; roc.ch = chan; roc.expired = expired; - roc.arg = user_arg; - roc.duration = duration; + roc.vif = vif; roc.cookie = cookie; result = handle_remain_on_chan(vif, &roc); if (result) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index 8e386db72e45..b0cb35590027 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -118,11 +118,11 @@ struct wilc_conn_info { void *param; }; +struct wilc_vif; struct wilc_remain_ch { u16 ch; - u32 duration; - void (*expired)(void *priv, u64 cookie); - void *arg; + void (*expired)(struct wilc_vif *vif, u64 cookie); + struct wilc_vif *vif; u64 cookie; }; @@ -150,7 +150,6 @@ struct host_if_drv { u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; -struct wilc_vif; int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, u8 mode, u8 cipher_mode, u8 index); @@ -192,10 +191,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list); -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg); +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)); int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, From ebab2723d0bd47ea899d339d54e1c4ac459d18c3 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 26 Oct 2023 17:10:12 +0300 Subject: [PATCH 0146/7721] wifi: wilc1000: always release SDIO host in wilc_sdio_cmd53() Ensure 'sdio_release_host()' is always issued on return from 'wilc_sdio_cmd53()'. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ajay Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026141016.71407-2-dmantipov@yandex.ru --- drivers/net/wireless/microchip/wilc1000/sdio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index 87948ba69a22..0d13e3e46e98 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -106,9 +106,10 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) size = cmd->count; if (cmd->use_global_buf) { - if (size > sizeof(u32)) - return -EINVAL; - + if (size > sizeof(u32)) { + ret = -EINVAL; + goto out; + } buf = sdio_priv->cmd53_buf; } @@ -123,7 +124,7 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) if (cmd->use_global_buf) memcpy(cmd->buffer, buf, size); } - +out: sdio_release_host(func); if (ret) From 9beac4ee49286101e30a1de2fe58625f998bf77c Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 26 Oct 2023 23:19:18 +0000 Subject: [PATCH 0147/7721] wifi: airo: replace deprecated strncpy with strscpy_pad strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. `extra` is clearly supposed to be NUL-terminated which is evident by the manual NUL-byte assignment as well as its immediate usage with strlen(). Moreover, let's NUL-pad since there is deliberate effort (48 instances) made elsewhere to zero-out buffers in these getters and setters: 6050 | memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); 6130 | memset(local->config.rates, 0, 8); 6139 | memset(local->config.rates, 0, 8); 6414 | memset(key.key, 0, MAX_KEY_SIZE); 6497 | memset(extra, 0, 16); (to be clear, strncpy also NUL-padded -- we are matching that behavior) Considering the above, a suitable replacement is `strscpy_pad` due to the fact that it guarantees both NUL-termination and NUL-padding on the destination buffer. We can also replace the hard-coded size of "16" to IW_ESSID_MAX_SIZE because this function is a wext handler. In wext-core.c we have: static const struct iw_ioctl_description standard_ioctl[] = { ... [IW_IOCTL_IDX(SIOCGIWNICKN)] = { .header_type = IW_HEADER_TYPE_POINT, .token_size = 1, .max_tokens = IW_ESSID_MAX_SIZE, }, So the buffer size is (strangely) IW_ESSID_MAX_SIZE Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231026-strncpy-drivers-net-wireless-cisco-airo-c-v2-1-413427249e47@google.com --- drivers/net/wireless/cisco/airo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index dbd13f7aa3e6..6a099642e854 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -6067,8 +6067,7 @@ static int airo_get_nick(struct net_device *dev, struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); - strncpy(extra, local->config.nodeName, 16); - extra[16] = '\0'; + strscpy_pad(extra, local->config.nodeName, IW_ESSID_MAX_SIZE); dwrq->length = strlen(extra); return 0; From 0f4aa3af137175dc5c5723781ec96e7792d5cda0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Oct 2023 09:50:56 +0800 Subject: [PATCH 0148/7721] wifi: rtw89: set entry size of address CAM to H2C field by chip The new chips change hardware design to shrink entry size of address CAM from 0x40 to 0x20, so make this change accordingly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231027015059.10032-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/cam.c | 16 +++++++++++++++- drivers/net/wireless/realtek/rtw89/mac.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index f5301c2bbf13..914c94988b2f 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -488,6 +488,20 @@ static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev, return 0; } +static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + switch (chip->chip_id) { + case RTL8852A: + case RTL8852B: + case RTL8851B: + return ADDR_CAM_ENT_SIZE; + default: + return ADDR_CAM_ENT_SHORT_SIZE; + } +} + int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam, const struct rtw89_bssid_cam_entry *bssid_cam) @@ -509,7 +523,7 @@ int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, } addr_cam->addr_cam_idx = addr_cam_idx; - addr_cam->len = ADDR_CAM_ENT_SIZE; + addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev); addr_cam->offset = 0; addr_cam->valid = true; addr_cam->addr_mask = 0; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index c11c904f87fe..cd2e9b850c72 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -10,6 +10,7 @@ #define MAC_MEM_DUMP_PAGE_SIZE 0x40000 #define ADDR_CAM_ENT_SIZE 0x40 +#define ADDR_CAM_ENT_SHORT_SIZE 0x20 #define BSSID_CAM_ENT_SIZE 0x08 #define HFC_PAGE_UNIT 64 #define RPWM_TRY_CNT 3 From 76d45f48e4fcf060675970829c7fde21e6e8a2f3 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 27 Oct 2023 09:50:57 +0800 Subject: [PATCH 0149/7721] wifi: rtw89: configure PPDU max user by chip Different chip can support different max user in one PPDU report. So, we now configure it in chip info. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231027015059.10032-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 ++++-- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 6 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index a3624ebf01b7..4327f725cafe 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1407,6 +1407,7 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data; bool rx_cnt_valid = false; u8 plcp_size = 0; @@ -1416,8 +1417,9 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD); plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); - if (usr_num > RTW89_PPDU_MAX_USR) { - rtw89_warn(rtwdev, "Invalid user number in mac info\n"); + if (usr_num > chip->ppdu_max_usr) { + rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n", + usr_num); return -EINVAL; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 91e4d4e79eea..2eb29ea9ff7b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2815,7 +2815,6 @@ struct rtw89_ra_info { u8 csi_bw:3; }; -#define RTW89_PPDU_MAX_USR 4 #define RTW89_PPDU_MAC_INFO_USR_SIZE 4 #define RTW89_PPDU_MAC_INFO_SIZE 8 #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 @@ -3644,6 +3643,7 @@ struct rtw89_chip_info { u8 bacam_num; u8 bacam_dynamic_num; enum rtw89_bacam_ver bacam_ver; + u8 ppdu_max_usr; u8 sec_ctrl_efuse_size; u32 physical_efuse_size; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 50522ff85003..ffc464b2ac10 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2393,6 +2393,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0c36e6180e25..0d6f87b900d5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2129,6 +2129,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 1536, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 9d4e6f08218d..62c2feab569c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2563,6 +2563,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 3b7d8ab39bab..7bb5d359a06a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2877,6 +2877,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bacam_num = 8, .bacam_dynamic_num = 8, .bacam_ver = RTW89_BACAM_V0_EXT, + .ppdu_max_usr = 8, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, From e343face52b013e5d0ff6305ddf40c9838adfe75 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Oct 2023 09:50:58 +0800 Subject: [PATCH 0150/7721] wifi: rtw89: consider RX info for WiFi 7 chips For WiFi 7 chips, some fields and predefined length are changed, so add them accordingly. The mac_id field is used to identify peer that send a packet, and we can use it to know RSSI and traffic from the peer. For WiFi 7 chips, RXWD.mac_id of PPDU status packet is not set by hardware. Instead, we should fill it by rxinfo_user[].mac_id of PPDU status content. Also, filter out invalid reports to prevent warning messages keep showing. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231027015059.10032-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 59 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/txrx.h | 4 ++ 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4327f725cafe..bc30be774037 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1409,29 +1409,63 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data; + const struct rtw89_rxinfo_user *user; + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE; bool rx_cnt_valid = false; + bool invalid = false; u8 plcp_size = 0; - u8 usr_num = 0; u8 *phy_sts; + u8 usr_num; + int i; + + if (chip_gen == RTW89_CHIP_BE) { + invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1); + rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1; + } + + if (invalid) + return -EINVAL; rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD); - plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; - usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); + if (chip_gen == RTW89_CHIP_BE) { + plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1); + } else { + plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); + } if (usr_num > chip->ppdu_max_usr) { rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n", usr_num); return -EINVAL; } + /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware, + * so update mac_id by rxinfo_user[].mac_id. + */ + for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) { + user = &rxinfo->user[i]; + if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID)) + continue; + + phy_ppdu->mac_id = + le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID); + break; + } + phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE; phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE; /* 8-byte alignment */ if (usr_num & BIT(0)) phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE; if (rx_cnt_valid) - phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE; + phy_sts += rx_cnt_size; phy_sts += plcp_size; + if (phy_sts > skb->data + skb->len) + return -EINVAL; + phy_ppdu->buf = phy_sts; phy_ppdu->len = skb->data + skb->len - phy_sts; @@ -1565,6 +1599,11 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, { const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf; u32 len_from_header; + bool physts_valid; + + physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID); + if (!physts_valid) + return -EINVAL; len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3; @@ -2054,13 +2093,19 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev, .mac_id = desc_info->mac_id}; int ret; - if (desc_info->mac_info_valid) - rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (desc_info->mac_info_valid) { + ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (ret) + goto out; + } + ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu); if (ret) - rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n"); + goto out; rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu); + +out: rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb); dev_kfree_skb_any(skb); } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2eb29ea9ff7b..da8181539d1a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2818,6 +2818,7 @@ struct rtw89_ra_info { #define RTW89_PPDU_MAC_INFO_USR_SIZE 4 #define RTW89_PPDU_MAC_INFO_SIZE 8 #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 +#define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128 #define RTW89_MAX_RX_AGG_NUM 64 #define RTW89_MAX_TX_AGG_NUM 128 diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 7142cce167de..c467a80ffa88 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -416,8 +416,11 @@ struct rtw89_rxinfo { } __packed; #define RTW89_RXINFO_W0_USR_NUM GENMASK(3, 0) +#define RTW89_RXINFO_W0_USR_NUM_V1 GENMASK(4, 0) #define RTW89_RXINFO_W0_FW_DEFINE GENMASK(15, 8) +#define RTW89_RXINFO_W0_PLCP_LEN_V1 GENMASK(23, 16) #define RTW89_RXINFO_W0_LSIG_LEN GENMASK(27, 16) +#define RTW89_RXINFO_W0_INVALID_V1 BIT(27) #define RTW89_RXINFO_W0_IS_TO_SELF BIT(28) #define RTW89_RXINFO_W0_RX_CNT_VLD BIT(29) #define RTW89_RXINFO_W0_LONG_RXD GENMASK(31, 30) @@ -430,6 +433,7 @@ struct rtw89_phy_sts_hdr { } __packed; #define RTW89_PHY_STS_HDR_W0_IE_MAP GENMASK(4, 0) +#define RTW89_PHY_STS_HDR_W0_VALID BIT(7) #define RTW89_PHY_STS_HDR_W0_LEN GENMASK(15, 8) #define RTW89_PHY_STS_HDR_W0_RSSI_AVG GENMASK(31, 24) #define RTW89_PHY_STS_HDR_W1_RSSI_A GENMASK(7, 0) From 944496bada22f1788cd3b39b542f7818a0a119d0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Oct 2023 09:50:59 +0800 Subject: [PATCH 0151/7721] wifi: rtw89: extend PHY status parser to support WiFi 7 chips PHY status IEs is used to have more information about received packets, such as RSSI and EVM. For each PHY IE type, it has different predefined PHY IE length, and the length are changed, so add them for WiFi 7 chips accordingly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231027015059.10032-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index bc30be774037..c689fc2b2d49 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1513,14 +1513,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, const struct rtw89_phy_sts_iehdr *iehdr) { - static const u8 physts_ie_len_tab[32] = { - 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, - VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, - VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = { + [RTW89_CHIP_AX] = { + 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, + [RTW89_CHIP_BE] = { + 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, }; + const u8 *physts_ie_len_tab; u16 ie_len; u8 ie; + physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen]; + ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); if (physts_ie_len_tab[ie] != VAR_LEN) ie_len = physts_ie_len_tab[ie]; @@ -1607,6 +1617,9 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + len_from_header += PHY_STS_HDR_LEN; + if (len_from_header != phy_ppdu->len) { rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n"); return -EINVAL; From 4b478bf6bdd8901cb29742ec8a65c0b2b92a9e56 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:43 +0200 Subject: [PATCH 0152/7721] wifi: libertas: drop 16-bit PCMCIA support With all the other PCMCIA WLAN adapters gone from the kernel, this is now the last remaining device with this interface, but as far as I can tell, all the actual libertas users were actually using either SDIO or USB. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/Kconfig | 7 +- .../net/wireless/marvell/libertas/Makefile | 1 - drivers/net/wireless/marvell/libertas/if_cs.c | 957 ------------------ 3 files changed, 1 insertion(+), 964 deletions(-) delete mode 100644 drivers/net/wireless/marvell/libertas/if_cs.c diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 6d62ab49aa8d..5bc92cb6b0fe 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" + depends on USB || SDIO || SPI depends on CFG80211 select WIRELESS_EXT select WEXT_SPY @@ -15,12 +16,6 @@ config LIBERTAS_USB help A driver for Marvell Libertas 8388 USB devices. -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP - help - A driver for Marvell Libertas 8385 CompactFlash devices. - config LIBERTAS_SDIO tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile index 41b9b440a542..2ac04f4d61a5 100644 --- a/drivers/net/wireless/marvell/libertas/Makefile +++ b/drivers/net/wireless/marvell/libertas/Makefile @@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o -obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c deleted file mode 100644 index 4103f15bca6b..000000000000 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ /dev/null @@ -1,957 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - Driver for the Marvell 8385 based compact flash WLAN cards. - - (C) 2007 by Holger Schurig - - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define DRV_NAME "libertas_cs" - -#include "decl.h" -#include "defs.h" -#include "dev.h" - - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Holger Schurig "); -MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); -MODULE_LICENSE("GPL"); - - - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -struct if_cs_card { - struct pcmcia_device *p_dev; - struct lbs_private *priv; - void __iomem *iobase; - bool align_regs; - u32 model; -}; - - -enum { - MODEL_UNKNOWN = 0x00, - MODEL_8305 = 0x01, - MODEL_8381 = 0x02, - MODEL_8385 = 0x03 -}; - -static const struct lbs_fw_table fw_table[] = { - { MODEL_8305, "libertas/cf8305.bin", NULL }, - { MODEL_8305, "libertas_cs_helper.fw", NULL }, - { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" }, - { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" }, - { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { 0, NULL, NULL } -}; -MODULE_FIRMWARE("libertas/cf8305.bin"); -MODULE_FIRMWARE("libertas/cf8381_helper.bin"); -MODULE_FIRMWARE("libertas/cf8381.bin"); -MODULE_FIRMWARE("libertas/cf8385_helper.bin"); -MODULE_FIRMWARE("libertas/cf8385.bin"); -MODULE_FIRMWARE("libertas_cs_helper.fw"); -MODULE_FIRMWARE("libertas_cs.fw"); - - -/********************************************************************/ -/* Hardware access */ -/********************************************************************/ - -/* This define enables wrapper functions which allow you - to dump all register accesses. You normally won't this, - except for development */ -/* #define DEBUG_IO */ - -#ifdef DEBUG_IO -static int debug_output = 0; -#else -/* This way the compiler optimizes the printk's away */ -#define debug_output 0 -#endif - -static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread8(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inb %08x<%02x\n", reg, val); - return val; -} -static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread16(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inw %08x<%04x\n", reg, val); - return val; -} -static inline void if_cs_read16_rep( - struct if_cs_card *card, - uint reg, - void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "insw %08x<(0x%lx words)\n", - reg, count); - ioread16_rep(card->iobase + reg, buf, count); -} - -static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) -{ - if (debug_output) - printk(KERN_INFO "outb %08x>%02x\n", reg, val); - iowrite8(val, card->iobase + reg); -} - -static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) -{ - if (debug_output) - printk(KERN_INFO "outw %08x>%04x\n", reg, val); - iowrite16(val, card->iobase + reg); -} - -static inline void if_cs_write16_rep( - struct if_cs_card *card, - uint reg, - const void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "outsw %08x>(0x%lx words)\n", - reg, count); - iowrite16_rep(card->iobase + reg, buf, count); -} - - -/* - * I know that polling/delaying is frowned upon. However, this procedure - * with polling is needed while downloading the firmware. At this stage, - * the hardware does unfortunately not create any interrupts. - * - * Fortunately, this function is never used once the firmware is in - * the card. :-) - * - * As a reference, see the "Firmware Specification v5.1", page 18 - * and 19. I did not follow their suggested timing to the word, - * but this works nice & fast anyway. - */ -static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) -{ - int i; - - for (i = 0; i < 100000; i++) { - u8 val = if_cs_read8(card, addr); - if (val == reg) - return 0; - udelay(5); - } - return -ETIME; -} - - - -/* - * First the bitmasks for the host/card interrupt/status registers: - */ -#define IF_CS_BIT_TX 0x0001 -#define IF_CS_BIT_RX 0x0002 -#define IF_CS_BIT_COMMAND 0x0004 -#define IF_CS_BIT_RESP 0x0008 -#define IF_CS_BIT_EVENT 0x0010 -#define IF_CS_BIT_MASK 0x001f - - - -/* - * It's not really clear to me what the host status register is for. It - * needs to be set almost in union with "host int cause". The following - * bits from above are used: - * - * IF_CS_BIT_TX driver downloaded a data packet - * IF_CS_BIT_RX driver got a data packet - * IF_CS_BIT_COMMAND driver downloaded a command - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT driver read a host event - */ -#define IF_CS_HOST_STATUS 0x00000000 - -/* - * With the host int cause register can the host (that is, Linux) cause - * an interrupt in the firmware, to tell the firmware about those events: - * - * IF_CS_BIT_TX a data packet has been downloaded - * IF_CS_BIT_RX a received data packet has retrieved - * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved - */ -#define IF_CS_HOST_INT_CAUSE 0x00000002 - -/* - * The host int mask register is used to enable/disable interrupt. However, - * I have the suspicion that disabled interrupts are lost. - */ -#define IF_CS_HOST_INT_MASK 0x00000004 - -/* - * Used to send or receive data packets: - */ -#define IF_CS_WRITE 0x00000016 -#define IF_CS_WRITE_LEN 0x00000014 -#define IF_CS_READ 0x00000010 -#define IF_CS_READ_LEN 0x00000024 - -/* - * Used to send commands (and to send firmware block) and to - * receive command responses: - */ -#define IF_CS_CMD 0x0000001A -#define IF_CS_CMD_LEN 0x00000018 -#define IF_CS_RESP 0x00000012 -#define IF_CS_RESP_LEN 0x00000030 - -/* - * The card status registers shows what the card/firmware actually - * accepts: - * - * IF_CS_BIT_TX you may send a data packet - * IF_CS_BIT_RX you may retrieve a data packet - * IF_CS_BIT_COMMAND you may send a command - * IF_CS_BIT_RESP you may retrieve a command response - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - * - * When reading this register several times, you will get back the same - * results --- with one exception: the IF_CS_BIT_EVENT clear itself - * automatically. - * - * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because - * we handle this via the card int cause register. - */ -#define IF_CS_CARD_STATUS 0x00000020 -#define IF_CS_CARD_STATUS_MASK 0x7f00 - -/* - * The card int cause register is used by the card/firmware to notify us - * about the following events: - * - * IF_CS_BIT_TX a data packet has successfully been sentx - * IF_CS_BIT_RX a data packet has been received and can be retrieved - * IF_CS_BIT_COMMAND not used - * IF_CS_BIT_RESP the firmware has a command response for us - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - */ -#define IF_CS_CARD_INT_CAUSE 0x00000022 - -/* - * This is used to for handshaking with the card's bootloader/helper image - * to synchronize downloading of firmware blocks. - */ -#define IF_CS_SQ_READ_LOW 0x00000028 -#define IF_CS_SQ_HELPER_OK 0x10 - -/* - * The scratch register tells us ... - * - * IF_CS_SCRATCH_BOOT_OK the bootloader runs - * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs - */ -#define IF_CS_SCRATCH 0x0000003F -#define IF_CS_SCRATCH_BOOT_OK 0x00 -#define IF_CS_SCRATCH_HELPER_OK 0x5a - -/* - * Used to detect ancient chips: - */ -#define IF_CS_PRODUCT_ID 0x0000001C -#define IF_CS_CF8385_B1_REV 0x12 -#define IF_CS_CF8381_B3_REV 0x04 -#define IF_CS_CF8305_B1_REV 0x03 - -/* - * Used to detect other cards than CF8385 since their revisions of silicon - * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. - */ -#define CF8305_MANFID 0x02db -#define CF8305_CARDID 0x8103 -#define CF8381_MANFID 0x02db -#define CF8381_CARDID 0x6064 -#define CF8385_MANFID 0x02df -#define CF8385_CARDID 0x8103 - -/* - * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when - * that gets fixed. Currently there's no way to access it from the probe hook. - */ -static inline u32 get_model(u16 manf_id, u16 card_id) -{ - /* NOTE: keep in sync with if_cs_ids */ - if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID) - return MODEL_8305; - else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID) - return MODEL_8381; - else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID) - return MODEL_8385; - return MODEL_UNKNOWN; -} - -/********************************************************************/ -/* I/O and interrupt handling */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); -} - -/* - * Called from if_cs_host_to_card to send a command to the hardware - */ -static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - int ret = -1; - int loops = 0; - - if_cs_disable_ints(card); - - /* Is hardware ready? */ - while (1) { - u16 status = if_cs_read16(card, IF_CS_CARD_STATUS); - if (status & IF_CS_BIT_COMMAND) - break; - if (++loops > 100) { - netdev_err(priv->dev, "card not ready for commands\n"); - goto done; - } - mdelay(1); - } - - if_cs_write16(card, IF_CS_CMD_LEN, nb); - - if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2); - /* Are we supposed to transfer an odd amount of bytes? */ - if (nb & 1) - if_cs_write8(card, IF_CS_CMD, buf[nb-1]); - - /* "Assert the download over interrupt command in the Host - * status register" */ - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = 0; - -done: - if_cs_enable_ints(card); - return ret; -} - -/* - * Called from if_cs_host_to_card to send a data to the hardware - */ -static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - u16 status; - - if_cs_disable_ints(card); - - status = if_cs_read16(card, IF_CS_CARD_STATUS); - BUG_ON((status & IF_CS_BIT_TX) == 0); - - if_cs_write16(card, IF_CS_WRITE_LEN, nb); - - /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2); - if (nb & 1) - if_cs_write8(card, IF_CS_WRITE, buf[nb-1]); - - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); - if_cs_enable_ints(card); -} - -/* - * Get the command result out of the card. - */ -static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) -{ - unsigned long flags; - int ret = -1; - u16 status; - - /* is hardware ready? */ - status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if ((status & IF_CS_BIT_RESP) == 0) { - netdev_err(priv->dev, "no cmd response in card\n"); - *len = 0; - goto out; - } - - *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); - if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - netdev_err(priv->dev, - "card cmd buffer has invalid # of bytes (%d)\n", - *len); - goto out; - } - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16)); - if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP); - - /* This is a workaround for a firmware that reports too much - * bytes */ - *len -= 8; - ret = 0; - - /* Clear this flag again */ - spin_lock_irqsave(&priv->driver_lock, flags); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - return ret; -} - -static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) -{ - struct sk_buff *skb = NULL; - u16 len; - u8 *data; - - len = if_cs_read16(priv->card, IF_CS_READ_LEN); - if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - netdev_err(priv->dev, - "card data buffer has invalid # of bytes (%d)\n", - len); - priv->dev->stats.rx_dropped++; - goto dat_err; - } - - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); - if (!skb) - goto out; - skb_put(skb, len); - skb_reserve(skb, 2);/* 16 byte align */ - data = skb->data; - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); - if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_READ); - -dat_err: - if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); - -out: - return skb; -} - -static irqreturn_t if_cs_interrupt(int irq, void *data) -{ - struct if_cs_card *card = data; - struct lbs_private *priv = card->priv; - u16 cause; - - /* Ask card interrupt cause register if there is something for us */ - cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); - lbs_deb_cs("cause 0x%04x\n", cause); - - if (cause == 0) { - /* Not for us */ - return IRQ_NONE; - } - - if (cause == 0xffff) { - /* Read in junk, the card has probably been removed */ - card->priv->surpriseremoved = 1; - return IRQ_HANDLED; - } - - if (cause & IF_CS_BIT_RX) { - struct sk_buff *skb; - lbs_deb_cs("rx packet\n"); - skb = if_cs_receive_data(priv); - if (skb) - lbs_process_rxed_packet(priv, skb); - } - - if (cause & IF_CS_BIT_TX) { - lbs_deb_cs("tx done\n"); - lbs_host_to_card_done(priv); - } - - if (cause & IF_CS_BIT_RESP) { - unsigned long flags; - u8 i; - - lbs_deb_cs("cmd resp\n"); - spin_lock_irqsave(&priv->driver_lock, flags); - i = (priv->resp_idx == 0) ? 1 : 0; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - BUG_ON(priv->resp_len[i]); - if_cs_receive_cmdres(priv, priv->resp_buf[i], - &priv->resp_len[i]); - - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_notify_command_response(priv, i); - spin_unlock_irqrestore(&priv->driver_lock, flags); - } - - if (cause & IF_CS_BIT_EVENT) { - u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, - IF_CS_BIT_EVENT); - lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8); - } - - /* Clear interrupt cause */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - - return IRQ_HANDLED; -} - - - - -/********************************************************************/ -/* Firmware */ -/********************************************************************/ - -/* - * Tries to program the helper firmware. - * - * Return 0 on success - */ -static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int sent = 0; - u8 scratch; - - /* - * This is the only place where an unaligned register access happens on - * the CF8305 card, therefore for the sake of speed of the driver, we do - * the alignment correction here. - */ - if (card->align_regs) - scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; - else - scratch = if_cs_read8(card, IF_CS_SCRATCH); - - /* "If the value is 0x5a, the firmware is already - * downloaded successfully" - */ - if (scratch == IF_CS_SCRATCH_HELPER_OK) - goto done; - - /* "If the value is != 00, it is invalid value of register */ - if (scratch != IF_CS_SCRATCH_BOOT_OK) { - ret = -ENODEV; - goto done; - } - - lbs_deb_cs("helper size %td\n", fw->size); - - /* "Set the 5 bytes of the helper image to 0" */ - /* Not needed, this contains an ARM branch instruction */ - - for (;;) { - /* "the number of bytes to send is 256" */ - int count = 256; - int remain = fw->size - sent; - - if (remain < count) - count = remain; - - /* - * "write the number of bytes to be sent to the I/O Command - * write length register" - */ - if_cs_write16(card, IF_CS_CMD_LEN, count); - - /* "write this to I/O Command port register as 16 bit writes */ - if (count) - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - count >> 1); - - /* - * "Assert the download over interrupt command in the Host - * status register" - */ - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* - * "Assert the download over interrupt command in the Card - * interrupt case register" - */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - /* - * "The host polls the Card Status register ... for 50 ms before - * declaring a failure" - */ - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); - goto done; - } - - if (count == 0) - break; - - sent += count; - } - -done: - return ret; -} - - -static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int retry = 0; - int len = 0; - int sent; - - lbs_deb_cs("fw size %td\n", fw->size); - - ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, - IF_CS_SQ_HELPER_OK); - if (ret < 0) { - pr_err("helper firmware doesn't answer\n"); - goto done; - } - - for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_SQ_READ_LOW); - if (len & 1) { - retry++; - pr_info("odd, need to retry this firmware block\n"); - } else { - retry = 0; - } - - if (retry > 20) { - pr_err("could not download firmware\n"); - ret = -ENODEV; - goto done; - } - if (retry) { - sent -= len; - } - - - if_cs_write16(card, IF_CS_CMD_LEN, len); - - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - (len+1) >> 1); - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download firmware at 0x%x\n", sent); - goto done; - } - } - - ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) - pr_err("firmware download failed\n"); - -done: - return ret; -} - -static void if_cs_prog_firmware(struct lbs_private *priv, int ret, - const struct firmware *helper, - const struct firmware *mainfw) -{ - struct if_cs_card *card = priv->card; - - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - return; - } - - /* Load the firmware */ - ret = if_cs_prog_helper(card, helper); - if (ret == 0 && (card->model != MODEL_8305)) - ret = if_cs_prog_real(card, mainfw); - if (ret) - return; - - /* Now actually get the IRQ */ - ret = request_irq(card->p_dev->irq, if_cs_interrupt, - IRQF_SHARED, DRV_NAME, card); - if (ret) { - pr_err("error in request_irq\n"); - return; - } - - /* - * Clear any interrupt cause that happened while sending - * firmware/initializing card - */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); - if_cs_enable_ints(card); - - /* And finally bring the card up */ - priv->fw_ready = 1; - if (lbs_start_card(priv) != 0) { - pr_err("could not activate card\n"); - free_irq(card->p_dev->irq, card); - } -} - - -/********************************************************************/ -/* Callback functions for libertas.ko */ -/********************************************************************/ - -/* Send commands or data packets to the card */ -static int if_cs_host_to_card(struct lbs_private *priv, - u8 type, - u8 *buf, - u16 nb) -{ - int ret = -1; - - switch (type) { - case MVMS_DAT: - priv->dnld_sent = DNLD_DATA_SENT; - if_cs_send_data(priv, buf, nb); - ret = 0; - break; - case MVMS_CMD: - priv->dnld_sent = DNLD_CMD_SENT; - ret = if_cs_send_cmd(priv, buf, nb); - break; - default: - netdev_err(priv->dev, "%s: unsupported type %d\n", - __func__, type); - } - - return ret; -} - - -static void if_cs_release(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - free_irq(p_dev->irq, card); - pcmcia_disable_device(p_dev); - if (card->iobase) - ioport_unmap(card->iobase); -} - - -static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[1]->end) { - pr_err("wrong CIS (check number of IO windows)\n"); - return -ENODEV; - } - - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); -} - -static int if_cs_probe(struct pcmcia_device *p_dev) -{ - int ret = -ENOMEM; - unsigned int prod_id; - struct lbs_private *priv; - struct if_cs_card *card; - - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); - if (!card) - goto out; - - card->p_dev = p_dev; - p_dev->priv = card; - - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - pr_err("error in pcmcia_loop_config\n"); - goto out1; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - if (!p_dev->irq) - goto out1; - - /* Initialize io access */ - card->iobase = ioport_map(p_dev->resource[0]->start, - resource_size(p_dev->resource[0])); - if (!card->iobase) { - pr_err("error in ioport_map\n"); - ret = -EIO; - goto out1; - } - - ret = pcmcia_enable_device(p_dev); - if (ret) { - pr_err("error in pcmcia_enable_device\n"); - goto out2; - } - - /* Finally, report what we've done */ - lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]); - - /* - * Most of the libertas cards can do unaligned register access, but some - * weird ones cannot. That's especially true for the CF8305 card. - */ - card->align_regs = false; - - card->model = get_model(p_dev->manf_id, p_dev->card_id); - if (card->model == MODEL_UNKNOWN) { - pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); - ret = -ENODEV; - goto out2; - } - - /* Check if we have a current silicon */ - prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); - if (card->model == MODEL_8305) { - card->align_regs = true; - if (prod_id < IF_CS_CF8305_B1_REV) { - pr_err("8305 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - } - - if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - pr_err("8381 rev B2 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - pr_err("8385 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - /* Make this card known to the libertas driver */ - priv = lbs_add_card(card, &p_dev->dev); - if (IS_ERR(priv)) { - ret = PTR_ERR(priv); - goto out2; - } - - /* Set up fields in lbs_private */ - card->priv = priv; - priv->card = card; - priv->hw_host_to_card = if_cs_host_to_card; - priv->enter_deep_sleep = NULL; - priv->exit_deep_sleep = NULL; - priv->reset_deep_sleep_wakeup = NULL; - - /* Get firmware */ - ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table, - if_cs_prog_firmware); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out3; - } - - goto out; - -out3: - lbs_remove_card(priv); -out2: - ioport_unmap(card->iobase); -out1: - pcmcia_disable_device(p_dev); -out: - return ret; -} - - -static void if_cs_detach(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - lbs_stop_card(card->priv); - lbs_remove_card(card->priv); - if_cs_disable_ints(card); - if_cs_release(p_dev); - kfree(card); -} - - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), - /* NOTE: keep in sync with get_model() */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); - -static struct pcmcia_driver lbs_driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .probe = if_cs_probe, - .remove = if_cs_detach, - .id_table = if_cs_ids, -}; -module_pcmcia_driver(lbs_driver); From 77e49bec64144cf68c494209347ebd762c675194 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:44 +0200 Subject: [PATCH 0153/7721] wifi: atmel: remove wext style at76c50x drivers Atmel at76c502/at76c504/at76c506 is a PIO-only (PCMCIA, mini-PCI and Cardbus) 802.11b driver with incomplete CFG80211 support. Both PCMCIA and WEXT are deprecated, and there is little chance that anyone is still using this driver, so remove it. The related at76c50x USB driver uses MAC80211 and remains. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 8 - drivers/net/wireless/atmel/Kconfig | 35 - drivers/net/wireless/atmel/Makefile | 4 - drivers/net/wireless/atmel/atmel.c | 4452 ------------------------ drivers/net/wireless/atmel/atmel.h | 31 - drivers/net/wireless/atmel/atmel_cs.c | 292 -- drivers/net/wireless/atmel/atmel_pci.c | 65 - 7 files changed, 4887 deletions(-) delete mode 100644 drivers/net/wireless/atmel/atmel.c delete mode 100644 drivers/net/wireless/atmel/atmel.h delete mode 100644 drivers/net/wireless/atmel/atmel_cs.c delete mode 100644 drivers/net/wireless/atmel/atmel_pci.c diff --git a/MAINTAINERS b/MAINTAINERS index 76dea3f2e391..1693d50b4260 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2392,7 +2392,6 @@ F: drivers/memory/atmel* F: drivers/watchdog/sama5d4_wdt.c F: include/soc/at91/ X: drivers/input/touchscreen/atmel_mxt_ts.c -X: drivers/net/wireless/atmel/ N: at91 N: atmel @@ -3284,13 +3283,6 @@ T: git git://github.com/ndyer/linux.git F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml F: drivers/input/touchscreen/atmel_mxt_ts.c -ATMEL WIRELESS DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://www.thekelleys.org.uk/atmel -W: http://atmelwlandriver.sourceforge.net/ -F: drivers/net/wireless/atmel/atmel* - ATOMIC INFRASTRUCTURE M: Will Deacon M: Peter Zijlstra diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index bafdd57b049a..7a2bb7a58ab7 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -12,41 +12,6 @@ config WLAN_VENDOR_ATMEL if WLAN_VENDOR_ATMEL -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - help - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - help - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - help - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - config AT76C50X_USB tristate "Atmel at76c503/at76c505/at76c505a USB cards" depends on MAC80211 && USB diff --git a/drivers/net/wireless/atmel/Makefile b/drivers/net/wireless/atmel/Makefile index 17e62805677d..8338d7098ba6 100644 --- a/drivers/net/wireless/atmel/Makefile +++ b/drivers/net/wireless/atmel/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ATMEL) += atmel.o -obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o -obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o - obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c deleted file mode 100644 index 461dce21de2b..000000000000 --- a/drivers/net/wireless/atmel/atmel.c +++ /dev/null @@ -1,4452 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003-2004 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds and the Linux wireless - extensions, (C) Jean Tourrilhes. - - The firmware module for reading the MAC address of the card comes from - net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright - by him. net.russotto.AtmelMACFW is used under the GPL license version 2. - This file contains the module in binary form and, under the terms - of the GPL, in source form. The source is located at the end of the file. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, see - . - - For all queries about this code, please contact the current author, - Simon Kelley and not Atmel Corporation. - - Credit is due to HP UK and Cambridge Online Systems Ltd for supplying - hardware used during development of this driver. - -******************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "atmel.h" - -#define DRIVER_MAJOR 0 -#define DRIVER_MINOR 98 - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/* The name of the firmware file to be loaded - over-rides any automatic selection */ -static char *firmware = NULL; -module_param(firmware, charp, 0); - -/* table of firmware file names */ -static struct { - AtmelFWType fw_type; - const char *fw_file; - const char *fw_file_ext; -} fw_table[] = { - { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, - { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, - { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, - { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, - { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, - { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, - { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, - { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, - { ATMEL_FW_TYPE_NONE, NULL, NULL } -}; -MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502.bin"); -MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502d.bin"); -MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502e.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com.bin"); -MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); -MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c506.bin"); - -#define MAX_SSID_LENGTH 32 -#define MGMT_JIFFIES (256 * HZ / 100) - -#define MAX_BSS_ENTRIES 64 - -/* registers */ -#define GCR 0x00 /* (SIR0) General Configuration Register */ -#define BSR 0x02 /* (SIR1) Bank Switching Select Register */ -#define AR 0x04 -#define DR 0x08 -#define MR1 0x12 /* Mirror Register 1 */ -#define MR2 0x14 /* Mirror Register 2 */ -#define MR3 0x16 /* Mirror Register 3 */ -#define MR4 0x18 /* Mirror Register 4 */ - -#define GPR1 0x0c -#define GPR2 0x0e -#define GPR3 0x10 -/* - * Constants for the GCR register. - */ -#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ -#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ -#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ -#define GCR_ENINT 0x0002 /* Enable Interrupts */ -#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ - -#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ -#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ -/* - *Constants for the MR registers. - */ -#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ -#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ -#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ - -#define MIB_MAX_DATA_BYTES 212 -#define MIB_HEADER_SIZE 4 /* first four fields */ - -struct get_set_mib { - u8 type; - u8 size; - u8 index; - u8 reserved; - u8 data[MIB_MAX_DATA_BYTES]; -}; - -struct rx_desc { - u32 Next; - u16 MsduPos; - u16 MsduSize; - - u8 State; - u8 Status; - u8 Rate; - u8 Rssi; - u8 LinkQuality; - u8 PreambleType; - u16 Duration; - u32 RxTime; -}; - -#define RX_DESC_FLAG_VALID 0x80 -#define RX_DESC_FLAG_CONSUMED 0x40 -#define RX_DESC_FLAG_IDLE 0x00 - -#define RX_STATUS_SUCCESS 0x00 - -#define RX_DESC_MSDU_POS_OFFSET 4 -#define RX_DESC_MSDU_SIZE_OFFSET 6 -#define RX_DESC_FLAGS_OFFSET 8 -#define RX_DESC_STATUS_OFFSET 9 -#define RX_DESC_RSSI_OFFSET 11 -#define RX_DESC_LINK_QUALITY_OFFSET 12 -#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 -#define RX_DESC_DURATION_OFFSET 14 -#define RX_DESC_RX_TIME_OFFSET 16 - -struct tx_desc { - u32 NextDescriptor; - u16 TxStartOfFrame; - u16 TxLength; - - u8 TxState; - u8 TxStatus; - u8 RetryCount; - - u8 TxRate; - - u8 KeyIndex; - u8 ChiperType; - u8 ChipreLength; - u8 Reserved1; - - u8 Reserved; - u8 PacketType; - u16 HostTxLength; -}; - -#define TX_DESC_NEXT_OFFSET 0 -#define TX_DESC_POS_OFFSET 4 -#define TX_DESC_SIZE_OFFSET 6 -#define TX_DESC_FLAGS_OFFSET 8 -#define TX_DESC_STATUS_OFFSET 9 -#define TX_DESC_RETRY_OFFSET 10 -#define TX_DESC_RATE_OFFSET 11 -#define TX_DESC_KEY_INDEX_OFFSET 12 -#define TX_DESC_CIPHER_TYPE_OFFSET 13 -#define TX_DESC_CIPHER_LENGTH_OFFSET 14 -#define TX_DESC_PACKET_TYPE_OFFSET 17 -#define TX_DESC_HOST_LENGTH_OFFSET 18 - -/* - * Host-MAC interface - */ - -#define TX_STATUS_SUCCESS 0x00 - -#define TX_FIRM_OWN 0x80 -#define TX_DONE 0x40 - -#define TX_ERROR 0x01 - -#define TX_PACKET_TYPE_DATA 0x01 -#define TX_PACKET_TYPE_MGMT 0x02 - -#define ISR_EMPTY 0x00 /* no bits set in ISR */ -#define ISR_TxCOMPLETE 0x01 /* packet transmitted */ -#define ISR_RxCOMPLETE 0x02 /* packet received */ -#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ -#define ISR_FATAL_ERROR 0x08 /* Fatal error */ -#define ISR_COMMAND_COMPLETE 0x10 /* command completed */ -#define ISR_OUT_OF_RANGE 0x20 /* command completed */ -#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ -#define ISR_GENERIC_IRQ 0x80 - -#define Local_Mib_Type 0x01 -#define Mac_Address_Mib_Type 0x02 -#define Mac_Mib_Type 0x03 -#define Statistics_Mib_Type 0x04 -#define Mac_Mgmt_Mib_Type 0x05 -#define Mac_Wep_Mib_Type 0x06 -#define Phy_Mib_Type 0x07 -#define Multi_Domain_MIB 0x08 - -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MIB_FRAG_THRESHOLD_POS 8 -#define MAC_MIB_RTS_THRESHOLD_POS 10 -#define MAC_MIB_SHORT_RETRY_POS 16 -#define MAC_MIB_LONG_RETRY_POS 17 -#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 -#define MAC_MGMT_MIB_BEACON_PER_POS 0 -#define MAC_MGMT_MIB_STATION_ID_POS 6 -#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MGMT_MIB_PS_MODE_POS 53 -#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 -#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 -#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 -#define PHY_MIB_CHANNEL_POS 14 -#define PHY_MIB_RATE_SET_POS 20 -#define PHY_MIB_REG_DOMAIN_POS 26 -#define LOCAL_MIB_AUTO_TX_RATE_POS 3 -#define LOCAL_MIB_SSID_SIZE 5 -#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 -#define LOCAL_MIB_TX_MGMT_RATE_POS 7 -#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 -#define LOCAL_MIB_PREAMBLE_TYPE 9 -#define MAC_ADDR_MIB_MAC_ADDR_POS 0 - -#define CMD_Set_MIB_Vars 0x01 -#define CMD_Get_MIB_Vars 0x02 -#define CMD_Scan 0x03 -#define CMD_Join 0x04 -#define CMD_Start 0x05 -#define CMD_EnableRadio 0x06 -#define CMD_DisableRadio 0x07 -#define CMD_SiteSurvey 0x0B - -#define CMD_STATUS_IDLE 0x00 -#define CMD_STATUS_COMPLETE 0x01 -#define CMD_STATUS_UNKNOWN 0x02 -#define CMD_STATUS_INVALID_PARAMETER 0x03 -#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 -#define CMD_STATUS_TIME_OUT 0x07 -#define CMD_STATUS_IN_PROGRESS 0x08 -#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 -#define CMD_STATUS_HOST_ERROR 0xFF -#define CMD_STATUS_BUSY 0xFE - -#define CMD_BLOCK_COMMAND_OFFSET 0 -#define CMD_BLOCK_STATUS_OFFSET 1 -#define CMD_BLOCK_PARAMETERS_OFFSET 4 - -#define SCAN_OPTIONS_SITE_SURVEY 0x80 - -#define MGMT_FRAME_BODY_OFFSET 24 -#define MAX_AUTHENTICATION_RETRIES 3 -#define MAX_ASSOCIATION_RETRIES 3 - -#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 - -#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ -#define LOOP_RETRY_LIMIT 500000 - -#define ACTIVE_MODE 1 -#define PS_MODE 2 - -#define MAX_ENCRYPTION_KEYS 4 -#define MAX_ENCRYPTION_KEY_SIZE 40 - -/* - * 802.11 related definitions - */ - -/* - * Regulatory Domains - */ - -#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ -#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ -#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ -#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ -#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ -#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ -#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ - -#define BSS_TYPE_AD_HOC 1 -#define BSS_TYPE_INFRASTRUCTURE 2 - -#define SCAN_TYPE_ACTIVE 0 -#define SCAN_TYPE_PASSIVE 1 - -#define LONG_PREAMBLE 0 -#define SHORT_PREAMBLE 1 -#define AUTO_PREAMBLE 2 - -#define DATA_FRAME_WS_HEADER_SIZE 30 - -/* promiscuous mode control */ -#define PROM_MODE_OFF 0x0 -#define PROM_MODE_UNKNOWN 0x1 -#define PROM_MODE_CRC_FAILED 0x2 -#define PROM_MODE_DUPLICATED 0x4 -#define PROM_MODE_MGMT 0x8 -#define PROM_MODE_CTRL 0x10 -#define PROM_MODE_BAD_PROTOCOL 0x20 - -#define IFACE_INT_STATUS_OFFSET 0 -#define IFACE_INT_MASK_OFFSET 1 -#define IFACE_LOCKOUT_HOST_OFFSET 2 -#define IFACE_LOCKOUT_MAC_OFFSET 3 -#define IFACE_FUNC_CTRL_OFFSET 28 -#define IFACE_MAC_STAT_OFFSET 30 -#define IFACE_GENERIC_INT_TYPE_OFFSET 32 - -#define CIPHER_SUITE_NONE 0 -#define CIPHER_SUITE_WEP_64 1 -#define CIPHER_SUITE_TKIP 2 -#define CIPHER_SUITE_AES 3 -#define CIPHER_SUITE_CCX 4 -#define CIPHER_SUITE_WEP_128 5 - -/* - * IFACE MACROS & definitions - */ - -/* - * FuncCtrl field: - */ -#define FUNC_CTRL_TxENABLE 0x10 -#define FUNC_CTRL_RxENABLE 0x20 -#define FUNC_CTRL_INIT_COMPLETE 0x01 - -/* A stub firmware image which reads the MAC address from NVRAM on the card. - For copyright information and source see the end of this file. */ -static u8 mac_reader[] = { - 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, - 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, - 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, - 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, - 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, - 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, - 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, - 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, - 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, - 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, - 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, - 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, - 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, - 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, - 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, - 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, - 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, - 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, - 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, - 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, - 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, - 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, - 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, - 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, - 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, - 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, - 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, - 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, - 0x00, 0x01, 0x00, 0x02 -}; - -struct atmel_private { - void *card; /* Bus dependent structure varies for PCcard */ - int (*present_callback)(void *); /* And callback which uses it */ - char firmware_id[32]; - AtmelFWType firmware_type; - u8 *firmware; - int firmware_length; - struct timer_list management_timer; - struct net_device *dev; - struct device *sys_dev; - struct iw_statistics wstats; - spinlock_t irqlock, timerlock; /* spinlocks */ - enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; - enum { - CARD_TYPE_PARALLEL_FLASH, - CARD_TYPE_SPI_FLASH, - CARD_TYPE_EEPROM - } card_type; - int do_rx_crc; /* If we need to CRC incoming packets */ - int probe_crc; /* set if we don't yet know */ - int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ - u16 rx_desc_head; - u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; - u16 tx_free_mem, tx_buff_head, tx_buff_tail; - - u16 frag_seq, frag_len, frag_no; - u8 frag_source[6]; - - u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; - u8 group_cipher_suite, pairwise_cipher_suite; - u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - int wep_key_len[MAX_ENCRYPTION_KEYS]; - int use_wpa, radio_on_broken; /* firmware dependent stuff. */ - - u16 host_info_base; - struct host_info_struct { - /* NB this is matched to the hardware, don't change. */ - u8 volatile int_status; - u8 volatile int_mask; - u8 volatile lockout_host; - u8 volatile lockout_mac; - - u16 tx_buff_pos; - u16 tx_buff_size; - u16 tx_desc_pos; - u16 tx_desc_count; - - u16 rx_buff_pos; - u16 rx_buff_size; - u16 rx_desc_pos; - u16 rx_desc_count; - - u16 build_version; - u16 command_pos; - - u16 major_version; - u16 minor_version; - - u16 func_ctrl; - u16 mac_status; - u16 generic_IRQ_type; - u8 reserved[2]; - } host_info; - - enum { - STATION_STATE_SCANNING, - STATION_STATE_JOINNING, - STATION_STATE_AUTHENTICATING, - STATION_STATE_ASSOCIATING, - STATION_STATE_READY, - STATION_STATE_REASSOCIATING, - STATION_STATE_DOWN, - STATION_STATE_MGMT_ERROR - } station_state; - - int operating_mode, power_mode; - unsigned long last_qual; - int beacons_this_sec; - int channel; - int reg_domain, config_reg_domain; - int tx_rate; - int auto_tx_rate; - int rts_threshold; - int frag_threshold; - int long_retry, short_retry; - int preamble; - int default_beacon_period, beacon_period, listen_interval; - int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; - int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; - enum { - SITE_SURVEY_IDLE, - SITE_SURVEY_IN_PROGRESS, - SITE_SURVEY_COMPLETED - } site_survey_state; - unsigned long last_survey; - - int station_was_associated, station_is_associated; - int fast_scan; - - struct bss_info { - int channel; - int SSIDsize; - int RSSI; - int UsingWEP; - int preamble; - int beacon_period; - int BSStype; - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - } BSSinfo[MAX_BSS_ENTRIES]; - int BSS_list_entries, current_BSS; - int connect_to_any_BSS; - int SSID_size, new_SSID_size; - u8 CurrentBSSID[6], BSSID[6]; - u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; - u64 last_beacon_timestamp; - u8 rx_buf[MAX_WIRELESS_BODY]; -}; - -static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; - -static const struct { - int reg_domain; - int min, max; - char *name; -} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, - { REG_DOMAIN_DOC, 1, 11, "Canada" }, - { REG_DOMAIN_ETSI, 1, 13, "Europe" }, - { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, - { REG_DOMAIN_FRANCE, 10, 13, "France" }, - { REG_DOMAIN_MKK, 14, 14, "MKK" }, - { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, - { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; - -static void build_wpa_mib(struct atmel_private *priv); -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len); -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len); -static void atmel_set_gcr(struct net_device *dev, u16 mask); -static void atmel_clear_gcr(struct net_device *dev, u16 mask); -static int atmel_lock_mac(struct atmel_private *priv); -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); -static void atmel_command_irq(struct atmel_private *priv); -static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi); -static void atmel_management_timer(struct timer_list *t); -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len); - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, - u8 data); -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data); -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len); -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len); -static void atmel_scan(struct atmel_private *priv, int specific_ssid); -static void atmel_join_bss(struct atmel_private *priv, int bss_index); -static void atmel_smooth_qual(struct atmel_private *priv); -static void atmel_writeAR(struct net_device *dev, u16 data); -static int probe_atmel_card(struct net_device *dev); -static int reset_atmel_card(struct net_device *dev); -static void atmel_enter_state(struct atmel_private *priv, int new_state); -int atmel_open (struct net_device *dev); - -static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) -{ - return priv->host_info_base + offset; -} - -static inline u16 atmel_co(struct atmel_private *priv, u16 offset) -{ - return priv->host_info.command_pos + offset; -} - -static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; -} - -static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; -} - -static inline u8 atmel_read8(struct net_device *dev, u16 offset) -{ - return inb(dev->base_addr + offset); -} - -static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) -{ - outb(data, dev->base_addr + offset); -} - -static inline u16 atmel_read16(struct net_device *dev, u16 offset) -{ - return inw(dev->base_addr + offset); -} - -static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) -{ - outw(data, dev->base_addr + offset); -} - -static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read8(priv->dev, DR); -} - -static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write8(priv->dev, DR, data); -} - -static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read16(priv->dev, DR); -} - -static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); -} - -static const struct iw_handler_def atmel_handler_def; - -static void tx_done_irq(struct atmel_private *priv) -{ - int i; - - for (i = 0; - atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && - i < priv->host_info.tx_desc_count; - i++) { - u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); - u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); - u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); - - priv->tx_free_mem += msdu_size; - priv->tx_desc_free++; - - if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) - priv->tx_buff_head = 0; - else - priv->tx_buff_head += msdu_size; - - if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_head++ ; - else - priv->tx_desc_head = 0; - - if (type == TX_PACKET_TYPE_DATA) { - if (status == TX_STATUS_SUCCESS) - priv->dev->stats.tx_packets++; - else - priv->dev->stats.tx_errors++; - netif_wake_queue(priv->dev); - } - } -} - -static u16 find_tx_buff(struct atmel_private *priv, u16 len) -{ - u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; - - if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) - return 0; - - if (bottom_free >= len) - return priv->host_info.tx_buff_pos + priv->tx_buff_tail; - - if (priv->tx_free_mem - bottom_free >= len) { - priv->tx_buff_tail = 0; - return priv->host_info.tx_buff_pos; - } - - return 0; -} - -static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, - u16 len, u16 buff, u8 type) -{ - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); - if (!priv->use_wpa) - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); - if (priv->use_wpa) { - int cipher_type, cipher_length; - if (is_bcast) { - cipher_type = priv->group_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->pairwise_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } else { - cipher_type = priv->pairwise_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->group_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), - cipher_type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), - cipher_length); - } - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); - if (priv->tx_desc_previous != priv->tx_desc_tail) - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); - priv->tx_desc_previous = priv->tx_desc_tail; - if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_tail++; - else - priv->tx_desc_tail = 0; - priv->tx_desc_free--; - priv->tx_free_mem -= len; -} - -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; - unsigned long flags; - u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (priv->station_state != STATION_STATE_READY) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* first ensure the timer func cannot run */ - spin_lock_bh(&priv->timerlock); - /* then stop the hardware ISR */ - spin_lock_irqsave(&priv->irqlock, flags); - /* nb doing the above in the opposite order will deadlock */ - - /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the - 12 first bytes (containing DA/SA) and put them in the appropriate - fields of the Wireless Header. Thus the packet length is then the - initial + 18 (+30-12) */ - - if (!(buff = find_tx_buff(priv, len + 18))) { - dev->stats.tx_dropped++; - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - - frame_ctl = IEEE80211_FTYPE_DATA; - header.duration_id = 0; - header.seq_ctrl = 0; - if (priv->wep_is_on) - frame_ctl |= IEEE80211_FCTL_PROTECTED; - if (priv->operating_mode == IW_MODE_ADHOC) { - skb_copy_from_linear_data(skb, &header.addr1, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - memcpy(&header.addr3, priv->BSSID, ETH_ALEN); - } else { - frame_ctl |= IEEE80211_FCTL_TODS; - memcpy(&header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &header.addr3, ETH_ALEN); - } - - if (priv->use_wpa) - memcpy(&header.addr4, rfc1042_header, ETH_ALEN); - - header.frame_control = cpu_to_le16(frame_ctl); - /* Copy the wireless header into the card */ - atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); - /* Copy the packet sans its 802.3 header addresses which have been replaced */ - atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); - priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; - - /* low bit of first byte of destination tells us if broadcast */ - tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); - dev->stats.tx_bytes += len; - - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len) -{ - u16 buff; - int len = MGMT_FRAME_BODY_OFFSET + body_len; - - if (!(buff = find_tx_buff(priv, len))) - return; - - atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); - atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); - priv->tx_buff_tail += len; - tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); -} - -static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc) -{ - /* fast path: unfragmented packet copy directly into skbuf */ - u8 mac4[6]; - struct sk_buff *skb; - unsigned char *skbp; - - /* get the final, mac 4 header field, this tells us encapsulation */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); - msdu_size -= 6; - - if (priv->do_rx_crc) { - crc = crc32_le(crc, mac4, 6); - msdu_size -= 4; - } - - if (!(skb = dev_alloc_skb(msdu_size + 14))) { - priv->dev->stats.rx_dropped++; - return; - } - - skb_reserve(skb, 2); - skbp = skb_put(skb, msdu_size + 12); - atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, skbp + 12, msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - dev_kfree_skb(skb); - return; - } - } - - memcpy(skbp, header->addr1, ETH_ALEN); /* destination address */ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(&skbp[ETH_ALEN], header->addr3, ETH_ALEN); - else - memcpy(&skbp[ETH_ALEN], header->addr2, ETH_ALEN); /* source address */ - - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += 12 + msdu_size; - priv->dev->stats.rx_packets++; -} - -/* Test to see if the packet in card memory at packet_loc has a valid CRC - It doesn't matter that this is slow: it is only used to proble the first few - packets. */ -static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) -{ - int i = msdu_size - 4; - u32 netcrc, crc = 0xffffffff; - - if (msdu_size < 4) - return 0; - - atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); - - atmel_writeAR(priv->dev, packet_loc); - while (i--) { - u8 octet = atmel_read8(priv->dev, DR); - crc = crc32_le(crc, &octet, 1); - } - - return (crc ^ 0xffffffff) == netcrc; -} - -static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, - u8 frag_no, int more_frags) -{ - u8 mac4[ETH_ALEN]; - u8 source[ETH_ALEN]; - struct sk_buff *skb; - - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(source, header->addr3, ETH_ALEN); - else - memcpy(source, header->addr2, ETH_ALEN); - - rx_packet_loc += 24; /* skip header */ - - if (priv->do_rx_crc) - msdu_size -= 4; - - if (frag_no == 0) { /* first fragment */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, ETH_ALEN); - msdu_size -= ETH_ALEN; - rx_packet_loc += ETH_ALEN; - - if (priv->do_rx_crc) - crc = crc32_le(crc, mac4, 6); - - priv->frag_seq = seq_no; - priv->frag_no = 1; - priv->frag_len = msdu_size; - memcpy(priv->frag_source, source, ETH_ALEN); - memcpy(&priv->rx_buf[ETH_ALEN], source, ETH_ALEN); - memcpy(priv->rx_buf, header->addr1, ETH_ALEN); - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - } - } - - } else if (priv->frag_no == frag_no && - priv->frag_seq == seq_no && - memcmp(priv->frag_source, source, ETH_ALEN) == 0) { - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], - rx_packet_loc, msdu_size); - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, - &priv->rx_buf[12 + priv->frag_len], - msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - more_frags = 1; /* don't send broken assembly */ - } - } - - priv->frag_len += msdu_size; - priv->frag_no++; - - if (!more_frags) { /* last one */ - eth_broadcast_addr(priv->frag_source); - if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { - priv->dev->stats.rx_dropped++; - } else { - skb_reserve(skb, 2); - skb_put_data(skb, priv->rx_buf, - priv->frag_len + 12); - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += priv->frag_len + 12; - priv->dev->stats.rx_packets++; - } - } - } else - priv->wstats.discard.fragment++; -} - -static void rx_done_irq(struct atmel_private *priv) -{ - int i; - struct ieee80211_hdr header; - - for (i = 0; - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && - i < priv->host_info.rx_desc_count; - i++) { - - u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; - u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); - u32 crc = 0xffffffff; - - if (status != RX_STATUS_SUCCESS) { - if (status == 0xc1) /* determined by experiment */ - priv->wstats.discard.nwid++; - else - priv->dev->stats.rx_errors++; - goto next; - } - - msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); - rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); - - if (msdu_size < 30) { - priv->dev->stats.rx_errors++; - goto next; - } - - /* Get header as far as end of seq_ctrl */ - atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_control); - seq_control = le16_to_cpu(header.seq_ctrl); - - /* probe for CRC use here if needed once five packets have - arrived with the same crc status, we assume we know what's - happening and stop probing */ - if (priv->probe_crc) { - if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); - } else { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); - } - if (priv->do_rx_crc) { - if (priv->crc_ok_cnt++ > 5) - priv->probe_crc = 0; - } else { - if (priv->crc_ko_cnt++ > 5) - priv->probe_crc = 0; - } - } - - /* don't CRC header when WEP in use */ - if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { - crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); - } - msdu_size -= 24; /* header */ - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; - u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; - u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; - - if (!more_fragments && packet_fragment_no == 0) { - fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); - } else { - frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, - packet_sequence_no, packet_fragment_no, more_fragments); - } - } - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - /* copy rest of packet into buffer */ - atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); - - /* we use the same buffer for frag reassembly and control packets */ - eth_broadcast_addr(priv->frag_source); - - if (priv->do_rx_crc) { - /* last 4 octets is crc */ - msdu_size -= 4; - crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); - if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { - priv->dev->stats.rx_crc_errors++; - goto next; - } - } - - atmel_management_frame(priv, &header, msdu_size, - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); - } - -next: - /* release descriptor */ - atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); - - if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) - priv->rx_desc_head++; - else - priv->rx_desc_head = 0; - } -} - -static irqreturn_t service_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct atmel_private *priv = netdev_priv(dev); - u8 isr; - int i = -1; - static const u8 irq_order[] = { - ISR_OUT_OF_RANGE, - ISR_RxCOMPLETE, - ISR_TxCOMPLETE, - ISR_RxFRAMELOST, - ISR_FATAL_ERROR, - ISR_COMMAND_COMPLETE, - ISR_IBSS_MERGE, - ISR_GENERIC_IRQ - }; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return IRQ_HANDLED; - - /* In this state upper-level code assumes it can mess with - the card unhampered by interrupts which may change register state. - Note that even though the card shouldn't generate interrupts - the inturrupt line may be shared. This allows card setup - to go on without disabling interrupts for a long time. */ - if (priv->station_state == STATION_STATE_DOWN) - return IRQ_NONE; - - atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ - - while (1) { - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - if (!isr) { - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ - return i == -1 ? IRQ_NONE : IRQ_HANDLED; - } - - atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ - - for (i = 0; i < ARRAY_SIZE(irq_order); i++) - if (isr & irq_order[i]) - break; - - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - isr ^= irq_order[i]; - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - switch (irq_order[i]) { - - case ISR_OUT_OF_RANGE: - if (priv->operating_mode == IW_MODE_INFRA && - priv->station_state == STATION_STATE_READY) { - priv->station_is_associated = 0; - atmel_scan(priv, 1); - } - break; - - case ISR_RxFRAMELOST: - priv->wstats.discard.misc++; - fallthrough; - case ISR_RxCOMPLETE: - rx_done_irq(priv); - break; - - case ISR_TxCOMPLETE: - tx_done_irq(priv); - break; - - case ISR_FATAL_ERROR: - printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - break; - - case ISR_COMMAND_COMPLETE: - atmel_command_irq(priv); - break; - - case ISR_IBSS_MERGE: - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - priv->CurrentBSSID, 6); - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - break; - case ISR_GENERIC_IRQ: - printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); - break; - } - } -} - -static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* update the link quality here in case we are seeing no beacons - at all to drive the process */ - atmel_smooth_qual(priv); - - priv->wstats.status = priv->station_state; - - if (priv->operating_mode == IW_MODE_INFRA) { - if (priv->station_state != STATION_STATE_READY) { - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID); - } - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; - } else { - /* Quality levels cannot be determined in ad-hoc mode, - because we can 'hear' more that one remote station. */ - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID - | IW_QUAL_NOISE_INVALID; - priv->wstats.miss.beacon = 0; - } - - return &priv->wstats; -} - -static int atmel_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - eth_hw_addr_set(dev, addr->sa_data); - return atmel_open(dev); -} - -EXPORT_SYMBOL(atmel_open); - -int atmel_open(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - int i, channel, err; - - /* any scheduled timer is no longer needed and might screw things up.. */ - del_timer_sync(&priv->management_timer); - - /* Interrupts will not touch the card once in this state... */ - priv->station_state = STATION_STATE_DOWN; - - if (priv->new_SSID_size) { - memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); - priv->SSID_size = priv->new_SSID_size; - priv->new_SSID_size = 0; - } - priv->BSS_list_entries = 0; - - priv->AuthenticationRequestRetryCnt = 0; - priv->AssociationRequestRetryCnt = 0; - priv->ReAssociationRequestRetryCnt = 0; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - priv->ExpectedAuthentTransactionSeqNum = 0x0002; - - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->station_is_associated = 0; - - err = reset_atmel_card(dev); - if (err) - return err; - - if (priv->config_reg_domain) { - priv->reg_domain = priv->config_reg_domain; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); - } else { - priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - break; - if (i == ARRAY_SIZE(channel_table)) { - priv->reg_domain = REG_DOMAIN_MKK1; - printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); - } - } - - if ((channel = atmel_validate_channel(priv, priv->channel))) - priv->channel = channel; - - /* this moves station_state on.... */ - atmel_scan(priv, 1); - - atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ - return 0; -} - -static int atmel_close(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* Send event to userspace that we are disassociating */ - if (priv->station_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - atmel_enter_state(priv, STATION_STATE_DOWN); - - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - return 0; -} - -static int atmel_validate_channel(struct atmel_private *priv, int channel) -{ - /* check that channel is OK, if so return zero, - else return suitable default channel */ - int i; - - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) { - if (channel >= channel_table[i].min && - channel <= channel_table[i].max) - return 0; - else - return channel_table[i].min; - } - return 0; -} - -#ifdef CONFIG_PROC_FS -static int atmel_proc_show(struct seq_file *m, void *v) -{ - struct atmel_private *priv = m->private; - int i; - char *s, *r, *c; - - seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); - - if (priv->station_state != STATION_STATE_DOWN) { - seq_printf(m, - "Firmware version:\t%d.%d build %d\n" - "Firmware location:\t", - priv->host_info.major_version, - priv->host_info.minor_version, - priv->host_info.build_version); - - if (priv->card_type != CARD_TYPE_EEPROM) - seq_puts(m, "on card\n"); - else if (priv->firmware) - seq_printf(m, "%s loaded by host\n", priv->firmware_id); - else - seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id); - - switch (priv->card_type) { - case CARD_TYPE_PARALLEL_FLASH: - c = "Parallel flash"; - break; - case CARD_TYPE_SPI_FLASH: - c = "SPI flash\n"; - break; - case CARD_TYPE_EEPROM: - c = "EEPROM"; - break; - default: - c = ""; - } - - r = ""; - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - r = channel_table[i].name; - - seq_printf(m, "MAC memory type:\t%s\n", c); - seq_printf(m, "Regulatory domain:\t%s\n", r); - seq_printf(m, "Host CRC checking:\t%s\n", - priv->do_rx_crc ? "On" : "Off"); - seq_printf(m, "WPA-capable firmware:\t%s\n", - priv->use_wpa ? "Yes" : "No"); - } - - switch (priv->station_state) { - case STATION_STATE_SCANNING: - s = "Scanning"; - break; - case STATION_STATE_JOINNING: - s = "Joining"; - break; - case STATION_STATE_AUTHENTICATING: - s = "Authenticating"; - break; - case STATION_STATE_ASSOCIATING: - s = "Associating"; - break; - case STATION_STATE_READY: - s = "Ready"; - break; - case STATION_STATE_REASSOCIATING: - s = "Reassociating"; - break; - case STATION_STATE_MGMT_ERROR: - s = "Management error"; - break; - case STATION_STATE_DOWN: - s = "Down"; - break; - default: - s = ""; - } - - seq_printf(m, "Current state:\t\t%s\n", s); - return 0; -} -#endif - -static const struct net_device_ops atmel_netdev_ops = { - .ndo_open = atmel_open, - .ndo_stop = atmel_close, - .ndo_set_mac_address = atmel_set_mac_address, - .ndo_start_xmit = start_tx, - .ndo_validate_addr = eth_validate_addr, -}; - -struct net_device *init_atmel_card(unsigned short irq, unsigned long port, - const AtmelFWType fw_type, - struct device *sys_dev, - int (*card_present)(void *), void *card) -{ - struct net_device *dev; - struct atmel_private *priv; - int rc; - - /* Create the network device object. */ - dev = alloc_etherdev(sizeof(*priv)); - if (!dev) - return NULL; - - if (dev_alloc_name(dev, dev->name) < 0) { - printk(KERN_ERR "atmel: Couldn't get name!\n"); - goto err_out_free; - } - - priv = netdev_priv(dev); - priv->dev = dev; - priv->sys_dev = sys_dev; - priv->present_callback = card_present; - priv->card = card; - priv->firmware = NULL; - priv->firmware_type = fw_type; - if (firmware) /* module parameter */ - strscpy(priv->firmware_id, firmware, sizeof(priv->firmware_id)); - priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; - priv->station_state = STATION_STATE_DOWN; - priv->do_rx_crc = 0; - /* For PCMCIA cards, some chips need CRC, some don't - so we have to probe. */ - if (priv->bus_type == BUS_TYPE_PCCARD) { - priv->probe_crc = 1; - priv->crc_ok_cnt = priv->crc_ko_cnt = 0; - } else - priv->probe_crc = 0; - priv->last_qual = jiffies; - priv->last_beacon_timestamp = 0; - memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); - eth_zero_addr(priv->BSSID); - priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ - priv->station_was_associated = 0; - - priv->last_survey = jiffies; - priv->preamble = LONG_PREAMBLE; - priv->operating_mode = IW_MODE_INFRA; - priv->connect_to_any_BSS = 0; - priv->config_reg_domain = 0; - priv->reg_domain = 0; - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - priv->channel = 4; - priv->power_mode = 0; - priv->SSID[0] = '\0'; - priv->SSID_size = 0; - priv->new_SSID_size = 0; - priv->frag_threshold = 2346; - priv->rts_threshold = 2347; - priv->short_retry = 7; - priv->long_retry = 4; - - priv->wep_is_on = 0; - priv->default_key = 0; - priv->encryption_level = 0; - priv->exclude_unencrypted = 0; - priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - priv->use_wpa = 0; - memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); - memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); - - priv->default_beacon_period = priv->beacon_period = 100; - priv->listen_interval = 1; - - timer_setup(&priv->management_timer, atmel_management_timer, 0); - spin_lock_init(&priv->irqlock); - spin_lock_init(&priv->timerlock); - - dev->netdev_ops = &atmel_netdev_ops; - dev->wireless_handlers = &atmel_handler_def; - dev->irq = irq; - dev->base_addr = port; - - /* MTU range: 68 - 2312 */ - dev->min_mtu = 68; - dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN; - - SET_NETDEV_DEV(dev, sys_dev); - - if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { - printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); - goto err_out_free; - } - - if (!request_region(dev->base_addr, 32, - priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { - goto err_out_irq; - } - - if (register_netdev(dev)) - goto err_out_res; - - if (!probe_atmel_card(dev)) { - unregister_netdev(dev); - goto err_out_res; - } - - netif_carrier_off(dev); - - if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show, - priv)) - printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); - - return dev; - -err_out_res: - release_region(dev->base_addr, 32); -err_out_irq: - free_irq(dev->irq, dev); -err_out_free: - free_netdev(dev); - return NULL; -} - -EXPORT_SYMBOL(init_atmel_card); - -void stop_atmel_card(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* put a brick on it... */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - - del_timer_sync(&priv->management_timer); - unregister_netdev(dev); - remove_proc_entry("driver/atmel", NULL); - free_irq(dev->irq, dev); - kfree(priv->firmware); - release_region(dev->base_addr, 32); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_atmel_card); - -static int atmel_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - priv->connect_to_any_BSS = 1; - } else { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - priv->connect_to_any_BSS = 0; - - /* Check the size of the string */ - if (dwrq->length > MAX_SSID_LENGTH) - return -E2BIG; - if (index != 0) - return -EINVAL; - - memcpy(priv->new_SSID, extra, dwrq->length); - priv->new_SSID_size = dwrq->length; - } - - return -EINPROGRESS; -} - -static int atmel_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Get the current SSID */ - if (priv->new_SSID_size != 0) { - memcpy(extra, priv->new_SSID, priv->new_SSID_size); - dwrq->length = priv->new_SSID_size; - } else { - memcpy(extra, priv->SSID, priv->SSID_size); - dwrq->length = priv->SSID_size; - } - - dwrq->flags = !priv->connect_to_any_BSS; /* active */ - - return 0; -} - -static int atmel_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - memcpy(awrq->sa_data, priv->CurrentBSSID, ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -static int atmel_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index = priv->default_key; - /* Check the size of the key */ - if (dwrq->length > 13) { - return -EINVAL; - } - /* Check the index (none -> use current) */ - if (index < 0 || index >= 4) - index = current_index; - else - priv->default_key = index; - /* Set the length */ - if (dwrq->length > 5) - priv->wep_key_len[index] = 13; - else - if (dwrq->length > 0) - priv->wep_key_len[index] = 5; - else - /* Disable the key */ - priv->wep_key_len[index] = 0; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(priv->wep_keys[index], 0, 13); - /* Copy the key in the driver */ - memcpy(priv->wep_keys[index], extra, dwrq->length); - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if (index == current_index && - priv->wep_key_len[index] > 0) { - priv->wep_is_on = 1; - priv->exclude_unencrypted = 1; - if (priv->wep_key_len[index] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (index >= 0 && index < 4) { - priv->default_key = index; - } else - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) { - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - } else { - priv->wep_is_on = 1; - if (priv->wep_key_len[priv->default_key] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - if (dwrq->flags & IW_ENCODE_RESTRICTED) - priv->exclude_unencrypted = 1; - if (dwrq->flags & IW_ENCODE_OPEN) - priv->exclude_unencrypted = 0; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - if (!priv->wep_is_on) - dwrq->flags = IW_ENCODE_DISABLED; - else { - if (priv->exclude_unencrypted) - dwrq->flags = IW_ENCODE_RESTRICTED; - else - dwrq->flags = IW_ENCODE_OPEN; - } - /* Which key do we want ? -1 -> tx index */ - if (index < 0 || index >= 4) - index = priv->default_key; - dwrq->flags |= index + 1; - /* Copy the key to the user buffer */ - dwrq->length = priv->wep_key_len[index]; - if (dwrq->length > 16) { - dwrq->length = 0; - } else { - memset(extra, 0, 16); - memcpy(extra, priv->wep_keys[index], dwrq->length); - } - - return 0; -} - -static int atmel_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, key_len, alg = ext->alg, set_key = 1; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->default_key = idx; - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > 5) { - priv->wep_key_len[idx] = 13; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else if (ext->key_len > 0) { - priv->wep_key_len[idx] = 5; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } else { - return -EINVAL; - } - priv->wep_is_on = 1; - memset(priv->wep_keys[idx], 0, 13); - key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); - memcpy(priv->wep_keys[idx], ext->key, key_len); - break; - default: - return -EINVAL; - } - } - - return -EINPROGRESS; -} - -static int atmel_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - if (!priv->wep_is_on) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - } else { - if (priv->encryption_level > 0) - ext->alg = IW_ENCODE_ALG_WEP; - else - return -EINVAL; - - ext->key_len = priv->wep_key_len[idx]; - memcpy(ext->key, priv->wep_keys[idx], ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - } - - return 0; -} - -static int atmel_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * atmel does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - priv->exclude_unencrypted = param->value ? 1 : 0; - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - priv->exclude_unencrypted = 1; - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - priv->exclude_unencrypted = 0; - } else - return -EINVAL; - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - -static int atmel_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = priv->exclude_unencrypted; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->exclude_unencrypted == 1) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int atmel_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-DS"); - return 0; -} - -static int atmel_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (vwrq->fixed == 0) { - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - } else { - priv->auto_tx_rate = 0; - - /* Which type of value ? */ - if ((vwrq->value < 4) && (vwrq->value >= 0)) { - /* Setting by rate index */ - priv->tx_rate = vwrq->value; - } else { - /* Setting by frequency value */ - switch (vwrq->value) { - case 1000000: - priv->tx_rate = 0; - break; - case 2000000: - priv->tx_rate = 1; - break; - case 5500000: - priv->tx_rate = 2; - break; - case 11000000: - priv->tx_rate = 3; - break; - default: - return -EINVAL; - } - } - } - - return -EINPROGRESS; -} - -static int atmel_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) - return -EINVAL; - - priv->operating_mode = *uwrq; - return -EINPROGRESS; -} - -static int atmel_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - *uwrq = priv->operating_mode; - return 0; -} - -static int atmel_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (priv->auto_tx_rate) { - vwrq->fixed = 0; - vwrq->value = 11000000; - } else { - vwrq->fixed = 1; - switch (priv->tx_rate) { - case 0: - vwrq->value = 1000000; - break; - case 1: - vwrq->value = 2000000; - break; - case 2: - vwrq->value = 5500000; - break; - case 3: - vwrq->value = 11000000; - break; - } - } - return 0; -} - -static int atmel_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - priv->power_mode = vwrq->disabled ? 0 : 1; - return -EINPROGRESS; -} - -static int atmel_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - vwrq->disabled = priv->power_mode ? 0 : 1; - vwrq->flags = IW_POWER_ON; - return 0; -} - -static int atmel_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { - if (vwrq->flags & IW_RETRY_LONG) - priv->long_retry = vwrq->value; - else if (vwrq->flags & IW_RETRY_SHORT) - priv->short_retry = vwrq->value; - else { - /* No modifier : set both */ - priv->long_retry = vwrq->value; - priv->short_retry = vwrq->value; - } - return -EINPROGRESS; - } - - return -EINVAL; -} - -static int atmel_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the short retry number */ - if (vwrq->flags & IW_RETRY_LONG) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = priv->long_retry; - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = priv->short_retry; - if (priv->long_retry != priv->short_retry) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -static int atmel_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = 2347; - if ((rthr < 0) || (rthr > 2347)) { - return -EINVAL; - } - priv->rts_threshold = rthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->rts_threshold; - vwrq->disabled = (vwrq->value >= 2347); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = 2346; - if ((fthr < 256) || (fthr > 2346)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - priv->frag_threshold = fthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->frag_threshold; - vwrq->disabled = (vwrq->value >= 2346); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - if (atmel_validate_channel(priv, channel) == 0) { - priv->channel = channel; - } else { - rc = -EINVAL; - } - } - return rc; -} - -static int atmel_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - - fwrq->m = priv->channel; - fwrq->e = 0; - return 0; -} - -static int atmel_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *dwrq, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (priv->station_state == STATION_STATE_DOWN) - return -EAGAIN; - - /* Timeout old surveys. */ - if (time_after(jiffies, priv->last_survey + 20 * HZ)) - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->last_survey = jiffies; - - /* Initiate a scan command */ - if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) - return -EBUSY; - - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - - priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; - priv->fast_scan = 0; - atmel_scan(priv, 0); - spin_unlock_irqrestore(&priv->irqlock, flags); - - return 0; -} - -static int atmel_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - if (priv->site_survey_state != SITE_SURVEY_COMPLETED) - return -EAGAIN; - - for (i = 0; i < priv->BSS_list_entries; i++) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - - iwe.u.data.length = priv->BSSinfo[i].SSIDsize; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, priv->BSSinfo[i].SSID); - - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = priv->BSSinfo[i].BSStype; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = priv->BSSinfo[i].channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = priv->BSSinfo[i].RSSI; - iwe.u.qual.qual = iwe.u.qual.level; - /* iwe.u.qual.noise = SOMETHING */ - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_QUAL_LEN); - - - iwe.cmd = SIOCGIWENCODE; - if (priv->BSSinfo[i].UsingWEP) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; - - return 0; -} - -static int atmel_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - struct iw_range *range = (struct iw_range *) extra; - int k, i, j; - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 0; - for (j = 0; j < ARRAY_SIZE(channel_table); j++) - if (priv->reg_domain == channel_table[j].reg_domain) { - range->num_channels = channel_table[j].max - channel_table[j].min + 1; - break; - } - if (range->num_channels != 0) { - for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { - range->freq[k].i = i; /* List index */ - - /* Values in MHz -> * 10^5 * 10 */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; - } - range->num_frequency = k; - } - - range->max_qual.qual = 100; - range->max_qual.level = 100; - range->max_qual.noise = 0; - range->max_qual.updated = IW_QUAL_NOISE_INVALID; - - range->avg_qual.qual = 50; - range->avg_qual.level = 50; - range->avg_qual.noise = 0; - range->avg_qual.updated = IW_QUAL_NOISE_INVALID; - - range->sensitivity = 0; - - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - range->num_bitrates = 4; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = 4; - - range->pmp_flags = IW_POWER_ON; - range->pmt_flags = IW_POWER_ON; - range->pm_capa = 0; - - range->we_version_source = WIRELESS_EXT; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT ; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = 0; - range->min_retry = 1; - range->max_retry = 65535; - - return 0; -} - -static int atmel_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - int i; - static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - unsigned long flags; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - - if (!memcmp(any, awrq->sa_data, 6) || - !memcmp(off, awrq->sa_data, 6)) { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_scan(priv, 1); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { - if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_join_bss(priv, i); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - } - } - - return -EINVAL; -} - -static int atmel_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *zwrq, /* NULL */ - char *extra) /* NULL */ -{ - return atmel_open(dev); -} - -static const iw_handler atmel_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, atmel_config_commit), - IW_HANDLER(SIOCGIWNAME, atmel_get_name), - IW_HANDLER(SIOCSIWFREQ, atmel_set_freq), - IW_HANDLER(SIOCGIWFREQ, atmel_get_freq), - IW_HANDLER(SIOCSIWMODE, atmel_set_mode), - IW_HANDLER(SIOCGIWMODE, atmel_get_mode), - IW_HANDLER(SIOCGIWRANGE, atmel_get_range), - IW_HANDLER(SIOCSIWAP, atmel_set_wap), - IW_HANDLER(SIOCGIWAP, atmel_get_wap), - IW_HANDLER(SIOCSIWSCAN, atmel_set_scan), - IW_HANDLER(SIOCGIWSCAN, atmel_get_scan), - IW_HANDLER(SIOCSIWESSID, atmel_set_essid), - IW_HANDLER(SIOCGIWESSID, atmel_get_essid), - IW_HANDLER(SIOCSIWRATE, atmel_set_rate), - IW_HANDLER(SIOCGIWRATE, atmel_get_rate), - IW_HANDLER(SIOCSIWRTS, atmel_set_rts), - IW_HANDLER(SIOCGIWRTS, atmel_get_rts), - IW_HANDLER(SIOCSIWFRAG, atmel_set_frag), - IW_HANDLER(SIOCGIWFRAG, atmel_get_frag), - IW_HANDLER(SIOCSIWRETRY, atmel_set_retry), - IW_HANDLER(SIOCGIWRETRY, atmel_get_retry), - IW_HANDLER(SIOCSIWENCODE, atmel_set_encode), - IW_HANDLER(SIOCGIWENCODE, atmel_get_encode), - IW_HANDLER(SIOCSIWPOWER, atmel_set_power), - IW_HANDLER(SIOCGIWPOWER, atmel_get_power), - IW_HANDLER(SIOCSIWAUTH, atmel_set_auth), - IW_HANDLER(SIOCGIWAUTH, atmel_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, atmel_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, atmel_get_encodeext), -}; - -static const iw_handler atmel_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -struct atmel_priv_ioctl { - char id[32]; - unsigned char __user *data; - unsigned short len; -}; - -#define ATMELFWL SIOCIWFIRSTPRIV -#define ATMELIDIFC ATMELFWL + 1 -#define ATMELRD ATMELFWL + 2 -#define ATMELMAGIC 0x51807 -#define REGDOMAINSZ 20 - -static const struct iw_priv_args atmel_private_args[] = { - { - .cmd = ATMELFWL, - .set_args = IW_PRIV_TYPE_BYTE - | IW_PRIV_SIZE_FIXED - | sizeof(struct atmel_priv_ioctl), - .get_args = IW_PRIV_TYPE_NONE, - .name = "atmelfwl" - }, { - .cmd = ATMELIDIFC, - .set_args = IW_PRIV_TYPE_NONE, - .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "atmelidifc" - }, { - .cmd = ATMELRD, - .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, - .get_args = IW_PRIV_TYPE_NONE, - .name = "regdomain" - }, -}; - -static const struct iw_handler_def atmel_handler_def = { - .num_standard = ARRAY_SIZE(atmel_handler), - .num_private = ARRAY_SIZE(atmel_private_handler), - .num_private_args = ARRAY_SIZE(atmel_private_args), - .standard = atmel_handler, - .private = atmel_private_handler, - .private_args = (struct iw_priv_args *) atmel_private_args, - .get_wireless_stats = atmel_get_wireless_stats -}; - -struct auth_body { - __le16 alg; - __le16 trans_seq; - __le16 status; - u8 el_id; - u8 chall_text_len; - u8 chall_text[253]; -}; - -static void atmel_enter_state(struct atmel_private *priv, int new_state) -{ - int old_state = priv->station_state; - - if (new_state == old_state) - return; - - priv->station_state = new_state; - - if (new_state == STATION_STATE_READY) { - netif_start_queue(priv->dev); - netif_carrier_on(priv->dev); - } - - if (old_state == STATION_STATE_READY) { - netif_carrier_off(priv->dev); - if (netif_running(priv->dev)) - netif_stop_queue(priv->dev); - priv->last_beacon_timestamp = 0; - } -} - -static void atmel_scan(struct atmel_private *priv, int specific_ssid) -{ - struct { - u8 BSSID[ETH_ALEN]; - u8 SSID[MAX_SSID_LENGTH]; - u8 scan_type; - u8 channel; - __le16 BSS_type; - __le16 min_channel_time; - __le16 max_channel_time; - u8 options; - u8 SSID_size; - } cmd; - - eth_broadcast_addr(cmd.BSSID); - - if (priv->fast_scan) { - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(50); - } else { - priv->BSS_list_entries = 0; - cmd.SSID_size = 0; - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(120); - } - - cmd.options = 0; - - if (!specific_ssid) - cmd.options |= SCAN_OPTIONS_SITE_SURVEY; - - cmd.channel = (priv->channel & 0x7f); - cmd.scan_type = SCAN_TYPE_ACTIVE; - cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? - BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); - - atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); - - /* This must come after all hardware access to avoid being messed up - by stuff happening in interrupt context after we leave STATE_DOWN */ - atmel_enter_state(priv, STATION_STATE_SCANNING); -} - -static void join(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; /* this is a short in a scan command - weird */ - u8 channel; - __le16 timeout; - u8 SSID_size; - u8 reserved; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->CurrentBSSID, ETH_ALEN); - cmd.channel = (priv->channel & 0x7f); - cmd.BSS_type = type; - cmd.timeout = cpu_to_le16(2000); - - atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); -} - -static void start(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; - u8 channel; - u8 SSID_size; - u8 reserved[3]; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->BSSID, ETH_ALEN); - cmd.BSS_type = type; - cmd.channel = (priv->channel & 0x7f); - - atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); -} - -static void handle_beacon_probe(struct atmel_private *priv, u16 capability, - u8 channel) -{ - int rejoin = 0; - int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; - - if (priv->preamble != new) { - priv->preamble = new; - rejoin = 1; - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); - } - - if (priv->channel != channel) { - priv->channel = channel; - rejoin = 1; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); - } - - if (rejoin) { - priv->station_is_associated = 0; - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); - } -} - -static void send_authentication_request(struct atmel_private *priv, u16 system, - u8 *challenge, int challenge_len) -{ - struct ieee80211_hdr header; - struct auth_body auth; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) - /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - auth.alg = cpu_to_le16(system); - - auth.status = 0; - auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); - priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; - priv->CurrentAuthentTransactionSeqNum += 2; - - if (challenge_len != 0) { - auth.el_id = 16; /* challenge_text */ - auth.chall_text_len = challenge_len; - memcpy(auth.chall_text, challenge, challenge_len); - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); - } else { - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); - } -} - -static void send_association_request(struct atmel_private *priv, int is_reassoc) -{ - u8 *ssid_el_p; - int bodysize; - struct ieee80211_hdr header; - struct ass_req_format { - __le16 capability; - __le16 listen_interval; - u8 ap[ETH_ALEN]; /* nothing after here directly accessible */ - u8 ssid_el_id; - u8 ssid_len; - u8 ssid[MAX_SSID_LENGTH]; - u8 sup_rates_el_id; - u8 sup_rates_len; - u8 rates[4]; - } body; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); - if (priv->wep_is_on) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); - - /* current AP address - only in reassoc frame */ - if (is_reassoc) { - memcpy(body.ap, priv->CurrentBSSID, ETH_ALEN); - ssid_el_p = &body.ssid_el_id; - bodysize = 18 + priv->SSID_size; - } else { - ssid_el_p = &body.ap[0]; - bodysize = 12 + priv->SSID_size; - } - - ssid_el_p[0] = WLAN_EID_SSID; - ssid_el_p[1] = priv->SSID_size; - memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; - ssid_el_p[3 + priv->SSID_size] = 4; /* len of supported rates */ - memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); - - atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); -} - -static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr *header) -{ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; - else - return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; -} - -static int retrieve_bss(struct atmel_private *priv) -{ - int i; - int max_rssi = -128; - int max_index = -1; - - if (priv->BSS_list_entries == 0) - return -1; - - if (priv->connect_to_any_BSS) { - /* Select a BSS with the max-RSSI but of the same type and of - the same WEP mode and that it is not marked as 'bad' (i.e. - we had previously failed to connect to this BSS with the - settings that we currently use) */ - priv->current_BSS = 0; - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->operating_mode == priv->BSSinfo[i].BSStype && - ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || - (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && - !(priv->BSSinfo[i].channel & 0x80)) { - max_rssi = priv->BSSinfo[i].RSSI; - priv->current_BSS = max_index = i; - } - } - return max_index; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && - memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && - priv->operating_mode == priv->BSSinfo[i].BSStype && - atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { - if (priv->BSSinfo[i].RSSI >= max_rssi) { - max_rssi = priv->BSSinfo[i].RSSI; - max_index = i; - } - } - } - return max_index; -} - -static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr *header, u16 capability, - u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, - u8 *ssid, int is_beacon) -{ - u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; - int i, index; - - for (index = -1, i = 0; i < priv->BSS_list_entries; i++) - if (memcmp(bss, priv->BSSinfo[i].BSSID, ETH_ALEN) == 0) - index = i; - - /* If we process a probe and an entry from this BSS exists - we will update the BSS entry with the info from this BSS. - If we process a beacon we will only update RSSI */ - - if (index == -1) { - if (priv->BSS_list_entries == MAX_BSS_ENTRIES) - return; - index = priv->BSS_list_entries++; - memcpy(priv->BSSinfo[index].BSSID, bss, ETH_ALEN); - priv->BSSinfo[index].RSSI = rssi; - } else { - if (rssi > priv->BSSinfo[index].RSSI) - priv->BSSinfo[index].RSSI = rssi; - if (is_beacon) - return; - } - - priv->BSSinfo[index].channel = channel; - priv->BSSinfo[index].beacon_period = beacon_period; - priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; - memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); - priv->BSSinfo[index].SSIDsize = ssid_len; - - if (capability & WLAN_CAPABILITY_IBSS) - priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; - else if (capability & WLAN_CAPABILITY_ESS) - priv->BSSinfo[index].BSStype = IW_MODE_INFRA; - - priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; -} - -static void authenticate(struct atmel_private *priv, u16 frame_len) -{ - struct auth_body *auth = (struct auth_body *)priv->rx_buf; - u16 status = le16_to_cpu(auth->status); - u16 trans_seq_no = le16_to_cpu(auth->trans_seq); - u16 system = le16_to_cpu(auth->alg); - - if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { - /* no WEP */ - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - - if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { - int should_associate = 0; - /* WEP */ - if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) - return; - - if (system == WLAN_AUTH_OPEN) { - if (trans_seq_no == 0x0002) { - should_associate = 1; - } - } else if (system == WLAN_AUTH_SHARED_KEY) { - if (trans_seq_no == 0x0002 && - auth->el_id == WLAN_EID_CHALLENGE) { - send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); - return; - } else if (trans_seq_no == 0x0004) { - should_associate = 1; - } - } - - if (should_associate) { - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - } - - if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - /* Flip back and forth between WEP auth modes until the max - * authentication tries has been exceeded. - */ - if (system == WLAN_AUTH_OPEN) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 1; - send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); - return; - } else if (system == WLAN_AUTH_SHARED_KEY - && priv->wep_is_on) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 0; - send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); - return; - } else if (priv->connect_to_any_BSS) { - int bss_index; - - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) { - atmel_join_bss(priv, bss_index); - return; - } - } - } - - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; -} - -static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) -{ - struct ass_resp_format { - __le16 capability; - __le16 status; - __le16 ass_id; - u8 el_id; - u8 length; - u8 rates[4]; - } *ass_resp = (struct ass_resp_format *)priv->rx_buf; - - u16 status = le16_to_cpu(ass_resp->status); - u16 ass_id = le16_to_cpu(ass_resp->ass_id); - u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; - - union iwreq_data wrqu; - - if (frame_len < 8 + rates_len) - return; - - if (status == WLAN_STATUS_SUCCESS) { - if (subtype == IEEE80211_STYPE_ASSOC_RESP) - priv->AssociationRequestRetryCnt = 0; - else - priv->ReAssociationRequestRetryCnt = 0; - - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); - atmel_set_mib(priv, Phy_Mib_Type, - PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); - if (priv->power_mode == 0) { - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } else { - priv->listen_interval = 2; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); - } - - priv->station_is_associated = 1; - priv->station_was_associated = 1; - atmel_enter_state(priv, STATION_STATE_READY); - - /* Send association event to userspace */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - return; - } - - if (subtype == IEEE80211_STYPE_ASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->AssociationRequestRetryCnt++; - send_association_request(priv, 0); - return; - } - - if (subtype == IEEE80211_STYPE_REASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->ReAssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->ReAssociationRequestRetryCnt++; - send_association_request(priv, 1); - return; - } - - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - - if (priv->connect_to_any_BSS) { - int bss_index; - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - } -} - -static void atmel_join_bss(struct atmel_private *priv, int bss_index) -{ - struct bss_info *bss = &priv->BSSinfo[bss_index]; - - memcpy(priv->CurrentBSSID, bss->BSSID, ETH_ALEN); - memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); - - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - - /* When switching to AdHoc turn OFF Power Save if needed */ - - if (bss->BSStype == IW_MODE_ADHOC && - priv->operating_mode != IW_MODE_ADHOC && - priv->power_mode) { - priv->power_mode = 0; - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } - - priv->operating_mode = bss->BSStype; - priv->channel = bss->channel & 0x7f; - priv->beacon_period = bss->beacon_period; - - if (priv->preamble != bss->preamble) { - priv->preamble = bss->preamble; - atmel_set_mib8(priv, Local_Mib_Type, - LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); - } - - if (!priv->wep_is_on && bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - if (priv->wep_is_on && !bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); -} - -static void restart_search(struct atmel_private *priv) -{ - int bss_index; - - if (!priv->connect_to_any_BSS) { - atmel_scan(priv, 1); - } else { - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - else - atmel_scan(priv, 0); - } -} - -static void smooth_rssi(struct atmel_private *priv, u8 rssi) -{ - u8 old = priv->wstats.qual.level; - u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ - - switch (priv->firmware_type) { - case ATMEL_FW_TYPE_502E: - max_rssi = 63; /* 502-rmfd-reve max by experiment */ - break; - default: - break; - } - - rssi = rssi * 100 / max_rssi; - if ((rssi + old) % 2) - priv->wstats.qual.level = (rssi + old) / 2 + 1; - else - priv->wstats.qual.level = (rssi + old) / 2; - priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; -} - -static void atmel_smooth_qual(struct atmel_private *priv) -{ - unsigned long time_diff = (jiffies - priv->last_qual) / HZ; - while (time_diff--) { - priv->last_qual += HZ; - priv->wstats.qual.qual = priv->wstats.qual.qual / 2; - priv->wstats.qual.qual += - priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; - priv->beacons_this_sec = 0; - } - priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; -} - -/* deals with incoming management frames. */ -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi) -{ - u16 subtype; - - subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; - switch (subtype) { - case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_PROBE_RESP: - - /* beacon frame has multiple variable-length fields - - never let an engineer loose with a data structure design. */ - { - struct beacon_format { - __le64 timestamp; - __le16 interval; - __le16 capability; - u8 ssid_el_id; - u8 ssid_length; - /* ssid here */ - u8 rates_el_id; - u8 rates_length; - /* rates here */ - u8 ds_el_id; - u8 ds_length; - /* ds here */ - } *beacon = (struct beacon_format *)priv->rx_buf; - - u8 channel, rates_length, ssid_length; - u64 timestamp = le64_to_cpu(beacon->timestamp); - u16 beacon_interval = le16_to_cpu(beacon->interval); - u16 capability = le16_to_cpu(beacon->capability); - u8 *beaconp = priv->rx_buf; - ssid_length = beacon->ssid_length; - /* this blows chunks. */ - if (frame_len < 14 || frame_len < ssid_length + 15) - return; - rates_length = beaconp[beacon->ssid_length + 15]; - if (frame_len < ssid_length + rates_length + 18) - return; - if (ssid_length > MAX_SSID_LENGTH) - return; - channel = beaconp[ssid_length + rates_length + 18]; - - if (priv->station_state == STATION_STATE_READY) { - smooth_rssi(priv, rssi); - if (is_frame_from_current_bss(priv, header)) { - priv->beacons_this_sec++; - atmel_smooth_qual(priv); - if (priv->last_beacon_timestamp) { - /* Note truncate this to 32 bits - kernel can't divide a long */ - u32 beacon_delay = timestamp - priv->last_beacon_timestamp; - int beacons = beacon_delay / (beacon_interval * 1000); - if (beacons > 1) - priv->wstats.miss.beacon += beacons - 1; - } - priv->last_beacon_timestamp = timestamp; - handle_beacon_probe(priv, capability, channel); - } - } - - if (priv->station_state == STATION_STATE_SCANNING) - store_bss_info(priv, header, capability, - beacon_interval, channel, rssi, - ssid_length, - &beacon->rates_el_id, - subtype == IEEE80211_STYPE_BEACON); - } - break; - - case IEEE80211_STYPE_AUTH: - - if (priv->station_state == STATION_STATE_AUTHENTICATING) - authenticate(priv, frame_len); - - break; - - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - - if (priv->station_state == STATION_STATE_ASSOCIATING || - priv->station_state == STATION_STATE_REASSOCIATING) - associate(priv, frame_len, subtype); - - break; - - case IEEE80211_STYPE_DISASSOC: - if (priv->station_is_associated && - priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - priv->station_is_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - - case IEEE80211_STYPE_DEAUTH: - if (priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - } -} - -/* run when timer expires */ -static void atmel_management_timer(struct timer_list *t) -{ - struct atmel_private *priv = from_timer(priv, t, management_timer); - unsigned long flags; - - /* Check if the card has been yanked. */ - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return; - - spin_lock_irqsave(&priv->irqlock, flags); - - switch (priv->station_state) { - - case STATION_STATE_AUTHENTICATING: - if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AuthenticationRequestRetryCnt = 0; - restart_search(priv); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt++; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - break; - - case STATION_STATE_ASSOCIATING: - if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->AssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 0); - } - break; - - case STATION_STATE_REASSOCIATING: - if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->ReAssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->ReAssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 1); - } - break; - - default: - break; - } - - spin_unlock_irqrestore(&priv->irqlock, flags); -} - -static void atmel_command_irq(struct atmel_private *priv) -{ - u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); - int fast_scan; - union iwreq_data wrqu; - - if (status == CMD_STATUS_IDLE || - status == CMD_STATUS_IN_PROGRESS) - return; - - switch (command) { - case CMD_Start: - if (status == CMD_STATUS_COMPLETE) { - priv->station_was_associated = priv->station_is_associated; - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - (u8 *)priv->CurrentBSSID, 6); - atmel_enter_state(priv, STATION_STATE_READY); - } - break; - - case CMD_Scan: - fast_scan = priv->fast_scan; - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) { - atmel_scan(priv, 1); - } else { - int bss_index = retrieve_bss(priv); - int notify_scan_complete = 1; - if (bss_index != -1) { - atmel_join_bss(priv, bss_index); - } else if (priv->operating_mode == IW_MODE_ADHOC && - priv->SSID_size != 0) { - start(priv, BSS_TYPE_AD_HOC); - } else { - priv->fast_scan = !fast_scan; - atmel_scan(priv, 1); - notify_scan_complete = 0; - } - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (notify_scan_complete) { - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } - } - break; - - case CMD_SiteSurvey: - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) - return; - - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (priv->station_is_associated) { - atmel_enter_state(priv, STATION_STATE_READY); - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } else { - atmel_scan(priv, 1); - } - break; - - case CMD_Join: - if (status == CMD_STATUS_COMPLETE) { - if (priv->operating_mode == IW_MODE_ADHOC) { - priv->station_was_associated = priv->station_is_associated; - atmel_enter_state(priv, STATION_STATE_READY); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); - - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->CurrentAuthentTransactionSeqNum = 0x0001; - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - return; - } - - atmel_scan(priv, 1); - } -} - -static int atmel_wakeup_firmware(struct atmel_private *priv) -{ - struct host_info_struct *iface = &priv->host_info; - u16 mr1, mr3; - int i; - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - atmel_set_gcr(priv->dev, GCR_REMAP); - - /* wake up on-board processor */ - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(priv->dev, BSR, BSS_SRAM); - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - mdelay(100); - - /* and wait for it */ - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_BOOT_COMPLETE) - break; - if (mr1 & MAC_BOOT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); - return -EIO; - } - - if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { - printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); - return -ENODEV; - } - - /* now check for completion of MAC initialization through - the FunCtrl field of the IFACE, poll MR1 to detect completion of - MAC initialization, check completion status, set interrupt mask, - enables interrupts and calls Tx and Rx initialization functions */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); - - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_INIT_COMPLETE) - break; - if (mr1 & MAC_INIT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to initialise.\n", - priv->dev->name); - return -EIO; - } - - /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ - if ((mr3 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); - return -EIO; - } - if ((mr1 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); - return -EIO; - } - - atmel_copy_to_host(priv->dev, (unsigned char *)iface, - priv->host_info_base, sizeof(*iface)); - - iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); - iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); - iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); - iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); - iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); - iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); - iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); - iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); - iface->build_version = le16_to_cpu(iface->build_version); - iface->command_pos = le16_to_cpu(iface->command_pos); - iface->major_version = le16_to_cpu(iface->major_version); - iface->minor_version = le16_to_cpu(iface->minor_version); - iface->func_ctrl = le16_to_cpu(iface->func_ctrl); - iface->mac_status = le16_to_cpu(iface->mac_status); - - return 0; -} - -/* determine type of memory and MAC address */ -static int probe_atmel_card(struct net_device *dev) -{ - int rc = 0; - struct atmel_private *priv = netdev_priv(dev); - u8 addr[ETH_ALEN] = {}; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - - atmel_write16(dev, GCR, 0x0040); - msleep(500); - - if (atmel_read16(dev, MR2) == 0) { - /* No stored firmware so load a small stub which just - tells us the MAC address */ - int i; - priv->card_type = CARD_TYPE_EEPROM; - atmel_write16(dev, BSR, BSS_IRAM); - atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); - atmel_set_gcr(dev, GCR_REMAP); - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(dev, BSR, BSS_SRAM); - for (i = LOOP_RETRY_LIMIT; i; i--) - if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) - break; - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); - } else { - - atmel_copy_to_host(dev, addr, atmel_read16(dev, MR2), 6); - eth_hw_addr_set(dev, addr); - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } else if (atmel_read16(dev, MR4) == 0) { - /* Mac address easy in this case. */ - priv->card_type = CARD_TYPE_PARALLEL_FLASH; - atmel_write16(dev, BSR, 1); - atmel_copy_to_host(dev, addr, 0xc000, 6); - eth_hw_addr_set(dev, addr); - atmel_write16(dev, BSR, 0x200); - rc = 1; - } else { - /* Standard firmware in flash, boot it up and ask - for the Mac Address */ - priv->card_type = CARD_TYPE_SPI_FLASH; - if (atmel_wakeup_firmware(priv) == 0) { - atmel_get_mib(priv, Mac_Address_Mib_Type, 0, addr, 6); - eth_hw_addr_set(dev, addr); - - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } - - if (rc) { - if (dev->dev_addr[0] == 0xFF) { - static const u8 default_mac[] = { - 0x00, 0x04, 0x25, 0x00, 0x00, 0x00 - }; - printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); - eth_hw_addr_set(dev, default_mac); - } - } - - return rc; -} - -/* Move the encyption information on the MIB structure. - This routine is for the pre-WPA firmware: later firmware has - a different format MIB and a different routine. */ -static void build_wep_mib(struct atmel_private *priv) -{ - struct { /* NB this is matched to the hardware, don't change. */ - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 reserved; - u8 exclude_unencrypted; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; - u8 encryption_level; /* 0, 1, 2 */ - u8 reserved2[3]; - } mib; - int i; - - mib.wep_is_on = priv->wep_is_on; - if (priv->wep_is_on) { - if (priv->wep_key_len[priv->default_key] > 5) - mib.encryption_level = 2; - else - mib.encryption_level = 1; - } else { - mib.encryption_level = 0; - } - - mib.default_key = priv->default_key; - mib.exclude_unencrypted = priv->exclude_unencrypted; - - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) - memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static void build_wpa_mib(struct atmel_private *priv) -{ - /* This is for the later (WPA enabled) firmware. */ - - struct { /* NB this is matched to the hardware, don't change. */ - u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - u8 receiver_address[ETH_ALEN]; - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 group_key; - u8 exclude_unencrypted; - u8 encryption_type; - u8 reserved; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 key_RSC[4][8]; - } mib; - - int i; - - mib.wep_is_on = priv->wep_is_on; - mib.exclude_unencrypted = priv->exclude_unencrypted; - memcpy(mib.receiver_address, priv->CurrentBSSID, ETH_ALEN); - - /* zero all the keys before adding in valid ones. */ - memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); - - if (priv->wep_is_on) { - /* There's a comment in the Atmel code to the effect that this - is only valid when still using WEP, it may need to be set to - something to use WPA */ - memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); - - mib.default_key = mib.group_key = 255; - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { - if (priv->wep_key_len[i] > 0) { - memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); - if (i == priv->default_key) { - mib.default_key = i; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; - } else { - mib.group_key = i; - priv->group_cipher_suite = priv->pairwise_cipher_suite; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; - } - } - } - if (mib.default_key == 255) - mib.default_key = mib.group_key != 255 ? mib.group_key : 0; - if (mib.group_key == 255) - mib.group_key = mib.default_key; - - } - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static int reset_atmel_card(struct net_device *dev) -{ - /* do everything necessary to wake up the hardware, including - waiting for the lightning strike and throwing the knife switch.... - - set all the Mib values which matter in the card to match - their settings in the atmel_private structure. Some of these - can be altered on the fly, but many (WEP, infrastructure or ad-hoc) - can only be changed by tearing down the world and coming back through - here. - - This routine is also responsible for initialising some - hardware-specific fields in the atmel_private structure, - including a copy of the firmware's hostinfo structure - which is the route into the rest of the firmware datastructures. */ - - struct atmel_private *priv = netdev_priv(dev); - u8 configuration; - int old_state = priv->station_state; - int err = 0; - - /* data to add to the firmware names, in priority order - this implemenents firmware versioning */ - - static char *firmware_modifier[] = { - "-wpa", - "", - NULL - }; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(priv->dev, GCR, 0x0060); - - /* stop card , disable interrupts */ - atmel_write16(priv->dev, GCR, 0x0040); - - if (priv->card_type == CARD_TYPE_EEPROM) { - /* copy in firmware if needed */ - const struct firmware *fw_entry = NULL; - const unsigned char *fw; - int len = priv->firmware_length; - if (!(fw = priv->firmware)) { - if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { - if (strlen(priv->firmware_id) == 0) { - printk(KERN_INFO - "%s: card type is unknown: assuming at76c502 firmware is OK.\n", - dev->name); - printk(KERN_INFO - "%s: if not, use the firmware= module parameter.\n", - dev->name); - strcpy(priv->firmware_id, "atmel_at76c502.bin"); - } - err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); - if (err != 0) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot continue.\n", - dev->name, priv->firmware_id); - return err; - } - } else { - int fw_index = 0; - int success = 0; - - /* get firmware filename entry based on firmware type ID */ - while (fw_table[fw_index].fw_type != priv->firmware_type - && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) - fw_index++; - - /* construct the actual firmware file name */ - if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { - int i; - for (i = 0; firmware_modifier[i]; i++) { - snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, - firmware_modifier[i], fw_table[fw_index].fw_file_ext); - priv->firmware_id[31] = '\0'; - if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { - success = 1; - break; - } - } - } - if (!success) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot start.\n", - dev->name, priv->firmware_id); - priv->firmware_id[0] = '\0'; - return -ENOENT; - } - } - - fw = fw_entry->data; - len = fw_entry->size; - } - - if (len <= 0x6000) { - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, len); - atmel_set_gcr(priv->dev, GCR_REMAP); - } else { - /* Remap */ - atmel_set_gcr(priv->dev, GCR_REMAP); - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, 0x6000); - atmel_write16(priv->dev, BSR, 0x2ff); - atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); - } - - release_firmware(fw_entry); - } - - err = atmel_wakeup_firmware(priv); - if (err != 0) - return err; - - /* Check the version and set the correct flag for wpa stuff, - old and new firmware is incompatible. - The pre-wpa 3com firmware reports major version 5, - the wpa 3com firmware is major version 4 and doesn't need - the 3com broken-ness filter. */ - priv->use_wpa = (priv->host_info.major_version == 4); - priv->radio_on_broken = (priv->host_info.major_version == 5); - - /* unmask all irq sources */ - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); - - /* int Tx system and enable Tx */ - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); - - priv->tx_desc_free = priv->host_info.tx_desc_count; - priv->tx_desc_head = 0; - priv->tx_desc_tail = 0; - priv->tx_desc_previous = 0; - priv->tx_free_mem = priv->host_info.tx_buff_size; - priv->tx_buff_head = 0; - priv->tx_buff_tail = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_TxENABLE); - - /* init Rx system and enable */ - priv->rx_desc_head = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_RxENABLE); - - if (!priv->radio_on_broken) { - if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == - CMD_STATUS_REJECTED_RADIO_OFF) { - printk(KERN_INFO "%s: cannot turn the radio on.\n", - dev->name); - return -EIO; - } - } - - /* set up enough MIB values to run. */ - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); - atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, - priv->dev->dev_addr, 6); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); - atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); - if (priv->use_wpa) - build_wpa_mib(priv); - else - build_wep_mib(priv); - - if (old_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - return 0; -} - -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - if (cmd) - atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), - cmd, cmd_size); - - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); -} - -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - int i, status; - - atmel_send_command(priv, command, cmd, cmd_size); - - for (i = 5000; i; i--) { - status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - if (status != CMD_STATUS_IDLE && - status != CMD_STATUS_IN_PROGRESS) - break; - udelay(20); - } - - if (i == 0) { - printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); - status = CMD_STATUS_HOST_ERROR; - } else { - if (command != CMD_EnableRadio) - status = CMD_STATUS_COMPLETE; - } - - return status; -} - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); - return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); -} - -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - m.data[0] = data; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); -} - -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 2; - m.index = index; - m.data[0] = data; - m.data[1] = data >> 8; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); -} - -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - memcpy(m.data, data, data_len); - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); -} - -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); - atmel_copy_to_host(priv->dev, data, - atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); -} - -static void atmel_writeAR(struct net_device *dev, u16 data) -{ - int i; - outw(data, dev->base_addr + AR); - /* Address register appears to need some convincing..... */ - for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) - outw(data, dev->base_addr + AR); -} - -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len) -{ - int i; - atmel_writeAR(dev, dest); - if (dest % 2) { - atmel_write8(dev, DR, *src); - src++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u8 lb = *src++; - u8 hb = *src++; - atmel_write16(dev, DR, lb | (hb << 8)); - } - if (i) - atmel_write8(dev, DR, *src); -} - -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len) -{ - int i; - atmel_writeAR(dev, src); - if (src % 2) { - *dest = atmel_read8(dev, DR); - dest++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u16 hw = atmel_read16(dev, DR); - *dest++ = hw; - *dest++ = hw >> 8; - } - if (i) - *dest = atmel_read8(dev, DR); -} - -static void atmel_set_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); -} - -static void atmel_clear_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); -} - -static int atmel_lock_mac(struct atmel_private *priv) -{ - int i, j = 20; - retry: - for (i = 5000; i; i--) { - if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) - break; - udelay(20); - } - - if (!i) - return 0; /* timed out */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); - if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - if (!j--) - return 0; /* timed out */ - goto retry; - } - - return 1; -} - -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); /* card is little-endian */ - atmel_write16(priv->dev, DR, data >> 16); -} - -/***************************************************************************/ -/* There follows the source form of the MAC address reading firmware */ -/***************************************************************************/ -#if 0 - -/* Copyright 2003 Matthew T. Russotto */ -/* But derived from the Atmel 76C502 firmware written by Atmel and */ -/* included in "atmel wireless lan drivers" package */ -/* - This file is part of net.russotto.AtmelMACFW, hereto referred to - as AtmelMACFW - - AtmelMACFW is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - AtmelMACFW is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with AtmelMACFW; if not, see . - -****************************************************************************/ -/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ -/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ -/* It only works on SPI EEPROM versions of the card. */ - -/* This firmware initializes the SPI controller and clock, reads the MAC */ -/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ -/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ -/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ -/* MR4, for investigational purposes (maybe we can determine chip type */ -/* from that?) */ - - .org 0 - .set MRBASE, 0x8000000 - .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ - .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ - .set SRAM_BASE, 0x02000000 - .set SP_BASE, 0x0F300000 - .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ - .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ - .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ - .set STACK_BASE, 0x5600 - .set SP_SR, 0x10 - .set SP_TDRE, 2 /* status register bit -- TDR empty */ - .set SP_RDRF, 1 /* status register bit -- RDR full */ - .set SP_SWRST, 0x80 - .set SP_SPIEN, 0x1 - .set SP_CR, 0 /* control register */ - .set SP_MR, 4 /* mode register */ - .set SP_RDR, 0x08 /* Read Data Register */ - .set SP_TDR, 0x0C /* Transmit Data Register */ - .set SP_CSR0, 0x30 /* chip select registers */ - .set SP_CSR1, 0x34 - .set SP_CSR2, 0x38 - .set SP_CSR3, 0x3C - .set NVRAM_CMD_RDSR, 5 /* read status register */ - .set NVRAM_CMD_READ, 3 /* read data */ - .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ - .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the - serial output, since SO is normally high. But it - does cause 8 clock cycles and thus 8 bits to be - clocked in to the chip. See Atmel's SPI - controller (e.g. AT91M55800) timing and 4K - SPI EEPROM manuals */ - - .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ - .set NVRAM_IMAGE, 0x02000200 - .set NVRAM_LENGTH, 0x0200 - .set MAC_ADDRESS_MIB, SRAM_BASE - .set MAC_ADDRESS_LENGTH, 6 - .set MAC_BOOT_FLAG, 0x10 - .set MR1, 0 - .set MR2, 4 - .set MR3, 8 - .set MR4, 0xC -RESET_VECTOR: - b RESET_HANDLER -UNDEF_VECTOR: - b HALT1 -SWI_VECTOR: - b HALT1 -IABORT_VECTOR: - b HALT1 -DABORT_VECTOR: -RESERVED_VECTOR: - b HALT1 -IRQ_VECTOR: - b HALT1 -FIQ_VECTOR: - b HALT1 -HALT1: b HALT1 -RESET_HANDLER: - mov r0, #CPSR_INITIAL - msr CPSR_c, r0 /* This is probably unnecessary */ - -/* I'm guessing this is initializing clock generator electronics for SPI */ - ldr r0, =SPI_CGEN_BASE - mov r1, #0 - mov r1, r1, lsl #3 - orr r1, r1, #0 - str r1, [r0] - ldr r1, [r0, #28] - bic r1, r1, #16 - str r1, [r0, #28] - mov r1, #1 - str r1, [r0, #8] - - ldr r0, =MRBASE - mov r1, #0 - strh r1, [r0, #MR1] - strh r1, [r0, #MR2] - strh r1, [r0, #MR3] - strh r1, [r0, #MR4] - - mov sp, #STACK_BASE - bl SP_INIT - mov r0, #10 - bl DELAY9 - bl GET_MAC_ADDR - bl GET_WHOLE_NVRAM - ldr r0, =MRBASE - ldr r1, =MAC_ADDRESS_MIB - strh r1, [r0, #MR2] - ldr r1, =NVRAM_IMAGE - strh r1, [r0, #MR4] - mov r1, #MAC_BOOT_FLAG - strh r1, [r0, #MR3] -HALT2: b HALT2 -.func Get_Whole_NVRAM, GET_WHOLE_NVRAM -GET_WHOLE_NVRAM: - stmdb sp!, {lr} - mov r2, #0 /* 0th bytes of NVRAM */ - mov r3, #NVRAM_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =NVRAM_IMAGE - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc - -.func Get_MAC_Addr, GET_MAC_ADDR -GET_MAC_ADDR: - stmdb sp!, {lr} - mov r2, #0x120 /* address of MAC Address within NVRAM */ - mov r3, #MAC_ADDRESS_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =MAC_ADDRESS_MIB - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc -.ltorg -.func Delay9, DELAY9 -DELAY9: - adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ -DELAYLOOP: - beq DELAY9_done - subs r0, r0, #1 - b DELAYLOOP -DELAY9_done: - bx lr -.endfunc - -.func SP_Init, SP_INIT -SP_INIT: - mov r1, #SP_SWRST - ldr r0, =SP_BASE - str r1, [r0, #SP_CR] /* reset the SPI */ - mov r1, #0 - str r1, [r0, #SP_CR] /* release SPI from reset state */ - mov r1, #SP_SPIEN - str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ - str r1, [r0, #SP_CR] /* enable the SPI */ - -/* My guess would be this turns on the SPI clock */ - ldr r3, =SPI_CGEN_BASE - ldr r1, [r3, #28] - orr r1, r1, #0x2000 - str r1, [r3, #28] - - ldr r1, =0x2000c01 - str r1, [r0, #SP_CSR0] - ldr r1, =0x2000201 - str r1, [r0, #SP_CSR1] - str r1, [r0, #SP_CSR2] - str r1, [r0, #SP_CSR3] - ldr r1, [r0, #SP_SR] - ldr r0, [r0, #SP_RDR] - bx lr -.endfunc -.func NVRAM_Init, NVRAM_INIT -NVRAM_INIT: - ldr r1, =SP_BASE - ldr r0, [r1, #SP_RDR] - mov r0, #NVRAM_CMD_RDSR - str r0, [r1, #SP_TDR] -SP_loop1: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop1 - - mov r0, #SPI_8CLOCKS - str r0, [r1, #SP_TDR] -SP_loop2: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop2 - - ldr r0, [r1, #SP_RDR] -SP_loop3: - ldr r0, [r1, #SP_SR] - tst r0, #SP_RDRF - beq SP_loop3 - - ldr r0, [r1, #SP_RDR] - and r0, r0, #255 - bx lr -.endfunc - -.func NVRAM_Xfer, NVRAM_XFER - /* r0 = dest address */ - /* r1 = not used */ - /* r2 = src address within NVRAM */ - /* r3 = length */ -NVRAM_XFER: - stmdb sp!, {r4, r5, lr} - mov r5, r0 /* save r0 (dest address) */ - mov r4, r3 /* save r3 (length) */ - mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ - and r0, r0, #8 - add r0, r0, #NVRAM_CMD_READ - ldr r1, =NVRAM_SCRATCH - strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ - strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ -_local1: - bl NVRAM_INIT - tst r0, #NVRAM_SR_RDY - bne _local1 - mov r0, #20 - bl DELAY9 - mov r2, r4 /* length */ - mov r1, r5 /* dest address */ - mov r0, #2 /* bytes to transfer in command */ - bl NVRAM_XFER2 - ldmia sp!, {r4, r5, lr} - bx lr -.endfunc - -.func NVRAM_Xfer2, NVRAM_XFER2 -NVRAM_XFER2: - stmdb sp!, {r4, r5, r6, lr} - ldr r4, =SP_BASE - mov r3, #0 - cmp r0, #0 - bls _local2 - ldr r5, =NVRAM_SCRATCH -_local4: - ldrb r6, [r5, r3] - str r6, [r4, #SP_TDR] -_local3: - ldr r6, [r4, #SP_SR] - tst r6, #SP_TDRE - beq _local3 - add r3, r3, #1 - cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ - blo _local4 -_local2: - mov r3, #SPI_8CLOCKS - str r3, [r4, #SP_TDR] - ldr r0, [r4, #SP_RDR] -_local5: - ldr r0, [r4, #SP_SR] - tst r0, #SP_RDRF - beq _local5 - ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ - mov r0, #0 - cmp r2, #0 /* r2 is # of bytes to copy in */ - bls _local6 -_local7: - ldr r5, [r4, #SP_SR] - tst r5, #SP_TDRE - beq _local7 - str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ -_local8: - ldr r5, [r4, #SP_SR] - tst r5, #SP_RDRF - beq _local8 - ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ - strb r5, [r1], #1 /* postindexed */ - add r0, r0, #1 - cmp r0, r2 - blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ -_local6: - mov r0, #200 - bl DELAY9 - ldmia sp!, {r4, r5, r6, lr} - bx lr -#endif diff --git a/drivers/net/wireless/atmel/atmel.h b/drivers/net/wireless/atmel/atmel.h deleted file mode 100644 index d2aa52cf6e8b..000000000000 --- a/drivers/net/wireless/atmel/atmel.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2005 Dan Williams and Red Hat, Inc. - - -******************************************************************************/ - -#ifndef _ATMEL_H -#define _ATMEL_H - -typedef enum { - ATMEL_FW_TYPE_NONE = 0, - ATMEL_FW_TYPE_502, - ATMEL_FW_TYPE_502D, - ATMEL_FW_TYPE_502E, - ATMEL_FW_TYPE_502_3COM, - ATMEL_FW_TYPE_504, - ATMEL_FW_TYPE_504_2958, - ATMEL_FW_TYPE_504A_2958, - ATMEL_FW_TYPE_506 -} AtmelFWType; - -struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *, - int (*present_func)(void *), void * ); -void stop_atmel_card( struct net_device *); -int atmel_open( struct net_device * ); - -#endif diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c deleted file mode 100644 index 58bba9875d36..000000000000 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ /dev/null @@ -1,292 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds. - - For all queries about this code, please contact the current author, - Simon Kelley and not Atmel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, see - . - -******************************************************************************/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "atmel.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int atmel_config(struct pcmcia_device *link); -static void atmel_release(struct pcmcia_device *link); - -static void atmel_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int atmel_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - int ret; - - dev_dbg(&p_dev->dev, "atmel_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - ret = atmel_config(p_dev); - if (ret) - goto err_free_priv; - - return 0; - -err_free_priv: - kfree(p_dev->priv); - return ret; -} - -static void atmel_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "atmel_detach\n"); - - atmel_release(link); - - kfree(link->priv); -} - -/* Call-back function to interrogate PCMCIA-specific information - about the current existence of the card */ -static int card_present(void *arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - if (pcmcia_dev_present(link)) - return 1; - - return 0; -} - -static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int atmel_config(struct pcmcia_device *link) -{ - int ret; - const struct pcmcia_device_id *did; - - did = dev_get_drvdata(&link->dev); - - dev_dbg(&link->dev, "atmel_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(link, atmel_config_check, NULL)) - goto failed; - - if (!link->irq) { - dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); - goto failed; - } - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - ((struct local_info *)link->priv)->eth_dev = - init_atmel_card(link->irq, - link->resource[0]->start, - did ? did->driver_info : ATMEL_FW_TYPE_NONE, - &link->dev, - card_present, - link); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - - return 0; - - failed: - atmel_release(link); - return -ENODEV; -} - -static void atmel_release(struct pcmcia_device *link) -{ - struct net_device *dev = ((struct local_info *)link->priv)->eth_dev; - - dev_dbg(&link->dev, "atmel_release\n"); - - if (dev) - stop_atmel_card(dev); - ((struct local_info *)link->priv)->eth_dev = NULL; - - pcmcia_disable_device(link); -} - -static int atmel_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int atmel_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - atmel_open(local->eth_dev); - netif_device_attach(local->eth_dev); - - return 0; -} - -/*====================================================================*/ -/* We use the driver_info field to store the correct firmware type for a card. */ - -#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \ - PCMCIA_DEV_ID_MATCH_CARD_ID, \ - .manf_id = (manf), \ - .card_id = (card), \ - .driver_info = (kernel_ulong_t)(info), } - -#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \ - PCMCIA_DEV_ID_MATCH_PROD_ID2, \ - .prod_id = { (v1), (v2), NULL, NULL }, \ - .prod_id_hash = { (vh1), (vh2), 0, 0 }, \ - .driver_info = (kernel_ulong_t)(info), } - -static const struct pcmcia_device_id atmel_ids[] = { - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_NULL -}; - -MODULE_DEVICE_TABLE(pcmcia, atmel_ids); - -static struct pcmcia_driver atmel_driver = { - .owner = THIS_MODULE, - .name = "atmel_cs", - .probe = atmel_probe, - .remove = atmel_detach, - .id_table = atmel_ids, - .suspend = atmel_suspend, - .resume = atmel_resume, -}; -module_pcmcia_driver(atmel_driver); - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ diff --git a/drivers/net/wireless/atmel/atmel_pci.c b/drivers/net/wireless/atmel/atmel_pci.c deleted file mode 100644 index f428dc79d916..000000000000 --- a/drivers/net/wireless/atmel/atmel_pci.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2004 Simon Kelley. - - -******************************************************************************/ -#include -#include -#include -#include -#include "atmel.h" - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -static const struct pci_device_id card_ids[] = { - { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, card_ids); - -static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void atmel_pci_remove(struct pci_dev *); - -static struct pci_driver atmel_driver = { - .name = "atmel", - .id_table = card_ids, - .probe = atmel_pci_probe, - .remove = atmel_pci_remove, -}; - - -static int atmel_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - - pci_set_master(pdev); - - dev = init_atmel_card(pdev->irq, pdev->resource[1].start, - ATMEL_FW_TYPE_506, - &pdev->dev, NULL, NULL); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void atmel_pci_remove(struct pci_dev *pdev) -{ - stop_atmel_card(pci_get_drvdata(pdev)); -} - -module_pci_driver(atmel_driver); From 6853c70ba5edca34f65b337a04183a6145303071 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:45 +0200 Subject: [PATCH 0154/7721] wifi: remove orphaned cisco/aironet driver Cisco Aironet is an 802.11b PCMCIA and mini-PCI with limited support for Cardbus DMA and for CFG80211. Both PCMCIA and WEXT are deprecated, and there is little chance that anyone is still using this driver, so remove it. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/Kconfig | 1 - drivers/net/wireless/Makefile | 1 - drivers/net/wireless/cisco/Kconfig | 59 - drivers/net/wireless/cisco/Makefile | 3 - drivers/net/wireless/cisco/airo.c | 8287 -------------------------- drivers/net/wireless/cisco/airo.h | 10 - drivers/net/wireless/cisco/airo_cs.c | 218 - 7 files changed, 8579 deletions(-) delete mode 100644 drivers/net/wireless/cisco/Kconfig delete mode 100644 drivers/net/wireless/cisco/Makefile delete mode 100644 drivers/net/wireless/cisco/airo.c delete mode 100644 drivers/net/wireless/cisco/airo.h delete mode 100644 drivers/net/wireless/cisco/airo_cs.c diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7555af5195ec..834d3725f1a5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig" source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/atmel/Kconfig" source "drivers/net/wireless/broadcom/Kconfig" -source "drivers/net/wireless/cisco/Kconfig" source "drivers/net/wireless/intel/Kconfig" source "drivers/net/wireless/intersil/Kconfig" source "drivers/net/wireless/marvell/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4d7374d567d1..ee722439d452 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ -obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/ obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/ obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/ obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/ diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig deleted file mode 100644 index b40ee25aca99..000000000000 --- a/drivers/net/wireless/cisco/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config WLAN_VENDOR_CISCO - bool "Cisco devices" - default y - help - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all the - questions about these cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_CISCO - -config AIRO - tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on CFG80211 && (PCI || BROKEN) - select WIRELESS_EXT - select CRYPTO - select CRYPTO_SKCIPHER - select WEXT_SPY - select WEXT_PRIV - help - This is the standard Linux driver to support Cisco/Aironet ISA and - PCI 802.11 wireless cards. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - - The driver can be compiled as a module and will be named "airo". - -config AIRO_CS - tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_AES - select CRYPTO_CTR - help - This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet - driver part of the Linux Pcmcia package. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also - supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom - 802.11b cards. - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - -endif # WLAN_VENDOR_CISCO diff --git a/drivers/net/wireless/cisco/Makefile b/drivers/net/wireless/cisco/Makefile deleted file mode 100644 index 506a19ce375f..000000000000 --- a/drivers/net/wireless/cisco/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_AIRO) += airo.o -obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c deleted file mode 100644 index 6a099642e854..000000000000 --- a/drivers/net/wireless/cisco/airo.c +++ /dev/null @@ -1,8287 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. Major code contributions were received from Javier Achirica - and Jean Tourrilhes . - Code was also integrated from the Cisco Aironet driver for Linux. - Support for MPI350 cards was added by Fabrice Bellet - . - -======================================================================*/ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "airo.h" - -#define DRV_NAME "airo" - -#ifdef CONFIG_PCI -static const struct pci_device_id card_ids[] = { - { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, - { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, card_ids); - -static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void airo_pci_remove(struct pci_dev *); -static int __maybe_unused airo_pci_suspend(struct device *dev); -static int __maybe_unused airo_pci_resume(struct device *dev); - -static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, - airo_pci_suspend, - airo_pci_resume); - -static struct pci_driver airo_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = airo_pci_probe, - .remove = airo_pci_remove, - .driver.pm = &airo_pci_pm_ops, -}; -#endif /* CONFIG_PCI */ - -/* Include Wireless Extension definition and check version - Jean II */ -#include -#define WIRELESS_SPY /* enable iwspy support */ - -#define CISCO_EXT /* enable Cisco extensions */ -#ifdef CISCO_EXT -#include -#endif - -/* Hack to do some power saving */ -#define POWER_ON_DOWN - -/* As you can see this list is HUGH! - I really don't know what a lot of these counts are about, but they - are all here for completeness. If the IGNLABEL macro is put in - infront of the label, that statistic will not be included in the list - of statistics in the /proc filesystem */ - -#define IGNLABEL(comment) NULL -static const char *statsLabels[] = { - "RxOverrun", - IGNLABEL("RxPlcpCrcErr"), - IGNLABEL("RxPlcpFormatErr"), - IGNLABEL("RxPlcpLengthErr"), - "RxMacCrcErr", - "RxMacCrcOk", - "RxWepErr", - "RxWepOk", - "RetryLong", - "RetryShort", - "MaxRetries", - "NoAck", - "NoCts", - "RxAck", - "RxCts", - "TxAck", - "TxRts", - "TxCts", - "TxMc", - "TxBc", - "TxUcFrags", - "TxUcPackets", - "TxBeacon", - "RxBeacon", - "TxSinColl", - "TxMulColl", - "DefersNo", - "DefersProt", - "DefersEngy", - "DupFram", - "RxFragDisc", - "TxAged", - "RxAged", - "LostSync-MaxRetry", - "LostSync-MissedBeacons", - "LostSync-ArlExceeded", - "LostSync-Deauth", - "LostSync-Disassoced", - "LostSync-TsfTiming", - "HostTxMc", - "HostTxBc", - "HostTxUc", - "HostTxFail", - "HostRxMc", - "HostRxBc", - "HostRxUc", - "HostRxDiscard", - IGNLABEL("HmacTxMc"), - IGNLABEL("HmacTxBc"), - IGNLABEL("HmacTxUc"), - IGNLABEL("HmacTxFail"), - IGNLABEL("HmacRxMc"), - IGNLABEL("HmacRxBc"), - IGNLABEL("HmacRxUc"), - IGNLABEL("HmacRxDiscard"), - IGNLABEL("HmacRxAccepted"), - "SsidMismatch", - "ApMismatch", - "RatesMismatch", - "AuthReject", - "AuthTimeout", - "AssocReject", - "AssocTimeout", - IGNLABEL("ReasonOutsideTable"), - IGNLABEL("ReasonStatus1"), - IGNLABEL("ReasonStatus2"), - IGNLABEL("ReasonStatus3"), - IGNLABEL("ReasonStatus4"), - IGNLABEL("ReasonStatus5"), - IGNLABEL("ReasonStatus6"), - IGNLABEL("ReasonStatus7"), - IGNLABEL("ReasonStatus8"), - IGNLABEL("ReasonStatus9"), - IGNLABEL("ReasonStatus10"), - IGNLABEL("ReasonStatus11"), - IGNLABEL("ReasonStatus12"), - IGNLABEL("ReasonStatus13"), - IGNLABEL("ReasonStatus14"), - IGNLABEL("ReasonStatus15"), - IGNLABEL("ReasonStatus16"), - IGNLABEL("ReasonStatus17"), - IGNLABEL("ReasonStatus18"), - IGNLABEL("ReasonStatus19"), - "RxMan", - "TxMan", - "RxRefresh", - "TxRefresh", - "RxPoll", - "TxPoll", - "HostRetries", - "LostSync-HostReq", - "HostTxBytes", - "HostRxBytes", - "ElapsedUsec", - "ElapsedSec", - "LostSyncBetterAP", - "PrivacyMismatch", - "Jammed", - "DiscRxNotWepped", - "PhyEleMismatch", - (char*)-1 }; -#ifndef RUN_AT -#define RUN_AT(x) (jiffies+(x)) -#endif - - -/* These variables are for insmod, since it seems that the rates - can only be set in setup_card. Rates should be a comma separated - (no spaces) list of rates (up to 8). */ - -static int rates[8]; -static char *ssids[3]; - -static int io[4]; -static int irq[4]; - -static -int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. - 0 means no limit. For old cards this was 4 */ - -static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ -static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read - the bap, needed on some older cards and buses. */ -static int adhoc; - -static int probe = 1; - -static kuid_t proc_kuid; -static int proc_uid /* = 0 */; - -static kgid_t proc_kgid; -static int proc_gid /* = 0 */; - -static int airo_perm = 0555; - -static int proc_perm = 0644; - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. " - "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs."); -MODULE_LICENSE("Dual BSD/GPL"); -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_array(rates, int, NULL, 0); -module_param_array(ssids, charp, NULL, 0); -module_param(auto_wep, int, 0); -MODULE_PARM_DESC(auto_wep, - "If non-zero, the driver will keep looping through the authentication options until an association is made. " - "The value of auto_wep is number of the wep keys to check. " - "A value of 2 will try using the key at index 0 and index 1."); -module_param(aux_bap, int, 0); -MODULE_PARM_DESC(aux_bap, - "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. " - "Before switching it checks that the switch is needed."); -module_param(maxencrypt, int, 0); -MODULE_PARM_DESC(maxencrypt, - "The maximum speed that the card can do encryption. " - "Units are in 512kbs. " - "Zero (default) means there is no limit. " - "Older cards used to be limited to 2mbs (4)."); -module_param(adhoc, int, 0); -MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); -module_param(probe, int, 0); -MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); - -module_param(proc_uid, int, 0); -MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); -module_param(proc_gid, int, 0); -MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); -module_param(airo_perm, int, 0); -MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); -module_param(proc_perm, int, 0); -MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); - -/* This is a kind of sloppy hack to get this information to OUT4500 and - IN4500. I would be extremely interested in the situation where this - doesn't work though!!! */ -static int do8bitIO /* = 0 */; - -/* Return codes */ -#define SUCCESS 0 -#define ERROR -1 -#define NO_PACKET -2 - -/* Commands */ -#define NOP2 0x0000 -#define MAC_ENABLE 0x0001 -#define MAC_DISABLE 0x0002 -#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ -#define CMD_SOFTRESET 0x0004 -#define HOSTSLEEP 0x0005 -#define CMD_MAGIC_PKT 0x0006 -#define CMD_SETWAKEMASK 0x0007 -#define CMD_READCFG 0x0008 -#define CMD_SETMODE 0x0009 -#define CMD_ALLOCATETX 0x000a -#define CMD_TRANSMIT 0x000b -#define CMD_DEALLOCATETX 0x000c -#define NOP 0x0010 -#define CMD_WORKAROUND 0x0011 -#define CMD_ALLOCATEAUX 0x0020 -#define CMD_ACCESS 0x0021 -#define CMD_PCIBAP 0x0022 -#define CMD_PCIAUX 0x0023 -#define CMD_ALLOCBUF 0x0028 -#define CMD_GETTLV 0x0029 -#define CMD_PUTTLV 0x002a -#define CMD_DELTLV 0x002b -#define CMD_FINDNEXTTLV 0x002c -#define CMD_PSPNODES 0x0030 -#define CMD_SETCW 0x0031 -#define CMD_SETPCF 0x0032 -#define CMD_SETPHYREG 0x003e -#define CMD_TXTEST 0x003f -#define MAC_ENABLETX 0x0101 -#define CMD_LISTBSS 0x0103 -#define CMD_SAVECFG 0x0108 -#define CMD_ENABLEAUX 0x0111 -#define CMD_WRITERID 0x0121 -#define CMD_USEPSPNODES 0x0130 -#define MAC_ENABLERX 0x0201 - -/* Command errors */ -#define ERROR_QUALIF 0x00 -#define ERROR_ILLCMD 0x01 -#define ERROR_ILLFMT 0x02 -#define ERROR_INVFID 0x03 -#define ERROR_INVRID 0x04 -#define ERROR_LARGE 0x05 -#define ERROR_NDISABL 0x06 -#define ERROR_ALLOCBSY 0x07 -#define ERROR_NORD 0x0B -#define ERROR_NOWR 0x0C -#define ERROR_INVFIDTX 0x0D -#define ERROR_TESTACT 0x0E -#define ERROR_TAGNFND 0x12 -#define ERROR_DECODE 0x20 -#define ERROR_DESCUNAV 0x21 -#define ERROR_BADLEN 0x22 -#define ERROR_MODE 0x80 -#define ERROR_HOP 0x81 -#define ERROR_BINTER 0x82 -#define ERROR_RXMODE 0x83 -#define ERROR_MACADDR 0x84 -#define ERROR_RATES 0x85 -#define ERROR_ORDER 0x86 -#define ERROR_SCAN 0x87 -#define ERROR_AUTH 0x88 -#define ERROR_PSMODE 0x89 -#define ERROR_RTYPE 0x8A -#define ERROR_DIVER 0x8B -#define ERROR_SSID 0x8C -#define ERROR_APLIST 0x8D -#define ERROR_AUTOWAKE 0x8E -#define ERROR_LEAP 0x8F - -/* Registers */ -#define COMMAND 0x00 -#define PARAM0 0x02 -#define PARAM1 0x04 -#define PARAM2 0x06 -#define STATUS 0x08 -#define RESP0 0x0a -#define RESP1 0x0c -#define RESP2 0x0e -#define LINKSTAT 0x10 -#define SELECT0 0x18 -#define OFFSET0 0x1c -#define RXFID 0x20 -#define TXALLOCFID 0x22 -#define TXCOMPLFID 0x24 -#define DATA0 0x36 -#define EVSTAT 0x30 -#define EVINTEN 0x32 -#define EVACK 0x34 -#define SWS0 0x28 -#define SWS1 0x2a -#define SWS2 0x2c -#define SWS3 0x2e -#define AUXPAGE 0x3A -#define AUXOFF 0x3C -#define AUXDATA 0x3E - -#define FID_TX 1 -#define FID_RX 2 -/* Offset into aux memory for descriptors */ -#define AUX_OFFSET 0x800 -/* Size of allocated packets */ -#define PKTSIZE 1840 -#define RIDSIZE 2048 -/* Size of the transmit queue */ -#define MAXTXQ 64 - -/* BAP selectors */ -#define BAP0 0 /* Used for receiving packets */ -#define BAP1 2 /* Used for xmiting packets and working with RIDS */ - -/* Flags */ -#define COMMAND_BUSY 0x8000 - -#define BAP_BUSY 0x8000 -#define BAP_ERR 0x4000 -#define BAP_DONE 0x2000 - -#define PROMISC 0xffff -#define NOPROMISC 0x0000 - -#define EV_CMD 0x10 -#define EV_CLEARCOMMANDBUSY 0x4000 -#define EV_RX 0x01 -#define EV_TX 0x02 -#define EV_TXEXC 0x04 -#define EV_ALLOC 0x08 -#define EV_LINK 0x80 -#define EV_AWAKE 0x100 -#define EV_TXCPY 0x400 -#define EV_UNKNOWN 0x800 -#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ -#define EV_AWAKEN 0x2000 -#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) - -#ifdef CHECK_UNKNOWN_INTS -#define IGNORE_INTS (EV_CMD | EV_UNKNOWN) -#else -#define IGNORE_INTS (~STATUS_INTS) -#endif - -/* RID TYPES */ -#define RID_RW 0x20 - -/* The RIDs */ -#define RID_CAPABILITIES 0xFF00 -#define RID_APINFO 0xFF01 -#define RID_RADIOINFO 0xFF02 -#define RID_UNKNOWN3 0xFF03 -#define RID_RSSI 0xFF04 -#define RID_CONFIG 0xFF10 -#define RID_SSID 0xFF11 -#define RID_APLIST 0xFF12 -#define RID_DRVNAME 0xFF13 -#define RID_ETHERENCAP 0xFF14 -#define RID_WEP_TEMP 0xFF15 -#define RID_WEP_PERM 0xFF16 -#define RID_MODULATION 0xFF17 -#define RID_OPTIONS 0xFF18 -#define RID_ACTUALCONFIG 0xFF20 /*readonly*/ -#define RID_FACTORYCONFIG 0xFF21 -#define RID_UNKNOWN22 0xFF22 -#define RID_LEAPUSERNAME 0xFF23 -#define RID_LEAPPASSWORD 0xFF24 -#define RID_STATUS 0xFF50 -#define RID_BEACON_HST 0xFF51 -#define RID_BUSY_HST 0xFF52 -#define RID_RETRIES_HST 0xFF53 -#define RID_UNKNOWN54 0xFF54 -#define RID_UNKNOWN55 0xFF55 -#define RID_UNKNOWN56 0xFF56 -#define RID_MIC 0xFF57 -#define RID_STATS16 0xFF60 -#define RID_STATS16DELTA 0xFF61 -#define RID_STATS16DELTACLEAR 0xFF62 -#define RID_STATS 0xFF68 -#define RID_STATSDELTA 0xFF69 -#define RID_STATSDELTACLEAR 0xFF6A -#define RID_ECHOTEST_RID 0xFF70 -#define RID_ECHOTEST_RESULTS 0xFF71 -#define RID_BSSLISTFIRST 0xFF72 -#define RID_BSSLISTNEXT 0xFF73 -#define RID_WPA_BSSLISTFIRST 0xFF74 -#define RID_WPA_BSSLISTNEXT 0xFF75 - -typedef struct { - u16 cmd; - u16 parm0; - u16 parm1; - u16 parm2; -} Cmd; - -typedef struct { - u16 status; - u16 rsp0; - u16 rsp1; - u16 rsp2; -} Resp; - -/* - * Rids and endian-ness: The Rids will always be in cpu endian, since - * this all the patches from the big-endian guys end up doing that. - * so all rid access should use the read/writeXXXRid routines. - */ - -/* This structure came from an email sent to me from an engineer at - aironet for inclusion into this driver */ -typedef struct WepKeyRid WepKeyRid; -struct WepKeyRid { - __le16 len; - __le16 kindex; - u8 mac[ETH_ALEN]; - __le16 klen; - u8 key[16]; -} __packed; - -/* These structures are from the Aironet's PC4500 Developers Manual */ -typedef struct Ssid Ssid; -struct Ssid { - __le16 len; - u8 ssid[32]; -} __packed; - -typedef struct SsidRid SsidRid; -struct SsidRid { - __le16 len; - Ssid ssids[3]; -} __packed; - -typedef struct ModulationRid ModulationRid; -struct ModulationRid { - __le16 len; - __le16 modulation; -#define MOD_DEFAULT cpu_to_le16(0) -#define MOD_CCK cpu_to_le16(1) -#define MOD_MOK cpu_to_le16(2) -} __packed; - -typedef struct ConfigRid ConfigRid; -struct ConfigRid { - __le16 len; /* sizeof(ConfigRid) */ - __le16 opmode; /* operating mode */ -#define MODE_STA_IBSS cpu_to_le16(0) -#define MODE_STA_ESS cpu_to_le16(1) -#define MODE_AP cpu_to_le16(2) -#define MODE_AP_RPTR cpu_to_le16(3) -#define MODE_CFG_MASK cpu_to_le16(0xff) -#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */ -#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */ -#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */ -#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */ -#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */ -#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */ -#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */ -#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */ -#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */ - __le16 rmode; /* receive mode */ -#define RXMODE_BC_MC_ADDR cpu_to_le16(0) -#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */ -#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */ -#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */ -#define RXMODE_RFMON_ANYBSS cpu_to_le16(4) -#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */ -#define RXMODE_MASK cpu_to_le16(255) -#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */ -#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER) -#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */ - __le16 fragThresh; - __le16 rtsThres; - u8 macAddr[ETH_ALEN]; - u8 rates[8]; - __le16 shortRetryLimit; - __le16 longRetryLimit; - __le16 txLifetime; /* in kusec */ - __le16 rxLifetime; /* in kusec */ - __le16 stationary; - __le16 ordering; - __le16 u16deviceType; /* for overriding device type */ - __le16 cfpRate; - __le16 cfpDuration; - __le16 _reserved1[3]; - /*---------- Scanning/Associating ----------*/ - __le16 scanMode; -#define SCANMODE_ACTIVE cpu_to_le16(0) -#define SCANMODE_PASSIVE cpu_to_le16(1) -#define SCANMODE_AIROSCAN cpu_to_le16(2) - __le16 probeDelay; /* in kusec */ - __le16 probeEnergyTimeout; /* in kusec */ - __le16 probeResponseTimeout; - __le16 beaconListenTimeout; - __le16 joinNetTimeout; - __le16 authTimeout; - __le16 authType; -#define AUTH_OPEN cpu_to_le16(0x1) -#define AUTH_ENCRYPT cpu_to_le16(0x101) -#define AUTH_SHAREDKEY cpu_to_le16(0x102) -#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200) - __le16 associationTimeout; - __le16 specifiedApTimeout; - __le16 offlineScanInterval; - __le16 offlineScanDuration; - __le16 linkLossDelay; - __le16 maxBeaconLostTime; - __le16 refreshInterval; -#define DISABLE_REFRESH cpu_to_le16(0xFFFF) - __le16 _reserved1a[1]; - /*---------- Power save operation ----------*/ - __le16 powerSaveMode; -#define POWERSAVE_CAM cpu_to_le16(0) -#define POWERSAVE_PSP cpu_to_le16(1) -#define POWERSAVE_PSPCAM cpu_to_le16(2) - __le16 sleepForDtims; - __le16 listenInterval; - __le16 fastListenInterval; - __le16 listenDecay; - __le16 fastListenDelay; - __le16 _reserved2[2]; - /*---------- Ap/Ibss config items ----------*/ - __le16 beaconPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 dtimPeriod; - __le16 bridgeDistance; - __le16 radioID; - /*---------- Radio configuration ----------*/ - __le16 radioType; -#define RADIOTYPE_DEFAULT cpu_to_le16(0) -#define RADIOTYPE_802_11 cpu_to_le16(1) -#define RADIOTYPE_LEGACY cpu_to_le16(2) - u8 rxDiversity; - u8 txDiversity; - __le16 txPower; -#define TXPOWER_DEFAULT 0 - __le16 rssiThreshold; -#define RSSI_DEFAULT 0 - __le16 modulation; -#define PREAMBLE_AUTO cpu_to_le16(0) -#define PREAMBLE_LONG cpu_to_le16(1) -#define PREAMBLE_SHORT cpu_to_le16(2) - __le16 preamble; - __le16 homeProduct; - __le16 radioSpecific; - /*---------- Aironet Extensions ----------*/ - u8 nodeName[16]; - __le16 arlThreshold; - __le16 arlDecay; - __le16 arlDelay; - __le16 _reserved4[1]; - /*---------- Aironet Extensions ----------*/ - u8 magicAction; -#define MAGIC_ACTION_STSCHG 1 -#define MAGIC_ACTION_RESUME 2 -#define MAGIC_IGNORE_MCAST (1<<8) -#define MAGIC_IGNORE_BCAST (1<<9) -#define MAGIC_SWITCH_TO_PSP (0<<10) -#define MAGIC_STAY_IN_CAM (1<<10) - u8 magicControl; - __le16 autoWake; -} __packed; - -typedef struct StatusRid StatusRid; -struct StatusRid { - __le16 len; - u8 mac[ETH_ALEN]; - __le16 mode; - __le16 errorCode; - __le16 sigQuality; - __le16 SSIDlen; - char SSID[32]; - char apName[16]; - u8 bssid[4][ETH_ALEN]; - __le16 beaconPeriod; - __le16 dimPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 hopsToBackbone; - __le16 apTotalLoad; - __le16 generatedLoad; - __le16 accumulatedArl; - __le16 signalQuality; - __le16 currentXmitRate; - __le16 apDevExtensions; - __le16 normalizedSignalStrength; - __le16 shortPreamble; - u8 apIP[4]; - u8 noisePercent; /* Noise percent in last second */ - u8 noisedBm; /* Noise dBm in last second */ - u8 noiseAvePercent; /* Noise percent in last minute */ - u8 noiseAvedBm; /* Noise dBm in last minute */ - u8 noiseMaxPercent; /* Highest noise percent in last minute */ - u8 noiseMaxdBm; /* Highest noise dbm in last minute */ - __le16 load; - u8 carrier[4]; - __le16 assocStatus; -#define STAT_NOPACKETS 0 -#define STAT_NOCARRIERSET 10 -#define STAT_GOTCARRIERSET 11 -#define STAT_WRONGSSID 20 -#define STAT_BADCHANNEL 25 -#define STAT_BADBITRATES 30 -#define STAT_BADPRIVACY 35 -#define STAT_APFOUND 40 -#define STAT_APREJECTED 50 -#define STAT_AUTHENTICATING 60 -#define STAT_DEAUTHENTICATED 61 -#define STAT_AUTHTIMEOUT 62 -#define STAT_ASSOCIATING 70 -#define STAT_DEASSOCIATED 71 -#define STAT_ASSOCTIMEOUT 72 -#define STAT_NOTAIROAP 73 -#define STAT_ASSOCIATED 80 -#define STAT_LEAPING 90 -#define STAT_LEAPFAILED 91 -#define STAT_LEAPTIMEDOUT 92 -#define STAT_LEAPCOMPLETE 93 -} __packed; - -typedef struct StatsRid StatsRid; -struct StatsRid { - __le16 len; - __le16 spacer; - __le32 vals[100]; -} __packed; - -typedef struct APListRid APListRid; -struct APListRid { - __le16 len; - u8 ap[4][ETH_ALEN]; -} __packed; - -typedef struct CapabilityRid CapabilityRid; -struct CapabilityRid { - __le16 len; - char oui[3]; - char zero; - __le16 prodNum; - char manName[32]; - char prodName[16]; - char prodVer[8]; - char factoryAddr[ETH_ALEN]; - char aironetAddr[ETH_ALEN]; - __le16 radioType; - __le16 country; - char callid[ETH_ALEN]; - char supportedRates[8]; - char rxDiversity; - char txDiversity; - __le16 txPowerLevels[8]; - __le16 hardVer; - __le16 hardCap; - __le16 tempRange; - __le16 softVer; - __le16 softSubVer; - __le16 interfaceVer; - __le16 softCap; - __le16 bootBlockVer; - __le16 requiredHard; - __le16 extSoftCap; -} __packed; - -/* Only present on firmware >= 5.30.17 */ -typedef struct BSSListRidExtra BSSListRidExtra; -struct BSSListRidExtra { - __le16 unknown[4]; - u8 fixed[12]; /* WLAN management frame */ - u8 iep[624]; -} __packed; - -typedef struct BSSListRid BSSListRid; -struct BSSListRid { - __le16 len; - __le16 index; /* First is 0 and 0xffff means end of list */ -#define RADIO_FH 1 /* Frequency hopping radio type */ -#define RADIO_DS 2 /* Direct sequence radio type */ -#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ - __le16 radioType; - u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ - u8 zero; - u8 ssidLen; - u8 ssid[32]; - __le16 dBm; -#define CAP_ESS cpu_to_le16(1<<0) -#define CAP_IBSS cpu_to_le16(1<<1) -#define CAP_PRIVACY cpu_to_le16(1<<4) -#define CAP_SHORTHDR cpu_to_le16(1<<5) - __le16 cap; - __le16 beaconInterval; - u8 rates[8]; /* Same as rates for config rid */ - struct { /* For frequency hopping only */ - __le16 dwell; - u8 hopSet; - u8 hopPattern; - u8 hopIndex; - u8 fill; - } fh; - __le16 dsChannel; - __le16 atimWindow; - - /* Only present on firmware >= 5.30.17 */ - BSSListRidExtra extra; -} __packed; - -typedef struct { - BSSListRid bss; - struct list_head list; -} BSSListElement; - -typedef struct tdsRssiEntry tdsRssiEntry; -struct tdsRssiEntry { - u8 rssipct; - u8 rssidBm; -} __packed; - -typedef struct tdsRssiRid tdsRssiRid; -struct tdsRssiRid { - u16 len; - tdsRssiEntry x[256]; -} __packed; - -typedef struct MICRid MICRid; -struct MICRid { - __le16 len; - __le16 state; - __le16 multicastValid; - u8 multicast[16]; - __le16 unicastValid; - u8 unicast[16]; -} __packed; - -typedef struct MICBuffer MICBuffer; -struct MICBuffer { - __be16 typelen; - - union { - u8 snap[8]; - struct { - u8 dsap; - u8 ssap; - u8 control; - u8 orgcode[3]; - u8 fieldtype[2]; - } llc; - } u; - __be32 mic; - __be32 seq; -} __packed; - -typedef struct { - u8 da[ETH_ALEN]; - u8 sa[ETH_ALEN]; -} etherHead; - -#define TXCTL_TXOK (1<<1) /* report if tx is ok */ -#define TXCTL_TXEX (1<<2) /* report if tx fails */ -#define TXCTL_802_3 (0<<3) /* 802.3 packet */ -#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ -#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ -#define TXCTL_LLC (1<<4) /* payload is llc */ -#define TXCTL_RELEASE (0<<5) /* release after completion */ -#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ - -#define BUSY_FID 0x10000 - -#ifdef CISCO_EXT -#define AIROMAGIC 0xa55a -/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ -#ifdef SIOCIWFIRSTPRIV -#ifdef SIOCDEVPRIVATE -#define AIROOLDIOCTL SIOCDEVPRIVATE -#define AIROOLDIDIFC AIROOLDIOCTL + 1 -#endif /* SIOCDEVPRIVATE */ -#else /* SIOCIWFIRSTPRIV */ -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ -/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably - * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root - * only and don't return the modified struct ifreq to the application which - * is usually a problem. - Jean II */ -#define AIROIOCTL SIOCIWFIRSTPRIV -#define AIROIDIFC AIROIOCTL + 1 - -/* Ioctl constants to be used in airo_ioctl.command */ - -#define AIROGCAP 0 // Capability rid -#define AIROGCFG 1 // USED A LOT -#define AIROGSLIST 2 // System ID list -#define AIROGVLIST 3 // List of specified AP's -#define AIROGDRVNAM 4 // NOTUSED -#define AIROGEHTENC 5 // NOTUSED -#define AIROGWEPKTMP 6 -#define AIROGWEPKNV 7 -#define AIROGSTAT 8 -#define AIROGSTATSC32 9 -#define AIROGSTATSD32 10 -#define AIROGMICRID 11 -#define AIROGMICSTATS 12 -#define AIROGFLAGS 13 -#define AIROGID 14 -#define AIRORRID 15 -#define AIRORSWVERSION 17 - -/* Leave gap of 40 commands after AIROGSTATSD32 for future */ - -#define AIROPCAP AIROGSTATSD32 + 40 -#define AIROPVLIST AIROPCAP + 1 -#define AIROPSLIST AIROPVLIST + 1 -#define AIROPCFG AIROPSLIST + 1 -#define AIROPSIDS AIROPCFG + 1 -#define AIROPAPLIST AIROPSIDS + 1 -#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ -#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ -#define AIROPSTCLR AIROPMACOFF + 1 -#define AIROPWEPKEY AIROPSTCLR + 1 -#define AIROPWEPKEYNV AIROPWEPKEY + 1 -#define AIROPLEAPPWD AIROPWEPKEYNV + 1 -#define AIROPLEAPUSR AIROPLEAPPWD + 1 - -/* Flash codes */ - -#define AIROFLSHRST AIROPWEPKEYNV + 40 -#define AIROFLSHGCHR AIROFLSHRST + 1 -#define AIROFLSHSTFL AIROFLSHGCHR + 1 -#define AIROFLSHPCHR AIROFLSHSTFL + 1 -#define AIROFLPUTBUF AIROFLSHPCHR + 1 -#define AIRORESTART AIROFLPUTBUF + 1 - -#define FLASHSIZE 32768 -#define AUXMEMSIZE (256 * 1024) - -typedef struct aironet_ioctl { - unsigned short command; // What to do - unsigned short len; // Len of data - unsigned short ridnum; // rid number - unsigned char __user *data; // d-data -} aironet_ioctl; - -static const char swversion[] = "2.1"; -#endif /* CISCO_EXT */ - -#define NUM_MODULES 2 -#define MIC_MSGLEN_MAX 2400 -#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX -#define AIRO_DEF_MTU 2312 - -typedef struct { - u32 size; // size - u8 enabled; // MIC enabled or not - u32 rxSuccess; // successful packets received - u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison - u32 rxNotMICed; // pkts dropped due to not being MIC'd - u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed - u32 rxWrongSequence; // pkts dropped due to sequence number violation - u32 reserve[32]; -} mic_statistics; - -typedef struct { - __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; - u64 accum; // accumulated mic, reduced to u32 in final() - int position; // current position (byte offset) in message - union { - u8 d8[4]; - __be32 d32; - } part; // saves partial message word across update() calls -} emmh32_context; - -typedef struct { - emmh32_context seed; // Context - the seed - u32 rx; // Received sequence number - u32 tx; // Tx sequence number - u32 window; // Start of window - u8 valid; // Flag to say if context is valid or not - u8 key[16]; -} miccntx; - -typedef struct { - miccntx mCtx; // Multicast context - miccntx uCtx; // Unicast context -} mic_module; - -typedef struct { - unsigned int rid: 16; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} Rid; - -typedef struct { - unsigned int offset: 15; - unsigned int eoc: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} TxFid; - -struct rx_hdr { - __le16 status, len; - u8 rssi[2]; - u8 rate; - u8 freq; - __le16 tmp[4]; -} __packed; - -typedef struct { - unsigned int ctl: 15; - unsigned int rdy: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} RxFid; - -/* - * Host receive descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - RxFid rx_desc; /* card receive descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostRxDesc; - -/* - * Host transmit descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - TxFid tx_desc; /* card transmit descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostTxDesc; - -/* - * Host RID descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - descriptor */ - Rid rid_desc; /* card RID descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ -} HostRidDesc; - -typedef struct { - u16 sw0; - u16 sw1; - u16 status; - u16 len; -#define HOST_SET (1 << 0) -#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ -#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ -#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ -#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ -#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ -#define HOST_CLR_AID (1 << 7) /* clear AID failure */ -#define HOST_RTS (1 << 9) /* Force RTS use */ -#define HOST_SHORT (1 << 10) /* Do short preamble */ - u16 ctl; - u16 aid; - u16 retries; - u16 fill; -} TxCtlHdr; - -typedef struct { - u16 ctl; - u16 duration; - char addr1[6]; - char addr2[6]; - char addr3[6]; - u16 seq; - char addr4[6]; -} WifiHdr; - - -typedef struct { - TxCtlHdr ctlhdr; - u16 fill1; - u16 fill2; - WifiHdr wifihdr; - u16 gaplen; - u16 status; -} WifiCtlHdr; - -static WifiCtlHdr wifictlhdr8023 = { - .ctlhdr = { - .ctl = HOST_DONT_RLSE, - } -}; - -// A few details needed for WEP (Wireless Equivalent Privacy) -#define MAX_KEY_SIZE 13 // 128 (?) bits -#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP -typedef struct wep_key_t { - u16 len; - u8 key[16]; /* 40-bit and 104-bit keys */ -} wep_key_t; - -/* List of Wireless Handlers (new API) */ -static const struct iw_handler_def airo_handler_def; - -static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; - -struct airo_info; - -static int get_dec_u16(char *buffer, int *start, int limit); -static void OUT4500(struct airo_info *, u16 reg, u16 value); -static unsigned short IN4500(struct airo_info *, u16 reg); -static u16 setup_card(struct airo_info*, struct net_device *dev, int lock); -static int enable_MAC(struct airo_info *ai, int lock); -static void disable_MAC(struct airo_info *ai, int lock); -static void enable_interrupts(struct airo_info*); -static void disable_interrupts(struct airo_info*); -static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp, - bool may_sleep); -static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); -static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen, - int whichbap); -static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); -static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); -static int PC4500_writerid(struct airo_info*, u16 rid, const void - *pBuf, int len, int lock); -static int do_writerid(struct airo_info*, u16 rid, const void *rid_data, - int len, int dummy); -static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); -static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); -static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); - -static int mpi_send_packet(struct net_device *dev); -static void mpi_unmap_card(struct pci_dev *pci); -static void mpi_receive_802_3(struct airo_info *ai); -static void mpi_receive_802_11(struct airo_info *ai); -static int waitbusy(struct airo_info *ai); - -static irqreturn_t airo_interrupt(int irq, void* dev_id); -static int airo_thread(void *data); -static void timer_func(struct net_device *dev); -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd); -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev); -#ifdef CISCO_EXT -static int readrids(struct net_device *dev, aironet_ioctl *comp); -static int writerids(struct net_device *dev, aironet_ioctl *comp); -static int flashcard(struct net_device *dev, aironet_ioctl *comp); -#endif /* CISCO_EXT */ -static void micinit(struct airo_info *ai); -static int micsetup(struct airo_info *ai); -static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); - -static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi); -static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm); - -static void airo_networks_free(struct airo_info *ai); - -struct airo_info { - struct net_device *dev; - struct list_head dev_list; - /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we - use the high bit to mark whether it is in use. */ -#define MAX_FIDS 6 -#define MPI_MAX_FIDS 1 - u32 fids[MAX_FIDS]; - ConfigRid config; - char keyindex; // Used with auto wep - char defindex; // Used with auto wep - struct proc_dir_entry *proc_entry; - spinlock_t aux_lock; -#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ -#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ -#define FLAG_RADIO_MASK 0x03 -#define FLAG_ENABLED 2 -#define FLAG_ADHOC 3 /* Needed by MIC */ -#define FLAG_MIC_CAPABLE 4 -#define FLAG_UPDATE_MULTI 5 -#define FLAG_UPDATE_UNI 6 -#define FLAG_802_11 7 -#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ -#define FLAG_PENDING_XMIT 9 -#define FLAG_PENDING_XMIT11 10 -#define FLAG_MPI 11 -#define FLAG_REGISTERED 12 -#define FLAG_COMMIT 13 -#define FLAG_RESET 14 -#define FLAG_FLASHING 15 -#define FLAG_WPA_CAPABLE 16 - unsigned long flags; -#define JOB_DIE 0 -#define JOB_XMIT 1 -#define JOB_XMIT11 2 -#define JOB_STATS 3 -#define JOB_PROMISC 4 -#define JOB_MIC 5 -#define JOB_EVENT 6 -#define JOB_AUTOWEP 7 -#define JOB_SCAN_RESULTS 9 - unsigned long jobs; - int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); - unsigned short *flash; - tdsRssiEntry *rssi; - struct task_struct *list_bss_task; - struct task_struct *airo_thread_task; - struct semaphore sem; - wait_queue_head_t thr_wait; - unsigned long expires; - struct { - struct sk_buff *skb; - int fid; - } xmit, xmit11; - struct net_device *wifidev; - struct iw_statistics wstats; // wireless stats - unsigned long scan_timeout; /* Time scan should be read */ - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - /* MIC stuff */ - struct crypto_sync_skcipher *tfm; - mic_module mod[2]; - mic_statistics micstats; - HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors - HostTxDesc txfids[MPI_MAX_FIDS]; - HostRidDesc config_desc; - unsigned long ridbus; // phys addr of config_desc - struct sk_buff_head txq;// tx queue used by mpi350 code - struct pci_dev *pci; - unsigned char __iomem *pcimem; - unsigned char __iomem *pciaux; - unsigned char *shared; - dma_addr_t shared_dma; - pm_message_t power; - SsidRid *SSID; - APListRid APList; -#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE - char proc_name[IFNAMSIZ]; - - int wep_capable; - int max_wep_idx; - int last_auth; - - /* WPA-related stuff */ - unsigned int bssListFirst; - unsigned int bssListNext; - unsigned int bssListRidLen; - - struct list_head network_list; - struct list_head network_free_list; - BSSListElement *networks; -}; - -static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, - int whichbap) -{ - return ai->bap_read(ai, pu16Dst, bytelen, whichbap); -} - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv); -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv); - -static int cmdreset(struct airo_info *ai); -static int setflashmode(struct airo_info *ai); -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime); -static int flashputbuf(struct airo_info *ai); -static int flashrestart(struct airo_info *ai, struct net_device *dev); - -#define airo_print(type, name, fmt, args...) \ - printk(type DRV_NAME "(%s): " fmt "\n", name, ##args) - -#define airo_print_info(name, fmt, args...) \ - airo_print(KERN_INFO, name, fmt, ##args) - -#define airo_print_dbg(name, fmt, args...) \ - airo_print(KERN_DEBUG, name, fmt, ##args) - -#define airo_print_warn(name, fmt, args...) \ - airo_print(KERN_WARNING, name, fmt, ##args) - -#define airo_print_err(name, fmt, args...) \ - airo_print(KERN_ERR, name, fmt, ##args) - -#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) - -/*********************************************************************** - * MIC ROUTINES * - *********************************************************************** - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq); -static void MoveWindow(miccntx *context, u32 micSeq); -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm); -static void emmh32_init(emmh32_context *context); -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); -static void emmh32_final(emmh32_context *context, u8 digest[4]); -static int flashpchar(struct airo_info *ai, int byte, int dwelltime); - -static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len, - struct crypto_sync_skcipher *tfm) -{ - /* If the current MIC context is valid and its key is the same as - * the MIC register, there's nothing to do. - */ - if (cur->valid && (memcmp(cur->key, key, key_len) == 0)) - return; - - /* Age current mic Context */ - memcpy(old, cur, sizeof(*cur)); - - /* Initialize new context */ - memcpy(cur->key, key, key_len); - cur->window = 33; /* Window always points to the middle */ - cur->rx = 0; /* Rx Sequence numbers */ - cur->tx = 0; /* Tx sequence numbers */ - cur->valid = 1; /* Key is now valid */ - - /* Give key to mic seed */ - emmh32_setseed(&cur->seed, key, key_len, tfm); -} - -/* micinit - Initialize mic seed */ - -static void micinit(struct airo_info *ai) -{ - MICRid mic_rid; - - clear_bit(JOB_MIC, &ai->jobs); - PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); - up(&ai->sem); - - ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0; - if (!ai->micstats.enabled) { - /* So next time we have a valid key and mic is enabled, we will - * update the sequence number if the key is the same as before. - */ - ai->mod[0].uCtx.valid = 0; - ai->mod[0].mCtx.valid = 0; - return; - } - - if (mic_rid.multicastValid) { - age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx, - mic_rid.multicast, sizeof(mic_rid.multicast), - ai->tfm); - } - - if (mic_rid.unicastValid) { - age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx, - mic_rid.unicast, sizeof(mic_rid.unicast), - ai->tfm); - } -} - -/* micsetup - Get ready for business */ - -static int micsetup(struct airo_info *ai) -{ - int i; - - if (ai->tfm == NULL) - ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0); - - if (IS_ERR(ai->tfm)) { - airo_print_err(ai->dev->name, "failed to load transform for AES"); - ai->tfm = NULL; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - memset(&ai->mod[i].mCtx, 0, sizeof(miccntx)); - memset(&ai->mod[i].uCtx, 0, sizeof(miccntx)); - } - return SUCCESS; -} - -static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; - -/*=========================================================================== - * Description: Mic a packet - * - * Inputs: etherHead * pointer to an 802.3 frame - * - * Returns: BOOLEAN if successful, otherwise false. - * PacketTxLen will be updated with the mic'd packets size. - * - * Caveats: It is assumed that the frame buffer will already - * be big enough to hold the largets mic message possible. - * (No memory allocation is done here). - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - */ - -static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen) -{ - miccntx *context; - - // Determine correct context - // If not adhoc, always use unicast key - - if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1)) - context = &ai->mod[0].mCtx; - else - context = &ai->mod[0].uCtx; - - if (!context->valid) - return ERROR; - - mic->typelen = htons(payLen + 16); //Length of Mic'd packet - - memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap - - // Add Tx sequence - mic->seq = htonl(context->tx); - context->tx += 2; - - emmh32_init(&context->seed); // Mic the packet - emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA - emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap - emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ - emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload - emmh32_final(&context->seed, (u8*)&mic->mic); - - /* New Type/length ?????????? */ - mic->typelen = 0; //Let NIC know it could be an oversized packet - return SUCCESS; -} - -typedef enum { - NONE, - NOMIC, - NOMICPLUMMED, - SEQUENCE, - INCORRECTMIC, -} mic_error; - -/*=========================================================================== - * Description: Decapsulates a MIC'd packet and returns the 802.3 packet - * (removes the MIC stuff) if packet is a valid packet. - * - * Inputs: etherHead pointer to the 802.3 packet - * - * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen) -{ - int i; - u32 micSEQ; - miccntx *context; - u8 digest[4]; - mic_error micError = NONE; - - // Check if the packet is a Mic'd packet - - if (!ai->micstats.enabled) { - //No Mic set or Mic OFF but we received a MIC'd packet. - if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { - ai->micstats.rxMICPlummed++; - return ERROR; - } - return SUCCESS; - } - - if (ntohs(mic->typelen) == 0x888E) - return SUCCESS; - - if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { - // Mic enabled but packet isn't Mic'd - ai->micstats.rxMICPlummed++; - return ERROR; - } - - micSEQ = ntohl(mic->seq); //store SEQ as CPU order - - //At this point we a have a mic'd packet and mic is enabled - //Now do the mic error checking. - - //Receive seq must be odd - if ((micSEQ & 1) == 0) { - ai->micstats.rxWrongSequence++; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - int mcast = eth->da[0] & 1; - //Determine proper context - context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; - - //Make sure context is valid - if (!context->valid) { - if (i == 0) - micError = NOMICPLUMMED; - continue; - } - //DeMic it - - if (!mic->typelen) - mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); - - emmh32_init(&context->seed); - emmh32_update(&context->seed, eth->da, ETH_ALEN*2); - emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); - emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq)); - emmh32_update(&context->seed, (u8 *)(eth + 1), payLen); - //Calculate MIC - emmh32_final(&context->seed, digest); - - if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match - //Invalid Mic - if (i == 0) - micError = INCORRECTMIC; - continue; - } - - //Check Sequence number if mics pass - if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { - ai->micstats.rxSuccess++; - return SUCCESS; - } - if (i == 0) - micError = SEQUENCE; - } - - // Update statistics - switch (micError) { - case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; - case SEQUENCE: ai->micstats.rxWrongSequence++; break; - case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; - case NONE: break; - case NOMIC: break; - } - return ERROR; -} - -/*=========================================================================== - * Description: Checks the Rx Seq number to make sure it is valid - * and hasn't already been received - * - * Inputs: miccntx - mic context to check seq against - * micSeq - the Mic seq number - * - * Returns: TRUE if valid otherwise FALSE. - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq) -{ - u32 seq, index; - - //Allow for the ap being rebooted - if it is then use the next - //sequence number of the current sequence number - might go backwards - - if (mcast) { - if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { - clear_bit (FLAG_UPDATE_MULTI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; - context->rx = 0; // Reset rx - } - } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { - clear_bit (FLAG_UPDATE_UNI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; // Move window - context->rx = 0; // Reset rx - } - - //Make sequence number relative to START of window - seq = micSeq - (context->window - 33); - - //Too old of a SEQ number to check. - if ((s32)seq < 0) - return ERROR; - - if (seq > 64) { - //Window is infinite forward - MoveWindow(context, micSeq); - return SUCCESS; - } - - // We are in the window. Now check the context rx bit to see if it was already sent - seq >>= 1; //divide by 2 because we only have odd numbers - index = 1 << seq; //Get an index number - - if (!(context->rx & index)) { - //micSEQ falls inside the window. - //Add seqence number to the list of received numbers. - context->rx |= index; - - MoveWindow(context, micSeq); - - return SUCCESS; - } - return ERROR; -} - -static void MoveWindow(miccntx *context, u32 micSeq) -{ - u32 shift; - - //Move window if seq greater than the middle of the window - if (micSeq > context->window) { - shift = (micSeq - context->window) >> 1; - - //Shift out old - if (shift < 32) - context->rx >>= shift; - else - context->rx = 0; - - context->window = micSeq; //Move window - } -} - -/*==============================================*/ -/*========== EMMH ROUTINES ====================*/ -/*==============================================*/ - -/* mic accumulate */ -#define MIC_ACCUM(val) \ - context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]); - -/* expand the key to fill the MMH coefficient array */ -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm) -{ - /* take the keying material, expand if necessary, truncate at 16-bytes */ - /* run through AES counter mode to generate context->coeff[] */ - - SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - struct scatterlist sg; - u8 iv[AES_BLOCK_SIZE] = {}; - int ret; - - crypto_sync_skcipher_setkey(tfm, pkey, 16); - - memset(context->coeff, 0, sizeof(context->coeff)); - sg_init_one(&sg, context->coeff, sizeof(context->coeff)); - - skcipher_request_set_sync_tfm(req, tfm); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv); - - ret = crypto_skcipher_encrypt(req); - WARN_ON_ONCE(ret); -} - -/* prepare for calculation of a new mic */ -static void emmh32_init(emmh32_context *context) -{ - /* prepare for new mic calculation */ - context->accum = 0; - context->position = 0; -} - -/* add some bytes to the mic calculation */ -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) -{ - int coeff_position, byte_position; - - if (len == 0) return; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - do { - if (len == 0) return; - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } while (byte_position < 4); - MIC_ACCUM(ntohl(context->part.d32)); - } - - /* deal with full 32-bit words */ - while (len >= 4) { - MIC_ACCUM(ntohl(*(__be32 *)pOctets)); - context->position += 4; - pOctets += 4; - len -= 4; - } - - /* deal with partial 32-bit word that will be left over from this update */ - byte_position = 0; - while (len > 0) { - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } -} - -/* mask used to zero empty bytes for final partial word */ -static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; - -/* calculate the mic */ -static void emmh32_final(emmh32_context *context, u8 digest[4]) -{ - int coeff_position, byte_position; - u32 val; - - u64 sum, utmp; - s64 stmp; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - val = ntohl(context->part.d32); - MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ - } - - /* reduce the accumulated u64 to a 32-bit MIC */ - sum = context->accum; - stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); - utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); - sum = utmp & 0xffffffffLL; - if (utmp > 0x10000000fLL) - sum -= 15; - - val = (u32)sum; - digest[0] = (val>>24) & 0xFF; - digest[1] = (val>>16) & 0xFF; - digest[2] = (val>>8) & 0xFF; - digest[3] = val & 0xFF; -} - -static int readBSSListRid(struct airo_info *ai, int first, - BSSListRid *list) -{ - Cmd cmd; - Resp rsp; - - if (first == 1) { - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - ai->list_bss_task = current; - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - /* Let the command take effect */ - schedule_timeout_uninterruptible(3 * HZ); - ai->list_bss_task = NULL; - } - return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, - list, ai->bssListRidLen, 1); -} - -static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock) -{ - return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, - wkr, sizeof(*wkr), lock); -} - -static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock) -{ - int rc; - rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); - if (perm) { - rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); - } - return rc; -} - -static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) -{ - return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); -} - -static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) -{ - return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock); -} - -static int readConfigRid(struct airo_info *ai, int lock) -{ - int rc; - ConfigRid cfg; - - if (ai->config.len) - return SUCCESS; - - rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); - if (rc != SUCCESS) - return rc; - - ai->config = cfg; - return SUCCESS; -} - -static inline void checkThrottle(struct airo_info *ai) -{ - int i; -/* Old hardware had a limit on encryption speed */ - if (ai->config.authType != AUTH_OPEN && maxencrypt) { - for (i = 0; i<8; i++) { - if (ai->config.rates[i] > maxencrypt) { - ai->config.rates[i] = 0; - } - } - } -} - -static int writeConfigRid(struct airo_info *ai, int lock) -{ - ConfigRid cfgr; - - if (!test_bit (FLAG_COMMIT, &ai->flags)) - return SUCCESS; - - clear_bit (FLAG_COMMIT, &ai->flags); - clear_bit (FLAG_RESET, &ai->flags); - checkThrottle(ai); - cfgr = ai->config; - - if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit(FLAG_ADHOC, &ai->flags); - else - clear_bit(FLAG_ADHOC, &ai->flags); - - return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); -} - -static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock) -{ - return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); -} - -static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock) -{ - return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); -} - -static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock) -{ - return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); -} - -static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) -{ - return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); -} - -static void try_auto_wep(struct airo_info *ai) -{ - if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } -} - -static int airo_open(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - int rc = 0; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - /* Make sure the card is configured. - * Wireless Extensions may postpone config changes until the card - * is open (to pipeline changes and speed-up card setup). If - * those changes are not yet committed, do it now - Jean II */ - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC(ai, 1); - writeConfigRid(ai, 1); - } - - if (ai->wifidev != dev) { - clear_bit(JOB_DIE, &ai->jobs); - ai->airo_thread_task = kthread_run(airo_thread, dev, "%s", - dev->name); - if (IS_ERR(ai->airo_thread_task)) - return (int)PTR_ERR(ai->airo_thread_task); - - rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED, - dev->name, dev); - if (rc) { - airo_print_err(dev->name, - "register interrupt %d failed, rc %d", - dev->irq, rc); - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - return rc; - } - - /* Power on the MAC controller (which may have been disabled) */ - clear_bit(FLAG_RADIO_DOWN, &ai->flags); - enable_interrupts(ai); - - try_auto_wep(ai); - } - enable_MAC(ai, 1); - - netif_start_queue(dev); - return 0; -} - -static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int npacks, pending; - unsigned long flags; - struct airo_info *ai = dev->ml_priv; - - if (!skb) { - airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - npacks = skb_queue_len (&ai->txq); - - if (npacks >= MAXTXQ - 1) { - netif_stop_queue (dev); - if (npacks > MAXTXQ) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - skb_queue_tail (&ai->txq, skb); - return NETDEV_TX_OK; - } - - spin_lock_irqsave(&ai->aux_lock, flags); - skb_queue_tail (&ai->txq, skb); - pending = test_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue (dev); - - if (pending == 0) { - set_bit(FLAG_PENDING_XMIT, &ai->flags); - mpi_send_packet (dev); - } - return NETDEV_TX_OK; -} - -/* - * @mpi_send_packet - * - * Attempt to transmit a packet. Can be called from interrupt - * or transmit . return number of packets we tried to send - */ - -static int mpi_send_packet (struct net_device *dev) -{ - struct sk_buff *skb; - unsigned char *buffer; - s16 len; - __le16 *payloadLen; - struct airo_info *ai = dev->ml_priv; - u8 *sendbuf; - - /* get a packet to send */ - - if ((skb = skb_dequeue(&ai->txq)) == NULL) { - airo_print_err(dev->name, - "%s: Dequeue'd zero in send_packet()", - __func__); - return 0; - } - - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buffer = skb->data; - - ai->txfids[0].tx_desc.offset = 0; - ai->txfids[0].tx_desc.valid = 1; - ai->txfids[0].tx_desc.eoc = 1; - ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - -/* - * Magic, the cards firmware needs a length count (2 bytes) in the host buffer - * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen - * is immediately after it. ------------------------------------------------ - * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| - * ------------------------------------------------ - */ - - memcpy(ai->txfids[0].virtual_host_addr, - (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); - - payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023)); - sendbuf = ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023) + 2 ; - - /* - * Firmware automatically puts 802 header on so - * we don't need to account for it in the length - */ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)buffer)[6]) != 0x888E)) { - MICBuffer pMic; - - if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) - return ERROR; - - *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); - ai->txfids[0].tx_desc.len += sizeof(pMic); - /* copy data into airo dma buffer */ - memcpy (sendbuf, buffer, sizeof(etherHead)); - buffer += sizeof(etherHead); - sendbuf += sizeof(etherHead); - memcpy (sendbuf, &pMic, sizeof(pMic)); - sendbuf += sizeof(pMic); - memcpy (sendbuf, buffer, len - sizeof(etherHead)); - } else { - *payloadLen = cpu_to_le16(len - sizeof(etherHead)); - - netif_trans_update(dev); - - /* copy data into airo dma buffer */ - memcpy(sendbuf, buffer, len); - } - - memcpy_toio(ai->txfids[0].card_ram_off, - &ai->txfids[0].tx_desc, sizeof(TxFid)); - - OUT4500(ai, EVACK, 8); - - dev_kfree_skb_any(skb); - return 1; -} - -static void get_tx_error(struct airo_info *ai, s32 fid) -{ - __le16 status; - - if (fid < 0) - status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; - else { - if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS) - return; - bap_read(ai, &status, 2, BAP0); - } - if (le16_to_cpu(status) & 2) /* Too many retries */ - ai->dev->stats.tx_aborted_errors++; - if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ - ai->dev->stats.tx_heartbeat_errors++; - if (le16_to_cpu(status) & 8) /* Aid fail */ - { } - if (le16_to_cpu(status) & 0x10) /* MAC disabled */ - ai->dev->stats.tx_carrier_errors++; - if (le16_to_cpu(status) & 0x20) /* Association lost */ - { } - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if ((le16_to_cpu(status) & 2) || - (le16_to_cpu(status) & 4)) { - union iwreq_data wrqu; - char junk[0x18]; - - /* Faster to skip over useless data than to do - * another bap_setup(). We are at offset 0x6 and - * need to go to 0x18 and read 6 bytes - Jean II */ - bap_read(ai, (__le16 *) junk, 0x18, BAP0); - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); - } -} - -static void airo_end_xmit(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit.skb; - int fid = priv->xmit.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT, &priv->flags); - status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = 0; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS / 2) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS / 2) { - netif_stop_queue(dev); - - if (i == MAX_FIDS / 2) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit.skb = skb; - priv->xmit.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit(dev, false); - return NETDEV_TX_OK; -} - -static void airo_end_xmit11(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit11.skb; - int fid = priv->xmit11.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT11, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT11, &priv->flags); - status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = MAX_FIDS / 2; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (test_bit(FLAG_MPI, &priv->flags)) { - /* Not implemented yet for MPI350 */ - netif_stop_queue(dev); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS) { - netif_stop_queue(dev); - - if (i == MAX_FIDS) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit11.skb = skb; - priv->xmit11.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT11, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT11, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit11(dev, false); - return NETDEV_TX_OK; -} - -static void airo_read_stats(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - StatsRid stats_rid; - __le32 *vals = stats_rid.vals; - - clear_bit(JOB_STATS, &ai->jobs); - if (ai->power.event) { - up(&ai->sem); - return; - } - readStatsRid(ai, &stats_rid, RID_STATS, 0); - up(&ai->sem); - - dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + - le32_to_cpu(vals[45]); - dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + - le32_to_cpu(vals[41]); - dev->stats.rx_bytes = le32_to_cpu(vals[92]); - dev->stats.tx_bytes = le32_to_cpu(vals[91]); - dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + - le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); - dev->stats.tx_errors = le32_to_cpu(vals[42]) + - dev->stats.tx_fifo_errors; - dev->stats.multicast = le32_to_cpu(vals[43]); - dev->stats.collisions = le32_to_cpu(vals[89]); - - /* detailed rx_errors: */ - dev->stats.rx_length_errors = le32_to_cpu(vals[3]); - dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); - dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); - dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); -} - -static struct net_device_stats *airo_get_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit(JOB_STATS, &local->jobs)) { - set_bit(JOB_STATS, &local->jobs); - wake_up_interruptible(&local->thr_wait); - } - - return &dev->stats; -} - -static void airo_set_promisc(struct airo_info *ai, bool may_sleep) -{ - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_SETMODE; - clear_bit(JOB_PROMISC, &ai->jobs); - cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; - issuecommand(ai, &cmd, &rsp, may_sleep); - up(&ai->sem); -} - -static void airo_set_multicast_list(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - if ((dev->flags ^ ai->flags) & IFF_PROMISC) { - change_bit(FLAG_PROMISC, &ai->flags); - if (down_trylock(&ai->sem) != 0) { - set_bit(JOB_PROMISC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } else - airo_set_promisc(ai, false); - } - - if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { - /* Turn on multicast. (Should be already setup...) */ - } -} - -static int airo_set_mac_address(struct net_device *dev, void *p) -{ - struct airo_info *ai = dev->ml_priv; - struct sockaddr *addr = p; - - readConfigRid(ai, 1); - memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); - set_bit (FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - dev_addr_set(ai->dev, addr->sa_data); - if (ai->wifidev) - dev_addr_set(ai->wifidev, addr->sa_data); - return 0; -} - -static LIST_HEAD(airo_devices); - -static void add_airo_dev(struct airo_info *ai) -{ - /* Upper layers already keep track of PCI devices, - * so we only need to remember our non-PCI cards. */ - if (!ai->pci) - list_add_tail(&ai->dev_list, &airo_devices); -} - -static void del_airo_dev(struct airo_info *ai) -{ - if (!ai->pci) - list_del(&ai->dev_list); -} - -static int airo_close(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - netif_stop_queue(dev); - - if (ai->wifidev != dev) { -#ifdef POWER_ON_DOWN - /* Shut power to the card. The idea is that the user can save - * power when he doesn't need the card with "ifconfig down". - * That's the method that is most friendly towards the network - * stack (i.e. the network stack won't try to broadcast - * anything on the interface and routes are gone. Jean II */ - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); -#endif - disable_interrupts(ai); - - free_irq(dev->irq, dev); - - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - } - return 0; -} - -void stop_airo_card(struct net_device *dev, int freeres) -{ - struct airo_info *ai = dev->ml_priv; - - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); - disable_interrupts(ai); - takedown_proc_entry(dev, ai); - if (test_bit(FLAG_REGISTERED, &ai->flags)) { - unregister_netdev(dev); - if (ai->wifidev) { - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); - ai->wifidev = NULL; - } - clear_bit(FLAG_REGISTERED, &ai->flags); - } - /* - * Clean out tx queue - */ - if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { - struct sk_buff *skb = NULL; - for (;(skb = skb_dequeue(&ai->txq));) - dev_kfree_skb(skb); - } - - airo_networks_free (ai); - - kfree(ai->flash); - kfree(ai->rssi); - kfree(ai->SSID); - if (freeres) { - /* PCMCIA frees this stuff, so only for PCI and ISA */ - release_region(dev->base_addr, 64); - if (test_bit(FLAG_MPI, &ai->flags)) { - if (ai->pci) - mpi_unmap_card(ai->pci); - if (ai->pcimem) - iounmap(ai->pcimem); - if (ai->pciaux) - iounmap(ai->pciaux); - dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN, - ai->shared, ai->shared_dma); - } - } - crypto_free_sync_skcipher(ai->tfm); - del_airo_dev(ai); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_airo_card); - -static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); - return ETH_ALEN; -} - -static void mpi_unmap_card(struct pci_dev *pci) -{ - unsigned long mem_start = pci_resource_start(pci, 1); - unsigned long mem_len = pci_resource_len(pci, 1); - unsigned long aux_start = pci_resource_start(pci, 2); - unsigned long aux_len = AUXMEMSIZE; - - release_mem_region(aux_start, aux_len); - release_mem_region(mem_start, mem_len); -} - -/************************************************************* - * This routine assumes that descriptors have been setup . - * Run at insmod time or after reset when the descriptors - * have been initialized . Returns 0 if all is well nz - * otherwise . Does not allocate memory but sets up card - * using previously allocated descriptors. - */ -static int mpi_init_descriptors (struct airo_info *ai) -{ - Cmd cmd; - Resp rsp; - int i; - int rc = SUCCESS; - - /* Alloc card RX descriptors */ - netif_stop_queue(ai->dev); - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_RX; - cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); - return rc; - } - - for (i = 0; irxfids[i].card_ram_off, - &ai->rxfids[i].rx_desc, sizeof(RxFid)); - } - - /* Alloc card TX descriptors */ - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_TX; - cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - - for (i = 0; itxfids[i].tx_desc.valid = 1; - memcpy_toio(ai->txfids[i].card_ram_off, - &ai->txfids[i].tx_desc, sizeof(TxFid)); - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); - return rc; - } - - /* Alloc card Rid descriptor */ - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = RID_RW; - cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux); - cmd.parm2 = 1; /* Magic number... */ - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RID"); - return rc; - } - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - return rc; -} - -/* - * We are setting up three things here: - * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. - * 2) Map PCI memory for issuing commands. - * 3) Allocate memory (shared) to send and receive ethernet frames. - */ -static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) -{ - unsigned long mem_start, mem_len, aux_start, aux_len; - int rc = -1; - int i; - dma_addr_t busaddroff; - unsigned char *vpackoff; - unsigned char __iomem *pciaddroff; - - mem_start = pci_resource_start(pci, 1); - mem_len = pci_resource_len(pci, 1); - aux_start = pci_resource_start(pci, 2); - aux_len = AUXMEMSIZE; - - if (!request_mem_region(mem_start, mem_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)mem_start, (int)mem_len); - goto out; - } - if (!request_mem_region(aux_start, aux_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_region1; - } - - ai->pcimem = ioremap(mem_start, mem_len); - if (!ai->pcimem) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)mem_start, (int)mem_len); - goto free_region2; - } - ai->pciaux = ioremap(aux_start, aux_len); - if (!ai->pciaux) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_memmap; - } - - /* Reserve PKTSIZE for each fid and 2K for the Rids */ - ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN, - &ai->shared_dma, GFP_KERNEL); - if (!ai->shared) { - airo_print_err("", "Couldn't alloc_coherent %d", - PCI_SHARED_LEN); - goto free_auxmap; - } - - /* - * Setup descriptor RX, TX, CONFIG - */ - busaddroff = ai->shared_dma; - pciaddroff = ai->pciaux + AUX_OFFSET; - vpackoff = ai->shared; - - /* RX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->rxfids[i].pending = 0; - ai->rxfids[i].card_ram_off = pciaddroff; - ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = busaddroff; - ai->rxfids[i].rx_desc.valid = 1; - ai->rxfids[i].rx_desc.len = PKTSIZE; - ai->rxfids[i].rx_desc.rdy = 0; - - pciaddroff += sizeof(RxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - - /* TX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->txfids[i].card_ram_off = pciaddroff; - ai->txfids[i].virtual_host_addr = vpackoff; - ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = busaddroff; - memcpy(ai->txfids[i].virtual_host_addr, - &wifictlhdr8023, sizeof(wifictlhdr8023)); - - pciaddroff += sizeof(TxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - /* Rid descriptor setup */ - ai->config_desc.card_ram_off = pciaddroff; - ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = busaddroff; - ai->ridbus = busaddroff; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.valid = 1; - pciaddroff += sizeof(Rid); - busaddroff += RIDSIZE; - vpackoff += RIDSIZE; - - /* Tell card about descriptors */ - if (mpi_init_descriptors (ai) != SUCCESS) - goto free_shared; - - return 0; - free_shared: - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - free_auxmap: - iounmap(ai->pciaux); - free_memmap: - iounmap(ai->pcimem); - free_region2: - release_mem_region(aux_start, aux_len); - free_region1: - release_mem_region(mem_start, mem_len); - out: - return rc; -} - -static const struct header_ops airo_header_ops = { - .parse = wll_header_parse, -}; - -static const struct net_device_ops airo11_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit11, - .ndo_get_stats = airo_get_stats, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, -}; - -static void wifi_setup(struct net_device *dev) -{ - dev->netdev_ops = &airo11_netdev_ops; - dev->header_ops = &airo_header_ops; - dev->wireless_handlers = &airo_handler_def; - - dev->type = ARPHRD_IEEE80211; - dev->hard_header_len = ETH_HLEN; - dev->mtu = AIRO_DEF_MTU; - dev->min_mtu = 68; - dev->max_mtu = MIC_MSGLEN_MAX; - dev->addr_len = ETH_ALEN; - dev->tx_queue_len = 100; - - eth_broadcast_addr(dev->broadcast); - - dev->flags = IFF_BROADCAST|IFF_MULTICAST; -} - -static struct net_device *init_wifidev(struct airo_info *ai, - struct net_device *ethdev) -{ - int err; - struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN, - wifi_setup); - if (!dev) - return NULL; - dev->ml_priv = ethdev->ml_priv; - dev->irq = ethdev->irq; - dev->base_addr = ethdev->base_addr; - dev->wireless_data = ethdev->wireless_data; - SET_NETDEV_DEV(dev, ethdev->dev.parent); - eth_hw_addr_inherit(dev, ethdev); - err = register_netdev(dev); - if (err<0) { - free_netdev(dev); - return NULL; - } - return dev; -} - -static int reset_card(struct net_device *dev, int lock) -{ - struct airo_info *ai = dev->ml_priv; - - if (lock && down_interruptible(&ai->sem)) - return -1; - waitbusy (ai); - OUT4500(ai, COMMAND, CMD_SOFTRESET); - msleep(200); - waitbusy (ai); - msleep(200); - if (lock) - up(&ai->sem); - return 0; -} - -#define AIRO_MAX_NETWORK_COUNT 64 -static int airo_networks_allocate(struct airo_info *ai) -{ - if (ai->networks) - return 0; - - ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement), - GFP_KERNEL); - if (!ai->networks) { - airo_print_warn("", "Out of memory allocating beacons"); - return -ENOMEM; - } - - return 0; -} - -static void airo_networks_free(struct airo_info *ai) -{ - kfree(ai->networks); - ai->networks = NULL; -} - -static void airo_networks_initialize(struct airo_info *ai) -{ - int i; - - INIT_LIST_HEAD(&ai->network_free_list); - INIT_LIST_HEAD(&ai->network_list); - for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++) - list_add_tail(&ai->networks[i].list, - &ai->network_free_list); -} - -static const struct net_device_ops airo_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops mpi_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = mpi_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - - -static struct net_device *_init_airo_card(unsigned short irq, int port, - int is_pcmcia, struct pci_dev *pci, - struct device *dmdev) -{ - struct net_device *dev; - struct airo_info *ai; - int i, rc; - CapabilityRid cap_rid; - - /* Create the network device object. */ - dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup); - if (!dev) { - airo_print_err("", "Couldn't alloc_etherdev"); - return NULL; - } - - ai = dev->ml_priv = netdev_priv(dev); - ai->wifidev = NULL; - ai->flags = 1 << FLAG_RADIO_DOWN; - ai->jobs = 0; - ai->dev = dev; - if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - airo_print_dbg("", "Found an MPI350 card"); - set_bit(FLAG_MPI, &ai->flags); - } - spin_lock_init(&ai->aux_lock); - sema_init(&ai->sem, 1); - ai->config.len = 0; - ai->pci = pci; - init_waitqueue_head (&ai->thr_wait); - ai->tfm = NULL; - add_airo_dev(ai); - ai->APList.len = cpu_to_le16(sizeof(struct APListRid)); - - if (airo_networks_allocate (ai)) - goto err_out_free; - airo_networks_initialize (ai); - - skb_queue_head_init (&ai->txq); - - /* The Airo-specific entries in the device structure. */ - if (test_bit(FLAG_MPI,&ai->flags)) - dev->netdev_ops = &mpi_netdev_ops; - else - dev->netdev_ops = &airo_netdev_ops; - dev->wireless_handlers = &airo_handler_def; - ai->wireless_data.spy_data = &ai->spy_data; - dev->wireless_data = &ai->wireless_data; - dev->irq = irq; - dev->base_addr = port; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->max_mtu = MIC_MSGLEN_MAX; - - SET_NETDEV_DEV(dev, dmdev); - - reset_card (dev, 1); - msleep(400); - - if (!is_pcmcia) { - if (!request_region(dev->base_addr, 64, DRV_NAME)) { - rc = -EBUSY; - airo_print_err(dev->name, "Couldn't request region"); - goto err_out_nets; - } - } - - if (test_bit(FLAG_MPI,&ai->flags)) { - if (mpi_map_card(ai, pci)) { - airo_print_err("", "Could not map memory"); - goto err_out_res; - } - } - - if (probe) { - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - rc = -EIO; - goto err_out_map; - } - } else if (!test_bit(FLAG_MPI,&ai->flags)) { - ai->bap_read = fast_bap_read; - set_bit(FLAG_FLASHING, &ai->flags); - } - - strcpy(dev->name, "eth%d"); - rc = register_netdev(dev); - if (rc) { - airo_print_err(dev->name, "Couldn't register_netdev"); - goto err_out_map; - } - ai->wifidev = init_wifidev(ai, dev); - if (!ai->wifidev) - goto err_out_reg; - - rc = readCapabilityRid(ai, &cap_rid, 1); - if (rc != SUCCESS) { - rc = -EIO; - goto err_out_wifi; - } - /* WEP capability discovery */ - ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0; - ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0; - - airo_print_info(dev->name, "Firmware version %x.%x.%02d", - ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF), - (le16_to_cpu(cap_rid.softVer) & 0xFF), - le16_to_cpu(cap_rid.softSubVer)); - - /* Test for WPA support */ - /* Only firmware versions 5.30.17 or better can do WPA */ - if (le16_to_cpu(cap_rid.softVer) > 0x530 - || (le16_to_cpu(cap_rid.softVer) == 0x530 - && le16_to_cpu(cap_rid.softSubVer) >= 17)) { - airo_print_info(ai->dev->name, "WPA supported."); - - set_bit(FLAG_WPA_CAPABLE, &ai->flags); - ai->bssListFirst = RID_WPA_BSSLISTFIRST; - ai->bssListNext = RID_WPA_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid); - } else { - airo_print_info(ai->dev->name, "WPA unsupported with firmware " - "versions older than 5.30.17."); - - ai->bssListFirst = RID_BSSLISTFIRST; - ai->bssListNext = RID_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); - } - - set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - - /* Allocate the transmit buffers */ - if (probe && !test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - if (setup_proc_entry(dev, dev->ml_priv) < 0) - goto err_out_wifi; - - return dev; - -err_out_wifi: - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); -err_out_reg: - unregister_netdev(dev); -err_out_map: - if (test_bit(FLAG_MPI,&ai->flags) && pci) { - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - iounmap(ai->pciaux); - iounmap(ai->pcimem); - mpi_unmap_card(ai->pci); - } -err_out_res: - if (!is_pcmcia) - release_region(dev->base_addr, 64); -err_out_nets: - airo_networks_free(ai); -err_out_free: - del_airo_dev(ai); - free_netdev(dev); - return NULL; -} - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev) -{ - return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev); -} - -EXPORT_SYMBOL(init_airo_card); - -static int waitbusy (struct airo_info *ai) -{ - int delay = 0; - while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { - udelay (10); - if ((++delay % 20) == 0) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - return delay < 10000; -} - -int reset_airo_card(struct net_device *dev) -{ - int i; - struct airo_info *ai = dev->ml_priv; - - if (reset_card (dev, 1)) - return -1; - - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - return -1; - } - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - /* Allocate the transmit buffers if needed */ - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - enable_interrupts(ai); - netif_wake_queue(dev); - return 0; -} - -EXPORT_SYMBOL(reset_airo_card); - -static void airo_send_event(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - union iwreq_data wrqu; - StatusRid status_rid; - - clear_bit(JOB_EVENT, &ai->jobs); - PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); - up(&ai->sem); - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void airo_process_scan_results (struct airo_info *ai) -{ - union iwreq_data wrqu; - BSSListRid bss; - int rc; - BSSListElement * loop_net; - BSSListElement * tmp_net; - - /* Blow away current list of scan results */ - list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { - list_move_tail (&loop_net->list, &ai->network_free_list); - /* Don't blow away ->list, just BSS data */ - memset (loop_net, 0, sizeof (loop_net->bss)); - } - - /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0); - if ((rc) || (bss.index == cpu_to_le16(0xffff))) { - /* No scan results */ - goto out; - } - - /* Read and parse all entries */ - tmp_net = NULL; - while ((!rc) && (bss.index != cpu_to_le16(0xffff))) { - /* Grab a network off the free list */ - if (!list_empty(&ai->network_free_list)) { - tmp_net = list_entry(ai->network_free_list.next, - BSSListElement, list); - list_del(ai->network_free_list.next); - } - - if (tmp_net != NULL) { - memcpy(tmp_net, &bss, sizeof(tmp_net->bss)); - list_add_tail(&tmp_net->list, &ai->network_list); - tmp_net = NULL; - } - - /* Read next entry */ - rc = PC4500_readrid(ai, ai->bssListNext, - &bss, ai->bssListRidLen, 0); - } - -out: - /* write APList back (we cleared it in airo_set_scan) */ - disable_MAC(ai, 2); - writeAPListRid(ai, &ai->APList, 0); - enable_MAC(ai, 0); - - ai->scan_timeout = 0; - clear_bit(JOB_SCAN_RESULTS, &ai->jobs); - up(&ai->sem); - - /* Send an empty event to user space. - * We don't send the received data on - * the event because it would require - * us to do complex transcoding, and - * we want to minimise the work done in - * the irq handler. Use a request to - * extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static int airo_thread(void *data) -{ - struct net_device *dev = data; - struct airo_info *ai = dev->ml_priv; - int locked; - - set_freezable(); - while (1) { - /* make swsusp happy with our thread */ - try_to_freeze(); - - if (test_bit(JOB_DIE, &ai->jobs)) - break; - - if (ai->jobs) { - locked = down_interruptible(&ai->sem); - } else { - wait_queue_entry_t wait; - - init_waitqueue_entry(&wait, current); - add_wait_queue(&ai->thr_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ai->jobs) - break; - if (ai->expires || ai->scan_timeout) { - if (ai->scan_timeout && - time_after_eq(jiffies, ai->scan_timeout)) { - set_bit(JOB_SCAN_RESULTS, &ai->jobs); - break; - } else if (ai->expires && - time_after_eq(jiffies, ai->expires)) { - set_bit(JOB_AUTOWEP, &ai->jobs); - break; - } - if (!kthread_should_stop() && - !freezing(current)) { - unsigned long wake_at; - if (!ai->expires || !ai->scan_timeout) { - wake_at = max(ai->expires, - ai->scan_timeout); - } else { - wake_at = min(ai->expires, - ai->scan_timeout); - } - schedule_timeout(wake_at - jiffies); - continue; - } - } else if (!kthread_should_stop() && - !freezing(current)) { - schedule(); - continue; - } - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&ai->thr_wait, &wait); - locked = 1; - } - - if (locked) - continue; - - if (test_bit(JOB_DIE, &ai->jobs)) { - up(&ai->sem); - break; - } - - if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) { - up(&ai->sem); - continue; - } - - if (test_bit(JOB_XMIT, &ai->jobs)) - airo_end_xmit(dev, true); - else if (test_bit(JOB_XMIT11, &ai->jobs)) - airo_end_xmit11(dev, true); - else if (test_bit(JOB_STATS, &ai->jobs)) - airo_read_stats(dev); - else if (test_bit(JOB_PROMISC, &ai->jobs)) - airo_set_promisc(ai, true); - else if (test_bit(JOB_MIC, &ai->jobs)) - micinit(ai); - else if (test_bit(JOB_EVENT, &ai->jobs)) - airo_send_event(dev); - else if (test_bit(JOB_AUTOWEP, &ai->jobs)) - timer_func(dev); - else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs)) - airo_process_scan_results(ai); - else /* Shouldn't get here, but we make sure to unlock */ - up(&ai->sem); - } - - return 0; -} - -static int header_len(__le16 ctl) -{ - u16 fc = le16_to_cpu(ctl); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - return 10; /* one-address control packet */ - return 16; /* two-address control packet */ - case 8: - if ((fc & 0x300) == 0x300) - return 30; /* WDS packet */ - } - return 24; -} - -static void airo_handle_cisco_mic(struct airo_info *ai) -{ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) { - set_bit(JOB_MIC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } -} - -/* Airo Status codes */ -#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */ -#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */ -#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ -#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */ -#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ -#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */ -#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */ -#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */ -#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */ -#define STAT_ASSOC 0x0400 /* Associated */ -#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ - -static void airo_print_status(const char *devname, u16 status) -{ - u8 reason = status & 0xFF; - - switch (status & 0xFF00) { - case STAT_NOBEACON: - switch (status) { - case STAT_NOBEACON: - airo_print_dbg(devname, "link lost (missed beacons)"); - break; - case STAT_MAXRETRIES: - case STAT_MAXARL: - airo_print_dbg(devname, "link lost (max retries)"); - break; - case STAT_FORCELOSS: - airo_print_dbg(devname, "link lost (local choice)"); - break; - case STAT_TSFSYNC: - airo_print_dbg(devname, "link lost (TSF sync lost)"); - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } - break; - case STAT_DEAUTH: - airo_print_dbg(devname, "deauthenticated (reason: %d)", reason); - break; - case STAT_DISASSOC: - airo_print_dbg(devname, "disassociated (reason: %d)", reason); - break; - case STAT_ASSOC_FAIL: - airo_print_dbg(devname, "association failed (reason: %d)", - reason); - break; - case STAT_AUTH_FAIL: - airo_print_dbg(devname, "authentication failed (reason: %d)", - reason); - break; - case STAT_ASSOC: - case STAT_REASSOC: - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } -} - -static void airo_handle_link(struct airo_info *ai) -{ - union iwreq_data wrqu; - int scan_forceloss = 0; - u16 status; - - /* Get new status and acknowledge the link change */ - status = le16_to_cpu(IN4500(ai, LINKSTAT)); - OUT4500(ai, EVACK, EV_LINK); - - if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0)) - scan_forceloss = 1; - - airo_print_status(ai->dev->name, status); - - if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) { - if (auto_wep) - ai->expires = 0; - if (ai->list_bss_task) - wake_up_process(ai->list_bss_task); - set_bit(FLAG_UPDATE_UNI, &ai->flags); - set_bit(FLAG_UPDATE_MULTI, &ai->flags); - - set_bit(JOB_EVENT, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - - netif_carrier_on(ai->dev); - } else if (!scan_forceloss) { - if (auto_wep && !ai->expires) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } - - /* Send event to user space */ - eth_zero_addr(wrqu.ap_addr.sa_data); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL); - netif_carrier_off(ai->dev); - } else { - netif_carrier_off(ai->dev); - } -} - -static void airo_handle_rx(struct airo_info *ai) -{ - struct sk_buff *skb = NULL; - __le16 fc, v, *buffer, tmpbuf[4]; - u16 len, hdrlen = 0, gap, fid; - struct rx_hdr hdr; - int success = 0; - - if (test_bit(FLAG_MPI, &ai->flags)) { - if (test_bit(FLAG_802_11, &ai->flags)) - mpi_receive_802_11(ai); - else - mpi_receive_802_3(ai); - OUT4500(ai, EVACK, EV_RX); - return; - } - - fid = IN4500(ai, RXFID); - - /* Get the packet length */ - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_setup (ai, fid, 4, BAP0); - bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - } else { - bap_setup(ai, fid, 0x36, BAP0); - bap_read(ai, &hdr.len, 2, BAP0); - } - len = le16_to_cpu(hdr.len); - - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto done; - } - if (len == 0) - goto done; - - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_read(ai, &fc, sizeof (fc), BAP0); - hdrlen = header_len(fc); - } else - hdrlen = ETH_ALEN * 2; - - skb = dev_alloc_skb(len + hdrlen + 2 + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto done; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = skb_put(skb, len + hdrlen); - if (test_bit(FLAG_802_11, &ai->flags)) { - buffer[0] = fc; - bap_read(ai, buffer + 1, hdrlen - 2, BAP0); - if (hdrlen == 24) - bap_read(ai, tmpbuf, 6, BAP0); - - bap_read(ai, &v, sizeof(v), BAP0); - gap = le16_to_cpu(v); - if (gap) { - if (gap <= 8) { - bap_read(ai, tmpbuf, gap, BAP0); - } else { - airo_print_err(ai->dev->name, "gaplen too " - "big. Problems will follow..."); - } - } - bap_read(ai, buffer + hdrlen/2, len, BAP0); - } else { - MICBuffer micbuf; - - bap_read(ai, buffer, ETH_ALEN * 2, BAP0); - if (ai->micstats.enabled) { - bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0); - if (ntohs(micbuf.typelen) > 0x05DC) - bap_setup(ai, fid, 0x44, BAP0); - else { - if (len <= sizeof (micbuf)) { - dev_kfree_skb_irq(skb); - goto done; - } - - len -= sizeof(micbuf); - skb_trim(skb, len + hdrlen); - } - } - - bap_read(ai, buffer + ETH_ALEN, len, BAP0); - if (decapsulate(ai, &micbuf, (etherHead*) buffer, len)) - dev_kfree_skb_irq (skb); - else - success = 1; - } - -#ifdef WIRELESS_SPY - if (success && (ai->spy_data.spy_number > 0)) { - char *sa; - struct iw_quality wstats; - - /* Prepare spy data : addr + qual */ - if (!test_bit(FLAG_802_11, &ai->flags)) { - sa = (char *) buffer + 6; - bap_setup(ai, fid, 8, BAP0); - bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0); - } else - sa = (char *) buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_QUAL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - -done: - OUT4500(ai, EVACK, EV_RX); - - if (success) { - if (test_bit(FLAG_802_11, &ai->flags)) { - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - } else - skb->protocol = eth_type_trans(skb, ai->dev); - skb->ip_summed = CHECKSUM_NONE; - - netif_rx(skb); - } -} - -static void airo_handle_tx(struct airo_info *ai, u16 status) -{ - int i, index = -1; - u16 fid; - - if (test_bit(FLAG_MPI, &ai->flags)) { - unsigned long flags; - - if (status & EV_TXEXC) - get_tx_error(ai, -1); - - spin_lock_irqsave(&ai->aux_lock, flags); - if (!skb_queue_empty(&ai->txq)) { - spin_unlock_irqrestore(&ai->aux_lock, flags); - mpi_send_packet(ai->dev); - } else { - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue(ai->dev); - } - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - return; - } - - fid = IN4500(ai, TXCOMPLFID); - - for (i = 0; i < MAX_FIDS; i++) { - if ((ai->fids[i] & 0xffff) == fid) - index = i; - } - - if (index != -1) { - if (status & EV_TXEXC) - get_tx_error(ai, index); - - OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC)); - - /* Set up to be used again */ - ai->fids[index] &= 0xffff; - if (index < MAX_FIDS / 2) { - if (!test_bit(FLAG_PENDING_XMIT, &ai->flags)) - netif_wake_queue(ai->dev); - } else { - if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags)) - netif_wake_queue(ai->wifidev); - } - } else { - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - airo_print_err(ai->dev->name, "Unallocated FID was used to xmit"); - } -} - -static irqreturn_t airo_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - u16 status, savedInterrupts = 0; - struct airo_info *ai = dev->ml_priv; - int handled = 0; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - for (;;) { - status = IN4500(ai, EVSTAT); - if (!(status & STATUS_INTS) || (status == 0xffff)) - break; - - handled = 1; - - if (status & EV_AWAKE) { - OUT4500(ai, EVACK, EV_AWAKE); - OUT4500(ai, EVACK, EV_AWAKE); - } - - if (!savedInterrupts) { - savedInterrupts = IN4500(ai, EVINTEN); - OUT4500(ai, EVINTEN, 0); - } - - if (status & EV_MIC) { - OUT4500(ai, EVACK, EV_MIC); - airo_handle_cisco_mic(ai); - } - - if (status & EV_LINK) { - /* Link status changed */ - airo_handle_link(ai); - } - - /* Check to see if there is something to receive */ - if (status & EV_RX) - airo_handle_rx(ai); - - /* Check to see if a packet has been transmitted */ - if (status & (EV_TX | EV_TXCPY | EV_TXEXC)) - airo_handle_tx(ai, status); - - if (status & ~STATUS_INTS & ~IGNORE_INTS) { - airo_print_warn(ai->dev->name, "Got weird status %x", - status & ~STATUS_INTS & ~IGNORE_INTS); - } - } - - if (savedInterrupts) - OUT4500(ai, EVINTEN, savedInterrupts); - - return IRQ_RETVAL(handled); -} - -/* - * Routines to talk to the card - */ - -/* - * This was originally written for the 4500, hence the name - * NOTE: If use with 8bit mode and SMP bad things will happen! - * Why would some one do 8 bit IO in an SMP machine?!? - */ -static void OUT4500(struct airo_info *ai, u16 reg, u16 val) -{ - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - outw(val, ai->dev->base_addr + reg); - else { - outb(val & 0xff, ai->dev->base_addr + reg); - outb(val >> 8, ai->dev->base_addr + reg + 1); - } -} - -static u16 IN4500(struct airo_info *ai, u16 reg) -{ - unsigned short rc; - - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - rc = inw(ai->dev->base_addr + reg); - else { - rc = inb(ai->dev->base_addr + reg); - rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8; - } - return rc; -} - -static int enable_MAC(struct airo_info *ai, int lock) -{ - int rc; - Cmd cmd; - Resp rsp; - - /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions - * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" - * Note : we could try to use !netif_running(dev) in enable_MAC() - * instead of this flag, but I don't trust it *within* the - * open/close functions, and testing both flags together is - * "cheaper" - Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; - - if (lock && down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - if (!test_bit(FLAG_ENABLED, &ai->flags)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_ENABLE; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc == SUCCESS) - set_bit(FLAG_ENABLED, &ai->flags); - } else - rc = SUCCESS; - - if (lock) - up(&ai->sem); - - if (rc) - airo_print_err(ai->dev->name, "Cannot enable MAC"); - else if ((rsp.status & 0xFF00) != 0) { - airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, " - "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2); - rc = ERROR; - } - return rc; -} - -static void disable_MAC(struct airo_info *ai, int lock) -{ - Cmd cmd; - Resp rsp; - - if (lock == 1 && down_interruptible(&ai->sem)) - return; - - if (test_bit(FLAG_ENABLED, &ai->flags)) { - if (lock != 2) /* lock == 2 means don't disable carrier */ - netif_carrier_off(ai->dev); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_DISABLE; // disable in case already enabled - issuecommand(ai, &cmd, &rsp, true); - clear_bit(FLAG_ENABLED, &ai->flags); - } - if (lock == 1) - up(&ai->sem); -} - -static void enable_interrupts(struct airo_info *ai) -{ - /* Enable the interrupts */ - OUT4500(ai, EVINTEN, STATUS_INTS); -} - -static void disable_interrupts(struct airo_info *ai) -{ - OUT4500(ai, EVINTEN, 0); -} - -static void mpi_receive_802_3(struct airo_info *ai) -{ - RxFid rxd; - int len = 0; - struct sk_buff *skb; - char *buffer; - int off = 0; - MICBuffer micbuf; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - /* Make sure we got something */ - if (rxd.rdy && rxd.valid == 0) { - len = rxd.len + 12; - if (len < 12 || len > 2048) - goto badrx; - - skb = dev_alloc_skb(len); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len); - memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); - if (ai->micstats.enabled) { - memcpy(&micbuf, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2, - sizeof(micbuf)); - if (ntohs(micbuf.typelen) <= 0x05DC) { - if (len <= sizeof(micbuf) + ETH_ALEN * 2) - goto badmic; - - off = sizeof(micbuf); - skb_trim (skb, len - off); - } - } - memcpy(buffer + ETH_ALEN * 2, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, - len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { -badmic: - dev_kfree_skb_irq (skb); - goto badrx; - } -#ifdef WIRELESS_SPY - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = buffer + ETH_ALEN; - wstats.qual = 0; /* XXX Where do I get that info from ??? */ - wstats.level = 0; - wstats.updated = 0; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - - skb->ip_summed = CHECKSUM_NONE; - skb->protocol = eth_type_trans(skb, ai->dev); - netif_rx(skb); - } -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static void mpi_receive_802_11(struct airo_info *ai) -{ - RxFid rxd; - struct sk_buff *skb = NULL; - u16 len, hdrlen = 0; - __le16 fc; - struct rx_hdr hdr; - u16 gap; - u16 *buffer; - char *ptr = ai->rxfids[0].virtual_host_addr + 4; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - memcpy ((char *)&hdr, ptr, sizeof(hdr)); - ptr += sizeof(hdr); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - len = le16_to_cpu(hdr.len); - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto badrx; - } - if (len == 0) - goto badrx; - - fc = get_unaligned((__le16 *)ptr); - hdrlen = header_len(fc); - - skb = dev_alloc_skb(len + hdrlen + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len + hdrlen); - memcpy ((char *)buffer, ptr, hdrlen); - ptr += hdrlen; - if (hdrlen == 24) - ptr += 6; - gap = get_unaligned_le16(ptr); - ptr += sizeof(__le16); - if (gap) { - if (gap <= 8) - ptr += gap; - else - airo_print_err(ai->dev->name, - "gaplen too big. Problems will follow..."); - } - memcpy ((char *)buffer + hdrlen, ptr, len); - ptr += len; -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = (char*)buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static inline void set_auth_type(struct airo_info *local, int auth_type) -{ - local->config.authType = auth_type; - /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT). - * Used by airo_set_auth() - */ - if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT) - local->last_auth = auth_type; -} - -static int noinline_for_stack airo_readconfig(struct airo_info *ai, - struct net_device *dev, int lock) -{ - int i, status; - /* large variables, so don't inline this function, - * maybe change to kmalloc - */ - tdsRssiRid rssi_rid; - CapabilityRid cap_rid; - - kfree(ai->SSID); - ai->SSID = NULL; - // general configuration (read/modify/write) - status = readConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - status = readCapabilityRid(ai, &cap_rid, lock); - if (status != SUCCESS) return ERROR; - - status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock); - if (status == SUCCESS) { - if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) - memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ - } - else { - kfree(ai->rssi); - ai->rssi = NULL; - if (cap_rid.softCap & cpu_to_le16(8)) - ai->config.rmode |= RXMODE_NORMALIZED_RSSI; - else - airo_print_warn(ai->dev->name, "unknown received signal " - "level scale"); - } - ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; - set_auth_type(ai, AUTH_OPEN); - ai->config.modulation = MOD_CCK; - - if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) && - (cap_rid.extSoftCap & cpu_to_le16(1)) && - micsetup(ai) == SUCCESS) { - ai->config.opmode |= MODE_MIC; - set_bit(FLAG_MIC_CAPABLE, &ai->flags); - } - - /* Save off the MAC */ - eth_hw_addr_set(dev, ai->config.macAddr); - - /* Check to see if there are any insmod configured - rates to add */ - if (rates[0]) { - memset(ai->config.rates, 0, sizeof(ai->config.rates)); - for (i = 0; i < 8 && rates[i]; i++) { - ai->config.rates[i] = rates[i]; - } - } - set_bit (FLAG_COMMIT, &ai->flags); - - return SUCCESS; -} - - -static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock) -{ - Cmd cmd; - Resp rsp; - int status; - SsidRid mySsid; - __le16 lastindex; - WepKeyRid wkr; - int rc; - - memset(&mySsid, 0, sizeof(mySsid)); - kfree (ai->flash); - ai->flash = NULL; - - /* The NOP is the first step in getting the card going */ - cmd.cmd = NOP; - cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; - if (lock && down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - return ERROR; - } - disable_MAC(ai, 0); - - // Let's figure out if we need to use the AUX port - if (!test_bit(FLAG_MPI,&ai->flags)) { - cmd.cmd = CMD_ENABLEAUX; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - airo_print_err(ai->dev->name, "Error checking for AUX port"); - return ERROR; - } - if (!aux_bap || rsp.status & 0xff00) { - ai->bap_read = fast_bap_read; - airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); - } else { - ai->bap_read = aux_bap_read; - airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); - } - } - if (lock) - up(&ai->sem); - if (ai->config.len == 0) { - status = airo_readconfig(ai, dev, lock); - if (status != SUCCESS) - return ERROR; - } - - /* Setup the SSIDs if present */ - if (ssids[0]) { - int i; - for (i = 0; i < 3 && ssids[i]; i++) { - size_t len = strlen(ssids[i]); - if (len > 32) - len = 32; - mySsid.ssids[i].len = cpu_to_le16(len); - memcpy(mySsid.ssids[i].ssid, ssids[i], len); - } - mySsid.len = cpu_to_le16(sizeof(mySsid)); - } - - status = writeConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - /* Set up the SSID list */ - if (ssids[0]) { - status = writeSsidRid(ai, &mySsid, lock); - if (status != SUCCESS) return ERROR; - } - - status = enable_MAC(ai, lock); - if (status != SUCCESS) - return ERROR; - - /* Grab the initial wep key, we gotta save it for auto_wep */ - rc = readWepKeyRid(ai, &wkr, 1, lock); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - ai->defindex = wkr.mac[0]; - } - rc = readWepKeyRid(ai, &wkr, 0, lock); - } while (lastindex != wkr.kindex); - - try_auto_wep(ai); - - return SUCCESS; -} - -static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp, - bool may_sleep) -{ - // Im really paranoid about letting it run forever! - int max_tries = 600000; - - if (IN4500(ai, EVSTAT) & EV_CMD) - OUT4500(ai, EVACK, EV_CMD); - - OUT4500(ai, PARAM0, pCmd->parm0); - OUT4500(ai, PARAM1, pCmd->parm1); - OUT4500(ai, PARAM2, pCmd->parm2); - OUT4500(ai, COMMAND, pCmd->cmd); - - while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { - if ((IN4500(ai, COMMAND)) == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if (may_sleep && (max_tries & 255) == 0) - cond_resched(); - } - - if (max_tries == -1) { - airo_print_err(ai->dev->name, - "Max tries exceeded when issuing command"); - if (IN4500(ai, COMMAND) & COMMAND_BUSY) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - return ERROR; - } - - // command completed - pRsp->status = IN4500(ai, STATUS); - pRsp->rsp0 = IN4500(ai, RESP0); - pRsp->rsp1 = IN4500(ai, RESP1); - pRsp->rsp2 = IN4500(ai, RESP2); - if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) - airo_print_err(ai->dev->name, - "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", - pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, - pRsp->rsp2); - - // clear stuck command busy if necessary - if (IN4500(ai, COMMAND) & COMMAND_BUSY) { - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - // acknowledge processing the status/response - OUT4500(ai, EVACK, EV_CMD); - - return SUCCESS; -} - -/* Sets up the bap to start exchange data. whichbap should - * be one of the BAP0 or BAP1 defines. Locks should be held before - * calling! */ -static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap) -{ - int timeout = 50; - int max_tries = 3; - - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - while (1) { - int status = IN4500(ai, OFFSET0+whichbap); - if (status & BAP_BUSY) { - /* This isn't really a timeout, but its kinda - close */ - if (timeout--) { - continue; - } - } else if (status & BAP_ERR) { - /* invalid rid or offset */ - airo_print_err(ai->dev->name, "BAP error %x %d", - status, whichbap); - return ERROR; - } else if (status & BAP_DONE) { // success - return SUCCESS; - } - if (!(max_tries--)) { - airo_print_err(ai->dev->name, - "BAP setup error too many retries\n"); - return ERROR; - } - // -- PC4500 missed it, try again - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - timeout = 50; - } -} - -/* should only be called by aux_bap_read. This aux function and the - following use concepts not documented in the developers guide. I - got them from a patch given to my by Aironet */ -static u16 aux_setup(struct airo_info *ai, u16 page, - u16 offset, u16 *len) -{ - u16 next; - - OUT4500(ai, AUXPAGE, page); - OUT4500(ai, AUXOFF, 0); - next = IN4500(ai, AUXDATA); - *len = IN4500(ai, AUXDATA)&0xff; - if (offset != 4) OUT4500(ai, AUXOFF, offset); - return next; -} - -/* requires call to bap_setup() first */ -static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - u16 len; - u16 page; - u16 offset; - u16 next; - int words; - int i; - unsigned long flags; - - spin_lock_irqsave(&ai->aux_lock, flags); - page = IN4500(ai, SWS0+whichbap); - offset = IN4500(ai, SWS2+whichbap); - next = aux_setup(ai, page, offset, &len); - words = (bytelen+1)>>1; - - for (i = 0; i>1) < (words-i) ? (len>>1) : (words-i); - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count); - else - insb(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count << 1); - i += count; - if (iaux_lock, flags); - return SUCCESS; -} - - -/* requires call to bap_setup() first */ -static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1); - else - insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen); - return SUCCESS; -} - -/* requires call to bap_setup() first */ -static int bap_write(struct airo_info *ai, const __le16 *pu16Src, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - outsw(ai->dev->base_addr+DATA0+whichbap, - pu16Src, bytelen>>1); - else - outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen); - return SUCCESS; -} - -static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd) -{ - Cmd cmd; /* for issuing commands */ - Resp rsp; /* response from commands */ - u16 status; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = accmd; - cmd.parm0 = rid; - status = issuecommand(ai, &cmd, &rsp, true); - if (status != 0) return status; - if ((rsp.status & 0x7F00) != 0) { - return (accmd << 8) + (rsp.rsp0 & 0xFF); - } - return 0; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * we must get a lock. */ -static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.host_addr = ai->ridbus; - - cmd.cmd = CMD_ACCESS; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - rc = issuecommand(ai, &cmd, &rsp, true); - - if (rsp.status & 0x7f00) - rc = rsp.rsp0; - if (!rc) - memcpy(pBuf, ai->config_desc.virtual_host_addr, len); - goto done; - } else { - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) { - rc = status; - goto done; - } - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - // read the rid length field - bap_read(ai, pBuf, 2, BAP1); - // length for remaining part of rid - len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; - - if (len <= 2) { - airo_print_err(ai->dev->name, - "Rid %x has a length of %d which is too short", - (int)rid, (int)len); - rc = ERROR; - goto done; - } - // read remainder of the rid - rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * make sure this isn't called when a transmit is happening */ -static int PC4500_writerid(struct airo_info *ai, u16 rid, - const void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - *(__le16*)pBuf = cpu_to_le16((u16)len); - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) - airo_print_err(ai->dev->name, - "%s: MAC should be disabled (rid=%04x)", - __func__, rid); - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = *((u16 *)pBuf); - ai->config_desc.rid_desc.rid = 0; - - cmd.cmd = CMD_WRITERID; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - if (len < 4 || len > 2047) { - airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); - rc = -1; - } else { - memcpy(ai->config_desc.virtual_host_addr, - pBuf, len); - - rc = issuecommand(ai, &cmd, &rsp, true); - if ((rc & 0xff00) != 0) { - airo_print_err(ai->dev->name, "%s: Write rid Error %d", - __func__, rc); - airo_print_err(ai->dev->name, "%s: Cmd=%04x", - __func__, cmd.cmd); - } - - if ((rsp.status & 0x7f00)) - rc = rsp.rsp0; - } - } else { - // --- first access so that we can write the rid data - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { - rc = status; - goto done; - } - // --- now write the rid data - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - bap_write(ai, pBuf, len, BAP1); - // ---now commit the rid data - rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Allocates a FID to be used for transmitting packets. We only use - one for now. */ -static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) -{ - unsigned int loop = 3000; - Cmd cmd; - Resp rsp; - u16 txFid; - __le16 txControl; - - cmd.cmd = CMD_ALLOCATETX; - cmd.parm0 = lenPayload; - if (down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - txFid = ERROR; - goto done; - } - if ((rsp.status & 0xFF00) != 0) { - txFid = ERROR; - goto done; - } - /* wait for the allocate event/indication - * It makes me kind of nervous that this can just sit here and spin, - * but in practice it only loops like four times. */ - while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop); - if (!loop) { - txFid = ERROR; - goto done; - } - - // get the allocated fid and acknowledge - txFid = IN4500(ai, TXALLOCFID); - OUT4500(ai, EVACK, EV_ALLOC); - - /* The CARD is pretty cool since it converts the ethernet packet - * into 802.11. Also note that we don't release the FID since we - * will be using the same one over and over again. */ - /* We only have to setup the control once since we are not - * releasing the fid. */ - if (raw) - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - else - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) - txFid = ERROR; - else - bap_write(ai, &txControl, sizeof(txControl), BAP1); - -done: - up(&ai->sem); - - return txFid; -} - -/* In general BAP1 is dedicated to transmiting packets. However, - since we need a BAP when accessing RIDs, we also use BAP1 for that. - Make sure the BAP1 spinlock is held when this is called. */ -static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 payloadLen; - Cmd cmd; - Resp rsp; - int miclen = 0; - u16 txFid = len; - MICBuffer pMic; - - len >>= 16; - - if (len <= ETH_ALEN * 2) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - len -= ETH_ALEN * 2; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) { - if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS) - return ERROR; - miclen = sizeof(pMic); - } - // packet is destination[6], source[6], payload[len-12] - // write the payload length and dst/src/payload - if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; - /* The hardware addresses aren't counted as part of the payload, so - * we have to subtract the 12 bytes for the addresses off */ - payloadLen = cpu_to_le16(len + miclen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1); - if (miclen) - bap_write(ai, (__le16*)&pMic, miclen, BAP1); - bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 fc, payloadLen; - Cmd cmd; - Resp rsp; - int hdrlen; - static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6}; - /* padding of header to full size + le16 gaplen (6) + gaplen bytes */ - u16 txFid = len; - len >>= 16; - - fc = *(__le16*)pPacket; - hdrlen = header_len(fc); - - if (len < hdrlen) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - - /* packet is 802.11 header + payload - * write the payload length and dst/src/payload */ - if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR; - /* The 802.11 header aren't counted as part of the payload, so - * we have to subtract the header bytes off */ - payloadLen = cpu_to_le16(len-hdrlen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; - bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1); - bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1); - - bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -/* - * This is the proc_fs routines. It is a bit messier than I would - * like! Feel free to clean it up! - */ - -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset); - -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset); -static int proc_close(struct inode *inode, struct file *file); - -static int proc_stats_open(struct inode *inode, struct file *file); -static int proc_statsdelta_open(struct inode *inode, struct file *file); -static int proc_status_open(struct inode *inode, struct file *file); -static int proc_SSID_open(struct inode *inode, struct file *file); -static int proc_APList_open(struct inode *inode, struct file *file); -static int proc_BSSList_open(struct inode *inode, struct file *file); -static int proc_config_open(struct inode *inode, struct file *file); -static int proc_wepkey_open(struct inode *inode, struct file *file); - -static const struct proc_ops proc_statsdelta_ops = { - .proc_read = proc_read, - .proc_open = proc_statsdelta_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_stats_ops = { - .proc_read = proc_read, - .proc_open = proc_stats_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_status_ops = { - .proc_read = proc_read, - .proc_open = proc_status_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_SSID_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_SSID_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_BSSList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_BSSList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_APList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_APList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_config_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_config_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_wepkey_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_wepkey_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static struct proc_dir_entry *airo_entry; - -struct proc_data { - int release_buffer; - int readlen; - char *rbuffer; - int writelen; - int maxwritelen; - char *wbuffer; - void (*on_close) (struct inode *, struct file *); -}; - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - struct proc_dir_entry *entry; - - /* First setup the device directory */ - strcpy(apriv->proc_name, dev->name); - apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm, - airo_entry); - if (!apriv->proc_entry) - return -ENOMEM; - proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); - - /* Setup the StatsDelta */ - entry = proc_create_data("StatsDelta", 0444 & proc_perm, - apriv->proc_entry, &proc_statsdelta_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Stats */ - entry = proc_create_data("Stats", 0444 & proc_perm, - apriv->proc_entry, &proc_stats_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Status */ - entry = proc_create_data("Status", 0444 & proc_perm, - apriv->proc_entry, &proc_status_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Config */ - entry = proc_create_data("Config", proc_perm, - apriv->proc_entry, &proc_config_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the SSID */ - entry = proc_create_data("SSID", proc_perm, - apriv->proc_entry, &proc_SSID_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the APList */ - entry = proc_create_data("APList", proc_perm, - apriv->proc_entry, &proc_APList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the BSSList */ - entry = proc_create_data("BSSList", proc_perm, - apriv->proc_entry, &proc_BSSList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the WepKey */ - entry = proc_create_data("WepKey", proc_perm, - apriv->proc_entry, &proc_wepkey_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - return 0; - -fail: - remove_proc_subtree(apriv->proc_name, airo_entry); - return -ENOMEM; -} - -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - remove_proc_subtree(apriv->proc_name, airo_entry); - return 0; -} - -/* - * What we want from the proc_fs is to be able to efficiently read - * and write the configuration. To do this, we want to read the - * configuration when the file is opened and write it when the file is - * closed. So basically we allocate a read buffer at open and fill it - * with data, and allocate a write buffer and read it at close. - */ - -/* - * The read routine is generic, it relies on the preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset) -{ - struct proc_data *priv = file->private_data; - - if (!priv->rbuffer) - return -EINVAL; - - return simple_read_from_buffer(buffer, len, offset, priv->rbuffer, - priv->readlen); -} - -/* - * The write routine is generic, it fills in a preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset) -{ - ssize_t ret; - struct proc_data *priv = file->private_data; - - if (!priv->wbuffer) - return -EINVAL; - - ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset, - buffer, len); - if (ret > 0) - priv->writelen = max_t(int, priv->writelen, *offset); - - return ret; -} - -static int proc_status_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - CapabilityRid cap_rid; - StatusRid status_rid; - u16 mode; - int i; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatusRid(apriv, &status_rid, 1); - readCapabilityRid(apriv, &cap_rid, 1); - - mode = le16_to_cpu(status_rid.mode); - - i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", - mode & 1 ? "CFG ": "", - mode & 2 ? "ACT ": "", - mode & 0x10 ? "SYN ": "", - mode & 0x20 ? "LNK ": "", - mode & 0x40 ? "LEAP ": "", - mode & 0x80 ? "PRIV ": "", - mode & 0x100 ? "KEY ": "", - mode & 0x200 ? "WEP ": "", - mode & 0x8000 ? "ERR ": ""); - sprintf(data->rbuffer+i, "Mode: %x\n" - "Signal Strength: %d\n" - "Signal Quality: %d\n" - "SSID: %-.*s\n" - "AP: %-.16s\n" - "Freq: %d\n" - "BitRate: %dmbs\n" - "Driver Version: %s\n" - "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" - "Radio type: %x\nCountry: %x\nHardware Version: %x\n" - "Software Version: %x\nSoftware Subversion: %x\n" - "Boot block version: %x\n", - le16_to_cpu(status_rid.mode), - le16_to_cpu(status_rid.normalizedSignalStrength), - le16_to_cpu(status_rid.signalQuality), - le16_to_cpu(status_rid.SSIDlen), - status_rid.SSID, - status_rid.apName, - le16_to_cpu(status_rid.channel), - le16_to_cpu(status_rid.currentXmitRate) / 2, - version, - cap_rid.prodName, - cap_rid.manName, - cap_rid.prodVer, - le16_to_cpu(cap_rid.radioType), - le16_to_cpu(cap_rid.country), - le16_to_cpu(cap_rid.hardVer), - le16_to_cpu(cap_rid.softVer), - le16_to_cpu(cap_rid.softSubVer), - le16_to_cpu(cap_rid.bootBlockVer)); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_stats_rid_open(struct inode*, struct file*, u16); -static int proc_statsdelta_open(struct inode *inode, - struct file *file) -{ - if (file->f_mode&FMODE_WRITE) { - return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); - } - return proc_stats_rid_open(inode, file, RID_STATSDELTA); -} - -static int proc_stats_open(struct inode *inode, struct file *file) -{ - return proc_stats_rid_open(inode, file, RID_STATS); -} - -static int proc_stats_rid_open(struct inode *inode, - struct file *file, - u16 rid) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - StatsRid stats; - int i, j; - __le32 *vals = stats.vals; - int len; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatsRid(apriv, &stats, rid, 1); - len = le16_to_cpu(stats.len); - - j = 0; - for (i = 0; statsLabels[i]!=(char *)-1 && i*44096) { - airo_print_warn(apriv->dev->name, - "Potentially disastrous buffer overflow averted!"); - break; - } - j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], - le32_to_cpu(vals[i])); - } - if (i*4 >= len) { - airo_print_warn(apriv->dev->name, "Got a short rid"); - } - data->readlen = j; - return 0; -} - -static int get_dec_u16(char *buffer, int *start, int limit) -{ - u16 value; - int valid = 0; - for (value = 0; *start < limit && buffer[*start] >= '0' && - buffer[*start] <= '9'; (*start)++) { - valid = 1; - value *= 10; - value += buffer[*start] - '0'; - } - if (!valid) return -1; - return value; -} - -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); - -static inline int sniffing_mode(struct airo_info *ai) -{ - return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >= - le16_to_cpu(RXMODE_RFMON); -} - -static void proc_config_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *line; - - if (!data->writelen) return; - - readConfigRid(ai, 1); - set_bit (FLAG_COMMIT, &ai->flags); - - line = data->wbuffer; - while (line[0]) { -/*** Mode processing */ - if (!strncmp(line, "Mode: ", 6)) { - line += 6; - if (sniffing_mode(ai)) - set_bit (FLAG_RESET, &ai->flags); - ai->config.rmode &= ~RXMODE_FULL_MASK; - clear_bit (FLAG_802_11, &ai->flags); - ai->config.opmode &= ~MODE_CFG_MASK; - ai->config.scanMode = SCANMODE_ACTIVE; - if (line[0] == 'a') { - ai->config.opmode |= MODE_STA_IBSS; - } else { - ai->config.opmode |= MODE_STA_ESS; - if (line[0] == 'r') { - ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'y') { - ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'l') - ai->config.rmode |= RXMODE_LANMON; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** Radio status */ - else if (!strncmp(line,"Radio: ", 7)) { - line += 7; - if (!strncmp(line,"off", 3)) { - set_bit (FLAG_RADIO_OFF, &ai->flags); - } else { - clear_bit (FLAG_RADIO_OFF, &ai->flags); - } - } -/*** NodeName processing */ - else if (!strncmp(line, "NodeName: ", 10)) { - int j; - - line += 10; - memset(ai->config.nodeName, 0, 16); -/* Do the name, assume a space between the mode and node name */ - for (j = 0; j < 16 && line[j] != '\n'; j++) { - ai->config.nodeName[j] = line[j]; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** PowerMode processing */ - else if (!strncmp(line, "PowerMode: ", 11)) { - line += 11; - if (!strncmp(line, "PSPCAM", 6)) { - ai->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "PSP", 3)) { - ai->config.powerSaveMode = POWERSAVE_PSP; - set_bit (FLAG_COMMIT, &ai->flags); - } else { - ai->config.powerSaveMode = POWERSAVE_CAM; - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "DataRates: ", 11)) { - int v, i = 0, k = 0; /* i is index into line, - k is index to rates */ - - line += 11; - while ((v = get_dec_u16(line, &i, 3))!=-1) { - ai->config.rates[k++] = (u8)v; - line += i + 1; - i = 0; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Channel: ", 9)) { - int v, i = 0; - line += 9; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.channelSet = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "XmitPower: ", 11)) { - int v, i = 0; - line += 11; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.txPower = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "WEP: ", 5)) { - line += 5; - switch(line[0]) { - case 's': - set_auth_type(ai, AUTH_SHAREDKEY); - break; - case 'e': - set_auth_type(ai, AUTH_ENCRYPT); - break; - default: - set_auth_type(ai, AUTH_OPEN); - break; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "LongRetryLimit: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.longRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "ShortRetryLimit: ", 17)) { - int v, i = 0; - - line += 17; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.shortRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RTSThreshold: ", 14)) { - int v, i = 0; - - line += 14; - v = get_dec_u16(line, &i, 4); - v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - ai->config.rtsThres = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.txLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.rxLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXDiversity: ", 13)) { - ai->config.txDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXDiversity: ", 13)) { - ai->config.rxDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "FragThreshold: ", 15)) { - int v, i = 0; - - line += 15; - v = get_dec_u16(line, &i, 4); - v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - v = v & 0xfffe; /* Make sure its even */ - ai->config.fragThresh = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Modulation: ", 12)) { - line += 12; - switch(*line) { - case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'c': ai->config.modulation = MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'm': ai->config.modulation = MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown modulation"); - } - } else if (!strncmp(line, "Preamble: ", 10)) { - line += 10; - switch(*line) { - case 'a': ai->config.preamble = PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'l': ai->config.preamble = PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; - case 's': ai->config.preamble = PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown preamble"); - } - } else { - airo_print_warn(ai->dev->name, "Couldn't figure out %s", line); - } - while (line[0] && line[0] != '\n') line++; - if (line[0]) line++; - } - airo_config_commit(dev, NULL, NULL, NULL); -} - -static const char *get_rmode(__le16 mode) -{ - switch(mode & RXMODE_MASK) { - case RXMODE_RFMON: return "rfmon"; - case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon"; - case RXMODE_LANMON: return "lanmon"; - } - return "ESS"; -} - -static int proc_config_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - __le16 mode; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - if ((data->wbuffer = kzalloc(2048, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->maxwritelen = 2048; - data->on_close = proc_config_on_close; - - readConfigRid(ai, 1); - - mode = ai->config.opmode & MODE_CFG_MASK; - i = sprintf(data->rbuffer, - "Mode: %s\n" - "Radio: %s\n" - "NodeName: %-16s\n" - "PowerMode: %s\n" - "DataRates: %d %d %d %d %d %d %d %d\n" - "Channel: %d\n" - "XmitPower: %d\n", - mode == MODE_STA_IBSS ? "adhoc" : - mode == MODE_STA_ESS ? get_rmode(ai->config.rmode): - mode == MODE_AP ? "AP" : - mode == MODE_AP_RPTR ? "AP RPTR" : "Error", - test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on", - ai->config.nodeName, - ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" : - ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" : - ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" : - "Error", - (int)ai->config.rates[0], - (int)ai->config.rates[1], - (int)ai->config.rates[2], - (int)ai->config.rates[3], - (int)ai->config.rates[4], - (int)ai->config.rates[5], - (int)ai->config.rates[6], - (int)ai->config.rates[7], - le16_to_cpu(ai->config.channelSet), - le16_to_cpu(ai->config.txPower) - ); - sprintf(data->rbuffer + i, - "LongRetryLimit: %d\n" - "ShortRetryLimit: %d\n" - "RTSThreshold: %d\n" - "TXMSDULifetime: %d\n" - "RXMSDULifetime: %d\n" - "TXDiversity: %s\n" - "RXDiversity: %s\n" - "FragThreshold: %d\n" - "WEP: %s\n" - "Modulation: %s\n" - "Preamble: %s\n", - le16_to_cpu(ai->config.longRetryLimit), - le16_to_cpu(ai->config.shortRetryLimit), - le16_to_cpu(ai->config.rtsThres), - le16_to_cpu(ai->config.txLifetime), - le16_to_cpu(ai->config.rxLifetime), - ai->config.txDiversity == 1 ? "left" : - ai->config.txDiversity == 2 ? "right" : "both", - ai->config.rxDiversity == 1 ? "left" : - ai->config.rxDiversity == 2 ? "right" : "both", - le16_to_cpu(ai->config.fragThresh), - ai->config.authType == AUTH_ENCRYPT ? "encrypt" : - ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open", - ai->config.modulation == MOD_DEFAULT ? "default" : - ai->config.modulation == MOD_CCK ? "cck" : - ai->config.modulation == MOD_MOK ? "mok" : "error", - ai->config.preamble == PREAMBLE_AUTO ? "auto" : - ai->config.preamble == PREAMBLE_LONG ? "long" : - ai->config.preamble == PREAMBLE_SHORT ? "short" : "error" - ); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static void proc_SSID_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - SsidRid SSID_rid; - int i; - char *p = data->wbuffer; - char *end = p + data->writelen; - - if (!data->writelen) - return; - - *end = '\n'; /* sentinel; we have space for it */ - - memset(&SSID_rid, 0, sizeof(SSID_rid)); - - for (i = 0; i < 3 && p < end; i++) { - int j = 0; - /* copy up to 32 characters from this line */ - while (*p != '\n' && j < 32) - SSID_rid.ssids[i].ssid[j++] = *p++; - if (j == 0) - break; - SSID_rid.ssids[i].len = cpu_to_le16(j); - /* skip to the beginning of the next line */ - while (*p++ != '\n') - ; - } - if (i) - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - disable_MAC(ai, 1); - writeSsidRid(ai, &SSID_rid, 1); - enable_MAC(ai, 1); -} - -static void proc_APList_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - APListRid *APList_rid = &ai->APList; - int i; - - if (!data->writelen) return; - - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - - for (i = 0; i < 4 && data->writelen >= (i + 1) * 6 * 3; i++) - mac_pton(data->wbuffer + i * 6 * 3, APList_rid->ap[i]); - - disable_MAC(ai, 1); - writeAPListRid(ai, APList_rid, 1); - enable_MAC(ai, 1); -} - -/* This function wraps PC4500_writerid with a MAC disable */ -static int do_writerid(struct airo_info *ai, u16 rid, const void *rid_data, - int len, int dummy) -{ - int rc; - - disable_MAC(ai, 1); - rc = PC4500_writerid(ai, rid, rid_data, len, 1); - enable_MAC(ai, 1); - return rc; -} - -/* Returns the WEP key at the specified index, or -1 if that key does - * not exist. The buffer is assumed to be at least 16 bytes in length. - */ -static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (le16_to_cpu(wkr.kindex) == index) { - int klen = min_t(int, buflen, le16_to_cpu(wkr.klen)); - memcpy(buf, wkr.key, klen); - return klen; - } - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int get_wep_tx_idx(struct airo_info *ai) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) - return wkr.mac[0]; - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key, - u16 keylen, int perm, int lock) -{ - static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; - WepKeyRid wkr; - int rc; - - if (WARN_ON(keylen == 0)) - return -1; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(index); - wkr.klen = cpu_to_le16(keylen); - memcpy(wkr.key, key, keylen); - memcpy(wkr.mac, macaddr, ETH_ALEN); - - if (perm) disable_MAC(ai, lock); - rc = writeWepKeyRid(ai, &wkr, perm, lock); - if (perm) enable_MAC(ai, lock); - return rc; -} - -static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock) -{ - WepKeyRid wkr; - int rc; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(0xffff); - wkr.mac[0] = (char)index; - - if (perm) { - ai->defindex = (char)index; - disable_MAC(ai, lock); - } - - rc = writeWepKeyRid(ai, &wkr, perm, lock); - - if (perm) - enable_MAC(ai, lock); - return rc; -} - -static void proc_wepkey_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i, rc; - u8 key[16]; - u16 index = 0; - int j = 0; - - memset(key, 0, sizeof(key)); - - data = file->private_data; - if (!data->writelen) return; - - if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' && - (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) { - index = data->wbuffer[0] - '0'; - if (data->wbuffer[1] == '\n') { - rc = set_wep_tx_idx(ai, index, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - index, rc); - } - return; - } - j = 2; - } else { - airo_print_err(ai->dev->name, "WepKey passed invalid key index"); - return; - } - - for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) { - int val; - - if (i % 3 == 2) - continue; - - val = hex_to_bin(data->wbuffer[i+j]); - if (val < 0) { - airo_print_err(ai->dev->name, "WebKey passed invalid key hex"); - return; - } - switch(i%3) { - case 0: - key[i/3] = (u8)val << 4; - break; - case 1: - key[i/3] |= (u8)val; - break; - } - } - - rc = set_wep_key(ai, index, key, i/3, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set WEP key at index " - "%d: %d.", index, rc); - } -} - -static int proc_wepkey_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - WepKeyRid wkr; - __le16 lastindex; - int j = 0; - int rc; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(&wkr, 0, sizeof(wkr)); - data = file->private_data; - if ((data->rbuffer = kzalloc(180, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 80; - if ((data->wbuffer = kzalloc(80, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_wepkey_on_close; - - ptr = data->rbuffer; - strcpy(ptr, "No wep keys\n"); - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - j += sprintf(ptr+j, "Tx key = %d\n", - (int)wkr.mac[0]); - } else { - j += sprintf(ptr+j, "Key %d set with length = %d\n", - le16_to_cpu(wkr.kindex), - le16_to_cpu(wkr.klen)); - } - readWepKeyRid(ai, &wkr, 0, 1); - } while ((lastindex != wkr.kindex) && (j < 180-30)); - - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_SSID_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - SsidRid SSID_rid; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 33*3; - /* allocate maxwritelen + 1; we'll want a sentinel */ - if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_SSID_on_close; - - readSsidRid(ai, &SSID_rid); - ptr = data->rbuffer; - for (i = 0; i < 3; i++) { - int j; - size_t len = le16_to_cpu(SSID_rid.ssids[i].len); - if (!len) - break; - if (len > 32) - len = 32; - for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++) - *ptr++ = SSID_rid.ssids[i].ssid[j]; - *ptr++ = '\n'; - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_APList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - APListRid *APList_rid = &ai->APList; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 4*6*3; - if ((data->wbuffer = kzalloc(data->maxwritelen, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_APList_on_close; - - ptr = data->rbuffer; - for (i = 0; i < 4; i++) { -// We end when we find a zero MAC - if (!*(int*)APList_rid->ap[i] && - !*(int*)&APList_rid->ap[i][2]) break; - ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]); - } - if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); - - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_BSSList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - BSSListRid BSSList_rid; - int rc; - /* If doLoseSync is not 1, we won't do a Lose Sync */ - int doLoseSync = -1; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(1024, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 0; - data->wbuffer = NULL; - data->on_close = NULL; - - if (file->f_mode & FMODE_WRITE) { - if (!(file->f_mode & FMODE_READ)) { - Cmd cmd; - Resp rsp; - - if (ai->flags & FLAG_RADIO_MASK) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ENETDOWN; - } - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ERESTARTSYS; - } - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - data->readlen = 0; - return 0; - } - doLoseSync = 1; - } - ptr = data->rbuffer; - /* There is a race condition here if there are concurrent opens. - Since it is a rare condition, we'll just live with it, otherwise - we have to add a spin lock... */ - rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); - while (rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%pM %.*s rssi = %d", - BSSList_rid.bssid, - (int)BSSList_rid.ssidLen, - BSSList_rid.ssid, - le16_to_cpu(BSSList_rid.dBm)); - ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", - le16_to_cpu(BSSList_rid.dsChannel), - BSSList_rid.cap & CAP_ESS ? "ESS" : "", - BSSList_rid.cap & CAP_IBSS ? "adhoc" : "", - BSSList_rid.cap & CAP_PRIVACY ? "wep" : "", - BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : ""); - rc = readBSSListRid(ai, 0, &BSSList_rid); - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - - if (data->on_close != NULL) - data->on_close(inode, file); - kfree(data->rbuffer); - kfree(data->wbuffer); - kfree(data); - return 0; -} - -/* Since the card doesn't automatically switch to the right WEP mode, - we will make it do it. If the card isn't associated, every secs we - will switch WEP modes to see if that will help. If the card is - associated we will check every minute to see if anything has - changed. */ -static void timer_func(struct net_device *dev) -{ - struct airo_info *apriv = dev->ml_priv; - -/* We don't have a link so try changing the authtype */ - readConfigRid(apriv, 0); - disable_MAC(apriv, 0); - switch(apriv->config.authType) { - case AUTH_ENCRYPT: -/* So drop to OPEN */ - apriv->config.authType = AUTH_OPEN; - break; - case AUTH_SHAREDKEY: - if (apriv->keyindex < auto_wep) { - set_wep_tx_idx(apriv, apriv->keyindex, 0, 0); - apriv->config.authType = AUTH_SHAREDKEY; - apriv->keyindex++; - } else { - /* Drop to ENCRYPT */ - apriv->keyindex = 0; - set_wep_tx_idx(apriv, apriv->defindex, 0, 0); - apriv->config.authType = AUTH_ENCRYPT; - } - break; - default: /* We'll escalate to SHAREDKEY */ - apriv->config.authType = AUTH_SHAREDKEY; - } - set_bit (FLAG_COMMIT, &apriv->flags); - writeConfigRid(apriv, 0); - enable_MAC(apriv, 0); - up(&apriv->sem); - -/* Schedule check to see if the change worked */ - clear_bit(JOB_AUTOWEP, &apriv->jobs); - apriv->expires = RUN_AT(HZ*3); -} - -#ifdef CONFIG_PCI -static int airo_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - pci_set_master(pdev); - - if (pdev->device == 0x5000 || pdev->device == 0xa504) - dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); - else - dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void airo_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - airo_print_info(dev->name, "Unregistering..."); - stop_airo_card(dev, 1); - pci_disable_device(pdev); -} - -static int __maybe_unused airo_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - - if (!ai->SSID) - ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL); - if (!ai->SSID) - return -ENOMEM; - readSsidRid(ai, ai->SSID); - memset(&cmd, 0, sizeof(cmd)); - /* the lock will be released at the end of the resume callback */ - if (down_interruptible(&ai->sem)) - return -EAGAIN; - disable_MAC(ai, 0); - netif_device_detach(dev); - ai->power = PMSG_SUSPEND; - cmd.cmd = HOSTSLEEP; - issuecommand(ai, &cmd, &rsp, true); - - device_wakeup_enable(dev_d); - return 0; -} - -static int __maybe_unused airo_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - pci_power_t prev_state = to_pci_dev(dev_d)->current_state; - - device_wakeup_disable(dev_d); - - if (prev_state != PCI_D1) { - reset_card(dev, 0); - mpi_init_descriptors(ai); - setup_card(ai, dev, 0); - clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - } else { - OUT4500(ai, EVACK, EV_AWAKEN); - OUT4500(ai, EVACK, EV_AWAKEN); - msleep(100); - } - - set_bit(FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 0); - msleep(200); - if (ai->SSID) { - writeSsidRid(ai, ai->SSID, 0); - kfree(ai->SSID); - ai->SSID = NULL; - } - writeAPListRid(ai, &ai->APList, 0); - writeConfigRid(ai, 0); - enable_MAC(ai, 0); - ai->power = PMSG_ON; - netif_device_attach(dev); - netif_wake_queue(dev); - enable_interrupts(ai); - up(&ai->sem); - return 0; -} -#endif - -static int __init airo_init_module(void) -{ - int i; - - proc_kuid = make_kuid(&init_user_ns, proc_uid); - proc_kgid = make_kgid(&init_user_ns, proc_gid); - if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid)) - return -EINVAL; - - airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL); - - if (airo_entry) - proc_set_user(airo_entry, proc_kuid, proc_kgid); - - for (i = 0; i < 4 && io[i] && irq[i]; i++) { - airo_print_info("", "Trying to configure ISA adapter at irq=%d " - "io = 0x%x", irq[i], io[i]); - if (init_airo_card(irq[i], io[i], 0, NULL)) { - /* do nothing */ ; - } - } - -#ifdef CONFIG_PCI - airo_print_info("", "Probing for PCI adapters"); - i = pci_register_driver(&airo_driver); - airo_print_info("", "Finished probing for PCI adapters"); - - if (i) { - remove_proc_entry("driver/aironet", NULL); - return i; - } -#endif - - /* Always exit with success, as we are a library module - * as well as a driver module - */ - return 0; -} - -static void __exit airo_cleanup_module(void) -{ - struct airo_info *ai; - while (!list_empty(&airo_devices)) { - ai = list_entry(airo_devices.next, struct airo_info, dev_list); - airo_print_info(ai->dev->name, "Unregistering..."); - stop_airo_card(ai->dev, 1); - } -#ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); -#endif - remove_proc_entry("driver/aironet", NULL); -} - -/* - * Initial Wireless Extension code for Aironet driver by : - * Jean Tourrilhes - HPL - 17 November 00 - * Conversion to new driver API by : - * Jean Tourrilhes - HPL - 26 March 02 - * Javier also did a good amount of work here, adding some new extensions - * and fixing my code. Let's just say that without him this code just - * would not work at all... - Jean II - */ - -static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi) -{ - if (!rssi_rid) - return 0; - - return (0x100 - rssi_rid[rssi].rssidBm); -} - -static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) -{ - int i; - - if (!rssi_rid) - return 0; - - for (i = 0; i < 256; i++) - if (rssi_rid[i].rssidBm == dbm) - return rssi_rid[i].rssipct; - - return 0; -} - - -static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) -{ - int quality = 0; - u16 sq; - - if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f)) - return 0; - - if (!(cap_rid->hardCap & cpu_to_le16(8))) - return 0; - - sq = le16_to_cpu(status_rid->signalQuality); - if (memcmp(cap_rid->prodName, "350", 3)) - if (sq > 0x20) - quality = 0; - else - quality = 0x20 - sq; - else - if (sq > 0xb0) - quality = 0; - else if (sq < 0x10) - quality = 0xa0; - else - quality = 0xb0 - sq; - return quality; -} - -#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) -#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50) - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int airo_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *cwrq, - char *extra) -{ - strcpy(cwrq->name, "IEEE 802.11-DS"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int airo_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - /* We should do a better check than that, - * based on the card capability !!! */ - if ((channel < 1) || (channel > 14)) { - airo_print_dbg(dev->name, "New channel value of %d is invalid!", - fwrq->m); - rc = -EINVAL; - } else { - readConfigRid(local, 1); - /* Yes ! We can set it !!! */ - local->config.channelSet = cpu_to_le16(channel); - set_bit (FLAG_COMMIT, &local->flags); - } - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int airo_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ch; - - readConfigRid(local, 1); - if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS) - status_rid.channel = local->config.channelSet; - else - readStatusRid(local, &status_rid, 1); - - ch = le16_to_cpu(status_rid.channel); - if ((ch > 0) && (ch < 15)) { - fwrq->m = 100000 * - ieee80211_channel_to_frequency(ch, NL80211_BAND_2GHZ); - fwrq->e = 1; - } else { - fwrq->m = ch; - fwrq->e = 0; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int airo_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - SsidRid SSID_rid; /* SSIDs */ - - /* Reload the list of current SSID */ - readSsidRid(local, &SSID_rid); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - /* Just send an empty SSID list */ - memset(&SSID_rid, 0, sizeof(SSID_rid)); - } else { - unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - /* Check the size of the string */ - if (dwrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG ; - - /* Check if index is valid */ - if (index >= ARRAY_SIZE(SSID_rid.ssids)) - return -EINVAL; - - /* Set the SSID */ - memset(SSID_rid.ssids[index].ssid, 0, - sizeof(SSID_rid.ssids[index].ssid)); - memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); - SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length); - } - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - /* Write it to the card */ - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - enable_MAC(local, 1); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int airo_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Note : if dwrq->flags != 0, we should - * get the relevant SSID from the SSID list... */ - - /* Get the current SSID */ - memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen)); - /* If none, we may want to get the one that was set */ - - /* Push it out ! */ - dwrq->length = le16_to_cpu(status_rid.SSIDlen); - dwrq->flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set AP address - */ -static int airo_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - Cmd cmd; - Resp rsp; - APListRid *APList_rid = &local->APList; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - else if (is_broadcast_ether_addr(awrq->sa_data) || - is_zero_ether_addr(awrq->sa_data)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LOSE_SYNC; - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - issuecommand(local, &cmd, &rsp, true); - up(&local->sem); - } else { - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN); - disable_MAC(local, 1); - writeAPListRid(local, APList_rid, 1); - enable_MAC(local, 1); - } - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int airo_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Tentative. This seems to work, wow, I'm lucky !!! */ - memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Nickname - */ -static int airo_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - /* Check the size of the string */ - if (dwrq->length > 16) { - return -E2BIG; - } - readConfigRid(local, 1); - memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); - memcpy(local->config.nodeName, extra, dwrq->length); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Nickname - */ -static int airo_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - strscpy_pad(extra, local->config.nodeName, IW_ESSID_MAX_SIZE); - dwrq->length = strlen(extra); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int airo_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - u8 brate = 0; - int i; - - /* First : get a valid bit rate value */ - readCapabilityRid(local, &cap_rid, 1); - - /* Which type of value ? */ - if ((vwrq->value < 8) && (vwrq->value >= 0)) { - /* Setting by rate index */ - /* Find value in the magic rate table */ - brate = cap_rid.supportedRates[vwrq->value]; - } else { - /* Setting by frequency value */ - u8 normvalue = (u8) (vwrq->value/500000); - - /* Check if rate is valid */ - for (i = 0 ; i < 8 ; i++) { - if (normvalue == cap_rid.supportedRates[i]) { - brate = normvalue; - break; - } - } - } - /* -1 designed the max rate (mostly auto mode) */ - if (vwrq->value == -1) { - /* Get the highest available rate */ - for (i = 0 ; i < 8 ; i++) { - if (cap_rid.supportedRates[i] == 0) - break; - } - if (i != 0) - brate = cap_rid.supportedRates[i - 1]; - } - /* Check that it is valid */ - if (brate == 0) { - return -EINVAL; - } - - readConfigRid(local, 1); - /* Now, check if we want a fixed or auto value */ - if (vwrq->fixed == 0) { - /* Fill all the rates up to this max rate */ - memset(local->config.rates, 0, 8); - for (i = 0 ; i < 8 ; i++) { - local->config.rates[i] = cap_rid.supportedRates[i]; - if (local->config.rates[i] == brate) - break; - } - } else { - /* Fixed mode */ - /* One rate, fixed */ - memset(local->config.rates, 0, 8); - local->config.rates[0] = brate; - } - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int airo_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ret; - - ret = readStatusRid(local, &status_rid, 1); - if (ret) - return -EBUSY; - - vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000; - /* If more than one rate, set auto */ - readConfigRid(local, 1); - vwrq->fixed = (local->config.rates[1] == 0); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int airo_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = AIRO_DEF_MTU; - if ((rthr < 0) || (rthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - readConfigRid(local, 1); - local->config.rtsThres = cpu_to_le16(rthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int airo_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rtsThres); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int airo_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = AIRO_DEF_MTU; - if ((fthr < 256) || (fthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - readConfigRid(local, 1); - local->config.fragThresh = cpu_to_le16(fthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int airo_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.fragThresh); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int airo_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - __u32 mode = uwrq->mode; - struct airo_info *local = dev->ml_priv; - int reset = 0; - - readConfigRid(local, 1); - if (sniffing_mode(local)) - reset = 1; - - switch (mode) { - case IW_MODE_ADHOC: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_IBSS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_INFRA: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MASTER: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_REPEAT: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP_RPTR; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MONITOR: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - local->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &local->flags); - break; - default: - return -EINVAL; - } - if (reset) - set_bit (FLAG_RESET, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int airo_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - /* If not managed, assume it's ad-hoc */ - switch (local->config.opmode & MODE_CFG_MASK) { - case MODE_STA_ESS: - uwrq->mode = IW_MODE_INFRA; - break; - case MODE_AP: - uwrq->mode = IW_MODE_MASTER; - break; - case MODE_AP_RPTR: - uwrq->mode = IW_MODE_REPEAT; - break; - default: - uwrq->mode = IW_MODE_ADHOC; - } - - return 0; -} - -static inline int valid_index(struct airo_info *ai, int index) -{ - return (index >= 0) && (index <= ai->max_wep_idx); -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Encryption Key - */ -static int airo_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int rc = 0; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - wep_key_t key; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index; - - /* Check the size of the key */ - if (dwrq->length > MAX_KEY_SIZE) { - return -EINVAL; - } - - current_index = get_wep_tx_idx(local); - if (current_index < 0) - current_index = 0; - - /* Check the index (none -> use current) */ - if (!valid_index(local, index)) - index = current_index; - - /* Set the length */ - if (dwrq->length > MIN_KEY_SIZE) - key.len = MAX_KEY_SIZE; - else - key.len = MIN_KEY_SIZE; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(key.key, 0, MAX_KEY_SIZE); - /* Copy the key in the driver */ - memcpy(key.key, extra, dwrq->length); - /* Send the key to the card */ - rc = set_wep_key(local, index, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP key at index %d: %d.", - index, rc); - return rc; - } - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if ((index == current_index) && (key.len > 0) && - (local->config.authType == AUTH_OPEN)) - set_auth_type(local, AUTH_ENCRYPT); - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (valid_index(local, index)) { - rc = set_wep_tx_idx(local, index, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP transmit index to %d: %d.", - index, rc); - return rc; - } - } else { - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (dwrq->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (dwrq->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); /* Only Wep */ - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Encryption Key - */ -static int airo_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - dwrq->flags = IW_ENCODE_OPEN; - break; - case AUTH_SHAREDKEY: - dwrq->flags = IW_ENCODE_RESTRICTED; - break; - default: - case AUTH_OPEN: - dwrq->flags = IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - dwrq->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Which key do we want ? -1 -> tx index */ - if (!valid_index(local, index)) { - index = get_wep_tx_idx(local); - if (index < 0) - index = 0; - } - dwrq->flags |= index + 1; - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - dwrq->length = 0; - } else { - dwrq->length = wep_key_len; - memcpy(extra, buf, dwrq->length); - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended Encryption parameters - */ -static int airo_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int perm = (encoding->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int idx, key_len, alg = ext->alg, set_key = 1, rc; - wep_key_t key; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - /* Only set transmit key index here, actual - * key is set below if needed. - */ - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - memset(key.key, 0, MAX_KEY_SIZE); - switch (alg) { - case IW_ENCODE_ALG_NONE: - key.len = 0; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > MIN_KEY_SIZE) { - key.len = MAX_KEY_SIZE; - } else if (ext->key_len > 0) { - key.len = MIN_KEY_SIZE; - } else { - return -EINVAL; - } - key_len = min (ext->key_len, key.len); - memcpy(key.key, ext->key, key_len); - break; - default: - return -EINVAL; - } - if (key.len == 0) { - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - } else { - rc = set_wep_key(local, idx, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP key at index %d: %d.", - idx, rc); - return rc; - } - } - } - - /* Read the flags */ - if (encoding->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (encoding->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (encoding->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended Encryption parameters - */ -static int airo_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len, wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - case AUTH_SHAREDKEY: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - default: - case AUTH_OPEN: - encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - encoding->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - ext->key_len = 0; - } else { - ext->key_len = wep_key_len; - memcpy(extra, buf, ext->key_len); - } - - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended authentication parameters - */ -static int airo_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * airo does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value) { - /* Only change auth type if unencrypted */ - if (currentAuthType == AUTH_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - } else { - set_auth_type(local, AUTH_OPEN); - } - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - set_auth_type(local, AUTH_SHAREDKEY); - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - /* We don't know here if WEP open system or - * unencrypted mode was requested - so use the - * last mode (of these two) used last time - */ - set_auth_type(local, local->last_auth); - } else - return -EINVAL; - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended authentication parameters - */ -static int airo_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - case AUTH_ENCRYPT: - param->value = 1; - break; - default: - param->value = 0; - break; - } - break; - - case IW_AUTH_80211_AUTH_ALG: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - param->value = IW_AUTH_ALG_SHARED_KEY; - break; - case AUTH_ENCRYPT: - default: - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - } - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Tx-Power - */ -static int airo_set_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int rc = -EINVAL; - __le16 v = cpu_to_le16(vwrq->value); - - readCapabilityRid(local, &cap_rid, 1); - - if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags != IW_TXPOW_MWATT) { - return -EINVAL; - } - clear_bit (FLAG_RADIO_OFF, &local->flags); - for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++) - if (v == cap_rid.txPowerLevels[i]) { - readConfigRid(local, 1); - local->config.txPower = v; - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - break; - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Tx-Power - */ -static int airo_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.txPower); - vwrq->fixed = 1; /* No power control */ - vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); - vwrq->flags = IW_TXPOW_MWATT; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Retry limits - */ -static int airo_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - int rc = -EINVAL; - - if (vwrq->disabled) { - return -EINVAL; - } - readConfigRid(local, 1); - if (vwrq->flags & IW_RETRY_LIMIT) { - __le16 v = cpu_to_le16(vwrq->value); - if (vwrq->flags & IW_RETRY_LONG) - local->config.longRetryLimit = v; - else if (vwrq->flags & IW_RETRY_SHORT) - local->config.shortRetryLimit = v; - else { - /* No modifier : set both */ - local->config.longRetryLimit = v; - local->config.shortRetryLimit = v; - } - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags & IW_RETRY_LIFETIME) { - local->config.txLifetime = cpu_to_le16(vwrq->value / 1024); - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Retry limits - */ -static int airo_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - - vwrq->disabled = 0; /* Can't be disabled */ - - readConfigRid(local, 1); - /* Note : by default, display the min retry number */ - if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - vwrq->flags = IW_RETRY_LIFETIME; - vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024; - } else if ((vwrq->flags & IW_RETRY_LONG)) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = le16_to_cpu(local->config.longRetryLimit); - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = le16_to_cpu(local->config.shortRetryLimit); - if (local->config.shortRetryLimit != local->config.longRetryLimit) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int airo_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct iw_range *range = (struct iw_range *) extra; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int k; - - readCapabilityRid(local, &cap_rid, 1); - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(*range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 14; - /* Should be based on cap_rid.country to give only - * what the current card support */ - k = 0; - for (i = 0; i < 14; i++) { - range->freq[k].i = i + 1; /* List index */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i + 1, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */ - } - range->num_frequency = k; - - range->sensitivity = 65535; - - /* Hum... Should put the right values there */ - if (local->rssi) - range->max_qual.qual = 100; /* % */ - else - range->max_qual.qual = airo_get_max_quality(&cap_rid); - range->max_qual.level = 0x100 - 120; /* -120 dBm */ - range->max_qual.noise = 0x100 - 120; /* -120 dBm */ - - /* Experimental measurements - boundary 11/5.5 Mb/s */ - /* Note : with or without the (local->rssi), results - * are somewhat different. - Jean II */ - if (local->rssi) { - range->avg_qual.qual = 50; /* % */ - range->avg_qual.level = 0x100 - 70; /* -70 dBm */ - } else { - range->avg_qual.qual = airo_get_avg_quality(&cap_rid); - range->avg_qual.level = 0x100 - 80; /* -80 dBm */ - } - range->avg_qual.noise = 0x100 - 85; /* -85 dBm */ - - for (i = 0 ; i < 8 ; i++) { - range->bitrate[i] = cap_rid.supportedRates[i] * 500000; - if (range->bitrate[i] == 0) - break; - } - range->num_bitrates = i; - - /* Set an indication of the max TCP throughput - * in bit/s that we can expect using this interface. - * May be use for QoS stuff... Jean II */ - if (i > 2) - range->throughput = 5000 * 1000; - else - range->throughput = 1500 * 1000; - - range->min_rts = 0; - range->max_rts = AIRO_DEF_MTU; - range->min_frag = 256; - range->max_frag = AIRO_DEF_MTU; - - if (cap_rid.softCap & cpu_to_le16(2)) { - // WEP: RC4 40 bits - range->encoding_size[0] = 5; - // RC4 ~128 bits - if (cap_rid.softCap & cpu_to_le16(0x100)) { - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - } else - range->num_encoding_sizes = 1; - range->max_encoding_tokens = - cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1; - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } - range->min_pmp = 0; - range->max_pmp = 5000000; /* 5 secs */ - range->min_pmt = 0; - range->max_pmt = 65535 * 1024; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - - /* Transmit Power - values are in mW */ - for (i = 0 ; i < 8 ; i++) { - range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]); - if (range->txpower[i] == 0) - break; - } - range->num_txpower = i; - range->txpower_capa = IW_TXPOW_MWATT; - range->we_version_source = 19; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 1; - range->max_retry = 65535; - range->min_r_time = 1024; - range->max_r_time = 65535 * 1024; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Power Management - */ -static int airo_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - if (vwrq->disabled) { - if (sniffing_mode(local)) - return -EINVAL; - local->config.powerSaveMode = POWERSAVE_CAM; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - local->config.fastListenInterval = - local->config.listenInterval = - cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } - switch (vwrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ALL_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ON: - /* This is broken, fixme ;-) */ - break; - default: - return -EINVAL; - } - // Note : we may want to factor local->need_commit here - // Note2 : may also want to factor RXMODE_RFMON test - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Power Management - */ -static int airo_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - __le16 mode; - - readConfigRid(local, 1); - mode = local->config.powerSaveMode; - if ((vwrq->disabled = (mode == POWERSAVE_CAM))) - return 0; - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024; - vwrq->flags = IW_POWER_TIMEOUT; - } else { - vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024; - vwrq->flags = IW_POWER_PERIOD; - } - if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR) - vwrq->flags |= IW_POWER_UNICAST_R; - else - vwrq->flags |= IW_POWER_ALL_R; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Sensitivity - */ -static int airo_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - local->config.rssiThreshold = - cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Sensitivity - */ -static int airo_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rssiThreshold); - vwrq->disabled = (vwrq->value == 0); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP List - * Note : this is deprecated in favor of IWSCAN - */ -static int airo_get_aplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct sockaddr *address = (struct sockaddr *) extra; - struct iw_quality *qual; - BSSListRid BSSList; - int i; - int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; - - qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL); - if (!qual) - return -ENOMEM; - - for (i = 0; i < IW_MAX_AP; i++) { - u16 dBm; - if (readBSSListRid(local, loseSync, &BSSList)) - break; - loseSync = 0; - memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - dBm = le16_to_cpu(BSSList.dBm); - if (local->rssi) { - qual[i].level = 0x100 - dBm; - qual[i].qual = airo_dbm_to_pct(local->rssi, dBm); - qual[i].updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - qual[i].level = (dBm + 321) / 2; - qual[i].qual = 0; - qual[i].updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - qual[i].noise = local->wstats.qual.noise; - if (BSSList.index == cpu_to_le16(0xffff)) - break; - } - if (!i) { - StatusRid status_rid; /* Card status info */ - readStatusRid(local, &status_rid, 1); - for (i = 0; - i < min(IW_MAX_AP, 4) && - (status_rid.bssid[i][0] - & status_rid.bssid[i][1] - & status_rid.bssid[i][2] - & status_rid.bssid[i][3] - & status_rid.bssid[i][4] - & status_rid.bssid[i][5])!=0xff && - (status_rid.bssid[i][0] - | status_rid.bssid[i][1] - | status_rid.bssid[i][2] - | status_rid.bssid[i][3] - | status_rid.bssid[i][4] - | status_rid.bssid[i][5]); - i++) { - memcpy(address[i].sa_data, - status_rid.bssid[i], ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - } - } else { - dwrq->flags = 1; /* Should be define'd */ - memcpy(extra + sizeof(struct sockaddr) * i, qual, - sizeof(struct iw_quality) * i); - } - dwrq->length = i; - - kfree(qual); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Initiate Scan - */ -static int airo_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - int wake = 0; - APListRid APList_rid_empty; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - /* If there's already a scan in progress, don't - * trigger another one. */ - if (ai->scan_timeout > 0) - goto out; - - /* Clear APList as it affects scan results */ - memset(&APList_rid_empty, 0, sizeof(APList_rid_empty)); - APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty)); - disable_MAC(ai, 2); - writeAPListRid(ai, &APList_rid_empty, 0); - enable_MAC(ai, 0); - - /* Initiate a scan command */ - ai->scan_timeout = RUN_AT(3*HZ); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - issuecommand(ai, &cmd, &rsp, true); - wake = 1; - -out: - up(&ai->sem); - if (wake) - wake_up_interruptible(&ai->thr_wait); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II - */ -static inline char *airo_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - BSSListRid *bss) -{ - struct airo_info *ai = dev->ml_priv; - struct iw_event iwe; /* Temporary buffer */ - __le16 capabilities; - char * current_val; /* For rates */ - int i; - char * buf; - u16 dBm; - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = bss->ssidLen; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = bss->cap; - if (capabilities & (CAP_ESS | CAP_IBSS)) { - if (capabilities & CAP_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - /* Add frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = 100000 * - ieee80211_channel_to_frequency(iwe.u.freq.m, NL80211_BAND_2GHZ); - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - dBm = le16_to_cpu(bss->dBm); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - if (ai->rssi) { - iwe.u.qual.level = 0x100 - dBm; - iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm); - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - iwe.u.qual.level = (dBm + 321) / 2; - iwe.u.qual.qual = 0; - iwe.u.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - iwe.u.qual.noise = ai->wstats.qual.noise; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & CAP_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Rate : stuffing multiple values in a single event require a bit - * more of magic - Jean II */ - current_val = current_ev + iwe_stream_lcp_len(info); - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 8 values */ - for (i = 0 ; i < 8 ; i++) { - /* NULL terminated */ - if (bss->rates[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000); - /* Add new value to event */ - current_val = iwe_stream_add_value(info, current_ev, - current_val, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - - /* Beacon interval */ - buf = kmalloc(30, GFP_KERNEL); - if (buf) { - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", bss->beaconInterval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - kfree(buf); - } - - /* Put WPA/RSN Information Elements into the event stream */ - if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { - unsigned int num_null_ies = 0; - u16 length = sizeof (bss->extra.iep); - u8 *ie = (void *)&bss->extra.iep; - - while ((length >= 2) && (num_null_ies < 2)) { - if (2 + ie[1] > length) { - /* Invalid element, don't continue parsing IE */ - break; - } - - switch (ie[0]) { - case WLAN_EID_SSID: - /* Two zero-length SSID elements - * mean we're done parsing elements */ - if (!ie[1]) - num_null_ies++; - break; - - case WLAN_EID_VENDOR_SPECIFIC: - if (ie[1] >= 4 && - ie[2] == 0x00 && - ie[3] == 0x50 && - ie[4] == 0xf2 && - ie[5] == 0x01) { - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, - 64); - current_ev = iwe_stream_add_point( - info, current_ev, - end_buf, &iwe, ie); - } - break; - - case WLAN_EID_RSN: - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, 64); - current_ev = iwe_stream_add_point( - info, current_ev, end_buf, - &iwe, ie); - break; - - default: - break; - } - - length -= 2 + ie[1]; - ie += 2 + ie[1]; - } - } - return current_ev; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Read Scan Results - */ -static int airo_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *ai = dev->ml_priv; - BSSListElement *net; - int err = 0; - char *current_ev = extra; - - /* If a scan is in-progress, return -EAGAIN */ - if (ai->scan_timeout > 0) - return -EAGAIN; - - if (down_interruptible(&ai->sem)) - return -EAGAIN; - - list_for_each_entry (net, &ai->network_list, list) { - /* Translate to WE format this entry */ - current_ev = airo_translate_scan(dev, info, current_ev, - extra + dwrq->length, - &net->bss); - - /* Check if there is space for one more entry */ - if ((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - err = -E2BIG; - goto out; - } - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; /* todo */ - -out: - up(&ai->sem); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *wrqu, /* NULL */ - char *extra) /* NULL */ -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit (FLAG_COMMIT, &local->flags)) - return 0; - - /* Some of the "SET" function may have modified some of the - * parameters. It's now time to commit them in the card */ - disable_MAC(local, 1); - if (test_bit (FLAG_RESET, &local->flags)) { - SsidRid SSID_rid; - - readSsidRid(local, &SSID_rid); - if (test_bit(FLAG_MPI,&local->flags)) - setup_card(local, dev, 1); - else - reset_airo_card(dev); - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - writeAPListRid(local, &local->APList, 1); - } - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - writeConfigRid(local, 0); - enable_MAC(local, 0); - if (test_bit (FLAG_RESET, &local->flags)) - airo_set_promisc(local, true); - else - up(&local->sem); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const struct iw_priv_args airo_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_BYTE | 2047, "airoioctl" }, - { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" }, -}; - -static const iw_handler airo_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, airo_config_commit), - IW_HANDLER(SIOCGIWNAME, airo_get_name), - IW_HANDLER(SIOCSIWFREQ, airo_set_freq), - IW_HANDLER(SIOCGIWFREQ, airo_get_freq), - IW_HANDLER(SIOCSIWMODE, airo_set_mode), - IW_HANDLER(SIOCGIWMODE, airo_get_mode), - IW_HANDLER(SIOCSIWSENS, airo_set_sens), - IW_HANDLER(SIOCGIWSENS, airo_get_sens), - IW_HANDLER(SIOCGIWRANGE, airo_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, airo_set_wap), - IW_HANDLER(SIOCGIWAP, airo_get_wap), - IW_HANDLER(SIOCGIWAPLIST, airo_get_aplist), - IW_HANDLER(SIOCSIWSCAN, airo_set_scan), - IW_HANDLER(SIOCGIWSCAN, airo_get_scan), - IW_HANDLER(SIOCSIWESSID, airo_set_essid), - IW_HANDLER(SIOCGIWESSID, airo_get_essid), - IW_HANDLER(SIOCSIWNICKN, airo_set_nick), - IW_HANDLER(SIOCGIWNICKN, airo_get_nick), - IW_HANDLER(SIOCSIWRATE, airo_set_rate), - IW_HANDLER(SIOCGIWRATE, airo_get_rate), - IW_HANDLER(SIOCSIWRTS, airo_set_rts), - IW_HANDLER(SIOCGIWRTS, airo_get_rts), - IW_HANDLER(SIOCSIWFRAG, airo_set_frag), - IW_HANDLER(SIOCGIWFRAG, airo_get_frag), - IW_HANDLER(SIOCSIWTXPOW, airo_set_txpow), - IW_HANDLER(SIOCGIWTXPOW, airo_get_txpow), - IW_HANDLER(SIOCSIWRETRY, airo_set_retry), - IW_HANDLER(SIOCGIWRETRY, airo_get_retry), - IW_HANDLER(SIOCSIWENCODE, airo_set_encode), - IW_HANDLER(SIOCGIWENCODE, airo_get_encode), - IW_HANDLER(SIOCSIWPOWER, airo_set_power), - IW_HANDLER(SIOCGIWPOWER, airo_get_power), - IW_HANDLER(SIOCSIWAUTH, airo_set_auth), - IW_HANDLER(SIOCGIWAUTH, airo_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, airo_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, airo_get_encodeext), -}; - -/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. - * We want to force the use of the ioctl code, because those can't be - * won't work the iw_handler code (because they simultaneously read - * and write data and iw_handler can't do that). - * Note that it's perfectly legal to read/write on a single ioctl command, - * you just can't use iwpriv and need to force it via the ioctl handler. - * Jean II */ -static const iw_handler airo_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -static const struct iw_handler_def airo_handler_def = -{ - .num_standard = ARRAY_SIZE(airo_handler), - .num_private = ARRAY_SIZE(airo_private_handler), - .num_private_args = ARRAY_SIZE(airo_private_args), - .standard = airo_handler, - .private = airo_private_handler, - .private_args = airo_private_args, - .get_wireless_stats = airo_get_wireless_stats, -}; - -/* - * This defines the configuration part of the Wireless Extensions - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check input value more carefully and fill correct values in range - * o Test and shakeout the bugs (if any) - * - * Jean II - * - * Javier Achirica did a great job of merging code from the unnamed CISCO - * developer that added support for flashing the card. - */ -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, - void __user *data, int cmd) -{ - int rc = 0; - struct airo_info *ai = dev->ml_priv; - - if (ai->power.event) - return 0; - - switch (cmd) { -#ifdef CISCO_EXT - case AIROIDIFC: -#ifdef AIROOLDIDIFC - case AIROOLDIDIFC: -#endif - { - int val = AIROMAGIC; - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) - rc = -EFAULT; - else if (copy_to_user(com.data, (char *)&val, sizeof(val))) - rc = -EFAULT; - } - break; - - case AIROIOCTL: -#ifdef AIROOLDIOCTL - case AIROOLDIOCTL: -#endif - /* Get the command struct and hand it off for evaluation by - * the proper subfunction - */ - { - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) { - rc = -EFAULT; - break; - } - - /* Separate R/W functions bracket legality here - */ - if (com.command == AIRORSWVERSION) { - if (copy_to_user(com.data, swversion, sizeof(swversion))) - rc = -EFAULT; - else - rc = 0; - } - else if (com.command <= AIRORRID) - rc = readrids(dev,&com); - else if (com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2)) - rc = writerids(dev,&com); - else if (com.command >= AIROFLSHRST && com.command <= AIRORESTART) - rc = flashcard(dev,&com); - else - rc = -EINVAL; /* Bad command in ioctl */ - } - break; -#endif /* CISCO_EXT */ - - // All other calls are currently unsupported - default: - rc = -EOPNOTSUPP; - } - return rc; -} - -/* - * Get the Wireless stats out of the driver - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs) - * - * Jean - */ -static void airo_read_wireless_stats(struct airo_info *local) -{ - StatusRid status_rid; - StatsRid stats_rid; - CapabilityRid cap_rid; - __le32 *vals = stats_rid.vals; - - /* Get stats out of the card */ - if (local->power.event) - return; - - readCapabilityRid(local, &cap_rid, 0); - readStatusRid(local, &status_rid, 0); - readStatsRid(local, &stats_rid, RID_STATS, 0); - - /* The status */ - local->wstats.status = le16_to_cpu(status_rid.mode); - - /* Signal quality and co */ - if (local->rssi) { - local->wstats.qual.level = - airo_rssi_to_dbm(local->rssi, - le16_to_cpu(status_rid.sigQuality)); - /* normalizedSignalStrength appears to be a percentage */ - local->wstats.qual.qual = - le16_to_cpu(status_rid.normalizedSignalStrength); - } else { - local->wstats.qual.level = - (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2; - local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); - } - if (le16_to_cpu(status_rid.len) >= 124) { - local->wstats.qual.noise = 0x100 - status_rid.noisedBm; - local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } else { - local->wstats.qual.noise = 0; - local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM; - } - - /* Packets discarded in the wireless adapter due to wireless - * specific problems */ - local->wstats.discard.nwid = le32_to_cpu(vals[56]) + - le32_to_cpu(vals[57]) + - le32_to_cpu(vals[58]); /* SSID Mismatch */ - local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */ - local->wstats.discard.fragment = le32_to_cpu(vals[30]); - local->wstats.discard.retries = le32_to_cpu(vals[10]); - local->wstats.discard.misc = le32_to_cpu(vals[1]) + - le32_to_cpu(vals[32]); - local->wstats.miss.beacon = le32_to_cpu(vals[34]); -} - -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!down_interruptible(&local->sem)) { - airo_read_wireless_stats(local); - up(&local->sem); - } - return &local->wstats; -} - -#ifdef CISCO_EXT -/* - * This just translates from driver IOCTL codes to the command codes to - * feed to the radio's host interface. Things can be added/deleted - * as needed. This represents the READ side of control I/O to - * the card - */ -static int readrids(struct net_device *dev, aironet_ioctl *comp) -{ - unsigned short ridcode; - unsigned char *iobuf; - int len; - struct airo_info *ai = dev->ml_priv; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - switch(comp->command) - { - case AIROGCAP: ridcode = RID_CAPABILITIES; break; - case AIROGCFG: ridcode = RID_CONFIG; - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC (ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - } - break; - case AIROGSLIST: ridcode = RID_SSID; break; - case AIROGVLIST: ridcode = RID_APLIST; break; - case AIROGDRVNAM: ridcode = RID_DRVNAME; break; - case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; - case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break; - case AIROGWEPKNV: ridcode = RID_WEP_PERM; break; - case AIROGSTAT: ridcode = RID_STATUS; break; - case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; - case AIROGSTATSC32: ridcode = RID_STATS; break; - case AIROGMICSTATS: - if (copy_to_user(comp->data, &ai->micstats, - min((int)comp->len, (int)sizeof(ai->micstats)))) - return -EFAULT; - return 0; - case AIRORRID: ridcode = comp->ridnum; break; - default: - return -EINVAL; - } - - if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) { - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, ridcode, iobuf, RIDSIZE, 1); - /* get the count of bytes in the rid docs say 1st 2 bytes is it. - * then return it to the user - * 9/22/2000 Honor user given length - */ - len = comp->len; - - if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; -} - -/* - * Danger Will Robinson write the rids here - */ - -static int writerids(struct net_device *dev, aironet_ioctl *comp) -{ - struct airo_info *ai = dev->ml_priv; - int ridcode; - int enabled; - int (*writer)(struct airo_info *, u16 rid, const void *, int, int); - unsigned char *iobuf; - - /* Only super-user can write RIDs */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - ridcode = 0; - writer = do_writerid; - - switch(comp->command) - { - case AIROPSIDS: ridcode = RID_SSID; break; - case AIROPCAP: ridcode = RID_CAPABILITIES; break; - case AIROPAPLIST: ridcode = RID_APLIST; break; - case AIROPCFG: ai->config.len = 0; - clear_bit(FLAG_COMMIT, &ai->flags); - ridcode = RID_CONFIG; break; - case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; - case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; - case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break; - case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid; - break; - case AIROPLEAPUSR+1: ridcode = 0xFF2A; break; - case AIROPLEAPUSR+2: ridcode = 0xFF2B; break; - - /* this is not really a rid but a command given to the card - * same with MAC off - */ - case AIROPMACON: - if (enable_MAC(ai, 1) != 0) - return -EIO; - return 0; - - /* - * Evidently this code in the airo driver does not get a symbol - * as disable_MAC. it's probably so short the compiler does not gen one. - */ - case AIROPMACOFF: - disable_MAC(ai, 1); - return 0; - - /* This command merely clears the counts does not actually store any data - * only reads rid. But as it changes the cards state, I put it in the - * writerid routines. - */ - case AIROPSTCLR: - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, RID_STATSDELTACLEAR, iobuf, RIDSIZE, 1); - - enabled = ai->micstats.enabled; - memset(&ai->micstats, 0, sizeof(ai->micstats)); - ai->micstats.enabled = enabled; - - if (copy_to_user(comp->data, iobuf, - min((int)comp->len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; - - default: - return -EOPNOTSUPP; /* Blarg! */ - } - if (comp->len > RIDSIZE) - return -EINVAL; - - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if (copy_from_user(iobuf, comp->data, comp->len)) { - kfree (iobuf); - return -EFAULT; - } - - if (comp->command == AIROPCFG) { - ConfigRid *cfg = (ConfigRid *)iobuf; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) - cfg->opmode |= MODE_MIC; - - if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit (FLAG_ADHOC, &ai->flags); - else - clear_bit (FLAG_ADHOC, &ai->flags); - } - - if ((*writer)(ai, ridcode, iobuf, comp->len, 1)) { - kfree (iobuf); - return -EIO; - } - kfree (iobuf); - return 0; -} - -/***************************************************************************** - * Ancillary flash / mod functions much black magic lurkes here * - ***************************************************************************** - */ - -/* - * Flash command switch table - */ - -static int flashcard(struct net_device *dev, aironet_ioctl *comp) -{ - int z; - - /* Only super-user can modify flash */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(comp->command) - { - case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->ml_priv); - - case AIROFLSHSTFL: - if (!AIRO_FLASH(dev) && - (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - return setflashmode((struct airo_info *)dev->ml_priv); - - case AIROFLSHGCHR: /* Get char from aux */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLSHPCHR: /* Send char to card. */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLPUTBUF: /* Send 32k to card */ - if (!AIRO_FLASH(dev)) - return -ENOMEM; - if (comp->len > FLASHSIZE) - return -EINVAL; - if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) - return -EFAULT; - - flashputbuf((struct airo_info *)dev->ml_priv); - return 0; - - case AIRORESTART: - if (flashrestart((struct airo_info *)dev->ml_priv, dev)) - return -EIO; - return 0; - } - return -EINVAL; -} - -#define FLASH_COMMAND 0x7e7e - -/* - * STEP 1) - * Disable MAC and do soft reset on - * card. - */ - -static int cmdreset(struct airo_info *ai) -{ - disable_MAC(ai, 1); - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang before RESET"); - return -EBUSY; - } - - OUT4500(ai, COMMAND, CMD_SOFTRESET); - - ssleep(1); /* WAS 600 12/7/00 */ - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET"); - return -EBUSY; - } - return 0; -} - -/* STEP 2) - * Put the card in legendary flash - * mode - */ - -static int setflashmode (struct airo_info *ai) -{ - set_bit (FLAG_FLASHING, &ai->flags); - - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, SWS1, FLASH_COMMAND); - if (probe) { - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0x10); - } else { - OUT4500(ai, SWS2, FLASH_COMMAND); - OUT4500(ai, SWS3, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0); - } - msleep(500); /* 500ms delay */ - - if (!waitbusy(ai)) { - clear_bit (FLAG_FLASHING, &ai->flags); - airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode"); - return -EIO; - } - return 0; -} - -/* Put character to SWS0 wait for dwelltime - * x 50us for echo . - */ - -static int flashpchar(struct airo_info *ai, int byte, int dwelltime) -{ - int echo; - int waittime; - - byte |= 0x8000; - - if (dwelltime == 0) - dwelltime = 200; - - waittime = dwelltime; - - /* Wait for busy bit d15 to go false indicating buffer empty */ - while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) { - udelay (50); - waittime -= 50; - } - - /* timeout for busy clear wait */ - if (waittime <= 0) { - airo_print_info(ai->dev->name, "flash putchar busywait timeout!"); - return -EBUSY; - } - - /* Port is clear now write byte and wait for it to echo back */ - do { - OUT4500(ai, SWS0, byte); - udelay(50); - dwelltime -= 50; - echo = IN4500(ai, SWS1); - } while (dwelltime >= 0 && echo != byte); - - OUT4500(ai, SWS1, 0); - - return (echo == byte) ? 0 : -EIO; -} - -/* - * Get a character from the card matching matchbyte - * Step 3) - */ -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime) -{ - int rchar; - unsigned char rbyte = 0; - - do { - rchar = IN4500(ai, SWS1); - - if (dwelltime && !(0x8000 & rchar)) { - dwelltime -= 10; - mdelay(10); - continue; - } - rbyte = 0xff & rchar; - - if ((rbyte == matchbyte) && (0x8000 & rchar)) { - OUT4500(ai, SWS1, 0); - return 0; - } - if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) - break; - OUT4500(ai, SWS1, 0); - - } while (dwelltime > 0); - return -EIO; -} - -/* - * Transfer 32k of firmware data from user buffer to our buffer and - * send to the card - */ - -static int flashputbuf(struct airo_info *ai) -{ - int nwords; - - /* Write stuff */ - if (test_bit(FLAG_MPI,&ai->flags)) - memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); - else { - OUT4500(ai, AUXPAGE, 0x100); - OUT4500(ai, AUXOFF, 0); - - for (nwords = 0; nwords != FLASHSIZE / 2; nwords++) { - OUT4500(ai, AUXDATA, ai->flash[nwords] & 0xffff); - } - } - OUT4500(ai, SWS0, 0x8000); - - return 0; -} - -/* - * - */ -static int flashrestart(struct airo_info *ai, struct net_device *dev) -{ - int i, status; - - ssleep(1); /* Added 12/7/00 */ - clear_bit (FLAG_FLASHING, &ai->flags); - if (test_bit(FLAG_MPI, &ai->flags)) { - status = mpi_init_descriptors(ai); - if (status != SUCCESS) - return status; - } - status = setup_card(ai, dev, 1); - - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) { - ai->fids[i] = transmit_allocate - (ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2); - } - - ssleep(1); /* Added 12/7/00 */ - return status; -} -#endif /* CISCO_EXT */ - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -module_init(airo_init_module); -module_exit(airo_cleanup_module); diff --git a/drivers/net/wireless/cisco/airo.h b/drivers/net/wireless/cisco/airo.h deleted file mode 100644 index 8a02977a2e2b..000000000000 --- a/drivers/net/wireless/cisco/airo.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _AIRO_H_ -#define _AIRO_H_ - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev); -int reset_airo_card(struct net_device *dev); -void stop_airo_card(struct net_device *dev, int freeres); - -#endif /* _AIRO_H_ */ diff --git a/drivers/net/wireless/cisco/airo_cs.c b/drivers/net/wireless/cisco/airo_cs.c deleted file mode 100644 index fcfe4c6d62f0..000000000000 --- a/drivers/net/wireless/cisco/airo_cs.c +++ /dev/null @@ -1,218 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. - - In addition this module was derived from dummy_cs. - The initial developer of dummy_cs is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -======================================================================*/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "airo.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet " - "cards. This is the module that links the PCMCIA card " - "with the airo module."); -MODULE_LICENSE("Dual BSD/GPL"); - -/*====================================================================*/ - -static int airo_config(struct pcmcia_device *link); -static void airo_release(struct pcmcia_device *link); - -static void airo_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int airo_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - - dev_dbg(&p_dev->dev, "airo_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - return airo_config(p_dev); -} /* airo_attach */ - -static void airo_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_detach\n"); - - airo_release(link); - - if (((struct local_info *)link->priv)->eth_dev) { - stop_airo_card(((struct local_info *)link->priv)->eth_dev, - 0); - } - ((struct local_info *)link->priv)->eth_dev = NULL; - - kfree(link->priv); -} /* airo_detach */ - -static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - - -static int airo_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "airo_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, airo_cs_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - ((struct local_info *)link->priv)->eth_dev = - init_airo_card(link->irq, - link->resource[0]->start, 1, &link->dev); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - return 0; - - failed: - airo_release(link); - return -ENODEV; -} /* airo_config */ - -static void airo_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_release\n"); - pcmcia_disable_device(link); -} - -static int airo_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int airo_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - if (link->open) { - reset_airo_card(local->eth_dev); - netif_device_attach(local->eth_dev); - } - - return 0; -} - -static const struct pcmcia_device_id airo_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007), - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, airo_ids); - -static struct pcmcia_driver airo_driver = { - .owner = THIS_MODULE, - .name = "airo_cs", - .probe = airo_probe, - .remove = airo_detach, - .id_table = airo_ids, - .suspend = airo_suspend, - .resume = airo_resume, -}; -module_pcmcia_driver(airo_driver); - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ From d0172d5f7576ed6c3f73622ca4c16ba63c49da4e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:46 +0200 Subject: [PATCH 0155/7721] wifi: remove obsolete hostap driver HostAP is an ISA/PCMCIA style 802.11b driver supporting only wireless extensions, and some custom ioctls (already removed). Some devices include a legacy PCI bridge but no DMA. The driver was marked obsolete in 2016 and is highly unlikely to still have any users. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 5 - drivers/net/wireless/intersil/Kconfig | 1 - drivers/net/wireless/intersil/Makefile | 1 - drivers/net/wireless/intersil/hostap/Kconfig | 95 - drivers/net/wireless/intersil/hostap/Makefile | 8 - drivers/net/wireless/intersil/hostap/hostap.h | 98 - .../wireless/intersil/hostap/hostap_80211.h | 97 - .../intersil/hostap/hostap_80211_rx.c | 1116 ----- .../intersil/hostap/hostap_80211_tx.c | 554 --- .../net/wireless/intersil/hostap/hostap_ap.c | 3277 -------------- .../net/wireless/intersil/hostap/hostap_ap.h | 264 -- .../wireless/intersil/hostap/hostap_common.h | 420 -- .../wireless/intersil/hostap/hostap_config.h | 49 - .../net/wireless/intersil/hostap/hostap_cs.c | 710 --- .../intersil/hostap/hostap_download.c | 810 ---- .../net/wireless/intersil/hostap/hostap_hw.c | 3387 --------------- .../wireless/intersil/hostap/hostap_info.c | 509 --- .../wireless/intersil/hostap/hostap_ioctl.c | 3847 ----------------- .../wireless/intersil/hostap/hostap_main.c | 1123 ----- .../net/wireless/intersil/hostap/hostap_pci.c | 445 -- .../net/wireless/intersil/hostap/hostap_plx.c | 617 --- .../wireless/intersil/hostap/hostap_proc.c | 411 -- .../wireless/intersil/hostap/hostap_wlan.h | 1051 ----- 23 files changed, 18895 deletions(-) delete mode 100644 drivers/net/wireless/intersil/hostap/Kconfig delete mode 100644 drivers/net/wireless/intersil/hostap/Makefile delete mode 100644 drivers/net/wireless/intersil/hostap/hostap.h delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211.h delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_rx.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_tx.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.h delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_common.h delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_config.h delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_cs.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_download.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_hw.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_info.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ioctl.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_main.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_pci.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_plx.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_proc.c delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_wlan.h diff --git a/MAINTAINERS b/MAINTAINERS index 1693d50b4260..53aac5fa5de1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9553,11 +9553,6 @@ S: Maintained F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml F: drivers/iio/pressure/mprls0025pa.c -HOST AP DRIVER -L: linux-wireless@vger.kernel.org -S: Obsolete -F: drivers/net/wireless/intersil/hostap/ - HP BIOSCFG DRIVER M: Jorge Lopez L: platform-driver-x86@vger.kernel.org diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index bd6bf70ece03..f2455ef45d99 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -12,7 +12,6 @@ config WLAN_VENDOR_INTERSIL if WLAN_VENDOR_INTERSIL -source "drivers/net/wireless/intersil/hostap/Kconfig" source "drivers/net/wireless/intersil/orinoco/Kconfig" source "drivers/net/wireless/intersil/p54/Kconfig" diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile index 65281d1b3d85..773147110c54 100644 --- a/drivers/net/wireless/intersil/Makefile +++ b/drivers/net/wireless/intersil/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig deleted file mode 100644 index 2edff8efbcbb..000000000000 --- a/drivers/net/wireless/intersil/hostap/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HOSTAP - tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_MICHAEL_MIC - select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP - help - Shared driver code for IEEE 802.11b wireless cards based on - Intersil Prism2/2.5/3 chipset. This driver supports so called - Host AP mode that allows the card to act as an IEEE 802.11 - access point. - - See for more information about the - Host AP driver configuration and tools. This site includes - information and tools (hostapd and wpa_supplicant) for WPA/WPA2 - support. - - This option includes the base Host AP driver code that is shared by - different hardware models. You will also need to enable support for - PLX/PCI/CS version of the driver to actually use the driver. - - The driver can be compiled as a module and it will be called - hostap. - -config HOSTAP_FIRMWARE - bool "Support downloading firmware images with Host AP driver" - depends on HOSTAP - help - Configure Host AP driver to include support for firmware image - download. This option by itself only enables downloading to the - volatile memory, i.e. the card RAM. This option is required to - support cards that don't have firmware in flash, such as D-Link - DWL-520 rev E and D-Link DWL-650 rev P. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_FIRMWARE_NVRAM - bool "Support for non-volatile firmware download" - depends on HOSTAP_FIRMWARE - help - Allow Host AP driver to write firmware images to the non-volatile - card memory, i.e. flash memory that survives power cycling. - Enable this option if you want to be able to change card firmware - permanently. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_PLX - tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" - depends on PCI && HOSTAP && HAS_IOPORT - help - Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based - PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_plx. - -config HOSTAP_PCI - tristate "Host AP driver for Prism2.5 PCI adaptors" - depends on PCI && HOSTAP - help - Host AP driver's version for Prism2.5 PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_pci. - -config HOSTAP_CS - tristate "Host AP driver for Prism2/2.5/3 PC Cards" - depends on PCMCIA && HOSTAP - help - Host AP driver's version for Prism2/2.5/3 PC Cards. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_cs. diff --git a/drivers/net/wireless/intersil/hostap/Makefile b/drivers/net/wireless/intersil/hostap/Makefile deleted file mode 100644 index ae3bb73b2d99..000000000000 --- a/drivers/net/wireless/intersil/hostap/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \ - hostap_ioctl.o hostap_main.o hostap_proc.o -obj-$(CONFIG_HOSTAP) += hostap.o - -obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o -obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o -obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h deleted file mode 100644 index 552ae33d7875..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap.h +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_H -#define HOSTAP_H - -#include -#include - -#include "hostap_wlan.h" -#include "hostap_ap.h" - -static const long __maybe_unused freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; -#define FREQ_COUNT ARRAY_SIZE(freq_list) - -/* hostap.c */ - -extern struct proc_dir_entry *hostap_proc; - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data); -int hostap_tx_callback_unregister(local_info_t *local, u16 idx); -int hostap_set_word(struct net_device *dev, int rid, u16 val); -int hostap_set_string(struct net_device *dev, int rid, const char *val); -u16 hostap_get_porttype(local_info_t *local); -int hostap_set_encryption(local_info_t *local); -int hostap_set_antsel(local_info_t *local); -int hostap_set_roaming(local_info_t *local); -int hostap_set_auth_algs(local_info_t *local); -void hostap_dump_rx_header(const char *name, - const struct hfa384x_rx_frame *rx); -void hostap_dump_tx_header(const char *name, - const struct hfa384x_tx_frame *tx); -extern const struct header_ops hostap_80211_ops; -int hostap_80211_get_hdrlen(__le16 fc); -struct net_device_stats *hostap_get_stats(struct net_device *dev); -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type); -void hostap_set_multicast_list_queue(struct work_struct *work); -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); -void hostap_cleanup(local_info_t *local); -void hostap_cleanup_handler(void *data); -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, const char *name); -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list); -int prism2_update_comms_qual(struct net_device *dev); -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen); -int prism2_sta_deauth(local_info_t *local, u16 reason); -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked); -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove); - - -/* hostap_ap.c */ - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); -void ap_control_kickall(struct ap_data *ap); -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt); -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist); -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer); -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); - - -/* hostap_proc.c */ - -void hostap_init_proc(local_info_t *local); -void hostap_remove_proc(local_info_t *local); - - -/* hostap_info.c */ - -void hostap_info_init(local_info_t *local); -void hostap_info_process(local_info_t *local, struct sk_buff *skb); - - -/* hostap_ioctl.c */ - -extern const struct iw_handler_def hostap_iw_handler_def; -extern const struct ethtool_ops prism2_ethtool_ops; - -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); - -#endif /* HOSTAP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211.h b/drivers/net/wireless/intersil/hostap/hostap_80211.h deleted file mode 100644 index 1452cf6ecb07..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211.h +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_80211_H -#define HOSTAP_80211_H - -#include -#include -#include - -struct hostap_ieee80211_mgmt { - __le16 frame_control; - __le16 duration; - u8 da[6]; - u8 sa[6]; - u8 bssid[6]; - __le16 seq_ctrl; - union { - struct { - __le16 auth_alg; - __le16 auth_transaction; - __le16 status_code; - /* possibly followed by Challenge text */ - u8 variable[0]; - } __packed auth; - struct { - __le16 reason_code; - } __packed deauth; - struct { - __le16 capab_info; - __le16 listen_interval; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed assoc_req; - struct { - __le16 capab_info; - __le16 status_code; - __le16 aid; - /* followed by Supported rates */ - u8 variable[0]; - } __packed assoc_resp, reassoc_resp; - struct { - __le16 capab_info; - __le16 listen_interval; - u8 current_ap[6]; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed reassoc_req; - struct { - __le16 reason_code; - } __packed disassoc; - struct { - } __packed probe_req; - struct { - u8 timestamp[8]; - __le16 beacon_int; - __le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params, TIM */ - u8 variable[0]; - } __packed beacon, probe_resp; - } u; -} __packed; - - -#define IEEE80211_MGMT_HDR_LEN 24 -#define IEEE80211_DATA_HDR3_LEN 24 -#define IEEE80211_DATA_HDR4_LEN 30 - - -struct hostap_80211_rx_status { - u32 mac_time; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ -}; - -/* prism2_rx_80211 'type' argument */ -enum { - PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, - PRISM2_RX_NULLFUNC_ACK -}; - -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type); -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev); - -#endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c deleted file mode 100644 index 61be822f90b5..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c +++ /dev/null @@ -1,1116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " - "jiffies=%ld\n", - name, rx_stats->signal, rx_stats->noise, rx_stats->rate, - skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* Send RX frame to netif with 802.11 (and possible prism) header. - * Called from hardware or software IRQ context. */ -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type) -{ - struct hostap_interface *iface; - local_info_t *local; - int hdrlen, phdrlen, head_need, tail_need; - u16 fc; - int prism_header, ret; - struct ieee80211_hdr *fhdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (dev->type == ARPHRD_IEEE80211_PRISM) { - if (local->monitor_type == PRISM2_MONITOR_PRISM) { - prism_header = 1; - phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); - } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ - prism_header = 2; - phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); - } - } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { - prism_header = 3; - phdrlen = sizeof(struct hostap_radiotap_rx); - } else { - prism_header = 0; - phdrlen = 0; - } - - fhdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(fhdr->frame_control); - - if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { - printk(KERN_DEBUG "%s: dropped management frame with header " - "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); - dev_kfree_skb_any(skb); - return 0; - } - - hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control); - - /* check if there is enough room for extra data; if not, expand skb - * buffer to be large enough for the changes */ - head_need = phdrlen; - tail_need = 0; -#ifdef PRISM2_ADD_BOGUS_CRC - tail_need += 4; -#endif /* PRISM2_ADD_BOGUS_CRC */ - - head_need -= skb_headroom(skb); - tail_need -= skb_tailroom(skb); - - if (head_need > 0 || tail_need > 0) { - if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, - tail_need > 0 ? tail_need : 0, - GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " - "reallocate skb buffer\n", dev->name); - dev_kfree_skb_any(skb); - return 0; - } - } - - /* We now have an skb with enough head and tail room, so just insert - * the extra data */ - -#ifdef PRISM2_ADD_BOGUS_CRC - memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ -#endif /* PRISM2_ADD_BOGUS_CRC */ - - if (prism_header == 1) { - struct linux_wlan_ng_prism_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->msgcode = LWNG_CAP_DID_BASE; - hdr->msglen = sizeof(*hdr); - memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); -#define LWNG_SETVAL(f,i,s,l,d) \ -hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ -hdr->f.status = s; hdr->f.len = l; hdr->f.data = d - LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); - LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); - LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); - LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); - LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); - LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); - LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); - LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); - LWNG_SETVAL(istx, 9, 0, 4, 0); - LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); -#undef LWNG_SETVAL - } else if (prism_header == 2) { - struct linux_wlan_ng_cap_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->version = htonl(LWNG_CAPHDR_VERSION); - hdr->length = htonl(phdrlen); - hdr->mactime = __cpu_to_be64(rx_stats->mac_time); - hdr->hosttime = __cpu_to_be64(jiffies); - hdr->phytype = htonl(4); /* dss_dot11_b */ - hdr->channel = htonl(local->channel); - hdr->datarate = htonl(rx_stats->rate); - hdr->antenna = htonl(0); /* unknown */ - hdr->priority = htonl(0); /* unknown */ - hdr->ssi_type = htonl(3); /* raw */ - hdr->ssi_signal = htonl(rx_stats->signal); - hdr->ssi_noise = htonl(rx_stats->noise); - hdr->preamble = htonl(0); /* unknown */ - hdr->encoding = htonl(1); /* cck */ - } else if (prism_header == 3) { - struct hostap_radiotap_rx *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->hdr.it_len = cpu_to_le16(phdrlen); - hdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); - hdr->tsft = cpu_to_le64(rx_stats->mac_time); - hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); - hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); - hdr->rate = rx_stats->rate / 5; - hdr->dbm_antsignal = rx_stats->signal; - hdr->dbm_antnoise = rx_stats->noise; - } - - ret = skb->len - phdrlen; - skb->dev = dev; - skb_reset_mac_header(skb); - skb_pull(skb, hdrlen); - if (prism_header) - skb_pull(skb, phdrlen); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void monitor_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - int len; - - len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct prism2_frag_entry * -prism2_frag_cache_find(local_info_t *local, unsigned int seq, - unsigned int frag, u8 *src, u8 *dst) -{ - struct prism2_frag_entry *entry; - int i; - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - entry = &local->frag_cache[i]; - if (entry->skb != NULL && - time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - printk(KERN_DEBUG "%s: expiring fragment cache entry " - "seq=%u last_frag=%u\n", - local->dev->name, entry->seq, entry->last_frag); - dev_kfree_skb(entry->skb); - entry->skb = NULL; - } - - if (entry->skb != NULL && entry->seq == seq && - (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) - return entry; - } - - return NULL; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sk_buff *skb = NULL; - u16 sc; - unsigned int frag, seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - if (frag == 0) { - /* Reserve enough space to fit maximum frame length */ - skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + - 8 /* LLC */ + - 2 /* alignment */ + - 8 /* WEP */ + ETH_ALEN /* WDS */); - if (skb == NULL) - return NULL; - - entry = &local->frag_cache[local->frag_next_idx]; - local->frag_next_idx++; - if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) - local->frag_next_idx = 0; - - if (entry->skb != NULL) - dev_kfree_skb(entry->skb); - - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->last_frag = frag; - entry->skb = skb; - memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); - memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); - } else { - /* received a fragment of a frame for which the head fragment - * should have already been received */ - entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, - hdr->addr1); - if (entry != NULL) { - entry->last_frag = frag; - skb = entry->skb; - } - } - - return skb; -} - - -/* Called only as a tasklet (software IRQ) */ -static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - u16 sc; - unsigned int seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); - - if (entry == NULL) { - printk(KERN_DEBUG "%s: could not invalidate fragment cache " - "entry (seq=%u)\n", - local->dev->name, seq); - return -1; - } - - entry->skb = NULL; - return 0; -} - - -static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct list_head *ptr; - struct hostap_bss_info *bss; - - list_for_each(ptr, &local->bss_list) { - bss = list_entry(ptr, struct hostap_bss_info, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && - (ssid == NULL || - (ssid_len == bss->ssid_len && - memcmp(ssid, bss->ssid, ssid_len) == 0))) { - list_move(&bss->list, &local->bss_list); - return bss; - } - } - - return NULL; -} - - -static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct hostap_bss_info *bss; - - if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - list_del(&bss->list); - local->num_bss_info--; - } else { - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); - if (bss == NULL) - return NULL; - } - - memset(bss, 0, sizeof(*bss)); - memcpy(bss->bssid, bssid, ETH_ALEN); - memcpy(bss->ssid, ssid, ssid_len); - bss->ssid_len = ssid_len; - local->num_bss_info++; - list_add(&bss->list, &local->bss_list); - return bss; -} - - -static void __hostap_expire_bss(local_info_t *local) -{ - struct hostap_bss_info *bss; - - while (local->num_bss_info > 0) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - if (!time_after(jiffies, bss->last_update + 60 * HZ)) - break; - - list_del(&bss->list); - local->num_bss_info--; - kfree(bss); - } -} - - -/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so - * the same routine can be used to parse both of them. */ -static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, - int stype) -{ - struct hostap_ieee80211_mgmt *mgmt; - int left, chan = 0; - u8 *pos; - u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; - size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; - struct hostap_bss_info *bss; - - if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) - return; - - mgmt = (struct hostap_ieee80211_mgmt *) skb->data; - pos = mgmt->u.beacon.variable; - left = skb->len - (pos - skb->data); - - while (left >= 2) { - if (2 + pos[1] > left) - return; /* parse failed */ - switch (*pos) { - case WLAN_EID_SSID: - ssid = pos + 2; - ssid_len = pos[1]; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (pos[1] >= 4 && - pos[2] == 0x00 && pos[3] == 0x50 && - pos[4] == 0xf2 && pos[5] == 1) { - wpa = pos; - wpa_len = pos[1] + 2; - } - break; - case WLAN_EID_RSN: - rsn = pos; - rsn_len = pos[1] + 2; - break; - case WLAN_EID_DS_PARAMS: - if (pos[1] >= 1) - chan = pos[2]; - break; - } - left -= 2 + pos[1]; - pos += 2 + pos[1]; - } - - if (wpa_len > MAX_WPA_IE_LEN) - wpa_len = MAX_WPA_IE_LEN; - if (rsn_len > MAX_WPA_IE_LEN) - rsn_len = MAX_WPA_IE_LEN; - if (ssid_len > sizeof(bss->ssid)) - ssid_len = sizeof(bss->ssid); - - spin_lock(&local->lock); - bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss == NULL) - bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss) { - bss->last_update = jiffies; - bss->count++; - bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); - if (wpa) { - memcpy(bss->wpa_ie, wpa, wpa_len); - bss->wpa_ie_len = wpa_len; - } else - bss->wpa_ie_len = 0; - if (rsn) { - memcpy(bss->rsn_ie, rsn, rsn_len); - bss->rsn_ie_len = rsn_len; - } else - bss->rsn_ie_len = 0; - bss->chan = chan; - } - __hostap_expire_bss(local); - spin_unlock(&local->lock); -} - - -static int -hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, u16 type, - u16 stype) -{ - if (local->iw_mode == IW_MODE_MASTER) - hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data); - - if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { - if (stype == IEEE80211_STYPE_BEACON && - local->iw_mode == IW_MODE_MASTER) { - struct sk_buff *skb2; - /* Process beacon frames also in kernel driver to - * update STA(AP) table statistics */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - hostap_rx(skb2->dev, skb2, rx_stats); - } - - /* send management frames to the user space daemon for - * processing */ - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - if (local->apdev == NULL) - return -1; - prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); - return 0; - } - - if (local->iw_mode == IW_MODE_MASTER) { - if (type != IEEE80211_FTYPE_MGMT && - type != IEEE80211_FTYPE_CTL) { - printk(KERN_DEBUG "%s: unknown management frame " - "(type=0x%02x, stype=0x%02x) dropped\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } - - hostap_rx(skb->dev, skb, rx_stats); - return 0; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_BEACON || - stype == IEEE80211_STYPE_PROBE_RESP)) { - hostap_rx_sta_beacon(local, skb, stype); - return -1; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_ASSOC_RESP || - stype == IEEE80211_STYPE_REASSOC_RESP)) { - /* Ignore (Re)AssocResp silently since these are not currently - * needed but are still received when WPA/RSN mode is enabled. - */ - return -1; - } else { - printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" - " management frame in non-Host AP mode (type=%d:%d)\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } -} - - -/* Called only as a tasklet (software IRQ) */ -static struct net_device *prism2_rx_get_wds(local_info_t *local, - u8 *addr) -{ - struct hostap_interface *iface = NULL; - struct list_head *ptr; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS && - memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) - break; - iface = NULL; - } - read_unlock_bh(&local->iface_lock); - - return iface ? iface->dev : NULL; -} - - -static int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc, - struct net_device **wds) -{ - /* FIX: is this really supposed to accept WDS frames only in Master - * mode? What about Repeater or Managed with WDS frames? */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && - (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) - return 0; /* not a WDS frame */ - - /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) - * or own non-standard frame with 4th address after payload */ - if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) && - (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || - hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || - hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { - /* RA (or BSSID) is not ours - drop */ - PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%pM\n", - local->dev->name, - fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - hdr->addr1); - return -1; - } - - /* check if the frame came from a registered WDS connection */ - *wds = prism2_rx_get_wds(local, hdr->addr2); - if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && - (local->iw_mode != IW_MODE_INFRA || - !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || - memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { - /* require that WDS link has been registered with TA or the - * frame is from current AP when using 'AP client mode' */ - PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%pM\n", - local->dev->name, hdr->addr2); - if (local->ap && local->ap->autom_ap_wds) - hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); - return -1; - } - - if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && - hostap_is_sta_assoc(local->ap, hdr->addr2)) { - /* STA is actually associated with us even though it has a - * registered WDS link. Assume it is in 'AP client' mode. - * Since this is a 3-addr frame, assume it is not (bogus) WDS - * frame and process it like any normal ToDS frame from - * associated STA. */ - *wds = NULL; - } - - return 0; -} - - -static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) -{ - struct net_device *dev = local->dev; - u16 fc, ethertype; - struct ieee80211_hdr *hdr; - u8 *pos; - - if (skb->len < 24) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - /* check that the frame is unicast frame to us */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS && - ether_addr_equal(hdr->addr1, dev->dev_addr) && - ether_addr_equal(hdr->addr3, dev->dev_addr)) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - /* FromDS frame with own addr as DA */ - } else - return 0; - - if (skb->len < 24 + 8) - return 0; - - /* check for port access entity Ethernet type */ - pos = skb->data + 24; - ethertype = (pos[6] << 8) | pos[7]; - if (ethertype == ETH_P_PAE) - return 1; - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from %pM\n", - local->dev->name, hdr->addr2); - } - return -1; - } - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", - local->dev->name, hdr->addr2, res); - local->comm_tallies.rx_discards_wep_undecryptable++; - return -1; - } - - return res; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%pM keyidx=%d)\n", - local->dev->name, hdr->addr2, keyidx); - return -1; - } - - return 0; -} - - -/* All received frames are sent to this function. @skb contains the frame in - * IEEE 802.11 format, i.e., in the format it was sent over air. - * This function is called only as a tasklet (software IRQ). */ -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - size_t hdrlen; - u16 fc, type, stype, sc; - struct net_device *wds = NULL; - unsigned int frag; - u8 *payload; - struct sk_buff *skb2 = NULL; - u16 ethertype; - int frame_authorized = 0; - int from_assoc_ap = 0; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; - void *sta = NULL; - int keyidx = 0; - - iface = netdev_priv(dev); - local = iface->local; - iface->stats.rx_packets++; - iface->stats.rx_bytes += skb->len; - - /* dev is the master radio device; change this to be the default - * virtual interface (this may be changed to WDS device below) */ - dev = local->ddev; - iface = netdev_priv(dev); - - hdr = (struct ieee80211_hdr *) skb->data; - - if (skb->len < 10) - goto rx_dropped; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Put this code here so that we avoid duplicating it in all - * Rx paths. - Jean II */ -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - /* If spy monitoring on */ - if (iface->spy_data.spy_number > 0) { - struct iw_quality wstats; - wstats.level = rx_stats->signal; - wstats.noise = rx_stats->noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, hdr->addr2, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - hostap_update_rx_stats(local->ap, hdr, rx_stats); - - if (local->iw_mode == IW_MODE_MONITOR) { - monitor_rx(dev, skb, rx_stats); - return; - } - - if (local->host_decrypt) { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - sta = NULL; - - /* Use station specific key to override default keys if the - * receiver address is a unicast address ("individual RA"). If - * bcrx_sta_key parameter is set, station specific key is used - * even with broad/multicast targets (this is against IEEE - * 802.11, but makes it easier to use different keys with - * stations that do not support WEP key mapping). */ - - if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) - (void) hostap_handle_sta_crypto(local, hdr, &crypt, - &sta); - - /* allow NULL decrypt to indicate an station specific override - * for default encryption */ - if (crypt && (crypt->ops == NULL || - crypt->ops->decrypt_mpdu == NULL)) - crypt = NULL; - - if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { -#if 0 - /* This seems to be triggered by some (multicast?) - * frames from other than current BSS, so just drop the - * frames silently instead of filling system log with - * these reports. */ - printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=%pM)\n", - local->dev->name, hdr->addr2); -#endif - local->comm_tallies.rx_discards_wep_undecryptable++; - goto rx_dropped; - } - } - - if (type != IEEE80211_FTYPE_DATA) { - if (type == IEEE80211_FTYPE_MGMT && - stype == IEEE80211_STYPE_AUTH && - fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - { - printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from %pM\n", dev->name, hdr->addr2); - /* TODO: could inform hostapd about this so that it - * could send auth failure report */ - goto rx_dropped; - } - - if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) - goto rx_dropped; - else - goto rx_exit; - } - - /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_DATA_HDR3_LEN) - goto rx_dropped; - - switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - break; - case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_DATA_HDR4_LEN) - goto rx_dropped; - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - break; - default: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - } - - if (hostap_rx_frame_wds(local, hdr, fc, &wds)) - goto rx_dropped; - if (wds) - skb->dev = dev = wds; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - local->stadev && - memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { - /* Frame from BSSID of the AP for which we are a client */ - skb->dev = dev = local->stadev; - from_assoc_ap = 1; - } - - if ((local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT) && - !from_assoc_ap) { - switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, - wds != NULL)) { - case AP_RX_CONTINUE_NOT_AUTHORIZED: - frame_authorized = 0; - break; - case AP_RX_CONTINUE: - frame_authorized = 1; - break; - case AP_RX_DROP: - goto rx_dropped; - case AP_RX_EXIT: - goto rx_exit; - } - } - - /* Nullfunc frames may have PS-bit set, so they must be passed to - * hostap_handle_sta_rx() before being dropped here. */ - if (stype != IEEE80211_STYPE_DATA && - stype != IEEE80211_STYPE_DATA_CFACK && - stype != IEEE80211_STYPE_DATA_CFPOLL && - stype != IEEE80211_STYPE_DATA_CFACKPOLL) { - if (stype != IEEE80211_STYPE_NULLFUNC) - printk(KERN_DEBUG "%s: RX: dropped data frame " - "with no data (type=0x%02x, subtype=0x%02x)\n", - dev->name, type >> 2, stype >> 4); - goto rx_dropped; - } - - /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; - - /* skb: hdr + (possibly fragmented) plaintext payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { - int flen; - struct sk_buff *frag_skb = - prism2_frag_cache_get(local, hdr); - if (!frag_skb) { - printk(KERN_DEBUG "%s: Rx cannot get skb from " - "fragment cache (morefrag=%d seq=%u frag=%u)\n", - dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, - (sc & IEEE80211_SCTL_SEQ) >> 4, frag); - goto rx_dropped; - } - - flen = skb->len; - if (frag != 0) - flen -= hdrlen; - - if (frag_skb->tail + flen > frag_skb->end) { - printk(KERN_WARNING "%s: host decrypted and " - "reassembled frame did not fit skb\n", - dev->name); - prism2_frag_cache_invalidate(local, hdr); - goto rx_dropped; - } - - if (frag == 0) { - /* copy first fragment (including full headers) into - * beginning of the fragment cache skb */ - skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), - flen); - } else { - /* append frame payload to the end of the fragment - * cache skb */ - skb_copy_from_linear_data_offset(skb, hdrlen, - skb_put(frag_skb, - flen), flen); - } - dev_kfree_skb(skb); - skb = NULL; - - if (fc & IEEE80211_FCTL_MOREFRAGS) { - /* more fragments expected - leave the skb in fragment - * cache for now; it will be delivered to upper layers - * after all fragments have been received */ - goto rx_exit; - } - - /* this was the last fragment and the frame will be - * delivered, so remove skb from fragment cache */ - skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; - prism2_frag_cache_invalidate(local, hdr); - } - - /* skb: hdr + (possible reassembled) full MSDU payload; possibly still - * encrypted/authenticated */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) - goto rx_dropped; - - hdr = (struct ieee80211_hdr *) skb->data; - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { - if (local->ieee_802_1x && - hostap_is_eapol_frame(local, skb)) { - /* pass unencrypted EAPOL frames even if encryption is - * configured */ - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", local->dev->name); - } else { - printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=%pM)\n", - local->dev->name, hdr->addr2); - goto rx_dropped; - } - } - - if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && - !hostap_is_eapol_frame(local, skb)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from %pM (drop_unencrypted=1)\n", - dev->name, hdr->addr2); - } - goto rx_dropped; - } - - /* skb: hdr + (possible reassembled) full plaintext payload */ - - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - /* If IEEE 802.1X is used, check whether the port is authorized to send - * the received frame. */ - if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { - if (ethertype == ETH_P_PAE) { - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", - dev->name); - if (local->hostapd && local->apdev) { - /* Send IEEE 802.1X frames to the user - * space daemon for processing */ - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_MGMT); - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - goto rx_exit; - } - } else if (!frame_authorized) { - printk(KERN_DEBUG "%s: dropped frame from " - "unauthorized port (IEEE 802.1X): " - "ethertype=0x%04x\n", - dev->name, ethertype); - goto rx_dropped; - } - } - - /* convert hdr + possible LLC headers into Ethernet header */ - if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, 6) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, 6) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - __be16 len; - /* Leave Ethernet header part of hdr and full payload */ - skb_pull(skb, hdrlen); - len = htons(skb->len); - memcpy(skb_push(skb, 2), &len, 2); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } - - if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS) && - skb->len >= ETH_HLEN + ETH_ALEN) { - /* Non-standard frame: get addr4 from its bogus location after - * the payload */ - skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN, - skb->data + ETH_ALEN, - ETH_ALEN); - skb_trim(skb, skb->len - ETH_ALEN); - } - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - local->ap->bridge_packets) { - if (dst[0] & 0x01) { - /* copy multicast frame both to the higher layers and - * to the wireless media */ - local->ap->bridged_multicast++; - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 == NULL) - printk(KERN_DEBUG "%s: skb_clone failed for " - "multicast frame\n", dev->name); - } else if (hostap_is_sta_authorized(local->ap, dst)) { - /* send frame directly to the associated STA using - * wireless media and not passing to higher layers */ - local->ap->bridged_unicast++; - skb2 = skb; - skb = NULL; - } - } - - if (skb2 != NULL) { - /* send to wireless media */ - skb2->dev = dev; - skb2->protocol = cpu_to_be16(ETH_P_802_3); - skb_reset_mac_header(skb2); - skb_reset_network_header(skb2); - /* skb2->network_header += ETH_HLEN; */ - dev_queue_xmit(skb2); - } - - if (skb) { - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - } - - rx_exit: - if (sta) - hostap_handle_sta_release(sta); - return; - - rx_dropped: - dev_kfree_skb(skb); - - dev->stats.rx_dropped++; - goto rx_exit; -} - - -EXPORT_SYMBOL(hostap_80211_rx); diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c deleted file mode 100644 index c47da06945c2..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c +++ /dev/null @@ -1,554 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap_common.h" -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", - name, skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) - * Convert Ethernet header into a suitable IEEE 802.11 header depending on - * device configuration. */ -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; - u16 fc, ethertype = 0; - enum { - WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME - } use_wds = WDS_NO; - u8 *encaps_data; - int hdr_len, encaps_len, skip_header_bytes; - int to_assoc_ap = 0; - struct hostap_skb_tx_data *meta; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < ETH_HLEN) { - printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (local->ddev != dev) { - use_wds = (local->iw_mode == IW_MODE_MASTER && - !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? - WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; - if (dev == local->stadev) { - to_assoc_ap = 1; - use_wds = WDS_NO; - } else if (dev == local->apdev) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "AP device with Ethernet net dev\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } - } else { - if (local->iw_mode == IW_MODE_REPEAT) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "non-WDS link in Repeater mode\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } else if (local->iw_mode == IW_MODE_INFRA && - (local->wds_type & HOSTAP_WDS_AP_CLIENT) && - !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) { - /* AP client mode: send frames with foreign src addr - * using 4-addr WDS frames */ - use_wds = WDS_COMPLIANT_FRAME; - } - } - - /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload - * ==> - * Prism2 TX frame with 802.11 header: - * txdesc (address order depending on used mode; includes dst_addr and - * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; - * proto[2], payload {, possible addr4[6]} */ - - ethertype = (skb->data[12] << 8) | skb->data[13]; - - memset(&hdr, 0, sizeof(hdr)); - - /* Length of data after IEEE 802.11 header */ - encaps_data = NULL; - encaps_len = 0; - skip_header_bytes = ETH_HLEN; - if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { - encaps_data = bridge_tunnel_header; - encaps_len = sizeof(bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= 0x600) { - encaps_data = rfc1042_header; - encaps_len = sizeof(rfc1042_header); - skip_header_bytes -= 2; - } - - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - hdr_len = IEEE80211_DATA_HDR3_LEN; - - if (use_wds != WDS_NO) { - /* Note! Prism2 station firmware has problems with sending real - * 802.11 frames with four addresses; until these problems can - * be fixed or worked around, 4-addr frames needed for WDS are - * using incompatible format: FromDS flag is not set and the - * fourth address is added after the frame payload; it is - * assumed, that the receiving station knows how to handle this - * frame format */ - - if (use_wds == WDS_COMPLIANT_FRAME) { - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; - /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, - * Addr4 = SA */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - hdr_len += ETH_ALEN; - } else { - /* bogus 4-addr format to workaround Prism2 station - * f/w bug */ - fc |= IEEE80211_FCTL_TODS; - /* From DS: Addr1 = DA (used as RA), - * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), - */ - - /* SA from skb->data + ETH_ALEN will be added after - * frame payload; use hdr.addr4 as a temporary buffer - */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - need_tailroom += ETH_ALEN; - } - - /* send broadcast and multicast frames to broadcast RA, if - * configured; otherwise, use unicast RA of the WDS link */ - if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && - is_multicast_ether_addr(skb->data)) - eth_broadcast_addr(hdr.addr1); - else if (iface->type == HOSTAP_INTERFACE_WDS) - memcpy(&hdr.addr1, iface->u.wds.remote_addr, - ETH_ALEN); - else - memcpy(&hdr.addr1, local->bssid, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { - fc |= IEEE80211_FCTL_FROMDS; - /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3, - ETH_ALEN); - } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ - memcpy(&hdr.addr1, to_assoc_ap ? - local->assoc_ap_addr : local->bssid, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - memcpy(&hdr.addr3, local->bssid, ETH_ALEN); - } - - hdr.frame_control = cpu_to_le16(fc); - - skb_pull(skb, skip_header_bytes); - need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; - if (skb_tailroom(skb) < need_tailroom) { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - if (pskb_expand_head(skb, need_headroom, need_tailroom, - GFP_ATOMIC)) { - kfree_skb(skb); - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else if (skb_headroom(skb) < need_headroom) { - struct sk_buff *tmp = skb; - skb = skb_realloc_headroom(skb, need_headroom); - kfree_skb(tmp); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } - - if (encaps_data) - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); - if (use_wds == WDS_OWN_FRAME) { - skb_put_data(skb, &hdr.addr4, ETH_ALEN); - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - skb_reset_mac_header(skb); - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - if (use_wds) - meta->flags |= HOSTAP_TX_FLAGS_WDS; - meta->ethertype = ethertype; - meta->iface = iface; - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* hard_start_xmit function for hostapd wlan#ap interfaces */ -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; - u16 fc; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 10) { - printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - - if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - if (ieee80211_is_data(hdr->frame_control) && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) { - u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + - sizeof(rfc1042_header)]; - meta->ethertype = (pos[0] << 8) | pos[1]; - } - } - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* Called only from software IRQ */ -static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - int prefix_len, postfix_len, hdr_len, res; - - iface = netdev_priv(skb->dev); - local = iface->local; - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - kfree_skb(skb); - return NULL; - } - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to %pM\n", - local->dev->name, hdr->addr1); - } - kfree_skb(skb); - return NULL; - } - - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) - return NULL; - - prefix_len = crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_msdu_prefix_len; - postfix_len = crypt->ops->extra_mpdu_postfix_len + - crypt->ops->extra_msdu_postfix_len; - if ((skb_headroom(skb) < prefix_len || - skb_tailroom(skb) < postfix_len) && - pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) { - kfree_skb(skb); - return NULL; - } - - hdr = (struct ieee80211_hdr *) skb->data; - hdr_len = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ - atomic_inc(&crypt->refcnt); - res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) - res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - kfree_skb(skb); - return NULL; - } - - return skb; -} - - -/* hard_start_xmit function for master radio interface wifi#. - * AP processing (TX rate control, power save buffering, etc.). - * Use hardware TX function to send the frame. */ -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - netdev_tx_t ret = NETDEV_TX_BUSY; - u16 fc; - struct hostap_tx_data tx; - ap_tx_ret tx_ret; - struct hostap_skb_tx_data *meta; - int no_encrypt = 0; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - tx.skb = skb; - tx.sta_ptr = NULL; - - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x)\n", - dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - if (local->host_encrypt) { - /* Set crypt to default algorithm and key; will be replaced in - * AP code if STA has own alg/key */ - tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; - tx.host_encrypt = 1; - } else { - tx.crypt = NULL; - tx.host_encrypt = 0; - } - - if (skb->len < 24) { - printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - /* FIX (?): - * Wi-Fi 802.11b test plan suggests that AP should ignore power save - * bit in authentication and (re)association frames and assume tha - * STA remains awake for the response. */ - tx_ret = hostap_handle_sta_tx(local, &tx); - skb = tx.skb; - meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - switch (tx_ret) { - case AP_TX_CONTINUE: - break; - case AP_TX_CONTINUE_NOT_AUTHORIZED: - if (local->ieee_802_1x && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE && - !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { - printk(KERN_DEBUG "%s: dropped frame to unauthorized " - "port (IEEE 802.1X): ethertype=0x%04x\n", - dev->name, meta->ethertype); - hostap_dump_tx_80211(dev->name, skb); - - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - } - break; - case AP_TX_DROP: - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - case AP_TX_RETRY: - goto fail; - case AP_TX_BUFFERED: - /* do not free skb here, it will be freed when the - * buffered frame is sent/timed out */ - ret = NETDEV_TX_OK; - goto tx_exit; - } - - /* Request TX callback if protocol version is 2 in 802.11 header; - * this version 2 is a special case used between hostapd and kernel - * driver */ - if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && - local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { - meta->tx_cb_idx = local->ap->tx_callback_idx; - - /* remove special version from the frame header */ - fc &= ~IEEE80211_FCTL_VERS; - hdr->frame_control = cpu_to_le16(fc); - } - - if (!ieee80211_is_data(hdr->frame_control)) { - no_encrypt = 1; - tx.crypt = NULL; - } - - if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_PROTECTED)) { - no_encrypt = 1; - PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", dev->name); - tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ - } - - if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) - tx.crypt = NULL; - else if ((tx.crypt || - local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && - !no_encrypt) { - /* Add ISWEP flag both for firmware and host based encryption - */ - fc |= IEEE80211_FCTL_PROTECTED; - hdr->frame_control = cpu_to_le16(fc); - } else if (local->drop_unencrypted && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted TX data " - "frame (drop_unencrypted=1)\n", dev->name); - } - iface->stats.tx_dropped++; - ret = NETDEV_TX_OK; - goto fail; - } - - if (tx.crypt) { - skb = hostap_tx_encrypt(skb, tx.crypt); - if (skb == NULL) { - printk(KERN_DEBUG "%s: TX - encryption failed\n", - dev->name); - ret = NETDEV_TX_OK; - goto fail; - } - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x) after hostap_tx_encrypt\n", - dev->name, meta->magic, - HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - } - - if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - } else { - ret = NETDEV_TX_OK; - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - } - - fail: - if (ret == NETDEV_TX_OK && skb) - dev_kfree_skb(skb); - tx_exit: - if (tx.sta_ptr) - hostap_handle_sta_release(tx.sta_ptr); - return ret; -} - - -EXPORT_SYMBOL(hostap_master_start_xmit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c deleted file mode 100644 index 9b546a71e7a2..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ /dev/null @@ -1,3277 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intersil Prism2 driver with Host AP (software access point) support - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - * - * This file is to be included into hostap.c when S/W AP functionality is - * compiled. - * - * AP: FIX: - * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from - * unauthenticated STA, send deauth. frame (8802.11: 5.5) - * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received - * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) - * - if unicast Class 3 received from unauthenticated STA, send deauth. frame - * (8802.11: 5.5) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, - DEF_INTS }; -module_param_array(other_ap_policy, int, NULL, 0444); -MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); - -static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, - DEF_INTS }; -module_param_array(ap_max_inactivity, int, NULL, 0444); -MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " - "inactivity"); - -static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(ap_bridge_packets, int, NULL, 0444); -MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " - "stations"); - -static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; -module_param_array(autom_ap_wds, int, NULL, 0444); -MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " - "automatically"); - - -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta); -static void handle_add_proc_queue(struct work_struct *work); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(struct work_struct *work); -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int ap_debug_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - - seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); - seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); - seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); - seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); - seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); - seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); - seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); - seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); - return 0; -} -#endif - -static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) -{ - sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; - ap->sta_hash[STA_HASH(sta->addr)] = sta; -} - -static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta->addr)]; - if (s == NULL) return; - if (ether_addr_equal(s->addr, sta->addr)) { - ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; - } - - while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr)) - s = s->hnext; - if (s->hnext != NULL) - s->hnext = s->hnext->hnext; - else - printk("AP: could not remove STA %pM from hash table\n", - sta->addr); -} - -static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) -{ - if (sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - - if (ap->proc != NULL) { - char name[20]; - sprintf(name, "%pM", sta->addr); - remove_proc_entry(name, ap->proc); - } - - if (sta->crypt) { - sta->crypt->ops->deinit(sta->crypt->priv); - kfree(sta->crypt); - sta->crypt = NULL; - } - - skb_queue_purge(&sta->tx_buf); - - ap->num_sta--; -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->aid > 0) - ap->sta_aid[sta->aid - 1] = NULL; - - if (!sta->ap) - kfree(sta->u.sta.challenge); - timer_shutdown_sync(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - kfree(sta); -} - - -static void hostap_set_tim(local_info_t *local, int aid, int set) -{ - if (local->func->set_tim) - local->func->set_tim(local->dev, aid, set); -} - - -static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); -} - - -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_handle_timer(struct timer_list *t) -{ - struct sta_info *sta = from_timer(sta, t, timer); - local_info_t *local; - struct ap_data *ap; - unsigned long next_time = 0; - int was_assoc; - - if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { - PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); - return; - } - - local = sta->local; - ap = local->ap; - was_assoc = sta->flags & WLAN_STA_ASSOC; - - if (atomic_read(&sta->users) != 0) - next_time = jiffies + HZ; - else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) - next_time = jiffies + ap->max_inactivity; - - if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { - /* station activity detected; reset timeout state */ - sta->timeout_next = STA_NULLFUNC; - next_time = sta->last_rx + ap->max_inactivity; - } else if (sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL)) { - /* STA ACKed data nullfunc frame poll */ - sta->timeout_next = STA_NULLFUNC; - next_time = jiffies + ap->max_inactivity; - } - - if (next_time) { - sta->timer.expires = next_time; - add_timer(&sta->timer); - return; - } - - if (sta->ap) - sta->timeout_next = STA_DEAUTH; - - if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { - spin_lock(&ap->sta_table_lock); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - spin_unlock(&ap->sta_table_lock); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } else if (sta->timeout_next == STA_DISASSOC) - sta->flags &= ~WLAN_STA_ASSOC; - - if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - - if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && - !skb_queue_empty(&sta->tx_buf)) { - hostap_set_tim(local, sta->aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - if (sta->ap) { - if (ap->autom_ap_wds) { - PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %pM\n", - local->dev->name, sta->addr); - hostap_wds_link_oper(local, sta->addr, WDS_DEL); - } - } else if (sta->timeout_next == STA_NULLFUNC) { - /* send data frame to poll STA and check whether this frame - * is ACKed */ - /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but - * it is apparently not retried so TX Exc events are not - * received for it */ - sta->flags |= WLAN_STA_PENDING_POLL; - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_DATA, NULL, 0, - sta->addr, ap->tx_callback_poll); - } else { - int deauth = sta->timeout_next == STA_DEAUTH; - __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" - "(last=%lu, jiffies=%lu)\n", - local->dev->name, - deauth ? "deauthentication" : "disassociation", - sta->addr, sta->last_rx, jiffies); - - resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | - (deauth ? IEEE80211_STYPE_DEAUTH : - IEEE80211_STYPE_DISASSOC), - (char *) &resp, 2, sta->addr, 0); - } - - if (sta->timeout_next == STA_DEAUTH) { - if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %pM" - " would have been removed, " - "but it has 'perm' flag\n", - local->dev->name, sta->addr); - } else - ap_free_sta(ap, sta); - return; - } - - if (sta->timeout_next == STA_NULLFUNC) { - sta->timeout_next = STA_DISASSOC; - sta->timer.expires = jiffies + AP_DISASSOC_DELAY; - } else { - sta->timeout_next = STA_DEAUTH; - sta->timer.expires = jiffies + AP_DEAUTH_DELAY; - } - - add_timer(&sta->timer); -} - - -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend) -{ - u8 addr[ETH_ALEN]; - __le16 resp; - int i; - - PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); - eth_broadcast_addr(addr); - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - - /* deauth message sent; try to resend it few times; the message is - * broadcast, so it may be delayed until next DTIM; there is not much - * else we can do at this point since the driver is going to be shut - * down */ - for (i = 0; i < 5; i++) { - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, addr, 0); - - if (!resend || ap->num_sta <= 0) - return; - - mdelay(50); - } -} - - -static int ap_control_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - char *policy_txt; - struct mac_entry *entry; - - if (v == SEQ_START_TOKEN) { - switch (ap->mac_restrictions.policy) { - case MAC_POLICY_OPEN: - policy_txt = "open"; - break; - case MAC_POLICY_ALLOW: - policy_txt = "allow"; - break; - case MAC_POLICY_DENY: - policy_txt = "deny"; - break; - default: - policy_txt = "unknown"; - break; - } - seq_printf(m, "MAC policy: %s\n", policy_txt); - seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); - seq_puts(m, "MAC list:\n"); - return 0; - } - - entry = v; - seq_printf(m, "%pM\n", entry->addr); - return 0; -} - -static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->mac_restrictions.lock); - return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); -} - -static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); -} - -static void ap_control_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->mac_restrictions.lock); -} - -static const struct seq_operations ap_control_proc_seqops = { - .start = ap_control_proc_start, - .next = ap_control_proc_next, - .stop = ap_control_proc_stop, - .show = ap_control_proc_show, -}; - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct mac_entry *entry; - - entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); - if (entry == NULL) - return -ENOMEM; - - memcpy(entry->addr, mac, ETH_ALEN); - - spin_lock_bh(&mac_restrictions->lock); - list_add_tail(&entry->list, &mac_restrictions->mac_list); - mac_restrictions->entries++; - spin_unlock_bh(&mac_restrictions->lock); - - return 0; -} - - -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct list_head *ptr; - struct mac_entry *entry; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next; - ptr != &mac_restrictions->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - - if (ether_addr_equal(entry->addr, mac)) { - list_del(ptr); - kfree(entry); - mac_restrictions->entries--; - spin_unlock_bh(&mac_restrictions->lock); - return 0; - } - } - spin_unlock_bh(&mac_restrictions->lock); - return -1; -} - - -static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, - u8 *mac) -{ - struct mac_entry *entry; - int found = 0; - - if (mac_restrictions->policy == MAC_POLICY_OPEN) - return 0; - - spin_lock_bh(&mac_restrictions->lock); - list_for_each_entry(entry, &mac_restrictions->mac_list, list) { - if (ether_addr_equal(entry->addr, mac)) { - found = 1; - break; - } - } - spin_unlock_bh(&mac_restrictions->lock); - - if (mac_restrictions->policy == MAC_POLICY_ALLOW) - return !found; - else - return found; -} - - -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) -{ - struct list_head *ptr, *n; - struct mac_entry *entry; - - if (mac_restrictions->entries == 0) - return; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next, n = ptr->next; - ptr != &mac_restrictions->mac_list; - ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - list_del(ptr); - kfree(entry); - } - mac_restrictions->entries = 0; - spin_unlock_bh(&mac_restrictions->lock); -} - - -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) -{ - struct sta_info *sta; - __le16 resp; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, mac); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -EINVAL; - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, sta->addr, 0); - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(dev, sta); - - ap_free_sta(ap, sta); - - return 0; -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void ap_control_kickall(struct ap_data *ap) -{ - struct list_head *ptr, *n; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; - ptr = n, n = ptr->next) { - sta = list_entry(ptr, struct sta_info, list); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static int prism2_ap_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = v; - int i; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); - return 0; - } - - if (!sta->ap) - return 0; - - seq_printf(m, "%pM %d %d %d %d '", - sta->addr, - sta->u.ap.channel, sta->last_rx_signal, - sta->last_rx_silence, sta->last_rx_rate); - - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - - seq_putc(m, '\''); - if (sta->capability & WLAN_CAPABILITY_ESS) - seq_puts(m, " [ESS]"); - if (sta->capability & WLAN_CAPABILITY_IBSS) - seq_puts(m, " [IBSS]"); - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - seq_puts(m, " [WEP]"); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->sta_table_lock); - return seq_list_start_head(&ap->sta_list, *_pos); -} - -static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->sta_list, _pos); -} - -static void prism2_ap_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->sta_table_lock); -} - -static const struct seq_operations prism2_ap_proc_seqops = { - .start = prism2_ap_proc_start, - .next = prism2_ap_proc_next, - .stop = prism2_ap_proc_stop, - .show = prism2_ap_proc_show, -}; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) -{ - if (!ap) - return; - - if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { - PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " - "firmware upgrade recommended\n"); - ap->nullfunc_ack = 1; - } else - ap->nullfunc_ack = 0; - - if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { - printk(KERN_WARNING "%s: Warning: secondary station firmware " - "version 1.4.2 does not seem to work in Host AP mode\n", - ap->local->dev->name); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - - if (!ap->local->hostapd || !ap->local->apdev) { - dev_kfree_skb(skb); - return; - } - - /* Pass the TX callback frame to the hostapd; use 802.11 header version - * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ - - hdr = (struct ieee80211_hdr *) skb->data; - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); - hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); - - skb->dev = ap->local->apdev; - skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 auth_alg, auth_transaction, status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if (!ieee80211_is_auth(hdr->frame_control) || - skb->len < IEEE80211_MGMT_HDR_LEN + 6) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = le16_to_cpu(*pos++); - auth_transaction = le16_to_cpu(*pos++); - status = le16_to_cpu(*pos++); - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - if (status == WLAN_STATUS_SUCCESS && - ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { - txt = "STA authenticated"; - sta->flags |= WLAN_STA_AUTH; - sta->last_auth = jiffies; - } else if (status != WLAN_STATUS_SUCCESS) - txt = "authentication failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " - "trans#=%d status=%d - %s\n", - dev->name, hdr->addr1, - auth_alg, auth_transaction, status, txt); - } - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if ((!ieee80211_is_assoc_resp(hdr->frame_control) && - !ieee80211_is_reassoc_resp(hdr->frame_control)) || - skb->len < IEEE80211_MGMT_HDR_LEN + 4) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - pos++; - status = le16_to_cpu(*pos++); - if (status == WLAN_STATUS_SUCCESS) { - if (!(sta->flags & WLAN_STA_ASSOC)) - hostap_event_new_sta(dev, sta); - txt = "STA associated"; - sta->flags |= WLAN_STA_ASSOC; - sta->last_assoc = jiffies; - } else - txt = "association failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", - dev->name, hdr->addr1, txt); - } - dev_kfree_skb(skb); -} - -/* Called only as a tasklet (software IRQ); TX callback for poll frames used - * in verifying whether the STA is still present. */ -static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - struct sta_info *sta; - - if (skb->len < 24) - goto fail; - hdr = (struct ieee80211_hdr *) skb->data; - if (ok) { - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - sta->flags &= ~WLAN_STA_PENDING_POLL; - spin_unlock(&ap->sta_table_lock); - } else { - PDEBUG(DEBUG_AP, - "%s: STA %pM did not ACK activity poll frame\n", - ap->local->dev->name, hdr->addr1); - } - - fail: - dev_kfree_skb(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_init_data(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - if (ap == NULL) { - printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); - return; - } - memset(ap, 0, sizeof(struct ap_data)); - ap->local = local; - - ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); - ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); - ap->max_inactivity = - GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; - ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); - - spin_lock_init(&ap->sta_table_lock); - INIT_LIST_HEAD(&ap->sta_list); - - /* Initialize task queue structure for AP management */ - INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); - - ap->tx_callback_idx = - hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); - if (ap->tx_callback_idx == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); - - ap->tx_callback_auth = - hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); - ap->tx_callback_assoc = - hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); - ap->tx_callback_poll = - hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); - if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || - ap->tx_callback_poll == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); - - spin_lock_init(&ap->mac_restrictions.lock); - INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 1; -} - - -void hostap_init_ap_proc(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - ap->proc = local->proc; - if (ap->proc == NULL) - return; - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops, - ap); - proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -} - - -void hostap_free_data(struct ap_data *ap) -{ - struct sta_info *n, *sta; - - if (ap == NULL || !ap->initialized) { - printk(KERN_DEBUG "hostap_free_data: ap has not yet been " - "initialized - skip resource freeing\n"); - return; - } - - flush_work(&ap->add_sta_proc_queue); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - flush_work(&ap->wds_oper_queue); - if (ap->crypt) - ap->crypt->deinit(ap->crypt_priv); - ap->crypt = ap->crypt_priv = NULL; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - list_for_each_entry_safe(sta, n, &ap->sta_list, list) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (ap->proc != NULL) { - remove_proc_entry("ap_debug", ap->proc); - } -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (ap->proc != NULL) { - remove_proc_entry("ap", ap->proc); - remove_proc_entry("ap_control", ap->proc); - } - ap_control_flush_macs(&ap->mac_restrictions); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 0; -} - - -/* caller should have mutex for AP STA list handling */ -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta)]; - while (s != NULL && !ether_addr_equal(s->addr, sta)) - s = s->hnext; - return s; -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -/* Called from timer handler and from scheduled AP queue handlers */ -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - u16 fc; - struct sk_buff *skb; - struct hostap_skb_tx_data *meta; - int hdrlen; - - iface = netdev_priv(dev); - local = iface->local; - dev = local->dev; /* always use master radio device */ - iface = netdev_priv(dev); - - if (!(dev->flags & IFF_UP)) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " - "cannot send frame\n", dev->name); - return; - } - - skb = dev_alloc_skb(sizeof(*hdr) + body_len); - if (skb == NULL) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " - "skb\n", dev->name); - return; - } - - fc = type_subtype; - hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); - hdr = skb_put_zero(skb, hdrlen); - if (body) - skb_put_data(skb, body, body_len); - - /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 - * tx_control instead of using local->tx_control */ - - - memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ - if (ieee80211_is_data(hdr->frame_control)) { - fc |= IEEE80211_FCTL_FROMDS; - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ - } else if (ieee80211_is_ctl(hdr->frame_control)) { - /* control:ACK does not have addr2 or addr3 */ - eth_zero_addr(hdr->addr2); - eth_zero_addr(hdr->addr3); - } else { - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ - } - - hdr->frame_control = cpu_to_le16(fc); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - meta->tx_cb_idx = tx_cb_idx; - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#ifdef CONFIG_PROC_FS -static int prism2_sta_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = m->private; - int i; - - /* FIX: possible race condition.. the STA data could have just expired, - * but proc entry was still here so that the read could have started; - * some locking should be done here.. */ - - seq_printf(m, - "%s=%pM\nusers=%d\naid=%d\n" - "flags=0x%04x%s%s%s%s%s%s%s\n" - "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", - sta->ap ? "AP" : "STA", - sta->addr, atomic_read(&sta->users), sta->aid, - sta->flags, - sta->flags & WLAN_STA_AUTH ? " AUTH" : "", - sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", - sta->flags & WLAN_STA_PS ? " PS" : "", - sta->flags & WLAN_STA_TIM ? " TIM" : "", - sta->flags & WLAN_STA_PERM ? " PERM" : "", - sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", - sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", - sta->capability, sta->listen_interval); - /* supported_rates: 500 kbit/s units with msb ignored */ - for (i = 0; i < sizeof(sta->supported_rates); i++) - if (sta->supported_rates[i] != 0) - seq_printf(m, "%d%sMbps ", - (sta->supported_rates[i] & 0x7f) / 2, - sta->supported_rates[i] & 1 ? ".5" : ""); - seq_printf(m, - "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" - "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" - "tx_packets=%lu\n" - "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" - "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" - "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" - "tx[11M]=%d\n" - "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", - jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, - sta->last_tx, - sta->rx_packets, sta->tx_packets, sta->rx_bytes, - sta->tx_bytes, skb_queue_len(&sta->tx_buf), - sta->last_rx_silence, - sta->last_rx_signal, sta->last_rx_rate / 10, - sta->last_rx_rate % 10 ? ".5" : "", - sta->tx_rate, sta->tx_count[0], sta->tx_count[1], - sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], - sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); - if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) - sta->crypt->ops->print_stats(m, sta->crypt->priv); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - if (sta->u.ap.channel >= 0) - seq_printf(m, "channel=%d\n", sta->u.ap.channel); - seq_puts(m, "ssid="); - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - seq_putc(m, '\n'); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return 0; -} -#endif - -static void handle_add_proc_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - add_sta_proc_queue); - struct sta_info *sta; - char name[20]; - struct add_sta_proc_data *entry, *prev; - - entry = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = NULL; - - while (entry) { - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, entry->addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta) { - sprintf(name, "%pM", sta->addr); - sta->proc = proc_create_single_data( - name, 0, ap->proc, - prism2_sta_proc_show, sta); - - atomic_dec(&sta->users); - } - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) -{ - struct sta_info *sta; - - sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC); - if (sta == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); - return NULL; - } - - /* initialize STA info data */ - sta->local = ap->local; - skb_queue_head_init(&sta->tx_buf); - memcpy(sta->addr, addr, ETH_ALEN); - - atomic_inc(&sta->users); - spin_lock_bh(&ap->sta_table_lock); - list_add(&sta->list, &ap->sta_list); - ap->num_sta++; - ap_sta_hash_add(ap, sta); - spin_unlock_bh(&ap->sta_table_lock); - - if (ap->proc) { - struct add_sta_proc_data *entry; - /* schedule a non-interrupt context process to add a procfs - * entry for the STA since procfs code use GFP_KERNEL */ - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (entry) { - memcpy(entry->addr, sta->addr, ETH_ALEN); - entry->next = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = entry; - schedule_work(&ap->add_sta_proc_queue); - } else - printk(KERN_DEBUG "Failed to add STA proc data\n"); - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - timer_setup(&sta->timer, ap_handle_timer, 0); - sta->timer.expires = jiffies + ap->max_inactivity; - if (!ap->local->hostapd) - add_timer(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return sta; -} - - -static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, - local_info_t *local) -{ - if (rateidx > sta->tx_max_rate || - !(sta->tx_supp_rates & (1 << rateidx))) - return 0; - - if (local->tx_rate_control != 0 && - !(local->tx_rate_control & (1 << rateidx))) - return 0; - - return 1; -} - - -static void prism2_check_tx_rates(struct sta_info *sta) -{ - int i; - - sta->tx_supp_rates = 0; - for (i = 0; i < sizeof(sta->supported_rates); i++) { - if ((sta->supported_rates[i] & 0x7f) == 2) - sta->tx_supp_rates |= WLAN_RATE_1M; - if ((sta->supported_rates[i] & 0x7f) == 4) - sta->tx_supp_rates |= WLAN_RATE_2M; - if ((sta->supported_rates[i] & 0x7f) == 11) - sta->tx_supp_rates |= WLAN_RATE_5M5; - if ((sta->supported_rates[i] & 0x7f) == 22) - sta->tx_supp_rates |= WLAN_RATE_11M; - } - sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; - if (sta->tx_supp_rates & WLAN_RATE_1M) { - sta->tx_max_rate = 0; - if (ap_tx_rate_ok(0, sta, sta->local)) { - sta->tx_rate = 10; - sta->tx_rate_idx = 0; - } - } - if (sta->tx_supp_rates & WLAN_RATE_2M) { - sta->tx_max_rate = 1; - if (ap_tx_rate_ok(1, sta, sta->local)) { - sta->tx_rate = 20; - sta->tx_rate_idx = 1; - } - } - if (sta->tx_supp_rates & WLAN_RATE_5M5) { - sta->tx_max_rate = 2; - if (ap_tx_rate_ok(2, sta, sta->local)) { - sta->tx_rate = 55; - sta->tx_rate_idx = 2; - } - } - if (sta->tx_supp_rates & WLAN_RATE_11M) { - sta->tx_max_rate = 3; - if (ap_tx_rate_ok(3, sta, sta->local)) { - sta->tx_rate = 110; - sta->tx_rate_idx = 3; - } - } -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_crypt_init(struct ap_data *ap) -{ - ap->crypt = lib80211_get_crypto_ops("WEP"); - - if (ap->crypt) { - if (ap->crypt->init) { - ap->crypt_priv = ap->crypt->init(0); - if (ap->crypt_priv == NULL) - ap->crypt = NULL; - else { - u8 key[WEP_KEY_LEN]; - get_random_bytes(key, WEP_KEY_LEN); - ap->crypt->set_key(key, WEP_KEY_LEN, NULL, - ap->crypt_priv); - } - } - } - - if (ap->crypt == NULL) { - printk(KERN_WARNING "AP could not initialize WEP: load module " - "lib80211_crypt_wep.ko\n"); - } -} - - -/* Generate challenge data for shared key authentication. IEEE 802.11 specifies - * that WEP algorithm is used for generating challenge. This should be unique, - * but otherwise there is not really need for randomness etc. Initialize WEP - * with pseudo random key and then use increasing IV to get unique challenge - * streams. - * - * Called only as a scheduled task for pending AP frames. - */ -static char * ap_auth_make_challenge(struct ap_data *ap) -{ - char *tmpbuf; - struct sk_buff *skb; - - if (ap->crypt == NULL) { - ap_crypt_init(ap); - if (ap->crypt == NULL) - return NULL; - } - - tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); - if (tmpbuf == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); - return NULL; - } - - skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_mpdu_prefix_len + - ap->crypt->extra_mpdu_postfix_len); - if (skb == NULL) { - kfree(tmpbuf); - return NULL; - } - - skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); - skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); - if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { - dev_kfree_skb(skb); - kfree(tmpbuf); - return NULL; - } - - skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, - tmpbuf, WLAN_AUTH_CHALLENGE_LEN); - dev_kfree_skb(skb); - - return tmpbuf; -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_authen(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - size_t hdrlen; - struct ap_data *ap = local->ap; - char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; - int len, olen; - u16 auth_alg, auth_transaction, status_code; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - struct lib80211_crypt_data *crypt; - char *txt = ""; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (len < 6) { - PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from %pM\n", dev->name, len, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta && sta->crypt) - crypt = sta->crypt; - else { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = __le16_to_cpu(*pos); - pos++; - auth_transaction = __le16_to_cpu(*pos); - pos++; - status_code = __le16_to_cpu(*pos); - pos++; - - if (ether_addr_equal(dev->dev_addr, hdr->addr2) || - ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { - txt = "authentication denied"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (((local->auth_algs & PRISM2_AUTH_OPEN) && - auth_alg == WLAN_AUTH_OPEN) || - ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && - crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { - } else { - txt = "unsupported algorithm"; - resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - goto fail; - } - - if (len >= 8) { - u8 *u = (u8 *) pos; - if (*u == WLAN_EID_CHALLENGE) { - if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { - txt = "invalid challenge len"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { - txt = "challenge underflow"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - challenge = (char *) (u + 2); - } - } - - if (sta && sta->ap) { - if (time_after(jiffies, sta->u.ap.last_beacon + - (10 * sta->listen_interval * HZ) / 1024)) { - PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP %pM is now STA\n", - dev->name, sta->addr); - sta->ap = 0; - sta->flags = 0; - sta->u.sta.challenge = NULL; - } else { - txt = "AP trying to authenticate?"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || - (auth_alg == WLAN_AUTH_SHARED_KEY && - (auth_transaction == 1 || - (auth_transaction == 3 && sta != NULL && - sta->u.sta.challenge != NULL)))) { - } else { - txt = "unknown authentication transaction number"; - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - goto fail; - } - - if (sta == NULL) { - txt = "new STA"; - - if (local->ap->num_sta >= MAX_STA_COUNT) { - /* FIX: might try to remove some old STAs first? */ - txt = "no more room for new STAs"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - txt = "ap_add_sta failed"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - switch (auth_alg) { - case WLAN_AUTH_OPEN: - txt = "authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - break; - - case WLAN_AUTH_SHARED_KEY: - if (auth_transaction == 1) { - if (sta->u.sta.challenge == NULL) { - sta->u.sta.challenge = - ap_auth_make_challenge(local->ap); - if (sta->u.sta.challenge == NULL) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - } else { - if (sta->u.sta.challenge == NULL || - challenge == NULL || - memcmp(sta->u.sta.challenge, challenge, - WLAN_AUTH_CHALLENGE_LEN) != 0 || - !ieee80211_has_protected(hdr->frame_control)) { - txt = "challenge response incorrect"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - - txt = "challenge OK - authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - kfree(sta->u.sta.challenge); - sta->u.sta.challenge = NULL; - } - break; - } - - fail: - pos = (__le16 *) body; - *pos = cpu_to_le16(auth_alg); - pos++; - *pos = cpu_to_le16(auth_transaction + 1); - pos++; - *pos = cpu_to_le16(resp); /* status_code */ - pos++; - olen = 6; - - if (resp == WLAN_STATUS_SUCCESS && sta != NULL && - sta->u.sta.challenge != NULL && - auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { - u8 *tmp = (u8 *) pos; - *tmp++ = WLAN_EID_CHALLENGE; - *tmp++ = WLAN_AUTH_CHALLENGE_LEN; - pos++; - memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); - olen += 2 + WLAN_AUTH_CHALLENGE_LEN; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, - body, olen, hdr->addr2, ap->tx_callback_auth); - - if (sta) { - sta->last_rx = jiffies; - atomic_dec(&sta->users); - } - - if (resp) { - PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " - "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, hdr->addr2, - auth_alg, auth_transaction, status_code, len, - le16_to_cpu(hdr->frame_control), resp, txt); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_assoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int reassoc) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char body[12], *p, *lpos; - int len, left; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - int send_deauth = 0; - char __always_unused *txt = ""; - u8 prev_ap[ETH_ALEN]; - - left = len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < (reassoc ? 10 : 4)) { - PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from %pM\n", - dev->name, len, reassoc, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "trying to associate before authentication"; - send_deauth = 1; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - sta = NULL; /* do not decrement sta->users */ - goto fail; - } - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - sta->capability = __le16_to_cpu(*pos); - pos++; left -= 2; - sta->listen_interval = __le16_to_cpu(*pos); - pos++; left -= 2; - - if (reassoc) { - memcpy(prev_ap, pos, ETH_ALEN); - pos++; pos++; pos++; left -= 6; - } else - eth_zero_addr(prev_ap); - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - txt = "SSID overflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0) { - txt = "not our SSID"; - resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; - goto fail; - } - - u += ileft; - left -= ileft; - } - - if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || - ileft > WLAN_SUPP_RATES_MAX) { - txt = "SUPP_RATES len error"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - memset(sta->supported_rates, 0, - sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, u, ileft); - prism2_check_tx_rates(sta); - - u += ileft; - left -= ileft; - } - - if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from %pM" - " with extra data (%d bytes) [", - dev->name, hdr->addr2, left); - while (left > 0) { - PDEBUG2(DEBUG_AP, "<%02x>", *u); - u++; left--; - } - PDEBUG2(DEBUG_AP, "]\n"); - } - } else { - txt = "frame underflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - /* get a unique AID */ - if (sta->aid > 0) - txt = "OK, old AID"; - else { - spin_lock_bh(&local->ap->sta_table_lock); - for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) - if (local->ap->sta_aid[sta->aid - 1] == NULL) - break; - if (sta->aid > MAX_AID_TABLE_SIZE) { - sta->aid = 0; - spin_unlock_bh(&local->ap->sta_table_lock); - resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - txt = "no room for more AIDs"; - } else { - local->ap->sta_aid[sta->aid - 1] = sta; - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "OK, new AID"; - } - } - - fail: - pos = (__le16 *) body; - - if (send_deauth) { - *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); - pos++; - } else { - /* FIX: CF-Pollable and CF-PollReq should be set to match the - * values in beacons/probe responses */ - /* FIX: how about privacy and WEP? */ - /* capability */ - *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); - pos++; - - /* status_code */ - *pos = cpu_to_le16(resp); - pos++; - - *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | - BIT(14) | BIT(15)); /* AID */ - pos++; - - /* Supported rates (Information element) */ - p = (char *) pos; - *p++ = WLAN_EID_SUPP_RATES; - lpos = p; - *p++ = 0; /* len */ - if (local->tx_rate_control & WLAN_RATE_1M) { - *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_2M) { - *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_5M5) { - *p++ = local->basic_rates & WLAN_RATE_5M5 ? - 0x8b : 0x0b; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_11M) { - *p++ = local->basic_rates & WLAN_RATE_11M ? - 0x96 : 0x16; - (*lpos)++; - } - pos = (__le16 *) p; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - (send_deauth ? IEEE80211_STYPE_DEAUTH : - (reassoc ? IEEE80211_STYPE_REASSOC_RESP : - IEEE80211_STYPE_ASSOC_RESP)), - body, (u8 *) pos - (u8 *) body, - hdr->addr2, - send_deauth ? 0 : local->ap->tx_callback_assoc); - - if (sta) { - if (resp == WLAN_STATUS_SUCCESS) { - sta->last_rx = jiffies; - /* STA will be marked associated from TX callback, if - * AssocResp is ACKed */ - } - atomic_dec(&sta->users); - } - -#if 0 - PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " - "prev_ap=%pM) => %d(%d) (%s)\n", - dev->name, - hdr->addr2, - reassoc ? "re" : "", len, - prev_ap, - resp, send_deauth, txt); -#endif -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_deauth(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_deauth - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: deauthentication from %pM, " - "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_disassoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_disassoc - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~WLAN_STA_ASSOC; - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: disassociation from %pM, " - "reason_code=%d, but STA not authenticated\n", - dev->name, hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - - /* some STA f/w's seem to require control::ACK frame for - * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does - * not send this.. - * send control::ACK for the data::nullfunc */ - - printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); - prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, - NULL, 0, hdr->addr2, 0); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - __le16 reason; - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { - PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); - atomic_dec(&sta->users); - return; - } - - reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? - IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), - (char *) &reason, sizeof(reason), hdr->addr2, 0); - - if (sta) - atomic_dec(&sta->users); -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a scheduled task for pending AP frames. */ -static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, - struct sk_buff *skb) -{ - struct hostap_skb_tx_data *meta; - - if (!(sta->flags & WLAN_STA_PS)) { - /* Station has moved to non-PS mode, so send all buffered - * frames using normal device queue. */ - dev_queue_xmit(skb); - return; - } - - /* add a flag for hostap_handle_sta_tx() to know that this skb should - * be passed through even though STA is using PS */ - meta = (struct hostap_skb_tx_data *) skb->cb; - meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; - if (!skb_queue_empty(&sta->tx_buf)) { - /* indicate to STA that more frames follow */ - meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; - } - dev_queue_xmit(skb); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - u16 aid; - struct sk_buff *skb; - - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", - hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, - "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", - hdr->addr1); - return; - } - - aid = le16_to_cpu(hdr->duration_id); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { - PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); - return; - } - aid &= ~(BIT(15) | BIT(14)); - if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { - PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); - return; - } - PDEBUG(DEBUG_PS2, " aid=%d\n", aid); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - PDEBUG(DEBUG_PS, " STA not found\n"); - return; - } - if (sta->aid != aid) { - PDEBUG(DEBUG_PS, " received aid=%i does not match with " - "assoc.aid=%d\n", aid, sta->aid); - return; - } - - /* FIX: todo: - * - add timeout for buffering (clear aid in TIM vector if buffer timed - * out (expiry time must be longer than ListenInterval for - * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" - * - what to do, if buffered, pspolled, and sent frame is not ACKed by - * sta; store buffer for later use and leave TIM aid bit set? use - * TX event to check whether frame was ACKed? - */ - - while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { - /* send buffered frame .. */ - PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" - " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); - - pspoll_send_buffered(local, sta, skb); - - if (sta->flags & WLAN_STA_PS) { - /* send only one buffered packet per PS Poll */ - /* FIX: should ignore further PS Polls until the - * buffered packet that was just sent is acknowledged - * (Tx or TxExc event) */ - break; - } - } - - if (skb_queue_empty(&sta->tx_buf)) { - /* try to clear aid from TIM */ - if (!(sta->flags & WLAN_STA_TIM)) - PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", - aid); - hostap_set_tim(local, aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - atomic_dec(&sta->users); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void handle_wds_oper_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - wds_oper_queue); - local_info_t *local = ap->local; - struct wds_oper_data *entry, *prev; - - spin_lock_bh(&local->lock); - entry = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = NULL; - spin_unlock_bh(&local->lock); - - while (entry) { - PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP %pM\n", - local->dev->name, - entry->type == WDS_ADD ? "adding" : "removing", - entry->addr); - if (entry->type == WDS_ADD) - prism2_wds_add(local, entry->addr, 0); - else if (entry->type == WDS_DEL) - prism2_wds_del(local, entry->addr, 0, 1); - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_beacon(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len, left; - u16 beacon_int, capability; - __le16 *pos; - char *ssid = NULL; - unsigned char *supp_rates = NULL; - int ssid_len = 0, supp_rates_len = 0; - struct sta_info *sta = NULL; - int new_sta = 0, channel = -1; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 8 + 2 + 2) { - printk(KERN_DEBUG "handle_beacon - too short payload " - "(len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - left = len; - - /* Timestamp (8 octets) */ - pos += 4; left -= 8; - /* Beacon interval (2 octets) */ - beacon_int = le16_to_cpu(*pos); - pos++; left -= 2; - /* Capability information (2 octets) */ - capability = le16_to_cpu(*pos); - pos++; left -= 2; - - if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && - capability & WLAN_CAPABILITY_IBSS) - return; - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - PDEBUG(DEBUG_AP, "SSID: overflow\n"); - return; - } - - if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && - (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0)) { - /* not our SSID */ - return; - } - - ssid = u; - ssid_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || ileft > 8) { - PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); - return; - } - - supp_rates = u; - supp_rates_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_DS_PARAMS) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft != 1) { - PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); - return; - } - - channel = *u; - - u += ileft; - left -= ileft; - } - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - /* add new AP */ - new_sta = 1; - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - printk(KERN_INFO "prism2: kmalloc failed for AP " - "data structure\n"); - return; - } - hostap_event_new_sta(local->dev, sta); - - /* mark APs authentication and associated for pseudo ad-hoc - * style communication */ - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - - if (local->ap->autom_ap_wds) { - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - } - - sta->ap = 1; - if (ssid) { - sta->u.ap.ssid_len = ssid_len; - memcpy(sta->u.ap.ssid, ssid, ssid_len); - sta->u.ap.ssid[ssid_len] = '\0'; - } else { - sta->u.ap.ssid_len = 0; - sta->u.ap.ssid[0] = '\0'; - } - sta->u.ap.channel = channel; - sta->rx_packets++; - sta->rx_bytes += len; - sta->u.ap.last_beacon = sta->last_rx = jiffies; - sta->capability = capability; - sta->listen_interval = beacon_int; - - atomic_dec(&sta->users); - - if (new_sta) { - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, supp_rates, supp_rates_len); - prism2_check_tx_rates(sta); - } -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a tasklet. */ -static void handle_ap_item(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - struct net_device *dev = local->dev; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - /* FIX: should give skb->len to handler functions and check that the - * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { - PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); - - if (!(fc & IEEE80211_FCTL_TODS) || - (fc & IEEE80211_FCTL_FROMDS)) { - if (stype == IEEE80211_STYPE_NULLFUNC) { - /* no ToDS nullfunc seems to be used to check - * AP association; so send reject message to - * speed up re-association */ - ap_handle_dropped_data(local, hdr); - goto done; - } - PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", - fc); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (local->ap->nullfunc_ack && - stype == IEEE80211_STYPE_NULLFUNC) - ap_handle_data_nullfunc(local, hdr); - else - ap_handle_dropped_data(local, hdr); - goto done; - } - - if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { - handle_beacon(local, skb, rx_stats); - goto done; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { - handle_pspoll(local, hdr, rx_stats); - goto done; - } - - if (local->hostapd) { - PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " - "subtype=0x%02x\n", type, stype); - goto done; - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (type != IEEE80211_FTYPE_MGMT) { - PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" - " not own MAC\n", hdr->addr3); - goto done; - } - - switch (stype) { - case IEEE80211_STYPE_ASSOC_REQ: - handle_assoc(local, skb, rx_stats, 0); - break; - case IEEE80211_STYPE_ASSOC_RESP: - PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_REASSOC_REQ: - handle_assoc(local, skb, rx_stats, 1); - break; - case IEEE80211_STYPE_REASSOC_RESP: - PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_ATIM: - PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); - break; - case IEEE80211_STYPE_DISASSOC: - handle_disassoc(local, skb, rx_stats); - break; - case IEEE80211_STYPE_AUTH: - handle_authen(local, skb, rx_stats); - break; - case IEEE80211_STYPE_DEAUTH: - handle_deauth(local, skb, rx_stats); - break; - default: - PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", - stype >> 4); - break; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - done: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 16) - goto drop; - - dev->stats.rx_packets++; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && - ieee80211_is_beacon(hdr->frame_control)) - goto drop; - - skb->protocol = cpu_to_be16(ETH_P_HOSTAP); - handle_ap_item(local, skb, rx_stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void schedule_packet_send(local_info_t *local, struct sta_info *sta) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct hostap_80211_rx_status rx_stats; - - if (skb_queue_empty(&sta->tx_buf)) - return; - - skb = dev_alloc_skb(16); - if (skb == NULL) { - printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " - "failed\n", local->dev->name); - return; - } - - hdr = skb_put(skb, 16); - - /* Generate a fake pspoll frame to start packet delivery */ - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); - memcpy(hdr->addr2, sta->addr, ETH_ALEN); - hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - - PDEBUG(DEBUG_PS2, - "%s: Scheduling buffered packet delivery for STA %pM\n", - local->dev->name, sta->addr); - - skb->dev = local->dev; - - memset(&rx_stats, 0, sizeof(rx_stats)); - hostap_rx(local->dev, skb, &rx_stats); -} - - -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist) -{ - struct ap_data *ap = local->ap; - struct list_head *ptr; - int count = 0; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - if (aplist && !sta->ap) - continue; - addr[count].sa_family = ARPHRD_ETHER; - memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); - if (sta->last_rx_silence == 0) - qual[count].qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - qual[count].qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - qual[count].updated = sta->last_rx_updated; - - sta->last_rx_updated = IW_QUAL_DBM; - - count++; - if (count >= buf_size) - break; - } - spin_unlock_bh(&ap->sta_table_lock); - - return count; -} - - -/* Translate our list of Access Points & Stations to a card independent - * format that the Wireless Tools will understand - Jean II */ -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ap_data *ap; - struct list_head *ptr; - struct iw_event iwe; - char *current_ev = buffer; - char *end_buf = buffer + IW_SCAN_MAX_DATA; -#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) - char buf[64]; -#endif - - iface = netdev_priv(dev); - local = iface->local; - ap = local->ap; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); - iwe.len = IW_EV_ADDR_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Use the mode to indicate if it's a station or - * an Access Point */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (sta->ap) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_INFRA; - iwe.len = IW_EV_UINT_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - - /* Some quality */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (sta->last_rx_silence == 0) - iwe.u.qual.qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - iwe.u.qual.qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - iwe.u.qual.updated = sta->last_rx_updated; - iwe.len = IW_EV_QUAL_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = sta->u.ap.ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = - IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - if (sta->u.ap.channel > 0 && - sta->u.ap.channel <= FREQ_COUNT) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] - * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event( - info, current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "beacon_interval=%d", - sta->listen_interval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - sta->last_rx_updated = IW_QUAL_DBM; - - /* To be continued, we should make good use of IWEVCUSTOM */ - } - - spin_unlock_bh(&ap->sta_table_lock); - - return current_ev - buffer; -} - - -static int prism2_hostapd_add_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta == NULL) { - sta = ap_add_sta(ap, param->sta_addr); - if (sta == NULL) - return -1; - } - - if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_new_sta(sta->local->dev, sta); - - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->last_rx = jiffies; - sta->aid = param->u.add_sta.aid; - sta->capability = param->u.add_sta.capability; - sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; - if (sta->tx_supp_rates & WLAN_RATE_1M) - sta->supported_rates[0] = 2; - if (sta->tx_supp_rates & WLAN_RATE_2M) - sta->supported_rates[1] = 4; - if (sta->tx_supp_rates & WLAN_RATE_5M5) - sta->supported_rates[2] = 11; - if (sta->tx_supp_rates & WLAN_RATE_11M) - sta->supported_rates[3] = 22; - prism2_check_tx_rates(sta); - atomic_dec(&sta->users); - return 0; -} - - -static int prism2_hostapd_remove_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - - return 0; -} - - -static int prism2_hostapd_get_info_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; - - atomic_dec(&sta->users); - - return 1; -} - - -static int prism2_hostapd_set_flags_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->flags |= param->u.set_flags_sta.flags_or; - sta->flags &= param->u.set_flags_sta.flags_and; - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - int rate; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->rx_packets = sta->tx_packets = 0; - sta->rx_bytes = sta->tx_bytes = 0; - for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { - sta->tx_count[rate] = 0; - sta->rx_count[rate] = 0; - } - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) -{ - switch (param->cmd) { - case PRISM2_HOSTAPD_FLUSH: - ap_control_kickall(ap); - return 0; - case PRISM2_HOSTAPD_ADD_STA: - return prism2_hostapd_add_sta(ap, param); - case PRISM2_HOSTAPD_REMOVE_STA: - return prism2_hostapd_remove_sta(ap, param); - case PRISM2_HOSTAPD_GET_INFO_STA: - return prism2_hostapd_get_info_sta(ap, param); - case PRISM2_HOSTAPD_SET_FLAGS_STA: - return prism2_hostapd_set_flags_sta(ap, param); - case PRISM2_HOSTAPD_STA_CLEAR_STATS: - return prism2_hostapd_sta_clear_stats(ap, param); - default: - printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", - param->cmd); - return -EOPNOTSUPP; - } -} - - -/* Update station info for host-based TX rate control and return current - * TX rate */ -static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) -{ - int ret = sta->tx_rate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - sta->tx_count[sta->tx_rate_idx]++; - sta->tx_since_last_failure++; - sta->tx_consecutive_exc = 0; - if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && - sta->tx_rate_idx < sta->tx_max_rate) { - /* use next higher rate */ - int old_rate, new_rate; - old_rate = new_rate = sta->tx_rate_idx; - while (new_rate < sta->tx_max_rate) { - new_rate++; - if (ap_tx_rate_ok(new_rate, sta, local)) { - sta->tx_rate_idx = new_rate; - break; - } - } - if (old_rate != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", - dev->name, sta->addr, sta->tx_rate); - } - sta->tx_since_last_failure = 0; - } - - return ret; -} - - -/* Called only from software IRQ. Called for each TX frame prior possible - * encryption and transmit. */ -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) -{ - struct sta_info *sta = NULL; - struct sk_buff *skb = tx->skb; - int set_tim, ret; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - meta = (struct hostap_skb_tx_data *) skb->cb; - ret = AP_TX_CONTINUE; - if (local->ap == NULL || skb->len < 10 || - meta->iface->type == HOSTAP_INTERFACE_STA) - goto out; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (hdr->addr1[0] & 0x01) { - /* broadcast/multicast frame - no AP related processing */ - if (local->ap->num_sta <= 0) - ret = AP_TX_DROP; - goto out; - } - - /* unicast packet - check whether destination STA is associated */ - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (local->iw_mode == IW_MODE_MASTER && sta == NULL && - !(meta->flags & HOSTAP_TX_FLAGS_WDS) && - meta->iface->type != HOSTAP_INTERFACE_MASTER && - meta->iface->type != HOSTAP_INTERFACE_AP) { -#if 0 - /* This can happen, e.g., when wlan0 is added to a bridge and - * bridging code does not know which port is the correct target - * for a unicast frame. In this case, the packet is send to all - * ports of the bridge. Since this is a valid scenario, do not - * print out any errors here. */ - if (net_ratelimit()) { - printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA %pM\n", hdr->addr1); - } -#endif - local->ap->tx_drop_nonassoc++; - ret = AP_TX_DROP; - goto out; - } - - if (sta == NULL) - goto out; - - if (!(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_TX_CONTINUE_NOT_AUTHORIZED; - - /* Set tx_rate if using host-based TX rate control */ - if (!local->fw_tx_rate_control) - local->ap->last_tx_rate = meta->rate = - ap_update_sta_tx_rate(sta, local->dev); - - if (local->iw_mode != IW_MODE_MASTER) - goto out; - - if (!(sta->flags & WLAN_STA_PS)) - goto out; - - if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { - /* indicate to STA that more frames follow */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { - /* packet was already buffered and now send due to - * PS poll, so do not rebuffer it */ - goto out; - } - - if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" - "PS mode buffer\n", - local->dev->name, sta->addr); - /* Make sure that TIM is set for the station (it might not be - * after AP wlan hw reset). */ - /* FIX: should fix hw reset to restore bits based on STA - * buffer state.. */ - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - ret = AP_TX_DROP; - goto out; - } - - /* STA in PS mode, buffer frame for later delivery */ - set_tim = skb_queue_empty(&sta->tx_buf); - skb_queue_tail(&sta->tx_buf, skb); - /* FIX: could save RX time to skb and expire buffered frames after - * some time if STA does not poll for them */ - - if (set_tim) { - if (sta->flags & WLAN_STA_TIM) - PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", - sta->aid); - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - } - - ret = AP_TX_BUFFERED; - - out: - if (sta != NULL) { - if (ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { - sta->tx_packets++; - sta->tx_bytes += skb->len; - sta->last_tx = jiffies; - } - - if ((ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && - sta->crypt && tx->host_encrypt) { - tx->crypt = sta->crypt; - tx->sta_ptr = sta; /* hostap_handle_sta_release() will - * be called to release sta info - * later */ - } else - atomic_dec(&sta->users); - } - - return ret; -} - - -void hostap_handle_sta_release(void *ptr) -{ - struct sta_info *sta = ptr; - atomic_dec(&sta->users); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) -{ - struct sta_info *sta; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - hdr = (struct ieee80211_hdr *) skb->data; - meta = (struct hostap_skb_tx_data *) skb->cb; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (!sta) { - spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" - " for this TX error (@%lu)\n", - local->dev->name, hdr->addr1, jiffies); - return; - } - - sta->tx_since_last_failure = 0; - sta->tx_consecutive_exc++; - - if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && - sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { - /* use next lower rate */ - int old, rate; - old = rate = sta->tx_rate_idx; - while (rate > 0) { - rate--; - if (ap_tx_rate_ok(rate, sta, local)) { - sta->tx_rate_idx = rate; - break; - } - } - if (old != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, - "%s: STA %pM TX rate lowered to %d\n", - local->dev->name, sta->addr, sta->tx_rate); - } - sta->tx_consecutive_exc = 0; - } - spin_unlock(&local->ap->sta_table_lock); -} - - -static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, - int pwrmgt, int type, int stype) -{ - if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { - sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " - "mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { - sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to not use " - "PS mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - if (type != IEEE80211_FTYPE_CTL || - stype != IEEE80211_STYPE_PSPOLL) - schedule_packet_send(local, sta); - } -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame to update - * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sta_info *sta; - u16 fc; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - fc = le16_to_cpu(hdr->frame_control); - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - fc & IEEE80211_FCTL_FTYPE, - fc & IEEE80211_FCTL_STYPE); - - atomic_dec(&sta->users); - return 0; -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame after - * getting RX header and payload from hardware. */ -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds) -{ - int ret; - struct sta_info *sta; - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - if (local->ap == NULL) - return AP_RX_CONTINUE; - - hdr = (struct ieee80211_hdr *) skb->data; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_RX_CONTINUE_NOT_AUTHORIZED; - else - ret = AP_RX_CONTINUE; - - - if (fc & IEEE80211_FCTL_TODS) { - if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA %pM" - " (type=0x%02x, subtype=0x%02x)\n", - dev->name, hdr->addr2, - type >> 2, stype >> 4); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - } else if (fc & IEEE80211_FCTL_FROMDS) { - if (!wds) { - /* FromDS frame - not for us; probably - * broadcast/multicast in another BSS - drop */ - if (ether_addr_equal(hdr->addr1, dev->dev_addr)) { - printk(KERN_DEBUG "Odd.. FromDS packet " - "received with own BSSID\n"); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* At least Lucent f/w seems to send data::nullfunc - * frames with no ToDS flag when the current AP returns - * after being unavailable for some time. Speed up - * re-association by informing the station about it not - * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc frame" - " without ToDS from not associated STA %pM\n", - dev->name, hdr->addr2); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } else if (stype == IEEE80211_STYPE_NULLFUNC) { - /* At least Lucent cards seem to send periodic nullfunc - * frames with ToDS. Let these through to update SQ - * stats and PS state. Nullfunc frames do not contain - * any data and they will be dropped below. */ - } else { - /* If BSSID (Addr3) is foreign, this frame is a normal - * broadcast frame from an IBSS network. Drop it silently. - * If BSSID is own, report the dropping of this frame. */ - if (ether_addr_equal(hdr->addr3, dev->dev_addr)) { - printk(KERN_DEBUG "%s: dropped received packet from %pM" - " with no ToDS flag " - "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2, type >> 2, stype >> 4); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - - if (sta) { - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - type, stype); - - sta->rx_packets++; - sta->rx_bytes += skb->len; - sta->last_rx = jiffies; - } - - if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && - fc & IEEE80211_FCTL_TODS) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NULLFUNC_ACK); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* some STA f/w's seem to require control::ACK frame - * for data::nullfunc, but Prism2 f/w 0.8.0 (at least - * from Compaq) does not send this.. Try to generate - * ACK for these frames from the host driver to make - * power saving work with, e.g., Lucent WaveLAN f/w */ - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - - out: - if (sta) - atomic_dec(&sta->users); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr) -{ - struct sta_info *sta; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - if (sta->crypt) { - *crypt = sta->crypt; - *sta_ptr = sta; - /* hostap_handle_sta_release() will be called to release STA - * info */ - } else - atomic_dec(&sta->users); - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && - ((sta->flags & WLAN_STA_AUTHORIZED) || - ap->local->ieee_802_1x == 0)) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 1; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta) - ret = 0; - spin_unlock(&ap->sta_table_lock); - - if (ret == 1) { - sta = ap_add_sta(ap, sta_addr); - if (!sta) - return -1; - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->ap = 1; - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - /* No way of knowing which rates are supported since we did not - * get supported rates element from beacon/assoc req. Assume - * that remote end supports all 802.11b rates. */ - sta->supported_rates[0] = 0x82; - sta->supported_rates[1] = 0x84; - sta->supported_rates[2] = 0x0b; - sta->supported_rates[3] = 0x16; - sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | - WLAN_RATE_5M5 | WLAN_RATE_11M; - sta->tx_rate = 110; - sta->tx_max_rate = sta->tx_rate_idx = 3; - } - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct sta_info *sta; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr2); - if (sta) { - sta->last_rx_silence = rx_stats->noise; - sta->last_rx_signal = rx_stats->signal; - sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - if (rx_stats->rate == 10) - sta->rx_count[0]++; - else if (rx_stats->rate == 20) - sta->rx_count[1]++; - else if (rx_stats->rate == 55) - sta->rx_count[2]++; - else if (rx_stats->rate == 110) - sta->rx_count[3]++; - } - spin_unlock(&ap->sta_table_lock); - - return sta ? 0 : -1; -} - - -void hostap_update_rates(local_info_t *local) -{ - struct sta_info *sta; - struct ap_data *ap = local->ap; - - if (!ap) - return; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - prism2_check_tx_rates(sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta && permanent) - sta = ap_add_sta(ap, addr); - - if (!sta) - return NULL; - - if (permanent) - sta->flags |= WLAN_STA_PERM; - - *crypt = &sta->crypt; - - return sta; -} - - -void hostap_add_wds_links(local_info_t *local) -{ - struct ap_data *ap = local->ap; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - if (sta->ap) - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - spin_unlock_bh(&ap->sta_table_lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) -{ - struct wds_oper_data *entry; - - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return; - memcpy(entry->addr, addr, ETH_ALEN); - entry->type = type; - spin_lock_bh(&local->lock); - entry->next = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = entry; - spin_unlock_bh(&local->lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -EXPORT_SYMBOL(hostap_init_data); -EXPORT_SYMBOL(hostap_init_ap_proc); -EXPORT_SYMBOL(hostap_free_data); -EXPORT_SYMBOL(hostap_check_sta_fw_version); -EXPORT_SYMBOL(hostap_handle_sta_tx_exc); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.h b/drivers/net/wireless/intersil/hostap/hostap_ap.h deleted file mode 100644 index b7ac9e2f1a39..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.h +++ /dev/null @@ -1,264 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_AP_H -#define HOSTAP_AP_H - -#include "hostap_80211.h" - -/* AP data structures for STAs */ - -/* maximum number of frames to buffer per STA */ -#define STA_MAX_TX_BUFFER 32 - -/* STA flags */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ - -#define WLAN_RATE_1M BIT(0) -#define WLAN_RATE_2M BIT(1) -#define WLAN_RATE_5M5 BIT(2) -#define WLAN_RATE_11M BIT(3) -#define WLAN_RATE_COUNT 4 - -/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, - * but some pre-standard IEEE 802.11g products use longer elements. */ -#define WLAN_SUPP_RATES_MAX 32 - -/* Try to increase TX rate after # successfully sent consecutive packets */ -#define WLAN_RATE_UPDATE_COUNT 50 - -/* Decrease TX rate after # consecutive dropped packets */ -#define WLAN_RATE_DECREASE_THRESHOLD 2 - -struct sta_info { - struct list_head list; - struct sta_info *hnext; /* next entry in hash table list */ - atomic_t users; /* number of users (do not remove if > 0) */ - struct proc_dir_entry *proc; - - u8 addr[6]; - u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ - u32 flags; - u16 capability; - u16 listen_interval; /* or beacon_int for APs */ - u8 supported_rates[WLAN_SUPP_RATES_MAX]; - - unsigned long last_auth; - unsigned long last_assoc; - unsigned long last_rx; - unsigned long last_tx; - unsigned long rx_packets, tx_packets; - unsigned long rx_bytes, tx_bytes; - struct sk_buff_head tx_buf; - /* FIX: timeout buffers with an expiry time somehow derived from - * listen_interval */ - - s8 last_rx_silence; /* Noise in dBm */ - s8 last_rx_signal; /* Signal strength in dBm */ - u8 last_rx_rate; /* TX rate in 0.1 Mbps */ - u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ - - u8 tx_supp_rates; /* bit field of supported TX rates */ - u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ - u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ - u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ - u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ - u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) - */ - u32 tx_since_last_failure; - u32 tx_consecutive_exc; - - struct lib80211_crypt_data *crypt; - - int ap; /* whether this station is an AP */ - - local_info_t *local; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - union { - struct { - char *challenge; /* shared key authentication - * challenge */ - } sta; - struct { - int ssid_len; - unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ - int channel; - unsigned long last_beacon; /* last RX beacon time */ - } ap; - } u; - - struct timer_list timer; - enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -#define MAX_STA_COUNT 1024 - -/* Maximum number of AIDs to use for STAs; must be 2007 or lower - * (8802.11 limitation) */ -#define MAX_AID_TABLE_SIZE 128 - -#define STA_HASH_SIZE 256 -#define STA_HASH(sta) (sta[5]) - - -/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC - * has passed since last received frame from the station, a nullfunc data - * frame is sent to the station. If this frame is not acknowledged and no other - * frames have been received, the station will be disassociated after - * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after - * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with - * max inactivity timer. */ -#define AP_MAX_INACTIVITY_SEC (5 * 60) -#define AP_DISASSOC_DELAY (HZ) -#define AP_DEAUTH_DELAY (HZ) - -/* ap_policy: whether to accept frames to/from other APs/IBSS */ -typedef enum { - AP_OTHER_AP_SKIP_ALL = 0, - AP_OTHER_AP_SAME_SSID = 1, - AP_OTHER_AP_ALL = 2, - AP_OTHER_AP_EVEN_IBSS = 3 -} ap_policy_enum; - -#define PRISM2_AUTH_OPEN BIT(0) -#define PRISM2_AUTH_SHARED_KEY BIT(1) - - -/* MAC address-based restrictions */ -struct mac_entry { - struct list_head list; - u8 addr[6]; -}; - -struct mac_restrictions { - enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; - unsigned int entries; - struct list_head mac_list; - spinlock_t lock; -}; - - -struct add_sta_proc_data { - u8 addr[ETH_ALEN]; - struct add_sta_proc_data *next; -}; - - -typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; -struct wds_oper_data { - wds_oper_type type; - u8 addr[ETH_ALEN]; - struct wds_oper_data *next; -}; - - -struct ap_data { - int initialized; /* whether ap_data has been initialized */ - local_info_t *local; - int bridge_packets; /* send packet to associated STAs directly to the - * wireless media instead of higher layers in the - * kernel */ - unsigned int bridged_unicast; /* number of unicast frames bridged on - * wireless media */ - unsigned int bridged_multicast; /* number of non-unicast frames - * bridged on wireless media */ - unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped - * because they were to an address that - * was not associated */ - int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ - - spinlock_t sta_table_lock; - int num_sta; /* number of entries in sta_list */ - struct list_head sta_list; /* STA info list head */ - struct sta_info *sta_hash[STA_HASH_SIZE]; - - struct proc_dir_entry *proc; - - ap_policy_enum ap_policy; - unsigned int max_inactivity; - int autom_ap_wds; - - struct mac_restrictions mac_restrictions; /* MAC-based auth */ - int last_tx_rate; - - struct work_struct add_sta_proc_queue; - struct add_sta_proc_data *add_sta_proc_entries; - - struct work_struct wds_oper_queue; - struct wds_oper_data *wds_oper_entries; - - u16 tx_callback_idx; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - /* pointers to STA info; based on allocated AID or NULL if AID free - * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 - * and so on - */ - struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; - - u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; - - /* WEP operations for generating challenges to be used with shared key - * authentication */ - struct lib80211_crypto_ops *crypt; - void *crypt_priv; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_init_data(local_info_t *local); -void hostap_init_ap_proc(local_info_t *local); -void hostap_free_data(struct ap_data *ap); -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); - -typedef enum { - AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, - AP_TX_CONTINUE_NOT_AUTHORIZED -} ap_tx_ret; -struct hostap_tx_data { - struct sk_buff *skb; - int host_encrypt; - struct lib80211_crypt_data *crypt; - void *sta_ptr; -}; -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); -void hostap_handle_sta_release(void *ptr); -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); -typedef enum { - AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED -} ap_rx_ret; -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr); -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats); -void hostap_update_rates(local_info_t *local); -void hostap_add_wds_links(local_info_t *local); -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#endif /* HOSTAP_AP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_common.h b/drivers/net/wireless/intersil/hostap/hostap_common.h deleted file mode 100644 index dd29a8e8d349..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_common.h +++ /dev/null @@ -1,420 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_COMMON_H -#define HOSTAP_COMMON_H - -#include -#include - -/* IEEE 802.11 defines */ - -/* HFA384X Configuration RIDs */ -#define HFA384X_RID_CNFPORTTYPE 0xFC00 -#define HFA384X_RID_CNFOWNMACADDR 0xFC01 -#define HFA384X_RID_CNFDESIREDSSID 0xFC02 -#define HFA384X_RID_CNFOWNCHANNEL 0xFC03 -#define HFA384X_RID_CNFOWNSSID 0xFC04 -#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 -#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 -#define HFA384X_RID_CNFMAXDATALEN 0xFC07 -#define HFA384X_RID_CNFWDSADDRESS 0xFC08 -#define HFA384X_RID_CNFPMENABLED 0xFC09 -#define HFA384X_RID_CNFPMEPS 0xFC0A -#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HFA384X_RID_CNFOWNNAME 0xFC0E -#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ -#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ -#define HFA384X_RID_UNKNOWN1 0xFC20 -#define HFA384X_RID_UNKNOWN2 0xFC21 -#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 -#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 -#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 -#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 -#define HFA384X_RID_CNFWEPFLAGS 0xFC28 -#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A -#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ -#define HFA384X_RID_CNFTXCONTROL 0xFC2C -#define HFA384X_RID_CNFROAMINGMODE 0xFC2D -#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ -#define HFA384X_RID_CNFRCVCRCERROR 0xFC30 -#define HFA384X_RID_CNFMMLIFE 0xFC31 -#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 -#define HFA384X_RID_CNFBEACONINT 0xFC33 -#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ -#define HFA384X_RID_CNFSTAPCFINFO 0xFC35 -#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HFA384X_RID_CNFTIMCTRL 0xFC40 -#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ -#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ -#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ -#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; - * write only */ -#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_GROUPADDRESSES 0xFC80 -#define HFA384X_RID_CREATEIBSS 0xFC81 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 -#define HFA384X_RID_RTSTHRESHOLD 0xFC83 -#define HFA384X_RID_TXRATECONTROL 0xFC84 -#define HFA384X_RID_PROMISCUOUSMODE 0xFC85 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ -#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HFA384X_RID_CNFBASICRATES 0xFCB3 -#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ -#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ -#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ -#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ -#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ -#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_TICKTIME 0xFCE0 -#define HFA384X_RID_SCANREQUEST 0xFCE1 -#define HFA384X_RID_JOINREQUEST 0xFCE2 -#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ -#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ -#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ - -/* HFA384X Information RIDs */ -#define HFA384X_RID_MAXLOADTIME 0xFD00 -#define HFA384X_RID_DOWNLOADBUFFER 0xFD01 -#define HFA384X_RID_PRIID 0xFD02 -#define HFA384X_RID_PRISUPRANGE 0xFD03 -#define HFA384X_RID_CFIACTRANGES 0xFD04 -#define HFA384X_RID_NICSERNUM 0xFD0A -#define HFA384X_RID_NICID 0xFD0B -#define HFA384X_RID_MFISUPRANGE 0xFD0C -#define HFA384X_RID_CFISUPRANGE 0xFD0D -#define HFA384X_RID_CHANNELLIST 0xFD10 -#define HFA384X_RID_REGULATORYDOMAINS 0xFD11 -#define HFA384X_RID_TEMPTYPE 0xFD12 -#define HFA384X_RID_CIS 0xFD13 -#define HFA384X_RID_STAID 0xFD20 -#define HFA384X_RID_STASUPRANGE 0xFD21 -#define HFA384X_RID_MFIACTRANGES 0xFD22 -#define HFA384X_RID_CFIACTRANGES2 0xFD23 -#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; - * only Prism2.5(?) */ -#define HFA384X_RID_PORTSTATUS 0xFD40 -#define HFA384X_RID_CURRENTSSID 0xFD41 -#define HFA384X_RID_CURRENTBSSID 0xFD42 -#define HFA384X_RID_COMMSQUALITY 0xFD43 -#define HFA384X_RID_CURRENTTXRATE 0xFD44 -#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 -#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 -#define HFA384X_RID_LONGRETRYLIMIT 0xFD49 -#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B -#define HFA384X_RID_CFPOLLABLE 0xFD4C -#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ -#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ -#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ -#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ -#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_PHYTYPE 0xFDC0 -#define HFA384X_RID_CURRENTCHANNEL 0xFDC1 -#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 -#define HFA384X_RID_CCAMODE 0xFDC3 -#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 -#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ -#define HFA384X_RID_BUILDSEQ 0xFFFE -#define HFA384X_RID_FWID 0xFFFF - - -struct hfa384x_comp_ident -{ - __le16 id; - __le16 variant; - __le16 major; - __le16 minor; -} __packed; - -#define HFA384X_COMP_ID_PRI 0x15 -#define HFA384X_COMP_ID_STA 0x1f -#define HFA384X_COMP_ID_FW_AP 0x14b - -struct hfa384x_sup_range -{ - __le16 role; - __le16 id; - __le16 variant; - __le16 bottom; - __le16 top; -} __packed; - - -struct hfa384x_build_id -{ - __le16 pri_seq; - __le16 sec_seq; -} __packed; - -/* FD01 - Download Buffer */ -struct hfa384x_rid_download_buffer -{ - __le16 page; - __le16 offset; - __le16 length; -} __packed; - -/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ -struct hfa384x_comms_quality { - __le16 comm_qual; /* 0 .. 92 */ - __le16 signal_level; /* 27 .. 154 */ - __le16 noise_level; /* 27 .. 154 */ -} __packed; - - -/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ - -/* New wireless extensions API - SET/GET convention (even ioctl numbers are - * root only) - */ -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) -#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) -#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) -#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) -#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) -#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) -#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) -#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) -#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) -#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) -#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) -#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) - -/* following are not in SIOCGIWPRIV list; check permission in the driver code - */ -#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) -#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) - - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ -enum { - /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_TXRATECTRL = 2, - PRISM2_PARAM_BEACON_INT = 3, - PRISM2_PARAM_PSEUDO_IBSS = 4, - PRISM2_PARAM_ALC = 5, - /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_DUMP = 7, - PRISM2_PARAM_OTHER_AP_POLICY = 8, - PRISM2_PARAM_AP_MAX_INACTIVITY = 9, - PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, - PRISM2_PARAM_DTIM_PERIOD = 11, - PRISM2_PARAM_AP_NULLFUNC_ACK = 12, - PRISM2_PARAM_MAX_WDS = 13, - PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, - PRISM2_PARAM_AP_AUTH_ALGS = 15, - PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, - PRISM2_PARAM_HOST_ENCRYPT = 17, - PRISM2_PARAM_HOST_DECRYPT = 18, - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ - PRISM2_PARAM_HOST_ROAMING = 21, - PRISM2_PARAM_BCRX_STA_KEY = 22, - PRISM2_PARAM_IEEE_802_1X = 23, - PRISM2_PARAM_ANTSEL_TX = 24, - PRISM2_PARAM_ANTSEL_RX = 25, - PRISM2_PARAM_MONITOR_TYPE = 26, - PRISM2_PARAM_WDS_TYPE = 27, - PRISM2_PARAM_HOSTSCAN = 28, - PRISM2_PARAM_AP_SCAN = 29, - PRISM2_PARAM_ENH_SEC = 30, - PRISM2_PARAM_IO_DEBUG = 31, - PRISM2_PARAM_BASIC_RATES = 32, - PRISM2_PARAM_OPER_RATES = 33, - PRISM2_PARAM_HOSTAPD = 34, - PRISM2_PARAM_HOSTAPD_STA = 35, - PRISM2_PARAM_WPA = 36, - PRISM2_PARAM_PRIVACY_INVOKED = 37, - PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, - PRISM2_PARAM_DROP_UNENCRYPTED = 39, - PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, -}; - -enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, - HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; - - -/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ -enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, - AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, - AP_MAC_CMD_KICKALL = 4 }; - - -/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ -enum { - PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, - /* Note! Old versions of prism2_srec have a fatal error in CRC-16 - * calculation, which will corrupt all non-volatile downloads. - * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to - * prevent use of old versions of prism2_srec for non-volatile - * download. */ - PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, - PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, - /* Persistent versions of volatile download commands (keep firmware - * data in memory and automatically re-download after hw_reset */ - PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, - PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, -}; - -struct prism2_download_param { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_area { - u32 addr; /* wlan card address */ - u32 len; - void __user *ptr; /* pointer to data in user space */ - } data[]; -}; - -#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 -#define PRISM2_MAX_DOWNLOAD_LEN 262144 - - -/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ -enum { - PRISM2_HOSTAPD_FLUSH = 1, - PRISM2_HOSTAPD_ADD_STA = 2, - PRISM2_HOSTAPD_REMOVE_STA = 3, - PRISM2_HOSTAPD_GET_INFO_STA = 4, - /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ - PRISM2_SET_ENCRYPTION = 6, - PRISM2_GET_ENCRYPTION = 7, - PRISM2_HOSTAPD_SET_FLAGS_STA = 8, - PRISM2_HOSTAPD_GET_RID = 9, - PRISM2_HOSTAPD_SET_RID = 10, - PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, - PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, - PRISM2_HOSTAPD_MLME = 13, - PRISM2_HOSTAPD_SCAN_REQ = 14, - PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, -}; - -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -#define PRISM2_HOSTAPD_RID_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.rid.data) -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.generic_elem.data) - -/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() - */ -#define HOSTAP_CRYPT_ALG_NAME_LEN 16 - - -struct prism2_hostapd_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u16 aid; - u16 capability; - u8 tx_supp_rates; - } add_sta; - struct { - u32 inactive_sec; - } get_info_sta; - struct { - u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; - u32 flags; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - struct { - u32 flags_and; - u32 flags_or; - } set_flags_sta; - struct { - u16 rid; - u16 len; - u8 data[0]; - } rid; - struct { - u8 len; - u8 data[0]; - } generic_elem; - struct { -#define MLME_STA_DEAUTH 0 -#define MLME_STA_DISASSOC 1 - u16 cmd; - u16 reason_code; - } mlme; - struct { - u8 ssid_len; - u8 ssid[32]; - } scan_req; - } u; -}; - -#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) -#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) - -#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 -#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 -#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 -#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 - - -#endif /* HOSTAP_COMMON_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_config.h b/drivers/net/wireless/intersil/hostap/hostap_config.h deleted file mode 100644 index 3ebd55847fad..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_config.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_CONFIG_H -#define HOSTAP_CONFIG_H - -/* In the previous versions of Host AP driver, support for user space version - * of IEEE 802.11 management (hostapd) used to be disabled in the default - * configuration. From now on, support for hostapd is always included and it is - * possible to disable kernel driver version of IEEE 802.11 management with a - * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ -/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -/* Maximum number of events handler per one interrupt */ -#define PRISM2_MAX_INTERRUPT_EVENTS 20 - -/* Include code for downloading firmware images into volatile RAM. */ -#define PRISM2_DOWNLOAD_SUPPORT - -/* Allow kernel configuration to enable download support. */ -#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) -#define PRISM2_DOWNLOAD_SUPPORT -#endif - -/* Allow kernel configuration to enable non-volatile download support. */ -#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM -#define PRISM2_NON_VOLATILE_DOWNLOAD -#endif - -/* Save low-level I/O for debugging. This should not be enabled in normal use. - */ -/* #define PRISM2_IO_DEBUG */ - -/* Following defines can be used to remove unneeded parts of the driver, e.g., - * to limit the size of the kernel module. Definitions can be added here in - * hostap_config.h or they can be added to make command with ccflags-y, - * e.g., - * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' - */ - -/* Do not include debug messages into the driver */ -/* #define PRISM2_NO_DEBUG */ - -/* Do not include /proc/net/prism2/wlan#/{registers,debug} */ -/* #define PRISM2_NO_PROCFS_DEBUG */ - -/* Do not include station functionality (i.e., allow only Master (Host AP) mode - */ -/* #define PRISM2_NO_STATION_MODES */ - -#endif /* HOSTAP_CONFIG_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c deleted file mode 100644 index ec7db2badc40..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_cs.c +++ /dev/null @@ -1,710 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCCARD - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_cs"; - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PC Card)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis_vcc; -module_param(ignore_cis_vcc, int, 0444); -MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); - - -/* struct local_info::hw_priv */ -struct hostap_cs_priv { - struct pcmcia_device *link; - int sandisk_connectplus; -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - - -static void prism2_detach(struct pcmcia_device *p_dev); -static void prism2_release(u_long arg); -static int prism2_config(struct pcmcia_device *link); - - -static int prism2_pccard_card_present(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) - return 1; - return 0; -} - - -/* - * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 - * Document No. 20-10-00058, January 2004 - * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf - */ -#define SANDISK_WLAN_ACTIVATION_OFF 0x40 -#define SANDISK_HCR_OFF 0x42 - - -static void sandisk_set_iobase(local_info_t *local) -{ - int res; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - res = pcmcia_write_config_byte(hw_priv->link, 0x10, - hw_priv->link->resource[0]->start & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" - " res=%d\n", res); - } - udelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, 0x12, - (hw_priv->link->resource[0]->start >> 8) & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" - " res=%d\n", res); - } -} - - -static void sandisk_write_hcr(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - int i; - - HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); - udelay(50); - for (i = 0; i < 10; i++) { - HFA384X_OUTB(hcr, SANDISK_HCR_OFF); - } - udelay(55); - HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); -} - - -static int sandisk_enable_wireless(struct net_device *dev) -{ - int res, ret = 0; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (resource_size(hw_priv->link->resource[0]) < 0x42) { - /* Not enough ports to be SanDisk multi-function card */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { - /* No SanDisk manfid found */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->socket->functions < 2) { - /* No multi-function links found */ - ret = -ENODEV; - goto done; - } - - printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" - " - using vendor-specific initialization\n", dev->name); - hw_priv->sandisk_connectplus = 1; - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - /* - * Do not enable interrupts here to avoid some bogus events. Interrupts - * will be enabled during the first cor_sreset call. - */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | - COR_FUNC_ENA)); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - sandisk_set_iobase(local); - - HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - -done: - return ret; -} - - -static void prism2_pccard_cor_sreset(local_info_t *local) -{ - int res; - u8 val; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", - res); - return; - } - printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", - val); - - val |= COR_SOFT_RESET; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - val &= ~COR_SOFT_RESET; - if (hw_priv->sandisk_connectplus) - val |= COR_IREQ_ENA; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - if (hw_priv->sandisk_connectplus) - sandisk_set_iobase(local); -} - - -static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) -{ - int res; - u8 old_cor; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - if (hw_priv->sandisk_connectplus) { - sandisk_write_hcr(local, hcr); - return; - } - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor); - if (res != 0) { - printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res); - return; - } - printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor | COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res); - return; - } - - mdelay(10); - - /* Setup Genesis mode */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr); - if (res != 0) { - printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res); - return; - } - mdelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor & ~COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res); - return; - } - - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pccard_funcs = -{ - .card_present = prism2_pccard_card_present, - .cor_sreset = prism2_pccard_cor_sreset, - .genesis_reset = prism2_pccard_genesis_reset, - .hw_type = HOSTAP_HW_PCCARD, -}; - - -/* allocate local data and register with CardServices - * initialize dev_link structure, but do not configure the card yet */ -static int hostap_cs_probe(struct pcmcia_device *p_dev) -{ - int ret; - - PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); - - ret = prism2_config(p_dev); - if (ret) { - PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); - } - - return ret; -} - - -static void prism2_detach(struct pcmcia_device *link) -{ - PDEBUG(DEBUG_FLOW, "prism2_detach\n"); - - prism2_release((u_long)link); - - /* release net devices */ - if (link->priv) { - struct hostap_cs_priv *hw_priv; - struct net_device *dev; - struct hostap_interface *iface; - dev = link->priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - prism2_free_local_data(dev); - kfree(hw_priv); - } -} - - -static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int prism2_config(struct pcmcia_device *link) -{ - struct net_device *dev; - struct hostap_interface *iface; - local_info_t *local; - int ret; - struct hostap_cs_priv *hw_priv; - unsigned long flags; - - PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) { - ret = -ENOMEM; - goto failed; - } - - /* Look for an appropriate configuration table entry in the CIS */ - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | - CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, prism2_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - /* Need to allocate net_device before requesting IRQ handler */ - dev = prism2_init_local_data(&prism2_pccard_funcs, 0, - &link->dev); - if (!dev) { - ret = -ENOMEM; - goto failed; - } - link->priv = dev; - - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - hw_priv->link = link; - - /* - * We enable IRQ here, but IRQ handler will not proceed - * until dev->base_addr is set below. This protect us from - * receive interrupts when driver is not initialized. - */ - ret = pcmcia_request_irq(link, prism2_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - spin_lock_irqsave(&local->irq_init_lock, flags); - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - spin_unlock_irqrestore(&local->irq_init_lock, flags); - - local->shutdown = 0; - - sandisk_enable_wireless(dev); - - ret = prism2_hw_config(dev, 1); - if (!ret) - ret = hostap_hw_ready(dev); - - return ret; - - failed: - kfree(hw_priv); - prism2_release((u_long)link); - return ret; -} - - -static void prism2_release(u_long arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - PDEBUG(DEBUG_FLOW, "prism2_release\n"); - - if (link->priv) { - struct net_device *dev = link->priv; - struct hostap_interface *iface; - - iface = netdev_priv(dev); - prism2_hw_shutdown(dev, 0); - iface->local->shutdown = 1; - } - - pcmcia_disable_device(link); - PDEBUG(DEBUG_FLOW, "release - done\n"); -} - -static int hostap_cs_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - if (dev_open) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int hostap_cs_resume(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); - - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, dev_open ? 0 : 1); - if (dev_open) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -static const struct pcmcia_device_id hostap_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), -/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", - 0x2d858104), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", - 0x74c5e40d), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", - 0x4b801a17), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02", - 0x4b74baa0), - PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", - 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_PROD_ID123( - "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", - 0xe6ec52ce, 0x08649af2, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Canon", "Wireless LAN CF Card K30225", "Version 01.00", - 0x96ef6fe2, 0x263fcbab, 0xa57adb8c), - PCMCIA_DEVICE_PROD_ID123( - "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", - 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Instant Wireless ", " Network PC CARD", "Version 01.02", - 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "SMC", "SMC2632W", "Version 01.02", - 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", - 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", - 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", - 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", - 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12( - "ZoomAir 11Mbps High", "Rate wireless Networking", - 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", - 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID123( - "Pretec", "CompactWLAN Card 802.11b", "2.5", - 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), - PCMCIA_DEVICE_PROD_ID123( - "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", - 0xc7b8df9d, 0x1700d087, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", - "Ver. 1.00", - 0x5cd01705, 0x4271660f, 0x9d08ee12), - PCMCIA_DEVICE_PROD_ID123( - "Wireless LAN" , "11Mbps PC Card", "Version 01.02", - 0x4b8870ff, 0x70e946d1, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); - - -static struct pcmcia_driver hostap_driver = { - .name = "hostap_cs", - .probe = hostap_cs_probe, - .remove = prism2_detach, - .owner = THIS_MODULE, - .id_table = hostap_cs_ids, - .suspend = hostap_cs_suspend, - .resume = hostap_cs_resume, -}; -module_pcmcia_driver(hostap_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_download.c b/drivers/net/wireless/intersil/hostap/hostap_download.c deleted file mode 100644 index 5e5bada28b5b..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_download.c +++ /dev/null @@ -1,810 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -static int prism2_enable_aux_port(struct net_device *dev, int enable) -{ - u16 val, reg; - int i, tries; - unsigned long flags; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - if (enable) { - PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " - "port is already enabled\n", dev->name); - } - return 0; - } - - spin_lock_irqsave(&local->cmdlock, flags); - - /* wait until busy bit is clear */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - spin_unlock_irqrestore(&local->cmdlock, flags); - printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", - dev->name, reg); - return -ETIMEDOUT; - } - - val = HFA384X_INW(HFA384X_CONTROL_OFF); - - if (enable) { - HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) - printk("prism2_enable_aux_port: was not disabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_ENABLE; - } else { - HFA384X_OUTW(0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) - printk("prism2_enable_aux_port: was not enabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_DISABLE; - } - HFA384X_OUTW(val, HFA384X_CONTROL_OFF); - - udelay(5); - - i = 10000; - while (i > 0) { - val = HFA384X_INW(HFA384X_CONTROL_OFF); - val &= HFA384X_AUX_PORT_MASK; - - if ((enable && val == HFA384X_AUX_PORT_ENABLED) || - (!enable && val == HFA384X_AUX_PORT_DISABLED)) - break; - - udelay(10); - i--; - } - - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (i == 0) { - printk("prism2_enable_aux_port(%d) timed out\n", - enable); - return -ETIMEDOUT; - } - - return 0; -} - - -static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int prism2_pda_ok(u8 *buf) -{ - __le16 *pda = (__le16 *) buf; - int pos; - u16 len, pdr; - - if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && - buf[3] == 0x00) - return 0; - - pos = 0; - while (pos + 1 < PRISM2_PDA_SIZE / 2) { - len = le16_to_cpu(pda[pos]); - pdr = le16_to_cpu(pda[pos + 1]); - if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) - return 0; - - if (pdr == 0x0000 && len == 2) { - /* PDA end found */ - return 1; - } - - pos += len + 1; - } - - return 0; -} - - -#define prism2_download_aux_dump_npages 65536 - -struct prism2_download_aux_dump { - local_info_t *local; - u16 page[0x80]; -}; - -static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - - hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); - seq_write(m, ctx->page, 0x80); - return 0; -} - -static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 1); - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - ++*_pos; - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 0); -} - -static const struct seq_operations prism2_download_aux_dump_proc_seqops = { - .start = prism2_download_aux_dump_proc_start, - .next = prism2_download_aux_dump_proc_next, - .stop = prism2_download_aux_dump_proc_stop, - .show = prism2_download_aux_dump_proc_show, -}; - -static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, - sizeof(struct prism2_download_aux_dump)); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = pde_data(inode); - } - return ret; -} - -static const struct proc_ops prism2_download_aux_dump_proc_ops = { - .proc_open = prism2_download_aux_dump_proc_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = seq_release_private, -}; - - -static u8 * prism2_read_pda(struct net_device *dev) -{ - u8 *buf; - int res, i, found = 0; -#define NUM_PDA_ADDRS 4 - unsigned int pda_addr[NUM_PDA_ADDRS] = { - 0x7f0000 /* others than HFA3841 */, - 0x3f0000 /* HFA3841 */, - 0x390000 /* apparently used in older cards */, - 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, - }; - - buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); - if (buf == NULL) - return NULL; - - /* Note: wlan card should be in initial state (just after init cmd) - * and no other operations should be performed concurrently. */ - - prism2_enable_aux_port(dev, 1); - - for (i = 0; i < NUM_PDA_ADDRS; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", - dev->name, pda_addr[i]); - res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); - if (res) - continue; - if (res == 0 && prism2_pda_ok(buf)) { - PDEBUG2(DEBUG_EXTRA2, ": OK\n"); - found = 1; - break; - } else { - PDEBUG2(DEBUG_EXTRA2, ": failed\n"); - } - } - - prism2_enable_aux_port(dev, 0); - - if (!found) { - printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); - kfree(buf); - buf = NULL; - } - - return buf; -} - - -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - u16 param0, param1; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - local->hw_downloading = 1; - if (local->pri_only) { - hfa384x_disable_interrupts(dev); - } else { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - param0 = param->start_addr & 0xffff; - param1 = param->start_addr >> 16; - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -1; - goto out; - } - } - - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - /* ProgMode disable causes the hardware to restart itself from the - * given starting address. Give hw some time and ACK command just in - * case restart did not happen. */ - mdelay(5); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after RAM " - "download failed\n", dev->name); - ret = -1; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -static int prism2_enable_genesis(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; - u8 readbuf[4]; - - printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", - dev->name, hcr); - local->func->cor_sreset(local); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - local->func->genesis_reset(local, hcr); - - /* Readback test */ - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - - if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { - printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", - hcr); - return 0; - } else { - printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n", - hcr, initseq, readbuf); - return 1; - } -} - - -static int prism2_get_ram_size(local_info_t *local) -{ - int ret; - - /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) - ret = 8; - else if (prism2_enable_genesis(local, 0x0f) == 0) - ret = 16; - else - ret = -1; - - /* Disable genesis mode */ - local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); - - return ret; -} - - -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ram16 = 0, i; - int ret = 0; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -EBUSY; - } - - if (!local->func->genesis_reset || !local->func->cor_sreset) { - printk(KERN_INFO "%s: Genesis mode downloading not supported " - "with this hwmodel\n", dev->name); - return -EOPNOTSUPP; - } - - local->hw_downloading = 1; - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_DEBUG "%s: failed to enable AUX port\n", - dev->name); - ret = -EIO; - goto out; - } - - if (local->sram_type == -1) { - /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) { - ram16 = 0; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " - "SRAM\n", dev->name); - } else if (prism2_enable_genesis(local, 0x0f) == 0) { - ram16 = 1; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " - "SRAM\n", dev->name); - } else { - printk(KERN_DEBUG "%s: Could not initiate genesis " - "mode\n", dev->name); - ret = -EIO; - goto out; - } - } else { - if (prism2_enable_genesis(local, local->sram_type == 8 ? - 0x1f : 0x0f)) { - printk(KERN_DEBUG "%s: Failed to set Genesis " - "mode (sram_type=%d)\n", dev->name, - local->sram_type); - ret = -EIO; - goto out; - } - ram16 = local->sram_type != 8; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -EIO; - goto out; - } - } - - PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); - local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Failed to disable AUX port\n", - dev->name); - } - - mdelay(5); - local->hw_downloading = 0; - - PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); - /* - * Make sure the INIT command does not generate a command completion - * event by disabling interrupts. - */ - hfa384x_disable_interrupts(dev); - if (prism2_hw_init(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); - if (prism2_hw_init2(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD -/* Note! Non-volatile downloading functionality has not yet been tested - * thoroughly and it may corrupt flash image and effectively kill the card that - * is being updated. You have been warned. */ - -static inline int prism2_download_block(struct net_device *dev, - u32 addr, u8 *data, - u32 bufaddr, int rest_len) -{ - u16 param0, param1; - int block_len; - - block_len = rest_len < 4096 ? rest_len : 4096; - - param0 = addr & 0xffff; - param1 = addr >> 16; - - HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Flash download command execution " - "failed\n", dev->name); - return -1; - } - - if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { - printk(KERN_WARNING "%s: flash download at 0x%08x " - "(len=%d) failed\n", dev->name, addr, block_len); - return -1; - } - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), - 0)) { - printk(KERN_WARNING "%s: Flash write command execution " - "failed\n", dev->name); - return -1; - } - - return block_len; -} - - -static int prism2_download_nonvolatile(local_info_t *local, - struct prism2_download_data *dl) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - struct { - __le16 page; - __le16 offset; - __le16 len; - } dlbuffer; - u32 bufaddr; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, - &dlbuffer, 6, 0); - - if (ret < 0) { - printk(KERN_WARNING "%s: Could not read download buffer " - "parameters\n", dev->name); - goto out; - } - - printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", - le16_to_cpu(dlbuffer.len), - le16_to_cpu(dlbuffer.page), - le16_to_cpu(dlbuffer.offset)); - - bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); - - local->hw_downloading = 1; - - if (!local->pri_only) { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - hfa384x_disable_interrupts(dev); - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - printk(KERN_DEBUG "%s: starting flash download\n", dev->name); - for (i = 0; i < dl->num_areas; i++) { - int rest_len = dl->data[i].len; - int data_off = 0; - - while (rest_len > 0) { - int block_len; - - block_len = prism2_download_block( - dev, dl->data[i].addr + data_off, - dl->data[i].data + data_off, bufaddr, - rest_len); - - if (block_len < 0) { - ret = -1; - goto out; - } - - rest_len -= block_len; - data_off += block_len; - } - } - - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), 0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - - local->func->hw_reset(dev); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after flash " - "download failed\n", dev->name); - ret = -1; - } else { - printk(KERN_INFO "%s: Card initialized successfully after " - "flash download\n", dev->name); - } - - out: - local->hw_downloading = 0; - return ret; -} -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - - -static void prism2_download_free_data(struct prism2_download_data *dl) -{ - int i; - - if (dl == NULL) - return; - - for (i = 0; i < dl->num_areas; i++) - kfree(dl->data[i].data); - kfree(dl); -} - - -static int prism2_download(local_info_t *local, - struct prism2_download_param *param) -{ - int ret = 0; - int i; - u32 total_len = 0; - struct prism2_download_data *dl = NULL; - - printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " - "num_areas=%d\n", - param->dl_cmd, param->start_addr, param->num_areas); - - if (param->num_areas > 100) { - ret = -EINVAL; - goto out; - } - - dl = kzalloc(struct_size(dl, data, param->num_areas), GFP_KERNEL); - if (dl == NULL) { - ret = -ENOMEM; - goto out; - } - dl->dl_cmd = param->dl_cmd; - dl->start_addr = param->start_addr; - dl->num_areas = param->num_areas; - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, - " area %d: addr=0x%08x len=%d ptr=0x%p\n", - i, param->data[i].addr, param->data[i].len, - param->data[i].ptr); - - dl->data[i].addr = param->data[i].addr; - dl->data[i].len = param->data[i].len; - - total_len += param->data[i].len; - if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || - total_len > PRISM2_MAX_DOWNLOAD_LEN) { - ret = -E2BIG; - goto out; - } - - dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); - if (dl->data[i].data == NULL) { - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(dl->data[i].data, param->data[i].ptr, - param->data[i].len)) { - ret = -EFAULT; - goto out; - } - } - - switch (param->dl_cmd) { - case PRISM2_DOWNLOAD_VOLATILE: - case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: - ret = prism2_download_volatile(local, dl); - break; - case PRISM2_DOWNLOAD_VOLATILE_GENESIS: - case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: - ret = prism2_download_genesis(local, dl); - break; - case PRISM2_DOWNLOAD_NON_VOLATILE: -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD - ret = prism2_download_nonvolatile(local, dl); -#else /* PRISM2_NON_VOLATILE_DOWNLOAD */ - printk(KERN_INFO "%s: non-volatile downloading not enabled\n", - local->dev->name); - ret = -EOPNOTSUPP; -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - break; - default: - printk(KERN_DEBUG "%s: unsupported download command %d\n", - local->dev->name, param->dl_cmd); - ret = -EINVAL; - break; - } - - out: - if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { - prism2_download_free_data(local->dl_pri); - local->dl_pri = dl; - } else if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { - prism2_download_free_data(local->dl_sec); - local->dl_sec = dl; - } else - prism2_download_free_data(dl); - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c deleted file mode 100644 index b74f4cb5d6d3..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ /dev/null @@ -1,3387 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - * - * FIX: - * - there is currently no way of associating TX packets to correct wds device - * when TX Exc/OK event occurs, so all tx_packets and some - * tx_errors/tx_dropped are added to the main netdevice; using sw_support - * field in txdesc might be used to fix this (using Alloc event to increment - * tx_packets would need some further info in txfid table) - * - * Buffer Access Path (BAP) usage: - * Prism2 cards have two separate BAPs for accessing the card memory. These - * should allow concurrent access to two different frames and the driver - * previously used BAP0 for sending data and BAP1 for receiving data. - * However, there seems to be number of issues with concurrent access and at - * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI - * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between - * host and card memories. BAP0 accesses are protected with local->baplock - * (spin_lock_bh) to prevent concurrent use. - */ - - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - - -/* #define final_version */ - -static int mtu = 1500; -module_param(mtu, int, 0444); -MODULE_PARM_DESC(mtu, "Maximum transfer unit"); - -static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; -module_param_array(channel, int, NULL, 0444); -MODULE_PARM_DESC(channel, "Initial channel"); - -static char essid[33] = "test"; -module_param_string(essid, essid, sizeof(essid), 0444); -MODULE_PARM_DESC(essid, "Host AP's ESSID"); - -static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; -module_param_array(iw_mode, int, NULL, 0444); -MODULE_PARM_DESC(iw_mode, "Initial operation mode"); - -static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; -module_param_array(beacon_int, int, NULL, 0444); -MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); - -static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(dtim_period, int, NULL, 0444); -MODULE_PARM_DESC(dtim_period, "DTIM period"); - -static char dev_template[16] = "wlan%d"; -module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); -MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " - "wlan%d)"); - -#ifdef final_version -#define EXTRA_EVENTS_WTERR 0 -#else -/* check WTERR events (Wait Time-out) in development versions */ -#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR -#endif - -/* Events that will be using BAP0 */ -#define HFA384X_BAP0_EVENTS \ - (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) - -/* event mask, i.e., events that will result in an interrupt */ -#define HFA384X_EVENT_MASK \ - (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ - HFA384X_EV_CMD | HFA384X_EV_TICK | \ - EXTRA_EVENTS_WTERR) - -/* Default TX control flags: use 802.11 headers and request interrupt for - * failed transmits. Frames that request ACK callback, will add - * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. - */ -#define HFA384X_TX_CTRL_FLAGS \ - (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) - - -/* ca. 1 usec */ -#define HFA384X_CMD_BUSY_TIMEOUT 5000 -#define HFA384X_BAP_BUSY_TIMEOUT 50000 - -/* ca. 10 usec */ -#define HFA384X_CMD_COMPL_TIMEOUT 20000 -#define HFA384X_DL_COMPL_TIMEOUT 1000000 - -/* Wait times for initialization; yield to other processes to avoid busy - * waiting for long time. */ -#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ -#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ - - -static void prism2_hw_reset(struct net_device *dev); -static void prism2_check_sta_fw_version(local_info_t *local); - -#ifdef PRISM2_DOWNLOAD_SUPPORT -/* hostap_download.c */ -static const struct proc_ops prism2_download_aux_dump_proc_ops; -static u8 * prism2_read_pda(struct net_device *dev); -static int prism2_download(local_info_t *local, - struct prism2_download_param *param); -static void prism2_download_free_data(struct prism2_download_data *dl); -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param); -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param); -static int prism2_get_ram_size(local_info_t *local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - - - -#ifndef final_version -/* magic value written to SWSUPPORT0 reg. for detecting whether card is still - * present */ -#define HFA384X_MAGIC 0x8A32 -#endif - -static void hfa384x_read_regs(struct net_device *dev, - struct hfa384x_regs *regs) -{ - regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); - regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); - regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); - regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); -} - - -/** - * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Internal helper function for freeing Prism2 command queue entries. - * Caller must have acquired local->cmdlock before calling this function. - */ -static inline void __hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - if (del_req) { - entry->del_req = 1; - if (!list_empty(&entry->list)) { - list_del_init(&entry->list); - local->cmd_queue_len--; - } - } - - if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) - kfree(entry); -} - - -/** - * hostap_cmd_queue_free - Free Prism2 command queue entry - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Free a Prism2 command queue entry. - */ -static inline void hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - unsigned long flags; - - spin_lock_irqsave(&local->cmdlock, flags); - __hostap_cmd_queue_free(local, entry, del_req); - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries - * @local: pointer to private Host AP driver data - */ -static void prism2_clear_cmd_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - unsigned long flags; - struct hostap_cmd_queue *entry; - - spin_lock_irqsave(&local->cmdlock, flags); - list_for_each_safe(ptr, n, &local->cmd_queue) { - entry = list_entry(ptr, struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - printk(KERN_DEBUG "%s: removed pending cmd_queue entry " - "(type=%d, cmd=0x%04x, param0=0x%04x)\n", - local->dev->name, entry->type, entry->cmd, - entry->param0); - __hostap_cmd_queue_free(local, entry, 1); - } - if (local->cmd_queue_len) { - /* This should not happen; print debug message and clear - * queue length. */ - printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " - "flush\n", local->dev->name, local->cmd_queue_len); - local->cmd_queue_len = 0; - } - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * hfa384x_cmd_issue - Issue a Prism2 command to the hardware - * @dev: pointer to net_device - * @entry: Prism2 command queue entry to be issued - */ -static int hfa384x_cmd_issue(struct net_device *dev, - struct hostap_cmd_queue *entry) -{ - struct hostap_interface *iface; - local_info_t *local; - int tries; - u16 reg; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->card_present && !local->func->card_present(local)) - return -ENODEV; - - if (entry->issued) { - printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", - dev->name, entry); - } - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } -#ifndef final_version - if (tries != HFA384X_CMD_BUSY_TIMEOUT) { - prism2_io_debug_error(dev, 1); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " - "for %d usec\n", dev->name, - HFA384X_CMD_BUSY_TIMEOUT - tries); - } -#endif - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, 2); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - /* write command */ - spin_lock_irqsave(&local->cmdlock, flags); - HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); - entry->issued = 1; - spin_unlock_irqrestore(&local->cmdlock, flags); - - return 0; -} - - -/** - * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @param1: value for Param1 register (pointer; %NULL if not used) - * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed - * - * Issue given command (possibly after waiting in command queue) and sleep - * until the command is completed (or timed out or interrupted). This can be - * called only from user process context. - */ -static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, - u16 *param1, u16 *resp0) -{ - struct hostap_interface *iface; - local_info_t *local; - int err, res, issue, issued = 0; - unsigned long flags; - struct hostap_cmd_queue *entry; - DECLARE_WAITQUEUE(wait, current); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - if (signal_pending(current)) - return -EINTR; - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_SLEEP; - entry->cmd = cmd; - entry->param0 = param0; - if (param1) - entry->param1 = *param1; - init_waitqueue_head(&entry->compl); - - /* prepare to wait for command completion event, but do not sleep yet - */ - add_wait_queue(&entry->compl, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - err = 0; - if (!issue) - goto wait_completion; - - if (signal_pending(current)) - err = -EINTR; - - if (!err) { - if (hfa384x_cmd_issue(dev, entry)) - err = -ETIMEDOUT; - else - issued = 1; - } - - wait_completion: - if (!err && entry->type != CMD_COMPLETED) { - /* sleep until command is completed or timed out */ - res = schedule_timeout(2 * HZ); - } else - res = -1; - - if (!err && signal_pending(current)) - err = -EINTR; - - if (err && issued) { - /* the command was issued, so a CmdCompl event should occur - * soon; however, there's a pending signal and - * schedule_timeout() would be interrupted; wait a short period - * of time to avoid removing entry from the list before - * CmdCompl event */ - udelay(300); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&entry->compl, &wait); - - /* If entry->list is still in the list, it must be removed - * first and in this case prism2_cmd_ev() does not yet have - * local reference to it, and the data can be kfree()'d - * here. If the command completion event is still generated, - * it will be assigned to next (possibly) pending command, but - * the driver will reset the card anyway due to timeout - * - * If the entry is not in the list prism2_cmd_ev() has a local - * reference to it, but keeps cmdlock as long as the data is - * needed, so the data can be kfree()'d here. */ - - /* FIX: if the entry->list is in the list, it has not been completed - * yet, so removing it here is somewhat wrong.. this could cause - * references to freed memory and next list_del() causing NULL pointer - * dereference.. it would probably be better to leave the entry in the - * list and the list should be emptied during hw reset */ - - spin_lock_irqsave(&local->cmdlock, flags); - if (!list_empty(&entry->list)) { - printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " - "(entry=%p, type=%d, res=%d)\n", dev->name, entry, - entry->type, res); - list_del_init(&entry->list); - local->cmd_queue_len--; - } - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (err) { - printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", - dev->name, err); - res = err; - goto done; - } - - if (entry->type != CMD_COMPLETED) { - u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " - "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " - "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, - res, entry, entry->type, entry->cmd, entry->param0, reg, - HFA384X_INW(HFA384X_INTEN_OFF)); - if (reg & HFA384X_EV_CMD) { - /* Command completion event is pending, but the - * interrupt was not delivered - probably an issue - * with pcmcia-cs configuration. */ - printk(KERN_WARNING "%s: interrupt delivery does not " - "seem to work\n", dev->name); - } - prism2_io_debug_error(dev, 3); - res = -ETIMEDOUT; - goto done; - } - - if (resp0 != NULL) - *resp0 = entry->resp0; -#ifndef final_version - if (entry->res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " - "resp0=0x%04x\n", - dev->name, cmd, entry->res, entry->resp0); - } -#endif /* final_version */ - - res = entry->res; - done: - hostap_cmd_queue_free(local, entry, 1); - return res; -} - - -/** - * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @callback: command completion callback function (%NULL = no callback) - * @context: context data to be given to the callback function - * - * Issue given command (possibly after waiting in command queue) and use - * callback function to indicate command completion. This can be called both - * from user and interrupt context. The callback function will be called in - * hardware IRQ context. It can be %NULL, when no function is called when - * command is completed. - */ -static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, - void (*callback)(struct net_device *dev, - long context, u16 resp0, - u16 status), - long context) -{ - struct hostap_interface *iface; - local_info_t *local; - int issue, ret; - unsigned long flags; - struct hostap_cmd_queue *entry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_CALLBACK; - entry->cmd = cmd; - entry->param0 = param0; - entry->callback = callback; - entry->context = context; - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (issue && hfa384x_cmd_issue(dev, entry)) - ret = -ETIMEDOUT; - else - ret = 0; - - hostap_cmd_queue_free(local, entry, ret); - - return ret; -} - - -/** - * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @io_debug_num: I/O debug error number - * - * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). - */ -static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, - int io_debug_num) -{ - int tries; - u16 reg; - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, io_debug_num); - printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " - "reg=0x%04x\n", dev->name, io_debug_num, reg); - return -ETIMEDOUT; - } - - /* write command */ - HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(cmd, HFA384X_CMD_OFF); - - return 0; -} - - -/** - * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) -{ - int res, tries; - u16 reg; - - res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); - if (res) - return res; - - /* wait for command completion */ - if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) - tries = HFA384X_DL_COMPL_TIMEOUT; - else - tries = HFA384X_CMD_COMPL_TIMEOUT; - - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - tries > 0) { - tries--; - udelay(10); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - prism2_io_debug_error(dev, 5); - printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | - BIT(8))) >> 8; -#ifndef final_version - if (res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", - dev->name, cmd, res); - } -#endif - - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - return res; -} - - -/** - * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, - u16 param0) -{ - return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); -} - - -/** - * prism2_cmd_ev - Prism2 command completion event handler - * @dev: pointer to net_device - * - * Interrupt handler for command completion events. Called by the main - * interrupt handler in hardware IRQ context. Read Resp0 and status registers - * from the hardware and ACK the event. Depending on the issued command type - * either wake up the sleeping process that is waiting for command completion - * or call the callback function. Issue the next command, if one is pending. - */ -static void prism2_cmd_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_cmd_queue *entry = NULL; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - list_del_init(&entry->list); - local->cmd_queue_len--; - - if (!entry->issued) { - printk(KERN_DEBUG "%s: Command completion event, but " - "cmd not issued\n", dev->name); - __hostap_cmd_queue_free(local, entry, 1); - entry = NULL; - } - } - spin_unlock(&local->cmdlock); - - if (!entry) { - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: Command completion event, but no " - "pending commands\n", dev->name); - return; - } - - entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); - entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | - BIT(9) | BIT(8))) >> 8; - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - /* TODO: rest of the CmdEv handling could be moved to tasklet */ - if (entry->type == CMD_SLEEP) { - entry->type = CMD_COMPLETED; - wake_up_interruptible(&entry->compl); - } else if (entry->type == CMD_CALLBACK) { - if (entry->callback) - entry->callback(dev, entry->context, entry->resp0, - entry->res); - } else { - printk(KERN_DEBUG "%s: Invalid command completion type %d\n", - dev->name, entry->type); - } - hostap_cmd_queue_free(local, entry, 1); - - /* issue next command, if pending */ - entry = NULL; - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - if (entry->issuing) { - /* hfa384x_cmd() has already started issuing this - * command, so do not start here */ - entry = NULL; - } - if (entry) - refcount_inc(&entry->usecnt); - } - spin_unlock(&local->cmdlock); - - if (entry) { - /* issue next command; if command issuing fails, remove the - * entry from cmd_queue */ - int res = hfa384x_cmd_issue(dev, entry); - spin_lock(&local->cmdlock); - __hostap_cmd_queue_free(local, entry, res); - spin_unlock(&local->cmdlock); - } -} - - -static int hfa384x_wait_offset(struct net_device *dev, u16 o_off) -{ - int tries = HFA384X_BAP_BUSY_TIMEOUT; - int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - - while (res && tries > 0) { - tries--; - udelay(1); - res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - } - return res; -} - - -/* Offset must be even */ -static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, - int offset) -{ - u16 o_off, s_off; - int ret = 0; - - if (offset % 2 || bap > 1) - return -EINVAL; - - if (bap == BAP1) { - o_off = HFA384X_OFFSET1_OFF; - s_off = HFA384X_SELECT1_OFF; - } else { - o_off = HFA384X_OFFSET0_OFF; - s_off = HFA384X_SELECT0_OFF; - } - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 7); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } - - HFA384X_OUTW(id, s_off); - HFA384X_OUTW(offset, o_off); - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 8); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } -#ifndef final_version - if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { - prism2_io_debug_error(dev, 9); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " - "(%d,0x04%x,%d); reg=0x%04x\n", - dev->name, bap, id, offset, HFA384X_INW(o_off)); - ret = -EINVAL; - } -#endif - - out: - return ret; -} - - -static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len) -{ - struct hostap_interface *iface; - local_info_t *local; - int res, rlen = 0; - struct hfa384x_rid_hdr rec; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); - if (res) { - printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " - "(res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - spin_lock_bh(&local->baplock); - - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (res) - goto unlock; - - res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); - if (res) - goto unlock; - - if (le16_to_cpu(rec.len) == 0) { - /* RID not available */ - res = -ENODATA; - goto unlock; - } - - rlen = (le16_to_cpu(rec.len) - 1) * 2; - if (exact_len && rlen != len) { - printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " - "rid=0x%04x, len=%d (expected %d)\n", - dev->name, rid, rlen, len); - res = -ENODATA; - } - - res = hfa384x_from_bap(dev, BAP0, buf, len); - -unlock: - spin_unlock_bh(&local->baplock); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - if (res != -ENODATA) - printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " - "len=%d) - failed - res=%d\n", dev->name, rid, - len, res); - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - return res; - } - - return rlen; -} - - -static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_rid_hdr rec; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - rec.rid = cpu_to_le16(rid); - /* RID len in words and +1 for rec.rid */ - rec.len = cpu_to_le16(len / 2 + len % 2 + 1); - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - spin_lock_bh(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (!res) - res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, buf, len); - spin_unlock_bh(&local->baplock); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " - "failed - res=%d\n", dev->name, rid, len, res); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " - "failed (res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - } - - return res; -} - - -static void hfa384x_disable_interrupts(struct net_device *dev) -{ - /* disable interrupts and clear event status */ - HFA384X_OUTW(0, HFA384X_INTEN_OFF); - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); -} - - -static void hfa384x_enable_interrupts(struct net_device *dev) -{ - /* ack pending events and enable interrupts from selected events */ - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_no_bap0(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, - HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_all(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_only_cmd(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); -} - - -static u16 hfa384x_allocate_fid(struct net_device *dev, int len) -{ - u16 fid; - unsigned long delay; - - /* FIX: this could be replace with hfa384x_cmd() if the Alloc event - * below would be handled like CmdCompl event (sleep here, wake up from - * interrupt handler */ - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { - printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", - dev->name, len); - return 0xffff; - } - - delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { - printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); - return 0xffff; - } - - fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - - return fid; -} - - -static int prism2_reset_port(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (!local->dev_enabled) - return 0; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to disable port\n", - dev->name); - else { - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to enable " - "port\n", dev->name); - } - - /* It looks like at least some STA firmware versions reset - * fragmentation threshold back to 2346 after enable command. Restore - * the configured value, if it differs from this default. */ - if (local->fragm_threshold != 2346 && - hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_DEBUG "%s: failed to restore fragmentation " - "threshold (%d) after Port0 enable\n", - dev->name, local->fragm_threshold); - } - - /* Some firmwares lose antenna selection settings on reset */ - (void) hostap_set_antsel(local); - - return res; -} - - -static int prism2_get_version_info(struct net_device *dev, u16 rid, - const char *txt) -{ - struct hfa384x_comp_ident comp; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - /* PRI f/w not yet available - cannot read RIDs */ - return -1; - } - if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { - printk(KERN_DEBUG "Could not get RID for component %s\n", txt); - return -1; - } - - printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, - __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), - __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); - return 0; -} - - -static int prism2_setup_rids(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - __le16 tmp; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); - - if (!local->fw_ap) { - u16 tmp1 = hostap_get_porttype(local); - ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1); - if (ret) { - printk("%s: Port type setting to %d failed\n", - dev->name, tmp1); - goto fail; - } - } - - /* Setting SSID to empty string seems to kill the card in Host AP mode - */ - if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { - ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, - local->essid); - if (ret) { - printk("%s: AP own SSID setting failed\n", dev->name); - goto fail; - } - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, - PRISM2_DATA_MAXLEN); - if (ret) { - printk("%s: MAC data length setting to %d failed\n", - dev->name, PRISM2_DATA_MAXLEN); - goto fail; - } - - if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { - printk("%s: Channel list read failed\n", dev->name); - ret = -EINVAL; - goto fail; - } - local->channel_mask = le16_to_cpu(tmp); - - if (local->channel < 1 || local->channel > 14 || - !(local->channel_mask & (1 << (local->channel - 1)))) { - printk(KERN_WARNING "%s: Channel setting out of range " - "(%d)!\n", dev->name, local->channel); - ret = -EBUSY; - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); - if (ret) { - printk("%s: Channel setting to %d failed\n", - dev->name, local->channel); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, - local->beacon_int); - if (ret) { - printk("%s: Beacon interval setting to %d failed\n", - dev->name, local->beacon_int); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, - local->dtim_period); - if (ret) { - printk("%s: DTIM period setting to %d failed\n", - dev->name, local->dtim_period); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc); - if (ret) - printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", - dev->name, local->is_promisc); - - if (!local->fw_ap) { - ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, - local->essid); - if (ret) { - printk("%s: Desired SSID setting failed\n", dev->name); - goto fail; - } - } - - /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and - * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic - * rates */ - if (local->tx_rate_control == 0) { - local->tx_rate_control = - HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | - HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - } - if (local->basic_rates == 0) - local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; - - if (!local->fw_ap) { - ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control); - if (ret) { - printk("%s: TXRateControl setting to %d failed\n", - dev->name, local->tx_rate_control); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control); - if (ret) { - printk("%s: cnfSupportedRates setting to %d failed\n", - dev->name, local->tx_rate_control); - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates); - if (ret) { - printk("%s: cnfBasicRates setting to %d failed\n", - dev->name, local->basic_rates); - } - - ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); - if (ret) { - printk("%s: Create IBSS setting to 1 failed\n", - dev->name); - } - } - - if (local->name_set) - (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, - local->name); - - if (hostap_set_encryption(local)) { - printk(KERN_INFO "%s: could not configure encryption\n", - dev->name); - } - - (void) hostap_set_antsel(local); - - if (hostap_set_roaming(local)) { - printk(KERN_INFO "%s: could not set host roaming\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && - hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) - printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", - dev->name, local->enh_sec); - - /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently - * not working correctly (last seven counters report bogus values). - * This has been fixed in 0.8.2, so enable 32-bit tallies only - * beginning with that firmware version. Another bug fix for 32-bit - * tallies in 1.4.0; should 16-bit tallies be used for some other - * versions, too? */ - if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { - if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { - printk(KERN_INFO "%s: cnfThirty2Tally setting " - "failed\n", dev->name); - local->tallies32 = 0; - } else - local->tallies32 = 1; - } else - local->tallies32 = 0; - - hostap_set_auth_algs(local); - - if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_INFO "%s: setting FragmentationThreshold to %d " - "failed\n", dev->name, local->fragm_threshold); - } - - if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, - local->rts_threshold)) { - printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", - dev->name, local->rts_threshold); - } - - if (local->manual_retry_count >= 0 && - hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - local->manual_retry_count)) { - printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", - dev->name, local->manual_retry_count); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && - hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { - local->rssi_to_dBm = le16_to_cpu(tmp); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && - hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { - printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && - hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, - local->generic_elem, local->generic_elem_len)) { - printk(KERN_INFO "%s: setting genericElement failed\n", - dev->name); - } - - fail: - return ret; -} - - -static int prism2_hw_init(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, first = 1; - unsigned long start, delay; - - PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); - - iface = netdev_priv(dev); - local = iface->local; - - clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); - - init: - /* initialize HFA 384x */ - ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); - if (ret) { - printk(KERN_INFO "%s: first command failed - assuming card " - "does not have primary firmware\n", dev_info); - } - - if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - /* EvStat has Cmd bit set in some cases, so retry once if no - * wait was needed */ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: init command completed too quickly - " - "retrying\n", dev->name); - first = 0; - goto init; - } - - start = jiffies; - delay = jiffies + HFA384X_INIT_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - printk(KERN_DEBUG "%s: assuming no Primary image in " - "flash - card initialization not completed\n", - dev_info); - local->no_pri = 1; -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->sram_type == -1) - local->sram_type = prism2_get_ram_size(local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - return 1; - } - local->no_pri = 0; - printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", - (jiffies - start) * 1000 / HZ); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - return 0; -} - - -static int prism2_hw_init2(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int i; - - iface = netdev_priv(dev); - local = iface->local; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - kfree(local->pda); - if (local->no_pri) - local->pda = NULL; - else - local->pda = prism2_read_pda(dev); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - hfa384x_disable_interrupts(dev); - -#ifndef final_version - HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - printk("SWSUPPORT0 write/read failed: %04X != %04X\n", - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); - goto failed; - } -#endif - - if (initial || local->pri_only) { - hfa384x_events_only_cmd(dev); - /* get card version information */ - if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || - prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { - hfa384x_disable_interrupts(dev); - goto failed; - } - - if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { - printk(KERN_DEBUG "%s: Failed to read STA f/w version " - "- only Primary f/w present\n", dev->name); - local->pri_only = 1; - return 0; - } - local->pri_only = 0; - hfa384x_disable_interrupts(dev); - } - - /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and - * enable interrupts before this. This would also require some sort of - * sleeping AllocEv waiting */ - - /* allocate TX FIDs */ - local->txfid_len = PRISM2_TXFID_LEN; - for (i = 0; i < PRISM2_TXFID_COUNT; i++) { - local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); - if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { - local->txfid[i] = hfa384x_allocate_fid(dev, 1600); - if (local->txfid[i] != 0xffff) { - printk(KERN_DEBUG "%s: Using shorter TX FID " - "(1600 bytes)\n", dev->name); - local->txfid_len = 1600; - } - } - if (local->txfid[i] == 0xffff) - goto failed; - local->intransmitfid[i] = PRISM2_TXFID_EMPTY; - } - - hfa384x_events_only_cmd(dev); - - if (initial) { - u8 addr[ETH_ALEN] = {}; - struct list_head *ptr; - - prism2_check_sta_fw_version(local); - - if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, - addr, ETH_ALEN, 1) < 0) { - printk("%s: could not get own MAC address\n", - dev->name); - } - eth_hw_addr_set(dev, addr); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_inherit(iface->dev, dev); - } - } else if (local->fw_ap) - prism2_check_sta_fw_version(local); - - prism2_setup_rids(dev); - - /* MAC is now configured, but port 0 is not yet enabled */ - return 0; - - failed: - if (!local->no_pri) - printk(KERN_WARNING "%s: Initialization failed\n", dev_info); - return 1; -} - - -static int prism2_hw_enable(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int was_resetting; - - iface = netdev_priv(dev); - local = iface->local; - was_resetting = local->hw_resetting; - - if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { - printk("%s: MAC port 0 enabling failed\n", dev->name); - return 1; - } - - local->hw_ready = 1; - local->hw_reset_tries = 0; - local->hw_resetting = 0; - hfa384x_enable_interrupts(dev); - - /* at least D-Link DWL-650 seems to require additional port reset - * before it starts acting as an AP, so reset port automatically - * here just in case */ - if (initial && prism2_reset_port(dev)) { - printk("%s: MAC port 0 resetting failed\n", dev->name); - return 1; - } - - if (was_resetting && netif_queue_stopped(dev)) { - /* If hw_reset() was called during pending transmit, netif - * queue was stopped. Wake it up now since the wlan card has - * been resetted. */ - netif_wake_queue(dev); - } - - return 0; -} - - -static int prism2_hw_config(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return 1; - - if (prism2_hw_init(dev, initial)) { - return local->no_pri ? 0 : 1; - } - - if (prism2_hw_init2(dev, initial)) - return 1; - - /* Enable firmware if secondary image is loaded and at least one of the - * netdevices is up. */ - if (!local->pri_only && - (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - return prism2_hw_enable(dev, initial); - } - - return 0; -} - - -static void prism2_hw_shutdown(struct net_device *dev, int no_disable) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Allow only command completion events during disable */ - hfa384x_events_only_cmd(dev); - - local->hw_ready = 0; - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - local->dev_enabled = 0; - - if (local->func->card_present && !local->func->card_present(local)) { - printk(KERN_DEBUG "%s: card already removed or not configured " - "during shutdown\n", dev->name); - return; - } - - if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && - hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) - printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); - - hfa384x_disable_interrupts(dev); - - if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) - hfa384x_events_only_cmd(dev); - else - prism2_clear_cmd_queue(local); -} - - -static void prism2_hw_reset(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - -#if 0 - static long last_reset = 0; - - /* do not reset card more than once per second to avoid ending up in a - * busy loop resetting the card */ - if (time_before_eq(jiffies, last_reset + HZ)) - return; - last_reset = jiffies; -#endif - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return; - - if (local->hw_resetting) { - printk(KERN_WARNING "%s: %s: already resetting card - " - "ignoring reset request\n", dev_info, dev->name); - return; - } - - local->hw_reset_tries++; - if (local->hw_reset_tries > 10) { - printk(KERN_WARNING "%s: too many reset tries, skipping\n", - dev->name); - return; - } - - printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); - hfa384x_disable_interrupts(dev); - local->hw_resetting = 1; - if (local->func->cor_sreset) { - /* Host system seems to hang in some cases with high traffic - * load or shared interrupts during COR sreset. Disable shared - * interrupts during reset to avoid these crashes. COS sreset - * takes quite a long time, so it is unfortunate that this - * seems to be needed. Anyway, I do not know of any better way - * of avoiding the crash. */ - disable_irq(dev->irq); - local->func->cor_sreset(local); - enable_irq(dev->irq); - } - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, 0); - local->hw_resetting = 0; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->dl_pri) { - printk(KERN_DEBUG "%s: persistent download of primary " - "firmware\n", dev->name); - if (prism2_download_genesis(local, local->dl_pri) < 0) - printk(KERN_WARNING "%s: download (PRI) failed\n", - dev->name); - } - - if (local->dl_sec) { - printk(KERN_DEBUG "%s: persistent download of secondary " - "firmware\n", dev->name); - if (prism2_download_volatile(local, local->dl_sec) < 0) - printk(KERN_WARNING "%s: download (SEC) failed\n", - dev->name); - } -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - /* TODO: restore beacon TIM bits for STAs that have buffered frames */ -} - - -static void prism2_schedule_reset(local_info_t *local) -{ - schedule_work(&local->reset_queue); -} - - -/* Called only as scheduled task after noticing card timeout in interrupt - * context */ -static void handle_reset_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, reset_queue); - - printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); - prism2_hw_reset(local->dev); - - if (netif_queue_stopped(local->dev)) { - int i; - - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { - PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " - "wake up queue\n"); - netif_wake_queue(local->dev); - break; - } - } -} - - -static int prism2_get_txfid_idx(local_info_t *local) -{ - int idx, end; - unsigned long flags; - - spin_lock_irqsave(&local->txfidlock, flags); - end = idx = local->next_txfid; - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; - spin_unlock_irqrestore(&local->txfidlock, flags); - return idx; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != end); - spin_unlock_irqrestore(&local->txfidlock, flags); - - PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " - "packet dropped\n"); - local->dev->stats.tx_dropped++; - - return -1; -} - - -/* Called only from hardware IRQ */ -static void prism2_transmit_cb(struct net_device *dev, long context, - u16 resp0, u16 res) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx = (int) context; - - iface = netdev_priv(dev); - local = iface->local; - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", - dev->name, res); - return; - } - - if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { - printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " - "idx=%d\n", dev->name, idx); - return; - } - - if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " - "with no pending transmit\n", dev->name); - } - - if (netif_queue_stopped(dev)) { - /* ready for next TX, so wake up queue that was stopped in - * prism2_transmit() */ - netif_wake_queue(dev); - } - - spin_lock(&local->txfidlock); - - /* With reclaim, Resp0 contains new txfid for transmit; the old txfid - * will be automatically allocated for the next TX frame */ - local->intransmitfid[idx] = resp0; - - PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " - "resp0=0x%04x, transmit_txfid=0x%04x\n", - dev->name, idx, local->txfid[idx], - resp0, local->intransmitfid[local->next_txfid]); - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - local->next_txfid = idx; - - /* check if all TX buffers are occupied */ - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - spin_unlock(&local->txfidlock); - return; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_txfid); - spin_unlock(&local->txfidlock); - - /* no empty TX buffers, stop queue */ - netif_stop_queue(dev); -} - - -/* Called only from software IRQ if PCI bus master is not used (with bus master - * this can be called both from software and hardware IRQ) */ -static int prism2_transmit(struct net_device *dev, int idx) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* The driver tries to stop netif queue so that there would not be - * more than one attempt to transmit frames going on; check that this - * is really the case */ - - if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " - "when previous TX was pending\n", dev->name); - return -1; - } - - /* stop the queue for the time that transmit is pending */ - netif_stop_queue(dev); - - /* transmit packet */ - res = hfa384x_cmd_callback( - dev, - HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, - local->txfid[idx], - prism2_transmit_cb, (long) idx); - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " - "failed (res=%d)\n", dev->name, res); - dev->stats.tx_dropped++; - netif_wake_queue(dev); - return -1; - } - netif_trans_update(dev); - - /* Since we did not wait for command completion, the card continues - * to process on the background and we will finish handling when - * command completion event is handled (prism2_cmd_ev() function) */ - - return 0; -} - - -/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and - * send the payload with this descriptor) */ -/* Called only from software IRQ */ -static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_tx_frame txdesc; - struct hostap_skb_tx_data *meta; - int hdr_len, data_len, idx, res, ret = -1; - u16 tx_control; - - iface = netdev_priv(dev); - local = iface->local; - - meta = (struct hostap_skb_tx_data *) skb->cb; - - prism2_callback(local, PRISM2_CALLBACK_TX_START); - - if ((local->func->card_present && !local->func->card_present(local)) || - !local->hw_ready || local->hw_downloading || local->pri_only) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" - " skipping\n", dev->name); - } - goto fail; - } - - memset(&txdesc, 0, sizeof(txdesc)); - - /* skb->data starts with txdesc->frame_control */ - hdr_len = sizeof(txdesc.header); - BUILD_BUG_ON(hdr_len != 24); - skb_copy_from_linear_data(skb, &txdesc.header, hdr_len); - if (ieee80211_is_data(txdesc.frame_control) && - ieee80211_has_a4(txdesc.frame_control) && - skb->len >= 30) { - /* Addr4 */ - skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, - ETH_ALEN); - hdr_len += ETH_ALEN; - } - - tx_control = local->tx_control; - if (meta->tx_cb_idx) { - tx_control |= HFA384X_TX_CTRL_TX_OK; - txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx); - } - txdesc.tx_control = cpu_to_le16(tx_control); - txdesc.tx_rate = meta->rate; - - data_len = skb->len - hdr_len; - txdesc.data_len = cpu_to_le16(data_len); - txdesc.len = cpu_to_be16(data_len); - - idx = prism2_get_txfid_idx(local); - if (idx < 0) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) - hostap_dump_tx_header(dev->name, &txdesc); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); - - if (!res) - res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, - skb->len - hdr_len); - spin_unlock(&local->baplock); - - if (!res) - res = prism2_transmit(dev, idx); - if (res) { - printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", - dev->name); - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - schedule_work(&local->reset_queue); - goto fail; - } - - ret = 0; - -fail: - prism2_callback(local, PRISM2_CALLBACK_TX_END); - return ret; -} - - -/* Some SMP systems have reported number of odd errors with hostap_pci. fid - * register has changed values between consecutive reads for an unknown reason. - * This should really not happen, so more debugging is needed. This test - * version is a bit slower, but it will detect most of such register changes - * and will try to get the correct fid eventually. */ -#define EXTRA_FID_READ_TESTS - -static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) -{ -#ifdef EXTRA_FID_READ_TESTS - u16 val, val2, val3; - int i; - - for (i = 0; i < 10; i++) { - val = HFA384X_INW(reg); - val2 = HFA384X_INW(reg); - val3 = HFA384X_INW(reg); - - if (val == val2 && val == val3) - return val; - - printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" - " %04x %04x %04x\n", - dev->name, i, reg, val, val2, val3); - if ((val == val2 || val == val3) && val != 0) - return val; - if (val2 == val3 && val2 != 0) - return val2; - } - printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " - "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); - return val; -#else /* EXTRA_FID_READ_TESTS */ - return HFA384X_INW(reg); -#endif /* EXTRA_FID_READ_TESTS */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_rx(local_info_t *local) -{ - struct net_device *dev = local->dev; - int res, rx_pending = 0; - u16 len, hdr_len, rxfid, status, macport; - struct hfa384x_rx_frame rxdesc; - struct sk_buff *skb = NULL; - - prism2_callback(local, PRISM2_CALLBACK_RX_START); - - rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); -#ifndef final_version - if (rxfid == 0) { - rxfid = HFA384X_INW(HFA384X_RXFID_OFF); - printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", - rxfid); - if (rxfid == 0) { - schedule_work(&local->reset_queue); - goto rx_dropped; - } - /* try to continue with the new rxfid value */ - } -#endif - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); - - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, - res); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto rx_dropped; - } - - len = le16_to_cpu(rxdesc.data_len); - hdr_len = sizeof(rxdesc); - status = le16_to_cpu(rxdesc.status); - macport = (status >> 8) & 0x07; - - /* Drop frames with too large reported payload length. Monitor mode - * seems to sometimes pass frames (e.g., ctrl::ack) with signed and - * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for - * macport 7 */ - if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { - if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { - if (len >= (u16) -14) { - hdr_len -= 65535 - len; - hdr_len--; - } - len = 0; - } else { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received frame with invalid " - "length 0x%04x\n", dev->name, len); - hostap_dump_rx_header(dev->name, &rxdesc); - goto rx_dropped; - } - } - - skb = dev_alloc_skb(len + hdr_len); - if (!skb) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: RX failed to allocate skb\n", - dev->name); - goto rx_dropped; - } - skb->dev = dev; - skb_put_data(skb, &rxdesc, hdr_len); - - if (len > 0) - res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); - spin_unlock(&local->baplock); - if (res) { - printk(KERN_DEBUG "%s: RX failed to read " - "frame data\n", dev->name); - goto rx_dropped; - } - - skb_queue_tail(&local->rx_list, skb); - tasklet_schedule(&local->rx_tasklet); - - rx_exit: - prism2_callback(local, PRISM2_CALLBACK_RX_END); - if (!rx_pending) { - HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); - } - - return; - - rx_dropped: - dev->stats.rx_dropped++; - if (skb) - dev_kfree_skb(skb); - goto rx_exit; -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_rx_frame *rxdesc; - struct net_device *dev = skb->dev; - struct hostap_80211_rx_status stats; - int hdrlen, rx_hdrlen; - - rx_hdrlen = sizeof(*rxdesc); - if (skb->len < sizeof(*rxdesc)) { - /* Allow monitor mode to receive shorter frames */ - if (local->iw_mode == IW_MODE_MONITOR && - skb->len >= sizeof(*rxdesc) - 30) { - rx_hdrlen = skb->len; - } else { - dev_kfree_skb(skb); - return; - } - } - - rxdesc = (struct hfa384x_rx_frame *) skb->data; - - if (local->frame_dump & PRISM2_DUMP_RX_HDR && - skb->len >= sizeof(*rxdesc)) - hostap_dump_rx_header(dev->name, rxdesc); - - if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && - (!local->monitor_allow_fcserr || - local->iw_mode != IW_MODE_MONITOR)) - goto drop; - - if (skb->len > PRISM2_DATA_MAXLEN) { - printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", - dev->name, skb->len, PRISM2_DATA_MAXLEN); - goto drop; - } - - stats.mac_time = le32_to_cpu(rxdesc->time); - stats.signal = rxdesc->signal - local->rssi_to_dBm; - stats.noise = rxdesc->silence - local->rssi_to_dBm; - stats.rate = rxdesc->rate; - - /* Convert Prism2 RX structure into IEEE 802.11 header */ - hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control); - if (hdrlen > rx_hdrlen) - hdrlen = rx_hdrlen; - - memmove(skb_pull(skb, rx_hdrlen - hdrlen), - &rxdesc->frame_control, hdrlen); - - hostap_80211_rx(dev, skb, &stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, rx_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->rx_list)) != NULL) - hostap_rx_skb(local, skb); -} - - -/* Called only from hardware IRQ */ -static void prism2_alloc_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx; - u16 fid; - - iface = netdev_priv(dev); - local = iface->local; - - fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); - - PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); - - spin_lock(&local->txfidlock); - idx = local->next_alloc; - - do { - if (local->txfid[idx] == fid) { - PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", - idx); - -#ifndef final_version - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) - printk("Already released txfid found at idx " - "%d\n", idx); - if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) - printk("Already reserved txfid found at idx " - "%d\n", idx); -#endif - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - idx++; - local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : - idx; - - if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && - netif_queue_stopped(dev)) - netif_wake_queue(dev); - - spin_unlock(&local->txfidlock); - return; - } - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_alloc); - - printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " - "read 0x%04x) for alloc event\n", dev->name, fid, - HFA384X_INW(HFA384X_ALLOCFID_OFF)); - printk(KERN_DEBUG "TXFIDs:"); - for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) - printk(" %04x[%04x]", local->txfid[idx], - local->intransmitfid[idx]); - printk("\n"); - spin_unlock(&local->txfidlock); - - /* FIX: should probably schedule reset; reference to one txfid was lost - * completely.. Bad things will happen if we run out of txfids - * Actually, this will cause netdev watchdog to notice TX timeout and - * then card reset after all txfids have been leaked. */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_tx_callback(local_info_t *local, - struct hfa384x_tx_frame *txdesc, int ok, - char *payload) -{ - u16 sw_support, hdrlen, len; - struct sk_buff *skb; - struct hostap_tx_callback_info *cb; - - /* Make sure that frame was from us. */ - if (!ether_addr_equal(txdesc->addr2, local->dev->dev_addr)) { - printk(KERN_DEBUG "%s: TX callback - foreign frame\n", - local->dev->name); - return; - } - - sw_support = le32_to_cpu(txdesc->sw_support); - - spin_lock(&local->lock); - cb = local->tx_callback; - while (cb != NULL && cb->idx != sw_support) - cb = cb->next; - spin_unlock(&local->lock); - - if (cb == NULL) { - printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", - local->dev->name, sw_support); - return; - } - - hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - len = le16_to_cpu(txdesc->data_len); - skb = dev_alloc_skb(hdrlen + len); - if (skb == NULL) { - printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " - "skb\n", local->dev->name); - return; - } - - skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen); - if (payload) - skb_put_data(skb, payload, len); - - skb->dev = local->dev; - skb_reset_mac_header(skb); - - cb->func(skb, ok, cb->data); -} - - -/* Called only as a tasklet (software IRQ) */ -static int hostap_tx_compl_read(local_info_t *local, int error, - struct hfa384x_tx_frame *txdesc, - char **payload) -{ - u16 fid, len; - int res, ret = 0; - struct net_device *dev = local->dev; - - fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); - - PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); - if (res) { - PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " - "read txdesc\n", dev->name, error, fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - ret = -1; - goto fail; - } - if (txdesc->sw_support) { - len = le16_to_cpu(txdesc->data_len); - if (len < PRISM2_DATA_MAXLEN) { - *payload = kmalloc(len, GFP_ATOMIC); - if (*payload == NULL || - hfa384x_from_bap(dev, BAP0, *payload, len)) { - PDEBUG(DEBUG_EXTRA, "%s: could not read TX " - "frame payload\n", dev->name); - kfree(*payload); - *payload = NULL; - ret = -1; - goto fail; - } - } - } - - fail: - spin_unlock(&local->baplock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_tx_ev(local_info_t *local) -{ - struct net_device *dev = local->dev; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) { - PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " - "retry_count=%d tx_rate=%d seq_ctrl=%d " - "duration_id=%d\n", - dev->name, le16_to_cpu(txdesc.status), - txdesc.retry_count, txdesc.tx_rate, - le16_to_cpu(txdesc.seq_ctrl), - le16_to_cpu(txdesc.duration_id)); - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 1, payload); - kfree(payload); - - fail: - HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_sta_tx_exc_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, sta_tx_exc_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { - struct hfa384x_tx_frame *txdesc = - (struct hfa384x_tx_frame *) skb->data; - - if (skb->len >= sizeof(*txdesc)) { - /* Convert Prism2 RX structure into IEEE 802.11 header - */ - int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), - &txdesc->frame_control, hdrlen); - - hostap_handle_sta_tx_exc(local, skb); - } - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_txexc(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 status, fc; - int show_dump, res; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; - dev->stats.tx_errors++; - - res = hostap_tx_compl_read(local, 1, &txdesc, &payload); - HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); - if (res) - return; - - status = le16_to_cpu(txdesc.status); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) - { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. */ - memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } else - show_dump = 1; - - if (local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->wds_type & HOSTAP_WDS_AP_CLIENT) { - struct sk_buff *skb; - skb = dev_alloc_skb(sizeof(txdesc)); - if (skb) { - skb_put_data(skb, &txdesc, sizeof(txdesc)); - skb_queue_tail(&local->sta_tx_exc_list, skb); - tasklet_schedule(&local->sta_tx_exc_tasklet); - } - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 0, payload); - kfree(payload); - - if (!show_dump) - return; - - PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" - " tx_control=%04x\n", - dev->name, status, - status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", - status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", - status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", - status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", - le16_to_cpu(txdesc.tx_control)); - - fc = le16_to_cpu(txdesc.frame_control); - PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " - "(%s%s%s::%d%s%s)\n", - txdesc.retry_count, txdesc.tx_rate, fc, - ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "", - ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "", - ieee80211_is_data(txdesc.frame_control) ? "Data" : "", - (fc & IEEE80211_FCTL_STYPE) >> 4, - ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "", - ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", - txdesc.addr1, txdesc.addr2, - txdesc.addr3, txdesc.addr4); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_info_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, info_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->info_list)) != NULL) { - hostap_info_process(local, skb); - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 fid; - int res, left; - struct hfa384x_info_frame info; - struct sk_buff *skb; - - fid = HFA384X_INW(HFA384X_INFOFID_OFF); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", - fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto out; - } - - left = (le16_to_cpu(info.len) - 1) * 2; - - if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) { - /* data register seems to give 0x8000 in some error cases even - * though busy bit is not set in offset register; - * in addition, length must be at least 1 due to type field */ - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received info frame with invalid " - "length 0x%04x (type 0x%04x)\n", dev->name, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - goto out; - } - - skb = dev_alloc_skb(sizeof(info) + left); - if (skb == NULL) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Could not allocate skb for info " - "frame\n", dev->name); - goto out; - } - - skb_put_data(skb, &info, sizeof(info)); - if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) - { - spin_unlock(&local->baplock); - printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " - "len=0x%04x, type=0x%04x\n", dev->name, fid, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - dev_kfree_skb(skb); - goto out; - } - spin_unlock(&local->baplock); - - skb_queue_tail(&local->info_list, skb); - tasklet_schedule(&local->info_tasklet); - - out: - HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_bap_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, bap_tasklet); - struct net_device *dev = local->dev; - u16 ev; - int frames = 30; - - if (local->func->card_present && !local->func->card_present(local)) - return; - - set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Process all pending BAP events without generating new interrupts - * for them */ - while (frames-- > 0) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) - break; - if (ev & HFA384X_EV_RX) - prism2_rx(local); - if (ev & HFA384X_EV_INFO) - prism2_info(local); - if (ev & HFA384X_EV_TX) - prism2_tx_ev(local); - if (ev & HFA384X_EV_TXEXC) - prism2_txexc(local); - } - - set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); - clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Enable interrupts for new BAP events */ - hfa384x_events_all(dev); - clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); -} - - -/* Called only from hardware IRQ */ -static void prism2_infdrop(struct net_device *dev) -{ - static unsigned long last_inquire = 0; - - PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); - - /* some firmware versions seem to get stuck with - * full CommTallies in high traffic load cases; every - * packet will then cause INFDROP event and CommTallies - * info frame will not be sent automatically. Try to - * get out of this state by inquiring CommTallies. */ - if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { - hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } -} - - -/* Called only from hardware IRQ */ -static void prism2_ev_tick(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 evstat, inten; - static int prev_stuck = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && - local->last_tick_timer) { - evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - inten = HFA384X_INW(HFA384X_INTEN_OFF); - if (!prev_stuck) { - printk(KERN_INFO "%s: SW TICK stuck? " - "bits=0x%lx EvStat=%04x IntEn=%04x\n", - dev->name, local->bits, evstat, inten); - } - local->sw_tick_stuck++; - if ((evstat & HFA384X_BAP0_EVENTS) && - (inten & HFA384X_BAP0_EVENTS)) { - printk(KERN_INFO "%s: trying to recover from IRQ " - "hang\n", dev->name); - hfa384x_events_no_bap0(dev); - } - prev_stuck = 1; - } else - prev_stuck = 0; -} - - -/* Called only from hardware IRQ */ -static void prism2_check_magic(local_info_t *local) -{ - /* at least PCI Prism2.5 with bus mastering seems to sometimes - * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the - * register once or twice seems to get the correct value.. PCI cards - * cannot anyway be removed during normal operation, so there is not - * really any need for this verification with them. */ - -#ifndef PRISM2_PCI -#ifndef final_version - static unsigned long last_magic_err = 0; - struct net_device *dev = local->dev; - - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - if (!local->hw_ready) - return; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - if (time_after(jiffies, last_magic_err + 10 * HZ)) { - printk("%s: Interrupt, but SWSUPPORT0 does not match: " - "%04X != %04X - card removed?\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - last_magic_err = jiffies; - } else if (net_ratelimit()) { - printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " - "MAGIC=%04x\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - } - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) - schedule_work(&local->reset_queue); - return; - } -#endif /* final_version */ -#endif /* !PRISM2_PCI */ -} - - -/* Called only from hardware IRQ */ -static irqreturn_t prism2_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct hostap_interface *iface; - local_info_t *local; - int events = 0; - u16 ev; - - iface = netdev_priv(dev); - local = iface->local; - - /* Detect early interrupt before driver is fully configured */ - spin_lock(&local->irq_init_lock); - if (!dev->base_addr) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", - dev->name); - } - spin_unlock(&local->irq_init_lock); - return IRQ_HANDLED; - } - spin_unlock(&local->irq_init_lock); - - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); - - if (local->func->card_present && !local->func->card_present(local)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", - dev->name); - } - return IRQ_HANDLED; - } - - prism2_check_magic(local); - - for (;;) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff) { - if (local->shutdown) - return IRQ_HANDLED; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", - dev->name); - return IRQ_HANDLED; - } - - ev &= HFA384X_INW(HFA384X_INTEN_OFF); - if (ev == 0) - break; - - if (ev & HFA384X_EV_CMD) { - prism2_cmd_ev(dev); - } - - /* Above events are needed even before hw is ready, but other - * events should be skipped during initialization. This may - * change for AllocEv if allocate_fid is implemented without - * busy waiting. */ - if (!local->hw_ready || local->hw_resetting || - !local->dev_enabled) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev & HFA384X_EV_CMD) - goto next_event; - if ((ev & HFA384X_EVENT_MASK) == 0) - return IRQ_HANDLED; - if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && - net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_interrupt: hw " - "not ready; skipping events 0x%04x " - "(IntEn=0x%04x)%s%s%s\n", - dev->name, ev, - HFA384X_INW(HFA384X_INTEN_OFF), - !local->hw_ready ? " (!hw_ready)" : "", - local->hw_resetting ? - " (hw_resetting)" : "", - !local->dev_enabled ? - " (!dev_enabled)" : ""); - } - HFA384X_OUTW(ev, HFA384X_EVACK_OFF); - return IRQ_HANDLED; - } - - if (ev & HFA384X_EV_TICK) { - prism2_ev_tick(dev); - HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); - } - - if (ev & HFA384X_EV_ALLOC) { - prism2_alloc_ev(dev); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - } - - /* Reading data from the card is quite time consuming, so do it - * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed - * and unmasked after needed data has been read completely. */ - if (ev & HFA384X_BAP0_EVENTS) { - hfa384x_events_no_bap0(dev); - tasklet_schedule(&local->bap_tasklet); - } - -#ifndef final_version - if (ev & HFA384X_EV_WTERR) { - PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); - HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); - } -#endif /* final_version */ - - if (ev & HFA384X_EV_INFDROP) { - prism2_infdrop(dev); - HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); - } - - next_event: - events++; - if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { - PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " - "(EvStat=0x%04x)\n", - PRISM2_MAX_INTERRUPT_EVENTS, - HFA384X_INW(HFA384X_EVSTAT_OFF)); - break; - } - } - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); - return IRQ_RETVAL(events); -} - - -static void prism2_check_sta_fw_version(local_info_t *local) -{ - struct hfa384x_comp_ident comp; - int id, variant, major, minor; - - if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, - &comp, sizeof(comp), 1) < 0) - return; - - local->fw_ap = 0; - id = le16_to_cpu(comp.id); - if (id != HFA384X_COMP_ID_STA) { - if (id == HFA384X_COMP_ID_FW_AP) - local->fw_ap = 1; - return; - } - - major = __le16_to_cpu(comp.major); - minor = __le16_to_cpu(comp.minor); - variant = __le16_to_cpu(comp.variant); - local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); - - /* Station firmware versions before 1.4.x seem to have a bug in - * firmware-based WEP encryption when using Host AP mode, so use - * host_encrypt as a default for them. Firmware version 1.4.9 is the - * first one that has been seen to produce correct encryption, but the - * bug might be fixed before that (although, at least 1.4.2 is broken). - */ - local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); - - if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - local->dev->name); - local->host_encrypt = 1; - } - - /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken - * in station firmware versions before 1.5.x. With these versions, the - * driver uses a workaround with bogus frame format (4th address after - * the payload). This is not compatible with other AP devices. Since - * the firmware bug is fixed in the latest station firmware versions, - * automatically enable standard compliant mode for cards using station - * firmware version 1.5.0 or newer. */ - if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) - local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; - else { - printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " - "workaround for firmware bug in Host AP mode WDS\n", - local->dev->name); - } - - hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); -} - - -static void hostap_passive_scan(struct timer_list *t) -{ - local_info_t *local = from_timer(local, t, passive_scan_timer); - struct net_device *dev = local->dev; - u16 chan; - - if (local->passive_scan_interval <= 0) - return; - - if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { - int max_tries = 16; - - /* Even though host system does not really know when the WLAN - * MAC is sending frames, try to avoid changing channels for - * passive scanning when a host-generated frame is being - * transmitted */ - if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: passive scan detected pending " - "TX - delaying\n", dev->name); - local->passive_scan_timer.expires = jiffies + HZ / 10; - add_timer(&local->passive_scan_timer); - return; - } - - do { - local->passive_scan_channel++; - if (local->passive_scan_channel > 14) - local->passive_scan_channel = 1; - max_tries--; - } while (!(local->channel_mask & - (1 << (local->passive_scan_channel - 1))) && - max_tries > 0); - - if (max_tries == 0) { - printk(KERN_INFO "%s: no allowed passive scan channels" - " found\n", dev->name); - return; - } - - printk(KERN_DEBUG "%s: passive scan channel %d\n", - dev->name, local->passive_scan_channel); - chan = local->passive_scan_channel; - local->passive_scan_state = PASSIVE_SCAN_WAIT; - local->passive_scan_timer.expires = jiffies + HZ / 10; - } else { - chan = local->channel; - local->passive_scan_state = PASSIVE_SCAN_LISTEN; - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - } - - if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CHANGE_CHANNEL << 8), - chan, NULL, 0)) - printk(KERN_ERR "%s: passive scan channel set %d " - "failed\n", dev->name, chan); - - add_timer(&local->passive_scan_timer); -} - - -/* Called only as a scheduled task when communications quality values should - * be updated. */ -static void handle_comms_qual_update(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, comms_qual_update); - prism2_update_comms_qual(local->dev); -} - - -/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is - * used to monitor that local->last_tick_timer is being updated. If not, - * interrupt busy-loop is assumed and driver tries to recover by masking out - * some events. */ -static void hostap_tick_timer(struct timer_list *t) -{ - static unsigned long last_inquire = 0; - local_info_t *local = from_timer(local, t, tick_timer); - local->last_tick_timer = jiffies; - - /* Inquire CommTallies every 10 seconds to keep the statistics updated - * more often during low load and when using 32-bit tallies. */ - if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && - !local->hw_downloading && local->hw_ready && - !local->hw_resetting && local->dev_enabled) { - hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } - - if ((local->last_comms_qual_update == 0 || - time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && - (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC)) { - schedule_work(&local->comms_qual_update); - } - - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); -} - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) -{ - return HFA384X_INW(reg); -} - -static int prism2_registers_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - -#define SHOW_REG(n) \ - seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) - - SHOW_REG(CMD); - SHOW_REG(PARAM0); - SHOW_REG(PARAM1); - SHOW_REG(PARAM2); - SHOW_REG(STATUS); - SHOW_REG(RESP0); - SHOW_REG(RESP1); - SHOW_REG(RESP2); - SHOW_REG(INFOFID); - SHOW_REG(CONTROL); - SHOW_REG(SELECT0); - SHOW_REG(SELECT1); - SHOW_REG(OFFSET0); - SHOW_REG(OFFSET1); - SHOW_REG(RXFID); - SHOW_REG(ALLOCFID); - SHOW_REG(TXCOMPLFID); - SHOW_REG(SWSUPPORT0); - SHOW_REG(SWSUPPORT1); - SHOW_REG(SWSUPPORT2); - SHOW_REG(EVSTAT); - SHOW_REG(INTEN); - SHOW_REG(EVACK); - /* Do not read data registers, because they change the state of the - * MAC (offset += 2) */ - /* SHOW_REG(DATA0); */ - /* SHOW_REG(DATA1); */ - SHOW_REG(AUXPAGE); - SHOW_REG(AUXOFFSET); - /* SHOW_REG(AUXDATA); */ -#ifdef PRISM2_PCI - SHOW_REG(PCICOR); - SHOW_REG(PCIHCR); - SHOW_REG(PCI_M0_ADDRH); - SHOW_REG(PCI_M0_ADDRL); - SHOW_REG(PCI_M0_LEN); - SHOW_REG(PCI_M0_CTL); - SHOW_REG(PCI_STATUS); - SHOW_REG(PCI_M1_ADDRH); - SHOW_REG(PCI_M1_ADDRL); - SHOW_REG(PCI_M1_LEN); - SHOW_REG(PCI_M1_CTL); -#endif /* PRISM2_PCI */ - - return 0; -} -#endif - -struct set_tim_data { - struct list_head list; - int aid; - int set; -}; - -static int prism2_set_tim(struct net_device *dev, int aid, int set) -{ - struct list_head *ptr; - struct set_tim_data *new_entry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); - if (new_entry == NULL) - return -ENOMEM; - - new_entry->aid = aid; - new_entry->set = set; - - spin_lock_bh(&local->set_tim_lock); - list_for_each(ptr, &local->set_tim_list) { - struct set_tim_data *entry = - list_entry(ptr, struct set_tim_data, list); - if (entry->aid == aid) { - PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " - "set=%d ==> %d\n", - local->dev->name, aid, entry->set, set); - entry->set = set; - kfree(new_entry); - new_entry = NULL; - break; - } - } - if (new_entry) - list_add_tail(&new_entry->list, &local->set_tim_list); - spin_unlock_bh(&local->set_tim_lock); - - schedule_work(&local->set_tim_queue); - - return 0; -} - - -static void handle_set_tim_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, set_tim_queue); - struct set_tim_data *entry; - u16 val; - - for (;;) { - entry = NULL; - spin_lock_bh(&local->set_tim_lock); - if (!list_empty(&local->set_tim_list)) { - entry = list_entry(local->set_tim_list.next, - struct set_tim_data, list); - list_del(&entry->list); - } - spin_unlock_bh(&local->set_tim_lock); - if (!entry) - break; - - PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", - local->dev->name, entry->aid, entry->set); - - val = entry->aid; - if (entry->set) - val |= 0x8000; - if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { - printk(KERN_DEBUG "%s: set_tim failed (aid=%d " - "set=%d)\n", - local->dev->name, entry->aid, entry->set); - } - - kfree(entry); - } -} - - -static void prism2_clear_set_tim_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - - list_for_each_safe(ptr, n, &local->set_tim_list) { - struct set_tim_data *entry; - entry = list_entry(ptr, struct set_tim_data, list); - list_del(&entry->list); - kfree(entry); - } -} - - -/* - * HostAP uses two layers of net devices, where the inner - * layer gets called all the time from the outer layer. - * This is a natural nesting, which needs a split lock type. - */ -static struct lock_class_key hostap_netdev_xmit_lock_key; -static struct lock_class_key hostap_netdev_addr_lock_key; - -static void prism2_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, - &hostap_netdev_xmit_lock_key); -} - -static void prism2_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, - &hostap_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL); -} - -static struct net_device * -prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, - struct device *sdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct local_info *local; - int len, i, ret; - - if (funcs == NULL) - return NULL; - - len = strlen(dev_template); - if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { - printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", - dev_template); - return NULL; - } - - len = sizeof(struct hostap_interface) + - 3 + sizeof(struct local_info) + - 3 + sizeof(struct ap_data); - - dev = alloc_etherdev(len); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); - local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); - local->dev = iface->dev = dev; - iface->local = local; - iface->type = HOSTAP_INTERFACE_MASTER; - INIT_LIST_HEAD(&local->hostap_interfaces); - - local->hw_module = THIS_MODULE; - -#ifdef PRISM2_IO_DEBUG - local->io_debug_enabled = 1; -#endif /* PRISM2_IO_DEBUG */ - - local->func = funcs; - local->func->cmd = hfa384x_cmd; - local->func->read_regs = hfa384x_read_regs; - local->func->get_rid = hfa384x_get_rid; - local->func->set_rid = hfa384x_set_rid; - local->func->hw_enable = prism2_hw_enable; - local->func->hw_config = prism2_hw_config; - local->func->hw_reset = prism2_hw_reset; - local->func->hw_shutdown = prism2_hw_shutdown; - local->func->reset_port = prism2_reset_port; - local->func->schedule_reset = prism2_schedule_reset; -#ifdef PRISM2_DOWNLOAD_SUPPORT - local->func->read_aux_proc_ops = &prism2_download_aux_dump_proc_ops; - local->func->download = prism2_download; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - local->func->tx = prism2_tx_80211; - local->func->set_tim = prism2_set_tim; - local->func->need_tx_headroom = 0; /* no need to add txdesc in - * skb->data (FIX: maybe for DMA bus - * mastering? */ - - local->mtu = mtu; - - rwlock_init(&local->iface_lock); - spin_lock_init(&local->txfidlock); - spin_lock_init(&local->cmdlock); - spin_lock_init(&local->baplock); - spin_lock_init(&local->lock); - spin_lock_init(&local->irq_init_lock); - mutex_init(&local->rid_bap_mtx); - - if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) - card_idx = 0; - local->card_idx = card_idx; - - len = strlen(essid); - memcpy(local->essid, essid, - len > MAX_SSID_LEN ? MAX_SSID_LEN : len); - local->essid[MAX_SSID_LEN] = '\0'; - i = GET_INT_PARM(iw_mode, card_idx); - if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || - i == IW_MODE_MONITOR) { - local->iw_mode = i; - } else { - printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " - "IW_MODE_MASTER\n", i); - local->iw_mode = IW_MODE_MASTER; - } - local->channel = GET_INT_PARM(channel, card_idx); - local->beacon_int = GET_INT_PARM(beacon_int, card_idx); - local->dtim_period = GET_INT_PARM(dtim_period, card_idx); - local->wds_max_connections = 16; - local->tx_control = HFA384X_TX_CTRL_FLAGS; - local->manual_retry_count = -1; - local->rts_threshold = 2347; - local->fragm_threshold = 2346; - local->rssi_to_dBm = 100; /* default; to be overriden by - * cnfDbmAdjust, if available */ - local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; - local->sram_type = -1; - local->scan_channel_mask = 0xffff; - local->monitor_type = PRISM2_MONITOR_RADIOTAP; - - /* Initialize task queue structures */ - INIT_WORK(&local->reset_queue, handle_reset_queue); - INIT_WORK(&local->set_multicast_list_queue, - hostap_set_multicast_list_queue); - - INIT_WORK(&local->set_tim_queue, handle_set_tim_queue); - INIT_LIST_HEAD(&local->set_tim_list); - spin_lock_init(&local->set_tim_lock); - - INIT_WORK(&local->comms_qual_update, handle_comms_qual_update); - - /* Initialize tasklets for handling hardware IRQ related operations - * outside hw IRQ handler */ - tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet); - tasklet_setup(&local->info_tasklet, hostap_info_tasklet); - hostap_info_init(local); - - tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet); - skb_queue_head_init(&local->rx_list); - - tasklet_setup(&local->sta_tx_exc_tasklet, - hostap_sta_tx_exc_tasklet); - skb_queue_head_init(&local->sta_tx_exc_list); - - INIT_LIST_HEAD(&local->cmd_queue); - init_waitqueue_head(&local->hostscan_wq); - - lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); - - timer_setup(&local->passive_scan_timer, hostap_passive_scan, 0); - timer_setup(&local->tick_timer, hostap_tick_timer, 0); - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); - - INIT_LIST_HEAD(&local->bss_list); - - hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER); - - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - - rtnl_lock(); - ret = dev_alloc_name(dev, "wifi%d"); - SET_NETDEV_DEV(dev, sdev); - if (ret >= 0) - ret = register_netdevice(dev); - - prism2_set_lockdep_class(dev); - rtnl_unlock(); - if (ret < 0) { - printk(KERN_WARNING "%s: register netdevice failed!\n", - dev_info); - goto fail; - } - printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); - - hostap_init_data(local); - return dev; - - fail: - free_netdev(dev); - return NULL; -} - - -static int hostap_hw_ready(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - - iface = netdev_priv(dev); - local = iface->local; - local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, - "", dev_template); - - if (local->ddev) { - if (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC) { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - } - hostap_init_proc(local); -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("registers", 0, local->proc, - prism2_registers_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_init_ap_proc(local); - return 0; - } - - return -1; -} - - -static void prism2_free_local_data(struct net_device *dev) -{ - struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; - int i; - struct hostap_interface *iface; - struct local_info *local; - struct list_head *ptr, *n; - - if (dev == NULL) - return; - - iface = netdev_priv(dev); - local = iface->local; - - /* Unregister all netdevs before freeing local data. */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - - unregister_netdev(local->dev); - - flush_work(&local->reset_queue); - flush_work(&local->set_multicast_list_queue); - flush_work(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - flush_work(&local->info_queue); -#endif - flush_work(&local->comms_qual_update); - - lib80211_crypt_info_free(&local->crypt_info); - - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - - if (timer_pending(&local->tick_timer)) - del_timer(&local->tick_timer); - - prism2_clear_cmd_queue(local); - - skb_queue_purge(&local->info_list); - skb_queue_purge(&local->rx_list); - skb_queue_purge(&local->sta_tx_exc_list); - - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - - if (local->ap != NULL) - hostap_free_data(local->ap); - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (local->proc != NULL) - remove_proc_entry("registers", local->proc); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_remove_proc(local); - - tx_cb = local->tx_callback; - while (tx_cb != NULL) { - tx_cb_prev = tx_cb; - tx_cb = tx_cb->next; - kfree(tx_cb_prev); - } - - hostap_set_hostapd(local, 0, 0); - hostap_set_hostapd_sta(local, 0, 0); - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - if (local->frag_cache[i].skb != NULL) - dev_kfree_skb(local->frag_cache[i].skb); - } - -#ifdef PRISM2_DOWNLOAD_SUPPORT - prism2_download_free_data(local->dl_pri); - prism2_download_free_data(local->dl_sec); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - prism2_clear_set_tim_queue(local); - - list_for_each_safe(ptr, n, &local->bss_list) { - struct hostap_bss_info *bss = - list_entry(ptr, struct hostap_bss_info, list); - kfree(bss); - } - - kfree(local->pda); - kfree(local->last_scan_results); - kfree(local->generic_elem); - - free_netdev(local->dev); -} - - -#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD) -static void __maybe_unused prism2_suspend(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - union iwreq_data wrqu; - - iface = netdev_priv(dev); - local = iface->local; - - /* Send disconnect event, e.g., to trigger reassociation after resume - * if wpa_supplicant is used. */ - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - - /* Disable hardware and firmware */ - prism2_hw_shutdown(dev, 0); -} -#endif /* PRISM2_PCI || PRISM2_PCCARD */ - - -/* These might at some point be compiled separately and used as separate - * kernel modules or linked into one */ -#ifdef PRISM2_DOWNLOAD_SUPPORT -#include "hostap_download.c" -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_CALLBACK -/* External hostap_callback.c file can be used to, e.g., blink activity led. - * This can use platform specific code and must define prism2_callback() - * function (if PRISM2_CALLBACK is not defined, these function calls are not - * used. */ -#include "hostap_callback.c" -#endif /* PRISM2_CALLBACK */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c deleted file mode 100644 index da8c30f10d92..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_info.c +++ /dev/null @@ -1,509 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Host AP driver Info Frame processing (part of hostap.o module) */ - -#include -#include -#include -#include -#include -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le16_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies32 *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies32)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies32 *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le32_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, - int left) -{ - if (local->tallies32) - prism2_info_commtallies32(local, buf, left); - else - prism2_info_commtallies16(local, buf, left); -} - - -#ifndef PRISM2_NO_STATION_MODES -#ifndef PRISM2_NO_DEBUG -static const char* hfa384x_linkstatus_str(u16 linkstatus) -{ - switch (linkstatus) { - case HFA384X_LINKSTATUS_CONNECTED: - return "Connected"; - case HFA384X_LINKSTATUS_DISCONNECTED: - return "Disconnected"; - case HFA384X_LINKSTATUS_AP_CHANGE: - return "Access point change"; - case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: - return "Access point out of range"; - case HFA384X_LINKSTATUS_AP_IN_RANGE: - return "Access point in range"; - case HFA384X_LINKSTATUS_ASSOC_FAILED: - return "Association failed"; - default: - return "Unknown"; - } -} -#endif /* PRISM2_NO_DEBUG */ - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, - int left) -{ - u16 val; - int non_sta_mode; - - /* Alloc new JoinRequests to occur since LinkStatus for the previous - * has been received */ - local->last_join_time = 0; - - if (left != 2) { - printk(KERN_DEBUG "%s: invalid linkstatus info frame " - "length %d\n", local->dev->name, left); - return; - } - - non_sta_mode = local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->iw_mode == IW_MODE_MONITOR; - - val = buf[0] | (buf[1] << 8); - if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", - local->dev->name, val, hfa384x_linkstatus_str(val)); - } - - if (non_sta_mode) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - return; - } - - /* Get current BSSID later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); - local->prev_link_status = val; - schedule_work(&local->info_queue); -} - - -static void prism2_host_roaming(local_info_t *local) -{ - struct hfa384x_join_request req; - struct net_device *dev = local->dev; - struct hfa384x_hostscan_result *selected, *entry; - int i; - unsigned long flags; - - if (local->last_join_time && - time_before(jiffies, local->last_join_time + 10 * HZ)) { - PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " - "completed - waiting for it before issuing new one\n", - dev->name); - return; - } - - /* ScanResults are sorted: first ESS results in decreasing signal - * quality then IBSS results in similar order. - * Trivial roaming policy: just select the first entry. - * This could probably be improved by adding hysteresis to limit - * number of handoffs, etc. - * - * Could do periodic RID_SCANREQUEST or Inquire F101 to get new - * ScanResults */ - spin_lock_irqsave(&local->lock, flags); - if (local->last_scan_results == NULL || - local->last_scan_results_count == 0) { - spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", - dev->name); - return; - } - - selected = &local->last_scan_results[0]; - - if (local->preferred_ap[0] || local->preferred_ap[1] || - local->preferred_ap[2] || local->preferred_ap[3] || - local->preferred_ap[4] || local->preferred_ap[5]) { - /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", - dev->name, local->preferred_ap); - for (i = 0; i < local->last_scan_results_count; i++) { - entry = &local->last_scan_results[i]; - if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) - { - PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " - "selection\n", dev->name); - selected = entry; - break; - } - } - } - - memcpy(req.bssid, selected->bssid, ETH_ALEN); - req.channel = selected->chid; - spin_unlock_irqrestore(&local->lock, flags); - - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" - " channel=%d\n", - dev->name, req.bssid, le16_to_cpu(req.channel)); - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); - } - local->last_join_time = jiffies; -} - - -static void hostap_report_scan_complete(local_info_t *local) -{ - union iwreq_data wrqu; - - /* Inform user space about new scan results (just empty event, - * SIOCGIWSCAN can be used to fetch data */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); - - /* Allow SIOCGIWSCAN handling to occur since we have received - * scanning result */ - local->scan_timestamp = 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, - int left) -{ - u16 *pos; - int new_count, i; - unsigned long flags; - struct hfa384x_scan_result *res; - struct hfa384x_hostscan_result *results, *prev; - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid scanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (u16 *) buf; - pos++; - pos++; - left -= 4; - - new_count = left / sizeof(struct hfa384x_scan_result); - results = kmalloc_array(new_count, - sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - /* Convert to hostscan result format. */ - res = (struct hfa384x_scan_result *) pos; - for (i = 0; i < new_count; i++) { - memcpy(&results[i], &res[i], - sizeof(struct hfa384x_scan_result)); - results[i].atim = 0; - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_SCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); - - /* Perform rest of ScanResults handling later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); - schedule_work(&local->info_queue); -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_hostscanresults(local_info_t *local, - unsigned char *buf, int left) -{ - int i, result_size, copy_len, new_count; - struct hfa384x_hostscan_result *results, *prev; - unsigned long flags; - __le16 *pos; - u8 *ptr; - - wake_up_interruptible(&local->hostscan_wq); - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid hostscanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (__le16 *) buf; - copy_len = result_size = le16_to_cpu(*pos); - if (result_size == 0) { - printk(KERN_DEBUG "%s: invalid result_size (0) in " - "hostscanresults\n", local->dev->name); - return; - } - if (copy_len > sizeof(struct hfa384x_hostscan_result)) - copy_len = sizeof(struct hfa384x_hostscan_result); - - pos++; - pos++; - left -= 4; - ptr = (u8 *) pos; - - new_count = left / result_size; - results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - for (i = 0; i < new_count; i++) { - memcpy(&results[i], ptr, copy_len); - ptr += result_size; - left -= result_size; - } - - if (left) { - printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", - local->dev->name, left, result_size); - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_HOSTSCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -/* Called only as a tasklet (software IRQ) */ -void hostap_info_process(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_info_frame *info; - unsigned char *buf; - int left; -#ifndef PRISM2_NO_DEBUG - int i; -#endif /* PRISM2_NO_DEBUG */ - - info = (struct hfa384x_info_frame *) skb->data; - buf = skb->data + sizeof(*info); - left = skb->len - sizeof(*info); - - switch (le16_to_cpu(info->type)) { - case HFA384X_INFO_COMMTALLIES: - prism2_info_commtallies(local, buf, left); - break; - -#ifndef PRISM2_NO_STATION_MODES - case HFA384X_INFO_LINKSTATUS: - prism2_info_linkstatus(local, buf, left); - break; - - case HFA384X_INFO_SCANRESULTS: - prism2_info_scanresults(local, buf, left); - break; - - case HFA384X_INFO_HOSTSCANRESULTS: - prism2_info_hostscanresults(local, buf, left); - break; -#endif /* PRISM2_NO_STATION_MODES */ - -#ifndef PRISM2_NO_DEBUG - default: - PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", - local->dev->name, le16_to_cpu(info->len), - le16_to_cpu(info->type)); - PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); - for (i = 0; i < (left < 100 ? left : 100); i++) - PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); - PDEBUG2(DEBUG_EXTRA, "\n"); - break; -#endif /* PRISM2_NO_DEBUG */ - } -} - - -#ifndef PRISM2_NO_STATION_MODES -static void handle_info_queue_linkstatus(local_info_t *local) -{ - int val = local->prev_link_status; - int connected; - union iwreq_data wrqu; - - connected = - val == HFA384X_LINKSTATUS_CONNECTED || - val == HFA384X_LINKSTATUS_AP_CHANGE || - val == HFA384X_LINKSTATUS_AP_IN_RANGE; - - if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, - local->bssid, ETH_ALEN, 1) < 0) { - printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " - "LinkStatus event\n", local->dev->name); - } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", - local->dev->name, - (unsigned char *) local->bssid); - if (local->wds_type & HOSTAP_WDS_AP_CLIENT) - hostap_add_sta(local->ap, local->bssid); - } - - /* Get BSSID if we have a valid AP address */ - if (connected) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); - } else { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - eth_zero_addr(wrqu.ap_addr.sa_data); - } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* - * Filter out sequential disconnect events in order not to cause a - * flood of SIOCGIWAP events that have a race condition with EAPOL - * frames and can confuse wpa_supplicant about the current association - * status. - */ - if (connected || local->prev_linkstatus_connected) - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - local->prev_linkstatus_connected = connected; -} - - -static void handle_info_queue_scanresults(local_info_t *local) -{ - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) - prism2_host_roaming(local); - - if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA && - !is_zero_ether_addr(local->preferred_ap)) { - /* - * Firmware seems to be getting into odd state in host_roaming - * mode 2 when hostscan is used without join command, so try - * to fix this by re-joining the current AP. This does not - * actually trigger a new association if the current AP is - * still in the scan results. - */ - prism2_host_roaming(local); - } -} - - -/* Called only as scheduled task after receiving info frames (used to avoid - * pending too much time in HW IRQ handler). */ -static void handle_info_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, info_queue); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, - &local->pending_info)) - handle_info_queue_linkstatus(local); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, - &local->pending_info)) - handle_info_queue_scanresults(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_info_init(local_info_t *local) -{ - skb_queue_head_init(&local->info_list); -#ifndef PRISM2_NO_STATION_MODES - INIT_WORK(&local->info_queue, handle_info_queue); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -EXPORT_SYMBOL(hostap_info_init); -EXPORT_SYMBOL(hostap_info_process); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c deleted file mode 100644 index 26162f92e3c3..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ /dev/null @@ -1,3847 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct iw_statistics *wstats; - - iface = netdev_priv(dev); - local = iface->local; - - /* Why are we doing that ? Jean II */ - if (iface->type != HOSTAP_INTERFACE_MAIN) - return NULL; - - wstats = &local->wstats; - - wstats->status = 0; - wstats->discard.code = - local->comm_tallies.rx_discards_wep_undecryptable; - wstats->discard.misc = - local->comm_tallies.rx_fcs_errors + - local->comm_tallies.rx_discards_no_buffer + - local->comm_tallies.tx_discards_wrong_sa; - - wstats->discard.retries = - local->comm_tallies.tx_retry_limit_exceeded; - wstats->discard.fragment = - local->comm_tallies.rx_message_in_bad_msg_fragments; - - if (local->iw_mode != IW_MODE_MASTER && - local->iw_mode != IW_MODE_REPEAT) { - - if (prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = IW_QUAL_ALL_UPDATED | - IW_QUAL_DBM; - - wstats->qual.qual = local->comms_qual; - wstats->qual.level = local->avg_signal; - wstats->qual.noise = local->avg_noise; - } else { - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} - - -static int prism2_get_datarates(struct net_device *dev, u8 *rates) -{ - struct hostap_interface *iface; - local_info_t *local; - u8 buf[12]; - int len; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, - sizeof(buf), 0); - if (len < 2) - return 0; - - val = le16_to_cpu(*(__le16 *) buf); /* string length */ - - if (len - 2 < val || val > 10) - return 0; - - memcpy(rates, buf + 2, val); - return val; -} - - -static int prism2_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 rates[10]; - int len, i, over2 = 0; - - len = prism2_get_datarates(dev, rates); - - for (i = 0; i < len; i++) { - if (rates[i] == 0x0b || rates[i] == 0x16) { - over2 = 1; - break; - } - } - - strcpy(wrqu->name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); - - return 0; -} - - -static int prism2_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i; - struct lib80211_crypt_data **crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = &local->crypt_info.crypt[i]; - - if (erq->flags & IW_ENCODE_DISABLED) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - if (*crypt != NULL && (*crypt)->ops != NULL && - strcmp((*crypt)->ops->name, "WEP") != 0) { - /* changing to use WEP; deinit previously used algorithm */ - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - } - - if (*crypt == NULL) { - struct lib80211_crypt_data *new_crypt; - - /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) - return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - if (!new_crypt->ops) { - request_module("lib80211_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - } - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (!new_crypt->ops || !new_crypt->priv) { - kfree(new_crypt); - new_crypt = NULL; - - printk(KERN_WARNING "%s: could not initialize WEP: " - "load module hostap_crypt_wep.o\n", - dev->name); - return -EOPNOTSUPP; - } - *crypt = new_crypt; - } - - if (erq->length > 0) { - int len = erq->length <= 5 ? 5 : 13; - int first = 1, j; - if (len > erq->length) - memset(keybuf + erq->length, 0, len - erq->length); - (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } else { - /* No key data - just set the default TX key index */ - local->crypt_info.tx_keyidx = i; - } - - done: - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - if (hostap_set_encryption(local)) { - printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); - return -EINVAL; - } - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { - printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); - return -EINVAL; - } - - return 0; -} - - -static int prism2_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i, len; - u16 val; - struct lib80211_crypt_data *crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = local->crypt_info.crypt[i]; - erq->flags = i + 1; - - if (crypt == NULL || crypt->ops == NULL) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - if (strcmp(crypt->ops->name, "WEP") != 0) { - /* only WEP is supported with wireless extensions, so just - * report that encryption is used */ - erq->length = 0; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - - /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show - * the keys from driver buffer */ - len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); - erq->length = (len >= 0 ? len : 0); - - if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) - { - printk("CNFWEPFLAGS reading failed\n"); - return -EOPNOTSUPP; - } - le16_to_cpus(&val); - if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) - erq->flags |= IW_ENCODE_ENABLED; - else - erq->flags |= IW_ENCODE_DISABLED; - if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - return 0; -} - - -static int hostap_set_rate(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, basic_rates; - - iface = netdev_priv(dev); - local = iface->local; - - basic_rates = local->basic_rates & local->tx_rate_control; - if (!basic_rates || basic_rates != local->basic_rates) { - printk(KERN_INFO "%s: updating basic rate set automatically " - "to match with the new supported rate set\n", - dev->name); - if (!basic_rates) - basic_rates = local->tx_rate_control; - - local->basic_rates = basic_rates; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - basic_rates)) - printk(KERN_WARNING "%s: failed to set " - "cnfBasicRates\n", dev->name); - } - - ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control) || - hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control) || - local->func->reset_port(dev)); - - if (ret) { - printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " - "setting to 0x%x failed\n", - dev->name, local->tx_rate_control); - } - - /* Update TX rate configuration for all STAs based on new operational - * rate set. */ - hostap_update_rates(local); - - return ret; -} - - -static int prism2_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->fixed) { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } else { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } - - return hostap_set_rate(dev); -} - - -static int prism2_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - u16 val; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < - 0) - return -EINVAL; - - if ((val & 0x1) && (val > 1)) - rrq->fixed = 0; - else - rrq->fixed = 1; - - if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && - !local->fw_tx_rate_control) { - /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in - * Host AP mode, so use the recorded TX rate of the last sent - * frame */ - rrq->value = local->ap->last_tx_rate > 0 ? - local->ap->last_tx_rate * 100000 : 11000000; - return 0; - } - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < - 0) - return -EINVAL; - - switch (val) { - case HFA384X_RATES_1MBPS: - rrq->value = 1000000; - break; - case HFA384X_RATES_2MBPS: - rrq->value = 2000000; - break; - case HFA384X_RATES_5MBPS: - rrq->value = 5500000; - break; - case HFA384X_RATES_11MBPS: - rrq->value = 11000000; - break; - default: - /* should not happen */ - rrq->value = 11000000; - ret = -EINVAL; - break; - } - - return ret; -} - - -static int prism2_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Set the desired AP density */ - if (sens->value < 1 || sens->value > 3) - return -EINVAL; - - if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - /* Get the current AP density */ - if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < - 0) - return -EINVAL; - - sens->value = le16_to_cpu(val); - sens->fixed = 1; - - return 0; -} - - -/* Deprecated in new wireless extension API */ -static int prism2_ioctl_giwaplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct sockaddr *addr; - struct iw_quality *qual; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode != IW_MODE_MASTER) { - printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " - "in Host AP mode\n"); - data->length = 0; - return -EOPNOTSUPP; - } - - addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL); - qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL); - if (addr == NULL || qual == NULL) { - kfree(addr); - kfree(qual); - data->length = 0; - return -ENOMEM; - } - - data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); - - memcpy(extra, addr, sizeof(struct sockaddr) * data->length); - data->flags = 1; /* has quality information */ - memcpy(extra + sizeof(struct sockaddr) * data->length, qual, - sizeof(struct iw_quality) * data->length); - - kfree(addr); - kfree(qual); - return 0; -} - - -static int prism2_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2347); - else if (rts->value < 0 || rts->value > 2347) - return -EINVAL; - else - val = cpu_to_le16(rts->value); - - if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || - local->func->reset_port(dev)) - return -EINVAL; - - local->rts_threshold = rts->value; - - return 0; -} - -static int prism2_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < - 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2347); - rts->fixed = 1; - - return 0; -} - - -static int prism2_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2346); - else if (rts->value < 256 || rts->value > 2346) - return -EINVAL; - else - val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */ - - local->fragm_threshold = rts->value & ~0x1; - if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, - 2) - || local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - &val, 2, 1) < 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2346); - rts->fixed = 1; - - return 0; -} - - -#ifndef PRISM2_NO_STATION_MODES -static int hostap_join_ap(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_join_request req; - unsigned long flags; - int i; - struct hfa384x_hostscan_result *entry; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(req.bssid, local->preferred_ap, ETH_ALEN); - req.channel = 0; - - spin_lock_irqsave(&local->lock, flags); - for (i = 0; i < local->last_scan_results_count; i++) { - if (!local->last_scan_results) - break; - entry = &local->last_scan_results[i]; - if (ether_addr_equal(local->preferred_ap, entry->bssid)) { - req.channel = entry->chid; - break; - } - } - spin_unlock_irqrestore(&local->lock, flags); - - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", - dev->name, local->preferred_ap); - return -1; - } - - printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", - dev->name, local->preferred_ap); - - return 0; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); - - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { - struct hfa384x_scan_request scan_req; - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, - &scan_req, sizeof(scan_req))) { - printk(KERN_DEBUG "%s: ScanResults request failed - " - "preferred AP delayed to next unsolicited " - "scan\n", dev->name); - } - } else if (local->host_roaming == 2 && - local->iw_mode == IW_MODE_INFRA) { - if (hostap_join_ap(dev)) - return -EINVAL; - } else { - printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " - "in Managed mode when host_roaming is enabled\n", - dev->name); - } - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - -static int prism2_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - ap_addr->sa_family = ARPHRD_ETHER; - switch (iface->type) { - case HOSTAP_INTERFACE_AP: - memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_STA: - memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_WDS: - memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); - break; - default: - if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, - &ap_addr->sa_data, ETH_ALEN, 1) < 0) - return -EOPNOTSUPP; - - /* local->bssid is also updated in LinkStatus handler when in - * station mode */ - memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); - break; - } - - return 0; -} - - -static int prism2_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memset(local->name, 0, sizeof(local->name)); - memcpy(local->name, nickname, data->length); - local->name_set = 1; - - if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int len; - char name[MAX_NAME_LEN + 3]; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, - &name, MAX_NAME_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) name); - if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) - return -EOPNOTSUPP; - - name[val + 2] = '\0'; - data->length = val + 1; - memcpy(nickname, name + 2, val + 1); - - return 0; -} - - -static int prism2_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* freq => chan. */ - if (freq->e == 1 && - freq->m / 100000 >= freq_list[0] && - freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { - int ch; - int fr = freq->m / 100000; - for (ch = 0; ch < FREQ_COUNT; ch++) { - if (fr == freq_list[ch]) { - freq->e = 0; - freq->m = ch + 1; - break; - } - } - } - - if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || - !(local->channel_mask & (1 << (freq->m - 1)))) - return -EINVAL; - - local->channel = freq->m; /* channel is used in prism2_setup_rids() */ - if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < - 0) - return -EINVAL; - - le16_to_cpus(&val); - if (val < 1 || val > FREQ_COUNT) - return -EINVAL; - - freq->m = freq_list[val - 1] * 100000; - freq->e = 1; - - return 0; -} - - -static void hostap_monitor_set_type(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - dev->type = ARPHRD_IEEE80211_PRISM; - } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { - dev->type = ARPHRD_IEEE80211_RADIOTAP; - } else { - dev->type = ARPHRD_IEEE80211; - } -} - - -static int prism2_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *ssid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - if (data->flags == 0) - ssid[0] = '\0'; /* ANY */ - - if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { - /* Setting SSID to empty string seems to kill the card in - * Host AP mode */ - printk(KERN_DEBUG "%s: Host AP mode does not support " - "'Any' essid\n", dev->name); - return -EINVAL; - } - - memcpy(local->essid, ssid, data->length); - local->essid[data->length] = '\0'; - - if ((!local->fw_ap && - hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) - || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - data->flags = 1; /* active */ - if (local->iw_mode == IW_MODE_MASTER) { - data->length = strlen(local->essid); - memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); - } else { - int len; - char ssid[MAX_SSID_LEN + 2]; - memset(ssid, 0, sizeof(ssid)); - len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, - &ssid, MAX_SSID_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) ssid); - if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { - return -EOPNOTSUPP; - } - data->length = val; - memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); - } - - return 0; -} - - -static int prism2_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct iw_range *range = (struct iw_range *) extra; - u8 rates[10]; - u16 val; - int i, len, over2; - - iface = netdev_priv(dev); - local = iface->local; - - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - /* TODO: could fill num_txpower and txpower array with - * something; however, there are 128 different values.. */ - - range->txpower_capa = IW_TXPOW_DBM; - - if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = FREQ_COUNT; - - val = 0; - for (i = 0; i < FREQ_COUNT; i++) { - if (local->channel_mask & (1 << i)) { - range->freq[val].i = i + 1; - range->freq[val].m = freq_list[i] * 100000; - range->freq[val].e = 1; - val++; - } - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - range->max_qual.qual = 70; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - } else { - range->max_qual.qual = 92; /* 0 .. 92 */ - range->max_qual.level = 154; /* 27 .. 154 */ - range->max_qual.noise = 154; /* 27 .. 154 */ - } - range->sensitivity = 3; - - range->max_encoding_tokens = WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - over2 = 0; - len = prism2_get_datarates(dev, rates); - range->num_bitrates = 0; - for (i = 0; i < len; i++) { - if (range->num_bitrates < IW_MAX_BITRATES) { - range->bitrate[range->num_bitrates] = - rates[i] * 500000; - range->num_bitrates++; - } - if (rates[i] == 0x0b || rates[i] == 0x16) - over2 = 1; - } - /* estimated maximum TCP throughput values (bps) */ - range->throughput = over2 ? 5500000 : 1500000; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | - IW_EVENT_CAPA_MASK(IWEVCUSTOM) | - IW_EVENT_CAPA_MASK(IWEVREGISTERED) | - IW_EVENT_CAPA_MASK(IWEVEXPIRED)); - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - range->scan_capa = IW_SCAN_CAPA_ESSID; - - return 0; -} - - -static int hostap_monitor_mode_enable(local_info_t *local) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "Enabling monitor mode\n"); - hostap_monitor_set_type(local); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_PSEUDO_IBSS)) { - printk(KERN_DEBUG "Port type setting for monitor mode " - "failed\n"); - return -EOPNOTSUPP; - } - - /* Host decrypt is needed to get the IV and ICV fields; - * however, monitor mode seems to remove WEP flag from frame - * control field */ - if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, - HFA384X_WEPFLAGS_HOSTENCRYPT | - HFA384X_WEPFLAGS_HOSTDECRYPT)) { - printk(KERN_DEBUG "WEP flags setting failed\n"); - return -EOPNOTSUPP; - } - - if (local->func->reset_port(dev) || - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_MONITOR << 8), - 0, NULL, NULL)) { - printk(KERN_DEBUG "Setting monitor mode failed\n"); - return -EOPNOTSUPP; - } - - return 0; -} - - -static int hostap_monitor_mode_disable(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return -1; - - printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); - dev->type = ARPHRD_ETHER; - - if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_STOP << 8), - 0, NULL, NULL)) - return -1; - return hostap_set_encryption(local); -} - - -static int prism2_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - int double_reset = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && - *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && - *mode != IW_MODE_MONITOR) - return -EOPNOTSUPP; - -#ifdef PRISM2_NO_STATION_MODES - if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ - - if (*mode == local->iw_mode) - return 0; - - if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { - printk(KERN_WARNING "%s: empty SSID not allowed in Master " - "mode\n", dev->name); - return -EINVAL; - } - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_disable(local); - - if ((local->iw_mode == IW_MODE_ADHOC || - local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) { - /* There seems to be a firmware bug in at least STA f/w v1.5.6 - * that leaves beacon frames to use IBSS type when moving from - * IBSS to Host AP mode. Doing double Port0 reset seems to be - * enough to workaround this. */ - double_reset = 1; - } - - printk(KERN_DEBUG "prism2: %s: operating mode changed " - "%d -> %d\n", dev->name, local->iw_mode, *mode); - local->iw_mode = *mode; - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_enable(local); - else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - dev->name); - local->host_encrypt = 1; - } - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) - return -EOPNOTSUPP; - - if (local->func->reset_port(dev)) - return -EINVAL; - if (double_reset && local->func->reset_port(dev)) - return -EINVAL; - - if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) - { - /* netif_carrier is used only in client modes for now, so make - * sure carrier is on when moving to non-client modes. */ - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - } - return 0; -} - - -static int prism2_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - switch (iface->type) { - case HOSTAP_INTERFACE_STA: - *mode = IW_MODE_INFRA; - break; - case HOSTAP_INTERFACE_WDS: - *mode = IW_MODE_REPEAT; - break; - default: - *mode = local->iw_mode; - break; - } - return 0; -} - - -static int prism2_ioctl_siwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *wrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - int ret = 0; - - if (wrq->disabled) - return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ALL_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ON: - break; - default: - return -EINVAL; - } - - if (wrq->flags & IW_POWER_TIMEOUT) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - if (wrq->flags & IW_POWER_PERIOD) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - - return ret; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - __le16 enable, mcast; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) - < 0) - return -EINVAL; - - if (!le16_to_cpu(enable)) { - rrq->disabled = 1; - return 0; - } - - rrq->disabled = 0; - - if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - __le16 timeout; - if (local->func->get_rid(dev, - HFA384X_RID_CNFPMHOLDOVERDURATION, - &timeout, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_TIMEOUT; - rrq->value = le16_to_cpu(timeout) * 1024; - } else { - __le16 period; - if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - &period, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_PERIOD; - rrq->value = le16_to_cpu(period) * 1024; - } - - if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, - 2, 1) < 0) - return -EINVAL; - - if (le16_to_cpu(mcast)) - rrq->flags |= IW_POWER_ALL_R; - else - rrq->flags |= IW_POWER_UNICAST_R; - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) - return -EINVAL; - - /* setting retry limits is not supported with the current station - * firmware code; simulate this with alternative retry count for now */ - if (rrq->flags == IW_RETRY_LIMIT) { - if (rrq->value < 0) { - /* disable manual retry count setting and use firmware - * defaults */ - local->manual_retry_count = -1; - local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; - } else { - if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - rrq->value)) { - printk(KERN_DEBUG "%s: Alternate retry count " - "setting to %d failed\n", - dev->name, rrq->value); - return -EOPNOTSUPP; - } - - local->manual_retry_count = rrq->value; - local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; - } - return 0; - } - - return -EOPNOTSUPP; - -#if 0 - /* what could be done, if firmware would support this.. */ - - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_LONG) - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - else if (rrq->flags & IW_RETRY_SHORT) - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - else { - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - } - - } - - if (rrq->flags & IW_RETRY_LIFETIME) { - HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; - } - - return 0; -#endif /* 0 */ -} - -static int prism2_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - __le16 shortretry, longretry, lifetime, altretry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, - &lifetime, 2, 1) < 0) - return -EINVAL; - - rrq->disabled = 0; - - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = le16_to_cpu(lifetime) * 1024; - } else { - if (local->manual_retry_count >= 0) { - rrq->flags = IW_RETRY_LIMIT; - if (local->func->get_rid(dev, - HFA384X_RID_CNFALTRETRYCOUNT, - &altretry, 2, 1) >= 0) - rrq->value = le16_to_cpu(altretry); - else - rrq->value = local->manual_retry_count; - } else if ((rrq->flags & IW_RETRY_LONG)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - rrq->value = le16_to_cpu(longretry); - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = le16_to_cpu(shortretry); - if (shortretry != longretry) - rrq->flags |= IW_RETRY_SHORT; - } - } - return 0; -} - - -/* Note! This TX power controlling is experimental and should not be used in - * production use. It just sets raw power register and does not use any kind of - * feedback information from the measured TX power (CR58). This is now - * commented out to make sure that it is not used by accident. TX power - * configuration will be enabled again after proper algorithm using feedback - * has been implemented. */ - -#ifdef RAW_TXPOWER_SETTING -/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. - * This version assumes following mapping: - * CR31 is 7-bit value with -64 to +63 range. - * -64 is mapped into +20dBm and +63 into -43dBm. - * This is certainly not an exact mapping for every card, but at least - * increasing dBm value should correspond to increasing TX power. - */ - -static int prism2_txpower_hfa386x_to_dBm(u16 val) -{ - signed char tmp; - - if (val > 255) - val = 255; - - tmp = val; - tmp >>= 2; - - return -12 - tmp; -} - -static u16 prism2_txpower_dBm_to_hfa386x(int val) -{ - signed char tmp; - - if (val > 20) - return 128; - else if (val < -43) - return 127; - - tmp = val; - tmp = -12 - tmp; - tmp <<= 2; - - return (unsigned char) tmp; -} -#endif /* RAW_TXPOWER_SETTING */ - - -static int prism2_ioctl_siwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; -#ifdef RAW_TXPOWER_SETTING - char *tmp; -#endif - u16 val; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) { - if (local->txpower_type != PRISM2_TXPOWER_OFF) { - val = 0xff; /* use all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, - &val, NULL); - printk(KERN_DEBUG "%s: Turning radio off: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_OFF; - } - return (ret ? -EOPNOTSUPP : 0); - } - - if (local->txpower_type == PRISM2_TXPOWER_OFF) { - val = 0; /* disable all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, &val, NULL); - printk(KERN_DEBUG "%s: Turning radio on: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_UNKNOWN; - } - -#ifdef RAW_TXPOWER_SETTING - if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { - printk(KERN_DEBUG "Setting ALC on\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_AUTO; - return 0; - } - - if (local->txpower_type != PRISM2_TXPOWER_FIXED) { - printk(KERN_DEBUG "Setting ALC off\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_FIXED; - } - - if (rrq->flags == IW_TXPOW_DBM) - tmp = "dBm"; - else if (rrq->flags == IW_TXPOW_MWATT) - tmp = "mW"; - else - tmp = "UNKNOWN"; - printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); - - if (rrq->flags != IW_TXPOW_DBM) { - printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); - return -EOPNOTSUPP; - } - - local->txpower = rrq->value; - val = prism2_txpower_dBm_to_hfa386x(local->txpower); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) - ret = -EOPNOTSUPP; -#else /* RAW_TXPOWER_SETTING */ - if (rrq->fixed) - ret = -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ - - return ret; -} - -static int prism2_ioctl_giwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ -#ifdef RAW_TXPOWER_SETTING - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - rrq->flags = IW_TXPOW_DBM; - rrq->disabled = 0; - rrq->fixed = 0; - - if (local->txpower_type == PRISM2_TXPOWER_AUTO) { - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_MANUAL_TX_POWER, - NULL, &resp0) == 0) { - rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); - } else { - /* Could not get real txpower; guess 15 dBm */ - rrq->value = 15; - } - } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { - rrq->value = 0; - rrq->disabled = 1; - } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { - rrq->value = local->txpower; - rrq->fixed = 1; - } else { - printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", - local->txpower_type); - } - return 0; -#else /* RAW_TXPOWER_SETTING */ - return -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ -} - - -#ifndef PRISM2_NO_STATION_MODES - -/* HostScan request works with and without host_roaming mode. In addition, it - * does not break current association. However, it requires newer station - * firmware version (>= 1.3.1) than scan request. */ -static int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_hostscan_request scan_req; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (ssid) { - if (ssid_len > 32) - return -EINVAL; - scan_req.target_ssid_len = cpu_to_le16(ssid_len); - memcpy(scan_req.target_ssid, ssid, ssid_len); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); - return -EINVAL; - } - return 0; -} - - -static int prism2_request_scan(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_scan_request scan_req; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - - /* FIX: - * It seems to be enough to set roaming mode for a short moment to - * host-based and then setup scanrequest data and return the mode to - * firmware-based. - * - * Master mode would need to drop to Managed mode for a short while - * to make scanning work.. Or sweep through the different channels and - * use passive scan based on beacons. */ - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_HOST); - - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "SCANREQUEST failed\n"); - ret = -EINVAL; - } - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_FIRMWARE); - - return ret; -} - -#else /* !PRISM2_NO_STATION_MODES */ - -static inline int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - return -EOPNOTSUPP; -} - - -static inline int prism2_request_scan(struct net_device *dev) -{ - return -EOPNOTSUPP; -} - -#endif /* !PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int ret; - u8 *ssid = NULL, ssid_len = 0; - struct iw_scan_req *req = (struct iw_scan_req *) extra; - - iface = netdev_priv(dev); - local = iface->local; - - if (data->length < sizeof(struct iw_scan_req)) - req = NULL; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In master mode, we just return the results of our local - * tables, so we don't need to start anything... - * Jean II */ - data->length = 0; - return 0; - } - - if (!local->dev_enabled) - return -ENETDOWN; - - if (req && data->flags & IW_SCAN_THIS_ESSID) { - ssid = req->essid; - ssid_len = req->essid_len; - - if (ssid_len && - ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) - return -EOPNOTSUPP; - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - ret = prism2_request_hostscan(dev, ssid, ssid_len); - else - ret = prism2_request_scan(dev); - - if (ret == 0) - local->scan_timestamp = jiffies; - - /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ - - return ret; -} - - -#ifndef PRISM2_NO_STATION_MODES -static char * __prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - struct hfa384x_hostscan_result *scan, - struct hostap_bss_info *bss, - char *current_ev, char *end_buf) -{ - int i, chan; - struct iw_event iwe; - char *current_val; - u16 capabilities; - u8 *pos; - u8 *ssid, *bssid; - size_t ssid_len; - char *buf; - - if (bss) { - ssid = bss->ssid; - ssid_len = bss->ssid_len; - bssid = bss->bssid; - } else { - ssid = scan->ssid; - ssid_len = le16_to_cpu(scan->ssid_len); - bssid = scan->bssid; - } - if (ssid_len > 32) - ssid_len = 32; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (bss) { - capabilities = bss->capab_info; - } else { - capabilities = le16_to_cpu(scan->capability); - } - if (capabilities & (WLAN_CAPABILITY_ESS | - WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (scan) { - chan = le16_to_cpu(scan->chid); - } else if (bss) { - chan = bss->chan; - } else { - chan = 0; - } - - if (chan > 0) { - iwe.u.freq.m = freq_list[chan - 1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (local->last_scan_type == PRISM2_HOSTSCAN) { - iwe.u.qual.level = le16_to_cpu(scan->sl); - iwe.u.qual.noise = le16_to_cpu(scan->anl); - } else { - iwe.u.qual.level = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); - iwe.u.qual.noise = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); - } - iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID - | IW_QUAL_DBM; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); - - /* TODO: add SuppRates into BSS table */ - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + iwe_stream_lcp_len(info); - pos = scan->sup_rates; - for (i = 0; i < sizeof(scan->sup_rates); i++) { - if (pos[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value( - info, current_ev, current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); - if (buf && scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - if (local->last_scan_type == PRISM2_HOSTSCAN && - (capabilities & WLAN_CAPABILITY_IBSS)) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } - } - kfree(buf); - - if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->wpa_ie); - } - - if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->rsn_ie); - } - - return current_ev; -} - - -/* Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II */ -static inline int prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - char *buffer, int buflen) -{ - struct hfa384x_hostscan_result *scan; - int entry; - char *current_ev = buffer; - char *end_buf = buffer + buflen; - struct list_head *ptr; - - spin_lock_bh(&local->lock); - - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - bss->included = 0; - } - - for (entry = 0; entry < local->last_scan_results_count; entry++) { - int found = 0; - scan = &local->last_scan_results[entry]; - - /* Report every SSID if the AP is using multiple SSIDs. If no - * BSS record is found (e.g., when WPA mode is disabled), - * report the AP once. */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (ether_addr_equal(bss->bssid, scan->bssid)) { - bss->included = 1; - current_ev = __prism2_translate_scan( - local, info, scan, bss, current_ev, - end_buf); - found++; - } - } - if (!found) { - current_ev = __prism2_translate_scan( - local, info, scan, NULL, current_ev, end_buf); - } - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - /* Prism2 firmware has limits (32 at least in some versions) for number - * of BSSes in scan results. Extend this limit by using local BSS list. - */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (bss->included) - continue; - current_ev = __prism2_translate_scan(local, info, NULL, bss, - current_ev, end_buf); - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - spin_unlock_bh(&local->lock); - - return current_ev - buffer; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* Wait until the scan is finished. We can probably do better - * than that - Jean II */ - if (local->scan_timestamp && - time_before(jiffies, local->scan_timestamp + 3 * HZ)) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy - * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before coming - * here (in dev_ioctl()). - * Third, the caller can wait on the Wireless Event - * - Jean II */ - return -EAGAIN; - } - local->scan_timestamp = 0; - - res = prism2_translate_scan(local, info, extra, data->length); - - if (res >= 0) { - data->length = res; - return 0; - } else { - data->length = 0; - return res; - } -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In MASTER mode, it doesn't make sense to go around - * scanning the frequencies and make the stations we serve - * wait when what the user is really interested about is the - * list of stations and access points we are talking to. - * So, just extract results from our cache... - * Jean II */ - - /* Translate to WE format */ - res = prism2_ap_translate_scan(dev, info, extra); - if (res >= 0) { - printk(KERN_DEBUG "Scan result translation succeeded " - "(length=%d)\n", res); - data->length = res; - return 0; - } else { - printk(KERN_DEBUG - "Scan result translation failed (res=%d)\n", - res); - data->length = 0; - return res; - } - } else { - /* Station mode */ - return prism2_ioctl_giwscan_sta(dev, info, data, extra); - } -} - - -static const struct iw_priv_args prism2_priv[] = { - { PRISM2_IOCTL_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, - { PRISM2_IOCTL_READMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, - { PRISM2_IOCTL_WRITEMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, - { PRISM2_IOCTL_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, - { PRISM2_IOCTL_INQUIRE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, - { PRISM2_IOCTL_SET_RID_WORD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, - { PRISM2_IOCTL_MACCMD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, - { PRISM2_IOCTL_WDS_ADD, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, - { PRISM2_IOCTL_WDS_DEL, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, - { PRISM2_IOCTL_ADDMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, - { PRISM2_IOCTL_DELMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, - { PRISM2_IOCTL_KICKMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, - /* --- raw access to sub-ioctls --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, - /* --- sub-ioctls handlers --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, - /* --- sub-ioctls definitions --- */ - { PRISM2_PARAM_TXRATECTRL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, - { PRISM2_PARAM_TXRATECTRL, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, - { PRISM2_PARAM_BEACON_INT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, - { PRISM2_PARAM_BEACON_INT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_PSEUDO_IBSS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, - { PRISM2_PARAM_PSEUDO_IBSS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_ALC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, - { PRISM2_PARAM_ALC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, - { PRISM2_PARAM_DUMP, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, - { PRISM2_PARAM_DUMP, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, - { PRISM2_PARAM_DTIM_PERIOD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, - { PRISM2_PARAM_DTIM_PERIOD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, - { PRISM2_PARAM_MAX_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, - { PRISM2_PARAM_MAX_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, - { PRISM2_PARAM_HOST_ENCRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, - { PRISM2_PARAM_HOST_ENCRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_HOST_ROAMING, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, - { PRISM2_PARAM_HOST_ROAMING, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_BCRX_STA_KEY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, - { PRISM2_PARAM_BCRX_STA_KEY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, - { PRISM2_PARAM_IEEE_802_1X, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, - { PRISM2_PARAM_IEEE_802_1X, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, - { PRISM2_PARAM_ANTSEL_TX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, - { PRISM2_PARAM_ANTSEL_TX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, - { PRISM2_PARAM_ANTSEL_RX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, - { PRISM2_PARAM_ANTSEL_RX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, - { PRISM2_PARAM_MONITOR_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, - { PRISM2_PARAM_MONITOR_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, - { PRISM2_PARAM_WDS_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, - { PRISM2_PARAM_WDS_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, - { PRISM2_PARAM_HOSTSCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, - { PRISM2_PARAM_HOSTSCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, - { PRISM2_PARAM_AP_SCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, - { PRISM2_PARAM_AP_SCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, - { PRISM2_PARAM_ENH_SEC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, - { PRISM2_PARAM_ENH_SEC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, -#ifdef PRISM2_IO_DEBUG - { PRISM2_PARAM_IO_DEBUG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, - { PRISM2_PARAM_IO_DEBUG, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, -#endif /* PRISM2_IO_DEBUG */ - { PRISM2_PARAM_BASIC_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, - { PRISM2_PARAM_BASIC_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, - { PRISM2_PARAM_OPER_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, - { PRISM2_PARAM_OPER_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, - { PRISM2_PARAM_HOSTAPD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, - { PRISM2_PARAM_HOSTAPD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, - { PRISM2_PARAM_HOSTAPD_STA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, - { PRISM2_PARAM_HOSTAPD_STA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, - { PRISM2_PARAM_WPA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, - { PRISM2_PARAM_WPA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" }, -}; - - -static int prism2_ioctl_priv_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *i = (int *) extra; - int param = *i; - int value = *(i + 1); - int ret = 0; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - switch (param) { - case PRISM2_PARAM_TXRATECTRL: - local->fw_tx_rate_control = value; - break; - - case PRISM2_PARAM_BEACON_INT: - if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || - local->func->reset_port(dev)) - ret = -EINVAL; - else - local->beacon_int = value; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_PSEUDO_IBSS: - if (value == local->pseudo_adhoc) - break; - - if (value != 0 && value != 1) { - ret = -EINVAL; - break; - } - - printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", - dev->name, local->pseudo_adhoc, value); - local->pseudo_adhoc = value; - if (local->iw_mode != IW_MODE_ADHOC) - break; - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) { - ret = -EOPNOTSUPP; - break; - } - - if (local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_ALC: - printk(KERN_DEBUG "%s: %s ALC\n", dev->name, - value == 0 ? "Disabling" : "Enabling"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), - value == 0 ? 0 : 1, &val, NULL); - break; - - case PRISM2_PARAM_DUMP: - local->frame_dump = value; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->ap_policy = value; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (value < 0 || value > 7 * 24 * 60 * 60) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->max_inactivity = value * HZ; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - local->ap->bridge_packets = value; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - if (value < 0 || value > 65535) { - ret = -EINVAL; - break; - } - if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) - || local->func->reset_port(dev)) - ret = -EINVAL; - else - local->dtim_period = value; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - local->ap->nullfunc_ack = value; - break; - - case PRISM2_PARAM_MAX_WDS: - local->wds_max_connections = value; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) { - if (!local->ap->autom_ap_wds && value) { - /* add WDS link to all APs in STA table */ - hostap_add_wds_links(local); - } - local->ap->autom_ap_wds = value; - } - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - local->auth_algs = value; - if (hostap_set_auth_algs(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - local->monitor_allow_fcserr = value; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - local->host_encrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - local->host_decrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_HOST_ROAMING: - if (value < 0 || value > 2) { - ret = -EINVAL; - break; - } - local->host_roaming = value; - if (hostap_set_roaming(local) || local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_BCRX_STA_KEY: - local->bcrx_sta_key = value; - break; - - case PRISM2_PARAM_IEEE_802_1X: - local->ieee_802_1x = value; - break; - - case PRISM2_PARAM_ANTSEL_TX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_tx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_ANTSEL_RX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_rx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_MONITOR_TYPE: - if (value != PRISM2_MONITOR_80211 && - value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM && - value != PRISM2_MONITOR_RADIOTAP) { - ret = -EINVAL; - break; - } - local->monitor_type = value; - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_set_type(local); - break; - - case PRISM2_PARAM_WDS_TYPE: - local->wds_type = value; - break; - - case PRISM2_PARAM_HOSTSCAN: - { - struct hfa384x_hostscan_request scan_req; - u16 rate; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - switch (value) { - case 1: rate = HFA384X_RATES_1MBPS; break; - case 2: rate = HFA384X_RATES_2MBPS; break; - case 3: rate = HFA384X_RATES_5MBPS; break; - case 4: rate = HFA384X_RATES_11MBPS; break; - default: rate = HFA384X_RATES_1MBPS; break; - } - scan_req.txrate = cpu_to_le16(rate); - /* leave SSID empty to accept all SSIDs */ - - if (local->iw_mode == IW_MODE_MASTER) { - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_BSS) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Leaving Host AP mode " - "for HostScan failed\n"); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "HOSTSCAN failed\n"); - ret = -EINVAL; - } - if (local->iw_mode == IW_MODE_MASTER) { - wait_queue_entry_t __wait; - init_waitqueue_entry(&__wait, current); - add_wait_queue(&local->hostscan_wq, &__wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - if (signal_pending(current)) - ret = -EINTR; - set_current_state(TASK_RUNNING); - remove_wait_queue(&local->hostscan_wq, &__wait); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_HOSTAP) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Returning to Host AP mode " - "after HostScan failed\n"); - } - break; - } - - case PRISM2_PARAM_AP_SCAN: - local->passive_scan_interval = value; - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - if (value > 0 && value < INT_MAX / HZ) { - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - add_timer(&local->passive_scan_timer); - } - break; - - case PRISM2_PARAM_ENH_SEC: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - local->enh_sec = value; - if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, - local->enh_sec) || - local->func->reset_port(dev)) { - printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " - "1.6.3 or newer\n", dev->name); - ret = -EOPNOTSUPP; - } - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - local->io_debug_enabled = value; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - if ((value & local->tx_rate_control) != value || value == 0) { - printk(KERN_INFO "%s: invalid basic rate set - basic " - "rates must be in supported rate set\n", - dev->name); - ret = -EINVAL; - break; - } - local->basic_rates = value; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_OPER_RATES: - local->tx_rate_control = value; - if (hostap_set_rate(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOSTAPD: - ret = hostap_set_hostapd(local, value, 1); - break; - - case PRISM2_PARAM_HOSTAPD_STA: - ret = hostap_set_hostapd_sta(local, value, 1); - break; - - case PRISM2_PARAM_WPA: - local->wpa = value; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - value ? 1 : 0)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - local->privacy_invoked = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = value; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - local->drop_unencrypted = value; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - local->scan_channel_mask = value; - break; - - default: - printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", - dev->name, param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *param = (int *) extra; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - switch (*param) { - case PRISM2_PARAM_TXRATECTRL: - *param = local->fw_tx_rate_control; - break; - - case PRISM2_PARAM_BEACON_INT: - *param = local->beacon_int; - break; - - case PRISM2_PARAM_PSEUDO_IBSS: - *param = local->pseudo_adhoc; - break; - - case PRISM2_PARAM_ALC: - ret = -EOPNOTSUPP; /* FIX */ - break; - - case PRISM2_PARAM_DUMP: - *param = local->frame_dump; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (local->ap != NULL) - *param = local->ap->ap_policy; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (local->ap != NULL) - *param = local->ap->max_inactivity / HZ; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - *param = local->ap->bridge_packets; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - *param = local->dtim_period; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - *param = local->ap->nullfunc_ack; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_MAX_WDS: - *param = local->wds_max_connections; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) - *param = local->ap->autom_ap_wds; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - *param = local->auth_algs; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - *param = local->monitor_allow_fcserr; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - *param = local->host_encrypt; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - *param = local->host_decrypt; - break; - - case PRISM2_PARAM_HOST_ROAMING: - *param = local->host_roaming; - break; - - case PRISM2_PARAM_BCRX_STA_KEY: - *param = local->bcrx_sta_key; - break; - - case PRISM2_PARAM_IEEE_802_1X: - *param = local->ieee_802_1x; - break; - - case PRISM2_PARAM_ANTSEL_TX: - *param = local->antsel_tx; - break; - - case PRISM2_PARAM_ANTSEL_RX: - *param = local->antsel_rx; - break; - - case PRISM2_PARAM_MONITOR_TYPE: - *param = local->monitor_type; - break; - - case PRISM2_PARAM_WDS_TYPE: - *param = local->wds_type; - break; - - case PRISM2_PARAM_HOSTSCAN: - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_SCAN: - *param = local->passive_scan_interval; - break; - - case PRISM2_PARAM_ENH_SEC: - *param = local->enh_sec; - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - *param = local->io_debug_enabled; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - *param = local->basic_rates; - break; - - case PRISM2_PARAM_OPER_RATES: - *param = local->tx_rate_control; - break; - - case PRISM2_PARAM_HOSTAPD: - *param = local->hostapd; - break; - - case PRISM2_PARAM_HOSTAPD_STA: - *param = local->hostapd_sta; - break; - - case PRISM2_PARAM_WPA: - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - *param = local->wpa; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - *param = local->privacy_invoked; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - *param = local->tkip_countermeasures; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - *param = local->drop_unencrypted; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - *param = local->scan_channel_mask; - break; - - default: - printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", - dev->name, *param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_readmif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, - &resp0)) - return -EOPNOTSUPP; - else - *extra = resp0; - - return 0; -} - - -static int prism2_ioctl_priv_writemif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 cr, val; - - iface = netdev_priv(dev); - local = iface->local; - - cr = *extra; - val = *(extra + 1); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) - return -EOPNOTSUPP; - - return 0; -} - - -#ifdef PRISM2_DOWNLOAD_SUPPORT -static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) -{ - struct prism2_download_param *param; - int ret = 0; - - if (p->length < sizeof(struct prism2_download_param) || - p->length > 1024 || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - if (p->length < sizeof(struct prism2_download_param) + - param->num_areas * sizeof(struct prism2_download_area)) { - ret = -EINVAL; - goto out; - } - - ret = local->func->download(local, param); - - out: - kfree(param); - return ret; -} -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - -static int prism2_set_genericelement(struct net_device *dev, u8 *elem, - size_t len) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - u8 *buf; - - /* - * Add 16-bit length in the beginning of the buffer because Prism2 RID - * includes it. - */ - buf = kmalloc(len + 2, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - *((__le16 *) buf) = cpu_to_le16(len); - memcpy(buf + 2, elem, len); - - kfree(local->generic_elem); - local->generic_elem = buf; - local->generic_elem_len = len + 2; - - return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, - buf, len + 2); -} - - -static int prism2_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = data->value; - break; - case IW_AUTH_DROP_UNENCRYPTED: - local->drop_unencrypted = data->value; - break; - case IW_AUTH_80211_AUTH_ALG: - local->auth_algs = data->value; - break; - case IW_AUTH_WPA_ENABLED: - if (data->value == 0) { - local->wpa = 0; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - break; - prism2_set_genericelement(dev, "", 0); - local->host_roaming = 0; - local->privacy_invoked = 0; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - 0) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - } - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - return -EOPNOTSUPP; - local->host_roaming = 2; - local->privacy_invoked = 1; - local->wpa = 1; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - local->ieee_802_1x = data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - local->privacy_invoked = data->value; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - return -EOPNOTSUPP; - case IW_AUTH_TKIP_COUNTERMEASURES: - data->value = local->tkip_countermeasures; - break; - case IW_AUTH_DROP_UNENCRYPTED: - data->value = local->drop_unencrypted; - break; - case IW_AUTH_80211_AUTH_ALG: - data->value = local->auth_algs; - break; - case IW_AUTH_WPA_ENABLED: - data->value = local->wpa; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - data->value = local->ieee_802_1x; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int i, ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - u8 *addr; - const char *alg, *module; - - i = erq->flags & IW_ENCODE_INDEX; - if (i > WEP_KEYS) - return -EINVAL; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - if (i != 0) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) { - if (local->iw_mode == IW_MODE_INFRA) { - /* - * TODO: add STA entry for the current AP so - * that unicast key can be used. For now, this - * is emulated by using default key idx 0. - */ - i = 0; - crypt = &local->crypt_info.crypt[i]; - } else - return -EINVAL; - } - } - - if ((erq->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - switch (ext->alg) { - case IW_ENCODE_ALG_WEP: - alg = "WEP"; - module = "lib80211_crypt_wep"; - break; - case IW_ENCODE_ALG_TKIP: - alg = "TKIP"; - module = "lib80211_crypt_tkip"; - break; - case IW_ENCODE_ALG_CCMP: - alg = "CCMP"; - module = "lib80211_crypt_ccmp"; - break; - default: - printk(KERN_DEBUG "%s: unsupported algorithm %d\n", - local->dev->name, ext->alg); - ret = -EOPNOTSUPP; - goto done; - } - - ops = lib80211_get_crypto_ops(alg); - if (ops == NULL) { - request_module(module); - ops = lib80211_get_crypto_ops(alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, alg); - ret = -EOPNOTSUPP; - goto done; - } - - if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { - /* - * Per station encryption and other than WEP algorithms - * require host-based encryption, so force them on - * automatically. - */ - local->host_decrypt = local->host_encrypt = 1; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - /* - * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the - * existing seq# should not be changed. - * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# - * should be changed to something else than zero. - */ - if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) - && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - ret = -EINVAL; - goto done; - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = i; - } - - - if (sta_ptr == NULL && ext->key_len > 0) { - int first = 1, j; - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - /* - * Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. - */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) - ret = -EINVAL; - - return ret; -} - - -static int prism2_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len, i; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - u8 *addr; - - max_key_len = erq->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - i = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) - return -EINVAL; - } - erq->flags = i + 1; - memset(ext, 0, sizeof(*ext)); - - if (*crypt == NULL || (*crypt)->ops == NULL) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - erq->flags |= IW_ENCODE_DISABLED; - } else { - if (strcmp((*crypt)->ops->name, "WEP") == 0) - ext->alg = IW_ENCODE_ALG_WEP; - else if (strcmp((*crypt)->ops->name, "TKIP") == 0) - ext->alg = IW_ENCODE_ALG_TKIP; - else if (strcmp((*crypt)->ops->name, "CCMP") == 0) - ext->alg = IW_ENCODE_ALG_CCMP; - else - return -EINVAL; - - if ((*crypt)->ops->get_key) { - ext->key_len = - (*crypt)->ops->get_key(ext->key, - max_key_len, - ext->tx_seq, - (*crypt)->priv); - if (ext->key_len && - (ext->alg == IW_ENCODE_ALG_TKIP || - ext->alg == IW_ENCODE_ALG_CCMP)) - ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_set_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - - param->u.crypt.err = 0; - param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int) ((char *) param->u.crypt.key - (char *) param) + - param->u.crypt.key_len) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - if (param->u.crypt.idx) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs( - local->ap, param->sta_addr, - (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("lib80211_crypt_wep"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("lib80211_crypt_tkip"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("lib80211_crypt_ccmp"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, param->u.crypt.alg); - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - /* station based encryption and other than WEP algorithms require - * host-based encryption, so force them on automatically */ - local->host_decrypt = local->host_encrypt = 1; - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || - param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = param->u.crypt.idx; - else if (param->u.crypt.idx) { - printk(KERN_DEBUG "%s: TX key idx setting failed\n", - local->dev->name); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - - -static int prism2_ioctl_get_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len; - - param->u.crypt.err = 0; - - max_key_len = param_len - - (int) ((char *) param->u.crypt.key - (char *) param); - if (max_key_len < 0) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - sta_ptr = NULL; - if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->crypt_info.tx_keyidx; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - param->u.crypt.idx = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (*crypt == NULL || (*crypt)->ops == NULL) { - memcpy(param->u.crypt.alg, "none", 5); - param->u.crypt.key_len = 0; - param->u.crypt.idx = 0xff; - } else { - strscpy(param->u.crypt.alg, (*crypt)->ops->name, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.key_len = 0; - - memset(param->u.crypt.seq, 0, 8); - if ((*crypt)->ops->get_key) { - param->u.crypt.key_len = - (*crypt)->ops->get_key(param->u.crypt.key, - max_key_len, - param->u.crypt.seq, - (*crypt)->priv); - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_get_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, res; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0) - return -EINVAL; - - res = local->func->get_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len, 0); - if (res >= 0) { - param->u.rid.len = res; - return 0; - } - - return res; -} - - -static int prism2_ioctl_set_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0 || max_len < param->u.rid.len) - return -EINVAL; - - return local->func->set_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len); -} - - -static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", - local->dev->name, param->sta_addr); - memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); - return 0; -} - - -static int prism2_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - return prism2_set_genericelement(dev, extra, data->length); -} - - -static int prism2_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - int len = local->generic_elem_len - 2; - - if (len <= 0 || local->generic_elem == NULL) { - data->length = 0; - return 0; - } - - if (data->length < len) - return -E2BIG; - - data->length = len; - memcpy(extra, local->generic_elem + 2, len); - - return 0; -} - - -static int prism2_ioctl_set_generic_element(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, len; - - len = param->u.generic_elem.len; - max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (max_len < 0 || max_len < len) - return -EINVAL; - - return prism2_set_genericelement(local->dev, - param->u.generic_elem.data, len); -} - - -static int prism2_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case IW_MLME_DISASSOC: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_mlme(local_info_t *local, - struct prism2_hostapd_param *param) -{ - __le16 reason; - - reason = cpu_to_le16(param->u.mlme.reason_code); - switch (param->u.mlme.cmd) { - case MLME_STA_DEAUTH: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case MLME_STA_DISASSOC: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_scan_req(local_info_t *local, - struct prism2_hostapd_param *param) -{ -#ifndef PRISM2_NO_STATION_MODES - if ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) - return -EOPNOTSUPP; - - if (!local->dev_enabled) - return -ENETDOWN; - - return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, - param->u.scan_req.ssid_len); -#else /* PRISM2_NO_STATION_MODES */ - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) -{ - struct prism2_hostapd_param *param; - int ret = 0; - int ap_ioctl = 0; - - if (p->length < sizeof(struct prism2_hostapd_param) || - p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - switch (param->cmd) { - case PRISM2_SET_ENCRYPTION: - ret = prism2_ioctl_set_encryption(local, param, p->length); - break; - case PRISM2_GET_ENCRYPTION: - ret = prism2_ioctl_get_encryption(local, param, p->length); - break; - case PRISM2_HOSTAPD_GET_RID: - ret = prism2_ioctl_get_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_RID: - ret = prism2_ioctl_set_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: - ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: - ret = prism2_ioctl_set_generic_element(local, param, - p->length); - break; - case PRISM2_HOSTAPD_MLME: - ret = prism2_ioctl_mlme(local, param); - break; - case PRISM2_HOSTAPD_SCAN_REQ: - ret = prism2_ioctl_scan_req(local, param); - break; - default: - ret = prism2_hostapd(local->ap, param); - ap_ioctl = 1; - break; - } - - if (ret == 1 || !ap_ioctl) { - if (copy_to_user(p->pointer, param, p->length)) { - ret = -EFAULT; - goto out; - } else if (ap_ioctl) - ret = 0; - } - - out: - kfree(param); - return ret; -} - - -static void prism2_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - strscpy(info->driver, "hostap", sizeof(info->driver)); - snprintf(info->fw_version, sizeof(info->fw_version), - "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, - (local->sta_fw_ver >> 8) & 0xff, - local->sta_fw_ver & 0xff); -} - -const struct ethtool_ops prism2_ethtool_ops = { - .get_drvinfo = prism2_get_drvinfo -}; - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler prism2_handler[] = -{ - IW_HANDLER(SIOCGIWNAME, prism2_get_name), - IW_HANDLER(SIOCSIWFREQ, prism2_ioctl_siwfreq), - IW_HANDLER(SIOCGIWFREQ, prism2_ioctl_giwfreq), - IW_HANDLER(SIOCSIWMODE, prism2_ioctl_siwmode), - IW_HANDLER(SIOCGIWMODE, prism2_ioctl_giwmode), - IW_HANDLER(SIOCSIWSENS, prism2_ioctl_siwsens), - IW_HANDLER(SIOCGIWSENS, prism2_ioctl_giwsens), - IW_HANDLER(SIOCGIWRANGE, prism2_ioctl_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, prism2_ioctl_siwap), - IW_HANDLER(SIOCGIWAP, prism2_ioctl_giwap), - IW_HANDLER(SIOCSIWMLME, prism2_ioctl_siwmlme), - IW_HANDLER(SIOCGIWAPLIST, prism2_ioctl_giwaplist), - IW_HANDLER(SIOCSIWSCAN, prism2_ioctl_siwscan), - IW_HANDLER(SIOCGIWSCAN, prism2_ioctl_giwscan), - IW_HANDLER(SIOCSIWESSID, prism2_ioctl_siwessid), - IW_HANDLER(SIOCGIWESSID, prism2_ioctl_giwessid), - IW_HANDLER(SIOCSIWNICKN, prism2_ioctl_siwnickn), - IW_HANDLER(SIOCGIWNICKN, prism2_ioctl_giwnickn), - IW_HANDLER(SIOCSIWRATE, prism2_ioctl_siwrate), - IW_HANDLER(SIOCGIWRATE, prism2_ioctl_giwrate), - IW_HANDLER(SIOCSIWRTS, prism2_ioctl_siwrts), - IW_HANDLER(SIOCGIWRTS, prism2_ioctl_giwrts), - IW_HANDLER(SIOCSIWFRAG, prism2_ioctl_siwfrag), - IW_HANDLER(SIOCGIWFRAG, prism2_ioctl_giwfrag), - IW_HANDLER(SIOCSIWTXPOW, prism2_ioctl_siwtxpow), - IW_HANDLER(SIOCGIWTXPOW, prism2_ioctl_giwtxpow), - IW_HANDLER(SIOCSIWRETRY, prism2_ioctl_siwretry), - IW_HANDLER(SIOCGIWRETRY, prism2_ioctl_giwretry), - IW_HANDLER(SIOCSIWENCODE, prism2_ioctl_siwencode), - IW_HANDLER(SIOCGIWENCODE, prism2_ioctl_giwencode), - IW_HANDLER(SIOCSIWPOWER, prism2_ioctl_siwpower), - IW_HANDLER(SIOCGIWPOWER, prism2_ioctl_giwpower), - IW_HANDLER(SIOCSIWGENIE, prism2_ioctl_siwgenie), - IW_HANDLER(SIOCGIWGENIE, prism2_ioctl_giwgenie), - IW_HANDLER(SIOCSIWAUTH, prism2_ioctl_siwauth), - IW_HANDLER(SIOCGIWAUTH, prism2_ioctl_giwauth), - IW_HANDLER(SIOCSIWENCODEEXT, prism2_ioctl_siwencodeext), - IW_HANDLER(SIOCGIWENCODEEXT, prism2_ioctl_giwencodeext), -}; - -static const iw_handler prism2_private_handler[] = -{ /* SIOCIWFIRSTPRIV + */ - prism2_ioctl_priv_prism2_param, /* 0 */ - prism2_ioctl_priv_get_prism2_param, /* 1 */ - prism2_ioctl_priv_writemif, /* 2 */ - prism2_ioctl_priv_readmif, /* 3 */ -}; - -const struct iw_handler_def hostap_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(prism2_handler), - .num_private = ARRAY_SIZE(prism2_private_handler), - .num_private_args = ARRAY_SIZE(prism2_priv), - .standard = prism2_handler, - .private = prism2_private_handler, - .private_args = (struct iw_priv_args *) prism2_priv, - .get_wireless_stats = hostap_get_wireless_stats, -}; - - -/* Private ioctls that are not used with iwpriv; - * in SIOCDEVPRIVATE range */ -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)ifr; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (in_compat_syscall()) /* not implemented yet */ - return -EOPNOTSUPP; - - switch (cmd) { -#ifdef PRISM2_DOWNLOAD_SUPPORT - case PRISM2_IOCTL_DOWNLOAD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_download(local, &wrq->u.data); - break; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - case PRISM2_IOCTL_HOSTAPD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c deleted file mode 100644 index bf86ac26c2ac..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ /dev/null @@ -1,1123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3 - hostap.o module, common routines - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap_80211.h" -#include "hostap_ap.h" -#include "hostap.h" - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP common routines"); -MODULE_LICENSE("GPL"); - -#define TX_TIMEOUT (2 * HZ) - -#define PRISM2_MAX_FRAME_SIZE 2304 -#define PRISM2_MIN_MTU 256 -/* FIX: */ -#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) - - -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, - const char *name) -{ - struct net_device *dev, *mdev; - struct hostap_interface *iface; - int ret; - - dev = alloc_etherdev(sizeof(struct hostap_interface)); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - iface->dev = dev; - iface->local = local; - iface->type = type; - list_add(&iface->list, &local->hostap_interfaces); - - mdev = local->dev; - eth_hw_addr_inherit(dev, mdev); - dev->base_addr = mdev->base_addr; - dev->irq = mdev->irq; - dev->mem_start = mdev->mem_start; - dev->mem_end = mdev->mem_end; - - hostap_setup_dev(dev, local, type); - dev->needs_free_netdev = true; - - sprintf(dev->name, "%s%s", prefix, name); - if (!rtnl_locked) - rtnl_lock(); - - SET_NETDEV_DEV(dev, mdev->dev.parent); - ret = register_netdevice(dev); - - if (!rtnl_locked) - rtnl_unlock(); - - if (ret < 0) { - printk(KERN_WARNING "%s: failed to add new netdevice!\n", - dev->name); - free_netdev(dev); - return NULL; - } - - printk(KERN_DEBUG "%s: registered netdevice %s\n", - mdev->name, dev->name); - - return dev; -} - - -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list) -{ - struct hostap_interface *iface; - - if (!dev) - return; - - iface = netdev_priv(dev); - - if (remove_from_list) { - list_del(&iface->list); - } - - if (dev == iface->local->ddev) - iface->local->ddev = NULL; - else if (dev == iface->local->apdev) - iface->local->apdev = NULL; - else if (dev == iface->local->stadev) - iface->local->stadev = NULL; - - if (rtnl_locked) - unregister_netdevice(dev); - else - unregister_netdev(dev); - - /* 'dev->needs_free_netdev = true' implies device data, including - * private data, will be freed when the device is removed */ -} - - -static inline int prism2_wds_special_addr(u8 *addr) -{ - if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) - return 0; - - return 1; -} - - -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked) -{ - struct net_device *dev; - struct list_head *ptr; - struct hostap_interface *iface, *empty, *match; - - empty = match = NULL; - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (prism2_wds_special_addr(iface->u.wds.remote_addr)) - empty = iface; - else if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - match = iface; - break; - } - } - if (!match && empty && !prism2_wds_special_addr(remote_addr)) { - /* take pre-allocated entry into use */ - memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); - read_unlock_bh(&local->iface_lock); - printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", - local->dev->name, empty->dev->name); - return 0; - } - read_unlock_bh(&local->iface_lock); - - if (!prism2_wds_special_addr(remote_addr)) { - if (match) - return -EEXIST; - hostap_add_sta(local->ap, remote_addr); - } - - if (local->wds_connections >= local->wds_max_connections) - return -ENOBUFS; - - /* verify that there is room for wds# postfix in the interface name */ - if (strlen(local->dev->name) >= IFNAMSIZ - 5) { - printk(KERN_DEBUG "'%s' too long base device name\n", - local->dev->name); - return -EINVAL; - } - - dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, - local->ddev->name, "wds%d"); - if (dev == NULL) - return -ENOMEM; - - iface = netdev_priv(dev); - memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); - - local->wds_connections++; - - return 0; -} - - -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove) -{ - unsigned long flags; - struct list_head *ptr; - struct hostap_interface *iface, *selected = NULL; - - write_lock_irqsave(&local->iface_lock, flags); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - selected = iface; - break; - } - } - if (selected && !do_not_remove) - list_del(&selected->list); - write_unlock_irqrestore(&local->iface_lock, flags); - - if (selected) { - if (do_not_remove) - eth_zero_addr(selected->u.wds.remote_addr); - else { - hostap_remove_interface(selected->dev, rtnl_locked, 0); - local->wds_connections--; - } - } - - return selected ? 0 : -ENODEV; -} - - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data) -{ - unsigned long flags; - struct hostap_tx_callback_info *entry; - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) - return 0; - - entry->func = func; - entry->data = data; - - spin_lock_irqsave(&local->lock, flags); - entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; - entry->next = local->tx_callback; - local->tx_callback = entry; - spin_unlock_irqrestore(&local->lock, flags); - - return entry->idx; -} - - -int hostap_tx_callback_unregister(local_info_t *local, u16 idx) -{ - unsigned long flags; - struct hostap_tx_callback_info *cb, *prev = NULL; - - spin_lock_irqsave(&local->lock, flags); - cb = local->tx_callback; - while (cb != NULL && cb->idx != idx) { - prev = cb; - cb = cb->next; - } - if (cb) { - if (prev == NULL) - local->tx_callback = cb->next; - else - prev->next = cb->next; - kfree(cb); - } - spin_unlock_irqrestore(&local->lock, flags); - - return cb ? 0 : -1; -} - - -/* val is in host byte order */ -int hostap_set_word(struct net_device *dev, int rid, u16 val) -{ - struct hostap_interface *iface; - __le16 tmp = cpu_to_le16(val); - iface = netdev_priv(dev); - return iface->local->func->set_rid(dev, rid, &tmp, 2); -} - - -int hostap_set_string(struct net_device *dev, int rid, const char *val) -{ - struct hostap_interface *iface; - char buf[MAX_SSID_LEN + 2]; - int len; - - iface = netdev_priv(dev); - len = strlen(val); - if (len > MAX_SSID_LEN) - return -1; - memset(buf, 0, sizeof(buf)); - buf[0] = len; /* little endian 16 bit word */ - memcpy(buf + 2, val, len); - - return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); -} - - -u16 hostap_get_porttype(local_info_t *local) -{ - if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - if (local->iw_mode == IW_MODE_ADHOC) - return HFA384X_PORTTYPE_IBSS; - if (local->iw_mode == IW_MODE_INFRA) - return HFA384X_PORTTYPE_BSS; - if (local->iw_mode == IW_MODE_REPEAT) - return HFA384X_PORTTYPE_WDS; - if (local->iw_mode == IW_MODE_MONITOR) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - return HFA384X_PORTTYPE_HOSTAP; -} - - -int hostap_set_encryption(local_info_t *local) -{ - u16 val, old_val; - int i, keylen, len, idx; - char keybuf[WEP_KEY_LEN + 1]; - enum { NONE, WEP, OTHER } encrypt_type; - - idx = local->crypt_info.tx_keyidx; - if (local->crypt_info.crypt[idx] == NULL || - local->crypt_info.crypt[idx]->ops == NULL) - encrypt_type = NONE; - else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) - encrypt_type = WEP; - else - encrypt_type = OTHER; - - if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, - 1) < 0) { - printk(KERN_DEBUG "Could not read current WEP flags.\n"); - goto fail; - } - le16_to_cpus(&val); - old_val = val; - - if (encrypt_type != NONE || local->privacy_invoked) - val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; - else - val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; - - if (local->open_wep || encrypt_type == NONE || - ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) - val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - else - val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_encrypt)) - val |= HFA384X_WEPFLAGS_HOSTENCRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_decrypt)) - val |= HFA384X_WEPFLAGS_HOSTDECRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; - - if (val != old_val && - hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { - printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", - val); - goto fail; - } - - if (encrypt_type != WEP) - return 0; - - /* 104-bit support seems to require that all the keys are set to the - * same keylen */ - keylen = 6; /* first 5 octets */ - len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, - local->crypt_info.crypt[idx]->priv); - if (idx >= 0 && idx < WEP_KEYS && len > 5) - keylen = WEP_KEY_LEN + 1; /* first 13 octets */ - - for (i = 0; i < WEP_KEYS; i++) { - memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt_info.crypt[i]) { - (void) local->crypt_info.crypt[i]->ops->get_key( - keybuf, sizeof(keybuf), - NULL, local->crypt_info.crypt[i]->priv); - } - if (local->func->set_rid(local->dev, - HFA384X_RID_CNFDEFAULTKEY0 + i, - keybuf, keylen)) { - printk(KERN_DEBUG "Could not set key %d (len=%d)\n", - i, keylen); - goto fail; - } - } - if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { - printk(KERN_DEBUG "Could not set default keyid %d\n", idx); - goto fail; - } - - return 0; - - fail: - printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); - return -1; -} - - -int hostap_set_antsel(local_info_t *local) -{ - u16 val; - int ret = 0; - - if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_TX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(2) | BIT(1)); - switch (local->antsel_tx) { - case HOSTAP_ANTSEL_DIVERSITY: - val |= BIT(1); - break; - case HOSTAP_ANTSEL_LOW: - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(2); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_TX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting TX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_RX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(1) | BIT(0)); - switch (local->antsel_rx) { - case HOSTAP_ANTSEL_DIVERSITY: - break; - case HOSTAP_ANTSEL_LOW: - val |= BIT(0); - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(0) | BIT(1); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_RX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting RX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - return ret; -} - - -int hostap_set_roaming(local_info_t *local) -{ - u16 val; - - switch (local->host_roaming) { - case 1: - val = HFA384X_ROAMING_HOST; - break; - case 2: - val = HFA384X_ROAMING_DISABLED; - break; - case 0: - default: - val = HFA384X_ROAMING_FIRMWARE; - break; - } - - return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); -} - - -int hostap_set_auth_algs(local_info_t *local) -{ - int val = local->auth_algs; - /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication - * set to include both Open and Shared Key flags. It tries to use - * Shared Key authentication in that case even if WEP keys are not - * configured.. STA f/w v0.7.6 is able to handle such configuration, - * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ - if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && - val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) - val = PRISM2_AUTH_OPEN; - - if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { - printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " - "failed\n", local->dev->name, local->auth_algs); - return -EINVAL; - } - - return 0; -} - - -void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) -{ - u16 status, fc; - - status = __le16_to_cpu(rx->status); - - printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " - "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " - "jiffies=%ld\n", - name, status, (status >> 8) & 0x07, status >> 13, status & 1, - rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); - - fc = __le16_to_cpu(rx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), - __le16_to_cpu(rx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - rx->addr1, rx->addr2, rx->addr3, rx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - rx->dst_addr, rx->src_addr, - __be16_to_cpu(rx->len)); -} - - -void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) -{ - u16 fc; - - printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " - "tx_control=0x%04x; jiffies=%ld\n", - name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, - __le16_to_cpu(tx->tx_control), jiffies); - - fc = __le16_to_cpu(tx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), - __le16_to_cpu(tx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - tx->addr1, tx->addr2, tx->addr3, tx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - tx->dst_addr, tx->src_addr, - __be16_to_cpu(tx->len)); -} - - -static int hostap_80211_header_parse(const struct sk_buff *skb, - unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - - -int hostap_80211_get_hdrlen(__le16 fc) -{ - if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc)) - return 30; /* Addr4 */ - else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc)) - return 10; - else if (ieee80211_is_ctl(fc)) - return 16; - - return 24; -} - - -static int prism2_close(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (dev == local->ddev) { - prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); - } -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && dev == local->dev && - (!local->func->card_present || local->func->card_present(local)) && - local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) - hostap_deauth_all_stas(dev, local->ap, 1); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (dev == local->dev) { - local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); - } - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - - cancel_work_sync(&local->reset_queue); - cancel_work_sync(&local->set_multicast_list_queue); - cancel_work_sync(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - cancel_work_sync(&local->info_queue); -#endif - cancel_work_sync(&local->comms_qual_update); - - module_put(local->hw_module); - - local->num_dev_open--; - - if (dev != local->dev && local->dev->flags & IFF_UP && - local->master_dev_auto_open && local->num_dev_open == 1) { - /* Close master radio interface automatically if it was also - * opened automatically and we are now closing the last - * remaining non-master device. */ - dev_close(local->dev); - } - - return 0; -} - - -static int prism2_open(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: could not set interface UP - no PRI " - "f/w\n", dev->name); - return -ENODEV; - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - if (!try_module_get(local->hw_module)) - return -ENODEV; - local->num_dev_open++; - - if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { - printk(KERN_WARNING "%s: could not enable MAC port\n", - dev->name); - prism2_close(dev); - return -ENODEV; - } - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - - if (dev != local->dev && !(local->dev->flags & IFF_UP)) { - /* Master radio interface is needed for all operation, so open - * it automatically when any virtual net_device is opened. */ - local->master_dev_auto_open = 1; - dev_open(local->dev, NULL); - } - - netif_device_attach(dev); - netif_start_queue(dev); - - return 0; -} - - -static int prism2_set_mac_address(struct net_device *dev, void *p) -{ - struct hostap_interface *iface; - local_info_t *local; - struct list_head *ptr; - struct sockaddr *addr = p; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, - ETH_ALEN) < 0 || local->func->reset_port(dev)) - return -EINVAL; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_set(iface->dev, addr->sa_data); - } - eth_hw_addr_set(local->dev, addr->sa_data); - read_unlock_bh(&local->iface_lock); - - return 0; -} - - -/* TODO: to be further implemented as soon as Prism2 fully supports - * GroupAddresses and correct documentation is available */ -void hostap_set_multicast_list_queue(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, set_multicast_list_queue); - struct net_device *dev = local->dev; - - if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc)) { - printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", - dev->name, local->is_promisc ? "en" : "dis"); - } -} - - -static void hostap_set_multicast_list(struct net_device *dev) -{ -#if 0 - /* FIX: promiscuous mode seems to be causing a lot of problems with - * some station firmware versions (FCSErr frames, invalid MACPort, etc. - * corrupted incoming frames). This code is now commented out while the - * problems are investigated. */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { - local->is_promisc = 1; - } else { - local->is_promisc = 0; - } - - schedule_work(&local->set_multicast_list_queue); -#endif -} - - -static void prism2_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_regs regs; - - iface = netdev_priv(dev); - local = iface->local; - - printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); - netif_stop_queue(local->dev); - - local->func->read_regs(dev, ®s); - printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " - "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", - dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, - regs.swsupport0); - - local->func->schedule_reset(local); -} - -const struct header_ops hostap_80211_ops = { - .create = eth_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, - .parse = hostap_80211_header_parse, -}; -EXPORT_SYMBOL(hostap_80211_ops); - - -static const struct net_device_ops hostap_netdev_ops = { - .ndo_start_xmit = hostap_data_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_mgmt_netdev_ops = { - .ndo_start_xmit = hostap_mgmt_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_master_ops = { - .ndo_start_xmit = hostap_master_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type) -{ - struct hostap_interface *iface; - - iface = netdev_priv(dev); - ether_setup(dev); - dev->min_mtu = PRISM2_MIN_MTU; - dev->max_mtu = PRISM2_MAX_MTU; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - - /* kernel callbacks */ - if (iface) { - /* Currently, we point to the proper spy_data only on - * the main_dev. This could be fixed. Jean II */ - iface->wireless_data.spy_data = &iface->spy_data; - dev->wireless_data = &iface->wireless_data; - } - dev->wireless_handlers = &hostap_iw_handler_def; - dev->watchdog_timeo = TX_TIMEOUT; - - switch(type) { - case HOSTAP_INTERFACE_AP: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_mgmt_netdev_ops; - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - break; - case HOSTAP_INTERFACE_MASTER: - dev->netdev_ops = &hostap_master_ops; - break; - default: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_netdev_ops; - } - - dev->mtu = local->mtu; - - - dev->ethtool_ops = &prism2_ethtool_ops; - -} - -static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->apdev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); - - local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, - rtnl_locked, local->ddev->name, - "ap"); - if (local->apdev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->apdev, rtnl_locked, 1); - local->apdev = NULL; - - return 0; -} - - -static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->stadev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); - - local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, - rtnl_locked, local->ddev->name, - "sta"); - if (local->stadev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->stadev, rtnl_locked, 1); - local->stadev = NULL; - - return 0; -} - - -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd(local, rtnl_locked); - if (ret == 0) - local->hostapd = 1; - } else { - local->hostapd = 0; - ret = hostap_disable_hostapd(local, rtnl_locked); - if (ret != 0) - local->hostapd = 1; - } - - return ret; -} - - -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd_sta == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd_sta(local, rtnl_locked); - if (ret == 0) - local->hostapd_sta = 1; - } else { - local->hostapd_sta = 0; - ret = hostap_disable_hostapd_sta(local, rtnl_locked); - if (ret != 0) - local->hostapd_sta = 1; - } - - - return ret; -} - - -int prism2_update_comms_qual(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - struct hfa384x_comms_quality sq; - - iface = netdev_priv(dev); - local = iface->local; - if (!local->sta_fw_ver) - ret = -1; - else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - if (local->func->get_rid(local->dev, - HFA384X_RID_DBMCOMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); - local->avg_signal = (s16) le16_to_cpu(sq.signal_level); - local->avg_noise = (s16) le16_to_cpu(sq.noise_level); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } else { - if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = le16_to_cpu(sq.comm_qual); - local->avg_signal = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.signal_level)); - local->avg_noise = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.noise_level)); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } - - return ret; -} - - -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen) -{ - struct sk_buff *skb; - struct hostap_ieee80211_mgmt *mgmt; - struct hostap_skb_tx_data *meta; - struct net_device *dev = local->dev; - - skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); - if (skb == NULL) - return -ENOMEM; - - mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); - memcpy(mgmt->da, dst, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, dst, ETH_ALEN); - if (body) - skb_put_data(skb, body, bodylen); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = netdev_priv(dev); - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); - - return 0; -} - - -int prism2_sta_deauth(local_info_t *local, u16 reason) -{ - union iwreq_data wrqu; - int ret; - __le16 val = cpu_to_le16(reason); - - if (local->iw_mode != IW_MODE_INFRA || - is_zero_ether_addr(local->bssid) || - ether_addr_equal(local->bssid, "\x44\x44\x44\x44\x44\x44")) - return 0; - - ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, - (u8 *) &val, 2); - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - return ret; -} - - -struct proc_dir_entry *hostap_proc; - -static int __init hostap_init(void) -{ - if (init_net.proc_net != NULL) { - hostap_proc = proc_mkdir("hostap", init_net.proc_net); - if (!hostap_proc) - printk(KERN_WARNING "Failed to mkdir " - "/proc/net/hostap\n"); - } else - hostap_proc = NULL; - - return 0; -} - - -static void __exit hostap_exit(void) -{ - if (hostap_proc != NULL) { - hostap_proc = NULL; - remove_proc_entry("hostap", init_net.proc_net); - } -} - - -EXPORT_SYMBOL(hostap_set_word); -EXPORT_SYMBOL(hostap_set_string); -EXPORT_SYMBOL(hostap_get_porttype); -EXPORT_SYMBOL(hostap_set_encryption); -EXPORT_SYMBOL(hostap_set_antsel); -EXPORT_SYMBOL(hostap_set_roaming); -EXPORT_SYMBOL(hostap_set_auth_algs); -EXPORT_SYMBOL(hostap_dump_rx_header); -EXPORT_SYMBOL(hostap_dump_tx_header); -EXPORT_SYMBOL(hostap_80211_get_hdrlen); -EXPORT_SYMBOL(hostap_setup_dev); -EXPORT_SYMBOL(hostap_set_multicast_list_queue); -EXPORT_SYMBOL(hostap_set_hostapd); -EXPORT_SYMBOL(hostap_set_hostapd_sta); -EXPORT_SYMBOL(hostap_add_interface); -EXPORT_SYMBOL(hostap_remove_interface); -EXPORT_SYMBOL(prism2_update_comms_qual); - -module_init(hostap_init); -module_exit(hostap_exit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c deleted file mode 100644 index 52d77506effd..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_pci.c +++ /dev/null @@ -1,445 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCI - -/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on - * driver patches from Reyk Floeter and - * Andy Warner */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_pci"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " - "PCI cards."); -MODULE_LICENSE("GPL"); - - -/* struct local_info::hw_priv */ -struct hostap_pci_priv { - void __iomem *mem_start; -}; - - -/* FIX: do we need mb/wmb/rmb with memory operations? */ - - -static const struct pci_device_id prism2_pci_id_table[] = { - /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ - { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, - /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ - { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, - /* Samsung MagicLAN SWL-2210P */ - { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, - { 0 } -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - writeb(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readb(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - writew(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readw(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a))) - -#else /* PRISM2_IO_DEBUG */ - -static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writeb(v, hw_priv->mem_start + a); -} - -static inline u8 hfa384x_inb(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readb(hw_priv->mem_start + a); -} - -static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writew(v, hw_priv->mem_start + a); -} - -static inline u16 hfa384x_inw(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readw(hw_priv->mem_start + a); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a))) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - *pos++ = HFA384X_INW_DATA(d_off); - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - HFA384X_OUTW_DATA(*pos++, d_off); - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - -static void prism2_pci_cor_sreset(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 reg; - - reg = HFA384X_INB(HFA384X_PCICOR_OFF); - printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); - - /* linux-wlan-ng uses extremely long hold and settle times for - * COR sreset. A comment in the driver code mentions that the long - * delays appear to be necessary. However, at least IBM 22P6901 seems - * to work fine with shorter delays. - * - * Longer delays can be configured by uncommenting following line: */ -/* #define PRISM2_PCI_USE_LONG_DELAYS */ - -#ifdef PRISM2_PCI_USE_LONG_DELAYS - int i; - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(250); - - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(500); - - /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ - i = 2000000 / 10; - while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) - udelay(10); - -#else /* PRISM2_PCI_USE_LONG_DELAYS */ - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - -#endif /* PRISM2_PCI_USE_LONG_DELAYS */ - - if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { - printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); - } -} - - -static void prism2_pci_genesis_reset(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - - HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); - mdelay(10); - HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); - mdelay(10); - HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pci_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_pci_cor_sreset, - .genesis_reset = prism2_pci_genesis_reset, - .hw_type = HOSTAP_HW_PCI, -}; - - -static int prism2_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long phymem; - void __iomem *mem = NULL; - local_info_t *local = NULL; - struct net_device *dev = NULL; - static int cards_found /* = 0 */; - int irq_registered = 0; - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - phymem = pci_resource_start(pdev, 0); - - if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { - printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); - goto err_out_disable; - } - - mem = pci_ioremap_bar(pdev, 0); - if (mem == NULL) { - printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; - goto fail; - } - - dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - hw_priv->mem_start = mem; - dev->base_addr = (unsigned long) mem; - - prism2_pci_cor_sreset(local); - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (!local->pri_only && prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " - "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (mem) - iounmap(mem); - - release_mem_region(phymem, pci_resource_len(pdev, 0)); - - err_out_disable: - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - void __iomem *mem_start; - struct hostap_pci_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_pci_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - - mem_start = hw_priv->mem_start; - prism2_free_local_data(dev); - kfree(hw_priv); - - iounmap(mem_start); - - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - pci_disable_device(pdev); -} - -static int __maybe_unused prism2_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int __maybe_unused prism2_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - prism2_hw_config(dev, 0); - if (netif_running(dev)) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); - -static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops, - prism2_pci_suspend, - prism2_pci_resume); - -static struct pci_driver prism2_pci_driver = { - .name = "hostap_pci", - .id_table = prism2_pci_id_table, - .probe = prism2_pci_probe, - .remove = prism2_pci_remove, - .driver.pm = &prism2_pci_pm_ops, -}; - -module_pci_driver(prism2_pci_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_plx.c b/drivers/net/wireless/intersil/hostap/hostap_plx.c deleted file mode 100644 index 58247290fcbc..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_plx.c +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PLX - -/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is - * based on: - * - Host AP driver patch from james@madingley.org - * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_plx"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PLX)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis; -module_param(ignore_cis, int, 0444); -MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); - - -/* struct local_info::hw_priv */ -struct hostap_plx_priv { - void __iomem *attr_mem; - unsigned int cor_offset; -}; - - -#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ -#define COR_SRESET 0x80 -#define COR_LEVLREQ 0x40 -#define COR_ENABLE_FUNC 0x01 -/* PCI Configuration Registers */ -#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ -/* Local Configuration Registers */ -#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ -#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ -#define PLX_CNTRL 0x50 -#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) - - -#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } - -static const struct pci_device_id prism2_plx_id_table[] = { - PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), - PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), - PLXDEV(0x126c, 0x8030, "Nortel emobility"), - PLXDEV(0x1562, 0x0001, "Symbol LA-4123"), - PLXDEV(0x1385, 0x4100, "Netgear MA301"), - PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), - PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), - PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), - PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"), - PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), - PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), - PLXDEV(0x16ab, 0x1103, "Longshine 8031"), - PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), - PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), - { 0 } -}; - - -/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid - * is not listed here, you will need to add it here to get the driver - * initialized. */ -static struct prism2_plx_manfid { - u16 manfid1, manfid2; -} prism2_plx_known_manfids[] = { - { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, - { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, - { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, - { 0x0126, 0x8000 } /* Proxim RangeLAN */, - { 0x0138, 0x0002 } /* Compaq WL100 */, - { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, - { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, - { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, - { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, - { 0x028a, 0x0002 } /* D-Link DRC-650 */, - { 0x0250, 0x0002 } /* Samsung SWL2000-N */, - { 0xc250, 0x0002 } /* EMTAC A2424i */, - { 0xd601, 0x0002 } /* Z-Com XI300 */, - { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, - { 0, 0} -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - -static void prism2_plx_cor_sreset(local_info_t *local) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", - dev_info); - - /* Set sreset bit of COR and clear it after hold time */ - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(2); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(2); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - } -} - - -static void prism2_plx_genesis_reset(local_info_t *local, int hcr) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(10); - outb(hcr, hw_priv->cor_offset + 2); - mdelay(10); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(10); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2); - mdelay(10); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - } -} - - -static struct prism2_helper_functions prism2_plx_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_plx_cor_sreset, - .genesis_reset = prism2_plx_genesis_reset, - .hw_type = HOSTAP_HW_PLX, -}; - - -static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, - unsigned int *cor_offset, - unsigned int *cor_index) -{ -#define CISTPL_CONFIG 0x1A -#define CISTPL_MANFID 0x20 -#define CISTPL_END 0xFF -#define CIS_MAX_LEN 256 - u8 *cis; - int i, pos; - unsigned int rmsz, rasz, manfid1, manfid2; - struct prism2_plx_manfid *manfid; - - cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); - if (cis == NULL) - return -ENOMEM; - - /* read CIS; it is in even offsets in the beginning of attr_mem */ - for (i = 0; i < CIS_MAX_LEN; i++) - cis[i] = readb(attr_mem + 2 * i); - printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis); - - /* set reasonable defaults for Prism2 cards just in case CIS parsing - * fails */ - *cor_offset = 0x3e0; - *cor_index = 0x01; - manfid1 = manfid2 = 0; - - pos = 0; - while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { - if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN) - goto cis_error; - - switch (cis[pos]) { - case CISTPL_CONFIG: - if (cis[pos + 1] < 2) - goto cis_error; - rmsz = (cis[pos + 2] & 0x3c) >> 2; - rasz = cis[pos + 2] & 0x03; - if (4 + rasz + rmsz > cis[pos + 1]) - goto cis_error; - *cor_index = cis[pos + 3] & 0x3F; - *cor_offset = 0; - for (i = 0; i <= rasz; i++) - *cor_offset += cis[pos + 4 + i] << (8 * i); - printk(KERN_DEBUG "%s: cor_index=0x%x " - "cor_offset=0x%x\n", dev_info, - *cor_index, *cor_offset); - if (*cor_offset > attr_len) { - printk(KERN_ERR "%s: COR offset not within " - "attr_mem\n", dev_info); - kfree(cis); - return -1; - } - break; - - case CISTPL_MANFID: - if (cis[pos + 1] < 4) - goto cis_error; - manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); - manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); - printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", - dev_info, manfid1, manfid2); - break; - } - - pos += cis[pos + 1] + 2; - } - - if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) - goto cis_error; - - for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) - if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { - kfree(cis); - return 0; - } - - printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" - " not supported card\n", dev_info, manfid1, manfid2); - goto fail; - - cis_error: - printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); - - fail: - kfree(cis); - if (ignore_cis) { - printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " - "errors during CIS verification\n", dev_info); - return 0; - } - return -1; -} - - -static int prism2_plx_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned int pccard_ioaddr, plx_ioaddr; - unsigned long pccard_attr_mem; - unsigned int pccard_attr_len; - void __iomem *attr_mem = NULL; - unsigned int cor_offset = 0, cor_index = 0; - u32 reg; - local_info_t *local = NULL; - struct net_device *dev = NULL; - struct hostap_interface *iface; - static int cards_found /* = 0 */; - int irq_registered = 0; - int tmd7160; - struct hostap_plx_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ - tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); - - plx_ioaddr = pci_resource_start(pdev, 1); - pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); - - if (tmd7160) { - /* TMD7160 */ - attr_mem = NULL; /* no access to PC Card attribute memory */ - - printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " - "irq=%d, pccard_io=0x%x\n", - plx_ioaddr, pdev->irq, pccard_ioaddr); - - cor_offset = plx_ioaddr; - cor_index = 0x04; - - outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); - mdelay(1); - reg = inb(plx_ioaddr); - if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { - printk(KERN_ERR "%s: Error setting COR (expected=" - "0x%02x, was=0x%02x)\n", dev_info, - cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); - goto fail; - } - } else { - /* PLX9052 */ - pccard_attr_mem = pci_resource_start(pdev, 2); - pccard_attr_len = pci_resource_len(pdev, 2); - if (pccard_attr_len < PLX_MIN_ATTR_LEN) - goto fail; - - - attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); - if (attr_mem == NULL) { - printk(KERN_ERR "%s: cannot remap attr_mem\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " - "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", - pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); - - if (prism2_plx_check_cis(attr_mem, pccard_attr_len, - &cor_offset, &cor_index)) { - printk(KERN_INFO "Unknown PC Card CIS - not a " - "Prism2/2.5 card?\n"); - goto fail; - } - - printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " - "adapter\n"); - - /* Write COR to enable PC Card */ - writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, - attr_mem + cor_offset); - - /* Enable PCI interrupts if they are not already enabled */ - reg = inl(plx_ioaddr + PLX_INTCSR); - printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); - if (!(reg & PLX_INTCSR_PCI_INTEN)) { - outl(reg | PLX_INTCSR_PCI_INTEN, - plx_ioaddr + PLX_INTCSR); - if (!(inl(plx_ioaddr + PLX_INTCSR) & - PLX_INTCSR_PCI_INTEN)) { - printk(KERN_WARNING "%s: Could not enable " - "Local Interrupts\n", dev_info); - goto fail; - } - } - - reg = inl(plx_ioaddr + PLX_CNTRL); - printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " - "present=%d)\n", - reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); - /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is - * not present; but are there really such cards in use(?) */ - } - - dev = prism2_init_local_data(&prism2_plx_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - dev->base_addr = pccard_ioaddr; - hw_priv->attr_mem = attr_mem; - hw_priv->cor_offset = cor_offset; - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (attr_mem) - iounmap(attr_mem); - - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_plx_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct hostap_plx_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_plx_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (hw_priv->attr_mem) - iounmap(hw_priv->attr_mem); - if (dev->irq) - free_irq(dev->irq, dev); - - prism2_free_local_data(dev); - kfree(hw_priv); - pci_disable_device(pdev); -} - - -MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); - -static struct pci_driver prism2_plx_driver = { - .name = "hostap_plx", - .id_table = prism2_plx_id_table, - .probe = prism2_plx_probe, - .remove = prism2_plx_remove, -}; - -module_pci_driver(prism2_plx_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c deleted file mode 100644 index 61f68786056f..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_proc.c +++ /dev/null @@ -1,411 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* /proc routines for Host AP driver */ - -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" - -#define PROC_LIMIT (PAGE_SIZE - 80) - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int prism2_debug_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "next_txfid=%d next_alloc=%d\n", - local->next_txfid, local->next_alloc); - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - seq_printf(m, "FID: tx=%04X intransmit=%04X\n", - local->txfid[i], local->intransmitfid[i]); - seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control); - seq_printf(m, "beacon_int=%d\n", local->beacon_int); - seq_printf(m, "dtim_period=%d\n", local->dtim_period); - seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections); - seq_printf(m, "dev_enabled=%d\n", local->dev_enabled); - seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops) { - seq_printf(m, "crypt[%d]=%s\n", i, - local->crypt_info.crypt[i]->ops->name); - } - } - seq_printf(m, "pri_only=%d\n", local->pri_only); - seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); - seq_printf(m, "sram_type=%d\n", local->sram_type); - seq_printf(m, "no_pri=%d\n", local->no_pri); - - return 0; -} -#endif - -#ifdef CONFIG_PROC_FS -static int prism2_stats_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - struct comm_tallies_sums *sums = &local->comm_tallies; - - seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); - seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames); - seq_printf(m, "TxFragments=%u\n", sums->tx_fragments); - seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); - seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); - seq_printf(m, "TxDeferredTransmissions=%u\n", - sums->tx_deferred_transmissions); - seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames); - seq_printf(m, "TxMultipleRetryFrames=%u\n", - sums->tx_multiple_retry_frames); - seq_printf(m, "TxRetryLimitExceeded=%u\n", - sums->tx_retry_limit_exceeded); - seq_printf(m, "TxDiscards=%u\n", sums->tx_discards); - seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); - seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); - seq_printf(m, "RxFragments=%u\n", sums->rx_fragments); - seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); - seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); - seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors); - seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer); - seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); - seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n", - sums->rx_discards_wep_undecryptable); - seq_printf(m, "RxMessageInMsgFragments=%u\n", - sums->rx_message_in_msg_fragments); - seq_printf(m, "RxMessageInBadMsgFragments=%u\n", - sums->rx_message_in_bad_msg_fragments); - /* FIX: this may grow too long for one page(?) */ - - return 0; -} -#endif - -static int prism2_wds_proc_show(struct seq_file *m, void *v) -{ - struct list_head *ptr = v; - struct hostap_interface *iface; - - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS) - seq_printf(m, "%s\t%pM\n", - iface->dev->name, iface->u.wds.remote_addr); - return 0; -} - -static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_lock_bh(&local->iface_lock); - return seq_list_start(&local->hostap_interfaces, *_pos); -} - -static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->hostap_interfaces, _pos); -} - -static void prism2_wds_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_unlock_bh(&local->iface_lock); -} - -static const struct seq_operations prism2_wds_proc_seqops = { - .start = prism2_wds_proc_start, - .next = prism2_wds_proc_next, - .stop = prism2_wds_proc_stop, - .show = prism2_wds_proc_show, -}; - -static int prism2_bss_list_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - struct list_head *ptr = v; - struct hostap_bss_info *bss; - - if (ptr == &local->bss_list) { - seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" - "SSID(hex)\tWPA IE\n"); - return 0; - } - - bss = list_entry(ptr, struct hostap_bss_info, list); - seq_printf(m, "%pM\t%lu\t%u\t0x%x\t", - bss->bssid, bss->last_update, - bss->count, bss->capab_info); - - seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid); - - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid); - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) - __acquires(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - return seq_list_start_head(&local->bss_list, *_pos); -} - -static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->bss_list, _pos); -} - -static void prism2_bss_list_proc_stop(struct seq_file *m, void *v) - __releases(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_bss_list_proc_seqops = { - .start = prism2_bss_list_proc_start, - .next = prism2_bss_list_proc_next, - .stop = prism2_bss_list_proc_stop, - .show = prism2_bss_list_proc_show, -}; - -#ifdef CONFIG_PROC_FS -static int prism2_crypt_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops && - local->crypt_info.crypt[i]->ops->print_stats) { - local->crypt_info.crypt[i]->ops->print_stats( - m, local->crypt_info.crypt[i]->priv); - } - } - return 0; -} -#endif - -static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, - size_t count, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(file)); - size_t off; - - if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE) - return 0; - - off = *_pos; - if (count > PRISM2_PDA_SIZE - off) - count = PRISM2_PDA_SIZE - off; - if (copy_to_user(buf, local->pda + off, count) != 0) - return -EFAULT; - *_pos += count; - return count; -} - -static const struct proc_ops prism2_pda_proc_ops = { - .proc_read = prism2_pda_proc_read, - .proc_lseek = generic_file_llseek, -}; - - -static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf, - size_t bufsize, loff_t *_pos) -{ - return 0; -} - -static const struct proc_ops prism2_aux_dump_proc_ops = { - .proc_read = prism2_aux_dump_proc_no_read, - .proc_lseek = default_llseek, -}; - - -#ifdef PRISM2_IO_DEBUG -static int prism2_io_debug_proc_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - local_info_t *local = (local_info_t *) data; - int head = local->io_debug_head; - int start_bytes, left, copy; - - if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { - *eof = 1; - if (off >= PRISM2_IO_DEBUG_SIZE * 4) - return 0; - count = PRISM2_IO_DEBUG_SIZE * 4 - off; - } - - start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; - left = count; - - if (off < start_bytes) { - copy = start_bytes - off; - if (copy > count) - copy = count; - memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); - left -= copy; - if (left > 0) - memcpy(&page[copy], local->io_debug, left); - } else { - memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), - left); - } - - *start = page; - - return count; -} -#endif /* PRISM2_IO_DEBUG */ - - -#ifndef PRISM2_NO_STATION_MODES -static int prism2_scan_results_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - unsigned long entry; - int i, len; - struct hfa384x_hostscan_result *scanres; - u8 *p; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, - "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n"); - return 0; - } - - entry = (unsigned long)v - 2; - scanres = &local->last_scan_results[entry]; - - seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ", - le16_to_cpu(scanres->chid), - (s16) le16_to_cpu(scanres->anl), - (s16) le16_to_cpu(scanres->sl), - le16_to_cpu(scanres->beacon_interval), - le16_to_cpu(scanres->capability), - le16_to_cpu(scanres->rate), - scanres->bssid, - le16_to_cpu(scanres->atim)); - - p = scanres->sup_rates; - for (i = 0; i < sizeof(scanres->sup_rates); i++) { - if (p[i] == 0) - break; - seq_printf(m, "<%02x>", p[i]); - } - seq_putc(m, ' '); - - p = scanres->ssid; - len = le16_to_cpu(scanres->ssid_len); - if (len > 32) - len = 32; - for (i = 0; i < len; i++) { - unsigned char c = p[i]; - if (c >= 32 && c < 127) - seq_putc(m, c); - else - seq_printf(m, "<%02x>", c); - } - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - - /* We have a header (pos 0) + N results to show (pos 1...N) */ - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - - ++*_pos; - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_scan_results_proc_seqops = { - .start = prism2_scan_results_proc_start, - .next = prism2_scan_results_proc_next, - .stop = prism2_scan_results_proc_stop, - .show = prism2_scan_results_proc_show, -}; -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_init_proc(local_info_t *local) -{ - local->proc = NULL; - - if (hostap_proc == NULL) { - printk(KERN_WARNING "%s: hostap proc directory not created\n", - local->dev->name); - return; - } - - local->proc = proc_mkdir(local->ddev->name, hostap_proc); - if (local->proc == NULL) { - printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", - local->ddev->name); - return; - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show, - local); - proc_create_seq_data("wds", 0, local->proc, - &prism2_wds_proc_seqops, local); - proc_create_data("pda", 0, local->proc, - &prism2_pda_proc_ops, local); - proc_create_data("aux_dump", 0, local->proc, - local->func->read_aux_proc_ops ?: &prism2_aux_dump_proc_ops, - local); - proc_create_seq_data("bss_list", 0, local->proc, - &prism2_bss_list_proc_seqops, local); - proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show, - local); -#ifdef PRISM2_IO_DEBUG - proc_create_single_data("io_debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_IO_DEBUG */ -#ifndef PRISM2_NO_STATION_MODES - proc_create_seq_data("scan_results", 0, local->proc, - &prism2_scan_results_proc_seqops, local); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -void hostap_remove_proc(local_info_t *local) -{ - proc_remove(local->proc); -} - - -EXPORT_SYMBOL(hostap_init_proc); -EXPORT_SYMBOL(hostap_remove_proc); diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h deleted file mode 100644 index f71c0545c0be..000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ /dev/null @@ -1,1051 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_WLAN_H -#define HOSTAP_WLAN_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_config.h" -#include "hostap_common.h" - -#define MAX_PARM_DEVICES 8 -#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) -#define DEF_INTS -1, -1, -1, -1, -1, -1, -1 -#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] - - -/* Specific skb->protocol value that indicates that the packet already contains - * txdesc header. - * FIX: This might need own value that would be allocated especially for Prism2 - * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". - * However, these skb's should have only minimal path in the kernel side since - * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ -#define ETH_P_HOSTAP ETH_P_CONTROL - -/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header - * (from linux-wlan-ng) */ -struct linux_wlan_ng_val { - u32 did; - u16 status, len; - u32 data; -} __packed; - -struct linux_wlan_ng_prism_hdr { - u32 msgcode, msglen; - char devname[16]; - struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, - noise, rate, istx, frmlen; -} __packed; - -struct linux_wlan_ng_cap_hdr { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; -} __packed; - -struct hostap_radiotap_rx { - struct ieee80211_radiotap_header hdr; - __le64 tsft; - u8 rate; - u8 padding; - __le16 chan_freq; - __le16 chan_flags; - s8 dbm_antsignal; - s8 dbm_antnoise; -} __packed; - -#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ -#define LWNG_CAPHDR_VERSION 0x80211001 - -struct hfa384x_rx_frame { - /* HFA384X RX frame descriptor */ - __le16 status; /* HFA384X_RX_STATUS_ flags */ - __le32 time; /* timestamp, 1 microsecond resolution */ - u8 silence; /* 27 .. 154; seems to be 0 */ - u8 signal; /* 27 .. 154 */ - u8 rate; /* 10, 20, 55, or 110 */ - u8 rxflow; - __le32 reserved; - - /* 802.11 */ - __le16 frame_control; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_tx_frame { - /* HFA384X TX frame descriptor */ - __le16 status; /* HFA384X_TX_STATUS_ flags */ - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; /* not yet implemented */ - u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ - __le16 tx_control; /* HFA384X_TX_CTRL_ flags */ - - /* 802.11 */ - struct_group(header, - __le16 frame_control; /* parts not used */ - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; /* filled by firmware */ - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; /* filled by firmware */ - ); - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_rid_hdr -{ - __le16 len; - __le16 rid; -} __packed; - - -/* Macro for converting signal levels (range 27 .. 154) to wireless ext - * dBm value with some accuracy */ -#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 - -#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 - -struct hfa384x_scan_request { - __le16 channel_list; - __le16 txrate; /* HFA384X_RATES_* */ -} __packed; - -struct hfa384x_hostscan_request { - __le16 channel_list; - __le16 txrate; - __le16 target_ssid_len; - u8 target_ssid[32]; -} __packed; - -struct hfa384x_join_request { - u8 bssid[ETH_ALEN]; - __le16 channel; -} __packed; - -struct hfa384x_info_frame { - __le16 len; - __le16 type; -} __packed; - -struct hfa384x_comm_tallies { - __le16 tx_unicast_frames; - __le16 tx_multicast_frames; - __le16 tx_fragments; - __le16 tx_unicast_octets; - __le16 tx_multicast_octets; - __le16 tx_deferred_transmissions; - __le16 tx_single_retry_frames; - __le16 tx_multiple_retry_frames; - __le16 tx_retry_limit_exceeded; - __le16 tx_discards; - __le16 rx_unicast_frames; - __le16 rx_multicast_frames; - __le16 rx_fragments; - __le16 rx_unicast_octets; - __le16 rx_multicast_octets; - __le16 rx_fcs_errors; - __le16 rx_discards_no_buffer; - __le16 tx_discards_wrong_sa; - __le16 rx_discards_wep_undecryptable; - __le16 rx_message_in_msg_fragments; - __le16 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_comm_tallies32 { - __le32 tx_unicast_frames; - __le32 tx_multicast_frames; - __le32 tx_fragments; - __le32 tx_unicast_octets; - __le32 tx_multicast_octets; - __le32 tx_deferred_transmissions; - __le32 tx_single_retry_frames; - __le32 tx_multiple_retry_frames; - __le32 tx_retry_limit_exceeded; - __le32 tx_discards; - __le32 rx_unicast_frames; - __le32 rx_multicast_frames; - __le32 rx_fragments; - __le32 rx_unicast_octets; - __le32 rx_multicast_octets; - __le32 rx_fcs_errors; - __le32 rx_discards_no_buffer; - __le32 tx_discards_wrong_sa; - __le32 rx_discards_wep_undecryptable; - __le32 rx_message_in_msg_fragments; - __le32 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_scan_result_hdr { - __le16 reserved; - __le16 scan_reason; -#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ -#define HFA384X_SCAN_HOST_INITIATED 1 -#define HFA384X_SCAN_FIRMWARE_INITIATED 2 -#define HFA384X_SCAN_INQUIRY_FROM_HOST 3 -} __packed; - -#define HFA384X_SCAN_MAX_RESULTS 32 - -struct hfa384x_scan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; -} __packed; - -struct hfa384x_hostscan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; - __le16 atim; -} __packed; - -struct comm_tallies_sums { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_wep_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - - -struct hfa384x_regs { - u16 cmd; - u16 evstat; - u16 offset0; - u16 offset1; - u16 swsupport0; -}; - - -#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) -/* I/O ports for HFA384X Controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x02 -#define HFA384X_PARAM1_OFF 0x04 -#define HFA384X_PARAM2_OFF 0x06 -#define HFA384X_STATUS_OFF 0x08 -#define HFA384X_RESP0_OFF 0x0A -#define HFA384X_RESP1_OFF 0x0C -#define HFA384X_RESP2_OFF 0x0E -#define HFA384X_INFOFID_OFF 0x10 -#define HFA384X_CONTROL_OFF 0x14 -#define HFA384X_SELECT0_OFF 0x18 -#define HFA384X_SELECT1_OFF 0x1A -#define HFA384X_OFFSET0_OFF 0x1C -#define HFA384X_OFFSET1_OFF 0x1E -#define HFA384X_RXFID_OFF 0x20 -#define HFA384X_ALLOCFID_OFF 0x22 -#define HFA384X_TXCOMPLFID_OFF 0x24 -#define HFA384X_SWSUPPORT0_OFF 0x28 -#define HFA384X_SWSUPPORT1_OFF 0x2A -#define HFA384X_SWSUPPORT2_OFF 0x2C -#define HFA384X_EVSTAT_OFF 0x30 -#define HFA384X_INTEN_OFF 0x32 -#define HFA384X_EVACK_OFF 0x34 -#define HFA384X_DATA0_OFF 0x36 -#define HFA384X_DATA1_OFF 0x38 -#define HFA384X_AUXPAGE_OFF 0x3A -#define HFA384X_AUXOFFSET_OFF 0x3C -#define HFA384X_AUXDATA_OFF 0x3E -#endif /* PRISM2_PCCARD || PRISM2_PLX */ - -#ifdef PRISM2_PCI -/* Memory addresses for ISL3874 controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x04 -#define HFA384X_PARAM1_OFF 0x08 -#define HFA384X_PARAM2_OFF 0x0C -#define HFA384X_STATUS_OFF 0x10 -#define HFA384X_RESP0_OFF 0x14 -#define HFA384X_RESP1_OFF 0x18 -#define HFA384X_RESP2_OFF 0x1C -#define HFA384X_INFOFID_OFF 0x20 -#define HFA384X_CONTROL_OFF 0x28 -#define HFA384X_SELECT0_OFF 0x30 -#define HFA384X_SELECT1_OFF 0x34 -#define HFA384X_OFFSET0_OFF 0x38 -#define HFA384X_OFFSET1_OFF 0x3C -#define HFA384X_RXFID_OFF 0x40 -#define HFA384X_ALLOCFID_OFF 0x44 -#define HFA384X_TXCOMPLFID_OFF 0x48 -#define HFA384X_PCICOR_OFF 0x4C -#define HFA384X_SWSUPPORT0_OFF 0x50 -#define HFA384X_SWSUPPORT1_OFF 0x54 -#define HFA384X_SWSUPPORT2_OFF 0x58 -#define HFA384X_PCIHCR_OFF 0x5C -#define HFA384X_EVSTAT_OFF 0x60 -#define HFA384X_INTEN_OFF 0x64 -#define HFA384X_EVACK_OFF 0x68 -#define HFA384X_DATA0_OFF 0x6C -#define HFA384X_DATA1_OFF 0x70 -#define HFA384X_AUXPAGE_OFF 0x74 -#define HFA384X_AUXOFFSET_OFF 0x78 -#define HFA384X_AUXDATA_OFF 0x7C -#define HFA384X_PCI_M0_ADDRH_OFF 0x80 -#define HFA384X_PCI_M0_ADDRL_OFF 0x84 -#define HFA384X_PCI_M0_LEN_OFF 0x88 -#define HFA384X_PCI_M0_CTL_OFF 0x8C -#define HFA384X_PCI_STATUS_OFF 0x98 -#define HFA384X_PCI_M1_ADDRH_OFF 0xA0 -#define HFA384X_PCI_M1_ADDRL_OFF 0xA4 -#define HFA384X_PCI_M1_LEN_OFF 0xA8 -#define HFA384X_PCI_M1_CTL_OFF 0xAC - -/* PCI bus master control bits (these are undocumented; based on guessing and - * experimenting..) */ -#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) -#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) - -#endif /* PRISM2_PCI */ - - -/* Command codes for CMD reg. */ -#define HFA384X_CMDCODE_INIT 0x00 -#define HFA384X_CMDCODE_ENABLE 0x01 -#define HFA384X_CMDCODE_DISABLE 0x02 -#define HFA384X_CMDCODE_ALLOC 0x0A -#define HFA384X_CMDCODE_TRANSMIT 0x0B -#define HFA384X_CMDCODE_INQUIRE 0x11 -#define HFA384X_CMDCODE_ACCESS 0x21 -#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) -#define HFA384X_CMDCODE_DOWNLOAD 0x22 -#define HFA384X_CMDCODE_READMIF 0x30 -#define HFA384X_CMDCODE_WRITEMIF 0x31 -#define HFA384X_CMDCODE_TEST 0x38 - -#define HFA384X_CMDCODE_MASK 0x3F - -/* Test mode operations */ -#define HFA384X_TEST_CHANGE_CHANNEL 0x08 -#define HFA384X_TEST_MONITOR 0x0B -#define HFA384X_TEST_STOP 0x0F -#define HFA384X_TEST_CFG_BITS 0x15 -#define HFA384X_TEST_CFG_BIT_ALC BIT(3) - -#define HFA384X_CMD_BUSY BIT(15) - -#define HFA384X_CMD_TX_RECLAIM BIT(8) - -#define HFA384X_OFFSET_ERR BIT(14) -#define HFA384X_OFFSET_BUSY BIT(15) - - -/* ProgMode for download command */ -#define HFA384X_PROGMODE_DISABLE 0 -#define HFA384X_PROGMODE_ENABLE_VOLATILE 1 -#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 -#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 - -#define HFA384X_AUX_MAGIC0 0xfe01 -#define HFA384X_AUX_MAGIC1 0xdc23 -#define HFA384X_AUX_MAGIC2 0xba45 - -#define HFA384X_AUX_PORT_DISABLED 0 -#define HFA384X_AUX_PORT_DISABLE BIT(14) -#define HFA384X_AUX_PORT_ENABLE BIT(15) -#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) -#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) - -#define PRISM2_PDA_SIZE 1024 - - -/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ -#define HFA384X_EV_TICK BIT(15) -#define HFA384X_EV_WTERR BIT(14) -#define HFA384X_EV_INFDROP BIT(13) -#ifdef PRISM2_PCI -#define HFA384X_EV_PCI_M1 BIT(9) -#define HFA384X_EV_PCI_M0 BIT(8) -#endif /* PRISM2_PCI */ -#define HFA384X_EV_INFO BIT(7) -#define HFA384X_EV_DTIM BIT(5) -#define HFA384X_EV_CMD BIT(4) -#define HFA384X_EV_ALLOC BIT(3) -#define HFA384X_EV_TXEXC BIT(2) -#define HFA384X_EV_TX BIT(1) -#define HFA384X_EV_RX BIT(0) - - -/* HFA384X Information frames */ -#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ -#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ -#define HFA384X_INFO_COMMTALLIES 0xF100 -#define HFA384X_INFO_SCANRESULTS 0xF101 -#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ -#define HFA384X_INFO_HOSTSCANRESULTS 0xF103 -#define HFA384X_INFO_LINKSTATUS 0xF200 -#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ -#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ -#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ -#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ - -enum { HFA384X_LINKSTATUS_CONNECTED = 1, - HFA384X_LINKSTATUS_DISCONNECTED = 2, - HFA384X_LINKSTATUS_AP_CHANGE = 3, - HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, - HFA384X_LINKSTATUS_AP_IN_RANGE = 5, - HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; - -enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, - HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, - HFA384X_PORTTYPE_HOSTAP = 6 }; - -#define HFA384X_RATES_1MBPS BIT(0) -#define HFA384X_RATES_2MBPS BIT(1) -#define HFA384X_RATES_5MBPS BIT(2) -#define HFA384X_RATES_11MBPS BIT(3) - -#define HFA384X_ROAMING_FIRMWARE 1 -#define HFA384X_ROAMING_HOST 2 -#define HFA384X_ROAMING_DISABLED 3 - -#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) -#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) -#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) -#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) - -#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) -#define HFA384X_RX_STATUS_PCF BIT(12) -#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) -#define HFA384X_RX_STATUS_UNDECR BIT(1) -#define HFA384X_RX_STATUS_FCSERR BIT(0) - -#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ -(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) -#define HFA384X_RX_STATUS_GET_MACPORT(s) \ -(((s) & HFA384X_RX_STATUS_MACPORT) >> 8) - -enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, - HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; - - -#define HFA384X_TX_CTRL_ALT_RTRY BIT(5) -#define HFA384X_TX_CTRL_802_11 BIT(3) -#define HFA384X_TX_CTRL_802_3 0 -#define HFA384X_TX_CTRL_TX_EX BIT(2) -#define HFA384X_TX_CTRL_TX_OK BIT(1) - -#define HFA384X_TX_STATUS_RETRYERR BIT(0) -#define HFA384X_TX_STATUS_AGEDERR BIT(1) -#define HFA384X_TX_STATUS_DISCON BIT(2) -#define HFA384X_TX_STATUS_FORMERR BIT(3) - -/* HFA3861/3863 (BBP) Control Registers */ -#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ -#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ -#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ -#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ -#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ - - -#ifdef __KERNEL__ - -#define PRISM2_TXFID_COUNT 8 -#define PRISM2_DATA_MAXLEN 2304 -#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) -#define PRISM2_TXFID_EMPTY 0xffff -#define PRISM2_TXFID_RESERVED 0xfffe -#define PRISM2_DUMMY_FID 0xffff -#define MAX_SSID_LEN 32 -#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ - -#define PRISM2_DUMP_RX_HDR BIT(0) -#define PRISM2_DUMP_TX_HDR BIT(1) -#define PRISM2_DUMP_TXEXC_HDR BIT(2) - -struct hostap_tx_callback_info { - u16 idx; - void (*func)(struct sk_buff *, int ok, void *); - void *data; - struct hostap_tx_callback_info *next; -}; - - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define PRISM2_FRAG_CACHE_LEN 4 - -struct prism2_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - - -struct hostap_cmd_queue { - struct list_head list; - wait_queue_head_t compl; - volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; - void (*callback)(struct net_device *dev, long context, u16 resp0, - u16 res); - long context; - u16 cmd, param0, param1; - u16 resp0, res; - volatile int issued, issuing; - - refcount_t usecnt; - int del_req; -}; - -/* options for hw_shutdown */ -#define HOSTAP_HW_NO_DISABLE BIT(0) -#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) - -typedef struct local_info local_info_t; - -struct prism2_helper_functions { - /* these functions are defined in hardware model specific files - * (hostap_{cs,plx,pci}.c */ - int (*card_present)(local_info_t *local); - void (*cor_sreset)(local_info_t *local); - void (*genesis_reset)(local_info_t *local, int hcr); - - /* the following functions are from hostap_hw.c, but they may have some - * hardware model specific code */ - - /* FIX: low-level commands like cmd might disappear at some point to - * make it easier to change them if needed (e.g., cmd would be replaced - * with write_mif/read_mif/testcmd/inquire); at least get_rid and - * set_rid might move to hostap_{cs,plx,pci}.c */ - int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, - u16 *resp0); - void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); - int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len); - int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); - int (*hw_enable)(struct net_device *dev, int initial); - int (*hw_config)(struct net_device *dev, int initial); - void (*hw_reset)(struct net_device *dev); - void (*hw_shutdown)(struct net_device *dev, int no_disable); - int (*reset_port)(struct net_device *dev); - void (*schedule_reset)(local_info_t *local); - int (*download)(local_info_t *local, - struct prism2_download_param *param); - int (*tx)(struct sk_buff *skb, struct net_device *dev); - int (*set_tim)(struct net_device *dev, int aid, int set); - const struct proc_ops *read_aux_proc_ops; - - int need_tx_headroom; /* number of bytes of headroom needed before - * IEEE 802.11 header */ - enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; -}; - - -struct prism2_download_data { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_data_area { - u32 addr; /* wlan card address */ - u32 len; - u8 *data; /* allocated data */ - } data[] __counted_by(num_areas); -}; - - -#define HOSTAP_MAX_BSS_COUNT 64 -#define MAX_WPA_IE_LEN 64 - -struct hostap_bss_info { - struct list_head list; - unsigned long last_update; - unsigned int count; - u8 bssid[ETH_ALEN]; - u16 capab_info; - u8 ssid[32]; - size_t ssid_len; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - int chan; - int included; -}; - - -/* Per radio private Host AP data - shared by all net devices interfaces used - * by each radio (wlan#, wlan#ap, wlan#sta, WDS). - * ((struct hostap_interface *) netdev_priv(dev))->local points to this - * structure. */ -struct local_info { - struct module *hw_module; - int card_idx; - int dev_enabled; - int master_dev_auto_open; /* was master device opened automatically */ - int num_dev_open; /* number of open devices */ - struct net_device *dev; /* master radio device */ - struct net_device *ddev; /* main data device */ - struct list_head hostap_interfaces; /* Host AP interface list (contains - * struct hostap_interface entries) - */ - rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock - * when removing entries from the list. - * TX and RX paths can use read lock. */ - spinlock_t cmdlock, baplock, lock, irq_init_lock; - struct mutex rid_bap_mtx; - u16 infofid; /* MAC buffer id for info frame */ - /* txfid, intransmitfid, next_txtid, and next_alloc are protected by - * txfidlock */ - spinlock_t txfidlock; - int txfid_len; /* length of allocated TX buffers */ - u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ - /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if - * corresponding txfid is free for next TX frame */ - u16 intransmitfid[PRISM2_TXFID_COUNT]; - int next_txfid; /* index to the next txfid to be checked for - * availability */ - int next_alloc; /* index to the next intransmitfid to be checked for - * allocation events */ - - /* bitfield for atomic bitops */ -#define HOSTAP_BITS_TRANSMIT 0 -#define HOSTAP_BITS_BAP_TASKLET 1 -#define HOSTAP_BITS_BAP_TASKLET2 2 - unsigned long bits; - - struct ap_data *ap; - - char essid[MAX_SSID_LEN + 1]; - char name[MAX_NAME_LEN + 1]; - int name_set; - u16 channel_mask; /* mask of allowed channels */ - u16 scan_channel_mask; /* mask of channels to be scanned */ - struct comm_tallies_sums comm_tallies; - struct proc_dir_entry *proc; - int iw_mode; /* operating mode (IW_MODE_*) */ - int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS - * 1: IW_MODE_ADHOC is "pseudo IBSS" */ - char bssid[ETH_ALEN]; - int channel; - int beacon_int; - int dtim_period; - int mtu; - int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ - int fw_tx_rate_control; - u16 tx_rate_control; - u16 basic_rates; - int hw_resetting; - int hw_ready; - int hw_reset_tries; /* how many times reset has been tried */ - int hw_downloading; - int shutdown; - int pri_only; - int no_pri; /* no PRI f/w present */ - int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ - - enum { - PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, - PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN - } txpower_type; - int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ - - /* command queue for hfa384x_cmd(); protected with cmdlock */ - struct list_head cmd_queue; - /* max_len for cmd_queue; in addition, cmd_callback can use two - * additional entries to prevent sleeping commands from stopping - * transmits */ -#define HOSTAP_CMD_QUEUE_MAX_LEN 16 - int cmd_queue_len; /* number of entries in cmd_queue */ - - /* if card timeout is detected in interrupt context, reset_queue is - * used to schedule card reseting to be done in user context */ - struct work_struct reset_queue; - - /* For scheduling a change of the promiscuous mode RID */ - int is_promisc; - struct work_struct set_multicast_list_queue; - - struct work_struct set_tim_queue; - struct list_head set_tim_list; - spinlock_t set_tim_lock; - - int wds_max_connections; - int wds_connections; -#define HOSTAP_WDS_BROADCAST_RA BIT(0) -#define HOSTAP_WDS_AP_CLIENT BIT(1) -#define HOSTAP_WDS_STANDARD_FRAME BIT(2) - u32 wds_type; - u16 tx_control; /* flags to be used in TX description */ - int manual_retry_count; /* -1 = use f/w default; otherwise retry count - * to be used with all frames */ - - struct iw_statistics wstats; - unsigned long scan_timestamp; /* Time started to scan */ - enum { - PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 - } monitor_type; - int monitor_allow_fcserr; - - int hostapd; /* whether user space daemon, hostapd, is used for AP - * management */ - int hostapd_sta; /* whether hostapd is used with an extra STA interface - */ - struct net_device *apdev; - struct net_device_stats apdevstats; - - char assoc_ap_addr[ETH_ALEN]; - struct net_device *stadev; - struct net_device_stats stadevstats; - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 - struct lib80211_crypt_info crypt_info; - - int open_wep; /* allow unencrypted frames */ - int host_encrypt; - int host_decrypt; - int privacy_invoked; /* force privacy invoked flag even if no keys are - * configured */ - int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working - * in Host AP mode (STA f/w 1.4.9 or newer) */ - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; - unsigned int frag_next_idx; - - int ieee_802_1x; /* is IEEE 802.1X used */ - - int antsel_tx, antsel_rx; - int rts_threshold; /* dot11RTSThreshold */ - int fragm_threshold; /* dot11FragmentationThreshold */ - int auth_algs; /* PRISM2_AUTH_ flags */ - - int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ - int tallies32; /* 32-bit tallies in use */ - - struct prism2_helper_functions *func; - - u8 *pda; - int fw_ap; -#define PRISM2_FW_VER(major, minor, variant) \ -(((major) << 16) | ((minor) << 8) | variant) - u32 sta_fw_ver; - - /* Tasklets for handling hardware IRQ related operations outside hw IRQ - * handler */ - struct tasklet_struct bap_tasklet; - - struct tasklet_struct info_tasklet; - struct sk_buff_head info_list; /* info frames as skb's for - * info_tasklet */ - - struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks - */ - - struct tasklet_struct rx_tasklet; - struct sk_buff_head rx_list; - - struct tasklet_struct sta_tx_exc_tasklet; - struct sk_buff_head sta_tx_exc_list; - - int host_roaming; - unsigned long last_join_time; /* time of last JoinRequest */ - struct hfa384x_hostscan_result *last_scan_results; - int last_scan_results_count; - enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; - struct work_struct info_queue; - unsigned long pending_info; /* bit field of pending info_queue items */ -#define PRISM2_INFO_PENDING_LINKSTATUS 0 -#define PRISM2_INFO_PENDING_SCANRESULTS 1 - int prev_link_status; /* previous received LinkStatus info */ - int prev_linkstatus_connected; - u8 preferred_ap[ETH_ALEN]; /* use this AP if possible */ - -#ifdef PRISM2_CALLBACK - void *callback_data; /* Can be used in callbacks; e.g., allocate - * on enable event and free on disable event. - * Host AP driver code does not touch this. */ -#endif /* PRISM2_CALLBACK */ - - wait_queue_head_t hostscan_wq; - - /* Passive scan in Host AP mode */ - struct timer_list passive_scan_timer; - int passive_scan_interval; /* in seconds, 0 = disabled */ - int passive_scan_channel; - enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; - - struct timer_list tick_timer; - unsigned long last_tick_timer; - unsigned int sw_tick_stuck; - - /* commsQuality / dBmCommsQuality data from periodic polling; only - * valid for Managed and Ad-hoc modes */ - unsigned long last_comms_qual_update; - int comms_qual; /* in some odd unit.. */ - int avg_signal; /* in dB (note: negative) */ - int avg_noise; /* in dB (note: negative) */ - struct work_struct comms_qual_update; - - /* RSSI to dBm adjustment (for RX descriptor fields) */ - int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */ - - /* BSS list / protected by local->lock */ - struct list_head bss_list; - int num_bss_info; - int wpa; /* WPA support enabled */ - int tkip_countermeasures; - int drop_unencrypted; - /* Generic IEEE 802.11 info element to be added to - * ProbeResp/Beacon/(Re)AssocReq */ - u8 *generic_elem; - size_t generic_elem_len; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - /* Persistent volatile download data */ - struct prism2_download_data *dl_pri; - struct prism2_download_data *dl_sec; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_IO_DEBUG -#define PRISM2_IO_DEBUG_SIZE 10000 - u32 io_debug[PRISM2_IO_DEBUG_SIZE]; - int io_debug_head; - int io_debug_enabled; -#endif /* PRISM2_IO_DEBUG */ - - /* Pointer to hardware model specific (cs,pci,plx) private data. */ - void *hw_priv; -}; - - -/* Per interface private Host AP data - * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, - * WDS) and netdev_priv(dev) points to this structure. */ -struct hostap_interface { - struct list_head list; /* list entry in Host AP interface list */ - struct net_device *dev; /* pointer to this device */ - struct local_info *local; /* pointer to shared private data */ - struct net_device_stats stats; - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; - - enum { - HOSTAP_INTERFACE_MASTER, - HOSTAP_INTERFACE_MAIN, - HOSTAP_INTERFACE_AP, - HOSTAP_INTERFACE_STA, - HOSTAP_INTERFACE_WDS, - } type; - - union { - struct hostap_interface_wds { - u8 remote_addr[ETH_ALEN]; - } wds; - } u; -}; - - -#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 - -/* - * TX meta data - stored in skb->cb buffer, so this must not be increased over - * the 48-byte limit. - * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE - * TO SEE THE DAY. - */ -struct hostap_skb_tx_data { - unsigned int __padding_for_default_qdiscs; - u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ - u8 rate; /* transmit rate */ -#define HOSTAP_TX_FLAGS_WDS BIT(0) -#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1) -#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2) - u8 flags; /* HOSTAP_TX_FLAGS_* */ - u16 tx_cb_idx; - struct hostap_interface *iface; - unsigned long jiffies; /* queueing timestamp */ - unsigned short ethertype; -}; - - -#ifndef PRISM2_NO_DEBUG - -#define DEBUG_FID BIT(0) -#define DEBUG_PS BIT(1) -#define DEBUG_FLOW BIT(2) -#define DEBUG_AP BIT(3) -#define DEBUG_HW BIT(4) -#define DEBUG_EXTRA BIT(5) -#define DEBUG_EXTRA2 BIT(6) -#define DEBUG_PS2 BIT(7) -#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) -#define PDEBUG(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) -#define PDEBUG2(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(args); } while (0) - -#else /* PRISM2_NO_DEBUG */ - -#define PDEBUG(n, args...) -#define PDEBUG2(n, args...) - -#endif /* PRISM2_NO_DEBUG */ - -enum { BAP0 = 0, BAP1 = 1 }; - -#define PRISM2_IO_DEBUG_CMD_INB 0 -#define PRISM2_IO_DEBUG_CMD_INW 1 -#define PRISM2_IO_DEBUG_CMD_INSW 2 -#define PRISM2_IO_DEBUG_CMD_OUTB 3 -#define PRISM2_IO_DEBUG_CMD_OUTW 4 -#define PRISM2_IO_DEBUG_CMD_OUTSW 5 -#define PRISM2_IO_DEBUG_CMD_ERROR 6 -#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 - -#ifdef PRISM2_IO_DEBUG - -#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ -(((cmd) << 24) | ((reg) << 16) | value) - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - if (!local->io_debug_enabled) - return; - - local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; - local->io_debug[local->io_debug_head] = - PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; -} - - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - unsigned long flags; - - if (!local->io_debug_enabled) - return; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); - if (local->io_debug_enabled == 1) { - local->io_debug_enabled = 0; - printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); - } - spin_unlock_irqrestore(&local->lock, flags); -} - -#else /* PRISM2_IO_DEBUG */ - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ -} - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ -} - -#endif /* PRISM2_IO_DEBUG */ - - -#ifdef PRISM2_CALLBACK -enum { - /* Called when card is enabled */ - PRISM2_CALLBACK_ENABLE, - - /* Called when card is disabled */ - PRISM2_CALLBACK_DISABLE, - - /* Called when RX/TX starts/ends */ - PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, - PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END -}; -void prism2_callback(local_info_t *local, int event); -#else /* PRISM2_CALLBACK */ -#define prism2_callback(d, e) do { } while (0) -#endif /* PRISM2_CALLBACK */ - -#endif /* __KERNEL__ */ - -#endif /* HOSTAP_WLAN_H */ From 757a46c2a7a99a4e12f6a267e945c98324c41702 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:47 +0200 Subject: [PATCH 0156/7721] wifi: remove orphaned zd1201 driver This is a wireless extensions style driver for 802.11b USB dongles, with partial support for cfg80211 interfaces. As these are all external dongles, there are probably few users that have not yet replaced them with cheap 802.11n devices that work better. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 6 - drivers/net/wireless/zydas/Kconfig | 19 - drivers/net/wireless/zydas/Makefile | 2 - drivers/net/wireless/zydas/zd1201.c | 1909 --------------------------- drivers/net/wireless/zydas/zd1201.h | 144 -- 5 files changed, 2080 deletions(-) delete mode 100644 drivers/net/wireless/zydas/zd1201.c delete mode 100644 drivers/net/wireless/zydas/zd1201.h diff --git a/MAINTAINERS b/MAINTAINERS index 53aac5fa5de1..2ada93d4cee4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22441,12 +22441,6 @@ S: Supported F: drivers/usb/host/pci-quirks* F: drivers/usb/host/xhci* -USB ZD1201 DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://linux-lc100020.sourceforge.net -F: drivers/net/wireless/zydas/zd1201.* - USER DATAGRAM PROTOCOL (UDP) M: Willem de Bruijn S: Maintained diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig index 08574433df66..839e1217e855 100644 --- a/drivers/net/wireless/zydas/Kconfig +++ b/drivers/net/wireless/zydas/Kconfig @@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS if WLAN_VENDOR_ZYDAS -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on CFG80211 && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - source "drivers/net/wireless/zydas/zd1211rw/Kconfig" endif # WLAN_VENDOR_ZYDAS diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile index c70003d30a8f..3e0a51db9874 100644 --- a/drivers/net/wireless/zydas/Makefile +++ b/drivers/net/wireless/zydas/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_ZD1211RW) += zd1211rw/ - -obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c deleted file mode 100644 index 2814df1ecc78..000000000000 --- a/drivers/net/wireless/zydas/zd1201.c +++ /dev/null @@ -1,1909 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for ZyDAS zd1201 based USB wireless devices. - * - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. They also made documentation available, thanks! - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "zd1201.h" - -static const struct usb_device_id zd1201_table[] = { - {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */ - {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */ - {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ - {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ - {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ - {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ - {} -}; - -static int ap; /* Are we an AP or a normal station? */ - -#define ZD1201_VERSION "0.15" - -MODULE_AUTHOR("Jeroen Vreeken "); -MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); -MODULE_VERSION(ZD1201_VERSION); -MODULE_LICENSE("GPL"); -module_param(ap, int, 0); -MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); -MODULE_DEVICE_TABLE(usb, zd1201_table); - - -static int zd1201_fw_upload(struct usb_device *dev, int apfw) -{ - const struct firmware *fw_entry; - const char *data; - unsigned long len; - int err; - unsigned char ret; - char *buf; - char *fwfile; - - if (apfw) - fwfile = "zd1201-ap.fw"; - else - fwfile = "zd1201.fw"; - - err = request_firmware(&fw_entry, fwfile, &dev->dev); - if (err) { - dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); - dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); - dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); - return err; - } - - data = fw_entry->data; - len = fw_entry->size; - - buf = kmalloc(1024, GFP_ATOMIC); - if (!buf) { - err = -ENOMEM; - goto exit; - } - - while (len > 0) { - int translen = (len > 1024) ? 1024 : len; - memcpy(buf, data, translen); - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, - USB_DIR_OUT | 0x40, 0, 0, buf, translen, - ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - len -= translen; - data += translen; - } - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, - USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, - USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - memcpy(&ret, buf, sizeof(ret)); - - if (ret & 0x80) { - err = -EIO; - goto exit; - } - - err = 0; -exit: - kfree(buf); - release_firmware(fw_entry); - return err; -} - -MODULE_FIRMWARE("zd1201-ap.fw"); -MODULE_FIRMWARE("zd1201.fw"); - -static void zd1201_usbfree(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", - zd->dev->name, urb->status); - } - - kfree(urb->transfer_buffer); - usb_free_urb(urb); -} - -/* cmdreq message: - u32 type - u16 cmd - u16 parm0 - u16 parm1 - u16 parm2 - u8 pad[4] - - total: 4 + 2 + 2 + 2 + 2 + 4 = 16 -*/ -static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, - int parm1, int parm2) -{ - unsigned char *command; - int ret; - struct urb *urb; - - command = kmalloc(16, GFP_ATOMIC); - if (!command) - return -ENOMEM; - - *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&command[4]) = cpu_to_le16(cmd); - *((__le16*)&command[6]) = cpu_to_le16(parm0); - *((__le16*)&command[8]) = cpu_to_le16(parm1); - *((__le16*)&command[10])= cpu_to_le16(parm2); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(command); - return -ENOMEM; - } - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - command, 16, zd1201_usbfree, zd); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree(command); - usb_free_urb(urb); - } - - return ret; -} - -/* Callback after sending out a packet */ -static void zd1201_usbtx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - netif_wake_queue(zd->dev); -} - -/* Incoming data */ -static void zd1201_usbrx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - int free = 0; - unsigned char *data = urb->transfer_buffer; - struct sk_buff *skb; - unsigned char type; - - if (!zd) - return; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", - zd->dev->name, urb->status); - free = 1; - goto exit; - } - - if (urb->status != 0 || urb->actual_length == 0) - goto resubmit; - - type = data[0]; - if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { - memcpy(zd->rxdata, data, urb->actual_length); - zd->rxlen = urb->actual_length; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - /* Info frame */ - if (type == ZD1201_PACKET_INQUIRE) { - int i = 0; - unsigned short infotype, copylen; - infotype = le16_to_cpu(*(__le16*)&data[6]); - - if (infotype == ZD1201_INF_LINKSTATUS) { - short linkstatus; - - linkstatus = le16_to_cpu(*(__le16*)&data[8]); - switch(linkstatus) { - case 1: - netif_carrier_on(zd->dev); - break; - case 2: - netif_carrier_off(zd->dev); - break; - case 3: - netif_carrier_off(zd->dev); - break; - case 4: - netif_carrier_on(zd->dev); - break; - default: - netif_carrier_off(zd->dev); - } - goto resubmit; - } - if (infotype == ZD1201_INF_ASSOCSTATUS) { - short status = le16_to_cpu(*(__le16*)(data+8)); - int event; - union iwreq_data wrqu; - - switch (status) { - case ZD1201_ASSOCSTATUS_STAASSOC: - case ZD1201_ASSOCSTATUS_REASSOC: - event = IWEVREGISTERED; - break; - case ZD1201_ASSOCSTATUS_DISASSOC: - case ZD1201_ASSOCSTATUS_ASSOCFAIL: - case ZD1201_ASSOCSTATUS_AUTHFAIL: - default: - event = IWEVEXPIRED; - } - memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(zd->dev, event, &wrqu, NULL); - - goto resubmit; - } - if (infotype == ZD1201_INF_AUTHREQ) { - union iwreq_data wrqu; - - memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - /* There isn't a event that trully fits this request. - We assume that userspace will be smart enough to - see a new station being expired and sends back a - authstation ioctl to authorize it. */ - wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); - goto resubmit; - } - /* Other infotypes are handled outside this handler */ - zd->rxlen = 0; - while (i < urb->actual_length) { - copylen = le16_to_cpu(*(__le16*)&data[i+2]); - /* Sanity check, sometimes we get junk */ - if (copylen+zd->rxlen > sizeof(zd->rxdata)) - break; - memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); - zd->rxlen += copylen; - i += 64; - } - if (i >= urb->actual_length) { - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - goto resubmit; - } - /* Actual data */ - if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { - int datalen = urb->actual_length-1; - unsigned short len, fc, seq; - - len = ntohs(*(__be16 *)&data[datalen-2]); - if (len>datalen) - len=datalen; - fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); - seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); - - if (zd->monitor) { - if (datalen < 24) - goto resubmit; - if (!(skb = dev_alloc_skb(datalen+24))) - goto resubmit; - - skb_put_data(skb, &data[datalen - 16], 2); - skb_put_data(skb, &data[datalen - 2], 2); - skb_put_data(skb, &data[datalen - 14], 6); - skb_put_data(skb, &data[datalen - 22], 6); - skb_put_data(skb, &data[datalen - 8], 6); - skb_put_data(skb, &data[datalen - 24], 2); - skb_put_data(skb, data, len); - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - goto resubmit; - } - - if ((seq & IEEE80211_SCTL_FRAG) || - (fc & IEEE80211_FCTL_MOREFRAGS)) { - struct zd1201_frag *frag = NULL; - char *ptr; - - if (datalen<14) - goto resubmit; - if ((seq & IEEE80211_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(*frag), GFP_ATOMIC); - if (!frag) - goto resubmit; - skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); - if (!skb) { - kfree(frag); - goto resubmit; - } - frag->skb = skb; - frag->seq = seq & IEEE80211_SCTL_SEQ; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - hlist_add_head(&frag->fnode, &zd->fraglist); - goto resubmit; - } - hlist_for_each_entry(frag, &zd->fraglist, fnode) - if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) - break; - if (!frag) - goto resubmit; - skb = frag->skb; - ptr = skb_put(skb, len); - if (ptr) - memcpy(ptr, data+8, len); - if (fc & IEEE80211_FCTL_MOREFRAGS) - goto resubmit; - hlist_del_init(&frag->fnode); - kfree(frag); - } else { - if (datalen<14) - goto resubmit; - skb = dev_alloc_skb(len + 14 + 2); - if (!skb) - goto resubmit; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - } - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -resubmit: - memset(data, 0, ZD1201_RXSIZE); - - urb->status = 0; - urb->dev = zd->usb; - if(usb_submit_urb(urb, GFP_ATOMIC)) - free = 1; - -exit: - if (free) { - zd->rxlen = 0; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - kfree(urb->transfer_buffer); - } -} - -static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, - unsigned int riddatalen) -{ - int err; - int i = 0; - int code; - int rid_fid; - int length; - unsigned char *pdata; - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); - rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); - length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); - if (length > zd->rxlen) - length = zd->rxlen-6; - - /* If access bit is not on, then error */ - if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) - return -EINVAL; - - /* Not enough buffer for allocating data */ - if (riddatalen != (length - 4)) { - dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", - riddatalen, zd->rxlen, length, rid, rid_fid); - return -ENODATA; - } - - zd->rxdatas = 0; - /* Issue SetRxRid commnd */ - err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); - if (err) - return err; - - /* Receive RID record from resource packets */ - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { - dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", - zd->rxdata[zd->rxlen-1]); - return -EINVAL; - } - - /* Set the data pointer and received data length */ - pdata = zd->rxdata; - length = zd->rxlen; - - do { - int actual_length; - - actual_length = (length > 64) ? 64 : length; - - if (pdata[0] != 0x3) { - dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", - pdata[0]); - return -EINVAL; - } - - if (actual_length != 64) { - /* Trim the last packet type byte */ - actual_length--; - } - - /* Skip the 4 bytes header (RID length and RID) */ - if (i == 0) { - pdata += 8; - actual_length -= 8; - } else { - pdata += 4; - actual_length -= 4; - } - - memcpy(riddata, pdata, actual_length); - riddata += actual_length; - pdata += actual_length; - length -= 64; - i++; - } while (length > 0); - - return 0; -} - -/* - * resreq: - * byte type - * byte sequence - * u16 reserved - * byte data[12] - * total: 16 - */ -static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait) -{ - int err; - unsigned char *request; - int reqlen; - char seq=0; - struct urb *urb; - gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; - - len += 4; /* first 4 are for header */ - - zd->rxdatas = 0; - zd->rxlen = 0; - for (seq=0; len > 0; seq++) { - request = kzalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - reqlen = len>12 ? 12 : len; - request[0] = ZD1201_USB_RESREQ; - request[1] = seq; - request[2] = 0; - request[3] = 0; - if (request[1] == 0) { - /* add header */ - *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); - *(__le16*)&request[6] = cpu_to_le16(rid); - memcpy(request+8, buf, reqlen-4); - buf += reqlen-4; - } else { - memcpy(request+4, buf, reqlen); - buf += reqlen; - } - - len -= reqlen; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, - zd->endp_out2), request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - } - - request = kmalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&request[4]) = - cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); - *((__le16*)&request[6]) = cpu_to_le16(rid); - *((__le16*)&request[8]) = cpu_to_le16(0); - *((__le16*)&request[10]) = cpu_to_le16(0); - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - - if (wait) { - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { - dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); - } - } - - return 0; -err: - kfree(request); - usb_free_urb(urb); - return err; -} - -static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) -{ - int err; - __le16 zdval; - - err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); - if (err) - return err; - *val = le16_to_cpu(zdval); - return 0; -} - -static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) -{ - __le16 zdval = cpu_to_le16(val); - return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); -} - -static int zd1201_drvr_start(struct zd1201 *zd) -{ - int err, i; - short max; - __le16 zdmax; - unsigned char *buffer; - - buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - usb_fill_bulk_urb(zd->rx_urb, zd->usb, - usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, - zd1201_usbrx, zd); - - err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); - if (err) - goto err_buffer; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); - if (err) - goto err_urb; - - err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, - sizeof(__le16)); - if (err) - goto err_urb; - - max = le16_to_cpu(zdmax); - for (i=0; irx_urb); - return err; -err_buffer: - kfree(buffer); - return err; -} - -/* Magic alert: The firmware doesn't seem to like the MAC state being - * toggled in promisc (aka monitor) mode. - * (It works a number of times, but will halt eventually) - * So we turn it of before disabling and on after enabling if needed. - */ -static int zd1201_enable(struct zd1201 *zd) -{ - int err; - - if (zd->mac_enabled) - return 0; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 1; - - if (zd->monitor) - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); - - return err; -} - -static int zd1201_disable(struct zd1201 *zd) -{ - int err; - - if (!zd->mac_enabled) - return 0; - if (zd->monitor) { - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - } - - err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 0; - return err; -} - -static int zd1201_mac_reset(struct zd1201 *zd) -{ - if (!zd->mac_enabled) - return 0; - zd1201_disable(zd); - return zd1201_enable(zd); -} - -static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) -{ - int err, val; - char buf[IW_ESSID_MAX_SIZE+2]; - - err = zd1201_disable(zd); - if (err) - return err; - - val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); - if (err) - return err; - - *(__le16 *)buf = cpu_to_le16(essidlen); - memcpy(buf+2, essid, essidlen); - if (!zd->ap) { /* Normal station */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } else { /* AP */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len, 1); - if (err) - return err; - - err = zd1201_enable(zd); - if (err) - return err; - - msleep(100); - return 0; -} - -static int zd1201_net_open(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - /* Start MAC with wildcard if no essid set */ - if (!zd->mac_enabled) - zd1201_join(zd, zd->essid, zd->essidlen); - netif_start_queue(dev); - - return 0; -} - -static int zd1201_net_stop(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -/* - RFC 1042 encapsulates Ethernet frames in 802.11 frames - by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 - (0x00, 0x00, 0x00). Zd requires an additional padding, copy - of ethernet addresses, length of the standard RFC 1042 packet - and a command byte (which is nul for tx). - - tx frame (from Wlan NG): - RFC 1042: - llc 0xAA 0xAA 0x03 (802.2 LLC) - snap 0x00 0x00 0x00 (Ethernet encapsulated) - type 2 bytes, Ethernet type field - payload (minus eth header) - Zydas specific: - padding 1B if (skb->len+8+1)%64==0 - Eth MAC addr 12 bytes, Ethernet MAC addresses - length 2 bytes, RFC 1042 packet length - (llc+snap+type+payload) - zd 1 null byte, zd1201 packet type - */ -static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - unsigned char *txbuf = zd->txdata; - int txbuflen, pad = 0, err; - struct urb *urb = zd->tx_urb; - - if (!zd->mac_enabled || zd->monitor) { - dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - - txbuflen = skb->len + 8 + 1; - if (txbuflen%64 == 0) { - pad = 1; - txbuflen++; - } - txbuf[0] = 0xAA; - txbuf[1] = 0xAA; - txbuf[2] = 0x03; - txbuf[3] = 0x00; /* rfc1042 */ - txbuf[4] = 0x00; - txbuf[5] = 0x00; - - skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); - if (pad) - txbuf[skb->len-12+6]=0; - skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); - *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); - txbuf[txbuflen-1] = 0; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), - txbuf, txbuflen, zd1201_usbtx, zd); - - err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); - if (err) { - dev->stats.tx_errors++; - netif_start_queue(dev); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - } - kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct zd1201 *zd = netdev_priv(dev); - - if (!zd) - return; - dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", - dev->name); - usb_unlink_urb(zd->tx_urb); - dev->stats.tx_errors++; - /* Restart the timeout to quiet the watchdog: */ - netif_trans_update(dev); /* prevent tx timeout */ -} - -static int zd1201_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - struct zd1201 *zd = netdev_priv(dev); - int err; - - if (!zd) - return -ENODEV; - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - addr->sa_data, dev->addr_len, 1); - if (err) - return err; - eth_hw_addr_set(dev, addr->sa_data); - - return zd1201_mac_reset(zd); -} - -static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - return &zd->iwstats; -} - -static void zd1201_set_multicast(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; - int i; - - if (netdev_mc_count(dev) > ZD1201_MAXMULTI) - return; - - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); - zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - netdev_mc_count(dev) * ETH_ALEN, 0); -} - -static int zd1201_config_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct zd1201 *zd = netdev_priv(dev); - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11b"); - return 0; -} - -static int zd1201_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel = 0; - int err; - - if (freq->e == 0) - channel = freq->m; - else - channel = ieee80211_frequency_to_channel(freq->m); - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); - if (err) - return err; - - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); - if (err) - return err; - freq->e = 0; - freq->m = channel; - - return 0; -} - -static int zd1201_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype, monitor = 0; - unsigned char buffer[IW_ESSID_MAX_SIZE+2]; - int err; - - if (zd->ap) { - if (*mode != IW_MODE_MASTER) - return -EINVAL; - return 0; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - zd->dev->type = ARPHRD_ETHER; - switch(*mode) { - case IW_MODE_MONITOR: - monitor = 1; - zd->dev->type = ARPHRD_IEEE80211; - /* Make sure we are no longer associated with by - setting an 'impossible' essid. - (otherwise we mess up firmware) - */ - zd1201_join(zd, "\0-*#\0", 5); - /* Put port in pIBSS */ - fallthrough; - case 8: /* No pseudo-IBSS in wireless extensions (yet) */ - porttype = ZD1201_PORTTYPE_PSEUDOIBSS; - break; - case IW_MODE_ADHOC: - porttype = ZD1201_PORTTYPE_IBSS; - break; - case IW_MODE_INFRA: - porttype = ZD1201_PORTTYPE_BSS; - break; - default: - return -EINVAL; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - return err; - if (zd->monitor && !monitor) { - zd1201_disable(zd); - *(__le16 *)buffer = cpu_to_le16(zd->essidlen); - memcpy(buffer+2, zd->essid, zd->essidlen); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, - buffer, IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - zd->monitor = monitor; - /* If monitor mode is set we don't actually turn it on here since it - * is done during mac reset anyway (see zd1201_mac_enable). - */ - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); - if (err) - return err; - switch(porttype) { - case ZD1201_PORTTYPE_IBSS: - *mode = IW_MODE_ADHOC; - break; - case ZD1201_PORTTYPE_BSS: - *mode = IW_MODE_INFRA; - break; - case ZD1201_PORTTYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case ZD1201_PORTTYPE_PSEUDOIBSS: - *mode = 8;/* No Pseudo-IBSS... */ - break; - case ZD1201_PORTTYPE_AP: - *mode = IW_MODE_MASTER; - break; - default: - dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", - porttype); - *mode = IW_MODE_AUTO; - } - if (zd->monitor) - *mode = IW_MODE_MONITOR; - - return 0; -} - -static int zd1201_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *wrq = &wrqu->data; - struct iw_range *range = (struct iw_range *)extra; - - wrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->max_qual.qual = 128; - range->max_qual.level = 128; - range->max_qual.noise = 128; - range->max_qual.updated = 7; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = ZD1201_NUMKEYS; - - range->num_bitrates = 4; - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - - range->min_rts = 0; - range->min_frag = ZD1201_FRAGMIN; - range->max_rts = ZD1201_RTSMAX; - range->min_frag = ZD1201_FRAGMAX; - - return 0; -} - -/* Little bit of magic here: we only get the quality if we poll - * for it, and we never get an actual request to trigger such - * a poll. Therefore we 'assume' that the user will soon ask for - * the stats after asking the bssid. - */ -static int zd1201_get_wap(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[6]; - - if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { - /* Unfortunately the quality and noise reported is useless. - they seem to be accumulators that increase until you - read them, unless we poll on a fixed interval we can't - use them - */ - /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ - zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); - /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ - zd->iwstats.qual.updated = 2; - } - - return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); -} - -static int zd1201_set_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* We do everything in get_scan */ - return 0; -} - -static int zd1201_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *srq = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - int err, i, j, enabled_save; - struct iw_event iwe; - char *cev = extra; - char *end_buf = extra + IW_SCAN_MAX_DATA; - - /* No scanning in AP mode */ - if (zd->ap) - return -EOPNOTSUPP; - - /* Scan doesn't seem to work if disabled */ - enabled_save = zd->mac_enabled; - zd1201_enable(zd); - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, - ZD1201_INQ_SCANRESULTS, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) - return -EIO; - - for(i=8; irxlen; i+=62) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = zd->rxdata[i+16]; - iwe.u.data.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, - &iwe, zd->rxdata+i+18); - - iwe.cmd = SIOCGIWMODE; - if (zd->rxdata[i+14]&0x01) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = zd->rxdata[i+0]; - iwe.u.freq.e = 0; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { - iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (zd->rxdata[i+14]&0x10) - iwe.u.data.flags = IW_ENCODE_ENABLED; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = zd->rxdata[i+4]; - iwe.u.qual.noise= zd->rxdata[i+2]/10-100; - iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; - iwe.u.qual.updated = 7; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - if (!enabled_save) - zd1201_disable(zd); - - srq->length = cev - extra; - srq->flags = 0; - - return 0; -} - -static int zd1201_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - if (data->length < 1) - data->length = 1; - zd->essidlen = data->length; - memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); - memcpy(zd->essid, essid, data->length); - return zd1201_join(zd, zd->essid, zd->essidlen); -} - -static int zd1201_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - memcpy(essid, zd->essid, zd->essidlen); - data->flags = 1; - data->length = zd->essidlen; - - return 0; -} - -static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *nick) -{ - struct iw_point *data = &wrqu->data; - strcpy(nick, "zd1201"); - data->flags = 1; - data->length = strlen(nick); - return 0; -} - -static int zd1201_set_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - switch (rrq->value) { - case 1000000: - rate = ZD1201_RATEB1; - break; - case 2000000: - rate = ZD1201_RATEB2; - break; - case 5500000: - rate = ZD1201_RATEB5; - break; - case 11000000: - default: - rate = ZD1201_RATEB11; - break; - } - if (!rrq->fixed) { /* Also enable all lower bitrates */ - rate |= rate-1; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); - if (err) - return err; - - switch(rate) { - case 1: - rrq->value = 1000000; - break; - case 2: - rrq->value = 2000000; - break; - case 5: - rrq->value = 5500000; - break; - case 11: - rrq->value = 11000000; - break; - default: - rrq->value = 0; - } - rrq->fixed = 0; - rrq->disabled = 0; - - return 0; -} - -static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = rts->value; - - if (rts->disabled || !rts->fixed) - val = ZD1201_RTSMAX; - if (val > ZD1201_RTSMAX) - return -EINVAL; - if (val < 0) - return -EINVAL; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - short rtst; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); - if (err) - return err; - rts->value = rtst; - rts->disabled = (rts->value == ZD1201_RTSMAX); - rts->fixed = 1; - - return 0; -} - -static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = frag->value; - - if (frag->disabled || !frag->fixed) - val = ZD1201_FRAGMAX; - if (val > ZD1201_FRAGMAX) - return -EINVAL; - if (val < ZD1201_FRAGMIN) - return -EINVAL; - if (val & 1) - return -EINVAL; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - short fragt; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); - if (err) - return err; - frag->value = fragt; - frag->disabled = (frag->value == ZD1201_FRAGMAX); - frag->fixed = 1; - - return 0; -} - -static int zd1201_set_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_get_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err, rid; - - if (erq->length > ZD1201_MAXKEYLEN) - return -EINVAL; - - i = (erq->flags & IW_ENCODE_INDEX)-1; - if (i == -1) { - err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); - if (err) - return err; - } else { - err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); - if (err) - return err; - } - - if (i < 0 || i >= ZD1201_NUMKEYS) - return -EINVAL; - - rid = ZD1201_RID_CNFDEFAULTKEY0 + i; - err = zd1201_setconfig(zd, rid, key, erq->length, 1); - if (err) - return err; - zd->encode_keylen[i] = erq->length; - memcpy(zd->encode_keys[i], key, erq->length); - - i=0; - if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { - i |= 0x01; - zd->encode_enabled = 1; - } else - zd->encode_enabled = 0; - if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { - i |= 0x02; - zd->encode_restricted = 1; - } else - zd->encode_restricted = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); - if (err) - return err; - - if (zd->encode_enabled) - i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; - else - i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err; - - if (zd->encode_enabled) - erq->flags = IW_ENCODE_ENABLED; - else - erq->flags = IW_ENCODE_DISABLED; - if (zd->encode_restricted) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - i = (erq->flags & IW_ENCODE_INDEX) -1; - if (i == -1) { - err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); - if (err) - return err; - } - if (i<0 || i>= ZD1201_NUMKEYS) - return -EINVAL; - - erq->flags |= i+1; - - erq->length = zd->encode_keylen[i]; - memcpy(key, zd->encode_keys[i], erq->length); - - return 0; -} - -static int zd1201_set_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, duration, level; - int err; - - enabled = vwrq->disabled ? 0 : 1; - if (enabled) { - if (vwrq->flags & IW_POWER_PERIOD) { - duration = vwrq->value; - err = zd1201_setconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, duration); - if (err) - return err; - goto out; - } - if (vwrq->flags & IW_POWER_TIMEOUT) { - err = zd1201_getconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - level = vwrq->value * 4 / duration; - if (level > 4) - level = 4; - if (level < 0) - level = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, - level); - if (err) - return err; - goto out; - } - return -EINVAL; - } -out: - return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); -} - -static int zd1201_get_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, level, duration; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - vwrq->disabled = enabled ? 0 : 1; - if (vwrq->flags & IW_POWER_TYPE) { - if (vwrq->flags & IW_POWER_PERIOD) { - vwrq->value = duration; - vwrq->flags = IW_POWER_PERIOD; - } else { - vwrq->value = duration * level / 4; - vwrq->flags = IW_POWER_TIMEOUT; - } - } - if (vwrq->flags & IW_POWER_MODE) { - if (enabled && level) - vwrq->flags = IW_POWER_UNICAST_R; - else - vwrq->flags = IW_POWER_ALL_R; - } - - return 0; -} - - -static const iw_handler zd1201_iw_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit), - IW_HANDLER(SIOCGIWNAME, zd1201_get_name), - IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq), - IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq), - IW_HANDLER(SIOCSIWMODE, zd1201_set_mode), - IW_HANDLER(SIOCGIWMODE, zd1201_get_mode), - IW_HANDLER(SIOCGIWRANGE, zd1201_get_range), - IW_HANDLER(SIOCGIWAP, zd1201_get_wap), - IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan), - IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan), - IW_HANDLER(SIOCSIWESSID, zd1201_set_essid), - IW_HANDLER(SIOCGIWESSID, zd1201_get_essid), - IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick), - IW_HANDLER(SIOCSIWRATE, zd1201_set_rate), - IW_HANDLER(SIOCGIWRATE, zd1201_get_rate), - IW_HANDLER(SIOCSIWRTS, zd1201_set_rts), - IW_HANDLER(SIOCGIWRTS, zd1201_get_rts), - IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag), - IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag), - IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry), - IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry), - IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode), - IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode), - IW_HANDLER(SIOCSIWPOWER, zd1201_set_power), - IW_HANDLER(SIOCGIWPOWER, zd1201_get_power), -}; - -static int zd1201_set_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); -} - -static int zd1201_get_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short hostauth; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); - if (err) - return err; - rrq->value = hostauth; - rrq->fixed = 1; - - return 0; -} - -static int zd1201_auth_sta(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *sta = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[10]; - - if (!zd->ap) - return -EOPNOTSUPP; - - memcpy(buffer, sta->sa_data, ETH_ALEN); - *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ - *(short*)(buffer+8) = 0; - - return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); -} - -static int zd1201_set_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); -} - -static int zd1201_get_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short maxassoc; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); - if (err) - return err; - rrq->value = maxassoc; - rrq->fixed = 1; - - return 0; -} - -static const iw_handler zd1201_private_handler[] = { - zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ - zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ - zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ - NULL, /* nothing to get */ - zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ - zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ -}; - -static const struct iw_priv_args zd1201_private_args[] = { - { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "sethostauth" }, - { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, - { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "authstation" }, - { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "setmaxassoc" }, - { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, -}; - -static const struct iw_handler_def zd1201_iw_handlers = { - .num_standard = ARRAY_SIZE(zd1201_iw_handler), - .num_private = ARRAY_SIZE(zd1201_private_handler), - .num_private_args = ARRAY_SIZE(zd1201_private_args), - .standard = zd1201_iw_handler, - .private = zd1201_private_handler, - .private_args = (struct iw_priv_args *) zd1201_private_args, - .get_wireless_stats = zd1201_get_wireless_stats, -}; - -static const struct net_device_ops zd1201_netdev_ops = { - .ndo_open = zd1201_net_open, - .ndo_stop = zd1201_net_stop, - .ndo_start_xmit = zd1201_hard_start_xmit, - .ndo_tx_timeout = zd1201_tx_timeout, - .ndo_set_rx_mode = zd1201_set_multicast, - .ndo_set_mac_address = zd1201_set_mac_address, - .ndo_validate_addr = eth_validate_addr, -}; - -static int zd1201_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct zd1201 *zd; - struct net_device *dev; - struct usb_device *usb; - int err; - short porttype; - char buf[IW_ESSID_MAX_SIZE+2]; - u8 addr[ETH_ALEN]; - - usb = interface_to_usbdev(interface); - - dev = alloc_etherdev(sizeof(*zd)); - if (!dev) - return -ENOMEM; - zd = netdev_priv(dev); - zd->dev = dev; - - zd->ap = ap; - zd->usb = usb; - zd->removed = 0; - init_waitqueue_head(&zd->rxdataq); - INIT_HLIST_HEAD(&zd->fraglist); - - err = zd1201_fw_upload(usb, zd->ap); - if (err) { - dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); - goto err_zd; - } - - zd->endp_in = 1; - zd->endp_out = 1; - zd->endp_out2 = 2; - zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!zd->rx_urb || !zd->tx_urb) { - err = -ENOMEM; - goto err_zd; - } - - mdelay(100); - err = zd1201_drvr_start(zd); - if (err) - goto err_zd; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); - if (err) - goto err_start; - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, - ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); - if (err) - goto err_start; - - dev->netdev_ops = &zd1201_netdev_ops; - dev->wireless_handlers = &zd1201_iw_handlers; - dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - strcpy(dev->name, "wlan%d"); - - err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN); - if (err) - goto err_start; - eth_hw_addr_set(dev, addr); - - /* Set wildcard essid to match zd->essid */ - *(__le16 *)buf = cpu_to_le16(0); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - goto err_start; - - if (zd->ap) - porttype = ZD1201_PORTTYPE_AP; - else - porttype = ZD1201_PORTTYPE_BSS; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - goto err_start; - - SET_NETDEV_DEV(dev, &usb->dev); - - err = register_netdev(dev); - if (err) - goto err_start; - dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - dev->name); - - usb_set_intfdata(interface, zd); - zd1201_enable(zd); /* zd1201 likes to startup enabled, */ - zd1201_disable(zd); /* interfering with all the wifis in range */ - return 0; - -err_start: - /* Leave the device in reset state */ - zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); -err_zd: - usb_free_urb(zd->tx_urb); - usb_free_urb(zd->rx_urb); - free_netdev(dev); - return err; -} - -static void zd1201_disconnect(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - struct hlist_node *node2; - struct zd1201_frag *frag; - - if (!zd) - return; - usb_set_intfdata(interface, NULL); - - hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) { - hlist_del_init(&frag->fnode); - kfree_skb(frag->skb); - kfree(frag); - } - - if (zd->tx_urb) { - usb_kill_urb(zd->tx_urb); - usb_free_urb(zd->tx_urb); - } - if (zd->rx_urb) { - usb_kill_urb(zd->rx_urb); - usb_free_urb(zd->rx_urb); - } - - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } -} - -#ifdef CONFIG_PM - -static int zd1201_suspend(struct usb_interface *interface, - pm_message_t message) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - netif_device_detach(zd->dev); - - zd->was_enabled = zd->mac_enabled; - - if (zd->was_enabled) - return zd1201_disable(zd); - else - return 0; -} - -static int zd1201_resume(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - if (!zd || !zd->dev) - return -ENODEV; - - netif_device_attach(zd->dev); - - if (zd->was_enabled) - return zd1201_enable(zd); - else - return 0; -} - -#else - -#define zd1201_suspend NULL -#define zd1201_resume NULL - -#endif - -static struct usb_driver zd1201_usb = { - .name = "zd1201", - .probe = zd1201_probe, - .disconnect = zd1201_disconnect, - .id_table = zd1201_table, - .suspend = zd1201_suspend, - .resume = zd1201_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(zd1201_usb); diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h deleted file mode 100644 index c46ac87550d1..000000000000 --- a/drivers/net/wireless/zydas/zd1201.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _INCLUDE_ZD1201_H_ -#define _INCLUDE_ZD1201_H_ - -#define ZD1201_NUMKEYS 4 -#define ZD1201_MAXKEYLEN 13 -#define ZD1201_MAXMULTI 16 -#define ZD1201_FRAGMAX 2500 -#define ZD1201_FRAGMIN 256 -#define ZD1201_RTSMAX 2500 - -#define ZD1201_RXSIZE 3000 - -struct zd1201 { - struct usb_device *usb; - int removed; - struct net_device *dev; - struct iw_statistics iwstats; - - int endp_in; - int endp_out; - int endp_out2; - struct urb *rx_urb; - struct urb *tx_urb; - - unsigned char rxdata[ZD1201_RXSIZE]; - int rxlen; - wait_queue_head_t rxdataq; - int rxdatas; - struct hlist_head fraglist; - unsigned char txdata[ZD1201_RXSIZE]; - - int ap; - char essid[IW_ESSID_MAX_SIZE+1]; - int essidlen; - int mac_enabled; - int was_enabled; - int monitor; - int encode_enabled; - int encode_restricted; - unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN]; - int encode_keylen[ZD1201_NUMKEYS]; -}; - -struct zd1201_frag { - struct hlist_node fnode; - int seq; - struct sk_buff *skb; -}; - -#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV -#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1 -#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2 -#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4 -#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1 - -#define ZD1201_FW_TIMEOUT (1000) - -#define ZD1201_TX_TIMEOUT (2000) - -#define ZD1201_USB_CMDREQ 0 -#define ZD1201_USB_RESREQ 1 - -#define ZD1201_CMDCODE_INIT 0x00 -#define ZD1201_CMDCODE_ENABLE 0x01 -#define ZD1201_CMDCODE_DISABLE 0x02 -#define ZD1201_CMDCODE_ALLOC 0x0a -#define ZD1201_CMDCODE_INQUIRE 0x11 -#define ZD1201_CMDCODE_SETRXRID 0x17 -#define ZD1201_CMDCODE_ACCESS 0x21 - -#define ZD1201_PACKET_EVENTSTAT 0x0 -#define ZD1201_PACKET_RXDATA 0x1 -#define ZD1201_PACKET_INQUIRE 0x2 -#define ZD1201_PACKET_RESOURCE 0x3 - -#define ZD1201_ACCESSBIT 0x0100 - -#define ZD1201_RID_CNFPORTTYPE 0xfc00 -#define ZD1201_RID_CNFOWNMACADDR 0xfc01 -#define ZD1201_RID_CNFDESIREDSSID 0xfc02 -#define ZD1201_RID_CNFOWNCHANNEL 0xfc03 -#define ZD1201_RID_CNFOWNSSID 0xfc04 -#define ZD1201_RID_CNFMAXDATALEN 0xfc07 -#define ZD1201_RID_CNFPMENABLED 0xfc09 -#define ZD1201_RID_CNFPMEPS 0xfc0a -#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c -#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23 -#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24 -#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25 -#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26 -#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27 -#define ZD1201_RID_CNFWEBFLAGS 0xfc28 -#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a -#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b -#define ZD1201_RID_CNFHOSTAUTH 0xfc2e -#define ZD1201_RID_CNFGROUPADDRESS 0xfc80 -#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82 -#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83 -#define ZD1201_RID_TXRATECNTL 0xfc84 -#define ZD1201_RID_PROMISCUOUSMODE 0xfc85 -#define ZD1201_RID_CNFBASICRATES 0xfcb3 -#define ZD1201_RID_AUTHENTICATESTA 0xfce3 -#define ZD1201_RID_CURRENTBSSID 0xfd42 -#define ZD1201_RID_COMMSQUALITY 0xfd43 -#define ZD1201_RID_CURRENTTXRATE 0xfd44 -#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0 -#define ZD1201_RID_CURRENTCHANNEL 0xfdc1 - -#define ZD1201_INQ_SCANRESULTS 0xf101 - -#define ZD1201_INF_LINKSTATUS 0xf200 -#define ZD1201_INF_ASSOCSTATUS 0xf201 -#define ZD1201_INF_AUTHREQ 0xf202 - -#define ZD1201_ASSOCSTATUS_STAASSOC 0x1 -#define ZD1201_ASSOCSTATUS_REASSOC 0x2 -#define ZD1201_ASSOCSTATUS_DISASSOC 0x3 -#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4 -#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5 - -#define ZD1201_PORTTYPE_IBSS 0 -#define ZD1201_PORTTYPE_BSS 1 -#define ZD1201_PORTTYPE_WDS 2 -#define ZD1201_PORTTYPE_PSEUDOIBSS 3 -#define ZD1201_PORTTYPE_AP 6 - -#define ZD1201_RATEB1 1 -#define ZD1201_RATEB2 2 -#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */ -#define ZD1201_RATEB11 8 - -#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001 -#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002 - -#endif /* _INCLUDE_ZD1201_H_ */ From 1535d5962d79b8f4bddfd480399828b8db9d7a1c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:48 +0200 Subject: [PATCH 0157/7721] wifi: remove orphaned orinoco driver Orinoco is a PIO-only ISA/PCMCIA 802.11b device with extra bus interface connections for PCI/Cardbus/mini-PCI and a few pre-2002 Apple PowerMac variants. It supports both wireless extensions and CFG80211, but I could not tell if it requires using both. This device used to be one of the most common ones 20 years ago, but has been orphaned for most of the time since then, and the conversion to cfg80211 has stalled in 2010. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 7 - drivers/net/wireless/intersil/Kconfig | 1 - drivers/net/wireless/intersil/Makefile | 1 - drivers/net/wireless/intersil/orinoco/Kconfig | 143 - .../net/wireless/intersil/orinoco/Makefile | 15 - .../net/wireless/intersil/orinoco/airport.c | 268 -- drivers/net/wireless/intersil/orinoco/cfg.c | 291 -- drivers/net/wireless/intersil/orinoco/cfg.h | 15 - drivers/net/wireless/intersil/orinoco/fw.c | 387 --- drivers/net/wireless/intersil/orinoco/fw.h | 21 - .../net/wireless/intersil/orinoco/hermes.c | 778 ------ .../net/wireless/intersil/orinoco/hermes.h | 534 ---- .../wireless/intersil/orinoco/hermes_dld.c | 477 ---- .../wireless/intersil/orinoco/hermes_dld.h | 52 - .../wireless/intersil/orinoco/hermes_rid.h | 165 -- drivers/net/wireless/intersil/orinoco/hw.c | 1362 ---------- drivers/net/wireless/intersil/orinoco/hw.h | 60 - drivers/net/wireless/intersil/orinoco/main.c | 2414 ----------------- drivers/net/wireless/intersil/orinoco/main.h | 50 - drivers/net/wireless/intersil/orinoco/mic.c | 89 - drivers/net/wireless/intersil/orinoco/mic.h | 23 - .../net/wireless/intersil/orinoco/orinoco.h | 251 -- .../wireless/intersil/orinoco/orinoco_cs.c | 350 --- .../intersil/orinoco/orinoco_nortel.c | 314 --- .../wireless/intersil/orinoco/orinoco_pci.c | 257 -- .../wireless/intersil/orinoco/orinoco_pci.h | 54 - .../wireless/intersil/orinoco/orinoco_plx.c | 362 --- .../wireless/intersil/orinoco/orinoco_tmd.c | 237 -- .../wireless/intersil/orinoco/orinoco_usb.c | 1787 ------------ drivers/net/wireless/intersil/orinoco/scan.c | 259 -- drivers/net/wireless/intersil/orinoco/scan.h | 21 - .../wireless/intersil/orinoco/spectrum_cs.c | 328 --- drivers/net/wireless/intersil/orinoco/wext.c | 1428 ---------- drivers/net/wireless/intersil/orinoco/wext.h | 13 - 34 files changed, 12814 deletions(-) delete mode 100644 drivers/net/wireless/intersil/orinoco/Kconfig delete mode 100644 drivers/net/wireless/intersil/orinoco/Makefile delete mode 100644 drivers/net/wireless/intersil/orinoco/airport.c delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.c delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.h delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.c delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.h delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.c delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.h delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.c delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.h delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_rid.h delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.c delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.h delete mode 100644 drivers/net/wireless/intersil/orinoco/main.c delete mode 100644 drivers/net/wireless/intersil/orinoco/main.h delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.c delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.h delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco.h delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_cs.c delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_nortel.c delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.c delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.h delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_plx.c delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_tmd.c delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_usb.c delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.c delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.h delete mode 100644 drivers/net/wireless/intersil/orinoco/spectrum_cs.c delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.c delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.h diff --git a/MAINTAINERS b/MAINTAINERS index 2ada93d4cee4..161bf9d89535 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16068,13 +16068,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git F: Documentation/filesystems/orangefs.rst F: fs/orangefs/ -ORINOCO DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco -W: http://www.nongnu.org/orinoco/ -F: drivers/net/wireless/intersil/orinoco/ - OV2659 OMNIVISION SENSOR DRIVER M: "Lad, Prabhakar" L: linux-media@vger.kernel.org diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index f2455ef45d99..201b1534a9ca 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -12,7 +12,6 @@ config WLAN_VENDOR_INTERSIL if WLAN_VENDOR_INTERSIL -source "drivers/net/wireless/intersil/orinoco/Kconfig" source "drivers/net/wireless/intersil/p54/Kconfig" endif # WLAN_VENDOR_INTERSIL diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile index 773147110c54..27e9b2869da1 100644 --- a/drivers/net/wireless/intersil/Makefile +++ b/drivers/net/wireless/intersil/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig deleted file mode 100644 index f62730aa7be3..000000000000 --- a/drivers/net/wireless/intersil/orinoco/Kconfig +++ /dev/null @@ -1,143 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HERMES - tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 - select CFG80211_WEXT_EXPORT - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select CRYPTO - select CRYPTO_MICHAEL_MIC - help - A driver for 802.11b wireless cards based on the "Hermes" or - Intersil HFA384x (Prism 2) MAC controller. This includes the vast - majority of the PCMCIA 802.11b cards (which are nearly all rebadges) - - except for the Cisco/Aironet cards. Cards supported include the - Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, - Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, - IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear - MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel - IPW2011, and Symbol Spectrum24 High Rate amongst others. - - This option includes the guts of the driver, but in order to - actually use a card you will also need to enable support for PCMCIA - Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. - - You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - - -config HERMES_PRISM - bool "Support Prism 2/2.5 chipset" - depends on HERMES - help - - Say Y to enable support for Prism 2 and 2.5 chipsets. These - chipsets are better handled by the hostap driver. This driver - would not support WPA or firmware download for Prism chipset. - - If you are not sure, say N. - -config HERMES_CACHE_FW_ON_INIT - bool "Cache Hermes firmware on driver initialisation" - depends on HERMES - default y - help - Say Y to cache any firmware required by the Hermes drivers - on startup. The firmware will remain cached until the - driver is unloaded. The cache uses 64K of RAM. - - Otherwise load the firmware from userspace as required. In - this case the driver should be unloaded and restarted - whenever the firmware is changed. - - If you are not sure, say Y. - -config APPLE_AIRPORT - tristate "Apple Airport support (built-in)" - depends on PPC_PMAC && HERMES - help - Say Y here to support the Airport 802.11b wireless Ethernet hardware - built into the Macintosh iBook and other recent PowerPC-based - Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface. - - This driver does not support the Airport Extreme (802.11b/g). Use - the BCM43xx driver for Airport Extreme cards. - -config PLX_HERMES - tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in PLX9052 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. The Netgear - MA301 is such an adaptor. - -config TMD_HERMES - tristate "Hermes in TMD7160 based PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in TMD7160 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. - -config NORTEL_HERMES - tristate "Nortel emobility PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in Nortel emobility PCI adaptors. These - adaptors are not full PCMCIA controllers, but act as a more limited - PCI <-> PCMCIA bridge. - -config PCI_HERMES - tristate "Prism 2.5 PCI 802.11b adaptor support" - depends on PCI && HERMES && HERMES_PRISM - help - Enable support for PCI and mini-PCI 802.11b wireless NICs based on - the Prism 2.5 chipset. These are true PCI cards, not the 802.11b - PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also - common. Some of the built-in wireless adaptors in laptops are of - this variety. - -config PCMCIA_HERMES - tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and - others). It should also be usable on various Prism II based cards - such as the Linksys, D-Link and Farallon Skyline. It should also - work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - - You will very likely need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works: - . - -config PCMCIA_SPECTRUM - tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - - This is a driver for 802.11b cards using RAM-loadable Symbol - firmware, such as Symbol Wireless Networker LA4100, CompactFlash - cards by Socket Communications and Intel PRO/Wireless 2011B. - - This driver requires firmware download on startup. Utilities - for downloading Symbol firmware are available at - - -config ORINOCO_USB - tristate "Agere Orinoco USB support" - depends on USB && HERMES - select FW_LOADER - help - This driver is for USB versions of the Agere Orinoco card. diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile deleted file mode 100644 index 0c29c56c88d6..000000000000 --- a/drivers/net/wireless/intersil/orinoco/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the orinoco wireless device drivers. -# -orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o - -obj-$(CONFIG_HERMES) += orinoco.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o -obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c deleted file mode 100644 index 45ac00fdafa5..000000000000 --- a/drivers/net/wireless/intersil/orinoco/airport.c +++ /dev/null @@ -1,268 +0,0 @@ -/* airport.c - * - * A driver for "Hermes" chipset based Apple Airport wireless - * card. - * - * Copyright notice & release notes in file main.c - * - * Note specific to airport stub: - * - * 0.05 : first version of the new split driver - * 0.06 : fix possible hang on powerup, add sleep support - */ - -#define DRIVER_NAME "airport" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -#define AIRPORT_IO_LEN (0x1000) /* one page */ - -struct airport { - struct macio_dev *mdev; - void __iomem *vaddr; - unsigned int irq; - int irq_requested; - int ndev_registered; -}; - -static int -airport_suspend(struct macio_dev *mdev, pm_message_t state) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", - dev->name); - return 0; - } - - orinoco_down(priv); - orinoco_unlock(priv, &flags); - - disable_irq(card->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - - return 0; -} - -static int -airport_resume(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - msleep(200); - - enable_irq(card->irq); - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = orinoco_up(priv); - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return err; -} - -static int -airport_detach(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct airport *card = priv->card; - - if (card->ndev_registered) - orinoco_if_del(priv); - card->ndev_registered = 0; - - if (card->irq_requested) - free_irq(card->irq, priv); - card->irq_requested = 0; - - if (card->vaddr) - iounmap(card->vaddr); - card->vaddr = NULL; - - macio_release_resource(mdev, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - ssleep(1); - - macio_set_drvdata(mdev, NULL); - free_orinocodev(priv); - - return 0; -} - -static int airport_hard_reset(struct orinoco_private *priv) -{ - /* It would be nice to power cycle the Airport for a real hard - * reset, but for some reason although it appears to - * re-initialize properly, it falls in a screaming heap - * shortly afterwards. */ -#if 0 - struct airport *card = priv->card; - - /* Vitally important. If we don't do this it seems we get an - * interrupt somewhere during the power cycle, since - * hw_unavailable is already set it doesn't get ACKed, we get - * into an interrupt loop and the PMU decides to turn us - * off. */ - disable_irq(card->irq); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 0); - ssleep(1); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 1); - ssleep(1); - - enable_irq(card->irq); - ssleep(1); -#endif - - return 0; -} - -static int -airport_attach(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct orinoco_private *priv; - struct airport *card; - unsigned long phys_addr; - struct hermes *hw; - - if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - return -ENODEV; - } - card = priv->card; - - hw = &priv->hw; - card->mdev = mdev; - - if (macio_request_resource(mdev, 0, DRIVER_NAME)) { - printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(priv); - return -EBUSY; - } - - macio_set_drvdata(mdev, priv); - - /* Setup interrupts & base address */ - card->irq = macio_irq(mdev, 0); - phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); - if (!card->vaddr) { - printk(KERN_ERR PFX "ioremap() failed\n"); - goto failed; - } - - hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); - - /* Power up card */ - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - ssleep(1); - - /* Reset it before we get the interrupt */ - hw->ops->init(hw); - - if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq); - goto failed; - } - card->irq_requested = 1; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - card->ndev_registered = 1; - return 0; - failed: - airport_detach(mdev); - return -ENODEV; -} /* airport_attach */ - - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Benjamin Herrenschmidt )"; -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); -MODULE_LICENSE("Dual MPL/GPL"); - -static const struct of_device_id airport_match[] = { - { - .name = "radio", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, airport_match); - -static struct macio_driver airport_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = airport_match, - }, - .probe = airport_attach, - .remove = airport_detach, - .suspend = airport_suspend, - .resume = airport_resume, -}; - -static int __init -init_airport(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return macio_register_driver(&airport_driver); -} - -static void __exit -exit_airport(void) -{ - macio_unregister_driver(&airport_driver); -} - -module_init(init_airport); -module_exit(exit_airport); diff --git a/drivers/net/wireless/intersil/orinoco/cfg.c b/drivers/net/wireless/intersil/orinoco/cfg.c deleted file mode 100644 index b2d5ec8634b5..000000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.c +++ /dev/null @@ -1,291 +0,0 @@ -/* cfg80211 support - * - * See copyright notice in main.c - */ -#include -#include -#include "hw.h" -#include "main.h" -#include "orinoco.h" - -#include "cfg.h" - -/* Supported bitrates. Must agree with hw.c */ -static struct ieee80211_rate orinoco_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20 }, - { .bitrate = 55 }, - { .bitrate = 110 }, -}; - -static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; - -/* Called after orinoco_private is allocated. */ -void orinoco_wiphy_init(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - - wiphy->privid = orinoco_wiphy_privid; - - set_wiphy_dev(wiphy, priv->dev); -} - -/* Called after firmware is initialised */ -int orinoco_wiphy_register(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int i, channels = 0; - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - wiphy->max_scan_ssids = 1; - else - wiphy->max_scan_ssids = 0; - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - /* TODO: should we set if we only have demo ad-hoc? - * (priv->has_port3) - */ - if (priv->has_ibss) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - - if (!priv->broken_monitor || force_monitor) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); - - priv->band.bitrates = orinoco_rates; - priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); - - /* Only support channels allowed by the card EEPROM */ - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - priv->channels[i].center_freq = - ieee80211_channel_to_frequency(i + 1, - NL80211_BAND_2GHZ); - channels++; - } - } - priv->band.channels = priv->channels; - priv->band.n_channels = channels; - - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - i = 0; - if (priv->has_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; - i++; - - if (priv->has_big_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; - i++; - } - } - if (priv->has_wpa) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; - i++; - } - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = i; - - wiphy->rts_threshold = priv->rts_thresh; - if (!priv->has_mwo) - wiphy->frag_threshold = priv->frag_thresh + 1; - wiphy->retry_short = priv->short_retry_limit; - wiphy->retry_long = priv->long_retry_limit; - - return wiphy_register(wiphy); -} - -static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long lock; - - if (orinoco_lock(priv, &lock) != 0) - return -EBUSY; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EINVAL; - break; - - case NL80211_IFTYPE_STATION: - break; - - case NL80211_IFTYPE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - wiphy_warn(wiphy, - "Monitor mode support is buggy in this firmware, not enabling\n"); - err = -EINVAL; - } - break; - - default: - err = -EINVAL; - } - - if (!err) { - priv->iw_mode = type; - set_port_type(priv); - err = orinoco_commit(priv); - } - - orinoco_unlock(priv, &lock); - - return err; -} - -static int orinoco_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err; - - if (!request) - return -EINVAL; - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - err = orinoco_hw_trigger_scan(priv, request->ssids); - /* On error the we aren't processing the request */ - if (err) - priv->scan_request = NULL; - - return err; -} - -static int orinoco_set_monitor_channel(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long flags; - int channel; - - if (!chandef->chan) - return -EINVAL; - - if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) - return -EINVAL; - - if (chandef->chan->band != NL80211_BAND_2GHZ) - return -EINVAL; - - channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); - - if ((channel < 1) || (channel > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (channel - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = channel; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - channel, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int frag_value = -1; - int rts_value = -1; - int err = 0; - - if (changed & WIPHY_PARAM_RETRY_SHORT) { - /* Setting short retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_RETRY_LONG) { - /* Setting long retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - /* Set fragmentation */ - if (priv->has_mwo) { - if (wiphy->frag_threshold == -1) - frag_value = 0; - else { - printk(KERN_WARNING "%s: Fixed fragmentation " - "is not supported on this firmware. " - "Using MWO robust instead.\n", - priv->ndev->name); - frag_value = 1; - } - } else { - if (wiphy->frag_threshold == -1) - frag_value = 2346; - else if ((wiphy->frag_threshold < 257) || - (wiphy->frag_threshold > 2347)) - err = -EINVAL; - else - /* cfg80211 value is 257-2347 (odd only) - * orinoco rid has range 256-2346 (even only) */ - frag_value = wiphy->frag_threshold & ~0x1; - } - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - /* Set RTS. - * - * Prism documentation suggests default of 2432, - * and a range of 0-3000. - * - * Current implementation uses 2347 as the default and - * the upper limit. - */ - - if (wiphy->rts_threshold == -1) - rts_value = 2347; - else if (wiphy->rts_threshold > 2347) - err = -EINVAL; - else - rts_value = wiphy->rts_threshold; - } - - if (!err) { - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (frag_value >= 0) { - if (priv->has_mwo) - priv->mwo_robust = frag_value; - else - priv->frag_thresh = frag_value; - } - if (rts_value >= 0) - priv->rts_thresh = rts_value; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - } - - return err; -} - -const struct cfg80211_ops orinoco_cfg_ops = { - .change_virtual_intf = orinoco_change_vif, - .set_monitor_channel = orinoco_set_monitor_channel, - .scan = orinoco_scan, - .set_wiphy_params = orinoco_set_wiphy_params, -}; diff --git a/drivers/net/wireless/intersil/orinoco/cfg.h b/drivers/net/wireless/intersil/orinoco/cfg.h deleted file mode 100644 index 3ddc96a06cd7..000000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.h +++ /dev/null @@ -1,15 +0,0 @@ -/* cfg80211 support. - * - * See copyright notice in main.c - */ -#ifndef ORINOCO_CFG_H -#define ORINOCO_CFG_H - -#include - -extern const struct cfg80211_ops orinoco_cfg_ops; - -void orinoco_wiphy_init(struct wiphy *wiphy); -int orinoco_wiphy_register(struct wiphy *wiphy); - -#endif /* ORINOCO_CFG_H */ diff --git a/drivers/net/wireless/intersil/orinoco/fw.c b/drivers/net/wireless/intersil/orinoco/fw.c deleted file mode 100644 index 015af782881b..000000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.c +++ /dev/null @@ -1,387 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "hermes_dld.h" -#include "orinoco.h" - -#include "fw.h" - -/* End markers (for Symbol firmware only) */ -#define TEXT_END 0x1A /* End of text header */ - -struct fw_info { - char *pri_fw; - char *sta_fw; - char *ap_fw; - u32 pda_addr; - u16 pda_size; -}; - -static const struct fw_info orinoco_fw[] = { - { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } -}; -MODULE_FIRMWARE("agere_sta_fw.bin"); -MODULE_FIRMWARE("agere_ap_fw.bin"); -MODULE_FIRMWARE("prism_sta_fw.bin"); -MODULE_FIRMWARE("prism_ap_fw.bin"); -MODULE_FIRMWARE("symbol_sp24t_prim_fw"); -MODULE_FIRMWARE("symbol_sp24t_sec_fw"); - -/* Structure used to access fields in FW - * Make sure LE decoding macros are used - */ -struct orinoco_fw_header { - char hdr_vers[6]; /* ASCII string for header version */ - __le16 headersize; /* Total length of header */ - __le32 entry_point; /* NIC entry point */ - __le32 blocks; /* Number of blocks to program */ - __le32 block_offset; /* Offset of block data from eof header */ - __le32 pdr_offset; /* Offset to PDR data from eof header */ - __le32 pri_offset; /* Offset to primary plug data */ - __le32 compat_offset; /* Offset to compatibility data*/ - char signature[]; /* FW signature length headersize-20 */ -} __packed; - -/* Check the range of various header entries. Return a pointer to a - * description of the problem, or NULL if everything checks out. */ -static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len) -{ - u16 hdrsize; - - if (len < sizeof(*hdr)) - return "image too small"; - if (memcmp(hdr->hdr_vers, "HFW", 3) != 0) - return "format not recognised"; - - hdrsize = le16_to_cpu(hdr->headersize); - if (hdrsize > len) - return "bad headersize"; - if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len) - return "bad block offset"; - if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len) - return "bad PDR offset"; - if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len) - return "bad PRI offset"; - if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len) - return "bad compat offset"; - - /* TODO: consider adding a checksum or CRC to the firmware format */ - return NULL; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -static inline const struct firmware * -orinoco_cached_fw_get(struct orinoco_private *priv, bool primary) -{ - if (primary) - return priv->cached_pri_fw; - else - return priv->cached_fw; -} -#else -#define orinoco_cached_fw_get(priv, primary) (NULL) -#endif - -/* Download either STA or AP firmware into the card. */ -static int -orinoco_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw, - int ap) -{ - /* Plug Data Area (PDA) */ - __le16 *pda; - - struct hermes *hw = &priv->hw; - const struct firmware *fw_entry; - const struct orinoco_fw_header *hdr; - const unsigned char *first_block; - const void *end; - const char *firmware; - const char *fw_err; - struct device *dev = priv->dev; - int err = 0; - - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - if (ap) - firmware = fw->ap_fw; - else - firmware = fw->sta_fw; - - dev_dbg(dev, "Attempting to download firmware %s\n", firmware); - - /* Read current plug data */ - err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - dev_dbg(dev, "Read PDA returned %d\n", err); - if (err) - goto free; - - if (!orinoco_cached_fw_get(priv, false)) { - err = request_firmware(&fw_entry, firmware, priv->dev); - - if (err) { - dev_err(dev, "Cannot find firmware %s\n", firmware); - err = -ENOENT; - goto free; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - hdr = (const struct orinoco_fw_header *) fw_entry->data; - - fw_err = validate_fw(hdr, fw_entry->size); - if (fw_err) { - dev_warn(dev, "Invalid firmware image detected (%s). " - "Aborting download\n", fw_err); - err = -EINVAL; - goto abort; - } - - /* Enable aux port to allow programming */ - err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); - dev_dbg(dev, "Program init returned %d\n", err); - if (err != 0) - goto abort; - - /* Program data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->block_offset)); - end = fw_entry->data + fw_entry->size; - - err = hermes_program(hw, first_block, end); - dev_dbg(dev, "Program returned %d\n", err); - if (err != 0) - goto abort; - - /* Update production data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->pdr_offset)); - - err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - dev_dbg(dev, "Apply PDA returned %d\n", err); - if (err) - goto abort; - - /* Tell card we've finished */ - err = hw->ops->program_end(hw); - dev_dbg(dev, "Program end returned %d\n", err); - if (err != 0) - goto abort; - - /* Check if we're running */ - dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); - -abort: - /* If we requested the firmware, release it. */ - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - -free: - kfree(pda); - return err; -} - -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ -static int -symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, - const unsigned char *image, const void *end, - int secondary) -{ - struct hermes *hw = &priv->hw; - int ret = 0; - const unsigned char *ptr; - const unsigned char *first_block; - - /* Plug Data Area (PDA) */ - __le16 *pda = NULL; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = ptr; - - /* Read the PDA from EEPROM */ - if (secondary) { - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - if (ret) - goto free; - } - - /* Stop the firmware, so that it can be safely rewritten */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 1); - if (ret) - goto free; - } - - /* Program the adapter with new firmware */ - ret = hermes_program(hw, first_block, end); - if (ret) - goto free; - - /* Write the PDA to the adapter */ - if (secondary) { - size_t len = hermes_blocks_length(first_block, end); - ptr = first_block + len; - ret = hermes_apply_pda(hw, ptr, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - kfree(pda); - if (ret) - return ret; - } - - /* Run the firmware */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 0); - if (ret) - return ret; - } - - /* Reset hermes chip and make sure it responds */ - ret = hw->ops->init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; - - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; - - return 0; - -free: - kfree(pda); - return ret; -} - - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ -static int -symbol_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw) -{ - struct device *dev = priv->dev; - int ret; - const struct firmware *fw_entry; - - if (!orinoco_cached_fw_get(priv, true)) { - if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, true); - - /* Load primary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 0); - - if (!orinoco_cached_fw_get(priv, true)) - release_firmware(fw_entry); - if (ret) { - dev_err(dev, "Primary firmware download failed\n"); - return ret; - } - - if (!orinoco_cached_fw_get(priv, false)) { - if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - /* Load secondary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 1); - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - if (ret) - dev_err(dev, "Secondary firmware download failed\n"); - - return ret; -} - -int orinoco_download(struct orinoco_private *priv) -{ - int err = 0; - /* Reload firmware */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* case FIRMWARE_TYPE_INTERSIL: */ - err = orinoco_dl_firmware(priv, - &orinoco_fw[priv->firmware_type], 0); - break; - - case FIRMWARE_TYPE_SYMBOL: - err = symbol_dl_firmware(priv, - &orinoco_fw[priv->firmware_type]); - break; - case FIRMWARE_TYPE_INTERSIL: - break; - } - /* TODO: if we fail we probably need to reinitialise - * the driver */ - - return err; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap) -{ - const struct firmware *fw_entry = NULL; - const char *pri_fw; - const char *fw; - - pri_fw = orinoco_fw[priv->firmware_type].pri_fw; - if (ap) - fw = orinoco_fw[priv->firmware_type].ap_fw; - else - fw = orinoco_fw[priv->firmware_type].sta_fw; - - if (pri_fw) { - if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) - priv->cached_pri_fw = fw_entry; - } - - if (fw) { - if (request_firmware(&fw_entry, fw, priv->dev) == 0) - priv->cached_fw = fw_entry; - } -} - -void orinoco_uncache_fw(struct orinoco_private *priv) -{ - release_firmware(priv->cached_pri_fw); - release_firmware(priv->cached_fw); - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -} -#endif diff --git a/drivers/net/wireless/intersil/orinoco/fw.h b/drivers/net/wireless/intersil/orinoco/fw.h deleted file mode 100644 index aca63e3c4b5b..000000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_FW_H_ -#define _ORINOCO_FW_H_ - -/* Forward declations */ -struct orinoco_private; - -int orinoco_download(struct orinoco_private *priv); - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap); -void orinoco_uncache_fw(struct orinoco_private *priv); -#else -#define orinoco_cache_fw(priv, ap) do { } while (0) -#define orinoco_uncache_fw(priv) do { } while (0) -#endif - -#endif /* _ORINOCO_FW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c deleted file mode 100644 index 4888286727ff..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.c +++ /dev/null @@ -1,778 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no - * particular order). - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include -#include - -#include "hermes.h" - -/* These are maximum timeouts. Most often, card wil react much faster */ -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ - -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ -#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - -/* HERMES_CMD_DOWNLD */ -#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) - -/* - * Debugging helpers - */ - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ - printk(stuff); } while (0) - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -static const struct hermes_ops hermes_ops_local; - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0, - u16 param1, u16 param2) -{ - int k = CMD_BUSY_TIMEOUT; - u16 reg; - - /* First wait for the command register to unbusy */ - reg = hermes_read_regn(hw, CMD); - while ((reg & HERMES_CMD_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - if (reg & HERMES_CMD_BUSY) - return -EBUSY; - - hermes_write_regn(hw, PARAM2, param2); - hermes_write_regn(hw, PARAM1, param1); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ -static int hermes_doicmd_wait(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp) -{ - int err = 0; - int k; - u16 status, reg; - - err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (!hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; -out: - return err; -} - -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing) -{ - hw->iobase = address; - hw->reg_spacing = reg_spacing; - hw->inten = 0x0; - hw->eeprom_pda = false; - hw->ops = &hermes_ops_local; -} -EXPORT_SYMBOL(hermes_struct_init); - -static int hermes_init(struct hermes *hw) -{ - u16 reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Normally it's a "can't happen" for the command register to - be busy when we go to issue a command because we are - serializing all commands. However we want to have some - chance of resetting the card even if it gets into a stupid - state, so we actually wait to see if the command register - will unbusy itself here. */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been - removed, so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - if we've timed - out hermes_issue_cmd() will probably return -EBUSY below */ - - /* According to the documentation, EVSTAT may contain - obsolete event occurrence information. We have to acknowledge - it by writing EVACK. */ - reg = hermes_read_regn(hw, EVSTAT); - hermes_write_regn(hw, EVACK, reg); - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: - * < 0 on internal error - * 0 on success - * > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - int err; - int k; - u16 reg; - u16 status; - - err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); - if (err) { - if (!hermes_present(hw)) { - if (net_ratelimit()) - printk(KERN_WARNING "hermes @ %p: " - "Card removed while issuing command " - "0x%04x.\n", hw->iobase, cmd); - err = -ENODEV; - } else - if (net_ratelimit()) - printk(KERN_ERR "hermes @ %p: " - "Error %d issuing command 0x%04x.\n", - hw->iobase, err, cmd); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: Card removed " - "while waiting for command 0x%04x completion.\n", - hw->iobase, cmd); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: Timeout waiting for " - "command 0x%04x completion.\n", hw->iobase, cmd); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: - return err; -} - -static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - int err = 0; - int k; - u16 reg; - - if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: " - "Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (!(reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - u16 reg; - - /* Paranoia.. */ - if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2)) - return -EINVAL; - - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* Now we actually set up the transfer */ - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg != offset) { - printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " - "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, - (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", - reg, id, offset); - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - return -EIO; /* error or wrong offset */ - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if ((len < 0) || (len % 2)) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_words(hw, dreg, buf, len / 2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len < 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_bytes(hw, dreg, buf, len); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - u16 rlength, rtype; - unsigned nwords; - - if (bufsize % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); - if (err) - return err; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - rlength = hermes_read_reg(hw, dreg); - - if (!rlength) - return -ENODATA; - - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes @ %p: %s(): " - "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __func__, rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) - printk(KERN_WARNING "hermes @ %p: " - "Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); - - nwords = min((unsigned)rlength - 1, bufsize / 2); - hermes_read_words(hw, dreg, buf, nwords); - - return 0; -} - -static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - unsigned count; - - if (length == 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_bytes(hw, dreg, value, count << 1); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, NULL); - - return err; -} - -/*** Hermes AUX control ***/ - -static inline void -hermes_aux_setaddr(struct hermes *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - -static inline int -hermes_aux_control(struct hermes *hw, int enabled) -{ - int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; - int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, action); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - desired_state) - return 0; - } - - return -EBUSY; -} - -/*** Hermes programming ***/ - -/* About to start programming data (Hermes I) - * offset is the entry point - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_init(struct hermes *hw, u32 offset) -{ - int err; - - /* Disable interrupts?*/ - /*hw->inten = 0x0;*/ - /*hermes_write_regn(hw, INTEN, 0);*/ - /*hermes_set_irqmask(hw, 0);*/ - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Using init_cmd_wait rather than cmd_wait */ - err = hw->ops->init_cmd_wait(hw, - 0x0100 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hw->ops->init_cmd_wait(hw, - 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", err); - - if (err) - return err; - - pr_debug("Enabling volatile, EP 0x%08x\n", offset); - err = hw->ops->init_cmd_wait(hw, - HERMES_PROGRAM_ENABLE_VOLATILE, - offset & 0xFFFFu, - offset >> 16, - 0, - NULL); - pr_debug("PROGRAM_ENABLE returned %d\n", err); - - return err; -} - -/* Done programming data (Hermes I) - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_end(struct hermes *hw) -{ - struct hermes_response resp; - int rc = 0; - int err; - - rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - - pr_debug("PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); - - if ((rc == 0) && - ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) - rc = -EIO; - - err = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", err); - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Reinitialise, ignoring return */ - (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - - return rc ? rc : err; -} - -static int hermes_program_bytes(struct hermes *hw, const char *data, - u32 addr, u32 len) -{ - /* wl lkm splits the programming into chunks of 2000 bytes. - * This restriction appears to come from USB. The PCMCIA - * adapters can program the whole lot in one go */ - hermes_aux_setaddr(hw, addr); - hermes_write_bytes(hw, HERMES_AUXDATA, data, len); - return 0; -} - -/* Read PDA from the adapter */ -static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr, - u16 pda_len) -{ - int ret; - u16 pda_size; - u16 data_len = pda_len; - __le16 *data = pda; - - if (hw->eeprom_pda) { - /* PDA of spectrum symbol is in eeprom */ - - /* Issue command to read EEPROM */ - ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - } else { - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - data_len = pda_len - 4; - data = pda + 2; - } - - /* Open auxiliary port */ - ret = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", ret); - if (ret) - return ret; - - /* Read PDA */ - hermes_aux_setaddr(hw, pda_addr); - hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); - - /* Close aux port */ - ret = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", ret); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - pr_debug("Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} - -static void hermes_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_irqsave(lock, *flags); -} - -static void hermes_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_irqrestore(lock, *flags); -} - -static void hermes_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_irq(lock); -} - -static void hermes_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_irq(lock); -} - -/* Hermes operations for local buses */ -static const struct hermes_ops hermes_ops_local = { - .init = hermes_init, - .cmd_wait = hermes_docmd_wait, - .init_cmd_wait = hermes_doicmd_wait, - .allocate = hermes_allocate, - .read_ltv = hermes_read_ltv, - .read_ltv_pr = hermes_read_ltv, - .write_ltv = hermes_write_ltv, - .bap_pread = hermes_bap_pread, - .bap_pwrite = hermes_bap_pwrite, - .read_pda = hermes_read_pda, - .program_init = hermesi_program_init, - .program_end = hermesi_program_end, - .program = hermes_program_bytes, - .lock_irqsave = hermes_lock_irqsave, - .unlock_irqrestore = hermes_unlock_irqrestore, - .lock_irq = hermes_lock_irq, - .unlock_irq = hermes_unlock_irq, -}; diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h deleted file mode 100644 index 3dc561a5cb7a..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.h +++ /dev/null @@ -1,534 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * Portions taken from hfa384x.h. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET register bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands ----------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands ---------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) - -/*--- Regulate Commands ------------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQUIRE (0x0011) - -/*--- Configure Commands -----------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Serial I/O Commands ----------------------------*/ -#define HERMES_CMD_READMIF (0x0030) -#define HERMES_CMD_WRITEMIF (0x0031) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_TEST (0x0038) - - -/* Test command arguments */ -#define HERMES_TEST_SET_CHANNEL 0x0800 -#define HERMES_TEST_MONITOR 0x0b00 -#define HERMES_TEST_STOP 0x0f00 - -/* Authentication algorithms */ -#define HERMES_AUTH_OPEN 1 -#define HERMES_AUTH_SHARED_KEY 2 - -/* WEP settings */ -#define HERMES_WEP_PRIVACY_INVOKED 0x0001 -#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 -#define HERMES_WEP_HOST_ENCRYPT 0x0010 -#define HERMES_WEP_HOST_DECRYPT 0x0080 - -/* Symbol hostscan options */ -#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 -#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 -#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 -#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 - -/* - * Frame structures and constants - */ - -#define HERMES_DESCRIPTOR_OFFSET 0 -#define HERMES_802_11_OFFSET (14) -#define HERMES_802_3_OFFSET (14 + 32) -#define HERMES_802_2_OFFSET (14 + 32 + 14) -#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) -#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ -#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ -#define HERMES_RXSTAT_MSGTYPE (0xE000) -#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ - -/* Shift amount for key ID in RXSTAT and TXCTRL */ -#define HERMES_MIC_KEY_ID_SHIFT 11 - -struct hermes_tx_descriptor { - __le16 status; - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; - u8 tx_rate; - __le16 tx_control; -} __packed; - -#define HERMES_TXSTAT_RETRYERR (0x0001) -#define HERMES_TXSTAT_AGEDERR (0x0002) -#define HERMES_TXSTAT_DISCON (0x0004) -#define HERMES_TXSTAT_FORMERR (0x0008) - -#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ -#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ -#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ -#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ -#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ -#define HERMES_TXCTRL_ALT_RTRY (0x0020) - -/* Inquiry constants and data types */ - -#define HERMES_INQ_TALLIES (0xF100) -#define HERMES_INQ_SCAN (0xF101) -#define HERMES_INQ_CHANNELINFO (0xF102) -#define HERMES_INQ_HOSTSCAN (0xF103) -#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) -#define HERMES_INQ_LINKSTATUS (0xF200) -#define HERMES_INQ_SEC_STAT_AGERE (0xF202) - -struct hermes_tallies_frame { - __le16 TxUnicastFrames; - __le16 TxMulticastFrames; - __le16 TxFragments; - __le16 TxUnicastOctets; - __le16 TxMulticastOctets; - __le16 TxDeferredTransmissions; - __le16 TxSingleRetryFrames; - __le16 TxMultipleRetryFrames; - __le16 TxRetryLimitExceeded; - __le16 TxDiscards; - __le16 RxUnicastFrames; - __le16 RxMulticastFrames; - __le16 RxFragments; - __le16 RxUnicastOctets; - __le16 RxMulticastOctets; - __le16 RxFCSErrors; - __le16 RxDiscards_NoBuffer; - __le16 TxDiscardsWrongSA; - __le16 RxWEPUndecryptable; - __le16 RxMsgInMsgFragments; - __le16 RxMsgInBadMsgFragments; - /* Those last are probably not available in very old firmwares */ - __le16 RxDiscards_WEPICVError; - __le16 RxDiscards_WEPExcluded; -} __packed; - -/* Grabbed from wlan-ng - Thanks Mark... - Jean II - * This is the result of a scan inquiry command */ -/* Structure describing info about an Access Point */ -struct prism2_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - u8 rates[10]; /* Bit rate supported */ - __le16 proberesp_rate; /* Data rate of the response frame */ - __le16 atim; /* ATIM window time, Kus (hostscan only) */ -} __packed; - -/* Same stuff for the Lucent/Agere card. - * Thanks to h1kari - Jean II */ -struct agere_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ -} __packed; - -/* Moustafa: Scan structure for Symbol cards */ -struct symbol_scan_apinfo { - u8 channel; /* Channel where the AP sits */ - u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - __le16 rates[5]; /* Bit rate supported */ - __le16 basic_rates; /* Basic rates bitmask */ - u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ - u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ -} __packed; - -union hermes_scan_info { - struct agere_scan_apinfo a; - struct prism2_scan_apinfo p; - struct symbol_scan_apinfo s; -}; - -/* Extended scan struct for HERMES_INQ_CHANNELINFO. - * wl_lkm calls this an ACS scan (Automatic Channel Select). - * Keep out of union hermes_scan_info because it is much bigger than - * the older scan structures. */ -struct agere_ext_scan_info { - __le16 reserved0; - - u8 noise; - u8 level; - u8 rx_flow; - u8 rate; - __le16 reserved1[2]; - - __le16 frame_control; - __le16 dur_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - __le16 sequence; - u8 addr4[ETH_ALEN]; - - __le16 data_length; - - /* Next 3 fields do not get filled in. */ - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - __le16 len_type; - - __le64 timestamp; - __le16 beacon_interval; - __le16 capabilities; - u8 data[]; -} __packed; - -#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) -#define HERMES_LINKSTATUS_CONNECTED (0x0001) -#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) -#define HERMES_LINKSTATUS_AP_CHANGE (0x0003) -#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) -#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) -#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) - -struct hermes_linkstatus { - __le16 linkstatus; /* Link status */ -} __packed; - -struct hermes_response { - u16 status, resp0, resp1, resp2; -}; - -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - __le16 len; - __le16 val[16]; -} __packed; - -struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __packed; - -/* Timeouts */ -#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ - -struct hermes; - -/* Functions to access hardware */ -struct hermes_ops { - int (*init)(struct hermes *hw); - int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp); - int (*init_cmd_wait)(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp); - int (*allocate)(struct hermes *hw, u16 size, u16 *fid); - int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen, - u16 *length, void *buf); - int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid, - unsigned buflen, u16 *length, void *buf); - int (*write_ltv)(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value); - int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset); - int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset); - int (*read_pda)(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len); - int (*program_init)(struct hermes *hw, u32 entry_point); - int (*program_end)(struct hermes *hw); - int (*program)(struct hermes *hw, const char *buf, - u32 addr, u32 len); - void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags); - void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags); - void (*lock_irq)(spinlock_t *lock); - void (*unlock_irq)(spinlock_t *lock); -}; - -/* Basic control structure */ -struct hermes { - void __iomem *iobase; - int reg_spacing; -#define HERMES_16BIT_REGSPACING 0 -#define HERMES_32BIT_REGSPACING 1 - u16 inten; /* Which interrupts should be enabled? */ - bool eeprom_pda; - const struct hermes_ops *ops; - void *priv; -}; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) \ - (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_write_reg(hw, off, val) \ - (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) -#define hermes_write_regn(hw, name, val) \ - hermes_write_reg((hw), HERMES_##name, (val)) - -/* Function prototypes */ -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing); - -/* Inline functions */ - -static inline int hermes_present(struct hermes *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_set_irqmask(struct hermes *hw, u16 events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, NULL); -} - -static inline int hermes_disable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), - 0, NULL); -} - -/* Initiate an INQUIRE command (tallies or scan). The result will come as an - * information frame in __orinoco_ev_info() */ -static inline int hermes_inquire(struct hermes *hw, u16 rid) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); -} - -#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1) -#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -static inline void hermes_read_words(struct hermes *hw, int off, - void *buf, unsigned count) -{ - off = off << hw->reg_spacing; - ioread16_rep(hw->iobase + off, buf, count); -} - -static inline void hermes_write_bytes(struct hermes *hw, int off, - const char *buf, unsigned count) -{ - off = off << hw->reg_spacing; - iowrite16_rep(hw->iobase + off, buf, count >> 1); - if (unlikely(count & 1)) - iowrite8(buf[count - 1], hw->iobase + off); -} - -static inline void hermes_clear_words(struct hermes *hw, int off, - unsigned count) -{ - unsigned i; - - off = off << hw->reg_spacing; - - for (i = 0; i < count; i++) - iowrite16(0, hw->iobase + off); -} - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \ - (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hw->ops->write_ltv((hw), (bap), (rid), \ - HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf))) - -static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid, - u16 word) -{ - __le16 rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -#endif /* _HERMES_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.c b/drivers/net/wireless/intersil/orinoco/hermes_dld.c deleted file mode 100644 index dbeadfcfefe2..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Hermes download helper. - * - * This helper: - * - is capable of writing to the volatile area of the hermes device - * - is currently not capable of writing to non-volatile areas - * - provide helpers to identify and update plugin data - * - is not capable of interpreting a fw image directly. That is up to - * the main card driver. - * - deals with Hermes I devices. It can probably be modified to deal - * with Hermes II devices - * - * Copyright (C) 2007, David Kilroy - * - * Plug data code slightly modified from spectrum_cs driver - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on information in wl_lkm_718 Agere driver - * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include "hermes.h" -#include "hermes_dld.h" - -#define PFX "hermes_dld: " - -/* End markers used in dblocks */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[]; /* data to be written */ -} __packed; - -/* - * Plug Data References are located in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[]; /* next PDR starts here */ -} __packed; - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[]; /* plug data */ -} __packed; - -/*** FW data block access functions ***/ - -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -/*** PDR Access functions ***/ - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -/*** PDI Access functions ***/ - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - -/*** Plug Data Functions ***/ - -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static const struct pdr * -hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end) -{ - const struct pdr *pdr = first_pdr; - - end -= sizeof(struct pdr); - - while (((void *) pdr <= end) && - (pdr_id(pdr) != PDI_END)) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - -/* Scan production data items for a particular entry */ -static const struct pdi * -hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end) -{ - const struct pdi *pdi = first_pdi; - - end -= sizeof(struct pdi); - - while (((void *) pdi <= end) && - (pdi_id(pdi) != PDI_END)) { - - /* If the record ID matches, we are done */ - if (pdi_id(pdi) == record_id) - return pdi; - - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return NULL; -} - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr, - const struct pdi *pdi, const void *pdr_end) -{ - const struct pdr *pdr; - - /* Find the PDR corresponding to this PDI */ - pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi)); - - return 0; -} - -/* Parse PDA and write the records into the adapter - * - * Attempt to write every records that is in the specified pda - * which also has a valid production data record for the firmware. - */ -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - int ret; - const struct pdi *pdi; - const struct pdr *pdr; - - pdr = (const struct pdr *) first_pdr; - pda_end -= sizeof(struct pdi); - - /* Go through every PDI and plug them into the adapter */ - pdi = (const struct pdi *) (pda + 2); - while (((void *) pdi <= pda_end) && - (pdi_id(pdi) != PDI_END)) { - ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} - -/* Identify the total number of bytes in all blocks - * including the header data. - */ -size_t -hermes_blocks_length(const char *first_block, const void *end) -{ - const struct dblock *blk = (const struct dblock *) first_block; - int total_len = 0; - int len; - - end -= sizeof(*blk); - - /* Skip all blocks to locate Plug Data References - * (Spectrum CS) */ - while (((void *) blk <= end) && - (dblock_addr(blk) != BLOCK_END)) { - len = dblock_len(blk); - total_len += sizeof(*blk) + len; - blk = (struct dblock *) &blk->data[len]; - } - - return total_len; -} - -/*** Hermes programming ***/ - -/* Program the data blocks */ -int hermes_program(struct hermes *hw, const char *first_block, const void *end) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; - int err = 0; - - blk = (const struct dblock *) first_block; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while ((blkaddr != BLOCK_END) && - (((void *) blk + blklen) <= end)) { - pr_debug(PFX "Programming block of length %d " - "to address 0x%08x\n", blklen, blkaddr); - - err = hw->ops->program(hw, blk->data, blkaddr, blklen); - if (err) - break; - - blk = (const struct dblock *) &blk->data[blklen]; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return err; -} - -/*** Default plugging data for Hermes I ***/ -/* Values from wl_lkm_718/hcf/dhf.c */ - -#define DEFINE_DEFAULT_PDR(pid, length, data) \ -static const struct { \ - __le16 len; \ - __le16 id; \ - u8 val[length]; \ -} __packed default_pdr_data_##pid = { \ - cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ - sizeof(__le16)) - 1), \ - cpu_to_le16(pid), \ - data \ -} - -#define DEFAULT_PDR(pid) default_pdr_data_##pid - -/* HWIF Compatibility */ -DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); - -/* PPPPSign */ -DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); - -/* PPPPProf */ -DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); - -/* Antenna diversity */ -DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); - -/* Modem VCO band Set-up */ -DEFINE_DEFAULT_PDR(0x0160, 28, - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"); - -/* Modem Rx Gain Table Values */ -DEFINE_DEFAULT_PDR(0x0161, 256, - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3E\01\x3E\x01\x3D\x01" - "\x3D\x01\x3C\01\x3C\x01\x3B\x01" - "\x3B\x01\x3A\01\x3A\x01\x39\x01" - "\x39\x01\x38\01\x38\x01\x37\x01" - "\x37\x01\x36\01\x36\x01\x35\x01" - "\x35\x01\x34\01\x34\x01\x33\x01" - "\x33\x01\x32\x01\x32\x01\x31\x01" - "\x31\x01\x30\x01\x30\x01\x7B\x01" - "\x7B\x01\x7A\x01\x7A\x01\x79\x01" - "\x79\x01\x78\x01\x78\x01\x77\x01" - "\x77\x01\x76\x01\x76\x01\x75\x01" - "\x75\x01\x74\x01\x74\x01\x73\x01" - "\x73\x01\x72\x01\x72\x01\x71\x01" - "\x71\x01\x70\x01\x70\x01\x68\x01" - "\x68\x01\x67\x01\x67\x01\x66\x01" - "\x66\x01\x65\x01\x65\x01\x57\x01" - "\x57\x01\x56\x01\x56\x01\x55\x01" - "\x55\x01\x54\x01\x54\x01\x53\x01" - "\x53\x01\x52\x01\x52\x01\x51\x01" - "\x51\x01\x50\x01\x50\x01\x48\x01" - "\x48\x01\x47\x01\x47\x01\x46\x01" - "\x46\x01\x45\x01\x45\x01\x44\x01" - "\x44\x01\x43\x01\x43\x01\x42\x01" - "\x42\x01\x41\x01\x41\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01"); - -/* Write PDA according to certain rules. - * - * For every production data record, look for a previous setting in - * the pda, and use that. - * - * For certain records, use defaults if they are not found in pda. - */ -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - const struct pdr *pdr = (const struct pdr *) first_pdr; - const struct pdi *first_pdi = (const struct pdi *) &pda[2]; - const struct pdi *pdi; - const struct pdi *default_pdi = NULL; - const struct pdi *outdoor_pdi; - int record_id; - - pdr_end -= sizeof(struct pdr); - - while (((void *) pdr <= pdr_end) && - (pdr_id(pdr) != PDI_END)) { - /* - * For spectrum_cs firmwares, - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - break; - record_id = pdr_id(pdr); - - pdi = hermes_find_pdi(first_pdi, record_id, pda_end); - if (pdi) - pr_debug(PFX "Found record 0x%04x at %p\n", - record_id, pdi); - - switch (record_id) { - case 0x110: /* Modem REFDAC values */ - case 0x120: /* Modem VGDAC values */ - outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1, - pda_end); - default_pdi = NULL; - if (outdoor_pdi) { - pdi = outdoor_pdi; - pr_debug(PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); - } - break; - case 0x5: /* HWIF Compatibility */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); - break; - case 0x108: /* PPPPSign */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); - break; - case 0x109: /* PPPPProf */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); - break; - case 0x150: /* Antenna diversity */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); - break; - case 0x160: /* Modem VCO band Set-up */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); - break; - case 0x161: /* Modem Rx Gain Table Values */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); - break; - default: - default_pdi = NULL; - break; - } - if (!pdi && default_pdi) { - /* Use default */ - pdi = default_pdi; - pr_debug(PFX "Using default record 0x%04x at %p\n", - record_id, pdi); - } - - if (pdi) { - /* Lengths of the data in PDI and PDR must match */ - if ((pdi_len(pdi) == pdr_len(pdr)) && - ((void *) pdi->data + pdi_len(pdi) < pda_end)) { - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), - pdi_len(pdi)); - } - } - - pdr++; - } - return 0; -} diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.h b/drivers/net/wireless/intersil/orinoco/hermes_dld.h deleted file mode 100644 index b5377e232c63..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007, David Kilroy - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ -#ifndef _HERMES_DLD_H -#define _HERMES_DLD_H - -#include "hermes.h" - -int hermesi_program_init(struct hermes *hw, u32 offset); -int hermesi_program_end(struct hermes *hw); -int hermes_program(struct hermes *hw, const char *first_block, const void *end); - -int hermes_read_pda(struct hermes *hw, - __le16 *pda, - u32 pda_addr, - u16 pda_len, - int use_eeprom); -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); - -size_t hermes_blocks_length(const char *first_block, const void *end); - -#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_rid.h b/drivers/net/wireless/intersil/orinoco/hermes_rid.h deleted file mode 100644 index 42eb67dea1df..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_rid.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _HERMES_RID_H -#define _HERMES_RID_H - -/* - * Configuration RIDs - */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 -#define HERMES_RID_CNFOWNMACADDR 0xFC01 -#define HERMES_RID_CNFDESIREDSSID 0xFC02 -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 -#define HERMES_RID_CNFOWNSSID 0xFC04 -#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 -#define HERMES_RID_CNFMAXDATALEN 0xFC07 -#define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 -#define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HERMES_RID_CNFOWNNAME 0xFC0E -#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HERMES_RID_CNFWDSADDRESS1 0xFC11 -#define HERMES_RID_CNFWDSADDRESS2 0xFC12 -#define HERMES_RID_CNFWDSADDRESS3 0xFC13 -#define HERMES_RID_CNFWDSADDRESS4 0xFC14 -#define HERMES_RID_CNFWDSADDRESS5 0xFC15 -#define HERMES_RID_CNFWDSADDRESS6 0xFC16 -#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 -#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 -#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 -#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A -#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B -#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B -#define HERMES_RID_CNFTXCONTROL 0xFC2C -#define HERMES_RID_CNFROAMINGMODE 0xFC2D -#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E -#define HERMES_RID_CNFRCVCRCERROR 0xFC30 -#define HERMES_RID_CNFMMLIFE 0xFC31 -#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 -#define HERMES_RID_CNFBEACONINT 0xFC33 -#define HERMES_RID_CNFAPPCFINFO 0xFC34 -#define HERMES_RID_CNFSTAPCFINFO 0xFC35 -#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HERMES_RID_CNFTIMCTRL 0xFC40 -#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 -#define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 -#define HERMES_RID_CNFCREATEIBSS 0xFC81 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 -#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 -#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 -#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 -#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 -#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A -#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B -#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C -#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D -#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB -#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 -#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 -#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 -#define HERMES_RID_CNFBASICRATES 0xFCB3 -#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 -#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 -#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 -#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 -#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 -#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 -#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA -#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB -#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 -#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 -#define HERMES_RID_CNFTICKTIME 0xFCE0 -#define HERMES_RID_CNFSCANREQUEST 0xFCE1 -#define HERMES_RID_CNFJOINREQUEST 0xFCE2 -#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 -#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 -#define HERMES_RID_CNFHOSTSCAN 0xFCE5 - -/* - * Information RIDs - */ -#define HERMES_RID_MAXLOADTIME 0xFD00 -#define HERMES_RID_DOWNLOADBUFFER 0xFD01 -#define HERMES_RID_PRIID 0xFD02 -#define HERMES_RID_PRISUPRANGE 0xFD03 -#define HERMES_RID_CFIACTRANGES 0xFD04 -#define HERMES_RID_NICSERNUM 0xFD0A -#define HERMES_RID_NICID 0xFD0B -#define HERMES_RID_MFISUPRANGE 0xFD0C -#define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 -#define HERMES_RID_REGULATORYDOMAINS 0xFD11 -#define HERMES_RID_TEMPTYPE 0xFD12 -#define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 -#define HERMES_RID_STASUPRANGE 0xFD21 -#define HERMES_RID_MFIACTRANGES 0xFD22 -#define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 -#define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 -#define HERMES_RID_CURRENTBSSID 0xFD42 -#define HERMES_RID_COMMSQUALITY 0xFD43 -#define HERMES_RID_CURRENTTXRATE 0xFD44 -#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B -#define HERMES_RID_CFPOLLABLE 0xFD4C -#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 -#define HERMES_RID_CURRENTTXRATE1 0xFD80 -#define HERMES_RID_CURRENTTXRATE2 0xFD81 -#define HERMES_RID_CURRENTTXRATE3 0xFD82 -#define HERMES_RID_CURRENTTXRATE4 0xFD83 -#define HERMES_RID_CURRENTTXRATE5 0xFD84 -#define HERMES_RID_CURRENTTXRATE6 0xFD85 -#define HERMES_RID_OWNMACADDR 0xFD86 -#define HERMES_RID_SCANRESULTSTABLE 0xFD88 -#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 -#define HERMES_RID_CURRENT_WPA_IE 0xFD8A -#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B -#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C -#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D -#define HERMES_RID_TXQUEUEEMPTY 0xFD91 -#define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 -#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 -#define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 -#define HERMES_RID_BUILDSEQ 0xFFFE -#define HERMES_RID_FWID 0xFFFF - -#endif diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c deleted file mode 100644 index 4fcca08e50de..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ /dev/null @@ -1,1362 +0,0 @@ -/* Encapsulate basic setting changes and retrieval on Hermes hardware - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include -#include -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" - -#define SYMBOL_MAX_VER_LEN (14) - -/* Symbol firmware has a bug allocating buffers larger than this */ -#define TX_NICBUF_SIZE_BUG 1585 - -/********************************************************************/ -/* Data tables */ -/********************************************************************/ - -/* This tables gives the actual meanings of the bitrate IDs returned - * by the firmware. */ -static const struct { - int bitrate; /* in 100s of kilobits */ - int automatic; - u16 agere_txratectrl; - u16 intersil_txratectrl; -} bitrate_table[] = { - {110, 1, 3, 15}, /* Entry 0 is the default */ - {10, 0, 1, 1}, - {10, 1, 1, 1}, - {20, 0, 2, 2}, - {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, - {110, 0, 5, 8}, -}; -#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) - -/* Firmware version encoding */ -struct comp_id { - u16 id, variant, major, minor; -} __packed; - -static inline enum fwtype determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties - * This function can be called before we have registerred with netdev, - * so all errors go out with dev_* rather than printk - * - * If non-NULL stores a firmware description in fw_name. - * If non-NULL stores a HW version in hw_ver - * - * These are output via generic cfg80211 ethtool support. - */ -int determine_fw_capabilities(struct orinoco_private *priv, - char *fw_name, size_t fw_name_len, - u32 *hw_ver) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - dev_err(dev, "Cannot read hardware identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", - nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); - - if (hw_ver) - *hw_ver = (((nic_id.id & 0xff) << 24) | - ((nic_id.variant & 0xff) << 16) | - ((nic_id.major & 0xff) << 8) | - (nic_id.minor & 0xff)); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - dev_err(dev, "Cannot read station identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", - sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - dev_err(dev, "Primary firmware is active\n"); - return -ENODEV; - case 0x14b: - dev_err(dev, "Tertiary firmware is active\n"); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - dev_notice(dev, "Unknown station ID, please report\n"); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d", - sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - dev_warn(dev, "Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) - | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) - | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - if (fw_name) - snprintf(fw_name, fw_name_len, "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d", - sta_id.major, sta_id.minor, sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - dev_notice(dev, "Intersil firmware earlier than v0.8.x" - " - several features not supported\n"); - priv->ibss_port = 1; - } - break; - } - if (fw_name) - dev_info(dev, "Firmware determined as %s\n", fw_name); - -#ifndef CONFIG_HERMES_PRISM - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - dev_err(dev, "Support for Prism chipset is not enabled\n"); - return -ENODEV; - } -#endif - - return 0; -} - -/* Read settings from EEPROM into our private structure. - * MAC address gets dropped into callers buffer - * Can be called before netdev registration. - */ -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) -{ - struct device *dev = priv->dev; - struct hermes_idstring nickbuf; - struct hermes *hw = &priv->hw; - int len; - int err; - u16 reclen; - - /* Get the MAC address */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev_addr); - if (err) { - dev_warn(dev, "Failed to read MAC address!\n"); - goto out; - } - - dev_dbg(dev, "MAC address %pM\n", dev_addr); - - /* Get the station name */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - dev_err(dev, "failed to read station name\n"); - goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - dev_dbg(dev, "Station name \"%s\"\n", priv->nick); - - /* Get allowed channels */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - dev_err(dev, "Failed to read channel list!\n"); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) - priv->has_sensitivity = 0; - - /* Get initial RTS threshold */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - dev_err(dev, "Failed to read RTS threshold!\n"); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - dev_err(dev, "Failed to read fragmentation settings!\n"); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - dev_err(dev, "Failed to read power management " - "period!\n"); - goto out; - } - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - dev_err(dev, "Failed to read power management " - "timeout!\n"); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) { - dev_err(dev, "Failed to read preamble setup\n"); - goto out; - } - } - - /* Retry settings */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, - &priv->short_retry_limit); - if (err) { - dev_err(dev, "Failed to read short retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, - &priv->long_retry_limit); - if (err) { - dev_err(dev, "Failed to read long retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, - &priv->retry_lifetime); - if (err) { - dev_err(dev, "Failed to read max retry lifetime\n"); - goto out; - } - -out: - return err; -} - -/* Can be called before netdev registration */ -int orinoco_hw_allocate_fid(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - - dev_warn(dev, "Firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - err ? "failed!" : "ok."); - } - - return err; -} - -int orinoco_get_bitratemode(int bitrate, int automatic) -{ - int ratemode = -1; - int i; - - if ((bitrate != 10) && (bitrate != 20) && - (bitrate != 55) && (bitrate != 110)) - return ratemode; - - for (i = 0; i < BITRATE_TABLE_SIZE; i++) { - if ((bitrate_table[i].bitrate == bitrate) && - (bitrate_table[i].automatic == automatic)) { - ratemode = i; - break; - } - } - return ratemode; -} - -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) -{ - BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); - - *bitrate = bitrate_table[ratemode].bitrate * 100000; - *automatic = bitrate_table[ratemode].automatic; -} - -int orinoco_hw_program_rids(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct wireless_dev *wdev = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), - dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Reset promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* Record mode change */ - wdev->iftype = priv->iw_mode; - - return 0; -} - -/* Get tsc from the firmware */ -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u8 tsc_arr[4][ORINOCO_SEQ_LEN]; - - if ((key < 0) || (key >= 4)) - return -EINVAL; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, - sizeof(tsc_arr), NULL, &tsc_arr); - if (!err) - memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); - - return err; -} - -int __orinoco_hw_set_bitrate(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int ratemode = priv->bitratemode; - int err = 0; - - if (ratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, ratemode); - return -EINVAL; - } - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].intersil_txratectrl); - break; - default: - BUG(); - } - - return err; -} - -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) -{ - struct hermes *hw = &priv->hw; - int i; - int err = 0; - u16 val; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CURRENTTXRATE, &val); - if (err) - return err; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ - /* Note : in Lucent firmware, the return value of - * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, - * and therefore is totally different from the - * encoding of HERMES_RID_CNFTXRATECONTROL. - * Don't forget that 6Mb/s is really 5.5Mb/s */ - if (val == 6) - *bitrate = 5500000; - else - *bitrate = val * 1000000; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - for (i = 0; i < BITRATE_TABLE_SIZE; i++) - if (bitrate_table[i].intersil_txratectrl == val) { - *bitrate = bitrate_table[i].bitrate * 100000; - break; - } - - if (i >= BITRATE_TABLE_SIZE) { - printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", - priv->ndev->name, val); - err = -EIO; - } - - break; - default: - BUG(); - } - - return err; -} - -/* Set fixed AP address */ -int __orinoco_hw_set_wap(struct orinoco_private *priv) -{ - int roaming_flag; - int err = 0; - struct hermes *hw = &priv->hw; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* not supported */ - break; - case FIRMWARE_TYPE_INTERSIL: - if (priv->bssid_fixed) - roaming_flag = 2; - else - roaming_flag = 1; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFROAMINGMODE, - roaming_flag); - break; - case FIRMWARE_TYPE_SYMBOL: - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFMANDATORYBSSID_SYMBOL, - &priv->desired_bssid); - break; - } - return err; -} - -/* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_enc() or directly from - * orinoco_ioctl_setiwencode(). In the later case the association - * with the AP is not broken (if the firmware can handle it), - * which is needed for 802.1x implementations. */ -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int i; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - { - struct orinoco_key keys[ORINOCO_MAX_KEYS]; - - memset(&keys, 0, sizeof(keys)); - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - int len = min(priv->keys[i].key_len, - ORINOCO_MAX_KEY_SIZE); - memcpy(&keys[i].data, priv->keys[i].key, len); - if (len > SMALL_KEY_SIZE) - keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); - else if (len > 0) - keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); - else - keys[i].len = cpu_to_le16(0); - } - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &keys); - if (err) - return err; - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - break; - } - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - { - int keylen; - - /* Force uniform key length to work around - * firmware bugs */ - keylen = priv->keys[priv->tx_key].key_len; - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, priv->tx_key, keylen); - return -E2BIG; - } else if (keylen > SMALL_KEY_SIZE) - keylen = LARGE_KEY_SIZE; - else if (keylen > 0) - keylen = SMALL_KEY_SIZE; - else - keylen = 0; - - /* Write all 4 keys */ - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - u8 key[LARGE_KEY_SIZE] = { 0 }; - - memcpy(key, priv->keys[i].key, - priv->keys[i].key_len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - key); - if (err) - return err; - } - - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - } - break; - } - - return 0; -} - -int __orinoco_hw_setup_enc(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; - int enc_flag; - - /* Setup WEP keys */ - if (priv->encode_alg == ORINOCO_ALG_WEP) - __orinoco_hw_setup_wepkeys(priv); - - if (priv->wep_restrict) - auth_flag = HERMES_AUTH_SHARED_KEY; - else - auth_flag = HERMES_AUTH_OPEN; - - if (priv->wpa_enabled) - enc_flag = 2; - else if (priv->encode_alg == ORINOCO_ALG_WEP) - enc_flag = 1; - else - enc_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - /* Enable the shared-key authentication. */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION_AGERE, - auth_flag); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - enc_flag); - if (err) - return err; - - if (priv->has_wpa) { - /* Set WPA key management */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, - priv->key_mgmt); - if (err) - return err; - } - - break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - if (priv->wep_restrict || - (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | - HERMES_WEP_EXCL_UNENCRYPTED; - else - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, - auth_flag); - if (err) - return err; - } else - master_wep_flag = 0; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - master_wep_flag |= HERMES_WEP_HOST_DECRYPT; - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; - - break; - } - - return 0; -} - -/* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be NULL or up to 8 bytes - * tsc must be NULL or up to 8 bytes - */ -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len) -{ - struct { - __le16 idx; - u8 rsc[ORINOCO_SEQ_LEN]; - struct { - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; - } tkip; - u8 tsc[ORINOCO_SEQ_LEN]; - } __packed buf; - struct hermes *hw = &priv->hw; - int ret; - int err; - int k; - u16 xmitting; - - key_idx &= 0x3; - - if (set_tx) - key_idx |= 0x8000; - - buf.idx = cpu_to_le16(key_idx); - if (key_len != sizeof(buf.tkip)) - return -EINVAL; - memcpy(&buf.tkip, key, sizeof(buf.tkip)); - - if (rsc_len > sizeof(buf.rsc)) - rsc_len = sizeof(buf.rsc); - - if (tsc_len > sizeof(buf.tsc)) - tsc_len = sizeof(buf.tsc); - - memset(buf.rsc, 0, sizeof(buf.rsc)); - memset(buf.tsc, 0, sizeof(buf.tsc)); - - if (rsc != NULL) - memcpy(buf.rsc, rsc, rsc_len); - - if (tsc != NULL) - memcpy(buf.tsc, tsc, tsc_len); - else - buf.tsc[4] = 0x10; - - /* Wait up to 100ms for tx queue to empty */ - for (k = 100; k > 0; k--) { - udelay(1000); - ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, - &xmitting); - if (ret || !xmitting) - break; - } - - if (k == 0) - ret = -ETIMEDOUT; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, - &buf); - - return ret ? ret : err; -} - -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, - key_idx); - if (err) - printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", - priv->ndev->name, err, key_idx); - return err; -} - -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - priv->ndev->name, err); - } else - priv->promiscuous = promisc; - } - - /* If we're not in promiscuous mode, then we need to set the - * group address if either we want to multicast, or if we were - * multicasting and want to stop */ - if (!promisc && (mc_count || priv->mc_count)) { - struct netdev_hw_addr *ha; - struct hermes_multicast mclist; - int i = 0; - - netdev_for_each_mc_addr(ha, dev) { - if (i == mc_count) - break; - memcpy(mclist.addr[i++], ha->addr, ETH_ALEN); - } - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - priv->ndev->name, err); - else - priv->mc_count = mc_count; - } - return err; -} - -/* Return : < 0 -> error code ; >= 0 -> length */ -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]) -{ - struct hermes *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - BUG_ON(len > IW_ESSID_MAX_SIZE); - - memset(buf, 0, IW_ESSID_MAX_SIZE); - memcpy(buf, p, len); - err = len; - - fail_unlock: - orinoco_unlock(priv, &flags); - - return err; -} - -int orinoco_hw_get_freq(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u16 channel; - int freq = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, - &channel); - if (err) - goto out; - - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; - } - - if ((channel < 1) || (channel > NUM_CHANNELS)) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; - - } - freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - out: - orinoco_unlock(priv, &flags); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) -{ - struct hermes *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - - return 0; -} - -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - break; - } - case FIRMWARE_TYPE_AGERE: - if (ssid->ssid_len > 0) { - struct hermes_idstring idbuf; - size_t len = ssid->ssid_len; - - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, ssid->ssid, len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -/* Disassociate from node with BSSID addr */ -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code) -{ - struct hermes *hw = &priv->hw; - int err; - - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __packed buf; - - /* Currently only supported by WPA enabled Agere fw */ - if (!priv->has_wpa) - return -EOPNOTSUPP; - - memcpy(buf.addr, addr, ETH_ALEN); - buf.reason_code = cpu_to_le16(reason_code); - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); - return err; -} - -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, addr); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h deleted file mode 100644 index da5804dbdf34..000000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Encapsulate basic setting changes on Hermes hardware - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_HW_H_ -#define _ORINOCO_HW_H_ - -#include -#include -#include - -/* Hardware BAPs */ -#define USER_BAP 0 -#define IRQ_BAP 1 - -/* WEP key sizes */ -#define SMALL_KEY_SIZE 5 -#define LARGE_KEY_SIZE 13 - -/* Number of supported channels */ -#define NUM_CHANNELS 14 - -/* Forward declarations */ -struct orinoco_private; - -int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name, - size_t fw_name_len, u32 *hw_ver); -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); -int orinoco_hw_allocate_fid(struct orinoco_private *priv); -int orinoco_get_bitratemode(int bitrate, int automatic); -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); - -int orinoco_hw_program_rids(struct orinoco_private *priv); -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); -int __orinoco_hw_set_bitrate(struct orinoco_private *priv); -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); -int __orinoco_hw_set_wap(struct orinoco_private *priv); -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); -int __orinoco_hw_setup_enc(struct orinoco_private *priv); -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len); -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc); -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]); -int orinoco_hw_get_freq(struct orinoco_private *priv); -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max); -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid); -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code); -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr); - -#endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c deleted file mode 100644 index 7df88d20ff3d..000000000000 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ /dev/null @@ -1,2414 +0,0 @@ -/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c) - * - * A driver for Hermes or Prism 2 chipset based PCMCIA wireless - * adaptors, with Lucent/Agere, Intersil or Symbol firmware. - * - * Current maintainers (as of 29 September 2003) are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corporation 2001-2003. - * Copyright (C) 2000 David Gibson, Linuxcare Australia. - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.stud.fh-dortmund.de/~andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. */ - -/* - * TODO - * o Handle de-encapsulation within network layer, provide 802.11 - * headers (patch from Thomas 'Dent' Mirlacher) - * o Fix possible races in SPY handling. - * o Disconnect wireless extensions from fundamental configuration. - * o (maybe) Software WEP support (patch from Stano Meduna). - * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. - */ - -/* Locking and synchronization: - * - * The basic principle is that everything is serialized through a - * single spinlock, priv->lock. The lock is used in user, bh and irq - * context, so when taken outside hardirq context it should always be - * taken with interrupts disabled. The lock protects both the - * hardware and the struct orinoco_private. - * - * Another flag, priv->hw_unavailable indicates that the hardware is - * unavailable for an extended period of time (e.g. suspended, or in - * the middle of a hard reset). This flag is protected by the - * spinlock. All code which touches the hardware should check the - * flag after taking the lock, and if it is set, give up on whatever - * they are doing and drop the lock again. The orinoco_lock() - * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). - */ - -#define DRIVER_NAME "orinoco" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes_rid.h" -#include "hermes_dld.h" -#include "hw.h" -#include "scan.h" -#include "mic.h" -#include "fw.h" -#include "wext.h" -#include "cfg.h" -#include "main.h" - -#include "orinoco.h" - -/********************************************************************/ -/* Module information */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin & " - "David Gibson "); -MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based " - "and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Level of debugging. Used in the macros in orinoco.h */ -#ifdef ORINOCO_DEBUG -int orinoco_debug = ORINOCO_DEBUG; -EXPORT_SYMBOL(orinoco_debug); -module_param(orinoco_debug, int, 0644); -MODULE_PARM_DESC(orinoco_debug, "Debug level"); -#endif - -static bool suppress_linkstatus; /* = 0 */ -module_param(suppress_linkstatus, bool, 0644); -MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); - -static int ignore_disconnect; /* = 0 */ -module_param(ignore_disconnect, int, 0644); -MODULE_PARM_DESC(ignore_disconnect, - "Don't report lost link to the network layer"); - -int force_monitor; /* = 0 */ -module_param(force_monitor, int, 0644); -MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); - -/********************************************************************/ -/* Internal constants */ -/********************************************************************/ - -/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ -static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) - -#define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) - -#define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of - * how many events the - * device could - * legitimately generate */ - -#define DUMMY_FID 0xFFFF - -/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ - HERMES_MAX_MULTICAST : 0)*/ -#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) - -#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ - | HERMES_EV_TX | HERMES_EV_TXEXC \ - | HERMES_EV_WTERR | HERMES_EV_INFO \ - | HERMES_EV_INFDROP) - -/********************************************************************/ -/* Data types */ -/********************************************************************/ - -/* Beginning of the Tx descriptor, used in TxExc handling */ -struct hermes_txexc_data { - struct hermes_tx_descriptor desc; - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; -} __packed; - -/* Rx frame header except compatibility 802.3 header */ -struct hermes_rx_descriptor { - /* Control */ - __le16 status; - __le32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - __le32 reserved; - - /* 802.11 header */ - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - - /* Data length */ - __le16 data_len; -} __packed; - -struct orinoco_rx_data { - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - struct list_head list; -}; - -struct orinoco_scan_data { - void *buf; - size_t len; - int type; - struct list_head list; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int __orinoco_set_multicast_list(struct net_device *dev); -static int __orinoco_up(struct orinoco_private *priv); -static int __orinoco_down(struct orinoco_private *priv); -static int __orinoco_commit(struct orinoco_private *priv); - -/********************************************************************/ -/* Internal helper functions */ -/********************************************************************/ - -void set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case NL80211_IFTYPE_STATION: - priv->port_type = 1; - priv->createibss = 0; - break; - case NL80211_IFTYPE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - case NL80211_IFTYPE_MONITOR: - priv->port_type = 3; - priv->createibss = 0; - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -int orinoco_open(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = __orinoco_up(priv); - - if (!err) - priv->open = 1; - - orinoco_unlock(priv, &flags); - - return err; -} -EXPORT_SYMBOL(orinoco_open); - -int orinoco_stop(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - - /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface even if hw_unavailable is set - (e.g. as we're released after a PC Card removal) */ - orinoco_lock_irq(priv); - - priv->open = 0; - - err = __orinoco_down(priv); - - orinoco_unlock_irq(priv); - - return err; -} -EXPORT_SYMBOL(orinoco_stop); - -void orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); - return; - } - - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); -} -EXPORT_SYMBOL(orinoco_set_multicast_list); - -int orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* MTU + encapsulation + header length */ - if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > - (priv->nicbuf_size - ETH_HLEN)) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} -EXPORT_SYMBOL(orinoco_change_mtu); - -/********************************************************************/ -/* Tx path */ -/********************************************************************/ - -/* Add encapsulation and MIC to the existing SKB. - * The main xmit routine will then send the whole lot to the card. - * Need 8 bytes headroom - * Need 8 bytes tailroom - * - * With encapsulated ethernet II frame - * -------- - * 803.3 header (14 bytes) - * dst[6] - * -------- src[6] - * 803.3 header (14 bytes) len[2] - * dst[6] 803.2 header (8 bytes) - * src[6] encaps[6] - * len[2] <- leave alone -> len[2] - * -------- -------- <-- 0 - * Payload Payload - * ... ... - * - * -------- -------- - * MIC (8 bytes) - * -------- - * - * returns 0 on success, -ENOMEM on error. - */ -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic_buf) -{ - struct orinoco_tkip_key *key; - struct ethhdr *eh; - int do_mic; - - key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; - - do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && - (key != NULL)); - - if (do_mic) - *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | - HERMES_TXCTRL_MIC; - - eh = (struct ethhdr *)skb->data; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ - struct header_struct { - struct ethhdr eth; /* 802.3 header */ - u8 encap[6]; /* 802.2 header */ - } __packed hdr; - int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN); - - if (skb_headroom(skb) < ENCAPS_OVERHEAD) { - if (net_ratelimit()) - printk(KERN_ERR - "%s: Not enough headroom for 802.2 headers %d\n", - dev->name, skb_headroom(skb)); - return -ENOMEM; - } - - /* Fill in new header */ - memcpy(&hdr.eth, eh, 2 * ETH_ALEN); - hdr.eth.h_proto = htons(len); - memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - - /* Make room for the new header, and copy it in */ - eh = skb_push(skb, ENCAPS_OVERHEAD); - memcpy(eh, &hdr, sizeof(hdr)); - } - - /* Calculate Michael MIC */ - if (do_mic) { - size_t len = skb->len - ETH_HLEN; - u8 *mic = &mic_buf[0]; - - /* Have to write to an even address, so copy the spare - * byte across */ - if (skb->len % 2) { - *mic = skb->data[skb->len - 1]; - mic++; - } - - orinoco_mic(priv->tx_tfm_mic, key->tx_mic, - eh->h_dest, eh->h_source, 0 /* priority */, - skb->data + ETH_HLEN, - len, mic); - } - - return 0; -} -EXPORT_SYMBOL(orinoco_process_xmit_skb); - -static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - int err = 0; - u16 txfid = priv->txfid; - int tx_control; - unsigned long flags; - u8 mic_buf[MICHAEL_MIC_LEN + 1]; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic_buf[0]); - if (err) - goto drop; - - if (priv->has_alt_txcntl) { - /* WPA enabled firmwares have tx_cntl at the end of - * the 802.11 header. So write zeroed descriptor and - * 802.11 header at the same time - */ - char desc[HERMES_802_3_OFFSET]; - __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; - - memset(&desc, 0, sizeof(desc)); - - *txcntl = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - } else { - struct hermes_tx_descriptor desc; - - memset(&desc, 0, sizeof(desc)); - - desc.tx_control = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); - } - - err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - goto busy; - } - - if (tx_control & HERMES_TXCTRL_MIC) { - size_t offset = HERMES_802_3_OFFSET + skb->len; - size_t len = MICHAEL_MIC_LEN; - - if (offset % 2) { - offset--; - len++; - } - err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, - txfid, offset); - if (err) { - printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", - dev->name, err); - goto busy; - } - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, - txfid, NULL); - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - if (err == -EIO) - schedule_work(&priv->reset_work); - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 fid = hermes_read_regn(hw, ALLOCFID); - - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } - - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); -} - -static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw) -{ - dev->stats.tx_packets++; - - netif_wake_queue(dev); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw) -{ - struct net_device_stats *stats = &dev->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - u16 status; - struct hermes_txexc_data hdr; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - /* Read part of the frame header - we need status and addr1 */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_txexc_data), - fid, 0); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); - stats->tx_errors++; - - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - return; - } - - DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, - err, fid); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - status = le16_to_cpu(hdr.desc.status); - if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } - - netif_wake_queue(dev); -} - -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; - - schedule_work(&priv->reset_work); -} -EXPORT_SYMBOL(orinoco_tx_timeout); - -/********************************************************************/ -/* Rx path (data frames) */ -/********************************************************************/ - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int is_ethersnap(void *_hdr) -{ - u8 *hdr = _hdr; - - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(hdr, &encaps_hdr, 5) == 0) - && ((hdr[5] == 0x00) || (hdr[5] == 0xf8)); -} - -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct iw_quality wstats; - wstats.level = level - 0x95; - wstats.noise = noise - 0x95; - wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} - -static void orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, - desc->signal, desc->silence); - } -} - -/* - * orinoco_rx_monitor - handle received monitor frames. - * - * Arguments: - * dev network device - * rxfid received FID - * desc rx descriptor of the frame - * - * Call context: interrupt - */ -static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, - struct hermes_rx_descriptor *desc) -{ - u32 hdrlen = 30; /* return full header by default */ - u32 datalen = 0; - u16 fc; - int err; - int len; - struct sk_buff *skb; - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - len = le16_to_cpu(desc->data_len); - - /* Determine the size of the header and the data */ - fc = le16_to_cpu(desc->frame_ctl); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_TODS) - && (fc & IEEE80211_FCTL_FROMDS)) - hdrlen = 30; - else - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_MGMT: - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_CTL: - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PSPOLL: - case IEEE80211_STYPE_RTS: - case IEEE80211_STYPE_CFEND: - case IEEE80211_STYPE_CFENDACK: - hdrlen = 16; - break; - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = 10; - break; - } - break; - default: - /* Unknown frame type */ - break; - } - - /* sanity check the length */ - if (datalen > IEEE80211_MAX_DATA_LEN + 12) { - printk(KERN_DEBUG "%s: oversized monitor frame, " - "data length = %d\n", dev->name, datalen); - stats->rx_length_errors++; - goto update_stats; - } - - skb = dev_alloc_skb(hdrlen + datalen); - if (!skb) { - printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", - dev->name); - goto update_stats; - } - - /* Copy the 802.11 header to the skb */ - skb_put_data(skb, &(desc->frame_ctl), hdrlen); - skb_reset_mac_header(skb); - - /* If any, copy the data from the card to the skb */ - if (datalen > 0) { - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), - ALIGN(datalen, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading monitor frame\n", - dev->name, err); - goto drop; - } - } - - skb->dev = dev; - skb->ip_summed = CHECKSUM_NONE; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - netif_rx(skb); - return; - - drop: - dev_kfree_skb_irq(skb); - update_stats: - stats->rx_errors++; - stats->rx_dropped++; -} - -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length; - struct hermes_rx_descriptor *desc; - struct orinoco_rx_data *rx_data; - int err; - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if (!desc) - goto update_stats; - - rxfid = hermes_read_regn(hw, RXFID); - - err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), - rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - goto update_stats; - } - - status = le16_to_cpu(desc->status); - - if (status & HERMES_RXSTAT_BADCRC) { - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - stats->rx_crc_errors++; - goto update_stats; - } - - /* Handle frames in monitor mode */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, desc); - goto out; - } - - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - wstats->discard.code++; - goto update_stats; - } - - length = le16_to_cpu(desc->data_len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - goto out; - } - if (length > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - goto update_stats; - } - - /* Payload size does not include Michael MIC. Increase payload - * size to read it together with the data. */ - if (status & HERMES_RXSTAT_MIC) - length += MICHAEL_MIC_LEN; - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - goto update_stats; - } - - /* We'll prepend the header, so reserve space for it. The worst - case is no decapsulation, when 802.3 header is prepended and - nothing is removed. 2 is for aligning the IP header. */ - skb_reserve(skb, ETH_HLEN + 2); - - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length), - ALIGN(length, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - goto drop; - } - - /* Add desc and skb to rx queue */ - rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); - if (!rx_data) - goto drop; - - rx_data->desc = desc; - rx_data->skb = skb; - list_add_tail(&rx_data->list, &priv->rx_list); - tasklet_schedule(&priv->rx_tasklet); - - return; - -drop: - dev_kfree_skb_irq(skb); -update_stats: - stats->rx_errors++; - stats->rx_dropped++; -out: - kfree(desc); -} -EXPORT_SYMBOL(__orinoco_ev_rx); - -static void orinoco_rx(struct net_device *dev, - struct hermes_rx_descriptor *desc, - struct sk_buff *skb) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - u16 status, fc; - int length; - struct ethhdr *hdr; - - status = le16_to_cpu(desc->status); - length = le16_to_cpu(desc->data_len); - fc = le16_to_cpu(desc->frame_ctl); - - /* Calculate and check MIC */ - if (status & HERMES_RXSTAT_MIC) { - struct orinoco_tkip_key *key; - int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> - HERMES_MIC_KEY_ID_SHIFT); - u8 mic[MICHAEL_MIC_LEN]; - u8 *rxmic; - u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? - desc->addr3 : desc->addr2; - - /* Extract Michael MIC from payload */ - rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; - - skb_trim(skb, skb->len - MICHAEL_MIC_LEN); - length -= MICHAEL_MIC_LEN; - - key = (struct orinoco_tkip_key *) priv->keys[key_id].key; - - if (!key) { - printk(KERN_WARNING "%s: Received encrypted frame from " - "%pM using key %i, but key is not installed\n", - dev->name, src, key_id); - goto drop; - } - - orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, - 0, /* priority or QoS? */ - skb->data, skb->len, &mic[0]); - - if (memcmp(mic, rxmic, - MICHAEL_MIC_LEN)) { - union iwreq_data wrqu; - struct iw_michaelmicfailure wxmic; - - printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %pM, " - "using key %i\n", - dev->name, src, key_id); - - /* TODO: update stats */ - - /* Notify userspace */ - memset(&wxmic, 0, sizeof(wxmic)); - wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; - wxmic.flags |= (desc->addr1[0] & 1) ? - IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; - wxmic.src_addr.sa_family = ARPHRD_ETHER; - memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); - - (void) orinoco_hw_get_tkip_iv(priv, key_id, - &wxmic.tsc[0]); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(wxmic); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, - (char *) &wxmic); - - goto drop; - } - } - - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if (length >= ENCAPS_OVERHEAD && - (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(skb->data))) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ - hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); - } else { - /* 802.3 frame - prepend 802.3 header as is */ - hdr = skb_push(skb, ETH_HLEN); - hdr->h_proto = htons(length); - } - memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); - if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc->addr3, ETH_ALEN); - else - memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - if (fc & IEEE80211_FCTL_TODS) - skb->pkt_type = PACKET_OTHERHOST; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, desc); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - dev_kfree_skb(skb); - stats->rx_errors++; - stats->rx_dropped++; -} - -static void orinoco_rx_isr_tasklet(struct tasklet_struct *t) -{ - struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet); - struct net_device *dev = priv->ndev; - struct orinoco_rx_data *rx_data, *temp; - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - unsigned long flags; - - /* orinoco_rx requires the driver lock, and we also need to - * protect priv->rx_list, so just hold the lock over the - * lot. - * - * If orinoco_lock fails, we've unplugged the card. In this - * case just abort. */ - if (orinoco_lock(priv, &flags) != 0) - return; - - /* extract desc and skb from queue */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - desc = rx_data->desc; - skb = rx_data->skb; - list_del(&rx_data->list); - kfree(rx_data); - - orinoco_rx(dev, desc, skb); - - kfree(desc); - } - - orinoco_unlock(priv, &flags); -} - -/********************************************************************/ -/* Rx path (info frames) */ -/********************************************************************/ - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char *s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_DEBUG "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} - -/* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, join_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - struct join_req { - u8 bssid[ETH_ALEN]; - __le16 channel; - } __packed req; - const int atom_len = offsetof(struct prism2_scan_apinfo, atim); - struct prism2_scan_apinfo *atom = NULL; - int offset = 4; - int found = 0; - u8 *buf; - u16 len; - - /* Allocate buffer for scan results */ - buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL); - if (!buf) - return; - - if (orinoco_lock(priv, &flags) != 0) - goto fail_lock; - - /* Sanity checks in case user changed something in the meantime */ - if (!priv->bssid_fixed) - goto out; - - if (strlen(priv->desired_essid) == 0) - goto out; - - /* Read scan results from the firmware */ - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_SCANRESULTSTABLE, - MAX_SCAN_LEN, &len, buf); - if (err) { - printk(KERN_ERR "%s: Cannot read scan results\n", - dev->name); - goto out; - } - - len = HERMES_RECLEN_TO_BYTES(len); - - /* Go through the scan results looking for the channel of the AP - * we were requested to join */ - for (; offset + atom_len <= len; offset += atom_len) { - atom = (struct prism2_scan_apinfo *) (buf + offset); - if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { - found = 1; - break; - } - } - - if (!found) { - DEBUG(1, "%s: Requested AP not found in scan results\n", - dev->name); - goto out; - } - - memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); - req.channel = atom->channel; /* both are little-endian */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, - &req); - if (err) - printk(KERN_ERR "%s: Error issuing join request\n", dev->name); - - out: - orinoco_unlock(priv, &flags); - - fail_lock: - kfree(buf); -} - -/* Send new BSSID to userspace */ -static void orinoco_send_bssid_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, wrqu.ap_addr.sa_data); - if (err != 0) - return; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); - } -} - -static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_CURRENT_ASSOC_RESP_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); - } -} - -static void orinoco_send_wevents(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; - - orinoco_send_assocreqie_wevent(priv); - orinoco_send_assocrespie_wevent(priv); - orinoco_send_bssid_wevent(priv); - - orinoco_unlock(priv, &flags); -} - -static void qbuf_scan(struct orinoco_private *priv, void *buf, - int len, int type) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->buf = buf; - sd->len = len; - sd->type = type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void qabort_scan(struct orinoco_private *priv) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->len = -1; /* Abort */ - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void orinoco_process_scan_results(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, process_scan); - struct orinoco_scan_data *sd, *temp; - unsigned long flags; - void *buf; - int len; - int type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { - - buf = sd->buf; - len = sd->len; - type = sd->type; - - list_del(&sd->list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - kfree(sd); - - if (len > 0) { - if (type == HERMES_INQ_CHANNELINFO) - orinoco_add_extscan_result(priv, buf, len); - else - orinoco_add_hostscan_results(priv, buf, len); - - kfree(buf); - } else { - /* Either abort or complete the scan */ - orinoco_scan_done(priv, (len < 0)); - } - - spin_lock_irqsave(&priv->scan_lock, flags); - } - spin_unlock_irqrestore(&priv->scan_lock, flags); -} - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 infofid; - struct { - __le16 len; - __le16 type; - } __packed info; - int len, type; - int err; - - /* This is an answer to an INQUIRE command that we did earlier, - * or an information "event" generated by the card - * The controller return to us a pseudo frame containing - * the information in question - Jean II */ - infofid = hermes_read_regn(hw, INFOFID); - - /* Read the info frame header - don't try too hard */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info), - infofid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading info frame. " - "Frame dropped.\n", dev->name, err); - return; - } - - len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); - type = le16_to_cpu(info.type); - - switch (type) { - case HERMES_INQ_TALLIES: { - struct hermes_tallies_frame tallies; - struct iw_statistics *wstats = &priv->wstats; - - if (len > sizeof(tallies)) { - printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", - dev->name, len); - len = sizeof(tallies); - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len, - infofid, sizeof(info)); - if (err) - break; - - /* Increment our various counters */ - /* wstats->discard.nwid - no wrong BSSID stuff */ - wstats->discard.code += - le16_to_cpu(tallies.RxWEPUndecryptable); - if (len == sizeof(tallies)) - wstats->discard.code += - le16_to_cpu(tallies.RxDiscards_WEPICVError) + - le16_to_cpu(tallies.RxDiscards_WEPExcluded); - wstats->discard.misc += - le16_to_cpu(tallies.TxDiscardsWrongSA); - wstats->discard.fragment += - le16_to_cpu(tallies.RxMsgInBadMsgFragments); - wstats->discard.retries += - le16_to_cpu(tallies.TxRetryLimitExceeded); - /* wstats->miss.beacon - no match */ - } - break; - case HERMES_INQ_LINKSTATUS: { - struct hermes_linkstatus linkstatus; - u16 newstatus; - int connected; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - break; - - if (len != sizeof(linkstatus)) { - printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", - dev->name, len); - break; - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len, - infofid, sizeof(info)); - if (err) - break; - newstatus = le16_to_cpu(linkstatus.linkstatus); - - /* Symbol firmware uses "out of range" to signal that - * the hostscan frame can be requested. */ - if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && - priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_request) { - hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); - break; - } - - connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); - - if (connected) - netif_carrier_on(dev); - else if (!ignore_disconnect) - netif_carrier_off(dev); - - if (newstatus != priv->last_linkstatus) { - priv->last_linkstatus = newstatus; - print_linkstatus(dev, newstatus); - /* The info frame contains only one word which is the - * status (see hermes.h). The status is pretty boring - * in itself, that's why we export the new BSSID... - * Jean II */ - schedule_work(&priv->wevent_work); - } - } - break; - case HERMES_INQ_SCAN: - if (!priv->scan_request && priv->bssid_fixed && - priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - schedule_work(&priv->join_work); - break; - } - fallthrough; - case HERMES_INQ_HOSTSCAN: - case HERMES_INQ_HOSTSCAN_SYMBOL: { - /* Result of a scanning. Contains information about - * cells in the vicinity - Jean II */ - unsigned char *buf; - - /* Sanity check */ - if (len > 4096) { - printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", - dev->name, len); - qabort_scan(priv); - break; - } - - /* Allocate buffer for results */ - buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) { - /* No memory, so can't printk()... */ - qabort_scan(priv); - break; - } - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len, - infofid, sizeof(info)); - if (err) { - kfree(buf); - qabort_scan(priv); - break; - } - -#ifdef ORINOCO_DEBUG - { - int i; - printk(KERN_DEBUG "Scan result [%02X", buf[0]); - for (i = 1; i < (len * 2); i++) - printk(":%02X", buf[i]); - printk("]\n"); - } -#endif /* ORINOCO_DEBUG */ - - qbuf_scan(priv, buf, len, type); - } - break; - case HERMES_INQ_CHANNELINFO: - { - struct agere_ext_scan_info *bss; - - if (!priv->scan_request) { - printk(KERN_DEBUG "%s: Got chaninfo without scan, " - "len=%d\n", dev->name, len); - break; - } - - /* An empty result indicates that the scan is complete */ - if (len == 0) { - qbuf_scan(priv, NULL, len, type); - break; - } - - /* Sanity check */ - else if (len < (offsetof(struct agere_ext_scan_info, - data) + 2)) { - /* Drop this result now so we don't have to - * keep checking later */ - printk(KERN_WARNING - "%s: Ext scan results too short (%d bytes)\n", - dev->name, len); - break; - } - - bss = kmalloc(len, GFP_ATOMIC); - if (bss == NULL) - break; - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len, - infofid, sizeof(info)); - if (err) - kfree(bss); - else - qbuf_scan(priv, bss, len, type); - - break; - } - case HERMES_INQ_SEC_STAT_AGERE: - /* Security status (Agere specific) */ - /* Ignore this frame for now */ - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - break; - fallthrough; - default: - printk(KERN_DEBUG "%s: Unknown information frame received: " - "type 0x%04x, length %d\n", dev->name, type, len); - /* We don't actually do anything about it */ - break; - } -} -EXPORT_SYMBOL(__orinoco_ev_info); - -static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw) -{ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); -} - -/********************************************************************/ -/* Internal hardware control routines */ -/********************************************************************/ - -static int __orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_carrier_off(dev); /* just to make sure */ - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_ERR "%s: Error %d configuring card\n", - dev->name, err); - return err; - } - - /* Fire things up again */ - hermes_set_irqmask(hw, ORINOCO_INTEN); - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d enabling MAC port\n", - dev->name, err); - return err; - } - - netif_start_queue(dev); - - return 0; -} - -static int __orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_stop_queue(dev); - - if (!priv->hw_unavailable) { - if (!priv->broken_disableport) { - err = hermes_disable_port(hw, 0); - if (err) { - /* Some firmwares (e.g. Intersil 1.3.x) seem - * to have problems disabling the port, oh - * well, too bad. */ - printk(KERN_WARNING "%s: Error %d disabling MAC port\n", - dev->name, err); - priv->broken_disableport = 1; - } - } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - } - - orinoco_scan_done(priv, true); - - /* firmware will have to reassociate */ - netif_carrier_off(dev); - priv->last_linkstatus = 0xffff; - - return 0; -} - -static int orinoco_reinit_firmware(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->init(hw); - if (priv->do_fw_download && !err) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - if (!err) - err = orinoco_hw_allocate_fid(priv); - - return err; -} - -static int -__orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (netdev_mc_count(dev) > MAX_MULTICAST(priv))) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = netdev_mc_count(dev); - } - - err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc); - - return err; -} - -/* This must be called from user context, without locks held - use - * schedule_work() */ -void orinoco_reset(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, reset_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - /* When the hardware becomes available again, whatever - * detects that is responsible for re-initializing - * it. So no need for anything further */ - return; - - netif_stop_queue(dev); - - /* Shut off interrupts. Depending on what state the hardware - * is in, this might not work, but we'll try anyway */ - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - priv->hw_unavailable++; - priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - netif_carrier_off(dev); - - orinoco_unlock(priv, &flags); - - /* Scanning support: Notify scan cancellation */ - orinoco_scan_done(priv, true); - - if (priv->hard_reset) { - err = (*priv->hard_reset)(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d " - "performing hard reset\n", dev->name, err); - goto disable; - } - } - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", - dev->name, err); - goto disable; - } - - /* This has to be called from user context */ - orinoco_lock_irq(priv); - - priv->hw_unavailable--; - - /* priv->open or priv->hw_unavailable might have changed while - * we dropped the lock */ - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - netif_trans_update(dev); - } - - orinoco_unlock_irq(priv); - - return; - disable: - hermes_set_irqmask(hw, 0); - netif_device_detach(dev); - printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); -} - -static int __orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - int err = 0; - - /* If we've called commit, we are reconfiguring or bringing the - * interface up. Maintaining countermeasures across this would - * be confusing, so note that we've disabled them. The port will - * be enabled later in orinoco_commit or __orinoco_up. */ - priv->tkip_cm_active = 0; - - err = orinoco_hw_program_rids(priv); - - /* FIXME: what about netif_tx_lock */ - (void) __orinoco_set_multicast_list(dev); - - return err; -} - -/* Ensures configuration changes are applied. May result in a reset. - * The caller should hold priv->lock - */ -int orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - if (priv->broken_disableport) { - schedule_work(&priv->reset_work); - return 0; - } - - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } - return err; -} - -/********************************************************************/ -/* Interrupt handler */ -/********************************************************************/ - -static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -irqreturn_t orinoco_interrupt(int irq, void *dev_id) -{ - struct orinoco_private *priv = dev_id; - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int count = MAX_IRQLOOPS_PER_IRQ; - u16 evstat, events; - /* These are used to detect a runaway interrupt situation. - * - * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, - * we panic and shut down the hardware - */ - /* jiffies value the last time we were called */ - static int last_irq_jiffy; /* = 0 */ - static int loops_this_jiffy; /* = 0 */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable - we don't know if the irq was - * for us or not */ - return IRQ_HANDLED; - } - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - if (!events) { - orinoco_unlock(priv, &flags); - return IRQ_NONE; - } - - if (jiffies != last_irq_jiffy) - loops_this_jiffy = 0; - last_irq_jiffy = jiffies; - - while (events && count--) { - if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_WARNING "%s: IRQ handler is looping too " - "much! Resetting.\n", dev->name); - /* Disable interrupts for now */ - hermes_set_irqmask(hw, 0); - schedule_work(&priv->reset_work); - break; - } - - /* Check the card hasn't been removed */ - if (!hermes_present(hw)) { - DEBUG(0, "orinoco_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __orinoco_ev_tick(dev, hw); - if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(dev, hw); - if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(dev, hw); - if (events & HERMES_EV_INFO) - __orinoco_ev_info(dev, hw); - if (events & HERMES_EV_RX) - __orinoco_ev_rx(dev, hw); - if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(dev, hw); - if (events & HERMES_EV_TX) - __orinoco_ev_tx(dev, hw); - if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(dev, hw); - - hermes_write_regn(hw, EVACK, evstat); - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - } - - orinoco_unlock(priv, &flags); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(orinoco_interrupt); - -/********************************************************************/ -/* Power management */ -/********************************************************************/ -#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) -static int orinoco_pm_notifier(struct notifier_block *notifier, - unsigned long pm_event, - void *unused) -{ - struct orinoco_private *priv = container_of(notifier, - struct orinoco_private, - pm_notifier); - - /* All we need to do is cache the firmware before suspend, and - * release it when we come out. - * - * Only need to do this if we're downloading firmware. */ - if (!priv->do_fw_download) - return NOTIFY_DONE; - - switch (pm_event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - orinoco_cache_fw(priv, 0); - break; - - case PM_POST_RESTORE: - /* Restore from hibernation failed. We need to clean - * up in exactly the same way, so fall through. */ - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - orinoco_uncache_fw(priv); - break; - - case PM_RESTORE_PREPARE: - default: - break; - } - - return NOTIFY_DONE; -} - -static void orinoco_register_pm_notifier(struct orinoco_private *priv) -{ - priv->pm_notifier.notifier_call = orinoco_pm_notifier; - register_pm_notifier(&priv->pm_notifier); -} - -static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) -{ - unregister_pm_notifier(&priv->pm_notifier); -} -#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ -#define orinoco_register_pm_notifier(priv) do { } while (0) -#define orinoco_unregister_pm_notifier(priv) do { } while (0) -#endif - -/********************************************************************/ -/* Initialization */ -/********************************************************************/ - -int orinoco_init(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct wiphy *wiphy = priv_to_wiphy(priv); - struct hermes *hw = &priv->hw; - int err = 0; - - /* No need to lock, the hw_unavailable flag is already set in - * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; - - /* Initialize the firmware */ - err = hw->ops->init(hw); - if (err != 0) { - dev_err(dev, "Failed to initialize firmware (err = %d)\n", - err); - goto out; - } - - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - - if (priv->do_fw_download) { -#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT - orinoco_cache_fw(priv, 0); -#endif - - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - - /* Check firmware version again */ - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - } - - if (priv->has_port3) - dev_info(dev, "Ad-hoc demo mode supported\n"); - if (priv->has_ibss) - dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n"); - if (priv->has_wep) - dev_info(dev, "WEP supported, %s-bit key\n", - priv->has_big_wep ? "104" : "40"); - if (priv->has_wpa) { - dev_info(dev, "WPA-PSK supported\n"); - if (orinoco_mic_init(priv)) { - dev_err(dev, "Failed to setup MIC crypto algorithm. " - "Disabling WPA support\n"); - priv->has_wpa = 0; - } - } - - err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); - if (err) - goto out; - - err = orinoco_hw_allocate_fid(priv); - if (err) { - dev_err(dev, "Failed to allocate NIC buffer!\n"); - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = NL80211_IFTYPE_STATION; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss); - set_port_type(priv); - priv->channel = 0; /* use firmware default */ - - priv->promiscuous = 0; - priv->encode_alg = ORINOCO_ALG_NONE; - priv->tx_key = 0; - priv->wpa_enabled = 0; - priv->tkip_cm_active = 0; - priv->key_mgmt = 0; - priv->wpa_ie_len = 0; - priv->wpa_ie = NULL; - - if (orinoco_wiphy_register(wiphy)) { - err = -ENODEV; - goto out; - } - - /* Make the hardware available, as long as it hasn't been - * removed elsewhere (e.g. by PCMCIA hot unplug) */ - orinoco_lock_irq(priv); - priv->hw_unavailable--; - orinoco_unlock_irq(priv); - - dev_dbg(dev, "Ready\n"); - - out: - return err; -} -EXPORT_SYMBOL(orinoco_init); - -static const struct net_device_ops orinoco_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = orinoco_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -/* Allocate private data. - * - * This driver has a number of structures associated with it - * netdev - Net device structure for each network interface - * wiphy - structure associated with wireless phy - * wireless_dev (wdev) - structure for each wireless interface - * hw - structure for hermes chip info - * card - card specific structure for use by the card driver - * (airport, orinoco_cs) - * priv - orinoco private data - * device - generic linux device structure - * - * +---------+ +---------+ - * | wiphy | | netdev | - * | +-------+ | +-------+ - * | | priv | | | wdev | - * | | +-----+ +-+-------+ - * | | | hw | - * | +-+-----+ - * | | card | - * +-+-------+ - * - * priv has a link to netdev and device - * wdev has a link to wiphy - */ -struct orinoco_private -*alloc_orinocodev(int sizeof_card, - struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)) -{ - struct orinoco_private *priv; - struct wiphy *wiphy; - - /* allocate wiphy - * NOTE: We only support a single virtual interface - * but this may change when monitor mode is added - */ - wiphy = wiphy_new(&orinoco_cfg_ops, - sizeof(struct orinoco_private) + sizeof_card); - if (!wiphy) - return NULL; - - priv = wiphy_priv(wiphy); - priv->dev = device; - - if (sizeof_card) - priv->card = (void *)((unsigned long)priv - + sizeof(struct orinoco_private)); - else - priv->card = NULL; - - orinoco_wiphy_init(wiphy); - -#ifdef WIRELESS_SPY - priv->wireless_data.spy_data = &priv->spy_data; -#endif - - /* Set up default callbacks */ - priv->hard_reset = hard_reset; - priv->stop_fw = stop_fw; - - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, orinoco_reset); - INIT_WORK(&priv->join_work, orinoco_join_ap); - INIT_WORK(&priv->wevent_work, orinoco_send_wevents); - - INIT_LIST_HEAD(&priv->rx_list); - tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet); - - spin_lock_init(&priv->scan_lock); - INIT_LIST_HEAD(&priv->scan_list); - INIT_WORK(&priv->process_scan, orinoco_process_scan_results); - - priv->last_linkstatus = 0xffff; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -#endif - - /* Register PM notifiers */ - orinoco_register_pm_notifier(priv); - - return priv; -} -EXPORT_SYMBOL(alloc_orinocodev); - -/* We can only support a single interface. We provide a separate - * function to set it up to distinguish between hardware - * initialisation and interface setup. - * - * The base_addr and irq parameters are passed on to netdev for use - * with SIOCGIFMAP. - */ -int orinoco_if_add(struct orinoco_private *priv, - unsigned long base_addr, - unsigned int irq, - const struct net_device_ops *ops) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct wireless_dev *wdev; - struct net_device *dev; - int ret; - - dev = alloc_etherdev(sizeof(struct wireless_dev)); - - if (!dev) - return -ENOMEM; - - /* Initialise wireless_dev */ - wdev = netdev_priv(dev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - - /* Setup / override net_device fields */ - dev->ieee80211_ptr = wdev; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->wireless_handlers = &orinoco_handler_def; -#ifdef WIRELESS_SPY - dev->wireless_data = &priv->wireless_data; -#endif - /* Default to standard ops if not set */ - if (ops) - dev->netdev_ops = ops; - else - dev->netdev_ops = &orinoco_netdev_ops; - - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->needed_headroom = ENCAPS_OVERHEAD; - - netif_carrier_off(dev); - - eth_hw_addr_set(dev, wiphy->perm_addr); - - dev->base_addr = base_addr; - dev->irq = irq; - - dev->min_mtu = ORINOCO_MIN_MTU; - dev->max_mtu = ORINOCO_MAX_MTU; - - SET_NETDEV_DEV(dev, priv->dev); - ret = register_netdev(dev); - if (ret) - goto fail; - - priv->ndev = dev; - - /* Report what we've done */ - dev_dbg(priv->dev, "Registered interface %s.\n", dev->name); - - return 0; - - fail: - free_netdev(dev); - return ret; -} -EXPORT_SYMBOL(orinoco_if_add); - -void orinoco_if_del(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - - unregister_netdev(dev); - free_netdev(dev); -} -EXPORT_SYMBOL(orinoco_if_del); - -void free_orinocodev(struct orinoco_private *priv) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct orinoco_rx_data *rx_data, *temp; - struct orinoco_scan_data *sd, *sdtemp; - - /* If the tasklet is scheduled when we call tasklet_kill it - * will run one final time. However the tasklet will only - * drain priv->rx_list if the hw is still available. */ - tasklet_kill(&priv->rx_tasklet); - - /* Explicitly drain priv->rx_list */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - list_del(&rx_data->list); - - dev_kfree_skb(rx_data->skb); - kfree(rx_data->desc); - kfree(rx_data); - } - - cancel_work_sync(&priv->process_scan); - /* Explicitly drain priv->scan_list */ - list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { - list_del(&sd->list); - - if (sd->len > 0) - kfree(sd->buf); - kfree(sd); - } - - orinoco_unregister_pm_notifier(priv); - orinoco_uncache_fw(priv); - - priv->wpa_ie_len = 0; - kfree(priv->wpa_ie); - orinoco_mic_free(priv); - wiphy_free(wiphy); -} -EXPORT_SYMBOL(free_orinocodev); - -int orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - goto exit; - } - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - -exit: - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return 0; -} -EXPORT_SYMBOL(orinoco_up); - -void orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); -} -EXPORT_SYMBOL(orinoco_down); - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson , " - "Pavel Roskin , et al)"; - -static int __init init_orinoco(void) -{ - printk(KERN_DEBUG "%s\n", version); - return 0; -} - -static void __exit exit_orinoco(void) -{ -} - -module_init(init_orinoco); -module_exit(exit_orinoco); diff --git a/drivers/net/wireless/intersil/orinoco/main.h b/drivers/net/wireless/intersil/orinoco/main.h deleted file mode 100644 index 5a8fec26136e..000000000000 --- a/drivers/net/wireless/intersil/orinoco/main.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Exports from main to helper modules - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MAIN_H_ -#define _ORINOCO_MAIN_H_ - -#include -#include "orinoco.h" - -/********************************************************************/ -/* Compile time configuration and compatibility stuff */ -/********************************************************************/ - -/* We do this this way to avoid ifdefs in the actual code */ -#ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_data.spy_number) -#else -#define SPY_NUMBER(priv) 0 -#endif /* WIRELESS_SPY */ - -/********************************************************************/ - -/* Export module parameter */ -extern int force_monitor; - -/* Forward declarations */ -struct net_device; -struct work_struct; - -void set_port_type(struct orinoco_private *priv); -int orinoco_commit(struct orinoco_private *priv); -void orinoco_reset(struct work_struct *work); - -/* Information element helpers - find a home for these... */ -#define WPA_OUI_TYPE "\x00\x50\xF2\x01" -#define WPA_SELECTOR_LEN 4 -static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) -{ - u8 *p = data; - while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) && - (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) - return p; - p += p[1] + 2; - } - return NULL; -} - -#endif /* _ORINOCO_MAIN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c deleted file mode 100644 index a324bc4b7938..000000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "mic.h" - -/********************************************************************/ -/* Michael MIC crypto setup */ -/********************************************************************/ -int orinoco_mic_init(struct orinoco_private *priv) -{ - priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->tx_tfm_mic = NULL; - return -ENOMEM; - } - - priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->rx_tfm_mic = NULL; - return -ENOMEM; - } - - return 0; -} - -void orinoco_mic_free(struct orinoco_private *priv) -{ - if (priv->tx_tfm_mic) - crypto_free_shash(priv->tx_tfm_mic); - if (priv->rx_tfm_mic) - crypto_free_shash(priv->rx_tfm_mic); -} - -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) -{ - SHASH_DESC_ON_STACK(desc, tfm_michael); - u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ - int err; - - if (tfm_michael == NULL) { - printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__); - return -1; - } - - /* Copy header into buffer. We need the padding on the end zeroed */ - memcpy(&hdr[0], da, ETH_ALEN); - memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); - hdr[ETH_ALEN * 2] = priority; - hdr[ETH_ALEN * 2 + 1] = 0; - hdr[ETH_ALEN * 2 + 2] = 0; - hdr[ETH_ALEN * 2 + 3] = 0; - - desc->tfm = tfm_michael; - - err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN); - if (err) - return err; - - err = crypto_shash_init(desc); - if (err) - return err; - - err = crypto_shash_update(desc, hdr, sizeof(hdr)); - if (err) - return err; - - err = crypto_shash_update(desc, data, data_len); - if (err) - return err; - - err = crypto_shash_final(desc, mic); - shash_desc_zero(desc); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h deleted file mode 100644 index e8724e889219..000000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MIC_H_ -#define _ORINOCO_MIC_H_ - -#include -#include - -#define MICHAEL_MIC_LEN 8 - -/* Forward declarations */ -struct orinoco_private; -struct crypto_ahash; - -int orinoco_mic_init(struct orinoco_private *priv); -void orinoco_mic_free(struct orinoco_private *priv); -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic); - -#endif /* ORINOCO_MIC_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h deleted file mode 100644 index cdd026af100b..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco.h +++ /dev/null @@ -1,251 +0,0 @@ -/* orinoco.h - * - * Common definitions to all pieces of the various orinoco - * drivers - */ - -#ifndef _ORINOCO_H -#define _ORINOCO_H - -#define DRIVER_VERSION "0.15" - -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -/* To enable debug messages */ -/*#define ORINOCO_DEBUG 3*/ - -#define WIRELESS_SPY /* enable iwspy support */ - -#define MAX_SCAN_LEN 4096 - -#define ORINOCO_SEQ_LEN 8 -#define ORINOCO_MAX_KEY_SIZE 14 -#define ORINOCO_MAX_KEYS 4 - -struct orinoco_key { - __le16 len; /* always stored as little-endian */ - char data[ORINOCO_MAX_KEY_SIZE]; -} __packed; - -#define TKIP_KEYLEN 16 -#define MIC_KEYLEN 8 - -struct orinoco_tkip_key { - u8 tkip[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; -}; - -enum orinoco_alg { - ORINOCO_ALG_NONE, - ORINOCO_ALG_WEP, - ORINOCO_ALG_TKIP -}; - -enum fwtype { - FIRMWARE_TYPE_AGERE, - FIRMWARE_TYPE_INTERSIL, - FIRMWARE_TYPE_SYMBOL -}; - -struct firmware; - -struct orinoco_private { - void *card; /* Pointer to card dependent structure */ - struct device *dev; - int (*hard_reset)(struct orinoco_private *); - int (*stop_fw)(struct orinoco_private *, int); - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[14]; - u32 cipher_suites[3]; - - /* Synchronisation stuff */ - spinlock_t lock; - int hw_unavailable; - struct work_struct reset_work; - - /* Interrupt tasklets */ - struct tasklet_struct rx_tasklet; - struct list_head rx_list; - - /* driver state */ - int open; - u16 last_linkstatus; - struct work_struct join_work; - struct work_struct wevent_work; - - /* Net device stuff */ - struct net_device *ndev; - struct iw_statistics wstats; - - /* Hardware control variables */ - struct hermes hw; - u16 txfid; - - /* Capabilities of the hardware/firmware */ - enum fwtype firmware_type; - int ibss_port; - int nicbuf_size; - u16 channel_mask; - - /* Boolean capabilities */ - unsigned int has_ibss:1; - unsigned int has_port3:1; - unsigned int has_wep:1; - unsigned int has_big_wep:1; - unsigned int has_mwo:1; - unsigned int has_pm:1; - unsigned int has_preamble:1; - unsigned int has_sensitivity:1; - unsigned int has_hostscan:1; - unsigned int has_alt_txcntl:1; - unsigned int has_ext_scan:1; - unsigned int has_wpa:1; - unsigned int do_fw_download:1; - unsigned int broken_disableport:1; - unsigned int broken_monitor:1; - unsigned int prefer_port3:1; - - /* Configuration paramaters */ - enum nl80211_iftype iw_mode; - enum orinoco_alg encode_alg; - u16 wep_restrict, tx_key; - struct key_params keys[ORINOCO_MAX_KEYS]; - - int bitratemode; - char nick[IW_ESSID_MAX_SIZE + 1]; - char desired_essid[IW_ESSID_MAX_SIZE + 1]; - char desired_bssid[ETH_ALEN]; - int bssid_fixed; - u16 frag_thresh, mwo_robust; - u16 channel; - u16 ap_density, rts_thresh; - u16 pm_on, pm_mcast, pm_period, pm_timeout; - u16 preamble; - u16 short_retry_limit, long_retry_limit; - u16 retry_lifetime; -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; -#endif - - /* Configuration dependent variables */ - int port_type, createibss; - int promiscuous, mc_count; - - /* Scanning support */ - struct cfg80211_scan_request *scan_request; - struct work_struct process_scan; - struct list_head scan_list; - spinlock_t scan_lock; /* protects the scan list */ - - /* WPA support */ - u8 *wpa_ie; - int wpa_ie_len; - - struct crypto_shash *rx_tfm_mic; - struct crypto_shash *tx_tfm_mic; - - unsigned int wpa_enabled:1; - unsigned int tkip_cm_active:1; - unsigned int key_mgmt:3; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - /* Cached in memory firmware to use during ->resume. */ - const struct firmware *cached_pri_fw; - const struct firmware *cached_fw; -#endif - - struct notifier_block pm_notifier; -}; - -#ifdef ORINOCO_DEBUG -extern int orinoco_debug; -#define DEBUG(n, args...) do { \ - if (orinoco_debug > (n)) \ - printk(KERN_DEBUG args); \ -} while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#endif /* ORINOCO_DEBUG */ - -/********************************************************************/ -/* Exported prototypes */ -/********************************************************************/ - -struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)); -void free_orinocodev(struct orinoco_private *priv); -int orinoco_init(struct orinoco_private *priv); -int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr, - unsigned int irq, const struct net_device_ops *ops); -void orinoco_if_del(struct orinoco_private *priv); -int orinoco_up(struct orinoco_private *priv); -void orinoco_down(struct orinoco_private *priv); -irqreturn_t orinoco_interrupt(int irq, void *dev_id); - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw); -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw); - -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic); - -/* Common ndo functions exported for reuse by orinoco_usb */ -int orinoco_open(struct net_device *dev); -int orinoco_stop(struct net_device *dev); -void orinoco_set_multicast_list(struct net_device *dev); -int orinoco_change_mtu(struct net_device *dev, int new_mtu); -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue); - -/********************************************************************/ -/* Locking and synchronization functions */ -/********************************************************************/ - -static inline int orinoco_lock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->lock_irqsave(&priv->lock, flags); - if (priv->hw_unavailable) { - DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", - priv->ndev); - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); - return -EBUSY; - } - return 0; -} - -static inline void orinoco_unlock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); -} - -static inline void orinoco_lock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->lock_irq(&priv->lock); -} - -static inline void orinoco_unlock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->unlock_irq(&priv->lock); -} - -/*** Navigate from net_device to orinoco_private ***/ -static inline struct orinoco_private *ndev_priv(struct net_device *dev) -{ - struct wireless_dev *wdev = netdev_priv(dev); - return wdev_priv(wdev); -} -#endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c deleted file mode 100644 index 03bfd2482656..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c +++ /dev/null @@ -1,350 +0,0 @@ -/* orinoco_cs.c (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright notice & release notes in file main.c - */ - -#define DRIVER_NAME "orinoco_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("David Gibson "); -MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco," - " Prism II based and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; - - /* Used to handle hard reset */ - /* yuck, we need this hack to work around the insanity of the - * PCMCIA layer */ - unsigned long hard_reset_in_progress; -}; - - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int orinoco_cs_config(struct pcmcia_device *link); -static void orinoco_cs_release(struct pcmcia_device *link); -static void orinoco_cs_detach(struct pcmcia_device *p_dev); - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -orinoco_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - int err; - - /* We need atomic ops here, because we're not holding the lock */ - set_bit(0, &card->hard_reset_in_progress); - - err = pcmcia_reset_card(link->socket); - if (err) - return err; - - msleep(100); - clear_bit(0, &card->hard_reset_in_progress); - - return 0; -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -orinoco_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - orinoco_cs_hard_reset, NULL); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = orinoco_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void orinoco_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - orinoco_cs_release(link); - - wiphy_unregister(priv_to_wiphy(priv)); - free_orinocodev(priv); -} /* orinoco_cs_detach */ - -static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -orinoco_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - orinoco_cs_release(link); - return -ENODEV; -} /* orinoco_cs_config */ - -static void -orinoco_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* orinoco_cs_release */ - -static int orinoco_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - - /* This is probably racy, but I can't think of - a better way, short of rewriting the PCMCIA - layer to not suck :-( */ - if (!test_bit(0, &card->hard_reset_in_progress)) - orinoco_down(priv); - - return 0; -} - -static int orinoco_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - int err = 0; - - if (!test_bit(0, &card->hard_reset_in_progress)) - err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ - PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */ - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ - PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), - PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), - PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), - PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), - PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), - PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), - PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), - PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), - PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), - PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), - PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */ -#ifdef CONFIG_HERMES_PRISM - /* Only entries that certainly identify Prism chipset */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ - PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), - PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), - PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), - PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), - PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), - PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), - PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), - PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), - PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - - /* This may be Agere or Intersil Firmware */ - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), -#endif - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = orinoco_cs_probe, - .remove = orinoco_cs_detach, - .id_table = orinoco_cs_ids, - .suspend = orinoco_cs_suspend, - .resume = orinoco_cs_resume, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c deleted file mode 100644 index 18bd0d9876c2..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c +++ /dev/null @@ -1,314 +0,0 @@ -/* orinoco_nortel.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in - * Nortel emobility, Symbol LA-4113 and Symbol LA-4123. - * - * Copyright (C) 2002 Tobias Hoffmann - * (C) 2003 Christoph Jungegger - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is borrowed from orinoco_pci.c - * Copyright (C) 2001 Jean Tourrilhes - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_nortel" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ - - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_nortel_cor_reset(struct orinoco_private *priv) -{ - struct orinoco_pci_card *card = priv->card; - - /* Assert the reset until the card notices */ - iowrite16(8, card->bridge_io + 2); - ioread16(card->attr_io + COR_OFFSET); - iowrite16(0x80, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Give time for the card to recover from this hard effort */ - iowrite16(0, card->attr_io + COR_OFFSET); - iowrite16(0, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Set COR as usual */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite16(0x228, card->bridge_io + 2); - - return 0; -} - -static int orinoco_nortel_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 reg; - - /* Setup bridge */ - if (ioread16(card->bridge_io) & 1) { - printk(KERN_ERR PFX "brg1 answer1 wrong\n"); - return -EBUSY; - } - iowrite16(0x118, card->bridge_io + 2); - iowrite16(0x108, card->bridge_io + 2); - mdelay(30); - iowrite16(0x8, card->bridge_io + 2); - for (i = 0; i < 30; i++) { - mdelay(30); - if (ioread16(card->bridge_io) & 0x10) - break; - } - if (i == 30) { - printk(KERN_ERR PFX "brg1 timed out\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET) & 1) { - printk(KERN_ERR PFX "brg2 answer1 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) { - printk(KERN_ERR PFX "brg2 answer2 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) { - printk(KERN_ERR PFX "brg2 answer3 wrong\n"); - return -EBUSY; - } - - /* Set the PCMCIA COR register */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - reg = ioread16(card->attr_io + COR_OFFSET); - if (reg != COR_VALUE) { - printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", - reg); - return -EBUSY; - } - - /* Set LEDs */ - iowrite16(1, card->bridge_io + 10); - return 0; -} - -static int orinoco_nortel_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io, *attr_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 0, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 1, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_nortel_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_nortel_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_nortel_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - /* Clear LEDs */ - iowrite16(0, card->bridge_io + 10); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_nortel_id_table[] = { - /* Nortel emobility PCI */ - {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, - /* Symbol LA-4123 PCI */ - {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table); - -static struct pci_driver orinoco_nortel_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_nortel_id_table, - .probe = orinoco_nortel_init_one, - .remove = orinoco_nortel_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Tobias Hoffmann & Christoph Jungegger )"; -MODULE_AUTHOR("Christoph Jungegger "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_nortel_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_nortel_driver); -} - -static void __exit orinoco_nortel_exit(void) -{ - pci_unregister_driver(&orinoco_nortel_driver); -} - -module_init(orinoco_nortel_init); -module_exit(orinoco_nortel_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c deleted file mode 100644 index 7e3a6dd60c15..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c +++ /dev/null @@ -1,257 +0,0 @@ -/* orinoco_pci.c - * - * Driver for Prism 2.5/3 devices that have a direct PCI interface - * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). - * The card contains only one PCI region, which contains all the usual - * hermes registers, as well as the COR register. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes - * And is now maintained by: - * (C) Copyright David Gibson, IBM Corp. 2002-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_pci" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -/* Offset of the COR register of the PCI card */ -#define HERMES_PCI_COR (0x26) - -/* Bitmask to reset the card */ -#define HERMES_PCI_COR_MASK (0x0080) - -/* Magic timeouts for doing the reset. - * Those times are straight from wlan-ng, and it is claimed that they - * are necessary. Alan will kill me. Take your time and grab a coffee. */ -#define HERMES_PCI_COR_ONT (250) /* ms */ -#define HERMES_PCI_COR_OFFT (500) /* ms */ -#define HERMES_PCI_COR_BUSYT (500) /* ms */ - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note : This code is done with irq enabled. This mean that many - * interrupts will occur while we are there. This is why we use the - * jiffies to regulate time instead of a straight mdelay(). Usually we - * need only around 245 iteration of the loop to do 250 ms delay. - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_pci_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - unsigned long timeout; - u16 reg; - - /* Assert the reset until the card notices */ - hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - mdelay(HERMES_PCI_COR_ONT); - - /* Give time for the card to recover from this hard effort */ - hermes_write_regn(hw, PCI_COR, 0x0000); - mdelay(HERMES_PCI_COR_OFFT); - - /* The card is ready when it's no longer busy */ - timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - hermes_io = pci_iomap(pdev, 0, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot remap chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_pci_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_pci_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_pci_id_table[] = { - /* Intersil Prism 3 */ - {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, - /* Intersil Prism 2.5 */ - {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, - /* Samsung MagicLAN SWL-2210P */ - {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); - -static struct pci_driver orinoco_pci_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_pci_id_table, - .probe = orinoco_pci_init_one, - .remove = orinoco_pci_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson &" - " Jean Tourrilhes )"; -MODULE_AUTHOR("Pavel Roskin &" - " David Gibson "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_pci_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_pci_driver); -} - -static void __exit orinoco_pci_exit(void) -{ - pci_unregister_driver(&orinoco_pci_driver); -} - -module_init(orinoco_pci_init); -module_exit(orinoco_pci_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h deleted file mode 100644 index d49d940864b4..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h +++ /dev/null @@ -1,54 +0,0 @@ -/* orinoco_pci.h - * - * Common code for all Orinoco drivers for PCI devices, including - * both native PCI and PCMCIA-to-PCI bridges. - * - * Copyright (C) 2005, Pavel Roskin. - * See main.c for license. - */ - -#ifndef _ORINOCO_PCI_H -#define _ORINOCO_PCI_H - -#include - -/* Driver specific data */ -struct orinoco_pci_card { - void __iomem *bridge_io; - void __iomem *attr_io; -}; - -static int __maybe_unused orinoco_pci_suspend(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_down(priv); - free_irq(pdev->irq, priv); - - return 0; -} - -static int __maybe_unused orinoco_pci_resume(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - int err; - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); - if (err) { - printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", - dev->name); - return -EBUSY; - } - - return orinoco_up(priv); -} - -static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops, - orinoco_pci_suspend, - orinoco_pci_resume); - -#endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c deleted file mode 100644 index 73e6ae124013..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c +++ /dev/null @@ -1,362 +0,0 @@ -/* orinoco_plx.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Here's the general details on how the PLX9052 adapter works: - * - * - Two PCI I/O address spaces, one 0x80 long which contains the - * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA - * slot I/O address space. - * - * - One PCI memory address space, mapped to the PCMCIA attribute space - * (containing the CIS). - * - * Using the later, you can read through the CIS data to make sure the - * card is compatible with the driver. Keep in mind that the PCMCIA - * spec specifies the CIS as the lower 8 bits of each word read from - * the CIS, so to read the bytes of the CIS, read every other byte - * (0,2,4,...). Passing that test, you need to enable the I/O address - * space on the PCMCIA card via the PCMCIA COR register. This is the - * first byte following the CIS. In my case (which may not have any - * relation to what's on the PRISM2 cards), COR was at offset 0x800 - * within the PCI memory space. Write 0x41 to the COR register to - * enable I/O mode and to select level triggered interrupts. To - * confirm you actually succeeded, read the COR register back and make - * sure it actually got set to 0x41, in case you have an unexpected - * card inserted. - * - * Following that, you can treat the second PCI I/O address space (the - * one that's not 0x80 in length) as the PCMCIA I/O space. - * - * Note that in the Eumitcom's source for their drivers, they register - * the interrupt as edge triggered when registering it with the - * Windows kernel. I don't recall how to register edge triggered on - * Linux (if it can be done at all). But in some experimentation, I - * don't see much operational difference between using either - * interrupt mode. Don't mess with the interrupt mode in the COR - * register though, as the PLX9052 wants level triggers with the way - * the serial EEPROM configures it on the WL11000. - * - * There's some other little quirks related to timing that I bumped - * into, but I don't recall right now. Also, there's two variants of - * the WL11000 I've seen, revision A1 and T2. These seem to differ - * slightly in the timings configured in the wait-state generator in - * the PLX9052. There have also been some comments from Eumitcom that - * cards shouldn't be hot swapped, apparently due to risk of cooking - * the PLX9052. I'm unsure why they believe this, as I can't see - * anything in the design that would really cause a problem, except - * for crashing drivers not written to expect it. And having developed - * drivers for the WL11000, I'd say it's quite tricky to write code - * that will successfully deal with a hot unplug. Very odd things - * happen on the I/O side of things. But anyway, be warned. Despite - * that, I've hot-swapped a number of times during debugging and - * driver development for various reasons (stuck WAIT# line after the - * radio card's firmware locks up). - */ - -#define DRIVER_NAME "orinoco_plx" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define PLX_RESET_TIME (500) /* milliseconds */ - -#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ -#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_plx_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_plx_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 csr_reg; - static const u8 cis_magic[] = { - 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 - }; - - printk(KERN_DEBUG PFX "CIS: "); - for (i = 0; i < 16; i++) - printk("%02X:", ioread8(card->attr_io + (i << 1))); - printk("\n"); - - /* Verify whether a supported PC card is present */ - /* FIXME: we probably need to be smarted about this */ - for (i = 0; i < sizeof(cis_magic); i++) { - if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { - printk(KERN_ERR PFX "The CIS value of Prism2 PC " - "card is unexpected\n"); - return -ENODEV; - } - } - - /* bjoern: We need to tell the card to enable interrupts, in - case the serial eprom didn't do this already. See the - PLX9052 data book, p8-1 and 8-24 for reference. */ - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - csr_reg |= PLX_INTCSR_INTEN; - iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - printk(KERN_ERR PFX "Cannot enable interrupts\n"); - return -EIO; - } - } - - return 0; -} - -static int orinoco_plx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *attr_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 2, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 3, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_plx_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_plx_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_plx_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_plx_id_table[] = { - {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ - {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ - {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, - Eumitcom PCI WL11000, - Addtron AWA-100 */ - {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ - {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ - {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ - {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ - {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams */ - {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); - -static struct pci_driver orinoco_plx_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_plx_id_table, - .probe = orinoco_plx_init_one, - .remove = orinoco_plx_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson ," - " Daniel Barlow )"; -MODULE_AUTHOR("Daniel Barlow "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_plx_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_plx_driver); -} - -static void __exit orinoco_plx_exit(void) -{ - pci_unregister_driver(&orinoco_plx_driver); -} - -module_init(orinoco_plx_init); -module_exit(orinoco_plx_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c deleted file mode 100644 index 939d5a1dce97..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c +++ /dev/null @@ -1,237 +0,0 @@ -/* orinoco_tmd.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a TMD7160. - * - * Copyright (C) 2003 Joerg Dorchain - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * The actual driving is done by main.c, this is just resource - * allocation stuff. - * - * This driver is modeled after the orinoco_plx driver. The main - * difference is that the TMD chip has only IO port ranges and doesn't - * provide access to the PCMCIA attribute space. - * - * Pheecom sells cards with the TMD chip as "ASIC version" - */ - -#define DRIVER_NAME "orinoco_tmd" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define TMD_RESET_TIME (500) /* milliseconds */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_tmd_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->bridge_io); - mdelay(1); - - iowrite8(COR_VALUE, card->bridge_io); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - - -static int orinoco_tmd_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_tmd_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_tmd_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_tmd_id_table[] = { - {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table); - -static struct pci_driver orinoco_tmd_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_tmd_id_table, - .probe = orinoco_tmd_init_one, - .remove = orinoco_tmd_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Joerg Dorchain )"; -MODULE_AUTHOR("Joerg Dorchain "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_tmd_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_tmd_driver); -} - -static void __exit orinoco_tmd_exit(void) -{ - pci_unregister_driver(&orinoco_tmd_driver); -} - -module_init(orinoco_tmd_init); -module_exit(orinoco_tmd_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c deleted file mode 100644 index 866e0230df25..000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * USB Orinoco driver - * - * Copyright (c) 2003 Manuel Estrada Sainz - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Queueing code based on linux-wlan-ng 0.2.1-pre5 - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The license is the same as above. - * - * Initialy based on USB Skeleton driver - 0.7 - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * NOTE: The original USB Skeleton driver is GPL, but all that code is - * gone so MPL/GPL applies. - */ - -#define DRIVER_NAME "orinoco_usb" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mic.h" -#include "orinoco.h" - -#ifndef URB_ASYNC_UNLINK -#define URB_ASYNC_UNLINK 0 -#endif - -struct header_struct { - /* 802.3 */ - u8 dest[ETH_ALEN]; - u8 src[ETH_ALEN]; - __be16 len; - /* 802.2 */ - u8 dsap; - u8 ssap; - u8 ctrl; - /* SNAP */ - u8 oui[3]; - __be16 ethertype; -} __packed; - -struct ez_usb_fw { - u16 size; - const u8 *code; -}; - -static struct ez_usb_fw firmware = { - .size = 0, - .code = NULL, -}; - -/* Debugging macros */ -#undef err -#define err(format, arg...) \ - do { printk(KERN_ERR PFX format "\n", ## arg); } while (0) - -MODULE_FIRMWARE("orinoco_ezusb_fw"); - -/* - * Under some conditions, the card gets stuck and stops paying attention - * to the world (i.e. data communication stalls) until we do something to - * it. Sending an INQ_TALLIES command seems to be enough and should be - * harmless otherwise. This behaviour has been observed when using the - * driver on a systemimager client during installation. In the past a - * timer was used to send INQ_TALLIES commands when there was no other - * activity, but it was troublesome and was removed. - */ - -#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */ -#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */ -#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */ -#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */ - -#define USB_MELCO_VENDOR_ID 0x0411 -#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */ -#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */ -#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */ - -#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */ -#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */ - -#define USB_AVAYA8_VENDOR_ID 0x0D98 -#define USB_AVAYAE_VENDOR_ID 0x0D9E -#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */ - -#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */ -#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */ -#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */ -#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */ - -#define USB_ELSA_VENDOR_ID 0x05CC -#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */ - -#define USB_LEGEND_VENDOR_ID 0x0E7C -#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */ - -#define USB_SAMSUNG_VENDOR_ID 0x04E8 -#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */ - -#define USB_IGATE_VENDOR_ID 0x0681 -#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */ - -#define USB_FUJITSU_VENDOR_ID 0x0BF8 -#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */ - -#define USB_2WIRE_VENDOR_ID 0x1630 -#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */ - - -#define EZUSB_REQUEST_FW_TRANS 0xA0 -#define EZUSB_REQUEST_TRIGGER 0xAA -#define EZUSB_REQUEST_TRIG_AC 0xAC -#define EZUSB_CPUCS_REG 0x7F92 - -#define EZUSB_RID_TX 0x0700 -#define EZUSB_RID_RX 0x0701 -#define EZUSB_RID_INIT1 0x0702 -#define EZUSB_RID_ACK 0x0710 -#define EZUSB_RID_READ_PDA 0x0800 -#define EZUSB_RID_PROG_INIT 0x0852 -#define EZUSB_RID_PROG_SET_ADDR 0x0853 -#define EZUSB_RID_PROG_BYTES 0x0854 -#define EZUSB_RID_PROG_END 0x0855 -#define EZUSB_RID_DOCMD 0x0860 - -/* Recognize info frames */ -#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF)) - -#define EZUSB_MAGIC 0x0210 - -#define EZUSB_FRAME_DATA 1 -#define EZUSB_FRAME_CONTROL 2 - -#define DEF_TIMEOUT (3 * HZ) - -#define BULK_BUF_SIZE 2048 - -#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet)) - -#define FW_BUF_SIZE 64 -#define FW_VAR_OFFSET_PTR 0x359 -#define FW_VAR_VALUE 0 -#define FW_HOLE_START 0x100 -#define FW_HOLE_END 0x300 - -struct ezusb_packet { - __le16 magic; /* 0x0210 */ - u8 req_reply_count; - u8 ans_reply_count; - __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */ - __le16 size; /* transport size */ - __le16 crc; /* CRC up to here */ - __le16 hermes_len; - __le16 hermes_rid; - u8 data[]; -} __packed; - -/* Table of devices that work or may work with this driver */ -static const struct usb_device_id ezusb_table[] = { - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)}, - {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)}, - {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)}, - {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)}, - {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)}, - {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID, - 0, 0)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)}, - {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)}, - {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)}, - {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ezusb_table); - -/* Structure to hold all of our device specific stuff */ -struct ezusb_priv { - struct usb_device *udev; - struct net_device *dev; - struct mutex mtx; - spinlock_t req_lock; - struct list_head req_pending; - struct list_head req_active; - spinlock_t reply_count_lock; - u16 hermes_reg_fake[0x40]; - u8 *bap_buf; - struct urb *read_urb; - int read_pipe; - int write_pipe; - u8 reply_count; -}; - -enum ezusb_state { - EZUSB_CTX_START, - EZUSB_CTX_QUEUED, - EZUSB_CTX_REQ_SUBMITTED, - EZUSB_CTX_REQ_COMPLETE, - EZUSB_CTX_RESP_RECEIVED, - EZUSB_CTX_REQ_TIMEOUT, - EZUSB_CTX_REQ_FAILED, - EZUSB_CTX_RESP_TIMEOUT, - EZUSB_CTX_REQSUBMIT_FAIL, - EZUSB_CTX_COMPLETE, -}; - -struct request_context { - struct list_head list; - refcount_t refcount; - struct completion done; /* Signals that CTX is dead */ - int killed; - struct urb *outurb; /* OUT for req pkt */ - struct ezusb_priv *upriv; - struct ezusb_packet *buf; - int buf_length; - struct timer_list timer; /* Timeout handling */ - enum ezusb_state state; /* Current state */ - /* the RID that we will wait for */ - u16 out_rid; - u16 in_rid; -}; - - -/* Forward declarations */ -static void ezusb_ctx_complete(struct request_context *ctx); -static void ezusb_req_queue_run(struct ezusb_priv *upriv); -static void ezusb_bulk_in_callback(struct urb *urb); - -static inline u8 ezusb_reply_inc(u8 count) -{ - if (count < 0x7F) - return count + 1; - else - return 1; -} - -static void ezusb_request_context_put(struct request_context *ctx) -{ - if (!refcount_dec_and_test(&ctx->refcount)) - return; - - WARN_ON(!ctx->done.done); - BUG_ON(ctx->outurb->status == -EINPROGRESS); - BUG_ON(timer_pending(&ctx->timer)); - usb_free_urb(ctx->outurb); - kfree(ctx->buf); - kfree(ctx); -} - -static inline void ezusb_mod_timer(struct ezusb_priv *upriv, - struct timer_list *timer, - unsigned long expire) -{ - if (!upriv->udev) - return; - mod_timer(timer, expire); -} - -static void ezusb_request_timerfn(struct timer_list *t) -{ - struct request_context *ctx = from_timer(ctx, t, timer); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) { - ctx->state = EZUSB_CTX_REQ_TIMEOUT; - } else { - ctx->state = EZUSB_CTX_RESP_TIMEOUT; - dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); - refcount_inc(&ctx->refcount); - ctx->killed = 1; - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - } -}; - -static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, - u16 out_rid, u16 in_rid) -{ - struct request_context *ctx; - - ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); - if (!ctx) - return NULL; - - ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC); - if (!ctx->buf) { - kfree(ctx); - return NULL; - } - ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC); - if (!ctx->outurb) { - kfree(ctx->buf); - kfree(ctx); - return NULL; - } - - ctx->upriv = upriv; - ctx->state = EZUSB_CTX_START; - ctx->out_rid = out_rid; - ctx->in_rid = in_rid; - - refcount_set(&ctx->refcount, 1); - init_completion(&ctx->done); - - timer_setup(&ctx->timer, ezusb_request_timerfn, 0); - return ctx; -} - -static void ezusb_ctx_complete(struct request_context *ctx) -{ - struct ezusb_priv *upriv = ctx->upriv; - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - list_del_init(&ctx->list); - if (upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_req_queue_run(upriv); - spin_lock_irqsave(&upriv->req_lock, flags); - } - - switch (ctx->state) { - case EZUSB_CTX_COMPLETE: - case EZUSB_CTX_REQSUBMIT_FAIL: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_RESP_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) { - struct net_device *dev = upriv->dev; - struct net_device_stats *stats = &dev->stats; - - if (ctx->state != EZUSB_CTX_COMPLETE) - stats->tx_errors++; - else - stats->tx_packets++; - - netif_wake_queue(dev); - } - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (!upriv->udev) { - /* This is normal, as all request contexts get flushed - * when the device is disconnected */ - err("Called, CTX not terminating, but device gone"); - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - } - - err("Called, CTX not in terminating state."); - /* Things are really bad if this happens. Just leak - * the CTX because it may still be linked to the - * queue or the OUT urb may still be active. - * Just leaking at least prevents an Oops or Panic. - */ - break; - } -} - -/* - * ezusb_req_queue_run: - * Description: - * Note: Only one active CTX at any one time, because there's no - * other (reliable) way to match the response URB to the correct - * CTX. - */ -static void ezusb_req_queue_run(struct ezusb_priv *upriv) -{ - unsigned long flags; - struct request_context *ctx; - int result; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!list_empty(&upriv->req_active)) - goto unlock; - - if (list_empty(&upriv->req_pending)) - goto unlock; - - ctx = - list_entry(upriv->req_pending.next, struct request_context, - list); - - if (!ctx->upriv->udev) - goto unlock; - - /* We need to split this off to avoid a race condition */ - list_move_tail(&ctx->list, &upriv->req_active); - - if (ctx->state == EZUSB_CTX_QUEUED) { - refcount_inc(&ctx->refcount); - result = usb_submit_urb(ctx->outurb, GFP_ATOMIC); - if (result) { - ctx->state = EZUSB_CTX_REQSUBMIT_FAIL; - - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Fatal, failed to submit command urb." - " error=%d\n", result); - - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - goto done; - } - - ctx->state = EZUSB_CTX_REQ_SUBMITTED; - ezusb_mod_timer(ctx->upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - } - - unlock: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - done: - return; -} - -static void ezusb_req_enqueue_run(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!ctx->upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - goto done; - } - refcount_inc(&ctx->refcount); - list_add_tail(&ctx->list, &upriv->req_pending); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ctx->state = EZUSB_CTX_QUEUED; - ezusb_req_queue_run(upriv); - - done: - return; -} - -static void ezusb_request_out_callback(struct urb *urb) -{ - unsigned long flags; - enum ezusb_state state; - struct request_context *ctx = urb->context; - struct ezusb_priv *upriv = ctx->upriv; - - spin_lock_irqsave(&upriv->req_lock, flags); - - del_timer(&ctx->timer); - - if (ctx->killed) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - pr_warn("interrupt called with dead ctx\n"); - goto out; - } - - state = ctx->state; - - if (urb->status == 0) { - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - if (ctx->in_rid) { - ctx->state = EZUSB_CTX_REQ_COMPLETE; - /* reply URB still pending */ - ezusb_mod_timer(upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - spin_unlock_irqrestore(&upriv->req_lock, - flags); - break; - } - fallthrough; - case EZUSB_CTX_RESP_RECEIVED: - /* IN already received before this OUT-ACK */ - ctx->state = EZUSB_CTX_COMPLETE; - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } else { - /* If someone cancels the OUT URB then its status - * should be either -ECONNRESET or -ENOENT. - */ - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_RESP_RECEIVED: - ctx->state = EZUSB_CTX_REQ_FAILED; - fallthrough; - - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } - out: - ezusb_request_context_put(ctx); -} - -static void ezusb_request_in_callback(struct ezusb_priv *upriv, - struct urb *urb) -{ - struct ezusb_packet *ans = urb->transfer_buffer; - struct request_context *ctx = NULL; - enum ezusb_state state; - unsigned long flags; - - /* Find the CTX on the active queue that requested this URB */ - spin_lock_irqsave(&upriv->req_lock, flags); - if (upriv->udev) { - struct list_head *item; - - list_for_each(item, &upriv->req_active) { - struct request_context *c; - int reply_count; - - c = list_entry(item, struct request_context, list); - reply_count = - ezusb_reply_inc(c->buf->req_reply_count); - if ((ans->ans_reply_count == reply_count) - && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) { - ctx = c; - break; - } - netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n", - le16_to_cpu(ans->hermes_rid), c->in_rid, - ans->ans_reply_count, reply_count); - } - } - - if (ctx == NULL) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("%s: got unexpected RID: 0x%04X", __func__, - le16_to_cpu(ans->hermes_rid)); - ezusb_req_queue_run(upriv); - return; - } - - /* The data we want is in the in buffer, exchange */ - urb->transfer_buffer = ctx->buf; - ctx->buf = (void *) ans; - ctx->buf_length = urb->actual_length; - - state = ctx->state; - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - /* We have received our response URB before - * our request has been acknowledged. Do NOT - * destroy our CTX yet, because our OUT URB - * is still alive ... - */ - ctx->state = EZUSB_CTX_RESP_RECEIVED; - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Let the machine continue running. */ - break; - - case EZUSB_CTX_REQ_COMPLETE: - /* This is the usual path: our request - * has already been acknowledged, and - * we have now received the reply. - */ - ctx->state = EZUSB_CTX_COMPLETE; - - /* Stop the intimer */ - del_timer(&ctx->timer); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Call the completion handler */ - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - pr_warn("Matched IN URB, unexpected context state(0x%x)\n", - state); - /* Throw this CTX away and try submitting another */ - del_timer(&ctx->timer); - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - usb_unlink_urb(ctx->outurb); - ezusb_req_queue_run(upriv); - break; - } /* switch */ -} - -typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *); - -static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - wait_for_completion(&ctx->done); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - int msecs; - - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - /* If we get called from a timer or with our lock acquired, then - * we can't wait for the completion and have to poll. This won't - * happen if the USB controller completes the URB requests in - * BH. - */ - msecs = DEF_TIMEOUT * (1000 / HZ); - - while (!try_wait_for_completion(&ctx->done) && msecs--) - udelay(1000); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - WARN(1, "Shouldn't be invoked for in_rid\n"); -} - -static inline u16 build_crc(struct ezusb_packet *data) -{ - u16 crc = 0; - u8 *bytes = (u8 *)data; - int i; - - for (i = 0; i < 8; i++) - crc = (crc << 1) + bytes[i]; - - return crc; -} - -/* - * ezusb_fill_req: - * - * if data == NULL and length > 0 the data is assumed to be already in - * the target buffer and only the header is filled. - * - */ -static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid, - const void *data, u16 frame_type, u8 reply_count) -{ - int total_size = sizeof(*req) + length; - - BUG_ON(total_size > BULK_BUF_SIZE); - - req->magic = cpu_to_le16(EZUSB_MAGIC); - req->req_reply_count = reply_count; - req->ans_reply_count = 0; - req->frame_type = cpu_to_le16(frame_type); - req->size = cpu_to_le16(length + 4); - req->crc = cpu_to_le16(build_crc(req)); - req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length)); - req->hermes_rid = cpu_to_le16(rid); - if (data) - memcpy(req->data, data, length); - return total_size; -} - -static int ezusb_submit_in_urb(struct ezusb_priv *upriv) -{ - int retval = 0; - void *cur_buf = upriv->read_urb->transfer_buffer; - - if (upriv->read_urb->status == -EINPROGRESS) { - netdev_dbg(upriv->dev, "urb busy, not resubmiting\n"); - retval = -EBUSY; - goto exit; - } - usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe, - cur_buf, BULK_BUF_SIZE, - ezusb_bulk_in_callback, upriv); - upriv->read_urb->transfer_flags = 0; - retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC); - if (retval) - err("%s submit failed %d", __func__, retval); - - exit: - return retval; -} - -static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset) -{ - int ret; - u8 *res_val = NULL; - - if (!upriv->udev) { - err("%s: !upriv->udev", __func__); - return -EFAULT; - } - - res_val = kmalloc(sizeof(*res_val), GFP_KERNEL); - - if (!res_val) - return -ENOMEM; - - *res_val = reset; /* avoid argument promotion */ - - ret = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val, - sizeof(*res_val), DEF_TIMEOUT); - - kfree(res_val); - - return ret; -} - -static int ezusb_firmware_download(struct ezusb_priv *upriv, - struct ez_usb_fw *fw) -{ - u8 *fw_buffer; - int retval, addr; - int variant_offset; - - fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL); - if (!fw_buffer) { - printk(KERN_ERR PFX "Out of memory for firmware buffer.\n"); - return -ENOMEM; - } - /* - * This byte is 1 and should be replaced with 0. The offset is - * 0x10AD in version 0.0.6. The byte in question should follow - * the end of the code pointed to by the jump in the beginning - * of the firmware. Also, it is read by code located at 0x358. - */ - variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]); - if (variant_offset >= fw->size) { - printk(KERN_ERR PFX "Invalid firmware variant offset: " - "0x%04x\n", variant_offset); - retval = -EINVAL; - goto fail; - } - - retval = ezusb_8051_cpucs(upriv, 1); - if (retval < 0) - goto fail; - for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) { - /* 0x100-0x300 should be left alone, it contains card - * specific data, like USB enumeration information */ - if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END)) - continue; - - memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE); - if (variant_offset >= addr && - variant_offset < addr + FW_BUF_SIZE) { - netdev_dbg(upriv->dev, - "Patching card_variant byte at 0x%04X\n", - variant_offset); - fw_buffer[variant_offset - addr] = FW_VAR_VALUE; - } - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE - | USB_DIR_OUT, - addr, 0x0, - fw_buffer, FW_BUF_SIZE, - DEF_TIMEOUT); - - if (retval < 0) - goto fail; - } - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) - goto fail; - - goto exit; - fail: - printk(KERN_ERR PFX "Firmware download failed, error %d\n", - retval); - exit: - kfree(fw_buffer); - return retval; -} - -static int ezusb_access_ltv(struct ezusb_priv *upriv, - struct request_context *ctx, - u16 length, const void *data, u16 frame_type, - void *ans_buff, unsigned ans_size, u16 *ans_length, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - int req_size; - int retval = 0; - enum ezusb_state state; - - if (!upriv->udev) { - retval = -ENODEV; - goto exit; - } - - if (upriv->read_urb->status != -EINPROGRESS) - err("%s: in urb not pending", __func__); - - /* protect upriv->reply_count, guarantee sequential numbers */ - spin_lock_bh(&upriv->reply_count_lock); - req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data, - frame_type, upriv->reply_count); - usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe, - ctx->buf, req_size, - ezusb_request_out_callback, ctx); - - if (ctx->in_rid) - upriv->reply_count = ezusb_reply_inc(upriv->reply_count); - - ezusb_req_enqueue_run(upriv, ctx); - - spin_unlock_bh(&upriv->reply_count_lock); - - if (ctx->in_rid) - ezusb_ctx_wait_func(upriv, ctx); - - state = ctx->state; - switch (state) { - case EZUSB_CTX_COMPLETE: - retval = ctx->outurb->status; - break; - - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - if (!ctx->in_rid) - break; - fallthrough; - default: - err("%s: Unexpected context state %d", __func__, - state); - fallthrough; - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_RESP_TIMEOUT: - case EZUSB_CTX_REQSUBMIT_FAIL: - printk(KERN_ERR PFX "Access failed, resetting (state %d," - " reply_count %d)\n", state, upriv->reply_count); - upriv->reply_count = 0; - if (state == EZUSB_CTX_REQ_TIMEOUT - || state == EZUSB_CTX_RESP_TIMEOUT) { - printk(KERN_ERR PFX "ctx timed out\n"); - retval = -ETIMEDOUT; - } else { - printk(KERN_ERR PFX "ctx failed\n"); - retval = -EFAULT; - } - goto exit; - } - if (ctx->in_rid) { - struct ezusb_packet *ans = ctx->buf; - unsigned exp_len; - - if (ans->hermes_len != 0) - exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12; - else - exp_len = 14; - - if (exp_len != ctx->buf_length) { - err("%s: length mismatch for RID 0x%04x: " - "expected %d, got %d", __func__, - ctx->in_rid, exp_len, ctx->buf_length); - retval = -EIO; - goto exit; - } - - if (ans_buff) - memcpy(ans_buff, ans->data, min(exp_len, ans_size)); - if (ans_length) - *ans_length = le16_to_cpu(ans->hermes_len); - } - exit: - ezusb_request_context_put(ctx); - return retval; -} - -static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - u16 frame_type; - struct request_context *ctx; - - if (length == 0) - return -EINVAL; - - length = HERMES_RECLEN_TO_BYTES(length); - - /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be - * set to be empty, but the USB bridge doesn't like it */ - if (length == 0) - return 0; - - ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - if (rid == EZUSB_RID_TX) - frame_type = EZUSB_FRAME_DATA; - else - frame_type = EZUSB_FRAME_CONTROL; - - return ezusb_access_ltv(upriv, ctx, length, data, frame_type, - NULL, 0, NULL, ezusb_ctx_wait_func); -} - -static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data) -{ - return __ezusb_write_ltv(hw, bap, rid, length, data, - ezusb_req_ctx_wait_poll); -} - -static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf, - ezusb_ctx_wait ezusb_ctx_wait_func) - -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - if (bufsize % 2) - return -EINVAL; - - ctx = ezusb_alloc_ctx(upriv, rid, rid); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL, - buf, bufsize, length, ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, - u16 parm2, struct hermes_response *resp) -{ - WARN_ON_ONCE(1); - return -EINVAL; -} - -static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - __le16 data[4] = { - cpu_to_le16(cmd), - cpu_to_le16(parm0), - 0, - 0, - }; - netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0); - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_ctx_wait_func); -} - -static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll); -} - -static int ezusb_bap_pread(struct hermes *hw, int bap, - void *buf, int len, u16 id, u16 offset) -{ - struct ezusb_priv *upriv = hw->priv; - struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer; - int actual_length = upriv->read_urb->actual_length; - - if (id == EZUSB_RID_RX) { - if ((sizeof(*ans) + offset + len) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in rx frame\n"); - return -EINVAL; - } - memcpy(buf, ans->data + offset, len); - return 0; - } - - if (EZUSB_IS_INFO(id)) { - /* Include 4 bytes for length/type */ - if ((sizeof(*ans) + offset + len - 4) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in info frame\n"); - return -EFAULT; - } - memcpy(buf, ans->data + offset - 4, len); - } else { - printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id); - return -EINVAL; - } - - return 0; -} - -static int ezusb_read_pda(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le16 data[] = { - cpu_to_le16(pda_addr & 0xffff), - cpu_to_le16(pda_len - 4) - }; - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA); - if (!ctx) - return -ENOMEM; - - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4, - NULL, ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_init(struct hermes *hw, u32 entry_point) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(entry_point); - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_end(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_bytes(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(addr); - int err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); - if (err) - return err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, len, buf, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - u32 ch_addr; - u32 ch_len; - int err = 0; - - /* We can only send 2048 bytes out of the bulk xmit at a time, - * so we have to split any programming into chunks of <2048 - * bytes. */ - - ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE; - ch_addr = addr; - - while (ch_addr < (addr + len)) { - pr_debug("Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - ch_len, ch_addr, &buf[ch_addr - addr]); - - err = ezusb_program_bytes(hw, &buf[ch_addr - addr], - ch_addr, ch_len); - if (err) - break; - - ch_addr += ch_len; - ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ? - (addr + len - ch_addr) : MAX_DL_SIZE; - } - - return err; -} - -static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct ezusb_priv *upriv = priv->card; - u8 mic[MICHAEL_MIC_LEN + 1]; - int err = 0; - int tx_control; - unsigned long flags; - struct request_context *ctx; - u8 *buf; - int tx_size; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR - "%s: ezusb_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = 0; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic[0]); - if (err) - goto drop; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0); - if (!ctx) - goto drop; - - memset(ctx->buf, 0, BULK_BUF_SIZE); - buf = ctx->buf->data; - - { - __le16 *tx_cntl = (__le16 *)buf; - *tx_cntl = cpu_to_le16(tx_control); - buf += sizeof(*tx_cntl); - } - - memcpy(buf, skb->data, skb->len); - buf += skb->len; - - if (tx_control & HERMES_TXCTRL_MIC) { - u8 *m = mic; - /* Mic has been offset so it can be copied to an even - * address. We're copying eveything anyway, so we - * don't need to copy that first byte. */ - if (skb->len % 2) - m++; - memcpy(buf, m, MICHAEL_MIC_LEN); - buf += MICHAEL_MIC_LEN; - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - /* The card may behave better if we send evenly sized usb transfers */ - tx_size = ALIGN(buf - ctx->buf->data, 2); - - err = ezusb_access_ltv(upriv, ctx, tx_size, NULL, - EZUSB_FRAME_DATA, NULL, 0, NULL, - ezusb_req_ctx_wait_skip); - - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - netif_trans_update(dev); - stats->tx_bytes += skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - *fid = EZUSB_RID_TX; - return 0; -} - - -static int ezusb_hard_reset(struct orinoco_private *priv) -{ - struct ezusb_priv *upriv = priv->card; - int retval = ezusb_8051_cpucs(upriv, 1); - - if (retval < 0) { - err("Failed to reset"); - return retval; - } - - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) { - err("Failed to unreset"); - return retval; - } - - netdev_dbg(upriv->dev, "sending control message\n"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIGGER, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x0, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIGGER failed retval %d", retval); - return retval; - } -#if 0 - dbg("Sending EZUSB_REQUEST_TRIG_AC"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIG_AC, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x00FA, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval); - return retval; - } -#endif - - return 0; -} - - -static int ezusb_init(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - int retval; - - if (!upriv) - return -EINVAL; - - upriv->reply_count = 0; - /* Write the MAGIC number on the simulated registers to keep - * orinoco.c happy */ - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - hermes_write_regn(hw, RXFID, EZUSB_RID_RX); - - usb_kill_urb(upriv->read_urb); - ezusb_submit_in_urb(upriv); - - retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1, - HERMES_BYTES_TO_RECLEN(2), "\x10\x00", - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval); - return retval; - } - - retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL, - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval); - return retval; - } - - return 0; -} - -static void ezusb_bulk_in_callback(struct urb *urb) -{ - struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context; - struct ezusb_packet *ans = urb->transfer_buffer; - u16 crc; - u16 hermes_rid; - - if (upriv->udev == NULL) - return; - - if (urb->status == -ETIMEDOUT) { - /* When a device gets unplugged we get this every time - * we resubmit, flooding the logs. Since we don't use - * USB timeouts, it shouldn't happen any other time*/ - pr_warn("%s: urb timed out, not resubmitting\n", __func__); - return; - } - if (urb->status == -ECONNABORTED) { - pr_warn("%s: connection abort, resubmitting urb\n", - __func__); - goto resubmit; - } - if ((urb->status == -EILSEQ) - || (urb->status == -ENOENT) - || (urb->status == -ECONNRESET)) { - netdev_dbg(upriv->dev, "status %d, not resubmiting\n", - urb->status); - return; - } - if (urb->status) - netdev_dbg(upriv->dev, "status: %d length: %d\n", - urb->status, urb->actual_length); - if (urb->actual_length < sizeof(*ans)) { - err("%s: short read, ignoring", __func__); - goto resubmit; - } - crc = build_crc(ans); - if (le16_to_cpu(ans->crc) != crc) { - err("CRC error, ignoring packet"); - goto resubmit; - } - - hermes_rid = le16_to_cpu(ans->hermes_rid); - if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) { - ezusb_request_in_callback(upriv, urb); - } else if (upriv->dev) { - struct net_device *dev = upriv->dev; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - - if (hermes_rid == EZUSB_RID_RX) { - __orinoco_ev_rx(dev, hw); - } else { - hermes_write_regn(hw, INFOFID, - le16_to_cpu(ans->hermes_rid)); - __orinoco_ev_info(dev, hw); - } - } - - resubmit: - if (upriv->udev) - ezusb_submit_in_urb(upriv); -} - -static inline void ezusb_delete(struct ezusb_priv *upriv) -{ - struct list_head *item; - struct list_head *tmp_item; - unsigned long flags; - - BUG_ON(!upriv); - - mutex_lock(&upriv->mtx); - - upriv->udev = NULL; /* No timer will be rearmed from here */ - - usb_kill_urb(upriv->read_urb); - - spin_lock_irqsave(&upriv->req_lock, flags); - list_for_each_safe(item, tmp_item, &upriv->req_active) { - struct request_context *ctx; - int err; - - ctx = list_entry(item, struct request_context, list); - refcount_inc(&ctx->refcount); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - err = usb_unlink_urb(ctx->outurb); - - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (err == -EINPROGRESS) - wait_for_completion(&ctx->done); - - del_timer_sync(&ctx->timer); - /* FIXME: there is an slight chance for the irq handler to - * be running */ - if (!list_empty(&ctx->list)) - ezusb_ctx_complete(ctx); - - ezusb_request_context_put(ctx); - spin_lock_irqsave(&upriv->req_lock, flags); - } - spin_unlock_irqrestore(&upriv->req_lock, flags); - - list_for_each_safe(item, tmp_item, &upriv->req_pending) - ezusb_ctx_complete(list_entry(item, - struct request_context, list)); - - if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS) - printk(KERN_ERR PFX "Some URB in progress\n"); - - mutex_unlock(&upriv->mtx); - - if (upriv->read_urb) { - kfree(upriv->read_urb->transfer_buffer); - usb_free_urb(upriv->read_urb); - } - kfree(upriv->bap_buf); - if (upriv->dev) { - struct orinoco_private *priv = ndev_priv(upriv->dev); - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(upriv)); - free_orinocodev(priv); - } -} - -static void ezusb_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static const struct hermes_ops ezusb_ops = { - .init = ezusb_init, - .cmd_wait = ezusb_docmd_wait, - .init_cmd_wait = ezusb_doicmd_wait, - .allocate = ezusb_allocate, - .read_ltv = ezusb_read_ltv, - .read_ltv_pr = ezusb_read_ltv_preempt, - .write_ltv = ezusb_write_ltv, - .bap_pread = ezusb_bap_pread, - .read_pda = ezusb_read_pda, - .program_init = ezusb_program_init, - .program_end = ezusb_program_end, - .program = ezusb_program, - .lock_irqsave = ezusb_lock_irqsave, - .unlock_irqrestore = ezusb_unlock_irqrestore, - .lock_irq = ezusb_lock_irq, - .unlock_irq = ezusb_unlock_irq, -}; - -static const struct net_device_ops ezusb_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = ezusb_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -static int ezusb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct orinoco_private *priv; - struct hermes *hw; - struct ezusb_priv *upriv = NULL; - struct usb_interface_descriptor *iface_desc; - struct usb_endpoint_descriptor *ep; - const struct firmware *fw_entry = NULL; - int retval = 0; - int i; - - priv = alloc_orinocodev(sizeof(*upriv), &udev->dev, - ezusb_hard_reset, NULL); - if (!priv) { - err("Couldn't allocate orinocodev"); - retval = -ENOMEM; - goto exit; - } - - hw = &priv->hw; - - upriv = priv->card; - - mutex_init(&upriv->mtx); - spin_lock_init(&upriv->reply_count_lock); - - spin_lock_init(&upriv->req_lock); - INIT_LIST_HEAD(&upriv->req_pending); - INIT_LIST_HEAD(&upriv->req_active); - - upriv->udev = udev; - - hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake; - hw->reg_spacing = HERMES_16BIT_REGSPACING; - hw->priv = upriv; - hw->ops = &ezusb_ops; - - /* set up the endpoint information */ - /* check out the endpoints */ - - iface_desc = &interface->cur_altsetting->desc; - for (i = 0; i < iface_desc->bNumEndpoints; ++i) { - ep = &interface->cur_altsetting->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(ep)) { - /* we found a bulk in endpoint */ - if (upriv->read_urb != NULL) { - pr_warn("Found a second bulk in ep, ignored\n"); - continue; - } - - upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!upriv->read_urb) - goto error; - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk in: wMaxPacketSize!= 64\n"); - if (ep->bEndpointAddress != (2 | USB_DIR_IN)) - pr_warn("bulk in: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->read_pipe = usb_rcvbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->read_urb->transfer_buffer = - kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->read_urb->transfer_buffer) { - err("Couldn't allocate IN buffer"); - goto error; - } - } - - if (usb_endpoint_is_bulk_out(ep)) { - /* we found a bulk out endpoint */ - if (upriv->bap_buf != NULL) { - pr_warn("Found a second bulk out ep, ignored\n"); - continue; - } - - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk out: wMaxPacketSize != 64\n"); - if (ep->bEndpointAddress != 2) - pr_warn("bulk out: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->write_pipe = usb_sndbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->bap_buf) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - } - } - if (!upriv->bap_buf || !upriv->read_urb) { - err("Didn't find the required bulk endpoints"); - goto error; - } - - if (request_firmware(&fw_entry, "orinoco_ezusb_fw", - &interface->dev) == 0) { - firmware.size = fw_entry->size; - firmware.code = fw_entry->data; - } - if (firmware.size && firmware.code) { - if (ezusb_firmware_download(upriv, &firmware) < 0) - goto error; - } else { - err("No firmware to download"); - goto error; - } - - if (ezusb_hard_reset(priv) < 0) { - err("Cannot reset the device"); - goto error; - } - - /* If the firmware is already downloaded orinoco.c will call - * ezusb_init but if the firmware is not already there, that will make - * the kernel very unstable, so we try initializing here and quit in - * case of error */ - if (ezusb_init(hw) < 0) { - err("Couldn't initialize the device"); - err("Firmware may not be downloaded or may be wrong."); - goto error; - } - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - err("orinoco_init() failed\n"); - goto error; - } - - if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) { - upriv->dev = NULL; - err("%s: orinoco_if_add() failed", __func__); - wiphy_unregister(priv_to_wiphy(priv)); - goto error; - } - upriv->dev = priv->ndev; - - goto exit; - - error: - ezusb_delete(upriv); - if (upriv->dev) { - /* upriv->dev was 0, so ezusb_delete() didn't free it */ - free_orinocodev(priv); - } - upriv = NULL; - retval = -EFAULT; - exit: - if (fw_entry) { - firmware.code = NULL; - firmware.size = 0; - release_firmware(fw_entry); - } - usb_set_intfdata(interface, upriv); - return retval; -} - - -static void ezusb_disconnect(struct usb_interface *intf) -{ - struct ezusb_priv *upriv = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - ezusb_delete(upriv); - printk(KERN_INFO PFX "Disconnected\n"); -} - - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver orinoco_driver = { - .name = DRIVER_NAME, - .probe = ezusb_probe, - .disconnect = ezusb_disconnect, - .id_table = ezusb_table, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(orinoco_driver); - -MODULE_AUTHOR("Manuel Estrada Sainz"); -MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge"); -MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c deleted file mode 100644 index 6d1d084854fb..000000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ - -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "orinoco.h" -#include "main.h" - -#include "scan.h" - -#define ZERO_DBM_OFFSET 0x95 -#define MAX_SIGNAL_LEVEL 0x8A -#define MIN_SIGNAL_LEVEL 0x2F - -#define SIGNAL_TO_DBM(x) \ - (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ - - ZERO_DBM_OFFSET) -#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) - -static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) -{ - int i; - u8 rate; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 5; i++) { - rate = le16_to_cpu(rates[i]); - /* NULL terminated */ - if (rate == 0x0) - break; - buf[i + 2] = rate; - } - buf[1] = i; - - return i + 2; -} - -static int prism_build_supp_rates(u8 *buf, const u8 *rates) -{ - int i; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 8; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[1] = i; - - /* We might still have another 2 rates, which need to go in - * extended supported rates */ - if (i == 8 && rates[i] > 0) { - buf[10] = WLAN_EID_EXT_SUPP_RATES; - for (; i < 10; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[11] = i - 8; - } - - return (i < 8) ? i + 2 : i + 4; -} - -static void orinoco_add_hostscan_result(struct orinoco_private *priv, - const union hermes_scan_info *bss) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - u8 *ie; - u8 ie_buf[46]; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - int ie_len; - int freq; - int len; - - len = le16_to_cpu(bss->a.essid_len); - - /* Reconstruct SSID and bitrate IEs to pass up */ - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = len; - memcpy(&ie_buf[2], bss->a.essid, len); - - ie = ie_buf + len + 2; - ie_len = ie_buf[1] + 2; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - ie_len += symbol_build_supp_rates(ie, bss->s.rates); - break; - - case FIRMWARE_TYPE_INTERSIL: - ie_len += prism_build_supp_rates(ie, bss->p.rates); - break; - - case FIRMWARE_TYPE_AGERE: - default: - break; - } - - freq = ieee80211_channel_to_frequency( - le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - if (!channel) { - printk(KERN_DEBUG "Invalid channel designation %04X(%04X)", - bss->a.channel, freq); - return; /* Then ignore it for now */ - } - timestamp = 0; - capability = le16_to_cpu(bss->a.capabilities); - beacon_interval = le16_to_cpu(bss->a.beacon_interv); - signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->a.bssid, timestamp, capability, - beacon_interval, ie_buf, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *bss, - size_t len) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - const u8 *ie; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - size_t ie_len; - int chan, freq; - - ie_len = len - sizeof(*bss); - ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len); - chan = ie ? ie[2] : 0; - freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - - timestamp = le64_to_cpu(bss->timestamp); - capability = le16_to_cpu(bss->capabilities); - beacon_interval = le16_to_cpu(bss->beacon_interval); - ie = bss->data; - signal = SIGNAL_TO_MBM(bss->level); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->bssid, timestamp, capability, - beacon_interval, ie, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_hostscan_results(struct orinoco_private *priv, - unsigned char *buf, - size_t len) -{ - int offset; /* In the scan data */ - size_t atom_len; - bool abort = false; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - atom_len = sizeof(struct agere_scan_apinfo); - offset = 0; - break; - - case FIRMWARE_TYPE_SYMBOL: - /* Lack of documentation necessitates this hack. - * Different firmwares have 68 or 76 byte long atoms. - * We try modulo first. If the length divides by both, - * we check what would be the channel in the second - * frame for a 68-byte atom. 76-byte atoms have 0 there. - * Valid channel cannot be 0. */ - if (len % 76) - atom_len = 68; - else if (len % 68) - atom_len = 76; - else if (len >= 1292 && buf[68] == 0) - atom_len = 76; - else - atom_len = 68; - offset = 0; - break; - - case FIRMWARE_TYPE_INTERSIL: - offset = 4; - if (priv->has_hostscan) { - atom_len = le16_to_cpup((__le16 *)buf); - /* Sanity check for atom_len */ - if (atom_len < sizeof(struct prism2_scan_apinfo)) { - printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %zu\n", priv->ndev->name, - atom_len); - abort = true; - goto scan_abort; - } - } else - atom_len = offsetof(struct prism2_scan_apinfo, atim); - break; - - default: - abort = true; - goto scan_abort; - } - - /* Check that we got an whole number of atoms */ - if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %zu, " - "atom_len %zu, offset %d\n", priv->ndev->name, len, - atom_len, offset); - abort = true; - goto scan_abort; - } - - /* Process the entries one by one */ - for (; offset + atom_len <= len; offset += atom_len) { - union hermes_scan_info *atom; - - atom = (union hermes_scan_info *) (buf + offset); - - orinoco_add_hostscan_result(priv, atom); - } - - scan_abort: - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} - -void orinoco_scan_done(struct orinoco_private *priv, bool abort) -{ - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} diff --git a/drivers/net/wireless/intersil/orinoco/scan.h b/drivers/net/wireless/intersil/orinoco/scan.h deleted file mode 100644 index 27281fb0a6dc..000000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_SCAN_H_ -#define _ORINOCO_SCAN_H_ - -/* Forward declarations */ -struct orinoco_private; -struct agere_ext_scan_info; - -/* Add scan results */ -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom, - size_t len); -void orinoco_add_hostscan_results(struct orinoco_private *dev, - unsigned char *buf, - size_t len); -void orinoco_scan_done(struct orinoco_private *priv, bool abort); - -#endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c deleted file mode 100644 index 841d623c621a..000000000000 --- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as - * Symbol Wireless Networker LA4137, CompactFlash cards by Socket - * Communications and Intel PRO/Wireless 2011B. - * - * The driver implements Symbol firmware download. The rest is handled - * in hermes.c and main.c. - * - * Utilities for downloading the Symbol firmware are available at - * http://sourceforge.net/projects/orinoco/ - * - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on orinoco_cs.c: - * Copyright (C) David Gibson, Linuxcare Australia - * Portions based on Spectrum24tDnld.c from original spectrum24 driver: - * Copyright (C) Symbol Technologies. - * - * See copyright notice in file main.c. - */ - -#define DRIVER_NAME "spectrum_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin "); -MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int spectrum_cs_config(struct pcmcia_device *link); -static void spectrum_cs_release(struct pcmcia_device *link); - -/* Constants for the CISREG_CCSR register */ -#define HCR_RUN 0x07 /* run firmware after reset */ -#define HCR_IDLE 0x0E /* don't run firmware after reset */ -#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ - - -/* - * Reset the card using configuration registers COR and CCSR. - * If IDLE is 1, stop the firmware, so that it can be safely rewritten. - */ -static int -spectrum_reset(struct pcmcia_device *link, int idle) -{ - int ret; - u8 save_cor; - u8 ccsr; - - /* Doing it if hardware is gone is guaranteed crash */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - - /* Save original COR value */ - ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor); - if (ret) - goto failed; - - /* Soft-Reset card */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor | COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - - /* Read CCSR */ - ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr); - if (ret) - goto failed; - - /* - * Start or stop the firmware. Memory width bit should be - * preserved from the value we've just read. - */ - ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16); - ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr); - if (ret) - goto failed; - udelay(1000); - - /* Restore original COR configuration index */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor & ~COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - return 0; - -failed: - return -ENODEV; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -spectrum_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - - return 0; -} - -static int -spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - return spectrum_reset(link, idle); -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -spectrum_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = spectrum_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void spectrum_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - spectrum_cs_release(link); - - free_orinocodev(priv); -} /* spectrum_cs_detach */ - -static int spectrum_cs_config_check(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -spectrum_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - hw->eeprom_pda = true; - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Reset card */ - if (spectrum_cs_hard_reset(priv) != 0) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - spectrum_cs_release(link); - return -ENODEV; -} /* spectrum_cs_config */ - -static void -spectrum_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* spectrum_cs_release */ - - -static int -spectrum_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - /* Mark the device as stopped, to block IO until later */ - orinoco_down(priv); - - return 0; -} - -static int -spectrum_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - int err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id spectrum_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ - PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = spectrum_cs_probe, - .remove = spectrum_cs_detach, - .suspend = spectrum_cs_suspend, - .resume = spectrum_cs_resume, - .id_table = spectrum_cs_ids, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c deleted file mode 100644 index dea1ff044342..000000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.c +++ /dev/null @@ -1,1428 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" -#include "mic.h" -#include "scan.h" -#include "main.h" - -#include "wext.h" - -#define MAX_RID_LEN 1024 - -/* Helper routine to record keys - * It is called under orinoco_lock so it may not sleep */ -static int orinoco_set_key(struct orinoco_private *priv, int index, - enum orinoco_alg alg, const u8 *key, int key_len, - const u8 *seq, int seq_len) -{ - kfree_sensitive(priv->keys[index].key); - kfree_sensitive(priv->keys[index].seq); - - if (key_len) { - priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); - if (!priv->keys[index].key) - goto nomem; - } else - priv->keys[index].key = NULL; - - if (seq_len) { - priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); - if (!priv->keys[index].seq) - goto free_key; - } else - priv->keys[index].seq = NULL; - - priv->keys[index].key_len = key_len; - priv->keys[index].seq_len = seq_len; - - if (key_len) - memcpy((void *)priv->keys[index].key, key, key_len); - if (seq_len) - memcpy((void *)priv->keys[index].seq, seq, seq_len); - - switch (alg) { - case ORINOCO_ALG_TKIP: - priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; - break; - - case ORINOCO_ALG_WEP: - priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? - WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; - break; - - case ORINOCO_ALG_NONE: - default: - priv->keys[index].cipher = 0; - break; - } - - return 0; - -free_key: - kfree(priv->keys[index].key); - priv->keys[index].key = NULL; - -nomem: - priv->keys[index].key_len = 0; - priv->keys[index].seq_len = 0; - priv->keys[index].cipher = 0; - - return -ENOMEM; -} - -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err; - unsigned long flags; - - if (!netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } - - /* If busy, return the old stats. Returning NULL may cause - * the interface to disappear from /proc/net/wireless */ - if (orinoco_lock(priv, &flags) != 0) - return wstats; - - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: Really we should wait for the inquiry to come back - - * as it is the stats we give don't make a whole lot of sense. - * Unfortunately, it's not clear how to do that within the - * wireless extensions framework: I think we're in user - * context, but a lock seems to be held by the time we get in - * here so we're not safe to sleep here. */ - hermes_inquire(hw, HERMES_INQ_TALLIES); - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_data.spy_stat[0].qual; - wstats->qual.level = priv->spy_data.spy_stat[0].level; - wstats->qual.noise = priv->spy_data.spy_stat[0].noise; - wstats->qual.updated = - priv->spy_data.spy_stat[0].updated; - } - } else { - struct { - __le16 qual, signal, noise, unused; - } __packed cq; - - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - if (!err) { - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = - IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } - } - - orinoco_unlock(priv, &flags); - return wstats; -} - -/********************************************************************/ -/* Wireless extensions */ -/********************************************************************/ - -static int orinoco_ioctl_setwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Enable automatic roaming - no sanity checks are needed */ - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - priv->bssid_fixed = 0; - eth_zero_addr(priv->desired_bssid); - - /* "off" means keep existing connection */ - if (ap_addr->sa_data[0] == 0) { - __orinoco_hw_set_wap(priv); - err = 0; - } - goto out; - } - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { - printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " - "support manual roaming\n", - dev->name); - err = -EOPNOTSUPP; - goto out; - } - - if (priv->iw_mode != NL80211_IFTYPE_STATION) { - printk(KERN_WARNING "%s: Manual roaming supported only in " - "managed mode\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Intersil firmware hangs without Desired ESSID */ - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && - strlen(priv->desired_essid) == 0) { - printk(KERN_WARNING "%s: Desired ESSID must be set for " - "manual roaming\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Finally, enable manual roaming */ - priv->bssid_fixed = 1; - memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_getwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - ap_addr->sa_family = ARPHRD_ETHER; - err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - enum orinoco_alg encode_alg = priv->encode_alg; - int restricted = priv->wep_restrict; - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (erq->pointer) { - /* We actually have a key to set - check its length */ - if (erq->length > LARGE_KEY_SIZE) - return -E2BIG; - - if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep) - return -E2BIG; - } - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) - (void) orinoco_clear_tkip_key(priv, setindex); - - if (erq->length > 0) { - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - /* Switch on WEP if off */ - if (encode_alg != ORINOCO_ALG_WEP) { - setindex = index; - encode_alg = ORINOCO_ALG_WEP; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { - if ((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if (priv->keys[index].key_len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = ORINOCO_ALG_NONE; - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer && erq->length > 0) { - err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, - erq->length, NULL, 0); - } - priv->tx_key = setindex; - - /* Try fast key change if connected and only keys are changed */ - if ((priv->encode_alg == encode_alg) && - (priv->wep_restrict == restricted) && - netif_carrier_ok(dev)) { - err = __orinoco_hw_setup_wepkeys(priv); - /* No need to commit if successful */ - goto out; - } - - priv->encode_alg = encode_alg; - priv->wep_restrict = restricted; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (!priv->encode_alg) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - if (priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - erq->length = priv->keys[index].key_len; - - memcpy(keybuf, priv->keys[index].key, erq->length); - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_setessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - /* Hum... Should not use Wireless Extension constant (may change), - * should use our own... - Jean II */ - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ - memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); - - /* If not ANY, get the new ESSID */ - if (erq->flags) - memcpy(priv->desired_essid, essidbuf, erq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - int active; - int err = 0; - unsigned long flags; - - if (netif_running(dev)) { - err = orinoco_hw_get_essid(priv, &active, essidbuf); - if (err < 0) - return err; - erq->length = err; - } else { - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); - erq->length = strlen(priv->desired_essid); - orinoco_unlock(priv, &flags); - } - - erq->flags = 1; - - return 0; -} - -static int orinoco_ioctl_setfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int chan = -1; - unsigned long flags; - int err = -EINPROGRESS; /* Call commit handler */ - - /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == NL80211_IFTYPE_STATION) - return -EBUSY; - - if ((frq->e == 0) && (frq->m <= 1000)) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency */ - int denom = 1; - int i; - - /* Calculate denominator to rescale to MHz */ - for (i = 0; i < (6 - frq->e); i++) - denom *= 10; - - chan = ieee80211_frequency_to_channel(frq->m / denom); - } - - if ((chan < 1) || (chan > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (chan - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = chan; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - chan, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int tmp; - - /* Locking done in there */ - tmp = orinoco_hw_get_freq(priv); - if (tmp < 0) - return tmp; - - frq->m = tmp * 100000; - frq->e = 1; - - return 0; -} - -static int orinoco_ioctl_getsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - u16 val; - int err; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, &val); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int orinoco_ioctl_setsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - int val = srq->value; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->ap_density = val; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_setrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int ratemode; - int bitrate; /* 100s of kilobits */ - unsigned long flags; - - /* As the user space doesn't know our highest rate, it uses -1 - * to ask us to set the highest rate. Test it using "iwconfig - * ethX rate auto" - Jean II */ - if (rrq->value == -1) - bitrate = 110; - else { - if (rrq->value % 100000) - return -EINVAL; - bitrate = rrq->value / 100000; - } - - ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed); - - if (ratemode == -1) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->bitratemode = ratemode; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; -} - -static int orinoco_ioctl_getrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int bitrate, automatic; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic); - - /* If the interface is running we try to find more about the - current mode */ - if (netif_running(dev)) { - int act_bitrate; - int lerr; - - /* Ignore errors if we can't get the actual bitrate */ - lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate); - if (!lerr) - bitrate = act_bitrate; - } - - orinoco_unlock(priv, &flags); - - rrq->value = bitrate; - rrq->fixed = !automatic; - rrq->disabled = 0; - - return err; -} - -static int orinoco_ioctl_setpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - goto out; - } - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if (!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int err = 0; - u16 enable, period, timeout, mcast; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, alg = ext->alg, set_key = 1; - unsigned long flags; - int err = -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { - /* Clear any TKIP TX key we had */ - (void) orinoco_clear_tkip_key(priv, priv->tx_key); - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->tx_key = idx; - set_key = ((alg == IW_ENCODE_ALG_TKIP) || - (ext->key_len > 0)) ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->encode_alg = ORINOCO_ALG_NONE; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, - NULL, 0, NULL, 0); - break; - - case IW_ENCODE_ALG_WEP: - if (ext->key_len <= 0) - goto out; - - priv->encode_alg = ORINOCO_ALG_WEP; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, - ext->key, ext->key_len, NULL, 0); - break; - - case IW_ENCODE_ALG_TKIP: - { - u8 *tkip_iv = NULL; - - if (!priv->has_wpa || - (ext->key_len > sizeof(struct orinoco_tkip_key))) - goto out; - - priv->encode_alg = ORINOCO_ALG_TKIP; - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - tkip_iv = &ext->rx_seq[0]; - - err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, - ext->key, ext->key_len, tkip_iv, - ORINOCO_SEQ_LEN); - - err = __orinoco_hw_set_tkip_key(priv, idx, - ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - priv->keys[idx].key, priv->keys[idx].key_len, - tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); - if (err) - printk(KERN_ERR "%s: Error %d setting TKIP key" - "\n", dev->name, err); - - goto out; - } - default: - goto out; - } - } - err = -EINPROGRESS; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = -EINVAL; - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - goto out; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - switch (priv->encode_alg) { - case ORINOCO_ALG_NONE: - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case ORINOCO_ALG_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - case ORINOCO_ALG_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - } - - err = 0; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = -EINPROGRESS; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - case IW_AUTH_DROP_UNENCRYPTED: - /* - * orinoco does not use these parameters - */ - break; - - case IW_AUTH_MFP: - /* Management Frame Protection not supported. - * Only fail if set to required. - */ - if (param->value == IW_AUTH_MFP_REQUIRED) - ret = -EINVAL; - break; - - case IW_AUTH_KEY_MGMT: - /* wl_lkm implies value 2 == PSK for Hermes I - * which ties in with WEXT - * no other hints tho :( - */ - priv->key_mgmt = param->value; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - /* When countermeasures are enabled, shut down the - * card; when disabled, re-enable the card. This must - * take effect immediately. - * - * TODO: Make sure that the EAPOL message is getting - * out before card disabled - */ - if (param->value) { - priv->tkip_cm_active = 1; - ret = hermes_disable_port(hw, 0); - } else { - priv->tkip_cm_active = 0; - ret = hermes_enable_port(hw, 0); - } - break; - - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - priv->wep_restrict = 1; - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - priv->wep_restrict = 0; - else - ret = -EINVAL; - break; - - case IW_AUTH_WPA_ENABLED: - if (priv->has_wpa) { - priv->wpa_enabled = param->value ? 1 : 0; - } else { - if (param->value) - ret = -EOPNOTSUPP; - /* else silently accept disable of WPA */ - priv->wpa_enabled = 0; - } - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_KEY_MGMT: - param->value = priv->key_mgmt; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - param->value = priv->tkip_cm_active; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->wep_restrict) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = priv->wpa_enabled; - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - u8 *buf; - unsigned long flags; - - /* cut off at IEEE80211_MAX_DATA_LEN */ - if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || - (wrqu->data.length && (extra == NULL))) - return -EINVAL; - - if (wrqu->data.length) { - buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - } else - buf = NULL; - - if (orinoco_lock(priv, &flags) != 0) { - kfree(buf); - return -EBUSY; - } - - kfree(priv->wpa_ie); - priv->wpa_ie = buf; - priv->wpa_ie_len = wrqu->data.length; - - if (priv->wpa_ie) { - /* Looks like wl_lkm wants to check the auth alg, and - * somehow pass it to the firmware. - * Instead it just calls the key mgmt rid - * - we do this in set auth. - */ - } - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { - wrqu->data.length = 0; - goto out; - } - - if (wrqu->data.length < priv->wpa_ie_len) { - err = -E2BIG; - goto out; - } - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - -out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* silently ignore */ - break; - - case IW_MLME_DISASSOC: - - ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, - mlme->reason_code); - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - - /* Firmware reset */ - orinoco_reset(&priv->reset_work); - } else { - printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - - schedule_work(&priv->reset_work); - } - - return 0; -} - -static int orinoco_ioctl_setibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->ibss_port = val; - - /* Actually update the mode we are using */ - set_port_type(priv); - - orinoco_unlock(priv, &flags); - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->ibss_port; - return 0; -} - -static int orinoco_ioctl_setport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (!priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (!priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (!err) { - /* Actually update the mode we are using */ - set_port_type(priv); - err = -EINPROGRESS; - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->prefer_port3; - return 0; -} - -static int orinoco_ioctl_setpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int val; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - val = *((int *) extra); - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (val) - priv->preamble = 1; - else - priv->preamble = 0; - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - *val = priv->preamble; - return 0; -} - -/* ioctl interface to hermes_read_ltv() - * To use with iwpriv, pass the RID as the token argument, e.g. - * iwpriv get_rid [0xfc00] - * At least Wireless Tools 25 is required to use iwpriv. - * For Wireless Tools 25 and 26 append "dummy" are the end. */ -static int orinoco_ioctl_getrid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *data = &wrqu->data; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int rid = data->flags; - u16 length; - int err; - unsigned long flags; - - /* It's a "get" function, but we don't want users to access the - * WEP key and other raw firmware data */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rid < 0xfc00 || rid > 0xffff) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, - extra); - if (err) - goto out; - - data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), - MAX_RID_LEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - - -/* Commit handler, called after set operations */ -static int orinoco_ioctl_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (!priv->open) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return err; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - return err; -} - -static const struct iw_priv_args orinoco_privtab[] = { - { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, - { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, - { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" }, - { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_ibssport" }, - { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_ibssport" }, - { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, - "get_rid" }, -}; - - -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler orinoco_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), - IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), - IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), - IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), - IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), - IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), - IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), - IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), - IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), - IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), - IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), - IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts), - IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts), - IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag), - IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag), - IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry), - IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), - IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), - IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), - IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), - IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), - IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), - IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), - IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), - IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), -}; - - -/* - Added typecasting since we no longer use iwreq_data -- Moustafa - */ -static const iw_handler orinoco_private_handler[] = { - [0] = orinoco_ioctl_reset, - [1] = orinoco_ioctl_reset, - [2] = orinoco_ioctl_setport3, - [3] = orinoco_ioctl_getport3, - [4] = orinoco_ioctl_setpreamble, - [5] = orinoco_ioctl_getpreamble, - [6] = orinoco_ioctl_setibssport, - [7] = orinoco_ioctl_getibssport, - [9] = orinoco_ioctl_getrid, -}; - -const struct iw_handler_def orinoco_handler_def = { - .num_standard = ARRAY_SIZE(orinoco_handler), - .num_private = ARRAY_SIZE(orinoco_private_handler), - .num_private_args = ARRAY_SIZE(orinoco_privtab), - .standard = orinoco_handler, - .private = orinoco_private_handler, - .private_args = orinoco_privtab, - .get_wireless_stats = orinoco_get_wireless_stats, -}; diff --git a/drivers/net/wireless/intersil/orinoco/wext.h b/drivers/net/wireless/intersil/orinoco/wext.h deleted file mode 100644 index 1479f4e26dde..000000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_WEXT_H_ -#define _ORINOCO_WEXT_H_ - -#include - -/* Structure defining all our WEXT handlers */ -extern const struct iw_handler_def orinoco_handler_def; - -#endif /* _ORINOCO_WEXT_H_ */ From 6b9dbaff83d626e5a9cc0c01a2b302f8fe423a1a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:49 +0200 Subject: [PATCH 0158/7721] wifi: remove orphaned ray_cs driver Aviator/Raytheon is an early PCMCIA driver, apparently predating 802.11b and only supporting wireless extensions. The driver has been orphaned since 2010 and only seen cosmetic updates long before than. Jean Tourrilhes pointed out in a 2005 changelog that he tested a change on actual hardware, which was apparently already noteworthy back then. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- .../networking/device_drivers/wifi/index.rst | 1 - .../networking/device_drivers/wifi/ray_cs.rst | 165 - MAINTAINERS | 5 - drivers/net/wireless/legacy/Kconfig | 16 - drivers/net/wireless/legacy/Makefile | 1 - drivers/net/wireless/legacy/ray_cs.c | 2824 ----------------- drivers/net/wireless/legacy/ray_cs.h | 74 - drivers/net/wireless/legacy/rayctl.h | 734 ----- 8 files changed, 3820 deletions(-) delete mode 100644 Documentation/networking/device_drivers/wifi/ray_cs.rst delete mode 100644 drivers/net/wireless/legacy/ray_cs.c delete mode 100644 drivers/net/wireless/legacy/ray_cs.h delete mode 100644 drivers/net/wireless/legacy/rayctl.h diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst index bf91a87c7acf..fb394f5de4a9 100644 --- a/Documentation/networking/device_drivers/wifi/index.rst +++ b/Documentation/networking/device_drivers/wifi/index.rst @@ -10,7 +10,6 @@ Contents: intel/ipw2100 intel/ipw2200 - ray_cs .. only:: subproject and html diff --git a/Documentation/networking/device_drivers/wifi/ray_cs.rst b/Documentation/networking/device_drivers/wifi/ray_cs.rst deleted file mode 100644 index 9a46d1ae8f20..000000000000 --- a/Documentation/networking/device_drivers/wifi/ray_cs.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: - -========================= -Raylink wireless LAN card -========================= - -September 21, 1999 - -Copyright |copy| 1998 Corey Thomas (corey@world.std.com) - -This file is the documentation for the Raylink Wireless LAN card driver for -Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE -802.11 compatible wireless network connectivity at 1 and 2 megabits/second. -See http://www.raytheon.com/micro/raylink/ for more information on the Raylink -card. This driver is in early development and does have bugs. See the known -bugs and limitations at the end of this document for more information. -This driver also works with WebGear's Aviator 2.4 and Aviator Pro -wireless LAN cards. - -As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel -source. My web page for the development of ray_cs is at -http://web.ralinktech.com/ralink/Home/Support/Linux.html -and I can be emailed at corey@world.std.com - -The kernel driver is based on ray_cs-1.62.tgz - -The driver at my web page is intended to be used as an add on to -David Hinds pcmcia package. All the command line parameters are -available when compiled as a module. When built into the kernel, only -the essid= string parameter is available via the kernel command line. -This will change after the method of sorting out parameters for all -the PCMCIA drivers is agreed upon. If you must have a built in driver -with nondefault parameters, they can be edited in -/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for module_param -will find them all. - -Information on card services is available at: - - http://pcmcia-cs.sourceforge.net/ - - -Card services user programs are still required for PCMCIA devices. -pcmcia-cs-3.1.1 or greater is required for the kernel version of -the driver. - -Currently, ray_cs is not part of David Hinds card services package, -so the following magic is required. - -At the end of the /etc/pcmcia/config.opts file, add the line: -source ./ray_cs.opts -This will make card services read the ray_cs.opts file -when starting. Create the file /etc/pcmcia/ray_cs.opts containing the -following:: - - #### start of /etc/pcmcia/ray_cs.opts ################### - # Configuration options for Raylink Wireless LAN PCMCIA card - device "ray_cs" - class "network" module "misc/ray_cs" - - card "RayLink PC Card WLAN Adapter" - manfid 0x01a6, 0x0000 - bind "ray_cs" - - module "misc/ray_cs" opts "" - #### end of /etc/pcmcia/ray_cs.opts ##################### - - -To join an existing network with -different parameters, contact the network administrator for the -configuration information, and edit /etc/pcmcia/ray_cs.opts. -Add the parameters below between the empty quotes. - -Parameters for ray_cs driver which may be specified in ray_cs.opts: - -=============== =============== ============================================= -bc integer 0 = normal mode (802.11 timing), - 1 = slow down inter frame timing to allow - operation with older breezecom access - points. - -beacon_period integer beacon period in Kilo-microseconds, - - legal values = must be integer multiple - of hop dwell - - default = 256 - -country integer 1 = USA (default), - 2 = Europe, - 3 = Japan, - 4 = Korea, - 5 = Spain, - 6 = France, - 7 = Israel, - 8 = Australia - -essid string ESS ID - network name to join - - string with maximum length of 32 chars - default value = "ADHOC_ESSID" - -hop_dwell integer hop dwell time in Kilo-microseconds - - legal values = 16,32,64,128(default),256 - -irq_mask integer linux standard 16 bit value 1bit/IRQ - - lsb is IRQ 0, bit 1 is IRQ 1 etc. - Used to restrict choice of IRQ's to use. - Recommended method for controlling - interrupts is in /etc/pcmcia/config.opts - -net_type integer 0 (default) = adhoc network, - 1 = infrastructure - -phy_addr string string containing new MAC address in - hex, must start with x eg - x00008f123456 - -psm integer 0 = continuously active, - 1 = power save mode (not useful yet) - -pc_debug integer (0-5) larger values for more verbose - logging. Replaces ray_debug. - -ray_debug integer Replaced with pc_debug - -ray_mem_speed integer defaults to 500 - -sniffer integer 0 = not sniffer (default), - 1 = sniffer which can be used to record all - network traffic using tcpdump or similar, - but no normal network use is allowed. - -translate integer 0 = no translation (encapsulate frames), - 1 = translation (RFC1042/802.1) -=============== =============== ============================================= - -More on sniffer mode: - -tcpdump does not understand 802.11 headers, so it can't -interpret the contents, but it can record to a file. This is only -useful for debugging 802.11 lowlevel protocols that are not visible to -linux. If you want to watch ftp xfers, or do similar things, you -don't need to use sniffer mode. Also, some packet types are never -sent up by the card, so you will never see them (ack, rts, cts, probe -etc.) There is a simple program (showcap) included in the ray_cs -package which parses the 802.11 headers. - -Known Problems and missing features - - Does not work with non x86 - - Does not work with SMP - - Support for defragmenting frames is not yet debugged, and in - fact is known to not work. I have never encountered a net set - up to fragment, but still, it should be fixed. - - The ioctl support is incomplete. The hardware address cannot be set - using ifconfig yet. If a different hardware address is needed, it may - be set using the phy_addr parameter in ray_cs.opts. This requires - a card insertion to take effect. diff --git a/MAINTAINERS b/MAINTAINERS index 161bf9d89535..91eacd4ecc9f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17961,11 +17961,6 @@ F: drivers/ras/ F: include/linux/ras.h F: include/ras/ras_event.h -RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/ray* - RC-CORE / LIRC FRAMEWORK M: Sean Young L: linux-media@vger.kernel.org diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig index 3a5275941212..1d77d53d6440 100644 --- a/drivers/net/wireless/legacy/Kconfig +++ b/drivers/net/wireless/legacy/Kconfig @@ -1,19 +1,3 @@ -config PCMCIA_RAYCS - tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - help - Say Y here if you intend to attach an Aviator/Raytheon PCMCIA - (PC-card) wireless Ethernet networking card to your computer. - Please read the file - for - details. - - To compile this driver as a module, choose M here: the module will be - called ray_cs. If unsure, say N. - config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" depends on CFG80211 && PCMCIA diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile index 36878f080bfc..d8705ccc5cf5 100644 --- a/drivers/net/wireless/legacy/Makefile +++ b/drivers/net/wireless/legacy/Makefile @@ -1,5 +1,4 @@ # 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c deleted file mode 100644 index c95a79e01cd0..000000000000 --- a/drivers/net/wireless/legacy/ray_cs.c +++ /dev/null @@ -1,2824 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/*============================================================================= - * - * A PCMCIA client driver for the Raylink wireless LAN card. - * The starting point for this module was the skeleton.c in the - * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net - * - * Copyright (c) 1998 Corey Thomas (corey@world.std.com) - * - * Changes: - * Arnaldo Carvalho de Melo - 08/08/2000 - * - reorganize kmallocs in ray_attach, checking all for failure - * and releasing the previous allocations if one fails - * - * Daniele Bellucci - 07/10/2003 - * - Audit copy_to_user in ioctl(SIOCGIWESSID) - * -=============================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* Warning : these stuff will slow down the driver... */ -#define WIRELESS_SPY /* Enable spying addresses */ -/* Definitions we need for spy */ -typedef struct iw_statistics iw_stats; -typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ - -#include "rayctl.h" -#include "ray_cs.h" - - -/** Prototypes based on PCMCIA skeleton driver *******************************/ -static int ray_config(struct pcmcia_device *link); -static void ray_release(struct pcmcia_device *link); -static void ray_detach(struct pcmcia_device *p_dev); - -/***** Prototypes indicated by device structure ******************************/ -static int ray_dev_close(struct net_device *dev); -static int ray_dev_config(struct net_device *dev, struct ifmap *map); -static struct net_device_stats *ray_get_stats(struct net_device *dev); -static int ray_dev_init(struct net_device *dev); - -static int ray_open(struct net_device *dev); -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void ray_update_multi_list(struct net_device *dev, int all); -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len); -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data); -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); -static iw_stats *ray_get_wireless_stats(struct net_device *dev); -static const struct iw_handler_def ray_handler_def; - -/***** Prototypes for raylink functions **************************************/ -static void authenticate(ray_dev_t *local); -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); -static void authenticate_timeout(struct timer_list *t); -static int get_free_ccs(ray_dev_t *local); -static int get_free_tx_ccs(ray_dev_t *local); -static void init_startup_params(ray_dev_t *local); -static int parse_addr(char *in_str, UCHAR *out); -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type); -static int ray_init(struct net_device *dev); -static int interrupt_ecf(ray_dev_t *local, int ccs); -static void ray_reset(struct net_device *dev); -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); -static void verify_dl_startup(struct timer_list *t); - -/* Prototypes for interrpt time functions **********************************/ -static irqreturn_t ray_interrupt(int reg, void *dev_id); -static void clear_interrupt(ray_dev_t *local); -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void associate(ray_dev_t *local); - -/* Card command functions */ -static int dl_startup_params(struct net_device *dev); -static void join_net(struct timer_list *t); -static void start_net(struct timer_list *t); - -/*===========================================================================*/ -/* Parameters that can be set with 'insmod' */ - -/* ADHOC=0, Infrastructure=1 */ -static int net_type = ADHOC; - -/* Hop dwell time in Kus (1024 us units defined by 802.11) */ -static int hop_dwell = 128; - -/* Beacon period in Kus */ -static int beacon_period = 256; - -/* power save mode (0 = off, 1 = save power) */ -static int psm; - -/* String for network's Extended Service Set ID. 32 Characters max */ -static char *essid; - -/* Default to encapsulation unless translation requested */ -static bool translate = true; - -static int country = USA; - -static int sniffer; - -static int bc; - -/* 48 bit physical card address if overriding card's real physical - * address is required. Since IEEE 802.11 addresses are 48 bits - * like ethernet, an int can't be used, so a string is used. To - * allow use of addresses starting with a decimal digit, the first - * character must be a letter and will be ignored. This letter is - * followed by up to 12 hex digits which are the address. If less - * than 12 digits are used, the address will be left filled with 0's. - * Note that bit 0 of the first byte is the broadcast bit, and evil - * things will happen if it is not 0 in a card address. - */ -static char *phy_addr = NULL; - -static unsigned int ray_mem_speed = 500; - -/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */ -static struct pcmcia_device *this_device = NULL; - -MODULE_AUTHOR("Corey Thomas "); -MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); -MODULE_LICENSE("GPL"); - -module_param(net_type, int, 0); -module_param(hop_dwell, int, 0); -module_param(beacon_period, int, 0); -module_param(psm, int, 0); -module_param(essid, charp, 0); -module_param(translate, bool, 0); -module_param(country, int, 0); -module_param(sniffer, int, 0); -module_param(bc, int, 0); -module_param(phy_addr, charp, 0); -module_param(ray_mem_speed, int, 0); - -static const UCHAR b5_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x00, 0x80, /* Hop time 128 Kus */ - 0x01, 0x00, /* Beacon period 256 Kus */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x32, /* Slot time */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x00, 0x3f, /* CW max */ - 0x00, 0x0f, /* CW min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* allow broadcast SSID probe resp */ - 0, 0, /* privacy must start, can join */ - 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ -}; - -static const UCHAR b4_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x02, 0x00, /* Hop time */ - 0x00, 0x01, /* Beacon period */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x4e, /* Slot time (TBD seems wrong) */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x3f, 0x0f, /* CW max, min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* rx/tx delay */ - 0, 0, 0, 0, 0, 0, /* current BSS id */ - 0 /* hop set */ -}; - -/*===========================================================================*/ -static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 }; - -static const char hop_pattern_length[] = { 1, - USA_HOP_MOD, EUROPE_HOP_MOD, - JAPAN_HOP_MOD, KOREA_HOP_MOD, - SPAIN_HOP_MOD, FRANCE_HOP_MOD, - ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, - JAPAN_TEST_HOP_MOD -}; - -static const char rcsid[] = - "Raylink/WebGear wireless LAN - Corey "; - -static const struct net_device_ops ray_netdev_ops = { - .ndo_init = ray_dev_init, - .ndo_open = ray_open, - .ndo_stop = ray_dev_close, - .ndo_start_xmit = ray_dev_start_xmit, - .ndo_set_config = ray_dev_config, - .ndo_get_stats = ray_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int ray_probe(struct pcmcia_device *p_dev) -{ - ray_dev_t *local; - struct net_device *dev; - int ret; - - dev_dbg(&p_dev->dev, "ray_attach()\n"); - - /* Allocate space for private device-specific data */ - dev = alloc_etherdev(sizeof(ray_dev_t)); - if (!dev) - return -ENOMEM; - - local = netdev_priv(dev); - local->finder = p_dev; - - /* The io structure describes IO port mapping. None used here */ - p_dev->resource[0]->end = 0; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - p_dev->priv = dev; - - local->finder = p_dev; - local->card_status = CARD_INSERTED; - local->authentication_state = UNAUTHENTICATED; - local->num_multi = 0; - dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", - p_dev, dev, local, &ray_interrupt); - - /* Raylink entries in the device structure */ - dev->netdev_ops = &ray_netdev_ops; - dev->wireless_handlers = &ray_handler_def; -#ifdef WIRELESS_SPY - local->wireless_data.spy_data = &local->spy_data; - dev->wireless_data = &local->wireless_data; -#endif /* WIRELESS_SPY */ - - - dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n"); - netif_stop_queue(dev); - - timer_setup(&local->timer, NULL, 0); - - this_device = p_dev; - ret = ray_config(p_dev); - if (ret) - goto err_free_dev; - - return 0; - -err_free_dev: - free_netdev(dev); - return ret; -} - -static void ray_detach(struct pcmcia_device *link) -{ - struct net_device *dev; - - dev_dbg(&link->dev, "ray_detach\n"); - - this_device = NULL; - dev = link->priv; - - ray_release(link); - - if (link->priv) { - unregister_netdev(dev); - free_netdev(dev); - } - dev_dbg(&link->dev, "ray_cs ray_detach ending\n"); -} /* ray_detach */ - -#define MAX_TUPLE_SIZE 128 -static int ray_config(struct pcmcia_device *link) -{ - int ret = 0; - int i; - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_config\n"); - - /* Determine card type and firmware version */ - printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n", - link->prod_id[0] ? link->prod_id[0] : " ", - link->prod_id[1] ? link->prod_id[1] : " ", - link->prod_id[2] ? link->prod_id[2] : " ", - link->prod_id[3] ? link->prod_id[3] : " "); - - /* Now allocate an interrupt line. Note that this does not - actually assign a handler to the interrupt. - */ - ret = pcmcia_request_irq(link, ray_interrupt); - if (ret) - goto failed; - dev->irq = link->irq; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - -/*** Set up 32k window for shared memory (transmit and control) ************/ - link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[2]->start = 0; - link->resource[2]->end = 0x8000; - ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[2], 0); - if (ret) - goto failed; - local->sram = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - if (!local->sram) - goto failed; - -/*** Set up 16k window for shared memory (receive buffer) ***************/ - link->resource[3]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[3]->start = 0; - link->resource[3]->end = 0x4000; - ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000); - if (ret) - goto failed; - local->rmem = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (!local->rmem) - goto failed; - -/*** Set up window for attribute memory ***********************************/ - link->resource[4]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[4]->start = 0; - link->resource[4]->end = 0x1000; - ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[4], 0); - if (ret) - goto failed; - local->amem = ioremap(link->resource[4]->start, - resource_size(link->resource[4])); - if (!local->amem) - goto failed; - - dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); - dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); - dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem); - if (ray_init(dev) < 0) { - ray_release(link); - return -ENODEV; - } - - SET_NETDEV_DEV(dev, &link->dev); - i = register_netdev(dev); - if (i != 0) { - printk("ray_config register_netdev() failed\n"); - ray_release(link); - return i; - } - - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", - dev->name, dev->irq, dev->dev_addr); - - return 0; - -failed: - ray_release(link); - return -ENODEV; -} /* ray_config */ - -static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) -{ - return dev->sram + CCS_BASE; -} - -static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) -{ - /* - * This looks nonsensical, since there is a separate - * RCS_BASE. But the difference between a "struct rcs" - * and a "struct ccs" ends up being in the _index_ off - * the base, so the base pointer is the same for both - * ccs/rcs. - */ - return dev->sram + CCS_BASE; -} - -/*===========================================================================*/ -static int ray_init(struct net_device *dev) -{ - int i; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_init(0x%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_init - device not present\n"); - return -1; - } - - local->net_type = net_type; - local->sta_type = TYPE_STA; - - /* Copy the startup results to local memory */ - memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE, - sizeof(struct startup_res_6)); - - /* Check Power up test status and get mac address from card */ - if (local->startup_res.startup_word != 0x80) { - printk(KERN_INFO "ray_init ERROR card status = %2x\n", - local->startup_res.startup_word); - local->card_status = CARD_INIT_ERROR; - return -1; - } - - local->fw_ver = local->startup_res.firmware_version[0]; - local->fw_bld = local->startup_res.firmware_version[1]; - local->fw_var = local->startup_res.firmware_version[2]; - dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver, - local->fw_bld); - - local->tib_length = 0x20; - if ((local->fw_ver == 5) && (local->fw_bld >= 30)) - local->tib_length = local->startup_res.tib_length; - dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length); - /* Initialize CCS's to buffer free state */ - pccs = ccs_base(local); - for (i = 0; i < NUMBER_OF_CCS; i++) { - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } - init_startup_params(local); - - /* copy mac address to startup parameters */ - if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) { - memcpy(&local->sparm.b4.a_mac_addr, - &local->startup_res.station_addr, ADDRLEN); - } - - clear_interrupt(local); /* Clear any interrupt from the card */ - local->card_status = CARD_AWAITING_PARAM; - dev_dbg(&link->dev, "ray_init ending\n"); - return 0; -} /* ray_init */ - -/*===========================================================================*/ -/* Download startup parameters to the card and command it to read them */ -static int dl_startup_params(struct net_device *dev) -{ - int ccsindex; - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "dl_startup_params entered\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n"); - return -1; - } - - /* Copy parameters to host to ECF area */ - if (local->fw_ver == 0x55) - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, - sizeof(struct b4_startup_params)); - else - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, - sizeof(struct b5_startup_params)); - - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return -1; - local->dl_param_ccs = ccsindex; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); - dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n", - local->dl_param_ccs); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - printk(KERN_INFO "ray dl_startup_params failed - " - "ECF not ready for intr\n"); - local->card_status = CARD_DL_PARAM_ERROR; - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -2; - } - local->card_status = CARD_DL_PARAM; - /* Start kernel timer to wait for dl startup to complete. */ - local->timer.expires = jiffies + HZ / 2; - local->timer.function = verify_dl_startup; - add_timer(&local->timer); - dev_dbg(&link->dev, - "ray_cs dl_startup_params started timer for verify_dl_startup\n"); - return 0; -} /* dl_startup_params */ - -/*===========================================================================*/ -static void init_startup_params(ray_dev_t *local) -{ - int i; - - if (country > JAPAN_TEST) - country = USA; - else if (country < USA) - country = USA; - /* structure for hop time and beacon period is defined here using - * New 802.11D6.1 format. Card firmware is still using old format - * until version 6. - * Before After - * a_hop_time ms byte a_hop_time ms byte - * a_hop_time 2s byte a_hop_time ls byte - * a_hop_time ls byte a_beacon_period ms byte - * a_beacon_period a_beacon_period ls byte - * - * a_hop_time = uS a_hop_time = KuS - * a_beacon_period = hops a_beacon_period = KuS - *//* 64ms = 010000 */ - if (local->fw_ver == 0x55) { - memcpy(&local->sparm.b4, b4_default_startup_parms, - sizeof(struct b4_startup_params)); - /* Translate sane kus input values to old build 4/5 format */ - /* i = hop time in uS truncated to 3 bytes */ - i = (hop_dwell * 1024) & 0xffffff; - local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; - local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; - local->sparm.b4.a_beacon_period[0] = 0; - local->sparm.b4.a_beacon_period[1] = - ((beacon_period / hop_dwell) - 1) & 0xff; - local->sparm.b4.a_curr_country_code = country; - local->sparm.b4.a_hop_pattern_length = - hop_pattern_length[(int)country] - 1; - if (bc) { - local->sparm.b4.a_ack_timeout = 0x50; - local->sparm.b4.a_sifs = 0x3f; - } - } else { /* Version 5 uses real kus values */ - memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms, - sizeof(struct b5_startup_params)); - - local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; - local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; - local->sparm.b5.a_beacon_period[0] = - (beacon_period >> 8) & 0xff; - local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; - if (psm) - local->sparm.b5.a_power_mgt_state = 1; - local->sparm.b5.a_curr_country_code = country; - local->sparm.b5.a_hop_pattern_length = - hop_pattern_length[(int)country]; - } - - local->sparm.b4.a_network_type = net_type & 0x01; - local->sparm.b4.a_acting_as_ap_status = TYPE_STA; - - if (essid != NULL) - strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); -} /* init_startup_params */ - -/*===========================================================================*/ -static void verify_dl_startup(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; - UCHAR status; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n"); - return; - } -#if 0 - { - int i; - printk(KERN_DEBUG - "verify_dl_startup parameters sent via ccs %d:\n", - local->dl_param_ccs); - for (i = 0; i < sizeof(struct b5_startup_params); i++) { - printk(" %2x", - (unsigned int)readb(local->sram + - HOST_TO_ECF_BASE + i)); - } - printk("\n"); - } -#endif - - status = readb(&pccs->buffer_status); - if (status != CCS_BUFFER_FREE) { - printk(KERN_INFO - "Download startup params failed. Status = %d\n", - status); - local->card_status = CARD_DL_PARAM_ERROR; - return; - } - if (local->sparm.b4.a_network_type == ADHOC) - start_net(&local->timer); - else - join_net(&local->timer); -} /* end verify_dl_startup */ - -/*===========================================================================*/ -/* Command card to start a network */ -static void start_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs start_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_START_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.start_network.update_param); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} /* end start_net */ - -/*===========================================================================*/ -/* Command card to join a network */ -static void join_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs join_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_JOIN_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.join_network.update_param); - writeb(0, &pccs->var.join_network.net_initiated); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} - - -static void ray_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_release\n"); - - del_timer_sync(&local->timer); - - if (local->sram) - iounmap(local->sram); - if (local->rmem) - iounmap(local->rmem); - if (local->amem) - iounmap(local->amem); - pcmcia_disable_device(link); - - dev_dbg(&link->dev, "ray_release ending\n"); -} - -static int ray_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int ray_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - ray_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*===========================================================================*/ -static int ray_dev_init(struct net_device *dev) -{ -#ifdef RAY_IMMEDIATE_INIT - int i; -#endif /* RAY_IMMEDIATE_INIT */ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_init - device not present\n"); - return -1; - } -#ifdef RAY_IMMEDIATE_INIT - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } -#else /* RAY_IMMEDIATE_INIT */ - /* Postpone the card init so that we can still configure the card, - * for example using the Wireless Extensions. The init will happen - * in ray_open() - Jean II */ - dev_dbg(&link->dev, - "ray_dev_init: postponing card init to ray_open() ; Status = %d\n", - local->card_status); -#endif /* RAY_IMMEDIATE_INIT */ - - /* copy mac and broadcast addresses to linux device */ - eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr); - eth_broadcast_addr(dev->broadcast); - - dev_dbg(&link->dev, "ray_dev_init ending\n"); - return 0; -} - -/*===========================================================================*/ -static int ray_dev_config(struct net_device *dev, struct ifmap *map) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - /* Dummy routine to satisfy device structure */ - dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_config - device not present\n"); - return -1; - } - - return 0; -} - -/*===========================================================================*/ -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - short length = skb->len; - - if (!pcmcia_dev_present(link)) { - dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); - if (local->authentication_state == NEED_TO_AUTH) { - dev_dbg(&link->dev, "ray_cs Sending authentication request.\n"); - if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { - local->authentication_state = AUTHENTICATED; - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - } - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - length = ETH_ZLEN; - } - switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { - case XMIT_NO_CCS: - case XMIT_NEED_AUTH: - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - case XMIT_NO_INTR: - case XMIT_MSG_BAD: - case XMIT_OK: - default: - dev_kfree_skb(skb); - } - - return NETDEV_TX_OK; -} /* ray_dev_start_xmit */ - -/*===========================================================================*/ -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, - UCHAR msg_type) -{ - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - int ccsindex; - int offset; - struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ - short int addr; /* Address of xmit buffer in card space */ - - pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev); - if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { - printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n", - len); - return XMIT_MSG_BAD; - } - switch (ccsindex = get_free_tx_ccs(local)) { - case ECCSBUSY: - pr_debug("ray_hw_xmit tx_ccs table busy\n"); - fallthrough; - case ECCSFULL: - pr_debug("ray_hw_xmit No free tx ccs\n"); - fallthrough; - case ECARDGONE: - netif_stop_queue(dev); - return XMIT_NO_CCS; - default: - break; - } - addr = TX_BUF_BASE + (ccsindex << 11); - - if (msg_type == DATA_TYPE) { - local->stats.tx_bytes += len; - local->stats.tx_packets++; - } - - ptx = local->sram + addr; - - ray_build_header(local, ptx, msg_type, data); - if (translate) { - offset = translate_frame(local, ptx, data, len); - } else { /* Encapsulate frame */ - /* TBD TIB length will move address of ptx->var */ - memcpy_toio(&ptx->var, data, len); - offset = 0; - } - - /* fill in the CCS */ - pccs = ccs_base(local) + ccsindex; - len += TX_HEADER_LENGTH + offset; - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); - writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); - writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); - writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); -/* TBD still need psm_cam? */ - writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); - writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); - writeb(0, &pccs->var.tx_request.antenna); - pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n", - local->net_default_tx_rate); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug("ray_hw_xmit failed - ECF not ready for intr\n"); -/* TBD very inefficient to copy packet to buffer, and then not - send it, but the alternative is to queue the messages and that - won't be done for a while. Maybe set tbusy until a CCS is free? -*/ - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - return XMIT_NO_INTR; - } - return XMIT_OK; -} /* end ray_hw_xmit */ - -/*===========================================================================*/ -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len) -{ - __be16 proto = ((struct ethhdr *)data)->h_proto; - if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */ - pr_debug("ray_cs translate_frame DIX II\n"); - /* Copy LLC header to card buffer */ - memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); - memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc), - (UCHAR *) &proto, 2); - if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { - /* This is the selective translation table, only 2 entries */ - writeb(0xf8, - &((struct snaphdr_t __iomem *)ptx->var)->org[2]); - } - /* Copy body of ethernet packet without ethernet header */ - memcpy_toio((void __iomem *)&ptx->var + - sizeof(struct snaphdr_t), data + ETH_HLEN, - len - ETH_HLEN); - return (int)sizeof(struct snaphdr_t) - ETH_HLEN; - } else { /* already 802 type, and proto is length */ - pr_debug("ray_cs translate_frame 802\n"); - if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ - pr_debug("ray_cs translate_frame evil IPX\n"); - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - /* TBD do other frame types */ -} /* end translate_frame */ - -/*===========================================================================*/ -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data) -{ - writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); -/*** IEEE 802.11 Address field assignments ************* - TODS FROMDS addr_1 addr_2 addr_3 addr_4 -Adhoc 0 0 dest src (terminal) BSSID N/A -AP to Terminal 0 1 dest AP(BSSID) source N/A -Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A -AP to AP 1 1 dest AP src AP dest source -*******************************************************/ - if (local->net_type == ADHOC) { - writeb(0, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, - ADDRLEN); - memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, - ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - } else { /* infrastructure */ - - if (local->sparm.b4.a_acting_as_ap_status) { - writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_source, ADDRLEN); - } else { /* Terminal */ - - writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, - ((struct ethhdr *)data)->h_source, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - } - } -} /* end encapsulate_frame */ - -/*====================================================================*/ - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int ray_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-FH"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int ray_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Setting by channel number */ - if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0)) - err = -EOPNOTSUPP; - else - local->sparm.b5.a_hop_pattern = wrqu->freq.m; - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int ray_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->freq.m = local->sparm.b5.a_hop_pattern; - wrqu->freq.e = 0; - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int ray_set_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if we asked for `any' */ - if (wrqu->essid.flags == 0) - /* Corey : can you do that ? */ - return -EOPNOTSUPP; - - /* Check the size of the string */ - if (wrqu->essid.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - /* Set the ESSID in the card */ - memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE); - memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int ray_get_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR tmp[IW_ESSID_MAX_SIZE + 1]; - - /* Get the essid that was set */ - memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - tmp[IW_ESSID_MAX_SIZE] = '\0'; - - /* Push it out ! */ - wrqu->essid.length = strlen(tmp); - wrqu->essid.flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int ray_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN); - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int ray_set_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if rate is in range */ - if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000)) - return -EINVAL; - - /* Hack for 1.5 Mb/s instead of 2 Mb/s */ - if ((local->fw_ver == 0x55) && /* Please check */ - (wrqu->bitrate.value == 2000000)) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = wrqu->bitrate.value / 500000; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int ray_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->net_default_tx_rate == 3) - wrqu->bitrate.value = 2000000; /* Hum... */ - else - wrqu->bitrate.value = local->net_default_tx_rate * 500000; - wrqu->bitrate.fixed = 0; /* We are in auto mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int ray_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int rthr = wrqu->rts.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.rts.fixed == 0) we should complain */ - if (wrqu->rts.disabled) - rthr = 32767; - else { - if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ - return -EINVAL; - } - local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; - local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int ray_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) - + local->sparm.b5.a_rts_threshold[1]; - wrqu->rts.disabled = (wrqu->rts.value == 32767); - wrqu->rts.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int ray_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int fthr = wrqu->frag.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.frag.fixed == 0) should complain */ - if (wrqu->frag.disabled) - fthr = 32767; - else { - if ((fthr < 256) || (fthr > 2347)) /* To check out ! */ - return -EINVAL; - } - local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; - local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int ray_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) - + local->sparm.b5.a_frag_threshold[1]; - wrqu->frag.disabled = (wrqu->frag.value == 32767); - wrqu->frag.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int ray_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - char card_mode = 1; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - switch (wrqu->mode) { - case IW_MODE_ADHOC: - card_mode = 0; - fallthrough; - case IW_MODE_INFRA: - local->sparm.b5.a_network_type = card_mode; - break; - default: - err = -EINVAL; - } - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int ray_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->sparm.b5.a_network_type) - wrqu->mode = IW_MODE_INFRA; - else - wrqu->mode = IW_MODE_ADHOC; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int ray_get_range(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - memset(range, 0, sizeof(struct iw_range)); - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct */ - range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */ - range->num_channels = hop_pattern_length[(int)country]; - range->num_frequency = 0; - range->max_qual.qual = 0; - range->max_qual.level = 255; /* What's the correct value ? */ - range->max_qual.noise = 255; /* Idem */ - range->num_bitrates = 2; - range->bitrate[0] = 1000000; /* 1 Mb/s */ - range->bitrate[1] = 2000000; /* 2 Mb/s */ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set framing mode - */ -static int ray_set_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - translate = !!*(extra); /* Set framing mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get framing mode - */ -static int ray_get_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = translate; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get country - */ -static int ray_get_country(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = country; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int ray_commit(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Stats handler : return Wireless Stats - */ -static iw_stats *ray_get_wireless_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - - local->wstats.status = local->card_status; -#ifdef WIRELESS_SPY - if ((local->spy_data.spy_number > 0) - && (local->sparm.b5.a_network_type == 0)) { - /* Get it from the first node in spy list */ - local->wstats.qual.qual = local->spy_data.spy_stat[0].qual; - local->wstats.qual.level = local->spy_data.spy_stat[0].level; - local->wstats.qual.noise = local->spy_data.spy_stat[0].noise; - local->wstats.qual.updated = - local->spy_data.spy_stat[0].updated; - } -#endif /* WIRELESS_SPY */ - - if (pcmcia_dev_present(link)) { - local->wstats.qual.noise = readb(&p->rxnoise); - local->wstats.qual.updated |= 4; - } - - return &local->wstats; -} /* end ray_get_wireless_stats */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler ray_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, ray_commit), - IW_HANDLER(SIOCGIWNAME, ray_get_name), - IW_HANDLER(SIOCSIWFREQ, ray_set_freq), - IW_HANDLER(SIOCGIWFREQ, ray_get_freq), - IW_HANDLER(SIOCSIWMODE, ray_set_mode), - IW_HANDLER(SIOCGIWMODE, ray_get_mode), - IW_HANDLER(SIOCGIWRANGE, ray_get_range), -#ifdef WIRELESS_SPY - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), -#endif /* WIRELESS_SPY */ - IW_HANDLER(SIOCGIWAP, ray_get_wap), - IW_HANDLER(SIOCSIWESSID, ray_set_essid), - IW_HANDLER(SIOCGIWESSID, ray_get_essid), - IW_HANDLER(SIOCSIWRATE, ray_set_rate), - IW_HANDLER(SIOCGIWRATE, ray_get_rate), - IW_HANDLER(SIOCSIWRTS, ray_set_rts), - IW_HANDLER(SIOCGIWRTS, ray_get_rts), - IW_HANDLER(SIOCSIWFRAG, ray_set_frag), - IW_HANDLER(SIOCGIWFRAG, ray_get_frag), -}; - -#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ -#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */ -#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ - -static const iw_handler ray_private_handler[] = { - [0] = ray_set_framing, - [1] = ray_get_framing, - [3] = ray_get_country, -}; - -static const struct iw_priv_args ray_private_args[] = { -/* cmd, set_args, get_args, name */ - {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, - "set_framing"}, - {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_framing"}, - {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_country"}, -}; - -static const struct iw_handler_def ray_handler_def = { - .num_standard = ARRAY_SIZE(ray_handler), - .num_private = ARRAY_SIZE(ray_private_handler), - .num_private_args = ARRAY_SIZE(ray_private_args), - .standard = ray_handler, - .private = ray_private_handler, - .private_args = ray_private_args, - .get_wireless_stats = ray_get_wireless_stats, -}; - -/*===========================================================================*/ -static int ray_open(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_open('%s')\n", dev->name); - - if (link->open == 0) - local->num_multi = 0; - link->open++; - - /* If the card is not started, time to start it ! - Jean II */ - if (local->card_status == CARD_AWAITING_PARAM) { - int i; - - dev_dbg(&link->dev, "ray_open: doing init now !\n"); - - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO - "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } - } - - if (sniffer) - netif_stop_queue(dev); - else - netif_start_queue(dev); - - dev_dbg(&link->dev, "ray_open ending\n"); - return 0; -} /* end ray_open */ - -/*===========================================================================*/ -static int ray_dev_close(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name); - - link->open--; - netif_stop_queue(dev); - - /* In here, we should stop the hardware (stop card from beeing active) - * and set local->card_status to CARD_AWAITING_PARAM, so that while the - * card is closed we can chage its configuration. - * Probably also need a COR reset to get sane state - Jean II */ - - return 0; -} /* end ray_dev_close */ - -/*===========================================================================*/ -static void ray_reset(struct net_device *dev) -{ - pr_debug("ray_reset entered\n"); -} - -/*===========================================================================*/ -/* Cause a firmware interrupt if it is ready for one */ -/* Return nonzero if not ready */ -static int interrupt_ecf(ray_dev_t *local, int ccs) -{ - int i = 50; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n"); - return -1; - } - dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs); - - while (i && - (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & - ECF_INTR_SET)) - i--; - if (i == 0) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n"); - return -1; - } - /* Fill the mailbox, then kick the card */ - writeb(ccs, local->sram + SCB_BASE); - writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); - return 0; -} /* interrupt_ecf */ - -/*===========================================================================*/ -/* Get next free transmit CCS */ -/* Return - index of current tx ccs */ -static int get_free_tx_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n"); - return ECARDGONE; - } - - if (test_and_set_bit(0, &local->tx_ccs_lock)) { - dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = 0; i < NUMBER_OF_TX_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->tx_ccs_lock = 0; - return i; - } - } - local->tx_ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_tx_ccs */ - -/*===========================================================================*/ -/* Get next free CCS */ -/* Return - index of current ccs */ -static int get_free_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n"); - return ECARDGONE; - } - if (test_and_set_bit(0, &local->ccs_lock)) { - dev_dbg(&link->dev, "ray_cs ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->ccs_lock = 0; - return i; - } - } - local->ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_ccs */ - -/*===========================================================================*/ -static void authenticate_timeout(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - del_timer(&local->timer); - printk(KERN_INFO "ray_cs Authentication with access point failed" - " - timeout\n"); - join_net(&local->timer); -} - -/*===========================================================================*/ -static int parse_addr(char *in_str, UCHAR *out) -{ - int i, k; - int len; - - if (in_str == NULL) - return 0; - len = strnlen(in_str, ADDRLEN * 2 + 1) - 1; - if (len < 1) - return 0; - memset(out, 0, ADDRLEN); - - i = 5; - - while (len > 0) { - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] = k; - else - return 0; - - if (len == 0) - break; - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] += k << 4; - else - return 0; - if (!i--) - break; - } - return 1; -} - -/*===========================================================================*/ -static struct net_device_stats *ray_get_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n"); - return &local->stats; - } - if (readb(&p->mrx_overflow_for_host)) { - local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow)); - writeb(0, &p->mrx_overflow); - writeb(0, &p->mrx_overflow_for_host); - } - if (readb(&p->mrx_checksum_error_for_host)) { - local->stats.rx_crc_errors += - swab16(readw(&p->mrx_checksum_error)); - writeb(0, &p->mrx_checksum_error); - writeb(0, &p->mrx_checksum_error_for_host); - } - if (readb(&p->rx_hec_error_for_host)) { - local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error)); - writeb(0, &p->rx_hec_error); - writeb(0, &p->rx_hec_error_for_host); - } - return &local->stats; -} - -/*===========================================================================*/ -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, - int len) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - int ccsindex; - int i; - struct ccs __iomem *pccs; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_parm - device not present\n"); - return; - } - - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_parm - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_PARAMS, &pccs->cmd); - writeb(objid, &pccs->var.update_param.object_id); - writeb(1, &pccs->var.update_param.number_objects); - writeb(0, &pccs->var.update_param.failure_cause); - for (i = 0; i < len; i++) { - writeb(value[i], local->sram + HOST_TO_ECF_BASE); - } - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} - -/*===========================================================================*/ -static void ray_update_multi_list(struct net_device *dev, int all) -{ - int ccsindex; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - void __iomem *p = local->sram + HOST_TO_ECF_BASE; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_multi_list - device not present\n"); - return; - } else - dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev); - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_multi - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); - - if (all) { - writeb(0xff, &pccs->var); - local->num_multi = 0xff; - } else { - struct netdev_hw_addr *ha; - int i = 0; - - /* Copy the kernel's list of MC addresses to card */ - netdev_for_each_mc_addr(ha, dev) { - memcpy_toio(p, ha->addr, ETH_ALEN); - dev_dbg(&link->dev, "ray_update_multi add addr %pm\n", - ha->addr); - p += ETH_ALEN; - i++; - } - if (i > 256 / ADDRLEN) - i = 256 / ADDRLEN; - writeb((UCHAR) i, &pccs->var); - dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i); - /* Interrupt the firmware to process the command */ - local->num_multi = i; - } - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, - "ray_cs update_multi failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} /* end ray_update_multi_list */ - -/*===========================================================================*/ -static void set_multicast_list(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR promisc; - - pr_debug("ray_cs set_multicast_list(%p)\n", dev); - - if (dev->flags & IFF_PROMISC) { - if (local->sparm.b5.a_promiscuous_mode == 0) { - pr_debug("ray_cs set_multicast_list promisc on\n"); - local->sparm.b5.a_promiscuous_mode = 1; - promisc = 1; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } else { - if (local->sparm.b5.a_promiscuous_mode == 1) { - pr_debug("ray_cs set_multicast_list promisc off\n"); - local->sparm.b5.a_promiscuous_mode = 0; - promisc = 0; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } - - if (dev->flags & IFF_ALLMULTI) - ray_update_multi_list(dev, 1); - else { - if (local->num_multi != netdev_mc_count(dev)) - ray_update_multi_list(dev, 0); - } -} /* end set_multicast_list */ - -/*============================================================================= - * All routines below here are run at interrupt time. -=============================================================================*/ -static irqreturn_t ray_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct pcmcia_device *link; - ray_dev_t *local; - struct ccs __iomem *pccs; - struct rcs __iomem *prcs; - UCHAR rcsindex; - UCHAR tmp; - UCHAR cmd; - UCHAR status; - UCHAR memtmp[ESSID_SIZE + 1]; - - - if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ - return IRQ_NONE; - - pr_debug("ray_cs: interrupt for *dev=%p\n", dev); - - local = netdev_priv(dev); - link = local->finder; - if (!pcmcia_dev_present(link)) { - pr_debug( - "ray_cs interrupt from device not present or suspended.\n"); - return IRQ_NONE; - } - rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); - - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); - clear_interrupt(local); - return IRQ_HANDLED; - } - if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */ - pccs = ccs_base(local) + rcsindex; - cmd = readb(&pccs->cmd); - status = readb(&pccs->buffer_status); - switch (cmd) { - case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ - del_timer(&local->timer); - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters OK\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters fail\n"); - } - break; - case CCS_UPDATE_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt update params done\n"); - if (status != CCS_COMMAND_COMPLETE) { - tmp = - readb(&pccs->var.update_param. - failure_cause); - dev_dbg(&link->dev, - "ray_cs interrupt update params failed - reason %d\n", - tmp); - } - break; - case CCS_REPORT_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt report params done\n"); - break; - case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ - dev_dbg(&link->dev, - "ray_cs interrupt CCS Update Multicast List done\n"); - break; - case CCS_UPDATE_POWER_SAVINGS_MODE: - dev_dbg(&link->dev, - "ray_cs interrupt update power save mode done\n"); - break; - case CCS_START_NETWORK: - case CCS_JOIN_NETWORK: - memcpy(memtmp, local->sparm.b4.a_current_ess_id, - ESSID_SIZE); - memtmp[ESSID_SIZE] = '\0'; - - if (status == CCS_COMMAND_COMPLETE) { - if (readb - (&pccs->var.start_network.net_initiated) == - 1) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" started\n", - memtmp); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" joined\n", - memtmp); - } - memcpy_fromio(&local->bss_id, - pccs->var.start_network.bssid, - ADDRLEN); - - if (local->fw_ver == 0x55) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = - readb(&pccs->var.start_network. - net_default_tx_rate); - local->encryption = - readb(&pccs->var.start_network.encryption); - if (!sniffer && (local->net_type == INFRA) - && !(local->sparm.b4.a_acting_as_ap_status)) { - authenticate(local); - } - local->card_status = CARD_ACQ_COMPLETE; - } else { - local->card_status = CARD_ACQ_FAILED; - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 5; - if (status == CCS_START_NETWORK) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" start failed\n", - memtmp); - local->timer.function = start_net; - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" join failed\n", - memtmp); - local->timer.function = join_net; - } - add_timer(&local->timer); - } - break; - case CCS_START_ASSOCIATION: - if (status == CCS_COMMAND_COMPLETE) { - local->card_status = CARD_ASSOC_COMPLETE; - dev_dbg(&link->dev, "ray_cs association successful\n"); - } else { - dev_dbg(&link->dev, "ray_cs association failed,\n"); - local->card_status = CARD_ASSOC_FAILED; - join_net(&local->timer); - } - break; - case CCS_TX_REQUEST: - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt tx request complete\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt tx request failed\n"); - } - if (!sniffer) - netif_start_queue(dev); - netif_wake_queue(dev); - break; - case CCS_TEST_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt mem test done\n"); - break; - case CCS_SHUTDOWN: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS returned - Shutdown\n"); - break; - case CCS_DUMP_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n"); - break; - case CCS_START_TIMER: - dev_dbg(&link->dev, - "ray_cs interrupt DING - raylink timer expired\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n", - rcsindex, cmd); - } - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - } else { /* It's an RCS */ - - prcs = rcs_base(local) + rcsindex; - - switch (readb(&prcs->interrupt_id)) { - case PROCESS_RX_PACKET: - ray_rx(dev, local, prcs); - break; - case REJOIN_NET_COMPLETE: - dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n"); - local->card_status = CARD_ACQ_COMPLETE; - /* do we need to clear tx buffers CCS's? */ - if (local->sparm.b4.a_network_type == ADHOC) { - if (!sniffer) - netif_start_queue(dev); - } else { - memcpy_fromio(&local->bss_id, - prcs->var.rejoin_net_complete. - bssid, ADDRLEN); - dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n", - local->bss_id); - if (!sniffer) - authenticate(local); - } - break; - case ROAMING_INITIATED: - dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n"); - netif_stop_queue(dev); - local->card_status = CARD_DOING_ACQ; - break; - case JAPAN_CALL_SIGN_RXD: - dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n", - rcsindex, - (unsigned int)readb(&prcs->interrupt_id)); - break; - } - writeb(CCS_BUFFER_FREE, &prcs->buffer_status); - } - clear_interrupt(local); - return IRQ_HANDLED; -} /* ray_interrupt */ - -/*===========================================================================*/ -static void ray_rx(struct net_device *dev, ray_dev_t *local, - struct rcs __iomem *prcs) -{ - int rx_len; - unsigned int pkt_addr; - void __iomem *pmsg; - pr_debug("ray_rx process rx packet\n"); - - /* Calculate address of packet within Rx buffer */ - pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; - /* Length of first packet fragment */ - rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_length[1]); - - local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev); - pmsg = local->rmem + pkt_addr; - switch (readb(pmsg)) { - case DATA_TYPE: - pr_debug("ray_rx data type\n"); - rx_data(dev, prcs, pkt_addr, rx_len); - break; - case AUTHENTIC_TYPE: - pr_debug("ray_rx authentic type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_authenticate(local, prcs, pkt_addr, rx_len); - break; - case DEAUTHENTIC_TYPE: - pr_debug("ray_rx deauth type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_deauthenticate(local, prcs, pkt_addr, rx_len); - break; - case NULL_MSG_TYPE: - pr_debug("ray_cs rx NULL msg\n"); - break; - case BEACON_TYPE: - pr_debug("ray_rx beacon type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - - copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr, - rx_len < sizeof(struct beacon_rx) ? - rx_len : sizeof(struct beacon_rx)); - - local->beacon_rxed = 1; - /* Get the statistics so the card counters never overflow */ - ray_get_stats(dev); - break; - default: - pr_debug("ray_cs unknown pkt type %2x\n", - (unsigned int)readb(pmsg)); - break; - } - -} /* end ray_rx */ - -/*===========================================================================*/ -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - struct sk_buff *skb = NULL; - struct rcs __iomem *prcslink = prcs; - ray_dev_t *local = netdev_priv(dev); - UCHAR *rx_ptr; - int total_len; - int tmp; -#ifdef WIRELESS_SPY - int siglev = local->last_rsl; - u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ -#endif - - if (!sniffer) { - if (translate) { -/* TBD length needs fixing for translated header */ - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } else { /* encapsulated ethernet */ - - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } - } - pr_debug("ray_cs rx_data packet\n"); - /* If fragmented packet, verify sizes of fragments add up */ - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - pr_debug("ray_cs rx'ed fragment\n"); - tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) - + readb(&prcs->var.rx_packet.totalpacketlength[1]); - total_len = tmp; - prcslink = prcs; - do { - tmp -= - (readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + readb(&prcslink->var.rx_packet.rx_data_length[1]); - if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) - == 0xFF || tmp < 0) - break; - prcslink = rcs_base(local) - + readb(&prcslink->link_field); - } while (1); - - if (tmp < 0) { - pr_debug( - "ray_cs rx_data fragment lengths don't add up\n"); - local->stats.rx_dropped++; - release_frag_chain(local, prcs); - return; - } - } else { /* Single unfragmented packet */ - total_len = rx_len; - } - - skb = dev_alloc_skb(total_len + 5); - if (skb == NULL) { - pr_debug("ray_cs rx_data could not allocate skb\n"); - local->stats.rx_dropped++; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) - release_frag_chain(local, prcs); - return; - } - skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */ - - pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len, - rx_len); - -/************************/ - /* Reserve enough room for the whole damn packet. */ - rx_ptr = skb_put(skb, total_len); - /* Copy the whole packet to sk_buff */ - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); - /* Get source address */ -#ifdef WIRELESS_SPY - skb_copy_from_linear_data_offset(skb, - offsetof(struct mac_header, addr_2), - linksrcaddr, ETH_ALEN); -#endif - /* Now, deal with encapsulation/translation/sniffer */ - if (!sniffer) { - if (!translate) { - /* Encapsulated ethernet, so just lop off 802.11 MAC header */ -/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ - skb_pull(skb, RX_MAC_HEADER_LENGTH); - } else { - /* Do translation */ - untranslate(local, skb, total_len); - } - } else { /* sniffer mode, so just pass whole packet */ - } - -/************************/ - /* Now pick up the rest of the fragments if any */ - tmp = 17; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - prcslink = prcs; - pr_debug("ray_cs rx_data in fragment loop\n"); - do { - prcslink = rcs_base(local) - + - readb(&prcslink->var.rx_packet.next_frag_rcs_index); - rx_len = - ((readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + - readb(&prcslink->var.rx_packet.rx_data_length[1])) - & RX_BUFF_END; - pkt_addr = - ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << - 8) - + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) - & RX_BUFF_END; - - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); - - } while (tmp-- && - readb(&prcslink->var.rx_packet.next_frag_rcs_index) != - 0xFF); - release_frag_chain(local, prcs); - } - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - local->stats.rx_packets++; - local->stats.rx_bytes += total_len; - - /* Gather signal strength per address */ -#ifdef WIRELESS_SPY - /* For the Access Point or the node having started the ad-hoc net - * note : ad-hoc work only in some specific configurations, but we - * kludge in ray_get_wireless_stats... */ - if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) { - /* Update statistics */ - /*local->wstats.qual.qual = none ? */ - local->wstats.qual.level = siglev; - /*local->wstats.qual.noise = none ? */ - local->wstats.qual.updated = 0x2; - } - /* Now, update the spy stuff */ - { - struct iw_quality wstats; - wstats.level = siglev; - /* wstats.noise = none ? */ - /* wstats.qual = none ? */ - wstats.updated = 0x2; - /* Update spy records */ - wireless_spy_update(dev, linksrcaddr, &wstats); - } -#endif /* WIRELESS_SPY */ -} /* end rx_data */ - -/*===========================================================================*/ -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) -{ - snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH); - struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data; - __be16 type = *(__be16 *) psnap->ethertype; - int delta; - struct ethhdr *peth; - UCHAR srcaddr[ADDRLEN]; - UCHAR destaddr[ADDRLEN]; - static const UCHAR org_bridge[3] = { 0, 0, 0xf8 }; - static const UCHAR org_1042[3] = { 0, 0, 0 }; - - memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); - memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); - -#if 0 - if { - print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ", - DUMP_PREFIX_NONE, 16, 1, - skb->data, 64, true); - printk(KERN_DEBUG - "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n", - ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl, - psnap->org[0], psnap->org[1], psnap->org[2]); - printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data); - } -#endif - - if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { - /* not a snap type so leave it alone */ - pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n", - psnap->dsap, psnap->ssap, psnap->ctrl); - - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); - } else { /* Its a SNAP */ - if (memcmp(psnap->org, org_bridge, 3) == 0) { - /* EtherII and nuke the LLC */ - pr_debug("ray_cs untranslate Bridge encap\n"); - delta = RX_MAC_HEADER_LENGTH - + sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } else if (memcmp(psnap->org, org_1042, 3) == 0) { - switch (ntohs(type)) { - case ETH_P_IPX: - case ETH_P_AARP: - pr_debug("ray_cs untranslate RFC IPX/AARP\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = - htons(len - RX_MAC_HEADER_LENGTH); - break; - default: - pr_debug("ray_cs untranslate RFC default\n"); - delta = RX_MAC_HEADER_LENGTH + - sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - break; - } - } else { - printk("ray_cs untranslate very confused by packet\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } - } -/* TBD reserve skb_reserve(skb, delta); */ - skb_pull(skb, delta); - pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta, - skb->data); - memcpy(peth->h_dest, destaddr, ADDRLEN); - memcpy(peth->h_source, srcaddr, ADDRLEN); -#if 0 - { - int i; - printk(KERN_DEBUG "skb->data after untranslate:"); - for (i = 0; i < 64; i++) - printk("%02x ", skb->data[i]); - printk("\n"); - } -#endif -} /* end untranslate */ - -/*===========================================================================*/ -/* Copy data from circular receive buffer to PC memory. - * dest = destination address in PC memory - * pkt_addr = source address in receive buffer - * len = length of packet to copy - */ -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, - int length) -{ - int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); - if (wrap_bytes <= 0) { - memcpy_fromio(dest, local->rmem + pkt_addr, length); - } else { /* Packet wrapped in circular buffer */ - - memcpy_fromio(dest, local->rmem + pkt_addr, - length - wrap_bytes); - memcpy_fromio(dest + length - wrap_bytes, local->rmem, - wrap_bytes); - } - return length; -} - -/*===========================================================================*/ -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs) -{ - struct rcs __iomem *prcslink = prcs; - int tmp = 17; - unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); - - while (tmp--) { - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n", - rcsindex); - break; - } - prcslink = rcs_base(local) + rcsindex; - rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); - } - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); -} - -/*===========================================================================*/ -static void authenticate(ray_dev_t *local) -{ - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_cs Starting authentication.\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs authenticate - device not present\n"); - return; - } - - del_timer(&local->timer); - if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { - local->timer.function = join_net; - } else { - local->timer.function = authenticate_timeout; - } - local->timer.expires = jiffies + HZ * 2; - add_timer(&local->timer); - local->authentication_state = AWAITING_RESPONSE; -} /* end authenticate */ - -/*===========================================================================*/ -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; - - del_timer(&local->timer); - - copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - /* if we are trying to get authenticated */ - if (local->sparm.b4.a_network_type == ADHOC) { - pr_debug("ray_cs rx_auth var= %6ph\n", msg->var); - if (msg->var[2] == 1) { - pr_debug("ray_cs Sending authentication response.\n"); - if (!build_auth_frame - (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { - local->authentication_state = NEED_TO_AUTH; - memcpy(local->auth_id, msg->mac.addr_2, - ADDRLEN); - } - } - } else { /* Infrastructure network */ - - if (local->authentication_state == AWAITING_RESPONSE) { - /* Verify authentication sequence #2 and success */ - if (msg->var[2] == 2) { - if ((msg->var[3] | msg->var[4]) == 0) { - pr_debug("Authentication successful\n"); - local->card_status = CARD_AUTH_COMPLETE; - associate(local); - local->authentication_state = - AUTHENTICATED; - } else { - pr_debug("Authentication refused\n"); - local->card_status = CARD_AUTH_REFUSED; - join_net(&local->timer); - local->authentication_state = - UNAUTHENTICATED; - } - } - } - } - -} /* end rx_authenticate */ - -/*===========================================================================*/ -static void associate(ray_dev_t *local) -{ - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - struct net_device *dev = link->priv; - int ccsindex; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs associate - device not present\n"); - return; - } - /* If no tx buffers available, return */ - if ((ccsindex = get_free_ccs(local)) < 0) { -/* TBD should never be here but... what if we are? */ - dev_dbg(&link->dev, "ray_cs associate - No free ccs\n"); - return; - } - dev_dbg(&link->dev, "ray_cs Starting association with access point\n"); - pccs = ccs_base(local) + ccsindex; - /* fill in the CCS */ - writeb(CCS_START_ASSOCIATION, &pccs->cmd); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 2; - local->timer.function = join_net; - add_timer(&local->timer); - local->card_status = CARD_ASSOC_FAILED; - return; - } - if (!sniffer) - netif_start_queue(dev); - -} /* end associate */ - -/*===========================================================================*/ -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ -/* UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; -*/ - pr_debug("Deauthentication frame received\n"); - local->authentication_state = UNAUTHENTICATED; - /* Need to reauthenticate or rejoin depending on reason code */ -/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - */ -} - -/*===========================================================================*/ -static void clear_interrupt(ray_dev_t *local) -{ - writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); -} - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -#define MAXDATA (PAGE_SIZE - 80) - -static const char *card_status[] = { - "Card inserted - uninitialized", /* 0 */ - "Card not downloaded", /* 1 */ - "Waiting for download parameters", /* 2 */ - "Card doing acquisition", /* 3 */ - "Acquisition complete", /* 4 */ - "Authentication complete", /* 5 */ - "Association complete", /* 6 */ - "???", "???", "???", "???", /* 7 8 9 10 undefined */ - "Card init error", /* 11 */ - "Download parameters error", /* 12 */ - "???", /* 13 */ - "Acquisition failed", /* 14 */ - "Authentication refused", /* 15 */ - "Association failed" /* 16 */ -}; - -static const char *nettype[] = { "Adhoc", "Infra " }; -static const char *framing[] = { "Encapsulation", "Translation" } - -; -/*===========================================================================*/ -static int ray_cs_proc_show(struct seq_file *m, void *v) -{ -/* Print current values which are not available via other means - * eg ifconfig - */ - int i; - struct pcmcia_device *link; - struct net_device *dev; - ray_dev_t *local; - UCHAR *p; - struct freq_hop_element *pfh; - UCHAR c[33]; - - link = this_device; - if (!link) - return 0; - dev = link->priv; - if (!dev) - return 0; - local = netdev_priv(dev); - if (!local) - return 0; - - seq_puts(m, "Raylink Wireless LAN driver status\n"); - seq_printf(m, "%s\n", rcsid); - /* build 4 does not report version, and field is 0x55 after memtest */ - seq_puts(m, "Firmware version = "); - if (local->fw_ver == 0x55) - seq_puts(m, "4 - Use dump_cis for more details\n"); - else - seq_printf(m, "%2d.%02d.%02d\n", - local->fw_ver, local->fw_bld, local->fw_var); - - for (i = 0; i < 32; i++) - c[i] = local->sparm.b5.a_current_ess_id[i]; - c[32] = 0; - seq_printf(m, "%s network ESSID = \"%s\"\n", - nettype[local->sparm.b5.a_network_type], c); - - p = local->bss_id; - seq_printf(m, "BSSID = %pM\n", p); - - seq_printf(m, "Country code = %d\n", - local->sparm.b5.a_curr_country_code); - - i = local->card_status; - if (i < 0) - i = 10; - if (i > 16) - i = 10; - seq_printf(m, "Card status = %s\n", card_status[i]); - - seq_printf(m, "Framing mode = %s\n", framing[translate]); - - seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl); - - if (local->beacon_rxed) { - /* Pull some fields out of last beacon received */ - seq_printf(m, "Beacon Interval = %d Kus\n", - local->last_bcn.beacon_intvl[0] - + 256 * local->last_bcn.beacon_intvl[1]); - - p = local->last_bcn.elements; - if (p[0] == C_ESSID_ELEMENT_ID) - p += p[1] + 2; - else { - seq_printf(m, - "Parse beacon failed at essid element id = %d\n", - p[0]); - return 0; - } - - if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { - seq_puts(m, "Supported rate codes = "); - for (i = 2; i < p[1] + 2; i++) - seq_printf(m, "0x%02x ", p[i]); - seq_putc(m, '\n'); - p += p[1] + 2; - } else { - seq_puts(m, "Parse beacon failed at rates element\n"); - return 0; - } - - if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) { - pfh = (struct freq_hop_element *)p; - seq_printf(m, "Hop dwell = %d Kus\n", - pfh->dwell_time[0] + - 256 * pfh->dwell_time[1]); - seq_printf(m, "Hop set = %d\n", - pfh->hop_set); - seq_printf(m, "Hop pattern = %d\n", - pfh->hop_pattern); - seq_printf(m, "Hop index = %d\n", - pfh->hop_index); - p += p[1] + 2; - } else { - seq_puts(m, - "Parse beacon failed at FH param element\n"); - return 0; - } - } else { - seq_puts(m, "No beacons received\n"); - } - return 0; -} -#endif -/*===========================================================================*/ -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) -{ - int addr; - struct ccs __iomem *pccs; - struct tx_msg __iomem *ptx; - int ccsindex; - - /* If no tx buffers available, return */ - if ((ccsindex = get_free_tx_ccs(local)) < 0) { - pr_debug("ray_cs send authenticate - No free tx ccs\n"); - return -1; - } - - pccs = ccs_base(local) + ccsindex; - - /* Address in card space */ - addr = TX_BUF_BASE + (ccsindex << 11); - /* fill in the CCS */ - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); - writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); - writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); - writeb(TX_AUTHENTICATE_LENGTH_LSB, - pccs->var.tx_request.tx_data_length + 1); - writeb(0, &pccs->var.tx_request.pow_sav_mode); - - ptx = local->sram + addr; - /* fill in the mac header */ - writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); - writeb(0, &ptx->mac.frame_ctl_2); - - memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - - /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ - memset_io(ptx->var, 0, 6); - writeb(auth_type & 0xff, ptx->var + 2); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug( - "ray_cs send authentication request failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -1; - } - return 0; -} /* End build_auth_frame */ - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -static ssize_t ray_cs_essid_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - static char proc_essid[33]; - unsigned int len = count; - - if (len > 32) - len = 32; - memset(proc_essid, 0, 33); - if (copy_from_user(proc_essid, buffer, len)) - return -EFAULT; - essid = proc_essid; - return count; -} - -static const struct proc_ops ray_cs_essid_proc_ops = { - .proc_write = ray_cs_essid_proc_write, - .proc_lseek = noop_llseek, -}; - -static ssize_t int_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - static char proc_number[10]; - char *p; - int nr, len; - - if (!count) - return 0; - - if (count > 9) - return -EINVAL; - if (copy_from_user(proc_number, buffer, count)) - return -EFAULT; - p = proc_number; - nr = 0; - len = count; - do { - unsigned int c = *p - '0'; - if (c > 9) - return -EINVAL; - nr = nr * 10 + c; - p++; - } while (--len); - *(int *)pde_data(file_inode(file)) = nr; - return count; -} - -static const struct proc_ops int_proc_ops = { - .proc_write = int_proc_write, - .proc_lseek = noop_llseek, -}; -#endif - -static const struct pcmcia_device_id ray_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000), - PCMCIA_DEVICE_NULL, -}; - -MODULE_DEVICE_TABLE(pcmcia, ray_ids); - -static struct pcmcia_driver ray_driver = { - .owner = THIS_MODULE, - .name = "ray_cs", - .probe = ray_probe, - .remove = ray_detach, - .id_table = ray_ids, - .suspend = ray_suspend, - .resume = ray_resume, -}; - -static int __init init_ray_cs(void) -{ - int rc; - - pr_debug("%s\n", rcsid); - rc = pcmcia_register_driver(&ray_driver); - pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n", - rc); - if (rc) - return rc; - -#ifdef CONFIG_PROC_FS - proc_mkdir("driver/ray_cs", NULL); - - proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show); - proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops); - proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops, - &net_type); - proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops, - &translate); -#endif - translate = !!translate; - return 0; -} /* init_ray_cs */ - -/*===========================================================================*/ - -static void __exit exit_ray_cs(void) -{ - pr_debug("ray_cs: cleanup_module\n"); - -#ifdef CONFIG_PROC_FS - remove_proc_subtree("driver/ray_cs", NULL); -#endif - - pcmcia_unregister_driver(&ray_driver); -} /* exit_ray_cs */ - -module_init(init_ray_cs); -module_exit(exit_ray_cs); - -/*===========================================================================*/ diff --git a/drivers/net/wireless/legacy/ray_cs.h b/drivers/net/wireless/legacy/ray_cs.h deleted file mode 100644 index 0609d8625019..000000000000 --- a/drivers/net/wireless/legacy/ray_cs.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Raytheon wireless LAN PCMCIA card driver for Linux - A PCMCIA client driver for the Raylink wireless network card - Written by Corey Thomas -*/ - -#ifndef _RAY_CS_H_ -#define _RAY_CS_H_ - -struct beacon_rx { - struct mac_header mac; - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; - -/* Return values for get_free{,_tx}_ccs */ -#define ECCSFULL (-1) -#define ECCSBUSY (-2) -#define ECARDGONE (-3) - -typedef struct ray_dev_t { - int card_status; - int authentication_state; - void __iomem *sram; /* pointer to beginning of shared RAM */ - void __iomem *amem; /* pointer to attribute mem window */ - void __iomem *rmem; /* pointer to receive buffer window */ - struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */ - struct timer_list timer; - unsigned long tx_ccs_lock; - unsigned long ccs_lock; - int dl_param_ccs; - union { - struct b4_startup_params b4; - struct b5_startup_params b5; - } sparm; - int timeout_flag; - UCHAR supported_rates[8]; - UCHAR japan_call_sign[12]; - struct startup_res_6 startup_res; - int num_multi; - /* Network parameters from start/join */ - UCHAR bss_id[6]; - UCHAR auth_id[6]; - UCHAR net_default_tx_rate; - UCHAR encryption; - struct net_device_stats stats; - - UCHAR net_type; - UCHAR sta_type; - UCHAR fw_ver; - UCHAR fw_bld; - UCHAR fw_var; - UCHAR ASIC_version; - UCHAR assoc_id[2]; - UCHAR tib_length; - UCHAR last_rsl; - int beacon_rxed; - struct beacon_rx last_bcn; - iw_stats wstats; /* Wireless specific stats */ -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; -#endif /* WIRELESS_SPY */ - -} ray_dev_t; -/*****************************************************************************/ - -#endif /* _RAY_CS_H_ */ diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h deleted file mode 100644 index 1f3bde8ac73d..000000000000 --- a/drivers/net/wireless/legacy/rayctl.h +++ /dev/null @@ -1,734 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _RAYCTL_H_ -#define _RAYCTL_H_ - -typedef unsigned char UCHAR; - -/****** IEEE 802.11 constants ************************************************/ -#define ADDRLEN 6 -/* Frame control 1 bit fields */ -#define PROTOCOL_VER 0x00 -#define DATA_TYPE 0x08 -#define ASSOC_REQ_TYPE 0x00 -#define ASSOC_RESP_TYPE 0x10 -#define REASSOC_REQ_TYPE 0x20 -#define REASSOC_RESP_TYPE 0x30 -#define NULL_MSG_TYPE 0x48 -#define BEACON_TYPE 0x80 -#define DISASSOC_TYPE 0xA0 -#define PSPOLL_TYPE 0xA4 -#define AUTHENTIC_TYPE 0xB0 -#define DEAUTHENTIC_TYPE 0xC0 -/* Frame control 2 bit fields */ -#define FC2_TO_DS 0x01 -#define FC2_FROM_DS 0x02 -#define FC2_MORE_FRAG 0x04 -#define FC2_RETRY 0x08 -#define FC2_PSM 0x10 -#define FC2_MORE_DATA 0x20 -#define FC2_WEP 0x40 -#define FC2_ORDER 0x80 -/*****************************************************************************/ -/* 802.11 element ID's and lengths */ -#define C_BP_CAPABILITY_ESS 0x01 -#define C_BP_CAPABILITY_IBSS 0x02 -#define C_BP_CAPABILITY_CF_POLLABLE 0x04 -#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08 -#define C_BP_CAPABILITY_PRIVACY 0x10 - -#define C_ESSID_ELEMENT_ID 0 -#define C_ESSID_ELEMENT_MAX_LENGTH 32 - -#define C_SUPPORTED_RATES_ELEMENT_ID 1 -#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2 - -#define C_FH_PARAM_SET_ELEMENT_ID 2 -#define C_FH_PARAM_SET_ELEMENT_LNGTH 5 - -#define C_CF_PARAM_SET_ELEMENT_ID 4 -#define C_CF_PARAM_SET_ELEMENT_LNGTH 6 - -#define C_TIM_ELEMENT_ID 5 -#define C_TIM_BITMAP_LENGTH 251 -#define C_TIM_BMCAST_BIT 0x01 - -#define C_IBSS_ELEMENT_ID 6 -#define C_IBSS_ELEMENT_LENGTH 2 - -#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51 -#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12 - -#define C_DISASSOC_REASON_CODE_LEN 2 -#define C_DISASSOC_REASON_CODE_DEFAULT 8 - -#define C_CRC_LEN 4 -#define C_NUM_SUPPORTED_RATES 8 -/****** IEEE 802.11 mac header for type data packets *************************/ -struct mac_header { - UCHAR frame_ctl_1; - UCHAR frame_ctl_2; - UCHAR duration_lsb; - UCHAR duration_msb; - UCHAR addr_1[ADDRLEN]; - UCHAR addr_2[ADDRLEN]; - UCHAR addr_3[ADDRLEN]; - UCHAR seq_frag_num[2]; -/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */ -}; -/****** IEEE 802.11 frame element structures *********************************/ -struct essid_element -{ - UCHAR id; - UCHAR length; - UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH]; -}; -struct rates_element -{ - UCHAR id; - UCHAR length; - UCHAR value[8]; -}; -struct freq_hop_element -{ - UCHAR id; - UCHAR length; - UCHAR dwell_time[2]; - UCHAR hop_set; - UCHAR hop_pattern; - UCHAR hop_index; -}; -struct tim_element -{ - UCHAR id; - UCHAR length; - UCHAR dtim_count; - UCHAR dtim_period; - UCHAR bitmap_control; - UCHAR tim[C_TIM_BITMAP_LENGTH]; -}; -struct ibss_element -{ - UCHAR id; - UCHAR length; - UCHAR atim_window[2]; -}; -struct japan_call_sign_element -{ - UCHAR id; - UCHAR length; - UCHAR call_sign[12]; -}; -/****** Beacon message structures ********************************************/ -/* .elements is a large lump of max size because elements are variable size */ -struct infra_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; -struct adhoc_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct ibss_element)]; -}; -/*****************************************************************************/ -/*****************************************************************************/ -/* #define C_MAC_HDR_2_WEP 0x40 */ -/* TX/RX CCS constants */ -#define TX_HEADER_LENGTH 0x1C -#define RX_MAC_HEADER_LENGTH 0x18 -#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) -#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2) -#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define FCS_LEN 4 - -#define ADHOC 0 -#define INFRA 1 - -#define TYPE_STA 0 -#define TYPE_AP 1 - -#define PASSIVE_SCAN 1 -#define ACTIVE_SCAN 1 - -#define PSM_CAM 0 - -/* Country codes */ -#define USA 1 -#define EUROPE 2 -#define JAPAN 3 -#define KOREA 4 -#define SPAIN 5 -#define FRANCE 6 -#define ISRAEL 7 -#define AUSTRALIA 8 -#define JAPAN_TEST 9 - -/* Hop pattern lengths */ -#define USA_HOP_MOD 79 -#define EUROPE_HOP_MOD 79 -#define JAPAN_HOP_MOD 23 -#define KOREA_HOP_MOD 23 -#define SPAIN_HOP_MOD 27 -#define FRANCE_HOP_MOD 35 -#define ISRAEL_HOP_MOD 35 -#define AUSTRALIA_HOP_MOD 47 -#define JAPAN_TEST_HOP_MOD 23 - -#define ESSID_SIZE 32 -/**********************************************************************/ -/* CIS Register Constants */ -#define CIS_OFFSET 0x0f00 -/* Configuration Option Register (0x0F00) */ -#define COR_OFFSET 0x00 -#define COR_SOFT_RESET 0x80 -#define COR_LEVEL_IRQ 0x40 -#define COR_CONFIG_NUM 0x01 -#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM) - -/* Card Configuration and Status Register (0x0F01) */ -#define CCSR_OFFSET 0x01 -#define CCSR_HOST_INTR_PENDING 0x01 -#define CCSR_POWER_DOWN 0x04 - -/* HCS Interrupt Register (0x0F05) */ -#define HCS_INTR_OFFSET 0x05 -/* #define HCS_INTR_OFFSET 0x0A */ -#define HCS_INTR_CLEAR 0x00 - -/* ECF Interrupt Register (0x0F06) */ -#define ECF_INTR_OFFSET 0x06 -/* #define ECF_INTR_OFFSET 0x0C */ -#define ECF_INTR_SET 0x01 - -/* Authorization Register 0 (0x0F08) */ -#define AUTH_0_ON 0x57 - -/* Authorization Register 1 (0x0F09) */ -#define AUTH_1_ON 0x82 - -/* Program Mode Register (0x0F0A) */ -#define PC2PM 0x02 -#define PC2CAL 0x10 -#define PC2MLSE 0x20 - -/* PC Test Mode Register (0x0F0B) */ -#define PC_TEST_MODE 0x08 - -/* Frequency Control Word (0x0F10) */ -/* Range 0x02 - 0xA6 */ - -/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */ - -/**********************************************************************/ - -/* Shared RAM Area */ -#define SCB_BASE 0x0000 -#define STATUS_BASE 0x0100 -#define HOST_TO_ECF_BASE 0x0200 -#define ECF_TO_HOST_BASE 0x0300 -#define CCS_BASE 0x0400 -#define RCS_BASE 0x0800 -#define INFRA_TIM_BASE 0x0C00 -#define SSID_LIST_BASE 0x0D00 -#define TX_BUF_BASE 0x1000 -#define RX_BUF_BASE 0x8000 - -#define NUMBER_OF_CCS 64 -#define NUMBER_OF_RCS 64 -/*#define NUMBER_OF_TX_CCS 14 */ -#define NUMBER_OF_TX_CCS 14 - -#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) -#define RX_BUFF_END 0x3FFF -/* Values for buffer_status */ -#define CCS_BUFFER_FREE 0 -#define CCS_BUFFER_BUSY 1 -#define CCS_COMMAND_COMPLETE 2 -#define CCS_COMMAND_FAILED 3 - -/* Values for cmd */ -#define CCS_DOWNLOAD_STARTUP_PARAMS 1 -#define CCS_UPDATE_PARAMS 2 -#define CCS_REPORT_PARAMS 3 -#define CCS_UPDATE_MULTICAST_LIST 4 -#define CCS_UPDATE_POWER_SAVINGS_MODE 5 -#define CCS_START_NETWORK 6 -#define CCS_JOIN_NETWORK 7 -#define CCS_START_ASSOCIATION 8 -#define CCS_TX_REQUEST 9 -#define CCS_TEST_MEMORY 0xa -#define CCS_SHUTDOWN 0xb -#define CCS_DUMP_MEMORY 0xc -#define CCS_START_TIMER 0xe -#define CCS_LAST_CMD CCS_START_TIMER - -/* Values for link field */ -#define CCS_END_LIST 0xff - -/* values for buffer_status field */ -#define RCS_BUFFER_FREE 0 -#define RCS_BUFFER_BUSY 1 -#define RCS_COMPLETE 2 -#define RCS_FAILED 3 -#define RCS_BUFFER_RELEASE 0xFF - -/* values for interrupt_id field */ -#define PROCESS_RX_PACKET 0x80 /* */ -#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */ -#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */ -#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */ - -/*****************************************************************************/ -/* Memory types for dump memory command */ -#define C_MEM_PROG 0 -#define C_MEM_XDATA 1 -#define C_MEM_SFR 2 -#define C_MEM_IDATA 3 - -/*** Return values for hw_xmit **********/ -#define XMIT_OK (0) -#define XMIT_MSG_BAD (-1) -#define XMIT_NO_CCS (-2) -#define XMIT_NO_INTR (-3) -#define XMIT_NEED_AUTH (-4) - -/*** Values for card status */ -#define CARD_INSERTED (0) - -#define CARD_AWAITING_PARAM (1) -#define CARD_INIT_ERROR (11) - -#define CARD_DL_PARAM (2) -#define CARD_DL_PARAM_ERROR (12) - -#define CARD_DOING_ACQ (3) - -#define CARD_ACQ_COMPLETE (4) -#define CARD_ACQ_FAILED (14) - -#define CARD_AUTH_COMPLETE (5) -#define CARD_AUTH_REFUSED (15) - -#define CARD_ASSOC_COMPLETE (6) -#define CARD_ASSOC_FAILED (16) - -/*** Values for authentication_state ***********************************/ -#define UNAUTHENTICATED (0) -#define AWAITING_RESPONSE (1) -#define AUTHENTICATED (2) -#define NEED_TO_AUTH (3) - -/*** Values for authentication type ************************************/ -#define OPEN_AUTH_REQUEST (1) -#define OPEN_AUTH_RESPONSE (2) -#define BROADCAST_DEAUTH (0xc0) -/*** Values for timer functions ****************************************/ -#define TODO_NOTHING (0) -#define TODO_VERIFY_DL_START (-1) -#define TODO_START_NET (-2) -#define TODO_JOIN_NET (-3) -#define TODO_AUTHENTICATE_TIMEOUT (-4) -#define TODO_SEND_CCS (-5) -/***********************************************************************/ -/* Parameter passing structure for update/report parameter CCS's */ -struct object_id { - void *object_addr; - unsigned char object_length; -}; - -#define OBJID_network_type 0 -#define OBJID_acting_as_ap_status 1 -#define OBJID_current_ess_id 2 -#define OBJID_scanning_mode 3 -#define OBJID_power_mgt_state 4 -#define OBJID_mac_address 5 -#define OBJID_frag_threshold 6 -#define OBJID_hop_time 7 -#define OBJID_beacon_period 8 -#define OBJID_dtim_period 9 -#define OBJID_retry_max 10 -#define OBJID_ack_timeout 11 -#define OBJID_sifs 12 -#define OBJID_difs 13 -#define OBJID_pifs 14 -#define OBJID_rts_threshold 15 -#define OBJID_scan_dwell_time 16 -#define OBJID_max_scan_dwell_time 17 -#define OBJID_assoc_resp_timeout 18 -#define OBJID_adhoc_scan_cycle_max 19 -#define OBJID_infra_scan_cycle_max 20 -#define OBJID_infra_super_cycle_max 21 -#define OBJID_promiscuous_mode 22 -#define OBJID_unique_word 23 -#define OBJID_slot_time 24 -#define OBJID_roaming_low_snr 25 -#define OBJID_low_snr_count_thresh 26 -#define OBJID_infra_missed_bcn 27 -#define OBJID_adhoc_missed_bcn 28 -#define OBJID_curr_country_code 29 -#define OBJID_hop_pattern 30 -#define OBJID_reserved 31 -#define OBJID_cw_max_msb 32 -#define OBJID_cw_min_msb 33 -#define OBJID_noise_filter_gain 34 -#define OBJID_noise_limit_offset 35 -#define OBJID_det_rssi_thresh_offset 36 -#define OBJID_med_busy_thresh_offset 37 -#define OBJID_det_sync_thresh 38 -#define OBJID_test_mode 39 -#define OBJID_test_min_chan_num 40 -#define OBJID_test_max_chan_num 41 -#define OBJID_allow_bcast_ID_prbrsp 42 -#define OBJID_privacy_must_start 43 -#define OBJID_privacy_can_join 44 -#define OBJID_basic_rate_set 45 - -/**** Configuration/Status/Control Area ***************************/ -/* System Control Block (SCB) Area - * Located at Shared RAM offset 0 - */ -struct scb { - UCHAR ccs_index; - UCHAR rcs_index; -}; - -/****** Status area at Shared RAM offset 0x0100 ******************************/ -struct status { - UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR reserved1; - short mrx_overflow; /* ECF increments on rx overflow */ - short mrx_checksum_error; /* ECF increments on rx CRC error */ - short rx_hec_error; /* ECF incs on mac header CRC error */ - UCHAR rxnoise; /* Average RSL measurement */ -}; - -/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/ -struct host_to_ecf_area { - -}; - -/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/ -struct startup_res_518 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR ecf_spare[7]; - UCHAR japan_call_sign[12]; -}; - -struct startup_res_6 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR reserved; - UCHAR supp_rates[8]; - UCHAR japan_call_sign[12]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR firmware_version[3]; - UCHAR asic_version; - UCHAR tib_length; -}; - -struct start_join_net_params { - UCHAR net_type; - UCHAR ssid[ESSID_SIZE]; - UCHAR reserved; - UCHAR privacy_can_join; -}; - -/****** Command Control Structure area at Shared ram offset 0x0400 ***********/ -/* Structures for command specific parameters (ccs.var) */ -struct update_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; -}; -struct report_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; - UCHAR length; -}; -struct start_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct join_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct tx_requested_cmd { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR host_reserved[2]; - UCHAR reserved[3]; - UCHAR tx_rate; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR antenna; -}; -struct tx_requested_cmd_4 { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR dest_addr[ADDRLEN]; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR station_id; -}; -struct memory_dump_cmd { - UCHAR memory_type; - UCHAR memory_ptr[2]; - UCHAR length; -}; -struct update_association_cmd { - UCHAR status; - UCHAR aid[2]; -}; -struct start_timer_cmd { - UCHAR duration[2]; -}; - -struct ccs { - UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */ - /* 2 = command complete, 3 = failed */ - UCHAR cmd; /* command to ECF */ - UCHAR link; /* link to next CCS, FF=end of list */ - /* command specific parameters */ - union { - char reserved[13]; - struct update_param_cmd update_param; - struct report_param_cmd report_param; - UCHAR nummulticast; - UCHAR mode; - struct start_network_cmd start_network; - struct join_network_cmd join_network; - struct tx_requested_cmd tx_request; - struct memory_dump_cmd memory_dump; - struct update_association_cmd update_assoc; - struct start_timer_cmd start_timer; - } var; -}; - -/*****************************************************************************/ -/* Transmit buffer structures */ -struct tib_structure { - UCHAR ccs_index; - UCHAR psm; - UCHAR pass_fail; - UCHAR retry_count; - UCHAR max_retries; - UCHAR frags_remaining; - UCHAR no_rb; - UCHAR rts_reqd; - UCHAR csma_tx_cntrl_2; - UCHAR sifs_tx_cntrl_2; - UCHAR tx_dma_addr_1[2]; - UCHAR tx_dma_addr_2[2]; - UCHAR var_dur_2mhz[2]; - UCHAR var_dur_1mhz[2]; - UCHAR max_dur_2mhz[2]; - UCHAR max_dur_1mhz[2]; - UCHAR hdr_len; - UCHAR max_frag_len[2]; - UCHAR var_len[2]; - UCHAR phy_hdr_4; - UCHAR mac_hdr_1; - UCHAR mac_hdr_2; - UCHAR sid[2]; -}; - -struct phy_header { - UCHAR sfd[2]; - UCHAR hdr_3; - UCHAR hdr_4; -}; -struct ray_rx_msg { - struct mac_header mac; - UCHAR var[]; -}; - -struct tx_msg { - struct tib_structure tib; - struct phy_header phy; - struct mac_header mac; - UCHAR var[]; -}; - -/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */ -/* Structures for command specific parameters (rcs.var) */ -struct rx_packet_cmd { - UCHAR rx_data_ptr[2]; - UCHAR rx_data_length[2]; - UCHAR rx_sig_lev; - UCHAR next_frag_rcs_index; - UCHAR totalpacketlength[2]; -}; -struct rejoin_net_cmplt_cmd { - UCHAR reserved; - UCHAR bssid[ADDRLEN]; -}; -struct japan_call_sign_rxd { - UCHAR rxd_call_sign[8]; - UCHAR reserved[5]; -}; - -struct rcs { - UCHAR buffer_status; - UCHAR interrupt_id; - UCHAR link_field; - /* command specific parameters */ - union { - UCHAR reserved[13]; - struct rx_packet_cmd rx_packet; - struct rejoin_net_cmplt_cmd rejoin_net_complete; - struct japan_call_sign_rxd japan_call_sign; - } var; -}; - -/****** Startup parameter structures for both versions of firmware ***********/ -struct b4_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max; /* */ - UCHAR a_cw_min; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_rx_tx_delay; /* */ - UCHAR a_current_bss_id[ADDRLEN]; /* */ - UCHAR a_hop_set; /* */ -}; -struct b5_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* 4 */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max[2]; /* */ - UCHAR a_cw_min[2]; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_allow_bcast_SSID_probe_rsp; - UCHAR a_privacy_must_start; - UCHAR a_privacy_can_join; - UCHAR a_basic_rate_set[8]; -}; - -/*****************************************************************************/ -#define RAY_IOCG_PARMS (SIOCDEVPRIVATE) -#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1) -#define RAY_DO_CMD (SIOCDEVPRIVATE + 2) - -/****** ethernet <-> 802.11 translation **************************************/ -typedef struct snaphdr_t -{ - UCHAR dsap; - UCHAR ssap; - UCHAR ctrl; - UCHAR org[3]; - UCHAR ethertype[2]; -} snaphdr_t; - -#define BRIDGE_ENCAP 0xf80000 -#define RFC1042_ENCAP 0 -#define SNAP_ID 0x0003aaaa -#define RAY_IPX_TYPE 0x8137 -#define APPLEARP_TYPE 0x80f3 -/*****************************************************************************/ -#endif /* _RAYCTL_H_ */ From 238349207cd3e158df53d866abf1d42b2392aa9e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:50 +0200 Subject: [PATCH 0159/7721] wifi: remove orphaned wl3501 driver Planet WL3501 is another PCMCIA driver for pre-802.11b interfaces (2Mbit/s) with incomplete CFG80211 support. This was marked as orphaned in 2017 but has been unmaintained for a long time before that. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 5 - drivers/net/wireless/legacy/Kconfig | 10 - drivers/net/wireless/legacy/Makefile | 3 - drivers/net/wireless/legacy/wl3501.h | 615 ------- drivers/net/wireless/legacy/wl3501_cs.c | 2036 ----------------------- 5 files changed, 2669 deletions(-) delete mode 100644 drivers/net/wireless/legacy/wl3501.h delete mode 100644 drivers/net/wireless/legacy/wl3501_cs.c diff --git a/MAINTAINERS b/MAINTAINERS index 91eacd4ecc9f..9ac0f62e38a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23236,11 +23236,6 @@ M: Miloslav Trmac S: Maintained F: drivers/input/misc/wistron_btns.c -WL3501 WIRELESS PCMCIA CARD DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/wl3501* - WMI BINARY MOF DRIVER M: Armin Wolf R: Thomas Weißschuh diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig index 1d77d53d6440..b4e0e516f2fa 100644 --- a/drivers/net/wireless/legacy/Kconfig +++ b/drivers/net/wireless/legacy/Kconfig @@ -1,13 +1,3 @@ -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" depends on USB diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile index d8705ccc5cf5..1ed83f33ad20 100644 --- a/drivers/net/wireless/legacy/Makefile +++ b/drivers/net/wireless/legacy/Makefile @@ -1,5 +1,2 @@ -# 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o - obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h deleted file mode 100644 index 91f276dd22a1..000000000000 --- a/drivers/net/wireless/legacy/wl3501.h +++ /dev/null @@ -1,615 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __WL3501_H__ -#define __WL3501_H__ - -#include -#include - -/* define for WLA 2.0 */ -#define WL3501_BLKSZ 256 -/* - * ID for input Signals of DRIVER block - * bit[7-5] is block ID: 000 - * bit[4-0] is signal ID -*/ -enum wl3501_signals { - WL3501_SIG_ALARM, - WL3501_SIG_MD_CONFIRM, - WL3501_SIG_MD_IND, - WL3501_SIG_ASSOC_CONFIRM, - WL3501_SIG_ASSOC_IND, - WL3501_SIG_AUTH_CONFIRM, - WL3501_SIG_AUTH_IND, - WL3501_SIG_DEAUTH_CONFIRM, - WL3501_SIG_DEAUTH_IND, - WL3501_SIG_DISASSOC_CONFIRM, - WL3501_SIG_DISASSOC_IND, - WL3501_SIG_GET_CONFIRM, - WL3501_SIG_JOIN_CONFIRM, - WL3501_SIG_PWR_MGMT_CONFIRM, - WL3501_SIG_REASSOC_CONFIRM, - WL3501_SIG_REASSOC_IND, - WL3501_SIG_SCAN_CONFIRM, - WL3501_SIG_SET_CONFIRM, - WL3501_SIG_START_CONFIRM, - WL3501_SIG_RESYNC_CONFIRM, - WL3501_SIG_SITE_CONFIRM, - WL3501_SIG_SAVE_CONFIRM, - WL3501_SIG_RFTEST_CONFIRM, -/* - * ID for input Signals of MLME block - * bit[7-5] is block ID: 010 - * bit[4-0] is signal ID - */ - WL3501_SIG_ASSOC_REQ = 0x20, - WL3501_SIG_AUTH_REQ, - WL3501_SIG_DEAUTH_REQ, - WL3501_SIG_DISASSOC_REQ, - WL3501_SIG_GET_REQ, - WL3501_SIG_JOIN_REQ, - WL3501_SIG_PWR_MGMT_REQ, - WL3501_SIG_REASSOC_REQ, - WL3501_SIG_SCAN_REQ, - WL3501_SIG_SET_REQ, - WL3501_SIG_START_REQ, - WL3501_SIG_MD_REQ, - WL3501_SIG_RESYNC_REQ, - WL3501_SIG_SITE_REQ, - WL3501_SIG_SAVE_REQ, - WL3501_SIG_RF_TEST_REQ, - WL3501_SIG_MM_CONFIRM = 0x60, - WL3501_SIG_MM_IND, -}; - -enum wl3501_mib_attribs { - WL3501_MIB_ATTR_STATION_ID, - WL3501_MIB_ATTR_AUTH_ALGORITHMS, - WL3501_MIB_ATTR_AUTH_TYPE, - WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, - WL3501_MIB_ATTR_CF_POLLABLE, - WL3501_MIB_ATTR_CFP_PERIOD, - WL3501_MIB_ATTR_CFPMAX_DURATION, - WL3501_MIB_ATTR_AUTH_RESP_TMOUT, - WL3501_MIB_ATTR_RX_DTIMS, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - WL3501_MIB_ATTR_PRIV_INVOKED, - WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, - WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - WL3501_MIB_ATTR_MAC_ADDR, - WL3501_MIB_ATTR_GROUP_ADDRS, - WL3501_MIB_ATTR_RTS_THRESHOLD, - WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - WL3501_MIB_ATTR_FRAG_THRESHOLD, - WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, - WL3501_MIB_ATTR_MAX_RX_LIFETIME, - WL3501_MIB_ATTR_MANUFACTURER_ID, - WL3501_MIB_ATTR_PRODUCT_ID, - WL3501_MIB_ATTR_TX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, - WL3501_MIB_ATTR_FAILED_COUNT, - WL3501_MIB_ATTR_RX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_RX_COUNT, - WL3501_MIB_ATTR_FCS_ERROR_COUNT, - WL3501_MIB_ATTR_RETRY_COUNT, - WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, - WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, - WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - WL3501_MIB_ATTR_PHY_TYPE, - WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, - WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, - WL3501_MIB_ATTR_SLOT_TIME, - WL3501_MIB_ATTR_CCA_TIME, - WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, - WL3501_MIB_ATTR_TX_PLCP_DELAY, - WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, - WL3501_MIB_ATTR_TX_RAMP_ON_TIME, - WL3501_MIB_ATTR_TX_RF_DELAY, - WL3501_MIB_ATTR_SIFS_TIME, - WL3501_MIB_ATTR_RX_RF_DELAY, - WL3501_MIB_ATTR_RX_PLCP_DELAY, - WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, - WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, - WL3501_MIB_ATTR_PREAMBLE_LEN, - WL3501_MIB_ATTR_PLCP_HEADER_LEN, - WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, - WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, - WL3501_MIB_ATTR_TEMP_TYPE, - WL3501_MIB_ATTR_CW_MIN, - WL3501_MIB_ATTR_CW_MAX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, - WL3501_MIB_ATTR_MPDU_MAX_LEN, - WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, - WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, - WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, - WL3501_MIB_ATTR_DIVERSITY_SUPPORT, - WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, - WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, - WL3501_MIB_ATTR_TX_PWR_LEVEL1, - WL3501_MIB_ATTR_TX_PWR_LEVEL2, - WL3501_MIB_ATTR_TX_PWR_LEVEL3, - WL3501_MIB_ATTR_TX_PWR_LEVEL4, - WL3501_MIB_ATTR_TX_PWR_LEVEL5, - WL3501_MIB_ATTR_TX_PWR_LEVEL6, - WL3501_MIB_ATTR_TX_PWR_LEVEL7, - WL3501_MIB_ATTR_TX_PWR_LEVEL8, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - WL3501_MIB_ATTR_CURRENT_CHAN, - WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, - WL3501_MIB_ATTR_CURRENT_CCA_MODE, - WL3501_MIB_ATTR_ED_THRESHOLD, - WL3501_MIB_ATTR_SINTHESIZER_LOCKED, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - WL3501_MIB_ATTR_DOZE_TURNON_TIME, - WL3501_MIB_ATTR_RCR33, - WL3501_MIB_ATTR_DEFAULT_CHAN, - WL3501_MIB_ATTR_SSID, - WL3501_MIB_ATTR_PWR_MGMT_ENABLE, - WL3501_MIB_ATTR_NET_CAPABILITY, - WL3501_MIB_ATTR_ROUTING, -}; - -enum wl3501_net_type { - WL3501_NET_TYPE_INFRA, - WL3501_NET_TYPE_ADHOC, - WL3501_NET_TYPE_ANY_BSS, -}; - -enum wl3501_scan_type { - WL3501_SCAN_TYPE_ACTIVE, - WL3501_SCAN_TYPE_PASSIVE, -}; - -enum wl3501_tx_result { - WL3501_TX_RESULT_SUCCESS, - WL3501_TX_RESULT_NO_BSS, - WL3501_TX_RESULT_RETRY_LIMIT, -}; - -enum wl3501_sys_type { - WL3501_SYS_TYPE_OPEN, - WL3501_SYS_TYPE_SHARE_KEY, -}; - -enum wl3501_status { - WL3501_STATUS_SUCCESS, - WL3501_STATUS_INVALID, - WL3501_STATUS_TIMEOUT, - WL3501_STATUS_REFUSED, - WL3501_STATUS_MANY_REQ, - WL3501_STATUS_ALREADY_BSS, -}; - -#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ -#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ -#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ - -#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ -#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ -#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ -#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ -#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ -#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ -#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ - -#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */ - -enum iw_mgmt_rate_labels { - IW_MGMT_RATE_LABEL_1MBIT = 2, - IW_MGMT_RATE_LABEL_2MBIT = 4, - IW_MGMT_RATE_LABEL_5_5MBIT = 11, - IW_MGMT_RATE_LABEL_11MBIT = 22, -}; - -enum iw_mgmt_info_element_ids { - IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */ - IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */ - IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - /* 7-15: Reserved, unused */ - IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16, - /* 17-31 Reserved for challenge text extension */ - /* 32-255 Reserved, unused */ -}; - -struct iw_mgmt_info_element { - u8 id; /* one of enum iw_mgmt_info_element_ids, - but sizeof(enum) > sizeof(u8) :-( */ - u8 len; - u8 data[]; -} __packed; - -struct iw_mgmt_essid_pset { - struct iw_mgmt_info_element el; - u8 essid[IW_ESSID_MAX_SIZE]; -} __packed; - -/* - * According to 802.11 Wireless Networks, the definitive guide - O'Reilly - * Pg 75 - */ -#define IW_DATA_RATE_MAX_LABELS 8 - -struct iw_mgmt_data_rset { - struct iw_mgmt_info_element el; - u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS]; -} __packed; - -struct iw_mgmt_ds_pset { - struct iw_mgmt_info_element el; - u8 chan; -} __packed; - -struct iw_mgmt_cf_pset { - struct iw_mgmt_info_element el; - u8 cfp_count; - u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_dur_remaining; -} __packed; - -struct iw_mgmt_ibss_pset { - struct iw_mgmt_info_element el; - u16 atim_window; -} __packed; - -struct wl3501_tx_hdr { - u16 tx_cnt; - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctrl; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_rx_hdr { - u16 rx_next_blk; - u16 rc_next_frame_blk; - u8 rx_blk_ctrl; - u8 rx_next_frame; - u8 rx_next_frame1; - u8 rssi; - char time[8]; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_start_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 beacon_period; - u16 dtim_period; - u16 probe_delay; - u16 cap_info; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_data_rset bss_basic_rset; - struct iw_mgmt_data_rset operational_rset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_ibss_pset ibss_pset; -}; - -struct wl3501_assoc_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 timeout; - u16 cap_info; - u16 listen_interval; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_assoc_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_assoc_ind { - u16 next_blk; - u8 sig_id; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 timeout; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 status; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_get_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_attrib; -}; - -struct wl3501_get_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_status; - u16 mib_attrib; - u8 mib_value[100]; -}; - -struct wl3501_req { - u16 beacon_period; - u16 dtim_period; - u16 cap_info; - u8 bss_type; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ibss_pset ibss_pset; - struct iw_mgmt_data_rset bss_basic_rset; -}; - -struct wl3501_join_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - struct iw_mgmt_data_rset operational_rset; - u16 reserved2; - u16 timeout; - u16 probe_delay; - u8 timestamp[8]; - u8 local_time[8]; - struct wl3501_req req; -}; - -struct wl3501_join_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_pwr_mgmt_req { - u16 next_blk; - u8 sig_id; - u8 pwr_save; - u8 wake_up; - u8 receive_dtims; -}; - -struct wl3501_pwr_mgmt_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_scan_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 probe_delay; - u16 min_chan_time; - u16 max_chan_time; - u8 chan_list[14]; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - enum wl3501_scan_type scan_type; -}; - -struct wl3501_scan_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; - char timestamp[8]; - char localtime[8]; - struct wl3501_req req; - u8 rssi; -}; - -struct wl3501_start_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_md_req { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_ind { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 reception; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 data; - u8 status; - u8 pri; - u8 service_class; -}; - -struct wl3501_resync_req { - u16 next_blk; - u8 sig_id; -}; - -/* Definitions for supporting clone adapters. */ -/* System Interface Registers (SIR space) */ -#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ -#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ -#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ -#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ -#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ -#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ -#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ -#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ - -/* Bits in GCR */ -#define WL3501_GCR_SWRESET ((u8)0x80) -#define WL3501_GCR_CORESET ((u8)0x40) -#define WL3501_GCR_DISPWDN ((u8)0x20) -#define WL3501_GCR_ECWAIT ((u8)0x10) -#define WL3501_GCR_ECINT ((u8)0x08) -#define WL3501_GCR_INT2EC ((u8)0x04) -#define WL3501_GCR_ENECINT ((u8)0x02) -#define WL3501_GCR_DAM ((u8)0x01) - -/* Bits in BSS (Bank Switching Select Register) */ -#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ -#define WL3501_BSS_FPAGE1 ((u8)0x28) -#define WL3501_BSS_FPAGE2 ((u8)0x30) -#define WL3501_BSS_FPAGE3 ((u8)0x38) -#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ -#define WL3501_BSS_SPAGE1 ((u8)0x08) -#define WL3501_BSS_SPAGE2 ((u8)0x10) -#define WL3501_BSS_SPAGE3 ((u8)0x18) - -/* Define Driver Interface */ -/* Refer IEEE 802.11 */ -/* Tx packet header, include PLCP and MPDU */ -/* Tx PLCP Header */ -struct wl3501_80211_tx_plcp_hdr { - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; -} __packed; - -struct wl3501_80211_tx_hdr { - struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; -} __packed __aligned(2); - -/* - Reserve the beginning Tx space for descriptor use. - - TxBlockOffset --> *----*----*----*----* \ - (TxFreeDesc) | 0 | 1 | 2 | 3 | \ - | 4 | 5 | 6 | 7 | | - | 8 | 9 | 10 | 11 | TX_DESC * 20 - | 12 | 13 | 14 | 15 | | - | 16 | 17 | 18 | 19 | / - TxBufferBegin --> *----*----*----*----* / - (TxBufferHead) | | - (TxBufferTail) | | - | Send Buffer | - | | - | | - *-------------------* - TxBufferEnd -------------------------/ - -*/ - -struct wl3501_card { - int base_addr; - u8 mac_addr[ETH_ALEN]; - spinlock_t lock; - wait_queue_head_t wait; - struct wl3501_get_confirm sig_get_confirm; - struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; - u16 tx_buffer_size; - u16 tx_buffer_head; - u16 tx_buffer_tail; - u16 tx_buffer_cnt; - u16 esbq_req_start; - u16 esbq_req_end; - u16 esbq_req_head; - u16 esbq_req_tail; - u16 esbq_confirm_start; - u16 esbq_confirm_end; - u16 esbq_confirm; - struct iw_mgmt_essid_pset essid; - struct iw_mgmt_essid_pset keep_essid; - u8 bssid[ETH_ALEN]; - int net_type; - char nick[32]; - char card_name[32]; - char firmware_date[32]; - u8 chan; - u8 cap_info; - u16 start_seg; - u16 bss_cnt; - u16 join_sta_bss; - u8 rssi; - u8 adhoc_times; - u8 reg_domain; - u8 version[2]; - struct wl3501_scan_confirm bss_set[20]; - - struct iw_statistics wstats; - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - struct pcmcia_device *p_dev; -}; -#endif diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c deleted file mode 100644 index c45c4b7cbbaf..000000000000 --- a/drivers/net/wireless/legacy/wl3501_cs.c +++ /dev/null @@ -1,2036 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WL3501 Wireless LAN PCMCIA Card Driver for Linux - * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw - * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo - * Wireless extensions in 2.4 by Gustavo Niemeyer - * - * References used by Fox Chen while writing the original driver for 2.0.30: - * - * 1. WL24xx packet drivers (tooasm.asm) - * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO - * 3. IEEE 802.11 - * 4. Linux network driver (/usr/src/linux/drivers/net) - * 5. ISA card driver - wl24.c - * 6. Linux PCMCIA skeleton driver - skeleton.c - * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c - * - * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 - * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. - * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null - * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct - * ETHER/IP/UDP/TCP header, and acknowledgement overhead) - * - * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, - * 173 Kbytes/s in TCP. - * - * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode - * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "wl3501.h" - -#ifndef __i386__ -#define slow_down_io() -#endif - -/* For rough constant delay */ -#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } - - - -#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } -#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } -#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } - -#define WL3501_RELEASE_TIMEOUT (25 * HZ) -#define WL3501_MAX_ADHOC_TRIES 16 - -#define WL3501_RESUME 0 -#define WL3501_SUSPEND 1 - -static int wl3501_config(struct pcmcia_device *link); -static void wl3501_release(struct pcmcia_device *link); - -static const struct { - int reg_domain; - int min, max, deflt; -} iw_channel_table[] = { - { - .reg_domain = IW_REG_DOMAIN_FCC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_DOC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ETSI, - .min = 1, - .max = 13, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_SPAIN, - .min = 10, - .max = 11, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_FRANCE, - .min = 10, - .max = 13, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK, - .min = 14, - .max = 14, - .deflt = 14, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK1, - .min = 1, - .max = 14, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ISRAEL, - .min = 3, - .max = 9, - .deflt = 9, - }, -}; - -/** - * iw_valid_channel - validate channel in regulatory domain - * @reg_domain: regulatory domain - * @channel: channel to validate - * - * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. - */ -static int iw_valid_channel(int reg_domain, int channel) -{ - int i, rc = 0; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = channel >= iw_channel_table[i].min && - channel <= iw_channel_table[i].max; - break; - } - return rc; -} - -/** - * iw_default_channel - get default channel for a regulatory domain - * @reg_domain: regulatory domain - * - * Returns the default channel for a regulatory domain - */ -static int iw_default_channel(int reg_domain) -{ - int i, rc = 1; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = iw_channel_table[i].deflt; - break; - } - return rc; -} - -static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, - struct iw_mgmt_info_element *el, - void *value, int len) -{ - el->id = id; - el->len = len; - memcpy(el->data, value, len); -} - -static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, - struct iw_mgmt_info_element *from) -{ - iw_set_mgmt_info_element(from->id, to, from->data, from->len); -} - -static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) -{ - wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); -} - -/* - * Get Ethernet MAC address. - * - * WARNING: We switch to FPAGE0 and switc back again. - * Making sure there is no other WL function beening called by ISR. - */ -static int wl3501_get_flash_mac_addr(struct wl3501_card *this) -{ - int base_addr = this->base_addr; - - /* get MAC addr */ - wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ - wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ - - /* wait for reading EEPROM */ - WL3501_NOPLOOP(100); - this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); - wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); - WL3501_NOPLOOP(100); - this->version[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->version[1] = inb(base_addr + WL3501_NIC_IODPA); - /* switch to SRAM Page 0 (for safety) */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - - /* The MAC addr should be 00:60:... */ - return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; -} - -/** - * wl3501_set_to_wla - Move 'size' bytes from PC to card - * @this: Card - * @dest: Card addressing space - * @src: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from PC to card. (Shouldn't be interrupted) - */ -static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); - - /* rep out to Port A */ - wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); -} - -/** - * wl3501_get_from_wla - Move 'size' bytes from card to PC - * @this: Card - * @src: Card addressing space - * @dest: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from card to PC. (Shouldn't be interrupted) - */ -static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); - - /* rep get from Port A */ - insb(this->base_addr + WL3501_NIC_IODPA, dest, size); -} - -/* - * Get/Allocate a free Tx Data Buffer - * - * *--------------*-----------------*----------------------------------* - * | PLCP | MAC Header | DST SRC Data ... | - * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | - * *--------------*-----------------*----------------------------------* - * \ \- IEEE 802.11 -/ \-------------- len --------------/ - * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ - * - * Return = Position in Card - */ -static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) -{ - u16 next, blk_cnt = 0, zero = 0; - u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; - u16 ret = 0; - - if (full_len > this->tx_buffer_cnt * 254) - goto out; - ret = this->tx_buffer_head; - while (full_len) { - if (full_len < 254) - full_len = 0; - else - full_len -= 254; - wl3501_get_from_wla(this, this->tx_buffer_head, &next, - sizeof(next)); - if (!full_len) - wl3501_set_to_wla(this, this->tx_buffer_head, &zero, - sizeof(zero)); - this->tx_buffer_head = next; - blk_cnt++; - /* if buffer is not enough */ - if (!next && full_len) { - this->tx_buffer_head = ret; - ret = 0; - goto out; - } - } - this->tx_buffer_cnt -= blk_cnt; -out: - return ret; -} - -/* - * Free an allocated Tx Buffer. ptr must be correct position. - */ -static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) -{ - /* check if all space is not free */ - if (!this->tx_buffer_head) - this->tx_buffer_head = ptr; - else - wl3501_set_to_wla(this, this->tx_buffer_tail, - &ptr, sizeof(ptr)); - while (ptr) { - u16 next; - - this->tx_buffer_cnt++; - wl3501_get_from_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; - ptr = next; - } -} - -static int wl3501_esbq_req_test(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) -{ - u16 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); - wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); - this->esbq_req_head += 4; - if (this->esbq_req_head >= this->esbq_req_end) - this->esbq_req_head = this->esbq_req_start; -} - -static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) -{ - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sig_size); - if (ptr) { - wl3501_set_to_wla(this, ptr, sig, sig_size); - wl3501_esbq_req(this, &ptr); - rc = 0; - } - } - return rc; -} - -static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf) -{ - struct wl3501_get_req sig = { - .sig_id = WL3501_SIG_GET_REQ, - .mib_attrib = index, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_get_confirm.mib_status = 255; - rc = 0; - } - } - spin_unlock_irqrestore(&this->lock, flags); - - return rc; -} - -static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, - void *bf, int size) -{ - int rc; - - rc = wl3501_request_mib(this, index, bf); - if (rc) - return rc; - - rc = wait_event_interruptible(this->wait, - this->sig_get_confirm.mib_status != 255); - if (rc) - return rc; - - memcpy(bf, this->sig_get_confirm.mib_value, size); - return 0; -} - -static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) -{ - struct wl3501_pwr_mgmt_req sig = { - .sig_id = WL3501_SIG_PWR_MGMT_REQ, - .pwr_save = suspend, - .wake_up = !suspend, - .receive_dtims = 10, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_pwr_mgmt_confirm.status = 255; - spin_unlock_irqrestore(&this->lock, flags); - rc = wait_event_interruptible(this->wait, - this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __func__, - suspend ? "suspend" : "resume", - this->sig_pwr_mgmt_confirm.status); - goto out; - } - } - spin_unlock_irqrestore(&this->lock, flags); -out: - return rc; -} - -/** - * wl3501_send_pkt - Send a packet. - * @this: Card - * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, - * data[6] - data[11] is Src MAC Addr) - * @len: Packet length - * Ref: IEEE 802.11 - */ -static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) -{ - u16 bf, sig_bf, next, tmplen, pktlen; - struct wl3501_md_req sig = { - .sig_id = WL3501_SIG_MD_REQ, - }; - size_t sig_addr_len = sizeof(sig.addr); - u8 *pdata = (char *)data; - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); - rc = -ENOMEM; - if (!sig_bf) /* No free buffer available */ - goto out; - bf = wl3501_get_tx_buffer(this, len + 26 + 24); - if (!bf) { - /* No free buffer available */ - wl3501_free_tx_buffer(this, sig_bf); - goto out; - } - rc = 0; - memcpy(&sig.addr, pdata, sig_addr_len); - pktlen = len - sig_addr_len; - pdata += sig_addr_len; - sig.data = bf; - if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { - u8 addr4[ETH_ALEN] = { - [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, - }; - - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - addr4, sizeof(addr4)); - sig.size = pktlen + 24 + 4 + 6; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr); - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, - bf + 2 + sizeof(struct wl3501_tx_hdr), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } else { - sig.size = pktlen + 24 + 4 - 2; - pdata += 2; - pktlen -= 2; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - while (pktlen > 0) { - if (pktlen > 254) { - tmplen = 254; - pktlen -= 254; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2, pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); - wl3501_esbq_req(this, &sig_bf); - } -out: - return rc; -} - -static int wl3501_mgmt_resync(struct wl3501_card *this) -{ - struct wl3501_resync_req sig = { - .sig_id = WL3501_SIG_RESYNC_REQ, - }; - - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static inline int wl3501_fw_bss_type(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : - WL3501_NET_TYPE_ADHOC; -} - -static inline int wl3501_fw_cap_info(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : - WL3501_MGMT_CAPABILITY_IBSS; -} - -static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) -{ - struct wl3501_scan_req sig = { - .sig_id = WL3501_SIG_SCAN_REQ, - .scan_type = WL3501_SCAN_TYPE_ACTIVE, - .probe_delay = 0x10, - .min_chan_time = chan_time, - .max_chan_time = chan_time, - .bss_type = wl3501_fw_bss_type(this), - }; - - this->bss_cnt = this->join_sta_bss = 0; - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) -{ - struct wl3501_join_req sig = { - .sig_id = WL3501_SIG_JOIN_REQ, - .timeout = 10, - .req.ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - }; - - memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req)); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_start(struct wl3501_card *this) -{ - struct wl3501_start_req sig = { - .sig_id = WL3501_SIG_START_REQ, - .beacon_period = 400, - .dtim_period = 1, - .ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - .bss_basic_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .operational_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .ibss_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - .len = 2, - }, - .atim_window = 10, - }, - .bss_type = wl3501_fw_bss_type(this), - .cap_info = wl3501_fw_cap_info(this), - }; - - iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); - iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) -{ - u16 i = 0; - int matchflag = 0; - struct wl3501_scan_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - pr_debug("success"); - if ((this->net_type == IW_MODE_INFRA && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || - (this->net_type == IW_MODE_ADHOC && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || - this->net_type == IW_MODE_AUTO) { - if (!this->essid.el.len) - matchflag = 1; - else if (this->essid.el.len == 3 && - !memcmp(this->essid.essid, "ANY", 3)) - matchflag = 1; - else if (this->essid.el.len != sig.req.ssid.el.len) - matchflag = 0; - else if (memcmp(this->essid.essid, sig.req.ssid.essid, - this->essid.el.len)) - matchflag = 0; - else - matchflag = 1; - if (matchflag) { - for (i = 0; i < this->bss_cnt; i++) { - if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid, - sig.req.bssid)) { - matchflag = 0; - break; - } - } - } - if (matchflag && (i < 20)) { - memcpy(&this->bss_set[i].req, - &sig.req, sizeof(sig.req)); - this->bss_cnt++; - this->rssi = sig.rssi; - this->bss_set[i].rssi = sig.rssi; - } - } - } else if (sig.status == WL3501_STATUS_TIMEOUT) { - pr_debug("timeout"); - this->join_sta_bss = 0; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -/** - * wl3501_block_interrupt - Mask interrupt from SUTRO - * @this: Card - * - * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_block_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | - WL3501_GCR_ENECINT)); - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_unblock_interrupt - Enable interrupt from SUTRO - * @this: Card - * - * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_unblock_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | - WL3501_GCR_ENECINT; - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_receive - Receive data from Receive Queue. - * - * Receive data from Receive Queue. - * - * @this: card - * @bf: address of host - * @size: size of buffer. - */ -static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) -{ - u16 next_addr, next_addr1; - u8 *data = bf + 12; - - size -= 12; - wl3501_get_from_wla(this, this->start_seg + 2, - &next_addr, sizeof(next_addr)); - if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), data, - WL3501_BLKSZ - - sizeof(struct wl3501_rx_hdr)); - size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - } else { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), - data, size); - size = 0; - } - while (size > 0) { - if (size > WL3501_BLKSZ - 5) { - wl3501_get_from_wla(this, next_addr + 5, data, - WL3501_BLKSZ - 5); - size -= WL3501_BLKSZ - 5; - data += WL3501_BLKSZ - 5; - wl3501_get_from_wla(this, next_addr + 2, &next_addr1, - sizeof(next_addr1)); - next_addr = next_addr1; - } else { - wl3501_get_from_wla(this, next_addr + 5, data, size); - size = 0; - } - } - return 0; -} - -static void wl3501_esbq_req_free(struct wl3501_card *this) -{ - u8 tmp; - u16 addr; - - if (this->esbq_req_head == this->esbq_req_tail) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); - if (!(tmp & 0x80)) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); - wl3501_free_tx_buffer(this, addr); - this->esbq_req_tail += 4; - if (this->esbq_req_tail >= this->esbq_req_end) - this->esbq_req_tail = this->esbq_req_start; -out: - return; -} - -static int wl3501_esbq_confirm(struct wl3501_card *this) -{ - u8 tmp; - - wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_online(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", - dev->name, this->bssid); - netif_wake_queue(dev); -} - -static void wl3501_esbq_confirm_done(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - this->esbq_confirm += 4; - if (this->esbq_confirm >= this->esbq_confirm_end) - this->esbq_confirm = this->esbq_confirm_start; -} - -static int wl3501_mgmt_auth(struct wl3501_card *this) -{ - struct wl3501_auth_req sig = { - .sig_id = WL3501_SIG_AUTH_REQ, - .type = WL3501_SYS_TYPE_OPEN, - .timeout = 1000, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_association(struct wl3501_card *this) -{ - struct wl3501_assoc_req sig = { - .sig_id = WL3501_SIG_ASSOC_REQ, - .timeout = 1000, - .listen_interval = 5, - .cap_info = this->cap_info, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_join_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - if (this->net_type == IW_MODE_INFRA) { - if (this->join_sta_bss < this->bss_cnt) { - const int i = this->join_sta_bss; - memcpy(this->bssid, - this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_mgmt_auth(this); - } - } else { - const int i = this->join_sta_bss; - - memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_online(dev); - } - } else { - int i; - this->join_sta_bss++; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -static inline void wl3501_alarm_interrupt(struct net_device *dev, - struct wl3501_card *this) -{ - if (this->net_type == IW_MODE_INFRA) { - printk(KERN_INFO "Wireless LAN offline\n"); - netif_stop_queue(dev); - wl3501_mgmt_resync(this); - } -} - -static inline void wl3501_md_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_md_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - wl3501_free_tx_buffer(this, sig.data); - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static inline void wl3501_md_ind_interrupt(struct net_device *dev, - struct wl3501_card *this, u16 addr) -{ - struct wl3501_md_ind sig; - struct sk_buff *skb; - u8 rssi, addr4[ETH_ALEN]; - u16 pkt_len; - - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - this->start_seg = sig.data; - wl3501_get_from_wla(this, - sig.data + offsetof(struct wl3501_rx_hdr, rssi), - &rssi, sizeof(rssi)); - this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; - - wl3501_get_from_wla(this, - sig.data + - offsetof(struct wl3501_rx_hdr, addr4), - &addr4, sizeof(addr4)); - if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && - addr4[2] == 0x03 && addr4[4] == 0x00)) { - printk(KERN_INFO "Unsupported packet type!\n"); - return; - } - pkt_len = sig.size + 12 - 24 - 4 - 6; - - skb = dev_alloc_skb(pkt_len + 5); - - if (!skb) { - printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", - dev->name, pkt_len); - dev->stats.rx_dropped++; - } else { - skb->dev = dev; - skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ - skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr, - sizeof(sig.addr)); - wl3501_receive(this, skb->data, pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -} - -static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, - u16 addr, void *sig, int size) -{ - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - wake_up(&this->wait); -} - -static inline void wl3501_start_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_start_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) - netif_wake_queue(dev); -} - -static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, - u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_assoc_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_online(dev); -} - -static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, - u16 addr) -{ - struct wl3501_auth_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_mgmt_association(this); - else - wl3501_mgmt_resync(this); -} - -static inline void wl3501_rx_interrupt(struct net_device *dev) -{ - int morepkts; - u16 addr; - u8 sig_id; - struct wl3501_card *this = netdev_priv(dev); - - pr_debug("entry"); -loop: - morepkts = 0; - if (!wl3501_esbq_confirm(this)) - goto free; - wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); - wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); - - switch (sig_id) { - case WL3501_SIG_DEAUTH_IND: - case WL3501_SIG_DISASSOC_IND: - case WL3501_SIG_ALARM: - wl3501_alarm_interrupt(dev, this); - break; - case WL3501_SIG_MD_CONFIRM: - wl3501_md_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_MD_IND: - wl3501_md_ind_interrupt(dev, this, addr); - break; - case WL3501_SIG_GET_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - break; - case WL3501_SIG_PWR_MGMT_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_pwr_mgmt_confirm, - sizeof(this->sig_pwr_mgmt_confirm)); - break; - case WL3501_SIG_START_CONFIRM: - wl3501_start_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_SCAN_CONFIRM: - wl3501_mgmt_scan_confirm(this, addr); - break; - case WL3501_SIG_JOIN_CONFIRM: - wl3501_mgmt_join_confirm(dev, addr); - break; - case WL3501_SIG_ASSOC_CONFIRM: - wl3501_assoc_confirm_interrupt(dev, addr); - break; - case WL3501_SIG_AUTH_CONFIRM: - wl3501_auth_confirm_interrupt(this, addr); - break; - case WL3501_SIG_RESYNC_CONFIRM: - wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ - break; - } - wl3501_esbq_confirm_done(this); - morepkts = 1; - /* free request if necessary */ -free: - wl3501_esbq_req_free(this); - if (morepkts) - goto loop; -} - -static inline void wl3501_ack_interrupt(struct wl3501_card *this) -{ - wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); -} - -/** - * wl3501_interrupt - Hardware interrupt from card. - * @irq: Interrupt number - * @dev_id: net_device - * - * We must acknowledge the interrupt as soon as possible, and block the - * interrupt from the same card immediately to prevent re-entry. - * - * Before accessing the Control_Status_Block, we must lock SUTRO first. - * On the other hand, to prevent SUTRO from malfunctioning, we must - * unlock the SUTRO as soon as possible. - */ -static irqreturn_t wl3501_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct wl3501_card *this; - - this = netdev_priv(dev); - spin_lock(&this->lock); - wl3501_ack_interrupt(this); - wl3501_block_interrupt(this); - wl3501_rx_interrupt(dev); - wl3501_unblock_interrupt(this); - spin_unlock(&this->lock); - - return IRQ_HANDLED; -} - -static int wl3501_reset_board(struct wl3501_card *this) -{ - u8 tmp = 0; - int i, rc = 0; - - /* Coreset */ - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - - /* Reset SRAM 0x480 to zero */ - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - - /* Start up */ - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - - WL3501_NOPLOOP(1024 * 50); - - wl3501_unblock_interrupt(this); /* acme: was commented */ - - /* Polling Self_Test_Status */ - for (i = 0; i < 10000; i++) { - wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); - - if (tmp == 'W') { - /* firmware complete all test successfully */ - tmp = 'A'; - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - goto out; - } - WL3501_NOPLOOP(10); - } - printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); - rc = -ENODEV; -out: - return rc; -} - -static int wl3501_init_firmware(struct wl3501_card *this) -{ - u16 ptr, next; - int rc = wl3501_reset_board(this); - - if (rc) - goto fail; - this->card_name[0] = '\0'; - wl3501_get_from_wla(this, 0x1a00, - this->card_name, sizeof(this->card_name)); - this->card_name[sizeof(this->card_name) - 1] = '\0'; - this->firmware_date[0] = '\0'; - wl3501_get_from_wla(this, 0x1a40, - this->firmware_date, sizeof(this->firmware_date)); - this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; - /* Switch to SRAM Page 0 */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - /* Read parameter from card */ - wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); - wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); - wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); - wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); - wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); - wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); - this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; - this->esbq_req_end += this->esbq_req_start; - this->esbq_confirm = this->esbq_confirm_start; - this->esbq_confirm_end += this->esbq_confirm_start; - /* Initial Tx Buffer */ - this->tx_buffer_cnt = 1; - ptr = this->tx_buffer_head; - next = ptr + WL3501_BLKSZ; - while ((next - this->tx_buffer_head) < this->tx_buffer_size) { - this->tx_buffer_cnt++; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - ptr = next; - next = ptr + WL3501_BLKSZ; - } - rc = 0; - next = 0; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; -out: - return rc; -fail: - printk(KERN_WARNING "%s: failed!\n", __func__); - goto out; -} - -static int wl3501_close(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - link->open--; - - /* Stop wl3501_hard_start_xmit() from now on */ - netif_stop_queue(dev); - wl3501_ack_interrupt(this); - - /* Mask interrupts from the SUTRO */ - wl3501_block_interrupt(this); - - printk(KERN_INFO "%s: WL3501 closed\n", dev->name); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -/** - * wl3501_reset - Reset the SUTRO. - * @dev: network device - * - * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() - * and wl3501_open() again, but I wouldn't like to free_irq() when the driver - * is running. It seems to be dangerous. - */ -static int wl3501_reset(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -ENODEV; - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wl3501_block_interrupt(this); - - if (wl3501_init_firmware(this)) { - printk(KERN_WARNING "%s: Can't initialize Firmware!\n", - dev->name); - /* Free IRQ, and mark IRQ as unused */ - free_irq(dev->irq, dev); - goto out; - } - - /* - * Queue has to be started only when the Card is Started - */ - netif_stop_queue(dev); - this->adhoc_times = 0; - wl3501_ack_interrupt(this); - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - pr_debug("%s: device reset", dev->name); - rc = 0; -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -} - -static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct net_device_stats *stats = &dev->stats; - int rc; - - stats->tx_errors++; - rc = wl3501_reset(dev); - if (rc) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, rc); - else { - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); - } -} - -/* - * Return : 0 - OK - * 1 - Could not transmit (dev_queue_xmit will queue it) - * and try to sent it later - */ -static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int enabled, rc; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - enabled = wl3501_block_interrupt(this); - rc = wl3501_send_pkt(this, skb->data, skb->len); - if (enabled) - wl3501_unblock_interrupt(this); - if (rc) { - ++dev->stats.tx_dropped; - netif_stop_queue(dev); - } else { - ++dev->stats.tx_packets; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - if (this->tx_buffer_cnt < 2) - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&this->lock, flags); - return NETDEV_TX_OK; -} - -static int wl3501_open(struct net_device *dev) -{ - int rc = -ENODEV; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - if (!pcmcia_dev_present(link)) - goto out; - netif_device_attach(dev); - link->open++; - - /* Initial WL3501 firmware */ - pr_debug("%s: Initialize WL3501 firmware...", dev->name); - if (wl3501_init_firmware(this)) - goto fail; - /* Initial device variables */ - this->adhoc_times = 0; - /* Acknowledge Interrupt, for cleaning last state */ - wl3501_ack_interrupt(this); - - /* Enable interrupt from card after all */ - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - rc = 0; - pr_debug("%s: WL3501 opened", dev->name); - printk(KERN_INFO "%s: Card Name: %s\n" - "%s: Firmware Date: %s\n", - dev->name, this->card_name, - dev->name, this->firmware_date); -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -fail: - printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); - goto out; -} - -static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - struct iw_statistics *wstats = &this->wstats; - u32 value; /* size checked: it is u32 */ - - memset(wstats, 0, sizeof(*wstats)); - wstats->status = netif_running(dev); - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, - &value, sizeof(value))) - wstats->discard.retries = value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - return wstats; -} - -/** - * wl3501_detach - deletes a driver "instance" - * @link: FILL_IN - * - * This deletes a driver "instance". The device is de-registered with Card - * Services. If it has been released, all local data structures are freed. - * Otherwise, the structures will be freed when the device is released. - */ -static void wl3501_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* If the device is currently configured and active, we won't actually - * delete it yet. Instead, it is marked so that when the release() - * function is called, that will trigger a proper detach(). */ - - while (link->open > 0) - wl3501_close(dev); - - netif_device_detach(dev); - wl3501_release(link); - - unregister_netdev(dev); - free_netdev(dev); -} - -static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); - return 0; -} - -static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int channel = wrqu->freq.m; - int rc = -EINVAL; - - if (iw_valid_channel(this->reg_domain, channel)) { - this->chan = channel; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->freq.m = 100000 * - ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ); - wrqu->freq.e = 1; - return 0; -} - -static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int rc = -EINVAL; - - if (wrqu->mode == IW_MODE_INFRA || - wrqu->mode == IW_MODE_ADHOC || - wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = netdev_priv(dev); - - this->net_type = wrqu->mode; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->mode = this->net_type; - return 0; -} - -static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->sens.value = this->rssi; - wrqu->sens.disabled = !wrqu->sens.value; - wrqu->sens.fixed = 1; - return 0; -} - -static int wl3501_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(*range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(*range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 1; - range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ - /* FIXME: study the code to fill in more fields... */ - return 0; -} - -static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -EINVAL; - - /* FIXME: we support other ARPHRDs...*/ - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - goto out; - if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) { - /* FIXME: rescan? */ - } else - memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - /* FIXME: rescan? deassoc & scan? */ - rc = 0; -out: - return rc; -} - -static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); - return 0; -} - -static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: trigger scanning with a reset, yes, I'm lazy - */ - return wl3501_reset(dev); -} - -static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - for (i = 0; i < this->bss_cnt; ++i) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.u.data.length = this->bss_set[i].req.ssid.el.len; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, - this->bss_set[i].req.ssid.essid); - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = this->bss_set[i].req.bss_type; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - iwe.cmd = SIOCGIWENCODE; - if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - /* Length of data */ - wrqu->data.length = (current_ev - extra); - wrqu->data.flags = 0; /* FIXME: set properly these flags */ - return 0; -} - -static int wl3501_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.flags) { - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, - extra, wrqu->data.length); - } else { /* We accept any ESSID */ - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, "ANY", 3); - } - return wl3501_reset(dev); -} - -static int wl3501_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wrqu->essid.flags = 1; - wrqu->essid.length = this->essid.el.len; - memcpy(extra, this->essid.essid, this->essid.el.len); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.length > sizeof(this->nick)) - return -E2BIG; - strscpy(this->nick, extra, wrqu->data.length); - return 0; -} - -static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - strscpy(extra, this->nick, 32); - wrqu->data.length = strlen(extra); - return 0; -} - -static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: have to see from where to get this info, perhaps this card - * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most - * common with the Planet Access Points. -acme - */ - wrqu->bitrate.value = 2000000; - wrqu->bitrate.fixed = 1; - return 0; -} - -static int wl3501_get_rts_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->rts.value = threshold; - wrqu->rts.disabled = threshold >= 2347; - wrqu->rts.fixed = 1; - } - return rc; -} - -static int wl3501_get_frag_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->frag.value = threshold; - wrqu->frag.disabled = threshold >= 2346; - wrqu->frag.fixed = 1; - } - return rc; -} - -static int wl3501_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 txpow; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - &txpow, sizeof(txpow)); - if (!rc) { - wrqu->txpower.value = txpow; - wrqu->txpower.disabled = 0; - /* - * From the MIB values I think this can be configurable, - * as it lists several tx power levels -acme - */ - wrqu->txpower.fixed = 0; - wrqu->txpower.flags = IW_TXPOW_MWATT; - } - return rc; -} - -static int wl3501_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - goto set_value; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; -set_value: - wrqu->retry.value = retry; - wrqu->retry.disabled = 0; -out: - return rc; -} - -static int wl3501_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - &implemented, sizeof(implemented)); - if (rc) - goto out; - if (!implemented) { - wrqu->encoding.flags = IW_ENCODE_DISABLED; - goto out; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - &restricted, sizeof(restricted)); - if (rc) - goto out; - wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : - IW_ENCODE_OPEN; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - &len_keys, sizeof(len_keys)); - if (rc) - goto out; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - keys, len_keys); - if (rc) - goto out; - tocopy = min_t(u16, len_keys, wrqu->encoding.length); - tocopy = min_t(u8, tocopy, 100); - wrqu->encoding.length = tocopy; - memcpy(extra, keys, tocopy); -out: - return rc; -} - -static int wl3501_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 pwr_state; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - &pwr_state, sizeof(pwr_state)); - if (rc) - goto out; - wrqu->power.disabled = !pwr_state; - wrqu->power.flags = IW_POWER_ON; -out: - return rc; -} - -static const iw_handler wl3501_handler[] = { - IW_HANDLER(SIOCGIWNAME, wl3501_get_name), - IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq), - IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq), - IW_HANDLER(SIOCSIWMODE, wl3501_set_mode), - IW_HANDLER(SIOCGIWMODE, wl3501_get_mode), - IW_HANDLER(SIOCGIWSENS, wl3501_get_sens), - IW_HANDLER(SIOCGIWRANGE, wl3501_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, wl3501_set_wap), - IW_HANDLER(SIOCGIWAP, wl3501_get_wap), - IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan), - IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan), - IW_HANDLER(SIOCSIWESSID, wl3501_set_essid), - IW_HANDLER(SIOCGIWESSID, wl3501_get_essid), - IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick), - IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick), - IW_HANDLER(SIOCGIWRATE, wl3501_get_rate), - IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold), - IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold), - IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow), - IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry), - IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode), - IW_HANDLER(SIOCGIWPOWER, wl3501_get_power), -}; - -static const struct iw_handler_def wl3501_handler_def = { - .num_standard = ARRAY_SIZE(wl3501_handler), - .standard = (iw_handler *)wl3501_handler, - .get_wireless_stats = wl3501_get_wireless_stats, -}; - -static const struct net_device_ops wl3501_netdev_ops = { - .ndo_open = wl3501_open, - .ndo_stop = wl3501_close, - .ndo_start_xmit = wl3501_hard_start_xmit, - .ndo_tx_timeout = wl3501_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int wl3501_probe(struct pcmcia_device *p_dev) -{ - struct net_device *dev; - struct wl3501_card *this; - int ret; - - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags = CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - dev = alloc_etherdev(sizeof(struct wl3501_card)); - if (!dev) - return -ENOMEM; - - dev->netdev_ops = &wl3501_netdev_ops; - dev->watchdog_timeo = 5 * HZ; - - this = netdev_priv(dev); - this->wireless_data.spy_data = &this->spy_data; - this->p_dev = p_dev; - dev->wireless_data = &this->wireless_data; - dev->wireless_handlers = &wl3501_handler_def; - netif_stop_queue(dev); - p_dev->priv = dev; - - ret = wl3501_config(p_dev); - if (ret) - goto out_free_etherdev; - - return 0; - -out_free_etherdev: - free_netdev(dev); - return ret; -} - -static int wl3501_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i = 0, j, ret; - struct wl3501_card *this; - - /* Try allocating IO ports. This tries a few fixed addresses. If you - * want, you can also read the card's config table to pick addresses -- - * see the serial driver for an example. */ - link->io_lines = 5; - - for (j = 0x280; j < 0x400; j += 0x20) { - /* The '^0x300' is so that we probe 0x300-0x3ff first, then - * 0x200-0x2ff, and so on, because this seems safer */ - link->resource[0]->start = j; - link->resource[1]->start = link->resource[0]->start + 0x10; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - /* Now allocate an interrupt line. Note that this does not actually - * assign a handler to the interrupt. */ - - ret = pcmcia_request_irq(link, wl3501_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - SET_NETDEV_DEV(dev, &link->dev); - if (register_netdev(dev)) { - printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); - goto failed; - } - - this = netdev_priv(dev); - - this->base_addr = dev->base_addr; - - if (!wl3501_get_flash_mac_addr(this)) { - printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n", - dev->name); - unregister_netdev(dev); - goto failed; - } - - eth_hw_addr_set(dev, this->mac_addr); - - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%pM\n", - dev->name, this->base_addr, (int)dev->irq, - dev->dev_addr); - /* - * Initialize card parameters - added by jss - */ - this->net_type = IW_MODE_INFRA; - this->bss_cnt = 0; - this->join_sta_bss = 0; - this->adhoc_times = 0; - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, - "ANY", 3); - this->card_name[0] = '\0'; - this->firmware_date[0] = '\0'; - this->rssi = 255; - this->chan = iw_default_channel(this->reg_domain); - strscpy(this->nick, "Planet WL3501", sizeof(this->nick)); - spin_lock_init(&this->lock); - init_waitqueue_head(&this->wait); - netif_start_queue(dev); - return 0; - -failed: - wl3501_release(link); - return -ENODEV; -} - -static void wl3501_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int wl3501_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int wl3501_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); - if (link->open) { - wl3501_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -static const struct pcmcia_device_id wl3501_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); - -static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .name = "wl3501_cs", - .probe = wl3501_probe, - .remove = wl3501_detach, - .id_table = wl3501_ids, - .suspend = wl3501_suspend, - .resume = wl3501_resume, -}; -module_pcmcia_driver(wl3501_driver); - -MODULE_AUTHOR("Fox Chen , " - "Arnaldo Carvalho de Melo ," - "Gustavo Niemeyer "); -MODULE_DESCRIPTION("Planet wl3501 wireless driver"); -MODULE_LICENSE("GPL"); From bec95598b24a42adba294994ab7a5d8db417cca5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 15:19:51 +0200 Subject: [PATCH 0160/7721] wifi: remove orphaned rndis_wlan driver Wireless RNDIS USB is a new-style CFG80211 driver for 802.11b and 802.11g USB hardware from around 2004 to 2006. This makes it more modern than any of the others, but Kalle already classified it as "legacy" in commit 298e50ad8eb8f ("wifi: move raycs, wl3501 and rndis_wlan to legacy directory"). Jussi Kivilinna worked on this driver between 2008 and 2012, and it has only seen cosmetic updates after that. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- MAINTAINERS | 5 - drivers/net/wireless/Kconfig | 2 - drivers/net/wireless/Makefile | 1 - drivers/net/wireless/legacy/Kconfig | 29 - drivers/net/wireless/legacy/Makefile | 2 - drivers/net/wireless/legacy/rndis_wlan.c | 3760 ---------------------- 6 files changed, 3799 deletions(-) delete mode 100644 drivers/net/wireless/legacy/Kconfig delete mode 100644 drivers/net/wireless/legacy/Makefile delete mode 100644 drivers/net/wireless/legacy/rndis_wlan.c diff --git a/MAINTAINERS b/MAINTAINERS index 9ac0f62e38a9..fca2003efa7b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22417,11 +22417,6 @@ F: drivers/usb/gadget/function/*uvc* F: drivers/usb/gadget/legacy/webcam.c F: include/uapi/linux/usb/g_uvc.h -USB WIRELESS RNDIS DRIVER (rndis_wlan) -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/rndis_wlan.c - USB XHCI DRIVER M: Mathias Nyman L: linux-usb@vger.kernel.org diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 834d3725f1a5..c6599594dc99 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -37,8 +37,6 @@ source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" source "drivers/net/wireless/quantenna/Kconfig" -source "drivers/net/wireless/legacy/Kconfig" - source "drivers/net/wireless/virtual/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ee722439d452..e1c4141c6004 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -22,5 +22,4 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ -obj-$(CONFIG_WLAN) += legacy/ obj-$(CONFIG_WLAN) += virtual/ diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig deleted file mode 100644 index b4e0e516f2fa..000000000000 --- a/drivers/net/wireless/legacy/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config USB_NET_RNDIS_WLAN - tristate "Wireless RNDIS USB support" - depends on USB - depends on CFG80211 - select USB_NET_DRIVERS - select USB_USBNET - select USB_NET_CDCETHER - select USB_NET_RNDIS_HOST - help - This is a driver for wireless RNDIS devices. - These are USB based adapters found in devices such as: - - Buffalo WLI-U2-KG125S - U.S. Robotics USR5421 - Belkin F5D7051 - Linksys WUSB54GSv2 - Linksys WUSB54GSC - Asus WL169gE - Eminent EM4045 - BT Voyager 1055 - Linksys WUSB54GSv1 - U.S. Robotics USR5420 - BUFFALO WLI-USB-G54 - - All of these devices are based on Broadcom 4320 chip which is the - only wireless RNDIS chip known to date. - - If you choose to build a module, it'll be called rndis_wlan. - diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile deleted file mode 100644 index 1ed83f33ad20..000000000000 --- a/drivers/net/wireless/legacy/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o - diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c deleted file mode 100644 index e7fea7ded6d5..000000000000 --- a/drivers/net/wireless/legacy/rndis_wlan.c +++ /dev/null @@ -1,3760 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for RNDIS based USB wireless devices. - * - * Copyright (C) 2007 by Bjorge Dijkstra - * Copyright (C) 2008-2009 by Jussi Kivilinna - * - * Portions of this file are based on NDISwrapper project, - * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani - * http://ndiswrapper.sourceforge.net/ - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* NOTE: All these are settings for Broadcom chipset */ -static char modparam_country[4] = "EU"; -module_param_string(country, modparam_country, 4, 0444); -MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU"); - -static int modparam_frameburst = 1; -module_param_named(frameburst, modparam_frameburst, int, 0444); -MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)"); - -static int modparam_afterburner = 0; -module_param_named(afterburner, modparam_afterburner, int, 0444); -MODULE_PARM_DESC(afterburner, - "enable afterburner aka '125 High Speed Mode' (default: off)"); - -static int modparam_power_save = 0; -module_param_named(power_save, modparam_power_save, int, 0444); -MODULE_PARM_DESC(power_save, - "set power save mode: 0=off, 1=on, 2=fast (default: off)"); - -static int modparam_power_output = 3; -module_param_named(power_output, modparam_power_output, int, 0444); -MODULE_PARM_DESC(power_output, - "set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)"); - -static int modparam_roamtrigger = -70; -module_param_named(roamtrigger, modparam_roamtrigger, int, 0444); -MODULE_PARM_DESC(roamtrigger, - "set roaming dBm trigger: -80=optimize for distance, " - "-60=bandwidth (default: -70)"); - -static int modparam_roamdelta = 1; -module_param_named(roamdelta, modparam_roamdelta, int, 0444); -MODULE_PARM_DESC(roamdelta, - "set roaming tendency: 0=aggressive, 1=moderate, " - "2=conservative (default: moderate)"); - -static int modparam_workaround_interval; -module_param_named(workaround_interval, modparam_workaround_interval, - int, 0444); -MODULE_PARM_DESC(workaround_interval, - "set stall workaround interval in msecs (0=disabled) (default: 0)"); - -/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */ -#define WL_NOISE -96 /* typical noise level in dBm */ -#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ - - -/* Assume that Broadcom 4320 (only chipset at time of writing known to be - * based on wireless rndis) has default txpower of 13dBm. - * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications. - * 100% : 20 mW ~ 13dBm - * 75% : 15 mW ~ 12dBm - * 50% : 10 mW ~ 10dBm - * 25% : 5 mW ~ 7dBm - */ -#define BCM4320_DEFAULT_TXPOWER_DBM_100 13 -#define BCM4320_DEFAULT_TXPOWER_DBM_75 12 -#define BCM4320_DEFAULT_TXPOWER_DBM_50 10 -#define BCM4320_DEFAULT_TXPOWER_DBM_25 7 - -/* Known device types */ -#define RNDIS_UNKNOWN 0 -#define RNDIS_BCM4320A 1 -#define RNDIS_BCM4320B 2 - - -/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c - * slightly modified for datatype endianess, etc - */ -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 - -enum ndis_80211_net_type { - NDIS_80211_TYPE_FREQ_HOP, - NDIS_80211_TYPE_DIRECT_SEQ, - NDIS_80211_TYPE_OFDM_A, - NDIS_80211_TYPE_OFDM_G -}; - -enum ndis_80211_net_infra { - NDIS_80211_INFRA_ADHOC, - NDIS_80211_INFRA_INFRA, - NDIS_80211_INFRA_AUTO_UNKNOWN -}; - -enum ndis_80211_auth_mode { - NDIS_80211_AUTH_OPEN, - NDIS_80211_AUTH_SHARED, - NDIS_80211_AUTH_AUTO_SWITCH, - NDIS_80211_AUTH_WPA, - NDIS_80211_AUTH_WPA_PSK, - NDIS_80211_AUTH_WPA_NONE, - NDIS_80211_AUTH_WPA2, - NDIS_80211_AUTH_WPA2_PSK -}; - -enum ndis_80211_encr_status { - NDIS_80211_ENCR_WEP_ENABLED, - NDIS_80211_ENCR_DISABLED, - NDIS_80211_ENCR_WEP_KEY_ABSENT, - NDIS_80211_ENCR_NOT_SUPPORTED, - NDIS_80211_ENCR_TKIP_ENABLED, - NDIS_80211_ENCR_TKIP_KEY_ABSENT, - NDIS_80211_ENCR_CCMP_ENABLED, - NDIS_80211_ENCR_CCMP_KEY_ABSENT -}; - -enum ndis_80211_priv_filter { - NDIS_80211_PRIV_ACCEPT_ALL, - NDIS_80211_PRIV_8021X_WEP -}; - -enum ndis_80211_status_type { - NDIS_80211_STATUSTYPE_AUTHENTICATION, - NDIS_80211_STATUSTYPE_MEDIASTREAMMODE, - NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST, - NDIS_80211_STATUSTYPE_RADIOSTATE, -}; - -enum ndis_80211_media_stream_mode { - NDIS_80211_MEDIA_STREAM_OFF, - NDIS_80211_MEDIA_STREAM_ON -}; - -enum ndis_80211_radio_status { - NDIS_80211_RADIO_STATUS_ON, - NDIS_80211_RADIO_STATUS_HARDWARE_OFF, - NDIS_80211_RADIO_STATUS_SOFTWARE_OFF, -}; - -enum ndis_80211_addkey_bits { - NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), - NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), - NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_addwep_bits { - NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_power_mode { - NDIS_80211_POWER_MODE_CAM, - NDIS_80211_POWER_MODE_MAX_PSP, - NDIS_80211_POWER_MODE_FAST_PSP, -}; - -enum ndis_80211_pmkid_cand_list_flag_bits { - NDIS_80211_PMKID_CAND_PREAUTH = cpu_to_le32(1 << 0) -}; - -struct ndis_80211_auth_request { - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_candidate { - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_cand_list { - __le32 version; - __le32 num_candidates; - struct ndis_80211_pmkid_candidate candidate_list[]; -} __packed; - -struct ndis_80211_status_indication { - __le32 status_type; - union { - __le32 media_stream_mode; - __le32 radio_status; - DECLARE_FLEX_ARRAY(struct ndis_80211_auth_request, auth_request); - struct ndis_80211_pmkid_cand_list cand_list; - } u; -} __packed; - -struct ndis_80211_ssid { - __le32 length; - u8 essid[NDIS_802_11_LENGTH_SSID]; -} __packed; - -struct ndis_80211_conf_freq_hop { - __le32 length; - __le32 hop_pattern; - __le32 hop_set; - __le32 dwell_time; -} __packed; - -struct ndis_80211_conf { - __le32 length; - __le32 beacon_period; - __le32 atim_window; - __le32 ds_config; - struct ndis_80211_conf_freq_hop fh_config; -} __packed; - -struct ndis_80211_bssid_ex { - __le32 length; - u8 mac[ETH_ALEN]; - u8 padding[2]; - struct ndis_80211_ssid ssid; - __le32 privacy; - __le32 rssi; - __le32 net_type; - struct ndis_80211_conf config; - __le32 net_infra; - u8 rates[NDIS_802_11_LENGTH_RATES_EX]; - __le32 ie_length; - u8 ies[]; -} __packed; - -struct ndis_80211_bssid_list_ex { - __le32 num_items; - u8 bssid_data[]; -} __packed; - -struct ndis_80211_fixed_ies { - u8 timestamp[8]; - __le16 beacon_interval; - __le16 capabilities; -} __packed; - -struct ndis_80211_wep_key { - __le32 size; - __le32 index; - __le32 length; - u8 material[32]; -} __packed; - -struct ndis_80211_key { - __le32 size; - __le32 index; - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[6]; - u8 rsc[8]; - u8 material[32]; -} __packed; - -struct ndis_80211_remove_key { - __le32 size; - __le32 index; - u8 bssid[ETH_ALEN]; - u8 padding[2]; -} __packed; - -struct ndis_config_param { - __le32 name_offs; - __le32 name_length; - __le32 type; - __le32 value_offs; - __le32 value_length; -} __packed; - -struct ndis_80211_assoc_info { - __le32 length; - __le16 req_ies; - struct req_ie { - __le16 capa; - __le16 listen_interval; - u8 cur_ap_address[ETH_ALEN]; - } req_ie; - __le32 req_ie_length; - __le32 offset_req_ies; - __le16 resp_ies; - struct resp_ie { - __le16 capa; - __le16 status_code; - __le16 assoc_id; - } resp_ie; - __le32 resp_ie_length; - __le32 offset_resp_ies; -} __packed; - -struct ndis_80211_capability { - __le32 length; - __le32 version; - __le32 num_pmkids; - __le32 num_auth_encr_pair; -} __packed; - -struct ndis_80211_bssid_info { - u8 bssid[ETH_ALEN]; - u8 pmkid[16]; -} __packed; - -struct ndis_80211_pmkid { - __le32 length; - __le32 bssid_info_count; - struct ndis_80211_bssid_info bssid_info[]; -} __packed; - -/* - * private data - */ -#define CAP_MODE_80211A 1 -#define CAP_MODE_80211B 2 -#define CAP_MODE_80211G 4 -#define CAP_MODE_MASK 7 - -#define WORK_LINK_UP 0 -#define WORK_LINK_DOWN 1 -#define WORK_SET_MULTICAST_LIST 2 - -#define RNDIS_WLAN_ALG_NONE 0 -#define RNDIS_WLAN_ALG_WEP (1<<0) -#define RNDIS_WLAN_ALG_TKIP (1<<1) -#define RNDIS_WLAN_ALG_CCMP (1<<2) - -#define RNDIS_WLAN_NUM_KEYS 4 -#define RNDIS_WLAN_KEY_MGMT_NONE 0 -#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) -#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) - -#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) - -static const struct ieee80211_channel rndis_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static const struct ieee80211_rate rndis_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60 }, - { .bitrate = 90 }, - { .bitrate = 120 }, - { .bitrate = 180 }, - { .bitrate = 240 }, - { .bitrate = 360 }, - { .bitrate = 480 }, - { .bitrate = 540 } -}; - -static const u32 rndis_cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, -}; - -struct rndis_wlan_encr_key { - int len; - u32 cipher; - u8 material[32]; - u8 bssid[ETH_ALEN]; - bool pairwise; - bool tx_key; -}; - -/* RNDIS device private data */ -struct rndis_wlan_private { - struct usbnet *usbdev; - - struct wireless_dev wdev; - - struct cfg80211_scan_request *scan_request; - - struct workqueue_struct *workqueue; - struct delayed_work dev_poller_work; - struct delayed_work scan_work; - struct work_struct work; - struct mutex command_lock; - unsigned long work_pending; - int last_qual; - s32 cqm_rssi_thold; - u32 cqm_rssi_hyst; - int last_cqm_event_rssi; - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; - u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; - - int device_type; - int caps; - int multicast_size; - - /* module parameters */ - char param_country[4]; - int param_frameburst; - int param_afterburner; - int param_power_save; - int param_power_output; - int param_roamtrigger; - int param_roamdelta; - u32 param_workaround_interval; - - /* hardware state */ - bool radio_on; - int power_mode; - int infra_mode; - bool connected; - u8 bssid[ETH_ALEN]; - u32 current_command_oid; - - /* encryption stuff */ - u8 encr_tx_key_index; - struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS]; - int wpa_version; - - u8 command_buffer[COMMAND_BUFFER_SIZE]; -}; - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params); - -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request); - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm); -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm); - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code); - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params); - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr); - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast); - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo); - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo); - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev); - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout); - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst); - -static const struct cfg80211_ops rndis_config_ops = { - .change_virtual_intf = rndis_change_virtual_intf, - .scan = rndis_scan, - .set_wiphy_params = rndis_set_wiphy_params, - .set_tx_power = rndis_set_tx_power, - .get_tx_power = rndis_get_tx_power, - .connect = rndis_connect, - .disconnect = rndis_disconnect, - .join_ibss = rndis_join_ibss, - .leave_ibss = rndis_leave_ibss, - .add_key = rndis_add_key, - .del_key = rndis_del_key, - .set_default_key = rndis_set_default_key, - .get_station = rndis_get_station, - .dump_station = rndis_dump_station, - .set_pmksa = rndis_set_pmksa, - .del_pmksa = rndis_del_pmksa, - .flush_pmksa = rndis_flush_pmksa, - .set_power_mgmt = rndis_set_power_mgmt, - .set_cqm_rssi_config = rndis_set_cqm_rssi_config, -}; - -static void *rndis_wiphy_privid = &rndis_wiphy_privid; - - -static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) -{ - return (struct rndis_wlan_private *)dev->driver_priv; -} - -static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) -{ - switch (priv->param_power_output) { - default: - case 3: - return BCM4320_DEFAULT_TXPOWER_DBM_100; - case 2: - return BCM4320_DEFAULT_TXPOWER_DBM_75; - case 1: - return BCM4320_DEFAULT_TXPOWER_DBM_50; - case 0: - return BCM4320_DEFAULT_TXPOWER_DBM_25; - } -} - -static bool is_wpa_key(struct rndis_wlan_private *priv, u8 idx) -{ - int cipher = priv->encr_keys[idx].cipher; - - return (cipher == WLAN_CIPHER_SUITE_CCMP || - cipher == WLAN_CIPHER_SUITE_TKIP); -} - -static int rndis_cipher_to_alg(u32 cipher) -{ - switch (cipher) { - default: - return RNDIS_WLAN_ALG_NONE; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return RNDIS_WLAN_ALG_WEP; - case WLAN_CIPHER_SUITE_TKIP: - return RNDIS_WLAN_ALG_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return RNDIS_WLAN_ALG_CCMP; - } -} - -static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) -{ - switch (akm_suite) { - default: - return RNDIS_WLAN_KEY_MGMT_NONE; - case WLAN_AKM_SUITE_8021X: - return RNDIS_WLAN_KEY_MGMT_802_1X; - case WLAN_AKM_SUITE_PSK: - return RNDIS_WLAN_KEY_MGMT_PSK; - } -} - -#ifdef DEBUG -static const char *oid_to_string(u32 oid) -{ - switch (oid) { -#define OID_STR(oid) case oid: return(#oid) - /* from rndis_host.h */ - OID_STR(RNDIS_OID_802_3_PERMANENT_ADDRESS); - OID_STR(RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE); - OID_STR(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); - OID_STR(RNDIS_OID_GEN_PHYSICAL_MEDIUM); - - /* from rndis_wlan.c */ - OID_STR(RNDIS_OID_GEN_LINK_SPEED); - OID_STR(RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER); - - OID_STR(RNDIS_OID_GEN_XMIT_OK); - OID_STR(RNDIS_OID_GEN_RCV_OK); - OID_STR(RNDIS_OID_GEN_XMIT_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_NO_BUFFER); - - OID_STR(RNDIS_OID_802_3_CURRENT_ADDRESS); - OID_STR(RNDIS_OID_802_3_MULTICAST_LIST); - OID_STR(RNDIS_OID_802_3_MAXIMUM_LIST_SIZE); - - OID_STR(RNDIS_OID_802_11_BSSID); - OID_STR(RNDIS_OID_802_11_SSID); - OID_STR(RNDIS_OID_802_11_INFRASTRUCTURE_MODE); - OID_STR(RNDIS_OID_802_11_ADD_WEP); - OID_STR(RNDIS_OID_802_11_REMOVE_WEP); - OID_STR(RNDIS_OID_802_11_DISASSOCIATE); - OID_STR(RNDIS_OID_802_11_AUTHENTICATION_MODE); - OID_STR(RNDIS_OID_802_11_PRIVACY_FILTER); - OID_STR(RNDIS_OID_802_11_BSSID_LIST_SCAN); - OID_STR(RNDIS_OID_802_11_ENCRYPTION_STATUS); - OID_STR(RNDIS_OID_802_11_ADD_KEY); - OID_STR(RNDIS_OID_802_11_REMOVE_KEY); - OID_STR(RNDIS_OID_802_11_ASSOCIATION_INFORMATION); - OID_STR(RNDIS_OID_802_11_CAPABILITY); - OID_STR(RNDIS_OID_802_11_PMKID); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPE_IN_USE); - OID_STR(RNDIS_OID_802_11_TX_POWER_LEVEL); - OID_STR(RNDIS_OID_802_11_RSSI); - OID_STR(RNDIS_OID_802_11_RSSI_TRIGGER); - OID_STR(RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD); - OID_STR(RNDIS_OID_802_11_RTS_THRESHOLD); - OID_STR(RNDIS_OID_802_11_SUPPORTED_RATES); - OID_STR(RNDIS_OID_802_11_CONFIGURATION); - OID_STR(RNDIS_OID_802_11_POWER_MODE); - OID_STR(RNDIS_OID_802_11_BSSID_LIST); -#undef OID_STR - } - - return "?"; -} -#else -static const char *oid_to_string(u32 oid) -{ - return "?"; -} -#endif - -/* translate error code */ -static int rndis_error_status(__le32 rndis_status) -{ - int ret = -EINVAL; - switch (le32_to_cpu(rndis_status)) { - case RNDIS_STATUS_SUCCESS: - ret = 0; - break; - case RNDIS_STATUS_FAILURE: - case RNDIS_STATUS_INVALID_DATA: - ret = -EINVAL; - break; - case RNDIS_STATUS_NOT_SUPPORTED: - ret = -EOPNOTSUPP; - break; - case RNDIS_STATUS_ADAPTER_NOT_READY: - case RNDIS_STATUS_ADAPTER_NOT_OPEN: - ret = -EBUSY; - break; - } - return ret; -} - -static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_query *get; - struct rndis_query_c *get_c; - } u; - int ret; - size_t buflen, resplen, respoffs, copylen; - - buflen = *len + sizeof(*u.get); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.get, 0, sizeof *u.get); - u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); - u.get->msg_len = cpu_to_le32(sizeof *u.get); - u.get->oid = cpu_to_le32(oid); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.get_c->status)); - - if (ret == 0) { - resplen = le32_to_cpu(u.get_c->len); - respoffs = le32_to_cpu(u.get_c->offset) + 8; - - if (respoffs > buflen) { - /* Device returned data offset outside buffer, error. */ - netdev_dbg(dev->net, - "%s(%s): received invalid data offset: %zu > %zu\n", - __func__, oid_to_string(oid), respoffs, buflen); - - ret = -EINVAL; - goto exit_unlock; - } - - copylen = min(resplen, buflen - respoffs); - - if (copylen > *len) - copylen = *len; - - memcpy(data, u.buf + respoffs, copylen); - - *len = resplen; - - ret = rndis_error_status(u.get_c->status); - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.get_c->status), ret); - } - -exit_unlock: - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_set_oid(struct usbnet *dev, u32 oid, const void *data, - int len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_set *set; - struct rndis_set_c *set_c; - } u; - int ret, buflen; - - buflen = len + sizeof(*u.set); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.set, 0, sizeof *u.set); - u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); - u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len); - u.set->oid = cpu_to_le32(oid); - u.set->len = cpu_to_le32(len); - u.set->offset = cpu_to_le32(sizeof(*u.set) - 8); - u.set->handle = cpu_to_le32(0); - memcpy(u.buf + sizeof(*u.set), data, len); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.set_c->status)); - - if (ret == 0) { - ret = rndis_error_status(u.set_c->status); - - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.set_c->status), ret); - } - - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_reset *reset; - int ret; - - mutex_lock(&priv->command_lock); - - reset = (void *)priv->command_buffer; - memset(reset, 0, sizeof(*reset)); - reset->msg_type = cpu_to_le32(RNDIS_MSG_RESET); - reset->msg_len = cpu_to_le32(sizeof(*reset)); - priv->current_command_oid = 0; - ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); - - mutex_unlock(&priv->command_lock); - - if (ret < 0) - return ret; - return 0; -} - -/* - * Specs say that we can only set config parameters only soon after device - * initialization. - * value_type: 0 = u32, 2 = unicode string - */ -static int rndis_set_config_parameter(struct usbnet *dev, char *param, - int value_type, void *value) -{ - struct ndis_config_param *infobuf; - int value_len, info_len, param_len, ret, i; - __le16 *unibuf; - __le32 *dst_value; - - if (value_type == 0) - value_len = sizeof(__le32); - else if (value_type == 2) - value_len = strlen(value) * sizeof(__le16); - else - return -EINVAL; - - param_len = strlen(param) * sizeof(__le16); - info_len = sizeof(*infobuf) + param_len + value_len; - -#ifdef DEBUG - info_len += 12; -#endif - infobuf = kmalloc(info_len, GFP_KERNEL); - if (!infobuf) - return -ENOMEM; - -#ifdef DEBUG - info_len -= 12; - /* extra 12 bytes are for padding (debug output) */ - memset(infobuf, 0xCC, info_len + 12); -#endif - - if (value_type == 2) - netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n", - param, (u8 *)value); - else - netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n", - param, *(u32 *)value); - - infobuf->name_offs = cpu_to_le32(sizeof(*infobuf)); - infobuf->name_length = cpu_to_le32(param_len); - infobuf->type = cpu_to_le32(value_type); - infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len); - infobuf->value_length = cpu_to_le32(value_len); - - /* simple string to unicode string conversion */ - unibuf = (void *)infobuf + sizeof(*infobuf); - for (i = 0; i < param_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(param[i]); - - if (value_type == 2) { - unibuf = (void *)infobuf + sizeof(*infobuf) + param_len; - for (i = 0; i < value_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(((u8 *)value)[i]); - } else { - dst_value = (void *)infobuf + sizeof(*infobuf) + param_len; - *dst_value = cpu_to_le32(*(u32 *)value); - } - -#ifdef DEBUG - netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len); - for (i = 0; i < info_len; i += 12) { - u32 *tmp = (u32 *)((u8 *)infobuf + i); - netdev_dbg(dev->net, "%08X:%08X:%08X\n", - cpu_to_be32(tmp[0]), - cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2])); - } -#endif - - ret = rndis_set_oid(dev, RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER, - infobuf, info_len); - if (ret != 0) - netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n", - ret); - - kfree(infobuf); - return ret; -} - -static int rndis_set_config_parameter_str(struct usbnet *dev, - char *param, char *value) -{ - return rndis_set_config_parameter(dev, param, 2, value); -} - -/* - * data conversion functions - */ -static int level_to_qual(int level) -{ - int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE); - return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; -} - -/* - * common functions - */ -static int set_infra_mode(struct usbnet *usbdev, int mode); -static void restore_keys(struct usbnet *usbdev); -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched); - -static int rndis_start_bssid_list_scan(struct usbnet *usbdev) -{ - __le32 tmp; - - /* Note: RNDIS_OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ - tmp = cpu_to_le32(1); - return rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); -} - -static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_SSID, - ssid, sizeof(*ssid)); - if (ret < 0) { - netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret); - return ret; - } - if (ret == 0) { - priv->radio_on = true; - netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__); - } - - return ret; -} - -static int set_bssid(struct usbnet *usbdev, const u8 *bssid) -{ - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, ETH_ALEN); - if (ret < 0) { - netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n", - bssid, ret); - return ret; - } - - return ret; -} - -static int clear_bssid(struct usbnet *usbdev) -{ - static const u8 broadcast_mac[ETH_ALEN] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - return set_bssid(usbdev, broadcast_mac); -} - -static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) -{ - int ret, len; - - len = ETH_ALEN; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, &len); - - if (ret != 0) - eth_zero_addr(bssid); - - return ret; -} - -static int get_association_info(struct usbnet *usbdev, - struct ndis_80211_assoc_info *info, int len) -{ - return rndis_query_oid(usbdev, - RNDIS_OID_802_11_ASSOCIATION_INFORMATION, - info, &len); -} - -static bool is_associated(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - u8 bssid[ETH_ALEN]; - - if (!priv->radio_on) - return false; - - return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid)); -} - -static int disassociate(struct usbnet *usbdev, bool reset_ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_ssid ssid; - int i, ret = 0; - - if (priv->radio_on) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_DISASSOCIATE, - NULL, 0); - if (ret == 0) { - priv->radio_on = false; - netdev_dbg(usbdev->net, "%s(): radio_on = false\n", - __func__); - - if (reset_ssid) - msleep(100); - } - } - - /* disassociate causes radio to be turned off; if reset_ssid - * is given, set random ssid to enable radio */ - if (reset_ssid) { - /* Set device to infrastructure mode so we don't get ad-hoc - * 'media connect' indications with the random ssid. - */ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - - ssid.length = cpu_to_le32(sizeof(ssid.essid)); - get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); - ssid.essid[0] = 0x1; - ssid.essid[1] = 0xff; - for (i = 2; i < sizeof(ssid.essid); i++) - ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff); - ret = set_essid(usbdev, &ssid); - } - return ret; -} - -static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, - enum nl80211_auth_type auth_type, int keymgmt) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int auth_mode, ret; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n", - __func__, wpa_version, auth_type, keymgmt); - - if (wpa_version & NL80211_WPA_VERSION_2) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA2; - else - auth_mode = NDIS_80211_AUTH_WPA2_PSK; - } else if (wpa_version & NL80211_WPA_VERSION_1) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA; - else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) - auth_mode = NDIS_80211_AUTH_WPA_PSK; - else - auth_mode = NDIS_80211_AUTH_WPA_NONE; - } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) - auth_mode = NDIS_80211_AUTH_SHARED; - else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) - auth_mode = NDIS_80211_AUTH_OPEN; - else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) - auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; - else - return -ENOTSUPP; - - tmp = cpu_to_le32(auth_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_AUTHENTICATION_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n", - ret); - return ret; - } - - priv->wpa_version = wpa_version; - - return 0; -} - -static int set_priv_filter(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n", - __func__, priv->wpa_version); - - if (priv->wpa_version & NL80211_WPA_VERSION_2 || - priv->wpa_version & NL80211_WPA_VERSION_1) - tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); - else - tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); - - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_PRIVACY_FILTER, &tmp, - sizeof(tmp)); -} - -static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) -{ - __le32 tmp; - int encr_mode, ret; - - netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n", - __func__, pairwise, groupwise); - - if (pairwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_WEP) - encr_mode = NDIS_80211_ENCR_WEP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else - encr_mode = NDIS_80211_ENCR_DISABLED; - - tmp = cpu_to_le32(encr_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ENCRYPTION_STATUS, &tmp, - sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n", - ret); - return ret; - } - - return 0; -} - -static int set_infra_mode(struct usbnet *usbdev, int mode) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int ret; - - netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n", - __func__, priv->infra_mode); - - tmp = cpu_to_le32(mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_INFRASTRUCTURE_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n", - ret); - return ret; - } - - /* NDIS drivers clear keys when infrastructure mode is - * changed. But Linux tools assume otherwise. So set the - * keys */ - restore_keys(usbdev); - - priv->infra_mode = mode; - return 0; -} - -static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - - if (rts_threshold == -1 || rts_threshold > 2347) - rts_threshold = 2347; - - tmp = cpu_to_le32(rts_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_RTS_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold); - - if (frag_threshold < 256 || frag_threshold > 2346) - frag_threshold = 2346; - - tmp = cpu_to_le32(frag_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static void set_default_iw_params(struct usbnet *usbdev) -{ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - set_priv_filter(usbdev); - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); -} - -static int deauthenticate(struct usbnet *usbdev) -{ - int ret; - - ret = disassociate(usbdev, true); - set_default_iw_params(usbdev); - return ret; -} - -static int set_channel(struct usbnet *usbdev, int channel) -{ - struct ndis_80211_conf config; - unsigned int dsconfig; - int len, ret; - - netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel); - - /* this OID is valid only when not associated */ - if (is_associated(usbdev)) - return 0; - - dsconfig = 1000 * - ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): querying configuration failed\n", - __func__); - return ret; - } - - config.ds_config = cpu_to_le32(dsconfig); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, sizeof(config)); - - netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret); - - return ret; -} - -static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev, - u32 *beacon_period) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_conf config; - int len, ret; - - /* Get channel and beacon interval */ - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_CONFIGURATION -> %d\n", - __func__, ret); - if (ret < 0) - return NULL; - - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(config.ds_config))); - if (!channel) - return NULL; - - if (beacon_period) - *beacon_period = le32_to_cpu(config.beacon_period); - return channel; -} - -/* index must be 0 - N, as per NDIS */ -static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_wep_key ndis_key; - u32 cipher; - int ret; - - netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n", - __func__, index, key_len); - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -EINVAL; - - if (key_len == 5) - cipher = WLAN_CIPHER_SUITE_WEP40; - else if (key_len == 13) - cipher = WLAN_CIPHER_SUITE_WEP104; - else - return -EINVAL; - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key)); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index); - memcpy(&ndis_key.material, key, key_len); - - if (index == priv->encr_tx_key_index) { - ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; - ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, - RNDIS_WLAN_ALG_NONE); - if (ret) - netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n", - ret); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_WEP, &ndis_key, - sizeof(ndis_key)); - if (ret != 0) { - netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n", - index + 1, ret); - return ret; - } - - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - eth_broadcast_addr(priv->encr_keys[index].bssid); - - return 0; -} - -static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, __le32 flags) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_key ndis_key; - bool is_addr_ok; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) { - netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n", - __func__, index); - return -EINVAL; - } - if (key_len > sizeof(ndis_key.material) || key_len < 0) { - netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n", - __func__, key_len); - return -EINVAL; - } - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { - if (!rx_seq || seq_len <= 0) { - netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n", - __func__); - return -EINVAL; - } - if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { - netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__); - return -EINVAL; - } - } - - is_addr_ok = addr && !is_zero_ether_addr(addr) && - !is_broadcast_ether_addr(addr); - if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { - netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n", - __func__, addr); - return -EINVAL; - } - - netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n", - __func__, index, - !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), - !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), - !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.material) + key_len); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index) | flags; - - if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) { - /* wpa_supplicant gives us the Michael MIC RX/TX keys in - * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.material, key, 16); - memcpy(ndis_key.material + 16, key + 24, 8); - memcpy(ndis_key.material + 24, key + 16, 8); - } else - memcpy(ndis_key.material, key, key_len); - - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) - memcpy(ndis_key.rsc, rx_seq, seq_len); - - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { - /* pairwise key */ - memcpy(ndis_key.bssid, addr, ETH_ALEN); - } else { - /* group key */ - if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - eth_broadcast_addr(ndis_key.bssid); - else - get_bssid(usbdev, ndis_key.bssid); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_ADD_KEY -> %08X\n", - __func__, ret); - if (ret != 0) - return ret; - - memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) - memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN); - else - eth_broadcast_addr(priv->encr_keys[index].bssid); - - if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) - priv->encr_tx_key_index = index; - - return 0; -} - -static int restore_key(struct usbnet *usbdev, u8 key_idx) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - - if (is_wpa_key(priv, key_idx)) - return 0; - - key = priv->encr_keys[key_idx]; - - netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len); - - if (key.len == 0) - return 0; - - return add_wep_key(usbdev, key.material, key.len, key_idx); -} - -static void restore_keys(struct usbnet *usbdev) -{ - int i; - - for (i = 0; i < 4; i++) - restore_key(usbdev, i); -} - -static void clear_key(struct rndis_wlan_private *priv, u8 idx) -{ - memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); -} - -/* remove_key is for both wep and wpa */ -static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_remove_key remove_key; - __le32 keyindex; - bool is_wpa; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - if (priv->encr_keys[index].len == 0) - return 0; - - is_wpa = is_wpa_key(priv, index); - - netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n", - __func__, index, is_wpa ? "wpa" : "wep", - priv->encr_keys[index].len); - - clear_key(priv, index); - - if (is_wpa) { - remove_key.size = cpu_to_le32(sizeof(remove_key)); - remove_key.index = cpu_to_le32(index); - if (bssid) { - /* pairwise key */ - if (!is_broadcast_ether_addr(bssid)) - remove_key.index |= - NDIS_80211_ADDKEY_PAIRWISE_KEY; - memcpy(remove_key.bssid, bssid, - sizeof(remove_key.bssid)); - } else - memset(remove_key.bssid, 0xff, - sizeof(remove_key.bssid)); - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_KEY, - &remove_key, sizeof(remove_key)); - if (ret != 0) - return ret; - } else { - keyindex = cpu_to_le32(index); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_WEP, - &keyindex, sizeof(keyindex)); - if (ret != 0) { - netdev_warn(usbdev->net, - "removing encryption key %d failed (%08X)\n", - index, ret); - return ret; - } - } - - /* if it is transmit key, disable encryption */ - if (index == priv->encr_tx_key_index) - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); - - return 0; -} - -static void set_multicast_list(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct netdev_hw_addr *ha; - __le32 filter, basefilter; - int ret; - char *mc_addrs = NULL; - int mc_count; - - basefilter = filter = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | - RNDIS_PACKET_TYPE_BROADCAST); - - if (usbdev->net->flags & IFF_PROMISC) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_PROMISCUOUS | - RNDIS_PACKET_TYPE_ALL_LOCAL); - } else if (usbdev->net->flags & IFF_ALLMULTI) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } - - if (filter != basefilter) - goto set_filter; - - /* - * mc_list should be accessed holding the lock, so copy addresses to - * local buffer first. - */ - netif_addr_lock_bh(usbdev->net); - mc_count = netdev_mc_count(usbdev->net); - if (mc_count > priv->multicast_size) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } else if (mc_count) { - int i = 0; - - mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC); - if (!mc_addrs) { - netif_addr_unlock_bh(usbdev->net); - return; - } - - netdev_for_each_mc_addr(ha, usbdev->net) - memcpy(mc_addrs + i++ * ETH_ALEN, - ha->addr, ETH_ALEN); - } - netif_addr_unlock_bh(usbdev->net); - - if (filter != basefilter) - goto set_filter; - - if (mc_count) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_3_MULTICAST_LIST, - mc_addrs, mc_count * ETH_ALEN); - kfree(mc_addrs); - if (ret == 0) - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_MULTICAST); - else - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - - netdev_dbg(usbdev->net, "RNDIS_OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", - mc_count, priv->multicast_size, ret); - } - -set_filter: - ret = rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - if (ret < 0) { - netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n", - le32_to_cpu(filter)); - } - - netdev_dbg(usbdev->net, "RNDIS_OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", - le32_to_cpu(filter), ret); -} - -#ifdef DEBUG -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int i, len, count, max_pmkids, entry_len; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = le32_to_cpu(pmkids->length); - count = le32_to_cpu(pmkids->bssid_info_count); - - entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1; - - netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: " - "%d)\n", func_str, count, len, entry_len); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) { - u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid; - - netdev_dbg(usbdev->net, "%s(): bssid: %pM, " - "pmkid: %08X:%08X:%08X:%08X\n", - func_str, pmkids->bssid_info[i].bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - } -} -#else -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - return; -} -#endif - -static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_pmkid *pmkids; - int len, ret, max_pmkids; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = struct_size(pmkids, bssid_info, max_pmkids); - - pmkids = kzalloc(len, GFP_KERNEL); - if (!pmkids) - return ERR_PTR(-ENOMEM); - - pmkids->length = cpu_to_le32(len); - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_PMKID, - pmkids, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d)" - " -> %d\n", __func__, len, max_pmkids, ret); - - kfree(pmkids); - return ERR_PTR(ret); - } - - if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids) - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - debug_print_pmkids(usbdev, pmkids, __func__); - - return pmkids; -} - -static int set_device_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids) -{ - int ret, len, num_pmkids; - - num_pmkids = le32_to_cpu(pmkids->bssid_info_count); - len = struct_size(pmkids, bssid_info, num_pmkids); - pmkids->length = cpu_to_le32(len); - - debug_print_pmkids(usbdev, pmkids, __func__); - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, pmkids, - le32_to_cpu(pmkids->length)); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d) -> %d" - "\n", __func__, len, num_pmkids, ret); - } - - kfree(pmkids); - return ret; -} - -static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - int i, err; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) - if (ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - break; - - /* pmkid not found */ - if (i == count) { - netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n", - __func__, pmksa->bssid); - err = -ENOENT; - goto error; - } - - for (; i + 1 < count; i++) - pmkids->bssid_info[i] = pmkids->bssid_info[i + 1]; - - count--; - pmkids->length = cpu_to_le32(struct_size(pmkids, bssid_info, count)); - pmkids->bssid_info_count = cpu_to_le32(count); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - struct ndis_80211_pmkid *new_pmkids; - int i, err, newlen; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - /* update with new pmkid */ - for (i = 0; i < count; i++) { - if (!ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - continue; - - memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, - WLAN_PMKID_LEN); - - return pmkids; - } - - /* out of space, return error */ - if (i == max_pmkids) { - netdev_dbg(usbdev->net, "%s(): out of space\n", __func__); - err = -ENOSPC; - goto error; - } - - /* add new pmkid */ - newlen = struct_size(pmkids, bssid_info, count + 1); - - new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL); - if (!new_pmkids) { - err = -ENOMEM; - goto error; - } - pmkids = new_pmkids; - - pmkids->length = cpu_to_le32(newlen); - pmkids->bssid_info_count = cpu_to_le32(count + 1); - - memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN); - memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int mode; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - mode = NDIS_80211_INFRA_ADHOC; - break; - case NL80211_IFTYPE_STATION: - mode = NDIS_80211_INFRA_INFRA; - break; - default: - return -EINVAL; - } - - priv->wdev.iftype = type; - - return set_infra_mode(usbdev, mode); -} - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int err; - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - err = set_frag_threshold(usbdev, wiphy->frag_threshold); - if (err < 0) - return err; - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - err = set_rts_threshold(usbdev, wiphy->rts_threshold); - if (err < 0) - return err; - } - - return 0; -} - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n", - __func__, type, mbm); - - if (mbm < 0 || (mbm % 100)) - return -ENOTSUPP; - - /* Device doesn't support changing txpower after initialization, only - * turn off/on radio. Support 'auto' mode and setting same dBm that is - * currently used. - */ - if (type == NL80211_TX_POWER_AUTOMATIC || - MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) { - if (!priv->radio_on) - disassociate(usbdev, true); /* turn on radio */ - - return 0; - } - - return -ENOTSUPP; -} - -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - *dbm = get_bcm4320_power_dbm(priv); - - netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm); - - return 0; -} - -#define SCAN_DELAY_JIFFIES (6 * HZ) -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct net_device *dev = request->wdev->netdev; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - int delay = SCAN_DELAY_JIFFIES; - - netdev_dbg(usbdev->net, "cfg80211.scan\n"); - - /* Get current bssid list from device before new scan, as new scan - * clears internal bssid list. - */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - ret = rndis_start_bssid_list_scan(usbdev); - if (ret == 0) { - if (priv->device_type == RNDIS_BCM4320A) - delay = HZ; - - /* Wait before retrieving scan results from device */ - queue_delayed_work(priv->workqueue, &priv->scan_work, delay); - } - - return ret; -} - -static bool rndis_bss_info_update(struct usbnet *usbdev, - struct ndis_80211_bssid_ex *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u16 beacon_interval; - struct ndis_80211_fixed_ies *fixed; - int ie_len, bssid_len; - u8 *ie; - - netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n", - bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length)); - - /* parse bssid structure */ - bssid_len = le32_to_cpu(bssid->length); - - if (bssid_len < sizeof(struct ndis_80211_bssid_ex) + - sizeof(struct ndis_80211_fixed_ies)) - return false; - - fixed = (struct ndis_80211_fixed_ies *)bssid->ies; - - ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); - ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->ie_length)); - ie_len -= sizeof(struct ndis_80211_fixed_ies); - if (ie_len < 0) - return false; - - /* extract data for cfg80211_inform_bss */ - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config))); - if (!channel) - return false; - - signal = level_to_qual(le32_to_cpu(bssid->rssi)); - timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp); - capability = le16_to_cpu(fixed->capabilities); - beacon_interval = le16_to_cpu(fixed->beacon_interval); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac, - timestamp, capability, beacon_interval, - ie, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); - - return (bss != NULL); -} - -static struct ndis_80211_bssid_ex *next_bssid_list_item( - struct ndis_80211_bssid_ex *bssid, - int *bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + *bssid_len; - - if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) { - *bssid_len = 0; - return NULL; - } else { - bssid = (void *)((char *)bssid + *bssid_len); - *bssid_len = le32_to_cpu(bssid->length); - return bssid; - } -} - -static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid, - int bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - if (!bssid || bssid_len <= 0 || bssid_len > len) - return false; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + bssid_len; - - return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0; -} - -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched) -{ - void *buf = NULL; - struct ndis_80211_bssid_list_ex *bssid_list; - struct ndis_80211_bssid_ex *bssid; - int ret = -EINVAL, len, count, bssid_len, real_count, new_len; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - len = CONTROL_BUFFER_SIZE; -resize_buf: - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - /* BSSID-list might have got bigger last time we checked, keep - * resizing until it won't get any bigger. - */ - new_len = len; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST, - buf, &new_len); - if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex)) - goto out; - - if (new_len > len) { - len = new_len; - kfree(buf); - goto resize_buf; - } - - len = new_len; - - bssid_list = buf; - count = le32_to_cpu(bssid_list->num_items); - real_count = 0; - netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len); - - bssid_len = 0; - bssid = next_bssid_list_item((void *)bssid_list->bssid_data, - &bssid_len, buf, len); - - /* Device returns incorrect 'num_items'. Workaround by ignoring the - * received 'num_items' and walking through full bssid buffer instead. - */ - while (check_bssid_list_item(bssid, bssid_len, buf, len)) { - if (rndis_bss_info_update(usbdev, bssid) && match_bssid && - matched) { - if (ether_addr_equal(bssid->mac, match_bssid)) - *matched = true; - } - - real_count++; - bssid = next_bssid_list_item(bssid, &bssid_len, buf, len); - } - - netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:" - " %d\n", __func__, count, real_count); - -out: - kfree(buf); - return ret; -} - -static void rndis_get_scan_results(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, scan_work.work); - struct usbnet *usbdev = priv->usbdev; - struct cfg80211_scan_info info = {}; - int ret; - - netdev_dbg(usbdev->net, "get_scan_results\n"); - - if (!priv->scan_request) - return; - - ret = rndis_check_bssid_list(usbdev, NULL, NULL); - - info.aborted = ret < 0; - cfg80211_scan_done(priv->scan_request, &info); - - priv->scan_request = NULL; -} - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = sme->channel; - struct ndis_80211_ssid ssid; - int pairwise = RNDIS_WLAN_ALG_NONE; - int groupwise = RNDIS_WLAN_ALG_NONE; - int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; - int length, i, ret, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); - for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) - pairwise |= - rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); - - if (sme->crypto.n_ciphers_pairwise > 0 && - pairwise == RNDIS_WLAN_ALG_NONE) { - netdev_err(usbdev->net, "Unsupported pairwise cipher\n"); - return -ENOTSUPP; - } - - for (i = 0; i < sme->crypto.n_akm_suites; i++) - keymgmt |= - rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); - - if (sme->crypto.n_akm_suites > 0 && - keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { - netdev_err(usbdev->net, "Invalid keymgmt\n"); - return -ENOTSUPP; - } - - netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n", - sme->ssid, sme->bssid, chan, - sme->privacy, sme->crypto.wpa_versions, sme->auth_type, - groupwise, pairwise, keymgmt); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, - keymgmt); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, pairwise, groupwise); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { - priv->encr_tx_key_index = sme->key_idx; - ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n", - ret, sme->key_len, sme->key_idx); - goto err_turn_radio_on; - } - } - - if (sme->bssid && !is_zero_ether_addr(sme->bssid) && - !is_broadcast_ether_addr(sme->bssid)) { - ret = set_bssid(usbdev, sme->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = sme->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, sme->ssid, length); - - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = params->chandef.chan; - struct ndis_80211_ssid ssid; - enum nl80211_auth_type auth_type; - int ret, alg, length, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - /* TODO: How to handle ad-hoc encryption? - * connect() has *key, join_ibss() doesn't. RNDIS requires key to be - * pre-shared for encryption (open/shared/wpa), is key set before - * join_ibss? Which auth_type to use (not in params)? What about WPA? - */ - if (params->privacy) { - auth_type = NL80211_AUTHTYPE_SHARED_KEY; - alg = RNDIS_WLAN_ALG_WEP; - } else { - auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; - alg = RNDIS_WLAN_ALG_NONE; - } - - netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n", - params->ssid, params->bssid, chan, params->privacy); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (params->bssid && !is_zero_ether_addr(params->bssid) && - !is_broadcast_ether_addr(params->bssid)) { - ret = set_bssid(usbdev, params->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = params->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, params->ssid, length); - - /* Don't need to pause rx queue for ad-hoc. */ - usbnet_purge_paused_rxq(usbdev); - usbnet_resume_rx(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n", - ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n"); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - __le32 flags; - - netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n", - __func__, key_index, mac_addr, params->cipher); - - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return add_wep_key(usbdev, params->key, params->key_len, - key_index); - case WLAN_CIPHER_SUITE_TKIP: - case WLAN_CIPHER_SUITE_CCMP: - flags = 0; - - if (params->seq && params->seq_len > 0) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (mac_addr) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY | - NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, params->key, params->key_len, - key_index, mac_addr, params->seq, - params->seq_len, params->cipher, flags); - default: - netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n", - __func__, params->cipher); - return -ENOTSUPP; - } -} - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr); - - return remove_key(usbdev, key_index, mac_addr); -} - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct rndis_wlan_encr_key key; - - netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index); - - if (key_index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - priv->encr_tx_key_index = key_index; - - if (is_wpa_key(priv, key_index)) - return 0; - - key = priv->encr_keys[key_index]; - - return add_wep_key(usbdev, key.material, key.len, key_index); -} - -static void rndis_fill_station_info(struct usbnet *usbdev, - struct station_info *sinfo) -{ - __le32 linkspeed, rssi; - int ret, len; - - memset(sinfo, 0, sizeof(*sinfo)); - - len = sizeof(linkspeed); - ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); - if (ret == 0) { - sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - } -} - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (!ether_addr_equal(priv->bssid, mac)) - return -ENOENT; - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (idx != 0) - return -ENOENT; - - memcpy(mac, priv->bssid, ETH_ALEN); - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, list full, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* Couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid pmkid; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - memset(&pmkid, 0, sizeof(pmkid)); - - pmkid.length = cpu_to_le32(sizeof(pmkid)); - pmkid.bssid_info_count = cpu_to_le32(0); - - return rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, - &pmkid, sizeof(pmkid)); -} - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int power_mode; - __le32 mode; - int ret; - - if (priv->device_type != RNDIS_BCM4320B) - return -ENOTSUPP; - - netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__, - enabled ? "enabled" : "disabled", - timeout); - - if (enabled) - power_mode = NDIS_80211_POWER_MODE_FAST_PSP; - else - power_mode = NDIS_80211_POWER_MODE_CAM; - - if (power_mode == priv->power_mode) - return 0; - - priv->power_mode = power_mode; - - mode = cpu_to_le32(power_mode); - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_POWER_MODE, - &mode, sizeof(mode)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_POWER_MODE -> %d\n", - __func__, ret); - - return ret; -} - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - - priv->cqm_rssi_thold = rssi_thold; - priv->cqm_rssi_hyst = rssi_hyst; - priv->last_cqm_event_rssi = 0; - - return 0; -} - -static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, - struct ndis_80211_assoc_info *info) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_ssid ssid; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u32 beacon_period = 0; - __le32 rssi; - u8 ie_buf[34]; - int len, ret, ie_len; - - /* Get signal quality, in case of error use rssi=0 and ignore error. */ - len = sizeof(rssi); - rssi = 0; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - signal = level_to_qual(le32_to_cpu(rssi)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_RSSI -> %d, " - "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), - level_to_qual(le32_to_cpu(rssi))); - - /* Get AP capabilities */ - if (info) { - capability = le16_to_cpu(info->resp_ie.capa); - } else { - /* Set atleast ESS/IBSS capability */ - capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ? - WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS; - } - - /* Get channel and beacon interval */ - channel = get_current_channel(usbdev, &beacon_period); - if (!channel) { - netdev_warn(usbdev->net, "%s(): could not get channel.\n", - __func__); - return; - } - - /* Get SSID, in case of error, use zero length SSID and ignore error. */ - len = sizeof(ssid); - memset(&ssid, 0, sizeof(ssid)); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_SSID, - &ssid, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_SSID -> %d, len: %d, ssid: " - "'%.32s'\n", __func__, ret, - le32_to_cpu(ssid.length), ssid.essid); - - if (le32_to_cpu(ssid.length) > 32) - ssid.length = cpu_to_le32(32); - - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = le32_to_cpu(ssid.length); - memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length)); - - ie_len = le32_to_cpu(ssid.length) + 2; - - /* no tsf */ - timestamp = 0; - - netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, " - "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), " - "signal:%d\n", __func__, (channel ? channel->center_freq : -1), - bssid, (u32)timestamp, capability, beacon_period, ie_len, - ssid.essid, signal); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid, - timestamp, capability, beacon_period, - ie_buf, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); -} - -/* - * workers, indication handlers, device poller - */ -static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_assoc_info *info = NULL; - u8 bssid[ETH_ALEN]; - unsigned int resp_ie_len, req_ie_len; - unsigned int offset; - u8 *req_ie, *resp_ie; - int ret; - bool roamed = false; - bool match_bss; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { - /* received media connect indication while connected, either - * device reassociated with same AP or roamed to new. */ - roamed = true; - } - - req_ie_len = 0; - resp_ie_len = 0; - req_ie = NULL; - resp_ie = NULL; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); - if (!info) { - /* No memory? Try resume work later */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - return; - } - - /* Get association info IEs from device. */ - ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE); - if (!ret) { - req_ie_len = le32_to_cpu(info->req_ie_length); - if (req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = CONTROL_BUFFER_SIZE; - if (req_ie_len != 0) { - offset = le32_to_cpu(info->offset_req_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - req_ie = (u8 *)info + offset; - - if (offset + req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - - resp_ie_len = le32_to_cpu(info->resp_ie_length); - if (resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = CONTROL_BUFFER_SIZE; - if (resp_ie_len != 0) { - offset = le32_to_cpu(info->offset_resp_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - resp_ie = (u8 *)info + offset; - - if (offset + resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - } else { - /* Since rndis_wlan_craft_connected_bss() might use info - * later and expects info to contain valid data if - * non-null, free info and set NULL here. - */ - kfree(info); - info = NULL; - } - } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) - return; - - ret = get_bssid(usbdev, bssid); - if (ret < 0) - memset(bssid, 0, sizeof(bssid)); - - netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", - bssid, roamed ? " roamed" : ""); - - /* Internal bss list in device should contain at least the currently - * connected bss and we can get it to cfg80211 with - * rndis_check_bssid_list(). - * - * NDIS spec says: "If the device is associated, but the associated - * BSSID is not in its BSSID scan list, then the driver must add an - * entry for the BSSID at the end of the data that it returns in - * response to query of RNDIS_OID_802_11_BSSID_LIST." - * - * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. - */ - match_bss = false; - rndis_check_bssid_list(usbdev, bssid, &match_bss); - - if (!is_zero_ether_addr(bssid) && !match_bss) { - /* Couldn't get bss from device, we need to manually craft bss - * for cfg80211. - */ - rndis_wlan_craft_connected_bss(usbdev, bssid, info); - } - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - if (!roamed) { - cfg80211_connect_result(usbdev->net, bssid, req_ie, - req_ie_len, resp_ie, - resp_ie_len, 0, GFP_KERNEL); - } else { - struct cfg80211_roam_info roam_info = { - .links[0].channel = - get_current_channel(usbdev, NULL), - .links[0].bssid = bssid, - .req_ie = req_ie, - .req_ie_len = req_ie_len, - .resp_ie = resp_ie, - .resp_ie_len = resp_ie_len, - }; - - cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL); - } - } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - cfg80211_ibss_joined(usbdev->net, bssid, - get_current_channel(usbdev, NULL), - GFP_KERNEL); - - kfree(info); - - priv->connected = true; - memcpy(priv->bssid, bssid, ETH_ALEN); - - usbnet_resume_rx(usbdev); - netif_carrier_on(usbdev->net); -} - -static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (priv->connected) { - priv->connected = false; - eth_zero_addr(priv->bssid); - - deauthenticate(usbdev); - - cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL); - } - - netif_carrier_off(usbdev->net); -} - -static void rndis_wlan_worker(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, work); - struct usbnet *usbdev = priv->usbdev; - - if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) - rndis_wlan_do_link_up_work(usbdev); - - if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) - rndis_wlan_do_link_down_work(usbdev); - - if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - set_multicast_list(usbdev); -} - -static void rndis_wlan_set_multicast_list(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - return; - - set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); -} - -static void rndis_wlan_auth_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - u8 *buf; - const char *type; - int flags, buflen, key_id; - bool pairwise_error, group_error; - struct ndis_80211_auth_request *auth_req; - enum nl80211_key_type key_type; - - /* must have at least one array entry */ - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_auth_request)) { - netdev_info(usbdev->net, "authentication indication: too short message (%i)\n", - len); - return; - } - - buf = (void *)&indication->u.auth_request[0]; - buflen = len - offsetof(struct ndis_80211_status_indication, u); - - while (buflen >= sizeof(*auth_req)) { - auth_req = (void *)buf; - if (buflen < le32_to_cpu(auth_req->length)) - return; - type = "unknown"; - flags = le32_to_cpu(auth_req->flags); - pairwise_error = false; - group_error = false; - - if (flags & 0x1) - type = "reauth request"; - if (flags & 0x2) - type = "key update request"; - if (flags & 0x6) { - pairwise_error = true; - type = "pairwise_error"; - } - if (flags & 0xe) { - group_error = true; - type = "group_error"; - } - - netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n", - type, le32_to_cpu(auth_req->flags)); - - if (pairwise_error) { - key_type = NL80211_KEYTYPE_PAIRWISE; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - if (group_error) { - key_type = NL80211_KEYTYPE_GROUP; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - buflen -= le32_to_cpu(auth_req->length); - buf += le32_to_cpu(auth_req->length); - } -} - -static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - struct ndis_80211_pmkid_cand_list *cand_list; - int list_len, expected_len, i; - - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_pmkid_cand_list)) { - netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n", - len); - return; - } - - list_len = le32_to_cpu(indication->u.cand_list.num_candidates) * - sizeof(struct ndis_80211_pmkid_candidate); - expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len + - offsetof(struct ndis_80211_status_indication, u); - - if (len < expected_len) { - netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n", - len, expected_len); - return; - } - - cand_list = &indication->u.cand_list; - - netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n", - le32_to_cpu(cand_list->version), - le32_to_cpu(cand_list->num_candidates)); - - if (le32_to_cpu(cand_list->version) != 1) - return; - - for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct ndis_80211_pmkid_candidate *cand = - &cand_list->candidate_list[i]; - bool preauth = !!(cand->flags & NDIS_80211_PMKID_CAND_PREAUTH); - - netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, preauth: %d, bssid: %pM\n", - i, le32_to_cpu(cand->flags), preauth, cand->bssid); - - cfg80211_pmksa_candidate_notify(usbdev->net, i, cand->bssid, - preauth, GFP_ATOMIC); - } -} - -static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, - struct rndis_indicate *msg, int buflen) -{ - struct ndis_80211_status_indication *indication; - unsigned int len, offset; - - offset = offsetof(struct rndis_indicate, status) + - le32_to_cpu(msg->offset); - len = le32_to_cpu(msg->length); - - if (len < 8) { - netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n", - len); - return; - } - - if (len > buflen || offset > buflen || offset + len > buflen) { - netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n", - offset + len, buflen); - return; - } - - indication = (void *)((u8 *)msg + offset); - - switch (le32_to_cpu(indication->status_type)) { - case NDIS_80211_STATUSTYPE_RADIOSTATE: - netdev_info(usbdev->net, "radio state indication: %i\n", - le32_to_cpu(indication->u.radio_status)); - return; - - case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: - netdev_info(usbdev->net, "media stream mode indication: %i\n", - le32_to_cpu(indication->u.media_stream_mode)); - return; - - case NDIS_80211_STATUSTYPE_AUTHENTICATION: - rndis_wlan_auth_indication(usbdev, indication, len); - return; - - case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST: - rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len); - return; - - default: - netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n", - le32_to_cpu(indication->status_type)); - } -} - -static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_indicate *msg = ind; - - switch (le32_to_cpu(msg->status)) { - case RNDIS_STATUS_MEDIA_CONNECT: - if (priv->current_command_oid == RNDIS_OID_802_11_ADD_KEY) { - /* RNDIS_OID_802_11_ADD_KEY causes sometimes extra - * "media connect" indications which confuses driver - * and userspace to think that device is - * roaming/reassociating when it isn't. - */ - netdev_dbg(usbdev->net, "ignored RNDIS_OID_802_11_ADD_KEY triggered 'media connect'\n"); - return; - } - - usbnet_pause_rx(usbdev); - - netdev_info(usbdev->net, "media connect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_DISCONNECT: - netdev_info(usbdev->net, "media disconnect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_DOWN, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION: - rndis_wlan_media_specific_indication(usbdev, msg, buflen); - break; - - default: - netdev_info(usbdev->net, "indication: 0x%08x\n", - le32_to_cpu(msg->status)); - break; - } -} - -static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) -{ - struct { - __le32 num_items; - __le32 items[8]; - } networks_supported; - struct ndis_80211_capability caps; - int len, retval, i, n; - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* determine supported modes */ - len = sizeof(networks_supported); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED, - &networks_supported, &len); - if (!retval) { - n = le32_to_cpu(networks_supported.num_items); - if (n > 8) - n = 8; - for (i = 0; i < n; i++) { - switch (le32_to_cpu(networks_supported.items[i])) { - case NDIS_80211_TYPE_FREQ_HOP: - case NDIS_80211_TYPE_DIRECT_SEQ: - priv->caps |= CAP_MODE_80211B; - break; - case NDIS_80211_TYPE_OFDM_A: - priv->caps |= CAP_MODE_80211A; - break; - case NDIS_80211_TYPE_OFDM_G: - priv->caps |= CAP_MODE_80211G; - break; - } - } - } - - /* get device 802.11 capabilities, number of PMKIDs */ - len = sizeof(caps); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CAPABILITY, - &caps, &len); - if (!retval) { - netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, " - "ver %d, pmkids %d, auth-encr-pairs %d\n", - le32_to_cpu(caps.length), - le32_to_cpu(caps.version), - le32_to_cpu(caps.num_pmkids), - le32_to_cpu(caps.num_auth_encr_pair)); - wiphy->max_num_pmkids = le32_to_cpu(caps.num_pmkids); - } else - wiphy->max_num_pmkids = 0; - - return retval; -} - -static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - enum nl80211_cqm_rssi_threshold_event event; - int thold, hyst, last_event; - - if (priv->cqm_rssi_thold >= 0 || rssi >= 0) - return; - if (priv->infra_mode != NDIS_80211_INFRA_INFRA) - return; - - last_event = priv->last_cqm_event_rssi; - thold = priv->cqm_rssi_thold; - hyst = priv->cqm_rssi_hyst; - - if (rssi < thold && (last_event == 0 || rssi < last_event - hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - else - return; - - priv->last_cqm_event_rssi = rssi; - cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL); -} - -#define DEVICE_POLLER_JIFFIES (HZ) -static void rndis_device_poller(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, - dev_poller_work.work); - struct usbnet *usbdev = priv->usbdev; - __le32 rssi, tmp; - int len, ret, j; - int update_jiffies = DEVICE_POLLER_JIFFIES; - void *buf; - - /* Only check/do workaround when connected. Calling is_associated() - * also polls device with rndis_command() and catches for media link - * indications. - */ - if (!is_associated(usbdev)) { - /* Workaround bad scanning in BCM4320a devices with active - * background scanning when not associated. - */ - if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && - !priv->scan_request) { - /* Get previous scan results */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - /* Initiate new scan */ - rndis_start_bssid_list_scan(usbdev); - } - - goto end; - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - rndis_do_cqm(usbdev, le32_to_cpu(rssi)); - } - - netdev_dbg(usbdev->net, "dev-poller: RNDIS_OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", - ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); - - /* Workaround transfer stalls on poor quality links. - * TODO: find right way to fix these stalls (as stalls do not happen - * with ndiswrapper/windows driver). */ - if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) { - /* Decrease stats worker interval to catch stalls. - * faster. Faster than 400-500ms causes packet loss, - * Slower doesn't catch stalls fast enough. - */ - j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > DEVICE_POLLER_JIFFIES) - j = DEVICE_POLLER_JIFFIES; - else if (j <= 0) - j = 1; - update_jiffies = j; - - /* Send scan OID. Use of both OIDs is required to get device - * working. - */ - tmp = cpu_to_le32(1); - rndis_set_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST_SCAN, - &tmp, sizeof(tmp)); - - len = CONTROL_BUFFER_SIZE; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - goto end; - - rndis_query_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST, - buf, &len); - kfree(buf); - } - -end: - if (update_jiffies >= HZ) - update_jiffies = round_jiffies_relative(update_jiffies); - else { - j = round_jiffies_relative(update_jiffies); - if (abs(j - update_jiffies) <= 10) - update_jiffies = j; - } - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - update_jiffies); -} - -/* - * driver/device initialization - */ -static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - priv->device_type = device_type; - - priv->param_country[0] = modparam_country[0]; - priv->param_country[1] = modparam_country[1]; - priv->param_country[2] = 0; - priv->param_frameburst = modparam_frameburst; - priv->param_afterburner = modparam_afterburner; - priv->param_power_save = modparam_power_save; - priv->param_power_output = modparam_power_output; - priv->param_roamtrigger = modparam_roamtrigger; - priv->param_roamdelta = modparam_roamdelta; - - priv->param_country[0] = toupper(priv->param_country[0]); - priv->param_country[1] = toupper(priv->param_country[1]); - /* doesn't support EU as country code, use FI instead */ - if (!strcmp(priv->param_country, "EU")) - strcpy(priv->param_country, "FI"); - - if (priv->param_power_save < 0) - priv->param_power_save = 0; - else if (priv->param_power_save > 2) - priv->param_power_save = 2; - - if (priv->param_power_output < 0) - priv->param_power_output = 0; - else if (priv->param_power_output > 3) - priv->param_power_output = 3; - - if (priv->param_roamtrigger < -80) - priv->param_roamtrigger = -80; - else if (priv->param_roamtrigger > -60) - priv->param_roamtrigger = -60; - - if (priv->param_roamdelta < 0) - priv->param_roamdelta = 0; - else if (priv->param_roamdelta > 2) - priv->param_roamdelta = 2; - - if (modparam_workaround_interval < 0) - priv->param_workaround_interval = 500; - else - priv->param_workaround_interval = modparam_workaround_interval; -} - -static int unknown_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for unknown so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); - - /* This is unknown device, so do not try set configuration parameters. - */ - - return 0; -} - -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for bcm4320a so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_BCM4320A); - - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - rndis_copy_module_params(usbdev, RNDIS_BCM4320B); - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ - - rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); - rndis_set_config_parameter_str(usbdev, "FrameBursting", - priv->param_frameburst ? "1" : "0"); - rndis_set_config_parameter_str(usbdev, "Afterburner", - priv->param_afterburner ? "1" : "0"); - sprintf(buf, "%d", priv->param_power_save); - rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf); - sprintf(buf, "%d", priv->param_power_output); - rndis_set_config_parameter_str(usbdev, "PwrOut", buf); - sprintf(buf, "%d", priv->param_roamtrigger); - rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf); - sprintf(buf, "%d", priv->param_roamdelta); - rndis_set_config_parameter_str(usbdev, "RoamDelta", buf); - - return 0; -} - -/* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wlan_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_get_stats64 = dev_get_tstats64, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = rndis_wlan_set_multicast_list, -}; - -static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct wiphy *wiphy; - struct rndis_wlan_private *priv; - int retval, len; - __le32 tmp; - - /* allocate wiphy and rndis private data - * NOTE: We only support a single virtual interface, so wiphy - * and wireless_dev are somewhat synonymous for this device. - */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); - if (!wiphy) - return -ENOMEM; - - priv = wiphy_priv(wiphy); - usbdev->net->ieee80211_ptr = &priv->wdev; - priv->wdev.wiphy = wiphy; - priv->wdev.iftype = NL80211_IFTYPE_STATION; - - /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wlan_early_init(). - */ - usbdev->driver_priv = priv; - priv->usbdev = usbdev; - - mutex_init(&priv->command_lock); - - /* because rndis_command() sleeps we need to use workqueue */ - priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - if (!priv->workqueue) { - wiphy_free(wiphy); - return -ENOMEM; - } - INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); - INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); - - /* try bind rndis_host */ - retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); - if (retval < 0) - goto fail; - - /* generic_rndis_bind set packet filter to multicast_all+ - * promisc mode which doesn't work well for our devices (device - * picks up rssi to closest station instead of to access point). - * - * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wlan. - */ - usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; - - tmp = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST); - retval = rndis_set_oid(usbdev, - RNDIS_OID_GEN_CURRENT_PACKET_FILTER, - &tmp, sizeof(tmp)); - - len = sizeof(tmp); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, - &tmp, &len); - priv->multicast_size = le32_to_cpu(tmp); - if (retval < 0 || priv->multicast_size < 0) - priv->multicast_size = 0; - if (priv->multicast_size > 0) - usbdev->net->flags |= IFF_MULTICAST; - else - usbdev->net->flags &= ~IFF_MULTICAST; - - /* fill-out wiphy structure and register w/ cfg80211 */ - memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); - wiphy->privid = rndis_wiphy_privid; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC); - wiphy->max_scan_ssids = 1; - - /* TODO: fill-out band/encr information based on priv->caps */ - rndis_wlan_get_caps(usbdev, wiphy); - - memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); - memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rndis_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; - - memcpy(priv->cipher_suites, rndis_cipher_suites, - sizeof(rndis_cipher_suites)); - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites); - - set_wiphy_dev(wiphy, &usbdev->udev->dev); - - if (wiphy_register(wiphy)) { - retval = -ENODEV; - goto fail; - } - - set_default_iw_params(usbdev); - - priv->power_mode = -1; - - /* set default rts/frag */ - rndis_set_wiphy_params(wiphy, - WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); - - /* turn radio off on init */ - priv->radio_on = false; - disassociate(usbdev, false); - netif_carrier_off(usbdev->net); - - return 0; - -fail: - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - wiphy_free(wiphy); - return retval; -} - -static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* turn radio off */ - disassociate(usbdev, false); - - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - rndis_unbind(usbdev, intf); - - wiphy_unregister(priv->wdev.wiphy); - wiphy_free(priv->wdev.wiphy); -} - -static int rndis_wlan_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = rndis_reset(usbdev); - if (retval) - netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval); - - /* rndis_reset cleared multicast list, so restore here. - (set_multicast_list() also turns on current packet filter) */ - set_multicast_list(usbdev); - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - round_jiffies_relative(DEVICE_POLLER_JIFFIES)); - - return deauthenticate(usbdev); -} - -static int rndis_wlan_stop(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - __le32 filter; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = disassociate(usbdev, false); - - priv->work_pending = 0; - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - flush_workqueue(priv->workqueue); - - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = true, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } - - /* Set current packet filter zero to block receiving data packets from - device. */ - filter = 0; - rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - - return retval; -} - -static const struct driver_info bcm4320b_info = { - .description = "Wireless RNDIS device, BCM4320b based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320b_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info bcm4320a_info = { - .description = "Wireless RNDIS device, BCM4320a based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320a_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info rndis_wlan_info = { - .description = "Wireless RNDIS device", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = unknown_early_init, - .indication = rndis_wlan_indication, -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products [] = { -#define RNDIS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = 2 /* ACM */, \ - .bInterfaceProtocol = 0x0ff - -/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom - * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x011b, /* U.S. Robotics USR5421 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x050d, - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1799, /* Belkin has two vendor ids */ - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0014, /* Linksys WUSB54GSv2 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0026, /* Linksys WUSB54GSC */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0b05, - .idProduct = 0x1717, /* Asus WL169gE */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0a5c, - .idProduct = 0xd11b, /* Eminent EM4045 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1690, - .idProduct = 0x0715, /* BT Voyager 1055 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, -/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom - * parameters available, hardware probably contain older firmware version with - * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x000e, /* Linksys WUSB54GSv1 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x0111, /* U.S. Robotics USR5420 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, -/* Generic Wireless RNDIS devices that we don't have exact - * idVendor/idProduct/chip yet. - */ -{ - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wlan_info, -}, { - /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ - USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wlan_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver rndis_wlan_driver = { - .name = "rndis_wlan", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(rndis_wlan_driver); - -MODULE_AUTHOR("Bjorge Dijkstra"); -MODULE_AUTHOR("Jussi Kivilinna"); -MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters"); -MODULE_LICENSE("GPL"); - From 8aa519f17512da50a2d850b60472de656e2b210a Mon Sep 17 00:00:00 2001 From: Dnyaneshwar Bhadane Date: Wed, 25 Oct 2023 18:47:09 +0530 Subject: [PATCH 0161/7721] drm/i915/mtl: Add Wa_22016670082 Implemented workaround for XeLPM+ BSpec: 51762 Signed-off-by: Dnyaneshwar Bhadane Reviewed-by: Balasubramani Vivekanandan Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231025131709.3368517-1-dnyaneshwar.bhadane@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 192ac0e59afa..6ae7a4de83b0 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -1674,6 +1674,9 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) */ wa_write_or(wal, XELPMP_GSC_MOD_CTRL, FORCE_MISS_FTLB); + /* Wa_22016670082 */ + wa_write_or(wal, GEN12_SQCNT1, GEN12_STRICT_RAR_ENABLE); + debug_dump_steering(gt); } From 9e372744c0f24d358967a9a2bbde69dee1491b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Oct 2023 17:02:14 +0300 Subject: [PATCH 0162/7721] drm/i915/bios: Clamp VBT HDMI level shift on BDW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently some BDW machines (eg. HP Pavilion 15-ab) shipped with a VBT inherited from some earlier HSW model. On HSW the HDMI level shift value could go up to 11, whereas on BDW the maximum value is 9. The DDI code does clamp the bogus value, but it does so with a WARN which we don't really want. To avoid that let's just sanitize the bogus VBT HDMI level shift value ahead of time for all BDW machines. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9461 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231013140214.1713-1-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_bios.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 69db1a3a1499..719fb550342b 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2473,6 +2473,27 @@ static void sanitize_device_type(struct intel_bios_encoder_data *devdata, devdata->child.device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT; } +static void sanitize_hdmi_level_shift(struct intel_bios_encoder_data *devdata, + enum port port) +{ + struct drm_i915_private *i915 = devdata->i915; + + if (!intel_bios_encoder_supports_dvi(devdata)) + return; + + /* + * Some BDW machines (eg. HP Pavilion 15-ab) shipped + * with a HSW VBT where the level shifter value goes + * up to 11, whereas the BDW max is 9. + */ + if (IS_BROADWELL(i915) && devdata->child.hdmi_level_shifter_value > 9) { + drm_dbg_kms(&i915->drm, "Bogus port %c VBT HDMI level shift %d, adjusting to %d\n", + port_name(port), devdata->child.hdmi_level_shifter_value, 9); + + devdata->child.hdmi_level_shifter_value = 9; + } +} + static bool intel_bios_encoder_supports_crt(const struct intel_bios_encoder_data *devdata) { @@ -2652,6 +2673,7 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata) } sanitize_device_type(devdata, port); + sanitize_hdmi_level_shift(devdata, port); } static bool has_ddi_port_info(struct drm_i915_private *i915) From f215038f4133ea9d1b525e9bb812527fe002db2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:35:19 +0300 Subject: [PATCH 0163/7721] drm/i915: Use named initializers for DPLL info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use named initializers when populating the DPLL info. This is just more convenient and less error prone as we no longer have to keep the initializers in a specific order. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012123522.26045-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 130 +++++++++--------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 399653a20f98..b7997b096796 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -631,9 +631,9 @@ static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = { }; static const struct dpll_info pch_plls[] = { - { "PCH DPLL A", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_A, 0 }, - { "PCH DPLL B", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_B, 0 }, - { }, + { .name = "PCH DPLL A", .funcs = &ibx_pch_dpll_funcs, .id = DPLL_ID_PCH_PLL_A, }, + { .name = "PCH DPLL B", .funcs = &ibx_pch_dpll_funcs, .id = DPLL_ID_PCH_PLL_B, }, + {} }; static const struct intel_dpll_mgr pch_pll_mgr = { @@ -1239,13 +1239,16 @@ static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = { }; static const struct dpll_info hsw_plls[] = { - { "WRPLL 1", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL1, 0 }, - { "WRPLL 2", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL2, 0 }, - { "SPLL", &hsw_ddi_spll_funcs, DPLL_ID_SPLL, 0 }, - { "LCPLL 810", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_810, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 1350", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_1350, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 2700", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_2700, INTEL_DPLL_ALWAYS_ON }, - { }, + { .name = "WRPLL 1", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL1, }, + { .name = "WRPLL 2", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL2, }, + { .name = "SPLL", .funcs = &hsw_ddi_spll_funcs, .id = DPLL_ID_SPLL, }, + { .name = "LCPLL 810", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_810, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "LCPLL 1350", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_1350, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "LCPLL 2700", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_2700, + .flags = INTEL_DPLL_ALWAYS_ON, }, + {} }; static const struct intel_dpll_mgr hsw_pll_mgr = { @@ -1921,11 +1924,12 @@ static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = { }; static const struct dpll_info skl_plls[] = { - { "DPLL 0", &skl_ddi_dpll0_funcs, DPLL_ID_SKL_DPLL0, INTEL_DPLL_ALWAYS_ON }, - { "DPLL 1", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, - { "DPLL 2", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, - { "DPLL 3", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &skl_ddi_dpll0_funcs, .id = DPLL_ID_SKL_DPLL0, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "DPLL 1", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, }, + { .name = "DPLL 2", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, }, + { .name = "DPLL 3", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL3, }, + {} }; static const struct intel_dpll_mgr skl_pll_mgr = { @@ -2376,10 +2380,10 @@ static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = { }; static const struct dpll_info bxt_plls[] = { - { "PORT PLL A", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL0, 0 }, - { "PORT PLL B", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, - { "PORT PLL C", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, - { }, + { .name = "PORT PLL A", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL0, }, + { .name = "PORT PLL B", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, }, + { .name = "PORT PLL C", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, }, + {} }; static const struct intel_dpll_mgr bxt_pll_mgr = { @@ -4014,14 +4018,14 @@ static const struct intel_shared_dpll_funcs mg_pll_funcs = { }; static const struct dpll_info icl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "MG PLL 1", &mg_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "MG PLL 2", &mg_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "MG PLL 3", &mg_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "MG PLL 4", &mg_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "MG PLL 3", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "MG PLL 4", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} }; static const struct intel_dpll_mgr icl_pll_mgr = { @@ -4035,10 +4039,10 @@ static const struct intel_dpll_mgr icl_pll_mgr = { }; static const struct dpll_info ehl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, }, + {} }; static const struct intel_dpll_mgr ehl_pll_mgr = { @@ -4058,16 +4062,16 @@ static const struct intel_shared_dpll_funcs dkl_pll_funcs = { }; static const struct dpll_info tgl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { "TC PLL 5", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL5, 0 }, - { "TC PLL 6", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL6, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + { .name = "TC PLL 5", .funcs = &dkl_pll_funcs, .id = DPLL_ID_TGL_MGPLL5, }, + { .name = "TC PLL 6", .funcs = &dkl_pll_funcs, .id = DPLL_ID_TGL_MGPLL6, }, + {} }; static const struct intel_dpll_mgr tgl_pll_mgr = { @@ -4081,10 +4085,10 @@ static const struct intel_dpll_mgr tgl_pll_mgr = { }; static const struct dpll_info rkl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, }, + {} }; static const struct intel_dpll_mgr rkl_pll_mgr = { @@ -4097,11 +4101,11 @@ static const struct intel_dpll_mgr rkl_pll_mgr = { }; static const struct dpll_info dg1_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_DG1_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_DG1_DPLL1, 0 }, - { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 }, - { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL1, }, + { .name = "DPLL 2", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL2, }, + { .name = "DPLL 3", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL3, }, + {} }; static const struct intel_dpll_mgr dg1_pll_mgr = { @@ -4114,11 +4118,11 @@ static const struct intel_dpll_mgr dg1_pll_mgr = { }; static const struct dpll_info adls_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 }, - { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 2", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL2, }, + { .name = "DPLL 3", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL3, }, + {} }; static const struct intel_dpll_mgr adls_pll_mgr = { @@ -4131,14 +4135,14 @@ static const struct intel_dpll_mgr adls_pll_mgr = { }; static const struct dpll_info adlp_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} }; static const struct intel_dpll_mgr adlp_pll_mgr = { From 7e72cd6cafb166b815b7997597c09a01412da064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:35:20 +0300 Subject: [PATCH 0164/7721] drm/i915: Abstract the extra JSL/EHL DPLL4 power domain better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just include the JSL/EHL DPLL4 extra power domain in the dpll_info struct. This way the same approach could be used by other platforms as well (should the need arise), and we don't have to sprinkle platform checks all over the place. Note that I'm perhaps slightly abusing things here as power_domain==0 (which is actually POWER_DOMAIN_DISPLAY_CORE) now indicates that no extra power domain is needed. I suppose using POWER_DOMAIN_INVALID would be more correct, but then we'd have to sprinkle that to all the other DPLLs. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012123522.26045-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 30 +++++-------------- drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 6 ++++ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index b7997b096796..4e524cb8ed83 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -3838,17 +3838,8 @@ static void combo_pll_enable(struct drm_i915_private *i915, { i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->info->id == DPLL_ID_EHL_DPLL4) { - - /* - * We need to disable DC states when this DPLL is enabled. - * This can be done by taking a reference on DPLL4 power - * domain. - */ - pll->wakeref = intel_display_power_get(i915, - POWER_DOMAIN_DC_OFF); - } + if (pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); icl_pll_power_enable(i915, pll, enable_reg); @@ -3946,10 +3937,8 @@ static void combo_pll_disable(struct drm_i915_private *i915, icl_pll_disable(i915, pll, enable_reg); - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->info->id == DPLL_ID_EHL_DPLL4) - intel_display_power_put(i915, POWER_DOMAIN_DC_OFF, - pll->wakeref); + if (pll->info->power_domain) + intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); } static void tbt_pll_disable(struct drm_i915_private *i915, @@ -4041,7 +4030,8 @@ static const struct intel_dpll_mgr icl_pll_mgr = { static const struct dpll_info ehl_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, }, + { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, + .power_domain = POWER_DOMAIN_DC_OFF, }, {} }; @@ -4369,12 +4359,8 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915, pll->on = intel_dpll_get_hw_state(i915, pll, &pll->state.hw_state); - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->on && - pll->info->id == DPLL_ID_EHL_DPLL4) { - pll->wakeref = intel_display_power_get(i915, - POWER_DOMAIN_DC_OFF); - } + if (pll->on && pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); pll->state.pipe_mask = 0; for_each_intel_crtc(&i915->drm, crtc) { diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index dd4796a61751..2e7ea0d8d3ff 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -27,6 +27,7 @@ #include +#include "intel_display_power.h" #include "intel_wakeref.h" #define for_each_shared_dpll(__i915, __pll, __i) \ @@ -270,6 +271,11 @@ struct dpll_info { */ enum intel_dpll_id id; + /** + * @power_domain: extra power domain required by the DPLL + */ + enum intel_display_power_domain power_domain; + #define INTEL_DPLL_ALWAYS_ON (1 << 0) /** * @flags: From 3e7e07c4cf638b281f420be77afef7d93481a212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:35:21 +0300 Subject: [PATCH 0165/7721] drm/i915: Move the DPLL extra power domain handling up one level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extra DPLL power domain is currently handled in three places: - combo_pll_enable() - combo_pll_disable() - readout_dpll_hw_state() First two of those are low level PLL funcs, but the third is a higher level thing. So the current situation is rather inconsistent. Unify this by moving the PLL enable/disable up one level. This also means the extra power domain could be trivially be used by other platforms as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012123522.26045-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 4e524cb8ed83..556b10eefe66 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -258,6 +258,10 @@ void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state) drm_WARN_ON(&i915->drm, pll->on); drm_dbg_kms(&i915->drm, "enabling %s\n", pll->info->name); + + if (pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); + pll->info->funcs->enable(i915, pll); pll->on = true; @@ -307,6 +311,9 @@ void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state) pll->info->funcs->disable(i915, pll); pll->on = false; + if (pll->info->power_domain) + intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); + out: mutex_unlock(&i915->display.dpll.lock); } @@ -3838,9 +3845,6 @@ static void combo_pll_enable(struct drm_i915_private *i915, { i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - if (pll->info->power_domain) - pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); - icl_pll_power_enable(i915, pll, enable_reg); icl_dpll_write(i915, pll); @@ -3936,9 +3940,6 @@ static void combo_pll_disable(struct drm_i915_private *i915, i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); icl_pll_disable(i915, pll, enable_reg); - - if (pll->info->power_domain) - intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); } static void tbt_pll_disable(struct drm_i915_private *i915, @@ -4409,6 +4410,9 @@ static void sanitize_dpll_state(struct drm_i915_private *i915, pll->info->funcs->disable(i915, pll); pll->on = false; + + if (pll->info->power_domain) + intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); } void intel_dpll_sanitize_state(struct drm_i915_private *i915) From 7880d41c55f1e177a88c275d2e3ccec4debfcb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:35:22 +0300 Subject: [PATCH 0166/7721] drm/i915: Extract _intel_{enable,disable}_shared_dpll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a bit of duplicated code around the DPLL disabling. Extract that to a new function, and for symmetry also do the same for the enable direction. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012123522.26045-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 556b10eefe66..7958d0bd851e 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -219,6 +219,26 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915, return MG_PLL_ENABLE(tc_port); } +static void _intel_enable_shared_dpll(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) +{ + if (pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); + + pll->info->funcs->enable(i915, pll); + pll->on = true; +} + +static void _intel_disable_shared_dpll(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) +{ + pll->info->funcs->disable(i915, pll); + pll->on = false; + + if (pll->info->power_domain) + intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); +} + /** * intel_enable_shared_dpll - enable a CRTC's shared DPLL * @crtc_state: CRTC, and its state, which has a shared DPLL @@ -259,11 +279,7 @@ void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state) drm_dbg_kms(&i915->drm, "enabling %s\n", pll->info->name); - if (pll->info->power_domain) - pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); - - pll->info->funcs->enable(i915, pll); - pll->on = true; + _intel_enable_shared_dpll(i915, pll); out: mutex_unlock(&i915->display.dpll.lock); @@ -308,11 +324,8 @@ void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state) goto out; drm_dbg_kms(&i915->drm, "disabling %s\n", pll->info->name); - pll->info->funcs->disable(i915, pll); - pll->on = false; - if (pll->info->power_domain) - intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); + _intel_disable_shared_dpll(i915, pll); out: mutex_unlock(&i915->display.dpll.lock); @@ -4408,11 +4421,7 @@ static void sanitize_dpll_state(struct drm_i915_private *i915, "%s enabled but not in use, disabling\n", pll->info->name); - pll->info->funcs->disable(i915, pll); - pll->on = false; - - if (pll->info->power_domain) - intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); + _intel_disable_shared_dpll(i915, pll); } void intel_dpll_sanitize_state(struct drm_i915_private *i915) From b0462e94c964145c1962876f18e99f82fb4e6e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:40:33 +0300 Subject: [PATCH 0167/7721] drm/i915: Move the g45 PEG band gap HPD workaround to the HPD code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are asked to reprogram PEG_BAND_GAP_DATA prior to enabling hotplug detection on the g45 HDMI/DP ports. Currently we do said reprogamming from the DP/HDMI connector initialization functions. That code should be mostly platform agnostic so clearly not the best place for this. Move the workaround to the place where we actually enable HPD detection. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012124033.26983-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 10 ---------- drivers/gpu/drm/i915/display/intel_hdmi.c | 10 ---------- drivers/gpu/drm/i915/display/intel_hotplug_irq.c | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ab4608dafe5d..ea97db7d9abf 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6231,16 +6231,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } - /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written - * 0xd. Failure to do so will result in spurious interrupts being - * generated on the port when a cable is not attached. - */ - if (IS_G45(dev_priv)) { - u32 temp = intel_de_read(dev_priv, PEG_BAND_GAP_DATA); - intel_de_write(dev_priv, PEG_BAND_GAP_DATA, - (temp & ~0xf) | 0xd); - } - intel_dp->frl.is_trained = false; intel_dp->frl.trained_rate_gbps = 0; diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index ac315f8e7820..ab18cfc19c0a 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3030,16 +3030,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } - /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written - * 0xd. Failure to do so will result in spurious interrupts being - * generated on the port when a cable is not attached. - */ - if (IS_G45(dev_priv)) { - u32 temp = intel_de_read(dev_priv, PEG_BAND_GAP_DATA); - intel_de_write(dev_priv, PEG_BAND_GAP_DATA, - (temp & ~0xf) | 0xd); - } - cec_fill_conn_info_from_drm(&conn_info, connector); intel_hdmi->cec_notifier = diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index f07047e9cb30..04f62f27ad74 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -1361,11 +1361,24 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) bxt_hpd_detection_setup(dev_priv); } +static void g45_hpd_peg_band_gap_wa(struct drm_i915_private *i915) +{ + /* + * For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written + * 0xd. Failure to do so will result in spurious interrupts being + * generated on the port when a cable is not attached. + */ + intel_de_rmw(i915, PEG_BAND_GAP_DATA, 0xf, 0xd); +} + static void i915_hpd_enable_detection(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 hotplug_en = hpd_mask_i915[encoder->hpd_pin]; + if (IS_G45(i915)) + g45_hpd_peg_band_gap_wa(i915); + /* HPD sense and interrupt enable are one and the same */ i915_hotplug_interrupt_update(i915, hotplug_en, hotplug_en); } @@ -1389,6 +1402,9 @@ static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv) hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + if (IS_G45(dev_priv)) + g45_hpd_peg_band_gap_wa(dev_priv); + /* Ignore TV since it's buggy */ i915_hotplug_interrupt_update_locked(dev_priv, HOTPLUG_INT_EN_MASK | From 56d9854bd7c6b29a65fbb4175e01196166ed61de Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Wed, 25 Oct 2023 20:47:56 +0300 Subject: [PATCH 0168/7721] wifi: ath12k: drop NULL pointer check in ath12k_update_per_peer_tx_stats() Since 'user_stats' is a fixed-size array of 'struct htt_ppdu_user_stats' in 'struct htt_ppdu_stats', any of its member can't be NULL and so relevant check may be dropped. Signed-off-by: Ma Ke Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231013074711.2202850-1-make_ruc2021@163.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 3543fadac4a5..9f831e3971f9 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1339,9 +1339,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, u8 tid = HTT_PPDU_STATS_NON_QOS_TID; bool is_ampdu = false; - if (!usr_stats) - return; - if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) return; From ac2f43d3d34e52b0d388b4c573ff6bbac90235b9 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 25 Oct 2023 20:47:56 +0300 Subject: [PATCH 0169/7721] wifi: ath10k: replace deprecated strncpy with memcpy strncpy() is deprecated [1] and we should prefer less ambiguous interfaces. In this case, arvif->u.ap.ssid has its length maintained by arvif->u.ap.ssid_len which indicates it may not need to be NUL-terminated. Make this explicit with __nonstring and use a plain old memcpy. This is also consistent with future copies into arvif->u.ap.ssid: if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { arvif->u.ap.ssid_len = vif->cfg.ssid_len; if (vif->cfg.ssid_len) memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); arvif->u.ap.hidden_ssid = info->hidden_ssid; } Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231024-strncpy-drivers-net-wireless-ath-ath10k-mac-c-v2-1-4c1f4cd4b4df@google.com --- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4b5239de4018..ba9795a8378a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -607,7 +607,7 @@ struct ath10k_vif { u8 tim_bitmap[64]; u8 tim_len; u32 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN] __nonstring; bool hidden_ssid; /* P2P_IE with NoA attribute for P2P_GO case */ u32 noa_len; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2cf693f3fea9..e18427f72492 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6121,9 +6121,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (ieee80211_vif_is_mesh(vif)) { /* mesh doesn't use SSID but firmware needs it */ - strncpy(arvif->u.ap.ssid, "mesh", - sizeof(arvif->u.ap.ssid)); arvif->u.ap.ssid_len = 4; + memcpy(arvif->u.ap.ssid, "mesh", arvif->u.ap.ssid_len); } } From da36ce00997e10ed06c9fa66fbce546cad23815f Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Thu, 26 Oct 2023 17:41:38 +0530 Subject: [PATCH 0170/7721] drm/i915/hdcp: Rename HCDP 1.4 enablement function Rename hdcp 1.4 enablement function from _intel_hdcp_enable to intel_hdcp1_enable to better represent what version of hdcp is being enabled Signed-off-by: Suraj Kandpal Reviewed-by: Jani Nikula Signed-off-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20231026121139.987437-2-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_hdcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index c89da3568ebd..7c0cfcb48521 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -923,7 +923,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector) return 0; } -static int _intel_hdcp_enable(struct intel_connector *connector) +static int intel_hdcp1_enable(struct intel_connector *connector) { struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; @@ -1058,7 +1058,7 @@ static int intel_hdcp_check_link(struct intel_connector *connector) goto out; } - ret = _intel_hdcp_enable(connector); + ret = intel_hdcp1_enable(connector); if (ret) { drm_err(&i915->drm, "Failed to enable hdcp (%d)\n", ret); intel_hdcp_update_value(connector, @@ -2388,7 +2388,7 @@ int intel_hdcp_enable(struct intel_atomic_state *state, */ if (ret && intel_hdcp_capable(connector) && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) { - ret = _intel_hdcp_enable(connector); + ret = intel_hdcp1_enable(connector); } if (!ret) { From 4f60f06a41f441cd5a8570c61701ba40796fa52c Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Thu, 26 Oct 2023 17:41:39 +0530 Subject: [PATCH 0171/7721] drm/i915/hdcp: Convert intel_hdcp_enable to a blanket function Let's convert intel_hdcp_enable to a blanket function which just has some conditions which needs to be checked before connectors enable hdcp. This cleans up code and avoids code duplication. --v3 -Keep function name as intel_hdcp_enable() [Jani] Signed-off-by: Suraj Kandpal Reviewed-by: Jani Nikula Signed-off-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20231026121139.987437-3-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 5 +---- drivers/gpu/drm/i915/display/intel_dp_mst.c | 5 +---- drivers/gpu/drm/i915/display/intel_hdcp.c | 21 ++++++++++++++++----- drivers/gpu/drm/i915/display/intel_hdcp.h | 8 ++++---- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c4dc1f71da4b..2e37708fecdd 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3259,10 +3259,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state, else intel_enable_ddi_dp(state, encoder, crtc_state, conn_state); - /* Enable hdcp if it's desired */ - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) - intel_hdcp_enable(state, encoder, crtc_state, conn_state); + intel_hdcp_enable(state, encoder, crtc_state, conn_state); } static void intel_disable_ddi_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 7b4628f4f124..4366da79fe81 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -836,10 +836,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_audio_codec_enable(encoder, pipe_config, conn_state); - /* Enable hdcp if it's desired */ - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) - intel_hdcp_enable(state, encoder, pipe_config, conn_state); + intel_hdcp_enable(state, encoder, pipe_config, conn_state); } static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 7c0cfcb48521..44c0a93f3af8 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -2324,10 +2324,10 @@ intel_hdcp_set_streams(struct intel_digital_port *dig_port, return 0; } -int intel_hdcp_enable(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *pipe_config, - const struct drm_connector_state *conn_state) +static int _intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_connector *connector = @@ -2404,6 +2404,17 @@ int intel_hdcp_enable(struct intel_atomic_state *state, return ret; } +void intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + /* Enable hdcp if it's desired */ + if (conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_DESIRED) + _intel_hdcp_enable(state, encoder, crtc_state, conn_state); +} + int intel_hdcp_disable(struct intel_connector *connector) { struct intel_digital_port *dig_port = intel_attached_dig_port(connector); @@ -2491,7 +2502,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, } if (desired_and_not_enabled || content_protection_type_changed) - intel_hdcp_enable(state, encoder, crtc_state, conn_state); + _intel_hdcp_enable(state, encoder, crtc_state, conn_state); } void intel_hdcp_component_fini(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h index 5997c52a0958..a9c784fd9ba5 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h @@ -28,10 +28,10 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, int intel_hdcp_init(struct intel_connector *connector, struct intel_digital_port *dig_port, const struct intel_hdcp_shim *hdcp_shim); -int intel_hdcp_enable(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *pipe_config, - const struct drm_connector_state *conn_state); +void intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state); int intel_hdcp_disable(struct intel_connector *connector); void intel_hdcp_update_pipe(struct intel_atomic_state *state, struct intel_encoder *encoder, From 3b9bbd79627043a9fa9dd5b01bb29882663976e0 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Thu, 26 Oct 2023 17:41:40 +0530 Subject: [PATCH 0172/7721] drm/i915/hdcp: Add more conditions to enable hdcp When we dock a monitor we end up with a enable and disable connector cycle but if hdcp content is running we get the userspace in enabled state and driver maintaining a undesired state which causes the content to stop playing and we only enable hdcp if the userspace state in desired. This patch fixes that. --v2 -Move code to intel_hdcp [Jani] Signed-off-by: Suraj Kandpal Reviewed-by: Ankit Nautiyal Signed-off-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20231026121139.987437-4-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_hdcp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 44c0a93f3af8..39b3f7c0c77c 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -2409,9 +2409,19 @@ void intel_hdcp_enable(struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - /* Enable hdcp if it's desired */ + struct intel_connector *connector = + to_intel_connector(conn_state->connector); + struct intel_hdcp *hdcp = &connector->hdcp; + + /* + * Enable hdcp if it's desired or if userspace is enabled and + * driver set its state to undesired + */ if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) + DRM_MODE_CONTENT_PROTECTION_DESIRED || + (conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_ENABLED && hdcp->value == + DRM_MODE_CONTENT_PROTECTION_UNDESIRED)) _intel_hdcp_enable(state, encoder, crtc_state, conn_state); } From 949113d34fb82a5dc6f5dd3ad9168001b441792b Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 25 Oct 2023 12:28:26 +0200 Subject: [PATCH 0173/7721] drm/i915/mtl: Apply notify_guc to all GTs Handle platforms with multiple GTs by iterate over all GTs. Add a Fixes commit so this gets propagated for MTL support. Fixes: 213c43676beb ("drm/i915/mtl: Remove the 'force_probe' requirement for Meteor Lake") Suggested-by: John Harrison Cc: Jani Nikula Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Andi Shyti Cc: Andrzej Hajda Signed-off-by: Nirmoy Das Reviewed-by: Andi Shyti Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20231025102826.16955-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/i915_debugfs_params.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs_params.c b/drivers/gpu/drm/i915/i915_debugfs_params.c index 614bde321589..8bca02025e09 100644 --- a/drivers/gpu/drm/i915/i915_debugfs_params.c +++ b/drivers/gpu/drm/i915/i915_debugfs_params.c @@ -38,10 +38,13 @@ static int i915_param_int_open(struct inode *inode, struct file *file) static int notify_guc(struct drm_i915_private *i915) { - int ret = 0; + struct intel_gt *gt; + int i, ret = 0; - if (intel_uc_uses_guc_submission(&to_gt(i915)->uc)) - ret = intel_guc_global_policies_update(&to_gt(i915)->uc.guc); + for_each_gt(gt, i915, i) { + if (intel_uc_uses_guc_submission(>->uc)) + ret = intel_guc_global_policies_update(>->uc.guc); + } return ret; } From 9bb66c179f50e61df20ba13c9b34ca17d00b05fb Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 26 Oct 2023 20:36:26 +0200 Subject: [PATCH 0174/7721] drm/i915: Reserve some kernel space per vm Reserve one page in each vm for kernel space to use for things such as workarounds. v2: use real memory, do not decrease vm.total v4: reserve only one page and explain flag v5: remove allocated object on ppgtt cleanup v6: decrease vm->total by reservation size Suggested-by: Chris Wilson Signed-off-by: Andrzej Hajda Reviewed-by: Jonathan Cavitt Reviewed-by: Nirmoy Das Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026-wabb-v6-1-4aa7d55d0a8a@intel.com --- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 43 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gtt.h | 4 +++ 2 files changed, 47 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 9895e18df043..fa46d2308b0e 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -5,6 +5,7 @@ #include +#include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" #include "gen8_ppgtt.h" @@ -222,6 +223,9 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); + if (vm->rsvd.obj) + i915_gem_object_put(vm->rsvd.obj); + if (intel_vgpu_active(vm->i915)) gen8_ppgtt_notify_vgt(ppgtt, false); @@ -950,6 +954,41 @@ gen8_alloc_top_pd(struct i915_address_space *vm) return ERR_PTR(err); } +static int gen8_init_rsvd(struct i915_address_space *vm) +{ + struct drm_i915_private *i915 = vm->i915; + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + int ret; + + /* The memory will be used only by GPU. */ + obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, + I915_BO_ALLOC_VOLATILE | + I915_BO_ALLOC_GPU_ONLY); + if (IS_ERR(obj)) + obj = i915_gem_object_create_internal(i915, PAGE_SIZE); + if (IS_ERR(obj)) + return PTR_ERR(obj); + + vma = i915_vma_instance(obj, vm, NULL); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto unref; + } + + ret = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_HIGH); + if (ret) + goto unref; + + vm->rsvd.vma = i915_vma_make_unshrinkable(vma); + vm->rsvd.obj = obj; + vm->total -= vma->node.size; + return 0; +unref: + i915_gem_object_put(obj); + return ret; +} + /* * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers * with a net effect resembling a 2-level page table in normal x86 terms. Each @@ -1031,6 +1070,10 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, if (intel_vgpu_active(gt->i915)) gen8_ppgtt_notify_vgt(ppgtt, true); + err = gen8_init_rsvd(&ppgtt->vm); + if (err) + goto err_put; + return ppgtt; err_put: diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index b471edac2699..028a5a988eea 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -249,6 +249,10 @@ struct i915_address_space { struct work_struct release_work; struct drm_mm mm; + struct { + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + } rsvd; struct intel_gt *gt; struct drm_i915_private *i915; struct device *dma; From 03fe4b87c6420fde29e3401f87fcdc271c960950 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 26 Oct 2023 20:36:27 +0200 Subject: [PATCH 0175/7721] drm/i915: Add WABB blit for Wa_16018031267 / Wa_16018063123 Apply WABB blit for Wa_16018031267 / Wa_16018063123. v3: drop unused enum definition v4: move selftest to separate patch, use wa only on BCS0. v5: fixed selftest caller to context_wabb Signed-off-by: Nirmoy Das Signed-off-by: Jonathan Cavitt Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026-wabb-v6-2-4aa7d55d0a8a@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_regs.h | 3 + drivers/gpu/drm/i915/gt/intel_gt.h | 4 + drivers/gpu/drm/i915/gt/intel_lrc.c | 100 +++++++++++++++++++- drivers/gpu/drm/i915/gt/selftest_lrc.c | 2 +- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index fdd4ddd3a978..b8618ee3e304 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -118,6 +118,9 @@ #define CCID_EXTENDED_STATE_RESTORE BIT(2) #define CCID_EXTENDED_STATE_SAVE BIT(3) #define RING_BB_PER_CTX_PTR(base) _MMIO((base) + 0x1c0) /* gen8+ */ +#define PER_CTX_BB_FORCE BIT(2) +#define PER_CTX_BB_VALID BIT(0) + #define RING_INDIRECT_CTX(base) _MMIO((base) + 0x1c4) /* gen8+ */ #define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base) + 0x1c8) /* gen8+ */ #define ECOSKPD(base) _MMIO((base) + 0x1d0) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 970bedf6b78a..9ffdb05e231e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -82,6 +82,10 @@ struct drm_printer; ##__VA_ARGS__); \ } while (0) +#define NEEDS_FASTCOLOR_BLT_WABB(engine) ( \ + IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 55), IP_VER(12, 71)) && \ + engine->class == COPY_ENGINE_CLASS && engine->instance == 0) + static inline bool gt_is_root(struct intel_gt *gt) { return !gt->info.id; diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index eaf66d903166..7c367ba8d9dc 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -828,6 +828,18 @@ lrc_ring_indirect_offset_default(const struct intel_engine_cs *engine) return 0; } +static void +lrc_setup_bb_per_ctx(u32 *regs, + const struct intel_engine_cs *engine, + u32 ctx_bb_ggtt_addr) +{ + GEM_BUG_ON(lrc_ring_wa_bb_per_ctx(engine) == -1); + regs[lrc_ring_wa_bb_per_ctx(engine) + 1] = + ctx_bb_ggtt_addr | + PER_CTX_BB_FORCE | + PER_CTX_BB_VALID; +} + static void lrc_setup_indirect_ctx(u32 *regs, const struct intel_engine_cs *engine, @@ -1020,7 +1032,13 @@ static u32 context_wa_bb_offset(const struct intel_context *ce) return PAGE_SIZE * ce->wa_bb_page; } -static u32 *context_indirect_bb(const struct intel_context *ce) +/* + * per_ctx below determines which WABB section is used. + * When true, the function returns the location of the + * PER_CTX_BB. When false, the function returns the + * location of the INDIRECT_CTX. + */ +static u32 *context_wabb(const struct intel_context *ce, bool per_ctx) { void *ptr; @@ -1029,6 +1047,7 @@ static u32 *context_indirect_bb(const struct intel_context *ce) ptr = ce->lrc_reg_state; ptr -= LRC_STATE_OFFSET; /* back to start of context image */ ptr += context_wa_bb_offset(ce); + ptr += per_ctx ? PAGE_SIZE : 0; return ptr; } @@ -1105,7 +1124,8 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) if (GRAPHICS_VER(engine->i915) >= 12) { ce->wa_bb_page = context_size / PAGE_SIZE; - context_size += PAGE_SIZE; + /* INDIRECT_CTX and PER_CTX_BB need separate pages. */ + context_size += PAGE_SIZE * 2; } if (intel_context_is_parent(ce) && intel_engine_uses_guc(engine)) { @@ -1407,12 +1427,85 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) return gen12_emit_aux_table_inv(ce->engine, cs); } +static u32 *xehp_emit_fastcolor_blt_wabb(const struct intel_context *ce, u32 *cs) +{ + struct intel_gt *gt = ce->engine->gt; + int mocs = gt->mocs.uc_index << 1; + + /** + * Wa_16018031267 / Wa_16018063123 requires that SW forces the + * main copy engine arbitration into round robin mode. We + * additionally need to submit the following WABB blt command + * to produce 4 subblits with each subblit generating 0 byte + * write requests as WABB: + * + * XY_FASTCOLOR_BLT + * BG0 -> 5100000E + * BG1 -> 0000003F (Dest pitch) + * BG2 -> 00000000 (X1, Y1) = (0, 0) + * BG3 -> 00040001 (X2, Y2) = (1, 4) + * BG4 -> scratch + * BG5 -> scratch + * BG6-12 -> 00000000 + * BG13 -> 20004004 (Surf. Width= 2,Surf. Height = 5 ) + * BG14 -> 00000010 (Qpitch = 4) + * BG15 -> 00000000 + */ + *cs++ = XY_FAST_COLOR_BLT_CMD | (16 - 2); + *cs++ = FIELD_PREP(XY_FAST_COLOR_BLT_MOCS_MASK, mocs) | 0x3f; + *cs++ = 0; + *cs++ = 4 << 16 | 1; + *cs++ = lower_32_bits(i915_vma_offset(ce->vm->rsvd.vma)); + *cs++ = upper_32_bits(i915_vma_offset(ce->vm->rsvd.vma)); + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0x20004004; + *cs++ = 0x10; + *cs++ = 0; + + return cs; +} + +static u32 * +xehp_emit_per_ctx_bb(const struct intel_context *ce, u32 *cs) +{ + /* Wa_16018031267, Wa_16018063123 */ + if (NEEDS_FASTCOLOR_BLT_WABB(ce->engine)) + cs = xehp_emit_fastcolor_blt_wabb(ce, cs); + + return cs; +} + +static void +setup_per_ctx_bb(const struct intel_context *ce, + const struct intel_engine_cs *engine, + u32 *(*emit)(const struct intel_context *, u32 *)) +{ + /* Place PER_CTX_BB on next page after INDIRECT_CTX */ + u32 * const start = context_wabb(ce, true); + u32 *cs; + + cs = emit(ce, start); + + /* PER_CTX_BB must manually terminate */ + *cs++ = MI_BATCH_BUFFER_END; + + GEM_BUG_ON(cs - start > I915_GTT_PAGE_SIZE / sizeof(*cs)); + lrc_setup_bb_per_ctx(ce->lrc_reg_state, engine, + lrc_indirect_bb(ce) + PAGE_SIZE); +} + static void setup_indirect_ctx_bb(const struct intel_context *ce, const struct intel_engine_cs *engine, u32 *(*emit)(const struct intel_context *, u32 *)) { - u32 * const start = context_indirect_bb(ce); + u32 * const start = context_wabb(ce, false); u32 *cs; cs = emit(ce, start); @@ -1511,6 +1604,7 @@ u32 lrc_update_regs(const struct intel_context *ce, /* Mutually exclusive wrt to global indirect bb */ GEM_BUG_ON(engine->wa_ctx.indirect_ctx.size); setup_indirect_ctx_bb(ce, engine, fn); + setup_per_ctx_bb(ce, engine, xehp_emit_per_ctx_bb); } return lrc_descriptor(ce) | CTX_DESC_FORCE_RESTORE; diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c index 5f826b6dcf5d..823d38aa3934 100644 --- a/drivers/gpu/drm/i915/gt/selftest_lrc.c +++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c @@ -1596,7 +1596,7 @@ emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) static void indirect_ctx_bb_setup(struct intel_context *ce) { - u32 *cs = context_indirect_bb(ce); + u32 *cs = context_wabb(ce, false); cs[CTX_BB_CANARY_INDEX] = 0xdeadf00d; From 3a32ef21ed5497f30f2bc99074014496748533d3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 26 Oct 2023 20:36:28 +0200 Subject: [PATCH 0176/7721] drm/i915/gt: add selftest to exercise WABB Test re-uses logic form indirect ctx BB selftest. Signed-off-by: Nirmoy Das Signed-off-by: Jonathan Cavitt Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026-wabb-v6-3-4aa7d55d0a8a@intel.com --- drivers/gpu/drm/i915/gt/selftest_lrc.c | 67 ++++++++++++++++++-------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c index 823d38aa3934..e17b8777d21d 100644 --- a/drivers/gpu/drm/i915/gt/selftest_lrc.c +++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c @@ -1555,7 +1555,7 @@ static int live_lrc_isolation(void *arg) return err; } -static int indirect_ctx_submit_req(struct intel_context *ce) +static int wabb_ctx_submit_req(struct intel_context *ce) { struct i915_request *rq; int err = 0; @@ -1579,7 +1579,8 @@ static int indirect_ctx_submit_req(struct intel_context *ce) #define CTX_BB_CANARY_INDEX (CTX_BB_CANARY_OFFSET / sizeof(u32)) static u32 * -emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) +emit_wabb_ctx_canary(const struct intel_context *ce, + u32 *cs, bool per_ctx) { *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_SRM_LRM_GLOBAL_GTT | @@ -1587,26 +1588,43 @@ emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) *cs++ = i915_mmio_reg_offset(RING_START(0)); *cs++ = i915_ggtt_offset(ce->state) + context_wa_bb_offset(ce) + - CTX_BB_CANARY_OFFSET; + CTX_BB_CANARY_OFFSET + + (per_ctx ? PAGE_SIZE : 0); *cs++ = 0; return cs; } -static void -indirect_ctx_bb_setup(struct intel_context *ce) +static u32 * +emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) { - u32 *cs = context_wabb(ce, false); + return emit_wabb_ctx_canary(ce, cs, false); +} + +static u32 * +emit_per_ctx_bb_canary(const struct intel_context *ce, u32 *cs) +{ + return emit_wabb_ctx_canary(ce, cs, true); +} + +static void +wabb_ctx_setup(struct intel_context *ce, bool per_ctx) +{ + u32 *cs = context_wabb(ce, per_ctx); cs[CTX_BB_CANARY_INDEX] = 0xdeadf00d; - setup_indirect_ctx_bb(ce, ce->engine, emit_indirect_ctx_bb_canary); + if (per_ctx) + setup_per_ctx_bb(ce, ce->engine, emit_per_ctx_bb_canary); + else + setup_indirect_ctx_bb(ce, ce->engine, emit_indirect_ctx_bb_canary); } -static bool check_ring_start(struct intel_context *ce) +static bool check_ring_start(struct intel_context *ce, bool per_ctx) { const u32 * const ctx_bb = (void *)(ce->lrc_reg_state) - - LRC_STATE_OFFSET + context_wa_bb_offset(ce); + LRC_STATE_OFFSET + context_wa_bb_offset(ce) + + (per_ctx ? PAGE_SIZE : 0); if (ctx_bb[CTX_BB_CANARY_INDEX] == ce->lrc_reg_state[CTX_RING_START]) return true; @@ -1618,21 +1636,21 @@ static bool check_ring_start(struct intel_context *ce) return false; } -static int indirect_ctx_bb_check(struct intel_context *ce) +static int wabb_ctx_check(struct intel_context *ce, bool per_ctx) { int err; - err = indirect_ctx_submit_req(ce); + err = wabb_ctx_submit_req(ce); if (err) return err; - if (!check_ring_start(ce)) + if (!check_ring_start(ce, per_ctx)) return -EINVAL; return 0; } -static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine) +static int __lrc_wabb_ctx(struct intel_engine_cs *engine, bool per_ctx) { struct intel_context *a, *b; int err; @@ -1667,14 +1685,14 @@ static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine) * As ring start is restored apriori of starting the indirect ctx bb and * as it will be different for each context, it fits to this purpose. */ - indirect_ctx_bb_setup(a); - indirect_ctx_bb_setup(b); + wabb_ctx_setup(a, per_ctx); + wabb_ctx_setup(b, per_ctx); - err = indirect_ctx_bb_check(a); + err = wabb_ctx_check(a, per_ctx); if (err) goto unpin_b; - err = indirect_ctx_bb_check(b); + err = wabb_ctx_check(b, per_ctx); unpin_b: intel_context_unpin(b); @@ -1688,7 +1706,7 @@ static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine) return err; } -static int live_lrc_indirect_ctx_bb(void *arg) +static int lrc_wabb_ctx(void *arg, bool per_ctx) { struct intel_gt *gt = arg; struct intel_engine_cs *engine; @@ -1697,7 +1715,7 @@ static int live_lrc_indirect_ctx_bb(void *arg) for_each_engine(engine, gt, id) { intel_engine_pm_get(engine); - err = __live_lrc_indirect_ctx_bb(engine); + err = __lrc_wabb_ctx(engine, per_ctx); intel_engine_pm_put(engine); if (igt_flush_test(gt->i915)) @@ -1710,6 +1728,16 @@ static int live_lrc_indirect_ctx_bb(void *arg) return err; } +static int live_lrc_indirect_ctx_bb(void *arg) +{ + return lrc_wabb_ctx(arg, false); +} + +static int live_lrc_per_ctx_bb(void *arg) +{ + return lrc_wabb_ctx(arg, true); +} + static void garbage_reset(struct intel_engine_cs *engine, struct i915_request *rq) { @@ -1947,6 +1975,7 @@ int intel_lrc_live_selftests(struct drm_i915_private *i915) SUBTEST(live_lrc_garbage), SUBTEST(live_pphwsp_runtime), SUBTEST(live_lrc_indirect_ctx_bb), + SUBTEST(live_lrc_per_ctx_bb), }; if (!HAS_LOGICAL_RING_CONTEXTS(i915)) From 2fb771f3b840ff59e593dad9b6289276ea545698 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Thu, 26 Oct 2023 20:36:29 +0200 Subject: [PATCH 0177/7721] drm/i915: Set copy engine arbitration for Wa_16018031267 / Wa_16018063123 Set copy engine arbitration into round robin mode for part of Wa_16018031267 / Wa_16018063123 mitigation. Signed-off-by: Nirmoy Das Signed-off-by: Jonathan Cavitt Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231026-wabb-v6-4-4aa7d55d0a8a@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_regs.h | 3 +++ drivers/gpu/drm/i915/gt/intel_workarounds.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index b8618ee3e304..c0c8c12edea1 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -124,6 +124,9 @@ #define RING_INDIRECT_CTX(base) _MMIO((base) + 0x1c4) /* gen8+ */ #define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base) + 0x1c8) /* gen8+ */ #define ECOSKPD(base) _MMIO((base) + 0x1d0) +#define XEHP_BLITTER_SCHEDULING_MODE_MASK REG_GENMASK(12, 11) +#define XEHP_BLITTER_ROUND_ROBIN_MODE \ + REG_FIELD_PREP(XEHP_BLITTER_SCHEDULING_MODE_MASK, 1) #define ECO_CONSTANT_BUFFER_SR_DISABLE REG_BIT(4) #define ECO_GATING_CX_ONLY REG_BIT(3) #define GEN6_BLITTER_FBC_NOTIFY REG_BIT(3) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 6ae7a4de83b0..12859b8d2092 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2785,6 +2785,11 @@ xcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) RING_SEMA_WAIT_POLL(engine->mmio_base), 1); } + /* Wa_16018031267, Wa_16018063123 */ + if (NEEDS_FASTCOLOR_BLT_WABB(engine)) + wa_masked_field_set(wal, ECOSKPD(engine->mmio_base), + XEHP_BLITTER_SCHEDULING_MODE_MASK, + XEHP_BLITTER_ROUND_ROBIN_MODE); } static void From ca34d816558c3e4c3f8fe037b5a6b16c944693de Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 20 Sep 2023 15:57:16 +0300 Subject: [PATCH 0178/7721] Revert "drm/tidss: Annotate dma-fence critical section in commit path" This reverts commit 4d56a4f08391857ba93465de489707b66adad114. The DMA-fence annotations cause a lockdep warning (see below). As per https://patchwork.freedesktop.org/patch/462170/ it sounds like the annotations don't work correctly. ====================================================== WARNING: possible circular locking dependency detected 6.6.0-rc2+ #1 Not tainted ------------------------------------------------------ kmstest/733 is trying to acquire lock: ffff8000819377f0 (fs_reclaim){+.+.}-{0:0}, at: __kmem_cache_alloc_node+0x58/0x2d4 but task is already holding lock: ffff800081a06aa0 (dma_fence_map){++++}-{0:0}, at: tidss_atomic_commit_tail+0x20/0xc0 [tidss] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (dma_fence_map){++++}-{0:0}: __dma_fence_might_wait+0x5c/0xd0 dma_resv_lockdep+0x1a4/0x32c do_one_initcall+0x84/0x2fc kernel_init_freeable+0x28c/0x4c4 kernel_init+0x24/0x1dc ret_from_fork+0x10/0x20 -> #1 (mmu_notifier_invalidate_range_start){+.+.}-{0:0}: fs_reclaim_acquire+0x70/0xe4 __kmem_cache_alloc_node+0x58/0x2d4 kmalloc_trace+0x38/0x78 __kthread_create_worker+0x3c/0x150 kthread_create_worker+0x64/0x8c workqueue_init+0x1e8/0x2f0 kernel_init_freeable+0x11c/0x4c4 kernel_init+0x24/0x1dc ret_from_fork+0x10/0x20 -> #0 (fs_reclaim){+.+.}-{0:0}: __lock_acquire+0x1370/0x20d8 lock_acquire+0x1e8/0x308 fs_reclaim_acquire+0xd0/0xe4 __kmem_cache_alloc_node+0x58/0x2d4 __kmalloc_node_track_caller+0x58/0xf0 kmemdup+0x34/0x60 regmap_bulk_write+0x64/0x2c0 tc358768_bridge_pre_enable+0x8c/0x12d0 [tc358768] drm_atomic_bridge_call_pre_enable+0x68/0x80 [drm] drm_atomic_bridge_chain_pre_enable+0x50/0x158 [drm] drm_atomic_helper_commit_modeset_enables+0x164/0x264 [drm_kms_helper] tidss_atomic_commit_tail+0x58/0xc0 [tidss] commit_tail+0xa0/0x188 [drm_kms_helper] drm_atomic_helper_commit+0x1a8/0x1c0 [drm_kms_helper] drm_atomic_commit+0xa8/0xe0 [drm] drm_mode_atomic_ioctl+0x9ec/0xc80 [drm] drm_ioctl_kernel+0xc4/0x170 [drm] drm_ioctl+0x234/0x4b0 [drm] drm_compat_ioctl+0x110/0x12c [drm] __arm64_compat_sys_ioctl+0x128/0x150 invoke_syscall+0x48/0x110 el0_svc_common.constprop.0+0x40/0xe0 do_el0_svc_compat+0x1c/0x38 el0_svc_compat+0x48/0xb4 el0t_32_sync_handler+0xb0/0x138 el0t_32_sync+0x194/0x198 other info that might help us debug this: Chain exists of: fs_reclaim --> mmu_notifier_invalidate_range_start --> dma_fence_map Possible unsafe locking scenario: CPU0 CPU1 ---- ---- rlock(dma_fence_map); lock(mmu_notifier_invalidate_range_start); lock(dma_fence_map); lock(fs_reclaim); *** DEADLOCK *** 3 locks held by kmstest/733: #0: ffff800082e5bba0 (crtc_ww_class_acquire){+.+.}-{0:0}, at: drm_mode_atomic_ioctl+0x118/0xc80 [drm] #1: ffff000004224c88 (crtc_ww_class_mutex){+.+.}-{3:3}, at: modeset_lock+0xdc/0x1a0 [drm] #2: ffff800081a06aa0 (dma_fence_map){++++}-{0:0}, at: tidss_atomic_commit_tail+0x20/0xc0 [tidss] stack backtrace: CPU: 0 PID: 733 Comm: kmstest Not tainted 6.6.0-rc2+ #1 Hardware name: Toradex Verdin AM62 on Verdin Development Board (DT) Call trace: dump_backtrace+0x98/0x118 show_stack+0x18/0x24 dump_stack_lvl+0x60/0xac dump_stack+0x18/0x24 print_circular_bug+0x288/0x368 check_noncircular+0x168/0x17c __lock_acquire+0x1370/0x20d8 lock_acquire+0x1e8/0x308 fs_reclaim_acquire+0xd0/0xe4 __kmem_cache_alloc_node+0x58/0x2d4 __kmalloc_node_track_caller+0x58/0xf0 kmemdup+0x34/0x60 regmap_bulk_write+0x64/0x2c0 tc358768_bridge_pre_enable+0x8c/0x12d0 [tc358768] drm_atomic_bridge_call_pre_enable+0x68/0x80 [drm] drm_atomic_bridge_chain_pre_enable+0x50/0x158 [drm] drm_atomic_helper_commit_modeset_enables+0x164/0x264 [drm_kms_helper] tidss_atomic_commit_tail+0x58/0xc0 [tidss] commit_tail+0xa0/0x188 [drm_kms_helper] drm_atomic_helper_commit+0x1a8/0x1c0 [drm_kms_helper] drm_atomic_commit+0xa8/0xe0 [drm] drm_mode_atomic_ioctl+0x9ec/0xc80 [drm] drm_ioctl_kernel+0xc4/0x170 [drm] drm_ioctl+0x234/0x4b0 [drm] drm_compat_ioctl+0x110/0x12c [drm] __arm64_compat_sys_ioctl+0x128/0x150 invoke_syscall+0x48/0x110 el0_svc_common.constprop.0+0x40/0xe0 do_el0_svc_compat+0x1c/0x38 el0_svc_compat+0x48/0xb4 el0t_32_sync_handler+0xb0/0x138 el0t_32_sync+0x194/0x198 Fixes: 4d56a4f08391 ("drm/tidss: Annotate dma-fence critical section in commit path") Reviewed-by: Aradhya Bhatia Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20230920-dma-fence-annotation-revert-v1-1-7ebf6f7f5bf6@ideasonboard.com --- drivers/gpu/drm/tidss/tidss_kms.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index c979ad1af236..d096d8d2bc8f 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -4,8 +4,6 @@ * Author: Tomi Valkeinen */ -#include - #include #include #include @@ -25,7 +23,6 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) { struct drm_device *ddev = old_state->dev; struct tidss_device *tidss = to_tidss(ddev); - bool fence_cookie = dma_fence_begin_signalling(); dev_dbg(ddev->dev, "%s\n", __func__); @@ -36,7 +33,6 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_enables(ddev, old_state); drm_atomic_helper_commit_hw_done(old_state); - dma_fence_end_signalling(fence_cookie); drm_atomic_helper_wait_for_flip_done(ddev, old_state); drm_atomic_helper_cleanup_planes(ddev, old_state); From 9d7c8c066916f231ca0ed4e4fce6c4b58ca3e451 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 20 Sep 2023 15:57:17 +0300 Subject: [PATCH 0179/7721] Revert "drm/omapdrm: Annotate dma-fence critical section in commit path" This reverts commit 250aa22920cd5d956a5d3e9c6a43d671c2bae217. The DMA-fence annotations cause a lockdep warning (see below). As per https://patchwork.freedesktop.org/patch/462170/ it sounds like the annotations don't work correctly. ====================================================== WARNING: possible circular locking dependency detected 6.5.0-rc2+ #2 Not tainted ------------------------------------------------------ kmstest/219 is trying to acquire lock: c4705838 (&hdmi->lock){+.+.}-{3:3}, at: hdmi5_bridge_mode_set+0x1c/0x50 but task is already holding lock: c11e1128 (dma_fence_map){++++}-{0:0}, at: omap_atomic_commit_tail+0x14/0xbc which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (dma_fence_map){++++}-{0:0}: __dma_fence_might_wait+0x48/0xb4 dma_resv_lockdep+0x1b8/0x2bc do_one_initcall+0x68/0x3b0 kernel_init_freeable+0x260/0x34c kernel_init+0x14/0x140 ret_from_fork+0x14/0x28 -> #1 (fs_reclaim){+.+.}-{0:0}: fs_reclaim_acquire+0x70/0xa8 __kmem_cache_alloc_node+0x3c/0x368 kmalloc_trace+0x28/0x58 _drm_do_get_edid+0x7c/0x35c hdmi5_bridge_get_edid+0xc8/0x1ac drm_bridge_connector_get_modes+0x64/0xc0 drm_helper_probe_single_connector_modes+0x170/0x528 drm_client_modeset_probe+0x208/0x1334 __drm_fb_helper_initial_config_and_unlock+0x30/0x548 omap_fbdev_client_hotplug+0x3c/0x6c drm_client_register+0x58/0x94 pdev_probe+0x544/0x6b0 platform_probe+0x58/0xbc really_probe+0xd8/0x3fc __driver_probe_device+0x94/0x1f4 driver_probe_device+0x2c/0xc4 __device_attach_driver+0xa4/0x11c bus_for_each_drv+0x84/0xdc __device_attach+0xac/0x20c bus_probe_device+0x8c/0x90 device_add+0x588/0x7e0 platform_device_add+0x110/0x24c platform_device_register_full+0x108/0x15c dss_bind+0x90/0xc0 try_to_bring_up_aggregate_device+0x1e0/0x2c8 __component_add+0xa4/0x174 hdmi5_probe+0x1c8/0x270 platform_probe+0x58/0xbc really_probe+0xd8/0x3fc __driver_probe_device+0x94/0x1f4 driver_probe_device+0x2c/0xc4 __device_attach_driver+0xa4/0x11c bus_for_each_drv+0x84/0xdc __device_attach+0xac/0x20c bus_probe_device+0x8c/0x90 deferred_probe_work_func+0x8c/0xd8 process_one_work+0x2ac/0x6e4 worker_thread+0x30/0x4ec kthread+0x100/0x124 ret_from_fork+0x14/0x28 -> #0 (&hdmi->lock){+.+.}-{3:3}: __lock_acquire+0x145c/0x29cc lock_acquire.part.0+0xb4/0x258 __mutex_lock+0x90/0x950 mutex_lock_nested+0x1c/0x24 hdmi5_bridge_mode_set+0x1c/0x50 drm_bridge_chain_mode_set+0x48/0x5c crtc_set_mode+0x188/0x1d0 omap_atomic_commit_tail+0x2c/0xbc commit_tail+0x9c/0x188 drm_atomic_helper_commit+0x158/0x18c drm_atomic_commit+0xa4/0xe8 drm_mode_atomic_ioctl+0x9a4/0xc38 drm_ioctl+0x210/0x4a8 sys_ioctl+0x138/0xf00 ret_fast_syscall+0x0/0x1c other info that might help us debug this: Chain exists of: &hdmi->lock --> fs_reclaim --> dma_fence_map Possible unsafe locking scenario: CPU0 CPU1 ---- ---- rlock(dma_fence_map); lock(fs_reclaim); lock(dma_fence_map); lock(&hdmi->lock); *** DEADLOCK *** 3 locks held by kmstest/219: #0: f1011de4 (crtc_ww_class_acquire){+.+.}-{0:0}, at: drm_mode_atomic_ioctl+0xf0/0xc38 #1: c47059c8 (crtc_ww_class_mutex){+.+.}-{3:3}, at: modeset_lock+0xf8/0x230 #2: c11e1128 (dma_fence_map){++++}-{0:0}, at: omap_atomic_commit_tail+0x14/0xbc stack backtrace: CPU: 1 PID: 219 Comm: kmstest Not tainted 6.5.0-rc2+ #2 Hardware name: Generic DRA74X (Flattened Device Tree) unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x58/0x70 dump_stack_lvl from check_noncircular+0x164/0x198 check_noncircular from __lock_acquire+0x145c/0x29cc __lock_acquire from lock_acquire.part.0+0xb4/0x258 lock_acquire.part.0 from __mutex_lock+0x90/0x950 __mutex_lock from mutex_lock_nested+0x1c/0x24 mutex_lock_nested from hdmi5_bridge_mode_set+0x1c/0x50 hdmi5_bridge_mode_set from drm_bridge_chain_mode_set+0x48/0x5c drm_bridge_chain_mode_set from crtc_set_mode+0x188/0x1d0 crtc_set_mode from omap_atomic_commit_tail+0x2c/0xbc omap_atomic_commit_tail from commit_tail+0x9c/0x188 commit_tail from drm_atomic_helper_commit+0x158/0x18c drm_atomic_helper_commit from drm_atomic_commit+0xa4/0xe8 drm_atomic_commit from drm_mode_atomic_ioctl+0x9a4/0xc38 drm_mode_atomic_ioctl from drm_ioctl+0x210/0x4a8 drm_ioctl from sys_ioctl+0x138/0xf00 sys_ioctl from ret_fast_syscall+0x0/0x1c Exception stack(0xf1011fa8 to 0xf1011ff0) 1fa0: 00466d58 be9ab510 00000003 c03864bc be9ab510 be9ab4e0 1fc0: 00466d58 be9ab510 c03864bc 00000036 00466ef0 00466fc0 00467020 00466f20 1fe0: b6bc7ef4 be9ab4d0 b6bbbb00 b6cb2cc0 Fixes: 250aa22920cd ("drm/omapdrm: Annotate dma-fence critical section in commit path") Reviewed-by: Aradhya Bhatia Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20230920-dma-fence-annotation-revert-v1-2-7ebf6f7f5bf6@ideasonboard.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index b2835b3ea6f5..6598c9c08ba1 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -69,7 +69,6 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; struct omap_drm_private *priv = dev->dev_private; - bool fence_cookie = dma_fence_begin_signalling(); dispc_runtime_get(priv->dispc); @@ -92,6 +91,8 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) omap_atomic_wait_for_completion(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state, 0); + + drm_atomic_helper_commit_hw_done(old_state); } else { /* * OMAP3 DSS seems to have issues with the work-around above, @@ -101,12 +102,10 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_planes(dev, old_state, 0); drm_atomic_helper_commit_modeset_enables(dev, old_state); + + drm_atomic_helper_commit_hw_done(old_state); } - drm_atomic_helper_commit_hw_done(old_state); - - dma_fence_end_signalling(fence_cookie); - /* * Wait for completion of the page flips to ensure that old buffers * can't be touched by the hardware anymore before cleaning up planes. From bfc87f90614523612ae7e94d06798e82bc78ade6 Mon Sep 17 00:00:00 2001 From: Krystian Pradzynski Date: Sat, 28 Oct 2023 17:59:29 +0200 Subject: [PATCH 0180/7721] accel/ivpu/40xx: Allow to change profiling frequency Profiling freq is a debug firmware feature. It switches default clock to higher resolution for fine-grained and more accurate firmware task profiling. We already configure it during boot up of VPU4. Add debugfs knob and helpers per HW generation that allow to change it. For vpu37xx the implementation is empty as profiling frequency can only be changed on VPU4 or newer. Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-2-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_debugfs.c | 29 +++++++++++++++++++++++++++++ drivers/accel/ivpu/ivpu_fw.c | 7 +++++++ drivers/accel/ivpu/ivpu_hw.h | 12 ++++++++++++ drivers/accel/ivpu/ivpu_hw_37xx.c | 13 +++++++++++++ drivers/accel/ivpu/ivpu_hw_40xx.c | 15 +++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 6e0d56823024..19035230563d 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -14,6 +14,7 @@ #include "ivpu_fw.h" #include "ivpu_fw_log.h" #include "ivpu_gem.h" +#include "ivpu_hw.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" @@ -176,6 +177,30 @@ static const struct file_operations fw_log_fops = { .release = single_release, }; +static ssize_t +fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, + size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + bool enable; + int ret; + + ret = kstrtobool_from_user(user_buf, size, &enable); + if (ret < 0) + return ret; + + ivpu_hw_profiling_freq_drive(vdev, enable); + ivpu_pm_schedule_recovery(vdev); + + return size; +} + +static const struct file_operations fw_profiling_freq_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = fw_profiling_freq_fops_write, +}; + static ssize_t fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) @@ -319,4 +344,8 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, &ivpu_reset_engine_fops); + + if (ivpu_hw_gen(vdev) >= IVPU_HW_40XX) + debugfs_create_file("fw_profiling_freq_drive", 0200, + debugfs_root, vdev, &fw_profiling_freq_fops); } diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 4a21be3a0c59..3fd74cd4205f 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -498,6 +498,13 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; boot_params->frequency = ivpu_hw_reg_pll_freq_get(vdev); + /* + * This param is a debug firmware feature. It switches default clock + * to higher resolution one for fine-grained and more accurate firmware + * task profiling. + */ + boot_params->perf_clk_frequency = ivpu_hw_profiling_freq_get(vdev); + /* * Uncached region of VPU address space, covers IPC buffers, job queues * and log buffers, programmable to L2$ Uncached by VPU MTRR diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index b7694b1cbc02..aa52e5c29a65 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -17,6 +17,8 @@ struct ivpu_hw_ops { int (*wait_for_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); + u32 (*profiling_freq_get)(struct ivpu_device *vdev); + void (*profiling_freq_drive)(struct ivpu_device *vdev, bool enable); u32 (*reg_pll_freq_get)(struct ivpu_device *vdev); u32 (*reg_telemetry_offset_get)(struct ivpu_device *vdev); u32 (*reg_telemetry_size_get)(struct ivpu_device *vdev); @@ -104,6 +106,16 @@ static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) vdev->hw->ops->wdt_disable(vdev); }; +static inline u32 ivpu_hw_profiling_freq_get(struct ivpu_device *vdev) +{ + return vdev->hw->ops->profiling_freq_get(vdev); +}; + +static inline void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + return vdev->hw->ops->profiling_freq_drive(vdev, enable); +}; + /* Register indirect accesses */ static inline u32 ivpu_hw_reg_pll_freq_get(struct ivpu_device *vdev) { diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 1c8c5715095b..81f81046d39a 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -29,6 +29,7 @@ #define PLL_REF_CLK_FREQ (50 * 1000000) #define PLL_SIMULATION_FREQ (10 * 1000000) +#define PLL_PROF_CLK_FREQ (38400 * 1000) #define PLL_DEFAULT_EPP_VALUE 0x80 #define TIM_SAFE_ENABLE 0xf1d0dead @@ -769,6 +770,16 @@ static void ivpu_hw_37xx_wdt_disable(struct ivpu_device *vdev) REGV_WR32(VPU_37XX_CPU_SS_TIM_GEN_CONFIG, val); } +static u32 ivpu_hw_37xx_profiling_freq_get(struct ivpu_device *vdev) +{ + return PLL_PROF_CLK_FREQ; +} + +static void ivpu_hw_37xx_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + /* Profiling freq - is a debug feature. Unavailable on VPU 37XX. */ +} + static u32 ivpu_hw_37xx_pll_to_freq(u32 ratio, u32 config) { u32 pll_clock = PLL_REF_CLK_FREQ * ratio; @@ -1012,6 +1023,8 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { .boot_fw = ivpu_hw_37xx_boot_fw, .wdt_disable = ivpu_hw_37xx_wdt_disable, .diagnose_failure = ivpu_hw_37xx_diagnose_failure, + .profiling_freq_get = ivpu_hw_37xx_profiling_freq_get, + .profiling_freq_drive = ivpu_hw_37xx_profiling_freq_drive, .reg_pll_freq_get = ivpu_hw_37xx_reg_pll_freq_get, .reg_telemetry_offset_get = ivpu_hw_37xx_reg_telemetry_offset_get, .reg_telemetry_size_get = ivpu_hw_37xx_reg_telemetry_size_get, diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 6a9672f650d1..a779b905f8b1 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -931,6 +931,19 @@ static void ivpu_hw_40xx_wdt_disable(struct ivpu_device *vdev) REGV_WR32(VPU_40XX_CPU_SS_TIM_GEN_CONFIG, val); } +static u32 ivpu_hw_40xx_profiling_freq_get(struct ivpu_device *vdev) +{ + return vdev->hw->pll.profiling_freq; +} + +static void ivpu_hw_40xx_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + if (enable) + vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_HIGH; + else + vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; +} + /* Register indirect accesses */ static u32 ivpu_hw_40xx_reg_pll_freq_get(struct ivpu_device *vdev) { @@ -1182,6 +1195,8 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = { .boot_fw = ivpu_hw_40xx_boot_fw, .wdt_disable = ivpu_hw_40xx_wdt_disable, .diagnose_failure = ivpu_hw_40xx_diagnose_failure, + .profiling_freq_get = ivpu_hw_40xx_profiling_freq_get, + .profiling_freq_drive = ivpu_hw_40xx_profiling_freq_drive, .reg_pll_freq_get = ivpu_hw_40xx_reg_pll_freq_get, .reg_telemetry_offset_get = ivpu_hw_40xx_reg_telemetry_offset_get, .reg_telemetry_size_get = ivpu_hw_40xx_reg_telemetry_size_get, From a06eb9be49a66e16e0c7819c630c1267c25b36dc Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 28 Oct 2023 17:59:30 +0200 Subject: [PATCH 0181/7721] accel/ivpu: Assure device is off if power up sequence fail We should not leave device half enabled if there is failure somewhere it power up sequence. Fix device init and resume paths. Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-3-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_pm.c | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 39bac45d88b5..064cabef41bb 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -543,7 +543,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev) /* Power up early so the rest of init code can access VPU registers */ ret = ivpu_hw_power_up(vdev); if (ret) - goto err_xa_destroy; + goto err_power_down; ret = ivpu_mmu_global_context_init(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 2d05fb9e3197..33d7c7731fe3 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -70,27 +70,31 @@ static int ivpu_resume(struct ivpu_device *vdev) ret = ivpu_hw_power_up(vdev); if (ret) { ivpu_err(vdev, "Failed to power up HW: %d\n", ret); - return ret; + goto err_power_down; } ret = ivpu_mmu_enable(vdev); if (ret) { ivpu_err(vdev, "Failed to resume MMU: %d\n", ret); - ivpu_hw_power_down(vdev); - return ret; + goto err_power_down; } ret = ivpu_boot(vdev); - if (ret) { - ivpu_mmu_disable(vdev); - ivpu_hw_power_down(vdev); - if (!ivpu_fw_is_cold_boot(vdev)) { - ivpu_warn(vdev, "Failed to resume the FW: %d. Retrying cold boot..\n", ret); - ivpu_pm_prepare_cold_boot(vdev); - goto retry; - } else { - ivpu_err(vdev, "Failed to resume the FW: %d\n", ret); - } + if (ret) + goto err_mmu_disable; + + return 0; + +err_mmu_disable: + ivpu_mmu_disable(vdev); +err_power_down: + ivpu_hw_power_down(vdev); + + if (!ivpu_fw_is_cold_boot(vdev)) { + ivpu_pm_prepare_cold_boot(vdev); + goto retry; + } else { + ivpu_err(vdev, "Failed to resume the FW: %d\n", ret); } return ret; From 57c7e3e4800ad65048a7044b03723cd85d9595af Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 28 Oct 2023 17:59:31 +0200 Subject: [PATCH 0182/7721] accel/ivpu: Stop job_done_thread on suspend Stop job_done thread when going to suspend. Use kthread_park() instead of kthread_stop() to avoid memory allocation and potential failure on resume. Use separate function as thread wake up condition. Use spin lock to assure rx_msg_list is properly protected against concurrent access. This avoid race condition when the rx_msg_list list is modified and read in ivpu_ipc_recive() at the same time. Reviewed-by: Karol Wachowski Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-4-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 2 ++ drivers/accel/ivpu/ivpu_ipc.c | 17 +++++++++++++++-- drivers/accel/ivpu/ivpu_job.c | 20 ++++++++++++++++---- drivers/accel/ivpu/ivpu_job.h | 2 ++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 064cabef41bb..60277ff6af69 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -378,6 +378,7 @@ int ivpu_boot(struct ivpu_device *vdev) enable_irq(vdev->irq); ivpu_hw_irq_enable(vdev); ivpu_ipc_enable(vdev); + ivpu_job_done_thread_enable(vdev); return 0; } @@ -389,6 +390,7 @@ int ivpu_shutdown(struct ivpu_device *vdev) disable_irq(vdev->irq); ivpu_ipc_disable(vdev); ivpu_mmu_disable(vdev); + ivpu_job_done_thread_disable(vdev); ret = ivpu_hw_power_down(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index d069d1e1f91d..270caef789bf 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -202,6 +202,20 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct v return ret; } +static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) +{ + int ret = 0; + + if (IS_KTHREAD()) + ret |= (kthread_should_stop() || kthread_should_park()); + + spin_lock_irq(&cons->rx_msg_lock); + ret |= !list_empty(&cons->rx_msg_list); + spin_unlock_irq(&cons->rx_msg_lock); + + return ret; +} + int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms) @@ -211,8 +225,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, int wait_ret, ret = 0; wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, - (IS_KTHREAD() && kthread_should_stop()) || - !list_empty(&cons->rx_msg_list), + ivpu_ipc_rx_need_wakeup(cons), msecs_to_jiffies(timeout_ms)); if (IS_KTHREAD() && kthread_should_stop()) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 6e96c921547d..a245b2d44db7 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -590,6 +590,11 @@ static int ivpu_job_done_thread(void *arg) ivpu_pm_schedule_recovery(vdev); } } + if (kthread_should_park()) { + ivpu_dbg(vdev, JOB, "Parked %s\n", __func__); + kthread_parkme(); + ivpu_dbg(vdev, JOB, "Unparked %s\n", __func__); + } } ivpu_ipc_consumer_del(vdev, &cons); @@ -610,9 +615,6 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) return -EIO; } - get_task_struct(thread); - wake_up_process(thread); - vdev->job_done_thread = thread; return 0; @@ -620,6 +622,16 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) void ivpu_job_done_thread_fini(struct ivpu_device *vdev) { + kthread_unpark(vdev->job_done_thread); kthread_stop(vdev->job_done_thread); - put_task_struct(vdev->job_done_thread); +} + +void ivpu_job_done_thread_disable(struct ivpu_device *vdev) +{ + kthread_park(vdev->job_done_thread); +} + +void ivpu_job_done_thread_enable(struct ivpu_device *vdev) +{ + kthread_unpark(vdev->job_done_thread); } diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index aa1f0b9479b0..a8e914e5affc 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -61,6 +61,8 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); int ivpu_job_done_thread_init(struct ivpu_device *vdev); void ivpu_job_done_thread_fini(struct ivpu_device *vdev); +void ivpu_job_done_thread_disable(struct ivpu_device *vdev); +void ivpu_job_done_thread_enable(struct ivpu_device *vdev); void ivpu_jobs_abort_all(struct ivpu_device *vdev); From ba6b035daac8c4fa5da1f14f262d97e0ffa45a6d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 28 Oct 2023 17:59:32 +0200 Subject: [PATCH 0183/7721] accel/ivpu: Abort pending rx ipc on reset Waking up process, which wait for particular condition, will go to sleep again on wake_up() if the condition is not met. Add abort flag to wake up IPC receivers, which will finish with -ECANCELED error. This is only needed for reset, run time power management prevent to suspend VPU when there is pending IPC processing or pending job. Reviewed-by: Karol Wachowski Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-5-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 20 +++++++++++++++++--- drivers/accel/ivpu/ivpu_ipc.h | 3 ++- drivers/accel/ivpu/ivpu_job.c | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 270caef789bf..255f2b8b0b5e 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -148,6 +148,7 @@ ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, cons->channel = channel; cons->tx_vpu_addr = 0; cons->request_id = 0; + cons->aborted = false; spin_lock_init(&cons->rx_msg_lock); INIT_LIST_HEAD(&cons->rx_msg_list); init_waitqueue_head(&cons->rx_msg_wq); @@ -169,7 +170,8 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c spin_lock_irq(&cons->rx_msg_lock); list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) { list_del(&rx_msg->link); - ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + if (!cons->aborted) + ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); } @@ -210,7 +212,7 @@ static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) ret |= (kthread_should_stop() || kthread_should_park()); spin_lock_irq(&cons->rx_msg_lock); - ret |= !list_empty(&cons->rx_msg_list); + ret |= !list_empty(&cons->rx_msg_list) || cons->aborted; spin_unlock_irq(&cons->rx_msg_lock); return ret; @@ -244,6 +246,12 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, return -EAGAIN; } list_del(&rx_msg->link); + if (cons->aborted) { + spin_unlock_irq(&cons->rx_msg_lock); + ret = -ECANCELED; + goto out; + } + spin_unlock_irq(&cons->rx_msg_lock); if (ipc_buf) @@ -261,6 +269,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, } ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); +out: atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); @@ -522,8 +531,12 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) mutex_unlock(&ipc->lock); spin_lock_irqsave(&ipc->cons_list_lock, flags); - list_for_each_entry_safe(cons, c, &ipc->cons_list, link) + list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { + spin_lock(&cons->rx_msg_lock); + cons->aborted = true; + spin_unlock(&cons->rx_msg_lock); wake_up(&cons->rx_msg_wq); + } spin_unlock_irqrestore(&ipc->cons_list_lock, flags); } @@ -532,6 +545,7 @@ void ivpu_ipc_reset(struct ivpu_device *vdev) struct ivpu_ipc_info *ipc = vdev->ipc; mutex_lock(&ipc->lock); + drm_WARN_ON(&vdev->drm, ipc->on); memset(ivpu_bo_vaddr(ipc->mem_tx), 0, ivpu_bo_size(ipc->mem_tx)); memset(ivpu_bo_vaddr(ipc->mem_rx), 0, ivpu_bo_size(ipc->mem_rx)); diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 6918db23daa4..a380787f7222 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -47,8 +47,9 @@ struct ivpu_ipc_consumer { u32 channel; u32 tx_vpu_addr; u32 request_id; + bool aborted; - spinlock_t rx_msg_lock; /* Protects rx_msg_list */ + spinlock_t rx_msg_lock; /* Protects rx_msg_list and aborted */ struct list_head rx_msg_list; wait_queue_head_t rx_msg_wq; }; diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index a245b2d44db7..15a408fad494 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -578,6 +578,7 @@ static int ivpu_job_done_thread(void *arg) ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET); while (!kthread_should_stop()) { + cons.aborted = false; timeout = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; jobs_submitted = !xa_empty(&vdev->submitted_jobs_xa); ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout); From e013aa9ab01b400cccc6c3e8b969b8e7f10bc6cb Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Sat, 28 Oct 2023 17:59:33 +0200 Subject: [PATCH 0184/7721] accel/ivpu: Print CMDQ errors after consumer timeout Add checking of error reason bits in IVPU_MMU_CMDQ_CONS register when waiting for consumer timeout occurred. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-6-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_mmu.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index 2538c78fbebe..b15cf9cc9c43 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -230,7 +230,12 @@ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_PRIQ_ABT)) | \ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_ABT))) -static char *ivpu_mmu_event_to_str(u32 cmd) +#define IVPU_MMU_CERROR_NONE 0x0 +#define IVPU_MMU_CERROR_ILL 0x1 +#define IVPU_MMU_CERROR_ABT 0x2 +#define IVPU_MMU_CERROR_ATC_INV_SYNC 0x3 + +static const char *ivpu_mmu_event_to_str(u32 cmd) { switch (cmd) { case IVPU_MMU_EVT_F_UUT: @@ -276,6 +281,22 @@ static char *ivpu_mmu_event_to_str(u32 cmd) } } +static const char *ivpu_mmu_cmdq_err_to_str(u32 err) +{ + switch (err) { + case IVPU_MMU_CERROR_NONE: + return "No CMDQ Error"; + case IVPU_MMU_CERROR_ILL: + return "Illegal command"; + case IVPU_MMU_CERROR_ABT: + return "External abort on CMDQ read"; + case IVPU_MMU_CERROR_ATC_INV_SYNC: + return "Sync failed to complete ATS invalidation"; + default: + return "Unknown CMDQ Error"; + } +} + static void ivpu_mmu_config_check(struct ivpu_device *vdev) { u32 val_ref; @@ -492,8 +513,15 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) REGV_WR32(IVPU_MMU_REG_CMDQ_PROD, q->prod); ret = ivpu_mmu_cmdq_wait_for_cons(vdev); - if (ret) - ivpu_err(vdev, "Timed out waiting for consumer: %d\n", ret); + if (ret) { + u32 err; + + val = REGV_RD32(IVPU_MMU_REG_CMDQ_CONS); + err = REG_GET_FLD(IVPU_MMU_REG_CMDQ_CONS, ERR, val); + + ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret, + ivpu_mmu_cmdq_err_to_str(err)); + } return ret; } From 3bcc5209ba6af1019487b54b30fc226ecf79193d Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Sat, 28 Oct 2023 17:59:34 +0200 Subject: [PATCH 0185/7721] accel/ivpu: Make DMA allocations for MMU600 write combined Previously using dma_alloc_wc() API we created cache coherent (mapped as write-back) mappings. Because we disable MMU600 snooping it was required to do costly page walk and cache flushes after each page table modification. With write-combined buffers it's possible to do a single write memory barrier to flush write-combined buffer to memory which simplifies the driver and significantly reduce time of map/unmap operations. Mapping time of 255 MB is reduced from 2.5 ms to 500 us. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-7-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_mmu_context.c | 115 ++++++++++++++------------ 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 0c8c65351919..7d8005bc78d2 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -5,6 +5,9 @@ #include #include +#include + +#include #include "ivpu_drv.h" #include "ivpu_hw.h" @@ -38,12 +41,57 @@ #define IVPU_MMU_ENTRY_MAPPED (IVPU_MMU_ENTRY_FLAG_AF | IVPU_MMU_ENTRY_FLAG_USER | \ IVPU_MMU_ENTRY_FLAG_NG | IVPU_MMU_ENTRY_VALID) +static void *ivpu_pgtable_alloc_page(struct ivpu_device *vdev, dma_addr_t *dma) +{ + dma_addr_t dma_addr; + struct page *page; + void *cpu; + + page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (!page) + return NULL; + + set_pages_array_wc(&page, 1); + + dma_addr = dma_map_page(vdev->drm.dev, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(vdev->drm.dev, dma_addr)) + goto err_free_page; + + cpu = vmap(&page, 1, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!cpu) + goto err_dma_unmap_page; + + + *dma = dma_addr; + return cpu; + +err_dma_unmap_page: + dma_unmap_page(vdev->drm.dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + +err_free_page: + put_page(page); + return NULL; +} + +static void ivpu_pgtable_free_page(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) +{ + struct page *page; + + if (cpu_addr) { + page = vmalloc_to_page(cpu_addr); + vunmap(cpu_addr); + dma_unmap_page(vdev->drm.dev, dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK, PAGE_SIZE, + DMA_BIDIRECTIONAL); + set_pages_array_wb(&page, 1); + put_page(page); + } +} + static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { dma_addr_t pgd_dma; - pgtable->pgd_dma_ptr = dma_alloc_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pgd_dma, - GFP_KERNEL); + pgtable->pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); if (!pgtable->pgd_dma_ptr) return -ENOMEM; @@ -52,13 +100,6 @@ static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtab return 0; } -static void ivpu_mmu_pgtable_free(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) -{ - if (cpu_addr) - dma_free_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, cpu_addr, - dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK); -} - static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { int pgd_idx, pud_idx, pmd_idx; @@ -83,19 +124,19 @@ static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgt pte_dma_ptr = pgtable->pte_ptrs[pgd_idx][pud_idx][pmd_idx]; pte_dma = pgtable->pmd_ptrs[pgd_idx][pud_idx][pmd_idx]; - ivpu_mmu_pgtable_free(vdev, pte_dma_ptr, pte_dma); + ivpu_pgtable_free_page(vdev, pte_dma_ptr, pte_dma); } kfree(pgtable->pte_ptrs[pgd_idx][pud_idx]); - ivpu_mmu_pgtable_free(vdev, pmd_dma_ptr, pmd_dma); + ivpu_pgtable_free_page(vdev, pmd_dma_ptr, pmd_dma); } kfree(pgtable->pmd_ptrs[pgd_idx]); kfree(pgtable->pte_ptrs[pgd_idx]); - ivpu_mmu_pgtable_free(vdev, pud_dma_ptr, pud_dma); + ivpu_pgtable_free_page(vdev, pud_dma_ptr, pud_dma); } - ivpu_mmu_pgtable_free(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); + ivpu_pgtable_free_page(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); } static u64* @@ -107,7 +148,7 @@ ivpu_mmu_ensure_pud(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pud_dma_ptr) return pud_dma_ptr; - pud_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pud_dma, GFP_KERNEL); + pud_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pud_dma); if (!pud_dma_ptr) return NULL; @@ -130,7 +171,7 @@ ivpu_mmu_ensure_pud(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, kfree(pgtable->pmd_ptrs[pgd_idx]); err_free_pud_dma_ptr: - ivpu_mmu_pgtable_free(vdev, pud_dma_ptr, pud_dma); + ivpu_pgtable_free_page(vdev, pud_dma_ptr, pud_dma); return NULL; } @@ -144,7 +185,7 @@ ivpu_mmu_ensure_pmd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pmd_dma_ptr) return pmd_dma_ptr; - pmd_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pmd_dma, GFP_KERNEL); + pmd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pmd_dma); if (!pmd_dma_ptr) return NULL; @@ -159,7 +200,7 @@ ivpu_mmu_ensure_pmd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, return pmd_dma_ptr; err_free_pmd_dma_ptr: - ivpu_mmu_pgtable_free(vdev, pmd_dma_ptr, pmd_dma); + ivpu_pgtable_free_page(vdev, pmd_dma_ptr, pmd_dma); return NULL; } @@ -173,7 +214,7 @@ ivpu_mmu_ensure_pte(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pte_dma_ptr) return pte_dma_ptr; - pte_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pte_dma, GFP_KERNEL); + pte_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pte_dma); if (!pte_dma_ptr) return NULL; @@ -248,38 +289,6 @@ static void ivpu_mmu_context_unmap_page(struct ivpu_mmu_context *ctx, u64 vpu_ad ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] = IVPU_MMU_ENTRY_INVALID; } -static void -ivpu_mmu_context_flush_page_tables(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size) -{ - struct ivpu_mmu_pgtable *pgtable = &ctx->pgtable; - u64 end_addr = vpu_addr + size; - - /* Align to PMD entry (2 MB) */ - vpu_addr &= ~(IVPU_MMU_PTE_MAP_SIZE - 1); - - while (vpu_addr < end_addr) { - int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr); - u64 pud_end = (pgd_idx + 1) * (u64)IVPU_MMU_PUD_MAP_SIZE; - - while (vpu_addr < end_addr && vpu_addr < pud_end) { - int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr); - u64 pmd_end = (pud_idx + 1) * (u64)IVPU_MMU_PMD_MAP_SIZE; - - while (vpu_addr < end_addr && vpu_addr < pmd_end) { - int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr); - - clflush_cache_range(pgtable->pte_ptrs[pgd_idx][pud_idx][pmd_idx], - IVPU_MMU_PGTABLE_SIZE); - vpu_addr += IVPU_MMU_PTE_MAP_SIZE; - } - clflush_cache_range(pgtable->pmd_ptrs[pgd_idx][pud_idx], - IVPU_MMU_PGTABLE_SIZE); - } - clflush_cache_range(pgtable->pud_ptrs[pgd_idx], IVPU_MMU_PGTABLE_SIZE); - } - clflush_cache_range(pgtable->pgd_dma_ptr, IVPU_MMU_PGTABLE_SIZE); -} - static int ivpu_mmu_context_map_pages(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr, dma_addr_t dma_addr, size_t size, u64 prot) @@ -352,10 +361,11 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, mutex_unlock(&ctx->lock); return ret; } - ivpu_mmu_context_flush_page_tables(ctx, vpu_addr, size); vpu_addr += size; } + /* Ensure page table modifications are flushed from wc buffers to memory */ + wmb(); mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); @@ -381,10 +391,11 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct size_t size = sg_dma_len(sg) + sg->offset; ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size); - ivpu_mmu_context_flush_page_tables(ctx, vpu_addr, size); vpu_addr += size; } + /* Ensure page table modifications are flushed from wc buffers to memory */ + wmb(); mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); From 0c287c27fbffa2737f155af73646a794e540e1d3 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Sat, 28 Oct 2023 17:59:35 +0200 Subject: [PATCH 0186/7721] accel/ivpu: Simplify MMU SYNC command CMD_SYNC does not need any args as we poll for completion anyway. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-8-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_mmu.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index b15cf9cc9c43..b46f3743c0e7 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -500,10 +500,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) u64 val; int ret; - val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_CS, 0x2) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSH, 0x3) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSI_ATTR, 0xf); + val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC); ret = ivpu_mmu_cmdq_cmd_write(vdev, "SYNC", val, 0); if (ret) From 2fc1a50fa4472301a3b262fcfc78744c841d5587 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Sat, 28 Oct 2023 17:59:36 +0200 Subject: [PATCH 0187/7721] accel/ivpu: Rename VPU to NPU in product strings VPU was rebranded as NPU (Neural Processing Unit) so user facing strings have to be updated but the code remains as is and the module is still called intel_vpu.ko. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231028155936.1183342-9-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/Kconfig | 9 +++++---- drivers/accel/ivpu/ivpu_drv.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 1a4c4ed9d113..82749e0da524 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_ACCEL_IVPU - tristate "Intel VPU for Meteor Lake and newer" + tristate "Intel NPU (Neural Processing Unit)" depends on DRM_ACCEL depends on X86_64 && !UML depends on PCI && PCI_MSI @@ -9,8 +9,9 @@ config DRM_ACCEL_IVPU select SHMEM select GENERIC_ALLOCATOR help - Choose this option if you have a system that has an 14th generation Intel CPU - or newer. VPU stands for Versatile Processing Unit and it's a CPU-integrated - inference accelerator for Computer Vision and Deep Learning applications. + Choose this option if you have a system with an 14th generation + Intel CPU (Meteor Lake) or newer. Intel NPU (formerly called Intel VPU) + is a CPU-integrated inference accelerator for Computer Vision + and Deep Learning applications. If "M" is selected, the module will be called intel_vpu. diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 1b482d1d66d9..79b193ffbc26 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -19,7 +19,7 @@ #include "ivpu_mmu_context.h" #define DRIVER_NAME "intel_vpu" -#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)" +#define DRIVER_DESC "Driver for Intel NPU (Neural Processing Unit)" #define DRIVER_DATE "20230117" #define PCI_DEVICE_ID_MTL 0x7d1d From 0da611a8702101814257a7c03f6caf0574c83b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 8 Sep 2023 10:27:23 +0200 Subject: [PATCH 0188/7721] dma-buf: add dma_fence_timestamp helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a fence signals there is a very small race window where the timestamp isn't updated yet. sync_file solves this by busy waiting for the timestamp to appear, but on other ocassions didn't handled this correctly. Provide a dma_fence_timestamp() helper function for this and use it in all appropriate cases. Another alternative would be to grab the spinlock when that happens. v2 by teddy: add a wait parameter to wait for the timestamp to show up, in case the accurate timestamp is needed and/or the timestamp is not based on ktime (e.g. hw timestamp) v3 chk: drop the parameter again for unified handling Signed-off-by: Yunxiang Li Signed-off-by: Christian König Fixes: 1774baa64f93 ("drm/scheduler: Change scheduled fence track v2") Reviewed-by: Alex Deucher CC: stable@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20230929104725.2358-1-christian.koenig@amd.com --- drivers/dma-buf/dma-fence-unwrap.c | 13 ++++--------- drivers/dma-buf/sync_file.c | 9 +++------ drivers/gpu/drm/scheduler/sched_main.c | 2 +- include/linux/dma-fence.h | 19 +++++++++++++++++++ 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index c625bb2b5d56..628af51c81af 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -76,16 +76,11 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) { if (!dma_fence_is_signaled(tmp)) { ++count; - } else if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, - &tmp->flags)) { - if (ktime_after(tmp->timestamp, timestamp)) - timestamp = tmp->timestamp; } else { - /* - * Use the current time if the fence is - * currently signaling. - */ - timestamp = ktime_get(); + ktime_t t = dma_fence_timestamp(tmp); + + if (ktime_after(t, timestamp)) + timestamp = t; } } } diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index af57799c86ce..2e9a316c596a 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -268,13 +268,10 @@ static int sync_fill_fence_info(struct dma_fence *fence, sizeof(info->driver_name)); info->status = dma_fence_get_status(fence); - while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && - !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) - cpu_relax(); info->timestamp_ns = - test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ? - ktime_to_ns(fence->timestamp) : - ktime_set(0, 0); + dma_fence_is_signaled(fence) ? + ktime_to_ns(dma_fence_timestamp(fence)) : + ktime_set(0, 0); return info->status; } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index fd755e953487..99797a8c836a 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -935,7 +935,7 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) if (next) { next->s_fence->scheduled.timestamp = - job->s_fence->finished.timestamp; + dma_fence_timestamp(&job->s_fence->finished); /* start TO timer for next job */ drm_sched_start_timeout(sched); } diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 0d678e9a7b24..ebe78bd3d121 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -568,6 +568,25 @@ static inline void dma_fence_set_error(struct dma_fence *fence, fence->error = error; } +/** + * dma_fence_timestamp - helper to get the completion timestamp of a fence + * @fence: fence to get the timestamp from. + * + * After a fence is signaled the timestamp is updated with the signaling time, + * but setting the timestamp can race with tasks waiting for the signaling. This + * helper busy waits for the correct timestamp to appear. + */ +static inline ktime_t dma_fence_timestamp(struct dma_fence *fence) +{ + if (WARN_ON(!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))) + return ktime_get(); + + while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) + cpu_relax(); + + return fence->timestamp; +} + signed long dma_fence_wait_timeout(struct dma_fence *, bool intr, signed long timeout); signed long dma_fence_wait_any_timeout(struct dma_fence **fences, From d1727cdd450d70cd747a466e96c63c26c78b6b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 18 Oct 2023 18:41:20 +0300 Subject: [PATCH 0189/7721] drm/i915/mst: Swap TRANSCONF vs. FECSTALL_DIS_DPTSTREAM_DPTTG disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP modeset sequence asks us to disable TRANSCONF before clearing the FECSTALL_DIS_DPTSTREAM_DPTTG bit, although we are still asked to wait for the transcoder to stop only after both steps have been done. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231018154123.5479-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1caf46e3e569..cdec0425f519 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -485,6 +485,8 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) if (!IS_I830(dev_priv)) val &= ~TRANSCONF_ENABLE; + intel_de_write(dev_priv, reg, val); + if (DISPLAY_VER(dev_priv) >= 14) intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), FECSTALL_DIS_DPTSTREAM_DPTTG, 0); @@ -492,7 +494,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), FECSTALL_DIS_DPTSTREAM_DPTTG, 0); - intel_de_write(dev_priv, reg, val); if ((val & TRANSCONF_ENABLE) == 0) intel_wait_for_pipe_off(old_crtc_state); } From d068fa53730b9eb79e532350cd90d50950ea79fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 18 Oct 2023 18:41:21 +0300 Subject: [PATCH 0190/7721] drm/i915/mst: Disable transcoder before deleting the payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bspec tells us that we should disable the transcoder before deleting the payload. Looks like this has been reversed since MST support was added. I suppose this shouldn't matter in practice since the downstream device shouldn't really do anything with the new payload until we send the ACT. But I see no compelling reason to deviate from the bspec sequence regardless. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231018154123.5479-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4366da79fe81..b90a4d7604bc 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -587,10 +587,6 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_dp_mst_topology_state *new_mst_state = - drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); - struct drm_dp_mst_atomic_payload *new_payload = - drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *i915 = to_i915(connector->base.dev); drm_dbg_kms(&i915->drm, "active links %d\n", @@ -598,8 +594,6 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); - drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } @@ -634,6 +628,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, intel_disable_transcoder(old_crtc_state); + drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); + clear_act_sent(encoder, old_crtc_state); intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder), From 817cb16e14de1fe29d4dfcd3cae8bce538f7d370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 18 Oct 2023 18:41:22 +0300 Subject: [PATCH 0191/7721] drm/i915/mst: Clear ACT just before triggering payload allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the bspec sequence more closely and clear ACT sent just before triggering the allocation. Can't see why we'd want to deviate from the spec sequence here. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231018154123.5479-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b90a4d7604bc..f379fcdebe9e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -791,8 +791,6 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder); - clear_act_sent(encoder, pipe_config); - if (intel_dp_is_uhbr(pipe_config)) { const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -806,6 +804,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_transcoder_func(encoder, pipe_config); + clear_act_sent(encoder, pipe_config); + intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(trans), 0, TRANS_DDI_DP_VC_PAYLOAD_ALLOC); From 08a573006d62221772bed4a079d05bb356331868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 18 Oct 2023 18:41:23 +0300 Subject: [PATCH 0192/7721] drm/i915/mst: Always write CHICKEN_TRANS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we're asked to disable FECSTALL_DIS_DPTSTREAM_DPTTG when the transcoder is disabled it seems prudent to also clear it when enabliing the transcoder w/o FEC, just in case someone else left it enabled by mistake. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231018154123.5479-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index f379fcdebe9e..82f425ef1595 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -817,12 +817,14 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, drm_atomic_get_mst_payload_state(mst_state, connector->port)); - if (DISPLAY_VER(dev_priv) >= 14 && pipe_config->fec_enable) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(trans), 0, - FECSTALL_DIS_DPTSTREAM_DPTTG); - else if (DISPLAY_VER(dev_priv) >= 12 && pipe_config->fec_enable) - intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), 0, - FECSTALL_DIS_DPTSTREAM_DPTTG); + if (DISPLAY_VER(dev_priv) >= 14) + intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(trans), + FECSTALL_DIS_DPTSTREAM_DPTTG, + pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); + else if (DISPLAY_VER(dev_priv) >= 12) + intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), + FECSTALL_DIS_DPTSTREAM_DPTTG, + pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); intel_audio_sdp_split_update(pipe_config); From 35963cf2cd25eeea8bdb4d02853dac1e66fb13a0 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 30 Oct 2023 20:24:35 -0700 Subject: [PATCH 0193/7721] drm/sched: Add drm_sched_wqueue_* helpers Add scheduler wqueue ready, stop, and start helpers to hide the implementation details of the scheduler from the drivers. v2: - s/sched_wqueue/sched_wqueue (Luben) - Remove the extra white line after the return-statement (Luben) - update drm_sched_wqueue_ready comment (Luben) Cc: Luben Tuikov Signed-off-by: Matthew Brost Reviewed-by: Luben Tuikov Link: https://lore.kernel.org/r/20231031032439.1558703-2-matthew.brost@intel.com Signed-off-by: Luben Tuikov --- .../drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 15 +++---- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 +++--- drivers/gpu/drm/msm/adreno/adreno_device.c | 6 ++- drivers/gpu/drm/scheduler/sched_main.c | 39 ++++++++++++++++++- include/drm/gpu_scheduler.h | 3 ++ 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 625db444df1c..10d56979fe3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -290,7 +290,7 @@ static int suspend_resume_compute_scheduler(struct amdgpu_device *adev, bool sus for (i = 0; i < adev->gfx.num_compute_rings; i++) { struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - if (!(ring && ring->sched.thread)) + if (!(ring && drm_sched_wqueue_ready(&ring->sched))) continue; /* stop secheduler and drain ring. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index a4faea4fa0b5..a4c0bb358db7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1659,9 +1659,9 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; - kthread_park(ring->sched.thread); + drm_sched_wqueue_stop(&ring->sched); } seq_puts(m, "run ib test:\n"); @@ -1675,9 +1675,9 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; - kthread_unpark(ring->sched.thread); + drm_sched_wqueue_start(&ring->sched); } up_write(&adev->reset_domain->sem); @@ -1897,7 +1897,8 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) ring = adev->rings[val]; - if (!ring || !ring->funcs->preempt_ib || !ring->sched.thread) + if (!ring || !ring->funcs->preempt_ib || + !drm_sched_wqueue_ready(&ring->sched)) return -EINVAL; /* the last preemption failed */ @@ -1915,7 +1916,7 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) goto pro_end; /* stop the scheduler */ - kthread_park(ring->sched.thread); + drm_sched_wqueue_stop(&ring->sched); /* preempt the IB */ r = amdgpu_ring_preempt_ib(ring); @@ -1949,7 +1950,7 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) failure: /* restart the scheduler */ - kthread_unpark(ring->sched.thread); + drm_sched_wqueue_start(&ring->sched); up_read(&adev->reset_domain->sem); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 19b539cab7fe..a7f7afcb2bf0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4601,7 +4601,7 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; spin_lock(&ring->sched.job_list_lock); @@ -4740,7 +4740,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; /* Clear job fence from fence drv to avoid force_completion @@ -5282,7 +5282,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_stop(&ring->sched, job ? &job->base : NULL); @@ -5357,7 +5357,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_start(&ring->sched, true); @@ -5683,7 +5683,7 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_stop(&ring->sched, NULL); @@ -5811,7 +5811,7 @@ void amdgpu_pci_resume(struct pci_dev *pdev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_start(&ring->sched, true); diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index fa527935ffd4..8fa9ce3746b6 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -809,7 +809,8 @@ static void suspend_scheduler(struct msm_gpu *gpu) */ for (i = 0; i < gpu->nr_rings; i++) { struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched; - kthread_park(sched->thread); + + drm_sched_wqueue_stop(sched); } } @@ -819,7 +820,8 @@ static void resume_scheduler(struct msm_gpu *gpu) for (i = 0; i < gpu->nr_rings; i++) { struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched; - kthread_unpark(sched->thread); + + drm_sched_wqueue_start(sched); } } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 99797a8c836a..54c1c5fe01ba 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -439,7 +439,7 @@ void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) { struct drm_sched_job *s_job, *tmp; - kthread_park(sched->thread); + drm_sched_wqueue_stop(sched); /* * Reinsert back the bad job here - now it's safe as @@ -552,7 +552,7 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) spin_unlock(&sched->job_list_lock); } - kthread_unpark(sched->thread); + drm_sched_wqueue_start(sched); } EXPORT_SYMBOL(drm_sched_start); @@ -1252,3 +1252,38 @@ void drm_sched_increase_karma(struct drm_sched_job *bad) } } EXPORT_SYMBOL(drm_sched_increase_karma); + +/** + * drm_sched_wqueue_ready - Is the scheduler ready for submission + * + * @sched: scheduler instance + * + * Returns true if submission is ready + */ +bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched) +{ + return !!sched->thread; +} +EXPORT_SYMBOL(drm_sched_wqueue_ready); + +/** + * drm_sched_wqueue_stop - stop scheduler submission + * + * @sched: scheduler instance + */ +void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched) +{ + kthread_park(sched->thread); +} +EXPORT_SYMBOL(drm_sched_wqueue_stop); + +/** + * drm_sched_wqueue_start - start scheduler submission + * + * @sched: scheduler instance + */ +void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched) +{ + kthread_unpark(sched->thread); +} +EXPORT_SYMBOL(drm_sched_wqueue_start); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 653e0eec9743..7e622c18d336 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -553,6 +553,9 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, void drm_sched_job_cleanup(struct drm_sched_job *job); void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched); +bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched); +void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched); +void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched); void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery); void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); From a6149f0393699308fb00149be913044977bceb56 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 30 Oct 2023 20:24:36 -0700 Subject: [PATCH 0194/7721] drm/sched: Convert drm scheduler to use a work queue rather than kthread In Xe, the new Intel GPU driver, a choice has made to have a 1 to 1 mapping between a drm_gpu_scheduler and drm_sched_entity. At first this seems a bit odd but let us explain the reasoning below. 1. In Xe the submission order from multiple drm_sched_entity is not guaranteed to be the same completion even if targeting the same hardware engine. This is because in Xe we have a firmware scheduler, the GuC, which allowed to reorder, timeslice, and preempt submissions. If a using shared drm_gpu_scheduler across multiple drm_sched_entity, the TDR falls apart as the TDR expects submission order == completion order. Using a dedicated drm_gpu_scheduler per drm_sched_entity solve this problem. 2. In Xe submissions are done via programming a ring buffer (circular buffer), a drm_gpu_scheduler provides a limit on number of jobs, if the limit of number jobs is set to RING_SIZE / MAX_SIZE_PER_JOB we get flow control on the ring for free. A problem with this design is currently a drm_gpu_scheduler uses a kthread for submission / job cleanup. This doesn't scale if a large number of drm_gpu_scheduler are used. To work around the scaling issue, use a worker rather than kthread for submission / job cleanup. v2: - (Rob Clark) Fix msm build - Pass in run work queue v3: - (Boris) don't have loop in worker v4: - (Tvrtko) break out submit ready, stop, start helpers into own patch v5: - (Boris) default to ordered work queue v6: - (Luben / checkpatch) fix alignment in msm_ringbuffer.c - (Luben) s/drm_sched_submit_queue/drm_sched_wqueue_enqueue - (Luben) Update comment for drm_sched_wqueue_enqueue - (Luben) Positive check for submit_wq in drm_sched_init - (Luben) s/alloc_submit_wq/own_submit_wq v7: - (Luben) s/drm_sched_wqueue_enqueue/drm_sched_run_job_queue v8: - (Luben) Adjust var names / comments Signed-off-by: Matthew Brost Reviewed-by: Luben Tuikov Link: https://lore.kernel.org/r/20231031032439.1558703-3-matthew.brost@intel.com Signed-off-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 2 +- drivers/gpu/drm/lima/lima_sched.c | 2 +- drivers/gpu/drm/msm/msm_ringbuffer.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.c | 2 +- drivers/gpu/drm/panfrost/panfrost_job.c | 2 +- drivers/gpu/drm/scheduler/sched_main.c | 133 +++++++++++---------- drivers/gpu/drm/v3d/v3d_sched.c | 10 +- include/drm/gpu_scheduler.h | 14 ++- 9 files changed, 87 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a7f7afcb2bf0..203dfcea82b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2279,7 +2279,7 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev) break; } - r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, + r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, ring->num_hw_submission, 0, timeout, adev->reset_domain->wq, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 9b79f218e21a..c4b04b0dee16 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -134,7 +134,7 @@ int etnaviv_sched_init(struct etnaviv_gpu *gpu) { int ret; - ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, + ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, msecs_to_jiffies(500), NULL, NULL, diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index 295f0353a02e..aa030e1f7cda 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -488,7 +488,7 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) INIT_WORK(&pipe->recover_work, lima_sched_recover_work); - return drm_sched_init(&pipe->base, &lima_sched_ops, + return drm_sched_init(&pipe->base, &lima_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, 1, lima_job_hang_limit, diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 95257ab0185d..4968568e3b54 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -94,7 +94,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, /* currently managing hangcheck ourselves: */ sched_timeout = MAX_SCHEDULE_TIMEOUT; - ret = drm_sched_init(&ring->sched, &msm_sched_ops, + ret = drm_sched_init(&ring->sched, &msm_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, num_hw_submissions, 0, sched_timeout, NULL, NULL, to_msm_bo(ring->bo)->name, gpu->dev->dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index e62b04109b2f..7e64b5ef90fb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -429,7 +429,7 @@ int nouveau_sched_init(struct nouveau_drm *drm) if (!drm->sched_wq) return -ENOMEM; - return drm_sched_init(sched, &nouveau_sched_ops, + return drm_sched_init(sched, &nouveau_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, NULL, NULL, "nouveau_sched", drm->dev->dev); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index ecd2e035147f..6d89e24322db 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -852,7 +852,7 @@ int panfrost_job_init(struct panfrost_device *pfdev) js->queue[j].fence_context = dma_fence_context_alloc(1); ret = drm_sched_init(&js->queue[j].sched, - &panfrost_sched_ops, + &panfrost_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, nentries, 0, msecs_to_jiffies(JOB_TIMEOUT_MS), diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 54c1c5fe01ba..d1ae05bded15 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -48,7 +48,6 @@ * through the jobs entity pointer. */ -#include #include #include #include @@ -256,6 +255,16 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) return rb ? rb_entry(rb, struct drm_sched_entity, rb_tree_node) : NULL; } +/** + * drm_sched_run_job_queue - enqueue run-job work + * @sched: scheduler instance + */ +static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) +{ + if (!READ_ONCE(sched->pause_submit)) + queue_work(sched->submit_wq, &sched->work_run_job); +} + /** * drm_sched_job_done - complete a job * @s_job: pointer to the job which is done @@ -275,7 +284,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result) dma_fence_get(&s_fence->finished); drm_sched_fence_finished(s_fence, result); dma_fence_put(&s_fence->finished); - wake_up_interruptible(&sched->wake_up_worker); + drm_sched_run_job_queue(sched); } /** @@ -874,7 +883,7 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched) { if (drm_sched_can_queue(sched)) - wake_up_interruptible(&sched->wake_up_worker); + drm_sched_run_job_queue(sched); } /** @@ -985,60 +994,41 @@ drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, EXPORT_SYMBOL(drm_sched_pick_best); /** - * drm_sched_blocked - check if the scheduler is blocked + * drm_sched_run_job_work - main scheduler thread * - * @sched: scheduler instance - * - * Returns true if blocked, otherwise false. + * @w: run job work */ -static bool drm_sched_blocked(struct drm_gpu_scheduler *sched) +static void drm_sched_run_job_work(struct work_struct *w) { - if (kthread_should_park()) { - kthread_parkme(); - return true; - } - - return false; -} - -/** - * drm_sched_main - main scheduler thread - * - * @param: scheduler instance - * - * Returns 0. - */ -static int drm_sched_main(void *param) -{ - struct drm_gpu_scheduler *sched = (struct drm_gpu_scheduler *)param; + struct drm_gpu_scheduler *sched = + container_of(w, struct drm_gpu_scheduler, work_run_job); + struct drm_sched_entity *entity; + struct drm_sched_job *cleanup_job; int r; - sched_set_fifo_low(current); + if (READ_ONCE(sched->pause_submit)) + return; - while (!kthread_should_stop()) { - struct drm_sched_entity *entity = NULL; + cleanup_job = drm_sched_get_cleanup_job(sched); + entity = drm_sched_select_entity(sched); + + if (!entity && !cleanup_job) + return; /* No more work */ + + if (cleanup_job) + sched->ops->free_job(cleanup_job); + + if (entity) { + struct dma_fence *fence; struct drm_sched_fence *s_fence; struct drm_sched_job *sched_job; - struct dma_fence *fence; - struct drm_sched_job *cleanup_job = NULL; - - wait_event_interruptible(sched->wake_up_worker, - (cleanup_job = drm_sched_get_cleanup_job(sched)) || - (!drm_sched_blocked(sched) && - (entity = drm_sched_select_entity(sched))) || - kthread_should_stop()); - - if (cleanup_job) - sched->ops->free_job(cleanup_job); - - if (!entity) - continue; sched_job = drm_sched_entity_pop_job(entity); - if (!sched_job) { complete_all(&entity->entity_idle); - continue; + if (!cleanup_job) + return; /* No more work */ + goto again; } s_fence = sched_job->s_fence; @@ -1069,7 +1059,9 @@ static int drm_sched_main(void *param) wake_up(&sched->job_scheduled); } - return 0; + +again: + drm_sched_run_job_queue(sched); } /** @@ -1077,6 +1069,8 @@ static int drm_sched_main(void *param) * * @sched: scheduler instance * @ops: backend operations for this scheduler + * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is + * allocated and used * @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT * @hw_submission: number of hw submissions that can be in flight * @hang_limit: number of times to allow a job to hang before dropping it @@ -1091,6 +1085,7 @@ static int drm_sched_main(void *param) */ int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, + struct workqueue_struct *submit_wq, u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev) @@ -1121,14 +1116,22 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, return 0; } + if (submit_wq) { + sched->submit_wq = submit_wq; + sched->own_submit_wq = false; + } else { + sched->submit_wq = alloc_ordered_workqueue(name, 0); + if (!sched->submit_wq) + return -ENOMEM; + + sched->own_submit_wq = true; + } + ret = -ENOMEM; sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq), GFP_KERNEL | __GFP_ZERO); - if (!sched->sched_rq) { - drm_err(sched, "%s: out of memory for sched_rq\n", __func__); - return -ENOMEM; - } + if (!sched->sched_rq) + goto Out_free; sched->num_rqs = num_rqs; - ret = -ENOMEM; for (i = DRM_SCHED_PRIORITY_MIN; i < sched->num_rqs; i++) { sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL); if (!sched->sched_rq[i]) @@ -1136,31 +1139,26 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, drm_sched_rq_init(sched, sched->sched_rq[i]); } - init_waitqueue_head(&sched->wake_up_worker); init_waitqueue_head(&sched->job_scheduled); INIT_LIST_HEAD(&sched->pending_list); spin_lock_init(&sched->job_list_lock); atomic_set(&sched->hw_rq_count, 0); INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout); + INIT_WORK(&sched->work_run_job, drm_sched_run_job_work); atomic_set(&sched->_score, 0); atomic64_set(&sched->job_id_count, 0); - - /* Each scheduler will run on a seperate kernel thread */ - sched->thread = kthread_run(drm_sched_main, sched, sched->name); - if (IS_ERR(sched->thread)) { - ret = PTR_ERR(sched->thread); - sched->thread = NULL; - DRM_DEV_ERROR(sched->dev, "Failed to create scheduler for %s.\n", name); - goto Out_unroll; - } + sched->pause_submit = false; sched->ready = true; return 0; Out_unroll: for (--i ; i >= DRM_SCHED_PRIORITY_MIN; i--) kfree(sched->sched_rq[i]); +Out_free: kfree(sched->sched_rq); sched->sched_rq = NULL; + if (sched->own_submit_wq) + destroy_workqueue(sched->submit_wq); drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__); return ret; } @@ -1178,8 +1176,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched) struct drm_sched_entity *s_entity; int i; - if (sched->thread) - kthread_stop(sched->thread); + drm_sched_wqueue_stop(sched); for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { struct drm_sched_rq *rq = sched->sched_rq[i]; @@ -1202,6 +1199,8 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched) /* Confirm no work left behind accessing device structures */ cancel_delayed_work_sync(&sched->work_tdr); + if (sched->own_submit_wq) + destroy_workqueue(sched->submit_wq); sched->ready = false; kfree(sched->sched_rq); sched->sched_rq = NULL; @@ -1262,7 +1261,7 @@ EXPORT_SYMBOL(drm_sched_increase_karma); */ bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched) { - return !!sched->thread; + return sched->ready; } EXPORT_SYMBOL(drm_sched_wqueue_ready); @@ -1273,7 +1272,8 @@ EXPORT_SYMBOL(drm_sched_wqueue_ready); */ void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched) { - kthread_park(sched->thread); + WRITE_ONCE(sched->pause_submit, true); + cancel_work_sync(&sched->work_run_job); } EXPORT_SYMBOL(drm_sched_wqueue_stop); @@ -1284,6 +1284,7 @@ EXPORT_SYMBOL(drm_sched_wqueue_stop); */ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched) { - kthread_unpark(sched->thread); + WRITE_ONCE(sched->pause_submit, false); + queue_work(sched->submit_wq, &sched->work_run_job); } EXPORT_SYMBOL(drm_sched_wqueue_start); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 038e1ae589c7..0b6696b0d882 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -388,7 +388,7 @@ v3d_sched_init(struct v3d_dev *v3d) int ret; ret = drm_sched_init(&v3d->queue[V3D_BIN].sched, - &v3d_bin_sched_ops, + &v3d_bin_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, hw_jobs_limit, job_hang_limit, msecs_to_jiffies(hang_limit_ms), NULL, @@ -397,7 +397,7 @@ v3d_sched_init(struct v3d_dev *v3d) return ret; ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched, - &v3d_render_sched_ops, + &v3d_render_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, hw_jobs_limit, job_hang_limit, msecs_to_jiffies(hang_limit_ms), NULL, @@ -406,7 +406,7 @@ v3d_sched_init(struct v3d_dev *v3d) goto fail; ret = drm_sched_init(&v3d->queue[V3D_TFU].sched, - &v3d_tfu_sched_ops, + &v3d_tfu_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, hw_jobs_limit, job_hang_limit, msecs_to_jiffies(hang_limit_ms), NULL, @@ -416,7 +416,7 @@ v3d_sched_init(struct v3d_dev *v3d) if (v3d_has_csd(v3d)) { ret = drm_sched_init(&v3d->queue[V3D_CSD].sched, - &v3d_csd_sched_ops, + &v3d_csd_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, hw_jobs_limit, job_hang_limit, msecs_to_jiffies(hang_limit_ms), NULL, @@ -425,7 +425,7 @@ v3d_sched_init(struct v3d_dev *v3d) goto fail; ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched, - &v3d_cache_clean_sched_ops, + &v3d_cache_clean_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, hw_jobs_limit, job_hang_limit, msecs_to_jiffies(hang_limit_ms), NULL, diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 7e622c18d336..4bf94aca2631 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -475,17 +475,16 @@ struct drm_sched_backend_ops { * @num_rqs: Number of run-queues. This is at most DRM_SCHED_PRIORITY_COUNT, * as there's usually one run-queue per priority, but could be less. * @sched_rq: An allocated array of run-queues of size @num_rqs; - * @wake_up_worker: the wait queue on which the scheduler sleeps until a job - * is ready to be scheduled. * @job_scheduled: once @drm_sched_entity_do_release is called the scheduler * waits on this wait queue until all the scheduled jobs are * finished. * @hw_rq_count: the number of jobs currently in the hardware queue. * @job_id_count: used to assign unique id to the each job. + * @submit_wq: workqueue used to queue @work_run_job * @timeout_wq: workqueue used to queue @work_tdr + * @work_run_job: work which calls run_job op of each scheduler. * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the * timeout interval is over. - * @thread: the kthread on which the scheduler which run. * @pending_list: the list of jobs which are currently in the job queue. * @job_list_lock: lock to protect the pending_list. * @hang_limit: once the hangs by a job crosses this limit then it is marked @@ -494,6 +493,8 @@ struct drm_sched_backend_ops { * @_score: score used when the driver doesn't provide one * @ready: marks if the underlying HW is ready to work * @free_guilty: A hit to time out handler to free the guilty job. + * @pause_submit: pause queuing of @work_run_job on @submit_wq + * @own_submit_wq: scheduler owns allocation of @submit_wq * @dev: system &struct device * * One scheduler is implemented for each hardware ring. @@ -505,13 +506,13 @@ struct drm_gpu_scheduler { const char *name; u32 num_rqs; struct drm_sched_rq **sched_rq; - wait_queue_head_t wake_up_worker; wait_queue_head_t job_scheduled; atomic_t hw_rq_count; atomic64_t job_id_count; + struct workqueue_struct *submit_wq; struct workqueue_struct *timeout_wq; + struct work_struct work_run_job; struct delayed_work work_tdr; - struct task_struct *thread; struct list_head pending_list; spinlock_t job_list_lock; int hang_limit; @@ -519,11 +520,14 @@ struct drm_gpu_scheduler { atomic_t _score; bool ready; bool free_guilty; + bool pause_submit; + bool own_submit_wq; struct device *dev; }; int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, + struct workqueue_struct *submit_wq, u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev); From f7fe64ad0f22ff034f8ebcfbd7299ee9cc9b57d7 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 30 Oct 2023 20:24:37 -0700 Subject: [PATCH 0195/7721] drm/sched: Split free_job into own work item Rather than call free_job and run_job in same work item have a dedicated work item for each. This aligns with the design and intended use of work queues. v2: - Test for DMA_FENCE_FLAG_TIMESTAMP_BIT before setting timestamp in free_job() work item (Danilo) v3: - Drop forward dec of drm_sched_select_entity (Boris) - Return in drm_sched_run_job_work if entity NULL (Boris) v4: - Replace dequeue with peek and invert logic (Luben) - Wrap to 100 lines (Luben) - Update comments for *_queue / *_queue_if_ready functions (Luben) v5: - Drop peek argument, blindly reinit idle (Luben) - s/drm_sched_free_job_queue_if_ready/drm_sched_free_job_queue_if_done (Luben) - Update work_run_job & work_free_job kernel doc (Luben) v6: - Do not move drm_sched_select_entity in file (Luben) Signed-off-by: Matthew Brost Link: https://lore.kernel.org/r/20231031032439.1558703-4-matthew.brost@intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 156 ++++++++++++++++--------- include/drm/gpu_scheduler.h | 4 +- 2 files changed, 106 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index d1ae05bded15..3b1b2f8eafe8 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -265,6 +265,32 @@ static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) queue_work(sched->submit_wq, &sched->work_run_job); } +/** + * drm_sched_free_job_queue - enqueue free-job work + * @sched: scheduler instance + */ +static void drm_sched_free_job_queue(struct drm_gpu_scheduler *sched) +{ + if (!READ_ONCE(sched->pause_submit)) + queue_work(sched->submit_wq, &sched->work_free_job); +} + +/** + * drm_sched_free_job_queue_if_done - enqueue free-job work if ready + * @sched: scheduler instance + */ +static void drm_sched_free_job_queue_if_done(struct drm_gpu_scheduler *sched) +{ + struct drm_sched_job *job; + + spin_lock(&sched->job_list_lock); + job = list_first_entry_or_null(&sched->pending_list, + struct drm_sched_job, list); + if (job && dma_fence_is_signaled(&job->s_fence->finished)) + drm_sched_free_job_queue(sched); + spin_unlock(&sched->job_list_lock); +} + /** * drm_sched_job_done - complete a job * @s_job: pointer to the job which is done @@ -284,7 +310,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result) dma_fence_get(&s_fence->finished); drm_sched_fence_finished(s_fence, result); dma_fence_put(&s_fence->finished); - drm_sched_run_job_queue(sched); + drm_sched_free_job_queue(sched); } /** @@ -943,8 +969,10 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) typeof(*next), list); if (next) { - next->s_fence->scheduled.timestamp = - dma_fence_timestamp(&job->s_fence->finished); + if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, + &next->s_fence->scheduled.flags)) + next->s_fence->scheduled.timestamp = + dma_fence_timestamp(&job->s_fence->finished); /* start TO timer for next job */ drm_sched_start_timeout(sched); } @@ -994,7 +1022,40 @@ drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, EXPORT_SYMBOL(drm_sched_pick_best); /** - * drm_sched_run_job_work - main scheduler thread + * drm_sched_run_job_queue_if_ready - enqueue run-job work if ready + * @sched: scheduler instance + */ +static void drm_sched_run_job_queue_if_ready(struct drm_gpu_scheduler *sched) +{ + if (drm_sched_select_entity(sched)) + drm_sched_run_job_queue(sched); +} + +/** + * drm_sched_free_job_work - worker to call free_job + * + * @w: free job work + */ +static void drm_sched_free_job_work(struct work_struct *w) +{ + struct drm_gpu_scheduler *sched = + container_of(w, struct drm_gpu_scheduler, work_free_job); + struct drm_sched_job *cleanup_job; + + if (READ_ONCE(sched->pause_submit)) + return; + + cleanup_job = drm_sched_get_cleanup_job(sched); + if (cleanup_job) { + sched->ops->free_job(cleanup_job); + + drm_sched_free_job_queue_if_done(sched); + drm_sched_run_job_queue_if_ready(sched); + } +} + +/** + * drm_sched_run_job_work - worker to call run_job * * @w: run job work */ @@ -1003,65 +1064,51 @@ static void drm_sched_run_job_work(struct work_struct *w) struct drm_gpu_scheduler *sched = container_of(w, struct drm_gpu_scheduler, work_run_job); struct drm_sched_entity *entity; - struct drm_sched_job *cleanup_job; + struct dma_fence *fence; + struct drm_sched_fence *s_fence; + struct drm_sched_job *sched_job; int r; if (READ_ONCE(sched->pause_submit)) return; - cleanup_job = drm_sched_get_cleanup_job(sched); entity = drm_sched_select_entity(sched); + if (!entity) + return; - if (!entity && !cleanup_job) - return; /* No more work */ - - if (cleanup_job) - sched->ops->free_job(cleanup_job); - - if (entity) { - struct dma_fence *fence; - struct drm_sched_fence *s_fence; - struct drm_sched_job *sched_job; - - sched_job = drm_sched_entity_pop_job(entity); - if (!sched_job) { - complete_all(&entity->entity_idle); - if (!cleanup_job) - return; /* No more work */ - goto again; - } - - s_fence = sched_job->s_fence; - - atomic_inc(&sched->hw_rq_count); - drm_sched_job_begin(sched_job); - - trace_drm_run_job(sched_job, entity); - fence = sched->ops->run_job(sched_job); + sched_job = drm_sched_entity_pop_job(entity); + if (!sched_job) { complete_all(&entity->entity_idle); - drm_sched_fence_scheduled(s_fence, fence); - - if (!IS_ERR_OR_NULL(fence)) { - /* Drop for original kref_init of the fence */ - dma_fence_put(fence); - - r = dma_fence_add_callback(fence, &sched_job->cb, - drm_sched_job_done_cb); - if (r == -ENOENT) - drm_sched_job_done(sched_job, fence->error); - else if (r) - DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", - r); - } else { - drm_sched_job_done(sched_job, IS_ERR(fence) ? - PTR_ERR(fence) : 0); - } - - wake_up(&sched->job_scheduled); + return; /* No more work */ } -again: - drm_sched_run_job_queue(sched); + s_fence = sched_job->s_fence; + + atomic_inc(&sched->hw_rq_count); + drm_sched_job_begin(sched_job); + + trace_drm_run_job(sched_job, entity); + fence = sched->ops->run_job(sched_job); + complete_all(&entity->entity_idle); + drm_sched_fence_scheduled(s_fence, fence); + + if (!IS_ERR_OR_NULL(fence)) { + /* Drop for original kref_init of the fence */ + dma_fence_put(fence); + + r = dma_fence_add_callback(fence, &sched_job->cb, + drm_sched_job_done_cb); + if (r == -ENOENT) + drm_sched_job_done(sched_job, fence->error); + else if (r) + DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r); + } else { + drm_sched_job_done(sched_job, IS_ERR(fence) ? + PTR_ERR(fence) : 0); + } + + wake_up(&sched->job_scheduled); + drm_sched_run_job_queue_if_ready(sched); } /** @@ -1145,6 +1192,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, atomic_set(&sched->hw_rq_count, 0); INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout); INIT_WORK(&sched->work_run_job, drm_sched_run_job_work); + INIT_WORK(&sched->work_free_job, drm_sched_free_job_work); atomic_set(&sched->_score, 0); atomic64_set(&sched->job_id_count, 0); sched->pause_submit = false; @@ -1274,6 +1322,7 @@ void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched) { WRITE_ONCE(sched->pause_submit, true); cancel_work_sync(&sched->work_run_job); + cancel_work_sync(&sched->work_free_job); } EXPORT_SYMBOL(drm_sched_wqueue_stop); @@ -1286,5 +1335,6 @@ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched) { WRITE_ONCE(sched->pause_submit, false); queue_work(sched->submit_wq, &sched->work_run_job); + queue_work(sched->submit_wq, &sched->work_free_job); } EXPORT_SYMBOL(drm_sched_wqueue_start); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 4bf94aca2631..6655aeeef9bb 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -480,9 +480,10 @@ struct drm_sched_backend_ops { * finished. * @hw_rq_count: the number of jobs currently in the hardware queue. * @job_id_count: used to assign unique id to the each job. - * @submit_wq: workqueue used to queue @work_run_job + * @submit_wq: workqueue used to queue @work_run_job and @work_free_job * @timeout_wq: workqueue used to queue @work_tdr * @work_run_job: work which calls run_job op of each scheduler. + * @work_free_job: work which calls free_job op of each scheduler. * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the * timeout interval is over. * @pending_list: the list of jobs which are currently in the job queue. @@ -512,6 +513,7 @@ struct drm_gpu_scheduler { struct workqueue_struct *submit_wq; struct workqueue_struct *timeout_wq; struct work_struct work_run_job; + struct work_struct work_free_job; struct delayed_work work_tdr; struct list_head pending_list; spinlock_t job_list_lock; From 7a36dcfa16a5a7a87f65e03e1a3eb2b5e2fca812 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 30 Oct 2023 20:24:38 -0700 Subject: [PATCH 0196/7721] drm/sched: Add drm_sched_start_timeout_unlocked helper Also add a lockdep assert to drm_sched_start_timeout. Signed-off-by: Matthew Brost Reviewed-by: Luben Tuikov Link: https://lore.kernel.org/r/20231031032439.1558703-5-matthew.brost@intel.com Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 3b1b2f8eafe8..fc387de5a0c7 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -334,11 +334,20 @@ static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb) */ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched) { + lockdep_assert_held(&sched->job_list_lock); + if (sched->timeout != MAX_SCHEDULE_TIMEOUT && !list_empty(&sched->pending_list)) queue_delayed_work(sched->timeout_wq, &sched->work_tdr, sched->timeout); } +static void drm_sched_start_timeout_unlocked(struct drm_gpu_scheduler *sched) +{ + spin_lock(&sched->job_list_lock); + drm_sched_start_timeout(sched); + spin_unlock(&sched->job_list_lock); +} + /** * drm_sched_fault - immediately start timeout handler * @@ -451,11 +460,8 @@ static void drm_sched_job_timedout(struct work_struct *work) spin_unlock(&sched->job_list_lock); } - if (status != DRM_GPU_SCHED_STAT_ENODEV) { - spin_lock(&sched->job_list_lock); - drm_sched_start_timeout(sched); - spin_unlock(&sched->job_list_lock); - } + if (status != DRM_GPU_SCHED_STAT_ENODEV) + drm_sched_start_timeout_unlocked(sched); } /** @@ -581,11 +587,8 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) drm_sched_job_done(s_job, -ECANCELED); } - if (full_recovery) { - spin_lock(&sched->job_list_lock); - drm_sched_start_timeout(sched); - spin_unlock(&sched->job_list_lock); - } + if (full_recovery) + drm_sched_start_timeout_unlocked(sched); drm_sched_wqueue_start(sched); } From 3c6c7ca4508b6cb1a033ac954c50a1b2c97af883 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 30 Oct 2023 20:24:39 -0700 Subject: [PATCH 0197/7721] drm/sched: Add a helper to queue TDR immediately Add a helper whereby a driver can invoke TDR immediately. v2: - Drop timeout args, rename function, use mod delayed work (Luben) v3: - s/XE/Xe (Luben) - present tense in commit message (Luben) - Adjust comment for drm_sched_tdr_queue_imm (Luben) v4: - Adjust commit message (Luben) Cc: Luben Tuikov Signed-off-by: Matthew Brost Reviewed-by: Luben Tuikov Link: https://lore.kernel.org/r/20231031032439.1558703-6-matthew.brost@intel.com Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 18 +++++++++++++++++- include/drm/gpu_scheduler.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index fc387de5a0c7..98b2ad54fc70 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -338,7 +338,7 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched) if (sched->timeout != MAX_SCHEDULE_TIMEOUT && !list_empty(&sched->pending_list)) - queue_delayed_work(sched->timeout_wq, &sched->work_tdr, sched->timeout); + mod_delayed_work(sched->timeout_wq, &sched->work_tdr, sched->timeout); } static void drm_sched_start_timeout_unlocked(struct drm_gpu_scheduler *sched) @@ -348,6 +348,22 @@ static void drm_sched_start_timeout_unlocked(struct drm_gpu_scheduler *sched) spin_unlock(&sched->job_list_lock); } +/** + * drm_sched_tdr_queue_imm: - immediately start job timeout handler + * + * @sched: scheduler for which the timeout handling should be started. + * + * Start timeout handling immediately for the named scheduler. + */ +void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched) +{ + spin_lock(&sched->job_list_lock); + sched->timeout = 0; + drm_sched_start_timeout(sched); + spin_unlock(&sched->job_list_lock); +} +EXPORT_SYMBOL(drm_sched_tdr_queue_imm); + /** * drm_sched_fault - immediately start timeout handler * diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 6655aeeef9bb..9daa78d2c04c 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -557,6 +557,7 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list); +void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched); void drm_sched_job_cleanup(struct drm_sched_job *job); void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched); bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched); From 43dea469e99b10ecc967a3576e50a5d416daf13c Mon Sep 17 00:00:00 2001 From: Dnyaneshwar Bhadane Date: Sat, 28 Oct 2023 01:20:52 +0530 Subject: [PATCH 0198/7721] drm/i915/mtl: Add Wa_14019821291 This workaround is primarily implemented by the BIOS. However if the BIOS applies the workaround it will reserve a small piece of our DSM (which should be at the top, right below the WOPCM); we just need to keep that region reserved so that nothing else attempts to re-use it. v2: Declare regs in intel_gt_regs.h (Matt Roper) v3: Shift WA implementation before calculation of *base (Matt Roper) v4: - Change condition gscpmi base to be fall in DSM range.(Matt Roper) Signed-off-by: Dnyaneshwar Bhadane Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231027195052.3676632-1-dnyaneshwar.bhadane@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_regs.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 1a766d8e7cce..8c88075eeab2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -386,6 +386,27 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); + /* Wa_14019821291 */ + if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) { + /* + * This workaround is primarily implemented by the BIOS. We + * just need to figure out whether the BIOS has applied the + * workaround (meaning the programmed address falls within + * the DSM) and, if so, reserve that part of the DSM to + * prevent accidental reuse. The DSM location should be just + * below the WOPCM. + */ + u64 gscpsmi_base = intel_uncore_read64_2x32(uncore, + MTL_GSCPSMI_BASEADDR_LSB, + MTL_GSCPSMI_BASEADDR_MSB); + if (gscpsmi_base >= i915->dsm.stolen.start && + gscpsmi_base < i915->dsm.stolen.end) { + *base = gscpsmi_base; + *size = i915->dsm.stolen.end - gscpsmi_base; + return; + } + } + switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { case GEN8_STOLEN_RESERVED_1M: *size = 1024 * 1024; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index eecd0a87a647..9de41703fae5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -537,6 +537,9 @@ #define XEHP_SQCM MCR_REG(0x8724) #define EN_32B_ACCESS REG_BIT(30) +#define MTL_GSCPSMI_BASEADDR_LSB _MMIO(0x880c) +#define MTL_GSCPSMI_BASEADDR_MSB _MMIO(0x8810) + #define HSW_IDICR _MMIO(0x9008) #define IDIHASHMSK(x) (((x) & 0x3f) << 16) From d59cf7bb73f3c702112a5a07824254345b7d089f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Tue, 31 Oct 2023 10:45:57 +0200 Subject: [PATCH 0199/7721] drm/i915/display: Use dma_fence interfaces instead of i915_sw_fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe driver. Xe driver doesn't have i915_sw_fence implementation. Lets drop i915_sw_fence usage from display code and use dma_fence interfaces directly. For this purpose stack dma fences from related objects into new plane state. Drm_gem_plane_helper_prepare_fb can be used for fences in new fb. Separate local implementation is used for Stacking fences from old fb into new plane state. Then wait for these stacked fences during atomic commit. There is no be need for separate GPU reset handling in intel_atomic_commit_fence_wait as the fences are signaled when GPU hang is detected and GPU is being reset. v4: - Drop to_new_plane_state suffix from add_dma_resv_fences - Use dma_resv_usage_rw(false) (DMA_RESV_USAGE_WRITE) v3: - Rename add_fences and it's parameters - Remove signaled check - Remove waiting old_plane_state fences v2: - Add fences from old fb into new_plane_state->uapi.fence rather than into old_plane_state->uapi.fence Cc: Ville Syrjälä Cc: Maarten Lankhorst Cc: José Roberto de Souza Signed-off-by: Jouni Högander Reviewed-by: Maarten Lankhorst Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231031084557.1181630-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_atomic.c | 3 - .../gpu/drm/i915/display/intel_atomic_plane.c | 83 +++++++++++-------- drivers/gpu/drm/i915/display/intel_display.c | 68 ++++----------- .../drm/i915/display/intel_display_types.h | 2 - 4 files changed, 61 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 5d18145da279..ec0d5168b503 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -331,9 +331,6 @@ void intel_atomic_state_free(struct drm_atomic_state *_state) drm_atomic_state_default_release(&state->base); kfree(state->global_objs); - - i915_sw_fence_fini(&state->commit_ready); - kfree(state); } diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index b1074350616c..3b9a66923422 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -31,7 +31,10 @@ * prepare/check/commit/cleanup steps. */ +#include + #include +#include #include #include @@ -1012,6 +1015,41 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } +static int add_dma_resv_fences(struct dma_resv *resv, + struct drm_plane_state *new_plane_state) +{ + struct dma_fence *fence = dma_fence_get(new_plane_state->fence); + struct dma_fence *new; + int ret; + + ret = dma_resv_get_singleton(resv, dma_resv_usage_rw(false), &new); + if (ret) + goto error; + + if (new && fence) { + struct dma_fence_chain *chain = dma_fence_chain_alloc(); + + if (!chain) { + ret = -ENOMEM; + goto error; + } + + dma_fence_chain_init(chain, fence, new, 1); + fence = &chain->base; + + } else if (new) { + fence = new; + } + + dma_fence_put(new_plane_state->fence); + new_plane_state->fence = fence; + return 0; + +error: + dma_fence_put(fence); + return ret; +} + /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @_plane: drm plane to prepare for @@ -1035,7 +1073,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, struct intel_atomic_state *state = to_intel_atomic_state(new_plane_state->uapi.state); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct intel_plane_state *old_plane_state = + struct intel_plane_state *old_plane_state = intel_atomic_get_old_plane_state(state, plane); struct drm_i915_gem_object *obj = intel_fb_obj(new_plane_state->hw.fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(old_plane_state->hw.fb); @@ -1058,55 +1096,28 @@ intel_prepare_plane_fb(struct drm_plane *_plane, * can safely continue. */ if (new_crtc_state && intel_crtc_needs_modeset(new_crtc_state)) { - ret = i915_sw_fence_await_reservation(&state->commit_ready, - old_obj->base.resv, - false, 0, - GFP_KERNEL); + ret = add_dma_resv_fences(old_obj->base.resv, + &new_plane_state->uapi); if (ret < 0) return ret; } } - if (new_plane_state->uapi.fence) { /* explicit fencing */ - i915_gem_fence_wait_priority(new_plane_state->uapi.fence, - &attr); - ret = i915_sw_fence_await_dma_fence(&state->commit_ready, - new_plane_state->uapi.fence, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - return ret; - } - if (!obj) return 0; - ret = intel_plane_pin_fb(new_plane_state); if (ret) return ret; - i915_gem_object_wait_priority(obj, 0, &attr); + ret = drm_gem_plane_helper_prepare_fb(&plane->base, &new_plane_state->uapi); + if (ret < 0) + goto unpin_fb; - if (!new_plane_state->uapi.fence) { /* implicit fencing */ - struct dma_resv_iter cursor; - struct dma_fence *fence; + if (new_plane_state->uapi.fence) { + i915_gem_fence_wait_priority(new_plane_state->uapi.fence, + &attr); - ret = i915_sw_fence_await_reservation(&state->commit_ready, - obj->base.resv, false, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - goto unpin_fb; - - dma_resv_iter_begin(&cursor, obj->base.resv, - DMA_RESV_USAGE_WRITE); - dma_resv_for_each_fence_unlocked(&cursor, fence) { - intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, - fence); - } - dma_resv_iter_end(&cursor); - } else { intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, new_plane_state->uapi.fence); } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index cdec0425f519..49ded4e32883 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -48,6 +48,7 @@ #include "g4x_dp.h" #include "g4x_hdmi.h" #include "hsw_ips.h" +#include "i915_config.h" #include "i915_drv.h" #include "i915_reg.h" #include "i915_utils.h" @@ -7057,29 +7058,22 @@ void intel_atomic_helper_free_state_worker(struct work_struct *work) static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state) { - struct wait_queue_entry wait_fence, wait_reset; - struct drm_i915_private *dev_priv = to_i915(intel_state->base.dev); + struct drm_i915_private *i915 = to_i915(intel_state->base.dev); + struct drm_plane *plane; + struct drm_plane_state *new_plane_state; + int ret, i; - init_wait_entry(&wait_fence, 0); - init_wait_entry(&wait_reset, 0); - for (;;) { - prepare_to_wait(&intel_state->commit_ready.wait, - &wait_fence, TASK_UNINTERRUPTIBLE); - prepare_to_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, - I915_RESET_MODESET), - &wait_reset, TASK_UNINTERRUPTIBLE); + for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) { + if (new_plane_state->fence) { + ret = dma_fence_wait_timeout(new_plane_state->fence, false, + i915_fence_timeout(i915)); + if (ret <= 0) + break; - - if (i915_sw_fence_done(&intel_state->commit_ready) || - test_bit(I915_RESET_MODESET, &to_gt(dev_priv)->reset.flags)) - break; - - schedule(); + dma_fence_put(new_plane_state->fence); + new_plane_state->fence = NULL; + } } - finish_wait(&intel_state->commit_ready.wait, &wait_fence); - finish_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, - I915_RESET_MODESET), - &wait_reset); } static void intel_atomic_cleanup_work(struct work_struct *work) @@ -7371,32 +7365,6 @@ static void intel_atomic_commit_work(struct work_struct *work) intel_atomic_commit_tail(state); } -static int -intel_atomic_commit_ready(struct i915_sw_fence *fence, - enum i915_sw_fence_notify notify) -{ - struct intel_atomic_state *state = - container_of(fence, struct intel_atomic_state, commit_ready); - - switch (notify) { - case FENCE_COMPLETE: - /* we do blocking waits in the worker, nothing to do here */ - break; - case FENCE_FREE: - { - struct drm_i915_private *i915 = to_i915(state->base.dev); - struct intel_atomic_helper *helper = - &i915->display.atomic_helper; - - if (llist_add(&state->freed, &helper->free_list)) - queue_work(i915->unordered_wq, &helper->free_work); - break; - } - } - - return NOTIFY_DONE; -} - static void intel_atomic_track_fbs(struct intel_atomic_state *state) { struct intel_plane_state *old_plane_state, *new_plane_state; @@ -7419,10 +7387,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, state->wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - drm_atomic_state_get(&state->base); - i915_sw_fence_init(&state->commit_ready, - intel_atomic_commit_ready); - /* * The intel_legacy_cursor_update() fast path takes care * of avoiding the vblank waits for simple cursor @@ -7455,7 +7419,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, if (ret) { drm_dbg_atomic(&dev_priv->drm, "Preparing state failed with %i\n", ret); - i915_sw_fence_commit(&state->commit_ready); intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); return ret; } @@ -7471,8 +7434,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, struct intel_crtc *crtc; int i; - i915_sw_fence_commit(&state->commit_ready); - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) intel_color_cleanup_commit(new_crtc_state); @@ -7486,7 +7447,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, drm_atomic_state_get(&state->base); INIT_WORK(&state->base.commit_work, intel_atomic_commit_work); - i915_sw_fence_commit(&state->commit_ready); if (nonblock && state->modeset) { queue_work(dev_priv->display.wq.modeset, &state->base.commit_work); } else if (nonblock) { diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 65ea37fe8cff..047fe3f8905a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -676,8 +676,6 @@ struct intel_atomic_state { bool rps_interactive; - struct i915_sw_fence commit_ready; - struct llist_node freed; }; From 8ddfc01ace51c85a2333fb9a9cbea34d9f87885d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 1 Nov 2023 18:20:16 +0100 Subject: [PATCH 0200/7721] fbdev/simplefb: Support memory-region property The simple-framebuffer bindings specify that the "memory-region" property can be used as an alternative to the "reg" property to define the framebuffer memory used by the display hardware. Implement support for this in the simplefb driver. Reviewed-by: Hans de Goede Signed-off-by: Thierry Reding Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231101172017.3872242-2-thierry.reding@gmail.com --- drivers/video/fbdev/simplefb.c | 35 +++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 62f99f6fccd3..18025f34fde7 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -121,12 +122,13 @@ struct simplefb_params { u32 height; u32 stride; struct simplefb_format *format; + struct resource memory; }; static int simplefb_parse_dt(struct platform_device *pdev, struct simplefb_params *params) { - struct device_node *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.of_node, *mem; int ret; const char *format; int i; @@ -166,6 +168,23 @@ static int simplefb_parse_dt(struct platform_device *pdev, return -EINVAL; } + mem = of_parse_phandle(np, "memory-region", 0); + if (mem) { + ret = of_address_to_resource(mem, 0, ¶ms->memory); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse memory-region\n"); + of_node_put(mem); + return ret; + } + + if (of_property_present(np, "reg")) + dev_warn(&pdev->dev, "preferring \"memory-region\" over \"reg\" property\n"); + + of_node_put(mem); + } else { + memset(¶ms->memory, 0, sizeof(params->memory)); + } + return 0; } @@ -193,6 +212,8 @@ static int simplefb_parse_pd(struct platform_device *pdev, return -EINVAL; } + memset(¶ms->memory, 0, sizeof(params->memory)); + return 0; } @@ -431,10 +452,14 @@ static int simplefb_probe(struct platform_device *pdev) if (ret) return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "No memory resource\n"); - return -EINVAL; + if (params.memory.start == 0 && params.memory.end == 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No memory resource\n"); + return -EINVAL; + } + } else { + res = ¶ms.memory; } mem = request_mem_region(res->start, resource_size(res), "simplefb"); From 92a511a568e44cf11681a2223cae4d576a1a515d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 1 Nov 2023 18:20:17 +0100 Subject: [PATCH 0201/7721] fbdev/simplefb: Add support for generic power-domains The simple-framebuffer device tree bindings document the power-domains property, so make sure that simplefb supports it. This ensures that the power domains remain enabled as long as simplefb is active. v2: - remove unnecessary call to simplefb_detach_genpds() since that's already done automatically by devres - fix crash if power-domains property is missing in DT Signed-off-by: Thierry Reding Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231101172017.3872242-3-thierry.reding@gmail.com --- drivers/video/fbdev/simplefb.c | 93 ++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 18025f34fde7..fe682af63827 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -25,6 +25,7 @@ #include #include #include +#include #include static const struct fb_fix_screeninfo simplefb_fix = { @@ -78,6 +79,11 @@ struct simplefb_par { unsigned int clk_count; struct clk **clks; #endif +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS + unsigned int num_genpds; + struct device **genpds; + struct device_link **genpd_links; +#endif #if defined CONFIG_OF && defined CONFIG_REGULATOR bool regulators_enabled; u32 regulator_count; @@ -432,6 +438,89 @@ static void simplefb_regulators_enable(struct simplefb_par *par, static void simplefb_regulators_destroy(struct simplefb_par *par) { } #endif +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS +static void simplefb_detach_genpds(void *res) +{ + struct simplefb_par *par = res; + unsigned int i = par->num_genpds; + + if (par->num_genpds <= 1) + return; + + while (i--) { + if (par->genpd_links[i]) + device_link_del(par->genpd_links[i]); + + if (!IS_ERR_OR_NULL(par->genpds[i])) + dev_pm_domain_detach(par->genpds[i], true); + } +} + +static int simplefb_attach_genpds(struct simplefb_par *par, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + unsigned int i; + int err; + + err = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (err < 0) { + dev_info(dev, "failed to parse power-domains: %d\n", err); + return err; + } + + par->num_genpds = err; + + /* + * Single power-domain devices are handled by the driver core, so + * nothing to do here. + */ + if (par->num_genpds <= 1) + return 0; + + par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds), + GFP_KERNEL); + if (!par->genpds) + return -ENOMEM; + + par->genpd_links = devm_kcalloc(dev, par->num_genpds, + sizeof(*par->genpd_links), + GFP_KERNEL); + if (!par->genpd_links) + return -ENOMEM; + + for (i = 0; i < par->num_genpds; i++) { + par->genpds[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(par->genpds[i])) { + err = PTR_ERR(par->genpds[i]); + if (err == -EPROBE_DEFER) { + simplefb_detach_genpds(par); + return err; + } + + dev_warn(dev, "failed to attach domain %u: %d\n", i, err); + continue; + } + + par->genpd_links[i] = device_link_add(dev, par->genpds[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!par->genpd_links[i]) + dev_warn(dev, "failed to link power-domain %u\n", i); + } + + return devm_add_action_or_reset(dev, simplefb_detach_genpds, par); +} +#else +static int simplefb_attach_genpds(struct simplefb_par *par, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int simplefb_probe(struct platform_device *pdev) { int ret; @@ -518,6 +607,10 @@ static int simplefb_probe(struct platform_device *pdev) if (ret < 0) goto error_clocks; + ret = simplefb_attach_genpds(par, pdev); + if (ret < 0) + goto error_regulators; + simplefb_clocks_enable(par, pdev); simplefb_regulators_enable(par, pdev); From 1118d10f5e5ab544c489fad4da373f9988416ece Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 31 Oct 2023 08:38:56 +0100 Subject: [PATCH 0202/7721] drm/v3d: update UAPI to match user-space for V3D 7.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V3D 7.x takes a new parameter to configure TFU jobs that needs to be provided by user space. Signed-off-by: Iago Toral Quiroga Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231031073859.25298-2-itoral@igalia.com --- include/uapi/drm/v3d_drm.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 3dfc0af8756a..1a7d7a689de3 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -319,6 +319,11 @@ struct drm_v3d_submit_tfu { /* Pointer to an array of ioctl extensions*/ __u64 extensions; + + struct { + __u32 ioc; + __u32 pad; + } v71; }; /* Submits a compute shader for dispatch. This job will block on any From 0ad5bc1ce4634ce9b5eaf017b01399ec5e49a03d Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 31 Oct 2023 08:38:57 +0100 Subject: [PATCH 0203/7721] drm/v3d: fix up register addresses for V3D 7.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch updates a number of register addresses that have been changed in Raspberry Pi 5 (V3D 7.1) and updates the code to use the corresponding registers and addresses based on the actual V3D version. Signed-off-by: Iago Toral Quiroga Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231031073859.25298-3-itoral@igalia.com --- drivers/gpu/drm/v3d/v3d_debugfs.c | 170 +++++++++++++++++------------- drivers/gpu/drm/v3d/v3d_gem.c | 4 +- drivers/gpu/drm/v3d/v3d_irq.c | 44 ++++---- drivers/gpu/drm/v3d/v3d_regs.h | 90 +++++++++------- drivers/gpu/drm/v3d/v3d_sched.c | 38 ++++--- 5 files changed, 197 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c index 330669f51fa7..f843a50d5dce 100644 --- a/drivers/gpu/drm/v3d/v3d_debugfs.c +++ b/drivers/gpu/drm/v3d/v3d_debugfs.c @@ -12,69 +12,83 @@ #include "v3d_drv.h" #include "v3d_regs.h" -#define REGDEF(reg) { reg, #reg } +#define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg } struct v3d_reg_def { + u32 min_ver; + u32 max_ver; u32 reg; const char *name; }; static const struct v3d_reg_def v3d_hub_reg_defs[] = { - REGDEF(V3D_HUB_AXICFG), - REGDEF(V3D_HUB_UIFCFG), - REGDEF(V3D_HUB_IDENT0), - REGDEF(V3D_HUB_IDENT1), - REGDEF(V3D_HUB_IDENT2), - REGDEF(V3D_HUB_IDENT3), - REGDEF(V3D_HUB_INT_STS), - REGDEF(V3D_HUB_INT_MSK_STS), + REGDEF(33, 42, V3D_HUB_AXICFG), + REGDEF(33, 71, V3D_HUB_UIFCFG), + REGDEF(33, 71, V3D_HUB_IDENT0), + REGDEF(33, 71, V3D_HUB_IDENT1), + REGDEF(33, 71, V3D_HUB_IDENT2), + REGDEF(33, 71, V3D_HUB_IDENT3), + REGDEF(33, 71, V3D_HUB_INT_STS), + REGDEF(33, 71, V3D_HUB_INT_MSK_STS), - REGDEF(V3D_MMU_CTL), - REGDEF(V3D_MMU_VIO_ADDR), - REGDEF(V3D_MMU_VIO_ID), - REGDEF(V3D_MMU_DEBUG_INFO), + REGDEF(33, 71, V3D_MMU_CTL), + REGDEF(33, 71, V3D_MMU_VIO_ADDR), + REGDEF(33, 71, V3D_MMU_VIO_ID), + REGDEF(33, 71, V3D_MMU_DEBUG_INFO), + + REGDEF(71, 71, V3D_GMP_STATUS(71)), + REGDEF(71, 71, V3D_GMP_CFG(71)), + REGDEF(71, 71, V3D_GMP_VIO_ADDR(71)), }; static const struct v3d_reg_def v3d_gca_reg_defs[] = { - REGDEF(V3D_GCA_SAFE_SHUTDOWN), - REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK), + REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN), + REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK), }; static const struct v3d_reg_def v3d_core_reg_defs[] = { - REGDEF(V3D_CTL_IDENT0), - REGDEF(V3D_CTL_IDENT1), - REGDEF(V3D_CTL_IDENT2), - REGDEF(V3D_CTL_MISCCFG), - REGDEF(V3D_CTL_INT_STS), - REGDEF(V3D_CTL_INT_MSK_STS), - REGDEF(V3D_CLE_CT0CS), - REGDEF(V3D_CLE_CT0CA), - REGDEF(V3D_CLE_CT0EA), - REGDEF(V3D_CLE_CT1CS), - REGDEF(V3D_CLE_CT1CA), - REGDEF(V3D_CLE_CT1EA), + REGDEF(33, 71, V3D_CTL_IDENT0), + REGDEF(33, 71, V3D_CTL_IDENT1), + REGDEF(33, 71, V3D_CTL_IDENT2), + REGDEF(33, 71, V3D_CTL_MISCCFG), + REGDEF(33, 71, V3D_CTL_INT_STS), + REGDEF(33, 71, V3D_CTL_INT_MSK_STS), + REGDEF(33, 71, V3D_CLE_CT0CS), + REGDEF(33, 71, V3D_CLE_CT0CA), + REGDEF(33, 71, V3D_CLE_CT0EA), + REGDEF(33, 71, V3D_CLE_CT1CS), + REGDEF(33, 71, V3D_CLE_CT1CA), + REGDEF(33, 71, V3D_CLE_CT1EA), - REGDEF(V3D_PTB_BPCA), - REGDEF(V3D_PTB_BPCS), + REGDEF(33, 71, V3D_PTB_BPCA), + REGDEF(33, 71, V3D_PTB_BPCS), - REGDEF(V3D_GMP_STATUS), - REGDEF(V3D_GMP_CFG), - REGDEF(V3D_GMP_VIO_ADDR), + REGDEF(33, 41, V3D_GMP_STATUS(33)), + REGDEF(33, 41, V3D_GMP_CFG(33)), + REGDEF(33, 41, V3D_GMP_VIO_ADDR(33)), - REGDEF(V3D_ERR_FDBGO), - REGDEF(V3D_ERR_FDBGB), - REGDEF(V3D_ERR_FDBGS), - REGDEF(V3D_ERR_STAT), + REGDEF(33, 71, V3D_ERR_FDBGO), + REGDEF(33, 71, V3D_ERR_FDBGB), + REGDEF(33, 71, V3D_ERR_FDBGS), + REGDEF(33, 71, V3D_ERR_STAT), }; static const struct v3d_reg_def v3d_csd_reg_defs[] = { - REGDEF(V3D_CSD_STATUS), - REGDEF(V3D_CSD_CURRENT_CFG0), - REGDEF(V3D_CSD_CURRENT_CFG1), - REGDEF(V3D_CSD_CURRENT_CFG2), - REGDEF(V3D_CSD_CURRENT_CFG3), - REGDEF(V3D_CSD_CURRENT_CFG4), - REGDEF(V3D_CSD_CURRENT_CFG5), - REGDEF(V3D_CSD_CURRENT_CFG6), + REGDEF(41, 71, V3D_CSD_STATUS), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG0(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG1(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG2(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG3(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG4(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG5(41)), + REGDEF(41, 41, V3D_CSD_CURRENT_CFG6(41)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG0(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG1(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG2(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG3(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG4(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG5(71)), + REGDEF(71, 71, V3D_CSD_CURRENT_CFG6(71)), + REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7), }; static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) @@ -85,38 +99,41 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) int i, core; for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) { - seq_printf(m, "%s (0x%04x): 0x%08x\n", - v3d_hub_reg_defs[i].name, v3d_hub_reg_defs[i].reg, - V3D_READ(v3d_hub_reg_defs[i].reg)); + const struct v3d_reg_def *def = &v3d_hub_reg_defs[i]; + + if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + def->name, def->reg, V3D_READ(def->reg)); + } } - if (v3d->ver < 41) { - for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { + for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { + const struct v3d_reg_def *def = &v3d_gca_reg_defs[i]; + + if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { seq_printf(m, "%s (0x%04x): 0x%08x\n", - v3d_gca_reg_defs[i].name, - v3d_gca_reg_defs[i].reg, - V3D_GCA_READ(v3d_gca_reg_defs[i].reg)); + def->name, def->reg, V3D_GCA_READ(def->reg)); } } for (core = 0; core < v3d->cores; core++) { for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) { - seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", - core, - v3d_core_reg_defs[i].name, - v3d_core_reg_defs[i].reg, - V3D_CORE_READ(core, - v3d_core_reg_defs[i].reg)); + const struct v3d_reg_def *def = &v3d_core_reg_defs[i]; + + if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", + core, def->name, def->reg, + V3D_CORE_READ(core, def->reg)); + } } - if (v3d_has_csd(v3d)) { - for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { + for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { + const struct v3d_reg_def *def = &v3d_csd_reg_defs[i]; + + if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", - core, - v3d_csd_reg_defs[i].name, - v3d_csd_reg_defs[i].reg, - V3D_CORE_READ(core, - v3d_csd_reg_defs[i].reg)); + core, def->name, def->reg, + V3D_CORE_READ(core, def->reg)); } } } @@ -147,8 +164,10 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU)); seq_printf(m, "TFU: %s\n", str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU)); - seq_printf(m, "TSY: %s\n", - str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); + if (v3d->ver <= 42) { + seq_printf(m, "TSY: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); + } seq_printf(m, "MSO: %s\n", str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO)); seq_printf(m, "L3C: %s (%dkb)\n", @@ -177,10 +196,14 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) seq_printf(m, " QPUs: %d\n", nslc * qups); seq_printf(m, " Semaphores: %d\n", V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM)); - seq_printf(m, " BCG int: %d\n", - (ident2 & V3D_IDENT2_BCG_INT) != 0); - seq_printf(m, " Override TMU: %d\n", - (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); + if (v3d->ver <= 42) { + seq_printf(m, " BCG int: %d\n", + (ident2 & V3D_IDENT2_BCG_INT) != 0); + } + if (v3d->ver < 40) { + seq_printf(m, " Override TMU: %d\n", + (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); + } } return 0; @@ -212,14 +235,15 @@ static int v3d_measure_clock(struct seq_file *m, void *unused) int measure_ms = 1000; if (v3d->ver >= 40) { + int cycle_count_reg = V3D_PCTR_CYCLE_COUNT(v3d->ver); V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, - V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT, + V3D_SET_FIELD(cycle_count_reg, V3D_PCTR_S0)); V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1); V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1); } else { V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0, - V3D_PCTR_CYCLE_COUNT); + V3D_PCTR_CYCLE_COUNT(v3d->ver)); V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1); V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN, V3D_V3_PCTR_0_EN_ENABLE | diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index afa7d170d1ff..5688d46d30e6 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -47,9 +47,9 @@ v3d_init_hw_state(struct v3d_dev *v3d) static void v3d_idle_axi(struct v3d_dev *v3d, int core) { - V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ); + V3D_CORE_WRITE(core, V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ); - if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS) & + if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) & (V3D_GMP_STATUS_RD_COUNT_MASK | V3D_GMP_STATUS_WR_COUNT_MASK | V3D_GMP_STATUS_CFG_BUSY)) == 0, 100)) { diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index e714d5318f30..9705e0cb576d 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -19,16 +19,17 @@ #include "v3d_regs.h" #include "v3d_trace.h" -#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ - V3D_INT_FLDONE | \ - V3D_INT_FRDONE | \ - V3D_INT_CSDDONE | \ - V3D_INT_GMPV)) +#define V3D_CORE_IRQS(ver) ((u32)(V3D_INT_OUTOMEM | \ + V3D_INT_FLDONE | \ + V3D_INT_FRDONE | \ + V3D_INT_CSDDONE(ver) | \ + (ver < 71 ? V3D_INT_GMPV : 0))) -#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ - V3D_HUB_INT_MMU_PTI | \ - V3D_HUB_INT_MMU_CAP | \ - V3D_HUB_INT_TFUC)) +#define V3D_HUB_IRQS(ver) ((u32)(V3D_HUB_INT_MMU_WRV | \ + V3D_HUB_INT_MMU_PTI | \ + V3D_HUB_INT_MMU_CAP | \ + V3D_HUB_INT_TFUC | \ + (ver >= 71 ? V3D_V7_HUB_INT_GMPV : 0))) static irqreturn_t v3d_hub_irq(int irq, void *arg); @@ -115,7 +116,7 @@ v3d_irq(int irq, void *arg) status = IRQ_HANDLED; } - if (intsts & V3D_INT_CSDDONE) { + if (intsts & V3D_INT_CSDDONE(v3d->ver)) { struct v3d_fence *fence = to_v3d_fence(v3d->csd_job->base.irq_fence); @@ -127,7 +128,7 @@ v3d_irq(int irq, void *arg) /* We shouldn't be triggering these if we have GMP in * always-allowed mode. */ - if (intsts & V3D_INT_GMPV) + if (v3d->ver < 71 && (intsts & V3D_INT_GMPV)) dev_err(v3d->drm.dev, "GMP violation\n"); /* V3D 4.2 wires the hub and core IRQs together, so if we & @@ -197,6 +198,11 @@ v3d_hub_irq(int irq, void *arg) status = IRQ_HANDLED; } + if (v3d->ver >= 71 && (intsts & V3D_V7_HUB_INT_GMPV)) { + dev_err(v3d->drm.dev, "GMP Violation\n"); + status = IRQ_HANDLED; + } + return status; } @@ -211,8 +217,8 @@ v3d_irq_init(struct v3d_dev *v3d) * for us. */ for (core = 0; core < v3d->cores; core++) - V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); - V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); + V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); + V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1); if (irq1 == -EPROBE_DEFER) @@ -256,12 +262,12 @@ v3d_irq_enable(struct v3d_dev *v3d) /* Enable our set of interrupts, masking out any others. */ for (core = 0; core < v3d->cores; core++) { - V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS); - V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS); + V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS(v3d->ver)); + V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS(v3d->ver)); } - V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS); - V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS); + V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS(v3d->ver)); + V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS(v3d->ver)); } void @@ -276,8 +282,8 @@ v3d_irq_disable(struct v3d_dev *v3d) /* Clear any pending interrupts we might have left. */ for (core = 0; core < v3d->cores; core++) - V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); - V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); + V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); + V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); cancel_work_sync(&v3d->overflow_mem_work); } diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h index 3663e0d6bf76..1b1a62ad9585 100644 --- a/drivers/gpu/drm/v3d/v3d_regs.h +++ b/drivers/gpu/drm/v3d/v3d_regs.h @@ -57,6 +57,7 @@ #define V3D_HUB_INT_MSK_STS 0x0005c #define V3D_HUB_INT_MSK_SET 0x00060 #define V3D_HUB_INT_MSK_CLR 0x00064 +# define V3D_V7_HUB_INT_GMPV BIT(6) # define V3D_HUB_INT_MMU_WRV BIT(5) # define V3D_HUB_INT_MMU_PTI BIT(4) # define V3D_HUB_INT_MMU_CAP BIT(3) @@ -64,6 +65,7 @@ # define V3D_HUB_INT_TFUC BIT(1) # define V3D_HUB_INT_TFUF BIT(0) +/* GCA registers only exist in V3D < 41 */ #define V3D_GCA_CACHE_CTRL 0x0000c # define V3D_GCA_CACHE_CTRL_FLUSH BIT(0) @@ -86,7 +88,8 @@ # define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0) -#define V3D_TFU_CS 0x00400 +#define V3D_TFU_CS(ver) ((ver >= 71) ? 0x00700 : 0x00400) + /* Stops current job, empties input fifo. */ # define V3D_TFU_CS_TFURST BIT(31) # define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16) @@ -95,7 +98,7 @@ # define V3D_TFU_CS_NFREE_SHIFT 8 # define V3D_TFU_CS_BUSY BIT(0) -#define V3D_TFU_SU 0x00404 +#define V3D_TFU_SU(ver) ((ver >= 71) ? 0x00704 : 0x00404) /* Interrupt when FINTTHR input slots are free (0 = disabled) */ # define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8) # define V3D_TFU_SU_FINTTHR_SHIFT 8 @@ -106,39 +109,42 @@ # define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0) # define V3D_TFU_SU_THROTTLE_SHIFT 0 -#define V3D_TFU_ICFG 0x00408 +#define V3D_TFU_ICFG(ver) ((ver >= 71) ? 0x00708 : 0x00408) /* Interrupt when the conversion is complete. */ # define V3D_TFU_ICFG_IOC BIT(0) /* Input Image Address */ -#define V3D_TFU_IIA 0x0040c +#define V3D_TFU_IIA(ver) ((ver >= 71) ? 0x0070c : 0x0040c) /* Input Chroma Address */ -#define V3D_TFU_ICA 0x00410 +#define V3D_TFU_ICA(ver) ((ver >= 71) ? 0x00710 : 0x00410) /* Input Image Stride */ -#define V3D_TFU_IIS 0x00414 +#define V3D_TFU_IIS(ver) ((ver >= 71) ? 0x00714 : 0x00414) /* Input Image U-Plane Address */ -#define V3D_TFU_IUA 0x00418 +#define V3D_TFU_IUA(ver) ((ver >= 71) ? 0x00718 : 0x00418) +/* Image output config (VD 7.x only) */ +#define V3D_V7_TFU_IOC 0x0071c /* Output Image Address */ -#define V3D_TFU_IOA 0x0041c +#define V3D_TFU_IOA(ver) ((ver >= 71) ? 0x00720 : 0x0041c) /* Image Output Size */ -#define V3D_TFU_IOS 0x00420 +#define V3D_TFU_IOS(ver) ((ver >= 71) ? 0x00724 : 0x00420) /* TFU YUV Coefficient 0 */ -#define V3D_TFU_COEF0 0x00424 -/* Use these regs instead of the defaults. */ +#define V3D_TFU_COEF0(ver) ((ver >= 71) ? 0x00728 : 0x00424) +/* Use these regs instead of the defaults (V3D 4.x only) */ # define V3D_TFU_COEF0_USECOEF BIT(31) /* TFU YUV Coefficient 1 */ -#define V3D_TFU_COEF1 0x00428 +#define V3D_TFU_COEF1(ver) ((ver >= 71) ? 0x0072c : 0x00428) /* TFU YUV Coefficient 2 */ -#define V3D_TFU_COEF2 0x0042c +#define V3D_TFU_COEF2(ver) ((ver >= 71) ? 0x00730 : 0x0042c) /* TFU YUV Coefficient 3 */ -#define V3D_TFU_COEF3 0x00430 +#define V3D_TFU_COEF3(ver) ((ver >= 71) ? 0x00734 : 0x00430) +/* V3D 4.x only */ #define V3D_TFU_CRC 0x00434 /* Per-MMU registers. */ #define V3D_MMUC_CONTROL 0x01000 -# define V3D_MMUC_CONTROL_CLEAR BIT(3) +#define V3D_MMUC_CONTROL_CLEAR(ver) ((ver >= 71) ? BIT(11) : BIT(3)) # define V3D_MMUC_CONTROL_FLUSHING BIT(2) # define V3D_MMUC_CONTROL_FLUSH BIT(1) # define V3D_MMUC_CONTROL_ENABLE BIT(0) @@ -246,7 +252,6 @@ #define V3D_CTL_L2TCACTL 0x00030 # define V3D_L2TCACTL_TMUWCF BIT(8) -# define V3D_L2TCACTL_L2T_NO_WM BIT(4) /* Invalidates cache lines. */ # define V3D_L2TCACTL_FLM_FLUSH 0 /* Removes cachelines without writing dirty lines back. */ @@ -267,8 +272,8 @@ #define V3D_CTL_INT_MSK_CLR 0x00064 # define V3D_INT_QPU_MASK V3D_MASK(27, 16) # define V3D_INT_QPU_SHIFT 16 -# define V3D_INT_CSDDONE BIT(7) -# define V3D_INT_PCTR BIT(6) +#define V3D_INT_CSDDONE(ver) ((ver >= 71) ? BIT(6) : BIT(7)) +#define V3D_INT_PCTR(ver) ((ver >= 71) ? BIT(5) : BIT(6)) # define V3D_INT_GMPV BIT(5) # define V3D_INT_TRFB BIT(4) # define V3D_INT_SPILLUSE BIT(3) @@ -350,21 +355,25 @@ #define V3D_V4_PCTR_0_SRC_X(x) (V3D_V4_PCTR_0_SRC_0_3 + \ 4 * (x)) # define V3D_PCTR_S0_MASK V3D_MASK(6, 0) +# define V3D_V7_PCTR_S0_MASK V3D_MASK(7, 0) # define V3D_PCTR_S0_SHIFT 0 # define V3D_PCTR_S1_MASK V3D_MASK(14, 8) +# define V3D_V7_PCTR_S1_MASK V3D_MASK(15, 8) # define V3D_PCTR_S1_SHIFT 8 # define V3D_PCTR_S2_MASK V3D_MASK(22, 16) +# define V3D_V7_PCTR_S2_MASK V3D_MASK(23, 16) # define V3D_PCTR_S2_SHIFT 16 # define V3D_PCTR_S3_MASK V3D_MASK(30, 24) +# define V3D_V7_PCTR_S3_MASK V3D_MASK(31, 24) # define V3D_PCTR_S3_SHIFT 24 -# define V3D_PCTR_CYCLE_COUNT 32 +#define V3D_PCTR_CYCLE_COUNT(ver) ((ver >= 71) ? 0 : 32) /* Output values of the counters. */ #define V3D_PCTR_0_PCTR0 0x00680 #define V3D_PCTR_0_PCTR31 0x006fc #define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \ 4 * (x)) -#define V3D_GMP_STATUS 0x00800 +#define V3D_GMP_STATUS(ver) ((ver >= 71) ? 0x00600 : 0x00800) # define V3D_GMP_STATUS_GMPRST BIT(31) # define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24) # define V3D_GMP_STATUS_WR_COUNT_SHIFT 24 @@ -377,13 +386,13 @@ # define V3D_GMP_STATUS_INVPROT BIT(1) # define V3D_GMP_STATUS_VIO BIT(0) -#define V3D_GMP_CFG 0x00804 +#define V3D_GMP_CFG(ver) ((ver >= 71) ? 0x00604 : 0x00804) # define V3D_GMP_CFG_LBURSTEN BIT(3) # define V3D_GMP_CFG_PGCRSEN BIT() # define V3D_GMP_CFG_STOP_REQ BIT(1) # define V3D_GMP_CFG_PROT_ENABLE BIT(0) -#define V3D_GMP_VIO_ADDR 0x00808 +#define V3D_GMP_VIO_ADDR(ver) ((ver >= 71) ? 0x00608 : 0x00808) #define V3D_GMP_VIO_TYPE 0x0080c #define V3D_GMP_TABLE_ADDR 0x00810 #define V3D_GMP_CLEAR_LOAD 0x00814 @@ -398,25 +407,25 @@ # define V3D_CSD_STATUS_HAVE_CURRENT_DISPATCH BIT(1) # define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0) -#define V3D_CSD_QUEUED_CFG0 0x00904 +#define V3D_CSD_QUEUED_CFG0(ver) ((ver >= 71) ? 0x00930 : 0x00904) # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16) # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16 # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0) # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0 -#define V3D_CSD_QUEUED_CFG1 0x00908 +#define V3D_CSD_QUEUED_CFG1(ver) ((ver >= 71) ? 0x00934 : 0x00908) # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16) # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16 # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0) # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0 -#define V3D_CSD_QUEUED_CFG2 0x0090c +#define V3D_CSD_QUEUED_CFG2(ver) ((ver >= 71) ? 0x00938 : 0x0090c) # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16) # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16 # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0) # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0 -#define V3D_CSD_QUEUED_CFG3 0x00910 +#define V3D_CSD_QUEUED_CFG3(ver) ((ver >= 71) ? 0x0093c : 0x00910) # define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26) # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20) # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20 @@ -428,23 +437,28 @@ # define V3D_CSD_QUEUED_CFG3_WG_SIZE_SHIFT 0 /* Number of batches, minus 1 */ -#define V3D_CSD_QUEUED_CFG4 0x00914 +#define V3D_CSD_QUEUED_CFG4(ver) ((ver >= 71) ? 0x00940 : 0x00914) /* Shader address, pnan, singleseg, threading, like a shader record. */ -#define V3D_CSD_QUEUED_CFG5 0x00918 +#define V3D_CSD_QUEUED_CFG5(ver) ((ver >= 71) ? 0x00944 : 0x00918) /* Uniforms address (4 byte aligned) */ -#define V3D_CSD_QUEUED_CFG6 0x0091c +#define V3D_CSD_QUEUED_CFG6(ver) ((ver >= 71) ? 0x00948 : 0x0091c) -#define V3D_CSD_CURRENT_CFG0 0x00920 -#define V3D_CSD_CURRENT_CFG1 0x00924 -#define V3D_CSD_CURRENT_CFG2 0x00928 -#define V3D_CSD_CURRENT_CFG3 0x0092c -#define V3D_CSD_CURRENT_CFG4 0x00930 -#define V3D_CSD_CURRENT_CFG5 0x00934 -#define V3D_CSD_CURRENT_CFG6 0x00938 +/* V3D 7.x+ only */ +#define V3D_V7_CSD_QUEUED_CFG7 0x0094c -#define V3D_CSD_CURRENT_ID0 0x0093c +#define V3D_CSD_CURRENT_CFG0(ver) ((ver >= 71) ? 0x00958 : 0x00920) +#define V3D_CSD_CURRENT_CFG1(ver) ((ver >= 71) ? 0x0095c : 0x00924) +#define V3D_CSD_CURRENT_CFG2(ver) ((ver >= 71) ? 0x00960 : 0x00928) +#define V3D_CSD_CURRENT_CFG3(ver) ((ver >= 71) ? 0x00964 : 0x0092c) +#define V3D_CSD_CURRENT_CFG4(ver) ((ver >= 71) ? 0x00968 : 0x00930) +#define V3D_CSD_CURRENT_CFG5(ver) ((ver >= 71) ? 0x0096c : 0x00934) +#define V3D_CSD_CURRENT_CFG6(ver) ((ver >= 71) ? 0x00970 : 0x00938) +/* V3D 7.x+ only */ +#define V3D_V7_CSD_CURRENT_CFG7 0x00974 + +#define V3D_CSD_CURRENT_ID0(ver) ((ver >= 71) ? 0x00978 : 0x0093c) # define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16) # define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16 # define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8) @@ -452,7 +466,7 @@ # define V3D_CSD_CURRENT_ID0_L_IDX_MASK V3D_MASK(7, 0) # define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0 -#define V3D_CSD_CURRENT_ID1 0x00940 +#define V3D_CSD_CURRENT_ID1(ver) ((ver >= 71) ? 0x0097c : 0x00940) # define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16) # define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16 # define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0) diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 0b6696b0d882..f59b63e51b14 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -190,20 +190,22 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); - V3D_WRITE(V3D_TFU_IIA, job->args.iia); - V3D_WRITE(V3D_TFU_IIS, job->args.iis); - V3D_WRITE(V3D_TFU_ICA, job->args.ica); - V3D_WRITE(V3D_TFU_IUA, job->args.iua); - V3D_WRITE(V3D_TFU_IOA, job->args.ioa); - V3D_WRITE(V3D_TFU_IOS, job->args.ios); - V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]); - if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) { - V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]); - V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]); - V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]); + V3D_WRITE(V3D_TFU_IIA(v3d->ver), job->args.iia); + V3D_WRITE(V3D_TFU_IIS(v3d->ver), job->args.iis); + V3D_WRITE(V3D_TFU_ICA(v3d->ver), job->args.ica); + V3D_WRITE(V3D_TFU_IUA(v3d->ver), job->args.iua); + V3D_WRITE(V3D_TFU_IOA(v3d->ver), job->args.ioa); + if (v3d->ver >= 71) + V3D_WRITE(V3D_V7_TFU_IOC, job->args.v71.ioc); + V3D_WRITE(V3D_TFU_IOS(v3d->ver), job->args.ios); + V3D_WRITE(V3D_TFU_COEF0(v3d->ver), job->args.coef[0]); + if (v3d->ver >= 71 || (job->args.coef[0] & V3D_TFU_COEF0_USECOEF)) { + V3D_WRITE(V3D_TFU_COEF1(v3d->ver), job->args.coef[1]); + V3D_WRITE(V3D_TFU_COEF2(v3d->ver), job->args.coef[2]); + V3D_WRITE(V3D_TFU_COEF3(v3d->ver), job->args.coef[3]); } /* ICFG kicks off the job. */ - V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC); + V3D_WRITE(V3D_TFU_ICFG(v3d->ver), job->args.icfg | V3D_TFU_ICFG_IOC); return fence; } @@ -215,7 +217,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) struct v3d_dev *v3d = job->base.v3d; struct drm_device *dev = &v3d->drm; struct dma_fence *fence; - int i; + int i, csd_cfg0_reg, csd_cfg_reg_count; v3d->csd_job = job; @@ -233,10 +235,12 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) v3d_switch_perfmon(v3d, &job->base); - for (i = 1; i <= 6; i++) - V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]); + csd_cfg0_reg = V3D_CSD_QUEUED_CFG0(v3d->ver); + csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7; + for (i = 1; i <= csd_cfg_reg_count; i++) + V3D_CORE_WRITE(0, csd_cfg0_reg + 4 * i, job->args.cfg[i]); /* CFG0 write kicks off the job. */ - V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]); + V3D_CORE_WRITE(0, csd_cfg0_reg, job->args.cfg[0]); return fence; } @@ -336,7 +340,7 @@ v3d_csd_job_timedout(struct drm_sched_job *sched_job) { struct v3d_csd_job *job = to_csd_job(sched_job); struct v3d_dev *v3d = job->base.v3d; - u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); + u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4(v3d->ver)); /* If we've made progress, skip reset and let the timer get * rearmed. From ebb2f6eea688b9ffa46527c3e7570b2c347497b8 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 31 Oct 2023 08:38:58 +0100 Subject: [PATCH 0204/7721] dt-bindings: gpu: v3d: Add BCM2712's compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM2712, Raspberry Pi 5's SoC, contains a V3D core. So add its specific compatible to the bindings. Signed-off-by: Iago Toral Quiroga Reviewed-by: Maíra Canal Acked-by: Conor Dooley Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231031073859.25298-4-itoral@igalia.com --- Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml index dae55b8a267b..dc078ceeca9a 100644 --- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - brcm,2711-v3d + - brcm,2712-v3d - brcm,7268-v3d - brcm,7278-v3d From 6fd9487147c4f18ad77eea00bd8c9189eec74a3e Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 31 Oct 2023 08:38:59 +0100 Subject: [PATCH 0205/7721] drm/v3d: add brcm,2712-v3d as a compatible V3D device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to get the V3D module to load with Raspberry Pi 5. Signed-off-by: Iago Toral Quiroga Reviewed-by: Stefan Wahren Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231031073859.25298-5-itoral@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index ffbbe9d527d3..1ab46bdf8ad7 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -187,6 +187,7 @@ static const struct drm_driver v3d_drm_driver = { static const struct of_device_id v3d_of_match[] = { { .compatible = "brcm,2711-v3d" }, + { .compatible = "brcm,2712-v3d" }, { .compatible = "brcm,7268-v3d" }, { .compatible = "brcm,7278-v3d" }, {}, From 2efb81e587961d5d863c2ad3156f96abde4d6a8f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 14:45:00 +0200 Subject: [PATCH 0206/7721] drm/i915: make some error capture functions static Not needed outside of i915_gpu_error.c. Signed-off-by: Jani Nikula Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231031124502.1772160-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_gpu_error.c | 8 ++++---- drivers/gpu/drm/i915/i915_gpu_error.h | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index b4e31e59c799..db7ac28c44e5 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -520,7 +520,7 @@ __find_vma(struct i915_vma_coredump *vma, const char *name) return NULL; } -struct i915_vma_coredump * +static struct i915_vma_coredump * intel_gpu_error_find_batch(const struct intel_engine_coredump *ee) { return __find_vma(ee->vma, "batch"); @@ -609,9 +609,9 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) va_end(args); } -void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, - const struct intel_engine_cs *engine, - const struct i915_vma_coredump *vma) +static void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, + const struct intel_engine_cs *engine, + const struct i915_vma_coredump *vma) { char out[ASCII85_BUFSZ]; struct page *page; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 9f5971f5e980..c982b162b7ff 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -275,11 +275,6 @@ static inline void intel_klog_error_capture(struct intel_gt *gt, __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); -void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, - const struct intel_engine_cs *engine, - const struct i915_vma_coredump *vma); -struct i915_vma_coredump * -intel_gpu_error_find_batch(const struct intel_engine_coredump *ee); struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags); From 4fca51984371d930a5d9d5a8b0848b892dbfdecc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 14:45:01 +0200 Subject: [PATCH 0207/7721] drm/i915: move gpu error debugfs to i915_gpu_error.c Hide gpu error specifics in i915_gpu_error.c. This is also cleaner wrt conditional compilation, as i915_gpu_error.c is only built with DRM_I915_CAPTURE_ERROR=y. Signed-off-by: Jani Nikula Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231031124502.1772160-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 108 +------------------------ drivers/gpu/drm/i915/i915_gpu_error.c | 111 +++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_gpu_error.h | 8 +- 3 files changed, 119 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e9b79c2c37d8..beffac46a5e2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -49,6 +49,7 @@ #include "i915_debugfs.h" #include "i915_debugfs_params.h" #include "i915_driver.h" +#include "i915_gpu_error.h" #include "i915_irq.h" #include "i915_reg.h" #include "i915_scheduler.h" @@ -297,107 +298,6 @@ static int i915_gem_object_info(struct seq_file *m, void *data) return 0; } -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) -static ssize_t gpu_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *pos) -{ - struct i915_gpu_coredump *error; - ssize_t ret; - void *buf; - - error = file->private_data; - if (!error) - return 0; - - /* Bounce buffer required because of kernfs __user API convenience. */ - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = i915_gpu_coredump_copy_to_buffer(error, buf, *pos, count); - if (ret <= 0) - goto out; - - if (!copy_to_user(ubuf, buf, ret)) - *pos += ret; - else - ret = -EFAULT; - -out: - kfree(buf); - return ret; -} - -static int gpu_state_release(struct inode *inode, struct file *file) -{ - i915_gpu_coredump_put(file->private_data); - return 0; -} - -static int i915_gpu_info_open(struct inode *inode, struct file *file) -{ - struct drm_i915_private *i915 = inode->i_private; - struct i915_gpu_coredump *gpu; - intel_wakeref_t wakeref; - - gpu = NULL; - with_intel_runtime_pm(&i915->runtime_pm, wakeref) - gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE); - - if (IS_ERR(gpu)) - return PTR_ERR(gpu); - - file->private_data = gpu; - return 0; -} - -static const struct file_operations i915_gpu_info_fops = { - .owner = THIS_MODULE, - .open = i915_gpu_info_open, - .read = gpu_state_read, - .llseek = default_llseek, - .release = gpu_state_release, -}; - -static ssize_t -i915_error_state_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) -{ - struct i915_gpu_coredump *error = filp->private_data; - - if (!error) - return 0; - - drm_dbg(&error->i915->drm, "Resetting error state\n"); - i915_reset_error_state(error->i915); - - return cnt; -} - -static int i915_error_state_open(struct inode *inode, struct file *file) -{ - struct i915_gpu_coredump *error; - - error = i915_first_error_state(inode->i_private); - if (IS_ERR(error)) - return PTR_ERR(error); - - file->private_data = error; - return 0; -} - -static const struct file_operations i915_error_state_fops = { - .owner = THIS_MODULE, - .open = i915_error_state_open, - .read = gpu_state_read, - .write = i915_error_state_write, - .llseek = default_llseek, - .release = gpu_state_release, -}; -#endif - static int i915_frequency_info(struct seq_file *m, void *unused) { struct drm_i915_private *i915 = node_to_i915(m->private); @@ -837,10 +737,6 @@ static const struct i915_debugfs_files { {"i915_perf_noa_delay", &i915_perf_noa_delay_fops}, {"i915_wedged", &i915_wedged_fops}, {"i915_gem_drop_caches", &i915_drop_caches_fops}, -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - {"i915_error_state", &i915_error_state_fops}, - {"i915_gpu_info", &i915_gpu_info_fops}, -#endif }; void i915_debugfs_register(struct drm_i915_private *dev_priv) @@ -863,4 +759,6 @@ void i915_debugfs_register(struct drm_i915_private *dev_priv) drm_debugfs_create_files(i915_debugfs_list, ARRAY_SIZE(i915_debugfs_list), minor->debugfs_root, minor); + + i915_gpu_error_debugfs_register(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index db7ac28c44e5..b4c8459deb7b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -2137,7 +2137,7 @@ __i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 du return error; } -struct i915_gpu_coredump * +static struct i915_gpu_coredump * i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags) { static DEFINE_MUTEX(capture_mutex); @@ -2375,3 +2375,112 @@ void intel_klog_error_capture(struct intel_gt *gt, drm_info(&i915->drm, "[Capture/%d.%d] Dumped %zd bytes\n", l_count, line++, pos_err); } #endif + +static ssize_t gpu_state_read(struct file *file, char __user *ubuf, + size_t count, loff_t *pos) +{ + struct i915_gpu_coredump *error; + ssize_t ret; + void *buf; + + error = file->private_data; + if (!error) + return 0; + + /* Bounce buffer required because of kernfs __user API convenience. */ + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = i915_gpu_coredump_copy_to_buffer(error, buf, *pos, count); + if (ret <= 0) + goto out; + + if (!copy_to_user(ubuf, buf, ret)) + *pos += ret; + else + ret = -EFAULT; + +out: + kfree(buf); + return ret; +} + +static int gpu_state_release(struct inode *inode, struct file *file) +{ + i915_gpu_coredump_put(file->private_data); + return 0; +} + +static int i915_gpu_info_open(struct inode *inode, struct file *file) +{ + struct drm_i915_private *i915 = inode->i_private; + struct i915_gpu_coredump *gpu; + intel_wakeref_t wakeref; + + gpu = NULL; + with_intel_runtime_pm(&i915->runtime_pm, wakeref) + gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE); + + if (IS_ERR(gpu)) + return PTR_ERR(gpu); + + file->private_data = gpu; + return 0; +} + +static const struct file_operations i915_gpu_info_fops = { + .owner = THIS_MODULE, + .open = i915_gpu_info_open, + .read = gpu_state_read, + .llseek = default_llseek, + .release = gpu_state_release, +}; + +static ssize_t +i915_error_state_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct i915_gpu_coredump *error = filp->private_data; + + if (!error) + return 0; + + drm_dbg(&error->i915->drm, "Resetting error state\n"); + i915_reset_error_state(error->i915); + + return cnt; +} + +static int i915_error_state_open(struct inode *inode, struct file *file) +{ + struct i915_gpu_coredump *error; + + error = i915_first_error_state(inode->i_private); + if (IS_ERR(error)) + return PTR_ERR(error); + + file->private_data = error; + return 0; +} + +static const struct file_operations i915_error_state_fops = { + .owner = THIS_MODULE, + .open = i915_error_state_open, + .read = gpu_state_read, + .write = i915_error_state_write, + .llseek = default_llseek, + .release = gpu_state_release, +}; + +void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_error_state", 0644, minor->debugfs_root, i915, + &i915_error_state_fops); + debugfs_create_file("i915_gpu_info", 0644, minor->debugfs_root, i915, + &i915_gpu_info_fops); +} diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index c982b162b7ff..a6f2a7518cf0 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -276,8 +276,6 @@ static inline void intel_klog_error_capture(struct intel_gt *gt, __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); -struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt, - intel_engine_mask_t engine_mask, u32 dump_flags); void i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags); @@ -329,6 +327,8 @@ struct i915_gpu_coredump *i915_first_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915); void i915_disable_error_state(struct drm_i915_private *i915, int err); +void i915_gpu_error_debugfs_register(struct drm_i915_private *i915); + #else __printf(2, 3) @@ -411,6 +411,10 @@ static inline void i915_disable_error_state(struct drm_i915_private *i915, { } +static inline void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) +{ +} + #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* _I915_GPU_ERROR_H_ */ From d581841076bc5de3c0ae72fd6bd50c59ce9f1638 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 14:45:02 +0200 Subject: [PATCH 0208/7721] drm/i915: move gpu error sysfs to i915_gpu_error.c Hide gpu error specifics in i915_gpu_error.c. This is also cleaner wrt conditional compilation, as i915_gpu_error.c is only built with DRM_I915_CAPTURE_ERROR=y. With this, we can also make i915_first_error_state() static. Signed-off-by: Jani Nikula Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231031124502.1772160-3-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_gpu_error.c | 75 ++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_gpu_error.h | 17 +++--- drivers/gpu/drm/i915/i915_sysfs.c | 79 +-------------------------- 3 files changed, 86 insertions(+), 85 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index b4c8459deb7b..f9e750217f18 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -57,6 +57,7 @@ #include "i915_memcpy.h" #include "i915_reg.h" #include "i915_scatterlist.h" +#include "i915_sysfs.h" #include "i915_utils.h" #define ALLOW_FAIL (__GFP_KSWAPD_RECLAIM | __GFP_RETRY_MAYFAIL | __GFP_NOWARN) @@ -2208,7 +2209,7 @@ void i915_capture_error_state(struct intel_gt *gt, i915_gpu_coredump_put(error); } -struct i915_gpu_coredump * +static struct i915_gpu_coredump * i915_first_error_state(struct drm_i915_private *i915) { struct i915_gpu_coredump *error; @@ -2484,3 +2485,75 @@ void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) debugfs_create_file("i915_gpu_info", 0644, minor->debugfs_root, i915, &i915_gpu_info_fops); } + +static ssize_t error_state_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + + struct device *kdev = kobj_to_dev(kobj); + struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); + struct i915_gpu_coredump *gpu; + ssize_t ret = 0; + + /* + * FIXME: Concurrent clients triggering resets and reading + clearing + * dumps can cause inconsistent sysfs reads when a user calls in with a + * non-zero offset to complete a prior partial read but the + * gpu_coredump has been cleared or replaced. + */ + + gpu = i915_first_error_state(i915); + if (IS_ERR(gpu)) { + ret = PTR_ERR(gpu); + } else if (gpu) { + ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count); + i915_gpu_coredump_put(gpu); + } else { + const char *str = "No error state collected\n"; + size_t len = strlen(str); + + if (off < len) { + ret = min_t(size_t, count, len - off); + memcpy(buf, str + off, ret); + } + } + + return ret; +} + +static ssize_t error_state_write(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *kdev = kobj_to_dev(kobj); + struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); + + drm_dbg(&dev_priv->drm, "Resetting error state\n"); + i915_reset_error_state(dev_priv); + + return count; +} + +static const struct bin_attribute error_state_attr = { + .attr.name = "error", + .attr.mode = S_IRUSR | S_IWUSR, + .size = 0, + .read = error_state_read, + .write = error_state_write, +}; + +void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) +{ + struct device *kdev = i915->drm.primary->kdev; + + if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr)) + drm_err(&i915->drm, "error_state sysfs setup failed\n"); +} + +void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915) +{ + struct device *kdev = i915->drm.primary->kdev; + + sysfs_remove_bin_file(&kdev->kobj, &error_state_attr); +} diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index a6f2a7518cf0..68c964d6720a 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -323,11 +323,12 @@ static inline void i915_gpu_coredump_put(struct i915_gpu_coredump *gpu) kref_put(&gpu->ref, __i915_gpu_coredump_free); } -struct i915_gpu_coredump *i915_first_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915); void i915_disable_error_state(struct drm_i915_private *i915, int err); void i915_gpu_error_debugfs_register(struct drm_i915_private *i915); +void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915); +void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915); #else @@ -396,12 +397,6 @@ static inline void i915_gpu_coredump_put(struct i915_gpu_coredump *gpu) { } -static inline struct i915_gpu_coredump * -i915_first_error_state(struct drm_i915_private *i915) -{ - return ERR_PTR(-ENODEV); -} - static inline void i915_reset_error_state(struct drm_i915_private *i915) { } @@ -415,6 +410,14 @@ static inline void i915_gpu_error_debugfs_register(struct drm_i915_private *i915 { } +static inline void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) +{ +} + +static inline void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915) +{ +} + #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* _I915_GPU_ERROR_H_ */ diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index e88bb4f04305..613decd47760 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -155,81 +155,6 @@ static const struct bin_attribute dpf_attrs_1 = { .private = (void *)1 }; -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - -static ssize_t error_state_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - - struct device *kdev = kobj_to_dev(kobj); - struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); - struct i915_gpu_coredump *gpu; - ssize_t ret = 0; - - /* - * FIXME: Concurrent clients triggering resets and reading + clearing - * dumps can cause inconsistent sysfs reads when a user calls in with a - * non-zero offset to complete a prior partial read but the - * gpu_coredump has been cleared or replaced. - */ - - gpu = i915_first_error_state(i915); - if (IS_ERR(gpu)) { - ret = PTR_ERR(gpu); - } else if (gpu) { - ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count); - i915_gpu_coredump_put(gpu); - } else { - const char *str = "No error state collected\n"; - size_t len = strlen(str); - - if (off < len) { - ret = min_t(size_t, count, len - off); - memcpy(buf, str + off, ret); - } - } - - return ret; -} - -static ssize_t error_state_write(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *kdev = kobj_to_dev(kobj); - struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); - - drm_dbg(&dev_priv->drm, "Resetting error state\n"); - i915_reset_error_state(dev_priv); - - return count; -} - -static const struct bin_attribute error_state_attr = { - .attr.name = "error", - .attr.mode = S_IRUSR | S_IWUSR, - .size = 0, - .read = error_state_read, - .write = error_state_write, -}; - -static void i915_setup_error_capture(struct device *kdev) -{ - if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr)) - drm_err(&kdev_minor_to_i915(kdev)->drm, - "error_state sysfs setup failed\n"); -} - -static void i915_teardown_error_capture(struct device *kdev) -{ - sysfs_remove_bin_file(&kdev->kobj, &error_state_attr); -} -#else -static void i915_setup_error_capture(struct device *kdev) {} -static void i915_teardown_error_capture(struct device *kdev) {} -#endif - void i915_setup_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; @@ -255,7 +180,7 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv) drm_warn(&dev_priv->drm, "failed to register GT sysfs directory\n"); - i915_setup_error_capture(kdev); + i915_gpu_error_sysfs_setup(dev_priv); intel_engines_add_sysfs(dev_priv); } @@ -264,7 +189,7 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; - i915_teardown_error_capture(kdev); + i915_gpu_error_sysfs_teardown(dev_priv); device_remove_bin_file(kdev, &dpf_attrs_1); device_remove_bin_file(kdev, &dpf_attrs); From 5fbae6874c92eec51cdcdcb68a4bafb535c066bf Mon Sep 17 00:00:00 2001 From: Dorcas AnonoLitunya Date: Fri, 27 Oct 2023 20:47:45 +0300 Subject: [PATCH 0209/7721] drm/i915/gt: Remove prohibited space after opening parenthesis Removes space after opening parenthesis. Fixes the checkpatch.pl error: ERROR: space prohibited after that opening parenthesis '(' Signed-off-by: Dorcas AnonoLitunya Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231027174745.4058-1-anonolitunya@gmail.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4a11219e560e..40687806d22a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -47,7 +47,7 @@ #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN11_LR_CONTEXT_RENDER_SIZE (14 * PAGE_SIZE) -#define GEN8_LR_CONTEXT_OTHER_SIZE ( 2 * PAGE_SIZE) +#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE) #define MAX_MMIO_BASES 3 struct engine_info { From 44793c6a5b784f1f25608e3773fd40e011c63391 Mon Sep 17 00:00:00 2001 From: Carl Vanderlip Date: Fri, 27 Oct 2023 12:08:10 -0600 Subject: [PATCH 0210/7721] accel/qaic: Quiet array bounds check on DMA abort message Current wrapper is right-sized to the message being transferred; however, this is smaller than the structure defining message wrappers since the trailing element is a union of message/transfer headers of various sizes (8 and 32 bytes on 32-bit system where issue was reported). Using the smaller header with a small message (wire_trans_dma_xfer is 24 bytes including header) ends up being smaller than a wrapper with the larger header. There are no accesses outside of the defined size, however they are possible if the larger union member is referenced. Abort messages are outside of hot-path and changing the wrapper struct would require a larger rewrite, so having the memory allocated to the message be 8 bytes too big is acceptable. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310182253.bcb9JcyJ-lkp@intel.com/ Signed-off-by: Carl Vanderlip Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231027180810.4873-1-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index 388abd40024b..84915824be54 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -1138,7 +1138,7 @@ static int abort_dma_cont(struct qaic_device *qdev, struct wrapper_list *wrapper if (!list_is_first(&wrapper->list, &wrappers->list)) kref_put(&wrapper->ref_count, free_wrapper); - wrapper = add_wrapper(wrappers, offsetof(struct wrapper_msg, trans) + sizeof(*out_trans)); + wrapper = add_wrapper(wrappers, sizeof(*wrapper)); if (!wrapper) return -ENOMEM; From 3b511278b6ef514b3ae3d99ff62947cddd434479 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 27 Oct 2023 10:43:30 -0600 Subject: [PATCH 0211/7721] accel/qaic: Support for 0 resize slice execution in BO Add support to partially execute a slice which is resized to zero. Executing a zero size slice in a BO should mean that there is no DMA transfers involved but you should still configure doorbell and semaphores. For example consider a BO of size 18K and it is sliced into 3 6K slices and user calls partial execute ioctl with resize as 10K. slice 0 - size is 6k and offset is 0, so resize of 10K will not cut short this slice hence we send the entire slice for execution. slice 1 - size is 6k and offset is 6k, so resize of 10K will cut short this slice and only the first 4k should be DMA along with configuring doorbell and semaphores. slice 2 - size is 6k and offset is 12k, so resize of 10k will cut short this slice and no DMA transfer would be involved but we should would configure doorbell and semaphores. This change begs to change the behavior of 0 resize. Currently, 0 resize partial execute ioctl behaves exactly like execute ioctl i.e. no resize. After this patch all the slice in BO should behave exactly like slice 2 in above example. Refactor copy_partial_exec_reqs() to make it more readable and less complex. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20231027164330.11978-1-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 104 ++++++++++++++------------------- include/uapi/drm/qaic_accel.h | 5 +- 2 files changed, 46 insertions(+), 63 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index ebc3cca1b094..8da81768f2ab 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -51,6 +51,7 @@ }) #define NUM_EVENTS 128 #define NUM_DELAYS 10 +#define fifo_at(base, offset) ((base) + (offset) * get_dbc_req_elem_size()) static unsigned int wait_exec_default_timeout_ms = 5000; /* 5 sec default */ module_param(wait_exec_default_timeout_ms, uint, 0600); @@ -1058,6 +1059,16 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi return ret; } +static inline u32 fifo_space_avail(u32 head, u32 tail, u32 q_size) +{ + u32 avail = head - tail - 1; + + if (head <= tail) + avail += q_size; + + return avail; +} + static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slice, u32 dbc_id, u32 head, u32 *ptail) { @@ -1066,27 +1077,20 @@ static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slic u32 tail = *ptail; u32 avail; - avail = head - tail; - if (head <= tail) - avail += dbc->nelem; - - --avail; - + avail = fifo_space_avail(head, tail, dbc->nelem); if (avail < slice->nents) return -EAGAIN; if (tail + slice->nents > dbc->nelem) { avail = dbc->nelem - tail; avail = min_t(u32, avail, slice->nents); - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * avail); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * avail); reqs += avail; avail = slice->nents - avail; if (avail) memcpy(dbc->req_q_base, reqs, sizeof(*reqs) * avail); } else { - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * slice->nents); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * slice->nents); } *ptail = (tail + slice->nents) % dbc->nelem; @@ -1094,46 +1098,31 @@ static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slic return 0; } -/* - * Based on the value of resize we may only need to transmit first_n - * entries and the last entry, with last_bytes to send from the last entry. - * Note that first_n could be 0. - */ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_slice *slice, - u64 resize, u32 dbc_id, u32 head, u32 *ptail) + u64 resize, struct dma_bridge_chan *dbc, u32 head, + u32 *ptail) { - struct dma_bridge_chan *dbc = &qdev->dbc[dbc_id]; struct dbc_req *reqs = slice->reqs; struct dbc_req *last_req; u32 tail = *ptail; - u64 total_bytes; u64 last_bytes; u32 first_n; u32 avail; - int ret; - int i; - avail = head - tail; - if (head <= tail) - avail += dbc->nelem; + avail = fifo_space_avail(head, tail, dbc->nelem); - --avail; - - total_bytes = 0; - for (i = 0; i < slice->nents; i++) { - total_bytes += le32_to_cpu(reqs[i].len); - if (total_bytes >= resize) + /* + * After this for loop is complete, first_n represents the index + * of the last DMA request of this slice that needs to be + * transferred after resizing and last_bytes represents DMA size + * of that request. + */ + last_bytes = resize; + for (first_n = 0; first_n < slice->nents; first_n++) + if (last_bytes > le32_to_cpu(reqs[first_n].len)) + last_bytes -= le32_to_cpu(reqs[first_n].len); + else break; - } - - if (total_bytes < resize) { - /* User space should have used the full buffer path. */ - ret = -EINVAL; - return ret; - } - - first_n = i; - last_bytes = i ? resize + le32_to_cpu(reqs[i].len) - total_bytes : resize; if (avail < (first_n + 1)) return -EAGAIN; @@ -1142,22 +1131,21 @@ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_sli if (tail + first_n > dbc->nelem) { avail = dbc->nelem - tail; avail = min_t(u32, avail, first_n); - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * avail); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * avail); last_req = reqs + avail; avail = first_n - avail; if (avail) memcpy(dbc->req_q_base, last_req, sizeof(*reqs) * avail); } else { - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * first_n); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * first_n); } } - /* Copy over the last entry. Here we need to adjust len to the left over + /* + * Copy over the last entry. Here we need to adjust len to the left over * size, and set src and dst to the entry it is copied to. */ - last_req = dbc->req_q_base + (tail + first_n) % dbc->nelem * get_dbc_req_elem_size(); + last_req = fifo_at(dbc->req_q_base, (tail + first_n) % dbc->nelem); memcpy(last_req, reqs + slice->nents - 1, sizeof(*reqs)); /* @@ -1168,6 +1156,9 @@ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_sli last_req->len = cpu_to_le32((u32)last_bytes); last_req->src_addr = reqs[first_n].src_addr; last_req->dest_addr = reqs[first_n].dest_addr; + if (!last_bytes) + /* Disable DMA transfer */ + last_req->cmd = GENMASK(7, 2) & reqs[first_n].cmd; *ptail = (tail + first_n + 1) % dbc->nelem; @@ -1227,26 +1218,17 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil bo->req_id = dbc->next_req_id++; list_for_each_entry(slice, &bo->slices, slice) { - /* - * If this slice does not fall under the given - * resize then skip this slice and continue the loop - */ - if (is_partial && pexec[i].resize && pexec[i].resize <= slice->offset) - continue; - for (j = 0; j < slice->nents; j++) slice->reqs[j].req_id = cpu_to_le16(bo->req_id); - /* - * If it is a partial execute ioctl call then check if - * resize has cut this slice short then do a partial copy - * else do complete copy - */ - if (is_partial && pexec[i].resize && - pexec[i].resize < slice->offset + slice->size) + if (is_partial && (!pexec[i].resize || pexec[i].resize <= slice->offset)) + /* Configure the slice for no DMA transfer */ + ret = copy_partial_exec_reqs(qdev, slice, 0, dbc, head, tail); + else if (is_partial && pexec[i].resize < slice->offset + slice->size) + /* Configure the slice to be partially DMA transferred */ ret = copy_partial_exec_reqs(qdev, slice, - pexec[i].resize - slice->offset, - dbc->id, head, tail); + pexec[i].resize - slice->offset, dbc, + head, tail); else ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail); if (ret) { diff --git a/include/uapi/drm/qaic_accel.h b/include/uapi/drm/qaic_accel.h index 43ac5d864512..9dab32316aee 100644 --- a/include/uapi/drm/qaic_accel.h +++ b/include/uapi/drm/qaic_accel.h @@ -287,8 +287,9 @@ struct qaic_execute_entry { * struct qaic_partial_execute_entry - Defines a BO to resize and submit. * @handle: In. GEM handle of the BO to commit to the device. * @dir: In. Direction of data. 1 = to device, 2 = from device. - * @resize: In. New size of the BO. Must be <= the original BO size. 0 is - * short for no resize. + * @resize: In. New size of the BO. Must be <= the original BO size. + * @resize as 0 would be interpreted as no DMA transfer is + * involved. */ struct qaic_partial_execute_entry { __u32 handle; From 451eaa1a614c911f5a51078dcb68022874e4cb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 31 Oct 2023 18:08:00 +0200 Subject: [PATCH 0212/7721] drm/i915: Bump GLK CDCLK frequency when driving multiple pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On GLK CDCLK frequency needs to be at least 2*96 MHz when accessing the audio hardware. Currently we bump the CDCLK frequency up temporarily (if not high enough already) whenever audio hardware is being accessed, and drop it back down afterwards. With a single active pipe this works just fine as we can switch between all the valid CDCLK frequencies by changing the cd2x divider, which doesn't require a full modeset. However with multiple active pipes the cd2x divider trick no longer works, and thus we end up blinking all displays off and back on. To avoid this let's just bump the CDCLK frequency to >=2*96MHz whenever multiple pipes are active. The downside is slightly higher power consumption, but that seems like an acceptable tradeoff. With a single active pipe we can stick to the current more optiomal (from power comsumption POV) behaviour. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9599 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231031160800.18371-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 6d7ba4d0f130..c4839c67cb0f 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2750,6 +2750,18 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) for_each_pipe(dev_priv, pipe) min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); + /* + * Avoid glk_force_audio_cdclk() causing excessive screen + * blinking when multiple pipes are active by making sure + * CDCLK frequency is always high enough for audio. With a + * single active pipe we can always change CDCLK frequency + * by changing the cd2x divider (see glk_cdclk_table[]) and + * thus a full modeset won't be needed then. + */ + if (IS_GEMINILAKE(dev_priv) && cdclk_state->active_pipes && + !is_power_of_2(cdclk_state->active_pipes)) + min_cdclk = max(2 * 96000, min_cdclk); + if (min_cdclk > dev_priv->display.cdclk.max_cdclk_freq) { drm_dbg_kms(&dev_priv->drm, "required cdclk (%d kHz) exceeds max (%d kHz)\n", From 7abbbe2694b3d4fd366dc91934f42c047a6d282d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 10:55:34 +0000 Subject: [PATCH 0213/7721] drm/sched: Rename drm_sched_get_cleanup_job to be more descriptive "Get cleanup job" makes it sound like helper is returning a job which will execute some cleanup, or something, while the kerneldoc itself accurately says "fetch the next _finished_ job". So lets rename the helper to be self documenting. Signed-off-by: Tvrtko Ursulin Cc: Luben Tuikov Cc: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20231102105538.391648-2-tvrtko.ursulin@linux.intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 98b2ad54fc70..fb64b35451f5 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -448,7 +448,7 @@ static void drm_sched_job_timedout(struct work_struct *work) sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work); - /* Protects against concurrent deletion in drm_sched_get_cleanup_job */ + /* Protects against concurrent deletion in drm_sched_get_finished_job */ spin_lock(&sched->job_list_lock); job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list); @@ -500,9 +500,9 @@ void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) /* * Reinsert back the bad job here - now it's safe as - * drm_sched_get_cleanup_job cannot race against us and release the + * drm_sched_get_finished_job cannot race against us and release the * bad job at this point - we parked (waited for) any in progress - * (earlier) cleanups and drm_sched_get_cleanup_job will not be called + * (earlier) cleanups and drm_sched_get_finished_job will not be called * now until the scheduler thread is unparked. */ if (bad && bad->sched == sched) @@ -960,7 +960,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) } /** - * drm_sched_get_cleanup_job - fetch the next finished job to be destroyed + * drm_sched_get_finished_job - fetch the next finished job to be destroyed * * @sched: scheduler instance * @@ -968,7 +968,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) * ready for it to be destroyed. */ static struct drm_sched_job * -drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) +drm_sched_get_finished_job(struct drm_gpu_scheduler *sched) { struct drm_sched_job *job, *next; @@ -1059,14 +1059,14 @@ static void drm_sched_free_job_work(struct work_struct *w) { struct drm_gpu_scheduler *sched = container_of(w, struct drm_gpu_scheduler, work_free_job); - struct drm_sched_job *cleanup_job; + struct drm_sched_job *job; if (READ_ONCE(sched->pause_submit)) return; - cleanup_job = drm_sched_get_cleanup_job(sched); - if (cleanup_job) { - sched->ops->free_job(cleanup_job); + job = drm_sched_get_finished_job(sched); + if (job) { + sched->ops->free_job(job); drm_sched_free_job_queue_if_done(sched); drm_sched_run_job_queue_if_ready(sched); From e608d9f7ac1a94a4a63d1ef2b37dd80669ad828d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 10:55:35 +0000 Subject: [PATCH 0214/7721] drm/sched: Move free worker re-queuing out of the if block Whether or not there are more jobs to clean up does not depend on the existance of the current job, given both drm_sched_get_finished_job and drm_sched_free_job_queue_if_done take and drop the job list lock. Therefore it is confusing to make it read like there is a dependency. Signed-off-by: Tvrtko Ursulin Cc: Luben Tuikov Cc: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20231102105538.391648-3-tvrtko.ursulin@linux.intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index fb64b35451f5..e1658030613f 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1065,12 +1065,11 @@ static void drm_sched_free_job_work(struct work_struct *w) return; job = drm_sched_get_finished_job(sched); - if (job) { + if (job) sched->ops->free_job(job); - drm_sched_free_job_queue_if_done(sched); - drm_sched_run_job_queue_if_ready(sched); - } + drm_sched_free_job_queue_if_done(sched); + drm_sched_run_job_queue_if_ready(sched); } /** From 67dd1d8c9f6543661720b9a89e28a25488cb8753 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 10:55:36 +0000 Subject: [PATCH 0215/7721] drm/sched: Rename drm_sched_free_job_queue to be more descriptive The current name makes it sound like helper will free a queue, while what it does is it enqueues the free job worker. Rename it to drm_sched_run_free_queue to align with existing drm_sched_run_job_queue. Despite that creating an illusion there are two queues, while in reality there is only one, at least it creates a consistent naming for the two enqueuing helpers. At the same time simplify the "if done" helper by dropping the suffix and adding a double underscore prefix to the one which just enqueues. Signed-off-by: Tvrtko Ursulin Cc: Luben Tuikov Cc: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20231102105538.391648-4-tvrtko.ursulin@linux.intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index e1658030613f..f9baca20b438 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -266,20 +266,20 @@ static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) } /** - * drm_sched_free_job_queue - enqueue free-job work + * __drm_sched_run_free_queue - enqueue free-job work * @sched: scheduler instance */ -static void drm_sched_free_job_queue(struct drm_gpu_scheduler *sched) +static void __drm_sched_run_free_queue(struct drm_gpu_scheduler *sched) { if (!READ_ONCE(sched->pause_submit)) queue_work(sched->submit_wq, &sched->work_free_job); } /** - * drm_sched_free_job_queue_if_done - enqueue free-job work if ready + * drm_sched_run_free_queue - enqueue free-job work if ready * @sched: scheduler instance */ -static void drm_sched_free_job_queue_if_done(struct drm_gpu_scheduler *sched) +static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched) { struct drm_sched_job *job; @@ -287,7 +287,7 @@ static void drm_sched_free_job_queue_if_done(struct drm_gpu_scheduler *sched) job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list); if (job && dma_fence_is_signaled(&job->s_fence->finished)) - drm_sched_free_job_queue(sched); + __drm_sched_run_free_queue(sched); spin_unlock(&sched->job_list_lock); } @@ -310,7 +310,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result) dma_fence_get(&s_fence->finished); drm_sched_fence_finished(s_fence, result); dma_fence_put(&s_fence->finished); - drm_sched_free_job_queue(sched); + __drm_sched_run_free_queue(sched); } /** @@ -1068,7 +1068,7 @@ static void drm_sched_free_job_work(struct work_struct *w) if (job) sched->ops->free_job(job); - drm_sched_free_job_queue_if_done(sched); + drm_sched_run_free_queue(sched); drm_sched_run_job_queue_if_ready(sched); } From 35a4279d42db534ad71a3a598029a53f22856f93 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 10:55:37 +0000 Subject: [PATCH 0216/7721] drm/sched: Rename drm_sched_run_job_queue_if_ready and clarify kerneldoc "If ready" is not immediately clear what it means - is the scheduler ready or something else? Drop the suffix, clarify kerneldoc, and employ the same naming scheme as in drm_sched_run_free_queue: - drm_sched_run_job_queue - enqueues if there is something to enqueue *and* scheduler is ready (can queue) - __drm_sched_run_job_queue - low-level helper to simply queue the job Signed-off-by: Tvrtko Ursulin Cc: Luben Tuikov Cc: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20231102105538.391648-5-tvrtko.ursulin@linux.intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index f9baca20b438..d5ddbce68fb7 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -256,10 +256,10 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) } /** - * drm_sched_run_job_queue - enqueue run-job work + * __drm_sched_run_job_queue - enqueue run-job work * @sched: scheduler instance */ -static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) +static void __drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) { if (!READ_ONCE(sched->pause_submit)) queue_work(sched->submit_wq, &sched->work_run_job); @@ -928,7 +928,7 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched) { if (drm_sched_can_queue(sched)) - drm_sched_run_job_queue(sched); + __drm_sched_run_job_queue(sched); } /** @@ -1041,13 +1041,13 @@ drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, EXPORT_SYMBOL(drm_sched_pick_best); /** - * drm_sched_run_job_queue_if_ready - enqueue run-job work if ready + * drm_sched_run_job_queue - enqueue run-job work if there are ready entities * @sched: scheduler instance */ -static void drm_sched_run_job_queue_if_ready(struct drm_gpu_scheduler *sched) +static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) { if (drm_sched_select_entity(sched)) - drm_sched_run_job_queue(sched); + __drm_sched_run_job_queue(sched); } /** @@ -1069,7 +1069,7 @@ static void drm_sched_free_job_work(struct work_struct *w) sched->ops->free_job(job); drm_sched_run_free_queue(sched); - drm_sched_run_job_queue_if_ready(sched); + drm_sched_run_job_queue(sched); } /** @@ -1126,7 +1126,7 @@ static void drm_sched_run_job_work(struct work_struct *w) } wake_up(&sched->job_scheduled); - drm_sched_run_job_queue_if_ready(sched); + drm_sched_run_job_queue(sched); } /** From f12af4c461fb6cd5ed7b48f8b4d09b22eb19fcc5 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 10:55:38 +0000 Subject: [PATCH 0217/7721] drm/sched: Drop suffix from drm_sched_wakeup_if_can_queue Because a) helper is exported to other parts of the scheduler and b) there isn't a plain drm_sched_wakeup to begin with, I think we can drop the suffix and by doing so separate the intimiate knowledge between the scheduler components a bit better. Signed-off-by: Tvrtko Ursulin Cc: Luben Tuikov Cc: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20231102105538.391648-6-tvrtko.ursulin@linux.intel.com Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_entity.c | 4 ++-- drivers/gpu/drm/scheduler/sched_main.c | 4 ++-- include/drm/gpu_scheduler.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 409e4256f6e7..f1db63cc8198 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -370,7 +370,7 @@ static void drm_sched_entity_wakeup(struct dma_fence *f, container_of(cb, struct drm_sched_entity, cb); drm_sched_entity_clear_dep(f, cb); - drm_sched_wakeup_if_can_queue(entity->rq->sched); + drm_sched_wakeup(entity->rq->sched); } /** @@ -602,7 +602,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) drm_sched_rq_update_fifo(entity, submit_ts); - drm_sched_wakeup_if_can_queue(entity->rq->sched); + drm_sched_wakeup(entity->rq->sched); } } EXPORT_SYMBOL(drm_sched_entity_push_job); diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index d5ddbce68fb7..27843e37d9b7 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -920,12 +920,12 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) } /** - * drm_sched_wakeup_if_can_queue - Wake up the scheduler + * drm_sched_wakeup - Wake up the scheduler if it is ready to queue * @sched: scheduler instance * * Wake up the scheduler if we can queue jobs. */ -void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched) +void drm_sched_wakeup(struct drm_gpu_scheduler *sched) { if (drm_sched_can_queue(sched)) __drm_sched_run_job_queue(sched); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 9daa78d2c04c..754fd2217334 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -559,7 +559,7 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched); void drm_sched_job_cleanup(struct drm_sched_job *job); -void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched); +void drm_sched_wakeup(struct drm_gpu_scheduler *sched); bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched); void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched); void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched); From a12480855ecbba6c7473c170d91c7bf41701a38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Thu, 2 Nov 2023 13:22:19 +0200 Subject: [PATCH 0218/7721] drm/i915/display: Use intel_bo_to_drm_bo instead of obj->base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe. Xe_bo doesn't have obj->base. Due to this use intel_bo_to_drm_bo instead in intel_prepare_plane_fb. Signed-off-by: Jouni Högander Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231102112219.1039362-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_atomic_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 3b9a66923422..06c2455bdd78 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -1096,7 +1096,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, * can safely continue. */ if (new_crtc_state && intel_crtc_needs_modeset(new_crtc_state)) { - ret = add_dma_resv_fences(old_obj->base.resv, + ret = add_dma_resv_fences(intel_bo_to_drm_bo(old_obj)->resv, &new_plane_state->uapi); if (ret < 0) return ret; From a379bf3d14602067812f219bd852ff89dff31133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 1 Nov 2023 13:42:08 +0200 Subject: [PATCH 0219/7721] drm/i915: Extract hsw_chicken_trans_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the same code to determine the CHICKEN_TRANS register offset sprinkled in a dozen places. Hoover it up into a small helper. TODO: find a better home for this Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231101114212.9345-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 9 +++++++++ drivers/gpu/drm/i915/display/intel_ddi.h | 2 ++ drivers/gpu/drm/i915/display/intel_display.c | 18 +++++------------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 ++------ drivers/gpu/drm/i915/display/intel_psr.c | 11 +++++------ 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2e37708fecdd..c75fd00e360a 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3115,6 +3115,15 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, trans_port_sync_stop_link_train(state, encoder, crtc_state); } +/* FIXME bad home for this function */ +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, + enum transcoder cpu_transcoder) +{ + return DISPLAY_VER(i915) >= 14 ? + MTL_CHICKEN_TRANS(cpu_transcoder) : + CHICKEN_TRANS(cpu_transcoder); +} + static i915_reg_t gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv, enum port port) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 4999c0ee229b..db845f2aca0c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -27,6 +27,8 @@ i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, + enum transcoder cpu_transcoder); void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 49ded4e32883..121ebbaba2e4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -488,11 +488,8 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) intel_de_write(dev_priv, reg, val); - if (DISPLAY_VER(dev_priv) >= 14) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), - FECSTALL_DIS_DPTSTREAM_DPTTG, 0); - else if (DISPLAY_VER(dev_priv) >= 12) - intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), + if (DISPLAY_VER(dev_priv) >= 12) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder), FECSTALL_DIS_DPTSTREAM_DPTTG, 0); if ((val & TRANSCONF_ENABLE) == 0) @@ -1503,12 +1500,9 @@ static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state) static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum transcoder transcoder = crtc_state->cpu_transcoder; - i915_reg_t reg = DISPLAY_VER(dev_priv) >= 14 ? MTL_CHICKEN_TRANS(transcoder) : - CHICKEN_TRANS(transcoder); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); - intel_de_rmw(dev_priv, reg, + intel_de_rmw(i915, hsw_chicken_trans_reg(i915, crtc_state->cpu_transcoder), HSW_FRAME_START_DELAY_MASK, HSW_FRAME_START_DELAY(crtc_state->framestart_delay - 1)); } @@ -3792,9 +3786,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, } if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { - tmp = intel_de_read(dev_priv, DISPLAY_VER(dev_priv) >= 14 ? - MTL_CHICKEN_TRANS(pipe_config->cpu_transcoder) : - CHICKEN_TRANS(pipe_config->cpu_transcoder)); + tmp = intel_de_read(dev_priv, hsw_chicken_trans_reg(dev_priv, pipe_config->cpu_transcoder)); pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; } else { diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 82f425ef1595..a32498c7826a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -817,12 +817,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, drm_atomic_get_mst_payload_state(mst_state, connector->port)); - if (DISPLAY_VER(dev_priv) >= 14) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(trans), - FECSTALL_DIS_DPTSTREAM_DPTTG, - pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); - else if (DISPLAY_VER(dev_priv) >= 12) - intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), + if (DISPLAY_VER(dev_priv) >= 12) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, trans), FECSTALL_DIS_DPTSTREAM_DPTTG, pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index ecd24a0b86cb..920f77336163 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -29,6 +29,7 @@ #include "i915_reg.h" #include "intel_atomic.h" #include "intel_crtc.h" +#include "intel_ddi.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" @@ -1452,12 +1453,10 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * All supported adlp panels have 1-based X granularity, this may * cause issues if non-supported panels are used. */ - if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), 0, - ADLP_1_BASED_X_GRANULARITY); - else if (IS_ALDERLAKE_P(dev_priv)) - intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), 0, - ADLP_1_BASED_X_GRANULARITY); + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || + IS_ALDERLAKE_P(dev_priv)) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder), + 0, ADLP_1_BASED_X_GRANULARITY); /* Wa_16012604467:adlp,mtl[a0,b0] */ if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) From f18020a5bd23b5f9b5b406b70198a5e51af67df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 1 Nov 2023 13:42:09 +0200 Subject: [PATCH 0220/7721] drm/i915: Stop using a 'reg' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'reg' is a very non-descriptive name. Just get rid of the silly local variable and spell out the full register name always. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231101114212.9345-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 121ebbaba2e4..9e9c03287869 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -398,7 +398,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - i915_reg_t reg; u32 val; drm_dbg_kms(&dev_priv->drm, "enabling pipe %c\n", pipe_name(pipe)); @@ -431,16 +430,16 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) intel_de_rmw(dev_priv, PIPE_ARB_CTL(pipe), 0, PIPE_ARB_USE_PROG_SLOTS); - reg = TRANSCONF(cpu_transcoder); - val = intel_de_read(dev_priv, reg); + val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder)); if (val & TRANSCONF_ENABLE) { /* we keep both pipes enabled on 830 */ drm_WARN_ON(&dev_priv->drm, !IS_I830(dev_priv)); return; } - intel_de_write(dev_priv, reg, val | TRANSCONF_ENABLE); - intel_de_posting_read(dev_priv, reg); + intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), + val | TRANSCONF_ENABLE); + intel_de_posting_read(dev_priv, TRANSCONF(cpu_transcoder)); /* * Until the pipe starts PIPEDSL reads will return a stale value, @@ -459,7 +458,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - i915_reg_t reg; u32 val; drm_dbg_kms(&dev_priv->drm, "disabling pipe %c\n", pipe_name(pipe)); @@ -470,8 +468,7 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) */ assert_planes_disabled(crtc); - reg = TRANSCONF(cpu_transcoder); - val = intel_de_read(dev_priv, reg); + val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder)); if ((val & TRANSCONF_ENABLE) == 0) return; @@ -486,7 +483,7 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) if (!IS_I830(dev_priv)) val &= ~TRANSCONF_ENABLE; - intel_de_write(dev_priv, reg, val); + intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), val); if (DISPLAY_VER(dev_priv) >= 12) intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder), From e5aaad610f296a79bc1096b73a31013ee0d43240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 1 Nov 2023 13:42:10 +0200 Subject: [PATCH 0221/7721] drm/i915: Extract mchbar_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop repeating the same logic to determine the correct config space register for MCHBAR. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231101114212.9345-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/soc/intel_gmch.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/soc/intel_gmch.c index f32e9f78770a..40874ebfb64c 100644 --- a/drivers/gpu/drm/i915/soc/intel_gmch.c +++ b/drivers/gpu/drm/i915/soc/intel_gmch.c @@ -33,18 +33,22 @@ int intel_gmch_bridge_setup(struct drm_i915_private *i915) i915->gmch.pdev); } +static int mchbar_reg(struct drm_i915_private *i915) +{ + return GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; +} + /* Allocate space for the MCH regs if needed, return nonzero on error */ static int intel_alloc_mchbar_resource(struct drm_i915_private *i915) { - int reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; u32 temp_lo, temp_hi = 0; u64 mchbar_addr; int ret; if (GRAPHICS_VER(i915) >= 4) - pci_read_config_dword(i915->gmch.pdev, reg + 4, &temp_hi); - pci_read_config_dword(i915->gmch.pdev, reg, &temp_lo); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915) + 4, &temp_hi); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp_lo); mchbar_addr = ((u64)temp_hi << 32) | temp_lo; /* If ACPI doesn't have it, assume we need to allocate it ourselves */ @@ -68,10 +72,10 @@ intel_alloc_mchbar_resource(struct drm_i915_private *i915) } if (GRAPHICS_VER(i915) >= 4) - pci_write_config_dword(i915->gmch.pdev, reg + 4, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915) + 4, upper_32_bits(i915->gmch.mch_res.start)); - pci_write_config_dword(i915->gmch.pdev, reg, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), lower_32_bits(i915->gmch.mch_res.start)); return 0; } @@ -79,7 +83,6 @@ intel_alloc_mchbar_resource(struct drm_i915_private *i915) /* Setup MCHBAR if possible, return true if we should disable it again */ void intel_gmch_bar_setup(struct drm_i915_private *i915) { - int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; u32 temp; bool enabled; @@ -92,7 +95,7 @@ void intel_gmch_bar_setup(struct drm_i915_private *i915) pci_read_config_dword(i915->gmch.pdev, DEVEN, &temp); enabled = !!(temp & DEVEN_MCHBAR_EN); } else { - pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp); enabled = temp & 1; } @@ -110,15 +113,13 @@ void intel_gmch_bar_setup(struct drm_i915_private *i915) pci_write_config_dword(i915->gmch.pdev, DEVEN, temp | DEVEN_MCHBAR_EN); } else { - pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp); - pci_write_config_dword(i915->gmch.pdev, mchbar_reg, temp | 1); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp); + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), temp | 1); } } void intel_gmch_bar_teardown(struct drm_i915_private *i915) { - int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; - if (i915->gmch.mchbar_need_disable) { if (IS_I915G(i915) || IS_I915GM(i915)) { u32 deven_val; @@ -131,10 +132,10 @@ void intel_gmch_bar_teardown(struct drm_i915_private *i915) } else { u32 mchbar_val; - pci_read_config_dword(i915->gmch.pdev, mchbar_reg, + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &mchbar_val); mchbar_val &= ~1; - pci_write_config_dword(i915->gmch.pdev, mchbar_reg, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), mchbar_val); } } From cf6e11650395fd27fabff294b95225886b7a9f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 1 Nov 2023 13:42:11 +0200 Subject: [PATCH 0222/7721] drm/i915/dsi: Remove dead GLK checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GLK has its own glk_dsi_clear_device_ready() so remove the dead GLK checks from vlv_dsi_clear_device_ready(). Sadly BXT still uses vlv_dsi_clear_device_ready() so the code still looks like a mess due to the difference in VLV/CHV vs. BXT port A/C shenanigans. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231101114212.9345-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/vlv_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 55da627a8b8d..64023fb8dd74 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -570,7 +570,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) drm_dbg_kms(&dev_priv->drm, "\n"); for_each_dsi_port(port, intel_dsi->ports) { /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */ - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? + i915_reg_t port_ctrl = IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A); intel_de_write(dev_priv, MIPI_DEVICE_READY(port), @@ -589,7 +589,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI * Port A only. MIPI Port C has no similar bit for checking. */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) || port == PORT_A) && + if ((IS_BROXTON(dev_priv) || port == PORT_A) && intel_de_wait_for_clear(dev_priv, port_ctrl, AFE_LATCHOUT, 30)) drm_err(&dev_priv->drm, "DSI LP not going Low\n"); From bda4a7ab26725081e222e71e00a98f4462247216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 1 Nov 2023 13:42:12 +0200 Subject: [PATCH 0223/7721] drm/i915/dsi: Extract port_ctrl_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code to determine the pre-ICL DSI port control register is repeated several times. Consolidate. vlv_dsi_clear_device_ready() is left with the open-coded version due to the weirdness with port A vs. C on VLV/CHV. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231101114212.9345-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/vlv_dsi.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 64023fb8dd74..bda49734ca33 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -561,6 +561,12 @@ static void glk_dsi_clear_device_ready(struct intel_encoder *encoder) glk_dsi_disable_mipi_io(encoder); } +static i915_reg_t port_ctrl_reg(struct drm_i915_private *i915, enum port port) +{ + return IS_GEMINILAKE(i915) || IS_BROXTON(i915) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); +} + static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -627,8 +633,7 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder, } for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); u32 temp; temp = intel_de_read(dev_priv, port_ctrl); @@ -664,8 +669,7 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) enum port port; for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); /* de-assert ip_tg_enable signal */ intel_de_rmw(dev_priv, port_ctrl, DPI_ENABLE, 0); @@ -955,9 +959,8 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, /* XXX: this only works for one DSI output */ for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t ctrl_reg = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); - bool enabled = intel_de_read(dev_priv, ctrl_reg) & DPI_ENABLE; + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); + bool enabled = intel_de_read(dev_priv, port_ctrl) & DPI_ENABLE; /* * Due to some hardware limitations on VLV/CHV, the DPI enable From 27b086382c22efb7e0a16442f7bdc2e120108ef3 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Fri, 3 Nov 2023 11:09:22 +0000 Subject: [PATCH 0224/7721] drm/i915: Fix potential spectre vulnerability Fix smatch warning: drivers/gpu/drm/i915/gem/i915_gem_context.c:847 set_proto_ctx_sseu() warn: potential spectre issue 'pc->user_engines' [r] (local cap) Fixes: d4433c7600f7 ("drm/i915/gem: Use the proto-context to handle create parameters (v5)") Cc: # v5.15+ Signed-off-by: Kunwu Chan Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20231103110922.430122-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 9a9ff84c90d7..e38f06a6e56e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -844,6 +844,7 @@ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv, if (idx >= pc->num_user_engines) return -EINVAL; + idx = array_index_nospec(idx, pc->num_user_engines); pe = &pc->user_engines[idx]; /* Only render engine supports RPCS configuration. */ From 15c28f0fc800a93801d56f164f1c4124b068ee58 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 09:32:47 +0000 Subject: [PATCH 0225/7721] drm/i915: Remove unused for_each_uabi_class_engine Unused macro after 99919be74aa3 ("drm/i915/gem: Zap the i915_gem_object_blt code") removed some code. Signed-off-by: Tvrtko Ursulin Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231102093248.362659-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8e81974607f2..4352cdd13c44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -403,11 +403,6 @@ static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) (engine__); \ (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) -#define for_each_uabi_class_engine(engine__, class__, i915__) \ - for ((engine__) = intel_engine_lookup_user((i915__), (class__), 0); \ - (engine__) && (engine__)->uabi_class == (class__); \ - (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) - #define INTEL_INFO(i915) ((i915)->__info) #define RUNTIME_INFO(i915) (&(i915)->__runtime) #define DRIVER_CAPS(i915) (&(i915)->caps) From 22d54ab6596ce4693c8d8b38371136067310a603 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Nov 2023 09:32:48 +0000 Subject: [PATCH 0226/7721] drm/i915: Move for_each_engine* out of i915_drv.h Iterators operate on struct intel_gt so lets move it to intel_gt.h in order to make i915_drv.h less of a dumping ground for stuff. Signed-off-by: Tvrtko Ursulin Suggested-by: Jani Nikula Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231102093248.362659-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_engine_pm.h | 1 + drivers/gpu/drm/i915/gt/intel_gt.h | 14 ++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 14 -------------- drivers/gpu/drm/i915/selftests/intel_uncore.c | 2 ++ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h index d68675925b79..1d97c435a015 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h @@ -10,6 +10,7 @@ #include "i915_request.h" #include "intel_engine_types.h" #include "intel_wakeref.h" +#include "intel_gt.h" #include "intel_gt_pm.h" static inline bool diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 2cac499d5aa3..df0f656c0362 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -167,6 +167,20 @@ void intel_gt_release_all(struct drm_i915_private *i915); (id__)++) \ for_each_if(((gt__) = (i915__)->gt[(id__)])) +/* Simple iterator over all initialised engines */ +#define for_each_engine(engine__, gt__, id__) \ + for ((id__) = 0; \ + (id__) < I915_NUM_ENGINES; \ + (id__)++) \ + for_each_if ((engine__) = (gt__)->engine[(id__)]) + +/* Iterator over subset of engines selected by mask */ +#define for_each_engine_masked(engine__, gt__, mask__, tmp__) \ + for ((tmp__) = (mask__) & (gt__)->info.engine_mask; \ + (tmp__) ? \ + ((engine__) = (gt__)->engine[__mask_next_bit(tmp__)]), 1 : \ + 0;) + void intel_gt_info_print(const struct intel_gt_info *info, struct drm_printer *p); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c index 8f9b874fdc9c..3aa1d014c14d 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c @@ -6,8 +6,8 @@ #include -#include "i915_drv.h" /* for_each_engine! */ #include "intel_engine.h" +#include "intel_gt.h" #include "intel_gt_debugfs.h" #include "intel_gt_engines_debugfs.h" diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4352cdd13c44..739f43af9b3a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -381,20 +381,6 @@ static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) return i915->gt[0]; } -/* Simple iterator over all initialised engines */ -#define for_each_engine(engine__, gt__, id__) \ - for ((id__) = 0; \ - (id__) < I915_NUM_ENGINES; \ - (id__)++) \ - for_each_if ((engine__) = (gt__)->engine[(id__)]) - -/* Iterator over subset of engines selected by mask */ -#define for_each_engine_masked(engine__, gt__, mask__, tmp__) \ - for ((tmp__) = (mask__) & (gt__)->info.engine_mask; \ - (tmp__) ? \ - ((engine__) = (gt__)->engine[__mask_next_bit(tmp__)]), 1 : \ - 0;) - #define rb_to_uabi_engine(rb) \ rb_entry_safe(rb, struct intel_engine_cs, uabi_node) diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 03ea75cd84dd..4f98aa8a861e 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -24,6 +24,8 @@ #include "../i915_selftest.h" +#include "gt/intel_gt.h" + static int intel_fw_table_check(const struct intel_forcewake_range *ranges, unsigned int num_ranges, bool is_watertight) From 70a3cbbe620ee66afb0c066624196077767e61b2 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Thu, 26 Oct 2023 14:56:36 +0200 Subject: [PATCH 0227/7721] drm/i915/tc: Fix -Wformat-truncation in intel_tc_port_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix below compiler warning: intel_tc.c:1879:11: error: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 3 [-Werror=format-truncation=] "%c/TC#%d", port_name(port), tc_port + 1); ^~ intel_tc.c:1878:2: note: ‘snprintf’ output between 7 and 17 bytes into a destination of size 8 snprintf(tc->port_name, sizeof(tc->port_name), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "%c/TC#%d", port_name(port), tc_port + 1); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ v2: use kasprintf(Imre) v3: use const for port_name, and fix tc mem leak(Imre) Fixes: 3eafcddf766b ("drm/i915/tc: Move TC port fields to a new intel_tc_port struct") Cc: Mika Kahola Cc: Imre Deak Cc: Jani Nikula Signed-off-by: Nirmoy Das Reviewed-by: Andrzej Hajda Reviewed-by: Imre Deak Reviewed-by: Mika Kahola Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231026125636.5080-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 37b0f8529b4f..f64d348a969e 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -58,7 +58,7 @@ struct intel_tc_port { struct delayed_work link_reset_work; int link_refcount; bool legacy_port:1; - char port_name[8]; + const char *port_name; enum tc_port_mode mode; enum tc_port_mode init_mode; enum phy_fia phy_fia; @@ -1875,8 +1875,12 @@ int intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) else tc->phy_ops = &icl_tc_phy_ops; - snprintf(tc->port_name, sizeof(tc->port_name), - "%c/TC#%d", port_name(port), tc_port + 1); + tc->port_name = kasprintf(GFP_KERNEL, "%c/TC#%d", port_name(port), + tc_port + 1); + if (!tc->port_name) { + kfree(tc); + return -ENOMEM; + } mutex_init(&tc->lock); /* TODO: Combine the two works */ @@ -1897,6 +1901,7 @@ void intel_tc_port_cleanup(struct intel_digital_port *dig_port) { intel_tc_port_suspend(dig_port); + kfree(dig_port->tc->port_name); kfree(dig_port->tc); dig_port->tc = NULL; } From 5faf6e1853d30d113ebc9977e015d0152e5e1970 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 27 Sep 2023 14:38:37 +0100 Subject: [PATCH 0228/7721] drm: Do not round to megabytes for greater than 1MiB sizes in fdinfo stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is better not to lose precision and not revert to 1 MiB size granularity for every size greater than 1 MiB. Sizes in KiB should not be so troublesome to read (and in fact machine parsing is I expect the norm here), they align with other api like /proc/meminfo, and they allow writing tests for the interface without having to embed drm.ko implementation knowledge into them. (Like knowing that minimum buffer size one can use for successful verification has to be 1MiB aligned, and on top account for any pre-existing memory utilisation outside of driver's control.) But probably even more importantly I think that it is just better to show the accurate sizes and not arbitrary lose precision for a little bit of a stretched use case of eyeballing fdinfo text directly. Signed-off-by: Tvrtko Ursulin Cc: Rob Clark Cc: Adrián Larumbe Cc: steven.price@arm.com Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20230927133843.247957-2-tvrtko.ursulin@linux.intel.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 446458aca8e9..5ddaffd32586 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -913,7 +913,7 @@ static void print_size(struct drm_printer *p, const char *stat, unsigned u; for (u = 0; u < ARRAY_SIZE(units) - 1; u++) { - if (sz < SZ_1K) + if (sz == 0 || !IS_ALIGNED(sz, SZ_1K)) break; sz = div_u64(sz, SZ_1K); } From ab67821fa9e01ff35790b8bbf256c1b65c3f628f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 2 Nov 2023 21:44:34 +0200 Subject: [PATCH 0229/7721] drm/i915/dp_mst: Disable DSC on ICL MST outputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling DSC on ICL MST outputs is broken leading to FIFO pipe / transcoder underruns and blank screen. On TGL+ platforms MST/DSC works - after fixing the known issues in [1] - however to make this work on ICL requires more work. So far DSC on MST probably didn't get enabled for users - due to an issue fixed by [2] - but after fixing that, DSC could get enabled, leading to a blank screen in ICL/MST configurations which do work atm. To prevent this disable MST/DSC on ICL for now. [1] https://lore.kernel.org/all/20231030155843.2251023-1-imre.deak@intel.com [2] https://lore.kernel.org/all/20231030155843.2251023-31-imre.deak@intel.com v2 (Ville): - Use DISPLAY_VER >= 12 instead of > 11. - Explain the ICL DSC issue in code comment. Cc: Stanislav Lisovskiy Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231102194434.2634786-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index a32498c7826a..de608c8ee7b9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -43,6 +43,7 @@ #include "intel_dpio_phy.h" #include "intel_hdcp.h" #include "intel_hotplug.h" +#include "intel_vdsc.h" #include "skl_scaler.h" static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp, @@ -297,6 +298,18 @@ static int intel_dp_mst_update_slots(struct intel_encoder *encoder, return 0; } +static bool +intel_dp_mst_dsc_source_support(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + /* + * FIXME: Enabling DSC on ICL results in blank screen and FIFO pipe / + * transcoder underruns, re-enable DSC after fixing this issue. + */ + return DISPLAY_VER(i915) >= 12 && intel_dsc_source_support(crtc_state); +} + static bool intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, @@ -375,6 +388,9 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, str_yes_no(ret), str_yes_no(intel_dp->force_dsc_en)); + if (!intel_dp_mst_dsc_source_support(pipe_config)) + return -EINVAL; + if (!intel_dp_mst_compute_config_limits(intel_dp, pipe_config, true, From 09a93cc4f7d1893777f6b788bffe60d64e4d5df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Tue, 5 Sep 2023 18:06:34 -0300 Subject: [PATCH 0230/7721] drm/v3d: Implement show_fdinfo() callback for GPU usage stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch exposes the accumulated amount of active time per client through the fdinfo infrastructure. The amount of active time is exposed for each V3D queue: BIN, RENDER, CSD, TFU and CACHE_CLEAN. In order to calculate the amount of active time per client, a CPU clock is used through the function local_clock(). The point where the jobs has started is marked and is finally compared with the time that the job had finished. Moreover, the number of jobs submitted to each queue is also exposed on fdinfo through the identifier "v3d-jobs-". Co-developed-by: Jose Maria Casanova Crespo Signed-off-by: Jose Maria Casanova Crespo Signed-off-by: Maíra Canal Acked-by: Jose Maria Casanova Crespo Reviewed-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20230905213416.1290219-3-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.c | 36 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/v3d/v3d_drv.h | 23 +++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_gem.c | 1 + drivers/gpu/drm/v3d/v3d_irq.c | 21 +++++++++++++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 20 ++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 1ab46bdf8ad7..82984b4df2a2 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,10 @@ v3d_open(struct drm_device *dev, struct drm_file *file) v3d_priv->v3d = v3d; for (i = 0; i < V3D_MAX_QUEUES; i++) { + v3d_priv->enabled_ns[i] = 0; + v3d_priv->start_ns[i] = 0; + v3d_priv->jobs_sent[i] = 0; + sched = &v3d->queue[i].sched; drm_sched_entity_init(&v3d_priv->sched_entity[i], DRM_SCHED_PRIORITY_NORMAL, &sched, @@ -136,7 +141,35 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) kfree(v3d_priv); } -DEFINE_DRM_GEM_FOPS(v3d_drm_fops); +static void v3d_show_fdinfo(struct drm_printer *p, struct drm_file *file) +{ + struct v3d_file_priv *file_priv = file->driver_priv; + u64 timestamp = local_clock(); + enum v3d_queue queue; + + for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { + /* Note that, in case of a GPU reset, the time spent during an + * attempt of executing the job is not computed in the runtime. + */ + drm_printf(p, "drm-engine-%s: \t%llu ns\n", + v3d_queue_to_string(queue), + file_priv->start_ns[queue] ? file_priv->enabled_ns[queue] + + timestamp - file_priv->start_ns[queue] + : file_priv->enabled_ns[queue]); + + /* Note that we only count jobs that completed. Therefore, jobs + * that were resubmitted due to a GPU reset are not computed. + */ + drm_printf(p, "v3d-jobs-%s: \t%llu jobs\n", + v3d_queue_to_string(queue), file_priv->jobs_sent[queue]); + } +} + +static const struct file_operations v3d_drm_fops = { + .owner = THIS_MODULE, + DRM_GEM_FOPS, + .show_fdinfo = drm_show_fdinfo, +}; /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP * protection between clients. Note that render nodes would be @@ -176,6 +209,7 @@ static const struct drm_driver v3d_drm_driver = { .ioctls = v3d_drm_ioctls, .num_ioctls = ARRAY_SIZE(v3d_drm_ioctls), .fops = &v3d_drm_fops, + .show_fdinfo = v3d_show_fdinfo, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 106454f28956..8f9d93239a17 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -21,6 +21,18 @@ struct reset_control; #define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) +static inline char *v3d_queue_to_string(enum v3d_queue queue) +{ + switch (queue) { + case V3D_BIN: return "bin"; + case V3D_RENDER: return "render"; + case V3D_TFU: return "tfu"; + case V3D_CSD: return "csd"; + case V3D_CACHE_CLEAN: return "cache_clean"; + } + return "UNKNOWN"; +} + struct v3d_queue_state { struct drm_gpu_scheduler sched; @@ -167,6 +179,12 @@ struct v3d_file_priv { } perfmon; struct drm_sched_entity sched_entity[V3D_MAX_QUEUES]; + + u64 start_ns[V3D_MAX_QUEUES]; + + u64 enabled_ns[V3D_MAX_QUEUES]; + + u64 jobs_sent[V3D_MAX_QUEUES]; }; struct v3d_bo { @@ -238,6 +256,11 @@ struct v3d_job { */ struct v3d_perfmon *perfmon; + /* File descriptor of the process that submitted the job that could be used + * for collecting stats by process of GPU usage. + */ + struct drm_file *file; + /* Callback for the freeing of the job on refcount going to 0. */ void (*free)(struct kref *ref); }; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 5688d46d30e6..a33e90f29bd5 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -415,6 +415,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, job = *container; job->v3d = v3d; job->free = free; + job->file = file_priv; ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], v3d_priv); diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index 9705e0cb576d..ba390b782103 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -14,6 +14,7 @@ */ #include +#include #include "v3d_drv.h" #include "v3d_regs.h" @@ -101,6 +102,11 @@ v3d_irq(int irq, void *arg) if (intsts & V3D_INT_FLDONE) { struct v3d_fence *fence = to_v3d_fence(v3d->bin_job->base.irq_fence); + struct v3d_file_priv *file = v3d->bin_job->base.file->driver_priv; + + file->enabled_ns[V3D_BIN] += local_clock() - file->start_ns[V3D_BIN]; + file->jobs_sent[V3D_BIN]++; + file->start_ns[V3D_BIN] = 0; trace_v3d_bcl_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -110,6 +116,11 @@ v3d_irq(int irq, void *arg) if (intsts & V3D_INT_FRDONE) { struct v3d_fence *fence = to_v3d_fence(v3d->render_job->base.irq_fence); + struct v3d_file_priv *file = v3d->render_job->base.file->driver_priv; + + file->enabled_ns[V3D_RENDER] += local_clock() - file->start_ns[V3D_RENDER]; + file->jobs_sent[V3D_RENDER]++; + file->start_ns[V3D_RENDER] = 0; trace_v3d_rcl_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -119,6 +130,11 @@ v3d_irq(int irq, void *arg) if (intsts & V3D_INT_CSDDONE(v3d->ver)) { struct v3d_fence *fence = to_v3d_fence(v3d->csd_job->base.irq_fence); + struct v3d_file_priv *file = v3d->csd_job->base.file->driver_priv; + + file->enabled_ns[V3D_CSD] += local_clock() - file->start_ns[V3D_CSD]; + file->jobs_sent[V3D_CSD]++; + file->start_ns[V3D_CSD] = 0; trace_v3d_csd_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -155,6 +171,11 @@ v3d_hub_irq(int irq, void *arg) if (intsts & V3D_HUB_INT_TFUC) { struct v3d_fence *fence = to_v3d_fence(v3d->tfu_job->base.irq_fence); + struct v3d_file_priv *file = v3d->tfu_job->base.file->driver_priv; + + file->enabled_ns[V3D_TFU] += local_clock() - file->start_ns[V3D_TFU]; + file->jobs_sent[V3D_TFU]++; + file->start_ns[V3D_TFU] = 0; trace_v3d_tfu_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index f59b63e51b14..19afceacda83 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -18,6 +18,7 @@ * semaphores to interlock between them. */ +#include #include #include "v3d_drv.h" @@ -76,6 +77,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) { struct v3d_bin_job *job = to_bin_job(sched_job); struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; struct drm_device *dev = &v3d->drm; struct dma_fence *fence; unsigned long irqflags; @@ -107,6 +109,8 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno, job->start, job->end); + file->start_ns[V3D_BIN] = local_clock(); + v3d_switch_perfmon(v3d, &job->base); /* Set the current and end address of the control list. @@ -131,6 +135,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) { struct v3d_render_job *job = to_render_job(sched_job); struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; struct drm_device *dev = &v3d->drm; struct dma_fence *fence; @@ -158,6 +163,8 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno, job->start, job->end); + file->start_ns[V3D_RENDER] = local_clock(); + v3d_switch_perfmon(v3d, &job->base); /* XXX: Set the QCFG */ @@ -176,6 +183,7 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) { struct v3d_tfu_job *job = to_tfu_job(sched_job); struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; struct drm_device *dev = &v3d->drm; struct dma_fence *fence; @@ -190,6 +198,8 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); + file->start_ns[V3D_TFU] = local_clock(); + V3D_WRITE(V3D_TFU_IIA(v3d->ver), job->args.iia); V3D_WRITE(V3D_TFU_IIS(v3d->ver), job->args.iis); V3D_WRITE(V3D_TFU_ICA(v3d->ver), job->args.ica); @@ -215,6 +225,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) { struct v3d_csd_job *job = to_csd_job(sched_job); struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; struct drm_device *dev = &v3d->drm; struct dma_fence *fence; int i, csd_cfg0_reg, csd_cfg_reg_count; @@ -233,6 +244,8 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno); + file->start_ns[V3D_CSD] = local_clock(); + v3d_switch_perfmon(v3d, &job->base); csd_cfg0_reg = V3D_CSD_QUEUED_CFG0(v3d->ver); @@ -250,9 +263,16 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job) { struct v3d_job *job = to_v3d_job(sched_job); struct v3d_dev *v3d = job->v3d; + struct v3d_file_priv *file = job->file->driver_priv; + + file->start_ns[V3D_CACHE_CLEAN] = local_clock(); v3d_clean_caches(v3d); + file->enabled_ns[V3D_CACHE_CLEAN] += local_clock() - file->start_ns[V3D_CACHE_CLEAN]; + file->jobs_sent[V3D_CACHE_CLEAN]++; + file->start_ns[V3D_CACHE_CLEAN] = 0; + return NULL; } From 509433d8146c64ca9e0bcc370ec910821fffe80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Tue, 5 Sep 2023 18:06:35 -0300 Subject: [PATCH 0231/7721] drm/v3d: Expose the total GPU usage stats on sysfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous patch exposed the accumulated amount of active time per client for each V3D queue. But this doesn't provide a global notion of the GPU usage. Therefore, provide the accumulated amount of active time for each V3D queue (BIN, RENDER, CSD, TFU and CACHE_CLEAN), considering all the jobs submitted to the queue, independent of the client. This data is exposed through the sysfs interface, so that if the interface is queried at two different points of time the usage percentage of each of the queues can be calculated. Co-developed-by: Jose Maria Casanova Crespo Signed-off-by: Jose Maria Casanova Crespo Signed-off-by: Maíra Canal Acked-by: Jose Maria Casanova Crespo Reviewed-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20230905213416.1290219-3-mcanal@igalia.com --- drivers/gpu/drm/v3d/Makefile | 3 +- drivers/gpu/drm/v3d/v3d_drv.c | 9 +++++ drivers/gpu/drm/v3d/v3d_drv.h | 8 ++++ drivers/gpu/drm/v3d/v3d_gem.c | 6 ++- drivers/gpu/drm/v3d/v3d_irq.c | 28 +++++++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 15 ++++++- drivers/gpu/drm/v3d/v3d_sysfs.c | 69 +++++++++++++++++++++++++++++++++ 7 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/v3d/v3d_sysfs.c diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile index e8b314137020..4b21b20e4998 100644 --- a/drivers/gpu/drm/v3d/Makefile +++ b/drivers/gpu/drm/v3d/Makefile @@ -11,7 +11,8 @@ v3d-y := \ v3d_mmu.o \ v3d_perfmon.o \ v3d_trace_points.o \ - v3d_sched.o + v3d_sched.o \ + v3d_sysfs.o v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 82984b4df2a2..44a1ca57d6a4 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -316,8 +316,14 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) if (ret) goto irq_disable; + ret = v3d_sysfs_init(dev); + if (ret) + goto drm_unregister; + return 0; +drm_unregister: + drm_dev_unregister(drm); irq_disable: v3d_irq_disable(v3d); gem_destroy: @@ -331,6 +337,9 @@ static void v3d_platform_drm_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); struct v3d_dev *v3d = to_v3d_dev(drm); + struct device *dev = &pdev->dev; + + v3d_sysfs_destroy(dev); drm_dev_unregister(drm); diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 8f9d93239a17..4c59fefaa0b4 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -38,6 +38,10 @@ struct v3d_queue_state { u64 fence_context; u64 emit_seqno; + + u64 start_ns; + u64 enabled_ns; + u64 jobs_sent; }; /* Performance monitor object. The perform lifetime is controlled by userspace @@ -441,3 +445,7 @@ int v3d_perfmon_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_perfmon_get_values_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); + +/* v3d_sysfs.c */ +int v3d_sysfs_init(struct device *dev); +void v3d_sysfs_destroy(struct device *dev); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index a33e90f29bd5..712675134c04 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -1014,8 +1014,12 @@ v3d_gem_init(struct drm_device *dev) u32 pt_size = 4096 * 1024; int ret, i; - for (i = 0; i < V3D_MAX_QUEUES; i++) + for (i = 0; i < V3D_MAX_QUEUES; i++) { v3d->queue[i].fence_context = dma_fence_context_alloc(1); + v3d->queue[i].start_ns = 0; + v3d->queue[i].enabled_ns = 0; + v3d->queue[i].jobs_sent = 0; + } spin_lock_init(&v3d->mm_lock); spin_lock_init(&v3d->job_lock); diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index ba390b782103..afc76390a197 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -103,10 +103,17 @@ v3d_irq(int irq, void *arg) struct v3d_fence *fence = to_v3d_fence(v3d->bin_job->base.irq_fence); struct v3d_file_priv *file = v3d->bin_job->base.file->driver_priv; + u64 runtime = local_clock() - file->start_ns[V3D_BIN]; file->enabled_ns[V3D_BIN] += local_clock() - file->start_ns[V3D_BIN]; file->jobs_sent[V3D_BIN]++; + v3d->queue[V3D_BIN].jobs_sent++; + file->start_ns[V3D_BIN] = 0; + v3d->queue[V3D_BIN].start_ns = 0; + + file->enabled_ns[V3D_BIN] += runtime; + v3d->queue[V3D_BIN].enabled_ns += runtime; trace_v3d_bcl_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -117,10 +124,17 @@ v3d_irq(int irq, void *arg) struct v3d_fence *fence = to_v3d_fence(v3d->render_job->base.irq_fence); struct v3d_file_priv *file = v3d->render_job->base.file->driver_priv; + u64 runtime = local_clock() - file->start_ns[V3D_RENDER]; file->enabled_ns[V3D_RENDER] += local_clock() - file->start_ns[V3D_RENDER]; file->jobs_sent[V3D_RENDER]++; + v3d->queue[V3D_RENDER].jobs_sent++; + file->start_ns[V3D_RENDER] = 0; + v3d->queue[V3D_RENDER].start_ns = 0; + + file->enabled_ns[V3D_RENDER] += runtime; + v3d->queue[V3D_RENDER].enabled_ns += runtime; trace_v3d_rcl_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -131,10 +145,17 @@ v3d_irq(int irq, void *arg) struct v3d_fence *fence = to_v3d_fence(v3d->csd_job->base.irq_fence); struct v3d_file_priv *file = v3d->csd_job->base.file->driver_priv; + u64 runtime = local_clock() - file->start_ns[V3D_CSD]; file->enabled_ns[V3D_CSD] += local_clock() - file->start_ns[V3D_CSD]; file->jobs_sent[V3D_CSD]++; + v3d->queue[V3D_CSD].jobs_sent++; + file->start_ns[V3D_CSD] = 0; + v3d->queue[V3D_CSD].start_ns = 0; + + file->enabled_ns[V3D_CSD] += runtime; + v3d->queue[V3D_CSD].enabled_ns += runtime; trace_v3d_csd_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); @@ -172,10 +193,17 @@ v3d_hub_irq(int irq, void *arg) struct v3d_fence *fence = to_v3d_fence(v3d->tfu_job->base.irq_fence); struct v3d_file_priv *file = v3d->tfu_job->base.file->driver_priv; + u64 runtime = local_clock() - file->start_ns[V3D_TFU]; file->enabled_ns[V3D_TFU] += local_clock() - file->start_ns[V3D_TFU]; file->jobs_sent[V3D_TFU]++; + v3d->queue[V3D_TFU].jobs_sent++; + file->start_ns[V3D_TFU] = 0; + v3d->queue[V3D_TFU].start_ns = 0; + + file->enabled_ns[V3D_TFU] += runtime; + v3d->queue[V3D_TFU].enabled_ns += runtime; trace_v3d_tfu_irq(&v3d->drm, fence->seqno); dma_fence_signal(&fence->base); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 19afceacda83..fccbea2a5f2e 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -110,6 +110,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) job->start, job->end); file->start_ns[V3D_BIN] = local_clock(); + v3d->queue[V3D_BIN].start_ns = file->start_ns[V3D_BIN]; v3d_switch_perfmon(v3d, &job->base); @@ -164,6 +165,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) job->start, job->end); file->start_ns[V3D_RENDER] = local_clock(); + v3d->queue[V3D_RENDER].start_ns = file->start_ns[V3D_RENDER]; v3d_switch_perfmon(v3d, &job->base); @@ -199,6 +201,7 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); file->start_ns[V3D_TFU] = local_clock(); + v3d->queue[V3D_TFU].start_ns = file->start_ns[V3D_TFU]; V3D_WRITE(V3D_TFU_IIA(v3d->ver), job->args.iia); V3D_WRITE(V3D_TFU_IIS(v3d->ver), job->args.iis); @@ -245,6 +248,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno); file->start_ns[V3D_CSD] = local_clock(); + v3d->queue[V3D_CSD].start_ns = file->start_ns[V3D_CSD]; v3d_switch_perfmon(v3d, &job->base); @@ -264,14 +268,23 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job) struct v3d_job *job = to_v3d_job(sched_job); struct v3d_dev *v3d = job->v3d; struct v3d_file_priv *file = job->file->driver_priv; + u64 runtime; file->start_ns[V3D_CACHE_CLEAN] = local_clock(); + v3d->queue[V3D_CACHE_CLEAN].start_ns = file->start_ns[V3D_CACHE_CLEAN]; v3d_clean_caches(v3d); - file->enabled_ns[V3D_CACHE_CLEAN] += local_clock() - file->start_ns[V3D_CACHE_CLEAN]; + runtime = local_clock() - file->start_ns[V3D_CACHE_CLEAN]; + + file->enabled_ns[V3D_CACHE_CLEAN] += runtime; + v3d->queue[V3D_CACHE_CLEAN].enabled_ns += runtime; + file->jobs_sent[V3D_CACHE_CLEAN]++; + v3d->queue[V3D_CACHE_CLEAN].jobs_sent++; + file->start_ns[V3D_CACHE_CLEAN] = 0; + v3d->queue[V3D_CACHE_CLEAN].start_ns = 0; return NULL; } diff --git a/drivers/gpu/drm/v3d/v3d_sysfs.c b/drivers/gpu/drm/v3d/v3d_sysfs.c new file mode 100644 index 000000000000..d106845ba890 --- /dev/null +++ b/drivers/gpu/drm/v3d/v3d_sysfs.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Igalia S.L. + */ + +#include +#include + +#include "v3d_drv.h" + +static ssize_t +gpu_stats_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct v3d_dev *v3d = to_v3d_dev(drm); + enum v3d_queue queue; + u64 timestamp = local_clock(); + u64 active_runtime; + ssize_t len = 0; + + len += sysfs_emit(buf, "queue\ttimestamp\tjobs\truntime\n"); + + for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { + if (v3d->queue[queue].start_ns) + active_runtime = timestamp - v3d->queue[queue].start_ns; + else + active_runtime = 0; + + /* Each line will display the queue name, timestamp, the number + * of jobs sent to that queue and the runtime, as can be seem here: + * + * queue timestamp jobs runtime + * bin 239043069420 22620 17438164056 + * render 239043069420 22619 27284814161 + * tfu 239043069420 8763 394592566 + * csd 239043069420 3168 10787905530 + * cache_clean 239043069420 6127 237375940 + */ + len += sysfs_emit_at(buf, len, "%s\t%llu\t%llu\t%llu\n", + v3d_queue_to_string(queue), + timestamp, + v3d->queue[queue].jobs_sent, + v3d->queue[queue].enabled_ns + active_runtime); + } + + return len; +} +static DEVICE_ATTR_RO(gpu_stats); + +static struct attribute *v3d_sysfs_entries[] = { + &dev_attr_gpu_stats.attr, + NULL, +}; + +static struct attribute_group v3d_sysfs_attr_group = { + .attrs = v3d_sysfs_entries, +}; + +int +v3d_sysfs_init(struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &v3d_sysfs_attr_group); +} + +void +v3d_sysfs_destroy(struct device *dev) +{ + return sysfs_remove_group(&dev->kobj, &v3d_sysfs_attr_group); +} From 27d9620e9a9a6bc27a646b464b85860d91e21af3 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Mon, 23 Oct 2023 11:05:56 +0200 Subject: [PATCH 0232/7721] drm/panel: nt35510: fix typo Replace 'HFP' with 'HBP'. Fixes: 899f24ed8d3a ("drm/panel: Add driver for Novatek NT35510-based panels") Signed-off-by: Dario Binacchi Reviewed-by: Neil Armstrong Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20231023090613.1694133-1-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/panel/panel-novatek-nt35510.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index d6dceb858008..83a9cf53d269 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -1023,7 +1023,7 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .hdisplay = 480, .hsync_start = 480 + 2, /* HFP = 2 */ .hsync_end = 480 + 2 + 0, /* HSync = 0 */ - .htotal = 480 + 2 + 0 + 5, /* HFP = 5 */ + .htotal = 480 + 2 + 0 + 5, /* HBP = 5 */ .vdisplay = 800, .vsync_start = 800 + 2, /* VFP = 2 */ .vsync_end = 800 + 2 + 0, /* VSync = 0 */ From 34df0a031d8f3488fe72627b041a1f82437fa6ec Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Thu, 2 Nov 2023 10:58:31 -0700 Subject: [PATCH 0233/7721] drm/i915/gt: Temporarily disable CPU caching into DMA for MTL FIXME: It is suspected that some Address Translation Service (ATS) issue on IOMMU is causing CAT errors to occur on some MTL workloads. Applying a write barrier to the ppgtt set entry functions appeared to have no effect, so we must temporarily use I915_MAP_WC in the map_pt_dma class of functions on MTL until a proper ATS solution is found. Signed-off-by: Jonathan Cavitt CC: Chris Wilson Reviewed-by: Radhakrishna Sripada Acked-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231102175831.872763-1-jonathan.cavitt@intel.com --- drivers/gpu/drm/i915/gt/intel_gtt.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 4fbed27ef0ec..21719563a602 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -95,6 +95,16 @@ int map_pt_dma(struct i915_address_space *vm, struct drm_i915_gem_object *obj) void *vaddr; type = intel_gt_coherent_map_type(vm->gt, obj, true); + /* + * FIXME: It is suspected that some Address Translation Service (ATS) + * issue on IOMMU is causing CAT errors to occur on some MTL workloads. + * Applying a write barrier to the ppgtt set entry functions appeared + * to have no effect, so we must temporarily use I915_MAP_WC here on + * MTL until a proper ATS solution is found. + */ + if (IS_METEORLAKE(vm->i915)) + type = I915_MAP_WC; + vaddr = i915_gem_object_pin_map_unlocked(obj, type); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); @@ -109,6 +119,16 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object void *vaddr; type = intel_gt_coherent_map_type(vm->gt, obj, true); + /* + * FIXME: It is suspected that some Address Translation Service (ATS) + * issue on IOMMU is causing CAT errors to occur on some MTL workloads. + * Applying a write barrier to the ppgtt set entry functions appeared + * to have no effect, so we must temporarily use I915_MAP_WC here on + * MTL until a proper ATS solution is found. + */ + if (IS_METEORLAKE(vm->i915)) + type = I915_MAP_WC; + vaddr = i915_gem_object_pin_map(obj, type); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); From 2b981d57e480e024cde2a0ecb6edee28a8ec39d6 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 6 Nov 2023 13:42:28 +0200 Subject: [PATCH 0234/7721] drm/i915/display: Support PSR entry VSC packet to be transmitted one frame earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display driver shall read DPCD 00071h[3:1] during configuration to get PSR setup time. This register provides the setup time requirement on the VSC SDP entry packet. If setup time cannot be met with the current timings (e.g., PSR setup time + other blanking requirements > blanking time), driver should enable sending VSC SDP one frame earlier before sending the capture frame. BSpec: 69895 (PSR Entry Setup Frames 17:16) v2: Write frames before su entry to correct register (Ville, Jouni) Move frames before su entry calculation to it's own function (Ville, Jouni) Rename PSR Entry Setup Frames register to indicate Lunarlake specificity (Jouni) v3: Modify setup entry frames calculation function to return the actual frames (Ville) Match comment with actual implementation (Jouni) v4: Drop "set" from function naming (Jouni, Ville) Use i915 instead of dev_priv (Jouni) Signed-off-by: Mika Kahola Reviewed-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231106114228.146574-1-mika.kahola@intel.com --- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 81 +++++++++++++++---- drivers/gpu/drm/i915/display/intel_psr_regs.h | 2 + 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 047fe3f8905a..92f06d67fd1e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1708,6 +1708,7 @@ struct intel_psr { u32 dc3co_exitline; u32 dc3co_exit_delay; struct delayed_work dc3co_work; + u8 entry_setup_frames; }; struct intel_dp { diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 920f77336163..3691f882e1c0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -593,6 +593,9 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) if (intel_dp->psr.req_psr2_sdp_prior_scanline) dpcd_val |= DP_PSR_SU_REGION_SCANLINE_CAPTURE; + if (intel_dp->psr.entry_setup_frames > 0) + dpcd_val |= DP_PSR_FRAME_CAPTURE; + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); @@ -691,6 +694,9 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 8) val |= EDP_PSR_CRC_ENABLE; + if (DISPLAY_VER(dev_priv) >= 20) + val |= LNL_EDP_PSR_ENTRY_SETUP_FRAMES(intel_dp->psr.entry_setup_frames); + intel_de_rmw(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), ~EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK, val); } @@ -728,11 +734,27 @@ static int psr2_block_count(struct intel_dp *intel_dp) return psr2_block_count_lines(intel_dp) / 4; } +static u8 frames_before_su_entry(struct intel_dp *intel_dp) +{ + u8 frames_before_su_entry; + + frames_before_su_entry = max_t(u8, + intel_dp->psr.sink_sync_latency + 1, + 2); + + /* Entry setup frames must be at least 1 less than frames before SU entry */ + if (intel_dp->psr.entry_setup_frames >= frames_before_su_entry) + frames_before_su_entry = intel_dp->psr.entry_setup_frames + 1; + + return frames_before_su_entry; +} + static void hsw_activate_psr2(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 val = EDP_PSR2_ENABLE; + u32 psr_val = 0; val |= EDP_PSR2_IDLE_FRAMES(psr_compute_idle_frames(intel_dp)); @@ -742,7 +764,8 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) val |= EDP_Y_COORDINATE_ENABLE; - val |= EDP_PSR2_FRAME_BEFORE_SU(max_t(u8, intel_dp->psr.sink_sync_latency + 1, 2)); + val |= EDP_PSR2_FRAME_BEFORE_SU(frames_before_su_entry(intel_dp)); + val |= intel_psr2_get_tp_time(intel_dp); if (DISPLAY_VER(dev_priv) >= 12) { @@ -786,6 +809,9 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (intel_dp->psr.req_psr2_sdp_prior_scanline) val |= EDP_PSR2_SU_SDP_SCANLINE; + if (DISPLAY_VER(dev_priv) >= 20) + psr_val |= LNL_EDP_PSR_ENTRY_SETUP_FRAMES(intel_dp->psr.entry_setup_frames); + if (intel_dp->psr.psr2_sel_fetch_enabled) { u32 tmp; @@ -799,7 +825,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. */ - intel_de_write(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), 0); + intel_de_write(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), psr_val); intel_de_write(dev_priv, EDP_PSR2_CTL(cpu_transcoder), val); } @@ -1067,6 +1093,39 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, return true; } +static u8 intel_psr_entry_setup_frames(struct intel_dp *intel_dp, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd); + u8 entry_setup_frames = 0; + + if (psr_setup_time < 0) { + drm_dbg_kms(&i915->drm, + "PSR condition failed: Invalid PSR setup time (0x%02x)\n", + intel_dp->psr_dpcd[1]); + return -ETIME; + } + + if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) > + adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) { + if (DISPLAY_VER(i915) >= 20) { + /* setup entry frames can be up to 3 frames */ + entry_setup_frames = 1; + drm_dbg_kms(&i915->drm, + "PSR setup entry frames %d\n", + entry_setup_frames); + } else { + drm_dbg_kms(&i915->drm, + "PSR condition failed: PSR setup time (%d us) too long\n", + psr_setup_time); + return -ETIME; + } + } + + return entry_setup_frames; +} + static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { @@ -1214,7 +1273,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - int psr_setup_time; + u8 entry_setup_frames; /* * Current PSR panels don't work reliably with VRR enabled @@ -1243,19 +1302,13 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; } - psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd); - if (psr_setup_time < 0) { - drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: Invalid PSR setup time (0x%02x)\n", - intel_dp->psr_dpcd[1]); - return; - } + entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode); - if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) > - adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) { + if (entry_setup_frames >= 0) { + intel_dp->psr.entry_setup_frames = entry_setup_frames; + } else { drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: PSR setup time (%d us) too long\n", - psr_setup_time); + "PSR condition failed: PSR setup timing not met\n"); return; } diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index d39951383c92..efe4306b37e0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -35,6 +35,8 @@ #define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES REG_FIELD_PREP(EDP_PSR_MIN_LINK_ENTRY_TIME_MASK, 3) #define EDP_PSR_MAX_SLEEP_TIME_MASK REG_GENMASK(24, 20) #define EDP_PSR_MAX_SLEEP_TIME(x) REG_FIELD_PREP(EDP_PSR_MAX_SLEEP_TIME_MASK, (x)) +#define LNL_EDP_PSR_ENTRY_SETUP_FRAMES_MASK REG_GENMASK(17, 16) +#define LNL_EDP_PSR_ENTRY_SETUP_FRAMES(x) REG_FIELD_PREP(LNL_EDP_PSR_ENTRY_SETUP_FRAMES_MASK, (x)) #define EDP_PSR_SKIP_AUX_EXIT REG_BIT(12) #define EDP_PSR_TP_MASK REG_BIT(11) #define EDP_PSR_TP_TP1_TP2 REG_FIELD_PREP(EDP_PSR_TP_MASK, 0) From c015fb6d01adb616fb54824feb55ce5ab18e8ca1 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Mon, 6 Nov 2023 14:08:26 +0100 Subject: [PATCH 0235/7721] accel/ivpu: Fix compilation with CONFIG_PM=n Use pm_runtime_status_suspended() instead of dev->power.runtime_status field that is not available without PM. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/all/20231106130827.1600948-1-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 255f2b8b0b5e..618dbc17df80 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "ivpu_drv.h" @@ -318,8 +319,7 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r struct vpu_jsm_msg hb_resp; int ret, hb_ret; - drm_WARN_ON(&vdev->drm, - vdev->drm.dev->power.runtime_status == RPM_SUSPENDED); + drm_WARN_ON(&vdev->drm, pm_runtime_status_suspended(vdev->drm.dev)); ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) From 3fef3e6ff86a405e51f4a7072109147b4b47caca Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Nov 2023 17:52:22 +0200 Subject: [PATCH 0236/7721] drm/i915: move display mutex inits to display code The core code has no business accessing i915->display directly. These could be further spread to respective files, but this is a start. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231102155223.2298316-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_driver.c | 6 ++++++ drivers/gpu/drm/i915/i915_driver.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 44b59ac301e6..0a5b922f2ad6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -181,6 +181,12 @@ void intel_display_driver_early_probe(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return; + mutex_init(&i915->display.backlight.lock); + mutex_init(&i915->display.audio.mutex); + mutex_init(&i915->display.wm.wm_mutex); + mutex_init(&i915->display.pps.mutex); + mutex_init(&i915->display.hdcp.hdcp_mutex); + intel_display_irq_init(i915); intel_dkl_phy_init(i915); intel_color_init_hooks(i915); diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 3d86db5638fc..8dead878e51a 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -230,16 +230,10 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); - mutex_init(&dev_priv->display.backlight.lock); mutex_init(&dev_priv->sb_lock); cpu_latency_qos_add_request(&dev_priv->sb_qos, PM_QOS_DEFAULT_VALUE); - mutex_init(&dev_priv->display.audio.mutex); - mutex_init(&dev_priv->display.wm.wm_mutex); - mutex_init(&dev_priv->display.pps.mutex); - mutex_init(&dev_priv->display.hdcp.hdcp_mutex); - i915_memcpy_init_early(dev_priv); intel_runtime_pm_init_early(&dev_priv->runtime_pm); From 607a2c64e879580ef361af65d6052367057bee14 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Nov 2023 17:52:23 +0200 Subject: [PATCH 0237/7721] drm/i915: move display spinlock init to display code The gem code has no business accessing i915->display directly. Signed-off-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231102155223.2298316-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_driver.c | 1 + drivers/gpu/drm/i915/i915_gem.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 0a5b922f2ad6..62f7b10484be 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -181,6 +181,7 @@ void intel_display_driver_early_probe(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return; + spin_lock_init(&i915->display.fb_tracking.lock); mutex_init(&i915->display.backlight.lock); mutex_init(&i915->display.audio.mutex); mutex_init(&i915->display.wm.wm_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 147d5b95b9ac..c9caa8638789 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1301,8 +1301,6 @@ void i915_gem_init_early(struct drm_i915_private *dev_priv) { i915_gem_init__mm(dev_priv); i915_gem_init__contexts(dev_priv); - - spin_lock_init(&dev_priv->display.fb_tracking.lock); } void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) From 1d9e6bc97eabac150b775d91d9a656ba24e92014 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Mon, 6 Nov 2023 17:19:59 -0300 Subject: [PATCH 0238/7721] drm/i915/xelpmp: Add Wa_16021867713 This workaround applies to all steppings of Xe_LPM+. Implement the KMD part. v2: - Put the definition of VDBOX_CGCTL3F1C() in the correct sort order. (Matt) Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231106201959.156943-1-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_regs.h | 2 ++ drivers/gpu/drm/i915/gt/intel_workarounds.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index c0c8c12edea1..a8eac59e3779 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -263,5 +263,7 @@ #define VDBOX_CGCTL3F18(base) _MMIO((base) + 0x3f18) #define ALNUNIT_CLKGATE_DIS REG_BIT(13) +#define VDBOX_CGCTL3F1C(base) _MMIO((base) + 0x3f1c) +#define MFXPIPE_CLKGATE_DIS REG_BIT(3) #endif /* __INTEL_ENGINE_REGS__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 12859b8d2092..63205edfea50 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -1662,9 +1662,23 @@ xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) debug_dump_steering(gt); } +static void +wa_16021867713(struct intel_gt *gt, struct i915_wa_list *wal) +{ + struct intel_engine_cs *engine; + int id; + + for_each_engine(engine, gt, id) + if (engine->class == VIDEO_DECODE_CLASS) + wa_write_or(wal, VDBOX_CGCTL3F1C(engine->mmio_base), + MFXPIPE_CLKGATE_DIS); +} + static void xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { + wa_16021867713(gt, wal); + /* * Wa_14018778641 * Wa_18018781329 From bc8d6a9df99038f61adf2881ad9f717abe414e06 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 2 Nov 2023 18:17:20 -0400 Subject: [PATCH 0239/7721] drm/sched: Don't disturb the entity when in RR-mode scheduling Don't call drm_sched_select_entity() in drm_sched_run_job_queue(). In fact, rename __drm_sched_run_job_queue() to just drm_sched_run_job_queue(), and let it do just that, schedule the work item for execution. The problem is that drm_sched_run_job_queue() calls drm_sched_select_entity() to determine if the scheduler has an entity ready in one of its run-queues, and in the case of the Round-Robin (RR) scheduling, the function drm_sched_rq_select_entity_rr() does just that, selects the _next_ entity which is ready, sets up the run-queue and completion and returns that entity. The FIFO scheduling algorithm is unaffected. Now, since drm_sched_run_job_work() also calls drm_sched_select_entity(), then in the case of RR scheduling, that would result in drm_sched_select_entity() having been called twice, which may result in skipping a ready entity if more than one entity is ready. This commit fixes this by eliminating the call to drm_sched_select_entity() from drm_sched_run_job_queue(), and leaves it only in drm_sched_run_job_work(). v2: Rebased on top of Tvrtko's renames series of patches. (Luben) Add fixes-tag. (Tvrtko) Signed-off-by: Luben Tuikov Fixes: f7fe64ad0f22ff ("drm/sched: Split free_job into own work item") Reviewed-by: Matthew Brost Reviewed-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231107041020.10035-2-ltuikov89@gmail.com --- drivers/gpu/drm/scheduler/sched_main.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 27843e37d9b7..cd0dc3f81d05 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -256,10 +256,10 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) } /** - * __drm_sched_run_job_queue - enqueue run-job work + * drm_sched_run_job_queue - enqueue run-job work * @sched: scheduler instance */ -static void __drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) +static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) { if (!READ_ONCE(sched->pause_submit)) queue_work(sched->submit_wq, &sched->work_run_job); @@ -928,7 +928,7 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) void drm_sched_wakeup(struct drm_gpu_scheduler *sched) { if (drm_sched_can_queue(sched)) - __drm_sched_run_job_queue(sched); + drm_sched_run_job_queue(sched); } /** @@ -1040,16 +1040,6 @@ drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, } EXPORT_SYMBOL(drm_sched_pick_best); -/** - * drm_sched_run_job_queue - enqueue run-job work if there are ready entities - * @sched: scheduler instance - */ -static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) -{ - if (drm_sched_select_entity(sched)) - __drm_sched_run_job_queue(sched); -} - /** * drm_sched_free_job_work - worker to call free_job * From 89d04995f76ce8318fe752feb33b1a45893b1a38 Mon Sep 17 00:00:00 2001 From: Emma Anholt Date: Tue, 31 Oct 2023 11:16:48 -0700 Subject: [PATCH 0240/7721] MAINTAINERS: Drop Emma Anholt from all M lines. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I am not active in the Linux kernel and don't want to see patches. Signed-off-by: Emma Anholt Acked-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20231031181648.48675-1-emma@anholt.net --- MAINTAINERS | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index f13e476ed803..4e1a63479cad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6405,8 +6405,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/sun4i/sun8i* DRM DRIVER FOR ARM PL111 CLCD -M: Emma Anholt -S: Supported +S: Orphan T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/pl111/ @@ -6521,8 +6520,7 @@ F: Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml F: drivers/gpu/drm/panel/panel-himax-hx8394.c DRM DRIVER FOR HX8357D PANELS -M: Emma Anholt -S: Maintained +S: Orphan T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/himax,hx8357d.txt F: drivers/gpu/drm/tiny/hx8357d.c @@ -7106,7 +7104,6 @@ F: Documentation/devicetree/bindings/display/ti/ F: drivers/gpu/drm/omapdrm/ DRM DRIVERS FOR V3D -M: Emma Anholt M: Melissa Wen S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc @@ -7115,7 +7112,6 @@ F: drivers/gpu/drm/v3d/ F: include/uapi/drm/v3d_drm.h DRM DRIVERS FOR VC4 -M: Emma Anholt M: Maxime Ripard S: Supported T: git git://github.com/anholt/linux From 560ea72c76eb6d0c59f77580414e64cc09f1093d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 30 Oct 2023 01:13:08 +0200 Subject: [PATCH 0241/7721] drm/i915/dp_mst: Fix race between connector registration and setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After drm_connector_init() is called the connector is visible to the rest of the kernel via the drm_mode_config::connector_list. Make sure that the DSC AUX device and capabilities are setup by that time. Another race condition is adding the connector to the connector list before drm_connector_helper_add() sets the connector helper functions. That's an unrelated issue, for which the fix is for a follow-up. One solution would be adding the connector to the connector list only during its registration in drm_connector_register(). Cc: Stanislav Lisovskiy Cc: Ville Syrjälä Fixes: 808b43fa7e56 ("drm/i915/dp_mst: Set connector DSC capabilities and decompression AUX") Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index de608c8ee7b9..4625900416e9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1168,6 +1168,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->port = port; drm_dp_mst_get_port_malloc(port); + /* + * TODO: set the AUX for the actual MST port decompressing the stream. + * At the moment the driver only supports enabling this globally in the + * first downstream MST branch, via intel_dp's (root port) AUX. + */ + intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; + intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); + connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); @@ -1179,14 +1187,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); - /* - * TODO: set the AUX for the actual MST port decompressing the stream. - * At the moment the driver only supports enabling this globally in the - * first downstream MST branch, via intel_dp's (root port) AUX. - */ - intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; - intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); - for_each_pipe(dev_priv, pipe) { struct drm_encoder *enc = &intel_dp->mst_encoders[pipe]->base.base; From 7707dd6022593f3edd8e182e7935870cf326f874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Oct 2023 04:08:57 +0300 Subject: [PATCH 0242/7721] drm/dp_mst: Fix fractional DSC bpp handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code does '(bpp << 4) / 16' in the MST PBN calculation, but that is just the same as 'bpp' so the DSC codepath achieves absolutely nothing. Fix it up so that the fractional part of the bpp value is actually used instead of truncated away. 64*1006 has enough zero lsbs that we can just shift that down in the dividend and thus still manage to stick to a 32bit divisor. And while touching this, let's just make the whole thing more straightforward by making the passed in bpp value .4 binary fixed point always, instead of having to pass in different things based on whether DSC is enabled or not. v2: - Fix DSC kunit test cases. Cc: Manasi Navare Cc: Lyude Paul Cc: Harry Wentland Cc: David Francis Cc: Mikita Lipski Cc: Alex Deucher Fixes: dc48529fb14e ("drm/dp_mst: Add PBN calculation for DSC modes") Signed-off-by: Ville Syrjälä [Imre: Fix kunit test cases] Acked-by: Maxime Ripard Reviewed-by: Lyude Paul Acked-by: Harry Wentland Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-3-imre.deak@intel.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- drivers/gpu/drm/display/drm_dp_mst_topology.c | 20 +++++-------------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 5 ++--- drivers/gpu/drm/nouveau/dispnv50/disp.c | 3 +-- .../gpu/drm/tests/drm_dp_mst_helper_test.c | 6 +++--- include/drm/display/drm_dp_mst_helper.h | 2 +- 7 files changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c6fd34bab358..df3c42bb9274 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6876,7 +6876,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, max_bpc); bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; clock = adjusted_mode->clock; - dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); } dm_new_connector_state->vcpi_slots = diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 57230661132b..2afd1bc74978 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1636,7 +1636,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( } else { /* check if mode could be supported within full_pbn */ bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3; - pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp, false); + pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp << 4); if (pbn > aconnector->mst_output_port->full_pbn) return DC_FAIL_BANDWIDTH_VALIDATE; diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index c490e8befc2f..bc2c9dfe229f 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -4718,13 +4718,12 @@ EXPORT_SYMBOL(drm_dp_check_act_status); /** * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode. - * @clock: dot clock for the mode - * @bpp: bpp for the mode. - * @dsc: DSC mode. If true, bpp has units of 1/16 of a bit per pixel + * @clock: dot clock + * @bpp: bpp as .4 binary fixed point * * This uses the formula in the spec to calculate the PBN value for a mode. */ -int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) +int drm_dp_calc_pbn_mode(int clock, int bpp) { /* * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 @@ -4735,18 +4734,9 @@ int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) * peak_kbps *= (1006/1000) * peak_kbps *= (64/54) * peak_kbps *= 8 convert to bytes - * - * If the bpp is in units of 1/16, further divide by 16. Put this - * factor in the numerator rather than the denominator to avoid - * integer overflow */ - - if (dsc) - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * (bpp / 16), 64 * 1006), - 8 * 54 * 1000 * 1000); - - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006), - 8 * 54 * 1000 * 1000); + return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), + 1000 * 8 * 54 * 1000); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4625900416e9..6f9c9f3b5b12 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -107,8 +107,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, continue; crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, - dsc ? bpp << 4 : bpp, - dsc); + bpp << 4); slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, @@ -982,7 +981,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, return ret; if (mode_rate > max_rate || mode->clock > max_dotclk || - drm_dp_calc_pbn_mode(mode->clock, min_bpp, false) > port->full_pbn) { + drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) { *status = MODE_CLOCK_HIGH; return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 52f1569ee37c..3d390f5029f6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -982,8 +982,7 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, const int clock = crtc_state->adjusted_mode.clock; asyh->or.bpc = connector->display_info.bpc; - asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3, - false); + asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4); } mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index 545beea33e8c..e3c818dfc0e6 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -42,13 +42,13 @@ static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases .clock = 332880, .bpp = 24, .dsc = true, - .expected = 50 + .expected = 1191 }, { .clock = 324540, .bpp = 24, .dsc = true, - .expected = 49 + .expected = 1161 }, }; @@ -56,7 +56,7 @@ static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) { const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value; - KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp, params->dsc), + KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp << 4), params->expected); } diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index 4429d3b1745b..655862b3d2a4 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -842,7 +842,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, int link_rate, int link_lane_count); -int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); +int drm_dp_calc_pbn_mode(int clock, int bpp); void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_t link_encoding_cap); From 9dcf67deeab6fbc4984175278b1b2c59881dca52 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:08:58 +0300 Subject: [PATCH 0243/7721] drm/dp_mst: Add helper to determine if an MST port is downstream of another port Add drm_dp_mst_port_downstream_of_parent() required by the i915 driver in a follow-up patch to resolve a BW overallocation of MST streams going through a given MST port. Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Lyude Paul Acked-by: Maxime Ripard Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-4-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 52 +++++++++++++++++++ include/drm/display/drm_dp_mst_helper.h | 3 ++ 2 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index bc2c9dfe229f..fa0049572f22 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5126,6 +5126,58 @@ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port, return false; } +static bool +drm_dp_mst_port_downstream_of_parent_locked(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_mst_port *parent) +{ + if (!mgr->mst_primary) + return false; + + port = drm_dp_mst_topology_get_port_validated_locked(mgr->mst_primary, + port); + if (!port) + return false; + + if (!parent) + return true; + + parent = drm_dp_mst_topology_get_port_validated_locked(mgr->mst_primary, + parent); + if (!parent) + return false; + + if (!parent->mstb) + return false; + + return drm_dp_mst_port_downstream_of_branch(port, parent->mstb); +} + +/** + * drm_dp_mst_port_downstream_of_parent - check if a port is downstream of a parent port + * @mgr: MST topology manager + * @port: the port being looked up + * @parent: the parent port + * + * The function returns %true if @port is downstream of @parent. If @parent is + * %NULL - denoting the root port - the function returns %true if @port is in + * @mgr's topology. + */ +bool +drm_dp_mst_port_downstream_of_parent(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_mst_port *parent) +{ + bool ret; + + mutex_lock(&mgr->lock); + ret = drm_dp_mst_port_downstream_of_parent_locked(mgr, port, parent); + mutex_unlock(&mgr->lock); + + return ret; +} +EXPORT_SYMBOL(drm_dp_mst_port_downstream_of_parent); + static int drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, struct drm_dp_mst_topology_state *state); diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index 655862b3d2a4..e44485aa74e9 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -892,6 +892,9 @@ drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_atomic_payload * drm_atomic_get_mst_payload_state(struct drm_dp_mst_topology_state *state, struct drm_dp_mst_port *port); +bool drm_dp_mst_port_downstream_of_parent(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_mst_port *parent); int __must_check drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, From 1cd0a5ea427931016c3e95b20dc20f17604937cc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:08:59 +0300 Subject: [PATCH 0244/7721] drm/dp_mst: Factor out a helper to check the atomic state of a topology manager Factor out a helper to check the atomic state for one MST topology manager, returning the MST port where the BW limit check has failed. This will be used in a follow-up patch by the i915 driver to improve the BW sharing between MST streams. Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Lyude Paul Acked-by: Maxime Ripard Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-5-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 93 +++++++++++++++---- include/drm/display/drm_dp_mst_helper.h | 4 + 2 files changed, 78 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index fa0049572f22..0fbfdd23ef4e 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5180,11 +5180,13 @@ EXPORT_SYMBOL(drm_dp_mst_port_downstream_of_parent); static int drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, - struct drm_dp_mst_topology_state *state); + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port); static int drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, - struct drm_dp_mst_topology_state *state) + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port) { struct drm_dp_mst_atomic_payload *payload; struct drm_dp_mst_port *port; @@ -5213,7 +5215,7 @@ drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, drm_dbg_atomic(mstb->mgr->dev, "[MSTB:%p] Checking bandwidth limits\n", mstb); list_for_each_entry(port, &mstb->ports, next) { - ret = drm_dp_mst_atomic_check_port_bw_limit(port, state); + ret = drm_dp_mst_atomic_check_port_bw_limit(port, state, failing_port); if (ret < 0) return ret; @@ -5225,7 +5227,8 @@ drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, static int drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, - struct drm_dp_mst_topology_state *state) + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port) { struct drm_dp_mst_atomic_payload *payload; int pbn_used = 0; @@ -5246,13 +5249,15 @@ drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, drm_dbg_atomic(port->mgr->dev, "[MSTB:%p] [MST PORT:%p] no BW available for the port\n", port->parent, port); + *failing_port = port; return -EINVAL; } pbn_used = payload->pbn; } else { pbn_used = drm_dp_mst_atomic_check_mstb_bw_limit(port->mstb, - state); + state, + failing_port); if (pbn_used <= 0) return pbn_used; } @@ -5261,6 +5266,7 @@ drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, drm_dbg_atomic(port->mgr->dev, "[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n", port->parent, port, pbn_used, port->full_pbn); + *failing_port = port; return -ENOSPC; } @@ -5438,20 +5444,79 @@ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); +/** + * drm_dp_mst_atomic_check_mgr - Check the atomic state of an MST topology manager + * @state: The global atomic state + * @mgr: Manager to check + * @mst_state: The MST atomic state for @mgr + * @failing_port: Returns the port with a BW limitation + * + * Checks the given MST manager's topology state for an atomic update to ensure + * that it's valid. This includes checking whether there's enough bandwidth to + * support the new timeslot allocations in the atomic update. + * + * Any atomic drivers supporting DP MST must make sure to call this or + * the drm_dp_mst_atomic_check() function after checking the rest of their state + * in their &drm_mode_config_funcs.atomic_check() callback. + * + * See also: + * drm_dp_mst_atomic_check() + * drm_dp_atomic_find_time_slots() + * drm_dp_atomic_release_time_slots() + * + * Returns: + * - 0 if the new state is valid + * - %-ENOSPC, if the new state is invalid, because of BW limitation + * @failing_port is set to: + * - The non-root port where a BW limit check failed + * The returned port pointer is valid until at least + * one payload downstream of it exists. + * - %NULL if the BW limit check failed at the root port + * - %-EINVAL, if the new state is invalid, because the root port has + * too many payloads. + */ +int drm_dp_mst_atomic_check_mgr(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_port **failing_port) +{ + int ret; + + *failing_port = NULL; + + if (!mgr->mst_state) + return 0; + + ret = drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); + if (ret) + return ret; + + mutex_lock(&mgr->lock); + ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary, + mst_state, + failing_port); + mutex_unlock(&mgr->lock); + + return ret < 0 ? ret : 0; +} +EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr); + /** * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an * atomic update is valid * @state: Pointer to the new &struct drm_dp_mst_topology_state * * Checks the given topology state for an atomic update to ensure that it's - * valid. This includes checking whether there's enough bandwidth to support - * the new timeslot allocations in the atomic update. + * valid, calling drm_dp_mst_atomic_check_mgr() for all MST manager in the + * atomic state. This includes checking whether there's enough bandwidth to + * support the new timeslot allocations in the atomic update. * * Any atomic drivers supporting DP MST must make sure to call this after * checking the rest of their state in their * &drm_mode_config_funcs.atomic_check() callback. * * See also: + * drm_dp_mst_atomic_check_mgr() * drm_dp_atomic_find_time_slots() * drm_dp_atomic_release_time_slots() * @@ -5466,21 +5531,11 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state) int i, ret = 0; for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { - if (!mgr->mst_state) - continue; + struct drm_dp_mst_port *tmp_port; - ret = drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); + ret = drm_dp_mst_atomic_check_mgr(state, mgr, mst_state, &tmp_port); if (ret) break; - - mutex_lock(&mgr->lock); - ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary, - mst_state); - mutex_unlock(&mgr->lock); - if (ret < 0) - break; - else - ret = 0; } return ret; diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index e44485aa74e9..a4aad6df71f1 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -916,6 +916,10 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, struct drm_dp_query_stream_enc_status_ack_reply *status); +int __must_check drm_dp_mst_atomic_check_mgr(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_port **failing_port); int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); int __must_check drm_dp_mst_root_conn_atomic_check(struct drm_connector_state *new_conn_state, struct drm_dp_mst_topology_mgr *mgr); From d075bca47c18779301fee5a9d140f146cde4b532 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:00 +0300 Subject: [PATCH 0245/7721] drm/dp_mst: Swap the order of checking root vs. non-root port BW limitations drm_dp_mst_atomic_check_mgr() should check for BW limitation starting from sink ports continuing towards the root port, so that drivers can use the @failing_port returned to resolve a BW overallocation in an ideal way. For instance from streams A,B,C in a topology A,B going through @failing_port and C not going through it, a BW overallocation of A,B due to a limit of the port must be resolved first before considering the limits of other ports closer to the root port. This way can avoid reducing the BW of stream C unnecessarily due to a BW limit closer to the root port. Based on the above swap the order of the BW check for the root port and the check for all the ports downstream of it (the latter going through the topology already in the sink->root port direction). Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Lyude Paul Reviewed-by: Stanislav Lisovskiy Acked-by: Maxime Ripard Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-6-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 0fbfdd23ef4e..8433b9c59cf2 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5469,9 +5469,13 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); * - %-ENOSPC, if the new state is invalid, because of BW limitation * @failing_port is set to: * - The non-root port where a BW limit check failed + * with all the ports downstream of @failing_port passing + * the BW limit check. * The returned port pointer is valid until at least * one payload downstream of it exists. * - %NULL if the BW limit check failed at the root port + * with all the ports downstream of the root port passing + * the BW limit check. * - %-EINVAL, if the new state is invalid, because the root port has * too many payloads. */ @@ -5487,17 +5491,16 @@ int drm_dp_mst_atomic_check_mgr(struct drm_atomic_state *state, if (!mgr->mst_state) return 0; - ret = drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); - if (ret) - return ret; - mutex_lock(&mgr->lock); ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary, mst_state, failing_port); mutex_unlock(&mgr->lock); - return ret < 0 ? ret : 0; + if (ret < 0) + return ret; + + return drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); } EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr); From 6f1aa39d6497d4d27f8ee132e9cb8bdbfe7c0674 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:01 +0300 Subject: [PATCH 0246/7721] drm/dp_mst: Allow DSC in any Synaptics last branch device The Synaptics MST branch devices support DSC decompression on all their output ports, provided that they are last branch devices (with their output ports connected to the sinks). The Thinkpad 40B0 TBT dock for instance has two such branch devices, a secondary one connected to one of the output ports of the primary; hence the decompression needs to be enabled in both branch devices to enable decompression for all the sinks. Based on the above add support for enabling decompression in last Synaptics branch devices. Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Stanislav Lisovskiy Acked-by: Maxime Ripard Reviewed-by: Lyude Paul Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-7-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 8433b9c59cf2..a462229908fc 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5994,6 +5994,7 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port) struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) { struct drm_dp_mst_port *immediate_upstream_port; + struct drm_dp_aux *immediate_upstream_aux; struct drm_dp_mst_port *fec_port; struct drm_dp_desc desc = {}; u8 endpoint_fec; @@ -6058,21 +6059,25 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) * - Port is on primary branch device * - Not a VGA adapter (DP_DWN_STRM_PORT_TYPE_ANALOG) */ - if (drm_dp_read_desc(port->mgr->aux, &desc, true)) + if (immediate_upstream_port) + immediate_upstream_aux = &immediate_upstream_port->aux; + else + immediate_upstream_aux = port->mgr->aux; + + if (drm_dp_read_desc(immediate_upstream_aux, &desc, true)) return NULL; - if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && - port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && - port->parent == port->mgr->mst_primary) { + if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD)) { u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; - if (drm_dp_read_dpcd_caps(port->mgr->aux, dpcd_ext) < 0) + if (drm_dp_read_dpcd_caps(immediate_upstream_aux, dpcd_ext) < 0) return NULL; - if ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) && + if (dpcd_ext[DP_DPCD_REV] >= DP_DPCD_REV_14 && + ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) && ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) - != DP_DWN_STRM_PORT_TYPE_ANALOG)) - return port->mgr->aux; + != DP_DWN_STRM_PORT_TYPE_ANALOG))) + return immediate_upstream_aux; } /* From b348150406564595cf6c1be388e9797fa97c2a5d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:02 +0300 Subject: [PATCH 0247/7721] drm/dp: Add DP_HBLANK_EXPANSION_CAPABLE and DSC_PASSTHROUGH_EN DPCD flags Add the DPCD flag to enable DSC passthrough in a last branch device, used in a follow-up i915 patch. Also add a flag to detect HBLANK expansion support in a branch device, used by a workaround in a follow-up i915 patch. Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Stanislav Lisovskiy Acked-by: Maxime Ripard Reviewed-by: Lyude Paul Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-8-imre.deak@intel.com --- include/drm/display/drm_dp.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index e69cece404b3..763d45a612f3 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -148,6 +148,7 @@ #define DP_RECEIVE_PORT_0_CAP_0 0x008 # define DP_LOCAL_EDID_PRESENT (1 << 1) # define DP_ASSOCIATED_TO_PRECEDING_PORT (1 << 2) +# define DP_HBLANK_EXPANSION_CAPABLE (1 << 3) #define DP_RECEIVE_PORT_0_BUFFER_SIZE 0x009 @@ -699,6 +700,7 @@ #define DP_DSC_ENABLE 0x160 /* DP 1.4 */ # define DP_DECOMPRESSION_EN (1 << 0) +# define DP_DSC_PASSTHROUGH_EN (1 << 1) #define DP_DSC_CONFIGURATION 0x161 /* DP 2.0 */ #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ From a6315ec25eed0e9a70cb1cfc43cf694911546a5c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 13:22:16 +0300 Subject: [PATCH 0248/7721] drm/dp_mst: Add HBLANK expansion quirk for Synaptics MST hubs Add a quirk for Synaptics MST hubs, which require a workaround - at leat on i915 - for some modes, on which the hub applies HBLANK expansion. These modes will only work by enabling DSC decompression for them, a follow-up patch will do this in i915. v2: - Fix the quirk name in its DocBook description. Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Stanislav Lisovskiy Acked-by: Maxime Ripard Reviewed-by: Lyude Paul Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-9-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 2 ++ include/drm/display/drm_dp_helper.h | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 8a1b64c57dfd..2a95a05f0437 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2242,6 +2242,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) }, /* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */ { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) }, + /* Synaptics DP1.4 MST hubs require DSC for some modes on which it applies HBLANK expansion. */ + { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) }, /* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */ { OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) }, }; diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 3369104e2d25..01636a679ee6 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -632,6 +632,13 @@ enum drm_dp_quirk { * the DP_MAX_LINK_RATE register reporting a lower max multiplier. */ DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS, + /** + * @DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC: + * + * The device applies HBLANK expansion for some modes, but this + * requires enabling DSC. + */ + DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC, }; /** From c1d6a22b7219bd52c66e9e038a282ba79f04be1f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 13:22:17 +0300 Subject: [PATCH 0249/7721] drm/dp: Add helpers to calculate the link BW overhead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helpers drivers can use to calculate the BW allocation overhead - due to SSC, FEC, DSC and data alignment on symbol cycles - and the channel coding efficiency - due to the 8b/10b, 128b/132b encoding. On 128b/132b links the FEC overhead is part of the coding efficiency, so not accounted for in the BW allocation overhead. The drivers can use these functions to calculate a ratio, controlling the stream symbol insertion rate of the source device in each SST TU or MST MTP frame. Drivers can calculate this m/n = (pixel_data_rate * drm_dp_bw_overhead()) / (link_data_rate * drm_dp_bw_channel_coding_efficiency()) ratio for a given link and pixel stream and with that the slots_per_mtp = CEIL(64 * m / n) allocated slots per MTP for the stream in a link frame and with that the pbn = slots_per_mtp * drm_mst_get_pbn_divider() allocated PBNs for the stream on the MST link path. Take drm_dp_bw_overhead() into use in drm_dp_calc_pbn_mode(), for drivers calculating the PBN value directly. v2: - Add dockbook description to drm_dp_bw_channel_coding_efficiency(). (LKP). - Clarify the way m/n ratio is calculated in the commit log. v3: - Fix compile breakage for !CONFIG_BACKLIGHT_CLASS_DEVICE. (LKP) - Account for FEC_PM overhead (+ 0.0015625 %), add comment with the formula to calculate the total FEC overhead. (Ville) v4: - Rename DRM_DP_OVERHEAD_SSC to DRM_DP_OVERHEAD_SSC_REF_CLK. (Ville) v5: - Clarify in the commit log what MTP means. - Simplify the commit log's formula to calculate PBN. Cc: Lyude Paul Cc: Ville Syrjälä Cc: kernel test robot Cc: dri-devel@lists.freedesktop.org Reviewed-by: Stanislav Lisovskiy (v2) Acked-by: Maxime Ripard Reviewed-by: Lyude Paul Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-1-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 132 ++++++++++++++++++ drivers/gpu/drm/display/drm_dp_mst_topology.c | 23 ++- include/drm/display/drm_dp_helper.h | 11 ++ 3 files changed, 160 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 2a95a05f0437..64c151e4f78c 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -3897,3 +3897,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) EXPORT_SYMBOL(drm_panel_dp_aux_backlight); #endif + +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, + int symbol_size, bool is_mst) +{ + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); + int align = is_mst ? 4 / lane_count : 1; + + return ALIGN(cycles, align); +} + +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, + int bpp_x16, int symbol_size, bool is_mst) +{ + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, + bpp_x16, symbol_size, is_mst); + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; + + return slice_count * (slice_data_cycles + slice_eoc_cycles); +} + +/** + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream + * @lane_count: DP link lane count + * @hactive: pixel count of the active period in one scanline of the stream + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set + * @bpp_x16: bits per pixel in .4 binary fixed point + * @flags: DRM_DP_OVERHEAD_x flags + * + * Calculate the BW allocation overhead of a DP link stream, depending + * on the link's + * - @lane_count + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) + * as well as the stream's + * - @hactive timing + * - @bpp_x16 color depth + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). + * Note that this overhead doesn't account for the 8b/10b, 128b/132b + * channel coding efficiency, for that see + * @drm_dp_link_bw_channel_coding_efficiency(). + * + * Returns the overhead as 100% + overhead% in 1ppm units. + */ +int drm_dp_bw_overhead(int lane_count, int hactive, + int dsc_slice_count, + int bpp_x16, unsigned long flags) +{ + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; + u32 overhead = 1000000; + int symbol_cycles; + + /* + * DP Standard v2.1 2.6.4.1 + * SSC downspread and ref clock variation margin: + * 5300ppm + 300ppm ~ 0.6% + */ + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) + overhead += 6000; + + /* + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: + * FEC symbol insertions for 8b/10b channel coding: + * After each 250 data symbols on 2-4 lanes: + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) + * After each 2 x 250 data symbols on 1 lane: + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: + * 256 * 256 bytes + 1 FEC_PM + * or + * 128 * 512 bytes + 1 FEC_PM + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % + */ + if (flags & DRM_DP_BW_OVERHEAD_FEC) + overhead += 24016; + + /* + * DP Standard v2.1 2.7.9, 5.9.7 + * The FEC overhead for UHBR is accounted for in its 96.71% channel + * coding efficiency. + */ + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && + (flags & DRM_DP_BW_OVERHEAD_FEC)); + + if (flags & DRM_DP_BW_OVERHEAD_DSC) + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, + dsc_slice_count, + bpp_x16, symbol_size, + is_mst); + else + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, + bpp_x16, symbol_size, + is_mst); + + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, + overhead * 16), + hactive * bpp_x16); +} +EXPORT_SYMBOL(drm_dp_bw_overhead); + +/** + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency + * @is_uhbr: Whether the link has a 128b/132b channel coding + * + * Return the channel coding efficiency of the given DP link type, which is + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead + * and for 128b/132b any link or PHY level control symbol insertion overhead + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the + * corresponding FEC overhead is BW allocation specific, included in the value + * returned by drm_dp_bw_overhead(). + * + * Returns the efficiency in the 100%/coding-overhead% ratio in + * 1ppm units. + */ +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) +{ + if (is_uhbr) + return 967100; + else + /* + * Note that on 8b/10b MST the efficiency is only + * 78.75% due to the 1 out of 64 MTPH packet overhead, + * not accounted for here. + */ + return 800000; +} +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index a462229908fc..0854fe428f17 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); int drm_dp_calc_pbn_mode(int clock, int bpp) { /* - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on * common multiplier to render an integer PBN for all link rate/lane * counts combinations * calculate - * peak_kbps *= (1006/1000) - * peak_kbps *= (64/54) - * peak_kbps *= 8 convert to bytes + * peak_kbps = clock * bpp / 16 + * peak_kbps *= SSC overhead / 1000000 + * peak_kbps /= 8 convert to Kbytes + * peak_kBps *= (64/54) / 1000 convert to PBN */ - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), - 1000 * 8 * 54 * 1000); + /* + * TODO: Use the actual link and mode parameters to calculate + * the overhead. For now it's assumed that these are + * 4 link lanes, 4096 hactive pixels, which don't add any + * significant data padding overhead and that there is no DSC + * or FEC overhead. + */ + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, + DRM_DP_BW_OVERHEAD_MST | + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); + + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), + 1000000ULL * 8 * 54 * 1000); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 01636a679ee6..3c59f64d4a69 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ const u8 port_cap[4], u8 color_spc); int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); +#define DRM_DP_BW_OVERHEAD_MST BIT(0) +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) + +int drm_dp_bw_overhead(int lane_count, int hactive, + int dsc_slice_count, + int bpp_x16, unsigned long flags); +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); + #endif /* _DRM_DP_HELPER_H_ */ From d91680efcaaba6cc2e7cd83e4aa5e1d0f1c6f684 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:05 +0300 Subject: [PATCH 0250/7721] drm/i915/dp_mst: Enable FEC early once it's known DSC is needed Enable FEC in crtc_state, as soon as it's known it will be needed by DSC. This fixes the calculation of BW allocation overhead, in case DSC is enabled by falling back to it during the encoder compute config phase (vs. enabling FEC due to DSC being enabled on other streams). v2: - Enable FEC only in intel_dp_mst_find_vcpi_slots_for_bpp(), since only by that will crtc_state->port_clock be set, which in turn is needed by intel_dp_is_uhbr(). Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-11-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 6 +++--- drivers/gpu/drm/i915/display/intel_dp.h | 5 +++++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 7 +++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ea97db7d9abf..516671f50b6c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1369,9 +1369,9 @@ static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, return false; } -static bool intel_dp_supports_fec(struct intel_dp *intel_dp, - const struct intel_connector *connector, - const struct intel_crtc_state *pipe_config) +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config) { return intel_dp_source_supports_fec(intel_dp, pipe_config) && drm_dp_sink_supports_fec(connector->dp.fec_capability); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 484aea215a25..0258580a6aad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -137,6 +137,11 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) } u32 intel_dp_mode_to_fec_clock(u32 mode_clock); + +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config); + u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 pipe_bpp); void intel_ddi_update_pipe(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 6f9c9f3b5b12..28db1775d3a5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -95,6 +95,13 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->lane_count = limits->max_lane_count; crtc_state->port_clock = limits->max_rate; + if (dsc) { + if (!intel_dp_supports_fec(intel_dp, connector, crtc_state)) + return -EINVAL; + + crtc_state->fec_enable = !intel_dp_is_uhbr(crtc_state); + } + mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, crtc_state->port_clock, crtc_state->lane_count); From 3e306daab76ac32b3496583e1db43baabe8a062e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:06 +0300 Subject: [PATCH 0251/7721] drm/i915/dp: Specify the FEC overhead as an increment vs. a remainder A follow-up patch will add up all the overheads on a DP link, where it makes more sense to specify each overhead factor in terms of the added overhead amount vs. the reciprocal remainder (of usable BW remaining after deducting the overhead). Prepare for that here, keeping the existing behavior. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-12-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 516671f50b6c..6186926f865e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -85,8 +85,8 @@ #define DP_DSC_MAX_ENC_THROUGHPUT_0 340000 #define DP_DSC_MAX_ENC_THROUGHPUT_1 400000 -/* DP DSC FEC Overhead factor = 1/(0.972261) */ -#define DP_DSC_FEC_OVERHEAD_FACTOR 972261 +/* DP DSC FEC Overhead factor in ppm = 1/(0.972261) = 1.028530 */ +#define DP_DSC_FEC_OVERHEAD_FACTOR 1028530 /* Compliance test status bits */ #define INTEL_DP_RESOLUTION_SHIFT_MASK 0 @@ -680,8 +680,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, u32 intel_dp_mode_to_fec_clock(u32 mode_clock) { - return div_u64(mul_u32_u32(mode_clock, 1000000U), - DP_DSC_FEC_OVERHEAD_FACTOR); + return div_u64(mul_u32_u32(mode_clock, DP_DSC_FEC_OVERHEAD_FACTOR), + 1000000U); } static int From 7ff2090c7c98644ea04be7ff8e304b74f47cf9dc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:07 +0300 Subject: [PATCH 0252/7721] drm/i915/dp: Pass actual BW overhead to m_n calculation A follow-up MST patch will need to specify the total BW allocation overhead, prepare for that here by passing the amount of overhead to intel_link_compute_m_n(), keeping the existing behavior. v2: - Fix passing the correct crtc_state->fec_enable param in intel_dp_mst_compute_link_config() / intel_dp_dsc_mst_compute_link_config(). Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-13-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 40 +++++++++++++++++--- drivers/gpu/drm/i915/display/intel_display.h | 4 +- drivers/gpu/drm/i915/display/intel_dp.c | 30 ++++++++++++--- drivers/gpu/drm/i915/display/intel_dp.h | 2 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 ++-- drivers/gpu/drm/i915/display/intel_fdi.c | 5 ++- 6 files changed, 71 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9e9c03287869..3c7ef2cc3b8b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2389,17 +2389,45 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n, intel_reduce_m_n_ratio(ret_m, ret_n); } +static void +add_bw_alloc_overhead(int link_clock, int bw_overhead, + int pixel_data_rate, int link_data_rate, + u32 *data_m, u32 *data_n) +{ + bool is_uhbr = intel_dp_is_uhbr_rate(link_clock); + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(is_uhbr); + + /* + * TODO: adjust for actual UHBR channel coding efficiency and BW + * overhead. + */ + if (is_uhbr) { + *data_m = pixel_data_rate; + *data_n = link_data_rate * 8 / 10; + return; + } + + *data_m = DIV_ROUND_UP_ULL(mul_u32_u32(pixel_data_rate, bw_overhead), + 1000000); + *data_n = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_data_rate, ch_coding_efficiency), + 1000000); +} + void intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, int pixel_clock, int link_clock, - struct intel_link_m_n *m_n, - bool fec_enable) + int bw_overhead, + struct intel_link_m_n *m_n) { u32 data_clock = bits_per_pixel * pixel_clock; + u32 data_m; + u32 data_n; - if (fec_enable) - data_clock = intel_dp_mode_to_fec_clock(data_clock); - + add_bw_alloc_overhead(link_clock, bw_overhead, + data_clock, + link_clock * 10 * nlanes, + &data_m, &data_n); /* * Windows/BIOS uses fixed M/N values always. Follow suit. * @@ -2409,7 +2437,7 @@ intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, */ m_n->tu = 64; compute_m_n(&m_n->data_m, &m_n->data_n, - data_clock, link_clock * nlanes * 8, + data_m, data_n, 0x8000000); compute_m_n(&m_n->link_m, &m_n->link_n, diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index cae2a3b12e20..6d0636acb725 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -394,8 +394,8 @@ u8 intel_calc_active_pipes(struct intel_atomic_state *state, u8 active_pipes); void intel_link_compute_m_n(u16 bpp, int nlanes, int pixel_clock, int link_clock, - struct intel_link_m_n *m_n, - bool fec_enable); + int bw_overhead, + struct intel_link_m_n *m_n); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); enum drm_mode_status diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6186926f865e..4dc923bc4c97 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -121,10 +121,15 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) static void intel_dp_unset_edid(struct intel_dp *intel_dp); +bool intel_dp_is_uhbr_rate(int rate) +{ + return rate >= 1000000; +} + /* Is link rate UHBR and thus 128b/132b? */ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) { - return crtc_state->port_clock >= 1000000; + return intel_dp_is_uhbr_rate(crtc_state->port_clock); } static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) @@ -684,6 +689,20 @@ u32 intel_dp_mode_to_fec_clock(u32 mode_clock) 1000000U); } +int intel_dp_bw_fec_overhead(bool fec_enabled) +{ + /* + * TODO: Calculate the actual overhead for a given mode. + * The hard-coded 1/0.972261=2.853% overhead factor + * corresponds (for instance) to the 8b/10b DP FEC 2.4% + + * 0.453% DSC overhead. This is enough for a 3840 width mode, + * which has a DSC overhead of up to ~0.2%, but may not be + * enough for a 1024 width mode where this is ~0.8% (on a 4 + * lane DP link, with 2 DSC slices and 8 bpp color depth). + */ + return fec_enabled ? DP_DSC_FEC_OVERHEAD_FACTOR : 1000000; +} + static int small_joiner_ram_size_bits(struct drm_i915_private *i915) { @@ -2655,8 +2674,9 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, pixel_clock /= pipe_config->splitter.link_count; intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, - pipe_config->port_clock, &pipe_config->dp_m2_n2, - pipe_config->fec_enable); + pipe_config->port_clock, + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m2_n2); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) @@ -2837,8 +2857,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, - &pipe_config->dp_m_n, - pipe_config->fec_enable); + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m_n); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 0258580a6aad..2080575fef69 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -77,6 +77,7 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state); bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); +bool intel_dp_is_uhbr_rate(int rate); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, @@ -137,6 +138,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) } u32 intel_dp_mode_to_fec_clock(u32 mode_clock); +int intel_dp_bw_fec_overhead(bool fec_enabled); bool intel_dp_supports_fec(struct intel_dp *intel_dp, const struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 28db1775d3a5..1f6fbab7d4ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -180,8 +180,8 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, - &crtc_state->dp_m_n, - crtc_state->fec_enable); + intel_dp_bw_fec_overhead(crtc_state->fec_enable), + &crtc_state->dp_m_n); crtc_state->dp_m_n.tu = slots; return 0; @@ -275,8 +275,8 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, - &crtc_state->dp_m_n, - crtc_state->fec_enable); + intel_dp_bw_fec_overhead(crtc_state->fec_enable), + &crtc_state->dp_m_n); crtc_state->dp_m_n.tu = slots; return 0; diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index e6429dfebe15..1d87fbc1e813 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -10,6 +10,7 @@ #include "intel_crtc.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_dp.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" @@ -339,7 +340,9 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc, pipe_config->fdi_lanes = lane; intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, - link_bw, &pipe_config->fdi_m_n, false); + link_bw, + intel_dp_bw_fec_overhead(false), + &pipe_config->fdi_m_n); return 0; } From 4e0837a8d00aa349910a73a6e14102f4c5d81ed5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:08 +0300 Subject: [PATCH 0253/7721] drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm, the BW allocated for an MST stream doesn't take into account the DSC control symbol (EOC) and data alignment overhead on the local (first downstream) MST link (reflected by the data M/N/TU values) and - besides the above overheads - the FEC symbol overhead on 8b/10b remote (after a downstream branch device) MST links. In addition the FEC overhead used on the local link is a fixed amount, which only applies to certain modes, but not enough for all modes; add a code comment clarifying this. Fix the above by calculating the data M/N values with the total BW overhead (not including the SSC overhead, since this isn't enabled by the source device) and using this the PBN and TU values for the local link and PBN for remote links (including SSC, since this is mandatory for links after downstream branch devices). For now keep the current fixed FEC overhead as a minimum, since this is what bspec requires for audio functionality. Calculate the effective link BW in a clearer way, applying the channel coding efficiency based on the coding type. The calculation was correct for 8b/10b, but not for 128b/132b links; this patch leaves the behavior for this unchanged, leaving the fix for a follow-up. v2: - Fix TU size programmed to the HW, making it match the payload size programmed to the payload table. v3: - Add code comment about the connection between the payload's size in the payload table and the corresponding PBN value. (Ville) - Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville) - Add code comment about factors not accounted for by the BW calculation in intel_dp_mst_mode_valid_ctx() (and compute config). (Ville) - Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div. Cc: Ville Syrjälä Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 124 ++++++++++++++++---- 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 1f6fbab7d4ad..9d6b76d1a52a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -67,6 +67,63 @@ static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp return 0; } +static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, + const struct intel_connector *connector, + bool ssc, bool dsc, int bpp) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + unsigned long flags = DRM_DP_BW_OVERHEAD_MST; + int dsc_slice_count = 0; + int overhead; + + flags |= intel_dp_is_uhbr(crtc_state) ? DRM_DP_BW_OVERHEAD_UHBR : 0; + flags |= ssc ? DRM_DP_BW_OVERHEAD_SSC_REF_CLK : 0; + flags |= crtc_state->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0; + + if (dsc) { + flags |= DRM_DP_BW_OVERHEAD_DSC; + /* TODO: add support for bigjoiner */ + dsc_slice_count = intel_dp_dsc_get_slice_count(connector, + adjusted_mode->clock, + adjusted_mode->hdisplay, + false); + } + + overhead = drm_dp_bw_overhead(crtc_state->lane_count, + adjusted_mode->hdisplay, + dsc_slice_count, + to_bpp_x16(bpp), + flags); + + /* + * TODO: clarify whether a minimum required by the fixed FEC overhead + * in the bspec audio programming sequence is required here. + */ + return max(overhead, intel_dp_bw_fec_overhead(crtc_state->fec_enable)); +} + +static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, + const struct intel_connector *connector, + bool ssc, bool dsc, + int bpp, + struct intel_link_m_n *m_n) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + int overhead = intel_dp_mst_bw_overhead(crtc_state, + connector, + ssc, dsc, bpp); + + intel_link_compute_m_n(bpp, crtc_state->lane_count, + adjusted_mode->crtc_clock, + crtc_state->port_clock, + overhead, + m_n); + + m_n->tu = DIV_ROUND_UP_ULL(mul_u32_u32(m_n->data_m, 64), m_n->data_n); +} + static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int max_bpp, @@ -107,14 +164,40 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->lane_count); for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { + struct intel_link_m_n remote_m_n; + int link_bpp; + drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); ret = intel_dp_mst_check_constraints(i915, bpp, adjusted_mode, crtc_state, dsc); if (ret) continue; - crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, - bpp << 4); + link_bpp = dsc ? bpp : + intel_dp_output_bpp(crtc_state->output_format, bpp); + + intel_dp_mst_compute_m_n(crtc_state, connector, false, dsc, link_bpp, + &crtc_state->dp_m_n); + intel_dp_mst_compute_m_n(crtc_state, connector, true, dsc, link_bpp, + &remote_m_n); + + /* + * The TU size programmed to the HW determines which slots in + * an MTP frame are used for this stream, which needs to match + * the payload size programmed to the first downstream branch + * device's payload table. + * + * Note that atm the payload's PBN value DRM core sends via + * the ALLOCATE_PAYLOAD side-band message matches the payload + * size (which it calculates from the PBN value) it programs + * to the first branch device's payload table. The allocation + * in the payload table could be reduced though (to + * crtc_state->dp_m_n.tu), provided that the driver doesn't + * enable SSC on the corresponding link. + */ + drm_WARN_ON(&i915->drm, remote_m_n.tu < crtc_state->dp_m_n.tu); + crtc_state->dp_m_n.tu = remote_m_n.tu; + crtc_state->pbn = remote_m_n.tu * mst_state->pbn_div; slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, @@ -123,6 +206,8 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, return slots; if (slots >= 0) { + drm_WARN_ON(&i915->drm, slots != remote_m_n.tu); + ret = drm_dp_mst_atomic_check(state); /* * If we got slots >= 0 and we can fit those based on check @@ -156,10 +241,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state, struct link_config_limits *limits) { - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; int slots = -EINVAL; - int link_bpp; /* * FIXME: allocate the BW according to link_bpp, which in the case of @@ -174,16 +256,6 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, if (slots < 0) return slots; - link_bpp = intel_dp_output_bpp(crtc_state->output_format, crtc_state->pipe_bpp); - - intel_link_compute_m_n(link_bpp, - crtc_state->lane_count, - adjusted_mode->crtc_clock, - crtc_state->port_clock, - intel_dp_bw_fec_overhead(crtc_state->fec_enable), - &crtc_state->dp_m_n); - crtc_state->dp_m_n.tu = slots; - return 0; } @@ -195,8 +267,6 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; int slots = -EINVAL; int i, num_bpc; u8 dsc_bpc[3] = {}; @@ -271,14 +341,6 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, return slots; } - intel_link_compute_m_n(crtc_state->dsc.compressed_bpp, - crtc_state->lane_count, - adjusted_mode->crtc_clock, - crtc_state->port_clock, - intel_dp_bw_fec_overhead(crtc_state->fec_enable), - &crtc_state->dp_m_n); - crtc_state->dp_m_n.tu = slots; - return 0; } static int intel_dp_mst_update_slots(struct intel_encoder *encoder, @@ -987,6 +1049,18 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, if (ret) return ret; + /* + * TODO: + * - Also check if compression would allow for the mode + * - Calculate the overhead using drm_dp_bw_overhead() / + * drm_dp_bw_channel_coding_efficiency(), similarly to the + * compute config code, as drm_dp_calc_pbn_mode() doesn't + * account with all the overheads. + * - Check here and during compute config the BW reported by + * DFP_Link_Available_Payload_Bandwidth_Number (or the + * corresponding link capabilities of the sink) in case the + * stream is uncompressed for it by the last branch device. + */ if (mode_rate > max_rate || mode->clock > max_dotclk || drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) { *status = MODE_CLOCK_HIGH; From 5d78cd80efdd4ac221a0ccd884082280ddef6128 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:09 +0300 Subject: [PATCH 0254/7721] drm/i915/dp_mst: Add atomic state for all streams on pre-tgl platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an MST stream is modeset, its state must be checked along all the other streams on the same MST link, for instance to resolve a BW overallocation of a non-sink MST port or to make sure that the FEC is enabled/disabled the same way for all these streams. To prepare for that this patch adds all the stream CRTCs to the atomic state and marks them for modeset similarly to tgl+ platforms. (If the state computation doesn't change the state the CRTC is switched back to fastset mode.) So far on tgl+ this was required because all streams in the topology shared the master transcoder. For older platforms this didn't apply but adding all the state is required now on all platforms based on the above. v2: - Add code and commit log comment clarifying the requirements on old/new platforms. (Stan) - Rename the function based on the new semantic. (Ville) Cc: Ville Syrjälä Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-15-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 9d6b76d1a52a..c9faac174aa2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -563,19 +563,23 @@ static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder, * that shares the same MST stream as mode changed, * intel_modeset_pipe_config()+intel_crtc_check_fastset() will take care to do * a fastset when possible. + * + * On TGL+ this is required since each stream go through a master transcoder, + * so if the master transcoder needs modeset, all other streams in the + * topology need a modeset. All platforms need to add the atomic state + * for all streams in the topology, since a modeset on one may require + * changing the MST link BW usage of the others, which in turn needs a + * recomputation of the corresponding CRTC states. */ static int -intel_dp_mst_atomic_master_trans_check(struct intel_connector *connector, - struct intel_atomic_state *state) +intel_dp_mst_atomic_topology_check(struct intel_connector *connector, + struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct drm_connector_list_iter connector_list_iter; struct intel_connector *connector_iter; int ret = 0; - if (DISPLAY_VER(dev_priv) < 12) - return 0; - if (!intel_connector_needs_modeset(state, &connector->base)) return 0; @@ -629,7 +633,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector, if (ret) return ret; - ret = intel_dp_mst_atomic_master_trans_check(intel_connector, state); + ret = intel_dp_mst_atomic_topology_check(intel_connector, state); if (ret) return ret; From 53f468aa90091d3a75ff17b1c2f4874a9b862b38 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:10 +0300 Subject: [PATCH 0255/7721] drm/i915/dp_mst: Program the DSC PPS SDP for each stream Atm the DSC PPS SDP is programmed only if the first stream is compressed and then it's programmed only for the first stream. This left all other compressed streams blank. Program the SDP for all streams. v2: - Rebase on upstream include "intel_vdsc.h" change. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 12 +++++++----- drivers/gpu/drm/i915/display/intel_dp_mst.c | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c75fd00e360a..87fa7f736925 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2505,7 +2505,8 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 6.o Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2643,7 +2644,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 7.l Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2705,10 +2707,10 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_fec(encoder, crtc_state); - if (!is_mst) + if (!is_mst) { intel_ddi_enable_transcoder_clock(encoder, crtc_state); - - intel_dsc_dp_pps_write(encoder, crtc_state); + intel_dsc_dp_pps_write(encoder, crtc_state); + } } static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index c9faac174aa2..5efc3cea73e5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -860,6 +860,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) < 12 || !first_mst_stream) intel_ddi_enable_transcoder_clock(encoder, pipe_config); + intel_dsc_dp_pps_write(&dig_port->base, pipe_config); intel_ddi_set_dp_msa(pipe_config, conn_state); } From aaa80e756e1cd8eb0561d7e244a9937fc23944d2 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:11 +0300 Subject: [PATCH 0256/7721] drm/i915/dp: Make sure the DSC PPS SDP is disabled whenever DSC is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm the DSC PPS SDP will stay enabled after enabling and disabling DSC. This leaves an output blank after switching off DSC on it. Make sure the SDP is disabled for an uncompressed output. v2: - Disable the SDP already during output disabling. (Ville) Cc: Ville Syrjälä Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-17-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 5 ++++- drivers/gpu/drm/i915/display/intel_dp_mst.c | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4dc923bc4c97..8ee2d8915586 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4069,7 +4069,10 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, VIDEO_DIP_ENABLE_SPD_HSW | VIDEO_DIP_ENABLE_DRM_GLK; u32 val = intel_de_read(dev_priv, reg) & ~dip_enable; - /* TODO: Add DSC case (DIP_ENABLE_PPS) */ + /* TODO: Sanitize DSC enabling wrt. intel_dsc_dp_pps_write(). */ + if (!enable && HAS_DSC(dev_priv)) + val &= ~VDIP_ENABLE_PPS; + /* When PSR is enabled, this routine doesn't disable VSC DIP */ if (!crtc_state->has_psr) val &= ~VIDEO_DIP_ENABLE_VSC_HSW; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 5efc3cea73e5..afa6d428cb0c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -746,9 +746,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, * BSpec 4287: disable DIP after the transcoder is disabled and before * the transcoder clock select is set to none. */ - if (last_mst_stream) - intel_dp_set_infoframes(&dig_port->base, false, - old_crtc_state, NULL); + intel_dp_set_infoframes(&dig_port->base, false, + old_crtc_state, NULL); /* * From TGL spec: "If multi-stream slave transcoder: Configure * Transcoder Clock Select to direct no clock to the transcoder" From b40887f8c8a874acad4158adfa2182b73db1fb31 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:12 +0300 Subject: [PATCH 0257/7721] drm/i915/dp_mst: Add missing DSC compression disabling Add the missing DSC compression disabling step for MST streams, similarly to how this is done for SST outputs. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-18-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index afa6d428cb0c..5214cdb049b3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -730,6 +730,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, intel_ddi_disable_transcoder_func(old_crtc_state); + intel_dsc_disable(old_crtc_state); + if (DISPLAY_VER(dev_priv) >= 9) skl_scaler_disable(old_crtc_state); else From 0cfdf662d4ef71569c8b9a628defd51586e102c3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:13 +0300 Subject: [PATCH 0258/7721] drm/i915/dp: Rename intel_ddi_disable_fec_state() to intel_ddi_disable_fec() Rename intel_ddi_disable_fec_state() to intel_ddi_disable_fec(), for symmetry with intel_ddi_enable_fec(). Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-19-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 87fa7f736925..c6cdac30bb4b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2234,8 +2234,8 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder, 0, DP_TP_CTL_FEC_ENABLE); } -static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void intel_ddi_disable_fec(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2868,8 +2868,7 @@ static void disable_ddi_buf(struct intel_encoder *encoder, intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), DP_TP_CTL_ENABLE, 0); - /* Disable FEC in DP Sink */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); if (wait) intel_wait_ddi_buf_idle(dev_priv, port); @@ -2884,7 +2883,7 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, mtl_disable_ddi_buf(encoder, crtc_state); /* 3.f Disable DP_TP_CTL FEC Enable if it is needed */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); } else { disable_ddi_buf(encoder, crtc_state); } From 6e916b35afa8a3729b254cdd839fa12618e8591f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:14 +0300 Subject: [PATCH 0259/7721] drm/i915/dp: Wait for FEC detected status in the sink As required by the DP standard wait for the sink to detect the FEC decode enabling symbol sent by the source. There is a difference between SST and MST when the source enables the FEC encoding: on SST this happens only after enabling the transcoder, whereas on MST it happens already after enabling the transcoder function (before enabling the transcoder). Wait for the detected status at the earliest spot accordingly. v2: - Wait for the FEC detected status on SST after the transcoder is enabled. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-20-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 73 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_ddi.h | 3 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 ++ 3 files changed, 80 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c6cdac30bb4b..c2ca459d9ca1 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -25,6 +25,7 @@ * */ +#include #include #include @@ -2220,6 +2221,74 @@ static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) drm_dbg_kms(&i915->drm, "Failed to set FEC_READY in the sink\n"); + + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, + DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0) + drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n"); +} + +static int read_fec_detected_status(struct drm_dp_aux *aux) +{ + int ret; + u8 status; + + ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); + if (ret < 0) + return ret; + + return status; +} + +static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) +{ + struct drm_i915_private *i915 = to_i915(aux->drm_dev); + int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; + int status; + int err; + + err = readx_poll_timeout(read_fec_detected_status, aux, status, + status & mask || status < 0, + 10000, 200000); + + if (!err && status >= 0) + return; + + if (err == -ETIMEDOUT) + drm_err(&i915->drm, "Timeout waiting for FEC %s to get detected\n", + str_enabled_disabled(enabled)); + else + drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status); +} + +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool enabled) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int ret; + + if (!crtc_state->fec_enable) + return; + + if (enabled) + ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + else + ret = intel_de_wait_for_clear(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + + if (ret) + drm_err(&i915->drm, + "Timeout waiting for FEC live state to get %s\n", + str_enabled_disabled(enabled)); + + /* + * At least the Synoptics MST hub doesn't set the detected flag for + * FEC decoding disabling so skip waiting for that. + */ + if (enabled) + wait_for_fec_detected(&intel_dp->aux, enabled); } static void intel_ddi_enable_fec(struct intel_encoder *encoder, @@ -2887,6 +2956,8 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, } else { disable_ddi_buf(encoder, crtc_state); } + + intel_ddi_wait_for_fec_status(encoder, crtc_state, false); } static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, @@ -3262,6 +3333,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_enable_transcoder(crtc_state); + intel_ddi_wait_for_fec_status(encoder, crtc_state, true); + intel_crtc_vblank_on(crtc_state); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index db845f2aca0c..63853a1f6582 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -62,6 +62,9 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state void intel_ddi_enable_transcoder_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_ddi_disable_transcoder_clock(const struct intel_crtc_state *crtc_state); +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool enabled); void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 5214cdb049b3..4d0827a3cd9b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -878,6 +878,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, struct drm_dp_mst_topology_state *mst_state = drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); enum transcoder trans = pipe_config->cpu_transcoder; + bool first_mst_stream = intel_dp->active_mst_links == 1; drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder); @@ -904,6 +905,9 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, wait_for_act_sent(encoder, pipe_config); + if (first_mst_stream) + intel_ddi_wait_for_fec_status(encoder, pipe_config, true); + drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, drm_atomic_get_mst_payload_state(mst_state, connector->port)); From 8ab5a03643fc529f0e8663bc4d5b43f8f6885922 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:15 +0300 Subject: [PATCH 0260/7721] drm/i915/dp: Disable FEC ready flag in the sink Disable the FEC ready flag in the sink during a disabling modeset. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-21-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c2ca459d9ca1..1abf74af6c5c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2211,18 +2211,21 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel } static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + bool enable) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (!crtc_state->fec_enable) return; - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) - drm_dbg_kms(&i915->drm, - "Failed to set FEC_READY in the sink\n"); + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, + enable ? DP_FEC_READY : 0) <= 0) + drm_dbg_kms(&i915->drm, "Failed to set FEC_READY to %s in the sink\n", + enable ? "enabled" : "disabled"); - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, + if (enable && + drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0) drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n"); } @@ -2541,7 +2544,7 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2692,7 +2695,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2768,7 +2771,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_configure_protocol_converter(intel_dp, crtc_state); intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_start_link_train(intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) && !is_trans_port_sync_mode(crtc_state)) @@ -2997,6 +3000,8 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, intel_disable_ddi_buf(encoder, old_crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, old_crtc_state, false); + /* * From TGL spec: "If single stream or multi-stream master transcoder: * Configure Transcoder Clock select to direct no clock to the From 55eaef164174480df6827edeac15620f3cbcd52b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:16 +0300 Subject: [PATCH 0261/7721] drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK period, presumedly to save BW, which the hub expands before forwarding the stream to the sink. In particular a 4k mode with a standard CVT HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80, 160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard describes the above HBLANK expansion functionality, but it requires enabling this explicitly, whereas these hubs apply the expansion transparently. In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes will work okay until DSC decompression is enabled in the hub for the given sink, but after this the same mode will not work reliably in decompressed mode. In another TBT dock (Thinkpad 40B0) the above modes will not work in uncompressed/18bpp mode (regardless of whether DSC decompression was enabled before or not). As a workaround force enable DSC for such modes. Apply the WA when the HBLANK period is 300ns or below, matching the above tested modes with a 533.25MHz dotclock and maximum 160 HBLANK pixels. OTOH DSC for these modes will only work above a certain compressed bpp threshold which depends on the link rate, so apply this limit as well in the workaround. On platforms, pipe/port configurations where DSC is not supported, for instance on ICL where DSC/MST is still work-in-progress, limit the minimum link bpp to 24. Apply the workaround only for Synaptics hubs which support the HBLANK expansion. v2: - Apply the WA whenever the HBLANK period is 300ns or below. v3: - Clarify in the commit log the failure modes of the different docks. - Handle platforms/pipe/port configurations without DSC support. Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com --- .../drm/i915/display/intel_display_types.h | 2 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 133 +++++++++++++++++- 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 92f06d67fd1e..1ef12f0d571f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -624,6 +624,8 @@ struct intel_connector { struct drm_dp_aux *dsc_decompression_aux; u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; u8 fec_capability; + + u8 dsc_hblank_expansion_quirk:1; } dp; /* Work struct to schedule a uevent on link train failure */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4d0827a3cd9b..4f066a868b9a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -378,8 +378,91 @@ intel_dp_mst_dsc_source_support(const struct intel_crtc_state *crtc_state) return DISPLAY_VER(i915) >= 12 && intel_dsc_source_support(crtc_state); } +static int mode_hblank_period_ns(const struct drm_display_mode *mode) +{ + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(mode->htotal - mode->hdisplay, + NSEC_PER_SEC / 1000), + mode->crtc_clock); +} + +static bool +hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector, + const struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + if (!connector->dp.dsc_hblank_expansion_quirk) + return false; + + if (mode_hblank_period_ns(adjusted_mode) > 300) + return false; + + return true; +} + +static bool +adjust_limits_for_dsc_hblank_expansion_quirk(const struct intel_connector *connector, + const struct intel_crtc_state *crtc_state, + struct link_config_limits *limits, + bool dsc) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int min_bpp_x16 = limits->link.min_bpp_x16; + + if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state)) + return true; + + if (!dsc) { + if (intel_dp_mst_dsc_source_support(crtc_state)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] DSC needed by hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name); + return false; + } + + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to 24 due to hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name); + + if (limits->link.max_bpp_x16 < to_bpp_x16(24)) + return false; + + limits->link.min_bpp_x16 = to_bpp_x16(24); + + return true; + } + + drm_WARN_ON(&i915->drm, limits->min_rate != limits->max_rate); + + if (limits->max_rate < 540000) + min_bpp_x16 = to_bpp_x16(13); + else if (limits->max_rate < 810000) + min_bpp_x16 = to_bpp_x16(10); + + if (limits->link.min_bpp_x16 >= min_bpp_x16) + return true; + + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to " BPP_X16_FMT " in DSC mode due to hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name, + BPP_X16_ARGS(min_bpp_x16)); + + if (limits->link.max_bpp_x16 < min_bpp_x16) + return false; + + limits->link.min_bpp_x16 = min_bpp_x16; + + return true; +} + static bool intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, + const struct intel_connector *connector, struct intel_crtc_state *crtc_state, bool dsc, struct link_config_limits *limits) @@ -407,10 +490,16 @@ intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); - return intel_dp_compute_config_link_bpp_limits(intel_dp, - crtc_state, - dsc, - limits); + if (!intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits)) + return false; + + return adjust_limits_for_dsc_hblank_expansion_quirk(connector, + crtc_state, + limits, + dsc); } static int intel_dp_mst_compute_config(struct intel_encoder *encoder, @@ -420,6 +509,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); struct intel_dp *intel_dp = &intel_mst->primary->dp; + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct link_config_limits limits; @@ -435,6 +526,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, dsc_needed = intel_dp->force_dsc_en || !intel_dp_mst_compute_config_limits(intel_dp, + connector, pipe_config, false, &limits); @@ -460,6 +552,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, return -EINVAL; if (!intel_dp_mst_compute_config_limits(intel_dp, + connector, pipe_config, true, &limits)) @@ -1236,6 +1329,36 @@ intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp, intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], connector); } +static bool detect_dsc_hblank_expansion_quirk(const struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_desc desc; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + + if (!connector->dp.dsc_decompression_aux) + return false; + + if (drm_dp_read_desc(connector->dp.dsc_decompression_aux, + &desc, true) < 0) + return false; + + if (!drm_dp_has_quirk(&desc, + DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC)) + return false; + + if (drm_dp_read_dpcd_caps(connector->dp.dsc_decompression_aux, dpcd) < 0) + return false; + + if (!(dpcd[DP_RECEIVE_PORT_0_CAP_0] & DP_HBLANK_EXPANSION_CAPABLE)) + return false; + + drm_dbg_kms(&i915->drm, + "[CONNECTOR:%d:%s] DSC HBLANK expansion quirk detected\n", + connector->base.base.id, connector->base.name); + + return true; +} + static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop) @@ -1265,6 +1388,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo */ intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); + intel_connector->dp.dsc_hblank_expansion_quirk = + detect_dsc_hblank_expansion_quirk(intel_connector); connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, From 503611c8a08ab660c718c295d26180e585058d95 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:17 +0300 Subject: [PATCH 0262/7721] drm/i915/dp_mst: Enable decompression in the sink from the MST encoder hooks Enable/disable the DSC decompression in the sink/branch from the MST encoder hooks. This prepares for an upcoming patch toggling DSC for each stream as needed, but for now keeps the current behavior, as DSC is only enabled for the first MST stream. v2: - Rebased on latest drm-tip. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 12 ++++++++---- drivers/gpu/drm/i915/display/intel_dp_mst.c | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 1abf74af6c5c..cc2a38fc22d0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2538,7 +2538,9 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link @@ -2689,7 +2691,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link @@ -2769,8 +2772,9 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, - true); + if (!is_mst) + intel_dp_sink_set_decompression_state(intel_dp, crtc_state, + true); intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_start_link_train(intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) && diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4f066a868b9a..eab69f57655d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -776,6 +776,13 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + + if (intel_dp->active_mst_links == 1) /* last stream ? */ + /* + * TODO: disable decompression for all streams/in any MST ports, not + * only in the first downstream branch device. + */ + intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, false); } static void intel_mst_post_disable_dp(struct intel_atomic_state *state, @@ -932,9 +939,15 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); - if (first_mst_stream) + if (first_mst_stream) { + /* + * TODO: enable decompression for all streams/in any MST ports, not + * only in the first downstream branch device. + */ + intel_dp_sink_set_decompression_state(intel_dp, pipe_config, true); dig_port->base.pre_enable(state, &dig_port->base, pipe_config, NULL); + } intel_dp->active_mst_links++; From 7c4631ff6233043b71b68c80f3b9f35510cdda33 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 13:22:18 +0300 Subject: [PATCH 0263/7721] drm/i915/dp: Enable DSC via the connector decompression AUX Enable DSC using the DSC AUX device stored for this purpose in the connector. For clarity add separate functions to enable/disable the decompression, since these sequences will diverge more in follow-up patches that also enable/disable DSC passthrough and on MST do the actual enabling/disabling only for the first/last user of the given AUX device. As a preparation for the latter refcounting change, also pass the atomic state to the functions. While at it set/clear only the DP_DECOMPRESSION_EN flag in the DP_DSC_ENABLE DPCD register, preserving the reserved register bits. Besides preserving the reserved register bits, the behavior stays as before, as DSC is still only enabled for the first MST stream (which a follow-up patch changes, enabling it for all streams). v2: - Add a helper function setting/clearing the decompression flag, preserving the reserved register bits. v3: - Add separate functions to enable/disable decompression and pass the atomic state to these. - Add DocBook for both functions. Reviewed-by: Stanislav Lisovskiy (v2) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-24-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 19 +++-- drivers/gpu/drm/i915/display/intel_dp.c | 90 ++++++++++++++++++--- drivers/gpu/drm/i915/display/intel_dp.h | 9 ++- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 +- 4 files changed, 101 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cc2a38fc22d0..6cec72ac6422 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2539,7 +2539,9 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst) - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit @@ -2692,7 +2694,9 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst) - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link @@ -2773,8 +2777,9 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst) - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, - true); + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_start_link_train(intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) && @@ -3360,6 +3365,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, const struct drm_connector_state *old_conn_state) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_connector *connector = + to_intel_connector(old_conn_state->connector); intel_dp->link_trained = false; @@ -3368,8 +3375,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, intel_psr_disable(intel_dp, old_crtc_state); intel_edp_backlight_off(old_conn_state); /* Disable the decompression in DP Sink */ - intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, - false); + intel_dp_sink_disable_decompression(state, + connector, old_crtc_state); /* Disable Ignore_MSA bit in DP Sink */ intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state, false); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8ee2d8915586..7d098a8c994c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2937,24 +2937,94 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp) intel_dp->downstream_ports[0] & DP_DS_PORT_HPD; } -void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - bool enable) +static int +write_dsc_decompression_flag(struct drm_dp_aux *aux, u8 flag, bool set) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); - int ret; + int err; + u8 val; - if (!crtc_state->dsc.compression_enable) - return; + err = drm_dp_dpcd_readb(aux, DP_DSC_ENABLE, &val); + if (err < 0) + return err; - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE, - enable ? DP_DECOMPRESSION_EN : 0); - if (ret < 0) + if (set) + val |= flag; + else + val &= ~flag; + + return drm_dp_dpcd_writeb(aux, DP_DSC_ENABLE, val); +} + +static void +intel_dp_sink_set_dsc_decompression(struct intel_connector *connector, + bool enable) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + + if (write_dsc_decompression_flag(connector->dp.dsc_decompression_aux, + DP_DECOMPRESSION_EN, enable) < 0) drm_dbg_kms(&i915->drm, "Failed to %s sink decompression state\n", str_enable_disable(enable)); } +/** + * intel_dp_sink_enable_decompression - Enable DSC decompression in sink/last branch device + * @state: atomic state + * @connector: connector to enable the decompression for + * @new_crtc_state: new state for the CRTC driving @connector + * + * Enable the DSC decompression if required in the %DP_DSC_ENABLE DPCD + * register of the appropriate sink/branch device. On SST this is always the + * sink device, whereas on MST based on each device's DSC capabilities it's + * either the last branch device (enabling decompression in it) or both the + * last branch device (enabling passthrough in it) and the sink device + * (enabling decompression in it). + */ +void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *new_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (!new_crtc_state->dsc.compression_enable) + return; + + if (drm_WARN_ON(&i915->drm, + !connector->dp.dsc_decompression_aux)) + return; + + /* TODO: Enable passthrough in the MST last branch device if needed. */ + intel_dp_sink_set_dsc_decompression(connector, true); +} + +/** + * intel_dp_sink_disable_decompression - Disable DSC decompression in sink/last branch device + * @state: atomic state + * @connector: connector to disable the decompression for + * @old_crtc_state: old state for the CRTC driving @connector + * + * Disable the DSC decompression if required in the %DP_DSC_ENABLE DPCD + * register of the appropriate sink/branch device, corresponding to the + * sequence in intel_dp_sink_enable_decompression(). + */ +void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *old_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (!old_crtc_state->dsc.compression_enable) + return; + + if (drm_WARN_ON(&i915->drm, + !connector->dp.dsc_decompression_aux)) + return; + + intel_dp_sink_set_dsc_decompression(connector, false); + /* TODO: Disable passthrough in the MST last branch device if needed. */ +} + static void intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 2080575fef69..7cc23d846dfb 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -57,9 +57,12 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode); void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); -void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - bool enable); +void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *new_crtc_state); +void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *old_crtc_state); void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder); void intel_dp_encoder_flush_work(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index eab69f57655d..bc992e77ffc7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -782,7 +782,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, * TODO: disable decompression for all streams/in any MST ports, not * only in the first downstream branch device. */ - intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, false); + intel_dp_sink_disable_decompression(state, connector, old_crtc_state); } static void intel_mst_post_disable_dp(struct intel_atomic_state *state, @@ -944,7 +944,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, * TODO: enable decompression for all streams/in any MST ports, not * only in the first downstream branch device. */ - intel_dp_sink_set_decompression_state(intel_dp, pipe_config, true); + intel_dp_sink_enable_decompression(state, connector, pipe_config); dig_port->base.pre_enable(state, &dig_port->base, pipe_config, NULL); } From 751dbac1a0235ea7303e5e76fade2762e8298907 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 13:22:19 +0300 Subject: [PATCH 0264/7721] drm/i915/dp_mst: Enable DSC passthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable passing through DSC streams to the sink in last branch devices. v2: - Fix the DPCD register address while setting/clearing the passthrough flag. Reviewed-by: Stanislav Lisovskiy Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-25-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7d098a8c994c..24a3c0c27635 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2968,6 +2968,24 @@ intel_dp_sink_set_dsc_decompression(struct intel_connector *connector, str_enable_disable(enable)); } +static void +intel_dp_sink_set_dsc_passthrough(const struct intel_connector *connector, + bool enable) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_aux *aux = connector->port ? + connector->port->passthrough_aux : NULL; + + if (!aux) + return; + + if (write_dsc_decompression_flag(aux, + DP_DSC_PASSTHROUGH_EN, enable) < 0) + drm_dbg_kms(&i915->drm, + "Failed to %s sink compression passthrough state\n", + str_enable_disable(enable)); +} + /** * intel_dp_sink_enable_decompression - Enable DSC decompression in sink/last branch device * @state: atomic state @@ -2994,7 +3012,7 @@ void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, !connector->dp.dsc_decompression_aux)) return; - /* TODO: Enable passthrough in the MST last branch device if needed. */ + intel_dp_sink_set_dsc_passthrough(connector, true); intel_dp_sink_set_dsc_decompression(connector, true); } @@ -3022,7 +3040,7 @@ void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, return; intel_dp_sink_set_dsc_decompression(connector, false); - /* TODO: Disable passthrough in the MST last branch device if needed. */ + intel_dp_sink_set_dsc_passthrough(connector, false); } static void From b2608c6b3212e4258379c161d8657c526bda902c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:20 +0300 Subject: [PATCH 0265/7721] drm/i915/dp_mst: Enable MST DSC decompression for all streams Enable DSC decompression for all streams. In particular atm if a sink is connected to a last branch device that is downstream of the first branch device connected to the source, decompression is not enabled for it. Similarly it's not enabled if the sink supports this with the last branch device passing through the compressed stream to it. Enable DSC in the above cases as well. Since last branch devices may handle the decompression for multiple ports, toggling DSC needs to be refcounted, add this using the DSC AUX device as a reference. v2: - Fix refcounting, setting/clearing connector->dp.dsc_decompression_enabled always as needed. (Stan) - Make the refcounting more uniform for the SST vs. MST case. - Add state checks for connector->dp.dsc_decompression_enabled and connector crtc. - Sanitize connector DSC decompression state during HW setup. - s/use_count/ref_count/ v3: - Remove stale TODO: comment to set the actual decompression_aux. Cc: Stanislav Lisovskiy Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-6-imre.deak@intel.com --- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 72 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp_mst.c | 24 ++----- .../drm/i915/display/intel_modeset_setup.c | 6 ++ 4 files changed, 82 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 1ef12f0d571f..926bf9c1a3ed 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -626,6 +626,7 @@ struct intel_connector { u8 fec_capability; u8 dsc_hblank_expansion_quirk:1; + u8 dsc_decompression_enabled:1; } dp; /* Work struct to schedule a uevent on link train failure */ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 24a3c0c27635..4ba50e68cb0f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1403,6 +1403,7 @@ static bool intel_dp_supports_dsc(const struct intel_connector *connector, return false; return intel_dsc_source_support(crtc_state) && + connector->dp.dsc_decompression_aux && drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd); } @@ -2986,6 +2987,65 @@ intel_dp_sink_set_dsc_passthrough(const struct intel_connector *connector, str_enable_disable(enable)); } +static int intel_dp_dsc_aux_ref_count(struct intel_atomic_state *state, + const struct intel_connector *connector, + bool for_get_ref) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct drm_connector *_connector_iter; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + int ref_count = 0; + int i; + + /* + * On SST the decompression AUX device won't be shared, each connector + * uses for this its own AUX targeting the sink device. + */ + if (!connector->mst_port) + return connector->dp.dsc_decompression_enabled ? 1 : 0; + + for_each_oldnew_connector_in_state(&state->base, _connector_iter, + old_conn_state, new_conn_state, i) { + const struct intel_connector * + connector_iter = to_intel_connector(_connector_iter); + + if (connector_iter->mst_port != connector->mst_port) + continue; + + if (!connector_iter->dp.dsc_decompression_enabled) + continue; + + drm_WARN_ON(&i915->drm, + (for_get_ref && !new_conn_state->crtc) || + (!for_get_ref && !old_conn_state->crtc)); + + if (connector_iter->dp.dsc_decompression_aux == + connector->dp.dsc_decompression_aux) + ref_count++; + } + + return ref_count; +} + +static bool intel_dp_dsc_aux_get_ref(struct intel_atomic_state *state, + struct intel_connector *connector) +{ + bool ret = intel_dp_dsc_aux_ref_count(state, connector, true) == 0; + + connector->dp.dsc_decompression_enabled = true; + + return ret; +} + +static bool intel_dp_dsc_aux_put_ref(struct intel_atomic_state *state, + struct intel_connector *connector) +{ + connector->dp.dsc_decompression_enabled = false; + + return intel_dp_dsc_aux_ref_count(state, connector, false) == 0; +} + /** * intel_dp_sink_enable_decompression - Enable DSC decompression in sink/last branch device * @state: atomic state @@ -3009,7 +3069,11 @@ void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, return; if (drm_WARN_ON(&i915->drm, - !connector->dp.dsc_decompression_aux)) + !connector->dp.dsc_decompression_aux || + connector->dp.dsc_decompression_enabled)) + return; + + if (!intel_dp_dsc_aux_get_ref(state, connector)) return; intel_dp_sink_set_dsc_passthrough(connector, true); @@ -3036,7 +3100,11 @@ void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, return; if (drm_WARN_ON(&i915->drm, - !connector->dp.dsc_decompression_aux)) + !connector->dp.dsc_decompression_aux || + !connector->dp.dsc_decompression_enabled)) + return; + + if (!intel_dp_dsc_aux_put_ref(state, connector)) return; intel_dp_sink_set_dsc_decompression(connector, false); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index bc992e77ffc7..b3d952bbb3cf 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -777,12 +777,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - if (intel_dp->active_mst_links == 1) /* last stream ? */ - /* - * TODO: disable decompression for all streams/in any MST ports, not - * only in the first downstream branch device. - */ - intel_dp_sink_disable_decompression(state, connector, old_crtc_state); + intel_dp_sink_disable_decompression(state, connector, old_crtc_state); } static void intel_mst_post_disable_dp(struct intel_atomic_state *state, @@ -939,15 +934,11 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); - if (first_mst_stream) { - /* - * TODO: enable decompression for all streams/in any MST ports, not - * only in the first downstream branch device. - */ - intel_dp_sink_enable_decompression(state, connector, pipe_config); + intel_dp_sink_enable_decompression(state, connector, pipe_config); + + if (first_mst_stream) dig_port->base.pre_enable(state, &dig_port->base, pipe_config, NULL); - } intel_dp->active_mst_links++; @@ -1394,12 +1385,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->port = port; drm_dp_mst_get_port_malloc(port); - /* - * TODO: set the AUX for the actual MST port decompressing the stream. - * At the moment the driver only supports enabling this globally in the - * first downstream MST branch, via intel_dp's (root port) AUX. - */ - intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; + intel_connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port); intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); intel_connector->dp.dsc_hblank_expansion_quirk = detect_dsc_hblank_expansion_quirk(intel_connector); diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index b8f43efb0ab5..94eece7f63be 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -318,6 +318,12 @@ static void intel_modeset_update_connector_atomic_state(struct drm_i915_private const struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + if (crtc_state->dsc.compression_enable) { + drm_WARN_ON(&i915->drm, !connector->dp.dsc_decompression_aux); + connector->dp.dsc_decompression_enabled = true; + } else { + connector->dp.dsc_decompression_enabled = false; + } conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3; } } From 1e4bd5c14e4c72fc74a985e05fdbc735d2cf7566 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:21 +0300 Subject: [PATCH 0266/7721] drm/i915: Factor out function to clear pipe update flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor out a helper to clear the pipe update flags, used by a follow-up patch to modeset an MST topology. v2: - Move the intel_crtc_needs_modeset() check to the callers. (Ville) v3 (Ville): - Rename clear_pipe_update_flags_on_modeset_crtc() to intel_crtc_flag_modeset(). - Also set crtc_state->uapi.mode_changed in the function. - Leave out the unrelated change to use intel_modeset_pipes_in_mask_early(). Cc: Ville Syrjälä Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 49 +++++++++----------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3c7ef2cc3b8b..afa5613fd847 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5542,6 +5542,16 @@ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, return 0; } +static void +intel_crtc_flag_modeset(struct intel_crtc_state *crtc_state) +{ + crtc_state->uapi.mode_changed = true; + + crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; +} + /** * intel_modeset_all_pipes_late - force a full modeset on all pipes * @state: intel atomic state @@ -5575,9 +5585,8 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state, if (ret) return ret; - crtc_state->update_pipe = false; - crtc_state->update_m_n = false; - crtc_state->update_lrr = false; + intel_crtc_flag_modeset(crtc_state); + crtc_state->update_planes |= crtc_state->active_planes; crtc_state->async_flip_planes = 0; crtc_state->do_async_flip = false; @@ -5690,17 +5699,17 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta else new_crtc_state->uapi.mode_changed = false; - if (intel_crtc_needs_modeset(new_crtc_state) || - intel_compare_link_m_n(&old_crtc_state->dp_m_n, + if (intel_compare_link_m_n(&old_crtc_state->dp_m_n, &new_crtc_state->dp_m_n)) new_crtc_state->update_m_n = false; - if (intel_crtc_needs_modeset(new_crtc_state) || - (old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && + if ((old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && old_crtc_state->hw.adjusted_mode.crtc_vblank_end == new_crtc_state->hw.adjusted_mode.crtc_vblank_end)) new_crtc_state->update_lrr = false; - if (!intel_crtc_needs_modeset(new_crtc_state)) + if (intel_crtc_needs_modeset(new_crtc_state)) + intel_crtc_flag_modeset(new_crtc_state); + else new_crtc_state->update_pipe = true; } @@ -6475,12 +6484,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_dp_mst_is_slave_trans(new_crtc_state)) { enum transcoder master = new_crtc_state->mst_master_transcoder; - if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_cpu_transcoders_need_modeset(state, BIT(master))) + intel_crtc_flag_modeset(new_crtc_state); } if (is_trans_port_sync_mode(new_crtc_state)) { @@ -6489,21 +6494,13 @@ int intel_atomic_check(struct drm_device *dev, if (new_crtc_state->master_transcoder != INVALID_TRANSCODER) trans |= BIT(new_crtc_state->master_transcoder); - if (intel_cpu_transcoders_need_modeset(state, trans)) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_cpu_transcoders_need_modeset(state, trans)) + intel_crtc_flag_modeset(new_crtc_state); } if (new_crtc_state->bigjoiner_pipes) { - if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) + intel_crtc_flag_modeset(new_crtc_state); } } From e37137380931ae971e0380ba4cea6b16843da953 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:22 +0300 Subject: [PATCH 0267/7721] drm/i915/dp_mst: Force modeset CRTC if DSC toggling requires it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling / disabling DSC decompression in the branch device downstream of the source may reset the whole branch device. To avoid this while the streams are still active, force a modeset on all CRTC/ports connected to this branch device. v2: - Check the CRTC state for each connector in the topology, instead of the CRTC being checked for a modeset requirement. (Ville) - Add DocBook for the new function. v3: - Rebased on a change not to use intel_modeset_pipes_in_mask_early(). Cc: Ville Syrjälä Reviewed-by: Stanislav Lisovskiy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-8-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 3 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 88 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.h | 2 + 3 files changed, 93 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index afa5613fd847..c4cb0e2273a0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6481,6 +6481,9 @@ int intel_atomic_check(struct drm_device *dev, if (!new_crtc_state->hw.enable || intel_crtc_needs_modeset(new_crtc_state)) continue; + if (intel_dp_mst_crtc_needs_modeset(state, crtc)) + intel_crtc_flag_modeset(new_crtc_state); + if (intel_dp_mst_is_slave_trans(new_crtc_state)) { enum transcoder master = new_crtc_state->mst_master_transcoder; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b3d952bbb3cf..079986b09f8b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1628,3 +1628,91 @@ int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, return 0; } + +static struct intel_connector * +get_connector_in_state_for_crtc(struct intel_atomic_state *state, + const struct intel_crtc *crtc) +{ + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_connector *_connector; + int i; + + for_each_oldnew_connector_in_state(&state->base, _connector, + old_conn_state, new_conn_state, i) { + struct intel_connector *connector = + to_intel_connector(_connector); + + if (old_conn_state->crtc == &crtc->base || + new_conn_state->crtc == &crtc->base) + return connector; + } + + return NULL; +} + +/** + * intel_dp_mst_crtc_needs_modeset - check if changes in topology need to modeset the given CRTC + * @state: atomic state + * @crtc: CRTC for which to check the modeset requirement + * + * Check if any change in a MST topology requires a forced modeset on @crtc in + * this topology. One such change is enabling/disabling the DSC decompression + * state in the first branch device's UFP DPCD as required by one CRTC, while + * the other @crtc in the same topology is still active, requiring a full modeset + * on @crtc. + */ +bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_connector *crtc_connector; + const struct drm_connector_state *conn_state; + const struct drm_connector *_connector; + int i; + + if (!intel_crtc_has_type(intel_atomic_get_new_crtc_state(state, crtc), + INTEL_OUTPUT_DP_MST)) + return false; + + crtc_connector = get_connector_in_state_for_crtc(state, crtc); + + if (!crtc_connector) + /* None of the connectors in the topology needs modeset */ + return false; + + for_each_new_connector_in_state(&state->base, _connector, conn_state, i) { + const struct intel_connector *connector = + to_intel_connector(_connector); + const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc_state *old_crtc_state; + struct intel_crtc *crtc_iter; + + if (connector->mst_port != crtc_connector->mst_port || + !conn_state->crtc) + continue; + + crtc_iter = to_intel_crtc(conn_state->crtc); + + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc_iter); + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc_iter); + + if (!intel_crtc_needs_modeset(new_crtc_state)) + continue; + + if (old_crtc_state->dsc.compression_enable == + new_crtc_state->dsc.compression_enable) + continue; + /* + * Toggling the decompression flag because of this stream in + * the first downstream branch device's UFP DPCD may reset the + * whole branch device. To avoid the reset while other streams + * are also active modeset the whole MST topology in this + * case. + */ + if (connector->dp.dsc_decompression_aux == + &connector->mst_port->aux) + return true; + } + + return false; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index f1815bb72267..fc5e85776a85 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -22,5 +22,7 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state); bool intel_dp_mst_source_support(struct intel_dp *intel_dp); int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc); +bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state, + struct intel_crtc *crtc); #endif /* __INTEL_DP_MST_H__ */ From 36f579ffc6921408fd2e466a6930463bac56b926 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:23 +0300 Subject: [PATCH 0268/7721] drm/i915/dp_mst: Improve BW sharing between MST streams At the moment modesetting a stream CRTC will fail if the stream's BW along with the current BW of all the other streams on the same MST link is above the total BW of the MST link. Make the BW sharing more dynamic by trying to reduce the link bpp of one or more streams on the MST link in this case. When selecting a stream to reduce the BW for, take into account which link segment in the MST topology ran out of BW and which streams go through this link segment. For instance with A,B,C streams in the same MST topology A and B may share the BW of a link segment downstream of a branch device, stream C not downstream of the branch device, hence not affecting this BW. If this link segment's BW runs out one or both of stream A/B's BW will be reduced until their total BW is within limits. While reducing the link bpp for a given stream DSC may need to be enabled for it, which requires FEC on the whole MST link. Check for this condition and recompute the state for all streams taking the FEC overhead into account (on 8b/10b links). v2: - Rebase on s/min_bpp_pipes/min_bpp_reached_pipes/ change. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-29-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 5 +- drivers/gpu/drm/i915/display/intel_dp.c | 11 +- drivers/gpu/drm/i915/display/intel_dp.h | 3 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 129 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.h | 3 + drivers/gpu/drm/i915/display/intel_link_bw.c | 16 ++- drivers/gpu/drm/i915/display/intel_link_bw.h | 1 + 7 files changed, 161 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c4cb0e2273a0..bad43626e204 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4698,6 +4698,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (ret) return ret; + crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe); crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe]; if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) { @@ -6524,10 +6525,6 @@ int intel_atomic_check(struct drm_device *dev, goto fail; } - ret = drm_dp_mst_atomic_check(&state->base); - if (ret) - goto fail; - ret = intel_atomic_check_planes(state); if (ret) goto fail; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4ba50e68cb0f..01655adf4c15 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2138,8 +2138,9 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, &pipe_config->hw.adjusted_mode; int ret; - pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && - intel_dp_supports_fec(intel_dp, connector, pipe_config); + pipe_config->fec_enable = pipe_config->fec_enable || + (!intel_dp_is_edp(intel_dp) && + intel_dp_supports_fec(intel_dp, connector, pipe_config)); if (!intel_dp_supports_dsc(connector, pipe_config)) return -EINVAL; @@ -2327,6 +2328,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -2335,6 +2338,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, bool dsc_needed; int ret = 0; + if (pipe_config->fec_enable && + !intel_dp_supports_fec(intel_dp, connector, pipe_config)) + return -EINVAL; + if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_clock)) pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 7cc23d846dfb..91051973be2d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -140,6 +140,9 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) return ~((1 << lane_count) - 1) & 0xf; } +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config); u32 intel_dp_mode_to_fec_clock(u32 mode_clock); int intel_dp_bw_fec_overhead(bool fec_enabled); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 079986b09f8b..b300e4b065df 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -43,6 +43,7 @@ #include "intel_dpio_phy.h" #include "intel_hdcp.h" #include "intel_hotplug.h" +#include "intel_link_bw.h" #include "intel_vdsc.h" #include "skl_scaler.h" @@ -517,6 +518,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, bool dsc_needed; int ret = 0; + if (pipe_config->fec_enable && + !intel_dp_supports_fec(intel_dp, connector, pipe_config)) + return -EINVAL; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; @@ -636,6 +641,130 @@ intel_dp_mst_transcoder_mask(struct intel_atomic_state *state, return transcoders; } +static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct drm_dp_mst_port *parent_port) +{ + const struct intel_digital_connector_state *conn_state; + struct intel_connector *connector; + u8 mask = 0; + int i; + + for_each_new_intel_connector_in_state(state, connector, conn_state, i) { + if (!conn_state->base.crtc) + continue; + + if (&connector->mst_port->mst_mgr != mst_mgr) + continue; + + if (connector->port != parent_port && + !drm_dp_mst_port_downstream_of_parent(mst_mgr, + connector->port, + parent_port)) + continue; + + mask |= BIT(to_intel_crtc(conn_state->base.crtc)->pipe); + } + + return mask; +} + +static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct intel_link_bw_limits *limits) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc *crtc; + u8 mst_pipe_mask; + u8 fec_pipe_mask = 0; + int ret; + + mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL); + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, mst_pipe_mask) { + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + + /* Atomic connector check should've added all the MST CRTCs. */ + if (drm_WARN_ON(&i915->drm, !crtc_state)) + return -EINVAL; + + if (crtc_state->fec_enable) + fec_pipe_mask |= BIT(crtc->pipe); + } + + if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask) + return 0; + + limits->force_fec_pipes |= mst_pipe_mask; + + ret = intel_modeset_pipes_in_mask_early(state, "MST FEC", + mst_pipe_mask); + + return ret ? : -EAGAIN; +} + +static int intel_dp_mst_check_bw(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct drm_dp_mst_topology_state *mst_state, + struct intel_link_bw_limits *limits) +{ + struct drm_dp_mst_port *mst_port; + u8 mst_port_pipes; + int ret; + + ret = drm_dp_mst_atomic_check_mgr(&state->base, mst_mgr, mst_state, &mst_port); + if (ret != -ENOSPC) + return ret; + + mst_port_pipes = get_pipes_downstream_of_mst_port(state, mst_mgr, mst_port); + + ret = intel_link_bw_reduce_bpp(state, limits, + mst_port_pipes, "MST link BW"); + + return ret ? : -EAGAIN; +} + +/** + * intel_dp_mst_atomic_check_link - check all modeset MST link configuration + * @state: intel atomic state + * @limits: link BW limits + * + * Check the link configuration for all modeset MST outputs. If the + * configuration is invalid @limits will be updated if possible to + * reduce the total BW, after which the configuration for all CRTCs in + * @state must be recomputed with the updated @limits. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @limits got updated + * with fallback values with which the configuration of all CRTCs in + * @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; + int ret; + int i; + + for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) { + ret = intel_dp_mst_check_fec_change(state, mgr, limits); + if (ret) + return ret; + + ret = intel_dp_mst_check_bw(state, mgr, mst_state, + limits); + if (ret) + return ret; + } + + return 0; +} + static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index fc5e85776a85..8ca1d599091c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -13,6 +13,7 @@ struct intel_crtc; struct intel_crtc_state; struct intel_digital_port; struct intel_dp; +struct intel_link_bw_limits; int intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port); @@ -22,6 +23,8 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state); bool intel_dp_mst_source_support(struct intel_dp *intel_dp); int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc); +int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits); bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state, struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index c5eb5f242536..390db5c0c24a 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -7,6 +7,7 @@ #include "intel_atomic.h" #include "intel_display_types.h" +#include "intel_dp_mst.h" #include "intel_fdi.h" #include "intel_link_bw.h" @@ -21,6 +22,7 @@ void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_ { enum pipe pipe; + limits->force_fec_pipes = 0; limits->bpp_limit_reached_pipes = 0; for_each_pipe(i915, pipe) limits->max_bpp_x16[pipe] = INT_MAX; @@ -143,6 +145,10 @@ static int check_all_link_config(struct intel_atomic_state *state, /* TODO: Check additional shared display link configurations like MST */ int ret; + ret = intel_dp_mst_atomic_check_link(state, limits); + if (ret) + return ret; + ret = intel_fdi_atomic_check_link(state, limits); if (ret) return ret; @@ -158,6 +164,12 @@ assert_link_limit_change_valid(struct drm_i915_private *i915, bool bpps_changed = false; enum pipe pipe; + /* FEC can't be forced off after it was forced on. */ + if (drm_WARN_ON(&i915->drm, + (old_limits->force_fec_pipes & new_limits->force_fec_pipes) != + old_limits->force_fec_pipes)) + return false; + for_each_pipe(i915, pipe) { /* The bpp limit can only decrease. */ if (drm_WARN_ON(&i915->drm, @@ -172,7 +184,9 @@ assert_link_limit_change_valid(struct drm_i915_private *i915, /* At least one limit must change. */ if (drm_WARN_ON(&i915->drm, - !bpps_changed)) + !bpps_changed && + new_limits->force_fec_pipes == + old_limits->force_fec_pipes)) return false; return true; diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h index e07df22a779a..2cf57307cc24 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.h +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -16,6 +16,7 @@ struct intel_atomic_state; struct intel_crtc_state; struct intel_link_bw_limits { + u8 force_fec_pipes; u8 bpp_limit_reached_pipes; /* in 1/16 bpp units */ int max_bpp_x16[I915_MAX_PIPES]; From 3a5f80e4ce973c6702ec31e5823502860208e030 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 Oct 2023 04:09:24 +0300 Subject: [PATCH 0269/7721] drm/i915/dp_mst: Check BW limitations only after all streams are computed After the previous patch the BW limits on the whole MST topology will be checked after computing the state for all the streams in the topology. Accordingly remove the check during the stream's encoder compute config step, to prevent failing an atomic commit due to a BW limit, if this can be resolved only by reducing the BW of other streams on the same MST link. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-30-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b300e4b065df..35989e287ee0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -209,13 +209,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, if (slots >= 0) { drm_WARN_ON(&i915->drm, slots != remote_m_n.tu); - ret = drm_dp_mst_atomic_check(state); - /* - * If we got slots >= 0 and we can fit those based on check - * then we can exit the loop. Otherwise keep trying. - */ - if (!ret) - break; + break; } } From 99831ab9ce46b1163ac66e92a04614da2da41b1b Mon Sep 17 00:00:00 2001 From: Stanislav Lisovskiy Date: Tue, 24 Oct 2023 04:09:25 +0300 Subject: [PATCH 0270/7721] drm/i915: Query compressed bpp properly using correct DPCD and DP Spec info Currently we seem to be using wrong DPCD register for reading compressed bpps, reading min/max input bpc instead of compressed bpp. Fix that, so that we now apply min/max compressed bpp limitations we get from DP Spec Table 2-157 DP v2.0 and/or correspondent DPCD register DP_DSC_MAX_BITS_PER_PIXEL_LOW/HIGH. This might also allow us to get rid of an ugly compressed bpp recalculation, which we had to add to make some MST hubs usable. v2: - Fix operator precedence v3: - Added debug info about compressed bpps v4: - Don't try to intersect Sink input bpp and compressed bpps. v5: - Decrease step while looking for suitable compressed bpp to accommodate. v6: - Use helper for getting min and max compressed_bpp (Ankit) v7: - Fix checkpatch warning (Ankit) Signed-off-by: Stanislav Lisovskiy Signed-off-by: Ankit Nautiyal Reviewed-by: Ankit Nautiyal Reviewed-by: Arun R Murthy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-31-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 20 +++++--- drivers/gpu/drm/i915/display/intel_dp.h | 4 ++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 54 ++++++++++----------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 01655adf4c15..670cf535e7c6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1811,7 +1811,7 @@ u16 intel_dp_dsc_max_sink_compressed_bppx16(const struct intel_connector *connec return 0; } -static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) +int intel_dp_dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) { /* From Mandatory bit rate range Support Table 2-157 (DP v2.0) */ switch (pipe_config->output_format) { @@ -1828,9 +1828,9 @@ static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) return 0; } -static int dsc_sink_max_compressed_bpp(const struct intel_connector *connector, - struct intel_crtc_state *pipe_config, - int bpc) +int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc) { return intel_dp_dsc_max_sink_compressed_bppx16(connector, pipe_config, bpc) >> 4; @@ -1944,12 +1944,14 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, int dsc_joiner_max_bpp; dsc_src_min_bpp = dsc_src_min_compressed_bpp(); - dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(pipe_config); dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); - dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + pipe_config, + pipe_bpp / 3); dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, adjusted_mode->clock, @@ -2104,12 +2106,14 @@ static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, pipe_config->lane_count = limits->max_lane_count; dsc_src_min_bpp = dsc_src_min_compressed_bpp(); - dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(pipe_config); dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); - dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + pipe_config, + pipe_bpp / 3); dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 91051973be2d..e80da6755419 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -129,6 +129,10 @@ u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, enum intel_output_format output_format, u32 pipe_bpp, u32 timeslots); +int intel_dp_dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config); +int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc); u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay, bool bigjoiner); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 35989e287ee0..107f7418ddc5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -164,6 +164,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->port_clock, crtc_state->lane_count); + drm_dbg_kms(&i915->drm, "Looking for slots in range min bpp %d max bpp %d\n", + min_bpp, max_bpp); + for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { struct intel_link_m_n remote_m_n; int link_bpp; @@ -267,8 +270,7 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, u8 dsc_bpc[3] = {}; int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp; u8 dsc_max_bpc; - bool need_timeslot_recalc = false; - u32 last_compressed_bpp; + int min_compressed_bpp, max_compressed_bpp; /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ if (DISPLAY_VER(i915) >= 12) @@ -304,38 +306,32 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, if (max_bpp > sink_max_bpp) max_bpp = sink_max_bpp; - min_bpp = max(min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); - max_bpp = min(max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + max_compressed_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + crtc_state, + max_bpp / 3); + max_compressed_bpp = min(max_compressed_bpp, + to_bpp_int(limits->link.max_bpp_x16)); - slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp, - min_bpp, limits, - conn_state, 2 * 3, true); + min_compressed_bpp = intel_dp_dsc_sink_min_compressed_bpp(crtc_state); + min_compressed_bpp = max(min_compressed_bpp, + to_bpp_int_roundup(limits->link.min_bpp_x16)); + + drm_dbg_kms(&i915->drm, "DSC Sink supported compressed min bpp %d compressed max bpp %d\n", + min_compressed_bpp, max_compressed_bpp); + + /* Align compressed bpps according to our own constraints */ + max_compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, max_compressed_bpp, + crtc_state->pipe_bpp); + min_compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, min_compressed_bpp, + crtc_state->pipe_bpp); + + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_compressed_bpp, + min_compressed_bpp, limits, + conn_state, 1, true); if (slots < 0) return slots; - last_compressed_bpp = crtc_state->dsc.compressed_bpp; - - crtc_state->dsc.compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, - last_compressed_bpp, - crtc_state->pipe_bpp); - - if (crtc_state->dsc.compressed_bpp != last_compressed_bpp) - need_timeslot_recalc = true; - - /* - * Apparently some MST hubs dislike if vcpi slots are not matching precisely - * the actual compressed bpp we use. - */ - if (need_timeslot_recalc) { - slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, - crtc_state->dsc.compressed_bpp, - crtc_state->dsc.compressed_bpp, - limits, conn_state, 2 * 3, true); - if (slots < 0) - return slots; - } - return 0; } static int intel_dp_mst_update_slots(struct intel_encoder *encoder, From b035224134626f506c1af73ca32bbc64dd2925ad Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Tue, 31 Oct 2023 08:31:53 +0100 Subject: [PATCH 0271/7721] accel/ivpu: Allocate vpu_addr in gem->open() callback Use gem->open() callback to simplify the code and prepare for gem_shmem conversion. It is called during handle creation for a gem object, during prime import and in BO_CREATE ioctl. Hence can be used for vpu_addr allocation. On the way remove unused bo->user_ptr field. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231031073156.1301669-2-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_gem.c | 66 ++++++++++++--------------- drivers/accel/ivpu/ivpu_gem.h | 1 - drivers/accel/ivpu/ivpu_mmu_context.c | 2 + 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index c91852f2edc8..d1077cf90b65 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -281,15 +281,6 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); int ret; - if (!range) { - if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) - range = &vdev->hw->ranges.shave; - else if (bo->flags & DRM_IVPU_BO_DMA_MEM) - range = &vdev->hw->ranges.dma; - else - range = &vdev->hw->ranges.user; - } - mutex_lock(&ctx->lock); ret = ivpu_mmu_context_insert_node_locked(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { @@ -299,6 +290,9 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, } mutex_unlock(&ctx->lock); + if (ret) + ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); + return ret; } @@ -337,9 +331,7 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx) } static struct ivpu_bo * -ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, - u64 size, u32 flags, const struct ivpu_bo_ops *ops, - const struct ivpu_addr_range *range, u64 user_ptr) +ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_bo_ops *ops) { struct ivpu_bo *bo; int ret = 0; @@ -364,7 +356,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, bo->base.funcs = &ivpu_gem_funcs; bo->flags = flags; bo->ops = ops; - bo->user_ptr = user_ptr; if (ops->type == IVPU_BO_TYPE_SHMEM) ret = drm_gem_object_init(&vdev->drm, &bo->base, size); @@ -384,14 +375,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, } } - if (mmu_context) { - ret = ivpu_bo_alloc_vpu_addr(bo, mmu_context, range); - if (ret) { - ivpu_err(vdev, "Failed to add BO to context: %d\n", ret); - goto err_release; - } - } - return bo; err_release: @@ -401,6 +384,23 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, return ERR_PTR(ret); } +static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct ivpu_device *vdev = file_priv->vdev; + struct ivpu_bo *bo = to_ivpu_bo(obj); + struct ivpu_addr_range *range; + + if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) + range = &vdev->hw->ranges.shave; + else if (bo->flags & DRM_IVPU_BO_DMA_MEM) + range = &vdev->hw->ranges.dma; + else + range = &vdev->hw->ranges.user; + + return ivpu_bo_alloc_vpu_addr(bo, &file_priv->ctx, range); +} + static void ivpu_bo_free(struct drm_gem_object *obj) { struct ivpu_bo *bo = to_ivpu_bo(obj); @@ -516,6 +516,7 @@ static const struct vm_operations_struct ivpu_vm_ops = { static const struct drm_gem_object_funcs ivpu_gem_funcs = { .free = ivpu_bo_free, + .open = ivpu_bo_open, .mmap = ivpu_bo_mmap, .vm_ops = &ivpu_vm_ops, .get_sg_table = ivpu_bo_get_sg_table, @@ -537,7 +538,7 @@ ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, &file_priv->ctx, size, args->flags, &shmem_ops, NULL, 0); + bo = ivpu_bo_alloc(vdev, size, args->flags, &shmem_ops); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to create BO: %pe (ctx %u size %llu flags 0x%x)", bo, file_priv->ctx.id, args->size, args->flags); @@ -578,13 +579,17 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla range = &vdev->hw->ranges.global; } - bo = ivpu_bo_alloc(vdev, &vdev->gctx, size, flags, &internal_ops, range, 0); + bo = ivpu_bo_alloc(vdev, size, flags, &internal_ops); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to create BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)", bo, vpu_addr, size, flags); return NULL; } + ret = ivpu_bo_alloc_vpu_addr(bo, &vdev->gctx, range); + if (ret) + goto err_put; + ret = ivpu_bo_pin(bo); if (ret) goto err_put; @@ -631,7 +636,7 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_ get_dma_buf(buf); - bo = ivpu_bo_alloc(vdev, NULL, buf->size, DRM_IVPU_BO_MAPPABLE, &prime_ops, NULL, 0); + bo = ivpu_bo_alloc(vdev, buf->size, DRM_IVPU_BO_MAPPABLE, &prime_ops); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to import BO: %pe (size %lu)", bo, buf->size); goto err_detach; @@ -651,8 +656,6 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct ivpu_file_priv *file_priv = file->driver_priv; - struct ivpu_device *vdev = to_ivpu_device(dev); struct drm_ivpu_bo_info *args = data; struct drm_gem_object *obj; struct ivpu_bo *bo; @@ -665,21 +668,12 @@ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file bo = to_ivpu_bo(obj); mutex_lock(&bo->lock); - - if (!bo->ctx) { - ret = ivpu_bo_alloc_vpu_addr(bo, &file_priv->ctx, NULL); - if (ret) { - ivpu_err(vdev, "Failed to allocate vpu_addr: %d\n", ret); - goto unlock; - } - } - args->flags = bo->flags; args->mmap_offset = drm_vma_node_offset_addr(&obj->vma_node); args->vpu_addr = bo->vpu_addr; args->size = obj->size; -unlock: mutex_unlock(&bo->lock); + drm_gem_object_put(obj); return ret; } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index a0b4d4a32b3b..9bbbcd779265 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -29,7 +29,6 @@ struct ivpu_bo { u64 vpu_addr; u32 handle; u32 flags; - uintptr_t user_ptr; u32 job_status; }; diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 7d8005bc78d2..f6de6a4ea608 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -410,6 +410,8 @@ ivpu_mmu_context_insert_node_locked(struct ivpu_mmu_context *ctx, { lockdep_assert_held(&ctx->lock); + WARN_ON(!range); + if (!ivpu_disable_mmu_cont_pages && size >= IVPU_MMU_CONT_PAGES_SIZE) { if (!drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_CONT_PAGES_SIZE, 0, range->start, range->end, DRM_MM_INSERT_BEST)) From 48aea7f2a2efae6a1bd201061c71a81b3f3b7e55 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Tue, 31 Oct 2023 08:31:54 +0100 Subject: [PATCH 0272/7721] accel/ivpu: Fix locking in ivpu_bo_remove_all_bos_from_context() ivpu_bo_remove_all_bos_from_context() could race with ivpu_bo_free() when prime buffer was closed after vpu device was closed. Move the bo_list from context to vdev and use a dedicated lock to sync it. This list is not modified when BO is added/removed from a context. Also rename ivpu_bo_free_vpu_addr() to ivpu_bo_unbind() because this function does more then just free vpu_addr. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231031073156.1301669-3-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 7 +- drivers/accel/ivpu/ivpu_drv.h | 3 + drivers/accel/ivpu/ivpu_gem.c | 133 +++++++++++++------------- drivers/accel/ivpu/ivpu_gem.h | 6 +- drivers/accel/ivpu/ivpu_mmu.c | 5 +- drivers/accel/ivpu/ivpu_mmu_context.c | 36 ++++--- drivers/accel/ivpu/ivpu_mmu_context.h | 11 +-- 7 files changed, 110 insertions(+), 91 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 60277ff6af69..cc6a4dca2aaa 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -91,8 +91,8 @@ static void file_priv_release(struct kref *ref) ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id); ivpu_cmdq_release_all(file_priv); - ivpu_bo_remove_all_bos_from_context(&file_priv->ctx); ivpu_jsm_context_release(vdev, file_priv->ctx.id); + ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx); ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv); mutex_destroy(&file_priv->lock); @@ -528,6 +528,11 @@ static int ivpu_dev_init(struct ivpu_device *vdev) xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC); xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); + INIT_LIST_HEAD(&vdev->bo_list); + + ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock); + if (ret) + goto err_xa_destroy; ret = ivpu_pci_init(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 79b193ffbc26..e0517ec4133d 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -115,6 +115,9 @@ struct ivpu_device { struct xarray context_xa; struct xa_limit context_xa_limit; + struct mutex bo_list_lock; /* Protects bo_list */ + struct list_head bo_list; + struct xarray submitted_jobs_xa; struct task_struct *job_done_thread; diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index d1077cf90b65..915c53d7bb97 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -26,6 +26,17 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs; static struct lock_class_key prime_bo_lock_class_key; +static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) +{ + if (bo->ctx) + ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", + action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle, + bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); + else + ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", + action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle); +} + static int __must_check prime_alloc_pages_locked(struct ivpu_bo *bo) { /* Pages are managed by the underlying dma-buf */ @@ -245,9 +256,8 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) mutex_lock(&bo->lock); - if (!bo->vpu_addr) { - ivpu_err(vdev, "vpu_addr not set for BO ctx_id: %d handle: %d\n", - bo->ctx->id, bo->handle); + if (!bo->ctx) { + ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle); ret = -EINVAL; goto unlock; } @@ -281,53 +291,68 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); int ret; - mutex_lock(&ctx->lock); - ret = ivpu_mmu_context_insert_node_locked(ctx, range, ivpu_bo_size(bo), &bo->mm_node); + mutex_lock(&bo->lock); + + ret = ivpu_mmu_context_insert_node(ctx, range, bo->base.size, &bo->mm_node); if (!ret) { bo->ctx = ctx; bo->vpu_addr = bo->mm_node.start; - list_add_tail(&bo->ctx_node, &ctx->bo_list); - } - mutex_unlock(&ctx->lock); - - if (ret) + } else { ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); + } + ivpu_dbg_bo(vdev, bo, "alloc"); + + mutex_unlock(&bo->lock); return ret; } -static void ivpu_bo_free_vpu_addr(struct ivpu_bo *bo) +static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - struct ivpu_mmu_context *ctx = bo->ctx; - ivpu_dbg(vdev, BO, "remove from ctx: ctx %d vpu_addr 0x%llx allocated %d mmu_mapped %d\n", - ctx->id, bo->vpu_addr, (bool)bo->sgt, bo->mmu_mapped); + lockdep_assert_held(&bo->lock); - mutex_lock(&bo->lock); + ivpu_dbg_bo(vdev, bo, "unbind"); + /* TODO: dma_unmap */ if (bo->mmu_mapped) { + drm_WARN_ON(&vdev->drm, !bo->ctx); + drm_WARN_ON(&vdev->drm, !bo->vpu_addr); drm_WARN_ON(&vdev->drm, !bo->sgt); - ivpu_mmu_context_unmap_sgt(vdev, ctx, bo->vpu_addr, bo->sgt); + ivpu_mmu_context_unmap_sgt(vdev, bo->ctx, bo->vpu_addr, bo->sgt); bo->mmu_mapped = false; } - mutex_lock(&ctx->lock); - list_del(&bo->ctx_node); - bo->vpu_addr = 0; - bo->ctx = NULL; - ivpu_mmu_context_remove_node_locked(ctx, &bo->mm_node); - mutex_unlock(&ctx->lock); + if (bo->ctx) { + ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node); + bo->vpu_addr = 0; + bo->ctx = NULL; + } +} +static void ivpu_bo_unbind(struct ivpu_bo *bo) +{ + mutex_lock(&bo->lock); + ivpu_bo_unbind_locked(bo); mutex_unlock(&bo->lock); } -void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx) +void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) { - struct ivpu_bo *bo, *tmp; + struct ivpu_bo *bo; - list_for_each_entry_safe(bo, tmp, &ctx->bo_list, ctx_node) - ivpu_bo_free_vpu_addr(bo); + if (drm_WARN_ON(&vdev->drm, !ctx)) + return; + + mutex_lock(&vdev->bo_list_lock); + list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { + mutex_lock(&bo->lock); + if (bo->ctx == ctx) + ivpu_bo_unbind_locked(bo); + mutex_unlock(&bo->lock); + } + mutex_unlock(&vdev->bo_list_lock); } static struct ivpu_bo * @@ -375,6 +400,10 @@ ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_b } } + mutex_lock(&vdev->bo_list_lock); + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); + return bo; err_release: @@ -406,19 +435,16 @@ static void ivpu_bo_free(struct drm_gem_object *obj) struct ivpu_bo *bo = to_ivpu_bo(obj); struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - if (bo->ctx) - ivpu_dbg(vdev, BO, "free: ctx %d vpu_addr 0x%llx allocated %d mmu_mapped %d\n", - bo->ctx->id, bo->vpu_addr, (bool)bo->sgt, bo->mmu_mapped); - else - ivpu_dbg(vdev, BO, "free: ctx (released) allocated %d mmu_mapped %d\n", - (bool)bo->sgt, bo->mmu_mapped); + mutex_lock(&vdev->bo_list_lock); + list_del(&bo->bo_list_node); + mutex_unlock(&vdev->bo_list_lock); drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); - vunmap(bo->kvaddr); + ivpu_dbg_bo(vdev, bo, "free"); - if (bo->ctx) - ivpu_bo_free_vpu_addr(bo); + ivpu_bo_unbind(bo); + vunmap(bo->kvaddr); if (bo->sgt) ivpu_bo_unmap_and_free_pages(bo); @@ -435,10 +461,6 @@ static void ivpu_bo_free(struct drm_gem_object *obj) static int ivpu_bo_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { struct ivpu_bo *bo = to_ivpu_bo(obj); - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - - ivpu_dbg(vdev, BO, "mmap: ctx %u handle %u vpu_addr 0x%llx size %zu type %s", - bo->ctx->id, bo->handle, bo->vpu_addr, ivpu_bo_size(bo), bo->ops->name); if (obj->import_attach) { /* Drop the reference drm_gem_mmap_obj() acquired.*/ @@ -553,9 +575,6 @@ ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) drm_gem_object_put(&bo->base); - ivpu_dbg(vdev, BO, "alloc shmem: ctx %u vpu_addr 0x%llx size %zu flags 0x%x\n", - file_priv->ctx.id, bo->vpu_addr, ivpu_bo_size(bo), bo->flags); - return ret; } @@ -609,9 +628,6 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla goto err_put; } - ivpu_dbg(vdev, BO, "alloc internal: ctx 0 vpu_addr 0x%llx size %zu flags 0x%x\n", - bo->vpu_addr, ivpu_bo_size(bo), flags); - return bo; err_put: @@ -708,41 +724,30 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) { unsigned long dma_refcount = 0; + mutex_lock(&bo->lock); + if (bo->base.dma_buf && bo->base.dma_buf->file) dma_refcount = atomic_long_read(&bo->base.dma_buf->file->f_count); drm_printf(p, "%5u %6d %16llx %10lu %10u %12lu %14s\n", - bo->ctx->id, bo->handle, bo->vpu_addr, ivpu_bo_size(bo), + bo->ctx ? bo->ctx->id : -1, bo->handle, bo->vpu_addr, bo->base.size, kref_read(&bo->base.refcount), dma_refcount, bo->ops->name); + + mutex_unlock(&bo->lock); } void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) { struct ivpu_device *vdev = to_ivpu_device(dev); - struct ivpu_file_priv *file_priv; - unsigned long ctx_id; struct ivpu_bo *bo; drm_printf(p, "%5s %6s %16s %10s %10s %12s %14s\n", "ctx", "handle", "vpu_addr", "size", "refcount", "dma_refcount", "type"); - mutex_lock(&vdev->gctx.lock); - list_for_each_entry(bo, &vdev->gctx.bo_list, ctx_node) + mutex_lock(&vdev->bo_list_lock); + list_for_each_entry(bo, &vdev->bo_list, bo_list_node) ivpu_bo_print_info(bo, p); - mutex_unlock(&vdev->gctx.lock); - - xa_for_each(&vdev->context_xa, ctx_id, file_priv) { - file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id); - if (!file_priv) - continue; - - mutex_lock(&file_priv->ctx.lock); - list_for_each_entry(bo, &file_priv->ctx.bo_list, ctx_node) - ivpu_bo_print_info(bo, p); - mutex_unlock(&file_priv->ctx.lock); - - ivpu_file_priv_put(&file_priv); - } + mutex_unlock(&vdev->bo_list_lock); } void ivpu_bo_list_print(struct drm_device *dev) diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 9bbbcd779265..214d8fd14310 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -17,10 +17,10 @@ struct ivpu_bo { const struct ivpu_bo_ops *ops; struct ivpu_mmu_context *ctx; - struct list_head ctx_node; + struct list_head bo_list_node; struct drm_mm_node mm_node; - struct mutex lock; /* Protects: pages, sgt, mmu_mapped */ + struct mutex lock; /* Protects: pages, sgt, ctx, mmu_mapped, vpu_addr */ struct sg_table *sgt; struct page **pages; bool mmu_mapped; @@ -48,7 +48,7 @@ struct ivpu_bo_ops { }; int ivpu_bo_pin(struct ivpu_bo *bo); -void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx); +void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p); void ivpu_bo_list_print(struct drm_device *dev); diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index b46f3743c0e7..2228c44b115f 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -775,9 +775,12 @@ int ivpu_mmu_init(struct ivpu_device *vdev) ivpu_dbg(vdev, MMU, "Init..\n"); - drmm_mutex_init(&vdev->drm, &mmu->lock); ivpu_mmu_config_check(vdev); + ret = drmm_mutex_init(&vdev->drm, &mmu->lock); + if (ret) + return ret; + ret = ivpu_mmu_structs_alloc(vdev); if (ret) return ret; diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index f6de6a4ea608..122c90fecf66 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -335,6 +335,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 prot; u64 i; + if (drm_WARN_ON(&vdev->drm, !ctx)) + return -EINVAL; + if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) return -EINVAL; /* @@ -382,8 +385,8 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct int ret; u64 i; - if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) - ivpu_warn(vdev, "Unaligned vpu_addr: 0x%llx\n", vpu_addr); + if (drm_WARN_ON(&vdev->drm, !ctx)) + return; mutex_lock(&ctx->lock); @@ -404,30 +407,34 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct } int -ivpu_mmu_context_insert_node_locked(struct ivpu_mmu_context *ctx, - const struct ivpu_addr_range *range, - u64 size, struct drm_mm_node *node) +ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range, + u64 size, struct drm_mm_node *node) { - lockdep_assert_held(&ctx->lock); + int ret; WARN_ON(!range); + mutex_lock(&ctx->lock); if (!ivpu_disable_mmu_cont_pages && size >= IVPU_MMU_CONT_PAGES_SIZE) { - if (!drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_CONT_PAGES_SIZE, 0, - range->start, range->end, DRM_MM_INSERT_BEST)) - return 0; + ret = drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_CONT_PAGES_SIZE, 0, + range->start, range->end, DRM_MM_INSERT_BEST); + if (!ret) + goto unlock; } - return drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_PAGE_SIZE, 0, - range->start, range->end, DRM_MM_INSERT_BEST); + ret = drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_PAGE_SIZE, 0, + range->start, range->end, DRM_MM_INSERT_BEST); +unlock: + mutex_unlock(&ctx->lock); + return ret; } void -ivpu_mmu_context_remove_node_locked(struct ivpu_mmu_context *ctx, struct drm_mm_node *node) +ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *node) { - lockdep_assert_held(&ctx->lock); - + mutex_lock(&ctx->lock); drm_mm_remove_node(node); + mutex_unlock(&ctx->lock); } static int @@ -437,7 +444,6 @@ ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u3 int ret; mutex_init(&ctx->lock); - INIT_LIST_HEAD(&ctx->bo_list); ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable); if (ret) { diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h index f15d8c630d8a..535db3a1fc74 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.h +++ b/drivers/accel/ivpu/ivpu_mmu_context.h @@ -23,10 +23,9 @@ struct ivpu_mmu_pgtable { }; struct ivpu_mmu_context { - struct mutex lock; /* protects: mm, pgtable, bo_list */ + struct mutex lock; /* Protects: mm, pgtable */ struct drm_mm mm; struct ivpu_mmu_pgtable pgtable; - struct list_head bo_list; u32 id; }; @@ -39,11 +38,9 @@ int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid); -int ivpu_mmu_context_insert_node_locked(struct ivpu_mmu_context *ctx, - const struct ivpu_addr_range *range, - u64 size, struct drm_mm_node *node); -void ivpu_mmu_context_remove_node_locked(struct ivpu_mmu_context *ctx, - struct drm_mm_node *node); +int ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range, + u64 size, struct drm_mm_node *node); +void ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *node); int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr, struct sg_table *sgt, bool llc_coherent); From 48d45fac3940347becd290b96b2fc6d5ad8171f7 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Tue, 31 Oct 2023 08:31:55 +0100 Subject: [PATCH 0273/7721] accel/ivpu: Remove support for uncached buffers Usages of DRM_IVPU_BO_UNCACHED should be replaced by DRM_IVPU_BO_WC. There is no functional benefit from DRM_IVPU_BO_UNCACHED if these buffers are never mapped to host VM. This allows to cut the buffer handling code in the kernel driver by half. Usage of DRM_IVPU_BO_UNCACHED buffers was removed from user-space driver and will not be part of first UMD release. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231031073156.1301669-4-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_fw.c | 2 +- drivers/accel/ivpu/ivpu_gem.c | 3 --- include/uapi/drm/ivpu_accel.h | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 3fd74cd4205f..3d0c18d68f6c 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -286,7 +286,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (fw->shave_nn_size) { fw->mem_shave_nn = ivpu_bo_alloc_internal(vdev, vdev->hw->ranges.shave.start, - fw->shave_nn_size, DRM_IVPU_BO_UNCACHED); + fw->shave_nn_size, DRM_IVPU_BO_WC); if (!fw->mem_shave_nn) { ivpu_err(vdev, "Failed to allocate shavenn buffer\n"); ret = -ENOMEM; diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 915c53d7bb97..2a91eb1e3627 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -89,8 +89,6 @@ static int __must_check shmem_alloc_pages_locked(struct ivpu_bo *bo) if (bo->flags & DRM_IVPU_BO_WC) set_pages_array_wc(pages, npages); - else if (bo->flags & DRM_IVPU_BO_UNCACHED) - set_pages_array_uc(pages, npages); bo->pages = pages; return 0; @@ -366,7 +364,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_b switch (flags & DRM_IVPU_BO_CACHE_MASK) { case DRM_IVPU_BO_CACHED: - case DRM_IVPU_BO_UNCACHED: case DRM_IVPU_BO_WC: break; default: diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h index 262db0c3beee..de1944e42c65 100644 --- a/include/uapi/drm/ivpu_accel.h +++ b/include/uapi/drm/ivpu_accel.h @@ -196,7 +196,7 @@ struct drm_ivpu_bo_create { * * %DRM_IVPU_BO_UNCACHED: * - * Allocated BO will not be cached on host side nor snooped on the VPU side. + * Not supported. Use DRM_IVPU_BO_WC instead. * * %DRM_IVPU_BO_WC: * From 8d88e4cdce4f5c56de55174a4d32ea9c06f7fa66 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Tue, 31 Oct 2023 08:31:56 +0100 Subject: [PATCH 0274/7721] accel/ivpu: Use GEM shmem helper for all buffers Use struct drm_gem_shmem_object as a base for struct ivpu_bo. This cuts by 50% the buffer management code. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231031073156.1301669-5-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/Kconfig | 2 +- drivers/accel/ivpu/ivpu_drv.c | 6 +- drivers/accel/ivpu/ivpu_gem.c | 530 ++++++++-------------------------- drivers/accel/ivpu/ivpu_gem.h | 70 +---- drivers/accel/ivpu/ivpu_job.c | 8 +- 5 files changed, 150 insertions(+), 466 deletions(-) diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 82749e0da524..682c53245286 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -6,7 +6,7 @@ config DRM_ACCEL_IVPU depends on X86_64 && !UML depends on PCI && PCI_MSI select FW_LOADER - select SHMEM + select DRM_GEM_SHMEM_HELPER select GENERIC_ALLOCATOR help Choose this option if you have a system with an 14th generation diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index cc6a4dca2aaa..51fa60b6254c 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -360,7 +360,7 @@ int ivpu_boot(struct ivpu_device *vdev) int ret; /* Update boot params located at first 4KB of FW memory */ - ivpu_fw_boot_params_setup(vdev, vdev->fw->mem->kvaddr); + ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem)); ret = ivpu_hw_boot_fw(vdev); if (ret) { @@ -409,7 +409,9 @@ static const struct drm_driver driver = { .open = ivpu_open, .postclose = ivpu_postclose, - .gem_prime_import = ivpu_gem_prime_import, + + .gem_create_object = ivpu_gem_create_object, + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, .ioctls = ivpu_drm_ioctls, .num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls), diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 2a91eb1e3627..1dda4f38ea25 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -20,224 +20,18 @@ #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" -MODULE_IMPORT_NS(DMA_BUF); - static const struct drm_gem_object_funcs ivpu_gem_funcs; -static struct lock_class_key prime_bo_lock_class_key; - static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) { if (bo->ctx) ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", - action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle, - bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); + action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, + bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); else ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", - action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle); -} - -static int __must_check prime_alloc_pages_locked(struct ivpu_bo *bo) -{ - /* Pages are managed by the underlying dma-buf */ - return 0; -} - -static void prime_free_pages_locked(struct ivpu_bo *bo) -{ - /* Pages are managed by the underlying dma-buf */ -} - -static int prime_map_pages_locked(struct ivpu_bo *bo) -{ - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - struct sg_table *sgt; - - sgt = dma_buf_map_attachment_unlocked(bo->base.import_attach, DMA_BIDIRECTIONAL); - if (IS_ERR(sgt)) { - ivpu_err(vdev, "Failed to map attachment: %ld\n", PTR_ERR(sgt)); - return PTR_ERR(sgt); - } - - bo->sgt = sgt; - return 0; -} - -static void prime_unmap_pages_locked(struct ivpu_bo *bo) -{ - dma_buf_unmap_attachment_unlocked(bo->base.import_attach, bo->sgt, DMA_BIDIRECTIONAL); - bo->sgt = NULL; -} - -static const struct ivpu_bo_ops prime_ops = { - .type = IVPU_BO_TYPE_PRIME, - .name = "prime", - .alloc_pages = prime_alloc_pages_locked, - .free_pages = prime_free_pages_locked, - .map_pages = prime_map_pages_locked, - .unmap_pages = prime_unmap_pages_locked, -}; - -static int __must_check shmem_alloc_pages_locked(struct ivpu_bo *bo) -{ - int npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - struct page **pages; - - pages = drm_gem_get_pages(&bo->base); - if (IS_ERR(pages)) - return PTR_ERR(pages); - - if (bo->flags & DRM_IVPU_BO_WC) - set_pages_array_wc(pages, npages); - - bo->pages = pages; - return 0; -} - -static void shmem_free_pages_locked(struct ivpu_bo *bo) -{ - if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) - set_pages_array_wb(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - drm_gem_put_pages(&bo->base, bo->pages, true, false); - bo->pages = NULL; -} - -static int ivpu_bo_map_pages_locked(struct ivpu_bo *bo) -{ - int npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - struct sg_table *sgt; - int ret; - - sgt = drm_prime_pages_to_sg(&vdev->drm, bo->pages, npages); - if (IS_ERR(sgt)) { - ivpu_err(vdev, "Failed to allocate sgtable\n"); - return PTR_ERR(sgt); - } - - ret = dma_map_sgtable(vdev->drm.dev, sgt, DMA_BIDIRECTIONAL, 0); - if (ret) { - ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); - goto err_free_sgt; - } - - bo->sgt = sgt; - return 0; - -err_free_sgt: - kfree(sgt); - return ret; -} - -static void ivpu_bo_unmap_pages_locked(struct ivpu_bo *bo) -{ - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - - dma_unmap_sgtable(vdev->drm.dev, bo->sgt, DMA_BIDIRECTIONAL, 0); - sg_free_table(bo->sgt); - kfree(bo->sgt); - bo->sgt = NULL; -} - -static const struct ivpu_bo_ops shmem_ops = { - .type = IVPU_BO_TYPE_SHMEM, - .name = "shmem", - .alloc_pages = shmem_alloc_pages_locked, - .free_pages = shmem_free_pages_locked, - .map_pages = ivpu_bo_map_pages_locked, - .unmap_pages = ivpu_bo_unmap_pages_locked, -}; - -static int __must_check internal_alloc_pages_locked(struct ivpu_bo *bo) -{ - unsigned int i, npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - struct page **pages; - int ret; - - pages = kvmalloc_array(npages, sizeof(*bo->pages), GFP_KERNEL); - if (!pages) - return -ENOMEM; - - for (i = 0; i < npages; i++) { - pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); - if (!pages[i]) { - ret = -ENOMEM; - goto err_free_pages; - } - cond_resched(); - } - - bo->pages = pages; - return 0; - -err_free_pages: - while (i--) - put_page(pages[i]); - kvfree(pages); - return ret; -} - -static void internal_free_pages_locked(struct ivpu_bo *bo) -{ - unsigned int i, npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - - if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) - set_pages_array_wb(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - for (i = 0; i < npages; i++) - put_page(bo->pages[i]); - - kvfree(bo->pages); - bo->pages = NULL; -} - -static const struct ivpu_bo_ops internal_ops = { - .type = IVPU_BO_TYPE_INTERNAL, - .name = "internal", - .alloc_pages = internal_alloc_pages_locked, - .free_pages = internal_free_pages_locked, - .map_pages = ivpu_bo_map_pages_locked, - .unmap_pages = ivpu_bo_unmap_pages_locked, -}; - -static int __must_check ivpu_bo_alloc_and_map_pages_locked(struct ivpu_bo *bo) -{ - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - int ret; - - lockdep_assert_held(&bo->lock); - drm_WARN_ON(&vdev->drm, bo->sgt); - - ret = bo->ops->alloc_pages(bo); - if (ret) { - ivpu_err(vdev, "Failed to allocate pages for BO: %d", ret); - return ret; - } - - ret = bo->ops->map_pages(bo); - if (ret) { - ivpu_err(vdev, "Failed to map pages for BO: %d", ret); - goto err_free_pages; - } - return ret; - -err_free_pages: - bo->ops->free_pages(bo); - return ret; -} - -static void ivpu_bo_unmap_and_free_pages(struct ivpu_bo *bo) -{ - mutex_lock(&bo->lock); - - WARN_ON(!bo->sgt); - bo->ops->unmap_pages(bo); - WARN_ON(bo->sgt); - bo->ops->free_pages(bo); - WARN_ON(bo->pages); - - mutex_unlock(&bo->lock); + action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, + bo->handle); } /* @@ -254,20 +48,24 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) mutex_lock(&bo->lock); + ivpu_dbg_bo(vdev, bo, "pin"); + if (!bo->ctx) { ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle); ret = -EINVAL; goto unlock; } - if (!bo->sgt) { - ret = ivpu_bo_alloc_and_map_pages_locked(bo); - if (ret) - goto unlock; - } - if (!bo->mmu_mapped) { - ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, bo->sgt, + struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); + + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); + goto unlock; + } + + ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt, ivpu_bo_is_snooped(bo)); if (ret) { ivpu_err(vdev, "Failed to map BO in MMU: %d\n", ret); @@ -291,13 +89,14 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, mutex_lock(&bo->lock); - ret = ivpu_mmu_context_insert_node(ctx, range, bo->base.size, &bo->mm_node); + ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { bo->ctx = ctx; bo->vpu_addr = bo->mm_node.start; } else { ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); } + ivpu_dbg_bo(vdev, bo, "alloc"); mutex_unlock(&bo->lock); @@ -314,11 +113,12 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) ivpu_dbg_bo(vdev, bo, "unbind"); /* TODO: dma_unmap */ + if (bo->mmu_mapped) { drm_WARN_ON(&vdev->drm, !bo->ctx); drm_WARN_ON(&vdev->drm, !bo->vpu_addr); - drm_WARN_ON(&vdev->drm, !bo->sgt); - ivpu_mmu_context_unmap_sgt(vdev, bo->ctx, bo->vpu_addr, bo->sgt); + drm_WARN_ON(&vdev->drm, !bo->base.sgt); + ivpu_mmu_context_unmap_sgt(vdev, bo->ctx, bo->vpu_addr, bo->base.sgt); bo->mmu_mapped = false; } @@ -353,15 +153,32 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m mutex_unlock(&vdev->bo_list_lock); } -static struct ivpu_bo * -ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_bo_ops *ops) +struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size) { struct ivpu_bo *bo; - int ret = 0; - if (drm_WARN_ON(&vdev->drm, size == 0 || !PAGE_ALIGNED(size))) + if (size == 0 || !PAGE_ALIGNED(size)) return ERR_PTR(-EINVAL); + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + if (!bo) + return ERR_PTR(-ENOMEM); + + bo->base.base.funcs = &ivpu_gem_funcs; + bo->base.pages_mark_dirty_on_put = true; /* VPU can dirty a BO anytime */ + + INIT_LIST_HEAD(&bo->bo_list_node); + mutex_init(&bo->lock); + + return &bo->base.base; +} + +static struct ivpu_bo * +ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags) +{ + struct drm_gem_shmem_object *shmem; + struct ivpu_bo *bo; + switch (flags & DRM_IVPU_BO_CACHE_MASK) { case DRM_IVPU_BO_CACHED: case DRM_IVPU_BO_WC: @@ -370,44 +187,22 @@ ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_b return ERR_PTR(-EINVAL); } - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - if (!bo) - return ERR_PTR(-ENOMEM); + shmem = drm_gem_shmem_create(&vdev->drm, size); + if (IS_ERR(shmem)) + return ERR_CAST(shmem); - mutex_init(&bo->lock); - bo->base.funcs = &ivpu_gem_funcs; + bo = to_ivpu_bo(&shmem->base); + bo->base.map_wc = flags & DRM_IVPU_BO_WC; bo->flags = flags; - bo->ops = ops; - - if (ops->type == IVPU_BO_TYPE_SHMEM) - ret = drm_gem_object_init(&vdev->drm, &bo->base, size); - else - drm_gem_private_object_init(&vdev->drm, &bo->base, size); - - if (ret) { - ivpu_err(vdev, "Failed to initialize drm object\n"); - goto err_free; - } - - if (flags & DRM_IVPU_BO_MAPPABLE) { - ret = drm_gem_create_mmap_offset(&bo->base); - if (ret) { - ivpu_err(vdev, "Failed to allocate mmap offset\n"); - goto err_release; - } - } mutex_lock(&vdev->bo_list_lock); list_add_tail(&bo->bo_list_node, &vdev->bo_list); mutex_unlock(&vdev->bo_list_lock); - return bo; + ivpu_dbg(vdev, BO, "create: vpu_addr 0x%llx size %zu flags 0x%x\n", + bo->vpu_addr, bo->base.base.size, flags); -err_release: - drm_gem_object_release(&bo->base); -err_free: - kfree(bo); - return ERR_PTR(ret); + return bo; } static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) @@ -429,8 +224,8 @@ static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) static void ivpu_bo_free(struct drm_gem_object *obj) { + struct ivpu_device *vdev = to_ivpu_device(obj->dev); struct ivpu_bo *bo = to_ivpu_bo(obj); - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); mutex_lock(&vdev->bo_list_lock); list_del(&bo->bo_list_node); @@ -441,108 +236,64 @@ static void ivpu_bo_free(struct drm_gem_object *obj) ivpu_dbg_bo(vdev, bo, "free"); ivpu_bo_unbind(bo); - vunmap(bo->kvaddr); - - if (bo->sgt) - ivpu_bo_unmap_and_free_pages(bo); - - if (bo->base.import_attach) - drm_prime_gem_destroy(&bo->base, bo->sgt); - - drm_gem_object_release(&bo->base); - mutex_destroy(&bo->lock); - kfree(bo); + + drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1); + drm_gem_shmem_free(&bo->base); } -static int ivpu_bo_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -{ - struct ivpu_bo *bo = to_ivpu_bo(obj); - - if (obj->import_attach) { - /* Drop the reference drm_gem_mmap_obj() acquired.*/ - drm_gem_object_put(obj); - vma->vm_private_data = NULL; - return dma_buf_mmap(obj->dma_buf, vma, 0); - } - - vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND); - vma->vm_page_prot = ivpu_bo_pgprot(bo, vm_get_page_prot(vma->vm_flags)); - - return 0; -} - -static struct sg_table *ivpu_bo_get_sg_table(struct drm_gem_object *obj) -{ - struct ivpu_bo *bo = to_ivpu_bo(obj); - loff_t npages = obj->size >> PAGE_SHIFT; - int ret = 0; - - mutex_lock(&bo->lock); - - if (!bo->sgt) - ret = ivpu_bo_alloc_and_map_pages_locked(bo); - - mutex_unlock(&bo->lock); - - if (ret) - return ERR_PTR(ret); - - return drm_prime_pages_to_sg(obj->dev, bo->pages, npages); -} - -static vm_fault_t ivpu_vm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_gem_object *obj = vma->vm_private_data; - struct ivpu_bo *bo = to_ivpu_bo(obj); - loff_t npages = obj->size >> PAGE_SHIFT; - pgoff_t page_offset; - struct page *page; - vm_fault_t ret; - int err; - - mutex_lock(&bo->lock); - - if (!bo->sgt) { - err = ivpu_bo_alloc_and_map_pages_locked(bo); - if (err) { - ret = vmf_error(err); - goto unlock; - } - } - - /* We don't use vmf->pgoff since that has the fake offset */ - page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; - if (page_offset >= npages) { - ret = VM_FAULT_SIGBUS; - } else { - page = bo->pages[page_offset]; - ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page)); - } - -unlock: - mutex_unlock(&bo->lock); - - return ret; -} - -static const struct vm_operations_struct ivpu_vm_ops = { - .fault = ivpu_vm_fault, - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, +static const struct dma_buf_ops ivpu_bo_dmabuf_ops = { + .cache_sgt_mapping = true, + .attach = drm_gem_map_attach, + .detach = drm_gem_map_detach, + .map_dma_buf = drm_gem_map_dma_buf, + .unmap_dma_buf = drm_gem_unmap_dma_buf, + .release = drm_gem_dmabuf_release, + .mmap = drm_gem_dmabuf_mmap, + .vmap = drm_gem_dmabuf_vmap, + .vunmap = drm_gem_dmabuf_vunmap, }; +static struct dma_buf *ivpu_bo_export(struct drm_gem_object *obj, int flags) +{ + struct drm_device *dev = obj->dev; + struct dma_buf_export_info exp_info = { + .exp_name = KBUILD_MODNAME, + .owner = dev->driver->fops->owner, + .ops = &ivpu_bo_dmabuf_ops, + .size = obj->size, + .flags = flags, + .priv = obj, + .resv = obj->resv, + }; + void *sgt; + + /* + * Make sure that pages are allocated and dma-mapped before exporting the bo. + * DMA-mapping is required if the bo will be imported to the same device. + */ + sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(obj)); + if (IS_ERR(sgt)) + return sgt; + + return drm_gem_dmabuf_export(dev, &exp_info); +} + static const struct drm_gem_object_funcs ivpu_gem_funcs = { .free = ivpu_bo_free, .open = ivpu_bo_open, - .mmap = ivpu_bo_mmap, - .vm_ops = &ivpu_vm_ops, - .get_sg_table = ivpu_bo_get_sg_table, + .export = ivpu_bo_export, + .print_info = drm_gem_shmem_object_print_info, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = drm_gem_shmem_object_mmap, + .vm_ops = &drm_gem_shmem_vm_ops, }; -int -ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct ivpu_file_priv *file_priv = file->driver_priv; struct ivpu_device *vdev = file_priv->vdev; @@ -557,20 +308,20 @@ ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, size, args->flags, &shmem_ops); + bo = ivpu_bo_create(vdev, size, args->flags); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to create BO: %pe (ctx %u size %llu flags 0x%x)", bo, file_priv->ctx.id, args->size, args->flags); return PTR_ERR(bo); } - ret = drm_gem_handle_create(file, &bo->base, &bo->handle); + ret = drm_gem_handle_create(file, &bo->base.base, &bo->handle); if (!ret) { args->vpu_addr = bo->vpu_addr; args->handle = bo->handle; } - drm_gem_object_put(&bo->base); + drm_gem_object_put(&bo->base.base); return ret; } @@ -580,8 +331,8 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla { const struct ivpu_addr_range *range; struct ivpu_addr_range fixed_range; + struct iosys_map map; struct ivpu_bo *bo; - pgprot_t prot; int ret; drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(vpu_addr)); @@ -595,7 +346,7 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla range = &vdev->hw->ranges.global; } - bo = ivpu_bo_alloc(vdev, size, flags, &internal_ops); + bo = ivpu_bo_create(vdev, size, flags); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to create BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)", bo, vpu_addr, size, flags); @@ -610,61 +361,23 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla if (ret) goto err_put; - if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) - drm_clflush_pages(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - if (bo->flags & DRM_IVPU_BO_WC) - set_pages_array_wc(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - else if (bo->flags & DRM_IVPU_BO_UNCACHED) - set_pages_array_uc(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - prot = ivpu_bo_pgprot(bo, PAGE_KERNEL); - bo->kvaddr = vmap(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT, VM_MAP, prot); - if (!bo->kvaddr) { - ivpu_err(vdev, "Failed to map BO into kernel virtual memory\n"); + ret = drm_gem_shmem_vmap(&bo->base, &map); + if (ret) goto err_put; - } return bo; err_put: - drm_gem_object_put(&bo->base); + drm_gem_object_put(&bo->base.base); return NULL; } void ivpu_bo_free_internal(struct ivpu_bo *bo) { - drm_gem_object_put(&bo->base); -} + struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); -struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *buf) -{ - struct ivpu_device *vdev = to_ivpu_device(dev); - struct dma_buf_attachment *attach; - struct ivpu_bo *bo; - - attach = dma_buf_attach(buf, dev->dev); - if (IS_ERR(attach)) - return ERR_CAST(attach); - - get_dma_buf(buf); - - bo = ivpu_bo_alloc(vdev, buf->size, DRM_IVPU_BO_MAPPABLE, &prime_ops); - if (IS_ERR(bo)) { - ivpu_err(vdev, "Failed to import BO: %pe (size %lu)", bo, buf->size); - goto err_detach; - } - - lockdep_set_class(&bo->lock, &prime_bo_lock_class_key); - - bo->base.import_attach = attach; - - return &bo->base; - -err_detach: - dma_buf_detach(buf, attach); - dma_buf_put(buf); - return ERR_CAST(bo); + drm_gem_shmem_vunmap(&bo->base, &map); + drm_gem_object_put(&bo->base.base); } int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -723,12 +436,23 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) mutex_lock(&bo->lock); - if (bo->base.dma_buf && bo->base.dma_buf->file) - dma_refcount = atomic_long_read(&bo->base.dma_buf->file->f_count); + if (bo->base.base.dma_buf && bo->base.base.dma_buf->file) + dma_refcount = atomic_long_read(&bo->base.base.dma_buf->file->f_count); - drm_printf(p, "%5u %6d %16llx %10lu %10u %12lu %14s\n", - bo->ctx ? bo->ctx->id : -1, bo->handle, bo->vpu_addr, bo->base.size, - kref_read(&bo->base.refcount), dma_refcount, bo->ops->name); + drm_printf(p, "%-3u %-6d 0x%-12llx %-10lu 0x%-8x %-4u %-8lu", + bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.base.size, + bo->flags, kref_read(&bo->base.base.refcount), dma_refcount); + + if (bo->base.base.import_attach) + drm_printf(p, " imported"); + + if (bo->base.pages) + drm_printf(p, " has_pages"); + + if (bo->mmu_mapped) + drm_printf(p, " mmu_mapped"); + + drm_printf(p, "\n"); mutex_unlock(&bo->lock); } @@ -738,8 +462,8 @@ void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) struct ivpu_device *vdev = to_ivpu_device(dev); struct ivpu_bo *bo; - drm_printf(p, "%5s %6s %16s %10s %10s %12s %14s\n", - "ctx", "handle", "vpu_addr", "size", "refcount", "dma_refcount", "type"); + drm_printf(p, "%-3s %-6s %-14s %-10s %-10s %-4s %-8s %s\n", + "ctx", "handle", "vpu_addr", "size", "flags", "refs", "dma_refs", "attribs"); mutex_lock(&vdev->bo_list_lock); list_for_each_entry(bo, &vdev->bo_list, bo_list_node) diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 214d8fd14310..d75cad0d3c74 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -6,83 +6,52 @@ #define __IVPU_GEM_H__ #include +#include #include -struct dma_buf; -struct ivpu_bo_ops; struct ivpu_file_priv; struct ivpu_bo { - struct drm_gem_object base; - const struct ivpu_bo_ops *ops; - + struct drm_gem_shmem_object base; struct ivpu_mmu_context *ctx; struct list_head bo_list_node; struct drm_mm_node mm_node; - struct mutex lock; /* Protects: pages, sgt, ctx, mmu_mapped, vpu_addr */ - struct sg_table *sgt; - struct page **pages; - bool mmu_mapped; - - void *kvaddr; + struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ u64 vpu_addr; u32 handle; u32 flags; - u32 job_status; -}; - -enum ivpu_bo_type { - IVPU_BO_TYPE_SHMEM = 1, - IVPU_BO_TYPE_INTERNAL, - IVPU_BO_TYPE_PRIME, -}; - -struct ivpu_bo_ops { - enum ivpu_bo_type type; - const char *name; - int (*alloc_pages)(struct ivpu_bo *bo); - void (*free_pages)(struct ivpu_bo *bo); - int (*map_pages)(struct ivpu_bo *bo); - void (*unmap_pages)(struct ivpu_bo *bo); + u32 job_status; /* Valid only for command buffer */ + bool mmu_mapped; }; int ivpu_bo_pin(struct ivpu_bo *bo); void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); -void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p); -void ivpu_bo_list_print(struct drm_device *dev); -struct ivpu_bo * -ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags); +struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size); +struct ivpu_bo *ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags); void ivpu_bo_free_internal(struct ivpu_bo *bo); -struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); -void ivpu_bo_unmap_sgt_and_remove_from_context(struct ivpu_bo *bo); int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p); +void ivpu_bo_list_print(struct drm_device *dev); + static inline struct ivpu_bo *to_ivpu_bo(struct drm_gem_object *obj) { - return container_of(obj, struct ivpu_bo, base); + return container_of(obj, struct ivpu_bo, base.base); } static inline void *ivpu_bo_vaddr(struct ivpu_bo *bo) { - return bo->kvaddr; + return bo->base.vaddr; } static inline size_t ivpu_bo_size(struct ivpu_bo *bo) { - return bo->base.size; -} - -static inline struct page *ivpu_bo_get_page(struct ivpu_bo *bo, u64 offset) -{ - if (offset > ivpu_bo_size(bo) || !bo->pages) - return NULL; - - return bo->pages[offset / PAGE_SIZE]; + return bo->base.base.size; } static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) @@ -95,20 +64,9 @@ static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; } -static inline pgprot_t ivpu_bo_pgprot(struct ivpu_bo *bo, pgprot_t prot) -{ - if (bo->flags & DRM_IVPU_BO_WC) - return pgprot_writecombine(prot); - - if (bo->flags & DRM_IVPU_BO_UNCACHED) - return pgprot_noncached(prot); - - return prot; -} - static inline struct ivpu_device *ivpu_bo_to_vdev(struct ivpu_bo *bo) { - return to_ivpu_device(bo->base.dev); + return to_ivpu_device(bo->base.base.dev); } static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 15a408fad494..02acd8dba02a 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -266,7 +266,7 @@ static void job_release(struct kref *ref) for (i = 0; i < job->bo_count; i++) if (job->bos[i]) - drm_gem_object_put(&job->bos[i]->base); + drm_gem_object_put(&job->bos[i]->base.base); dma_fence_put(job->done_fence); ivpu_file_priv_put(&job->file_priv); @@ -450,7 +450,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 } bo = job->bos[CMD_BUF_IDX]; - if (!dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_READ)) { + if (!dma_resv_test_signaled(bo->base.base.resv, DMA_RESV_USAGE_READ)) { ivpu_warn(vdev, "Buffer is already in use\n"); return -EBUSY; } @@ -470,7 +470,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 } for (i = 0; i < buf_count; i++) { - ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1); + ret = dma_resv_reserve_fences(job->bos[i]->base.base.resv, 1); if (ret) { ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret); goto unlock_reservations; @@ -479,7 +479,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 for (i = 0; i < buf_count; i++) { usage = (i == CMD_BUF_IDX) ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_BOOKKEEP; - dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, usage); + dma_resv_add_fence(job->bos[i]->base.base.resv, job->done_fence, usage); } unlock_reservations: From d08361e1f66381ba615852cb6155f028a52a0fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Sep 2023 15:25:39 +0300 Subject: [PATCH 0275/7721] drm/i915: Drop redundant !modeset check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 7de5b6b54630 ("drm/i915: Don't flag both full modeset and fastset at the same time") intel_crtc_needs_fastset() and intel_crtc_needs_modeset() have been mutually exclusive. Drop the redundant check. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230907122541.32261-2-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index bad43626e204..4bce36e14da6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6831,7 +6831,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, * valid pipe configuration from the BIOS we need to take care * of enabling them on the CRTC's first fastset. */ - if (intel_crtc_needs_fastset(new_crtc_state) && !modeset && + if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited) intel_crtc_arm_fifo_underrun(crtc, new_crtc_state); } From c39c93578106f035218078c300db6361cf6a326c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Sep 2023 15:25:40 +0300 Subject: [PATCH 0276/7721] drm/i915: Split intel_update_crtc() into two parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split intel_update_crtc() into two parts such that the first part performs all the non-vblank evasion preparatory stuff, and the second part just does the vblank evasion stuff. For now we just call these back to back so that there is no funcitonal change. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230907122541.32261-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4bce36e14da6..bedd338ee9be 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6760,8 +6760,8 @@ static void intel_enable_crtc(struct intel_atomic_state *state, intel_crtc_enable_pipe_crc(crtc); } -static void intel_update_crtc(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static void intel_pre_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_crtc_state *old_crtc_state = @@ -6803,6 +6803,15 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_color_commit_noarm(new_crtc_state); intel_crtc_planes_update_noarm(state, crtc); +} + +static void intel_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); /* Perform vblank evasion around commit operation */ intel_pipe_update_start(state, crtc); @@ -6926,6 +6935,7 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state) continue; intel_enable_crtc(state, crtc); + intel_pre_update_crtc(state, crtc); intel_update_crtc(state, crtc); } } @@ -6978,6 +6988,7 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) entries[pipe] = new_crtc_state->wm.skl.ddb; update_pipes &= ~BIT(pipe); + intel_pre_update_crtc(state, crtc); intel_update_crtc(state, crtc); /* @@ -7045,6 +7056,7 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) entries[pipe] = new_crtc_state->wm.skl.ddb; update_pipes &= ~BIT(pipe); + intel_pre_update_crtc(state, crtc); intel_update_crtc(state, crtc); } From c610e841f19d57233062868f2408349e9ecade91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Sep 2023 15:25:41 +0300 Subject: [PATCH 0277/7721] drm/i915: Do plane/etc. updates more atomically across pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Perform all the intel_pre_update_crtc() stuff for all pipes first, and only then do the intel_update_crtc() vblank evasion stuff for every pipe back to back. This should make it more likely that the plane updates from multiple pipes happen on the same frame (assuming the pipes are running in sync, eg. due to bigjoiner or port sync). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230907122541.32261-4-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index bedd338ee9be..3effafcbb411 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6936,6 +6936,12 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state) intel_enable_crtc(state, crtc); intel_pre_update_crtc(state, crtc); + } + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!new_crtc_state->hw.active) + continue; + intel_update_crtc(state, crtc); } } @@ -6973,6 +6979,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) * So first lets enable all pipes that do not need a fullmodeset as * those don't have any external dependency. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + while (update_pipes) { for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { @@ -6988,7 +7003,6 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) entries[pipe] = new_crtc_state->wm.skl.ddb; update_pipes &= ~BIT(pipe); - intel_pre_update_crtc(state, crtc); intel_update_crtc(state, crtc); /* @@ -7044,6 +7058,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) /* * Finally we do the plane updates/etc. for all pipes that got enabled. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe; @@ -7056,7 +7079,6 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) entries[pipe] = new_crtc_state->wm.skl.ddb; update_pipes &= ~BIT(pipe); - intel_pre_update_crtc(state, crtc); intel_update_crtc(state, crtc); } From 65c02404380fb328e4d1fe40318ac6de0e63327a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Oct 2023 15:24:42 +0300 Subject: [PATCH 0278/7721] drm/i915/gvt: Clean up zero initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just use a simple {} to zero initialize arrays/structs instead of the hodgepodge of stuff we are using currently. Cc: Zhenyu Wang Cc: Zhi Wang Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231012122442.15718-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/gvt/cmd_parser.c | 2 +- drivers/gpu/drm/i915/gvt/fb_decoder.c | 6 +++--- drivers/gpu/drm/i915/gvt/handlers.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 05f9348b7a9d..d4a3f3e093b0 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -3047,7 +3047,7 @@ static int shadow_indirect_ctx(struct intel_shadow_wa_ctx *wa_ctx) static int combine_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) { - u32 per_ctx_start[CACHELINE_DWORDS] = {0}; + u32 per_ctx_start[CACHELINE_DWORDS] = {}; unsigned char *bb_start_sva; if (!wa_ctx->per_ctx.valid) diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index 835c3fde8a20..313efdabee57 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -56,7 +56,7 @@ static const struct pixel_format bdw_pixel_formats[] = { {DRM_FORMAT_XBGR8888, 32, "32-bit RGBX (8:8:8:8 MSB-X:B:G:R)"}, /* non-supported format has bpp default to 0 */ - {0, 0, NULL}, + {} }; static const struct pixel_format skl_pixel_formats[] = { @@ -76,7 +76,7 @@ static const struct pixel_format skl_pixel_formats[] = { {DRM_FORMAT_XRGB2101010, 32, "32-bit BGRX (2:10:10:10 MSB-X:R:G:B)"}, /* non-supported format has bpp default to 0 */ - {0, 0, NULL}, + {} }; static int bdw_format_to_drm(int format) @@ -293,7 +293,7 @@ static const struct cursor_mode_format cursor_pixel_formats[] = { {DRM_FORMAT_ARGB8888, 32, 64, 64, "64x64 32bpp ARGB"}, /* non-supported format has bpp default to 0 */ - {0, 0, 0, 0, NULL}, + {} }; static int cursor_mode_to_drm(int mode) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 72addd8d380f..90f6c1ece57d 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -538,7 +538,7 @@ static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) int refclk = vgpu->gvt->gt->i915->display.dpll.ref_clks.nssc; enum dpio_phy phy = DPIO_PHY0; enum dpio_channel ch = DPIO_CH0; - struct dpll clock = {0}; + struct dpll clock = {}; u32 temp; /* Port to PHY mapping is fixed, see bxt_ddi_phy_info{} */ From 40018a8fa9aa63ca5b26e803502138158fb0ff96 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 30 Oct 2023 12:03:23 +0300 Subject: [PATCH 0279/7721] wifi: plfxlc: check for allocation failure in plfxlc_usb_wreq_async() Check for if the usb_alloc_urb() failed. Fixes: 68d57a07bfe5 ("wireless: add plfxlc driver for pureLiFi X, XL, XC devices") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/e8d4a19a-f251-4101-a89b-607345e938cb@moroto.mountain --- drivers/net/wireless/purelifi/plfxlc/usb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c index 76d0a778636a..311676c1ece0 100644 --- a/drivers/net/wireless/purelifi/plfxlc/usb.c +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c @@ -493,9 +493,12 @@ int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer, void *context) { struct usb_device *udev = interface_to_usbdev(usb->ez_usb); - struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC); + struct urb *urb; int r; + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), (void *)buffer, buffer_len, complete_fn, context); From 4859b08f197b11b35932fdb4f584b89ff5243ad9 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 31 Oct 2023 20:13:23 +0300 Subject: [PATCH 0280/7721] wifi: wilc1000: cleanup struct wilc_conn_info Remove set but otherwise unused 'ch' member of 'struct wilc_conn_info' and avoid typeless 'void *' pointers in '(*conn_result)()' callback. Likewise for 'wilc_parse_join_bss_param()'. Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231031171330.70399-1-dmantipov@yandex.ru --- .../net/wireless/microchip/wilc1000/cfg80211.c | 6 ++---- drivers/net/wireless/microchip/wilc1000/hif.c | 13 +++++++------ drivers/net/wireless/microchip/wilc1000/hif.h | 15 +++++++++------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index bf2a60533506..af6d17724bf3 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -162,9 +162,8 @@ static void cfg_scan_result(enum scan_event scan_event, } static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, - void *priv_data) + struct wilc_priv *priv) { - struct wilc_priv *priv = priv_data; struct net_device *dev = priv->dev; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; @@ -412,9 +411,8 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, wfi_drv->conn_info.security = security; wfi_drv->conn_info.auth_type = auth_type; - wfi_drv->conn_info.ch = ch; wfi_drv->conn_info.conn_result = cfg_connect_result; - wfi_drv->conn_info.arg = priv; + wfi_drv->conn_info.priv = priv; wfi_drv->conn_info.param = join_params; if (sme->mfp == NL80211_MFP_OPTIONAL) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 2c42683dd5fb..a5115227644b 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -348,7 +348,7 @@ static void handle_connect_timeout(struct work_struct *work) if (hif_drv->conn_info.conn_result) { hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, WILC_MAC_STATUS_DISCONNECTED, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); @@ -371,8 +371,9 @@ static void handle_connect_timeout(struct work_struct *work) kfree(msg); } -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto) +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) { struct wilc_join_bss_param *param; struct ieee80211_p2p_noa_attr noa_attr; @@ -627,7 +628,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); if (mac_status == WILC_MAC_STATUS_CONNECTED && conn_info->status == WLAN_STATUS_SUCCESS) { @@ -657,7 +658,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif) if (hif_drv->conn_info.conn_result) hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, hif_drv->conn_info.arg); + 0, hif_drv->conn_info.priv); eth_zero_addr(hif_drv->assoc_bssid); @@ -739,7 +740,7 @@ int wilc_disconnect(struct wilc_vif *vif) del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, - conn_info->arg); + conn_info->priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index b0cb35590027..07f81c7c5130 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -95,6 +95,7 @@ struct wilc_rcvd_net_info { struct ieee80211_mgmt *mgmt; }; +struct wilc_priv; struct wilc_user_scan_req { void (*scan_result)(enum scan_event evt, struct wilc_rcvd_net_info *info, void *priv); @@ -102,20 +103,21 @@ struct wilc_user_scan_req { u32 ch_cnt; }; +struct wilc_join_bss_param; struct wilc_conn_info { u8 bssid[ETH_ALEN]; u8 security; enum authtype auth_type; enum mfptype mfp_type; - u8 ch; u8 *req_ies; size_t req_ies_len; u8 *resp_ies; u16 resp_ies_len; u16 status; - void (*conn_result)(enum conn_event evt, u8 status, void *priv_data); - void *arg; - void *param; + void (*conn_result)(enum conn_event evt, u8 status, + struct wilc_priv *priv); + struct wilc_priv *priv; + struct wilc_join_bss_param *param; }; struct wilc_vif; @@ -207,8 +209,9 @@ int wilc_set_external_auth_param(struct wilc_vif *vif, void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto); +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index); void wilc_handle_disconnect(struct wilc_vif *vif); From a2fbf9e1e8acf89de8132d1df255e1ee0b8320fe Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 31 Oct 2023 20:13:24 +0300 Subject: [PATCH 0281/7721] wifi: wilc1000: simplify wilc_scan() Simplify 'wilc_scan()' assuming 'struct wilc_priv *' is the only data passed to '(*scan_result)()' callback and thus avoid typeless 'void *' pointers in related code, including 'struct wilc_user_scan_req'. Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231031171330.70399-2-dmantipov@yandex.ru --- .../wireless/microchip/wilc1000/cfg80211.c | 10 ++++------ drivers/net/wireless/microchip/wilc1000/hif.c | 20 ++++++++++--------- drivers/net/wireless/microchip/wilc1000/hif.h | 14 +++++++------ 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index af6d17724bf3..ad2509d8c99a 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -105,10 +105,9 @@ struct wilc_ch_list_elem { } __packed; static void cfg_scan_result(enum scan_event scan_event, - struct wilc_rcvd_net_info *info, void *user_void) + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv) { - struct wilc_priv *priv = user_void; - if (!priv->cfg_scanning) return; @@ -285,9 +284,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) else scan_type = WILC_FW_PASSIVE_SCAN; - ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list, - request->n_channels, cfg_scan_result, (void *)priv, - request); + ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, + scan_ch_list, cfg_scan_result, request); if (ret) { priv->scan_req = NULL; diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index a5115227644b..839f142663e8 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -144,18 +144,19 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) scan_req = &hif_drv->usr_scan_req; if (scan_req->scan_result) { - scan_req->scan_result(evt, NULL, scan_req->arg); + scan_req->scan_result(evt, NULL, scan_req->priv); scan_req->scan_result = NULL; } return result; } -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request) + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request) { int result = 0; struct wid wid_list[WILC_SCAN_WID_LIST_SIZE]; @@ -164,6 +165,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u8 *buffer; u8 valuesize = 0; u8 *search_ssid_vals = NULL; + const u8 ch_list_len = request->n_channels; struct host_if_drv *hif_drv = vif->hif_drv; if (hif_drv->hif_state >= HOST_IF_SCANNING && @@ -249,7 +251,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, index++; hif_drv->usr_scan_req.scan_result = scan_result_fn; - hif_drv->usr_scan_req.arg = user_arg; + hif_drv->usr_scan_req.priv = &vif->priv; result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index); if (result) { @@ -546,7 +548,7 @@ static void handle_rcvd_ntwrk_info(struct work_struct *work) if (scan_req->scan_result) scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info, - scan_req->arg); + scan_req->priv); done: kfree(rcvd_info->mgmt); @@ -730,7 +732,7 @@ int wilc_disconnect(struct wilc_vif *vif) if (scan_req->scan_result) { del_timer(&hif_drv->scan_timer); - scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv); scan_req->scan_result = NULL; } @@ -1539,7 +1541,7 @@ int wilc_deinit(struct wilc_vif *vif) if (hif_drv->usr_scan_req.scan_result) { hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg); + hif_drv->usr_scan_req.priv); hif_drv->usr_scan_req.scan_result = NULL; } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index 07f81c7c5130..0d380586b1d9 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -98,8 +98,9 @@ struct wilc_rcvd_net_info { struct wilc_priv; struct wilc_user_scan_req { void (*scan_result)(enum scan_event evt, - struct wilc_rcvd_net_info *info, void *priv); - void *arg; + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv); + struct wilc_priv *priv; u32 ch_cnt; }; @@ -172,11 +173,12 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, int wilc_disconnect(struct wilc_vif *vif); int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request); + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request); int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *cfg_param); int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); From 07fabde630a6ce6d0ec791415d3dc3ade858f8c5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 1 Nov 2023 15:21:45 +0800 Subject: [PATCH 0282/7721] wifi: rtw89: pci: add PCI generation information to pci_info for each chip In order to reuse PCI initial and configuration flows, add struct rtw89_pci_gen_def to abstract the differences between WiFi 6/7 generations. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231101072149.21997-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 4 ++++ drivers/net/wireless/realtek/rtw89/pci.h | 6 ++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ae.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ce.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 8 files changed, 27 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/pci_be.c diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index b2de5280d934..411e9c270638 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3853,6 +3853,10 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); +const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { +}; +EXPORT_SYMBOL(rtw89_pci_gen_ax); + static const struct rtw89_hci_ops rtw89_pci_ops = { .tx_write = rtw89_pci_ops_tx_write, .tx_kick_off = rtw89_pci_ops_tx_kick_off, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index fe1019ae5e5b..f4662c7057ee 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -922,7 +922,11 @@ struct rtw89_pci_bd_ram { u8 min_num; }; +struct rtw89_pci_gen_def { +}; + struct rtw89_pci_info { + const struct rtw89_pci_gen_def *gen_def; enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; enum mac_ax_rxbd_mode rxbd_mode; @@ -1229,6 +1233,8 @@ extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_be; struct pci_device_id; diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c new file mode 100644 index 000000000000..17dcf3211b77 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include + +#include "pci.h" +#include "reg.h" + +const struct rtw89_pci_gen_def rtw89_pci_gen_be = { +}; +EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 3b299778119a..6858fd760013 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -10,6 +10,7 @@ #include "rtw8851b.h" static const struct rtw89_pci_info rtw8851b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index a40e87405dc8..f539f4602c02 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -10,6 +10,7 @@ #include "rtw8852a.h" static const struct rtw89_pci_info rtw8852a_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 9500ff9bb4aa..b9bbb6e9b4ff 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -10,6 +10,7 @@ #include "rtw8852b.h" static const struct rtw89_pci_info rtw8852b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 5c84589fd50e..f6bf35342719 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -19,6 +19,7 @@ static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = { }; static const struct rtw89_pci_info rtw8852c_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index e55f25bafc6e..8ea5261b9ee4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -9,6 +9,7 @@ #include "reg.h" static const struct rtw89_pci_info rtw8922a_pci_info = { + .gen_def = &rtw89_pci_gen_be, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, From bfdcfee3659c6289f391d6eced54b18b244a21ea Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 1 Nov 2023 15:21:46 +0800 Subject: [PATCH 0283/7721] wifi: rtw89: pci: use gen_def pointer to configure mac_{pre,post}_init and clear PCI ring index Use gen_def pointer to call three WiFi 6 specific functions, and add _ax suffix to them. Then, we will implement functions for WiFi 7 chips later. The mac_{pre,post}_init are used to initialize PCI during doing MAC initialization, and clear PCI ring index to make index consistent between driver, firmware and hardware. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231101072149.21997-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 10 ++++++--- drivers/net/wireless/realtek/rtw89/pci.h | 28 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 411e9c270638..0384f46648e7 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2361,7 +2361,7 @@ static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev) B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG); } -static void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -2549,7 +2549,7 @@ static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; int ret; @@ -2706,7 +2706,7 @@ int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en) } EXPORT_SYMBOL(rtw89_pci_ltr_set_v1); -static int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3854,6 +3854,10 @@ SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { + .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, + .mac_post_init = rtw89_pci_ops_mac_post_init_ax, + + .clr_idx_all = rtw89_pci_clr_idx_all_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index f4662c7057ee..32e56938a170 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -923,6 +923,10 @@ struct rtw89_pci_bd_ram { }; struct rtw89_pci_gen_def { + int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_post_init)(struct rtw89_dev *rtwdev); + + void (*clr_idx_all)(struct rtw89_dev *rtwdev); }; struct rtw89_pci_info { @@ -1331,4 +1335,28 @@ void rtw89_chip_recognize_intrs(struct rtw89_dev *rtwdev, info->recognize_intrs(rtwdev, rtwpci, isrs); } +static inline int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_pre_init(rtwdev); +} + +static inline int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_post_init(rtwdev); +} + +static inline void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + gen_def->clr_idx_all(rtwdev); +} + #endif From 2daafe9a0cb6c93379ae2099610ac4069f1e286d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 1 Nov 2023 15:21:47 +0800 Subject: [PATCH 0284/7721] wifi: rtw89: pci: implement PCI mac_pre_init for WiFi 7 chips Call this function when doing MAC initialization at probe stage. It does partial initial registers only, because we only need basic ability to download firmware. The function to clear index is the sub-function, so set its pointer as well. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231101072149.21997-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 2 +- drivers/net/wireless/realtek/rtw89/pci.h | 71 +++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 324 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 228 ++++++++++++++ 4 files changed, 624 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 0384f46648e7..74828dd37715 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1537,7 +1537,7 @@ static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev, rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring); } -static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 32e56938a170..d9fe9a013a56 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -245,6 +245,51 @@ #define B_AX_HS1ISR_IND_INT BIT(25) #define B_AX_PCIE_DBG_STE_INT BIT(13) +#define R_BE_PCIE_FRZ_CLK 0x3004 +#define B_BE_PCIE_FRZ_MAC_HW_RST BIT(31) +#define B_BE_PCIE_FRZ_CFG_SPC_RST BIT(30) +#define B_BE_PCIE_FRZ_ELBI_RST BIT(29) +#define B_BE_PCIE_MAC_IS_ACTIVE BIT(28) +#define B_BE_PCIE_FRZ_RTK_HW_RST BIT(27) +#define B_BE_PCIE_FRZ_REG_RST BIT(26) +#define B_BE_PCIE_FRZ_ANA_RST BIT(25) +#define B_BE_PCIE_FRZ_WLAN_RST BIT(24) +#define B_BE_PCIE_FRZ_FLR_RST BIT(23) +#define B_BE_PCIE_FRZ_RET_NON_STKY_RST BIT(22) +#define B_BE_PCIE_FRZ_RET_STKY_RST BIT(21) +#define B_BE_PCIE_FRZ_NON_STKY_RST BIT(20) +#define B_BE_PCIE_FRZ_STKY_RST BIT(19) +#define B_BE_PCIE_FRZ_RET_CORE_RST BIT(18) +#define B_BE_PCIE_FRZ_PWR_RST BIT(17) +#define B_BE_PCIE_FRZ_PERST_RST BIT(16) +#define B_BE_PCIE_FRZ_PHY_ALOAD BIT(15) +#define B_BE_PCIE_FRZ_PHY_HW_RST BIT(14) +#define B_BE_PCIE_DBG_CLK BIT(4) +#define B_BE_PCIE_EN_CLK BIT(3) +#define B_BE_PCIE_DBI_ACLK_ACT BIT(2) +#define B_BE_PCIE_S1_ACLK_ACT BIT(1) +#define B_BE_PCIE_EN_AUX_CLK BIT(0) + +#define R_BE_PCIE_PS_CTRL 0x3008 +#define B_BE_RSM_L0S_EN BIT(8) +#define B_BE_CMAC_EXIT_L1_EN BIT(7) +#define B_BE_DMAC0_EXIT_L1_EN BIT(6) +#define B_BE_FORCE_L0 BIT(5) +#define B_BE_DBI_RO_WR_DISABLE BIT(4) +#define B_BE_SEL_XFER_PENDING BIT(3) +#define B_BE_SEL_REQ_ENTR_L1 BIT(2) +#define B_BE_PCIE_EN_SWENT_L23 BIT(1) +#define B_BE_SEL_REQ_EXIT_L1 BIT(0) + +#define R_BE_PCIE_LAT_CTRL 0x3044 +#define B_BE_ELBI_PHY_REMAP_MASK GENMASK(29, 24) +#define B_BE_SYS_SUS_L12_EN BIT(17) +#define B_BE_MDIO_S_EN BIT(16) +#define B_BE_SYM_AUX_CLK_SEL BIT(15) +#define B_BE_RTK_LDO_POWER_LATENCY_MASK GENMASK(11, 10) +#define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) +#define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) + /* TX/RX */ #define R_AX_DRV_FW_HSK_0 0x01B0 #define R_AX_DRV_FW_HSK_1 0x01B4 @@ -656,6 +701,31 @@ #define R_BE_PCIE_HRPWM 0x30C0 #define R_BE_PCIE_CRPWM 0x30C4 +#define R_BE_L1_2_CTRL_HCILDO 0x3110 +#define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0) + +#define R_BE_PL1_DBG_INFO 0x3120 +#define B_BE_END_PL1_CNT_MASK GENMASK(23, 16) +#define B_BE_START_PL1_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_PL1_CTRL 0x34A8 +#define B_BE_PL1_SER_PL1_EN BIT(31) +#define B_BE_PL1_IGNORE_HOT_RST BIT(30) +#define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17) +#define B_BE_PL1_TIMER_CLEAR BIT(0) + +#define R_BE_REG_PL1_MASK 0x34B0 +#define B_BE_SER_PCLKREQ_ACK_MASK BIT(5) +#define B_BE_SER_PM_CLK_MASK BIT(4) +#define B_BE_SER_LTSSM_IMR BIT(3) +#define B_BE_SER_PM_MASTER_IMR BIT(2) +#define B_BE_SER_L1SUB_IMR BIT(1) +#define B_BE_SER_PMU_IMR BIT(0) + +#define R_BE_RX_APPEND_MODE 0x8920 +#define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16) +#define B_BE_APPEND_LEN_MASK GENMASK(15, 0) + #define R_BE_TXBD_RWPTR_CLR1 0xB014 #define B_BE_CLR_CH14_IDX BIT(14) #define B_BE_CLR_CH13_IDX BIT(13) @@ -1244,6 +1314,7 @@ struct pci_device_id; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw89_pci_remove(struct pci_dev *pdev); +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 17dcf3211b77..0510fe9f7146 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -7,6 +7,330 @@ #include "pci.h" #include "reg.h" +enum pcie_rxbd_mode { + PCIE_RXBD_NORM = 0, + PCIE_RXBD_SEP, + PCIE_RXBD_EXT, +}; + +#define PL0_TMR_SCALE_ASIC 1 +#define PL0_TMR_ANA_172US 0x800 +#define PL0_TMR_MAC_1MS 0x27100 +#define PL0_TMR_AUX_1MS 0x1E848 + +static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up) +{ + if (power_up) + rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); + else + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); +} + +static void rtw89_pci_set_io_rcy_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 scale = PL0_TMR_SCALE_ASIC; + u32 val32; + + if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) { + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_ANA_172US : info->io_rcy_tmr; + val32 /= scale; + + rtw89_write32(rtwdev, R_BE_AON_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_MDIO_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_LA_MODE_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AR_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AW_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_W_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_B_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_R_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_MAC_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_WLAN_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_AXIDMA_WDT_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_AUX_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_LOCAL_WDT_TMR, val32); + } else { + rtw89_write32_clr(rtwdev, R_BE_WLAN_WDT, B_BE_WLAN_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AXIDMA_WDT, B_BE_AXIDMA_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AON_WDT, B_BE_AON_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LOCAL_WDT, B_BE_LOCAL_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_MDIO_WDT, B_BE_MDIO_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LA_MODE_WDT, B_BE_LA_MODE_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AR, B_BE_WDT_AR_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AW, B_BE_WDT_AW_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_W, B_BE_WDT_W_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_B, B_BE_WDT_B_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_R, B_BE_WDT_R_ENABLE); + } +} + +static void rtw89_pci_ctrl_wpdma_pcie_be(struct rtw89_dev *rtwdev, bool en) +{ + if (en) + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); + else + rtw89_write32_set(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); +} + +static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, + enum mac_ax_pcie_func_ctrl tx_en, + enum mac_ax_pcie_func_ctrl rx_en, + enum mac_ax_pcie_func_ctrl io_en) +{ + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + + if (tx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_TXDMA_EN; + else if (tx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_TXDMA_EN; + + if (rx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_RXDMA_EN; + else if (rx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_RXDMA_EN; + + if (io_en == MAC_AX_PCIE_ENABLE) + val &= ~B_BE_STOP_AXI_MST; + else if (io_en == MAC_AX_PCIE_DISABLE) + val |= B_BE_STOP_AXI_MST; + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); +} + +static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_rx_ring *rx_ring; + u32 val; + + val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX | + B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | + B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX | + B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | + B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX; + rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val); + + rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, + B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; + rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); +} + +static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 check; + u32 val; + + check = B_BE_RXQ0_BUSY_V1 | B_BE_RPQ0_BUSY_V1; + + return read_poll_timeout(rtw89_read32, val, (val & check) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_pci_poll_txdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "txdma ch busy\n"); + return ret; + } + + ret = rtw89_pci_poll_rxdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "rxdma ch busy\n"); + return ret; + } + + return 0; +} + +static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 val32_init1, val32_rxapp, val32_exp; + + val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); + val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1); + + if (info->rxbd_mode == MAC_AX_RXBD_PKT) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, + B_BE_RXQ_RXBD_MODE_MASK); + } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, + B_BE_RXQ_RXBD_MODE_MASK); + val32_rxapp = u32_replace_bits(val32_rxapp, 0, + B_BE_APPEND_LEN_MASK); + } + + val32_init1 = u32_replace_bits(val32_init1, info->tx_burst, + B_BE_MAX_TXDMA_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->rx_burst, + B_BE_MAX_RXDMA_MASK); + val32_exp = u32_replace_bits(val32_exp, info->multi_tag_num, + B_BE_MAX_TAG_NUM_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_idle_intvl, + B_BE_CFG_WD_PERIOD_IDLE_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_act_intvl, + B_BE_CFG_WD_PERIOD_ACTIVE_MASK); + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1); + rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); + rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp); +} + +static int rtw89_pci_rst_bdram_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + rtw89_write32_set(rtwdev, R_BE_HAXI_INIT_CFG1, B_BE_SET_BDRAM_BOUND); + + return read_poll_timeout(rtw89_read32, val, !(val & B_BE_SET_BDRAM_BOUND), + 50, 500000, false, rtwdev, R_BE_HAXI_INIT_CFG1); +} + +static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + val32 = rtw89_read32(rtwdev, R_BE_SYS_PAGE_CLK_GATED); + val32 = u32_replace_bits(val32, 0, B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK); + val32 |= B_BE_SYM_PRST_DEBUNC_SEL; + rtw89_write32(rtwdev, R_BE_SYS_PAGE_CLK_GATED, val32); +} + +static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN); + rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED, + B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP | + B_BE_CPHY_POWER_READY_CHK); + rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN | + B_BE_PCIE_DIS_L2_RTK_PERST | + B_BE_PCIE_DIS_L2__CTRL_LDO_HCI); + rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO); +} + +static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + + rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_EN_AUX_CLK); + rtw89_write32_clr(rtwdev, R_BE_PCIE_PS_CTRL, B_BE_CMAC_EXIT_L1_EN); + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + return; + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL); + rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL); +} + +static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); + rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); + val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | + B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK; + rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); +} + +static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en, + bool h2c_en) +{ + u32 mask_all; + u32 val; + + mask_all = B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | + B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | + B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | + B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11; + + val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); + val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; + + if (all_en) + val &= ~mask_all; + else + val |= mask_all; + + if (h2c_en) + val &= ~B_BE_STOP_CH12; + else + val |= B_BE_STOP_CH12; + + rtw89_write32(rtwdev, R_BE_HAXI_DMA_STOP1, val); +} + +static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_set_io_rcy_be(rtwdev); + _patch_pcie_power_wake_be(rtwdev, true); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, false); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + ret = rtw89_pci_poll_dma_all_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n"); + return ret; + } + + rtw89_pci_mode_op_be(rtwdev); + rtw89_pci_ops_reset(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]pcie rst bdram\n"); + return ret; + } + + rtw89_pci_debounce_be(rtwdev); + rtw89_pci_ldo_low_pwr_be(rtwdev); + rtw89_pci_pcie_setting_be(rtwdev); + rtw89_pci_ser_setting_be(rtwdev); + + rtw89_pci_ctrl_txdma_ch_be(rtwdev, false, true); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_ENABLE, + MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE); + + return 0; +} + const struct rtw89_pci_gen_def rtw89_pci_gen_be = { + .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, + + .clr_idx_all = rtw89_pci_clr_idx_all_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index b509e9582ccf..58b0e09b07aa 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -116,6 +116,7 @@ #define B_AX_LTE_MUX_CTRL_PATH BIT(26) #define R_AX_HCI_OPT_CTRL 0x0074 +#define BIT_WAKE_CTRL_V1 BIT(23) #define BIT_WAKE_CTRL BIT(5) #define R_AX_HCI_BG_CTRL 0x0078 @@ -3629,6 +3630,33 @@ #define B_AX_GNT_BT_TX_SW_VAL BIT(1) #define B_AX_GNT_BT_TX_SW_CTRL BIT(0) +#define R_BE_SYS_PW_CTRL 0x0004 +#define B_BE_SOP_ASWRM BIT(31) +#define B_BE_SOP_EASWR BIT(30) +#define B_BE_SOP_PWMM_DSWR BIT(29) +#define B_BE_SOP_EDSWR BIT(28) +#define B_BE_SOP_ACKF BIT(27) +#define B_BE_SOP_ERCK BIT(26) +#define B_BE_SOP_ANA_CLK_DIVISION_2 BIT(25) +#define B_BE_SOP_EXTL BIT(24) +#define B_BE_SOP_OFF_CAPC_EN BIT(23) +#define B_BE_XTAL_OFF_A_DIE BIT(22) +#define B_BE_ROP_SWPR BIT(21) +#define B_BE_DIS_HW_LPLDM BIT(20) +#define B_BE_DIS_HW_LPURLDO BIT(19) +#define B_BE_DIS_WLBT_PDNSUSEN_SOPC BIT(18) +#define B_BE_RDY_SYSPWR BIT(17) +#define B_BE_EN_WLON BIT(16) +#define B_BE_APDM_HPDN BIT(15) +#define B_BE_PSUS_OFF_CAPC_EN BIT(14) +#define B_BE_AFSM_PCIE_SUS_EN BIT(12) +#define B_BE_AFSM_WLSUS_EN BIT(11) +#define B_BE_APFM_SWLPS BIT(10) +#define B_BE_APFM_OFFMAC BIT(9) +#define B_BE_APFN_ONMAC BIT(8) +#define B_BE_CHIP_PDN_EN BIT(7) +#define B_BE_RDY_MACDIS BIT(6) + #define R_BE_SYS_CLK_CTRL 0x0008 #define B_BE_CPU_CLK_EN BIT(14) #define B_BE_SYMR_BE_CLK_EN BIT(13) @@ -3639,6 +3667,90 @@ #define B_BE_ANA_CLK_DIVISION_2 BIT(1) #define B_BE_CNTD16V_EN BIT(0) +#define R_BE_SYS_PAGE_CLK_GATED 0x000C +#define B_BE_USB_APHY_PC_DLP_OP BIT(27) +#define B_BE_PCIE_APHY_PC_DLP_OP BIT(26) +#define B_BE_UPHY_POWER_READY_CHK BIT(25) +#define B_BE_CPHY_POWER_READY_CHK BIT(24) +#define B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK GENMASK(23, 22) +#define B_BE_SYM_PRST_DEBUNC_SEL BIT(21) +#define B_BE_CPHY_AUXCLK_OP BIT(20) +#define B_BE_SOP_OFFUA_PC BIT(19) +#define B_BE_SOP_OFFPOOBS_PC BIT(18) +#define B_BE_PCIE_LAN1_MASK BIT(17) +#define B_BE_PCIE_LAN0_MASK BIT(16) +#define B_BE_DIS_CLK_REGF_GATE BIT(15) +#define B_BE_DIS_CLK_REGE_GATE BIT(14) +#define B_BE_DIS_CLK_REGD_GATE BIT(13) +#define B_BE_DIS_CLK_REGC_GATE BIT(12) +#define B_BE_DIS_CLK_REGB_GATE BIT(11) +#define B_BE_DIS_CLK_REGA_GATE BIT(10) +#define B_BE_DIS_CLK_REG9_GATE BIT(9) +#define B_BE_DIS_CLK_REG8_GATE BIT(8) +#define B_BE_DIS_CLK_REG7_GATE BIT(7) +#define B_BE_DIS_CLK_REG6_GATE BIT(6) +#define B_BE_DIS_CLK_REG5_GATE BIT(5) +#define B_BE_DIS_CLK_REG4_GATE BIT(4) +#define B_BE_DIS_CLK_REG3_GATE BIT(3) +#define B_BE_DIS_CLK_REG2_GATE BIT(2) +#define B_BE_DIS_CLK_REG1_GATE BIT(1) +#define B_BE_DIS_CLK_REG0_GATE BIT(0) + +#define R_BE_SYS_SDIO_CTRL 0x0070 +#define B_BE_MCM_FLASH_EN BIT(28) +#define B_BE_PCIE_SEC_LOAD BIT(26) +#define B_BE_PCIE_SER_RSTB BIT(25) +#define B_BE_PCIE_SEC_LOAD_CLR BIT(24) +#define B_BE_SDIO_CMD_SW_RST BIT(20) +#define B_BE_SDIO_INT_POLARITY BIT(19) +#define B_BE_SDIO_OFF_EN BIT(17) +#define B_BE_SDIO_ON_EN BIT(16) +#define B_BE_PCIE_DIS_L2__CTRL_LDO_HCI BIT(15) +#define B_BE_PCIE_DIS_L2_RTK_PERST BIT(14) +#define B_BE_PCIE_FORCE_PWR_NGAT BIT(13) +#define B_BE_PCIE_FORCE_IBX_EN BIT(12) +#define B_BE_PCIE_AUXCLK_GATE BIT(11) +#define B_BE_PCIE_WAIT_TIMEOUT_EVENT BIT(10) +#define B_BE_PCIE_WAIT_TIME BIT(9) +#define B_BE_L1OFF_TO_L0_RESUME_EVT BIT(8) +#define B_BE_USBA_FORCE_PWR_NGAT BIT(7) +#define B_BE_USBD_FORCE_PWR_NGAT BIT(6) +#define B_BE_BT_CTRL_USB_PWR BIT(5) +#define B_BE_USB_D_STATE_HOLD BIT(4) +#define B_BE_R_BE_FORCE_DP BIT(3) +#define B_BE_R_BE_DP_MODE BIT(2) +#define B_BE_RES_USB_MASS_STORAGE_DESC BIT(1) +#define B_BE_USB_WAIT_TIME BIT(0) + +#define R_BE_HCI_OPT_CTRL 0x0074 +#define B_BE_HCI_WLAN_IO_ST BIT(31) +#define B_BE_HCI_WLAN_IO_EN BIT(28) +#define B_BE_HAXIDMA_IO_ST BIT(27) +#define B_BE_HAXIDMA_BACKUP_RESTORE_ST BIT(26) +#define B_BE_HAXIDMA_IO_EN BIT(24) +#define B_BE_EN_PCIE_WAKE BIT(23) +#define B_BE_SDIO_PAD_H3L1 BIT(22) +#define B_BE_USBMAC_ANACLK_SW BIT(21) +#define B_BE_PCIE_CPHY_CCK_XTAL_SEL BIT(20) +#define B_BE_SDIO_DATA_PAD_SMT BIT(19) +#define B_BE_SDIO_PAD_E5 BIT(18) +#define B_BE_FORCE_PCIE_AUXCLK BIT(17) +#define B_BE_HCI_LA_ADDR_MAP BIT(16) +#define B_BE_HCI_LA_GLO_RST BIT(15) +#define B_BE_USB3_SUS_DIS BIT(14) +#define B_BE_NOPWR_CTRL_SEL BIT(13) +#define B_BE_USB_HOST_PWR_OFF_EN BIT(12) +#define B_BE_SYM_LPS_BLOCK_EN BIT(11) +#define B_BE_USB_LPM_ACT_EN BIT(10) +#define B_BE_USB_LPM_NY BIT(9) +#define B_BE_USB2_SUS_DIS BIT(8) +#define B_BE_SDIO_PAD_E_MASK GENMASK(7, 5) +#define B_BE_USB_LPPLL_EN BIT(4) +#define B_BE_USB1_1_USB2_0_DECISION BIT(3) +#define B_BE_ROP_SW15 BIT(2) +#define B_BE_PCI_CKRDY_OPT BIT(1) +#define B_BE_PCI_VAUX_EN BIT(0) + #define R_BE_PLATFORM_ENABLE 0x0088 #define B_BE_HOLD_AFTER_RESET BIT(11) #define B_BE_SYM_WLPLT_MEM_MUX_EN BIT(10) @@ -3652,6 +3764,22 @@ #define B_BE_WCPU_EN BIT(1) #define B_BE_PLATFORM_EN BIT(0) +#define R_BE_EFUSE_CTRL_2_V1 0x00A4 +#define B_BE_EF_ENT BIT(31) +#define B_BE_EF_TCOLUMN_EN BIT(29) +#define B_BE_BT_OTP_PWC_DIS BIT(28) +#define B_BE_EF_RDT BIT(27) +#define B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL BIT(24) +#define B_BE_EF_PGTS_MASK GENMASK(23, 20) +#define B_BE_EF_BURST BIT(19) +#define B_BE_EF_TEST_SEL_MASK GENMASK(18, 16) +#define B_BE_EF_TROW_EN BIT(15) +#define B_BE_EF_ERR_FLAG BIT(14) +#define B_BE_EF_FBURST_DIS BIT(13) +#define B_BE_EF_HT_SEL BIT(12) +#define B_BE_EF_DSB_EN BIT(11) +#define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) @@ -3676,6 +3804,28 @@ #define R_BE_SECURE_BOOT_MALLOC_INFO 0x0184 +#define R_BE_FWS1IMR 0x0198 +#define B_BE_FS_RPWM_INT_EN_V1 BIT(24) +#define B_BE_PCIE_HOTRST_EN BIT(22) +#define B_BE_PCIE_SER_TIMEOUT_INDIC_EN BIT(21) +#define B_BE_PCIE_RXI300_SLVTOUT_INDIC_EN BIT(20) +#define B_BE_AON_PCIE_FLR_INT_EN BIT(19) +#define B_BE_PCIE_ERR_INDIC_INT_EN BIT(18) +#define B_BE_SDIO_ERR_INDIC_INT_EN BIT(17) +#define B_BE_USB_ERR_INDIC_INT_EN BIT(16) +#define B_BE_FS_GPIO27_INT_EN BIT(11) +#define B_BE_FS_GPIO26_INT_EN BIT(10) +#define B_BE_FS_GPIO25_INT_EN BIT(9) +#define B_BE_FS_GPIO24_INT_EN BIT(8) +#define B_BE_FS_GPIO23_INT_EN BIT(7) +#define B_BE_FS_GPIO22_INT_EN BIT(6) +#define B_BE_FS_GPIO21_INT_EN BIT(5) +#define B_BE_FS_GPIO20_INT_EN BIT(4) +#define B_BE_FS_GPIO19_INT_EN BIT(3) +#define B_BE_FS_GPIO18_INT_EN BIT(2) +#define B_BE_FS_GPIO17_INT_EN BIT(1) +#define B_BE_FS_GPIO16_INT_EN BIT(0) + #define R_BE_WCPU_FW_CTRL 0x01E0 #define B_BE_RUN_ENV_MASK GENMASK(31, 30) #define B_BE_WCPU_FWDL_STATUS_MASK GENMASK(29, 26) @@ -3732,6 +3882,84 @@ #define R_BE_FILTER_MODEL_ADDR 0x0C04 +#define R_BE_WLAN_WDT 0x3050 +#define B_BE_WLAN_WDT_TIMEOUT BIT(31) +#define B_BE_WLAN_WDT_TIMER_CLEAR BIT(4) +#define B_BE_WLAN_WDT_BYPASS BIT(1) +#define B_BE_WLAN_WDT_ENABLE BIT(0) + +#define R_BE_AXIDMA_WDT 0x305C +#define B_BE_AXIDMA_WDT_TIMEOUT BIT(31) +#define B_BE_AXIDMA_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AXIDMA_WDT_BYPASS BIT(1) +#define B_BE_AXIDMA_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT 0x3068 +#define B_BE_AON_WDT_TIMEOUT BIT(31) +#define B_BE_AON_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AON_WDT_BYPASS BIT(1) +#define B_BE_AON_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT_TMR 0x306C +#define R_BE_MDIO_WDT_TMR 0x3090 +#define R_BE_LA_MODE_WDT_TMR 0x309C +#define R_BE_WDT_AR_TMR 0x3144 +#define R_BE_WDT_AW_TMR 0x3150 +#define R_BE_WLAN_WDT_TMR 0x3054 +#define R_BE_WDT_W_TMR 0x315C +#define R_BE_AXIDMA_WDT_TMR 0x3060 +#define R_BE_WDT_B_TMR 0x3164 +#define R_BE_WDT_R_TMR 0x316C +#define R_BE_LOCAL_WDT_TMR 0x3084 + +#define R_BE_LOCAL_WDT 0x3080 +#define B_BE_LOCAL_WDT_TIMEOUT BIT(31) +#define B_BE_LOCAL_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LOCAL_WDT_BYPASS BIT(1) +#define B_BE_LOCAL_WDT_ENABLE BIT(0) + +#define R_BE_MDIO_WDT 0x308C +#define B_BE_MDIO_WDT_TIMEOUT BIT(31) +#define B_BE_MDIO_WDT_TIMER_CLEAR BIT(4) +#define B_BE_MDIO_WDT_BYPASS BIT(1) +#define B_BE_MDIO_WDT_ENABLE BIT(0) + +#define R_BE_LA_MODE_WDT 0x3098 +#define B_BE_LA_MODE_WDT_TIMEOUT BIT(31) +#define B_BE_LA_MODE_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LA_MODE_WDT_BYPASS BIT(1) +#define B_BE_LA_MODE_WDT_ENABLE BIT(0) + +#define R_BE_WDT_AR 0x3140 +#define B_BE_WDT_AR_TIMEOUT BIT(31) +#define B_BE_WDT_AR_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AR_BYPASS BIT(1) +#define B_BE_WDT_AR_ENABLE BIT(0) + +#define R_BE_WDT_AW 0x314C +#define B_BE_WDT_AW_TIMEOUT BIT(31) +#define B_BE_WDT_AW_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AW_BYPASS BIT(1) +#define B_BE_WDT_AW_ENABLE BIT(0) + +#define R_BE_WDT_W 0x3158 +#define B_BE_WDT_W_TIMEOUT BIT(31) +#define B_BE_WDT_W_TIMER_CLEAR BIT(4) +#define B_BE_WDT_W_BYPASS BIT(1) +#define B_BE_WDT_W_ENABLE BIT(0) + +#define R_BE_WDT_B 0x3160 +#define B_BE_WDT_B_TIMEOUT BIT(31) +#define B_BE_WDT_B_TIMER_CLEAR BIT(4) +#define B_BE_WDT_B_BYPASS BIT(1) +#define B_BE_WDT_B_ENABLE BIT(0) + +#define R_BE_WDT_R 0x3168 +#define B_BE_WDT_R_TIMEOUT BIT(31) +#define B_BE_WDT_R_TIMER_CLEAR BIT(4) +#define B_BE_WDT_R_BYPASS BIT(1) +#define B_BE_WDT_R_ENABLE BIT(0) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) From e24ae0f07625d51934e9367e155510c71b088a2b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 1 Nov 2023 15:21:48 +0800 Subject: [PATCH 0285/7721] wifi: rtw89: pci: add LTR v2 for WiFi 7 chip PCI LTR (Latency Tolerance Reporting) is a capability to yield expected power consumption, and we configure the parameters according to design. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231101072149.21997-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 1 + drivers/net/wireless/realtek/rtw89/pci_be.c | 57 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 43 ++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 4 files changed, 102 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index d9fe9a013a56..9b39ca4bbb66 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1317,6 +1317,7 @@ void rtw89_pci_remove(struct pci_dev *pdev); void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en); u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 0510fe9f7146..33c841613c3d 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -328,6 +328,63 @@ static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) return 0; } +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) +{ + u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; + + ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0); + if (rtw89_pci_ltr_is_err_reg_val(ctrl0)) + return -EINVAL; + cfg0 = rtw89_read32(rtwdev, R_BE_LTR_CFG_0); + if (rtw89_pci_ltr_is_err_reg_val(cfg0)) + return -EINVAL; + cfg1 = rtw89_read32(rtwdev, R_BE_LTR_CFG_1); + if (rtw89_pci_ltr_is_err_reg_val(cfg1)) + return -EINVAL; + dec_ctrl = rtw89_read32(rtwdev, R_BE_LTR_DECISION_CTRL_V1); + if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl)) + return -EINVAL; + idle_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1); + if (rtw89_pci_ltr_is_err_reg_val(idle_ltcy)) + return -EINVAL; + act_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1); + if (rtw89_pci_ltr_is_err_reg_val(act_ltcy)) + return -EINVAL; + dis_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1); + if (rtw89_pci_ltr_is_err_reg_val(dis_ltcy)) + return -EINVAL; + + if (en) { + dec_ctrl |= B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1; + ctrl0 |= B_BE_LTR_HW_EN; + } else { + dec_ctrl &= ~(B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1 | + B_BE_LTR_EN_PORT_V1_MASK); + ctrl0 &= ~B_BE_LTR_HW_EN; + } + + dec_ctrl = u32_replace_bits(dec_ctrl, PCI_LTR_SPC_500US, + B_BE_LTR_SPACE_IDX_MASK); + cfg0 = u32_replace_bits(cfg0, PCI_LTR_IDLE_TIMER_3_2MS, + B_BE_LTR_IDLE_TIMER_IDX_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK); + cfg0 = u32_replace_bits(cfg0, 1, B_BE_LTR_IDX_ACTIVE_MASK); + cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK); + dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK); + + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0); + rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl); + rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0); + rtw89_write32(rtwdev, R_BE_LTR_CFG_1, cfg1); + rtw89_write32(rtwdev, R_BE_LTR_CTRL_0, ctrl0); + + return 0; +} +EXPORT_SYMBOL(rtw89_pci_ltr_set_v2); + const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 58b0e09b07aa..68a5d8ff6a70 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3960,6 +3960,49 @@ #define B_BE_WDT_R_BYPASS BIT(1) #define B_BE_WDT_R_ENABLE BIT(0) +#define R_BE_LTR_DECISION_CTRL_V1 0x3610 +#define B_BE_ENABLE_LTR_CTL_DECISION BIT(31) +#define B_BE_LAT_LTR_IDX_DRV_VLD_V1 BIT(24) +#define B_BE_LAT_LTR_IDX_DRV_V1_MASK GENMASK(23, 22) +#define B_BE_LAT_LTR_IDX_FW_VLD_V1 BIT(21) +#define B_BE_LAT_LTR_IDX_FW_V1_MASK GENMASK(20, 19) +#define B_BE_LAT_LTR_IDX_HW_VLD_V1 BIT(18) +#define B_BE_LAT_LTR_IDX_HW_V1_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_DRV_V1_MASK GENMASK(15, 14) +#define B_BE_LTR_REQ_DRV_V1 BIT(13) +#define B_BE_LTR_IDX_DISABLE_V1_MASK GENMASK(9, 8) +#define B_BE_LTR_EN_PORT_V1_MASK GENMASK(6, 4) +#define B_BE_LTR_DRV_DEC_EN_V1 BIT(6) +#define B_BE_LTR_FW_DEC_EN_V1 BIT(5) +#define B_BE_LTR_HW_DEC_EN_V1 BIT(4) +#define B_BE_LTR_SPACE_IDX_MASK GENMASK(1, 0) + +#define R_BE_LTR_LATENCY_IDX0_V1 0x3614 +#define R_BE_LTR_LATENCY_IDX1_V1 0x3618 +#define R_BE_LTR_LATENCY_IDX2_V1 0x361C +#define R_BE_LTR_LATENCY_IDX3_V1 0x3620 + +#define R_BE_LTR_CTRL_0 0x8410 +#define B_BE_LTR_REQ_FW BIT(18) +#define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_LTR_WD_NOEMP_CHK BIT(1) +#define B_BE_LTR_HW_EN BIT(0) + +#define R_BE_LTR_CFG_0 0x8414 +#define B_BE_LTR_IDX_DISABLE_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_IDLE_MASK GENMASK(15, 14) +#define B_BE_LTR_IDX_ACTIVE_MASK GENMASK(13, 12) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_EN_LTR_CMAC_RX_USE_PG_CHK BIT(3) +#define B_BE_EN_LTR_WD_NON_EMPTY_CHK BIT(2) +#define B_BE_EN_LTR_HAXIDMA_TX_IDLE_CHK BIT(1) +#define B_BE_EN_LTR_HAXIDMA_RX_IDLE_CHK BIT(0) + +#define R_BE_LTR_CFG_1 0x8418 +#define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) +#define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 8ea5261b9ee4..944337c60191 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -48,6 +48,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, .bd_ram_table = NULL, + .ltr_set = rtw89_pci_ltr_set_v2, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, }; From 5cb0d6b878c375f25f1a74b4d1258561f176ea8b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 1 Nov 2023 15:21:49 +0800 Subject: [PATCH 0286/7721] wifi: rtw89: pci: implement PCI mac_post_init for WiFi 7 chips For normal use, we do additional settings than mac_pre_init, such as more TX/RX DMA channels, interrupt mitigation and etc. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231101072149.21997-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 44 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 36 +++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 9b39ca4bbb66..37398e416e58 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -708,6 +708,45 @@ #define B_BE_END_PL1_CNT_MASK GENMASK(23, 16) #define B_BE_START_PL1_CNT_MASK GENMASK(7, 0) +#define R_BE_PCIE_MIT0_TMR 0x3330 +#define B_BE_PCIE_MIT0_RX_TMR_MASK GENMASK(5, 4) +#define BE_MIT0_TMR_UNIT_1MS 0 +#define BE_MIT0_TMR_UNIT_2MS 1 +#define BE_MIT0_TMR_UNIT_4MS 2 +#define BE_MIT0_TMR_UNIT_8MS 3 +#define B_BE_PCIE_MIT0_TX_TMR_MASK GENMASK(1, 0) + +#define R_BE_PCIE_MIT0_CNT 0x3334 +#define B_BE_PCIE_RX_MIT0_CNT_MASK GENMASK(31, 24) +#define B_BE_PCIE_TX_MIT0_CNT_MASK GENMASK(23, 16) +#define B_BE_PCIE_RX_MIT0_TMR_CNT_MASK GENMASK(15, 8) +#define B_BE_PCIE_TX_MIT0_TMR_CNT_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIT_CH_EN 0x3338 +#define B_BE_PCIE_MIT_RX1P1_EN BIT(23) +#define B_BE_PCIE_MIT_RX0P1_EN BIT(22) +#define B_BE_PCIE_MIT_ROQ1_EN BIT(21) +#define B_BE_PCIE_MIT_RPQ1_EN BIT(20) +#define B_BE_PCIE_MIT_RX1P2_EN BIT(19) +#define B_BE_PCIE_MIT_ROQ0_EN BIT(18) +#define B_BE_PCIE_MIT_RPQ0_EN BIT(17) +#define B_BE_PCIE_MIT_RX0P2_EN BIT(16) +#define B_BE_PCIE_MIT_TXCH14_EN BIT(14) +#define B_BE_PCIE_MIT_TXCH13_EN BIT(13) +#define B_BE_PCIE_MIT_TXCH12_EN BIT(12) +#define B_BE_PCIE_MIT_TXCH11_EN BIT(11) +#define B_BE_PCIE_MIT_TXCH10_EN BIT(10) +#define B_BE_PCIE_MIT_TXCH9_EN BIT(9) +#define B_BE_PCIE_MIT_TXCH8_EN BIT(8) +#define B_BE_PCIE_MIT_TXCH7_EN BIT(7) +#define B_BE_PCIE_MIT_TXCH6_EN BIT(6) +#define B_BE_PCIE_MIT_TXCH5_EN BIT(5) +#define B_BE_PCIE_MIT_TXCH4_EN BIT(4) +#define B_BE_PCIE_MIT_TXCH3_EN BIT(3) +#define B_BE_PCIE_MIT_TXCH2_EN BIT(2) +#define B_BE_PCIE_MIT_TXCH1_EN BIT(1) +#define B_BE_PCIE_MIT_TXCH0_EN BIT(0) + #define R_BE_SER_PL1_CTRL 0x34A8 #define B_BE_PL1_SER_PL1_EN BIT(31) #define B_BE_PL1_IGNORE_HOT_RST BIT(30) @@ -800,12 +839,15 @@ #define RTW89_PCI_MULTITAG 8 /* PCIE CFG register */ +#define RTW89_PCIE_CAPABILITY_SPEED 0x7C +#define RTW89_PCIE_SUPPORT_GEN_MASK GENMASK(3, 0) #define RTW89_PCIE_L1_STS_V1 0x80 #define RTW89_BCFG_LINK_SPEED_MASK GENMASK(19, 16) #define RTW89_PCIE_GEN1_SPEED 0x01 #define RTW89_PCIE_GEN2_SPEED 0x02 #define RTW89_PCIE_PHY_RATE 0x82 #define RTW89_PCIE_PHY_RATE_MASK GENMASK(1, 0) +#define RTW89_PCIE_LINK_CHANGE_SPEED 0xA0 #define RTW89_PCIE_L1SS_STS_V1 0x0168 #define RTW89_PCIE_BIT_ASPM_L11 BIT(3) #define RTW89_PCIE_BIT_ASPM_L12 BIT(2) @@ -820,6 +862,8 @@ #define RTW89_PCIE_BIT_CLK BIT(4) #define RTW89_PCIE_BIT_L1 BIT(3) #define RTW89_PCIE_CLK_CTRL 0x0725 +#define RTW89_PCIE_FTS 0x080C +#define RTW89_PCIE_POLLING_BIT BIT(17) #define RTW89_PCIE_RST_MSTATE 0x0B48 #define RTW89_PCIE_BIT_CFG_RST_MSTATE BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 33c841613c3d..f3aab34a3a24 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -385,8 +385,44 @@ int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) } EXPORT_SYMBOL(rtw89_pci_ltr_set_v2); +static void rtw89_pci_configure_mit_be(struct rtw89_dev *rtwdev) +{ + u32 cnt; + u32 val; + + rtw89_write32_mask(rtwdev, R_BE_PCIE_MIT0_TMR, + B_BE_PCIE_MIT0_RX_TMR_MASK, BE_MIT0_TMR_UNIT_1MS); + + val = rtw89_read32(rtwdev, R_BE_PCIE_MIT0_CNT); + cnt = min_t(u32, U8_MAX, RTW89_PCI_RXBD_NUM_MAX / 2); + val = u32_replace_bits(val, cnt, B_BE_PCIE_RX_MIT0_CNT_MASK); + val = u32_replace_bits(val, 2, B_BE_PCIE_RX_MIT0_TMR_CNT_MASK); + rtw89_write32(rtwdev, R_BE_PCIE_MIT0_CNT, val); +} + +static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + int ret; + + ret = info->ltr_set(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "pci ltr set fail\n"); + return ret; + } + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_IGNORE, + MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_ENABLE); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, true); + rtw89_pci_ctrl_txdma_ch_be(rtwdev, true, true); + rtw89_pci_configure_mit_be(rtwdev); + + return 0; +} + const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, + .mac_post_init = rtw89_pci_ops_mac_post_init_be, .clr_idx_all = rtw89_pci_clr_idx_all_be, }; From ca76817f4c4bbf8f98268772f4eeea8382a34bcd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 2 Nov 2023 08:37:16 +0800 Subject: [PATCH 0287/7721] wifi: rtw89: coex: use struct assignment to replace memcpy() to append TDMA content To notify firmware TDMA timeslot assignment, append TDMA parameters when sending policy H2C firmware command. However, compiler warns we do memcpy() data to val[] field of TLV struct. To avoid this, assign the struct value with simple '=' instead. Compile tested only. rtw89/coex.c: In function '_append_tdma': drivers/net/wireless/realtek/rtw89/coex.c:1585:17: warning: writing 8 bytes into a region of size 0 [-Wstringop-overflow=] 1585 | memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/net/wireless/realtek/rtw89/coex.h:8, from drivers/net/wireless/realtek/rtw89/coex.c:5: drivers/net/wireless/realtek/rtw89/core.h:2703:37: note: at offset [5714, 71249] into destination object 'ver' of size 8 2703 | const struct rtw89_btc_ver *ver; | ^~~ drivers/net/wireless/realtek/rtw89/coex.c:1579:17: warning: writing 8 bytes into a region of size 0 [-Wstringop-overflow=] 1579 | memcpy(v, &dm->tdma, sizeof(*v)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/realtek/rtw89/core.h:2703:37: note: at offset [5710, 71245] into destination object 'ver' of size 8 2703 | const struct rtw89_btc_ver *ver; | ^~~ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310301908.Wrj0diqe-lkp@intel.com/ Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231102003716.25815-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index bdcc172639e4..b842cd9a86f8 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -1576,13 +1576,13 @@ static void _append_tdma(struct rtw89_dev *rtwdev) if (ver->fcxtdma == 1) { v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0]; tlv->len = sizeof(*v); - memcpy(v, &dm->tdma, sizeof(*v)); + *v = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); } else { tlv->len = sizeof(*v3); v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0]; v3->fver = ver->fcxtdma; - memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); + v3->tdma = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3); } From ed4f0c195e8fba06fa5c1072ade7feaadb91c03d Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 2 Nov 2023 14:55:55 +0300 Subject: [PATCH 0288/7721] wifi: rtw88: simplify __rtw_tx_work() Since 'ieee80211_txq_get_depth()' allows NULL for 2nd and 3rd arguments, simplify '__rtw_tx_work()' by dropping unused 'byte_cnt'. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231102115606.69838-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw88/tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index f63900b6621d..c02ac673be32 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -656,9 +656,8 @@ void __rtw_tx_work(struct rtw_dev *rtwdev) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); unsigned long frame_cnt; - unsigned long byte_cnt; - ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + ieee80211_txq_get_depth(txq, &frame_cnt, NULL); rtw_txq_push(rtwdev, rtwtxq, frame_cnt); list_del_init(&rtwtxq->list); From 53ee0b3b99edc6a47096bffef15695f5a895386f Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 3 Nov 2023 10:08:51 +0800 Subject: [PATCH 0289/7721] wifi: rtw88: fix RX filter in FIF_ALLMULTI flag The broadcast packets will be filtered in the FIF_ALLMULTI flag in the original code, which causes beacon packets to be filtered out and disconnection. Therefore, we fix it. Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231103020851.102238-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/mac80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index a99b53d44267..d8d68f16014e 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -280,9 +280,9 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) - rtwdev->hal.rcr |= BIT_AM | BIT_AB; + rtwdev->hal.rcr |= BIT_AM; else - rtwdev->hal.rcr &= ~(BIT_AM | BIT_AB); + rtwdev->hal.rcr &= ~(BIT_AM); } if (changed_flags & FIF_FCSFAIL) { if (*new_flags & FIF_FCSFAIL) From b1275cdd7456ef811747dfb4f3c46310ddd300cd Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sat, 4 Nov 2023 16:57:58 +0800 Subject: [PATCH 0290/7721] wifi: rt2x00: introduce DMA busy check watchdog for rt2800 When I tried to fix the watchdog of rt2800, I found that sometimes the watchdog can not reset the hung device. This is because the queue is not completely stuck, it just becomes very slow. The MTK vendor driver for the new chip MT7603/MT7612 has a DMA busy watchdog to detect device hangs by checking DMA busy status. This watchdog implementation is something similar to it. To reduce unnecessary reset, we can check the INT_SOURCE_CSR register together as I found that when the radio hung, the RX/TX coherent interrupt will always stuck at triggered state. The 'watchdog' module parameter has been extended to control all watchdogs(0=disabled, 1=hang watchdog, 2=DMA watchdog, 3=both). This new watchdog function is a slight schedule and it won't affect the transmission speed. So we can turn on it by default. Due to the INT_SOURCE_CSR register is invalid on rt2800 USB NICs, the DMA busy watchdog will be automatically disabled for them. Tested on MT7620 and RT5350. Signed-off-by: Shiji Yang Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYAP286MB0315D7462CE08A119A99DE34BCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM --- drivers/net/wireless/ralink/rt2x00/rt2800.h | 4 + .../net/wireless/ralink/rt2x00/rt2800lib.c | 77 ++++++++++++++++--- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 + 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h index 48521e45577d..8930589b4967 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h @@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word { */ #define BCN_TBTT_OFFSET 64 +/* Watchdog type mask */ +#define RT2800_WATCHDOG_HANG BIT(0) +#define RT2800_WATCHDOG_DMA_BUSY BIT(1) + #endif /* RT2800_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index ee880f749b3c..532b6c60c8b1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -30,9 +30,10 @@ #include "rt2800lib.h" #include "rt2800.h" -static bool modparam_watchdog; -module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO); -MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected"); +static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY; +module_param_named(watchdog, modparam_watchdog, uint, 0444); +MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n" + "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)"); /* * Register access. @@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev) chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); } -void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; bool hung_tx = false; bool hung_rx = false; - if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) - return; - rt2800_update_survey(rt2x00dev); queue_for_each(rt2x00dev, queue) { @@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) } } + if (!hung_tx && !hung_rx) + return false; + if (hung_tx) rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n"); if (hung_rx) rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n"); - if (hung_tx || hung_rx) { - queue_for_each(rt2x00dev, queue) - queue->wd_count = 0; + queue_for_each(rt2x00dev, queue) + queue->wd_count = 0; + return true; +} + +static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev) +{ + bool busy_rx, busy_tx; + u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); + u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR); + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT)) + rt2x00dev->rxdma_busy++; + else + rt2x00dev->rxdma_busy = 0; + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT)) + rt2x00dev->txdma_busy++; + else + rt2x00dev->txdma_busy = 0; + + busy_rx = rt2x00dev->rxdma_busy > 30 ? true : false; + busy_tx = rt2x00dev->txdma_busy > 30 ? true : false; + + if (!busy_rx && !busy_tx) + return false; + + if (busy_rx) + rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n"); + + if (busy_tx) + rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n"); + + rt2x00dev->rxdma_busy = 0; + rt2x00dev->txdma_busy = 0; + + return true; +} + +void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +{ + bool reset = false; + + if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) + return; + + if (modparam_watchdog & RT2800_WATCHDOG_DMA_BUSY) + reset = rt2800_watchdog_dma_busy(rt2x00dev); + + if (modparam_watchdog & RT2800_WATCHDOG_HANG) + reset = rt2800_watchdog_hung(rt2x00dev) || reset; + + if (reset) ieee80211_restart_hw(rt2x00dev->hw); - } } EXPORT_SYMBOL_GPL(rt2800_watchdog); @@ -12013,6 +12065,9 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); } + /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */ + if (rt2x00_is_usb(rt2x00dev)) + modparam_watchdog &= ~RT2800_WATCHDOG_DMA_BUSY; if (modparam_watchdog) { __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags); rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index aaaf99331967..62fed38f41c0 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -926,6 +926,9 @@ struct rt2x00_dev { */ u16 beacon_int; + /* Rx/Tx DMA busy watchdog counter */ + u16 rxdma_busy, txdma_busy; + /** * Timestamp of last received beacon */ From 570beb6285fd355904b22625da20809f477096c5 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sat, 4 Nov 2023 16:57:59 +0800 Subject: [PATCH 0291/7721] wifi: rt2x00: disable RTS threshold for rt2800 by default rt2800 has a lot of registers to control the RTS enable/disable status for different rates. And the driver control them via rt2800_set_rts_threshold(). When RTS was disabled in user interface, this function won't be called at all. This means that the RTS is still 'on' for CCK and OFDM rates. So we'd better to disable them by default because it should be like this. The RTS for HT20 and HT40 is already default off so we don't need to touch them. If we toggle the RTS status, these register bits will be enable/disable again by rt2800_set_rts_threshold(). Signed-off-by: Shiji Yang Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYAP286MB03155DDB953155B7A2DE849ABCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 532b6c60c8b1..70cd35d90338 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -6100,7 +6100,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); @@ -6113,7 +6113,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); From a11d965a218f0cd95b13fe44d0bcd8a20ce134a8 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sat, 4 Nov 2023 16:58:00 +0800 Subject: [PATCH 0292/7721] wifi: rt2x00: restart beacon queue when hardware reset When a hardware reset is triggered, all registers are reset, so all queues are forced to stop in hardware interface. However, mac80211 will not automatically stop the queue. If we don't manually stop the beacon queue, the queue will be deadlocked and unable to start again. This patch fixes the issue where Apple devices cannot connect to the AP after calling ieee80211_restart_hw(). Signed-off-by: Shiji Yang Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYAP286MB031530EB6D98DCE4DF20766CBCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM --- drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 3 +++ drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index c88ce446e117..9e7d9dbe954c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -101,6 +101,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00link_stop_tuner(rt2x00dev); rt2x00queue_stop_queues(rt2x00dev); rt2x00queue_flush_queues(rt2x00dev, true); + rt2x00queue_stop_queue(rt2x00dev->bcn); /* * Disable radio. @@ -1286,6 +1287,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + rt2x00dev->intf_beaconing = 0; /* Enable the radio */ retval = rt2x00lib_enable_radio(rt2x00dev); @@ -1312,6 +1314,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + rt2x00dev->intf_beaconing = 0; } static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 4202c6517783..75fda72c14ca 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -598,6 +598,17 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ if (changes & BSS_CHANGED_BEACON_ENABLED) { mutex_lock(&intf->beacon_skb_mutex); + + /* + * Clear the 'enable_beacon' flag and clear beacon because + * the beacon queue has been stopped after hardware reset. + */ + if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) && + intf->enable_beacon) { + intf->enable_beacon = false; + rt2x00queue_clear_beacon(rt2x00dev, vif); + } + if (!bss_conf->enable_beacon && intf->enable_beacon) { rt2x00dev->intf_beaconing--; intf->enable_beacon = false; From bae9fca9684335478ff147413bd69c8d77b66cf9 Mon Sep 17 00:00:00 2001 From: Sam James Date: Tue, 7 Nov 2023 21:55:33 +0000 Subject: [PATCH 0293/7721] drm: i915: Adapt to -Walloc-size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 14 introduces a new -Walloc-size included in -Wextra which errors out like: ``` drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c: In function ‘eb_copy_relocations’: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:1681:24: error: allocation of insufficient size ‘1’ for type ‘struct drm_i915_gem_relocation_entry’ with size ‘32’ [-Werror=alloc-size] 1681 | relocs = kvmalloc_array(size, 1, GFP_KERNEL); | ^ ``` So, just swap the number of members and size arguments to match the prototype, as we're initialising 1 element of size `size`. GCC then sees we're not doing anything wrong. Signed-off-by: Sam James Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231107215538.1891359-1-sam@gentoo.org --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 683fd8d3151c..45b9d9e34b8b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -1678,7 +1678,7 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb) urelocs = u64_to_user_ptr(eb->exec[i].relocs_ptr); size = nreloc * sizeof(*relocs); - relocs = kvmalloc_array(size, 1, GFP_KERNEL); + relocs = kvmalloc_array(1, size, GFP_KERNEL); if (!relocs) { err = -ENOMEM; goto err; From 078a5b498d6a3e9c2acb637427258eb6b3079923 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 25 Oct 2023 15:24:27 +0200 Subject: [PATCH 0294/7721] drm/tests: Remove slow tests Both the drm_buddy and drm_mm tests have been converted from selftest to kunit recently. However, a significant portion of them are trying to exert some part of their API over a huge number of iterations and with random variations of their parameters. They are thus more a way to discover new bugs than actual unit tests. This is fine in itself but leads to very slow runtime (up to 25s for some drm_test_mm_reserve and drm_test_mm_insert on a Ryzen 7950x while running the tests in qemu) which make them a poor fit for kunit. Let's remove those tests from the drm_mm and drm_buddy test suites for now, and if it's ever needed we can always create proper unit tests for them later on. This made the entire DRM tests execution time (as of v6.6-rc1) come from 65s to less than .5s on a Ryzen 7950x system when running under qemu, and from 9 minutes to about 4s on a RaspberryPi4. Acked-by: Daniel Vetter Suggested-by: Daniel Vetter Link: https://lore.kernel.org/r/20231025132428.723672-1-mripard@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_buddy_test.c | 465 ------ drivers/gpu/drm/tests/drm_mm_test.c | 1904 ------------------------ 2 files changed, 2369 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index 09ee6f6af896..ea2af6bd9abe 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -13,315 +13,11 @@ #include "../lib/drm_random.h" -#define TIMEOUT(name__) \ - unsigned long name__ = jiffies + MAX_SCHEDULE_TIMEOUT - -static unsigned int random_seed; - static inline u64 get_size(int order, u64 chunk_size) { return (1 << order) * chunk_size; } -__printf(2, 3) -static bool __timeout(unsigned long timeout, const char *fmt, ...) -{ - va_list va; - - if (!signal_pending(current)) { - cond_resched(); - if (time_before(jiffies, timeout)) - return false; - } - - if (fmt) { - va_start(va, fmt); - vprintk(fmt, va); - va_end(va); - } - - return true; -} - -static void __dump_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block, bool buddy) -{ - kunit_err(test, "block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%d buddy=%d\n", - block->header, drm_buddy_block_state(block), - drm_buddy_block_order(block), drm_buddy_block_offset(block), - drm_buddy_block_size(mm, block), !block->parent, buddy); -} - -static void dump_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *buddy; - - __dump_block(test, mm, block, false); - - buddy = drm_get_buddy(block); - if (buddy) - __dump_block(test, mm, buddy, true); -} - -static int check_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *buddy; - unsigned int block_state; - u64 block_size; - u64 offset; - int err = 0; - - block_state = drm_buddy_block_state(block); - - if (block_state != DRM_BUDDY_ALLOCATED && - block_state != DRM_BUDDY_FREE && block_state != DRM_BUDDY_SPLIT) { - kunit_err(test, "block state mismatch\n"); - err = -EINVAL; - } - - block_size = drm_buddy_block_size(mm, block); - offset = drm_buddy_block_offset(block); - - if (block_size < mm->chunk_size) { - kunit_err(test, "block size smaller than min size\n"); - err = -EINVAL; - } - - /* We can't use is_power_of_2() for a u64 on 32-bit systems. */ - if (block_size & (block_size - 1)) { - kunit_err(test, "block size not power of two\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(block_size, mm->chunk_size)) { - kunit_err(test, "block size not aligned to min size\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(offset, mm->chunk_size)) { - kunit_err(test, "block offset not aligned to min size\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(offset, block_size)) { - kunit_err(test, "block offset not aligned to block size\n"); - err = -EINVAL; - } - - buddy = drm_get_buddy(block); - - if (!buddy && block->parent) { - kunit_err(test, "buddy has gone fishing\n"); - err = -EINVAL; - } - - if (buddy) { - if (drm_buddy_block_offset(buddy) != (offset ^ block_size)) { - kunit_err(test, "buddy has wrong offset\n"); - err = -EINVAL; - } - - if (drm_buddy_block_size(mm, buddy) != block_size) { - kunit_err(test, "buddy size mismatch\n"); - err = -EINVAL; - } - - if (drm_buddy_block_state(buddy) == block_state && - block_state == DRM_BUDDY_FREE) { - kunit_err(test, "block and its buddy are free\n"); - err = -EINVAL; - } - } - - return err; -} - -static int check_blocks(struct kunit *test, struct drm_buddy *mm, - struct list_head *blocks, u64 expected_size, bool is_contiguous) -{ - struct drm_buddy_block *block; - struct drm_buddy_block *prev; - u64 total; - int err = 0; - - block = NULL; - prev = NULL; - total = 0; - - list_for_each_entry(block, blocks, link) { - err = check_block(test, mm, block); - - if (!drm_buddy_block_is_allocated(block)) { - kunit_err(test, "block not allocated\n"); - err = -EINVAL; - } - - if (is_contiguous && prev) { - u64 prev_block_size; - u64 prev_offset; - u64 offset; - - prev_offset = drm_buddy_block_offset(prev); - prev_block_size = drm_buddy_block_size(mm, prev); - offset = drm_buddy_block_offset(block); - - if (offset != (prev_offset + prev_block_size)) { - kunit_err(test, "block offset mismatch\n"); - err = -EINVAL; - } - } - - if (err) - break; - - total += drm_buddy_block_size(mm, block); - prev = block; - } - - if (!err) { - if (total != expected_size) { - kunit_err(test, "size mismatch, expected=%llx, found=%llx\n", - expected_size, total); - err = -EINVAL; - } - return err; - } - - if (prev) { - kunit_err(test, "prev block, dump:\n"); - dump_block(test, mm, prev); - } - - kunit_err(test, "bad block, dump:\n"); - dump_block(test, mm, block); - - return err; -} - -static int check_mm(struct kunit *test, struct drm_buddy *mm) -{ - struct drm_buddy_block *root; - struct drm_buddy_block *prev; - unsigned int i; - u64 total; - int err = 0; - - if (!mm->n_roots) { - kunit_err(test, "n_roots is zero\n"); - return -EINVAL; - } - - if (mm->n_roots != hweight64(mm->size)) { - kunit_err(test, "n_roots mismatch, n_roots=%u, expected=%lu\n", - mm->n_roots, hweight64(mm->size)); - return -EINVAL; - } - - root = NULL; - prev = NULL; - total = 0; - - for (i = 0; i < mm->n_roots; ++i) { - struct drm_buddy_block *block; - unsigned int order; - - root = mm->roots[i]; - if (!root) { - kunit_err(test, "root(%u) is NULL\n", i); - err = -EINVAL; - break; - } - - err = check_block(test, mm, root); - - if (!drm_buddy_block_is_free(root)) { - kunit_err(test, "root not free\n"); - err = -EINVAL; - } - - order = drm_buddy_block_order(root); - - if (!i) { - if (order != mm->max_order) { - kunit_err(test, "max order root missing\n"); - err = -EINVAL; - } - } - - if (prev) { - u64 prev_block_size; - u64 prev_offset; - u64 offset; - - prev_offset = drm_buddy_block_offset(prev); - prev_block_size = drm_buddy_block_size(mm, prev); - offset = drm_buddy_block_offset(root); - - if (offset != (prev_offset + prev_block_size)) { - kunit_err(test, "root offset mismatch\n"); - err = -EINVAL; - } - } - - block = list_first_entry_or_null(&mm->free_list[order], - struct drm_buddy_block, link); - if (block != root) { - kunit_err(test, "root mismatch at order=%u\n", order); - err = -EINVAL; - } - - if (err) - break; - - prev = root; - total += drm_buddy_block_size(mm, root); - } - - if (!err) { - if (total != mm->size) { - kunit_err(test, "expected mm size=%llx, found=%llx\n", - mm->size, total); - err = -EINVAL; - } - return err; - } - - if (prev) { - kunit_err(test, "prev root(%u), dump:\n", i - 1); - dump_block(test, mm, prev); - } - - if (root) { - kunit_err(test, "bad root(%u), dump:\n", i); - dump_block(test, mm, root); - } - - return err; -} - -static void mm_config(u64 *size, u64 *chunk_size) -{ - DRM_RND_STATE(prng, random_seed); - u32 s, ms; - - /* Nothing fancy, just try to get an interesting bit pattern */ - - prandom_seed_state(&prng, random_seed); - - /* Let size be a random number of pages up to 8 GB (2M pages) */ - s = 1 + drm_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); - /* Let the chunk size be a random power of 2 less than size */ - ms = BIT(drm_prandom_u32_max_state(ilog2(s), &prng)); - /* Round size down to the chunk size */ - s &= -ms; - - /* Convert from pages to bytes */ - *chunk_size = (u64)ms << 12; - *size = (u64)s << 12; -} - static void drm_test_buddy_alloc_pathological(struct kunit *test) { u64 mm_size, size, start = 0; @@ -403,96 +99,6 @@ static void drm_test_buddy_alloc_pathological(struct kunit *test) drm_buddy_fini(&mm); } -static void drm_test_buddy_alloc_smoke(struct kunit *test) -{ - u64 mm_size, chunk_size, start = 0; - unsigned long flags = 0; - struct drm_buddy mm; - int *order; - int i; - - DRM_RND_STATE(prng, random_seed); - TIMEOUT(end_time); - - mm_config(&mm_size, &chunk_size); - - KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, chunk_size), - "buddy_init failed\n"); - - order = drm_random_order(mm.max_order + 1, &prng); - KUNIT_ASSERT_TRUE(test, order); - - for (i = 0; i <= mm.max_order; ++i) { - struct drm_buddy_block *block; - int max_order = order[i]; - bool timeout = false; - LIST_HEAD(blocks); - u64 total, size; - LIST_HEAD(tmp); - int order, err; - - KUNIT_ASSERT_FALSE_MSG(test, check_mm(test, &mm), - "pre-mm check failed, abort\n"); - - order = max_order; - total = 0; - - do { -retry: - size = get_size(order, chunk_size); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, size, &tmp, flags); - if (err) { - if (err == -ENOMEM) { - KUNIT_FAIL(test, "buddy_alloc hit -ENOMEM with order=%d\n", - order); - } else { - if (order--) { - err = 0; - goto retry; - } - - KUNIT_FAIL(test, "buddy_alloc with order=%d failed\n", - order); - } - - break; - } - - block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); - KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); - - list_move_tail(&block->link, &blocks); - KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_order(block), order, - "buddy_alloc order mismatch\n"); - - total += drm_buddy_block_size(&mm, block); - - if (__timeout(end_time, NULL)) { - timeout = true; - break; - } - } while (total < mm.size); - - if (!err) - err = check_blocks(test, &mm, &blocks, total, false); - - drm_buddy_free_list(&mm, &blocks); - - if (!err) { - KUNIT_EXPECT_FALSE_MSG(test, check_mm(test, &mm), - "post-mm check failed\n"); - } - - if (err || timeout) - break; - - cond_resched(); - } - - kfree(order); - drm_buddy_fini(&mm); -} - static void drm_test_buddy_alloc_pessimistic(struct kunit *test) { u64 mm_size, size, start = 0; @@ -634,64 +240,6 @@ static void drm_test_buddy_alloc_optimistic(struct kunit *test) drm_buddy_fini(&mm); } -static void drm_test_buddy_alloc_range(struct kunit *test) -{ - unsigned long flags = DRM_BUDDY_RANGE_ALLOCATION; - u64 offset, size, rem, chunk_size, end; - unsigned long page_num; - struct drm_buddy mm; - LIST_HEAD(blocks); - - mm_config(&size, &chunk_size); - - KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, size, chunk_size), - "buddy_init failed"); - - KUNIT_ASSERT_FALSE_MSG(test, check_mm(test, &mm), - "pre-mm check failed, abort!"); - - rem = mm.size; - offset = 0; - - for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { - struct drm_buddy_block *block; - LIST_HEAD(tmp); - - size = min(page_num * mm.chunk_size, rem); - end = offset + size; - - KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, offset, end, - size, mm.chunk_size, - &tmp, flags), - "alloc_range with offset=%llx, size=%llx failed\n", offset, size); - - block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); - KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_range has no blocks\n"); - - KUNIT_ASSERT_EQ_MSG(test, drm_buddy_block_offset(block), offset, - "alloc_range start offset mismatch, found=%llx, expected=%llx\n", - drm_buddy_block_offset(block), offset); - - KUNIT_ASSERT_FALSE(test, check_blocks(test, &mm, &tmp, size, true)); - - list_splice_tail(&tmp, &blocks); - - offset += size; - - rem -= size; - if (!rem) - break; - - cond_resched(); - } - - drm_buddy_free_list(&mm, &blocks); - - KUNIT_EXPECT_FALSE_MSG(test, check_mm(test, &mm), "post-mm check failed\n"); - - drm_buddy_fini(&mm); -} - static void drm_test_buddy_alloc_limit(struct kunit *test) { u64 size = U64_MAX, start = 0; @@ -727,29 +275,16 @@ static void drm_test_buddy_alloc_limit(struct kunit *test) drm_buddy_fini(&mm); } -static int drm_buddy_suite_init(struct kunit_suite *suite) -{ - while (!random_seed) - random_seed = get_random_u32(); - - kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n", random_seed); - - return 0; -} - static struct kunit_case drm_buddy_tests[] = { KUNIT_CASE(drm_test_buddy_alloc_limit), - KUNIT_CASE(drm_test_buddy_alloc_range), KUNIT_CASE(drm_test_buddy_alloc_optimistic), KUNIT_CASE(drm_test_buddy_alloc_pessimistic), - KUNIT_CASE(drm_test_buddy_alloc_smoke), KUNIT_CASE(drm_test_buddy_alloc_pathological), {} }; static struct kunit_suite drm_buddy_test_suite = { .name = "drm_buddy", - .suite_init = drm_buddy_suite_init, .test_cases = drm_buddy_tests, }; diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c index 186b28dc7038..4e9247cf9977 100644 --- a/drivers/gpu/drm/tests/drm_mm_test.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -17,10 +17,6 @@ #include "../lib/drm_random.h" -static unsigned int random_seed; -static unsigned int max_iterations = 8192; -static unsigned int max_prime = 128; - enum { BEST, BOTTOMUP, @@ -37,10 +33,6 @@ static const struct insert_mode { [TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH }, [EVICT] = { "evict", DRM_MM_INSERT_EVICT }, {} -}, evict_modes[] = { - { "bottom-up", DRM_MM_INSERT_LOW }, - { "top-down", DRM_MM_INSERT_HIGH }, - {} }; static bool assert_no_holes(struct kunit *test, const struct drm_mm *mm) @@ -97,57 +89,6 @@ static bool assert_one_hole(struct kunit *test, const struct drm_mm *mm, u64 sta return ok; } -static bool assert_continuous(struct kunit *test, const struct drm_mm *mm, u64 size) -{ - struct drm_mm_node *node, *check, *found; - unsigned long n; - u64 addr; - - if (!assert_no_holes(test, mm)) - return false; - - n = 0; - addr = 0; - drm_mm_for_each_node(node, mm) { - if (node->start != addr) { - KUNIT_FAIL(test, "node[%ld] list out of order, expected %llx found %llx\n", - n, addr, node->start); - return false; - } - - if (node->size != size) { - KUNIT_FAIL(test, "node[%ld].size incorrect, expected %llx, found %llx\n", - n, size, node->size); - return false; - } - - if (drm_mm_hole_follows(node)) { - KUNIT_FAIL(test, "node[%ld] is followed by a hole!\n", n); - return false; - } - - found = NULL; - drm_mm_for_each_node_in_range(check, mm, addr, addr + size) { - if (node != check) { - KUNIT_FAIL(test, - "lookup return wrong node, expected start %llx, found %llx\n", - node->start, check->start); - return false; - } - found = check; - } - if (!found) { - KUNIT_FAIL(test, "lookup failed for node %llx + %llx\n", addr, size); - return false; - } - - addr += size; - n++; - } - - return true; -} - static u64 misalignment(struct drm_mm_node *node, u64 alignment) { u64 rem; @@ -270,215 +211,6 @@ static void drm_test_mm_debug(struct kunit *test) nodes[0].start, nodes[0].size); } -static struct drm_mm_node *set_node(struct drm_mm_node *node, - u64 start, u64 size) -{ - node->start = start; - node->size = size; - return node; -} - -static bool expect_reserve_fail(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node) -{ - int err; - - err = drm_mm_reserve_node(mm, node); - if (likely(err == -ENOSPC)) - return true; - - if (!err) { - KUNIT_FAIL(test, "impossible reserve succeeded, node %llu + %llu\n", - node->start, node->size); - drm_mm_remove_node(node); - } else { - KUNIT_FAIL(test, - "impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", - err, -ENOSPC, node->start, node->size); - } - return false; -} - -static bool noinline_for_stack check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, - unsigned int count, - u64 size) -{ - const struct boundary { - u64 start, size; - const char *name; - } boundaries[] = { -#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" } - B(0, 0), - B(-size, 0), - B(size, 0), - B(size * count, 0), - B(-size, size), - B(-size, -size), - B(-size, 2 * size), - B(0, -size), - B(size, -size), - B(count * size, size), - B(count * size, -size), - B(count * size, count * size), - B(count * size, -count * size), - B(count * size, -(count + 1) * size), - B((count + 1) * size, size), - B((count + 1) * size, -size), - B((count + 1) * size, -2 * size), -#undef B - }; - struct drm_mm_node tmp = {}; - int n; - - for (n = 0; n < ARRAY_SIZE(boundaries); n++) { - if (!expect_reserve_fail(test, mm, set_node(&tmp, boundaries[n].start, - boundaries[n].size))) { - KUNIT_FAIL(test, "boundary[%d:%s] failed, count=%u, size=%lld\n", - n, boundaries[n].name, count, size); - return false; - } - } - - return true; -} - -static int __drm_test_mm_reserve(struct kunit *test, unsigned int count, u64 size) -{ - DRM_RND_STATE(prng, random_seed); - struct drm_mm mm; - struct drm_mm_node tmp, *nodes, *node, *next; - unsigned int *order, n, m, o = 0; - int ret, err; - - /* For exercising drm_mm_reserve_node(), we want to check that - * reservations outside of the drm_mm range are rejected, and to - * overlapping and otherwise already occupied ranges. Afterwards, - * the tree and nodes should be intact. - */ - - DRM_MM_BUG_ON(!count); - DRM_MM_BUG_ON(!size); - - ret = -ENOMEM; - order = drm_random_order(count, &prng); - if (!order) - goto err; - - nodes = vzalloc(array_size(count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - ret = -EINVAL; - drm_mm_init(&mm, 0, count * size); - - if (!check_reserve_boundaries(test, &mm, count, size)) - goto out; - - for (n = 0; n < count; n++) { - nodes[n].start = order[n] * size; - nodes[n].size = size; - - err = drm_mm_reserve_node(&mm, &nodes[n]); - if (err) { - KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", - n, nodes[n].start); - ret = err; - goto out; - } - - if (!drm_mm_node_allocated(&nodes[n])) { - KUNIT_FAIL(test, "reserved node not allocated! step %d, start %llu\n", - n, nodes[n].start); - goto out; - } - - if (!expect_reserve_fail(test, &mm, &nodes[n])) - goto out; - } - - /* After random insertion the nodes should be in order */ - if (!assert_continuous(test, &mm, size)) - goto out; - - /* Repeated use should then fail */ - drm_random_reorder(order, count, &prng); - for (n = 0; n < count; n++) { - if (!expect_reserve_fail(test, &mm, set_node(&tmp, order[n] * size, 1))) - goto out; - - /* Remove and reinsert should work */ - drm_mm_remove_node(&nodes[order[n]]); - err = drm_mm_reserve_node(&mm, &nodes[order[n]]); - if (err) { - KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", - n, nodes[n].start); - ret = err; - goto out; - } - } - - if (!assert_continuous(test, &mm, size)) - goto out; - - /* Overlapping use should then fail */ - for (n = 0; n < count; n++) { - if (!expect_reserve_fail(test, &mm, set_node(&tmp, 0, size * count))) - goto out; - } - for (n = 0; n < count; n++) { - if (!expect_reserve_fail(test, &mm, set_node(&tmp, size * n, size * (count - n)))) - goto out; - } - - /* Remove several, reinsert, check full */ - for_each_prime_number(n, min(max_prime, count)) { - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - drm_mm_remove_node(node); - } - - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - err = drm_mm_reserve_node(&mm, node); - if (err) { - KUNIT_FAIL(test, "reserve failed, step %d/%d, start %llu\n", - m, n, node->start); - ret = err; - goto out; - } - } - - o += n; - - if (!assert_continuous(test, &mm, size)) - goto out; - } - - ret = 0; -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - vfree(nodes); - kfree(order); -err: - return ret; -} - -static void drm_test_mm_reserve(struct kunit *test) -{ - const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); - int n; - - for_each_prime_number_from(n, 1, 54) { - u64 size = BIT_ULL(n); - - KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size - 1)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size + 1)); - - cond_resched(); - } -} - static bool expect_insert(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, const struct insert_mode *mode) @@ -503,600 +235,6 @@ static bool expect_insert(struct kunit *test, struct drm_mm *mm, return true; } -static bool expect_insert_fail(struct kunit *test, struct drm_mm *mm, u64 size) -{ - struct drm_mm_node tmp = {}; - int err; - - err = drm_mm_insert_node(mm, &tmp, size); - if (likely(err == -ENOSPC)) - return true; - - if (!err) { - KUNIT_FAIL(test, "impossible insert succeeded, node %llu + %llu\n", - tmp.start, tmp.size); - drm_mm_remove_node(&tmp); - } else { - KUNIT_FAIL(test, - "impossible insert failed with wrong error %d [expected %d], size %llu\n", - err, -ENOSPC, size); - } - return false; -} - -static int __drm_test_mm_insert(struct kunit *test, unsigned int count, u64 size, bool replace) -{ - DRM_RND_STATE(prng, random_seed); - const struct insert_mode *mode; - struct drm_mm mm; - struct drm_mm_node *nodes, *node, *next; - unsigned int *order, n, m, o = 0; - int ret; - - /* Fill a range with lots of nodes, check it doesn't fail too early */ - - DRM_MM_BUG_ON(!count); - DRM_MM_BUG_ON(!size); - - ret = -ENOMEM; - nodes = vmalloc(array_size(count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - order = drm_random_order(count, &prng); - if (!order) - goto err_nodes; - - ret = -EINVAL; - drm_mm_init(&mm, 0, count * size); - - for (mode = insert_modes; mode->name; mode++) { - for (n = 0; n < count; n++) { - struct drm_mm_node tmp; - - node = replace ? &tmp : &nodes[n]; - memset(node, 0, sizeof(*node)); - if (!expect_insert(test, &mm, node, size, 0, n, mode)) { - KUNIT_FAIL(test, "%s insert failed, size %llu step %d\n", - mode->name, size, n); - goto out; - } - - if (replace) { - drm_mm_replace_node(&tmp, &nodes[n]); - if (drm_mm_node_allocated(&tmp)) { - KUNIT_FAIL(test, - "replaced old-node still allocated! step %d\n", - n); - goto out; - } - - if (!assert_node(test, &nodes[n], &mm, size, 0, n)) { - KUNIT_FAIL(test, - "replaced node did not inherit parameters, size %llu step %d\n", - size, n); - goto out; - } - - if (tmp.start != nodes[n].start) { - KUNIT_FAIL(test, - "replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", - tmp.start, size, nodes[n].start, nodes[n].size); - goto out; - } - } - } - - /* After random insertion the nodes should be in order */ - if (!assert_continuous(test, &mm, size)) - goto out; - - /* Repeated use should then fail */ - if (!expect_insert_fail(test, &mm, size)) - goto out; - - /* Remove one and reinsert, as the only hole it should refill itself */ - for (n = 0; n < count; n++) { - u64 addr = nodes[n].start; - - drm_mm_remove_node(&nodes[n]); - if (!expect_insert(test, &mm, &nodes[n], size, 0, n, mode)) { - KUNIT_FAIL(test, "%s reinsert failed, size %llu step %d\n", - mode->name, size, n); - goto out; - } - - if (nodes[n].start != addr) { - KUNIT_FAIL(test, - "%s reinsert node moved, step %d, expected %llx, found %llx\n", - mode->name, n, addr, nodes[n].start); - goto out; - } - - if (!assert_continuous(test, &mm, size)) - goto out; - } - - /* Remove several, reinsert, check full */ - for_each_prime_number(n, min(max_prime, count)) { - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - drm_mm_remove_node(node); - } - - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - if (!expect_insert(test, &mm, node, size, 0, n, mode)) { - KUNIT_FAIL(test, - "%s multiple reinsert failed, size %llu step %d\n", - mode->name, size, n); - goto out; - } - } - - o += n; - - if (!assert_continuous(test, &mm, size)) - goto out; - - if (!expect_insert_fail(test, &mm, size)) - goto out; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - DRM_MM_BUG_ON(!drm_mm_clean(&mm)); - - cond_resched(); - } - - ret = 0; -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_nodes: - vfree(nodes); - return ret; -} - -static void drm_test_mm_insert(struct kunit *test) -{ - const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); - unsigned int n; - - for_each_prime_number_from(n, 1, 54) { - u64 size = BIT_ULL(n); - - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, false)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, false)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, false)); - - cond_resched(); - } -} - -static void drm_test_mm_replace(struct kunit *test) -{ - const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); - unsigned int n; - - /* Reuse __drm_test_mm_insert to exercise replacement by inserting a dummy node, - * then replacing it with the intended node. We want to check that - * the tree is intact and all the information we need is carried - * across to the target node. - */ - - for_each_prime_number_from(n, 1, 54) { - u64 size = BIT_ULL(n); - - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, true)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, true)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, true)); - - cond_resched(); - } -} - -static bool expect_insert_in_range(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node, - u64 size, u64 alignment, unsigned long color, - u64 range_start, u64 range_end, const struct insert_mode *mode) -{ - int err; - - err = drm_mm_insert_node_in_range(mm, node, - size, alignment, color, - range_start, range_end, - mode->mode); - if (err) { - KUNIT_FAIL(test, - "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", - size, alignment, color, mode->name, - range_start, range_end, err); - return false; - } - - if (!assert_node(test, node, mm, size, alignment, color)) { - drm_mm_remove_node(node); - return false; - } - - return true; -} - -static bool expect_insert_in_range_fail(struct kunit *test, struct drm_mm *mm, - u64 size, u64 range_start, u64 range_end) -{ - struct drm_mm_node tmp = {}; - int err; - - err = drm_mm_insert_node_in_range(mm, &tmp, size, 0, 0, range_start, range_end, - 0); - if (likely(err == -ENOSPC)) - return true; - - if (!err) { - KUNIT_FAIL(test, - "impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", - tmp.start, tmp.size, range_start, range_end); - drm_mm_remove_node(&tmp); - } else { - KUNIT_FAIL(test, - "impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", - err, -ENOSPC, size, range_start, range_end); - } - - return false; -} - -static bool assert_contiguous_in_range(struct kunit *test, struct drm_mm *mm, - u64 size, u64 start, u64 end) -{ - struct drm_mm_node *node; - unsigned int n; - - if (!expect_insert_in_range_fail(test, mm, size, start, end)) - return false; - - n = div64_u64(start + size - 1, size); - drm_mm_for_each_node(node, mm) { - if (node->start < start || node->start + node->size > end) { - KUNIT_FAIL(test, - "node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", - n, node->start, node->start + node->size, start, end); - return false; - } - - if (node->start != n * size) { - KUNIT_FAIL(test, "node %d out of order, expected start %llx, found %llx\n", - n, n * size, node->start); - return false; - } - - if (node->size != size) { - KUNIT_FAIL(test, "node %d has wrong size, expected size %llx, found %llx\n", - n, size, node->size); - return false; - } - - if (drm_mm_hole_follows(node) && drm_mm_hole_node_end(node) < end) { - KUNIT_FAIL(test, "node %d is followed by a hole!\n", n); - return false; - } - - n++; - } - - if (start > 0) { - node = __drm_mm_interval_first(mm, 0, start - 1); - if (drm_mm_node_allocated(node)) { - KUNIT_FAIL(test, "node before start: node=%llx+%llu, start=%llx\n", - node->start, node->size, start); - return false; - } - } - - if (end < U64_MAX) { - node = __drm_mm_interval_first(mm, end, U64_MAX); - if (drm_mm_node_allocated(node)) { - KUNIT_FAIL(test, "node after end: node=%llx+%llu, end=%llx\n", - node->start, node->size, end); - return false; - } - } - - return true; -} - -static int __drm_test_mm_insert_range(struct kunit *test, unsigned int count, u64 size, - u64 start, u64 end) -{ - const struct insert_mode *mode; - struct drm_mm mm; - struct drm_mm_node *nodes, *node, *next; - unsigned int n, start_n, end_n; - int ret; - - DRM_MM_BUG_ON(!count); - DRM_MM_BUG_ON(!size); - DRM_MM_BUG_ON(end <= start); - - /* Very similar to __drm_test_mm_insert(), but now instead of populating the - * full range of the drm_mm, we try to fill a small portion of it. - */ - - ret = -ENOMEM; - nodes = vzalloc(array_size(count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - ret = -EINVAL; - drm_mm_init(&mm, 0, count * size); - - start_n = div64_u64(start + size - 1, size); - end_n = div64_u64(end - size, size); - - for (mode = insert_modes; mode->name; mode++) { - for (n = start_n; n <= end_n; n++) { - if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, - start, end, mode)) { - KUNIT_FAIL(test, - "%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", - mode->name, size, n, start_n, end_n, start, end); - goto out; - } - } - - if (!assert_contiguous_in_range(test, &mm, size, start, end)) { - KUNIT_FAIL(test, - "%s: range [%llx, %llx] not full after initialisation, size=%llu\n", - mode->name, start, end, size); - goto out; - } - - /* Remove one and reinsert, it should refill itself */ - for (n = start_n; n <= end_n; n++) { - u64 addr = nodes[n].start; - - drm_mm_remove_node(&nodes[n]); - if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, - start, end, mode)) { - KUNIT_FAIL(test, "%s reinsert failed, step %d\n", mode->name, n); - goto out; - } - - if (nodes[n].start != addr) { - KUNIT_FAIL(test, - "%s reinsert node moved, step %d, expected %llx, found %llx\n", - mode->name, n, addr, nodes[n].start); - goto out; - } - } - - if (!assert_contiguous_in_range(test, &mm, size, start, end)) { - KUNIT_FAIL(test, - "%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", - mode->name, start, end, size); - goto out; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - DRM_MM_BUG_ON(!drm_mm_clean(&mm)); - - cond_resched(); - } - - ret = 0; -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - vfree(nodes); - return ret; -} - -static int insert_outside_range(struct kunit *test) -{ - struct drm_mm mm; - const unsigned int start = 1024; - const unsigned int end = 2048; - const unsigned int size = end - start; - - drm_mm_init(&mm, start, size); - - if (!expect_insert_in_range_fail(test, &mm, 1, 0, start)) - return -EINVAL; - - if (!expect_insert_in_range_fail(test, &mm, size, - start - size / 2, start + (size + 1) / 2)) - return -EINVAL; - - if (!expect_insert_in_range_fail(test, &mm, size, - end - (size + 1) / 2, end + size / 2)) - return -EINVAL; - - if (!expect_insert_in_range_fail(test, &mm, 1, end, end + size)) - return -EINVAL; - - drm_mm_takedown(&mm); - return 0; -} - -static void drm_test_mm_insert_range(struct kunit *test) -{ - const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); - unsigned int n; - - /* Check that requests outside the bounds of drm_mm are rejected. */ - KUNIT_ASSERT_FALSE(test, insert_outside_range(test)); - - for_each_prime_number_from(n, 1, 50) { - const u64 size = BIT_ULL(n); - const u64 max = count * size; - - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 1, max)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max - 1)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max / 2)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, - max / 2, max / 2)); - KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, - max / 4 + 1, 3 * max / 4 - 1)); - - cond_resched(); - } -} - -static int prepare_frag(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *nodes, - unsigned int num_insert, const struct insert_mode *mode) -{ - unsigned int size = 4096; - unsigned int i; - - for (i = 0; i < num_insert; i++) { - if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { - KUNIT_FAIL(test, "%s insert failed\n", mode->name); - return -EINVAL; - } - } - - /* introduce fragmentation by freeing every other node */ - for (i = 0; i < num_insert; i++) { - if (i % 2 == 0) - drm_mm_remove_node(&nodes[i]); - } - - return 0; -} - -static u64 get_insert_time(struct kunit *test, struct drm_mm *mm, - unsigned int num_insert, struct drm_mm_node *nodes, - const struct insert_mode *mode) -{ - unsigned int size = 8192; - ktime_t start; - unsigned int i; - - start = ktime_get(); - for (i = 0; i < num_insert; i++) { - if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { - KUNIT_FAIL(test, "%s insert failed\n", mode->name); - return 0; - } - } - - return ktime_to_ns(ktime_sub(ktime_get(), start)); -} - -static void drm_test_mm_frag(struct kunit *test) -{ - struct drm_mm mm; - const struct insert_mode *mode; - struct drm_mm_node *nodes, *node, *next; - unsigned int insert_size = 10000; - unsigned int scale_factor = 4; - - /* We need 4 * insert_size nodes to hold intermediate allocated - * drm_mm nodes. - * 1 times for prepare_frag() - * 1 times for get_insert_time() - * 2 times for get_insert_time() - */ - nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - /* For BOTTOMUP and TOPDOWN, we first fragment the - * address space using prepare_frag() and then try to verify - * that insertions scale quadratically from 10k to 20k insertions - */ - drm_mm_init(&mm, 1, U64_MAX - 2); - for (mode = insert_modes; mode->name; mode++) { - u64 insert_time1, insert_time2; - - if (mode->mode != DRM_MM_INSERT_LOW && - mode->mode != DRM_MM_INSERT_HIGH) - continue; - - if (prepare_frag(test, &mm, nodes, insert_size, mode)) - goto err; - - insert_time1 = get_insert_time(test, &mm, insert_size, - nodes + insert_size, mode); - if (insert_time1 == 0) - goto err; - - insert_time2 = get_insert_time(test, &mm, (insert_size * 2), - nodes + insert_size * 2, mode); - if (insert_time2 == 0) - goto err; - - kunit_info(test, "%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", - mode->name, insert_size, insert_size * 2, insert_time1, insert_time2); - - if (insert_time2 > (scale_factor * insert_time1)) { - KUNIT_FAIL(test, "%s fragmented insert took %llu nsecs more\n", - mode->name, insert_time2 - (scale_factor * insert_time1)); - goto err; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - } - -err: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - vfree(nodes); -} - -static void drm_test_mm_align(struct kunit *test) -{ - const struct insert_mode *mode; - const unsigned int max_count = min(8192u, max_prime); - struct drm_mm mm; - struct drm_mm_node *nodes, *node, *next; - unsigned int prime; - - /* For each of the possible insertion modes, we pick a few - * arbitrary alignments and check that the inserted node - * meets our requirements. - */ - - nodes = vzalloc(array_size(max_count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - drm_mm_init(&mm, 1, U64_MAX - 2); - - for (mode = insert_modes; mode->name; mode++) { - unsigned int i = 0; - - for_each_prime_number_from(prime, 1, max_count) { - u64 size = next_prime_number(prime); - - if (!expect_insert(test, &mm, &nodes[i], size, prime, i, mode)) { - KUNIT_FAIL(test, "%s insert failed with alignment=%d", - mode->name, prime); - goto out; - } - - i++; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - DRM_MM_BUG_ON(!drm_mm_clean(&mm)); - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - vfree(nodes); -} - static void drm_test_mm_align_pot(struct kunit *test, int max) { struct drm_mm mm; @@ -1144,626 +282,6 @@ static void drm_test_mm_align64(struct kunit *test) drm_test_mm_align_pot(test, 64); } -static void show_scan(struct kunit *test, const struct drm_mm_scan *scan) -{ - kunit_info(test, "scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", - scan->hit_start, scan->hit_end, scan->size, scan->alignment, scan->color); -} - -static void show_holes(struct kunit *test, const struct drm_mm *mm, int count) -{ - u64 hole_start, hole_end; - struct drm_mm_node *hole; - - drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { - struct drm_mm_node *next = list_next_entry(hole, node_list); - const char *node1 = NULL, *node2 = NULL; - - if (drm_mm_node_allocated(hole)) - node1 = kasprintf(GFP_KERNEL, "[%llx + %lld, color=%ld], ", - hole->start, hole->size, hole->color); - - if (drm_mm_node_allocated(next)) - node2 = kasprintf(GFP_KERNEL, ", [%llx + %lld, color=%ld]", - next->start, next->size, next->color); - - kunit_info(test, "%sHole [%llx - %llx, size %lld]%s\n", node1, - hole_start, hole_end, hole_end - hole_start, node2); - - kfree(node2); - kfree(node1); - - if (!--count) - break; - } -} - -struct evict_node { - struct drm_mm_node node; - struct list_head link; -}; - -static bool evict_nodes(struct kunit *test, struct drm_mm_scan *scan, - struct evict_node *nodes, unsigned int *order, unsigned int count, - bool use_color, struct list_head *evict_list) -{ - struct evict_node *e, *en; - unsigned int i; - - for (i = 0; i < count; i++) { - e = &nodes[order ? order[i] : i]; - list_add(&e->link, evict_list); - if (drm_mm_scan_add_block(scan, &e->node)) - break; - } - list_for_each_entry_safe(e, en, evict_list, link) { - if (!drm_mm_scan_remove_block(scan, &e->node)) - list_del(&e->link); - } - if (list_empty(evict_list)) { - KUNIT_FAIL(test, - "Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", - scan->size, count, scan->alignment, scan->color); - return false; - } - - list_for_each_entry(e, evict_list, link) - drm_mm_remove_node(&e->node); - - if (use_color) { - struct drm_mm_node *node; - - while ((node = drm_mm_scan_color_evict(scan))) { - e = container_of(node, typeof(*e), node); - drm_mm_remove_node(&e->node); - list_add(&e->link, evict_list); - } - } else { - if (drm_mm_scan_color_evict(scan)) { - KUNIT_FAIL(test, - "drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); - return false; - } - } - - return true; -} - -static bool evict_nothing(struct kunit *test, struct drm_mm *mm, - unsigned int total_size, struct evict_node *nodes) -{ - struct drm_mm_scan scan; - LIST_HEAD(evict_list); - struct evict_node *e; - struct drm_mm_node *node; - unsigned int n; - - drm_mm_scan_init(&scan, mm, 1, 0, 0, 0); - for (n = 0; n < total_size; n++) { - e = &nodes[n]; - list_add(&e->link, &evict_list); - drm_mm_scan_add_block(&scan, &e->node); - } - list_for_each_entry(e, &evict_list, link) - drm_mm_scan_remove_block(&scan, &e->node); - - for (n = 0; n < total_size; n++) { - e = &nodes[n]; - - if (!drm_mm_node_allocated(&e->node)) { - KUNIT_FAIL(test, "node[%d] no longer allocated!\n", n); - return false; - } - - e->link.next = NULL; - } - - drm_mm_for_each_node(node, mm) { - e = container_of(node, typeof(*e), node); - e->link.next = &e->link; - } - - for (n = 0; n < total_size; n++) { - e = &nodes[n]; - - if (!e->link.next) { - KUNIT_FAIL(test, "node[%d] no longer connected!\n", n); - return false; - } - } - - return assert_continuous(test, mm, nodes[0].node.size); -} - -static bool evict_everything(struct kunit *test, struct drm_mm *mm, - unsigned int total_size, struct evict_node *nodes) -{ - struct drm_mm_scan scan; - LIST_HEAD(evict_list); - struct evict_node *e; - unsigned int n; - int err; - - drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0); - for (n = 0; n < total_size; n++) { - e = &nodes[n]; - list_add(&e->link, &evict_list); - if (drm_mm_scan_add_block(&scan, &e->node)) - break; - } - - err = 0; - list_for_each_entry(e, &evict_list, link) { - if (!drm_mm_scan_remove_block(&scan, &e->node)) { - if (!err) { - KUNIT_FAIL(test, "Node %lld not marked for eviction!\n", - e->node.start); - err = -EINVAL; - } - } - } - if (err) - return false; - - list_for_each_entry(e, &evict_list, link) - drm_mm_remove_node(&e->node); - - if (!assert_one_hole(test, mm, 0, total_size)) - return false; - - list_for_each_entry(e, &evict_list, link) { - err = drm_mm_reserve_node(mm, &e->node); - if (err) { - KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", - e->node.start); - return false; - } - } - - return assert_continuous(test, mm, nodes[0].node.size); -} - -static int evict_something(struct kunit *test, struct drm_mm *mm, - u64 range_start, u64 range_end, struct evict_node *nodes, - unsigned int *order, unsigned int count, unsigned int size, - unsigned int alignment, const struct insert_mode *mode) -{ - struct drm_mm_scan scan; - LIST_HEAD(evict_list); - struct evict_node *e; - struct drm_mm_node tmp; - int err; - - drm_mm_scan_init_with_range(&scan, mm, size, alignment, 0, range_start, - range_end, mode->mode); - if (!evict_nodes(test, &scan, nodes, order, count, false, &evict_list)) - return -EINVAL; - - memset(&tmp, 0, sizeof(tmp)); - err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, - DRM_MM_INSERT_EVICT); - if (err) { - KUNIT_FAIL(test, "Failed to insert into eviction hole: size=%d, align=%d\n", - size, alignment); - show_scan(test, &scan); - show_holes(test, mm, 3); - return err; - } - - if (tmp.start < range_start || tmp.start + tmp.size > range_end) { - KUNIT_FAIL(test, - "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", - tmp.start, tmp.size, range_start, range_end); - err = -EINVAL; - } - - if (!assert_node(test, &tmp, mm, size, alignment, 0) || - drm_mm_hole_follows(&tmp)) { - KUNIT_FAIL(test, - "Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", - tmp.size, size, alignment, misalignment(&tmp, alignment), - tmp.start, drm_mm_hole_follows(&tmp)); - err = -EINVAL; - } - - drm_mm_remove_node(&tmp); - if (err) - return err; - - list_for_each_entry(e, &evict_list, link) { - err = drm_mm_reserve_node(mm, &e->node); - if (err) { - KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", - e->node.start); - return err; - } - } - - if (!assert_continuous(test, mm, nodes[0].node.size)) { - KUNIT_FAIL(test, "range is no longer continuous\n"); - return -EINVAL; - } - - return 0; -} - -static void drm_test_mm_evict(struct kunit *test) -{ - DRM_RND_STATE(prng, random_seed); - const unsigned int size = 8192; - const struct insert_mode *mode; - struct drm_mm mm; - struct evict_node *nodes; - struct drm_mm_node *node, *next; - unsigned int *order, n; - - /* Here we populate a full drm_mm and then try and insert a new node - * by evicting other nodes in a random order. The drm_mm_scan should - * pick the first matching hole it finds from the random list. We - * repeat that for different allocation strategies, alignments and - * sizes to try and stress the hole finder. - */ - - nodes = vzalloc(array_size(size, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - order = drm_random_order(size, &prng); - if (!order) - goto err_nodes; - - drm_mm_init(&mm, 0, size); - for (n = 0; n < size; n++) { - if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { - KUNIT_FAIL(test, "insert failed, step %d\n", n); - goto out; - } - } - - /* First check that using the scanner doesn't break the mm */ - if (!evict_nothing(test, &mm, size, nodes)) { - KUNIT_FAIL(test, "evict_nothing() failed\n"); - goto out; - } - if (!evict_everything(test, &mm, size, nodes)) { - KUNIT_FAIL(test, "evict_everything() failed\n"); - goto out; - } - - for (mode = evict_modes; mode->name; mode++) { - for (n = 1; n <= size; n <<= 1) { - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, n, 1, - mode)) { - KUNIT_FAIL(test, "%s evict_something(size=%u) failed\n", - mode->name, n); - goto out; - } - } - - for (n = 1; n < size; n <<= 1) { - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, - size / 2, n, mode)) { - KUNIT_FAIL(test, - "%s evict_something(size=%u, alignment=%u) failed\n", - mode->name, size / 2, n); - goto out; - } - } - - for_each_prime_number_from(n, 1, min(size, max_prime)) { - unsigned int nsize = (size - n + 1) / 2; - - DRM_MM_BUG_ON(!nsize); - - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, - nsize, n, mode)) { - KUNIT_FAIL(test, - "%s evict_something(size=%u, alignment=%u) failed\n", - mode->name, nsize, n); - goto out; - } - } - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_nodes: - vfree(nodes); -} - -static void drm_test_mm_evict_range(struct kunit *test) -{ - DRM_RND_STATE(prng, random_seed); - const unsigned int size = 8192; - const unsigned int range_size = size / 2; - const unsigned int range_start = size / 4; - const unsigned int range_end = range_start + range_size; - const struct insert_mode *mode; - struct drm_mm mm; - struct evict_node *nodes; - struct drm_mm_node *node, *next; - unsigned int *order, n; - - /* Like drm_test_mm_evict() but now we are limiting the search to a - * small portion of the full drm_mm. - */ - - nodes = vzalloc(array_size(size, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - order = drm_random_order(size, &prng); - if (!order) - goto err_nodes; - - drm_mm_init(&mm, 0, size); - for (n = 0; n < size; n++) { - if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { - KUNIT_FAIL(test, "insert failed, step %d\n", n); - goto out; - } - } - - for (mode = evict_modes; mode->name; mode++) { - for (n = 1; n <= range_size; n <<= 1) { - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, range_start, range_end, nodes, - order, size, n, 1, mode)) { - KUNIT_FAIL(test, - "%s evict_something(size=%u) failed with range [%u, %u]\n", - mode->name, n, range_start, range_end); - goto out; - } - } - - for (n = 1; n <= range_size; n <<= 1) { - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, range_start, range_end, nodes, - order, size, range_size / 2, n, mode)) { - KUNIT_FAIL(test, - "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", - mode->name, range_size / 2, n, range_start, range_end); - goto out; - } - } - - for_each_prime_number_from(n, 1, min(range_size, max_prime)) { - unsigned int nsize = (range_size - n + 1) / 2; - - DRM_MM_BUG_ON(!nsize); - - drm_random_reorder(order, size, &prng); - if (evict_something(test, &mm, range_start, range_end, nodes, - order, size, nsize, n, mode)) { - KUNIT_FAIL(test, - "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", - mode->name, nsize, n, range_start, range_end); - goto out; - } - } - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_nodes: - vfree(nodes); -} - -static unsigned int node_index(const struct drm_mm_node *node) -{ - return div64_u64(node->start, node->size); -} - -static void drm_test_mm_topdown(struct kunit *test) -{ - const struct insert_mode *topdown = &insert_modes[TOPDOWN]; - - DRM_RND_STATE(prng, random_seed); - const unsigned int count = 8192; - unsigned int size; - unsigned long *bitmap; - struct drm_mm mm; - struct drm_mm_node *nodes, *node, *next; - unsigned int *order, n, m, o = 0; - - /* When allocating top-down, we expect to be returned a node - * from a suitable hole at the top of the drm_mm. We check that - * the returned node does match the highest available slot. - */ - - nodes = vzalloc(array_size(count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - bitmap = bitmap_zalloc(count, GFP_KERNEL); - if (!bitmap) - goto err_nodes; - - order = drm_random_order(count, &prng); - if (!order) - goto err_bitmap; - - for (size = 1; size <= 64; size <<= 1) { - drm_mm_init(&mm, 0, size * count); - for (n = 0; n < count; n++) { - if (!expect_insert(test, &mm, &nodes[n], size, 0, n, topdown)) { - KUNIT_FAIL(test, "insert failed, size %u step %d\n", size, n); - goto out; - } - - if (drm_mm_hole_follows(&nodes[n])) { - KUNIT_FAIL(test, - "hole after topdown insert %d, start=%llx\n, size=%u", - n, nodes[n].start, size); - goto out; - } - - if (!assert_one_hole(test, &mm, 0, size * (count - n - 1))) - goto out; - } - - if (!assert_continuous(test, &mm, size)) - goto out; - - drm_random_reorder(order, count, &prng); - for_each_prime_number_from(n, 1, min(count, max_prime)) { - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - drm_mm_remove_node(node); - __set_bit(node_index(node), bitmap); - } - - for (m = 0; m < n; m++) { - unsigned int last; - - node = &nodes[order[(o + m) % count]]; - if (!expect_insert(test, &mm, node, size, 0, 0, topdown)) { - KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); - goto out; - } - - if (drm_mm_hole_follows(node)) { - KUNIT_FAIL(test, - "hole after topdown insert %d/%d, start=%llx\n", - m, n, node->start); - goto out; - } - - last = find_last_bit(bitmap, count); - if (node_index(node) != last) { - KUNIT_FAIL(test, - "node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", - m, n, size, last, node_index(node)); - goto out; - } - - __clear_bit(last, bitmap); - } - - DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); - - o += n; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - DRM_MM_BUG_ON(!drm_mm_clean(&mm)); - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_bitmap: - bitmap_free(bitmap); -err_nodes: - vfree(nodes); -} - -static void drm_test_mm_bottomup(struct kunit *test) -{ - const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; - - DRM_RND_STATE(prng, random_seed); - const unsigned int count = 8192; - unsigned int size; - unsigned long *bitmap; - struct drm_mm mm; - struct drm_mm_node *nodes, *node, *next; - unsigned int *order, n, m, o = 0; - - /* Like drm_test_mm_topdown, but instead of searching for the last hole, - * we search for the first. - */ - - nodes = vzalloc(array_size(count, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - bitmap = bitmap_zalloc(count, GFP_KERNEL); - if (!bitmap) - goto err_nodes; - - order = drm_random_order(count, &prng); - if (!order) - goto err_bitmap; - - for (size = 1; size <= 64; size <<= 1) { - drm_mm_init(&mm, 0, size * count); - for (n = 0; n < count; n++) { - if (!expect_insert(test, &mm, &nodes[n], size, 0, n, bottomup)) { - KUNIT_FAIL(test, - "bottomup insert failed, size %u step %d\n", size, n); - goto out; - } - - if (!assert_one_hole(test, &mm, size * (n + 1), size * count)) - goto out; - } - - if (!assert_continuous(test, &mm, size)) - goto out; - - drm_random_reorder(order, count, &prng); - for_each_prime_number_from(n, 1, min(count, max_prime)) { - for (m = 0; m < n; m++) { - node = &nodes[order[(o + m) % count]]; - drm_mm_remove_node(node); - __set_bit(node_index(node), bitmap); - } - - for (m = 0; m < n; m++) { - unsigned int first; - - node = &nodes[order[(o + m) % count]]; - if (!expect_insert(test, &mm, node, size, 0, 0, bottomup)) { - KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); - goto out; - } - - first = find_first_bit(bitmap, count); - if (node_index(node) != first) { - KUNIT_FAIL(test, - "node %d/%d not inserted into bottom hole, expected %d, found %d\n", - m, n, first, node_index(node)); - goto out; - } - __clear_bit(first, bitmap); - } - - DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); - - o += n; - } - - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - DRM_MM_BUG_ON(!drm_mm_clean(&mm)); - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_bitmap: - bitmap_free(bitmap); -err_nodes: - vfree(nodes); -} - static void drm_test_mm_once(struct kunit *test, unsigned int mode) { struct drm_mm mm; @@ -1817,440 +335,18 @@ static void drm_test_mm_highest(struct kunit *test) drm_test_mm_once(test, DRM_MM_INSERT_HIGH); } -static void separate_adjacent_colors(const struct drm_mm_node *node, - unsigned long color, u64 *start, u64 *end) -{ - if (drm_mm_node_allocated(node) && node->color != color) - ++*start; - - node = list_next_entry(node, node_list); - if (drm_mm_node_allocated(node) && node->color != color) - --*end; -} - -static bool colors_abutt(struct kunit *test, const struct drm_mm_node *node) -{ - if (!drm_mm_hole_follows(node) && - drm_mm_node_allocated(list_next_entry(node, node_list))) { - KUNIT_FAIL(test, "colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", - node->color, node->start, node->size, - list_next_entry(node, node_list)->color, - list_next_entry(node, node_list)->start, - list_next_entry(node, node_list)->size); - return true; - } - - return false; -} - -static void drm_test_mm_color(struct kunit *test) -{ - const unsigned int count = min(4096u, max_iterations); - const struct insert_mode *mode; - struct drm_mm mm; - struct drm_mm_node *node, *nn; - unsigned int n; - - /* Color adjustment complicates everything. First we just check - * that when we insert a node we apply any color_adjustment callback. - * The callback we use should ensure that there is a gap between - * any two nodes, and so after each insertion we check that those - * holes are inserted and that they are preserved. - */ - - drm_mm_init(&mm, 0, U64_MAX); - - for (n = 1; n <= count; n++) { - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - goto out; - - if (!expect_insert(test, &mm, node, n, 0, n, &insert_modes[0])) { - KUNIT_FAIL(test, "insert failed, step %d\n", n); - kfree(node); - goto out; - } - } - - drm_mm_for_each_node_safe(node, nn, &mm) { - if (node->color != node->size) { - KUNIT_FAIL(test, "invalid color stored: expected %lld, found %ld\n", - node->size, node->color); - - goto out; - } - - drm_mm_remove_node(node); - kfree(node); - } - - /* Now, let's start experimenting with applying a color callback */ - mm.color_adjust = separate_adjacent_colors; - for (mode = insert_modes; mode->name; mode++) { - u64 last; - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - goto out; - - node->size = 1 + 2 * count; - node->color = node->size; - - if (drm_mm_reserve_node(&mm, node)) { - KUNIT_FAIL(test, "initial reserve failed!\n"); - goto out; - } - - last = node->start + node->size; - - for (n = 1; n <= count; n++) { - int rem; - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - goto out; - - node->start = last; - node->size = n + count; - node->color = node->size; - - if (drm_mm_reserve_node(&mm, node) != -ENOSPC) { - KUNIT_FAIL(test, "reserve %d did not report color overlap!", n); - goto out; - } - - node->start += n + 1; - rem = misalignment(node, n + count); - node->start += n + count - rem; - - if (drm_mm_reserve_node(&mm, node)) { - KUNIT_FAIL(test, "reserve %d failed", n); - goto out; - } - - last = node->start + node->size; - } - - for (n = 1; n <= count; n++) { - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - goto out; - - if (!expect_insert(test, &mm, node, n, n, n, mode)) { - KUNIT_FAIL(test, "%s insert failed, step %d\n", mode->name, n); - kfree(node); - goto out; - } - } - - drm_mm_for_each_node_safe(node, nn, &mm) { - u64 rem; - - if (node->color != node->size) { - KUNIT_FAIL(test, - "%s invalid color stored: expected %lld, found %ld\n", - mode->name, node->size, node->color); - - goto out; - } - - if (colors_abutt(test, node)) - goto out; - - div64_u64_rem(node->start, node->size, &rem); - if (rem) { - KUNIT_FAIL(test, - "%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", - mode->name, node->start, node->size, rem); - goto out; - } - - drm_mm_remove_node(node); - kfree(node); - } - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, nn, &mm) { - drm_mm_remove_node(node); - kfree(node); - } - drm_mm_takedown(&mm); -} - -static int evict_color(struct kunit *test, struct drm_mm *mm, u64 range_start, - u64 range_end, struct evict_node *nodes, unsigned int *order, - unsigned int count, unsigned int size, unsigned int alignment, - unsigned long color, const struct insert_mode *mode) -{ - struct drm_mm_scan scan; - LIST_HEAD(evict_list); - struct evict_node *e; - struct drm_mm_node tmp; - int err; - - drm_mm_scan_init_with_range(&scan, mm, size, alignment, color, range_start, - range_end, mode->mode); - if (!evict_nodes(test, &scan, nodes, order, count, true, &evict_list)) - return -EINVAL; - - memset(&tmp, 0, sizeof(tmp)); - err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, - DRM_MM_INSERT_EVICT); - if (err) { - KUNIT_FAIL(test, - "Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", - size, alignment, color, err); - show_scan(test, &scan); - show_holes(test, mm, 3); - return err; - } - - if (tmp.start < range_start || tmp.start + tmp.size > range_end) { - KUNIT_FAIL(test, - "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", - tmp.start, tmp.size, range_start, range_end); - err = -EINVAL; - } - - if (colors_abutt(test, &tmp)) - err = -EINVAL; - - if (!assert_node(test, &tmp, mm, size, alignment, color)) { - KUNIT_FAIL(test, - "Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", - tmp.size, size, alignment, misalignment(&tmp, alignment), tmp.start); - err = -EINVAL; - } - - drm_mm_remove_node(&tmp); - if (err) - return err; - - list_for_each_entry(e, &evict_list, link) { - err = drm_mm_reserve_node(mm, &e->node); - if (err) { - KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", - e->node.start); - return err; - } - } - - cond_resched(); - return 0; -} - -static void drm_test_mm_color_evict(struct kunit *test) -{ - DRM_RND_STATE(prng, random_seed); - const unsigned int total_size = min(8192u, max_iterations); - const struct insert_mode *mode; - unsigned long color = 0; - struct drm_mm mm; - struct evict_node *nodes; - struct drm_mm_node *node, *next; - unsigned int *order, n; - - /* Check that the drm_mm_scan also honours color adjustment when - * choosing its victims to create a hole. Our color_adjust does not - * allow two nodes to be placed together without an intervening hole - * enlarging the set of victims that must be evicted. - */ - - nodes = vzalloc(array_size(total_size, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - order = drm_random_order(total_size, &prng); - if (!order) - goto err_nodes; - - drm_mm_init(&mm, 0, 2 * total_size - 1); - mm.color_adjust = separate_adjacent_colors; - for (n = 0; n < total_size; n++) { - if (!expect_insert(test, &mm, &nodes[n].node, - 1, 0, color++, - &insert_modes[0])) { - KUNIT_FAIL(test, "insert failed, step %d\n", n); - goto out; - } - } - - for (mode = evict_modes; mode->name; mode++) { - for (n = 1; n <= total_size; n <<= 1) { - drm_random_reorder(order, total_size, &prng); - if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, - n, 1, color++, mode)) { - KUNIT_FAIL(test, "%s evict_color(size=%u) failed\n", mode->name, n); - goto out; - } - } - - for (n = 1; n < total_size; n <<= 1) { - drm_random_reorder(order, total_size, &prng); - if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, - total_size / 2, n, color++, mode)) { - KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", - mode->name, total_size / 2, n); - goto out; - } - } - - for_each_prime_number_from(n, 1, min(total_size, max_prime)) { - unsigned int nsize = (total_size - n + 1) / 2; - - DRM_MM_BUG_ON(!nsize); - - drm_random_reorder(order, total_size, &prng); - if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, - nsize, n, color++, mode)) { - KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", - mode->name, nsize, n); - goto out; - } - } - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_nodes: - vfree(nodes); -} - -static void drm_test_mm_color_evict_range(struct kunit *test) -{ - DRM_RND_STATE(prng, random_seed); - const unsigned int total_size = 8192; - const unsigned int range_size = total_size / 2; - const unsigned int range_start = total_size / 4; - const unsigned int range_end = range_start + range_size; - const struct insert_mode *mode; - unsigned long color = 0; - struct drm_mm mm; - struct evict_node *nodes; - struct drm_mm_node *node, *next; - unsigned int *order, n; - - /* Like drm_test_mm_color_evict(), but limited to small portion of the full - * drm_mm range. - */ - - nodes = vzalloc(array_size(total_size, sizeof(*nodes))); - KUNIT_ASSERT_TRUE(test, nodes); - - order = drm_random_order(total_size, &prng); - if (!order) - goto err_nodes; - - drm_mm_init(&mm, 0, 2 * total_size - 1); - mm.color_adjust = separate_adjacent_colors; - for (n = 0; n < total_size; n++) { - if (!expect_insert(test, &mm, &nodes[n].node, - 1, 0, color++, - &insert_modes[0])) { - KUNIT_FAIL(test, "insert failed, step %d\n", n); - goto out; - } - } - - for (mode = evict_modes; mode->name; mode++) { - for (n = 1; n <= range_size; n <<= 1) { - drm_random_reorder(order, range_size, &prng); - if (evict_color(test, &mm, range_start, range_end, nodes, order, - total_size, n, 1, color++, mode)) { - KUNIT_FAIL(test, - "%s evict_color(size=%u) failed for range [%x, %x]\n", - mode->name, n, range_start, range_end); - goto out; - } - } - - for (n = 1; n < range_size; n <<= 1) { - drm_random_reorder(order, total_size, &prng); - if (evict_color(test, &mm, range_start, range_end, nodes, order, - total_size, range_size / 2, n, color++, mode)) { - KUNIT_FAIL(test, - "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", - mode->name, total_size / 2, n, range_start, range_end); - goto out; - } - } - - for_each_prime_number_from(n, 1, min(range_size, max_prime)) { - unsigned int nsize = (range_size - n + 1) / 2; - - DRM_MM_BUG_ON(!nsize); - - drm_random_reorder(order, total_size, &prng); - if (evict_color(test, &mm, range_start, range_end, nodes, order, - total_size, nsize, n, color++, mode)) { - KUNIT_FAIL(test, - "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", - mode->name, nsize, n, range_start, range_end); - goto out; - } - } - - cond_resched(); - } - -out: - drm_mm_for_each_node_safe(node, next, &mm) - drm_mm_remove_node(node); - drm_mm_takedown(&mm); - kfree(order); -err_nodes: - vfree(nodes); -} - -static int drm_mm_suite_init(struct kunit_suite *suite) -{ - while (!random_seed) - random_seed = get_random_u32(); - - kunit_info(suite, - "Testing DRM range manager, with random_seed=0x%x max_iterations=%u max_prime=%u\n", - random_seed, max_iterations, max_prime); - - return 0; -} - -module_param(random_seed, uint, 0400); -module_param(max_iterations, uint, 0400); -module_param(max_prime, uint, 0400); - static struct kunit_case drm_mm_tests[] = { KUNIT_CASE(drm_test_mm_init), KUNIT_CASE(drm_test_mm_debug), - KUNIT_CASE(drm_test_mm_reserve), - KUNIT_CASE(drm_test_mm_insert), - KUNIT_CASE(drm_test_mm_replace), - KUNIT_CASE(drm_test_mm_insert_range), - KUNIT_CASE(drm_test_mm_frag), - KUNIT_CASE(drm_test_mm_align), KUNIT_CASE(drm_test_mm_align32), KUNIT_CASE(drm_test_mm_align64), - KUNIT_CASE(drm_test_mm_evict), - KUNIT_CASE(drm_test_mm_evict_range), - KUNIT_CASE(drm_test_mm_topdown), - KUNIT_CASE(drm_test_mm_bottomup), KUNIT_CASE(drm_test_mm_lowest), KUNIT_CASE(drm_test_mm_highest), - KUNIT_CASE(drm_test_mm_color), - KUNIT_CASE(drm_test_mm_color_evict), - KUNIT_CASE(drm_test_mm_color_evict_range), {} }; static struct kunit_suite drm_mm_test_suite = { .name = "drm_mm", - .suite_init = drm_mm_suite_init, .test_cases = drm_mm_tests, }; From a0a0bd3effea22d9886ee6ff98c591acd9565787 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 25 Oct 2023 15:24:28 +0200 Subject: [PATCH 0295/7721] drm/todo: Add entry to clean up former seltests suites Most of those suites are undocumented and aren't really clear about what they are testing. Let's add a TODO entry as a future task to get started into KUnit and DRM. Acked-by: Daniel Vetter Link: https://lore.kernel.org/r/20231025132428.723672-2-mripard@kernel.org Signed-off-by: Maxime Ripard --- Documentation/gpu/todo.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 03fe5d1247be..b62c7fa0c2bc 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -621,6 +621,23 @@ Contact: Javier Martinez Canillas Level: Intermediate +Clean up and document former selftests suites +--------------------------------------------- + +Some KUnit test suites (drm_buddy, drm_cmdline_parser, drm_damage_helper, +drm_format, drm_framebuffer, drm_dp_mst_helper, drm_mm, drm_plane_helper and +drm_rect) are former selftests suites that have been converted over when KUnit +was first introduced. + +These suites were fairly undocumented, and with different goals than what unit +tests can be. Trying to identify what each test in these suites actually test +for, whether that makes sense for a unit test, and either remove it if it +doesn't or document it if it does would be of great help. + +Contact: Maxime Ripard + +Level: Intermediate + Enable trinity for DRM ---------------------- From c400eb4d6f5f603f4f3f6cc4b6fdacd416ff142e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Mon, 6 Nov 2023 10:41:20 -0300 Subject: [PATCH 0296/7721] MAINTAINERS: Add Maira to V3D maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've been contributing to V3D with improvements, reviews, testing and debugging. Therefore, add myself as a co-maintainer of the V3D driver. Signed-off-by: Maíra Canal Acked-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231106134201.725805-1-mcanal@igalia.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4e1a63479cad..ec79843f842a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7105,6 +7105,7 @@ F: drivers/gpu/drm/omapdrm/ DRM DRIVERS FOR V3D M: Melissa Wen +M: Maíra Canal S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml From 8eb80946ab0c18a853be5f90d6b6ccbe3fd42989 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:38 +0200 Subject: [PATCH 0297/7721] drm/edid: split out drm_eld.h from drm_edid.h The drm_edid.[ch] files are starting to be a bit crowded, and with plans to add more ELD related functionality, it's perhaps cleanest to split the ELD code out to a header of its own. Include drm_eld.h from drm_edid.h for starters, and leave it to follow-up work to only include drm_eld.h where needed. Cc: Mitul Golani Reviewed-by: Mitul Golani Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/0c6d631fa1058036d72dd25d1cabc90a7c52490e.1698747331.git.jani.nikula@intel.com --- Documentation/gpu/drm-kms-helpers.rst | 3 + include/drm/drm_edid.h | 149 +----------------------- include/drm/drm_eld.h | 159 ++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 148 deletions(-) create mode 100644 include/drm/drm_eld.h diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index b748b8ae70b2..cfa8e6c399b6 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -363,6 +363,9 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: +.. kernel-doc:: include/drm/drm_eld.h + :internal: + SCDC Helper Functions Reference =============================== diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 882d2638708e..1ff52f57ab9c 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -25,6 +25,7 @@ #include #include +#include /* FIXME: remove this, include directly where needed */ #include struct drm_device; @@ -269,64 +270,6 @@ struct detailed_timing { #define DRM_EDID_DSC_MAX_SLICES 0xf #define DRM_EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f -/* ELD Header Block */ -#define DRM_ELD_HEADER_BLOCK_SIZE 4 - -#define DRM_ELD_VER 0 -# define DRM_ELD_VER_SHIFT 3 -# define DRM_ELD_VER_MASK (0x1f << 3) -# define DRM_ELD_VER_CEA861D (2 << 3) /* supports 861D or below */ -# define DRM_ELD_VER_CANNED (0x1f << 3) - -#define DRM_ELD_BASELINE_ELD_LEN 2 /* in dwords! */ - -/* ELD Baseline Block for ELD_Ver == 2 */ -#define DRM_ELD_CEA_EDID_VER_MNL 4 -# define DRM_ELD_CEA_EDID_VER_SHIFT 5 -# define DRM_ELD_CEA_EDID_VER_MASK (7 << 5) -# define DRM_ELD_CEA_EDID_VER_NONE (0 << 5) -# define DRM_ELD_CEA_EDID_VER_CEA861 (1 << 5) -# define DRM_ELD_CEA_EDID_VER_CEA861A (2 << 5) -# define DRM_ELD_CEA_EDID_VER_CEA861BCD (3 << 5) -# define DRM_ELD_MNL_SHIFT 0 -# define DRM_ELD_MNL_MASK (0x1f << 0) - -#define DRM_ELD_SAD_COUNT_CONN_TYPE 5 -# define DRM_ELD_SAD_COUNT_SHIFT 4 -# define DRM_ELD_SAD_COUNT_MASK (0xf << 4) -# define DRM_ELD_CONN_TYPE_SHIFT 2 -# define DRM_ELD_CONN_TYPE_MASK (3 << 2) -# define DRM_ELD_CONN_TYPE_HDMI (0 << 2) -# define DRM_ELD_CONN_TYPE_DP (1 << 2) -# define DRM_ELD_SUPPORTS_AI (1 << 1) -# define DRM_ELD_SUPPORTS_HDCP (1 << 0) - -#define DRM_ELD_AUD_SYNCH_DELAY 6 /* in units of 2 ms */ -# define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */ - -#define DRM_ELD_SPEAKER 7 -# define DRM_ELD_SPEAKER_MASK 0x7f -# define DRM_ELD_SPEAKER_RLRC (1 << 6) -# define DRM_ELD_SPEAKER_FLRC (1 << 5) -# define DRM_ELD_SPEAKER_RC (1 << 4) -# define DRM_ELD_SPEAKER_RLR (1 << 3) -# define DRM_ELD_SPEAKER_FC (1 << 2) -# define DRM_ELD_SPEAKER_LFE (1 << 1) -# define DRM_ELD_SPEAKER_FLR (1 << 0) - -#define DRM_ELD_PORT_ID 8 /* offsets 8..15 inclusive */ -# define DRM_ELD_PORT_ID_LEN 8 - -#define DRM_ELD_MANUFACTURER_NAME0 16 -#define DRM_ELD_MANUFACTURER_NAME1 17 - -#define DRM_ELD_PRODUCT_CODE0 18 -#define DRM_ELD_PRODUCT_CODE1 19 - -#define DRM_ELD_MONITOR_NAME_STRING 20 /* offsets 20..(20+mnl-1) inclusive */ - -#define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad)) - struct edid { u8 header[8]; /* Vendor & product info */ @@ -409,96 +352,6 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, const struct drm_display_mode *mode, enum hdmi_quantization_range rgb_quant_range); -/** - * drm_eld_mnl - Get ELD monitor name length in bytes. - * @eld: pointer to an eld memory structure with mnl set - */ -static inline int drm_eld_mnl(const uint8_t *eld) -{ - return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; -} - -/** - * drm_eld_sad - Get ELD SAD structures. - * @eld: pointer to an eld memory structure with sad_count set - */ -static inline const uint8_t *drm_eld_sad(const uint8_t *eld) -{ - unsigned int ver, mnl; - - ver = (eld[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT; - if (ver != 2 && ver != 31) - return NULL; - - mnl = drm_eld_mnl(eld); - if (mnl > 16) - return NULL; - - return eld + DRM_ELD_CEA_SAD(mnl, 0); -} - -/** - * drm_eld_sad_count - Get ELD SAD count. - * @eld: pointer to an eld memory structure with sad_count set - */ -static inline int drm_eld_sad_count(const uint8_t *eld) -{ - return (eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_SAD_COUNT_MASK) >> - DRM_ELD_SAD_COUNT_SHIFT; -} - -/** - * drm_eld_calc_baseline_block_size - Calculate baseline block size in bytes - * @eld: pointer to an eld memory structure with mnl and sad_count set - * - * This is a helper for determining the payload size of the baseline block, in - * bytes, for e.g. setting the Baseline_ELD_Len field in the ELD header block. - */ -static inline int drm_eld_calc_baseline_block_size(const uint8_t *eld) -{ - return DRM_ELD_MONITOR_NAME_STRING - DRM_ELD_HEADER_BLOCK_SIZE + - drm_eld_mnl(eld) + drm_eld_sad_count(eld) * 3; -} - -/** - * drm_eld_size - Get ELD size in bytes - * @eld: pointer to a complete eld memory structure - * - * The returned value does not include the vendor block. It's vendor specific, - * and comprises of the remaining bytes in the ELD memory buffer after - * drm_eld_size() bytes of header and baseline block. - * - * The returned value is guaranteed to be a multiple of 4. - */ -static inline int drm_eld_size(const uint8_t *eld) -{ - return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; -} - -/** - * drm_eld_get_spk_alloc - Get speaker allocation - * @eld: pointer to an ELD memory structure - * - * The returned value is the speakers mask. User has to use %DRM_ELD_SPEAKER - * field definitions to identify speakers. - */ -static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld) -{ - return eld[DRM_ELD_SPEAKER] & DRM_ELD_SPEAKER_MASK; -} - -/** - * drm_eld_get_conn_type - Get device type hdmi/dp connected - * @eld: pointer to an ELD memory structure - * - * The caller need to use %DRM_ELD_CONN_TYPE_HDMI or %DRM_ELD_CONN_TYPE_DP to - * identify the display type connected. - */ -static inline u8 drm_eld_get_conn_type(const uint8_t *eld) -{ - return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; -} - /** * drm_edid_decode_mfg_id - Decode the manufacturer ID * @mfg_id: The manufacturer ID diff --git a/include/drm/drm_eld.h b/include/drm/drm_eld.h new file mode 100644 index 000000000000..9bde89bd96ea --- /dev/null +++ b/include/drm/drm_eld.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __DRM_ELD_H__ +#define __DRM_ELD_H__ + +#include + +/* ELD Header Block */ +#define DRM_ELD_HEADER_BLOCK_SIZE 4 + +#define DRM_ELD_VER 0 +# define DRM_ELD_VER_SHIFT 3 +# define DRM_ELD_VER_MASK (0x1f << 3) +# define DRM_ELD_VER_CEA861D (2 << 3) /* supports 861D or below */ +# define DRM_ELD_VER_CANNED (0x1f << 3) + +#define DRM_ELD_BASELINE_ELD_LEN 2 /* in dwords! */ + +/* ELD Baseline Block for ELD_Ver == 2 */ +#define DRM_ELD_CEA_EDID_VER_MNL 4 +# define DRM_ELD_CEA_EDID_VER_SHIFT 5 +# define DRM_ELD_CEA_EDID_VER_MASK (7 << 5) +# define DRM_ELD_CEA_EDID_VER_NONE (0 << 5) +# define DRM_ELD_CEA_EDID_VER_CEA861 (1 << 5) +# define DRM_ELD_CEA_EDID_VER_CEA861A (2 << 5) +# define DRM_ELD_CEA_EDID_VER_CEA861BCD (3 << 5) +# define DRM_ELD_MNL_SHIFT 0 +# define DRM_ELD_MNL_MASK (0x1f << 0) + +#define DRM_ELD_SAD_COUNT_CONN_TYPE 5 +# define DRM_ELD_SAD_COUNT_SHIFT 4 +# define DRM_ELD_SAD_COUNT_MASK (0xf << 4) +# define DRM_ELD_CONN_TYPE_SHIFT 2 +# define DRM_ELD_CONN_TYPE_MASK (3 << 2) +# define DRM_ELD_CONN_TYPE_HDMI (0 << 2) +# define DRM_ELD_CONN_TYPE_DP (1 << 2) +# define DRM_ELD_SUPPORTS_AI (1 << 1) +# define DRM_ELD_SUPPORTS_HDCP (1 << 0) + +#define DRM_ELD_AUD_SYNCH_DELAY 6 /* in units of 2 ms */ +# define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */ + +#define DRM_ELD_SPEAKER 7 +# define DRM_ELD_SPEAKER_MASK 0x7f +# define DRM_ELD_SPEAKER_RLRC (1 << 6) +# define DRM_ELD_SPEAKER_FLRC (1 << 5) +# define DRM_ELD_SPEAKER_RC (1 << 4) +# define DRM_ELD_SPEAKER_RLR (1 << 3) +# define DRM_ELD_SPEAKER_FC (1 << 2) +# define DRM_ELD_SPEAKER_LFE (1 << 1) +# define DRM_ELD_SPEAKER_FLR (1 << 0) + +#define DRM_ELD_PORT_ID 8 /* offsets 8..15 inclusive */ +# define DRM_ELD_PORT_ID_LEN 8 + +#define DRM_ELD_MANUFACTURER_NAME0 16 +#define DRM_ELD_MANUFACTURER_NAME1 17 + +#define DRM_ELD_PRODUCT_CODE0 18 +#define DRM_ELD_PRODUCT_CODE1 19 + +#define DRM_ELD_MONITOR_NAME_STRING 20 /* offsets 20..(20+mnl-1) inclusive */ + +#define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad)) + +/** + * drm_eld_mnl - Get ELD monitor name length in bytes. + * @eld: pointer to an eld memory structure with mnl set + */ +static inline int drm_eld_mnl(const uint8_t *eld) +{ + return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; +} + +/** + * drm_eld_sad - Get ELD SAD structures. + * @eld: pointer to an eld memory structure with sad_count set + */ +static inline const uint8_t *drm_eld_sad(const uint8_t *eld) +{ + unsigned int ver, mnl; + + ver = (eld[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT; + if (ver != 2 && ver != 31) + return NULL; + + mnl = drm_eld_mnl(eld); + if (mnl > 16) + return NULL; + + return eld + DRM_ELD_CEA_SAD(mnl, 0); +} + +/** + * drm_eld_sad_count - Get ELD SAD count. + * @eld: pointer to an eld memory structure with sad_count set + */ +static inline int drm_eld_sad_count(const uint8_t *eld) +{ + return (eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_SAD_COUNT_MASK) >> + DRM_ELD_SAD_COUNT_SHIFT; +} + +/** + * drm_eld_calc_baseline_block_size - Calculate baseline block size in bytes + * @eld: pointer to an eld memory structure with mnl and sad_count set + * + * This is a helper for determining the payload size of the baseline block, in + * bytes, for e.g. setting the Baseline_ELD_Len field in the ELD header block. + */ +static inline int drm_eld_calc_baseline_block_size(const uint8_t *eld) +{ + return DRM_ELD_MONITOR_NAME_STRING - DRM_ELD_HEADER_BLOCK_SIZE + + drm_eld_mnl(eld) + drm_eld_sad_count(eld) * 3; +} + +/** + * drm_eld_size - Get ELD size in bytes + * @eld: pointer to a complete eld memory structure + * + * The returned value does not include the vendor block. It's vendor specific, + * and comprises of the remaining bytes in the ELD memory buffer after + * drm_eld_size() bytes of header and baseline block. + * + * The returned value is guaranteed to be a multiple of 4. + */ +static inline int drm_eld_size(const uint8_t *eld) +{ + return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; +} + +/** + * drm_eld_get_spk_alloc - Get speaker allocation + * @eld: pointer to an ELD memory structure + * + * The returned value is the speakers mask. User has to use %DRM_ELD_SPEAKER + * field definitions to identify speakers. + */ +static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld) +{ + return eld[DRM_ELD_SPEAKER] & DRM_ELD_SPEAKER_MASK; +} + +/** + * drm_eld_get_conn_type - Get device type hdmi/dp connected + * @eld: pointer to an ELD memory structure + * + * The caller need to use %DRM_ELD_CONN_TYPE_HDMI or %DRM_ELD_CONN_TYPE_DP to + * identify the display type connected. + */ +static inline u8 drm_eld_get_conn_type(const uint8_t *eld) +{ + return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; +} + +#endif /* __DRM_ELD_H__ */ From 533914536bf5cb5984755244f5aa13cf93cc84d3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:39 +0200 Subject: [PATCH 0298/7721] drm/eld: replace uint8_t with u8 Unify on kernel types. Cc: Mitul Golani Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Mitul Golani Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/6e048fc4c8a3ebec638ce27b0b8b969a3d2fa8bc.1698747331.git.jani.nikula@intel.com --- include/drm/drm_eld.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/drm/drm_eld.h b/include/drm/drm_eld.h index 9bde89bd96ea..7b674256b9aa 100644 --- a/include/drm/drm_eld.h +++ b/include/drm/drm_eld.h @@ -70,7 +70,7 @@ * drm_eld_mnl - Get ELD monitor name length in bytes. * @eld: pointer to an eld memory structure with mnl set */ -static inline int drm_eld_mnl(const uint8_t *eld) +static inline int drm_eld_mnl(const u8 *eld) { return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; } @@ -79,7 +79,7 @@ static inline int drm_eld_mnl(const uint8_t *eld) * drm_eld_sad - Get ELD SAD structures. * @eld: pointer to an eld memory structure with sad_count set */ -static inline const uint8_t *drm_eld_sad(const uint8_t *eld) +static inline const u8 *drm_eld_sad(const u8 *eld) { unsigned int ver, mnl; @@ -98,7 +98,7 @@ static inline const uint8_t *drm_eld_sad(const uint8_t *eld) * drm_eld_sad_count - Get ELD SAD count. * @eld: pointer to an eld memory structure with sad_count set */ -static inline int drm_eld_sad_count(const uint8_t *eld) +static inline int drm_eld_sad_count(const u8 *eld) { return (eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_SAD_COUNT_MASK) >> DRM_ELD_SAD_COUNT_SHIFT; @@ -111,7 +111,7 @@ static inline int drm_eld_sad_count(const uint8_t *eld) * This is a helper for determining the payload size of the baseline block, in * bytes, for e.g. setting the Baseline_ELD_Len field in the ELD header block. */ -static inline int drm_eld_calc_baseline_block_size(const uint8_t *eld) +static inline int drm_eld_calc_baseline_block_size(const u8 *eld) { return DRM_ELD_MONITOR_NAME_STRING - DRM_ELD_HEADER_BLOCK_SIZE + drm_eld_mnl(eld) + drm_eld_sad_count(eld) * 3; @@ -127,7 +127,7 @@ static inline int drm_eld_calc_baseline_block_size(const uint8_t *eld) * * The returned value is guaranteed to be a multiple of 4. */ -static inline int drm_eld_size(const uint8_t *eld) +static inline int drm_eld_size(const u8 *eld) { return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; } @@ -139,7 +139,7 @@ static inline int drm_eld_size(const uint8_t *eld) * The returned value is the speakers mask. User has to use %DRM_ELD_SPEAKER * field definitions to identify speakers. */ -static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld) +static inline u8 drm_eld_get_spk_alloc(const u8 *eld) { return eld[DRM_ELD_SPEAKER] & DRM_ELD_SPEAKER_MASK; } @@ -151,7 +151,7 @@ static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld) * The caller need to use %DRM_ELD_CONN_TYPE_HDMI or %DRM_ELD_CONN_TYPE_DP to * identify the display type connected. */ -static inline u8 drm_eld_get_conn_type(const uint8_t *eld) +static inline u8 drm_eld_get_conn_type(const u8 *eld) { return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; } From 439590ace7755657523a1a0230c6099cb0a6e15f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:40 +0200 Subject: [PATCH 0299/7721] drm/edid: include drm_eld.h only where required Reduce the dependencies on drm_eld.h. Some files might be able to drop the dependency on drm_edid.h too with the direct inclusion of drm_eld.h. Cc: Mitul Golani Reviewed-by: Mitul Golani Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/9f5963ce900d747f3279312c0cd1da599fd83f94.1698747331.git.jani.nikula@intel.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + drivers/gpu/drm/drm_edid.c | 1 + drivers/gpu/drm/i915/display/intel_audio.c | 1 + drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 1 + drivers/gpu/drm/i915/display/intel_sdvo.c | 1 + drivers/gpu/drm/nouveau/dispnv50/disp.c | 1 + drivers/gpu/drm/radeon/radeon_audio.c | 1 + drivers/gpu/drm/tegra/hdmi.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + include/drm/drm_edid.h | 1 - sound/core/pcm_drm_eld.c | 1 + sound/soc/codecs/hdac_hdmi.c | 1 + sound/soc/codecs/hdmi-codec.c | 1 + sound/x86/intel_hdmi_audio.c | 1 + 14 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c6fd34bab358..42fa2e142712 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ec1cb4890acb..85f719f67b50 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 19605264a35c..39f5b698e08a 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 66fe880af8f3..2d15e82c0b3d 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -4,6 +4,7 @@ */ #include +#include #include "i915_drv.h" #include "intel_crtc_state_dump.h" diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 950ba0431f5f..f967fe06f549 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "i915_drv.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index a0ac8c258d9f..334ca7f919f2 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index d6ccaf24ee0c..279bf130a18c 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -26,6 +26,7 @@ #include #include +#include #include "dce6_afmt.h" #include "evergreen_hdmi.h" #include "radeon.h" diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0ba3ca3ac509..a1fcee665023 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index d5a3d3f4fece..83341576630d 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 1ff52f57ab9c..e98aa6818700 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -25,7 +25,6 @@ #include #include -#include /* FIXME: remove this, include directly where needed */ #include struct drm_device; diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index 07075071972d..1cdca4d4fc9c 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 8b6b76029694..d1b53fc1efb6 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 13689e718d36..9b4e9192cd79 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -17,6 +17,7 @@ #include #include /* This is only to get MAX_ELD_BYTES */ +#include #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index ab95fb34a635..02f5a7f9b728 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "intel_hdmi_audio.h" From e8d0b2c06fd779709baea71d5e8bfd99b2116518 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:41 +0200 Subject: [PATCH 0300/7721] drm/edid: use a temp variable for sads to drop one level of dereferences Use a temporary variable struct cea_sad *, instead of using struct cea_sad ** directly with the double dereferences. It's arguably easier on the eyes, and drops a set of parenthesis too. Cc: Mitul Golani Reviewed-by: Mitul Golani Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/b6e2f295ae5491c2bb0f528508f0f5fca921dc77.1698747331.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 85f719f67b50..4f3e7e855f63 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5591,7 +5591,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, } static int _drm_edid_to_sad(const struct drm_edid *drm_edid, - struct cea_sad **sads) + struct cea_sad **psads) { const struct cea_db *db; struct cea_db_iter iter; @@ -5600,19 +5600,21 @@ static int _drm_edid_to_sad(const struct drm_edid *drm_edid, cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { + struct cea_sad *sads; int j; count = cea_db_payload_len(db) / 3; /* SAD is 3B */ - *sads = kcalloc(count, sizeof(**sads), GFP_KERNEL); - if (!*sads) + sads = kcalloc(count, sizeof(*sads), GFP_KERNEL); + *psads = sads; + if (!sads) return -ENOMEM; for (j = 0; j < count; j++) { const u8 *sad = &db->data[j * 3]; - (*sads)[j].format = (sad[0] & 0x78) >> 3; - (*sads)[j].channels = sad[0] & 0x7; - (*sads)[j].freq = sad[1] & 0x7F; - (*sads)[j].byte2 = sad[2]; + sads[j].format = (sad[0] & 0x78) >> 3; + sads[j].channels = sad[0] & 0x7; + sads[j].freq = sad[1] & 0x7F; + sads[j].byte2 = sad[2]; } break; } From 8af4681189e58a51be8a0fc9f0687e615cdb82c9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:42 +0200 Subject: [PATCH 0301/7721] drm/edid: add helpers to get/set struct cea_sad from/to 3-byte sad Add helpers to pack/unpack SADs. Both ways and non-static, as follow-up work needs them. v2: Add include to get the declarations Cc: Mitul Golani Reviewed-by: Mitul Golani Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/21d657ca854ce26423b461c0bb71e7a0727ba437.1698747331.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 34 +++++++++++++++++++++++++--------- drivers/gpu/drm/drm_internal.h | 6 ++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4f3e7e855f63..9619f91c8331 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -46,6 +46,7 @@ #include #include "drm_crtc_internal.h" +#include "drm_internal.h" static int oui(u8 first, u8 second, u8 third) { @@ -5507,6 +5508,27 @@ static void clear_eld(struct drm_connector *connector) connector->audio_latency[1] = 0; } +/* + * Get 3-byte SAD buffer from struct cea_sad. + */ +void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad) +{ + sad[0] = cta_sad->format << 3 | cta_sad->channels; + sad[1] = cta_sad->freq; + sad[2] = cta_sad->byte2; +} + +/* + * Set struct cea_sad from 3-byte SAD buffer. + */ +void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad) +{ + cta_sad->format = (sad[0] & 0x78) >> 3; + cta_sad->channels = sad[0] & 0x07; + cta_sad->freq = sad[1] & 0x7f; + cta_sad->byte2 = sad[2]; +} + /* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink @@ -5601,21 +5623,15 @@ static int _drm_edid_to_sad(const struct drm_edid *drm_edid, cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { struct cea_sad *sads; - int j; + int i; count = cea_db_payload_len(db) / 3; /* SAD is 3B */ sads = kcalloc(count, sizeof(*sads), GFP_KERNEL); *psads = sads; if (!sads) return -ENOMEM; - for (j = 0; j < count; j++) { - const u8 *sad = &db->data[j * 3]; - - sads[j].format = (sad[0] & 0x78) >> 3; - sads[j].channels = sad[0] & 0x7; - sads[j].freq = sad[1] & 0x7F; - sads[j].byte2 = sad[2]; - } + for (i = 0; i < count; i++) + drm_edid_cta_sad_set(&sads[i], &db->data[i * 3]); break; } } diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8462b657c375..b12c463bc460 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -31,6 +32,7 @@ #define DRM_IF_VERSION(maj, min) (maj << 16 | min) +struct cea_sad; struct dentry; struct dma_buf; struct iosys_map; @@ -267,3 +269,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); void drm_framebuffer_debugfs_init(struct drm_device *dev); + +/* drm_edid.c */ +void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad); +void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad); From f415a6078f640ab15bae34d3c6a1d8e6071363de Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 31 Oct 2023 12:16:43 +0200 Subject: [PATCH 0302/7721] drm/eld: add helpers to modify the SADs of an ELD Occasionally it's necessary for drivers to modify the SADs of an ELD, but it's not so cool to have drivers poke at the ELD buffer directly. Using the helpers to translate between 3-byte SAD and struct cea_sad, add ELD helpers to get/set the SADs from/to an ELD. v2: s/i/sad_index/ (Mitul) Cc: Mitul Golani Signed-off-by: Jani Nikula Reviewed-by: Mitul Golani Link: https://patchwork.freedesktop.org/patch/msgid/8e9a05f2b1e0dd184132d636e1e778e8917ec25d.1698747331.git.jani.nikula@intel.com --- Documentation/gpu/drm-kms-helpers.rst | 3 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_eld.c | 55 +++++++++++++++++++++++++++ include/drm/drm_eld.h | 5 +++ 4 files changed, 64 insertions(+) create mode 100644 drivers/gpu/drm/drm_eld.c diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index cfa8e6c399b6..59cfe8a7a8ba 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -366,6 +366,9 @@ EDID Helper Functions Reference .. kernel-doc:: include/drm/drm_eld.h :internal: +.. kernel-doc:: drivers/gpu/drm/drm_eld.c + :export: + SCDC Helper Functions Reference =============================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8e1bde059170..cdbe91ac0bfc 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -22,6 +22,7 @@ drm-y := \ drm_drv.o \ drm_dumb_buffers.o \ drm_edid.o \ + drm_eld.o \ drm_encoder.o \ drm_file.o \ drm_fourcc.o \ diff --git a/drivers/gpu/drm/drm_eld.c b/drivers/gpu/drm/drm_eld.c new file mode 100644 index 000000000000..5177991aa272 --- /dev/null +++ b/drivers/gpu/drm/drm_eld.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include + +#include "drm_internal.h" + +/** + * drm_eld_sad_get - get SAD from ELD to struct cea_sad + * @eld: ELD buffer + * @sad_index: SAD index + * @cta_sad: destination struct cea_sad + * + * @return: 0 on success, or negative on errors + */ +int drm_eld_sad_get(const u8 *eld, int sad_index, struct cea_sad *cta_sad) +{ + const u8 *sad; + + if (sad_index >= drm_eld_sad_count(eld)) + return -EINVAL; + + sad = eld + DRM_ELD_CEA_SAD(drm_eld_mnl(eld), sad_index); + + drm_edid_cta_sad_set(cta_sad, sad); + + return 0; +} +EXPORT_SYMBOL(drm_eld_sad_get); + +/** + * drm_eld_sad_set - set SAD to ELD from struct cea_sad + * @eld: ELD buffer + * @sad_index: SAD index + * @cta_sad: source struct cea_sad + * + * @return: 0 on success, or negative on errors + */ +int drm_eld_sad_set(u8 *eld, int sad_index, const struct cea_sad *cta_sad) +{ + u8 *sad; + + if (sad_index >= drm_eld_sad_count(eld)) + return -EINVAL; + + sad = eld + DRM_ELD_CEA_SAD(drm_eld_mnl(eld), sad_index); + + drm_edid_cta_sad_get(cta_sad, sad); + + return 0; +} +EXPORT_SYMBOL(drm_eld_sad_set); diff --git a/include/drm/drm_eld.h b/include/drm/drm_eld.h index 7b674256b9aa..0a88d10b28b0 100644 --- a/include/drm/drm_eld.h +++ b/include/drm/drm_eld.h @@ -8,6 +8,8 @@ #include +struct cea_sad; + /* ELD Header Block */ #define DRM_ELD_HEADER_BLOCK_SIZE 4 @@ -75,6 +77,9 @@ static inline int drm_eld_mnl(const u8 *eld) return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; } +int drm_eld_sad_get(const u8 *eld, int sad_index, struct cea_sad *cta_sad); +int drm_eld_sad_set(u8 *eld, int sad_index, const struct cea_sad *cta_sad); + /** * drm_eld_sad - Get ELD SAD structures. * @eld: pointer to an eld memory structure with sad_count set From f3123c2590005c5ff631653d31428e40cd10c618 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 9 Nov 2023 18:53:26 -0500 Subject: [PATCH 0303/7721] drm/sched: Qualify drm_sched_wakeup() by drm_sched_entity_is_ready() Don't "wake up" the GPU scheduler unless the entity is ready, as well as we can queue to the scheduler, i.e. there is no point in waking up the scheduler for the entity unless the entity is ready. Signed-off-by: Luben Tuikov Fixes: bc8d6a9df99038 ("drm/sched: Don't disturb the entity when in RR-mode scheduling") Reviewed-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231110000123.72565-2-ltuikov89@gmail.com --- drivers/gpu/drm/scheduler/sched_entity.c | 4 ++-- drivers/gpu/drm/scheduler/sched_main.c | 8 +++++--- include/drm/gpu_scheduler.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index f1db63cc8198..4d42b1e4daa6 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -370,7 +370,7 @@ static void drm_sched_entity_wakeup(struct dma_fence *f, container_of(cb, struct drm_sched_entity, cb); drm_sched_entity_clear_dep(f, cb); - drm_sched_wakeup(entity->rq->sched); + drm_sched_wakeup(entity->rq->sched, entity); } /** @@ -602,7 +602,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) drm_sched_rq_update_fifo(entity, submit_ts); - drm_sched_wakeup(entity->rq->sched); + drm_sched_wakeup(entity->rq->sched, entity); } } EXPORT_SYMBOL(drm_sched_entity_push_job); diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index cd0dc3f81d05..8f5e466bd582 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -925,10 +925,12 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) * * Wake up the scheduler if we can queue jobs. */ -void drm_sched_wakeup(struct drm_gpu_scheduler *sched) +void drm_sched_wakeup(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity) { - if (drm_sched_can_queue(sched)) - drm_sched_run_job_queue(sched); + if (drm_sched_entity_is_ready(entity)) + if (drm_sched_can_queue(sched)) + drm_sched_run_job_queue(sched); } /** diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 754fd2217334..09916c84703f 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -559,7 +559,7 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched); void drm_sched_job_cleanup(struct drm_sched_job *job); -void drm_sched_wakeup(struct drm_gpu_scheduler *sched); +void drm_sched_wakeup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity); bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched); void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched); void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched); From fc6e7679296530106ee0954e8ddef1aa58b2e0b5 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Tue, 7 Nov 2023 12:41:51 -0800 Subject: [PATCH 0304/7721] drm/panel-edp: drm/panel-edp: Fix AUO B116XAK01 name and timing Rename AUO 0x405c B116XAK01 to B116XAK01.0 and adjust the timing of auo_b116xak01: T3=200, T12=500, T7_max = 50 according to decoding edid and datasheet. Fixes: da458286a5e2 ("drm/panel: Add support for AUO B116XAK01 panel") Cc: stable@vger.kernel.org Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Acked-by: Maxime Ripard Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231107204611.3082200-2-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 9dce4c702414..2fba7c1f49ce 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = { }, .delay = { .hpd_absent = 200, + .unprepare = 500, + .enable = 50, }, }; @@ -1870,7 +1872,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), From 962845c090c4f85fa4f6872a5b6c89ee61f53cc0 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Tue, 7 Nov 2023 12:41:52 -0800 Subject: [PATCH 0305/7721] drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02 name Rename AUO 0x235c B116XTN02 to B116XTN02.3 according to decoding edid. Fixes: 3db2420422a5 ("drm/panel-edp: Add AUO B116XTN02, BOE NT116WHM-N21,836X2, NV116WHM-N49 V8.0") Cc: stable@vger.kernel.org Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Acked-by: Maxime Ripard Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231107204611.3082200-3-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 2fba7c1f49ce..d41d205f7f5b 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1871,7 +1871,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), From 4d53cf81479500d7af787fe6bc881c24ec31f005 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Tue, 7 Nov 2023 12:41:53 -0800 Subject: [PATCH 0306/7721] drm/panel-edp: drm/panel-edp: Add several generic edp panels Add a few generic edp panels used by mt8186 chromebooks. Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Acked-by: Maxime Ripard Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231107204611.3082200-4-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index d41d205f7f5b..599a949d74d1 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1832,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = { .enable = 50, }; +static const struct panel_delay delay_200_500_e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 80, +}; + static const struct panel_delay delay_200_500_e80_d50 = { .hpd_absent = 200, .unprepare = 500, @@ -1851,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d10 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 10, +}; + +static const struct panel_delay delay_200_150_e200 = { + .hpd_absent = 200, + .unprepare = 150, + .enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1871,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, &delay_200_500_e50, "B140HTN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), + + EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), + EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), From 36245bd02e88e68ac5955c2958c968879d7b75a9 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 9 Nov 2023 19:11:46 -0500 Subject: [PATCH 0307/7721] drm/sched: Define pr_fmt() for DRM using pr_*() Define pr_fmt() as "[drm] " for DRM code using pr_*() facilities, especially when no devices are available. This makes it easier to browse kernel logs. Signed-off-by: Luben Tuikov Acked-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231110002659.113208-2-ltuikov89@gmail.com --- include/drm/drm_print.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index a93a387f8a1a..e8fe60d0eb87 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -26,6 +26,20 @@ #ifndef DRM_PRINT_H_ #define DRM_PRINT_H_ +/* Define this before including linux/printk.h, so that the format + * string in pr_*() macros is correctly set for DRM. If a file wants + * to define this to something else, it should do so before including + * this header file. + * + * It is encouraged code using pr_err() to prefix their format with + * the string "*ERROR* ", to make it easier to scan kernel logs. For + * instance, + * pr_err("*ERROR* ", args). + */ +#ifndef pr_fmt +#define pr_fmt(fmt) "[drm] " fmt +#endif + #include #include #include From a78422e9dff366b3a46ae44caf6ec8ded9c9fc2f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 10 Nov 2023 01:16:33 +0100 Subject: [PATCH 0308/7721] drm/sched: implement dynamic job-flow control Currently, job flow control is implemented simply by limiting the number of jobs in flight. Therefore, a scheduler is initialized with a credit limit that corresponds to the number of jobs which can be sent to the hardware. This implies that for each job, drivers need to account for the maximum job size possible in order to not overflow the ring buffer. However, there are drivers, such as Nouveau, where the job size has a rather large range. For such drivers it can easily happen that job submissions not even filling the ring by 1% can block subsequent submissions, which, in the worst case, can lead to the ring run dry. In order to overcome this issue, allow for tracking the actual job size instead of the number of jobs. Therefore, add a field to track a job's credit count, which represents the number of credits a job contributes to the scheduler's credit limit. Signed-off-by: Danilo Krummrich Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20231110001638.71750-1-dakr@redhat.com --- Documentation/gpu/drm-mm.rst | 6 + drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 +- drivers/gpu/drm/lima/lima_device.c | 2 +- drivers/gpu/drm/lima/lima_sched.c | 2 +- drivers/gpu/drm/msm/msm_gem_submit.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.c | 2 +- drivers/gpu/drm/panfrost/panfrost_drv.c | 2 +- drivers/gpu/drm/panfrost/panfrost_job.c | 2 +- .../gpu/drm/scheduler/gpu_scheduler_trace.h | 2 +- drivers/gpu/drm/scheduler/sched_main.c | 170 ++++++++++++++---- drivers/gpu/drm/v3d/v3d_gem.c | 2 +- include/drm/gpu_scheduler.h | 28 ++- 14 files changed, 175 insertions(+), 51 deletions(-) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 602010cb6894..acc5901ac840 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -552,6 +552,12 @@ Overview .. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c :doc: Overview +Flow Control +------------ + +.. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c + :doc: Flow Control + Scheduler Function References ----------------------------- diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 1f357198533f..62bb7fc7448a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -115,7 +115,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (!entity) return 0; - return drm_sched_job_init(&(*job)->base, entity, owner); + return drm_sched_job_init(&(*job)->base, entity, 1, owner); } int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 2416c526f9b0..3d0f8d182506 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -535,7 +535,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, ret = drm_sched_job_init(&submit->sched_job, &ctx->sched_entity[args->pipe], - submit->ctx); + 1, submit->ctx); if (ret) goto err_submit_put; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 9276756e1397..5105d290e72e 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1917,7 +1917,7 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev) u32 idle, mask; /* If there are any jobs in the HW queue, we're not idle */ - if (atomic_read(&gpu->sched.hw_rq_count)) + if (atomic_read(&gpu->sched.credit_count)) return -EBUSY; /* Check whether the hardware (except FE and MC) is idle */ diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c index 02cef0cea657..0bf7105c8748 100644 --- a/drivers/gpu/drm/lima/lima_device.c +++ b/drivers/gpu/drm/lima/lima_device.c @@ -514,7 +514,7 @@ int lima_device_suspend(struct device *dev) /* check any task running */ for (i = 0; i < lima_pipe_num; i++) { - if (atomic_read(&ldev->pipe[i].base.hw_rq_count)) + if (atomic_read(&ldev->pipe[i].base.credit_count)) return -EBUSY; } diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index aa030e1f7cda..c3bf8cda8498 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -123,7 +123,7 @@ int lima_sched_task_init(struct lima_sched_task *task, for (i = 0; i < num_bos; i++) drm_gem_object_get(&bos[i]->base.base); - err = drm_sched_job_init(&task->base, &context->base, vm); + err = drm_sched_job_init(&task->base, &context->base, 1, vm); if (err) { kfree(task->bos); return err; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 99744de6c05a..c002cabe7b9c 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -48,7 +48,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, return ERR_PTR(ret); } - ret = drm_sched_job_init(&submit->base, queue->entity, queue); + ret = drm_sched_job_init(&submit->base, queue->entity, 1, queue); if (ret) { kfree(submit->hw_fence); kfree(submit); diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 7e64b5ef90fb..1b2cc3f2e1c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -89,7 +89,7 @@ nouveau_job_init(struct nouveau_job *job, } - ret = drm_sched_job_init(&job->base, &entity->base, NULL); + ret = drm_sched_job_init(&job->base, &entity->base, 1, NULL); if (ret) goto err_free_chains; diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index b834777b409b..54d1c19bea84 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -274,7 +274,7 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, ret = drm_sched_job_init(&job->base, &file_priv->sched_entity[slot], - NULL); + 1, NULL); if (ret) goto out_put_job; diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 6d89e24322db..f9446e197428 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -963,7 +963,7 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) for (i = 0; i < NUM_JOB_SLOTS; i++) { /* If there are any jobs in the HW queue, we're not idle */ - if (atomic_read(&js->queue[i].sched.hw_rq_count)) + if (atomic_read(&js->queue[i].sched.credit_count)) return false; } diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h b/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h index 3143ecaaff86..f8ed093b7356 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h +++ b/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h @@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(drm_sched_job, __assign_str(name, sched_job->sched->name); __entry->job_count = spsc_queue_count(&entity->job_queue); __entry->hw_job_count = atomic_read( - &sched_job->sched->hw_rq_count); + &sched_job->sched->credit_count); ), TP_printk("entity=%p, id=%llu, fence=%p, ring=%s, job count:%u, hw job count:%d", __entry->entity, __entry->id, diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 8f5e466bd582..044a8c4875ba 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -48,6 +48,30 @@ * through the jobs entity pointer. */ +/** + * DOC: Flow Control + * + * The DRM GPU scheduler provides a flow control mechanism to regulate the rate + * in which the jobs fetched from scheduler entities are executed. + * + * In this context the &drm_gpu_scheduler keeps track of a driver specified + * credit limit representing the capacity of this scheduler and a credit count; + * every &drm_sched_job carries a driver specified number of credits. + * + * Once a job is executed (but not yet finished), the job's credits contribute + * to the scheduler's credit count until the job is finished. If by executing + * one more job the scheduler's credit count would exceed the scheduler's + * credit limit, the job won't be executed. Instead, the scheduler will wait + * until the credit count has decreased enough to not overflow its credit limit. + * This implies waiting for previously executed jobs. + * + * Optionally, drivers may register a callback (update_job_credits) provided by + * struct drm_sched_backend_ops to update the job's credits dynamically. The + * scheduler executes this callback every time the scheduler considers a job for + * execution and subsequently checks whether the job fits the scheduler's credit + * limit. + */ + #include #include #include @@ -75,6 +99,51 @@ int drm_sched_policy = DRM_SCHED_POLICY_FIFO; MODULE_PARM_DESC(sched_policy, "Specify the scheduling policy for entities on a run-queue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin, " __stringify(DRM_SCHED_POLICY_FIFO) " = FIFO (default)."); module_param_named(sched_policy, drm_sched_policy, int, 0444); +static u32 drm_sched_available_credits(struct drm_gpu_scheduler *sched) +{ + u32 credits; + + drm_WARN_ON(sched, check_sub_overflow(sched->credit_limit, + atomic_read(&sched->credit_count), + &credits)); + + return credits; +} + +/** + * drm_sched_can_queue -- Can we queue more to the hardware? + * @sched: scheduler instance + * @entity: the scheduler entity + * + * Return true if we can push at least one more job from @entity, false + * otherwise. + */ +static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity) +{ + struct drm_sched_job *s_job; + + s_job = to_drm_sched_job(spsc_queue_peek(&entity->job_queue)); + if (!s_job) + return false; + + if (sched->ops->update_job_credits) { + s_job->credits = sched->ops->update_job_credits(s_job); + + drm_WARN(sched, !s_job->credits, + "Jobs with zero credits bypass job-flow control.\n"); + } + + /* If a job exceeds the credit limit, truncate it to the credit limit + * itself to guarantee forward progress. + */ + if (drm_WARN(sched, s_job->credits > sched->credit_limit, + "Jobs may not exceed the credit limit, truncate.\n")) + s_job->credits = sched->credit_limit; + + return drm_sched_available_credits(sched) >= s_job->credits; +} + static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a, const struct rb_node *b) { @@ -186,12 +255,18 @@ void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, /** * drm_sched_rq_select_entity_rr - Select an entity which could provide a job to run * + * @sched: the gpu scheduler * @rq: scheduler run queue to check. * - * Try to find a ready entity, returns NULL if none found. + * Try to find the next ready entity. + * + * Return an entity if one is found; return an error-pointer (!NULL) if an + * entity was ready, but the scheduler had insufficient credits to accommodate + * its job; return NULL, if no ready entity was found. */ static struct drm_sched_entity * -drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) +drm_sched_rq_select_entity_rr(struct drm_gpu_scheduler *sched, + struct drm_sched_rq *rq) { struct drm_sched_entity *entity; @@ -201,6 +276,14 @@ drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) if (entity) { list_for_each_entry_continue(entity, &rq->entities, list) { if (drm_sched_entity_is_ready(entity)) { + /* If we can't queue yet, preserve the current + * entity in terms of fairness. + */ + if (!drm_sched_can_queue(sched, entity)) { + spin_unlock(&rq->lock); + return ERR_PTR(-ENOSPC); + } + rq->current_entity = entity; reinit_completion(&entity->entity_idle); spin_unlock(&rq->lock); @@ -210,8 +293,15 @@ drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) } list_for_each_entry(entity, &rq->entities, list) { - if (drm_sched_entity_is_ready(entity)) { + /* If we can't queue yet, preserve the current entity in + * terms of fairness. + */ + if (!drm_sched_can_queue(sched, entity)) { + spin_unlock(&rq->lock); + return ERR_PTR(-ENOSPC); + } + rq->current_entity = entity; reinit_completion(&entity->entity_idle); spin_unlock(&rq->lock); @@ -230,12 +320,18 @@ drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) /** * drm_sched_rq_select_entity_fifo - Select an entity which provides a job to run * + * @sched: the gpu scheduler * @rq: scheduler run queue to check. * - * Find oldest waiting ready entity, returns NULL if none found. + * Find oldest waiting ready entity. + * + * Return an entity if one is found; return an error-pointer (!NULL) if an + * entity was ready, but the scheduler had insufficient credits to accommodate + * its job; return NULL, if no ready entity was found. */ static struct drm_sched_entity * -drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) +drm_sched_rq_select_entity_fifo(struct drm_gpu_scheduler *sched, + struct drm_sched_rq *rq) { struct rb_node *rb; @@ -245,6 +341,14 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) entity = rb_entry(rb, struct drm_sched_entity, rb_tree_node); if (drm_sched_entity_is_ready(entity)) { + /* If we can't queue yet, preserve the current entity in + * terms of fairness. + */ + if (!drm_sched_can_queue(sched, entity)) { + spin_unlock(&rq->lock); + return ERR_PTR(-ENOSPC); + } + rq->current_entity = entity; reinit_completion(&entity->entity_idle); break; @@ -302,7 +406,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result) struct drm_sched_fence *s_fence = s_job->s_fence; struct drm_gpu_scheduler *sched = s_fence->sched; - atomic_dec(&sched->hw_rq_count); + atomic_sub(s_job->credits, &sched->credit_count); atomic_dec(sched->score); trace_drm_sched_process_job(s_fence); @@ -525,7 +629,7 @@ void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) &s_job->cb)) { dma_fence_put(s_job->s_fence->parent); s_job->s_fence->parent = NULL; - atomic_dec(&sched->hw_rq_count); + atomic_sub(s_job->credits, &sched->credit_count); } else { /* * remove job from pending_list. @@ -586,7 +690,7 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) { struct dma_fence *fence = s_job->s_fence->parent; - atomic_inc(&sched->hw_rq_count); + atomic_add(s_job->credits, &sched->credit_count); if (!full_recovery) continue; @@ -667,6 +771,8 @@ EXPORT_SYMBOL(drm_sched_resubmit_jobs); * drm_sched_job_init - init a scheduler job * @job: scheduler job to init * @entity: scheduler entity to use + * @credits: the number of credits this job contributes to the schedulers + * credit limit * @owner: job owner for debugging * * Refer to drm_sched_entity_push_job() documentation @@ -684,7 +790,7 @@ EXPORT_SYMBOL(drm_sched_resubmit_jobs); */ int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, - void *owner) + u32 credits, void *owner) { if (!entity->rq) { /* This will most likely be followed by missing frames @@ -695,7 +801,13 @@ int drm_sched_job_init(struct drm_sched_job *job, return -ENOENT; } + if (unlikely(!credits)) { + pr_err("*ERROR* %s: credits cannot be 0!\n", __func__); + return -EINVAL; + } + job->entity = entity; + job->credits = credits; job->s_fence = drm_sched_fence_alloc(entity, owner); if (!job->s_fence) return -ENOMEM; @@ -907,21 +1019,10 @@ void drm_sched_job_cleanup(struct drm_sched_job *job) } EXPORT_SYMBOL(drm_sched_job_cleanup); -/** - * drm_sched_can_queue -- Can we queue more to the hardware? - * @sched: scheduler instance - * - * Return true if we can push more jobs to the hw, otherwise false. - */ -static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) -{ - return atomic_read(&sched->hw_rq_count) < - sched->hw_submission_limit; -} - /** * drm_sched_wakeup - Wake up the scheduler if it is ready to queue * @sched: scheduler instance + * @entity: the scheduler entity * * Wake up the scheduler if we can queue jobs. */ @@ -929,7 +1030,7 @@ void drm_sched_wakeup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { if (drm_sched_entity_is_ready(entity)) - if (drm_sched_can_queue(sched)) + if (drm_sched_can_queue(sched, entity)) drm_sched_run_job_queue(sched); } @@ -938,7 +1039,11 @@ void drm_sched_wakeup(struct drm_gpu_scheduler *sched, * * @sched: scheduler instance * - * Returns the entity to process or NULL if none are found. + * Return an entity to process or NULL if none are found. + * + * Note, that we break out of the for-loop when "entity" is non-null, which can + * also be an error-pointer--this assures we don't process lower priority + * run-queues. See comments in the respectively called functions. */ static struct drm_sched_entity * drm_sched_select_entity(struct drm_gpu_scheduler *sched) @@ -946,19 +1051,16 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) struct drm_sched_entity *entity; int i; - if (!drm_sched_can_queue(sched)) - return NULL; - /* Kernel run queue has higher priority than normal run queue*/ for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ? - drm_sched_rq_select_entity_fifo(sched->sched_rq[i]) : - drm_sched_rq_select_entity_rr(sched->sched_rq[i]); + drm_sched_rq_select_entity_fifo(sched, sched->sched_rq[i]) : + drm_sched_rq_select_entity_rr(sched, sched->sched_rq[i]); if (entity) break; } - return entity; + return IS_ERR(entity) ? NULL : entity; } /** @@ -1094,7 +1196,7 @@ static void drm_sched_run_job_work(struct work_struct *w) s_fence = sched_job->s_fence; - atomic_inc(&sched->hw_rq_count); + atomic_add(sched_job->credits, &sched->credit_count); drm_sched_job_begin(sched_job); trace_drm_run_job(sched_job, entity); @@ -1129,7 +1231,7 @@ static void drm_sched_run_job_work(struct work_struct *w) * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is * allocated and used * @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT - * @hw_submission: number of hw submissions that can be in flight + * @credit_limit: the number of credits this scheduler can hold from all jobs * @hang_limit: number of times to allow a job to hang before dropping it * @timeout: timeout value in jiffies for the scheduler * @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is @@ -1143,14 +1245,14 @@ static void drm_sched_run_job_work(struct work_struct *w) int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, struct workqueue_struct *submit_wq, - u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit, + u32 num_rqs, u32 credit_limit, unsigned int hang_limit, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev) { int i, ret; sched->ops = ops; - sched->hw_submission_limit = hw_submission; + sched->credit_limit = credit_limit; sched->name = name; sched->timeout = timeout; sched->timeout_wq = timeout_wq ? : system_wq; @@ -1199,7 +1301,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, init_waitqueue_head(&sched->job_scheduled); INIT_LIST_HEAD(&sched->pending_list); spin_lock_init(&sched->job_list_lock); - atomic_set(&sched->hw_rq_count, 0); + atomic_set(&sched->credit_count, 0); INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout); INIT_WORK(&sched->work_run_job, drm_sched_run_job_work); INIT_WORK(&sched->work_free_job, drm_sched_free_job_work); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 712675134c04..9d2ac23c29e3 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -418,7 +418,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, job->file = file_priv; ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], - v3d_priv); + 1, v3d_priv); if (ret) goto fail; diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 09916c84703f..1d60eab747de 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -321,6 +321,7 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); * @sched: the scheduler instance on which this job is scheduled. * @s_fence: contains the fences for the scheduling of job. * @finish_cb: the callback for the finished fence. + * @credits: the number of credits this job contributes to the scheduler * @work: Helper to reschdeule job kill to different context. * @id: a unique id assigned to each job scheduled on the scheduler. * @karma: increment on every hang caused by this job. If this exceeds the hang @@ -340,6 +341,8 @@ struct drm_sched_job { struct drm_gpu_scheduler *sched; struct drm_sched_fence *s_fence; + u32 credits; + /* * work is used only after finish_cb has been used and will not be * accessed anymore. @@ -463,13 +466,27 @@ struct drm_sched_backend_ops { * and it's time to clean it up. */ void (*free_job)(struct drm_sched_job *sched_job); + + /** + * @update_job_credits: Called when the scheduler is considering this + * job for execution. + * + * This callback returns the number of credits the job would take if + * pushed to the hardware. Drivers may use this to dynamically update + * the job's credit count. For instance, deduct the number of credits + * for already signalled native fences. + * + * This callback is optional. + */ + u32 (*update_job_credits)(struct drm_sched_job *sched_job); }; /** * struct drm_gpu_scheduler - scheduler instance-specific data * * @ops: backend operations provided by the driver. - * @hw_submission_limit: the max size of the hardware queue. + * @credit_limit: the credit limit of this scheduler + * @credit_count: the current credit count of this scheduler * @timeout: the time after which a job is removed from the scheduler. * @name: name of the ring for which this scheduler is being used. * @num_rqs: Number of run-queues. This is at most DRM_SCHED_PRIORITY_COUNT, @@ -478,7 +495,6 @@ struct drm_sched_backend_ops { * @job_scheduled: once @drm_sched_entity_do_release is called the scheduler * waits on this wait queue until all the scheduled jobs are * finished. - * @hw_rq_count: the number of jobs currently in the hardware queue. * @job_id_count: used to assign unique id to the each job. * @submit_wq: workqueue used to queue @work_run_job and @work_free_job * @timeout_wq: workqueue used to queue @work_tdr @@ -502,13 +518,13 @@ struct drm_sched_backend_ops { */ struct drm_gpu_scheduler { const struct drm_sched_backend_ops *ops; - uint32_t hw_submission_limit; + u32 credit_limit; + atomic_t credit_count; long timeout; const char *name; u32 num_rqs; struct drm_sched_rq **sched_rq; wait_queue_head_t job_scheduled; - atomic_t hw_rq_count; atomic64_t job_id_count; struct workqueue_struct *submit_wq; struct workqueue_struct *timeout_wq; @@ -530,14 +546,14 @@ struct drm_gpu_scheduler { int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, struct workqueue_struct *submit_wq, - u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit, + u32 num_rqs, u32 credit_limit, unsigned int hang_limit, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev); void drm_sched_fini(struct drm_gpu_scheduler *sched); int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, - void *owner); + u32 credits, void *owner); void drm_sched_job_arm(struct drm_sched_job *job); int drm_sched_job_add_dependency(struct drm_sched_job *job, struct dma_fence *fence); From 2b62aa59d02ed281fa4fc218df3ca91b773e1e62 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:43 -0700 Subject: [PATCH 0309/7721] selftests/bpf: fix RELEASE=1 build for tc_opts Compiler complains about malloc(). We also don't need to dynamically allocate anything, so make the life easier by using statically sized buffer. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/tc_opts.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tc_opts.c b/tools/testing/selftests/bpf/prog_tests/tc_opts.c index 51883ccb8020..196abf223465 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_opts.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_opts.c @@ -2387,12 +2387,9 @@ static int generate_dummy_prog(void) const size_t prog_insn_cnt = sizeof(prog_insns) / sizeof(struct bpf_insn); LIBBPF_OPTS(bpf_prog_load_opts, opts); const size_t log_buf_sz = 256; - char *log_buf; + char log_buf[log_buf_sz]; int fd = -1; - log_buf = malloc(log_buf_sz); - if (!ASSERT_OK_PTR(log_buf, "log_buf_alloc")) - return fd; opts.log_buf = log_buf; opts.log_size = log_buf_sz; @@ -2402,7 +2399,6 @@ static int generate_dummy_prog(void) prog_insns, prog_insn_cnt, &opts); ASSERT_STREQ(log_buf, "", "log_0"); ASSERT_GE(fd, 0, "prog_fd"); - free(log_buf); return fd; } From fac85c291e141a67fce46bdce01f9ee33aafabfe Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Sat, 28 Oct 2023 10:54:13 +0530 Subject: [PATCH 0310/7721] selftests/bpf: Convert CHECK macros to ASSERT_* macros in bpf_iter As it was pointed out by Yonghong Song [1], in the bpf selftests the use of the ASSERT_* series of macros is preferred over the CHECK macro. This patch replaces all CHECK calls in bpf_iter with the appropriate ASSERT_* macros. [1] https://lore.kernel.org/lkml/0a142924-633c-44e6-9a92-2dc019656bf2@linux.dev Suggested-by: Yonghong Song Signed-off-by: Yuran Pereira Acked-by: Yonghong Song Acked-by: Kui-Feng Lee Link: https://lore.kernel.org/r/DB3PR10MB6835E9C8DFCA226DD6FEF914E8A3A@DB3PR10MB6835.EURPRD10.PROD.OUTLOOK.COM Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/bpf_iter.c | 79 ++++++++----------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c index e3498f607b49..5e334d3d7ac2 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -34,8 +34,6 @@ #include "bpf_iter_ksym.skel.h" #include "bpf_iter_sockmap.skel.h" -static int duration; - static void test_btf_id_or_null(void) { struct bpf_iter_test_kern3 *skel; @@ -64,7 +62,7 @@ static void do_dummy_read_opts(struct bpf_program *prog, struct bpf_iter_attach_ /* not check contents, but ensure read() ends without error */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - CHECK(len < 0, "read", "read failed: %s\n", strerror(errno)); + ASSERT_GE(len, 0, "read"); close(iter_fd); @@ -413,7 +411,7 @@ static int do_btf_read(struct bpf_iter_task_btf *skel) goto free_link; } - if (CHECK(err < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(err, 0, "read")) goto free_link; ASSERT_HAS_SUBSTR(taskbuf, "(struct task_struct)", @@ -526,11 +524,11 @@ static int do_read_with_fd(int iter_fd, const char *expected, start = 0; while ((len = read(iter_fd, buf + start, read_buf_len)) > 0) { start += len; - if (CHECK(start >= 16, "read", "read len %d\n", len)) + if (!ASSERT_LT(start, 16, "read")) return -1; read_buf_len = read_one_char ? 1 : 16 - start; } - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) return -1; if (!ASSERT_STREQ(buf, expected, "read")) @@ -571,8 +569,7 @@ static int do_read(const char *path, const char *expected) int err, iter_fd; iter_fd = open(path, O_RDONLY); - if (CHECK(iter_fd < 0, "open", "open %s failed: %s\n", - path, strerror(errno))) + if (!ASSERT_GE(iter_fd, 0, "open")) return -1; err = do_read_with_fd(iter_fd, expected, false); @@ -600,7 +597,7 @@ static void test_file_iter(void) unlink(path); err = bpf_link__pin(link, path); - if (CHECK(err, "pin_iter", "pin_iter to %s failed: %d\n", path, err)) + if (!ASSERT_OK(err, "pin_iter")) goto free_link; err = do_read(path, "abcd"); @@ -651,12 +648,10 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) * overflow and needs restart. */ map1_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 8, 1, NULL); - if (CHECK(map1_fd < 0, "bpf_map_create", - "map_creation failed: %s\n", strerror(errno))) + if (!ASSERT_GE(map1_fd, 0, "bpf_map_create")) goto out; map2_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 8, 1, NULL); - if (CHECK(map2_fd < 0, "bpf_map_create", - "map_creation failed: %s\n", strerror(errno))) + if (!ASSERT_GE(map2_fd, 0, "bpf_map_create")) goto free_map1; /* bpf_seq_printf kernel buffer is 8 pages, so one map @@ -685,14 +680,12 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) /* setup filtering map_id in bpf program */ map_info_len = sizeof(map_info); err = bpf_map_get_info_by_fd(map1_fd, &map_info, &map_info_len); - if (CHECK(err, "get_map_info", "get map info failed: %s\n", - strerror(errno))) + if (!ASSERT_OK(err, "get_map_info")) goto free_map2; skel->bss->map1_id = map_info.id; err = bpf_map_get_info_by_fd(map2_fd, &map_info, &map_info_len); - if (CHECK(err, "get_map_info", "get map info failed: %s\n", - strerror(errno))) + if (!ASSERT_OK(err, "get_map_info")) goto free_map2; skel->bss->map2_id = map_info.id; @@ -714,16 +707,14 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) while ((len = read(iter_fd, buf, expected_read_len)) > 0) total_read_len += len; - CHECK(len != -1 || errno != E2BIG, "read", - "expected ret -1, errno E2BIG, but get ret %d, error %s\n", - len, strerror(errno)); + ASSERT_EQ(len, -1, "read"); + ASSERT_EQ(errno, E2BIG, "read"); goto free_buf; } else if (!ret1) { while ((len = read(iter_fd, buf, expected_read_len)) > 0) total_read_len += len; - if (CHECK(len < 0, "read", "read failed: %s\n", - strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto free_buf; } else { do { @@ -732,8 +723,7 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) total_read_len += len; } while (len > 0 || len == -EAGAIN); - if (CHECK(len < 0, "read", "read failed: %s\n", - strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto free_buf; } @@ -836,7 +826,7 @@ static void test_bpf_hash_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -917,7 +907,7 @@ static void test_bpf_percpu_hash_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -983,17 +973,14 @@ static void test_bpf_array_map(void) start = 0; while ((len = read(iter_fd, buf + start, sizeof(buf) - start)) > 0) start += len; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ res_first_key = *(__u32 *)buf; res_first_val = *(__u64 *)(buf + sizeof(__u32)); - if (CHECK(res_first_key != 0 || res_first_val != first_val, - "bpf_seq_write", - "seq_write failure: first key %u vs expected 0, " - " first value %llu vs expected %llu\n", - res_first_key, res_first_val, first_val)) + if (!ASSERT_EQ(res_first_key, 0, "bpf_seq_write") || + !ASSERT_EQ(res_first_val, first_val, "bpf_seq_write")) goto close_iter; if (!ASSERT_EQ(skel->bss->key_sum, expected_key, "key_sum")) @@ -1092,7 +1079,7 @@ static void test_bpf_percpu_array_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -1131,6 +1118,7 @@ static void test_bpf_sk_storage_delete(void) sock_fd = socket(AF_INET6, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "socket")) goto out; + err = bpf_map_update_elem(map_fd, &sock_fd, &val, BPF_NOEXIST); if (!ASSERT_OK(err, "map_update")) goto out; @@ -1151,14 +1139,19 @@ static void test_bpf_sk_storage_delete(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - if (CHECK(!err || errno != ENOENT, "bpf_map_lookup_elem", - "map value wasn't deleted (err=%d, errno=%d)\n", err, errno)) - goto close_iter; + + /* Note: The following assertions serve to ensure + * the value was deleted. It does so by asserting + * that bpf_map_lookup_elem has failed. This might + * seem counterintuitive at first. + */ + ASSERT_ERR(err, "bpf_map_lookup_elem"); + ASSERT_EQ(errno, ENOENT, "bpf_map_lookup_elem"); close_iter: close(iter_fd); @@ -1203,17 +1196,15 @@ static void test_bpf_sk_storage_get(void) do_dummy_read(skel->progs.fill_socket_owner); err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - if (CHECK(err || val != getpid(), "bpf_map_lookup_elem", - "map value wasn't set correctly (expected %d, got %d, err=%d)\n", - getpid(), val, err)) + if (!ASSERT_OK(err, "bpf_map_lookup_elem") || + !ASSERT_EQ(val, getpid(), "bpf_map_lookup_elem")) goto close_socket; do_dummy_read(skel->progs.negate_socket_local_storage); err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - CHECK(err || val != -getpid(), "bpf_map_lookup_elem", - "map value wasn't set correctly (expected %d, got %d, err=%d)\n", - -getpid(), val, err); + ASSERT_OK(err, "bpf_map_lookup_elem"); + ASSERT_EQ(val, -getpid(), "bpf_map_lookup_elem"); close_socket: close(sock_fd); @@ -1290,7 +1281,7 @@ static void test_bpf_sk_storage_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ From f4c7e887324f5776eef6e6e47a90e0ac8058a7a8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:44 -0700 Subject: [PATCH 0311/7721] selftests/bpf: satisfy compiler by having explicit return in btf test Some compilers complain about get_pprint_mapv_size() not returning value in some code paths. Fix with explicit return. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/btf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c index 92d51f377fe5..8fb4a04fbbc0 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf.c +++ b/tools/testing/selftests/bpf/prog_tests/btf.c @@ -5265,6 +5265,7 @@ static size_t get_pprint_mapv_size(enum pprint_mapv_kind_t mapv_kind) #endif assert(0); + return 0; } static void set_pprint_mapv(enum pprint_mapv_kind_t mapv_kind, From bf4a64b9323f181df8aba32d66cb37b9fa5df959 Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Sat, 28 Oct 2023 10:54:14 +0530 Subject: [PATCH 0312/7721] selftests/bpf: Add malloc failure checks in bpf_iter Since some malloc calls in bpf_iter may at times fail, this patch adds the appropriate fail checks, and ensures that any previously allocated resource is appropriately destroyed before returning the function. Signed-off-by: Yuran Pereira Acked-by: Yonghong Song Acked-by: Kui-Feng Lee Link: https://lore.kernel.org/r/DB3PR10MB6835F0ECA792265FA41FC39BE8A3A@DB3PR10MB6835.EURPRD10.PROD.OUTLOOK.COM Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/bpf_iter.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c index 5e334d3d7ac2..4e02093c2cbe 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -698,7 +698,7 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) goto free_link; buf = malloc(expected_read_len); - if (!buf) + if (!ASSERT_OK_PTR(buf, "malloc")) goto close_iter; /* do read */ @@ -868,6 +868,8 @@ static void test_bpf_percpu_hash_map(void) skel->rodata->num_cpus = bpf_num_possible_cpus(); val = malloc(8 * bpf_num_possible_cpus()); + if (!ASSERT_OK_PTR(val, "malloc")) + goto out; err = bpf_iter_bpf_percpu_hash_map__load(skel); if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_percpu_hash_map__load")) @@ -1044,6 +1046,8 @@ static void test_bpf_percpu_array_map(void) skel->rodata->num_cpus = bpf_num_possible_cpus(); val = malloc(8 * bpf_num_possible_cpus()); + if (!ASSERT_OK_PTR(val, "malloc")) + goto out; err = bpf_iter_bpf_percpu_array_map__load(skel); if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_percpu_array_map__load")) From 93f7378734b595fb61e89b802002fb7e3a1267d2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:45 -0700 Subject: [PATCH 0313/7721] bpf: derive smin/smax from umin/max bounds Add smin/smax derivation from appropriate umin/umax values. Previously the logic was surprisingly asymmetric, trying to derive umin/umax from smin/smax (if possible), but not trying to do the same in the other direction. A simple addition to __reg64_deduce_bounds() fixes this. Added also generic comment about u64/s64 ranges and their relationship. Hopefully that helps readers to understand all the bounds deductions a bit better. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index bd1c42eb540f..1a5c389b951a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2358,6 +2358,77 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) static void __reg64_deduce_bounds(struct bpf_reg_state *reg) { + /* If u64 range forms a valid s64 range (due to matching sign bit), + * try to learn from that. Let's do a bit of ASCII art to see when + * this is happening. Let's take u64 range first: + * + * 0 0x7fffffffffffffff 0x8000000000000000 U64_MAX + * |-------------------------------|--------------------------------| + * + * Valid u64 range is formed when umin and umax are anywhere in the + * range [0, U64_MAX], and umin <= umax. u64 case is simple and + * straightforward. Let's see how s64 range maps onto the same range + * of values, annotated below the line for comparison: + * + * 0 0x7fffffffffffffff 0x8000000000000000 U64_MAX + * |-------------------------------|--------------------------------| + * 0 S64_MAX S64_MIN -1 + * + * So s64 values basically start in the middle and they are logically + * contiguous to the right of it, wrapping around from -1 to 0, and + * then finishing as S64_MAX (0x7fffffffffffffff) right before + * S64_MIN. We can try drawing the continuity of u64 vs s64 values + * more visually as mapped to sign-agnostic range of hex values. + * + * u64 start u64 end + * _______________________________________________________________ + * / \ + * 0 0x7fffffffffffffff 0x8000000000000000 U64_MAX + * |-------------------------------|--------------------------------| + * 0 S64_MAX S64_MIN -1 + * / \ + * >------------------------------ -------------------------------> + * s64 continues... s64 end s64 start s64 "midpoint" + * + * What this means is that, in general, we can't always derive + * something new about u64 from any random s64 range, and vice versa. + * + * But we can do that in two particular cases. One is when entire + * u64/s64 range is *entirely* contained within left half of the above + * diagram or when it is *entirely* contained in the right half. I.e.: + * + * |-------------------------------|--------------------------------| + * ^ ^ ^ ^ + * A B C D + * + * [A, B] and [C, D] are contained entirely in their respective halves + * and form valid contiguous ranges as both u64 and s64 values. [A, B] + * will be non-negative both as u64 and s64 (and in fact it will be + * identical ranges no matter the signedness). [C, D] treated as s64 + * will be a range of negative values, while in u64 it will be + * non-negative range of values larger than 0x8000000000000000. + * + * Now, any other range here can't be represented in both u64 and s64 + * simultaneously. E.g., [A, C], [A, D], [B, C], [B, D] are valid + * contiguous u64 ranges, but they are discontinuous in s64. [B, C] + * in s64 would be properly presented as [S64_MIN, C] and [B, S64_MAX], + * for example. Similarly, valid s64 range [D, A] (going from negative + * to positive values), would be two separate [D, U64_MAX] and [0, A] + * ranges as u64. Currently reg_state can't represent two segments per + * numeric domain, so in such situations we can only derive maximal + * possible range ([0, U64_MAX] for u64, and [S64_MIN, S64_MAX] for s64). + * + * So we use these facts to derive umin/umax from smin/smax and vice + * versa only if they stay within the same "half". This is equivalent + * to checking sign bit: lower half will have sign bit as zero, upper + * half have sign bit 1. Below in code we simplify this by just + * casting umin/umax as smin/smax and checking if they form valid + * range, and vice versa. Those are equivalent checks. + */ + if ((s64)reg->umin_value <= (s64)reg->umax_value) { + reg->smin_value = max_t(s64, reg->smin_value, reg->umin_value); + reg->smax_value = min_t(s64, reg->smax_value, reg->umax_value); + } /* Learn sign from signed bounds. * If we cannot cross the sign boundary, then signed and unsigned bounds * are the same, so combine. This works even in the negative case, e.g. From d540517990a9d105bf0312760665964916ac044f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:46 -0700 Subject: [PATCH 0314/7721] bpf: derive smin32/smax32 from umin32/umax32 bounds All the logic that applies to u64 vs s64, equally applies for u32 vs s32 relationships (just taken in a smaller 32-bit numeric space). So do the same deduction of smin32/smax32 from umin32/umax32, if we can. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1a5c389b951a..b53ee72a7d72 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2324,6 +2324,13 @@ static void __update_reg_bounds(struct bpf_reg_state *reg) /* Uses signed min/max values to inform unsigned, and vice-versa */ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) { + /* if u32 range forms a valid s32 range (due to matching sign bit), + * try to learn from that + */ + if ((s32)reg->u32_min_value <= (s32)reg->u32_max_value) { + reg->s32_min_value = max_t(s32, reg->s32_min_value, reg->u32_min_value); + reg->s32_max_value = min_t(s32, reg->s32_max_value, reg->u32_max_value); + } /* Learn sign from signed bounds. * If we cannot cross the sign boundary, then signed and unsigned bounds * are the same, so combine. This works even in the negative case, e.g. From c1efab6468fd5ef541d47d81dbb62cca27f8db3b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:47 -0700 Subject: [PATCH 0315/7721] bpf: derive subreg bounds from full bounds when upper 32 bits are constant Comments in code try to explain the idea behind why this is correct. Please check the code and comments. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b53ee72a7d72..9e39f12538f7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2324,6 +2324,51 @@ static void __update_reg_bounds(struct bpf_reg_state *reg) /* Uses signed min/max values to inform unsigned, and vice-versa */ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) { + /* If upper 32 bits of u64/s64 range don't change, we can use lower 32 + * bits to improve our u32/s32 boundaries. + * + * E.g., the case where we have upper 32 bits as zero ([10, 20] in + * u64) is pretty trivial, it's obvious that in u32 we'll also have + * [10, 20] range. But this property holds for any 64-bit range as + * long as upper 32 bits in that entire range of values stay the same. + * + * E.g., u64 range [0x10000000A, 0x10000000F] ([4294967306, 4294967311] + * in decimal) has the same upper 32 bits throughout all the values in + * that range. As such, lower 32 bits form a valid [0xA, 0xF] ([10, 15]) + * range. + * + * Note also, that [0xA, 0xF] is a valid range both in u32 and in s32, + * following the rules outlined below about u64/s64 correspondence + * (which equally applies to u32 vs s32 correspondence). In general it + * depends on actual hexadecimal values of 32-bit range. They can form + * only valid u32, or only valid s32 ranges in some cases. + * + * So we use all these insights to derive bounds for subregisters here. + */ + if ((reg->umin_value >> 32) == (reg->umax_value >> 32)) { + /* u64 to u32 casting preserves validity of low 32 bits as + * a range, if upper 32 bits are the same + */ + reg->u32_min_value = max_t(u32, reg->u32_min_value, (u32)reg->umin_value); + reg->u32_max_value = min_t(u32, reg->u32_max_value, (u32)reg->umax_value); + + if ((s32)reg->umin_value <= (s32)reg->umax_value) { + reg->s32_min_value = max_t(s32, reg->s32_min_value, (s32)reg->umin_value); + reg->s32_max_value = min_t(s32, reg->s32_max_value, (s32)reg->umax_value); + } + } + if ((reg->smin_value >> 32) == (reg->smax_value >> 32)) { + /* low 32 bits should form a proper u32 range */ + if ((u32)reg->smin_value <= (u32)reg->smax_value) { + reg->u32_min_value = max_t(u32, reg->u32_min_value, (u32)reg->smin_value); + reg->u32_max_value = min_t(u32, reg->u32_max_value, (u32)reg->smax_value); + } + /* low 32 bits should form a proper s32 range */ + if ((s32)reg->smin_value <= (s32)reg->smax_value) { + reg->s32_min_value = max_t(s32, reg->s32_min_value, (s32)reg->smin_value); + reg->s32_max_value = min_t(s32, reg->s32_max_value, (s32)reg->smax_value); + } + } /* if u32 range forms a valid s32 range (due to matching sign bit), * try to learn from that */ From 6593f2e6741f03b49bffc9d55ddd4c1c47853c39 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:48 -0700 Subject: [PATCH 0316/7721] bpf: add special smin32/smax32 derivation from 64-bit bounds Add a special case where we can derive valid s32 bounds from umin/umax or smin/smax by stitching together negative s32 subrange and non-negative s32 subrange. That requires upper 32 bits to form a [N, N+1] range in u32 domain (taking into account wrap around, so 0xffffffff to 0x00000000 is a valid [N, N+1] range in this sense). See code comment for concrete examples. Eduard Zingerman also provided an alternative explanation ([0]) for more mathematically inclined readers: Suppose: . there are numbers a, b, c . 2**31 <= b < 2**32 . 0 <= c < 2**31 . umin = 2**32 * a + b . umax = 2**32 * (a + 1) + c The number of values in the range represented by [umin; umax] is: . N = umax - umin + 1 = 2**32 + c - b + 1 . min(N) = 2**32 + 0 - (2**32-1) + 1 = 2, with b = 2**32-1, c = 0 . max(N) = 2**32 + (2**31 - 1) - 2**31 + 1 = 2**32, with b = 2**31, c = 2**31-1 Hence [(s32)b; (s32)c] forms a valid range. [0] https://lore.kernel.org/bpf/d7af631802f0cfae20df77fe70068702d24bbd31.camel@gmail.com/ Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9e39f12538f7..0fffbf01328e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2369,6 +2369,29 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) reg->s32_max_value = min_t(s32, reg->s32_max_value, (s32)reg->smax_value); } } + /* Special case where upper bits form a small sequence of two + * sequential numbers (in 32-bit unsigned space, so 0xffffffff to + * 0x00000000 is also valid), while lower bits form a proper s32 range + * going from negative numbers to positive numbers. E.g., let's say we + * have s64 range [-1, 1] ([0xffffffffffffffff, 0x0000000000000001]). + * Possible s64 values are {-1, 0, 1} ({0xffffffffffffffff, + * 0x0000000000000000, 0x00000000000001}). Ignoring upper 32 bits, + * we still get a valid s32 range [-1, 1] ([0xffffffff, 0x00000001]). + * Note that it doesn't have to be 0xffffffff going to 0x00000000 in + * upper 32 bits. As a random example, s64 range + * [0xfffffff0fffffff0; 0xfffffff100000010], forms a valid s32 range + * [-16, 16] ([0xfffffff0; 0x00000010]) in its 32 bit subregister. + */ + if ((u32)(reg->umin_value >> 32) + 1 == (u32)(reg->umax_value >> 32) && + (s32)reg->umin_value < 0 && (s32)reg->umax_value >= 0) { + reg->s32_min_value = max_t(s32, reg->s32_min_value, (s32)reg->umin_value); + reg->s32_max_value = min_t(s32, reg->s32_max_value, (s32)reg->umax_value); + } + if ((u32)(reg->smin_value >> 32) + 1 == (u32)(reg->smax_value >> 32) && + (s32)reg->smin_value < 0 && (s32)reg->smax_value >= 0) { + reg->s32_min_value = max_t(s32, reg->s32_min_value, (s32)reg->smin_value); + reg->s32_max_value = min_t(s32, reg->s32_max_value, (s32)reg->smax_value); + } /* if u32 range forms a valid s32 range (due to matching sign bit), * try to learn from that */ From c51d5ad6543cc36334ef1fcd762d0df767a0bf7e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:49 -0700 Subject: [PATCH 0317/7721] bpf: improve deduction of 64-bit bounds from 32-bit bounds Add a few interesting cases in which we can tighten 64-bit bounds based on newly learnt information about 32-bit bounds. E.g., when full u64/s64 registers are used in BPF program, and then eventually compared as u32/s32. The latter comparison doesn't change the value of full register, but it does impose new restrictions on possible lower 32 bits of such full registers. And we can use that to derive additional full register bounds information. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231102033759.2541186-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0fffbf01328e..969f1ecfe310 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2536,10 +2536,54 @@ static void __reg64_deduce_bounds(struct bpf_reg_state *reg) } } +static void __reg_deduce_mixed_bounds(struct bpf_reg_state *reg) +{ + /* Try to tighten 64-bit bounds from 32-bit knowledge, using 32-bit + * values on both sides of 64-bit range in hope to have tigher range. + * E.g., if r1 is [0x1'00000000, 0x3'80000000], and we learn from + * 32-bit signed > 0 operation that s32 bounds are now [1; 0x7fffffff]. + * With this, we can substitute 1 as low 32-bits of _low_ 64-bit bound + * (0x100000000 -> 0x100000001) and 0x7fffffff as low 32-bits of + * _high_ 64-bit bound (0x380000000 -> 0x37fffffff) and arrive at a + * better overall bounds for r1 as [0x1'000000001; 0x3'7fffffff]. + * We just need to make sure that derived bounds we are intersecting + * with are well-formed ranges in respecitve s64 or u64 domain, just + * like we do with similar kinds of 32-to-64 or 64-to-32 adjustments. + */ + __u64 new_umin, new_umax; + __s64 new_smin, new_smax; + + /* u32 -> u64 tightening, it's always well-formed */ + new_umin = (reg->umin_value & ~0xffffffffULL) | reg->u32_min_value; + new_umax = (reg->umax_value & ~0xffffffffULL) | reg->u32_max_value; + reg->umin_value = max_t(u64, reg->umin_value, new_umin); + reg->umax_value = min_t(u64, reg->umax_value, new_umax); + /* u32 -> s64 tightening, u32 range embedded into s64 preserves range validity */ + new_smin = (reg->smin_value & ~0xffffffffULL) | reg->u32_min_value; + new_smax = (reg->smax_value & ~0xffffffffULL) | reg->u32_max_value; + reg->smin_value = max_t(s64, reg->smin_value, new_smin); + reg->smax_value = min_t(s64, reg->smax_value, new_smax); + + /* if s32 can be treated as valid u32 range, we can use it as well */ + if ((u32)reg->s32_min_value <= (u32)reg->s32_max_value) { + /* s32 -> u64 tightening */ + new_umin = (reg->umin_value & ~0xffffffffULL) | (u32)reg->s32_min_value; + new_umax = (reg->umax_value & ~0xffffffffULL) | (u32)reg->s32_max_value; + reg->umin_value = max_t(u64, reg->umin_value, new_umin); + reg->umax_value = min_t(u64, reg->umax_value, new_umax); + /* s32 -> s64 tightening */ + new_smin = (reg->smin_value & ~0xffffffffULL) | (u32)reg->s32_min_value; + new_smax = (reg->smax_value & ~0xffffffffULL) | (u32)reg->s32_max_value; + reg->smin_value = max_t(s64, reg->smin_value, new_smin); + reg->smax_value = min_t(s64, reg->smax_value, new_smax); + } +} + static void __reg_deduce_bounds(struct bpf_reg_state *reg) { __reg32_deduce_bounds(reg); __reg64_deduce_bounds(reg); + __reg_deduce_mixed_bounds(reg); } /* Attempts to improve var_off based on unsigned min/max information */ From d7f00873817129e62f8c70891cb13c8eafe9feef Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:50 -0700 Subject: [PATCH 0318/7721] bpf: try harder to deduce register bounds from different numeric domains There are cases (caught by subsequent reg_bounds tests in selftests/bpf) where performing one round of __reg_deduce_bounds() doesn't propagate all the information from, say, s32 to u32 bounds and than from newly learned u32 bounds back to u64 and s64. So perform __reg_deduce_bounds() twice to make sure such derivations are propagated fully after reg_bounds_sync(). One such example is test `(s64)[0xffffffff00000001; 0] (u64)< 0xffffffff00000000` from selftest patch from this patch set. It demonstrates an intricate dance of u64 -> s64 -> u64 -> u32 bounds adjustments, which requires two rounds of __reg_deduce_bounds(). Here are corresponding refinement log from selftest, showing evolution of knowledge. REFINING (FALSE R1) (u64)SRC=[0xffffffff00000000; U64_MAX] (u64)DST_OLD=[0; U64_MAX] (u64)DST_NEW=[0xffffffff00000000; U64_MAX] REFINING (FALSE R1) (u64)SRC=[0xffffffff00000000; U64_MAX] (s64)DST_OLD=[0xffffffff00000001; 0] (s64)DST_NEW=[0xffffffff00000001; -1] REFINING (FALSE R1) (s64)SRC=[0xffffffff00000001; -1] (u64)DST_OLD=[0xffffffff00000000; U64_MAX] (u64)DST_NEW=[0xffffffff00000001; U64_MAX] REFINING (FALSE R1) (u64)SRC=[0xffffffff00000001; U64_MAX] (u32)DST_OLD=[0; U32_MAX] (u32)DST_NEW=[1; U32_MAX] R1 initially has smin/smax set to [0xffffffff00000001; -1], while umin/umax is unknown. After (u64)< comparison, in FALSE branch we gain knowledge that umin/umax is [0xffffffff00000000; U64_MAX]. That causes smin/smax to learn that zero can't happen and upper bound is -1. Then smin/smax is adjusted from umin/umax improving lower bound from 0xffffffff00000000 to 0xffffffff00000001. And then eventually umin32/umax32 bounds are drived from umin/umax and become [1; U32_MAX]. Selftest in the last patch is actually implementing a multi-round fixed-point convergence logic, but so far all the tests are handled by two rounds of reg_bounds_sync() on the verifier state, so we keep it simple for now. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 969f1ecfe310..61f17b63ba00 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2605,6 +2605,7 @@ static void reg_bounds_sync(struct bpf_reg_state *reg) __update_reg_bounds(reg); /* We might have learned something about the sign bit. */ __reg_deduce_bounds(reg); + __reg_deduce_bounds(reg); /* We might have learned some bits from the bounds. */ __reg_bound_offset(reg); /* Intersecting with the old var_off might have improved our bounds From 9e314f5d8682e1fe6ac214fb34580a238b6fd3c4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:51 -0700 Subject: [PATCH 0319/7721] bpf: drop knowledge-losing __reg_combine_{32,64}_into_{64,32} logic When performing 32-bit conditional operation operating on lower 32 bits of a full 64-bit register, register full value isn't changed. We just potentially gain new knowledge about that register's lower 32 bits. Unfortunately, __reg_combine_{32,64}_into_{64,32} logic that reg_set_min_max() performs as a last step, can lose information in some cases due to __mark_reg64_unbounded() and __reg_assign_32_into_64(). That's bad and completely unnecessary. Especially __reg_assign_32_into_64() looks completely out of place here, because we are not performing zero-extending subregister assignment during conditional jump. So this patch replaced __reg_combine_* with just a normal reg_bounds_sync() which will do a proper job of deriving u64/s64 bounds from u32/s32, and vice versa (among all other combinations). __reg_combine_64_into_32() is also used in one more place, coerce_reg_to_size(), while handling 1- and 2-byte register loads. Looking into this, it seems like besides marking subregister as unbounded before performing reg_bounds_sync(), we were also performing deduction of smin32/smax32 and umin32/umax32 bounds from respective smin/smax and umin/umax bounds. It's now redundant as reg_bounds_sync() performs all the same logic more generically (e.g., without unnecessary assumption that upper 32 bits of full register should be zero). Long story short, we remove __reg_combine_64_into_32() completely, and coerce_reg_to_size() now only does resetting subreg to unbounded and then performing reg_bounds_sync() to recover as much information as possible from 64-bit umin/umax and smin/smax bounds, set explicitly in coerce_reg_to_size() earlier. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231102033759.2541186-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 60 ++++++------------------------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 61f17b63ba00..b4d6b5a032ce 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2639,51 +2639,6 @@ static void __reg_assign_32_into_64(struct bpf_reg_state *reg) } } -static void __reg_combine_32_into_64(struct bpf_reg_state *reg) -{ - /* special case when 64-bit register has upper 32-bit register - * zeroed. Typically happens after zext or <<32, >>32 sequence - * allowing us to use 32-bit bounds directly, - */ - if (tnum_equals_const(tnum_clear_subreg(reg->var_off), 0)) { - __reg_assign_32_into_64(reg); - } else { - /* Otherwise the best we can do is push lower 32bit known and - * unknown bits into register (var_off set from jmp logic) - * then learn as much as possible from the 64-bit tnum - * known and unknown bits. The previous smin/smax bounds are - * invalid here because of jmp32 compare so mark them unknown - * so they do not impact tnum bounds calculation. - */ - __mark_reg64_unbounded(reg); - } - reg_bounds_sync(reg); -} - -static bool __reg64_bound_s32(s64 a) -{ - return a >= S32_MIN && a <= S32_MAX; -} - -static bool __reg64_bound_u32(u64 a) -{ - return a >= U32_MIN && a <= U32_MAX; -} - -static void __reg_combine_64_into_32(struct bpf_reg_state *reg) -{ - __mark_reg32_unbounded(reg); - if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) { - reg->s32_min_value = (s32)reg->smin_value; - reg->s32_max_value = (s32)reg->smax_value; - } - if (__reg64_bound_u32(reg->umin_value) && __reg64_bound_u32(reg->umax_value)) { - reg->u32_min_value = (u32)reg->umin_value; - reg->u32_max_value = (u32)reg->umax_value; - } - reg_bounds_sync(reg); -} - /* Mark a register as having a completely unknown (scalar) value. */ static void __mark_reg_unknown(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) @@ -6387,9 +6342,10 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) * values are also truncated so we push 64-bit bounds into * 32-bit bounds. Above were truncated < 32-bits already. */ - if (size >= 4) - return; - __reg_combine_64_into_32(reg); + if (size < 4) { + __mark_reg32_unbounded(reg); + reg_bounds_sync(reg); + } } static void set_sext64_default_val(struct bpf_reg_state *reg, int size) @@ -14642,13 +14598,13 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, tnum_subreg(false_32off)); true_reg->var_off = tnum_or(tnum_clear_subreg(true_64off), tnum_subreg(true_32off)); - __reg_combine_32_into_64(false_reg); - __reg_combine_32_into_64(true_reg); + reg_bounds_sync(false_reg); + reg_bounds_sync(true_reg); } else { false_reg->var_off = false_64off; true_reg->var_off = true_64off; - __reg_combine_64_into_32(false_reg); - __reg_combine_64_into_32(true_reg); + reg_bounds_sync(false_reg); + reg_bounds_sync(true_reg); } } From c2a3ab094683ddc154879a1364fc7cb0228f96a6 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:53 -0700 Subject: [PATCH 0320/7721] bpf: rename is_branch_taken reg arguments to prepare for the second one Just taking mundane refactoring bits out into a separate patch. No functional changes. Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231102033759.2541186-12-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 108 +++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b4d6b5a032ce..770d5bd54ff3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14188,26 +14188,26 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, })); } -static int is_branch32_taken(struct bpf_reg_state *reg, u32 val, u8 opcode) +static int is_branch32_taken(struct bpf_reg_state *reg1, u32 val, u8 opcode) { - struct tnum subreg = tnum_subreg(reg->var_off); + struct tnum subreg = tnum_subreg(reg1->var_off); s32 sval = (s32)val; switch (opcode) { case BPF_JEQ: if (tnum_is_const(subreg)) return !!tnum_equals_const(subreg, val); - else if (val < reg->u32_min_value || val > reg->u32_max_value) + else if (val < reg1->u32_min_value || val > reg1->u32_max_value) return 0; - else if (sval < reg->s32_min_value || sval > reg->s32_max_value) + else if (sval < reg1->s32_min_value || sval > reg1->s32_max_value) return 0; break; case BPF_JNE: if (tnum_is_const(subreg)) return !tnum_equals_const(subreg, val); - else if (val < reg->u32_min_value || val > reg->u32_max_value) + else if (val < reg1->u32_min_value || val > reg1->u32_max_value) return 1; - else if (sval < reg->s32_min_value || sval > reg->s32_max_value) + else if (sval < reg1->s32_min_value || sval > reg1->s32_max_value) return 1; break; case BPF_JSET: @@ -14217,51 +14217,51 @@ static int is_branch32_taken(struct bpf_reg_state *reg, u32 val, u8 opcode) return 0; break; case BPF_JGT: - if (reg->u32_min_value > val) + if (reg1->u32_min_value > val) return 1; - else if (reg->u32_max_value <= val) + else if (reg1->u32_max_value <= val) return 0; break; case BPF_JSGT: - if (reg->s32_min_value > sval) + if (reg1->s32_min_value > sval) return 1; - else if (reg->s32_max_value <= sval) + else if (reg1->s32_max_value <= sval) return 0; break; case BPF_JLT: - if (reg->u32_max_value < val) + if (reg1->u32_max_value < val) return 1; - else if (reg->u32_min_value >= val) + else if (reg1->u32_min_value >= val) return 0; break; case BPF_JSLT: - if (reg->s32_max_value < sval) + if (reg1->s32_max_value < sval) return 1; - else if (reg->s32_min_value >= sval) + else if (reg1->s32_min_value >= sval) return 0; break; case BPF_JGE: - if (reg->u32_min_value >= val) + if (reg1->u32_min_value >= val) return 1; - else if (reg->u32_max_value < val) + else if (reg1->u32_max_value < val) return 0; break; case BPF_JSGE: - if (reg->s32_min_value >= sval) + if (reg1->s32_min_value >= sval) return 1; - else if (reg->s32_max_value < sval) + else if (reg1->s32_max_value < sval) return 0; break; case BPF_JLE: - if (reg->u32_max_value <= val) + if (reg1->u32_max_value <= val) return 1; - else if (reg->u32_min_value > val) + else if (reg1->u32_min_value > val) return 0; break; case BPF_JSLE: - if (reg->s32_max_value <= sval) + if (reg1->s32_max_value <= sval) return 1; - else if (reg->s32_min_value > sval) + else if (reg1->s32_min_value > sval) return 0; break; } @@ -14270,79 +14270,79 @@ static int is_branch32_taken(struct bpf_reg_state *reg, u32 val, u8 opcode) } -static int is_branch64_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) +static int is_branch64_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode) { s64 sval = (s64)val; switch (opcode) { case BPF_JEQ: - if (tnum_is_const(reg->var_off)) - return !!tnum_equals_const(reg->var_off, val); - else if (val < reg->umin_value || val > reg->umax_value) + if (tnum_is_const(reg1->var_off)) + return !!tnum_equals_const(reg1->var_off, val); + else if (val < reg1->umin_value || val > reg1->umax_value) return 0; - else if (sval < reg->smin_value || sval > reg->smax_value) + else if (sval < reg1->smin_value || sval > reg1->smax_value) return 0; break; case BPF_JNE: - if (tnum_is_const(reg->var_off)) - return !tnum_equals_const(reg->var_off, val); - else if (val < reg->umin_value || val > reg->umax_value) + if (tnum_is_const(reg1->var_off)) + return !tnum_equals_const(reg1->var_off, val); + else if (val < reg1->umin_value || val > reg1->umax_value) return 1; - else if (sval < reg->smin_value || sval > reg->smax_value) + else if (sval < reg1->smin_value || sval > reg1->smax_value) return 1; break; case BPF_JSET: - if ((~reg->var_off.mask & reg->var_off.value) & val) + if ((~reg1->var_off.mask & reg1->var_off.value) & val) return 1; - if (!((reg->var_off.mask | reg->var_off.value) & val)) + if (!((reg1->var_off.mask | reg1->var_off.value) & val)) return 0; break; case BPF_JGT: - if (reg->umin_value > val) + if (reg1->umin_value > val) return 1; - else if (reg->umax_value <= val) + else if (reg1->umax_value <= val) return 0; break; case BPF_JSGT: - if (reg->smin_value > sval) + if (reg1->smin_value > sval) return 1; - else if (reg->smax_value <= sval) + else if (reg1->smax_value <= sval) return 0; break; case BPF_JLT: - if (reg->umax_value < val) + if (reg1->umax_value < val) return 1; - else if (reg->umin_value >= val) + else if (reg1->umin_value >= val) return 0; break; case BPF_JSLT: - if (reg->smax_value < sval) + if (reg1->smax_value < sval) return 1; - else if (reg->smin_value >= sval) + else if (reg1->smin_value >= sval) return 0; break; case BPF_JGE: - if (reg->umin_value >= val) + if (reg1->umin_value >= val) return 1; - else if (reg->umax_value < val) + else if (reg1->umax_value < val) return 0; break; case BPF_JSGE: - if (reg->smin_value >= sval) + if (reg1->smin_value >= sval) return 1; - else if (reg->smax_value < sval) + else if (reg1->smax_value < sval) return 0; break; case BPF_JLE: - if (reg->umax_value <= val) + if (reg1->umax_value <= val) return 1; - else if (reg->umin_value > val) + else if (reg1->umin_value > val) return 0; break; case BPF_JSLE: - if (reg->smax_value <= sval) + if (reg1->smax_value <= sval) return 1; - else if (reg->smin_value > sval) + else if (reg1->smin_value > sval) return 0; break; } @@ -14357,11 +14357,11 @@ static int is_branch64_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) * -1 - unknown. Example: "if (reg < 5)" is unknown when register value * range [0,10] */ -static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode, +static int is_branch_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode, bool is_jmp32) { - if (__is_pointer_value(false, reg)) { - if (!reg_not_null(reg)) + if (__is_pointer_value(false, reg1)) { + if (!reg_not_null(reg1)) return -1; /* If pointer is valid tests against zero will fail so we can @@ -14381,8 +14381,8 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode, } if (is_jmp32) - return is_branch32_taken(reg, val, opcode); - return is_branch64_taken(reg, val, opcode); + return is_branch32_taken(reg1, val, opcode); + return is_branch64_taken(reg1, val, opcode); } static int flip_opcode(u32 opcode) From c31534267c180f7ed00288d239a501b554885300 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:54 -0700 Subject: [PATCH 0321/7721] bpf: generalize is_branch_taken() to work with two registers While still assuming that second register is a constant, generalize is_branch_taken-related code to accept two registers instead of register plus explicit constant value. This also, as a side effect, allows to simplify check_cond_jmp_op() by unifying BPF_K case with BPF_X case, for which we use a fake register to represent BPF_K's imm constant as a register. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231102033759.2541186-13-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 57 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 770d5bd54ff3..79d01445093b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14188,9 +14188,13 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, })); } -static int is_branch32_taken(struct bpf_reg_state *reg1, u32 val, u8 opcode) +/* + * , currently assuming reg2 is a constant + */ +static int is_branch32_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode) { struct tnum subreg = tnum_subreg(reg1->var_off); + u32 val = (u32)tnum_subreg(reg2->var_off).value; s32 sval = (s32)val; switch (opcode) { @@ -14270,8 +14274,12 @@ static int is_branch32_taken(struct bpf_reg_state *reg1, u32 val, u8 opcode) } -static int is_branch64_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode) +/* + * , currently assuming reg2 is a constant + */ +static int is_branch64_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode) { + u64 val = reg2->var_off.value; s64 sval = (s64)val; switch (opcode) { @@ -14350,16 +14358,23 @@ static int is_branch64_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode) return -1; } -/* compute branch direction of the expression "if (reg opcode val) goto target;" +/* compute branch direction of the expression "if ( opcode ) goto target;" * and return: * 1 - branch will be taken and "goto target" will be executed * 0 - branch will not be taken and fall-through to next insn - * -1 - unknown. Example: "if (reg < 5)" is unknown when register value + * -1 - unknown. Example: "if (reg1 < 5)" is unknown when register value * range [0,10] */ -static int is_branch_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode, - bool is_jmp32) +static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, + u8 opcode, bool is_jmp32) { + struct tnum reg2_tnum = is_jmp32 ? tnum_subreg(reg2->var_off) : reg2->var_off; + u64 val; + + if (!tnum_is_const(reg2_tnum)) + return -1; + val = reg2_tnum.value; + if (__is_pointer_value(false, reg1)) { if (!reg_not_null(reg1)) return -1; @@ -14381,8 +14396,8 @@ static int is_branch_taken(struct bpf_reg_state *reg1, u64 val, u8 opcode, } if (is_jmp32) - return is_branch32_taken(reg1, val, opcode); - return is_branch64_taken(reg1, val, opcode); + return is_branch32_taken(reg1, reg2, opcode); + return is_branch64_taken(reg1, reg2, opcode); } static int flip_opcode(u32 opcode) @@ -14853,6 +14868,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs; struct bpf_reg_state *dst_reg, *other_branch_regs, *src_reg = NULL; struct bpf_reg_state *eq_branch_regs; + struct bpf_reg_state fake_reg = {}; u8 opcode = BPF_OP(insn->code); bool is_jmp32; int pred = -1; @@ -14893,36 +14909,27 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); return -EINVAL; } + src_reg = &fake_reg; + src_reg->type = SCALAR_VALUE; + __mark_reg_known(src_reg, insn->imm); } is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; if (BPF_SRC(insn->code) == BPF_K) { - pred = is_branch_taken(dst_reg, insn->imm, opcode, is_jmp32); + pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); } else if (src_reg->type == SCALAR_VALUE && is_jmp32 && tnum_is_const(tnum_subreg(src_reg->var_off))) { - pred = is_branch_taken(dst_reg, - tnum_subreg(src_reg->var_off).value, - opcode, - is_jmp32); + pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); } else if (src_reg->type == SCALAR_VALUE && !is_jmp32 && tnum_is_const(src_reg->var_off)) { - pred = is_branch_taken(dst_reg, - src_reg->var_off.value, - opcode, - is_jmp32); + pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); } else if (dst_reg->type == SCALAR_VALUE && is_jmp32 && tnum_is_const(tnum_subreg(dst_reg->var_off))) { - pred = is_branch_taken(src_reg, - tnum_subreg(dst_reg->var_off).value, - flip_opcode(opcode), - is_jmp32); + pred = is_branch_taken(src_reg, dst_reg, flip_opcode(opcode), is_jmp32); } else if (dst_reg->type == SCALAR_VALUE && !is_jmp32 && tnum_is_const(dst_reg->var_off)) { - pred = is_branch_taken(src_reg, - dst_reg->var_off.value, - flip_opcode(opcode), - is_jmp32); + pred = is_branch_taken(src_reg, dst_reg, flip_opcode(opcode), is_jmp32); } else if (reg_is_pkt_pointer_any(dst_reg) && reg_is_pkt_pointer_any(src_reg) && !is_jmp32) { From c697289efe4ef38bc5c62f119cb74433f784b826 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:55 -0700 Subject: [PATCH 0322/7721] bpf: move is_branch_taken() down Move is_branch_taken() slightly down. In subsequent patched we'll need both flip_opcode() and is_pkt_ptr_branch_taken() for is_branch_taken(), but instead of sprinkling forward declarations around, it makes more sense to move is_branch_taken() lower below is_pkt_ptr_branch_taken(), and also keep it closer to very tightly related reg_set_min_max(), as they are two critical parts of the same SCALAR range tracking logic. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-14-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 84 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 79d01445093b..414a7c58b4a4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14358,48 +14358,6 @@ static int is_branch64_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *r return -1; } -/* compute branch direction of the expression "if ( opcode ) goto target;" - * and return: - * 1 - branch will be taken and "goto target" will be executed - * 0 - branch will not be taken and fall-through to next insn - * -1 - unknown. Example: "if (reg1 < 5)" is unknown when register value - * range [0,10] - */ -static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, - u8 opcode, bool is_jmp32) -{ - struct tnum reg2_tnum = is_jmp32 ? tnum_subreg(reg2->var_off) : reg2->var_off; - u64 val; - - if (!tnum_is_const(reg2_tnum)) - return -1; - val = reg2_tnum.value; - - if (__is_pointer_value(false, reg1)) { - if (!reg_not_null(reg1)) - return -1; - - /* If pointer is valid tests against zero will fail so we can - * use this to direct branch taken. - */ - if (val != 0) - return -1; - - switch (opcode) { - case BPF_JEQ: - return 0; - case BPF_JNE: - return 1; - default: - return -1; - } - } - - if (is_jmp32) - return is_branch32_taken(reg1, reg2, opcode); - return is_branch64_taken(reg1, reg2, opcode); -} - static int flip_opcode(u32 opcode) { /* How can we transform "a b" into "b a"? */ @@ -14461,6 +14419,48 @@ static int is_pkt_ptr_branch_taken(struct bpf_reg_state *dst_reg, return -1; } +/* compute branch direction of the expression "if ( opcode ) goto target;" + * and return: + * 1 - branch will be taken and "goto target" will be executed + * 0 - branch will not be taken and fall-through to next insn + * -1 - unknown. Example: "if (reg1 < 5)" is unknown when register value + * range [0,10] + */ +static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, + u8 opcode, bool is_jmp32) +{ + struct tnum reg2_tnum = is_jmp32 ? tnum_subreg(reg2->var_off) : reg2->var_off; + u64 val; + + if (!tnum_is_const(reg2_tnum)) + return -1; + val = reg2_tnum.value; + + if (__is_pointer_value(false, reg1)) { + if (!reg_not_null(reg1)) + return -1; + + /* If pointer is valid tests against zero will fail so we can + * use this to direct branch taken. + */ + if (val != 0) + return -1; + + switch (opcode) { + case BPF_JEQ: + return 0; + case BPF_JNE: + return 1; + default: + return -1; + } + } + + if (is_jmp32) + return is_branch32_taken(reg1, reg2, opcode); + return is_branch64_taken(reg1, reg2, opcode); +} + /* Adjusts the register min/max values in the case that the dst_reg is the * variable register that we are working on, and src_reg is a constant or we're * simply doing a BPF_K check. From b74c2a842bba941945279027083fcee1e9aaa73f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:56 -0700 Subject: [PATCH 0323/7721] bpf: generalize is_branch_taken to handle all conditional jumps in one place Make is_branch_taken() a single entry point for branch pruning decision making, handling both pointer vs pointer, pointer vs scalar, and scalar vs scalar cases in one place. This also nicely cleans up check_cond_jmp_op(). Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-15-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 49 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 414a7c58b4a4..17bbff33e0e8 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14188,6 +14188,19 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, })); } +/* check if register is a constant scalar value */ +static bool is_reg_const(struct bpf_reg_state *reg, bool subreg32) +{ + return reg->type == SCALAR_VALUE && + tnum_is_const(subreg32 ? tnum_subreg(reg->var_off) : reg->var_off); +} + +/* assuming is_reg_const() is true, return constant value of a register */ +static u64 reg_const_value(struct bpf_reg_state *reg, bool subreg32) +{ + return subreg32 ? tnum_subreg(reg->var_off).value : reg->var_off.value; +} + /* * , currently assuming reg2 is a constant */ @@ -14429,12 +14442,20 @@ static int is_pkt_ptr_branch_taken(struct bpf_reg_state *dst_reg, static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode, bool is_jmp32) { - struct tnum reg2_tnum = is_jmp32 ? tnum_subreg(reg2->var_off) : reg2->var_off; u64 val; - if (!tnum_is_const(reg2_tnum)) + if (reg_is_pkt_pointer_any(reg1) && reg_is_pkt_pointer_any(reg2) && !is_jmp32) + return is_pkt_ptr_branch_taken(reg1, reg2, opcode); + + /* try to make sure reg2 is a constant SCALAR_VALUE */ + if (!is_reg_const(reg2, is_jmp32)) { + opcode = flip_opcode(opcode); + swap(reg1, reg2); + } + /* for now we expect reg2 to be a constant to make any useful decisions */ + if (!is_reg_const(reg2, is_jmp32)) return -1; - val = reg2_tnum.value; + val = reg_const_value(reg2, is_jmp32); if (__is_pointer_value(false, reg1)) { if (!reg_not_null(reg1)) @@ -14915,27 +14936,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, } is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; - - if (BPF_SRC(insn->code) == BPF_K) { - pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); - } else if (src_reg->type == SCALAR_VALUE && - is_jmp32 && tnum_is_const(tnum_subreg(src_reg->var_off))) { - pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); - } else if (src_reg->type == SCALAR_VALUE && - !is_jmp32 && tnum_is_const(src_reg->var_off)) { - pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); - } else if (dst_reg->type == SCALAR_VALUE && - is_jmp32 && tnum_is_const(tnum_subreg(dst_reg->var_off))) { - pred = is_branch_taken(src_reg, dst_reg, flip_opcode(opcode), is_jmp32); - } else if (dst_reg->type == SCALAR_VALUE && - !is_jmp32 && tnum_is_const(dst_reg->var_off)) { - pred = is_branch_taken(src_reg, dst_reg, flip_opcode(opcode), is_jmp32); - } else if (reg_is_pkt_pointer_any(dst_reg) && - reg_is_pkt_pointer_any(src_reg) && - !is_jmp32) { - pred = is_pkt_ptr_branch_taken(dst_reg, src_reg, opcode); - } - + pred = is_branch_taken(dst_reg, src_reg, opcode, is_jmp32); if (pred >= 0) { /* If we get here with a dst_reg pointer type it is because * above is_branch_taken() special cased the 0 comparison. From 4d345887d2e5a1915600cb5d37b16c4088c6ee1c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:57 -0700 Subject: [PATCH 0324/7721] bpf: unify 32-bit and 64-bit is_branch_taken logic Combine 32-bit and 64-bit is_branch_taken logic for SCALAR_VALUE registers. It makes it easier to see parallels between two domains (32-bit and 64-bit), and makes subsequent refactoring more straightforward. No functional changes. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-16-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 200 +++++++++++++----------------------------- 1 file changed, 59 insertions(+), 141 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 17bbff33e0e8..c77cca5c4461 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14204,166 +14204,86 @@ static u64 reg_const_value(struct bpf_reg_state *reg, bool subreg32) /* * , currently assuming reg2 is a constant */ -static int is_branch32_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode) +static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, + u8 opcode, bool is_jmp32) { - struct tnum subreg = tnum_subreg(reg1->var_off); - u32 val = (u32)tnum_subreg(reg2->var_off).value; - s32 sval = (s32)val; + struct tnum t1 = is_jmp32 ? tnum_subreg(reg1->var_off) : reg1->var_off; + u64 umin1 = is_jmp32 ? (u64)reg1->u32_min_value : reg1->umin_value; + u64 umax1 = is_jmp32 ? (u64)reg1->u32_max_value : reg1->umax_value; + s64 smin1 = is_jmp32 ? (s64)reg1->s32_min_value : reg1->smin_value; + s64 smax1 = is_jmp32 ? (s64)reg1->s32_max_value : reg1->smax_value; + u64 uval = is_jmp32 ? (u32)tnum_subreg(reg2->var_off).value : reg2->var_off.value; + s64 sval = is_jmp32 ? (s32)uval : (s64)uval; switch (opcode) { case BPF_JEQ: - if (tnum_is_const(subreg)) - return !!tnum_equals_const(subreg, val); - else if (val < reg1->u32_min_value || val > reg1->u32_max_value) + if (tnum_is_const(t1)) + return !!tnum_equals_const(t1, uval); + else if (uval < umin1 || uval > umax1) return 0; - else if (sval < reg1->s32_min_value || sval > reg1->s32_max_value) + else if (sval < smin1 || sval > smax1) return 0; break; case BPF_JNE: - if (tnum_is_const(subreg)) - return !tnum_equals_const(subreg, val); - else if (val < reg1->u32_min_value || val > reg1->u32_max_value) + if (tnum_is_const(t1)) + return !tnum_equals_const(t1, uval); + else if (uval < umin1 || uval > umax1) return 1; - else if (sval < reg1->s32_min_value || sval > reg1->s32_max_value) + else if (sval < smin1 || sval > smax1) return 1; break; case BPF_JSET: - if ((~subreg.mask & subreg.value) & val) + if ((~t1.mask & t1.value) & uval) return 1; - if (!((subreg.mask | subreg.value) & val)) + if (!((t1.mask | t1.value) & uval)) return 0; break; case BPF_JGT: - if (reg1->u32_min_value > val) + if (umin1 > uval ) return 1; - else if (reg1->u32_max_value <= val) + else if (umax1 <= uval) return 0; break; case BPF_JSGT: - if (reg1->s32_min_value > sval) + if (smin1 > sval) return 1; - else if (reg1->s32_max_value <= sval) + else if (smax1 <= sval) return 0; break; case BPF_JLT: - if (reg1->u32_max_value < val) + if (umax1 < uval) return 1; - else if (reg1->u32_min_value >= val) + else if (umin1 >= uval) return 0; break; case BPF_JSLT: - if (reg1->s32_max_value < sval) + if (smax1 < sval) return 1; - else if (reg1->s32_min_value >= sval) + else if (smin1 >= sval) return 0; break; case BPF_JGE: - if (reg1->u32_min_value >= val) + if (umin1 >= uval) return 1; - else if (reg1->u32_max_value < val) + else if (umax1 < uval) return 0; break; case BPF_JSGE: - if (reg1->s32_min_value >= sval) + if (smin1 >= sval) return 1; - else if (reg1->s32_max_value < sval) + else if (smax1 < sval) return 0; break; case BPF_JLE: - if (reg1->u32_max_value <= val) + if (umax1 <= uval) return 1; - else if (reg1->u32_min_value > val) + else if (umin1 > uval) return 0; break; case BPF_JSLE: - if (reg1->s32_max_value <= sval) + if (smax1 <= sval) return 1; - else if (reg1->s32_min_value > sval) - return 0; - break; - } - - return -1; -} - - -/* - * , currently assuming reg2 is a constant - */ -static int is_branch64_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode) -{ - u64 val = reg2->var_off.value; - s64 sval = (s64)val; - - switch (opcode) { - case BPF_JEQ: - if (tnum_is_const(reg1->var_off)) - return !!tnum_equals_const(reg1->var_off, val); - else if (val < reg1->umin_value || val > reg1->umax_value) - return 0; - else if (sval < reg1->smin_value || sval > reg1->smax_value) - return 0; - break; - case BPF_JNE: - if (tnum_is_const(reg1->var_off)) - return !tnum_equals_const(reg1->var_off, val); - else if (val < reg1->umin_value || val > reg1->umax_value) - return 1; - else if (sval < reg1->smin_value || sval > reg1->smax_value) - return 1; - break; - case BPF_JSET: - if ((~reg1->var_off.mask & reg1->var_off.value) & val) - return 1; - if (!((reg1->var_off.mask | reg1->var_off.value) & val)) - return 0; - break; - case BPF_JGT: - if (reg1->umin_value > val) - return 1; - else if (reg1->umax_value <= val) - return 0; - break; - case BPF_JSGT: - if (reg1->smin_value > sval) - return 1; - else if (reg1->smax_value <= sval) - return 0; - break; - case BPF_JLT: - if (reg1->umax_value < val) - return 1; - else if (reg1->umin_value >= val) - return 0; - break; - case BPF_JSLT: - if (reg1->smax_value < sval) - return 1; - else if (reg1->smin_value >= sval) - return 0; - break; - case BPF_JGE: - if (reg1->umin_value >= val) - return 1; - else if (reg1->umax_value < val) - return 0; - break; - case BPF_JSGE: - if (reg1->smin_value >= sval) - return 1; - else if (reg1->smax_value < sval) - return 0; - break; - case BPF_JLE: - if (reg1->umax_value <= val) - return 1; - else if (reg1->umin_value > val) - return 0; - break; - case BPF_JSLE: - if (reg1->smax_value <= sval) - return 1; - else if (reg1->smin_value > sval) + else if (smin1 > sval) return 0; break; } @@ -14477,9 +14397,7 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg } } - if (is_jmp32) - return is_branch32_taken(reg1, reg2, opcode); - return is_branch64_taken(reg1, reg2, opcode); + return is_scalar_branch_taken(reg1, reg2, opcode, is_jmp32); } /* Adjusts the register min/max values in the case that the dst_reg is the @@ -14489,15 +14407,15 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg */ static void reg_set_min_max(struct bpf_reg_state *true_reg, struct bpf_reg_state *false_reg, - u64 val, u32 val32, + u64 uval, u32 uval32, u8 opcode, bool is_jmp32) { struct tnum false_32off = tnum_subreg(false_reg->var_off); struct tnum false_64off = false_reg->var_off; struct tnum true_32off = tnum_subreg(true_reg->var_off); struct tnum true_64off = true_reg->var_off; - s64 sval = (s64)val; - s32 sval32 = (s32)val32; + s64 sval = (s64)uval; + s32 sval32 = (s32)uval32; /* If the dst_reg is a pointer, we can't learn anything about its * variable offset from the compare (unless src_reg were a pointer into @@ -14520,49 +14438,49 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, */ case BPF_JEQ: if (is_jmp32) { - __mark_reg32_known(true_reg, val32); + __mark_reg32_known(true_reg, uval32); true_32off = tnum_subreg(true_reg->var_off); } else { - ___mark_reg_known(true_reg, val); + ___mark_reg_known(true_reg, uval); true_64off = true_reg->var_off; } break; case BPF_JNE: if (is_jmp32) { - __mark_reg32_known(false_reg, val32); + __mark_reg32_known(false_reg, uval32); false_32off = tnum_subreg(false_reg->var_off); } else { - ___mark_reg_known(false_reg, val); + ___mark_reg_known(false_reg, uval); false_64off = false_reg->var_off; } break; case BPF_JSET: if (is_jmp32) { - false_32off = tnum_and(false_32off, tnum_const(~val32)); - if (is_power_of_2(val32)) + false_32off = tnum_and(false_32off, tnum_const(~uval32)); + if (is_power_of_2(uval32)) true_32off = tnum_or(true_32off, - tnum_const(val32)); + tnum_const(uval32)); } else { - false_64off = tnum_and(false_64off, tnum_const(~val)); - if (is_power_of_2(val)) + false_64off = tnum_and(false_64off, tnum_const(~uval)); + if (is_power_of_2(uval)) true_64off = tnum_or(true_64off, - tnum_const(val)); + tnum_const(uval)); } break; case BPF_JGE: case BPF_JGT: { if (is_jmp32) { - u32 false_umax = opcode == BPF_JGT ? val32 : val32 - 1; - u32 true_umin = opcode == BPF_JGT ? val32 + 1 : val32; + u32 false_umax = opcode == BPF_JGT ? uval32 : uval32 - 1; + u32 true_umin = opcode == BPF_JGT ? uval32 + 1 : uval32; false_reg->u32_max_value = min(false_reg->u32_max_value, false_umax); true_reg->u32_min_value = max(true_reg->u32_min_value, true_umin); } else { - u64 false_umax = opcode == BPF_JGT ? val : val - 1; - u64 true_umin = opcode == BPF_JGT ? val + 1 : val; + u64 false_umax = opcode == BPF_JGT ? uval : uval - 1; + u64 true_umin = opcode == BPF_JGT ? uval + 1 : uval; false_reg->umax_value = min(false_reg->umax_value, false_umax); true_reg->umin_value = max(true_reg->umin_value, true_umin); @@ -14591,16 +14509,16 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, case BPF_JLT: { if (is_jmp32) { - u32 false_umin = opcode == BPF_JLT ? val32 : val32 + 1; - u32 true_umax = opcode == BPF_JLT ? val32 - 1 : val32; + u32 false_umin = opcode == BPF_JLT ? uval32 : uval32 + 1; + u32 true_umax = opcode == BPF_JLT ? uval32 - 1 : uval32; false_reg->u32_min_value = max(false_reg->u32_min_value, false_umin); true_reg->u32_max_value = min(true_reg->u32_max_value, true_umax); } else { - u64 false_umin = opcode == BPF_JLT ? val : val + 1; - u64 true_umax = opcode == BPF_JLT ? val - 1 : val; + u64 false_umin = opcode == BPF_JLT ? uval : uval + 1; + u64 true_umax = opcode == BPF_JLT ? uval - 1 : uval; false_reg->umin_value = max(false_reg->umin_value, false_umin); true_reg->umax_value = min(true_reg->umax_value, true_umax); @@ -14649,7 +14567,7 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, */ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, struct bpf_reg_state *false_reg, - u64 val, u32 val32, + u64 uval, u32 uval32, u8 opcode, bool is_jmp32) { opcode = flip_opcode(opcode); @@ -14657,7 +14575,7 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, * BPF_JA, can't get here. */ if (opcode) - reg_set_min_max(true_reg, false_reg, val, val32, opcode, is_jmp32); + reg_set_min_max(true_reg, false_reg, uval, uval32, opcode, is_jmp32); } /* Regs are known to be equal, so intersect their min/max/var_off */ From d79924ca579c647d5dc55f605899c98f7ea04d0f Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Wed, 1 Nov 2023 11:24:53 +0800 Subject: [PATCH 0325/7721] selftests/bpf: Use value with enough-size when updating per-cpu map When updating per-cpu map in map_percpu_stats test, patch_map_thread() only passes 4-bytes-sized value to bpf_map_update_elem(). The expected size of the value is 8 * num_possible_cpus(), so fix it by passing a value with enough-size for per-cpu map update. Signed-off-by: Hou Tao Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231101032455.3808547-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../bpf/map_tests/map_percpu_stats.c | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c index 8bf497a9843e..a98d6b94dd02 100644 --- a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c +++ b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c @@ -131,6 +131,12 @@ static bool is_lru(__u32 map_type) map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH; } +static bool is_percpu(__u32 map_type) +{ + return map_type == BPF_MAP_TYPE_PERCPU_HASH || + map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH; +} + struct upsert_opts { __u32 map_type; int map_fd; @@ -150,17 +156,26 @@ static int create_small_hash(void) static void *patch_map_thread(void *arg) { + /* 8KB is enough for 1024 CPUs. And it is shared between N_THREADS. */ + static __u8 blob[8 << 10]; struct upsert_opts *opts = arg; + void *val_ptr; int val; int ret; int i; for (i = 0; i < opts->n; i++) { - if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) + if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { val = create_small_hash(); - else + val_ptr = &val; + } else if (is_percpu(opts->map_type)) { + val_ptr = blob; + } else { val = rand(); - ret = bpf_map_update_elem(opts->map_fd, &i, &val, 0); + val_ptr = &val; + } + + ret = bpf_map_update_elem(opts->map_fd, &i, val_ptr, 0); CHECK(ret < 0, "bpf_map_update_elem", "key=%d error: %s\n", i, strerror(errno)); if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) From 811476e9cc578cb6c776627ac069dc45a8431791 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:58 -0700 Subject: [PATCH 0326/7721] bpf: prepare reg_set_min_max for second set of registers Similarly to is_branch_taken()-related refactorings, start preparing reg_set_min_max() to handle more generic case of two non-const registers. Start with renaming arguments to accommodate later addition of second register as an input argument. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-17-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 80 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c77cca5c4461..40ed261d3489 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14405,25 +14405,25 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg * simply doing a BPF_K check. * In JEQ/JNE cases we also adjust the var_off values. */ -static void reg_set_min_max(struct bpf_reg_state *true_reg, - struct bpf_reg_state *false_reg, +static void reg_set_min_max(struct bpf_reg_state *true_reg1, + struct bpf_reg_state *false_reg1, u64 uval, u32 uval32, u8 opcode, bool is_jmp32) { - struct tnum false_32off = tnum_subreg(false_reg->var_off); - struct tnum false_64off = false_reg->var_off; - struct tnum true_32off = tnum_subreg(true_reg->var_off); - struct tnum true_64off = true_reg->var_off; + struct tnum false_32off = tnum_subreg(false_reg1->var_off); + struct tnum false_64off = false_reg1->var_off; + struct tnum true_32off = tnum_subreg(true_reg1->var_off); + struct tnum true_64off = true_reg1->var_off; s64 sval = (s64)uval; s32 sval32 = (s32)uval32; /* If the dst_reg is a pointer, we can't learn anything about its * variable offset from the compare (unless src_reg were a pointer into * the same object, but we don't bother with that. - * Since false_reg and true_reg have the same type by construction, we + * Since false_reg1 and true_reg1 have the same type by construction, we * only need to check one of them for pointerness. */ - if (__is_pointer_value(false, false_reg)) + if (__is_pointer_value(false, false_reg1)) return; switch (opcode) { @@ -14438,20 +14438,20 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, */ case BPF_JEQ: if (is_jmp32) { - __mark_reg32_known(true_reg, uval32); - true_32off = tnum_subreg(true_reg->var_off); + __mark_reg32_known(true_reg1, uval32); + true_32off = tnum_subreg(true_reg1->var_off); } else { - ___mark_reg_known(true_reg, uval); - true_64off = true_reg->var_off; + ___mark_reg_known(true_reg1, uval); + true_64off = true_reg1->var_off; } break; case BPF_JNE: if (is_jmp32) { - __mark_reg32_known(false_reg, uval32); - false_32off = tnum_subreg(false_reg->var_off); + __mark_reg32_known(false_reg1, uval32); + false_32off = tnum_subreg(false_reg1->var_off); } else { - ___mark_reg_known(false_reg, uval); - false_64off = false_reg->var_off; + ___mark_reg_known(false_reg1, uval); + false_64off = false_reg1->var_off; } break; case BPF_JSET: @@ -14474,16 +14474,16 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, u32 false_umax = opcode == BPF_JGT ? uval32 : uval32 - 1; u32 true_umin = opcode == BPF_JGT ? uval32 + 1 : uval32; - false_reg->u32_max_value = min(false_reg->u32_max_value, + false_reg1->u32_max_value = min(false_reg1->u32_max_value, false_umax); - true_reg->u32_min_value = max(true_reg->u32_min_value, + true_reg1->u32_min_value = max(true_reg1->u32_min_value, true_umin); } else { u64 false_umax = opcode == BPF_JGT ? uval : uval - 1; u64 true_umin = opcode == BPF_JGT ? uval + 1 : uval; - false_reg->umax_value = min(false_reg->umax_value, false_umax); - true_reg->umin_value = max(true_reg->umin_value, true_umin); + false_reg1->umax_value = min(false_reg1->umax_value, false_umax); + true_reg1->umin_value = max(true_reg1->umin_value, true_umin); } break; } @@ -14494,14 +14494,14 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, s32 false_smax = opcode == BPF_JSGT ? sval32 : sval32 - 1; s32 true_smin = opcode == BPF_JSGT ? sval32 + 1 : sval32; - false_reg->s32_max_value = min(false_reg->s32_max_value, false_smax); - true_reg->s32_min_value = max(true_reg->s32_min_value, true_smin); + false_reg1->s32_max_value = min(false_reg1->s32_max_value, false_smax); + true_reg1->s32_min_value = max(true_reg1->s32_min_value, true_smin); } else { s64 false_smax = opcode == BPF_JSGT ? sval : sval - 1; s64 true_smin = opcode == BPF_JSGT ? sval + 1 : sval; - false_reg->smax_value = min(false_reg->smax_value, false_smax); - true_reg->smin_value = max(true_reg->smin_value, true_smin); + false_reg1->smax_value = min(false_reg1->smax_value, false_smax); + true_reg1->smin_value = max(true_reg1->smin_value, true_smin); } break; } @@ -14512,16 +14512,16 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, u32 false_umin = opcode == BPF_JLT ? uval32 : uval32 + 1; u32 true_umax = opcode == BPF_JLT ? uval32 - 1 : uval32; - false_reg->u32_min_value = max(false_reg->u32_min_value, + false_reg1->u32_min_value = max(false_reg1->u32_min_value, false_umin); - true_reg->u32_max_value = min(true_reg->u32_max_value, + true_reg1->u32_max_value = min(true_reg1->u32_max_value, true_umax); } else { u64 false_umin = opcode == BPF_JLT ? uval : uval + 1; u64 true_umax = opcode == BPF_JLT ? uval - 1 : uval; - false_reg->umin_value = max(false_reg->umin_value, false_umin); - true_reg->umax_value = min(true_reg->umax_value, true_umax); + false_reg1->umin_value = max(false_reg1->umin_value, false_umin); + true_reg1->umax_value = min(true_reg1->umax_value, true_umax); } break; } @@ -14532,14 +14532,14 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, s32 false_smin = opcode == BPF_JSLT ? sval32 : sval32 + 1; s32 true_smax = opcode == BPF_JSLT ? sval32 - 1 : sval32; - false_reg->s32_min_value = max(false_reg->s32_min_value, false_smin); - true_reg->s32_max_value = min(true_reg->s32_max_value, true_smax); + false_reg1->s32_min_value = max(false_reg1->s32_min_value, false_smin); + true_reg1->s32_max_value = min(true_reg1->s32_max_value, true_smax); } else { s64 false_smin = opcode == BPF_JSLT ? sval : sval + 1; s64 true_smax = opcode == BPF_JSLT ? sval - 1 : sval; - false_reg->smin_value = max(false_reg->smin_value, false_smin); - true_reg->smax_value = min(true_reg->smax_value, true_smax); + false_reg1->smin_value = max(false_reg1->smin_value, false_smin); + true_reg1->smax_value = min(true_reg1->smax_value, true_smax); } break; } @@ -14548,17 +14548,17 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, } if (is_jmp32) { - false_reg->var_off = tnum_or(tnum_clear_subreg(false_64off), + false_reg1->var_off = tnum_or(tnum_clear_subreg(false_64off), tnum_subreg(false_32off)); - true_reg->var_off = tnum_or(tnum_clear_subreg(true_64off), + true_reg1->var_off = tnum_or(tnum_clear_subreg(true_64off), tnum_subreg(true_32off)); - reg_bounds_sync(false_reg); - reg_bounds_sync(true_reg); + reg_bounds_sync(false_reg1); + reg_bounds_sync(true_reg1); } else { - false_reg->var_off = false_64off; - true_reg->var_off = true_64off; - reg_bounds_sync(false_reg); - reg_bounds_sync(true_reg); + false_reg1->var_off = false_64off; + true_reg1->var_off = true_64off; + reg_bounds_sync(false_reg1); + reg_bounds_sync(true_reg1); } } From b9b79553163788d3fc42e25c2662c0a46dc9a3c5 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Wed, 1 Nov 2023 11:24:54 +0800 Subject: [PATCH 0327/7721] selftests/bpf: Export map_update_retriable() Export map_update_retriable() to make it usable for other map_test cases. These cases may only need retry for specific errno, so add a new callback parameter to let map_update_retriable() decide whether or not the errno is retriable. Signed-off-by: Hou Tao Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231101032455.3808547-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_maps.c | 17 ++++++++++++----- tools/testing/selftests/bpf/test_maps.h | 5 +++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 7fc00e423e4d..767e0693df10 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -1396,13 +1396,18 @@ static void test_map_stress(void) #define MAX_DELAY_US 50000 #define MIN_DELAY_RANGE_US 5000 -static int map_update_retriable(int map_fd, const void *key, const void *value, - int flags, int attempts) +static bool retry_for_again_or_busy(int err) +{ + return (err == EAGAIN || err == EBUSY); +} + +int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts, + retry_for_error_fn need_retry) { int delay = rand() % MIN_DELAY_RANGE_US; while (bpf_map_update_elem(map_fd, key, value, flags)) { - if (!attempts || (errno != EAGAIN && errno != EBUSY)) + if (!attempts || !need_retry(errno)) return -errno; if (delay <= MAX_DELAY_US / 2) @@ -1445,11 +1450,13 @@ static void test_update_delete(unsigned int fn, void *data) key = value = i; if (do_update) { - err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES); + err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES, + retry_for_again_or_busy); if (err) printf("error %d %d\n", err, errno); assert(err == 0); - err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES); + err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES, + retry_for_again_or_busy); if (err) printf("error %d %d\n", err, errno); assert(err == 0); diff --git a/tools/testing/selftests/bpf/test_maps.h b/tools/testing/selftests/bpf/test_maps.h index f6fbca761732..e4ac704a536c 100644 --- a/tools/testing/selftests/bpf/test_maps.h +++ b/tools/testing/selftests/bpf/test_maps.h @@ -4,6 +4,7 @@ #include #include +#include #define CHECK(condition, tag, format...) ({ \ int __ret = !!(condition); \ @@ -16,4 +17,8 @@ extern int skips; +typedef bool (*retry_for_error_fn)(int err); +int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts, + retry_for_error_fn need_retry); + #endif From 4621202adc5bc0d1006af37fe8b9aca131387d3c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 1 Nov 2023 20:37:59 -0700 Subject: [PATCH 0328/7721] bpf: generalize reg_set_min_max() to handle two sets of two registers Change reg_set_min_max() to take FALSE/TRUE sets of two registers each, instead of assuming that we are always comparing to a constant. For now we still assume that right-hand side registers are constants (and make sure that's the case by swapping src/dst regs, if necessary), but subsequent patches will remove this limitation. reg_set_min_max() is now called unconditionally for any register comparison, so that might include pointer vs pointer. This makes it consistent with is_branch_taken() generality. But we currently only support adjustments based on SCALAR vs SCALAR comparisons, so reg_set_min_max() has to guard itself againts pointers. Taking two by two registers allows to further unify and simplify check_cond_jmp_op() logic. We utilize fake register for BPF_K conditional jump case, just like with is_branch_taken() part. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231102033759.2541186-18-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 127 ++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 73 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 40ed261d3489..e801c50d3857 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14400,32 +14400,50 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg return is_scalar_branch_taken(reg1, reg2, opcode, is_jmp32); } -/* Adjusts the register min/max values in the case that the dst_reg is the - * variable register that we are working on, and src_reg is a constant or we're - * simply doing a BPF_K check. - * In JEQ/JNE cases we also adjust the var_off values. +/* Adjusts the register min/max values in the case that the dst_reg and + * src_reg are both SCALAR_VALUE registers (or we are simply doing a BPF_K + * check, in which case we havea fake SCALAR_VALUE representing insn->imm). + * Technically we can do similar adjustments for pointers to the same object, + * but we don't support that right now. */ static void reg_set_min_max(struct bpf_reg_state *true_reg1, + struct bpf_reg_state *true_reg2, struct bpf_reg_state *false_reg1, - u64 uval, u32 uval32, + struct bpf_reg_state *false_reg2, u8 opcode, bool is_jmp32) { - struct tnum false_32off = tnum_subreg(false_reg1->var_off); - struct tnum false_64off = false_reg1->var_off; - struct tnum true_32off = tnum_subreg(true_reg1->var_off); - struct tnum true_64off = true_reg1->var_off; - s64 sval = (s64)uval; - s32 sval32 = (s32)uval32; + struct tnum false_32off, false_64off; + struct tnum true_32off, true_64off; + u64 uval; + u32 uval32; + s64 sval; + s32 sval32; - /* If the dst_reg is a pointer, we can't learn anything about its - * variable offset from the compare (unless src_reg were a pointer into - * the same object, but we don't bother with that. - * Since false_reg1 and true_reg1 have the same type by construction, we - * only need to check one of them for pointerness. + /* If either register is a pointer, we can't learn anything about its + * variable offset from the compare (unless they were a pointer into + * the same object, but we don't bother with that). */ - if (__is_pointer_value(false, false_reg1)) + if (false_reg1->type != SCALAR_VALUE || false_reg2->type != SCALAR_VALUE) return; + /* we expect right-hand registers (src ones) to be constants, for now */ + if (!is_reg_const(false_reg2, is_jmp32)) { + opcode = flip_opcode(opcode); + swap(true_reg1, true_reg2); + swap(false_reg1, false_reg2); + } + if (!is_reg_const(false_reg2, is_jmp32)) + return; + + false_32off = tnum_subreg(false_reg1->var_off); + false_64off = false_reg1->var_off; + true_32off = tnum_subreg(true_reg1->var_off); + true_64off = true_reg1->var_off; + uval = false_reg2->var_off.value; + uval32 = (u32)tnum_subreg(false_reg2->var_off).value; + sval = (s64)uval; + sval32 = (s32)uval32; + switch (opcode) { /* JEQ/JNE comparison doesn't change the register equivalence. * @@ -14562,22 +14580,6 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg1, } } -/* Same as above, but for the case that dst_reg holds a constant and src_reg is - * the variable reg. - */ -static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, - struct bpf_reg_state *false_reg, - u64 uval, u32 uval32, - u8 opcode, bool is_jmp32) -{ - opcode = flip_opcode(opcode); - /* This uses zero as "not present in table"; luckily the zero opcode, - * BPF_JA, can't get here. - */ - if (opcode) - reg_set_min_max(true_reg, false_reg, uval, uval32, opcode, is_jmp32); -} - /* Regs are known to be equal, so intersect their min/max/var_off */ static void __reg_combine_min_max(struct bpf_reg_state *src_reg, struct bpf_reg_state *dst_reg) @@ -14902,53 +14904,32 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, return -EFAULT; other_branch_regs = other_branch->frame[other_branch->curframe]->regs; - /* detect if we are comparing against a constant value so we can adjust - * our min/max values for our dst register. - * this is only legit if both are scalars (or pointers to the same - * object, I suppose, see the PTR_MAYBE_NULL related if block below), - * because otherwise the different base pointers mean the offsets aren't - * comparable. - */ if (BPF_SRC(insn->code) == BPF_X) { - struct bpf_reg_state *src_reg = ®s[insn->src_reg]; + reg_set_min_max(&other_branch_regs[insn->dst_reg], + &other_branch_regs[insn->src_reg], + dst_reg, src_reg, opcode, is_jmp32); if (dst_reg->type == SCALAR_VALUE && - src_reg->type == SCALAR_VALUE) { - if (tnum_is_const(src_reg->var_off) || - (is_jmp32 && - tnum_is_const(tnum_subreg(src_reg->var_off)))) - reg_set_min_max(&other_branch_regs[insn->dst_reg], - dst_reg, - src_reg->var_off.value, - tnum_subreg(src_reg->var_off).value, - opcode, is_jmp32); - else if (tnum_is_const(dst_reg->var_off) || - (is_jmp32 && - tnum_is_const(tnum_subreg(dst_reg->var_off)))) - reg_set_min_max_inv(&other_branch_regs[insn->src_reg], - src_reg, - dst_reg->var_off.value, - tnum_subreg(dst_reg->var_off).value, - opcode, is_jmp32); - else if (!is_jmp32 && - (opcode == BPF_JEQ || opcode == BPF_JNE)) - /* Comparing for equality, we can combine knowledge */ - reg_combine_min_max(&other_branch_regs[insn->src_reg], - &other_branch_regs[insn->dst_reg], - src_reg, dst_reg, opcode); - if (src_reg->id && - !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { - find_equal_scalars(this_branch, src_reg); - find_equal_scalars(other_branch, &other_branch_regs[insn->src_reg]); - } - + src_reg->type == SCALAR_VALUE && + !is_jmp32 && (opcode == BPF_JEQ || opcode == BPF_JNE)) { + /* Comparing for equality, we can combine knowledge */ + reg_combine_min_max(&other_branch_regs[insn->src_reg], + &other_branch_regs[insn->dst_reg], + src_reg, dst_reg, opcode); } - } else if (dst_reg->type == SCALAR_VALUE) { + } else /* BPF_SRC(insn->code) == BPF_K */ { reg_set_min_max(&other_branch_regs[insn->dst_reg], - dst_reg, insn->imm, (u32)insn->imm, - opcode, is_jmp32); + src_reg /* fake one */, + dst_reg, src_reg /* same fake one */, + opcode, is_jmp32); } + if (BPF_SRC(insn->code) == BPF_X && + src_reg->type == SCALAR_VALUE && src_reg->id && + !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { + find_equal_scalars(this_branch, src_reg); + find_equal_scalars(other_branch, &other_branch_regs[insn->src_reg]); + } if (dst_reg->type == SCALAR_VALUE && dst_reg->id && !WARN_ON_ONCE(dst_reg->id != other_branch_regs[insn->dst_reg].id)) { find_equal_scalars(this_branch, dst_reg); From 2f553b032cad4993969cab356b3b0e306fcd1cd1 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Wed, 1 Nov 2023 11:24:55 +0800 Subject: [PATCH 0329/7721] selftsets/bpf: Retry map update for non-preallocated per-cpu map BPF CI failed due to map_percpu_stats_percpu_hash from time to time [1]. It seems that the failure reason is per-cpu bpf memory allocator may not be able to allocate per-cpu pointer successfully and it can not refill free llist timely, and bpf_map_update_elem() will return -ENOMEM. So mitigate the problem by retrying the update operation for non-preallocated per-cpu map. [1]: https://github.com/kernel-patches/bpf/actions/runs/6713177520/job/18244865326?pr=5909 Signed-off-by: Hou Tao Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231101032455.3808547-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../bpf/map_tests/map_percpu_stats.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c index a98d6b94dd02..2ea36408816b 100644 --- a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c +++ b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c @@ -141,6 +141,7 @@ struct upsert_opts { __u32 map_type; int map_fd; __u32 n; + bool retry_for_nomem; }; static int create_small_hash(void) @@ -154,6 +155,11 @@ static int create_small_hash(void) return map_fd; } +static bool retry_for_nomem_fn(int err) +{ + return err == ENOMEM; +} + static void *patch_map_thread(void *arg) { /* 8KB is enough for 1024 CPUs. And it is shared between N_THREADS. */ @@ -175,7 +181,12 @@ static void *patch_map_thread(void *arg) val_ptr = &val; } - ret = bpf_map_update_elem(opts->map_fd, &i, val_ptr, 0); + /* 2 seconds may be enough ? */ + if (opts->retry_for_nomem) + ret = map_update_retriable(opts->map_fd, &i, val_ptr, 0, + 40, retry_for_nomem_fn); + else + ret = bpf_map_update_elem(opts->map_fd, &i, val_ptr, 0); CHECK(ret < 0, "bpf_map_update_elem", "key=%d error: %s\n", i, strerror(errno)); if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) @@ -296,6 +307,13 @@ static void __test(int map_fd) else opts.n /= 2; + /* per-cpu bpf memory allocator may not be able to allocate per-cpu + * pointer successfully and it can not refill free llist timely, and + * bpf_map_update_elem() will return -ENOMEM. so just retry to mitigate + * the problem temporarily. + */ + opts.retry_for_nomem = is_percpu(opts.map_type) && (info.map_flags & BPF_F_NO_PREALLOC); + /* * Upsert keys [0, n) under some competition: with random values from * N_THREADS threads. Check values, then delete all elements and check From b0cf0dcde8cae24571b1f382e81328229e475604 Mon Sep 17 00:00:00 2001 From: Manu Bretelle Date: Tue, 31 Oct 2023 14:27:17 -0700 Subject: [PATCH 0330/7721] selftests/bpf: Consolidate VIRTIO/9P configs in config.vm file Those configs are needed to be able to run VM somewhat consistently. For instance, ATM, s390x is missing the `CONFIG_VIRTIO_CONSOLE` which prevents s390x kernels built in CI to leverage qemu-guest-agent. By moving them to `config,vm`, we should have selftest kernels which are equal in term of VM functionalities when they include this file. The set of config unabled were picked using grep -h -E '(_9P|_VIRTIO)' config.x86_64 config | sort | uniq added to `config.vm` and then grep -vE '(_9P|_VIRTIO)' config.{x86_64,aarch64,s390x} as a side-effect, some config may have disappeared to the aarch64 and s390x kernels, but they should not be needed. CI will tell. Signed-off-by: Manu Bretelle Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231031212717.4037892-1-chantr4@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/config.aarch64 | 16 ---------------- tools/testing/selftests/bpf/config.s390x | 9 --------- tools/testing/selftests/bpf/config.vm | 12 ++++++++++++ tools/testing/selftests/bpf/config.x86_64 | 12 ------------ tools/testing/selftests/bpf/vmtest.sh | 4 +++- 5 files changed, 15 insertions(+), 38 deletions(-) create mode 100644 tools/testing/selftests/bpf/config.vm diff --git a/tools/testing/selftests/bpf/config.aarch64 b/tools/testing/selftests/bpf/config.aarch64 index 253821494884..fa8ecf626c73 100644 --- a/tools/testing/selftests/bpf/config.aarch64 +++ b/tools/testing/selftests/bpf/config.aarch64 @@ -1,4 +1,3 @@ -CONFIG_9P_FS=y CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y CONFIG_ARM_SMMU_V3=y @@ -46,7 +45,6 @@ CONFIG_DEBUG_SG=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_DEVTMPFS=y -CONFIG_DRM_VIRTIO_GPU=y CONFIG_DRM=y CONFIG_DUMMY=y CONFIG_EXPERT=y @@ -67,7 +65,6 @@ CONFIG_HAVE_KRETPROBES=y CONFIG_HEADERS_INSTALL=y CONFIG_HIGH_RES_TIMERS=y CONFIG_HUGETLBFS=y -CONFIG_HW_RANDOM_VIRTIO=y CONFIG_HW_RANDOM=y CONFIG_HZ_100=y CONFIG_IDLE_PAGE_TRACKING=y @@ -99,8 +96,6 @@ CONFIG_MEMCG=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_NAMESPACES=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_NET_9P=y CONFIG_NET_ACT_BPF=y CONFIG_NET_ACT_GACT=y CONFIG_NETDEVICES=y @@ -140,7 +135,6 @@ CONFIG_SCHED_TRACER=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_VIRTIO=y CONFIG_SCSI=y CONFIG_SECURITY_NETWORK=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y @@ -167,16 +161,6 @@ CONFIG_UPROBES=y CONFIG_USELIB=y CONFIG_USER_NS=y CONFIG_VETH=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_VIRTIO_FS=y -CONFIG_VIRTIO_INPUT=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -CONFIG_VIRTIO_MMIO=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/config.s390x b/tools/testing/selftests/bpf/config.s390x index 2ba92167be35..e93330382849 100644 --- a/tools/testing/selftests/bpf/config.s390x +++ b/tools/testing/selftests/bpf/config.s390x @@ -1,4 +1,3 @@ -CONFIG_9P_FS=y CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y CONFIG_AUDIT=y CONFIG_BLK_CGROUP=y @@ -84,8 +83,6 @@ CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_NAMESPACES=y CONFIG_NET=y -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y CONFIG_NET_ACT_BPF=y CONFIG_NET_ACT_GACT=y CONFIG_NET_KEY=y @@ -114,7 +111,6 @@ CONFIG_SAMPLE_SECCOMP=y CONFIG_SAMPLES=y CONFIG_SCHED_TRACER=y CONFIG_SCSI=y -CONFIG_SCSI_VIRTIO=y CONFIG_SECURITY_NETWORK=y CONFIG_STACK_TRACER=y CONFIG_STATIC_KEYS_SELFTEST=y @@ -136,11 +132,6 @@ CONFIG_UPROBES=y CONFIG_USELIB=y CONFIG_USER_NS=y CONFIG_VETH=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/config.vm b/tools/testing/selftests/bpf/config.vm new file mode 100644 index 000000000000..a9746ca78777 --- /dev/null +++ b/tools/testing/selftests/bpf/config.vm @@ -0,0 +1,12 @@ +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_VSOCKETS_COMMON=y diff --git a/tools/testing/selftests/bpf/config.x86_64 b/tools/testing/selftests/bpf/config.x86_64 index 2e70a6048278..f7bfb2b09c82 100644 --- a/tools/testing/selftests/bpf/config.x86_64 +++ b/tools/testing/selftests/bpf/config.x86_64 @@ -1,6 +1,3 @@ -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y -CONFIG_9P_FS_SECURITY=y CONFIG_AGP=y CONFIG_AGP_AMD64=y CONFIG_AGP_INTEL=y @@ -45,7 +42,6 @@ CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPUSETS=y CONFIG_CRC_T10DIF=y CONFIG_CRYPTO_BLAKE2B=y -CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_XXHASH=y CONFIG_DCB=y @@ -145,8 +141,6 @@ CONFIG_MEMORY_FAILURE=y CONFIG_MINIX_SUBPARTITION=y CONFIG_NAMESPACES=y CONFIG_NET=y -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y CONFIG_NET_ACT_BPF=y CONFIG_NET_CLS_CGROUP=y CONFIG_NET_EMATCH=y @@ -228,12 +222,6 @@ CONFIG_USER_NS=y CONFIG_VALIDATE_FS_PARSER=y CONFIG_VETH=y CONFIG_VIRT_DRIVERS=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh index 685034528018..65d14f3bbe30 100755 --- a/tools/testing/selftests/bpf/vmtest.sh +++ b/tools/testing/selftests/bpf/vmtest.sh @@ -36,7 +36,9 @@ DEFAULT_COMMAND="./test_progs" MOUNT_DIR="mnt" ROOTFS_IMAGE="root.img" OUTPUT_DIR="$HOME/.bpf_selftests" -KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config" "tools/testing/selftests/bpf/config.${ARCH}") +KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config" + "tools/testing/selftests/bpf/config.vm" + "tools/testing/selftests/bpf/config.${ARCH}") INDEX_URL="https://raw.githubusercontent.com/libbpf/ci/master/INDEX" NUM_COMPILE_JOBS="$(nproc)" LOG_FILE_BASE="$(date +"bpf_selftests.%Y-%m-%d_%H-%M-%S")" From 74523c06ae20b83c5508a98af62393ac34913362 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Mon, 6 Nov 2023 20:57:23 -0800 Subject: [PATCH 0331/7721] bpf: Add __bpf_dynptr_data* for in kernel use Different types of bpf dynptr have different internal data storage. Specifically, SKB and XDP type of dynptr may have non-continuous data. Therefore, it is not always safe to directly access dynptr->data. Add __bpf_dynptr_data and __bpf_dynptr_data_rw to replace direct access to dynptr->data. Update bpf_verify_pkcs7_signature to use __bpf_dynptr_data instead of dynptr->data. Signed-off-by: Song Liu Signed-off-by: Andrii Nakryiko Acked-by: Vadim Fedorenko Link: https://lore.kernel.org/bpf/20231107045725.2278852-2-song@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 2 ++ kernel/bpf/helpers.c | 19 +++++++++++++++++++ kernel/trace/bpf_trace.c | 12 ++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b4825d3cdb29..eb84caf133df 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1222,6 +1222,8 @@ enum bpf_dynptr_type { int bpf_dynptr_check_size(u32 size); u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr); +const void *__bpf_dynptr_data(const struct bpf_dynptr_kern *ptr, u32 len); +void *__bpf_dynptr_data_rw(const struct bpf_dynptr_kern *ptr, u32 len); #ifdef CONFIG_BPF_JIT int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr); diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 56b0c1f678ee..174f02a9e703 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2618,3 +2618,22 @@ static int __init kfunc_init(void) } late_initcall(kfunc_init); + +/* Get a pointer to dynptr data up to len bytes for read only access. If + * the dynptr doesn't have continuous data up to len bytes, return NULL. + */ +const void *__bpf_dynptr_data(const struct bpf_dynptr_kern *ptr, u32 len) +{ + return bpf_dynptr_slice(ptr, 0, NULL, len); +} + +/* Get a pointer to dynptr data up to len bytes for read write access. If + * the dynptr doesn't have continuous data up to len bytes, or the dynptr + * is read only, return NULL. + */ +void *__bpf_dynptr_data_rw(const struct bpf_dynptr_kern *ptr, u32 len) +{ + if (__bpf_dynptr_is_rdonly(ptr)) + return NULL; + return (void *)__bpf_dynptr_data(ptr, len); +} diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 84e8a0f6e4e0..f0b8b7c29126 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1376,6 +1376,8 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, struct bpf_dynptr_kern *sig_ptr, struct bpf_key *trusted_keyring) { + const void *data, *sig; + u32 data_len, sig_len; int ret; if (trusted_keyring->has_ref) { @@ -1392,10 +1394,12 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, return ret; } - return verify_pkcs7_signature(data_ptr->data, - __bpf_dynptr_size(data_ptr), - sig_ptr->data, - __bpf_dynptr_size(sig_ptr), + data_len = __bpf_dynptr_size(data_ptr); + data = __bpf_dynptr_data(data_ptr, data_len); + sig_len = __bpf_dynptr_size(sig_ptr); + sig = __bpf_dynptr_data(sig_ptr, sig_len); + + return verify_pkcs7_signature(data, data_len, sig, sig_len, trusted_keyring->key, VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); From a46afaa03f6db8c65492302ffdafcb2e769e5667 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Fri, 3 Nov 2023 09:11:26 +0100 Subject: [PATCH 0332/7721] bpftool: Fix prog object type in manpage bpftool's man page lists "program" as one of possible values for OBJECT, while in fact bpftool accepts "prog" instead. Reported-by: Jerry Snitselaar Signed-off-by: Artem Savkov Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20231103081126.170034-1-asavkov@redhat.com Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/Documentation/bpftool.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 6965c94dfdaf..09e4f2ff5658 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -20,7 +20,7 @@ SYNOPSIS **bpftool** **version** - *OBJECT* := { **map** | **program** | **link** | **cgroup** | **perf** | **net** | **feature** | + *OBJECT* := { **map** | **prog** | **link** | **cgroup** | **perf** | **net** | **feature** | **btf** | **gen** | **struct_ops** | **iter** } *OPTIONS* := { { **-V** | **--version** } | |COMMON_OPTIONS| } From 0b51940729150e807fc4b7767164e6bb6cf4f7dd Mon Sep 17 00:00:00 2001 From: Song Liu Date: Mon, 6 Nov 2023 20:57:24 -0800 Subject: [PATCH 0333/7721] bpf: Factor out helper check_reg_const_str() ARG_PTR_TO_CONST_STR is used to specify constant string args for BPF helpers. The logic that verifies a reg is ARG_PTR_TO_CONST_STR is implemented in check_func_arg(). As we introduce kfuncs with constant string args, it is necessary to do the same check for kfuncs (in check_kfunc_args). Factor out the logic for ARG_PTR_TO_CONST_STR to a new check_reg_const_str() so that it can be reused. check_func_arg() ensures check_reg_const_str() is only called with reg of type PTR_TO_MAP_VALUE. Add a redundent type check in check_reg_const_str() to avoid misuse in the future. Other than this redundent check, there is no change in behavior. Signed-off-by: Song Liu Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: Vadim Fedorenko Link: https://lore.kernel.org/bpf/20231107045725.2278852-3-song@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e801c50d3857..637f34231633 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8725,6 +8725,54 @@ static enum bpf_dynptr_type dynptr_get_type(struct bpf_verifier_env *env, return state->stack[spi].spilled_ptr.dynptr.type; } +static int check_reg_const_str(struct bpf_verifier_env *env, + struct bpf_reg_state *reg, u32 regno) +{ + struct bpf_map *map = reg->map_ptr; + int err; + int map_off; + u64 map_addr; + char *str_ptr; + + if (reg->type != PTR_TO_MAP_VALUE) + return -EINVAL; + + if (!bpf_map_is_rdonly(map)) { + verbose(env, "R%d does not point to a readonly map'\n", regno); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off)) { + verbose(env, "R%d is not a constant address'\n", regno); + return -EACCES; + } + + if (!map->ops->map_direct_value_addr) { + verbose(env, "no direct value access support for this map type\n"); + return -EACCES; + } + + err = check_map_access(env, regno, reg->off, + map->value_size - reg->off, false, + ACCESS_HELPER); + if (err) + return err; + + map_off = reg->off + reg->var_off.value; + err = map->ops->map_direct_value_addr(map, &map_addr, map_off); + if (err) { + verbose(env, "direct value access on string failed\n"); + return err; + } + + str_ptr = (char *)(long)(map_addr); + if (!strnchr(str_ptr + map_off, map->value_size - map_off, 0)) { + verbose(env, "string is not zero-terminated\n"); + return -EINVAL; + } + return 0; +} + static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_call_arg_meta *meta, const struct bpf_func_proto *fn, @@ -8969,44 +9017,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, } case ARG_PTR_TO_CONST_STR: { - struct bpf_map *map = reg->map_ptr; - int map_off; - u64 map_addr; - char *str_ptr; - - if (!bpf_map_is_rdonly(map)) { - verbose(env, "R%d does not point to a readonly map'\n", regno); - return -EACCES; - } - - if (!tnum_is_const(reg->var_off)) { - verbose(env, "R%d is not a constant address'\n", regno); - return -EACCES; - } - - if (!map->ops->map_direct_value_addr) { - verbose(env, "no direct value access support for this map type\n"); - return -EACCES; - } - - err = check_map_access(env, regno, reg->off, - map->value_size - reg->off, false, - ACCESS_HELPER); + err = check_reg_const_str(env, reg, regno); if (err) return err; - - map_off = reg->off + reg->var_off.value; - err = map->ops->map_direct_value_addr(map, &map_addr, map_off); - if (err) { - verbose(env, "direct value access on string failed\n"); - return err; - } - - str_ptr = (char *)(long)(map_addr); - if (!strnchr(str_ptr + map_off, map->value_size - map_off, 0)) { - verbose(env, "string is not zero-terminated\n"); - return -EINVAL; - } break; } case ARG_PTR_TO_KPTR: From f2d2c7e1b7c9e8847478769d6e1f8a76b5e91952 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 3 Nov 2023 23:09:12 +0100 Subject: [PATCH 0334/7721] selftests/bpf: Disable CONFIG_DEBUG_INFO_REDUCED in config.aarch64 Building an arm64 kernel and seftests/bpf with defconfig + selftests/bpf/config and selftests/bpf/config.aarch64 the fragment CONFIG_DEBUG_INFO_REDUCED is enabled in arm64's defconfig, it should be disabled in file sefltests/bpf/config.aarch64 since if its not disabled CONFIG_DEBUG_INFO_BTF wont be enabled. Signed-off-by: Anders Roxell Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231103220912.333930-1-anders.roxell@linaro.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/config.aarch64 | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/config.aarch64 b/tools/testing/selftests/bpf/config.aarch64 index fa8ecf626c73..29c8635c5722 100644 --- a/tools/testing/selftests/bpf/config.aarch64 +++ b/tools/testing/selftests/bpf/config.aarch64 @@ -36,6 +36,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_INFO_BTF=y CONFIG_DEBUG_INFO_DWARF4=y +CONFIG_DEBUG_INFO_REDUCED=n CONFIG_DEBUG_LIST=y CONFIG_DEBUG_LOCKDEP=y CONFIG_DEBUG_NOTIFIERS=y From 045edee19d591e59ed53772bf6dfc9b1ed9577eb Mon Sep 17 00:00:00 2001 From: Song Liu Date: Mon, 6 Nov 2023 20:57:25 -0800 Subject: [PATCH 0335/7721] bpf: Introduce KF_ARG_PTR_TO_CONST_STR Similar to ARG_PTR_TO_CONST_STR for BPF helpers, KF_ARG_PTR_TO_CONST_STR specifies kfunc args that point to const strings. Annotation "__str" is used to specify kfunc arg of type KF_ARG_PTR_TO_CONST_STR. Also, add documentation for the "__str" annotation. bpf_get_file_xattr() will be the first kfunc that uses this type. Signed-off-by: Song Liu Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: Vadim Fedorenko Link: https://lore.kernel.org/bpf/20231107045725.2278852-4-song@kernel.org Signed-off-by: Alexei Starovoitov --- Documentation/bpf/kfuncs.rst | 24 ++++++++++++++++++++++++ kernel/bpf/verifier.c | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 723408e399ab..7985c6615f3c 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -135,6 +135,30 @@ Either way, the returned buffer is either NULL, or of size buffer_szk. Without t annotation, the verifier will reject the program if a null pointer is passed in with a nonzero size. +2.2.5 __str Annotation +---------------------------- +This annotation is used to indicate that the argument is a constant string. + +An example is given below:: + + __bpf_kfunc bpf_get_file_xattr(..., const char *name__str, ...) + { + ... + } + +In this case, ``bpf_get_file_xattr()`` can be called as:: + + bpf_get_file_xattr(..., "xattr_name", ...); + +Or:: + + const char name[] = "xattr_name"; /* This need to be global */ + int BPF_PROG(...) + { + ... + bpf_get_file_xattr(..., name, ...); + ... + } .. _BPF_kfunc_nodef: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 637f34231633..9276e0abcb4b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10810,6 +10810,11 @@ static bool is_kfunc_arg_nullable(const struct btf *btf, const struct btf_param return __kfunc_param_match_suffix(btf, arg, "__nullable"); } +static bool is_kfunc_arg_const_str(const struct btf *btf, const struct btf_param *arg) +{ + return __kfunc_param_match_suffix(btf, arg, "__str"); +} + static bool is_kfunc_arg_scalar_with_name(const struct btf *btf, const struct btf_param *arg, const char *name) @@ -10953,6 +10958,7 @@ enum kfunc_ptr_arg_type { KF_ARG_PTR_TO_RB_ROOT, KF_ARG_PTR_TO_RB_NODE, KF_ARG_PTR_TO_NULL, + KF_ARG_PTR_TO_CONST_STR, }; enum special_kfunc_type { @@ -11103,6 +11109,9 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, if (is_kfunc_arg_rbtree_node(meta->btf, &args[argno])) return KF_ARG_PTR_TO_RB_NODE; + if (is_kfunc_arg_const_str(meta->btf, &args[argno])) + return KF_ARG_PTR_TO_CONST_STR; + if ((base_type(reg->type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(reg->type)])) { if (!btf_type_is_struct(ref_t)) { verbose(env, "kernel function %s args#%d pointer type %s %s is not supported\n", @@ -11734,6 +11743,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ case KF_ARG_PTR_TO_MEM_SIZE: case KF_ARG_PTR_TO_CALLBACK: case KF_ARG_PTR_TO_REFCOUNTED_KPTR: + case KF_ARG_PTR_TO_CONST_STR: /* Trusted by default */ break; default: @@ -12005,6 +12015,15 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ meta->arg_btf = reg->btf; meta->arg_btf_id = reg->btf_id; break; + case KF_ARG_PTR_TO_CONST_STR: + if (reg->type != PTR_TO_MAP_VALUE) { + verbose(env, "arg#%d doesn't point to a const string\n", i); + return -EINVAL; + } + ret = check_reg_const_str(env, reg, regno); + if (ret) + return ret; + break; } } From 9b75dbeb36fcd9fc7ed51d370310d0518a387769 Mon Sep 17 00:00:00 2001 From: Florian Lehner Date: Sun, 5 Nov 2023 09:58:01 +0100 Subject: [PATCH 0336/7721] bpf, lpm: Fix check prefixlen before walking trie When looking up an element in LPM trie, the condition 'matchlen == trie->max_prefixlen' will never return true, if key->prefixlen is larger than trie->max_prefixlen. Consequently all elements in the LPM trie will be visited and no element is returned in the end. To resolve this, check key->prefixlen first before walking the LPM trie. Fixes: b95a5c4db09b ("bpf: add a longest prefix match trie map implementation") Signed-off-by: Florian Lehner Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231105085801.3742-1-dev@der-flo.net Signed-off-by: Alexei Starovoitov --- kernel/bpf/lpm_trie.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index 17c7e7782a1f..b32be680da6c 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c @@ -231,6 +231,9 @@ static void *trie_lookup_elem(struct bpf_map *map, void *_key) struct lpm_trie_node *node, *found = NULL; struct bpf_lpm_trie_key *key = _key; + if (key->prefixlen > trie->max_prefixlen) + return NULL; + /* Start walking the trie from the root node ... */ for (node = rcu_dereference_check(trie->root, rcu_read_lock_bh_held()); From 1500a5d9f49cb66906d3ea1c9158df25cc41dd40 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:34 -0800 Subject: [PATCH 0337/7721] bpf: Add KF_RCU flag to bpf_refcount_acquire_impl Refcounted local kptrs are kptrs to user-defined types with a bpf_refcount field. Recent commits ([0], [1]) modified the lifetime of refcounted local kptrs such that the underlying memory is not reused until RCU grace period has elapsed. Separately, verification of bpf_refcount_acquire calls currently succeeds for MAYBE_NULL non-owning reference input, which is a problem as bpf_refcount_acquire_impl has no handling for this case. This patch takes advantage of aforementioned lifetime changes to tag bpf_refcount_acquire_impl kfunc KF_RCU, thereby preventing MAYBE_NULL input to the kfunc. The KF_RCU flag applies to all kfunc params; it's fine for it to apply to the void *meta__ign param as that's populated by the verifier and is tagged __ign regardless. [0]: commit 7e26cd12ad1c ("bpf: Use bpf_mem_free_rcu when bpf_obj_dropping refcounted nodes") is the actual change to allocation behaivor [1]: commit 0816b8c6bf7f ("bpf: Consider non-owning refs to refcounted nodes RCU protected") modified verifier understanding of refcounted local kptrs to match [0]'s changes Signed-off-by: Dave Marchevsky Fixes: 7c50b1cb76ac ("bpf: Add bpf_refcount_acquire kfunc") Link: https://lore.kernel.org/r/20231107085639.3016113-2-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 174f02a9e703..b84d8cb8d239 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2520,7 +2520,7 @@ BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_percpu_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) BTF_ID_FLAGS(func, bpf_percpu_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL | KF_RCU) BTF_ID_FLAGS(func, bpf_list_push_front_impl) BTF_ID_FLAGS(func, bpf_list_push_back_impl) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) From f460e7bdb027d1da93f0c5090b239889cd46a33d Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:35 -0800 Subject: [PATCH 0338/7721] selftests/bpf: Add test passing MAYBE_NULL reg to bpf_refcount_acquire The test added in this patch exercises the logic fixed in the previous patch in this series. Before the previous patch's changes, bpf_refcount_acquire accepts MAYBE_NULL local kptrs; after the change the verifier correctly rejects the such a call. Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20231107085639.3016113-3-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- .../bpf/progs/refcounted_kptr_fail.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c index 1ef07f6ee580..1553b9c16aa7 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c @@ -53,6 +53,25 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) return 0; } +SEC("?tc") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +long refcount_acquire_maybe_null(void *ctx) +{ + struct node_acquire *n, *m; + + n = bpf_obj_new(typeof(*n)); + /* Intentionally not testing !n + * it's MAYBE_NULL for refcount_acquire + */ + m = bpf_refcount_acquire(n); + if (m) + bpf_obj_drop(m); + if (n) + bpf_obj_drop(n); + + return 0; +} + SEC("?tc") __failure __msg("Unreleased reference id=3 alloc_insn=9") long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx) From 649924b76ab151a96bdd22a97a993fb0421f134c Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:36 -0800 Subject: [PATCH 0339/7721] bpf: Use bpf_mem_free_rcu when bpf_obj_dropping non-refcounted nodes The use of bpf_mem_free_rcu to free refcounted local kptrs was added in commit 7e26cd12ad1c ("bpf: Use bpf_mem_free_rcu when bpf_obj_dropping refcounted nodes"). In the cover letter for the series containing that patch [0] I commented: Perhaps it makes sense to move to mem_free_rcu for _all_ non-owning refs in the future, not just refcounted. This might allow custom non-owning ref lifetime + invalidation logic to be entirely subsumed by MEM_RCU handling. IMO this needs a bit more thought and should be tackled outside of a fix series, so it's not attempted here. It's time to start moving in the "non-owning refs have MEM_RCU lifetime" direction. As mentioned in that comment, using bpf_mem_free_rcu for all local kptrs - not just refcounted - is necessarily the first step towards that goal. This patch does so. After this patch the memory pointed to by all local kptrs will not be reused until RCU grace period elapses. The verifier's understanding of non-owning ref validity and the clobbering logic it uses to enforce that understanding are not changed here, that'll happen gradually in future work, including further patches in the series. [0]: https://lore.kernel.org/all/20230821193311.3290257-1-davemarchevsky@fb.com/ Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20231107085639.3016113-4-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index b84d8cb8d239..03517db5cfb3 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1937,10 +1937,7 @@ void __bpf_obj_drop_impl(void *p, const struct btf_record *rec, bool percpu) ma = &bpf_global_percpu_ma; else ma = &bpf_global_ma; - if (rec && rec->refcount_off >= 0) - bpf_mem_free_rcu(ma, p); - else - bpf_mem_free(ma, p); + bpf_mem_free_rcu(ma, p); } __bpf_kfunc void bpf_obj_drop_impl(void *p__alloc, void *meta__ign) From 7f7c43693c1b46652cfafb7af67ba31726d6ec4e Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 7 Nov 2023 12:15:11 -0800 Subject: [PATCH 0340/7721] libbpf: Fix potential uninitialized tail padding with LIBBPF_OPTS_RESET Martin reported that there is a libbpf complaining of non-zero-value tail padding with LIBBPF_OPTS_RESET macro if struct bpf_netkit_opts is modified to have a 4-byte tail padding. This only happens to clang compiler. The commend line is: ./test_progs -t tc_netkit_multi_links Martin and I did some investigation and found this indeed the case and the following are the investigation details. Clang: clang version 18.0.0 tools/lib/bpf/libbpf_common.h: #define LIBBPF_OPTS_RESET(NAME, ...) \ do { \ memset(&NAME, 0, sizeof(NAME)); \ NAME = (typeof(NAME)) { \ .sz = sizeof(NAME), \ __VA_ARGS__ \ }; \ } while (0) #endif tools/lib/bpf/libbpf.h: struct bpf_netkit_opts { /* size of this struct, for forward/backward compatibility */ size_t sz; __u32 flags; __u32 relative_fd; __u32 relative_id; __u64 expected_revision; size_t :0; }; #define bpf_netkit_opts__last_field expected_revision In the above struct bpf_netkit_opts, there is no tail padding. prog_tests/tc_netkit.c: static void serial_test_tc_netkit_multi_links_target(int mode, int target) { ... LIBBPF_OPTS(bpf_netkit_opts, optl); ... LIBBPF_OPTS_RESET(optl, .flags = BPF_F_BEFORE, .relative_fd = bpf_program__fd(skel->progs.tc1), ); ... } Let us make the following source change, note that we have a 4-byte tailing padding now. diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 6cd9c501624f..0dd83910ae9a 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -803,13 +803,13 @@ bpf_program__attach_tcx(const struct bpf_program *prog, int ifindex, struct bpf_netkit_opts { /* size of this struct, for forward/backward compatibility */ size_t sz; - __u32 flags; __u32 relative_fd; __u32 relative_id; __u64 expected_revision; + __u32 flags; size_t :0; }; -#define bpf_netkit_opts__last_field expected_revision +#define bpf_netkit_opts__last_field flags The clang 18 generated asm code looks like below: ; LIBBPF_OPTS_RESET(optl, 55e3: 48 8d 7d 98 leaq -0x68(%rbp), %rdi 55e7: 31 f6 xorl %esi, %esi 55e9: ba 20 00 00 00 movl $0x20, %edx 55ee: e8 00 00 00 00 callq 0x55f3 55f3: 48 c7 85 10 fd ff ff 20 00 00 00 movq $0x20, -0x2f0(%rbp) 55fe: 48 8b 85 68 ff ff ff movq -0x98(%rbp), %rax 5605: 48 8b 78 18 movq 0x18(%rax), %rdi 5609: e8 00 00 00 00 callq 0x560e 560e: 89 85 18 fd ff ff movl %eax, -0x2e8(%rbp) 5614: c7 85 1c fd ff ff 00 00 00 00 movl $0x0, -0x2e4(%rbp) 561e: 48 c7 85 20 fd ff ff 00 00 00 00 movq $0x0, -0x2e0(%rbp) 5629: c7 85 28 fd ff ff 08 00 00 00 movl $0x8, -0x2d8(%rbp) 5633: 48 8b 85 10 fd ff ff movq -0x2f0(%rbp), %rax 563a: 48 89 45 98 movq %rax, -0x68(%rbp) 563e: 48 8b 85 18 fd ff ff movq -0x2e8(%rbp), %rax 5645: 48 89 45 a0 movq %rax, -0x60(%rbp) 5649: 48 8b 85 20 fd ff ff movq -0x2e0(%rbp), %rax 5650: 48 89 45 a8 movq %rax, -0x58(%rbp) 5654: 48 8b 85 28 fd ff ff movq -0x2d8(%rbp), %rax 565b: 48 89 45 b0 movq %rax, -0x50(%rbp) ; link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl); At -O0 level, the clang compiler creates an intermediate copy. We have below to store 'flags' with 4-byte store and leave another 4 byte in the same 8-byte-aligned storage undefined, 5629: c7 85 28 fd ff ff 08 00 00 00 movl $0x8, -0x2d8(%rbp) and later we store 8-byte to the original zero'ed buffer 5654: 48 8b 85 28 fd ff ff movq -0x2d8(%rbp), %rax 565b: 48 89 45 b0 movq %rax, -0x50(%rbp) This caused a problem as the 4-byte value at [%rbp-0x2dc, %rbp-0x2e0) may be garbage. gcc (gcc 11.4) does not have this issue as it does zeroing struct first before doing assignments: ; LIBBPF_OPTS_RESET(optl, 50fd: 48 8d 85 40 fc ff ff leaq -0x3c0(%rbp), %rax 5104: ba 20 00 00 00 movl $0x20, %edx 5109: be 00 00 00 00 movl $0x0, %esi 510e: 48 89 c7 movq %rax, %rdi 5111: e8 00 00 00 00 callq 0x5116 5116: 48 8b 45 f0 movq -0x10(%rbp), %rax 511a: 48 8b 40 18 movq 0x18(%rax), %rax 511e: 48 89 c7 movq %rax, %rdi 5121: e8 00 00 00 00 callq 0x5126 5126: 48 c7 85 40 fc ff ff 00 00 00 00 movq $0x0, -0x3c0(%rbp) 5131: 48 c7 85 48 fc ff ff 00 00 00 00 movq $0x0, -0x3b8(%rbp) 513c: 48 c7 85 50 fc ff ff 00 00 00 00 movq $0x0, -0x3b0(%rbp) 5147: 48 c7 85 58 fc ff ff 00 00 00 00 movq $0x0, -0x3a8(%rbp) 5152: 48 c7 85 40 fc ff ff 20 00 00 00 movq $0x20, -0x3c0(%rbp) 515d: 89 85 48 fc ff ff movl %eax, -0x3b8(%rbp) 5163: c7 85 58 fc ff ff 08 00 00 00 movl $0x8, -0x3a8(%rbp) ; link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl); It is not clear how to resolve the compiler code generation as the compiler generates correct code w.r.t. how to handle unnamed padding in C standard. So this patch changed LIBBPF_OPTS_RESET macro to avoid uninitialized tail padding. We already knows LIBBPF_OPTS macro works on both gcc and clang, even with tail padding. So LIBBPF_OPTS_RESET is changed to be a LIBBPF_OPTS followed by a memcpy(), thus avoiding uninitialized tail padding. The below is asm code generated with this patch and with clang compiler: ; LIBBPF_OPTS_RESET(optl, 55e3: 48 8d bd 10 fd ff ff leaq -0x2f0(%rbp), %rdi 55ea: 31 f6 xorl %esi, %esi 55ec: ba 20 00 00 00 movl $0x20, %edx 55f1: e8 00 00 00 00 callq 0x55f6 55f6: 48 c7 85 10 fd ff ff 20 00 00 00 movq $0x20, -0x2f0(%rbp) 5601: 48 8b 85 68 ff ff ff movq -0x98(%rbp), %rax 5608: 48 8b 78 18 movq 0x18(%rax), %rdi 560c: e8 00 00 00 00 callq 0x5611 5611: 89 85 18 fd ff ff movl %eax, -0x2e8(%rbp) 5617: c7 85 1c fd ff ff 00 00 00 00 movl $0x0, -0x2e4(%rbp) 5621: 48 c7 85 20 fd ff ff 00 00 00 00 movq $0x0, -0x2e0(%rbp) 562c: c7 85 28 fd ff ff 08 00 00 00 movl $0x8, -0x2d8(%rbp) 5636: 48 8b 85 10 fd ff ff movq -0x2f0(%rbp), %rax 563d: 48 89 45 98 movq %rax, -0x68(%rbp) 5641: 48 8b 85 18 fd ff ff movq -0x2e8(%rbp), %rax 5648: 48 89 45 a0 movq %rax, -0x60(%rbp) 564c: 48 8b 85 20 fd ff ff movq -0x2e0(%rbp), %rax 5653: 48 89 45 a8 movq %rax, -0x58(%rbp) 5657: 48 8b 85 28 fd ff ff movq -0x2d8(%rbp), %rax 565e: 48 89 45 b0 movq %rax, -0x50(%rbp) ; link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl); In the above code, a temporary buffer is zeroed and then has proper value assigned. Finally, values in temporary buffer are copied to the original variable buffer, hence tail padding is guaranteed to be 0. Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Tested-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20231107201511.2548645-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf_common.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/libbpf_common.h b/tools/lib/bpf/libbpf_common.h index b7060f254486..8fe248e14eb6 100644 --- a/tools/lib/bpf/libbpf_common.h +++ b/tools/lib/bpf/libbpf_common.h @@ -79,11 +79,14 @@ */ #define LIBBPF_OPTS_RESET(NAME, ...) \ do { \ - memset(&NAME, 0, sizeof(NAME)); \ - NAME = (typeof(NAME)) { \ - .sz = sizeof(NAME), \ - __VA_ARGS__ \ - }; \ + typeof(NAME) ___##NAME = ({ \ + memset(&___##NAME, 0, sizeof(NAME)); \ + (typeof(NAME)) { \ + .sz = sizeof(NAME), \ + __VA_ARGS__ \ + }; \ + }); \ + memcpy(&NAME, &___##NAME, sizeof(NAME)); \ } while (0) #endif /* __LIBBPF_LIBBPF_COMMON_H */ From 790ce3cfefb1b768dccd4eee324ddef0f0ce3db4 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:37 -0800 Subject: [PATCH 0341/7721] bpf: Move GRAPH_{ROOT,NODE}_MASK macros into btf_field_type enum This refactoring patch removes the unused BPF_GRAPH_NODE_OR_ROOT btf_field_type and moves BPF_GRAPH_{NODE,ROOT} macros into the btf_field_type enum. Further patches in the series will use BPF_GRAPH_NODE, so let's move this useful definition out of btf.c. Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20231107085639.3016113-5-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 4 ++-- kernel/bpf/btf.c | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index eb84caf133df..4001d11be151 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -186,8 +186,8 @@ enum btf_field_type { BPF_LIST_NODE = (1 << 6), BPF_RB_ROOT = (1 << 7), BPF_RB_NODE = (1 << 8), - BPF_GRAPH_NODE_OR_ROOT = BPF_LIST_NODE | BPF_LIST_HEAD | - BPF_RB_NODE | BPF_RB_ROOT, + BPF_GRAPH_NODE = BPF_RB_NODE | BPF_LIST_NODE, + BPF_GRAPH_ROOT = BPF_RB_ROOT | BPF_LIST_HEAD, BPF_REFCOUNT = (1 << 9), }; diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 15d71d2986d3..63cf4128fc05 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3840,9 +3840,6 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type return ERR_PTR(ret); } -#define GRAPH_ROOT_MASK (BPF_LIST_HEAD | BPF_RB_ROOT) -#define GRAPH_NODE_MASK (BPF_LIST_NODE | BPF_RB_NODE) - int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec) { int i; @@ -3855,13 +3852,13 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec) * Hence we only need to ensure that bpf_{list_head,rb_root} ownership * does not form cycles. */ - if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & GRAPH_ROOT_MASK)) + if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & BPF_GRAPH_ROOT)) return 0; for (i = 0; i < rec->cnt; i++) { struct btf_struct_meta *meta; u32 btf_id; - if (!(rec->fields[i].type & GRAPH_ROOT_MASK)) + if (!(rec->fields[i].type & BPF_GRAPH_ROOT)) continue; btf_id = rec->fields[i].graph_root.value_btf_id; meta = btf_find_struct_meta(btf, btf_id); @@ -3873,7 +3870,7 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec) * to check ownership cycle for a type unless it's also a * node type. */ - if (!(rec->field_mask & GRAPH_NODE_MASK)) + if (!(rec->field_mask & BPF_GRAPH_NODE)) continue; /* We need to ensure ownership acyclicity among all types. The @@ -3909,7 +3906,7 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec) * - A is both an root and node. * - B is only an node. */ - if (meta->record->field_mask & GRAPH_ROOT_MASK) + if (meta->record->field_mask & BPF_GRAPH_ROOT) return -ELOOP; } return 0; From 5d4a7aaca1ebcc7c864caec13203662a061c4f4f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 7 Nov 2023 21:14:29 -0800 Subject: [PATCH 0342/7721] veristat: add ability to sort by stat's absolute value Add ability to sort results by absolute values of specified stats. This is especially useful to find biggest deviations in comparison mode. When comparing verifier change effect against a large base of BPF object files, it's necessary to see big changes both in positive and negative directions, as both might be a signal for regressions or bugs. The syntax is natural, e.g., adding `-s '|insns_diff|'^` will instruct veristat to sort by absolute value of instructions difference in ascending order. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231108051430.1830950-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/veristat.c | 68 +++++++++++++++++++++----- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 655095810d4a..102914f70573 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -99,6 +100,7 @@ struct stat_specs { enum stat_id ids[ALL_STATS_CNT]; enum stat_variant variants[ALL_STATS_CNT]; bool asc[ALL_STATS_CNT]; + bool abs[ALL_STATS_CNT]; int lens[ALL_STATS_CNT * 3]; /* 3x for comparison mode */ }; @@ -133,6 +135,7 @@ struct filter { int stat_id; enum stat_variant stat_var; long value; + bool abs; }; static struct env { @@ -455,7 +458,8 @@ static struct { { OP_EQ, "=" }, }; -static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_variant *var); +static bool parse_stat_id_var(const char *name, size_t len, int *id, + enum stat_variant *var, bool *is_abs); static int append_filter(struct filter **filters, int *cnt, const char *str) { @@ -488,13 +492,14 @@ static int append_filter(struct filter **filters, int *cnt, const char *str) long val; const char *end = str; const char *op_str; + bool is_abs; op_str = operators[i].op_str; p = strstr(str, op_str); if (!p) continue; - if (!parse_stat_id_var(str, p - str, &id, &var)) { + if (!parse_stat_id_var(str, p - str, &id, &var, &is_abs)) { fprintf(stderr, "Unrecognized stat name in '%s'!\n", str); return -EINVAL; } @@ -533,6 +538,7 @@ static int append_filter(struct filter **filters, int *cnt, const char *str) f->stat_id = id; f->stat_var = var; f->op = operators[i].op_kind; + f->abs = true; f->value = val; *cnt += 1; @@ -657,7 +663,8 @@ static struct stat_def { [MARK_READ_MAX_LEN] = { "Max mark read length", {"max_mark_read_len", "mark_read"}, }, }; -static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_variant *var) +static bool parse_stat_id_var(const char *name, size_t len, int *id, + enum stat_variant *var, bool *is_abs) { static const char *var_sfxs[] = { [VARIANT_A] = "_a", @@ -667,6 +674,14 @@ static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_v }; int i, j, k; + /* || means we take absolute value of given stat */ + *is_abs = false; + if (len > 2 && name[0] == '|' && name[len - 1] == '|') { + *is_abs = true; + name += 1; + len -= 2; + } + for (i = 0; i < ARRAY_SIZE(stat_defs); i++) { struct stat_def *def = &stat_defs[i]; size_t alias_len, sfx_len; @@ -722,7 +737,7 @@ static bool is_desc_sym(char c) static int parse_stat(const char *stat_name, struct stat_specs *specs) { int id; - bool has_order = false, is_asc = false; + bool has_order = false, is_asc = false, is_abs = false; size_t len = strlen(stat_name); enum stat_variant var; @@ -737,7 +752,7 @@ static int parse_stat(const char *stat_name, struct stat_specs *specs) len -= 1; } - if (!parse_stat_id_var(stat_name, len, &id, &var)) { + if (!parse_stat_id_var(stat_name, len, &id, &var, &is_abs)) { fprintf(stderr, "Unrecognized stat name '%s'\n", stat_name); return -ESRCH; } @@ -745,6 +760,7 @@ static int parse_stat(const char *stat_name, struct stat_specs *specs) specs->ids[specs->spec_cnt] = id; specs->variants[specs->spec_cnt] = var; specs->asc[specs->spec_cnt] = has_order ? is_asc : stat_defs[id].asc_by_default; + specs->abs[specs->spec_cnt] = is_abs; specs->spec_cnt++; return 0; @@ -1103,7 +1119,7 @@ static int process_obj(const char *filename) } static int cmp_stat(const struct verif_stats *s1, const struct verif_stats *s2, - enum stat_id id, bool asc) + enum stat_id id, bool asc, bool abs) { int cmp = 0; @@ -1124,6 +1140,11 @@ static int cmp_stat(const struct verif_stats *s1, const struct verif_stats *s2, long v1 = s1->stats[id]; long v2 = s2->stats[id]; + if (abs) { + v1 = v1 < 0 ? -v1 : v1; + v2 = v2 < 0 ? -v2 : v2; + } + if (v1 != v2) cmp = v1 < v2 ? -1 : 1; break; @@ -1142,7 +1163,8 @@ static int cmp_prog_stats(const void *v1, const void *v2) int i, cmp; for (i = 0; i < env.sort_spec.spec_cnt; i++) { - cmp = cmp_stat(s1, s2, env.sort_spec.ids[i], env.sort_spec.asc[i]); + cmp = cmp_stat(s1, s2, env.sort_spec.ids[i], + env.sort_spec.asc[i], env.sort_spec.abs[i]); if (cmp != 0) return cmp; } @@ -1211,7 +1233,8 @@ static void fetch_join_stat_value(const struct verif_stats_join *s, static int cmp_join_stat(const struct verif_stats_join *s1, const struct verif_stats_join *s2, - enum stat_id id, enum stat_variant var, bool asc) + enum stat_id id, enum stat_variant var, + bool asc, bool abs) { const char *str1 = NULL, *str2 = NULL; double v1, v2; @@ -1220,6 +1243,11 @@ static int cmp_join_stat(const struct verif_stats_join *s1, fetch_join_stat_value(s1, id, var, &str1, &v1); fetch_join_stat_value(s2, id, var, &str2, &v2); + if (abs) { + v1 = fabs(v1); + v2 = fabs(v2); + } + if (str1) cmp = strcmp(str1, str2); else if (v1 != v2) @@ -1237,7 +1265,8 @@ static int cmp_join_stats(const void *v1, const void *v2) cmp = cmp_join_stat(s1, s2, env.sort_spec.ids[i], env.sort_spec.variants[i], - env.sort_spec.asc[i]); + env.sort_spec.asc[i], + env.sort_spec.abs[i]); if (cmp != 0) return cmp; } @@ -1720,6 +1749,9 @@ static bool is_join_stat_filter_matched(struct filter *f, const struct verif_sta fetch_join_stat_value(stats, f->stat_id, f->stat_var, &str, &value); + if (f->abs) + value = fabs(value); + switch (f->op) { case OP_EQ: return value > f->value - eps && value < f->value + eps; case OP_NEQ: return value < f->value - eps || value > f->value + eps; @@ -1766,7 +1798,7 @@ static int handle_comparison_mode(void) struct stat_specs base_specs = {}, comp_specs = {}; struct stat_specs tmp_sort_spec; enum resfmt cur_fmt; - int err, i, j, last_idx; + int err, i, j, last_idx, cnt; if (env.filename_cnt != 2) { fprintf(stderr, "Comparison mode expects exactly two input CSV files!\n\n"); @@ -1879,7 +1911,7 @@ static int handle_comparison_mode(void) env.join_stat_cnt += 1; } - /* now sort joined results accorsing to sort spec */ + /* now sort joined results according to sort spec */ qsort(env.join_stats, env.join_stat_cnt, sizeof(*env.join_stats), cmp_join_stats); /* for human-readable table output we need to do extra pass to @@ -1896,16 +1928,22 @@ static int handle_comparison_mode(void) output_comp_headers(cur_fmt); last_idx = -1; + cnt = 0; for (i = 0; i < env.join_stat_cnt; i++) { const struct verif_stats_join *join = &env.join_stats[i]; if (!should_output_join_stats(join)) continue; + if (env.top_n && cnt >= env.top_n) + break; + if (cur_fmt == RESFMT_TABLE_CALCLEN) last_idx = i; output_comp_stats(join, cur_fmt, i == last_idx); + + cnt++; } if (cur_fmt == RESFMT_TABLE_CALCLEN) { @@ -1920,6 +1958,9 @@ static bool is_stat_filter_matched(struct filter *f, const struct verif_stats *s { long value = stats->stats[f->stat_id]; + if (f->abs) + value = value < 0 ? -value : value; + switch (f->op) { case OP_EQ: return value == f->value; case OP_NEQ: return value != f->value; @@ -1964,7 +2005,7 @@ static bool should_output_stats(const struct verif_stats *stats) static void output_prog_stats(void) { const struct verif_stats *stats; - int i, last_stat_idx = 0; + int i, last_stat_idx = 0, cnt = 0; if (env.out_fmt == RESFMT_TABLE) { /* calculate column widths */ @@ -1984,7 +2025,10 @@ static void output_prog_stats(void) stats = &env.prog_stats[i]; if (!should_output_stats(stats)) continue; + if (env.top_n && cnt >= env.top_n) + break; output_stats(stats, env.out_fmt, i == last_stat_idx); + cnt++; } } From 1b12171533a9bb23cf6fba7262b479028b65e1e8 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:38 -0800 Subject: [PATCH 0343/7721] bpf: Mark direct ld of stashed bpf_{rb,list}_node as non-owning ref This patch enables the following pattern: /* mapval contains a __kptr pointing to refcounted local kptr */ mapval = bpf_map_lookup_elem(&map, &idx); if (!mapval || !mapval->some_kptr) { /* omitted */ } p = bpf_refcount_acquire(&mapval->some_kptr); Currently this doesn't work because bpf_refcount_acquire expects an owning or non-owning ref. The verifier defines non-owning ref as a type: PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF while mapval->some_kptr is PTR_TO_BTF_ID | PTR_UNTRUSTED. It's possible to do the refcount_acquire by first bpf_kptr_xchg'ing mapval->some_kptr into a temp kptr, refcount_acquiring that, and xchg'ing back into mapval, but this is unwieldy and shouldn't be necessary. This patch modifies btf_ld_kptr_type such that user-allocated types are marked MEM_ALLOC and if those types have a bpf_{rb,list}_node they're marked NON_OWN_REF as well. Additionally, due to changes to bpf_obj_drop_impl earlier in this series, rcu_protected_object now returns true for all user-allocated types, resulting in mapval->some_kptr being marked MEM_RCU. After this patch's changes, mapval->some_kptr is now: PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU which results in it passing the non-owning ref test, and the motivating example passing verification. Future work will likely get rid of special non-owning ref lifetime logic in the verifier, at which point we'll be able to delete the NON_OWN_REF flag entirely. Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20231107085639.3016113-6-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 993e4677bbe9..9ae6eae13471 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5557,10 +5557,23 @@ BTF_SET_END(rcu_protected_types) static bool rcu_protected_object(const struct btf *btf, u32 btf_id) { if (!btf_is_kernel(btf)) - return false; + return true; return btf_id_set_contains(&rcu_protected_types, btf_id); } +static struct btf_record *kptr_pointee_btf_record(struct btf_field *kptr_field) +{ + struct btf_struct_meta *meta; + + if (btf_is_kernel(kptr_field->kptr.btf)) + return NULL; + + meta = btf_find_struct_meta(kptr_field->kptr.btf, + kptr_field->kptr.btf_id); + + return meta ? meta->record : NULL; +} + static bool rcu_safe_kptr(const struct btf_field *field) { const struct btf_field_kptr *kptr = &field->kptr; @@ -5571,12 +5584,25 @@ static bool rcu_safe_kptr(const struct btf_field *field) static u32 btf_ld_kptr_type(struct bpf_verifier_env *env, struct btf_field *kptr_field) { + struct btf_record *rec; + u32 ret; + + ret = PTR_MAYBE_NULL; if (rcu_safe_kptr(kptr_field) && in_rcu_cs(env)) { - if (kptr_field->type != BPF_KPTR_PERCPU) - return PTR_MAYBE_NULL | MEM_RCU; - return PTR_MAYBE_NULL | MEM_RCU | MEM_PERCPU; + ret |= MEM_RCU; + if (kptr_field->type == BPF_KPTR_PERCPU) + ret |= MEM_PERCPU; + else if (!btf_is_kernel(kptr_field->kptr.btf)) + ret |= MEM_ALLOC; + + rec = kptr_pointee_btf_record(kptr_field); + if (rec && btf_record_has_field(rec, BPF_GRAPH_NODE)) + ret |= NON_OWN_REF; + } else { + ret |= PTR_UNTRUSTED; } - return PTR_MAYBE_NULL | PTR_UNTRUSTED; + + return ret; } static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno, From 27007fae704eb12547b9b5c7b1005e11640d4f19 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 7 Nov 2023 21:14:30 -0800 Subject: [PATCH 0344/7721] veristat: add ability to filter top N results Add ability to filter top B results, both in replay/verifier mode and comparison mode. Just adding `-n10` will emit only first 10 rows, or less, if there is not enough rows. This is not just a shortcut instead of passing veristat output through `head`, though. Filtering out all the other rows influences final table formatting, as table column widths are calculated based on actual emitted test. To demonstrate the difference, compare two "equivalent" forms below, one using head and another using -n argument. TOP N FEATURE ============= [vmuser@archvm bpf]$ sudo ./veristat -C ~/baseline-results-selftests.csv ~/sanity2-results-selftests.csv -e file,prog,insns,states -s '|insns_diff|' -n10 File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) ---------------------------------------- --------------------- --------- --------- ------------ ---------- ---------- ------------- test_seg6_loop.bpf.linked3.o __add_egr_x 12440 12360 -80 (-0.64%) 364 357 -7 (-1.92%) async_stack_depth.bpf.linked3.o async_call_root_check 145 145 +0 (+0.00%) 3 3 +0 (+0.00%) async_stack_depth.bpf.linked3.o pseudo_call_check 139 139 +0 (+0.00%) 3 3 +0 (+0.00%) atomic_bounds.bpf.linked3.o sub 7 7 +0 (+0.00%) 0 0 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o kmalloc 5 5 +0 (+0.00%) 0 0 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o sched_process_fork 22 22 +0 (+0.00%) 2 2 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o socket_post_create 23 23 +0 (+0.00%) 2 2 +0 (+0.00%) bind4_prog.bpf.linked3.o bind_v4_prog 358 358 +0 (+0.00%) 33 33 +0 (+0.00%) bind6_prog.bpf.linked3.o bind_v6_prog 429 429 +0 (+0.00%) 37 37 +0 (+0.00%) bind_perm.bpf.linked3.o bind_v4_prog 15 15 +0 (+0.00%) 1 1 +0 (+0.00%) PIPING TO HEAD ============== [vmuser@archvm bpf]$ sudo ./veristat -C ~/baseline-results-selftests.csv ~/sanity2-results-selftests.csv -e file,prog,insns,states -s '|insns_diff|' | head -n12 File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) ----------------------------------------------------- ---------------------------------------------------- --------- --------- ------------ ---------- ---------- ------------- test_seg6_loop.bpf.linked3.o __add_egr_x 12440 12360 -80 (-0.64%) 364 357 -7 (-1.92%) async_stack_depth.bpf.linked3.o async_call_root_check 145 145 +0 (+0.00%) 3 3 +0 (+0.00%) async_stack_depth.bpf.linked3.o pseudo_call_check 139 139 +0 (+0.00%) 3 3 +0 (+0.00%) atomic_bounds.bpf.linked3.o sub 7 7 +0 (+0.00%) 0 0 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o kmalloc 5 5 +0 (+0.00%) 0 0 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o sched_process_fork 22 22 +0 (+0.00%) 2 2 +0 (+0.00%) bench_local_storage_create.bpf.linked3.o socket_post_create 23 23 +0 (+0.00%) 2 2 +0 (+0.00%) bind4_prog.bpf.linked3.o bind_v4_prog 358 358 +0 (+0.00%) 33 33 +0 (+0.00%) bind6_prog.bpf.linked3.o bind_v6_prog 429 429 +0 (+0.00%) 37 37 +0 (+0.00%) bind_perm.bpf.linked3.o bind_v4_prog 15 15 +0 (+0.00%) 1 1 +0 (+0.00%) Note all the wasted whitespace in the "PIPING TO HEAD" variant. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231108051430.1830950-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/veristat.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 102914f70573..443a29fc6a62 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -149,6 +149,7 @@ static struct env { bool show_version; bool comparison_mode; bool replay_mode; + int top_n; int log_level; int log_size; @@ -215,6 +216,7 @@ static const struct argp_option opts[] = { { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" }, { "test-states", 't', NULL, 0, "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, + { "top-n", 'n', "N", 0, "Emit only up to first N results." }, { "quiet", 'q', NULL, 0, "Quiet mode" }, { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, { "sort", 's', "SPEC", 0, "Specify sort order" }, @@ -293,6 +295,14 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 't': env.force_checkpoints = true; break; + case 'n': + errno = 0; + env.top_n = strtol(arg, NULL, 10); + if (errno) { + fprintf(stderr, "invalid top N specifier: %s\n", arg); + argp_usage(state); + } + break; case 'C': env.comparison_mode = true; break; From e9ed8df7187cfdce1075d0ee591544ac15d072f1 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 7 Nov 2023 00:56:39 -0800 Subject: [PATCH 0345/7721] selftests/bpf: Test bpf_refcount_acquire of node obtained via direct ld This patch demonstrates that verifier changes earlier in this series result in bpf_refcount_acquire(mapval->stashed_kptr) passing verification. The added test additionally validates that stashing a kptr in mapval and - in a separate BPF program - refcount_acquiring the kptr without unstashing works as expected at runtime. Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20231107085639.3016113-7-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/local_kptr_stash.c | 33 +++++++++ .../selftests/bpf/progs/local_kptr_stash.c | 71 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c index b25b870f87ba..e6e50a394472 100644 --- a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c @@ -73,6 +73,37 @@ static void test_local_kptr_stash_unstash(void) local_kptr_stash__destroy(skel); } +static void test_refcount_acquire_without_unstash(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_in = &pkt_v4, + .data_size_in = sizeof(pkt_v4), + .repeat = 1, + ); + struct local_kptr_stash *skel; + int ret; + + skel = local_kptr_stash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) + return; + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.refcount_acquire_without_unstash), + &opts); + ASSERT_OK(ret, "refcount_acquire_without_unstash run"); + ASSERT_EQ(opts.retval, 2, "refcount_acquire_without_unstash retval"); + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_refcounted_node), &opts); + ASSERT_OK(ret, "stash_refcounted_node run"); + ASSERT_OK(opts.retval, "stash_refcounted_node retval"); + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.refcount_acquire_without_unstash), + &opts); + ASSERT_OK(ret, "refcount_acquire_without_unstash (2) run"); + ASSERT_EQ(opts.retval, 42, "refcount_acquire_without_unstash (2) retval"); + + local_kptr_stash__destroy(skel); +} + static void test_local_kptr_stash_fail(void) { RUN_TESTS(local_kptr_stash_fail); @@ -86,6 +117,8 @@ void test_local_kptr_stash(void) test_local_kptr_stash_plain(); if (test__start_subtest("local_kptr_stash_unstash")) test_local_kptr_stash_unstash(); + if (test__start_subtest("refcount_acquire_without_unstash")) + test_refcount_acquire_without_unstash(); if (test__start_subtest("local_kptr_stash_fail")) test_local_kptr_stash_fail(); } diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash.c b/tools/testing/selftests/bpf/progs/local_kptr_stash.c index b567a666d2b8..1769fdff6aea 100644 --- a/tools/testing/selftests/bpf/progs/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/progs/local_kptr_stash.c @@ -14,6 +14,24 @@ struct node_data { struct bpf_rb_node node; }; +struct refcounted_node { + long data; + struct bpf_rb_node rb_node; + struct bpf_refcount refcount; +}; + +struct stash { + struct bpf_spin_lock l; + struct refcounted_node __kptr *stashed; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct stash); + __uint(max_entries, 10); +} refcounted_node_stash SEC(".maps"); + struct plain_local { long key; long data; @@ -38,6 +56,7 @@ struct map_value { * Had to do the same w/ bpf_kfunc_call_test_release below */ struct node_data *just_here_because_btf_bug; +struct refcounted_node *just_here_because_btf_bug2; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -132,4 +151,56 @@ long stash_test_ref_kfunc(void *ctx) return 0; } +SEC("tc") +long refcount_acquire_without_unstash(void *ctx) +{ + struct refcounted_node *p; + struct stash *s; + int ret = 0; + + s = bpf_map_lookup_elem(&refcounted_node_stash, &ret); + if (!s) + return 1; + + if (!s->stashed) + /* refcount_acquire failure is expected when no refcounted_node + * has been stashed before this program executes + */ + return 2; + + p = bpf_refcount_acquire(s->stashed); + if (!p) + return 3; + + ret = s->stashed ? s->stashed->data : -1; + bpf_obj_drop(p); + return ret; +} + +/* Helper for refcount_acquire_without_unstash test */ +SEC("tc") +long stash_refcounted_node(void *ctx) +{ + struct refcounted_node *p; + struct stash *s; + int key = 0; + + s = bpf_map_lookup_elem(&refcounted_node_stash, &key); + if (!s) + return 1; + + p = bpf_obj_new(typeof(*p)); + if (!p) + return 2; + p->data = 42; + + p = bpf_kptr_xchg(&s->stashed, p); + if (p) { + bpf_obj_drop(p); + return 3; + } + + return 0; +} + char _license[] SEC("license") = "GPL"; From 82ce364c6087e31ff9837380a4641a856284064c Mon Sep 17 00:00:00 2001 From: Shung-Hsi Yu Date: Wed, 8 Nov 2023 22:00:41 +0800 Subject: [PATCH 0346/7721] bpf: replace register_is_const() with is_reg_const() The addition of is_reg_const() in commit 171de12646d2 ("bpf: generalize is_branch_taken to handle all conditional jumps in one place") has made the register_is_const() redundant. Give the former has more feature, plus the fact the latter is only used in one place, replace register_is_const() with is_reg_const(), and remove the definition of register_is_const. This requires moving the definition of is_reg_const() further up. And since the comment of reg_const_value() reference is_reg_const(), move it up as well. Signed-off-by: Shung-Hsi Yu Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231108140043.12282-1-shung-hsi.yu@suse.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9276e0abcb4b..993e4677bbe9 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4690,9 +4690,17 @@ static bool register_is_null(struct bpf_reg_state *reg) return reg->type == SCALAR_VALUE && tnum_equals_const(reg->var_off, 0); } -static bool register_is_const(struct bpf_reg_state *reg) +/* check if register is a constant scalar value */ +static bool is_reg_const(struct bpf_reg_state *reg, bool subreg32) { - return reg->type == SCALAR_VALUE && tnum_is_const(reg->var_off); + return reg->type == SCALAR_VALUE && + tnum_is_const(subreg32 ? tnum_subreg(reg->var_off) : reg->var_off); +} + +/* assuming is_reg_const() is true, return constant value of a register */ +static u64 reg_const_value(struct bpf_reg_state *reg, bool subreg32) +{ + return subreg32 ? tnum_subreg(reg->var_off).value : reg->var_off.value; } static bool __is_scalar_unbounded(struct bpf_reg_state *reg) @@ -10050,7 +10058,7 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, val = reg->var_off.value; max = map->max_entries; - if (!(register_is_const(reg) && val < max)) { + if (!(is_reg_const(reg, false) && val < max)) { bpf_map_key_store(aux, BPF_MAP_KEY_POISON); return 0; } @@ -14220,19 +14228,6 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, })); } -/* check if register is a constant scalar value */ -static bool is_reg_const(struct bpf_reg_state *reg, bool subreg32) -{ - return reg->type == SCALAR_VALUE && - tnum_is_const(subreg32 ? tnum_subreg(reg->var_off) : reg->var_off); -} - -/* assuming is_reg_const() is true, return constant value of a register */ -static u64 reg_const_value(struct bpf_reg_state *reg, bool subreg32) -{ - return subreg32 ? tnum_subreg(reg->var_off).value : reg->var_off.value; -} - /* * , currently assuming reg2 is a constant */ From 155addf0814a92d08fce26a11b27e3315cdba977 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 3 Nov 2023 19:49:00 -0700 Subject: [PATCH 0347/7721] bpf: Use named fields for certain bpf uapi structs Martin and Vadim reported a verifier failure with bpf_dynptr usage. The issue is mentioned but Vadim workarounded the issue with source change ([1]). The below describes what is the issue and why there is a verification failure. int BPF_PROG(skb_crypto_setup) { struct bpf_dynptr algo, key; ... bpf_dynptr_from_mem(..., ..., 0, &algo); ... } The bpf program is using vmlinux.h, so we have the following definition in vmlinux.h: struct bpf_dynptr { long: 64; long: 64; }; Note that in uapi header bpf.h, we have struct bpf_dynptr { long: 64; long: 64; } __attribute__((aligned(8))); So we lost alignment information for struct bpf_dynptr by using vmlinux.h. Let us take a look at a simple program below: $ cat align.c typedef unsigned long long __u64; struct bpf_dynptr_no_align { __u64 :64; __u64 :64; }; struct bpf_dynptr_yes_align { __u64 :64; __u64 :64; } __attribute__((aligned(8))); void bar(void *, void *); int foo() { struct bpf_dynptr_no_align a; struct bpf_dynptr_yes_align b; bar(&a, &b); return 0; } $ clang --target=bpf -O2 -S -emit-llvm align.c Look at the generated IR file align.ll: ... %a = alloca %struct.bpf_dynptr_no_align, align 1 %b = alloca %struct.bpf_dynptr_yes_align, align 8 ... The compiler dictates the alignment for struct bpf_dynptr_no_align is 1 and the alignment for struct bpf_dynptr_yes_align is 8. So theoretically compiler could allocate variable %a with alignment 1 although in reallity the compiler may choose a different alignment by considering other local variables. In [1], the verification failure happens because variable 'algo' is allocated on the stack with alignment 4 (fp-28). But the verifer wants its alignment to be 8. To fix the issue, the RFC patch ([1]) tried to add '__attribute__((aligned(8)))' to struct bpf_dynptr plus other similar structs. Andrii suggested that we could directly modify uapi struct with named fields like struct 'bpf_iter_num': struct bpf_iter_num { /* opaque iterator state; having __u64 here allows to preserve correct * alignment requirements in vmlinux.h, generated from BTF */ __u64 __opaque[1]; } __attribute__((aligned(8))); Indeed, adding named fields for those affected structs in this patch can preserve alignment when bpf program references them in vmlinux.h. With this patch, the verification failure in [1] can also be resolved. [1] https://lore.kernel.org/bpf/1b100f73-7625-4c1f-3ae5-50ecf84d3ff0@linux.dev/ [2] https://lore.kernel.org/bpf/20231103055218.2395034-1-yonghong.song@linux.dev/ Cc: Vadim Fedorenko Cc: Martin KaFai Lau Suggested-by: Andrii Nakryiko Signed-off-by: Yonghong Song Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231104024900.1539182-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 23 +++++++---------------- tools/include/uapi/linux/bpf.h | 23 +++++++---------------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 0f6cdf52b1da..095ca7238ac2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -7151,40 +7151,31 @@ struct bpf_spin_lock { }; struct bpf_timer { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_dynptr { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_head { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_node { - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[3]; } __attribute__((aligned(8))); struct bpf_rb_root { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_rb_node { - __u64 :64; - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[4]; } __attribute__((aligned(8))); struct bpf_refcount { - __u32 :32; + __u32 __opaque[1]; } __attribute__((aligned(4))); struct bpf_sysctl { diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 0f6cdf52b1da..095ca7238ac2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -7151,40 +7151,31 @@ struct bpf_spin_lock { }; struct bpf_timer { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_dynptr { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_head { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_node { - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[3]; } __attribute__((aligned(8))); struct bpf_rb_root { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_rb_node { - __u64 :64; - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[4]; } __attribute__((aligned(8))); struct bpf_refcount { - __u32 :32; + __u32 __opaque[1]; } __attribute__((aligned(4))); struct bpf_sysctl { From 48d054c2d34cdc67acb8cc9cfac326d91f1470ed Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 8 Nov 2023 12:52:58 +0530 Subject: [PATCH 0348/7721] drm/panelreplay: dpcd register definition for panelreplay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DPCD register definition for discovering, enabling and checking status of panel replay of the sink. Cc: Jouni Högander Cc: Arun R Murthy Cc: Jani Nikula Acked-by: Maxime Ripard Reviewed-by: Arun R Murthy Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-2-animesh.manna@intel.com --- include/drm/display/drm_dp.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 763d45a612f3..83d2039c018b 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -544,6 +544,10 @@ /* DFP Capability Extension */ #define DP_DFP_CAPABILITY_EXTENSION_SUPPORT 0x0a3 /* 2.0 */ +#define DP_PANEL_REPLAY_CAP 0x0b0 /* DP 2.0 */ +# define DP_PANEL_REPLAY_SUPPORT (1 << 0) +# define DP_PANEL_REPLAY_SU_SUPPORT (1 << 1) + /* Link Configuration */ #define DP_LINK_BW_SET 0x100 # define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ @@ -718,6 +722,13 @@ #define DP_BRANCH_DEVICE_CTRL 0x1a1 # define DP_BRANCH_DEVICE_IRQ_HPD (1 << 0) +#define PANEL_REPLAY_CONFIG 0x1b0 /* DP 2.0 */ +# define DP_PANEL_REPLAY_ENABLE (1 << 0) +# define DP_PANEL_REPLAY_UNRECOVERABLE_ERROR_EN (1 << 3) +# define DP_PANEL_REPLAY_RFB_STORAGE_ERROR_EN (1 << 4) +# define DP_PANEL_REPLAY_ACTIVE_FRAME_CRC_ERROR_EN (1 << 5) +# define DP_PANEL_REPLAY_SU_ENABLE (1 << 6) + #define DP_PAYLOAD_ALLOCATE_SET 0x1c0 #define DP_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x1c1 #define DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x1c2 @@ -1107,6 +1118,18 @@ #define DP_LANE_ALIGN_STATUS_UPDATED_ESI 0x200e /* status same as 0x204 */ #define DP_SINK_STATUS_ESI 0x200f /* status same as 0x205 */ +#define DP_PANEL_REPLAY_ERROR_STATUS 0x2020 /* DP 2.1*/ +# define DP_PANEL_REPLAY_LINK_CRC_ERROR (1 << 0) +# define DP_PANEL_REPLAY_RFB_STORAGE_ERROR (1 << 1) +# define DP_PANEL_REPLAY_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) + +#define DP_SINK_DEVICE_PR_AND_FRAME_LOCK_STATUS 0x2022 /* DP 2.1 */ +# define DP_SINK_DEVICE_PANEL_REPLAY_STATUS_MASK (7 << 0) +# define DP_SINK_FRAME_LOCKED_SHIFT 3 +# define DP_SINK_FRAME_LOCKED_MASK (3 << 3) +# define DP_SINK_FRAME_LOCKED_STATUS_VALID_SHIFT 5 +# define DP_SINK_FRAME_LOCKED_STATUS_VALID_MASK (1 << 5) + /* Extended Receiver Capability: See DP_DPCD_REV for definitions */ #define DP_DP13_DPCD_REV 0x2200 From dd8f2298e34bf64f07ad5ff27c5964994783e7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 8 Nov 2023 12:52:59 +0530 Subject: [PATCH 0349/7721] drm/i915/psr: Move psr specific dpcd init into own function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is preparing adding panel replay specific dpcd init. Cc: Arun R Murthy Cc: Jani Nikula Reviewed-by: Arun R Murthy Signed-off-by: Jouni Högander Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-3-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 41 +++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 3691f882e1c0..627d82164933 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -475,27 +475,22 @@ static void intel_dp_get_su_granularity(struct intel_dp *intel_dp) intel_dp->psr.su_y_granularity = y; } -void intel_psr_init_dpcd(struct intel_dp *intel_dp) +static void _psr_init_dpcd(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = + struct drm_i915_private *i915 = to_i915(dp_to_dig_port(intel_dp)->base.base.dev); - drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, - sizeof(intel_dp->psr_dpcd)); - - if (!intel_dp->psr_dpcd[0]) - return; - drm_dbg_kms(&dev_priv->drm, "eDP panel supports PSR version %x\n", + drm_dbg_kms(&i915->drm, "eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "PSR support not currently available for this panel\n"); return; } if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "Panel lacks power state control, PSR cannot be enabled\n"); return; } @@ -504,8 +499,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) intel_dp->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); - if (DISPLAY_VER(dev_priv) >= 9 && - (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { + if (DISPLAY_VER(i915) >= 9 && + intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { bool y_req = intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; bool alpm = intel_dp_get_alpm_status(intel_dp); @@ -522,14 +517,24 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * GTC first. */ intel_dp->psr.sink_psr2_support = y_req && alpm; - drm_dbg_kms(&dev_priv->drm, "PSR2 %ssupported\n", + drm_dbg_kms(&i915->drm, "PSR2 %ssupported\n", intel_dp->psr.sink_psr2_support ? "" : "not "); + } +} - if (intel_dp->psr.sink_psr2_support) { - intel_dp->psr.colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); - intel_dp_get_su_granularity(intel_dp); - } +void intel_psr_init_dpcd(struct intel_dp *intel_dp) +{ + drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, + sizeof(intel_dp->psr_dpcd)); + + if (intel_dp->psr_dpcd[0]) + _psr_init_dpcd(intel_dp); + /* TODO: Add PR case here */ + + if (intel_dp->psr.sink_psr2_support) { + intel_dp->psr.colorimetry_support = + intel_dp_get_colorimetry_status(intel_dp); + intel_dp_get_su_granularity(intel_dp); } } From b8cf5b5d266ec20e1ab90f38c8d779c669c2d219 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 8 Nov 2023 12:53:00 +0530 Subject: [PATCH 0350/7721] drm/i915/panelreplay: Initializaton and compute config for panel replay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify existing PSR implementation to enable panel replay feature of DP 2.0 which is similar to PSR feature of EDP panel. There is different DPCD address to check panel capability compare to PSR and vsc sdp header is different. v1: Initial version. v2: - Set source_panel_replay_support flag under HAS_PANEL_REPLAY() condition check. [Jouni] - Code restructured around intel_panel_replay_init and renamed to intel_panel_replay_init_dpcd. [Jouni] - Remove the initial code modification around has_psr2 flag. [Jouni] - Add CAN_PANEL_REPLAY() in intel_encoder_can_psr which is used to enable in intel_psr_post_plane_update. [Jouni] v3: - Initialize both psr and panel-replay. [Jouni] - Initialize both panel replay and psr if detected. [Jouni] - Refactoring psr function by introducing _psr_compute_config(). [Jouni] - Add check for !is_edp while deriving source_panel_replay_support. [Jouni] - Enable panel replay dpcd initialization in a separate patch. [Jouni] v4: - HAS_PANEL_REPLAY() check not needed during sink capability check. [Jouni] - Set either panel replay source support or psr. [Jouni] v5: - HAS_PANEL_REPLAY() removed and use HAS_DP20() instead. [Jouni] - Move psr related code to intel_psr.c. [Jani] - Reset sink_panel_replay_support flag during disconnection. [Jani] v6: return statement restored which is removed by misatke. [Jouni] v7: cosmetic changes. [Arun] Cc: Jouni Högander Cc: Arun R Murthy Cc: Jani Nikula Reviewed-by: Arun R Murthy Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-4-animesh.manna@intel.com --- .../drm/i915/display/intel_display_types.h | 14 +--- drivers/gpu/drm/i915/display/intel_dp.c | 49 +++++++++-- drivers/gpu/drm/i915/display/intel_dp_mst.c | 3 + drivers/gpu/drm/i915/display/intel_psr.c | 84 ++++++++++++++----- drivers/gpu/drm/i915/display/intel_psr.h | 7 ++ 5 files changed, 117 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 926bf9c1a3ed..c83132d9dff0 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1211,6 +1211,7 @@ struct intel_crtc_state { bool has_psr2; bool enable_psr2_sel_fetch; bool req_psr2_sdp_prior_scanline; + bool has_panel_replay; bool wm_level_disabled; u32 dc3co_exitline; u16 su_y_granularity; @@ -1708,6 +1709,8 @@ struct intel_psr { bool irq_aux_error; u16 su_w_granularity; u16 su_y_granularity; + bool source_panel_replay_support; + bool sink_panel_replay_support; u32 dc3co_exitline; u32 dc3co_exit_delay; struct delayed_work dc3co_work; @@ -1994,17 +1997,6 @@ dp_to_lspcon(struct intel_dp *intel_dp) #define dp_to_i915(__intel_dp) to_i915(dp_to_dig_port(__intel_dp)->base.base.dev) -#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ - (intel_dp)->psr.source_support) - -static inline bool intel_encoder_can_psr(struct intel_encoder *encoder) -{ - if (!intel_encoder_is_dp(encoder)) - return false; - - return CAN_PSR(enc_to_intel_dp(encoder)); -} - static inline struct intel_digital_port * hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 670cf535e7c6..03e520c43248 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2470,12 +2470,22 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - /* - * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118 - * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/ - * Colorimetry Format indication. - */ - vsc->revision = 0x5; + if (crtc_state->has_panel_replay) { + /* + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo, Panel Replay, and Pixel + * Encoding/Colorimetry Format indication. + */ + vsc->revision = 0x7; + } else { + /* + * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118 + * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/ + * Colorimetry Format indication. + */ + vsc->revision = 0x5; + } + vsc->length = 0x13; /* DP 1.4a spec, Table 2-120 */ @@ -2584,6 +2594,21 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, vsc->revision = 0x4; vsc->length = 0xe; } + } else if (crtc_state->has_panel_replay) { + if (intel_dp->psr.colorimetry_support && + intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { + /* [Panel Replay with colorimetry info] */ + intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, + vsc); + } else { + /* + * [Panel Replay without colorimetry info] + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo + Panel Replay. + */ + vsc->revision = 0x6; + vsc->length = 0x10; + } } else { /* * [PSR1] @@ -4052,11 +4077,16 @@ static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc, sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */ sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */ + if (vsc->revision == 0x6) { + sdp->db[0] = 1; + sdp->db[3] = 1; + } + /* - * Only revision 0x5 supports Pixel Encoding/Colorimetry Format as - * per DP 1.4a spec. + * Revision 0x5 and revision 0x7 supports Pixel Encoding/Colorimetry + * Format as per DP 1.4a spec and DP 2.0 respectively. */ - if (vsc->revision != 0x5) + if (!(vsc->revision == 0x5 || vsc->revision == 0x7)) goto out; /* VSC SDP Payload for DB16 through DB18 */ @@ -5603,6 +5633,7 @@ intel_dp_detect(struct drm_connector *connector, if (status == connector_status_disconnected) { memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance)); memset(intel_connector->dp.dsc_dpcd, 0, sizeof(intel_connector->dp.dsc_dpcd)); + intel_dp->psr.sink_panel_replay_support = false; if (intel_dp->is_mst) { drm_dbg_kms(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 107f7418ddc5..b943dbf394a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -44,6 +44,7 @@ #include "intel_hdcp.h" #include "intel_hotplug.h" #include "intel_link_bw.h" +#include "intel_psr.h" #include "intel_vdsc.h" #include "skl_scaler.h" @@ -592,6 +593,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_psr_compute_config(intel_dp, pipe_config, conn_state); + return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 627d82164933..3ffdeb451a83 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -173,6 +173,15 @@ * irrelevant for normal operation. */ +bool intel_encoder_can_psr(struct intel_encoder *encoder) +{ + if (intel_encoder_is_dp(encoder) || encoder->type == INTEL_OUTPUT_DP_MST) + return CAN_PSR(enc_to_intel_dp(encoder)) || + CAN_PANEL_REPLAY(enc_to_intel_dp(encoder)); + else + return false; +} + static bool psr_global_enabled(struct intel_dp *intel_dp) { struct intel_connector *connector = intel_dp->attached_connector; @@ -475,6 +484,25 @@ static void intel_dp_get_su_granularity(struct intel_dp *intel_dp) intel_dp->psr.su_y_granularity = y; } +static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u8 pr_dpcd = 0; + + intel_dp->psr.sink_panel_replay_support = false; + drm_dp_dpcd_readb(&intel_dp->aux, DP_PANEL_REPLAY_CAP, &pr_dpcd); + + if (!(pr_dpcd & DP_PANEL_REPLAY_SUPPORT)) { + drm_dbg_kms(&i915->drm, + "Panel replay is not supported by panel\n"); + return; + } + + drm_dbg_kms(&i915->drm, + "Panel replay is supported by panel\n"); + intel_dp->psr.sink_panel_replay_support = true; +} + static void _psr_init_dpcd(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = @@ -524,12 +552,13 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp) void intel_psr_init_dpcd(struct intel_dp *intel_dp) { + _panel_replay_init_dpcd(intel_dp); + drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, sizeof(intel_dp->psr_dpcd)); if (intel_dp->psr_dpcd[0]) _psr_init_dpcd(intel_dp); - /* TODO: Add PR case here */ if (intel_dp->psr.sink_psr2_support) { intel_dp->psr.colorimetry_support = @@ -1271,13 +1300,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } -void intel_psr_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static bool _psr_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; u8 entry_setup_frames; /* @@ -1285,10 +1312,30 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, * So if VRR is enabled, do not enable PSR. */ if (crtc_state->vrr.enable) - return; + return false; if (!CAN_PSR(intel_dp)) - return; + return false; + + entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode); + + if (entry_setup_frames >= 0) { + intel_dp->psr.entry_setup_frames = entry_setup_frames; + } else { + drm_dbg_kms(&dev_priv->drm, + "PSR condition failed: PSR setup timing not met\n"); + return false; + } + + return true; +} + +void intel_psr_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; if (!psr_global_enabled(intel_dp)) { drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n"); @@ -1307,17 +1354,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; } - entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode); + if (CAN_PANEL_REPLAY(intel_dp)) + crtc_state->has_panel_replay = true; + else + crtc_state->has_psr = _psr_compute_config(intel_dp, crtc_state); - if (entry_setup_frames >= 0) { - intel_dp->psr.entry_setup_frames = entry_setup_frames; - } else { - drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: PSR setup timing not met\n"); - return; - } - - crtc_state->has_psr = true; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); @@ -2750,7 +2791,7 @@ void intel_psr_init(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (!HAS_PSR(dev_priv)) + if (!(HAS_PSR(dev_priv) || HAS_DP20(dev_priv))) return; /* @@ -2768,7 +2809,10 @@ void intel_psr_init(struct intel_dp *intel_dp) return; } - intel_dp->psr.source_support = true; + if (HAS_DP20(dev_priv) && !intel_dp_is_edp(intel_dp)) + intel_dp->psr.source_panel_replay_support = true; + else + intel_dp->psr.source_support = true; /* Set link_standby x link_off defaults */ if (DISPLAY_VER(dev_priv) < 12) diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index bf35f42df6bc..6a1f4573852b 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -21,6 +21,13 @@ struct intel_encoder; struct intel_plane; struct intel_plane_state; +#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ + (intel_dp)->psr.source_support) + +#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \ + (intel_dp)->psr.source_panel_replay_support) + +bool intel_encoder_can_psr(struct intel_encoder *encoder); void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc); From cceeaa312d390e4f8407c056ae27ba7edd50307e Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 8 Nov 2023 12:53:01 +0530 Subject: [PATCH 0351/7721] drm/i915/panelreplay: Enable panel replay dpcd initialization for DP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to similarity panel replay dpcd initialization got added in psr function which is specific for edp panel. This patch enables panel replay initialization for dp connector. Cc: Jouni Högander Cc: Arun R Murthy Cc: Jani Nikula Reviewed-by: Arun R Murthy Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-5-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 3ffdeb451a83..3c25c8d85803 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2794,6 +2794,9 @@ void intel_psr_init(struct intel_dp *intel_dp) if (!(HAS_PSR(dev_priv) || HAS_DP20(dev_priv))) return; + if (!intel_dp_is_edp(intel_dp)) + intel_psr_init_dpcd(intel_dp); + /* * HSW spec explicitly says PSR is tied to port A. * BDW+ platforms have a instance of PSR registers per transcoder but From 3257e55d3ea7e35ea76ff6ae07347b803f068068 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 8 Nov 2023 12:53:02 +0530 Subject: [PATCH 0352/7721] drm/i915/panelreplay: enable/disable panel replay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TRANS_DP2_CTL register is programmed to enable panel replay from source and sink is enabled through panel replay dpcd configuration address. Bspec: 1407940617 v1: Initial version. v2: - Use pr_* flags instead psr_* flags. [Jouni] - Remove intel_dp_is_edp check as edp1.5 also has panel replay. [Jouni] v3: Cover letter updated and selective fetch condition check is added before updating its bit in PSR2_MAN_TRK_CTL register. [Jouni] v4: Selective fetch related PSR2_MAN_TRK_CTL programmming dropped. [Jouni] v5: Added PSR2_MAN_TRK_CTL programming as needed for Continuous Full Frame (CFF) update. v6: Rebased on latest. Note: Initial plan is to enable panel replay in full-screen live active frame update mode. In a incremental approach panel replay will be enabled in selctive update mode if there is any gap in curent implementation. Cc: Jouni Högander Cc: Arun R Murthy Cc: Jani Nikula Reviewed-by: Arun R Murthy Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-6-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 7 ++- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 63 ++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 6cec72ac6422..0712a5200ad3 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2800,10 +2800,15 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - if (HAS_DP20(dev_priv)) + if (HAS_DP20(dev_priv)) { intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder), crtc_state); + if (crtc_state->has_panel_replay) + drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, + DP_PANEL_REPLAY_ENABLE); + } if (DISPLAY_VER(dev_priv) >= 14) mtl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c83132d9dff0..d2a15817dee2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1711,6 +1711,7 @@ struct intel_psr { u16 su_y_granularity; bool source_panel_replay_support; bool sink_panel_replay_support; + bool panel_replay_enabled; u32 dc3co_exitline; u32 dc3co_exit_delay; struct delayed_work dc3co_work; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 3c25c8d85803..ea292832ca47 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -609,8 +609,11 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 dpcd_val = DP_PSR_ENABLE; - /* Enable ALPM at sink for psr2 */ + if (intel_dp->psr.panel_replay_enabled) + return; + if (intel_dp->psr.psr2_enabled) { + /* Enable ALPM at sink for psr2 */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE); @@ -783,6 +786,17 @@ static u8 frames_before_su_entry(struct intel_dp *intel_dp) return frames_before_su_entry; } +static void dg2_activate_panel_replay(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + intel_de_rmw(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), + 0, ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME); + + intel_de_rmw(dev_priv, TRANS_DP2_CTL(intel_dp->psr.transcoder), 0, + TRANS_DP2_PANEL_REPLAY_ENABLE); +} + static void hsw_activate_psr2(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -1379,18 +1393,23 @@ void intel_psr_get_config(struct intel_encoder *encoder, return; intel_dp = &dig_port->dp; - if (!CAN_PSR(intel_dp)) + if (!(CAN_PSR(intel_dp) || CAN_PANEL_REPLAY(intel_dp))) return; mutex_lock(&intel_dp->psr.lock); if (!intel_dp->psr.enabled) goto unlock; - /* - * Not possible to read EDP_PSR/PSR2_CTL registers as it is - * enabled/disabled because of frontbuffer tracking and others. - */ - pipe_config->has_psr = true; + if (intel_dp->psr.panel_replay_enabled) { + pipe_config->has_panel_replay = true; + } else { + /* + * Not possible to read EDP_PSR/PSR2_CTL registers as it is + * enabled/disabled because of frontbuffer tracking and others. + */ + pipe_config->has_psr = true; + } + pipe_config->has_psr2 = intel_dp->psr.psr2_enabled; pipe_config->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); @@ -1427,8 +1446,10 @@ static void intel_psr_activate(struct intel_dp *intel_dp) lockdep_assert_held(&intel_dp->psr.lock); - /* psr1 and psr2 are mutually exclusive.*/ - if (intel_dp->psr.psr2_enabled) + /* psr1, psr2 and panel-replay are mutually exclusive.*/ + if (intel_dp->psr.panel_replay_enabled) + dg2_activate_panel_replay(intel_dp); + else if (intel_dp->psr.psr2_enabled) hsw_activate_psr2(intel_dp); else hsw_activate_psr1(intel_dp); @@ -1606,6 +1627,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled); intel_dp->psr.psr2_enabled = crtc_state->has_psr2; + intel_dp->psr.panel_replay_enabled = crtc_state->has_panel_replay; intel_dp->psr.busy_frontbuffer_bits = 0; intel_dp->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; intel_dp->psr.transcoder = crtc_state->cpu_transcoder; @@ -1621,8 +1643,12 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, if (!psr_interrupt_error_check(intel_dp)) return; - drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", - intel_dp->psr.psr2_enabled ? "2" : "1"); + if (intel_dp->psr.panel_replay_enabled) + drm_dbg_kms(&dev_priv->drm, "Enabling Panel Replay\n"); + else + drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", + intel_dp->psr.psr2_enabled ? "2" : "1"); + intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); @@ -1651,7 +1677,10 @@ static void intel_psr_exit(struct intel_dp *intel_dp) return; } - if (intel_dp->psr.psr2_enabled) { + if (intel_dp->psr.panel_replay_enabled) { + intel_de_rmw(dev_priv, TRANS_DP2_CTL(intel_dp->psr.transcoder), + TRANS_DP2_PANEL_REPLAY_ENABLE, 0); + } else if (intel_dp->psr.psr2_enabled) { tgl_disallow_dc3co_on_psr2_exit(intel_dp); val = intel_de_rmw(dev_priv, EDP_PSR2_CTL(cpu_transcoder), @@ -1700,8 +1729,11 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) if (!intel_dp->psr.enabled) return; - drm_dbg_kms(&dev_priv->drm, "Disabling PSR%s\n", - intel_dp->psr.psr2_enabled ? "2" : "1"); + if (intel_dp->psr.panel_replay_enabled) + drm_dbg_kms(&dev_priv->drm, "Disabling Panel Replay\n"); + else + drm_dbg_kms(&dev_priv->drm, "Disabling PSR%s\n", + intel_dp->psr.psr2_enabled ? "2" : "1"); intel_psr_exit(intel_dp); intel_psr_wait_exit_locked(intel_dp); @@ -1734,6 +1766,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, 0); intel_dp->psr.enabled = false; + intel_dp->psr.panel_replay_enabled = false; intel_dp->psr.psr2_enabled = false; intel_dp->psr.psr2_sel_fetch_enabled = false; intel_dp->psr.psr2_sel_fetch_cff_enabled = false; @@ -2305,7 +2338,7 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder; - if (!crtc_state->has_psr) + if (!(crtc_state->has_psr || crtc_state->has_panel_replay)) return; for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, From e4ae85e364fc652ea15d85b0f3a6da304c9b5ce7 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:01 +0000 Subject: [PATCH 0353/7721] drm/i915: Add ability for tracking buffer objects per client In order to show per client memory usage lets add some infrastructure which enables tracking buffer objects owned by clients. We add a per client list protected by a new per client lock and to support delayed destruction (post client exit) we make tracked objects hold references to the owning client. Also, object memory region teardown is moved to the existing RCU free callback to allow safe dereference from the fdinfo RCU read section. Signed-off-by: Tvrtko Ursulin Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 13 +++++-- .../gpu/drm/i915/gem/i915_gem_object_types.h | 12 +++++++ drivers/gpu/drm/i915/i915_drm_client.c | 36 +++++++++++++++++++ drivers/gpu/drm/i915/i915_drm_client.h | 32 +++++++++++++++++ 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index c26d87555825..25eeeb863209 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -106,6 +106,10 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, INIT_LIST_HEAD(&obj->mm.link); +#ifdef CONFIG_PROC_FS + INIT_LIST_HEAD(&obj->client_link); +#endif + INIT_LIST_HEAD(&obj->lut_list); spin_lock_init(&obj->lut_lock); @@ -293,6 +297,10 @@ void __i915_gem_free_object_rcu(struct rcu_head *head) container_of(head, typeof(*obj), rcu); struct drm_i915_private *i915 = to_i915(obj->base.dev); + /* We need to keep this alive for RCU read access from fdinfo. */ + if (obj->mm.n_placements > 1) + kfree(obj->mm.placements); + i915_gem_object_free(obj); GEM_BUG_ON(!atomic_read(&i915->mm.free_count)); @@ -389,9 +397,6 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj) if (obj->ops->release) obj->ops->release(obj); - if (obj->mm.n_placements > 1) - kfree(obj->mm.placements); - if (obj->shares_resv_from) i915_vm_resv_put(obj->shares_resv_from); @@ -442,6 +447,8 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj) GEM_BUG_ON(i915_gem_object_is_framebuffer(obj)); + i915_drm_client_remove_object(obj); + /* * Before we free the object, make sure any pure RCU-only * read-side critical sections are complete, e.g. diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 2292404007c8..0c5cdab278b6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -302,6 +302,18 @@ struct drm_i915_gem_object { */ struct i915_address_space *shares_resv_from; +#ifdef CONFIG_PROC_FS + /** + * @client: @i915_drm_client which created the object + */ + struct i915_drm_client *client; + + /** + * @client_link: Link into @i915_drm_client.objects_list + */ + struct list_head client_link; +#endif + union { struct rcu_head rcu; struct llist_node freed; diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index 2a44b3876cb5..2e5e69edc0f9 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -28,6 +28,10 @@ struct i915_drm_client *i915_drm_client_alloc(void) kref_init(&client->kref); spin_lock_init(&client->ctx_lock); INIT_LIST_HEAD(&client->ctx_list); +#ifdef CONFIG_PROC_FS + spin_lock_init(&client->objects_lock); + INIT_LIST_HEAD(&client->objects_list); +#endif return client; } @@ -108,4 +112,36 @@ void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file) for (i = 0; i < ARRAY_SIZE(uabi_class_names); i++) show_client_class(p, i915, file_priv->client, i); } + +void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj) +{ + unsigned long flags; + + GEM_WARN_ON(obj->client); + GEM_WARN_ON(!list_empty(&obj->client_link)); + + spin_lock_irqsave(&client->objects_lock, flags); + obj->client = i915_drm_client_get(client); + list_add_tail_rcu(&obj->client_link, &client->objects_list); + spin_unlock_irqrestore(&client->objects_lock, flags); +} + +bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +{ + struct i915_drm_client *client = fetch_and_zero(&obj->client); + unsigned long flags; + + /* Object may not be associated with a client. */ + if (!client) + return false; + + spin_lock_irqsave(&client->objects_lock, flags); + list_del_rcu(&obj->client_link); + spin_unlock_irqrestore(&client->objects_lock, flags); + + i915_drm_client_put(client); + + return true; +} #endif diff --git a/drivers/gpu/drm/i915/i915_drm_client.h b/drivers/gpu/drm/i915/i915_drm_client.h index 67816c912bca..5f58fdf7dcb8 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.h +++ b/drivers/gpu/drm/i915/i915_drm_client.h @@ -12,6 +12,9 @@ #include +#include "i915_file_private.h" +#include "gem/i915_gem_object_types.h" + #define I915_LAST_UABI_ENGINE_CLASS I915_ENGINE_CLASS_COMPUTE struct drm_file; @@ -25,6 +28,20 @@ struct i915_drm_client { spinlock_t ctx_lock; /* For add/remove from ctx_list. */ struct list_head ctx_list; /* List of contexts belonging to client. */ +#ifdef CONFIG_PROC_FS + /** + * @objects_lock: lock protecting @objects_list + */ + spinlock_t objects_lock; + + /** + * @objects_list: list of objects created by this client + * + * Protected by @objects_lock. + */ + struct list_head objects_list; +#endif + /** * @past_runtime: Accumulation of pphwsp runtimes from closed contexts. */ @@ -49,4 +66,19 @@ struct i915_drm_client *i915_drm_client_alloc(void); void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file); +#ifdef CONFIG_PROC_FS +void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj); +bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj); +#else +static inline void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj) +{ +} + +static inline bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +{ +} +#endif + #endif /* !__I915_DRM_CLIENT_H__ */ From ca02a0119f814b792484cba0c148fba292327ed6 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:02 +0000 Subject: [PATCH 0354/7721] drm/i915: Record which client owns a VM To enable accounting of indirect client memory usage (such as page tables) in the following patch, lets start recording the creator of each PPGTT. Signed-off-by: Tvrtko Ursulin Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 11 ++++++++--- drivers/gpu/drm/i915/gem/i915_gem_context_types.h | 3 +++ drivers/gpu/drm/i915/gem/selftests/mock_context.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_gtt.h | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index e38f06a6e56e..dcbfe32fd30c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -279,7 +279,8 @@ static int proto_context_set_protected(struct drm_i915_private *i915, } static struct i915_gem_proto_context * -proto_context_create(struct drm_i915_private *i915, unsigned int flags) +proto_context_create(struct drm_i915_file_private *fpriv, + struct drm_i915_private *i915, unsigned int flags) { struct i915_gem_proto_context *pc, *err; @@ -287,6 +288,7 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags) if (!pc) return ERR_PTR(-ENOMEM); + pc->fpriv = fpriv; pc->num_user_engines = -1; pc->user_engines = NULL; pc->user_flags = BIT(UCONTEXT_BANNABLE) | @@ -1622,6 +1624,7 @@ i915_gem_create_context(struct drm_i915_private *i915, err = PTR_ERR(ppgtt); goto err_ctx; } + ppgtt->vm.fpriv = pc->fpriv; vm = &ppgtt->vm; } if (vm) @@ -1741,7 +1744,7 @@ int i915_gem_context_open(struct drm_i915_private *i915, /* 0 reserved for invalid/unassigned ppgtt */ xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1); - pc = proto_context_create(i915, 0); + pc = proto_context_create(file_priv, i915, 0); if (IS_ERR(pc)) { err = PTR_ERR(pc); goto err; @@ -1823,6 +1826,7 @@ int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data, GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */ args->vm_id = id; + ppgtt->vm.fpriv = file_priv; return 0; err_put: @@ -2285,7 +2289,8 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, return -EIO; } - ext_data.pc = proto_context_create(i915, args->flags); + ext_data.pc = proto_context_create(file->driver_priv, i915, + args->flags); if (IS_ERR(ext_data.pc)) return PTR_ERR(ext_data.pc); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h index cb78214a7dcd..c573c067779f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h @@ -188,6 +188,9 @@ struct i915_gem_proto_engine { * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE. */ struct i915_gem_proto_context { + /** @fpriv: Client which creates the context */ + struct drm_i915_file_private *fpriv; + /** @vm: See &i915_gem_context.vm */ struct i915_address_space *vm; diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c index e199d7dbb876..2b0327cc47c2 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c @@ -83,7 +83,7 @@ live_context(struct drm_i915_private *i915, struct file *file) int err; u32 id; - pc = proto_context_create(i915, 0); + pc = proto_context_create(fpriv, i915, 0); if (IS_ERR(pc)) return ERR_CAST(pc); @@ -152,7 +152,7 @@ kernel_context(struct drm_i915_private *i915, struct i915_gem_context *ctx; struct i915_gem_proto_context *pc; - pc = proto_context_create(i915, 0); + pc = proto_context_create(NULL, i915, 0); if (IS_ERR(pc)) return ERR_CAST(pc); diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index 028a5a988eea..6b85222ee3ea 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -255,6 +255,7 @@ struct i915_address_space { } rsvd; struct intel_gt *gt; struct drm_i915_private *i915; + struct drm_i915_file_private *fpriv; struct device *dma; u64 total; /* size addr space maps (ex. 2GB for ggtt) */ u64 reserved; /* size addr space reserved */ From 978e1a52ca1f0228eccc51ad5ed3a118bac1ad1c Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:03 +0000 Subject: [PATCH 0355/7721] drm/i915: Track page table backing store usage Account page table backing store against the owning client memory usage stats. Signed-off-by: Tvrtko Ursulin Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-3-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_gtt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 21719563a602..86f73fe558ca 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -63,6 +63,9 @@ struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz) if (!IS_ERR(obj)) { obj->base.resv = i915_vm_resv_get(vm); obj->shares_resv_from = vm; + + if (vm->fpriv) + i915_drm_client_add_object(vm->fpriv->client, obj); } return obj; @@ -84,6 +87,9 @@ struct drm_i915_gem_object *alloc_pt_dma(struct i915_address_space *vm, int sz) if (!IS_ERR(obj)) { obj->base.resv = i915_vm_resv_get(vm); obj->shares_resv_from = vm; + + if (vm->fpriv) + i915_drm_client_add_object(vm->fpriv->client, obj); } return obj; From dc1a2775070f0618b661500310b2ea8643592ed1 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:04 +0000 Subject: [PATCH 0356/7721] drm/i915: Account ring buffer and context state storage Account ring buffers and logical context space against the owning client memory usage stats. Signed-off-by: Tvrtko Ursulin Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-4-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 14 ++++++++++++++ drivers/gpu/drm/i915/i915_drm_client.c | 10 ++++++++++ drivers/gpu/drm/i915/i915_drm_client.h | 9 +++++++++ 3 files changed, 33 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index a53b26178f0a..a2f1245741bb 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -6,6 +6,7 @@ #include "gem/i915_gem_context.h" #include "gem/i915_gem_pm.h" +#include "i915_drm_client.h" #include "i915_drv.h" #include "i915_trace.h" @@ -50,6 +51,7 @@ intel_context_create(struct intel_engine_cs *engine) int intel_context_alloc_state(struct intel_context *ce) { + struct i915_gem_context *ctx; int err = 0; if (mutex_lock_interruptible(&ce->pin_mutex)) @@ -66,6 +68,18 @@ int intel_context_alloc_state(struct intel_context *ce) goto unlock; set_bit(CONTEXT_ALLOC_BIT, &ce->flags); + + rcu_read_lock(); + ctx = rcu_dereference(ce->gem_context); + if (ctx && !kref_get_unless_zero(&ctx->ref)) + ctx = NULL; + rcu_read_unlock(); + if (ctx) { + if (ctx->client) + i915_drm_client_add_context_objects(ctx->client, + ce); + i915_gem_context_put(ctx); + } } unlock: diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index 2e5e69edc0f9..a61356012df8 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -144,4 +144,14 @@ bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) return true; } + +void i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce) +{ + if (ce->state) + i915_drm_client_add_object(client, ce->state->obj); + + if (ce->ring != ce->engine->legacy.ring && ce->ring->vma) + i915_drm_client_add_object(client, ce->ring->vma->obj); +} #endif diff --git a/drivers/gpu/drm/i915/i915_drm_client.h b/drivers/gpu/drm/i915/i915_drm_client.h index 5f58fdf7dcb8..69cedfcd3d69 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.h +++ b/drivers/gpu/drm/i915/i915_drm_client.h @@ -14,6 +14,7 @@ #include "i915_file_private.h" #include "gem/i915_gem_object_types.h" +#include "gt/intel_context_types.h" #define I915_LAST_UABI_ENGINE_CLASS I915_ENGINE_CLASS_COMPUTE @@ -70,6 +71,8 @@ void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file); void i915_drm_client_add_object(struct i915_drm_client *client, struct drm_i915_gem_object *obj); bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj); +void i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce); #else static inline void i915_drm_client_add_object(struct i915_drm_client *client, struct drm_i915_gem_object *obj) @@ -79,6 +82,12 @@ static inline void i915_drm_client_add_object(struct i915_drm_client *client, static inline bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) { } + +static inline void +i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce) +{ +} #endif #endif /* !__I915_DRM_CLIENT_H__ */ From 3b38d35157530c12c84fc02cccd469b9a0a00ae7 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:05 +0000 Subject: [PATCH 0357/7721] drm/i915: Add stable memory region names At the moment memory region names are a bit too varied and too inconsistent to be used for ABI purposes, like for upcoming fdinfo memory stats. System memory can be either system or system-ttm. Local memory has the instance number appended, others do not. Not only incosistent but thi kind of implementation detail is uninteresting for intended users of fdinfo memory stats. Add a stable name always formed as $type$instance. Could have chosen a different stable scheme, but I think any consistent and stable scheme should do just fine. Signed-off-by: Tvrtko Ursulin Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-5-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_memory_region.c | 19 +++++++++++++++++++ drivers/gpu/drm/i915/intel_memory_region.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 3d1fdea9811d..60a03340bbd4 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -216,6 +216,22 @@ static int intel_memory_region_memtest(struct intel_memory_region *mem, return err; } +static const char *region_type_str(u16 type) +{ + switch (type) { + case INTEL_MEMORY_SYSTEM: + return "system"; + case INTEL_MEMORY_LOCAL: + return "local"; + case INTEL_MEMORY_STOLEN_LOCAL: + return "stolen-local"; + case INTEL_MEMORY_STOLEN_SYSTEM: + return "stolen-system"; + default: + return "unknown"; + } +} + struct intel_memory_region * intel_memory_region_create(struct drm_i915_private *i915, resource_size_t start, @@ -244,6 +260,9 @@ intel_memory_region_create(struct drm_i915_private *i915, mem->type = type; mem->instance = instance; + snprintf(mem->uabi_name, sizeof(mem->uabi_name), "%s%u", + region_type_str(type), instance); + mutex_init(&mem->objects.lock); INIT_LIST_HEAD(&mem->objects.list); diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index 2953ed5c3248..9ba36454e51b 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -80,6 +80,7 @@ struct intel_memory_region { u16 instance; enum intel_region_id id; char name[16]; + char uabi_name[16]; bool private; /* not for userspace */ struct { From 968853033d8aa4dbb80fbafa6f5d9b6a0ea21272 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 7 Nov 2023 10:18:06 +0000 Subject: [PATCH 0358/7721] drm/i915: Implement fdinfo memory stats printing Use the newly added drm_print_memory_stats helper to show memory utilisation of our objects in drm/driver specific fdinfo output. To collect the stats we walk the per memory regions object lists and accumulate object size into the respective drm_memory_stats categories. v2: * Only account against the active region. * Use DMA_RESV_USAGE_BOOKKEEP when testing for active. (Tejas) v3: * Update commit text. (Aravind) * Update to use memory regions uabi names. Signed-off-by: Tvrtko Ursulin Cc: Aravind Iddamsetty Cc: Rob Clark Cc: Andi Shyti Cc: Tejas Upadhyay Reviewed-by: Andi Shyti Reviewed-by: Aravind Iddamsetty Link: https://patchwork.freedesktop.org/patch/msgid/20231107101806.608990-6-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_drm_client.c | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index a61356012df8..7efffdaa508d 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -45,6 +45,68 @@ void __i915_drm_client_free(struct kref *kref) } #ifdef CONFIG_PROC_FS +static void +obj_meminfo(struct drm_i915_gem_object *obj, + struct drm_memory_stats stats[INTEL_REGION_UNKNOWN]) +{ + const enum intel_region_id id = obj->mm.region ? + obj->mm.region->id : INTEL_REGION_SMEM; + const u64 sz = obj->base.size; + + if (obj->base.handle_count > 1) + stats[id].shared += sz; + else + stats[id].private += sz; + + if (i915_gem_object_has_pages(obj)) { + stats[id].resident += sz; + + if (!dma_resv_test_signaled(obj->base.resv, + DMA_RESV_USAGE_BOOKKEEP)) + stats[id].active += sz; + else if (i915_gem_object_is_shrinkable(obj) && + obj->mm.madv == I915_MADV_DONTNEED) + stats[id].purgeable += sz; + } +} + +static void show_meminfo(struct drm_printer *p, struct drm_file *file) +{ + struct drm_memory_stats stats[INTEL_REGION_UNKNOWN] = {}; + struct drm_i915_file_private *fpriv = file->driver_priv; + struct i915_drm_client *client = fpriv->client; + struct drm_i915_private *i915 = fpriv->i915; + struct drm_i915_gem_object *obj; + struct intel_memory_region *mr; + struct list_head *pos; + unsigned int id; + + /* Public objects. */ + spin_lock(&file->table_lock); + idr_for_each_entry(&file->object_idr, obj, id) + obj_meminfo(obj, stats); + spin_unlock(&file->table_lock); + + /* Internal objects. */ + rcu_read_lock(); + list_for_each_rcu(pos, &client->objects_list) { + obj = i915_gem_object_get_rcu(list_entry(pos, typeof(*obj), + client_link)); + if (!obj) + continue; + obj_meminfo(obj, stats); + i915_gem_object_put(obj); + } + rcu_read_unlock(); + + for_each_memory_region(mr, i915, id) + drm_print_memory_stats(p, + &stats[id], + DRM_GEM_OBJECT_RESIDENT | + DRM_GEM_OBJECT_PURGEABLE, + mr->uabi_name); +} + static const char * const uabi_class_names[] = { [I915_ENGINE_CLASS_RENDER] = "render", [I915_ENGINE_CLASS_COPY] = "copy", @@ -106,6 +168,8 @@ void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file) * ****************************************************************** */ + show_meminfo(p, file); + if (GRAPHICS_VER(i915) < 8) return; From 22aa1a209018dc2eca78745f7666db63637cd5dc Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 2 Nov 2023 15:15:07 +0100 Subject: [PATCH 0359/7721] drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off() The layout of the registers {TILER,SHADER,L2}_PWROFF_LO, used to request powering off cores, is the same as the {TILER,SHADER,L2}_PWRON_LO ones: this means that in order to request poweroff of cores, we are supposed to write a bitmask of cores that should be powered off! This means that the panfrost_gpu_power_off() function has always been doing nothing. Fix powering off the GPU by writing a bitmask of the cores to poweroff to the relevant PWROFF_LO registers and then check that the transition (from ON to OFF) has finished by polling the relevant PWRTRANS_LO registers. While at it, in order to avoid code duplication, move the core mask logic from panfrost_gpu_power_on() to a new panfrost_get_core_mask() function, used in both poweron and poweroff. Fixes: f3ba91228e8e ("drm/panfrost: Add initial panfrost driver") Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231102141507.73481-1-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 64 ++++++++++++++++++------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index f0be7e19b13e..97f097ee5c1d 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -362,28 +362,38 @@ unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev) return ((u64)hi << 32) | lo; } +static u64 panfrost_get_core_mask(struct panfrost_device *pfdev) +{ + u64 core_mask; + + if (pfdev->features.l2_present == 1) + return U64_MAX; + + /* + * Only support one core group now. + * ~(l2_present - 1) unsets all bits in l2_present except + * the bottom bit. (l2_present - 2) has all the bits in + * the first core group set. AND them together to generate + * a mask of cores in the first core group. + */ + core_mask = ~(pfdev->features.l2_present - 1) & + (pfdev->features.l2_present - 2); + dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", + hweight64(core_mask), + hweight64(pfdev->features.shader_present)); + + return core_mask; +} + void panfrost_gpu_power_on(struct panfrost_device *pfdev) { int ret; u32 val; - u64 core_mask = U64_MAX; + u64 core_mask; panfrost_gpu_init_quirks(pfdev); + core_mask = panfrost_get_core_mask(pfdev); - if (pfdev->features.l2_present != 1) { - /* - * Only support one core group now. - * ~(l2_present - 1) unsets all bits in l2_present except - * the bottom bit. (l2_present - 2) has all the bits in - * the first core group set. AND them together to generate - * a mask of cores in the first core group. - */ - core_mask = ~(pfdev->features.l2_present - 1) & - (pfdev->features.l2_present - 2); - dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", - hweight64(core_mask), - hweight64(pfdev->features.shader_present)); - } gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask); ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, val, val == (pfdev->features.l2_present & core_mask), @@ -408,9 +418,27 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) void panfrost_gpu_power_off(struct panfrost_device *pfdev) { - gpu_write(pfdev, TILER_PWROFF_LO, 0); - gpu_write(pfdev, SHADER_PWROFF_LO, 0); - gpu_write(pfdev, L2_PWROFF_LO, 0); + u64 core_mask = panfrost_get_core_mask(pfdev); + int ret; + u32 val; + + gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present & core_mask); + ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO, + val, !val, 1, 1000); + if (ret) + dev_err(pfdev->dev, "shader power transition timeout"); + + gpu_write(pfdev, TILER_PWROFF_LO, pfdev->features.tiler_present); + ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_PWRTRANS_LO, + val, !val, 1, 1000); + if (ret) + dev_err(pfdev->dev, "tiler power transition timeout"); + + gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present & core_mask); + ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO, + val, !val, 0, 1000); + if (ret) + dev_err(pfdev->dev, "l2 power transition timeout"); } int panfrost_gpu_init(struct panfrost_device *pfdev) From 57d4e26717b030fd794df3534e6b2e806eb761e4 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:38 +0100 Subject: [PATCH 0360/7721] drm/panfrost: Perform hard reset to recover GPU if soft reset fails Even though soft reset should ideally never fail, during development of some power management features I managed to get some bits wrong: this resulted in GPU soft reset failures, where the GPU was never able to recover, not even after suspend/resume cycles, meaning that the only way to get functionality back was to reboot the machine. Perform a hard reset after a soft reset failure to be able to recover the GPU during runtime (so, without any machine reboot). Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-2-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 13 ++++++++++--- drivers/gpu/drm/panfrost/panfrost_regs.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 97f097ee5c1d..c9469bf7770a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -60,14 +60,21 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_INT_MASK, 0); gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); - gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); + gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); if (ret) { - dev_err(pfdev->dev, "gpu soft reset timed out\n"); - return ret; + dev_err(pfdev->dev, "gpu soft reset timed out, attempting hard reset\n"); + + gpu_write(pfdev, GPU_CMD, GPU_CMD_HARD_RESET); + ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, val, + val & GPU_IRQ_RESET_COMPLETED, 100, 10000); + if (ret) { + dev_err(pfdev->dev, "gpu hard reset timed out\n"); + return ret; + } } gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index 55ec807550b3..c25743b05c55 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -44,6 +44,7 @@ GPU_IRQ_MULTIPLE_FAULT) #define GPU_CMD 0x30 #define GPU_CMD_SOFT_RESET 0x01 +#define GPU_CMD_HARD_RESET 0x02 #define GPU_CMD_PERFCNT_CLEAR 0x03 #define GPU_CMD_PERFCNT_SAMPLE 0x04 #define GPU_CMD_CYCLE_COUNT_START 0x05 From 4d74420ffcf4c99165908f058066dd242813dc75 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:39 +0100 Subject: [PATCH 0361/7721] drm/panfrost: Tighten polling for soft reset and power on In many cases, soft reset takes more than 1 microsecond, but definitely less than 10; moreover in the poweron flow, tilers, shaders and l2 will become ready (each) in less than 10 microseconds as well. Even in the cases (at least on my platforms, rarely) in which those take more than 10 microseconds, it's very unlikely to see both soft reset and poweron to take more than 70 microseconds. Shorten the polling delay to 10 microseconds to consistently reduce the runtime resume time of the GPU. As an indicative example, measurements taken on a MediaTek MT8195 SoC Average runtime resume time in nanoseconds before this commit: GDM, user selection up/down: 88435ns GDM, Text Entry (typing user/password): 91489ns GNOME Desktop, idling, GKRELLM running: 73200ns After this commit: GDM: user selection up/down: 26690ns GDM: Text Entry (typing user/password): 27917ns GNOME Desktop, idling, GKRELLM running: 25304ns Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-3-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index c9469bf7770a..09f5e1563ebd 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -63,7 +63,7 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, - val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); + val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000); if (ret) { dev_err(pfdev->dev, "gpu soft reset timed out, attempting hard reset\n"); @@ -404,7 +404,7 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask); ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, val, val == (pfdev->features.l2_present & core_mask), - 100, 20000); + 10, 20000); if (ret) dev_err(pfdev->dev, "error powering up gpu L2"); @@ -412,13 +412,13 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) pfdev->features.shader_present & core_mask); ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, val, val == (pfdev->features.shader_present & core_mask), - 100, 20000); + 10, 20000); if (ret) dev_err(pfdev->dev, "error powering up gpu shader"); gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present); ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO, - val, val == pfdev->features.tiler_present, 100, 1000); + val, val == pfdev->features.tiler_present, 10, 1000); if (ret) dev_err(pfdev->dev, "error powering up gpu tiler"); } From 56e76c0179185568049913257c18069293f8bde9 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:40 +0100 Subject: [PATCH 0362/7721] drm/panfrost: Implement ability to turn on/off GPU clocks in suspend Currently, the GPU is being internally powered off for runtime suspend and turned back on for runtime resume through commands sent to it, but note that the GPU doesn't need to be clocked during the poweroff state, hence it is possible to save some power on selected platforms. Add suspend and resume handlers for full system sleep and then add a new panfrost_gpu_pm enumeration and a pm_features variable in the panfrost_compatible structure: BIT(GPU_PM_CLK_DIS) will be used to enable this power saving technique only on SoCs that are able to safely use it. Note that this was implemented only for the system sleep case and not for runtime PM because testing on one of my MediaTek platforms showed issues when turning on and off clocks aggressively (in PM runtime) resulting in a full system lockup. Doing this only for full system sleep never showed issues during my testing by suspending and resuming the system continuously for more than 100 cycles. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-4-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_device.c | 61 ++++++++++++++++++++-- drivers/gpu/drm/panfrost/panfrost_device.h | 11 ++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index 28f7046e1b1a..b4ddbc3b8069 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -403,7 +403,7 @@ void panfrost_device_reset(struct panfrost_device *pfdev) panfrost_job_enable_interrupts(pfdev); } -static int panfrost_device_resume(struct device *dev) +static int panfrost_device_runtime_resume(struct device *dev) { struct panfrost_device *pfdev = dev_get_drvdata(dev); @@ -413,7 +413,7 @@ static int panfrost_device_resume(struct device *dev) return 0; } -static int panfrost_device_suspend(struct device *dev) +static int panfrost_device_runtime_suspend(struct device *dev) { struct panfrost_device *pfdev = dev_get_drvdata(dev); @@ -426,5 +426,58 @@ static int panfrost_device_suspend(struct device *dev) return 0; } -EXPORT_GPL_RUNTIME_DEV_PM_OPS(panfrost_pm_ops, panfrost_device_suspend, - panfrost_device_resume, NULL); +static int panfrost_device_resume(struct device *dev) +{ + struct panfrost_device *pfdev = dev_get_drvdata(dev); + int ret; + + if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) { + ret = clk_enable(pfdev->clock); + if (ret) + return ret; + + if (pfdev->bus_clock) { + ret = clk_enable(pfdev->bus_clock); + if (ret) + goto err_bus_clk; + } + } + + ret = pm_runtime_force_resume(dev); + if (ret) + goto err_resume; + + return 0; + +err_resume: + if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS) && pfdev->bus_clock) + clk_disable(pfdev->bus_clock); +err_bus_clk: + if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) + clk_disable(pfdev->clock); + return ret; +} + +static int panfrost_device_suspend(struct device *dev) +{ + struct panfrost_device *pfdev = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) { + if (pfdev->bus_clock) + clk_disable(pfdev->bus_clock); + + clk_disable(pfdev->clock); + } + + return 0; +} + +EXPORT_GPL_DEV_PM_OPS(panfrost_pm_ops) = { + RUNTIME_PM_OPS(panfrost_device_runtime_suspend, panfrost_device_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(panfrost_device_suspend, panfrost_device_resume) +}; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 1e85656dc2f7..32453b97c39c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -25,6 +25,14 @@ struct panfrost_perfcnt; #define NUM_JOB_SLOTS 3 #define MAX_PM_DOMAINS 5 +/** + * enum panfrost_gpu_pm - Supported kernel power management features + * @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend + */ +enum panfrost_gpu_pm { + GPU_PM_CLK_DIS, +}; + struct panfrost_features { u16 id; u16 revision; @@ -75,6 +83,9 @@ struct panfrost_compatible { /* Vendor implementation quirks callback */ void (*vendor_quirk)(struct panfrost_device *pfdev); + + /* Allowed PM features */ + u8 pm_features; }; struct panfrost_device { From 32f175d4261a2c940fe7913f509f9f41c105b2b6 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:41 +0100 Subject: [PATCH 0363/7721] drm/panfrost: Set clocks on/off during system sleep on MediaTek SoCs All of the MediaTek SoCs supported by Panfrost can switch the clocks off and on during system sleep to save some power without any user experience penalty. Measurements taken on multiple MediaTek SoCs (MT8183/8186/8192/8195) show that adding this will not prolong the time that is required to resume the system in any meaningful way. As an example, for MT8195 - a "before" with only runtime PM operations (so, without turning on/off GPU clocks), and an "after" executing both the system sleep .resume() handler and .runtime_resume() (so the time refers to T_Resume + T_Runtime_Resume): Average Panfrost-only system sleep resume time, before: ~28000ns Average Panfrost-only system sleep resume time, after: ~33500ns Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-5-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 54d1c19bea84..6d2897c03a8f 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -730,6 +730,7 @@ static const struct panfrost_compatible mediatek_mt8183_b_data = { .supply_names = mediatek_mt8183_b_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains, + .pm_features = BIT(GPU_PM_CLK_DIS), }; static const char * const mediatek_mt8186_pm_domains[] = { "core0", "core1" }; @@ -738,6 +739,7 @@ static const struct panfrost_compatible mediatek_mt8186_data = { .supply_names = mediatek_mt8183_b_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8186_pm_domains), .pm_domain_names = mediatek_mt8186_pm_domains, + .pm_features = BIT(GPU_PM_CLK_DIS), }; static const char * const mediatek_mt8192_supplies[] = { "mali", NULL }; @@ -748,6 +750,7 @@ static const struct panfrost_compatible mediatek_mt8192_data = { .supply_names = mediatek_mt8192_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8192_pm_domains), .pm_domain_names = mediatek_mt8192_pm_domains, + .pm_features = BIT(GPU_PM_CLK_DIS), }; static const struct of_device_id dt_match[] = { From 889a2b06f823575f4e8def0fe60d294365b0e1f9 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:42 +0100 Subject: [PATCH 0364/7721] drm/panfrost: Implement ability to turn on/off regulators in suspend Some platforms/SoCs can power off the GPU entirely by completely cutting off power, greatly enhancing battery time during system suspend: add a new pm_feature GPU_PM_VREG_OFF to allow turning off the GPU regulators during full suspend only on selected platforms. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-6-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_device.c | 19 ++++++++++++++++++- drivers/gpu/drm/panfrost/panfrost_device.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index b4ddbc3b8069..c90ad5ee34e7 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -431,10 +431,21 @@ static int panfrost_device_resume(struct device *dev) struct panfrost_device *pfdev = dev_get_drvdata(dev); int ret; + if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF)) { + unsigned long freq = pfdev->pfdevfreq.fast_rate; + struct dev_pm_opp *opp; + + opp = dev_pm_opp_find_freq_ceil(dev, &freq); + if (IS_ERR(opp)) + return PTR_ERR(opp); + dev_pm_opp_set_opp(dev, opp); + dev_pm_opp_put(opp); + } + if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) { ret = clk_enable(pfdev->clock); if (ret) - return ret; + goto err_clk; if (pfdev->bus_clock) { ret = clk_enable(pfdev->bus_clock); @@ -455,6 +466,9 @@ static int panfrost_device_resume(struct device *dev) err_bus_clk: if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) clk_disable(pfdev->clock); +err_clk: + if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF)) + dev_pm_opp_set_opp(dev, NULL); return ret; } @@ -474,6 +488,9 @@ static int panfrost_device_suspend(struct device *dev) clk_disable(pfdev->clock); } + if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF)) + dev_pm_opp_set_opp(dev, NULL); + return 0; } diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 32453b97c39c..7de77990a221 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -28,9 +28,11 @@ struct panfrost_perfcnt; /** * enum panfrost_gpu_pm - Supported kernel power management features * @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend + * @GPU_PM_VREG_OFF: Allow turning off regulators during system suspend */ enum panfrost_gpu_pm { GPU_PM_CLK_DIS, + GPU_PM_VREG_OFF, }; struct panfrost_features { From 540527b1385fb203cc4513ca838b4de60bbbc49a Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 9 Nov 2023 11:25:43 +0100 Subject: [PATCH 0365/7721] drm/panfrost: Set regulators on/off during system sleep on MediaTek SoCs All of the MediaTek SoCs supported by Panfrost can completely cut power to the GPU during full system sleep without any user-noticeable delay in the resume operation, as shown by measurements taken on multiple MediaTek SoCs (MT8183/86/92/95). As an example, for MT8195 - a "before" with only runtime PM operations (so, without turning on/off regulators), and an "after" executing both the system sleep .resume() handler and .runtime_resume() (so the time refers to T_Resume + T_Runtime_Resume): Average Panfrost-only system sleep resume time, before: ~33500ns Average Panfrost-only system sleep resume time, after: ~336200ns Keep in mind that this additional ~308200 nanoseconds delay happens only in resume from a full system suspend, and not in runtime PM operations, hence it is acceptable. Measurements were also taken on MT8186, showing a delay of ~312000 ns. Testing of this happened on all of the aforementioned MediaTek SoCs, but: MT8183 got tested only by KernelCI with <=10 suspend/resume cycles MT8186, MT8192, MT8195 were tested manually with over 100 suspend/resume cycles with GNOME DE (Mutter + Wayland). Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20231109102543.42971-7-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 6d2897c03a8f..7a628e89d379 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -730,7 +730,7 @@ static const struct panfrost_compatible mediatek_mt8183_b_data = { .supply_names = mediatek_mt8183_b_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains), .pm_domain_names = mediatek_mt8183_pm_domains, - .pm_features = BIT(GPU_PM_CLK_DIS), + .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF), }; static const char * const mediatek_mt8186_pm_domains[] = { "core0", "core1" }; @@ -739,7 +739,7 @@ static const struct panfrost_compatible mediatek_mt8186_data = { .supply_names = mediatek_mt8183_b_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8186_pm_domains), .pm_domain_names = mediatek_mt8186_pm_domains, - .pm_features = BIT(GPU_PM_CLK_DIS), + .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF), }; static const char * const mediatek_mt8192_supplies[] = { "mali", NULL }; @@ -750,7 +750,7 @@ static const struct panfrost_compatible mediatek_mt8192_data = { .supply_names = mediatek_mt8192_supplies, .num_pm_domains = ARRAY_SIZE(mediatek_mt8192_pm_domains), .pm_domain_names = mediatek_mt8192_pm_domains, - .pm_features = BIT(GPU_PM_CLK_DIS), + .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF), }; static const struct of_device_id dt_match[] = { From 689b097a06bafb461ec162fc3b3ecc9765cea67b Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Mon, 6 Nov 2023 03:18:02 +0000 Subject: [PATCH 0366/7721] compiler-gcc: Suppress -Wmissing-prototypes warning for all supported GCC The kernel supports a minimum GCC version of 5.1.0 for building. However, the "__diag_ignore_all" directive only suppresses the "-Wmissing-prototypes" warning for GCC versions >= 8.0.0. As a result, when building the kernel with older GCC versions, warnings may be triggered. The example below illustrates the warnings reported by the kernel test robot using GCC 7.5.0: compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0 All warnings (new ones prefixed by >>): kernel/bpf/helpers.c:1893:19: warning: no previous prototype for 'bpf_obj_new_impl' [-Wmissing-prototypes] __bpf_kfunc void *bpf_obj_new_impl(u64 local_type_id__k, void *meta__ign) ^~~~~~~~~~~~~~~~ kernel/bpf/helpers.c:1907:19: warning: no previous prototype for 'bpf_percpu_obj_new_impl' [-Wmissing-prototypes] __bpf_kfunc void *bpf_percpu_obj_new_impl(u64 local_type_id__k, void *meta__ign) [...] To address this, we should also suppress the "-Wmissing-prototypes" warning for older GCC versions. "#pragma GCC diagnostic push" is supported as of GCC 4.6, and both "-Wmissing-prototypes" and "-Wmissing-declarations" are supported for all the GCC versions that we currently support. Therefore, it is reasonable to suppress these warnings for all supported GCC versions. With this adjustment, it's important to note that after implementing "__diag_ignore_all", it will effectively suppress warnings for all the supported GCC versions. In the future, if you wish to suppress warnings that are only supported on higher GCC versions, it is advisable to explicitly use "__diag_ignore" to specify the GCC version you are targeting. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311031651.A7crZEur-lkp@intel.com/ Suggested-by: Arnd Bergmann Signed-off-by: Yafang Shao Cc: Kumar Kartikeya Dwivedi Cc: Arnd Bergmann Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231106031802.4188-1-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- include/linux/compiler-gcc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 2ceba3fe4ec1..aebb65bf95a7 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -136,7 +136,7 @@ #endif #define __diag_ignore_all(option, comment) \ - __diag_GCC(8, ignore, option) + __diag(__diag_GCC_ignore option) /* * Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size" From b8e3a87a627b575896e448021e5c2f8a3bc19931 Mon Sep 17 00:00:00 2001 From: Jordan Rome Date: Wed, 8 Nov 2023 03:23:34 -0800 Subject: [PATCH 0367/7721] bpf: Add crosstask check to __bpf_get_stack Currently get_perf_callchain only supports user stack walking for the current task. Passing the correct *crosstask* param will return 0 frames if the task passed to __bpf_get_stack isn't the current one instead of a single incorrect frame/address. This change passes the correct *crosstask* param but also does a preemptive check in __bpf_get_stack if the task is current and returns -EOPNOTSUPP if it is not. This issue was found using bpf_get_task_stack inside a BPF iterator ("iter/task"), which iterates over all tasks. bpf_get_task_stack works fine for fetching kernel stacks but because get_perf_callchain relies on the caller to know if the requested *task* is the current one (via *crosstask*) it was failing in a confusing way. It might be possible to get user stacks for all tasks utilizing something like access_process_vm but that requires the bpf program calling bpf_get_task_stack to be sleepable and would therefore be a breaking change. Fixes: fa28dcb82a38 ("bpf: Introduce helper bpf_get_task_stack()") Signed-off-by: Jordan Rome Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231108112334.3433136-1-jordalgo@meta.com --- include/uapi/linux/bpf.h | 3 +++ kernel/bpf/stackmap.c | 11 ++++++++++- tools/include/uapi/linux/bpf.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 095ca7238ac2..7cf8bcf9f6a2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -4517,6 +4517,8 @@ union bpf_attr { * long bpf_get_task_stack(struct task_struct *task, void *buf, u32 size, u64 flags) * Description * Return a user or a kernel stack in bpf program provided buffer. + * Note: the user stack will only be populated if the *task* is + * the current task; all other tasks will return -EOPNOTSUPP. * To achieve this, the helper needs *task*, which is a valid * pointer to **struct task_struct**. To store the stacktrace, the * bpf program provides *buf* with a nonnegative *size*. @@ -4528,6 +4530,7 @@ union bpf_attr { * * **BPF_F_USER_STACK** * Collect a user space stack instead of a kernel stack. + * The *task* must be the current task. * **BPF_F_USER_BUILD_ID** * Collect buildid+offset instead of ips for user stack, * only valid if **BPF_F_USER_STACK** is also specified. diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index d6b277482085..dff7ba539701 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -388,6 +388,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, { u32 trace_nr, copy_len, elem_size, num_elem, max_depth; bool user_build_id = flags & BPF_F_USER_BUILD_ID; + bool crosstask = task && task != current; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; bool user = flags & BPF_F_USER_STACK; struct perf_callchain_entry *trace; @@ -410,6 +411,14 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, if (task && user && !user_mode(regs)) goto err_fault; + /* get_perf_callchain does not support crosstask user stack walking + * but returns an empty stack instead of NULL. + */ + if (crosstask && user) { + err = -EOPNOTSUPP; + goto clear; + } + num_elem = size / elem_size; max_depth = num_elem + skip; if (sysctl_perf_event_max_stack < max_depth) @@ -421,7 +430,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, trace = get_callchain_entry_for_task(task, max_depth); else trace = get_perf_callchain(regs, 0, kernel, user, max_depth, - false, false); + crosstask, false); if (unlikely(!trace)) goto err_fault; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 095ca7238ac2..7cf8bcf9f6a2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -4517,6 +4517,8 @@ union bpf_attr { * long bpf_get_task_stack(struct task_struct *task, void *buf, u32 size, u64 flags) * Description * Return a user or a kernel stack in bpf program provided buffer. + * Note: the user stack will only be populated if the *task* is + * the current task; all other tasks will return -EOPNOTSUPP. * To achieve this, the helper needs *task*, which is a valid * pointer to **struct task_struct**. To store the stacktrace, the * bpf program provides *buf* with a nonnegative *size*. @@ -4528,6 +4530,7 @@ union bpf_attr { * * **BPF_F_USER_STACK** * Collect a user space stack instead of a kernel stack. + * The *task* must be the current task. * **BPF_F_USER_BUILD_ID** * Collect buildid+offset instead of ips for user stack, * only valid if **BPF_F_USER_STACK** is also specified. From 88a6e46cd3e33756b168c7f2366bf7029a16da56 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Nov 2023 18:07:21 +0200 Subject: [PATCH 0368/7721] drm/i915: abstract plane protection check Centralize the conditions in a function. Reviewed-by: Rodrigo Vivi Reviewed-by: Suraj Kandpal Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231109160722.3372379-1-jani.nikula@intel.com --- .../gpu/drm/i915/display/skl_universal_plane.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 68035675ae3c..98acf25a5ca3 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1866,6 +1866,19 @@ static bool pxp_is_borked(struct drm_i915_gem_object *obj) return i915_gem_object_is_protected(obj) && !bo_has_valid_encryption(obj); } +static void check_protection(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *i915 = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + if (DISPLAY_VER(i915) < 11) + return; + + plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); + plane_state->force_black = pxp_is_borked(intel_fb_obj(fb)); +} + static int skl_plane_check(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { @@ -1910,10 +1923,7 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - if (DISPLAY_VER(dev_priv) >= 11) { - plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); - plane_state->force_black = pxp_is_borked(intel_fb_obj(fb)); - } + check_protection(plane_state); /* HW only has 8 bits pixel precision, disable plane if invisible */ if (!(plane_state->hw.alpha >> 8)) From 9b1c97fc0ce6090c328b5723250f4deeefc95fcd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Nov 2023 18:07:22 +0200 Subject: [PATCH 0369/7721] drm/i915: remove excess functions from plane protection check Reduce the function calls by reusing ->decrypt. Reviewed-by: Rodrigo Vivi Reviewed-by: Suraj Kandpal Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231109160722.3372379-2-jani.nikula@intel.com --- .../gpu/drm/i915/display/skl_universal_plane.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 98acf25a5ca3..39499a0ec6c0 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1854,29 +1854,19 @@ static bool skl_fb_scalable(const struct drm_framebuffer *fb) } } -static bool bo_has_valid_encryption(struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *i915 = to_i915(obj->base.dev); - - return intel_pxp_key_check(i915->pxp, obj, false) == 0; -} - -static bool pxp_is_borked(struct drm_i915_gem_object *obj) -{ - return i915_gem_object_is_protected(obj) && !bo_has_valid_encryption(obj); -} - static void check_protection(struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *i915 = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->hw.fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); if (DISPLAY_VER(i915) < 11) return; - plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); - plane_state->force_black = pxp_is_borked(intel_fb_obj(fb)); + plane_state->decrypt = intel_pxp_key_check(i915->pxp, obj, false) == 0; + plane_state->force_black = i915_gem_object_is_protected(obj) && + !plane_state->decrypt; } static int skl_plane_check(struct intel_crtc_state *crtc_state, From ff5a55a3e80eba616f4d06fa255bfe4f8b032bec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 10 Nov 2023 13:48:06 +0200 Subject: [PATCH 0370/7721] MAINTAINERS: update drm/i915 W: and B: entries The 01.org page has ceased to exist, and the relevant documentation is now hosted at https://drm.pages.freedesktop.org/intel-docs/ Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231110114807.3455739-1-jani.nikula@intel.com --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e05506ea8917..d42116703f2f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10473,9 +10473,9 @@ M: Rodrigo Vivi M: Tvrtko Ursulin L: intel-gfx@lists.freedesktop.org S: Supported -W: https://01.org/linuxgraphics/ +W: https://drm.pages.freedesktop.org/intel-docs/ Q: http://patchwork.freedesktop.org/project/intel-gfx/ -B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs +B: https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html C: irc://irc.oftc.net/intel-gfx T: git git://anongit.freedesktop.org/drm-intel F: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon From f8e9325f09c778fb61d3cebd27a9f3738e6fea48 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 10 Nov 2023 13:48:07 +0200 Subject: [PATCH 0371/7721] drm/i915: update in-source bug filing URLs The bug filing documentation has been moved from the gitlab wiki to gitlab pages at https://drm.pages.freedesktop.org/intel-docs/. Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231110114807.3455739-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/Kconfig | 2 +- drivers/gpu/drm/i915/i915_gpu_error.c | 2 +- drivers/gpu/drm/i915/i915_utils.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index ce397a8797f7..b5d6e3352071 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -94,7 +94,7 @@ config DRM_I915_CAPTURE_ERROR This option enables capturing the GPU state when a hang is detected. This information is vital for triaging hangs and assists in debugging. Please report any hang for triaging according to: - https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs + https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html If in doubt, say "Y". diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 53fff687b00e..6ff410dc1a4a 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -2168,7 +2168,7 @@ void i915_error_state_store(struct i915_gpu_coredump *error) ktime_get_real_seconds() - DRIVER_TIMESTAMP < DAY_AS_SECONDS(180)) { pr_info("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); pr_info("Please file a _new_ bug report at https://gitlab.freedesktop.org/drm/intel/issues/new.\n"); - pr_info("Please see https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs for details.\n"); + pr_info("Please see https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html for details.\n"); pr_info("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); pr_info("The GPU crash dump is required to analyze GPU hangs, so please always attach it.\n"); pr_info("GPU crash dump saved to /sys/class/drm/card%d/error\n", diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index c61066498bf2..f98577967b7f 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -40,7 +40,7 @@ struct drm_i915_private; struct timer_list; -#define FDO_BUG_URL "https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs" +#define FDO_BUG_URL "https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html" #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) From e4178256094a76cc36d9b9aabe7482615959b26f Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Wed, 18 Oct 2023 11:17:26 -0700 Subject: [PATCH 0372/7721] drm/virtio: use uint64_t more in virtio_gpu_context_init_ioctl drm_virtgpu_context_set_param defines both param and value to be u64s. Signed-off-by: Gurchetan Singh Reviewed-by: Josh Simonot Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20231018181727.772-1-gurchetansingh@chromium.org --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index b24b11f25197..8d13b17c215b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -565,8 +565,8 @@ static int virtio_gpu_context_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { int ret = 0; - uint32_t num_params, i, param, value; - uint64_t valid_ring_mask; + uint32_t num_params, i; + uint64_t valid_ring_mask, param, value; size_t len; struct drm_virtgpu_context_set_param *ctx_set_params = NULL; struct virtio_gpu_device *vgdev = dev->dev_private; From 7add80126bcedddd157ddc09988b032c93ed56c7 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Wed, 18 Oct 2023 11:17:27 -0700 Subject: [PATCH 0373/7721] drm/uapi: add explicit virtgpu context debug name There are two problems with the current method of determining the virtio-gpu debug name. 1) TASK_COMM_LEN is defined to be 16 bytes only, and this is a Linux kernel idiom (see PR_SET_NAME + PR_GET_NAME). Though, Android/FreeBSD get around this via setprogname(..)/getprogname(..) in libc. On Android, names longer than 16 bytes are common. For example, one often encounters a program like "com.android.systemui". The virtio-gpu spec allows the debug name to be up to 64 bytes, so ideally userspace should be able to set debug names up to 64 bytes. 2) The current implementation determines the debug name using whatever task initiated virtgpu. This is could be a "RenderThread" of a larger program, when we actually want to propagate the debug name of the program. To fix these issues, add a new CONTEXT_INIT param that allows userspace to set the debug name when creating a context. It takes a null-terminated C-string as the param value. The length of the string (excluding the terminator) **should** be <= 64 bytes. Otherwise, the debug_name will be truncated to 64 bytes. Link to open-source userspace: https://android-review.googlesource.com/c/platform/hardware/google/gfxstream/+/2787176 Signed-off-by: Gurchetan Singh Reviewed-by: Josh Simonot Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20231018181727.772-2-gurchetansingh@chromium.org --- drivers/gpu/drm/virtio/virtgpu_drv.h | 5 ++++ drivers/gpu/drm/virtio/virtgpu_ioctl.c | 36 +++++++++++++++++++++----- include/uapi/drm/virtgpu_drm.h | 2 ++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 96365a772f77..bb7d86a0c6a1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -58,6 +58,9 @@ #define MAX_CAPSET_ID 63 #define MAX_RINGS 64 +/* See virtio_gpu_ctx_create. One additional character for NULL terminator. */ +#define DEBUG_NAME_MAX_LEN 65 + struct virtio_gpu_object_params { unsigned long size; bool dumb; @@ -274,6 +277,8 @@ struct virtio_gpu_fpriv { uint64_t base_fence_ctx; uint64_t ring_idx_mask; struct mutex context_lock; + char debug_name[DEBUG_NAME_MAX_LEN]; + bool explicit_debug_name; }; /* virtgpu_ioctl.c */ diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 8d13b17c215b..1e2042419f95 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -42,12 +42,19 @@ static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev, struct virtio_gpu_fpriv *vfpriv) { - char dbgname[TASK_COMM_LEN]; + if (vfpriv->explicit_debug_name) { + virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id, + vfpriv->context_init, + strlen(vfpriv->debug_name), + vfpriv->debug_name); + } else { + char dbgname[TASK_COMM_LEN]; - get_task_comm(dbgname, current); - virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id, - vfpriv->context_init, strlen(dbgname), - dbgname); + get_task_comm(dbgname, current); + virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id, + vfpriv->context_init, strlen(dbgname), + dbgname); + } vfpriv->context_created = true; } @@ -107,6 +114,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs: value = vgdev->capset_id_mask; break; + case VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME: + value = vgdev->has_context_init ? 1 : 0; + break; default: return -EINVAL; } @@ -580,7 +590,7 @@ static int virtio_gpu_context_init_ioctl(struct drm_device *dev, return -EINVAL; /* Number of unique parameters supported at this time. */ - if (num_params > 3) + if (num_params > 4) return -EINVAL; ctx_set_params = memdup_user(u64_to_user_ptr(args->ctx_set_params), @@ -642,6 +652,20 @@ static int virtio_gpu_context_init_ioctl(struct drm_device *dev, vfpriv->ring_idx_mask = value; break; + case VIRTGPU_CONTEXT_PARAM_DEBUG_NAME: + if (vfpriv->explicit_debug_name) { + ret = -EINVAL; + goto out_unlock; + } + + ret = strncpy_from_user(vfpriv->debug_name, + u64_to_user_ptr(value), + DEBUG_NAME_MAX_LEN - 1); + if (ret < 0) + goto out_unlock; + + vfpriv->explicit_debug_name = true; + break; default: ret = -EINVAL; goto out_unlock; diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index b1d0e56565bc..c2ce71987e9b 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -97,6 +97,7 @@ struct drm_virtgpu_execbuffer { #define VIRTGPU_PARAM_CROSS_DEVICE 5 /* Cross virtio-device resource sharing */ #define VIRTGPU_PARAM_CONTEXT_INIT 6 /* DRM_VIRTGPU_CONTEXT_INIT */ #define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */ +#define VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME 8 /* Ability to set debug name from userspace */ struct drm_virtgpu_getparam { __u64 param; @@ -198,6 +199,7 @@ struct drm_virtgpu_resource_create_blob { #define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 #define VIRTGPU_CONTEXT_PARAM_NUM_RINGS 0x0002 #define VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK 0x0003 +#define VIRTGPU_CONTEXT_PARAM_DEBUG_NAME 0x0004 struct drm_virtgpu_context_set_param { __u64 param; __u64 value; From 100888fb6d8a185866b1520031ee7e3182b173de Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 10 Nov 2023 11:36:44 -0800 Subject: [PATCH 0374/7721] selftests/bpf: Fix pyperf180 compilation failure with clang18 With latest clang18 (main branch of llvm-project repo), when building bpf selftests, [~/work/bpf-next (master)]$ make -C tools/testing/selftests/bpf LLVM=1 -j The following compilation error happens: fatal error: error in backend: Branch target out of insn range ... Stack dump: 0. Program arguments: clang -g -Wall -Werror -D__TARGET_ARCH_x86 -mlittle-endian -I/home/yhs/work/bpf-next/tools/testing/selftests/bpf/tools/include -I/home/yhs/work/bpf-next/tools/testing/selftests/bpf -I/home/yhs/work/bpf-next/tools/include/uapi -I/home/yhs/work/bpf-next/tools/testing/selftests/usr/include -idirafter /home/yhs/work/llvm-project/llvm/build.18/install/lib/clang/18/include -idirafter /usr/local/include -idirafter /usr/include -Wno-compare-distinct-pointer-types -DENABLE_ATOMICS_TESTS -O2 --target=bpf -c progs/pyperf180.c -mcpu=v3 -o /home/yhs/work/bpf-next/tools/testing/selftests/bpf/pyperf180.bpf.o 1. parser at end of file 2. Code generation ... The compilation failure only happens to cpu=v2 and cpu=v3. cpu=v4 is okay since cpu=v4 supports 32-bit branch target offset. The above failure is due to upstream llvm patch [1] where some inlining behavior are changed in clang18. To workaround the issue, previously all 180 loop iterations are fully unrolled. The bpf macro __BPF_CPU_VERSION__ (implemented in clang18 recently) is used to avoid unrolling changes if cpu=v4. If __BPF_CPU_VERSION__ is not available and the compiler is clang18, the unrollng amount is unconditionally reduced. [1] https://github.com/llvm/llvm-project/commit/1a2e77cf9e11dbf56b5720c607313a566eebb16e Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Tested-by: Alan Maguire Link: https://lore.kernel.org/bpf/20231110193644.3130906-1-yonghong.song@linux.dev --- tools/testing/selftests/bpf/progs/pyperf180.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/pyperf180.c b/tools/testing/selftests/bpf/progs/pyperf180.c index c39f559d3100..42c4a8b62e36 100644 --- a/tools/testing/selftests/bpf/progs/pyperf180.c +++ b/tools/testing/selftests/bpf/progs/pyperf180.c @@ -1,4 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Facebook #define STACK_MAX_LEN 180 + +/* llvm upstream commit at clang18 + * https://github.com/llvm/llvm-project/commit/1a2e77cf9e11dbf56b5720c607313a566eebb16e + * changed inlining behavior and caused compilation failure as some branch + * target distance exceeded 16bit representation which is the maximum for + * cpu v1/v2/v3. Macro __BPF_CPU_VERSION__ is later implemented in clang18 + * to specify which cpu version is used for compilation. So a smaller + * unroll_count can be set if __BPF_CPU_VERSION__ is less than 4, which + * reduced some branch target distances and resolved the compilation failure. + * + * To capture the case where a developer/ci uses clang18 but the corresponding + * repo checkpoint does not have __BPF_CPU_VERSION__, a smaller unroll_count + * will be set as well to prevent potential compilation failures. + */ +#ifdef __BPF_CPU_VERSION__ +#if __BPF_CPU_VERSION__ < 4 +#define UNROLL_COUNT 90 +#endif +#elif __clang_major__ == 18 +#define UNROLL_COUNT 90 +#endif + #include "pyperf.h" From fc85d9d0b3ba8f8934963c760af98fc38029d9da Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 9 Nov 2023 15:58:59 +0200 Subject: [PATCH 0375/7721] ASoC: SOF: imx8m: Add DAI driver entry for MICFIL PDM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow creating of PDM DAI links. Reviewed-by: Péter Ujfalusi Reviewed-by: Iuliana Prodan Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20231109135900.88310-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8m.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 2680f061ba42..f088fd1a672b 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -313,6 +313,13 @@ static struct snd_soc_dai_driver imx8m_dai[] = { .channels_max = 32, }, }, +{ + .name = "micfil", + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, }; static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev, From 89ef42088b3ba884a007ad10bd89ce8a81b9dedd Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 9 Nov 2023 15:59:00 +0200 Subject: [PATCH 0376/7721] ASoC: SOF: Add support for configuring PDM interface from topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only support configuration for number of channels and sample rate. Reviewed-by: Péter Ujfalusi Reviewed-by: Iuliana Prodan Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20231109135900.88310-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- include/sound/sof/dai-imx.h | 7 +++++ include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/tokens.h | 4 +++ sound/soc/sof/ipc3-pcm.c | 11 ++++++++ sound/soc/sof/ipc3-topology.c | 46 +++++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 1 + sound/soc/sof/topology.c | 5 ++++ 7 files changed, 76 insertions(+) diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h index ca8325353d41..6bc987bd4761 100644 --- a/include/sound/sof/dai-imx.h +++ b/include/sound/sof/dai-imx.h @@ -51,4 +51,11 @@ struct sof_ipc_dai_sai_params { uint16_t tdm_slot_width; uint16_t reserved2; /* alignment */ } __packed; + +/* MICFIL Configuration Request - SOF_IPC_DAI_MICFIL_CONFIG */ +struct sof_ipc_dai_micfil_params { + uint32_t pdm_rate; + uint32_t pdm_ch; +} __packed; + #endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 3041f5805b7b..4773a5f616a4 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -88,6 +88,7 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_HS, /**< Amd HS */ SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */ SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */ + SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ }; /* general purpose DAI configuration */ @@ -117,6 +118,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_acpdmic_params acpdmic; struct sof_ipc_dai_acp_params acphs; struct sof_ipc_dai_mtk_afe_params afe; + struct sof_ipc_dai_micfil_params micfil; }; } __packed; diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 453cab2a1209..0fb39780f9bd 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -213,4 +213,8 @@ #define SOF_TKN_AMD_ACPI2S_CH 1701 #define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702 +/* MICFIL PDM */ +#define SOF_TKN_IMX_MICFIL_RATE 2000 +#define SOF_TKN_IMX_MICFIL_CH 2001 + #endif diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 2d0addcbc819..330f04bcd75d 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -384,6 +384,17 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_IMX_MICFIL: + rate->min = private->dai_config->micfil.pdm_rate; + rate->max = private->dai_config->micfil.pdm_rate; + channels->min = private->dai_config->micfil.pdm_ch; + channels->max = private->dai_config->micfil.pdm_ch; + + dev_dbg(component->dev, + "MICFIL PDM rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, "MICFIL PDM channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type); break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index ba4ef290b634..7a4932c152a9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -286,6 +286,16 @@ static const struct sof_topology_token acpi2s_tokens[] = { offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, }; +/* MICFIL PDM */ +static const struct sof_topology_token micfil_pdm_tokens[] = { + {SOF_TKN_IMX_MICFIL_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_micfil_params, pdm_rate)}, + {SOF_TKN_IMX_MICFIL_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_micfil_params, pdm_ch)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -322,6 +332,8 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)}, [SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)}, + [SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens", + micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)}, }; /** @@ -1136,6 +1148,37 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_da return 0; } +static int sof_link_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + config->hdr.size = size; + + /* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->micfil, SOF_MICFIL_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + dev_info(scomp->dev, "MICFIL PDM config dai_index %d channel %d rate %d\n", + config->dai_index, config->micfil.pdm_ch, config->micfil.pdm_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1559,6 +1602,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) case SOF_DAI_IMX_ESAI: ret = sof_link_esai_load(scomp, slink, config, dai); break; + case SOF_DAI_IMX_MICFIL: + ret = sof_link_micfil_load(scomp, slink, config, dai); + break; case SOF_DAI_AMD_BT: ret = sof_link_acp_bt_load(scomp, slink, config, dai); break; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5d5eeb1a1a6f..99c940b22538 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -275,6 +275,7 @@ enum sof_tokens { SOF_GAIN_TOKENS, SOF_ACPDMIC_TOKENS, SOF_ACPI2S_TOKENS, + SOF_MICFIL_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a3a3af252259..9f717366cddc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -296,6 +296,7 @@ static const struct sof_dai_types sof_dais[] = { {"AFE", SOF_DAI_MEDIATEK_AFE}, {"ACPSP_VIRTUAL", SOF_DAI_AMD_SP_VIRTUAL}, {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, + {"MICFIL", SOF_DAI_IMX_MICFIL}, }; @@ -1960,6 +1961,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ token_id = SOF_ACPI2S_TOKENS; num_tuples += token_list[SOF_ACPI2S_TOKENS].count; break; + case SOF_DAI_IMX_MICFIL: + token_id = SOF_MICFIL_TOKENS; + num_tuples += token_list[SOF_MICFIL_TOKENS].count; + break; default: break; } From 59fff33e9d923779b68fe46f39262256caba71d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:46:56 +0100 Subject: [PATCH 0377/7721] ASoC: Intel: avs: da7219: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/da7219.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 6060894954df..c018f84fe025 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -277,16 +277,24 @@ static int avs_da7219_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_da7219_driver_ids[] = { + { + .name = "avs_da7219", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids); + static struct platform_driver avs_da7219_driver = { .probe = avs_da7219_probe, .driver = { .name = "avs_da7219", .pm = &snd_soc_pm_ops, }, + .id_table = avs_da7219_driver_ids, }; module_platform_driver(avs_da7219_driver); MODULE_AUTHOR("Cezary Rojewski "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_da7219"); From deb8dcad7bc3505881e2c0680d8f01f23fcbba98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:46:57 +0100 Subject: [PATCH 0378/7721] ASoC: Intel: avs: dmic: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/dmic.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index c270646faf86..ba2bc7f689eb 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -77,15 +77,23 @@ static int avs_dmic_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_dmic_driver_ids[] = { + { + .name = "avs_dmic", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids); + static struct platform_driver avs_dmic_driver = { .probe = avs_dmic_probe, .driver = { .name = "avs_dmic", .pm = &snd_soc_pm_ops, }, + .id_table = avs_dmic_driver_ids, }; module_platform_driver(avs_dmic_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_dmic"); From 9441450e171fc90aa3fceadae9728acf8bd0726a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:46:58 +0100 Subject: [PATCH 0379/7721] ASoC: Intel: avs: es8336: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/es8336.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index f972ef64d284..1090082e7d5b 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -307,15 +307,23 @@ static int avs_es8336_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_es8336_driver_ids[] = { + { + .name = "avs_es8336", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids); + static struct platform_driver avs_es8336_driver = { .probe = avs_es8336_probe, .driver = { .name = "avs_es8336", .pm = &snd_soc_pm_ops, }, + .id_table = avs_es8336_driver_ids, }; module_platform_driver(avs_es8336_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_es8336"); From 9a872caede56d20564caf30d7ea7cf61b66f4060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:46:59 +0100 Subject: [PATCH 0380/7721] ASoC: Intel: avs: hdaudio: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-5-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/hdaudio.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 8876558f19a1..844a918f9a81 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -218,12 +218,21 @@ static int avs_hdaudio_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_hdaudio_driver_ids[] = { + { + .name = "avs_hdaudio", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids); + static struct platform_driver avs_hdaudio_driver = { .probe = avs_hdaudio_probe, .driver = { .name = "avs_hdaudio", .pm = &snd_soc_pm_ops, }, + .id_table = avs_hdaudio_driver_ids, }; module_platform_driver(avs_hdaudio_driver) @@ -231,4 +240,3 @@ module_platform_driver(avs_hdaudio_driver) MODULE_DESCRIPTION("Intel HD-Audio machine driver"); MODULE_AUTHOR("Cezary Rojewski "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_hdaudio"); From 8267213c54db078db091b778e904ec1af8fc6ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:00 +0100 Subject: [PATCH 0381/7721] ASoC: Intel: avs: i2s_test: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-6-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/i2s_test.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 3d03e1eed3a9..28f254eb0d03 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -185,15 +185,23 @@ static int avs_i2s_test_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_i2s_test_driver_ids[] = { + { + .name = "avs_i2s_test", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids); + static struct platform_driver avs_i2s_test_driver = { .probe = avs_i2s_test_probe, .driver = { .name = "avs_i2s_test", .pm = &snd_soc_pm_ops, }, + .id_table = avs_i2s_test_driver_ids, }; module_platform_driver(avs_i2s_test_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_i2s_test"); From f1e9f4f5e9e5506edbd17b33065ec8c8a9e6caab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:01 +0100 Subject: [PATCH 0382/7721] ASoC: Intel: avs: max98357a: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-7-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98357a.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 6ba7b6564279..a83b95f25129 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -135,15 +135,23 @@ static int avs_max98357a_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98357a_driver_ids[] = { + { + .name = "avs_max98357a", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids); + static struct platform_driver avs_max98357a_driver = { .probe = avs_max98357a_probe, .driver = { .name = "avs_max98357a", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98357a_driver_ids, }; module_platform_driver(avs_max98357a_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98357a"); From 8e660f303230741ecaab561a30e123e7dc76abda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:02 +0100 Subject: [PATCH 0383/7721] ASoC: Intel: avs: max98373: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-8-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98373.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index cc7dfdf72083..3b980a025e6f 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -192,15 +192,23 @@ static int avs_max98373_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98373_driver_ids[] = { + { + .name = "avs_max98373", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids); + static struct platform_driver avs_max98373_driver = { .probe = avs_max98373_probe, .driver = { .name = "avs_max98373", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98373_driver_ids, }; module_platform_driver(avs_max98373_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98373"); From c3ff01859c31408eadfd607352d4f87e52096371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:03 +0100 Subject: [PATCH 0384/7721] ASoC: Intel: avs: max98927: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-9-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98927.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index fb0175f37d61..86dd2b228df3 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -189,15 +189,23 @@ static int avs_max98927_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98927_driver_ids[] = { + { + .name = "avs_max98927", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids); + static struct platform_driver avs_max98927_driver = { .probe = avs_max98927_probe, .driver = { .name = "avs_max98927", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98927_driver_ids, }; module_platform_driver(avs_max98927_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98927"); From c94643c2b416afc473541943291e61c453846a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:04 +0100 Subject: [PATCH 0385/7721] ASoC: Intel: avs: nau8825: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-10-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/nau8825.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index d98b5deb78c9..1c1e2083f474 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -294,15 +294,23 @@ static int avs_nau8825_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_nau8825_driver_ids[] = { + { + .name = "avs_nau8825", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids); + static struct platform_driver avs_nau8825_driver = { .probe = avs_nau8825_probe, .driver = { .name = "avs_nau8825", .pm = &snd_soc_pm_ops, }, + .id_table = avs_nau8825_driver_ids, }; module_platform_driver(avs_nau8825_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_nau8825"); From 4a5403e3a75ddc24941f754c14c3299cc0e28fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:05 +0100 Subject: [PATCH 0386/7721] ASoC: Intel: avs: probe: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-11-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/probe.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 411acaee74f9..a9469b5ecb40 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -50,15 +50,23 @@ static int avs_probe_mb_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_probe_mb_driver_ids[] = { + { + .name = "avs_probe_mb", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids); + static struct platform_driver avs_probe_mb_driver = { .probe = avs_probe_mb_probe, .driver = { .name = "avs_probe_mb", .pm = &snd_soc_pm_ops, }, + .id_table = avs_probe_mb_driver_ids, }; module_platform_driver(avs_probe_mb_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_probe_mb"); From 54c830fd4e38261adffa51bb22c44a2e33d803ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:06 +0100 Subject: [PATCH 0387/7721] ASoC: Intel: avs: rt274: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-12-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt274.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 157183b1de24..bfcb8845fd15 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -257,15 +257,23 @@ static int avs_rt274_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt274_driver_ids[] = { + { + .name = "avs_rt274", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids); + static struct platform_driver avs_rt274_driver = { .probe = avs_rt274_probe, .driver = { .name = "avs_rt274", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt274_driver_ids, }; module_platform_driver(avs_rt274_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt274"); From 027ab0cab18071fa3476ffe7bb69ade551515ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:07 +0100 Subject: [PATCH 0388/7721] ASoC: Intel: avs: rt286: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-13-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt286.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 131237471e3e..28d7d86b1cc9 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -228,15 +228,23 @@ static int avs_rt286_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt286_driver_ids[] = { + { + .name = "avs_rt286", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids); + static struct platform_driver avs_rt286_driver = { .probe = avs_rt286_probe, .driver = { .name = "avs_rt286", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt286_driver_ids, }; module_platform_driver(avs_rt286_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt286"); From 3d4021f30abdb7cef51a901adc0dfc4d4ee98e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:08 +0100 Subject: [PATCH 0389/7721] ASoC: Intel: avs: rt298: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-14-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt298.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index ea32a7690c8a..80f490b9e118 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -247,15 +247,23 @@ static int avs_rt298_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt298_driver_ids[] = { + { + .name = "avs_rt298", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids); + static struct platform_driver avs_rt298_driver = { .probe = avs_rt298_probe, .driver = { .name = "avs_rt298", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt298_driver_ids, }; module_platform_driver(avs_rt298_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt298"); From 389f3c6c7ed89d53ecd83e629b7e529630cdb96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:09 +0100 Subject: [PATCH 0390/7721] ASoC: Intel: avs: rt5514: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-15-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5514.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index ad486a52e5e3..60105f453ae2 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -173,15 +173,23 @@ static int avs_rt5514_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5514_driver_ids[] = { + { + .name = "avs_rt5514", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids); + static struct platform_driver avs_rt5514_driver = { .probe = avs_rt5514_probe, .driver = { .name = "avs_rt5514", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5514_driver_ids, }; module_platform_driver(avs_rt5514_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5514"); From 5f249523d3fcf1fe28e567a17a3053ea7ff899a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:10 +0100 Subject: [PATCH 0391/7721] ASoC: Intel: avs: rt5663: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-16-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5663.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 3effd789a45e..b4762c2a7bf2 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -246,15 +246,23 @@ static int avs_rt5663_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5663_driver_ids[] = { + { + .name = "avs_rt5663", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids); + static struct platform_driver avs_rt5663_driver = { .probe = avs_rt5663_probe, .driver = { .name = "avs_rt5663", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5663_driver_ids, }; module_platform_driver(avs_rt5663_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5663"); From ba096fc618254918056061ecef32aa77c2fcaf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:11 +0100 Subject: [PATCH 0392/7721] ASoC: Intel: avs: rt5682: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-17-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5682.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 84e850c0b085..243f979fda98 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -322,16 +322,24 @@ static int avs_rt5682_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5682_driver_ids[] = { + { + .name = "avs_rt5682", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids); + static struct platform_driver avs_rt5682_driver = { .probe = avs_rt5682_probe, .driver = { .name = "avs_rt5682", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5682_driver_ids, }; module_platform_driver(avs_rt5682_driver) MODULE_AUTHOR("Cezary Rojewski "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5682"); From ca5abf5d2e1c3860382e0e33599e969cb9c9b42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 2 Nov 2023 13:47:12 +0100 Subject: [PATCH 0393/7721] ASoC: Intel: avs: ssm4567: Add proper id_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add id_table and use it instead of alias to load module. Suggested-by: Krzysztof Kozlowski Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231102124712.2549327-18-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/ssm4567.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 6bcab9deae5c..4a0e136835ff 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -181,15 +181,23 @@ static int avs_ssm4567_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_ssm4567_driver_ids[] = { + { + .name = "avs_ssm4567", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids); + static struct platform_driver avs_ssm4567_driver = { .probe = avs_ssm4567_probe, .driver = { .name = "avs_ssm4567", .pm = &snd_soc_pm_ops, }, + .id_table = avs_ssm4567_driver_ids, }; module_platform_driver(avs_ssm4567_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_ssm4567"); From 1fb1a7c4a6328aff97eeca513fe7239099c13016 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Tue, 7 Nov 2023 11:52:29 +0800 Subject: [PATCH 0394/7721] ASoC: dt-bindings: nau8821: Add DMIC slew rate. Add input with DMIC slew rate controls. Signed-off-by: Seven Lee Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231107035230.1241683-2-wtli@nuvoton.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8821.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml index 3e54abd4ca74..3380b6aa9542 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -89,6 +89,14 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 default: 3072000 + nuvoton,dmic-slew-rate: + description: The range 0 to 7 represents the speed of DMIC slew rate. + The lowest value 0 means the slowest rate and the highest value + 7 means the fastest rate. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 0 + nuvoton,left-input-single-end: description: Enable left input with single-ended settings if set. For the headset mic application, the single-ended control is @@ -127,6 +135,7 @@ examples: nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <0>; nuvoton,dmic-clk-threshold = <3072000>; + nuvoton,dmic-slew-rate= <0>; #sound-dai-cells = <0>; }; }; From 91d1a18b6381abd7a0137449fe345924072e4a32 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Tue, 7 Nov 2023 11:52:30 +0800 Subject: [PATCH 0395/7721] ASoC: nau8821: Add slew rate controls. The patch supports DMIC clock slew rate controls. Signed-off-by: Seven Lee Link: https://lore.kernel.org/r/20231107035230.1241683-3-wtli@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8821.c | 7 +++++++ sound/soc/codecs/nau8821.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index 6e1b6b26298a..012e347e6391 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -1738,6 +1738,10 @@ static int nau8821_read_device_properties(struct device *dev, &nau8821->dmic_clk_threshold); if (ret) nau8821->dmic_clk_threshold = 3072000; + ret = device_property_read_u32(dev, "nuvoton,dmic-slew-rate", + &nau8821->dmic_slew_rate); + if (ret) + nau8821->dmic_slew_rate = 0; return 0; } @@ -1797,6 +1801,9 @@ static void nau8821_init_regs(struct nau8821 *nau8821) NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1, NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64); + regmap_update_bits(regmap, NAU8821_R13_DMIC_CTRL, + NAU8821_DMIC_SLEW_MASK, nau8821->dmic_slew_rate << + NAU8821_DMIC_SLEW_SFT); if (nau8821->left_input_single_end) { regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE, NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN); diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index 00a888ed07ce..62eaad130b2e 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -236,6 +236,8 @@ #define NAU8821_DMIC_SRC_MASK (0x3 << NAU8821_DMIC_SRC_SFT) #define NAU8821_CLK_DMIC_SRC (0x2 << NAU8821_DMIC_SRC_SFT) #define NAU8821_DMIC_EN_SFT 0 +#define NAU8821_DMIC_SLEW_SFT 8 +#define NAU8821_DMIC_SLEW_MASK (0x7 << NAU8821_DMIC_SLEW_SFT) /* GPIO12_CTRL (0x1a) */ #define NAU8821_JKDET_PULL_UP (0x1 << 11) /* 0 - pull down, 1 - pull up */ @@ -573,6 +575,7 @@ struct nau8821 { int jack_eject_debounce; int fs; int dmic_clk_threshold; + int dmic_slew_rate; int key_enable; }; From ee09084fbf9fdda6bf0179bcdca52196d0cde8a1 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Wed, 1 Nov 2023 15:27:00 +0800 Subject: [PATCH 0396/7721] ASoC: codecs: ES8326: Add chip version flag The new chip version requires the addition of a new clock table. We determine which clock table to choose based on the version. Newer versions of the chip have fewer processes to go through in the headset detection, so the version flag is used to skip them. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20231101072702.91316-2-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 174 +++++++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 67 deletions(-) mode change 100644 => 100755 sound/soc/codecs/es8326.c diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c old mode 100644 new mode 100755 index 6c263086c44d..7400c3d8af23 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -198,77 +198,108 @@ struct _coeff_div { /* codec hifi mclk clock divider coefficients */ /* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */ -static const struct _coeff_div coeff_div[] = { - {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, +static const struct _coeff_div coeff_div_v0[] = { + {64, 8000, 512000, 0x60, 0x01, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {64, 44100, 2822400, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {128, 8000, 1024000, 0x60, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {128, 44100, 5644800, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, - {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f}, - {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {192, 32000, 6144000, 0xE0, 0x02, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {256, 8000, 2048000, 0x60, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {384, 32000, 12288000, 0xE0, 0x05, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {400, 48000, 19200000, 0xE9, 0x04, 0x0F, 0x6d, 0x4A, 0x0A, 0x1F, 0x1F}, - {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - - {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F}, - {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - - {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0x4A, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - - {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F}, - {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - }; -static inline int get_coeff(int mclk, int rate) +static const struct _coeff_div coeff_div_v3[] = { + {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {64, 8000, 512000, 0x60, 0x00, 0x35, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {64, 44100, 2822400, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0xB8, 0x08, 0x4f, 0x1f}, + {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + + {128, 8000, 1024000, 0x60, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x31, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {128, 44100, 5644800, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {192, 32000, 6144000, 0xE0, 0x02, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0xCA, 0x1B, 0x1F, 0x3F}, + + {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x27, 0x27}, + {256, 8000, 2048000, 0x60, 0x00, 0x31, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {384, 32000, 12288000, 0xE0, 0x02, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {400, 48000, 19200000, 0xE4, 0x04, 0x35, 0x6d, 0xCA, 0x0A, 0x1F, 0x1F}, + {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0xCA, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x5F}, + {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, +}; + +static inline int get_coeff(int mclk, int rate, int array, + const struct _coeff_div *coeff_div) { int i; - for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + for (i = 0; i < array; i++) { if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) return i; } @@ -276,6 +307,7 @@ static inline int get_coeff(int mclk, int rate) return -EINVAL; } + static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { @@ -333,11 +365,19 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + const struct _coeff_div *coeff_div; struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); u8 srate = 0; - int coeff; + int coeff, array; - coeff = get_coeff(es8326->sysclk, params_rate(params)); + if (es8326->version == 0) { + coeff_div = coeff_div_v0; + array = ARRAY_SIZE(coeff_div_v0); + } else { + coeff_div = coeff_div_v3; + array = ARRAY_SIZE(coeff_div_v3); + } + coeff = get_coeff(es8326->sysclk, params_rate(params), array, coeff_div); /* bit size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -594,7 +634,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); - if (es8326->jack_remove_retry == 1) { + if ((es8326->jack_remove_retry == 1) && (es8326->version != ES8326_VERSION_B)) { if (iface & ES8326_HPINSERT_FLAG) es8326->jack_remove_retry = 2; else @@ -628,7 +668,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) /* * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event */ - if (es8326->jack_remove_retry == 0) { + if ((es8326->jack_remove_retry == 0) && (es8326->version != ES8326_VERSION_B)) { es8326->jack_remove_retry = 1; dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", es8326->jack_remove_retry); From fc702b2c04d778d7e3a4091ebe54a86c5d0a0d96 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Wed, 1 Nov 2023 15:27:01 +0800 Subject: [PATCH 0397/7721] ASoC: codecs: ES8326: Changing initialisation and broadcasting New chip versions require new initialisation and playback processes. Changing the initialisation and playback process for better results. The old chip versions are going to work well with the new sequences. We've tested this with version_v0 and version_v3 chips under the new sequence and they both pass. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20231101072702.91316-3-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 7400c3d8af23..772788811197 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -132,6 +132,11 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, + 4, 7, 0, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, + 0, 7, 0, 0), + SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), }; @@ -156,6 +161,9 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"LHPMIX", NULL, "Left DAC"}, {"RHPMIX", NULL, "Right DAC"}, + {"HPOR", NULL, "HPOR Supply"}, + {"HPOL", NULL, "HPOL Supply"}, + {"HPOL", NULL, "LHPMIX"}, {"HPOR", NULL, "RHPMIX"}, }; @@ -307,7 +315,6 @@ static inline int get_coeff(int mclk, int rate, int array, return -EINVAL; } - static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { @@ -449,8 +456,8 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); es8326->calibrated = true; } - regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0); - regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x91); regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, ~(ES8326_MUTE)); @@ -470,8 +477,6 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, if (ret) return ret; - regmap_write(es8326->regmap, ES8326_RESET, 0x9f); - msleep(20); regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, @@ -480,19 +485,21 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00); regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20); - regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + + regmap_update_bits(es8326->regmap, ES8326_RESET, + ES8326_CSM_ON, ES8326_CSM_ON); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - break; - case SND_SOC_BIAS_OFF: - clk_disable_unprepare(es8326->mclk); regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8326->mclk); + break; } return 0; @@ -762,13 +769,15 @@ static int es8326_calibrate(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01); regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30); regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed); + regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, 0x08); regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1); regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03); regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f); - regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x03); regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88); - regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + usleep_range(15000, 20000); regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + usleep_range(15000, 20000); regmap_write(es8326->regmap, ES8326_RESET, 0xc0); usleep_range(15000, 20000); @@ -806,27 +815,27 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_RESET, 0x1f); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); usleep_range(10000, 15000); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xe9); + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4b); /* set headphone default type and detect pin */ - regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81); + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x83); regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30); /* set internal oscillator as clock source of headpone cp */ - regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84); + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x89); regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); /* clock manager reset release */ regmap_write(es8326->regmap, ES8326_RESET, 0x17); /* set headphone detection as half scan mode */ - regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08); + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30); regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00); /* enable headphone driver */ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7); usleep_range(2000, 5000); - regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab); - usleep_range(2000, 5000); - regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb); - usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xa3); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xb3); regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); @@ -840,9 +849,6 @@ static int es8326_resume(struct snd_soc_component *component) /* set ADC and DAC in low power mode */ regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); - /* force micbias on */ - regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f); - regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); /* select vdda as micbias source */ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23); @@ -870,6 +876,7 @@ static int es8326_resume(struct snd_soc_component *component) ((es8326->version == ES8326_VERSION_B) ? (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x11); es8326->jack_remove_retry = 0; es8326->hp = 0; From 8a81491adbd9b25a648704c9825adaefb0c31868 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Wed, 1 Nov 2023 15:27:02 +0800 Subject: [PATCH 0398/7721] ASoC: codecs: ES8326: Changing the headset detection time The old headset detection time is not enough for the new chip version. An error occurs with the old detection time.According to tests, 400ms is the best detection time that does not trigger an error. The delay time after the trigger is reduced by 300ms to keep the whole detection time unchanged. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20231101072702.91316-4-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 772788811197..fa890f6205e2 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -691,14 +691,14 @@ static void es8326_jack_detect_handler(struct work_struct *work) if (es8326->hp == 0) { dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n"); /* - * set auto-check mode, then restart jack_detect_work after 100ms. + * set auto-check mode, then restart jack_detect_work after 400ms. * Don't report jack status. */ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(100)); + msecs_to_jiffies(400)); es8326->hp = 1; goto exit; } @@ -748,7 +748,7 @@ static irqreturn_t es8326_irq(int irq, void *dev_id) msecs_to_jiffies(10)); else queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(600)); + msecs_to_jiffies(300)); out: return IRQ_HANDLED; From ab475966455ce285c2c9978a3e3bfe97d75ff8d4 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Fri, 3 Nov 2023 17:54:30 +0800 Subject: [PATCH 0399/7721] ASoC: SOF: mediatek: mt8195: clean up unused code Since there are some variables that are no longer being used, we remove the code that was implemented for those variables. Signed-off-by: Trevor Wu Reviewed-by: Yaochun Hung Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231103095433.10475-2-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 49 -------------------------- 1 file changed, 49 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index cac0a085f60a..8ee7ee246344 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) struct mtk_adsp_chip_info *adsp = data; int ret; - mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!mem_region) { - dev_err(dev, "no dma memory-region phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); - if (ret) { - dev_err(dev, "of_address_to_resource dma failed\n"); - return ret; - } - - dev_dbg(dev, "DMA %pR\n", &res); - - adsp->pa_shared_dram = (phys_addr_t)res.start; - adsp->shared_size = resource_size(&res); - if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { - dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", - (u32)adsp->pa_shared_dram); - return -EINVAL; - } - ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -238,26 +215,6 @@ static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info return 0; } -static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) -{ - struct device *dev = &pdev->dev; - struct mtk_adsp_chip_info *adsp = data; - - /* remap shared-dram base to be non-cachable */ - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - adsp->shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "failed to ioremap base %pa size %#x\n", - adsp->shared_dram, adsp->shared_size); - return -ENOMEM; - } - - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); - - return 0; -} - static int mt8195_run(struct snd_sof_dev *sdev) { u32 adsp_bootup_addr; @@ -338,12 +295,6 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) } priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; - ret = adsp_shared_base_ioremap(pdev, priv->adsp); - if (ret) { - dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); - goto err_adsp_sram_power_off; - } - sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; From a4de5a345cf76c6f294a906e11c2fb675a46fd3d Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Fri, 3 Nov 2023 17:54:31 +0800 Subject: [PATCH 0400/7721] ASoC: SOF: mediatek: mt8186: clean up unused code Since there are some variables that are no longer being used, we remove the code that was implemented for those variables. Signed-off-by: Trevor Wu Reviewed-by: Yaochun Hung Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231103095433.10475-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 49 -------------------------- 1 file changed, 49 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index b69fa788b16f..0d2d7d697de0 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) struct mtk_adsp_chip_info *adsp = data; int ret; - mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!mem_region) { - dev_err(dev, "no dma memory-region phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); - if (ret) { - dev_err(dev, "of_address_to_resource dma failed\n"); - return ret; - } - - dev_dbg(dev, "DMA %pR\n", &res); - - adsp->pa_shared_dram = (phys_addr_t)res.start; - adsp->shared_size = resource_size(&res); - if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { - dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", - (u32)adsp->pa_shared_dram); - return -EINVAL; - } - ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -248,26 +225,6 @@ static int adsp_memory_remap_init(struct snd_sof_dev *sdev, struct mtk_adsp_chip return 0; } -static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) -{ - struct device *dev = &pdev->dev; - struct mtk_adsp_chip_info *adsp = data; - - /* remap shared-dram base to be non-cachable */ - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - adsp->shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "failed to ioremap base %pa size %#x\n", - adsp->shared_dram, adsp->shared_size); - return -ENOMEM; - } - - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); - - return 0; -} - static int mt8186_run(struct snd_sof_dev *sdev) { u32 adsp_bootup_addr; @@ -324,12 +281,6 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; - ret = adsp_shared_base_ioremap(pdev, priv->adsp); - if (ret) { - dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); - return ret; - } - sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; sdev->bar[DSP_SECREG_BAR] = priv->adsp->va_secreg; sdev->bar[DSP_BUSREG_BAR] = priv->adsp->va_busreg; From a08ee9d00e3120e2e77a3fc093ba29070a3979be Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Fri, 3 Nov 2023 17:54:32 +0800 Subject: [PATCH 0401/7721] ASoC: SOF: mediatek: remove unused variables To prevent confusion on the follow-up platform, it is necessary to remove any unused variables within the struct mtk_adsp_chip_info. Signed-off-by: Trevor Wu Reviewed-by: Yaochun Hung Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231103095433.10475-4-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/adsp_helper.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index d41e904e6614..35527567962e 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -15,17 +15,13 @@ struct mtk_adsp_chip_info { phys_addr_t pa_sram; phys_addr_t pa_dram; /* adsp dram physical base */ - phys_addr_t pa_shared_dram; /* adsp dram physical base */ phys_addr_t pa_cfgreg; u32 sramsize; u32 dramsize; u32 cfgregsize; - u32 shared_size; void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_cfgreg; - void __iomem *shared_sram; /* part of va_sram */ - void __iomem *shared_dram; /* part of va_dram */ phys_addr_t adsp_bootup_addr; int dram_offset; /*dram offset between system and dsp view*/ From bb341f75a05238ccd35b1ec1eb1849a3955eebb3 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Mon, 6 Nov 2023 20:51:03 +0800 Subject: [PATCH 0402/7721] ASoC: sti-uniperf: Use default pcm_config instead The sti-uniperf pcm_config is the same as the default pcm_config. Since commit 43556516fffe ("ASoC: soc-generic-dmaengine-pcm: Use default config when none is given"), passing a NULL pointer could let this driver use the default config. Signed-off-by: Keguang Zhang Link: https://lore.kernel.org/r/20231106-sti-uniperf-v1-1-b2d8749cfa2e@gmail.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 2c21a86421e6..ba824f14a39c 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -461,10 +461,6 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, return 0; } -static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, -}; - static int sti_uniperiph_probe(struct platform_device *pdev) { struct sti_uniperiph_data *priv; @@ -493,8 +489,7 @@ static int sti_uniperiph_probe(struct platform_device *pdev) if (ret < 0) return ret; - return devm_snd_dmaengine_pcm_register(&pdev->dev, - &dmaengine_pcm_config, 0); + return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); } static struct platform_driver sti_uniperiph_driver = { From 79323dc80318aab6c2d05abdbcf88f09b50522c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 26 Oct 2023 13:35:49 +0200 Subject: [PATCH 0403/7721] ASoC: dapm: Simplify widget clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New DAPM widgets are created based on a provided template. When cloning the data, the name and stream name also need to be cloned. Currently the data and the names are initialized in different places. Simplify the code by having entire initialization in one place. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231026113549.1897368-1-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3844f777c87b..407a26af3eaf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -320,7 +320,8 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( - const struct snd_soc_dapm_widget *_widget) + const struct snd_soc_dapm_widget *_widget, + const char *prefix) { struct snd_soc_dapm_widget *w; @@ -328,13 +329,19 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( if (!w) return NULL; - /* - * w->name is duplicated in caller, but w->sname isn't. - * Duplicate it here if defined - */ + if (prefix) + w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, _widget->name); + else + w->name = kstrdup_const(_widget->name, GFP_KERNEL); + if (!w->name) { + kfree(w); + return NULL; + } + if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); if (!w->sname) { + kfree_const(w->name); kfree(w); return NULL; } @@ -3629,20 +3636,12 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, { enum snd_soc_dapm_direction dir; struct snd_soc_dapm_widget *w; - const char *prefix; int ret = -ENOMEM; - if ((w = dapm_cnew_widget(widget)) == NULL) + w = dapm_cnew_widget(widget, soc_dapm_prefix(dapm)); + if (!w) goto cnew_failed; - prefix = soc_dapm_prefix(dapm); - if (prefix) - w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); - else - w->name = kstrdup_const(widget->name, GFP_KERNEL); - if (!w->name) - goto name_failed; - switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, widget->name); @@ -3767,7 +3766,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, dev_err_probe(dapm->dev, ret, "ASoC: Failed to request %s\n", w->name); kfree_const(w->name); -name_failed: kfree_const(w->sname); kfree(w); cnew_failed: From 60b4a86cc6b83ccd1e4fb6a74f28a127b8025bce Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Tue, 31 Oct 2023 19:29:32 +0530 Subject: [PATCH 0404/7721] ASoC: amd: acp: Fix for indentation issue Fix indentation issue reported in acp70_pcm_resume() function. Fixes: e84db124cb21 (ASoC: amd: acp: Add pci legacy driver support for acp7.0 platform") Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20231031135949.1064581-1-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp70.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index dd384c966ae9..1d699c96f619 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -229,8 +229,8 @@ static int __maybe_unused acp70_pcm_resume(struct device *dev) } } } - spin_unlock(&adata->acp_lock); - return 0; + spin_unlock(&adata->acp_lock); + return 0; } static const struct dev_pm_ops acp70_dma_pm_ops = { From 970f88ad0026ba8427e319b1da932c161723db82 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Tue, 31 Oct 2023 19:29:33 +0530 Subject: [PATCH 0405/7721] ASoC: amd: acp: correct the format order Correct the formats order for dai driver structures. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20231031135949.1064581-2-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp70.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 1d699c96f619..0d7cdd4017e5 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -52,8 +52,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S SP Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -62,8 +62,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S SP Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, @@ -77,8 +77,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S BT Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -87,8 +87,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S BT Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, @@ -102,8 +102,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S HS Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -112,8 +112,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S HS Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, From 6d02f355c3d2fe86f503793e4df09898e9f9e703 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Nov 2023 09:09:22 -0500 Subject: [PATCH 0406/7721] ASoC: dt-bindings: Simplify port schema The use of 'definitions' is not necessary and also problematic because the dtschema tools don't process 'definitions' resulting in this spurious warning: Documentation/devicetree/bindings/sound/renesas,rsnd.example.dtb: sound@ec500000: port:endpoint: Unevaluated properties are not allowed ('phandle' was unexpected) from schema $id: http://devicetree.org/schemas/sound/renesas,rsnd.yaml# Fix this by moving the port schema to #/properties/port and referencing that directly from the 'ports' schema. Really, a binding should just always use 'ports' if multiple ports are possible. There's no benefit to supporting both forms. However, it appears there are already lots of users of this one with a single 'port' node. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231101140923.16344-2-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.yaml | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 13a5a0a10fe6..1174205286d4 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -9,20 +9,6 @@ title: Renesas R-Car Sound Driver maintainers: - Kuninori Morimoto -definitions: - port-def: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false - properties: compatible: @@ -125,7 +111,17 @@ properties: # ports is below port: - $ref: "#/definitions/port-def" + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + "^endpoint(@[0-9a-f]+)?": + $ref: audio-graph-port.yaml#/definitions/endpoint-base + properties: + playback: + $ref: /schemas/types.yaml#/definitions/phandle-array + capture: + $ref: /schemas/types.yaml#/definitions/phandle-array + unevaluatedProperties: false rcar_sound,dvc: description: DVC subnode. @@ -269,7 +265,7 @@ patternProperties: unevaluatedProperties: false patternProperties: '^port(@[0-9a-f]+)?$': - $ref: "#/definitions/port-def" + $ref: "#/properties/port" required: - compatible From 8df735701a7051825254ec7a12a661307bb7bdc1 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 11 Nov 2023 18:37:39 +0100 Subject: [PATCH 0407/7721] ASoC: tegra: convert not to use dma_request_slave_channel() dma_request_slave_channel() is deprecated. dma_request_chan() should be used directly instead. Switch to the preferred function and update the error handling accordingly. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/b78685e4103f12931ddb09c1654bc6b04b640868.1699724240.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 142e8d4eefd5..42acb56543db 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -98,8 +98,8 @@ int tegra_pcm_open(struct snd_soc_component *component, return ret; } - chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name); - if (!chan) { + chan = dma_request_chan(cpu_dai->dev, dmap->chan_name); + if (IS_ERR(chan)) { dev_err(cpu_dai->dev, "dmaengine request slave channel failed! (%s)\n", dmap->chan_name); From fc213b8d4466d1fcf39ab760979be4eac2a67635 Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Thu, 9 Nov 2023 17:37:07 +0800 Subject: [PATCH 0408/7721] ASoC: codecs: Modify the bin file parsing method Modify the aw88395_lib file so that the bin file parsing is no longer related to the chip id of the chip. Adopt the bin file data type "prof_data_type" as the differentiation between different chip bin file parsing methods. Since the chip id macro for the aw88399 is no longer defined in aw88395_reg.h, define the chip id for the aw88399 in aw88399.h Signed-off-by: Weidong Wang Link: https://lore.kernel.org/r/20231109093708.13155-1-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395_device.h | 1 + sound/soc/codecs/aw88395/aw88395_lib.c | 124 +++++++--------------- sound/soc/codecs/aw88395/aw88395_reg.h | 3 - sound/soc/codecs/aw88399.c | 1 - sound/soc/codecs/aw88399.h | 1 + 5 files changed, 42 insertions(+), 88 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h index 791c8c106557..0f750f654f3e 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.h +++ b/sound/soc/codecs/aw88395/aw88395_device.h @@ -146,6 +146,7 @@ struct aw_device { unsigned int channel; unsigned int fade_step; + unsigned int prof_data_type; struct i2c_client *i2c; struct device *dev; diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 9ebe7c510109..f25f6e0d4428 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -11,7 +11,6 @@ #include #include "aw88395_lib.h" #include "aw88395_device.h" -#include "aw88395_reg.h" #define AW88395_CRC8_POLYNOMIAL 0x8C DECLARE_CRC8_TABLE(aw_crc8_table); @@ -456,14 +455,6 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, goto parse_bin_failed; } - if (aw_dev->chip_id == AW88261_CHIP_ID) { - if (aw_bin->header_info[0].valid_data_len % 4) { - dev_err(aw_dev->dev, "bin data len get error!"); - ret = -EINVAL; - goto parse_bin_failed; - } - } - prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = data + aw_bin->header_info[0].valid_data_addr; prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = @@ -528,7 +519,7 @@ static int aw_dev_parse_dev_type(struct aw_device *aw_dev, cfg_dde[i].dev_profile); return -EINVAL; } - + aw_dev->prof_data_type = cfg_dde[i].data_type; ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); if (ret < 0) { @@ -564,6 +555,7 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, cfg_dde[i].dev_profile); return -EINVAL; } + aw_dev->prof_data_type = cfg_dde[i].data_type; ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); if (ret < 0) { @@ -582,7 +574,7 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, return 0; } -static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw_dev_cfg_get_reg_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info *all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; @@ -624,7 +616,7 @@ static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, return 0; } -static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info *all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; @@ -703,26 +695,20 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, goto exit; } - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - ret = aw88395_dev_cfg_get_valid_prof(aw_dev, all_prof_info); - if (ret < 0) - goto exit; + switch (aw_dev->prof_data_type) { + case ACF_SEC_TYPE_MULTIPLE_BIN: + ret = aw_dev_cfg_get_multiple_valid_prof(aw_dev, all_prof_info); break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - ret = aw88261_dev_cfg_get_valid_prof(aw_dev, all_prof_info); - if (ret < 0) - goto exit; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info); break; default: - dev_err(aw_dev->dev, "valid prof unsupported"); + dev_err(aw_dev->dev, "unsupport data type\n"); ret = -EINVAL; break; } - - aw_dev->prof_info.prof_name_list = profile_name; + if (!ret) + aw_dev->prof_info.prof_name_list = profile_name; exit: devm_kfree(aw_dev->dev, all_prof_info); @@ -791,39 +777,23 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; - int ret; - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; - } - ret = 0; - break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || - (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; - } - ret = 0; - break; - default: - dev_err(aw_dev->dev, "unsupported device"); - ret = -EINVAL; - break; + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; } - return ret; + if ((*scene_num) == 0) { + dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num)); + return -EINVAL; + } + + return 0; } static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, @@ -834,37 +804,23 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; - int ret; - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; - } - ret = 0; - break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || - (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; - } - ret = 0; - break; - default: - dev_err(aw_dev->dev, "unsupported device"); - ret = -EINVAL; - break; + + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; } - return ret; + if ((*scene_num) == 0) { + dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num)); + return -EINVAL; + } + + return 0; } static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev, diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index ede7deab6a9c..e64f24e97150 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -95,10 +95,7 @@ #define AW88395_TM_REG (0x7C) enum aw88395_id { - AW88399_CHIP_ID = 0x2183, AW88395_CHIP_ID = 0x2049, - AW88261_CHIP_ID = 0x2113, - AW87390_CHIP_ID = 0x76, }; #define AW88395_REG_MAX (0x7D) diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index 54f8457e8497..9fcb805bf971 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -15,7 +15,6 @@ #include #include "aw88399.h" #include "aw88395/aw88395_device.h" -#include "aw88395/aw88395_reg.h" static const struct regmap_config aw88399_remap_config = { .val_bits = 16, diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h index 4f391099d0f2..5e9cdf725d3d 100644 --- a/sound/soc/codecs/aw88399.h +++ b/sound/soc/codecs/aw88399.h @@ -491,6 +491,7 @@ #define AW88399_CRC_FW_BASE_ADDR (0x4C0) #define AW88399_ACF_FILE "aw88399_acf.bin" #define AW88399_DEV_SYSST_CHECK_MAX (10) +#define AW88399_CHIP_ID 0x2183 #define AW88399_I2C_NAME "aw88399" From c479f4989486b79cb92f0ee3b2ffcfc77fc3e443 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 9 Nov 2023 19:44:43 +0100 Subject: [PATCH 0409/7721] dt-bindings: es8328: convert to DT schema format Convert the binding to DT schema format. Note, that "IPVDD-supply" got fixed to be "HPVDD-supply" during the conversion. This was obviously a typo in the old binding. The old binding example, DT files, chip datasheet and Linux driver use HPVDD. Signed-off-by: Sebastian Reichel Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231109184453.108676-1-sebastian.reichel@collabora.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/es8328.txt | 38 --------- .../bindings/sound/everest,es8328.yaml | 77 +++++++++++++++++++ 2 files changed, 77 insertions(+), 38 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/es8328.txt create mode 100644 Documentation/devicetree/bindings/sound/everest,es8328.yaml diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt deleted file mode 100644 index 33fbf058c997..000000000000 --- a/Documentation/devicetree/bindings/sound/es8328.txt +++ /dev/null @@ -1,38 +0,0 @@ -Everest ES8328 audio CODEC - -This device supports both I2C and SPI. - -Required properties: - - - compatible : Should be "everest,es8328" or "everest,es8388" - - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V - - AVDD-supply : Regulator providing analog supply voltage 3.3V - - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V - - IPVDD-supply : Regulator providing analog output voltage 3.3V - - clocks : A 22.5792 or 11.2896 MHz clock - - reg : the I2C address of the device for I2C, the chip select number for SPI - -Pins on the device (for linking into audio routes): - - * LOUT1 - * LOUT2 - * ROUT1 - * ROUT2 - * LINPUT1 - * RINPUT1 - * LINPUT2 - * RINPUT2 - * Mic Bias - - -Example: - -codec: es8328@11 { - compatible = "everest,es8328"; - DVDD-supply = <®_3p3v>; - AVDD-supply = <®_3p3v>; - PVDD-supply = <®_3p3v>; - HPVDD-supply = <®_3p3v>; - clocks = <&clks 169>; - reg = <0x11>; -}; diff --git a/Documentation/devicetree/bindings/sound/everest,es8328.yaml b/Documentation/devicetree/bindings/sound/everest,es8328.yaml new file mode 100644 index 000000000000..a0f4670fa38c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es8328.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/everest,es8328.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Everest ES8328 audio CODEC + +description: + Everest Audio Codec, which can be connected via I2C or SPI. + Pins on the device (for linking into audio routes) are + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * RINPUT1 + * LINPUT2 + * RINPUT2 + * Mic Bias + +maintainers: + - David Yang + +properties: + compatible: + enum: + - everest,es8328 + - everest,es8388 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + items: + - description: A 22.5792 or 11.2896 MHz clock + + DVDD-supply: + description: Regulator providing digital core supply voltage 1.8 - 3.6V + + AVDD-supply: + description: Regulator providing analog supply voltage 3.3V + + PVDD-supply: + description: Regulator providing digital IO supply voltage 1.8 - 3.6V + + HPVDD-supply: + description: Regulator providing analog output voltage 3.3V + +required: + - compatible + - clocks + - DVDD-supply + - AVDD-supply + - PVDD-supply + - HPVDD-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + es8328: codec@11 { + compatible = "everest,es8328"; + reg = <0x11>; + AVDD-supply = <®_3p3v>; + DVDD-supply = <®_3p3v>; + HPVDD-supply = <®_3p3v>; + PVDD-supply = <®_3p3v>; + clocks = <&clks 169>; + }; + }; From c239b79315167d3e9b4b1e537b00e1ff5b87a317 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 6 Nov 2023 19:04:22 +0100 Subject: [PATCH 0410/7721] ASoC: dt-bindings: qcom,sm8250: add SM8550 sound card Add sound card for SM8550, which as of now looks fully compatible with SM8450. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231106180422.170492-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index e082a4fe095d..ec641fa2cd4b 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -21,6 +21,10 @@ properties: - lenovo,yoga-c630-sndcard - qcom,db845c-sndcard - const: qcom,sdm845-sndcard + - items: + - enum: + - qcom,sm8550-sndcard + - const: qcom,sm8450-sndcard - enum: - qcom,apq8016-sbc-sndcard - qcom,msm8916-qdsp6-sndcard From dc29d3d253f1f3513a916f0b4271569223860c71 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:16:10 +0100 Subject: [PATCH 0411/7721] ASoC: dt-bindings: use "soundwire" as controller's node name in examples Soundwire Devicetree bindings expect the Soundwire controller device node to be named just "soundwire". Correct examples, so the incorrect code will not be re-used. Reported-by: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231107101610.13728-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/adi,max98363.yaml | 2 +- Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml | 2 +- Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/adi,max98363.yaml b/Documentation/devicetree/bindings/sound/adi,max98363.yaml index a844b63f3930..c388cda56011 100644 --- a/Documentation/devicetree/bindings/sound/adi,max98363.yaml +++ b/Documentation/devicetree/bindings/sound/adi,max98363.yaml @@ -39,7 +39,7 @@ unevaluatedProperties: false examples: - | - soundwire-controller@3250000 { + soundwire@3250000 { #address-cells = <2>; #size-cells = <0>; reg = <0x3250000 0x2000>; diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml index ba572a7f4f3c..8e462cdf0018 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml @@ -52,7 +52,7 @@ examples: - | #include - soundwire-controller@3250000 { + soundwire@3250000 { #address-cells = <2>; #size-cells = <0>; reg = <0x3250000 0x2000>; diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml index e6723c9e312a..d717017b0fdb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml @@ -48,7 +48,7 @@ examples: - | #include - soundwire-controller { + soundwire { #address-cells = <2>; #size-cells = <0>; From 601cc04c9d73ed728b29eaddb29ae13b48b03ce7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 30 Oct 2023 12:03:51 +0300 Subject: [PATCH 0412/7721] ASoC: amd: acp: remove unnecessary NULL check The list iterator in a list_for_each_entry() loop can never be NULL. Remove the check and pull the code in a tab. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/e376a712-e0c6-446f-9e0b-c444dd795cbb@moroto.mountain Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp63.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index b871a216a6af..4d342441a650 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -283,18 +283,16 @@ static int __maybe_unused acp63_pcm_resume(struct device *dev) spin_lock(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { - if (stream) { - substream = stream->substream; - if (substream && substream->runtime) { - buf_in_frames = (substream->runtime->buffer_size); - buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); - if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); - else - restore_acp_pdm_params(substream, adata); - } + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(adata, stream); + config_acp_dma(adata, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, adata, stream); + else + restore_acp_pdm_params(substream, adata); } } spin_unlock(&adata->acp_lock); From 476b7c7e00ec3d909bacaeaf1dc53eb2b2d0c41d Mon Sep 17 00:00:00 2001 From: Bernard Metzler Date: Sat, 4 Nov 2023 08:56:43 +0100 Subject: [PATCH 0413/7721] RDMA/siw: Use ib_umem_get() to pin user pages Abandon siw private code to pin user pages during user memory registration, but use ib_umem_get() instead. This will help maintaining the driver in case of changes to the memory subsystem. Signed-off-by: Bernard Metzler Link: https://lore.kernel.org/r/20231104075643.195186-1-bmt@zurich.ibm.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw.h | 3 +- drivers/infiniband/sw/siw/siw_mem.c | 109 ++++++++++---------------- drivers/infiniband/sw/siw/siw_mem.h | 5 +- drivers/infiniband/sw/siw/siw_verbs.c | 19 +---- 4 files changed, 47 insertions(+), 89 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index cec5cccd2e75..849e496c7e67 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -121,11 +121,10 @@ struct siw_page_chunk { }; struct siw_umem { + struct ib_umem *base_mem; struct siw_page_chunk *page_chunk; int num_pages; - bool writable; u64 fp_addr; /* First page base address */ - struct mm_struct *owning_mm; }; struct siw_pble { diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c index c5f7f1669d09..2110ceb0603c 100644 --- a/drivers/infiniband/sw/siw/siw_mem.c +++ b/drivers/infiniband/sw/siw/siw_mem.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -60,28 +61,17 @@ struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index) return NULL; } -static void siw_free_plist(struct siw_page_chunk *chunk, int num_pages, - bool dirty) +void siw_umem_release(struct siw_umem *umem) { - unpin_user_pages_dirty_lock(chunk->plist, num_pages, dirty); -} - -void siw_umem_release(struct siw_umem *umem, bool dirty) -{ - struct mm_struct *mm_s = umem->owning_mm; int i, num_pages = umem->num_pages; - for (i = 0; num_pages; i++) { - int to_free = min_t(int, PAGES_PER_CHUNK, num_pages); + if (umem->base_mem) + ib_umem_release(umem->base_mem); - siw_free_plist(&umem->page_chunk[i], to_free, - umem->writable && dirty); + for (i = 0; num_pages > 0; i++) { kfree(umem->page_chunk[i].plist); - num_pages -= to_free; + num_pages -= PAGES_PER_CHUNK; } - atomic64_sub(umem->num_pages, &mm_s->pinned_vm); - - mmdrop(mm_s); kfree(umem->page_chunk); kfree(umem); } @@ -145,7 +135,7 @@ void siw_free_mem(struct kref *ref) if (!mem->is_mw && mem->mem_obj) { if (mem->is_pbl == 0) - siw_umem_release(mem->umem, true); + siw_umem_release(mem->umem); else kfree(mem->pbl); } @@ -362,18 +352,16 @@ struct siw_pbl *siw_pbl_alloc(u32 num_buf) return pbl; } -struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable) +struct siw_umem *siw_umem_get(struct ib_device *base_dev, u64 start, + u64 len, int rights) { struct siw_umem *umem; - struct mm_struct *mm_s; + struct ib_umem *base_mem; + struct sg_page_iter sg_iter; + struct sg_table *sgt; u64 first_page_va; - unsigned long mlock_limit; - unsigned int foll_flags = FOLL_LONGTERM; int num_pages, num_chunks, i, rv = 0; - if (!can_do_mlock()) - return ERR_PTR(-EPERM); - if (!len) return ERR_PTR(-EINVAL); @@ -385,65 +373,50 @@ struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable) if (!umem) return ERR_PTR(-ENOMEM); - mm_s = current->mm; - umem->owning_mm = mm_s; - umem->writable = writable; - - mmgrab(mm_s); - - if (writable) - foll_flags |= FOLL_WRITE; - - mmap_read_lock(mm_s); - - mlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - - if (atomic64_add_return(num_pages, &mm_s->pinned_vm) > mlock_limit) { - rv = -ENOMEM; - goto out_sem_up; - } - umem->fp_addr = first_page_va; - umem->page_chunk = kcalloc(num_chunks, sizeof(struct siw_page_chunk), GFP_KERNEL); if (!umem->page_chunk) { rv = -ENOMEM; - goto out_sem_up; + goto err_out; } - for (i = 0; num_pages; i++) { + base_mem = ib_umem_get(base_dev, start, len, rights); + if (IS_ERR(base_mem)) { + rv = PTR_ERR(base_mem); + siw_dbg(base_dev, "Cannot pin user memory: %d\n", rv); + goto err_out; + } + umem->fp_addr = first_page_va; + umem->base_mem = base_mem; + + sgt = &base_mem->sgt_append.sgt; + __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); + + if (!__sg_page_iter_next(&sg_iter)) { + rv = -EINVAL; + goto err_out; + } + for (i = 0; num_pages > 0; i++) { int nents = min_t(int, num_pages, PAGES_PER_CHUNK); struct page **plist = kcalloc(nents, sizeof(struct page *), GFP_KERNEL); if (!plist) { rv = -ENOMEM; - goto out_sem_up; + goto err_out; } umem->page_chunk[i].plist = plist; - while (nents) { - rv = pin_user_pages(first_page_va, nents, foll_flags, - plist); - if (rv < 0) - goto out_sem_up; - - umem->num_pages += rv; - first_page_va += rv * PAGE_SIZE; - plist += rv; - nents -= rv; - num_pages -= rv; + while (nents--) { + *plist = sg_page_iter_page(&sg_iter); + umem->num_pages++; + num_pages--; + plist++; + if (!__sg_page_iter_next(&sg_iter)) + break; } } -out_sem_up: - mmap_read_unlock(mm_s); - - if (rv > 0) - return umem; - - /* Adjust accounting for pages not pinned */ - if (num_pages) - atomic64_sub(num_pages, &mm_s->pinned_vm); - - siw_umem_release(umem, false); + return umem; +err_out: + siw_umem_release(umem); return ERR_PTR(rv); } diff --git a/drivers/infiniband/sw/siw/siw_mem.h b/drivers/infiniband/sw/siw/siw_mem.h index a2835284fe5b..e74cfcd6dbc1 100644 --- a/drivers/infiniband/sw/siw/siw_mem.h +++ b/drivers/infiniband/sw/siw/siw_mem.h @@ -6,8 +6,9 @@ #ifndef _SIW_MEM_H #define _SIW_MEM_H -struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable); -void siw_umem_release(struct siw_umem *umem, bool dirty); +struct siw_umem *siw_umem_get(struct ib_device *base_dave, u64 start, + u64 len, int rights); +void siw_umem_release(struct siw_umem *umem); struct siw_pbl *siw_pbl_alloc(u32 num_buf); dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx); struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index); diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index c5c27db9c2fe..27f7dda89e49 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -1321,8 +1321,6 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len, struct siw_umem *umem = NULL; struct siw_ureq_reg_mr ureq; struct siw_device *sdev = to_siw_dev(pd->device); - - unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK); int rv; siw_dbg_pd(pd, "start: 0x%pK, va: 0x%pK, len: %llu\n", @@ -1338,20 +1336,7 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len, rv = -EINVAL; goto err_out; } - if (mem_limit != RLIM_INFINITY) { - unsigned long num_pages = - (PAGE_ALIGN(len + (start & ~PAGE_MASK))) >> PAGE_SHIFT; - mem_limit >>= PAGE_SHIFT; - - if (num_pages > mem_limit - current->mm->locked_vm) { - siw_dbg_pd(pd, "pages req %lu, max %lu, lock %lu\n", - num_pages, mem_limit, - current->mm->locked_vm); - rv = -ENOMEM; - goto err_out; - } - } - umem = siw_umem_get(start, len, ib_access_writable(rights)); + umem = siw_umem_get(pd->device, start, len, rights); if (IS_ERR(umem)) { rv = PTR_ERR(umem); siw_dbg_pd(pd, "getting user memory failed: %d\n", rv); @@ -1404,7 +1389,7 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len, kfree_rcu(mr, rcu); } else { if (umem) - siw_umem_release(umem, false); + siw_umem_release(umem); } return ERR_PTR(rv); } From c170d4ff21a8a525d782e3d1bc58d9538d95afe6 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 2 Nov 2023 20:13:09 +0100 Subject: [PATCH 0414/7721] RDMA/hfi1: Copy userspace arrays safely Currently, memdup_user() is utilized at two positions to copy userspace arrays. This is done without overflow checks. Use the new wrapper memdup_array_user() to copy the arrays more safely. Suggested-by: Dave Airlie Signed-off-by: Philipp Stanner Link: https://lore.kernel.org/r/20231102191308.52046-2-pstanner@redhat.com Acked-by: Dennis Dalessandro Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hfi1/user_exp_rcv.c | 4 ++-- drivers/infiniband/hw/hfi1/user_sdma.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c index 6419872f95cf..cf2d29098406 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c @@ -491,8 +491,8 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, if (unlikely(tinfo->tidcnt > fd->tid_used)) return -EINVAL; - tidinfo = memdup_user(u64_to_user_ptr(tinfo->tidlist), - sizeof(tidinfo[0]) * tinfo->tidcnt); + tidinfo = memdup_array_user(u64_to_user_ptr(tinfo->tidlist), + tinfo->tidcnt, sizeof(tidinfo[0])); if (IS_ERR(tidinfo)) return PTR_ERR(tidinfo); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index 6a4aa59c0cbc..b72625283fcf 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -494,8 +494,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, * equal to the pkt count. However, there is no way to * tell at this point. */ - tmp = memdup_user(iovec[idx].iov_base, - ntids * sizeof(*req->tids)); + tmp = memdup_array_user(iovec[idx].iov_base, + ntids, sizeof(*req->tids)); if (IS_ERR(tmp)) { ret = PTR_ERR(tmp); SDMA_DBG(req, "Failed to copy %d TIDs (%d)", From 3a4304d82695015d0703ee0c3331458d22e3ba7c Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Mon, 23 Oct 2023 07:03:22 -0700 Subject: [PATCH 0415/7721] RDMA/bnxt_re: Refactor the queue index update The queue index wrap around logic is based on power of 2 size depth. All queues are created with power of 2 depth. This increases the memory usage by the driver. This change is required for the next patches that avoids the power of 2 depth requirement for each of the queues. Update the function that increments producer index and consumer index during wrap around. Also, changes the index handling across multiple functions. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1698069803-1787-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 138 ++++++++++----------- drivers/infiniband/hw/bnxt_re/qplib_fp.h | 20 ++- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 17 ++- drivers/infiniband/hw/bnxt_re/qplib_rcfw.h | 4 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.h | 37 ++++-- 6 files changed, 123 insertions(+), 95 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index abbabea7f5fa..b821c37dffd9 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -237,18 +237,15 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq) struct bnxt_qplib_hwq *hwq = &nq->hwq; struct nq_base *nqe, **nq_ptr; int budget = nq->budget; - u32 sw_cons, raw_cons; uintptr_t q_handle; u16 type; spin_lock_bh(&hwq->lock); /* Service the NQ until empty */ - raw_cons = hwq->cons; while (budget--) { - sw_cons = HWQ_CMP(raw_cons, hwq); nq_ptr = (struct nq_base **)hwq->pbl_ptr; - nqe = &nq_ptr[NQE_PG(sw_cons)][NQE_IDX(sw_cons)]; - if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements)) + nqe = &nq_ptr[NQE_PG(hwq->cons)][NQE_IDX(hwq->cons)]; + if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags)) break; /* @@ -276,7 +273,8 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq) default: break; } - raw_cons++; + bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, + 1, &nq->nq_db.dbinfo.flags); } spin_unlock_bh(&hwq->lock); } @@ -302,18 +300,16 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) struct bnxt_qplib_hwq *hwq = &nq->hwq; struct bnxt_qplib_cq *cq; int budget = nq->budget; - u32 sw_cons, raw_cons; struct nq_base *nqe; uintptr_t q_handle; + u32 hw_polled = 0; u16 type; spin_lock_bh(&hwq->lock); /* Service the NQ until empty */ - raw_cons = hwq->cons; while (budget--) { - sw_cons = HWQ_CMP(raw_cons, hwq); - nqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); - if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements)) + nqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL); + if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags)) break; /* @@ -372,12 +368,12 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) "nqe with type = 0x%x not handled\n", type); break; } - raw_cons++; + hw_polled++; + bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, + 1, &nq->nq_db.dbinfo.flags); } - if (hwq->cons != raw_cons) { - hwq->cons = raw_cons; + if (hw_polled) bnxt_qplib_ring_nq_db(&nq->nq_db.dbinfo, nq->res->cctx, true); - } spin_unlock_bh(&hwq->lock); } @@ -505,6 +501,7 @@ static int bnxt_qplib_map_nq_db(struct bnxt_qplib_nq *nq, u32 reg_offt) pdev = nq->pdev; nq_db = &nq->nq_db; + nq_db->dbinfo.flags = 0; nq_db->reg.bar_id = NQ_CONS_PCI_BAR_REGION; nq_db->reg.bar_base = pci_resource_start(pdev, nq_db->reg.bar_id); if (!nq_db->reg.bar_base) { @@ -649,7 +646,7 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, rc = -ENOMEM; goto fail; } - + srq->dbinfo.flags = 0; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_CREATE_SRQ, sizeof(req)); @@ -703,13 +700,9 @@ int bnxt_qplib_modify_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq) { struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; - u32 sw_prod, sw_cons, count = 0; + u32 count; - sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); - sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq); - - count = sw_prod > sw_cons ? sw_prod - sw_cons : - srq_hwq->max_elements - sw_cons + sw_prod; + count = __bnxt_qplib_get_avail(srq_hwq); if (count > srq->threshold) { srq->arm_req = false; bnxt_qplib_srq_arm_db(&srq->dbinfo, srq->threshold); @@ -761,7 +754,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; struct rq_wqe *srqe; struct sq_sge *hw_sge; - u32 sw_prod, sw_cons, count = 0; + u32 count = 0; int i, next; spin_lock(&srq_hwq->lock); @@ -775,8 +768,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, srq->start_idx = srq->swq[next].next_idx; spin_unlock(&srq_hwq->lock); - sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); - srqe = bnxt_qplib_get_qe(srq_hwq, sw_prod, NULL); + srqe = bnxt_qplib_get_qe(srq_hwq, srq_hwq->prod, NULL); memset(srqe, 0, srq->wqe_size); /* Calculate wqe_size16 and data_len */ for (i = 0, hw_sge = (struct sq_sge *)srqe->data; @@ -792,17 +784,10 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, srqe->wr_id[0] = cpu_to_le32((u32)next); srq->swq[next].wr_id = wqe->wr_id; - srq_hwq->prod++; + bnxt_qplib_hwq_incr_prod(&srq->dbinfo, srq_hwq, srq->dbinfo.max_slot); spin_lock(&srq_hwq->lock); - sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); - /* retaining srq_hwq->cons for this logic - * actually the lock is only required to - * read srq_hwq->cons. - */ - sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq); - count = sw_prod > sw_cons ? sw_prod - sw_cons : - srq_hwq->max_elements - sw_cons + sw_prod; + count = __bnxt_qplib_get_avail(srq_hwq); spin_unlock(&srq_hwq->lock); /* Ring DB */ bnxt_qplib_ring_prod_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ); @@ -849,6 +834,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) u32 tbl_indx; int rc; + sq->dbinfo.flags = 0; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_CREATE_QP1, sizeof(req)); @@ -885,6 +871,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) /* RQ */ if (rq->max_wqe) { + rq->dbinfo.flags = 0; hwq_attr.res = res; hwq_attr.sginfo = &rq->sg_info; hwq_attr.stride = sizeof(struct sq_sge); @@ -992,6 +979,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) u32 tbl_indx; u16 nsge; + sq->dbinfo.flags = 0; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_CREATE_QP, sizeof(req)); @@ -1040,6 +1028,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) /* RQ */ if (!qp->srq) { + rq->dbinfo.flags = 0; hwq_attr.res = res; hwq_attr.sginfo = &rq->sg_info; hwq_attr.stride = sizeof(struct sq_sge); @@ -1454,12 +1443,15 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp) { struct bnxt_qplib_hwq *cq_hwq = &cq->hwq; + u32 peek_flags, peek_cons; struct cq_base *hw_cqe; int i; + peek_flags = cq->dbinfo.flags; + peek_cons = cq_hwq->cons; for (i = 0; i < cq_hwq->max_elements; i++) { - hw_cqe = bnxt_qplib_get_qe(cq_hwq, i, NULL); - if (!CQE_CMP_VALID(hw_cqe, i, cq_hwq->max_elements)) + hw_cqe = bnxt_qplib_get_qe(cq_hwq, peek_cons, NULL); + if (!CQE_CMP_VALID(hw_cqe, peek_flags)) continue; /* * The valid test of the entry must be done first before @@ -1489,6 +1481,8 @@ static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp) default: break; } + bnxt_qplib_hwq_incr_cons(cq_hwq->max_elements, &peek_cons, + 1, &peek_flags); } } @@ -1961,7 +1955,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, bnxt_qplib_fill_psn_search(qp, wqe, swq); queue_err: bnxt_qplib_swq_mod_start(sq, wqe_idx); - bnxt_qplib_hwq_incr_prod(hwq, swq->slots); + bnxt_qplib_hwq_incr_prod(&sq->dbinfo, hwq, swq->slots); qp->wqe_cnt++; done: if (sch_handler) { @@ -2049,7 +2043,7 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp, base_hdr->wr_id[0] = cpu_to_le32(wqe_idx); queue_err: bnxt_qplib_swq_mod_start(rq, wqe_idx); - bnxt_qplib_hwq_incr_prod(hwq, swq->slots); + bnxt_qplib_hwq_incr_prod(&rq->dbinfo, hwq, swq->slots); done: if (sch_handler) { nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC); @@ -2086,6 +2080,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) return -EINVAL; } + cq->dbinfo.flags = 0; hwq_attr.res = res; hwq_attr.depth = cq->max_wqe; hwq_attr.stride = sizeof(struct cq_base); @@ -2101,7 +2096,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) req.dpi = cpu_to_le32(cq->dpi->dpi); req.cq_handle = cpu_to_le64(cq->cq_handle); - req.cq_size = cpu_to_le32(cq->hwq.max_elements); + req.cq_size = cpu_to_le32(cq->max_wqe); pbl = &cq->hwq.pbl[PBL_LVL_0]; pg_sz_lvl = (bnxt_qplib_base_pg_size(&cq->hwq) << CMDQ_CREATE_CQ_PG_SIZE_SFT); @@ -2144,6 +2139,8 @@ void bnxt_qplib_resize_cq_complete(struct bnxt_qplib_res *res, { bnxt_qplib_free_hwq(res, &cq->hwq); memcpy(&cq->hwq, &cq->resize_hwq, sizeof(cq->hwq)); + /* Reset only the cons bit in the flags */ + cq->dbinfo.flags &= ~(1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT); } int bnxt_qplib_resize_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq, @@ -2240,7 +2237,8 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp, cqe++; (*budget)--; skip_compl: - bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[last].slots); + bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, + sq->swq[last].slots, &sq->dbinfo.flags); sq->swq_last = sq->swq[last].next_idx; } *pcqe = cqe; @@ -2287,7 +2285,8 @@ static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp, cqe->wr_id = rq->swq[last].wr_id; cqe++; (*budget)--; - bnxt_qplib_hwq_incr_cons(&rq->hwq, rq->swq[last].slots); + bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, + rq->swq[last].slots, &rq->dbinfo.flags); rq->swq_last = rq->swq[last].next_idx; } *pcqe = cqe; @@ -2316,7 +2315,7 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, u32 cq_cons, u32 swq_last, u32 cqe_sq_cons) { - u32 peek_sw_cq_cons, peek_raw_cq_cons, peek_sq_cons_idx; + u32 peek_sw_cq_cons, peek_sq_cons_idx, peek_flags; struct bnxt_qplib_q *sq = &qp->sq; struct cq_req *peek_req_hwcqe; struct bnxt_qplib_qp *peek_qp; @@ -2347,16 +2346,14 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, } if (sq->condition) { /* Peek at the completions */ - peek_raw_cq_cons = cq->hwq.cons; + peek_flags = cq->dbinfo.flags; peek_sw_cq_cons = cq_cons; i = cq->hwq.max_elements; while (i--) { - peek_sw_cq_cons = HWQ_CMP((peek_sw_cq_cons), &cq->hwq); peek_hwcqe = bnxt_qplib_get_qe(&cq->hwq, peek_sw_cq_cons, NULL); /* If the next hwcqe is VALID */ - if (CQE_CMP_VALID(peek_hwcqe, peek_raw_cq_cons, - cq->hwq.max_elements)) { + if (CQE_CMP_VALID(peek_hwcqe, peek_flags)) { /* * The valid test of the entry must be done first before * reading any further. @@ -2399,8 +2396,9 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, rc = -EINVAL; goto out; } - peek_sw_cq_cons++; - peek_raw_cq_cons++; + bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements, + &peek_sw_cq_cons, + 1, &peek_flags); } dev_err(&cq->hwq.pdev->dev, "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x\n", @@ -2487,7 +2485,8 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, } } skip: - bnxt_qplib_hwq_incr_cons(&sq->hwq, swq->slots); + bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, + swq->slots, &sq->dbinfo.flags); sq->swq_last = swq->next_idx; if (sq->single) break; @@ -2514,7 +2513,8 @@ static void bnxt_qplib_release_srqe(struct bnxt_qplib_srq *srq, u32 tag) srq->swq[srq->last_idx].next_idx = (int)tag; srq->last_idx = (int)tag; srq->swq[srq->last_idx].next_idx = -1; - srq->hwq.cons++; /* Support for SRQE counter */ + bnxt_qplib_hwq_incr_cons(srq->hwq.max_elements, &srq->hwq.cons, + srq->dbinfo.max_slot, &srq->dbinfo.flags); spin_unlock(&srq->hwq.lock); } @@ -2583,7 +2583,8 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, cqe->wr_id = swq->wr_id; cqe++; (*budget)--; - bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); + bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, + swq->slots, &rq->dbinfo.flags); rq->swq_last = swq->next_idx; *pcqe = cqe; @@ -2669,7 +2670,8 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, cqe->wr_id = swq->wr_id; cqe++; (*budget)--; - bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); + bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, + swq->slots, &rq->dbinfo.flags); rq->swq_last = swq->next_idx; *pcqe = cqe; @@ -2686,14 +2688,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) { struct cq_base *hw_cqe; - u32 sw_cons, raw_cons; bool rc = true; - raw_cons = cq->hwq.cons; - sw_cons = HWQ_CMP(raw_cons, &cq->hwq); - hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL); + hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL); /* Check for Valid bit. If the CQE is valid, return false */ - rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); + rc = !CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags); return rc; } @@ -2775,7 +2774,8 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, cqe->wr_id = swq->wr_id; cqe++; (*budget)--; - bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); + bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, + swq->slots, &rq->dbinfo.flags); rq->swq_last = swq->next_idx; *pcqe = cqe; @@ -2848,7 +2848,8 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, cqe++; (*budget)--; } - bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[swq_last].slots); + bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, + sq->swq[swq_last].slots, &sq->dbinfo.flags); sq->swq_last = sq->swq[swq_last].next_idx; } *pcqe = cqe; @@ -2933,19 +2934,17 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, int num_cqes, struct bnxt_qplib_qp **lib_qp) { struct cq_base *hw_cqe; - u32 sw_cons, raw_cons; int budget, rc = 0; + u32 hw_polled = 0; u8 type; - raw_cons = cq->hwq.cons; budget = num_cqes; while (budget) { - sw_cons = HWQ_CMP(raw_cons, &cq->hwq); - hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL); + hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL); /* Check for Valid bit */ - if (!CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements)) + if (!CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags)) break; /* @@ -2960,7 +2959,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, rc = bnxt_qplib_cq_process_req(cq, (struct cq_req *)hw_cqe, &cqe, &budget, - sw_cons, lib_qp); + cq->hwq.cons, lib_qp); break; case CQ_BASE_CQE_TYPE_RES_RC: rc = bnxt_qplib_cq_process_res_rc(cq, @@ -3006,12 +3005,13 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, dev_err(&cq->hwq.pdev->dev, "process_cqe error rc = 0x%x\n", rc); } - raw_cons++; + hw_polled++; + bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements, &cq->hwq.cons, + 1, &cq->dbinfo.flags); + } - if (cq->hwq.cons != raw_cons) { - cq->hwq.cons = raw_cons; + if (hw_polled) bnxt_qplib_ring_db(&cq->dbinfo, DBC_DBC_TYPE_CQ); - } exit: return num_cqes - budget; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 404b851091ca..23c27cb42978 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -348,9 +348,21 @@ struct bnxt_qplib_qp { #define CQE_IDX(x) ((x) & CQE_MAX_IDX_PER_PG) #define ROCE_CQE_CMP_V 0 -#define CQE_CMP_VALID(hdr, raw_cons, cp_bit) \ +#define CQE_CMP_VALID(hdr, pass) \ (!!((hdr)->cqe_type_toggle & CQ_BASE_TOGGLE) == \ - !((raw_cons) & (cp_bit))) + !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) + +static inline u32 __bnxt_qplib_get_avail(struct bnxt_qplib_hwq *hwq) +{ + int cons, prod, avail; + + cons = hwq->cons; + prod = hwq->prod; + avail = cons - prod; + if (cons <= prod) + avail += hwq->depth; + return avail; +} static inline bool bnxt_qplib_queue_full(struct bnxt_qplib_q *que, u8 slots) @@ -443,9 +455,9 @@ struct bnxt_qplib_cq { #define NQE_PG(x) (((x) & ~NQE_MAX_IDX_PER_PG) / NQE_CNT_PER_PG) #define NQE_IDX(x) ((x) & NQE_MAX_IDX_PER_PG) -#define NQE_CMP_VALID(hdr, raw_cons, cp_bit) \ +#define NQE_CMP_VALID(hdr, pass) \ (!!(le32_to_cpu((hdr)->info63_v[0]) & NQ_BASE_V) == \ - !((raw_cons) & (cp_bit))) + !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) #define BNXT_QPLIB_NQE_MAX_CNT (128 * 1024) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index e47b4ca64d33..15e6d2b80c70 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -734,17 +734,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t) u32 type, budget = CREQ_ENTRY_POLL_BUDGET; struct bnxt_qplib_hwq *hwq = &creq->hwq; struct creq_base *creqe; - u32 sw_cons, raw_cons; unsigned long flags; u32 num_wakeup = 0; + u32 hw_polled = 0; /* Service the CREQ until budget is over */ spin_lock_irqsave(&hwq->lock, flags); - raw_cons = hwq->cons; while (budget > 0) { - sw_cons = HWQ_CMP(raw_cons, hwq); - creqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); - if (!CREQ_CMP_VALID(creqe, raw_cons, hwq->max_elements)) + creqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL); + if (!CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags)) break; /* The valid test of the entry must be done first before * reading any further. @@ -775,15 +773,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t) type); break; } - raw_cons++; budget--; + hw_polled++; + bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, + 1, &creq->creq_db.dbinfo.flags); } - if (hwq->cons != raw_cons) { - hwq->cons = raw_cons; + if (hw_polled) bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, true); - } spin_unlock_irqrestore(&hwq->lock, flags); if (num_wakeup) wake_up_nr(&rcfw->cmdq.waitq, num_wakeup); @@ -1113,6 +1111,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) pdev = rcfw->pdev; creq_db = &rcfw->creq.creq_db; + creq_db->dbinfo.flags = 0; creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); if (!creq_db->reg.bar_id) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 7b31bee3e000..45996e60a0d0 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -141,9 +141,9 @@ struct bnxt_qplib_crsbe { /* Allocate 1 per QP for async error notification for now */ #define BNXT_QPLIB_CREQE_MAX_CNT (64 * 1024) #define BNXT_QPLIB_CREQE_UNITS 16 /* 16-Bytes per prod unit */ -#define CREQ_CMP_VALID(hdr, raw_cons, cp_bit) \ +#define CREQ_CMP_VALID(hdr, pass) \ (!!((hdr)->v & CREQ_BASE_V) == \ - !((raw_cons) & (cp_bit))) + !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) #define CREQ_ENTRY_POLL_BUDGET 0x100 /* HWQ */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 157db6b7e119..ae2bde34e785 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -343,7 +343,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, hwq->cons = 0; hwq->pdev = pdev; hwq->depth = hwq_attr->depth; - hwq->max_elements = depth; + hwq->max_elements = hwq->depth; hwq->element_size = stride; hwq->qe_ppg = pg_size / stride; /* For direct access to the elements */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index 5949f004f785..3e3383b8a913 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -186,6 +186,14 @@ struct bnxt_qplib_db_info { struct bnxt_qplib_hwq *hwq; u32 xid; u32 max_slot; + u32 flags; +}; + +enum bnxt_qplib_db_info_flags_mask { + BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT = 0x0UL, + BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT = 0x1UL, + BNXT_QPLIB_FLAG_EPOCH_CONS_MASK = 0x1UL, + BNXT_QPLIB_FLAG_EPOCH_PROD_MASK = 0x2UL, }; /* Tables */ @@ -396,24 +404,34 @@ void bnxt_qplib_unmap_db_bar(struct bnxt_qplib_res *res); int bnxt_qplib_determine_atomics(struct pci_dev *dev); -static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_hwq *hwq, u32 cnt) +static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_db_info *dbinfo, + struct bnxt_qplib_hwq *hwq, u32 cnt) { - hwq->prod = (hwq->prod + cnt) % hwq->depth; + /* move prod and update toggle/epoch if wrap around */ + hwq->prod += cnt; + if (hwq->prod >= hwq->depth) { + hwq->prod %= hwq->depth; + dbinfo->flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT; + } } -static inline void bnxt_qplib_hwq_incr_cons(struct bnxt_qplib_hwq *hwq, - u32 cnt) +static inline void bnxt_qplib_hwq_incr_cons(u32 max_elements, u32 *cons, u32 cnt, + u32 *dbinfo_flags) { - hwq->cons = (hwq->cons + cnt) % hwq->depth; + /* move cons and update toggle/epoch if wrap around */ + *cons += cnt; + if (*cons >= max_elements) { + *cons %= max_elements; + *dbinfo_flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT; + } } static inline void bnxt_qplib_ring_db32(struct bnxt_qplib_db_info *info, bool arm) { - u32 key; + u32 key = 0; - key = info->hwq->cons & (info->hwq->max_elements - 1); - key |= (CMPL_DOORBELL_IDX_VALID | + key |= info->hwq->cons | (CMPL_DOORBELL_IDX_VALID | (CMPL_DOORBELL_KEY_CMPL & CMPL_DOORBELL_KEY_MASK)); if (!arm) key |= CMPL_DOORBELL_MASK; @@ -427,8 +445,7 @@ static inline void bnxt_qplib_ring_db(struct bnxt_qplib_db_info *info, key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type; key <<= 32; - key |= (info->hwq->cons & (info->hwq->max_elements - 1)) & - DBC_DBC_INDEX_MASK; + key |= (info->hwq->cons & DBC_DBC_INDEX_MASK); writeq(key, info->db); } From 48f996d4adf15a0a0af8b8184d3ec6042a684ea4 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Mon, 23 Oct 2023 07:03:23 -0700 Subject: [PATCH 0416/7721] RDMA/bnxt_re: Remove roundup_pow_of_two depth for all hardware queue resources Rounding up the queue depth to power of two is not a hardware requirement. In order to optimize the per connection memory usage, removing drivers implementation which round up to the queue depths to the power of 2. Implements a mask to maintain backward compatibility with older library. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1698069803-1787-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 59 ++++++++++++++++-------- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 7 +++ include/uapi/rdma/bnxt_re-abi.h | 9 ++++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index faa88d12ee86..b2467de721dc 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1184,7 +1184,8 @@ static struct bnxt_re_qp *bnxt_re_create_shadow_qp } static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp, - struct ib_qp_init_attr *init_attr) + struct ib_qp_init_attr *init_attr, + struct bnxt_re_ucontext *uctx) { struct bnxt_qplib_dev_attr *dev_attr; struct bnxt_qplib_qp *qplqp; @@ -1213,7 +1214,7 @@ static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp, /* Allocate 1 more than what's provided so posting max doesn't * mean empty. */ - entries = roundup_pow_of_two(init_attr->cap.max_recv_wr + 1); + entries = bnxt_re_init_depth(init_attr->cap.max_recv_wr + 1, uctx); rq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); rq->q_full_delta = 0; rq->sg_info.pgsize = PAGE_SIZE; @@ -1243,7 +1244,7 @@ static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp) static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, struct ib_qp_init_attr *init_attr, - struct ib_udata *udata) + struct bnxt_re_ucontext *uctx) { struct bnxt_qplib_dev_attr *dev_attr; struct bnxt_qplib_qp *qplqp; @@ -1272,7 +1273,7 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, /* Allocate 128 + 1 more than what's provided */ diff = (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) ? 0 : BNXT_QPLIB_RESERVED_QP_WRS; - entries = roundup_pow_of_two(entries + diff + 1); + entries = bnxt_re_init_depth(entries + diff + 1, uctx); sq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + diff + 1); sq->q_full_delta = diff + 1; /* @@ -1288,7 +1289,8 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, } static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp, - struct ib_qp_init_attr *init_attr) + struct ib_qp_init_attr *init_attr, + struct bnxt_re_ucontext *uctx) { struct bnxt_qplib_dev_attr *dev_attr; struct bnxt_qplib_qp *qplqp; @@ -1300,7 +1302,7 @@ static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp, dev_attr = &rdev->dev_attr; if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { - entries = roundup_pow_of_two(init_attr->cap.max_send_wr + 1); + entries = bnxt_re_init_depth(init_attr->cap.max_send_wr + 1, uctx); qplqp->sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); qplqp->sq.q_full_delta = qplqp->sq.max_wqe - @@ -1338,6 +1340,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, struct ib_udata *udata) { struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_re_ucontext *uctx; struct bnxt_qplib_qp *qplqp; struct bnxt_re_dev *rdev; struct bnxt_re_cq *cq; @@ -1347,6 +1350,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, qplqp = &qp->qplib_qp; dev_attr = &rdev->dev_attr; + uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); /* Setup misc params */ ether_addr_copy(qplqp->smac, rdev->netdev->dev_addr); qplqp->pd = &pd->qplib_pd; @@ -1388,18 +1392,18 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, } /* Setup RQ/SRQ */ - rc = bnxt_re_init_rq_attr(qp, init_attr); + rc = bnxt_re_init_rq_attr(qp, init_attr, uctx); if (rc) goto out; if (init_attr->qp_type == IB_QPT_GSI) bnxt_re_adjust_gsi_rq_attr(qp); /* Setup SQ */ - rc = bnxt_re_init_sq_attr(qp, init_attr, udata); + rc = bnxt_re_init_sq_attr(qp, init_attr, uctx); if (rc) goto out; if (init_attr->qp_type == IB_QPT_GSI) - bnxt_re_adjust_gsi_sq_attr(qp, init_attr); + bnxt_re_adjust_gsi_sq_attr(qp, init_attr, uctx); if (udata) /* This will update DPI and qp_handle */ rc = bnxt_re_init_user_qp(rdev, pd, qp, udata); @@ -1715,6 +1719,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, { struct bnxt_qplib_dev_attr *dev_attr; struct bnxt_qplib_nq *nq = NULL; + struct bnxt_re_ucontext *uctx; struct bnxt_re_dev *rdev; struct bnxt_re_srq *srq; struct bnxt_re_pd *pd; @@ -1739,13 +1744,14 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, goto exit; } + uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); srq->rdev = rdev; srq->qplib_srq.pd = &pd->qplib_pd; srq->qplib_srq.dpi = &rdev->dpi_privileged; /* Allocate 1 more than what's provided so posting max doesn't * mean empty */ - entries = roundup_pow_of_two(srq_init_attr->attr.max_wr + 1); + entries = bnxt_re_init_depth(srq_init_attr->attr.max_wr + 1, uctx); if (entries > dev_attr->max_srq_wqes + 1) entries = dev_attr->max_srq_wqes + 1; srq->qplib_srq.max_wqe = entries; @@ -2103,6 +2109,9 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic; } if (qp_attr_mask & IB_QP_CAP) { + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE | CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE | @@ -2119,7 +2128,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, "Create QP failed - max exceeded"); return -EINVAL; } - entries = roundup_pow_of_two(qp_attr->cap.max_send_wr); + entries = bnxt_re_init_depth(qp_attr->cap.max_send_wr, uctx); qp->qplib_qp.sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe - @@ -2132,7 +2141,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, qp->qplib_qp.sq.q_full_delta -= 1; qp->qplib_qp.sq.max_sge = qp_attr->cap.max_send_sge; if (qp->qplib_qp.rq.max_wqe) { - entries = roundup_pow_of_two(qp_attr->cap.max_recv_wr); + entries = bnxt_re_init_depth(qp_attr->cap.max_recv_wr, uctx); qp->qplib_qp.rq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe - @@ -2920,9 +2929,11 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, struct ib_udata *udata) { - struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibcq->device, ibdev); - struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq); + struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibcq->device, ibdev); + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; int rc, entries; int cqe = attr->cqe; struct bnxt_qplib_nq *nq = NULL; @@ -2941,7 +2952,7 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->rdev = rdev; cq->qplib_cq.cq_handle = (u64)(unsigned long)(&cq->qplib_cq); - entries = roundup_pow_of_two(cqe + 1); + entries = bnxt_re_init_depth(cqe + 1, uctx); if (entries > dev_attr->max_cq_wqes + 1) entries = dev_attr->max_cq_wqes + 1; @@ -2949,8 +2960,6 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->qplib_cq.sg_info.pgshft = PAGE_SHIFT; if (udata) { struct bnxt_re_cq_req req; - struct bnxt_re_ucontext *uctx = rdma_udata_to_drv_context( - udata, struct bnxt_re_ucontext, ib_uctx); if (ib_copy_from_udata(&req, udata, sizeof(req))) { rc = -EFAULT; goto fail; @@ -3072,12 +3081,11 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) return -EINVAL; } - entries = roundup_pow_of_two(cqe + 1); + uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + entries = bnxt_re_init_depth(cqe + 1, uctx); if (entries > dev_attr->max_cq_wqes + 1) entries = dev_attr->max_cq_wqes + 1; - uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, - ib_uctx); /* uverbs consumer */ if (ib_copy_from_udata(&req, udata, sizeof(req))) { rc = -EFAULT; @@ -4108,6 +4116,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; struct bnxt_re_user_mmap_entry *entry; struct bnxt_re_uctx_resp resp = {}; + struct bnxt_re_uctx_req ureq = {}; u32 chip_met_rev_num = 0; int rc; @@ -4157,6 +4166,16 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) if (rdev->pacing.dbr_pacing) resp.comp_mask |= BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED; + if (udata->inlen >= sizeof(ureq)) { + rc = ib_copy_from_udata(&ureq, udata, min(udata->inlen, sizeof(ureq))); + if (rc) + goto cfail; + if (ureq.comp_mask & BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT) { + resp.comp_mask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED; + uctx->cmask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED; + } + } + rc = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp))); if (rc) { ibdev_err(ibdev, "Failed to copy user context"); diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index 84715b7e7a4e..98baea98fc17 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -140,6 +140,7 @@ struct bnxt_re_ucontext { void *shpg; spinlock_t sh_lock; /* protect shpg */ struct rdma_user_mmap_entry *shpage_mmap; + u64 cmask; }; enum bnxt_re_mmap_flag { @@ -167,6 +168,12 @@ static inline u16 bnxt_re_get_rwqe_size(int nsge) return sizeof(struct rq_wqe_hdr) + (nsge * sizeof(struct sq_sge)); } +static inline u32 bnxt_re_init_depth(u32 ent, struct bnxt_re_ucontext *uctx) +{ + return uctx ? (uctx->cmask & BNXT_RE_UCNTX_CMASK_POW2_DISABLED) ? + ent : roundup_pow_of_two(ent) : ent; +} + int bnxt_re_query_device(struct ib_device *ibdev, struct ib_device_attr *ib_attr, struct ib_udata *udata); diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h index 6e7c67a0cca3..a1b896d6d940 100644 --- a/include/uapi/rdma/bnxt_re-abi.h +++ b/include/uapi/rdma/bnxt_re-abi.h @@ -54,6 +54,7 @@ enum { BNXT_RE_UCNTX_CMASK_HAVE_MODE = 0x02ULL, BNXT_RE_UCNTX_CMASK_WC_DPI_ENABLED = 0x04ULL, BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED = 0x08ULL, + BNXT_RE_UCNTX_CMASK_POW2_DISABLED = 0x10ULL, }; enum bnxt_re_wqe_mode { @@ -62,6 +63,14 @@ enum bnxt_re_wqe_mode { BNXT_QPLIB_WQE_MODE_INVALID = 0x02, }; +enum { + BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT = 0x01, +}; + +struct bnxt_re_uctx_req { + __aligned_u64 comp_mask; +}; + struct bnxt_re_uctx_resp { __u32 dev_id; __u32 max_qp; From 9aac6c05a56289be7bb2ad4b6c34486dfa2d31eb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 28 Oct 2023 21:58:39 -0700 Subject: [PATCH 0417/7721] RDMA/siw: Use crypto_shash_digest() in siw_qp_prepare_tx() Simplify siw_qp_prepare_tx() by using crypto_shash_digest() instead of an init+update+final sequence. This should also improve performance. Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20231029045839.154071-1-ebiggers@kernel.org Acked-by: Bernard Metzler Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_tx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index b2c06100cf01..64c113dc8a99 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -249,14 +249,10 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx) /* * Do complete CRC if enabled and short packet */ - if (c_tx->mpa_crc_hd) { - crypto_shash_init(c_tx->mpa_crc_hd); - if (crypto_shash_update(c_tx->mpa_crc_hd, - (u8 *)&c_tx->pkt, - c_tx->ctrl_len)) - return -EINVAL; - crypto_shash_final(c_tx->mpa_crc_hd, (u8 *)crc); - } + if (c_tx->mpa_crc_hd && + crypto_shash_digest(c_tx->mpa_crc_hd, (u8 *)&c_tx->pkt, + c_tx->ctrl_len, (u8 *)crc) != 0) + return -EINVAL; c_tx->ctrl_len += MPA_CRC_SIZE; return PKT_COMPLETE; From 057a30168175048be9e9b30f0cafd26f5043eb07 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 28 Oct 2023 21:57:56 -0700 Subject: [PATCH 0418/7721] RDMA/irdma: Use crypto_shash_digest() in irdma_ieq_check_mpacrc() Simplify irdma_ieq_check_mpacrc() by using crypto_shash_digest() instead of an init+update+final sequence. This should also improve performance. Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20231029045756.153943-1-ebiggers@kernel.org Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/utils.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index 916bfe2a91eb..0422787592d8 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -1393,17 +1393,12 @@ int irdma_ieq_check_mpacrc(struct shash_desc *desc, void *addr, u32 len, u32 val) { u32 crc = 0; - int ret; - int ret_code = 0; - crypto_shash_init(desc); - ret = crypto_shash_update(desc, addr, len); - if (!ret) - crypto_shash_final(desc, (u8 *)&crc); + crypto_shash_digest(desc, addr, len, (u8 *)&crc); if (crc != val) - ret_code = -EINVAL; + return -EINVAL; - return ret_code; + return 0; } /** From 59be90248b422f2924872de0be2867652214096a Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Thu, 9 Nov 2023 13:21:48 +0200 Subject: [PATCH 0419/7721] drm/i915/mtl: C20 state verification Add state verification for C20 as we have one for C10. V2: Use abstractation of HW readout (Gustavo) Drop MPLLA/B from message for TX and CMN parameters (Gustavo) Reviewed-by: Gustavo Sousa (v1,v2) Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231109112148.309669-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 120 +++++++++++++----- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 2 +- .../drm/i915/display/intel_modeset_verify.c | 2 +- 3 files changed, 88 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index b2ad4c6172f6..a8fa76580802 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -3017,55 +3017,33 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, return ICL_PORT_DPLL_DEFAULT; } -void intel_c10pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static void intel_c10pll_state_verify(const struct intel_crtc_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder, + struct intel_c10pll_state *mpllb_hw_state) { - 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 intel_c10pll_state mpllb_hw_state = {}; - const struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; - struct intel_encoder *encoder; - enum phy phy; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const struct intel_c10pll_state *mpllb_sw_state = &state->cx0pll_state.c10; int i; - if (DISPLAY_VER(i915) < 14) - return; - - if (!new_crtc_state->hw.active) - return; - - /* intel_get_crtc_new_encoder() only works for modeset/fastset commits */ - if (!intel_crtc_needs_modeset(new_crtc_state) && - !intel_crtc_needs_fastset(new_crtc_state)) - return; - - encoder = intel_get_crtc_new_encoder(state, new_crtc_state); - phy = intel_port_to_phy(i915, encoder->port); - - if (!intel_is_c10phy(i915, phy)) - return; - - intel_c10pll_readout_hw_state(encoder, &mpllb_hw_state); - for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { u8 expected = mpllb_sw_state->pll[i]; - I915_STATE_WARN(i915, mpllb_hw_state.pll[i] != expected, + I915_STATE_WARN(i915, mpllb_hw_state->pll[i] != expected, "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)", crtc->base.base.id, crtc->base.name, i, - expected, mpllb_hw_state.pll[i]); + expected, mpllb_hw_state->pll[i]); } - I915_STATE_WARN(i915, mpllb_hw_state.tx != mpllb_sw_state->tx, + I915_STATE_WARN(i915, mpllb_hw_state->tx != mpllb_sw_state->tx, "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)", crtc->base.base.id, crtc->base.name, - mpllb_sw_state->tx, mpllb_hw_state.tx); + mpllb_sw_state->tx, mpllb_hw_state->tx); - I915_STATE_WARN(i915, mpllb_hw_state.cmn != mpllb_sw_state->cmn, + I915_STATE_WARN(i915, mpllb_hw_state->cmn != mpllb_sw_state->cmn, "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)", crtc->base.base.id, crtc->base.name, - mpllb_sw_state->cmn, mpllb_hw_state.cmn); + mpllb_sw_state->cmn, mpllb_hw_state->cmn); } void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, @@ -3091,3 +3069,77 @@ int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, return intel_c20pll_calc_port_clock(encoder, &pll_state->c20); } + +static void intel_c20pll_state_verify(const struct intel_crtc_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder, + struct intel_c20pll_state *mpll_hw_state) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20; + bool use_mplla; + int i; + + use_mplla = intel_c20_use_mplla(mpll_hw_state->clock); + if (use_mplla) { + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) { + I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i], + "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]); + } + } else { + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) { + I915_STATE_WARN(i915, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i], + "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]); + } + } + + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) { + I915_STATE_WARN(i915, mpll_hw_state->tx[i] != mpll_sw_state->tx[i], + "[CRTC:%d:%s] mismatch in C20: Register TX[%i] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->tx[i], mpll_hw_state->tx[i]); + } + + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->cmn); i++) { + I915_STATE_WARN(i915, mpll_hw_state->cmn[i] != mpll_sw_state->cmn[i], + "[CRTC:%d:%s] mismatch in C20: Register CMN[%i] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->cmn[i], mpll_hw_state->cmn[i]); + } +} + +void intel_cx0pll_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + 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 intel_encoder *encoder; + struct intel_cx0pll_state mpll_hw_state = {}; + enum phy phy; + + if (DISPLAY_VER(i915) < 14) + return; + + if (!new_crtc_state->hw.active) + return; + + /* intel_get_crtc_new_encoder() only works for modeset/fastset commits */ + if (!intel_crtc_needs_modeset(new_crtc_state) && + !intel_crtc_needs_fastset(new_crtc_state)) + return; + + encoder = intel_get_crtc_new_encoder(state, new_crtc_state); + phy = intel_port_to_phy(i915, encoder->port); + + intel_cx0pll_readout_hw_state(encoder, &mpll_hw_state); + + if (intel_is_c10phy(i915, phy)) + intel_c10pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c10); + else + intel_c20pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c20); +} diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 222aed16e739..c6682677253a 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -38,7 +38,7 @@ int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, const struct intel_c10pll_state *hw_state); -void intel_c10pll_state_verify(struct intel_atomic_state *state, +void intel_cx0pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, const struct intel_c20pll_state *hw_state); diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 5e1c2c780412..076298a8d405 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -244,7 +244,7 @@ void intel_modeset_verify_crtc(struct intel_atomic_state *state, verify_crtc_state(state, crtc); intel_shared_dpll_state_verify(state, crtc); intel_mpllb_state_verify(state, crtc); - intel_c10pll_state_verify(state, crtc); + intel_cx0pll_state_verify(state, crtc); } void intel_modeset_verify_disabled(struct intel_atomic_state *state) From 6ebf1725e1f0bf712f547de7d9d14066279bb546 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 31 Aug 2023 13:52:34 +0200 Subject: [PATCH 0420/7721] ARM: dts: renesas: marzen: Add FLASH node Add a device node for the Spansion S29GL512N NOR FLASH on the Marzen development board. This FLASH resides in the external address space of the Local Bus State Controller. Note that as the CFI-FLASH has a run-time conflict with CPU bring-up, it will only be available when booting with SMP disabled. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/440ce3bb950c34fd57071b4eec83ad9643b682e5.1693481518.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7779-marzen.dts | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts index 08ea149b1ee6..1e192b8a73a0 100644 --- a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts @@ -215,6 +215,35 @@ &extal_clk { }; &lbsc { + flash@0 { + compatible = "cfi-flash"; + reg = <0x0 0x04000000>; + pinctrl-0 = <&flash_pins>; + pinctrl-names = "default"; + bank-width = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "uboot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "uboot-env"; + reg = <0x00040000 0x00040000>; + read-only; + }; + partition@80000 { + label = "flash"; + reg = <0x00080000 0x03f80000>; + }; + }; + }; + ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; @@ -266,6 +295,11 @@ lbsc { }; }; + flash_pins: flash { + groups = "lbsc_cs0"; + function = "lbsc"; + }; + scif2_pins: scif2 { groups = "scif2_data_c"; function = "scif2"; From d758ec1ceedb07607a005c7f2deb2fcbf2e170a4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 31 Aug 2023 13:52:35 +0200 Subject: [PATCH 0421/7721] ARM: dts: renesas: blanche: Add FLASH node Add a device node for the Spansion S29GL512S NOR FLASH on the Blanche development board. This FLASH resides in the external address space of the Local Bus State Controller. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/7edb26bc29ad58198901ae6b6f869684473bb29d.1693481518.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7792-blanche.dts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts index e793134f32a3..4ee83b8aae2a 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts @@ -182,6 +182,35 @@ &can_clk { }; &lbsc { + flash@0 { + compatible = "cfi-flash"; + reg = <0x00000000 0x04000000>; + pinctrl-0 = <&flash_pins>; + pinctrl-names = "default"; + bank-width = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "uboot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "uboot-env"; + reg = <0x00040000 0x00040000>; + read-only; + }; + partition@80000 { + label = "flash"; + reg = <0x00080000 0x03f80000>; + }; + }; + }; + ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; @@ -240,6 +269,11 @@ du1_pins: du1 { function = "du1"; }; + flash_pins: flash { + groups = "lbsc_cs0"; + function = "lbsc"; + }; + keyboard_pins: keyboard { pins = "GP_3_10", "GP_3_11", "GP_3_12", "GP_3_15", "GP_11_2"; bias-pull-up; From bfc1d3a9011a35e673b026055194dc09e734742a Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 9 Oct 2023 10:37:48 +0100 Subject: [PATCH 0422/7721] riscv: dts: renesas: Convert isa detection to new properties Convert the RZ/Five devicetrees to use the new properties "riscv,isa-base" & "riscv,isa-extensions". For compatibility with other projects, "riscv,isa" remains. Signed-off-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231009-smog-gag-3ba67e68126b@wendy Signed-off-by: Geert Uytterhoeven --- arch/riscv/boot/dts/renesas/r9a07g043f.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi index b0796015e36b..a92cfcfc021b 100644 --- a/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi +++ b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi @@ -24,6 +24,10 @@ cpu0: cpu@0 { reg = <0x0>; status = "okay"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "zicntr", "zicsr", "zifencei", + "zihpm"; mmu-type = "riscv,sv39"; i-cache-size = <0x8000>; i-cache-line-size = <0x40>; From a84e0556f1347936557dabfd875b55563de52d16 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Oct 2023 15:52:15 +0200 Subject: [PATCH 0423/7721] ARM: dts: renesas: rcar-gen2: Fix I2C bus demux node names make dtbs_check: $nodename:0: 'i2c-10' does not match '^(i2c-?)?mux' Fix this by renaming all I2C bus demultiplexer node names to "i2c-mux". Signed-off-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/63e97cb50282b3255ba9654f539b9baa8c621b30.1698068647.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7790-lager.dts | 8 ++++---- arch/arm/boot/dts/renesas/r8a7791-koelsch.dts | 6 +++--- arch/arm/boot/dts/renesas/r8a7791-porter.dts | 2 +- arch/arm/boot/dts/renesas/r8a7793-gose.dts | 4 ++-- arch/arm/boot/dts/renesas/r8a7794-alt.dts | 4 ++-- arch/arm/boot/dts/renesas/r8a7794-silk.dts | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r8a7790-lager.dts b/arch/arm/boot/dts/renesas/r8a7790-lager.dts index 4d666ad8b114..bc04567ccf8d 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-lager.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-lager.dts @@ -303,7 +303,7 @@ gpioi2c2: i2c-9 { * * IIC0/I2C0 does not appear to support fallback to GPIO. */ - i2cexio0: i2c-10 { + i2cexio0: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic0>, <&i2c0>; i2c-bus-name = "i2c-exio0"; @@ -316,7 +316,7 @@ i2cexio0: i2c-10 { * This is similar to the arangement described for i2cexio0 (above) * with a fallback to GPIO also provided. */ - i2cexio1: i2c-11 { + i2cexio1: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic1>, <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-exio1"; @@ -328,7 +328,7 @@ i2cexio1: i2c-11 { * IIC2 and I2C2 may be switched using pinmux. * A fallback to GPIO is also provided. */ - i2chdmi: i2c-12 { + i2chdmi: i2c-mux3 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -417,7 +417,7 @@ adv7612_out: endpoint { * IIC3 and I2C3 may be switched using pinmux. * IIC3/I2C3 does not appear to support fallback to GPIO. */ - i2cpwr: i2c-13 { + i2cpwr: i2c-mux4 { compatible = "i2c-demux-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&pmic_irq_pins>; diff --git a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts index 545515b41ea3..63ca0256975d 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts @@ -340,7 +340,7 @@ gpioi2c4: i2c-11 { * I2C1 is routed to EXIO connector B, pins 64 (SCL) + 66 (SDA). * A fallback to GPIO is provided. */ - i2cexio1: i2c-12 { + i2cexio1: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-exio1"; @@ -351,7 +351,7 @@ i2cexio1: i2c-12 { /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-13 { + i2chdmi: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -446,7 +446,7 @@ eeprom@50 { * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-14 { + i2cexio4: i2c-mux3 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts index ec0a20d5130d..65fd462e7b43 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts @@ -148,7 +148,7 @@ gpioi2c2: i2c-9 { /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-10 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts index 79b537b24642..58e26706a5bc 100644 --- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts +++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts @@ -324,7 +324,7 @@ gpioi2c4: i2c-10 { /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-11 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -430,7 +430,7 @@ eeprom@50 { * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-12 { + i2cexio4: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7794-alt.dts b/arch/arm/boot/dts/renesas/r8a7794-alt.dts index 08df031bc27c..c0d067df22a0 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-alt.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-alt.dts @@ -192,7 +192,7 @@ gpioi2c4: i2c-10 { /* * A fallback to GPIO is provided for I2C1. */ - i2chdmi: i2c-11 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-hdmi"; @@ -222,7 +222,7 @@ eeprom@50 { * I2C4 is routed to EXIO connector B, pins 73 (SCL) + 74 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-14 { + i2cexio4: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7794-silk.dts b/arch/arm/boot/dts/renesas/r8a7794-silk.dts index b7af1befa126..01fb06d10cbd 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-silk.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-silk.dts @@ -225,7 +225,7 @@ gpioi2c1: i2c-9 { /* * A fallback to GPIO is provided for I2C1. */ - i2chdmi: i2c-10 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-hdmi"; From cc75154c2f106d033f45c06412a1e432eda50634 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Oct 2023 15:52:16 +0200 Subject: [PATCH 0424/7721] ARM: dts: renesas: Add missing ADV751[13] power supply properties make dtbs_check: arch/arm/boot/dts/renesas/r8a7791-koelsch.dtb: hdmi@39: 'avdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm/boot/dts/renesas/r8a7791-koelsch.dtb: hdmi@39: 'dvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm/boot/dts/renesas/r8a7791-koelsch.dtb: hdmi@39: 'pvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm/boot/dts/renesas/r8a7791-koelsch.dtb: hdmi@39: 'dvdd-3v-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm/boot/dts/renesas/r8a7791-koelsch.dtb: hdmi@39: 'bgvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# ... Fix this by adding the missing power supply properties, and by adding fixed regulators where needed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/6c49fd83d327a68040f052bd9fd96fe25b0fc301.1698068647.git.geert+renesas@glider.be --- .../boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi | 15 ++++++++++++ .../renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts | 15 ++++++++++++ arch/arm/boot/dts/renesas/r8a7790-lager.dts | 15 ++++++++++++ arch/arm/boot/dts/renesas/r8a7790-stout.dts | 15 ++++++++++++ arch/arm/boot/dts/renesas/r8a7791-koelsch.dts | 24 +++++++++++++++++++ arch/arm/boot/dts/renesas/r8a7791-porter.dts | 24 +++++++++++++++++++ arch/arm/boot/dts/renesas/r8a7792-blanche.dts | 15 ++++++++++++ arch/arm/boot/dts/renesas/r8a7792-wheat.dts | 21 ++++++++++++++++ arch/arm/boot/dts/renesas/r8a7793-gose.dts | 24 +++++++++++++++++++ arch/arm/boot/dts/renesas/r8a7794-silk.dts | 15 ++++++++++++ 10 files changed, 183 insertions(+) diff --git a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi index e10f99278c77..de52218ceaa4 100644 --- a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi +++ b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi @@ -27,6 +27,15 @@ hdmi_con_out: endpoint { }; }; }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; }; &can1 { @@ -69,6 +78,12 @@ hdmi@39 { clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts index b1f679da36b2..a0b574398055 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts @@ -34,6 +34,15 @@ hdmi_con: endpoint { }; }; }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; }; &du { @@ -81,6 +90,12 @@ hdmi@39 { clock-names = "cec"; pd-gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7790-lager.dts b/arch/arm/boot/dts/renesas/r8a7790-lager.dts index bc04567ccf8d..2fba4d084001 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-lager.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-lager.dts @@ -122,6 +122,15 @@ led8 { }; }; + fixedregulator1v8: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + fixedregulator3v3: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -361,6 +370,12 @@ hdmi@39 { clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <&fixedregulator1v8>; + dvdd-supply = <&fixedregulator1v8>; + pvdd-supply = <&fixedregulator1v8>; + dvdd-3v-supply = <&fixedregulator3v3>; + bgvdd-supply = <&fixedregulator1v8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7790-stout.dts b/arch/arm/boot/dts/renesas/r8a7790-stout.dts index fe14727eefe1..f9bc5b4f019d 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-stout.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-stout.dts @@ -44,6 +44,15 @@ led5 { }; }; + fixedregulator1v8: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + fixedregulator3v3: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -296,6 +305,12 @@ hdmi@39 { clocks = <&osc4_clk>; clock-names = "cec"; + avdd-supply = <&fixedregulator1v8>; + dvdd-supply = <&fixedregulator1v8>; + pvdd-supply = <&fixedregulator1v8>; + dvdd-3v-supply = <&fixedregulator3v3>; + bgvdd-supply = <&fixedregulator1v8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts index 63ca0256975d..e9c13bb03772 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts @@ -174,6 +174,24 @@ led8 { }; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -384,6 +402,12 @@ hdmi@39 { clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts index 65fd462e7b43..7e8bc06715f6 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts @@ -47,6 +47,24 @@ memory@200000000 { reg = <2 0x00000000 0 0x40000000>; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -179,6 +197,12 @@ hdmi@39 { interrupt-parent = <&gpio3>; interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts index 4ee83b8aae2a..4f9838cf97ee 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts @@ -30,6 +30,15 @@ memory@40000000 { reg = <0 0x40000000 0 0x40000000>; }; + d1_8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -330,6 +339,12 @@ hdmi@39 { interrupt-parent = <&irqc>; interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts index f87e78fe3f6e..000f21a2a863 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts @@ -29,6 +29,15 @@ memory@40000000 { reg = <0 0x40000000 0 0x40000000>; }; + d1_8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -254,6 +263,12 @@ hdmi@3d { reg = <0x3d>, <0x4d>, <0x2d>, <0x5d>; reg-names = "main", "edid", "cec", "packet"; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -283,6 +298,12 @@ hdmi@39 { reg = <0x39>, <0x49>, <0x29>, <0x59>; reg-names = "main", "edid", "cec", "packet"; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts index 58e26706a5bc..1744fdbf9e0c 100644 --- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts +++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts @@ -165,6 +165,24 @@ led8 { }; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -368,6 +386,12 @@ hdmi@39 { interrupt-parent = <&gpio3>; interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7794-silk.dts b/arch/arm/boot/dts/renesas/r8a7794-silk.dts index 01fb06d10cbd..43d480a7f3ea 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-silk.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-silk.dts @@ -102,6 +102,15 @@ key-d { }; }; + d1_8v: regulator-d1-8v { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-d3-3v { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -256,6 +265,12 @@ hdmi@39 { interrupt-parent = <&gpio5>; interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; From 74c3bb4819071e94bfa58d13ea4825065f00587c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Oct 2023 15:52:17 +0200 Subject: [PATCH 0425/7721] arm64: dts: renesas: Add missing ADV751[13] power supply properties make dtbs_check: arch/arm64/boot/dts/renesas/r8a77990-ebisu.dtb: hdmi-encoder@39: 'avdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm64/boot/dts/renesas/r8a77990-ebisu.dtb: hdmi-encoder@39: 'dvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm64/boot/dts/renesas/r8a77990-ebisu.dtb: hdmi-encoder@39: 'pvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm64/boot/dts/renesas/r8a77990-ebisu.dtb: hdmi-encoder@39: 'dvdd-3v-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# arch/arm64/boot/dts/renesas/r8a77990-ebisu.dtb: hdmi-encoder@39: 'bgvdd-supply' is a required property from schema $id: http://devicetree.org/schemas/display/bridge/adi,adv7511.yaml# ... Fix this by adding the missing power supply properties. Add fixed regulators where needed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/4d58019b2f5f7ce026a5b671ac54aab79a58b278.1698068647.git.geert+renesas@glider.be --- arch/arm64/boot/dts/renesas/draak.dtsi | 6 ++++++ arch/arm64/boot/dts/renesas/ebisu.dtsi | 6 ++++++ arch/arm64/boot/dts/renesas/r8a77970-eagle.dts | 15 +++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/draak.dtsi b/arch/arm64/boot/dts/renesas/draak.dtsi index ef3bb835d5c0..ce57c9ad9672 100644 --- a/arch/arm64/boot/dts/renesas/draak.dtsi +++ b/arch/arm64/boot/dts/renesas/draak.dtsi @@ -374,6 +374,12 @@ hdmi-encoder@39 { interrupt-parent = <&gpio1>; interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm64/boot/dts/renesas/ebisu.dtsi b/arch/arm64/boot/dts/renesas/ebisu.dtsi index f1a5778ef115..cba2fde9dd36 100644 --- a/arch/arm64/boot/dts/renesas/ebisu.dtsi +++ b/arch/arm64/boot/dts/renesas/ebisu.dtsi @@ -403,6 +403,12 @@ hdmi-encoder@39 { interrupt-parent = <&gpio1>; interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 405404c0843d..0608dce92e40 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -29,6 +29,15 @@ chosen { stdout-path = "serial0:115200n8"; }; + d1p8: regulator-fixed { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3p3: regulator-fixed { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -166,6 +175,12 @@ hdmi@39 { interrupt-parent = <&gpio1>; interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <&d1p8>; + dvdd-supply = <&d1p8>; + pvdd-supply = <&d1p8>; + dvdd-3v-supply = <&d3p3>; + bgvdd-supply = <&d1p8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; From 788d24c59d24c446c479ecb1779eaa67325fca7c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Oct 2023 12:09:31 +0200 Subject: [PATCH 0426/7721] ARM: dts: renesas: iwg22d-sodimm: Fix stmpe node names make dtbs_check: arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dtb: stmpe811@44: 'stmpe_touchscreen' does not match any of the regexes: 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/mfd/st,stmpe.yaml# arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dtb: stmpe811@44: 'stmpe_touchscreen' does not match any of the regexes: 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/mfd/st,stmpe.yaml# Fix this by using recommended node names for the STMicroelectronics Port Expander (STMPE) device node and its subnode. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/40536ce7ca01e5acc9ed1d595f0e3a720eeb78d7.1698228434.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts index c105932f642e..24411044ef6c 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts @@ -182,7 +182,7 @@ sgtl5000: codec@a { VDDIO-supply = <®_3p3v>; }; - stmpe811@44 { + port-expander@44 { compatible = "st,stmpe811"; reg = <0x44>; interrupt-parent = <&gpio4>; @@ -197,7 +197,7 @@ stmpe811@44 { /* internal ADC reference */ st,ref-sel = <0>; - stmpe_touchscreen { + touchscreen { compatible = "st,stmpe-ts"; /* 8 sample average control */ st,ave-ctrl = <3>; From 2bbaebc5a75901404715a61e5a5c304ded5eee37 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Oct 2023 12:04:23 +0200 Subject: [PATCH 0427/7721] ARM: dts: renesas: marzen: Rename keyboard nodes make dtbs_check: arch/arm/boot/dts/renesas/r8a7779-marzen.dtb: /: keyboard-gpio: {'compatible': ['gpio-keys-polled'], 'poll-interval': [[50]], 'pinctrl-0': [[29]], 'pinctrl-names': ['default'], 'key-3': {'gpios': [[28, 19, 1]], 'linux,code': [[4]], 'label': ['SW1-3'], 'debounce-interval': [[20]]}, 'key-4': {'gpios': [[28, 20, 1]], 'linux,code': [[5]], 'label': ['SW1-4'], 'debounce-interval': [[20]]}} is not of type 'array' from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml# arch/arm/boot/dts/renesas/r8a7779-marzen.dtb: pinctrl@fffc0000: keyboard-gpio: {'pins': ['GP_0_19', 'GP_0_20'], 'bias-pull-up': True, 'phandle': [[29]]} is not of type 'array' from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml# Node names ending in "-gpio" confuse the checker. Fix this by renaming the keyboards to "keypad-0" and "keypad-1", as they are not full keyboards. Signed-off-by: Geert Uytterhoeven Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/eec1ccfb75c6215428609fdcaf3a37c75fe1fc87.1698228163.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7779-marzen.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts index 1e192b8a73a0..9b13e8d1538b 100644 --- a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts @@ -52,10 +52,10 @@ vccq_sdhi0: regulator-vccq-sdhi0 { states = <3300000 1>, <1800000 0>; }; - keyboard-irq { + keypad-0 { compatible = "gpio-keys"; - pinctrl-0 = <&keyboard_irq_pins>; + pinctrl-0 = <&keypad0_pins>; pinctrl-names = "default"; interrupt-parent = <&gpio0>; @@ -76,11 +76,11 @@ key-2 { }; }; - keyboard-gpio { + keypad-1 { compatible = "gpio-keys-polled"; poll-interval = <50>; - pinctrl-0 = <&keyboard_gpio_pins>; + pinctrl-0 = <&keypad1_pins>; pinctrl-names = "default"; key-3 { @@ -193,7 +193,7 @@ endpoint { }; &gpio0 { - keyboard-irq-hog { + keypad0-hog { gpio-hog; gpios = <17 GPIO_ACTIVE_LOW>, <18 GPIO_ACTIVE_LOW>; input; @@ -320,11 +320,11 @@ hspi0_pins: hspi0 { function = "hspi0"; }; - keyboard_irq_pins: keyboard-irq { + keypad0_pins: keypad-0 { pins = "GP_0_17", "GP_0_18"; bias-pull-up; }; - keyboard_gpio_pins: keyboard-gpio { + keypad1_pins: keypad-1 { pins = "GP_0_19", "GP_0_20"; bias-pull-up; }; From 189df98777a32c17d73e116df144e22b2ac3ae6b Mon Sep 17 00:00:00 2001 From: "xinglong.yang" Date: Thu, 9 Nov 2023 16:28:55 +0800 Subject: [PATCH 0428/7721] firmware: arm_scmi: Check beforehand if the perf domain set operations are allowed Certain SCMI performance domains may have restrictions on the set level and/or limits operation. If the set level/limits are performed by an agent who is not allowed to do so may get SCMI_ERR_SUPPORT. However, since this information about the domain is already known to the agent(OSPM here) obtained via PERF_DOMAIN_ATTRIBUTES, the agent(OSPM) can avoid making PERF_LEVEL_SET and PERF_LIMITS_SET calls to the firmware. Add those checks and return -ENOTSUPP to the caller without interacting with the firmware based on the information collected during the domain enumeration stage. Signed-off-by: xinglong.yang Link: https://lore.kernel.org/r/20231109082855.472681-1-xinglong.yang@cixtech.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/perf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index c2435be0ae1b..f5a063b0b1ab 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -504,6 +504,9 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, if (IS_ERR(dom)) return PTR_ERR(dom); + if (!dom->set_limits) + return -EOPNOTSUPP; + if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf) return -EINVAL; @@ -654,6 +657,9 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, if (IS_ERR(dom)) return PTR_ERR(dom); + if (!dom->info.set_perf) + return -EOPNOTSUPP; + if (dom->level_indexing_mode) { struct scmi_opp *opp; From 619bc6e034f3ec3ab88eba856f2f4ffdec26ea38 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 13 Nov 2023 14:32:52 +0000 Subject: [PATCH 0429/7721] firmware: arm_scmi: Populate fastchannel info only if set operations are allowed Certain SCMI performance domains may have restrictions on the set level and/or limits operation. If the SCMI domain supports fastchannel and the set operations are not allowed, then any attempts to fetch the fastchannel information for set level and/or limits operation will result in the SCMI platform returning SCMI_ERR_SUPPORT. However, since this information about the domain is already known to the agent(OSPM here) obtained via PERF_DOMAIN_ATTRIBUTES, the agent(OSPM) can avoid calls to the firmware trying to fetch the fastchannel information for the same. Add those checks and skip querying the fastchannel information from the firmware based on the information collected during the domain enumeration stage. Link: https://lore.kernel.org/r/20231113143252.37160-1-sudeep.holla@arm.com Reviewed-by: Cristian Marussi Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/perf.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index f5a063b0b1ab..36cdcfaf4324 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -762,29 +762,36 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, u32 domain, struct scmi_fc_info **p_fc) { struct scmi_fc_info *fc; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return; fc = devm_kcalloc(ph->dev, PERF_FC_MAX, sizeof(*fc), GFP_KERNEL); if (!fc) return; - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LEVEL_SET, 4, domain, - &fc[PERF_FC_LEVEL].set_addr, - &fc[PERF_FC_LEVEL].set_db); - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, PERF_LEVEL_GET, 4, domain, &fc[PERF_FC_LEVEL].get_addr, NULL); - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LIMITS_SET, 8, domain, - &fc[PERF_FC_LIMIT].set_addr, - &fc[PERF_FC_LIMIT].set_db); - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, PERF_LIMITS_GET, 8, domain, &fc[PERF_FC_LIMIT].get_addr, NULL); + if (dom->info.set_perf) + ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, + PERF_LEVEL_SET, 4, domain, + &fc[PERF_FC_LEVEL].set_addr, + &fc[PERF_FC_LEVEL].set_db); + + if (dom->set_limits) + ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, + PERF_LIMITS_SET, 8, domain, + &fc[PERF_FC_LIMIT].set_addr, + &fc[PERF_FC_LIMIT].set_db); + *p_fc = fc; } From 2a3ec40b98b46c339adb57313d3b933ee5e7a8e8 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 27 Oct 2023 08:57:18 +0200 Subject: [PATCH 0430/7721] wifi: ath11k: Defer on rproc_get failure If we already have gotten the rproc_handle (meaning the "qcom,rproc" property is defined in the devicetree), it's a valid state that the remoteproc module hasn't probed yet so we should defer probing instead of just failing to probe. This resolves a race condition when the ath11k driver probes and fails before the wpss remoteproc driver has probed, like the following: [ 6.232360] ath11k 17a10040.wifi: failed to get rproc [ 6.232366] ath11k 17a10040.wifi: failed to get rproc: -22 [ 6.232478] ath11k: probe of 17a10040.wifi failed with error -22 ... [ 6.252415] remoteproc remoteproc2: 8a00000.remoteproc is available [ 6.252776] remoteproc remoteproc2: powering up 8a00000.remoteproc [ 6.252781] remoteproc remoteproc2: Booting fw image qcom/qcm6490/fairphone5/wpss.mdt, size 7188 So, defer the probe if we hit that so we can retry later once the wpss remoteproc is available. Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-01264-QCAMSLSWPLZ-1.37886.3 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Luca Weiss Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231027-ath11k-rproc-defer-v1-1-f6b6a812cd18@fairphone.com --- drivers/net/wireless/ath/ath11k/ahb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 235336ef2a7a..f8f5e653cd03 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -803,8 +803,8 @@ static int ath11k_core_get_rproc(struct ath11k_base *ab) prproc = rproc_get_by_phandle(rproc_phandle); if (!prproc) { - ath11k_err(ab, "failed to get rproc\n"); - return -EINVAL; + ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n"); + return -EPROBE_DEFER; } ab_ahb->tgt_rproc = prproc; From 8f157593689fcffc2d9b18af9472fce764188b43 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 30 Oct 2023 14:02:25 +0800 Subject: [PATCH 0431/7721] wifi: ath11k: Remove unneeded semicolon ./drivers/net/wireless/ath/ath11k/fw.c:136:2-3: Unneeded semicolon Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7073 Signed-off-by: Yang Li Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231030060225.28987-1-yang.lee@linux.alibaba.com --- drivers/net/wireless/ath/ath11k/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c index 8f84fba29886..4e36292a79db 100644 --- a/drivers/net/wireless/ath/ath11k/fw.c +++ b/drivers/net/wireless/ath/ath11k/fw.c @@ -133,7 +133,7 @@ static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab, len -= ie_len; data += ie_len; - }; + } return 0; From fc84abc4a9b25da0559622c41045212175d6732f Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 13 Nov 2023 18:45:58 +0530 Subject: [PATCH 0432/7721] gpio: tangier: use EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS() helper Use EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS() helper to export pm_ops to GPIO_TANGIER namespace, so that they can be reused. Signed-off-by: Raag Jadav Link: https://lore.kernel.org/r/20231113131600.10828-2-raag.jadav@intel.com Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-tangier.c | 3 +++ drivers/gpio/gpio-tangier.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c index 7ce3eddaed25..52d0868476e1 100644 --- a/drivers/gpio/gpio-tangier.c +++ b/drivers/gpio/gpio-tangier.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -531,6 +532,8 @@ int tng_gpio_resume(struct device *dev) } EXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER); +EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(tng_gpio_pm_ops, tng_gpio_suspend, tng_gpio_resume, GPIO_TANGIER); + MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Pandith N "); MODULE_AUTHOR("Raag Jadav "); diff --git a/drivers/gpio/gpio-tangier.h b/drivers/gpio/gpio-tangier.h index 16c4f22908fb..333e5f79b908 100644 --- a/drivers/gpio/gpio-tangier.h +++ b/drivers/gpio/gpio-tangier.h @@ -13,6 +13,7 @@ #define _GPIO_TANGIER_H_ #include +#include #include #include @@ -114,4 +115,6 @@ int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio); int tng_gpio_suspend(struct device *dev); int tng_gpio_resume(struct device *dev); +extern const struct dev_pm_ops tng_gpio_pm_ops; + #endif /* _GPIO_TANGIER_H_ */ From 49d478b41268bb2419e44d876bf66bacc55135f5 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 13 Nov 2023 18:45:59 +0530 Subject: [PATCH 0433/7721] gpio: elkhartlake: reuse pm_ops from Intel Tangier driver Reuse tng_gpio_pm_ops from Intel Tangier driver instead of calling them through a local copy. Signed-off-by: Raag Jadav Link: https://lore.kernel.org/r/20231113131600.10828-3-raag.jadav@intel.com Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-elkhartlake.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-elkhartlake.c b/drivers/gpio/gpio-elkhartlake.c index a9c8b16215be..887c0fe99d39 100644 --- a/drivers/gpio/gpio-elkhartlake.c +++ b/drivers/gpio/gpio-elkhartlake.c @@ -55,18 +55,6 @@ static int ehl_gpio_probe(struct platform_device *pdev) return 0; } -static int ehl_gpio_suspend(struct device *dev) -{ - return tng_gpio_suspend(dev); -} - -static int ehl_gpio_resume(struct device *dev) -{ - return tng_gpio_resume(dev); -} - -static DEFINE_SIMPLE_DEV_PM_OPS(ehl_gpio_pm_ops, ehl_gpio_suspend, ehl_gpio_resume); - static const struct platform_device_id ehl_gpio_ids[] = { { "gpio-elkhartlake" }, { } @@ -76,7 +64,7 @@ MODULE_DEVICE_TABLE(platform, ehl_gpio_ids); static struct platform_driver ehl_gpio_driver = { .driver = { .name = "gpio-elkhartlake", - .pm = pm_sleep_ptr(&ehl_gpio_pm_ops), + .pm = pm_sleep_ptr(&tng_gpio_pm_ops), }, .probe = ehl_gpio_probe, .id_table = ehl_gpio_ids, From c4a79ae280a632786d6f9c7856ef27ebaa585ea7 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 13 Nov 2023 18:46:00 +0530 Subject: [PATCH 0434/7721] gpio: tangier: unexport suspend/resume handles Unexport suspend/resume handles for the lack of external users and while at it, make them static, so that they can be discarded by the compiler if not used (CONFIG_PM_SLEEP=n). Signed-off-by: Raag Jadav Link: https://lore.kernel.org/r/20231113131600.10828-4-raag.jadav@intel.com Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-tangier.c | 6 ++---- drivers/gpio/gpio-tangier.h | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c index 52d0868476e1..158fa9054e9c 100644 --- a/drivers/gpio/gpio-tangier.c +++ b/drivers/gpio/gpio-tangier.c @@ -478,7 +478,7 @@ int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio) } EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER); -int tng_gpio_suspend(struct device *dev) +static int tng_gpio_suspend(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; @@ -503,9 +503,8 @@ int tng_gpio_suspend(struct device *dev) return 0; } -EXPORT_SYMBOL_NS_GPL(tng_gpio_suspend, GPIO_TANGIER); -int tng_gpio_resume(struct device *dev) +static int tng_gpio_resume(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; @@ -530,7 +529,6 @@ int tng_gpio_resume(struct device *dev) return 0; } -EXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER); EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(tng_gpio_pm_ops, tng_gpio_suspend, tng_gpio_resume, GPIO_TANGIER); diff --git a/drivers/gpio/gpio-tangier.h b/drivers/gpio/gpio-tangier.h index 333e5f79b908..ca7ab6cf6fa5 100644 --- a/drivers/gpio/gpio-tangier.h +++ b/drivers/gpio/gpio-tangier.h @@ -112,9 +112,6 @@ struct tng_gpio { int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio); -int tng_gpio_suspend(struct device *dev); -int tng_gpio_resume(struct device *dev); - extern const struct dev_pm_ops tng_gpio_pm_ops; #endif /* _GPIO_TANGIER_H_ */ From 546ca4d35dccaca6613766ed36ccfb2b5bd63bfe Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:31 +0100 Subject: [PATCH 0435/7721] drm/gpuvm: convert WARN() to drm_WARN() variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_WARN() and drm_WARN_ON() variants to indicate drivers the context the failing VM resides in. Acked-by: Christian König Reviewed-by: Boris Brezillon Reviewed-by: Thomas Hellström Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-2-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 32 ++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_uvmm.c | 3 ++- include/drm/drm_gpuvm.h | 7 ++++++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 08c088319652..d7367a202fee 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -614,12 +614,12 @@ static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, static void __drm_gpuva_remove(struct drm_gpuva *va); static bool -drm_gpuvm_check_overflow(u64 addr, u64 range) +drm_gpuvm_check_overflow(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { u64 end; - return WARN(check_add_overflow(addr, range, &end), - "GPUVA address limited to %zu bytes.\n", sizeof(end)); + return drm_WARN(gpuvm->drm, check_add_overflow(addr, range, &end), + "GPUVA address limited to %zu bytes.\n", sizeof(end)); } static bool @@ -647,7 +647,7 @@ static bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { - return !drm_gpuvm_check_overflow(addr, range) && + return !drm_gpuvm_check_overflow(gpuvm, addr, range) && drm_gpuvm_in_mm_range(gpuvm, addr, range) && !drm_gpuvm_in_kernel_node(gpuvm, addr, range); } @@ -656,6 +656,7 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, * drm_gpuvm_init() - initialize a &drm_gpuvm * @gpuvm: pointer to the &drm_gpuvm to initialize * @name: the name of the GPU VA space + * @drm: the &drm_device this VM resides in * @start_offset: the start offset of the GPU VA space * @range: the size of the GPU VA space * @reserve_offset: the start of the kernel reserved GPU VA area @@ -668,8 +669,8 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, * &name is expected to be managed by the surrounding driver structures. */ void -drm_gpuvm_init(struct drm_gpuvm *gpuvm, - const char *name, +drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, + struct drm_device *drm, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops) @@ -677,20 +678,20 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, gpuvm->rb.tree = RB_ROOT_CACHED; INIT_LIST_HEAD(&gpuvm->rb.list); - drm_gpuvm_check_overflow(start_offset, range); + gpuvm->name = name ? name : "unknown"; + gpuvm->ops = ops; + gpuvm->drm = drm; + + drm_gpuvm_check_overflow(gpuvm, start_offset, range); gpuvm->mm_start = start_offset; gpuvm->mm_range = range; - gpuvm->name = name ? name : "unknown"; - gpuvm->ops = ops; - memset(&gpuvm->kernel_alloc_node, 0, sizeof(struct drm_gpuva)); - if (reserve_range) { gpuvm->kernel_alloc_node.va.addr = reserve_offset; gpuvm->kernel_alloc_node.va.range = reserve_range; - if (likely(!drm_gpuvm_check_overflow(reserve_offset, + if (likely(!drm_gpuvm_check_overflow(gpuvm, reserve_offset, reserve_range))) __drm_gpuva_insert(gpuvm, &gpuvm->kernel_alloc_node); } @@ -712,8 +713,8 @@ drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) if (gpuvm->kernel_alloc_node.va.range) __drm_gpuva_remove(&gpuvm->kernel_alloc_node); - WARN(!RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), - "GPUVA tree is not empty, potentially leaking memory."); + drm_WARN(gpuvm->drm, !RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), + "GPUVA tree is not empty, potentially leaking memory.\n"); } EXPORT_SYMBOL_GPL(drm_gpuvm_destroy); @@ -795,7 +796,8 @@ drm_gpuva_remove(struct drm_gpuva *va) struct drm_gpuvm *gpuvm = va->vm; if (unlikely(va == &gpuvm->kernel_alloc_node)) { - WARN(1, "Can't destroy kernel reserved node.\n"); + drm_WARN(gpuvm->drm, 1, + "Can't destroy kernel reserved node.\n"); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 5cf892c50f43..aaf5d28bd587 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1808,6 +1808,7 @@ int nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, u64 kernel_managed_addr, u64 kernel_managed_size) { + struct drm_device *drm = cli->drm->dev; int ret; u64 kernel_managed_end = kernel_managed_addr + kernel_managed_size; @@ -1836,7 +1837,7 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, uvmm->kernel_managed_addr = kernel_managed_addr; uvmm->kernel_managed_size = kernel_managed_size; - drm_gpuvm_init(&uvmm->base, cli->name, + drm_gpuvm_init(&uvmm->base, cli->name, drm, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, kernel_managed_addr, kernel_managed_size, diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index bdfafc4a7705..687fd5893624 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -29,6 +29,7 @@ #include #include +#include #include struct drm_gpuvm; @@ -201,6 +202,11 @@ struct drm_gpuvm { */ const char *name; + /** + * @drm: the &drm_device this VM lives in + */ + struct drm_device *drm; + /** * @mm_start: start of the VA space */ @@ -241,6 +247,7 @@ struct drm_gpuvm { }; void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, + struct drm_device *drm, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops); From d1adea27d0c8a08031b075f1bf4c5ce6f135ad7c Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:32 +0100 Subject: [PATCH 0436/7721] drm/gpuvm: don't always WARN in drm_gpuvm_check_overflow() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't always WARN in drm_gpuvm_check_overflow() and separate it into a drm_gpuvm_check_overflow() and a dedicated drm_gpuvm_warn_check_overflow() variant. This avoids printing warnings due to invalid userspace requests. Acked-by: Christian König Reviewed-by: Thomas Hellström Reviewed-by: Boris Brezillon Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-3-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index d7367a202fee..445767f8fbc4 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -614,12 +614,18 @@ static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, static void __drm_gpuva_remove(struct drm_gpuva *va); static bool -drm_gpuvm_check_overflow(struct drm_gpuvm *gpuvm, u64 addr, u64 range) +drm_gpuvm_check_overflow(u64 addr, u64 range) { u64 end; - return drm_WARN(gpuvm->drm, check_add_overflow(addr, range, &end), - "GPUVA address limited to %zu bytes.\n", sizeof(end)); + return check_add_overflow(addr, range, &end); +} + +static bool +drm_gpuvm_warn_check_overflow(struct drm_gpuvm *gpuvm, u64 addr, u64 range) +{ + return drm_WARN(gpuvm->drm, drm_gpuvm_check_overflow(addr, range), + "GPUVA address limited to %zu bytes.\n", sizeof(addr)); } static bool @@ -647,7 +653,7 @@ static bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { - return !drm_gpuvm_check_overflow(gpuvm, addr, range) && + return !drm_gpuvm_check_overflow(addr, range) && drm_gpuvm_in_mm_range(gpuvm, addr, range) && !drm_gpuvm_in_kernel_node(gpuvm, addr, range); } @@ -682,7 +688,7 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, gpuvm->ops = ops; gpuvm->drm = drm; - drm_gpuvm_check_overflow(gpuvm, start_offset, range); + drm_gpuvm_warn_check_overflow(gpuvm, start_offset, range); gpuvm->mm_start = start_offset; gpuvm->mm_range = range; @@ -691,8 +697,8 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, gpuvm->kernel_alloc_node.va.addr = reserve_offset; gpuvm->kernel_alloc_node.va.range = reserve_range; - if (likely(!drm_gpuvm_check_overflow(gpuvm, reserve_offset, - reserve_range))) + if (likely(!drm_gpuvm_warn_check_overflow(gpuvm, reserve_offset, + reserve_range))) __drm_gpuva_insert(gpuvm, &gpuvm->kernel_alloc_node); } } From 9297cfc9405bc6b60540b8b8aaf930b7e449e15a Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:33 +0100 Subject: [PATCH 0437/7721] drm/gpuvm: export drm_gpuvm_range_valid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drivers may use this function to validate userspace requests in advance, hence export it. Acked-by: Christian König Reviewed-by: Thomas Hellström Reviewed-by: Boris Brezillon Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-4-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 14 +++++++++++++- include/drm/drm_gpuvm.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 445767f8fbc4..2669f9bbc377 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -649,7 +649,18 @@ drm_gpuvm_in_kernel_node(struct drm_gpuvm *gpuvm, u64 addr, u64 range) return krange && addr < kend && kstart < end; } -static bool +/** + * drm_gpuvm_range_valid() - checks whether the given range is valid for the + * given &drm_gpuvm + * @gpuvm: the GPUVM to check the range for + * @addr: the base address + * @range: the range starting from the base address + * + * Checks whether the range is within the GPUVM's managed boundaries. + * + * Returns: true for a valid range, false otherwise + */ +bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { @@ -657,6 +668,7 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, drm_gpuvm_in_mm_range(gpuvm, addr, range) && !drm_gpuvm_in_kernel_node(gpuvm, addr, range); } +EXPORT_SYMBOL_GPL(drm_gpuvm_range_valid); /** * drm_gpuvm_init() - initialize a &drm_gpuvm diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 687fd5893624..13eac6f70061 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -253,6 +253,7 @@ void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, const struct drm_gpuvm_ops *ops); void drm_gpuvm_destroy(struct drm_gpuvm *gpuvm); +bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range); bool drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range); static inline struct drm_gpuva * From b41e297abd2347075ec640daf0e5da576e3d7418 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:34 +0100 Subject: [PATCH 0438/7721] drm/nouveau: make use of drm_gpuvm_range_valid() Use drm_gpuvm_range_valid() in order to validate userspace requests. Reviewed-by: Dave Airlie Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-5-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 17 +---------------- drivers/gpu/drm/nouveau/nouveau_uvmm.h | 3 --- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index aaf5d28bd587..641a911528db 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -929,25 +929,13 @@ nouveau_uvmm_sm_unmap_cleanup(struct nouveau_uvmm *uvmm, static int nouveau_uvmm_validate_range(struct nouveau_uvmm *uvmm, u64 addr, u64 range) { - u64 end = addr + range; - u64 kernel_managed_end = uvmm->kernel_managed_addr + - uvmm->kernel_managed_size; - if (addr & ~PAGE_MASK) return -EINVAL; if (range & ~PAGE_MASK) return -EINVAL; - if (end <= addr) - return -EINVAL; - - if (addr < NOUVEAU_VA_SPACE_START || - end > NOUVEAU_VA_SPACE_END) - return -EINVAL; - - if (addr < kernel_managed_end && - end > uvmm->kernel_managed_addr) + if (!drm_gpuvm_range_valid(&uvmm->base, addr, range)) return -EINVAL; return 0; @@ -1834,9 +1822,6 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, goto out_unlock; } - uvmm->kernel_managed_addr = kernel_managed_addr; - uvmm->kernel_managed_size = kernel_managed_size; - drm_gpuvm_init(&uvmm->base, cli->name, drm, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index a308c59760a5..06a0c36de392 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -14,9 +14,6 @@ struct nouveau_uvmm { struct mutex mutex; struct dma_resv resv; - u64 kernel_managed_addr; - u64 kernel_managed_size; - bool disabled; }; From bbe8458037e74b9887ba2f0f0b8084a13ade3a90 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:35 +0100 Subject: [PATCH 0439/7721] drm/gpuvm: add common dma-resv per struct drm_gpuvm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a common dma-resv for GEM objects not being used outside of this GPU-VM. This is used in a subsequent patch to generalize dma-resv, external and evicted object handling and GEM validation. Acked-by: Christian König Reviewed-by: Boris Brezillon Reviewed-by: Thomas Hellström Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-6-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 53 ++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_uvmm.c | 13 ++++++- include/drm/drm_gpuvm.h | 33 ++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 2669f9bbc377..af5805e4d7c9 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -61,6 +61,15 @@ * contained within struct drm_gpuva already. Hence, for inserting &drm_gpuva * entries from within dma-fence signalling critical sections it is enough to * pre-allocate the &drm_gpuva structures. + * + * &drm_gem_objects which are private to a single VM can share a common + * &dma_resv in order to improve locking efficiency (e.g. with &drm_exec). + * For this purpose drivers must pass a &drm_gem_object to drm_gpuvm_init(), in + * the following called 'resv object', which serves as the container of the + * GPUVM's shared &dma_resv. This resv object can be a driver specific + * &drm_gem_object, such as the &drm_gem_object containing the root page table, + * but it can also be a 'dummy' object, which can be allocated with + * drm_gpuvm_resv_object_alloc(). */ /** @@ -670,11 +679,49 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, } EXPORT_SYMBOL_GPL(drm_gpuvm_range_valid); +static void +drm_gpuvm_gem_object_free(struct drm_gem_object *obj) +{ + drm_gem_object_release(obj); + kfree(obj); +} + +static const struct drm_gem_object_funcs drm_gpuvm_object_funcs = { + .free = drm_gpuvm_gem_object_free, +}; + +/** + * drm_gpuvm_resv_object_alloc() - allocate a dummy &drm_gem_object + * @drm: the drivers &drm_device + * + * Allocates a dummy &drm_gem_object which can be passed to drm_gpuvm_init() in + * order to serve as root GEM object providing the &drm_resv shared across + * &drm_gem_objects local to a single GPUVM. + * + * Returns: the &drm_gem_object on success, NULL on failure + */ +struct drm_gem_object * +drm_gpuvm_resv_object_alloc(struct drm_device *drm) +{ + struct drm_gem_object *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return NULL; + + obj->funcs = &drm_gpuvm_object_funcs; + drm_gem_private_object_init(drm, obj, 0); + + return obj; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_resv_object_alloc); + /** * drm_gpuvm_init() - initialize a &drm_gpuvm * @gpuvm: pointer to the &drm_gpuvm to initialize * @name: the name of the GPU VA space * @drm: the &drm_device this VM resides in + * @r_obj: the resv &drm_gem_object providing the GPUVM's common &dma_resv * @start_offset: the start offset of the GPU VA space * @range: the size of the GPU VA space * @reserve_offset: the start of the kernel reserved GPU VA area @@ -689,6 +736,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_range_valid); void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, struct drm_device *drm, + struct drm_gem_object *r_obj, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops) @@ -699,6 +747,9 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, gpuvm->name = name ? name : "unknown"; gpuvm->ops = ops; gpuvm->drm = drm; + gpuvm->r_obj = r_obj; + + drm_gem_object_get(r_obj); drm_gpuvm_warn_check_overflow(gpuvm, start_offset, range); gpuvm->mm_start = start_offset; @@ -733,6 +784,8 @@ drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) drm_WARN(gpuvm->drm, !RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), "GPUVA tree is not empty, potentially leaking memory.\n"); + + drm_gem_object_put(gpuvm->r_obj); } EXPORT_SYMBOL_GPL(drm_gpuvm_destroy); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 641a911528db..f74bf30bc683 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1797,8 +1797,9 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, u64 kernel_managed_addr, u64 kernel_managed_size) { struct drm_device *drm = cli->drm->dev; - int ret; + struct drm_gem_object *r_obj; u64 kernel_managed_end = kernel_managed_addr + kernel_managed_size; + int ret; mutex_init(&uvmm->mutex); dma_resv_init(&uvmm->resv); @@ -1822,11 +1823,19 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, goto out_unlock; } - drm_gpuvm_init(&uvmm->base, cli->name, drm, + r_obj = drm_gpuvm_resv_object_alloc(drm); + if (!r_obj) { + ret = -ENOMEM; + goto out_unlock; + } + + drm_gpuvm_init(&uvmm->base, cli->name, drm, r_obj, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, kernel_managed_addr, kernel_managed_size, NULL); + /* GPUVM takes care from here on. */ + drm_gem_object_put(r_obj); ret = nvif_vmm_ctor(&cli->mmu, "uvmm", cli->vmm.vmm.object.oclass, RAW, diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 13eac6f70061..ff3377cbfe52 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -244,10 +244,16 @@ struct drm_gpuvm { * @ops: &drm_gpuvm_ops providing the split/merge steps to drivers */ const struct drm_gpuvm_ops *ops; + + /** + * @r_obj: Resv GEM object; representing the GPUVM's common &dma_resv. + */ + struct drm_gem_object *r_obj; }; void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, struct drm_device *drm, + struct drm_gem_object *r_obj, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops); @@ -256,6 +262,33 @@ void drm_gpuvm_destroy(struct drm_gpuvm *gpuvm); bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range); bool drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range); +struct drm_gem_object * +drm_gpuvm_resv_object_alloc(struct drm_device *drm); + +/** + * drm_gpuvm_resv() - returns the &drm_gpuvm's &dma_resv + * @gpuvm__: the &drm_gpuvm + * + * Returns: a pointer to the &drm_gpuvm's shared &dma_resv + */ +#define drm_gpuvm_resv(gpuvm__) ((gpuvm__)->r_obj->resv) + +/** + * drm_gpuvm_resv_obj() - returns the &drm_gem_object holding the &drm_gpuvm's + * &dma_resv + * @gpuvm__: the &drm_gpuvm + * + * Returns: a pointer to the &drm_gem_object holding the &drm_gpuvm's shared + * &dma_resv + */ +#define drm_gpuvm_resv_obj(gpuvm__) ((gpuvm__)->r_obj) + +#define drm_gpuvm_resv_held(gpuvm__) \ + dma_resv_held(drm_gpuvm_resv(gpuvm__)) + +#define drm_gpuvm_resv_assert_held(gpuvm__) \ + dma_resv_assert_held(drm_gpuvm_resv(gpuvm__)) + static inline struct drm_gpuva * __drm_gpuva_next(struct drm_gpuva *va) { From 6118411428a393fb0868bad9025d71875418058b Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:36 +0100 Subject: [PATCH 0440/7721] drm/nouveau: make use of the GPUVM's shared dma-resv DRM GEM objects private to a single GPUVM can use a shared dma-resv. Make use of the shared dma-resv of GPUVM rather than a driver specific one. The shared dma-resv originates from a "root" GEM object serving as container for the dma-resv to make it compatible with drm_exec. In order to make sure the object proving the shared dma-resv can't be freed up before the objects making use of it, let every such GEM object take a reference on it. Reviewed-by: Dave Airlie Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-7-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_bo.c | 11 +++++++++-- drivers/gpu/drm/nouveau/nouveau_bo.h | 5 +++++ drivers/gpu/drm/nouveau/nouveau_gem.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 7 ++----- drivers/gpu/drm/nouveau/nouveau_uvmm.h | 1 - 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 0f3bd187ede6..7afad86da64b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -148,10 +148,17 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) * If nouveau_bo_new() allocated this buffer, the GEM object was never * initialized, so don't attempt to release it. */ - if (bo->base.dev) + if (bo->base.dev) { + /* Gem objects not being shared with other VMs get their + * dma_resv from a root GEM object. + */ + if (nvbo->no_share) + drm_gem_object_put(nvbo->r_obj); + drm_gem_object_release(&bo->base); - else + } else { dma_resv_fini(&bo->base._resv); + } kfree(nvbo); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 07f671cf895e..70c551921a9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -26,6 +26,11 @@ struct nouveau_bo { struct list_head entry; int pbbo_index; bool validate_mapped; + + /* Root GEM object we derive the dma_resv of in case this BO is not + * shared between VMs. + */ + struct drm_gem_object *r_obj; bool no_share; /* GPU address space is independent of CPU word size */ diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index a0d303e5ce3d..49c2bcbef129 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -111,7 +111,8 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50) return 0; - if (nvbo->no_share && uvmm && &uvmm->resv != nvbo->bo.base.resv) + if (nvbo->no_share && uvmm && + drm_gpuvm_resv(&uvmm->base) != nvbo->bo.base.resv) return -EPERM; ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); @@ -245,7 +246,7 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, if (unlikely(!uvmm)) return -EINVAL; - resv = &uvmm->resv; + resv = drm_gpuvm_resv(&uvmm->base); } if (!(domain & (NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART))) @@ -288,6 +289,11 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) nvbo->valid_domains &= domain; + if (nvbo->no_share) { + nvbo->r_obj = drm_gpuvm_resv_obj(&uvmm->base); + drm_gem_object_get(nvbo->r_obj); + } + *pnvbo = nvbo; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index f74bf30bc683..8977a518de96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1802,7 +1802,6 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, int ret; mutex_init(&uvmm->mutex); - dma_resv_init(&uvmm->resv); mt_init_flags(&uvmm->region_mt, MT_FLAGS_LOCK_EXTERN); mt_set_external_lock(&uvmm->region_mt, &uvmm->mutex); @@ -1842,14 +1841,14 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, kernel_managed_addr, kernel_managed_size, NULL, 0, &cli->uvmm.vmm.vmm); if (ret) - goto out_free_gpuva_mgr; + goto out_gpuvm_fini; cli->uvmm.vmm.cli = cli; mutex_unlock(&cli->mutex); return 0; -out_free_gpuva_mgr: +out_gpuvm_fini: drm_gpuvm_destroy(&uvmm->base); out_unlock: mutex_unlock(&cli->mutex); @@ -1907,6 +1906,4 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) nouveau_vmm_fini(&uvmm->vmm); drm_gpuvm_destroy(&uvmm->base); mutex_unlock(&cli->mutex); - - dma_resv_fini(&uvmm->resv); } diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index 06a0c36de392..22607270fae0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -12,7 +12,6 @@ struct nouveau_uvmm { struct nouveau_vmm vmm; struct maple_tree region_mt; struct mutex mutex; - struct dma_resv resv; bool disabled; }; From 809ef191ee600e8bcbe2f8a769e00d2d54c16094 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:37 +0100 Subject: [PATCH 0441/7721] drm/gpuvm: add drm_gpuvm_flags to drm_gpuvm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce flags for struct drm_gpuvm, this required by subsequent commits. Acked-by: Christian König Reviewed-by: Boris Brezillon Reviewed-by: Thomas Hellström Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-8-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 3 +++ drivers/gpu/drm/nouveau/nouveau_uvmm.c | 2 +- include/drm/drm_gpuvm.h | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index af5805e4d7c9..53e2c406fb04 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -720,6 +720,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_resv_object_alloc); * drm_gpuvm_init() - initialize a &drm_gpuvm * @gpuvm: pointer to the &drm_gpuvm to initialize * @name: the name of the GPU VA space + * @flags: the &drm_gpuvm_flags for this GPUVM * @drm: the &drm_device this VM resides in * @r_obj: the resv &drm_gem_object providing the GPUVM's common &dma_resv * @start_offset: the start offset of the GPU VA space @@ -735,6 +736,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_resv_object_alloc); */ void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, + enum drm_gpuvm_flags flags, struct drm_device *drm, struct drm_gem_object *r_obj, u64 start_offset, u64 range, @@ -745,6 +747,7 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, INIT_LIST_HEAD(&gpuvm->rb.list); gpuvm->name = name ? name : "unknown"; + gpuvm->flags = flags; gpuvm->ops = ops; gpuvm->drm = drm; gpuvm->r_obj = r_obj; diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 8977a518de96..f765e3835306 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1828,7 +1828,7 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, goto out_unlock; } - drm_gpuvm_init(&uvmm->base, cli->name, drm, r_obj, + drm_gpuvm_init(&uvmm->base, cli->name, 0, drm, r_obj, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, kernel_managed_addr, kernel_managed_size, diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index ff3377cbfe52..0c2e24155a93 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -184,6 +184,16 @@ static inline bool drm_gpuva_invalidated(struct drm_gpuva *va) return va->flags & DRM_GPUVA_INVALIDATED; } +/** + * enum drm_gpuvm_flags - flags for struct drm_gpuvm + */ +enum drm_gpuvm_flags { + /** + * @DRM_GPUVM_USERBITS: user defined bits + */ + DRM_GPUVM_USERBITS = BIT(0), +}; + /** * struct drm_gpuvm - DRM GPU VA Manager * @@ -202,6 +212,11 @@ struct drm_gpuvm { */ const char *name; + /** + * @flags: the &drm_gpuvm_flags of this GPUVM + */ + enum drm_gpuvm_flags flags; + /** * @drm: the &drm_device this VM lives in */ @@ -252,6 +267,7 @@ struct drm_gpuvm { }; void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, + enum drm_gpuvm_flags flags, struct drm_device *drm, struct drm_gem_object *r_obj, u64 start_offset, u64 range, From 266f7618e761c8a6aa89dbfe43cda1b69cdbbf14 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:38 +0100 Subject: [PATCH 0442/7721] drm/nouveau: separately allocate struct nouveau_uvmm Allocate struct nouveau_uvmm separately in preparation for subsequent commits introducing reference counting for struct drm_gpuvm. While at it, get rid of nouveau_uvmm_init() as indirection of nouveau_uvmm_ioctl_vm_init() and perform some minor cleanups. Reviewed-by: Dave Airlie Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-9-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_drm.c | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 10 ++-- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 63 +++++++++++++------------- drivers/gpu/drm/nouveau/nouveau_uvmm.h | 4 -- 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 50589f982d1a..f603eaef1560 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -190,6 +190,8 @@ nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence, static void nouveau_cli_fini(struct nouveau_cli *cli) { + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm_locked(cli); + /* All our channels are dead now, which means all the fences they * own are signalled, and all callback functions have been called. * @@ -199,7 +201,8 @@ nouveau_cli_fini(struct nouveau_cli *cli) WARN_ON(!list_empty(&cli->worker)); usif_client_fini(cli); - nouveau_uvmm_fini(&cli->uvmm); + if (uvmm) + nouveau_uvmm_fini(uvmm); nouveau_sched_entity_fini(&cli->sched_entity); nouveau_vmm_fini(&cli->svm); nouveau_vmm_fini(&cli->vmm); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3666a7403e47..e514110bf391 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -93,7 +93,10 @@ struct nouveau_cli { struct nvif_mmu mmu; struct nouveau_vmm vmm; struct nouveau_vmm svm; - struct nouveau_uvmm uvmm; + struct { + struct nouveau_uvmm *ptr; + bool disabled; + } uvmm; struct nouveau_sched_entity sched_entity; @@ -121,10 +124,7 @@ struct nouveau_cli_work { static inline struct nouveau_uvmm * nouveau_cli_uvmm(struct nouveau_cli *cli) { - if (!cli || !cli->uvmm.vmm.cli) - return NULL; - - return &cli->uvmm; + return cli ? cli->uvmm.ptr : NULL; } static inline struct nouveau_uvmm * diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index f765e3835306..54be12c1272f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1636,18 +1636,6 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, return ret; } -int -nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, - void *data, - struct drm_file *file_priv) -{ - struct nouveau_cli *cli = nouveau_cli(file_priv); - struct drm_nouveau_vm_init *init = data; - - return nouveau_uvmm_init(&cli->uvmm, cli, init->kernel_managed_addr, - init->kernel_managed_size); -} - static int nouveau_uvmm_vm_bind(struct nouveau_uvmm_bind_job_args *args) { @@ -1793,17 +1781,25 @@ nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo) } int -nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, - u64 kernel_managed_addr, u64 kernel_managed_size) +nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, + void *data, + struct drm_file *file_priv) { + struct nouveau_uvmm *uvmm; + struct nouveau_cli *cli = nouveau_cli(file_priv); struct drm_device *drm = cli->drm->dev; struct drm_gem_object *r_obj; - u64 kernel_managed_end = kernel_managed_addr + kernel_managed_size; + struct drm_nouveau_vm_init *init = data; + u64 kernel_managed_end; int ret; - mutex_init(&uvmm->mutex); - mt_init_flags(&uvmm->region_mt, MT_FLAGS_LOCK_EXTERN); - mt_set_external_lock(&uvmm->region_mt, &uvmm->mutex); + if (check_add_overflow(init->kernel_managed_addr, + init->kernel_managed_size, + &kernel_managed_end)) + return -EINVAL; + + if (kernel_managed_end > NOUVEAU_VA_SPACE_END) + return -EINVAL; mutex_lock(&cli->mutex); @@ -1812,44 +1808,49 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, goto out_unlock; } - if (kernel_managed_end <= kernel_managed_addr) { - ret = -EINVAL; - goto out_unlock; - } - - if (kernel_managed_end > NOUVEAU_VA_SPACE_END) { - ret = -EINVAL; + uvmm = kzalloc(sizeof(*uvmm), GFP_KERNEL); + if (!uvmm) { + ret = -ENOMEM; goto out_unlock; } r_obj = drm_gpuvm_resv_object_alloc(drm); if (!r_obj) { + kfree(uvmm); ret = -ENOMEM; goto out_unlock; } + mutex_init(&uvmm->mutex); + mt_init_flags(&uvmm->region_mt, MT_FLAGS_LOCK_EXTERN); + mt_set_external_lock(&uvmm->region_mt, &uvmm->mutex); + drm_gpuvm_init(&uvmm->base, cli->name, 0, drm, r_obj, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, - kernel_managed_addr, kernel_managed_size, + init->kernel_managed_addr, + init->kernel_managed_size, NULL); /* GPUVM takes care from here on. */ drm_gem_object_put(r_obj); ret = nvif_vmm_ctor(&cli->mmu, "uvmm", cli->vmm.vmm.object.oclass, RAW, - kernel_managed_addr, kernel_managed_size, - NULL, 0, &cli->uvmm.vmm.vmm); + init->kernel_managed_addr, + init->kernel_managed_size, + NULL, 0, &uvmm->vmm.vmm); if (ret) goto out_gpuvm_fini; - cli->uvmm.vmm.cli = cli; + uvmm->vmm.cli = cli; + cli->uvmm.ptr = uvmm; mutex_unlock(&cli->mutex); return 0; out_gpuvm_fini: drm_gpuvm_destroy(&uvmm->base); + kfree(uvmm); out_unlock: mutex_unlock(&cli->mutex); return ret; @@ -1864,9 +1865,6 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) struct nouveau_sched_entity *entity = &cli->sched_entity; struct drm_gpuva *va, *next; - if (!cli) - return; - rmb(); /* for list_empty to work without lock */ wait_event(entity->job.wq, list_empty(&entity->job.list.head)); @@ -1905,5 +1903,6 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) mutex_lock(&cli->mutex); nouveau_vmm_fini(&uvmm->vmm); drm_gpuvm_destroy(&uvmm->base); + kfree(uvmm); mutex_unlock(&cli->mutex); } diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index 22607270fae0..f0a6d98ace4f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -12,8 +12,6 @@ struct nouveau_uvmm { struct nouveau_vmm vmm; struct maple_tree region_mt; struct mutex mutex; - - bool disabled; }; struct nouveau_uvma_region { @@ -78,8 +76,6 @@ struct nouveau_uvmm_bind_job_args { #define to_uvmm_bind_job(job) container_of((job), struct nouveau_uvmm_bind_job, base) -int nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, - u64 kernel_managed_addr, u64 kernel_managed_size); void nouveau_uvmm_fini(struct nouveau_uvmm *uvmm); void nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbov, struct nouveau_mem *mem); From 8af72338dd81d1f8667e0240bd28f5fc98b3f20d Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:39 +0100 Subject: [PATCH 0443/7721] drm/gpuvm: reference count drm_gpuvm structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement reference counting for struct drm_gpuvm. Acked-by: Christian König Reviewed-by: Thomas Hellström Reviewed-by: Boris Brezillon Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-10-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 56 +++++++++++++++++++++----- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 20 ++++++--- include/drm/drm_gpuvm.h | 31 +++++++++++++- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 53e2c406fb04..ef968eba6fe6 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -746,6 +746,8 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, gpuvm->rb.tree = RB_ROOT_CACHED; INIT_LIST_HEAD(&gpuvm->rb.list); + kref_init(&gpuvm->kref); + gpuvm->name = name ? name : "unknown"; gpuvm->flags = flags; gpuvm->ops = ops; @@ -770,15 +772,8 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, } EXPORT_SYMBOL_GPL(drm_gpuvm_init); -/** - * drm_gpuvm_destroy() - cleanup a &drm_gpuvm - * @gpuvm: pointer to the &drm_gpuvm to clean up - * - * Note that it is a bug to call this function on a manager that still - * holds GPU VA mappings. - */ -void -drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) +static void +drm_gpuvm_fini(struct drm_gpuvm *gpuvm) { gpuvm->name = NULL; @@ -790,7 +785,35 @@ drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) drm_gem_object_put(gpuvm->r_obj); } -EXPORT_SYMBOL_GPL(drm_gpuvm_destroy); + +static void +drm_gpuvm_free(struct kref *kref) +{ + struct drm_gpuvm *gpuvm = container_of(kref, struct drm_gpuvm, kref); + + drm_gpuvm_fini(gpuvm); + + if (drm_WARN_ON(gpuvm->drm, !gpuvm->ops->vm_free)) + return; + + gpuvm->ops->vm_free(gpuvm); +} + +/** + * drm_gpuvm_put() - drop a struct drm_gpuvm reference + * @gpuvm: the &drm_gpuvm to release the reference of + * + * This releases a reference to @gpuvm. + * + * This function may be called from atomic context. + */ +void +drm_gpuvm_put(struct drm_gpuvm *gpuvm) +{ + if (gpuvm) + kref_put(&gpuvm->kref, drm_gpuvm_free); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_put); static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, @@ -839,11 +862,21 @@ drm_gpuva_insert(struct drm_gpuvm *gpuvm, { u64 addr = va->va.addr; u64 range = va->va.range; + int ret; if (unlikely(!drm_gpuvm_range_valid(gpuvm, addr, range))) return -EINVAL; - return __drm_gpuva_insert(gpuvm, va); + ret = __drm_gpuva_insert(gpuvm, va); + if (likely(!ret)) + /* Take a reference of the GPUVM for the successfully inserted + * drm_gpuva. We can't take the reference in + * __drm_gpuva_insert() itself, since we don't want to increse + * the reference count for the GPUVM's kernel_alloc_node. + */ + drm_gpuvm_get(gpuvm); + + return ret; } EXPORT_SYMBOL_GPL(drm_gpuva_insert); @@ -876,6 +909,7 @@ drm_gpuva_remove(struct drm_gpuva *va) } __drm_gpuva_remove(va); + drm_gpuvm_put(va->vm); } EXPORT_SYMBOL_GPL(drm_gpuva_remove); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 54be12c1272f..cb2f06565c46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1780,6 +1780,18 @@ nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo) } } +static void +nouveau_uvmm_free(struct drm_gpuvm *gpuvm) +{ + struct nouveau_uvmm *uvmm = uvmm_from_gpuvm(gpuvm); + + kfree(uvmm); +} + +static const struct drm_gpuvm_ops gpuvm_ops = { + .vm_free = nouveau_uvmm_free, +}; + int nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, void *data, @@ -1830,7 +1842,7 @@ nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, NOUVEAU_VA_SPACE_END, init->kernel_managed_addr, init->kernel_managed_size, - NULL); + &gpuvm_ops); /* GPUVM takes care from here on. */ drm_gem_object_put(r_obj); @@ -1849,8 +1861,7 @@ nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, return 0; out_gpuvm_fini: - drm_gpuvm_destroy(&uvmm->base); - kfree(uvmm); + drm_gpuvm_put(&uvmm->base); out_unlock: mutex_unlock(&cli->mutex); return ret; @@ -1902,7 +1913,6 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) mutex_lock(&cli->mutex); nouveau_vmm_fini(&uvmm->vmm); - drm_gpuvm_destroy(&uvmm->base); - kfree(uvmm); + drm_gpuvm_put(&uvmm->base); mutex_unlock(&cli->mutex); } diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 0c2e24155a93..4e6e1fd3485a 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -247,6 +247,11 @@ struct drm_gpuvm { struct list_head list; } rb; + /** + * @kref: reference count of this object + */ + struct kref kref; + /** * @kernel_alloc_node: * @@ -273,7 +278,23 @@ void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops); -void drm_gpuvm_destroy(struct drm_gpuvm *gpuvm); + +/** + * drm_gpuvm_get() - acquire a struct drm_gpuvm reference + * @gpuvm: the &drm_gpuvm to acquire the reference of + * + * This function acquires an additional reference to @gpuvm. It is illegal to + * call this without already holding a reference. No locks required. + */ +static inline struct drm_gpuvm * +drm_gpuvm_get(struct drm_gpuvm *gpuvm) +{ + kref_get(&gpuvm->kref); + + return gpuvm; +} + +void drm_gpuvm_put(struct drm_gpuvm *gpuvm); bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range); bool drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range); @@ -673,6 +694,14 @@ static inline void drm_gpuva_init_from_op(struct drm_gpuva *va, * operations to drivers. */ struct drm_gpuvm_ops { + /** + * @vm_free: called when the last reference of a struct drm_gpuvm is + * dropped + * + * This callback is mandatory. + */ + void (*vm_free)(struct drm_gpuvm *gpuvm); + /** * @op_alloc: called when the &drm_gpuvm allocates * a struct drm_gpuva_op From 94bc2249f08e141fb4aa120bfdc392c7a5e78211 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:40 +0100 Subject: [PATCH 0444/7721] drm/gpuvm: add an abstraction for a VM / BO combination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an abstraction layer between the drm_gpuva mappings of a particular drm_gem_object and this GEM object itself. The abstraction represents a combination of a drm_gem_object and drm_gpuvm. The drm_gem_object holds a list of drm_gpuvm_bo structures (the structure representing this abstraction), while each drm_gpuvm_bo contains list of mappings of this GEM object. This has multiple advantages: 1) We can use the drm_gpuvm_bo structure to attach it to various lists of the drm_gpuvm. This is useful for tracking external and evicted objects per VM, which is introduced in subsequent patches. 2) Finding mappings of a certain drm_gem_object mapped in a certain drm_gpuvm becomes much cheaper. 3) Drivers can derive and extend the structure to easily represent driver specific states of a BO for a certain GPUVM. The idea of this abstraction was taken from amdgpu, hence the credit for this idea goes to the developers of amdgpu. Cc: Christian König Acked-by: Christian König Reviewed-by: Thomas Hellström Reviewed-by: Boris Brezillon Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-11-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 336 +++++++++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 63 +++-- include/drm/drm_gem.h | 32 +-- include/drm/drm_gpuvm.h | 185 +++++++++++++- 4 files changed, 532 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index ef968eba6fe6..7e193bca8bab 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -70,6 +70,18 @@ * &drm_gem_object, such as the &drm_gem_object containing the root page table, * but it can also be a 'dummy' object, which can be allocated with * drm_gpuvm_resv_object_alloc(). + * + * In order to connect a struct drm_gpuva its backing &drm_gem_object each + * &drm_gem_object maintains a list of &drm_gpuvm_bo structures, and each + * &drm_gpuvm_bo contains a list of &drm_gpuva structures. + * + * A &drm_gpuvm_bo is an abstraction that represents a combination of a + * &drm_gpuvm and a &drm_gem_object. Every such combination should be unique. + * This is ensured by the API through drm_gpuvm_bo_obtain() and + * drm_gpuvm_bo_obtain_prealloc() which first look into the corresponding + * &drm_gem_object list of &drm_gpuvm_bos for an existing instance of this + * particular combination. If not existent a new instance is created and linked + * to the &drm_gem_object. */ /** @@ -395,21 +407,28 @@ /** * DOC: Locking * - * Generally, the GPU VA manager does not take care of locking itself, it is - * the drivers responsibility to take care about locking. Drivers might want to - * protect the following operations: inserting, removing and iterating - * &drm_gpuva objects as well as generating all kinds of operations, such as - * split / merge or prefetch. + * In terms of managing &drm_gpuva entries DRM GPUVM does not take care of + * locking itself, it is the drivers responsibility to take care about locking. + * Drivers might want to protect the following operations: inserting, removing + * and iterating &drm_gpuva objects as well as generating all kinds of + * operations, such as split / merge or prefetch. * - * The GPU VA manager also does not take care of the locking of the backing - * &drm_gem_object buffers GPU VA lists by itself; drivers are responsible to - * enforce mutual exclusion using either the GEMs dma_resv lock or alternatively - * a driver specific external lock. For the latter see also - * drm_gem_gpuva_set_lock(). + * DRM GPUVM also does not take care of the locking of the backing + * &drm_gem_object buffers GPU VA lists and &drm_gpuvm_bo abstractions by + * itself; drivers are responsible to enforce mutual exclusion using either the + * GEMs dma_resv lock or alternatively a driver specific external lock. For the + * latter see also drm_gem_gpuva_set_lock(). * - * However, the GPU VA manager contains lockdep checks to ensure callers of its - * API hold the corresponding lock whenever the &drm_gem_objects GPU VA list is - * accessed by functions such as drm_gpuva_link() or drm_gpuva_unlink(). + * However, DRM GPUVM contains lockdep checks to ensure callers of its API hold + * the corresponding lock whenever the &drm_gem_objects GPU VA list is accessed + * by functions such as drm_gpuva_link() or drm_gpuva_unlink(), but also + * drm_gpuvm_bo_obtain() and drm_gpuvm_bo_put(). + * + * The latter is required since on creation and destruction of a &drm_gpuvm_bo + * the &drm_gpuvm_bo is attached / removed from the &drm_gem_objects gpuva list. + * Subsequent calls to drm_gpuvm_bo_obtain() for the same &drm_gpuvm and + * &drm_gem_object must be able to observe previous creations and destructions + * of &drm_gpuvm_bos in order to keep instances unique. */ /** @@ -439,6 +458,7 @@ * { * struct drm_gpuva_ops *ops; * struct drm_gpuva_op *op + * struct drm_gpuvm_bo *vm_bo; * * driver_lock_va_space(); * ops = drm_gpuvm_sm_map_ops_create(gpuvm, addr, range, @@ -446,6 +466,10 @@ * if (IS_ERR(ops)) * return PTR_ERR(ops); * + * vm_bo = drm_gpuvm_bo_obtain(gpuvm, obj); + * if (IS_ERR(vm_bo)) + * return PTR_ERR(vm_bo); + * * drm_gpuva_for_each_op(op, ops) { * struct drm_gpuva *va; * @@ -458,7 +482,7 @@ * * driver_vm_map(); * drm_gpuva_map(gpuvm, va, &op->map); - * drm_gpuva_link(va); + * drm_gpuva_link(va, vm_bo); * * break; * case DRM_GPUVA_OP_REMAP: { @@ -485,11 +509,11 @@ * driver_vm_remap(); * drm_gpuva_remap(prev, next, &op->remap); * - * drm_gpuva_unlink(va); * if (prev) - * drm_gpuva_link(prev); + * drm_gpuva_link(prev, va->vm_bo); * if (next) - * drm_gpuva_link(next); + * drm_gpuva_link(next, va->vm_bo); + * drm_gpuva_unlink(va); * * break; * } @@ -505,6 +529,7 @@ * break; * } * } + * drm_gpuvm_bo_put(vm_bo); * driver_unlock_va_space(); * * return 0; @@ -514,6 +539,7 @@ * * struct driver_context { * struct drm_gpuvm *gpuvm; + * struct drm_gpuvm_bo *vm_bo; * struct drm_gpuva *new_va; * struct drm_gpuva *prev_va; * struct drm_gpuva *next_va; @@ -534,6 +560,7 @@ * struct drm_gem_object *obj, u64 offset) * { * struct driver_context ctx; + * struct drm_gpuvm_bo *vm_bo; * struct drm_gpuva_ops *ops; * struct drm_gpuva_op *op; * int ret = 0; @@ -543,16 +570,23 @@ * ctx.new_va = kzalloc(sizeof(*ctx.new_va), GFP_KERNEL); * ctx.prev_va = kzalloc(sizeof(*ctx.prev_va), GFP_KERNEL); * ctx.next_va = kzalloc(sizeof(*ctx.next_va), GFP_KERNEL); - * if (!ctx.new_va || !ctx.prev_va || !ctx.next_va) { + * ctx.vm_bo = drm_gpuvm_bo_create(gpuvm, obj); + * if (!ctx.new_va || !ctx.prev_va || !ctx.next_va || !vm_bo) { * ret = -ENOMEM; * goto out; * } * + * // Typically protected with a driver specific GEM gpuva lock + * // used in the fence signaling path for drm_gpuva_link() and + * // drm_gpuva_unlink(), hence pre-allocate. + * ctx.vm_bo = drm_gpuvm_bo_obtain_prealloc(ctx.vm_bo); + * * driver_lock_va_space(); * ret = drm_gpuvm_sm_map(gpuvm, &ctx, addr, range, obj, offset); * driver_unlock_va_space(); * * out: + * drm_gpuvm_bo_put(ctx.vm_bo); * kfree(ctx.new_va); * kfree(ctx.prev_va); * kfree(ctx.next_va); @@ -565,7 +599,7 @@ * * drm_gpuva_map(ctx->vm, ctx->new_va, &op->map); * - * drm_gpuva_link(ctx->new_va); + * drm_gpuva_link(ctx->new_va, ctx->vm_bo); * * // prevent the new GPUVA from being freed in * // driver_mapping_create() @@ -577,22 +611,23 @@ * int driver_gpuva_remap(struct drm_gpuva_op *op, void *__ctx) * { * struct driver_context *ctx = __ctx; + * struct drm_gpuva *va = op->remap.unmap->va; * * drm_gpuva_remap(ctx->prev_va, ctx->next_va, &op->remap); * - * drm_gpuva_unlink(op->remap.unmap->va); - * kfree(op->remap.unmap->va); - * * if (op->remap.prev) { - * drm_gpuva_link(ctx->prev_va); + * drm_gpuva_link(ctx->prev_va, va->vm_bo); * ctx->prev_va = NULL; * } * * if (op->remap.next) { - * drm_gpuva_link(ctx->next_va); + * drm_gpuva_link(ctx->next_va, va->vm_bo); * ctx->next_va = NULL; * } * + * drm_gpuva_unlink(va); + * kfree(va); + * * return 0; * } * @@ -815,6 +850,199 @@ drm_gpuvm_put(struct drm_gpuvm *gpuvm) } EXPORT_SYMBOL_GPL(drm_gpuvm_put); +/** + * drm_gpuvm_bo_create() - create a new instance of struct drm_gpuvm_bo + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * If provided by the driver, this function uses the &drm_gpuvm_ops + * vm_bo_alloc() callback to allocate. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, NULL on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo; + + if (ops && ops->vm_bo_alloc) + vm_bo = ops->vm_bo_alloc(); + else + vm_bo = kzalloc(sizeof(*vm_bo), GFP_KERNEL); + + if (unlikely(!vm_bo)) + return NULL; + + vm_bo->vm = drm_gpuvm_get(gpuvm); + vm_bo->obj = obj; + drm_gem_object_get(obj); + + kref_init(&vm_bo->kref); + INIT_LIST_HEAD(&vm_bo->list.gpuva); + INIT_LIST_HEAD(&vm_bo->list.entry.gem); + + return vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create); + +static void +drm_gpuvm_bo_destroy(struct kref *kref) +{ + struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo, + kref); + struct drm_gpuvm *gpuvm = vm_bo->vm; + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gem_object *obj = vm_bo->obj; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + if (!lock) + drm_gpuvm_resv_assert_held(gpuvm); + + drm_gem_gpuva_assert_lock_held(obj); + list_del(&vm_bo->list.entry.gem); + + if (ops && ops->vm_bo_free) + ops->vm_bo_free(vm_bo); + else + kfree(vm_bo); + + drm_gpuvm_put(gpuvm); + drm_gem_object_put(obj); +} + +/** + * drm_gpuvm_bo_put() - drop a struct drm_gpuvm_bo reference + * @vm_bo: the &drm_gpuvm_bo to release the reference of + * + * This releases a reference to @vm_bo. + * + * If the reference count drops to zero, the &gpuvm_bo is destroyed, which + * includes removing it from the GEMs gpuva list. Hence, if a call to this + * function can potentially let the reference count drop to zero the caller must + * hold the dma-resv or driver specific GEM gpuva lock. + * + * This function may only be called from non-atomic context. + */ +void +drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo) +{ + might_sleep(); + + if (vm_bo) + kref_put(&vm_bo->kref, drm_gpuvm_bo_destroy); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put); + +static struct drm_gpuvm_bo * +__drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo; + + drm_gem_gpuva_assert_lock_held(obj); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) + if (vm_bo->vm == gpuvm) + return vm_bo; + + return NULL; +} + +/** + * drm_gpuvm_bo_find() - find the &drm_gpuvm_bo for the given + * &drm_gpuvm and &drm_gem_object + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the &drm_gpuvm_bo accordingly. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, NULL on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo = __drm_gpuvm_bo_find(gpuvm, obj); + + return vm_bo ? drm_gpuvm_bo_get(vm_bo) : NULL; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_find); + +/** + * drm_gpuvm_bo_obtain() - obtains and instance of the &drm_gpuvm_bo for the + * given &drm_gpuvm and &drm_gem_object + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the &drm_gpuvm_bo accordingly. If not found, allocates a new + * &drm_gpuvm_bo. + * + * A new &drm_gpuvm_bo is added to the GEMs gpuva list. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, an ERR_PTR on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo; + + vm_bo = drm_gpuvm_bo_find(gpuvm, obj); + if (vm_bo) + return vm_bo; + + vm_bo = drm_gpuvm_bo_create(gpuvm, obj); + if (!vm_bo) + return ERR_PTR(-ENOMEM); + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&vm_bo->list.entry.gem, &obj->gpuva.list); + + return vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); + +/** + * drm_gpuvm_bo_obtain_prealloc() - obtains and instance of the &drm_gpuvm_bo + * for the given &drm_gpuvm and &drm_gem_object + * @__vm_bo: A pre-allocated struct drm_gpuvm_bo. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the found &drm_gpuvm_bo accordingly, while the @__vm_bo reference + * count is decreased. If not found @__vm_bo is returned without further + * increase of the reference count. + * + * A new &drm_gpuvm_bo is added to the GEMs gpuva list. + * + * Returns: a pointer to the found &drm_gpuvm_bo or @__vm_bo if no existing + * &drm_gpuvm_bo was found + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo) +{ + struct drm_gpuvm *gpuvm = __vm_bo->vm; + struct drm_gem_object *obj = __vm_bo->obj; + struct drm_gpuvm_bo *vm_bo; + + vm_bo = drm_gpuvm_bo_find(gpuvm, obj); + if (vm_bo) { + drm_gpuvm_bo_put(__vm_bo); + return vm_bo; + } + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&__vm_bo->list.entry.gem, &obj->gpuva.list); + + return __vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain_prealloc); + static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va) @@ -916,24 +1144,33 @@ EXPORT_SYMBOL_GPL(drm_gpuva_remove); /** * drm_gpuva_link() - link a &drm_gpuva * @va: the &drm_gpuva to link + * @vm_bo: the &drm_gpuvm_bo to add the &drm_gpuva to * - * This adds the given &va to the GPU VA list of the &drm_gem_object it is - * associated with. + * This adds the given &va to the GPU VA list of the &drm_gpuvm_bo and the + * &drm_gpuvm_bo to the &drm_gem_object it is associated with. + * + * For every &drm_gpuva entry added to the &drm_gpuvm_bo an additional + * reference of the latter is taken. * * This function expects the caller to protect the GEM's GPUVA list against - * concurrent access using the GEMs dma_resv lock. + * concurrent access using either the GEMs dma_resv lock or a driver specific + * lock set through drm_gem_gpuva_set_lock(). */ void -drm_gpuva_link(struct drm_gpuva *va) +drm_gpuva_link(struct drm_gpuva *va, struct drm_gpuvm_bo *vm_bo) { struct drm_gem_object *obj = va->gem.obj; + struct drm_gpuvm *gpuvm = va->vm; if (unlikely(!obj)) return; - drm_gem_gpuva_assert_lock_held(obj); + drm_WARN_ON(gpuvm->drm, obj != vm_bo->obj); - list_add_tail(&va->gem.entry, &obj->gpuva.list); + va->vm_bo = drm_gpuvm_bo_get(vm_bo); + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&va->gem.entry, &vm_bo->list.gpuva); } EXPORT_SYMBOL_GPL(drm_gpuva_link); @@ -944,20 +1181,31 @@ EXPORT_SYMBOL_GPL(drm_gpuva_link); * This removes the given &va from the GPU VA list of the &drm_gem_object it is * associated with. * + * This removes the given &va from the GPU VA list of the &drm_gpuvm_bo and + * the &drm_gpuvm_bo from the &drm_gem_object it is associated with in case + * this call unlinks the last &drm_gpuva from the &drm_gpuvm_bo. + * + * For every &drm_gpuva entry removed from the &drm_gpuvm_bo a reference of + * the latter is dropped. + * * This function expects the caller to protect the GEM's GPUVA list against - * concurrent access using the GEMs dma_resv lock. + * concurrent access using either the GEMs dma_resv lock or a driver specific + * lock set through drm_gem_gpuva_set_lock(). */ void drm_gpuva_unlink(struct drm_gpuva *va) { struct drm_gem_object *obj = va->gem.obj; + struct drm_gpuvm_bo *vm_bo = va->vm_bo; if (unlikely(!obj)) return; drm_gem_gpuva_assert_lock_held(obj); - list_del_init(&va->gem.entry); + + va->vm_bo = NULL; + drm_gpuvm_bo_put(vm_bo); } EXPORT_SYMBOL_GPL(drm_gpuva_unlink); @@ -1102,10 +1350,10 @@ drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva *next, struct drm_gpuva_op_remap *op) { - struct drm_gpuva *curr = op->unmap->va; - struct drm_gpuvm *gpuvm = curr->vm; + struct drm_gpuva *va = op->unmap->va; + struct drm_gpuvm *gpuvm = va->vm; - drm_gpuva_remove(curr); + drm_gpuva_remove(va); if (op->prev) { drm_gpuva_init_from_op(prev, op->prev); @@ -1747,9 +1995,8 @@ drm_gpuvm_prefetch_ops_create(struct drm_gpuvm *gpuvm, EXPORT_SYMBOL_GPL(drm_gpuvm_prefetch_ops_create); /** - * drm_gpuvm_gem_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM - * @gpuvm: the &drm_gpuvm representing the GPU VA space - * @obj: the &drm_gem_object to unmap + * drm_gpuvm_bo_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM + * @vm_bo: the &drm_gpuvm_bo abstraction * * This function creates a list of operations to perform unmapping for every * GPUVA attached to a GEM. @@ -1766,15 +2013,14 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_prefetch_ops_create); * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, - struct drm_gem_object *obj) +drm_gpuvm_bo_unmap_ops_create(struct drm_gpuvm_bo *vm_bo) { struct drm_gpuva_ops *ops; struct drm_gpuva_op *op; struct drm_gpuva *va; int ret; - drm_gem_gpuva_assert_lock_held(obj); + drm_gem_gpuva_assert_lock_held(vm_bo->obj); ops = kzalloc(sizeof(*ops), GFP_KERNEL); if (!ops) @@ -1782,8 +2028,8 @@ drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, INIT_LIST_HEAD(&ops->list); - drm_gem_for_each_gpuva(va, obj) { - op = gpuva_op_alloc(gpuvm); + drm_gpuvm_bo_for_each_va(va, vm_bo) { + op = gpuva_op_alloc(vm_bo->vm); if (!op) { ret = -ENOMEM; goto err_free_ops; @@ -1797,10 +2043,10 @@ drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, return ops; err_free_ops: - drm_gpuva_ops_free(gpuvm, ops); + drm_gpuva_ops_free(vm_bo->vm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuvm_gem_unmap_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_unmap_ops_create); /** * drm_gpuva_ops_free() - free the given &drm_gpuva_ops diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index cb2f06565c46..eda7bb8624f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -62,6 +62,8 @@ struct bind_job_op { enum vm_bind_op op; u32 flags; + struct drm_gpuvm_bo *vm_bo; + struct { u64 addr; u64 range; @@ -1101,22 +1103,28 @@ bind_validate_region(struct nouveau_job *job) } static void -bind_link_gpuvas(struct drm_gpuva_ops *ops, struct nouveau_uvma_prealloc *new) +bind_link_gpuvas(struct bind_job_op *bop) { + struct nouveau_uvma_prealloc *new = &bop->new; + struct drm_gpuvm_bo *vm_bo = bop->vm_bo; + struct drm_gpuva_ops *ops = bop->ops; struct drm_gpuva_op *op; drm_gpuva_for_each_op(op, ops) { switch (op->op) { case DRM_GPUVA_OP_MAP: - drm_gpuva_link(&new->map->va); + drm_gpuva_link(&new->map->va, vm_bo); break; - case DRM_GPUVA_OP_REMAP: + case DRM_GPUVA_OP_REMAP: { + struct drm_gpuva *va = op->remap.unmap->va; + if (op->remap.prev) - drm_gpuva_link(&new->prev->va); + drm_gpuva_link(&new->prev->va, va->vm_bo); if (op->remap.next) - drm_gpuva_link(&new->next->va); - drm_gpuva_unlink(op->remap.unmap->va); + drm_gpuva_link(&new->next->va, va->vm_bo); + drm_gpuva_unlink(va); break; + } case DRM_GPUVA_OP_UNMAP: drm_gpuva_unlink(op->unmap.va); break; @@ -1138,10 +1146,17 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) list_for_each_op(op, &bind_job->ops) { if (op->op == OP_MAP) { - op->gem.obj = drm_gem_object_lookup(job->file_priv, - op->gem.handle); - if (!op->gem.obj) + struct drm_gem_object *obj = op->gem.obj = + drm_gem_object_lookup(job->file_priv, + op->gem.handle); + if (!obj) return -ENOENT; + + dma_resv_lock(obj->resv, NULL); + op->vm_bo = drm_gpuvm_bo_obtain(&uvmm->base, obj); + dma_resv_unlock(obj->resv); + if (IS_ERR(op->vm_bo)) + return PTR_ERR(op->vm_bo); } ret = bind_validate_op(job, op); @@ -1352,7 +1367,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) case OP_UNMAP_SPARSE: case OP_MAP: case OP_UNMAP: - bind_link_gpuvas(op->ops, &op->new); + bind_link_gpuvas(op); break; default: break; @@ -1499,6 +1514,12 @@ nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) if (!IS_ERR_OR_NULL(op->ops)) drm_gpuva_ops_free(&uvmm->base, op->ops); + if (!IS_ERR_OR_NULL(op->vm_bo)) { + dma_resv_lock(obj->resv, NULL); + drm_gpuvm_bo_put(op->vm_bo); + dma_resv_unlock(obj->resv); + } + if (obj) drm_gem_object_put(obj); } @@ -1752,15 +1773,18 @@ void nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbo, struct nouveau_mem *mem) { struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuvm_bo *vm_bo; struct drm_gpuva *va; dma_resv_assert_held(obj->resv); - drm_gem_for_each_gpuva(va, obj) { - struct nouveau_uvma *uvma = uvma_from_va(va); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct nouveau_uvma *uvma = uvma_from_va(va); - nouveau_uvma_map(uvma, mem); - drm_gpuva_invalidate(va, false); + nouveau_uvma_map(uvma, mem); + drm_gpuva_invalidate(va, false); + } } } @@ -1768,15 +1792,18 @@ void nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo) { struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuvm_bo *vm_bo; struct drm_gpuva *va; dma_resv_assert_held(obj->resv); - drm_gem_for_each_gpuva(va, obj) { - struct nouveau_uvma *uvma = uvma_from_va(va); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct nouveau_uvma *uvma = uvma_from_va(va); - nouveau_uvma_unmap(uvma); - drm_gpuva_invalidate(va, true); + nouveau_uvma_unmap(uvma); + drm_gpuva_invalidate(va, true); + } } } diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 16364487fde9..369505447acd 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -580,7 +580,7 @@ int drm_gem_evict(struct drm_gem_object *obj); * drm_gem_gpuva_init() - initialize the gpuva list of a GEM object * @obj: the &drm_gem_object * - * This initializes the &drm_gem_object's &drm_gpuva list. + * This initializes the &drm_gem_object's &drm_gpuvm_bo list. * * Calling this function is only necessary for drivers intending to support the * &drm_driver_feature DRIVER_GEM_GPUVA. @@ -593,28 +593,28 @@ static inline void drm_gem_gpuva_init(struct drm_gem_object *obj) } /** - * drm_gem_for_each_gpuva() - iternator to walk over a list of gpuvas - * @entry__: &drm_gpuva structure to assign to in each iteration step - * @obj__: the &drm_gem_object the &drm_gpuvas to walk are associated with + * drm_gem_for_each_gpuvm_bo() - iterator to walk over a list of &drm_gpuvm_bo + * @entry__: &drm_gpuvm_bo structure to assign to in each iteration step + * @obj__: the &drm_gem_object the &drm_gpuvm_bo to walk are associated with * - * This iterator walks over all &drm_gpuva structures associated with the - * &drm_gpuva_manager. + * This iterator walks over all &drm_gpuvm_bo structures associated with the + * &drm_gem_object. */ -#define drm_gem_for_each_gpuva(entry__, obj__) \ - list_for_each_entry(entry__, &(obj__)->gpuva.list, gem.entry) +#define drm_gem_for_each_gpuvm_bo(entry__, obj__) \ + list_for_each_entry(entry__, &(obj__)->gpuva.list, list.entry.gem) /** - * drm_gem_for_each_gpuva_safe() - iternator to safely walk over a list of - * gpuvas - * @entry__: &drm_gpuva structure to assign to in each iteration step - * @next__: &next &drm_gpuva to store the next step - * @obj__: the &drm_gem_object the &drm_gpuvas to walk are associated with + * drm_gem_for_each_gpuvm_bo_safe() - iterator to safely walk over a list of + * &drm_gpuvm_bo + * @entry__: &drm_gpuvm_bostructure to assign to in each iteration step + * @next__: &next &drm_gpuvm_bo to store the next step + * @obj__: the &drm_gem_object the &drm_gpuvm_bo to walk are associated with * - * This iterator walks over all &drm_gpuva structures associated with the + * This iterator walks over all &drm_gpuvm_bo structures associated with the * &drm_gem_object. It is implemented with list_for_each_entry_safe(), hence * it is save against removal of elements. */ -#define drm_gem_for_each_gpuva_safe(entry__, next__, obj__) \ - list_for_each_entry_safe(entry__, next__, &(obj__)->gpuva.list, gem.entry) +#define drm_gem_for_each_gpuvm_bo_safe(entry__, next__, obj__) \ + list_for_each_entry_safe(entry__, next__, &(obj__)->gpuva.list, list.entry.gem) #endif /* __DRM_GEM_H__ */ diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 4e6e1fd3485a..b12fb22b0e22 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -25,6 +25,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -33,6 +34,7 @@ #include struct drm_gpuvm; +struct drm_gpuvm_bo; struct drm_gpuvm_ops; /** @@ -73,6 +75,12 @@ struct drm_gpuva { */ struct drm_gpuvm *vm; + /** + * @vm_bo: the &drm_gpuvm_bo abstraction for the mapped + * &drm_gem_object + */ + struct drm_gpuvm_bo *vm_bo; + /** * @flags: the &drm_gpuva_flags for this mapping */ @@ -108,7 +116,7 @@ struct drm_gpuva { struct drm_gem_object *obj; /** - * @entry: the &list_head to attach this object to a &drm_gem_object + * @entry: the &list_head to attach this object to a &drm_gpuvm_bo */ struct list_head entry; } gem; @@ -141,7 +149,7 @@ struct drm_gpuva { int drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va); void drm_gpuva_remove(struct drm_gpuva *va); -void drm_gpuva_link(struct drm_gpuva *va); +void drm_gpuva_link(struct drm_gpuva *va, struct drm_gpuvm_bo *vm_bo); void drm_gpuva_unlink(struct drm_gpuva *va); struct drm_gpuva *drm_gpuva_find(struct drm_gpuvm *gpuvm, @@ -188,10 +196,16 @@ static inline bool drm_gpuva_invalidated(struct drm_gpuva *va) * enum drm_gpuvm_flags - flags for struct drm_gpuvm */ enum drm_gpuvm_flags { + /** + * @DRM_GPUVM_RESV_PROTECTED: GPUVM is protected externally by the + * GPUVM's &dma_resv lock + */ + DRM_GPUVM_RESV_PROTECTED = BIT(0), + /** * @DRM_GPUVM_USERBITS: user defined bits */ - DRM_GPUVM_USERBITS = BIT(0), + DRM_GPUVM_USERBITS = BIT(1), }; /** @@ -302,6 +316,19 @@ bool drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range); struct drm_gem_object * drm_gpuvm_resv_object_alloc(struct drm_device *drm); +/** + * drm_gpuvm_resv_protected() - indicates whether &DRM_GPUVM_RESV_PROTECTED is + * set + * @gpuvm: the &drm_gpuvm + * + * Returns: true if &DRM_GPUVM_RESV_PROTECTED is set, false otherwise. + */ +static inline bool +drm_gpuvm_resv_protected(struct drm_gpuvm *gpuvm) +{ + return gpuvm->flags & DRM_GPUVM_RESV_PROTECTED; +} + /** * drm_gpuvm_resv() - returns the &drm_gpuvm's &dma_resv * @gpuvm__: the &drm_gpuvm @@ -320,6 +347,12 @@ drm_gpuvm_resv_object_alloc(struct drm_device *drm); */ #define drm_gpuvm_resv_obj(gpuvm__) ((gpuvm__)->r_obj) +#define drm_gpuvm_resv_held(gpuvm__) \ + dma_resv_held(drm_gpuvm_resv(gpuvm__)) + +#define drm_gpuvm_resv_assert_held(gpuvm__) \ + dma_resv_assert_held(drm_gpuvm_resv(gpuvm__)) + #define drm_gpuvm_resv_held(gpuvm__) \ dma_resv_held(drm_gpuvm_resv(gpuvm__)) @@ -404,6 +437,125 @@ __drm_gpuva_next(struct drm_gpuva *va) #define drm_gpuvm_for_each_va_safe(va__, next__, gpuvm__) \ list_for_each_entry_safe(va__, next__, &(gpuvm__)->rb.list, rb.entry) +/** + * struct drm_gpuvm_bo - structure representing a &drm_gpuvm and + * &drm_gem_object combination + * + * This structure is an abstraction representing a &drm_gpuvm and + * &drm_gem_object combination. It serves as an indirection to accelerate + * iterating all &drm_gpuvas within a &drm_gpuvm backed by the same + * &drm_gem_object. + * + * Furthermore it is used cache evicted GEM objects for a certain GPU-VM to + * accelerate validation. + * + * Typically, drivers want to create an instance of a struct drm_gpuvm_bo once + * a GEM object is mapped first in a GPU-VM and release the instance once the + * last mapping of the GEM object in this GPU-VM is unmapped. + */ +struct drm_gpuvm_bo { + /** + * @vm: The &drm_gpuvm the @obj is mapped in. This is a reference + * counted pointer. + */ + struct drm_gpuvm *vm; + + /** + * @obj: The &drm_gem_object being mapped in @vm. This is a reference + * counted pointer. + */ + struct drm_gem_object *obj; + + /** + * @kref: The reference count for this &drm_gpuvm_bo. + */ + struct kref kref; + + /** + * @list: Structure containing all &list_heads. + */ + struct { + /** + * @gpuva: The list of linked &drm_gpuvas. + * + * It is safe to access entries from this list as long as the + * GEM's gpuva lock is held. See also struct drm_gem_object. + */ + struct list_head gpuva; + + /** + * @entry: Structure containing all &list_heads serving as + * entry. + */ + struct { + /** + * @gem: List entry to attach to the &drm_gem_objects + * gpuva list. + */ + struct list_head gem; + } entry; + } list; +}; + +struct drm_gpuvm_bo * +drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj); + +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj); +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *vm_bo); + +/** + * drm_gpuvm_bo_get() - acquire a struct drm_gpuvm_bo reference + * @vm_bo: the &drm_gpuvm_bo to acquire the reference of + * + * This function acquires an additional reference to @vm_bo. It is illegal to + * call this without already holding a reference. No locks required. + */ +static inline struct drm_gpuvm_bo * +drm_gpuvm_bo_get(struct drm_gpuvm_bo *vm_bo) +{ + kref_get(&vm_bo->kref); + return vm_bo; +} + +void drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo); + +struct drm_gpuvm_bo * +drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj); + +/** + * drm_gpuvm_bo_for_each_va() - iterator to walk over a list of &drm_gpuva + * @va__: &drm_gpuva structure to assign to in each iteration step + * @vm_bo__: the &drm_gpuvm_bo the &drm_gpuva to walk are associated with + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gpuvm_bo. + * + * The caller must hold the GEM's gpuva lock. + */ +#define drm_gpuvm_bo_for_each_va(va__, vm_bo__) \ + list_for_each_entry(va__, &(vm_bo)->list.gpuva, gem.entry) + +/** + * drm_gpuvm_bo_for_each_va_safe() - iterator to safely walk over a list of + * &drm_gpuva + * @va__: &drm_gpuva structure to assign to in each iteration step + * @next__: &next &drm_gpuva to store the next step + * @vm_bo__: the &drm_gpuvm_bo the &drm_gpuva to walk are associated with + * + * This iterator walks over all &drm_gpuva structures associated with the + * &drm_gpuvm_bo. It is implemented with list_for_each_entry_safe(), hence + * it is save against removal of elements. + * + * The caller must hold the GEM's gpuva lock. + */ +#define drm_gpuvm_bo_for_each_va_safe(va__, next__, vm_bo__) \ + list_for_each_entry_safe(va__, next__, &(vm_bo)->list.gpuva, gem.entry) + /** * enum drm_gpuva_op_type - GPU VA operation type * @@ -673,8 +825,7 @@ drm_gpuvm_prefetch_ops_create(struct drm_gpuvm *gpuvm, u64 addr, u64 range); struct drm_gpuva_ops * -drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, - struct drm_gem_object *obj); +drm_gpuvm_bo_unmap_ops_create(struct drm_gpuvm_bo *vm_bo); void drm_gpuva_ops_free(struct drm_gpuvm *gpuvm, struct drm_gpuva_ops *ops); @@ -726,6 +877,30 @@ struct drm_gpuvm_ops { */ void (*op_free)(struct drm_gpuva_op *op); + /** + * @vm_bo_alloc: called when the &drm_gpuvm allocates + * a struct drm_gpuvm_bo + * + * Some drivers may want to embed struct drm_gpuvm_bo into driver + * specific structures. By implementing this callback drivers can + * allocate memory accordingly. + * + * This callback is optional. + */ + struct drm_gpuvm_bo *(*vm_bo_alloc)(void); + + /** + * @vm_bo_free: called when the &drm_gpuvm frees a + * struct drm_gpuvm_bo + * + * Some drivers may want to embed struct drm_gpuvm_bo into driver + * specific structures. By implementing this callback drivers can + * free the previously allocated memory accordingly. + * + * This callback is optional. + */ + void (*vm_bo_free)(struct drm_gpuvm_bo *vm_bo); + /** * @sm_step_map: called from &drm_gpuvm_sm_map to finally insert the * mapping once all previous steps were completed From 50c1a36f594bb3dd33f3f9386c5d960cd12327d8 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 8 Nov 2023 01:12:41 +0100 Subject: [PATCH 0445/7721] drm/gpuvm: track/lock/validate external/evicted objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the DRM GPUVM offers common infrastructure to track GPU VA allocations and mappings, generically connect GPU VA mappings to their backing buffers and perform more complex mapping operations on the GPU VA space. However, there are more design patterns commonly used by drivers, which can potentially be generalized in order to make the DRM GPUVM represent a basis for GPU-VM implementations. In this context, this patch aims at generalizing the following elements. 1) Provide a common dma-resv for GEM objects not being used outside of this GPU-VM. 2) Provide tracking of external GEM objects (GEM objects which are shared with other GPU-VMs). 3) Provide functions to efficiently lock all GEM objects dma-resv the GPU-VM contains mappings of. 4) Provide tracking of evicted GEM objects the GPU-VM contains mappings of, such that validation of evicted GEM objects is accelerated. 5) Provide some convinience functions for common patterns. Big thanks to Boris Brezillon for his help to figure out locking for drivers updating the GPU VA space within the fence signalling path. Acked-by: Christian König Reviewed-by: Boris Brezillon Reviewed-by: Thomas Hellström Suggested-by: Matthew Brost Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231108001259.15123-12-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 633 ++++++++++++++++++++++++++++++++++++ include/drm/drm_gpuvm.h | 250 ++++++++++++++ 2 files changed, 883 insertions(+) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 7e193bca8bab..54f5e8851de5 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -82,6 +82,21 @@ * &drm_gem_object list of &drm_gpuvm_bos for an existing instance of this * particular combination. If not existent a new instance is created and linked * to the &drm_gem_object. + * + * &drm_gpuvm_bo structures, since unique for a given &drm_gpuvm, are also used + * as entry for the &drm_gpuvm's lists of external and evicted objects. Those + * lists are maintained in order to accelerate locking of dma-resv locks and + * validation of evicted objects bound in a &drm_gpuvm. For instance, all + * &drm_gem_object's &dma_resv of a given &drm_gpuvm can be locked by calling + * drm_gpuvm_exec_lock(). Once locked drivers can call drm_gpuvm_validate() in + * order to validate all evicted &drm_gem_objects. It is also possible to lock + * additional &drm_gem_objects by providing the corresponding parameters to + * drm_gpuvm_exec_lock() as well as open code the &drm_exec loop while making + * use of helper functions such as drm_gpuvm_prepare_range() or + * drm_gpuvm_prepare_objects(). + * + * Every bound &drm_gem_object is treated as external object when its &dma_resv + * structure is different than the &drm_gpuvm's common &dma_resv structure. */ /** @@ -429,6 +444,20 @@ * Subsequent calls to drm_gpuvm_bo_obtain() for the same &drm_gpuvm and * &drm_gem_object must be able to observe previous creations and destructions * of &drm_gpuvm_bos in order to keep instances unique. + * + * The &drm_gpuvm's lists for keeping track of external and evicted objects are + * protected against concurrent insertion / removal and iteration internally. + * + * However, drivers still need ensure to protect concurrent calls to functions + * iterating those lists, namely drm_gpuvm_prepare_objects() and + * drm_gpuvm_validate(). + * + * Alternatively, drivers can set the &DRM_GPUVM_RESV_PROTECTED flag to indicate + * that the corresponding &dma_resv locks are held in order to protect the + * lists. If &DRM_GPUVM_RESV_PROTECTED is set, internal locking is disabled and + * the corresponding lockdep checks are enabled. This is an optimization for + * drivers which are capable of taking the corresponding &dma_resv locks and + * hence do not require internal locking. */ /** @@ -641,6 +670,201 @@ * } */ +/** + * get_next_vm_bo_from_list() - get the next vm_bo element + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * @__local_list: a pointer to the local list used to store already iterated items + * @__prev_vm_bo: the previous element we got from get_next_vm_bo_from_list() + * + * This helper is here to provide lockless list iteration. Lockless as in, the + * iterator releases the lock immediately after picking the first element from + * the list, so list insertion deletion can happen concurrently. + * + * Elements popped from the original list are kept in a local list, so removal + * and is_empty checks can still happen while we're iterating the list. + */ +#define get_next_vm_bo_from_list(__gpuvm, __list_name, __local_list, __prev_vm_bo) \ + ({ \ + struct drm_gpuvm_bo *__vm_bo = NULL; \ + \ + drm_gpuvm_bo_put(__prev_vm_bo); \ + \ + spin_lock(&(__gpuvm)->__list_name.lock); \ + if (!(__gpuvm)->__list_name.local_list) \ + (__gpuvm)->__list_name.local_list = __local_list; \ + else \ + drm_WARN_ON((__gpuvm)->drm, \ + (__gpuvm)->__list_name.local_list != __local_list); \ + \ + while (!list_empty(&(__gpuvm)->__list_name.list)) { \ + __vm_bo = list_first_entry(&(__gpuvm)->__list_name.list, \ + struct drm_gpuvm_bo, \ + list.entry.__list_name); \ + if (kref_get_unless_zero(&__vm_bo->kref)) { \ + list_move_tail(&(__vm_bo)->list.entry.__list_name, \ + __local_list); \ + break; \ + } else { \ + list_del_init(&(__vm_bo)->list.entry.__list_name); \ + __vm_bo = NULL; \ + } \ + } \ + spin_unlock(&(__gpuvm)->__list_name.lock); \ + \ + __vm_bo; \ + }) + +/** + * for_each_vm_bo_in_list() - internal vm_bo list iterator + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * @__local_list: a pointer to the local list used to store already iterated items + * @__vm_bo: the struct drm_gpuvm_bo to assign in each iteration step + * + * This helper is here to provide lockless list iteration. Lockless as in, the + * iterator releases the lock immediately after picking the first element from the + * list, hence list insertion and deletion can happen concurrently. + * + * It is not allowed to re-assign the vm_bo pointer from inside this loop. + * + * Typical use: + * + * struct drm_gpuvm_bo *vm_bo; + * LIST_HEAD(my_local_list); + * + * ret = 0; + * for_each_vm_bo_in_list(gpuvm, , &my_local_list, vm_bo) { + * ret = do_something_with_vm_bo(..., vm_bo); + * if (ret) + * break; + * } + * // Drop ref in case we break out of the loop. + * drm_gpuvm_bo_put(vm_bo); + * restore_vm_bo_list(gpuvm, , &my_local_list); + * + * + * Only used for internal list iterations, not meant to be exposed to the outside + * world. + */ +#define for_each_vm_bo_in_list(__gpuvm, __list_name, __local_list, __vm_bo) \ + for (__vm_bo = get_next_vm_bo_from_list(__gpuvm, __list_name, \ + __local_list, NULL); \ + __vm_bo; \ + __vm_bo = get_next_vm_bo_from_list(__gpuvm, __list_name, \ + __local_list, __vm_bo)) + +static void +__restore_vm_bo_list(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *list, struct list_head **local_list) +{ + /* Merge back the two lists, moving local list elements to the + * head to preserve previous ordering, in case it matters. + */ + spin_lock(lock); + if (*local_list) { + list_splice(*local_list, list); + *local_list = NULL; + } + spin_unlock(lock); +} + +/** + * restore_vm_bo_list() - move vm_bo elements back to their original list + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * + * When we're done iterating a vm_bo list, we should call restore_vm_bo_list() + * to restore the original state and let new iterations take place. + */ +#define restore_vm_bo_list(__gpuvm, __list_name) \ + __restore_vm_bo_list((__gpuvm), &(__gpuvm)->__list_name.lock, \ + &(__gpuvm)->__list_name.list, \ + &(__gpuvm)->__list_name.local_list) + +static void +cond_spin_lock(spinlock_t *lock, bool cond) +{ + if (cond) + spin_lock(lock); +} + +static void +cond_spin_unlock(spinlock_t *lock, bool cond) +{ + if (cond) + spin_unlock(lock); +} + +static void +__drm_gpuvm_bo_list_add(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *entry, struct list_head *list) +{ + cond_spin_lock(lock, !!lock); + if (list_empty(entry)) + list_add_tail(entry, list); + cond_spin_unlock(lock, !!lock); +} + +/** + * drm_gpuvm_bo_list_add() - insert a vm_bo into the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Inserts the given @__vm_bo into the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_add(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_add((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + &(__vm_bo)->vm->__list_name.list) + +static void +__drm_gpuvm_bo_list_del(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *entry, bool init) +{ + cond_spin_lock(lock, !!lock); + if (init) { + if (!list_empty(entry)) + list_del_init(entry); + } else { + list_del(entry); + } + cond_spin_unlock(lock, !!lock); +} + +/** + * drm_gpuvm_bo_list_del_init() - remove a vm_bo from the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Removes the given @__vm_bo from the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_del_init(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_del((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + true) + +/** + * drm_gpuvm_bo_list_del() - remove a vm_bo from the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Removes the given @__vm_bo from the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_del(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_del((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + false) + #define to_drm_gpuva(__node) container_of((__node), struct drm_gpuva, rb.node) #define GPUVA_START(node) ((node)->va.addr) @@ -781,6 +1005,12 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, gpuvm->rb.tree = RB_ROOT_CACHED; INIT_LIST_HEAD(&gpuvm->rb.list); + INIT_LIST_HEAD(&gpuvm->extobj.list); + spin_lock_init(&gpuvm->extobj.lock); + + INIT_LIST_HEAD(&gpuvm->evict.list); + spin_lock_init(&gpuvm->evict.lock); + kref_init(&gpuvm->kref); gpuvm->name = name ? name : "unknown"; @@ -818,6 +1048,11 @@ drm_gpuvm_fini(struct drm_gpuvm *gpuvm) drm_WARN(gpuvm->drm, !RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), "GPUVA tree is not empty, potentially leaking memory.\n"); + drm_WARN(gpuvm->drm, !list_empty(&gpuvm->extobj.list), + "Extobj list should be empty.\n"); + drm_WARN(gpuvm->drm, !list_empty(&gpuvm->evict.list), + "Evict list should be empty.\n"); + drm_gem_object_put(gpuvm->r_obj); } @@ -850,6 +1085,343 @@ drm_gpuvm_put(struct drm_gpuvm *gpuvm) } EXPORT_SYMBOL_GPL(drm_gpuvm_put); +static int +__drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + struct drm_gpuvm_bo *vm_bo; + LIST_HEAD(extobjs); + int ret = 0; + + for_each_vm_bo_in_list(gpuvm, extobj, &extobjs, vm_bo) { + ret = drm_exec_prepare_obj(exec, vm_bo->obj, num_fences); + if (ret) + break; + } + /* Drop ref in case we break out of the loop. */ + drm_gpuvm_bo_put(vm_bo); + restore_vm_bo_list(gpuvm, extobj); + + return ret; +} + +static int +drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + struct drm_gpuvm_bo *vm_bo; + int ret = 0; + + drm_gpuvm_resv_assert_held(gpuvm); + list_for_each_entry(vm_bo, &gpuvm->extobj.list, list.entry.extobj) { + ret = drm_exec_prepare_obj(exec, vm_bo->obj, num_fences); + if (ret) + break; + + if (vm_bo->evicted) + drm_gpuvm_bo_list_add(vm_bo, evict, false); + } + + return ret; +} + +/** + * drm_gpuvm_prepare_objects() - prepare all assoiciated BOs + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec locking context + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for all &drm_gem_objects the given + * &drm_gpuvm contains mappings of. + * + * Using this function directly, it is the drivers responsibility to call + * drm_exec_init() and drm_exec_fini() accordingly. + * + * Note: This function is safe against concurrent insertion and removal of + * external objects, however it is not safe against concurrent usage itself. + * + * Drivers need to make sure to protect this case with either an outer VM lock + * or by calling drm_gpuvm_prepare_vm() before this function within the + * drm_exec_until_all_locked() loop, such that the GPUVM's dma-resv lock ensures + * mutual exclusion. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + if (drm_gpuvm_resv_protected(gpuvm)) + return drm_gpuvm_prepare_objects_locked(gpuvm, exec, + num_fences); + else + return __drm_gpuvm_prepare_objects(gpuvm, exec, num_fences); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_objects); + +/** + * drm_gpuvm_prepare_range() - prepare all BOs mapped within a given range + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec locking context + * @addr: the start address within the VA space + * @range: the range to iterate within the VA space + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for all &drm_gem_objects mapped between @addr + * and @addr + @range. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, struct drm_exec *exec, + u64 addr, u64 range, unsigned int num_fences) +{ + struct drm_gpuva *va; + u64 end = addr + range; + int ret; + + drm_gpuvm_for_each_va_range(va, gpuvm, addr, end) { + struct drm_gem_object *obj = va->gem.obj; + + ret = drm_exec_prepare_obj(exec, obj, num_fences); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_range); + +/** + * drm_gpuvm_exec_lock() - lock all dma-resv of all assoiciated BOs + * @vm_exec: the &drm_gpuvm_exec wrapper + * + * Acquires all dma-resv locks of all &drm_gem_objects the given + * &drm_gpuvm contains mappings of. + * + * Addionally, when calling this function with struct drm_gpuvm_exec::extra + * being set the driver receives the given @fn callback to lock additional + * dma-resv in the context of the &drm_gpuvm_exec instance. Typically, drivers + * would call drm_exec_prepare_obj() from within this callback. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec) +{ + struct drm_gpuvm *gpuvm = vm_exec->vm; + struct drm_exec *exec = &vm_exec->exec; + unsigned int num_fences = vm_exec->num_fences; + int ret; + + drm_exec_init(exec, vm_exec->flags); + + drm_exec_until_all_locked(exec) { + ret = drm_gpuvm_prepare_vm(gpuvm, exec, num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + + ret = drm_gpuvm_prepare_objects(gpuvm, exec, num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + + if (vm_exec->extra.fn) { + ret = vm_exec->extra.fn(vm_exec); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + } + } + + return 0; + +err: + drm_exec_fini(exec); + return ret; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock); + +static int +fn_lock_array(struct drm_gpuvm_exec *vm_exec) +{ + struct { + struct drm_gem_object **objs; + unsigned int num_objs; + } *args = vm_exec->extra.priv; + + return drm_exec_prepare_array(&vm_exec->exec, args->objs, + args->num_objs, vm_exec->num_fences); +} + +/** + * drm_gpuvm_exec_lock_array() - lock all dma-resv of all assoiciated BOs + * @vm_exec: the &drm_gpuvm_exec wrapper + * @objs: additional &drm_gem_objects to lock + * @num_objs: the number of additional &drm_gem_objects to lock + * + * Acquires all dma-resv locks of all &drm_gem_objects the given &drm_gpuvm + * contains mappings of, plus the ones given through @objs. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock_array(struct drm_gpuvm_exec *vm_exec, + struct drm_gem_object **objs, + unsigned int num_objs) +{ + struct { + struct drm_gem_object **objs; + unsigned int num_objs; + } args; + + args.objs = objs; + args.num_objs = num_objs; + + vm_exec->extra.fn = fn_lock_array; + vm_exec->extra.priv = &args; + + return drm_gpuvm_exec_lock(vm_exec); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock_array); + +/** + * drm_gpuvm_exec_lock_range() - prepare all BOs mapped within a given range + * @vm_exec: the &drm_gpuvm_exec wrapper + * @addr: the start address within the VA space + * @range: the range to iterate within the VA space + * + * Acquires all dma-resv locks of all &drm_gem_objects mapped between @addr and + * @addr + @range. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock_range(struct drm_gpuvm_exec *vm_exec, + u64 addr, u64 range) +{ + struct drm_gpuvm *gpuvm = vm_exec->vm; + struct drm_exec *exec = &vm_exec->exec; + int ret; + + drm_exec_init(exec, vm_exec->flags); + + drm_exec_until_all_locked(exec) { + ret = drm_gpuvm_prepare_range(gpuvm, exec, addr, range, + vm_exec->num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + } + + return ret; + +err: + drm_exec_fini(exec); + return ret; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock_range); + +static int +__drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo; + LIST_HEAD(evict); + int ret = 0; + + for_each_vm_bo_in_list(gpuvm, evict, &evict, vm_bo) { + ret = ops->vm_bo_validate(vm_bo, exec); + if (ret) + break; + } + /* Drop ref in case we break out of the loop. */ + drm_gpuvm_bo_put(vm_bo); + restore_vm_bo_list(gpuvm, evict); + + return ret; +} + +static int +drm_gpuvm_validate_locked(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo, *next; + int ret = 0; + + drm_gpuvm_resv_assert_held(gpuvm); + + list_for_each_entry_safe(vm_bo, next, &gpuvm->evict.list, + list.entry.evict) { + ret = ops->vm_bo_validate(vm_bo, exec); + if (ret) + break; + + dma_resv_assert_held(vm_bo->obj->resv); + if (!vm_bo->evicted) + drm_gpuvm_bo_list_del_init(vm_bo, evict, false); + } + + return ret; +} + +/** + * drm_gpuvm_validate() - validate all BOs marked as evicted + * @gpuvm: the &drm_gpuvm to validate evicted BOs + * @exec: the &drm_exec instance used for locking the GPUVM + * + * Calls the &drm_gpuvm_ops::vm_bo_validate callback for all evicted buffer + * objects being mapped in the given &drm_gpuvm. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + + if (unlikely(!ops || !ops->vm_bo_validate)) + return -EOPNOTSUPP; + + if (drm_gpuvm_resv_protected(gpuvm)) + return drm_gpuvm_validate_locked(gpuvm, exec); + else + return __drm_gpuvm_validate(gpuvm, exec); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_validate); + +/** + * drm_gpuvm_resv_add_fence - add fence to private and all extobj + * dma-resv + * @gpuvm: the &drm_gpuvm to add a fence to + * @exec: the &drm_exec locking context + * @fence: fence to add + * @private_usage: private dma-resv usage + * @extobj_usage: extobj dma-resv usage + */ +void +drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + struct dma_fence *fence, + enum dma_resv_usage private_usage, + enum dma_resv_usage extobj_usage) +{ + struct drm_gem_object *obj; + unsigned long index; + + drm_exec_for_each_locked_object(exec, index, obj) { + dma_resv_assert_held(obj->resv); + dma_resv_add_fence(obj->resv, fence, + drm_gpuvm_is_extobj(gpuvm, obj) ? + extobj_usage : private_usage); + } +} +EXPORT_SYMBOL_GPL(drm_gpuvm_resv_add_fence); + /** * drm_gpuvm_bo_create() - create a new instance of struct drm_gpuvm_bo * @gpuvm: The &drm_gpuvm the @obj is mapped in. @@ -883,6 +1455,9 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, INIT_LIST_HEAD(&vm_bo->list.gpuva); INIT_LIST_HEAD(&vm_bo->list.entry.gem); + INIT_LIST_HEAD(&vm_bo->list.entry.extobj); + INIT_LIST_HEAD(&vm_bo->list.entry.evict); + return vm_bo; } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create); @@ -900,6 +1475,9 @@ drm_gpuvm_bo_destroy(struct kref *kref) if (!lock) drm_gpuvm_resv_assert_held(gpuvm); + drm_gpuvm_bo_list_del(vm_bo, extobj, lock); + drm_gpuvm_bo_list_del(vm_bo, evict, lock); + drm_gem_gpuva_assert_lock_held(obj); list_del(&vm_bo->list.entry.gem); @@ -1043,6 +1621,61 @@ drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo) } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain_prealloc); +/** + * drm_gpuvm_bo_extobj_add() - adds the &drm_gpuvm_bo to its &drm_gpuvm's + * extobj list + * @vm_bo: The &drm_gpuvm_bo to add to its &drm_gpuvm's the extobj list. + * + * Adds the given @vm_bo to its &drm_gpuvm's extobj list if not on the list + * already and if the corresponding &drm_gem_object is an external object, + * actually. + */ +void +drm_gpuvm_bo_extobj_add(struct drm_gpuvm_bo *vm_bo) +{ + struct drm_gpuvm *gpuvm = vm_bo->vm; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + if (!lock) + drm_gpuvm_resv_assert_held(gpuvm); + + if (drm_gpuvm_is_extobj(gpuvm, vm_bo->obj)) + drm_gpuvm_bo_list_add(vm_bo, extobj, lock); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_extobj_add); + +/** + * drm_gpuvm_bo_evict() - add / remove a &drm_gpuvm_bo to / from the &drm_gpuvms + * evicted list + * @vm_bo: the &drm_gpuvm_bo to add or remove + * @evict: indicates whether the object is evicted + * + * Adds a &drm_gpuvm_bo to or removes it from the &drm_gpuvms evicted list. + */ +void +drm_gpuvm_bo_evict(struct drm_gpuvm_bo *vm_bo, bool evict) +{ + struct drm_gpuvm *gpuvm = vm_bo->vm; + struct drm_gem_object *obj = vm_bo->obj; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + dma_resv_assert_held(obj->resv); + vm_bo->evicted = evict; + + /* Can't add external objects to the evicted list directly if not using + * internal spinlocks, since in this case the evicted list is protected + * with the VM's common dma-resv lock. + */ + if (drm_gpuvm_is_extobj(gpuvm, obj) && !lock) + return; + + if (evict) + drm_gpuvm_bo_list_add(vm_bo, evict, lock); + else + drm_gpuvm_bo_list_del_init(vm_bo, evict, lock); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_evict); + static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va) diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index b12fb22b0e22..8ca10461d8ac 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -32,6 +32,7 @@ #include #include +#include struct drm_gpuvm; struct drm_gpuvm_bo; @@ -283,6 +284,50 @@ struct drm_gpuvm { * @r_obj: Resv GEM object; representing the GPUVM's common &dma_resv. */ struct drm_gem_object *r_obj; + + /** + * @extobj: structure holding the extobj list + */ + struct { + /** + * @list: &list_head storing &drm_gpuvm_bos serving as + * external object + */ + struct list_head list; + + /** + * @local_list: pointer to the local list temporarily storing + * entries from the external object list + */ + struct list_head *local_list; + + /** + * @lock: spinlock to protect the extobj list + */ + spinlock_t lock; + } extobj; + + /** + * @evict: structure holding the evict list and evict list lock + */ + struct { + /** + * @list: &list_head storing &drm_gpuvm_bos currently being + * evicted + */ + struct list_head list; + + /** + * @local_list: pointer to the local list temporarily storing + * entries from the evicted object list + */ + struct list_head *local_list; + + /** + * @lock: spinlock to protect the evict list + */ + spinlock_t lock; + } evict; }; void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, @@ -359,6 +404,22 @@ drm_gpuvm_resv_protected(struct drm_gpuvm *gpuvm) #define drm_gpuvm_resv_assert_held(gpuvm__) \ dma_resv_assert_held(drm_gpuvm_resv(gpuvm__)) +/** + * drm_gpuvm_is_extobj() - indicates whether the given &drm_gem_object is an + * external object + * @gpuvm: the &drm_gpuvm to check + * @obj: the &drm_gem_object to check + * + * Returns: true if the &drm_gem_object &dma_resv differs from the + * &drm_gpuvms &dma_resv, false otherwise + */ +static inline bool +drm_gpuvm_is_extobj(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + return obj && obj->resv != drm_gpuvm_resv(gpuvm); +} + static inline struct drm_gpuva * __drm_gpuva_next(struct drm_gpuva *va) { @@ -437,6 +498,144 @@ __drm_gpuva_next(struct drm_gpuva *va) #define drm_gpuvm_for_each_va_safe(va__, next__, gpuvm__) \ list_for_each_entry_safe(va__, next__, &(gpuvm__)->rb.list, rb.entry) +/** + * struct drm_gpuvm_exec - &drm_gpuvm abstraction of &drm_exec + * + * This structure should be created on the stack as &drm_exec should be. + * + * Optionally, @extra can be set in order to lock additional &drm_gem_objects. + */ +struct drm_gpuvm_exec { + /** + * @exec: the &drm_exec structure + */ + struct drm_exec exec; + + /** + * @flags: the flags for the struct drm_exec + */ + uint32_t flags; + + /** + * @vm: the &drm_gpuvm to lock its DMA reservations + */ + struct drm_gpuvm *vm; + + /** + * @num_fences: the number of fences to reserve for the &dma_resv of the + * locked &drm_gem_objects + */ + unsigned int num_fences; + + /** + * @extra: Callback and corresponding private data for the driver to + * lock arbitrary additional &drm_gem_objects. + */ + struct { + /** + * @fn: The driver callback to lock additional &drm_gem_objects. + */ + int (*fn)(struct drm_gpuvm_exec *vm_exec); + + /** + * @priv: driver private data for the @fn callback + */ + void *priv; + } extra; +}; + +/** + * drm_gpuvm_prepare_vm() - prepare the GPUVMs common dma-resv + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec context + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for the GPUVMs dummy &drm_gem_object. + * + * Using this function directly, it is the drivers responsibility to call + * drm_exec_init() and drm_exec_fini() accordingly. + * + * Returns: 0 on success, negative error code on failure. + */ +static inline int +drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + return drm_exec_prepare_obj(exec, gpuvm->r_obj, num_fences); +} + +int drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences); + +int drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + u64 addr, u64 range, + unsigned int num_fences); + +int drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec); + +int drm_gpuvm_exec_lock_array(struct drm_gpuvm_exec *vm_exec, + struct drm_gem_object **objs, + unsigned int num_objs); + +int drm_gpuvm_exec_lock_range(struct drm_gpuvm_exec *vm_exec, + u64 addr, u64 range); + +/** + * drm_gpuvm_exec_unlock() - lock all dma-resv of all assoiciated BOs + * @vm_exec: the &drm_gpuvm_exec wrapper + * + * Releases all dma-resv locks of all &drm_gem_objects previously acquired + * through drm_gpuvm_exec_lock() or its variants. + * + * Returns: 0 on success, negative error code on failure. + */ +static inline void +drm_gpuvm_exec_unlock(struct drm_gpuvm_exec *vm_exec) +{ + drm_exec_fini(&vm_exec->exec); +} + +int drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec); +void drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + struct dma_fence *fence, + enum dma_resv_usage private_usage, + enum dma_resv_usage extobj_usage); + +/** + * drm_gpuvm_exec_resv_add_fence() + * @vm_exec: the &drm_gpuvm_exec wrapper + * @fence: fence to add + * @private_usage: private dma-resv usage + * @extobj_usage: extobj dma-resv usage + * + * See drm_gpuvm_resv_add_fence(). + */ +static inline void +drm_gpuvm_exec_resv_add_fence(struct drm_gpuvm_exec *vm_exec, + struct dma_fence *fence, + enum dma_resv_usage private_usage, + enum dma_resv_usage extobj_usage) +{ + drm_gpuvm_resv_add_fence(vm_exec->vm, &vm_exec->exec, fence, + private_usage, extobj_usage); +} + +/** + * drm_gpuvm_exec_validate() + * @vm_exec: the &drm_gpuvm_exec wrapper + * + * See drm_gpuvm_validate(). + */ +static inline int +drm_gpuvm_exec_validate(struct drm_gpuvm_exec *vm_exec) +{ + return drm_gpuvm_validate(vm_exec->vm, &vm_exec->exec); +} + /** * struct drm_gpuvm_bo - structure representing a &drm_gpuvm and * &drm_gem_object combination @@ -466,6 +665,12 @@ struct drm_gpuvm_bo { */ struct drm_gem_object *obj; + /** + * @evicted: Indicates whether the &drm_gem_object is evicted; field + * protected by the &drm_gem_object's dma-resv lock. + */ + bool evicted; + /** * @kref: The reference count for this &drm_gpuvm_bo. */ @@ -493,6 +698,18 @@ struct drm_gpuvm_bo { * gpuva list. */ struct list_head gem; + + /** + * @evict: List entry to attach to the &drm_gpuvms + * extobj list. + */ + struct list_head extobj; + + /** + * @evict: List entry to attach to the &drm_gpuvms evict + * list. + */ + struct list_head evict; } entry; } list; }; @@ -527,6 +744,27 @@ struct drm_gpuvm_bo * drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj); +void drm_gpuvm_bo_evict(struct drm_gpuvm_bo *vm_bo, bool evict); + +/** + * drm_gpuvm_bo_gem_evict() + * @obj: the &drm_gem_object + * @evict: indicates whether @obj is evicted + * + * See drm_gpuvm_bo_evict(). + */ +static inline void +drm_gpuvm_bo_gem_evict(struct drm_gem_object *obj, bool evict) +{ + struct drm_gpuvm_bo *vm_bo; + + drm_gem_gpuva_assert_lock_held(obj); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) + drm_gpuvm_bo_evict(vm_bo, evict); +} + +void drm_gpuvm_bo_extobj_add(struct drm_gpuvm_bo *vm_bo); + /** * drm_gpuvm_bo_for_each_va() - iterator to walk over a list of &drm_gpuva * @va__: &drm_gpuva structure to assign to in each iteration step @@ -901,6 +1139,18 @@ struct drm_gpuvm_ops { */ void (*vm_bo_free)(struct drm_gpuvm_bo *vm_bo); + /** + * @vm_bo_validate: called from drm_gpuvm_validate() + * + * Drivers receive this callback for every evicted &drm_gem_object being + * mapped in the corresponding &drm_gpuvm. + * + * Typically, drivers would call their driver specific variant of + * ttm_bo_validate() from within this callback. + */ + int (*vm_bo_validate)(struct drm_gpuvm_bo *vm_bo, + struct drm_exec *exec); + /** * @sm_step_map: called from &drm_gpuvm_sm_map to finally insert the * mapping once all previous steps were completed From 5a841e4eb8ed2fea91025b19af8a9ba544f63323 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:15 +0200 Subject: [PATCH 0446/7721] ice: rename switchdev to eswitch Eswitch is used as a prefix for related functions. Main structure storing all data related to eswitch should also be named as eswitch instead of ice_switchdev_info. Rename it. Also rename switchdev to eswitch where the context is not about eswitch mode. ::uplink_netdev was changed to netdev for simplicity. There is no other netdev in function scope so it is obvious. Reviewed-by: Wojciech Drewek Reviewed-by: Piotr Raczynski Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 6 +- drivers/net/ethernet/intel/ice/ice_eswitch.c | 63 ++++++++++--------- .../net/ethernet/intel/ice/ice_eswitch_br.c | 12 ++-- drivers/net/ethernet/intel/ice/ice_tc_lib.c | 4 +- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 351e0d36df44..6c59ca86d959 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -522,7 +522,7 @@ enum ice_misc_thread_tasks { ICE_MISC_THREAD_NBITS /* must be last */ }; -struct ice_switchdev_info { +struct ice_eswitch { struct ice_vsi *control_vsi; struct ice_vsi *uplink_vsi; struct ice_esw_br_offloads *br_offloads; @@ -637,7 +637,7 @@ struct ice_pf { struct ice_link_default_override_tlv link_dflt_override; struct ice_lag *lag; /* Link Aggregation information */ - struct ice_switchdev_info switchdev; + struct ice_eswitch eswitch; struct ice_esw_br_port *br_port; #define ICE_INVALID_AGG_NODE_ID 0 @@ -846,7 +846,7 @@ static inline struct ice_vsi *ice_find_vsi(struct ice_pf *pf, u16 vsi_num) */ static inline bool ice_is_switchdev_running(struct ice_pf *pf) { - return pf->switchdev.is_running; + return pf->eswitch.is_running; } #define ICE_FD_STAT_CTR_BLOCK_COUNT 256 diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index a655d499abfa..e7f1e53314d7 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -16,12 +16,12 @@ * @vf: pointer to VF struct * * This function adds advanced rule that forwards packets with - * VF's VSI index to the corresponding switchdev ctrl VSI queue. + * VF's VSI index to the corresponding eswitch ctrl VSI queue. */ static int ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) { - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; struct ice_adv_rule_info rule_info = { 0 }; struct ice_adv_lkup_elem *list; struct ice_hw *hw = &pf->hw; @@ -59,7 +59,7 @@ ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) * @vf: pointer to the VF struct * * Delete the advanced rule that was used to forward packets with the VF's VSI - * index to the corresponding switchdev ctrl VSI queue. + * index to the corresponding eswitch ctrl VSI queue. */ static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf) { @@ -70,7 +70,7 @@ static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf) } /** - * ice_eswitch_setup_env - configure switchdev HW filters + * ice_eswitch_setup_env - configure eswitch HW filters * @pf: pointer to PF struct * * This function adds HW filters configuration specific for switchdev @@ -78,18 +78,18 @@ static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf) */ static int ice_eswitch_setup_env(struct ice_pf *pf) { - struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi; - struct net_device *uplink_netdev = uplink_vsi->netdev; - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; + struct net_device *netdev = uplink_vsi->netdev; struct ice_vsi_vlan_ops *vlan_ops; bool rule_added = false; ice_remove_vsi_fltr(&pf->hw, uplink_vsi->idx); - netif_addr_lock_bh(uplink_netdev); - __dev_uc_unsync(uplink_netdev, NULL); - __dev_mc_unsync(uplink_netdev, NULL); - netif_addr_unlock_bh(uplink_netdev); + netif_addr_lock_bh(netdev); + __dev_uc_unsync(netdev, NULL); + __dev_mc_unsync(netdev, NULL); + netif_addr_unlock_bh(netdev); if (ice_vsi_add_vlan_zero(uplink_vsi)) goto err_def_rx; @@ -132,10 +132,10 @@ static int ice_eswitch_setup_env(struct ice_pf *pf) } /** - * ice_eswitch_remap_rings_to_vectors - reconfigure rings of switchdev ctrl VSI + * ice_eswitch_remap_rings_to_vectors - reconfigure rings of eswitch ctrl VSI * @pf: pointer to PF struct * - * In switchdev number of allocated Tx/Rx rings is equal. + * In eswitch number of allocated Tx/Rx rings is equal. * * This function fills q_vectors structures associated with representor and * move each ring pairs to port representor netdevs. Each port representor @@ -144,7 +144,7 @@ static int ice_eswitch_setup_env(struct ice_pf *pf) */ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) { - struct ice_vsi *vsi = pf->switchdev.control_vsi; + struct ice_vsi *vsi = pf->eswitch.control_vsi; int q_id; ice_for_each_txq(vsi, q_id) { @@ -189,7 +189,7 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) /** * ice_eswitch_release_reprs - clear PR VSIs configuration * @pf: poiner to PF struct - * @ctrl_vsi: pointer to switchdev control VSI + * @ctrl_vsi: pointer to eswitch control VSI */ static void ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi) @@ -223,7 +223,7 @@ ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi) */ static int ice_eswitch_setup_reprs(struct ice_pf *pf) { - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; int max_vsi_num = 0; struct ice_vf *vf; unsigned int bkt; @@ -359,7 +359,7 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev) } /** - * ice_eswitch_set_target_vsi - set switchdev context in Tx context descriptor + * ice_eswitch_set_target_vsi - set eswitch context in Tx context descriptor * @skb: pointer to send buffer * @off: pointer to offload struct */ @@ -382,7 +382,7 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb, } /** - * ice_eswitch_release_env - clear switchdev HW filters + * ice_eswitch_release_env - clear eswitch HW filters * @pf: pointer to PF struct * * This function removes HW filters configuration specific for switchdev @@ -390,8 +390,8 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb, */ static void ice_eswitch_release_env(struct ice_pf *pf) { - struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi; - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; struct ice_vsi_vlan_ops *vlan_ops; vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi); @@ -407,7 +407,7 @@ static void ice_eswitch_release_env(struct ice_pf *pf) } /** - * ice_eswitch_vsi_setup - configure switchdev control VSI + * ice_eswitch_vsi_setup - configure eswitch control VSI * @pf: pointer to PF structure * @pi: pointer to port_info structure */ @@ -486,12 +486,12 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) return -EINVAL; } - pf->switchdev.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info); - if (!pf->switchdev.control_vsi) + pf->eswitch.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info); + if (!pf->eswitch.control_vsi) return -ENODEV; - ctrl_vsi = pf->switchdev.control_vsi; - pf->switchdev.uplink_vsi = uplink_vsi; + ctrl_vsi = pf->eswitch.control_vsi; + pf->eswitch.uplink_vsi = uplink_vsi; if (ice_eswitch_setup_env(pf)) goto err_vsi; @@ -526,12 +526,12 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) } /** - * ice_eswitch_disable_switchdev - disable switchdev resources + * ice_eswitch_disable_switchdev - disable eswitch resources * @pf: pointer to PF structure */ static void ice_eswitch_disable_switchdev(struct ice_pf *pf) { - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; ice_eswitch_napi_disable(pf); ice_eswitch_br_offloads_deinit(pf); @@ -625,7 +625,7 @@ void ice_eswitch_release(struct ice_pf *pf) return; ice_eswitch_disable_switchdev(pf); - pf->switchdev.is_running = false; + pf->eswitch.is_running = false; } /** @@ -636,14 +636,15 @@ int ice_eswitch_configure(struct ice_pf *pf) { int status; - if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY || pf->switchdev.is_running) + if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY || + pf->eswitch.is_running) return 0; status = ice_eswitch_enable_switchdev(pf); if (status) return status; - pf->switchdev.is_running = true; + pf->eswitch.is_running = true; return 0; } @@ -693,7 +694,7 @@ void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) */ int ice_eswitch_rebuild(struct ice_pf *pf) { - struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; + struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; int status; ice_eswitch_napi_disable(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c index 6ae0269bdf73..16bbcaca8fda 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c @@ -947,7 +947,7 @@ ice_eswitch_br_vf_repr_port_init(struct ice_esw_br *bridge, static int ice_eswitch_br_uplink_port_init(struct ice_esw_br *bridge, struct ice_pf *pf) { - struct ice_vsi *vsi = pf->switchdev.uplink_vsi; + struct ice_vsi *vsi = pf->eswitch.uplink_vsi; struct ice_esw_br_port *br_port; int err; @@ -1185,7 +1185,7 @@ ice_eswitch_br_port_event(struct notifier_block *nb, static void ice_eswitch_br_offloads_dealloc(struct ice_pf *pf) { - struct ice_esw_br_offloads *br_offloads = pf->switchdev.br_offloads; + struct ice_esw_br_offloads *br_offloads = pf->eswitch.br_offloads; ASSERT_RTNL(); @@ -1194,7 +1194,7 @@ ice_eswitch_br_offloads_dealloc(struct ice_pf *pf) ice_eswitch_br_deinit(br_offloads, br_offloads->bridge); - pf->switchdev.br_offloads = NULL; + pf->eswitch.br_offloads = NULL; kfree(br_offloads); } @@ -1205,14 +1205,14 @@ ice_eswitch_br_offloads_alloc(struct ice_pf *pf) ASSERT_RTNL(); - if (pf->switchdev.br_offloads) + if (pf->eswitch.br_offloads) return ERR_PTR(-EEXIST); br_offloads = kzalloc(sizeof(*br_offloads), GFP_KERNEL); if (!br_offloads) return ERR_PTR(-ENOMEM); - pf->switchdev.br_offloads = br_offloads; + pf->eswitch.br_offloads = br_offloads; br_offloads->pf = pf; return br_offloads; @@ -1223,7 +1223,7 @@ ice_eswitch_br_offloads_deinit(struct ice_pf *pf) { struct ice_esw_br_offloads *br_offloads; - br_offloads = pf->switchdev.br_offloads; + br_offloads = pf->eswitch.br_offloads; if (!br_offloads) return; diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index dd03cb69ad26..08d3bbf4b44c 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -653,7 +653,7 @@ static int ice_tc_setup_redirect_action(struct net_device *filter_dev, ice_tc_is_dev_uplink(target_dev)) { repr = ice_netdev_to_repr(filter_dev); - fltr->dest_vsi = repr->src_vsi->back->switchdev.uplink_vsi; + fltr->dest_vsi = repr->src_vsi->back->eswitch.uplink_vsi; fltr->direction = ICE_ESWITCH_FLTR_EGRESS; } else if (ice_tc_is_dev_uplink(filter_dev) && ice_is_port_repr_netdev(target_dev)) { @@ -765,7 +765,7 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) rule_info.sw_act.src = hw->pf_id; rule_info.flags_info.act = ICE_SINGLE_ACT_LB_ENABLE; } else if (fltr->direction == ICE_ESWITCH_FLTR_EGRESS && - fltr->dest_vsi == vsi->back->switchdev.uplink_vsi) { + fltr->dest_vsi == vsi->back->eswitch.uplink_vsi) { /* VF to Uplink */ rule_info.sw_act.flag |= ICE_FLTR_TX; rule_info.sw_act.src = vsi->idx; From ab5fe17cbb06516877753ee1069e13967f8cc6bb Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:16 +0200 Subject: [PATCH 0447/7721] ice: remove redundant max_vsi_num variable It is a leftover from previous implementation. Accidentally it wasn't removed. Do it now. Commit that has removed it: commit c1e5da5dd465 ("ice: improve switchdev's slow-path") Reviewed-by: Wojciech Drewek Reviewed-by: Piotr Raczynski Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index e7f1e53314d7..fd8d59f4d97d 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -224,7 +224,6 @@ ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi) static int ice_eswitch_setup_reprs(struct ice_pf *pf) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - int max_vsi_num = 0; struct ice_vf *vf; unsigned int bkt; @@ -267,9 +266,6 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) goto err; } - if (max_vsi_num < vsi->vsi_num) - max_vsi_num = vsi->vsi_num; - netif_napi_add(vf->repr->netdev, &vf->repr->q_vector->napi, ice_napi_poll); From ff21a4e6193f4f752f37a9e16dd6a47074eb9076 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:17 +0200 Subject: [PATCH 0448/7721] ice: remove unused control VSI parameter It isn't used in ice_eswitch_release_reprs(). Probably leftover. Remove it. Commit that has removed usage of ctrl_vsi: commit c1e5da5dd465 ("ice: improve switchdev's slow-path") Reviewed-by: Wojciech Drewek Reviewed-by: Piotr Raczynski Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index fd8d59f4d97d..a862681c0f64 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -189,10 +189,9 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) /** * ice_eswitch_release_reprs - clear PR VSIs configuration * @pf: poiner to PF struct - * @ctrl_vsi: pointer to eswitch control VSI */ static void -ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi) +ice_eswitch_release_reprs(struct ice_pf *pf) { struct ice_vf *vf; unsigned int bkt; @@ -286,7 +285,7 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) return 0; err: - ice_eswitch_release_reprs(pf, ctrl_vsi); + ice_eswitch_release_reprs(pf); return -ENODEV; } @@ -532,7 +531,7 @@ static void ice_eswitch_disable_switchdev(struct ice_pf *pf) ice_eswitch_napi_disable(pf); ice_eswitch_br_offloads_deinit(pf); ice_eswitch_release_env(pf); - ice_eswitch_release_reprs(pf, ctrl_vsi); + ice_eswitch_release_reprs(pf); ice_vsi_release(ctrl_vsi); ice_repr_rem_from_all_vfs(pf); } From 7c37bf99a60c990682829e71fb86f75494d02504 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:18 +0200 Subject: [PATCH 0449/7721] ice: track q_id in representor Previously queue index of control plane VSI used by port representor was always id of VF. If we want to allow adding port representors for different devices we have to track queue index in the port representor structure. Reviewed-by: Wojciech Drewek Reviewed-by: Piotr Raczynski Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 2 +- drivers/net/ethernet/intel/ice/ice_repr.c | 1 + drivers/net/ethernet/intel/ice/ice_repr.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index a862681c0f64..119185564450 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -38,7 +38,7 @@ ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) rule_info.sw_act.vsi_handle = ctrl_vsi->idx; rule_info.sw_act.fltr_act = ICE_FWD_TO_Q; rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id + - ctrl_vsi->rxq_map[vf->vf_id]; + ctrl_vsi->rxq_map[vf->repr->q_id]; rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE; rule_info.flags_info.act_valid = true; rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN; diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index c686ac0935eb..a2dc216c964f 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -306,6 +306,7 @@ static int ice_repr_add(struct ice_vf *vf) repr->src_vsi = vsi; repr->vf = vf; + repr->q_id = vf->vf_id; vf->repr = repr; np = netdev_priv(repr->netdev); np->repr = repr; diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h index e1ee2d2c1d2d..f350273b8874 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.h +++ b/drivers/net/ethernet/intel/ice/ice_repr.h @@ -13,6 +13,7 @@ struct ice_repr { struct net_device *netdev; struct metadata_dst *dst; struct ice_esw_br_port *br_port; + int q_id; #ifdef CONFIG_ICE_SWITCHDEV /* info about slow path rule */ struct ice_rule_query_data sp_rule; From 5c53c1224f241284d1945c62697e1140f2147b05 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:19 +0200 Subject: [PATCH 0450/7721] ice: use repr instead of vf->repr Extract repr from vf->repr as it is often use in the ice_repr_rem(). Remove meaningless clearing of q_vector and netdev pointers as kfree is called on repr pointer. Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_repr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index a2dc216c964f..903a3385eacb 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -355,16 +355,16 @@ static int ice_repr_add(struct ice_vf *vf) */ static void ice_repr_rem(struct ice_vf *vf) { - if (!vf->repr) + struct ice_repr *repr = vf->repr; + + if (!repr) return; - kfree(vf->repr->q_vector); - vf->repr->q_vector = NULL; - unregister_netdev(vf->repr->netdev); + kfree(repr->q_vector); + unregister_netdev(repr->netdev); ice_devlink_destroy_vf_port(vf); - free_netdev(vf->repr->netdev); - vf->repr->netdev = NULL; - kfree(vf->repr); + free_netdev(repr->netdev); + kfree(repr); vf->repr = NULL; ice_virtchnl_set_dflt_ops(vf); From af41b1859024114c672c483ccd635c88b71eaf3d Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:20 +0200 Subject: [PATCH 0451/7721] ice: track port representors in xarray Instead of assuming that each VF has pointer to port representor save it in xarray. It will allow adding port representor for other device types. Drop reference to VF where it is use only to get port representor. Get it from xarray instead. The functions will no longer by specific for VF, rename them. Track id assigned by xarray in port representor structure. The id can't be used as ::q_id, because it is fixed during port representor lifetime. ::q_id can change after adding / removing other port representors. Side effect of removing VF pointer is that we are losing VF MAC information used in unrolling. Store it in port representor as parent MAC. Reviewed-by: Piotr Raczynski Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_eswitch.c | 182 +++++++++---------- drivers/net/ethernet/intel/ice/ice_main.c | 2 + drivers/net/ethernet/intel/ice/ice_repr.c | 8 + drivers/net/ethernet/intel/ice/ice_repr.h | 2 + 5 files changed, 94 insertions(+), 101 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 6c59ca86d959..597bdb6945c6 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -526,6 +526,7 @@ struct ice_eswitch { struct ice_vsi *control_vsi; struct ice_vsi *uplink_vsi; struct ice_esw_br_offloads *br_offloads; + struct xarray reprs; bool is_running; }; diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 119185564450..a6b528bc2023 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -11,15 +11,15 @@ #include "ice_tc_lib.h" /** - * ice_eswitch_add_vf_sp_rule - add adv rule with VF's VSI index + * ice_eswitch_add_sp_rule - add adv rule with device's VSI index * @pf: pointer to PF struct - * @vf: pointer to VF struct + * @repr: pointer to the repr struct * * This function adds advanced rule that forwards packets with - * VF's VSI index to the corresponding eswitch ctrl VSI queue. + * device's VSI index to the corresponding eswitch ctrl VSI queue. */ static int -ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) +ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; struct ice_adv_rule_info rule_info = { 0 }; @@ -38,35 +38,32 @@ ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) rule_info.sw_act.vsi_handle = ctrl_vsi->idx; rule_info.sw_act.fltr_act = ICE_FWD_TO_Q; rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id + - ctrl_vsi->rxq_map[vf->repr->q_id]; + ctrl_vsi->rxq_map[repr->q_id]; rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE; rule_info.flags_info.act_valid = true; rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN; - rule_info.src_vsi = vf->lan_vsi_idx; + rule_info.src_vsi = repr->src_vsi->idx; err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, - &vf->repr->sp_rule); + &repr->sp_rule); if (err) - dev_err(ice_pf_to_dev(pf), "Unable to add VF slow-path rule in switchdev mode for VF %d", - vf->vf_id); + dev_err(ice_pf_to_dev(pf), "Unable to add slow-path rule in switchdev mode"); kfree(list); return err; } /** - * ice_eswitch_del_vf_sp_rule - delete adv rule with VF's VSI index - * @vf: pointer to the VF struct + * ice_eswitch_del_sp_rule - delete adv rule with device's VSI index + * @pf: pointer to the PF struct + * @repr: pointer to the repr struct * - * Delete the advanced rule that was used to forward packets with the VF's VSI - * index to the corresponding eswitch ctrl VSI queue. + * Delete the advanced rule that was used to forward packets with the device's + * VSI index to the corresponding eswitch ctrl VSI queue. */ -static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf) +static void ice_eswitch_del_sp_rule(struct ice_pf *pf, struct ice_repr *repr) { - if (!vf->repr) - return; - - ice_rem_adv_rule_by_id(&vf->pf->hw, &vf->repr->sp_rule); + ice_rem_adv_rule_by_id(&pf->hw, &repr->sp_rule); } /** @@ -193,26 +190,24 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) static void ice_eswitch_release_reprs(struct ice_pf *pf) { - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; - lockdep_assert_held(&pf->vfs.table_lock); + xa_for_each(&pf->eswitch.reprs, id, repr) { + struct ice_vsi *vsi = repr->src_vsi; - ice_for_each_vf(pf, bkt, vf) { - struct ice_vsi *vsi = vf->repr->src_vsi; - - /* Skip VFs that aren't configured */ - if (!vf->repr->dst) + /* Skip representors that aren't configured */ + if (!repr->dst) continue; ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); - metadata_dst_free(vf->repr->dst); - vf->repr->dst = NULL; - ice_eswitch_del_vf_sp_rule(vf); - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + metadata_dst_free(repr->dst); + repr->dst = NULL; + ice_eswitch_del_sp_rule(pf, repr); + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); - netif_napi_del(&vf->repr->q_vector->napi); + netif_napi_del(&repr->q_vector->napi); } } @@ -223,56 +218,53 @@ ice_eswitch_release_reprs(struct ice_pf *pf) static int ice_eswitch_setup_reprs(struct ice_pf *pf) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) { - struct ice_vsi *vsi = vf->repr->src_vsi; + xa_for_each(&pf->eswitch.reprs, id, repr) { + struct ice_vsi *vsi = repr->src_vsi; ice_remove_vsi_fltr(&pf->hw, vsi->idx); - vf->repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, - GFP_KERNEL); - if (!vf->repr->dst) { - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, + GFP_KERNEL); + if (!repr->dst) { + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); goto err; } - if (ice_eswitch_add_vf_sp_rule(pf, vf)) { - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + if (ice_eswitch_add_sp_rule(pf, repr)) { + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); goto err; } if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof)) { - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); - ice_eswitch_del_vf_sp_rule(vf); - metadata_dst_free(vf->repr->dst); - vf->repr->dst = NULL; + ice_eswitch_del_sp_rule(pf, repr); + metadata_dst_free(repr->dst); + repr->dst = NULL; goto err; } if (ice_vsi_add_vlan_zero(vsi)) { - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); - ice_eswitch_del_vf_sp_rule(vf); - metadata_dst_free(vf->repr->dst); - vf->repr->dst = NULL; + ice_eswitch_del_sp_rule(pf, repr); + metadata_dst_free(repr->dst); + repr->dst = NULL; ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); goto err; } - netif_napi_add(vf->repr->netdev, &vf->repr->q_vector->napi, + netif_napi_add(repr->netdev, &repr->q_vector->napi, ice_napi_poll); - netif_keep_dst(vf->repr->netdev); + netif_keep_dst(repr->netdev); } - ice_for_each_vf(pf, bkt, vf) { - struct ice_repr *repr = vf->repr; + xa_for_each(&pf->eswitch.reprs, id, repr) { struct ice_vsi *vsi = repr->src_vsi; struct metadata_dst *dst; @@ -291,7 +283,7 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) } /** - * ice_eswitch_update_repr - reconfigure VF port representor + * ice_eswitch_update_repr - reconfigure port representor * @vsi: VF VSI for which port representor is configured */ void ice_eswitch_update_repr(struct ice_vsi *vsi) @@ -420,47 +412,41 @@ ice_eswitch_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) /** * ice_eswitch_napi_del - remove NAPI handle for all port representors - * @pf: pointer to PF structure + * @reprs: xarray of reprs */ -static void ice_eswitch_napi_del(struct ice_pf *pf) +static void ice_eswitch_napi_del(struct xarray *reprs) { - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) - netif_napi_del(&vf->repr->q_vector->napi); + xa_for_each(reprs, id, repr) + netif_napi_del(&repr->q_vector->napi); } /** * ice_eswitch_napi_enable - enable NAPI for all port representors - * @pf: pointer to PF structure + * @reprs: xarray of reprs */ -static void ice_eswitch_napi_enable(struct ice_pf *pf) +static void ice_eswitch_napi_enable(struct xarray *reprs) { - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) - napi_enable(&vf->repr->q_vector->napi); + xa_for_each(reprs, id, repr) + napi_enable(&repr->q_vector->napi); } /** * ice_eswitch_napi_disable - disable NAPI for all port representors - * @pf: pointer to PF structure + * @reprs: xarray of reprs */ -static void ice_eswitch_napi_disable(struct ice_pf *pf) +static void ice_eswitch_napi_disable(struct xarray *reprs) { - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) - napi_disable(&vf->repr->q_vector->napi); + xa_for_each(reprs, id, repr) + napi_disable(&repr->q_vector->napi); } /** @@ -505,7 +491,7 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) if (ice_eswitch_br_offloads_init(pf)) goto err_br_offloads; - ice_eswitch_napi_enable(pf); + ice_eswitch_napi_enable(&pf->eswitch.reprs); return 0; @@ -528,7 +514,7 @@ static void ice_eswitch_disable_switchdev(struct ice_pf *pf) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - ice_eswitch_napi_disable(pf); + ice_eswitch_napi_disable(&pf->eswitch.reprs); ice_eswitch_br_offloads_deinit(pf); ice_eswitch_release_env(pf); ice_eswitch_release_reprs(pf); @@ -561,6 +547,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode, case DEVLINK_ESWITCH_MODE_LEGACY: dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to legacy", pf->hw.pf_id); + xa_destroy(&pf->eswitch.reprs); NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to legacy"); break; case DEVLINK_ESWITCH_MODE_SWITCHDEV: @@ -573,6 +560,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode, dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to switchdev", pf->hw.pf_id); + xa_init_flags(&pf->eswitch.reprs, XA_FLAGS_ALLOC); NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to switchdev"); break; } @@ -649,18 +637,14 @@ int ice_eswitch_configure(struct ice_pf *pf) */ static void ice_eswitch_start_all_tx_queues(struct ice_pf *pf) { - struct ice_vf *vf; - unsigned int bkt; - - lockdep_assert_held(&pf->vfs.table_lock); + struct ice_repr *repr; + unsigned long id; if (test_bit(ICE_DOWN, pf->state)) return; - ice_for_each_vf(pf, bkt, vf) { - if (vf->repr) - ice_repr_start_tx_queues(vf->repr); - } + xa_for_each(&pf->eswitch.reprs, id, repr) + ice_repr_start_tx_queues(repr); } /** @@ -669,18 +653,14 @@ static void ice_eswitch_start_all_tx_queues(struct ice_pf *pf) */ void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) { - struct ice_vf *vf; - unsigned int bkt; - - lockdep_assert_held(&pf->vfs.table_lock); + struct ice_repr *repr; + unsigned long id; if (test_bit(ICE_DOWN, pf->state)) return; - ice_for_each_vf(pf, bkt, vf) { - if (vf->repr) - ice_repr_stop_tx_queues(vf->repr); - } + xa_for_each(&pf->eswitch.reprs, id, repr) + ice_repr_stop_tx_queues(repr); } /** @@ -692,8 +672,8 @@ int ice_eswitch_rebuild(struct ice_pf *pf) struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; int status; - ice_eswitch_napi_disable(pf); - ice_eswitch_napi_del(pf); + ice_eswitch_napi_disable(&pf->eswitch.reprs); + ice_eswitch_napi_del(&pf->eswitch.reprs); status = ice_eswitch_setup_env(pf); if (status) @@ -711,7 +691,7 @@ int ice_eswitch_rebuild(struct ice_pf *pf) if (status) return status; - ice_eswitch_napi_enable(pf); + ice_eswitch_napi_enable(&pf->eswitch.reprs); ice_eswitch_start_all_tx_queues(pf); return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6607fa6fe556..7ea6e2ad3272 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4702,6 +4702,8 @@ static void ice_deinit_features(struct ice_pf *pf) ice_ptp_release(pf); if (test_bit(ICE_FLAG_DPLL, pf->flags)) ice_dpll_deinit(pf); + if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) + xa_destroy(&pf->eswitch.reprs); } static void ice_init_wakeup(struct ice_pf *pf) diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index 903a3385eacb..e56c59a304ef 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -318,6 +318,11 @@ static int ice_repr_add(struct ice_vf *vf) } repr->q_vector = q_vector; + err = xa_alloc(&vf->pf->eswitch.reprs, &repr->id, repr, + xa_limit_32b, GFP_KERNEL); + if (err) + goto err_xa_alloc; + err = ice_devlink_create_vf_port(vf); if (err) goto err_devlink; @@ -338,6 +343,8 @@ static int ice_repr_add(struct ice_vf *vf) err_netdev: ice_devlink_destroy_vf_port(vf); err_devlink: + xa_erase(&vf->pf->eswitch.reprs, repr->id); +err_xa_alloc: kfree(repr->q_vector); vf->repr->q_vector = NULL; err_alloc_q_vector: @@ -363,6 +370,7 @@ static void ice_repr_rem(struct ice_vf *vf) kfree(repr->q_vector); unregister_netdev(repr->netdev); ice_devlink_destroy_vf_port(vf); + xa_erase(&vf->pf->eswitch.reprs, repr->id); free_netdev(repr->netdev); kfree(repr); vf->repr = NULL; diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h index f350273b8874..735cb556c620 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.h +++ b/drivers/net/ethernet/intel/ice/ice_repr.h @@ -14,6 +14,8 @@ struct ice_repr { struct metadata_dst *dst; struct ice_esw_br_port *br_port; int q_id; + u32 id; + u8 parent_mac[ETH_ALEN]; #ifdef CONFIG_ICE_SWITCHDEV /* info about slow path rule */ struct ice_rule_query_data sp_rule; From e4c46abc729130d03e22ce7e54554c698df8893d Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:21 +0200 Subject: [PATCH 0452/7721] ice: remove VF pointer reference in eswitch code Make eswitch code generic by removing VF pointer reference in functions. It is needed to support eswitch mode for other type of devices. Previously queue id used for Rx was based on VF number. Use ::q_id saved in port representor instead. After adding or removing port representor ::q_id value can change. It isn't good idea to iterate over representors list using this value. Use xa_find starting from the first one instead to get next port representor to remap. The number of port representors has to be equal to ::num_rx/tx_q. Warn if it isn't true. Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 39 ++++++++++---------- drivers/net/ethernet/intel/ice/ice_eswitch.h | 5 ++- drivers/net/ethernet/intel/ice/ice_repr.c | 1 + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 2 +- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index a6b528bc2023..66cbe2c80fea 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -47,7 +47,8 @@ ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr) err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, &repr->sp_rule); if (err) - dev_err(ice_pf_to_dev(pf), "Unable to add slow-path rule in switchdev mode"); + dev_err(ice_pf_to_dev(pf), "Unable to add slow-path rule for eswitch for PR %d", + repr->id); kfree(list); return err; @@ -142,6 +143,7 @@ static int ice_eswitch_setup_env(struct ice_pf *pf) static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) { struct ice_vsi *vsi = pf->eswitch.control_vsi; + unsigned long repr_id = 0; int q_id; ice_for_each_txq(vsi, q_id) { @@ -149,13 +151,14 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) struct ice_tx_ring *tx_ring; struct ice_rx_ring *rx_ring; struct ice_repr *repr; - struct ice_vf *vf; - vf = ice_get_vf_by_id(pf, q_id); - if (WARN_ON(!vf)) - continue; + repr = xa_find(&pf->eswitch.reprs, &repr_id, U32_MAX, + XA_PRESENT); + if (WARN_ON(!repr)) + break; - repr = vf->repr; + repr_id += 1; + repr->q_id = q_id; q_vector = repr->q_vector; tx_ring = vsi->tx_rings[q_id]; rx_ring = vsi->rx_rings[q_id]; @@ -178,8 +181,6 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) rx_ring->q_vector = q_vector; rx_ring->next = NULL; rx_ring->netdev = repr->netdev; - - ice_put_vf(vf); } } @@ -284,20 +285,17 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) /** * ice_eswitch_update_repr - reconfigure port representor - * @vsi: VF VSI for which port representor is configured + * @repr: pointer to repr struct + * @vsi: VSI for which port representor is configured */ -void ice_eswitch_update_repr(struct ice_vsi *vsi) +void ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - struct ice_repr *repr; - struct ice_vf *vf; int ret; if (!ice_is_switchdev_running(pf)) return; - vf = vsi->vf; - repr = vf->repr; repr->src_vsi = vsi; repr->dst->u.port_info.port_id = vsi->vsi_num; @@ -306,9 +304,10 @@ void ice_eswitch_update_repr(struct ice_vsi *vsi) ret = ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof); if (ret) { - ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI); - dev_err(ice_pf_to_dev(pf), "Failed to update VF %d port representor", - vsi->vf->vf_id); + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, + ICE_FWD_TO_VSI); + dev_err(ice_pf_to_dev(pf), "Failed to update VSI of port representor %d", + repr->id); } } @@ -340,7 +339,7 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev) skb_dst_drop(skb); dst_hold((struct dst_entry *)repr->dst); skb_dst_set(skb, (struct dst_entry *)repr->dst); - skb->queue_mapping = repr->vf->vf_id; + skb->queue_mapping = repr->q_id; return ice_start_xmit(skb, netdev); } @@ -486,7 +485,7 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) ice_eswitch_remap_rings_to_vectors(pf); if (ice_vsi_open(ctrl_vsi)) - goto err_setup_reprs; + goto err_vsi_open; if (ice_eswitch_br_offloads_init(pf)) goto err_br_offloads; @@ -497,6 +496,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) err_br_offloads: ice_vsi_close(ctrl_vsi); +err_vsi_open: + ice_eswitch_release_reprs(pf); err_setup_reprs: ice_repr_rem_from_all_vfs(pf); err_repr_add: diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index b18bf83a2f5b..f43db1cce3ad 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -17,7 +17,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode, struct netlink_ext_ack *extack); bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf); -void ice_eswitch_update_repr(struct ice_vsi *vsi); +void ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi); void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf); @@ -34,7 +34,8 @@ static inline void ice_eswitch_set_target_vsi(struct sk_buff *skb, struct ice_tx_offload_params *off) { } -static inline void ice_eswitch_update_repr(struct ice_vsi *vsi) { } +static inline void +ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi) { } static inline int ice_eswitch_configure(struct ice_pf *pf) { diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index e56c59a304ef..77cc77ab826a 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -336,6 +336,7 @@ static int ice_repr_add(struct ice_vf *vf) if (err) goto err_netdev; + ether_addr_copy(repr->parent_mac, vf->hw_lan_addr); ice_virtchnl_set_repr_ops(vf); return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index aca1f2ea5034..462ee9fdf815 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -928,7 +928,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) goto out_unlock; } - ice_eswitch_update_repr(vsi); + ice_eswitch_update_repr(vf->repr, vsi); /* if the VF has been reset allow it to come up again */ ice_mbx_clear_malvf(&vf->mbx_info); From 604283e95eb0b2f4f38238e7acec4f1d68e00e2e Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:22 +0200 Subject: [PATCH 0453/7721] ice: make representor code generic Representor code needs to be independent from specific device type, like in this case VF. Make generic add / remove representor function and specific add VF / rem VF function. New device types will follow this scheme. In bridge offload code there is a need to get representor pointer based on VSI. Implement helper function to achieve that. Reviewed-by: Piotr Raczynski Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 9 +- drivers/net/ethernet/intel/ice/ice_eswitch.h | 4 +- .../net/ethernet/intel/ice/ice_eswitch_br.c | 10 +- drivers/net/ethernet/intel/ice/ice_lib.c | 10 +- drivers/net/ethernet/intel/ice/ice_repr.c | 204 ++++++++++-------- drivers/net/ethernet/intel/ice/ice_repr.h | 2 + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 2 +- drivers/net/ethernet/intel/ice/ice_vf_lib.h | 2 +- 8 files changed, 141 insertions(+), 102 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 66cbe2c80fea..67231e43ffa6 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -285,17 +285,22 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) /** * ice_eswitch_update_repr - reconfigure port representor - * @repr: pointer to repr struct + * @repr_id: representor ID * @vsi: VSI for which port representor is configured */ -void ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi) +void ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + struct ice_repr *repr; int ret; if (!ice_is_switchdev_running(pf)) return; + repr = xa_load(&pf->eswitch.reprs, repr_id); + if (!repr) + return; + repr->src_vsi = vsi; repr->dst->u.port_info.port_id = vsi->vsi_num; diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index f43db1cce3ad..ff110bd9fc4c 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -17,7 +17,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode, struct netlink_ext_ack *extack); bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf); -void ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi); +void ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi); void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf); @@ -35,7 +35,7 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb, struct ice_tx_offload_params *off) { } static inline void -ice_eswitch_update_repr(struct ice_repr *repr, struct ice_vsi *vsi) { } +ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi) { } static inline int ice_eswitch_configure(struct ice_pf *pf) { diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c index 16bbcaca8fda..ac5beecd028b 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c @@ -893,10 +893,14 @@ ice_eswitch_br_port_deinit(struct ice_esw_br *bridge, ice_eswitch_br_fdb_entry_delete(bridge, fdb_entry); } - if (br_port->type == ICE_ESWITCH_BR_UPLINK_PORT && vsi->back) + if (br_port->type == ICE_ESWITCH_BR_UPLINK_PORT && vsi->back) { vsi->back->br_port = NULL; - else if (vsi->vf && vsi->vf->repr) - vsi->vf->repr->br_port = NULL; + } else { + struct ice_repr *repr = ice_repr_get_by_vsi(vsi); + + if (repr) + repr->br_port = NULL; + } xa_erase(&bridge->ports, br_port->vsi_idx); ice_eswitch_br_port_vlans_flush(br_port); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 4b1e56396293..ae4b4220e1bb 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -519,16 +519,14 @@ static irqreturn_t ice_eswitch_msix_clean_rings(int __always_unused irq, void *d { struct ice_q_vector *q_vector = (struct ice_q_vector *)data; struct ice_pf *pf = q_vector->vsi->back; - struct ice_vf *vf; - unsigned int bkt; + struct ice_repr *repr; + unsigned long id; if (!q_vector->tx.tx_ring && !q_vector->rx.rx_ring) return IRQ_HANDLED; - rcu_read_lock(); - ice_for_each_vf_rcu(pf, bkt, vf) - napi_schedule(&vf->repr->q_vector->napi); - rcu_read_unlock(); + xa_for_each(&pf->eswitch.reprs, id, repr) + napi_schedule(&repr->q_vector->napi); return IRQ_HANDLED; } diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index 77cc77ab826a..fce25472d053 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -14,7 +14,7 @@ */ static int ice_repr_get_sw_port_id(struct ice_repr *repr) { - return repr->vf->pf->hw.port_info->lport; + return repr->src_vsi->back->hw.port_info->lport; } /** @@ -35,7 +35,7 @@ ice_repr_get_phys_port_name(struct net_device *netdev, char *buf, size_t len) return -EOPNOTSUPP; res = snprintf(buf, len, "pf%dvfr%d", ice_repr_get_sw_port_id(repr), - repr->vf->vf_id); + repr->id); if (res <= 0) return -EOPNOTSUPP; return 0; @@ -279,103 +279,28 @@ ice_repr_reg_netdev(struct net_device *netdev) } /** - * ice_repr_add - add representor for VF - * @vf: pointer to VF structure + * ice_repr_rem - remove representor from VF + * @reprs: xarray storing representors + * @repr: pointer to representor structure */ -static int ice_repr_add(struct ice_vf *vf) +static void ice_repr_rem(struct xarray *reprs, struct ice_repr *repr) { - struct ice_q_vector *q_vector; - struct ice_netdev_priv *np; - struct ice_repr *repr; - struct ice_vsi *vsi; - int err; - - vsi = ice_get_vf_vsi(vf); - if (!vsi) - return -EINVAL; - - repr = kzalloc(sizeof(*repr), GFP_KERNEL); - if (!repr) - return -ENOMEM; - - repr->netdev = alloc_etherdev(sizeof(struct ice_netdev_priv)); - if (!repr->netdev) { - err = -ENOMEM; - goto err_alloc; - } - - repr->src_vsi = vsi; - repr->vf = vf; - repr->q_id = vf->vf_id; - vf->repr = repr; - np = netdev_priv(repr->netdev); - np->repr = repr; - - q_vector = kzalloc(sizeof(*q_vector), GFP_KERNEL); - if (!q_vector) { - err = -ENOMEM; - goto err_alloc_q_vector; - } - repr->q_vector = q_vector; - - err = xa_alloc(&vf->pf->eswitch.reprs, &repr->id, repr, - xa_limit_32b, GFP_KERNEL); - if (err) - goto err_xa_alloc; - - err = ice_devlink_create_vf_port(vf); - if (err) - goto err_devlink; - - repr->netdev->min_mtu = ETH_MIN_MTU; - repr->netdev->max_mtu = ICE_MAX_MTU; - - SET_NETDEV_DEV(repr->netdev, ice_pf_to_dev(vf->pf)); - SET_NETDEV_DEVLINK_PORT(repr->netdev, &vf->devlink_port); - err = ice_repr_reg_netdev(repr->netdev); - if (err) - goto err_netdev; - - ether_addr_copy(repr->parent_mac, vf->hw_lan_addr); - ice_virtchnl_set_repr_ops(vf); - - return 0; - -err_netdev: - ice_devlink_destroy_vf_port(vf); -err_devlink: - xa_erase(&vf->pf->eswitch.reprs, repr->id); -err_xa_alloc: + xa_erase(reprs, repr->id); kfree(repr->q_vector); - vf->repr->q_vector = NULL; -err_alloc_q_vector: free_netdev(repr->netdev); - repr->netdev = NULL; -err_alloc: kfree(repr); - vf->repr = NULL; - return err; } -/** - * ice_repr_rem - remove representor from VF - * @vf: pointer to VF structure - */ -static void ice_repr_rem(struct ice_vf *vf) +static void ice_repr_rem_vf(struct ice_vf *vf) { - struct ice_repr *repr = vf->repr; + struct ice_repr *repr = xa_load(&vf->pf->eswitch.reprs, vf->repr_id); if (!repr) return; - kfree(repr->q_vector); unregister_netdev(repr->netdev); + ice_repr_rem(&vf->pf->eswitch.reprs, repr); ice_devlink_destroy_vf_port(vf); - xa_erase(&vf->pf->eswitch.reprs, repr->id); - free_netdev(repr->netdev); - kfree(repr); - vf->repr = NULL; - ice_virtchnl_set_dflt_ops(vf); } @@ -392,7 +317,7 @@ void ice_repr_rem_from_all_vfs(struct ice_pf *pf) lockdep_assert_held(&pf->vfs.table_lock); ice_for_each_vf(pf, bkt, vf) - ice_repr_rem(vf); + ice_repr_rem_vf(vf); /* since all port representors are destroyed, there is * no point in keeping the nodes @@ -403,6 +328,103 @@ void ice_repr_rem_from_all_vfs(struct ice_pf *pf) devl_unlock(devlink); } +/** + * ice_repr_add - add representor for generic VSI + * @pf: pointer to PF structure + * @src_vsi: pointer to VSI structure of device to represent + * @parent_mac: device MAC address + */ +static struct ice_repr * +ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac) +{ + struct ice_q_vector *q_vector; + struct ice_netdev_priv *np; + struct ice_repr *repr; + int err; + + repr = kzalloc(sizeof(*repr), GFP_KERNEL); + if (!repr) + return ERR_PTR(-ENOMEM); + + repr->netdev = alloc_etherdev(sizeof(struct ice_netdev_priv)); + if (!repr->netdev) { + err = -ENOMEM; + goto err_alloc; + } + + repr->src_vsi = src_vsi; + np = netdev_priv(repr->netdev); + np->repr = repr; + + q_vector = kzalloc(sizeof(*q_vector), GFP_KERNEL); + if (!q_vector) { + err = -ENOMEM; + goto err_alloc_q_vector; + } + repr->q_vector = q_vector; + + err = xa_alloc(&pf->eswitch.reprs, &repr->id, repr, + XA_LIMIT(1, INT_MAX), GFP_KERNEL); + if (err) + goto err_xa_alloc; + repr->q_id = repr->id; + + ether_addr_copy(repr->parent_mac, parent_mac); + + return repr; + +err_xa_alloc: + kfree(repr->q_vector); +err_alloc_q_vector: + free_netdev(repr->netdev); +err_alloc: + kfree(repr); + return ERR_PTR(err); +} + +static int ice_repr_add_vf(struct ice_vf *vf) +{ + struct ice_repr *repr; + struct ice_vsi *vsi; + int err; + + vsi = ice_get_vf_vsi(vf); + if (!vsi) + return -EINVAL; + + err = ice_devlink_create_vf_port(vf); + if (err) + return err; + + repr = ice_repr_add(vf->pf, vsi, vf->hw_lan_addr); + if (IS_ERR(repr)) { + err = PTR_ERR(repr); + goto err_repr_add; + } + + vf->repr_id = repr->id; + repr->vf = vf; + + repr->netdev->min_mtu = ETH_MIN_MTU; + repr->netdev->max_mtu = ICE_MAX_MTU; + + SET_NETDEV_DEV(repr->netdev, ice_pf_to_dev(vf->pf)); + SET_NETDEV_DEVLINK_PORT(repr->netdev, &vf->devlink_port); + err = ice_repr_reg_netdev(repr->netdev); + if (err) + goto err_netdev; + + ice_virtchnl_set_repr_ops(vf); + + return 0; + +err_netdev: + ice_repr_rem(&vf->pf->eswitch.reprs, repr); +err_repr_add: + ice_devlink_destroy_vf_port(vf); + return err; +} + /** * ice_repr_add_for_all_vfs - add port representor for all VFs * @pf: pointer to PF structure @@ -417,7 +439,7 @@ int ice_repr_add_for_all_vfs(struct ice_pf *pf) lockdep_assert_held(&pf->vfs.table_lock); ice_for_each_vf(pf, bkt, vf) { - err = ice_repr_add(vf); + err = ice_repr_add_vf(vf); if (err) goto err; } @@ -437,6 +459,14 @@ int ice_repr_add_for_all_vfs(struct ice_pf *pf) return err; } +struct ice_repr *ice_repr_get_by_vsi(struct ice_vsi *vsi) +{ + if (!vsi->vf) + return NULL; + + return xa_load(&vsi->back->eswitch.reprs, vsi->vf->repr_id); +} + /** * ice_repr_start_tx_queues - start Tx queues of port representor * @repr: pointer to repr structure diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h index 735cb556c620..a3cd256d82b7 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.h +++ b/drivers/net/ethernet/intel/ice/ice_repr.h @@ -32,4 +32,6 @@ void ice_repr_set_traffic_vsi(struct ice_repr *repr, struct ice_vsi *vsi); struct ice_repr *ice_netdev_to_repr(struct net_device *netdev); bool ice_is_port_repr_netdev(const struct net_device *netdev); + +struct ice_repr *ice_repr_get_by_vsi(struct ice_vsi *vsi); #endif diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 462ee9fdf815..68f9de0a7a8f 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -928,7 +928,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) goto out_unlock; } - ice_eswitch_update_repr(vf->repr, vsi); + ice_eswitch_update_repr(vf->repr_id, vsi); /* if the VF has been reset allow it to come up again */ ice_mbx_clear_malvf(&vf->mbx_info); diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index 93c774f2f437..35866553f288 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -130,7 +130,7 @@ struct ice_vf { struct ice_mdd_vf_events mdd_tx_events; DECLARE_BITMAP(opcodes_allowlist, VIRTCHNL_OP_MAX); - struct ice_repr *repr; + unsigned long repr_id; const struct ice_virtchnl_ops *virtchnl_ops; const struct ice_vf_ops *vf_ops; From deb53f2030e7db0e5f9c0b1ffdfd4fa43aa10ce5 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:23 +0200 Subject: [PATCH 0454/7721] ice: return pointer to representor In follow up patches it will be easier to obtain created port representor pointer instead of the id. Without it the pattern from eswitch side will look like: - create PR - get PR based on the id Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_repr.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index fce25472d053..b29a3d010780 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -382,7 +382,7 @@ ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac) return ERR_PTR(err); } -static int ice_repr_add_vf(struct ice_vf *vf) +static struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) { struct ice_repr *repr; struct ice_vsi *vsi; @@ -390,11 +390,11 @@ static int ice_repr_add_vf(struct ice_vf *vf) vsi = ice_get_vf_vsi(vf); if (!vsi) - return -EINVAL; + return ERR_PTR(-ENOENT); err = ice_devlink_create_vf_port(vf); if (err) - return err; + return ERR_PTR(err); repr = ice_repr_add(vf->pf, vsi, vf->hw_lan_addr); if (IS_ERR(repr)) { @@ -416,13 +416,13 @@ static int ice_repr_add_vf(struct ice_vf *vf) ice_virtchnl_set_repr_ops(vf); - return 0; + return repr; err_netdev: ice_repr_rem(&vf->pf->eswitch.reprs, repr); err_repr_add: ice_devlink_destroy_vf_port(vf); - return err; + return ERR_PTR(err); } /** @@ -432,6 +432,7 @@ static int ice_repr_add_vf(struct ice_vf *vf) int ice_repr_add_for_all_vfs(struct ice_pf *pf) { struct devlink *devlink; + struct ice_repr *repr; struct ice_vf *vf; unsigned int bkt; int err; @@ -439,9 +440,11 @@ int ice_repr_add_for_all_vfs(struct ice_pf *pf) lockdep_assert_held(&pf->vfs.table_lock); ice_for_each_vf(pf, bkt, vf) { - err = ice_repr_add_vf(vf); - if (err) + repr = ice_repr_add_vf(vf); + if (IS_ERR(repr)) { + err = PTR_ERR(repr); goto err; + } } /* only export if ADQ and DCB disabled */ From 292e0154006fcd7351cda334e928b089934c6fed Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:24 +0200 Subject: [PATCH 0455/7721] ice: allow changing SWITCHDEV_CTRL VSI queues Implement mechanism to change number of queues for SWITCHDEV_CTRL VSI type. Value from ::req_txq/rxq will be written to ::alloc_txq/rxq after calling ice_vsi_rebuild(). Reviewed-by: Piotr Raczynski Reviewed-by: Wojciech Drewek Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index ae4b4220e1bb..85a8cb28a489 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -212,11 +212,18 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) vsi->alloc_txq)); break; case ICE_VSI_SWITCHDEV_CTRL: - /* The number of queues for ctrl VSI is equal to number of VFs. + /* The number of queues for ctrl VSI is equal to number of PRs * Each ring is associated to the corresponding VF_PR netdev. + * Tx and Rx rings are always equal */ - vsi->alloc_txq = ice_get_num_vfs(pf); - vsi->alloc_rxq = vsi->alloc_txq; + if (vsi->req_txq && vsi->req_rxq) { + vsi->alloc_txq = vsi->req_txq; + vsi->alloc_rxq = vsi->req_rxq; + } else { + vsi->alloc_txq = 1; + vsi->alloc_rxq = 1; + } + vsi->num_q_vectors = 1; break; case ICE_VSI_VF: From 86197ad5800bf5c2653495374b857ae5096d54ac Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:25 +0200 Subject: [PATCH 0456/7721] ice: set Tx topology every time new repr is added It is needed to track correct Tx topology. Update it every time new representor is created or remove node in case of removing corresponding representor. Still clear all node when removing switchdev mode as part of Tx topology isn't related only to representors. Also clear ::rate_note value to prevent skipping this node next time Tx topology is created. Reviewed-by: Piotr Raczynski Reviewed-by: Wojciech Drewek Reviewed-by: Jacob Keller Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_devlink.c | 29 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_devlink.h | 1 + drivers/net/ethernet/intel/ice/ice_eswitch.c | 9 ++++++ drivers/net/ethernet/intel/ice/ice_repr.c | 27 +++++++++++++----- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 80dc5445b50d..f4e24d11ebd0 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -810,6 +810,10 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node struct ice_vf *vf; int i; + if (node->rate_node) + /* already added, skip to the next */ + goto traverse_children; + if (node->parent == tc_node) { /* create root node */ rate_node = devl_rate_node_create(devlink, node, node->name, NULL); @@ -831,6 +835,7 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node if (rate_node && !IS_ERR(rate_node)) node->rate_node = rate_node; +traverse_children: for (i = 0; i < node->num_children; i++) ice_traverse_tx_tree(devlink, node->children[i], tc_node, pf); } @@ -861,6 +866,30 @@ int ice_devlink_rate_init_tx_topology(struct devlink *devlink, struct ice_vsi *v return 0; } +static void ice_clear_rate_nodes(struct ice_sched_node *node) +{ + node->rate_node = NULL; + + for (int i = 0; i < node->num_children; i++) + ice_clear_rate_nodes(node->children[i]); +} + +/** + * ice_devlink_rate_clear_tx_topology - clear node->rate_node + * @vsi: main vsi struct + * + * Clear rate_node to cleanup creation of Tx topology. + * + */ +void ice_devlink_rate_clear_tx_topology(struct ice_vsi *vsi) +{ + struct ice_port_info *pi = vsi->port_info; + + mutex_lock(&pi->sched_lock); + ice_clear_rate_nodes(pi->root->children[0]); + mutex_unlock(&pi->sched_lock); +} + /** * ice_set_object_tx_share - sets node scheduling parameter * @pi: devlink struct instance diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.h b/drivers/net/ethernet/intel/ice/ice_devlink.h index 6ec96779f52e..d291c0e2e17b 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.h +++ b/drivers/net/ethernet/intel/ice/ice_devlink.h @@ -20,5 +20,6 @@ void ice_devlink_destroy_regions(struct ice_pf *pf); int ice_devlink_rate_init_tx_topology(struct devlink *devlink, struct ice_vsi *vsi); void ice_tear_down_devlink_rate_tree(struct ice_pf *pf); +void ice_devlink_rate_clear_tx_topology(struct ice_vsi *vsi); #endif /* _ICE_DEVLINK_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 67231e43ffa6..db70a62429e3 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -519,6 +519,7 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) static void ice_eswitch_disable_switchdev(struct ice_pf *pf) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; + struct devlink *devlink = priv_to_devlink(pf); ice_eswitch_napi_disable(&pf->eswitch.reprs); ice_eswitch_br_offloads_deinit(pf); @@ -526,6 +527,14 @@ static void ice_eswitch_disable_switchdev(struct ice_pf *pf) ice_eswitch_release_reprs(pf); ice_vsi_release(ctrl_vsi); ice_repr_rem_from_all_vfs(pf); + + /* since all port representors are destroyed, there is + * no point in keeping the nodes + */ + ice_devlink_rate_clear_tx_topology(ice_get_main_vsi(pf)); + devl_lock(devlink); + devl_rate_nodes_destroy(devlink); + devl_unlock(devlink); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index b29a3d010780..fa36cc932c5f 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -278,6 +278,13 @@ ice_repr_reg_netdev(struct net_device *netdev) return register_netdev(netdev); } +static void ice_repr_remove_node(struct devlink_port *devlink_port) +{ + devl_lock(devlink_port->devlink); + devl_rate_leaf_destroy(devlink_port); + devl_unlock(devlink_port->devlink); +} + /** * ice_repr_rem - remove representor from VF * @reprs: xarray storing representors @@ -298,6 +305,7 @@ static void ice_repr_rem_vf(struct ice_vf *vf) if (!repr) return; + ice_repr_remove_node(&repr->vf->devlink_port); unregister_netdev(repr->netdev); ice_repr_rem(&vf->pf->eswitch.reprs, repr); ice_devlink_destroy_vf_port(vf); @@ -310,7 +318,6 @@ static void ice_repr_rem_vf(struct ice_vf *vf) */ void ice_repr_rem_from_all_vfs(struct ice_pf *pf) { - struct devlink *devlink; struct ice_vf *vf; unsigned int bkt; @@ -318,14 +325,19 @@ void ice_repr_rem_from_all_vfs(struct ice_pf *pf) ice_for_each_vf(pf, bkt, vf) ice_repr_rem_vf(vf); +} + +static void ice_repr_set_tx_topology(struct ice_pf *pf) +{ + struct devlink *devlink; + + /* only export if ADQ and DCB disabled and eswitch enabled*/ + if (ice_is_adq_active(pf) || ice_is_dcb_active(pf) || + !ice_is_switchdev_running(pf)) + return; - /* since all port representors are destroyed, there is - * no point in keeping the nodes - */ devlink = priv_to_devlink(pf); - devl_lock(devlink); - devl_rate_nodes_destroy(devlink); - devl_unlock(devlink); + ice_devlink_rate_init_tx_topology(devlink, ice_get_main_vsi(pf)); } /** @@ -415,6 +427,7 @@ static struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) goto err_netdev; ice_virtchnl_set_repr_ops(vf); + ice_repr_set_tx_topology(vf->pf); return repr; From 5995ef88e3a8c2b014f51256a88be8e336532ce7 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:26 +0200 Subject: [PATCH 0457/7721] ice: realloc VSI stats arrays Previously only case when queues amount is lower was covered. Implement realloc for case when queues amount is higher than previous one. Use krealloc() function and zero new allocated elements. It has to be done before ice_vsi_def_cfg(), because stats element for ring is set there. Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 58 ++++++++++++++++-------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 85a8cb28a489..d826b5afa143 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3076,27 +3076,26 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, } /** - * ice_vsi_realloc_stat_arrays - Frees unused stat structures + * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones * @vsi: VSI pointer - * @prev_txq: Number of Tx rings before ring reallocation - * @prev_rxq: Number of Rx rings before ring reallocation */ -static void -ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq) +static int +ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi) { + u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq; + u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq; + struct ice_ring_stats **tx_ring_stats; + struct ice_ring_stats **rx_ring_stats; struct ice_vsi_stats *vsi_stat; struct ice_pf *pf = vsi->back; + u16 prev_txq = vsi->alloc_txq; + u16 prev_rxq = vsi->alloc_rxq; int i; - if (!prev_txq || !prev_rxq) - return; - if (vsi->type == ICE_VSI_CHNL) - return; - vsi_stat = pf->vsi_stats[vsi->idx]; - if (vsi->num_txq < prev_txq) { - for (i = vsi->num_txq; i < prev_txq; i++) { + if (req_txq < prev_txq) { + for (i = req_txq; i < prev_txq; i++) { if (vsi_stat->tx_ring_stats[i]) { kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); @@ -3104,14 +3103,36 @@ ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq) } } - if (vsi->num_rxq < prev_rxq) { - for (i = vsi->num_rxq; i < prev_rxq; i++) { + tx_ring_stats = vsi_stat->rx_ring_stats; + vsi_stat->tx_ring_stats = + krealloc_array(vsi_stat->tx_ring_stats, req_txq, + sizeof(*vsi_stat->tx_ring_stats), + GFP_KERNEL | __GFP_ZERO); + if (!vsi_stat->tx_ring_stats) { + vsi_stat->tx_ring_stats = tx_ring_stats; + return -ENOMEM; + } + + if (req_rxq < prev_rxq) { + for (i = req_rxq; i < prev_rxq; i++) { if (vsi_stat->rx_ring_stats[i]) { kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); } } } + + rx_ring_stats = vsi_stat->rx_ring_stats; + vsi_stat->rx_ring_stats = + krealloc_array(vsi_stat->rx_ring_stats, req_rxq, + sizeof(*vsi_stat->rx_ring_stats), + GFP_KERNEL | __GFP_ZERO); + if (!vsi_stat->rx_ring_stats) { + vsi_stat->rx_ring_stats = rx_ring_stats; + return -ENOMEM; + } + + return 0; } /** @@ -3128,9 +3149,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) { struct ice_vsi_cfg_params params = {}; struct ice_coalesce_stored *coalesce; - int ret, prev_txq, prev_rxq; int prev_num_q_vectors = 0; struct ice_pf *pf; + int ret; if (!vsi) return -EINVAL; @@ -3149,8 +3170,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce); - prev_txq = vsi->num_txq; - prev_rxq = vsi->num_rxq; + ret = ice_vsi_realloc_stat_arrays(vsi); + if (ret) + goto err_vsi_cfg; ice_vsi_decfg(vsi); ret = ice_vsi_cfg_def(vsi, ¶ms); @@ -3168,8 +3190,6 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) return ice_schedule_reset(pf, ICE_RESET_PFR); } - ice_vsi_realloc_stat_arrays(vsi, prev_txq, prev_rxq); - ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors); kfree(coalesce); From fff292b47ac19258381fea50c9dfd26091ef7fbc Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:27 +0200 Subject: [PATCH 0458/7721] ice: add VF representors one by one Implement adding representors one by one. Always set switchdev environment when first representor is being added and clear environment when last one is being removed. Basic switchdev configuration remains the same. Code related to creating and configuring representor was changed. Instead of setting whole representors in one function handle only one representor in setup function. The same with removing representors. Stop representors when new one is being added or removed. Stop means, disabling napi, stopping traffic and removing slow path rule. It is needed because ::q_id will change after remapping, so each representor will need new rule. When representor are stopped rebuild control plane VSI with one more or one less queue. One more if new representor is being added, one less if representor is being removed. Bridge port is removed during unregister_netdev() call on PR, so there is no need to call it from driver side. After that do remap new queues to correct vector. At the end start all representors (napi enable, start queues, add slow path rule). Reviewed-by: Piotr Raczynski Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 349 +++++++++++-------- drivers/net/ethernet/intel/ice/ice_eswitch.h | 13 +- drivers/net/ethernet/intel/ice/ice_repr.c | 85 +---- drivers/net/ethernet/intel/ice/ice_repr.h | 4 +- drivers/net/ethernet/intel/ice/ice_sriov.c | 17 +- 5 files changed, 227 insertions(+), 241 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index db70a62429e3..de5744aa5c2a 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -10,6 +10,24 @@ #include "ice_devlink.h" #include "ice_tc_lib.h" +/** + * ice_eswitch_del_sp_rules - delete adv rules added on PRs + * @pf: pointer to the PF struct + * + * Delete all advanced rules that were used to forward packets with the + * device's VSI index to the corresponding eswitch ctrl VSI queue. + */ +static void ice_eswitch_del_sp_rules(struct ice_pf *pf) +{ + struct ice_repr *repr; + unsigned long id; + + xa_for_each(&pf->eswitch.reprs, id, repr) { + if (repr->sp_rule.rid) + ice_rem_adv_rule_by_id(&pf->hw, &repr->sp_rule); + } +} + /** * ice_eswitch_add_sp_rule - add adv rule with device's VSI index * @pf: pointer to PF struct @@ -18,8 +36,7 @@ * This function adds advanced rule that forwards packets with * device's VSI index to the corresponding eswitch ctrl VSI queue. */ -static int -ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr) +static int ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; struct ice_adv_rule_info rule_info = { 0 }; @@ -54,17 +71,22 @@ ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr) return err; } -/** - * ice_eswitch_del_sp_rule - delete adv rule with device's VSI index - * @pf: pointer to the PF struct - * @repr: pointer to the repr struct - * - * Delete the advanced rule that was used to forward packets with the device's - * VSI index to the corresponding eswitch ctrl VSI queue. - */ -static void ice_eswitch_del_sp_rule(struct ice_pf *pf, struct ice_repr *repr) +static int +ice_eswitch_add_sp_rules(struct ice_pf *pf) { - ice_rem_adv_rule_by_id(&pf->hw, &repr->sp_rule); + struct ice_repr *repr; + unsigned long id; + int err; + + xa_for_each(&pf->eswitch.reprs, id, repr) { + err = ice_eswitch_add_sp_rule(pf, repr); + if (err) { + ice_eswitch_del_sp_rules(pf); + return err; + } + } + + return 0; } /** @@ -131,7 +153,7 @@ static int ice_eswitch_setup_env(struct ice_pf *pf) /** * ice_eswitch_remap_rings_to_vectors - reconfigure rings of eswitch ctrl VSI - * @pf: pointer to PF struct + * @eswitch: pointer to eswitch struct * * In eswitch number of allocated Tx/Rx rings is equal. * @@ -140,9 +162,9 @@ static int ice_eswitch_setup_env(struct ice_pf *pf) * will have dedicated 1 Tx/Rx ring pair, so number of rings pair is equal to * number of VFs. */ -static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) +static void ice_eswitch_remap_rings_to_vectors(struct ice_eswitch *eswitch) { - struct ice_vsi *vsi = pf->eswitch.control_vsi; + struct ice_vsi *vsi = eswitch->control_vsi; unsigned long repr_id = 0; int q_id; @@ -152,7 +174,7 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) struct ice_rx_ring *rx_ring; struct ice_repr *repr; - repr = xa_find(&pf->eswitch.reprs, &repr_id, U32_MAX, + repr = xa_find(&eswitch->reprs, &repr_id, U32_MAX, XA_PRESENT); if (WARN_ON(!repr)) break; @@ -185,100 +207,70 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf) } /** - * ice_eswitch_release_reprs - clear PR VSIs configuration + * ice_eswitch_release_repr - clear PR VSI configuration * @pf: poiner to PF struct + * @repr: pointer to PR */ static void -ice_eswitch_release_reprs(struct ice_pf *pf) +ice_eswitch_release_repr(struct ice_pf *pf, struct ice_repr *repr) { - struct ice_repr *repr; - unsigned long id; + struct ice_vsi *vsi = repr->src_vsi; - xa_for_each(&pf->eswitch.reprs, id, repr) { - struct ice_vsi *vsi = repr->src_vsi; + /* Skip representors that aren't configured */ + if (!repr->dst) + return; - /* Skip representors that aren't configured */ - if (!repr->dst) - continue; + ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); + metadata_dst_free(repr->dst); + repr->dst = NULL; + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, + ICE_FWD_TO_VSI); - ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); - metadata_dst_free(repr->dst); - repr->dst = NULL; - ice_eswitch_del_sp_rule(pf, repr); - ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, - ICE_FWD_TO_VSI); - - netif_napi_del(&repr->q_vector->napi); - } + netif_napi_del(&repr->q_vector->napi); } /** - * ice_eswitch_setup_reprs - configure port reprs to run in switchdev mode + * ice_eswitch_setup_repr - configure PR to run in switchdev mode * @pf: pointer to PF struct + * @repr: pointer to PR struct */ -static int ice_eswitch_setup_reprs(struct ice_pf *pf) +static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - struct ice_repr *repr; - unsigned long id; + struct ice_vsi *vsi = repr->src_vsi; + struct metadata_dst *dst; - xa_for_each(&pf->eswitch.reprs, id, repr) { - struct ice_vsi *vsi = repr->src_vsi; + ice_remove_vsi_fltr(&pf->hw, vsi->idx); + repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, + GFP_KERNEL); + if (!repr->dst) + goto err_add_mac_fltr; - ice_remove_vsi_fltr(&pf->hw, vsi->idx); - repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, - GFP_KERNEL); - if (!repr->dst) { - ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, - ICE_FWD_TO_VSI); - goto err; - } + if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof)) + goto err_dst_free; - if (ice_eswitch_add_sp_rule(pf, repr)) { - ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, - ICE_FWD_TO_VSI); - goto err; - } + if (ice_vsi_add_vlan_zero(vsi)) + goto err_update_security; - if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof)) { - ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, - ICE_FWD_TO_VSI); - ice_eswitch_del_sp_rule(pf, repr); - metadata_dst_free(repr->dst); - repr->dst = NULL; - goto err; - } + netif_napi_add(repr->netdev, &repr->q_vector->napi, + ice_napi_poll); - if (ice_vsi_add_vlan_zero(vsi)) { - ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, - ICE_FWD_TO_VSI); - ice_eswitch_del_sp_rule(pf, repr); - metadata_dst_free(repr->dst); - repr->dst = NULL; - ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); - goto err; - } + netif_keep_dst(repr->netdev); - netif_napi_add(repr->netdev, &repr->q_vector->napi, - ice_napi_poll); - - netif_keep_dst(repr->netdev); - } - - xa_for_each(&pf->eswitch.reprs, id, repr) { - struct ice_vsi *vsi = repr->src_vsi; - struct metadata_dst *dst; - - dst = repr->dst; - dst->u.port_info.port_id = vsi->vsi_num; - dst->u.port_info.lower_dev = repr->netdev; - ice_repr_set_traffic_vsi(repr, ctrl_vsi); - } + dst = repr->dst; + dst->u.port_info.port_id = vsi->vsi_num; + dst->u.port_info.lower_dev = repr->netdev; + ice_repr_set_traffic_vsi(repr, ctrl_vsi); return 0; -err: - ice_eswitch_release_reprs(pf); +err_update_security: + ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); +err_dst_free: + metadata_dst_free(repr->dst); + repr->dst = NULL; +err_add_mac_fltr: + ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI); return -ENODEV; } @@ -481,31 +473,14 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) if (ice_eswitch_setup_env(pf)) goto err_vsi; - if (ice_repr_add_for_all_vfs(pf)) - goto err_repr_add; - - if (ice_eswitch_setup_reprs(pf)) - goto err_setup_reprs; - - ice_eswitch_remap_rings_to_vectors(pf); - - if (ice_vsi_open(ctrl_vsi)) - goto err_vsi_open; - if (ice_eswitch_br_offloads_init(pf)) goto err_br_offloads; - ice_eswitch_napi_enable(&pf->eswitch.reprs); + pf->eswitch.is_running = true; return 0; err_br_offloads: - ice_vsi_close(ctrl_vsi); -err_vsi_open: - ice_eswitch_release_reprs(pf); -err_setup_reprs: - ice_repr_rem_from_all_vfs(pf); -err_repr_add: ice_eswitch_release_env(pf); err_vsi: ice_vsi_release(ctrl_vsi); @@ -519,22 +494,12 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) static void ice_eswitch_disable_switchdev(struct ice_pf *pf) { struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - struct devlink *devlink = priv_to_devlink(pf); - ice_eswitch_napi_disable(&pf->eswitch.reprs); ice_eswitch_br_offloads_deinit(pf); ice_eswitch_release_env(pf); - ice_eswitch_release_reprs(pf); ice_vsi_release(ctrl_vsi); - ice_repr_rem_from_all_vfs(pf); - /* since all port representors are destroyed, there is - * no point in keeping the nodes - */ - ice_devlink_rate_clear_tx_topology(ice_get_main_vsi(pf)); - devl_lock(devlink); - devl_rate_nodes_destroy(devlink); - devl_unlock(devlink); + pf->eswitch.is_running = false; } /** @@ -613,39 +578,6 @@ bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf) return pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV; } -/** - * ice_eswitch_release - cleanup eswitch - * @pf: pointer to PF structure - */ -void ice_eswitch_release(struct ice_pf *pf) -{ - if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY) - return; - - ice_eswitch_disable_switchdev(pf); - pf->eswitch.is_running = false; -} - -/** - * ice_eswitch_configure - configure eswitch - * @pf: pointer to PF structure - */ -int ice_eswitch_configure(struct ice_pf *pf) -{ - int status; - - if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY || - pf->eswitch.is_running) - return 0; - - status = ice_eswitch_enable_switchdev(pf); - if (status) - return status; - - pf->eswitch.is_running = true; - return 0; -} - /** * ice_eswitch_start_all_tx_queues - start Tx queues of all port representors * @pf: pointer to PF structure @@ -678,6 +610,20 @@ void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) ice_repr_stop_tx_queues(repr); } +static void ice_eswitch_stop_reprs(struct ice_pf *pf) +{ + ice_eswitch_del_sp_rules(pf); + ice_eswitch_stop_all_tx_queues(pf); + ice_eswitch_napi_disable(&pf->eswitch.reprs); +} + +static void ice_eswitch_start_reprs(struct ice_pf *pf) +{ + ice_eswitch_napi_enable(&pf->eswitch.reprs); + ice_eswitch_start_all_tx_queues(pf); + ice_eswitch_add_sp_rules(pf); +} + /** * ice_eswitch_rebuild - rebuild eswitch * @pf: pointer to PF structure @@ -694,11 +640,7 @@ int ice_eswitch_rebuild(struct ice_pf *pf) if (status) return status; - status = ice_eswitch_setup_reprs(pf); - if (status) - return status; - - ice_eswitch_remap_rings_to_vectors(pf); + ice_eswitch_remap_rings_to_vectors(&pf->eswitch); ice_replay_tc_fltrs(pf); @@ -711,3 +653,102 @@ int ice_eswitch_rebuild(struct ice_pf *pf) return 0; } + +static void +ice_eswitch_cp_change_queues(struct ice_eswitch *eswitch, int change) +{ + struct ice_vsi *cp = eswitch->control_vsi; + + ice_vsi_close(cp); + + cp->req_txq = cp->alloc_txq + change; + cp->req_rxq = cp->alloc_rxq + change; + ice_vsi_rebuild(cp, ICE_VSI_FLAG_NO_INIT); + ice_eswitch_remap_rings_to_vectors(eswitch); + + ice_vsi_open(cp); +} + +int +ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf) +{ + struct ice_repr *repr; + int change = 1; + int err; + + if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY) + return 0; + + if (xa_empty(&pf->eswitch.reprs)) { + err = ice_eswitch_enable_switchdev(pf); + if (err) + return err; + /* Control plane VSI is created with 1 queue as default */ + change = 0; + } + + ice_eswitch_stop_reprs(pf); + + repr = ice_repr_add_vf(vf); + if (IS_ERR(repr)) + goto err_create_repr; + + err = ice_eswitch_setup_repr(pf, repr); + if (err) + goto err_setup_repr; + + err = xa_alloc(&pf->eswitch.reprs, &repr->id, repr, + XA_LIMIT(1, INT_MAX), GFP_KERNEL); + if (err) + goto err_xa_alloc; + + vf->repr_id = repr->id; + + ice_eswitch_cp_change_queues(&pf->eswitch, change); + ice_eswitch_start_reprs(pf); + + return 0; + +err_xa_alloc: + ice_eswitch_release_repr(pf, repr); +err_setup_repr: + ice_repr_rem_vf(repr); +err_create_repr: + if (xa_empty(&pf->eswitch.reprs)) + ice_eswitch_disable_switchdev(pf); + ice_eswitch_start_reprs(pf); + + return err; +} + +void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) +{ + struct ice_repr *repr = xa_load(&pf->eswitch.reprs, vf->repr_id); + struct devlink *devlink = priv_to_devlink(pf); + + if (!repr) + return; + + ice_eswitch_stop_reprs(pf); + xa_erase(&pf->eswitch.reprs, repr->id); + + if (xa_empty(&pf->eswitch.reprs)) + ice_eswitch_disable_switchdev(pf); + else + ice_eswitch_cp_change_queues(&pf->eswitch, -1); + + ice_eswitch_release_repr(pf, repr); + ice_repr_rem_vf(repr); + + if (xa_empty(&pf->eswitch.reprs)) { + /* since all port representors are destroyed, there is + * no point in keeping the nodes + */ + ice_devlink_rate_clear_tx_topology(ice_get_main_vsi(pf)); + devl_lock(devlink); + devl_rate_nodes_destroy(devlink); + devl_unlock(devlink); + } else { + ice_eswitch_start_reprs(pf); + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index ff110bd9fc4c..59d51c0d14e5 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -7,8 +7,9 @@ #include #ifdef CONFIG_ICE_SWITCHDEV -void ice_eswitch_release(struct ice_pf *pf); -int ice_eswitch_configure(struct ice_pf *pf); +void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf); +int +ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf); int ice_eswitch_rebuild(struct ice_pf *pf); int ice_eswitch_mode_get(struct devlink *devlink, u16 *mode); @@ -26,7 +27,13 @@ void ice_eswitch_set_target_vsi(struct sk_buff *skb, netdev_tx_t ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev); #else /* CONFIG_ICE_SWITCHDEV */ -static inline void ice_eswitch_release(struct ice_pf *pf) { } +static inline void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) { } + +static inline int +ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf) +{ + return -EOPNOTSUPP; +} static inline void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) { } diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index fa36cc932c5f..5f30fb131f74 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -287,44 +287,26 @@ static void ice_repr_remove_node(struct devlink_port *devlink_port) /** * ice_repr_rem - remove representor from VF - * @reprs: xarray storing representors * @repr: pointer to representor structure */ -static void ice_repr_rem(struct xarray *reprs, struct ice_repr *repr) +static void ice_repr_rem(struct ice_repr *repr) { - xa_erase(reprs, repr->id); kfree(repr->q_vector); free_netdev(repr->netdev); kfree(repr); } -static void ice_repr_rem_vf(struct ice_vf *vf) +/** + * ice_repr_rem_vf - remove representor from VF + * @repr: pointer to representor structure + */ +void ice_repr_rem_vf(struct ice_repr *repr) { - struct ice_repr *repr = xa_load(&vf->pf->eswitch.reprs, vf->repr_id); - - if (!repr) - return; - ice_repr_remove_node(&repr->vf->devlink_port); unregister_netdev(repr->netdev); - ice_repr_rem(&vf->pf->eswitch.reprs, repr); - ice_devlink_destroy_vf_port(vf); - ice_virtchnl_set_dflt_ops(vf); -} - -/** - * ice_repr_rem_from_all_vfs - remove port representor for all VFs - * @pf: pointer to PF structure - */ -void ice_repr_rem_from_all_vfs(struct ice_pf *pf) -{ - struct ice_vf *vf; - unsigned int bkt; - - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) - ice_repr_rem_vf(vf); + ice_devlink_destroy_vf_port(repr->vf); + ice_virtchnl_set_dflt_ops(repr->vf); + ice_repr_rem(repr); } static void ice_repr_set_tx_topology(struct ice_pf *pf) @@ -374,19 +356,12 @@ ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac) goto err_alloc_q_vector; } repr->q_vector = q_vector; - - err = xa_alloc(&pf->eswitch.reprs, &repr->id, repr, - XA_LIMIT(1, INT_MAX), GFP_KERNEL); - if (err) - goto err_xa_alloc; repr->q_id = repr->id; ether_addr_copy(repr->parent_mac, parent_mac); return repr; -err_xa_alloc: - kfree(repr->q_vector); err_alloc_q_vector: free_netdev(repr->netdev); err_alloc: @@ -394,7 +369,7 @@ ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac) return ERR_PTR(err); } -static struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) +struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) { struct ice_repr *repr; struct ice_vsi *vsi; @@ -414,7 +389,6 @@ static struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) goto err_repr_add; } - vf->repr_id = repr->id; repr->vf = vf; repr->netdev->min_mtu = ETH_MIN_MTU; @@ -432,49 +406,12 @@ static struct ice_repr *ice_repr_add_vf(struct ice_vf *vf) return repr; err_netdev: - ice_repr_rem(&vf->pf->eswitch.reprs, repr); + ice_repr_rem(repr); err_repr_add: ice_devlink_destroy_vf_port(vf); return ERR_PTR(err); } -/** - * ice_repr_add_for_all_vfs - add port representor for all VFs - * @pf: pointer to PF structure - */ -int ice_repr_add_for_all_vfs(struct ice_pf *pf) -{ - struct devlink *devlink; - struct ice_repr *repr; - struct ice_vf *vf; - unsigned int bkt; - int err; - - lockdep_assert_held(&pf->vfs.table_lock); - - ice_for_each_vf(pf, bkt, vf) { - repr = ice_repr_add_vf(vf); - if (IS_ERR(repr)) { - err = PTR_ERR(repr); - goto err; - } - } - - /* only export if ADQ and DCB disabled */ - if (ice_is_adq_active(pf) || ice_is_dcb_active(pf)) - return 0; - - devlink = priv_to_devlink(pf); - ice_devlink_rate_init_tx_topology(devlink, ice_get_main_vsi(pf)); - - return 0; - -err: - ice_repr_rem_from_all_vfs(pf); - - return err; -} - struct ice_repr *ice_repr_get_by_vsi(struct ice_vsi *vsi) { if (!vsi->vf) diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h index a3cd256d82b7..f9aede315716 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.h +++ b/drivers/net/ethernet/intel/ice/ice_repr.h @@ -22,8 +22,8 @@ struct ice_repr { #endif }; -int ice_repr_add_for_all_vfs(struct ice_pf *pf); -void ice_repr_rem_from_all_vfs(struct ice_pf *pf); +struct ice_repr *ice_repr_add_vf(struct ice_vf *vf); +void ice_repr_rem_vf(struct ice_repr *repr); void ice_repr_start_tx_queues(struct ice_repr *repr); void ice_repr_stop_tx_queues(struct ice_repr *repr); diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 2a5e6616cc0a..51f5f420d632 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -174,11 +174,10 @@ void ice_free_vfs(struct ice_pf *pf) mutex_lock(&vfs->table_lock); - ice_eswitch_release(pf); - ice_for_each_vf(pf, bkt, vf) { mutex_lock(&vf->cfg_lock); + ice_eswitch_detach(pf, vf); ice_dis_vf_qs(vf); if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { @@ -614,6 +613,14 @@ static int ice_start_vfs(struct ice_pf *pf) goto teardown; } + retval = ice_eswitch_attach(pf, vf); + if (retval) { + dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d", + vf->vf_id, retval); + ice_vf_vsi_release(vf); + goto teardown; + } + set_bit(ICE_VF_STATE_INIT, vf->vf_states); ice_ena_vf_mappings(vf); wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); @@ -932,12 +939,6 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs) clear_bit(ICE_VF_DIS, pf->state); - ret = ice_eswitch_configure(pf); - if (ret) { - dev_err(dev, "Failed to configure eswitch, err %d\n", ret); - goto err_unroll_sriov; - } - /* rearm global interrupts */ if (test_and_clear_bit(ICE_OICR_INTR_DIS, pf->state)) ice_irq_dynamic_ena(hw, NULL, NULL); From c9663f79cd82e64d5bcce3b3aafbcae15494a592 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:28 +0200 Subject: [PATCH 0459/7721] ice: adjust switchdev rebuild path There is no need to use specific functions for rebuilding path. Let's use current implementation by removing all representors and as the result remove switchdev environment. It will be added in devices rebuild path. For example during adding VFs, port representors for them also will be created. Rebuild control plane VSI before removing representors with INIT_VSI flag set to reinit VSI in hardware after reset. Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 66 +++++++------------- drivers/net/ethernet/intel/ice/ice_main.c | 4 +- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 +-- 3 files changed, 28 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index de5744aa5c2a..9ff4fe4fb133 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -406,19 +406,6 @@ ice_eswitch_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) return ice_vsi_setup(pf, ¶ms); } -/** - * ice_eswitch_napi_del - remove NAPI handle for all port representors - * @reprs: xarray of reprs - */ -static void ice_eswitch_napi_del(struct xarray *reprs) -{ - struct ice_repr *repr; - unsigned long id; - - xa_for_each(reprs, id, repr) - netif_napi_del(&repr->q_vector->napi); -} - /** * ice_eswitch_napi_enable - enable NAPI for all port representors * @reprs: xarray of reprs @@ -624,36 +611,6 @@ static void ice_eswitch_start_reprs(struct ice_pf *pf) ice_eswitch_add_sp_rules(pf); } -/** - * ice_eswitch_rebuild - rebuild eswitch - * @pf: pointer to PF structure - */ -int ice_eswitch_rebuild(struct ice_pf *pf) -{ - struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi; - int status; - - ice_eswitch_napi_disable(&pf->eswitch.reprs); - ice_eswitch_napi_del(&pf->eswitch.reprs); - - status = ice_eswitch_setup_env(pf); - if (status) - return status; - - ice_eswitch_remap_rings_to_vectors(&pf->eswitch); - - ice_replay_tc_fltrs(pf); - - status = ice_vsi_open(ctrl_vsi); - if (status) - return status; - - ice_eswitch_napi_enable(&pf->eswitch.reprs); - ice_eswitch_start_all_tx_queues(pf); - - return 0; -} - static void ice_eswitch_cp_change_queues(struct ice_eswitch *eswitch, int change) { @@ -752,3 +709,26 @@ void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) ice_eswitch_start_reprs(pf); } } + +/** + * ice_eswitch_rebuild - rebuild eswitch + * @pf: pointer to PF structure + */ +int ice_eswitch_rebuild(struct ice_pf *pf) +{ + struct ice_repr *repr; + unsigned long id; + int err; + + if (!ice_is_switchdev_running(pf)) + return 0; + + err = ice_vsi_rebuild(pf->eswitch.control_vsi, ICE_VSI_FLAG_INIT); + if (err) + return err; + + xa_for_each(&pf->eswitch.reprs, id, repr) + ice_eswitch_detach(pf, repr->vf); + + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 7ea6e2ad3272..10822011de22 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7412,9 +7412,9 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) ice_ptp_cfg_timestamp(pf, true); } - err = ice_vsi_rebuild_by_type(pf, ICE_VSI_SWITCHDEV_CTRL); + err = ice_eswitch_rebuild(pf); if (err) { - dev_err(dev, "Switchdev CTRL VSI rebuild failed: %d\n", err); + dev_err(dev, "Switchdev rebuild failed: %d\n", err); goto err_vsi_rebuild; } diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 68f9de0a7a8f..d2a99a20c4ad 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -760,6 +760,7 @@ void ice_reset_all_vfs(struct ice_pf *pf) ice_for_each_vf(pf, bkt, vf) { mutex_lock(&vf->cfg_lock); + ice_eswitch_detach(pf, vf); vf->driver_caps = 0; ice_vc_set_default_allowlist(vf); @@ -775,13 +776,11 @@ void ice_reset_all_vfs(struct ice_pf *pf) ice_vf_rebuild_vsi(vf); ice_vf_post_vsi_rebuild(vf); + ice_eswitch_attach(pf, vf); + mutex_unlock(&vf->cfg_lock); } - if (ice_is_eswitch_mode_switchdev(pf)) - if (ice_eswitch_rebuild(pf)) - dev_warn(dev, "eswitch rebuild failed\n"); - ice_flush(hw); clear_bit(ICE_VF_DIS, pf->state); From 19b39caec0622cc291d3ac42ec1fe4f9b6535739 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 24 Oct 2023 13:09:29 +0200 Subject: [PATCH 0460/7721] ice: reserve number of CP queues Rebuilding CP VSI each time the PR is created drastically increase the time of maximum VFs creation. Add function to reserve number of CP queues to deal with this problem. Use the same function to decrease number of queues in case of removing VFs. Assume that caller of ice_eswitch_reserve_cp_queues() will also call ice_eswitch_attach/detach() correct number of times. Still one by one PR adding is handy for VF resetting routine. Reviewed-by: Wojciech Drewek Signed-off-by: Michal Swiatkowski Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 6 +++ drivers/net/ethernet/intel/ice/ice_eswitch.c | 52 +++++++++++++++++--- drivers/net/ethernet/intel/ice/ice_eswitch.h | 4 ++ drivers/net/ethernet/intel/ice/ice_sriov.c | 3 ++ 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 597bdb6945c6..cd7dcd0fa7f2 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -528,6 +528,12 @@ struct ice_eswitch { struct ice_esw_br_offloads *br_offloads; struct xarray reprs; bool is_running; + /* struct to allow cp queues management optimization */ + struct { + int to_reach; + int value; + bool is_reaching; + } qs; }; struct ice_agg_node { diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 9ff4fe4fb133..3f80e2081e5d 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -176,7 +176,7 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_eswitch *eswitch) repr = xa_find(&eswitch->reprs, &repr_id, U32_MAX, XA_PRESENT); - if (WARN_ON(!repr)) + if (!repr) break; repr_id += 1; @@ -455,6 +455,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) return -ENODEV; ctrl_vsi = pf->eswitch.control_vsi; + /* cp VSI is createad with 1 queue as default */ + pf->eswitch.qs.value = 1; pf->eswitch.uplink_vsi = uplink_vsi; if (ice_eswitch_setup_env(pf)) @@ -487,6 +489,7 @@ static void ice_eswitch_disable_switchdev(struct ice_pf *pf) ice_vsi_release(ctrl_vsi); pf->eswitch.is_running = false; + pf->eswitch.qs.is_reaching = false; } /** @@ -615,15 +618,33 @@ static void ice_eswitch_cp_change_queues(struct ice_eswitch *eswitch, int change) { struct ice_vsi *cp = eswitch->control_vsi; + int queues = 0; - ice_vsi_close(cp); + if (eswitch->qs.is_reaching) { + if (eswitch->qs.to_reach >= eswitch->qs.value + change) { + queues = eswitch->qs.to_reach; + eswitch->qs.is_reaching = false; + } else { + queues = 0; + } + } else if ((change > 0 && cp->alloc_txq <= eswitch->qs.value) || + change < 0) { + queues = cp->alloc_txq + change; + } - cp->req_txq = cp->alloc_txq + change; - cp->req_rxq = cp->alloc_rxq + change; - ice_vsi_rebuild(cp, ICE_VSI_FLAG_NO_INIT); + if (queues) { + cp->req_txq = queues; + cp->req_rxq = queues; + ice_vsi_close(cp); + ice_vsi_rebuild(cp, ICE_VSI_FLAG_NO_INIT); + ice_vsi_open(cp); + } else if (!change) { + /* change == 0 means that VSI wasn't open, open it here */ + ice_vsi_open(cp); + } + + eswitch->qs.value += change; ice_eswitch_remap_rings_to_vectors(eswitch); - - ice_vsi_open(cp); } int @@ -641,6 +662,7 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf) if (err) return err; /* Control plane VSI is created with 1 queue as default */ + pf->eswitch.qs.to_reach -= 1; change = 0; } @@ -732,3 +754,19 @@ int ice_eswitch_rebuild(struct ice_pf *pf) return 0; } + +/** + * ice_eswitch_reserve_cp_queues - reserve control plane VSI queues + * @pf: pointer to PF structure + * @change: how many more (or less) queues is needed + * + * Remember to call ice_eswitch_attach/detach() the "change" times. + */ +void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change) +{ + if (pf->eswitch.qs.value + change < 0) + return; + + pf->eswitch.qs.to_reach = pf->eswitch.qs.value + change; + pf->eswitch.qs.is_reaching = true; +} diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index 59d51c0d14e5..1a288a03a79a 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -26,6 +26,7 @@ void ice_eswitch_set_target_vsi(struct sk_buff *skb, struct ice_tx_offload_params *off); netdev_tx_t ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev); +void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change); #else /* CONFIG_ICE_SWITCHDEV */ static inline void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) { } @@ -76,5 +77,8 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev) { return NETDEV_TX_BUSY; } + +static inline void +ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change) { } #endif /* CONFIG_ICE_SWITCHDEV */ #endif /* _ICE_ESWITCH_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 51f5f420d632..5a45bd5ce6ad 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -172,6 +172,8 @@ void ice_free_vfs(struct ice_pf *pf) else dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n"); + ice_eswitch_reserve_cp_queues(pf, -ice_get_num_vfs(pf)); + mutex_lock(&vfs->table_lock); ice_for_each_vf(pf, bkt, vf) { @@ -930,6 +932,7 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs) goto err_unroll_sriov; } + ice_eswitch_reserve_cp_queues(pf, num_vfs); ret = ice_start_vfs(pf); if (ret) { dev_err(dev, "Failed to start %d VFs, err %d\n", num_vfs, ret); From a1321811985bed1b110d224a6c7ce1b967ee7607 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Nov 2023 15:14:29 +0000 Subject: [PATCH 0461/7721] ASoC: cs42l43: Add missing static from runtime PM ops Fixes: 2b59332ead54 ("ASoC: cs42l43: Use new-style PM runtime macros") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311091824.5z6PROGZ-lkp@intel.com/ Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20231113151429.1554139-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index d62c9f26c632..5c98343ebf71 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2251,8 +2251,8 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL, - cs42l43_codec_runtime_resume, NULL); +static DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL, + cs42l43_codec_runtime_resume, NULL); static const struct platform_device_id cs42l43_codec_id_table[] = { { "cs42l43-codec", }, From a55ea47bb8743ee044550c5dfdd3cb3147602e05 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Mon, 13 Nov 2023 06:59:07 -0500 Subject: [PATCH 0462/7721] ASoC: Intel: sof_rt5682: add mtl_rt5650 support RT5650 is I2S codec integrated with HP and SPK. The HW board connects SoC I2S to RT5650 codec as below: I2S0: ALC5650 aif1 for Speaker I2S2: ALC5650 aif2 for Headphone Reviewed-by: Bard Liao Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231113115907.18539-1-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 9 +++++++++ sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 06ad15af46de..9723479f43da 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -1147,6 +1147,15 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(0) | SOF_RT5682_NUM_HDMIDEV(3)), }, + { + .name = "mtl_rt5650", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(2) | + SOF_RT5682_SSP_AMP(0) | + SOF_RT5682_NUM_HDMIDEV(3) | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 301b8142d554..af4224bff718 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -40,6 +40,11 @@ static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = { .codecs = {"INTC10B0"} }; +static const struct snd_soc_acpi_codecs mtl_rt5650_amp = { + .num_codecs = 1, + .codecs = {"10EC5650"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { { .comp_ids = &mtl_rt5682_rt5682s_hp, @@ -77,6 +82,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "10EC5650", + .drv_name = "mtl_rt5650", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mtl_rt5650_amp, + .sof_tplg_filename = "sof-mtl-rt5650.tplg", + }, /* place amp-only boards in the end of table */ { .id = "INTC10B0", From d3534684ada99ef8c0899eb28c62b4462483ee19 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 13 Nov 2023 18:03:42 +0530 Subject: [PATCH 0463/7721] ASoC: amd: acp: add Kconfig options for acp7.0 based platform driver ACP7.0 based platform legacy drivers can be built by selecting necessary kernel config option. This patch enables build support of the same. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20231113123345.2196504-1-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 12 ++++++++++++ sound/soc/amd/acp/Makefile | 2 ++ 2 files changed, 14 insertions(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 5fb322212938..c8ac0027f741 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -73,6 +73,18 @@ config SND_AMD_ASOC_ACP63 Say Y if you want to enable AUDIO on ACP6.3 If unsure select "N". +config SND_AMD_ASOC_ACP70 + tristate "AMD ACP ASOC Acp7.0 Support" + depends on X86 && PCI + depends on ACPI + select SND_SOC_AMD_ACP_PCM + select SND_SOC_AMD_ACP_I2S + select SND_SOC_AMD_ACP_PDM + help + This option enables Acp7.0 PDM support on AMD platform. + Say Y if you want to enable AUDIO on ACP7.0 + If unsure select "N". + config SND_SOC_AMD_MACH_COMMON tristate depends on X86 && PCI && I2C diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index dd85700f1c5f..ff5f7893b81e 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -15,6 +15,7 @@ snd-acp-pci-objs := acp-pci.o snd-acp-renoir-objs := acp-renoir.o snd-acp-rembrandt-objs := acp-rembrandt.o snd-acp63-objs := acp63.o +snd-acp70-objs := acp70.o #machine specific driver snd-acp-mach-objs := acp-mach-common.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o obj-$(CONFIG_SND_AMD_ASOC_ACP63) += snd-acp63.o +obj-$(CONFIG_SND_AMD_ASOC_ACP70) += snd-acp70.o obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o From fbe567785968d5ef65e64df879c64e545ea1c984 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 21 Sep 2023 18:40:48 -0700 Subject: [PATCH 0464/7721] igc: Simplify setting flags in the TX data descriptor We can re-use the IGC_SET_FLAG() macro to simplify setting some values in the TX data descriptor. With the macro it's easier to get the meaning of the operations. Signed-off-by: Vinicius Costa Gomes Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index e9bb403bbacf..7059710154eb 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1299,14 +1299,12 @@ static void igc_tx_olinfo_status(struct igc_ring *tx_ring, u32 olinfo_status = paylen << IGC_ADVTXD_PAYLEN_SHIFT; /* insert L4 checksum */ - olinfo_status |= (tx_flags & IGC_TX_FLAGS_CSUM) * - ((IGC_TXD_POPTS_TXSM << 8) / - IGC_TX_FLAGS_CSUM); + olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_CSUM, + (IGC_TXD_POPTS_TXSM << 8)); /* insert IPv4 checksum */ - olinfo_status |= (tx_flags & IGC_TX_FLAGS_IPV4) * - (((IGC_TXD_POPTS_IXSM << 8)) / - IGC_TX_FLAGS_IPV4); + olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_IPV4, + (IGC_TXD_POPTS_IXSM << 8)); tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); } From 069b142f58196bd9f47b35e493255741e2c663c7 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 21 Sep 2023 18:40:49 -0700 Subject: [PATCH 0465/7721] igc: Add support for PTP .getcyclesx64() Add support for using Timer 1 (i225/i226 have 4 timer registers) as a free-running clock (the "cycles" clock) in addition to Timer 0 (the default, "adjustable clock"). The objective is to allow taprio/etf offloading to coexist with PTP vclocks. Besides the implementation of .getcyclesx64() for i225/i226, to keep timestamping working when vclocks are in use, we also need to add support for TX and RX timestamping using the free running timer, when the requesting socket is bound to a vclock. On the RX side, i225/i226 can be configured to store the values of two timers in the received packet metadata area, so it's a matter of configuring the right registers and retrieving the right timestamp. The TX is a bit more involved because the hardware stores a single timestamp (with the selected timer in the TX descriptor) into one of the timestamp registers. Note some changes at how the timestamps are done for RX, the conversion and adjustment of timestamps are now done closer to the consumption of the timestamp instead of near the reception. Signed-off-by: Vinicius Costa Gomes Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc.h | 21 +++++++- drivers/net/ethernet/intel/igc/igc_base.h | 4 ++ drivers/net/ethernet/intel/igc/igc_defines.h | 2 + drivers/net/ethernet/intel/igc/igc_main.c | 55 ++++++++++++++------ drivers/net/ethernet/intel/igc/igc_ptp.c | 50 +++++++++++------- drivers/net/ethernet/intel/igc/igc_regs.h | 5 ++ 6 files changed, 101 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index f48f82d5e274..ac7c861e83a0 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -81,6 +81,21 @@ struct igc_tx_timestamp_request { u32 flags; /* flags that should be added to the tx_buffer */ }; +struct igc_inline_rx_tstamps { + /* Timestamps are saved in little endian at the beginning of the packet + * buffer following the layout: + * + * DWORD: | 0 | 1 | 2 | 3 | + * Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH | + * + * SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds + * part of the timestamp. + * + */ + __le32 timer1[2]; + __le32 timer0[2]; +}; + struct igc_ring_container { struct igc_ring *ring; /* pointer to linked list of rings */ unsigned int total_bytes; /* total bytes processed this int */ @@ -261,6 +276,8 @@ struct igc_adapter { unsigned int ptp_flags; /* System time value lock */ spinlock_t tmreg_lock; + /* Free-running timer lock */ + spinlock_t free_timer_lock; struct cyclecounter cc; struct timecounter tc; struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */ @@ -469,6 +486,8 @@ enum igc_tx_flags { IGC_TX_FLAGS_TSTAMP_1 = 0x100, IGC_TX_FLAGS_TSTAMP_2 = 0x200, IGC_TX_FLAGS_TSTAMP_3 = 0x400, + + IGC_TX_FLAGS_TSTAMP_TIMER_1 = 0x800, }; enum igc_boards { @@ -531,7 +550,7 @@ struct igc_rx_buffer { struct igc_xdp_buff { struct xdp_buff xdp; union igc_adv_rx_desc *rx_desc; - ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */ + struct igc_inline_rx_tstamps *rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */ }; struct igc_q_vector { diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index f7d6491d4c60..bf8cdfbba9ff 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -37,6 +37,10 @@ struct igc_adv_tx_context_desc { #define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */ #define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */ #define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */ +#define IGC_ADVTXD_TSTAMP_TIMER_1 0x00010000 /* Select timer 1 for timestamp */ +#define IGC_ADVTXD_TSTAMP_TIMER_2 0x00020000 /* Select timer 2 for timestamp */ +#define IGC_ADVTXD_TSTAMP_TIMER_3 0x00030000 /* Select timer 3 for timestamp */ + #define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */ #define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ #define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */ diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index b3037016f31d..5f92b3c7c3d4 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -317,6 +317,8 @@ #define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ #define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ +#define IGC_TXD_PTP2_TIMER_1 0x00000020 + /* IPSec Encrypt Enable */ #define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ #define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 7059710154eb..61db1d3bfa0b 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1306,6 +1306,10 @@ static void igc_tx_olinfo_status(struct igc_ring *tx_ring, olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_IPV4, (IGC_TXD_POPTS_IXSM << 8)); + /* Use the second timer (free running, in general) for the timestamp */ + olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_TIMER_1, + IGC_TXD_PTP2_TIMER_1); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); } @@ -1649,6 +1653,8 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb, if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags; + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_USE_CYCLES) + tx_flags |= IGC_TX_FLAGS_TSTAMP_TIMER_1; } else { adapter->tx_hwtstamp_skipped++; } @@ -1961,9 +1967,9 @@ static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring, static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring, struct igc_rx_buffer *rx_buffer, - struct xdp_buff *xdp, - ktime_t timestamp) + struct igc_xdp_buff *ctx) { + struct xdp_buff *xdp = &ctx->xdp; unsigned int metasize = xdp->data - xdp->data_meta; unsigned int size = xdp->data_end - xdp->data; unsigned int truesize = igc_get_rx_frame_truesize(rx_ring, size); @@ -1980,8 +1986,10 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring, if (unlikely(!skb)) return NULL; - if (timestamp) - skb_hwtstamps(skb)->hwtstamp = timestamp; + if (ctx->rx_ts) { + skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV; + skb_hwtstamps(skb)->netdev_data = ctx->rx_ts; + } /* Determine available headroom for copy */ headlen = size; @@ -2581,11 +2589,10 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) int xdp_status = 0, rx_buffer_pgcnt; while (likely(total_packets < budget)) { - union igc_adv_rx_desc *rx_desc; + struct igc_xdp_buff ctx = { .rx_ts = NULL }; struct igc_rx_buffer *rx_buffer; + union igc_adv_rx_desc *rx_desc; unsigned int size, truesize; - struct igc_xdp_buff ctx; - ktime_t timestamp = 0; int pkt_offset = 0; void *pktbuf; @@ -2612,9 +2619,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) pktbuf = page_address(rx_buffer->page) + rx_buffer->page_offset; if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) { - timestamp = igc_ptp_rx_pktstamp(q_vector->adapter, - pktbuf); - ctx.rx_ts = timestamp; + ctx.rx_ts = pktbuf; pkt_offset = IGC_TS_HDR_LEN; size -= IGC_TS_HDR_LEN; } @@ -2651,8 +2656,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) else if (ring_uses_build_skb(rx_ring)) skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp); else - skb = igc_construct_skb(rx_ring, rx_buffer, &ctx.xdp, - timestamp); + skb = igc_construct_skb(rx_ring, rx_buffer, &ctx); /* exit if we failed to retrieve a buffer */ if (!skb) { @@ -2801,9 +2805,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget) ctx->rx_desc = desc; if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) { - timestamp = igc_ptp_rx_pktstamp(q_vector->adapter, - bi->xdp->data); - ctx->rx_ts = timestamp; + ctx->rx_ts = bi->xdp->data; bi->xdp->data += IGC_TS_HDR_LEN; @@ -6560,6 +6562,24 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags) return 0; } +static ktime_t igc_get_tstamp(struct net_device *dev, + const struct skb_shared_hwtstamps *hwtstamps, + bool cycles) +{ + struct igc_adapter *adapter = netdev_priv(dev); + struct igc_inline_rx_tstamps *tstamp; + ktime_t timestamp; + + tstamp = hwtstamps->netdev_data; + + if (cycles) + timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer1); + else + timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0); + + return timestamp; +} + static const struct net_device_ops igc_netdev_ops = { .ndo_open = igc_open, .ndo_stop = igc_close, @@ -6577,6 +6597,7 @@ static const struct net_device_ops igc_netdev_ops = { .ndo_bpf = igc_bpf, .ndo_xdp_xmit = igc_xdp_xmit, .ndo_xsk_wakeup = igc_xsk_wakeup, + .ndo_get_tstamp = igc_get_tstamp, }; /* PCIe configuration access */ @@ -6680,9 +6701,11 @@ static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, static int igc_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp) { const struct igc_xdp_buff *ctx = (void *)_ctx; + struct igc_adapter *adapter = netdev_priv(ctx->xdp.rxq->dev); + struct igc_inline_rx_tstamps *tstamp = ctx->rx_ts; if (igc_test_staterr(ctx->rx_desc, IGC_RXDADV_STAT_TSIP)) { - *timestamp = ctx->rx_ts; + *timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0); return 0; } diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 928f38792203..885faaa7b9de 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -459,12 +459,10 @@ static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, /** * igc_ptp_rx_pktstamp - Retrieve timestamp from Rx packet buffer * @adapter: Pointer to adapter the packet buffer belongs to - * @buf: Pointer to packet buffer + * @buf: Pointer to start of timestamp in HW format (2 32-bit words) * - * This function retrieves the timestamp saved in the beginning of packet - * buffer. While two timestamps are available, one in timer0 reference and the - * other in timer1 reference, this function considers only the timestamp in - * timer0 reference. + * This function retrieves and converts the timestamp stored at @buf + * to ktime_t, adjusting for hardware latencies. * * Returns timestamp value. */ @@ -474,17 +472,8 @@ ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf) u32 secs, nsecs; int adjust; - /* Timestamps are saved in little endian at the beginning of the packet - * buffer following the layout: - * - * DWORD: | 0 | 1 | 2 | 3 | - * Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH | - * - * SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds - * part of the timestamp. - */ - nsecs = le32_to_cpu(buf[2]); - secs = le32_to_cpu(buf[3]); + nsecs = le32_to_cpu(buf[0]); + secs = le32_to_cpu(buf[1]); timestamp = ktime_set(secs, nsecs); @@ -542,10 +531,11 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { val = rd32(IGC_SRRCTL(i)); - /* FIXME: For now, only support retrieving RX timestamps from - * timer 0. + /* Enable retrieving timestamps from timer 0, the + * "adjustable clock" and timer 1 the "free running + * clock". */ - val |= IGC_SRRCTL_TIMER1SEL(0) | IGC_SRRCTL_TIMER0SEL(0) | + val |= IGC_SRRCTL_TIMER1SEL(1) | IGC_SRRCTL_TIMER0SEL(0) | IGC_SRRCTL_TIMESTAMP; wr32(IGC_SRRCTL(i), val); } @@ -1035,6 +1025,26 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp, adapter, &adapter->snapshot, cts); } +static int igc_ptp_getcyclesx64(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct igc_adapter *igc = container_of(ptp, struct igc_adapter, ptp_caps); + struct igc_hw *hw = &igc->hw; + unsigned long flags; + + spin_lock_irqsave(&igc->free_timer_lock, flags); + + ptp_read_system_prets(sts); + ts->tv_nsec = rd32(IGC_SYSTIML_1); + ts->tv_sec = rd32(IGC_SYSTIMH_1); + ptp_read_system_postts(sts); + + spin_unlock_irqrestore(&igc->free_timer_lock, flags); + + return 0; +} + /** * igc_ptp_init - Initialize PTP functionality * @adapter: Board private structure @@ -1088,6 +1098,7 @@ void igc_ptp_init(struct igc_adapter *adapter) adapter->ptp_caps.adjfine = igc_ptp_adjfine_i225; adapter->ptp_caps.adjtime = igc_ptp_adjtime_i225; adapter->ptp_caps.gettimex64 = igc_ptp_gettimex64_i225; + adapter->ptp_caps.getcyclesx64 = igc_ptp_getcyclesx64; adapter->ptp_caps.settime64 = igc_ptp_settime_i225; adapter->ptp_caps.enable = igc_ptp_feature_enable_i225; adapter->ptp_caps.pps = 1; @@ -1108,6 +1119,7 @@ void igc_ptp_init(struct igc_adapter *adapter) } spin_lock_init(&adapter->ptp_tx_lock); + spin_lock_init(&adapter->free_timer_lock); spin_lock_init(&adapter->tmreg_lock); adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index 20e17f5fbce3..d38c87d7e5e8 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -243,6 +243,11 @@ #define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */ #define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */ +#define IGC_SYSTIML_1 0x0B688 /* System time register Low - RO (timer 1) */ +#define IGC_SYSTIMH_1 0x0B68C /* System time register High - RO (timer 1) */ +#define IGC_SYSTIMR_1 0x0B684 /* System time register Residue (timer 1) */ +#define IGC_TIMINCA_1 0x0B690 /* Increment attributes register - RW (timer 1) */ + /* TX Timestamp Low */ #define IGC_TXSTMPL_0 0x0B618 #define IGC_TXSTMPL_1 0x0B698 From b0e396d68fef9c9c050dfbb590cc0066441f65c7 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Fri, 10 Nov 2023 20:01:57 -0500 Subject: [PATCH 0466/7721] Revert "drm/sched: Define pr_fmt() for DRM using pr_*()" From Jani: The drm_print.[ch] facilities use very few pr_*() calls directly. The users of pr_*() calls do not necessarily include at all, and really don't have to. Even the ones that do include it, usually have includes first, and includes next. Notably, includes . And, of course, defines pr_fmt() itself if not already defined. No, it's encouraged not to use pr_*() at all, and prefer drm device based logging, or device based logging. This reverts commit 36245bd02e88e68ac5955c2958c968879d7b75a9. Signed-off-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/878r75wzm9.fsf@intel.com Acked-by: Javier Martinez Canillas Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231111024130.11464-2-ltuikov89@gmail.com --- include/drm/drm_print.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index e8fe60d0eb87..a93a387f8a1a 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -26,20 +26,6 @@ #ifndef DRM_PRINT_H_ #define DRM_PRINT_H_ -/* Define this before including linux/printk.h, so that the format - * string in pr_*() macros is correctly set for DRM. If a file wants - * to define this to something else, it should do so before including - * this header file. - * - * It is encouraged code using pr_err() to prefix their format with - * the string "*ERROR* ", to make it easier to scan kernel logs. For - * instance, - * pr_err("*ERROR* ", args). - */ -#ifndef pr_fmt -#define pr_fmt(fmt) "[drm] " fmt -#endif - #include #include #include From 727a92d62fd6a382b4c5972008e45667e707b0e4 Mon Sep 17 00:00:00 2001 From: Jordan Rome Date: Sat, 11 Nov 2023 18:30:10 -0800 Subject: [PATCH 0467/7721] selftests/bpf: Add assert for user stacks in test_task_stack This is a follow up to: commit b8e3a87a627b ("bpf: Add crosstask check to __bpf_get_stack"). This test ensures that the task iterator only gets a single user stack (for the current task). Signed-off-by: Jordan Rome Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20231112023010.144675-1-linux@jordanrome.com --- tools/testing/selftests/bpf/prog_tests/bpf_iter.c | 2 ++ tools/testing/selftests/bpf/progs/bpf_iter_task_stack.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c index 4e02093c2cbe..618af9dfae9b 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -332,6 +332,8 @@ static void test_task_stack(void) do_dummy_read(skel->progs.dump_task_stack); do_dummy_read(skel->progs.get_task_user_stacks); + ASSERT_EQ(skel->bss->num_user_stacks, 1, "num_user_stacks"); + bpf_iter_task_stack__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_task_stack.c b/tools/testing/selftests/bpf/progs/bpf_iter_task_stack.c index f2b8167b72a8..442f4ca39fd7 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_task_stack.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_task_stack.c @@ -35,6 +35,8 @@ int dump_task_stack(struct bpf_iter__task *ctx) return 0; } +int num_user_stacks = 0; + SEC("iter/task") int get_task_user_stacks(struct bpf_iter__task *ctx) { @@ -51,6 +53,9 @@ int get_task_user_stacks(struct bpf_iter__task *ctx) if (res <= 0) return 0; + /* Only one task, the current one, should succeed */ + ++num_user_stacks; + buf_sz += res; /* If the verifier doesn't refine bpf_get_task_stack res, and instead From e4679a1b8a73584c5774af0fe19bcece94245487 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sun, 24 Sep 2023 10:04:01 +0200 Subject: [PATCH 0468/7721] batman-adv: Start new development cycle This version will contain all the (major or even only minor) changes for Linux 6.8. The version number isn't a semantic version number with major and minor information. It is just encoding the year of the expected publishing as Linux -rc1 and the number of published versions this year (starting at 0). Signed-off-by: Simon Wunderlich --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 10007c5894a1..870dcd7f1786 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -13,7 +13,7 @@ #define BATADV_DRIVER_DEVICE "batman-adv" #ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2023.3" +#define BATADV_SOURCE_VERSION "2024.0" #endif /* B.A.T.M.A.N. parameters */ From 07afe1ba288c04280622fa002ed385f1ac0b6fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 7 Sep 2023 03:09:08 +0200 Subject: [PATCH 0469/7721] batman-adv: mcast: implement multicast packet reception and forwarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement functionality to receive and forward a new TVLV capable multicast packet type. The new batman-adv multicast packet type allows to contain several originator destination addresses within a TVLV. Routers on the way will potentially split the batman-adv multicast packet and adjust its tracker TVLV contents. Routing decisions are still based on the selected BATMAN IV or BATMAN V routing algorithm. So this new batman-adv multicast packet type retains the same loop-free properties. Also a new OGM multicast TVLV flag is introduced to signal to other nodes that we are capable of handling a batman-adv multicast packet and multicast tracker TVLV. And that all of our hard interfaces have an MTU of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now to avoid MTU issues while forwarding. Signed-off-by: Linus Lüssing Signed-off-by: Simon Wunderlich --- include/uapi/linux/batadv_packet.h | 45 +++++- net/batman-adv/Makefile | 1 + net/batman-adv/fragmentation.c | 8 +- net/batman-adv/main.c | 2 + net/batman-adv/multicast.c | 48 +++++- net/batman-adv/multicast.h | 5 + net/batman-adv/multicast_forw.c | 239 +++++++++++++++++++++++++++++ net/batman-adv/originator.c | 28 ++++ net/batman-adv/originator.h | 3 + net/batman-adv/routing.c | 70 +++++++++ net/batman-adv/routing.h | 11 ++ net/batman-adv/soft-interface.c | 12 ++ net/batman-adv/types.h | 64 ++++++++ 13 files changed, 518 insertions(+), 18 deletions(-) create mode 100644 net/batman-adv/multicast_forw.c diff --git a/include/uapi/linux/batadv_packet.h b/include/uapi/linux/batadv_packet.h index 9204e4494b25..6e25753015df 100644 --- a/include/uapi/linux/batadv_packet.h +++ b/include/uapi/linux/batadv_packet.h @@ -116,6 +116,9 @@ enum batadv_icmp_packettype { * only need routable IPv4 multicast packets we signed up for explicitly * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore * only need routable IPv6 multicast packets we signed up for explicitly + * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward + * batman-adv multicast packets with a multicast tracker TVLV. And all our + * hard interfaces have an MTU of at least 1280 bytes. */ enum batadv_mcast_flags { BATADV_MCAST_WANT_ALL_UNSNOOPABLES = 1UL << 0, @@ -123,6 +126,7 @@ enum batadv_mcast_flags { BATADV_MCAST_WANT_ALL_IPV6 = 1UL << 2, BATADV_MCAST_WANT_NO_RTR4 = 1UL << 3, BATADV_MCAST_WANT_NO_RTR6 = 1UL << 4, + BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5, }; /* tt data subtypes */ @@ -174,14 +178,16 @@ enum batadv_bla_claimframe { * @BATADV_TVLV_TT: translation table tvlv * @BATADV_TVLV_ROAM: roaming advertisement tvlv * @BATADV_TVLV_MCAST: multicast capability tvlv + * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv */ enum batadv_tvlv_type { - BATADV_TVLV_GW = 0x01, - BATADV_TVLV_DAT = 0x02, - BATADV_TVLV_NC = 0x03, - BATADV_TVLV_TT = 0x04, - BATADV_TVLV_ROAM = 0x05, - BATADV_TVLV_MCAST = 0x06, + BATADV_TVLV_GW = 0x01, + BATADV_TVLV_DAT = 0x02, + BATADV_TVLV_NC = 0x03, + BATADV_TVLV_TT = 0x04, + BATADV_TVLV_ROAM = 0x05, + BATADV_TVLV_MCAST = 0x06, + BATADV_TVLV_MCAST_TRACKER = 0x07, }; #pragma pack(2) @@ -487,6 +493,25 @@ struct batadv_bcast_packet { */ }; +/** + * struct batadv_mcast_packet - multicast packet for network payload + * @packet_type: batman-adv packet type, part of the general header + * @version: batman-adv protocol version, part of the general header + * @ttl: time to live for this packet, part of the general header + * @reserved: reserved byte for alignment + * @tvlv_len: length of the appended tvlv buffer (in bytes) + */ +struct batadv_mcast_packet { + __u8 packet_type; + __u8 version; + __u8 ttl; + __u8 reserved; + __be16 tvlv_len; + /* "4 bytes boundary + 2 bytes" long to make the payload after the + * following ethernet header again 4 bytes boundary aligned + */ +}; + /** * struct batadv_coded_packet - network coded packet * @packet_type: batman-adv packet type, part of the general header @@ -628,6 +653,14 @@ struct batadv_tvlv_mcast_data { __u8 reserved[3]; }; +/** + * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv + * @num_dests: number of subsequent destination originator MAC addresses + */ +struct batadv_tvlv_mcast_tracker { + __be16 num_dests; +}; + #pragma pack() #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */ diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index 3bd0760c76a2..b51d8b071b56 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -20,6 +20,7 @@ batman-adv-y += hash.o batman-adv-$(CONFIG_BATMAN_ADV_DEBUG) += log.o batman-adv-y += main.o batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o +batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast_forw.o batman-adv-y += netlink.o batman-adv-$(CONFIG_BATMAN_ADV_NC) += network-coding.o batman-adv-y += originator.o diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index c120c7c6d25f..757c084ac2d1 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -25,7 +25,6 @@ #include "hard-interface.h" #include "originator.h" -#include "routing.h" #include "send.h" /** @@ -351,18 +350,14 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, struct batadv_orig_node *orig_node_src) { struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct batadv_orig_node *orig_node_dst; struct batadv_neigh_node *neigh_node = NULL; struct batadv_frag_packet *packet; u16 total_size; bool ret = false; packet = (struct batadv_frag_packet *)skb->data; - orig_node_dst = batadv_orig_hash_find(bat_priv, packet->dest); - if (!orig_node_dst) - goto out; - neigh_node = batadv_find_router(bat_priv, orig_node_dst, recv_if); + neigh_node = batadv_orig_to_router(bat_priv, packet->dest, recv_if); if (!neigh_node) goto out; @@ -381,7 +376,6 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, } out: - batadv_orig_node_put(orig_node_dst); batadv_neigh_node_put(neigh_node); return ret; } diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index e8a449915566..50b2bf2b748c 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -532,6 +532,8 @@ static void batadv_recv_handler_init(void) /* broadcast packet */ batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; + /* multicast packet */ + batadv_rx_handler[BATADV_MCAST] = batadv_recv_mcast_packet; /* unicast packets ... */ /* unicast with 4 addresses packet */ diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 315394f12c55..dfc2c645b13f 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -235,6 +235,37 @@ static u8 batadv_mcast_mla_rtr_flags_get(struct batadv_priv *bat_priv, return flags; } +/** + * batadv_mcast_mla_forw_flags_get() - get multicast forwarding flags + * @bat_priv: the bat priv with all the soft interface information + * + * Checks if all active hard interfaces have an MTU larger or equal to 1280 + * bytes (IPv6 minimum MTU). + * + * Return: BATADV_MCAST_HAVE_MC_PTYPE_CAPA if yes, BATADV_NO_FLAGS otherwise. + */ +static u8 batadv_mcast_mla_forw_flags_get(struct batadv_priv *bat_priv) +{ + const struct batadv_hard_iface *hard_iface; + + rcu_read_lock(); + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->if_status != BATADV_IF_ACTIVE) + continue; + + if (hard_iface->soft_iface != bat_priv->soft_iface) + continue; + + if (hard_iface->net_dev->mtu < IPV6_MIN_MTU) { + rcu_read_unlock(); + return BATADV_NO_FLAGS; + } + } + rcu_read_unlock(); + + return BATADV_MCAST_HAVE_MC_PTYPE_CAPA; +} + /** * batadv_mcast_mla_flags_get() - get the new multicast flags * @bat_priv: the bat priv with all the soft interface information @@ -256,6 +287,7 @@ batadv_mcast_mla_flags_get(struct batadv_priv *bat_priv) mla_flags.enabled = 1; mla_flags.tvlv_flags |= batadv_mcast_mla_rtr_flags_get(bat_priv, bridge); + mla_flags.tvlv_flags |= batadv_mcast_mla_forw_flags_get(bat_priv); if (!bridge) return mla_flags; @@ -806,23 +838,25 @@ static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags) { bool old_enabled = bat_priv->mcast.mla_flags.enabled; u8 old_flags = bat_priv->mcast.mla_flags.tvlv_flags; - char str_old_flags[] = "[.... . ]"; + char str_old_flags[] = "[.... . .]"; - sprintf(str_old_flags, "[%c%c%c%s%s]", + sprintf(str_old_flags, "[%c%c%c%s%s%c]", (old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', (old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', (old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.', !(old_flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ", - !(old_flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". "); + !(old_flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ", + !(old_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA) ? 'P' : '.'); batadv_dbg(BATADV_DBG_MCAST, bat_priv, - "Changing multicast flags from '%s' to '[%c%c%c%s%s]'\n", + "Changing multicast flags from '%s' to '[%c%c%c%s%s%c]'\n", old_enabled ? str_old_flags : "", (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.', !(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ", - !(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". "); + !(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ", + !(flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA) ? 'P' : '.'); } /** @@ -1820,6 +1854,10 @@ void batadv_mcast_init(struct batadv_priv *bat_priv) batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler, NULL, NULL, BATADV_TVLV_MCAST, 2, BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + batadv_tvlv_handler_register(bat_priv, NULL, NULL, + batadv_mcast_forw_tracker_tvlv_handler, + BATADV_TVLV_MCAST_TRACKER, 1, + BATADV_TVLV_HANDLER_OGM_CIFNOTFND); INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update); batadv_mcast_start_timer(bat_priv); diff --git a/net/batman-adv/multicast.h b/net/batman-adv/multicast.h index a9770d8d6d36..a5c0f384bb9a 100644 --- a/net/batman-adv/multicast.h +++ b/net/batman-adv/multicast.h @@ -52,6 +52,11 @@ void batadv_mcast_free(struct batadv_priv *bat_priv); void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node); +/* multicast_forw.c */ + +int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv, + struct sk_buff *skb); + #else static inline enum batadv_forw_mode diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c new file mode 100644 index 000000000000..d17341dfb832 --- /dev/null +++ b/net/batman-adv/multicast_forw.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) B.A.T.M.A.N. contributors: + * + * Linus Lüssing + */ + +#include "multicast.h" +#include "main.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "originator.h" +#include "send.h" + +#define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \ + for (; num_dests; num_dests--, (dest) += ETH_ALEN) + +#define batadv_mcast_forw_tracker_for_each_dest2(dest1, dest2, num_dests) \ + for (; num_dests; num_dests--, (dest1) += ETH_ALEN, (dest2) += ETH_ALEN) + +/** + * batadv_mcast_forw_scrub_dests() - scrub destinations in a tracker TVLV + * @bat_priv: the bat priv with all the soft interface information + * @comp_neigh: next hop neighbor to scrub+collect destinations for + * @dest: start MAC entry in original skb's tracker TVLV + * @next_dest: start MAC entry in to be sent skb's tracker TVLV + * @num_dests: number of remaining destination MAC entries to iterate over + * + * This sorts destination entries into either the original batman-adv + * multicast packet or the skb (copy) that is going to be sent to comp_neigh + * next. + * + * In preparation for the next, to be (unicast) transmitted batman-adv multicast + * packet skb to be sent to the given neighbor node, tries to collect all + * originator MAC addresses that have the given neighbor node as their next hop + * in the to be transmitted skb (copy), which next_dest points into. That is we + * zero all destination entries in next_dest which do not have comp_neigh as + * their next hop. And zero all destination entries in the original skb that + * would have comp_neigh as their next hop (to avoid redundant transmissions and + * duplicated payload later). + */ +static void +batadv_mcast_forw_scrub_dests(struct batadv_priv *bat_priv, + struct batadv_neigh_node *comp_neigh, u8 *dest, + u8 *next_dest, u16 num_dests) +{ + struct batadv_neigh_node *next_neigh; + + /* skip first entry, this is what we are comparing with */ + eth_zero_addr(dest); + dest += ETH_ALEN; + next_dest += ETH_ALEN; + num_dests--; + + batadv_mcast_forw_tracker_for_each_dest2(dest, next_dest, num_dests) { + if (is_zero_ether_addr(next_dest)) + continue; + + /* sanity check, we expect unicast destinations */ + if (is_multicast_ether_addr(next_dest)) { + eth_zero_addr(dest); + eth_zero_addr(next_dest); + continue; + } + + next_neigh = batadv_orig_to_router(bat_priv, next_dest, NULL); + if (!next_neigh) { + eth_zero_addr(next_dest); + continue; + } + + if (!batadv_compare_eth(next_neigh->addr, comp_neigh->addr)) { + eth_zero_addr(next_dest); + batadv_neigh_node_put(next_neigh); + continue; + } + + /* found an entry for our next packet to transmit, so remove it + * from the original packet + */ + eth_zero_addr(dest); + batadv_neigh_node_put(next_neigh); + } +} + +/** + * batadv_mcast_forw_packet() - forward a batman-adv multicast packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: the received or locally generated batman-adv multicast packet + * @local_xmit: indicates that the packet was locally generated and not received + * + * Parses the tracker TVLV of a batman-adv multicast packet and forwards the + * packet as indicated in this TVLV. + * + * Caller needs to set the skb network header to the start of the multicast + * tracker TVLV (excluding the generic TVLV header) and the skb transport header + * to the next byte after this multicast tracker TVLV. + * + * Caller needs to free the skb. + * + * Return: NET_RX_SUCCESS or NET_RX_DROP on success or a negative error + * code on failure. NET_RX_SUCCESS if the received packet is supposed to be + * decapsulated and forwarded to the own soft interface, NET_RX_DROP otherwise. + */ +static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv, + struct sk_buff *skb, bool local_xmit) +{ + struct batadv_tvlv_mcast_tracker *mcast_tracker; + struct batadv_neigh_node *neigh_node; + unsigned long offset, num_dests_off; + struct sk_buff *nexthop_skb; + unsigned char *skb_net_hdr; + bool local_recv = false; + unsigned int tvlv_len; + bool xmitted = false; + u8 *dest, *next_dest; + u16 num_dests; + int ret; + + /* (at least) TVLV part needs to be linearized */ + SKB_LINEAR_ASSERT(skb); + + /* check if num_dests is within skb length */ + num_dests_off = offsetof(struct batadv_tvlv_mcast_tracker, num_dests); + if (num_dests_off > skb_network_header_len(skb)) + return -EINVAL; + + skb_net_hdr = skb_network_header(skb); + mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr; + num_dests = ntohs(mcast_tracker->num_dests); + + dest = (u8 *)mcast_tracker + sizeof(*mcast_tracker); + + /* check if full tracker tvlv is within skb length */ + tvlv_len = sizeof(*mcast_tracker) + ETH_ALEN * num_dests; + if (tvlv_len > skb_network_header_len(skb)) + return -EINVAL; + + /* invalidate checksum: */ + skb->ip_summed = CHECKSUM_NONE; + + batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) { + if (is_zero_ether_addr(dest)) + continue; + + /* only unicast originator addresses supported */ + if (is_multicast_ether_addr(dest)) { + eth_zero_addr(dest); + continue; + } + + if (batadv_is_my_mac(bat_priv, dest)) { + eth_zero_addr(dest); + local_recv = true; + continue; + } + + neigh_node = batadv_orig_to_router(bat_priv, dest, NULL); + if (!neigh_node) { + eth_zero_addr(dest); + continue; + } + + nexthop_skb = skb_copy(skb, GFP_ATOMIC); + if (!nexthop_skb) { + batadv_neigh_node_put(neigh_node); + return -ENOMEM; + } + + offset = dest - skb->data; + next_dest = nexthop_skb->data + offset; + + batadv_mcast_forw_scrub_dests(bat_priv, neigh_node, dest, + next_dest, num_dests); + + batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_TX); + batadv_add_counter(bat_priv, BATADV_CNT_MCAST_TX_BYTES, + nexthop_skb->len + ETH_HLEN); + xmitted = true; + ret = batadv_send_unicast_skb(nexthop_skb, neigh_node); + + batadv_neigh_node_put(neigh_node); + + if (ret < 0) + return ret; + } + + if (xmitted) { + if (local_xmit) { + batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_TX_LOCAL); + batadv_add_counter(bat_priv, + BATADV_CNT_MCAST_TX_LOCAL_BYTES, + skb->len - + skb_transport_offset(skb)); + } else { + batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_FWD); + batadv_add_counter(bat_priv, BATADV_CNT_MCAST_FWD_BYTES, + skb->len + ETH_HLEN); + } + } + + if (local_recv) + return NET_RX_SUCCESS; + else + return NET_RX_DROP; +} + +/** + * batadv_mcast_forw_tracker_tvlv_handler() - handle an mcast tracker tvlv + * @bat_priv: the bat priv with all the soft interface information + * @skb: the received batman-adv multicast packet + * + * Parses the tracker TVLV of an incoming batman-adv multicast packet and + * forwards the packet as indicated in this TVLV. + * + * Caller needs to set the skb network header to the start of the multicast + * tracker TVLV (excluding the generic TVLV header) and the skb transport header + * to the next byte after this multicast tracker TVLV. + * + * Caller needs to free the skb. + * + * Return: NET_RX_SUCCESS or NET_RX_DROP on success or a negative error + * code on failure. NET_RX_SUCCESS if the received packet is supposed to be + * decapsulated and forwarded to the own soft interface, NET_RX_DROP otherwise. + */ +int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + return batadv_mcast_forw_packet(bat_priv, skb, false); +} diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 34903df4fe93..71c143d4b6d0 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -311,6 +311,33 @@ batadv_orig_router_get(struct batadv_orig_node *orig_node, return router; } +/** + * batadv_orig_to_router() - get next hop neighbor to an orig address + * @bat_priv: the bat priv with all the soft interface information + * @orig_addr: the originator MAC address to search the best next hop router for + * @if_outgoing: the interface where the payload packet has been received or + * the OGM should be sent to + * + * Return: A neighbor node which is the best router towards the given originator + * address. + */ +struct batadv_neigh_node * +batadv_orig_to_router(struct batadv_priv *bat_priv, u8 *orig_addr, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_neigh_node *neigh_node; + struct batadv_orig_node *orig_node; + + orig_node = batadv_orig_hash_find(bat_priv, orig_addr); + if (!orig_node) + return NULL; + + neigh_node = batadv_find_router(bat_priv, orig_node, if_outgoing); + batadv_orig_node_put(orig_node); + + return neigh_node; +} + /** * batadv_orig_ifinfo_get() - find the ifinfo from an orig_node * @orig_node: the orig node to be queried @@ -942,6 +969,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, #ifdef CONFIG_BATMAN_ADV_MCAST orig_node->mcast_flags = BATADV_MCAST_WANT_NO_RTR4; orig_node->mcast_flags |= BATADV_MCAST_WANT_NO_RTR6; + orig_node->mcast_flags |= BATADV_MCAST_HAVE_MC_PTYPE_CAPA; INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node); INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node); INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node); diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index ea3d69e4e670..db0c55128170 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -36,6 +36,9 @@ void batadv_neigh_node_release(struct kref *ref); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, const struct batadv_hard_iface *if_outgoing); +struct batadv_neigh_node * +batadv_orig_to_router(struct batadv_priv *bat_priv, u8 *orig_addr, + struct batadv_hard_iface *if_outgoing); struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 163cd43c4821..f1061985149f 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1270,3 +1270,73 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, batadv_orig_node_put(orig_node); return ret; } + +#ifdef CONFIG_BATMAN_ADV_MCAST +/** + * batadv_recv_mcast_packet() - process received batman-adv multicast packet + * @skb: the received batman-adv multicast packet + * @recv_if: interface that the skb is received on + * + * Parses the given, received batman-adv multicast packet. Depending on the + * contents of its TVLV forwards it and/or decapsulates it to hand it to the + * soft interface. + * + * Return: NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise. + */ +int batadv_recv_mcast_packet(struct sk_buff *skb, + struct batadv_hard_iface *recv_if) +{ + struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); + struct batadv_mcast_packet *mcast_packet; + int hdr_size = sizeof(*mcast_packet); + unsigned char *tvlv_buff; + int ret = NET_RX_DROP; + u16 tvlv_buff_len; + + if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) + goto free_skb; + + /* create a copy of the skb, if needed, to modify it. */ + if (skb_cow(skb, ETH_HLEN) < 0) + goto free_skb; + + /* packet needs to be linearized to access the tvlv content */ + if (skb_linearize(skb) < 0) + goto free_skb; + + mcast_packet = (struct batadv_mcast_packet *)skb->data; + if (mcast_packet->ttl-- < 2) + goto free_skb; + + tvlv_buff = (unsigned char *)(skb->data + hdr_size); + tvlv_buff_len = ntohs(mcast_packet->tvlv_len); + + if (tvlv_buff_len > skb->len - hdr_size) + goto free_skb; + + ret = batadv_tvlv_containers_process(bat_priv, BATADV_MCAST, NULL, skb, + tvlv_buff, tvlv_buff_len); + if (ret >= 0) { + batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_RX); + batadv_add_counter(bat_priv, BATADV_CNT_MCAST_RX_BYTES, + skb->len + ETH_HLEN); + } + + hdr_size += tvlv_buff_len; + + if (ret == NET_RX_SUCCESS && (skb->len - hdr_size >= ETH_HLEN)) { + batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_RX_LOCAL); + batadv_add_counter(bat_priv, BATADV_CNT_MCAST_RX_LOCAL_BYTES, + skb->len - hdr_size); + + batadv_interface_rx(bat_priv->soft_iface, skb, hdr_size, NULL); + /* skb was consumed */ + skb = NULL; + } + +free_skb: + kfree_skb(skb); + + return ret; +} +#endif /* CONFIG_BATMAN_ADV_MCAST */ diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index afd15b3879f1..e9849f032a24 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h @@ -27,6 +27,17 @@ int batadv_recv_frag_packet(struct sk_buff *skb, struct batadv_hard_iface *iface); int batadv_recv_bcast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if); +#ifdef CONFIG_BATMAN_ADV_MCAST +int batadv_recv_mcast_packet(struct sk_buff *skb, + struct batadv_hard_iface *recv_if); +#else +static inline int batadv_recv_mcast_packet(struct sk_buff *skb, + struct batadv_hard_iface *recv_if) +{ + kfree_skb(skb); + return NET_RX_DROP; +} +#endif int batadv_recv_unicast_tvlv(struct sk_buff *skb, struct batadv_hard_iface *recv_if); int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 1bf1232a4f75..1b0e2c59aef2 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -925,6 +925,18 @@ static const struct { { "tt_response_rx" }, { "tt_roam_adv_tx" }, { "tt_roam_adv_rx" }, +#ifdef CONFIG_BATMAN_ADV_MCAST + { "mcast_tx" }, + { "mcast_tx_bytes" }, + { "mcast_tx_local" }, + { "mcast_tx_local_bytes" }, + { "mcast_rx" }, + { "mcast_rx_bytes" }, + { "mcast_rx_local" }, + { "mcast_rx_local_bytes" }, + { "mcast_fwd" }, + { "mcast_fwd_bytes" }, +#endif #ifdef CONFIG_BATMAN_ADV_DAT { "dat_get_tx" }, { "dat_get_rx" }, diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 17d5ea1d8e84..850b184e5b04 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -862,6 +862,70 @@ enum batadv_counters { */ BATADV_CNT_TT_ROAM_ADV_RX, +#ifdef CONFIG_BATMAN_ADV_MCAST + /** + * @BATADV_CNT_MCAST_TX: transmitted batman-adv multicast packets + * counter + */ + BATADV_CNT_MCAST_TX, + + /** + * @BATADV_CNT_MCAST_TX_BYTES: transmitted batman-adv multicast packets + * bytes counter + */ + BATADV_CNT_MCAST_TX_BYTES, + + /** + * @BATADV_CNT_MCAST_TX_LOCAL: counter for multicast packets which + * were locally encapsulated and transmitted as batman-adv multicast + * packets + */ + BATADV_CNT_MCAST_TX_LOCAL, + + /** + * @BATADV_CNT_MCAST_TX_LOCAL_BYTES: bytes counter for multicast packets + * which were locally encapsulated and transmitted as batman-adv + * multicast packets + */ + BATADV_CNT_MCAST_TX_LOCAL_BYTES, + + /** + * @BATADV_CNT_MCAST_RX: received batman-adv multicast packet counter + */ + BATADV_CNT_MCAST_RX, + + /** + * @BATADV_CNT_MCAST_RX_BYTES: received batman-adv multicast packet + * bytes counter + */ + BATADV_CNT_MCAST_RX_BYTES, + + /** + * @BATADV_CNT_MCAST_RX_LOCAL: counter for received batman-adv multicast + * packets which were forwarded to the local soft interface + */ + BATADV_CNT_MCAST_RX_LOCAL, + + /** + * @BATADV_CNT_MCAST_RX_LOCAL_BYTES: bytes counter for received + * batman-adv multicast packets which were forwarded to the local soft + * interface + */ + BATADV_CNT_MCAST_RX_LOCAL_BYTES, + + /** + * @BATADV_CNT_MCAST_FWD: counter for received batman-adv multicast + * packets which were forwarded to other, neighboring nodes + */ + BATADV_CNT_MCAST_FWD, + + /** + * @BATADV_CNT_MCAST_FWD_BYTES: bytes counter for received batman-adv + * multicast packets which were forwarded to other, neighboring nodes + */ + BATADV_CNT_MCAST_FWD_BYTES, +#endif + #ifdef CONFIG_BATMAN_ADV_DAT /** * @BATADV_CNT_DAT_GET_TX: transmitted dht GET traffic packet counter From 90039133221e33964ccb4a536dad7eb0a372fff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 7 Sep 2023 03:09:09 +0200 Subject: [PATCH 0470/7721] batman-adv: mcast: implement multicast packet generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the preparation of a batman-adv multicast packet and use this under certain conditions. For one thing this implements the capability to push a complete batman-adv multicast packet header, including a tracker TVLV with all originator destinations that have signaled interest in it, onto a given ethernet frame with an IP multicast packet inside. For another checks are implemented to determine if encapsulating a multicast packet in this new batman-adv multicast packet type and using it is feasible. Those checks are: 1) Have all nodes signaled that they are capable of handling the new batman-adv multicast packet type? 2) Do all active hard interfaces of all nodes, including us, have an MTU of at least 1280 bytes? 3) Does a complete multicast packet header with all its destination addresses fit onto the given multicast packet / ethernet frame and does not exceed 1280 bytes? If all checks passed then the new batman-adv multicast packet type will be used for transmission and distribution. Otherwise we fall back to one or more batman-adv unicast packet transmissions, if possible. Or if not possible we will fall back to classic flooding through a batman-adv broadcast packet. Signed-off-by: Linus Lüssing Signed-off-by: Simon Wunderlich --- net/batman-adv/multicast.c | 79 +++- net/batman-adv/multicast.h | 25 +- net/batman-adv/multicast_forw.c | 732 ++++++++++++++++++++++++++++++++ net/batman-adv/soft-interface.c | 6 +- net/batman-adv/types.h | 6 + 5 files changed, 840 insertions(+), 8 deletions(-) diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index dfc2c645b13f..62288afdad49 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -1169,17 +1169,62 @@ static int batadv_mcast_forw_rtr_count(struct batadv_priv *bat_priv, } } +/** + * batadv_mcast_forw_mode_by_count() - get forwarding mode by count + * @bat_priv: the bat priv with all the soft interface information + * @skb: the multicast packet to check + * @vid: the vlan identifier + * @is_routable: stores whether the destination is routable + * @count: the number of originators the multicast packet need to be sent to + * + * For a multicast packet with multiple destination originators, checks which + * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a + * complete batman-adv multicast header. + * + * Return: + * BATADV_FORW_MCAST: If all nodes have multicast packet routing + * capabilities and an MTU >= 1280 on all hard interfaces (including us) + * and the encapsulated multicast packet with all destination addresses + * would still fit into an 1280 bytes batman-adv multicast packet + * (excluding the outer ethernet frame) and we could successfully push + * the full batman-adv multicast packet header. + * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv + * multicast packet and the amount of batman-adv unicast packets needed + * is smaller or equal to the configured multicast fanout. + * BATADV_FORW_BCAST: Otherwise. + */ +static enum batadv_forw_mode +batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv, + struct sk_buff *skb, unsigned short vid, + int is_routable, int count) +{ + unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count); + u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags; + + if (!atomic_read(&bat_priv->mcast.num_no_mc_ptype_capa) && + own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA && + skb->len + mcast_hdrlen <= IPV6_MIN_MTU && + batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count)) + return BATADV_FORW_MCAST; + + if (count <= atomic_read(&bat_priv->multicast_fanout)) + return BATADV_FORW_UCASTS; + + return BATADV_FORW_BCAST; +} + /** * batadv_mcast_forw_mode() - check on how to forward a multicast packet * @bat_priv: the bat priv with all the soft interface information * @skb: the multicast packet to check + * @vid: the vlan identifier * @is_routable: stores whether the destination is routable * * Return: The forwarding mode as enum batadv_forw_mode. */ enum batadv_forw_mode batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, - int *is_routable) + unsigned short vid, int *is_routable) { int ret, tt_count, ip_count, unsnoop_count, total_count; bool is_unsnoopable = false; @@ -1209,10 +1254,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, else if (unsnoop_count) return BATADV_FORW_BCAST; - if (total_count <= atomic_read(&bat_priv->multicast_fanout)) - return BATADV_FORW_UCASTS; - - return BATADV_FORW_BCAST; + return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable, + total_count); } /** @@ -1772,6 +1815,31 @@ static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv, } } +/** + * batadv_mcast_have_mc_ptype_update() - update multicast packet type counter + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node which multicast state might have changed of + * @mcast_flags: flags indicating the new multicast state + * + * If the BATADV_MCAST_HAVE_MC_PTYPE_CAPA flag of this originator, orig, has + * toggled then this method updates the counter accordingly. + */ +static void batadv_mcast_have_mc_ptype_update(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + u8 mcast_flags) +{ + lockdep_assert_held(&orig->mcast_handler_lock); + + /* switched from flag set to unset */ + if (!(mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA) && + orig->mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA) + atomic_inc(&bat_priv->mcast.num_no_mc_ptype_capa); + /* switched from flag unset to set */ + else if (mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA && + !(orig->mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA)) + atomic_dec(&bat_priv->mcast.num_no_mc_ptype_capa); +} + /** * batadv_mcast_tvlv_flags_get() - get multicast flags from an OGM TVLV * @enabled: whether the originator has multicast TVLV support enabled @@ -1840,6 +1908,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags); batadv_mcast_want_rtr4_update(bat_priv, orig, mcast_flags); batadv_mcast_want_rtr6_update(bat_priv, orig, mcast_flags); + batadv_mcast_have_mc_ptype_update(bat_priv, orig, mcast_flags); orig->mcast_flags = mcast_flags; spin_unlock_bh(&orig->mcast_handler_lock); diff --git a/net/batman-adv/multicast.h b/net/batman-adv/multicast.h index a5c0f384bb9a..d97ee51d26f2 100644 --- a/net/batman-adv/multicast.h +++ b/net/batman-adv/multicast.h @@ -11,6 +11,7 @@ #include #include +#include /** * enum batadv_forw_mode - the way a packet should be forwarded as @@ -28,6 +29,12 @@ enum batadv_forw_mode { */ BATADV_FORW_UCASTS, + /** + * @BATADV_FORW_MCAST: forward the packet to some nodes via a + * batman-adv multicast packet + */ + BATADV_FORW_MCAST, + /** @BATADV_FORW_NONE: don't forward, drop it */ BATADV_FORW_NONE, }; @@ -36,7 +43,7 @@ enum batadv_forw_mode { enum batadv_forw_mode batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, - int *is_routable); + unsigned short vid, int *is_routable); int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid, int is_routable); @@ -57,11 +64,18 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node); int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv, struct sk_buff *skb); +unsigned int batadv_mcast_forw_packet_hdrlen(unsigned int num_dests); + +bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, int is_routable, int count); + +int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv, struct sk_buff *skb); + #else static inline enum batadv_forw_mode batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, - int *is_routable) + unsigned short vid, int *is_routable) { return BATADV_FORW_BCAST; } @@ -99,6 +113,13 @@ static inline void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node) { } +static inline int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + kfree_skb(skb); + return NET_XMIT_DROP; +} + #endif /* CONFIG_BATMAN_ADV_MCAST */ #endif /* _NET_BATMAN_ADV_MULTICAST_H_ */ diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c index d17341dfb832..a2c5c587b8fb 100644 --- a/net/batman-adv/multicast_forw.c +++ b/net/batman-adv/multicast_forw.c @@ -7,19 +7,30 @@ #include "multicast.h" #include "main.h" +#include +#include #include +#include #include #include #include #include +#include +#include +#include #include +#include +#include #include #include +#include #include #include +#include "bridge_loop_avoidance.h" #include "originator.h" #include "send.h" +#include "translation-table.h" #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \ for (; num_dests; num_dests--, (dest) += ETH_ALEN) @@ -27,6 +38,600 @@ #define batadv_mcast_forw_tracker_for_each_dest2(dest1, dest2, num_dests) \ for (; num_dests; num_dests--, (dest1) += ETH_ALEN, (dest2) += ETH_ALEN) +/** + * batadv_mcast_forw_skb_push() - skb_push and memorize amount of pushed bytes + * @skb: the skb to push onto + * @size: the amount of bytes to push + * @len: stores the total amount of bytes pushed + * + * Performs an skb_push() onto the given skb and adds the amount of pushed bytes + * to the given len pointer. + * + * Return: the return value of the skb_push() call. + */ +static void *batadv_mcast_forw_skb_push(struct sk_buff *skb, size_t size, + unsigned short *len) +{ + *len += size; + return skb_push(skb, size); +} + +/** + * batadv_mcast_forw_push_padding() - push 2 padding bytes to skb's front + * @skb: the skb to push onto + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Pushes two padding bytes to the front of the given skb. + * + * Return: On success a pointer to the first byte of the two pushed padding + * bytes within the skb. NULL otherwise. + */ +static char * +batadv_mcast_forw_push_padding(struct sk_buff *skb, unsigned short *tvlv_len) +{ + const int pad_len = 2; + char *padding; + + if (skb_headroom(skb) < pad_len) + return NULL; + + padding = batadv_mcast_forw_skb_push(skb, pad_len, tvlv_len); + memset(padding, 0, pad_len); + + return padding; +} + +/** + * batadv_mcast_forw_push_est_padding() - push padding bytes if necessary + * @skb: the skb to potentially push the padding onto + * @count: the (estimated) number of originators the multicast packet needs to + * be sent to + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * If the number of destination entries is even then this adds two + * padding bytes to the end of the tracker TVLV. + * + * Return: true on success or if no padding is needed, false otherwise. + */ +static bool +batadv_mcast_forw_push_est_padding(struct sk_buff *skb, int count, + unsigned short *tvlv_len) +{ + if (!(count % 2) && !batadv_mcast_forw_push_padding(skb, tvlv_len)) + return false; + + return true; +} + +/** + * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node + * @node: the hlist node to get the orig_node from + * @entry_offset: the offset of the hlist node within the orig_node struct + * + * Return: The orig_node containing the hlist node on success, NULL on error. + */ +static struct batadv_orig_node * +batadv_mcast_forw_orig_entry(struct hlist_node *node, + size_t entry_offset) +{ + /* sanity check */ + switch (entry_offset) { + case offsetof(struct batadv_orig_node, mcast_want_all_ipv4_node): + case offsetof(struct batadv_orig_node, mcast_want_all_ipv6_node): + case offsetof(struct batadv_orig_node, mcast_want_all_rtr4_node): + case offsetof(struct batadv_orig_node, mcast_want_all_rtr6_node): + break; + default: + WARN_ON(1); + return NULL; + } + + return (struct batadv_orig_node *)((void *)node - entry_offset); +} + +/** + * batadv_mcast_forw_push_dest() - push an originator MAC address onto an skb + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination address onto + * @vid: the vlan identifier + * @orig_node: the originator node to get the MAC address from + * @num_dests: a pointer to store the number of pushed addresses in + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * If the orig_node is a BLA backbone gateway, if there is not enough skb + * headroom available or if num_dests is already at its maximum (65535) then + * neither the skb nor num_dests is changed. Otherwise the originator's MAC + * address is pushed onto the given skb and num_dests incremented by one. + * + * Return: true if the orig_node is a backbone gateway or if an orig address + * was pushed successfully, false otherwise. + */ +static bool batadv_mcast_forw_push_dest(struct batadv_priv *bat_priv, + struct sk_buff *skb, unsigned short vid, + struct batadv_orig_node *orig_node, + unsigned short *num_dests, + unsigned short *tvlv_len) +{ + BUILD_BUG_ON(sizeof_field(struct batadv_tvlv_mcast_tracker, num_dests) + != sizeof(__be16)); + + /* Avoid sending to other BLA gateways - they already got the frame from + * the LAN side we share with them. + * TODO: Refactor to take BLA into account earlier in mode check. + */ + if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) + return true; + + if (skb_headroom(skb) < ETH_ALEN || *num_dests == U16_MAX) + return false; + + batadv_mcast_forw_skb_push(skb, ETH_ALEN, tvlv_len); + ether_addr_copy(skb->data, orig_node->orig); + (*num_dests)++; + + return true; +} + +/** + * batadv_mcast_forw_push_dests_list() - push originators from list onto an skb + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination addresses onto + * @vid: the vlan identifier + * @head: the list to gather originators from + * @entry_offset: offset of an hlist node in an orig_node structure + * @num_dests: a pointer to store the number of pushed addresses in + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Push the MAC addresses of all originators in the given list onto the given + * skb. + * + * Return: true on success, false otherwise. + */ +static int batadv_mcast_forw_push_dests_list(struct batadv_priv *bat_priv, + struct sk_buff *skb, + unsigned short vid, + struct hlist_head *head, + size_t entry_offset, + unsigned short *num_dests, + unsigned short *tvlv_len) +{ + struct hlist_node *node; + struct batadv_orig_node *orig_node; + + rcu_read_lock(); + __hlist_for_each_rcu(node, head) { + orig_node = batadv_mcast_forw_orig_entry(node, entry_offset); + if (!orig_node || + !batadv_mcast_forw_push_dest(bat_priv, skb, vid, orig_node, + num_dests, tvlv_len)) { + rcu_read_unlock(); + return false; + } + } + rcu_read_unlock(); + + return true; +} + +/** + * batadv_mcast_forw_push_tt() - push originators with interest through TT + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination addresses onto + * @vid: the vlan identifier + * @num_dests: a pointer to store the number of pushed addresses in + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Push the MAC addresses of all originators which have indicated interest in + * this multicast packet through the translation table onto the given skb. + * + * Return: true on success, false otherwise. + */ +static bool +batadv_mcast_forw_push_tt(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, unsigned short *num_dests, + unsigned short *tvlv_len) +{ + struct batadv_tt_orig_list_entry *orig_entry; + + struct batadv_tt_global_entry *tt_global; + const u8 *addr = eth_hdr(skb)->h_dest; + + /* ok */ + int ret = true; + + tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); + if (!tt_global) + goto out; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) { + if (!batadv_mcast_forw_push_dest(bat_priv, skb, vid, + orig_entry->orig_node, + num_dests, tvlv_len)) { + ret = false; + break; + } + } + rcu_read_unlock(); + + batadv_tt_global_entry_put(tt_global); + +out: + return ret; +} + +/** + * batadv_mcast_forw_push_want_all() - push originators with want-all flag + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination addresses onto + * @vid: the vlan identifier + * @num_dests: a pointer to store the number of pushed addresses in + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Push the MAC addresses of all originators which have indicated interest in + * this multicast packet through the want-all flag onto the given skb. + * + * Return: true on success, false otherwise. + */ +static bool batadv_mcast_forw_push_want_all(struct batadv_priv *bat_priv, + struct sk_buff *skb, + unsigned short vid, + unsigned short *num_dests, + unsigned short *tvlv_len) +{ + struct hlist_head *head = NULL; + size_t offset; + int ret; + + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + head = &bat_priv->mcast.want_all_ipv4_list; + offset = offsetof(struct batadv_orig_node, + mcast_want_all_ipv4_node); + break; + case htons(ETH_P_IPV6): + head = &bat_priv->mcast.want_all_ipv6_list; + offset = offsetof(struct batadv_orig_node, + mcast_want_all_ipv6_node); + break; + default: + return false; + } + + ret = batadv_mcast_forw_push_dests_list(bat_priv, skb, vid, head, + offset, num_dests, tvlv_len); + if (!ret) + return false; + + return true; +} + +/** + * batadv_mcast_forw_push_want_rtr() - push originators with want-router flag + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination addresses onto + * @vid: the vlan identifier + * @num_dests: a pointer to store the number of pushed addresses in + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Push the MAC addresses of all originators which have indicated interest in + * this multicast packet through the want-all-rtr flag onto the given skb. + * + * Return: true on success, false otherwise. + */ +static bool batadv_mcast_forw_push_want_rtr(struct batadv_priv *bat_priv, + struct sk_buff *skb, + unsigned short vid, + unsigned short *num_dests, + unsigned short *tvlv_len) +{ + struct hlist_head *head = NULL; + size_t offset; + int ret; + + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + head = &bat_priv->mcast.want_all_rtr4_list; + offset = offsetof(struct batadv_orig_node, + mcast_want_all_rtr4_node); + break; + case htons(ETH_P_IPV6): + head = &bat_priv->mcast.want_all_rtr6_list; + offset = offsetof(struct batadv_orig_node, + mcast_want_all_rtr6_node); + break; + default: + return false; + } + + ret = batadv_mcast_forw_push_dests_list(bat_priv, skb, vid, head, + offset, num_dests, tvlv_len); + if (!ret) + return false; + + return true; +} + +/** + * batadv_mcast_forw_scrape() - remove bytes within skb data + * @skb: the skb to remove bytes from + * @offset: the offset from the skb data from which to scrape + * @len: the amount of bytes to scrape starting from the offset + * + * Scrapes/removes len bytes from the given skb at the given offset from the + * skb data. + * + * Caller needs to ensure that the region from the skb data's start up + * to/including the to be removed bytes are linearized. + */ +static void batadv_mcast_forw_scrape(struct sk_buff *skb, + unsigned short offset, + unsigned short len) +{ + char *to, *from; + + SKB_LINEAR_ASSERT(skb); + + to = skb_pull(skb, len); + from = to - len; + + memmove(to, from, offset); +} + +/** + * batadv_mcast_forw_push_scrape_padding() - remove TVLV padding + * @skb: the skb to potentially adjust the TVLV's padding on + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Remove two padding bytes from the end of the multicast tracker TVLV, + * from before the payload data. + * + * Caller needs to ensure that the TVLV bytes are linearized. + */ +static void batadv_mcast_forw_push_scrape_padding(struct sk_buff *skb, + unsigned short *tvlv_len) +{ + const int pad_len = 2; + + batadv_mcast_forw_scrape(skb, *tvlv_len - pad_len, pad_len); + *tvlv_len -= pad_len; +} + +/** + * batadv_mcast_forw_push_insert_padding() - insert TVLV padding + * @skb: the skb to potentially adjust the TVLV's padding on + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Inserts two padding bytes at the end of the multicast tracker TVLV, + * before the payload data in the given skb. + * + * Return: true on success, false otherwise. + */ +static bool batadv_mcast_forw_push_insert_padding(struct sk_buff *skb, + unsigned short *tvlv_len) +{ + unsigned short offset = *tvlv_len; + char *to, *from = skb->data; + + to = batadv_mcast_forw_push_padding(skb, tvlv_len); + if (!to) + return false; + + memmove(to, from, offset); + memset(to + offset, 0, *tvlv_len - offset); + return true; +} + +/** + * batadv_mcast_forw_push_adjust_padding() - adjust padding if necessary + * @skb: the skb to potentially adjust the TVLV's padding on + * @count: the estimated number of originators the multicast packet needs to + * be sent to + * @num_dests_pushed: the number of originators that were actually added to the + * multicast packet's tracker TVLV + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Adjusts the padding in the multicast packet's tracker TVLV depending on the + * initially estimated amount of destinations versus the amount of destinations + * that were actually added to the tracker TVLV. + * + * If the initial estimate was correct or at least the oddness was the same then + * no padding adjustment is performed. + * If the initially estimated number was even, so padding was initially added, + * but it turned out to be odd then padding is removed. + * If the initially estimated number was odd, so no padding was initially added, + * but it turned out to be even then padding is added. + * + * Return: true if no padding adjustment is needed or the adjustment was + * successful, false otherwise. + */ +static bool +batadv_mcast_forw_push_adjust_padding(struct sk_buff *skb, int *count, + unsigned short num_dests_pushed, + unsigned short *tvlv_len) +{ + int ret = true; + + if (likely((num_dests_pushed % 2) == (*count % 2))) + goto out; + + /** + * estimated even number of destinations, but turned out to be odd + * -> remove padding + */ + if (!(*count % 2) && (num_dests_pushed % 2)) + batadv_mcast_forw_push_scrape_padding(skb, tvlv_len); + /** + * estimated odd number of destinations, but turned out to be even + * -> add padding + */ + else if ((*count % 2) && (!(num_dests_pushed % 2))) + ret = batadv_mcast_forw_push_insert_padding(skb, tvlv_len); + +out: + *count = num_dests_pushed; + return ret; +} + +/** + * batadv_mcast_forw_push_dests() - push originator addresses onto an skb + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the destination addresses onto + * @vid: the vlan identifier + * @is_routable: indicates whether the destination is routable + * @count: the number of originators the multicast packet needs to be sent to + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Push the MAC addresses of all originators which have indicated interest in + * this multicast packet onto the given skb. + * + * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on + * success 0. + */ +static int +batadv_mcast_forw_push_dests(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, int is_routable, int *count, + unsigned short *tvlv_len) +{ + unsigned short num_dests = 0; + + if (!batadv_mcast_forw_push_est_padding(skb, *count, tvlv_len)) + goto err; + + if (!batadv_mcast_forw_push_tt(bat_priv, skb, vid, &num_dests, + tvlv_len)) + goto err; + + if (!batadv_mcast_forw_push_want_all(bat_priv, skb, vid, &num_dests, + tvlv_len)) + goto err; + + if (is_routable && + !batadv_mcast_forw_push_want_rtr(bat_priv, skb, vid, &num_dests, + tvlv_len)) + goto err; + + if (!batadv_mcast_forw_push_adjust_padding(skb, count, num_dests, + tvlv_len)) + goto err; + + return 0; +err: + return -ENOMEM; +} + +/** + * batadv_mcast_forw_push_tracker() - push a multicast tracker TVLV header + * @skb: the skb to push the tracker TVLV onto + * @num_dests: the number of destination addresses to set in the header + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Pushes a multicast tracker TVLV header onto the given skb, including the + * generic TVLV header but excluding the destination MAC addresses. + * + * The provided num_dests value is taken into consideration to set the + * num_dests field in the tracker header and to set the appropriate TVLV length + * value fields. + * + * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on + * success 0. + */ +static int batadv_mcast_forw_push_tracker(struct sk_buff *skb, int num_dests, + unsigned short *tvlv_len) +{ + struct batadv_tvlv_mcast_tracker *mcast_tracker; + struct batadv_tvlv_hdr *tvlv_hdr; + unsigned int tvlv_value_len; + + if (skb_headroom(skb) < sizeof(*mcast_tracker) + sizeof(*tvlv_hdr)) + return -ENOMEM; + + tvlv_value_len = sizeof(*mcast_tracker) + *tvlv_len; + if (tvlv_value_len + sizeof(*tvlv_hdr) > U16_MAX) + return -ENOMEM; + + batadv_mcast_forw_skb_push(skb, sizeof(*mcast_tracker), tvlv_len); + mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb->data; + mcast_tracker->num_dests = htons(num_dests); + + skb_reset_network_header(skb); + + batadv_mcast_forw_skb_push(skb, sizeof(*tvlv_hdr), tvlv_len); + tvlv_hdr = (struct batadv_tvlv_hdr *)skb->data; + tvlv_hdr->type = BATADV_TVLV_MCAST_TRACKER; + tvlv_hdr->version = 1; + tvlv_hdr->len = htons(tvlv_value_len); + + return 0; +} + +/** + * batadv_mcast_forw_push_tvlvs() - push a multicast tracker TVLV onto an skb + * @bat_priv: the bat priv with all the soft interface information + * @skb: the skb to push the tracker TVLV onto + * @vid: the vlan identifier + * @is_routable: indicates whether the destination is routable + * @count: the number of originators the multicast packet needs to be sent to + * @tvlv_len: stores the amount of currently pushed TVLV bytes + * + * Pushes a multicast tracker TVLV onto the given skb, including the collected + * destination MAC addresses and the generic TVLV header. + * + * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on + * success 0. + */ +static int +batadv_mcast_forw_push_tvlvs(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, int is_routable, int count, + unsigned short *tvlv_len) +{ + int ret; + + ret = batadv_mcast_forw_push_dests(bat_priv, skb, vid, is_routable, + &count, tvlv_len); + if (ret < 0) + return ret; + + ret = batadv_mcast_forw_push_tracker(skb, count, tvlv_len); + if (ret < 0) + return ret; + + return 0; +} + +/** + * batadv_mcast_forw_push_hdr() - push a multicast packet header onto an skb + * @skb: the skb to push the header onto + * @tvlv_len: the total TVLV length value to set in the header + * + * Pushes a batman-adv multicast packet header onto the given skb and sets + * the provided total TVLV length value in it. + * + * Caller needs to ensure enough skb headroom is available. + * + * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on + * success 0. + */ +static int +batadv_mcast_forw_push_hdr(struct sk_buff *skb, unsigned short tvlv_len) +{ + struct batadv_mcast_packet *mcast_packet; + + if (skb_headroom(skb) < sizeof(*mcast_packet)) + return -ENOMEM; + + skb_push(skb, sizeof(*mcast_packet)); + + mcast_packet = (struct batadv_mcast_packet *)skb->data; + mcast_packet->version = BATADV_COMPAT_VERSION; + mcast_packet->ttl = BATADV_TTL; + mcast_packet->packet_type = BATADV_MCAST; + mcast_packet->reserved = 0; + mcast_packet->tvlv_len = htons(tvlv_len); + + return 0; +} + /** * batadv_mcast_forw_scrub_dests() - scrub destinations in a tracker TVLV * @bat_priv: the bat priv with all the soft interface information @@ -237,3 +842,130 @@ int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv, { return batadv_mcast_forw_packet(bat_priv, skb, false); } + +/** + * batadv_mcast_forw_packet_hdrlen() - multicast packet header length + * @num_dests: number of destination nodes + * + * Calculates the total batman-adv multicast packet header length for a given + * number of destination nodes (excluding the outer ethernet frame). + * + * Return: The calculated total batman-adv multicast packet header length. + */ +unsigned int batadv_mcast_forw_packet_hdrlen(unsigned int num_dests) +{ + /** + * If the number of destination entries is even then we need to add + * two byte padding to the tracker TVLV. + */ + int padding = (!(num_dests % 2)) ? 2 : 0; + + return padding + num_dests * ETH_ALEN + + sizeof(struct batadv_tvlv_mcast_tracker) + + sizeof(struct batadv_tvlv_hdr) + + sizeof(struct batadv_mcast_packet); +} + +/** + * batadv_mcast_forw_expand_head() - expand headroom for an mcast packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: the multicast packet to send + * + * Tries to expand an skb's headroom so that its head to tail is 1298 + * bytes (minimum IPv6 MTU + vlan ethernet header size) large. + * + * Return: -EINVAL if the given skb's length is too large or -ENOMEM on memory + * allocation failure. Otherwise, on success, zero is returned. + */ +static int batadv_mcast_forw_expand_head(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + int hdr_size = VLAN_ETH_HLEN + IPV6_MIN_MTU - skb->len; + + /* TODO: Could be tightened to actual number of destination nodes? + * But it's tricky, number of destinations might have increased since + * we last checked. + */ + if (hdr_size < 0) { + /* batadv_mcast_forw_mode_check_count() should ensure we do not + * end up here + */ + WARN_ON(1); + return -EINVAL; + } + + if (skb_headroom(skb) < hdr_size && + pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC) < 0) + return -ENOMEM; + + return 0; +} + +/** + * batadv_mcast_forw_push() - encapsulate skb in a batman-adv multicast packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: the multicast packet to encapsulate and send + * @vid: the vlan identifier + * @is_routable: indicates whether the destination is routable + * @count: the number of originators the multicast packet needs to be sent to + * + * Encapsulates the given multicast packet in a batman-adv multicast packet. + * A multicast tracker TVLV with destination originator addresses for any node + * that signaled interest in it, that is either via the translation table or the + * according want-all flags, is attached accordingly. + * + * Return: true on success, false otherwise. + */ +bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, int is_routable, int count) +{ + unsigned short tvlv_len = 0; + int ret; + + if (batadv_mcast_forw_expand_head(bat_priv, skb) < 0) + goto err; + + skb_reset_transport_header(skb); + + ret = batadv_mcast_forw_push_tvlvs(bat_priv, skb, vid, is_routable, + count, &tvlv_len); + if (ret < 0) + goto err; + + ret = batadv_mcast_forw_push_hdr(skb, tvlv_len); + if (ret < 0) + goto err; + + return true; + +err: + if (tvlv_len) + skb_pull(skb, tvlv_len); + + return false; +} + +/** + * batadv_mcast_forw_mcsend() - send a self prepared batman-adv multicast packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: the multicast packet to encapsulate and send + * + * Transmits a batman-adv multicast packet that was locally prepared and + * consumes/frees it. + * + * Return: NET_XMIT_DROP on memory allocation failure. NET_XMIT_SUCCESS + * otherwise. + */ +int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + int ret = batadv_mcast_forw_packet(bat_priv, skb, true); + + if (ret < 0) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + consume_skb(skb); + return NET_XMIT_SUCCESS; +} diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 1b0e2c59aef2..89c51b3cf430 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -301,12 +301,13 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, send: if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) { - forw_mode = batadv_mcast_forw_mode(bat_priv, skb, + forw_mode = batadv_mcast_forw_mode(bat_priv, skb, vid, &mcast_is_routable); switch (forw_mode) { case BATADV_FORW_BCAST: break; case BATADV_FORW_UCASTS: + case BATADV_FORW_MCAST: do_bcast = false; break; case BATADV_FORW_NONE: @@ -365,6 +366,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, } else if (forw_mode == BATADV_FORW_UCASTS) { ret = batadv_mcast_forw_send(bat_priv, skb, vid, mcast_is_routable); + } else if (forw_mode == BATADV_FORW_MCAST) { + ret = batadv_mcast_forw_mcsend(bat_priv, skb); } else { if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb)) @@ -762,6 +765,7 @@ static int batadv_softif_init_late(struct net_device *dev) atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0); + atomic_set(&bat_priv->mcast.num_no_mc_ptype_capa, 0); #endif atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF); atomic_set(&bat_priv->gw.bandwidth_down, 100); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 850b184e5b04..00840d5784fe 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1342,6 +1342,12 @@ struct batadv_priv_mcast { /** @num_want_all_rtr6: counter for items in want_all_rtr6_list */ atomic_t num_want_all_rtr6; + /** + * @num_no_mc_ptype_capa: counter for number of nodes without the + * BATADV_MCAST_HAVE_MC_PTYPE_CAPA flag + */ + atomic_t num_no_mc_ptype_capa; + /** * @want_lists_lock: lock for protecting modifications to mcasts * want_all_{unsnoopables,ipv4,ipv6}_list (traversals are rcu-locked) From 2dfe644a1ce017cacd449adabd68c3bc49199e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 7 Sep 2023 03:09:10 +0200 Subject: [PATCH 0471/7721] batman-adv: mcast: shrink tracker packet after scrubbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast packet's tracker TVLV before transmitting it and update all headers accordingly. This way, instead of keeping the multicast packet at a constant size throughout its journey through the mesh, it will become more lightweight, smaller with every interested receiver on the way and on each splitting intersection. Which can save some valuable bandwidth. Signed-off-by: Linus Lüssing Signed-off-by: Simon Wunderlich --- net/batman-adv/multicast_forw.c | 207 ++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c index a2c5c587b8fb..fafd6ba8c056 100644 --- a/net/batman-adv/multicast_forw.c +++ b/net/batman-adv/multicast_forw.c @@ -697,6 +697,212 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv *bat_priv, } } +/** + * batadv_mcast_forw_shrink_fill() - swap slot with next non-zero destination + * @slot: the to be filled zero-MAC destination entry in a tracker TVLV + * @num_dests_slot: remaining entries in tracker TVLV from/including slot + * + * Searches for the next non-zero-MAC destination entry in a tracker TVLV after + * the given slot pointer. And if found, swaps it with the zero-MAC destination + * entry which the slot points to. + * + * Return: true if slot was swapped/filled successfully, false otherwise. + */ +static bool batadv_mcast_forw_shrink_fill(u8 *slot, u16 num_dests_slot) +{ + u16 num_dests_filler; + u8 *filler; + + /* sanity check, should not happen */ + if (!num_dests_slot) + return false; + + num_dests_filler = num_dests_slot - 1; + filler = slot + ETH_ALEN; + + /* find a candidate to fill the empty slot */ + batadv_mcast_forw_tracker_for_each_dest(filler, num_dests_filler) { + if (is_zero_ether_addr(filler)) + continue; + + ether_addr_copy(slot, filler); + eth_zero_addr(filler); + return true; + } + + return false; +} + +/** + * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV + * @skb: the batman-adv multicast packet to compact destinations in + * + * Compacts the originator destination MAC addresses in the multicast tracker + * TVLV of the given multicast packet. This is done by moving all non-zero + * MAC addresses in direction of the skb head and all zero MAC addresses in skb + * tail direction, within the multicast tracker TVLV. + * + * Return: The number of consecutive zero MAC address destinations which are + * now at the end of the multicast tracker TVLV. + */ +static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb) +{ + struct batadv_tvlv_mcast_tracker *mcast_tracker; + unsigned char *skb_net_hdr; + u16 num_dests_slot; + u8 *slot; + + skb_net_hdr = skb_network_header(skb); + mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr; + num_dests_slot = ntohs(mcast_tracker->num_dests); + + slot = (u8 *)mcast_tracker + sizeof(*mcast_tracker); + + batadv_mcast_forw_tracker_for_each_dest(slot, num_dests_slot) { + /* find an empty slot */ + if (!is_zero_ether_addr(slot)) + continue; + + if (!batadv_mcast_forw_shrink_fill(slot, num_dests_slot)) + /* could not find a filler, so we successfully packed + * and can stop - and must not reduce num_dests_slot! + */ + break; + } + + /* num_dests_slot is now the amount of reduced, zeroed + * destinations at the end of the tracker TVLV + */ + return num_dests_slot; +} + +/** + * batadv_mcast_forw_shrink_align_offset() - get new alignment offset + * @num_dests_old: the old, to be updated amount of destination nodes + * @num_dests_reduce: the number of destinations that were removed + * + * Calculates the amount of potential extra alignment offset that is needed to + * adjust the TVLV padding after the change in destination nodes. + * + * Return: + * 0: If no change to padding is needed. + * 2: If padding needs to be removed. + * -2: If padding needs to be added. + */ +static short +batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old, + unsigned int num_dests_reduce) +{ + /* even amount of removed destinations -> no alignment change */ + if (!(num_dests_reduce % 2)) + return 0; + + /* even to odd amount of destinations -> remove padding */ + if (!(num_dests_old % 2)) + return 2; + + /* odd to even amount of destinations -> add padding */ + return -2; +} + +/** + * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers + * @skb: the batman-adv multicast packet to update headers of + * @num_dests_reduce: the number of destinations that were removed + * + * This updates any fields of a batman-adv multicast packet that are affected + * by the reduced number of destinations in the multicast tracket TVLV. In + * particular this updates: + * + * The num_dest field of the multicast tracker TVLV. + * The TVLV length field of the according generic TVLV header. + * The batman-adv multicast packet's total TVLV length field. + * + * Return: The offset in skb's tail direction at which the new batman-adv + * multicast packet header needs to start. + */ +static unsigned int +batadv_mcast_forw_shrink_update_headers(struct sk_buff *skb, + unsigned int num_dests_reduce) +{ + struct batadv_tvlv_mcast_tracker *mcast_tracker; + struct batadv_mcast_packet *mcast_packet; + struct batadv_tvlv_hdr *tvlv_hdr; + unsigned char *skb_net_hdr; + unsigned int offset; + short align_offset; + u16 num_dests; + + skb_net_hdr = skb_network_header(skb); + mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr; + num_dests = ntohs(mcast_tracker->num_dests); + + align_offset = batadv_mcast_forw_shrink_align_offset(num_dests, + num_dests_reduce); + offset = ETH_ALEN * num_dests_reduce + align_offset; + num_dests -= num_dests_reduce; + + /* update tracker header */ + mcast_tracker->num_dests = htons(num_dests); + + /* update tracker's tvlv header's length field */ + tvlv_hdr = (struct batadv_tvlv_hdr *)(skb_network_header(skb) - + sizeof(*tvlv_hdr)); + tvlv_hdr->len = htons(ntohs(tvlv_hdr->len) - offset); + + /* update multicast packet header's tvlv length field */ + mcast_packet = (struct batadv_mcast_packet *)skb->data; + mcast_packet->tvlv_len = htons(ntohs(mcast_packet->tvlv_len) - offset); + + return offset; +} + +/** + * batadv_mcast_forw_shrink_move_headers() - move multicast headers by offset + * @skb: the batman-adv multicast packet to move headers for + * @offset: a non-negative offset to move headers by, towards the skb tail + * + * Moves the batman-adv multicast packet header, its multicast tracker TVLV and + * any TVLVs in between by the given offset in direction towards the tail. + */ +static void +batadv_mcast_forw_shrink_move_headers(struct sk_buff *skb, unsigned int offset) +{ + struct batadv_tvlv_mcast_tracker *mcast_tracker; + unsigned char *skb_net_hdr; + unsigned int len; + u16 num_dests; + + skb_net_hdr = skb_network_header(skb); + mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr; + num_dests = ntohs(mcast_tracker->num_dests); + len = skb_network_offset(skb) + sizeof(*mcast_tracker); + len += num_dests * ETH_ALEN; + + batadv_mcast_forw_scrape(skb, len, offset); +} + +/** + * batadv_mcast_forw_shrink_tracker() - remove zero addresses in a tracker tvlv + * @skb: the batman-adv multicast packet to (potentially) shrink + * + * Removes all destinations with a zero MAC addresses (00:00:00:00:00:00) from + * the given batman-adv multicast packet's tracker TVLV and updates headers + * accordingly to maintain a valid batman-adv multicast packet. + */ +static void batadv_mcast_forw_shrink_tracker(struct sk_buff *skb) +{ + unsigned int offset; + u16 dests_reduced; + + dests_reduced = batadv_mcast_forw_shrink_pack_dests(skb); + if (!dests_reduced) + return; + + offset = batadv_mcast_forw_shrink_update_headers(skb, dests_reduced); + batadv_mcast_forw_shrink_move_headers(skb, offset); +} + /** * batadv_mcast_forw_packet() - forward a batman-adv multicast packet * @bat_priv: the bat priv with all the soft interface information @@ -786,6 +992,7 @@ static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv, batadv_mcast_forw_scrub_dests(bat_priv, neigh_node, dest, next_dest, num_dests); + batadv_mcast_forw_shrink_tracker(nexthop_skb); batadv_inc_counter(bat_priv, BATADV_CNT_MCAST_TX); batadv_add_counter(bat_priv, BATADV_CNT_MCAST_TX_BYTES, From 69f9aff27a94ba574567d3f1c57aca53c76dd01a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 30 Oct 2023 15:58:35 +0100 Subject: [PATCH 0472/7721] batman-adv: Switch to linux/sprintf.h The commit 39ced19b9e60 ("lib/vsprintf: split out sprintf() and friends") introduced a new header for the sprintf related functions which were previously exposed via linux/kernel.h. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/bridge_loop_avoidance.c | 2 +- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/main.c | 1 + net/batman-adv/multicast.c | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 37ce6cfb3520..5f46ca3d4bb8 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index d26124bc27e1..0ddd8b4b3f4c 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 50b2bf2b748c..e8c25583a127 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 62288afdad49..d982daea8329 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include From c3ed16a64c0b0a5b116c9753bf48496d49daffb5 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 13 Nov 2023 16:27:45 +0100 Subject: [PATCH 0473/7721] batman-adv: Switch to linux/array_size.h The commit 3cd39bc3b11b ("kernel.h: Move ARRAY_SIZE() to a separate header") introduced a new header for the ARRAY_SIZE macro which was previously exposed via linux/kernel.h. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/main.c | 2 +- net/batman-adv/netlink.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index e8c25583a127..5fc754b0b3f7 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -6,6 +6,7 @@ #include "main.h" +#include #include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 0c64d81a7761..1f7ed9d4f6fd 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -7,6 +7,7 @@ #include "netlink.h" #include "main.h" +#include #include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include #include #include From ce3adea16612a677dd50bdad6861f37f5dc878c3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 8 Nov 2023 17:22:31 +0000 Subject: [PATCH 0474/7721] arm64: dts: renesas: rzg2l-smarc-som: Enable 4-bit tx support Enable 4-bit tx support for sbc node. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231108172232.259301-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi index 547859c388ce..4409c47239b9 100644 --- a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi @@ -312,6 +312,7 @@ flash@0 { m25p,fast-read; spi-max-frequency = <50000000>; spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; partitions { compatible = "fixed-partitions"; From 51dad0523b1e94493c9dd8596bd4a9d0d88d8fcb Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 8 Nov 2023 17:22:32 +0000 Subject: [PATCH 0475/7721] arm64: dts: renesas: rzg2lc-smarc-som: Enable 4-bit tx support Enable 4-bit tx support for sbc node. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231108172232.259301-3-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi index 56ff92453976..5e4209d6fb42 100644 --- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi @@ -241,6 +241,7 @@ flash@0 { m25p,fast-read; spi-max-frequency = <50000000>; spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; partitions { compatible = "fixed-partitions"; From 38b2d9d385102f430eb023aee1ed0ed37d9173f5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:30 +0200 Subject: [PATCH 0476/7721] drm/format-helper: Cache buffers with struct drm_format_conv_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hold temporary memory for format conversion in an instance of struct drm_format_conv_state. Update internal helpers of DRM's format-conversion code accordingly. Drivers will later be able to maintain this cache by themselves. Besides caching, struct drm_format_conv_state will be useful to hold additional information for format conversion, such as palette data or foreground/background colors. This will enable conversion from indexed color formats to component-based formats. v5: * improve documentation (Javier, Noralf) v3: * rename struct drm_xfrm_buf to struct drm_format_conv_state (Javier) * remove managed cleanup * add drm_format_conv_state_copy() for shadow-plane support Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Acked-by: Noralf Trønnes Tested-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_format_helper.c | 118 +++++++++++++++++++++++++--- include/drm/drm_format_helper.h | 51 ++++++++++++ 2 files changed, 158 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index f93a4efcee90..28d013d42778 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -20,6 +20,97 @@ #include #include +/** + * drm_format_conv_state_init - Initialize format-conversion state + * @state: The state to initialize + * + * Clears all fields in struct drm_format_conv_state. The state will + * be empty with no preallocated resources. + */ +void drm_format_conv_state_init(struct drm_format_conv_state *state) +{ + state->tmp.mem = NULL; + state->tmp.size = 0; + state->tmp.preallocated = false; +} +EXPORT_SYMBOL(drm_format_conv_state_init); + +/** + * drm_format_conv_state_copy - Copy format-conversion state + * @state: Destination state + * @old_state: Source state + * + * Copies format-conversion state from @old_state to @state; except for + * temporary storage. + */ +void drm_format_conv_state_copy(struct drm_format_conv_state *state, + const struct drm_format_conv_state *old_state) +{ + /* + * So far, there's only temporary storage here, which we don't + * duplicate. Just clear the fields. + */ + state->tmp.mem = NULL; + state->tmp.size = 0; + state->tmp.preallocated = false; +} +EXPORT_SYMBOL(drm_format_conv_state_copy); + +/** + * drm_format_conv_state_reserve - Allocates storage for format conversion + * @state: The format-conversion state + * @new_size: The minimum allocation size + * @flags: Flags for kmalloc() + * + * Allocates at least @new_size bytes and returns a pointer to the memory + * range. After calling this function, previously returned memory blocks + * are invalid. It's best to collect all memory requirements of a format + * conversion and call this function once to allocate the range. + * + * Returns: + * A pointer to the allocated memory range, or NULL otherwise. + */ +void *drm_format_conv_state_reserve(struct drm_format_conv_state *state, + size_t new_size, gfp_t flags) +{ + void *mem; + + if (new_size <= state->tmp.size) + goto out; + else if (state->tmp.preallocated) + return NULL; + + mem = krealloc(state->tmp.mem, new_size, flags); + if (!mem) + return NULL; + + state->tmp.mem = mem; + state->tmp.size = new_size; + +out: + return state->tmp.mem; +} +EXPORT_SYMBOL(drm_format_conv_state_reserve); + +/** + * drm_format_conv_state_release - Releases an format-conversion storage + * @state: The format-conversion state + * + * Releases the memory range references by the format-conversion state. + * After this call, all pointers to the memory are invalid. Prefer + * drm_format_conv_state_init() for cleaning up and unloading a driver. + */ +void drm_format_conv_state_release(struct drm_format_conv_state *state) +{ + if (state->tmp.preallocated) + return; + + kfree(state->tmp.mem); + state->tmp.mem = NULL; + state->tmp.size = 0; +} +EXPORT_SYMBOL(drm_format_conv_state_release); + static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp) { return clip->y1 * pitch + clip->x1 * cpp; @@ -45,6 +136,7 @@ EXPORT_SYMBOL(drm_fb_clip_offset); static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); @@ -60,7 +152,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p * one line at a time. */ if (!vaddr_cached_hint) { - stmp = kmalloc(sbuf_len, GFP_KERNEL); + stmp = drm_format_conv_state_reserve(state, sbuf_len, GFP_KERNEL); if (!stmp) return -ENOMEM; } @@ -79,8 +171,6 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p dst += dst_pitch; } - kfree(stmp); - return 0; } @@ -88,6 +178,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); @@ -101,9 +192,9 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign void *dbuf; if (vaddr_cached_hint) { - dbuf = kmalloc(dbuf_len, GFP_KERNEL); + dbuf = drm_format_conv_state_reserve(state, dbuf_len, GFP_KERNEL); } else { - dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); + dbuf = drm_format_conv_state_reserve(state, stmp_off + sbuf_len, GFP_KERNEL); stmp = dbuf + stmp_off; } if (!dbuf) @@ -124,8 +215,6 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign dst += dst_pitch; } - kfree(dbuf); - return 0; } @@ -139,17 +228,24 @@ static int drm_fb_xfrm(struct iosys_map *dst, static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 0, 0, 0, 0 }; + struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; + int ret; if (!dst_pitch) dst_pitch = default_dst_pitch; /* TODO: handle src in I/O memory here */ if (dst[0].is_iomem) - return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); + ret = __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, &fmtcnv_state, + xfrm_line); else - return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); + ret = __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, &fmtcnv_state, + xfrm_line); + drm_format_conv_state_release(&fmtcnv_state); + + return ret; } /** diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index 291deb09475b..724a9baf7315 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -15,6 +15,57 @@ struct drm_rect; struct iosys_map; +/** + * struct drm_format_conv_state - Stores format-conversion state + * + * DRM helpers for format conversion store temporary state in + * struct drm_xfrm_buf. The buffer's resources can be reused + * among multiple conversion operations. + * + * All fields are considered private. + */ +struct drm_format_conv_state { + struct { + void *mem; + size_t size; + bool preallocated; + } tmp; +}; + +#define __DRM_FORMAT_CONV_STATE_INIT(_mem, _size, _preallocated) { \ + .tmp = { \ + .mem = (_mem), \ + .size = (_size), \ + .preallocated = (_preallocated), \ + } \ + } + +/** + * DRM_FORMAT_CONV_STATE_INIT - Initializer for struct drm_format_conv_state + * + * Initializes an instance of struct drm_format_conv_state to default values. + */ +#define DRM_FORMAT_CONV_STATE_INIT \ + __DRM_FORMAT_CONV_STATE_INIT(NULL, 0, false) + +/** + * DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED - Initializer for struct drm_format_conv_state + * @_mem: The preallocated memory area + * @_size: The number of bytes in _mem + * + * Initializes an instance of struct drm_format_conv_state to preallocated + * storage. The caller is responsible for releasing the provided memory range. + */ +#define DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED(_mem, _size) \ + __DRM_FORMAT_CONV_STATE_INIT(_mem, _size, true) + +void drm_format_conv_state_init(struct drm_format_conv_state *state); +void drm_format_conv_state_copy(struct drm_format_conv_state *state, + const struct drm_format_conv_state *old_state); +void *drm_format_conv_state_reserve(struct drm_format_conv_state *state, + size_t new_size, gfp_t flags); +void drm_format_conv_state_release(struct drm_format_conv_state *state); + unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format, const struct drm_rect *clip); From 903674588a48df25bb79b1bedbfc48450f1d5d8f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:31 +0200 Subject: [PATCH 0477/7721] drm/atomic-helper: Add format-conversion state to shadow-plane state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store an instance of struct drm_format_conv_state in the shadow-plane state struct drm_shadow_plane_state. Many drivers with shadow planes use DRM's format helpers to copy or convert the framebuffer data to backing storage in the scanout buffer. The shadow plane provides the necessary state and manages the conversion's intermediate buffer memory. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Acked-by: Noralf Trønnes Tested-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_atomic_helper.c | 9 +++++++++ include/drm/drm_gem_atomic_helper.h | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 5d4b9cd077f7..e440f458b663 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -218,7 +218,14 @@ void __drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane, struct drm_shadow_plane_state *new_shadow_plane_state) { + struct drm_plane_state *plane_state = plane->state; + struct drm_shadow_plane_state *shadow_plane_state = + to_drm_shadow_plane_state(plane_state); + __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base); + + drm_format_conv_state_copy(&shadow_plane_state->fmtcnv_state, + &new_shadow_plane_state->fmtcnv_state); } EXPORT_SYMBOL(__drm_gem_duplicate_shadow_plane_state); @@ -266,6 +273,7 @@ EXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state); */ void __drm_gem_destroy_shadow_plane_state(struct drm_shadow_plane_state *shadow_plane_state) { + drm_format_conv_state_release(&shadow_plane_state->fmtcnv_state); __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); } EXPORT_SYMBOL(__drm_gem_destroy_shadow_plane_state); @@ -302,6 +310,7 @@ void __drm_gem_reset_shadow_plane(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state) { __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); + drm_format_conv_state_init(&shadow_plane_state->fmtcnv_state); } EXPORT_SYMBOL(__drm_gem_reset_shadow_plane); diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index 40b8b039518e..3e01c619a25e 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -5,6 +5,7 @@ #include +#include #include #include @@ -49,6 +50,15 @@ struct drm_shadow_plane_state { /** @base: plane state */ struct drm_plane_state base; + /** + * @fmtcnv_state: Format-conversion state + * + * Per-plane state for format conversion. + * Flags for copying shadow buffers into backend storage. Also holds + * temporary storage for format conversion. + */ + struct drm_format_conv_state fmtcnv_state; + /* Transitional state - do not export or duplicate */ /** From 4cd24d4b1a9548f42cdb7f449edc6f869a8ae730 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:32 +0200 Subject: [PATCH 0478/7721] drm/format-helper: Pass format-conversion state to helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass an instance of struct drm_format_conv_state to DRM's format conversion helpers. Update all callers. Most drivers can use the format-conversion state from their shadow- plane state. The shadow plane's destroy function releases the allocated buffer. Drivers will later be able to allocate a buffer of appropriate size in their plane's atomic_check code. The gud driver uses a separate thread for committing updates. For now, the update worker contains its own format-conversion state. Images in the format-helper tests are small. The tests preallocate a static page for the temporary buffer. Unloading the module releases the memory. v6: * update patch for ssd132x support v5: * avoid using unusupported shadow-plane state in repaper (Noralf) * fix documentation (Noralf, kernel test robot) v3: * store buffer in shadow-plane state (Javier, Maxime) * replace ARRAY_SIZE() with sizeof() (Jani) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas # ssd130x Cc: Noralf Trønnes Cc: Javier Martinez Canillas Cc: Gerd Hoffmann Cc: David Lechner Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_format_helper.c | 123 ++++++++++-------- drivers/gpu/drm/drm_mipi_dbi.c | 19 ++- drivers/gpu/drm/gud/gud_pipe.c | 30 +++-- drivers/gpu/drm/solomon/ssd130x.c | 16 ++- .../gpu/drm/tests/drm_format_helper_test.c | 72 ++++++---- drivers/gpu/drm/tiny/cirrus.c | 3 +- drivers/gpu/drm/tiny/ili9225.c | 10 +- drivers/gpu/drm/tiny/ofdrm.c | 2 +- drivers/gpu/drm/tiny/repaper.c | 10 +- drivers/gpu/drm/tiny/simpledrm.c | 2 +- drivers/gpu/drm/tiny/st7586.c | 19 +-- include/drm/drm_format_helper.h | 30 +++-- include/drm/drm_mipi_dbi.h | 4 +- 13 files changed, 200 insertions(+), 140 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 28d013d42778..b1be458ed4dd 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -223,29 +223,25 @@ static int drm_fb_xfrm(struct iosys_map *dst, const unsigned int *dst_pitch, const u8 *dst_pixsize, const struct iosys_map *src, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 0, 0, 0, 0 }; - struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; - int ret; if (!dst_pitch) dst_pitch = default_dst_pitch; /* TODO: handle src in I/O memory here */ if (dst[0].is_iomem) - ret = __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, &fmtcnv_state, - xfrm_line); + return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, state, + xfrm_line); else - ret = __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, &fmtcnv_state, - xfrm_line); - drm_format_conv_state_release(&fmtcnv_state); - - return ret; + return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, state, + xfrm_line); } /** @@ -331,6 +327,7 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * @cached: Source buffer is mapped cached (eg. not write-combined) + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and swaps per-pixel * bytes during the process. Destination and framebuffer formats must match. The @@ -345,7 +342,8 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels */ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool cached) + const struct drm_rect *clip, bool cached, + struct drm_format_conv_state *state) { const struct drm_format_info *format = fb->format; u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8); @@ -364,7 +362,7 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, return; } - drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line); + drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, state, swab_line); } EXPORT_SYMBOL(drm_fb_swab); @@ -391,6 +389,7 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -405,13 +404,13 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne */ void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 1, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgb332_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); @@ -460,6 +459,7 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * @swab: Swap bytes * * This function copies parts of a framebuffer to display memory and converts the @@ -475,7 +475,8 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, */ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool swab) + const struct drm_rect *clip, struct drm_format_conv_state *state, + bool swab) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, @@ -488,7 +489,7 @@ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pi else xfrm_line = drm_fb_xrgb8888_to_rgb565_line; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line); + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); @@ -517,6 +518,7 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -532,13 +534,13 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig */ void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xrgb1555_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555); @@ -569,6 +571,7 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -584,13 +587,13 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig */ void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb1555_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555); @@ -621,6 +624,7 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -636,13 +640,13 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig */ void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgba5551_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551); @@ -671,6 +675,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -686,13 +691,13 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne */ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 3, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgb888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); @@ -719,6 +724,7 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. The parameters @dst, @dst_pitch and @src refer @@ -734,13 +740,13 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig */ void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb8888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888); @@ -765,13 +771,14 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_abgr8888_line); } @@ -795,13 +802,14 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xbgr8888_line); } @@ -831,6 +839,7 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -846,13 +855,14 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un */ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xrgb2101010_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); @@ -884,6 +894,7 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -899,13 +910,14 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un */ void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb2101010_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010); @@ -935,6 +947,7 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -954,13 +967,13 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned */ void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 1, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_gray8_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); @@ -974,6 +987,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); * @src: The framebuffer memory to copy from * @fb: The framebuffer to copy from * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory. If the * formats of the display and the framebuffer mismatch, the blit function @@ -992,7 +1006,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); */ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { uint32_t fb_format = fb->format->format; @@ -1000,44 +1014,44 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d drm_fb_memcpy(dst, dst_pitch, src, fb, clip); return 0; } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); return 0; } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); return 0; } else if (fb_format == DRM_FORMAT_XRGB8888) { if (dst_format == DRM_FORMAT_RGB565) { - drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); + drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false); return 0; } else if (dst_format == DRM_FORMAT_XRGB1555) { - drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB1555) { - drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_RGBA5551) { - drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_RGB888) { - drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB8888) { - drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_XBGR8888) { - drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ABGR8888) { - drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_XRGB2101010) { - drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB2101010) { - drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_BGRX8888) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); return 0; } } @@ -1074,6 +1088,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -1098,7 +1113,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int */ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 0, 0, 0, 0 @@ -1138,7 +1153,7 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc * Allocate a buffer to be used for both copying from the cma * memory and to store the intermediate grayscale line pixels. */ - src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL); + src32 = drm_format_conv_state_reserve(state, len_src32 + linepixels, GFP_KERNEL); if (!src32) return; @@ -1152,8 +1167,6 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc vaddr += fb->pitches[0]; mono += dst_pitch_0; } - - kfree(src32); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index e90f0bf895b3..daac649aabdb 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -197,12 +197,14 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf); * @fb: The source framebuffer * @clip: Clipping rectangle of the area to be copied * @swap: When true, swap MSB/LSB of 16-bit values + * @fmtcnv_state: Format-conversion state * * Returns: * Zero on success, negative error code on failure. */ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *clip, bool swap) + struct drm_rect *clip, bool swap, + struct drm_format_conv_state *fmtcnv_state) { struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst); @@ -215,12 +217,13 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer * switch (fb->format->format) { case DRM_FORMAT_RGB565: if (swap) - drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach); + drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach, + fmtcnv_state); else drm_fb_memcpy(&dst_map, NULL, src, fb, clip); break; case DRM_FORMAT_XRGB8888: - drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, swap); + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); break; default: drm_err_once(fb->dev, "Format is not supported: %p4cc\n", @@ -252,7 +255,7 @@ static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev, } static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, struct drm_format_conv_state *fmtcnv_state) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; @@ -270,7 +273,7 @@ static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, if (!dbi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = dbidev->tx_buf; - ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap); + ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap, fmtcnv_state); if (ret) goto err_msg; } else { @@ -332,7 +335,8 @@ void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } @@ -368,7 +372,8 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev, if (!drm_dev_enter(&dbidev->drm, &idx)) return; - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); backlight_enable(dbidev->backlight); drm_dev_exit(idx); diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index d2f199ea3c11..28171de84718 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -51,7 +51,8 @@ static bool gud_is_big_endian(void) static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format, void *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, + struct drm_format_conv_state *fmtcnv_state) { unsigned int block_width = drm_format_info_block_width(format, 0); unsigned int bits_per_pixel = 8 / block_width; @@ -75,7 +76,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format iosys_map_set_vaddr(&dst_map, buf); iosys_map_set_vaddr(&vmap, src); - drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect, fmtcnv_state); pix8 = buf; for (y = 0; y < height; y++) { @@ -152,7 +153,8 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, const struct iosys_map *src, bool cached_reads, const struct drm_format_info *format, struct drm_rect *rect, - struct gud_set_buffer_req *req) + struct gud_set_buffer_req *req, + struct drm_format_conv_state *fmtcnv_state) { u8 compression = gdrm->compression; struct iosys_map dst; @@ -178,23 +180,23 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, */ if (format != fb->format) { if (format->format == GUD_DRM_FORMAT_R1) { - len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect); + len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect, fmtcnv_state); if (!len) return -ENOMEM; } else if (format->format == DRM_FORMAT_R8) { - drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect, fmtcnv_state); } else if (format->format == DRM_FORMAT_RGB332) { - drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, fmtcnv_state); } else if (format->format == DRM_FORMAT_RGB565) { - drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, + drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, fmtcnv_state, gud_is_big_endian()); } else if (format->format == DRM_FORMAT_RGB888) { - drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, fmtcnv_state); } else { len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect); } } else if (gud_is_big_endian() && format->cpp[0] > 1) { - drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads); + drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads, fmtcnv_state); } else if (compression && cached_reads && pitch == fb->pitches[0]) { /* can compress directly from the framebuffer */ buf = vaddr + rect->y1 * pitch; @@ -266,7 +268,8 @@ static int gud_usb_bulk(struct gud_device *gdrm, size_t len) static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb, const struct iosys_map *src, bool cached_reads, - const struct drm_format_info *format, struct drm_rect *rect) + const struct drm_format_info *format, struct drm_rect *rect, + struct drm_format_conv_state *fmtcnv_state) { struct gud_set_buffer_req req; size_t len, trlen; @@ -274,7 +277,7 @@ static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb, drm_dbg(&gdrm->drm, "Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); - ret = gud_prep_flush(gdrm, fb, src, cached_reads, format, rect, &req); + ret = gud_prep_flush(gdrm, fb, src, cached_reads, format, rect, &req, fmtcnv_state); if (ret) return ret; @@ -318,6 +321,7 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb const struct iosys_map *src, bool cached_reads, struct drm_rect *damage) { + struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; const struct drm_format_info *format; unsigned int i, lines; size_t pitch; @@ -340,7 +344,7 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb rect.y1 += i * lines; rect.y2 = min_t(u32, rect.y1 + lines, damage->y2); - ret = gud_flush_rect(gdrm, fb, src, cached_reads, format, &rect); + ret = gud_flush_rect(gdrm, fb, src, cached_reads, format, &rect, &fmtcnv_state); if (ret) { if (ret != -ENODEV && ret != -ECONNRESET && ret != -ESHUTDOWN && ret != -EPROTO) @@ -350,6 +354,8 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb break; } } + + drm_format_conv_state_release(&fmtcnv_state); } void gud_flush_work(struct work_struct *work) diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index e0174f82e353..ee0a06c50692 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -808,7 +808,8 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, struct drm_rect *rect, - u8 *buf, u8 *data_array) + u8 *buf, u8 *data_array, + struct drm_format_conv_state *fmtcnv_state) { struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); struct iosys_map dst; @@ -826,7 +827,7 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, return ret; iosys_map_set_vaddr(&dst, buf); - drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect); + drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); @@ -838,7 +839,8 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, struct drm_rect *rect, u8 *buf, - u8 *data_array) + u8 *data_array, + struct drm_format_conv_state *fmtcnv_state) { struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); unsigned int dst_pitch = drm_rect_width(rect); @@ -855,7 +857,7 @@ static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb, return ret; iosys_map_set_vaddr(&dst, buf); - drm_fb_xrgb8888_to_gray8(&dst, &dst_pitch, vmap, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); @@ -968,7 +970,8 @@ static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane, ssd130x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip, ssd130x_plane_state->buffer, - ssd130x_crtc_state->data_array); + ssd130x_crtc_state->data_array, + &shadow_plane_state->fmtcnv_state); } drm_dev_exit(idx); @@ -1002,7 +1005,8 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane, ssd132x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip, ssd130x_plane_state->buffer, - ssd130x_crtc_state->data_array); + ssd130x_crtc_state->data_array, + &shadow_plane_state->fmtcnv_state); } drm_dev_exit(idx); diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index f6408e56f786..08992636ec05 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -20,6 +20,10 @@ #define TEST_USE_DEFAULT_PITCH 0 +static unsigned char fmtcnv_state_mem[PAGE_SIZE]; +static struct drm_format_conv_state fmtcnv_state = + DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED(fmtcnv_state_mem, sizeof(fmtcnv_state_mem)); + struct convert_to_gray8_result { unsigned int dst_pitch; const u8 expected[TEST_BUF_SIZE]; @@ -630,8 +634,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, ¶ms->clip); - + drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -664,7 +667,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -697,12 +700,14 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); + drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip, + &fmtcnv_state, false); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); buf = dst.vaddr; /* restore original value of buf */ - drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true); + drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, + &fmtcnv_state, true); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size); @@ -711,7 +716,8 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB565, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB565, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); @@ -748,7 +754,7 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -757,7 +763,8 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB1555, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB1555, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); @@ -794,7 +801,7 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -803,7 +810,8 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB1555, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB1555, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); @@ -840,7 +848,7 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -849,7 +857,8 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGBA5551, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGBA5551, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); @@ -890,7 +899,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); buf = dst.vaddr; /* restore original value of buf */ @@ -898,7 +907,8 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB888, &src, &fb, ¶ms->clip, + &fmtcnv_state); KUNIT_EXPECT_FALSE(test, blit_result); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -933,7 +943,7 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -942,7 +952,8 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB8888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB8888, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); @@ -979,7 +990,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -989,7 +1000,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) int blit_result = 0; blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB2101010, &src, &fb, - ¶ms->clip); + ¶ms->clip, &fmtcnv_state); KUNIT_EXPECT_FALSE(test, blit_result); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -1024,7 +1035,7 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -1034,7 +1045,7 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) int blit_result = 0; blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB2101010, &src, &fb, - ¶ms->clip); + ¶ms->clip, &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); @@ -1071,7 +1082,7 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, ¶ms->clip); + drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -1104,7 +1115,7 @@ static void drm_test_fb_swab(struct kunit *test) const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? NULL : &result->dst_pitch; - drm_fb_swab(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); + drm_fb_swab(&dst, dst_pitch, &src, &fb, ¶ms->clip, false, &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -1114,7 +1125,7 @@ static void drm_test_fb_swab(struct kunit *test) int blit_result; blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888 | DRM_FORMAT_BIG_ENDIAN, - &src, &fb, ¶ms->clip); + &src, &fb, ¶ms->clip, &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_FALSE(test, blit_result); @@ -1123,7 +1134,8 @@ static void drm_test_fb_swab(struct kunit *test) buf = dst.vaddr; memset(buf, 0, dst_size); - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_BGRX8888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_BGRX8888, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_FALSE(test, blit_result); @@ -1137,7 +1149,8 @@ static void drm_test_fb_swab(struct kunit *test) mock_format.format |= DRM_FORMAT_BIG_ENDIAN; fb.format = &mock_format; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_FALSE(test, blit_result); @@ -1175,7 +1188,8 @@ static void drm_test_fb_xrgb8888_to_abgr8888(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ABGR8888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ABGR8888, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); @@ -1214,7 +1228,8 @@ static void drm_test_fb_xrgb8888_to_xbgr8888(struct kunit *test) int blit_result = 0; - blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XBGR8888, &src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XBGR8888, &src, &fb, ¶ms->clip, + &fmtcnv_state); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); @@ -1817,7 +1832,8 @@ static void drm_test_fb_memcpy(struct kunit *test) int blit_result; - blit_result = drm_fb_blit(dst, dst_pitches, params->format, src, &fb, ¶ms->clip); + blit_result = drm_fb_blit(dst, dst_pitches, params->format, src, &fb, ¶ms->clip, + &fmtcnv_state); KUNIT_EXPECT_FALSE(test, blit_result); for (size_t i = 0; i < fb.format->num_planes; i++) { diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index c5c34cd2edc1..4e3a152f897a 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -411,7 +411,8 @@ static void cirrus_primary_plane_helper_atomic_update(struct drm_plane *plane, unsigned int offset = drm_fb_clip_offset(pitch, format, &damage); struct iosys_map dst = IOSYS_MAP_INIT_OFFSET(&vaddr, offset); - drm_fb_blit(&dst, &pitch, format->format, shadow_plane_state->data, fb, &damage); + drm_fb_blit(&dst, &pitch, format->format, shadow_plane_state->data, fb, + &damage, &shadow_plane_state->fmtcnv_state); } drm_dev_exit(idx); diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index 4ceb68ffac4b..dd8b0a181be9 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -78,7 +78,7 @@ static inline int ili9225_command(struct mipi_dbi *dbi, u8 cmd, u16 data) } static void ili9225_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, struct drm_format_conv_state *fmtcnv_state) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; @@ -98,7 +98,7 @@ static void ili9225_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, if (!dbi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = dbidev->tx_buf; - ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap); + ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap, fmtcnv_state); if (ret) goto err_msg; } else { @@ -171,7 +171,8 @@ static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } @@ -281,7 +282,8 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, ili9225_command(dbi, ILI9225_DISPLAY_CONTROL_1, 0x1017); - ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); out_exit: drm_dev_exit(idx); diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 2d999a0facde..404c83032cec 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -817,7 +817,7 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane, iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip)); drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb, - &damage); + &damage, &shadow_plane_state->fmtcnv_state); } drm_dev_exit(idx); diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 73dd4f4289c2..8fd6758f5725 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -509,7 +509,8 @@ static void repaper_get_temperature(struct repaper_epd *epd) epd->factored_stage_time = epd->stage_time * factor10x / 10; } -static int repaper_fb_dirty(struct drm_framebuffer *fb) +static int repaper_fb_dirty(struct drm_framebuffer *fb, + struct drm_format_conv_state *fmtcnv_state) { struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); struct repaper_epd *epd = drm_to_epd(fb->dev); @@ -545,7 +546,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb) iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&vmap, dma_obj->vaddr); - drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, &vmap, fb, &clip); + drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, &vmap, fb, &clip, fmtcnv_state); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); @@ -830,13 +831,16 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane_state *state = pipe->plane.state; + struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; struct drm_rect rect; if (!pipe->crtc.state->active) return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - repaper_fb_dirty(state->fb); + repaper_fb_dirty(state->fb, &fmtcnv_state); + + drm_format_conv_state_release(&fmtcnv_state); } static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 8bdaf66044fc..4916e9b0d46a 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -609,7 +609,7 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, - fb, &damage); + fb, &damage, &shadow_plane_state->fmtcnv_state); } drm_dev_exit(idx); diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 3cf4eec16a81..7336fa1ddaed 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -64,7 +64,8 @@ static const u8 st7586_lookup[] = { 0x7, 0x4, 0x2, 0x0 }; static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_rect *clip) + struct drm_rect *clip, + struct drm_format_conv_state *fmtcnv_state) { size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1); unsigned int x, y; @@ -77,7 +78,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, iosys_map_set_vaddr(&dst_map, buf); iosys_map_set_vaddr(&vmap, vaddr); - drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, clip); + drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, clip, fmtcnv_state); src = buf; for (y = clip->y1; y < clip->y2; y++) { @@ -93,7 +94,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, } static int st7586_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *clip) + struct drm_rect *clip, struct drm_format_conv_state *fmtcnv_state) { int ret; @@ -101,7 +102,7 @@ static int st7586_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuf if (ret) return ret; - st7586_xrgb8888_to_gray332(dst, src->vaddr, fb, clip); + st7586_xrgb8888_to_gray332(dst, src->vaddr, fb, clip, fmtcnv_state); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); @@ -109,7 +110,7 @@ static int st7586_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuf } static void st7586_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, struct drm_format_conv_state *fmtcnv_state) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); struct mipi_dbi *dbi = &dbidev->dbi; @@ -121,7 +122,7 @@ static void st7586_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); - ret = st7586_buf_copy(dbidev->tx_buf, src, fb, rect); + ret = st7586_buf_copy(dbidev->tx_buf, src, fb, rect, fmtcnv_state); if (ret) goto err_msg; @@ -160,7 +161,8 @@ static void st7586_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } @@ -238,7 +240,8 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, msleep(100); - st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); out_exit: diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index 724a9baf7315..f13b34e0b752 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -74,45 +74,49 @@ void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch, const struct drm_rect *clip); void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool cached); + const struct drm_rect *clip, bool cached, + struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool swab); + const struct drm_rect *clip, struct drm_format_conv_state *state, + bool swab); void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, + struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, + struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *rect); + const struct drm_rect *clip, struct drm_format_conv_state *state); void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip); + const struct drm_rect *clip, struct drm_format_conv_state *state); size_t drm_fb_build_fourcc_list(struct drm_device *dev, const u32 *native_fourccs, size_t native_nfourccs, diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h index 816f196b3d4c..e8e0f8d39f3a 100644 --- a/include/drm/drm_mipi_dbi.h +++ b/include/drm/drm_mipi_dbi.h @@ -12,6 +12,7 @@ #include #include +struct drm_format_conv_state; struct drm_rect; struct gpio_desc; struct iosys_map; @@ -192,7 +193,8 @@ int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len); int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, const u8 *data, size_t len); int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *clip, bool swap); + struct drm_rect *clip, bool swap, + struct drm_format_conv_state *fmtcnv_state); /** * mipi_dbi_command - MIPI DCS command with optional parameter(s) From 58b184dcb3f4c52c15b6ff4fa2fa0d69d1e1313f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:33 +0200 Subject: [PATCH 0479/7721] drm/ofdrm: Preallocate format-conversion buffer in atomic_check Preallocate the format-conversion state's storage in the plane's atomic_check function if a format conversion is necessary. Allows the update to fail if no memory is available. Avoids the same allocation within atomic_update, which may not fail. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-5-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 404c83032cec..05a72473cfc6 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -758,7 +758,11 @@ static const uint64_t ofdrm_primary_plane_format_modifiers[] = { static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *new_state) { + struct drm_device *dev = plane->dev; + struct ofdrm_device *odev = ofdrm_device_of_dev(dev); struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_shadow_plane_state *new_shadow_plane_state = + to_drm_shadow_plane_state(new_plane_state); struct drm_framebuffer *new_fb = new_plane_state->fb; struct drm_crtc *new_crtc = new_plane_state->crtc; struct drm_crtc_state *new_crtc_state = NULL; @@ -777,6 +781,16 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, else if (!new_plane_state->visible) return 0; + if (new_fb->format != odev->format) { + void *buf; + + /* format conversion necessary; reserve buffer */ + buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state, + odev->pitch, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state); From e7c814d305e110d6db3f440d14490a8d0d9477d9 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:34 +0200 Subject: [PATCH 0480/7721] drm/simpledrm: Preallocate format-conversion buffer in atomic_check Preallocate the format-conversion state's storage in the plane's atomic_check function if a format conversion is necessary. Allows the update to fail if no memory is available. Avoids the same allocation within atomic_update, which may not fail. Also inline drm_plane_helper_atomic_check() into the driver and thus return early for invisible planes. Avoids memory allocation entirely in this case. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-6-tzimmermann@suse.de --- drivers/gpu/drm/tiny/simpledrm.c | 41 +++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 4916e9b0d46a..22a827102dfd 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -579,6 +580,44 @@ static const uint64_t simpledrm_primary_plane_format_modifiers[] = { DRM_FORMAT_MOD_INVALID }; +static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_shadow_plane_state *new_shadow_plane_state = + to_drm_shadow_plane_state(new_plane_state); + struct drm_framebuffer *new_fb = new_plane_state->fb; + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + struct drm_device *dev = plane->dev; + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); + int ret; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; + + if (new_fb->format != sdev->format) { + void *buf; + + /* format conversion necessary; reserve buffer */ + buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state, + sdev->pitch, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + return 0; +} + static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -635,7 +674,7 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, - .atomic_check = drm_plane_helper_atomic_check, + .atomic_check = simpledrm_primary_plane_helper_atomic_check, .atomic_update = simpledrm_primary_plane_helper_atomic_update, .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, }; From c669875041d038e91fa99766a07ec2d8bd6dcf6a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 9 Oct 2023 16:06:36 +0200 Subject: [PATCH 0481/7721] drm/ssd130x: Preallocate format-conversion buffer in atomic_check Preallocate the format-conversion state's storage in the plane's atomic_check function if a format conversion is necessary. Allows the update to fail if no memory is available. Avoids the same allocation within atomic_update, which may not fail. v6: * update patch for ssd132x support Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231009141018.11291-8-tzimmermann@suse.de --- drivers/gpu/drm/solomon/ssd130x.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index ee0a06c50692..bef293922b98 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -873,6 +873,7 @@ static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane, struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state); + struct drm_shadow_plane_state *shadow_plane_state = &ssd130x_state->base; struct drm_crtc *crtc = plane_state->crtc; struct drm_crtc_state *crtc_state = NULL; const struct drm_format_info *fi; @@ -897,6 +898,16 @@ static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane, pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + if (plane_state->fb->format != fi) { + void *buf; + + /* format conversion necessary; reserve buffer */ + buf = drm_format_conv_state_reserve(&shadow_plane_state->fmtcnv_state, + pitch, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL); if (!ssd130x_state->buffer) return -ENOMEM; @@ -911,6 +922,7 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane, struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state); + struct drm_shadow_plane_state *shadow_plane_state = &ssd130x_state->base; struct drm_crtc *crtc = plane_state->crtc; struct drm_crtc_state *crtc_state = NULL; const struct drm_format_info *fi; @@ -935,6 +947,16 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane, pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + if (plane_state->fb->format != fi) { + void *buf; + + /* format conversion necessary; reserve buffer */ + buf = drm_format_conv_state_reserve(&shadow_plane_state->fmtcnv_state, + pitch, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL); if (!ssd130x_state->buffer) return -ENOMEM; From 78dfe8a0ef779159a6ff51231d71b3a65c55ccf5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Nov 2023 11:35:42 +0100 Subject: [PATCH 0482/7721] drm: Remove struct drm_flip_task from DRM interfaces Contain struct drm_flip_task and its helper functions drm_flip_work_allocate_task() and drm_flip_work_queue_task() within drm_flip_work.c There are no callers outside of the flip-work code. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231101103618.23806-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_flip_work.c | 27 +++++++-------------------- include/drm/drm_flip_work.h | 18 ++---------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c index 060b753881a2..8c6090a90d56 100644 --- a/drivers/gpu/drm/drm_flip_work.c +++ b/drivers/gpu/drm/drm_flip_work.c @@ -27,14 +27,12 @@ #include #include -/** - * drm_flip_work_allocate_task - allocate a flip-work task - * @data: data associated to the task - * @flags: allocator flags - * - * Allocate a drm_flip_task object and attach private data to it. - */ -struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) +struct drm_flip_task { + struct list_head node; + void *data; +}; + +static struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) { struct drm_flip_task *task; @@ -44,18 +42,8 @@ struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) return task; } -EXPORT_SYMBOL(drm_flip_work_allocate_task); -/** - * drm_flip_work_queue_task - queue a specific task - * @work: the flip-work - * @task: the task to handle - * - * Queues task, that will later be run (passed back to drm_flip_func_t - * func) on a work queue after drm_flip_work_commit() is called. - */ -void drm_flip_work_queue_task(struct drm_flip_work *work, - struct drm_flip_task *task) +static void drm_flip_work_queue_task(struct drm_flip_work *work, struct drm_flip_task *task) { unsigned long flags; @@ -63,7 +51,6 @@ void drm_flip_work_queue_task(struct drm_flip_work *work, list_add_tail(&task->node, &work->queued); spin_unlock_irqrestore(&work->lock, flags); } -EXPORT_SYMBOL(drm_flip_work_queue_task); /** * drm_flip_work_queue - queue work diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h index 21c3d512d25c..6be4ba6f3514 100644 --- a/include/drm/drm_flip_work.h +++ b/include/drm/drm_flip_work.h @@ -33,9 +33,8 @@ * * Util to queue up work to run from work-queue context after flip/vblank. * Typically this can be used to defer unref of framebuffer's, cursor - * bo's, etc until after vblank. The APIs are all thread-safe. - * Moreover, drm_flip_work_queue_task and drm_flip_work_queue can be called - * in atomic context. + * bo's, etc until after vblank. The APIs are all thread-safe. Moreover, + * drm_flip_work_queue can be called in atomic context. */ struct drm_flip_work; @@ -51,16 +50,6 @@ struct drm_flip_work; */ typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val); -/** - * struct drm_flip_task - flip work task - * @node: list entry element - * @data: data to pass to &drm_flip_work.func - */ -struct drm_flip_task { - struct list_head node; - void *data; -}; - /** * struct drm_flip_work - flip work queue * @name: debug name @@ -79,9 +68,6 @@ struct drm_flip_work { spinlock_t lock; }; -struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags); -void drm_flip_work_queue_task(struct drm_flip_work *work, - struct drm_flip_task *task); void drm_flip_work_queue(struct drm_flip_work *work, void *val); void drm_flip_work_commit(struct drm_flip_work *work, struct workqueue_struct *wq); From ce64630dca7026ed9dc880dcd005977f662c99fe Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Nov 2023 11:35:43 +0100 Subject: [PATCH 0483/7721] drm: Fix flip-task docs Say that drm_flip_work_commit() is safe to call in atomic context. Turn the name into a hyperlink. Suggested-by: Daniel Vetter Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231101103618.23806-3-tzimmermann@suse.de --- include/drm/drm_flip_work.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h index 6be4ba6f3514..1eef3283a109 100644 --- a/include/drm/drm_flip_work.h +++ b/include/drm/drm_flip_work.h @@ -31,10 +31,10 @@ /** * DOC: flip utils * - * Util to queue up work to run from work-queue context after flip/vblank. + * Utility to queue up work to run from work-queue context after flip/vblank. * Typically this can be used to defer unref of framebuffer's, cursor - * bo's, etc until after vblank. The APIs are all thread-safe. Moreover, - * drm_flip_work_queue can be called in atomic context. + * bo's, etc until after vblank. The APIs are all thread-safe. Moreover, + * drm_flip_work_commit() can be called in atomic context. */ struct drm_flip_work; From 0c2287c9652150cf659408b66c1789830822132f Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 10 Nov 2023 15:40:10 +0530 Subject: [PATCH 0484/7721] drm/display/dp: Add helper function to get DSC bpp precision Add helper to get the DSC bits_per_pixel precision for the DP sink. Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-2-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 27 +++++++++++++++++++++++++ include/drm/display/drm_dp_helper.h | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 64c151e4f78c..ff8d67d0e9dc 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2325,6 +2325,33 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, } EXPORT_SYMBOL(drm_dp_read_desc); +/** + * drm_dp_dsc_sink_bpp_incr() - Get bits per pixel increment + * @dsc_dpcd: DSC capabilities from DPCD + * + * Returns the bpp precision supported by the DP sink. + */ +u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) +{ + u8 bpp_increment_dpcd = dsc_dpcd[DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT]; + + switch (bpp_increment_dpcd) { + case DP_DSC_BITS_PER_PIXEL_1_16: + return 16; + case DP_DSC_BITS_PER_PIXEL_1_8: + return 8; + case DP_DSC_BITS_PER_PIXEL_1_4: + return 4; + case DP_DSC_BITS_PER_PIXEL_1_2: + return 2; + case DP_DSC_BITS_PER_PIXEL_1_1: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_dsc_sink_bpp_incr); + /** * drm_dp_dsc_sink_max_slice_count() - Get the max slice count * supported by the DSC sink. diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 3c59f64d4a69..194715083399 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -164,6 +164,7 @@ drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } /* DP/eDP DSC support */ +u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], bool is_edp); u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); From 59a266f068b4f9f54c58e4066ac9ee9023ad9232 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 10 Nov 2023 15:40:11 +0530 Subject: [PATCH 0485/7721] drm/i915/display: Store compressed bpp in U6.4 format DSC parameter bits_per_pixel is stored in U6.4 format. The 4 bits represent the fractional part of the bpp. Currently we use compressed_bpp member of dsc structure to store only the integral part of the bits_per_pixel. To store the full bits_per_pixel along with the fractional part, compressed_bpp is changed to store bpp in U6.4 formats. Intergral part is retrieved by simply right shifting the member compressed_bpp by 4. v2: -Use to_bpp_int, to_bpp_frac_dec, to_bpp_x16 helpers while dealing with compressed bpp. (Suraj) -Fix comment styling. (Suraj) v3: -Add separate file for 6.4 fixed point helper(Jani, Nikula) -Add comment for magic values(Suraj) v4: -Fix checkpatch warnings caused by renaming(Suraj) v5: -Rebase. -Use existing helpers for conversion of bpp_int to bpp_x16 and vice versa. Signed-off-by: Ankit Nautiyal Signed-off-by: Mitul Golani Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-3-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 10 +++---- drivers/gpu/drm/i915/display/intel_audio.c | 2 +- drivers/gpu/drm/i915/display/intel_bios.c | 4 +-- drivers/gpu/drm/i915/display/intel_cdclk.c | 5 ++-- drivers/gpu/drm/i915/display/intel_display.c | 2 +- .../drm/i915/display/intel_display_types.h | 3 ++- drivers/gpu/drm/i915/display/intel_dp.c | 27 ++++++++++--------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/display/intel_link_bw.c | 2 +- drivers/gpu/drm/i915/display/intel_vdsc.c | 4 +-- 10 files changed, 33 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index c4585e445198..481fcb650850 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -330,7 +330,7 @@ static int afe_clk(struct intel_encoder *encoder, int bpp; if (crtc_state->dsc.compression_enable) - bpp = crtc_state->dsc.compressed_bpp; + bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); else bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); @@ -860,7 +860,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, * compressed and non-compressed bpp. */ if (crtc_state->dsc.compression_enable) { - mul = crtc_state->dsc.compressed_bpp; + mul = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); } @@ -884,7 +884,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, int bpp, line_time_us, byte_clk_period_ns; if (crtc_state->dsc.compression_enable) - bpp = crtc_state->dsc.compressed_bpp; + bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); else bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); @@ -1451,8 +1451,8 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - if (pipe_config->dsc.compressed_bpp) { - int div = pipe_config->dsc.compressed_bpp; + if (pipe_config->dsc.compressed_bpp_x16) { + int div = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); adjusted_mode->crtc_htotal = diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 19605264a35c..aa93ccd6c2aa 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -528,7 +528,7 @@ static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, h_active = crtc_state->hw.adjusted_mode.crtc_hdisplay; h_total = crtc_state->hw.adjusted_mode.crtc_htotal; pixel_clk = crtc_state->hw.adjusted_mode.crtc_clock; - vdsc_bpp = crtc_state->dsc.compressed_bpp; + vdsc_bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); cdclk = i915->display.cdclk.hw.cdclk; /* fec= 0.972261, using rounding multiplier of 1000000 */ fec_coeff = 972261; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 719fb550342b..2fd72b2fd109 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3414,8 +3414,8 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, crtc_state->pipe_bpp = bpc * 3; - crtc_state->dsc.compressed_bpp = min(crtc_state->pipe_bpp, - VBT_DSC_MAX_BPP(dsc->max_bpp)); + crtc_state->dsc.compressed_bpp_x16 = to_bpp_x16(min(crtc_state->pipe_bpp, + VBT_DSC_MAX_BPP(dsc->max_bpp))); /* * FIXME: This is ugly, and slice count should take DSC engine diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c4839c67cb0f..b93d1ad7936d 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2598,8 +2598,9 @@ static int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits */ int bigjoiner_interface_bits = DISPLAY_VER(i915) > 13 ? 36 : 24; - int min_cdclk_bj = (crtc_state->dsc.compressed_bpp * pixel_clock) / - (2 * bigjoiner_interface_bits); + int min_cdclk_bj = + (to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) * + pixel_clock) / (2 * bigjoiner_interface_bits); min_cdclk = max(min_cdclk, min_cdclk_bj); } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3effafcbb411..b4a8e3087e50 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5434,7 +5434,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(dsc.compression_enable); PIPE_CONF_CHECK_I(dsc.dsc_split); - PIPE_CONF_CHECK_I(dsc.compressed_bpp); + PIPE_CONF_CHECK_I(dsc.compressed_bpp_x16); PIPE_CONF_CHECK_BOOL(splitter.enable); PIPE_CONF_CHECK_I(splitter.link_count); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index d2a15817dee2..779b18fc6c39 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1363,7 +1363,8 @@ struct intel_crtc_state { struct { bool compression_enable; bool dsc_split; - u16 compressed_bpp; + /* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */ + u16 compressed_bpp_x16; u8 slice_count; struct drm_dsc_config config; } dsc; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 03e520c43248..e341e4b155c9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1885,7 +1885,8 @@ icl_dsc_compute_link_config(struct intel_dp *intel_dp, valid_dsc_bpp[i], timeslots); if (ret == 0) { - pipe_config->dsc.compressed_bpp = valid_dsc_bpp[i]; + pipe_config->dsc.compressed_bpp_x16 = + to_bpp_x16(valid_dsc_bpp[i]); return 0; } } @@ -1923,7 +1924,8 @@ xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, compressed_bpp, timeslots); if (ret == 0) { - pipe_config->dsc.compressed_bpp = compressed_bpp; + pipe_config->dsc.compressed_bpp_x16 = + to_bpp_x16(compressed_bpp); return 0; } } @@ -2120,7 +2122,8 @@ static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, /* Compressed BPP should be less than the Input DSC bpp */ dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); - pipe_config->dsc.compressed_bpp = max(dsc_min_bpp, dsc_max_bpp); + pipe_config->dsc.compressed_bpp_x16 = + to_bpp_x16(max(dsc_min_bpp, dsc_max_bpp)); pipe_config->pipe_bpp = pipe_bpp; @@ -2209,18 +2212,18 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { drm_dbg_kms(&dev_priv->drm, - "Cannot compute valid DSC parameters for Input Bpp = %d " - "Compressed BPP = %d\n", + "Cannot compute valid DSC parameters for Input Bpp = %d" + "Compressed BPP = " BPP_X16_FMT "\n", pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp); + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16)); return ret; } pipe_config->dsc.compression_enable = true; drm_dbg_kms(&dev_priv->drm, "DP DSC computed with Input Bpp = %d " - "Compressed Bpp = %d Slice Count = %d\n", + "Compressed Bpp = " BPP_X16_FMT " Slice Count = %d\n", pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp, + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16), pipe_config->dsc.slice_count); return 0; @@ -2393,15 +2396,15 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, if (pipe_config->dsc.compression_enable) { drm_dbg_kms(&i915->drm, - "DP lane count %d clock %d Input bpp %d Compressed bpp %d\n", + "DP lane count %d clock %d Input bpp %d Compressed bpp " BPP_X16_FMT "\n", pipe_config->lane_count, pipe_config->port_clock, pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp); + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16)); drm_dbg_kms(&i915->drm, "DP link rate required %i available %i\n", intel_dp_link_required(adjusted_mode->crtc_clock, - pipe_config->dsc.compressed_bpp), + to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)), intel_dp_max_data_rate(pipe_config->port_clock, pipe_config->lane_count)); } else { @@ -2863,7 +2866,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, drm_dp_enhanced_frame_cap(intel_dp->dpcd); if (pipe_config->dsc.compression_enable) - link_bpp = pipe_config->dsc.compressed_bpp; + link_bpp = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); else link_bpp = intel_dp_output_bpp(pipe_config->output_format, pipe_config->pipe_bpp); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b943dbf394a2..4db902dc6eb1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -228,7 +228,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, if (!dsc) crtc_state->pipe_bpp = bpp; else - crtc_state->dsc.compressed_bpp = bpp; + crtc_state->dsc.compressed_bpp_x16 = to_bpp_x16(bpp); drm_dbg_kms(&i915->drm, "Got %d slots for pipe bpp %d dsc %d\n", slots, bpp, dsc); } diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index 390db5c0c24a..02a0af2aa5ba 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -70,7 +70,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, return PTR_ERR(crtc_state); if (crtc_state->dsc.compression_enable) - link_bpp = crtc_state->dsc.compressed_bpp; + link_bpp = crtc_state->dsc.compressed_bpp_x16; else /* * TODO: for YUV420 the actual link bpp is only half diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 6757dbae9ee5..3a1ed574edbb 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -248,7 +248,7 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_dsc_config *vdsc_cfg = &pipe_config->dsc.config; - u16 compressed_bpp = pipe_config->dsc.compressed_bpp; + u16 compressed_bpp = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); int err; int ret; @@ -874,7 +874,7 @@ static void intel_dsc_get_pps_config(struct intel_crtc_state *crtc_state) if (vdsc_cfg->native_420) vdsc_cfg->bits_per_pixel >>= 1; - crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + crtc_state->dsc.compressed_bpp_x16 = vdsc_cfg->bits_per_pixel; /* PPS 2 */ pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 2); From 87c8812f4b009b5a5d38b1560b45d4a1cc4b24c5 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 10 Nov 2023 15:40:12 +0530 Subject: [PATCH 0486/7721] drm/i915/display: Consider fractional vdsc bpp while computing m_n values MTL+ supports fractional compressed bits_per_pixel, with precision of 1/16. This compressed bpp is stored in U6.4 format. Accommodate this precision while computing m_n values. v1: Replace the computation of 'data_clock' with 'data_clock = DIV_ROUND_UP(data_clock, 16).' (Sui Jingfeng). v2: Rebase and pass bits_per_pixel in U6.4 format. Signed-off-by: Ankit Nautiyal Signed-off-by: Mitul Golani Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-4-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- drivers/gpu/drm/i915/display/intel_dp.c | 16 ++++++++-------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 14 +++++++------- drivers/gpu/drm/i915/display/intel_fdi.c | 3 ++- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b4a8e3087e50..125903007a29 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2415,12 +2415,12 @@ add_bw_alloc_overhead(int link_clock, int bw_overhead, } void -intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, +intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, int pixel_clock, int link_clock, int bw_overhead, struct intel_link_m_n *m_n) { - u32 data_clock = bits_per_pixel * pixel_clock; + u32 data_clock = DIV_ROUND_UP(bits_per_pixel_x16 * pixel_clock, 16); u32 data_m; u32 data_n; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index e341e4b155c9..d4118d25f39b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2688,7 +2688,7 @@ static bool can_enable_drrs(struct intel_connector *connector, static void intel_dp_drrs_compute_config(struct intel_connector *connector, struct intel_crtc_state *pipe_config, - int link_bpp) + int link_bpp_x16) { struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *downclock_mode = @@ -2713,7 +2713,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, if (pipe_config->splitter.enable) pixel_clock /= pipe_config->splitter.link_count; - intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, + intel_link_compute_m_n(link_bpp_x16, pipe_config->lane_count, pixel_clock, pipe_config->port_clock, intel_dp_bw_fec_overhead(pipe_config->fec_enable), &pipe_config->dp_m2_n2); @@ -2817,7 +2817,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); const struct drm_display_mode *fixed_mode; struct intel_connector *connector = intel_dp->attached_connector; - int ret = 0, link_bpp; + int ret = 0, link_bpp_x16; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A) pipe_config->has_pch_encoder = true; @@ -2866,10 +2866,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, drm_dp_enhanced_frame_cap(intel_dp->dpcd); if (pipe_config->dsc.compression_enable) - link_bpp = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); + link_bpp_x16 = pipe_config->dsc.compressed_bpp_x16; else - link_bpp = intel_dp_output_bpp(pipe_config->output_format, - pipe_config->pipe_bpp); + link_bpp_x16 = to_bpp_x16(intel_dp_output_bpp(pipe_config->output_format, + pipe_config->pipe_bpp)); if (intel_dp->mso_link_count) { int n = intel_dp->mso_link_count; @@ -2893,7 +2893,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_audio_compute_config(encoder, pipe_config, conn_state); - intel_link_compute_m_n(link_bpp, + intel_link_compute_m_n(link_bpp_x16, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, @@ -2909,7 +2909,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_vrr_compute_config(pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state); - intel_dp_drrs_compute_config(connector, pipe_config, link_bpp); + intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4db902dc6eb1..0cb9405f59ea 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -71,7 +71,7 @@ static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, const struct intel_connector *connector, - bool ssc, bool dsc, int bpp) + bool ssc, bool dsc, int bpp_x16) { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; @@ -95,7 +95,7 @@ static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, overhead = drm_dp_bw_overhead(crtc_state->lane_count, adjusted_mode->hdisplay, dsc_slice_count, - to_bpp_x16(bpp), + bpp_x16, flags); /* @@ -108,16 +108,16 @@ static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, const struct intel_connector *connector, bool ssc, bool dsc, - int bpp, + int bpp_x16, struct intel_link_m_n *m_n) { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int overhead = intel_dp_mst_bw_overhead(crtc_state, connector, - ssc, dsc, bpp); + ssc, dsc, bpp_x16); - intel_link_compute_m_n(bpp, crtc_state->lane_count, + intel_link_compute_m_n(bpp_x16, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, overhead, @@ -181,9 +181,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, link_bpp = dsc ? bpp : intel_dp_output_bpp(crtc_state->output_format, bpp); - intel_dp_mst_compute_m_n(crtc_state, connector, false, dsc, link_bpp, + intel_dp_mst_compute_m_n(crtc_state, connector, false, dsc, to_bpp_x16(link_bpp), &crtc_state->dp_m_n); - intel_dp_mst_compute_m_n(crtc_state, connector, true, dsc, link_bpp, + intel_dp_mst_compute_m_n(crtc_state, connector, true, dsc, to_bpp_x16(link_bpp), &remote_m_n); /* diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 1d87fbc1e813..295a0f24ebbf 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -339,7 +339,8 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc, pipe_config->fdi_lanes = lane; - intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, + intel_link_compute_m_n(to_bpp_x16(pipe_config->pipe_bpp), + lane, fdi_dotclock, link_bw, intel_dp_bw_fec_overhead(false), &pipe_config->fdi_m_n); From 08fcb5ab7b32848b1852145baf89007a3e3c28b9 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 10 Nov 2023 15:40:13 +0530 Subject: [PATCH 0487/7721] drm/i915/audio: Consider fractional vdsc bpp while computing tu_data MTL+ supports fractional compressed bits_per_pixel, with precision of 1/16. This compressed bpp is stored in U6.4 format. Accommodate the precision during calculation of transfer unit data for hblank_early calculation. v2: -Fix tu_data calculation while dealing with U6.4 format. (Stan) v3: -Use BPP_X16_FMT to print vdsc bpp. Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-5-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index aa93ccd6c2aa..8796d90c46a6 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -521,25 +521,25 @@ static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, unsigned int link_clks_available, link_clks_required; unsigned int tu_data, tu_line, link_clks_active; unsigned int h_active, h_total, hblank_delta, pixel_clk; - unsigned int fec_coeff, cdclk, vdsc_bpp; + unsigned int fec_coeff, cdclk, vdsc_bppx16; unsigned int link_clk, lanes; unsigned int hblank_rise; h_active = crtc_state->hw.adjusted_mode.crtc_hdisplay; h_total = crtc_state->hw.adjusted_mode.crtc_htotal; pixel_clk = crtc_state->hw.adjusted_mode.crtc_clock; - vdsc_bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); + vdsc_bppx16 = crtc_state->dsc.compressed_bpp_x16; cdclk = i915->display.cdclk.hw.cdclk; /* fec= 0.972261, using rounding multiplier of 1000000 */ fec_coeff = 972261; link_clk = crtc_state->port_clock; lanes = crtc_state->lane_count; - drm_dbg_kms(&i915->drm, "h_active = %u link_clk = %u :" - "lanes = %u vdsc_bpp = %u cdclk = %u\n", - h_active, link_clk, lanes, vdsc_bpp, cdclk); + drm_dbg_kms(&i915->drm, + "h_active = %u link_clk = %u : lanes = %u vdsc_bpp = " BPP_X16_FMT " cdclk = %u\n", + h_active, link_clk, lanes, BPP_X16_ARGS(vdsc_bppx16), cdclk); - if (WARN_ON(!link_clk || !pixel_clk || !lanes || !vdsc_bpp || !cdclk)) + if (WARN_ON(!link_clk || !pixel_clk || !lanes || !vdsc_bppx16 || !cdclk)) return 0; link_clks_available = (h_total - h_active) * link_clk / pixel_clk - 28; @@ -551,8 +551,8 @@ static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, hblank_delta = DIV64_U64_ROUND_UP(mul_u32_u32(5 * (link_clk + cdclk), pixel_clk), mul_u32_u32(link_clk, cdclk)); - tu_data = div64_u64(mul_u32_u32(pixel_clk * vdsc_bpp * 8, 1000000), - mul_u32_u32(link_clk * lanes, fec_coeff)); + tu_data = div64_u64(mul_u32_u32(pixel_clk * vdsc_bppx16 * 8, 1000000), + mul_u32_u32(link_clk * lanes * 16, fec_coeff)); tu_line = div64_u64(h_active * mul_u32_u32(link_clk, fec_coeff), mul_u32_u32(64 * pixel_clk, 1000000)); link_clks_active = (tu_line - 1) * 64 + tu_data; From 2df50cb46a4c64107e7a70e8b00e7ffc0806b5a3 Mon Sep 17 00:00:00 2001 From: Vandita Kulkarni Date: Fri, 10 Nov 2023 15:40:14 +0530 Subject: [PATCH 0488/7721] drm/i915/dsc/mtl: Add support for fractional bpp Consider the fractional bpp while reading the qp values. v2: Use helpers for fractional, integral bits of bits_per_pixel. (Suraj) Signed-off-by: Vandita Kulkarni Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-6-ankit.k.nautiyal@intel.com --- .../gpu/drm/i915/display/intel_qp_tables.c | 3 --- drivers/gpu/drm/i915/display/intel_vdsc.c | 25 +++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_qp_tables.c b/drivers/gpu/drm/i915/display/intel_qp_tables.c index 543cdc46aa1d..600c815e37e4 100644 --- a/drivers/gpu/drm/i915/display/intel_qp_tables.c +++ b/drivers/gpu/drm/i915/display/intel_qp_tables.c @@ -34,9 +34,6 @@ * These qp tables are as per the C model * and it has the rows pointing to bpps which increment * in steps of 0.5 - * We do not support fractional bpps as of today, - * hence we would skip the fractional bpps during - * our references for qp calclulations. */ static const u8 rc_range_minqp444_8bpc[DSC_NUM_BUF_RANGES][RC_RANGE_QP444_8BPC_MAX_NUM_BPP] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 3a1ed574edbb..5f2fb702e367 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -77,8 +77,8 @@ intel_vdsc_set_min_max_qp(struct drm_dsc_config *vdsc_cfg, int buf, static void calculate_rc_params(struct drm_dsc_config *vdsc_cfg) { + int bpp = to_bpp_int(vdsc_cfg->bits_per_pixel); int bpc = vdsc_cfg->bits_per_component; - int bpp = vdsc_cfg->bits_per_pixel >> 4; int qp_bpc_modifier = (bpc - 8) * 2; int uncompressed_bpg_rate; int first_line_bpg_offset; @@ -148,7 +148,13 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) static const s8 ofs_und8[] = { 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 }; - + /* + * For 420 format since bits_per_pixel (bpp) is set to target bpp * 2, + * QP table values for target bpp 4.0 to 4.4375 (rounded to 4.0) are + * actually for bpp 8 to 8.875 (rounded to 4.0 * 2 i.e 8). + * Similarly values for target bpp 4.5 to 4.8375 (rounded to 4.5) + * are for bpp 9 to 9.875 (rounded to 4.5 * 2 i.e 9), and so on. + */ bpp_i = bpp - 8; for (buf_i = 0; buf_i < DSC_NUM_BUF_RANGES; buf_i++) { u8 range_bpg_offset; @@ -178,6 +184,9 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) range_bpg_offset & DSC_RANGE_BPG_OFFSET_MASK; } } else { + /* fractional bpp part * 10000 (for precision up to 4 decimal places) */ + int fractional_bits = to_bpp_frac(vdsc_cfg->bits_per_pixel); + static const s8 ofs_und6[] = { 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 }; @@ -191,7 +200,14 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 }; - bpp_i = (2 * (bpp - 6)); + /* + * QP table rows have values in increment of 0.5. + * So 6.0 bpp to 6.4375 will have index 0, 6.5 to 6.9375 will have index 1, + * and so on. + * 0.5 fractional part with 4 decimal precision becomes 5000 + */ + bpp_i = ((bpp - 6) + (fractional_bits < 5000 ? 0 : 1)); + for (buf_i = 0; buf_i < DSC_NUM_BUF_RANGES; buf_i++) { u8 range_bpg_offset; @@ -279,8 +295,7 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) /* Gen 11 does not support VBR */ vdsc_cfg->vbr_enable = false; - /* Gen 11 only supports integral values of bpp */ - vdsc_cfg->bits_per_pixel = compressed_bpp << 4; + vdsc_cfg->bits_per_pixel = pipe_config->dsc.compressed_bpp_x16; /* * According to DSC 1.2 specs in Section 4.1 if native_420 is set From dc59990efda0bc785a3c26c41880cc513f9ed09f Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 10 Nov 2023 15:40:15 +0530 Subject: [PATCH 0489/7721] drm/i915/dp: Iterate over output bpp with fractional step size This patch adds support to iterate over compressed output bpp as per the fractional step, supported by DP sink. v2: -Avoid ending up with compressed bpp, same as pipe bpp. (Stan) Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-7-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 43 +++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d4118d25f39b..23686c3913e7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1737,15 +1737,15 @@ static bool intel_dp_dsc_supports_format(const struct intel_connector *connector return drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, sink_dsc_format); } -static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, +static bool is_bw_sufficient_for_dsc_config(u16 compressed_bppx16, u32 link_clock, u32 lane_count, u32 mode_clock, enum intel_output_format output_format, int timeslots) { u32 available_bw, required_bw; - available_bw = (link_clock * lane_count * timeslots) / 8; - required_bw = compressed_bpp * (intel_dp_mode_to_fec_clock(mode_clock)); + available_bw = (link_clock * lane_count * timeslots * 16) / 8; + required_bw = compressed_bppx16 * (intel_dp_mode_to_fec_clock(mode_clock)); return available_bw > required_bw; } @@ -1753,7 +1753,7 @@ static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, static int dsc_compute_link_config(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, struct link_config_limits *limits, - u16 compressed_bpp, + u16 compressed_bppx16, int timeslots) { const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -1768,8 +1768,8 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp, for (lane_count = limits->min_lane_count; lane_count <= limits->max_lane_count; lane_count <<= 1) { - if (!is_bw_sufficient_for_dsc_config(compressed_bpp, link_rate, lane_count, - adjusted_mode->clock, + if (!is_bw_sufficient_for_dsc_config(compressed_bppx16, link_rate, + lane_count, adjusted_mode->clock, pipe_config->output_format, timeslots)) continue; @@ -1882,7 +1882,7 @@ icl_dsc_compute_link_config(struct intel_dp *intel_dp, ret = dsc_compute_link_config(intel_dp, pipe_config, limits, - valid_dsc_bpp[i], + valid_dsc_bpp[i] << 4, timeslots); if (ret == 0) { pipe_config->dsc.compressed_bpp_x16 = @@ -1902,6 +1902,7 @@ icl_dsc_compute_link_config(struct intel_dp *intel_dp, */ static int xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, + const struct intel_connector *connector, struct intel_crtc_state *pipe_config, struct link_config_limits *limits, int dsc_max_bpp, @@ -1909,23 +1910,31 @@ xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, int pipe_bpp, int timeslots) { - u16 compressed_bpp; + u8 bppx16_incr = drm_dp_dsc_sink_bpp_incr(connector->dp.dsc_dpcd); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u16 compressed_bppx16; + u8 bppx16_step; int ret; - /* Compressed BPP should be less than the Input DSC bpp */ - dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + if (DISPLAY_VER(i915) < 14 || bppx16_incr <= 1) + bppx16_step = 16; + else + bppx16_step = 16 / bppx16_incr; - for (compressed_bpp = dsc_max_bpp; - compressed_bpp >= dsc_min_bpp; - compressed_bpp--) { + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp << 4, (pipe_bpp << 4) - bppx16_step); + dsc_min_bpp = dsc_min_bpp << 4; + + for (compressed_bppx16 = dsc_max_bpp; + compressed_bppx16 >= dsc_min_bpp; + compressed_bppx16 -= bppx16_step) { ret = dsc_compute_link_config(intel_dp, pipe_config, limits, - compressed_bpp, + compressed_bppx16, timeslots); if (ret == 0) { - pipe_config->dsc.compressed_bpp_x16 = - to_bpp_x16(compressed_bpp); + pipe_config->dsc.compressed_bpp_x16 = compressed_bppx16; return 0; } } @@ -1963,7 +1972,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); if (DISPLAY_VER(i915) >= 13) - return xelpd_dsc_compute_link_config(intel_dp, pipe_config, limits, + return xelpd_dsc_compute_link_config(intel_dp, connector, pipe_config, limits, dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); return icl_dsc_compute_link_config(intel_dp, pipe_config, limits, dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); From 680c1e31a59b223d677a22b508017d26b71a636a Mon Sep 17 00:00:00 2001 From: Swati Sharma Date: Fri, 10 Nov 2023 15:40:16 +0530 Subject: [PATCH 0490/7721] drm/i915/dsc: Add debugfs entry to validate DSC fractional bpp DSC_Sink_BPP_Precision entry is added to i915_dsc_fec_support_show to depict sink's precision. Also, new debugfs entry is created to enforce fractional bpp. If Force_DSC_Fractional_BPP_en is set then while iterating over output bpp with fractional step size we will continue if output_bpp is computed as integer. With this approach, we will be able to validate DSC with fractional bpp. v2: Add drm_modeset_unlock to new line(Suraj) Signed-off-by: Swati Sharma Signed-off-by: Ankit Nautiyal Signed-off-by: Mitul Golani Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-8-ankit.k.nautiyal@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 84 +++++++++++++++++++ .../drm/i915/display/intel_display_types.h | 1 + 2 files changed, 85 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 42bd352f9fee..a7675a7339c3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1257,6 +1257,8 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) DP_DSC_YCbCr420_Native)), str_yes_no(drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, DP_DSC_YCbCr444))); + seq_printf(m, "DSC_Sink_BPP_Precision: %d\n", + drm_dp_dsc_sink_bpp_incr(connector->dp.dsc_dpcd)); seq_printf(m, "Force_DSC_Enable: %s\n", str_yes_no(intel_dp->force_dsc_en)); if (!intel_dp_is_edp(intel_dp)) @@ -1449,6 +1451,85 @@ static const struct file_operations i915_dsc_output_format_fops = { .write = i915_dsc_output_format_write }; +static int i915_dsc_fractional_bpp_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc; + struct intel_dp *intel_dp; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_encoder *encoder = intel_attached_encoder(intel_connector); + int ret; + + if (!encoder) + return -ENODEV; + + ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + if (ret) + return ret; + + crtc = connector->state->crtc; + if (connector->status != connector_status_connected || !crtc) { + ret = -ENODEV; + goto out; + } + + intel_dp = intel_attached_dp(intel_connector); + seq_printf(m, "Force_DSC_Fractional_BPP_Enable: %s\n", + str_yes_no(intel_dp->force_dsc_fractional_bpp_en)); + +out: + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + return ret; +} + +static ssize_t i915_dsc_fractional_bpp_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct drm_connector *connector = + ((struct seq_file *)file->private_data)->private; + struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + bool dsc_fractional_bpp_enable = false; + int ret; + + if (len == 0) + return 0; + + drm_dbg(&i915->drm, + "Copied %zu bytes from user to force fractional bpp for DSC\n", len); + + ret = kstrtobool_from_user(ubuf, len, &dsc_fractional_bpp_enable); + if (ret < 0) + return ret; + + drm_dbg(&i915->drm, "Got %s for DSC Fractional BPP Enable\n", + (dsc_fractional_bpp_enable) ? "true" : "false"); + intel_dp->force_dsc_fractional_bpp_en = dsc_fractional_bpp_enable; + + *offp += len; + + return len; +} + +static int i915_dsc_fractional_bpp_open(struct inode *inode, + struct file *file) +{ + return single_open(file, i915_dsc_fractional_bpp_show, inode->i_private); +} + +static const struct file_operations i915_dsc_fractional_bpp_fops = { + .owner = THIS_MODULE, + .open = i915_dsc_fractional_bpp_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_dsc_fractional_bpp_write +}; + /* * Returns the Current CRTC's bpc. * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc @@ -1526,6 +1607,9 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector) debugfs_create_file("i915_dsc_output_format", 0644, root, connector, &i915_dsc_output_format_fops); + + debugfs_create_file("i915_dsc_fractional_bpp", 0644, root, + connector, &i915_dsc_fractional_bpp_fops); } if (connector->connector_type == DRM_MODE_CONNECTOR_DSI || diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 779b18fc6c39..9a44350ba05d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1815,6 +1815,7 @@ struct intel_dp { /* Display stream compression testing */ bool force_dsc_en; int force_dsc_output_format; + bool force_dsc_fractional_bpp_en; int force_dsc_bpc; bool hobl_failed; From 5bbdcc86a481d82433e0905a548335bd3683eadf Mon Sep 17 00:00:00 2001 From: Swati Sharma Date: Fri, 10 Nov 2023 15:40:17 +0530 Subject: [PATCH 0491/7721] drm/i915/dsc: Allow DSC only with fractional bpp when forced from debugfs If force_dsc_fractional_bpp_en is set through debugfs allow DSC iff compressed bpp is fractional. Continue if the computed compressed bpp turns out to be a integer. v2: -Use helpers for fractional, integral bits of bits_per_pixel. (Suraj) -Fix comment (Suraj) Signed-off-by: Swati Sharma Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Reviewed-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231110101020.4067342-9-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 23686c3913e7..effb3da291e1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1928,6 +1928,9 @@ xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, for (compressed_bppx16 = dsc_max_bpp; compressed_bppx16 >= dsc_min_bpp; compressed_bppx16 -= bppx16_step) { + if (intel_dp->force_dsc_fractional_bpp_en && + !to_bpp_frac(compressed_bppx16)) + continue; ret = dsc_compute_link_config(intel_dp, pipe_config, limits, @@ -1935,6 +1938,10 @@ xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, timeslots); if (ret == 0) { pipe_config->dsc.compressed_bpp_x16 = compressed_bppx16; + if (intel_dp->force_dsc_fractional_bpp_en && + to_bpp_frac(compressed_bppx16)) + drm_dbg_kms(&i915->drm, "Forcing DSC fractional bpp\n"); + return 0; } } From cab4a9bc06fdd9d605d7df2665e64e5c48f2db84 Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Thu, 2 Nov 2023 13:00:56 +0530 Subject: [PATCH 0492/7721] tee: optee: Remove redundant custom workqueue Global system workqueue is sufficient to suffice OP-TEE bus scanning work needs. So drop redundant usage of the custom workqueue. Tested-by: Jan Kiszka Tested-by: Masahisa Kojima Signed-off-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/optee/core.c | 13 ++----------- drivers/tee/optee/optee_private.h | 2 -- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 2a258bd3b6b5..1eaa191b6ff6 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "optee_private.h" int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, @@ -110,12 +109,7 @@ int optee_open(struct tee_context *ctx, bool cap_memref_null) if (!optee->scan_bus_done) { INIT_WORK(&optee->scan_bus_work, optee_bus_scan); - optee->scan_bus_wq = create_workqueue("optee_bus_scan"); - if (!optee->scan_bus_wq) { - kfree(ctxdata); - return -ECHILD; - } - queue_work(optee->scan_bus_wq, &optee->scan_bus_work); + schedule_work(&optee->scan_bus_work); optee->scan_bus_done = true; } } @@ -158,10 +152,7 @@ void optee_release_supp(struct tee_context *ctx) struct optee *optee = tee_get_drvdata(ctx->teedev); optee_release_helper(ctx, optee_close_session_helper); - if (optee->scan_bus_wq) { - destroy_workqueue(optee->scan_bus_wq); - optee->scan_bus_wq = NULL; - } + optee_supp_release(&optee->supp); } diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 6bb5cae09688..94c0ee381894 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -178,7 +178,6 @@ struct optee_ops { * @pool: shared memory pool * @rpc_param_count: If > 0 number of RPC parameters to make room for * @scan_bus_done flag if device registation was already done. - * @scan_bus_wq workqueue to scan optee bus and register optee drivers * @scan_bus_work workq to scan optee bus and register optee drivers */ struct optee { @@ -197,7 +196,6 @@ struct optee { struct tee_shm_pool *pool; unsigned int rpc_param_count; bool scan_bus_done; - struct workqueue_struct *scan_bus_wq; struct work_struct scan_bus_work; }; From 8170b04c2c92eee52ea50b96db4c54662197e512 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Nov 2023 16:34:03 +0100 Subject: [PATCH 0493/7721] wifi: libertas: stop selecting wext Libertas no longer references the iw_handler infrastructure or wext_spy, so neither of the 'select' statements are used any more. Fixes: e86dc1ca4676 ("Libertas: cfg80211 support") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231108153409.1065286-1-arnd@kernel.org --- drivers/net/wireless/marvell/libertas/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 5bc92cb6b0fe..56156a021be3 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -3,8 +3,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on USB || SDIO || SPI depends on CFG80211 - select WIRELESS_EXT - select WEXT_SPY select LIB80211 select FW_LOADER help From 50da74e1e8b682853d1e07fc8bbe3a0774ae5e09 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Thu, 9 Nov 2023 12:38:51 +0800 Subject: [PATCH 0494/7721] wifi: rt2x00: correct wrong BBP register in RxDCOC calibration Refer to Mediatek vendor driver RxDCOC_Calibration() function, when performing gainfreeze calibration, we should write register 140 instead of 141. This fix can reduce the total calibration time from 6 seconds to 1 second. Signed-off-by: Shiji Yang Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYAP286MB0315B13B89DF57B6B27BB854BCAFA@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 70cd35d90338..84b218adbaaf 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -8711,7 +8711,7 @@ static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4); rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4); - rt2800_bbp_write(rt2x00dev, 158, 141); + rt2800_bbp_write(rt2x00dev, 158, 140); bbpreg = rt2800_bbp_read(rt2x00dev, 159); bbpreg = bbpreg & (~0x40); rt2800_bbp_write(rt2x00dev, 159, bbpreg); From af3077af7c0754ef4609a00343d2f2a483804b48 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 10 Nov 2023 15:36:02 +0800 Subject: [PATCH 0495/7721] wifi: iwlegacy: Remove the unused variable len Variable len is not effectively used, so delete it. drivers/net/wireless/intel/iwlegacy/4965-mac.c:4234:7: warning: variable 'len' set but not used. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7223 Signed-off-by: Jiapeng Chong Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110073602.16846-1-jiapeng.chong@linux.alibaba.com --- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 69276266ce6f..70e420df1643 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4231,8 +4231,6 @@ il4965_rx_handle(struct il_priv *il) fill_rx = 1; while (i != r) { - int len; - rxb = rxq->queue[i]; /* If an RXB doesn't have a Rx queue slot associated with it, @@ -4246,10 +4244,6 @@ il4965_rx_handle(struct il_priv *il) PAGE_SIZE << il->hw_params.rx_page_order, DMA_FROM_DEVICE); pkt = rxb_addr(rxb); - - len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - reclaim = il_need_reclaim(il, pkt); /* Based on type of command response or notification, From d5d717a776405107c24a41116af18c7176197210 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 10 Nov 2023 09:23:13 +0800 Subject: [PATCH 0496/7721] wifi: rtw89: pci: reset BDRAM according to chip gen Configure callback of reset BDRAM (buffer descriptor RAM) by chip gen. Refine the one of 802.11ax chip gen and drop a redundant duplicate of it in 802.11ax chip gen. Then, assign right callback of rst_bdram for HCI ops which needs to do callback according to chip gen. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 33 +++++---------------- drivers/net/wireless/realtek/rtw89/pci.h | 9 ++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 1 + 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 74828dd37715..bac9ec2236da 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -19,22 +19,18 @@ MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support"); MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support"); MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support"); -static int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev) +static int rtw89_pci_rst_bdram_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; - rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, - rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM); + rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RST_BDRAM); ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM), 1, RTW89_PCI_POLL_BDRAM_RST_CNT, false, rtwdev, R_AX_PCIE_INIT_CFG1); - if (ret) - return -EBUSY; - - return 0; + return ret; } static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, @@ -2608,7 +2604,7 @@ static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev) /* fill TRX BD indexes */ rtw89_pci_ops_reset(rtwdev); - ret = rtw89_pci_rst_bdram_pcie(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) { rtw89_warn(rtwdev, "reset bdram busy\n"); return ret; @@ -3691,22 +3687,6 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return ret; } - - -static int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev) -{ - int ret = 0; - u32 val32, sts; - - val32 = B_AX_RST_BDRAM; - rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32); - - ret = read_poll_timeout_atomic(rtw89_read32, sts, - (sts & B_AX_RST_BDRAM) == 0x0, 1, 100, - true, rtwdev, R_AX_PCIE_INIT_CFG1); - return ret; -} - static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) { u32 ret; @@ -3718,7 +3698,7 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); rtw89_pci_clr_idx_all(rtwdev); - ret = rtw89_pci_rst_bdram(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) return ret; @@ -3858,6 +3838,7 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .mac_post_init = rtw89_pci_ops_mac_post_init_ax, .clr_idx_all = rtw89_pci_clr_idx_all_ax, + .rst_bdram = rtw89_pci_rst_bdram_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); @@ -3899,7 +3880,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .clear = rtw89_pci_clear_resource, .disable_intr = rtw89_pci_disable_intr_lock, .enable_intr = rtw89_pci_enable_intr_lock, - .rst_bdram = rtw89_pci_rst_bdram_pcie, + .rst_bdram = rtw89_pci_reset_bdram, }; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 37398e416e58..e3a4a6119660 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1041,6 +1041,7 @@ struct rtw89_pci_gen_def { int (*mac_post_init)(struct rtw89_dev *rtwdev); void (*clr_idx_all)(struct rtw89_dev *rtwdev); + int (*rst_bdram)(struct rtw89_dev *rtwdev); }; struct rtw89_pci_info { @@ -1475,4 +1476,12 @@ static inline void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) gen_def->clr_idx_all(rtwdev); } +static inline int rtw89_pci_reset_bdram(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->rst_bdram(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index f3aab34a3a24..7d552b1a2d5e 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -425,5 +425,6 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_post_init = rtw89_pci_ops_mac_post_init_be, .clr_idx_all = rtw89_pci_clr_idx_all_be, + .rst_bdram = rtw89_pci_rst_bdram_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); From d720cca762ed58a5d811b40a5525066329d3641a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 10 Nov 2023 09:23:14 +0800 Subject: [PATCH 0497/7721] wifi: rtw89: pci: stop/start DMA for level 1 recovery according to chip gen Level 1 recovery is to recover TX/RX rings, so it needs PCI to stop/start DMA. But, different chip gen have different implementations, either register address/mask or function flow. So, configure callback of stop/start DMA by chip gen. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 21 +++++--- drivers/net/wireless/realtek/rtw89/pci.h | 4 ++ drivers/net/wireless/realtek/rtw89/pci_be.c | 55 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/ser.c | 6 +++ 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index bac9ec2236da..822b914cf935 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1755,7 +1755,7 @@ static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable) rtw89_write32_set(rtwdev, reg->addr, reg->mask); } -static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) { rtw89_pci_ctrl_dma_io(rtwdev, enable); rtw89_pci_ctrl_dma_trx(rtwdev, enable); @@ -3640,7 +3640,7 @@ static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev) rtw89_pci_l1ss_set(rtwdev, true); } -static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) +static int rtw89_pci_poll_io_idle_ax(struct rtw89_dev *rtwdev) { int ret = 0; u32 sts; @@ -3657,7 +3657,7 @@ static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) return ret; } -static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; @@ -3666,7 +3666,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return 0; rtw89_pci_ctrl_dma_all(rtwdev, false); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); if (ret) { val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, @@ -3677,7 +3677,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) if (val & B_AX_RX_STUCK) rtw89_mac_ctrl_hci_dma_rx(rtwdev, false); rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n", @@ -3687,7 +3687,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return ret; } -static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev) { u32 ret; @@ -3709,18 +3709,20 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step) { + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; int ret; switch (step) { case RTW89_LV1_RCVY_STEP_1: - ret = rtw89_pci_lv1rst_stop_dma(rtwdev); + ret = gen_def->lv1rst_stop_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n"); break; case RTW89_LV1_RCVY_STEP_2: - ret = rtw89_pci_lv1rst_start_dma(rtwdev); + ret = gen_def->lv1rst_start_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n"); break; @@ -3839,6 +3841,9 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .clr_idx_all = rtw89_pci_clr_idx_all_ax, .rst_bdram = rtw89_pci_rst_bdram_ax, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index e3a4a6119660..30ab9d41e0ee 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1042,6 +1042,9 @@ struct rtw89_pci_gen_def { void (*clr_idx_all)(struct rtw89_dev *rtwdev); int (*rst_bdram)(struct rtw89_dev *rtwdev); + + int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev); + int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev); }; struct rtw89_pci_info { @@ -1369,6 +1372,7 @@ u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable); void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 7d552b1a2d5e..01d72cde48a3 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -4,6 +4,7 @@ #include +#include "mac.h" #include "pci.h" #include "reg.h" @@ -420,11 +421,65 @@ static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_pci_poll_io_idle_be(struct rtw89_dev *rtwdev) +{ + u32 sts; + int ret; + + ret = read_poll_timeout_atomic(rtw89_read32, sts, + !(sts & B_BE_HAXI_MST_BUSY), + 10, 1000, false, rtwdev, + R_BE_HAXI_DMA_BUSY1); + if (ret) { + rtw89_err(rtwdev, "pci dmach busy1 0x%X\n", sts); + return ret; + } + + return 0; +} + +static int rtw89_pci_lv1rst_stop_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_ctrl_dma_all(rtwdev, false); + ret = rtw89_pci_poll_io_idle_be(rtwdev); + if (!ret) + return 0; + + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "[PCIe] poll_io_idle fail; reset hci dma trx\n"); + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + + return rtw89_pci_poll_io_idle_be(rtwdev); +} + +static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + rtw89_pci_clr_idx_all(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) + return ret; + + rtw89_pci_ctrl_dma_all(rtwdev, true); + return 0; +} + const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, .mac_post_init = rtw89_pci_ops_mac_post_init_be, .clr_idx_all = rtw89_pci_clr_idx_all_be, .rst_bdram = rtw89_pci_rst_bdram_be, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index c1644353053f..1e4a79a3b814 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -361,6 +361,9 @@ static int hal_enable_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); if (!ret) clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to start dma: %d\n", ret); return ret; } @@ -376,6 +379,9 @@ static int hal_stop_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); if (!ret) set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to stop dma: %d\n", ret); return ret; } From 9e1aff437a560cd72cb6a60ee33fe162b0afdaf1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 10 Nov 2023 09:23:15 +0800 Subject: [PATCH 0498/7721] wifi: rtw89: pci: add pre_deinit to be called after probe complete At probe stage, we only do partial initialization to enable ability to download firmware and read capabilities. After that, we use this pre_deinit to disable HCI to save power. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 2 ++ drivers/net/wireless/realtek/rtw89/core.h | 6 ++++++ drivers/net/wireless/realtek/rtw89/pci.c | 2 ++ drivers/net/wireless/realtek/rtw89/pci.h | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 18 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 9 +++++++++ 6 files changed, 49 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index c689fc2b2d49..b18f54b16f9a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4236,6 +4236,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) rtw89_core_setup_phycap(rtwdev); + rtw89_hci_mac_pre_deinit(rtwdev); + rtw89_mac_pwr_off(rtwdev); return 0; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index da8181539d1a..07b529a76396 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3064,6 +3064,7 @@ struct rtw89_hci_ops { void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data); int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); int (*deinit)(struct rtw89_dev *rtwdev); @@ -4803,6 +4804,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) return rtwdev->hci.ops->tx_kick_off(rtwdev, txch); } +static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return rtwdev->hci.ops->mac_pre_deinit(rtwdev); +} + static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues, bool drop) { diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 822b914cf935..013588a572c5 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3837,6 +3837,7 @@ EXPORT_SYMBOL(rtw89_pm_ops); const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, + .mac_pre_deinit = NULL, .mac_post_init = rtw89_pci_ops_mac_post_init_ax, .clr_idx_all = rtw89_pci_clr_idx_all_ax, @@ -3866,6 +3867,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .write32 = rtw89_pci_ops_write32, .mac_pre_init = rtw89_pci_ops_mac_pre_init, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit, .mac_post_init = rtw89_pci_ops_mac_post_init, .deinit = rtw89_pci_ops_deinit, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 30ab9d41e0ee..426f9d28650b 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1038,6 +1038,7 @@ struct rtw89_pci_bd_ram { struct rtw89_pci_gen_def { int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); void (*clr_idx_all)(struct rtw89_dev *rtwdev); @@ -1464,6 +1465,17 @@ static inline int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) return gen_def->mac_pre_init(rtwdev); } +static inline int rtw89_pci_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + if (!gen_def->mac_pre_deinit) + return 0; + + return gen_def->mac_pre_deinit(rtwdev); +} + static inline int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 01d72cde48a3..4f76395e243a 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -329,6 +329,23 @@ static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + _patch_pcie_power_wake_be(rtwdev, false); + + val = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (val == 0) + return 0; + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + return 0; +} + int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) { u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; @@ -474,6 +491,7 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be, .mac_post_init = rtw89_pci_ops_mac_post_init_be, .clr_idx_all = rtw89_pci_clr_idx_all_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 68a5d8ff6a70..470302e6de11 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3871,6 +3871,15 @@ #define R_BE_UDM2 0x01F8 #define B_BE_UDM2_EPC_RA_MASK GENMASK(31, 0) +#define R_BE_IC_PWR_STATE 0x03F0 +#define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) +#define MAC_AX_SYS_ACT 0x220 +#define B_BE_WLMAC_PWR_STE_MASK GENMASK(9, 8) +#define B_BE_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6) +#define B_BE_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4) +#define B_BE_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) +#define B_BE_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) + #define R_BE_DCPU_PLATFORM_ENABLE 0x0888 #define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10) #define B_BE_DCPU_WARM_EN BIT(9) From aa70f76120ee4e67b1ba90a2e2ec1fea595cf108 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 10 Nov 2023 09:23:16 +0800 Subject: [PATCH 0499/7721] wifi: rtw89: pci: generalize interrupt status bits of interrupt handlers For WiFi 7, interrupt status registers and their definitions are changed a lot, but the logic is still the same, so define fields to reuse the code. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 27 +++++---- drivers/net/wireless/realtek/rtw89/pci.h | 62 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 6 ++ drivers/net/wireless/realtek/rtw89/reg.h | 27 +++++++++ 4 files changed, 111 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 013588a572c5..71c73adfcf59 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -696,12 +696,6 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1); -static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00) -{ - /* write 1 clear */ - rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00); -} - void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); @@ -773,6 +767,8 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) { struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; struct rtw89_pci_isrs isrs; unsigned long flags; @@ -780,13 +776,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - if (unlikely(isrs.isrs[0] & B_AX_RDU_INT)) + if (unlikely(isrs.isrs[0] & gen_def->isr_rdu)) rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); - if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h)) rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); - if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout)) rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT); if (unlikely(rtwpci->under_recovery)) @@ -3748,17 +3744,19 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) { struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; unsigned long flags; int work_done; rtwdev->napi_budget_countdown = budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data); work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done == budget) return budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data); work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done < budget && napi_complete_done(napi, work_done)) { spin_lock_irqsave(&rtwpci->irq_lock, flags); @@ -3836,6 +3834,13 @@ SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { + .isr_rdu = B_AX_RDU_INT, + .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, + .isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN, + .isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT}, + .isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | + B_AX_RDU_INT}, + .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, .mac_pre_deinit = NULL, .mac_post_init = rtw89_pci_ops_mac_post_init_ax, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 426f9d28650b..cb95ad653419 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -290,6 +290,62 @@ #define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) #define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) +#define R_BE_PCIE_DMA_ISR 0x30BC +#define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_ISR_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_ISR_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_ISR_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_ISR_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_ISR_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_ISR BIT(14) +#define B_BE_PCIE_TX_CH13_ISR BIT(13) +#define B_BE_PCIE_TX_CH12_ISR BIT(12) +#define B_BE_PCIE_TX_CH11_ISR BIT(11) +#define B_BE_PCIE_TX_CH10_ISR BIT(10) +#define B_BE_PCIE_TX_CH9_ISR BIT(9) +#define B_BE_PCIE_TX_CH8_ISR BIT(8) +#define B_BE_PCIE_TX_CH7_ISR BIT(7) +#define B_BE_PCIE_TX_CH6_ISR BIT(6) +#define B_BE_PCIE_TX_CH5_ISR BIT(5) +#define B_BE_PCIE_TX_CH4_ISR BIT(4) +#define B_BE_PCIE_TX_CH3_ISR BIT(3) +#define B_BE_PCIE_TX_CH2_ISR BIT(2) +#define B_BE_PCIE_TX_CH1_ISR BIT(1) +#define B_BE_PCIE_TX_CH0_ISR BIT(0) + +#define R_BE_HAXI_HISR00 0xB0B4 +#define B_BE_RDU_CH6_INT BIT(28) +#define B_BE_RDU_CH5_INT BIT(27) +#define B_BE_RDU_CH4_INT BIT(26) +#define B_BE_RDU_CH2_INT BIT(25) +#define B_BE_RDU_CH1_INT BIT(24) +#define B_BE_RDU_CH0_INT BIT(23) +#define B_BE_RXDMA_STUCK_INT BIT(22) +#define B_BE_TXDMA_STUCK_INT BIT(21) +#define B_BE_TXDMA_CH14_INT BIT(20) +#define B_BE_TXDMA_CH13_INT BIT(19) +#define B_BE_TXDMA_CH12_INT BIT(18) +#define B_BE_TXDMA_CH11_INT BIT(17) +#define B_BE_TXDMA_CH10_INT BIT(16) +#define B_BE_TXDMA_CH9_INT BIT(15) +#define B_BE_TXDMA_CH8_INT BIT(14) +#define B_BE_TXDMA_CH7_INT BIT(13) +#define B_BE_TXDMA_CH6_INT BIT(12) +#define B_BE_TXDMA_CH5_INT BIT(11) +#define B_BE_TXDMA_CH4_INT BIT(10) +#define B_BE_TXDMA_CH3_INT BIT(9) +#define B_BE_TXDMA_CH2_INT BIT(8) +#define B_BE_TXDMA_CH1_INT BIT(7) +#define B_BE_TXDMA_CH0_INT BIT(6) +#define B_BE_RPQ1DMA_INT BIT(5) +#define B_BE_RX1P1DMA_INT BIT(4) +#define B_BE_RX1DMA_INT BIT(3) +#define B_BE_RPQ0DMA_INT BIT(2) +#define B_BE_RX0P1DMA_INT BIT(1) +#define B_BE_RX0DMA_INT BIT(0) + /* TX/RX */ #define R_AX_DRV_FW_HSK_0 0x01B0 #define R_AX_DRV_FW_HSK_1 0x01B4 @@ -1037,6 +1093,12 @@ struct rtw89_pci_bd_ram { }; struct rtw89_pci_gen_def { + u32 isr_rdu; + u32 isr_halt_c2h; + u32 isr_wdt_timeout; + struct rtw89_reg2_def isr_clear_rpq; + struct rtw89_reg2_def isr_clear_rxq; + int (*mac_pre_init)(struct rtw89_dev *rtwdev); int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 4f76395e243a..629ffa4bee91 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -490,6 +490,12 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) } const struct rtw89_pci_gen_def rtw89_pci_gen_be = { + .isr_rdu = B_BE_RDU_CH1_INT | B_BE_RDU_CH0_INT, + .isr_halt_c2h = B_BE_HALT_C2H_INT, + .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT, + .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1}, + .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1}, + .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be, .mac_post_init = rtw89_pci_ops_mac_post_init_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 470302e6de11..51a0394eee3c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3826,6 +3826,33 @@ #define B_BE_FS_GPIO17_INT_EN BIT(1) #define B_BE_FS_GPIO16_INT_EN BIT(0) +#define R_BE_HISR0 0x01A4 +#define B_BE_WDT_DATACPU_TIMEOUT_INT BIT(25) +#define B_BE_HALT_D2H_INT BIT(24) +#define B_BE_WDT_TIMEOUT_INT BIT(22) +#define B_BE_HALT_C2H_INT BIT(21) +#define B_BE_RON_INT BIT(20) +#define B_BE_PDNINT BIT(19) +#define B_BE_SPSANA_OCP_INT BIT(18) +#define B_BE_SPS_OCP_INT BIT(17) +#define B_BE_BTON_STS_UPDATE_INT BIT(16) +#define B_BE_GPIOF_INT BIT(15) +#define B_BE_GPIOE_INT BIT(14) +#define B_BE_GPIOD_INT BIT(13) +#define B_BE_GPIOC_INT BIT(12) +#define B_BE_GPIOB_INT BIT(11) +#define B_BE_GPIOA_INT BIT(10) +#define B_BE_GPIO9_INT BIT(9) +#define B_BE_GPIO8_INT BIT(8) +#define B_BE_GPIO7_INT BIT(7) +#define B_BE_GPIO6_INT BIT(6) +#define B_BE_GPIO5_INT BIT(5) +#define B_BE_GPIO4_INT BIT(4) +#define B_BE_GPIO3_INT BIT(3) +#define B_BE_GPIO2_INT BIT(2) +#define B_BE_GPIO1_INT BIT(1) +#define B_BE_GPIO0_INT BIT(0) + #define R_BE_WCPU_FW_CTRL 0x01E0 #define B_BE_RUN_ENV_MASK GENMASK(31, 30) #define B_BE_WCPU_FWDL_STATUS_MASK GENMASK(29, 26) From d8872fb60e720ed656e03883e9bed576a72e0006 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 10 Nov 2023 09:23:17 +0800 Subject: [PATCH 0500/7721] wifi: rtw89: 8922ae: add v2 interrupt handlers for 8922AE The handlers include three parts -- 1) configure interrupt mask; 2) enable/disable interrupt; 3) recognize (read) interrupt status. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 86 +++++++++++++++ drivers/net/wireless/realtek/rtw89/pci.h | 102 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 27 +++++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 4 + 4 files changed, 219 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 71c73adfcf59..9c6d55af8c8e 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -696,6 +696,27 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1); +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs) +{ + isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs; + isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ? + rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0; + isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ? + rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0; + isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR); + + if (isrs->halt_c2h_isrs) + rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs); + if (isrs->isrs[0]) + rtw89_write32(rtwdev, R_BE_HAXI_HISR00, isrs->isrs[0]); + if (isrs->isrs[1]) + rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs); +} +EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2); + void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); @@ -727,6 +748,22 @@ void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc } EXPORT_SYMBOL(rtw89_pci_disable_intr_v1); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs); + rtw89_write32(rtwdev, R_BE_HAXI_HIMR00, rtwpci->intrs[0]); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs); +} +EXPORT_SYMBOL(rtw89_pci_enable_intr_v2); + +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0); +} +EXPORT_SYMBOL(rtw89_pci_disable_intr_v2); + static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -3343,6 +3380,55 @@ void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1); +static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HCI_AXIDMA_INT_EN0 | + B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = B_BE_RDU_CH1_INT_IMR_V1 | + B_BE_RDU_CH0_INT_IMR_V1; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_low_power_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0 | + B_BE_HS1_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + if (rtwpci->under_recovery) + rtw89_pci_recovery_intr_mask_v2(rtwdev); + else if (rtwpci->low_power) + rtw89_pci_low_power_intr_mask_v2(rtwdev); + else + rtw89_pci_default_intr_mask_v2(rtwdev); +} +EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2); + static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index cb95ad653419..d2a0a9aa4da3 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -290,6 +290,69 @@ #define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) #define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) +#define R_BE_PCIE_HIMR0 0x30B0 +#define B_BE_PCIE_HB1_IND_INTA_IMR BIT(31) +#define B_BE_PCIE_HB0_IND_INTA_IMR BIT(30) +#define B_BE_HCI_AXIDMA_INTA_IMR BIT(29) +#define B_BE_HC0_IND_INTA_IMR BIT(28) +#define B_BE_HD1_IND_INTA_IMR BIT(27) +#define B_BE_HD0_IND_INTA_IMR BIT(26) +#define B_BE_HS1_IND_INTA_IMR BIT(25) +#define B_BE_HS0_IND_INTA_IMR BIT(24) +#define B_BE_PCIE_HOTRST_INT_EN BIT(16) +#define B_BE_PCIE_FLR_INT_EN BIT(15) +#define B_BE_PCIE_PERST_INT_EN BIT(14) +#define B_BE_PCIE_DBG_STE_INT_EN BIT(13) +#define B_BE_HB1_IND_INT_EN0 BIT(9) +#define B_BE_HB0_IND_INT_EN0 BIT(8) +#define B_BE_HC1_IND_INT_EN0 BIT(7) +#define B_BE_HCI_AXIDMA_INT_EN0 BIT(5) +#define B_BE_HC0_IND_INT_EN0 BIT(4) +#define B_BE_HD1_IND_INT_EN0 BIT(3) +#define B_BE_HD0_IND_INT_EN0 BIT(2) +#define B_BE_HS1_IND_INT_EN0 BIT(1) +#define B_BE_HS0_IND_INT_EN0 BIT(0) + +#define R_BE_PCIE_HISR 0x30B4 +#define B_BE_PCIE_HOTRST_INT BIT(16) +#define B_BE_PCIE_FLR_INT BIT(15) +#define B_BE_PCIE_PERST_INT BIT(14) +#define B_BE_PCIE_DBG_STE_INT BIT(13) +#define B_BE_HB1IMR_IND BIT(9) +#define B_BE_HB0IMR_IND BIT(8) +#define B_BE_HC1ISR_IND_INT BIT(7) +#define B_BE_HCI_AXIDMA_INT BIT(5) +#define B_BE_HC0ISR_IND_INT BIT(4) +#define B_BE_HD1ISR_IND_INT BIT(3) +#define B_BE_HD0ISR_IND_INT BIT(2) +#define B_BE_HS1ISR_IND_INT BIT(1) +#define B_BE_HS0ISR_IND_INT BIT(0) + +#define R_BE_PCIE_DMA_IMR_0_V1 0x30B8 +#define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_IMR0_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_IMR0_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_IMR0_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_IMR0_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_IMR0_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_IMR0 BIT(14) +#define B_BE_PCIE_TX_CH13_IMR0 BIT(13) +#define B_BE_PCIE_TX_CH12_IMR0 BIT(12) +#define B_BE_PCIE_TX_CH11_IMR0 BIT(11) +#define B_BE_PCIE_TX_CH10_IMR0 BIT(10) +#define B_BE_PCIE_TX_CH9_IMR0 BIT(9) +#define B_BE_PCIE_TX_CH8_IMR0 BIT(8) +#define B_BE_PCIE_TX_CH7_IMR0 BIT(7) +#define B_BE_PCIE_TX_CH6_IMR0 BIT(6) +#define B_BE_PCIE_TX_CH5_IMR0 BIT(5) +#define B_BE_PCIE_TX_CH4_IMR0 BIT(4) +#define B_BE_PCIE_TX_CH3_IMR0 BIT(3) +#define B_BE_PCIE_TX_CH2_IMR0 BIT(2) +#define B_BE_PCIE_TX_CH1_IMR0 BIT(1) +#define B_BE_PCIE_TX_CH0_IMR0 BIT(0) + #define R_BE_PCIE_DMA_ISR 0x30BC #define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23) #define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22) @@ -315,6 +378,39 @@ #define B_BE_PCIE_TX_CH1_ISR BIT(1) #define B_BE_PCIE_TX_CH0_ISR BIT(0) +#define R_BE_HAXI_HIMR00 0xB0B0 +#define B_BE_RDU_CH5_INT_IMR_V1 BIT(30) +#define B_BE_RDU_CH4_INT_IMR_V1 BIT(29) +#define B_BE_RDU_CH3_INT_IMR_V1 BIT(28) +#define B_BE_RDU_CH2_INT_IMR_V1 BIT(27) +#define B_BE_RDU_CH1_INT_IMR_V1 BIT(26) +#define B_BE_RDU_CH0_INT_IMR_V1 BIT(25) +#define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24) +#define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23) +#define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22) +#define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21) +#define B_BE_TXDMA_CH12_INT_EN_V1 BIT(20) +#define B_BE_TXDMA_CH11_INT_EN_V1 BIT(19) +#define B_BE_TXDMA_CH10_INT_EN_V1 BIT(18) +#define B_BE_TXDMA_CH9_INT_EN_V1 BIT(17) +#define B_BE_TXDMA_CH8_INT_EN_V1 BIT(16) +#define B_BE_TXDMA_CH7_INT_EN_V1 BIT(15) +#define B_BE_TXDMA_CH6_INT_EN_V1 BIT(14) +#define B_BE_TXDMA_CH5_INT_EN_V1 BIT(13) +#define B_BE_TXDMA_CH4_INT_EN_V1 BIT(12) +#define B_BE_TXDMA_CH3_INT_EN_V1 BIT(11) +#define B_BE_TXDMA_CH2_INT_EN_V1 BIT(10) +#define B_BE_TXDMA_CH1_INT_EN_V1 BIT(9) +#define B_BE_TXDMA_CH0_INT_EN_V1 BIT(8) +#define B_BE_RX1P1DMA_INT_EN_V1 BIT(7) +#define B_BE_RX0P1DMA_INT_EN_V1 BIT(6) +#define B_BE_RO1DMA_INT_EN BIT(5) +#define B_BE_RP1DMA_INT_EN BIT(4) +#define B_BE_RX1DMA_INT_EN BIT(3) +#define B_BE_RO0DMA_INT_EN BIT(2) +#define B_BE_RP0DMA_INT_EN BIT(1) +#define B_BE_RX0DMA_INT_EN BIT(0) + #define R_BE_HAXI_HISR00 0xB0B4 #define B_BE_RDU_CH6_INT BIT(28) #define B_BE_RDU_CH5_INT BIT(27) @@ -1438,16 +1534,22 @@ u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable); void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev); +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs); static inline u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 51a0394eee3c..080db70b87d2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3826,6 +3826,33 @@ #define B_BE_FS_GPIO17_INT_EN BIT(1) #define B_BE_FS_GPIO16_INT_EN BIT(0) +#define R_BE_HIMR0 0x01A0 +#define B_BE_WDT_DATACPU_TIMEOUT_INT_EN BIT(25) +#define B_BE_HALT_D2H_INT_EN BIT(24) +#define B_BE_WDT_TIMEOUT_INT_EN BIT(22) +#define B_BE_HALT_C2H_INT_EN BIT(21) +#define B_BE_RON_INT_EN BIT(20) +#define B_BE_PDNINT_EN BIT(19) +#define B_BE_SPSANA_OCP_INT_EN BIT(18) +#define B_BE_SPS_OCP_INT_EN BIT(17) +#define B_BE_BTON_STS_UPDATE_INT_EN BIT(16) +#define B_BE_GPIOF_INT_EN BIT(15) +#define B_BE_GPIOE_INT_EN BIT(14) +#define B_BE_GPIOD_INT_EN BIT(13) +#define B_BE_GPIOC_INT_EN BIT(12) +#define B_BE_GPIOB_INT_EN BIT(11) +#define B_BE_GPIOA_INT_EN BIT(10) +#define B_BE_GPIO9_INT_EN BIT(9) +#define B_BE_GPIO8_INT_EN BIT(8) +#define B_BE_GPIO7_INT_EN BIT(7) +#define B_BE_GPIO6_INT_EN BIT(6) +#define B_BE_GPIO5_INT_EN BIT(5) +#define B_BE_GPIO4_INT_EN BIT(4) +#define B_BE_GPIO3_INT_EN BIT(3) +#define B_BE_GPIO2_INT_EN BIT(2) +#define B_BE_GPIO1_INT_EN BIT(1) +#define B_BE_GPIO0_INT_EN BIT(0) + #define R_BE_HISR0 0x01A4 #define B_BE_WDT_DATACPU_TIMEOUT_INT BIT(25) #define B_BE_HALT_D2H_INT BIT(24) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 944337c60191..2a9ad5a254d8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -50,6 +50,10 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .ltr_set = rtw89_pci_ltr_set_v2, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, + .config_intr_mask = rtw89_pci_config_intr_mask_v2, + .enable_intr = rtw89_pci_enable_intr_v2, + .disable_intr = rtw89_pci_disable_intr_v2, + .recognize_intrs = rtw89_pci_recognize_intrs_v2, }; static const struct rtw89_driver_info rtw89_8922ae_info = { From 9f08c77b776976a6eabd9678d77ff9ab4ff4233e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 10 Nov 2023 09:23:18 +0800 Subject: [PATCH 0501/7721] wifi: rtw89: pci: correct interrupt mitigation register for 8852CE To reduce interrupt count, configure mitigation register with thresholds of time and packet count. We missed that 8852CE uses different register address, so correct it. Then, interrupt counts down to 30,763 from 229,825 during stress test in 20 seconds. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 3 ++- drivers/net/wireless/realtek/rtw89/pci.h | 8 ++++++++ drivers/net/wireless/realtek/rtw89/rtw8851be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ae.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ce.c | 1 + 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 9c6d55af8c8e..09de12a9e3c2 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3620,6 +3620,7 @@ static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) { + const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_traffic_stats *stats = &rtwdev->stats; enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; @@ -3632,7 +3633,7 @@ static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) | FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64); - rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val); + rtw89_write32(rtwdev, info->mit_addr, val); } static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index d2a0a9aa4da3..e2d8eef52b20 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -812,6 +812,13 @@ #define B_AX_RXCOUNTER_MATCH_MASK GENMASK(15, 8) #define B_AX_RXTIMER_MATCH_MASK GENMASK(7, 0) +#define R_AX_INT_MIT_RX_V1 0x1184 +#define B_AX_RXMIT_RXP2_SEL_V1 BIT(19) +#define B_AX_RXMIT_RXP1_SEL_V1 BIT(18) +#define B_AX_MIT_RXTIMER_UNIT_MASK GENMASK(17, 16) +#define B_AX_MIT_RXCOUNTER_MATCH_MASK GENMASK(15, 8) +#define B_AX_MIT_RXTIMER_MATCH_MASK GENMASK(7, 0) + #define R_AX_DBG_ERR_FLAG 0x11C4 #define B_AX_PCIE_RPQ_FULL BIT(29) #define B_AX_PCIE_RXQ_FULL BIT(28) @@ -1241,6 +1248,7 @@ struct rtw89_pci_info { u32 rpwm_addr; u32 cpwm_addr; + u32 mit_addr; u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 6858fd760013..ade69bd30fc8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -43,6 +43,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index f539f4602c02..f1e890bde049 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -44,6 +44,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index b9bbb6e9b4ff..920b20bbcfb7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -44,6 +44,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index f6bf35342719..4592de3dbd94 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -53,6 +53,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM_V1, .cpwm_addr = R_AX_PCIE_CRPWM, + .mit_addr = R_AX_INT_MIT_RX_V1, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, From 0a78bb64a49995c7377b1d716bbff7a9d92212cb Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 10 Nov 2023 09:23:19 +0800 Subject: [PATCH 0502/7721] wifi: rtw89: pci: update interrupt mitigation register for 8922AE To reduce interrupts, configure the mitigation setting of 8922AE when bringing interface up, and then check situations to decide turning on or off the function. With this, interrupt count decreases to 20,141 from 202,141 in period of 20 seconds. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231110012319.12727-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 11 +++++++++-- drivers/net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 09de12a9e3c2..0ca07ae63594 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3620,19 +3620,26 @@ static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) { + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_traffic_stats *stats = &rtwdev->stats; enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; u32 val = 0; - if (!rtwdev->scanning && - (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH)) + if (rtwdev->scanning || + (tx_tfc_lv < RTW89_TFC_HIGH && rx_tfc_lv < RTW89_TFC_HIGH)) + goto out; + + if (chip_gen == RTW89_CHIP_BE) + val = B_BE_PCIE_MIT_RX0P2_EN | B_BE_PCIE_MIT_RX0P1_EN; + else val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL | FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) | FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) | FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64); +out: rtw89_write32(rtwdev, info->mit_addr, val); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 2a9ad5a254d8..414635d301aa 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -43,6 +43,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .rpwm_addr = R_BE_PCIE_HRPWM, .cpwm_addr = R_BE_PCIE_CRPWM, + .mit_addr = R_BE_PCIE_MIT_CH_EN, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, From a6865fe6fd784a8edec6bd6d396f8c054ade0de8 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 13 Nov 2023 11:37:37 +0200 Subject: [PATCH 0503/7721] drm/i915/display: Use int for entry setup frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least one TGL had regression when using u8 types for entry setup frames calculation. So, let's switch to use ints instead. intel_psr_entry_setup_frames() function expects to return u8 but since in case of error the error code -ETIME is returned. This doesn't fit into u8 and hence the return value is not as expected. Fixes: 2b981d57e480 ("drm/i915/display: Support PSR entry VSC packet to be transmitted one frame earlier") Signed-off-by: Mika Kahola Reviewed-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231113093737.358137-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index ea292832ca47..2fc89ac5b27a 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1141,12 +1141,12 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, return true; } -static u8 intel_psr_entry_setup_frames(struct intel_dp *intel_dp, - const struct drm_display_mode *adjusted_mode) +static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp, + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); int psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd); - u8 entry_setup_frames = 0; + int entry_setup_frames = 0; if (psr_setup_time < 0) { drm_dbg_kms(&i915->drm, From e4e6e8f1ad0f3d6c4d87045aa4d0fa4b7496182a Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Tue, 14 Nov 2023 14:54:49 +0000 Subject: [PATCH 0504/7721] firmware: arm_scmi: Add optional flags to extended names helper Some recently added SCMI protocols needs an additional flags parameter to be able to properly configure the command used to query the extended name of a resource. Modify extended_name_get helper accordingly. Signed-off-by: Cristian Marussi Link: https://lore.kernel.org/r/20231114145449.3136412-1-cristian.marussi@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/clock.c | 2 +- drivers/firmware/arm_scmi/driver.c | 12 ++++++++---- drivers/firmware/arm_scmi/perf.c | 2 +- drivers/firmware/arm_scmi/power.c | 2 +- drivers/firmware/arm_scmi/powercap.c | 2 +- drivers/firmware/arm_scmi/protocols.h | 3 ++- drivers/firmware/arm_scmi/reset.c | 3 ++- drivers/firmware/arm_scmi/sensors.c | 2 +- drivers/firmware/arm_scmi/voltage.c | 2 +- 9 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 42b81c181d68..98511a3aa367 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -318,7 +318,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) { if (SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, - clk->name, + NULL, clk->name, SCMI_MAX_STR_SIZE); if (SUPPORTS_RATE_CHANGED_NOTIF(attributes)) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 09371f40d61f..3eb19ed6f148 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1438,6 +1438,7 @@ struct scmi_msg_resp_domain_name_get { * @ph: A protocol handle reference. * @cmd_id: The specific command ID to use. * @res_id: The specific resource ID to use. + * @flags: A pointer to specific flags to use, if any. * @name: A pointer to the preallocated area where the retrieved name will be * stored as a NULL terminated string. * @len: The len in bytes of the @name char array. @@ -1445,19 +1446,22 @@ struct scmi_msg_resp_domain_name_get { * Return: 0 on Succcess */ static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph, - u8 cmd_id, u32 res_id, char *name, - size_t len) + u8 cmd_id, u32 res_id, u32 *flags, + char *name, size_t len) { int ret; + size_t txlen; struct scmi_xfer *t; struct scmi_msg_resp_domain_name_get *resp; - ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(res_id), - sizeof(*resp), &t); + txlen = !flags ? sizeof(res_id) : sizeof(res_id) + sizeof(*flags); + ret = ph->xops->xfer_get_init(ph, cmd_id, txlen, sizeof(*resp), &t); if (ret) goto out; put_unaligned_le32(res_id, t->tx.buf); + if (flags) + put_unaligned_le32(*flags, t->tx.buf + sizeof(res_id)); resp = t->rx.buf; ret = ph->xops->do_xfer(ph, t); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 36cdcfaf4324..d1323c5d9c27 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -288,7 +288,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, - dom_info->id, dom_info->info.name, + dom_info->id, NULL, dom_info->info.name, SCMI_MAX_STR_SIZE); if (dom_info->level_indexing_mode) { diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 356e83631664..077767d6e902 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -133,7 +133,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) { ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET, - domain, dom_info->name, + domain, NULL, dom_info->name, SCMI_MAX_STR_SIZE); } diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c index cb5617443a14..62a7780fedbb 100644 --- a/drivers/firmware/arm_scmi/powercap.c +++ b/drivers/firmware/arm_scmi/powercap.c @@ -270,7 +270,7 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph, */ if (!ret && SUPPORTS_EXTENDED_NAMES(flags)) ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET, - domain, dom_info->name, + domain, NULL, dom_info->name, SCMI_MAX_STR_SIZE); return ret; diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h index 78e1a01eb656..b3c6314bb4b8 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -256,7 +256,8 @@ struct scmi_fc_info { */ struct scmi_proto_helpers_ops { int (*extended_name_get)(const struct scmi_protocol_handle *ph, - u8 cmd_id, u32 res_id, char *name, size_t len); + u8 cmd_id, u32 res_id, u32 *flags, char *name, + size_t len); void *(*iter_response_init)(const struct scmi_protocol_handle *ph, struct scmi_iterator_ops *ops, unsigned int max_resources, u8 msg_id, diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index e9afa8cab730..7217fd7c6afa 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -128,7 +128,8 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain, - dom_info->name, SCMI_MAX_STR_SIZE); + NULL, dom_info->name, + SCMI_MAX_STR_SIZE); return ret; } diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 0b5853fa9d87..9952a7bc6682 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -644,7 +644,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph, if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(attrl)) ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id, - s->name, SCMI_MAX_STR_SIZE); + NULL, s->name, SCMI_MAX_STR_SIZE); if (s->extended_scalar_attrs) { s->sensor_power = le32_to_cpu(sdesc->power); diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index eaa8d944926a..36e2df77738c 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -242,7 +242,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, if (SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, VOLTAGE_DOMAIN_NAME_GET, - v->id, v->name, + v->id, NULL, v->name, SCMI_MAX_STR_SIZE); if (SUPPORTS_ASYNC_LEVEL_SET(attributes)) v->async_level_set = true; From 4be756fd983a0d91c258196b3206e9131e63d62d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:27 +0100 Subject: [PATCH 0505/7721] dt-bindings: hwinfo: samsung,exynos-chipid: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231108104343.24192-2-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/hwinfo/samsung,exynos-chipid.yaml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml index 95cbdcb56efe..45f3d468db7c 100644 --- a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml @@ -11,9 +11,20 @@ maintainers: properties: compatible: - enum: - - samsung,exynos4210-chipid - - samsung,exynos850-chipid + oneOf: + - enum: + - samsung,exynos4210-chipid + - samsung,exynos850-chipid + - items: + - enum: + - samsung,exynos5433-chipid + - samsung,exynos7-chipid + - const: samsung,exynos4210-chipid + - items: + - enum: + - samsung,exynos7885-chipid + - samsung,exynosautov9-chipid + - const: samsung,exynos850-chipid reg: maxItems: 1 From 9da80ed69eb150617e8c72aeb7fdb9bfc7b97fba Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:28 +0100 Subject: [PATCH 0506/7721] dt-bindings: i2c: exynos5: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Acked-by: Rob Herring Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/20231108104343.24192-3-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml | 10 +++++++++- .../devicetree/bindings/soc/samsung/exynos-usi.yaml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml index 3e52a0db6c41..c1f5d2cb7709 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml @@ -25,7 +25,15 @@ properties: - samsung,exynos5250-hsi2c # Exynos5250 and Exynos5420 - samsung,exynos5260-hsi2c # Exynos5260 - samsung,exynos7-hsi2c # Exynos7 - - samsung,exynosautov9-hsi2c # ExynosAutoV9 and Exynos850 + - samsung,exynosautov9-hsi2c + - items: + - enum: + - samsung,exynos5433-hsi2c + - const: samsung,exynos7-hsi2c + - items: + - enum: + - samsung,exynos850-hsi2c + - const: samsung,exynosautov9-hsi2c - const: samsung,exynos5-hsi2c # Exynos5250 and Exynos5420 deprecated: true diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index a6836904a4f8..5b7ab69546c4 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -155,7 +155,7 @@ examples: }; hsi2c_0: i2c@13820000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", "samsung,exynosautov9-hsi2c"; reg = <0x13820000 0xc0>; interrupts = ; #address-cells = <1>; From c45860f6ee9b52b2e2f9b9255d93b9875e416cb0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:29 +0100 Subject: [PATCH 0507/7721] dt-bindings: i2c: samsung,s3c2410-i2c: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Reviewed-by: Linus Walleij Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/20231108104343.24192-4-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/i2c/samsung,s3c2410-i2c.yaml | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml b/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml index b204e35e4f8d..1303502cf265 100644 --- a/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml @@ -11,14 +11,20 @@ maintainers: properties: compatible: - enum: - - samsung,s3c2410-i2c - - samsung,s3c2440-i2c - # For s3c2440-like I2C used inside HDMIPHY block found on several SoCs: - - samsung,s3c2440-hdmiphy-i2c - # For s3c2440-like I2C used as a host to SATA PHY controller on an - # internal bus: - - samsung,exynos5-sata-phy-i2c + oneOf: + - enum: + - samsung,s3c2410-i2c + - samsung,s3c2440-i2c + # For s3c2440-like I2C used inside HDMIPHY block found on several SoCs: + - samsung,s3c2440-hdmiphy-i2c + # For s3c2440-like I2C used as a host to SATA PHY controller on an + # internal bus: + - samsung,exynos5-sata-phy-i2c + - items: + - enum: + - samsung,exynos7885-i2c + - samsung,exynos850-i2c + - const: samsung,s3c2440-i2c '#address-cells': const: 1 From dd99d5b1ab93e7b731dda3d39cc7caf4639f8652 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 13 Nov 2023 16:20:51 +0200 Subject: [PATCH 0508/7721] drm/i915/dp: Tune down FEC detection timeout error message At least a Realtek DP branch device with the OUI 00-e0-4c dev-ID Dp1.4 HW-rev 1.0 SW-rev 131.1 device identification doesn't report detecting the FEC decoding start symbol. Tune down the corresponding error to a debug message. Reviewed-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231113142051.258864-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 0712a5200ad3..f70af660dfcf 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2257,8 +2257,8 @@ static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) return; if (err == -ETIMEDOUT) - drm_err(&i915->drm, "Timeout waiting for FEC %s to get detected\n", - str_enabled_disabled(enabled)); + drm_dbg_kms(&i915->drm, "Timeout waiting for FEC %s to get detected\n", + str_enabled_disabled(enabled)); else drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status); } From fe977716b40cb98cf9c91a66454adf3dc2f8c59a Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:29 +0000 Subject: [PATCH 0509/7721] bpf: Add a new kfunc for cgroup1 hierarchy A new kfunc is added to acquire cgroup1 of a task: - bpf_task_get_cgroup1 Acquires the associated cgroup of a task whithin a specific cgroup1 hierarchy. The cgroup1 hierarchy is identified by its hierarchy ID. This new kfunc enables the tracing of tasks within a designated container or cgroup directory in BPF programs. Suggested-by: Tejun Heo Signed-off-by: Yafang Shao Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20231111090034.4248-2-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 03517db5cfb3..b45a8381f9bd 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2228,6 +2228,25 @@ __bpf_kfunc long bpf_task_under_cgroup(struct task_struct *task, rcu_read_unlock(); return ret; } + +/** + * bpf_task_get_cgroup1 - Acquires the associated cgroup of a task within a + * specific cgroup1 hierarchy. The cgroup1 hierarchy is identified by its + * hierarchy ID. + * @task: The target task + * @hierarchy_id: The ID of a cgroup1 hierarchy + * + * On success, the cgroup is returen. On failure, NULL is returned. + */ +__bpf_kfunc struct cgroup * +bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) +{ + struct cgroup *cgrp = task_get_cgroup1(task, hierarchy_id); + + if (IS_ERR(cgrp)) + return NULL; + return cgrp; +} #endif /* CONFIG_CGROUPS */ /** @@ -2534,6 +2553,7 @@ BTF_ID_FLAGS(func, bpf_cgroup_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_cgroup_ancestor, KF_ACQUIRE | KF_RCU | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_cgroup_from_id, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_task_under_cgroup, KF_RCU) +BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL) #endif BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_throw) From 4849775587844e44d215289c425bcd70f315efe7 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:30 +0000 Subject: [PATCH 0510/7721] selftests/bpf: Fix issues in setup_classid_environment() If the net_cls subsystem is already mounted, attempting to mount it again in setup_classid_environment() will result in a failure with the error code EBUSY. Despite this, tmpfs will have been successfully mounted at /sys/fs/cgroup/net_cls. Consequently, the /sys/fs/cgroup/net_cls directory will be empty, causing subsequent setup operations to fail. Here's an error log excerpt illustrating the issue when net_cls has already been mounted at /sys/fs/cgroup/net_cls prior to running setup_classid_environment(): - Before that change $ tools/testing/selftests/bpf/test_progs --name=cgroup_v1v2 test_cgroup_v1v2:PASS:server_fd 0 nsec test_cgroup_v1v2:PASS:client_fd 0 nsec test_cgroup_v1v2:PASS:cgroup_fd 0 nsec test_cgroup_v1v2:PASS:server_fd 0 nsec run_test:PASS:skel_open 0 nsec run_test:PASS:prog_attach 0 nsec test_cgroup_v1v2:PASS:cgroup-v2-only 0 nsec (cgroup_helpers.c:248: errno: No such file or directory) Opening Cgroup Procs: /sys/fs/cgroup/net_cls/cgroup.procs (cgroup_helpers.c:540: errno: No such file or directory) Opening cgroup classid: /sys/fs/cgroup/net_cls/cgroup-test-work-dir/net_cls.classid run_test:PASS:skel_open 0 nsec run_test:PASS:prog_attach 0 nsec (cgroup_helpers.c:248: errno: No such file or directory) Opening Cgroup Procs: /sys/fs/cgroup/net_cls/cgroup-test-work-dir/cgroup.procs run_test:FAIL:join_classid unexpected error: 1 (errno 2) test_cgroup_v1v2:FAIL:cgroup-v1v2 unexpected error: -1 (errno 2) (cgroup_helpers.c:248: errno: No such file or directory) Opening Cgroup Procs: /sys/fs/cgroup/net_cls/cgroup.procs #44 cgroup_v1v2:FAIL Summary: 0/0 PASSED, 0 SKIPPED, 1 FAILED - After that change $ tools/testing/selftests/bpf/test_progs --name=cgroup_v1v2 #44 cgroup_v1v2:OK Summary: 1/0 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Yafang Shao Link: https://lore.kernel.org/r/20231111090034.4248-3-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/cgroup_helpers.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 5b1da2a32ea7..10b5f42e65e7 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -523,10 +523,20 @@ int setup_classid_environment(void) return 1; } - if (mount("net_cls", NETCLS_MOUNT_PATH, "cgroup", 0, "net_cls") && - errno != EBUSY) { - log_err("mount cgroup net_cls"); - return 1; + if (mount("net_cls", NETCLS_MOUNT_PATH, "cgroup", 0, "net_cls")) { + if (errno != EBUSY) { + log_err("mount cgroup net_cls"); + return 1; + } + + if (rmdir(NETCLS_MOUNT_PATH)) { + log_err("rmdir cgroup net_cls"); + return 1; + } + if (umount(CGROUP_MOUNT_DFLT)) { + log_err("umount cgroup base"); + return 1; + } } cleanup_classid_environment(); From f744d35ecf46f111bf9b54bfdbc89a28ee8b928a Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:31 +0000 Subject: [PATCH 0511/7721] selftests/bpf: Add parallel support for classid Include the current pid in the classid cgroup path. This way, different testers relying on classid-based configurations will have distinct classid cgroup directories, enabling them to run concurrently. Additionally, we leverage the current pid as the classid, ensuring unique identification. Signed-off-by: Yafang Shao Link: https://lore.kernel.org/r/20231111090034.4248-4-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/cgroup_helpers.c | 18 +++++++++++------- tools/testing/selftests/bpf/cgroup_helpers.h | 2 +- .../selftests/bpf/prog_tests/cgroup_v1v2.c | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 10b5f42e65e7..f18649a79d64 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -45,9 +45,12 @@ #define format_parent_cgroup_path(buf, path) \ format_cgroup_path_pid(buf, path, getppid()) -#define format_classid_path(buf) \ - snprintf(buf, sizeof(buf), "%s%s", NETCLS_MOUNT_PATH, \ - CGROUP_WORK_DIR) +#define format_classid_path_pid(buf, pid) \ + snprintf(buf, sizeof(buf), "%s%s%d", NETCLS_MOUNT_PATH, \ + CGROUP_WORK_DIR, pid) + +#define format_classid_path(buf) \ + format_classid_path_pid(buf, getpid()) static __thread bool cgroup_workdir_mounted; @@ -551,15 +554,16 @@ int setup_classid_environment(void) /** * set_classid() - Set a cgroupv1 net_cls classid - * @id: the numeric classid * - * Writes the passed classid into the cgroup work dir's net_cls.classid + * Writes the classid into the cgroup work dir's net_cls.classid * file in order to later on trigger socket tagging. * + * We leverage the current pid as the classid, ensuring unique identification. + * * On success, it returns 0, otherwise on failure it returns 1. If there * is a failure, it prints the error to stderr. */ -int set_classid(unsigned int id) +int set_classid(void) { char cgroup_workdir[PATH_MAX - 42]; char cgroup_classid_path[PATH_MAX + 1]; @@ -575,7 +579,7 @@ int set_classid(unsigned int id) return 1; } - if (dprintf(fd, "%u\n", id) < 0) { + if (dprintf(fd, "%u\n", getpid()) < 0) { log_err("Setting cgroup classid"); rc = 1; } diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index 5c2cb9c8b546..92fc41daf4a4 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -29,7 +29,7 @@ int setup_cgroup_environment(void); void cleanup_cgroup_environment(void); /* cgroupv1 related */ -int set_classid(unsigned int id); +int set_classid(void); int join_classid(void); int setup_classid_environment(void); diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c b/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c index 9026b42914d3..addf720428f7 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c @@ -71,7 +71,7 @@ void test_cgroup_v1v2(void) } ASSERT_OK(run_test(cgroup_fd, server_fd, false), "cgroup-v2-only"); setup_classid_environment(); - set_classid(42); + set_classid(); ASSERT_OK(run_test(cgroup_fd, server_fd, true), "cgroup-v1v2"); cleanup_classid_environment(); close(server_fd); From c1dcc050aa648bb3b831030d547c3fcc1c68140c Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:32 +0000 Subject: [PATCH 0512/7721] selftests/bpf: Add a new cgroup helper get_classid_cgroup_id() Introduce a new helper function to retrieve the cgroup ID from a net_cls cgroup directory. Signed-off-by: Yafang Shao Link: https://lore.kernel.org/r/20231111090034.4248-5-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/cgroup_helpers.c | 28 +++++++++++++++----- tools/testing/selftests/bpf/cgroup_helpers.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index f18649a79d64..63bfa72185be 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -422,26 +422,23 @@ int create_and_get_cgroup(const char *relative_path) } /** - * get_cgroup_id() - Get cgroup id for a particular cgroup path - * @relative_path: The cgroup path, relative to the workdir, to join + * get_cgroup_id_from_path - Get cgroup id for a particular cgroup path + * @cgroup_workdir: The absolute cgroup path * * On success, it returns the cgroup id. On failure it returns 0, * which is an invalid cgroup id. * If there is a failure, it prints the error to stderr. */ -unsigned long long get_cgroup_id(const char *relative_path) +unsigned long long get_cgroup_id_from_path(const char *cgroup_workdir) { int dirfd, err, flags, mount_id, fhsize; union { unsigned long long cgid; unsigned char raw_bytes[8]; } id; - char cgroup_workdir[PATH_MAX + 1]; struct file_handle *fhp, *fhp2; unsigned long long ret = 0; - format_cgroup_path(cgroup_workdir, relative_path); - dirfd = AT_FDCWD; flags = 0; fhsize = sizeof(*fhp); @@ -477,6 +474,14 @@ unsigned long long get_cgroup_id(const char *relative_path) return ret; } +unsigned long long get_cgroup_id(const char *relative_path) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_cgroup_path(cgroup_workdir, relative_path); + return get_cgroup_id_from_path(cgroup_workdir); +} + int cgroup_setup_and_join(const char *path) { int cg_fd; @@ -621,3 +626,14 @@ void cleanup_classid_environment(void) join_cgroup_from_top(NETCLS_MOUNT_PATH); nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT); } + +/** + * get_classid_cgroup_id - Get the cgroup id of a net_cls cgroup + */ +unsigned long long get_classid_cgroup_id(void) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_classid_path(cgroup_workdir); + return get_cgroup_id_from_path(cgroup_workdir); +} diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index 92fc41daf4a4..e71da4ef031b 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -31,6 +31,7 @@ void cleanup_cgroup_environment(void); /* cgroupv1 related */ int set_classid(void); int join_classid(void); +unsigned long long get_classid_cgroup_id(void); int setup_classid_environment(void); void cleanup_classid_environment(void); From bf47300b186facc8ae66a0e2aa89073565f82bb3 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:33 +0000 Subject: [PATCH 0513/7721] selftests/bpf: Add a new cgroup helper get_cgroup_hierarchy_id() A new cgroup helper function, get_cgroup1_hierarchy_id(), has been introduced to obtain the ID of a cgroup1 hierarchy based on the provided cgroup name. This cgroup name can be obtained from the /proc/self/cgroup file. Signed-off-by: Yafang Shao Link: https://lore.kernel.org/r/20231111090034.4248-6-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/cgroup_helpers.c | 52 ++++++++++++++++++++ tools/testing/selftests/bpf/cgroup_helpers.h | 1 + 2 files changed, 53 insertions(+) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 63bfa72185be..5aa133bf3688 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -637,3 +637,55 @@ unsigned long long get_classid_cgroup_id(void) format_classid_path(cgroup_workdir); return get_cgroup_id_from_path(cgroup_workdir); } + +/** + * get_cgroup1_hierarchy_id - Retrieves the ID of a cgroup1 hierarchy from the cgroup1 subsys name. + * @subsys_name: The cgroup1 subsys name, which can be retrieved from /proc/self/cgroup. It can be + * a named cgroup like "name=systemd", a controller name like "net_cls", or multi-contollers like + * "net_cls,net_prio". + */ +int get_cgroup1_hierarchy_id(const char *subsys_name) +{ + char *c, *c2, *c3, *c4; + bool found = false; + char line[1024]; + FILE *file; + int i, id; + + if (!subsys_name) + return -1; + + file = fopen("/proc/self/cgroup", "r"); + if (!file) { + log_err("fopen /proc/self/cgroup"); + return -1; + } + + while (fgets(line, 1024, file)) { + i = 0; + for (c = strtok_r(line, ":", &c2); c && i < 2; c = strtok_r(NULL, ":", &c2)) { + if (i == 0) { + id = strtol(c, NULL, 10); + } else if (i == 1) { + if (!strcmp(c, subsys_name)) { + found = true; + break; + } + + /* Multiple subsystems may share one single mount point */ + for (c3 = strtok_r(c, ",", &c4); c3; + c3 = strtok_r(NULL, ",", &c4)) { + if (!strcmp(c, subsys_name)) { + found = true; + break; + } + } + } + i++; + } + if (found) + break; + } + fclose(file); + return found ? id : -1; +} diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index e71da4ef031b..ee053641c026 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -20,6 +20,7 @@ int get_root_cgroup(void); int create_and_get_cgroup(const char *relative_path); void remove_cgroup(const char *relative_path); unsigned long long get_cgroup_id(const char *relative_path); +int get_cgroup1_hierarchy_id(const char *subsys_name); int join_cgroup(const char *relative_path); int join_root_cgroup(void); From 360769233cc9c921e90ae387d167ea3cd3cbb04c Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 11 Nov 2023 09:00:34 +0000 Subject: [PATCH 0514/7721] selftests/bpf: Add selftests for cgroup1 hierarchy Add selftests for cgroup1 hierarchy. The result as follows, $ tools/testing/selftests/bpf/test_progs --name=cgroup1_hierarchy #36/1 cgroup1_hierarchy/test_cgroup1_hierarchy:OK #36/2 cgroup1_hierarchy/test_root_cgid:OK #36/3 cgroup1_hierarchy/test_invalid_level:OK #36/4 cgroup1_hierarchy/test_invalid_cgid:OK #36/5 cgroup1_hierarchy/test_invalid_hid:OK #36/6 cgroup1_hierarchy/test_invalid_cgrp_name:OK #36/7 cgroup1_hierarchy/test_invalid_cgrp_name2:OK #36/8 cgroup1_hierarchy/test_sleepable_prog:OK #36 cgroup1_hierarchy:OK Summary: 1/8 PASSED, 0 SKIPPED, 0 FAILED Besides, I also did some stress test similar to the patch #2 in this series, as follows (with CONFIG_PROVE_RCU_LIST enabled): - Continuously mounting and unmounting named cgroups in some tasks, for example: cgrp_name=$1 while true do mount -t cgroup -o none,name=$cgrp_name none /$cgrp_name umount /$cgrp_name done - Continuously run this selftest concurrently, while true; do ./test_progs --name=cgroup1_hierarchy; done They can ran successfully without any RCU warnings in dmesg. Signed-off-by: Yafang Shao Link: https://lore.kernel.org/r/20231111090034.4248-7-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/cgroup1_hierarchy.c | 158 ++++++++++++++++++ .../bpf/progs/test_cgroup1_hierarchy.c | 71 ++++++++ 2 files changed, 229 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c create mode 100644 tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c b/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c new file mode 100644 index 000000000000..74d6d7546f40 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023 Yafang Shao */ + +#include +#include +#include +#include "cgroup_helpers.h" +#include "test_cgroup1_hierarchy.skel.h" + +static void bpf_cgroup1(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + ASSERT_NULL(fentry_link, "fentry_attach_fail"); + + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_lsm"); +} + +static void bpf_cgroup1_sleepable(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_s_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + ASSERT_NULL(fentry_link, "fentry_attach_fail"); + + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_lsm"); +} + +static void bpf_cgroup1_invalid_id(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + if (!ASSERT_OK_PTR(fentry_link, "fentry_attach_success")) + goto cleanup; + + err = bpf_link__destroy(fentry_link); + ASSERT_OK(err, "destroy_lsm"); + +cleanup: + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_fentry"); +} + +void test_cgroup1_hierarchy(void) +{ + struct test_cgroup1_hierarchy *skel; + __u64 current_cgid; + int hid, err; + + skel = test_cgroup1_hierarchy__open(); + if (!ASSERT_OK_PTR(skel, "open")) + return; + + skel->bss->target_pid = getpid(); + + err = bpf_program__set_attach_target(skel->progs.fentry_run, 0, "bpf_fentry_test1"); + if (!ASSERT_OK(err, "fentry_set_target")) + goto destroy; + + err = test_cgroup1_hierarchy__load(skel); + if (!ASSERT_OK(err, "load")) + goto destroy; + + /* Setup cgroup1 hierarchy */ + err = setup_classid_environment(); + if (!ASSERT_OK(err, "setup_classid_environment")) + goto destroy; + + err = join_classid(); + if (!ASSERT_OK(err, "join_cgroup1")) + goto cleanup; + + current_cgid = get_classid_cgroup_id(); + if (!ASSERT_GE(current_cgid, 0, "cgroup1 id")) + goto cleanup; + + hid = get_cgroup1_hierarchy_id("net_cls"); + if (!ASSERT_GE(hid, 0, "cgroup1 id")) + goto cleanup; + skel->bss->target_hid = hid; + + if (test__start_subtest("test_cgroup1_hierarchy")) { + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1(skel); + } + + if (test__start_subtest("test_root_cgid")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 0; + bpf_cgroup1(skel); + } + + if (test__start_subtest("test_invalid_level")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 1; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgid")) { + skel->bss->target_ancestor_cgid = 0; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_hid")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 0; + skel->bss->target_hid = -1; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgrp_name")) { + skel->bss->target_hid = get_cgroup1_hierarchy_id("net_cl"); + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgrp_name2")) { + skel->bss->target_hid = get_cgroup1_hierarchy_id("net_cls,"); + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_sleepable_prog")) { + skel->bss->target_hid = hid; + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_sleepable(skel); + } + +cleanup: + cleanup_classid_environment(); +destroy: + test_cgroup1_hierarchy__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c b/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c new file mode 100644 index 000000000000..44628865fe1d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023 Yafang Shao */ + +#include "vmlinux.h" +#include +#include +#include + +__u32 target_ancestor_level; +__u64 target_ancestor_cgid; +int target_pid, target_hid; + +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +struct cgroup *bpf_cgroup_ancestor(struct cgroup *cgrp, int level) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static int bpf_link_create_verify(int cmd) +{ + struct cgroup *cgrp, *ancestor; + struct task_struct *task; + int ret = 0; + + if (cmd != BPF_LINK_CREATE) + return 0; + + task = bpf_get_current_task_btf(); + + /* Then it can run in parallel with others */ + if (task->pid != target_pid) + return 0; + + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + /* Refuse it if its cgid or its ancestor's cgid is the target cgid */ + if (cgrp->kn->id == target_ancestor_cgid) + ret = -1; + + ancestor = bpf_cgroup_ancestor(cgrp, target_ancestor_level); + if (!ancestor) + goto out; + + if (ancestor->kn->id == target_ancestor_cgid) + ret = -1; + bpf_cgroup_release(ancestor); + +out: + bpf_cgroup_release(cgrp); + return ret; +} + +SEC("lsm/bpf") +int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size) +{ + return bpf_link_create_verify(cmd); +} + +SEC("lsm.s/bpf") +int BPF_PROG(lsm_s_run, int cmd, union bpf_attr *attr, unsigned int size) +{ + return bpf_link_create_verify(cmd); +} + +SEC("fentry") +int BPF_PROG(fentry_run) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; From 5de106ec1ea9b6106a0263cb2741ebfd7c39e820 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:43 +0300 Subject: [PATCH 0515/7721] arm64: dts: qcom: ipq6018: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-8-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 35 ++++++++++++--------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index 9aec89d5e095..a89b6f54d3a7 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -236,31 +236,26 @@ qusb_phy_1: qusb@59000 { ssphy_0: ssphy@78000 { compatible = "qcom,ipq6018-qmp-usb3-phy"; - reg = <0x0 0x00078000 0x0 0x1c4>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0x0 0x00078000 0x0 0x1000>; clocks = <&gcc GCC_USB0_AUX_CLK>, - <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB0_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "gcc_usb0_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB0_PHY_BCR>, <&gcc GCC_USB3PHY_0_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + reset-names = "phy", + "phy_phy"; - usb0_ssphy: phy@78200 { - reg = <0x0 0x00078200 0x0 0x130>, /* Tx */ - <0x0 0x00078400 0x0 0x200>, /* Rx */ - <0x0 0x00078800 0x0 0x1f8>, /* PCS */ - <0x0 0x00078600 0x0 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB0_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "gcc_usb0_pipe_clk_src"; - }; + status = "disabled"; }; qusb_phy_0: qusb@79000 { @@ -566,7 +561,7 @@ dwc_0: usb@8a00000 { compatible = "snps,dwc3"; reg = <0x0 0x08a00000 0x0 0xcd00>; interrupts = ; - phys = <&qusb_phy_0>, <&usb0_ssphy>; + phys = <&qusb_phy_0>, <&ssphy_0>; phy-names = "usb2-phy", "usb3-phy"; clocks = <&xo>; clock-names = "ref"; From 5e2af1902d7409fdd60d425690141e643eff583c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:44 +0300 Subject: [PATCH 0516/7721] arm64: dts: qcom: ipq8074: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-9-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 76 +++++++++++---------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 5d05819f356d..3d4ff7476320 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -125,32 +125,26 @@ soc: soc@0 { ssphy_1: phy@58000 { compatible = "qcom,ipq8074-qmp-usb3-phy"; - reg = <0x00058000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00058000 0x1000>; clocks = <&gcc GCC_USB1_AUX_CLK>, - <&gcc GCC_USB1_PHY_CFG_AHB_CLK>, - <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB1_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB1_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3phy_1_cc_pipe_clk"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB1_PHY_BCR>, - <&gcc GCC_USB3PHY_1_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + <&gcc GCC_USB3PHY_1_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - usb1_ssphy: phy@58200 { - reg = <0x00058200 0x130>, /* Tx */ - <0x00058400 0x200>, /* Rx */ - <0x00058800 0x1f8>, /* PCS */ - <0x00058600 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB1_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3phy_1_cc_pipe_clk"; - }; + status = "disabled"; }; qusb_phy_1: phy@59000 { @@ -168,32 +162,26 @@ qusb_phy_1: phy@59000 { ssphy_0: phy@78000 { compatible = "qcom,ipq8074-qmp-usb3-phy"; - reg = <0x00078000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00078000 0x1000>; clocks = <&gcc GCC_USB0_AUX_CLK>, - <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, - <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB0_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3phy_0_cc_pipe_clk"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB0_PHY_BCR>, - <&gcc GCC_USB3PHY_0_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + <&gcc GCC_USB3PHY_0_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - usb0_ssphy: phy@78200 { - reg = <0x00078200 0x130>, /* Tx */ - <0x00078400 0x200>, /* Rx */ - <0x00078800 0x1f8>, /* PCS */ - <0x00078600 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB0_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3phy_0_cc_pipe_clk"; - }; + status = "disabled"; }; qusb_phy_0: phy@79000 { @@ -628,7 +616,7 @@ dwc_0: usb@8a00000 { compatible = "snps,dwc3"; reg = <0x8a00000 0xcd00>; interrupts = ; - phys = <&qusb_phy_0>, <&usb0_ssphy>; + phys = <&qusb_phy_0>, <&ssphy_0>; phy-names = "usb2-phy", "usb3-phy"; snps,is-utmi-l1-suspend; snps,hird-threshold = /bits/ 8 <0x0>; @@ -670,7 +658,7 @@ dwc_1: usb@8c00000 { compatible = "snps,dwc3"; reg = <0x8c00000 0xcd00>; interrupts = ; - phys = <&qusb_phy_1>, <&usb1_ssphy>; + phys = <&qusb_phy_1>, <&ssphy_1>; phy-names = "usb2-phy", "usb3-phy"; snps,is-utmi-l1-suspend; snps,hird-threshold = /bits/ 8 <0x0>; From 48660cc40455b704d3478e9b197915772f056fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:45 +0300 Subject: [PATCH 0517/7721] arm64: dts: qcom: msm8996: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-10-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8996.dtsi | 40 ++++++++++++--------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 6ba9da9e6a8b..35a0d2a69711 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -779,7 +779,7 @@ gcc: clock-controller@300000 { <&pciephy_0>, <&pciephy_1>, <&pciephy_2>, - <&ssusb_phy_0>, + <&usb3phy>, <&ufsphy_lane 0>, <&ufsphy_lane 1>, <&ufsphy_lane 2>; @@ -3056,7 +3056,7 @@ usb3_dwc3: usb@6a00000 { compatible = "snps,dwc3"; reg = <0x06a00000 0xcc00>; interrupts = ; - phys = <&hsusb_phy1>, <&ssusb_phy_0>; + phys = <&hsusb_phy1>, <&usb3phy>; phy-names = "usb2-phy", "usb3-phy"; snps,hird-threshold = /bits/ 8 <0>; snps,dis_u2_susphy_quirk; @@ -3068,32 +3068,26 @@ usb3_dwc3: usb@6a00000 { usb3phy: phy@7410000 { compatible = "qcom,msm8996-qmp-usb3-phy"; - reg = <0x07410000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x07410000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, - <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB3_PHY_BCR>, - <&gcc GCC_USB3PHY_PHY_BCR>; - reset-names = "phy", "common"; + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; + status = "disabled"; - - ssusb_phy_0: phy@7410200 { - reg = <0x07410200 0x200>, - <0x07410400 0x130>, - <0x07410600 0x1a8>; - #phy-cells = <0>; - - #clock-cells = <0>; - clock-output-names = "usb3_phy_pipe_clk_src"; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - }; }; hsusb_phy1: phy@7411000 { From b7efebfeb2e8ad8187cdabba5f0212ba2e6c1069 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:46 +0300 Subject: [PATCH 0518/7721] arm64: dts: qcom: msm8998: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-11-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8998.dtsi | 35 +++++++++++---------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index b485bf925ce6..67a5a0f612d9 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -2149,7 +2149,7 @@ usb3_dwc3: usb@a800000 { interrupts = ; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&qusb2phy>, <&usb1_ssphy>; + phys = <&qusb2phy>, <&usb3phy>; phy-names = "usb2-phy", "usb3-phy"; snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; @@ -2158,33 +2158,26 @@ usb3_dwc3: usb@a800000 { usb3phy: phy@c010000 { compatible = "qcom,msm8998-qmp-usb3-phy"; - reg = <0x0c010000 0x18c>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x0c010000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_CLKREF_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB3_PHY_BCR>, <&gcc GCC_USB3PHY_PHY_BCR>; - reset-names = "phy", "common"; + reset-names = "phy", + "phy_phy"; - usb1_ssphy: phy@c010200 { - reg = <0xc010200 0x128>, - <0xc010400 0x200>, - <0xc010c00 0x20c>, - <0xc010600 0x128>, - <0xc010800 0x200>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_phy_pipe_clk_src"; - }; + status = "disabled"; }; qusb2phy: phy@c012000 { From ca5ca568d7388b38039c8d658735fc539352b1db Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:47 +0300 Subject: [PATCH 0519/7721] arm64: dts: qcom: sdm845: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-12-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 39 ++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index bf5e6eb9d313..22cf162dd816 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4000,33 +4000,28 @@ usb_1_qmpphy: phy@88e8000 { usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sdm845-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x18c>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "cfg_ahb", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x128>, - <0 0x088eb400 0 0x1fc>, - <0 0x088eb800 0 0x218>, - <0 0x088eb600 0 0x70>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; usb_1: usb@a6f8800 { @@ -4126,7 +4121,7 @@ usb_2_dwc3: usb@a800000 { iommus = <&apps_smmu 0x760 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From da9a1e6569ff46e6ef135eade705987a4c104cf6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:48 +0300 Subject: [PATCH 0520/7721] arm64: dts: qcom: sm8150: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-13-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 39 ++++++++++++---------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 97623af13464..7eee72415ebb 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3451,33 +3451,26 @@ usb_1_qmpphy: phy@88e8000 { usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8150-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x200>, - <0 0x088eb400 0 0x200>, - <0 0x088eb800 0 0x800>, - <0 0x088eb600 0 0x200>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; sdhc_2: mmc@8804000 { @@ -3640,7 +3633,7 @@ usb_2_dwc3: usb@a800000 { iommus = <&apps_smmu 0x160 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From 2dcb4a0058e53443c4e916c8e771691e0db0e780 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:49 +0300 Subject: [PATCH 0521/7721] arm64: dts: qcom: sm8250: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-14-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 38 ++++++++++++---------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index be970472f6c4..125f5fb0e4e5 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -3889,32 +3889,26 @@ port@2 { usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8250-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x200>, - <0 0x088eb400 0 0x200>, - <0 0x088eb800 0 0x800>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; sdhc_2: mmc@8804000 { @@ -4223,7 +4217,7 @@ usb_2_dwc3: usb@a800000 { iommus = <&apps_smmu 0x20 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From d6e2bc901cb71dc73cdb8a4da35ed8f43e7727d0 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:50 +0300 Subject: [PATCH 0522/7721] arm64: dts: qcom: sm8350: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-15-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 39 ++++++++++++---------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index b46236235b7f..4978f691e3c5 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -2238,34 +2238,27 @@ usb_1_qmpphy_dp_in: endpoint { }; }; - usb_2_qmpphy: phy-wrapper@88eb000 { + usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8350-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; + reg = <0 0x088eb000 0 0x2000>; status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; - - usb_2_ssphy: phy@88ebe00 { - reg = <0 0x088ebe00 0 0x200>, - <0 0x088ec000 0 0x200>, - <0 0x088eb200 0 0x1100>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; }; dc_noc: interconnect@90c0000 { @@ -2418,7 +2411,7 @@ usb_2_dwc3: usb@a800000 { iommus = <&apps_smmu 0x20 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From a18bbe1cb25e699cba633f197a960e6d29c600d5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:51 +0300 Subject: [PATCH 0523/7721] ARM: dts: qcom-sdx55: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-16-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx55.dtsi | 37 +++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi index 2aa5089a8513..f604a27f50be 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi @@ -228,31 +228,26 @@ usb_hsphy: phy@ff4000 { usb_qmpphy: phy@ff6000 { compatible = "qcom,sdx55-qmp-usb3-uni-phy"; - reg = <0x00ff6000 0x1c0>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00ff6000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_BCR>, - <&gcc GCC_USB3_PHY_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - usb_ssphy: phy@ff6200 { - reg = <0x00ff6200 0x170>, - <0x00ff6400 0x200>, - <0x00ff6800 0x800>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; mc_virt: interconnect@1100000 { @@ -603,7 +598,7 @@ usb_dwc3: usb@a600000 { iommus = <&apps_smmu 0x1a0 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_hsphy>, <&usb_ssphy>; + phys = <&usb_hsphy>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From d721d6b1aaa51e9c2e21183809a155a7125f94f2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 25 Aug 2023 00:19:52 +0300 Subject: [PATCH 0524/7721] ARM: dts: qcom-sdx65: switch USB QMP PHY to new style of bindings Change the USB QMP PHY to use newer style of QMP PHY bindings (single resource region, no per-PHY subnodes). Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230824211952.1397699-17-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx65.dtsi | 35 +++++++++++--------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index e559adaaeee7..726755c4f8a3 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -233,32 +233,27 @@ usb_hsphy: phy@ff4000 { usb_qmpphy: phy@ff6000 { compatible = "qcom,sdx65-qmp-usb3-uni-phy"; - reg = <0x00ff6000 0x1c8>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00ff6000 0x2000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_EN>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_EN>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_BCR>, - <&gcc GCC_USB3_PHY_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; status = "disabled"; - usb_ssphy: phy@ff6200 { - reg = <0x00ff6e00 0x160>, - <0x00ff7000 0x1ec>, - <0x00ff6200 0x1e00>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; }; system_noc: interconnect@1620000 { @@ -520,7 +515,7 @@ usb_dwc3: usb@a600000 { iommus = <&apps_smmu 0x1a0 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_hsphy>, <&usb_ssphy>; + phys = <&usb_hsphy>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; From 086fdb48bc65d6fde0f0e7d42dbfb3c00ea52628 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 8 Sep 2023 12:53:49 +0200 Subject: [PATCH 0525/7721] soc: qcom: add ADSP PDCharger ULOG driver The Qualcomm PMIC PDCharger ULOG driver provides access to logs of the ADSP firmware PDCharger module in charge of Battery and Power Delivery on modern systems. Implement trace events as a simple rpmsg driver with an 1s interval to retrieve the messages. The interface allows filtering the messages by subsystem and priority level, this could be implemented later on. Signed-off-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230908-topic-sm8550-upstream-pdcharge-ulog-v1-1-d1b16b02ced2@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 12 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/pmic_pdcharger_ulog.c | 166 +++++++++++++++++++++++++ drivers/soc/qcom/pmic_pdcharger_ulog.h | 36 ++++++ 4 files changed, 215 insertions(+) create mode 100644 drivers/soc/qcom/pmic_pdcharger_ulog.c create mode 100644 drivers/soc/qcom/pmic_pdcharger_ulog.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b3634e10f6f5..2686fda9fe27 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -77,6 +77,18 @@ config QCOM_PDR_HELPERS select QCOM_QMI_HELPERS depends on NET +config QCOM_PMIC_PDCHARGER_ULOG + tristate "Qualcomm PMIC PDCharger ULOG driver" + depends on RPMSG + depends on EVENT_TRACING + help + The Qualcomm PMIC PDCharger ULOG driver provides access to logs of + the ADSP firmware PDCharger module in charge of Battery and Power + Delivery on modern systems. + + Say yes here to support PDCharger ULOG event tracing on modern + Qualcomm platforms. + config QCOM_PMIC_GLINK tristate "Qualcomm PMIC GLINK driver" depends on RPMSG diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index bbca2e1e55bb..110108e23669 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_QCOM_OCMEM) += ocmem.o obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o +obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o qmi_helpers-y += qmi_encdec.o qmi_interface.o obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.c b/drivers/soc/qcom/pmic_pdcharger_ulog.c new file mode 100644 index 000000000000..f1aaacf05005 --- /dev/null +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd + */ +#include +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include "pmic_pdcharger_ulog.h" + +#define MSG_OWNER_CHG_ULOG 32778 +#define MSG_TYPE_REQ_RESP 1 + +#define GET_CHG_ULOG_REQ 0x18 +#define SET_CHG_ULOG_PROP_REQ 0x19 + +#define LOG_DEFAULT_TIME_MS 1000 + +#define MAX_ULOG_SIZE 8192 + +struct pmic_pdcharger_ulog_hdr { + __le32 owner; + __le32 type; + __le32 opcode; +}; + +struct pmic_pdcharger_ulog { + struct rpmsg_device *rpdev; + struct delayed_work ulog_work; +}; + +struct get_ulog_req_msg { + struct pmic_pdcharger_ulog_hdr hdr; + u32 log_size; +}; + +struct get_ulog_resp_msg { + struct pmic_pdcharger_ulog_hdr hdr; + u8 buf[MAX_ULOG_SIZE]; +}; + +static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len) +{ + return rpmsg_send(pg->rpdev->ept, data, len); +} + +static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg) +{ + struct get_ulog_req_msg req_msg = { + .hdr = { + .owner = MSG_OWNER_CHG_ULOG, + .type = MSG_TYPE_REQ_RESP, + .opcode = GET_CHG_ULOG_REQ + }, + .log_size = MAX_ULOG_SIZE + }; + + return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg)); +} + +static void pmic_pdcharger_ulog_work(struct work_struct *work) +{ + struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog, + ulog_work.work); + int rc; + + rc = pmic_pdcharger_ulog_request(pg); + if (rc) { + dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc); + return; + } +} + +static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg, + struct get_ulog_resp_msg *resp_msg, + size_t len) +{ + char *token, *buf = resp_msg->buf; + + if (len != sizeof(*resp_msg)) { + dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n", + sizeof(*resp_msg), len); + return; + } + + buf[MAX_ULOG_SIZE - 1] = '\0'; + + do { + token = strsep((char **)&buf, "\n"); + if (token && strlen(token)) + trace_pmic_pdcharger_ulog_msg(token); + } while (token); +} + +static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 addr) +{ + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); + struct pmic_pdcharger_ulog_hdr *hdr = data; + u32 opcode; + + opcode = le32_to_cpu(hdr->opcode); + + switch (opcode) { + case GET_CHG_ULOG_REQ: + schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS)); + pmic_pdcharger_ulog_handle_message(pg, data, len); + break; + default: + dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode); + break; + } + + return 0; +} + +static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct pmic_pdcharger_ulog *pg; + struct device *dev = &rpdev->dev; + + pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL); + if (!pg) + return -ENOMEM; + + pg->rpdev = rpdev; + INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work); + + dev_set_drvdata(dev, pg); + + pmic_pdcharger_ulog_request(pg); + + return 0; +} + +static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); + + cancel_delayed_work_sync(&pg->ulog_work); +} + +static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = { + { "PMIC_LOGS_ADSP_APPS" }, + {} +}; + +static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = { + .probe = pmic_pdcharger_ulog_rpmsg_probe, + .remove = pmic_pdcharger_ulog_rpmsg_remove, + .callback = pmic_pdcharger_ulog_rpmsg_callback, + .id_table = pmic_pdcharger_ulog_rpmsg_id_match, + .drv = { + .name = "qcom_pmic_pdcharger_ulog_rpmsg", + }, +}; + +module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver); +MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.h b/drivers/soc/qcom/pmic_pdcharger_ulog.h new file mode 100644 index 000000000000..9d5d9af4fbe4 --- /dev/null +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Ltd + */ + +#if !defined(_TRACE_PMIC_PDCHARGER_ULOG_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_PMIC_PDCHARGER_ULOG_H + +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pmic_pdcharger_ulog + +TRACE_EVENT(pmic_pdcharger_ulog_msg, + TP_PROTO(char *msg), + TP_ARGS(msg), + TP_STRUCT__entry( + __string(msg, msg) + ), + TP_fast_assign( + __assign_str(msg, msg); + ), + TP_printk("%s", __get_str(msg)) +); + +#endif /* _TRACE_PMIC_PDCHARGER_ULOG_H */ + +/* This part must be outside protection */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pmic_pdcharger_ulog + +#include From 2e122362d25e1b977aa5c5c88c03956be4228e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Tue, 24 Oct 2023 13:07:10 +0200 Subject: [PATCH 0526/7721] iosys-map: Rename locals used inside macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Widely used variable names can be used by macro users, potentially leading to name collisions. Suffix locals used inside the macros with an underscore, to reduce the collision potential. Suggested-by: Lucas De Marchi Signed-off-by: Michał Winiarski Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20231024110710.3039807-1-michal.winiarski@intel.com --- include/linux/iosys-map.h | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h index 1b06d074ade0..e3649a6563dd 100644 --- a/include/linux/iosys-map.h +++ b/include/linux/iosys-map.h @@ -168,9 +168,9 @@ struct iosys_map { * about the use of uninitialized variable. */ #define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({ \ - struct iosys_map copy = *map_; \ - iosys_map_incr(©, offset_); \ - copy; \ + struct iosys_map copy_ = *map_; \ + iosys_map_incr(©_, offset_); \ + copy_; \ }) /** @@ -391,14 +391,14 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * Returns: * The value read from the mapping. */ -#define iosys_map_rd(map__, offset__, type__) ({ \ - type__ val; \ - if ((map__)->is_iomem) { \ - __iosys_map_rd_io(val, (map__)->vaddr_iomem + (offset__), type__);\ - } else { \ - __iosys_map_rd_sys(val, (map__)->vaddr + (offset__), type__); \ - } \ - val; \ +#define iosys_map_rd(map__, offset__, type__) ({ \ + type__ val_; \ + if ((map__)->is_iomem) { \ + __iosys_map_rd_io(val_, (map__)->vaddr_iomem + (offset__), type__); \ + } else { \ + __iosys_map_rd_sys(val_, (map__)->vaddr + (offset__), type__); \ + } \ + val_; \ }) /** @@ -413,13 +413,13 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * or if pointer may be unaligned (and problematic for the architecture * supported), use iosys_map_memcpy_to() */ -#define iosys_map_wr(map__, offset__, type__, val__) ({ \ - type__ val = (val__); \ - if ((map__)->is_iomem) { \ - __iosys_map_wr_io(val, (map__)->vaddr_iomem + (offset__), type__);\ - } else { \ - __iosys_map_wr_sys(val, (map__)->vaddr + (offset__), type__); \ - } \ +#define iosys_map_wr(map__, offset__, type__, val__) ({ \ + type__ val_ = (val__); \ + if ((map__)->is_iomem) { \ + __iosys_map_wr_io(val_, (map__)->vaddr_iomem + (offset__), type__); \ + } else { \ + __iosys_map_wr_sys(val_, (map__)->vaddr + (offset__), type__); \ + } \ }) /** @@ -485,9 +485,9 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * The value read from the mapping. */ #define iosys_map_rd_field(map__, struct_offset__, struct_type__, field__) ({ \ - struct_type__ *s; \ + struct_type__ *s_; \ iosys_map_rd(map__, struct_offset__ + offsetof(struct_type__, field__), \ - typeof(s->field__)); \ + typeof(s_->field__)); \ }) /** @@ -508,9 +508,9 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * usage and memory layout. */ #define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({ \ - struct_type__ *s; \ + struct_type__ *s_; \ iosys_map_wr(map__, struct_offset__ + offsetof(struct_type__, field__), \ - typeof(s->field__), val__); \ + typeof(s_->field__), val__); \ }) #endif /* __IOSYS_MAP_H__ */ From 554557542e709e190eff8a598f0cde02647d533a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:35 +0300 Subject: [PATCH 0527/7721] ARM: dts: qcom: apq8064: correct XOADC register address The XOADC is present at the address 0x197 rather than just 197. It doesn't change a lot (since the driver hardcodes all register addresses), but the DT should present correct address anyway. Fixes: c4b70883ee33 ("ARM: dts: add XOADC and IIO HWMON to APQ8064") Reviewed-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-3-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-apq8064.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index 59fd86b9fb47..099a16c34e1f 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -738,7 +738,7 @@ pwrkey@1c { xoadc: xoadc@197 { compatible = "qcom,pm8921-adc"; - reg = <197>; + reg = <0x197>; interrupts-extended = <&pmicintc 78 IRQ_TYPE_EDGE_RISING>; #address-cells = <2>; #size-cells = <0>; From 6b6056961a2e2fb7a788b1d40feeb91073ad4ca1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:36 +0300 Subject: [PATCH 0528/7721] ARM: dts: qcom: msm8960: introduce label for PMIC keypad To simplify MSM8960 CDP board file, add label to PMIC keypad node. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-4-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts | 20 +++++++++----------- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts index 6c1bc3818883..4641b4f2195d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts @@ -88,17 +88,15 @@ clk-pins { }; }; -&pmicintc { - keypad@148 { - linux,keymap = < - MATRIX_KEY(0, 0, KEY_VOLUMEUP) - MATRIX_KEY(0, 1, KEY_VOLUMEDOWN) - MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS) - MATRIX_KEY(0, 3, KEY_CAMERA) - >; - keypad,num-rows = <1>; - keypad,num-columns = <5>; - }; +&pm8921_keypad { + linux,keymap = < + MATRIX_KEY(0, 0, KEY_VOLUMEUP) + MATRIX_KEY(0, 1, KEY_VOLUMEDOWN) + MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS) + MATRIX_KEY(0, 3, KEY_CAMERA) + >; + keypad,num-rows = <1>; + keypad,num-columns = <5>; }; &rpm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index d13080fcbeea..a34fda93d6a4 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -283,7 +283,7 @@ pwrkey@1c { pull-up; }; - keypad@148 { + pm8921_keypad: keypad@148 { compatible = "qcom,pm8921-keypad"; reg = <0x148>; interrupt-parent = <&pmicintc>; From a26d147f187206854f7a88197d28333c0e11f41b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:37 +0300 Subject: [PATCH 0529/7721] ARM: dts: qcom: msm8660-surf: use keypad label directly Directly use pm8058_keypad to declare keypad properties instead of referencing pm8058 top-level node. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-5-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts | 50 ++++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts index be18f1be29a1..86fbb6dfdc2a 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts @@ -34,32 +34,30 @@ &gsbi12_serial { status = "okay"; }; -&pm8058 { - keypad@148 { - linux,keymap = < - MATRIX_KEY(0, 0, KEY_FN_F1) - MATRIX_KEY(0, 1, KEY_UP) - MATRIX_KEY(0, 2, KEY_LEFT) - MATRIX_KEY(0, 3, KEY_VOLUMEUP) - MATRIX_KEY(1, 0, KEY_FN_F2) - MATRIX_KEY(1, 1, KEY_RIGHT) - MATRIX_KEY(1, 2, KEY_DOWN) - MATRIX_KEY(1, 3, KEY_VOLUMEDOWN) - MATRIX_KEY(2, 3, KEY_ENTER) - MATRIX_KEY(4, 0, KEY_CAMERA_FOCUS) - MATRIX_KEY(4, 1, KEY_UP) - MATRIX_KEY(4, 2, KEY_LEFT) - MATRIX_KEY(4, 3, KEY_HOME) - MATRIX_KEY(4, 4, KEY_FN_F3) - MATRIX_KEY(5, 0, KEY_CAMERA) - MATRIX_KEY(5, 1, KEY_RIGHT) - MATRIX_KEY(5, 2, KEY_DOWN) - MATRIX_KEY(5, 3, KEY_BACK) - MATRIX_KEY(5, 4, KEY_MENU) - >; - keypad,num-rows = <6>; - keypad,num-columns = <5>; - }; +&pm8058_keypad { + linux,keymap = < + MATRIX_KEY(0, 0, KEY_FN_F1) + MATRIX_KEY(0, 1, KEY_UP) + MATRIX_KEY(0, 2, KEY_LEFT) + MATRIX_KEY(0, 3, KEY_VOLUMEUP) + MATRIX_KEY(1, 0, KEY_FN_F2) + MATRIX_KEY(1, 1, KEY_RIGHT) + MATRIX_KEY(1, 2, KEY_DOWN) + MATRIX_KEY(1, 3, KEY_VOLUMEDOWN) + MATRIX_KEY(2, 3, KEY_ENTER) + MATRIX_KEY(4, 0, KEY_CAMERA_FOCUS) + MATRIX_KEY(4, 1, KEY_UP) + MATRIX_KEY(4, 2, KEY_LEFT) + MATRIX_KEY(4, 3, KEY_HOME) + MATRIX_KEY(4, 4, KEY_FN_F3) + MATRIX_KEY(5, 0, KEY_CAMERA) + MATRIX_KEY(5, 1, KEY_RIGHT) + MATRIX_KEY(5, 2, KEY_DOWN) + MATRIX_KEY(5, 3, KEY_BACK) + MATRIX_KEY(5, 4, KEY_MENU) + >; + keypad,num-rows = <6>; + keypad,num-columns = <5>; }; /* eMMC */ From 0802de336a43e0de423dc35289613dc2c6eba12b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:38 +0300 Subject: [PATCH 0530/7721] ARM: dts: qcom: apq8064-nexus7: move sdcc1 node to proper place Move sdcc1 device node to follow the alphanumberic sorting order. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-6-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts index c0dd6399f597..0c2f2a46927f 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts @@ -180,13 +180,6 @@ &mdp { status = "okay"; }; -/* eMMC */ -&sdcc1 { - vmmc-supply = <&pm8921_l5>; - vqmmc-supply = <&pm8921_s4>; - status = "okay"; -}; - &mdp_dsi1_out { remote-endpoint = <&dsi0_in>; }; @@ -335,6 +328,13 @@ lvs7 { }; }; +/* eMMC */ +&sdcc1 { + vmmc-supply = <&pm8921_l5>; + vqmmc-supply = <&pm8921_s4>; + status = "okay"; +}; + &usb_hs1_phy { v3p3-supply = <&pm8921_l3>; v1p8-supply = <&pm8921_l4>; From 249aae3ffcfe19564946ad7b3d58ee9786d53372 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:39 +0300 Subject: [PATCH 0531/7721] ARM: dts: qcom: mdm9615-wp8548-mangoh-green: group include clauses Group file inclusion to follow contemporary practice. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-7-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts index b269fdca1460..e3b4b93c3d38 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts @@ -6,11 +6,11 @@ * Author : Neil Armstrong */ +#include #include +#include #include "qcom-mdm9615-wp8548.dtsi" -#include -#include / { model = "MangOH Green with WP8548 Module"; From 455a4c46e023ab84263eae0fc7acca9a5ee8b7ac Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:40 +0300 Subject: [PATCH 0532/7721] ARM: dts: qcom: strip prefix from PMIC files As the vendor DTS files were moved to per-vendor subdirs, there no need to use common prefixes. Drop the `qcom-' prefix from PMIC dtsi file. This makes 32-bit qcom/ dts files closer to arm64 ones. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-8-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/{qcom-pm8226.dtsi => pm8226.dtsi} | 0 arch/arm/boot/dts/qcom/{qcom-pm8841.dtsi => pm8841.dtsi} | 0 arch/arm/boot/dts/qcom/{qcom-pm8941.dtsi => pm8941.dtsi} | 0 arch/arm/boot/dts/qcom/{qcom-pma8084.dtsi => pma8084.dtsi} | 0 arch/arm/boot/dts/qcom/{qcom-pmx55.dtsi => pmx55.dtsi} | 0 arch/arm/boot/dts/qcom/{qcom-pmx65.dtsi => pmx65.dtsi} | 0 arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts | 2 +- arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts | 2 +- arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts | 2 +- arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts | 2 +- arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts | 2 +- arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts | 2 +- arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi | 4 ++-- arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts | 2 +- .../dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts | 2 +- arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts | 2 +- arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts | 2 +- arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) rename arch/arm/boot/dts/qcom/{qcom-pm8226.dtsi => pm8226.dtsi} (100%) rename arch/arm/boot/dts/qcom/{qcom-pm8841.dtsi => pm8841.dtsi} (100%) rename arch/arm/boot/dts/qcom/{qcom-pm8941.dtsi => pm8941.dtsi} (100%) rename arch/arm/boot/dts/qcom/{qcom-pma8084.dtsi => pma8084.dtsi} (100%) rename arch/arm/boot/dts/qcom/{qcom-pmx55.dtsi => pmx55.dtsi} (100%) rename arch/arm/boot/dts/qcom/{qcom-pmx65.dtsi => pmx65.dtsi} (100%) diff --git a/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi b/arch/arm/boot/dts/qcom/pm8226.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pm8226.dtsi rename to arch/arm/boot/dts/qcom/pm8226.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi b/arch/arm/boot/dts/qcom/pm8841.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pm8841.dtsi rename to arch/arm/boot/dts/qcom/pm8841.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom/pm8941.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pm8941.dtsi rename to arch/arm/boot/dts/qcom/pm8941.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom/pma8084.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pma8084.dtsi rename to arch/arm/boot/dts/qcom/pma8084.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi b/arch/arm/boot/dts/qcom/pmx55.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pmx55.dtsi rename to arch/arm/boot/dts/qcom/pmx55.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi b/arch/arm/boot/dts/qcom/pmx65.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/qcom-pmx65.dtsi rename to arch/arm/boot/dts/qcom/pmx65.dtsi diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts index aa0e0e8d2a97..a39f5a161b03 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts index de19640efe55..59b218042d32 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" #include /delete-node/ &adsp_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts index b887e5361ec3..feb78afef3a6 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts index f516e0426bb9..cffc069712b2 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts @@ -7,7 +7,7 @@ #include #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; /delete-node/ &smem_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts index 6d1b2439ae3a..950fa652f985 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts @@ -4,8 +4,8 @@ #include #include #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" /delete-node/ &mpss_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts index 116e59a3b76d..1df24c922be9 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-apq8084.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" / { model = "Qualcomm APQ8084/IFC6540"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts index c6b6680248a6..d4e6aee034af 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-apq8084.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" / { model = "Qualcomm APQ 8084-MTP"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts index 60bdfddeae69..da99f770d4f5 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi index 68a2f9094e53..23ae474698aa 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts index 42d253b75dad..6c4153689b39 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts index 8230d0e1d95d..c0ca264d8140 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts index 3e2c86591ee2..325feb89b343 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" #include #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts index 11468d1409f7..0798cce3dbea 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts index 7e97ad5803d8..247069361909 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts @@ -9,7 +9,7 @@ #include "qcom-sdx55.dtsi" #include #include -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Qualcomm Technologies, Inc. SDX55 MTP"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts index 51058b065279..082f7ed1a01f 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts @@ -8,7 +8,7 @@ #include #include #include "qcom-sdx55.dtsi" -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Thundercomm T55 Development Kit"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts index 8fadc6e70692..e336a15b45c4 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts @@ -8,7 +8,7 @@ #include #include #include "qcom-sdx55.dtsi" -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Telit FN980 TLB"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts index 9649c859a2c3..07c10c84eefa 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts @@ -12,7 +12,7 @@ #include #include #include -#include "qcom-pmx65.dtsi" +#include "pmx65.dtsi" / { model = "Qualcomm Technologies, Inc. SDX65 MTP"; From eba2158528b1882055b7fe2b7647820516178f06 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:41 +0300 Subject: [PATCH 0533/7721] ARM: dts: qcom: apq8064: fix PMIC node labels Change PM8921 node labels to start with pm8921_ prefix, following other Qualcomm PMIC device nodes. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-9-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-apq8064.dtsi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index 099a16c34e1f..07e854a886d2 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -292,13 +292,13 @@ scm { */ iio-hwmon { compatible = "iio-hwmon"; - io-channels = <&xoadc 0x00 0x01>, /* Battery */ - <&xoadc 0x00 0x02>, /* DC in (charger) */ - <&xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&xoadc 0x00 0x0b>, /* Die temperature */ - <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&xoadc 0x00 0x0e>; /* Charger temperature */ + io-channels = <&pm8921_xoadc 0x00 0x01>, /* Battery */ + <&pm8921_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8921_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8921_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8921_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8921_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8921_xoadc 0x00 0x0e>; /* Charger temperature */ }; soc: soc { @@ -686,7 +686,7 @@ ssbi@500000 { reg = <0x00500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - pmicintc: pmic { + pm8921: pmic { compatible = "qcom,pm8921"; interrupt-parent = <&tlmm_pinmux>; interrupts = <74 8>; @@ -721,7 +721,7 @@ pm8921_mpps: mpps@50 { rtc@11d { compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8921>; interrupts = <39 1>; reg = <0x11d>; allow-set-time; @@ -730,16 +730,16 @@ rtc@11d { pwrkey@1c { compatible = "qcom,pm8921-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8921>; interrupts = <50 1>, <51 1>; debounce = <15625>; pull-up; }; - xoadc: xoadc@197 { + pm8921_xoadc: xoadc@197 { compatible = "qcom,pm8921-adc"; reg = <0x197>; - interrupts-extended = <&pmicintc 78 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8921 78 IRQ_TYPE_EDGE_RISING>; #address-cells = <2>; #size-cells = <0>; #io-channel-cells = <2>; From 0e4688cd4ee6efbeae2b31f75e16961fd7f72735 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:42 +0300 Subject: [PATCH 0534/7721] ARM: dts: qcom: mdm9615: fix PMIC node labels Change PM8018 node labels to start with pm8018_ prefix, following other Qualcomm PMIC device nodes. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-10-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi | 2 +- arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi index 92c8003dac25..dac3aa793f71 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi @@ -76,7 +76,7 @@ reset-out-pins { }; }; -&pmicgpio { +&pm8018_gpio { usb_vbus_5v_pins: usb-vbus-5v-state { pins = "gpio4"; function = "normal"; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index 63e21aa23642..c0a60bae703b 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -261,7 +261,7 @@ qcom,ssbi@500000 { reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - pmicintc: pmic { + pm8018: pmic { compatible = "qcom,pm8018", "qcom,pm8921"; interrupts = ; #interrupt-cells = <2>; @@ -272,38 +272,38 @@ pmicintc: pmic { pwrkey@1c { compatible = "qcom,pm8018-pwrkey", "qcom,pm8921-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8018>; interrupts = <50 IRQ_TYPE_EDGE_RISING>, <51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; pull-up; }; - pmicmpp: mpps@50 { + pm8018_mpps: mpps@50 { compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; interrupt-controller; #interrupt-cells = <2>; reg = <0x50>; gpio-controller; #gpio-cells = <2>; - gpio-ranges = <&pmicmpp 0 0 6>; + gpio-ranges = <&pm8018_mpps 0 0 6>; }; rtc@11d { compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8018>; interrupts = <39 IRQ_TYPE_EDGE_RISING>; reg = <0x11d>; allow-set-time; }; - pmicgpio: gpio@150 { + pm8018_gpio: gpio@150 { compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; reg = <0x150>; interrupt-controller; #interrupt-cells = <2>; gpio-controller; - gpio-ranges = <&pmicgpio 0 0 6>; + gpio-ranges = <&pm8018_gpio 0 0 6>; #gpio-cells = <2>; }; }; From c6d86aa8a12194d1c9c2f9108910a46c8a3ddc90 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:43 +0300 Subject: [PATCH 0535/7721] ARM: dts: qcom: msm8660: fix PMIC node labels Change PM8058 node labels to start with pm8058_ prefix, following other Qualcomm PMIC device nodes. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-11-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcom-apq8060-dragonboard.dts | 4 ++-- arch/arm/boot/dts/qcom/qcom-msm8660.dtsi | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index 569cbf0d8df8..94351c9bf94b 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -71,7 +71,7 @@ cm3605 { /* Trig on both edges - getting close or far away */ interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>; /* MPP05 analog input to the XOADC */ - io-channels = <&xoadc 0x00 0x05>; + io-channels = <&pm8058_xoadc 0x00 0x05>; io-channel-names = "aout"; pinctrl-names = "default"; pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>; @@ -944,7 +944,7 @@ irq-pins { }; }; -&xoadc { +&pm8058_xoadc { /* Reference voltage 2.2 V */ xoadc-ref-supply = <&pm8058_l18>; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index 78023ed2fdf7..9217ced108c4 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -80,13 +80,13 @@ sleep-clk { */ iio-hwmon { compatible = "iio-hwmon"; - io-channels = <&xoadc 0x00 0x01>, /* Battery */ - <&xoadc 0x00 0x02>, /* DC in (charger) */ - <&xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&xoadc 0x00 0x0b>, /* Die temperature */ - <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ + io-channels = <&pm8058_xoadc 0x00 0x01>, /* Battery */ + <&pm8058_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8058_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8058_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8058_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8058_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8058_xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ }; soc: soc { @@ -390,7 +390,7 @@ pm8058_keypad: keypad@148 { row-hold = <91500>; }; - xoadc: xoadc@197 { + pm8058_xoadc: xoadc@197 { compatible = "qcom,pm8058-adc"; reg = <0x197>; interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; From a10a09f34eb80b83ca7275e23bf982dae2aa7632 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:44 +0300 Subject: [PATCH 0536/7721] ARM: dts: qcom: msm8960: fix PMIC node labels Change PM8921 node labels to start with pm8921_ prefix, following other Qualcomm PMIC device nodes. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-12-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index a34fda93d6a4..ea2d961b266b 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -264,7 +264,7 @@ ssbi@500000 { reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - pmicintc: pmic { + pm8921: pmic { compatible = "qcom,pm8921"; interrupt-parent = <&msmgpio>; interrupts = <104 IRQ_TYPE_LEVEL_LOW>; @@ -276,7 +276,7 @@ pmicintc: pmic { pwrkey@1c { compatible = "qcom,pm8921-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8921>; interrupts = <50 IRQ_TYPE_EDGE_RISING>, <51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; @@ -286,7 +286,7 @@ pwrkey@1c { pm8921_keypad: keypad@148 { compatible = "qcom,pm8921-keypad"; reg = <0x148>; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8921>; interrupts = <74 IRQ_TYPE_EDGE_RISING>, <75 IRQ_TYPE_EDGE_RISING>; debounce = <15>; @@ -296,7 +296,7 @@ pm8921_keypad: keypad@148 { rtc@11d { compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; + interrupt-parent = <&pm8921>; interrupts = <39 IRQ_TYPE_EDGE_RISING>; reg = <0x11d>; allow-set-time; From 7b22923c3f504114e3509b0577bbb3a42eb0c49e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:45 +0300 Subject: [PATCH 0537/7721] ARM: dts: qcom: apq8064: move PMIC interrupts to the board files The interrupt of SSBI PMICs is routed to the SoCs GPIO. As such, it is not a property of the SoC, it is a property of the particular board (even if it is standard and unified between all devices). Move these interrupt specifications to the board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-13-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts | 8 ++++++++ arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts | 8 ++++++++ arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts | 8 ++++++++ .../boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts | 8 ++++++++ arch/arm/boot/dts/qcom/qcom-apq8064.dtsi | 4 ---- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts index 0c2f2a46927f..d6fb2bc7f32f 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts @@ -184,6 +184,14 @@ &mdp_dsi1_out { remote-endpoint = <&dsi0_in>; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &rpm { regulators { vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts index d6ecfd8addb7..c01254b1a3a7 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts @@ -69,6 +69,14 @@ &pcie { status = "okay"; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { wlan_default_gpios: wlan-gpios-state { pinconf { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts index b0c5e7bd5e74..4cd14b121b65 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts @@ -170,6 +170,14 @@ &pcie { perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { wlan_default_gpios: wlan-gpios-state { pinconf { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts index 9244512b74d1..7917f1657025 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts @@ -65,6 +65,14 @@ &gsbi5_serial { status = "okay"; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { gpio_keys_pin_a: gpio-keys-active-state { pins = "gpio3", "gpio4", "gpio29", "gpio35"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index 07e854a886d2..3bf9b6e61f52 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -662,8 +662,6 @@ ssbi@c00000 { pm8821: pmic { compatible = "qcom,pm8821"; - interrupt-parent = <&tlmm_pinmux>; - interrupts = <76 IRQ_TYPE_LEVEL_LOW>; #interrupt-cells = <2>; interrupt-controller; #address-cells = <1>; @@ -688,8 +686,6 @@ ssbi@500000 { pm8921: pmic { compatible = "qcom,pm8921"; - interrupt-parent = <&tlmm_pinmux>; - interrupts = <74 8>; #interrupt-cells = <2>; interrupt-controller; #address-cells = <1>; From 7661e1e7f66ee770bed744728da3e66c3900bb38 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:46 +0300 Subject: [PATCH 0538/7721] ARM: dts: qcom: mdm9615: move PMIC interrupts to the board files The interrupt of SSBI PMICs is routed to the SoCs GPIO. As such, it is not a property of the SoC, it is a property of the particular board (even if it is standard and unified between all devices). Move these interrupt specifications to the board files. Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-14-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi | 4 ++++ arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi index dac3aa793f71..b782ff0d16cd 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi @@ -76,6 +76,10 @@ reset-out-pins { }; }; +&pm8018 { + interrupts-extended = <&intc GIC_PPI 226 IRQ_TYPE_LEVEL_HIGH>; +}; + &pm8018_gpio { usb_vbus_5v_pins: usb-vbus-5v-state { pins = "gpio4"; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index c0a60bae703b..0b88ed3189b5 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -263,7 +263,6 @@ qcom,ssbi@500000 { pm8018: pmic { compatible = "qcom,pm8018", "qcom,pm8921"; - interrupts = ; #interrupt-cells = <2>; interrupt-controller; #address-cells = <1>; From 41cdee8a33495a4778ee534afb8ecfd524bb9c4f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:47 +0300 Subject: [PATCH 0539/7721] ARM: dts: qcom: msm8660: move PMIC interrupts to the board files The interrupt of SSBI PMICs is routed to the SoCs GPIO. As such, it is not a property of the SoC, it is a property of the particular board (even if it is standard and unified between all devices). Move these interrupt specifications to the board files. Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-15-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts | 4 ++++ arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts | 4 ++++ arch/arm/boot/dts/qcom/qcom-msm8660.dtsi | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index 94351c9bf94b..8a82f56fe7ca 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -272,6 +272,10 @@ kxsd9@18 { }; }; +&pm8058 { + interrupts-extended = <&tlmm 88 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8058_gpio { dragon_ethernet_gpios: ethernet-state { pinconf { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts index 86fbb6dfdc2a..a5441aecd637 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts @@ -34,6 +34,10 @@ &gsbi12_serial { status = "okay"; }; +&pm8058 { + interrupts-extended = <&tlmm 88 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8058_keypad { linux,keymap = < MATRIX_KEY(0, 0, KEY_FN_F1) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index 9217ced108c4..84b0366792d4 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -341,8 +341,6 @@ ssbi@500000 { pm8058: pmic { compatible = "qcom,pm8058"; - interrupt-parent = <&tlmm>; - interrupts = <88 8>; #interrupt-cells = <2>; interrupt-controller; #address-cells = <1>; From 31c4b7415ae4f710c59844358862483728a2b17b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:48 +0300 Subject: [PATCH 0540/7721] ARM: dts: qcom: msm8960: move PMIC interrupts to the board files The interrupt of SSBI PMICs is routed to the SoCs GPIO. As such, it is not a property of the SoC, it is a property of the particular board (even if it is standard and unified between all devices). Move these interrupt specifications to the board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-16-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts | 4 ++++ arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts | 4 ++++ arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts index 4641b4f2195d..43149c90c4fc 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts @@ -88,6 +88,10 @@ clk-pins { }; }; +&pm8921 { + interrupts-extended = <&msmgpio 104 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_keypad { linux,keymap = < MATRIX_KEY(0, 0, KEY_VOLUMEUP) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts index 13e85c287498..9e203164beb6 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts @@ -84,6 +84,10 @@ clk-pins { }; }; +&pm8921 { + interrupts-extended = <&msmgpio 104 IRQ_TYPE_LEVEL_LOW>; +}; + &rpm { regulators { compatible = "qcom,rpm-pm8921-regulators"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index ea2d961b266b..f1267c83d67a 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -266,8 +266,6 @@ ssbi@500000 { pm8921: pmic { compatible = "qcom,pm8921"; - interrupt-parent = <&msmgpio>; - interrupts = <104 IRQ_TYPE_LEVEL_LOW>; #interrupt-cells = <2>; interrupt-controller; #address-cells = <1>; From 5c903b859aaced384c0cd01d515f3e43a115fd9e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:49 +0300 Subject: [PATCH 0541/7721] ARM: dts: qcom: msm8960: split PMIC to separate dtsi files The PMIC is not a part of the SoC, so move PMIC to a separate file and include it from the board files. Suggested-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-17-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 40 +++++++++++++++++++ arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts | 1 + .../qcom/qcom-msm8960-samsung-expressatt.dts | 3 +- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 39 +----------------- 4 files changed, 44 insertions(+), 39 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/pm8921.dtsi diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi new file mode 100644 index 000000000000..414941f7a42f --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 + +&ssbi { + pm8921: pmic { + compatible = "qcom,pm8921"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pwrkey@1c { + compatible = "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pm8921>; + interrupts = <50 IRQ_TYPE_EDGE_RISING>, + <51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + + pm8921_keypad: keypad@148 { + compatible = "qcom,pm8921-keypad"; + reg = <0x148>; + interrupt-parent = <&pm8921>; + interrupts = <74 IRQ_TYPE_EDGE_RISING>, + <75 IRQ_TYPE_EDGE_RISING>; + debounce = <15>; + scan-delay = <32>; + row-hold = <91500>; + }; + + rtc@11d { + compatible = "qcom,pm8921-rtc"; + interrupt-parent = <&pm8921>; + interrupts = <39 IRQ_TYPE_EDGE_RISING>; + reg = <0x11d>; + allow-set-time; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts index 43149c90c4fc..a5ea4843db43 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts @@ -2,6 +2,7 @@ #include #include "qcom-msm8960.dtsi" +#include "pm8921.dtsi" / { model = "Qualcomm MSM8960 CDP"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts index 9e203164beb6..1a5116336ff0 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include "qcom-msm8960.dtsi" -#include +#include "pm8921.dtsi" / { model = "Samsung Galaxy Express SGH-I437"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index f1267c83d67a..774f507fa25a 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -259,47 +259,10 @@ gsbi5_serial: serial@16440000 { }; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8921: pmic { - compatible = "qcom,pm8921"; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pwrkey@1c { - compatible = "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8921>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; - debounce = <15625>; - pull-up; - }; - - pm8921_keypad: keypad@148 { - compatible = "qcom,pm8921-keypad"; - reg = <0x148>; - interrupt-parent = <&pm8921>; - interrupts = <74 IRQ_TYPE_EDGE_RISING>, - <75 IRQ_TYPE_EDGE_RISING>; - debounce = <15>; - scan-delay = <32>; - row-hold = <91500>; - }; - - rtc@11d { - compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pm8921>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; - allow-set-time; - }; - }; }; rng@1a500000 { From 2308f2df5b66c7ae5266c3d058fbb4c211de0e6a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:50 +0300 Subject: [PATCH 0542/7721] ARM: dts: qcom: apq8064: split PMICs to separate dtsi files The PMICs are not a part of the SoC, so move PMICs to separate files and include them from the board files. Suggested-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-18-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8821.dtsi | 22 +++ arch/arm/boot/dts/qcom/pm8921.dtsi | 99 +++++++++++++ .../dts/qcom/qcom-apq8064-asus-nexus7-flo.dts | 6 +- .../boot/dts/qcom/qcom-apq8064-cm-qs600.dts | 5 +- .../boot/dts/qcom/qcom-apq8064-ifc6410.dts | 5 +- .../qcom-apq8064-sony-xperia-lagan-yuga.dts | 5 +- arch/arm/boot/dts/qcom/qcom-apq8064.dtsi | 134 +----------------- 7 files changed, 140 insertions(+), 136 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/pm8821.dtsi diff --git a/arch/arm/boot/dts/qcom/pm8821.dtsi b/arch/arm/boot/dts/qcom/pm8821.dtsi new file mode 100644 index 000000000000..064e3ba54e18 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8821.dtsi @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* This PMIC is used on a secondary SSBI bus */ +&ssbi2 { + pm8821: pmic { + compatible = "qcom,pm8821"; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + pm8821_mpps: mpps@50 { + compatible = "qcom,pm8821-mpp", "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8821_mpps 0 0 4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index 414941f7a42f..ad41d99ab265 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -8,6 +8,30 @@ pm8921: pmic { #address-cells = <1>; #size-cells = <0>; + pm8921_gpio: gpio@150 { + + compatible = "qcom,pm8921-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8921_gpio 0 0 44>; + #gpio-cells = <2>; + + }; + + pm8921_mpps: mpps@50 { + compatible = "qcom,pm8921-mpp", + "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8921_mpps 0 0 12>; + interrupt-controller; + #interrupt-cells = <2>; + }; + pwrkey@1c { compatible = "qcom,pm8921-pwrkey"; reg = <0x1c>; @@ -36,5 +60,80 @@ rtc@11d { reg = <0x11d>; allow-set-time; }; + + pm8921_xoadc: xoadc@197 { + compatible = "qcom,pm8921-adc"; + reg = <0x197>; + interrupts-extended = <&pm8921 78 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; + #io-channel-cells = <2>; + + vcoin: adc-channel@0 { + reg = <0x00 0x00>; + }; + + vbat: adc-channel@1 { + reg = <0x00 0x01>; + }; + + dcin: adc-channel@2 { + reg = <0x00 0x02>; + }; + + vph_pwr: adc-channel@4 { + reg = <0x00 0x04>; + }; + + batt_therm: adc-channel@8 { + reg = <0x00 0x08>; + }; + + batt_id: adc-channel@9 { + reg = <0x00 0x09>; + }; + + usb_vbus: adc-channel@a { + reg = <0x00 0x0a>; + }; + + die_temp: adc-channel@b { + reg = <0x00 0x0b>; + }; + + ref_625mv: adc-channel@c { + reg = <0x00 0x0c>; + }; + + ref_1250mv: adc-channel@d { + reg = <0x00 0x0d>; + }; + + chg_temp: adc-channel@e { + reg = <0x00 0x0e>; + }; + + ref_muxoff: adc-channel@f { + reg = <0x00 0x0f>; + }; + }; + }; +}; + +/ { + /* + * These channels from the ADC are simply hardware monitors. + * That is why the ADC is referred to as "HKADC" - HouseKeeping + * ADC. + */ + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&pm8921_xoadc 0x00 0x01>, /* Battery */ + <&pm8921_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8921_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8921_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8921_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8921_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8921_xoadc 0x00 0x0e>; /* Charger temperature */ }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts index d6fb2bc7f32f..e8f893d86980 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include + +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Asus Nexus7(flo)"; compatible = "asus,nexus7-flo", "qcom,apq8064"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts index c01254b1a3a7..d4db84e9fcf3 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "CompuLab CM-QS600"; compatible = "qcom,apq8064-cm-qs600", "qcom,apq8064"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts index 4cd14b121b65..6aea97a0d54d 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Qualcomm APQ8064/IFC6410"; compatible = "qcom,apq8064-ifc6410", "qcom,apq8064"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts index 7917f1657025..ba18a02b1c57 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Sony Xperia Z"; compatible = "sony,xperia-yuga", "qcom,apq8064"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index 3bf9b6e61f52..f7c6db3a0fdd 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -284,23 +284,6 @@ scm { }; }; - - /* - * These channels from the ADC are simply hardware monitors. - * That is why the ADC is referred to as "HKADC" - HouseKeeping - * ADC. - */ - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&pm8921_xoadc 0x00 0x01>, /* Battery */ - <&pm8921_xoadc 0x00 0x02>, /* DC in (charger) */ - <&pm8921_xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&pm8921_xoadc 0x00 0x0b>, /* Die temperature */ - <&pm8921_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&pm8921_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&pm8921_xoadc 0x00 0x0e>; /* Charger temperature */ - }; - soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -655,129 +638,16 @@ rng@1a500000 { clock-names = "core"; }; - ssbi@c00000 { + ssbi2: ssbi@c00000 { compatible = "qcom,ssbi"; reg = <0x00c00000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8821: pmic { - compatible = "qcom,pm8821"; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8821_mpps: mpps@50 { - compatible = "qcom,pm8821-mpp", "qcom,ssbi-mpp"; - reg = <0x50>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8821_mpps 0 0 4>; - }; - }; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x00500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8921: pmic { - compatible = "qcom,pm8921"; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8921_gpio: gpio@150 { - - compatible = "qcom,pm8921-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8921_gpio 0 0 44>; - #gpio-cells = <2>; - - }; - - pm8921_mpps: mpps@50 { - compatible = "qcom,pm8921-mpp", - "qcom,ssbi-mpp"; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8921_mpps 0 0 12>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - rtc@11d { - compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pm8921>; - interrupts = <39 1>; - reg = <0x11d>; - allow-set-time; - }; - - pwrkey@1c { - compatible = "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8921>; - interrupts = <50 1>, <51 1>; - debounce = <15625>; - pull-up; - }; - - pm8921_xoadc: xoadc@197 { - compatible = "qcom,pm8921-adc"; - reg = <0x197>; - interrupts-extended = <&pm8921 78 IRQ_TYPE_EDGE_RISING>; - #address-cells = <2>; - #size-cells = <0>; - #io-channel-cells = <2>; - - vcoin: adc-channel@0 { - reg = <0x00 0x00>; - }; - vbat: adc-channel@1 { - reg = <0x00 0x01>; - }; - dcin: adc-channel@2 { - reg = <0x00 0x02>; - }; - vph_pwr: adc-channel@4 { - reg = <0x00 0x04>; - }; - batt_therm: adc-channel@8 { - reg = <0x00 0x08>; - }; - batt_id: adc-channel@9 { - reg = <0x00 0x09>; - }; - usb_vbus: adc-channel@a { - reg = <0x00 0x0a>; - }; - die_temp: adc-channel@b { - reg = <0x00 0x0b>; - }; - ref_625mv: adc-channel@c { - reg = <0x00 0x0c>; - }; - ref_1250mv: adc-channel@d { - reg = <0x00 0x0d>; - }; - chg_temp: adc-channel@e { - reg = <0x00 0x0e>; - }; - ref_muxoff: adc-channel@f { - reg = <0x00 0x0f>; - }; - }; - }; }; qfprom: qfprom@700000 { From e9297150225194bc68594a3241c33d28feed0d29 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:51 +0300 Subject: [PATCH 0543/7721] ARM: dts: qcom: mdm9615: split PMIC to separate dtsi files The PMIC is not a part of the SoC, so move PMIC to a separate file and include it from the board files. Suggested-by: Konrad Dybcio Reviewed-by: Neil Armstrong Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-19-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8018.dtsi | 57 +++++++++++++++++++ .../boot/dts/qcom/qcom-mdm9615-wp8548.dtsi | 1 + arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi | 48 +--------------- 3 files changed, 59 insertions(+), 47 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/pm8018.dtsi diff --git a/arch/arm/boot/dts/qcom/pm8018.dtsi b/arch/arm/boot/dts/qcom/pm8018.dtsi new file mode 100644 index 000000000000..c602544900b2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8018.dtsi @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Device Tree Source for Qualcomm PM8018 + * + * Copyright (C) 2016 BayLibre, SAS. + * Author : Neil Armstrong + */ + +&ssbi { + pm8018: pmic { + compatible = "qcom,pm8018", "qcom,pm8921"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pwrkey@1c { + compatible = "qcom,pm8018-pwrkey", + "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pm8018>; + interrupts = <50 IRQ_TYPE_EDGE_RISING>, + <51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + + pm8018_mpps: mpps@50 { + compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8018_mpps 0 0 6>; + }; + + rtc@11d { + compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; + interrupt-parent = <&pm8018>; + interrupts = <39 IRQ_TYPE_EDGE_RISING>; + reg = <0x11d>; + allow-set-time; + }; + + pm8018_gpio: gpio@150 { + compatible = "qcom,pm8058-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8018_gpio 0 0 6>; + #gpio-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi index b782ff0d16cd..27c3d92d9452 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi @@ -7,6 +7,7 @@ */ #include "qcom-mdm9615.dtsi" +#include "pm8018.dtsi" / { model = "Sierra Wireless WP8548 Module"; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index 0b88ed3189b5..e0950e02a796 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -256,56 +256,10 @@ gsbi5_serial: serial@16440000 { }; }; - qcom,ssbi@500000 { + ssbi: qcom,ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8018: pmic { - compatible = "qcom,pm8018", "qcom,pm8921"; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pwrkey@1c { - compatible = "qcom,pm8018-pwrkey", "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8018>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; - debounce = <15625>; - pull-up; - }; - - pm8018_mpps: mpps@50 { - compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8018_mpps 0 0 6>; - }; - - rtc@11d { - compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; - interrupt-parent = <&pm8018>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; - allow-set-time; - }; - - pm8018_gpio: gpio@150 { - compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8018_gpio 0 0 6>; - #gpio-cells = <2>; - }; - }; }; sdcc1bam: dma-controller@12182000 { From b00c86c2e9eec92159e8db20abbc0dd85835b071 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:52 +0300 Subject: [PATCH 0544/7721] ARM: dts: qcom: msm8660: split PMIC to separate dtsi files The PMIC is not a part of the SoC, so move PMIC to a separate file and include it from the board files. Suggested-by: Konrad Dybcio Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-20-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8058.dtsi | 160 ++++++++++++++++++ .../dts/qcom/qcom-apq8060-dragonboard.dts | 1 + arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts | 1 + arch/arm/boot/dts/qcom/qcom-msm8660.dtsi | 149 +--------------- 4 files changed, 163 insertions(+), 148 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/pm8058.dtsi diff --git a/arch/arm/boot/dts/qcom/pm8058.dtsi b/arch/arm/boot/dts/qcom/pm8058.dtsi new file mode 100644 index 000000000000..ad581c3bcbd2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8058.dtsi @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 + +&ssbi { + pm8058: pmic { + compatible = "qcom,pm8058"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pm8058_gpio: gpio@150 { + compatible = "qcom,pm8058-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8058_gpio 0 0 44>; + #gpio-cells = <2>; + }; + + pm8058_mpps: mpps@50 { + compatible = "qcom,pm8058-mpp", + "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8058_mpps 0 0 12>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pwrkey@1c { + compatible = "qcom,pm8058-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pm8058>; + interrupts = <50 1>, <51 1>; + debounce = <15625>; + pull-up; + }; + + pm8058_keypad: keypad@148 { + compatible = "qcom,pm8058-keypad"; + reg = <0x148>; + interrupt-parent = <&pm8058>; + interrupts = <74 1>, <75 1>; + debounce = <15>; + scan-delay = <32>; + row-hold = <91500>; + }; + + pm8058_xoadc: xoadc@197 { + compatible = "qcom,pm8058-adc"; + reg = <0x197>; + interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; + #io-channel-cells = <2>; + + vcoin: adc-channel@0 { + reg = <0x00 0x00>; + }; + + vbat: adc-channel@1 { + reg = <0x00 0x01>; + }; + + dcin: adc-channel@2 { + reg = <0x00 0x02>; + }; + + ichg: adc-channel@3 { + reg = <0x00 0x03>; + }; + + vph_pwr: adc-channel@4 { + reg = <0x00 0x04>; + }; + + usb_vbus: adc-channel@a { + reg = <0x00 0x0a>; + }; + + die_temp: adc-channel@b { + reg = <0x00 0x0b>; + }; + + ref_625mv: adc-channel@c { + reg = <0x00 0x0c>; + }; + + ref_1250mv: adc-channel@d { + reg = <0x00 0x0d>; + }; + + ref_325mv: adc-channel@e { + reg = <0x00 0x0e>; + }; + + ref_muxoff: adc-channel@f { + reg = <0x00 0x0f>; + }; + }; + + rtc@1e8 { + compatible = "qcom,pm8058-rtc"; + reg = <0x1e8>; + interrupt-parent = <&pm8058>; + interrupts = <39 1>; + allow-set-time; + }; + + vibrator@4a { + compatible = "qcom,pm8058-vib"; + reg = <0x4a>; + }; + + pm8058_led48: led@48 { + compatible = "qcom,pm8058-keypad-led"; + reg = <0x48>; + status = "disabled"; + }; + + pm8058_led131: led@131 { + compatible = "qcom,pm8058-led"; + reg = <0x131>; + status = "disabled"; + }; + + pm8058_led132: led@132 { + compatible = "qcom,pm8058-led"; + reg = <0x132>; + status = "disabled"; + }; + + pm8058_led133: led@133 { + compatible = "qcom,pm8058-led"; + reg = <0x133>; + status = "disabled"; + }; + }; +}; + +/ { + /* + * These channels from the ADC are simply hardware monitors. + * That is why the ADC is referred to as "HKADC" - HouseKeeping + * ADC. + */ + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&pm8058_xoadc 0x00 0x01>, /* Battery */ + <&pm8058_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8058_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8058_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8058_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8058_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8058_xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index 8a82f56fe7ca..aa6a620f180d 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -5,6 +5,7 @@ #include #include #include "qcom-msm8660.dtsi" +#include "pm8058.dtsi" / { model = "Qualcomm APQ8060 Dragonboard"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts index a5441aecd637..be2fbc1e0950 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts @@ -2,6 +2,7 @@ #include #include "qcom-msm8660.dtsi" +#include "pm8058.dtsi" / { model = "Qualcomm MSM8660 SURF"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index 84b0366792d4..eef4712bbcc4 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -73,22 +73,6 @@ sleep-clk { }; }; - /* - * These channels from the ADC are simply hardware monitors. - * That is why the ADC is referred to as "HKADC" - HouseKeeping - * ADC. - */ - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&pm8058_xoadc 0x00 0x01>, /* Battery */ - <&pm8058_xoadc 0x00 0x02>, /* DC in (charger) */ - <&pm8058_xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&pm8058_xoadc 0x00 0x0b>, /* Die temperature */ - <&pm8058_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&pm8058_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&pm8058_xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ - }; - soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -334,141 +318,10 @@ ebi2: external-bus@1a100000 { status = "disabled"; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8058: pmic { - compatible = "qcom,pm8058"; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8058_gpio: gpio@150 { - compatible = "qcom,pm8058-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8058_gpio 0 0 44>; - #gpio-cells = <2>; - - }; - - pm8058_mpps: mpps@50 { - compatible = "qcom,pm8058-mpp", - "qcom,ssbi-mpp"; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8058_mpps 0 0 12>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pwrkey@1c { - compatible = "qcom,pm8058-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8058>; - interrupts = <50 1>, <51 1>; - debounce = <15625>; - pull-up; - }; - - pm8058_keypad: keypad@148 { - compatible = "qcom,pm8058-keypad"; - reg = <0x148>; - interrupt-parent = <&pm8058>; - interrupts = <74 1>, <75 1>; - debounce = <15>; - scan-delay = <32>; - row-hold = <91500>; - }; - - pm8058_xoadc: xoadc@197 { - compatible = "qcom,pm8058-adc"; - reg = <0x197>; - interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; - #address-cells = <2>; - #size-cells = <0>; - #io-channel-cells = <2>; - - vcoin: adc-channel@0 { - reg = <0x00 0x00>; - }; - vbat: adc-channel@1 { - reg = <0x00 0x01>; - }; - dcin: adc-channel@2 { - reg = <0x00 0x02>; - }; - ichg: adc-channel@3 { - reg = <0x00 0x03>; - }; - vph_pwr: adc-channel@4 { - reg = <0x00 0x04>; - }; - usb_vbus: adc-channel@a { - reg = <0x00 0x0a>; - }; - die_temp: adc-channel@b { - reg = <0x00 0x0b>; - }; - ref_625mv: adc-channel@c { - reg = <0x00 0x0c>; - }; - ref_1250mv: adc-channel@d { - reg = <0x00 0x0d>; - }; - ref_325mv: adc-channel@e { - reg = <0x00 0x0e>; - }; - ref_muxoff: adc-channel@f { - reg = <0x00 0x0f>; - }; - }; - - rtc@1e8 { - compatible = "qcom,pm8058-rtc"; - reg = <0x1e8>; - interrupt-parent = <&pm8058>; - interrupts = <39 1>; - allow-set-time; - }; - - vibrator@4a { - compatible = "qcom,pm8058-vib"; - reg = <0x4a>; - }; - - pm8058_led48: led@48 { - compatible = "qcom,pm8058-keypad-led"; - reg = <0x48>; - status = "disabled"; - }; - - pm8058_led131: led@131 { - compatible = "qcom,pm8058-led"; - reg = <0x131>; - status = "disabled"; - }; - - pm8058_led132: led@132 { - compatible = "qcom,pm8058-led"; - reg = <0x132>; - status = "disabled"; - }; - - pm8058_led133: led@133 { - compatible = "qcom,pm8058-led"; - reg = <0x133>; - status = "disabled"; - }; - - }; }; l2cc: clock-controller@2082000 { From a195fb9165205985f8e335fe88ca769f957ffbdd Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:53 +0300 Subject: [PATCH 0545/7721] ARM: dts: qcom: pm8058: reorder nodes Move pm8058 device nodes to follow the alphanumberic sorting order. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-21-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8058.dtsi | 90 +++++++++++++++--------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8058.dtsi b/arch/arm/boot/dts/qcom/pm8058.dtsi index ad581c3bcbd2..913a511719fa 100644 --- a/arch/arm/boot/dts/qcom/pm8058.dtsi +++ b/arch/arm/boot/dts/qcom/pm8058.dtsi @@ -8,15 +8,24 @@ pm8058: pmic { #address-cells = <1>; #size-cells = <0>; - pm8058_gpio: gpio@150 { - compatible = "qcom,pm8058-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8058_gpio 0 0 44>; - #gpio-cells = <2>; + pwrkey@1c { + compatible = "qcom,pm8058-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pm8058>; + interrupts = <50 1>, <51 1>; + debounce = <15625>; + pull-up; + }; + + pm8058_led48: led@48 { + compatible = "qcom,pm8058-keypad-led"; + reg = <0x48>; + status = "disabled"; + }; + + vibrator@4a { + compatible = "qcom,pm8058-vib"; + reg = <0x4a>; }; pm8058_mpps: mpps@50 { @@ -30,13 +39,22 @@ pm8058_mpps: mpps@50 { #interrupt-cells = <2>; }; - pwrkey@1c { - compatible = "qcom,pm8058-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8058>; - interrupts = <50 1>, <51 1>; - debounce = <15625>; - pull-up; + pm8058_led131: led@131 { + compatible = "qcom,pm8058-led"; + reg = <0x131>; + status = "disabled"; + }; + + pm8058_led132: led@132 { + compatible = "qcom,pm8058-led"; + reg = <0x132>; + status = "disabled"; + }; + + pm8058_led133: led@133 { + compatible = "qcom,pm8058-led"; + reg = <0x133>; + status = "disabled"; }; pm8058_keypad: keypad@148 { @@ -49,6 +67,17 @@ pm8058_keypad: keypad@148 { row-hold = <91500>; }; + pm8058_gpio: gpio@150 { + compatible = "qcom,pm8058-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8058_gpio 0 0 44>; + #gpio-cells = <2>; + }; + pm8058_xoadc: xoadc@197 { compatible = "qcom,pm8058-adc"; reg = <0x197>; @@ -109,35 +138,6 @@ rtc@1e8 { interrupts = <39 1>; allow-set-time; }; - - vibrator@4a { - compatible = "qcom,pm8058-vib"; - reg = <0x4a>; - }; - - pm8058_led48: led@48 { - compatible = "qcom,pm8058-keypad-led"; - reg = <0x48>; - status = "disabled"; - }; - - pm8058_led131: led@131 { - compatible = "qcom,pm8058-led"; - reg = <0x131>; - status = "disabled"; - }; - - pm8058_led132: led@132 { - compatible = "qcom,pm8058-led"; - reg = <0x132>; - status = "disabled"; - }; - - pm8058_led133: led@133 { - compatible = "qcom,pm8058-led"; - reg = <0x133>; - status = "disabled"; - }; }; }; From 0c78700a8aa03a9eb7c0be33803e07ebf146b565 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:54 +0300 Subject: [PATCH 0546/7721] ARM: dts: qcom: pm8921: reorder nodes Move pm8921 device nodes to follow the alphanumberic sorting order. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-22-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 48 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index ad41d99ab265..4697ca33666f 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -8,17 +8,14 @@ pm8921: pmic { #address-cells = <1>; #size-cells = <0>; - pm8921_gpio: gpio@150 { - - compatible = "qcom,pm8921-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8921_gpio 0 0 44>; - #gpio-cells = <2>; - + pwrkey@1c { + compatible = "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pm8921>; + interrupts = <50 IRQ_TYPE_EDGE_RISING>, + <51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; }; pm8921_mpps: mpps@50 { @@ -32,14 +29,12 @@ pm8921_mpps: mpps@50 { #interrupt-cells = <2>; }; - pwrkey@1c { - compatible = "qcom,pm8921-pwrkey"; - reg = <0x1c>; + rtc@11d { + compatible = "qcom,pm8921-rtc"; interrupt-parent = <&pm8921>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; - debounce = <15625>; - pull-up; + interrupts = <39 IRQ_TYPE_EDGE_RISING>; + reg = <0x11d>; + allow-set-time; }; pm8921_keypad: keypad@148 { @@ -53,12 +48,17 @@ pm8921_keypad: keypad@148 { row-hold = <91500>; }; - rtc@11d { - compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pm8921>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; - allow-set-time; + pm8921_gpio: gpio@150 { + + compatible = "qcom,pm8921-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8921_gpio 0 0 44>; + #gpio-cells = <2>; + }; pm8921_xoadc: xoadc@197 { From 4d6f4d391f01a90198dab3c1d1445f340f295855 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:55 +0300 Subject: [PATCH 0547/7721] ARM: dts: qcom: pm8018: move reg property Move reg property to come after compatible. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-23-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8018.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8018.dtsi b/arch/arm/boot/dts/qcom/pm8018.dtsi index c602544900b2..85ab36b6d006 100644 --- a/arch/arm/boot/dts/qcom/pm8018.dtsi +++ b/arch/arm/boot/dts/qcom/pm8018.dtsi @@ -27,9 +27,9 @@ pwrkey@1c { pm8018_mpps: mpps@50 { compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; + reg = <0x50>; interrupt-controller; #interrupt-cells = <2>; - reg = <0x50>; gpio-controller; #gpio-cells = <2>; gpio-ranges = <&pm8018_mpps 0 0 6>; @@ -37,9 +37,9 @@ pm8018_mpps: mpps@50 { rtc@11d { compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; + reg = <0x11d>; interrupt-parent = <&pm8018>; interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; allow-set-time; }; From 4181b6ce576ab8ff972ba0c7d918d9a4eae57b21 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:56 +0300 Subject: [PATCH 0548/7721] ARM: dts: qcom: pm8921: move reg property Move reg property to come after compatible. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-24-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index 4697ca33666f..fa00b57e28b9 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -31,9 +31,9 @@ pm8921_mpps: mpps@50 { rtc@11d { compatible = "qcom,pm8921-rtc"; + reg = <0x11d>; interrupt-parent = <&pm8921>; interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; allow-set-time; }; From cfe406658eb811981fd2035a20b13b9eedeeec5b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:57 +0300 Subject: [PATCH 0549/7721] ARM: dts: qcom: pm8058: use defined IRQ flags Use symbolic names for IRQ flags instead of using the numeric values. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-25-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8058.dtsi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8058.dtsi b/arch/arm/boot/dts/qcom/pm8058.dtsi index 913a511719fa..3683d7b60918 100644 --- a/arch/arm/boot/dts/qcom/pm8058.dtsi +++ b/arch/arm/boot/dts/qcom/pm8058.dtsi @@ -12,7 +12,8 @@ pwrkey@1c { compatible = "qcom,pm8058-pwrkey"; reg = <0x1c>; interrupt-parent = <&pm8058>; - interrupts = <50 1>, <51 1>; + interrupts = <50 IRQ_TYPE_EDGE_RISING>, + <51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; pull-up; }; @@ -61,7 +62,8 @@ pm8058_keypad: keypad@148 { compatible = "qcom,pm8058-keypad"; reg = <0x148>; interrupt-parent = <&pm8058>; - interrupts = <74 1>, <75 1>; + interrupts = <74 IRQ_TYPE_EDGE_RISING>, + <75 IRQ_TYPE_EDGE_RISING>; debounce = <15>; scan-delay = <32>; row-hold = <91500>; @@ -135,7 +137,7 @@ rtc@1e8 { compatible = "qcom,pm8058-rtc"; reg = <0x1e8>; interrupt-parent = <&pm8058>; - interrupts = <39 1>; + interrupts = <39 IRQ_TYPE_EDGE_RISING>; allow-set-time; }; }; From bd05d27e076430326263a59bef2770da4eccce38 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:58 +0300 Subject: [PATCH 0550/7721] ARM: dts: qcom: pm8921: switch to interrupts-extended Merge interrups and interrupt-parent properties into a single interrupts-extended property. Suggested-by: Konrad Dybcio Reviewed-by: Konrad DYbcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-26-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index fa00b57e28b9..360a179670c5 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -11,9 +11,8 @@ pm8921: pmic { pwrkey@1c { compatible = "qcom,pm8921-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pm8921>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8921 50 IRQ_TYPE_EDGE_RISING>, + <&pm8921 51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; pull-up; }; @@ -32,17 +31,15 @@ pm8921_mpps: mpps@50 { rtc@11d { compatible = "qcom,pm8921-rtc"; reg = <0x11d>; - interrupt-parent = <&pm8921>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8921 39 IRQ_TYPE_EDGE_RISING>; allow-set-time; }; pm8921_keypad: keypad@148 { compatible = "qcom,pm8921-keypad"; reg = <0x148>; - interrupt-parent = <&pm8921>; - interrupts = <74 IRQ_TYPE_EDGE_RISING>, - <75 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8921 74 IRQ_TYPE_EDGE_RISING>, + <&pm8921 75 IRQ_TYPE_EDGE_RISING>; debounce = <15>; scan-delay = <32>; row-hold = <91500>; From b721204a85d8e136252b8cffe00ba3dbb6ffce9b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:02:59 +0300 Subject: [PATCH 0551/7721] ARM: dts: qcom: pm8018: switch to interrupts-extended Merge interrups and interrupt-parent properties into a single interrupts-extended property. Suggested-by: Konrad Dybcio Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-27-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8018.dtsi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8018.dtsi b/arch/arm/boot/dts/qcom/pm8018.dtsi index 85ab36b6d006..22f3c7bac522 100644 --- a/arch/arm/boot/dts/qcom/pm8018.dtsi +++ b/arch/arm/boot/dts/qcom/pm8018.dtsi @@ -18,9 +18,8 @@ pwrkey@1c { compatible = "qcom,pm8018-pwrkey", "qcom,pm8921-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pm8018>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8018 50 IRQ_TYPE_EDGE_RISING>, + <&pm8018 51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; pull-up; }; @@ -38,8 +37,7 @@ pm8018_mpps: mpps@50 { rtc@11d { compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; reg = <0x11d>; - interrupt-parent = <&pm8018>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8018 39 IRQ_TYPE_EDGE_RISING>; allow-set-time; }; From 69a59e9fc442c814f8b0faef32ea2cca7f592083 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:00 +0300 Subject: [PATCH 0552/7721] ARM: dts: qcom: pm8058: switch to interrupts-extended Merge interrups and interrupt-parent properties into a single interrupts-extended property. Suggested-by: Konrad Dybcio Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-28-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8058.dtsi | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/qcom/pm8058.dtsi b/arch/arm/boot/dts/qcom/pm8058.dtsi index 3683d7b60918..984b79777984 100644 --- a/arch/arm/boot/dts/qcom/pm8058.dtsi +++ b/arch/arm/boot/dts/qcom/pm8058.dtsi @@ -11,9 +11,8 @@ pm8058: pmic { pwrkey@1c { compatible = "qcom,pm8058-pwrkey"; reg = <0x1c>; - interrupt-parent = <&pm8058>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8058 50 IRQ_TYPE_EDGE_RISING>, + <&pm8058 51 IRQ_TYPE_EDGE_RISING>; debounce = <15625>; pull-up; }; @@ -61,9 +60,8 @@ pm8058_led133: led@133 { pm8058_keypad: keypad@148 { compatible = "qcom,pm8058-keypad"; reg = <0x148>; - interrupt-parent = <&pm8058>; - interrupts = <74 IRQ_TYPE_EDGE_RISING>, - <75 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8058 74 IRQ_TYPE_EDGE_RISING>, + <&pm8058 75 IRQ_TYPE_EDGE_RISING>; debounce = <15>; scan-delay = <32>; row-hold = <91500>; @@ -136,8 +134,7 @@ ref_muxoff: adc-channel@f { rtc@1e8 { compatible = "qcom,pm8058-rtc"; reg = <0x1e8>; - interrupt-parent = <&pm8058>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pm8058 39 IRQ_TYPE_EDGE_RISING>; allow-set-time; }; }; From d25762097bc26394c8d88ebc9353497bdc67ec27 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:01 +0300 Subject: [PATCH 0553/7721] ARM: dts: qcom: apq8064: move RPM regulators to board files The set of regulators available over the RPM requests is not a property of the SoC. Move them to board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-29-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../dts/qcom/qcom-apq8064-asus-nexus7-flo.dts | 42 ++++---- .../boot/dts/qcom/qcom-apq8064-cm-qs600.dts | 22 ++--- .../boot/dts/qcom/qcom-apq8064-ifc6410.dts | 29 +++--- .../qcom-apq8064-sony-xperia-lagan-yuga.dts | 98 +++++++++++-------- arch/arm/boot/dts/qcom/qcom-apq8064.dtsi | 63 ------------ 5 files changed, 108 insertions(+), 146 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts index e8f893d86980..d460743fbb94 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts @@ -198,11 +198,12 @@ &pm8921 { &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs4_5_7-supply = <&pm8921_s4>; - vdd_l24-supply = <&pm8921_s1>; vdd_l25-supply = <&pm8921_s1>; vin_lvs2-supply = <&pm8921_s1>; @@ -214,7 +215,7 @@ regulators { vdd_ncp-supply = <&pm8921_l6>; /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -223,7 +224,7 @@ s1 { }; /* msm otg HSUSB_VDDCX */ - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <500000>; regulator-max-microvolt = <1150000>; qcom,switch-mode-frequency = <4800000>; @@ -236,55 +237,58 @@ s3 { * tabla2x-slim-CDC_VDD_CP * tabla2x-slim-VDDIO_CDC */ - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; regulator-always-on; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; /* mipi_dsi.1-dsi1_pll_vdda */ - l2 { + pm8921_l2: l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-always-on; }; /* msm_otg-HSUSB_3p3 */ - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3075000>; regulator-max-microvolt = <3075000>; bias-pull-down; }; /* msm_otg-HSUSB_1p8 */ - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; /* msm_sdcc.1-sdc_vdd */ - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; regulator-always-on; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; }; + pm8921_l8: l8 { + }; + /* mipi_dsi.1-dsi1_avdd */ - l11 { + pm8921_l11: l11 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; @@ -292,14 +296,14 @@ l11 { }; /* pwm_power for backlight */ - l17 { + pm8921_l17: l17 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; regulator-always-on; }; /* camera, qdsp6 */ - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; @@ -309,32 +313,32 @@ l23 { * tabla2x-slim-CDC_VDDA_A_1P2V * tabla2x-slim-VDDD_CDC_D */ - l25 { + pm8921_l25: l25 { regulator-min-microvolt = <1250000>; regulator-max-microvolt = <1250000>; bias-pull-down; }; - lvs1 { + pm8921_lvs1: lvs1 { bias-pull-down; }; - lvs4 { + pm8921_lvs4: lvs4 { bias-pull-down; }; - lvs5 { + pm8921_lvs5: lvs5 { bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; /* * mipi_dsi.1-dsi1_vddio * pil_riva-pll_vdd */ - lvs7 { + pm8921_lvs7: lvs7 { bias-pull-down; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts index d4db84e9fcf3..671d58cc2741 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts @@ -93,6 +93,8 @@ pinconf { &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs2-supply = <&pm8921_s1>; vin_lvs4_5_7-supply = <&pm8921_s4>; @@ -104,9 +106,8 @@ regulators { vdd_l27-supply = <&pm8921_s7>; vdd_l28-supply = <&pm8921_s7>; - /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -114,52 +115,51 @@ s1 { bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <4800000>; }; - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3050000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2750000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1700000>; regulator-max-microvolt = <1900000>; bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; - }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts index 6aea97a0d54d..ed86b24119c9 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts @@ -203,6 +203,8 @@ pinconf { &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs2-supply = <&pm8921_s1>; vin_lvs4_5_7-supply = <&pm8921_s4>; @@ -214,9 +216,8 @@ regulators { vdd_l27-supply = <&pm8921_s7>; vdd_l28-supply = <&pm8921_s7>; - /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -224,59 +225,63 @@ s1 { bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <4800000>; }; - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3050000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2750000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1700000>; regulator-max-microvolt = <1900000>; bias-pull-down; }; - lvs1 { + pm8921_lvs1: lvs1 { bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { + bias-pull-down; + }; + + pm8921_hdmi_switch: hdmi-switch { bias-pull-down; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts index ba18a02b1c57..2412aa3e3e8d 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts @@ -93,11 +93,25 @@ gpio_keys_pin_a: gpio-keys-active-state { &riva { pinctrl-names = "default"; pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>; + + vddcx-supply = <&pm8921_s3>; + vddmx-supply = <&pm8921_l24>; + vddpx-supply = <&pm8921_s4>; + status = "okay"; + + iris { + vddxo-supply = <&pm8921_l4>; + vddrfa-supply = <&pm8921_s2>; + vddpa-supply = <&pm8921_l10>; + vdddig-supply = <&pm8921_lvs2>; + }; }; &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_l1_l2_l12_l18-supply = <&pm8921_s4>; vin_lvs_1_3_6-supply = <&pm8921_s4>; vin_lvs_4_5_7-supply = <&pm8921_s4>; @@ -109,7 +123,7 @@ regulators { vin_l28-supply = <&pm8921_s7>; /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -117,21 +131,21 @@ s1 { bias-pull-down; }; - s2 { + pm8921_s2: s2 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <500000>; regulator-max-microvolt = <1150000>; qcom,switch-mode-frequency = <4800000>; bias-pull-down; }; - s4 { + pm8921_s4: s4 { regulator-always-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -140,205 +154,207 @@ s4 { qcom,force-mode = ; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - s8 { + pm8921_s8: s8 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; qcom,switch-mode-frequency = <1600000>; }; /* PMOS LDO */ - l1 { + pm8921_l1: l1 { regulator-always-on; regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; bias-pull-down; }; - l2 { + pm8921_l2: l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3075000>; regulator-max-microvolt = <3075000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-always-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l7 { + pm8921_l7: l7 { regulator-min-microvolt = <1850000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l8 { + pm8921_l8: l8 { regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; bias-pull-down; }; - l9 { + pm8921_l9: l9 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l10 { + pm8921_l10: l10 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; bias-pull-down; }; - l11 { + pm8921_l11: l11 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l12 { + pm8921_l12: l12 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l14 { + pm8921_l14: l14 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l15 { + pm8921_l15: l15 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l16 { + pm8921_l16: l16 { regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; bias-pull-down; }; - l17 { + pm8921_l17: l17 { regulator-min-microvolt = <2000000>; regulator-max-microvolt = <2000000>; bias-pull-down; }; - l18 { + pm8921_l18: l18 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l21 { + pm8921_l21: l21 { regulator-min-microvolt = <1050000>; regulator-max-microvolt = <1050000>; bias-pull-down; }; - l22 { + pm8921_l22: l22 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l24 { + pm8921_l24: l24 { regulator-min-microvolt = <750000>; regulator-max-microvolt = <1150000>; bias-pull-down; }; - l25 { + pm8921_l25: l25 { regulator-always-on; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <1250000>; bias-pull-down; }; - l27 { + pm8921_l27: l27 { regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; }; - l28 { + pm8921_l28: l28 { regulator-min-microvolt = <1050000>; regulator-max-microvolt = <1050000>; bias-pull-down; }; - l29 { + pm8921_l29: l29 { regulator-min-microvolt = <2000000>; regulator-max-microvolt = <2000000>; bias-pull-down; }; /* Low Voltage Switch */ - lvs1 { + pm8921_lvs1: lvs1 { bias-pull-down; }; - lvs2 { + pm8921_lvs2: lvs2 { bias-pull-down; }; - lvs3 { + pm8921_lvs3: lvs3 { bias-pull-down; }; - lvs4 { + pm8921_lvs4: lvs4 { bias-pull-down; }; - lvs5 { + pm8921_lvs5: lvs5 { bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; - lvs7 { + pm8921_lvs7: lvs7 { bias-pull-down; }; - usb-switch {}; + pm8921_usb_switch: usb-switch {}; - hdmi-switch {}; + pm8921_hdmi_switch: hdmi-switch { + bias-pull-down; + }; - ncp { + pm8921_ncp: ncp { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index f7c6db3a0fdd..95ac25e1a3b4 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -757,60 +757,6 @@ rpmcc: clock-controller { clocks = <&pxo_board>, <&cxo_board>; clock-names = "pxo", "cxo"; }; - - regulators { - compatible = "qcom,rpm-pm8921-regulators"; - - pm8921_s1: s1 {}; - pm8921_s2: s2 {}; - pm8921_s3: s3 {}; - pm8921_s4: s4 {}; - pm8921_s7: s7 {}; - pm8921_s8: s8 {}; - - pm8921_l1: l1 {}; - pm8921_l2: l2 {}; - pm8921_l3: l3 {}; - pm8921_l4: l4 {}; - pm8921_l5: l5 {}; - pm8921_l6: l6 {}; - pm8921_l7: l7 {}; - pm8921_l8: l8 {}; - pm8921_l9: l9 {}; - pm8921_l10: l10 {}; - pm8921_l11: l11 {}; - pm8921_l12: l12 {}; - pm8921_l14: l14 {}; - pm8921_l15: l15 {}; - pm8921_l16: l16 {}; - pm8921_l17: l17 {}; - pm8921_l18: l18 {}; - pm8921_l21: l21 {}; - pm8921_l22: l22 {}; - pm8921_l23: l23 {}; - pm8921_l24: l24 {}; - pm8921_l25: l25 {}; - pm8921_l26: l26 {}; - pm8921_l27: l27 {}; - pm8921_l28: l28 {}; - pm8921_l29: l29 {}; - - pm8921_lvs1: lvs1 {}; - pm8921_lvs2: lvs2 {}; - pm8921_lvs3: lvs3 {}; - pm8921_lvs4: lvs4 {}; - pm8921_lvs5: lvs5 {}; - pm8921_lvs6: lvs6 {}; - pm8921_lvs7: lvs7 {}; - - pm8921_usb_switch: usb-switch {}; - - pm8921_hdmi_switch: hdmi-switch { - bias-pull-down; - }; - - pm8921_ncp: ncp {}; - }; }; usb1: usb@12500000 { @@ -1489,10 +1435,6 @@ riva: riva-pil@3200800 { memory-region = <&wcnss_mem>; - vddcx-supply = <&pm8921_s3>; - vddmx-supply = <&pm8921_l24>; - vddpx-supply = <&pm8921_s4>; - status = "disabled"; iris { @@ -1500,11 +1442,6 @@ iris { clocks = <&cxo_board>; clock-names = "xo"; - - vddxo-supply = <&pm8921_l4>; - vddrfa-supply = <&pm8921_s2>; - vddpa-supply = <&pm8921_l10>; - vdddig-supply = <&pm8921_lvs2>; }; smd-edge { From 8299cc4b6ca3c02f2b51a8bb18beb659f3c4f4c1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:02 +0300 Subject: [PATCH 0554/7721] ARM: dts: qcom: mdm9615: move RPM regulators to board files The set of regulators available over the RPM requests is not a property of the SoC. Move them to board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-30-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcom-mdm9615-wp8548.dtsi | 136 ++++++++++++++++++ arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi | 134 ----------------- 2 files changed, 136 insertions(+), 134 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi index 27c3d92d9452..0dd52cac0e2e 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi @@ -134,6 +134,142 @@ &gsbi5_serial { pinctrl-names = "default"; }; +&rpm { + regulators { + compatible = "qcom,rpm-pm8018-regulators"; + + vin_lvs1-supply = <&pm8018_s3>; + + vdd_l7-supply = <&pm8018_s4>; + vdd_l8-supply = <&pm8018_s3>; + vdd_l9_l10_l11_l12-supply = <&pm8018_s5>; + + /* Buck SMPS */ + pm8018_s1: s1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1150000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s2: s2 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1300000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s3: s3 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s4: s4 { + regulator-min-microvolt = <2100000>; + regulator-max-microvolt = <2200000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s5: s5 { + regulator-always-on; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + /* PMOS LDO */ + pm8018_l2: l2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8018_l3: l3 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8018_l4: l4 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + bias-pull-down; + }; + + pm8018_l5: l5 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + pm8018_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + pm8018_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1900000>; + bias-pull-down; + }; + + pm8018_l8: l8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8018_l9: l9 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1150000>; + bias-pull-down; + }; + + pm8018_l10: l10 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l11: l11 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l12: l12 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l13: l13 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8018_l14: l14 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + /* Low Voltage Switch */ + pm8018_lvs1: lvs1 { + bias-pull-down; + }; + }; +}; + &sdcc1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index e0950e02a796..a5232e98ca6e 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -336,140 +336,6 @@ rpm: rpm@108000 { , ; interrupt-names = "ack", "err", "wakeup"; - - regulators { - compatible = "qcom,rpm-pm8018-regulators"; - - vin_lvs1-supply = <&pm8018_s3>; - - vdd_l7-supply = <&pm8018_s4>; - vdd_l8-supply = <&pm8018_s3>; - vdd_l9_l10_l11_l12-supply = <&pm8018_s5>; - - /* Buck SMPS */ - pm8018_s1: s1 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1150000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s2: s2 { - regulator-min-microvolt = <1225000>; - regulator-max-microvolt = <1300000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s3: s3 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s4: s4 { - regulator-min-microvolt = <2100000>; - regulator-max-microvolt = <2200000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s5: s5 { - regulator-always-on; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - /* PMOS LDO */ - pm8018_l2: l2 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - bias-pull-down; - }; - - pm8018_l3: l3 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - bias-pull-down; - }; - - pm8018_l4: l4 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - bias-pull-down; - }; - - pm8018_l5: l5 { - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - pm8018_l6: l6 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - pm8018_l7: l7 { - regulator-min-microvolt = <1850000>; - regulator-max-microvolt = <1900000>; - bias-pull-down; - }; - - pm8018_l8: l8 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - bias-pull-down; - }; - - pm8018_l9: l9 { - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1150000>; - bias-pull-down; - }; - - pm8018_l10: l10 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l11: l11 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l12: l12 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l13: l13 { - regulator-min-microvolt = <1850000>; - regulator-max-microvolt = <2950000>; - bias-pull-down; - }; - - pm8018_l14: l14 { - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - /* Low Voltage Switch */ - pm8018_lvs1: lvs1 { - bias-pull-down; - }; - }; }; }; }; From 203cc864c95891e76ddaebb447df9b80bb603263 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:03 +0300 Subject: [PATCH 0555/7721] ARM: dts: qcom: msm8660: move RPM regulators to board files The set of regulators available over the RPM requests is not a property of the SoC. Move them to board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-31-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../dts/qcom/qcom-apq8060-dragonboard.dts | 163 +++++++++++------- arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts | 10 ++ arch/arm/boot/dts/qcom/qcom-msm8660.dtsi | 66 ------- 3 files changed, 113 insertions(+), 126 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index aa6a620f180d..dbc1bfbf5a70 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -452,6 +452,8 @@ &rpm { * that means */ regulators-0 { + compatible = "qcom,rpm-pm8901-regulators"; + vdd_l0-supply = <&pm8901_s4>; vdd_l1-supply = <&vph>; vdd_l2-supply = <&vph>; @@ -469,57 +471,63 @@ regulators-0 { lvs3_in-supply = <&pm8058_s2>; mvs_in-supply = <&pm8058_s3>; - l0 { + pm8901_l0: l0 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l1 { + + pm8901_l1: l1 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l2 { + + pm8901_l2: l2 { /* TMA340 requires strictly 3.3V */ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l3 { + + pm8901_l3: l3 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + + pm8901_l4: l4 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l5 { + + pm8901_l5: l5 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l6 { + + pm8901_l6: l6 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; bias-pull-down; }; /* s0 and s1 are SAW regulators controlled over SPM */ - s2 { + pm8901_s2: s2 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + pm8901_s3: s3 { regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s4 { + pm8901_s4: s4 { regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; qcom,switch-mode-frequency = <1600000>; @@ -527,17 +535,22 @@ s4 { }; /* LVS0 thru 3 and mvs are just switches */ - lvs0 { + pm8901_lvs0: lvs0 { regulator-always-on; }; - lvs1 { }; - lvs2 { }; - lvs3 { }; - mvs { }; + pm8901_lvs1: lvs1 { }; + + pm8901_lvs2: lvs2 { }; + + pm8901_lvs3: lvs3 { }; + + pm8901_mvs: mvs { }; }; regulators-1 { + compatible = "qcom,rpm-pm8058-regulators"; + vdd_l0_l1_lvs-supply = <&pm8058_s3>; vdd_l2_l11_l12-supply = <&vph>; vdd_l3_l4_l5-supply = <&vph>; @@ -559,144 +572,169 @@ regulators-1 { vdd_s4-supply = <&vph>; vdd_ncp-supply = <&vph>; - l0 { + pm8058_l0: l0 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l1 { + + pm8058_l1: l1 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l2 { + + pm8058_l2: l2 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l3 { + + pm8058_l3: l3 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l4 { + + pm8058_l4: l4 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l5 { + + pm8058_l5: l5 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l6 { + + pm8058_l6: l6 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3600000>; bias-pull-down; }; - l7 { + + pm8058_l7: l7 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l8 { + + pm8058_l8: l8 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <3050000>; bias-pull-down; }; - l9 { + + pm8058_l9: l9 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l10 { + + pm8058_l10: l10 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l11 { + + pm8058_l11: l11 { regulator-min-microvolt = <1500000>; regulator-max-microvolt = <1500000>; bias-pull-down; }; - l12 { + + pm8058_l12: l12 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; bias-pull-down; }; - l13 { + + pm8058_l13: l13 { regulator-min-microvolt = <2050000>; regulator-max-microvolt = <2050000>; bias-pull-down; }; - l14 { + + pm8058_l14: l14 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; }; - l15 { + + pm8058_l15: l15 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l16 { + + pm8058_l16: l16 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; regulator-always-on; }; - l17 { + + pm8058_l17: l17 { // 1.5V according to schematic regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l18 { + + pm8058_l18: l18 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; bias-pull-down; }; - l19 { + + pm8058_l19: l19 { regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; bias-pull-down; }; - l20 { + + pm8058_l20: l20 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l21 { + + pm8058_l21: l21 { // 1.1 V according to schematic regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; regulator-always-on; }; - l22 { + + pm8058_l22: l22 { // 1.2 V according to schematic regulator-min-microvolt = <1150000>; regulator-max-microvolt = <1150000>; bias-pull-down; }; - l23 { + + pm8058_l23: l23 { // Unused regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l24 { - // Unused - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - bias-pull-down; - }; - l25 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - bias-pull-down; - }; - s0 { + pm8058_l24: l24 { + // Unused + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8058_l25: l25 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8058_s0: s0 { // regulator-min-microvolt = <500000>; // regulator-max-microvolt = <1325000>; regulator-min-microvolt = <1100000>; @@ -704,7 +742,8 @@ s0 { qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s1 { + + pm8058_s1: s1 { // regulator-min-microvolt = <500000>; // regulator-max-microvolt = <1250000>; regulator-min-microvolt = <1100000>; @@ -712,21 +751,24 @@ s1 { qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s2 { + + pm8058_s2: s2 { // 1.3 V according to schematic regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + + pm8058_s3: s3 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; regulator-always-on; bias-pull-down; }; - s4 { + + pm8058_s4: s4 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; qcom,switch-mode-frequency = <1600000>; @@ -735,14 +777,15 @@ s4 { }; /* LVS0 and LVS1 are just switches */ - lvs0 { - bias-pull-down; - }; - lvs1 { + pm8058_lvs0: lvs0 { bias-pull-down; }; - ncp { + pm8058_lvs1: lvs1 { + bias-pull-down; + }; + + pm8058_ncp: ncp { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts index be2fbc1e0950..69fe651f564d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts @@ -65,6 +65,16 @@ MATRIX_KEY(5, 4, KEY_MENU) keypad,num-columns = <5>; }; +&rpm { + regulators-0 { + compatible = "qcom,rpm-pm8901-regulators"; + }; + + regulators-1 { + compatible = "qcom,rpm-pm8058-regulators"; + }; +}; + /* eMMC */ &sdcc1 { vmmc-supply = <&vsdcc_fixed>; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index eef4712bbcc4..a7c245b9c8f9 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -347,72 +347,6 @@ rpmcc: clock-controller { clocks = <&pxo_board>; clock-names = "pxo"; }; - - regulators-0 { - compatible = "qcom,rpm-pm8901-regulators"; - - pm8901_l0: l0 {}; - pm8901_l1: l1 {}; - pm8901_l2: l2 {}; - pm8901_l3: l3 {}; - pm8901_l4: l4 {}; - pm8901_l5: l5 {}; - pm8901_l6: l6 {}; - - /* S0 and S1 Handled as SAW regulators by SPM */ - pm8901_s2: s2 {}; - pm8901_s3: s3 {}; - pm8901_s4: s4 {}; - - pm8901_lvs0: lvs0 {}; - pm8901_lvs1: lvs1 {}; - pm8901_lvs2: lvs2 {}; - pm8901_lvs3: lvs3 {}; - - pm8901_mvs: mvs {}; - }; - - regulators-1 { - compatible = "qcom,rpm-pm8058-regulators"; - - pm8058_l0: l0 {}; - pm8058_l1: l1 {}; - pm8058_l2: l2 {}; - pm8058_l3: l3 {}; - pm8058_l4: l4 {}; - pm8058_l5: l5 {}; - pm8058_l6: l6 {}; - pm8058_l7: l7 {}; - pm8058_l8: l8 {}; - pm8058_l9: l9 {}; - pm8058_l10: l10 {}; - pm8058_l11: l11 {}; - pm8058_l12: l12 {}; - pm8058_l13: l13 {}; - pm8058_l14: l14 {}; - pm8058_l15: l15 {}; - pm8058_l16: l16 {}; - pm8058_l17: l17 {}; - pm8058_l18: l18 {}; - pm8058_l19: l19 {}; - pm8058_l20: l20 {}; - pm8058_l21: l21 {}; - pm8058_l22: l22 {}; - pm8058_l23: l23 {}; - pm8058_l24: l24 {}; - pm8058_l25: l25 {}; - - pm8058_s0: s0 {}; - pm8058_s1: s1 {}; - pm8058_s2: s2 {}; - pm8058_s3: s3 {}; - pm8058_s4: s4 {}; - - pm8058_lvs0: lvs0 {}; - pm8058_lvs1: lvs1 {}; - - pm8058_ncp: ncp {}; - }; }; amba { From 4187a3f87b95070bee5be317202b9b11b2273853 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:04 +0300 Subject: [PATCH 0556/7721] ARM: dts: qcom: msm8960: drop useless rpm regulators node The set of regulators available over the RPM requests is not a property of the SoC. The only msm8960 board file (qcom-msm8960-cdp) also defines this node together with the compatible string. Drop the useless device node. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-32-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index 774f507fa25a..f420740e068e 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -200,10 +200,6 @@ rpm: rpm@108000 { , ; interrupt-names = "ack", "err", "wakeup"; - - regulators { - compatible = "qcom,rpm-pm8921-regulators"; - }; }; acc0: clock-controller@2088000 { From 74eafc5f82a59568354076295688e0d9af43659f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:05 +0300 Subject: [PATCH 0557/7721] ARM: dts: qcom: msm8974: move regulators to board files The vph-pwr and boost regulators (even if they are unified by design) are not a property of SoC, so move them to board files. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-33-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../dts/qcom/qcom-apq8074-dragonboard.dts | 27 +++++++++++++++++++ .../qcom-msm8974-lge-nexus5-hammerhead.dts | 27 +++++++++++++++++++ .../qcom/qcom-msm8974-sony-xperia-rhine.dtsi | 27 +++++++++++++++++++ arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 27 ------------------- .../qcom/qcom-msm8974pro-fairphone-fp2.dts | 27 +++++++++++++++++++ .../qcom/qcom-msm8974pro-oneplus-bacon.dts | 27 +++++++++++++++++++ .../dts/qcom/qcom-msm8974pro-samsung-klte.dts | 10 ++++++- ...-msm8974pro-sony-xperia-shinano-castor.dts | 27 +++++++++++++++++++ 8 files changed, 171 insertions(+), 28 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts index 950fa652f985..d7fb3e0e8886 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts @@ -49,6 +49,33 @@ mpss_region: mpss@ac00000 { no-map; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_uart2 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts index da99f770d4f5..ca402b4a68bd 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -60,6 +60,33 @@ vibrator { enable-gpios = <&tlmm 60 GPIO_ACTIVE_HIGH>; }; + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; + vreg_wlan: wlan-regulator { compatible = "regulator-fixed"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi index 23ae474698aa..a43341ae4495 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi @@ -65,6 +65,33 @@ ramoops@3e8e0000 { pmsg-size = <0x80000>; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index 0bc2e66d15b1..b3a0a71c6369 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -2408,31 +2408,4 @@ timer { ; clock-frequency = <19200000>; }; - - vreg_boost: vreg-boost { - compatible = "regulator-fixed"; - - regulator-name = "vreg-boost"; - regulator-min-microvolt = <3150000>; - regulator-max-microvolt = <3150000>; - - regulator-always-on; - regulator-boot-on; - - gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; - enable-active-high; - - pinctrl-names = "default"; - pinctrl-0 = <&boost_bypass_n_pin>; - }; - - vreg_vph_pwr: vreg-vph-pwr { - compatible = "regulator-fixed"; - regulator-name = "vph-pwr"; - - regulator-min-microvolt = <3600000>; - regulator-max-microvolt = <3600000>; - - regulator-always-on; - }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts index 6c4153689b39..66c422004dcd 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts @@ -57,6 +57,33 @@ vibrator { enable-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; vcc-supply = <&pm8941_l18>; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts index c0ca264d8140..6d1412aec45a 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts @@ -51,6 +51,33 @@ event-hall-sensor { debounce-interval = <150>; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c1 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts index 325feb89b343..ca3aa16b4b10 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts @@ -155,7 +155,15 @@ vreg_panel: panel-regulator { enable-active-high; }; - /delete-node/ vreg-boost; + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts index 0798cce3dbea..818ff5835031 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts @@ -84,6 +84,33 @@ vreg_vsp: lcd-dcdc-regulator { pinctrl-0 = <&lcd_dcdc_en_pin_a>; }; + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; + vreg_wlan: wlan-regulator { compatible = "regulator-fixed"; From 61023dd0ec536d0bd62b88e1230edd46576c0dfb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:06 +0300 Subject: [PATCH 0558/7721] ARM: dts: qcom: pm8921: Disable keypad by default Since keypad is used only by some devices, disable it by default and enable explicitly. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-34-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 1 + arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index 360a179670c5..058962af3005 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -43,6 +43,7 @@ pm8921_keypad: keypad@148 { debounce = <15>; scan-delay = <32>; row-hold = <91500>; + status = "disabled"; }; pm8921_gpio: gpio@150 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts index a5ea4843db43..36f4c997b0b3 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts @@ -102,6 +102,8 @@ MATRIX_KEY(0, 3, KEY_CAMERA) >; keypad,num-rows = <1>; keypad,num-columns = <5>; + + status = "okay"; }; &rpm { From 3f0533c6f2708d5851ce4852beb0dc09fc5264f3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:07 +0300 Subject: [PATCH 0559/7721] ARM: dts: qcom: apq8060-dragonboard: rename mpp ADC channels to adc-channel Use generic `adc-channel@N' node names for board-specific ADC channels (routed to MPP pins) to follow the schema. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230928110309.1212221-35-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- .../arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index dbc1bfbf5a70..009afd8212c2 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -997,23 +997,27 @@ &pm8058_xoadc { xoadc-ref-supply = <&pm8058_l18>; /* Board-specific channels */ - mpp5@5 { + adc-channel@5 { /* Connected to AOUT of ALS sensor */ reg = <0x00 0x05>; }; - mpp6@6 { + + adc-channel@6 { /* Connected to test point TP43 */ reg = <0x00 0x06>; }; - mpp7@7 { + + adc-channel@7 { /* Connected to battery thermistor */ reg = <0x00 0x07>; }; - mpp8@8 { + + adc-channel@8 { /* Connected to battery ID detector */ reg = <0x00 0x08>; }; - mpp9@9 { + + adc-channel@9 { /* Connected to XO thermistor */ reg = <0x00 0x09>; }; From 77c1b2b30e0f03d4e0e2f871a62d18c57fc17d10 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:08 +0300 Subject: [PATCH 0560/7721] ARM: dts: qcom: ipq8064: drop qcom, prefix from SSBI node name Device tree node names should not use vendor prefix, they contain a generic name of the device. Drop the qcom, prefix from the SSBI node name. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230928110309.1212221-36-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi index 6198f42f6a9c..c3677440b786 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi @@ -366,7 +366,7 @@ rpmcc: clock-controller { }; }; - qcom,ssbi@500000 { + ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x00500000 0x1000>; qcom,controller-type = "pmic-arbiter"; From bded0924f6a424eb9bf675759aa90741940e5628 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 28 Sep 2023 14:03:09 +0300 Subject: [PATCH 0561/7721] ARM: dts: qcom: mdm9615: drop qcom, prefix from SSBI node name Device tree node names should not use vendor prefix, they contain a generic name of the device. Drop the qcom, prefix from the SSBI node name. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230928110309.1212221-37-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index a5232e98ca6e..34c60994d026 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -256,7 +256,7 @@ gsbi5_serial: serial@16440000 { }; }; - ssbi: qcom,ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; From 5a17f863c042beef7835688fe7a9667083530df2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:30 +0100 Subject: [PATCH 0562/7721] dt-bindings: mmc: samsung,exynos-dw-mshc: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. While re-indenting the first enum, put also axis,artpec8-dw-mshc in alphabetical order. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Acked-by: Ulf Hansson Link: https://lore.kernel.org/r/20231108104343.24192-5-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/mmc/samsung,exynos-dw-mshc.yaml | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml index 6ee78a38bd74..5fe65795f796 100644 --- a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml @@ -14,15 +14,22 @@ maintainers: properties: compatible: - enum: - - samsung,exynos4210-dw-mshc - - samsung,exynos4412-dw-mshc - - samsung,exynos5250-dw-mshc - - samsung,exynos5420-dw-mshc - - samsung,exynos5420-dw-mshc-smu - - samsung,exynos7-dw-mshc - - samsung,exynos7-dw-mshc-smu - - axis,artpec8-dw-mshc + oneOf: + - enum: + - axis,artpec8-dw-mshc + - samsung,exynos4210-dw-mshc + - samsung,exynos4412-dw-mshc + - samsung,exynos5250-dw-mshc + - samsung,exynos5420-dw-mshc + - samsung,exynos5420-dw-mshc-smu + - samsung,exynos7-dw-mshc + - samsung,exynos7-dw-mshc-smu + - items: + - enum: + - samsung,exynos5433-dw-mshc-smu + - samsung,exynos7885-dw-mshc-smu + - samsung,exynos850-dw-mshc-smu + - const: samsung,exynos7-dw-mshc-smu reg: maxItems: 1 From 577d71544871b075a25a09e4c5aa31008850c0a8 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 13 Nov 2023 10:37:15 +0000 Subject: [PATCH 0563/7721] ASoC: rt5682s: Add LDO output selection for dacref Add LDO output selection for dacref. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/62cad4e51c044108bad872ab349e36f8@realtek.com Signed-off-by: Mark Brown --- include/sound/rt5682s.h | 8 ++++++++ sound/soc/codecs/rt5682s.c | 23 +++++++++++++++++++++++ sound/soc/codecs/rt5682s.h | 7 +++++++ 3 files changed, 38 insertions(+) diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h index 66ca0c75b914..006e6003d11c 100644 --- a/include/sound/rt5682s.h +++ b/include/sound/rt5682s.h @@ -31,6 +31,13 @@ enum rt5682s_dai_clks { RT5682S_DAI_NUM_CLKS, }; +enum { + RT5682S_LDO_1_607V, + RT5682S_LDO_1_5V, + RT5682S_LDO_1_406V, + RT5682S_LDO_1_731V, +}; + struct rt5682s_platform_data { enum rt5682s_dmic1_data_pin dmic1_data_pin; enum rt5682s_dmic1_clk_pin dmic1_clk_pin; @@ -38,6 +45,7 @@ struct rt5682s_platform_data { unsigned int dmic_clk_rate; unsigned int dmic_delay; unsigned int amic_delay; + unsigned int ldo_dacref; bool dmic_clk_driving_high; const char *dai_clk_names[RT5682S_DAI_NUM_CLKS]; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c261c33c4be7..3322056bbb3b 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2971,6 +2971,8 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) &rt5682s->pdata.dmic_delay); device_property_read_u32(dev, "realtek,amic-delay-ms", &rt5682s->pdata.amic_delay); + device_property_read_u32(dev, "realtek,ldo-sel", + &rt5682s->pdata.ldo_dacref); if (device_property_read_string_array(dev, "clock-output-names", rt5682s->pdata.dai_clk_names, @@ -3250,6 +3252,27 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) break; } + /* LDO output voltage control */ + switch (rt5682s->pdata.ldo_dacref) { + case RT5682S_LDO_1_607V: + break; + case RT5682S_LDO_1_5V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_5V); + break; + case RT5682S_LDO_1_406V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_406V); + break; + case RT5682S_LDO_1_731V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_731V); + break; + default: + dev_warn(&i2c->dev, "invalid LDO output setting.\n"); + break; + } + INIT_DELAYED_WORK(&rt5682s->jack_detect_work, rt5682s_jack_detect_handler); INIT_DELAYED_WORK(&rt5682s->jd_check_work, rt5682s_jd_check_handler); diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 1d79d432d0d8..67f42898de96 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1263,6 +1263,13 @@ #define RT5682S_JDH_NO_PLUG (0x1 << 4) #define RT5682S_JDH_PLUG (0x0 << 4) +/* Bias current control 7 (0x0110) */ +#define RT5682S_LDO_DACREF_MASK (0x3 << 4) +#define RT5682S_LDO_DACREF_1_607V (0x0 << 4) +#define RT5682S_LDO_DACREF_1_5V (0x1 << 4) +#define RT5682S_LDO_DACREF_1_406V (0x2 << 4) +#define RT5682S_LDO_DACREF_1_731V (0x3 << 4) + /* Charge Pump Internal Register1 (0x0125) */ #define RT5682S_CP_CLK_HP_MASK (0x3 << 4) #define RT5682S_CP_CLK_HP_100KHZ (0x0 << 4) From 34b98a5f7a185c19715cc98c57d7e27b4785dfdf Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 12 Nov 2023 01:42:36 +0300 Subject: [PATCH 0564/7721] drm/virtio: Fix return value for VIRTGPU_CONTEXT_PARAM_DEBUG_NAME The strncpy_from_user() returns number of copied bytes and not zero on success. The non-zero return value of ioctl is treated as error. Return zero on success instead of the number of copied bytes. Fixes: 7add80126bce ("drm/uapi: add explicit virtgpu context debug name") Signed-off-by: Dmitry Osipenko Reviewed-by: Gurchetan Singh Link: https://patchwork.freedesktop.org/patch/msgid/20231111224236.890431-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 1e2042419f95..e4f76f315550 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -665,6 +665,7 @@ static int virtio_gpu_context_init_ioctl(struct drm_device *dev, goto out_unlock; vfpriv->explicit_debug_name = true; + ret = 0; break; default: ret = -EINVAL; From 8fedaaca40711a7f3a00f3c20ecdca7c2313054a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 13 Nov 2023 08:50:30 -0800 Subject: [PATCH 0565/7721] net: dsa: tag_rtl4_a: Use existing ETH_P_REALTEK constant No functional change, uses the existing ETH_P_REALTEK constant already defined in if_ether.h. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20231113165030.2440083-1-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- net/dsa/tag_rtl4_a.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c index 4da5bad1a7aa..a019226ec6d2 100644 --- a/net/dsa/tag_rtl4_a.c +++ b/net/dsa/tag_rtl4_a.c @@ -23,7 +23,6 @@ #define RTL4_A_NAME "rtl4a" #define RTL4_A_HDR_LEN 4 -#define RTL4_A_ETHERTYPE 0x8899 #define RTL4_A_PROTOCOL_SHIFT 12 /* * 0x1 = Realtek Remote Control protocol (RRCP) @@ -54,7 +53,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb, /* Set Ethertype */ p = (__be16 *)tag; - *p = htons(RTL4_A_ETHERTYPE); + *p = htons(ETH_P_REALTEK); out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT); /* The lower bits indicate the port number */ @@ -82,7 +81,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, tag = dsa_etype_header_pos_rx(skb); p = (__be16 *)tag; etype = ntohs(*p); - if (etype != RTL4_A_ETHERTYPE) { + if (etype != ETH_P_REALTEK) { /* Not custom, just pass through */ netdev_dbg(dev, "non-realtek ethertype 0x%04x\n", etype); return skb; From aa6908ca3bd1e713fd6cd8d7193a008f060bf7d9 Mon Sep 17 00:00:00 2001 From: Justin Bronder Date: Mon, 13 Nov 2023 15:10:20 -0800 Subject: [PATCH 0566/7721] i40e: increase max descriptors for XL710 In Tables 8-12 and 8-22 in the X710/XXV710/XL710 datasheet, the QLEN description states that the maximum size of the descriptor queue is 8k minus 32, or 8160. Signed-off-by: Justin Bronder Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-2-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + .../net/ethernet/intel/i40e/i40e_ethtool.c | 25 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 1bf424ac3145..e070a1b908f7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -24,6 +24,7 @@ #define I40E_MAX_VEB 16 #define I40E_MAX_NUM_DESCRIPTORS 4096 +#define I40E_MAX_NUM_DESCRIPTORS_XL710 8160 #define I40E_MAX_CSR_SPACE (4 * 1024 * 1024 - 64 * 1024) #define I40E_DEFAULT_NUM_DESCRIPTORS 512 #define I40E_REQ_DESCRIPTOR_MULTIPLE 32 diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fd7163128c4d..2e781fe24bba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2015,6 +2015,18 @@ static void i40e_get_drvinfo(struct net_device *netdev, drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN; } +static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + + switch (hw->mac.type) { + case I40E_MAC_XL710: + return I40E_MAX_NUM_DESCRIPTORS_XL710; + default: + return I40E_MAX_NUM_DESCRIPTORS; + } +} + static void i40e_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, @@ -2024,8 +2036,8 @@ static void i40e_get_ringparam(struct net_device *netdev, struct i40e_pf *pf = np->vsi->back; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; - ring->rx_max_pending = I40E_MAX_NUM_DESCRIPTORS; - ring->tx_max_pending = I40E_MAX_NUM_DESCRIPTORS; + ring->rx_max_pending = i40e_get_max_num_descriptors(pf); + ring->tx_max_pending = i40e_get_max_num_descriptors(pf); ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; ring->rx_pending = vsi->rx_rings[0]->count; @@ -2050,12 +2062,12 @@ static int i40e_set_ringparam(struct net_device *netdev, struct kernel_ethtool_ringparam *kernel_ring, struct netlink_ext_ack *extack) { + u32 new_rx_count, new_tx_count, max_num_descriptors; struct i40e_ring *tx_rings = NULL, *rx_rings = NULL; struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_hw *hw = &np->vsi->back->hw; struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; - u32 new_rx_count, new_tx_count; u16 tx_alloc_queue_pairs; int timeout = 50; int i, err = 0; @@ -2063,14 +2075,15 @@ static int i40e_set_ringparam(struct net_device *netdev, if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - if (ring->tx_pending > I40E_MAX_NUM_DESCRIPTORS || + max_num_descriptors = i40e_get_max_num_descriptors(pf); + if (ring->tx_pending > max_num_descriptors || ring->tx_pending < I40E_MIN_NUM_DESCRIPTORS || - ring->rx_pending > I40E_MAX_NUM_DESCRIPTORS || + ring->rx_pending > max_num_descriptors || ring->rx_pending < I40E_MIN_NUM_DESCRIPTORS) { netdev_info(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n", ring->tx_pending, ring->rx_pending, - I40E_MIN_NUM_DESCRIPTORS, I40E_MAX_NUM_DESCRIPTORS); + I40E_MIN_NUM_DESCRIPTORS, max_num_descriptors); return -EINVAL; } From add35e623e77fd48c4720d0d8cf1f0f425149ed4 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Mon, 13 Nov 2023 15:10:21 -0800 Subject: [PATCH 0567/7721] i40e: add an error code check in i40e_vsi_setup check the value of 'ret' after calling 'i40e_vsi_config_rss'. Signed-off-by: Su Hui Reviewed-by: Dan Carpenter Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-3-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f7a332e51524..af8491f3211d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -14591,9 +14591,13 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) && (vsi->type == I40E_VSI_VMDQ2)) { ret = i40e_vsi_config_rss(vsi); + if (ret) + goto err_config; } return vsi; +err_config: + i40e_vsi_clear_rings(vsi); err_rings: i40e_vsi_free_q_vectors(vsi); err_msix: From 2c0fa38a579f96cdee372965d6b0c06c40806cad Mon Sep 17 00:00:00 2001 From: Andrii Staikov Date: Mon, 13 Nov 2023 15:10:22 -0800 Subject: [PATCH 0568/7721] i40e: Change user notification of non-SFP module in i40e_get_module_info() Make the driver not produce an error message on "ethtool -m ethX" command when a non-SFP module is encountered hence there is no possibility to read the EEPROM. Make the message to appear in the debug log rather than as an error string. Change the return code to -EOPNOTSUPP and the string to make it more verbose. Signed-off-by: Andrii Staikov Reviewed-by: Wojciech Drewek CC: Stefan Assmann CC: Michal Schmidt Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-4-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 2e781fe24bba..93525a982df2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5584,8 +5584,8 @@ static int i40e_get_module_info(struct net_device *netdev, modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN; break; default: - netdev_err(vsi->netdev, "Module type unrecognized\n"); - return -EINVAL; + netdev_dbg(vsi->netdev, "SFP module type unrecognized or no SFP connector used.\n"); + return -EOPNOTSUPP; } return 0; } From e8fcf58f6109cb79370ff38174dd442fbeeb756a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:23 -0800 Subject: [PATCH 0569/7721] i40e: Remove unused flags The flag I40E_FLAG_RX_CSUM_ENABLED and I40E_HW_FLAG_DROP_MODE are set and never read. Remove them. Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-5-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e.h | 57 +++++++++---------- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_type.h | 3 +- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index e070a1b908f7..7d83dcbd9294 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -502,33 +502,32 @@ struct i40e_pf { #define I40E_HW_RESTART_AUTONEG BIT(18) u32 flags; -#define I40E_FLAG_RX_CSUM_ENABLED BIT(0) -#define I40E_FLAG_MSI_ENABLED BIT(1) -#define I40E_FLAG_MSIX_ENABLED BIT(2) -#define I40E_FLAG_RSS_ENABLED BIT(3) -#define I40E_FLAG_VMDQ_ENABLED BIT(4) -#define I40E_FLAG_SRIOV_ENABLED BIT(5) -#define I40E_FLAG_DCB_CAPABLE BIT(6) -#define I40E_FLAG_DCB_ENABLED BIT(7) -#define I40E_FLAG_FD_SB_ENABLED BIT(8) -#define I40E_FLAG_FD_ATR_ENABLED BIT(9) -#define I40E_FLAG_MFP_ENABLED BIT(10) -#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT(11) -#define I40E_FLAG_VEB_MODE_ENABLED BIT(12) -#define I40E_FLAG_VEB_STATS_ENABLED BIT(13) -#define I40E_FLAG_LINK_POLLING_ENABLED BIT(14) -#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT(15) -#define I40E_FLAG_LEGACY_RX BIT(16) -#define I40E_FLAG_PTP BIT(17) -#define I40E_FLAG_IWARP_ENABLED BIT(18) -#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(19) -#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(20) -#define I40E_FLAG_TC_MQPRIO BIT(21) -#define I40E_FLAG_FD_SB_INACTIVE BIT(22) -#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(23) -#define I40E_FLAG_DISABLE_FW_LLDP BIT(24) -#define I40E_FLAG_RS_FEC BIT(25) -#define I40E_FLAG_BASE_R_FEC BIT(26) +#define I40E_FLAG_MSI_ENABLED BIT(0) +#define I40E_FLAG_MSIX_ENABLED BIT(1) +#define I40E_FLAG_RSS_ENABLED BIT(2) +#define I40E_FLAG_VMDQ_ENABLED BIT(3) +#define I40E_FLAG_SRIOV_ENABLED BIT(4) +#define I40E_FLAG_DCB_CAPABLE BIT(5) +#define I40E_FLAG_DCB_ENABLED BIT(6) +#define I40E_FLAG_FD_SB_ENABLED BIT(7) +#define I40E_FLAG_FD_ATR_ENABLED BIT(8) +#define I40E_FLAG_MFP_ENABLED BIT(9) +#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT(10) +#define I40E_FLAG_VEB_MODE_ENABLED BIT(11) +#define I40E_FLAG_VEB_STATS_ENABLED BIT(12) +#define I40E_FLAG_LINK_POLLING_ENABLED BIT(13) +#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT(14) +#define I40E_FLAG_LEGACY_RX BIT(15) +#define I40E_FLAG_PTP BIT(16) +#define I40E_FLAG_IWARP_ENABLED BIT(17) +#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(18) +#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(19) +#define I40E_FLAG_TC_MQPRIO BIT(20) +#define I40E_FLAG_FD_SB_INACTIVE BIT(21) +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(22) +#define I40E_FLAG_DISABLE_FW_LLDP BIT(23) +#define I40E_FLAG_RS_FEC BIT(24) +#define I40E_FLAG_BASE_R_FEC BIT(25) /* TOTAL_PORT_SHUTDOWN * Allows to physically disable the link on the NIC's port. * If enabled, (after link down request from the OS) @@ -550,8 +549,8 @@ struct i40e_pf { * the link is being brought down by clearing bit (I40E_AQ_PHY_ENABLE_LINK) * in abilities field of i40e_aq_set_phy_config structure */ -#define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED BIT(27) -#define I40E_FLAG_VF_VLAN_PRUNING BIT(28) +#define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED BIT(26) +#define I40E_FLAG_VF_VLAN_PRUNING BIT(27) struct i40e_client_instance *cinst; bool stat_offsets_loaded; diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 9ce6e633cc2f..9a5a47b29bb7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -555,10 +555,8 @@ static void i40e_set_hw_flags(struct i40e_hw *hw) if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && - aq->api_min_ver >= 8)) { + aq->api_min_ver >= 8)) hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT; - hw->flags |= I40E_HW_FLAG_DROP_MODE; - } if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index af8491f3211d..2158a93261cf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -12717,9 +12717,7 @@ static int i40e_sw_init(struct i40e_pf *pf) u16 pow; /* Set default capability flags */ - pf->flags = I40E_FLAG_RX_CSUM_ENABLED | - I40E_FLAG_MSI_ENABLED | - I40E_FLAG_MSIX_ENABLED; + pf->flags = I40E_FLAG_MSI_ENABLED | I40E_FLAG_MSIX_ENABLED; /* Set default ITR */ pf->rx_itr_default = I40E_ITR_RX_DEF; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index aff6dc6afbe2..060aac35d945 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -553,8 +553,7 @@ struct i40e_hw { #define I40E_HW_FLAG_FW_LLDP_STOPPABLE BIT_ULL(4) #define I40E_HW_FLAG_FW_LLDP_PERSISTENT BIT_ULL(5) #define I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED BIT_ULL(6) -#define I40E_HW_FLAG_DROP_MODE BIT_ULL(7) -#define I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE BIT_ULL(8) +#define I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE BIT_ULL(7) u64 flags; /* Used in set switch config AQ command */ From addca9175e5f74cf29e8ad918c38c09b8663b5b8 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:24 -0800 Subject: [PATCH 0570/7721] i40e: Remove _t suffix from enum type names Enum type names should not be suffixed by '_t'. Either to use 'typedef enum name name_t' to so plain 'name_t var' instead of 'enum name_t var'. Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-6-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e.h | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 6 +++--- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 7d83dcbd9294..f47c2e6bf786 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -79,7 +79,7 @@ #define I40E_MAX_BW_INACTIVE_ACCUM 4 /* accumulate 4 credits max */ /* driver state flags */ -enum i40e_state_t { +enum i40e_state { __I40E_TESTING, __I40E_CONFIG_BUSY, __I40E_CONFIG_DONE, @@ -127,7 +127,7 @@ enum i40e_state_t { BIT_ULL(__I40E_PF_RESET_AND_REBUILD_REQUESTED) /* VSI state flags */ -enum i40e_vsi_state_t { +enum i40e_vsi_state { __I40E_VSI_DOWN, __I40E_VSI_NEEDS_RESTART, __I40E_VSI_SYNCING_FILTERS, diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 20b77398f060..65c714d0bfff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -35,7 +35,7 @@ enum i40e_ptp_pin { GPIO_4 }; -enum i40e_can_set_pins_t { +enum i40e_can_set_pins { CANT_DO_PINS = -1, CAN_SET_PINS, CAN_DO_PINS @@ -193,7 +193,7 @@ static bool i40e_is_ptp_pin_dev(struct i40e_hw *hw) * return CAN_DO_PINS if pins can be manipulated within a NIC or * return CANT_DO_PINS otherwise. **/ -static enum i40e_can_set_pins_t i40e_can_set_pins(struct i40e_pf *pf) +static enum i40e_can_set_pins i40e_can_set_pins(struct i40e_pf *pf) { if (!i40e_is_ptp_pin_dev(&pf->hw)) { dev_warn(&pf->pdev->dev, @@ -1071,7 +1071,7 @@ static void i40e_ptp_set_pins_hw(struct i40e_pf *pf) static int i40e_ptp_set_pins(struct i40e_pf *pf, struct i40e_ptp_pins_settings *pins) { - enum i40e_can_set_pins_t pin_caps = i40e_can_set_pins(pf); + enum i40e_can_set_pins pin_caps = i40e_can_set_pins(pf); int i = 0; if (pin_caps == CANT_DO_PINS) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 421fe5675584..1c667408f687 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -58,7 +58,7 @@ static inline u16 i40e_intrl_usec_to_reg(int intrl) * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any * register but instead is a special value meaning "don't update" ITR0/1/2. */ -enum i40e_dyn_idx_t { +enum i40e_dyn_idx { I40E_IDX_ITR0 = 0, I40E_IDX_ITR1 = 1, I40E_IDX_ITR2 = 2, @@ -306,7 +306,7 @@ struct i40e_rx_queue_stats { u64 page_busy_count; }; -enum i40e_ring_state_t { +enum i40e_ring_state { __I40E_TX_FDIR_INIT_DONE, __I40E_TX_XPS_INIT_DONE, __I40E_RING_STATE_NBITS /* must be last */ From 70756d0a4727fe8fa23afaee76028299af4062dd Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:25 -0800 Subject: [PATCH 0571/7721] i40e: Use DECLARE_BITMAP for flags and hw_features fields in i40e_pf Convert flags and hw_features fields from i40e_pf from u32 to bitmaps and their usage to use bit access functions. Changes: - Convert "pf_ptr->(flags|hw_features) & FL" to "test_bit(FL, ...)" - Convert "pf_ptr->(flags|hw_features) |= FL" to "set_bit(FL, ...)" - Convert "pf_ptr->(flags|hw_features) &= ~FL" to "clear_bit(FL, ...)" - Rename flag field to bitno in i40e_priv_flags and adjust ethtool callbacks to work with flags bitmap - Rename flag names where '_ENABLED'->'_ENA' and '_DISABLED'->'_DIS' like in ice driver Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-7-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e.h | 165 ++--- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 24 +- .../net/ethernet/intel/i40e/i40e_debugfs.c | 4 +- .../net/ethernet/intel/i40e/i40e_ethtool.c | 209 ++++--- drivers/net/ethernet/intel/i40e/i40e_main.c | 587 +++++++++--------- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 26 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 20 +- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 4 +- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 20 +- 9 files changed, 544 insertions(+), 515 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index f47c2e6bf786..ba87870e0fb4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -34,11 +34,11 @@ #define I40E_MIN_VSI_ALLOC 83 /* LAN, ATR, FCOE, 64 VF */ /* max 16 qps */ #define i40e_default_queues_per_vmdq(pf) \ - (((pf)->hw_features & I40E_HW_RSS_AQ_CAPABLE) ? 4 : 1) + (test_bit(I40E_HW_RSS_AQ_CAPABLE, (pf)->hw_features) ? 4 : 1) #define I40E_DEFAULT_QUEUES_PER_VF 4 #define I40E_MAX_VF_QUEUES 16 #define i40e_pf_get_max_q_per_tc(pf) \ - (((pf)->hw_features & I40E_HW_128_QP_RSS_CAPABLE) ? 128 : 64) + (test_bit(I40E_HW_128_QP_RSS_CAPABLE, (pf)->hw_features) ? 128 : 64) #define I40E_FDIR_RING_COUNT 32 #define I40E_MAX_AQ_BUF_SIZE 4096 #define I40E_AQ_LEN 256 @@ -139,6 +139,82 @@ enum i40e_vsi_state { __I40E_VSI_STATE_SIZE__, }; +enum i40e_pf_hw_features { + I40E_HW_RSS_AQ_CAPABLE, + I40E_HW_128_QP_RSS_CAPABLE, + I40E_HW_ATR_EVICT_CAPABLE, + I40E_HW_WB_ON_ITR_CAPABLE, + I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, + I40E_HW_NO_PCI_LINK_CHECK, + I40E_HW_100M_SGMII_CAPABLE, + I40E_HW_NO_DCB_SUPPORT, + I40E_HW_USE_SET_LLDP_MIB, + I40E_HW_GENEVE_OFFLOAD_CAPABLE, + I40E_HW_PTP_L4_CAPABLE, + I40E_HW_WOL_MC_MAGIC_PKT_WAKE, + I40E_HW_HAVE_CRT_RETIMER, + I40E_HW_OUTER_UDP_CSUM_CAPABLE, + I40E_HW_PHY_CONTROLS_LEDS, + I40E_HW_STOP_FW_LLDP, + I40E_HW_PORT_ID_VALID, + I40E_HW_RESTART_AUTONEG, + I40E_PF_HW_FEATURES_NBITS, /* must be last */ +}; + +enum i40e_pf_flags { + I40E_FLAG_MSI_ENA, + I40E_FLAG_MSIX_ENA, + I40E_FLAG_RSS_ENA, + I40E_FLAG_VMDQ_ENA, + I40E_FLAG_SRIOV_ENA, + I40E_FLAG_DCB_CAPABLE, + I40E_FLAG_DCB_ENA, + I40E_FLAG_FD_SB_ENA, + I40E_FLAG_FD_ATR_ENA, + I40E_FLAG_MFP_ENA, + I40E_FLAG_HW_ATR_EVICT_ENA, + I40E_FLAG_VEB_MODE_ENA, + I40E_FLAG_VEB_STATS_ENA, + I40E_FLAG_LINK_POLLING_ENA, + I40E_FLAG_TRUE_PROMISC_ENA, + I40E_FLAG_LEGACY_RX_ENA, + I40E_FLAG_PTP_ENA, + I40E_FLAG_IWARP_ENA, + I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, + I40E_FLAG_SOURCE_PRUNING_DIS, + I40E_FLAG_TC_MQPRIO_ENA, + I40E_FLAG_FD_SB_INACTIVE, + I40E_FLAG_FD_SB_TO_CLOUD_FILTER, + I40E_FLAG_FW_LLDP_DIS, + I40E_FLAG_RS_FEC, + I40E_FLAG_BASE_R_FEC, + /* TOTAL_PORT_SHUTDOWN_ENA + * Allows to physically disable the link on the NIC's port. + * If enabled, (after link down request from the OS) + * no link, traffic or led activity is possible on that port. + * + * If I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA is set, the + * I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA must be explicitly forced + * to true and cannot be disabled by system admin at that time. + * The functionalities are exclusive in terms of configuration, but + * they also have similar behavior (allowing to disable physical + * link of the port), with following differences: + * - LINK_DOWN_ON_CLOSE_ENA is configurable at host OS run-time and + * is supported by whole family of 7xx Intel Ethernet Controllers + * - TOTAL_PORT_SHUTDOWN_ENA may be enabled only before OS loads + * (in BIOS) only if motherboard's BIOS and NIC's FW has support of it + * - when LINK_DOWN_ON_CLOSE_ENABLED is used, the link is being brought + * down by sending phy_type=0 to NIC's FW + * - when TOTAL_PORT_SHUTDOWN_ENA is used, phy_type is not altered, + * instead the link is being brought down by clearing + * bit (I40E_AQ_PHY_ENABLE_LINK) in abilities field of + * i40e_aq_set_phy_config structure + */ + I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, + I40E_FLAG_VF_VLAN_PRUNING_ENA, + I40E_PF_FLAGS_NBITS, /* must be last */ +}; + enum i40e_interrupt_policy { I40E_INTERRUPT_BEST_CASE, I40E_INTERRUPT_MEDIUM, @@ -481,77 +557,8 @@ struct i40e_pf { struct timer_list service_timer; struct work_struct service_task; - u32 hw_features; -#define I40E_HW_RSS_AQ_CAPABLE BIT(0) -#define I40E_HW_128_QP_RSS_CAPABLE BIT(1) -#define I40E_HW_ATR_EVICT_CAPABLE BIT(2) -#define I40E_HW_WB_ON_ITR_CAPABLE BIT(3) -#define I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE BIT(4) -#define I40E_HW_NO_PCI_LINK_CHECK BIT(5) -#define I40E_HW_100M_SGMII_CAPABLE BIT(6) -#define I40E_HW_NO_DCB_SUPPORT BIT(7) -#define I40E_HW_USE_SET_LLDP_MIB BIT(8) -#define I40E_HW_GENEVE_OFFLOAD_CAPABLE BIT(9) -#define I40E_HW_PTP_L4_CAPABLE BIT(10) -#define I40E_HW_WOL_MC_MAGIC_PKT_WAKE BIT(11) -#define I40E_HW_HAVE_CRT_RETIMER BIT(13) -#define I40E_HW_OUTER_UDP_CSUM_CAPABLE BIT(14) -#define I40E_HW_PHY_CONTROLS_LEDS BIT(15) -#define I40E_HW_STOP_FW_LLDP BIT(16) -#define I40E_HW_PORT_ID_VALID BIT(17) -#define I40E_HW_RESTART_AUTONEG BIT(18) - - u32 flags; -#define I40E_FLAG_MSI_ENABLED BIT(0) -#define I40E_FLAG_MSIX_ENABLED BIT(1) -#define I40E_FLAG_RSS_ENABLED BIT(2) -#define I40E_FLAG_VMDQ_ENABLED BIT(3) -#define I40E_FLAG_SRIOV_ENABLED BIT(4) -#define I40E_FLAG_DCB_CAPABLE BIT(5) -#define I40E_FLAG_DCB_ENABLED BIT(6) -#define I40E_FLAG_FD_SB_ENABLED BIT(7) -#define I40E_FLAG_FD_ATR_ENABLED BIT(8) -#define I40E_FLAG_MFP_ENABLED BIT(9) -#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT(10) -#define I40E_FLAG_VEB_MODE_ENABLED BIT(11) -#define I40E_FLAG_VEB_STATS_ENABLED BIT(12) -#define I40E_FLAG_LINK_POLLING_ENABLED BIT(13) -#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT(14) -#define I40E_FLAG_LEGACY_RX BIT(15) -#define I40E_FLAG_PTP BIT(16) -#define I40E_FLAG_IWARP_ENABLED BIT(17) -#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(18) -#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(19) -#define I40E_FLAG_TC_MQPRIO BIT(20) -#define I40E_FLAG_FD_SB_INACTIVE BIT(21) -#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(22) -#define I40E_FLAG_DISABLE_FW_LLDP BIT(23) -#define I40E_FLAG_RS_FEC BIT(24) -#define I40E_FLAG_BASE_R_FEC BIT(25) -/* TOTAL_PORT_SHUTDOWN - * Allows to physically disable the link on the NIC's port. - * If enabled, (after link down request from the OS) - * no link, traffic or led activity is possible on that port. - * - * If I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED is set, the - * I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED must be explicitly forced to true - * and cannot be disabled by system admin at that time. - * The functionalities are exclusive in terms of configuration, but they also - * have similar behavior (allowing to disable physical link of the port), - * with following differences: - * - LINK_DOWN_ON_CLOSE_ENABLED is configurable at host OS run-time and is - * supported by whole family of 7xx Intel Ethernet Controllers - * - TOTAL_PORT_SHUTDOWN may be enabled only before OS loads (in BIOS) - * only if motherboard's BIOS and NIC's FW has support of it - * - when LINK_DOWN_ON_CLOSE_ENABLED is used, the link is being brought down - * by sending phy_type=0 to NIC's FW - * - when TOTAL_PORT_SHUTDOWN is used, phy_type is not altered, instead - * the link is being brought down by clearing bit (I40E_AQ_PHY_ENABLE_LINK) - * in abilities field of i40e_aq_set_phy_config structure - */ -#define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED BIT(26) -#define I40E_FLAG_VF_VLAN_PRUNING BIT(27) - + DECLARE_BITMAP(hw_features, I40E_PF_HW_FEATURES_NBITS); + DECLARE_BITMAP(flags, I40E_PF_FLAGS_NBITS); struct i40e_client_instance *cinst; bool stat_offsets_loaded; struct i40e_hw_port_stats stats; @@ -1267,7 +1274,7 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr); void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); static inline bool i40e_is_sw_dcb(struct i40e_pf *pf) { - return !!(pf->flags & I40E_FLAG_DISABLE_FW_LLDP); + return test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags); } #ifdef CONFIG_I40E_DCB @@ -1301,7 +1308,7 @@ int i40e_set_partition_bw_setting(struct i40e_pf *pf); int i40e_commit_partition_bw_setting(struct i40e_pf *pf); void i40e_print_link_message(struct i40e_vsi *vsi, bool isup); -void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags); +void i40e_set_fec_in_flags(u8 fec_cfg, unsigned long *flags); static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi) { @@ -1321,13 +1328,13 @@ int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi, * i40e_is_tc_mqprio_enabled - check if TC MQPRIO is enabled on PF * @pf: pointer to a pf. * - * Check and return value of flag I40E_FLAG_TC_MQPRIO. + * Check and return state of flag I40E_FLAG_TC_MQPRIO. * - * Return: I40E_FLAG_TC_MQPRIO set state. + * Return: true/false if I40E_FLAG_TC_MQPRIO is set or not **/ -static inline u32 i40e_is_tc_mqprio_enabled(struct i40e_pf *pf) +static inline bool i40e_is_tc_mqprio_enabled(struct i40e_pf *pf) { - return pf->flags & I40E_FLAG_TC_MQPRIO; + return test_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index 077a95dad32c..1ee77a2433c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -310,8 +310,8 @@ static u8 i40e_dcbnl_getstate(struct net_device *netdev) struct i40e_pf *pf = i40e_netdev_to_pf(netdev); dev_dbg(&pf->pdev->dev, "DCB state=%d\n", - !!(pf->flags & I40E_FLAG_DCB_ENABLED)); - return !!(pf->flags & I40E_FLAG_DCB_ENABLED); + test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0); + return test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0; } /** @@ -331,19 +331,19 @@ static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state) return ret; dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n", - state, (pf->flags & I40E_FLAG_DCB_ENABLED) ? 1 : 0); + state, test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0); /* Nothing to do */ - if (!state == !(pf->flags & I40E_FLAG_DCB_ENABLED)) + if (!state == !test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return ret; if (i40e_is_sw_dcb(pf)) { if (state) { - pf->flags |= I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_ENA, pf->flags); memcpy(&pf->hw.desired_dcbx_config, &pf->hw.local_dcbx_config, sizeof(struct i40e_dcbx_config)); } else { - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); } } else { /* Cannot directly manipulate FW LLDP Agent */ @@ -653,7 +653,7 @@ static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) { struct i40e_pf *pf = i40e_netdev_to_pf(netdev); - if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) + if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) return I40E_DCBNL_STATUS_ERROR; switch (capid) { @@ -693,7 +693,7 @@ static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) { struct i40e_pf *pf = i40e_netdev_to_pf(netdev); - if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) + if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) return -EINVAL; *num = I40E_MAX_TRAFFIC_CLASS; @@ -891,11 +891,11 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi) return; /* DCB not enabled */ - if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) + if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return; /* MFP mode but not an iSCSI PF so return */ - if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(hw->func_caps.iscsi)) + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(hw->func_caps.iscsi)) return; dcbxcfg = &hw->local_dcbx_config; @@ -1002,7 +1002,7 @@ void i40e_dcbnl_flush_apps(struct i40e_pf *pf, int i; /* MFP mode but not an iSCSI PF so return */ - if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi)) + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(pf->hw.func_caps.iscsi)) return; for (i = 0; i < old_cfg->numapps; i++) { @@ -1025,7 +1025,7 @@ void i40e_dcbnl_setup(struct i40e_vsi *vsi) struct i40e_pf *pf = i40e_netdev_to_pf(dev); /* Not DCB capable */ - if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) + if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) return; dev->dcbnl_ops = &dcbnl_ops; diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 999c9708def5..e0849f0c9c27 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -820,8 +820,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp, /* By default we are in VEPA mode, if this is the first VF/VMDq * VSI to be added switch to VEB mode. */ - if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) { - pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; + if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) { + set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 93525a982df2..a06062c2e84d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -430,35 +430,35 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = { struct i40e_priv_flags { char flag_string[ETH_GSTRING_LEN]; - u64 flag; + u8 bitno; bool read_only; }; -#define I40E_PRIV_FLAG(_name, _flag, _read_only) { \ +#define I40E_PRIV_FLAG(_name, _bitno, _read_only) { \ .flag_string = _name, \ - .flag = _flag, \ + .bitno = _bitno, \ .read_only = _read_only, \ } static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = { /* NOTE: MFP setting cannot be changed */ - I40E_PRIV_FLAG("MFP", I40E_FLAG_MFP_ENABLED, 1), + I40E_PRIV_FLAG("MFP", I40E_FLAG_MFP_ENA, 1), I40E_PRIV_FLAG("total-port-shutdown", - I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED, 1), - I40E_PRIV_FLAG("LinkPolling", I40E_FLAG_LINK_POLLING_ENABLED, 0), - I40E_PRIV_FLAG("flow-director-atr", I40E_FLAG_FD_ATR_ENABLED, 0), - I40E_PRIV_FLAG("veb-stats", I40E_FLAG_VEB_STATS_ENABLED, 0), - I40E_PRIV_FLAG("hw-atr-eviction", I40E_FLAG_HW_ATR_EVICT_ENABLED, 0), + I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, 1), + I40E_PRIV_FLAG("LinkPolling", I40E_FLAG_LINK_POLLING_ENA, 0), + I40E_PRIV_FLAG("flow-director-atr", I40E_FLAG_FD_ATR_ENA, 0), + I40E_PRIV_FLAG("veb-stats", I40E_FLAG_VEB_STATS_ENA, 0), + I40E_PRIV_FLAG("hw-atr-eviction", I40E_FLAG_HW_ATR_EVICT_ENA, 0), I40E_PRIV_FLAG("link-down-on-close", - I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED, 0), - I40E_PRIV_FLAG("legacy-rx", I40E_FLAG_LEGACY_RX, 0), + I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, 0), + I40E_PRIV_FLAG("legacy-rx", I40E_FLAG_LEGACY_RX_ENA, 0), I40E_PRIV_FLAG("disable-source-pruning", - I40E_FLAG_SOURCE_PRUNING_DISABLED, 0), - I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0), + I40E_FLAG_SOURCE_PRUNING_DIS, 0), + I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_FW_LLDP_DIS, 0), I40E_PRIV_FLAG("rs-fec", I40E_FLAG_RS_FEC, 0), I40E_PRIV_FLAG("base-r-fec", I40E_FLAG_BASE_R_FEC, 0), I40E_PRIV_FLAG("vf-vlan-pruning", - I40E_FLAG_VF_VLAN_PRUNING, 0), + I40E_FLAG_VF_VLAN_PRUNING_ENA, 0), }; #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags) @@ -466,7 +466,7 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = { /* Private flags with a global effect, restricted to PF 0 */ static const struct i40e_priv_flags i40e_gl_gstrings_priv_flags[] = { I40E_PRIV_FLAG("vf-true-promisc-support", - I40E_FLAG_TRUE_PROMISC_SUPPORT, 0), + I40E_FLAG_TRUE_PROMISC_ENA, 0), }; #define I40E_GL_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gl_gstrings_priv_flags) @@ -502,7 +502,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) ethtool_link_ksettings_add_link_mode(ks, advertising, 1000baseT_Full); - if (pf->hw_features & I40E_HW_100M_SGMII_CAPABLE) { + if (test_bit(I40E_HW_100M_SGMII_CAPABLE, pf->hw_features)) { ethtool_link_ksettings_add_link_mode(ks, supported, 100baseT_Full); ethtool_link_ksettings_add_link_mode(ks, advertising, @@ -601,7 +601,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, 10000baseKX4_Full); } if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_KR && - !(pf->hw_features & I40E_HW_HAVE_CRT_RETIMER)) { + !test_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features)) { ethtool_link_ksettings_add_link_mode(ks, supported, 10000baseKR_Full); if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB) @@ -609,7 +609,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, 10000baseKR_Full); } if (phy_types & I40E_CAP_PHY_TYPE_1000BASE_KX && - !(pf->hw_features & I40E_HW_HAVE_CRT_RETIMER)) { + !test_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features)) { ethtool_link_ksettings_add_link_mode(ks, supported, 1000baseKX_Full); if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) @@ -917,7 +917,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw, if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) ethtool_link_ksettings_add_link_mode(ks, advertising, 1000baseT_Full); - if (pf->hw_features & I40E_HW_100M_SGMII_CAPABLE) { + if (test_bit(I40E_HW_100M_SGMII_CAPABLE, pf->hw_features)) { ethtool_link_ksettings_add_link_mode(ks, supported, 100baseT_Full); if (hw_link_info->requested_speeds & @@ -1488,12 +1488,8 @@ static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg) struct i40e_pf *pf = np->vsi->back; struct i40e_hw *hw = &pf->hw; int status = 0; - u32 flags = 0; int err = 0; - flags = READ_ONCE(pf->flags); - i40e_set_fec_in_flags(fec_cfg, &flags); - /* Get the current phy config */ memset(&abilities, 0, sizeof(abilities)); status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, @@ -1525,7 +1521,7 @@ static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg) err = -EAGAIN; goto done; } - pf->flags = flags; + i40e_set_fec_in_flags(fec_cfg, pf->flags); status = i40e_update_link_info(hw); if (status) /* debug level message only due to relation to the link @@ -2432,7 +2428,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, veb_stats = ((pf->lan_veb != I40E_NO_VEB) && (pf->lan_veb < I40E_MAX_VEB) && - (pf->flags & I40E_FLAG_VEB_STATS_ENABLED)); + test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)); if (veb_stats) { veb = pf->veb[pf->lan_veb]; @@ -2561,7 +2557,7 @@ static int i40e_get_ts_info(struct net_device *dev, struct i40e_pf *pf = i40e_netdev_to_pf(dev); /* only report HW timestamping if PTP is enabled */ - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return ethtool_op_get_ts_info(dev, info); info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | @@ -2583,7 +2579,7 @@ static int i40e_get_ts_info(struct net_device *dev, BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ); - if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE) + if (test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | @@ -2832,7 +2828,7 @@ static int i40e_set_phys_id(struct net_device *netdev, switch (state) { case ETHTOOL_ID_ACTIVE: - if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) { + if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) { pf->led_status = i40e_led_get(hw); } else { if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) @@ -2844,19 +2840,19 @@ static int i40e_set_phys_id(struct net_device *netdev, } return blink_freq; case ETHTOOL_ID_ON: - if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) + if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) i40e_led_set(hw, 0xf, false); else ret = i40e_led_set_phy(hw, true, pf->led_status, 0); break; case ETHTOOL_ID_OFF: - if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) + if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) i40e_led_set(hw, 0x0, false); else ret = i40e_led_set_phy(hw, false, pf->led_status, 0); break; case ETHTOOL_ID_INACTIVE: - if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) { + if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) { i40e_led_set(hw, pf->led_status, false); } else { ret = i40e_led_set_phy(hw, false, pf->led_status, @@ -3641,7 +3637,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) bitmap_zero(flow_pctypes, FLOW_PCTYPES_SIZE); - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { dev_err(&pf->pdev->dev, "Change of RSS hash input set is not supported when MFP mode is enabled\n"); return -EOPNOTSUPP; @@ -3657,19 +3653,22 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) switch (nfc->flow_type) { case TCP_V4_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP, flow_pctypes); - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) + if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, + pf->hw_features)) set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK, flow_pctypes); break; case TCP_V6_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP, flow_pctypes); - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) + if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, + pf->hw_features)) set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK, flow_pctypes); break; case UDP_V4_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_UDP, flow_pctypes); - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) { + if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, + pf->hw_features)) { set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP, flow_pctypes); set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP, @@ -3679,7 +3678,8 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) break; case UDP_V6_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_UDP, flow_pctypes); - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) { + if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, + pf->hw_features)) { set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP, flow_pctypes); set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP, @@ -4657,7 +4657,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, * main port cannot change them when in MFP mode as this would impact * any filters on the other ports. */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { netif_err(pf, drv, vsi->netdev, "Cannot change Flow Director input sets while MFP is enabled\n"); return -EOPNOTSUPP; } @@ -4817,7 +4817,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, return -EINVAL; pf = vsi->back; - if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) return -EOPNOTSUPP; if (test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) @@ -5014,7 +5014,7 @@ static void i40e_get_channels(struct net_device *dev, ch->max_combined = i40e_max_channels(vsi); /* report info for other vector */ - ch->other_count = (pf->flags & I40E_FLAG_FD_SB_ENABLED) ? 1 : 0; + ch->other_count = test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ? 1 : 0; ch->max_other = ch->other_count; /* Note: This code assumes DCB is disabled for now. */ @@ -5057,7 +5057,7 @@ static int i40e_set_channels(struct net_device *dev, return -EINVAL; /* verify other_count has not changed */ - if (ch->other_count != ((pf->flags & I40E_FLAG_FD_SB_ENABLED) ? 1 : 0)) + if (ch->other_count != (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ? 1 : 0)) return -EINVAL; /* verify the number of channels does not exceed hardware limits */ @@ -5228,11 +5228,11 @@ static u32 i40e_get_priv_flags(struct net_device *dev) u32 i, j, ret_flags = 0; for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) { - const struct i40e_priv_flags *priv_flags; + const struct i40e_priv_flags *priv_flag; - priv_flags = &i40e_gstrings_priv_flags[i]; + priv_flag = &i40e_gstrings_priv_flags[i]; - if (priv_flags->flag & pf->flags) + if (test_bit(priv_flag->bitno, pf->flags)) ret_flags |= BIT(i); } @@ -5240,11 +5240,11 @@ static u32 i40e_get_priv_flags(struct net_device *dev) return ret_flags; for (j = 0; j < I40E_GL_PRIV_FLAGS_STR_LEN; j++) { - const struct i40e_priv_flags *priv_flags; + const struct i40e_priv_flags *priv_flag; - priv_flags = &i40e_gl_gstrings_priv_flags[j]; + priv_flag = &i40e_gl_gstrings_priv_flags[j]; - if (priv_flags->flag & pf->flags) + if (test_bit(priv_flag->bitno, pf->flags)) ret_flags |= BIT(i + j); } @@ -5258,8 +5258,10 @@ static u32 i40e_get_priv_flags(struct net_device *dev) **/ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) { + DECLARE_BITMAP(changed_flags, I40E_PF_FLAGS_NBITS); + DECLARE_BITMAP(orig_flags, I40E_PF_FLAGS_NBITS); + DECLARE_BITMAP(new_flags, I40E_PF_FLAGS_NBITS); struct i40e_netdev_priv *np = netdev_priv(dev); - u64 orig_flags, new_flags, changed_flags; enum i40e_admin_queue_err adq_err; struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; @@ -5267,51 +5269,57 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) int status; u32 i, j; - orig_flags = READ_ONCE(pf->flags); - new_flags = orig_flags; + bitmap_copy(orig_flags, pf->flags, I40E_PF_FLAGS_NBITS); + bitmap_copy(new_flags, pf->flags, I40E_PF_FLAGS_NBITS); for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) { - const struct i40e_priv_flags *priv_flags; + const struct i40e_priv_flags *priv_flag; + bool new_val; - priv_flags = &i40e_gstrings_priv_flags[i]; - - if (flags & BIT(i)) - new_flags |= priv_flags->flag; - else - new_flags &= ~(priv_flags->flag); + priv_flag = &i40e_gstrings_priv_flags[i]; + new_val = (flags & BIT(i)) ? true : false; /* If this is a read-only flag, it can't be changed */ - if (priv_flags->read_only && - ((orig_flags ^ new_flags) & ~BIT(i))) + if (priv_flag->read_only && + test_bit(priv_flag->bitno, orig_flags) != new_val) return -EOPNOTSUPP; + + if (new_val) + set_bit(priv_flag->bitno, new_flags); + else + clear_bit(priv_flag->bitno, new_flags); } if (pf->hw.pf_id != 0) goto flags_complete; for (j = 0; j < I40E_GL_PRIV_FLAGS_STR_LEN; j++) { - const struct i40e_priv_flags *priv_flags; + const struct i40e_priv_flags *priv_flag; + bool new_val; - priv_flags = &i40e_gl_gstrings_priv_flags[j]; - - if (flags & BIT(i + j)) - new_flags |= priv_flags->flag; - else - new_flags &= ~(priv_flags->flag); + priv_flag = &i40e_gl_gstrings_priv_flags[j]; + new_val = (flags & BIT(i + j)) ? true : false; /* If this is a read-only flag, it can't be changed */ - if (priv_flags->read_only && - ((orig_flags ^ new_flags) & ~BIT(i))) + if (priv_flag->read_only && + test_bit(priv_flag->bitno, orig_flags) != new_val) return -EOPNOTSUPP; + + if (new_val) + set_bit(priv_flag->bitno, new_flags); + else + clear_bit(priv_flag->bitno, new_flags); } flags_complete: - changed_flags = orig_flags ^ new_flags; + bitmap_xor(changed_flags, pf->flags, orig_flags, I40E_PF_FLAGS_NBITS); - if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) + if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags)) reset_needed = I40E_PF_RESET_AND_REBUILD_FLAG; - if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED | - I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED)) + + if (test_bit(I40E_FLAG_VEB_STATS_ENA, changed_flags) || + test_bit(I40E_FLAG_LEGACY_RX_ENA, changed_flags) || + test_bit(I40E_FLAG_SOURCE_PRUNING_DIS, changed_flags)) reset_needed = BIT(__I40E_PF_RESET_REQUESTED); /* Before we finalize any flag changes, we need to perform some @@ -5319,8 +5327,8 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) */ /* ATR eviction is not supported on all devices */ - if ((new_flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) && - !(pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE)) + if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, new_flags) && + !test_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features)) return -EOPNOTSUPP; /* If the driver detected FW LLDP was disabled on init, this flag could @@ -5331,15 +5339,14 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) * disable LLDP, however we _must_ not allow the user to enable/disable * LLDP with this flag on unsupported FW versions. */ - if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) { - if (!(pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) { - dev_warn(&pf->pdev->dev, - "Device does not support changing FW LLDP\n"); - return -EOPNOTSUPP; - } + if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags) && + (!(pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))) { + dev_warn(&pf->pdev->dev, + "Device does not support changing FW LLDP\n"); + return -EOPNOTSUPP; } - if (changed_flags & I40E_FLAG_RS_FEC && + if (test_bit(I40E_FLAG_RS_FEC, changed_flags) && pf->hw.device_id != I40E_DEV_ID_25G_SFP28 && pf->hw.device_id != I40E_DEV_ID_25G_B) { dev_warn(&pf->pdev->dev, @@ -5347,7 +5354,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) return -EOPNOTSUPP; } - if (changed_flags & I40E_FLAG_BASE_R_FEC && + if (test_bit(I40E_FLAG_BASE_R_FEC, changed_flags) && pf->hw.device_id != I40E_DEV_ID_25G_SFP28 && pf->hw.device_id != I40E_DEV_ID_25G_B && pf->hw.device_id != I40E_DEV_ID_KX_X722) { @@ -5362,17 +5369,17 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) */ /* Flush current ATR settings if ATR was disabled */ - if ((changed_flags & I40E_FLAG_FD_ATR_ENABLED) && - !(new_flags & I40E_FLAG_FD_ATR_ENABLED)) { + if (test_bit(I40E_FLAG_FD_ATR_ENA, changed_flags) && + !test_bit(I40E_FLAG_FD_ATR_ENA, new_flags)) { set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state); set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state); } - if (changed_flags & I40E_FLAG_TRUE_PROMISC_SUPPORT) { + if (test_bit(I40E_FLAG_TRUE_PROMISC_ENA, changed_flags)) { u16 sw_flags = 0, valid_flags = 0; int ret; - if (!(new_flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) + if (!test_bit(I40E_FLAG_TRUE_PROMISC_ENA, new_flags)) sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC; valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC; ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags, @@ -5387,17 +5394,17 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) } } - if ((changed_flags & I40E_FLAG_RS_FEC) || - (changed_flags & I40E_FLAG_BASE_R_FEC)) { + if (test_bit(I40E_FLAG_RS_FEC, changed_flags) || + test_bit(I40E_FLAG_BASE_R_FEC, changed_flags)) { u8 fec_cfg = 0; - if (new_flags & I40E_FLAG_RS_FEC && - new_flags & I40E_FLAG_BASE_R_FEC) { + if (test_bit(I40E_FLAG_RS_FEC, new_flags) && + test_bit(I40E_FLAG_BASE_R_FEC, new_flags)) { fec_cfg = I40E_AQ_SET_FEC_AUTO; - } else if (new_flags & I40E_FLAG_RS_FEC) { + } else if (test_bit(I40E_FLAG_RS_FEC, new_flags)) { fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS | I40E_AQ_SET_FEC_ABILITY_RS); - } else if (new_flags & I40E_FLAG_BASE_R_FEC) { + } else if (test_bit(I40E_FLAG_BASE_R_FEC, new_flags)) { fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR | I40E_AQ_SET_FEC_ABILITY_KR); } @@ -5405,35 +5412,35 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) dev_warn(&pf->pdev->dev, "Cannot change FEC config\n"); } - if ((changed_flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) && - (orig_flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)) { + if (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, changed_flags) && + test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, orig_flags)) { dev_err(&pf->pdev->dev, "Setting link-down-on-close not supported on this port (because total-port-shutdown is enabled)\n"); return -EOPNOTSUPP; } - if ((changed_flags & I40E_FLAG_VF_VLAN_PRUNING) && + if (test_bit(I40E_FLAG_VF_VLAN_PRUNING_ENA, changed_flags) && pf->num_alloc_vfs) { dev_warn(&pf->pdev->dev, "Changing vf-vlan-pruning flag while VF(s) are active is not supported\n"); return -EOPNOTSUPP; } - if ((changed_flags & I40E_FLAG_LEGACY_RX) && + if (test_bit(I40E_FLAG_LEGACY_RX_ENA, changed_flags) && I40E_2K_TOO_SMALL_WITH_PADDING) { dev_warn(&pf->pdev->dev, "2k Rx buffer is too small to fit standard MTU and skb_shared_info\n"); return -EOPNOTSUPP; } - if ((changed_flags & new_flags & - I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) && - (new_flags & I40E_FLAG_MFP_ENABLED)) + if (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, changed_flags) && + test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, new_flags) && + test_bit(I40E_FLAG_MFP_ENA, new_flags)) dev_warn(&pf->pdev->dev, "Turning on link-down-on-close flag may affect other partitions\n"); - if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) { - if (new_flags & I40E_FLAG_DISABLE_FW_LLDP) { + if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags)) { + if (test_bit(I40E_FLAG_FW_LLDP_DIS, new_flags)) { #ifdef CONFIG_I40E_DCB i40e_dcb_sw_default_config(pf); #endif /* CONFIG_I40E_DCB */ @@ -5474,7 +5481,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) * initialization or (b) while holding the RTNL lock, we don't need * anything fancy here. */ - pf->flags = new_flags; + bitmap_copy(pf->flags, new_flags, I40E_PF_FLAGS_NBITS); /* Issue reset to cause things to take effect, as additional bits * are added we will need to create a mask of bits requiring reset diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2158a93261cf..1c84136b9482 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -371,7 +371,7 @@ static void i40e_tx_timeout(struct net_device *netdev, unsigned int txqueue) if (tx_ring) { head = i40e_get_head(tx_ring); /* Read interrupt register */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) val = rd32(&pf->hw, I40E_PFINT_DYN_CTLN(tx_ring->q_vector->v_idx + tx_ring->vsi->base_vector - 1)); @@ -1209,13 +1209,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf) pf->stat_offsets_loaded, &osd->rx_lpi_count, &nsd->rx_lpi_count); - if (pf->flags & I40E_FLAG_FD_SB_ENABLED && + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && !test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) nsd->fd_sb_status = true; else nsd->fd_sb_status = false; - if (pf->flags & I40E_FLAG_FD_ATR_ENABLED && + if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) && !test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) nsd->fd_atr_status = true; else @@ -1485,7 +1485,7 @@ static s16 i40e_get_vf_new_vlan(struct i40e_vsi *vsi, return pvid; is_any = (trusted || - !(pf->flags & I40E_FLAG_VF_VLAN_PRUNING)); + !test_bit(I40E_FLAG_VF_VLAN_PRUNING_ENA, pf->flags)); if ((vlan_filters && f->vlan == I40E_VLAN_ANY) || (!is_any && !vlan_filters && f->vlan == I40E_VLAN_ANY) || @@ -1890,7 +1890,7 @@ static int i40e_vsi_config_rss(struct i40e_vsi *vsi) u8 *lut; int ret; - if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE)) + if (!test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) return 0; if (!vsi->rss_size) vsi->rss_size = min_t(int, pf->alloc_rss_size, @@ -2045,7 +2045,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, */ if (vsi->req_queue_pairs > 0) vsi->num_queue_pairs = vsi->req_queue_pairs; - else if (pf->flags & I40E_FLAG_MSIX_ENABLED) + else if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) vsi->num_queue_pairs = pf->num_lan_msix; else vsi->num_queue_pairs = 1; @@ -2058,7 +2058,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, else num_tc_qps = vsi->alloc_queue_pairs; - if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) { + if (enabled_tc && test_bit(I40E_FLAG_DCB_ENA, vsi->back->flags)) { /* Find numtc from enabled TC bitmap */ for (i = 0, numtc = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (enabled_tc & BIT(i)) /* TC is enabled */ @@ -2077,7 +2077,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1; /* Do not allow use more TC queue pairs than MSI-X vectors exist */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) num_tc_qps = min_t(int, num_tc_qps, pf->num_lan_msix); /* Setup queue offset/count for all TCs for given VSI */ @@ -2089,8 +2089,10 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, switch (vsi->type) { case I40E_VSI_MAIN: - if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED)) || + if ((!test_bit(I40E_FLAG_FD_SB_ENA, + pf->flags) && + !test_bit(I40E_FLAG_FD_ATR_ENA, + pf->flags)) || vsi->tc_config.enabled_tc != 1) { qcount = min_t(int, pf->alloc_rss_size, num_tc_qps); @@ -2476,7 +2478,7 @@ static int i40e_set_promiscuous(struct i40e_pf *pf, bool promisc) if (vsi->type == I40E_VSI_MAIN && pf->lan_veb != I40E_NO_VEB && - !(pf->flags & I40E_FLAG_MFP_ENABLED)) { + !test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { /* set defport ON for Main VSI instead of true promisc * this way we will get all unicast/multicast and VLAN * promisc behavior but will not get VF or VMDq traffic @@ -2907,7 +2909,7 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf) */ static u16 i40e_calculate_vsi_rx_buf_len(struct i40e_vsi *vsi) { - if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX)) + if (!vsi->netdev || test_bit(I40E_FLAG_LEGACY_RX_ENA, vsi->back->flags)) return SKB_WITH_OVERHEAD(I40E_RXBUFFER_2048); return PAGE_SIZE < 8192 ? I40E_RXBUFFER_3072 : I40E_RXBUFFER_2048; @@ -3462,7 +3464,7 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) ring->xsk_pool = i40e_xsk_pool(ring); /* some ATR related tx ring init */ - if (vsi->back->flags & I40E_FLAG_FD_ATR_ENABLED) { + if (test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags)) { ring->atr_sample_rate = vsi->back->atr_sample_rate; ring->atr_count = 0; } else { @@ -3478,9 +3480,11 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) tx_ctx.new_context = 1; tx_ctx.base = (ring->dma / 128); tx_ctx.qlen = ring->count; - tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED)); - tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP); + if (test_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags) || + test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags)) + tx_ctx.fd_ena = 1; + if (test_bit(I40E_FLAG_PTP_ENA, vsi->back->flags)) + tx_ctx.timesync_ena = 1; /* FDIR VSI tx ring can still use RS bit and writebacks */ if (vsi->type != I40E_VSI_FDIR) tx_ctx.head_wb_ena = 1; @@ -3663,7 +3667,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) } /* configure Rx buffer alignment */ - if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX)) { + if (!vsi->netdev || test_bit(I40E_FLAG_LEGACY_RX_ENA, vsi->back->flags)) { if (I40E_2K_TOO_SMALL_WITH_PADDING) { dev_info(&vsi->back->pdev->dev, "2k Rx buffer is too small to fit standard MTU and skb_shared_info\n"); @@ -3761,7 +3765,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi) u16 qoffset, qcount; int i, n; - if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED)) { + if (!test_bit(I40E_FLAG_DCB_ENA, vsi->back->flags)) { /* Reset the TC information */ for (i = 0; i < vsi->num_queue_pairs; i++) { rx_ring = vsi->rx_rings[i]; @@ -3828,7 +3832,7 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi) struct i40e_pf *pf = vsi->back; struct hlist_node *node; - if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) return; /* Reset FDir counters as we're replaying all existing filters */ @@ -3966,10 +3970,10 @@ static void i40e_enable_misc_int_causes(struct i40e_pf *pf) I40E_PFINT_ICR0_ENA_VFLR_MASK | I40E_PFINT_ICR0_ENA_ADMINQ_MASK; - if (pf->flags & I40E_FLAG_IWARP_ENABLED) + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) val |= I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; - if (pf->flags & I40E_FLAG_PTP) + if (test_bit(I40E_FLAG_PTP_ENA, pf->flags)) val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, val); @@ -4205,7 +4209,7 @@ static void i40e_vsi_disable_irq(struct i40e_vsi *vsi) } /* disable each interrupt */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { for (i = vsi->base_vector; i < (vsi->num_q_vectors + vsi->base_vector); i++) wr32(hw, I40E_PFINT_DYN_CTLN(i - 1), 0); @@ -4231,7 +4235,7 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi) struct i40e_pf *pf = vsi->back; int i; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { for (i = 0; i < vsi->num_q_vectors; i++) i40e_irq_dynamic_enable(vsi, i); } else { @@ -4252,7 +4256,7 @@ static void i40e_free_misc_vector(struct i40e_pf *pf) wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0); i40e_flush(&pf->hw); - if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) { free_irq(pf->msix_entries[0].vector, pf); clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state); } @@ -4287,7 +4291,7 @@ static irqreturn_t i40e_intr(int irq, void *data) (icr0 & I40E_PFINT_ICR0_SWINT_MASK)) pf->sw_int_count++; - if ((pf->flags & I40E_FLAG_IWARP_ENABLED) && + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags) && (icr0 & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) { ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n"); @@ -4480,7 +4484,7 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget) i += tx_ring->count; tx_ring->next_to_clean = i; - if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) i40e_irq_dynamic_enable(vsi, tx_ring->q_vector->v_idx); return budget > 0; @@ -4593,9 +4597,9 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename) struct i40e_pf *pf = vsi->back; int err; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) err = i40e_vsi_request_irq_msix(vsi, basename); - else if (pf->flags & I40E_FLAG_MSI_ENABLED) + else if (test_bit(I40E_FLAG_MSI_ENA, pf->flags)) err = request_irq(pf->pdev->irq, i40e_intr, 0, pf->int_name, pf); else @@ -4627,7 +4631,7 @@ static void i40e_netpoll(struct net_device *netdev) if (test_bit(__I40E_VSI_DOWN, vsi->state)) return; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { for (i = 0; i < vsi->num_q_vectors; i++) i40e_msix_clean_rings(0, vsi->q_vectors[i]); } else { @@ -4967,7 +4971,7 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi) u32 val, qp; int i; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { if (!vsi->q_vectors) return; @@ -5129,16 +5133,17 @@ static void i40e_vsi_free_q_vectors(struct i40e_vsi *vsi) static void i40e_reset_interrupt_capability(struct i40e_pf *pf) { /* If we're in Legacy mode, the interrupt was cleaned in vsi_close */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { pci_disable_msix(pf->pdev); kfree(pf->msix_entries); pf->msix_entries = NULL; kfree(pf->irq_pile); pf->irq_pile = NULL; - } else if (pf->flags & I40E_FLAG_MSI_ENABLED) { + } else if (test_bit(I40E_FLAG_MSI_ENA, pf->flags)) { pci_disable_msi(pf->pdev); } - pf->flags &= ~(I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED); + clear_bit(I40E_FLAG_MSI_ENA, pf->flags); + clear_bit(I40E_FLAG_MSIX_ENA, pf->flags); } /** @@ -5478,11 +5483,11 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) return pf->vsi[pf->lan_vsi]->mqprio_qopt.qopt.num_tc; /* If neither MQPRIO nor DCB is enabled, then always use single TC */ - if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) + if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return 1; /* SFP mode will be enabled for all TCs on port */ - if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags)) return i40e_dcb_get_num_tc(dcbcfg); /* MFP mode return count of enabled TCs for this PF */ @@ -5512,11 +5517,11 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) /* If neither MQPRIO nor DCB is enabled for this PF then just return * default TC */ - if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) + if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return I40E_DEFAULT_TRAFFIC_CLASS; /* SFP mode we want PF to be enabled for all TCs */ - if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags)) return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config); /* MFP enabled and iSCSI PF type */ @@ -5605,7 +5610,7 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, /* There is no need to reset BW when mqprio mode is on. */ if (i40e_is_tc_mqprio_enabled(pf)) return 0; - if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) { + if (!vsi->mqprio_qopt.qopt.hw && !test_bit(I40E_FLAG_DCB_ENA, pf->flags)) { ret = i40e_set_bw_limit(vsi, vsi->seid, 0); if (ret) dev_info(&pf->pdev->dev, @@ -5858,7 +5863,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) } vsi->reconfig_rss = false; } - if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, vsi->back->flags)) { ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID); ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA; @@ -6271,7 +6276,7 @@ static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid, if (ch->type == I40E_VSI_VMDQ2) ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2; - if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) { + if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) { ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); ctxt.info.switch_id = @@ -6576,8 +6581,8 @@ int i40e_create_queue_channel(struct i40e_vsi *vsi, * VSI to be added switch to VEB mode. */ - if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) { - pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; + if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) { + set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); if (vsi->type == I40E_VSI_MAIN) { if (i40e_is_tc_mqprio_enabled(pf)) @@ -6988,9 +6993,9 @@ int i40e_hw_dcb_config(struct i40e_pf *pf, struct i40e_dcbx_config *new_cfg) if (need_reconfig) { /* Enable DCB tagging only when more than one TC */ if (new_numtc > 1) - pf->flags |= I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_ENA, pf->flags); else - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); set_bit(__I40E_PORT_SUSPENDED, pf->state); /* Reconfiguration needed quiesce all VSIs */ @@ -7080,7 +7085,7 @@ int i40e_hw_dcb_config(struct i40e_pf *pf, struct i40e_dcbx_config *new_cfg) set_bit(__I40E_CLIENT_L2_CHANGE, pf->state); } /* registers are set, lets apply */ - if (pf->hw_features & I40E_HW_USE_SET_LLDP_MIB) + if (test_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features)) ret = i40e_hw_set_dcb_config(pf, new_cfg); } @@ -7101,7 +7106,7 @@ int i40e_dcb_sw_default_config(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; int err; - if (pf->hw_features & I40E_HW_USE_SET_LLDP_MIB) { + if (test_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features)) { /* Update the local cached instance with TC0 ETS */ memset(&pf->tmp_cfg, 0, sizeof(struct i40e_dcbx_config)); pf->tmp_cfg.etscfg.willing = I40E_IEEE_DEFAULT_ETS_WILLING; @@ -7162,12 +7167,12 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) /* Do not enable DCB for SW1 and SW2 images even if the FW is capable * Also do not enable DCBx if FW LLDP agent is disabled */ - if (pf->hw_features & I40E_HW_NO_DCB_SUPPORT) { + if (test_bit(I40E_HW_NO_DCB_SUPPORT, pf->hw_features)) { dev_info(&pf->pdev->dev, "DCB is not supported.\n"); err = -EOPNOTSUPP; goto out; } - if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) { + if (test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)) { dev_info(&pf->pdev->dev, "FW LLDP is disabled, attempting SW DCB\n"); err = i40e_dcb_sw_default_config(pf); if (err) { @@ -7178,8 +7183,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) pf->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; /* at init capable but disabled */ - pf->flags |= I40E_FLAG_DCB_CAPABLE; - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); goto out; } err = i40e_init_dcb(hw, true); @@ -7194,20 +7199,20 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_IEEE; - pf->flags |= I40E_FLAG_DCB_CAPABLE; + set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); /* Enable DCB tagging only when more than one TC * or explicitly disable if only one TC */ if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1) - pf->flags |= I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_ENA, pf->flags); else - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); dev_dbg(&pf->pdev->dev, "DCBX offload is supported for this PF.\n"); } } else if (pf->hw.aq.asq_last_status == I40E_AQ_RC_EPERM) { dev_info(&pf->pdev->dev, "FW LLDP disabled for this PF.\n"); - pf->flags |= I40E_FLAG_DISABLE_FW_LLDP; + set_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags); } else { dev_info(&pf->pdev->dev, "Query for DCB configuration failed, err %pe aq_err %s\n", @@ -7367,7 +7372,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi) struct i40e_pf *pf = vsi->back; int err; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) i40e_vsi_configure_msix(vsi); else i40e_configure_msi_and_legacy(vsi); @@ -7471,7 +7476,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up) * and its speed values are OK, no need for a flap * if non_zero_phy_type was set, still need to force up */ - if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED) + if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) non_zero_phy_type = true; else if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0) return 0; @@ -7487,7 +7492,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up) non_zero_phy_type ? (u8)((mask >> 32) & 0xff) : 0; /* Copy the old settings, except of phy_type */ config.abilities = abilities.abilities; - if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED) { + if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) { if (is_up) config.abilities |= I40E_AQ_PHY_ENABLE_LINK; else @@ -7537,8 +7542,8 @@ int i40e_up(struct i40e_vsi *vsi) int err; if (vsi->type == I40E_VSI_MAIN && - (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED || - vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)) + (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags) || + test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, vsi->back->flags))) i40e_force_link_state(vsi->back, true); err = i40e_vsi_configure(vsi); @@ -7566,8 +7571,8 @@ void i40e_down(struct i40e_vsi *vsi) i40e_vsi_disable_irq(vsi); i40e_vsi_stop_rings(vsi); if (vsi->type == I40E_VSI_MAIN && - (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED || - vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)) + (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags) || + test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, vsi->back->flags))) i40e_force_link_state(vsi->back, false); i40e_napi_disable_all(vsi); @@ -7973,7 +7978,7 @@ static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev) struct i40e_fwd_adapter *fwd; int avail_macvlan, ret; - if ((pf->flags & I40E_FLAG_DCB_ENABLED)) { + if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) { netdev_info(netdev, "Macvlans are not supported when DCB is enabled\n"); return ERR_PTR(-EINVAL); } @@ -8168,23 +8173,23 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data) hw = mqprio_qopt->qopt.hw; mode = mqprio_qopt->mode; if (!hw) { - pf->flags &= ~I40E_FLAG_TC_MQPRIO; + clear_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags); memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt)); goto config_tc; } /* Check if MFP enabled */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { netdev_info(netdev, "Configuring TC not supported in MFP mode\n"); return ret; } switch (mode) { case TC_MQPRIO_MODE_DCB: - pf->flags &= ~I40E_FLAG_TC_MQPRIO; + clear_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags); /* Check if DCB enabled to continue */ - if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) { + if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) { netdev_info(netdev, "DCB is not enabled for adapter\n"); return ret; @@ -8198,20 +8203,20 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data) } break; case TC_MQPRIO_MODE_CHANNEL: - if (pf->flags & I40E_FLAG_DCB_ENABLED) { + if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) { netdev_info(netdev, "Full offload of TC Mqprio options is not supported when DCB is enabled\n"); return ret; } - if (!(pf->flags & I40E_FLAG_MSIX_ENABLED)) + if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return ret; ret = i40e_validate_mqprio_qopt(vsi, mqprio_qopt); if (ret) return ret; memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt)); - pf->flags |= I40E_FLAG_TC_MQPRIO; - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); break; default: return -EINVAL; @@ -8795,11 +8800,11 @@ static int i40e_configure_clsflower(struct i40e_vsi *vsi, return -EINVAL; } - if (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags)) { dev_err(&vsi->back->pdev->dev, "Disable Flow Director Sideband, configuring Cloud filters via tc-flower\n"); - vsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED; - vsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER; + clear_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags); + clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, vsi->back->flags); } filter = kzalloc(sizeof(*filter), GFP_KERNEL); @@ -8895,11 +8900,11 @@ static int i40e_delete_clsflower(struct i40e_vsi *vsi, pf->num_cloud_filters--; if (!pf->num_cloud_filters) - if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) && - !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) { - pf->flags |= I40E_FLAG_FD_SB_ENABLED; - pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER; - pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE; + if (test_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags) && + !test_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags)) { + set_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags); + clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); } return 0; } @@ -9200,11 +9205,11 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf) } pf->num_cloud_filters = 0; - if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) && - !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) { - pf->flags |= I40E_FLAG_FD_SB_ENABLED; - pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER; - pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE; + if (test_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags) && + !test_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags)) { + set_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags); + clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); } } @@ -9292,7 +9297,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired) i40e_prep_for_reset(pf); i40e_reset_and_rebuild(pf, true, lock_acquired); dev_info(&pf->pdev->dev, - pf->flags & I40E_FLAG_DISABLE_FW_LLDP ? + test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags) ? "FW LLDP is disabled\n" : "FW LLDP is enabled\n"); @@ -9407,12 +9412,12 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, if (I40E_IS_X710TL_DEVICE(hw->device_id) && (hw->phy.link_info.link_speed & ~(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB)) && - !(pf->flags & I40E_FLAG_DCB_CAPABLE)) + !test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) /* let firmware decide if the DCB should be disabled */ - pf->flags |= I40E_FLAG_DCB_CAPABLE; + set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); /* Not DCB capable or capability disabled */ - if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) + if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) return ret; /* Ignore if event is not for Nearest Bridge */ @@ -9448,7 +9453,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, (I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB))) { dev_warn(&pf->pdev->dev, "DCB is not supported for X710-T*L 2.5/5G speeds\n"); - pf->flags &= ~I40E_FLAG_DCB_CAPABLE; + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); } else { dev_info(&pf->pdev->dev, "Failed querying DCB configuration data from firmware, err %pe aq_err %s\n", @@ -9476,9 +9481,9 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, /* Enable DCB tagging only when more than one TC */ if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1) - pf->flags |= I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_ENA, pf->flags); else - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); set_bit(__I40E_PORT_SUSPENDED, pf->state); /* Reconfiguration needed quiesce all VSIs */ @@ -9610,7 +9615,7 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf) static void i40e_reenable_fdir_sb(struct i40e_pf *pf) { if (test_and_clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) - if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && (I40E_DEBUG_FD & pf->hw.debug_mask)) dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n"); } @@ -9631,7 +9636,7 @@ static void i40e_reenable_fdir_atr(struct i40e_pf *pf) I40E_L3_SRC_MASK | I40E_L3_DST_MASK | I40E_L4_SRC_MASK | I40E_L4_DST_MASK); - if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) && (I40E_DEBUG_FD & pf->hw.debug_mask)) dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n"); } @@ -9946,7 +9951,7 @@ static void i40e_link_event(struct i40e_pf *pf) if (pf->vf) i40e_vc_notify_link_state(pf); - if (pf->flags & I40E_FLAG_PTP) + if (test_bit(I40E_FLAG_PTP_ENA, pf->flags)) i40e_ptp_set_increment(pf); #ifdef CONFIG_I40E_DCB if (new_link == old_link) @@ -9963,13 +9968,13 @@ static void i40e_link_event(struct i40e_pf *pf) memset(&pf->tmp_cfg, 0, sizeof(pf->tmp_cfg)); err = i40e_dcb_sw_default_config(pf); if (err) { - pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | - I40E_FLAG_DCB_ENABLED); + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); } else { pf->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; - pf->flags |= I40E_FLAG_DCB_CAPABLE; - pf->flags &= ~I40E_FLAG_DCB_ENABLED; + set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); } } #endif /* CONFIG_I40E_DCB */ @@ -9994,7 +9999,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) return; pf->service_timer_previous = jiffies; - if ((pf->flags & I40E_FLAG_LINK_POLLING_ENABLED) || + if (test_bit(I40E_FLAG_LINK_POLLING_ENA, pf->flags) || test_bit(__I40E_TEMP_LINK_POLLING, pf->state)) i40e_link_event(pf); @@ -10005,7 +10010,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) if (pf->vsi[i] && pf->vsi[i]->netdev) i40e_update_stats(pf->vsi[i]); - if (pf->flags & I40E_FLAG_VEB_STATS_ENABLED) { + if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) { /* Update the stats for the active switching components */ for (i = 0; i < I40E_MAX_VEB; i++) if (pf->veb[i]) @@ -10094,7 +10099,7 @@ static void i40e_handle_link_event(struct i40e_pf *pf, if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && (!(status->link_info & I40E_AQ_LINK_UP)) && - (!(pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))) { + (!test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))) { dev_err(&pf->pdev->dev, "Rx/Tx is disabled on this device because an unsupported SFP module type was detected.\n"); dev_err(&pf->pdev->dev, @@ -10400,7 +10405,7 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) if (ret) goto end_reconstitute; - if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) + if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) veb->bridge_mode = BRIDGE_MODE_VEB; else veb->bridge_mode = BRIDGE_MODE_VEPA; @@ -10545,7 +10550,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) wr32(&pf->hw, I40E_GLQF_HKEY(i), hkey[i]); } - if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) return; /* find existing VSI and see if it needs configuring */ @@ -10557,8 +10562,8 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) pf->vsi[pf->lan_vsi]->seid, 0); if (!vsi) { dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n"); - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); return; } } @@ -10936,14 +10941,14 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) i40e_aq_set_dcb_parameters(hw, false, NULL); dev_warn(&pf->pdev->dev, "DCB is not supported for X710-T*L 2.5/5G speeds\n"); - pf->flags &= ~I40E_FLAG_DCB_CAPABLE; + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); } else { i40e_aq_set_dcb_parameters(hw, true, NULL); ret = i40e_init_pf_dcb(pf); if (ret) { dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n", ret); - pf->flags &= ~I40E_FLAG_DCB_CAPABLE; + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); /* Continue without DCB enabled */ } } @@ -11064,7 +11069,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) wr32(hw, I40E_REG_MSS, val); } - if (pf->hw_features & I40E_HW_RESTART_AUTONEG) { + if (test_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features)) { msleep(75); ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (ret) @@ -11074,7 +11079,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) pf->hw.aq.asq_last_status)); } /* reinit the misc interrupt */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { ret = i40e_setup_misc_vector(pf); if (ret) goto end_unlock; @@ -11349,7 +11354,7 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) if (!vsi->num_rx_desc) vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS, I40E_REQ_DESCRIPTOR_MULTIPLE); - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) vsi->num_q_vectors = pf->num_lan_msix; else vsi->num_q_vectors = 1; @@ -11667,7 +11672,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) ring->count = vsi->num_tx_desc; ring->size = 0; ring->dcb_tc = 0; - if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) + if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, vsi->back->hw_features)) ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; ring->itr_setting = pf->tx_itr_default; WRITE_ONCE(vsi->tx_rings[i], ring++); @@ -11684,7 +11689,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) ring->count = vsi->num_tx_desc; ring->size = 0; ring->dcb_tc = 0; - if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) + if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, vsi->back->hw_features)) ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; set_ring_xdp(ring); ring->itr_setting = pf->tx_itr_default; @@ -11748,7 +11753,7 @@ static int i40e_init_msix(struct i40e_pf *pf) int v_actual; int iwarp_requested = 0; - if (!(pf->flags & I40E_FLAG_MSIX_ENABLED)) + if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return -ENODEV; /* The number of vectors we'll request will be comprised of: @@ -11787,7 +11792,7 @@ static int i40e_init_msix(struct i40e_pf *pf) vectors_left -= pf->num_lan_msix; /* reserve one vector for sideband flow director */ - if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { if (vectors_left) { pf->num_fdsb_msix = 1; v_budget++; @@ -11798,7 +11803,7 @@ static int i40e_init_msix(struct i40e_pf *pf) } /* can we reserve enough for iWARP? */ - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { iwarp_requested = pf->num_iwarp_msix; if (!vectors_left) @@ -11810,7 +11815,7 @@ static int i40e_init_msix(struct i40e_pf *pf) } /* any vectors left over go for VMDq support */ - if (pf->flags & I40E_FLAG_VMDQ_ENABLED) { + if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags)) { if (!vectors_left) { pf->num_vmdq_msix = 0; pf->num_vmdq_qps = 0; @@ -11867,7 +11872,7 @@ static int i40e_init_msix(struct i40e_pf *pf) v_actual = i40e_reserve_msix_vectors(pf, v_budget); if (v_actual < I40E_MIN_MSIX) { - pf->flags &= ~I40E_FLAG_MSIX_ENABLED; + clear_bit(I40E_FLAG_MSIX_ENA, pf->flags); kfree(pf->msix_entries); pf->msix_entries = NULL; pci_disable_msix(pf->pdev); @@ -11905,7 +11910,7 @@ static int i40e_init_msix(struct i40e_pf *pf) pf->num_lan_msix = 1; break; case 3: - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { pf->num_lan_msix = 1; pf->num_iwarp_msix = 1; } else { @@ -11913,7 +11918,7 @@ static int i40e_init_msix(struct i40e_pf *pf) } break; default: - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { pf->num_iwarp_msix = min_t(int, (vec / 3), iwarp_requested); pf->num_vmdq_vsis = min_t(int, (vec / 3), @@ -11922,7 +11927,7 @@ static int i40e_init_msix(struct i40e_pf *pf) pf->num_vmdq_vsis = min_t(int, (vec / 2), I40E_DEFAULT_NUM_VMDQ_VSI); } - if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { pf->num_fdsb_msix = 1; vec--; } @@ -11934,22 +11939,20 @@ static int i40e_init_msix(struct i40e_pf *pf) } } - if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && - (pf->num_fdsb_msix == 0)) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && pf->num_fdsb_msix == 0) { dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough MSI-X vectors\n"); - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); } - if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) && - (pf->num_vmdq_msix == 0)) { + if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags) && pf->num_vmdq_msix == 0) { dev_info(&pf->pdev->dev, "VMDq disabled, not enough MSI-X vectors\n"); - pf->flags &= ~I40E_FLAG_VMDQ_ENABLED; + clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags); } - if ((pf->flags & I40E_FLAG_IWARP_ENABLED) && - (pf->num_iwarp_msix == 0)) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags) && + pf->num_iwarp_msix == 0) { dev_info(&pf->pdev->dev, "IWARP disabled, not enough MSI-X vectors\n"); - pf->flags &= ~I40E_FLAG_IWARP_ENABLED; + clear_bit(I40E_FLAG_IWARP_ENA, pf->flags); } i40e_debug(&pf->hw, I40E_DEBUG_INIT, "MSI-X vector distribution: PF %d, VMDq %d, FDSB %d, iWARP %d\n", @@ -12003,7 +12006,7 @@ static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi) int err, v_idx, num_q_vectors; /* if not MSIX, give the one vector only to the LAN VSI */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) num_q_vectors = vsi->num_q_vectors; else if (vsi == pf->vsi[pf->lan_vsi]) num_q_vectors = 1; @@ -12034,38 +12037,39 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf) int vectors = 0; ssize_t size; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { vectors = i40e_init_msix(pf); if (vectors < 0) { - pf->flags &= ~(I40E_FLAG_MSIX_ENABLED | - I40E_FLAG_IWARP_ENABLED | - I40E_FLAG_RSS_ENABLED | - I40E_FLAG_DCB_CAPABLE | - I40E_FLAG_DCB_ENABLED | - I40E_FLAG_SRIOV_ENABLED | - I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED | - I40E_FLAG_VMDQ_ENABLED); - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + clear_bit(I40E_FLAG_MSIX_ENA, pf->flags); + clear_bit(I40E_FLAG_IWARP_ENA, pf->flags); + clear_bit(I40E_FLAG_RSS_ENA, pf->flags); + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); + clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags); + clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); /* rework the queue expectations without MSIX */ i40e_determine_queue_usage(pf); } } - if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) && - (pf->flags & I40E_FLAG_MSI_ENABLED)) { + if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags) && + test_bit(I40E_FLAG_MSI_ENA, pf->flags)) { dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n"); vectors = pci_enable_msi(pf->pdev); if (vectors < 0) { dev_info(&pf->pdev->dev, "MSI init failed - %d\n", vectors); - pf->flags &= ~I40E_FLAG_MSI_ENABLED; + clear_bit(I40E_FLAG_MSI_ENA, pf->flags); } vectors = 1; /* one MSI or Legacy vector */ } - if (!(pf->flags & (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED))) + if (!test_bit(I40E_FLAG_MSI_ENA, pf->flags) && + !test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n"); /* set up vector assignment tracking */ @@ -12098,7 +12102,8 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) * scheme. We need to re-enabled them here in order to attempt to * re-acquire the MSI or MSI-X vectors */ - pf->flags |= (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED); + set_bit(I40E_FLAG_MSI_ENA, pf->flags); + set_bit(I40E_FLAG_MSIX_ENA, pf->flags); err = i40e_init_interrupt_scheme(pf); if (err) @@ -12120,7 +12125,7 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) if (err) goto err_unwind; - if (pf->flags & I40E_FLAG_IWARP_ENABLED) + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) i40e_client_update_msix_info(pf); return 0; @@ -12148,7 +12153,7 @@ static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf) { int err; - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { err = i40e_setup_misc_vector(pf); if (err) { @@ -12158,7 +12163,7 @@ static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf) return err; } } else { - u32 flags = pf->flags & I40E_FLAG_MSI_ENABLED ? 0 : IRQF_SHARED; + u32 flags = test_bit(I40E_FLAG_MSI_ENA, pf->flags) ? 0 : IRQF_SHARED; err = request_irq(pf->pdev->irq, i40e_intr, flags, pf->int_name, pf); @@ -12362,7 +12367,7 @@ int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) { struct i40e_pf *pf = vsi->back; - if (pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) + if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) return i40e_config_rss_aq(vsi, seed, lut, lut_size); else return i40e_config_rss_reg(vsi, seed, lut, lut_size); @@ -12381,7 +12386,7 @@ int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) { struct i40e_pf *pf = vsi->back; - if (pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) + if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) return i40e_get_rss_aq(vsi, seed, lut, lut_size); else return i40e_get_rss_reg(vsi, seed, lut, lut_size); @@ -12484,7 +12489,7 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count) struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; int new_rss_size; - if (!(pf->flags & I40E_FLAG_RSS_ENABLED)) + if (!test_bit(I40E_FLAG_RSS_ENA, pf->flags)) return 0; queue_count = min_t(int, queue_count, num_online_cpus()); @@ -12717,7 +12722,9 @@ static int i40e_sw_init(struct i40e_pf *pf) u16 pow; /* Set default capability flags */ - pf->flags = I40E_FLAG_MSI_ENABLED | I40E_FLAG_MSIX_ENABLED; + bitmap_zero(pf->flags, I40E_PF_FLAGS_NBITS); + set_bit(I40E_FLAG_MSI_ENA, pf->flags); + set_bit(I40E_FLAG_MSIX_ENA, pf->flags); /* Set default ITR */ pf->rx_itr_default = I40E_ITR_RX_DEF; @@ -12737,14 +12744,14 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->rss_size_max = min_t(int, pf->rss_size_max, pow); if (pf->hw.func_caps.rss) { - pf->flags |= I40E_FLAG_RSS_ENABLED; + set_bit(I40E_FLAG_RSS_ENA, pf->flags); pf->alloc_rss_size = min_t(int, pf->rss_size_max, num_online_cpus()); } /* MFP mode enabled */ if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.flex10_enable) { - pf->flags |= I40E_FLAG_MFP_ENABLED; + set_bit(I40E_FLAG_MFP_ENA, pf->flags); dev_info(&pf->pdev->dev, "MFP mode Enabled\n"); if (i40e_get_partition_bw_setting(pf)) { dev_warn(&pf->pdev->dev, @@ -12761,14 +12768,14 @@ static int i40e_sw_init(struct i40e_pf *pf) if ((pf->hw.func_caps.fd_filters_guaranteed > 0) || (pf->hw.func_caps.fd_filters_best_effort > 0)) { - pf->flags |= I40E_FLAG_FD_ATR_ENABLED; + set_bit(I40E_FLAG_FD_ATR_ENA, pf->flags); pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE; - if (pf->flags & I40E_FLAG_MFP_ENABLED && + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && pf->hw.num_partitions > 1) dev_info(&pf->pdev->dev, "Flow Director Sideband mode Disabled in MFP mode\n"); else - pf->flags |= I40E_FLAG_FD_SB_ENABLED; + set_bit(I40E_FLAG_FD_SB_ENA, pf->flags); pf->fdir_pf_filter_count = pf->hw.func_caps.fd_filters_guaranteed; pf->hw.fdir_shared_filter_count = @@ -12776,69 +12783,69 @@ static int i40e_sw_init(struct i40e_pf *pf) } if (pf->hw.mac.type == I40E_MAC_X722) { - pf->hw_features |= (I40E_HW_RSS_AQ_CAPABLE | - I40E_HW_128_QP_RSS_CAPABLE | - I40E_HW_ATR_EVICT_CAPABLE | - I40E_HW_WB_ON_ITR_CAPABLE | - I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE | - I40E_HW_NO_PCI_LINK_CHECK | - I40E_HW_USE_SET_LLDP_MIB | - I40E_HW_GENEVE_OFFLOAD_CAPABLE | - I40E_HW_PTP_L4_CAPABLE | - I40E_HW_WOL_MC_MAGIC_PKT_WAKE | - I40E_HW_OUTER_UDP_CSUM_CAPABLE); + set_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features); + set_bit(I40E_HW_128_QP_RSS_CAPABLE, pf->hw_features); + set_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features); + set_bit(I40E_HW_WB_ON_ITR_CAPABLE, pf->hw_features); + set_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, pf->hw_features); + set_bit(I40E_HW_NO_PCI_LINK_CHECK, pf->hw_features); + set_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features); + set_bit(I40E_HW_GENEVE_OFFLOAD_CAPABLE, pf->hw_features); + set_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features); + set_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features); + set_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features); #define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03 if (rd32(&pf->hw, I40E_GLQF_FDEVICTENA(1)) != I40E_FDEVICT_PCTYPE_DEFAULT) { dev_warn(&pf->pdev->dev, "FD EVICT PCTYPES are not right, disable FD HW EVICT\n"); - pf->hw_features &= ~I40E_HW_ATR_EVICT_CAPABLE; + clear_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features); } } else if ((pf->hw.aq.api_maj_ver > 1) || ((pf->hw.aq.api_maj_ver == 1) && (pf->hw.aq.api_min_ver > 4))) { /* Supported in FW API version higher than 1.4 */ - pf->hw_features |= I40E_HW_GENEVE_OFFLOAD_CAPABLE; + set_bit(I40E_HW_GENEVE_OFFLOAD_CAPABLE, pf->hw_features); } /* Enable HW ATR eviction if possible */ - if (pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE) - pf->flags |= I40E_FLAG_HW_ATR_EVICT_ENABLED; + if (test_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features)) + set_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags); if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) || (pf->hw.aq.fw_maj_ver < 4))) { - pf->hw_features |= I40E_HW_RESTART_AUTONEG; + set_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features); /* No DCB support for FW < v4.33 */ - pf->hw_features |= I40E_HW_NO_DCB_SUPPORT; + set_bit(I40E_HW_NO_DCB_SUPPORT, pf->hw_features); } /* Disable FW LLDP if FW < v4.3 */ if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || (pf->hw.aq.fw_maj_ver < 4))) - pf->hw_features |= I40E_HW_STOP_FW_LLDP; + set_bit(I40E_HW_STOP_FW_LLDP, pf->hw_features); /* Use the FW Set LLDP MIB API if FW > v4.40 */ if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) || (pf->hw.aq.fw_maj_ver >= 5))) - pf->hw_features |= I40E_HW_USE_SET_LLDP_MIB; + set_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features); /* Enable PTP L4 if FW > v6.0 */ if (pf->hw.mac.type == I40E_MAC_XL710 && pf->hw.aq.fw_maj_ver >= 6) - pf->hw_features |= I40E_HW_PTP_L4_CAPABLE; + set_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features); if (pf->hw.func_caps.vmdq && num_online_cpus() != 1) { pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; - pf->flags |= I40E_FLAG_VMDQ_ENABLED; + set_bit(I40E_FLAG_VMDQ_ENA, pf->flags); pf->num_vmdq_qps = i40e_default_queues_per_vmdq(pf); } if (pf->hw.func_caps.iwarp && num_online_cpus() != 1) { - pf->flags |= I40E_FLAG_IWARP_ENABLED; + set_bit(I40E_FLAG_IWARP_ENA, pf->flags); /* IWARP needs one extra vector for CQP just like MISC.*/ pf->num_iwarp_msix = (int)num_online_cpus() + 1; } @@ -12855,7 +12862,7 @@ static int i40e_sw_init(struct i40e_pf *pf) #ifdef CONFIG_PCI_IOV if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) { pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF; - pf->flags |= I40E_FLAG_SRIOV_ENABLED; + set_bit(I40E_FLAG_SRIOV_ENA, pf->flags); pf->num_req_vfs = min_t(int, pf->hw.func_caps.num_vfs, I40E_MAX_VF_COUNT); @@ -12866,7 +12873,7 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->lan_vsi = I40E_NO_VSI; /* By default FW has this off for performance reasons */ - pf->flags &= ~I40E_FLAG_VEB_STATS_ENABLED; + clear_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags); /* set up queue assignment tracking */ size = sizeof(struct i40e_lump_tracking) @@ -12885,8 +12892,8 @@ static int i40e_sw_init(struct i40e_pf *pf) /* Link down on close must be on when total port shutdown * is enabled for a given port */ - pf->flags |= (I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED | - I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED); + set_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags); + set_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags); dev_info(&pf->pdev->dev, "total-port-shutdown was enabled, link-down-on-close is forced on\n"); } @@ -12912,31 +12919,31 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features) */ if (features & NETIF_F_NTUPLE) { /* Enable filters and mark for reset */ - if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) need_reset = true; /* enable FD_SB only if there is MSI-X vector and no cloud * filters exist */ if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) { - pf->flags |= I40E_FLAG_FD_SB_ENABLED; - pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE; + set_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); } } else { /* turn off filters, mark for reset and clear SW filter list */ - if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { need_reset = true; i40e_fdir_filter_exit(pf); } - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state); - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); /* reset fd counters */ pf->fd_add_err = 0; pf->fd_atr_cnt = 0; /* if ATR was auto disabled it can be re-enabled. */ if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) - if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) && (I40E_DEBUG_FD & pf->hw.debug_mask)) dev_info(&pf->pdev->dev, "ATR re-enabled.\n"); } @@ -13085,7 +13092,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev, struct i40e_pf *pf = np->vsi->back; struct i40e_hw *hw = &pf->hw; - if (!(pf->hw_features & I40E_HW_PORT_ID_VALID)) + if (!test_bit(I40E_HW_PORT_ID_VALID, pf->hw_features)) return -EOPNOTSUPP; ppid->id_len = min_t(int, sizeof(hw->mac.port_addr), sizeof(ppid->id)); @@ -13114,7 +13121,7 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct i40e_pf *pf = np->vsi->back; int err = 0; - if (!(pf->flags & I40E_FLAG_SRIOV_ENABLED)) + if (!test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) return -EOPNOTSUPP; if (vid) { @@ -13214,9 +13221,9 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, veb->bridge_mode = mode; /* TODO: If no VFs or VMDq VSIs, disallow VEB mode */ if (mode == BRIDGE_MODE_VEB) - pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; + set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); else - pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED; + clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); i40e_do_reset(pf, I40E_PF_RESET_FLAG, true); break; } @@ -13550,7 +13557,7 @@ static void i40e_queue_pair_enable_irq(struct i40e_vsi *vsi, int queue_pair) struct i40e_hw *hw = &pf->hw; /* All rings in a qp belong to the same qvector. */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) i40e_irq_dynamic_enable(vsi, rxr->q_vector->v_idx); else i40e_irq_dynamic_enable_icr0(pf); @@ -13575,7 +13582,7 @@ static void i40e_queue_pair_disable_irq(struct i40e_vsi *vsi, int queue_pair) * * All rings in a qp belong to the same qvector. */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { u32 intpf = vsi->base_vector + rxr->q_vector->v_idx; wr32(hw, I40E_PFINT_DYN_CTLN(intpf - 1), 0); @@ -13760,7 +13767,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) NETIF_F_RXCSUM | 0; - if (!(pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE)) + if (!test_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features)) netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM; netdev->udp_tunnel_nic_info = &pf->udp_tunnel_nic; @@ -13796,7 +13803,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; - if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags)) hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; netdev->hw_features |= hw_features | NETIF_F_LOOPBACK; @@ -13987,7 +13994,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) * negative logic - if it's set, we need to fiddle with * the VSI to disable source pruning. */ - if (pf->flags & I40E_FLAG_SOURCE_PRUNING_DISABLED) { + if (test_bit(I40E_FLAG_SOURCE_PRUNING_DIS, pf->flags)) { memset(&ctxt, 0, sizeof(ctxt)); ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; @@ -14009,7 +14016,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) } /* MFP mode setup queue map and update VSI */ - if ((pf->flags & I40E_FLAG_MFP_ENABLED) && + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(pf->hw.func_caps.iscsi)) { /* NIC type PF */ memset(&ctxt, 0, sizeof(ctxt)); ctxt.seid = pf->main_vsi_seid; @@ -14057,7 +14064,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ctxt.uplink_seid = vsi->uplink_seid; ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL; ctxt.flags = I40E_AQ_VSI_TYPE_PF; - if ((pf->flags & I40E_FLAG_VEB_MODE_ENABLED) && + if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags) && (i40e_is_vsi_uplink_mode_veb(vsi))) { ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); @@ -14105,7 +14112,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); } - if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, vsi->back->flags)) { ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID); ctxt.info.queueing_opt_flags |= @@ -14321,7 +14328,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) /* In Legacy mode, we do not have to get any other vector since we * piggyback on the misc/ICR0 for queue interrupts. */ - if (!(pf->flags & I40E_FLAG_MSIX_ENABLED)) + if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return ret; if (vsi->num_q_vectors) vsi->base_vector = i40e_get_lump(pf, pf->irq_pile, @@ -14488,9 +14495,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, * already enabled, in which case we can't force VEPA * mode. */ - if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) { + if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) { veb->bridge_mode = BRIDGE_MODE_VEPA; - pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED; + clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); } i40e_config_bridge_mode(veb); } @@ -14586,8 +14593,8 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, break; } - if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) && - (vsi->type == I40E_VSI_VMDQ2)) { + if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features) && + vsi->type == I40E_VSI_VMDQ2) { ret = i40e_vsi_config_rss(vsi); if (ret) goto err_config; @@ -14833,7 +14840,7 @@ void i40e_veb_release(struct i40e_veb *veb) static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) { struct i40e_pf *pf = veb->pf; - bool enable_stats = !!(pf->flags & I40E_FLAG_VEB_STATS_ENABLED); + bool enable_stats = !!test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags); int ret; ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid, @@ -15133,7 +15140,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acqui */ if ((pf->hw.pf_id == 0) && - !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) { + !test_bit(I40E_FLAG_TRUE_PROMISC_ENA, pf->flags)) { flags = I40E_AQ_SET_SWITCH_CFG_PROMISC; pf->last_sw_conf_flags = flags; } @@ -15200,7 +15207,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acqui /* enable RSS in the HW, even for only one queue, as the stack can use * the hash */ - if ((pf->flags & I40E_FLAG_RSS_ENABLED)) + if (test_bit(I40E_FLAG_RSS_ENA, pf->flags)) i40e_pf_config_rss(pf); /* fill in link information and enable LSE reporting */ @@ -15242,42 +15249,42 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) queues_left = pf->hw.func_caps.num_tx_qp; if ((queues_left == 1) || - !(pf->flags & I40E_FLAG_MSIX_ENABLED)) { + !test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { /* one qp for PF, no queues for anything else */ queues_left = 0; pf->alloc_rss_size = pf->num_lan_qps = 1; /* make sure all the fancies are disabled */ - pf->flags &= ~(I40E_FLAG_RSS_ENABLED | - I40E_FLAG_IWARP_ENABLED | - I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED | - I40E_FLAG_DCB_CAPABLE | - I40E_FLAG_DCB_ENABLED | - I40E_FLAG_SRIOV_ENABLED | - I40E_FLAG_VMDQ_ENABLED); - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; - } else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED | - I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED | - I40E_FLAG_DCB_CAPABLE))) { + clear_bit(I40E_FLAG_RSS_ENA, pf->flags); + clear_bit(I40E_FLAG_IWARP_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags); + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); + clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags); + clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); + } else if (!test_bit(I40E_FLAG_RSS_ENA, pf->flags) && + !test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && + !test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) && + !test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) { /* one qp for PF */ pf->alloc_rss_size = pf->num_lan_qps = 1; queues_left -= pf->num_lan_qps; - pf->flags &= ~(I40E_FLAG_RSS_ENABLED | - I40E_FLAG_IWARP_ENABLED | - I40E_FLAG_FD_SB_ENABLED | - I40E_FLAG_FD_ATR_ENABLED | - I40E_FLAG_DCB_ENABLED | - I40E_FLAG_VMDQ_ENABLED); - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + clear_bit(I40E_FLAG_RSS_ENA, pf->flags); + clear_bit(I40E_FLAG_IWARP_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); + clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); } else { /* Not enough queues for all TCs */ - if ((pf->flags & I40E_FLAG_DCB_CAPABLE) && - (queues_left < I40E_MAX_TRAFFIC_CLASS)) { - pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | - I40E_FLAG_DCB_ENABLED); + if (test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags) && + queues_left < I40E_MAX_TRAFFIC_CLASS) { + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); dev_info(&pf->pdev->dev, "not enough queues for DCB. DCB is disabled.\n"); } @@ -15290,24 +15297,24 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) queues_left -= pf->num_lan_qps; } - if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { if (queues_left > 1) { queues_left -= 1; /* save 1 queue for FD */ } else { - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - pf->flags |= I40E_FLAG_FD_SB_INACTIVE; + clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags); + set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags); dev_info(&pf->pdev->dev, "not enough queues for Flow Director. Flow Director feature is disabled\n"); } } - if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) && + if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) && pf->num_vf_qps && pf->num_req_vfs && queues_left) { pf->num_req_vfs = min_t(int, pf->num_req_vfs, (queues_left / pf->num_vf_qps)); queues_left -= (pf->num_req_vfs * pf->num_vf_qps); } - if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) && + if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags) && pf->num_vmdq_vsis && pf->num_vmdq_qps && queues_left) { pf->num_vmdq_vsis = min_t(int, pf->num_vmdq_vsis, (queues_left / pf->num_vmdq_qps)); @@ -15318,7 +15325,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) dev_dbg(&pf->pdev->dev, "qs_avail=%d FD SB=%d lan_qs=%d lan_tc0=%d vf=%d*%d vmdq=%d*%d, remaining=%d\n", pf->hw.func_caps.num_tx_qp, - !!(pf->flags & I40E_FLAG_FD_SB_ENABLED), + !!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags), pf->num_lan_qps, pf->alloc_rss_size, pf->num_req_vfs, pf->num_vf_qps, pf->num_vmdq_vsis, pf->num_vmdq_qps, queues_left); @@ -15342,7 +15349,8 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf) settings->hash_lut_size = I40E_HASH_LUT_SIZE_128; /* Flow Director is enabled */ - if (pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)) + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) || + test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags)) settings->enable_fdir = true; /* Ethtype and MACVLAN filters enabled for PF */ @@ -15374,21 +15382,21 @@ static void i40e_print_features(struct i40e_pf *pf) i += scnprintf(&buf[i], REMAIN(i), " VSIs: %d QP: %d", pf->hw.func_caps.num_vsis, pf->vsi[pf->lan_vsi]->num_queue_pairs); - if (pf->flags & I40E_FLAG_RSS_ENABLED) + if (test_bit(I40E_FLAG_RSS_ENA, pf->flags)) i += scnprintf(&buf[i], REMAIN(i), " RSS"); - if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) + if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags)) i += scnprintf(&buf[i], REMAIN(i), " FD_ATR"); - if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { i += scnprintf(&buf[i], REMAIN(i), " FD_SB"); i += scnprintf(&buf[i], REMAIN(i), " NTUPLE"); } - if (pf->flags & I40E_FLAG_DCB_CAPABLE) + if (test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) i += scnprintf(&buf[i], REMAIN(i), " DCB"); i += scnprintf(&buf[i], REMAIN(i), " VxLAN"); i += scnprintf(&buf[i], REMAIN(i), " Geneve"); - if (pf->flags & I40E_FLAG_PTP) + if (test_bit(I40E_FLAG_PTP_ENA, pf->flags)) i += scnprintf(&buf[i], REMAIN(i), " PTP"); - if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) + if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) i += scnprintf(&buf[i], REMAIN(i), " VEB"); else i += scnprintf(&buf[i], REMAIN(i), " VEPA"); @@ -15419,22 +15427,26 @@ static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf) * @fec_cfg: FEC option to set in flags * @flags: ptr to flags in which we set FEC option **/ -void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags) +void i40e_set_fec_in_flags(u8 fec_cfg, unsigned long *flags) { - if (fec_cfg & I40E_AQ_SET_FEC_AUTO) - *flags |= I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC; + if (fec_cfg & I40E_AQ_SET_FEC_AUTO) { + set_bit(I40E_FLAG_RS_FEC, flags); + set_bit(I40E_FLAG_BASE_R_FEC, flags); + } if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_RS) || (fec_cfg & I40E_AQ_SET_FEC_ABILITY_RS)) { - *flags |= I40E_FLAG_RS_FEC; - *flags &= ~I40E_FLAG_BASE_R_FEC; + set_bit(I40E_FLAG_RS_FEC, flags); + clear_bit(I40E_FLAG_BASE_R_FEC, flags); } if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_KR) || (fec_cfg & I40E_AQ_SET_FEC_ABILITY_KR)) { - *flags |= I40E_FLAG_BASE_R_FEC; - *flags &= ~I40E_FLAG_RS_FEC; + set_bit(I40E_FLAG_BASE_R_FEC, flags); + clear_bit(I40E_FLAG_RS_FEC, flags); + } + if (fec_cfg == 0) { + clear_bit(I40E_FLAG_RS_FEC, flags); + clear_bit(I40E_FLAG_BASE_R_FEC, flags); } - if (fec_cfg == 0) - *flags &= ~(I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC); } /** @@ -15915,7 +15927,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * Ignore error return codes because if it was already disabled via * hardware settings this will fail */ - if (pf->hw_features & I40E_HW_STOP_FW_LLDP) { + if (test_bit(I40E_HW_STOP_FW_LLDP, pf->hw_features)) { dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n"); i40e_aq_stop_lldp(hw, true, false, NULL); } @@ -15932,7 +15944,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ether_addr_copy(hw->mac.perm_addr, hw->mac.addr); i40e_get_port_mac_addr(hw, hw->mac.port_addr); if (is_valid_ether_addr(hw->mac.port_addr)) - pf->hw_features |= I40E_HW_PORT_ID_VALID; + set_bit(I40E_HW_PORT_ID_VALID, pf->hw_features); i40e_ptp_alloc_pins(pf); pci_set_drvdata(pdev, pf); @@ -15942,10 +15954,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) status = i40e_get_fw_lldp_status(&pf->hw, &lldp_status); (!status && lldp_status == I40E_GET_FW_LLDP_STATUS_ENABLED) ? - (pf->flags &= ~I40E_FLAG_DISABLE_FW_LLDP) : - (pf->flags |= I40E_FLAG_DISABLE_FW_LLDP); + (clear_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)) : + (set_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)); dev_info(&pdev->dev, - (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) ? + test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags) ? "FW LLDP is disabled\n" : "FW LLDP is enabled\n"); @@ -15955,7 +15967,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_pf_dcb(pf); if (err) { dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err); - pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | I40E_FLAG_DCB_ENABLED); + clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); + clear_bit(I40E_FLAG_DCB_ENA, pf->flags); /* Continue without DCB enabled */ } #endif /* CONFIG_I40E_DCB */ @@ -16023,11 +16036,11 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_PCI_IOV /* prep for VF support */ - if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) && - (pf->flags & I40E_FLAG_MSIX_ENABLED) && + if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) && + test_bit(I40E_FLAG_MSIX_ENA, pf->flags) && !test_bit(__I40E_BAD_EEPROM, pf->state)) { if (pci_num_vf(pdev)) - pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; + set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); } #endif err = i40e_setup_pf_switch(pf, false, false); @@ -16068,7 +16081,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) wr32(hw, I40E_REG_MSS, val); } - if (pf->hw_features & I40E_HW_RESTART_AUTONEG) { + if (test_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features)) { msleep(75); err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (err) @@ -16088,7 +16101,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * the misc functionality and queue processing is combined in * the same vector and that gets setup at open. */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { err = i40e_setup_misc_vector(pf); if (err) { dev_info(&pdev->dev, @@ -16101,8 +16114,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_PCI_IOV /* prep for VF support */ - if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) && - (pf->flags & I40E_FLAG_MSIX_ENABLED) && + if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) && + test_bit(I40E_FLAG_MSIX_ENA, pf->flags) && !test_bit(__I40E_BAD_EEPROM, pf->state)) { /* disable link interrupts for VFs */ val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM); @@ -16122,7 +16135,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } #endif /* CONFIG_PCI_IOV */ - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { pf->iwarp_base_vector = i40e_get_lump(pf, pf->irq_pile, pf->num_iwarp_msix, I40E_IWARP_IRQ_PILE_ID); @@ -16130,7 +16143,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "failed to get tracking for %d vectors for IWARP err=%d\n", pf->num_iwarp_msix, pf->iwarp_base_vector); - pf->flags &= ~I40E_FLAG_IWARP_ENABLED; + clear_bit(I40E_FLAG_IWARP_ENA, pf->flags); } } @@ -16144,7 +16157,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) round_jiffies(jiffies + pf->service_timer_period)); /* add this PF to client device list and launch a client service task */ - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { err = i40e_lan_add_device(pf); if (err) dev_info(&pdev->dev, "Failed to add PF to client API service list: %d\n", @@ -16157,7 +16170,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * and will report PCI Gen 1 x 1 by default so don't bother * checking them. */ - if (!(pf->hw_features & I40E_HW_NO_PCI_LINK_CHECK)) { + if (!test_bit(I40E_HW_NO_PCI_LINK_CHECK, pf->hw_features)) { char speed[PCI_SPEED_SIZE] = "Unknown"; char width[PCI_WIDTH_SIZE] = "Unknown"; @@ -16211,7 +16224,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pf->hw.phy.link_info.requested_speeds = abilities.link_speed; /* set the FEC config due to the board capabilities */ - i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, &pf->flags); + i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, pf->flags); /* get the supported phy types from the fw */ err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, NULL); @@ -16238,10 +16251,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pf->main_vsi_seid); if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) || - (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) - pf->hw_features |= I40E_HW_PHY_CONTROLS_LEDS; + (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) + set_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features); if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722) - pf->hw_features |= I40E_HW_HAVE_CRT_RETIMER; + set_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features); /* print a string summarizing features */ i40e_print_features(pf); @@ -16310,10 +16323,10 @@ static void i40e_remove(struct pci_dev *pdev) usleep_range(1000, 2000); set_bit(__I40E_IN_REMOVE, pf->state); - if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) { set_bit(__I40E_VF_RESETS_DISABLED, pf->state); i40e_free_vfs(pf); - pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; + clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags); } /* no more scheduling of any task */ set_bit(__I40E_SUSPENDED, pf->state); @@ -16368,7 +16381,7 @@ static void i40e_remove(struct pci_dev *pdev) i40e_cloud_filter_exit(pf); /* remove attached clients */ - if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) { ret_code = i40e_lan_del_device(pf); if (ret_code) dev_warn(&pdev->dev, "Failed to delete client device: %d\n", @@ -16387,7 +16400,7 @@ static void i40e_remove(struct pci_dev *pdev) unmap: /* Free MSI/legacy interrupt 0 when in recovery mode. */ if (test_bit(__I40E_RECOVERY_MODE, pf->state) && - !(pf->flags & I40E_FLAG_MSIX_ENABLED)) + !test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) free_irq(pf->pdev->irq, pf); /* shutdown the adminq */ @@ -16603,7 +16616,8 @@ static void i40e_shutdown(struct pci_dev *pdev) */ i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false); - if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE)) + if (test_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features) && + pf->wol_en) i40e_enable_mc_magic_wake(pf); i40e_prep_for_reset(pf); @@ -16615,7 +16629,7 @@ static void i40e_shutdown(struct pci_dev *pdev) /* Free MSI/legacy interrupt 0 when in recovery mode. */ if (test_bit(__I40E_RECOVERY_MODE, pf->state) && - !(pf->flags & I40E_FLAG_MSIX_ENABLED)) + !test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) free_irq(pf->pdev->irq, pf); /* Since we're going to destroy queues during the @@ -16656,7 +16670,8 @@ static int __maybe_unused i40e_suspend(struct device *dev) */ i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false); - if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE)) + if (test_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features) && + pf->wol_en) i40e_enable_mc_magic_wake(pf); /* Since we're going to destroy queues during the diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 65c714d0bfff..10fb83d2ffe1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -680,7 +680,7 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf) * configured. We don't want to spuriously warn about Rx timestamp * hangs if we don't care about the timestamps. */ - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx) return; spin_lock_bh(&pf->ptp_rx_lock); @@ -733,7 +733,7 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf) { struct sk_buff *skb; - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx) return; /* Nothing to do if we're not already waiting for a timestamp */ @@ -771,7 +771,7 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) u32 hi, lo; u64 ns; - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx) return; /* don't attempt to timestamp if we don't have an skb */ @@ -818,7 +818,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx) return; hw = &pf->hw; @@ -924,7 +924,7 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) { struct hwtstamp_config *config = &pf->tstamp_config; - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return -EOPNOTSUPP; return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? @@ -1211,7 +1211,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) + if (!test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) return -ERANGE; pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | @@ -1225,7 +1225,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) + if (!test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) return -ERANGE; fallthrough; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: @@ -1234,7 +1234,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V2; - if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE) { + if (test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) { tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; } else { @@ -1308,7 +1308,7 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) struct hwtstamp_config config; int err; - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return -EOPNOTSUPP; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) @@ -1426,7 +1426,7 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf) void i40e_ptp_save_hw_time(struct i40e_pf *pf) { /* don't try to access the PTP clock if it's not enabled */ - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return; i40e_ptp_gettimex(&pf->ptp_caps, &pf->ptp_prev_hw_time, NULL); @@ -1483,7 +1483,7 @@ void i40e_ptp_init(struct i40e_pf *pf) pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> I40E_PRTTSYN_CTL0_PF_ID_SHIFT; if (hw->pf_id != pf_id) { - pf->flags &= ~I40E_FLAG_PTP; + clear_bit(I40E_FLAG_PTP_ENA, pf->flags); dev_info(&pf->pdev->dev, "%s: PTP not supported on %s\n", __func__, netdev->name); @@ -1504,7 +1504,7 @@ void i40e_ptp_init(struct i40e_pf *pf) if (pf->hw.debug_mask & I40E_DEBUG_LAN) dev_info(&pf->pdev->dev, "PHC enabled\n"); - pf->flags |= I40E_FLAG_PTP; + set_bit(I40E_FLAG_PTP_ENA, pf->flags); /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); @@ -1539,7 +1539,7 @@ void i40e_ptp_stop(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; u32 regval; - pf->flags &= ~I40E_FLAG_PTP; + clear_bit(I40E_FLAG_PTP_ENA, pf->flags); pf->ptp_tx = false; pf->ptp_rx = false; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index dd410b15000f..b82df5bdfac0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -464,7 +464,7 @@ static int i40e_add_del_fdir_tcp(struct i40e_vsi *vsi, &pf->fd_tcp6_filter_cnt); if (add) { - if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) && I40E_DEBUG_FD & pf->hw.debug_mask) dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state); @@ -734,7 +734,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u64 qword0_raw, * FD ATR/SB and then re-enable it when there is room. */ if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) { - if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && + if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && !test_and_set_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) if (I40E_DEBUG_FD & pf->hw.debug_mask) @@ -1071,7 +1071,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, if (q_vector->arm_wb_state) return; - if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) { val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK | I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */ @@ -1095,7 +1095,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, **/ void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { - if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { + if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) { u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */ I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | @@ -2699,7 +2699,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, u32 intval; /* If we don't have MSIX, then we only need to re-enable icr0 */ - if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED)) { + if (!test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) { i40e_irq_dynamic_enable_icr0(vsi->back); return; } @@ -2888,7 +2888,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, u16 i; /* make sure ATR is enabled */ - if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) + if (!test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags)) return; if (test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) @@ -2933,7 +2933,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, /* Due to lack of space, no more new filters can be programmed */ if (th->syn && test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) return; - if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) { + if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags)) { /* HW ATR eviction will take care of removing filters on FIN * and RST packets. */ @@ -2995,7 +2995,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & I40E_TXD_FLTR_QW1_CNTINDEX_MASK; - if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) + if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags)) dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK; fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); @@ -3053,7 +3053,7 @@ static inline int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, tx_flags |= I40E_TX_FLAGS_SW_VLAN; } - if (!(tx_ring->vsi->back->flags & I40E_FLAG_DCB_ENABLED)) + if (!test_bit(I40E_FLAG_DCB_ENA, tx_ring->vsi->back->flags)) goto out; /* Insert 802.1p priority into VLAN header */ @@ -3229,7 +3229,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, * we are not already transmitting a packet to be timestamped */ pf = i40e_netdev_to_pf(tx_ring->netdev); - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return 0; if (pf->ptp_tx && diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 1c667408f687..cbc2eda0ddaa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -92,8 +92,8 @@ enum i40e_dyn_idx { BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) #define i40e_pf_get_default_rss_hena(pf) \ - (((pf)->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \ - I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA) + (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, (pf)->hw_features) ? \ + I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA) /* Supported Rx Buffer Sizes (a multiple of 128) */ #define I40E_RXBUFFER_256 256 diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 08d7edccfb8d..8236baedfadd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1808,7 +1808,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) if (pci_num_vf(pf->pdev) != num_alloc_vfs) { ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); if (ret) { - pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED; + clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); pf->num_alloc_vfs = 0; goto err_iov; } @@ -1919,8 +1919,8 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) } if (num_vfs) { - if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) { - pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; + if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) { + set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG); } ret = i40e_pci_sriov_enable(pdev, num_vfs); @@ -1929,7 +1929,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) if (!pci_vfs_assigned(pf->pdev)) { i40e_free_vfs(pf); - pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED; + clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags); i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG); } else { dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n"); @@ -2137,14 +2137,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) { vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; } else { - if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) && + if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features) && (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ; else vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; } - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) { + if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, pf->hw_features)) { if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; @@ -2153,12 +2153,12 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; - if ((pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE) && + if (test_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features) && (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) { - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { dev_err(&pf->pdev->dev, "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n", vf->vf_id); @@ -2168,7 +2168,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; } - if (pf->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) { + if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, pf->hw_features)) { if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; @@ -4841,7 +4841,7 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting) goto out; } - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) { dev_err(&pf->pdev->dev, "Trusted VF not supported in MFP mode.\n"); ret = -EINVAL; goto out; From d0b1314c8b338bc053b5d266579afb79490f5f9a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:26 -0800 Subject: [PATCH 0572/7721] i40e: Use DECLARE_BITMAP for flags field in i40e_hw Convert flags field in i40e_hw from u64 to bitmap and its usage to use bit access functions and rename the field to 'caps' as this field describes capabilities that are set once on init and read many times later. Changes: - Convert "hw_ptr->flags & FLAG" to "test_bit(FLAG, ...)" - Convert "hw_ptr->flags |= FLAG" to "set_bit(FLAG, ...)" - Convert "hw_ptr->flags &= ~FLAG" to "clear_bit(FLAG, ...)" - Rename i40e_hw.flags to i40e_hw.caps - Rename i40e_set_hw_flags() to i40e_set_hw_caps() - Adjust caps names so they are prefixed by I40E_HW_CAP_ and existing _CAPABLE suffixes are stripped Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-8-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 38 +++++++++---------- drivers/net/ethernet/intel/i40e/i40e_common.c | 20 +++++----- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 2 +- .../net/ethernet/intel/i40e/i40e_ethtool.c | 10 ++--- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 10 ++--- drivers/net/ethernet/intel/i40e/i40e_type.h | 22 ++++++----- 7 files changed, 55 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 9a5a47b29bb7..6754f6b3508c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -503,44 +503,44 @@ static int i40e_shutdown_arq(struct i40e_hw *hw) } /** - * i40e_set_hw_flags - set HW flags + * i40e_set_hw_caps - set HW flags * @hw: pointer to the hardware structure **/ -static void i40e_set_hw_flags(struct i40e_hw *hw) +static void i40e_set_hw_caps(struct i40e_hw *hw) { struct i40e_adminq_info *aq = &hw->aq; - hw->flags = 0; + bitmap_zero(hw->caps, I40E_HW_CAPS_NBITS); switch (hw->mac.type) { case I40E_MAC_XL710: if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)) { - hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; - hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); + set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); /* The ability to RX (not drop) 802.1ad frames */ - hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE; + set_bit(I40E_HW_CAP_802_1AD, hw->caps); } break; case I40E_MAC_X722: - hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE | - I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; + set_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps); + set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps); if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722)) - hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_X722)) - hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; + set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= I40E_MINOR_VER_FW_REQUEST_FEC_X722)) - hw->flags |= I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE; + set_bit(I40E_HW_CAP_X722_FEC_REQUEST, hw->caps); fallthrough; default: @@ -551,17 +551,17 @@ static void i40e_set_hw_flags(struct i40e_hw *hw) if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= 5)) - hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; + set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps); if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= 8)) - hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT; + set_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps); if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= 9)) - hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED; + set_bit(I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, hw->caps); } /** @@ -631,7 +631,7 @@ int i40e_init_adminq(struct i40e_hw *hw) /* Some features were introduced in different FW API version * for different MAC type. */ - i40e_set_hw_flags(hw); + i40e_set_hw_caps(hw); /* get the NVM version info */ i40e_read_nvm_word(hw, I40E_SR_NVM_DEV_STARTER_VERSION, @@ -649,20 +649,20 @@ int i40e_init_adminq(struct i40e_hw *hw) if (hw->mac.type == I40E_MAC_XL710 && hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) { - hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; - hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); + set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); } if (hw->mac.type == I40E_MAC_X722 && hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && hw->aq.api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722) { - hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); } /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */ if (hw->aq.api_maj_ver > 1 || (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver >= 7)) - hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE; + set_bit(I40E_HW_CAP_802_1AD, hw->caps); if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) { ret_code = -EIO; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index d7e24d661724..7fce881abc93 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1650,7 +1650,7 @@ int i40e_aq_get_link_info(struct i40e_hw *hw, hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE) hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU; - if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE && + if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps) && hw->mac.type != I40E_MAC_X722) { __le32 tmp; @@ -2253,7 +2253,7 @@ int i40e_aq_set_switch_config(struct i40e_hw *hw, scfg->flags = cpu_to_le16(flags); scfg->valid_flags = cpu_to_le16(valid_flags); scfg->mode = mode; - if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) { + if (test_bit(I40E_HW_CAP_802_1AD, hw->caps)) { scfg->switch_tag = cpu_to_le16(hw->switch_tag); scfg->first_tag = cpu_to_le16(hw->first_tag); scfg->second_tag = cpu_to_le16(hw->second_tag); @@ -3637,7 +3637,7 @@ i40e_aq_restore_lldp(struct i40e_hw *hw, u8 *setting, bool restore, (struct i40e_aqc_lldp_restore *)&desc.params.raw; int status; - if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)) { + if (!test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) { i40e_debug(hw, I40E_DEBUG_ALL, "Restore LLDP not supported by current FW version.\n"); return -ENODEV; @@ -3680,7 +3680,7 @@ int i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent, cmd->command |= I40E_AQ_LLDP_AGENT_SHUTDOWN; if (persist) { - if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) + if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) cmd->command |= I40E_AQ_LLDP_AGENT_STOP_PERSIST; else i40e_debug(hw, I40E_DEBUG_ALL, @@ -3713,7 +3713,7 @@ int i40e_aq_start_lldp(struct i40e_hw *hw, bool persist, cmd->command = I40E_AQ_LLDP_AGENT_START; if (persist) { - if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) + if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) cmd->command |= I40E_AQ_LLDP_AGENT_START_PERSIST; else i40e_debug(hw, I40E_DEBUG_ALL, @@ -3741,7 +3741,7 @@ i40e_aq_set_dcb_parameters(struct i40e_hw *hw, bool dcb_enable, (struct i40e_aqc_set_dcb_parameters *)&desc.params.raw; int status; - if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) + if (!test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps)) return -ENODEV; i40e_fill_default_direct_cmd_desc(&desc, @@ -5043,7 +5043,7 @@ static int i40e_led_get_reg(struct i40e_hw *hw, u16 led_addr, u32 i; *reg_val = 0; - if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) { + if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) { status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, @@ -5076,7 +5076,7 @@ static int i40e_led_set_reg(struct i40e_hw *hw, u16 led_addr, int status; u32 i; - if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) { + if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) { status = i40e_aq_set_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, @@ -5115,7 +5115,7 @@ int i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr, u8 port_num; u32 i; - if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) { + if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) { status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, @@ -5335,7 +5335,7 @@ static void i40e_mdio_if_number_selection(struct i40e_hw *hw, bool set_mdio, struct i40e_aqc_phy_register_access *cmd) { if (set_mdio && cmd->phy_interface == I40E_AQ_PHY_REG_ACCESS_EXTERNAL) { - if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED) + if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, hw->caps)) cmd->cmd_flags |= I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER | ((mdio_num << diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 68602fc375f6..39e44a2e0677 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -877,7 +877,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change) return -EOPNOTSUPP; /* Read LLDP NVM area */ - if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) { + if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) { u8 offset = 0; if (hw->mac.type == I40E_MAC_XL710) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index a06062c2e84d..b4cc9bb4bc4e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1595,7 +1595,7 @@ static int i40e_set_fec_param(struct net_device *netdev, return -EPERM; if (hw->mac.type == I40E_MAC_X722 && - !(hw->flags & I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE)) { + !test_bit(I40E_HW_CAP_X722_FEC_REQUEST, hw->caps)) { netdev_err(netdev, "Setting FEC encoding not supported by firmware. Please update the NVM image.\n"); return -EOPNOTSUPP; } @@ -2831,7 +2831,7 @@ static int i40e_set_phys_id(struct net_device *netdev, if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) { pf->led_status = i40e_led_get(hw); } else { - if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) + if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) i40e_aq_set_phy_debug(hw, I40E_PHY_DEBUG_ALL, NULL); ret = i40e_led_get_phy(hw, &temp_status, @@ -2858,7 +2858,7 @@ static int i40e_set_phys_id(struct net_device *netdev, ret = i40e_led_set_phy(hw, false, pf->led_status, (pf->phy_led_val | I40E_PHY_LED_MODE_ORIG)); - if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) + if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) i40e_aq_set_phy_debug(hw, 0, NULL); } break; @@ -5340,7 +5340,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) * LLDP with this flag on unsupported FW versions. */ if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags) && - (!(pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))) { + !test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps)) { dev_warn(&pf->pdev->dev, "Device does not support changing FW LLDP\n"); return -EOPNOTSUPP; @@ -5511,7 +5511,7 @@ static int i40e_get_module_info(struct net_device *netdev, int status; /* Check if firmware supports reading module EEPROM. */ - if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) { + if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) { netdev_err(vsi->netdev, "Module EEPROM memory read not supported. Please update the NVM image.\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1c84136b9482..7523ac4bd430 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -12856,8 +12856,8 @@ static int i40e_sw_init(struct i40e_pf *pf) */ if (pf->hw.mac.type == I40E_MAC_XL710 && pf->hw.func_caps.npar_enable && - (pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) - pf->hw.flags &= ~I40E_HW_FLAG_FW_LLDP_STOPPABLE; + test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps)) + clear_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps); #ifdef CONFIG_PCI_IOV if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 77cdbfc19d47..62eb34871094 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -291,7 +291,7 @@ static int i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, static int __i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data) { - if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) + if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps)) return i40e_read_nvm_word_aq(hw, offset, data); return i40e_read_nvm_word_srctl(hw, offset, data); @@ -310,14 +310,14 @@ int i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, { int ret_code = 0; - if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK) + if (test_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps)) ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); if (ret_code) return ret_code; ret_code = __i40e_read_nvm_word(hw, offset, data); - if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK) + if (test_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps)) i40e_release_nvm(hw); return ret_code; @@ -499,7 +499,7 @@ static int __i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data) { - if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) + if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps)) return i40e_read_nvm_buffer_aq(hw, offset, words, data); return i40e_read_nvm_buffer_srctl(hw, offset, words, data); @@ -521,7 +521,7 @@ int i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, { int ret_code = 0; - if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) { + if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps)) { ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); if (!ret_code) { ret_code = i40e_read_nvm_buffer_aq(hw, offset, words, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 060aac35d945..889bc2404738 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -482,6 +482,18 @@ struct i40e_dcbx_config { struct i40e_dcb_app_priority_table app[I40E_DCBX_MAX_APPS]; }; +enum i40e_hw_flags { + I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, + I40E_HW_CAP_802_1AD, + I40E_HW_CAP_AQ_PHY_ACCESS, + I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, + I40E_HW_CAP_FW_LLDP_STOPPABLE, + I40E_HW_CAP_FW_LLDP_PERSISTENT, + I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, + I40E_HW_CAP_X722_FEC_REQUEST, + I40E_HW_CAPS_NBITS, +}; + /* Port hardware description */ struct i40e_hw { u8 __iomem *hw_addr; @@ -546,15 +558,7 @@ struct i40e_hw { struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */ struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */ -#define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0) -#define I40E_HW_FLAG_802_1AD_CAPABLE BIT_ULL(1) -#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE BIT_ULL(2) -#define I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK BIT_ULL(3) -#define I40E_HW_FLAG_FW_LLDP_STOPPABLE BIT_ULL(4) -#define I40E_HW_FLAG_FW_LLDP_PERSISTENT BIT_ULL(5) -#define I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED BIT_ULL(6) -#define I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE BIT_ULL(7) - u64 flags; + DECLARE_BITMAP(caps, I40E_HW_CAPS_NBITS); /* Used in set switch config AQ command */ u16 switch_tag; From 0e8b9fdd40fe65b28d58ea7fa3f97aed350da69a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:27 -0800 Subject: [PATCH 0573/7721] i40e: Consolidate hardware capabilities Fields .caps in i40e_hw and .hw_features in i40e_pf both indicate capabilities provided by hardware. Move and merge i40e_pf.hw_features into i40e_hw.caps as this is more appropriate place for them and adjust their names to I40E_HW_CAP_... convention. Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-9-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e.h | 27 +------ .../net/ethernet/intel/i40e/i40e_ethtool.c | 36 ++++----- drivers/net/ethernet/intel/i40e/i40e_main.c | 78 +++++++++---------- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 6 +- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 +- drivers/net/ethernet/intel/i40e/i40e_type.h | 18 +++++ .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 8 +- 7 files changed, 85 insertions(+), 90 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index ba87870e0fb4..6022944d04f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -34,11 +34,11 @@ #define I40E_MIN_VSI_ALLOC 83 /* LAN, ATR, FCOE, 64 VF */ /* max 16 qps */ #define i40e_default_queues_per_vmdq(pf) \ - (test_bit(I40E_HW_RSS_AQ_CAPABLE, (pf)->hw_features) ? 4 : 1) + (test_bit(I40E_HW_CAP_RSS_AQ, (pf)->hw.caps) ? 4 : 1) #define I40E_DEFAULT_QUEUES_PER_VF 4 #define I40E_MAX_VF_QUEUES 16 #define i40e_pf_get_max_q_per_tc(pf) \ - (test_bit(I40E_HW_128_QP_RSS_CAPABLE, (pf)->hw_features) ? 128 : 64) + (test_bit(I40E_HW_CAP_128_QP_RSS, (pf)->hw.caps) ? 128 : 64) #define I40E_FDIR_RING_COUNT 32 #define I40E_MAX_AQ_BUF_SIZE 4096 #define I40E_AQ_LEN 256 @@ -139,28 +139,6 @@ enum i40e_vsi_state { __I40E_VSI_STATE_SIZE__, }; -enum i40e_pf_hw_features { - I40E_HW_RSS_AQ_CAPABLE, - I40E_HW_128_QP_RSS_CAPABLE, - I40E_HW_ATR_EVICT_CAPABLE, - I40E_HW_WB_ON_ITR_CAPABLE, - I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, - I40E_HW_NO_PCI_LINK_CHECK, - I40E_HW_100M_SGMII_CAPABLE, - I40E_HW_NO_DCB_SUPPORT, - I40E_HW_USE_SET_LLDP_MIB, - I40E_HW_GENEVE_OFFLOAD_CAPABLE, - I40E_HW_PTP_L4_CAPABLE, - I40E_HW_WOL_MC_MAGIC_PKT_WAKE, - I40E_HW_HAVE_CRT_RETIMER, - I40E_HW_OUTER_UDP_CSUM_CAPABLE, - I40E_HW_PHY_CONTROLS_LEDS, - I40E_HW_STOP_FW_LLDP, - I40E_HW_PORT_ID_VALID, - I40E_HW_RESTART_AUTONEG, - I40E_PF_HW_FEATURES_NBITS, /* must be last */ -}; - enum i40e_pf_flags { I40E_FLAG_MSI_ENA, I40E_FLAG_MSIX_ENA, @@ -557,7 +535,6 @@ struct i40e_pf { struct timer_list service_timer; struct work_struct service_task; - DECLARE_BITMAP(hw_features, I40E_PF_HW_FEATURES_NBITS); DECLARE_BITMAP(flags, I40E_PF_FLAGS_NBITS); struct i40e_client_instance *cinst; bool stat_offsets_loaded; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b4cc9bb4bc4e..eb9a7b32af73 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -502,7 +502,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) ethtool_link_ksettings_add_link_mode(ks, advertising, 1000baseT_Full); - if (test_bit(I40E_HW_100M_SGMII_CAPABLE, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_100M_SGMII, pf->hw.caps)) { ethtool_link_ksettings_add_link_mode(ks, supported, 100baseT_Full); ethtool_link_ksettings_add_link_mode(ks, advertising, @@ -601,7 +601,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, 10000baseKX4_Full); } if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_KR && - !test_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features)) { + !test_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps)) { ethtool_link_ksettings_add_link_mode(ks, supported, 10000baseKR_Full); if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB) @@ -609,7 +609,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, 10000baseKR_Full); } if (phy_types & I40E_CAP_PHY_TYPE_1000BASE_KX && - !test_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features)) { + !test_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps)) { ethtool_link_ksettings_add_link_mode(ks, supported, 1000baseKX_Full); if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) @@ -917,7 +917,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw, if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) ethtool_link_ksettings_add_link_mode(ks, advertising, 1000baseT_Full); - if (test_bit(I40E_HW_100M_SGMII_CAPABLE, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_100M_SGMII, pf->hw.caps)) { ethtool_link_ksettings_add_link_mode(ks, supported, 100baseT_Full); if (hw_link_info->requested_speeds & @@ -2579,7 +2579,7 @@ static int i40e_get_ts_info(struct net_device *dev, BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ); - if (test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) + if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | @@ -2828,7 +2828,7 @@ static int i40e_set_phys_id(struct net_device *netdev, switch (state) { case ETHTOOL_ID_ACTIVE: - if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) { + if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) { pf->led_status = i40e_led_get(hw); } else { if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) @@ -2840,19 +2840,19 @@ static int i40e_set_phys_id(struct net_device *netdev, } return blink_freq; case ETHTOOL_ID_ON: - if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) i40e_led_set(hw, 0xf, false); else ret = i40e_led_set_phy(hw, true, pf->led_status, 0); break; case ETHTOOL_ID_OFF: - if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) i40e_led_set(hw, 0x0, false); else ret = i40e_led_set_phy(hw, false, pf->led_status, 0); break; case ETHTOOL_ID_INACTIVE: - if (!test_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features)) { + if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) { i40e_led_set(hw, pf->led_status, false); } else { ret = i40e_led_set_phy(hw, false, pf->led_status, @@ -3653,22 +3653,22 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) switch (nfc->flow_type) { case TCP_V4_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP, flow_pctypes); - if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, - pf->hw_features)) + if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, + pf->hw.caps)) set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK, flow_pctypes); break; case TCP_V6_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP, flow_pctypes); - if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, - pf->hw_features)) + if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, + pf->hw.caps)) set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK, flow_pctypes); break; case UDP_V4_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_UDP, flow_pctypes); - if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, - pf->hw_features)) { + if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, + pf->hw.caps)) { set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP, flow_pctypes); set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP, @@ -3678,8 +3678,8 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) break; case UDP_V6_FLOW: set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_UDP, flow_pctypes); - if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, - pf->hw_features)) { + if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, + pf->hw.caps)) { set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP, flow_pctypes); set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP, @@ -5328,7 +5328,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) /* ATR eviction is not supported on all devices */ if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, new_flags) && - !test_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features)) + !test_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps)) return -EOPNOTSUPP; /* If the driver detected FW LLDP was disabled on init, this flag could diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7523ac4bd430..5696864c5151 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1890,7 +1890,7 @@ static int i40e_vsi_config_rss(struct i40e_vsi *vsi) u8 *lut; int ret; - if (!test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps)) return 0; if (!vsi->rss_size) vsi->rss_size = min_t(int, pf->alloc_rss_size, @@ -7085,7 +7085,7 @@ int i40e_hw_dcb_config(struct i40e_pf *pf, struct i40e_dcbx_config *new_cfg) set_bit(__I40E_CLIENT_L2_CHANGE, pf->state); } /* registers are set, lets apply */ - if (test_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features)) + if (test_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps)) ret = i40e_hw_set_dcb_config(pf, new_cfg); } @@ -7106,7 +7106,7 @@ int i40e_dcb_sw_default_config(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; int err; - if (test_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps)) { /* Update the local cached instance with TC0 ETS */ memset(&pf->tmp_cfg, 0, sizeof(struct i40e_dcbx_config)); pf->tmp_cfg.etscfg.willing = I40E_IEEE_DEFAULT_ETS_WILLING; @@ -7167,7 +7167,7 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) /* Do not enable DCB for SW1 and SW2 images even if the FW is capable * Also do not enable DCBx if FW LLDP agent is disabled */ - if (test_bit(I40E_HW_NO_DCB_SUPPORT, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_NO_DCB_SUPPORT, pf->hw.caps)) { dev_info(&pf->pdev->dev, "DCB is not supported.\n"); err = -EOPNOTSUPP; goto out; @@ -11069,7 +11069,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) wr32(hw, I40E_REG_MSS, val); } - if (test_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) { msleep(75); ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (ret) @@ -11672,7 +11672,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) ring->count = vsi->num_tx_desc; ring->size = 0; ring->dcb_tc = 0; - if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, vsi->back->hw_features)) + if (test_bit(I40E_HW_CAP_WB_ON_ITR, vsi->back->hw.caps)) ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; ring->itr_setting = pf->tx_itr_default; WRITE_ONCE(vsi->tx_rings[i], ring++); @@ -11689,7 +11689,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) ring->count = vsi->num_tx_desc; ring->size = 0; ring->dcb_tc = 0; - if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, vsi->back->hw_features)) + if (test_bit(I40E_HW_CAP_WB_ON_ITR, vsi->back->hw.caps)) ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; set_ring_xdp(ring); ring->itr_setting = pf->tx_itr_default; @@ -12367,7 +12367,7 @@ int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) { struct i40e_pf *pf = vsi->back; - if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) + if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps)) return i40e_config_rss_aq(vsi, seed, lut, lut_size); else return i40e_config_rss_reg(vsi, seed, lut, lut_size); @@ -12386,7 +12386,7 @@ int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) { struct i40e_pf *pf = vsi->back; - if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features)) + if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps)) return i40e_get_rss_aq(vsi, seed, lut, lut_size); else return i40e_get_rss_reg(vsi, seed, lut, lut_size); @@ -12783,60 +12783,60 @@ static int i40e_sw_init(struct i40e_pf *pf) } if (pf->hw.mac.type == I40E_MAC_X722) { - set_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features); - set_bit(I40E_HW_128_QP_RSS_CAPABLE, pf->hw_features); - set_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features); - set_bit(I40E_HW_WB_ON_ITR_CAPABLE, pf->hw_features); - set_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, pf->hw_features); - set_bit(I40E_HW_NO_PCI_LINK_CHECK, pf->hw_features); - set_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features); - set_bit(I40E_HW_GENEVE_OFFLOAD_CAPABLE, pf->hw_features); - set_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features); - set_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features); - set_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features); + set_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps); + set_bit(I40E_HW_CAP_128_QP_RSS, pf->hw.caps); + set_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps); + set_bit(I40E_HW_CAP_WB_ON_ITR, pf->hw.caps); + set_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, pf->hw.caps); + set_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, pf->hw.caps); + set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps); + set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, pf->hw.caps); + set_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps); + set_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps); + set_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps); #define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03 if (rd32(&pf->hw, I40E_GLQF_FDEVICTENA(1)) != I40E_FDEVICT_PCTYPE_DEFAULT) { dev_warn(&pf->pdev->dev, "FD EVICT PCTYPES are not right, disable FD HW EVICT\n"); - clear_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features); + clear_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps); } } else if ((pf->hw.aq.api_maj_ver > 1) || ((pf->hw.aq.api_maj_ver == 1) && (pf->hw.aq.api_min_ver > 4))) { /* Supported in FW API version higher than 1.4 */ - set_bit(I40E_HW_GENEVE_OFFLOAD_CAPABLE, pf->hw_features); + set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, pf->hw.caps); } /* Enable HW ATR eviction if possible */ - if (test_bit(I40E_HW_ATR_EVICT_CAPABLE, pf->hw_features)) + if (test_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps)) set_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags); if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) || (pf->hw.aq.fw_maj_ver < 4))) { - set_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features); + set_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps); /* No DCB support for FW < v4.33 */ - set_bit(I40E_HW_NO_DCB_SUPPORT, pf->hw_features); + set_bit(I40E_HW_CAP_NO_DCB_SUPPORT, pf->hw.caps); } /* Disable FW LLDP if FW < v4.3 */ if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || (pf->hw.aq.fw_maj_ver < 4))) - set_bit(I40E_HW_STOP_FW_LLDP, pf->hw_features); + set_bit(I40E_HW_CAP_STOP_FW_LLDP, pf->hw.caps); /* Use the FW Set LLDP MIB API if FW > v4.40 */ if ((pf->hw.mac.type == I40E_MAC_XL710) && (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) || (pf->hw.aq.fw_maj_ver >= 5))) - set_bit(I40E_HW_USE_SET_LLDP_MIB, pf->hw_features); + set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps); /* Enable PTP L4 if FW > v6.0 */ if (pf->hw.mac.type == I40E_MAC_XL710 && pf->hw.aq.fw_maj_ver >= 6) - set_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features); + set_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps); if (pf->hw.func_caps.vmdq && num_online_cpus() != 1) { pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; @@ -13092,7 +13092,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev, struct i40e_pf *pf = np->vsi->back; struct i40e_hw *hw = &pf->hw; - if (!test_bit(I40E_HW_PORT_ID_VALID, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_PORT_ID_VALID, pf->hw.caps)) return -EOPNOTSUPP; ppid->id_len = min_t(int, sizeof(hw->mac.port_addr), sizeof(ppid->id)); @@ -13767,7 +13767,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) NETIF_F_RXCSUM | 0; - if (!test_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps)) netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM; netdev->udp_tunnel_nic_info = &pf->udp_tunnel_nic; @@ -14593,7 +14593,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, break; } - if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features) && + if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps) && vsi->type == I40E_VSI_VMDQ2) { ret = i40e_vsi_config_rss(vsi); if (ret) @@ -15927,7 +15927,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * Ignore error return codes because if it was already disabled via * hardware settings this will fail */ - if (test_bit(I40E_HW_STOP_FW_LLDP, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_STOP_FW_LLDP, pf->hw.caps)) { dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n"); i40e_aq_stop_lldp(hw, true, false, NULL); } @@ -15944,7 +15944,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ether_addr_copy(hw->mac.perm_addr, hw->mac.addr); i40e_get_port_mac_addr(hw, hw->mac.port_addr); if (is_valid_ether_addr(hw->mac.port_addr)) - set_bit(I40E_HW_PORT_ID_VALID, pf->hw_features); + set_bit(I40E_HW_CAP_PORT_ID_VALID, pf->hw.caps); i40e_ptp_alloc_pins(pf); pci_set_drvdata(pdev, pf); @@ -16081,7 +16081,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) wr32(hw, I40E_REG_MSS, val); } - if (test_bit(I40E_HW_RESTART_AUTONEG, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) { msleep(75); err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (err) @@ -16170,7 +16170,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * and will report PCI Gen 1 x 1 by default so don't bother * checking them. */ - if (!test_bit(I40E_HW_NO_PCI_LINK_CHECK, pf->hw_features)) { + if (!test_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, pf->hw.caps)) { char speed[PCI_SPEED_SIZE] = "Unknown"; char width[PCI_WIDTH_SIZE] = "Unknown"; @@ -16252,9 +16252,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) || (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) - set_bit(I40E_HW_PHY_CONTROLS_LEDS, pf->hw_features); + set_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps); if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722) - set_bit(I40E_HW_HAVE_CRT_RETIMER, pf->hw_features); + set_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps); /* print a string summarizing features */ i40e_print_features(pf); @@ -16616,7 +16616,7 @@ static void i40e_shutdown(struct pci_dev *pdev) */ i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false); - if (test_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features) && + if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) && pf->wol_en) i40e_enable_mc_magic_wake(pf); @@ -16670,7 +16670,7 @@ static int __maybe_unused i40e_suspend(struct device *dev) */ i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false); - if (test_bit(I40E_HW_WOL_MC_MAGIC_PKT_WAKE, pf->hw_features) && + if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) && pf->wol_en) i40e_enable_mc_magic_wake(pf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 10fb83d2ffe1..1cf993a79438 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -1211,7 +1211,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - if (!test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) return -ERANGE; pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | @@ -1225,7 +1225,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - if (!test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) + if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) return -ERANGE; fallthrough; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: @@ -1234,7 +1234,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V2; - if (test_bit(I40E_HW_PTP_L4_CAPABLE, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) { tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; } else { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index cbc2eda0ddaa..abf15067eb5d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -92,7 +92,7 @@ enum i40e_dyn_idx { BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) #define i40e_pf_get_default_rss_hena(pf) \ - (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, (pf)->hw_features) ? \ + (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, (pf)->hw.caps) ? \ I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA) /* Supported Rx Buffer Sizes (a multiple of 128) */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 889bc2404738..346a74a516a8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -491,6 +491,24 @@ enum i40e_hw_flags { I40E_HW_CAP_FW_LLDP_PERSISTENT, I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, I40E_HW_CAP_X722_FEC_REQUEST, + I40E_HW_CAP_RSS_AQ, + I40E_HW_CAP_128_QP_RSS, + I40E_HW_CAP_ATR_EVICT, + I40E_HW_CAP_WB_ON_ITR, + I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, + I40E_HW_CAP_NO_PCI_LINK_CHECK, + I40E_HW_CAP_100M_SGMII, + I40E_HW_CAP_NO_DCB_SUPPORT, + I40E_HW_CAP_USE_SET_LLDP_MIB, + I40E_HW_CAP_GENEVE_OFFLOAD, + I40E_HW_CAP_PTP_L4, + I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, + I40E_HW_CAP_CRT_RETIMER, + I40E_HW_CAP_OUTER_UDP_CSUM, + I40E_HW_CAP_PHY_CONTROLS_LEDS, + I40E_HW_CAP_STOP_FW_LLDP, + I40E_HW_CAP_PORT_ID_VALID, + I40E_HW_CAP_RESTART_AUTONEG, I40E_HW_CAPS_NBITS, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 8236baedfadd..af47ba51e28a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2137,14 +2137,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) { vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; } else { - if (test_bit(I40E_HW_RSS_AQ_CAPABLE, pf->hw_features) && + if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps) && (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ; else vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; } - if (test_bit(I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, pf->hw.caps)) { if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; @@ -2153,7 +2153,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; - if (test_bit(I40E_HW_OUTER_UDP_CSUM_CAPABLE, pf->hw_features) && + if (test_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps) && (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; @@ -2168,7 +2168,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; } - if (test_bit(I40E_HW_WB_ON_ITR_CAPABLE, pf->hw_features)) { + if (test_bit(I40E_HW_CAP_WB_ON_ITR, pf->hw.caps)) { if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; From 8cc29564d22777724626c4ea54fbe582d0c8e7d0 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:28 -0800 Subject: [PATCH 0574/7721] i40e: Initialize hardware capabilities at single place Some i40e_hw.caps bits are set in i40e_set_hw_caps(), some of them in i40e_init_adminq() and the rest of them in i40e_sw_init(). Consolidate the initialization to single proper place i40e_set_hw_caps(). Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-10-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 66 ++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_debug.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 55 +--------------- .../net/ethernet/intel/i40e/i40e_register.h | 1 + 4 files changed, 51 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 6754f6b3508c..86591140f748 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -522,10 +522,52 @@ static void i40e_set_hw_caps(struct i40e_hw *hw) /* The ability to RX (not drop) 802.1ad frames */ set_bit(I40E_HW_CAP_802_1AD, hw->caps); } + if ((aq->api_maj_ver == 1 && aq->api_min_ver > 4) || + aq->api_maj_ver > 1) { + /* Supported in FW API version higher than 1.4 */ + set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, hw->caps); + } + if ((aq->fw_maj_ver == 4 && aq->fw_min_ver < 33) || + aq->fw_maj_ver < 4) { + set_bit(I40E_HW_CAP_RESTART_AUTONEG, hw->caps); + /* No DCB support for FW < v4.33 */ + set_bit(I40E_HW_CAP_NO_DCB_SUPPORT, hw->caps); + } + if ((aq->fw_maj_ver == 4 && aq->fw_min_ver < 3) || + aq->fw_maj_ver < 4) { + /* Disable FW LLDP if FW < v4.3 */ + set_bit(I40E_HW_CAP_STOP_FW_LLDP, hw->caps); + } + if ((aq->fw_maj_ver == 4 && aq->fw_min_ver >= 40) || + aq->fw_maj_ver >= 5) { + /* Use the FW Set LLDP MIB API if FW > v4.40 */ + set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, hw->caps); + } + if (aq->fw_maj_ver >= 6) { + /* Enable PTP L4 if FW > v6.0 */ + set_bit(I40E_HW_CAP_PTP_L4, hw->caps); + } break; case I40E_MAC_X722: set_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps); set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps); + set_bit(I40E_HW_CAP_RSS_AQ, hw->caps); + set_bit(I40E_HW_CAP_128_QP_RSS, hw->caps); + set_bit(I40E_HW_CAP_ATR_EVICT, hw->caps); + set_bit(I40E_HW_CAP_WB_ON_ITR, hw->caps); + set_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, hw->caps); + set_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, hw->caps); + set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, hw->caps); + set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, hw->caps); + set_bit(I40E_HW_CAP_PTP_L4, hw->caps); + set_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, hw->caps); + set_bit(I40E_HW_CAP_OUTER_UDP_CSUM, hw->caps); + + if (rd32(hw, I40E_GLQF_FDEVICTENA(1)) != + I40E_FDEVICT_PCTYPE_DEFAULT) { + hw_warn(hw, "FD EVICT PCTYPES are not right, disable FD HW EVICT\n"); + clear_bit(I40E_HW_CAP_ATR_EVICT, hw->caps); + } if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && @@ -553,6 +595,12 @@ static void i40e_set_hw_caps(struct i40e_hw *hw) aq->api_min_ver >= 5)) set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps); + /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */ + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= 7)) + set_bit(I40E_HW_CAP_802_1AD, hw->caps); + if (aq->api_maj_ver > 1 || (aq->api_maj_ver == 1 && aq->api_min_ver >= 8)) @@ -646,24 +694,6 @@ int i40e_init_adminq(struct i40e_hw *hw) &oem_lo); hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo; - if (hw->mac.type == I40E_MAC_XL710 && - hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && - hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) { - set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); - set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); - } - if (hw->mac.type == I40E_MAC_X722 && - hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && - hw->aq.api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722) { - set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); - } - - /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */ - if (hw->aq.api_maj_ver > 1 || - (hw->aq.api_maj_ver == 1 && - hw->aq.api_min_ver >= 7)) - set_bit(I40E_HW_CAP_802_1AD, hw->caps); - if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) { ret_code = -EIO; goto init_adminq_free_arq; diff --git a/drivers/net/ethernet/intel/i40e/i40e_debug.h b/drivers/net/ethernet/intel/i40e/i40e_debug.h index 27ebc72d8bfe..e9871dfb32bd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debug.h +++ b/drivers/net/ethernet/intel/i40e/i40e_debug.h @@ -37,6 +37,7 @@ struct i40e_hw; struct device *i40e_hw_to_dev(struct i40e_hw *hw); #define hw_dbg(hw, S, A...) dev_dbg(i40e_hw_to_dev(hw), S, ##A) +#define hw_warn(hw, S, A...) dev_warn(i40e_hw_to_dev(hw), S, ##A) #define i40e_debug(h, m, s, ...) \ do { \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5696864c5151..8948bdc8bda1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -12782,62 +12782,10 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->hw.func_caps.fd_filters_best_effort; } - if (pf->hw.mac.type == I40E_MAC_X722) { - set_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps); - set_bit(I40E_HW_CAP_128_QP_RSS, pf->hw.caps); - set_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps); - set_bit(I40E_HW_CAP_WB_ON_ITR, pf->hw.caps); - set_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, pf->hw.caps); - set_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, pf->hw.caps); - set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps); - set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, pf->hw.caps); - set_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps); - set_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps); - set_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps); - -#define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03 - if (rd32(&pf->hw, I40E_GLQF_FDEVICTENA(1)) != - I40E_FDEVICT_PCTYPE_DEFAULT) { - dev_warn(&pf->pdev->dev, - "FD EVICT PCTYPES are not right, disable FD HW EVICT\n"); - clear_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps); - } - } else if ((pf->hw.aq.api_maj_ver > 1) || - ((pf->hw.aq.api_maj_ver == 1) && - (pf->hw.aq.api_min_ver > 4))) { - /* Supported in FW API version higher than 1.4 */ - set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, pf->hw.caps); - } - /* Enable HW ATR eviction if possible */ if (test_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps)) set_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags); - if ((pf->hw.mac.type == I40E_MAC_XL710) && - (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) || - (pf->hw.aq.fw_maj_ver < 4))) { - set_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps); - /* No DCB support for FW < v4.33 */ - set_bit(I40E_HW_CAP_NO_DCB_SUPPORT, pf->hw.caps); - } - - /* Disable FW LLDP if FW < v4.3 */ - if ((pf->hw.mac.type == I40E_MAC_XL710) && - (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || - (pf->hw.aq.fw_maj_ver < 4))) - set_bit(I40E_HW_CAP_STOP_FW_LLDP, pf->hw.caps); - - /* Use the FW Set LLDP MIB API if FW > v4.40 */ - if ((pf->hw.mac.type == I40E_MAC_XL710) && - (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) || - (pf->hw.aq.fw_maj_ver >= 5))) - set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps); - - /* Enable PTP L4 if FW > v6.0 */ - if (pf->hw.mac.type == I40E_MAC_XL710 && - pf->hw.aq.fw_maj_ver >= 6) - set_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps); - if (pf->hw.func_caps.vmdq && num_online_cpus() != 1) { pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; set_bit(I40E_FLAG_VMDQ_ENA, pf->flags); @@ -12855,8 +12803,7 @@ static int i40e_sw_init(struct i40e_pf *pf) * if NPAR is functioning so unset this hw flag in this case. */ if (pf->hw.mac.type == I40E_MAC_XL710 && - pf->hw.func_caps.npar_enable && - test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps)) + pf->hw.func_caps.npar_enable) clear_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps); #ifdef CONFIG_PCI_IOV diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index f408fcf23ce8..d561687303ea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -899,6 +899,7 @@ #define I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT 7 #define I40E_GLQF_ORT_FLX_PAYLOAD_MASK I40E_MASK(0x1, I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT) #define I40E_GLQF_FDEVICTENA(_i) (0x00270384 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ +#define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03 /* Redefined for X722 family */ #define I40E_GLGEN_STAT_CLEAR 0x00390004 /* Reset: CORER */ #endif /* _I40E_REGISTER_H_ */ From 28c1726b2c9cab8a6e541fbf6bca63caef912fc0 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:29 -0800 Subject: [PATCH 0575/7721] i40e: Move i40e_is_aq_api_ver_ge helper Move i40e_is_aq_api_ver_ge helper function (used to check if AdminQ API version is recent enough) to header so it can be used from other .c files. Signed-off-by: Ivan Vecera Reviewed-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-11-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_common.c | 23 ++++--------------- drivers/net/ethernet/intel/i40e/i40e_type.h | 14 +++++++++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 7fce881abc93..df7ba349030d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1749,21 +1749,6 @@ int i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, return status; } -/** - * i40e_is_aq_api_ver_ge - * @aq: pointer to AdminQ info containing HW API version to compare - * @maj: API major value - * @min: API minor value - * - * Assert whether current HW API version is greater/equal than provided. - **/ -static bool i40e_is_aq_api_ver_ge(struct i40e_adminq_info *aq, u16 maj, - u16 min) -{ - return (aq->api_maj_ver > maj || - (aq->api_maj_ver == maj && aq->api_min_ver >= min)); -} - /** * i40e_aq_add_vsi * @hw: pointer to the hw struct @@ -1890,14 +1875,14 @@ int i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw, if (set) { flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST; - if (rx_only_promisc && i40e_is_aq_api_ver_ge(&hw->aq, 1, 5)) + if (rx_only_promisc && i40e_is_aq_api_ver_ge(hw, 1, 5)) flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY; } cmd->promiscuous_flags = cpu_to_le16(flags); cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST); - if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5)) + if (i40e_is_aq_api_ver_ge(hw, 1, 5)) cmd->valid_flags |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY); @@ -2000,13 +1985,13 @@ int i40e_aq_set_vsi_uc_promisc_on_vlan(struct i40e_hw *hw, if (enable) { flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST; - if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5)) + if (i40e_is_aq_api_ver_ge(hw, 1, 5)) flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY; } cmd->promiscuous_flags = cpu_to_le16(flags); cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST); - if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5)) + if (i40e_is_aq_api_ver_ge(hw, 1, 5)) cmd->valid_flags |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY); cmd->seid = cpu_to_le16(seid); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 346a74a516a8..8b1efb6b91c5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -594,6 +594,20 @@ static inline bool i40e_is_vf(struct i40e_hw *hw) hw->mac.type == I40E_MAC_X722_VF); } +/** + * i40e_is_aq_api_ver_ge + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current HW API version is greater/equal than provided. + **/ +static inline bool i40e_is_aq_api_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.api_maj_ver > maj || + (hw->aq.api_maj_ver == maj && hw->aq.api_min_ver >= min)); +} + struct i40e_driver_version { u8 major_version; u8 minor_version; From cf488e13221f94536db3156b35cfe6424cc6df2a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:30 -0800 Subject: [PATCH 0576/7721] i40e: Add other helpers to check version of running firmware and AQ API Add another helper functions that will be used by subsequent patch to refactor existing open-coded checks whether the version of running firmware and AdminQ API is recent enough to provide certain capabilities. Signed-off-by: Ivan Vecera Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-12-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_type.h | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 8b1efb6b91c5..9752d145939c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -608,6 +608,60 @@ static inline bool i40e_is_aq_api_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) (hw->aq.api_maj_ver == maj && hw->aq.api_min_ver >= min)); } +/** + * i40e_is_aq_api_ver_lt + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current HW API version is less than provided. + **/ +static inline bool i40e_is_aq_api_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) +{ + return !i40e_is_aq_api_ver_ge(hw, maj, min); +} + +/** + * i40e_is_fw_ver_ge + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is greater/equal than provided. + **/ +static inline bool i40e_is_fw_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.fw_maj_ver > maj || + (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver >= min)); +} + +/** + * i40e_is_fw_ver_lt + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is less than provided. + **/ +static inline bool i40e_is_fw_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) +{ + return !i40e_is_fw_ver_ge(hw, maj, min); +} + +/** + * i40e_is_fw_ver_eq + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is equal to provided. + **/ +static inline bool i40e_is_fw_ver_eq(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.fw_maj_ver > maj || + (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min)); +} + struct i40e_driver_version { u8 major_version; u8 minor_version; From e329a8b9aac4b815f3c9bbecca01962f261688ca Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:31 -0800 Subject: [PATCH 0577/7721] i40e: Use helpers to check running FW and AQ API versions Use new helpers to check versions of running FW and provided AQ API to make the code more readable. Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-13-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 56 +++++++------------ drivers/net/ethernet/intel/i40e/i40e_common.c | 25 ++++----- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 7 +-- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +- 4 files changed, 36 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 86591140f748..29fc46abf690 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -508,42 +508,35 @@ static int i40e_shutdown_arq(struct i40e_hw *hw) **/ static void i40e_set_hw_caps(struct i40e_hw *hw) { - struct i40e_adminq_info *aq = &hw->aq; - bitmap_zero(hw->caps, I40E_HW_CAPS_NBITS); switch (hw->mac.type) { case I40E_MAC_XL710: - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)) { + if (i40e_is_aq_api_ver_ge(hw, 1, + I40E_MINOR_VER_GET_LINK_INFO_XL710)) { set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); /* The ability to RX (not drop) 802.1ad frames */ set_bit(I40E_HW_CAP_802_1AD, hw->caps); } - if ((aq->api_maj_ver == 1 && aq->api_min_ver > 4) || - aq->api_maj_ver > 1) { + if (i40e_is_aq_api_ver_ge(hw, 1, 5)) { /* Supported in FW API version higher than 1.4 */ set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, hw->caps); } - if ((aq->fw_maj_ver == 4 && aq->fw_min_ver < 33) || - aq->fw_maj_ver < 4) { + if (i40e_is_fw_ver_lt(hw, 4, 33)) { set_bit(I40E_HW_CAP_RESTART_AUTONEG, hw->caps); /* No DCB support for FW < v4.33 */ set_bit(I40E_HW_CAP_NO_DCB_SUPPORT, hw->caps); } - if ((aq->fw_maj_ver == 4 && aq->fw_min_ver < 3) || - aq->fw_maj_ver < 4) { + if (i40e_is_fw_ver_lt(hw, 4, 3)) { /* Disable FW LLDP if FW < v4.3 */ set_bit(I40E_HW_CAP_STOP_FW_LLDP, hw->caps); } - if ((aq->fw_maj_ver == 4 && aq->fw_min_ver >= 40) || - aq->fw_maj_ver >= 5) { - /* Use the FW Set LLDP MIB API if FW > v4.40 */ + if (i40e_is_fw_ver_ge(hw, 4, 40)) { + /* Use the FW Set LLDP MIB API if FW >= v4.40 */ set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, hw->caps); } - if (aq->fw_maj_ver >= 6) { + if (i40e_is_fw_ver_ge(hw, 6, 0)) { /* Enable PTP L4 if FW > v6.0 */ set_bit(I40E_HW_CAP_PTP_L4, hw->caps); } @@ -569,19 +562,16 @@ static void i40e_set_hw_caps(struct i40e_hw *hw) clear_bit(I40E_HW_CAP_ATR_EVICT, hw->caps); } - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722)) + if (i40e_is_aq_api_ver_ge(hw, 1, + I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722)) set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps); - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_X722)) + if (i40e_is_aq_api_ver_ge(hw, 1, + I40E_MINOR_VER_GET_LINK_INFO_X722)) set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps); - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= I40E_MINOR_VER_FW_REQUEST_FEC_X722)) + if (i40e_is_aq_api_ver_ge(hw, 1, + I40E_MINOR_VER_FW_REQUEST_FEC_X722)) set_bit(I40E_HW_CAP_X722_FEC_REQUEST, hw->caps); fallthrough; @@ -590,25 +580,17 @@ static void i40e_set_hw_caps(struct i40e_hw *hw) } /* Newer versions of firmware require lock when reading the NVM */ - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= 5)) + if (i40e_is_aq_api_ver_ge(hw, 1, 5)) set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps); /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */ - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= 7)) + if (i40e_is_aq_api_ver_ge(hw, 1, 7)) set_bit(I40E_HW_CAP_802_1AD, hw->caps); - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= 8)) + if (i40e_is_aq_api_ver_ge(hw, 1, 8)) set_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps); - if (aq->api_maj_ver > 1 || - (aq->api_maj_ver == 1 && - aq->api_min_ver >= 9)) + if (i40e_is_aq_api_ver_ge(hw, 1, 9)) set_bit(I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, hw->caps); } @@ -694,7 +676,7 @@ int i40e_init_adminq(struct i40e_hw *hw) &oem_lo); hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo; - if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) { + if (i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR + 1, 0)) { ret_code = -EIO; goto init_adminq_free_arq; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index df7ba349030d..e171f4814e21 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1374,8 +1374,8 @@ i40e_aq_get_phy_capabilities(struct i40e_hw *hw, if (report_init) { if (hw->mac.type == I40E_MAC_XL710 && - hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && - hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) { + i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR, + I40E_MINOR_VER_GET_LINK_INFO_XL710)) { status = i40e_aq_get_link_info(hw, true, NULL, NULL); } else { hw->phy.phy_types = le32_to_cpu(abilities->phy_type); @@ -1645,9 +1645,8 @@ int i40e_aq_get_link_info(struct i40e_hw *hw, else hw_link_info->lse_enable = false; - if ((hw->mac.type == I40E_MAC_XL710) && - (hw->aq.fw_maj_ver < 4 || (hw->aq.fw_maj_ver == 4 && - hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE) + if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_lt(hw, 4, 40) && + hw_link_info->phy_type == 0xE) hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU; if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps) && @@ -5223,14 +5222,14 @@ int i40e_aq_rx_ctl_read_register(struct i40e_hw *hw, **/ u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr) { - bool use_register; + bool use_register = false; int status = 0; int retry = 5; u32 val = 0; - use_register = (((hw->aq.api_maj_ver == 1) && - (hw->aq.api_min_ver < 5)) || - (hw->mac.type == I40E_MAC_X722)); + if (i40e_is_aq_api_ver_lt(hw, 1, 5) || hw->mac.type == I40E_MAC_X722) + use_register = true; + if (!use_register) { do_retry: status = i40e_aq_rx_ctl_read_register(hw, reg_addr, &val, NULL); @@ -5285,13 +5284,13 @@ int i40e_aq_rx_ctl_write_register(struct i40e_hw *hw, **/ void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val) { - bool use_register; + bool use_register = false; int status = 0; int retry = 5; - use_register = (((hw->aq.api_maj_ver == 1) && - (hw->aq.api_min_ver < 5)) || - (hw->mac.type == I40E_MAC_X722)); + if (i40e_is_aq_api_ver_lt(hw, 1, 5) || hw->mac.type == I40E_MAC_X722) + use_register = true; + if (!use_register) { do_retry: status = i40e_aq_rx_ctl_write_register(hw, reg_addr, diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 39e44a2e0677..498728e16a37 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -804,14 +804,11 @@ int i40e_get_dcb_config(struct i40e_hw *hw) int ret = 0; /* If Firmware version < v4.33 on X710/XL710, IEEE only */ - if ((hw->mac.type == I40E_MAC_XL710) && - (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || - (hw->aq.fw_maj_ver < 4))) + if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_lt(hw, 4, 33)) return i40e_get_ieee_dcb_config(hw); /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */ - if ((hw->mac.type == I40E_MAC_XL710) && - ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) { + if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_eq(hw, 4, 33)) { ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg, sizeof(cee_v1_cfg), NULL); if (!ret) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 8948bdc8bda1..7ded598a68e6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -15819,15 +15819,15 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->vendor_id, hw->device_id, hw->subsystem_vendor_id, hw->subsystem_device_id); - if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && - hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) + if (i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR, + I40E_FW_MINOR_VERSION(hw) + 1)) dev_dbg(&pdev->dev, "The driver for the device detected a newer version of the NVM image v%u.%u than v%u.%u.\n", hw->aq.api_maj_ver, hw->aq.api_min_ver, I40E_FW_API_VERSION_MAJOR, I40E_FW_MINOR_VERSION(hw)); - else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) + else if (i40e_is_aq_api_ver_lt(hw, 1, 4)) dev_info(&pdev->dev, "The driver for the device detected an older version of the NVM image v%u.%u than expected v%u.%u. Please update the NVM image.\n", hw->aq.api_maj_ver, From d8c6bee01caa5d16aee2be7f8feff875bb8f4fcc Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:32 -0800 Subject: [PATCH 0578/7721] i40e: Remove VF MAC types The i40e_hw.mac.type cannot to be equal to I40E_MAC_VF or I40E_MAC_X722_VF so remove helper i40e_is_vf(), simplify i40e_adminq_init_regs() and remove enums for these VF MAC types. Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-14-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 33 ++++++------------- drivers/net/ethernet/intel/i40e/i40e_type.h | 8 ----- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 29fc46abf690..896c43905309 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -17,29 +17,16 @@ static void i40e_resume_aq(struct i40e_hw *hw); static void i40e_adminq_init_regs(struct i40e_hw *hw) { /* set head and tail registers in our local struct */ - if (i40e_is_vf(hw)) { - hw->aq.asq.tail = I40E_VF_ATQT1; - hw->aq.asq.head = I40E_VF_ATQH1; - hw->aq.asq.len = I40E_VF_ATQLEN1; - hw->aq.asq.bal = I40E_VF_ATQBAL1; - hw->aq.asq.bah = I40E_VF_ATQBAH1; - hw->aq.arq.tail = I40E_VF_ARQT1; - hw->aq.arq.head = I40E_VF_ARQH1; - hw->aq.arq.len = I40E_VF_ARQLEN1; - hw->aq.arq.bal = I40E_VF_ARQBAL1; - hw->aq.arq.bah = I40E_VF_ARQBAH1; - } else { - hw->aq.asq.tail = I40E_PF_ATQT; - hw->aq.asq.head = I40E_PF_ATQH; - hw->aq.asq.len = I40E_PF_ATQLEN; - hw->aq.asq.bal = I40E_PF_ATQBAL; - hw->aq.asq.bah = I40E_PF_ATQBAH; - hw->aq.arq.tail = I40E_PF_ARQT; - hw->aq.arq.head = I40E_PF_ARQH; - hw->aq.arq.len = I40E_PF_ARQLEN; - hw->aq.arq.bal = I40E_PF_ARQBAL; - hw->aq.arq.bah = I40E_PF_ARQBAH; - } + hw->aq.asq.tail = I40E_PF_ATQT; + hw->aq.asq.head = I40E_PF_ATQH; + hw->aq.asq.len = I40E_PF_ATQLEN; + hw->aq.asq.bal = I40E_PF_ATQBAL; + hw->aq.asq.bah = I40E_PF_ATQBAH; + hw->aq.arq.tail = I40E_PF_ARQT; + hw->aq.arq.head = I40E_PF_ARQH; + hw->aq.arq.len = I40E_PF_ARQLEN; + hw->aq.arq.bal = I40E_PF_ARQBAL; + hw->aq.arq.bah = I40E_PF_ARQBAH; } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 9752d145939c..e21a8e06f6b2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -64,9 +64,7 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); enum i40e_mac_type { I40E_MAC_UNKNOWN = 0, I40E_MAC_XL710, - I40E_MAC_VF, I40E_MAC_X722, - I40E_MAC_X722_VF, I40E_MAC_GENERIC, }; @@ -588,12 +586,6 @@ struct i40e_hw { char err_str[16]; }; -static inline bool i40e_is_vf(struct i40e_hw *hw) -{ - return (hw->mac.type == I40E_MAC_VF || - hw->mac.type == I40E_MAC_X722_VF); -} - /** * i40e_is_aq_api_ver_ge * @hw: pointer to i40e_hw structure From f699a4bfc8624bf87aa2ba9327a0eef03edce43b Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:33 -0800 Subject: [PATCH 0579/7721] i40e: Move inline helpers to i40e_prototype.h Move version check helper functions from i40e_type.h to i40e_prototype.h as per discussion [1]. [1] https://lore.kernel.org/all/cdcd6b97-1138-4cd7-854f-b3faa1f475f8@intel.com/#t Cc: Jacob Keller Signed-off-by: Ivan Vecera Reviewed-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-15-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/intel/i40e/i40e_prototype.h | 70 +++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 68 ------------------ 2 files changed, 70 insertions(+), 68 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 001162042050..af4269330581 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -501,4 +501,74 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw, /* i40e_ddp */ int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash); +/* Firmware and AdminQ version check helpers */ + +/** + * i40e_is_aq_api_ver_ge + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current HW API version is greater/equal than provided. + **/ +static inline bool i40e_is_aq_api_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.api_maj_ver > maj || + (hw->aq.api_maj_ver == maj && hw->aq.api_min_ver >= min)); +} + +/** + * i40e_is_aq_api_ver_lt + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current HW API version is less than provided. + **/ +static inline bool i40e_is_aq_api_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) +{ + return !i40e_is_aq_api_ver_ge(hw, maj, min); +} + +/** + * i40e_is_fw_ver_ge + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is greater/equal than provided. + **/ +static inline bool i40e_is_fw_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.fw_maj_ver > maj || + (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver >= min)); +} + +/** + * i40e_is_fw_ver_lt + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is less than provided. + **/ +static inline bool i40e_is_fw_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) +{ + return !i40e_is_fw_ver_ge(hw, maj, min); +} + +/** + * i40e_is_fw_ver_eq + * @hw: pointer to i40e_hw structure + * @maj: API major value to compare + * @min: API minor value to compare + * + * Assert whether current firmware version is equal to provided. + **/ +static inline bool i40e_is_fw_ver_eq(struct i40e_hw *hw, u16 maj, u16 min) +{ + return (hw->aq.fw_maj_ver > maj || + (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min)); +} + #endif /* _I40E_PROTOTYPE_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index e21a8e06f6b2..e3f73be5eb09 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -586,74 +586,6 @@ struct i40e_hw { char err_str[16]; }; -/** - * i40e_is_aq_api_ver_ge - * @hw: pointer to i40e_hw structure - * @maj: API major value to compare - * @min: API minor value to compare - * - * Assert whether current HW API version is greater/equal than provided. - **/ -static inline bool i40e_is_aq_api_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) -{ - return (hw->aq.api_maj_ver > maj || - (hw->aq.api_maj_ver == maj && hw->aq.api_min_ver >= min)); -} - -/** - * i40e_is_aq_api_ver_lt - * @hw: pointer to i40e_hw structure - * @maj: API major value to compare - * @min: API minor value to compare - * - * Assert whether current HW API version is less than provided. - **/ -static inline bool i40e_is_aq_api_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) -{ - return !i40e_is_aq_api_ver_ge(hw, maj, min); -} - -/** - * i40e_is_fw_ver_ge - * @hw: pointer to i40e_hw structure - * @maj: API major value to compare - * @min: API minor value to compare - * - * Assert whether current firmware version is greater/equal than provided. - **/ -static inline bool i40e_is_fw_ver_ge(struct i40e_hw *hw, u16 maj, u16 min) -{ - return (hw->aq.fw_maj_ver > maj || - (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver >= min)); -} - -/** - * i40e_is_fw_ver_lt - * @hw: pointer to i40e_hw structure - * @maj: API major value to compare - * @min: API minor value to compare - * - * Assert whether current firmware version is less than provided. - **/ -static inline bool i40e_is_fw_ver_lt(struct i40e_hw *hw, u16 maj, u16 min) -{ - return !i40e_is_fw_ver_ge(hw, maj, min); -} - -/** - * i40e_is_fw_ver_eq - * @hw: pointer to i40e_hw structure - * @maj: API major value to compare - * @min: API minor value to compare - * - * Assert whether current firmware version is equal to provided. - **/ -static inline bool i40e_is_fw_ver_eq(struct i40e_hw *hw, u16 maj, u16 min) -{ - return (hw->aq.fw_maj_ver > maj || - (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min)); -} - struct i40e_driver_version { u8 major_version; u8 minor_version; From 3f06462b3eb8a49c07d9c0bc5631dd423ea5ebac Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 13 Nov 2023 15:10:34 -0800 Subject: [PATCH 0580/7721] i40e: Delete unused i40e_mac_info fields From commit 9eed69a9147c ("i40e: Drop FCoE code from core driver files") the field i40e_mac_info.san_addr is unused (never filled). The field i40e_mac_info.max_fcoeq is unused from the beginning. Remove both. Reviewed-by: Wojciech Drewek Co-developed-by: Michal Schmidt Signed-off-by: Michal Schmidt Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20231113231047.548659-16-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 5 +---- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 3 +-- drivers/net/ethernet/intel/i40e/i40e_type.h | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index 1ee77a2433c0..4721845fda6e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -827,15 +827,12 @@ static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev, u8 *perm_addr) { struct i40e_pf *pf = i40e_netdev_to_pf(dev); - int i, j; + int i; memset(perm_addr, 0xff, MAX_ADDR_LEN); for (i = 0; i < dev->addr_len; i++) perm_addr[i] = pf->hw.mac.perm_addr[i]; - - for (j = 0; j < dev->addr_len; j++, i++) - perm_addr[i] = pf->hw.mac.san_addr[j]; } static const struct dcbnl_rtnl_ops dcbnl_ops = { diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index e0849f0c9c27..88240571721a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -147,9 +147,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid) " state[%d] = %08lx\n", i, vsi->state[i]); if (vsi == pf->vsi[pf->lan_vsi]) - dev_info(&pf->pdev->dev, " MAC address: %pM SAN MAC: %pM Port MAC: %pM\n", + dev_info(&pf->pdev->dev, " MAC address: %pM Port MAC: %pM\n", pf->hw.mac.addr, - pf->hw.mac.san_addr, pf->hw.mac.port_addr); hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { dev_info(&pf->pdev->dev, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index e3f73be5eb09..de69c2e22448 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -270,9 +270,7 @@ struct i40e_mac_info { enum i40e_mac_type type; u8 addr[ETH_ALEN]; u8 perm_addr[ETH_ALEN]; - u8 san_addr[ETH_ALEN]; u8 port_addr[ETH_ALEN]; - u16 max_fcoeq; }; enum i40e_aq_resources_ids { From 8a4353d077788b4efb11beb8c4e3869ea7aeaff7 Mon Sep 17 00:00:00 2001 From: Vinod Govindapillai Date: Sat, 11 Nov 2023 13:43:20 +0200 Subject: [PATCH 0581/7721] drm/i915/xe2lpd: implement WA for underruns while enabling FBC FIFO underruns are observed when FBC is enabled on plane 2 or plane 3. Recommended WA is to update the FBC enabling sequence. The plane binding register bits need to be updated separately before programming the FBC enable bit. Bspec: 74151 Reviewed-by: Mika Kahola #v3 Signed-off-by: Vinod Govindapillai Reviewed-by: Mika Kahola Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231111114320.87277-2-vinod.govindapillai@intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index bde12fe62275..b73cf1c5ba33 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -608,6 +608,7 @@ static u32 ivb_dpfc_ctl(struct intel_fbc *fbc) static void ivb_fbc_activate(struct intel_fbc *fbc) { struct drm_i915_private *i915 = fbc->i915; + u32 dpfc_ctl; if (DISPLAY_VER(i915) >= 10) glk_fbc_program_cfb_stride(fbc); @@ -617,8 +618,13 @@ static void ivb_fbc_activate(struct intel_fbc *fbc) if (intel_gt_support_legacy_fencing(to_gt(i915))) snb_fbc_program_fence(fbc); + /* wa_14019417088 Alternative WA*/ + dpfc_ctl = ivb_dpfc_ctl(fbc); + if (DISPLAY_VER(i915) >= 20) + intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl); + intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), - DPFC_CTL_EN | ivb_dpfc_ctl(fbc)); + DPFC_CTL_EN | dpfc_ctl); } static bool ivb_fbc_is_compressing(struct intel_fbc *fbc) From 34eec1f29a5998305578fcc3e55d491a1795b56d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:09 -0800 Subject: [PATCH 0582/7721] bnxt_en: Put the TX producer information in the TX BD opaque field Currently, the opaque field in the TX BD is only used for debugging. The TX completion logic relies on getting one TX completion for each packet and they always complete in order. Improve this scheme by putting the producer information (ring index plus number of BDs for the packet) in the opaque field. This way, we can handle TX completion processing by looking at the last TX completion instead of counting the number of completions. Since we no longer need to count the exact number of completions, we can optimize xmit_more by disabling TX completion when the xmit_more condition is true. This will be done in later patches. This patch is only initializing the opaque field in the TX BD and is not changing the driver's TX completion logic yet. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 7 +++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d0359b569afe..669ea945d3cd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -432,8 +432,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; - txbd->tx_bd_opaque = prod; - tx_buf = &txr->tx_buf_ring[prod]; tx_buf->skb = skb; tx_buf->nr_frags = last_frag; @@ -519,7 +517,9 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type; txbd->tx_bd_haddr = txr->data_mapping; + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 2); prod = NEXT_TX(prod); + tx_push->tx_bd_opaque = txbd->tx_bd_opaque; txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; memcpy(txbd, tx_push1, sizeof(*txbd)); prod = NEXT_TX(prod); @@ -562,6 +562,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) ((last_frag + 2) << TX_BD_FLAGS_BD_CNT_SHIFT); txbd->tx_bd_haddr = cpu_to_le64(mapping); + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 2 + last_frag); prod = NEXT_TX(prod); txbd1 = (struct tx_bd_ext *) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index e702dbc3e6b1..c7895e7d78d5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -61,6 +61,13 @@ struct tx_bd { __le64 tx_bd_haddr; } __packed; +#define TX_OPAQUE_IDX_MASK 0x0000ffff +#define TX_OPAQUE_BDS_MASK 0x00ff0000 +#define TX_OPAQUE_BDS_SHIFT 16 + +#define SET_TX_OPAQUE(bp, idx, bds) \ + (((bds) << TX_OPAQUE_BDS_SHIFT) | ((idx) & (bp)->tx_ring_mask)) + struct tx_bd_ext { __le32 tx_bd_hsize_lflags; #define TX_BD_FLAGS_TCP_UDP_CHKSUM (1 << 0) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 96f5ca778c67..3e5144aafb0c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -52,7 +52,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) | bnxt_lhint_arr[len >> 9]; txbd->tx_bd_len_flags_type = cpu_to_le32(flags); - txbd->tx_bd_opaque = prod; + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 1 + num_frags); txbd->tx_bd_haddr = cpu_to_le64(mapping); /* now let us fill up the frags into the next buffers */ From 7f0a168b0441ef7fd6b46563efb2706c58ac2a4c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:10 -0800 Subject: [PATCH 0583/7721] bnxt_en: Add completion ring pointer in TX and RX ring structures From the TX or RX ring structure, we need to find the corresponding completion ring during initialization. On P5 chips, we use the MSIX/napi entry to locate the completion ring because there is only one RX/TX ring per MSIX. To allow multiple TX rings for each MSIX, we need to add a direct pointer from the TX ring and RX ring structures. This also simplifies the existing logic. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 43 +++++++++++-------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 11 ++++- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 12 +++--- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 669ea945d3cd..4dfe0b66c5f7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -331,16 +331,16 @@ static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) } void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr, - int idx) + u16 curr) { struct bnxt_napi *bnapi = txr->bnapi; if (bnapi->tx_fault) return; - netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_pkts:%d cons:%u prod:%u i:%d)", - txr->txq_index, bnapi->tx_pkts, - txr->tx_cons, txr->tx_prod, idx); + netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_hw_cons:%u cons:%u prod:%u curr:%u)", + txr->txq_index, txr->tx_hw_cons, + txr->tx_cons, txr->tx_prod, curr); WARN_ON_ONCE(1); bnapi->tx_fault = 1; bnxt_queue_sp_work(bp, BNXT_RESET_TASK_SP_EVENT); @@ -691,13 +691,13 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txr->txq_index); + u16 hw_cons = txr->tx_hw_cons; u16 cons = txr->tx_cons; struct pci_dev *pdev = bp->pdev; - int nr_pkts = bnapi->tx_pkts; - int i; unsigned int tx_bytes = 0; + int tx_pkts = 0; - for (i = 0; i < nr_pkts; i++) { + while (cons != hw_cons) { struct bnxt_sw_tx_bd *tx_buf; struct sk_buff *skb; int j, last; @@ -708,10 +708,11 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) tx_buf->skb = NULL; if (unlikely(!skb)) { - bnxt_sched_reset_txr(bp, txr, i); + bnxt_sched_reset_txr(bp, txr, cons); return; } + tx_pkts++; tx_bytes += skb->len; if (tx_buf->is_push) { @@ -748,10 +749,10 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) dev_consume_skb_any(skb); } - bnapi->tx_pkts = 0; + bnapi->events &= ~BNXT_TX_CMP_EVENT; WRITE_ONCE(txr->tx_cons, cons); - __netif_txq_completed_wake(txq, nr_pkts, tx_bytes, + __netif_txq_completed_wake(txq, tx_pkts, tx_bytes, bnxt_tx_avail(bp, txr), bp->tx_wake_thresh, READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING); } @@ -2588,14 +2589,15 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, { struct bnxt_napi *bnapi = cpr->bnapi; u32 raw_cons = cpr->cp_raw_cons; + struct bnxt_tx_ring_info *txr; u32 cons; - int tx_pkts = 0; int rx_pkts = 0; u8 event = 0; struct tx_cmp *txcmp; cpr->has_more_work = 0; cpr->had_work_done = 1; + txr = bnapi->tx_ring; while (1) { int rc; @@ -2610,9 +2612,15 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, */ dma_rmb(); if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) { - tx_pkts++; + u32 opaque = txcmp->tx_cmp_opaque; + u16 tx_freed; + + event |= BNXT_TX_CMP_EVENT; + txr->tx_hw_cons = TX_OPAQUE_PROD(bp, opaque); + tx_freed = (txr->tx_hw_cons - txr->tx_cons) & + bp->tx_ring_mask; /* return full budget so NAPI will complete. */ - if (unlikely(tx_pkts >= bp->tx_wake_thresh)) { + if (unlikely(tx_freed >= bp->tx_wake_thresh)) { rx_pkts = budget; raw_cons = NEXT_RAW_CMP(raw_cons); if (budget) @@ -2666,7 +2674,6 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } cpr->cp_raw_cons = raw_cons; - bnapi->tx_pkts += tx_pkts; bnapi->events |= event; return rx_pkts; } @@ -2674,7 +2681,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { - if (bnapi->tx_pkts && !bnapi->tx_fault) + if ((bnapi->events & BNXT_TX_CMP_EVENT) && !bnapi->tx_fault) bnapi->tx_int(bp, bnapi, budget); if ((bnapi->events & BNXT_RX_EVENT) && !(bnapi->in_reset)) { @@ -2687,7 +2694,7 @@ static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi, bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); } - bnapi->events = 0; + bnapi->events &= BNXT_TX_CMP_EVENT; } static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, @@ -4515,6 +4522,7 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) if (txr) { txr->tx_prod = 0; txr->tx_cons = 0; + txr->tx_hw_cons = 0; } rxr = bnapi->rx_ring; @@ -4524,6 +4532,7 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) rxr->rx_sw_agg_prod = 0; rxr->rx_next_cons = 0; } + bnapi->events = 0; } } @@ -9528,8 +9537,6 @@ static void bnxt_enable_napi(struct bnxt *bp) cpr = &bnapi->cp_ring; bnapi->in_reset = false; - bnapi->tx_pkts = 0; - if (bnapi->rx_ring) { INIT_WORK(&cpr->dim.work, bnxt_dim_work); cpr->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c7895e7d78d5..cf22aae91f70 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -68,6 +68,12 @@ struct tx_bd { #define SET_TX_OPAQUE(bp, idx, bds) \ (((bds) << TX_OPAQUE_BDS_SHIFT) | ((idx) & (bp)->tx_ring_mask)) +#define TX_OPAQUE_IDX(opq) ((opq) & TX_OPAQUE_IDX_MASK) +#define TX_OPAQUE_BDS(opq) (((opq) & TX_OPAQUE_BDS_MASK) >> \ + TX_OPAQUE_BDS_SHIFT) +#define TX_OPAQUE_PROD(bp, opq) ((TX_OPAQUE_IDX(opq) + TX_OPAQUE_BDS(opq)) &\ + (bp)->tx_ring_mask) + struct tx_bd_ext { __le32 tx_bd_hsize_lflags; #define TX_BD_FLAGS_TCP_UDP_CHKSUM (1 << 0) @@ -709,6 +715,7 @@ struct nqe_cn { #define BNXT_AGG_EVENT 2 #define BNXT_TX_EVENT 4 #define BNXT_REDIRECT_EVENT 8 +#define BNXT_TX_CMP_EVENT 0x10 struct bnxt_sw_tx_bd { union { @@ -801,6 +808,7 @@ struct bnxt_tx_ring_info { struct bnxt_napi *bnapi; u16 tx_prod; u16 tx_cons; + u16 tx_hw_cons; u16 txq_index; u8 kick_pending; struct bnxt_db_info tx_db; @@ -1027,7 +1035,6 @@ struct bnxt_napi { void (*tx_int)(struct bnxt *, struct bnxt_napi *, int budget); - int tx_pkts; u8 events; u8 tx_fault:1; @@ -2367,7 +2374,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init); void bnxt_tx_disable(struct bnxt *bp); void bnxt_tx_enable(struct bnxt *bp); void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr, - int idx); + u16 curr); void bnxt_report_link(struct bnxt *bp); int bnxt_update_link(struct bnxt *bp, bool chng_link_state); int bnxt_hwrm_set_pause(struct bnxt *); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 3e5144aafb0c..23476100fad2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -129,17 +129,17 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; + u16 tx_hw_cons = txr->tx_hw_cons; bool rx_doorbell_needed = false; - int nr_pkts = bnapi->tx_pkts; struct bnxt_sw_tx_bd *tx_buf; u16 tx_cons = txr->tx_cons; u16 last_tx_cons = tx_cons; - int i, j, frags; + int j, frags; if (!budget) return; - for (i = 0; i < nr_pkts; i++) { + while (tx_cons != tx_hw_cons) { tx_buf = &txr->tx_buf_ring[tx_cons]; if (tx_buf->action == XDP_REDIRECT) { @@ -164,13 +164,13 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) page_pool_recycle_direct(rxr->page_pool, tx_buf->page); } } else { - bnxt_sched_reset_txr(bp, txr, i); + bnxt_sched_reset_txr(bp, txr, tx_cons); return; } tx_cons = NEXT_TX(tx_cons); } - bnapi->tx_pkts = 0; + bnapi->events &= ~BNXT_TX_CMP_EVENT; WRITE_ONCE(txr->tx_cons, tx_cons); if (rx_doorbell_needed) { tx_buf = &txr->tx_buf_ring[last_tx_cons]; @@ -275,7 +275,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, case XDP_TX: rx_buf = &rxr->rx_buf_ring[cons]; mapping = rx_buf->mapping - bp->rx_dma_offset; - *event = 0; + *event &= BNXT_TX_CMP_EVENT; if (unlikely(xdp_buff_has_frags(&xdp))) { struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(&xdp); From d1eec614100c25b96b672b50d3125ba3d120b682 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:11 -0800 Subject: [PATCH 0584/7721] bnxt_en: Restructure cp_ring_arr in struct bnxt_cp_ring_info The cp_ring_arr is currently a fixed array of 2 pointers for the TX and RX completion rings. These pointers are allocated during ring initialization. Currntly, we support up to 2 completion rings for each MSIX. In order to support more completion rings, we change this fixed array to a pointer and allocate the required entries during ring initialization. This patch keeps the current scheme of allocating only 2 entries when needed. Later patches will expand and allocate more entries when required. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 132 ++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 +- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- 3 files changed, 65 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4dfe0b66c5f7..585120369935 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2834,14 +2834,11 @@ static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; int i, work_done = 0; - for (i = 0; i < 2; i++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i]; + for (i = 0; i < cpr->cp_ring_count; i++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[i]; - if (cpr2) { - work_done += __bnxt_poll_work(bp, cpr2, - budget - work_done); - cpr->has_more_work |= cpr2->has_more_work; - } + work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); + cpr->has_more_work |= cpr2->has_more_work; } return work_done; } @@ -2852,11 +2849,11 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; int i; - for (i = 0; i < 2; i++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i]; + for (i = 0; i < cpr->cp_ring_count; i++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[i]; struct bnxt_db_info *db; - if (cpr2 && cpr2->had_work_done) { + if (cpr2->had_work_done) { db = &cpr2->cp_db; bnxt_writeq(bp, db->db_key64 | dbr_type | RING_CMP(cpr2->cp_raw_cons), db->doorbell); @@ -2915,7 +2912,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) if (budget && work_done >= budget && idx == BNXT_RX_HDL) break; - cpr2 = cpr->cp_ring_arr[idx]; + cpr2 = &cpr->cp_ring_arr[idx]; work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); cpr->has_more_work |= cpr2->has_more_work; @@ -2930,8 +2927,8 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) BNXT_DB_NQ_P5(&cpr->cp_db, raw_cons); } poll_done: - cpr_rx = cpr->cp_ring_arr[BNXT_RX_HDL]; - if (cpr_rx && (bp->flags & BNXT_FLAG_DIM)) { + cpr_rx = &cpr->cp_ring_arr[BNXT_RX_HDL]; + if (cpr_rx->bnapi && (bp->flags & BNXT_FLAG_DIM)) { struct dim_sample dim_sample = {}; dim_update_sample(cpr->event_ctr, @@ -3541,36 +3538,33 @@ static void bnxt_free_cp_rings(struct bnxt *bp) bnxt_free_ring(bp, &ring->ring_mem); - for (j = 0; j < 2; j++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + if (!cpr->cp_ring_arr) + continue; - if (cpr2) { - ring = &cpr2->cp_ring_struct; - bnxt_free_ring(bp, &ring->ring_mem); - bnxt_free_cp_arrays(cpr2); - kfree(cpr2); - cpr->cp_ring_arr[j] = NULL; - } + for (j = 0; j < cpr->cp_ring_count; j++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j]; + + ring = &cpr2->cp_ring_struct; + bnxt_free_ring(bp, &ring->ring_mem); + bnxt_free_cp_arrays(cpr2); } + kfree(cpr->cp_ring_arr); + cpr->cp_ring_arr = NULL; + cpr->cp_ring_count = 0; } } -static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp) +static int bnxt_alloc_cp_sub_ring(struct bnxt *bp, + struct bnxt_cp_ring_info *cpr) { struct bnxt_ring_mem_info *rmem; struct bnxt_ring_struct *ring; - struct bnxt_cp_ring_info *cpr; int rc; - cpr = kzalloc(sizeof(*cpr), GFP_KERNEL); - if (!cpr) - return NULL; - rc = bnxt_alloc_cp_arrays(cpr, bp->cp_nr_pages); if (rc) { bnxt_free_cp_arrays(cpr); - kfree(cpr); - return NULL; + return -ENOMEM; } ring = &cpr->cp_ring_struct; rmem = &ring->ring_mem; @@ -3583,10 +3577,8 @@ static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp) if (rc) { bnxt_free_ring(bp, rmem); bnxt_free_cp_arrays(cpr); - kfree(cpr); - cpr = NULL; } - return cpr; + return rc; } static int bnxt_alloc_cp_rings(struct bnxt *bp) @@ -3598,7 +3590,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) ulp_base_vec = bnxt_get_ulp_msix_base(bp); for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; - struct bnxt_cp_ring_info *cpr; + struct bnxt_cp_ring_info *cpr, *cpr2; struct bnxt_ring_struct *ring; if (!bnapi) @@ -3620,23 +3612,27 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_CHIP_P5)) continue; - if (i < bp->rx_nr_rings) { - struct bnxt_cp_ring_info *cpr2 = - bnxt_alloc_cp_sub_ring(bp); + cpr->cp_ring_count = 2; + cpr->cp_ring_arr = kcalloc(cpr->cp_ring_count, sizeof(*cpr), + GFP_KERNEL); + if (!cpr->cp_ring_arr) { + cpr->cp_ring_count = 0; + return -ENOMEM; + } - cpr->cp_ring_arr[BNXT_RX_HDL] = cpr2; - if (!cpr2) - return -ENOMEM; + if (i < bp->rx_nr_rings) { + cpr2 = &cpr->cp_ring_arr[BNXT_RX_HDL]; + rc = bnxt_alloc_cp_sub_ring(bp, cpr2); + if (rc) + return rc; cpr2->bnapi = bnapi; } if ((sh && i < bp->tx_nr_rings) || (!sh && i >= bp->rx_nr_rings)) { - struct bnxt_cp_ring_info *cpr2 = - bnxt_alloc_cp_sub_ring(bp); - - cpr->cp_ring_arr[BNXT_TX_HDL] = cpr2; - if (!cpr2) - return -ENOMEM; + cpr2 = &cpr->cp_ring_arr[BNXT_TX_HDL]; + rc = bnxt_alloc_cp_sub_ring(bp, cpr2); + if (rc) + return rc; cpr2->bnapi = bnapi; } } @@ -3822,11 +3818,10 @@ static void bnxt_init_cp_rings(struct bnxt *bp) ring->fw_ring_id = INVALID_HW_RING_ID; cpr->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks; cpr->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs; - for (j = 0; j < 2; j++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; - - if (!cpr2) - continue; + if (!cpr->cp_ring_arr) + continue; + for (j = 0; j < cpr->cp_ring_count; j++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j]; ring = &cpr2->cp_ring_struct; ring->fw_ring_id = INVALID_HW_RING_ID; @@ -5251,7 +5246,7 @@ static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) struct bnxt_napi *bnapi = rxr->bnapi; struct bnxt_cp_ring_info *cpr; - cpr = bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL]; + cpr = &bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL]; return cpr->cp_ring_struct.fw_ring_id; } else { return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct); @@ -5264,7 +5259,7 @@ static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr) struct bnxt_napi *bnapi = txr->bnapi; struct bnxt_cp_ring_info *cpr; - cpr = bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL]; + cpr = &bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL]; return cpr->cp_ring_struct.fw_ring_id; } else { return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct); @@ -6032,7 +6027,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 type2 = HWRM_RING_ALLOC_CMPL; cpr = &bnapi->cp_ring; - cpr2 = cpr->cp_ring_arr[BNXT_TX_HDL]; + cpr2 = &cpr->cp_ring_arr[BNXT_TX_HDL]; ring = &cpr2->cp_ring_struct; ring->handle = BNXT_TX_HDL; map_idx = bnapi->index; @@ -6071,7 +6066,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 type2 = HWRM_RING_ALLOC_CMPL; struct bnxt_cp_ring_info *cpr2; - cpr2 = cpr->cp_ring_arr[BNXT_RX_HDL]; + cpr2 = &cpr->cp_ring_arr[BNXT_RX_HDL]; ring = &cpr2->cp_ring_struct; ring->handle = BNXT_RX_HDL; rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); @@ -6218,18 +6213,16 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) struct bnxt_ring_struct *ring; int j; - for (j = 0; j < 2; j++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + for (j = 0; j < cpr->cp_ring_count && cpr->cp_ring_arr; j++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j]; - if (cpr2) { - ring = &cpr2->cp_ring_struct; - if (ring->fw_ring_id == INVALID_HW_RING_ID) - continue; - hwrm_ring_free_send_msg(bp, ring, - RING_FREE_REQ_RING_TYPE_L2_CMPL, - INVALID_HW_RING_ID); - ring->fw_ring_id = INVALID_HW_RING_ID; - } + ring = &cpr2->cp_ring_struct; + if (ring->fw_ring_id == INVALID_HW_RING_ID) + continue; + hwrm_ring_free_send_msg(bp, ring, + RING_FREE_REQ_RING_TYPE_L2_CMPL, + INVALID_HW_RING_ID); + ring->fw_ring_id = INVALID_HW_RING_ID; } ring = &cpr->cp_ring_struct; if (ring->fw_ring_id != INVALID_HW_RING_ID) { @@ -12005,12 +11998,11 @@ static void bnxt_chk_missed_irq(struct bnxt *bp) continue; cpr = &bnapi->cp_ring; - for (j = 0; j < 2; j++) { - struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + for (j = 0; j < cpr->cp_ring_count; j++) { + struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j]; u32 val[2]; - if (!cpr2 || cpr2->has_more_work || - !bnxt_has_work(bp, cpr2)) + if (cpr2->has_more_work || !bnxt_has_work(bp, cpr2)) continue; if (cpr2->cp_raw_cons != cpr2->last_cp_raw_cons) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index cf22aae91f70..429df1cf4a6a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1019,7 +1019,8 @@ struct bnxt_cp_ring_info { struct bnxt_ring_struct cp_ring_struct; - struct bnxt_cp_ring_info *cp_ring_arr[2]; + int cp_ring_count; + struct bnxt_cp_ring_info *cp_ring_arr; #define BNXT_RX_HDL 0 #define BNXT_TX_HDL 1 }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index f3f384773ac0..675e37700289 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3941,7 +3941,7 @@ static int bnxt_run_loopback(struct bnxt *bp) cpr = &rxr->bnapi->cp_ring; if (bp->flags & BNXT_FLAG_CHIP_P5) - cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; + cpr = &cpr->cp_ring_arr[BNXT_RX_HDL]; pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) From 7845b8dfc7136752cdffe2acde43fa892ab4f0e0 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:12 -0800 Subject: [PATCH 0585/7721] bnxt_en: Add completion ring pointer in TX and RX ring structures From the TX or RX ring structure, we need to find the corresponding completion ring during initialization. On P5 chips, we use the MSIX/napi entry to locate the completion ring because there is only one RX/TX ring per MSIX. To allow multiple TX rings for each MSIX, we need to add a direct pointer from the TX ring and RX ring structures. This also simplifies the existing logic. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 40 ++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 585120369935..11a85cb28517 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3584,11 +3584,11 @@ static int bnxt_alloc_cp_sub_ring(struct bnxt *bp, static int bnxt_alloc_cp_rings(struct bnxt *bp) { bool sh = !!(bp->flags & BNXT_FLAG_SHARED_RINGS); - int i, rc, ulp_base_vec, ulp_msix; + int i, j, rc, ulp_base_vec, ulp_msix; ulp_msix = bnxt_get_ulp_msix_num(bp); ulp_base_vec = bnxt_get_ulp_msix_base(bp); - for (i = 0; i < bp->cp_nr_rings; i++) { + for (i = 0, j = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr, *cpr2; struct bnxt_ring_struct *ring; @@ -3626,6 +3626,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) if (rc) return rc; cpr2->bnapi = bnapi; + bp->rx_ring[i].rx_cpr = cpr2; } if ((sh && i < bp->tx_nr_rings) || (!sh && i >= bp->rx_nr_rings)) { @@ -3634,6 +3635,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) if (rc) return rc; cpr2->bnapi = bnapi; + bp->tx_ring[j++].tx_cpr = cpr2; } } return 0; @@ -4654,6 +4656,8 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) BNXT_RMEM_RING_PTE_FLAG; rxr->rx_agg_ring_struct.ring_mem.flags = BNXT_RMEM_RING_PTE_FLAG; + } else { + rxr->rx_cpr = &bp->bnapi[i]->cp_ring; } rxr->bnapi = bp->bnapi[i]; bp->bnapi[i]->rx_ring = &bp->rx_ring[i]; @@ -4682,6 +4686,8 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) if (bp->flags & BNXT_FLAG_CHIP_P5) txr->tx_ring_struct.ring_mem.flags = BNXT_RMEM_RING_PTE_FLAG; + else + txr->tx_cpr = &bp->bnapi[i]->cp_ring; txr->bnapi = bp->bnapi[j]; bp->bnapi[j]->tx_ring = txr; bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i; @@ -5242,28 +5248,18 @@ static u16 bnxt_cp_ring_from_grp(struct bnxt *bp, struct bnxt_ring_struct *ring) static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { - struct bnxt_napi *bnapi = rxr->bnapi; - struct bnxt_cp_ring_info *cpr; - - cpr = &bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL]; - return cpr->cp_ring_struct.fw_ring_id; - } else { + if (bp->flags & BNXT_FLAG_CHIP_P5) + return rxr->rx_cpr->cp_ring_struct.fw_ring_id; + else return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct); - } } static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { - struct bnxt_napi *bnapi = txr->bnapi; - struct bnxt_cp_ring_info *cpr; - - cpr = &bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL]; - return cpr->cp_ring_struct.fw_ring_id; - } else { + if (bp->flags & BNXT_FLAG_CHIP_P5) + return txr->tx_cpr->cp_ring_struct.fw_ring_id; + else return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct); - } } static int bnxt_alloc_rss_indir_tbl(struct bnxt *bp) @@ -6022,12 +6018,10 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 map_idx; if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_cp_ring_info *cpr2 = txr->tx_cpr; struct bnxt_napi *bnapi = txr->bnapi; - struct bnxt_cp_ring_info *cpr, *cpr2; u32 type2 = HWRM_RING_ALLOC_CMPL; - cpr = &bnapi->cp_ring; - cpr2 = &cpr->cp_ring_arr[BNXT_TX_HDL]; ring = &cpr2->cp_ring_struct; ring->handle = BNXT_TX_HDL; map_idx = bnapi->index; @@ -6062,11 +6056,9 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id; if (bp->flags & BNXT_FLAG_CHIP_P5) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_cp_ring_info *cpr2 = rxr->rx_cpr; u32 type2 = HWRM_RING_ALLOC_CMPL; - struct bnxt_cp_ring_info *cpr2; - cpr2 = &cpr->cp_ring_arr[BNXT_RX_HDL]; ring = &cpr2->cp_ring_struct; ring->handle = BNXT_RX_HDL; rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 429df1cf4a6a..c04089e7ac39 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -806,6 +806,7 @@ struct bnxt_db_info { struct bnxt_tx_ring_info { struct bnxt_napi *bnapi; + struct bnxt_cp_ring_info *tx_cpr; u16 tx_prod; u16 tx_cons; u16 tx_hw_cons; @@ -916,6 +917,7 @@ struct bnxt_tpa_idx_map { struct bnxt_rx_ring_info { struct bnxt_napi *bnapi; + struct bnxt_cp_ring_info *rx_cpr; u16 rx_prod; u16 rx_agg_prod; u16 rx_sw_agg_prod; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 675e37700289..18c06158fead 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3941,7 +3941,7 @@ static int bnxt_run_loopback(struct bnxt *bp) cpr = &rxr->bnapi->cp_ring; if (bp->flags & BNXT_FLAG_CHIP_P5) - cpr = &cpr->cp_ring_arr[BNXT_RX_HDL]; + cpr = rxr->rx_cpr; pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) From 9c0b06de6fb6f3b5871011aae19305b40084e037 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:13 -0800 Subject: [PATCH 0586/7721] bnxt_en: Remove BNXT_RX_HDL and BNXT_TX_HDL These 2 constants were used for the one RX and one TX completion ring pointer in the cpr->cp_ring_arr fixed array. Now that we've changed to allocating the array for the exact number of entries to support more TX rings, we no longer use these constants. The array index as well as the type of completion ring (RX/TX) are now encoded in the handle for the completion ring. This will allow us to locate the completion ring during NAPI for any number of completion rings sharing the same MSIX. In the following patches, we'll be adding support for more TX rings associated with the same MSIX vector. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 55 +++++++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 17 ++++++- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 11a85cb28517..a4f7fa17daf8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2906,12 +2906,15 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) { u32 idx = le32_to_cpu(nqcmp->cq_handle_low); + u32 cq_type = BNXT_NQ_HDL_TYPE(idx); struct bnxt_cp_ring_info *cpr2; /* No more budget for RX work */ - if (budget && work_done >= budget && idx == BNXT_RX_HDL) + if (budget && work_done >= budget && + cq_type == BNXT_NQ_HDL_TYPE_RX) break; + idx = BNXT_NQ_HDL_IDX(idx); cpr2 = &cpr->cp_ring_arr[idx]; work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); @@ -2927,8 +2930,9 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) BNXT_DB_NQ_P5(&cpr->cp_db, raw_cons); } poll_done: - cpr_rx = &cpr->cp_ring_arr[BNXT_RX_HDL]; - if (cpr_rx->bnapi && (bp->flags & BNXT_FLAG_DIM)) { + cpr_rx = &cpr->cp_ring_arr[0]; + if (cpr_rx->cp_ring_type == BNXT_NQ_HDL_TYPE_RX && + (bp->flags & BNXT_FLAG_DIM)) { struct dim_sample dim_sample = {}; dim_update_sample(cpr->event_ctr, @@ -3592,6 +3596,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr, *cpr2; struct bnxt_ring_struct *ring; + int cp_count = 0, k; if (!bnapi) continue; @@ -3612,30 +3617,32 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_CHIP_P5)) continue; - cpr->cp_ring_count = 2; - cpr->cp_ring_arr = kcalloc(cpr->cp_ring_count, sizeof(*cpr), - GFP_KERNEL); - if (!cpr->cp_ring_arr) { - cpr->cp_ring_count = 0; - return -ENOMEM; - } - - if (i < bp->rx_nr_rings) { - cpr2 = &cpr->cp_ring_arr[BNXT_RX_HDL]; - rc = bnxt_alloc_cp_sub_ring(bp, cpr2); - if (rc) - return rc; - cpr2->bnapi = bnapi; - bp->rx_ring[i].rx_cpr = cpr2; - } + if (i < bp->rx_nr_rings) + cp_count++; if ((sh && i < bp->tx_nr_rings) || - (!sh && i >= bp->rx_nr_rings)) { - cpr2 = &cpr->cp_ring_arr[BNXT_TX_HDL]; + (!sh && i >= bp->rx_nr_rings)) + cp_count++; + + cpr->cp_ring_arr = kcalloc(cp_count, sizeof(*cpr), + GFP_KERNEL); + if (!cpr->cp_ring_arr) + return -ENOMEM; + cpr->cp_ring_count = cp_count; + + for (k = 0; k < cp_count; k++) { + cpr2 = &cpr->cp_ring_arr[k]; rc = bnxt_alloc_cp_sub_ring(bp, cpr2); if (rc) return rc; cpr2->bnapi = bnapi; - bp->tx_ring[j++].tx_cpr = cpr2; + cpr2->cp_idx = k; + if (!k && i < bp->rx_nr_rings) { + bp->rx_ring[i].rx_cpr = cpr2; + cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_RX; + } else { + bp->tx_ring[j++].tx_cpr = cpr2; + cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_TX; + } } } return 0; @@ -6023,7 +6030,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 type2 = HWRM_RING_ALLOC_CMPL; ring = &cpr2->cp_ring_struct; - ring->handle = BNXT_TX_HDL; + ring->handle = BNXT_SET_NQ_HDL(cpr2); map_idx = bnapi->index; rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); if (rc) @@ -6060,7 +6067,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 type2 = HWRM_RING_ALLOC_CMPL; ring = &cpr2->cp_ring_struct; - ring->handle = BNXT_RX_HDL; + ring->handle = BNXT_SET_NQ_HDL(cpr2); rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); if (rc) goto err_out; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c04089e7ac39..efb0db54575b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -543,6 +543,19 @@ struct nqe_cn { __le32 cq_handle_high; }; +#define BNXT_NQ_HDL_IDX_MASK 0x00ffffff +#define BNXT_NQ_HDL_TYPE_MASK 0xff000000 +#define BNXT_NQ_HDL_TYPE_SHIFT 24 +#define BNXT_NQ_HDL_TYPE_RX 0x00 +#define BNXT_NQ_HDL_TYPE_TX 0x01 + +#define BNXT_NQ_HDL_IDX(hdl) ((hdl) & BNXT_NQ_HDL_IDX_MASK) +#define BNXT_NQ_HDL_TYPE(hdl) (((hdl) & BNXT_NQ_HDL_TYPE_MASK) >> \ + BNXT_NQ_HDL_TYPE_SHIFT) + +#define BNXT_SET_NQ_HDL(cpr) \ + (((cpr)->cp_ring_type << BNXT_NQ_HDL_TYPE_SHIFT) | (cpr)->cp_idx) + #define DB_IDX_MASK 0xffffff #define DB_IDX_VALID (0x1 << 26) #define DB_IRQ_DIS (0x1 << 27) @@ -997,6 +1010,8 @@ struct bnxt_cp_ring_info { u8 had_work_done:1; u8 has_more_work:1; + u8 cp_ring_type; + u8 cp_idx; u32 last_cp_raw_cons; @@ -1023,8 +1038,6 @@ struct bnxt_cp_ring_info { int cp_ring_count; struct bnxt_cp_ring_info *cp_ring_arr; -#define BNXT_RX_HDL 0 -#define BNXT_TX_HDL 1 }; struct bnxt_napi { From ebf72319cef6e1c038e13bd4c9e3f0ad857e57ff Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:14 -0800 Subject: [PATCH 0587/7721] bnxt_en: Refactor bnxt_tx_int() bnxt_tx_int() processes the only one TX ring from the bnxt_napi pointer. To prepare for more TX rings associated with the bnxt_napi structure, add a new __bnxt_tx_int() function that takes the bnxt_tx_ring_info pointer to process that one TX ring. No functional change. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a4f7fa17daf8..ad56ca9d3ceb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -687,14 +687,14 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) +static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + int budget) { - struct bnxt_tx_ring_info *txr = bnapi->tx_ring; struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txr->txq_index); - u16 hw_cons = txr->tx_hw_cons; - u16 cons = txr->tx_cons; struct pci_dev *pdev = bp->pdev; + u16 hw_cons = txr->tx_hw_cons; unsigned int tx_bytes = 0; + u16 cons = txr->tx_cons; int tx_pkts = 0; while (cons != hw_cons) { @@ -749,7 +749,6 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) dev_consume_skb_any(skb); } - bnapi->events &= ~BNXT_TX_CMP_EVENT; WRITE_ONCE(txr->tx_cons, cons); __netif_txq_completed_wake(txq, tx_pkts, tx_bytes, @@ -757,6 +756,14 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING); } +static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) +{ + struct bnxt_tx_ring_info *txr = bnapi->tx_ring; + + __bnxt_tx_int(bp, txr, budget); + bnapi->events &= ~BNXT_TX_CMP_EVENT; +} + static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, struct bnxt_rx_ring_info *rxr, unsigned int *offset, From 5a3c585fa83f9172848c19b1000c6ad3c8b36129 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:15 -0800 Subject: [PATCH 0588/7721] bnxt_en: New encoding for the TX opaque field In order to support multiple TX rings on the same MSIX, we'll use the upper byte of the TX opaque field to store the ring index in the new tx_napi_idx field. This tx_napi_idx field is currently always 0 until more infrastructure is added in later patches. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 10 ++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index ad56ca9d3ceb..1a7f14d086f7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -517,7 +517,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type; txbd->tx_bd_haddr = txr->data_mapping; - txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 2); + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2); prod = NEXT_TX(prod); tx_push->tx_bd_opaque = txbd->tx_bd_opaque; txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; @@ -562,7 +562,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) ((last_frag + 2) << TX_BD_FLAGS_BD_CNT_SHIFT); txbd->tx_bd_haddr = cpu_to_le64(mapping); - txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 2 + last_frag); + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2 + last_frag); prod = NEXT_TX(prod); txbd1 = (struct tx_bd_ext *) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index efb0db54575b..430538844178 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -64,11 +64,16 @@ struct tx_bd { #define TX_OPAQUE_IDX_MASK 0x0000ffff #define TX_OPAQUE_BDS_MASK 0x00ff0000 #define TX_OPAQUE_BDS_SHIFT 16 +#define TX_OPAQUE_RING_MASK 0xff000000 +#define TX_OPAQUE_RING_SHIFT 24 -#define SET_TX_OPAQUE(bp, idx, bds) \ - (((bds) << TX_OPAQUE_BDS_SHIFT) | ((idx) & (bp)->tx_ring_mask)) +#define SET_TX_OPAQUE(bp, txr, idx, bds) \ + (((txr)->tx_napi_idx << TX_OPAQUE_RING_SHIFT) | \ + ((bds) << TX_OPAQUE_BDS_SHIFT) | ((idx) & (bp)->tx_ring_mask)) #define TX_OPAQUE_IDX(opq) ((opq) & TX_OPAQUE_IDX_MASK) +#define TX_OPAQUE_RING(opq) (((opq) & TX_OPAQUE_RING_MASK) >> \ + TX_OPAQUE_RING_SHIFT) #define TX_OPAQUE_BDS(opq) (((opq) & TX_OPAQUE_BDS_MASK) >> \ TX_OPAQUE_BDS_SHIFT) #define TX_OPAQUE_PROD(bp, opq) ((TX_OPAQUE_IDX(opq) + TX_OPAQUE_BDS(opq)) &\ @@ -824,6 +829,7 @@ struct bnxt_tx_ring_info { u16 tx_cons; u16 tx_hw_cons; u16 txq_index; + u8 tx_napi_idx; u8 kick_pending; struct bnxt_db_info tx_db; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 23476100fad2..3515a12a6fea 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -52,7 +52,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) | bnxt_lhint_arr[len >> 9]; txbd->tx_bd_len_flags_type = cpu_to_le32(flags); - txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, prod, 1 + num_frags); + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 1 + num_frags); txbd->tx_bd_haddr = cpu_to_le64(mapping); /* now let us fill up the frags into the next buffers */ From 877edb347323b669c5c9511cc9e097e1192dd31b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:16 -0800 Subject: [PATCH 0589/7721] bnxt_en: Refactor bnxt_hwrm_set_coal() Add 2 helper functions to set coalescing for each RX and TX rings. This will make it easier to expand the number of TX rings per MSIX in the next patches. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 43 ++++++++++++++--------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1a7f14d086f7..c84a72b666aa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6896,10 +6896,29 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) return hwrm_req_send(bp, req_rx); } +static int +bnxt_hwrm_set_rx_coal(struct bnxt *bp, struct bnxt_napi *bnapi, + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) +{ + u16 ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring); + + req->ring_id = cpu_to_le16(ring_id); + return hwrm_req_send(bp, req); +} + +static int +bnxt_hwrm_set_tx_coal(struct bnxt *bp, struct bnxt_napi *bnapi, + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) +{ + u16 ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); + + req->ring_id = cpu_to_le16(ring_id); + return hwrm_req_send(bp, req); +} + int bnxt_hwrm_set_coal(struct bnxt *bp) { - struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req_rx, *req_tx, - *req; + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req_rx, *req_tx; int i, rc; rc = hwrm_req_init(bp, req_rx, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); @@ -6920,18 +6939,11 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_coal *hw_coal; - u16 ring_id; - req = req_rx; - if (!bnapi->rx_ring) { - ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); - req = req_tx; - } else { - ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring); - } - req->ring_id = cpu_to_le16(ring_id); - - rc = hwrm_req_send(bp, req); + if (!bnapi->rx_ring) + rc = bnxt_hwrm_set_tx_coal(bp, bnapi, req_tx); + else + rc = bnxt_hwrm_set_rx_coal(bp, bnapi, req_rx); if (rc) break; @@ -6939,10 +6951,7 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) continue; if (bnapi->rx_ring && bnapi->tx_ring) { - req = req_tx; - ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); - req->ring_id = cpu_to_le16(ring_id); - rc = hwrm_req_send(bp, req); + rc = bnxt_hwrm_set_tx_coal(bp, bnapi, req_tx); if (rc) break; } From 0589a1ed4d334c156110f7f42ad7c39a02761438 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:17 -0800 Subject: [PATCH 0590/7721] bnxt_en: Support up to 8 TX rings per MSIX For each mqprio TC, we allocate a set of TX rings to map to the new hardware CoS queue. Expand the tx_ring pointer in struct bnxt_napi to an array of 8 to support up to 8 TX rings, one for each TC. Only array entry 0 is used at this time. The rest of the array entries will be used in later patches. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 78 +++++++++++-------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 12 ++- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 4 +- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c84a72b666aa..6002b834e898 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -758,9 +758,13 @@ static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr, static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { - struct bnxt_tx_ring_info *txr = bnapi->tx_ring; + struct bnxt_tx_ring_info *txr; + int i; - __bnxt_tx_int(bp, txr, budget); + bnxt_for_each_napi_tx(i, bnapi, txr) { + if (txr->tx_hw_cons != txr->tx_cons) + __bnxt_tx_int(bp, txr, budget); + } bnapi->events &= ~BNXT_TX_CMP_EVENT; } @@ -2596,7 +2600,6 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, { struct bnxt_napi *bnapi = cpr->bnapi; u32 raw_cons = cpr->cp_raw_cons; - struct bnxt_tx_ring_info *txr; u32 cons; int rx_pkts = 0; u8 event = 0; @@ -2604,7 +2607,6 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, cpr->has_more_work = 0; cpr->had_work_done = 1; - txr = bnapi->tx_ring; while (1) { int rc; @@ -2620,8 +2622,10 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, dma_rmb(); if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) { u32 opaque = txcmp->tx_cmp_opaque; + struct bnxt_tx_ring_info *txr; u16 tx_freed; + txr = bnapi->tx_ring[TX_OPAQUE_RING(opaque)]; event |= BNXT_TX_CMP_EVENT; txr->tx_hw_cons = TX_OPAQUE_PROD(bp, opaque); tx_freed = (txr->tx_hw_cons - txr->tx_cons) & @@ -2671,7 +2675,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, xdp_do_flush(); if (event & BNXT_TX_EVENT) { - struct bnxt_tx_ring_info *txr = bnapi->tx_ring; + struct bnxt_tx_ring_info *txr = bnapi->tx_ring[0]; u16 prod = txr->tx_prod; /* Sync BD data before updating doorbell */ @@ -3657,7 +3661,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) static void bnxt_init_ring_struct(struct bnxt *bp) { - int i; + int i, j; for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; @@ -3702,18 +3706,16 @@ static void bnxt_init_ring_struct(struct bnxt *bp) rmem->vmem = (void **)&rxr->rx_agg_ring; skip_rx: - txr = bnapi->tx_ring; - if (!txr) - continue; - - ring = &txr->tx_ring_struct; - rmem = &ring->ring_mem; - rmem->nr_pages = bp->tx_nr_pages; - rmem->page_size = HW_RXBD_RING_SIZE; - rmem->pg_arr = (void **)txr->tx_desc_ring; - rmem->dma_arr = txr->tx_desc_mapping; - rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages; - rmem->vmem = (void **)&txr->tx_buf_ring; + bnxt_for_each_napi_tx(j, bnapi, txr) { + ring = &txr->tx_ring_struct; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->tx_nr_pages; + rmem->page_size = HW_TXBD_RING_SIZE; + rmem->pg_arr = (void **)txr->tx_desc_ring; + rmem->dma_arr = txr->tx_desc_mapping; + rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages; + rmem->vmem = (void **)&txr->tx_buf_ring; + } } } @@ -4512,7 +4514,7 @@ static int bnxt_alloc_stats(struct bnxt *bp) static void bnxt_clear_ring_indices(struct bnxt *bp) { - int i; + int i, j; if (!bp->bnapi) return; @@ -4529,8 +4531,7 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) cpr = &bnapi->cp_ring; cpr->cp_raw_cons = 0; - txr = bnapi->tx_ring; - if (txr) { + bnxt_for_each_napi_tx(j, bnapi, txr) { txr->tx_prod = 0; txr->tx_cons = 0; txr->tx_hw_cons = 0; @@ -4703,7 +4704,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) else txr->tx_cpr = &bp->bnapi[i]->cp_ring; txr->bnapi = bp->bnapi[j]; - bp->bnapi[j]->tx_ring = txr; + bp->bnapi[j]->tx_ring[0] = txr; bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i; if (i >= bp->tx_nr_rings_xdp) { txr->txq_index = i - bp->tx_nr_rings_xdp; @@ -6910,10 +6911,21 @@ static int bnxt_hwrm_set_tx_coal(struct bnxt *bp, struct bnxt_napi *bnapi, struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) { - u16 ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); + struct bnxt_tx_ring_info *txr; + int i, rc; - req->ring_id = cpu_to_le16(ring_id); - return hwrm_req_send(bp, req); + bnxt_for_each_napi_tx(i, bnapi, txr) { + u16 ring_id; + + ring_id = bnxt_cp_ring_for_tx(bp, txr); + req->ring_id = cpu_to_le16(ring_id); + rc = hwrm_req_send(bp, req); + if (rc) + return rc; + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + return 0; + } + return 0; } int bnxt_hwrm_set_coal(struct bnxt *bp) @@ -6950,7 +6962,7 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_CHIP_P5)) continue; - if (bnapi->rx_ring && bnapi->tx_ring) { + if (bnapi->rx_ring && bnapi->tx_ring[0]) { rc = bnxt_hwrm_set_tx_coal(bp, bnapi, req_tx); if (rc) break; @@ -11575,15 +11587,13 @@ static int bnxt_dbg_hwrm_ring_info_get(struct bnxt *bp, u8 ring_type, static void bnxt_dump_tx_sw_state(struct bnxt_napi *bnapi) { - struct bnxt_tx_ring_info *txr = bnapi->tx_ring; - int i = bnapi->index; + struct bnxt_tx_ring_info *txr; + int i = bnapi->index, j; - if (!txr) - return; - - netdev_info(bnapi->bp->dev, "[%d]: tx{fw_ring: %d prod: %x cons: %x}\n", - i, txr->tx_ring_struct.fw_ring_id, txr->tx_prod, - txr->tx_cons); + bnxt_for_each_napi_tx(j, bnapi, txr) + netdev_info(bnapi->bp->dev, "[%d.%d]: tx{fw_ring: %d prod: %x cons: %x}\n", + i, j, txr->tx_ring_struct.fw_ring_id, txr->tx_prod, + txr->tx_cons); } static void bnxt_dump_rx_sw_state(struct bnxt_napi *bnapi) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 430538844178..2028233c0561 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1046,6 +1046,14 @@ struct bnxt_cp_ring_info { struct bnxt_cp_ring_info *cp_ring_arr; }; +#define BNXT_MAX_QUEUE 8 +#define BNXT_MAX_TXR_PER_NAPI BNXT_MAX_QUEUE + +#define bnxt_for_each_napi_tx(iter, bnapi, txr) \ + for (iter = 0, txr = (bnapi)->tx_ring[0]; txr; \ + txr = (iter < BNXT_MAX_TXR_PER_NAPI - 1) ? \ + (bnapi)->tx_ring[++iter] : NULL) + struct bnxt_napi { struct napi_struct napi; struct bnxt *bp; @@ -1053,7 +1061,7 @@ struct bnxt_napi { int index; struct bnxt_cp_ring_info cp_ring; struct bnxt_rx_ring_info *rx_ring; - struct bnxt_tx_ring_info *tx_ring; + struct bnxt_tx_ring_info *tx_ring[BNXT_MAX_TXR_PER_NAPI]; void (*tx_int)(struct bnxt *, struct bnxt_napi *, int budget); @@ -1391,8 +1399,6 @@ struct bnxt_link_info { (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_DISABLE | \ BNXT_FEC_RS_OFF(link_info)) -#define BNXT_MAX_QUEUE 8 - struct bnxt_queue_info { u8 queue_id; u8 queue_profile; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 3515a12a6fea..52b75108e130 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -127,7 +127,7 @@ static void __bnxt_xmit_xdp_redirect(struct bnxt *bp, void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { - struct bnxt_tx_ring_info *txr = bnapi->tx_ring; + struct bnxt_tx_ring_info *txr = bnapi->tx_ring[0]; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; u16 tx_hw_cons = txr->tx_hw_cons; bool rx_doorbell_needed = false; @@ -249,7 +249,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, pdev = bp->pdev; offset = bp->rx_offset; - txr = rxr->bnapi->tx_ring; + txr = rxr->bnapi->tx_ring[0]; /* BNXT_RX_PAGE_MODE(bp) when XDP enabled */ orig_data = xdp.data; From f5b29c6afe369f5f2ee3966a332b9e8f70609933 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:18 -0800 Subject: [PATCH 0591/7721] bnxt_en: Add helper to get the number of CP rings required for TX rings Up until now, each TX ring always requires a completion ring/NQ/MSIX. bnxt_trim_rings() and the assignment of bp->cp_nr_rings always make this assumption. This will no longer be true in the next patches, so we refactor and add helper functions to determine the proper relationship between TX rings and the required completion ring/NQ/MSIX. This patch does not change the 1:1 relationship yet. Note that on P5 chips, each RX and TX ring still requires a completion ring. Only the number of NQs has been reduced. We should no longer call bnxt_trim_rings() to adjust the RX and TX rings on P5 chips. Replace with simple logic to check that RX + TX < CP and adjust accordingly. bnxt_check_rings() should call _bnxt_get_max_rings() to get the raw number of rings instead of bnxt_get_max_rings(). If we are about to create TCs, bnxt_get_max_rings() would not be able to calculate the max rings correctly. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 95 +++++++++++++++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 +- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 5 +- 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6002b834e898..7c1a3db651f5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6284,7 +6284,8 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp) if (bp->flags & BNXT_FLAG_AGG_RINGS) rx >>= 1; if (cp < (rx + tx)) { - bnxt_trim_rings(bp, &rx, &tx, cp, false); + rx = cp / 2; + tx = rx; if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; hw_resc->resv_rx_rings = rx; @@ -6585,6 +6586,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) int grp, rx_rings, rc; int vnic = 1, stat; bool sh = false; + int tx_cp; if (!bnxt_need_reserve_rings(bp)) return 0; @@ -6634,7 +6636,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp) rc = bnxt_trim_rings(bp, &rx_rings, &tx, cp, sh); if (bp->flags & BNXT_FLAG_AGG_RINGS) rx = rx_rings << 1; - cp = sh ? max_t(int, tx, rx_rings) : tx + rx_rings; + tx_cp = bnxt_num_tx_to_cp(bp, tx); + cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; bp->tx_nr_rings = tx; /* If we cannot reserve all the RX rings, reset the RSS map only @@ -9061,8 +9064,8 @@ static int bnxt_set_real_num_queues(struct bnxt *bp) return rc; } -static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, - bool shared) +static int __bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, + bool shared) { int _rx = *rx, _tx = *tx; @@ -9085,6 +9088,46 @@ static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, return 0; } +static int __bnxt_num_tx_to_cp(struct bnxt *bp, int tx, int tx_sets, int tx_xdp) +{ + return tx; +} + +int bnxt_num_tx_to_cp(struct bnxt *bp, int tx) +{ + int tcs = netdev_get_num_tc(bp->dev); + + if (!tcs) + tcs = 1; + return __bnxt_num_tx_to_cp(bp, tx, tcs, bp->tx_nr_rings_xdp); +} + +static int bnxt_num_cp_to_tx(struct bnxt *bp, int tx_cp) +{ + int tcs = netdev_get_num_tc(bp->dev); + + return (tx_cp - bp->tx_nr_rings_xdp) * tcs + + bp->tx_nr_rings_xdp; +} + +static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, + bool sh) +{ + int tx_cp = bnxt_num_tx_to_cp(bp, *tx); + + if (tx_cp != *tx) { + int tx_saved = tx_cp, rc; + + rc = __bnxt_trim_rings(bp, rx, &tx_cp, max, sh); + if (rc) + return rc; + if (tx_cp != tx_saved) + *tx = bnxt_num_cp_to_tx(bp, tx_cp); + return 0; + } + return __bnxt_trim_rings(bp, rx, tx, max, sh); +} + static void bnxt_setup_msix(struct bnxt *bp) { const int len = sizeof(bp->irq_tbl[0].name); @@ -9247,7 +9290,7 @@ static int bnxt_get_num_msix(struct bnxt *bp) static int bnxt_init_msix(struct bnxt *bp) { - int i, total_vecs, max, rc = 0, min = 1, ulp_msix; + int i, total_vecs, max, rc = 0, min = 1, ulp_msix, tx_cp; struct msix_entry *msix_ent; total_vecs = bnxt_get_num_msix(bp); @@ -9289,9 +9332,10 @@ static int bnxt_init_msix(struct bnxt *bp) if (rc) goto msix_setup_exit; + tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); bp->cp_nr_rings = (min == 1) ? - max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : - bp->tx_nr_rings + bp->rx_nr_rings; + max_t(int, tx_cp, bp->rx_nr_rings) : + tx_cp + bp->rx_nr_rings; } else { rc = -ENOMEM; @@ -12186,23 +12230,27 @@ static void bnxt_sp_task(struct work_struct *work) clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); } +static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx, + int *max_cp); + /* Under rtnl_lock */ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, int tx_xdp) { - int max_rx, max_tx, tx_sets = 1; + int max_rx, max_tx, max_cp, tx_sets = 1, tx_cp; int tx_rings_needed, stats; int rx_rings = rx; - int cp, vnics, rc; + int cp, vnics; if (tcs) tx_sets = tcs; - rc = bnxt_get_max_rings(bp, &max_rx, &max_tx, sh); - if (rc) - return rc; + if (bp->flags & BNXT_FLAG_AGG_RINGS) + rx_rings <<= 1; - if (max_rx < rx) + _bnxt_get_max_rings(bp, &max_rx, &max_tx, &max_cp); + + if (max_rx < rx_rings) return -ENOMEM; tx_rings_needed = tx * tx_sets + tx_xdp; @@ -12211,11 +12259,12 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, vnics = 1; if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS) - vnics += rx_rings; + vnics += rx; - if (bp->flags & BNXT_FLAG_AGG_RINGS) - rx_rings <<= 1; - cp = sh ? max_t(int, tx_rings_needed, rx) : tx_rings_needed + rx; + tx_cp = __bnxt_num_tx_to_cp(bp, tx_rings_needed, tx_sets, tx_xdp); + cp = sh ? max_t(int, tx_cp, rx) : tx_cp + rx; + if (max_cp < cp) + return -ENOMEM; stats = cp; if (BNXT_NEW_RM(bp)) { cp += bnxt_get_ulp_msix_num(bp); @@ -12849,7 +12898,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc) { struct bnxt *bp = netdev_priv(dev); bool sh = false; - int rc; + int rc, tx_cp; if (tc > bp->max_tc) { netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n", @@ -12880,8 +12929,9 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc) netdev_reset_tc(dev); } bp->tx_nr_rings += bp->tx_nr_rings_xdp; - bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : - bp->tx_nr_rings + bp->rx_nr_rings; + tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); + bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : + tx_cp + bp->rx_nr_rings; if (netif_running(bp->dev)) return bnxt_open_nic(bp, true, false); @@ -13360,7 +13410,10 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx, if (bp->flags & BNXT_FLAG_AGG_RINGS) *max_rx >>= 1; if (bp->flags & BNXT_FLAG_CHIP_P5) { - bnxt_trim_rings(bp, max_rx, max_tx, *max_cp, false); + if (*max_cp < (*max_rx + *max_tx)) { + *max_rx = *max_cp / 2; + *max_tx = *max_rx; + } /* On P5 chips, max_cp output param should be available NQs */ *max_cp = max_irq; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 2028233c0561..4ce993943924 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2393,6 +2393,7 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); int bnxt_nq_rings_in_use(struct bnxt *bp); int bnxt_hwrm_set_coal(struct bnxt *); void bnxt_free_ctx_mem(struct bnxt *bp); +int bnxt_num_tx_to_cp(struct bnxt *bp, int tx); unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp); unsigned int bnxt_get_avail_stat_ctxs_for_en(struct bnxt *bp); unsigned int bnxt_get_max_func_cp_rings(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 18c06158fead..76f2eab52ce7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -923,6 +923,7 @@ static int bnxt_set_channels(struct net_device *dev, bool sh = false; int tx_xdp = 0; int rc = 0; + int tx_cp; if (channel->other_count) return -EINVAL; @@ -994,8 +995,9 @@ static int bnxt_set_channels(struct net_device *dev, if (tcs > 1) bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; - bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : - bp->tx_nr_rings + bp->rx_nr_rings; + tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); + bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : + tx_cp + bp->rx_nr_rings; /* After changing number of rx channels, update NTUPLE feature. */ netdev_update_features(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 52b75108e130..9d428eb3fdb9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -398,7 +398,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames, static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) { struct net_device *dev = bp->dev; - int tx_xdp = 0, rc, tc; + int tx_xdp = 0, tx_cp, rc, tc; struct bpf_prog *old; if (prog && !prog->aux->xdp_has_frags && @@ -446,7 +446,8 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) } bp->tx_nr_rings_xdp = tx_xdp; bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp; - bp->cp_nr_rings = max_t(int, bp->tx_nr_rings, bp->rx_nr_rings); + tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); + bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings); bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); From f07b58801befb2a9449f9cdc6a379c707ba7a35c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:19 -0800 Subject: [PATCH 0592/7721] bnxt_en: Add macros related to TC and TX rings Add 3 macros that handle to conversions between TC numbers and TX ring numbers. These will help to clarify the existing logic and the new logic in the next patch. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7c1a3db651f5..d0eca7648927 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3415,6 +3415,15 @@ static void bnxt_free_tx_rings(struct bnxt *bp) } } +#define BNXT_TC_TO_RING_BASE(bp, tc) \ + ((tc) * (bp)->tx_nr_rings_per_tc) + +#define BNXT_RING_TO_TC_OFF(bp, tx) \ + ((tx) % (bp)->tx_nr_rings_per_tc) + +#define BNXT_RING_TO_TC(bp, tx) \ + ((tx) / (bp)->tx_nr_rings_per_tc) + static int bnxt_alloc_tx_rings(struct bnxt *bp) { int i, j, rc; @@ -3470,7 +3479,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp) spin_lock_init(&txr->xdp_tx_lock); if (i < bp->tx_nr_rings_xdp) continue; - if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1)) + if (BNXT_RING_TO_TC_OFF(bp, i) == (bp->tx_nr_rings_per_tc - 1)) j++; } return 0; @@ -9140,7 +9149,7 @@ static void bnxt_setup_msix(struct bnxt *bp) for (i = 0; i < tcs; i++) { count = bp->tx_nr_rings_per_tc; - off = i * count; + off = BNXT_TC_TO_RING_BASE(bp, i); netdev_set_tc_queue(dev, i, count, off); } } From ba098017791eb8a0782b373d4cee0d82eb2f660e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:20 -0800 Subject: [PATCH 0593/7721] bnxt_en: Use existing MSIX vectors for all mqprio TX rings We can now fully support sharing the same MSIX for all mqprio TX rings belonging to the same ethtool channel with the new infrastructure: 1. Allocate the proper entries for cp_ring_arr in struct bnxt_cp_ring_info to support the additional TX rings. 2. Populate the tx_ring array in struct bnxt_napi for all TX rings sharing the same NAPI. 3. bnxt_num_tx_to_cp() returns the proper NQ/completion rings to support the TX rings in the input. 4. Adjust bnxt_get_num_ring_stats() for the reduced number of ring counters with the new scheme. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 56 ++++++++++++++----- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 +- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d0eca7648927..d1af1d2ff800 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3609,7 +3609,10 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) { bool sh = !!(bp->flags & BNXT_FLAG_SHARED_RINGS); int i, j, rc, ulp_base_vec, ulp_msix; + int tcs = netdev_get_num_tc(bp->dev); + if (!tcs) + tcs = 1; ulp_msix = bnxt_get_ulp_msix_num(bp); ulp_base_vec = bnxt_get_ulp_msix_base(bp); for (i = 0, j = 0; i < bp->cp_nr_rings; i++) { @@ -3617,6 +3620,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) struct bnxt_cp_ring_info *cpr, *cpr2; struct bnxt_ring_struct *ring; int cp_count = 0, k; + int rx = 0, tx = 0; if (!bnapi) continue; @@ -3637,11 +3641,18 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_CHIP_P5)) continue; - if (i < bp->rx_nr_rings) + if (i < bp->rx_nr_rings) { cp_count++; - if ((sh && i < bp->tx_nr_rings) || - (!sh && i >= bp->rx_nr_rings)) + rx = 1; + } + if (i < bp->tx_nr_rings_xdp) { cp_count++; + tx = 1; + } else if ((sh && i < bp->tx_nr_rings) || + (!sh && i >= bp->rx_nr_rings)) { + cp_count += tcs; + tx = 1; + } cpr->cp_ring_arr = kcalloc(cp_count, sizeof(*cpr), GFP_KERNEL); @@ -3656,14 +3667,19 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) return rc; cpr2->bnapi = bnapi; cpr2->cp_idx = k; - if (!k && i < bp->rx_nr_rings) { + if (!k && rx) { bp->rx_ring[i].rx_cpr = cpr2; cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_RX; } else { - bp->tx_ring[j++].tx_cpr = cpr2; + int n, tc = k - rx; + + n = BNXT_TC_TO_RING_BASE(bp, tc) + j; + bp->tx_ring[n].tx_cpr = cpr2; cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_TX; } } + if (tx) + j++; } return 0; } @@ -4704,24 +4720,33 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) else j = bp->rx_nr_rings; - for (i = 0; i < bp->tx_nr_rings; i++, j++) { + for (i = 0; i < bp->tx_nr_rings; i++) { struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; + struct bnxt_napi *bnapi2; if (bp->flags & BNXT_FLAG_CHIP_P5) txr->tx_ring_struct.ring_mem.flags = BNXT_RMEM_RING_PTE_FLAG; - else - txr->tx_cpr = &bp->bnapi[i]->cp_ring; - txr->bnapi = bp->bnapi[j]; - bp->bnapi[j]->tx_ring[0] = txr; bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i; if (i >= bp->tx_nr_rings_xdp) { + int k = j + BNXT_RING_TO_TC_OFF(bp, i); + + bnapi2 = bp->bnapi[k]; txr->txq_index = i - bp->tx_nr_rings_xdp; - bp->bnapi[j]->tx_int = bnxt_tx_int; + txr->tx_napi_idx = + BNXT_RING_TO_TC(bp, txr->txq_index); + bnapi2->tx_ring[txr->tx_napi_idx] = txr; + bnapi2->tx_int = bnxt_tx_int; } else { - bp->bnapi[j]->flags |= BNXT_NAPI_FLAG_XDP; - bp->bnapi[j]->tx_int = bnxt_tx_int_xdp; + bnapi2 = bp->bnapi[j]; + bnapi2->flags |= BNXT_NAPI_FLAG_XDP; + bnapi2->tx_ring[0] = txr; + bnapi2->tx_int = bnxt_tx_int_xdp; + j++; } + txr->bnapi = bnapi2; + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + txr->tx_cpr = &bnapi2->cp_ring; } rc = bnxt_alloc_stats(bp); @@ -9099,7 +9124,7 @@ static int __bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, static int __bnxt_num_tx_to_cp(struct bnxt *bp, int tx, int tx_sets, int tx_xdp) { - return tx; + return (tx - tx_xdp) / tx_sets + tx_xdp; } int bnxt_num_tx_to_cp(struct bnxt *bp, int tx) @@ -13723,7 +13748,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } max_irqs = bnxt_get_max_irq(pdev); - dev = alloc_etherdev_mq(sizeof(*bp), max_irqs); + dev = alloc_etherdev_mqs(sizeof(*bp), max_irqs * BNXT_MAX_QUEUE, + max_irqs); if (!dev) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 76f2eab52ce7..585044310141 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -528,7 +528,8 @@ static int bnxt_get_num_ring_stats(struct bnxt *bp) bnxt_get_num_tpa_ring_stats(bp); tx = NUM_RING_TX_HW_STATS; cmn = NUM_RING_CMN_SW_STATS; - return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + + return rx * bp->rx_nr_rings + + tx * (bp->tx_nr_rings_xdp + bp->tx_nr_rings_per_tc) + cmn * bp->cp_nr_rings; } From c1056a59aee1d352c7113c2cba4d214bf5f195af Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Nov 2023 16:16:21 -0800 Subject: [PATCH 0594/7721] bnxt_en: Optimize xmit_more TX path Now that we use the cumulative consumer index scheme for TX completion, we don't need to have one TX completion per TX packet in the xmit_more code path. Set the TX_BD_FLAGS_NO_CMPL flag if xmit_more is true. Fallback to one interrupt per packet if the ring is filled beyond bp->tx_wake_thresh. Also, move the wmb() to bnxt_txr_db_kick(). When xmit_more is true, we'll skip the bnxt_txr_db_kick() call and there is no need to call wmb() to sync. the TX BD data. Reviewed-by: Somnath Kotur Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d1af1d2ff800..e6ac1bd21bb3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -381,6 +381,8 @@ static u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb) static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr, u16 prod) { + /* Sync BD data before updating doorbell */ + wmb(); bnxt_db_write(bp, &txr->tx_db, prod); txr->kick_pending = 0; } @@ -388,7 +390,7 @@ static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr, static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); - struct tx_bd *txbd; + struct tx_bd *txbd, *txbd0; struct tx_bd_ext *txbd1; struct netdev_queue *txq; int i; @@ -602,6 +604,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags); txbd1->tx_bd_cfa_action = cpu_to_le32(cfa_action << TX_BD_CFA_ACTION_SHIFT); + txbd0 = txbd; for (i = 0; i < last_frag; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -633,16 +636,17 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); - /* Sync BD data before updating doorbell */ - wmb(); - prod = NEXT_TX(prod); WRITE_ONCE(txr->tx_prod, prod); - if (!netdev_xmit_more() || netif_xmit_stopped(txq)) + if (!netdev_xmit_more() || netif_xmit_stopped(txq)) { bnxt_txr_db_kick(bp, txr, prod); - else + } else { + if (free_size >= bp->tx_wake_thresh) + txbd0->tx_bd_len_flags_type |= + cpu_to_le32(TX_BD_FLAGS_NO_CMPL); txr->kick_pending = 1; + } tx_done: From e316dd1cf1358ff9c44b37c7be273a7dc4349986 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 14 Nov 2023 00:11:42 -0500 Subject: [PATCH 0595/7721] net: don't dump stack on queue timeout The top syzbot report for networking (#14 for the entire kernel) is the queue timeout splat. We kept it around for a long time, because in real life it provides pretty strong signal that something is wrong with the driver or the device. Removing it is also likely to break monitoring for those who track it as a kernel warning. Nevertheless, WARN()ings are best suited for catching kernel programming bugs. If a Tx queue gets starved due to a pause storm, priority configuration, or other weirdness - that's obviously a problem, but not a problem we can fix at the kernel level. Bite the bullet and convert the WARN() to a print. Before: NETDEV WATCHDOG: eni1np1 (netdevsim): transmit queue 0 timed out 1975 ms WARNING: CPU: 0 PID: 0 at net/sched/sch_generic.c:525 dev_watchdog+0x39e/0x3b0 [... completely pointless stack trace of a timer follows ...] Now: netdevsim netdevsim1 eni1np1: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 1769 ms Alternatively we could mark the drivers which syzbot has learned to abuse as "print-instead-of-WARN" selectively. Reported-by: syzbot+d55372214aff0faa1f1f@syzkaller.appspotmail.com Reviewed-by: Jiri Pirko Reviewed-by: Eric Dumazet Reviewed-by: Jamal Hadi Salim Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 4195a4bc26ca..8dd0e5925342 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -522,8 +522,9 @@ static void dev_watchdog(struct timer_list *t) if (unlikely(timedout_ms)) { trace_net_dev_xmit_timeout(dev, i); - WARN_ONCE(1, "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out %u ms\n", - dev->name, netdev_drivername(dev), i, timedout_ms); + netdev_crit(dev, "NETDEV WATCHDOG: CPU: %d: transmit queue %u timed out %u ms\n", + raw_smp_processor_id(), + i, timedout_ms); netif_freeze_queues(dev); dev->netdev_ops->ndo_tx_timeout(dev, i); netif_unfreeze_queues(dev); From 1d2c16e1ab98db04af2d1215d8dddcf5c09f57c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:32 +0100 Subject: [PATCH 0596/7721] dt-bindings: rtc: s3c-rtc: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20231108104343.24192-7-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/rtc/s3c-rtc.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml index d51b236939bf..bf4e11d6dffb 100644 --- a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml @@ -17,6 +17,11 @@ properties: - samsung,s3c2416-rtc - samsung,s3c2443-rtc - samsung,s3c6410-rtc + - items: + - enum: + - samsung,exynos7-rtc + - samsung,exynos850-rtc + - const: samsung,s3c6410-rtc - const: samsung,exynos3250-rtc deprecated: true From 5436459961da39dd4025a52e65c39e589011667c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:33 +0100 Subject: [PATCH 0597/7721] dt-bindings: serial: samsung: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Re-shuffle also the entries in compatibles, so the one-compatible-enum is the first. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231108104343.24192-8-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/serial/samsung_uart.yaml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index ac60ab1e35e3..0d0215b23ab7 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -18,9 +18,6 @@ description: |+ properties: compatible: oneOf: - - items: - - const: samsung,exynosautov9-uart - - const: samsung,exynos850-uart - enum: - apple,s5l-uart - axis,artpec8-uart @@ -29,6 +26,17 @@ properties: - samsung,exynos4210-uart - samsung,exynos5433-uart - samsung,exynos850-uart + - items: + - enum: + - samsung,exynos7-uart + - const: samsung,exynos4210-uart + - items: + - enum: + - samsung,exynos7885-uart + - const: samsung,exynos5433-uart + - items: + - const: samsung,exynosautov9-uart + - const: samsung,exynos850-uart reg: maxItems: 1 From 25737c24cb06c040a342072f93a42799a28432dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:34 +0100 Subject: [PATCH 0598/7721] dt-bindings: samsung: exynos-pmu: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231108104343.24192-9-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/soc/samsung/exynos-pmu.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index e1d716df5dfa..6492e92586d9 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -48,6 +48,12 @@ properties: - samsung,exynos850-pmu - samsung-s5pv210-pmu - const: syscon + - items: + - enum: + - samsung,exynos7885-pmu + - samsung,exynosautov9-pmu + - const: samsung,exynos7-pmu + - const: syscon - items: - enum: - samsung,exynos3250-pmu From 416231a9e38331c870da3bc84f3535e3d67cfb92 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:35 +0100 Subject: [PATCH 0599/7721] dt-bindings: gpu: arm,mali-midgard: add specific compatibles for existing Exynos SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231108104343.24192-10-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml index ca02baba5526..0801da33a385 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml @@ -40,6 +40,11 @@ properties: - rockchip,rk3288-mali - samsung,exynos5433-mali - const: arm,mali-t760 + - items: + - enum: + - samsung,exynos7-mali + - const: samsung,exynos5433-mali + - const: arm,mali-t760 - items: - enum: - rockchip,rk3399-mali From b709ff4da1beaab1c92df91c9023aad7388b84c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:36 +0100 Subject: [PATCH 0600/7721] dt-bindings: iio: samsung,exynos-adc: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231108104343.24192-11-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/iio/adc/samsung,exynos-adc.yaml | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml index 582d0a03b814..4e40f6bed5db 100644 --- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml @@ -11,18 +11,23 @@ maintainers: properties: compatible: - enum: - - samsung,exynos-adc-v1 # Exynos5250 - - samsung,exynos-adc-v2 - - samsung,exynos3250-adc - - samsung,exynos4212-adc # Exynos4212 and Exynos4412 - - samsung,exynos7-adc - - samsung,s3c2410-adc - - samsung,s3c2416-adc - - samsung,s3c2440-adc - - samsung,s3c2443-adc - - samsung,s3c6410-adc - - samsung,s5pv210-adc + oneOf: + - enum: + - samsung,exynos-adc-v1 # Exynos5250 + - samsung,exynos-adc-v2 + - samsung,exynos3250-adc + - samsung,exynos4212-adc # Exynos4212 and Exynos4412 + - samsung,exynos7-adc + - samsung,s3c2410-adc + - samsung,s3c2416-adc + - samsung,s3c2440-adc + - samsung,s3c2443-adc + - samsung,s3c6410-adc + - samsung,s5pv210-adc + - items: + - enum: + - samsung,exynos5433-adc + - const: samsung,exynos7-adc reg: maxItems: 1 From cb931ee571be5eacd50628e108e81c065c9cb5f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:37 +0100 Subject: [PATCH 0601/7721] ASoC: dt-bindings: samsung-i2s: add specific compatibles for existing SoC Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Acked-by: Lee Jones Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231108104343.24192-12-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../mfd/samsung,exynos5433-lpass.yaml | 2 +- .../bindings/sound/samsung-i2s.yaml | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml index b97b06848729..f154103f32cc 100644 --- a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml +++ b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml @@ -85,7 +85,7 @@ examples: }; i2s@11440000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", "samsung,exynos7-i2s"; reg = <0x11440000 0x100>; dmas = <&adma 0>, <&adma 2>; dma-names = "tx", "rx"; diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml index 30b3b6e9824b..f45f73b5056d 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml @@ -44,13 +44,18 @@ properties: frequencies supported by Exynos7 I2S and 7.1 channel TDM support for playback and capture TDM (Time division multiplexing) to allow transfer of multiple channel audio data on single data line. - enum: - - samsung,s3c6410-i2s - - samsung,s5pv210-i2s - - samsung,exynos5420-i2s - - samsung,exynos7-i2s - - samsung,exynos7-i2s1 - - tesla,fsd-i2s + oneOf: + - enum: + - samsung,s3c6410-i2s + - samsung,s5pv210-i2s + - samsung,exynos5420-i2s + - samsung,exynos7-i2s + - samsung,exynos7-i2s1 + - tesla,fsd-i2s + - items: + - enum: + - samsung,exynos5433-i2s + - const: samsung,exynos7-i2s '#address-cells': const: 1 From 622018516aa581d25e86a0c8a7d3a6d749d35d0e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:38 +0100 Subject: [PATCH 0602/7721] dt-bindings: pwm: samsung: add specific compatibles for existing SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Samsung Exynos SoC reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to each SoC in front of all old-SoC-like compatibles. Reviewed-by: Alim Akhtar Acked-by: Rob Herring Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231108104343.24192-13-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/pwm/pwm-samsung.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml index 2162f661ed5a..89a3875cb50a 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml @@ -29,6 +29,8 @@ properties: - samsung,exynos4210-pwm # 32-bit, Exynos - items: - enum: + - samsung,exynos5433-pwm + - samsung,exynos7-pwm - samsung,exynosautov9-pwm - const: samsung,exynos4210-pwm From c226e8c5e716d89349a8b2b0b54fd1739a575ed0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:39 +0100 Subject: [PATCH 0603/7721] arm64: dts: exynos5433: add specific compatibles to several blocks Exynos5433 reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to Exynos5433 in front of all old-SoC-like compatibles. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20231108104343.24192-14-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 60 ++++++++++++++-------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi index 91ae0462a706..7fbbec04bff0 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi @@ -361,7 +361,8 @@ soc: soc@0 { ranges = <0x0 0x0 0x0 0x18000000>; chipid@10000000 { - compatible = "samsung,exynos4210-chipid"; + compatible = "samsung,exynos5433-chipid", + "samsung,exynos4210-chipid"; reg = <0x10000000 0x100>; }; @@ -850,7 +851,8 @@ pinctrl_alive: pinctrl@10580000 { reg = <0x10580000 0x1a20>, <0x11090000 0x100>; wakeup-interrupt-controller { - compatible = "samsung,exynos7-wakeup-eint"; + compatible = "samsung,exynos5433-wakeup-eint", + "samsung,exynos7-wakeup-eint"; interrupts = ; }; }; @@ -1546,7 +1548,7 @@ spi_4: spi@14d00000 { }; adc: adc@14d10000 { - compatible = "samsung,exynos7-adc"; + compatible = "samsung,exynos5433-adc", "samsung,exynos7-adc"; reg = <0x14d10000 0x100>; interrupts = ; clock-names = "adc"; @@ -1556,7 +1558,7 @@ adc: adc@14d10000 { }; i2s1: i2s@14d60000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", "samsung,exynos7-i2s"; reg = <0x14d60000 0x100>; dmas = <&pdma0 31>, <&pdma0 30>; dma-names = "tx", "rx"; @@ -1571,7 +1573,7 @@ i2s1: i2s@14d60000 { }; pwm: pwm@14dd0000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "samsung,exynos5433-pwm", "samsung,exynos4210-pwm"; reg = <0x14dd0000 0x100>; interrupts = , , @@ -1586,7 +1588,8 @@ pwm: pwm@14dd0000 { }; hsi2c_0: i2c@14e40000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e40000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1599,7 +1602,8 @@ hsi2c_0: i2c@14e40000 { }; hsi2c_1: i2c@14e50000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e50000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1612,7 +1616,8 @@ hsi2c_1: i2c@14e50000 { }; hsi2c_2: i2c@14e60000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e60000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1625,7 +1630,8 @@ hsi2c_2: i2c@14e60000 { }; hsi2c_3: i2c@14e70000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e70000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1638,7 +1644,8 @@ hsi2c_3: i2c@14e70000 { }; hsi2c_4: i2c@14ec0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ec0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1651,7 +1658,8 @@ hsi2c_4: i2c@14ec0000 { }; hsi2c_5: i2c@14ed0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ed0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1664,7 +1672,8 @@ hsi2c_5: i2c@14ed0000 { }; hsi2c_6: i2c@14ee0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ee0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1677,7 +1686,8 @@ hsi2c_6: i2c@14ee0000 { }; hsi2c_7: i2c@14ef0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ef0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1690,7 +1700,8 @@ hsi2c_7: i2c@14ef0000 { }; hsi2c_8: i2c@14d90000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14d90000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1703,7 +1714,8 @@ hsi2c_8: i2c@14d90000 { }; hsi2c_9: i2c@14da0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14da0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1716,7 +1728,8 @@ hsi2c_9: i2c@14da0000 { }; hsi2c_10: i2c@14de0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14de0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1729,7 +1742,8 @@ hsi2c_10: i2c@14de0000 { }; hsi2c_11: i2c@14df0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14df0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1820,7 +1834,8 @@ usbhost_dwc3: usb@0 { }; mshc_0: mmc@15540000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1833,7 +1848,8 @@ mshc_0: mmc@15540000 { }; mshc_1: mmc@15550000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1846,7 +1862,8 @@ mshc_1: mmc@15550000 { }; mshc_2: mmc@15560000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1897,7 +1914,8 @@ adma: dma-controller@11420000 { }; i2s0: i2s@11440000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", + "samsung,exynos7-i2s"; reg = <0x11440000 0x100>; dmas = <&adma 0>, <&adma 2>; dma-names = "tx", "rx"; From ea9875b7d4aec65d39e17980fd682b5bd9068158 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:40 +0100 Subject: [PATCH 0604/7721] arm64: dts: exynos7: add specific compatibles to several blocks Exynos7 reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to Exynos7 in front of all old-SoC-like compatibles. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20231108104343.24192-15-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos7.dtsi | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi index 6ed80ddf3369..9cb6bd61262e 100644 --- a/arch/arm64/boot/dts/exynos/exynos7.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi @@ -128,7 +128,8 @@ soc: soc@0 { ranges = <0 0 0 0x18000000>; chipid@10000000 { - compatible = "samsung,exynos4210-chipid"; + compatible = "samsung,exynos7-chipid", + "samsung,exynos4210-chipid"; reg = <0x10000000 0x100>; }; @@ -279,7 +280,7 @@ clock_fsys1: clock-controller@156e0000 { }; serial_0: serial@13630000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x13630000 0x100>; interrupts = ; clocks = <&clock_peric0 PCLK_UART0>, @@ -289,7 +290,7 @@ serial_0: serial@13630000 { }; serial_1: serial@14c20000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c20000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART1>, @@ -299,7 +300,7 @@ serial_1: serial@14c20000 { }; serial_2: serial@14c30000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c30000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART2>, @@ -309,7 +310,7 @@ serial_2: serial@14c30000 { }; serial_3: serial@14c40000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c40000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART3>, @@ -539,7 +540,7 @@ pmu_system_controller: system-controller@105c0000 { }; rtc: rtc@10590000 { - compatible = "samsung,s3c6410-rtc"; + compatible = "samsung,exynos7-rtc", "samsung,s3c6410-rtc"; reg = <0x10590000 0x100>; interrupts = , ; @@ -559,7 +560,8 @@ watchdog: watchdog@101d0000 { }; gpu: gpu@14ac0000 { - compatible = "samsung,exynos5433-mali", "arm,mali-t760"; + compatible = "samsung,exynos7-mali", + "samsung,exynos5433-mali", "arm,mali-t760"; reg = <0x14ac0000 0x5000>; interrupts = , , @@ -619,7 +621,7 @@ adc: adc@13620000 { }; pwm: pwm@136c0000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "samsung,exynos7-pwm", "samsung,exynos4210-pwm"; reg = <0x136c0000 0x100>; interrupts = , , From 0ffc692ad83625358bf382c072f6c0af609ba157 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:41 +0100 Subject: [PATCH 0605/7721] arm64: dts: exynos7885: add specific compatibles to several blocks Exynos7885 reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to Exynos7885 in front of all old-SoC-like compatibles. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20231108104343.24192-16-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos7885.dtsi | 45 ++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynos7885.dtsi b/arch/arm64/boot/dts/exynos/exynos7885.dtsi index d69fc2392bd0..008228fb319a 100644 --- a/arch/arm64/boot/dts/exynos/exynos7885.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos7885.dtsi @@ -172,7 +172,8 @@ soc: soc@0 { ranges = <0x0 0x0 0x0 0x20000000>; chipid@10000000 { - compatible = "samsung,exynos850-chipid"; + compatible = "samsung,exynos7885-chipid", + "samsung,exynos850-chipid"; reg = <0x10000000 0x24>; }; @@ -264,7 +265,8 @@ pinctrl_alive: pinctrl@11cb0000 { reg = <0x11cb0000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos7-wakeup-eint"; + compatible = "samsung,exynos7885-wakeup-eint", + "samsung,exynos7-wakeup-eint"; interrupt-parent = <&gic>; interrupts = ; }; @@ -289,12 +291,14 @@ pinctrl_dispaud: pinctrl@148f0000 { }; pmu_system_controller: system-controller@11c80000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "samsung,exynos7885-pmu", + "samsung,exynos7-pmu", "syscon"; reg = <0x11c80000 0x10000>; }; mmc_0: mmc@13500000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos7885-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; reg = <0x13500000 0x2000>; interrupts = ; #address-cells = <1>; @@ -307,7 +311,8 @@ mmc_0: mmc@13500000 { }; serial_0: serial@13800000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13800000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -320,7 +325,8 @@ serial_0: serial@13800000 { }; serial_1: serial@13810000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13810000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -333,7 +339,8 @@ serial_1: serial@13810000 { }; serial_2: serial@13820000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13820000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -346,7 +353,8 @@ serial_2: serial@13820000 { }; i2c_0: i2c@13830000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13830000 0x100>; interrupts = ; #address-cells = <1>; @@ -359,7 +367,8 @@ i2c_0: i2c@13830000 { }; i2c_1: i2c@13840000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13840000 0x100>; interrupts = ; #address-cells = <1>; @@ -372,7 +381,8 @@ i2c_1: i2c@13840000 { }; i2c_2: i2c@13850000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13850000 0x100>; interrupts = ; #address-cells = <1>; @@ -385,7 +395,8 @@ i2c_2: i2c@13850000 { }; i2c_3: i2c@13860000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13860000 0x100>; interrupts = ; #address-cells = <1>; @@ -398,7 +409,8 @@ i2c_3: i2c@13860000 { }; i2c_4: i2c@13870000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13870000 0x100>; interrupts = ; #address-cells = <1>; @@ -411,7 +423,8 @@ i2c_4: i2c@13870000 { }; i2c_5: i2c@13880000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13880000 0x100>; interrupts = ; #address-cells = <1>; @@ -424,7 +437,8 @@ i2c_5: i2c@13880000 { }; i2c_6: i2c@13890000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13890000 0x100>; interrupts = ; #address-cells = <1>; @@ -437,7 +451,8 @@ i2c_6: i2c@13890000 { }; i2c_7: i2c@11cd0000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x11cd0000 0x100>; interrupts = ; #address-cells = <1>; From bce7af250d0fe16f088b27dc9682addb0236194b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:42 +0100 Subject: [PATCH 0606/7721] arm64: dts: exynos850: add specific compatibles to several blocks Exynos850 reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to Exynos850 in front of all old-SoC-like compatibles. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20231108104343.24192-17-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos850.dtsi | 34 +++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynos850.dtsi b/arch/arm64/boot/dts/exynos/exynos850.dtsi index 53104e65b9c6..df5ea43ebcad 100644 --- a/arch/arm64/boot/dts/exynos/exynos850.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos850.dtsi @@ -396,7 +396,7 @@ pinctrl_aud: pinctrl@14a60000 { }; rtc: rtc@11a30000 { - compatible = "samsung,s3c6410-rtc"; + compatible = "samsung,exynos850-rtc", "samsung,s3c6410-rtc"; reg = <0x11a30000 0x100>; interrupts = , ; @@ -406,7 +406,8 @@ rtc: rtc@11a30000 { }; mmc_0: mmc@12100000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos850-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; reg = <0x12100000 0x2000>; interrupts = ; #address-cells = <1>; @@ -419,7 +420,7 @@ mmc_0: mmc@12100000 { }; i2c_0: i2c@13830000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13830000 0x100>; interrupts = ; #address-cells = <1>; @@ -432,7 +433,7 @@ i2c_0: i2c@13830000 { }; i2c_1: i2c@13840000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13840000 0x100>; interrupts = ; #address-cells = <1>; @@ -445,7 +446,7 @@ i2c_1: i2c@13840000 { }; i2c_2: i2c@13850000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13850000 0x100>; interrupts = ; #address-cells = <1>; @@ -458,7 +459,7 @@ i2c_2: i2c@13850000 { }; i2c_3: i2c@13860000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13860000 0x100>; interrupts = ; #address-cells = <1>; @@ -471,7 +472,7 @@ i2c_3: i2c@13860000 { }; i2c_4: i2c@13870000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13870000 0x100>; interrupts = ; #address-cells = <1>; @@ -485,7 +486,7 @@ i2c_4: i2c@13870000 { /* I2C_5 (also called CAM_PMIC_I2C in TRM) */ i2c_5: i2c@13880000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13880000 0x100>; interrupts = ; #address-cells = <1>; @@ -499,7 +500,7 @@ i2c_5: i2c@13880000 { /* I2C_6 (also called MOTOR_I2C in TRM) */ i2c_6: i2c@13890000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13890000 0x100>; interrupts = ; #address-cells = <1>; @@ -640,7 +641,8 @@ usi_hsi2c_0: usi@138a00c0 { status = "disabled"; hsi2c_0: i2c@138a0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138a0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -668,7 +670,8 @@ usi_hsi2c_1: usi@138b00c0 { status = "disabled"; hsi2c_1: i2c@138b0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138b0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -696,7 +699,8 @@ usi_hsi2c_2: usi@138c00c0 { status = "disabled"; hsi2c_2: i2c@138c0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138c0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -738,7 +742,8 @@ usi_cmgp0: usi@11d000c0 { status = "disabled"; hsi2c_3: i2c@11d00000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x11d00000 0xc0>; interrupts = ; #address-cells = <1>; @@ -778,7 +783,8 @@ usi_cmgp1: usi@11d200c0 { status = "disabled"; hsi2c_4: i2c@11d20000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x11d20000 0xc0>; interrupts = ; #address-cells = <1>; From b5acc262278f679bfb7479f817423180096acb8b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Nov 2023 11:43:43 +0100 Subject: [PATCH 0607/7721] arm64: dts: exynosautov9: add specific compatibles to several blocks ExynosAutov9 reuses several devices from older designs, thus historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add compatibles specific to ExynosAutov9 in front of all old-SoC-like compatibles. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20231108104343.24192-18-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynosautov9.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi index b228cd7e351e..417aa56a81f6 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi +++ b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi @@ -166,7 +166,8 @@ soc: soc@0 { ranges = <0x0 0x0 0x0 0x20000000>; chipid@10000000 { - compatible = "samsung,exynos850-chipid"; + compatible = "samsung,exynosautov9-chipid", + "samsung,exynos850-chipid"; reg = <0x10000000 0x24>; }; @@ -349,7 +350,8 @@ pinctrl_peric1: pinctrl@10830000 { }; pmu_system_controller: system-controller@10460000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "samsung,exynosautov9-pmu", + "samsung,exynos7-pmu", "syscon"; reg = <0x10460000 0x10000>; reboot: syscon-reboot { From 353ff168fb99cf1ff9d8556692ce18f646ae8992 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Fri, 27 Oct 2023 13:03:37 +0900 Subject: [PATCH 0608/7721] arm64: dts: exynos: add gpio-key node for exynosautov9-sadk ExynosAutov9 SADK board has 3 keys to test external GPIO interrupt. To support this, add 3 gpio-key(Wakeup, Volume Down, Volume Up) node. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231027040338.63088-1-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- .../boot/dts/exynos/exynosautov9-sadk.dts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts b/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts index bc1815f6ada2..de2c1de51a76 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts +++ b/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts @@ -9,6 +9,7 @@ /dts-v1/; #include "exynosautov9.dtsi" #include +#include / { model = "Samsung ExynosAuto v9 SADK board"; @@ -32,6 +33,31 @@ memory@80000000 { <0xa 0x00000000 0x2 0x00000000>; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_wakeup &key_volup &key_voldown>; + + key-wakeup { + label = "Wakeup"; + linux,code = ; + gpios = <&gpa0 0 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + key-volume-down { + label = "Volume Down"; + linux,code = ; + gpios = <&gpg2 0 GPIO_ACTIVE_LOW>; + }; + + key-volume-up { + label = "Volume Up"; + linux,code = ; + gpios = <&gpg1 5 GPIO_ACTIVE_LOW>; + }; + }; + ufs_0_fixed_vcc_reg: regulator-0 { compatible = "regulator-fixed"; regulator-name = "ufs-vcc"; @@ -49,6 +75,31 @@ ufs_1_fixed_vcc_reg: regulator-1 { }; }; +&pinctrl_alive { + key_wakeup: key-wakeup-pins { + samsung,pins = "gpa0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_peric1 { + key_voldown: key-voldown-pins { + samsung,pins = "gpg2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_volup: key-volup-pins { + samsung,pins = "gpg1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + &pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm_tout3>; From f740f031cce7703a966ad0279d0f15973d61df16 Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Wed, 15 Nov 2023 11:35:36 +0100 Subject: [PATCH 0609/7721] drm/test: rearrange test entries in Kconfig and Makefile Rearrange entries in Kconfig and Makefile alphabetically to make room for additional KUnit test suites. Signed-off-by: Marco Pagani Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231115103537.220760-1-marpagan@redhat.com --- drivers/gpu/drm/Kconfig | 12 ++++++------ drivers/gpu/drm/tests/Makefile | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3eee8636f847..cdbc56e07649 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -75,15 +75,15 @@ config DRM_KUNIT_TEST_HELPERS config DRM_KUNIT_TEST tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS depends on DRM && KUNIT - select PRIME_NUMBERS + select DRM_BUDDY select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER - select DRM_LIB_RANDOM - select DRM_KMS_HELPER - select DRM_BUDDY - select DRM_EXPORT_FOR_TESTS if m - select DRM_KUNIT_TEST_HELPERS select DRM_EXEC + select DRM_EXPORT_FOR_TESTS if m + select DRM_KMS_HELPER + select DRM_KUNIT_TEST_HELPERS + select DRM_LIB_RANDOM + select PRIME_NUMBERS default KUNIT_ALL_TESTS help This builds unit tests for DRM. This option is not useful for diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index ba7baa622675..2645af241ff0 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_connector_test.o \ drm_damage_helper_test.o \ drm_dp_mst_helper_test.o \ + drm_exec_test.o \ drm_format_helper_test.o \ drm_format_test.o \ drm_framebuffer_test.o \ @@ -17,7 +18,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_modes_test.o \ drm_plane_helper_test.o \ drm_probe_helper_test.o \ - drm_rect_test.o \ - drm_exec_test.o + drm_rect_test.o CFLAGS_drm_mm_test.o := $(DISABLE_STRUCTLEAK_PLUGIN) From beea67c7c2ef161c6ee7ef4e39d842fc0be3995c Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:56:05 +0900 Subject: [PATCH 0610/7721] soc: samsung: exynos-chipid: add exynosautov920 SoC support Add EXYNOSAUTOV920 information to soc_ids tables. This SoC product id is "0x0A920000". Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-10-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/exynos-chipid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 3fd0f2b84dd3..b1118d37779e 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -59,6 +59,7 @@ static const struct exynos_soc_id { { "EXYNOS7885", 0xE7885000 }, { "EXYNOS850", 0xE3830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, + { "EXYNOSAUTOV920", 0x0A920000 }, }; static const char *product_id_to_soc_id(unsigned int product_id) From 20862a23260a3ab76ea5b425f93967d0683b28a2 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:55:57 +0900 Subject: [PATCH 0611/7721] dt-bindings: samsung: exynos-sysreg: add exynosautov920 sysreg Add compatible for ExynosAutov920 sysreg controllers. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-2-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- .../bindings/soc/samsung/samsung,exynos-sysreg.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 163e912e9cad..2de4301a467d 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -50,6 +50,11 @@ properties: - samsung,exynosautov9-peric1-sysreg - const: samsung,exynosautov9-sysreg - const: syscon + - items: + - enum: + - samsung,exynosautov920-peric0-sysreg + - samsung,exynosautov920-peric1-sysreg + - const: syscon reg: maxItems: 1 From 705672285530cd513b5549f96f92b2a9fcd63017 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:55:58 +0900 Subject: [PATCH 0612/7721] dt-bindings: samsung: exynos-pmu: add exynosautov920 compatible Add samsung,exynosautov920-pmu compatible for representing pmu of ExynosAutov920 SoC. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-3-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index 6492e92586d9..28e2cb50d85e 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -52,6 +52,7 @@ properties: - enum: - samsung,exynos7885-pmu - samsung,exynosautov9-pmu + - samsung,exynosautov920-pmu - const: samsung,exynos7-pmu - const: syscon - items: From 7a5e832d05025a3679d0fcd60584e6e946a3e358 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:55:59 +0900 Subject: [PATCH 0613/7721] dt-bindings: samsung: usi: add exynosautov920-usi compatible Add samsung,exynosautov920-usi dedicated compatible for representing USI of ExynosAutoV920 SoC. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-4-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index 5b7ab69546c4..61be1f2ddbe7 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -24,7 +24,9 @@ properties: compatible: oneOf: - items: - - const: samsung,exynosautov9-usi + - enum: + - samsung,exynosautov9-usi + - samsung,exynosautov920-usi - const: samsung,exynos850-usi - enum: - samsung,exynos850-usi From 9433b8d8d35bd0b17d6e0df76ec135dd2fe63e7c Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:56:00 +0900 Subject: [PATCH 0614/7721] dt-bindings: serial: samsung: add exynosautov920-uart compatible Add samsung,exynosautov9-uart dedicated compatible for representing uart of ExynosAutov920 SoC. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-5-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 0d0215b23ab7..e32c1b462836 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -35,7 +35,9 @@ properties: - samsung,exynos7885-uart - const: samsung,exynos5433-uart - items: - - const: samsung,exynosautov9-uart + - enum: + - samsung,exynosautov9-uart + - samsung,exynosautov920-uart - const: samsung,exynos850-uart reg: From d2d9e80a0ba6b1f507c14d6d8e2b833a474744d3 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:56:01 +0900 Subject: [PATCH 0615/7721] dt-bindings: pwm: samsung: add exynosautov920 compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add samsung,exynosautov920-pwm compatible string to binding document. Signed-off-by: Jaewon Kim Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231115095609.39883-6-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/pwm/pwm-samsung.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml index 89a3875cb50a..16de6434693b 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml @@ -32,6 +32,7 @@ properties: - samsung,exynos5433-pwm - samsung,exynos7-pwm - samsung,exynosautov9-pwm + - samsung,exynosautov920-pwm - const: samsung,exynos4210-pwm reg: From 8bd05d4a86d5e1cec35dc7b8d1a5c0d925ecde1e Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:56:03 +0900 Subject: [PATCH 0616/7721] dt-bindings: arm: samsung: Document exynosautov920 SADK board binding Add binding for the ExynosAutov920 SADK(Samsung Automotive Development Kit) board. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-8-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/arm/samsung/samsung-boards.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml index e3ffd8159ab6..01dcbd8aa703 100644 --- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml @@ -230,6 +230,12 @@ properties: - samsung,exynosautov9-sadk # Samsung Exynos Auto v9 SADK - const: samsung,exynosautov9 + - description: Exynos Auto v920 based boards + items: + - enum: + - samsung,exynosautov920-sadk # Samsung Exynos Auto v920 SADK + - const: samsung,exynosautov920 + required: - compatible From 92b022550ae55527b4ce8f8cae7863857c7b795a Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 15 Nov 2023 18:56:04 +0900 Subject: [PATCH 0617/7721] dt-bindings: hwinfo: samsung,exynos-chipid: add exynosautov920 compatible Add "samsung,exynosautov920-chipid" compatible string to binding document. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231115095609.39883-9-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml index 45f3d468db7c..780ccb5ee9b4 100644 --- a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml @@ -24,6 +24,7 @@ properties: - enum: - samsung,exynos7885-chipid - samsung,exynosautov9-chipid + - samsung,exynosautov920-chipid - const: samsung,exynos850-chipid reg: From 312292a4ee19dddcbc7cf58349596b6a7e39fcd0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 2 Nov 2023 14:08:06 +0100 Subject: [PATCH 0618/7721] drm/client: Do not acquire module reference Do not acquire a reference on the module that provides a client's callback functions in drm_client_init(). The additional reference prevents the user from unloading the callback functions' module and thus creating dangling pointers. This is only necessary if there is no direct dependency between the caller of drm_client_init() and the provider of the callbacks in struct drm_client_funcs. If this case ever existed, it has been removed from the DRM code. Callers of drm_client_init() also provide the callback implementation. The lifetime of the clients is tied to the dependency chain's outer-most module, which is the hardware's DRM driver. Before client helpers could be unloaded, the driver module would have to be unloaded, which also unregisters all clients. Driver modules that set up DRM clients can now be unloaded. Signed-off-by: Thomas Zimmermann Acked-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231102131056.7256-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_client.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index c3027115d055..9403b3f576f7 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -84,16 +83,13 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create) return -EOPNOTSUPP; - if (funcs && !try_module_get(funcs->owner)) - return -ENODEV; - client->dev = dev; client->name = name; client->funcs = funcs; ret = drm_client_modeset_create(client); if (ret) - goto err_put_module; + return ret; ret = drm_client_open(client); if (ret) @@ -105,10 +101,6 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, err_free: drm_client_modeset_free(client); -err_put_module: - if (funcs) - module_put(funcs->owner); - return ret; } EXPORT_SYMBOL(drm_client_init); @@ -177,8 +169,6 @@ void drm_client_release(struct drm_client_dev *client) drm_client_modeset_free(client); drm_client_close(client); drm_dev_put(dev); - if (client->funcs) - module_put(client->funcs->owner); } EXPORT_SYMBOL(drm_client_release); From f1013d8405af0f4fe1812b5901cbac9ce4d1fb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 25 Sep 2023 11:55:31 +0200 Subject: [PATCH 0619/7721] soc/xilinx: zynqmp_power: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230925095532.1984344-41-u.kleine-koenig@pengutronix.de Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_power.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index c2c819701eec..9d27f850f491 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -275,7 +275,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev) return 0; } -static int zynqmp_pm_remove(struct platform_device *pdev) +static void zynqmp_pm_remove(struct platform_device *pdev) { sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr); if (event_registered) @@ -283,8 +283,6 @@ static int zynqmp_pm_remove(struct platform_device *pdev) if (!rx_chan) mbox_free_channel(rx_chan); - - return 0; } static const struct of_device_id pm_of_match[] = { @@ -295,7 +293,7 @@ MODULE_DEVICE_TABLE(of, pm_of_match); static struct platform_driver zynqmp_pm_platform_driver = { .probe = zynqmp_pm_probe, - .remove = zynqmp_pm_remove, + .remove_new = zynqmp_pm_remove, .driver = { .name = "zynqmp_power", .of_match_table = pm_of_match, From ef75c25e8fedbfcf07ae4223fb7cc9ea5fb342a7 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 8 Nov 2023 12:53:03 +0530 Subject: [PATCH 0620/7721] drm/i915/panelreplay: Debugfs support for panel replay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add debugfs support which will print source and sink status per connector basis. Existing i915_psr_status and i915_psr_sink_status will be used to get the source and sink status of panel replay. v1: Initial version. [rb-ed by Arun] v2: Added check for DP 2.0 and connector type in connector_debugfs_add(). v3: Optimization and cosmetic changes. [Jouni] Cc: Jouni Högander Cc: Arun R Murthy Cc: Jani Nikula Reviewed-by: Arun R Murthy Signed-off-by: Animesh Manna Reviewed-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231108072303.3414118-7-animesh.manna@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 87 +++++++++++++++++------- 1 file changed, 63 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2fc89ac5b27a..8d180132a74b 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2865,12 +2865,19 @@ static int psr_get_status_and_error_status(struct intel_dp *intel_dp, { struct drm_dp_aux *aux = &intel_dp->aux; int ret; + unsigned int offset; - ret = drm_dp_dpcd_readb(aux, DP_PSR_STATUS, status); + offset = intel_dp->psr.panel_replay_enabled ? + DP_SINK_DEVICE_PR_AND_FRAME_LOCK_STATUS : DP_PSR_STATUS; + + ret = drm_dp_dpcd_readb(aux, offset, status); if (ret != 1) return ret; - ret = drm_dp_dpcd_readb(aux, DP_PSR_ERROR_STATUS, error_status); + offset = intel_dp->psr.panel_replay_enabled ? + DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS; + + ret = drm_dp_dpcd_readb(aux, offset, error_status); if (ret != 1) return ret; @@ -3091,7 +3098,7 @@ psr_source_status(struct intel_dp *intel_dp, struct seq_file *m) status = live_status[status_val]; } - seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val); + seq_printf(m, "Source PSR/PanelReplay status: %s [0x%08x]\n", status, val); } static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) @@ -3104,18 +3111,22 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) bool enabled; u32 val; - seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support)); + seq_printf(m, "Sink support: PSR = %s", + str_yes_no(psr->sink_support)); + if (psr->sink_support) seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]); - seq_puts(m, "\n"); + seq_printf(m, ", Panel Replay = %s\n", str_yes_no(psr->sink_panel_replay_support)); - if (!psr->sink_support) + if (!(psr->sink_support || psr->sink_panel_replay_support)) return 0; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); mutex_lock(&psr->lock); - if (psr->enabled) + if (psr->panel_replay_enabled) + status = "Panel Replay Enabled"; + else if (psr->enabled) status = psr->psr2_enabled ? "PSR2 enabled" : "PSR1 enabled"; else status = "disabled"; @@ -3128,14 +3139,17 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) goto unlock; } - if (psr->psr2_enabled) { + if (psr->panel_replay_enabled) { + val = intel_de_read(dev_priv, TRANS_DP2_CTL(cpu_transcoder)); + enabled = val & TRANS_DP2_PANEL_REPLAY_ENABLE; + } else if (psr->psr2_enabled) { val = intel_de_read(dev_priv, EDP_PSR2_CTL(cpu_transcoder)); enabled = val & EDP_PSR2_ENABLE; } else { val = intel_de_read(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder)); enabled = val & EDP_PSR_ENABLE; } - seq_printf(m, "Source PSR ctl: %s [0x%08x]\n", + seq_printf(m, "Source PSR/PanelReplay ctl: %s [0x%08x]\n", str_enabled_disabled(enabled), val); psr_source_status(intel_dp, m); seq_printf(m, "Busy frontbuffer bits: 0x%08x\n", @@ -3273,6 +3287,16 @@ void intel_psr_debugfs_register(struct drm_i915_private *i915) i915, &i915_edp_psr_status_fops); } +static const char *psr_mode_str(struct intel_dp *intel_dp) +{ + if (intel_dp->psr.panel_replay_enabled) + return "PANEL-REPLAY"; + else if (intel_dp->psr.enabled) + return "PSR"; + + return "unknown"; +} + static int i915_psr_sink_status_show(struct seq_file *m, void *data) { struct intel_connector *connector = m->private; @@ -3287,12 +3311,19 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) "reserved", "sink internal error", }; + static const char * const panel_replay_status[] = { + "Sink device frame is locked to the Source device", + "Sink device is coasting, using the VTotal target", + "Sink device is governing the frame rate (frame rate unlock is granted)", + "Sink device in the process of re-locking with the Source device", + }; const char *str; int ret; u8 status, error_status; + u32 idx; - if (!CAN_PSR(intel_dp)) { - seq_puts(m, "PSR Unsupported\n"); + if (!(CAN_PSR(intel_dp) || CAN_PANEL_REPLAY(intel_dp))) { + seq_puts(m, "PSR/Panel-Replay Unsupported\n"); return -ENODEV; } @@ -3303,15 +3334,20 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) if (ret) return ret; - status &= DP_PSR_SINK_STATE_MASK; - if (status < ARRAY_SIZE(sink_status)) - str = sink_status[status]; - else - str = "unknown"; + str = "unknown"; + if (intel_dp->psr.panel_replay_enabled) { + idx = (status & DP_SINK_FRAME_LOCKED_MASK) >> DP_SINK_FRAME_LOCKED_SHIFT; + if (idx < ARRAY_SIZE(panel_replay_status)) + str = panel_replay_status[idx]; + } else if (intel_dp->psr.enabled) { + idx = status & DP_PSR_SINK_STATE_MASK; + if (idx < ARRAY_SIZE(sink_status)) + str = sink_status[idx]; + } - seq_printf(m, "Sink PSR status: 0x%x [%s]\n", status, str); + seq_printf(m, "Sink %s status: 0x%x [%s]\n", psr_mode_str(intel_dp), status, str); - seq_printf(m, "Sink PSR error status: 0x%x", error_status); + seq_printf(m, "Sink %s error status: 0x%x", psr_mode_str(intel_dp), error_status); if (error_status & (DP_PSR_RFB_STORAGE_ERROR | DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | @@ -3320,11 +3356,11 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) else seq_puts(m, "\n"); if (error_status & DP_PSR_RFB_STORAGE_ERROR) - seq_puts(m, "\tPSR RFB storage error\n"); + seq_printf(m, "\t%s RFB storage error\n", psr_mode_str(intel_dp)); if (error_status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) - seq_puts(m, "\tPSR VSC SDP uncorrectable error\n"); + seq_printf(m, "\t%s VSC SDP uncorrectable error\n", psr_mode_str(intel_dp)); if (error_status & DP_PSR_LINK_CRC_ERROR) - seq_puts(m, "\tPSR Link CRC error\n"); + seq_printf(m, "\t%s Link CRC error\n", psr_mode_str(intel_dp)); return ret; } @@ -3344,13 +3380,16 @@ void intel_psr_connector_debugfs_add(struct intel_connector *connector) struct drm_i915_private *i915 = to_i915(connector->base.dev); struct dentry *root = connector->base.debugfs_entry; - if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) - return; + if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) { + if (!(HAS_DP20(i915) && + connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort)) + return; + } debugfs_create_file("i915_psr_sink_status", 0444, root, connector, &i915_psr_sink_status_fops); - if (HAS_PSR(i915)) + if (HAS_PSR(i915) || HAS_DP20(i915)) debugfs_create_file("i915_psr_status", 0444, root, connector, &i915_psr_status_fops); } From aa4db51bbd51654e215905f384eecf22327bafa9 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:53 -0700 Subject: [PATCH 0621/7721] scsi: mpt3sas: Use flexible arrays when obviously possible These terminal 1-length variable arrays can be directly converted into C99 flexible array members without any binary changes. In most cases, they belong to unused structs, or to structs used only by unused code. The remaining few coincidentally have their sizes calculated in roundabout ways that do not depend on the sizeof() their structs. Reviewed-by: Kees Cook Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-2-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 181 ++++++++------------------ drivers/scsi/mpt3sas/mpi/mpi2_image.h | 32 ++--- drivers/scsi/mpt3sas/mpi/mpi2_ioc.h | 27 ++-- 3 files changed, 75 insertions(+), 165 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 4d0be5ab98c1..42d820159c44 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -643,18 +643,14 @@ typedef struct _MPI2_CHIP_REVISION_ID { /*Manufacturing Page 2 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check Header.PageLength at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check Header.PageLength at + *runtime before using HwSettings[]. */ -#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_2 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ - U32 - HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/*0x08 */ + U32 HwSettings[]; /*0x08 */ } MPI2_CONFIG_PAGE_MAN_2, *PTR_MPI2_CONFIG_PAGE_MAN_2, Mpi2ManufacturingPage2_t, @@ -666,18 +662,14 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_2 { /*Manufacturing Page 3 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check Header.PageLength at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check Header.PageLength at + *runtime before using Info[]. */ -#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_3 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ - U32 - Info[MPI2_MAN_PAGE_3_INFO_WORDS];/*0x08 */ + U32 Info[]; /*0x08 */ } MPI2_CONFIG_PAGE_MAN_3, *PTR_MPI2_CONFIG_PAGE_MAN_3, Mpi2ManufacturingPage3_t, @@ -765,12 +757,9 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4 { /*Manufacturing Page 5 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using Phy[]. */ -#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -#endif typedef struct _MPI2_MANUFACTURING5_ENTRY { U64 WWID; /*0x00 */ @@ -787,8 +776,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_5 { U16 Reserved2; /*0x06 */ U32 Reserved3; /*0x08 */ U32 Reserved4; /*0x0C */ - MPI2_MANUFACTURING5_ENTRY - Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/*0x08 */ + MPI2_MANUFACTURING5_ENTRY Phy[]; /*0x10 */ } MPI2_CONFIG_PAGE_MAN_5, *PTR_MPI2_CONFIG_PAGE_MAN_5, Mpi2ManufacturingPage5_t, @@ -864,12 +852,9 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { #define MPI2_MANPAGE7_SLOT_UNKNOWN (0xFFFF) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using ConnectorInfo[]. */ -#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_7 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -880,8 +865,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 { U8 NumPhys; /*0x20 */ U8 Reserved3; /*0x21 */ U16 Reserved4; /*0x22 */ - MPI2_MANPAGE7_CONNECTOR_INFO - ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /*0x24 */ + MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[]; /*0x24 */ } MPI2_CONFIG_PAGE_MAN_7, *PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, @@ -1019,12 +1003,9 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 { /*IO Unit Page 5 */ /* - *Upper layer code (drivers, utilities, etc.) should leave this define set to - *one and check the value returned for NumDmaEngines at runtime. + *Upper layer code (drivers, utilities, etc.) should check the value returned + *for NumDmaEngines at runtime before using DmaEngineCapabilities[]. */ -#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1042,7 +1023,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { U32 Reserved2; /*0x24 */ U32 Reserved3; /*0x28 */ U32 - DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /*0x2C */ + DmaEngineCapabilities[]; /*0x2C */ } MPI2_CONFIG_PAGE_IO_UNIT_5, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, Mpi2IOUnitPage5_t, *pMpi2IOUnitPage5_t; @@ -1259,12 +1240,9 @@ typedef struct _MPI2_IOUNIT9_SENSOR { #define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumSensors at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumSensors at runtime before using Sensor[]. */ -#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1273,8 +1251,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { U8 NumSensors; /*0x0C */ U8 Reserved4; /*0x0D */ U16 Reserved3; /*0x0E */ - MPI2_IOUNIT9_SENSOR - Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/*0x10 */ + MPI2_IOUNIT9_SENSOR Sensor[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_9, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, Mpi2IOUnitPage9_t, *pMpi2IOUnitPage9_t; @@ -1294,12 +1271,9 @@ typedef struct _MPI2_IOUNIT10_FUNCTION { *pMpi2IOUnit10Function_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumFunctions at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumFunctions at runtime before using Function[]. */ -#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1308,8 +1282,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { U16 Reserved2; /*0x06 */ U32 Reserved3; /*0x08 */ U32 Reserved4; /*0x0C */ - MPI2_IOUNIT10_FUNCTION - Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/*0x10 */ + MPI2_IOUNIT10_FUNCTION Function[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_10, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, Mpi2IOUnitPage10_t, *pMpi2IOUnitPage10_t; @@ -1764,12 +1737,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3 { /*BIOS Page 4 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using Phy[]. */ -#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -#endif typedef struct _MPI2_BIOS4_ENTRY { U64 ReassignmentWWID; /*0x00 */ @@ -1782,8 +1752,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_4 { U8 NumPhys; /*0x04 */ U8 Reserved1; /*0x05 */ U16 Reserved2; /*0x06 */ - MPI2_BIOS4_ENTRY - Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /*0x08 */ + MPI2_BIOS4_ENTRY Phy[]; /*0x08 */ } MPI2_CONFIG_PAGE_BIOS_4, *PTR_MPI2_CONFIG_PAGE_BIOS_4, Mpi2BiosPage4_t, *pMpi2BiosPage4_t; @@ -2045,12 +2014,9 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 { /*RAID Physical Disk Page 1 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhysDiskPaths at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhysDiskPaths at runtime before using PhysicalDiskPath[]. */ -#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -#endif typedef struct _MPI2_RAIDPHYSDISK1_PATH { U16 DevHandle; /*0x00 */ @@ -2075,8 +2041,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { U8 PhysDiskNum; /*0x05 */ U16 Reserved1; /*0x06 */ U32 Reserved2; /*0x08 */ - MPI2_RAIDPHYSDISK1_PATH - PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/*0x0C */ + MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[]; /*0x0C */ } MPI2_CONFIG_PAGE_RD_PDISK_1, *PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, Mpi2RaidPhysDiskPage1_t, @@ -2502,12 +2467,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { #define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using SASPhyPowerManagementSettings[]. */ -#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2516,7 +2478,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { U16 Reserved2;/*0x0A */ U32 Reserved3;/*0x0C */ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS - SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX];/*0x10 */ + SASPhyPowerManagementSettings[]; /*0x10 */ } MPI2_CONFIG_PAGE_SASIOUNIT_5, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, Mpi2SasIOUnitPage5_t, *pMpi2SasIOUnitPage5_t; @@ -2554,12 +2516,9 @@ typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { #define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumGroups at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumGroups at runtime before using PortWidthModulationGroupStatus[]. */ -#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2569,7 +2528,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { U8 Reserved3; /*0x11 */ U16 Reserved4; /*0x12 */ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS - PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /*0x14 */ + PortWidthModulationGroupStatus[]; /*0x14 */ } MPI2_CONFIG_PAGE_SASIOUNIT_6, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, Mpi2SasIOUnitPage6_t, *pMpi2SasIOUnitPage6_t; @@ -2597,12 +2556,9 @@ typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumGroups at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumGroups at runtime before using PortWidthModulationGroupSettings[]. */ -#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2615,7 +2571,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { U8 Reserved4; /*0x15 */ U16 Reserved5; /*0x16 */ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS - PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX];/*0x18 */ + PortWidthModulationGroupSettings[]; /*0x18 */ } MPI2_CONFIG_PAGE_SASIOUNIT_7, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, Mpi2SasIOUnitPage7_t, *pMpi2SasIOUnitPage7_t; @@ -3086,12 +3042,9 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhyEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhyEvents at runtime before using PhyEvent[]. */ -#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER @@ -3105,7 +3058,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { U16 Reserved3; /*0x0E */ MPI2_SASPHY2_PHY_EVENT - PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /*0x10 */ + PhyEvent[]; /*0x10 */ } MPI2_CONFIG_PAGE_SAS_PHY_2, *PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, Mpi2SasPhyPage2_t, @@ -3200,12 +3153,9 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { #define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhyEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhyEvents at runtime before using PhyEventConfig[]. */ -#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER @@ -3219,7 +3169,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { U16 Reserved3; /*0x0E */ MPI2_SASPHY3_PHY_EVENT_CONFIG - PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /*0x10 */ + PhyEventConfig[]; /*0x10 */ } MPI2_CONFIG_PAGE_SAS_PHY_3, *PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, Mpi2SasPhyPage3_t, *pMpi2SasPhyPage3_t; @@ -3358,12 +3308,9 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { /*Log Page 0 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLogEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLogEntries at runtime before using LogEntry[]. */ -#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -#endif #define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) @@ -3393,8 +3340,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 { U32 Reserved2; /*0x0C */ U16 NumLogEntries;/*0x10 */ U16 Reserved3; /*0x12 */ - MPI2_LOG_0_ENTRY - LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /*0x14 */ + MPI2_LOG_0_ENTRY LogEntry[]; /*0x14 */ } MPI2_CONFIG_PAGE_LOG_0, *PTR_MPI2_CONFIG_PAGE_LOG_0, Mpi2LogPage0_t, *pMpi2LogPage0_t; @@ -3408,12 +3354,9 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 { /*RAID Page 0 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumElements at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumElements at runtime before using ConfigElement[]. */ -#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -#endif typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT { U16 ElementFlags; /*0x00 */ @@ -3446,8 +3389,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 { U8 NumElements; /*0x2C */ U8 Reserved2; /*0x2D */ U16 Reserved3; /*0x2E */ - MPI2_RAIDCONFIG0_CONFIG_ELEMENT - ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /*0x30 */ + MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[];/*0x30 */ } MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, *PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, Mpi2RaidConfigurationPage0_t, @@ -3687,12 +3629,9 @@ typedef struct _MPI26_PCIE_IO_UNIT0_PHY_DATA { Mpi26PCIeIOUnit0PhyData_t, *pMpi26PCIeIOUnit0PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI26_PCIE_IOUNIT0_PHY_MAX -#define MPI26_PCIE_IOUNIT0_PHY_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -3701,7 +3640,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0 { U8 InitStatus; /*0x0D */ U16 Reserved3; /*0x0E */ MPI26_PCIE_IO_UNIT0_PHY_DATA - PhyData[MPI26_PCIE_IOUNIT0_PHY_MAX]; /*0x10 */ + PhyData[]; /*0x10 */ } MPI26_CONFIG_PAGE_PIOUNIT_0, *PTR_MPI26_CONFIG_PAGE_PIOUNIT_0, Mpi26PCIeIOUnitPage0_t, *pMpi26PCIeIOUnitPage0_t; @@ -3993,12 +3932,9 @@ typedef struct _MPI26_PCIELINK2_LINK_EVENT { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLinkEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLinkEvents at runtime before using LinkEvent[]. */ -#ifndef MPI26_PCIELINK2_LINK_EVENT_MAX -#define MPI26_PCIELINK2_LINK_EVENT_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -4009,7 +3945,7 @@ typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2 { U8 Reserved3; /*0x0D */ U16 Reserved4; /*0x0E */ MPI26_PCIELINK2_LINK_EVENT - LinkEvent[MPI26_PCIELINK2_LINK_EVENT_MAX]; /*0x10 */ + LinkEvent[]; /*0x10 */ } MPI26_CONFIG_PAGE_PCIELINK_2, *PTR_MPI26_CONFIG_PAGE_PCIELINK_2, Mpi26PcieLinkPage2_t, *pMpi26PcieLinkPage2_t; @@ -4067,12 +4003,9 @@ typedef struct _MPI26_PCIELINK3_LINK_EVENT_CONFIG { #define MPI26_PCIELINK3_TFLAGS_EVENT_NOTIFY (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLinkEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLinkEvents at runtime before using LinkEventConfig[]. */ -#ifndef MPI26_PCIELINK3_LINK_EVENT_MAX -#define MPI26_PCIELINK3_LINK_EVENT_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -4083,7 +4016,7 @@ typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3 { U8 Reserved3; /*0x0D */ U16 Reserved4; /*0x0E */ MPI26_PCIELINK3_LINK_EVENT_CONFIG - LinkEventConfig[MPI26_PCIELINK3_LINK_EVENT_MAX]; /*0x10 */ + LinkEventConfig[]; /*0x10 */ } MPI26_CONFIG_PAGE_PCIELINK_3, *PTR_MPI26_CONFIG_PAGE_PCIELINK_3, Mpi26PcieLinkPage3_t, *pMpi26PcieLinkPage3_t; diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_image.h b/drivers/scsi/mpt3sas/mpi/mpi2_image.h index 33b9c3a6fd40..798ab6e33eb9 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_image.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_image.h @@ -295,20 +295,9 @@ typedef struct _MPI2_EXT_IMAGE_HEADER { /*FLASH Layout Extended Image Data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check RegionsPerLayout at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumberOfLayouts and + *RegionsPerLayout at runtime before using Layout[] and Region[]. */ -#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -#endif - -/* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumberOfLayouts at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -#endif typedef struct _MPI2_FLASH_REGION { U8 RegionType; /*0x00 */ @@ -325,7 +314,7 @@ typedef struct _MPI2_FLASH_LAYOUT { U32 Reserved1; /*0x04 */ U32 Reserved2; /*0x08 */ U32 Reserved3; /*0x0C */ - MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS]; /*0x10 */ + MPI2_FLASH_REGION Region[]; /*0x10 */ } MPI2_FLASH_LAYOUT, *PTR_MPI2_FLASH_LAYOUT, Mpi2FlashLayout_t, *pMpi2FlashLayout_t; @@ -339,7 +328,7 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA { U16 MinimumSectorAlignment; /*0x08 */ U16 Reserved3; /*0x0A */ U32 Reserved4; /*0x0C */ - MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS]; /*0x10 */ + MPI2_FLASH_LAYOUT Layout[]; /*0x10 */ } MPI2_FLASH_LAYOUT_DATA, *PTR_MPI2_FLASH_LAYOUT_DATA, Mpi2FlashLayoutData_t, *pMpi2FlashLayoutData_t; @@ -373,12 +362,9 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA { /*Supported Devices Extended Image Data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumberOfDevices at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumberOfDevices at + *runtime before using SupportedDevice[]. */ -#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -#endif typedef struct _MPI2_SUPPORTED_DEVICE { U16 DeviceID; /*0x00 */ @@ -399,7 +385,7 @@ typedef struct _MPI2_SUPPORTED_DEVICES_DATA { U8 Reserved2; /*0x03 */ U32 Reserved3; /*0x04 */ MPI2_SUPPORTED_DEVICE - SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES];/*0x08 */ + SupportedDevice[]; /*0x08 */ } MPI2_SUPPORTED_DEVICES_DATA, *PTR_MPI2_SUPPORTED_DEVICES_DATA, Mpi2SupportedDevicesData_t, *pMpi2SupportedDevicesData_t; @@ -464,7 +450,7 @@ typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { U8 EncryptionAlgorithm; /*0x02 */ U8 Reserved1; /*0x03 */ U32 Reserved2; /*0x04 */ - U32 EncryptedHash[1]; /*0x08 */ /* variable length */ + U32 EncryptedHash[]; /*0x08 */ } MPI25_ENCRYPTED_HASH_ENTRY, *PTR_MPI25_ENCRYPTED_HASH_ENTRY, Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; @@ -508,7 +494,7 @@ typedef struct _MPI25_ENCRYPTED_HASH_DATA { U8 NumHash; /*0x01 */ U16 Reserved1; /*0x02 */ U32 Reserved2; /*0x04 */ - MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /*0x08 */ + MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[]; /*0x08 */ } MPI25_ENCRYPTED_HASH_DATA, *PTR_MPI25_ENCRYPTED_HASH_DATA, Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t; diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index 2c57115172cf..d92852591134 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -808,12 +808,9 @@ typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK { /*Integrated RAID Configuration Change List Event data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumElements at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumElements at + *runtime before using ConfigElement[]. */ -#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -#endif typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT { U16 ElementFlags; /*0x00 */ @@ -848,7 +845,7 @@ typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST { U8 ConfigNum; /*0x03 */ U32 Flags; /*0x04 */ MPI2_EVENT_IR_CONFIG_ELEMENT - ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];/*0x08 */ + ConfigElement[];/*0x08 */ } MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, *PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, Mpi2EventDataIrConfigChangeList_t, @@ -969,12 +966,9 @@ typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW { /*SAS Topology Change List Event data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumEntries at + *runtime before using PHY[]. */ -#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -#endif typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY { U16 AttachedDevHandle; /*0x00 */ @@ -994,7 +988,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST { U8 ExpStatus; /*0x0A */ U8 PhysicalPort; /*0x0B */ MPI2_EVENT_SAS_TOPO_PHY_ENTRY - PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /*0x0C */ + PHY[]; /*0x0C */ } MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, *PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, Mpi2EventDataSasTopologyChangeList_t, @@ -1229,12 +1223,9 @@ typedef struct _MPI26_EVENT_DATA_PCIE_ENUMERATION { /*PCIe Topology Change List Event data (MPI v2.6 and later) */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumEntries at + *runtime before using PortEntry[]. */ -#ifndef MPI26_EVENT_PCIE_TOPO_PORT_COUNT -#define MPI26_EVENT_PCIE_TOPO_PORT_COUNT (1) -#endif typedef struct _MPI26_EVENT_PCIE_TOPO_PORT_ENTRY { U16 AttachedDevHandle; /*0x00 */ @@ -1286,7 +1277,7 @@ typedef struct _MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST { U8 SwitchStatus; /*0x0A */ U8 PhysicalPort; /*0x0B */ MPI26_EVENT_PCIE_TOPO_PORT_ENTRY - PortEntry[MPI26_EVENT_PCIE_TOPO_PORT_COUNT]; /*0x0C */ + PortEntry[]; /*0x0C */ } MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, *PTR_MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, Mpi26EventDataPCIeTopologyChangeList_t, From f7830af68eb66d1db193129918036eb98708e6a5 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:54 -0700 Subject: [PATCH 0622/7721] scsi: mpt3sas: Make MPI2_CONFIG_PAGE_IO_UNIT_8::Sensor[] a flexible array This terminal 1-length variable array can be directly converted into a C99 flexible array member. As all users of MPI2_CONFIG_PAGE_IO_UNIT_8 (Mpi2IOUnitPage8_t) do not use Sensor[], no further source changes are required to accommodate its reduced sizeof(): - mpt3sas_config.c:mpt3sas_config_get_iounit_pg8() fetches a Mpi2IOUnitPage8_t into a caller-provided buffer, assuming sizeof(Mpi2IOUnitPage8_t) as the buffer size. It has one caller: - mpt3sas_base.c:_base_static_config_pages() passes the address of the Mpi2IOUnitPage8_t iounit_pg8 member of the per-adapter struct (struct MPT3SAS_ADAPTER *ioc) as the buffer. The assumed buffer size is therefore correct. However, the only subsequent use in mpt3sas of the thus populated ioc->iounit_pg8 is a little further on in the same function, and this use does not involve ioc->iounit_pg8.Sensor[]. Note that iounit_pg8 occurs in the middle of the per-adapter struct, not at the end. The per-adapter struct is extensively used throughout mpt3sas even if its iounit_pg8 member isn't, resulting in an especially large amount of noise when comparing binary changes attributable to this commit. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-3-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 42d820159c44..12b656bd883d 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -1200,12 +1200,9 @@ typedef struct _MPI2_IOUNIT8_SENSOR { #define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumSensors at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumSensors at runtime before using Sensor[]. */ -#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1214,8 +1211,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { U8 NumSensors; /*0x0C */ U8 PollingInterval; /*0x0D */ U16 Reserved3; /*0x0E */ - MPI2_IOUNIT8_SENSOR - Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/*0x10 */ + MPI2_IOUNIT8_SENSOR Sensor[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_8, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, Mpi2IOUnitPage8_t, *pMpi2IOUnitPage8_t; From cb7c03c5d3574f9edfcb17d207d56500690ac0ad Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:55 -0700 Subject: [PATCH 0623/7721] scsi: mpt3sas: Make MPI2_CONFIG_PAGE_RAID_VOL_0::PhysDisk[] a flexible array This terminal 1-length variable array can be directly converted into a C99 flexible array member. As all users of MPI2_CONFIG_PAGE_RAID_VOL_0 (Mpi2RaidVolPage0_t) either calculate its size without depending on its sizeof() or do not use PhysDisk[], no further source changes are required: - mpt3sas_config.c:mpt3sas_config_get_number_pds() fetches a Mpi2RaidVolPage0_t for itself, but does not use PhysDisk[]. - mpt3sas_config.c:mpt3sas_config_get_raid_volume_pg0() fetches a Mpi2RaidVolPage0_t into a caller-provided buffer, and may fetch and write PhysDisk[] into that buffer depending on its sz argument. Its callers: - mpt3sas_scsih.c:scsih_get_resync(), mpt3sas_scsih.c:scsih_get_state(), mpt3sas_scsih.c:_scsih_search_responding_raid_devices(), and mpt3sas_scsih.c:_scsih_scan_for_devices_after_reset() all pass sizeof(Mpi2RaidVolPage0_t) as sz, but do not use PhysDisk[]. - mpt3sas_scsih.c:_scsih_get_volume_capabilities() and mpt3sas_warpdrive.c:mpt3sas_init_warpdrive_properties() both calculate sz independently of sizeof(Mpi2RaidVolPage0_t) and allocate a suitable buffer before calling mpt3sas_config_get_raid_volume_pg0() and using PhysDisk[]. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-4-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 12b656bd883d..55abfc00301e 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -1801,12 +1801,9 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS { #define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhysDisks at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhysDisks at runtime before using PhysDisk[]. */ -#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1826,8 +1823,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { U8 Reserved2; /*0x25 */ U8 Reserved3; /*0x26 */ U8 InactiveStatus; /*0x27 */ - MPI2_RAIDVOL0_PHYS_DISK - PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /*0x28 */ + MPI2_RAIDVOL0_PHYS_DISK PhysDisk[]; /*0x28 */ } MPI2_CONFIG_PAGE_RAID_VOL_0, *PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, Mpi2RaidVolPage0_t, *pMpi2RaidVolPage0_t; From dccc1e3ed9e3c613fa9f4b335d12cab89e2273c1 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:56 -0700 Subject: [PATCH 0624/7721] scsi: mpt3sas: Make MPI2_CONFIG_PAGE_SASIOUNIT_0::PhyData[] a flexible array This terminal 1-length variable array can be directly converted into a C99 flexible array member. As all users of MPI2_CONFIG_PAGE_SASIOUNIT_0 (Mpi2SasIOUnitPage0_t) either calculate its size without depending on its sizeof() or do not use PhyData[], no further source changes are required: - mpt3sas_config.c:mpt3sas_config_get_number_hba_phys() fetches a Mpi2SasIOUnitPage0_t for itself, but does not use PhyData[]. - mpt3sas_config.c:mpt3sas_config_get_sas_iounit_pg0() fetches a Mpi2SasIOUnitPage0_t into a caller-provided buffer, and may fetch and write PhyData[] into that buffer depending on its sz argument. Its callers: - mpt3sas_scsih.c:_scsih_update_vphys_after_reset(), mpt3sas_scsih.c:_scsih_get_port_table_after_reset(), mpt3sas_scsih.c:_scsih_sas_host_refresh(), mpt3sas_scsih.c:_scsih_sas_host_add(), and mpt3sas_transport.c:_transport_phy_enable() all calculate sz independently of sizeof(Mpi2SasIOUnitPage0_t) and allocate a suitable buffer before calling mpt3sas_config_get_sas_iounit_pg0() and using PhyData[]. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-5-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 55abfc00301e..07a8d7646b6d 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -2178,12 +2178,9 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA { *pMpi2SasIOUnit0PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2191,8 +2188,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { U8 NumPhys; /*0x0C */ U8 Reserved2;/*0x0D */ U16 Reserved3;/*0x0E */ - MPI2_SAS_IO_UNIT0_PHY_DATA - PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /*0x10 */ + MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[];/*0x10 */ } MPI2_CONFIG_PAGE_SASIOUNIT_0, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, Mpi2SasIOUnitPage0_t, *pMpi2SasIOUnitPage0_t; From e249a957ce43b7da365ea0bddbeaec04e4cc3ad0 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:57 -0700 Subject: [PATCH 0625/7721] scsi: mpt3sas: Make MPI2_CONFIG_PAGE_SASIOUNIT_1::PhyData[] a flexible array This terminal 1-length variable array can be directly converted into a C99 flexible array member. As all users of MPI2_CONFIG_PAGE_SASIOUNIT_1 (Mpi2SasIOUnitPage1_t) either calculate its size without depending on its sizeof() or do not use PhyData[], no further source changes are required: - mpt3sas_config.c:mpt3sas_config_get_sas_iounit_pg1() fetches a Mpi2SasIOUnitPage1_t into a caller-provided buffer, and may fetch and write PhyData[] into that buffer depending on its sz argument. Its callers: - mpt3sas_base.c:_base_assign_fw_reported_qd() passes sizeof(Mpi2SasIOUnitPage1_t) as sz, but does not use PhyData[]. - mpt3sas_base.c:mpt3sas_base_update_missing_delay(), mpt3sas_scsih.c:_scsih_sas_host_add(), mpt3sas_transport.c:_transport_phy_enable(), and mpt3sas_transport.c:_transport_phy_speed() all calculate sz independently of sizeof(Mpi2SasIOUnitPage1_t) and allocate a suitable buffer before calling mpt3sas_config_get_sas_iounit_pg1() and using PhyData[]. - mpt3sas_config.c:mpt3sas_config_set_sas_iounit_pg1() writes the contents of a caller-provided buffer to the adapter, with the size of the write depending on its sz argument. Its callers: - mpt3sas_base.c:mpt3sas_base_update_missing_delay(), mpt3sas_transport.c:_transport_phy_enable(), and mpt3sas_transport.c:_transport_phy_speed() have all previously called mpt3sas_config_get_sas_iounit_pg1() to obtain a Mpi2SasIOUnitPage1_t, and are merely writing back this same struct with the same previously calculated sz. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-6-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 07a8d7646b6d..138f31def81d 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -2249,12 +2249,9 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA { *pMpi2SasIOUnit1PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2275,7 +2272,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { U8 IODeviceMissingDelay; /*0x13 */ MPI2_SAS_IO_UNIT1_PHY_DATA - PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /*0x14 */ + PhyData[]; /*0x14 */ } MPI2_CONFIG_PAGE_SASIOUNIT_1, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, Mpi2SasIOUnitPage1_t, *pMpi2SasIOUnitPage1_t; From 1f1126609969496bec23c366f83d843db6d7854c Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:58 -0700 Subject: [PATCH 0626/7721] scsi: mpt3sas: Make MPI26_CONFIG_PAGE_PIOUNIT_1::PhyData[] a flexible array This terminal 1-length variable array can be directly converted into a C99 flexible array member. As all users of MPI26_CONFIG_PAGE_PIOUNIT_1 (Mpi26PCIeIOUnitPage1_t) do not use PhyData[], no further source changes are required to accommodate its reduced sizeof(): - mpt3sas_config.c:mpt3sas_config_get_pcie_iounit_pg1() fetches a Mpi26PCIeIOUnitPage1_t into a caller-provided buffer, and may fetch and write PhyData[] into that buffer depending on its sz argument. It has one caller: - mpt3sas_base.c:_base_assign_fw_reported_qd() passes sizeof(Mpi26PCIeIOUnitPage1_t) as sz, but does not use PhyData[]. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-7-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 138f31def81d..84b167d49e34 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -3668,12 +3668,9 @@ typedef struct _MPI26_PCIE_IO_UNIT1_PHY_DATA { #define MPI26_PCIEIOUNIT1_LINKFLAGS_SRNS_EN (0x02) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI26_PCIE_IOUNIT1_PHY_MAX -#define MPI26_PCIE_IOUNIT1_PHY_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -3685,7 +3682,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { U8 DMDReportPCIe; /*0x11 */ U16 Reserved2; /*0x12 */ MPI26_PCIE_IO_UNIT1_PHY_DATA - PhyData[MPI26_PCIE_IOUNIT1_PHY_MAX];/*0x14 */ + PhyData[]; /*0x14 */ } MPI26_CONFIG_PAGE_PIOUNIT_1, *PTR_MPI26_CONFIG_PAGE_PIOUNIT_1, Mpi26PCIeIOUnitPage1_t, *pMpi26PCIeIOUnitPage1_t; From f4f76e141769d7be10d801706858e89cf299c250 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:05:59 -0700 Subject: [PATCH 0627/7721] scsi: mpt3sas: Use struct_size() for struct size calculations After converting terminal variable arrays into flexible array members, use the bounds-checking struct_size() helper when possible to avoid open-coded arithmetic struct size calculations. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-8-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 3 +-- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 18 ++++++------------ drivers/scsi/mpt3sas/mpt3sas_transport.c | 9 +++------ drivers/scsi/mpt3sas/mpt3sas_warpdrive.c | 3 +-- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index a75f670bf551..bee1e2727a4c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4893,8 +4893,7 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, if (!num_phys) return; - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 605013d3ee83..0a720ce1383a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2431,8 +2431,7 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, } raid_device->num_pds = num_pds; - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); + sz = struct_size(vol_pg0, PhysDisk, num_pds); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { dfailprintk(ioc, @@ -5966,8 +5965,7 @@ _scsih_update_vphys_after_reset(struct MPT3SAS_ADAPTER *ioc) /* * Read SASIOUnitPage0 to get each HBA Phy's data. */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + - (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6145,8 +6143,7 @@ _scsih_get_port_table_after_reset(struct MPT3SAS_ADAPTER *ioc, u64 attached_sas_addr; u8 found = 0, port_count = 0, port_id; - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6579,8 +6576,7 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "updating handles for sas_host(0x%016llx)\n", (u64)ioc->sas_hba.sas_address)); - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6731,8 +6727,7 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) ioc->sas_hba.num_phys = num_phys; /* sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6754,8 +6749,7 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) } /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index e8a4750f6ec4..421ea511b664 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1792,8 +1792,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable) /* handle hba phys */ /* read sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -1833,8 +1832,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable) } /* read sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -1944,8 +1942,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) /* handle hba phys */ /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c index cc07ba41f507..1d64e5056a8a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -141,8 +141,7 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, return; } - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); + sz = struct_size(vol_pg0, PhysDisk, num_pds); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { ioc_info(ioc, "WarpDrive : Direct IO is disabled Memory allocation failure for RVPG0\n"); From 66f2a53fc620d2db7099f85fbe6c0af061d6f63f Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:06:00 -0700 Subject: [PATCH 0628/7721] scsi: mpt3sas: Remove the iounit_pg8 member of the per-adapter struct The per-adapter struct (struct MPT3SAS_ADAPTER) contains a MPI2_CONFIG_PAGE_IO_UNIT_8 (Mpi2IOUnitPage8_t) iounit_pg8 member that is populated by mpt3sas_base.c:_base_static_config_pages(). As the name of that function indicates, the iounit_pg8 member represents a static configuration page data structure that rarely changes, and is among several such static config pages that are currently being fetched once per adapter per init (or reset) and copied to the per-adapter struct for later use. However, unlike the other static config pages, the iounit_pg8 member is never actually used outside of _base_static_config_pages(). Also, Mpi2IOUnitPage8_t has a flexible array member, making its presence in the _middle_ of the per-adapter struct rather strange. Remove this member from the per-adapter struct and fix up the portion of _base_static_config_pages() that uses it. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-9-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 7 ++++--- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 -- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index bee1e2727a4c..8c38d6884d88 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5587,6 +5587,7 @@ mpt3sas_atto_init(struct MPT3SAS_ADAPTER *ioc) static int _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) { + Mpi2IOUnitPage8_t iounit_pg8; Mpi2ConfigReply_t mpi_reply; u32 iounit_pg1_flags; int tg_flags = 0; @@ -5683,7 +5684,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) rc = mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); if (rc) return rc; - rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); + rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &iounit_pg8); if (rc) return rc; _base_display_ioc_capabilities(ioc); @@ -5705,8 +5706,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) if (rc) return rc; - if (ioc->iounit_pg8.NumSensors) - ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; + if (iounit_pg8.NumSensors) + ioc->temp_sensors_count = iounit_pg8.NumSensors; if (ioc->is_aero_ioc) { rc = _base_update_ioc_page1_inlinewith_perf_mode(ioc); if (rc) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 1be0850ca17a..c672f3a1c67d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1237,7 +1237,6 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @ioc_pg8: static ioc page 8 * @iounit_pg0: static iounit page 0 * @iounit_pg1: static iounit page 1 - * @iounit_pg8: static iounit page 8 * @sas_hba: sas host object * @sas_expander_list: expander object list * @enclosure_list: enclosure object list @@ -1465,7 +1464,6 @@ struct MPT3SAS_ADAPTER { Mpi2IOCPage8_t ioc_pg8; Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; - Mpi2IOUnitPage8_t iounit_pg8; Mpi2IOCPage1_t ioc_pg1_copy; struct _boot_device req_boot_device; From 8a3db51e01d57786dcab8b9d70b3d1287d95245a Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:06:01 -0700 Subject: [PATCH 0629/7721] scsi: mpt3sas: Fix an outdated comment May reduce confusion for users of MPI2_CONFIG_PAGE_IO_UNIT_3::GPIOVal[]. Fixes: a1c4d7741323 ("scsi: mpt3sas: Replace unnecessary dynamic allocation with a static one") Reviewed-by: Kees Cook Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-10-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 84b167d49e34..587f7d248219 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -974,7 +974,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 { /* *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for GPIOCount at runtime. + *36 and check the value returned for GPIOCount at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (36) From e5035459d302f4073546eed2bbd6ab55cfdfbcc8 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:06:02 -0700 Subject: [PATCH 0630/7721] scsi: mpt3sas: Fix typo of "TRIGGER" Change "TIGGER" to "TRIGGER" in struct names and typedefs. Reviewed-by: Kees Cook Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-11-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 6 +-- drivers/scsi/mpt3sas/mpt3sas_config.c | 6 +-- drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h | 44 ++++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8c38d6884d88..f83f9297e9fb 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5043,7 +5043,7 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage2_t trigger_pg2; struct SL_WH_EVENT_TRIGGER_T *event_tg; - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg; + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY *mpi_event_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; @@ -5095,7 +5095,7 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage3_t trigger_pg3; struct SL_WH_SCSI_TRIGGER_T *scsi_tg; - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg; + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY *mpi_scsi_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; @@ -5147,7 +5147,7 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage4_t trigger_pg4; struct SL_WH_MPI_TRIGGER_T *status_tg; - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg; + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY *mpi_status_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index d114ef381c44..2e88f456fc34 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -2334,7 +2334,7 @@ mpt3sas_config_update_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, tg_pg2.NumMPIEventTrigger = 0; memset(&tg_pg2.MPIEventTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY)); + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg2(ioc, &mpi_reply, &tg_pg2); @@ -2493,7 +2493,7 @@ mpt3sas_config_update_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, tg_pg3.NumSCSISenseTrigger = 0; memset(&tg_pg3.SCSISenseTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY)); + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg3(ioc, &mpi_reply, &tg_pg3); @@ -2649,7 +2649,7 @@ mpt3sas_config_update_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, tg_pg4.NumIOCStatusLogInfoTrigger = 0; memset(&tg_pg4.IOCStatusLoginfoTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY)); + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg4(ioc, &mpi_reply, &tg_pg4); diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h index 5f3328f011a2..edb8fe709089 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h @@ -20,12 +20,12 @@ #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER (0xE0) #define MPI26_DRIVER_TRIGGER_PAGE0_PAGEVERSION (0x01) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 TriggerFlags; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ U32 Reserved0xC[61]; /* 0x0C */ -} _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0, Mpi26DriverTriggerPage0_t; +} _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_0, Mpi26DriverTriggerPage0_t; /* Trigger Flags */ #define MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID (0x0001) @@ -34,61 +34,61 @@ typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0 { #define MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID (0x0008) #define MPI26_DRIVER_TRIGGER_PAGE1_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_MASTER_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_MASTER_TRIGGER_ENTRY { U32 MasterTriggerFlags; -} MPI26_DRIVER_MASTER_TIGGER_ENTRY; +} MPI26_DRIVER_MASTER_TRIGGER_ENTRY; #define MPI26_MAX_MASTER_TRIGGERS (1) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_1 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumMasterTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_MASTER_TIGGER_ENTRY MasterTriggers[MPI26_MAX_MASTER_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_1, Mpi26DriverTriggerPage1_t; + MPI26_DRIVER_MASTER_TRIGGER_ENTRY MasterTriggers[MPI26_MAX_MASTER_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_1, Mpi26DriverTriggerPage1_t; #define MPI26_DRIVER_TRIGGER_PAGE2_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY { U16 MPIEventCode; /* 0x00 */ U16 MPIEventCodeSpecific; /* 0x02 */ -} MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY; +} MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY; #define MPI26_MAX_MPI_EVENT_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_2 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumMPIEventTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY MPIEventTriggers[MPI26_MAX_MPI_EVENT_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_2, Mpi26DriverTriggerPage2_t; + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY MPIEventTriggers[MPI26_MAX_MPI_EVENT_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_2, Mpi26DriverTriggerPage2_t; #define MPI26_DRIVER_TRIGGER_PAGE3_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY { U8 ASCQ; /* 0x00 */ U8 ASC; /* 0x01 */ U8 SenseKey; /* 0x02 */ U8 Reserved; /* 0x03 */ -} MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY; +} MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY; #define MPI26_MAX_SCSI_SENSE_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_3 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumSCSISenseTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY SCSISenseTriggers[MPI26_MAX_SCSI_SENSE_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_3, Mpi26DriverTriggerPage3_t; + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY SCSISenseTriggers[MPI26_MAX_SCSI_SENSE_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_3, Mpi26DriverTriggerPage3_t; #define MPI26_DRIVER_TRIGGER_PAGE4_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY { U16 IOCStatus; /* 0x00 */ U16 Reserved; /* 0x02 */ U32 LogInfo; /* 0x04 */ -} MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY; +} MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY; #define MPI26_MAX_LOGINFO_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_4 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_4 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumIOCStatusLogInfoTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY IOCStatusLoginfoTriggers[MPI26_MAX_LOGINFO_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_4, Mpi26DriverTriggerPage4_t; + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY IOCStatusLoginfoTriggers[MPI26_MAX_LOGINFO_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_4, Mpi26DriverTriggerPage4_t; #endif From dde41e0c1cc2f81bfb5e4fc86ad66c2234c1878c Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:06:03 -0700 Subject: [PATCH 0631/7721] scsi: mpt3sas: Replace a dynamic allocation with a local variable mpt3sas_base.c:_base_update_diag_trigger_pages() allocates and fetches a MPI2_CONFIG_PAGE_SASIOUNIT_1 struct (Mpi2SasIOUnitPage_t), but does not include the terminal flexible array member in the struct size calculation, fetch that member, or otherwise use that member in any way. This dynamic allocation can be replaced with a local variable. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-12-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index f83f9297e9fb..8761bc58d965 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5378,10 +5378,9 @@ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc) static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) { Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasIOUnitPage1_t sas_iounit_pg1; Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1; u16 depth; - int sz; int rc = 0; ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH; @@ -5391,28 +5390,21 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) if (!ioc->is_gen35_ioc) goto out; /* sas iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData); - sas_iounit_pg1 = kzalloc(sizeof(Mpi2SasIOUnitPage1_t), GFP_KERNEL); - if (!sas_iounit_pg1) { - pr_err("%s: failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return rc; - } rc = mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz); + &sas_iounit_pg1, sizeof(Mpi2SasIOUnitPage1_t)); if (rc) { pr_err("%s: failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); goto out; } - depth = le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth); + depth = le16_to_cpu(sas_iounit_pg1.SASWideMaxQueueDepth); ioc->max_wideport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); - depth = le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth); + depth = le16_to_cpu(sas_iounit_pg1.SASNarrowMaxQueueDepth); ioc->max_narrowport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); - depth = sas_iounit_pg1->SATAMaxQDepth; + depth = sas_iounit_pg1.SATAMaxQDepth; ioc->max_sata_qd = (depth ? depth : MPT3SAS_SATA_QUEUE_DEPTH); /* pcie iounit page 1 */ @@ -5431,7 +5423,6 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) "MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n", ioc->max_wideport_qd, ioc->max_narrowport_qd, ioc->max_sata_qd, ioc->max_nvme_qd)); - kfree(sas_iounit_pg1); return rc; } From e188215562727972cb49681b6ea56936455cf66e Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 6 Aug 2023 10:06:04 -0700 Subject: [PATCH 0632/7721] scsi: mpt3sas: Replace dynamic allocations with local variables mpt3sas_scsih.c:_scsih_scan_for_devices_after_reset() allocates and fetches a MPI2_CONFIG_PAGE_RAID_VOL_0 struct (Mpi2RaidVolPage0_t) and a MPI2_CONFIG_PAGE_RAID_VOL_1 struct (Mpi2RaidVolPage1_t), but does not include the terminal flexible array members in the struct size calculations, fetch those members, or otherwise use those members in any way. These dynamic allocations can be replaced with local variables. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230806170604.16143-13-james@equiv.tech Tested-by: Borislav Petkov (AMD) Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 37 +++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 0a720ce1383a..5037e24596d8 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -10370,8 +10370,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) Mpi2ExpanderPage0_t expander_pg0; Mpi2SasDevicePage0_t sas_device_pg0; Mpi26PCIeDevicePage0_t pcie_device_pg0; - Mpi2RaidVolPage1_t *volume_pg1; - Mpi2RaidVolPage0_t *volume_pg0; + Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidVolPage0_t volume_pg0; Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2EventIrConfigElement_t element; Mpi2ConfigReply_t mpi_reply; @@ -10386,16 +10386,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) u8 retry_count; unsigned long flags; - volume_pg0 = kzalloc(sizeof(*volume_pg0), GFP_KERNEL); - if (!volume_pg0) - return; - - volume_pg1 = kzalloc(sizeof(*volume_pg1), GFP_KERNEL); - if (!volume_pg1) { - kfree(volume_pg0); - return; - } - ioc_info(ioc, "scan devices: start\n"); _scsih_sas_host_refresh(ioc); @@ -10505,7 +10495,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) /* volumes */ handle = 0xFFFF; while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { @@ -10513,15 +10503,15 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } - handle = le16_to_cpu(volume_pg1->DevHandle); + handle = le16_to_cpu(volume_pg1.DevHandle); spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_wwid(ioc, - le64_to_cpu(volume_pg1->WWID)); + le64_to_cpu(volume_pg1.WWID)); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (raid_device) continue; if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, + &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) continue; ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & @@ -10531,17 +10521,17 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } - if (volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { + if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; - element.VolDevHandle = volume_pg1->DevHandle; + element.VolDevHandle = volume_pg1.DevHandle; ioc_info(ioc, "\tBEFORE adding volume: handle (0x%04x)\n", - volume_pg1->DevHandle); + volume_pg1.DevHandle); _scsih_sas_volume_add(ioc, &element); ioc_info(ioc, "\tAFTER adding volume: handle (0x%04x)\n", - volume_pg1->DevHandle); + volume_pg1.DevHandle); } } @@ -10630,9 +10620,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); } - kfree(volume_pg0); - kfree(volume_pg1); - ioc_info(ioc, "\tpcie devices: pcie end devices complete\n"); ioc_info(ioc, "scan devices: complete\n"); } From b9a85e5eec126d6ae6c362f94b447c223e8fe6e4 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 13 Nov 2023 11:28:02 +0200 Subject: [PATCH 0633/7721] RDMA/usnic: Silence uninitialized symbol smatch warnings The patch 1da177e4c3f4: "Linux-2.6.12-rc2" from Apr 16, 2005 (linux-next), leads to the following Smatch static checker warning: drivers/infiniband/hw/mthca/mthca_cmd.c:644 mthca_SYS_EN() error: uninitialized symbol 'out'. drivers/infiniband/hw/mthca/mthca_cmd.c 636 int mthca_SYS_EN(struct mthca_dev *dev) 637 { 638 u64 out; 639 int ret; 640 641 ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D); We pass out here and it gets used without being initialized. err = mthca_cmd_post(dev, in_param, out_param ? *out_param : 0, ^^^^^^^^^^ in_modifier, op_modifier, op, context->token, 1); It's the same in mthca_cmd_wait() and mthca_cmd_poll(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/533bc3df-8078-4397-b93d-d1f6cec9b636@moroto.mountain Link: https://lore.kernel.org/r/c559cb7113158c02d75401ac162652072ef1b5f0.1699867650.git.leon@kernel.org Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mthca/mthca_cmd.c | 4 ++-- drivers/infiniband/hw/mthca/mthca_main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f330ce895d88..8fe0cef7e2be 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -635,7 +635,7 @@ void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox) int mthca_SYS_EN(struct mthca_dev *dev) { - u64 out; + u64 out = 0; int ret; ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D); @@ -1955,7 +1955,7 @@ int mthca_WRITE_MGM(struct mthca_dev *dev, int index, int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox, u16 *hash) { - u64 imm; + u64 imm = 0; int err; err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH, diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index b54bc8865dae..1ab268b77096 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -382,7 +382,7 @@ static int mthca_init_icm(struct mthca_dev *mdev, struct mthca_init_hca_param *init_hca, u64 icm_size) { - u64 aux_pages; + u64 aux_pages = 0; int err; err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages); From 3a179fe34acbd55eb287377811b05fbeb749e52c Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:10 +0800 Subject: [PATCH 0634/7721] RDMA/siw: Introduce siw_get_page Add the wrapper function to get either pbl page or umem page. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-2-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_tx.c | 31 +++++++++++---------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 64c113dc8a99..86186cd3cca4 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -34,6 +34,15 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx) return NULL; } +static struct page *siw_get_page(struct siw_mem *mem, struct siw_sge *sge, + unsigned long offset, int *pbl_idx) +{ + if (!mem->is_pbl) + return siw_get_upage(mem->umem, sge->laddr + offset); + else + return siw_get_pblpage(mem, sge->laddr + offset, pbl_idx); +} + /* * Copy short payload at provided destination payload address */ @@ -67,11 +76,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr) char *buffer; int pbl_idx = 0; - if (!mem->is_pbl) - p = siw_get_upage(mem->umem, sge->laddr); - else - p = siw_get_pblpage(mem, sge->laddr, &pbl_idx); - + p = siw_get_page(mem, sge, 0, &pbl_idx); if (unlikely(!p)) return -EFAULT; @@ -85,13 +90,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr) memcpy(paddr, buffer + off, part); kunmap_local(buffer); - if (!mem->is_pbl) - p = siw_get_upage(mem->umem, - sge->laddr + part); - else - p = siw_get_pblpage(mem, - sge->laddr + part, - &pbl_idx); + p = siw_get_page(mem, sge, part, &pbl_idx); if (unlikely(!p)) return -EFAULT; @@ -498,13 +497,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s) if (!is_kva) { struct page *p; - if (mem->is_pbl) - p = siw_get_pblpage( - mem, sge->laddr + sge_off, - &pbl_idx); - else - p = siw_get_upage(mem->umem, - sge->laddr + sge_off); + p = siw_get_page(mem, sge, sge_off, &pbl_idx); if (unlikely(!p)) { siw_unmap_pages(iov, kmap_mask, seg); wqe->processed -= c_tx->bytes_unsent; From a2b64565e8ea9530cce8e1c528f53ca888c0a45b Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:11 +0800 Subject: [PATCH 0635/7721] RDMA/siw: Introduce siw_update_skb_rcvd There are some places share the same logic, factor a common helper for it. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-3-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_rx.c | 31 +++++++++++---------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c index 33e0fdb362ff..10805a7d0487 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -881,6 +881,13 @@ int siw_proc_rresp(struct siw_qp *qp) return rv; } +static void siw_update_skb_rcvd(struct siw_rx_stream *srx, u16 length) +{ + srx->skb_offset += length; + srx->skb_new -= length; + srx->skb_copied += length; +} + int siw_proc_terminate(struct siw_qp *qp) { struct siw_rx_stream *srx = &qp->rx_stream; @@ -925,9 +932,7 @@ int siw_proc_terminate(struct siw_qp *qp) goto out; infop += to_copy; - srx->skb_offset += to_copy; - srx->skb_new -= to_copy; - srx->skb_copied += to_copy; + siw_update_skb_rcvd(srx, to_copy); srx->fpdu_part_rcvd += to_copy; srx->fpdu_part_rem -= to_copy; @@ -949,9 +954,7 @@ int siw_proc_terminate(struct siw_qp *qp) term->flag_m ? "valid" : "invalid"); } out: - srx->skb_new -= to_copy; - srx->skb_offset += to_copy; - srx->skb_copied += to_copy; + siw_update_skb_rcvd(srx, to_copy); srx->fpdu_part_rcvd += to_copy; srx->fpdu_part_rem -= to_copy; @@ -970,9 +973,7 @@ static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx) skb_copy_bits(skb, srx->skb_offset, tbuf, avail); - srx->skb_new -= avail; - srx->skb_offset += avail; - srx->skb_copied += avail; + siw_update_skb_rcvd(srx, avail); srx->fpdu_part_rem -= avail; if (srx->fpdu_part_rem) @@ -1023,12 +1024,8 @@ static int siw_get_hdr(struct siw_rx_stream *srx) skb_copy_bits(skb, srx->skb_offset, (char *)c_hdr + srx->fpdu_part_rcvd, bytes); + siw_update_skb_rcvd(srx, bytes); srx->fpdu_part_rcvd += bytes; - - srx->skb_new -= bytes; - srx->skb_offset += bytes; - srx->skb_copied += bytes; - if (srx->fpdu_part_rcvd < MIN_DDP_HDR) return -EAGAIN; @@ -1091,12 +1088,8 @@ static int siw_get_hdr(struct siw_rx_stream *srx) skb_copy_bits(skb, srx->skb_offset, (char *)c_hdr + srx->fpdu_part_rcvd, bytes); + siw_update_skb_rcvd(srx, bytes); srx->fpdu_part_rcvd += bytes; - - srx->skb_new -= bytes; - srx->skb_offset += bytes; - srx->skb_copied += bytes; - if (srx->fpdu_part_rcvd < hdrlen) return -EAGAIN; } From 2109ddf032ebc57e0cd43e4378474ea6f2a378c2 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:12 +0800 Subject: [PATCH 0636/7721] RDMA/siw: Use iov.iov_len in kernel_sendmsg We can pass iov.iov_len here. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-4-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 86186cd3cca4..838123c621e2 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -292,8 +292,7 @@ static int siw_tx_ctrl(struct siw_iwarp_tx *c_tx, struct socket *s, (char *)&c_tx->pkt.ctrl + c_tx->ctrl_sent, .iov_len = c_tx->ctrl_len - c_tx->ctrl_sent }; - int rv = kernel_sendmsg(s, &msg, &iov, 1, - c_tx->ctrl_len - c_tx->ctrl_sent); + int rv = kernel_sendmsg(s, &msg, &iov, 1, iov.iov_len); if (rv >= 0) { c_tx->ctrl_sent += rv; From d248960941b71ebc1b62bd3241744f8a5eadc3d7 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:13 +0800 Subject: [PATCH 0637/7721] RDMA/siw: Remove goto lable in siw_mmap Let's remove it since the failure case only falls through to the useless label. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-5-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_verbs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index 27f7dda89e49..aad0a7d8789f 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -66,12 +66,9 @@ int siw_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma) entry = to_siw_mmap_entry(rdma_entry); rv = remap_vmalloc_range(vma, entry->address, 0); - if (rv) { + if (rv) pr_warn("remap_vmalloc_range failed: %lu, %zu\n", vma->vm_pgoff, size); - goto out; - } -out: rdma_user_mmap_entry_put(rdma_entry); return rv; From 659da08ed83a67aec9d106e44d2d88c5963fb85a Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:14 +0800 Subject: [PATCH 0638/7721] RDMA/siw: Remove rcu from siw_qp Remove it since it is not used. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-6-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index 849e496c7e67..b36d1ec25327 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -465,7 +465,6 @@ struct siw_qp { } term_info; struct rdma_user_mmap_entry *sq_entry; /* mmap info for SQE array */ struct rdma_user_mmap_entry *rq_entry; /* mmap info for RQE array */ - struct rcu_head rcu; }; /* helper macros */ From 065186d228c5280d0390fde0e7ddba998e66f047 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:15 +0800 Subject: [PATCH 0639/7721] RDMA/siw: No need to check term_info.valid before call siw_send_terminate Remove the redundate checking since siw_send_terminate check it inside. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-7-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 7de651cb44e8..5e6e57153611 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -393,8 +393,7 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule) } siw_dbg_cep(cep, "immediate close, state %d\n", cep->state); - if (qp->term_info.valid) - siw_send_terminate(qp); + siw_send_terminate(qp); if (cep->cm_id) { switch (cep->state) { @@ -1061,7 +1060,7 @@ static void siw_cm_work_handler(struct work_struct *w) /* * QP scheduled LLP close */ - if (cep->qp && cep->qp->term_info.valid) + if (cep->qp) siw_send_terminate(cep->qp); if (cep->cm_id) From 60d2136db8780b080bb6d5c7bdb0522b49c4eac6 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:16 +0800 Subject: [PATCH 0640/7721] RDMA/siw: Factor out siw_rx_data helper Remove the redundant code given they share the same logic. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-8-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_rx.c | 53 ++++++++++----------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c index 10805a7d0487..ed4fc39718b4 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -405,6 +405,20 @@ static struct siw_wqe *siw_rqe_get(struct siw_qp *qp) return wqe; } +static int siw_rx_data(struct siw_mem *mem_p, struct siw_rx_stream *srx, + unsigned int *pbl_idx, u64 addr, int bytes) +{ + int rv; + + if (mem_p->mem_obj == NULL) + rv = siw_rx_kva(srx, ib_virt_dma_to_ptr(addr), bytes); + else if (!mem_p->is_pbl) + rv = siw_rx_umem(srx, mem_p->umem, addr, bytes); + else + rv = siw_rx_pbl(srx, pbl_idx, mem_p, addr, bytes); + return rv; +} + /* * siw_proc_send: * @@ -485,17 +499,8 @@ int siw_proc_send(struct siw_qp *qp) break; } mem_p = *mem; - if (mem_p->mem_obj == NULL) - rv = siw_rx_kva(srx, - ib_virt_dma_to_ptr(sge->laddr + frx->sge_off), - sge_bytes); - else if (!mem_p->is_pbl) - rv = siw_rx_umem(srx, mem_p->umem, - sge->laddr + frx->sge_off, sge_bytes); - else - rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p, - sge->laddr + frx->sge_off, sge_bytes); - + rv = siw_rx_data(mem_p, srx, &frx->pbl_idx, + sge->laddr + frx->sge_off, sge_bytes); if (unlikely(rv != sge_bytes)) { wqe->processed += rcvd_bytes; @@ -598,17 +603,8 @@ int siw_proc_write(struct siw_qp *qp) return -EINVAL; } - if (mem->mem_obj == NULL) - rv = siw_rx_kva(srx, - (void *)(uintptr_t)(srx->ddp_to + srx->fpdu_part_rcvd), - bytes); - else if (!mem->is_pbl) - rv = siw_rx_umem(srx, mem->umem, - srx->ddp_to + srx->fpdu_part_rcvd, bytes); - else - rv = siw_rx_pbl(srx, &frx->pbl_idx, mem, - srx->ddp_to + srx->fpdu_part_rcvd, bytes); - + rv = siw_rx_data(mem, srx, &frx->pbl_idx, + srx->ddp_to + srx->fpdu_part_rcvd, bytes); if (unlikely(rv != bytes)) { siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, DDP_ETYPE_CATASTROPHIC, @@ -849,17 +845,8 @@ int siw_proc_rresp(struct siw_qp *qp) mem_p = *mem; bytes = min(srx->fpdu_part_rem, srx->skb_new); - - if (mem_p->mem_obj == NULL) - rv = siw_rx_kva(srx, - ib_virt_dma_to_ptr(sge->laddr + wqe->processed), - bytes); - else if (!mem_p->is_pbl) - rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed, - bytes); - else - rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p, - sge->laddr + wqe->processed, bytes); + rv = siw_rx_data(mem_p, srx, &frx->pbl_idx, + sge->laddr + wqe->processed, bytes); if (rv != bytes) { wqe->wc_status = SIW_WC_GENERAL_ERR; rv = -EINVAL; From 6a343cc3bf2626bc0c487bf2a72c90b4519c3da4 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:17 +0800 Subject: [PATCH 0641/7721] RDMA/siw: Introduce SIW_STAG_MAX_INDEX Add the macro to remove magic number in the code. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-9-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_mem.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c index 2110ceb0603c..dcb963607c8b 100644 --- a/drivers/infiniband/sw/siw/siw_mem.c +++ b/drivers/infiniband/sw/siw/siw_mem.c @@ -14,18 +14,20 @@ #include "siw.h" #include "siw_mem.h" +/* Stag lookup is based on its index part only (24 bits). */ +#define SIW_STAG_MAX_INDEX 0x00ffffff + /* - * Stag lookup is based on its index part only (24 bits). * The code avoids special Stag of zero and tries to randomize * STag values between 1 and SIW_STAG_MAX_INDEX. */ int siw_mem_add(struct siw_device *sdev, struct siw_mem *m) { - struct xa_limit limit = XA_LIMIT(1, 0x00ffffff); + struct xa_limit limit = XA_LIMIT(1, SIW_STAG_MAX_INDEX); u32 id, next; get_random_bytes(&next, 4); - next &= 0x00ffffff; + next &= SIW_STAG_MAX_INDEX; if (xa_alloc_cyclic(&sdev->mem_xa, &id, m, limit, &next, GFP_KERNEL) < 0) @@ -81,7 +83,7 @@ int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj, { struct siw_device *sdev = to_siw_dev(pd->device); struct siw_mem *mem = kzalloc(sizeof(*mem), GFP_KERNEL); - struct xa_limit limit = XA_LIMIT(1, 0x00ffffff); + struct xa_limit limit = XA_LIMIT(1, SIW_STAG_MAX_INDEX); u32 id, next; if (!mem) @@ -97,7 +99,7 @@ int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj, kref_init(&mem->ref); get_random_bytes(&next, 4); - next &= 0x00ffffff; + next &= SIW_STAG_MAX_INDEX; if (xa_alloc_cyclic(&sdev->mem_xa, &id, mem, limit, &next, GFP_KERNEL) < 0) { From 25680c1f2614756463040f2dc03b3ec611ae3bfe Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:18 +0800 Subject: [PATCH 0642/7721] RDMA/siw: Add one parameter to siw_destroy_cpulist With that we can reuse it in siw_init_cpulist. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-10-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_main.c | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c index 1ab62982df74..61ad8ca3d1a2 100644 --- a/drivers/infiniband/sw/siw/siw_main.c +++ b/drivers/infiniband/sw/siw/siw_main.c @@ -109,6 +109,17 @@ static struct { int num_nodes; } siw_cpu_info; +static void siw_destroy_cpulist(int number) +{ + int i = 0; + + while (i < number) + kfree(siw_cpu_info.tx_valid_cpus[i++]); + + kfree(siw_cpu_info.tx_valid_cpus); + siw_cpu_info.tx_valid_cpus = NULL; +} + static int siw_init_cpulist(void) { int i, num_nodes = nr_node_ids; @@ -138,24 +149,11 @@ static int siw_init_cpulist(void) out_err: siw_cpu_info.num_nodes = 0; - while (--i >= 0) - kfree(siw_cpu_info.tx_valid_cpus[i]); - kfree(siw_cpu_info.tx_valid_cpus); - siw_cpu_info.tx_valid_cpus = NULL; + siw_destroy_cpulist(i); return -ENOMEM; } -static void siw_destroy_cpulist(void) -{ - int i = 0; - - while (i < siw_cpu_info.num_nodes) - kfree(siw_cpu_info.tx_valid_cpus[i++]); - - kfree(siw_cpu_info.tx_valid_cpus); -} - /* * Choose CPU with least number of active QP's from NUMA node of * TX interface. @@ -558,7 +556,7 @@ static __init int siw_init_module(void) pr_info("SoftIWARP attach failed. Error: %d\n", rv); siw_cm_exit(); - siw_destroy_cpulist(); + siw_destroy_cpulist(siw_cpu_info.num_nodes); return rv; } @@ -573,7 +571,7 @@ static void __exit siw_exit_module(void) siw_cm_exit(); - siw_destroy_cpulist(); + siw_destroy_cpulist(siw_cpu_info.num_nodes); if (siw_crypto_shash) crypto_free_shash(siw_crypto_shash); From b5c91543204c345f1b28af573854c4b7e699cc91 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:19 +0800 Subject: [PATCH 0643/7721] RDMA/siw: Introduce siw_cep_set_free_and_put Add the helper which can be used in some places. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-11-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 5e6e57153611..d72c9fab01d9 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -444,6 +444,12 @@ void siw_cep_put(struct siw_cep *cep) kref_put(&cep->ref, __siw_cep_dealloc); } +static void siw_cep_set_free_and_put(struct siw_cep *cep) +{ + siw_cep_set_free(cep); + siw_cep_put(cep); +} + void siw_cep_get(struct siw_cep *cep) { kref_get(&cep->ref); @@ -1514,9 +1520,7 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state = SIW_EPSTATE_CLOSED; - siw_cep_set_free(cep); - - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); } else if (s) { sock_release(s); @@ -1564,16 +1568,14 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) { siw_dbg_cep(cep, "out of state\n"); - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); return -ECONNRESET; } qp = siw_qp_id2obj(sdev, params->qpn); if (!qp) { WARN(1, "[QP %d] does not exist\n", params->qpn); - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); return -EINVAL; } @@ -1719,8 +1721,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->qp = NULL; siw_qp_put(qp); - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); return rv; } @@ -1743,8 +1744,7 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len) if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) { siw_dbg_cep(cep, "out of state\n"); - siw_cep_set_free(cep); - siw_cep_put(cep); /* put last reference */ + siw_cep_set_free_and_put(cep); /* put last reference */ return -ECONNRESET; } @@ -1761,8 +1761,7 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len) cep->state = SIW_EPSTATE_CLOSED; - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); return 0; } @@ -1897,8 +1896,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog) siw_socket_disassoc(s); cep->state = SIW_EPSTATE_CLOSED; - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); } sock_release(s); @@ -1932,8 +1930,7 @@ static void siw_drop_listeners(struct iw_cm_id *id) cep->sock = NULL; } cep->state = SIW_EPSTATE_CLOSED; - siw_cep_set_free(cep); - siw_cep_put(cep); + siw_cep_set_free_and_put(cep); } } From 08456d4db73bbb3fcaa0d63252ea2399c65297a4 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:20 +0800 Subject: [PATCH 0644/7721] RDMA/siw: Introduce siw_free_cm_id Factor out a helper to simplify code. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310091656.JlrmcNXB-lkp@intel.com/ Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-12-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index d72c9fab01d9..36fd459b136c 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -364,6 +364,15 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason, return id->event_handler(id, &event); } +static void siw_free_cm_id(struct siw_cep *cep) +{ + if (!cep->cm_id) + return; + + cep->cm_id->rem_ref(cep->cm_id); + cep->cm_id = NULL; +} + /* * siw_qp_cm_drop() * @@ -415,8 +424,7 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule) default: break; } - cep->cm_id->rem_ref(cep->cm_id); - cep->cm_id = NULL; + siw_free_cm_id(cep); siw_cep_put(cep); } cep->state = SIW_EPSTATE_CLOSED; @@ -1180,8 +1188,7 @@ static void siw_cm_work_handler(struct work_struct *w) cep->sock = NULL; } if (cep->cm_id) { - cep->cm_id->rem_ref(cep->cm_id); - cep->cm_id = NULL; + siw_free_cm_id(cep); siw_cep_put(cep); } } @@ -1710,10 +1717,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state = SIW_EPSTATE_CLOSED; - if (cep->cm_id) { - cep->cm_id->rem_ref(id); - cep->cm_id = NULL; - } + siw_free_cm_id(cep); if (qp->cep) { siw_cep_put(cep); qp->cep = NULL; @@ -1888,10 +1892,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog) if (cep) { siw_cep_set_inuse(cep); - if (cep->cm_id) { - cep->cm_id->rem_ref(cep->cm_id); - cep->cm_id = NULL; - } + siw_free_cm_id(cep); cep->sock = NULL; siw_socket_disassoc(s); cep->state = SIW_EPSTATE_CLOSED; @@ -1920,10 +1921,7 @@ static void siw_drop_listeners(struct iw_cm_id *id) siw_cep_set_inuse(cep); - if (cep->cm_id) { - cep->cm_id->rem_ref(cep->cm_id); - cep->cm_id = NULL; - } + siw_free_cm_id(cep); if (cep->sock) { siw_socket_disassoc(cep->sock); sock_release(cep->sock); From 77b59bd932a026b64303d313d966decb0e9225fa Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:21 +0800 Subject: [PATCH 0645/7721] RDMA/siw: Cleanup siw_accept With the initialization of rv and the two added label, we can simplifiy code a bit. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-13-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 41 ++++++++++-------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 36fd459b136c..5e9a591eec58 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -1558,7 +1558,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) struct siw_cep *cep = (struct siw_cep *)id->provider_data; struct siw_qp *qp; struct siw_qp_attrs qp_attrs; - int rv, max_priv_data = MPA_MAX_PRIVDATA; + int rv = -EINVAL, max_priv_data = MPA_MAX_PRIVDATA; bool wait_for_peer_rts = false; siw_cep_set_inuse(cep); @@ -1574,24 +1574,17 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) { siw_dbg_cep(cep, "out of state\n"); - - siw_cep_set_free_and_put(cep); - - return -ECONNRESET; + rv = -ECONNRESET; + goto free_cep; } qp = siw_qp_id2obj(sdev, params->qpn); if (!qp) { WARN(1, "[QP %d] does not exist\n", params->qpn); - siw_cep_set_free_and_put(cep); - - return -EINVAL; + goto free_cep; } down_write(&qp->state_lock); - if (qp->attrs.state > SIW_QP_STATE_RTR) { - rv = -EINVAL; - up_write(&qp->state_lock); - goto error; - } + if (qp->attrs.state > SIW_QP_STATE_RTR) + goto error_unlock; siw_dbg_cep(cep, "[QP %d]\n", params->qpn); if (try_gso && cep->mpa.hdr.params.bits & MPA_RR_FLAG_GSO_EXP) { @@ -1605,9 +1598,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) "[QP %u]: ord %d (max %d), ird %d (max %d)\n", qp_id(qp), params->ord, sdev->attrs.max_ord, params->ird, sdev->attrs.max_ird); - rv = -EINVAL; - up_write(&qp->state_lock); - goto error; + goto error_unlock; } if (cep->enhanced_rdma_conn_est) max_priv_data -= sizeof(struct mpa_v2_data); @@ -1617,9 +1608,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep, "[QP %u]: private data length: %d (max %d)\n", qp_id(qp), params->private_data_len, max_priv_data); - rv = -EINVAL; - up_write(&qp->state_lock); - goto error; + goto error_unlock; } if (cep->enhanced_rdma_conn_est) { if (params->ord > cep->ord) { @@ -1628,9 +1617,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) } else { cep->ird = params->ird; cep->ord = params->ord; - rv = -EINVAL; - up_write(&qp->state_lock); - goto error; + goto error_unlock; } } if (params->ird < cep->ird) { @@ -1639,8 +1626,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) params->ird = cep->ird; else { rv = -ENOMEM; - up_write(&qp->state_lock); - goto error; + goto error_unlock; } } if (cep->mpa.v2_ctrl.ord & @@ -1687,7 +1673,6 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD | SIW_QP_ATTR_MPA); up_write(&qp->state_lock); - if (rv) goto error; @@ -1710,6 +1695,9 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) siw_cep_set_free(cep); return 0; + +error_unlock: + up_write(&qp->state_lock); error: siw_socket_disassoc(cep->sock); sock_release(cep->sock); @@ -1724,9 +1712,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) } cep->qp = NULL; siw_qp_put(qp); - +free_cep: siw_cep_set_free_and_put(cep); - return rv; } From a410a7327870264da2a1a3eed704380053ffdf9f Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:22 +0800 Subject: [PATCH 0646/7721] RDMA/siw: Remove siw_sk_save_upcalls Let's move it into siw_sk_assign_cm_upcalls, then we only need to get sk_callback_lock once. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-14-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 5e9a591eec58..5c0f9f8bf3db 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -40,16 +40,6 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason, int status); static void siw_sk_assign_cm_upcalls(struct sock *sk) -{ - write_lock_bh(&sk->sk_callback_lock); - sk->sk_state_change = siw_cm_llp_state_change; - sk->sk_data_ready = siw_cm_llp_data_ready; - sk->sk_write_space = siw_cm_llp_write_space; - sk->sk_error_report = siw_cm_llp_error_report; - write_unlock_bh(&sk->sk_callback_lock); -} - -static void siw_sk_save_upcalls(struct sock *sk) { struct siw_cep *cep = sk_to_cep(sk); @@ -58,6 +48,11 @@ static void siw_sk_save_upcalls(struct sock *sk) cep->sk_data_ready = sk->sk_data_ready; cep->sk_write_space = sk->sk_write_space; cep->sk_error_report = sk->sk_error_report; + + sk->sk_state_change = siw_cm_llp_state_change; + sk->sk_data_ready = siw_cm_llp_data_ready; + sk->sk_write_space = siw_cm_llp_write_space; + sk->sk_error_report = siw_cm_llp_error_report; write_unlock_bh(&sk->sk_callback_lock); } @@ -156,7 +151,6 @@ static void siw_cep_socket_assoc(struct siw_cep *cep, struct socket *s) siw_cep_get(cep); s->sk->sk_user_data = cep; - siw_sk_save_upcalls(s->sk); siw_sk_assign_cm_upcalls(s->sk); } From 3beced14d1998c8e0c5d3d78b2dd86255365e705 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:23 +0800 Subject: [PATCH 0647/7721] RDMA/siw: Fix typo Replace ORRQ with ORQ. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-15-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c index 26e3904d2f41..da92cfa2073d 100644 --- a/drivers/infiniband/sw/siw/siw_qp.c +++ b/drivers/infiniband/sw/siw/siw_qp.c @@ -1183,7 +1183,7 @@ int siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes, /* * siw_sq_flush() * - * Flush SQ and ORRQ entries to CQ. + * Flush SQ and ORQ entries to CQ. * * Must be called with QP state write lock held. * Therefore, SQ and ORQ lock must not be taken. From 788bbf4c2fc6e0c35bae9ed5068f484272539d3e Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:24 +0800 Subject: [PATCH 0648/7721] RDMA/siw: Only check attrs->cap.max_send_wr in siw_create_qp We can just check max_send_wr here given both max_send_wr and max_recv_wr are defined as u32 type, and we also need to ensure num_sqe (derived from max_send_wr) shouldn't be zero. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-16-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_verbs.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index aad0a7d8789f..dca6a155523d 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -333,11 +333,10 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, goto err_atomic; } /* - * NOTE: we allow for zero element SQ and RQ WQE's SGL's - * but not for a QP unable to hold any WQE (SQ + RQ) + * NOTE: we don't allow for a QP unable to hold any SQ WQE */ - if (attrs->cap.max_send_wr + attrs->cap.max_recv_wr == 0) { - siw_dbg(base_dev, "QP must have send or receive queue\n"); + if (attrs->cap.max_send_wr == 0) { + siw_dbg(base_dev, "QP must have send queue\n"); rv = -EINVAL; goto err_atomic; } @@ -357,21 +356,14 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, if (rv) goto err_atomic; - num_sqe = attrs->cap.max_send_wr; - num_rqe = attrs->cap.max_recv_wr; /* All queue indices are derived from modulo operations * on a free running 'get' (consumer) and 'put' (producer) * unsigned counter. Having queue sizes at power of two * avoids handling counter wrap around. */ - if (num_sqe) - num_sqe = roundup_pow_of_two(num_sqe); - else { - /* Zero sized SQ is not supported */ - rv = -EINVAL; - goto err_out_xa; - } + num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr); + num_rqe = attrs->cap.max_recv_wr; if (num_rqe) num_rqe = roundup_pow_of_two(num_rqe); From d9a5b48681315a5881cea24bc8f384da02828e88 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:25 +0800 Subject: [PATCH 0649/7721] RDMA/siw: Introduce siw_destroy_cep_sock Add one helper to simplify code a bit. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310091735.oG7bTvLR-lkp@intel.com/` Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-17-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_cm.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 5c0f9f8bf3db..86323918a570 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -367,6 +367,15 @@ static void siw_free_cm_id(struct siw_cep *cep) cep->cm_id = NULL; } +static void siw_destroy_cep_sock(struct siw_cep *cep) +{ + if (cep->sock) { + siw_socket_disassoc(cep->sock); + sock_release(cep->sock); + cep->sock = NULL; + } +} + /* * siw_qp_cm_drop() * @@ -423,14 +432,7 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule) } cep->state = SIW_EPSTATE_CLOSED; - if (cep->sock) { - siw_socket_disassoc(cep->sock); - /* - * Immediately close socket - */ - sock_release(cep->sock); - cep->sock = NULL; - } + siw_destroy_cep_sock(cep); if (cep->qp) { cep->qp = NULL; siw_qp_put(qp); @@ -1693,9 +1695,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) error_unlock: up_write(&qp->state_lock); error: - siw_socket_disassoc(cep->sock); - sock_release(cep->sock); - cep->sock = NULL; + siw_destroy_cep_sock(cep); cep->state = SIW_EPSTATE_CLOSED; @@ -1740,9 +1740,7 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len) cep->mpa.hdr.params.bits |= MPA_RR_FLAG_REJECT; /* reject */ siw_send_mpareqrep(cep, pdata, pd_len); } - siw_socket_disassoc(cep->sock); - sock_release(cep->sock); - cep->sock = NULL; + siw_destroy_cep_sock(cep); cep->state = SIW_EPSTATE_CLOSED; From 79844118d6c1cd48bd2cfacbab67592e6bf32fe8 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 13 Nov 2023 19:57:26 +0800 Subject: [PATCH 0650/7721] RDMA/siw: Update comments for siw_qp_sq_process There is no siw_sq_work_handler in code, change it with siw_tx_thread since siw_run_sq -> siw_sq_resume -> siw_qp_sq_process. Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20231113115726.12762-18-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw_qp_tx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 838123c621e2..64ad9e0895bd 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -997,13 +997,12 @@ static int siw_qp_sq_proc_local(struct siw_qp *qp, struct siw_wqe *wqe) * MPA FPDUs, each containing a DDP segment. * * SQ processing may occur in user context as a result of posting - * new WQE's or from siw_sq_work_handler() context. Processing in + * new WQE's or from siw_tx_thread context. Processing in * user context is limited to non-kernel verbs users. * * SQ processing may get paused anytime, possibly in the middle of a WR * or FPDU, if insufficient send space is available. SQ processing - * gets resumed from siw_sq_work_handler(), if send space becomes - * available again. + * gets resumed from siw_tx_thread, if send space becomes available again. * * Must be called with the QP state read-locked. * From 7936a19e944b934d21d79f1b90d478d1f7081b63 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 23 Oct 2023 19:50:57 +0000 Subject: [PATCH 0651/7721] scsi: 3w-sas: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. This pattern of strncpy(dest, src, strlen(src)) is extremely bug-prone. This pattern basically never results in NUL-terminated destination strings unless `dest` was zero-initialized. The current implementation may be accidentally correct as tw_dev is zero-allocated via: host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); ... tw_dev = shost_priv(host); ... wherein scsi_host_alloc() zero-allocates host: shost = kzalloc(sizeof(struct Scsi_Host) + privsize, GFP_KERNEL); Also, further suggesting this change is worthwhile is another strscpy() usage in 3w-9xxx.c: strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, sizeof(tw_dev->tw_compat_info.driver_version)); Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's not be accidentally correct, let's be definitely correct. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231023-strncpy-drivers-scsi-3w-sas-c-v1-1-4c40a1e99dfc@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-sas.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 55989eaa2d9f..9bdb75dfdcd7 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1326,7 +1326,8 @@ static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) } /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; From b04a2eff9e9c6f8890d25dbb073fbf5c00892a9a Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 23 Oct 2023 20:12:22 +0000 Subject: [PATCH 0652/7721] scsi: bnx2fc: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect hba->chip_num to be NUL-terminated based on its usage with format strings: snprintf(fc_host_symbolic_name(lport->host), 256, "%s (QLogic %s) v%s over %s", BNX2FC_NAME, hba->chip_num, BNX2FC_VERSION, interface->netdev->name); Moreover, NUL-padding is not required as hba is zero-allocated from its callsite: hba = kzalloc(sizeof(*hba), GFP_KERNEL); Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Regarding stats_addr->version, I've opted to also use strscpy() instead of strscpy_pad() as I typically see these XYZ_get_strings() pass zero-allocated data. I couldn't track all of where bnx2fc_ulp_get_stats() is used and if required, we could opt for strscpy_pad(). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231023-strncpy-drivers-scsi-bnx2fc-bnx2fc_fcoe-c-v1-1-a3736943cde2@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 05ddbb9bb7d8..3ebfb09329ad 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1737,32 +1737,32 @@ static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba) switch (pdev->device) { case PCI_DEVICE_ID_NX2_57710: - strncpy(hba->chip_num, "BCM57710", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57710", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57711: - strncpy(hba->chip_num, "BCM57711", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57711", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57712: case PCI_DEVICE_ID_NX2_57712_MF: case PCI_DEVICE_ID_NX2_57712_VF: - strncpy(hba->chip_num, "BCM57712", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57712", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57800: case PCI_DEVICE_ID_NX2_57800_MF: case PCI_DEVICE_ID_NX2_57800_VF: - strncpy(hba->chip_num, "BCM57800", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57800", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57810: case PCI_DEVICE_ID_NX2_57810_MF: case PCI_DEVICE_ID_NX2_57810_VF: - strncpy(hba->chip_num, "BCM57810", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57810", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57840: case PCI_DEVICE_ID_NX2_57840_MF: case PCI_DEVICE_ID_NX2_57840_VF: case PCI_DEVICE_ID_NX2_57840_2_20: case PCI_DEVICE_ID_NX2_57840_4_10: - strncpy(hba->chip_num, "BCM57840", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57840", sizeof(hba->chip_num)); break; default: pr_err(PFX "Unknown device id 0x%x\n", pdev->device); @@ -1800,7 +1800,7 @@ static int bnx2fc_ulp_get_stats(void *handle) if (!stats_addr) return -EINVAL; - strncpy(stats_addr->version, BNX2FC_VERSION, + strscpy(stats_addr->version, BNX2FC_VERSION, sizeof(stats_addr->version)); stats_addr->txq_size = BNX2FC_SQ_WQES_MAX; stats_addr->rxq_size = BNX2FC_CQ_WQES_MAX; From daed80ed07580e5adc0e6d8bc79933a35154135a Mon Sep 17 00:00:00 2001 From: HariBabu Gattem Date: Thu, 26 Oct 2023 22:56:22 -0700 Subject: [PATCH 0653/7721] soc: xilinx: Fix for call trace due to the usage of smp_processor_id() When preemption is enabled in kernel and if any task which can be preempted should not use smp_processor_id() directly, since CPU switch can happen at any time, the previous value of cpu_id differs with current cpu_id. As a result we see the below call trace during xlnx_event_manager_probe. [ 6.140197] dump_backtrace+0x0/0x190 [ 6.143884] show_stack+0x18/0x40 [ 6.147220] dump_stack_lvl+0x7c/0xa0 [ 6.150907] dump_stack+0x18/0x34 [ 6.154241] check_preemption_disabled+0x124/0x134 [ 6.159068] debug_smp_processor_id+0x20/0x2c [ 6.163453] xlnx_event_manager_probe+0x48/0x250 To protect cpu_id, It is recommended to use get_cpu()/put_cpu() to disable preemption, get the cpu_id and enable preemption respectively. (For Reference, Documentation/locking/preempt-locking.rst and Documentation/kernel-hacking/hacking.rst) Use preempt_disable()/smp_processor_id()/preempt_enable() API's to achieve the same. Signed-off-by: HariBabu Gattem Signed-off-by: Jay Buddhabhatti Link: https://lore.kernel.org/r/20231027055622.21544-1-jay.buddhabhatti@amd.com Signed-off-by: Michal Simek --- drivers/soc/xilinx/xlnx_event_manager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index 86a048a10a13..edfb1d5c10c6 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -555,7 +555,7 @@ static void xlnx_disable_percpu_irq(void *data) static int xlnx_event_init_sgi(struct platform_device *pdev) { int ret = 0; - int cpu = smp_processor_id(); + int cpu; /* * IRQ related structures are used for the following: * for each SGI interrupt ensure its mapped by GIC IRQ domain @@ -592,9 +592,12 @@ static int xlnx_event_init_sgi(struct platform_device *pdev) sgi_fwspec.param[0] = sgi_num; virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec); + cpu = get_cpu(); per_cpu(cpu_number1, cpu) = cpu; ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt", &cpu_number1); + put_cpu(); + WARN_ON(ret); if (ret) { irq_dispose_mapping(virq_sgi); From dc7a7f10e673499856dd275691768df6d07a2815 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 23 Oct 2023 20:20:14 +0000 Subject: [PATCH 0654/7721] scsi: ch: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. These labels get copied out to the user so lets make sure they are NUL-terminated and NUL-padded. vparams is already memset to 0 so we don't need to do any NUL-padding (like what strncpy() is doing). Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy() usage of: (dest, src, sizeof(dest)) as this more closely ties the destination buffer to the length. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231023-strncpy-drivers-scsi-ch-c-v1-1-dc67ba8075a3@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index cb0a399be1cc..2b864061e073 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -659,19 +659,23 @@ static long ch_ioctl(struct file *file, memset(&vparams,0,sizeof(vparams)); if (ch->counts[CHET_V1]) { vparams.cvp_n1 = ch->counts[CHET_V1]; - strncpy(vparams.cvp_label1,vendor_labels[0],16); + strscpy(vparams.cvp_label1, vendor_labels[0], + sizeof(vparams.cvp_label1)); } if (ch->counts[CHET_V2]) { vparams.cvp_n2 = ch->counts[CHET_V2]; - strncpy(vparams.cvp_label2,vendor_labels[1],16); + strscpy(vparams.cvp_label2, vendor_labels[1], + sizeof(vparams.cvp_label2)); } if (ch->counts[CHET_V3]) { vparams.cvp_n3 = ch->counts[CHET_V3]; - strncpy(vparams.cvp_label3,vendor_labels[2],16); + strscpy(vparams.cvp_label3, vendor_labels[2], + sizeof(vparams.cvp_label3)); } if (ch->counts[CHET_V4]) { vparams.cvp_n4 = ch->counts[CHET_V4]; - strncpy(vparams.cvp_label4,vendor_labels[3],16); + strscpy(vparams.cvp_label4, vendor_labels[3], + sizeof(vparams.cvp_label4)); } if (copy_to_user(argp, &vparams, sizeof(vparams))) return -EFAULT; From 4c0afac2dfa1e11bbea9ef69da5c3c2bfdfe4c43 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 27 Oct 2023 23:41:35 +0530 Subject: [PATCH 0655/7721] soc: xilinx: fix quoted string split across lines Fix checkpatch warning "quoted string split across lines". No functional change. Signed-off-by: Michal Simek Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/1698430295-2731040-1-git-send-email-radhey.shyam.pandey@amd.com --- drivers/soc/xilinx/zynqmp_power.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 9d27f850f491..abcf7e883279 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -83,8 +83,8 @@ static irqreturn_t zynqmp_pm_isr(int irq, void *data) pm_suspend(PM_SUSPEND_MEM); break; default: - pr_err("%s Unsupported InitSuspendCb reason " - "code %d\n", __func__, payload[1]); + pr_err("%s Unsupported InitSuspendCb reason code %d\n", + __func__, payload[1]); } } @@ -252,8 +252,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev) dev_name(&pdev->dev), &pdev->dev); if (ret) { - dev_err(&pdev->dev, "devm_request_threaded_irq '%d' " - "failed with %d\n", irq, ret); + dev_err(&pdev->dev, "devm_request_threaded_irq '%d' failed with %d\n", + irq, ret); return ret; } } else { From 9c6724abf969251af53cdae525ad8100ec78d3c2 Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Fri, 27 Oct 2023 23:53:59 +0530 Subject: [PATCH 0656/7721] soc: xilinx: fix unhandled SGI warning message Xen broadcasts SGI to each VM when multiple VMs run on Xen hypervisor. In such case spurious SGI is expected if one event is registered by one VM and not registered by another VM. We let users know that Unhandled SGI is not error and expected if kernel is running on Xen hypervisor. Signed-off-by: Tanmay Shah Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/1698431039-2734260-1-git-send-email-radhey.shyam.pandey@amd.com Signed-off-by: Michal Simek --- drivers/soc/xilinx/xlnx_event_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index edfb1d5c10c6..042553abe1bf 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -477,7 +477,7 @@ static void xlnx_call_notify_cb_handler(const u32 *payload) } } if (!is_callback_found) - pr_warn("Didn't find any registered callback for 0x%x 0x%x\n", + pr_warn("Unhandled SGI node 0x%x event 0x%x. Expected with Xen hypervisor\n", payload[1], payload[2]); } From 4592411784ccf83f873f98ba94aeae2482783c9a Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 23 Oct 2023 20:26:13 +0000 Subject: [PATCH 0657/7721] scsi: csiostor: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. 'hw' is kzalloc'd just before this string assignment: | hw = kzalloc(sizeof(struct csio_hw), GFP_KERNEL); ... which means any NUL-padding is redundant. Since CSIO_DRV_VERSION is a small string literal (smaller than sizeof(dest)): ... there is functionally no change in this swap from strncpy() to strscpy(). Nonetheless, let's make the change for robustness' sake -- as it will ensure that drv_version is _always_ NUL-terminated. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231023-strncpy-drivers-scsi-csiostor-csio_init-c-v1-1-5ea445b56864@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index 0c32faefad7c..d649b7a2a879 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -521,7 +521,8 @@ static struct csio_hw *csio_hw_alloc(struct pci_dev *pdev) goto err; hw->pdev = pdev; - strncpy(hw->drv_version, CSIO_DRV_VERSION, 32); + strscpy(hw->drv_version, CSIO_DRV_VERSION, + sizeof(hw->drv_version)); /* memory pool/DMA pool allocation */ if (csio_resource_alloc(hw)) From 66d6143ebff038a69d875e582e536bae02b14290 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Sun, 12 Nov 2023 18:34:32 -0800 Subject: [PATCH 0658/7721] gpio: sifive: remove unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Reviewed-by: Alexandru Ardelean Signed-off-by: Andrei Coardos Reviewed-by: Andy Shevchenko Signed-off-by: Samuel Holland Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sifive.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 8decd9b5d229..067c8edb62e2 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -250,7 +250,6 @@ static int sifive_gpio_probe(struct platform_device *pdev) girq->handler = handle_bad_irq; girq->default_type = IRQ_TYPE_NONE; - platform_set_drvdata(pdev, chip); return gpiochip_add_data(&chip->gc, chip); } From 1057f44137c5484e402cc69d0ad9954e6cd7e029 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 26 Oct 2023 01:53:13 +0000 Subject: [PATCH 0659/7721] scsi: elx: libefc: Replace deprecated strncpy() with strscpy_pad()/memcpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. To keep node->current_state_name and node->prev_state_name NUL-padded and NUL-terminated let's use strscpy_pad() as this implicitly provides both. For the swap between the two, a simple memcpy() will suffice. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231026-strncpy-drivers-scsi-elx-libefc-efc_node-h-v2-1-5c083d0c13f4@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/libefc/efc_node.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/elx/libefc/efc_node.h b/drivers/scsi/elx/libefc/efc_node.h index e9c600ac45d5..e57579988ba4 100644 --- a/drivers/scsi/elx/libefc/efc_node.h +++ b/drivers/scsi/elx/libefc/efc_node.h @@ -26,13 +26,13 @@ efc_node_evt_set(struct efc_sm_ctx *ctx, enum efc_sm_event evt, struct efc_node *node = ctx->app; if (evt == EFC_EVT_ENTER) { - strncpy(node->current_state_name, handler, - sizeof(node->current_state_name)); + strscpy_pad(node->current_state_name, handler, + sizeof(node->current_state_name)); } else if (evt == EFC_EVT_EXIT) { - strncpy(node->prev_state_name, node->current_state_name, - sizeof(node->prev_state_name)); - strncpy(node->current_state_name, "invalid", - sizeof(node->current_state_name)); + memcpy(node->prev_state_name, node->current_state_name, + sizeof(node->prev_state_name)); + strscpy_pad(node->current_state_name, "invalid", + sizeof(node->current_state_name)); } node->prev_evt = node->current_evt; node->current_evt = evt; From 2fe4b6a67730e6ffd002b2b3c4752ef262fedde4 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:16 -0700 Subject: [PATCH 0660/7721] scsi: lpfc: Correct maximum PCI function value for RAS fw logging Currently, the ras_fwlog_func sysfs parameter allows users to input a value greater than three when selecting a PCI function to enable RAS fw logging feature. The user's input is sanity checked in lpfc_sli4_ras_init(), but allowing an input greater than three doesn't make sense because the max number of ports per HBA is four. Change the allowable range from [0, 7] to [0, 3]. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-2-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b1c9107d3408..48c727a51193 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5905,11 +5905,11 @@ LPFC_ATTR_RW(ras_fwlog_level, 0, 0, 4, "Firmware Logging Level"); /* * lpfc_ras_fwlog_func: Firmware logging enabled on function number * Default function which has RAS support : 0 - * Value Range is [0..7]. + * Value Range is [0..3]. * FW logging is a global action and enablement is via a specific * port. */ -LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function"); +LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 3, "Firmware Logging Enabled on Function"); /* * lpfc_enable_bbcr: Enable BB Credit Recovery From f5779b529240b715f0e358489ad0ed933bf77c97 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:17 -0700 Subject: [PATCH 0661/7721] scsi: lpfc: Fix possible file string name overflow when updating firmware Because file_name and phba->ModelName are both declared a size 80 bytes, the extra ".grp" file extension could cause an overflow into file_name. Define a ELX_FW_NAME_SIZE macro with value 84. 84 incorporates the 4 extra characters from ".grp". file_name is changed to be declared as a char and initialized to zeros i.e. null chars. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-3-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index af15f7a22d25..04d608ea9106 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -33,6 +33,7 @@ struct lpfc_sli2_slim; #define ELX_MODEL_NAME_SIZE 80 +#define ELX_FW_NAME_SIZE 84 #define LPFC_PCI_DEV_LP 0x1 #define LPFC_PCI_DEV_OC 0x2 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e7c47ee185a4..70bcee64bc8c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -14721,7 +14721,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) int lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) { - uint8_t file_name[ELX_MODEL_NAME_SIZE]; + char file_name[ELX_FW_NAME_SIZE] = {0}; int ret; const struct firmware *fw; @@ -14730,7 +14730,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) LPFC_SLI_INTF_IF_TYPE_2) return -EPERM; - snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName); + scnprintf(file_name, sizeof(file_name), "%s.grp", phba->ModelName); if (fw_upgrade == INT_FW_UPGRADE) { ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, From 1dec1311b9b6cc9c5fd26a77b936f542f03c51d1 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:18 -0700 Subject: [PATCH 0662/7721] scsi: lpfc: Fix list_entry null check warning in lpfc_cmpl_els_plogi() Smatch called out a warning for null checking a ptr that is assigned by list_entry(). list_entry() does not return null and, if the list is empty, can return an invalid ptr. Thus, the !psrp check does not execute properly. drivers/scsi/lpfc/lpfc_els.c:2133 lpfc_cmpl_els_plogi() warn: list_entry() does not return NULL 'prsp' Replace list_entry() with list_get_first(), which does a list_empty() check before returning the first entry. Fixes: a3c3c0a806f1 ("scsi: lpfc: Validate ELS LS_ACC completion payload") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-scsi/01b7568f-4ab4-4d56-bfa6-9ecc5fc261fe@moroto.mountain/ Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-4-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f9627eddab08..0829fe6ddff8 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2128,8 +2128,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, NLP_EVT_DEVICE_RM); } else { /* Good status, call state machine */ - prsp = list_entry(cmdiocb->cmd_dmabuf->list.next, - struct lpfc_dmabuf, list); + prsp = list_get_first(&cmdiocb->cmd_dmabuf->list, + struct lpfc_dmabuf, list); if (!prsp) goto out; if (!lpfc_is_els_acc_rsp(prsp)) From e07ac2d2aa5fce0cefe7273f6b9babec1e9a1503 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:19 -0700 Subject: [PATCH 0663/7721] scsi: lpfc: Eliminate unnecessary relocking in lpfc_check_nlp_post_devloss() In lpfc_check_nlp_post_devloss(), retaking of the ndlp lock in the if statement is useless because the very next line unlocks. Simply return to avoid relocking. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-5-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7ef9841f0728..f80bbc315f4c 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -411,7 +411,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, "port_state = x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, ndlp->nlp_flag, vport->port_state); - spin_lock_irqsave(&ndlp->lock, iflags); + return; } spin_unlock_irqrestore(&ndlp->lock, iflags); } From 57ea41eb7fe6d6a6bf80f40de9acddb33b41eeb9 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:20 -0700 Subject: [PATCH 0664/7721] scsi: lpfc: Return early in lpfc_poll_eratt() when the driver is unloading Add a check in lpfc_poll_eratt() when the driver is unloading. There is no point to check for error attention events if the driver is rmmod'ed. If the driver is reloaded, as part of insmod initialization, then a fresh reset is always asserted to start clean and free of error attention events. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-6-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9386e7b44750..2cb327efd57d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3938,6 +3938,9 @@ void lpfc_poll_eratt(struct timer_list *t) if (!(phba->hba_flag & HBA_SETUP)) return; + if (phba->pport->load_flag & FC_UNLOADING) + return; + /* Here we will also keep track of interrupts per sec of the hba */ sli_intr = phba->sli.slistat.sli_intr; From 349b1e2c1bdaf0bd00ac5065593563dbf6426fa6 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:21 -0700 Subject: [PATCH 0665/7721] scsi: lpfc: Refactor and clean up mailbox command memory free A lot of repeated clean up code exists when freeing mailbox commands in lpfc_mem_free_all(). Introduce a lpfc_mem_free_sli_mbox() helper routine to refactor the copy-paste code. Additionally, reinitialize the mailbox command structure context pointers to NULL in lpfc_sli4_mbox_cmd_free(). Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-7-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_mbox.c | 4 +++- drivers/scsi/lpfc/lpfc_mem.c | 45 ++++++++++++++++++++--------------- drivers/scsi/lpfc/lpfc_sli.c | 6 +++++ drivers/scsi/lpfc/lpfc_sli.h | 8 ++++--- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 0dfdc0c4c08c..b5ab44234f20 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1814,7 +1814,9 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, mbox->sge_array->addr[sgentry], phyaddr); } - /* Free the sge address array memory */ + /* Reinitialize the context pointers to avoid stale usage. */ + mbox->ctx_buf = NULL; + mbox->context3 = NULL; kfree(mbox->sge_array); /* Finally, free the mailbox command itself */ mempool_free(mbox, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 89cbeba06aea..ef6e5256a35e 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -48,6 +48,29 @@ #define LPFC_RRQ_POOL_SIZE 256 /* max elements in non-DMA pool */ #define LPFC_MBX_POOL_SIZE 256 /* max elements in MBX non-DMA pool */ +/* lpfc_mbox_free_sli_mbox + * + * @phba: HBA to free memory for + * @mbox: mailbox command to free + * + * This routine detects the mbox type and calls the correct + * free routine to fully release all associated memory. + */ +static void +lpfc_mem_free_sli_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) +{ + /* Detect if the caller's mbox is an SLI4_CONFIG type. If so, this + * mailbox type requires a different cleanup routine. Otherwise, the + * mailbox is just an mbuf and mem_pool release. + */ + if (phba->sli_rev == LPFC_SLI_REV4 && + bf_get(lpfc_mqe_command, &mbox->u.mqe) == MBX_SLI4_CONFIG) { + lpfc_sli4_mbox_cmd_free(phba, mbox); + } else { + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + } +} + int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { size_t bytes; @@ -288,27 +311,16 @@ lpfc_mem_free_all(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; LPFC_MBOXQ_t *mbox, *next_mbox; - struct lpfc_dmabuf *mp; /* Free memory used in mailbox queue back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); } /* Free memory used in mailbox cmpl list back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) { - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); } /* Free the active mailbox command back to the mailbox memory pool */ spin_lock_irq(&phba->hbalock); @@ -316,12 +328,7 @@ lpfc_mem_free_all(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); if (psli->mbox_active) { mbox = psli->mbox_active; - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); psli->mbox_active = NULL; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2cb327efd57d..bfbc23248692 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -22170,6 +22170,12 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, * The data will be truncated if datasz is not large enough. * Version 1 is not supported with Embedded mbox cmd, so we must use version 0. * Returns the actual bytes read from the object. + * + * This routine is hard coded to use a poll completion. Unlike other + * sli4_config mailboxes, it uses lpfc_mbuf memory which is not + * cleaned up in lpfc_sli4_cmd_mbox_free. If this routine is modified + * to use interrupt-based completions, code is needed to fully cleanup + * the memory. */ int lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap, diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index cd33dfec758c..14b8b5a3addf 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -182,9 +182,11 @@ typedef struct lpfcMboxq { struct lpfc_mqe mqe; } u; struct lpfc_vport *vport; /* virtual port pointer */ - void *ctx_ndlp; /* caller ndlp information */ - void *ctx_buf; /* caller buffer information */ - void *context3; + void *ctx_ndlp; /* an lpfc_nodelist pointer */ + void *ctx_buf; /* an lpfc_dmabuf pointer */ + void *context3; /* a generic pointer. Code must + * accommodate the actual datatype. + */ void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); uint8_t mbox_flag; From e6af45218755fa5ad29b3f0cbb37e299af723da0 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:22 -0700 Subject: [PATCH 0666/7721] scsi: lpfc: Enhance driver logging for selected discovery events Typically, debugging discovery issues requires the ndlp reference count, nlp flags, transport flags, and the io tag for root cause analysis. Modify important discovery log messages to include one or more of these attributes to aid in debugging and support. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-8-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 49 +++++++++++++++++++++++------------- drivers/scsi/lpfc/lpfc_sli.c | 11 +++++--- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0829fe6ddff8..f04326db8c19 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2062,8 +2062,9 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* PLOGI completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0102 PLOGI completes to NPort x%06x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_fc4_type, + "IoTag x%x Data: x%x x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + ndlp->nlp_fc4_type, ulp_status, ulp_word4, disc, vport->num_disc_nodes); @@ -2362,9 +2363,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* PRLI completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0103 PRLI completes to NPort x%06x " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x x%x\n", ndlp->nlp_DID, ulp_status, ulp_word4, - vport->num_disc_nodes, ndlp->fc4_prli_sent); + vport->num_disc_nodes, ndlp->fc4_prli_sent, + ndlp->fc4_xpt_flags); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) @@ -2805,7 +2807,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; int disc; - u32 ulp_status, ulp_word4, tmo; + u32 ulp_status, ulp_word4, tmo, iotag; bool release_node = false; /* we pass cmdiocb to state machine which needs rspiocb as well */ @@ -2818,9 +2820,11 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (phba->sli_rev == LPFC_SLI_REV4) { tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); } else { irsp = &rspiocb->iocb; tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -2838,9 +2842,11 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* ADISC completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0104 ADISC completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, ulp_status, ulp_word4, + "IoTag x%x Data: x%x x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + ulp_status, ulp_word4, tmo, disc, vport->num_disc_nodes); + /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { spin_lock_irq(&ndlp->lock); @@ -3001,7 +3007,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, int wake_up_waiter = 0; u32 ulp_status; u32 ulp_word4; - u32 tmo; + u32 tmo, iotag; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->rsp_iocb = rspiocb; @@ -3011,9 +3017,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (phba->sli_rev == LPFC_SLI_REV4) { tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); } else { irsp = &rspiocb->iocb; tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; } spin_lock_irq(&ndlp->lock); @@ -3032,9 +3040,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* LOGO completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " - "refcnt %d nflags x%x Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, - ulp_status, ulp_word4, + "IoTag x%x refcnt %d nflags x%x xflags x%x " + "Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->fc4_xpt_flags, ulp_status, ulp_word4, tmo, vport->num_disc_nodes); if (lpfc_els_chk_latt(vport)) { @@ -5075,16 +5085,19 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (logerr) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0137 No retry ELS command x%x to remote " - "NPORT x%x: Out of Resources: Error:x%x/%x\n", - cmd, did, ulp_status, - ulp_word4); + "NPORT x%x: Out of Resources: Error:x%x/%x " + "IoTag x%x\n", + cmd, did, ulp_status, ulp_word4, + cmdiocb->iotag); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0108 No retry ELS command x%x to remote " - "NPORT x%x Retried:%d Error:x%x/%x\n", - cmd, did, cmdiocb->retry, ulp_status, - ulp_word4); + "0108 No retry ELS command x%x to remote " + "NPORT x%x Retried:%d Error:x%x/%x " + "IoTag x%x nflags x%x\n", + cmd, did, cmdiocb->retry, ulp_status, + ulp_word4, cmdiocb->iotag, + (ndlp ? ndlp->nlp_flag : 0)); } return 0; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index bfbc23248692..46e6f807d1ca 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2995,8 +2995,9 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_MBOX | LOG_SLI, - "0010 UNREG_LOGIN vpi:%x " + vport, KERN_INFO, + LOG_MBOX | LOG_SLI | LOG_NODE, + "0010 UNREG_LOGIN vpi:x%x " "rpi:%x DID:%x defer x%x flg x%x " "x%px\n", vport->vpi, ndlp->nlp_rpi, @@ -3012,7 +3013,8 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_DISCOVERY, + vport, KERN_INFO, + LOG_MBOX | LOG_SLI | LOG_NODE, "4111 UNREG cmpl deferred " "clr x%x on " "NPort x%x Data: x%x x%px\n", @@ -10144,11 +10146,12 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, spin_unlock_irqrestore(&phba->hbalock, iflags); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0354 Mbox cmd issue - Enqueue Data: " - "x%x (x%x/x%x) x%x x%x x%x\n", + "x%x (x%x/x%x) x%x x%x x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0xffffff, bf_get(lpfc_mqe_command, &mboxq->u.mqe), lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + mboxq->u.mb.un.varUnregLogin.rpi, phba->pport->port_state, psli->sli_flag, MBX_NOWAIT); /* Wake up worker thread to transport mailbox command from head */ From c855e02b57edfc1b2fd42468e9224f9cf0de1e9e Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:23 -0700 Subject: [PATCH 0667/7721] scsi: lpfc: Update lpfc version to 14.2.0.16 Update lpfc version to 14.2.0.16. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-9-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 88068834cab9..b7d39e2f19fc 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.15" +#define LPFC_DRIVER_VERSION "14.2.0.16" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From 1f86b0d9c76c7e0a1a951850b9f251cc6e248279 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 31 Oct 2023 12:12:24 -0700 Subject: [PATCH 0668/7721] scsi: lpfc: Copyright updates for 14.2.0.16 patches Update copyrights to 2023 for files modified in the 14.2.0.16 patch set. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20231031191224.150862-10-justintee8345@gmail.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_mbox.c | 2 +- drivers/scsi/lpfc/lpfc_mem.c | 2 +- drivers/scsi/lpfc/lpfc_sli.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index b5ab44234f20..cadcd16494e1 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ef6e5256a35e..2697da3248b3 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 14b8b5a3addf..c911a39cb46b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * From 4f6dd2a4bf378bc4d169296739ea7d6972c0d858 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Wed, 1 Nov 2023 18:58:36 -0700 Subject: [PATCH 0669/7721] scsi: ufs: ufs-sysfs: Expose UFS power info Having UFS power info available in sysfs makes it easier to tell the state of the link during runtime considering we have a bunch of power saving features and various combinations for backward compatibility. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1698890324-7374-1-git-send-email-quic_cang@quicinc.com Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- Documentation/ABI/testing/sysfs-driver-ufs | 49 +++++++++ drivers/ufs/core/ufs-sysfs.c | 120 +++++++++++++++++++++ include/ufs/unipro.h | 4 +- 3 files changed, 171 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs index 0c7efaf62de0..b73067bb5ea2 100644 --- a/Documentation/ABI/testing/sysfs-driver-ufs +++ b/Documentation/ABI/testing/sysfs-driver-ufs @@ -1223,6 +1223,55 @@ Description: This file shows the total latency (in micro seconds) of write The file is read only. +What: /sys/bus/platform/drivers/ufshcd/*/power_info/lane +What: /sys/bus/platform/devices/*.ufs/power_info/lane +Date: September 2023 +Contact: Can Guo +Description: This file shows how many lanes are enabled on the UFS link, + i.e., an output 2 means UFS link is operating with 2 lanes. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/mode +What: /sys/bus/platform/devices/*.ufs/power_info/mode +Date: September 2023 +Contact: Can Guo +Description: This file shows the PA power mode of UFS. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/rate +What: /sys/bus/platform/devices/*.ufs/power_info/rate +Date: September 2023 +Contact: Can Guo +Description: This file shows the speed rate of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/gear +What: /sys/bus/platform/devices/*.ufs/power_info/gear +Date: September 2023 +Contact: Can Guo +Description: This file shows the gear of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/dev_pm +What: /sys/bus/platform/devices/*.ufs/power_info/dev_pm +Date: September 2023 +Contact: Can Guo +Description: This file shows the UFS device power mode. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/link_state +What: /sys/bus/platform/devices/*.ufs/power_info/link_state +Date: September 2023 +Contact: Can Guo +Description: This file shows the state of UFS link. + + The file is read only. + What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/wb_presv_us_en What: /sys/bus/platform/devices/*.ufs/device_descriptor/wb_presv_us_en Date: June 2020 diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index c95906443d5f..05b10ca90b50 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -7,9 +7,56 @@ #include #include +#include #include "ufs-sysfs.h" #include "ufshcd-priv.h" +static const char *ufs_pa_pwr_mode_to_string(enum ufs_pa_pwr_mode mode) +{ + switch (mode) { + case FAST_MODE: return "FAST_MODE"; + case SLOW_MODE: return "SLOW_MODE"; + case FASTAUTO_MODE: return "FASTAUTO_MODE"; + case SLOWAUTO_MODE: return "SLOWAUTO_MODE"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_rate_to_string(enum ufs_hs_gear_rate rate) +{ + switch (rate) { + case PA_HS_MODE_A: return "HS_RATE_A"; + case PA_HS_MODE_B: return "HS_RATE_B"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_pwm_gear_to_string(enum ufs_pwm_gear_tag gear) +{ + switch (gear) { + case UFS_PWM_G1: return "PWM_GEAR1"; + case UFS_PWM_G2: return "PWM_GEAR2"; + case UFS_PWM_G3: return "PWM_GEAR3"; + case UFS_PWM_G4: return "PWM_GEAR4"; + case UFS_PWM_G5: return "PWM_GEAR5"; + case UFS_PWM_G6: return "PWM_GEAR6"; + case UFS_PWM_G7: return "PWM_GEAR7"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear) +{ + switch (gear) { + case UFS_HS_G1: return "HS_GEAR1"; + case UFS_HS_G2: return "HS_GEAR2"; + case UFS_HS_G3: return "HS_GEAR3"; + case UFS_HS_G4: return "HS_GEAR4"; + case UFS_HS_G5: return "HS_GEAR5"; + default: return "UNKNOWN"; + } +} + static const char *ufshcd_uic_link_state_to_string( enum uic_link_state state) { @@ -628,6 +675,78 @@ static const struct attribute_group ufs_sysfs_monitor_group = { .attrs = ufs_sysfs_monitor_attrs, }; +static ssize_t lane_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", hba->pwr_info.lane_rx); +} + +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_pa_pwr_mode_to_string(hba->pwr_info.pwr_rx)); +} + +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_hs_gear_rate_to_string(hba->pwr_info.hs_rate)); +} + +static ssize_t gear_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", hba->pwr_info.hs_rate ? + ufs_hs_gear_to_string(hba->pwr_info.gear_rx) : + ufs_pwm_gear_to_string(hba->pwr_info.gear_rx)); +} + +static ssize_t dev_pm_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string(hba->curr_dev_pwr_mode)); +} + +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string(hba->uic_link_state)); +} + +static DEVICE_ATTR_RO(lane); +static DEVICE_ATTR_RO(mode); +static DEVICE_ATTR_RO(rate); +static DEVICE_ATTR_RO(gear); +static DEVICE_ATTR_RO(dev_pm); +static DEVICE_ATTR_RO(link_state); + +static struct attribute *ufs_power_info_attrs[] = { + &dev_attr_lane.attr, + &dev_attr_mode.attr, + &dev_attr_rate.attr, + &dev_attr_gear.attr, + &dev_attr_dev_pm.attr, + &dev_attr_link_state.attr, + NULL +}; + +static const struct attribute_group ufs_sysfs_power_info_group = { + .name = "power_info", + .attrs = ufs_power_info_attrs, +}; + static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, u8 desc_index, @@ -1233,6 +1352,7 @@ static const struct attribute_group *ufs_sysfs_groups[] = { &ufs_sysfs_default_group, &ufs_sysfs_capabilities_group, &ufs_sysfs_monitor_group, + &ufs_sysfs_power_info_group, &ufs_sysfs_device_descriptor_group, &ufs_sysfs_interconnect_descriptor_group, &ufs_sysfs_geometry_descriptor_group, diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index 256eb3a43f54..360e1245fb40 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -193,7 +193,7 @@ #define DME_LocalAFC0ReqTimeOutVal 0xD043 /* PA power modes */ -enum { +enum ufs_pa_pwr_mode { FAST_MODE = 1, SLOW_MODE = 2, FASTAUTO_MODE = 4, @@ -205,7 +205,7 @@ enum { #define PWRMODE_RX_OFFSET 4 /* PA TX/RX Frequency Series */ -enum { +enum ufs_hs_gear_rate { PA_HS_MODE_A = 1, PA_HS_MODE_B = 2, }; From 6a965ee1892a7a44f6d8f4a0b9fb5f775a8b4ccb Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Thu, 19 Oct 2023 17:37:06 +0200 Subject: [PATCH 0670/7721] scsi: mpt3sas: Suppress a warning in debug kernel The mpt3sas_ctl_exit() should be called after communication with the controller stops but currently it may cause false warnings about not released memory. Fix this by letting mpt3sas_ctl_exit() handle misc driver release per driver and release DMA in mpt3sas_ctl_release() per ioc. Signed-off-by: Tomas Henzl Link: https://lore.kernel.org/r/20231019153706.7967-1-thenzl@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 1 + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 42 ++++++++++++++++------------ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1 + 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index c672f3a1c67d..6d0bc8c66700 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1981,6 +1981,7 @@ extern const struct attribute_group *mpt3sas_host_groups[]; extern const struct attribute_group *mpt3sas_dev_groups[]; void mpt3sas_ctl_init(ushort hbas_to_enumerate); void mpt3sas_ctl_exit(ushort hbas_to_enumerate); +void mpt3sas_ctl_release(struct MPT3SAS_ADAPTER *ioc); u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc); diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index efdb8178db32..147cb7088d55 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -4156,6 +4156,30 @@ mpt3sas_ctl_init(ushort hbas_to_enumerate) init_waitqueue_head(&ctl_poll_wait); } +/** + * mpt3sas_ctl_release - release dma for ctl + * @ioc: per adapter object + */ +void +mpt3sas_ctl_release(struct MPT3SAS_ADAPTER *ioc) +{ + int i; + + /* free memory associated to diag buffers */ + for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { + if (!ioc->diag_buffer[i]) + continue; + dma_free_coherent(&ioc->pdev->dev, + ioc->diag_buffer_sz[i], + ioc->diag_buffer[i], + ioc->diag_buffer_dma[i]); + ioc->diag_buffer[i] = NULL; + ioc->diag_buffer_status[i] = 0; + } + + kfree(ioc->event_log); +} + /** * mpt3sas_ctl_exit - exit point for ctl * @hbas_to_enumerate: ? @@ -4163,25 +4187,7 @@ mpt3sas_ctl_init(ushort hbas_to_enumerate) void mpt3sas_ctl_exit(ushort hbas_to_enumerate) { - struct MPT3SAS_ADAPTER *ioc; - int i; - list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { - - /* free memory associated to diag buffers */ - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!ioc->diag_buffer[i]) - continue; - dma_free_coherent(&ioc->pdev->dev, - ioc->diag_buffer_sz[i], - ioc->diag_buffer[i], - ioc->diag_buffer_dma[i]); - ioc->diag_buffer[i] = NULL; - ioc->diag_buffer_status[i] = 0; - } - - kfree(ioc->event_log); - } if (hbas_to_enumerate != 1) misc_deregister(&ctl_dev); if (hbas_to_enumerate != 2) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5037e24596d8..51b5788da040 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -11331,6 +11331,7 @@ static void scsih_remove(struct pci_dev *pdev) } mpt3sas_base_detach(ioc); + mpt3sas_ctl_release(ioc); spin_lock(&gioc_lock); list_del(&ioc->list); spin_unlock(&gioc_lock); From 7c8601aea3a5e8a829a73cc9e572309c12ce9aca Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 14 Nov 2023 16:10:12 +0200 Subject: [PATCH 0671/7721] drm/i915: Fix fractional bpp handling in intel_link_bw_reduce_bpp() Convert crtc_state->pipe_bpp to U6.4 format as expected by the rest of the function. Fixes: 59a266f068b4 ("drm/i915/display: Store compressed bpp in U6.4 format") Cc: Ankit Nautiyal Cc: Suraj Kandpal Cc: Sui Jingfeng Reviewed-by: Ankit Nautiyal Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231114141012.603960-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_link_bw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index 02a0af2aa5ba..9c6d35a405a1 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -55,11 +55,11 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(state->base.dev); enum pipe max_bpp_pipe = INVALID_PIPE; struct intel_crtc *crtc; - int max_bpp = 0; + int max_bpp_x16 = 0; for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) { struct intel_crtc_state *crtc_state; - int link_bpp; + int link_bpp_x16; if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe)) continue; @@ -70,7 +70,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, return PTR_ERR(crtc_state); if (crtc_state->dsc.compression_enable) - link_bpp = crtc_state->dsc.compressed_bpp_x16; + link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16; else /* * TODO: for YUV420 the actual link bpp is only half @@ -78,10 +78,10 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, * is based on the pipe bpp value, set the actual link bpp * limit here once the MST BW allocation is fixed. */ - link_bpp = crtc_state->pipe_bpp; + link_bpp_x16 = to_bpp_x16(crtc_state->pipe_bpp); - if (link_bpp > max_bpp) { - max_bpp = link_bpp; + if (link_bpp_x16 > max_bpp_x16) { + max_bpp_x16 = link_bpp_x16; max_bpp_pipe = crtc->pipe; } } @@ -89,7 +89,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, if (max_bpp_pipe == INVALID_PIPE) return -ENOSPC; - limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1; + limits->max_bpp_x16[max_bpp_pipe] = max_bpp_x16 - 1; return intel_modeset_pipes_in_mask_early(state, reason, BIT(max_bpp_pipe)); From 6767b6f4b461149c2f5320daf6a2ac25e36dff9e Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 3 Nov 2023 15:43:03 -0700 Subject: [PATCH 0672/7721] dt-bindings: qcom,pdc: Add compatible for SM8550 Document the compatible for SM8550 PDC. Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Elliot Berman Link: https://lore.kernel.org/r/20231103224304.764730-1-quic_eberman@quicinc.com Signed-off-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/qcom,pdc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index 86d61896f591..8473afffce63 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -41,6 +41,7 @@ properties: - qcom,sm8250-pdc - qcom,sm8350-pdc - qcom,sm8450-pdc + - qcom,sm8550-pdc - const: qcom,pdc reg: From 8a5236acacb98f8d8dce1e440aa80caa9ffee29c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 6 Nov 2023 14:03:24 +0100 Subject: [PATCH 0673/7721] of: overlay: enable of_overlay_fdt_apply() kerneldoc of_overlay_fdt_apply() already has a kerneldoc-formatted documentation, except it is nor marked as such. Adding the second asterisk is enough for the documentation to take it into account correctly. Signed-off-by: Luca Ceresoli Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231106-of_overlay_fdt_apply-kerneldoc-v1-1-9a2d132bc6c1@bootlin.com Signed-off-by: Rob Herring --- drivers/of/overlay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index a9a292d6d59b..2ae7e9d24a64 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -964,7 +964,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs, return ret; } -/* +/** * of_overlay_fdt_apply() - Create and apply an overlay changeset * @overlay_fdt: pointer to overlay FDT * @overlay_fdt_size: number of bytes in @overlay_fdt From 7d646d5c50c60580530a5779bb250c3f277e8f77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 15:42:30 -0300 Subject: [PATCH 0674/7721] dt-bindings: power: fsl,scu-pd: Document imx8dl imx8dxl also contains the SCU PD block. Add an entry for 'fsl,imx8dl-scu-pd'. Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231113184230.14413-1-festevam@gmail.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/power/fsl,scu-pd.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml index 407b7cfec783..7a0f1a400868 100644 --- a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml +++ b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml @@ -20,6 +20,7 @@ properties: compatible: items: - enum: + - fsl,imx8dl-scu-pd - fsl,imx8qm-scu-pd - fsl,imx8qxp-scu-pd - const: fsl,scu-pd From 7b2bfd4ebf796ec4c5ff86b2531b26766ab2fd61 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 6 Sep 2023 12:18:05 +0300 Subject: [PATCH 0675/7721] net/mlx5: print change on SW reset semaphore returns busy While collecting crdump as part of fw_fatal health reporter dump the PF may fail to lock the SW reset semaphore. Change the print to indicate if it was due to another PF locked the semaphore already and so trying to lock the semaphore returned -EBUSY. Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c index 28d02749d3c4..7659ad21e6e5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c @@ -55,7 +55,10 @@ int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data) ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, MLX5_VSC_LOCK); if (ret) { - mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n"); + if (ret == -EBUSY) + mlx5_core_info(dev, "SW reset semaphore is already in use\n"); + else + mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n"); goto unlock_gw; } From cecf44ea1a1ffcc9158f746f391aa12fba953453 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 12 Jun 2023 19:09:25 +0300 Subject: [PATCH 0676/7721] net/mlx5: Allow sync reset flow when BF MGT interface device is present In sync reset flow, PF is checking that only devices of same device ID as itself present on the PCIe bridge, otherwise it will NACK the reset. Since the PCIe bridge connection to NIC card has to be 1 to 1, this is valid. However, the BlueField device may also expose another sub-device to the PCI called management interface, which only provides an ethernet channel between the host and the smart NIC. Allow sync reset flow also when management interface sub-device present when checking devices on the PCIe bridge. Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/fw_reset.c | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index b568988e92e3..4b8cb120362b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -325,6 +325,25 @@ static void mlx5_fw_live_patch_event(struct work_struct *work) mlx5_core_err(dev, "Failed to reload FW tracer\n"); } +static const struct pci_device_id mgt_ifc_device_ids[] = { + { PCI_VDEVICE(MELLANOX, 0xc2d2) }, /* BlueField1 MGT interface device ID */ + { PCI_VDEVICE(MELLANOX, 0xc2d3) }, /* BlueField2 MGT interface device ID */ + { PCI_VDEVICE(MELLANOX, 0xc2d4) }, /* BlueField3-Lx MGT interface device ID */ + { PCI_VDEVICE(MELLANOX, 0xc2d5) }, /* BlueField3 MGT interface device ID */ + { PCI_VDEVICE(MELLANOX, 0xc2d6) }, /* BlueField4 MGT interface device ID */ +}; + +static bool mlx5_is_mgt_ifc_pci_device(struct mlx5_core_dev *dev, u16 dev_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mgt_ifc_device_ids); ++i) + if (mgt_ifc_device_ids[i].device == dev_id) + return true; + + return false; +} + static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id) { struct pci_bus *bridge_bus = dev->pdev->bus; @@ -339,10 +358,15 @@ static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id) err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id); if (err) return pcibios_err_to_errno(err); - if (sdev_id != dev_id) { - mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id); - return -EPERM; - } + + if (sdev_id == dev_id) + continue; + + if (mlx5_is_mgt_ifc_pci_device(dev, sdev_id)) + continue; + + mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id); + return -EPERM; } return 0; } From 312eb3fd624495fef4f1c987e21a44a5e4fb6088 Mon Sep 17 00:00:00 2001 From: Amir Tzin Date: Wed, 6 Sep 2023 13:40:38 +0300 Subject: [PATCH 0677/7721] net/mlx5e: Some cleanup in mlx5e_tc_stats_matchall() Function mlx5e_tc_stats_matchall() is only called from one file: drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c Move it there and make it static as exposing it is unnecessary. Also variable cur_stats is redundant. Remove it and avoid superfluous copy. This patch does not change functionality. Reviewed-by: Patrisious Haddad Signed-off-by: Amir Tzin Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 14 ++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 16 ---------------- drivers/net/ethernet/mellanox/mlx5/core/en_tc.h | 2 -- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c index b12fe3c5a258..a55452c69f06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c @@ -147,6 +147,20 @@ mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv, } } +static void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv, + struct tc_cls_matchall_offload *ma) +{ + struct mlx5e_rep_priv *rpriv = priv->ppriv; + u64 dbytes; + u64 dpkts; + + dpkts = priv->stats.rep_stats.vport_rx_packets - rpriv->prev_vf_vport_stats.rx_packets; + dbytes = priv->stats.rep_stats.vport_rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes; + mlx5e_stats_copy_rep_stats(&rpriv->prev_vf_vport_stats, &priv->stats.rep_stats); + flow_stats_update(&ma->stats, dbytes, dpkts, 0, jiffies, + FLOW_ACTION_HW_STATS_DELAYED); +} + static int mlx5e_rep_setup_tc_cls_matchall(struct mlx5e_priv *priv, struct tc_cls_matchall_offload *ma) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9a5a5c2c7da9..25743a7eda26 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -5007,22 +5007,6 @@ int mlx5e_tc_delete_matchall(struct mlx5e_priv *priv, return apply_police_params(priv, 0, extack); } -void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv, - struct tc_cls_matchall_offload *ma) -{ - struct mlx5e_rep_priv *rpriv = priv->ppriv; - struct rtnl_link_stats64 cur_stats; - u64 dbytes; - u64 dpkts; - - mlx5e_stats_copy_rep_stats(&cur_stats, &priv->stats.rep_stats); - dpkts = cur_stats.rx_packets - rpriv->prev_vf_vport_stats.rx_packets; - dbytes = cur_stats.rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes; - rpriv->prev_vf_vport_stats = cur_stats; - flow_stats_update(&ma->stats, dbytes, dpkts, 0, jiffies, - FLOW_ACTION_HW_STATS_DELAYED); -} - static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h index adb39e30f90f..c24bda56b2b5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h @@ -203,8 +203,6 @@ int mlx5e_tc_configure_matchall(struct mlx5e_priv *priv, struct tc_cls_matchall_offload *f); int mlx5e_tc_delete_matchall(struct mlx5e_priv *priv, struct tc_cls_matchall_offload *f); -void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv, - struct tc_cls_matchall_offload *ma); struct mlx5e_encap_entry; void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, From 0f452a862a9f4eef172e9e66d828343b611190ee Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Oct 2023 16:17:22 -0700 Subject: [PATCH 0678/7721] net/mlx5: Annotate struct mlx5_fc_bulk with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct mlx5_fc_bulk. Cc: Saeed Mahameed Cc: Leon Romanovsky Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: netdev@vger.kernel.org Cc: linux-rdma@vger.kernel.org Link: https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci [1] Signed-off-by: Kees Cook Reviewed-by: Justin Stitt Reviewed-by: Gustavo A. R. Silva Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 17fe30a4c06c..0c26d707eed2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -539,7 +539,7 @@ struct mlx5_fc_bulk { u32 base_id; int bulk_len; unsigned long *bitmask; - struct mlx5_fc fcs[]; + struct mlx5_fc fcs[] __counted_by(bulk_len); }; static void mlx5_fc_init(struct mlx5_fc *counter, struct mlx5_fc_bulk *bulk, From 9454e56433924af11451795b67d084eb14c1027f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Oct 2023 16:17:30 -0700 Subject: [PATCH 0679/7721] net/mlx5: Annotate struct mlx5_flow_handle with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct mlx5_flow_handle. Cc: Saeed Mahameed Cc: Leon Romanovsky Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: netdev@vger.kernel.org Cc: linux-rdma@vger.kernel.org Link: https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci [1] Signed-off-by: Kees Cook Reviewed-by: Justin Stitt Reviewed-by: Gustavo A. R. Silva Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 4aed1768b85f..78eb6b7097e1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -181,7 +181,7 @@ struct mlx5_flow_rule { struct mlx5_flow_handle { int num_rules; - struct mlx5_flow_rule *rule[]; + struct mlx5_flow_rule *rule[] __counted_by(num_rules); }; /* Type of children is mlx5_flow_group */ From 10b49d0e76513a6f6890f321a10a2df0b779c761 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 11 Oct 2023 21:29:57 +0000 Subject: [PATCH 0680/7721] net/mlx5: simplify mlx5_set_driver_version string assignments In total, just assigning this version string takes: (1) strncpy()'s (5) strlen()'s (3) strncat()'s (1) snprintf()'s (4) max_t()'s Moreover, `strncpy` is deprecated [1] and `strncat` really shouldn't be used either [2]. With this in mind, let's simply use a single `snprintf`. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://elixir.bootlin.com/linux/v6.6-rc5/source/include/linux/fortify-string.h#L448 [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Cc: Kees Cook Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/main.c | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index a17152c1cbb2..bccf6e53556c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -219,7 +219,6 @@ static void mlx5_set_driver_version(struct mlx5_core_dev *dev) int driver_ver_sz = MLX5_FLD_SZ_BYTES(set_driver_version_in, driver_version); u8 in[MLX5_ST_SZ_BYTES(set_driver_version_in)] = {}; - int remaining_size = driver_ver_sz; char *string; if (!MLX5_CAP_GEN(dev, driver_version)) @@ -227,22 +226,9 @@ static void mlx5_set_driver_version(struct mlx5_core_dev *dev) string = MLX5_ADDR_OF(set_driver_version_in, in, driver_version); - strncpy(string, "Linux", remaining_size); - - remaining_size = max_t(int, 0, driver_ver_sz - strlen(string)); - strncat(string, ",", remaining_size); - - remaining_size = max_t(int, 0, driver_ver_sz - strlen(string)); - strncat(string, KBUILD_MODNAME, remaining_size); - - remaining_size = max_t(int, 0, driver_ver_sz - strlen(string)); - strncat(string, ",", remaining_size); - - remaining_size = max_t(int, 0, driver_ver_sz - strlen(string)); - - snprintf(string + strlen(string), remaining_size, "%u.%u.%u", - LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, - LINUX_VERSION_SUBLEVEL); + snprintf(string, driver_ver_sz, "Linux,%s,%u.%u.%u", + KBUILD_MODNAME, LINUX_VERSION_MAJOR, + LINUX_VERSION_PATCHLEVEL, LINUX_VERSION_SUBLEVEL); /*Send the command*/ MLX5_SET(set_driver_version_in, in, opcode, From 88e928b22930343eaad8eefdcba096cdba247ef2 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Tue, 24 Oct 2023 14:42:59 +0300 Subject: [PATCH 0681/7721] net/mlx5e: Access array with enum values instead of magic numbers Access the headers array using pedit_cmd enum values, and don't assume anything about their values. Signed-off-by: Gal Pressman Reviewed-by: Vlad Buslov Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c index 368a95fa77d3..b14cd62edffc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c @@ -48,7 +48,8 @@ mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv, struct pedit_headers_action *hdrs, struct netlink_ext_ack *extack) { - u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? 0 : 1; + u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? TCA_PEDIT_KEY_EX_CMD_SET : + TCA_PEDIT_KEY_EX_CMD_ADD; u8 htype = act->mangle.htype; int err = -EOPNOTSUPP; u32 mask, val, offset; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 25743a7eda26..4e1f339e381f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -3195,10 +3195,10 @@ static int offload_pedit_fields(struct mlx5e_priv *priv, headers_c = mlx5e_get_match_headers_criteria(*action_flags, &parse_attr->spec); headers_v = mlx5e_get_match_headers_value(*action_flags, &parse_attr->spec); - set_masks = &hdrs[0].masks; - add_masks = &hdrs[1].masks; - set_vals = &hdrs[0].vals; - add_vals = &hdrs[1].vals; + set_masks = &hdrs[TCA_PEDIT_KEY_EX_CMD_SET].masks; + add_masks = &hdrs[TCA_PEDIT_KEY_EX_CMD_ADD].masks; + set_vals = &hdrs[TCA_PEDIT_KEY_EX_CMD_SET].vals; + add_vals = &hdrs[TCA_PEDIT_KEY_EX_CMD_ADD].vals; for (i = 0; i < ARRAY_SIZE(fields); i++) { bool skip; From 330af90c4b43bdcc2a49b221bdd996afd3a0abb6 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 17 Jul 2023 11:40:21 -0700 Subject: [PATCH 0682/7721] net/mlx5: Refactor real time clock operation checks for PHC Check if the MTUTC register of the NIC can be modified before attempting to execute a real-time clock operation. Previous implementation aborted the real-time clock operation pre-emptively when the MTUTC register used to control the real-time clock was not modifiable, indicating real-time clock mode was not enabled on the NIC. The original control flow was confusing since the noop-if-RTC-disabled branch looked similar to an error handling guard clause. The purpose of this patch is purely for improving readability and should lead to no functional change. Signed-off-by: Rahul Rameshbabu Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/lib/clock.c | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index aa29f09e8356..c4f4d1c63463 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -266,9 +266,6 @@ static int mlx5_ptp_settime_real_time(struct mlx5_core_dev *mdev, { u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {}; - if (!mlx5_modify_mtutc_allowed(mdev)) - return 0; - if (ts->tv_sec < 0 || ts->tv_sec > U32_MAX || ts->tv_nsec < 0 || ts->tv_nsec > NSEC_PER_SEC) return -EINVAL; @@ -286,12 +283,15 @@ static int mlx5_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 struct mlx5_timer *timer = &clock->timer; struct mlx5_core_dev *mdev; unsigned long flags; - int err; mdev = container_of(clock, struct mlx5_core_dev, clock); - err = mlx5_ptp_settime_real_time(mdev, ts); - if (err) - return err; + + if (mlx5_modify_mtutc_allowed(mdev)) { + int err = mlx5_ptp_settime_real_time(mdev, ts); + + if (err) + return err; + } write_seqlock_irqsave(&clock->lock, flags); timecounter_init(&timer->tc, &timer->cycles, timespec64_to_ns(ts)); @@ -341,9 +341,6 @@ static int mlx5_ptp_adjtime_real_time(struct mlx5_core_dev *mdev, s64 delta) { u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {}; - if (!mlx5_modify_mtutc_allowed(mdev)) - return 0; - /* HW time adjustment range is checked. If out of range, settime instead */ if (!mlx5_is_mtutc_time_adj_cap(mdev, delta)) { struct timespec64 ts; @@ -367,13 +364,16 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) struct mlx5_timer *timer = &clock->timer; struct mlx5_core_dev *mdev; unsigned long flags; - int err; mdev = container_of(clock, struct mlx5_core_dev, clock); - err = mlx5_ptp_adjtime_real_time(mdev, delta); - if (err) - return err; + if (mlx5_modify_mtutc_allowed(mdev)) { + int err = mlx5_ptp_adjtime_real_time(mdev, delta); + + if (err) + return err; + } + write_seqlock_irqsave(&clock->lock, flags); timecounter_adjtime(&timer->tc, delta); mlx5_update_clock_info_page(mdev); @@ -391,9 +391,6 @@ static int mlx5_ptp_freq_adj_real_time(struct mlx5_core_dev *mdev, long scaled_p { u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {}; - if (!mlx5_modify_mtutc_allowed(mdev)) - return 0; - MLX5_SET(mtutc_reg, in, operation, MLX5_MTUTC_OPERATION_ADJUST_FREQ_UTC); if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_freq_adj_units)) { @@ -415,13 +412,15 @@ static int mlx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) struct mlx5_core_dev *mdev; unsigned long flags; u32 mult; - int err; mdev = container_of(clock, struct mlx5_core_dev, clock); - err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm); - if (err) - return err; + if (mlx5_modify_mtutc_allowed(mdev)) { + int err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm); + + if (err) + return err; + } mult = (u32)adjust_by_scaled_ppm(timer->nominal_c_mult, scaled_ppm); From 4395d9de4e21376dcd5592fdf9627beaa8609055 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 17 Jul 2023 12:10:42 -0700 Subject: [PATCH 0683/7721] net/mlx5: Initialize clock->ptp_info inside mlx5_init_timer_clock Configure the PHC inside mlx5_init_timer_clock for calling mlx5_ptp_settime later in the function. Would previously use mlx5_ptp_clock_info instance to invoke mlx5_ptp_settime to set the NIC real-time clock to be synchronized with the host system clock. Signed-off-by: Rahul Rameshbabu Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index c4f4d1c63463..ca7691930f6b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -1002,10 +1002,12 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev) { struct mlx5_clock *clock = &mdev->clock; + /* Configure the PHC */ + clock->ptp_info = mlx5_ptp_clock_info; + mlx5_timecounter_init(mdev); mlx5_init_clock_info(mdev); mlx5_init_overflow_period(clock); - clock->ptp_info = mlx5_ptp_clock_info; if (mlx5_real_time_mode(mdev)) { struct timespec64 ts; @@ -1036,11 +1038,10 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev) } seqlock_init(&clock->lock); - mlx5_init_timer_clock(mdev); INIT_WORK(&clock->pps_info.out_work, mlx5_pps_out); - /* Configure the PHC */ - clock->ptp_info = mlx5_ptp_clock_info; + /* Initialize the device clock */ + mlx5_init_timer_clock(mdev); /* Initialize 1PPS data structures */ mlx5_init_pps(mdev); From 78c1b26754d9df062c3c8e08f5d6427967e3ba4b Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Thu, 24 Aug 2023 20:29:50 -0700 Subject: [PATCH 0684/7721] net/mlx5: Convert scaled ppm values outside the s32 range for PHC frequency adjustments Represent scaled ppm as ppb to the device when the value in scaled ppm is not representable as a 32-bit signed integer. mlx5 devices only support a 32-bit field for the frequency adjustment value in units of either scaled ppm or ppb. Since mlx5 devices only support a 32-bit field for the frequency adjustment value independent of unit used, limit the maximum frequency adjustment to S32_MAX ppb. Signed-off-by: Rahul Rameshbabu Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index ca7691930f6b..1daa4b019513 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -393,10 +393,12 @@ static int mlx5_ptp_freq_adj_real_time(struct mlx5_core_dev *mdev, long scaled_p MLX5_SET(mtutc_reg, in, operation, MLX5_MTUTC_OPERATION_ADJUST_FREQ_UTC); - if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_freq_adj_units)) { + if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_freq_adj_units) && + scaled_ppm <= S32_MAX && scaled_ppm >= S32_MIN) { + /* HW scaled_ppm support on mlx5 devices only supports a 32-bit value */ MLX5_SET(mtutc_reg, in, freq_adj_units, MLX5_MTUTC_FREQ_ADJ_UNITS_SCALED_PPM); - MLX5_SET(mtutc_reg, in, freq_adjustment, scaled_ppm); + MLX5_SET(mtutc_reg, in, freq_adjustment, (s32)scaled_ppm); } else { MLX5_SET(mtutc_reg, in, freq_adj_units, MLX5_MTUTC_FREQ_ADJ_UNITS_PPB); MLX5_SET(mtutc_reg, in, freq_adjustment, scaled_ppm_to_ppb(scaled_ppm)); From 4aea6a6d61cd6e3df9ed98345638abad1b1e5276 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Thu, 30 Mar 2023 15:05:38 -0700 Subject: [PATCH 0685/7721] net/mlx5: Query maximum frequency adjustment of the PTP hardware clock Some mlx5 devices do not support the default advertised maximum frequency adjustment value for the PTP hardware clock that is set by the driver. These devices need to be queried when initializing the clock functionality in order to get the maximum supported frequency adjustment value. This value can be greater than the minimum supported frequency adjustment across mlx5 devices (50 million ppb). Signed-off-by: Rahul Rameshbabu Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/lib/clock.c | 22 +++++++++++++++++++ include/linux/mlx5/mlx5_ifc.h | 5 ++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 1daa4b019513..cac60a841e1d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -1000,6 +1000,25 @@ static void mlx5_init_clock_info(struct mlx5_core_dev *mdev) info->frac = timer->tc.frac; } +static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev) +{ + struct mlx5_clock *clock = &mdev->clock; + u32 out[MLX5_ST_SZ_DW(mtutc_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {}; + u8 log_max_freq_adjustment = 0; + int err; + + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), + MLX5_REG_MTUTC, 0, 0); + if (!err) + log_max_freq_adjustment = + MLX5_GET(mtutc_reg, out, log_max_freq_adjustment); + + if (log_max_freq_adjustment) + clock->ptp_info.max_adj = + min(S32_MAX, 1 << log_max_freq_adjustment); +} + static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev) { struct mlx5_clock *clock = &mdev->clock; @@ -1007,6 +1026,9 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev) /* Configure the PHC */ clock->ptp_info = mlx5_ptp_clock_info; + if (MLX5_CAP_MCAM_REG(mdev, mtutc)) + mlx5_init_timer_max_freq_adjustment(mdev); + mlx5_timecounter_init(mdev); mlx5_init_clock_info(mdev); mlx5_init_overflow_period(clock); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 6f3631425f38..ce2e71cd6d2a 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -10103,7 +10103,10 @@ enum { struct mlx5_ifc_mtutc_reg_bits { u8 reserved_at_0[0x5]; u8 freq_adj_units[0x3]; - u8 reserved_at_8[0x14]; + u8 reserved_at_8[0x3]; + u8 log_max_freq_adjustment[0x5]; + + u8 reserved_at_10[0xc]; u8 operation[0x4]; u8 freq_adjustment[0x20]; From b2a62e56b173ceb153cc1651189c537ebb5345cc Mon Sep 17 00:00:00 2001 From: Or Har-Toov Date: Mon, 16 Oct 2023 18:00:00 +0300 Subject: [PATCH 0686/7721] net/mlx5e: Add local loopback counter to vport rep stats Add counter for number of unicast, multicast and broadcast packets/ octets that were loopback. Signed-off-by: Or Har-Toov Reviewed-by: Patrisious Haddad Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 26 ++++++++++++++++++- .../ethernet/mellanox/mlx5/core/en_stats.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 693e55b010d9..2fd96471554b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -108,8 +108,18 @@ static const struct counter_desc vport_rep_stats_desc[] = { tx_vport_rdma_multicast_bytes) }, }; +static const struct counter_desc vport_rep_loopback_stats_desc[] = { + { MLX5E_DECLARE_STAT(struct mlx5e_rep_stats, + vport_loopback_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_rep_stats, + vport_loopback_bytes) }, +}; + #define NUM_VPORT_REP_SW_COUNTERS ARRAY_SIZE(sw_rep_stats_desc) #define NUM_VPORT_REP_HW_COUNTERS ARRAY_SIZE(vport_rep_stats_desc) +#define NUM_VPORT_REP_LOOPBACK_COUNTERS(dev) \ + (MLX5_CAP_GEN(dev, vport_counter_local_loopback) ? \ + ARRAY_SIZE(vport_rep_loopback_stats_desc) : 0) static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(sw_rep) { @@ -153,7 +163,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw_rep) static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(vport_rep) { - return NUM_VPORT_REP_HW_COUNTERS; + return NUM_VPORT_REP_HW_COUNTERS + + NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev); } static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport_rep) @@ -162,6 +173,9 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport_rep) for (i = 0; i < NUM_VPORT_REP_HW_COUNTERS; i++) strcpy(data + (idx++) * ETH_GSTRING_LEN, vport_rep_stats_desc[i].format); + for (i = 0; i < NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev); i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + vport_rep_loopback_stats_desc[i].format); return idx; } @@ -172,6 +186,9 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(vport_rep) for (i = 0; i < NUM_VPORT_REP_HW_COUNTERS; i++) data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.rep_stats, vport_rep_stats_desc, i); + for (i = 0; i < NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev); i++) + data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.rep_stats, + vport_rep_loopback_stats_desc, i); return idx; } @@ -243,6 +260,13 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep) rep_stats->tx_vport_rdma_multicast_bytes = MLX5_GET_CTR(out, received_ib_multicast.octets); + if (MLX5_CAP_GEN(priv->mdev, vport_counter_local_loopback)) { + rep_stats->vport_loopback_packets = + MLX5_GET_CTR(out, local_loopback.packets); + rep_stats->vport_loopback_bytes = + MLX5_GET_CTR(out, local_loopback.octets); + } + out: kvfree(out); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index 477c547dcc04..12b3607afecd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -476,6 +476,8 @@ struct mlx5e_rep_stats { u64 tx_vport_rdma_multicast_packets; u64 rx_vport_rdma_multicast_bytes; u64 tx_vport_rdma_multicast_bytes; + u64 vport_loopback_packets; + u64 vport_loopback_bytes; }; struct mlx5e_stats { From 23ec6972865b59d2f58a1aafd12b108b4dd6caa1 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Mon, 9 Oct 2023 09:17:44 +0300 Subject: [PATCH 0687/7721] net/mlx5e: Remove early assignment to netdev->features The netdev->features is initialized to netdev->hw_features at a later point in the flow. Remove any redundant earlier assignment. Signed-off-by: Tariq Toukan Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index ea58c6917433..3aecdf099a2f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -5244,7 +5244,6 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) netdev->gso_partial_features |= NETIF_F_GSO_UDP_L4; netdev->hw_features |= NETIF_F_GSO_UDP_L4; - netdev->features |= NETIF_F_GSO_UDP_L4; mlx5_query_port_fcs(mdev, &fcs_supported, &fcs_enabled); From 67420501e8681ae18f9f0ea0a69cd2f432100e70 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:05:57 -0800 Subject: [PATCH 0688/7721] bpf: generalize reg_set_min_max() to handle non-const register comparisons Generalize bounds adjustment logic of reg_set_min_max() to handle not just register vs constant case, but in general any register vs any register cases. For most of the operations it's trivial extension based on range vs range comparison logic, we just need to properly pick min/max of a range to compare against min/max of the other range. For BPF_JSET we keep the original capabilities, just make sure JSET is integrated in the common framework. This is manifested in the internal-only BPF_JSET + BPF_X "opcode" to allow for simpler and more uniform rev_opcode() handling. See the code for details. This allows to reuse the same code exactly both for TRUE and FALSE branches without explicitly handling both conditions with custom code. Note also that now we don't need a special handling of BPF_JEQ/BPF_JNE case none of the registers are constants. This is now just a normal generic case handled by reg_set_min_max(). To make tnum handling cleaner, tnum_with_subreg() helper is added, as that's a common operator when dealing with 32-bit subregister bounds. This keeps the overall logic much less noisy when it comes to tnums. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231112010609.848406-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/tnum.h | 4 + kernel/bpf/tnum.c | 7 +- kernel/bpf/verifier.c | 362 +++++++++++++++++++----------------------- 3 files changed, 170 insertions(+), 203 deletions(-) diff --git a/include/linux/tnum.h b/include/linux/tnum.h index 1c3948a1d6ad..3c13240077b8 100644 --- a/include/linux/tnum.h +++ b/include/linux/tnum.h @@ -106,6 +106,10 @@ int tnum_sbin(char *str, size_t size, struct tnum a); struct tnum tnum_subreg(struct tnum a); /* Returns the tnum with the lower 32-bit subreg cleared */ struct tnum tnum_clear_subreg(struct tnum a); +/* Returns the tnum with the lower 32-bit subreg in *reg* set to the lower + * 32-bit subreg in *subreg* + */ +struct tnum tnum_with_subreg(struct tnum reg, struct tnum subreg); /* Returns the tnum with the lower 32-bit subreg set to value */ struct tnum tnum_const_subreg(struct tnum a, u32 value); /* Returns true if 32-bit subreg @a is a known constant*/ diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c index 3d7127f439a1..f4c91c9b27d7 100644 --- a/kernel/bpf/tnum.c +++ b/kernel/bpf/tnum.c @@ -208,7 +208,12 @@ struct tnum tnum_clear_subreg(struct tnum a) return tnum_lshift(tnum_rshift(a, 32), 32); } +struct tnum tnum_with_subreg(struct tnum reg, struct tnum subreg) +{ + return tnum_or(tnum_clear_subreg(reg), tnum_subreg(subreg)); +} + struct tnum tnum_const_subreg(struct tnum a, u32 value) { - return tnum_or(tnum_clear_subreg(a), tnum_const(value)); + return tnum_with_subreg(a, tnum_const(value)); } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9ae6eae13471..39ce141c55d3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14453,6 +14453,158 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg return is_scalar_branch_taken(reg1, reg2, opcode, is_jmp32); } +/* Opcode that corresponds to a *false* branch condition. + * E.g., if r1 < r2, then reverse (false) condition is r1 >= r2 + */ +static u8 rev_opcode(u8 opcode) +{ + switch (opcode) { + case BPF_JEQ: return BPF_JNE; + case BPF_JNE: return BPF_JEQ; + /* JSET doesn't have it's reverse opcode in BPF, so add + * BPF_X flag to denote the reverse of that operation + */ + case BPF_JSET: return BPF_JSET | BPF_X; + case BPF_JSET | BPF_X: return BPF_JSET; + case BPF_JGE: return BPF_JLT; + case BPF_JGT: return BPF_JLE; + case BPF_JLE: return BPF_JGT; + case BPF_JLT: return BPF_JGE; + case BPF_JSGE: return BPF_JSLT; + case BPF_JSGT: return BPF_JSLE; + case BPF_JSLE: return BPF_JSGT; + case BPF_JSLT: return BPF_JSGE; + default: return 0; + } +} + +/* Refine range knowledge for 2 conditional operation. */ +static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, + u8 opcode, bool is_jmp32) +{ + struct tnum t; + u64 val; + +again: + switch (opcode) { + case BPF_JEQ: + if (is_jmp32) { + reg1->u32_min_value = max(reg1->u32_min_value, reg2->u32_min_value); + reg1->u32_max_value = min(reg1->u32_max_value, reg2->u32_max_value); + reg1->s32_min_value = max(reg1->s32_min_value, reg2->s32_min_value); + reg1->s32_max_value = min(reg1->s32_max_value, reg2->s32_max_value); + reg2->u32_min_value = reg1->u32_min_value; + reg2->u32_max_value = reg1->u32_max_value; + reg2->s32_min_value = reg1->s32_min_value; + reg2->s32_max_value = reg1->s32_max_value; + + t = tnum_intersect(tnum_subreg(reg1->var_off), tnum_subreg(reg2->var_off)); + reg1->var_off = tnum_with_subreg(reg1->var_off, t); + reg2->var_off = tnum_with_subreg(reg2->var_off, t); + } else { + reg1->umin_value = max(reg1->umin_value, reg2->umin_value); + reg1->umax_value = min(reg1->umax_value, reg2->umax_value); + reg1->smin_value = max(reg1->smin_value, reg2->smin_value); + reg1->smax_value = min(reg1->smax_value, reg2->smax_value); + reg2->umin_value = reg1->umin_value; + reg2->umax_value = reg1->umax_value; + reg2->smin_value = reg1->smin_value; + reg2->smax_value = reg1->smax_value; + + reg1->var_off = tnum_intersect(reg1->var_off, reg2->var_off); + reg2->var_off = reg1->var_off; + } + break; + case BPF_JNE: + /* we don't derive any new information for inequality yet */ + break; + case BPF_JSET: + if (!is_reg_const(reg2, is_jmp32)) + swap(reg1, reg2); + if (!is_reg_const(reg2, is_jmp32)) + break; + val = reg_const_value(reg2, is_jmp32); + /* BPF_JSET (i.e., TRUE branch, *not* BPF_JSET | BPF_X) + * requires single bit to learn something useful. E.g., if we + * know that `r1 & 0x3` is true, then which bits (0, 1, or both) + * are actually set? We can learn something definite only if + * it's a single-bit value to begin with. + * + * BPF_JSET | BPF_X (i.e., negation of BPF_JSET) doesn't have + * this restriction. I.e., !(r1 & 0x3) means neither bit 0 nor + * bit 1 is set, which we can readily use in adjustments. + */ + if (!is_power_of_2(val)) + break; + if (is_jmp32) { + t = tnum_or(tnum_subreg(reg1->var_off), tnum_const(val)); + reg1->var_off = tnum_with_subreg(reg1->var_off, t); + } else { + reg1->var_off = tnum_or(reg1->var_off, tnum_const(val)); + } + break; + case BPF_JSET | BPF_X: /* reverse of BPF_JSET, see rev_opcode() */ + if (!is_reg_const(reg2, is_jmp32)) + swap(reg1, reg2); + if (!is_reg_const(reg2, is_jmp32)) + break; + val = reg_const_value(reg2, is_jmp32); + if (is_jmp32) { + t = tnum_and(tnum_subreg(reg1->var_off), tnum_const(~val)); + reg1->var_off = tnum_with_subreg(reg1->var_off, t); + } else { + reg1->var_off = tnum_and(reg1->var_off, tnum_const(~val)); + } + break; + case BPF_JLE: + if (is_jmp32) { + reg1->u32_max_value = min(reg1->u32_max_value, reg2->u32_max_value); + reg2->u32_min_value = max(reg1->u32_min_value, reg2->u32_min_value); + } else { + reg1->umax_value = min(reg1->umax_value, reg2->umax_value); + reg2->umin_value = max(reg1->umin_value, reg2->umin_value); + } + break; + case BPF_JLT: + if (is_jmp32) { + reg1->u32_max_value = min(reg1->u32_max_value, reg2->u32_max_value - 1); + reg2->u32_min_value = max(reg1->u32_min_value + 1, reg2->u32_min_value); + } else { + reg1->umax_value = min(reg1->umax_value, reg2->umax_value - 1); + reg2->umin_value = max(reg1->umin_value + 1, reg2->umin_value); + } + break; + case BPF_JSLE: + if (is_jmp32) { + reg1->s32_max_value = min(reg1->s32_max_value, reg2->s32_max_value); + reg2->s32_min_value = max(reg1->s32_min_value, reg2->s32_min_value); + } else { + reg1->smax_value = min(reg1->smax_value, reg2->smax_value); + reg2->smin_value = max(reg1->smin_value, reg2->smin_value); + } + break; + case BPF_JSLT: + if (is_jmp32) { + reg1->s32_max_value = min(reg1->s32_max_value, reg2->s32_max_value - 1); + reg2->s32_min_value = max(reg1->s32_min_value + 1, reg2->s32_min_value); + } else { + reg1->smax_value = min(reg1->smax_value, reg2->smax_value - 1); + reg2->smin_value = max(reg1->smin_value + 1, reg2->smin_value); + } + break; + case BPF_JGE: + case BPF_JGT: + case BPF_JSGE: + case BPF_JSGT: + /* just reuse LE/LT logic above */ + opcode = flip_opcode(opcode); + swap(reg1, reg2); + goto again; + default: + return; + } +} + /* Adjusts the register min/max values in the case that the dst_reg and * src_reg are both SCALAR_VALUE registers (or we are simply doing a BPF_K * check, in which case we havea fake SCALAR_VALUE representing insn->imm). @@ -14465,13 +14617,6 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg1, struct bpf_reg_state *false_reg2, u8 opcode, bool is_jmp32) { - struct tnum false_32off, false_64off; - struct tnum true_32off, true_64off; - u64 uval; - u32 uval32; - s64 sval; - s32 sval32; - /* If either register is a pointer, we can't learn anything about its * variable offset from the compare (unless they were a pointer into * the same object, but we don't bother with that). @@ -14479,192 +14624,15 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg1, if (false_reg1->type != SCALAR_VALUE || false_reg2->type != SCALAR_VALUE) return; - /* we expect right-hand registers (src ones) to be constants, for now */ - if (!is_reg_const(false_reg2, is_jmp32)) { - opcode = flip_opcode(opcode); - swap(true_reg1, true_reg2); - swap(false_reg1, false_reg2); - } - if (!is_reg_const(false_reg2, is_jmp32)) - return; + /* fallthrough (FALSE) branch */ + regs_refine_cond_op(false_reg1, false_reg2, rev_opcode(opcode), is_jmp32); + reg_bounds_sync(false_reg1); + reg_bounds_sync(false_reg2); - false_32off = tnum_subreg(false_reg1->var_off); - false_64off = false_reg1->var_off; - true_32off = tnum_subreg(true_reg1->var_off); - true_64off = true_reg1->var_off; - uval = false_reg2->var_off.value; - uval32 = (u32)tnum_subreg(false_reg2->var_off).value; - sval = (s64)uval; - sval32 = (s32)uval32; - - switch (opcode) { - /* JEQ/JNE comparison doesn't change the register equivalence. - * - * r1 = r2; - * if (r1 == 42) goto label; - * ... - * label: // here both r1 and r2 are known to be 42. - * - * Hence when marking register as known preserve it's ID. - */ - case BPF_JEQ: - if (is_jmp32) { - __mark_reg32_known(true_reg1, uval32); - true_32off = tnum_subreg(true_reg1->var_off); - } else { - ___mark_reg_known(true_reg1, uval); - true_64off = true_reg1->var_off; - } - break; - case BPF_JNE: - if (is_jmp32) { - __mark_reg32_known(false_reg1, uval32); - false_32off = tnum_subreg(false_reg1->var_off); - } else { - ___mark_reg_known(false_reg1, uval); - false_64off = false_reg1->var_off; - } - break; - case BPF_JSET: - if (is_jmp32) { - false_32off = tnum_and(false_32off, tnum_const(~uval32)); - if (is_power_of_2(uval32)) - true_32off = tnum_or(true_32off, - tnum_const(uval32)); - } else { - false_64off = tnum_and(false_64off, tnum_const(~uval)); - if (is_power_of_2(uval)) - true_64off = tnum_or(true_64off, - tnum_const(uval)); - } - break; - case BPF_JGE: - case BPF_JGT: - { - if (is_jmp32) { - u32 false_umax = opcode == BPF_JGT ? uval32 : uval32 - 1; - u32 true_umin = opcode == BPF_JGT ? uval32 + 1 : uval32; - - false_reg1->u32_max_value = min(false_reg1->u32_max_value, - false_umax); - true_reg1->u32_min_value = max(true_reg1->u32_min_value, - true_umin); - } else { - u64 false_umax = opcode == BPF_JGT ? uval : uval - 1; - u64 true_umin = opcode == BPF_JGT ? uval + 1 : uval; - - false_reg1->umax_value = min(false_reg1->umax_value, false_umax); - true_reg1->umin_value = max(true_reg1->umin_value, true_umin); - } - break; - } - case BPF_JSGE: - case BPF_JSGT: - { - if (is_jmp32) { - s32 false_smax = opcode == BPF_JSGT ? sval32 : sval32 - 1; - s32 true_smin = opcode == BPF_JSGT ? sval32 + 1 : sval32; - - false_reg1->s32_max_value = min(false_reg1->s32_max_value, false_smax); - true_reg1->s32_min_value = max(true_reg1->s32_min_value, true_smin); - } else { - s64 false_smax = opcode == BPF_JSGT ? sval : sval - 1; - s64 true_smin = opcode == BPF_JSGT ? sval + 1 : sval; - - false_reg1->smax_value = min(false_reg1->smax_value, false_smax); - true_reg1->smin_value = max(true_reg1->smin_value, true_smin); - } - break; - } - case BPF_JLE: - case BPF_JLT: - { - if (is_jmp32) { - u32 false_umin = opcode == BPF_JLT ? uval32 : uval32 + 1; - u32 true_umax = opcode == BPF_JLT ? uval32 - 1 : uval32; - - false_reg1->u32_min_value = max(false_reg1->u32_min_value, - false_umin); - true_reg1->u32_max_value = min(true_reg1->u32_max_value, - true_umax); - } else { - u64 false_umin = opcode == BPF_JLT ? uval : uval + 1; - u64 true_umax = opcode == BPF_JLT ? uval - 1 : uval; - - false_reg1->umin_value = max(false_reg1->umin_value, false_umin); - true_reg1->umax_value = min(true_reg1->umax_value, true_umax); - } - break; - } - case BPF_JSLE: - case BPF_JSLT: - { - if (is_jmp32) { - s32 false_smin = opcode == BPF_JSLT ? sval32 : sval32 + 1; - s32 true_smax = opcode == BPF_JSLT ? sval32 - 1 : sval32; - - false_reg1->s32_min_value = max(false_reg1->s32_min_value, false_smin); - true_reg1->s32_max_value = min(true_reg1->s32_max_value, true_smax); - } else { - s64 false_smin = opcode == BPF_JSLT ? sval : sval + 1; - s64 true_smax = opcode == BPF_JSLT ? sval - 1 : sval; - - false_reg1->smin_value = max(false_reg1->smin_value, false_smin); - true_reg1->smax_value = min(true_reg1->smax_value, true_smax); - } - break; - } - default: - return; - } - - if (is_jmp32) { - false_reg1->var_off = tnum_or(tnum_clear_subreg(false_64off), - tnum_subreg(false_32off)); - true_reg1->var_off = tnum_or(tnum_clear_subreg(true_64off), - tnum_subreg(true_32off)); - reg_bounds_sync(false_reg1); - reg_bounds_sync(true_reg1); - } else { - false_reg1->var_off = false_64off; - true_reg1->var_off = true_64off; - reg_bounds_sync(false_reg1); - reg_bounds_sync(true_reg1); - } -} - -/* Regs are known to be equal, so intersect their min/max/var_off */ -static void __reg_combine_min_max(struct bpf_reg_state *src_reg, - struct bpf_reg_state *dst_reg) -{ - src_reg->umin_value = dst_reg->umin_value = max(src_reg->umin_value, - dst_reg->umin_value); - src_reg->umax_value = dst_reg->umax_value = min(src_reg->umax_value, - dst_reg->umax_value); - src_reg->smin_value = dst_reg->smin_value = max(src_reg->smin_value, - dst_reg->smin_value); - src_reg->smax_value = dst_reg->smax_value = min(src_reg->smax_value, - dst_reg->smax_value); - src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off, - dst_reg->var_off); - reg_bounds_sync(src_reg); - reg_bounds_sync(dst_reg); -} - -static void reg_combine_min_max(struct bpf_reg_state *true_src, - struct bpf_reg_state *true_dst, - struct bpf_reg_state *false_src, - struct bpf_reg_state *false_dst, - u8 opcode) -{ - switch (opcode) { - case BPF_JEQ: - __reg_combine_min_max(true_src, true_dst); - break; - case BPF_JNE: - __reg_combine_min_max(false_src, false_dst); - break; - } + /* jump (TRUE) branch */ + regs_refine_cond_op(true_reg1, true_reg2, opcode, is_jmp32); + reg_bounds_sync(true_reg1); + reg_bounds_sync(true_reg2); } static void mark_ptr_or_null_reg(struct bpf_func_state *state, @@ -14961,22 +14929,12 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, reg_set_min_max(&other_branch_regs[insn->dst_reg], &other_branch_regs[insn->src_reg], dst_reg, src_reg, opcode, is_jmp32); - - if (dst_reg->type == SCALAR_VALUE && - src_reg->type == SCALAR_VALUE && - !is_jmp32 && (opcode == BPF_JEQ || opcode == BPF_JNE)) { - /* Comparing for equality, we can combine knowledge */ - reg_combine_min_max(&other_branch_regs[insn->src_reg], - &other_branch_regs[insn->dst_reg], - src_reg, dst_reg, opcode); - } } else /* BPF_SRC(insn->code) == BPF_K */ { reg_set_min_max(&other_branch_regs[insn->dst_reg], src_reg /* fake one */, dst_reg, src_reg /* same fake one */, opcode, is_jmp32); } - if (BPF_SRC(insn->code) == BPF_X && src_reg->type == SCALAR_VALUE && src_reg->id && !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { From 96381879a370425a30b810906946f64c0726450e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:05:58 -0800 Subject: [PATCH 0689/7721] bpf: generalize is_scalar_branch_taken() logic Generalize is_branch_taken logic for SCALAR_VALUE register to handle cases when both registers are not constants. Previously supported vs cases are a natural subset of more generic vs set of cases. Generalized logic relies on straightforward segment intersection checks. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231112010609.848406-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 98 +++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 39ce141c55d3..f459ad99256e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14261,82 +14261,99 @@ static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_sta u8 opcode, bool is_jmp32) { struct tnum t1 = is_jmp32 ? tnum_subreg(reg1->var_off) : reg1->var_off; + struct tnum t2 = is_jmp32 ? tnum_subreg(reg2->var_off) : reg2->var_off; u64 umin1 = is_jmp32 ? (u64)reg1->u32_min_value : reg1->umin_value; u64 umax1 = is_jmp32 ? (u64)reg1->u32_max_value : reg1->umax_value; s64 smin1 = is_jmp32 ? (s64)reg1->s32_min_value : reg1->smin_value; s64 smax1 = is_jmp32 ? (s64)reg1->s32_max_value : reg1->smax_value; - u64 uval = is_jmp32 ? (u32)tnum_subreg(reg2->var_off).value : reg2->var_off.value; - s64 sval = is_jmp32 ? (s32)uval : (s64)uval; + u64 umin2 = is_jmp32 ? (u64)reg2->u32_min_value : reg2->umin_value; + u64 umax2 = is_jmp32 ? (u64)reg2->u32_max_value : reg2->umax_value; + s64 smin2 = is_jmp32 ? (s64)reg2->s32_min_value : reg2->smin_value; + s64 smax2 = is_jmp32 ? (s64)reg2->s32_max_value : reg2->smax_value; switch (opcode) { case BPF_JEQ: - if (tnum_is_const(t1)) - return !!tnum_equals_const(t1, uval); - else if (uval < umin1 || uval > umax1) + /* constants, umin/umax and smin/smax checks would be + * redundant in this case because they all should match + */ + if (tnum_is_const(t1) && tnum_is_const(t2)) + return t1.value == t2.value; + /* non-overlapping ranges */ + if (umin1 > umax2 || umax1 < umin2) return 0; - else if (sval < smin1 || sval > smax1) + if (smin1 > smax2 || smax1 < smin2) return 0; break; case BPF_JNE: - if (tnum_is_const(t1)) - return !tnum_equals_const(t1, uval); - else if (uval < umin1 || uval > umax1) + /* constants, umin/umax and smin/smax checks would be + * redundant in this case because they all should match + */ + if (tnum_is_const(t1) && tnum_is_const(t2)) + return t1.value != t2.value; + /* non-overlapping ranges */ + if (umin1 > umax2 || umax1 < umin2) return 1; - else if (sval < smin1 || sval > smax1) + if (smin1 > smax2 || smax1 < smin2) return 1; break; case BPF_JSET: - if ((~t1.mask & t1.value) & uval) + if (!is_reg_const(reg2, is_jmp32)) { + swap(reg1, reg2); + swap(t1, t2); + } + if (!is_reg_const(reg2, is_jmp32)) + return -1; + if ((~t1.mask & t1.value) & t2.value) return 1; - if (!((t1.mask | t1.value) & uval)) + if (!((t1.mask | t1.value) & t2.value)) return 0; break; case BPF_JGT: - if (umin1 > uval ) + if (umin1 > umax2) return 1; - else if (umax1 <= uval) + else if (umax1 <= umin2) return 0; break; case BPF_JSGT: - if (smin1 > sval) + if (smin1 > smax2) return 1; - else if (smax1 <= sval) + else if (smax1 <= smin2) return 0; break; case BPF_JLT: - if (umax1 < uval) + if (umax1 < umin2) return 1; - else if (umin1 >= uval) + else if (umin1 >= umax2) return 0; break; case BPF_JSLT: - if (smax1 < sval) + if (smax1 < smin2) return 1; - else if (smin1 >= sval) + else if (smin1 >= smax2) return 0; break; case BPF_JGE: - if (umin1 >= uval) + if (umin1 >= umax2) return 1; - else if (umax1 < uval) + else if (umax1 < umin2) return 0; break; case BPF_JSGE: - if (smin1 >= sval) + if (smin1 >= smax2) return 1; - else if (smax1 < sval) + else if (smax1 < smin2) return 0; break; case BPF_JLE: - if (umax1 <= uval) + if (umax1 <= umin2) return 1; - else if (umin1 > uval) + else if (umin1 > umax2) return 0; break; case BPF_JSLE: - if (smax1 <= sval) + if (smax1 <= smin2) return 1; - else if (smin1 > sval) + else if (smin1 > smax2) return 0; break; } @@ -14415,28 +14432,28 @@ static int is_pkt_ptr_branch_taken(struct bpf_reg_state *dst_reg, static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2, u8 opcode, bool is_jmp32) { - u64 val; - if (reg_is_pkt_pointer_any(reg1) && reg_is_pkt_pointer_any(reg2) && !is_jmp32) return is_pkt_ptr_branch_taken(reg1, reg2, opcode); - /* try to make sure reg2 is a constant SCALAR_VALUE */ - if (!is_reg_const(reg2, is_jmp32)) { - opcode = flip_opcode(opcode); - swap(reg1, reg2); - } - /* for now we expect reg2 to be a constant to make any useful decisions */ - if (!is_reg_const(reg2, is_jmp32)) - return -1; - val = reg_const_value(reg2, is_jmp32); + if (__is_pointer_value(false, reg1) || __is_pointer_value(false, reg2)) { + u64 val; + + /* arrange that reg2 is a scalar, and reg1 is a pointer */ + if (!is_reg_const(reg2, is_jmp32)) { + opcode = flip_opcode(opcode); + swap(reg1, reg2); + } + /* and ensure that reg2 is a constant */ + if (!is_reg_const(reg2, is_jmp32)) + return -1; - if (__is_pointer_value(false, reg1)) { if (!reg_not_null(reg1)) return -1; /* If pointer is valid tests against zero will fail so we can * use this to direct branch taken. */ + val = reg_const_value(reg2, is_jmp32); if (val != 0) return -1; @@ -14450,6 +14467,7 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *reg } } + /* now deal with two scalars, but not necessarily constants */ return is_scalar_branch_taken(reg1, reg2, opcode, is_jmp32); } From be41a203bb9e0159099e189e510388fe61962eb8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:05:59 -0800 Subject: [PATCH 0690/7721] bpf: enhance BPF_JEQ/BPF_JNE is_branch_taken logic Use 32-bit subranges to prune some 64-bit BPF_JEQ/BPF_JNE conditions that otherwise would be "inconclusive" (i.e., is_branch_taken() would return -1). This can happen, for example, when registers are initialized as 64-bit u64/s64, then compared for inequality as 32-bit subregisters, and then followed by 64-bit equality/inequality check. That 32-bit inequality can establish some pattern for lower 32 bits of a register (e.g., s< 0 condition determines whether the bit #31 is zero or not), while overall 64-bit value could be anything (according to a value range representation). This is not a fancy quirky special case, but actually a handling that's necessary to prevent correctness issue with BPF verifier's range tracking: set_range_min_max() assumes that register ranges are non-overlapping, and if that condition is not guaranteed by is_branch_taken() we can end up with invalid ranges, where min > max. [0] https://lore.kernel.org/bpf/CACkBjsY2q1_fUohD7hRmKGqv1MV=eP2f6XK8kjkYNw7BaiF8iQ@mail.gmail.com/ Acked-by: Shung-Hsi Yu Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f459ad99256e..65570eedfe88 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14283,6 +14283,18 @@ static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_sta return 0; if (smin1 > smax2 || smax1 < smin2) return 0; + if (!is_jmp32) { + /* if 64-bit ranges are inconclusive, see if we can + * utilize 32-bit subrange knowledge to eliminate + * branches that can't be taken a priori + */ + if (reg1->u32_min_value > reg2->u32_max_value || + reg1->u32_max_value < reg2->u32_min_value) + return 0; + if (reg1->s32_min_value > reg2->s32_max_value || + reg1->s32_max_value < reg2->s32_min_value) + return 0; + } break; case BPF_JNE: /* constants, umin/umax and smin/smax checks would be @@ -14295,6 +14307,18 @@ static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_sta return 1; if (smin1 > smax2 || smax1 < smin2) return 1; + if (!is_jmp32) { + /* if 64-bit ranges are inconclusive, see if we can + * utilize 32-bit subrange knowledge to eliminate + * branches that can't be taken a priori + */ + if (reg1->u32_min_value > reg2->u32_max_value || + reg1->u32_max_value < reg2->u32_min_value) + return 1; + if (reg1->s32_min_value > reg2->s32_max_value || + reg1->s32_max_value < reg2->s32_min_value) + return 1; + } break; case BPF_JSET: if (!is_reg_const(reg2, is_jmp32)) { From 5f99f312bd3bedb3b266b0d26376a8c500cdc97f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:00 -0800 Subject: [PATCH 0691/7721] bpf: add register bounds sanity checks and sanitization Add simple sanity checks that validate well-formed ranges (min <= max) across u64, s64, u32, and s32 ranges. Also for cases when the value is constant (either 64-bit or 32-bit), we validate that ranges and tnums are in agreement. These bounds checks are performed at the end of BPF_ALU/BPF_ALU64 operations, on conditional jumps, and for LDX instructions (where subreg zero/sign extension is probably the most important to check). This covers most of the interesting cases. Also, we validate the sanity of the return register when manually adjusting it for some special helpers. By default, sanity violation will trigger a warning in verifier log and resetting register bounds to "unbounded" ones. But to aid development and debugging, BPF_F_TEST_SANITY_STRICT flag is added, which will trigger hard failure of verification with -EFAULT on register bounds violations. This allows selftests to catch such issues. veristat will also gain a CLI option to enable this behavior. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231112010609.848406-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 1 + include/uapi/linux/bpf.h | 3 + kernel/bpf/syscall.c | 3 +- kernel/bpf/verifier.c | 117 ++++++++++++++++++++++++++------- tools/include/uapi/linux/bpf.h | 3 + 5 files changed, 101 insertions(+), 26 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 24213a99cc79..402b6bc44a1b 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -602,6 +602,7 @@ struct bpf_verifier_env { int stack_size; /* number of states to be processed */ bool strict_alignment; /* perform strict pointer alignment checks */ bool test_state_freq; /* test verifier with different pruning frequency */ + bool test_sanity_strict; /* fail verification on sanity violations */ struct bpf_verifier_state *cur_state; /* current verifier state */ struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ struct bpf_verifier_state_list *free_list; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 7cf8bcf9f6a2..8a5855fcee69 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1200,6 +1200,9 @@ enum bpf_perf_event_type { */ #define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6) +/* The verifier internal test flag. Behavior is undefined */ +#define BPF_F_TEST_SANITY_STRICT (1U << 7) + /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 0ed286b8a0f0..f266e03ba342 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2573,7 +2573,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_SLEEPABLE | BPF_F_TEST_RND_HI32 | BPF_F_XDP_HAS_FRAGS | - BPF_F_XDP_DEV_BOUND_ONLY)) + BPF_F_XDP_DEV_BOUND_ONLY | + BPF_F_TEST_SANITY_STRICT)) return -EINVAL; if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 65570eedfe88..e7edacf86e0f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2615,6 +2615,56 @@ static void reg_bounds_sync(struct bpf_reg_state *reg) __update_reg_bounds(reg); } +static int reg_bounds_sanity_check(struct bpf_verifier_env *env, + struct bpf_reg_state *reg, const char *ctx) +{ + const char *msg; + + if (reg->umin_value > reg->umax_value || + reg->smin_value > reg->smax_value || + reg->u32_min_value > reg->u32_max_value || + reg->s32_min_value > reg->s32_max_value) { + msg = "range bounds violation"; + goto out; + } + + if (tnum_is_const(reg->var_off)) { + u64 uval = reg->var_off.value; + s64 sval = (s64)uval; + + if (reg->umin_value != uval || reg->umax_value != uval || + reg->smin_value != sval || reg->smax_value != sval) { + msg = "const tnum out of sync with range bounds"; + goto out; + } + } + + if (tnum_subreg_is_const(reg->var_off)) { + u32 uval32 = tnum_subreg(reg->var_off).value; + s32 sval32 = (s32)uval32; + + if (reg->u32_min_value != uval32 || reg->u32_max_value != uval32 || + reg->s32_min_value != sval32 || reg->s32_max_value != sval32) { + msg = "const subreg tnum out of sync with range bounds"; + goto out; + } + } + + return 0; +out: + verbose(env, "REG SANITY VIOLATION (%s): %s u64=[%#llx, %#llx] " + "s64=[%#llx, %#llx] u32=[%#x, %#x] s32=[%#x, %#x] var_off=(%#llx, %#llx)\n", + ctx, msg, reg->umin_value, reg->umax_value, + reg->smin_value, reg->smax_value, + reg->u32_min_value, reg->u32_max_value, + reg->s32_min_value, reg->s32_max_value, + reg->var_off.value, reg->var_off.mask); + if (env->test_sanity_strict) + return -EFAULT; + __mark_reg_unbounded(reg); + return 0; +} + static bool __reg32_bound_s64(s32 a) { return a >= 0 && a <= S32_MAX; @@ -9982,14 +10032,15 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) return 0; } -static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type, - int func_id, - struct bpf_call_arg_meta *meta) +static int do_refine_retval_range(struct bpf_verifier_env *env, + struct bpf_reg_state *regs, int ret_type, + int func_id, + struct bpf_call_arg_meta *meta) { struct bpf_reg_state *ret_reg = ®s[BPF_REG_0]; if (ret_type != RET_INTEGER) - return; + return 0; switch (func_id) { case BPF_FUNC_get_stack: @@ -10015,6 +10066,8 @@ static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type, reg_bounds_sync(ret_reg); break; } + + return reg_bounds_sanity_check(env, ret_reg, "retval"); } static int @@ -10666,7 +10719,9 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0].ref_obj_id = id; } - do_refine_retval_range(regs, fn->ret_type, func_id, &meta); + err = do_refine_retval_range(env, regs, fn->ret_type, func_id, &meta); + if (err) + return err; err = check_map_func_compatibility(env, meta.map_ptr, func_id); if (err) @@ -14166,13 +14221,12 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) /* check dest operand */ err = check_reg_arg(env, insn->dst_reg, DST_OP_NO_MARK); + err = err ?: adjust_reg_min_max_vals(env, insn); if (err) return err; - - return adjust_reg_min_max_vals(env, insn); } - return 0; + return reg_bounds_sanity_check(env, ®s[insn->dst_reg], "alu"); } static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, @@ -14653,18 +14707,21 @@ static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state * Technically we can do similar adjustments for pointers to the same object, * but we don't support that right now. */ -static void reg_set_min_max(struct bpf_reg_state *true_reg1, - struct bpf_reg_state *true_reg2, - struct bpf_reg_state *false_reg1, - struct bpf_reg_state *false_reg2, - u8 opcode, bool is_jmp32) +static int reg_set_min_max(struct bpf_verifier_env *env, + struct bpf_reg_state *true_reg1, + struct bpf_reg_state *true_reg2, + struct bpf_reg_state *false_reg1, + struct bpf_reg_state *false_reg2, + u8 opcode, bool is_jmp32) { + int err; + /* If either register is a pointer, we can't learn anything about its * variable offset from the compare (unless they were a pointer into * the same object, but we don't bother with that). */ if (false_reg1->type != SCALAR_VALUE || false_reg2->type != SCALAR_VALUE) - return; + return 0; /* fallthrough (FALSE) branch */ regs_refine_cond_op(false_reg1, false_reg2, rev_opcode(opcode), is_jmp32); @@ -14675,6 +14732,12 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg1, regs_refine_cond_op(true_reg1, true_reg2, opcode, is_jmp32); reg_bounds_sync(true_reg1); reg_bounds_sync(true_reg2); + + err = reg_bounds_sanity_check(env, true_reg1, "true_reg1"); + err = err ?: reg_bounds_sanity_check(env, true_reg2, "true_reg2"); + err = err ?: reg_bounds_sanity_check(env, false_reg1, "false_reg1"); + err = err ?: reg_bounds_sanity_check(env, false_reg2, "false_reg2"); + return err; } static void mark_ptr_or_null_reg(struct bpf_func_state *state, @@ -14968,15 +15031,20 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, other_branch_regs = other_branch->frame[other_branch->curframe]->regs; if (BPF_SRC(insn->code) == BPF_X) { - reg_set_min_max(&other_branch_regs[insn->dst_reg], - &other_branch_regs[insn->src_reg], - dst_reg, src_reg, opcode, is_jmp32); + err = reg_set_min_max(env, + &other_branch_regs[insn->dst_reg], + &other_branch_regs[insn->src_reg], + dst_reg, src_reg, opcode, is_jmp32); } else /* BPF_SRC(insn->code) == BPF_K */ { - reg_set_min_max(&other_branch_regs[insn->dst_reg], - src_reg /* fake one */, - dst_reg, src_reg /* same fake one */, - opcode, is_jmp32); + err = reg_set_min_max(env, + &other_branch_regs[insn->dst_reg], + src_reg /* fake one */, + dst_reg, src_reg /* same fake one */, + opcode, is_jmp32); } + if (err) + return err; + if (BPF_SRC(insn->code) == BPF_X && src_reg->type == SCALAR_VALUE && src_reg->id && !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { @@ -17479,10 +17547,8 @@ static int do_check(struct bpf_verifier_env *env) insn->off, BPF_SIZE(insn->code), BPF_READ, insn->dst_reg, false, BPF_MODE(insn->code) == BPF_MEMSX); - if (err) - return err; - - err = save_aux_ptr_type(env, src_reg_type, true); + err = err ?: save_aux_ptr_type(env, src_reg_type, true); + err = err ?: reg_bounds_sanity_check(env, ®s[insn->dst_reg], "ldx"); if (err) return err; } else if (class == BPF_STX) { @@ -20769,6 +20835,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (is_priv) env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ; + env->test_sanity_strict = attr->prog_flags & BPF_F_TEST_SANITY_STRICT; env->explored_states = kvcalloc(state_htab_size(env), sizeof(struct bpf_verifier_state_list *), diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 7cf8bcf9f6a2..8a5855fcee69 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1200,6 +1200,9 @@ enum bpf_perf_event_type { */ #define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6) +/* The verifier internal test flag. Behavior is undefined */ +#define BPF_F_TEST_SANITY_STRICT (1U << 7) + /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ From 3cf98cf594ea923b8b1e0385b580d3d8aae68c06 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:01 -0800 Subject: [PATCH 0692/7721] bpf: remove redundant s{32,64} -> u{32,64} deduction logic Equivalent checks were recently added in more succinct and, arguably, safer form in: - f188765f23a5 ("bpf: derive smin32/smax32 from umin32/umax32 bounds"); - 2e74aef782d3 ("bpf: derive smin/smax from umin/max bounds"). The checks we are removing in this patch set do similar checks to detect if entire u32/u64 range has signed bit set or not set, but does it with two separate checks. Further, we forcefully overwrite either smin or smax (and 32-bit equvalents) without applying normal min/max intersection logic. It's not clear why that would be correct in all cases and seems to work by accident. This logic is also "gated" by previous signed -> unsigned derivation, which returns early. All this is quite confusing and seems error-prone, while we already have at least equivalent checks happening earlier. So remove this duplicate and error-prone logic to simplify things a bit. Acked-by: Shung-Hsi Yu Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e7edacf86e0f..53a9e3e79ab4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2411,24 +2411,6 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) min_t(u32, reg->s32_max_value, reg->u32_max_value); return; } - /* Learn sign from unsigned bounds. Signed bounds cross the sign - * boundary, so we must be careful. - */ - if ((s32)reg->u32_max_value >= 0) { - /* Positive. We can't learn anything from the smin, but smax - * is positive, hence safe. - */ - reg->s32_min_value = reg->u32_min_value; - reg->s32_max_value = reg->u32_max_value = - min_t(u32, reg->s32_max_value, reg->u32_max_value); - } else if ((s32)reg->u32_min_value < 0) { - /* Negative. We can't learn anything from the smax, but smin - * is negative, hence safe. - */ - reg->s32_min_value = reg->u32_min_value = - max_t(u32, reg->s32_min_value, reg->u32_min_value); - reg->s32_max_value = reg->u32_max_value; - } } static void __reg64_deduce_bounds(struct bpf_reg_state *reg) @@ -2516,24 +2498,6 @@ static void __reg64_deduce_bounds(struct bpf_reg_state *reg) reg->umax_value); return; } - /* Learn sign from unsigned bounds. Signed bounds cross the sign - * boundary, so we must be careful. - */ - if ((s64)reg->umax_value >= 0) { - /* Positive. We can't learn anything from the smin, but smax - * is positive, hence safe. - */ - reg->smin_value = reg->umin_value; - reg->smax_value = reg->umax_value = min_t(u64, reg->smax_value, - reg->umax_value); - } else if ((s64)reg->umin_value < 0) { - /* Negative. We can't learn anything from the smax, but smin - * is negative, hence safe. - */ - reg->smin_value = reg->umin_value = max_t(u64, reg->smin_value, - reg->umin_value); - reg->smax_value = reg->umax_value; - } } static void __reg_deduce_mixed_bounds(struct bpf_reg_state *reg) From cf5fe3c71c5a34ac0108afc550407c672d0a032d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:02 -0800 Subject: [PATCH 0693/7721] bpf: make __reg{32,64}_deduce_bounds logic more robust This change doesn't seem to have any effect on selftests and production BPF object files, but we preemptively try to make it more robust. First, "learn sign from signed bounds" comment is misleading, as we are learning not just sign, but also values. Second, we simplify the check for determining whether entire range is positive or negative similarly to other checks added earlier, using appropriate u32/u64 cast and single comparisons. As explain in comments in __reg64_deduce_bounds(), the checks are equivalent. Last but not least, smin/smax and s32_min/s32_max reassignment based on min/max of both umin/umax and smin/smax (and 32-bit equivalents) is hard to explain and justify. We are updating unsigned bounds from signed bounds, why would we update signed bounds at the same time? This might be correct, but it's far from obvious why and the code or comments don't try to justify this. Given we've added a separate deduction of signed bounds from unsigned bounds earlier, this seems at least redundant, if not just wrong. In short, we remove doubtful pieces, and streamline the rest to follow the logic and approach of the rest of reg_bounds_sync() checks. Acked-by: Shung-Hsi Yu Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 53a9e3e79ab4..59505881e7a7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2399,17 +2399,13 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg) reg->s32_min_value = max_t(s32, reg->s32_min_value, reg->u32_min_value); reg->s32_max_value = min_t(s32, reg->s32_max_value, reg->u32_max_value); } - /* Learn sign from signed bounds. - * If we cannot cross the sign boundary, then signed and unsigned bounds + /* If we cannot cross the sign boundary, then signed and unsigned bounds * are the same, so combine. This works even in the negative case, e.g. * -3 s<= x s<= -1 implies 0xf...fd u<= x u<= 0xf...ff. */ - if (reg->s32_min_value >= 0 || reg->s32_max_value < 0) { - reg->s32_min_value = reg->u32_min_value = - max_t(u32, reg->s32_min_value, reg->u32_min_value); - reg->s32_max_value = reg->u32_max_value = - min_t(u32, reg->s32_max_value, reg->u32_max_value); - return; + if ((u32)reg->s32_min_value <= (u32)reg->s32_max_value) { + reg->u32_min_value = max_t(u32, reg->s32_min_value, reg->u32_min_value); + reg->u32_max_value = min_t(u32, reg->s32_max_value, reg->u32_max_value); } } @@ -2486,17 +2482,13 @@ static void __reg64_deduce_bounds(struct bpf_reg_state *reg) reg->smin_value = max_t(s64, reg->smin_value, reg->umin_value); reg->smax_value = min_t(s64, reg->smax_value, reg->umax_value); } - /* Learn sign from signed bounds. - * If we cannot cross the sign boundary, then signed and unsigned bounds + /* If we cannot cross the sign boundary, then signed and unsigned bounds * are the same, so combine. This works even in the negative case, e.g. * -3 s<= x s<= -1 implies 0xf...fd u<= x u<= 0xf...ff. */ - if (reg->smin_value >= 0 || reg->smax_value < 0) { - reg->smin_value = reg->umin_value = max_t(u64, reg->smin_value, - reg->umin_value); - reg->smax_value = reg->umax_value = min_t(u64, reg->smax_value, - reg->umax_value); - return; + if ((u64)reg->smin_value <= (u64)reg->smax_value) { + reg->umin_value = max_t(u64, reg->smin_value, reg->umin_value); + reg->umax_value = min_t(u64, reg->smax_value, reg->umax_value); } } From 8863238993e23ccc6d5a9d4ff9f1c043f88f692e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:03 -0800 Subject: [PATCH 0694/7721] selftests/bpf: BPF register range bounds tester Add test to validate BPF verifier's register range bounds tracking logic. The main bulk is a lot of auto-generated tests based on a small set of seed values for lower and upper 32 bits of full 64-bit values. Currently we validate only range vs const comparisons, but the idea is to start validating range over range comparisons in subsequent patch set. When setting up initial register ranges we treat registers as one of u64/s64/u32/s32 numeric types, and then independently perform conditional comparisons based on a potentially different u64/s64/u32/s32 types. This tests lots of tricky cases of deriving bounds information across different numeric domains. Given there are lots of auto-generated cases, we guard them behind SLOW_TESTS=1 envvar requirement, and skip them altogether otherwise. With current full set of upper/lower seed value, all supported comparison operators and all the combinations of u64/s64/u32/s32 number domains, we get about 7.7 million tests, which run in about 35 minutes on my local qemu instance without parallelization. But we also split those tests by init/cond numeric types, which allows to rely on test_progs's parallelization of tests with `-j` option, getting run time down to about 5 minutes on 8 cores. It's still something that shouldn't be run during normal test_progs run. But we can run it a reasonable time, and so perhaps a nightly CI test run (once we have it) would be a good option for this. We also add a small set of tricky conditions that came up during development and triggered various bugs or corner cases in either selftest's reimplementation of range bounds logic or in verifier's logic itself. These are fast enough to be run as part of normal test_progs test run and are great for a quick sanity checking. Let's take a look at test output to understand what's going on: $ sudo ./test_progs -t reg_bounds_crafted #191/1 reg_bounds_crafted/(u64)[0; 0xffffffff] (u64)< 0:OK ... #191/115 reg_bounds_crafted/(u64)[0; 0x17fffffff] (s32)< 0:OK ... #191/137 reg_bounds_crafted/(u64)[0xffffffff; 0x100000000] (u64)== 0:OK Each test case is uniquely and fully described by this generated string. E.g.: "(u64)[0; 0x17fffffff] (s32)< 0". This means that we initialize a register (R6) in such a way that verifier knows that it can have a value in [(u64)0; (u64)0x17fffffff] range. Another register (R7) is also set up as u64, but this time a constant (zero in this case). They then are compared using 32-bit signed < operation. Resulting TRUE/FALSE branches are evaluated (including cases where it's known that one of the branches will never be taken, in which case we validate that verifier also determines this as a dead code). Test validates that verifier's final register state matches expected state based on selftest's own reg_state logic, implemented from scratch for cross-checking purposes. These test names can be conveniently used for further debugging, and if -vv verboseness is requested we can get a corresponding verifier log (with mark_precise logs filtered out as irrelevant and distracting). Example below is slightly redacted for brevity, omitting irrelevant register output in some places, marked with [...]. $ sudo ./test_progs -a 'reg_bounds_crafted/(u32)[0; U32_MAX] (s32)< -1' -vv ... VERIFIER LOG: ======================== func#0 @0 0: R1=ctx(off=0,imm=0) R10=fp0 0: (05) goto pc+2 3: (85) call bpf_get_current_pid_tgid#14 ; R0_w=scalar() 4: (bc) w6 = w0 ; R0_w=scalar() R6_w=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff)) 5: (85) call bpf_get_current_pid_tgid#14 ; R0_w=scalar() 6: (bc) w7 = w0 ; R0_w=scalar() R7_w=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff)) 7: (b4) w1 = 0 ; R1_w=0 8: (b4) w2 = -1 ; R2=4294967295 9: (ae) if w6 < w1 goto pc-9 9: R1=0 R6=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff)) 10: (2e) if w6 > w2 goto pc-10 10: R2=4294967295 R6=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff)) 11: (b4) w1 = -1 ; R1_w=4294967295 12: (b4) w2 = -1 ; R2_w=4294967295 13: (ae) if w7 < w1 goto pc-13 ; R1_w=4294967295 R7=4294967295 14: (2e) if w7 > w2 goto pc-14 14: R2_w=4294967295 R7=4294967295 15: (bc) w0 = w6 ; [...] R6=scalar(id=1,smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff)) 16: (bc) w0 = w7 ; [...] R7=4294967295 17: (ce) if w6 s< w7 goto pc+3 ; R6=scalar(id=1,smin=0,smax=umax=4294967295,smin32=-1,var_off=(0x0; 0xffffffff)) R7=4294967295 18: (bc) w0 = w6 ; [...] R6=scalar(id=1,smin=0,smax=umax=4294967295,smin32=-1,var_off=(0x0; 0xffffffff)) 19: (bc) w0 = w7 ; [...] R7=4294967295 20: (95) exit from 17 to 21: [...] 21: (bc) w0 = w6 ; [...] R6=scalar(id=1,smin=umin=umin32=2147483648,smax=umax=umax32=4294967294,smax32=-2,var_off=(0x80000000; 0x7fffffff)) 22: (bc) w0 = w7 ; [...] R7=4294967295 23: (95) exit from 13 to 1: [...] 1: [...] 1: (b7) r0 = 0 ; R0_w=0 2: (95) exit processed 24 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 1 ===================== Verifier log above is for `(u32)[0; U32_MAX] (s32)< -1` use cases, where u32 range is used for initialization, followed by signed < operator. Note how we use w6/w7 in this case for register initialization (it would be R6/R7 for 64-bit types) and then `if w6 s< w7` for comparison at instruction #17. It will be `if R6 < R7` for 64-bit unsigned comparison. Above example gives a good impression of the overall structure of a BPF programs generated for reg_bounds tests. In the future, this "framework" can be extended to test not just conditional jumps, but also arithmetic operations. Adding randomized testing is another possibility. Some implementation notes. We basically have our own generics-like operations on numbers, where all the numbers are stored in u64, but how they are interpreted is passed as runtime argument enum num_t. Further, `struct range` represents a bounds range, and those are collected together into a minimal `struct reg_state`, which collects range bounds across all four numberical domains: u64, s64, u32, s64. Based on these primitives and `enum op` representing possible conditional operation (<, <=, >, >=, ==, !=), there is a set of generic helpers to perform "range arithmetics", which is used to maintain struct reg_state. We simulate what verifier will do for reg bounds of R6 and R7 registers using these range and reg_state primitives. Simulated information is used to determine branch taken conclusion and expected exact register state across all four number domains. Implementation of "range arithmetics" is more generic than what verifier is currently performing: it allows range over range comparisons and adjustments. This is the intended end goal of this patch set overall and verifier logic is enhanced in subsequent patches in this series to handle range vs range operations, at which point selftests are extended to validate these conditions as well. For now it's range vs const cases only. Note that tests are split into multiple groups by their numeric types for initialization of ranges and for comparison operation. This allows to use test_progs's -j parallelization to speed up tests, as we now have 16 groups of parallel running tests. Overall reduction of running time that allows is pretty good, we go down from more than 30 minutes to slightly less than 5 minutes running time. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Shung-Hsi Yu Link: https://lore.kernel.org/r/20231112010609.848406-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/reg_bounds.c | 1838 +++++++++++++++++ 1 file changed, 1838 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/reg_bounds.c diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c new file mode 100644 index 000000000000..7a524b381ed3 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -0,0 +1,1838 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +/* ================================= + * SHORT AND CONSISTENT NUMBER TYPES + * ================================= + */ +#define U64_MAX ((u64)UINT64_MAX) +#define U32_MAX ((u32)UINT_MAX) +#define S64_MIN ((s64)INT64_MIN) +#define S64_MAX ((s64)INT64_MAX) +#define S32_MIN ((s32)INT_MIN) +#define S32_MAX ((s32)INT_MAX) + +typedef unsigned long long ___u64; +typedef unsigned int ___u32; +typedef long long ___s64; +typedef int ___s32; + +/* avoid conflicts with already defined types in kernel headers */ +#define u64 ___u64 +#define u32 ___u32 +#define s64 ___s64 +#define s32 ___s32 + +/* ================================== + * STRING BUF ABSTRACTION AND HELPERS + * ================================== + */ +struct strbuf { + size_t buf_sz; + int pos; + char buf[0]; +}; + +#define DEFINE_STRBUF(name, N) \ + struct { struct strbuf buf; char data[(N)]; } ___##name; \ + struct strbuf *name = (___##name.buf.buf_sz = (N), ___##name.buf.pos = 0, &___##name.buf) + +__printf(2, 3) +static inline void snappendf(struct strbuf *s, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + s->pos += vsnprintf(s->buf + s->pos, + s->pos < s->buf_sz ? s->buf_sz - s->pos : 0, + fmt, args); + va_end(args); +} + +/* ================================== + * GENERIC NUMBER TYPE AND OPERATIONS + * ================================== + */ +enum num_t { U64, first_t = U64, U32, S64, S32, last_t = S32 }; + +static __always_inline u64 min_t(enum num_t t, u64 x, u64 y) +{ + switch (t) { + case U64: return (u64)x < (u64)y ? (u64)x : (u64)y; + case U32: return (u32)x < (u32)y ? (u32)x : (u32)y; + case S64: return (s64)x < (s64)y ? (s64)x : (s64)y; + case S32: return (s32)x < (s32)y ? (s32)x : (s32)y; + default: printf("min_t!\n"); exit(1); + } +} + +static __always_inline u64 max_t(enum num_t t, u64 x, u64 y) +{ + switch (t) { + case U64: return (u64)x > (u64)y ? (u64)x : (u64)y; + case U32: return (u32)x > (u32)y ? (u32)x : (u32)y; + case S64: return (s64)x > (s64)y ? (s64)x : (s64)y; + case S32: return (s32)x > (s32)y ? (u32)(s32)x : (u32)(s32)y; + default: printf("max_t!\n"); exit(1); + } +} + +static const char *t_str(enum num_t t) +{ + switch (t) { + case U64: return "u64"; + case U32: return "u32"; + case S64: return "s64"; + case S32: return "s32"; + default: printf("t_str!\n"); exit(1); + } +} + +static enum num_t t_is_32(enum num_t t) +{ + switch (t) { + case U64: return false; + case U32: return true; + case S64: return false; + case S32: return true; + default: printf("t_is_32!\n"); exit(1); + } +} + +static enum num_t t_signed(enum num_t t) +{ + switch (t) { + case U64: return S64; + case U32: return S32; + case S64: return S64; + case S32: return S32; + default: printf("t_signed!\n"); exit(1); + } +} + +static enum num_t t_unsigned(enum num_t t) +{ + switch (t) { + case U64: return U64; + case U32: return U32; + case S64: return U64; + case S32: return U32; + default: printf("t_unsigned!\n"); exit(1); + } +} + +static bool num_is_small(enum num_t t, u64 x) +{ + switch (t) { + case U64: return (u64)x <= 256; + case U32: return (u32)x <= 256; + case S64: return (s64)x >= -256 && (s64)x <= 256; + case S32: return (s32)x >= -256 && (s32)x <= 256; + default: printf("num_is_small!\n"); exit(1); + } +} + +static void snprintf_num(enum num_t t, struct strbuf *sb, u64 x) +{ + bool is_small = num_is_small(t, x); + + if (is_small) { + switch (t) { + case U64: return snappendf(sb, "%llu", (u64)x); + case U32: return snappendf(sb, "%u", (u32)x); + case S64: return snappendf(sb, "%lld", (s64)x); + case S32: return snappendf(sb, "%d", (s32)x); + default: printf("snprintf_num!\n"); exit(1); + } + } else { + switch (t) { + case U64: + if (x == U64_MAX) + return snappendf(sb, "U64_MAX"); + else if (x >= U64_MAX - 256) + return snappendf(sb, "U64_MAX-%llu", U64_MAX - x); + else + return snappendf(sb, "%#llx", (u64)x); + case U32: + if ((u32)x == U32_MAX) + return snappendf(sb, "U32_MAX"); + else if ((u32)x >= U32_MAX - 256) + return snappendf(sb, "U32_MAX-%u", U32_MAX - (u32)x); + else + return snappendf(sb, "%#x", (u32)x); + case S64: + if ((s64)x == S64_MAX) + return snappendf(sb, "S64_MAX"); + else if ((s64)x >= S64_MAX - 256) + return snappendf(sb, "S64_MAX-%lld", S64_MAX - (s64)x); + else if ((s64)x == S64_MIN) + return snappendf(sb, "S64_MIN"); + else if ((s64)x <= S64_MIN + 256) + return snappendf(sb, "S64_MIN+%lld", (s64)x - S64_MIN); + else + return snappendf(sb, "%#llx", (s64)x); + case S32: + if ((s32)x == S32_MAX) + return snappendf(sb, "S32_MAX"); + else if ((s32)x >= S32_MAX - 256) + return snappendf(sb, "S32_MAX-%d", S32_MAX - (s32)x); + else if ((s32)x == S32_MIN) + return snappendf(sb, "S32_MIN"); + else if ((s32)x <= S32_MIN + 256) + return snappendf(sb, "S32_MIN+%d", (s32)x - S32_MIN); + else + return snappendf(sb, "%#x", (s32)x); + default: printf("snprintf_num!\n"); exit(1); + } + } +} + +/* =================================== + * GENERIC RANGE STRUCT AND OPERATIONS + * =================================== + */ +struct range { + u64 a, b; +}; + +static void snprintf_range(enum num_t t, struct strbuf *sb, struct range x) +{ + if (x.a == x.b) + return snprintf_num(t, sb, x.a); + + snappendf(sb, "["); + snprintf_num(t, sb, x.a); + snappendf(sb, "; "); + snprintf_num(t, sb, x.b); + snappendf(sb, "]"); +} + +static void print_range(enum num_t t, struct range x, const char *sfx) +{ + DEFINE_STRBUF(sb, 128); + + snprintf_range(t, sb, x); + printf("%s%s", sb->buf, sfx); +} + +static const struct range unkn[] = { + [U64] = { 0, U64_MAX }, + [U32] = { 0, U32_MAX }, + [S64] = { (u64)S64_MIN, (u64)S64_MAX }, + [S32] = { (u64)(u32)S32_MIN, (u64)(u32)S32_MAX }, +}; + +static struct range unkn_subreg(enum num_t t) +{ + switch (t) { + case U64: return unkn[U32]; + case U32: return unkn[U32]; + case S64: return unkn[U32]; + case S32: return unkn[S32]; + default: printf("unkn_subreg!\n"); exit(1); + } +} + +static struct range range(enum num_t t, u64 a, u64 b) +{ + switch (t) { + case U64: return (struct range){ (u64)a, (u64)b }; + case U32: return (struct range){ (u32)a, (u32)b }; + case S64: return (struct range){ (s64)a, (s64)b }; + case S32: return (struct range){ (u32)(s32)a, (u32)(s32)b }; + default: printf("range!\n"); exit(1); + } +} + +static __always_inline u32 sign64(u64 x) { return (x >> 63) & 1; } +static __always_inline u32 sign32(u64 x) { return ((u32)x >> 31) & 1; } +static __always_inline u32 upper32(u64 x) { return (u32)(x >> 32); } +static __always_inline u64 swap_low32(u64 x, u32 y) { return (x & 0xffffffff00000000ULL) | y; } + +static bool range_eq(struct range x, struct range y) +{ + return x.a == y.a && x.b == y.b; +} + +static struct range range_cast_to_s32(struct range x) +{ + u64 a = x.a, b = x.b; + + /* if upper 32 bits are constant, lower 32 bits should form a proper + * s32 range to be correct + */ + if (upper32(a) == upper32(b) && (s32)a <= (s32)b) + return range(S32, a, b); + + /* Special case where upper bits form a small sequence of two + * sequential numbers (in 32-bit unsigned space, so 0xffffffff to + * 0x00000000 is also valid), while lower bits form a proper s32 range + * going from negative numbers to positive numbers. + * + * E.g.: [0xfffffff0ffffff00; 0xfffffff100000010]. Iterating + * over full 64-bit numbers range will form a proper [-16, 16] + * ([0xffffff00; 0x00000010]) range in its lower 32 bits. + */ + if (upper32(a) + 1 == upper32(b) && (s32)a < 0 && (s32)b >= 0) + return range(S32, a, b); + + /* otherwise we can't derive much meaningful information */ + return unkn[S32]; +} + +static struct range range_cast_u64(enum num_t to_t, struct range x) +{ + u64 a = (u64)x.a, b = (u64)x.b; + + switch (to_t) { + case U64: + return x; + case U32: + if (upper32(a) != upper32(b)) + return unkn[U32]; + return range(U32, a, b); + case S64: + if (sign64(a) != sign64(b)) + return unkn[S64]; + return range(S64, a, b); + case S32: + return range_cast_to_s32(x); + default: printf("range_cast_u64!\n"); exit(1); + } +} + +static struct range range_cast_s64(enum num_t to_t, struct range x) +{ + s64 a = (s64)x.a, b = (s64)x.b; + + switch (to_t) { + case U64: + /* equivalent to (s64)a <= (s64)b check */ + if (sign64(a) != sign64(b)) + return unkn[U64]; + return range(U64, a, b); + case U32: + if (upper32(a) != upper32(b) || sign32(a) != sign32(b)) + return unkn[U32]; + return range(U32, a, b); + case S64: + return x; + case S32: + return range_cast_to_s32(x); + default: printf("range_cast_s64!\n"); exit(1); + } +} + +static struct range range_cast_u32(enum num_t to_t, struct range x) +{ + u32 a = (u32)x.a, b = (u32)x.b; + + switch (to_t) { + case U64: + case S64: + /* u32 is always a valid zero-extended u64/s64 */ + return range(to_t, a, b); + case U32: + return x; + case S32: + return range_cast_to_s32(range(U32, a, b)); + default: printf("range_cast_u32!\n"); exit(1); + } +} + +static struct range range_cast_s32(enum num_t to_t, struct range x) +{ + s32 a = (s32)x.a, b = (s32)x.b; + + switch (to_t) { + case U64: + case U32: + case S64: + if (sign32(a) != sign32(b)) + return unkn[to_t]; + return range(to_t, a, b); + case S32: + return x; + default: printf("range_cast_s32!\n"); exit(1); + } +} + +/* Reinterpret range in *from_t* domain as a range in *to_t* domain preserving + * all possible information. Worst case, it will be unknown range within + * *to_t* domain, if nothing more specific can be guaranteed during the + * conversion + */ +static struct range range_cast(enum num_t from_t, enum num_t to_t, struct range from) +{ + switch (from_t) { + case U64: return range_cast_u64(to_t, from); + case U32: return range_cast_u32(to_t, from); + case S64: return range_cast_s64(to_t, from); + case S32: return range_cast_s32(to_t, from); + default: printf("range_cast!\n"); exit(1); + } +} + +static bool is_valid_num(enum num_t t, u64 x) +{ + switch (t) { + case U64: return true; + case U32: return upper32(x) == 0; + case S64: return true; + case S32: return upper32(x) == 0; + default: printf("is_valid_num!\n"); exit(1); + } +} + +static bool is_valid_range(enum num_t t, struct range x) +{ + if (!is_valid_num(t, x.a) || !is_valid_num(t, x.b)) + return false; + + switch (t) { + case U64: return (u64)x.a <= (u64)x.b; + case U32: return (u32)x.a <= (u32)x.b; + case S64: return (s64)x.a <= (s64)x.b; + case S32: return (s32)x.a <= (s32)x.b; + default: printf("is_valid_range!\n"); exit(1); + } +} + +static struct range range_improve(enum num_t t, struct range old, struct range new) +{ + return range(t, max_t(t, old.a, new.a), min_t(t, old.b, new.b)); +} + +static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, struct range y) +{ + struct range y_cast; + + y_cast = range_cast(y_t, x_t, y); + + /* the case when new range knowledge, *y*, is a 32-bit subregister + * range, while previous range knowledge, *x*, is a full register + * 64-bit range, needs special treatment to take into account upper 32 + * bits of full register range + */ + if (t_is_32(y_t) && !t_is_32(x_t)) { + struct range x_swap; + + /* some combinations of upper 32 bits and sign bit can lead to + * invalid ranges, in such cases it's easier to detect them + * after cast/swap than try to enumerate all the conditions + * under which transformation and knowledge transfer is valid + */ + x_swap = range(x_t, swap_low32(x.a, y_cast.a), swap_low32(x.b, y_cast.b)); + if (!is_valid_range(x_t, x_swap)) + return x; + return range_improve(x_t, x, x_swap); + } + + /* otherwise, plain range cast and intersection works */ + return range_improve(x_t, x, y_cast); +} + +/* ======================= + * GENERIC CONDITIONAL OPS + * ======================= + */ +enum op { OP_LT, OP_LE, OP_GT, OP_GE, OP_EQ, OP_NE, first_op = OP_LT, last_op = OP_NE }; + +static enum op complement_op(enum op op) +{ + switch (op) { + case OP_LT: return OP_GE; + case OP_LE: return OP_GT; + case OP_GT: return OP_LE; + case OP_GE: return OP_LT; + case OP_EQ: return OP_NE; + case OP_NE: return OP_EQ; + default: printf("complement_op!\n"); exit(1); + } +} + +static const char *op_str(enum op op) +{ + switch (op) { + case OP_LT: return "<"; + case OP_LE: return "<="; + case OP_GT: return ">"; + case OP_GE: return ">="; + case OP_EQ: return "=="; + case OP_NE: return "!="; + default: printf("op_str!\n"); exit(1); + } +} + +/* Can register with range [x.a, x.b] *EVER* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_canbe_op(enum num_t t, struct range x, struct range y, enum op op) +{ +#define range_canbe(T) do { \ + switch (op) { \ + case OP_LT: return (T)x.a < (T)y.b; \ + case OP_LE: return (T)x.a <= (T)y.b; \ + case OP_GT: return (T)x.b > (T)y.a; \ + case OP_GE: return (T)x.b >= (T)y.a; \ + case OP_EQ: return (T)max_t(t, x.a, y.a) <= (T)min_t(t, x.b, y.b); \ + case OP_NE: return !((T)x.a == (T)x.b && (T)y.a == (T)y.b && (T)x.a == (T)y.a); \ + default: printf("range_canbe op %d\n", op); exit(1); \ + } \ +} while (0) + + switch (t) { + case U64: { range_canbe(u64); } + case U32: { range_canbe(u32); } + case S64: { range_canbe(s64); } + case S32: { range_canbe(s32); } + default: printf("range_canbe!\n"); exit(1); + } +#undef range_canbe +} + +/* Does register with range [x.a, x.b] *ALWAYS* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_always_op(enum num_t t, struct range x, struct range y, enum op op) +{ + /* always op <=> ! canbe complement(op) */ + return !range_canbe_op(t, x, y, complement_op(op)); +} + +/* Does register with range [x.a, x.b] *NEVER* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_never_op(enum num_t t, struct range x, struct range y, enum op op) +{ + return !range_canbe_op(t, x, y, op); +} + +/* similar to verifier's is_branch_taken(): + * 1 - always taken; + * 0 - never taken, + * -1 - unsure. + */ +static int range_branch_taken_op(enum num_t t, struct range x, struct range y, enum op op) +{ + if (range_always_op(t, x, y, op)) + return 1; + if (range_never_op(t, x, y, op)) + return 0; + return -1; +} + +/* What would be the new estimates for register x and y ranges assuming truthful + * OP comparison between them. I.e., (x OP y == true) => x <- newx, y <- newy. + * + * We assume "interesting" cases where ranges overlap. Cases where it's + * obvious that (x OP y) is either always true or false should be filtered with + * range_never and range_always checks. + */ +static void range_cond(enum num_t t, struct range x, struct range y, + enum op op, struct range *newx, struct range *newy) +{ + if (!range_canbe_op(t, x, y, op)) { + /* nothing to adjust, can't happen, return original values */ + *newx = x; + *newy = y; + return; + } + switch (op) { + case OP_LT: + *newx = range(t, x.a, min_t(t, x.b, y.b - 1)); + *newy = range(t, max_t(t, x.a + 1, y.a), y.b); + break; + case OP_LE: + *newx = range(t, x.a, min_t(t, x.b, y.b)); + *newy = range(t, max_t(t, x.a, y.a), y.b); + break; + case OP_GT: + *newx = range(t, max_t(t, x.a, y.a + 1), x.b); + *newy = range(t, y.a, min_t(t, x.b - 1, y.b)); + break; + case OP_GE: + *newx = range(t, max_t(t, x.a, y.a), x.b); + *newy = range(t, y.a, min_t(t, x.b, y.b)); + break; + case OP_EQ: + *newx = range(t, max_t(t, x.a, y.a), min_t(t, x.b, y.b)); + *newy = range(t, max_t(t, x.a, y.a), min_t(t, x.b, y.b)); + break; + case OP_NE: + /* generic case, can't derive more information */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a, y.b); + break; + + /* below extended logic is not supported by verifier just yet */ + if (x.a == x.b && x.a == y.a) { + /* X is a constant matching left side of Y */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a + 1, y.b); + } else if (x.a == x.b && x.b == y.b) { + /* X is a constant matching rigth side of Y */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a, y.b - 1); + } else if (y.a == y.b && x.a == y.a) { + /* Y is a constant matching left side of X */ + *newx = range(t, x.a + 1, x.b); + *newy = range(t, y.a, y.b); + } else if (y.a == y.b && x.b == y.b) { + /* Y is a constant matching rigth side of X */ + *newx = range(t, x.a, x.b - 1); + *newy = range(t, y.a, y.b); + } else { + /* generic case, can't derive more information */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a, y.b); + } + + break; + default: + break; + } +} + +/* ======================= + * REGISTER STATE HANDLING + * ======================= + */ +struct reg_state { + struct range r[4]; /* indexed by enum num_t: U64, U32, S64, S32 */ + bool valid; +}; + +static void print_reg_state(struct reg_state *r, const char *sfx) +{ + DEFINE_STRBUF(sb, 512); + enum num_t t; + int cnt = 0; + + if (!r->valid) { + printf("%s", sfx); + return; + } + + snappendf(sb, "scalar("); + for (t = first_t; t <= last_t; t++) { + snappendf(sb, "%s%s=", cnt++ ? "," : "", t_str(t)); + snprintf_range(t, sb, r->r[t]); + } + snappendf(sb, ")"); + + printf("%s%s", sb->buf, sfx); +} + +static void print_refinement(enum num_t s_t, struct range src, + enum num_t d_t, struct range old, struct range new, + const char *ctx) +{ + printf("REFINING (%s) (%s)SRC=", ctx, t_str(s_t)); + print_range(s_t, src, ""); + printf(" (%s)DST_OLD=", t_str(d_t)); + print_range(d_t, old, ""); + printf(" (%s)DST_NEW=", t_str(d_t)); + print_range(d_t, new, "\n"); +} + +static void reg_state_refine(struct reg_state *r, enum num_t t, struct range x, const char *ctx) +{ + enum num_t d_t, s_t; + struct range old; + bool keep_going = false; + +again: + /* try to derive new knowledge from just learned range x of type t */ + for (d_t = first_t; d_t <= last_t; d_t++) { + old = r->r[d_t]; + r->r[d_t] = range_refine(d_t, r->r[d_t], t, x); + if (!range_eq(r->r[d_t], old)) { + keep_going = true; + if (env.verbosity >= VERBOSE_VERY) + print_refinement(t, x, d_t, old, r->r[d_t], ctx); + } + } + + /* now see if we can derive anything new from updated reg_state's ranges */ + for (s_t = first_t; s_t <= last_t; s_t++) { + for (d_t = first_t; d_t <= last_t; d_t++) { + old = r->r[d_t]; + r->r[d_t] = range_refine(d_t, r->r[d_t], s_t, r->r[s_t]); + if (!range_eq(r->r[d_t], old)) { + keep_going = true; + if (env.verbosity >= VERBOSE_VERY) + print_refinement(s_t, r->r[s_t], d_t, old, r->r[d_t], ctx); + } + } + } + + /* keep refining until we converge */ + if (keep_going) { + keep_going = false; + goto again; + } +} + +static void reg_state_set_const(struct reg_state *rs, enum num_t t, u64 val) +{ + enum num_t tt; + + rs->valid = true; + for (tt = first_t; tt <= last_t; tt++) + rs->r[tt] = tt == t ? range(t, val, val) : unkn[tt]; + + reg_state_refine(rs, t, rs->r[t], "CONST"); +} + +static void reg_state_cond(enum num_t t, struct reg_state *x, struct reg_state *y, enum op op, + struct reg_state *newx, struct reg_state *newy, const char *ctx) +{ + char buf[32]; + enum num_t ts[2]; + struct reg_state xx = *x, yy = *y; + int i, t_cnt; + struct range z1, z2; + + if (op == OP_EQ || op == OP_NE) { + /* OP_EQ and OP_NE are sign-agnostic, so we need to process + * both signed and unsigned domains at the same time + */ + ts[0] = t_unsigned(t); + ts[1] = t_signed(t); + t_cnt = 2; + } else { + ts[0] = t; + t_cnt = 1; + } + + for (i = 0; i < t_cnt; i++) { + t = ts[i]; + z1 = x->r[t]; + z2 = y->r[t]; + + range_cond(t, z1, z2, op, &z1, &z2); + + if (newx) { + snprintf(buf, sizeof(buf), "%s R1", ctx); + reg_state_refine(&xx, t, z1, buf); + } + if (newy) { + snprintf(buf, sizeof(buf), "%s R2", ctx); + reg_state_refine(&yy, t, z2, buf); + } + } + + if (newx) + *newx = xx; + if (newy) + *newy = yy; +} + +static int reg_state_branch_taken_op(enum num_t t, struct reg_state *x, struct reg_state *y, + enum op op) +{ + if (op == OP_EQ || op == OP_NE) { + /* OP_EQ and OP_NE are sign-agnostic */ + enum num_t tu = t_unsigned(t); + enum num_t ts = t_signed(t); + int br_u, br_s; + + br_u = range_branch_taken_op(tu, x->r[tu], y->r[tu], op); + br_s = range_branch_taken_op(ts, x->r[ts], y->r[ts], op); + + if (br_u >= 0 && br_s >= 0 && br_u != br_s) + ASSERT_FALSE(true, "branch taken inconsistency!\n"); + if (br_u >= 0) + return br_u; + return br_s; + } + return range_branch_taken_op(t, x->r[t], y->r[t], op); +} + +/* ===================================== + * BPF PROGS GENERATION AND VERIFICATION + * ===================================== + */ +struct case_spec { + /* whether to init full register (r1) or sub-register (w1) */ + bool init_subregs; + /* whether to establish initial value range on full register (r1) or + * sub-register (w1) + */ + bool setup_subregs; + /* whether to establish initial value range using signed or unsigned + * comparisons (i.e., initialize umin/umax or smin/smax directly) + */ + bool setup_signed; + /* whether to perform comparison on full registers or sub-registers */ + bool compare_subregs; + /* whether to perform comparison using signed or unsigned operations */ + bool compare_signed; +}; + +/* Generate test BPF program based on provided test ranges, operation, and + * specifications about register bitness and signedness. + */ +static int load_range_cmp_prog(struct range x, struct range y, enum op op, + int branch_taken, struct case_spec spec, + char *log_buf, size_t log_sz, + int *false_pos, int *true_pos) +{ +#define emit(insn) ({ \ + struct bpf_insn __insns[] = { insn }; \ + int __i; \ + for (__i = 0; __i < ARRAY_SIZE(__insns); __i++) \ + insns[cur_pos + __i] = __insns[__i]; \ + cur_pos += __i; \ +}) +#define JMP_TO(target) (target - cur_pos - 1) + int cur_pos = 0, exit_pos, fd, op_code; + struct bpf_insn insns[64]; + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .log_level = 2, + .log_buf = log_buf, + .log_size = log_sz, + ); + + /* ; skip exit block below + * goto +2; + */ + emit(BPF_JMP_A(2)); + exit_pos = cur_pos; + /* ; exit block for all the preparatory conditionals + * out: + * r0 = 0; + * exit; + */ + emit(BPF_MOV64_IMM(BPF_REG_0, 0)); + emit(BPF_EXIT_INSN()); + /* + * ; assign r6/w6 and r7/w7 unpredictable u64/u32 value + * call bpf_get_current_pid_tgid; + * r6 = r0; | w6 = w0; + * call bpf_get_current_pid_tgid; + * r7 = r0; | w7 = w0; + */ + emit(BPF_EMIT_CALL(BPF_FUNC_get_current_pid_tgid)); + if (spec.init_subregs) + emit(BPF_MOV32_REG(BPF_REG_6, BPF_REG_0)); + else + emit(BPF_MOV64_REG(BPF_REG_6, BPF_REG_0)); + emit(BPF_EMIT_CALL(BPF_FUNC_get_current_pid_tgid)); + if (spec.init_subregs) + emit(BPF_MOV32_REG(BPF_REG_7, BPF_REG_0)); + else + emit(BPF_MOV64_REG(BPF_REG_7, BPF_REG_0)); + /* ; setup initial r6/w6 possible value range ([x.a, x.b]) + * r1 = %[x.a] ll; | w1 = %[x.a]; + * r2 = %[x.b] ll; | w2 = %[x.b]; + * if r6 < r1 goto out; | if w6 < w1 goto out; + * if r6 > r2 goto out; | if w6 > w2 goto out; + */ + if (spec.setup_subregs) { + emit(BPF_MOV32_IMM(BPF_REG_1, (s32)x.a)); + emit(BPF_MOV32_IMM(BPF_REG_2, (s32)x.b)); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_6, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_6, BPF_REG_2, JMP_TO(exit_pos))); + } else { + emit(BPF_LD_IMM64(BPF_REG_1, x.a)); + emit(BPF_LD_IMM64(BPF_REG_2, x.b)); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_6, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_6, BPF_REG_2, JMP_TO(exit_pos))); + } + /* ; setup initial r7/w7 possible value range ([y.a, y.b]) + * r1 = %[y.a] ll; | w1 = %[y.a]; + * r2 = %[y.b] ll; | w2 = %[y.b]; + * if r7 < r1 goto out; | if w7 < w1 goto out; + * if r7 > r2 goto out; | if w7 > w2 goto out; + */ + if (spec.setup_subregs) { + emit(BPF_MOV32_IMM(BPF_REG_1, (s32)y.a)); + emit(BPF_MOV32_IMM(BPF_REG_2, (s32)y.b)); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_7, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_7, BPF_REG_2, JMP_TO(exit_pos))); + } else { + emit(BPF_LD_IMM64(BPF_REG_1, y.a)); + emit(BPF_LD_IMM64(BPF_REG_2, y.b)); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_7, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_7, BPF_REG_2, JMP_TO(exit_pos))); + } + /* ; range test instruction + * if r6 r7 goto +3; | if w6 w7 goto +3; + */ + switch (op) { + case OP_LT: op_code = spec.compare_signed ? BPF_JSLT : BPF_JLT; break; + case OP_LE: op_code = spec.compare_signed ? BPF_JSLE : BPF_JLE; break; + case OP_GT: op_code = spec.compare_signed ? BPF_JSGT : BPF_JGT; break; + case OP_GE: op_code = spec.compare_signed ? BPF_JSGE : BPF_JGE; break; + case OP_EQ: op_code = BPF_JEQ; break; + case OP_NE: op_code = BPF_JNE; break; + default: + printf("unrecognized op %d\n", op); + return -ENOTSUP; + } + /* ; BEFORE conditional, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * ; this is used for debugging, as verifier doesn't always print + * ; registers states as of condition jump instruction (e.g., when + * ; precision marking happens) + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + */ + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (spec.compare_subregs) + emit(BPF_JMP32_REG(op_code, BPF_REG_6, BPF_REG_7, 3)); + else + emit(BPF_JMP_REG(op_code, BPF_REG_6, BPF_REG_7, 3)); + /* ; FALSE branch, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + * exit; + */ + *false_pos = cur_pos; + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (branch_taken == 1) /* false branch is never taken */ + emit(BPF_EMIT_CALL(0xDEAD)); /* poison this branch */ + else + emit(BPF_EXIT_INSN()); + /* ; TRUE branch, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + * exit; + */ + *true_pos = cur_pos; + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (branch_taken == 0) /* true branch is never taken */ + emit(BPF_EMIT_CALL(0xDEAD)); /* poison this branch */ + emit(BPF_EXIT_INSN()); /* last instruction has to be exit */ + + fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT, "reg_bounds_test", + "GPL", insns, cur_pos, &opts); + if (fd < 0) + return fd; + + close(fd); + return 0; +#undef emit +#undef JMP_TO +} + +#define str_has_pfx(str, pfx) (strncmp(str, pfx, strlen(pfx)) == 0) + +/* Parse register state from verifier log. + * `s` should point to the start of "Rx = ..." substring in the verifier log. + */ +static int parse_reg_state(const char *s, struct reg_state *reg) +{ + /* There are two generic forms for SCALAR register: + * - known constant: R6_rwD=P%lld + * - range: R6_rwD=scalar(id=1,...), where "..." is a comma-separated + * list of optional range specifiers: + * - umin=%llu, if missing, assumed 0; + * - umax=%llu, if missing, assumed U64_MAX; + * - smin=%lld, if missing, assumed S64_MIN; + * - smax=%lld, if missing, assummed S64_MAX; + * - umin32=%d, if missing, assumed 0; + * - umax32=%d, if missing, assumed U32_MAX; + * - smin32=%d, if missing, assumed S32_MIN; + * - smax32=%d, if missing, assummed S32_MAX; + * - var_off=(%#llx; %#llx), tnum part, we don't care about it. + * + * If some of the values are equal, they will be grouped (but min/max + * are not mixed together, and similarly negative values are not + * grouped with non-negative ones). E.g.: + * + * R6_w=Pscalar(smin=smin32=0, smax=umax=umax32=1000) + * + * _rwD part is optional (and any of the letters can be missing). + * P (precision mark) is optional as well. + * + * Anything inside scalar() is optional, including id, of course. + */ + struct { + const char *pfx; + const char *fmt; + u64 *dst, def; + bool is_32, is_set; + } *f, fields[8] = { + {"smin=", "%lld", ®->r[S64].a, S64_MIN}, + {"smax=", "%lld", ®->r[S64].b, S64_MAX}, + {"umin=", "%llu", ®->r[U64].a, 0}, + {"umax=", "%llu", ®->r[U64].b, U64_MAX}, + {"smin32=", "%lld", ®->r[S32].a, (u32)S32_MIN, true}, + {"smax32=", "%lld", ®->r[S32].b, (u32)S32_MAX, true}, + {"umin32=", "%llu", ®->r[U32].a, 0, true}, + {"umax32=", "%llu", ®->r[U32].b, U32_MAX, true}, + }; + const char *p, *fmt; + int i; + + p = strchr(s, '='); + if (!p) + return -EINVAL; + p++; + if (*p == 'P') + p++; + + if (!str_has_pfx(p, "scalar(")) { + long long sval; + enum num_t t; + + if (sscanf(p, "%lld", &sval) != 1) + return -EINVAL; + + reg->valid = true; + for (t = first_t; t <= last_t; t++) { + reg->r[t] = range(t, sval, sval); + } + return 0; + } + + p += sizeof("scalar"); + while (p) { + int midxs[ARRAY_SIZE(fields)], mcnt = 0; + u64 val; + + for (i = 0; i < ARRAY_SIZE(fields); i++) { + f = &fields[i]; + if (!str_has_pfx(p, f->pfx)) + continue; + midxs[mcnt++] = i; + p += strlen(f->pfx); + } + + if (mcnt) { + /* populate all matched fields */ + fmt = fields[midxs[0]].fmt; + if (sscanf(p, fmt, &val) != 1) + return -EINVAL; + + for (i = 0; i < mcnt; i++) { + f = &fields[midxs[i]]; + f->is_set = true; + *f->dst = f->is_32 ? (u64)(u32)val : val; + } + } else if (str_has_pfx(p, "var_off")) { + /* skip "var_off=(0x0; 0x3f)" part completely */ + p = strchr(p, ')'); + if (!p) + return -EINVAL; + p++; + } + + p = strpbrk(p, ",)"); + if (*p == ')') + break; + if (p) + p++; + } + + reg->valid = true; + + for (i = 0; i < ARRAY_SIZE(fields); i++) { + f = &fields[i]; + if (!f->is_set) + *f->dst = f->def; + } + + return 0; +} + + +/* Parse all register states (TRUE/FALSE branches and DST/SRC registers) + * out of the verifier log for a corresponding test case BPF program. + */ +static int parse_range_cmp_log(const char *log_buf, struct case_spec spec, + int false_pos, int true_pos, + struct reg_state *false1_reg, struct reg_state *false2_reg, + struct reg_state *true1_reg, struct reg_state *true2_reg) +{ + struct { + int insn_idx; + int reg_idx; + const char *reg_upper; + struct reg_state *state; + } specs[] = { + {false_pos, 6, "R6=", false1_reg}, + {false_pos + 1, 7, "R7=", false2_reg}, + {true_pos, 6, "R6=", true1_reg}, + {true_pos + 1, 7, "R7=", true2_reg}, + }; + char buf[32]; + const char *p = log_buf, *q; + int i, err; + + for (i = 0; i < 4; i++) { + sprintf(buf, "%d: (%s) %s = %s%d", specs[i].insn_idx, + spec.compare_subregs ? "bc" : "bf", + spec.compare_subregs ? "w0" : "r0", + spec.compare_subregs ? "w" : "r", specs[i].reg_idx); + + q = strstr(p, buf); + if (!q) { + *specs[i].state = (struct reg_state){.valid = false}; + continue; + } + p = strstr(q, specs[i].reg_upper); + if (!p) + return -EINVAL; + err = parse_reg_state(p, specs[i].state); + if (err) + return -EINVAL; + } + return 0; +} + +/* Validate ranges match, and print details if they don't */ +static bool assert_range_eq(enum num_t t, struct range x, struct range y, + const char *ctx1, const char *ctx2) +{ + DEFINE_STRBUF(sb, 512); + + if (range_eq(x, y)) + return true; + + snappendf(sb, "MISMATCH %s.%s: ", ctx1, ctx2); + snprintf_range(t, sb, x); + snappendf(sb, " != "); + snprintf_range(t, sb, y); + + printf("%s\n", sb->buf); + + return false; +} + +/* Validate that register states match, and print details if they don't */ +static bool assert_reg_state_eq(struct reg_state *r, struct reg_state *e, const char *ctx) +{ + bool ok = true; + enum num_t t; + + if (r->valid != e->valid) { + printf("MISMATCH %s: actual %s != expected %s\n", ctx, + r->valid ? "" : "", + e->valid ? "" : ""); + return false; + } + + if (!r->valid) + return true; + + for (t = first_t; t <= last_t; t++) { + if (!assert_range_eq(t, r->r[t], e->r[t], ctx, t_str(t))) + ok = false; + } + + return ok; +} + +/* Printf verifier log, filtering out irrelevant noise */ +static void print_verifier_log(const char *buf) +{ + const char *p; + + while (buf[0]) { + p = strchrnul(buf, '\n'); + + /* filter out irrelevant precision backtracking logs */ + if (str_has_pfx(buf, "mark_precise: ")) + goto skip_line; + + printf("%.*s\n", (int)(p - buf), buf); + +skip_line: + buf = *p == '\0' ? p : p + 1; + } +} + +/* Simulate provided test case purely with our own range-based logic. + * This is done to set up expectations for verifier's branch_taken logic and + * verifier's register states in the verifier log. + */ +static void sim_case(enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, enum op op, + struct reg_state *fr1, struct reg_state *fr2, + struct reg_state *tr1, struct reg_state *tr2, + int *branch_taken) +{ + const u64 A = x.a; + const u64 B = x.b; + const u64 C = y.a; + const u64 D = y.b; + struct reg_state rc; + enum op rev_op = complement_op(op); + enum num_t t; + + fr1->valid = fr2->valid = true; + tr1->valid = tr2->valid = true; + for (t = first_t; t <= last_t; t++) { + /* if we are initializing using 32-bit subregisters, + * full registers get upper 32 bits zeroed automatically + */ + struct range z = t_is_32(init_t) ? unkn_subreg(t) : unkn[t]; + + fr1->r[t] = fr2->r[t] = tr1->r[t] = tr2->r[t] = z; + } + + /* step 1: r1 >= A, r2 >= C */ + reg_state_set_const(&rc, init_t, A); + reg_state_cond(init_t, fr1, &rc, OP_GE, fr1, NULL, "r1>=A"); + reg_state_set_const(&rc, init_t, C); + reg_state_cond(init_t, fr2, &rc, OP_GE, fr2, NULL, "r2>=C"); + *tr1 = *fr1; + *tr2 = *fr2; + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP1 (%s) R1: ", t_str(init_t)); print_reg_state(fr1, "\n"); + printf("STEP1 (%s) R2: ", t_str(init_t)); print_reg_state(fr2, "\n"); + } + + /* step 2: r1 <= B, r2 <= D */ + reg_state_set_const(&rc, init_t, B); + reg_state_cond(init_t, fr1, &rc, OP_LE, fr1, NULL, "r1<=B"); + reg_state_set_const(&rc, init_t, D); + reg_state_cond(init_t, fr2, &rc, OP_LE, fr2, NULL, "r2<=D"); + *tr1 = *fr1; + *tr2 = *fr2; + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP2 (%s) R1: ", t_str(init_t)); print_reg_state(fr1, "\n"); + printf("STEP2 (%s) R2: ", t_str(init_t)); print_reg_state(fr2, "\n"); + } + + /* step 3: r1 r2 */ + *branch_taken = reg_state_branch_taken_op(cond_t, fr1, fr2, op); + fr1->valid = fr2->valid = false; + tr1->valid = tr2->valid = false; + if (*branch_taken != 1) { /* FALSE is possible */ + fr1->valid = fr2->valid = true; + reg_state_cond(cond_t, fr1, fr2, rev_op, fr1, fr2, "FALSE"); + } + if (*branch_taken != 0) { /* TRUE is possible */ + tr1->valid = tr2->valid = true; + reg_state_cond(cond_t, tr1, tr2, op, tr1, tr2, "TRUE"); + } + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP3 (%s) FALSE R1:", t_str(cond_t)); print_reg_state(fr1, "\n"); + printf("STEP3 (%s) FALSE R2:", t_str(cond_t)); print_reg_state(fr2, "\n"); + printf("STEP3 (%s) TRUE R1:", t_str(cond_t)); print_reg_state(tr1, "\n"); + printf("STEP3 (%s) TRUE R2:", t_str(cond_t)); print_reg_state(tr2, "\n"); + } +} + +/* =============================== + * HIGH-LEVEL TEST CASE VALIDATION + * =============================== + */ +static u32 upper_seeds[] = { + 0, + 1, + U32_MAX, + U32_MAX - 1, + S32_MAX, + (u32)S32_MIN, +}; + +static u32 lower_seeds[] = { + 0, + 1, + 2, (u32)-2, + 255, (u32)-255, + UINT_MAX, + UINT_MAX - 1, + INT_MAX, + (u32)INT_MIN, +}; + +struct ctx { + int val_cnt, subval_cnt, range_cnt, subrange_cnt; + u64 uvals[ARRAY_SIZE(upper_seeds) * ARRAY_SIZE(lower_seeds)]; + s64 svals[ARRAY_SIZE(upper_seeds) * ARRAY_SIZE(lower_seeds)]; + u32 usubvals[ARRAY_SIZE(lower_seeds)]; + s32 ssubvals[ARRAY_SIZE(lower_seeds)]; + struct range *uranges, *sranges; + struct range *usubranges, *ssubranges; + int max_failure_cnt, cur_failure_cnt; + int total_case_cnt, case_cnt; + __u64 start_ns; + char progress_ctx[32]; +}; + +static void cleanup_ctx(struct ctx *ctx) +{ + free(ctx->uranges); + free(ctx->sranges); + free(ctx->usubranges); + free(ctx->ssubranges); +} + +struct subtest_case { + enum num_t init_t; + enum num_t cond_t; + struct range x; + struct range y; + enum op op; +}; + +static void subtest_case_str(struct strbuf *sb, struct subtest_case *t) +{ + snappendf(sb, "(%s)", t_str(t->init_t)); + snprintf_range(t->init_t, sb, t->x); + snappendf(sb, " (%s)%s ", t_str(t->cond_t), op_str(t->op)); + snprintf_range(t->init_t, sb, t->y); +} + +/* Generate and validate test case based on specific combination of setup + * register ranges (including their expected num_t domain), and conditional + * operation to perform (including num_t domain in which it has to be + * performed) + */ +static int verify_case_op(enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, enum op op) +{ + char log_buf[256 * 1024]; + size_t log_sz = sizeof(log_buf); + int err, false_pos = 0, true_pos = 0, branch_taken; + struct reg_state fr1, fr2, tr1, tr2; + struct reg_state fe1, fe2, te1, te2; + bool failed = false; + struct case_spec spec = { + .init_subregs = (init_t == U32 || init_t == S32), + .setup_subregs = (init_t == U32 || init_t == S32), + .setup_signed = (init_t == S64 || init_t == S32), + .compare_subregs = (cond_t == U32 || cond_t == S32), + .compare_signed = (cond_t == S64 || cond_t == S32), + }; + + log_buf[0] = '\0'; + + sim_case(init_t, cond_t, x, y, op, &fe1, &fe2, &te1, &te2, &branch_taken); + + err = load_range_cmp_prog(x, y, op, branch_taken, spec, + log_buf, log_sz, &false_pos, &true_pos); + if (err) { + ASSERT_OK(err, "load_range_cmp_prog"); + failed = true; + } + + err = parse_range_cmp_log(log_buf, spec, false_pos, true_pos, + &fr1, &fr2, &tr1, &tr2); + if (err) { + ASSERT_OK(err, "parse_range_cmp_log"); + failed = true; + } + + if (!assert_reg_state_eq(&fr1, &fe1, "false_reg1") || + !assert_reg_state_eq(&fr2, &fe2, "false_reg2") || + !assert_reg_state_eq(&tr1, &te1, "true_reg1") || + !assert_reg_state_eq(&tr2, &te2, "true_reg2")) { + failed = true; + } + + if (failed || env.verbosity >= VERBOSE_NORMAL) { + if (failed || env.verbosity >= VERBOSE_VERY) { + printf("VERIFIER LOG:\n========================\n"); + print_verifier_log(log_buf); + printf("=====================\n"); + } + printf("ACTUAL FALSE1: "); print_reg_state(&fr1, "\n"); + printf("EXPECTED FALSE1: "); print_reg_state(&fe1, "\n"); + printf("ACTUAL FALSE2: "); print_reg_state(&fr2, "\n"); + printf("EXPECTED FALSE2: "); print_reg_state(&fe2, "\n"); + printf("ACTUAL TRUE1: "); print_reg_state(&tr1, "\n"); + printf("EXPECTED TRUE1: "); print_reg_state(&te1, "\n"); + printf("ACTUAL TRUE2: "); print_reg_state(&tr2, "\n"); + printf("EXPECTED TRUE2: "); print_reg_state(&te2, "\n"); + + return failed ? -EINVAL : 0; + } + + return 0; +} + +/* Given setup ranges and number types, go over all supported operations, + * generating individual subtest for each allowed combination + */ +static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, + struct range x, struct range y) +{ + DEFINE_STRBUF(sb, 256); + int err; + struct subtest_case sub = { + .init_t = init_t, + .cond_t = cond_t, + .x = x, + .y = y, + }; + + for (sub.op = first_op; sub.op <= last_op; sub.op++) { + sb->pos = 0; /* reset position in strbuf */ + subtest_case_str(sb, &sub); + if (!test__start_subtest(sb->buf)) + continue; + + if (env.verbosity >= VERBOSE_NORMAL) /* this speeds up debugging */ + printf("TEST CASE: %s\n", sb->buf); + + err = verify_case_op(init_t, cond_t, x, y, sub.op); + if (err || env.verbosity >= VERBOSE_NORMAL) + ASSERT_OK(err, sb->buf); + if (err) { + ctx->cur_failure_cnt++; + if (ctx->cur_failure_cnt > ctx->max_failure_cnt) + return err; + return 0; /* keep testing other cases */ + } + ctx->case_cnt++; + if ((ctx->case_cnt % 10000) == 0) { + double progress = (ctx->case_cnt + 0.0) / ctx->total_case_cnt; + u64 elapsed_ns = get_time_ns() - ctx->start_ns; + double remain_ns = elapsed_ns / progress * (1 - progress); + + fprintf(env.stderr, "PROGRESS (%s): %d/%d (%.2lf%%), " + "elapsed %llu mins (%.2lf hrs), " + "ETA %.0lf mins (%.2lf hrs)\n", + ctx->progress_ctx, + ctx->case_cnt, ctx->total_case_cnt, 100.0 * progress, + elapsed_ns / 1000000000 / 60, + elapsed_ns / 1000000000.0 / 3600, + remain_ns / 1000000000.0 / 60, + remain_ns / 1000000000.0 / 3600); + } + } + + return 0; +} + +/* ================================ + * GENERATED CASES FROM SEED VALUES + * ================================ + */ +static int u64_cmp(const void *p1, const void *p2) +{ + u64 x1 = *(const u64 *)p1, x2 = *(const u64 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int u32_cmp(const void *p1, const void *p2) +{ + u32 x1 = *(const u32 *)p1, x2 = *(const u32 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int s64_cmp(const void *p1, const void *p2) +{ + s64 x1 = *(const s64 *)p1, x2 = *(const s64 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int s32_cmp(const void *p1, const void *p2) +{ + s32 x1 = *(const s32 *)p1, x2 = *(const s32 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +/* Generate valid unique constants from seeds, both signed and unsigned */ +static void gen_vals(struct ctx *ctx) +{ + int i, j, cnt = 0; + + for (i = 0; i < ARRAY_SIZE(upper_seeds); i++) { + for (j = 0; j < ARRAY_SIZE(lower_seeds); j++) { + ctx->uvals[cnt++] = (((u64)upper_seeds[i]) << 32) | lower_seeds[j]; + } + } + + /* sort and compact uvals (i.e., it's `sort | uniq`) */ + qsort(ctx->uvals, cnt, sizeof(*ctx->uvals), u64_cmp); + for (i = 1, j = 0; i < cnt; i++) { + if (ctx->uvals[j] == ctx->uvals[i]) + continue; + j++; + ctx->uvals[j] = ctx->uvals[i]; + } + ctx->val_cnt = j + 1; + + /* we have exactly the same number of s64 values, they are just in + * a different order than u64s, so just sort them differently + */ + for (i = 0; i < ctx->val_cnt; i++) + ctx->svals[i] = ctx->uvals[i]; + qsort(ctx->svals, ctx->val_cnt, sizeof(*ctx->svals), s64_cmp); + + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + for (i = 0; i < ctx->val_cnt; i++) { + sb1->pos = sb2->pos = 0; + snprintf_num(U64, sb1, ctx->uvals[i]); + snprintf_num(S64, sb2, ctx->svals[i]); + printf("SEED #%d: u64=%-20s s64=%-20s\n", i, sb1->buf, sb2->buf); + } + } + + /* 32-bit values are generated separately */ + cnt = 0; + for (i = 0; i < ARRAY_SIZE(lower_seeds); i++) { + ctx->usubvals[cnt++] = lower_seeds[i]; + } + + /* sort and compact usubvals (i.e., it's `sort | uniq`) */ + qsort(ctx->usubvals, cnt, sizeof(*ctx->usubvals), u32_cmp); + for (i = 1, j = 0; i < cnt; i++) { + if (ctx->usubvals[j] == ctx->usubvals[i]) + continue; + j++; + ctx->usubvals[j] = ctx->usubvals[i]; + } + ctx->subval_cnt = j + 1; + + for (i = 0; i < ctx->subval_cnt; i++) + ctx->ssubvals[i] = ctx->usubvals[i]; + qsort(ctx->ssubvals, ctx->subval_cnt, sizeof(*ctx->ssubvals), s32_cmp); + + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + for (i = 0; i < ctx->subval_cnt; i++) { + sb1->pos = sb2->pos = 0; + snprintf_num(U32, sb1, ctx->usubvals[i]); + snprintf_num(S32, sb2, ctx->ssubvals[i]); + printf("SUBSEED #%d: u32=%-10s s32=%-10s\n", i, sb1->buf, sb2->buf); + } + } +} + +/* Generate valid ranges from upper/lower seeds */ +static int gen_ranges(struct ctx *ctx) +{ + int i, j, cnt = 0; + + for (i = 0; i < ctx->val_cnt; i++) { + for (j = i; j < ctx->val_cnt; j++) { + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + sb1->pos = sb2->pos = 0; + snprintf_range(U64, sb1, range(U64, ctx->uvals[i], ctx->uvals[j])); + snprintf_range(S64, sb2, range(S64, ctx->svals[i], ctx->svals[j])); + printf("RANGE #%d: u64=%-40s s64=%-40s\n", cnt, sb1->buf, sb2->buf); + } + cnt++; + } + } + ctx->range_cnt = cnt; + + ctx->uranges = calloc(ctx->range_cnt, sizeof(*ctx->uranges)); + if (!ASSERT_OK_PTR(ctx->uranges, "uranges_calloc")) + return -EINVAL; + ctx->sranges = calloc(ctx->range_cnt, sizeof(*ctx->sranges)); + if (!ASSERT_OK_PTR(ctx->sranges, "sranges_calloc")) + return -EINVAL; + + cnt = 0; + for (i = 0; i < ctx->val_cnt; i++) { + for (j = i; j < ctx->val_cnt; j++) { + ctx->uranges[cnt] = range(U64, ctx->uvals[i], ctx->uvals[j]); + ctx->sranges[cnt] = range(S64, ctx->svals[i], ctx->svals[j]); + cnt++; + } + } + + cnt = 0; + for (i = 0; i < ctx->subval_cnt; i++) { + for (j = i; j < ctx->subval_cnt; j++) { + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + sb1->pos = sb2->pos = 0; + snprintf_range(U32, sb1, range(U32, ctx->usubvals[i], ctx->usubvals[j])); + snprintf_range(S32, sb2, range(S32, ctx->ssubvals[i], ctx->ssubvals[j])); + printf("SUBRANGE #%d: u32=%-20s s32=%-20s\n", cnt, sb1->buf, sb2->buf); + } + cnt++; + } + } + ctx->subrange_cnt = cnt; + + ctx->usubranges = calloc(ctx->subrange_cnt, sizeof(*ctx->usubranges)); + if (!ASSERT_OK_PTR(ctx->usubranges, "usubranges_calloc")) + return -EINVAL; + ctx->ssubranges = calloc(ctx->subrange_cnt, sizeof(*ctx->ssubranges)); + if (!ASSERT_OK_PTR(ctx->ssubranges, "ssubranges_calloc")) + return -EINVAL; + + cnt = 0; + for (i = 0; i < ctx->subval_cnt; i++) { + for (j = i; j < ctx->subval_cnt; j++) { + ctx->usubranges[cnt] = range(U32, ctx->usubvals[i], ctx->usubvals[j]); + ctx->ssubranges[cnt] = range(S32, ctx->ssubvals[i], ctx->ssubvals[j]); + cnt++; + } + } + + return 0; +} + +static int parse_env_vars(struct ctx *ctx) +{ + const char *s; + + if (!(s = getenv("SLOW_TESTS")) || strcmp(s, "1") != 0) { + test__skip(); + return -ENOTSUP; + } + + if ((s = getenv("REG_BOUNDS_MAX_FAILURE_CNT"))) { + errno = 0; + ctx->max_failure_cnt = strtol(s, NULL, 10); + if (errno || ctx->max_failure_cnt < 0) { + ASSERT_OK(-errno, "REG_BOUNDS_MAX_FAILURE_CNT"); + return -EINVAL; + } + } + + return 0; +} + +static int prepare_gen_tests(struct ctx *ctx) +{ + int err; + + err = parse_env_vars(ctx); + if (err) + return err; + + gen_vals(ctx); + err = gen_ranges(ctx); + if (err) { + ASSERT_OK(err, "gen_ranges"); + return err; + } + + return 0; +} + +/* Go over generated constants and ranges and validate various supported + * combinations of them + */ +static void validate_gen_range_vs_const_64(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + struct range rconst; + const struct range *ranges; + const u64 *vals; + int i, j; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + ranges = init_t == U64 ? ctx.uranges : ctx.sranges; + vals = init_t == U64 ? ctx.uvals : (const u64 *)ctx.svals; + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.range_cnt * ctx.val_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x CONST, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < ctx.val_cnt; i++) { + for (j = 0; j < ctx.range_cnt; j++) { + rconst = range(init_t, vals[i], vals[i]); + + /* (u64|s64)( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[j], rconst)) + goto cleanup; + /* (u64|s64)( x ) */ + if (verify_case(&ctx, init_t, cond_t, rconst, ranges[j])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + +static void validate_gen_range_vs_const_32(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + struct range rconst; + const struct range *ranges; + const u32 *vals; + int i, j; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + ranges = init_t == U32 ? ctx.usubranges : ctx.ssubranges; + vals = init_t == U32 ? ctx.usubvals : (const u32 *)ctx.ssubvals; + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.subrange_cnt * ctx.subval_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x CONST, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < ctx.subval_cnt; i++) { + for (j = 0; j < ctx.subrange_cnt; j++) { + rconst = range(init_t, vals[i], vals[i]); + + /* (u32|s32)( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[j], rconst)) + goto cleanup; + /* (u32|s32)( x ) */ + if (verify_case(&ctx, init_t, cond_t, rconst, ranges[j])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + +/* Go over thousands of test cases generated from initial seed values. + * Given this take a long time, guard this begind SLOW_TESTS=1 envvar. If + * envvar is not set, this test is skipped during test_progs testing. + * + * We split this up into smaller subsets based on initialization and + * conditiona numeric domains to get an easy parallelization with test_progs' + * -j argument. + */ + +/* RANGE x CONST, U64 initial range */ +void test_reg_bounds_gen_consts_u64_u64(void) { validate_gen_range_vs_const_64(U64, U64); } +void test_reg_bounds_gen_consts_u64_s64(void) { validate_gen_range_vs_const_64(U64, S64); } +void test_reg_bounds_gen_consts_u64_u32(void) { validate_gen_range_vs_const_64(U64, U32); } +void test_reg_bounds_gen_consts_u64_s32(void) { validate_gen_range_vs_const_64(U64, S32); } +/* RANGE x CONST, S64 initial range */ +void test_reg_bounds_gen_consts_s64_u64(void) { validate_gen_range_vs_const_64(S64, U64); } +void test_reg_bounds_gen_consts_s64_s64(void) { validate_gen_range_vs_const_64(S64, S64); } +void test_reg_bounds_gen_consts_s64_u32(void) { validate_gen_range_vs_const_64(S64, U32); } +void test_reg_bounds_gen_consts_s64_s32(void) { validate_gen_range_vs_const_64(S64, S32); } +/* RANGE x CONST, U32 initial range */ +void test_reg_bounds_gen_consts_u32_u64(void) { validate_gen_range_vs_const_32(U32, U64); } +void test_reg_bounds_gen_consts_u32_s64(void) { validate_gen_range_vs_const_32(U32, S64); } +void test_reg_bounds_gen_consts_u32_u32(void) { validate_gen_range_vs_const_32(U32, U32); } +void test_reg_bounds_gen_consts_u32_s32(void) { validate_gen_range_vs_const_32(U32, S32); } +/* RANGE x CONST, S32 initial range */ +void test_reg_bounds_gen_consts_s32_u64(void) { validate_gen_range_vs_const_32(S32, U64); } +void test_reg_bounds_gen_consts_s32_s64(void) { validate_gen_range_vs_const_32(S32, S64); } +void test_reg_bounds_gen_consts_s32_u32(void) { validate_gen_range_vs_const_32(S32, U32); } +void test_reg_bounds_gen_consts_s32_s32(void) { validate_gen_range_vs_const_32(S32, S32); } + +/* A set of hard-coded "interesting" cases to validate as part of normal + * test_progs test runs + */ +static struct subtest_case crafted_cases[] = { + {U64, U64, {0, 0xffffffff}, {0, 0}}, + {U64, U64, {0, 0x80000000}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x100000100ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x180000000ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1ffffff00ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1ffffff01ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1fffffffeULL}, {0, 0}}, + {U64, U64, {0x100000001ULL, 0x1000000ffULL}, {0, 0}}, + + {U64, S64, {0, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0x7fffffffffffffffULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0, 0xffffffffULL}, {1, 1}}, + {U64, S64, {0, 0xffffffffULL}, {0x7fffffff, 0x7fffffff}}, + + {U64, U32, {0, 0x100000000}, {0, 0}}, + {U64, U32, {0xfffffffe, 0x100000000}, {0x80000000, 0x80000000}}, + + {U64, S32, {0, 0xffffffff00000000ULL}, {0, 0}}, + /* these are tricky cases where lower 32 bits allow to tighten 64 + * bit boundaries based on tightened lower 32 bit boundaries + */ + {U64, S32, {0, 0x0ffffffffULL}, {0, 0}}, + {U64, S32, {0, 0x100000000ULL}, {0, 0}}, + {U64, S32, {0, 0x100000001ULL}, {0, 0}}, + {U64, S32, {0, 0x180000000ULL}, {0, 0}}, + {U64, S32, {0, 0x17fffffffULL}, {0, 0}}, + {U64, S32, {0, 0x180000001ULL}, {0, 0}}, + + /* verifier knows about [-1, 0] range for s32 for this case already */ + {S64, S64, {0xffffffffffffffffULL, 0}, {0xffffffff00000000ULL, 0xffffffff00000000ULL}}, + /* but didn't know about these cases initially */ + {U64, U64, {0xffffffff, 0x100000000ULL}, {0, 0}}, /* s32: [-1, 0] */ + {U64, U64, {0xffffffff, 0x100000001ULL}, {0, 0}}, /* s32: [-1, 1] */ + + /* longer convergence case: learning from u64 -> s64 -> u64 -> u32, + * arriving at u32: [1, U32_MAX] (instead of more pessimistic [0, U32_MAX]) + */ + {S64, U64, {0xffffffff00000001ULL, 0}, {0xffffffff00000000ULL, 0xffffffff00000000ULL}}, + + {U32, U32, {1, U32_MAX}, {0, 0}}, + + {U32, S32, {0, U32_MAX}, {U32_MAX, U32_MAX}}, +}; + +/* Go over crafted hard-coded cases. This is fast, so we do it as part of + * normal test_progs run. + */ +void test_reg_bounds_crafted(void) +{ + struct ctx ctx; + int i; + + memset(&ctx, 0, sizeof(ctx)); + + for (i = 0; i < ARRAY_SIZE(crafted_cases); i++) { + struct subtest_case *c = &crafted_cases[i]; + + verify_case(&ctx, c->init_t, c->cond_t, c->x, c->y); + verify_case(&ctx, c->init_t, c->cond_t, c->y, c->x); + } + + cleanup_ctx(&ctx); +} From 774f94c5e74d86d554c4fd1e97c517a1a7ee7fe0 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:04 -0800 Subject: [PATCH 0695/7721] selftests/bpf: adjust OP_EQ/OP_NE handling to use subranges for branch taken Similar to kernel-side BPF verifier logic enhancements, use 32-bit subrange knowledge for is_branch_taken() logic in reg_bounds selftests. Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20231112010609.848406-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/reg_bounds.c | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index 7a524b381ed3..10f3b6898274 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -748,16 +748,38 @@ static int reg_state_branch_taken_op(enum num_t t, struct reg_state *x, struct r /* OP_EQ and OP_NE are sign-agnostic */ enum num_t tu = t_unsigned(t); enum num_t ts = t_signed(t); - int br_u, br_s; + int br_u, br_s, br; br_u = range_branch_taken_op(tu, x->r[tu], y->r[tu], op); br_s = range_branch_taken_op(ts, x->r[ts], y->r[ts], op); if (br_u >= 0 && br_s >= 0 && br_u != br_s) ASSERT_FALSE(true, "branch taken inconsistency!\n"); - if (br_u >= 0) - return br_u; - return br_s; + + /* if 64-bit ranges are indecisive, use 32-bit subranges to + * eliminate always/never taken branches, if possible + */ + if (br_u == -1 && (t == U64 || t == S64)) { + br = range_branch_taken_op(U32, x->r[U32], y->r[U32], op); + /* we can only reject for OP_EQ, never take branch + * based on lower 32 bits + */ + if (op == OP_EQ && br == 0) + return 0; + /* for OP_NEQ we can be conclusive only if lower 32 bits + * differ and thus inequality branch is always taken + */ + if (op == OP_NE && br == 1) + return 1; + + br = range_branch_taken_op(S32, x->r[S32], y->r[S32], op); + if (op == OP_EQ && br == 0) + return 0; + if (op == OP_NE && br == 1) + return 1; + } + + return br_u >= 0 ? br_u : br_s; } return range_branch_taken_op(t, x->r[t], y->r[t], op); } From 2b0d204e368b306d4db894749947ed591b667ec5 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:05 -0800 Subject: [PATCH 0696/7721] selftests/bpf: add range x range test to reg_bounds Now that verifier supports range vs range bounds adjustments, validate that by checking each generated range against every other generated range, across all supported operators (everything by JSET). We also add few cases that were problematic during development either for verifier or for selftest's range tracking implementation. Note that we utilize the same trick with splitting everything into multiple independent parallelizable tests, but init_t and cond_t. This brings down verification time in parallel mode from more than 8 hours down to less that 1.5 hours. 106 million cases were successfully validate for range vs range logic, in addition to about 7 million range vs const cases, added in earlier patch. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/reg_bounds.c | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index 10f3b6898274..5320fe5d9433 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -1760,6 +1760,60 @@ static void validate_gen_range_vs_const_32(enum num_t init_t, enum num_t cond_t) cleanup_ctx(&ctx); } +static void validate_gen_range_vs_range(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + const struct range *ranges; + int i, j, rcnt; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + switch (init_t) + { + case U64: + ranges = ctx.uranges; + rcnt = ctx.range_cnt; + break; + case U32: + ranges = ctx.usubranges; + rcnt = ctx.subrange_cnt; + break; + case S64: + ranges = ctx.sranges; + rcnt = ctx.range_cnt; + break; + case S32: + ranges = ctx.ssubranges; + rcnt = ctx.subrange_cnt; + break; + default: + printf("validate_gen_range_vs_range!\n"); + exit(1); + } + + ctx.total_case_cnt = (MAX_OP - MIN_OP + 1) * (2 * rcnt * (rcnt + 1) / 2); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x RANGE, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < rcnt; i++) { + for (j = i; j < rcnt; j++) { + /* ( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[i], ranges[j])) + goto cleanup; + if (verify_case(&ctx, init_t, cond_t, ranges[j], ranges[i])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + /* Go over thousands of test cases generated from initial seed values. * Given this take a long time, guard this begind SLOW_TESTS=1 envvar. If * envvar is not set, this test is skipped during test_progs testing. @@ -1790,6 +1844,27 @@ void test_reg_bounds_gen_consts_s32_s64(void) { validate_gen_range_vs_const_32(S void test_reg_bounds_gen_consts_s32_u32(void) { validate_gen_range_vs_const_32(S32, U32); } void test_reg_bounds_gen_consts_s32_s32(void) { validate_gen_range_vs_const_32(S32, S32); } +/* RANGE x RANGE, U64 initial range */ +void test_reg_bounds_gen_ranges_u64_u64(void) { validate_gen_range_vs_range(U64, U64); } +void test_reg_bounds_gen_ranges_u64_s64(void) { validate_gen_range_vs_range(U64, S64); } +void test_reg_bounds_gen_ranges_u64_u32(void) { validate_gen_range_vs_range(U64, U32); } +void test_reg_bounds_gen_ranges_u64_s32(void) { validate_gen_range_vs_range(U64, S32); } +/* RANGE x RANGE, S64 initial range */ +void test_reg_bounds_gen_ranges_s64_u64(void) { validate_gen_range_vs_range(S64, U64); } +void test_reg_bounds_gen_ranges_s64_s64(void) { validate_gen_range_vs_range(S64, S64); } +void test_reg_bounds_gen_ranges_s64_u32(void) { validate_gen_range_vs_range(S64, U32); } +void test_reg_bounds_gen_ranges_s64_s32(void) { validate_gen_range_vs_range(S64, S32); } +/* RANGE x RANGE, U32 initial range */ +void test_reg_bounds_gen_ranges_u32_u64(void) { validate_gen_range_vs_range(U32, U64); } +void test_reg_bounds_gen_ranges_u32_s64(void) { validate_gen_range_vs_range(U32, S64); } +void test_reg_bounds_gen_ranges_u32_u32(void) { validate_gen_range_vs_range(U32, U32); } +void test_reg_bounds_gen_ranges_u32_s32(void) { validate_gen_range_vs_range(U32, S32); } +/* RANGE x RANGE, S32 initial range */ +void test_reg_bounds_gen_ranges_s32_u64(void) { validate_gen_range_vs_range(S32, U64); } +void test_reg_bounds_gen_ranges_s32_s64(void) { validate_gen_range_vs_range(S32, S64); } +void test_reg_bounds_gen_ranges_s32_u32(void) { validate_gen_range_vs_range(S32, U32); } +void test_reg_bounds_gen_ranges_s32_s32(void) { validate_gen_range_vs_range(S32, S32); } + /* A set of hard-coded "interesting" cases to validate as part of normal * test_progs test runs */ @@ -1803,6 +1878,12 @@ static struct subtest_case crafted_cases[] = { {U64, U64, {0x100000000ULL, 0x1fffffffeULL}, {0, 0}}, {U64, U64, {0x100000001ULL, 0x1000000ffULL}, {0, 0}}, + /* single point overlap, interesting BPF_EQ and BPF_NE interactions */ + {U64, U64, {0, 1}, {1, 0x80000000}}, + {U64, S64, {0, 1}, {1, 0x80000000}}, + {U64, U32, {0, 1}, {1, 0x80000000}}, + {U64, S32, {0, 1}, {1, 0x80000000}}, + {U64, S64, {0, 0xffffffff00000000ULL}, {0, 0}}, {U64, S64, {0x7fffffffffffffffULL, 0xffffffff00000000ULL}, {0, 0}}, {U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}}, @@ -1837,6 +1918,11 @@ static struct subtest_case crafted_cases[] = { {U32, U32, {1, U32_MAX}, {0, 0}}, {U32, S32, {0, U32_MAX}, {U32_MAX, U32_MAX}}, + + {S32, U64, {(u32)(s32)S32_MIN, (u32)(s32)S32_MIN}, {(u32)(s32)-255, 0}}, + {S32, S64, {(u32)(s32)S32_MIN, (u32)(s32)-255}, {(u32)(s32)-2, 0}}, + {S32, S64, {0, 1}, {(u32)(s32)S32_MIN, (u32)(s32)S32_MIN}}, + {S32, U32, {(u32)(s32)S32_MIN, (u32)(s32)S32_MIN}, {(u32)(s32)S32_MIN, (u32)(s32)S32_MIN}}, }; /* Go over crafted hard-coded cases. This is fast, so we do it as part of From dab16659c50e8c9c7c5d9584beacec28c769dcca Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:06 -0800 Subject: [PATCH 0697/7721] selftests/bpf: add randomized reg_bounds tests Add random cases generation to reg_bounds.c and run them without SLOW_TESTS=1 to increase a chance of BPF CI catching latent issues. Suggested-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-11-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/reg_bounds.c | 166 +++++++++++++++++- 1 file changed, 159 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index 5320fe5d9433..f3f724062b35 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -83,6 +83,17 @@ static __always_inline u64 max_t(enum num_t t, u64 x, u64 y) } } +static __always_inline u64 cast_t(enum num_t t, u64 x) +{ + switch (t) { + case U64: return (u64)x; + case U32: return (u32)x; + case S64: return (s64)x; + case S32: return (u32)(s32)x; + default: printf("cast_t!\n"); exit(1); + } +} + static const char *t_str(enum num_t t) { switch (t) { @@ -1312,8 +1323,10 @@ struct ctx { struct range *usubranges, *ssubranges; int max_failure_cnt, cur_failure_cnt; int total_case_cnt, case_cnt; + int rand_case_cnt; + unsigned rand_seed; __u64 start_ns; - char progress_ctx[32]; + char progress_ctx[64]; }; static void cleanup_ctx(struct ctx *ctx) @@ -1644,11 +1657,6 @@ static int parse_env_vars(struct ctx *ctx) { const char *s; - if (!(s = getenv("SLOW_TESTS")) || strcmp(s, "1") != 0) { - test__skip(); - return -ENOTSUP; - } - if ((s = getenv("REG_BOUNDS_MAX_FAILURE_CNT"))) { errno = 0; ctx->max_failure_cnt = strtol(s, NULL, 10); @@ -1658,13 +1666,37 @@ static int parse_env_vars(struct ctx *ctx) } } + if ((s = getenv("REG_BOUNDS_RAND_CASE_CNT"))) { + errno = 0; + ctx->rand_case_cnt = strtol(s, NULL, 10); + if (errno || ctx->rand_case_cnt < 0) { + ASSERT_OK(-errno, "REG_BOUNDS_RAND_CASE_CNT"); + return -EINVAL; + } + } + + if ((s = getenv("REG_BOUNDS_RAND_SEED"))) { + errno = 0; + ctx->rand_seed = strtoul(s, NULL, 10); + if (errno) { + ASSERT_OK(-errno, "REG_BOUNDS_RAND_SEED"); + return -EINVAL; + } + } + return 0; } static int prepare_gen_tests(struct ctx *ctx) { + const char *s; int err; + if (!(s = getenv("SLOW_TESTS")) || strcmp(s, "1") != 0) { + test__skip(); + return -ENOTSUP; + } + err = parse_env_vars(ctx); if (err) return err; @@ -1794,7 +1826,7 @@ static void validate_gen_range_vs_range(enum num_t init_t, enum num_t cond_t) exit(1); } - ctx.total_case_cnt = (MAX_OP - MIN_OP + 1) * (2 * rcnt * (rcnt + 1) / 2); + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * rcnt * (rcnt + 1) / 2); ctx.start_ns = get_time_ns(); snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), "RANGE x RANGE, %s -> %s", @@ -1865,6 +1897,126 @@ void test_reg_bounds_gen_ranges_s32_s64(void) { validate_gen_range_vs_range(S32, void test_reg_bounds_gen_ranges_s32_u32(void) { validate_gen_range_vs_range(S32, U32); } void test_reg_bounds_gen_ranges_s32_s32(void) { validate_gen_range_vs_range(S32, S32); } +#define DEFAULT_RAND_CASE_CNT 25 + +#define RAND_21BIT_MASK ((1 << 22) - 1) + +static u64 rand_u64() +{ + /* RAND_MAX is guaranteed to be at least 1<<15, but in practice it + * seems to be 1<<31, so we need to call it thrice to get full u64; + * we'll use rougly equal split: 22 + 21 + 21 bits + */ + return ((u64)random() << 42) | + (((u64)random() & RAND_21BIT_MASK) << 21) | + (random() & RAND_21BIT_MASK); +} + +static u64 rand_const(enum num_t t) +{ + return cast_t(t, rand_u64()); +} + +static struct range rand_range(enum num_t t) +{ + u64 x = rand_const(t), y = rand_const(t); + + return range(t, min_t(t, x, y), max_t(t, x, y)); +} + +static void validate_rand_ranges(enum num_t init_t, enum num_t cond_t, bool const_range) +{ + struct ctx ctx; + struct range range1, range2; + int err, i; + u64 t; + + memset(&ctx, 0, sizeof(ctx)); + + err = parse_env_vars(&ctx); + if (err) { + ASSERT_OK(err, "parse_env_vars"); + return; + } + + if (ctx.rand_case_cnt == 0) + ctx.rand_case_cnt = DEFAULT_RAND_CASE_CNT; + if (ctx.rand_seed == 0) + ctx.rand_seed = (unsigned)get_time_ns(); + + srandom(ctx.rand_seed); + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.rand_case_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "[RANDOM SEED %u] RANGE x %s, %s -> %s", + ctx.rand_seed, const_range ? "CONST" : "RANGE", + t_str(init_t), t_str(cond_t)); + fprintf(env.stdout, "%s\n", ctx.progress_ctx); + + for (i = 0; i < ctx.rand_case_cnt; i++) { + range1 = rand_range(init_t); + if (const_range) { + t = rand_const(init_t); + range2 = range(init_t, t, t); + } else { + range2 = rand_range(init_t); + } + + /* x */ + if (verify_case(&ctx, init_t, cond_t, range1, range2)) + goto cleanup; + /* x */ + if (verify_case(&ctx, init_t, cond_t, range2, range1)) + goto cleanup; + } + +cleanup: + cleanup_ctx(&ctx); +} + +/* [RANDOM] RANGE x CONST, U64 initial range */ +void test_reg_bounds_rand_consts_u64_u64(void) { validate_rand_ranges(U64, U64, true /* const */); } +void test_reg_bounds_rand_consts_u64_s64(void) { validate_rand_ranges(U64, S64, true /* const */); } +void test_reg_bounds_rand_consts_u64_u32(void) { validate_rand_ranges(U64, U32, true /* const */); } +void test_reg_bounds_rand_consts_u64_s32(void) { validate_rand_ranges(U64, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, S64 initial range */ +void test_reg_bounds_rand_consts_s64_u64(void) { validate_rand_ranges(S64, U64, true /* const */); } +void test_reg_bounds_rand_consts_s64_s64(void) { validate_rand_ranges(S64, S64, true /* const */); } +void test_reg_bounds_rand_consts_s64_u32(void) { validate_rand_ranges(S64, U32, true /* const */); } +void test_reg_bounds_rand_consts_s64_s32(void) { validate_rand_ranges(S64, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, U32 initial range */ +void test_reg_bounds_rand_consts_u32_u64(void) { validate_rand_ranges(U32, U64, true /* const */); } +void test_reg_bounds_rand_consts_u32_s64(void) { validate_rand_ranges(U32, S64, true /* const */); } +void test_reg_bounds_rand_consts_u32_u32(void) { validate_rand_ranges(U32, U32, true /* const */); } +void test_reg_bounds_rand_consts_u32_s32(void) { validate_rand_ranges(U32, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, S32 initial range */ +void test_reg_bounds_rand_consts_s32_u64(void) { validate_rand_ranges(S32, U64, true /* const */); } +void test_reg_bounds_rand_consts_s32_s64(void) { validate_rand_ranges(S32, S64, true /* const */); } +void test_reg_bounds_rand_consts_s32_u32(void) { validate_rand_ranges(S32, U32, true /* const */); } +void test_reg_bounds_rand_consts_s32_s32(void) { validate_rand_ranges(S32, S32, true /* const */); } + +/* [RANDOM] RANGE x RANGE, U64 initial range */ +void test_reg_bounds_rand_ranges_u64_u64(void) { validate_rand_ranges(U64, U64, false /* range */); } +void test_reg_bounds_rand_ranges_u64_s64(void) { validate_rand_ranges(U64, S64, false /* range */); } +void test_reg_bounds_rand_ranges_u64_u32(void) { validate_rand_ranges(U64, U32, false /* range */); } +void test_reg_bounds_rand_ranges_u64_s32(void) { validate_rand_ranges(U64, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, S64 initial range */ +void test_reg_bounds_rand_ranges_s64_u64(void) { validate_rand_ranges(S64, U64, false /* range */); } +void test_reg_bounds_rand_ranges_s64_s64(void) { validate_rand_ranges(S64, S64, false /* range */); } +void test_reg_bounds_rand_ranges_s64_u32(void) { validate_rand_ranges(S64, U32, false /* range */); } +void test_reg_bounds_rand_ranges_s64_s32(void) { validate_rand_ranges(S64, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, U32 initial range */ +void test_reg_bounds_rand_ranges_u32_u64(void) { validate_rand_ranges(U32, U64, false /* range */); } +void test_reg_bounds_rand_ranges_u32_s64(void) { validate_rand_ranges(U32, S64, false /* range */); } +void test_reg_bounds_rand_ranges_u32_u32(void) { validate_rand_ranges(U32, U32, false /* range */); } +void test_reg_bounds_rand_ranges_u32_s32(void) { validate_rand_ranges(U32, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, S32 initial range */ +void test_reg_bounds_rand_ranges_s32_u64(void) { validate_rand_ranges(S32, U64, false /* range */); } +void test_reg_bounds_rand_ranges_s32_s64(void) { validate_rand_ranges(S32, S64, false /* range */); } +void test_reg_bounds_rand_ranges_s32_u32(void) { validate_rand_ranges(S32, U32, false /* range */); } +void test_reg_bounds_rand_ranges_s32_s32(void) { validate_rand_ranges(S32, S32, false /* range */); } + /* A set of hard-coded "interesting" cases to validate as part of normal * test_progs test runs */ From 8c5677f8b31e92b57be7d5d0fbb1ac66eedf4f91 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:07 -0800 Subject: [PATCH 0698/7721] selftests/bpf: set BPF_F_TEST_SANITY_SCRIPT by default Make sure to set BPF_F_TEST_SANITY_STRICT program flag by default across most verifier tests (and a bunch of others that set custom prog flags). There are currently two tests that do fail validation, if enforced strictly: verifier_bounds/crossing_64_bit_signed_boundary_2 and verifier_bounds/crossing_32_bit_signed_boundary_2. To accommodate them, we teach test_loader a flag negation: __flag(!) will *clear* specified flag, allowing easy opt-out. We apply __flag(!BPF_F_TEST_SANITY_STRICT) to these to tests. Also sprinkle BPF_F_TEST_SANITY_STRICT everywhere where we already set test-only BPF_F_TEST_RND_HI32 flag, for completeness. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-12-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/bpf_verif_scale.c | 2 +- .../selftests/bpf/progs/verifier_bounds.c | 2 ++ tools/testing/selftests/bpf/test_loader.c | 35 ++++++++++++++----- tools/testing/selftests/bpf/test_sock_addr.c | 1 + tools/testing/selftests/bpf/test_verifier.c | 2 +- tools/testing/selftests/bpf/testing_helpers.c | 4 +-- 6 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index 731c343897d8..3f2d70831873 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c @@ -35,7 +35,7 @@ static int check_load(const char *file, enum bpf_prog_type type) } bpf_program__set_type(prog, type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); + bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT); bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags); err = bpf_object__load(obj); diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c index c5588a14fe2e..0c1460936373 100644 --- a/tools/testing/selftests/bpf/progs/verifier_bounds.c +++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c @@ -965,6 +965,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP_JSLT for crossing 64-bit signed boundary") __success __retval(0) +__flag(!BPF_F_TEST_SANITY_STRICT) /* known sanity violation */ __naked void crossing_64_bit_signed_boundary_2(void) { asm volatile (" \ @@ -1046,6 +1047,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary") __success __retval(0) +__flag(!BPF_F_TEST_SANITY_STRICT) /* known sanity violation */ __naked void crossing_32_bit_signed_boundary_2(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c index 37ffa57f28a1..57e27b1a73a6 100644 --- a/tools/testing/selftests/bpf/test_loader.c +++ b/tools/testing/selftests/bpf/test_loader.c @@ -153,6 +153,14 @@ static int parse_retval(const char *str, int *val, const char *name) return parse_int(str, val, name); } +static void update_flags(int *flags, int flag, bool clear) +{ + if (clear) + *flags &= ~flag; + else + *flags |= flag; +} + /* Uses btf_decl_tag attributes to describe the expected test * behavior, see bpf_misc.h for detailed description of each attribute * and attribute combinations. @@ -171,6 +179,7 @@ static int parse_test_spec(struct test_loader *tester, memset(spec, 0, sizeof(*spec)); spec->prog_name = bpf_program__name(prog); + spec->prog_flags = BPF_F_TEST_SANITY_STRICT; /* by default be strict */ btf = bpf_object__btf(obj); if (!btf) { @@ -187,7 +196,8 @@ static int parse_test_spec(struct test_loader *tester, for (i = 1; i < btf__type_cnt(btf); i++) { const char *s, *val, *msg; const struct btf_type *t; - int tmp; + bool clear; + int flags; t = btf__type_by_id(btf, i); if (!btf_is_decl_tag(t)) @@ -253,23 +263,30 @@ static int parse_test_spec(struct test_loader *tester, goto cleanup; } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; + + clear = val[0] == '!'; + if (clear) + val++; + if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) { - spec->prog_flags |= BPF_F_STRICT_ALIGNMENT; + update_flags(&spec->prog_flags, BPF_F_STRICT_ALIGNMENT, clear); } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) { - spec->prog_flags |= BPF_F_ANY_ALIGNMENT; + update_flags(&spec->prog_flags, BPF_F_ANY_ALIGNMENT, clear); } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) { - spec->prog_flags |= BPF_F_TEST_RND_HI32; + update_flags(&spec->prog_flags, BPF_F_TEST_RND_HI32, clear); } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) { - spec->prog_flags |= BPF_F_TEST_STATE_FREQ; + update_flags(&spec->prog_flags, BPF_F_TEST_STATE_FREQ, clear); } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) { - spec->prog_flags |= BPF_F_SLEEPABLE; + update_flags(&spec->prog_flags, BPF_F_SLEEPABLE, clear); } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { - spec->prog_flags |= BPF_F_XDP_HAS_FRAGS; + update_flags(&spec->prog_flags, BPF_F_XDP_HAS_FRAGS, clear); + } else if (strcmp(val, "BPF_F_TEST_SANITY_STRICT") == 0) { + update_flags(&spec->prog_flags, BPF_F_TEST_SANITY_STRICT, clear); } else /* assume numeric value */ { - err = parse_int(val, &tmp, "test prog flags"); + err = parse_int(val, &flags, "test prog flags"); if (err) goto cleanup; - spec->prog_flags |= tmp; + update_flags(&spec->prog_flags, flags, clear); } } } diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index 2c89674fc62c..878c077e0fa7 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -680,6 +680,7 @@ static int load_path(const struct sock_addr_test *test, const char *path) bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); bpf_program__set_expected_attach_type(prog, test->expected_attach_type); bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); + bpf_program__set_flags(prog, BPF_F_TEST_SANITY_STRICT); err = bpf_object__load(obj); if (err) { diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 98107e0452d3..4992022f3137 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1588,7 +1588,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (fixup_skips != skips) return; - pflags = BPF_F_TEST_RND_HI32; + pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT; if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) pflags |= BPF_F_STRICT_ALIGNMENT; if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 8d994884c7b4..9786a94a666c 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -276,7 +276,7 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type, if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) bpf_program__set_type(prog, type); - flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32; + flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT; bpf_program__set_flags(prog, flags); err = bpf_object__load(obj); @@ -299,7 +299,7 @@ int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, { LIBBPF_OPTS(bpf_prog_load_opts, opts, .kern_version = kern_version, - .prog_flags = BPF_F_TEST_RND_HI32, + .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT, .log_level = extra_prog_load_log_flags, .log_buf = log_buf, .log_size = log_buf_sz, From a5c57f81eb2b5d6de4f46e47fd85be50d179bfd8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:08 -0800 Subject: [PATCH 0699/7721] veristat: add ability to set BPF_F_TEST_SANITY_STRICT flag with -r flag Add a new flag -r (--test-sanity), similar to -t (--test-states), to add extra BPF program flags when loading BPF programs. This allows to use veristat to easily catch sanity violations in production BPF programs. reg_bounds tests are also enforcing BPF_F_TEST_SANITY_STRICT flag now. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-13-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/reg_bounds.c | 1 + tools/testing/selftests/bpf/veristat.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index f3f724062b35..fe0cb906644b 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -838,6 +838,7 @@ static int load_range_cmp_prog(struct range x, struct range y, enum op op, .log_level = 2, .log_buf = log_buf, .log_size = log_sz, + .prog_flags = BPF_F_TEST_SANITY_STRICT, ); /* ; skip exit block below diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 443a29fc6a62..609fd9753af0 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -145,6 +145,7 @@ static struct env { bool debug; bool quiet; bool force_checkpoints; + bool strict_range_sanity; enum resfmt out_fmt; bool show_version; bool comparison_mode; @@ -214,8 +215,6 @@ static const struct argp_option opts[] = { { "log-level", 'l', "LEVEL", 0, "Verifier log level (default 0 for normal mode, 1 for verbose mode)" }, { "log-fixed", OPT_LOG_FIXED, NULL, 0, "Disable verifier log rotation" }, { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" }, - { "test-states", 't', NULL, 0, - "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, { "top-n", 'n', "N", 0, "Emit only up to first N results." }, { "quiet", 'q', NULL, 0, "Quiet mode" }, { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, @@ -224,6 +223,10 @@ static const struct argp_option opts[] = { { "compare", 'C', NULL, 0, "Comparison mode" }, { "replay", 'R', NULL, 0, "Replay mode" }, { "filter", 'f', "FILTER", 0, "Filter expressions (or @filename for file with expressions)." }, + { "test-states", 't', NULL, 0, + "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, + { "test-sanity", 'r', NULL, 0, + "Force strict BPF verifier register sanity behavior (BPF_F_TEST_SANITY_STRICT program flag)" }, {}, }; @@ -295,6 +298,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 't': env.force_checkpoints = true; break; + case 'r': + env.strict_range_sanity = true; + break; case 'n': errno = 0; env.top_n = strtol(arg, NULL, 10); @@ -302,7 +308,6 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) fprintf(stderr, "invalid top N specifier: %s\n", arg); argp_usage(state); } - break; case 'C': env.comparison_mode = true; break; @@ -1023,6 +1028,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf if (env.force_checkpoints) bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_STATE_FREQ); + if (env.strict_range_sanity) + bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_SANITY_STRICT); err = bpf_object__load(obj); env.progs_processed++; From 882e3d873c2d8a2aebbc6c192aa1a2990b9d5b27 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 11 Nov 2023 17:06:09 -0800 Subject: [PATCH 0700/7721] selftests/bpf: add iter test requiring range x range logic Add a simple verifier test that requires deriving reg bounds for one register from another register that's not a constant. This is a realistic example of iterating elements of an array with fixed maximum number of elements, but smaller actual number of elements. This small example was an original motivation for doing this whole patch set in the first place, yes. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231112010609.848406-14-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/iters.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index c20c4e38b71c..b2181f850d3e 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -1411,4 +1411,26 @@ __naked int checkpoint_states_deletion(void) ); } +struct { + int data[32]; + int n; +} loop_data; + +SEC("raw_tp") +__success +int iter_arr_with_actual_elem_count(const void *ctx) +{ + int i, n = loop_data.n, sum = 0; + + if (n > ARRAY_SIZE(loop_data.data)) + return 0; + + bpf_for(i, 0, n) { + /* no rechecking of i against ARRAY_SIZE(loop_data.n) */ + sum += loop_data.data[i]; + } + + return sum; +} + char _license[] SEC("license") = "GPL"; From 5fa201f37c2ef58a0f821e656d794af89b3a1738 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Fri, 10 Nov 2023 17:51:50 +0000 Subject: [PATCH 0701/7721] bpf: Remove test for MOVSX32 with offset=32 MOVSX32 only supports sign extending 8-bit and 16-bit operands into 32 bit operands. The "ALU_MOVSX | BPF_W" test tries to sign extend a 32 bit operand into a 32 bit operand which is equivalent to a normal BPF_MOV. Remove this test as it tries to run an invalid instruction. Fixes: daabb2b098e0 ("bpf/tests: add tests for cpuv4 instructions") Signed-off-by: Puranjay Mohan Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202310111838.46ff5b6a-oliver.sang@intel.com Acked-by: Stanislav Fomichev Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231110175150.87803-1-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov --- lib/test_bpf.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 7916503e6a6a..c148f8d1e564 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -5144,22 +5144,6 @@ static struct bpf_test tests[] = { { }, { { 0, 0x1 } }, }, - { - "ALU_MOVSX | BPF_W", - .u.insns_int = { - BPF_LD_IMM64(R2, 0x00000000deadbeefLL), - BPF_LD_IMM64(R3, 0xdeadbeefdeadbeefLL), - BPF_MOVSX32_REG(R1, R3, 32), - BPF_JMP_REG(BPF_JEQ, R2, R1, 2), - BPF_MOV32_IMM(R0, 2), - BPF_EXIT_INSN(), - BPF_MOV32_IMM(R0, 1), - BPF_EXIT_INSN(), - }, - INTERNAL, - { }, - { { 0, 0x1 } }, - }, /* MOVSX64 REG */ { "ALU64_MOVSX | BPF_B", From 797bf47d8a42792762cfc74dc84109d6d893ddf2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 22 Jul 2023 14:17:17 +0200 Subject: [PATCH 0702/7721] ARM: dts: samsung: exynos4x12: replace duplicate pmu node with phandle Devicetree for the FIMC IS camera included duplicated PMU node as its child. This is not a correct representation of the hardware. Mapping the PMU (Power Management Unit) IO memory should be via syscon-like phandle (samsung,pmu-syscon, already used for other drivers), not by duplicating "pmu" Devicetree node inside the FIMC IS. The change is not compatible with older Linux kernel, which does not parse samsung,pmu-syscon property. Link: https://lore.kernel.org/r/20230722121719.150094-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/samsung/exynos4x12.dtsi | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/samsung/exynos4x12.dtsi b/arch/arm/boot/dts/samsung/exynos4x12.dtsi index 84c1db221c98..4524c1e6bb2f 100644 --- a/arch/arm/boot/dts/samsung/exynos4x12.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4x12.dtsi @@ -516,15 +516,12 @@ fimc_is: fimc-is@12000000 { iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>, <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; iommu-names = "isp", "drc", "fd", "mcuctl"; + samsung,pmu-syscon = <&pmu_system_controller>; #address-cells = <1>; #size-cells = <1>; ranges; status = "disabled"; - pmu@10020000 { - reg = <0x10020000 0x3000>; - }; - i2c1_isp: i2c-isp@12140000 { compatible = "samsung,exynos4212-i2c-isp"; reg = <0x12140000 0x100>; From ba2a45a48503665f7e8eeec51f8b40456566b0cd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 22 Jul 2023 14:17:18 +0200 Subject: [PATCH 0703/7721] ARM: dts: samsung: exynos4: fix camera unit addresses/ranges The camera node has both unit address and children within the same bus mapping, thus needs proper ranges property to fix dtc W=1 warnings: Warning (unit_address_vs_reg): /soc/camera@11800000: node has a unit name, but no reg or ranges property Warning (simple_bus_reg): /soc/camera@11800000: missing or empty reg/ranges property Subtract 0x11800000 from all its children nodes. No functional impact expected. Link: https://lore.kernel.org/r/20230722121719.150094-2-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/samsung/exynos4.dtsi | 26 +++++++++++------------ arch/arm/boot/dts/samsung/exynos4x12.dtsi | 17 ++++++++------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/arch/arm/boot/dts/samsung/exynos4.dtsi b/arch/arm/boot/dts/samsung/exynos4.dtsi index f775b9377a38..7f981b5c0d64 100644 --- a/arch/arm/boot/dts/samsung/exynos4.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4.dtsi @@ -203,16 +203,16 @@ dsi_0: dsi@11c80000 { camera: camera@11800000 { compatible = "samsung,fimc"; + ranges = <0x0 0x11800000 0xa0000>; status = "disabled"; #address-cells = <1>; #size-cells = <1>; #clock-cells = <1>; clock-output-names = "cam_a_clkout", "cam_b_clkout"; - ranges; - fimc_0: fimc@11800000 { + fimc_0: fimc@0 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11800000 0x1000>; + reg = <0x0 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC0>, <&clock CLK_SCLK_FIMC0>; @@ -223,9 +223,9 @@ fimc_0: fimc@11800000 { status = "disabled"; }; - fimc_1: fimc@11810000 { + fimc_1: fimc@10000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11810000 0x1000>; + reg = <0x00010000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC1>, <&clock CLK_SCLK_FIMC1>; @@ -236,9 +236,9 @@ fimc_1: fimc@11810000 { status = "disabled"; }; - fimc_2: fimc@11820000 { + fimc_2: fimc@20000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11820000 0x1000>; + reg = <0x00020000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC2>, <&clock CLK_SCLK_FIMC2>; @@ -249,9 +249,9 @@ fimc_2: fimc@11820000 { status = "disabled"; }; - fimc_3: fimc@11830000 { + fimc_3: fimc@30000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11830000 0x1000>; + reg = <0x00030000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC3>, <&clock CLK_SCLK_FIMC3>; @@ -262,9 +262,9 @@ fimc_3: fimc@11830000 { status = "disabled"; }; - csis_0: csis@11880000 { + csis_0: csis@80000 { compatible = "samsung,exynos4210-csis"; - reg = <0x11880000 0x4000>; + reg = <0x00080000 0x4000>; interrupts = ; clocks = <&clock CLK_CSIS0>, <&clock CLK_SCLK_CSIS0>; @@ -278,9 +278,9 @@ csis_0: csis@11880000 { #size-cells = <0>; }; - csis_1: csis@11890000 { + csis_1: csis@90000 { compatible = "samsung,exynos4210-csis"; - reg = <0x11890000 0x4000>; + reg = <0x00090000 0x4000>; interrupts = ; clocks = <&clock CLK_CSIS1>, <&clock CLK_SCLK_CSIS1>; diff --git a/arch/arm/boot/dts/samsung/exynos4x12.dtsi b/arch/arm/boot/dts/samsung/exynos4x12.dtsi index 4524c1e6bb2f..b4b5e769145b 100644 --- a/arch/arm/boot/dts/samsung/exynos4x12.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4x12.dtsi @@ -451,14 +451,15 @@ &combiner { }; &camera { + ranges = <0x0 0x11800000 0xba1000>; clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>, <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>; clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1"; /* fimc_[0-3] are configured outside, under phandles */ - fimc_lite_0: fimc-lite@12390000 { + fimc_lite_0: fimc-lite@b90000 { compatible = "samsung,exynos4212-fimc-lite"; - reg = <0x12390000 0x1000>; + reg = <0x00b90000 0x1000>; interrupts = ; power-domains = <&pd_isp>; clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; @@ -467,9 +468,9 @@ fimc_lite_0: fimc-lite@12390000 { status = "disabled"; }; - fimc_lite_1: fimc-lite@123a0000 { + fimc_lite_1: fimc-lite@ba0000 { compatible = "samsung,exynos4212-fimc-lite"; - reg = <0x123a0000 0x1000>; + reg = <0x00ba0000 0x1000>; interrupts = ; power-domains = <&pd_isp>; clocks = <&isp_clock CLK_ISP_FIMC_LITE1>; @@ -478,9 +479,9 @@ fimc_lite_1: fimc-lite@123a0000 { status = "disabled"; }; - fimc_is: fimc-is@12000000 { + fimc_is: fimc-is@800000 { compatible = "samsung,exynos4212-fimc-is"; - reg = <0x12000000 0x260000>; + reg = <0x00800000 0x260000>; interrupts = , ; power-domains = <&pd_isp>; @@ -522,9 +523,9 @@ fimc_is: fimc-is@12000000 { ranges; status = "disabled"; - i2c1_isp: i2c-isp@12140000 { + i2c1_isp: i2c-isp@940000 { compatible = "samsung,exynos4212-i2c-isp"; - reg = <0x12140000 0x100>; + reg = <0x00940000 0x100>; clocks = <&isp_clock CLK_ISP_I2C1_ISP>; clock-names = "i2c_isp"; #address-cells = <1>; From 07e6a553c2f1d385edfc9185081dee442a9dd38d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 22 Jul 2023 14:17:19 +0200 Subject: [PATCH 0704/7721] ARM: dts: samsung: s5pv210: fix camera unit addresses/ranges The camera node has both unit address and children within the same bus mapping, thus needs proper ranges property to fix dtc W=1 warnings: Warning (unit_address_vs_reg): /soc/camera@fa600000: node has a unit name, but no reg or ranges property Warning (simple_bus_reg): /soc/camera@fa600000: missing or empty reg/ranges property Subtract 0xfa600000 from all its children nodes. No functional impact expected. Link: https://lore.kernel.org/r/20230722121719.150094-3-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/samsung/s5pv210.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/samsung/s5pv210.dtsi b/arch/arm/boot/dts/samsung/s5pv210.dtsi index f7de5b5f2f38..ed560c9a3aa1 100644 --- a/arch/arm/boot/dts/samsung/s5pv210.dtsi +++ b/arch/arm/boot/dts/samsung/s5pv210.dtsi @@ -549,17 +549,17 @@ i2c1: i2c@fab00000 { camera: camera@fa600000 { compatible = "samsung,fimc"; + ranges = <0x0 0xfa600000 0xe01000>; clocks = <&clocks SCLK_CAM0>, <&clocks SCLK_CAM1>; clock-names = "sclk_cam0", "sclk_cam1"; #address-cells = <1>; #size-cells = <1>; #clock-cells = <1>; clock-output-names = "cam_a_clkout", "cam_b_clkout"; - ranges; - csis0: csis@fa600000 { + csis0: csis@0 { compatible = "samsung,s5pv210-csis"; - reg = <0xfa600000 0x4000>; + reg = <0x00000000 0x4000>; interrupt-parent = <&vic2>; interrupts = <29>; clocks = <&clocks CLK_CSIS>, @@ -572,9 +572,9 @@ csis0: csis@fa600000 { #size-cells = <0>; }; - fimc0: fimc@fb200000 { + fimc0: fimc@c00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb200000 0x1000>; + reg = <0x00c00000 0x1000>; interrupts = <5>; interrupt-parent = <&vic2>; clocks = <&clocks CLK_FIMC0>, @@ -586,9 +586,9 @@ fimc0: fimc@fb200000 { samsung,cam-if; }; - fimc1: fimc@fb300000 { + fimc1: fimc@d00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb300000 0x1000>; + reg = <0x00d00000 0x1000>; interrupt-parent = <&vic2>; interrupts = <6>; clocks = <&clocks CLK_FIMC1>, @@ -602,9 +602,9 @@ fimc1: fimc@fb300000 { samsung,lcd-wb; }; - fimc2: fimc@fb400000 { + fimc2: fimc@e00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb400000 0x1000>; + reg = <0x00e00000 0x1000>; interrupt-parent = <&vic2>; interrupts = <7>; clocks = <&clocks CLK_FIMC2>, From d7b4832cbeb85075293b1211a9c89fad4fdda1f1 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Thu, 9 Nov 2023 11:21:48 -0800 Subject: [PATCH 0705/7721] drm/i915: Read a shadowed mmio register for ggtt flush We read RENDER_HEAD as a part of the flush. If GT is in deeper sleep states, this could lead to read errors since we are not using a forcewake. Safer to read a shadowed register instead. Cc: John Harrison Cc: Daniele Ceraolo Spurio Signed-off-by: Vinay Belgaumkar Reviewed-by: Radhakrishna Sripada Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20231109192148.475156-1-vinay.belgaumkar@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index ed32bf5b1546..ea814ea5f700 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -451,7 +451,7 @@ void intel_gt_flush_ggtt_writes(struct intel_gt *gt) spin_lock_irqsave(&uncore->lock, flags); intel_uncore_posting_read_fw(uncore, - RING_HEAD(RENDER_RING_BASE)); + RING_TAIL(RENDER_RING_BASE)); spin_unlock_irqrestore(&uncore->lock, flags); } } From 74d016ecc1a7974664e98d1afbf649cd4e0e0423 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 15 Nov 2023 22:41:27 -0500 Subject: [PATCH 0706/7721] new helper: user_path_locked_at() Equivalent of kern_path_locked() taking dfd/userland name. User introduced in the next commit. Signed-off-by: Al Viro --- fs/namei.c | 16 +++++++++++++--- include/linux/namei.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 71c13b2990b4..3ffbe268d52c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2573,13 +2573,13 @@ static int filename_parentat(int dfd, struct filename *name, } /* does lookup, returns the object with parent locked */ -static struct dentry *__kern_path_locked(struct filename *name, struct path *path) +static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path) { struct dentry *d; struct qstr last; int type, error; - error = filename_parentat(AT_FDCWD, name, 0, path, &last, &type); + error = filename_parentat(dfd, name, 0, path, &last, &type); if (error) return ERR_PTR(error); if (unlikely(type != LAST_NORM)) { @@ -2598,12 +2598,22 @@ static struct dentry *__kern_path_locked(struct filename *name, struct path *pat struct dentry *kern_path_locked(const char *name, struct path *path) { struct filename *filename = getname_kernel(name); - struct dentry *res = __kern_path_locked(filename, path); + struct dentry *res = __kern_path_locked(AT_FDCWD, filename, path); putname(filename); return res; } +struct dentry *user_path_locked_at(int dfd, const char __user *name, struct path *path) +{ + struct filename *filename = getname(name); + struct dentry *res = __kern_path_locked(dfd, filename, path); + + putname(filename); + return res; +} +EXPORT_SYMBOL(user_path_locked_at); + int kern_path(const char *name, unsigned int flags, struct path *path) { struct filename *filename = getname_kernel(name); diff --git a/include/linux/namei.h b/include/linux/namei.h index 3100371b5e32..74e0cc14ebf8 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -66,6 +66,7 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int); extern void done_path_create(struct path *, struct dentry *); extern struct dentry *kern_path_locked(const char *, struct path *); +extern struct dentry *user_path_locked_at(int , const char __user *, struct path *); int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, struct path *parent, struct qstr *last, int *type, const struct path *root); From bbe6a7c899e7f265c5a6d01a178336a405e98ed6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2023 18:52:42 -0500 Subject: [PATCH 0707/7721] bch2_ioctl_subvolume_destroy(): fix locking make it use user_path_locked_at() to get the normal directory protection for modifications, as well as stable ->d_parent and ->d_name in victim Signed-off-by: Al Viro --- fs/bcachefs/fs-ioctl.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c index 5a39bcb597a3..c5ab5a2dc9be 100644 --- a/fs/bcachefs/fs-ioctl.c +++ b/fs/bcachefs/fs-ioctl.c @@ -453,33 +453,36 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp, static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp, struct bch_ioctl_subvolume arg) { + const char __user *name = (void __user *)(unsigned long)arg.dst_ptr; struct path path; struct inode *dir; + struct dentry *victim; int ret = 0; if (arg.flags) return -EINVAL; - ret = user_path_at(arg.dirfd, - (const char __user *)(unsigned long)arg.dst_ptr, - LOOKUP_FOLLOW, &path); - if (ret) - return ret; + victim = user_path_locked_at(arg.dirfd, name, &path); + if (IS_ERR(victim)) + return PTR_ERR(victim); - if (path.dentry->d_sb->s_fs_info != c) { + if (victim->d_sb->s_fs_info != c) { ret = -EXDEV; goto err; } - - dir = path.dentry->d_parent->d_inode; - - ret = __bch2_unlink(dir, path.dentry, true); - if (ret) + if (!d_is_positive(victim)) { + ret = -ENOENT; goto err; - - fsnotify_rmdir(dir, path.dentry); - d_delete(path.dentry); + } + dir = d_inode(path.dentry); + ret = __bch2_unlink(dir, victim, true); + if (!ret) { + fsnotify_rmdir(dir, victim); + d_delete(victim); + } + inode_unlock(dir); err: + dput(victim); path_put(&path); return ret; } From 98ed369800f79a2cd199b8415d14d82a5f2e007f Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Fri, 10 Nov 2023 08:55:18 +0530 Subject: [PATCH 0708/7721] drm/i915/dsb: DSB code refactoring Refactor DSB implementation to be compatible with Xe driver. v1: RFC version. v2: Make intel_dsb structure opaque from external usage. [Jani] v3: Rebased on latest. v4: - Add boundary check in dsb_buffer_memset(). [Luca] - Use size_t instead of u32. [Luca] v5: WARN_ON() added for out of boudary case with some optimization. [Luca] v6: Rebased on latest and fix a rebase-miss. Cc: Jani Nikula Reviewed-by: Luca Coelho Signed-off-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231110032518.3564279-1-animesh.manna@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_dsb.c | 98 +++++++------------ .../gpu/drm/i915/display/intel_dsb_buffer.c | 82 ++++++++++++++++ .../gpu/drm/i915/display/intel_dsb_buffer.h | 29 ++++++ 4 files changed, 148 insertions(+), 62 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_dsb_buffer.c create mode 100644 drivers/gpu/drm/i915/display/intel_dsb_buffer.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 239da40a401f..7e5d6a39d450 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -277,6 +277,7 @@ i915-y += \ display/intel_dpt.o \ display/intel_drrs.o \ display/intel_dsb.o \ + display/intel_dsb_buffer.o \ display/intel_fb.o \ display/intel_fb_pin.o \ display/intel_fbc.o \ diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 78b6fe24dcd8..9598d50f68f2 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -4,9 +4,6 @@ * */ -#include "gem/i915_gem_internal.h" -#include "gem/i915_gem_lmem.h" - #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" @@ -14,12 +11,13 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" +#include "intel_dsb_buffer.h" #include "intel_dsb_regs.h" #include "intel_vblank.h" #include "intel_vrr.h" #include "skl_watermark.h" -struct i915_vma; +#define CACHELINE_BYTES 64 enum dsb_id { INVALID_DSB = -1, @@ -32,8 +30,7 @@ enum dsb_id { struct intel_dsb { enum dsb_id id; - u32 *cmd_buf; - struct i915_vma *vma; + struct intel_dsb_buffer dsb_buf; struct intel_crtc *crtc; /* @@ -109,15 +106,17 @@ static void intel_dsb_dump(struct intel_dsb *dsb) { struct intel_crtc *crtc = dsb->crtc; struct drm_i915_private *i915 = to_i915(crtc->base.dev); - const u32 *buf = dsb->cmd_buf; int i; drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] DSB %d commands {\n", crtc->base.base.id, crtc->base.name, dsb->id); for (i = 0; i < ALIGN(dsb->free_pos, 64 / 4); i += 4) drm_dbg_kms(&i915->drm, - " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", - i * 4, buf[i], buf[i+1], buf[i+2], buf[i+3]); + " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4, + intel_dsb_buffer_read(&dsb->dsb_buf, i), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 1), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 2), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 3)); drm_dbg_kms(&i915->drm, "}\n"); } @@ -129,8 +128,6 @@ static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe, static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) { - u32 *buf = dsb->cmd_buf; - if (!assert_dsb_has_room(dsb)) return; @@ -139,14 +136,13 @@ static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) dsb->ins_start_offset = dsb->free_pos; - buf[dsb->free_pos++] = ldw; - buf[dsb->free_pos++] = udw; + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, ldw); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, udw); } static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, u32 opcode, i915_reg_t reg) { - const u32 *buf = dsb->cmd_buf; u32 prev_opcode, prev_reg; /* @@ -157,8 +153,10 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, if (dsb->free_pos == 0) return false; - prev_opcode = buf[dsb->ins_start_offset + 1] & ~DSB_REG_VALUE_MASK; - prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK; + prev_opcode = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 1) & ~DSB_REG_VALUE_MASK; + prev_reg = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 1) & DSB_REG_VALUE_MASK; return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg); } @@ -191,6 +189,8 @@ static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_ void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val) { + u32 old_val; + /* * For example the buffer will look like below for 3 dwords for auto * increment register: @@ -214,31 +214,32 @@ void intel_dsb_reg_write(struct intel_dsb *dsb, (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) | i915_mmio_reg_offset(reg)); } else { - u32 *buf = dsb->cmd_buf; - if (!assert_dsb_has_room(dsb)) return; /* convert to indexed write? */ if (intel_dsb_prev_ins_is_mmio_write(dsb, reg)) { - u32 prev_val = buf[dsb->ins_start_offset + 0]; + u32 prev_val = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 0); - buf[dsb->ins_start_offset + 0] = 1; /* count */ - buf[dsb->ins_start_offset + 1] = - (DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) | - i915_mmio_reg_offset(reg); - buf[dsb->ins_start_offset + 2] = prev_val; + intel_dsb_buffer_write(&dsb->dsb_buf, + dsb->ins_start_offset + 0, 1); /* count */ + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset + 1, + (DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) | + i915_mmio_reg_offset(reg)); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset + 2, prev_val); dsb->free_pos++; } - buf[dsb->free_pos++] = val; + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, val); /* Update the count */ - buf[dsb->ins_start_offset]++; + old_val = intel_dsb_buffer_read(&dsb->dsb_buf, dsb->ins_start_offset); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset, old_val + 1); /* if number of data words is odd, then the last dword should be 0.*/ if (dsb->free_pos & 0x1) - buf[dsb->free_pos] = 0; + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos, 0); } } @@ -297,8 +298,8 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb) aligned_tail = ALIGN(tail, CACHELINE_BYTES); if (aligned_tail > tail) - memset(&dsb->cmd_buf[dsb->free_pos], 0, - aligned_tail - tail); + intel_dsb_buffer_memset(&dsb->dsb_buf, dsb->free_pos, 0, + aligned_tail - tail); dsb->free_pos = aligned_tail / 4; } @@ -317,7 +318,7 @@ void intel_dsb_finish(struct intel_dsb *dsb) intel_dsb_align_tail(dsb); - i915_gem_object_flush_map(dsb->vma->obj); + intel_dsb_buffer_flush_map(&dsb->dsb_buf); } static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state) @@ -361,7 +362,7 @@ static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, ctrl | DSB_ENABLE); intel_de_write_fw(dev_priv, DSB_HEAD(pipe, dsb->id), - i915_ggtt_offset(dsb->vma)); + intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf)); if (dewake_scanline >= 0) { int diff, hw_dewake_scanline; @@ -383,7 +384,7 @@ static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, } intel_de_write_fw(dev_priv, DSB_TAIL(pipe, dsb->id), - i915_ggtt_offset(dsb->vma) + tail); + intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf) + tail); } /** @@ -408,7 +409,7 @@ void intel_dsb_wait(struct intel_dsb *dsb) enum pipe pipe = crtc->pipe; if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) { - u32 offset = i915_ggtt_offset(dsb->vma); + u32 offset = intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf); intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), DSB_ENABLE | DSB_HALT); @@ -445,12 +446,9 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); - struct drm_i915_gem_object *obj; intel_wakeref_t wakeref; struct intel_dsb *dsb; - struct i915_vma *vma; unsigned int size; - u32 *buf; if (!HAS_DSB(i915)) return NULL; @@ -464,37 +462,13 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, /* ~1 qword per instruction, full cachelines */ size = ALIGN(max_cmds * 8, CACHELINE_BYTES); - if (HAS_LMEM(i915)) { - obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size), - I915_BO_ALLOC_CONTIGUOUS); - if (IS_ERR(obj)) - goto out_put_rpm; - } else { - obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); - if (IS_ERR(obj)) - goto out_put_rpm; - - i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); - } - - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); - if (IS_ERR(vma)) { - i915_gem_object_put(obj); + if (!intel_dsb_buffer_create(crtc, &dsb->dsb_buf, size)) goto out_put_rpm; - } - - buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC); - if (IS_ERR(buf)) { - i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); - goto out_put_rpm; - } intel_runtime_pm_put(&i915->runtime_pm, wakeref); dsb->id = DSB1; - dsb->vma = vma; dsb->crtc = crtc; - dsb->cmd_buf = buf; dsb->size = size / 4; /* in dwords */ dsb->free_pos = 0; dsb->ins_start_offset = 0; @@ -522,6 +496,6 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, */ void intel_dsb_cleanup(struct intel_dsb *dsb) { - i915_vma_unpin_and_release(&dsb->vma, I915_VMA_RELEASE_MAP); + intel_dsb_buffer_cleanup(&dsb->dsb_buf); kfree(dsb); } diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.c b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c new file mode 100644 index 000000000000..c77d48bda26a --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2023, Intel Corporation. + */ + +#include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" +#include "i915_drv.h" +#include "i915_vma.h" +#include "intel_display_types.h" +#include "intel_dsb_buffer.h" + +u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf) +{ + return i915_ggtt_offset(dsb_buf->vma); +} + +void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val) +{ + dsb_buf->cmd_buf[idx] = val; +} + +u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx) +{ + return dsb_buf->cmd_buf[idx]; +} + +void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size) +{ + WARN_ON(idx > (dsb_buf->buf_size - size) / sizeof(*dsb_buf->cmd_buf)); + + memset(&dsb_buf->cmd_buf[idx], val, size); +} + +bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, size_t size) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + u32 *buf; + + if (HAS_LMEM(i915)) { + obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size), + I915_BO_ALLOC_CONTIGUOUS); + if (IS_ERR(obj)) + return false; + } else { + obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); + if (IS_ERR(obj)) + return false; + + i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); + } + + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); + if (IS_ERR(vma)) { + i915_gem_object_put(obj); + return false; + } + + buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC); + if (IS_ERR(buf)) { + i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); + return false; + } + + dsb_buf->vma = vma; + dsb_buf->cmd_buf = buf; + dsb_buf->buf_size = size; + + return true; +} + +void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf) +{ + i915_vma_unpin_and_release(&dsb_buf->vma, I915_VMA_RELEASE_MAP); +} + +void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf) +{ + i915_gem_object_flush_map(dsb_buf->vma->obj); +} diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h new file mode 100644 index 000000000000..425acd393905 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright © 2023 Intel Corporation + */ + +#ifndef _INTEL_DSB_BUFFER_H +#define _INTEL_DSB_BUFFER_H + +#include + +struct intel_crtc; +struct i915_vma; + +struct intel_dsb_buffer { + u32 *cmd_buf; + struct i915_vma *vma; + size_t buf_size; +}; + +u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf); +void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val); +u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx); +void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size); +bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, + size_t size); +void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf); +void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf); + +#endif From f5502cd25ac0405740e98e2dcdb9dcd355866e03 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:14 +0800 Subject: [PATCH 0709/7721] media: dt-bindings: Add JH7110 Camera Subsystem Add the bindings documentation for Starfive JH7110 Camera Subsystem which is used for handing image sensor data. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Laurent Pinchart Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- .../bindings/media/starfive,jh7110-camss.yaml | 180 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 187 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml diff --git a/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml new file mode 100644 index 000000000000..c66586d90fa2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/starfive,jh7110-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Starfive SoC CAMSS ISP + +maintainers: + - Jack Zhu + - Changhuang Liang + +description: + The Starfive CAMSS ISP is a Camera interface for Starfive JH7110 SoC. It + consists of a VIN controller (Video In Controller, a top-level control unit) + and an ISP. + +properties: + compatible: + const: starfive,jh7110-camss + + reg: + maxItems: 2 + + reg-names: + items: + - const: syscon + - const: isp + + clocks: + maxItems: 7 + + clock-names: + items: + - const: apb_func + - const: wrapper_clk_c + - const: dvp_inv + - const: axiwr + - const: mipi_rx0_pxl + - const: ispcore_2x + - const: isp_axi + + resets: + maxItems: 6 + + reset-names: + items: + - const: wrapper_p + - const: wrapper_c + - const: axird + - const: axiwr + - const: isp_top_n + - const: isp_top_axi + + power-domains: + items: + - description: JH7110 ISP Power Domain Switch Controller. + + interrupts: + maxItems: 4 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: Input port for receiving DVP data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + + bus-width: + enum: [8, 10, 12] + + data-shift: + enum: [0, 2] + default: 0 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + required: + - bus-type + - bus-width + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Input port for receiving CSI data. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - resets + - reset-names + - power-domains + - interrupts + - ports + +additionalProperties: false + +examples: + - | + isp@19840000 { + compatible = "starfive,jh7110-camss"; + reg = <0x19840000 0x10000>, + <0x19870000 0x30000>; + reg-names = "syscon", "isp"; + clocks = <&ispcrg 0>, + <&ispcrg 13>, + <&ispcrg 2>, + <&ispcrg 12>, + <&ispcrg 1>, + <&syscrg 51>, + <&syscrg 52>; + clock-names = "apb_func", + "wrapper_clk_c", + "dvp_inv", + "axiwr", + "mipi_rx0_pxl", + "ispcore_2x", + "isp_axi"; + resets = <&ispcrg 0>, + <&ispcrg 1>, + <&ispcrg 10>, + <&ispcrg 11>, + <&syscrg 41>, + <&syscrg 42>; + reset-names = "wrapper_p", + "wrapper_c", + "axird", + "axiwr", + "isp_top_n", + "isp_top_axi"; + power-domains = <&pwrc 5>; + interrupts = <92>, <87>, <88>, <90>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + vin_from_sc2235: endpoint { + remote-endpoint = <&sc2235_to_vin>; + bus-type = <5>; + bus-width = <8>; + data-shift = <2>; + hsync-active = <1>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + vin_from_csi2rx: endpoint { + remote-endpoint = <&csi2rx_to_vin>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..7c17a576b6c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20638,6 +20638,13 @@ M: Ion Badulescu S: Odd Fixes F: drivers/net/ethernet/adaptec/starfire* +STARFIVE CAMERA SUBSYSTEM DRIVER +M: Jack Zhu +M: Changhuang Liang +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml + STARFIVE CRYPTO DRIVER M: Jia Jie Ho M: William Qiu From f72f80550d01060a9dda8d0a1c3a7abbf333bc77 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:15 +0800 Subject: [PATCH 0710/7721] media: admin-guide: Add starfive_camss.rst for Starfive Camera Subsystem Add starfive_camss.rst file that documents the Starfive Camera Subsystem driver which is used for handing image sensor data. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- .../admin-guide/media/starfive_camss.rst | 72 +++++++++++++++++++ .../media/starfive_camss_graph.dot | 12 ++++ .../admin-guide/media/v4l-drivers.rst | 1 + MAINTAINERS | 1 + 4 files changed, 86 insertions(+) create mode 100644 Documentation/admin-guide/media/starfive_camss.rst create mode 100644 Documentation/admin-guide/media/starfive_camss_graph.dot diff --git a/Documentation/admin-guide/media/starfive_camss.rst b/Documentation/admin-guide/media/starfive_camss.rst new file mode 100644 index 000000000000..ca42e9447c47 --- /dev/null +++ b/Documentation/admin-guide/media/starfive_camss.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +================================ +Starfive Camera Subsystem driver +================================ + +Introduction +------------ + +This file documents the driver for the Starfive Camera Subsystem found on +Starfive JH7110 SoC. The driver is located under drivers/staging/media/starfive/ +camss. + +The driver implements V4L2, Media controller and v4l2_subdev interfaces. Camera +sensor using V4L2 subdev interface in the kernel is supported. + +The driver has been successfully used on the Gstreamer 1.18.5 with v4l2src +plugin. + + +Starfive Camera Subsystem hardware +---------------------------------- + +The Starfive Camera Subsystem hardware consists of:: + + |\ +---------------+ +-----------+ + +----------+ | \ | | | | + | | | | | | | | + | MIPI |----->| |----->| ISP |----->| | + | | | | | | | | + +----------+ | | | | | Memory | + |MUX| +---------------+ | Interface | + +----------+ | | | | + | | | |---------------------------->| | + | Parallel |----->| | | | + | | | | | | + +----------+ | / | | + |/ +-----------+ + +- MIPI: The MIPI interface, receiving data from a MIPI CSI-2 camera sensor. + +- Parallel: The parallel interface, receiving data from a parallel sensor. + +- ISP: The ISP, processing raw Bayer data from an image sensor and producing + YUV frames. + + +Topology +-------- + +The media controller pipeline graph is as follows: + +.. _starfive_camss_graph: + +.. kernel-figure:: starfive_camss_graph.dot + :alt: starfive_camss_graph.dot + :align: center + +The driver has 2 video devices: + +- capture_raw: The capture device, capturing image data directly from a sensor. +- capture_yuv: The capture device, capturing YUV frame data processed by the + ISP module + +The driver has 3 subdevices: + +- stf_isp: is responsible for all the isp operations, outputs YUV frames. +- cdns_csi2rx: a CSI-2 bridge supporting up to 4 CSI lanes in input, and 4 + different pixel streams in output. +- imx219: an image sensor, image data is sent through MIPI CSI-2. diff --git a/Documentation/admin-guide/media/starfive_camss_graph.dot b/Documentation/admin-guide/media/starfive_camss_graph.dot new file mode 100644 index 000000000000..8eff1f161ac7 --- /dev/null +++ b/Documentation/admin-guide/media/starfive_camss_graph.dot @@ -0,0 +1,12 @@ +digraph board { + rankdir=TB + n00000001 [label="{{ 0} | stf_isp\n/dev/v4l-subdev0 | { 1}}", shape=Mrecord, style=filled, fillcolor=green] + n00000001:port1 -> n00000008 [style=dashed] + n00000004 [label="capture_raw\n/dev/video0", shape=box, style=filled, fillcolor=yellow] + n00000008 [label="capture_yuv\n/dev/video1", shape=box, style=filled, fillcolor=yellow] + n0000000e [label="{{ 0} | cdns_csi2rx.19800000.csi-bridge\n | { 1 | 2 | 3 | 4}}", shape=Mrecord, style=filled, fillcolor=green] + n0000000e:port1 -> n00000001:port0 [style=dashed] + n0000000e:port1 -> n00000004 [style=dashed] + n00000018 [label="{{} | imx219 6-0010\n/dev/v4l-subdev1 | { 0}}", shape=Mrecord, style=filled, fillcolor=green] + n00000018:port0 -> n0000000e:port0 [style=bold] +} diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index 61283d67ceef..f4bb2605f07e 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -28,6 +28,7 @@ Video4Linux (V4L) driver-specific documentation si470x si4713 si476x + starfive_camss vimc visl vivid diff --git a/MAINTAINERS b/MAINTAINERS index 7c17a576b6c3..0c7c33279ee1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20643,6 +20643,7 @@ M: Jack Zhu M: Changhuang Liang L: linux-media@vger.kernel.org S: Maintained +F: Documentation/admin-guide/media/starfive_camss.rst F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml STARFIVE CRYPTO DRIVER From bba185d141b1278728f53d2ebf97214ab023ed07 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:16 +0800 Subject: [PATCH 0711/7721] media: staging: media: starfive: camss: Add core driver Add core driver for StarFive Camera Subsystem. The code parses the device platform resources and registers related devices. Reviewed-by: Bryan O'Donoghue Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- MAINTAINERS | 1 + drivers/staging/media/Kconfig | 2 + drivers/staging/media/Makefile | 1 + drivers/staging/media/starfive/Kconfig | 5 + drivers/staging/media/starfive/Makefile | 2 + drivers/staging/media/starfive/camss/Kconfig | 17 + drivers/staging/media/starfive/camss/Makefile | 9 + .../staging/media/starfive/camss/stf-camss.c | 320 ++++++++++++++++++ .../staging/media/starfive/camss/stf-camss.h | 129 +++++++ 9 files changed, 486 insertions(+) create mode 100644 drivers/staging/media/starfive/Kconfig create mode 100644 drivers/staging/media/starfive/Makefile create mode 100644 drivers/staging/media/starfive/camss/Kconfig create mode 100644 drivers/staging/media/starfive/camss/Makefile create mode 100644 drivers/staging/media/starfive/camss/stf-camss.c create mode 100644 drivers/staging/media/starfive/camss/stf-camss.h diff --git a/MAINTAINERS b/MAINTAINERS index 0c7c33279ee1..7d86cef515ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20645,6 +20645,7 @@ L: linux-media@vger.kernel.org S: Maintained F: Documentation/admin-guide/media/starfive_camss.rst F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml +F: drivers/staging/media/starfive/camss STARFIVE CRYPTO DRIVER M: Jia Jie Ho diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index bc6c7b248f86..554c2e475ce3 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -36,6 +36,8 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/rkvdec/Kconfig" +source "drivers/staging/media/starfive/Kconfig" + source "drivers/staging/media/sunxi/Kconfig" source "drivers/staging/media/tegra-video/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 1a4c3a062e3d..dcaeeca0ee6d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ +obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ diff --git a/drivers/staging/media/starfive/Kconfig b/drivers/staging/media/starfive/Kconfig new file mode 100644 index 000000000000..34727cf56072 --- /dev/null +++ b/drivers/staging/media/starfive/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "StarFive media platform drivers" + +source "drivers/staging/media/starfive/camss/Kconfig" diff --git a/drivers/staging/media/starfive/Makefile b/drivers/staging/media/starfive/Makefile new file mode 100644 index 000000000000..4639fa1bca32 --- /dev/null +++ b/drivers/staging/media/starfive/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += camss/ diff --git a/drivers/staging/media/starfive/camss/Kconfig b/drivers/staging/media/starfive/camss/Kconfig new file mode 100644 index 000000000000..bd184f42c98f --- /dev/null +++ b/drivers/staging/media/starfive/camss/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_STARFIVE_CAMSS + tristate "Starfive Camera Subsystem driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV && OF + depends on HAS_DMA + depends on PM + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Enable this to support for the Starfive Camera subsystem + found on Starfive JH7110 SoC. + + To compile this driver as a module, choose M here: the + module will be called starfive-camss. diff --git a/drivers/staging/media/starfive/camss/Makefile b/drivers/staging/media/starfive/camss/Makefile new file mode 100644 index 000000000000..78211e30550f --- /dev/null +++ b/drivers/staging/media/starfive/camss/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for StarFive Camera Subsystem driver +# + +starfive-camss-objs += \ + stf-camss.o + +obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o diff --git a/drivers/staging/media/starfive/camss/stf-camss.c b/drivers/staging/media/starfive/camss/stf-camss.c new file mode 100644 index 000000000000..c9743ff23b81 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-camss.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * stf_camss.c + * + * Starfive Camera Subsystem driver + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + * + * Author: Jack Zhu + * Author: Changhuang Liang + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stf-camss.h" + +static const char * const stfcamss_clocks[] = { + "wrapper_clk_c", + "ispcore_2x", + "isp_axi", +}; + +static const char * const stfcamss_resets[] = { + "wrapper_p", + "wrapper_c", + "axiwr", + "isp_top_n", + "isp_top_axi", +}; + +static int stfcamss_get_mem_res(struct stfcamss *stfcamss) +{ + struct platform_device *pdev = to_platform_device(stfcamss->dev); + + stfcamss->syscon_base = + devm_platform_ioremap_resource_byname(pdev, "syscon"); + if (IS_ERR(stfcamss->syscon_base)) + return PTR_ERR(stfcamss->syscon_base); + + stfcamss->isp_base = devm_platform_ioremap_resource_byname(pdev, "isp"); + if (IS_ERR(stfcamss->isp_base)) + return PTR_ERR(stfcamss->isp_base); + + return 0; +} + +/* + * stfcamss_of_parse_endpoint_node - Parse port endpoint node + * @dev: Device + * @node: Device node to be parsed + * @csd: Parsed data from port endpoint node + * + * Return 0 on success or a negative error code on failure + */ +static int stfcamss_of_parse_endpoint_node(struct stfcamss *stfcamss, + struct device_node *node, + struct stfcamss_async_subdev *csd) +{ + struct v4l2_fwnode_endpoint vep = { { 0 } }; + int ret; + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); + if (ret) { + dev_err(stfcamss->dev, "endpoint not defined at %pOF\n", node); + return ret; + } + + csd->port = vep.base.port; + + return 0; +} + +/* + * stfcamss_of_parse_ports - Parse ports node + * @stfcamss: STFCAMSS device + * + * Return number of "port" nodes found in "ports" node + */ +static int stfcamss_of_parse_ports(struct stfcamss *stfcamss) +{ + struct device_node *node = NULL; + int ret, num_subdevs = 0; + + for_each_endpoint_of_node(stfcamss->dev->of_node, node) { + struct stfcamss_async_subdev *csd; + + if (!of_device_is_available(node)) + continue; + + csd = v4l2_async_nf_add_fwnode_remote(&stfcamss->notifier, + of_fwnode_handle(node), + struct stfcamss_async_subdev); + if (IS_ERR(csd)) { + ret = PTR_ERR(csd); + dev_err(stfcamss->dev, "failed to add async notifier\n"); + goto err_cleanup; + } + + ret = stfcamss_of_parse_endpoint_node(stfcamss, node, csd); + if (ret) + goto err_cleanup; + + num_subdevs++; + } + + return num_subdevs; + +err_cleanup: + of_node_put(node); + return ret; +} + +static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf) +{ + struct stfcamss *stfcamss = + container_of(ntf, struct stfcamss, notifier); + + return v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev); +} + +static const struct v4l2_async_notifier_operations +stfcamss_subdev_notifier_ops = { + .complete = stfcamss_subdev_notifier_complete, +}; + +static void stfcamss_mc_init(struct platform_device *pdev, + struct stfcamss *stfcamss) +{ + stfcamss->media_dev.dev = stfcamss->dev; + strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem", + sizeof(stfcamss->media_dev.model)); + media_device_init(&stfcamss->media_dev); + + stfcamss->v4l2_dev.mdev = &stfcamss->media_dev; +} + +/* + * stfcamss_probe - Probe STFCAMSS platform device + * @pdev: Pointer to STFCAMSS platform device + * + * Return 0 on success or a negative error code on failure + */ +static int stfcamss_probe(struct platform_device *pdev) +{ + struct stfcamss *stfcamss; + struct device *dev = &pdev->dev; + int ret, num_subdevs; + unsigned int i; + + stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL); + if (!stfcamss) + return -ENOMEM; + + stfcamss->dev = dev; + + stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk); + for (i = 0; i < stfcamss->nclks; ++i) + stfcamss->sys_clk[i].id = stfcamss_clocks[i]; + ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk); + if (ret) { + dev_err(dev, "Failed to get clk controls\n"); + return ret; + } + + stfcamss->nrsts = ARRAY_SIZE(stfcamss->sys_rst); + for (i = 0; i < stfcamss->nrsts; ++i) + stfcamss->sys_rst[i].id = stfcamss_resets[i]; + ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts, + stfcamss->sys_rst); + if (ret) { + dev_err(dev, "Failed to get reset controls\n"); + return ret; + } + + ret = stfcamss_get_mem_res(stfcamss); + if (ret) { + dev_err(dev, "Could not map registers\n"); + return ret; + } + + platform_set_drvdata(pdev, stfcamss); + + v4l2_async_nf_init(&stfcamss->notifier, &stfcamss->v4l2_dev); + + num_subdevs = stfcamss_of_parse_ports(stfcamss); + if (num_subdevs < 0) { + ret = -ENODEV; + dev_err(dev, "Failed to get sub devices: %d\n", ret); + goto err_cleanup_notifier; + } + + stfcamss_mc_init(pdev, stfcamss); + + ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev); + if (ret < 0) { + dev_err(dev, "Failed to register V4L2 device: %d\n", ret); + goto err_cleanup_media_device; + } + + ret = media_device_register(&stfcamss->media_dev); + if (ret) { + dev_err(dev, "Failed to register media device: %d\n", ret); + goto err_unregister_device; + } + + pm_runtime_enable(dev); + + stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops; + ret = v4l2_async_nf_register(&stfcamss->notifier); + if (ret) { + dev_err(dev, "Failed to register async subdev nodes: %d\n", + ret); + pm_runtime_disable(dev); + goto err_unregister_media_dev; + } + + return 0; + +err_unregister_media_dev: + media_device_unregister(&stfcamss->media_dev); +err_unregister_device: + v4l2_device_unregister(&stfcamss->v4l2_dev); +err_cleanup_media_device: + media_device_cleanup(&stfcamss->media_dev); +err_cleanup_notifier: + v4l2_async_nf_cleanup(&stfcamss->notifier); + return ret; +} + +/* + * stfcamss_remove - Remove STFCAMSS platform device + * @pdev: Pointer to STFCAMSS platform device + * + * Always returns 0. + */ +static int stfcamss_remove(struct platform_device *pdev) +{ + struct stfcamss *stfcamss = platform_get_drvdata(pdev); + + v4l2_device_unregister(&stfcamss->v4l2_dev); + media_device_cleanup(&stfcamss->media_dev); + v4l2_async_nf_cleanup(&stfcamss->notifier); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id stfcamss_of_match[] = { + { .compatible = "starfive,jh7110-camss" }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, stfcamss_of_match); + +static int __maybe_unused stfcamss_runtime_suspend(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + int ret; + + ret = reset_control_bulk_assert(stfcamss->nrsts, stfcamss->sys_rst); + if (ret) { + dev_err(dev, "reset assert failed\n"); + return ret; + } + + clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk); + + return 0; +} + +static int __maybe_unused stfcamss_runtime_resume(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(stfcamss->nclks, stfcamss->sys_clk); + if (ret) { + dev_err(dev, "clock prepare enable failed\n"); + return ret; + } + + ret = reset_control_bulk_deassert(stfcamss->nrsts, stfcamss->sys_rst); + if (ret < 0) { + dev_err(dev, "cannot deassert resets\n"); + clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops stfcamss_pm_ops = { + SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, + stfcamss_runtime_resume, + NULL) +}; + +static struct platform_driver stfcamss_driver = { + .probe = stfcamss_probe, + .remove = stfcamss_remove, + .driver = { + .name = "starfive-camss", + .pm = &stfcamss_pm_ops, + .of_match_table = stfcamss_of_match, + }, +}; + +module_platform_driver(stfcamss_driver); + +MODULE_AUTHOR("Jack Zhu "); +MODULE_AUTHOR("Changhuang Liang "); +MODULE_DESCRIPTION("StarFive Camera Subsystem driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/starfive/camss/stf-camss.h b/drivers/staging/media/starfive/camss/stf-camss.h new file mode 100644 index 000000000000..47d715122155 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-camss.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * stf_camss.h + * + * Starfive Camera Subsystem driver + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#ifndef STF_CAMSS_H +#define STF_CAMSS_H + +#include +#include +#include +#include +#include +#include +#include + +enum stf_port_num { + STF_PORT_DVP = 0, + STF_PORT_CSI2RX +}; + +enum stf_clk { + STF_CLK_WRAPPER_CLK_C = 0, + STF_CLK_ISPCORE_2X, + STF_CLK_ISP_AXI, + STF_CLK_NUM +}; + +enum stf_rst { + STF_RST_WRAPPER_P = 0, + STF_RST_WRAPPER_C, + STF_RST_AXIWR, + STF_RST_ISP_TOP_N, + STF_RST_ISP_TOP_AXI, + STF_RST_NUM +}; + +struct stf_isr_data { + const char *name; + irqreturn_t (*isr)(int irq, void *priv); +}; + +struct stfcamss { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct media_pipeline pipe; + struct device *dev; + struct v4l2_async_notifier notifier; + void __iomem *syscon_base; + void __iomem *isp_base; + struct clk_bulk_data sys_clk[STF_CLK_NUM]; + int nclks; + struct reset_control_bulk_data sys_rst[STF_RST_NUM]; + int nrsts; +}; + +struct stfcamss_async_subdev { + struct v4l2_async_connection asd; /* must be first */ + enum stf_port_num port; +}; + +static inline u32 stf_isp_reg_read(struct stfcamss *stfcamss, u32 reg) +{ + return ioread32(stfcamss->isp_base + reg); +} + +static inline void stf_isp_reg_write(struct stfcamss *stfcamss, + u32 reg, u32 val) +{ + iowrite32(val, stfcamss->isp_base + reg); +} + +static inline void stf_isp_reg_write_delay(struct stfcamss *stfcamss, + u32 reg, u32 val, u32 delay) +{ + iowrite32(val, stfcamss->isp_base + reg); + usleep_range(1000 * delay, 1000 * delay + 100); +} + +static inline void stf_isp_reg_set_bit(struct stfcamss *stfcamss, + u32 reg, u32 mask, u32 val) +{ + u32 value; + + value = ioread32(stfcamss->isp_base + reg) & ~mask; + val &= mask; + val |= value; + iowrite32(val, stfcamss->isp_base + reg); +} + +static inline void stf_isp_reg_set(struct stfcamss *stfcamss, u32 reg, u32 mask) +{ + iowrite32(ioread32(stfcamss->isp_base + reg) | mask, + stfcamss->isp_base + reg); +} + +static inline u32 stf_syscon_reg_read(struct stfcamss *stfcamss, u32 reg) +{ + return ioread32(stfcamss->syscon_base + reg); +} + +static inline void stf_syscon_reg_write(struct stfcamss *stfcamss, + u32 reg, u32 val) +{ + iowrite32(val, stfcamss->syscon_base + reg); +} + +static inline void stf_syscon_reg_set_bit(struct stfcamss *stfcamss, + u32 reg, u32 bit_mask) +{ + u32 value; + + value = ioread32(stfcamss->syscon_base + reg); + iowrite32(value | bit_mask, stfcamss->syscon_base + reg); +} + +static inline void stf_syscon_reg_clear_bit(struct stfcamss *stfcamss, + u32 reg, u32 bit_mask) +{ + u32 value; + + value = ioread32(stfcamss->syscon_base + reg); + iowrite32(value & ~bit_mask, stfcamss->syscon_base + reg); +} +#endif /* STF_CAMSS_H */ From b7eedc7d2b9465f8c302cfd7749176bae3f1eddd Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:17 +0800 Subject: [PATCH 0712/7721] media: staging: media: starfive: camss: Add video driver Add video driver for StarFive Camera Subsystem. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/Makefile | 3 +- .../staging/media/starfive/camss/stf-video.c | 572 ++++++++++++++++++ .../staging/media/starfive/camss/stf-video.h | 100 +++ 3 files changed, 674 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/media/starfive/camss/stf-video.c create mode 100644 drivers/staging/media/starfive/camss/stf-video.h diff --git a/drivers/staging/media/starfive/camss/Makefile b/drivers/staging/media/starfive/camss/Makefile index 78211e30550f..7d320b9317c8 100644 --- a/drivers/staging/media/starfive/camss/Makefile +++ b/drivers/staging/media/starfive/camss/Makefile @@ -4,6 +4,7 @@ # starfive-camss-objs += \ - stf-camss.o + stf-camss.o \ + stf-video.o obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o diff --git a/drivers/staging/media/starfive/camss/stf-video.c b/drivers/staging/media/starfive/camss/stf-video.c new file mode 100644 index 000000000000..0b305f21eb53 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-video.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * stf_video.c + * + * StarFive Camera Subsystem - V4L2 device node + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#include "stf-camss.h" +#include "stf-video.h" + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static inline struct stfcamss_buffer * +to_stfcamss_buffer(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct stfcamss_buffer, vb); +} + +static const struct stfcamss_format_info * +video_g_fi_by_index(struct stfcamss_video *video, int index) +{ + if (index >= video->nformats) + return NULL; + + return &video->formats[index]; +} + +static const struct stfcamss_format_info * +video_g_fi_by_mcode(struct stfcamss_video *video, u32 mcode) +{ + unsigned int i; + + for (i = 0; i < video->nformats; i++) { + if (video->formats[i].code == mcode) + return &video->formats[i]; + } + + return NULL; +} + +static const struct stfcamss_format_info * +video_g_fi_by_pfmt(struct stfcamss_video *video, u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < video->nformats; i++) { + if (video->formats[i].pixelformat == pixelformat) + return &video->formats[i]; + } + + return NULL; +} + +static int __video_try_fmt(struct stfcamss_video *video, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct stfcamss_format_info *fi; + u32 width, height; + u32 bpl; + unsigned int i; + + fi = video_g_fi_by_pfmt(video, pix->pixelformat); + if (!fi) + fi = &video->formats[0]; /* default format */ + + width = pix->width; + height = pix->height; + + memset(pix, 0, sizeof(*pix)); + + pix->pixelformat = fi->pixelformat; + pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH, + STFCAMSS_FRAME_MAX_WIDTH); + pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT, + STFCAMSS_FRAME_MAX_HEIGHT); + bpl = pix->width * fi->bpp / 8; + bpl = ALIGN(bpl, video->bpl_alignment); + pix->bytesperline = bpl; + + for (i = 0; i < fi->planes; ++i) + pix->sizeimage += bpl * pix->height / fi->vsub[i]; + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_SRGB; + pix->flags = 0; + pix->ycbcr_enc = + V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); + pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, + pix->colorspace, + pix->ycbcr_enc); + pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); + + return 0; +} + +static int stf_video_init_format(struct stfcamss_video *video) +{ + int ret; + struct v4l2_format format = { + .type = video->type, + .fmt.pix = { + .width = 1920, + .height = 1080, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }; + + ret = __video_try_fmt(video, &format); + + if (ret < 0) + return ret; + + video->active_fmt = format; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Video queue operations + */ + +static int video_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct stfcamss_video *video = vb2_get_drv_priv(q); + const struct v4l2_pix_format *format = &video->active_fmt.fmt.pix; + + if (*num_planes) { + if (*num_planes != 1) + return -EINVAL; + + if (sizes[0] < format->sizeimage) + return -EINVAL; + } else { + *num_planes = 1; + sizes[0] = format->sizeimage; + } + + if (!sizes[0]) { + dev_dbg(video->stfcamss->dev, + "%s: error size is zero.\n", __func__); + return -EINVAL; + } + + dev_dbg(video->stfcamss->dev, "planes = %d, size = %d\n", + *num_planes, sizes[0]); + + return 0; +} + +static int video_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct stfcamss_buffer *buffer = to_stfcamss_buffer(vbuf); + const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix; + dma_addr_t *paddr; + + paddr = vb2_plane_cookie(vb, 0); + buffer->addr[0] = *paddr; + + if (fmt->pixelformat == V4L2_PIX_FMT_NV12) + buffer->addr[1] = + buffer->addr[0] + fmt->bytesperline * fmt->height; + + return 0; +} + +static int video_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); + const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix; + + if (fmt->sizeimage > vb2_plane_size(vb, 0)) { + dev_dbg(video->stfcamss->dev, + "sizeimage = %u, plane size = %u\n", + fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0)); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, fmt->sizeimage); + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static void video_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct stfcamss_buffer *buffer = to_stfcamss_buffer(vbuf); + + video->ops->queue_buffer(video, buffer); +} + +static int video_get_subdev_format(struct stfcamss_video *video, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_subdev *subdev; + struct media_pad *pad; + struct media_entity *entity; + int ret; + + entity = &video->vdev.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_pad_remote_pad_first(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + fmt->pad = pad->index; + + ret = v4l2_subdev_call_state_active(subdev, pad, get_fmt, fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + else if (!ret) + break; + } + + return 0; +} + +static int stf_video_check_format(struct stfcamss_video *video) +{ + struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix; + const struct stfcamss_format_info *fi; + int ret; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + ret = video_get_subdev_format(video, &sd_fmt); + if (ret < 0) + return ret; + + fi = video_g_fi_by_mcode(video, sd_fmt.format.code); + if (!fi) + return -EINVAL; + + if (pix->pixelformat != fi->pixelformat || + pix->height != sd_fmt.format.height || + pix->width != sd_fmt.format.width || + pix->field != sd_fmt.format.field) + return -EPIPE; + + return 0; +} + +static int video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct stfcamss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + int ret; + + ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe); + if (ret < 0) { + dev_err(video->stfcamss->dev, + "Failed to media_pipeline_start: %d\n", ret); + goto err_ret_buffers; + } + + ret = pm_runtime_resume_and_get(video->stfcamss->dev); + if (ret < 0) { + dev_err(video->stfcamss->dev, "power up failed %d\n", ret); + goto err_pipeline_stop; + } + + video->ops->start_streaming(video); + + ret = v4l2_subdev_call(video->source_subdev, video, s_stream, true); + if (ret) { + dev_err(video->stfcamss->dev, "stream on failed\n"); + goto err_pm_put; + } + + return 0; + +err_pm_put: + pm_runtime_put(video->stfcamss->dev); +err_pipeline_stop: + video_device_pipeline_stop(vdev); +err_ret_buffers: + video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void video_stop_streaming(struct vb2_queue *q) +{ + struct stfcamss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + + video->ops->stop_streaming(video); + + v4l2_subdev_call(video->source_subdev, video, s_stream, false); + + pm_runtime_put(video->stfcamss->dev); + + video_device_pipeline_stop(vdev); + video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops stf_video_vb2_q_ops = { + .queue_setup = video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = video_buf_init, + .buf_prepare = video_buf_prepare, + .buf_queue = video_buf_queue, + .start_streaming = video_start_streaming, + .stop_streaming = video_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, "starfive-camss", sizeof(cap->driver)); + strscpy(cap->card, "Starfive Camera Subsystem", sizeof(cap->card)); + + return 0; +} + +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct stfcamss_video *video = video_drvdata(file); + const struct stfcamss_format_info *fi; + + if (f->index >= video->nformats) + return -EINVAL; + + if (f->mbus_code) { + /* Each entry in formats[] table has unique mbus_code */ + if (f->index > 0) + return -EINVAL; + + fi = video_g_fi_by_mcode(video, f->mbus_code); + } else { + fi = video_g_fi_by_index(video, f->index); + } + + if (!fi) + return -EINVAL; + + f->pixelformat = fi->pixelformat; + + return 0; +} + +static int video_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct stfcamss_video *video = video_drvdata(file); + unsigned int i; + + if (fsize->index) + return -EINVAL; + + for (i = 0; i < video->nformats; i++) { + if (video->formats[i].pixelformat == fsize->pixel_format) + break; + } + + if (i == video->nformats) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH; + fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH; + fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT; + fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct stfcamss_video *video = video_drvdata(file); + + *f = video->active_fmt; + + return 0; +} + +static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct stfcamss_video *video = video_drvdata(file); + int ret; + + if (vb2_is_busy(&video->vb2_q)) + return -EBUSY; + + ret = __video_try_fmt(video, f); + if (ret < 0) + return ret; + + video->active_fmt = *f; + + return 0; +} + +static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct stfcamss_video *video = video_drvdata(file); + + return __video_try_fmt(video, f); +} + +static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = { + .vidioc_querycap = video_querycap, + .vidioc_enum_fmt_vid_cap = video_enum_fmt, + .vidioc_enum_framesizes = video_enum_framesizes, + .vidioc_g_fmt_vid_cap = video_g_fmt, + .vidioc_s_fmt_vid_cap = video_s_fmt, + .vidioc_try_fmt_vid_cap = video_try_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static const struct v4l2_file_operations stf_vid_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +/* ----------------------------------------------------------------------------- + * STFCAMSS video core + */ + +static int stf_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->sink->entity); + struct stfcamss_video *video = video_get_drvdata(vdev); + int ret; + + ret = stf_video_check_format(video); + + return ret; +} + +static const struct media_entity_operations stf_media_ops = { + .link_validate = stf_link_validate, +}; + +static void stf_video_release(struct video_device *vdev) +{ + struct stfcamss_video *video = video_get_drvdata(vdev); + + media_entity_cleanup(&vdev->entity); + + mutex_destroy(&video->q_lock); + mutex_destroy(&video->lock); +} + +int stf_video_register(struct stfcamss_video *video, + struct v4l2_device *v4l2_dev, const char *name) +{ + struct video_device *vdev = &video->vdev; + struct vb2_queue *q; + struct media_pad *pad = &video->pad; + int ret; + + mutex_init(&video->q_lock); + mutex_init(&video->lock); + + q = &video->vb2_q; + q->drv_priv = video; + q->mem_ops = &vb2_dma_contig_memops; + q->ops = &stf_video_vb2_q_ops; + q->type = video->type; + q->io_modes = VB2_DMABUF | VB2_MMAP; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->buf_struct_size = sizeof(struct stfcamss_buffer); + q->dev = video->stfcamss->dev; + q->lock = &video->q_lock; + q->min_buffers_needed = STFCAMSS_MIN_BUFFERS; + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(video->stfcamss->dev, + "Failed to init vb2 queue: %d\n", ret); + goto err_mutex_destroy; + } + + pad->flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, pad); + if (ret < 0) { + dev_err(video->stfcamss->dev, + "Failed to init video entity: %d\n", ret); + goto err_mutex_destroy; + } + + ret = stf_video_init_format(video); + if (ret < 0) { + dev_err(video->stfcamss->dev, + "Failed to init format: %d\n", ret); + goto err_media_cleanup; + } + + vdev->fops = &stf_vid_fops; + vdev->ioctl_ops = &stf_vid_ioctl_ops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->entity.ops = &stf_media_ops; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = stf_video_release; + vdev->v4l2_dev = v4l2_dev; + vdev->queue = &video->vb2_q; + vdev->lock = &video->lock; + strscpy(vdev->name, name, sizeof(vdev->name)); + + video_set_drvdata(vdev, video); + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret < 0) { + dev_err(video->stfcamss->dev, + "Failed to register video device: %d\n", ret); + goto err_media_cleanup; + } + + return 0; + +err_media_cleanup: + media_entity_cleanup(&vdev->entity); +err_mutex_destroy: + mutex_destroy(&video->lock); + mutex_destroy(&video->q_lock); + return ret; +} + +void stf_video_unregister(struct stfcamss_video *video) +{ + vb2_video_unregister_device(&video->vdev); +} diff --git a/drivers/staging/media/starfive/camss/stf-video.h b/drivers/staging/media/starfive/camss/stf-video.h new file mode 100644 index 000000000000..8052b77e3ad8 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-video.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * stf_video.h + * + * StarFive Camera Subsystem - V4L2 device node + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#ifndef STF_VIDEO_H +#define STF_VIDEO_H + +#include +#include +#include +#include +#include +#include +#include + +#define STFCAMSS_FRAME_MIN_WIDTH 64 +#define STFCAMSS_FRAME_MAX_WIDTH 1920 +#define STFCAMSS_FRAME_MIN_HEIGHT 64 +#define STFCAMSS_FRAME_MAX_HEIGHT 1080 +#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8 +#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128 +#define STFCAMSS_MIN_BUFFERS 2 + +#define STFCAMSS_MAX_ENTITY_NAME_LEN 27 + +enum stf_v_line_id { + STF_V_LINE_WR = 0, + STF_V_LINE_ISP, + STF_V_LINE_MAX, +}; + +enum stf_capture_type { + STF_CAPTURE_RAW = 0, + STF_CAPTURE_YUV, + STF_CAPTURE_NUM, +}; + +struct stfcamss_buffer { + struct vb2_v4l2_buffer vb; + dma_addr_t addr[2]; + struct list_head queue; +}; + +struct fract { + u8 numerator; + u8 denominator; +}; + +/* + * struct stfcamss_format_info - ISP media bus format information + * @code: V4L2 media bus format code + * @pixelformat: V4L2 pixel format FCC identifier + * @planes: Number of planes + * @vsub: Vertical subsampling (for each plane) + * @bpp: Bits per pixel when stored in memory (for each plane) + */ +struct stfcamss_format_info { + u32 code; + u32 pixelformat; + u8 planes; + u8 vsub[3]; + u8 bpp; +}; + +struct stfcamss_video { + struct stfcamss *stfcamss; + struct vb2_queue vb2_q; + struct video_device vdev; + struct media_pad pad; + struct v4l2_format active_fmt; + enum v4l2_buf_type type; + const struct stfcamss_video_ops *ops; + struct mutex lock; /* serialize device access */ + struct mutex q_lock; /* protects the queue */ + unsigned int bpl_alignment; + const struct stfcamss_format_info *formats; + unsigned int nformats; + struct v4l2_subdev *source_subdev; +}; + +struct stfcamss_video_ops { + int (*queue_buffer)(struct stfcamss_video *video, + struct stfcamss_buffer *buf); + int (*flush_buffers)(struct stfcamss_video *video, + enum vb2_buffer_state state); + void (*start_streaming)(struct stfcamss_video *video); + void (*stop_streaming)(struct stfcamss_video *video); +}; + +int stf_video_register(struct stfcamss_video *video, + struct v4l2_device *v4l2_dev, const char *name); + +void stf_video_unregister(struct stfcamss_video *video); + +#endif /* STF_VIDEO_H */ From e57854628f585c2b7719433dd008f74285a57ed9 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:18 +0800 Subject: [PATCH 0713/7721] media: staging: media: starfive: camss: Add ISP driver Add ISP driver for StarFive Camera Subsystem. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/Makefile | 2 + .../staging/media/starfive/camss/stf-camss.h | 3 + .../media/starfive/camss/stf-isp-hw-ops.c | 445 ++++++++++++++++++ .../staging/media/starfive/camss/stf-isp.c | 382 +++++++++++++++ .../staging/media/starfive/camss/stf-isp.h | 428 +++++++++++++++++ 5 files changed, 1260 insertions(+) create mode 100644 drivers/staging/media/starfive/camss/stf-isp-hw-ops.c create mode 100644 drivers/staging/media/starfive/camss/stf-isp.c create mode 100644 drivers/staging/media/starfive/camss/stf-isp.h diff --git a/drivers/staging/media/starfive/camss/Makefile b/drivers/staging/media/starfive/camss/Makefile index 7d320b9317c8..97e1522b21ae 100644 --- a/drivers/staging/media/starfive/camss/Makefile +++ b/drivers/staging/media/starfive/camss/Makefile @@ -5,6 +5,8 @@ starfive-camss-objs += \ stf-camss.o \ + stf-isp.o \ + stf-isp-hw-ops.o \ stf-video.o obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o diff --git a/drivers/staging/media/starfive/camss/stf-camss.h b/drivers/staging/media/starfive/camss/stf-camss.h index 47d715122155..c7b0a34cd29b 100644 --- a/drivers/staging/media/starfive/camss/stf-camss.h +++ b/drivers/staging/media/starfive/camss/stf-camss.h @@ -18,6 +18,8 @@ #include #include +#include "stf-isp.h" + enum stf_port_num { STF_PORT_DVP = 0, STF_PORT_CSI2RX @@ -49,6 +51,7 @@ struct stfcamss { struct media_device media_dev; struct media_pipeline pipe; struct device *dev; + struct stf_isp_dev isp_dev; struct v4l2_async_notifier notifier; void __iomem *syscon_base; void __iomem *isp_base; diff --git a/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c b/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c new file mode 100644 index 000000000000..c34631ff9422 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * stf_isp_hw_ops.c + * + * Register interface file for StarFive ISP driver + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + * + */ + +#include "stf-camss.h" + +static void stf_isp_config_obc(struct stfcamss *stfcamss) +{ + u32 reg_val, reg_add; + + stf_isp_reg_write(stfcamss, ISP_REG_OBC_CFG, OBC_W_H(11) | OBC_W_W(11)); + + reg_val = GAIN_D_POINT(0x40) | GAIN_C_POINT(0x40) | + GAIN_B_POINT(0x40) | GAIN_A_POINT(0x40); + for (reg_add = ISP_REG_OBCG_CFG_0; reg_add <= ISP_REG_OBCG_CFG_3;) { + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + } + + reg_val = OFFSET_D_POINT(0) | OFFSET_C_POINT(0) | + OFFSET_B_POINT(0) | OFFSET_A_POINT(0); + for (reg_add = ISP_REG_OBCO_CFG_0; reg_add <= ISP_REG_OBCO_CFG_3;) { + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + } +} + +static void stf_isp_config_oecf(struct stfcamss *stfcamss) +{ + u32 reg_add, par_val; + u16 par_h, par_l; + + par_h = 0x10; par_l = 0; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG0; reg_add <= ISP_REG_OECF_Y3_CFG0;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x40; par_l = 0x20; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG1; reg_add <= ISP_REG_OECF_Y3_CFG1;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x80; par_l = 0x60; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG2; reg_add <= ISP_REG_OECF_Y3_CFG2;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0xc0; par_l = 0xa0; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG3; reg_add <= ISP_REG_OECF_Y3_CFG3;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x100; par_l = 0xe0; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG4; reg_add <= ISP_REG_OECF_Y3_CFG4;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x200; par_l = 0x180; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG5; reg_add <= ISP_REG_OECF_Y3_CFG5;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x300; par_l = 0x280; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG6; reg_add <= ISP_REG_OECF_Y3_CFG6;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x3fe; par_l = 0x380; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_X0_CFG7; reg_add <= ISP_REG_OECF_Y3_CFG7;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 0x20; + } + + par_h = 0x80; par_l = 0x80; + par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); + for (reg_add = ISP_REG_OECF_S0_CFG0; reg_add <= ISP_REG_OECF_S3_CFG7;) { + stf_isp_reg_write(stfcamss, reg_add, par_val); + reg_add += 4; + } +} + +static void stf_isp_config_lccf(struct stfcamss *stfcamss) +{ + u32 reg_add; + + stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_0, + Y_DISTANCE(0x21C) | X_DISTANCE(0x3C0)); + stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_1, LCCF_MAX_DIS(0xb)); + + for (reg_add = ISP_REG_LCCF_CFG_2; reg_add <= ISP_REG_LCCF_CFG_5;) { + stf_isp_reg_write(stfcamss, reg_add, + LCCF_F2_PAR(0x0) | LCCF_F1_PAR(0x0)); + reg_add += 4; + } +} + +static void stf_isp_config_awb(struct stfcamss *stfcamss) +{ + u32 reg_val, reg_add; + u16 symbol_h, symbol_l; + + symbol_h = 0x0; symbol_l = 0x0; + reg_val = AWB_X_SYMBOL_H(symbol_h) | AWB_X_SYMBOL_L(symbol_l); + + for (reg_add = ISP_REG_AWB_X0_CFG_0; reg_add <= ISP_REG_AWB_X3_CFG_1;) { + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + } + + symbol_h = 0x0, symbol_l = 0x0; + reg_val = AWB_Y_SYMBOL_H(symbol_h) | AWB_Y_SYMBOL_L(symbol_l); + + for (reg_add = ISP_REG_AWB_Y0_CFG_0; reg_add <= ISP_REG_AWB_Y3_CFG_1;) { + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + } + + symbol_h = 0x80, symbol_l = 0x80; + reg_val = AWB_S_SYMBOL_H(symbol_h) | AWB_S_SYMBOL_L(symbol_l); + + for (reg_add = ISP_REG_AWB_S0_CFG_0; reg_add <= ISP_REG_AWB_S3_CFG_1;) { + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + } +} + +static void stf_isp_config_grgb(struct stfcamss *stfcamss) +{ + stf_isp_reg_write(stfcamss, ISP_REG_ICTC, + GF_MODE(1) | MAXGT(0x140) | MINGT(0x40)); + stf_isp_reg_write(stfcamss, ISP_REG_IDBC, BADGT(0x200) | BADXT(0x200)); +} + +static void stf_isp_config_cfa(struct stfcamss *stfcamss) +{ + stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, + SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | SMY3(2) | + SMY2(3) | SMY1(2) | SMY0(3)); + stf_isp_reg_write(stfcamss, ISP_REG_ICFAM, CROSS_COV(3) | HV_W(2)); +} + +static void stf_isp_config_ccm(struct stfcamss *stfcamss) +{ + u32 reg_add; + + stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_0, DNRM_F(6) | CCM_M_DAT(0)); + + for (reg_add = ISP_REG_ICAMD_12; reg_add <= ISP_REG_ICAMD_20;) { + stf_isp_reg_write(stfcamss, reg_add, CCM_M_DAT(0x80)); + reg_add += 0x10; + } + + stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_24, CCM_M_DAT(0x700)); + stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_25, CCM_M_DAT(0x200)); +} + +static void stf_isp_config_gamma(struct stfcamss *stfcamss) +{ + u32 reg_val, reg_add; + u16 gamma_slope_v, gamma_v; + + gamma_slope_v = 0x2400; gamma_v = 0x0; + reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); + stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL0, reg_val); + + gamma_slope_v = 0x800; gamma_v = 0x20; + for (reg_add = ISP_REG_GAMMA_VAL1; reg_add <= ISP_REG_GAMMA_VAL7;) { + reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + gamma_v += 0x20; + } + + gamma_v = 0x100; + for (reg_add = ISP_REG_GAMMA_VAL8; reg_add <= ISP_REG_GAMMA_VAL13;) { + reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); + stf_isp_reg_write(stfcamss, reg_add, reg_val); + reg_add += 4; + gamma_v += 0x80; + } + + gamma_v = 0x3fe; + reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); + stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL14, reg_val); +} + +static void stf_isp_config_r2y(struct stfcamss *stfcamss) +{ + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_0, 0x4C); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_1, 0x97); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_2, 0x1d); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_3, 0x1d5); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_4, 0x1ac); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_5, 0x80); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_6, 0x80); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_7, 0x194); + stf_isp_reg_write(stfcamss, ISP_REG_R2Y_8, 0x1ec); +} + +static void stf_isp_config_y_curve(struct stfcamss *stfcamss) +{ + u32 reg_add; + u16 y_curve; + + y_curve = 0x0; + for (reg_add = ISP_REG_YCURVE_0; reg_add <= ISP_REG_YCURVE_63;) { + stf_isp_reg_write(stfcamss, reg_add, y_curve); + reg_add += 4; + y_curve += 0x10; + } +} + +static void stf_isp_config_sharpen(struct stfcamss *sc) +{ + u32 reg_add; + + stf_isp_reg_write(sc, ISP_REG_SHARPEN0, S_DELTA(0x7) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN1, S_DELTA(0x18) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN2, S_DELTA(0x80) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN3, S_DELTA(0x100) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN4, S_DELTA(0x10) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN5, S_DELTA(0x60) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN6, S_DELTA(0x100) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN7, S_DELTA(0x190) | S_WEIGHT(0xf)); + stf_isp_reg_write(sc, ISP_REG_SHARPEN8, S_DELTA(0x0) | S_WEIGHT(0xf)); + + for (reg_add = ISP_REG_SHARPEN9; reg_add <= ISP_REG_SHARPEN14;) { + stf_isp_reg_write(sc, reg_add, S_WEIGHT(0xf)); + reg_add += 4; + } + + for (reg_add = ISP_REG_SHARPEN_FS0; reg_add <= ISP_REG_SHARPEN_FS5;) { + stf_isp_reg_write(sc, reg_add, S_FACTOR(0x10) | S_SLOPE(0x0)); + reg_add += 4; + } + + stf_isp_reg_write(sc, ISP_REG_SHARPEN_WN, + PDIRF(0x8) | NDIRF(0x8) | WSUM(0xd7c)); + stf_isp_reg_write(sc, ISP_REG_IUVS1, UVDIFF2(0xC0) | UVDIFF1(0x40)); + stf_isp_reg_write(sc, ISP_REG_IUVS2, UVF(0xff) | UVSLOPE(0x0)); + stf_isp_reg_write(sc, ISP_REG_IUVCKS1, + UVCKDIFF2(0xa0) | UVCKDIFF1(0x40)); +} + +static void stf_isp_config_dnyuv(struct stfcamss *stfcamss) +{ + u32 reg_val; + + reg_val = YUVSW5(7) | YUVSW4(7) | YUVSW3(7) | YUVSW2(7) | + YUVSW1(7) | YUVSW0(7); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR0, reg_val); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR0, reg_val); + + reg_val = YUVSW3(7) | YUVSW2(7) | YUVSW1(7) | YUVSW0(7); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR1, reg_val); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR1, reg_val); + + reg_val = CURVE_D_H(0x60) | CURVE_D_L(0x40); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR0, reg_val); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR0, reg_val); + + reg_val = CURVE_D_H(0xd8) | CURVE_D_L(0x90); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR1, reg_val); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR1, reg_val); + + reg_val = CURVE_D_H(0x1e6) | CURVE_D_L(0x144); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR2, reg_val); + stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR2, reg_val); +} + +static void stf_isp_config_sat(struct stfcamss *stfcamss) +{ + stf_isp_reg_write(stfcamss, ISP_REG_CS_GAIN, CMAD(0x0) | CMAB(0x100)); + stf_isp_reg_write(stfcamss, ISP_REG_CS_THRESHOLD, CMD(0x1f) | CMB(0x1)); + stf_isp_reg_write(stfcamss, ISP_REG_CS_OFFSET, VOFF(0x0) | UOFF(0x0)); + stf_isp_reg_write(stfcamss, ISP_REG_CS_HUE_F, SIN(0x0) | COS(0x100)); + stf_isp_reg_write(stfcamss, ISP_REG_CS_SCALE, 0x8); + stf_isp_reg_write(stfcamss, ISP_REG_YADJ0, YOIR(0x401) | YIMIN(0x1)); + stf_isp_reg_write(stfcamss, ISP_REG_YADJ1, YOMAX(0x3ff) | YOMIN(0x1)); +} + +int stf_isp_reset(struct stf_isp_dev *isp_dev) +{ + stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0, + ISPC_RST_MASK, ISPC_RST); + stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0, + ISPC_RST_MASK, 0); + + return 0; +} + +void stf_isp_init_cfg(struct stf_isp_dev *isp_dev) +{ + stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DC_CFG_1, DC_AXI_ID(0x0)); + stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DEC_CFG, + DEC_V_KEEP(0x0) | + DEC_V_PERIOD(0x0) | + DEC_H_KEEP(0x0) | + DEC_H_PERIOD(0x0)); + + stf_isp_config_obc(isp_dev->stfcamss); + stf_isp_config_oecf(isp_dev->stfcamss); + stf_isp_config_lccf(isp_dev->stfcamss); + stf_isp_config_awb(isp_dev->stfcamss); + stf_isp_config_grgb(isp_dev->stfcamss); + stf_isp_config_cfa(isp_dev->stfcamss); + stf_isp_config_ccm(isp_dev->stfcamss); + stf_isp_config_gamma(isp_dev->stfcamss); + stf_isp_config_r2y(isp_dev->stfcamss); + stf_isp_config_y_curve(isp_dev->stfcamss); + stf_isp_config_sharpen(isp_dev->stfcamss); + stf_isp_config_dnyuv(isp_dev->stfcamss); + stf_isp_config_sat(isp_dev->stfcamss); + + stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_CSI_MODULE_CFG, + CSI_DUMP_EN | CSI_SC_EN | CSI_AWB_EN | + CSI_LCCF_EN | CSI_OECF_EN | CSI_OBC_EN | CSI_DEC_EN); + stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_ISP_CTRL_1, + CTRL_SAT(1) | CTRL_DBC | CTRL_CTC | CTRL_YHIST | + CTRL_YCURVE | CTRL_BIYUV | CTRL_SCE | CTRL_EE | + CTRL_CCE | CTRL_RGE | CTRL_CME | CTRL_AE | CTRL_CE); +} + +static void stf_isp_config_crop(struct stfcamss *stfcamss, + struct v4l2_rect *crop) +{ + u32 bpp = stfcamss->isp_dev.current_fmt->bpp; + u32 val; + + val = VSTART_CAP(crop->top) | HSTART_CAP(crop->left); + stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_START_CFG, val); + + val = VEND_CAP(crop->height + crop->top - 1) | + HEND_CAP(crop->width + crop->left - 1); + stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_END_CFG, val); + + val = H_ACT_CAP(crop->height) | W_ACT_CAP(crop->width); + stf_isp_reg_write(stfcamss, ISP_REG_PIPELINE_XY_SIZE, val); + + val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8); + stf_isp_reg_write(stfcamss, ISP_REG_STRIDE, val); +} + +static void stf_isp_config_raw_fmt(struct stfcamss *stfcamss, u32 mcode) +{ + u32 val, val1; + + switch (mcode) { + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB8_1X8: + /* 3 2 3 2 1 0 1 0 B Gb B Gb Gr R Gr R */ + val = SMY13(3) | SMY12(2) | SMY11(3) | SMY10(2) | + SMY3(1) | SMY2(0) | SMY1(1) | SMY0(0); + val1 = CTRL_SAT(0x0); + break; + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG8_1X8: + /* 2 3 2 3 0 1 0 1, Gb B Gb B R Gr R Gr */ + val = SMY13(2) | SMY12(3) | SMY11(2) | SMY10(3) | + SMY3(0) | SMY2(1) | SMY1(0) | SMY0(1); + val1 = CTRL_SAT(0x2); + break; + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG8_1X8: + /* 1 0 1 0 3 2 3 2, Gr R Gr R B Gb B Gb */ + val = SMY13(1) | SMY12(0) | SMY11(1) | SMY10(0) | + SMY3(3) | SMY2(2) | SMY1(3) | SMY0(2); + val1 = CTRL_SAT(0x3); + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR8_1X8: + /* 0 1 0 1 2 3 2 3 R Gr R Gr Gb B Gb B */ + val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | + SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3); + val1 = CTRL_SAT(0x1); + break; + default: + val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | + SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3); + val1 = CTRL_SAT(0x1); + break; + } + stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, val); + stf_isp_reg_set_bit(stfcamss, ISP_REG_ISP_CTRL_1, CTRL_SAT_MASK, val1); +} + +void stf_isp_settings(struct stf_isp_dev *isp_dev, + struct v4l2_rect *crop, u32 mcode) +{ + struct stfcamss *stfcamss = isp_dev->stfcamss; + + stf_isp_config_crop(stfcamss, crop); + stf_isp_config_raw_fmt(stfcamss, mcode); + + stf_isp_reg_set_bit(stfcamss, ISP_REG_DUMP_CFG_1, + DUMP_BURST_LEN_MASK | DUMP_SD_MASK, + DUMP_BURST_LEN(3)); + + stf_isp_reg_write(stfcamss, ISP_REG_ITIIWSR, + ITI_HSIZE(IMAGE_MAX_HEIGH) | + ITI_WSIZE(IMAGE_MAX_WIDTH)); + stf_isp_reg_write(stfcamss, ISP_REG_ITIDWLSR, 0x960); + stf_isp_reg_write(stfcamss, ISP_REG_ITIDRLSR, 0x960); + stf_isp_reg_write(stfcamss, ISP_REG_SENSOR, IMAGER_SEL(1)); +} + +void stf_isp_stream_set(struct stf_isp_dev *isp_dev) +{ + struct stfcamss *stfcamss = isp_dev->stfcamss; + + stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, + ISPC_ENUO | ISPC_ENLS | ISPC_RST, 10); + stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, + ISPC_ENUO | ISPC_ENLS, 10); + stf_isp_reg_write(stfcamss, ISP_REG_IESHD, SHAD_UP_M); + stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, + ISPC_ENUO | ISPC_ENLS | ISPC_EN, 10); + stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS, + CSI_INTS(1) | CSI_SHA_M(4), 10); + stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS, + CSI_INTS(2) | CSI_SHA_M(4), 10); + stf_isp_reg_write_delay(stfcamss, ISP_REG_CSI_INPUT_EN_AND_STATUS, + CSI_EN_S, 10); +} diff --git a/drivers/staging/media/starfive/camss/stf-isp.c b/drivers/staging/media/starfive/camss/stf-isp.c new file mode 100644 index 000000000000..4205671214b2 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-isp.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * stf_isp.c + * + * StarFive Camera Subsystem - ISP Module + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ +#include + +#include "stf-camss.h" + +#define SINK_FORMATS_INDEX 0 +#define SOURCE_FORMATS_INDEX 1 + +static int isp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel); + +static const struct stf_isp_format isp_formats_sink[] = { + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, +}; + +static const struct stf_isp_format isp_formats_source[] = { + { MEDIA_BUS_FMT_YUYV8_1_5X8, 8 }, +}; + +static const struct stf_isp_format_table isp_formats_st7110[] = { + { isp_formats_sink, ARRAY_SIZE(isp_formats_sink) }, + { isp_formats_source, ARRAY_SIZE(isp_formats_source) }, +}; + +static const struct stf_isp_format * +stf_g_fmt_by_mcode(const struct stf_isp_format_table *fmt_table, u32 mcode) +{ + unsigned int i; + + for (i = 0; i < fmt_table->nfmts; i++) { + if (fmt_table->fmts[i].code == mcode) + return &fmt_table->fmts[i]; + } + + return NULL; +} + +int stf_isp_init(struct stfcamss *stfcamss) +{ + struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; + + isp_dev->stfcamss = stfcamss; + isp_dev->formats = isp_formats_st7110; + isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110); + isp_dev->current_fmt = &isp_formats_source[0]; + + return 0; +} + +static int isp_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); + struct v4l2_subdev_state *sd_state; + struct v4l2_mbus_framefmt *fmt; + struct v4l2_rect *crop; + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, STF_ISP_PAD_SINK); + crop = v4l2_subdev_get_pad_crop(sd, sd_state, STF_ISP_PAD_SRC); + + if (enable) { + stf_isp_reset(isp_dev); + stf_isp_init_cfg(isp_dev); + stf_isp_settings(isp_dev, crop, fmt->code); + stf_isp_stream_set(isp_dev); + } + + v4l2_subdev_call(isp_dev->source_subdev, video, s_stream, enable); + + v4l2_subdev_unlock_state(sd_state); + return 0; +} + +static void isp_try_format(struct stf_isp_dev *isp_dev, + struct v4l2_subdev_state *state, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt) +{ + const struct stf_isp_format_table *formats; + + if (pad >= STF_ISP_PAD_MAX) { + fmt->colorspace = V4L2_COLORSPACE_SRGB; + return; + } + + if (pad == STF_ISP_PAD_SINK) + formats = &isp_dev->formats[SINK_FORMATS_INDEX]; + else if (pad == STF_ISP_PAD_SRC) + formats = &isp_dev->formats[SOURCE_FORMATS_INDEX]; + + fmt->width = clamp_t(u32, fmt->width, STFCAMSS_FRAME_MIN_WIDTH, + STFCAMSS_FRAME_MAX_WIDTH); + fmt->height = clamp_t(u32, fmt->height, STFCAMSS_FRAME_MIN_HEIGHT, + STFCAMSS_FRAME_MAX_HEIGHT); + fmt->height &= ~0x1; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->flags = 0; + + if (!stf_g_fmt_by_mcode(formats, fmt->code)) + fmt->code = formats->fmts[0].code; +} + +static int isp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); + const struct stf_isp_format_table *formats; + + if (code->pad == STF_ISP_PAD_SINK) { + if (code->index > ARRAY_SIZE(isp_formats_sink)) + return -EINVAL; + + formats = &isp_dev->formats[SINK_FORMATS_INDEX]; + code->code = formats->fmts[code->index].code; + } else { + struct v4l2_mbus_framefmt *sink_fmt; + + if (code->index > ARRAY_SIZE(isp_formats_source)) + return -EINVAL; + + sink_fmt = v4l2_subdev_get_pad_format(sd, state, + STF_ISP_PAD_SRC); + + code->code = sink_fmt->code; + if (!code->code) + return -EINVAL; + } + code->flags = 0; + + return 0; +} + +static int isp_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + if (!format) + return -EINVAL; + + isp_try_format(isp_dev, state, fmt->pad, &fmt->format); + *format = fmt->format; + + isp_dev->current_fmt = stf_g_fmt_by_mcode(&isp_dev->formats[fmt->pad], + fmt->format.code); + + /* Propagate to in crop */ + if (fmt->pad == STF_ISP_PAD_SINK) { + struct v4l2_subdev_selection sel = { 0 }; + + /* Reset sink pad compose selection */ + sel.which = fmt->which; + sel.pad = STF_ISP_PAD_SINK; + sel.target = V4L2_SEL_TGT_CROP; + sel.r.width = fmt->format.width; + sel.r.height = fmt->format.height; + isp_set_selection(sd, state, &sel); + } + + return 0; +} + +static const struct v4l2_rect stf_frame_min_crop = { + .width = STFCAMSS_FRAME_MIN_WIDTH, + .height = STFCAMSS_FRAME_MIN_HEIGHT, + .top = 0, + .left = 0, +}; + +static void isp_try_crop(struct stf_isp_dev *isp_dev, + struct v4l2_subdev_state *state, + struct v4l2_rect *crop) +{ + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_pad_format(&isp_dev->subdev, state, + STF_ISP_PAD_SINK); + + const struct v4l2_rect bounds = { + .width = fmt->width, + .height = fmt->height, + .left = 0, + .top = 0, + }; + + v4l2_rect_set_min_size(crop, &stf_frame_min_crop); + v4l2_rect_map_inside(crop, &bounds); +} + +static int isp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_subdev_format fmt = { 0 }; + struct v4l2_rect *rect; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + if (sel->pad == STF_ISP_PAD_SINK) { + fmt.format = *v4l2_subdev_get_pad_format(sd, state, + sel->pad); + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = fmt.format.width; + sel->r.height = fmt.format.height; + } else if (sel->pad == STF_ISP_PAD_SRC) { + rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + sel->r = *rect; + } + break; + + case V4L2_SEL_TGT_CROP: + rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + if (!rect) + return -EINVAL; + + sel->r = *rect; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int isp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); + struct v4l2_rect *rect; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + if (sel->target == V4L2_SEL_TGT_CROP && + sel->pad == STF_ISP_PAD_SINK) { + struct v4l2_subdev_selection crop = { 0 }; + + rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + if (!rect) + return -EINVAL; + + isp_try_crop(isp_dev, state, &sel->r); + *rect = sel->r; + + /* Reset source crop selection */ + crop.which = sel->which; + crop.pad = STF_ISP_PAD_SRC; + crop.target = V4L2_SEL_TGT_CROP; + crop.r = *rect; + isp_set_selection(sd, state, &crop); + } else if (sel->target == V4L2_SEL_TGT_CROP && + sel->pad == STF_ISP_PAD_SRC) { + struct v4l2_subdev_format fmt = { 0 }; + + rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + if (!rect) + return -EINVAL; + + isp_try_crop(isp_dev, state, &sel->r); + *rect = sel->r; + + /* Reset source pad format width and height */ + fmt.which = sel->which; + fmt.pad = STF_ISP_PAD_SRC; + fmt.format.width = rect->width; + fmt.format.height = rect->height; + isp_set_format(sd, state, &fmt); + } + + dev_dbg(isp_dev->stfcamss->dev, "pad: %d sel(%d,%d)/%dx%d\n", + sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); + + return 0; +} + +static int isp_init_formats(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format format = { + .pad = STF_ISP_PAD_SINK, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 1920, + .height = 1080 + } + }; + + return isp_set_format(sd, sd_state, &format); +} + +static const struct v4l2_subdev_video_ops isp_video_ops = { + .s_stream = isp_set_stream, +}; + +static const struct v4l2_subdev_pad_ops isp_pad_ops = { + .init_cfg = isp_init_formats, + .enum_mbus_code = isp_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = isp_set_format, + .get_selection = isp_get_selection, + .set_selection = isp_set_selection, +}; + +static const struct v4l2_subdev_ops isp_v4l2_ops = { + .video = &isp_video_ops, + .pad = &isp_pad_ops, +}; + +static const struct media_entity_operations isp_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev) +{ + struct v4l2_subdev *sd = &isp_dev->subdev; + struct media_pad *pads = isp_dev->pads; + int ret; + + v4l2_subdev_init(sd, &isp_v4l2_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, ARRAY_SIZE(sd->name), "stf_isp"); + v4l2_set_subdevdata(sd, isp_dev); + + pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; + sd->entity.ops = &isp_media_ops; + ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads); + if (ret) { + dev_err(isp_dev->stfcamss->dev, + "Failed to init media entity: %d\n", ret); + return ret; + } + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) { + dev_err(isp_dev->stfcamss->dev, + "Failed to register subdev: %d\n", ret); + goto err_subdev_cleanup; + } + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: + media_entity_cleanup(&sd->entity); + return ret; +} + +int stf_isp_unregister(struct stf_isp_dev *isp_dev) +{ + v4l2_device_unregister_subdev(&isp_dev->subdev); + v4l2_subdev_cleanup(&isp_dev->subdev); + media_entity_cleanup(&isp_dev->subdev.entity); + + return 0; +} diff --git a/drivers/staging/media/starfive/camss/stf-isp.h b/drivers/staging/media/starfive/camss/stf-isp.h new file mode 100644 index 000000000000..955cbb048363 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-isp.h @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * stf_isp.h + * + * StarFive Camera Subsystem - ISP Module + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#ifndef STF_ISP_H +#define STF_ISP_H + +#include + +#include "stf-video.h" + +#define ISP_RAW_DATA_BITS 12 +#define SCALER_RATIO_MAX 1 +#define STF_ISP_REG_OFFSET_MAX 0x0fff +#define STF_ISP_REG_DELAY_MAX 100 + +/* isp registers */ +#define ISP_REG_CSI_INPUT_EN_AND_STATUS 0x000 +#define CSI_SCD_ERR BIT(6) +#define CSI_ITU656_ERR BIT(4) +#define CSI_ITU656_F BIT(3) +#define CSI_SCD_DONE BIT(2) +#define CSI_BUSY_S BIT(1) +#define CSI_EN_S BIT(0) + +#define ISP_REG_CSIINTS 0x008 +#define CSI_INTS(n) ((n) << 16) +#define CSI_SHA_M(n) ((n) << 0) +#define CSI_INTS_MASK GENMASK(17, 16) + +#define ISP_REG_CSI_MODULE_CFG 0x010 +#define CSI_DUMP_EN BIT(19) +#define CSI_VS_EN BIT(18) +#define CSI_SC_EN BIT(17) +#define CSI_OBA_EN BIT(16) +#define CSI_AWB_EN BIT(7) +#define CSI_LCCF_EN BIT(6) +#define CSI_OECFHM_EN BIT(5) +#define CSI_OECF_EN BIT(4) +#define CSI_LCBQ_EN BIT(3) +#define CSI_OBC_EN BIT(2) +#define CSI_DEC_EN BIT(1) +#define CSI_DC_EN BIT(0) + +#define ISP_REG_SENSOR 0x014 +#define DVP_SYNC_POL(n) ((n) << 2) +#define ITU656_EN(n) ((n) << 1) +#define IMAGER_SEL(n) ((n) << 0) + +#define ISP_REG_RAW_FORMAT_CFG 0x018 +#define SMY13(n) ((n) << 14) +#define SMY12(n) ((n) << 12) +#define SMY11(n) ((n) << 10) +#define SMY10(n) ((n) << 8) +#define SMY3(n) ((n) << 6) +#define SMY2(n) ((n) << 4) +#define SMY1(n) ((n) << 2) +#define SMY0(n) ((n) << 0) + +#define ISP_REG_PIC_CAPTURE_START_CFG 0x01c +#define VSTART_CAP(n) ((n) << 16) +#define HSTART_CAP(n) ((n) << 0) + +#define ISP_REG_PIC_CAPTURE_END_CFG 0x020 +#define VEND_CAP(n) ((n) << 16) +#define HEND_CAP(n) ((n) << 0) + +#define ISP_REG_DUMP_CFG_0 0x024 +#define ISP_REG_DUMP_CFG_1 0x028 +#define DUMP_ID(n) ((n) << 24) +#define DUMP_SHT(n) ((n) << 20) +#define DUMP_BURST_LEN(n) ((n) << 16) +#define DUMP_SD(n) ((n) << 0) +#define DUMP_BURST_LEN_MASK GENMASK(17, 16) +#define DUMP_SD_MASK GENMASK(15, 0) + +#define ISP_REG_DEC_CFG 0x030 +#define DEC_V_KEEP(n) ((n) << 24) +#define DEC_V_PERIOD(n) ((n) << 16) +#define DEC_H_KEEP(n) ((n) << 8) +#define DEC_H_PERIOD(n) ((n) << 0) + +#define ISP_REG_OBC_CFG 0x034 +#define OBC_W_H(y) ((y) << 4) +#define OBC_W_W(x) ((x) << 0) + +#define ISP_REG_DC_CFG_1 0x044 +#define DC_AXI_ID(n) ((n) << 0) + +#define ISP_REG_LCCF_CFG_0 0x050 +#define Y_DISTANCE(y) ((y) << 16) +#define X_DISTANCE(x) ((x) << 0) + +#define ISP_REG_LCCF_CFG_1 0x058 +#define LCCF_MAX_DIS(n) ((n) << 0) + +#define ISP_REG_LCBQ_CFG_0 0x074 +#define H_LCBQ(y) ((y) << 12) +#define W_LCBQ(x) ((x) << 8) + +#define ISP_REG_LCBQ_CFG_1 0x07c +#define Y_COOR(y) ((y) << 16) +#define X_COOR(x) ((x) << 0) + +#define ISP_REG_LCCF_CFG_2 0x0e0 +#define ISP_REG_LCCF_CFG_3 0x0e4 +#define ISP_REG_LCCF_CFG_4 0x0e8 +#define ISP_REG_LCCF_CFG_5 0x0ec +#define LCCF_F2_PAR(n) ((n) << 16) +#define LCCF_F1_PAR(n) ((n) << 0) + +#define ISP_REG_OECF_X0_CFG0 0x100 +#define ISP_REG_OECF_X0_CFG1 0x104 +#define ISP_REG_OECF_X0_CFG2 0x108 +#define ISP_REG_OECF_X0_CFG3 0x10c +#define ISP_REG_OECF_X0_CFG4 0x110 +#define ISP_REG_OECF_X0_CFG5 0x114 +#define ISP_REG_OECF_X0_CFG6 0x118 +#define ISP_REG_OECF_X0_CFG7 0x11c + +#define ISP_REG_OECF_Y3_CFG0 0x1e0 +#define ISP_REG_OECF_Y3_CFG1 0x1e4 +#define ISP_REG_OECF_Y3_CFG2 0x1e8 +#define ISP_REG_OECF_Y3_CFG3 0x1ec +#define ISP_REG_OECF_Y3_CFG4 0x1f0 +#define ISP_REG_OECF_Y3_CFG5 0x1f4 +#define ISP_REG_OECF_Y3_CFG6 0x1f8 +#define ISP_REG_OECF_Y3_CFG7 0x1fc + +#define ISP_REG_OECF_S0_CFG0 0x200 +#define ISP_REG_OECF_S3_CFG7 0x27c +#define OCEF_PAR_H(n) ((n) << 16) +#define OCEF_PAR_L(n) ((n) << 0) + +#define ISP_REG_AWB_X0_CFG_0 0x280 +#define ISP_REG_AWB_X0_CFG_1 0x284 +#define ISP_REG_AWB_X1_CFG_0 0x288 +#define ISP_REG_AWB_X1_CFG_1 0x28c +#define ISP_REG_AWB_X2_CFG_0 0x290 +#define ISP_REG_AWB_X2_CFG_1 0x294 +#define ISP_REG_AWB_X3_CFG_0 0x298 +#define ISP_REG_AWB_X3_CFG_1 0x29c +#define AWB_X_SYMBOL_H(n) ((n) << 16) +#define AWB_X_SYMBOL_L(n) ((n) << 0) + +#define ISP_REG_AWB_Y0_CFG_0 0x2a0 +#define ISP_REG_AWB_Y0_CFG_1 0x2a4 +#define ISP_REG_AWB_Y1_CFG_0 0x2a8 +#define ISP_REG_AWB_Y1_CFG_1 0x2ac +#define ISP_REG_AWB_Y2_CFG_0 0x2b0 +#define ISP_REG_AWB_Y2_CFG_1 0x2b4 +#define ISP_REG_AWB_Y3_CFG_0 0x2b8 +#define ISP_REG_AWB_Y3_CFG_1 0x2bc +#define AWB_Y_SYMBOL_H(n) ((n) << 16) +#define AWB_Y_SYMBOL_L(n) ((n) << 0) + +#define ISP_REG_AWB_S0_CFG_0 0x2c0 +#define ISP_REG_AWB_S0_CFG_1 0x2c4 +#define ISP_REG_AWB_S1_CFG_0 0x2c8 +#define ISP_REG_AWB_S1_CFG_1 0x2cc +#define ISP_REG_AWB_S2_CFG_0 0x2d0 +#define ISP_REG_AWB_S2_CFG_1 0x2d4 +#define ISP_REG_AWB_S3_CFG_0 0x2d8 +#define ISP_REG_AWB_S3_CFG_1 0x2dc +#define AWB_S_SYMBOL_H(n) ((n) << 16) +#define AWB_S_SYMBOL_L(n) ((n) << 0) + +#define ISP_REG_OBCG_CFG_0 0x2e0 +#define ISP_REG_OBCG_CFG_1 0x2e4 +#define ISP_REG_OBCG_CFG_2 0x2e8 +#define ISP_REG_OBCG_CFG_3 0x2ec +#define ISP_REG_OBCO_CFG_0 0x2f0 +#define ISP_REG_OBCO_CFG_1 0x2f4 +#define ISP_REG_OBCO_CFG_2 0x2f8 +#define ISP_REG_OBCO_CFG_3 0x2fc +#define GAIN_D_POINT(x) ((x) << 24) +#define GAIN_C_POINT(x) ((x) << 16) +#define GAIN_B_POINT(x) ((x) << 8) +#define GAIN_A_POINT(x) ((x) << 0) +#define OFFSET_D_POINT(x) ((x) << 24) +#define OFFSET_C_POINT(x) ((x) << 16) +#define OFFSET_B_POINT(x) ((x) << 8) +#define OFFSET_A_POINT(x) ((x) << 0) + +#define ISP_REG_ISP_CTRL_0 0xa00 +#define ISPC_LINE BIT(27) +#define ISPC_SC BIT(26) +#define ISPC_CSI BIT(25) +#define ISPC_ISP BIT(24) +#define ISPC_ENUO BIT(20) +#define ISPC_ENLS BIT(17) +#define ISPC_ENSS1 BIT(12) +#define ISPC_ENSS0 BIT(11) +#define ISPC_RST BIT(1) +#define ISPC_EN BIT(0) +#define ISPC_RST_MASK BIT(1) +#define ISPC_INT_ALL_MASK GENMASK(27, 24) + +#define ISP_REG_ISP_CTRL_1 0xa08 +#define CTRL_SAT(n) ((n) << 28) +#define CTRL_DBC BIT(22) +#define CTRL_CTC BIT(21) +#define CTRL_YHIST BIT(20) +#define CTRL_YCURVE BIT(19) +#define CTRL_CTM BIT(18) +#define CTRL_BIYUV BIT(17) +#define CTRL_SCE BIT(8) +#define CTRL_EE BIT(7) +#define CTRL_CCE BIT(5) +#define CTRL_RGE BIT(4) +#define CTRL_CME BIT(3) +#define CTRL_AE BIT(2) +#define CTRL_CE BIT(1) +#define CTRL_SAT_MASK GENMASK(31, 28) + +#define ISP_REG_PIPELINE_XY_SIZE 0xa0c +#define H_ACT_CAP(n) ((n) << 16) +#define W_ACT_CAP(n) ((n) << 0) + +#define ISP_REG_ICTC 0xa10 +#define GF_MODE(n) ((n) << 30) +#define MAXGT(n) ((n) << 16) +#define MINGT(n) ((n) << 0) + +#define ISP_REG_IDBC 0xa14 +#define BADGT(n) ((n) << 16) +#define BADXT(n) ((n) << 0) + +#define ISP_REG_ICFAM 0xa1c +#define CROSS_COV(n) ((n) << 4) +#define HV_W(n) ((n) << 0) + +#define ISP_REG_CS_GAIN 0xa30 +#define CMAD(n) ((n) << 16) +#define CMAB(n) ((n) << 0) + +#define ISP_REG_CS_THRESHOLD 0xa34 +#define CMD(n) ((n) << 16) +#define CMB(n) ((n) << 0) + +#define ISP_REG_CS_OFFSET 0xa38 +#define VOFF(n) ((n) << 16) +#define UOFF(n) ((n) << 0) + +#define ISP_REG_CS_HUE_F 0xa3c +#define SIN(n) ((n) << 16) +#define COS(n) ((n) << 0) + +#define ISP_REG_CS_SCALE 0xa40 + +#define ISP_REG_IESHD 0xa50 +#define SHAD_UP_M BIT(1) +#define SHAD_UP_EN BIT(0) + +#define ISP_REG_YADJ0 0xa54 +#define YOIR(n) ((n) << 16) +#define YIMIN(n) ((n) << 0) + +#define ISP_REG_YADJ1 0xa58 +#define YOMAX(n) ((n) << 16) +#define YOMIN(n) ((n) << 0) + +#define ISP_REG_Y_PLANE_START_ADDR 0xa80 +#define ISP_REG_UV_PLANE_START_ADDR 0xa84 +#define ISP_REG_STRIDE 0xa88 + +#define ISP_REG_ITIIWSR 0xb20 +#define ITI_HSIZE(n) ((n) << 16) +#define ITI_WSIZE(n) ((n) << 0) + +#define ISP_REG_ITIDWLSR 0xb24 +#define ISP_REG_ITIPDFR 0xb38 +#define ISP_REG_ITIDRLSR 0xb3C + +#define ISP_REG_DNYUV_YSWR0 0xc00 +#define ISP_REG_DNYUV_YSWR1 0xc04 +#define ISP_REG_DNYUV_CSWR0 0xc08 +#define ISP_REG_DNYUV_CSWR1 0xc0c +#define YUVSW5(n) ((n) << 20) +#define YUVSW4(n) ((n) << 16) +#define YUVSW3(n) ((n) << 12) +#define YUVSW2(n) ((n) << 8) +#define YUVSW1(n) ((n) << 4) +#define YUVSW0(n) ((n) << 0) + +#define ISP_REG_DNYUV_YDR0 0xc10 +#define ISP_REG_DNYUV_YDR1 0xc14 +#define ISP_REG_DNYUV_YDR2 0xc18 +#define ISP_REG_DNYUV_CDR0 0xc1c +#define ISP_REG_DNYUV_CDR1 0xc20 +#define ISP_REG_DNYUV_CDR2 0xc24 +#define CURVE_D_H(n) ((n) << 16) +#define CURVE_D_L(n) ((n) << 0) + +#define ISP_REG_ICAMD_0 0xc40 +#define ISP_REG_ICAMD_12 0xc70 +#define ISP_REG_ICAMD_20 0xc90 +#define ISP_REG_ICAMD_24 0xca0 +#define ISP_REG_ICAMD_25 0xca4 +#define DNRM_F(n) ((n) << 16) +#define CCM_M_DAT(n) ((n) << 0) + +#define ISP_REG_GAMMA_VAL0 0xe00 +#define ISP_REG_GAMMA_VAL1 0xe04 +#define ISP_REG_GAMMA_VAL2 0xe08 +#define ISP_REG_GAMMA_VAL3 0xe0c +#define ISP_REG_GAMMA_VAL4 0xe10 +#define ISP_REG_GAMMA_VAL5 0xe14 +#define ISP_REG_GAMMA_VAL6 0xe18 +#define ISP_REG_GAMMA_VAL7 0xe1c +#define ISP_REG_GAMMA_VAL8 0xe20 +#define ISP_REG_GAMMA_VAL9 0xe24 +#define ISP_REG_GAMMA_VAL10 0xe28 +#define ISP_REG_GAMMA_VAL11 0xe2c +#define ISP_REG_GAMMA_VAL12 0xe30 +#define ISP_REG_GAMMA_VAL13 0xe34 +#define ISP_REG_GAMMA_VAL14 0xe38 +#define GAMMA_S_VAL(n) ((n) << 16) +#define GAMMA_VAL(n) ((n) << 0) + +#define ISP_REG_R2Y_0 0xe40 +#define ISP_REG_R2Y_1 0xe44 +#define ISP_REG_R2Y_2 0xe48 +#define ISP_REG_R2Y_3 0xe4c +#define ISP_REG_R2Y_4 0xe50 +#define ISP_REG_R2Y_5 0xe54 +#define ISP_REG_R2Y_6 0xe58 +#define ISP_REG_R2Y_7 0xe5c +#define ISP_REG_R2Y_8 0xe60 + +#define ISP_REG_SHARPEN0 0xe80 +#define ISP_REG_SHARPEN1 0xe84 +#define ISP_REG_SHARPEN2 0xe88 +#define ISP_REG_SHARPEN3 0xe8c +#define ISP_REG_SHARPEN4 0xe90 +#define ISP_REG_SHARPEN5 0xe94 +#define ISP_REG_SHARPEN6 0xe98 +#define ISP_REG_SHARPEN7 0xe9c +#define ISP_REG_SHARPEN8 0xea0 +#define ISP_REG_SHARPEN9 0xea4 +#define ISP_REG_SHARPEN10 0xea8 +#define ISP_REG_SHARPEN11 0xeac +#define ISP_REG_SHARPEN12 0xeb0 +#define ISP_REG_SHARPEN13 0xeb4 +#define ISP_REG_SHARPEN14 0xeb8 +#define S_DELTA(n) ((n) << 16) +#define S_WEIGHT(n) ((n) << 8) + +#define ISP_REG_SHARPEN_FS0 0xebc +#define ISP_REG_SHARPEN_FS1 0xec0 +#define ISP_REG_SHARPEN_FS2 0xec4 +#define ISP_REG_SHARPEN_FS3 0xec8 +#define ISP_REG_SHARPEN_FS4 0xecc +#define ISP_REG_SHARPEN_FS5 0xed0 +#define S_FACTOR(n) ((n) << 24) +#define S_SLOPE(n) ((n) << 0) + +#define ISP_REG_SHARPEN_WN 0xed4 +#define PDIRF(n) ((n) << 28) +#define NDIRF(n) ((n) << 24) +#define WSUM(n) ((n) << 0) + +#define ISP_REG_IUVS1 0xed8 +#define UVDIFF2(n) ((n) << 16) +#define UVDIFF1(n) ((n) << 0) + +#define ISP_REG_IUVS2 0xedc +#define UVF(n) ((n) << 24) +#define UVSLOPE(n) ((n) << 0) + +#define ISP_REG_IUVCKS1 0xee0 +#define UVCKDIFF2(n) ((n) << 16) +#define UVCKDIFF1(n) ((n) << 0) + +#define ISP_REG_IUVCKS2 0xee4 + +#define ISP_REG_ISHRPET 0xee8 +#define TH(n) ((n) << 8) +#define EN(n) ((n) << 0) + +#define ISP_REG_YCURVE_0 0xf00 +#define ISP_REG_YCURVE_63 0xffc + +#define IMAGE_MAX_WIDTH 1920 +#define IMAGE_MAX_HEIGH 1080 + +/* pad id for media framework */ +enum stf_isp_pad_id { + STF_ISP_PAD_SINK = 0, + STF_ISP_PAD_SRC, + STF_ISP_PAD_MAX +}; + +struct stf_isp_format { + u32 code; + u8 bpp; +}; + +struct stf_isp_format_table { + const struct stf_isp_format *fmts; + int nfmts; +}; + +struct stf_isp_dev { + struct stfcamss *stfcamss; + struct v4l2_subdev subdev; + struct media_pad pads[STF_ISP_PAD_MAX]; + const struct stf_isp_format_table *formats; + unsigned int nformats; + struct v4l2_subdev *source_subdev; + const struct stf_isp_format *current_fmt; +}; + +int stf_isp_reset(struct stf_isp_dev *isp_dev); +void stf_isp_init_cfg(struct stf_isp_dev *isp_dev); +void stf_isp_settings(struct stf_isp_dev *isp_dev, + struct v4l2_rect *crop, u32 mcode); +void stf_isp_stream_set(struct stf_isp_dev *isp_dev); +int stf_isp_init(struct stfcamss *stfcamss); +int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev); +int stf_isp_unregister(struct stf_isp_dev *isp_dev); + +#endif /* STF_ISP_H */ From e080f339c80aedb13ecb5de1e9bdcafdb4bb6652 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:19 +0800 Subject: [PATCH 0714/7721] media: staging: media: starfive: camss: Add capture driver Add capture driver for StarFive Camera Subsystem. It contains two video devices: capture_yuv and capture_raw. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/Makefile | 1 + .../staging/media/starfive/camss/stf-camss.h | 2 + .../media/starfive/camss/stf-capture.c | 603 ++++++++++++++++++ .../media/starfive/camss/stf-capture.h | 86 +++ 4 files changed, 692 insertions(+) create mode 100644 drivers/staging/media/starfive/camss/stf-capture.c create mode 100644 drivers/staging/media/starfive/camss/stf-capture.h diff --git a/drivers/staging/media/starfive/camss/Makefile b/drivers/staging/media/starfive/camss/Makefile index 97e1522b21ae..005790202e7b 100644 --- a/drivers/staging/media/starfive/camss/Makefile +++ b/drivers/staging/media/starfive/camss/Makefile @@ -5,6 +5,7 @@ starfive-camss-objs += \ stf-camss.o \ + stf-capture.o \ stf-isp.o \ stf-isp-hw-ops.o \ stf-video.o diff --git a/drivers/staging/media/starfive/camss/stf-camss.h b/drivers/staging/media/starfive/camss/stf-camss.h index c7b0a34cd29b..e2b0cfb437bd 100644 --- a/drivers/staging/media/starfive/camss/stf-camss.h +++ b/drivers/staging/media/starfive/camss/stf-camss.h @@ -19,6 +19,7 @@ #include #include "stf-isp.h" +#include "stf-capture.h" enum stf_port_num { STF_PORT_DVP = 0, @@ -52,6 +53,7 @@ struct stfcamss { struct media_pipeline pipe; struct device *dev; struct stf_isp_dev isp_dev; + struct stf_capture captures[STF_CAPTURE_NUM]; struct v4l2_async_notifier notifier; void __iomem *syscon_base; void __iomem *isp_base; diff --git a/drivers/staging/media/starfive/camss/stf-capture.c b/drivers/staging/media/starfive/camss/stf-capture.c new file mode 100644 index 000000000000..70c24b050a1b --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-capture.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * stf_capture.c + * + * StarFive Camera Subsystem - capture device + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#include "stf-camss.h" + +static const char * const stf_cap_names[] = { + "capture_raw", + "capture_yuv", +}; + +static const struct stfcamss_format_info stf_wr_fmts[] = { + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .planes = 1, + .vsub = { 1 }, + .bpp = 10, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .planes = 1, + .vsub = { 1 }, + .bpp = 10, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .planes = 1, + .vsub = { 1 }, + .bpp = 10, + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .planes = 1, + .vsub = { 1 }, + .bpp = 10, + }, +}; + +static const struct stfcamss_format_info stf_isp_fmts[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_1_5X8, + .pixelformat = V4L2_PIX_FMT_NV12, + .planes = 2, + .vsub = { 1, 2 }, + .bpp = 8, + }, +}; + +static inline struct stf_capture *to_stf_capture(struct stfcamss_video *video) +{ + return container_of(video, struct stf_capture, video); +} + +static void stf_set_raw_addr(struct stfcamss *stfcamss, dma_addr_t addr) +{ + stf_syscon_reg_write(stfcamss, VIN_START_ADDR_O, (long)addr); + stf_syscon_reg_write(stfcamss, VIN_START_ADDR_N, (long)addr); +} + +static void stf_set_yuv_addr(struct stfcamss *stfcamss, + dma_addr_t y_addr, dma_addr_t uv_addr) +{ + stf_isp_reg_write(stfcamss, ISP_REG_Y_PLANE_START_ADDR, y_addr); + stf_isp_reg_write(stfcamss, ISP_REG_UV_PLANE_START_ADDR, uv_addr); +} + +static void stf_init_addrs(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *output = &cap->buffers; + dma_addr_t addr0, addr1; + + output->active_buf = 0; + + if (!output->buf[0]) + return; + + addr0 = output->buf[0]->addr[0]; + addr1 = output->buf[0]->addr[1]; + + if (cap->type == STF_CAPTURE_RAW) + stf_set_raw_addr(video->stfcamss, addr0); + else if (cap->type == STF_CAPTURE_YUV) + stf_set_yuv_addr(video->stfcamss, addr0, addr1); +} + +static struct stfcamss_buffer *stf_buf_get_pending(struct stf_v_buf *output) +{ + struct stfcamss_buffer *buffer = NULL; + + if (!list_empty(&output->pending_bufs)) { + buffer = list_first_entry(&output->pending_bufs, + struct stfcamss_buffer, + queue); + list_del(&buffer->queue); + } + + return buffer; +} + +static void stf_cap_s_cfg(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *output = &cap->buffers; + unsigned long flags; + + spin_lock_irqsave(&output->lock, flags); + + output->state = STF_OUTPUT_IDLE; + output->buf[0] = stf_buf_get_pending(output); + + if (!output->buf[0] && output->buf[1]) { + output->buf[0] = output->buf[1]; + output->buf[1] = NULL; + } + + if (output->buf[0]) + output->state = STF_OUTPUT_SINGLE; + + output->sequence = 0; + stf_init_addrs(video); + + spin_unlock_irqrestore(&output->lock, flags); +} + +static int stf_cap_s_cleanup(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *output = &cap->buffers; + unsigned long flags; + + spin_lock_irqsave(&output->lock, flags); + + output->state = STF_OUTPUT_OFF; + + spin_unlock_irqrestore(&output->lock, flags); + + return 0; +} + +static void stf_wr_data_en(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stfcamss *stfcamss = cap->video.stfcamss; + + stf_syscon_reg_set_bit(stfcamss, VIN_CHANNEL_SEL_EN, U0_VIN_AXIWR0_EN); +} + +static void stf_wr_irq_enable(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stfcamss *stfcamss = cap->video.stfcamss; + + stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_M); +} + +static void stf_wr_irq_disable(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stfcamss *stfcamss = cap->video.stfcamss; + + stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN); + stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN); + stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_M); +} + +static void stf_channel_set(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stfcamss *stfcamss = cap->video.stfcamss; + u32 val; + + if (cap->type == STF_CAPTURE_RAW) { + val = stf_syscon_reg_read(stfcamss, VIN_CHANNEL_SEL_EN); + val &= ~U0_VIN_CHANNEL_SEL_MASK; + val |= CHANNEL(0); + stf_syscon_reg_write(stfcamss, VIN_CHANNEL_SEL_EN, val); + + val = stf_syscon_reg_read(stfcamss, VIN_INRT_PIX_CFG); + val &= ~U0_VIN_PIX_CT_MASK; + val |= PIX_CT(1); + + val &= ~U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS; + val |= PIXEL_HEIGH_BIT_SEL(0); + + val &= ~U0_VIN_PIX_CNT_END_MASK; + val |= PIX_CNT_END(IMAGE_MAX_WIDTH / 4 - 1); + + stf_syscon_reg_write(stfcamss, VIN_INRT_PIX_CFG, val); + } else if (cap->type == STF_CAPTURE_YUV) { + val = stf_syscon_reg_read(stfcamss, VIN_CFG_REG); + val &= ~U0_VIN_MIPI_BYTE_EN_ISP0_MASK; + val |= U0_VIN_MIPI_BYTE_EN_ISP0(0); + + val &= ~U0_VIN_MIPI_CHANNEL_SEL0_MASK; + val |= U0_VIN_MIPI_CHANNEL_SEL0(0); + + val &= ~U0_VIN_PIX_NUM_MASK; + val |= U0_VIN_PIX_NUM(0); + + val &= ~U0_VIN_P_I_MIPI_HAEDER_EN0_MASK; + val |= U0_VIN_P_I_MIPI_HAEDER_EN0(1); + + stf_syscon_reg_write(stfcamss, VIN_CFG_REG, val); + } +} + +static void stf_capture_start(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + + stf_channel_set(video); + if (cap->type == STF_CAPTURE_RAW) { + stf_wr_irq_enable(video); + stf_wr_data_en(video); + } + + stf_cap_s_cfg(video); +} + +static void stf_capture_stop(struct stfcamss_video *video) +{ + struct stf_capture *cap = to_stf_capture(video); + + if (cap->type == STF_CAPTURE_RAW) + stf_wr_irq_disable(video); + + stf_cap_s_cleanup(video); +} + +static void stf_capture_init(struct stfcamss *stfcamss, struct stf_capture *cap) +{ + cap->buffers.state = STF_OUTPUT_OFF; + cap->buffers.buf[0] = NULL; + cap->buffers.buf[1] = NULL; + cap->buffers.active_buf = 0; + atomic_set(&cap->buffers.frame_skip, 4); + INIT_LIST_HEAD(&cap->buffers.pending_bufs); + INIT_LIST_HEAD(&cap->buffers.ready_bufs); + spin_lock_init(&cap->buffers.lock); + + cap->video.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cap->video.stfcamss = stfcamss; + cap->video.bpl_alignment = 16 * 8; + + if (cap->type == STF_CAPTURE_RAW) { + cap->video.formats = stf_wr_fmts; + cap->video.nformats = ARRAY_SIZE(stf_wr_fmts); + cap->video.bpl_alignment = 8; + } else if (cap->type == STF_CAPTURE_YUV) { + cap->video.formats = stf_isp_fmts; + cap->video.nformats = ARRAY_SIZE(stf_isp_fmts); + cap->video.bpl_alignment = 1; + } +} + +static void stf_buf_add_ready(struct stf_v_buf *output, + struct stfcamss_buffer *buffer) +{ + INIT_LIST_HEAD(&buffer->queue); + list_add_tail(&buffer->queue, &output->ready_bufs); +} + +static struct stfcamss_buffer *stf_buf_get_ready(struct stf_v_buf *output) +{ + struct stfcamss_buffer *buffer = NULL; + + if (!list_empty(&output->ready_bufs)) { + buffer = list_first_entry(&output->ready_bufs, + struct stfcamss_buffer, + queue); + list_del(&buffer->queue); + } + + return buffer; +} + +static void stf_buf_add_pending(struct stf_v_buf *output, + struct stfcamss_buffer *buffer) +{ + INIT_LIST_HEAD(&buffer->queue); + list_add_tail(&buffer->queue, &output->pending_bufs); +} + +static void stf_buf_update_on_last(struct stf_v_buf *output) +{ + switch (output->state) { + case STF_OUTPUT_CONTINUOUS: + output->state = STF_OUTPUT_SINGLE; + output->active_buf = !output->active_buf; + break; + case STF_OUTPUT_SINGLE: + output->state = STF_OUTPUT_STOPPING; + break; + default: + break; + } +} + +static void stf_buf_update_on_next(struct stf_v_buf *output) +{ + switch (output->state) { + case STF_OUTPUT_CONTINUOUS: + output->active_buf = !output->active_buf; + break; + case STF_OUTPUT_SINGLE: + default: + break; + } +} + +static void stf_buf_update_on_new(struct stfcamss_video *video, + struct stfcamss_buffer *new_buf) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *output = &cap->buffers; + + switch (output->state) { + case STF_OUTPUT_SINGLE: + stf_buf_add_pending(output, new_buf); + break; + case STF_OUTPUT_IDLE: + if (!output->buf[0]) { + output->buf[0] = new_buf; + stf_init_addrs(video); + output->state = STF_OUTPUT_SINGLE; + } else { + stf_buf_add_pending(output, new_buf); + } + break; + case STF_OUTPUT_STOPPING: + if (output->last_buffer) { + output->buf[output->active_buf] = output->last_buffer; + output->last_buffer = NULL; + } + + output->state = STF_OUTPUT_SINGLE; + stf_buf_add_pending(output, new_buf); + break; + case STF_OUTPUT_CONTINUOUS: + default: + stf_buf_add_pending(output, new_buf); + break; + } +} + +static void stf_buf_flush(struct stf_v_buf *output, enum vb2_buffer_state state) +{ + struct stfcamss_buffer *buf; + struct stfcamss_buffer *t; + + list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->queue); + } + list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->queue); + } +} + +static void stf_buf_done(struct stf_v_buf *output) +{ + struct stfcamss_buffer *ready_buf; + u64 ts = ktime_get_ns(); + unsigned long flags; + + if (output->state == STF_OUTPUT_OFF || + output->state == STF_OUTPUT_RESERVED) + return; + + spin_lock_irqsave(&output->lock, flags); + + while ((ready_buf = stf_buf_get_ready(output))) { + ready_buf->vb.vb2_buf.timestamp = ts; + ready_buf->vb.sequence = output->sequence++; + + vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } + + spin_unlock_irqrestore(&output->lock, flags); +} + +static void stf_change_buffer(struct stf_v_buf *output) +{ + struct stf_capture *cap = container_of(output, struct stf_capture, + buffers); + struct stfcamss *stfcamss = cap->video.stfcamss; + struct stfcamss_buffer *ready_buf; + dma_addr_t *new_addr; + unsigned long flags; + u32 active_index; + + if (output->state == STF_OUTPUT_OFF || + output->state == STF_OUTPUT_STOPPING || + output->state == STF_OUTPUT_RESERVED || + output->state == STF_OUTPUT_IDLE) + return; + + spin_lock_irqsave(&output->lock, flags); + + active_index = output->active_buf; + + ready_buf = output->buf[active_index]; + if (!ready_buf) { + dev_dbg(stfcamss->dev, "missing ready buf %d %d.\n", + active_index, output->state); + active_index = !active_index; + ready_buf = output->buf[active_index]; + if (!ready_buf) { + dev_dbg(stfcamss->dev, + "missing ready buf2 %d %d.\n", + active_index, output->state); + goto out_unlock; + } + } + + /* Get next buffer */ + output->buf[active_index] = stf_buf_get_pending(output); + if (!output->buf[active_index]) { + new_addr = ready_buf->addr; + stf_buf_update_on_last(output); + } else { + new_addr = output->buf[active_index]->addr; + stf_buf_update_on_next(output); + } + + if (output->state == STF_OUTPUT_STOPPING) { + output->last_buffer = ready_buf; + } else { + if (cap->type == STF_CAPTURE_RAW) + stf_set_raw_addr(stfcamss, new_addr[0]); + else if (cap->type == STF_CAPTURE_YUV) + stf_set_yuv_addr(stfcamss, new_addr[0], new_addr[1]); + + stf_buf_add_ready(output, ready_buf); + } + +out_unlock: + spin_unlock_irqrestore(&output->lock, flags); +} + +irqreturn_t stf_wr_irq_handler(int irq, void *priv) +{ + struct stfcamss *stfcamss = priv; + struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_RAW]; + + if (atomic_dec_if_positive(&cap->buffers.frame_skip) < 0) { + stf_change_buffer(&cap->buffers); + stf_buf_done(&cap->buffers); + } + + stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN); + stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN); + + return IRQ_HANDLED; +} + +irqreturn_t stf_isp_irq_handler(int irq, void *priv) +{ + struct stfcamss *stfcamss = priv; + struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_YUV]; + u32 status; + + status = stf_isp_reg_read(stfcamss, ISP_REG_ISP_CTRL_0); + if (status & ISPC_ISP) { + if (status & ISPC_ENUO) + stf_buf_done(&cap->buffers); + + stf_isp_reg_write(stfcamss, ISP_REG_ISP_CTRL_0, + (status & ~ISPC_INT_ALL_MASK) | + ISPC_ISP | ISPC_CSI | ISPC_SC); + } + + return IRQ_HANDLED; +} + +irqreturn_t stf_line_irq_handler(int irq, void *priv) +{ + struct stfcamss *stfcamss = priv; + struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_YUV]; + u32 status; + + status = stf_isp_reg_read(stfcamss, ISP_REG_ISP_CTRL_0); + if (status & ISPC_LINE) { + if (atomic_dec_if_positive(&cap->buffers.frame_skip) < 0) { + if ((status & ISPC_ENUO)) + stf_change_buffer(&cap->buffers); + } + + stf_isp_reg_set_bit(stfcamss, ISP_REG_CSIINTS, + CSI_INTS_MASK, CSI_INTS(0x3)); + stf_isp_reg_set_bit(stfcamss, ISP_REG_IESHD, + SHAD_UP_M | SHAD_UP_EN, 0x3); + + stf_isp_reg_write(stfcamss, ISP_REG_ISP_CTRL_0, + (status & ~ISPC_INT_ALL_MASK) | ISPC_LINE); + } + + return IRQ_HANDLED; +} + +static int stf_queue_buffer(struct stfcamss_video *video, + struct stfcamss_buffer *buf) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *v_bufs = &cap->buffers; + unsigned long flags; + + spin_lock_irqsave(&v_bufs->lock, flags); + stf_buf_update_on_new(video, buf); + spin_unlock_irqrestore(&v_bufs->lock, flags); + + return 0; +} + +static int stf_flush_buffers(struct stfcamss_video *video, + enum vb2_buffer_state state) +{ + struct stf_capture *cap = to_stf_capture(video); + struct stf_v_buf *v_bufs = &cap->buffers; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&v_bufs->lock, flags); + + stf_buf_flush(v_bufs, state); + + for (i = 0; i < ARRAY_SIZE(v_bufs->buf); i++) { + if (v_bufs->buf[i]) + vb2_buffer_done(&v_bufs->buf[i]->vb.vb2_buf, state); + + v_bufs->buf[i] = NULL; + } + + if (v_bufs->last_buffer) { + vb2_buffer_done(&v_bufs->last_buffer->vb.vb2_buf, state); + v_bufs->last_buffer = NULL; + } + + spin_unlock_irqrestore(&v_bufs->lock, flags); + return 0; +} + +static const struct stfcamss_video_ops stf_capture_ops = { + .queue_buffer = stf_queue_buffer, + .flush_buffers = stf_flush_buffers, + .start_streaming = stf_capture_start, + .stop_streaming = stf_capture_stop, +}; + +static void stf_capture_unregister_one(struct stf_capture *cap) +{ + if (!video_is_registered(&cap->video.vdev)) + return; + + media_entity_cleanup(&cap->video.vdev.entity); + vb2_video_unregister_device(&cap->video.vdev); +} + +void stf_capture_unregister(struct stfcamss *stfcamss) +{ + struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW]; + struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV]; + + stf_capture_unregister_one(cap_raw); + stf_capture_unregister_one(cap_yuv); +} + +int stf_capture_register(struct stfcamss *stfcamss, + struct v4l2_device *v4l2_dev) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(stfcamss->captures); i++) { + struct stf_capture *capture = &stfcamss->captures[i]; + + capture->type = i; + capture->video.ops = &stf_capture_ops; + stf_capture_init(stfcamss, capture); + + ret = stf_video_register(&capture->video, v4l2_dev, + stf_cap_names[i]); + if (ret < 0) { + dev_err(stfcamss->dev, + "Failed to register video node: %d\n", ret); + stf_capture_unregister(stfcamss); + return ret; + } + } + + return 0; +} diff --git a/drivers/staging/media/starfive/camss/stf-capture.h b/drivers/staging/media/starfive/camss/stf-capture.h new file mode 100644 index 000000000000..2f9740b7e500 --- /dev/null +++ b/drivers/staging/media/starfive/camss/stf-capture.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * stf_capture.h + * + * Starfive Camera Subsystem driver + * + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. + */ + +#ifndef STF_CAPTURE_H +#define STF_CAPTURE_H + +#include "stf-video.h" + +#define VIN_CHANNEL_SEL_EN 0x14 +#define VIN_START_ADDR_N 0x18 +#define VIN_INRT_PIX_CFG 0x1c +#define VIN_START_ADDR_O 0x20 +#define VIN_CFG_REG 0x24 + +#define U0_VIN_CNFG_AXI_DVP_EN BIT(2) + +#define U0_VIN_CHANNEL_SEL_MASK GENMASK(3, 0) +#define U0_VIN_AXIWR0_EN BIT(4) +#define CHANNEL(x) ((x) << 0) + +#define U0_VIN_INTR_CLEAN BIT(0) +#define U0_VIN_INTR_M BIT(1) +#define U0_VIN_PIX_CNT_END_MASK GENMASK(12, 2) +#define U0_VIN_PIX_CT_MASK GENMASK(14, 13) +#define U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS GENMASK(16, 15) + +#define PIX_CNT_END(x) ((x) << 2) +#define PIX_CT(x) ((x) << 13) +#define PIXEL_HEIGH_BIT_SEL(x) ((x) << 15) + +#define U0_VIN_CNFG_DVP_HS_POS BIT(1) +#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2) +#define U0_VIN_CNFG_DVP_VS_POS BIT(3) +#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4) +#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5) +#define U0_VIN_MIPI_BYTE_EN_ISP0(n) ((n) << 6) +#define U0_VIN_MIPI_CHANNEL_SEL0(n) ((n) << 8) +#define U0_VIN_P_I_MIPI_HAEDER_EN0(n) ((n) << 12) +#define U0_VIN_PIX_NUM(n) ((n) << 13) +#define U0_VIN_MIPI_BYTE_EN_ISP0_MASK GENMASK(7, 6) +#define U0_VIN_MIPI_CHANNEL_SEL0_MASK GENMASK(11, 8) +#define U0_VIN_P_I_MIPI_HAEDER_EN0_MASK BIT(12) +#define U0_VIN_PIX_NUM_MASK GENMASK(16, 13) + +enum stf_v_state { + STF_OUTPUT_OFF, + STF_OUTPUT_RESERVED, + STF_OUTPUT_SINGLE, + STF_OUTPUT_CONTINUOUS, + STF_OUTPUT_IDLE, + STF_OUTPUT_STOPPING +}; + +struct stf_v_buf { + int active_buf; + struct stfcamss_buffer *buf[2]; + struct stfcamss_buffer *last_buffer; + struct list_head pending_bufs; + struct list_head ready_bufs; + enum stf_v_state state; + unsigned int sequence; + /* protects the above member variables */ + spinlock_t lock; + atomic_t frame_skip; +}; + +struct stf_capture { + struct stfcamss_video video; + struct stf_v_buf buffers; + enum stf_capture_type type; +}; + +irqreturn_t stf_wr_irq_handler(int irq, void *priv); +irqreturn_t stf_isp_irq_handler(int irq, void *priv); +irqreturn_t stf_line_irq_handler(int irq, void *priv); +int stf_capture_register(struct stfcamss *stfcamss, + struct v4l2_device *v4l2_dev); +void stf_capture_unregister(struct stfcamss *stfcamss); + +#endif From 1ee1b01b97cd7da9eefba156d33db6ccf10110bb Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:20 +0800 Subject: [PATCH 0715/7721] media: staging: media: starfive: camss: Add interrupt handling Parse interrupt resources and register interrupt handlers. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- .../staging/media/starfive/camss/stf-camss.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/staging/media/starfive/camss/stf-camss.c b/drivers/staging/media/starfive/camss/stf-camss.c index c9743ff23b81..7174a07732f2 100644 --- a/drivers/staging/media/starfive/camss/stf-camss.c +++ b/drivers/staging/media/starfive/camss/stf-camss.c @@ -35,6 +35,12 @@ static const char * const stfcamss_resets[] = { "isp_top_axi", }; +static const struct stf_isr_data stf_isrs[] = { + {"wr_irq", stf_wr_irq_handler}, + {"isp_irq", stf_isp_irq_handler}, + {"line_irq", stf_line_irq_handler}, +}; + static int stfcamss_get_mem_res(struct stfcamss *stfcamss) { struct platform_device *pdev = to_platform_device(stfcamss->dev); @@ -160,6 +166,21 @@ static int stfcamss_probe(struct platform_device *pdev) stfcamss->dev = dev; + for (i = 0; i < ARRAY_SIZE(stf_isrs); ++i) { + int irq; + + irq = platform_get_irq(pdev, i); + if (irq < 0) + return irq; + + ret = devm_request_irq(stfcamss->dev, irq, stf_isrs[i].isr, 0, + stf_isrs[i].name, stfcamss); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } + } + stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk); for (i = 0; i < stfcamss->nclks; ++i) stfcamss->sys_clk[i].id = stfcamss_clocks[i]; From ac7da4a73b104589f9fbce0514ff5f84cda99d67 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:21 +0800 Subject: [PATCH 0716/7721] media: staging: media: starfive: camss: Register devices Register ISP sub-device and video devices for StarFive Camera Subsystem. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- .../staging/media/starfive/camss/stf-camss.c | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/starfive/camss/stf-camss.c b/drivers/staging/media/starfive/camss/stf-camss.c index 7174a07732f2..a587f860101a 100644 --- a/drivers/staging/media/starfive/camss/stf-camss.c +++ b/drivers/staging/media/starfive/camss/stf-camss.c @@ -123,6 +123,85 @@ static int stfcamss_of_parse_ports(struct stfcamss *stfcamss) return ret; } +static int stfcamss_register_devs(struct stfcamss *stfcamss) +{ + struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV]; + struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; + int ret; + + ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev); + if (ret < 0) { + dev_err(stfcamss->dev, + "failed to register stf isp%d entity: %d\n", 0, ret); + return ret; + } + + ret = stf_capture_register(stfcamss, &stfcamss->v4l2_dev); + if (ret < 0) { + dev_err(stfcamss->dev, + "failed to register capture: %d\n", ret); + goto err_isp_unregister; + } + + ret = media_create_pad_link(&isp_dev->subdev.entity, STF_ISP_PAD_SRC, + &cap_yuv->video.vdev.entity, 0, 0); + if (ret) + goto err_cap_unregister; + + cap_yuv->video.source_subdev = &isp_dev->subdev; + + return ret; + +err_cap_unregister: + stf_capture_unregister(stfcamss); +err_isp_unregister: + stf_isp_unregister(&stfcamss->isp_dev); + + return ret; +} + +static void stfcamss_unregister_devs(struct stfcamss *stfcamss) +{ + stf_isp_unregister(&stfcamss->isp_dev); + stf_capture_unregister(stfcamss); +} + +static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct stfcamss *stfcamss = + container_of(async, struct stfcamss, notifier); + struct stfcamss_async_subdev *csd = + container_of(asc, struct stfcamss_async_subdev, asd); + enum stf_port_num port = csd->port; + struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; + struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW]; + struct media_pad *pad; + int ret; + + if (port == STF_PORT_CSI2RX) { + pad = &isp_dev->pads[STF_ISP_PAD_SINK]; + } else { + dev_err(stfcamss->dev, "not support port %d\n", port); + return -EPERM; + } + + ret = v4l2_create_fwnode_links_to_pad(subdev, pad, 0); + if (ret) + return ret; + + ret = media_create_pad_link(&subdev->entity, 1, + &cap_raw->video.vdev.entity, 0, 0); + if (ret) + return ret; + + isp_dev->source_subdev = subdev; + cap_raw->video.source_subdev = subdev; + + return 0; +} + static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf) { struct stfcamss *stfcamss = @@ -133,6 +212,7 @@ static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf) static const struct v4l2_async_notifier_operations stfcamss_subdev_notifier_ops = { + .bound = stfcamss_subdev_notifier_bound, .complete = stfcamss_subdev_notifier_complete, }; @@ -217,6 +297,12 @@ static int stfcamss_probe(struct platform_device *pdev) goto err_cleanup_notifier; } + ret = stf_isp_init(stfcamss); + if (ret < 0) { + dev_err(dev, "Failed to init isp: %d\n", ret); + goto err_cleanup_notifier; + } + stfcamss_mc_init(pdev, stfcamss); ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev); @@ -231,6 +317,12 @@ static int stfcamss_probe(struct platform_device *pdev) goto err_unregister_device; } + ret = stfcamss_register_devs(stfcamss); + if (ret < 0) { + dev_err(dev, "Failed to register subdevice: %d\n", ret); + goto err_unregister_media_dev; + } + pm_runtime_enable(dev); stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops; @@ -239,11 +331,13 @@ static int stfcamss_probe(struct platform_device *pdev) dev_err(dev, "Failed to register async subdev nodes: %d\n", ret); pm_runtime_disable(dev); - goto err_unregister_media_dev; + goto err_unregister_subdevs; } return 0; +err_unregister_subdevs: + stfcamss_unregister_devs(stfcamss); err_unregister_media_dev: media_device_unregister(&stfcamss->media_dev); err_unregister_device: @@ -265,6 +359,7 @@ static int stfcamss_remove(struct platform_device *pdev) { struct stfcamss *stfcamss = platform_get_drvdata(pdev); + stfcamss_unregister_devs(stfcamss); v4l2_device_unregister(&stfcamss->v4l2_dev); media_device_cleanup(&stfcamss->media_dev); v4l2_async_nf_cleanup(&stfcamss->notifier); From 7ad7d7fb3e69d8d58ffa173bfa6dc74d0a392175 Mon Sep 17 00:00:00 2001 From: Jack Zhu Date: Wed, 25 Oct 2023 11:14:22 +0800 Subject: [PATCH 0717/7721] media: staging: media: starfive: camss: Add TODO file Add a TODO.txt file to explain what needs to be done to get them out of staging. Signed-off-by: Jack Zhu Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/TODO.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 drivers/staging/media/starfive/camss/TODO.txt diff --git a/drivers/staging/media/starfive/camss/TODO.txt b/drivers/staging/media/starfive/camss/TODO.txt new file mode 100644 index 000000000000..7d459f4f09d0 --- /dev/null +++ b/drivers/staging/media/starfive/camss/TODO.txt @@ -0,0 +1,4 @@ +Unstaging requirements: +- Add userspace support which demonstrates the ability to receive statistics and + adapt hardware modules configuration accordingly; +- Add documentation for description of the statistics data structures; From 3185d57cfcd34fadbe28f4ed57a6cb5122277ece Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 14 Nov 2023 11:42:02 +0100 Subject: [PATCH 0718/7721] indirect_call_wrapper: Fix typo in INDIRECT_CALL_$NR kerneldoc Fix a small typo in the kerneldoc comment of the INDIRECT_CALL_$NR macro. Signed-off-by: Tobias Klauser Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231114104202.4680-1-tklauser@distanz.ch Signed-off-by: Paolo Abeni --- include/linux/indirect_call_wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/indirect_call_wrapper.h b/include/linux/indirect_call_wrapper.h index c1c76a70a6ce..adb83a42a6b9 100644 --- a/include/linux/indirect_call_wrapper.h +++ b/include/linux/indirect_call_wrapper.h @@ -11,7 +11,7 @@ * @__VA_ARGS__: arguments for @f * * Avoid retpoline overhead for known builtin, checking @f vs each of them and - * eventually invoking directly the builtin function. The functions are check + * eventually invoking directly the builtin function. The functions are checked * in the given order. Fallback to the indirect call. */ #define INDIRECT_CALL_1(f, f1, ...) \ From 864acca58000d9cd4cf810ddfca2815be045c748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 4 Nov 2023 00:00:02 +0100 Subject: [PATCH 0719/7721] bus: fsl-mc: Drop if block with always false condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mc that belongs to a pdev is always a root dprc. In fsl_mc_bus_probe() the mc device gets assigned the platform device as parent. As dev_is_fsl_mc() is false for a platform device, fsl_mc_get_root_dprc() will always be true and so the if body is never run and it can be dropped. The motivation for this change is to get rid of an error path in .remove() that is broken (because only a part of the necessary cleanup is done resulting in leaks and/or use-after-frees and the driver core ignores the return value of .remove().) Link: https://lore.kernel.org/r/20231103230001.3652259-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/fsl-mc/fsl-mc-bus.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 2f6d5002e43d..75a8d365ffd4 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1172,9 +1172,6 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) struct fsl_mc *mc = platform_get_drvdata(pdev); struct fsl_mc_io *mc_io; - if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev)) - return -EINVAL; - mc_io = mc->root_mc_bus_dev->mc_io; fsl_mc_device_remove(mc->root_mc_bus_dev); fsl_destroy_mc_io(mc_io); From a8759bd4c4fa1355a59160777e56efb3e9db966f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 4 Nov 2023 00:00:03 +0100 Subject: [PATCH 0720/7721] bus: fsl-mc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. As fsl_mc_bus_remove() has the same type now as fsl_mc_bus_shutdown() and the only thing the latter does is to call the former, use fsl_mc_bus_remove() directly as .shutdown() callback. Link: https://lore.kernel.org/r/20231103230001.3652259-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/fsl-mc/fsl-mc-bus.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 75a8d365ffd4..78b96cd63de9 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1167,7 +1167,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) * fsl_mc_bus_remove - callback invoked when the root MC bus is being * removed */ -static int fsl_mc_bus_remove(struct platform_device *pdev) +static void fsl_mc_bus_remove(struct platform_device *pdev) { struct fsl_mc *mc = platform_get_drvdata(pdev); struct fsl_mc_io *mc_io; @@ -1187,13 +1187,6 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) (GCR1_P1_STOP | GCR1_P2_STOP), mc->fsl_mc_regs + FSL_MC_GCR1); } - - return 0; -} - -static void fsl_mc_bus_shutdown(struct platform_device *pdev) -{ - fsl_mc_bus_remove(pdev); } static const struct of_device_id fsl_mc_bus_match_table[] = { @@ -1217,8 +1210,8 @@ static struct platform_driver fsl_mc_bus_driver = { .acpi_match_table = fsl_mc_bus_acpi_match_table, }, .probe = fsl_mc_bus_probe, - .remove = fsl_mc_bus_remove, - .shutdown = fsl_mc_bus_shutdown, + .remove_new = fsl_mc_bus_remove, + .shutdown = fsl_mc_bus_remove, }; static int fsl_mc_bus_notifier(struct notifier_block *nb, From 459956b17dd5cba06b0f2b75772497e46a59468b Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Thu, 16 Nov 2023 11:03:57 +0530 Subject: [PATCH 0721/7721] ASoC: amd: acp: add missing SND_SOC_AMD_ACP_LEGACY_COMMON flag for ACP70 add missing dependent SND_SOC_AMD_ACP_LEGACY_COMMON flag for ACP70 platform. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20231116053405.2574081-1-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index c8ac0027f741..84c963241dc5 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -80,6 +80,7 @@ config SND_AMD_ASOC_ACP70 select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON help This option enables Acp7.0 PDM support on AMD platform. Say Y if you want to enable AUDIO on ACP7.0 From 103d15bc20086820ce2c2af40a651529a87c9e3c Mon Sep 17 00:00:00 2001 From: Sebastian Fricke Date: Wed, 8 Nov 2023 20:29:20 +0100 Subject: [PATCH 0722/7721] media: v4l2: Add ignore_streaming flag Add a new flag to the `struct v4l2_m2m_dev` to toggle whether a queue must be streaming in order to allow queuing jobs to the ready queue. Currently, both queues (CAPTURE & OUTPUT) must be streaming in order to allow adding new jobs. This behavior limits the usability of M2M for some drivers, as these have to be able, to perform analysis of the sequence to ensure, that userspace prepares the CAPTURE queue correctly. Signed-off-by: Sebastian Fricke Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- include/media/v4l2-mem2mem.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index d6c8eb2b5201..1288fe364fab 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -84,6 +84,12 @@ struct v4l2_m2m_queue_ctx { * @last_src_buf: indicate the last source buffer for draining * @next_buf_last: next capture queud buffer will be tagged as last * @has_stopped: indicate the device has been stopped + * @ignore_cap_streaming: If true, job_ready can be called even if the CAPTURE + * queue is not streaming. This allows firmware to + * analyze the bitstream header which arrives on the + * OUTPUT queue. The driver must implement the job_ready + * callback correctly to make sure that the requirements + * for actual decoding are met. * @m2m_dev: opaque pointer to the internal data to handle M2M context * @cap_q_ctx: Capture (output to memory) queue context * @out_q_ctx: Output (input from memory) queue context @@ -106,6 +112,7 @@ struct v4l2_m2m_ctx { struct vb2_v4l2_buffer *last_src_buf; bool next_buf_last; bool has_stopped; + bool ignore_cap_streaming; /* internal use only */ struct v4l2_m2m_dev *m2m_dev; From 4f61d8aa73e44614f1c59aff07274304ecdea9ad Mon Sep 17 00:00:00 2001 From: Sebastian Fricke Date: Wed, 8 Nov 2023 20:29:21 +0100 Subject: [PATCH 0723/7721] media: v4l2: Allow M2M job queuing w/o streaming CAP queue Allow decoder drivers to enable set the ignore_streaming flag on their CAPTURE queue, to allow queuing jobs to the M2M ready queue and perform firmware sequence analysis with just a streaming OUTPUT queue and available bitstream data. Signed-off-by: Sebastian Fricke Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-mem2mem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 0cc30397fbad..9e983176542b 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -301,9 +301,12 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx); - if (!m2m_ctx->out_q_ctx.q.streaming - || !m2m_ctx->cap_q_ctx.q.streaming) { - dprintk("Streaming needs to be on for both queues\n"); + if (!m2m_ctx->out_q_ctx.q.streaming || + (!m2m_ctx->cap_q_ctx.q.streaming && !m2m_ctx->ignore_cap_streaming)) { + if (!m2m_ctx->ignore_cap_streaming) + dprintk("Streaming needs to be on for both queues\n"); + else + dprintk("Streaming needs to be on for the OUTPUT queue\n"); return; } From 02a8b425639d66c2e46f6ef4d2ff5f1d9d060ad7 Mon Sep 17 00:00:00 2001 From: Sebastian Fricke Date: Wed, 8 Nov 2023 20:29:22 +0100 Subject: [PATCH 0724/7721] media: platform: chips-media: Move Coda to separate folder Prepare the folder structure for a second Chips&Media driver. Move the Coda driver to a sub-directory. Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- MAINTAINERS | 2 +- drivers/media/platform/chips-media/Kconfig | 17 +---------------- drivers/media/platform/chips-media/Makefile | 5 +---- .../media/platform/chips-media/coda/Kconfig | 18 ++++++++++++++++++ .../media/platform/chips-media/coda/Makefile | 6 ++++++ .../platform/chips-media/{ => coda}/coda-bit.c | 0 .../chips-media/{ => coda}/coda-common.c | 0 .../platform/chips-media/{ => coda}/coda-gdi.c | 0 .../chips-media/{ => coda}/coda-h264.c | 0 .../chips-media/{ => coda}/coda-jpeg.c | 0 .../chips-media/{ => coda}/coda-mpeg2.c | 0 .../chips-media/{ => coda}/coda-mpeg4.c | 0 .../platform/chips-media/{ => coda}/coda.h | 0 .../chips-media/{ => coda}/coda_regs.h | 0 .../platform/chips-media/{ => coda}/imx-vdoa.c | 0 .../platform/chips-media/{ => coda}/imx-vdoa.h | 0 .../platform/chips-media/{ => coda}/trace.h | 2 +- 17 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 drivers/media/platform/chips-media/coda/Kconfig create mode 100644 drivers/media/platform/chips-media/coda/Makefile rename drivers/media/platform/chips-media/{ => coda}/coda-bit.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-common.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-gdi.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-h264.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-jpeg.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-mpeg2.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda-mpeg4.c (100%) rename drivers/media/platform/chips-media/{ => coda}/coda.h (100%) rename drivers/media/platform/chips-media/{ => coda}/coda_regs.h (100%) rename drivers/media/platform/chips-media/{ => coda}/imx-vdoa.c (100%) rename drivers/media/platform/chips-media/{ => coda}/imx-vdoa.h (100%) rename drivers/media/platform/chips-media/{ => coda}/trace.h (99%) diff --git a/MAINTAINERS b/MAINTAINERS index 7d86cef515ba..6ed7462367ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5169,7 +5169,7 @@ M: Philipp Zabel L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/coda.yaml -F: drivers/media/platform/chips-media/ +F: drivers/media/platform/chips-media/coda CODE OF CONDUCT M: Greg Kroah-Hartman diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig index 57f8f8a22df8..f87a0d693df7 100644 --- a/drivers/media/platform/chips-media/Kconfig +++ b/drivers/media/platform/chips-media/Kconfig @@ -2,19 +2,4 @@ comment "Chips&Media media platform drivers" -config VIDEO_CODA - tristate "Chips&Media Coda multi-standard codec IP" - depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST) - select SRAM - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_JPEG_HELPER - select V4L2_MEM2MEM_DEV - select GENERIC_ALLOCATOR - help - Coda is a range of video codec IPs that supports - H.264, MPEG-4, and other video formats. - -config VIDEO_IMX_VDOA - def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST +source "drivers/media/platform/chips-media/coda/Kconfig" diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile index bbb16425a875..5ee693f651c1 100644 --- a/drivers/media/platform/chips-media/Makefile +++ b/drivers/media/platform/chips-media/Makefile @@ -1,6 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o - -obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o -obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o +obj-y += coda/ diff --git a/drivers/media/platform/chips-media/coda/Kconfig b/drivers/media/platform/chips-media/coda/Kconfig new file mode 100644 index 000000000000..cb7b66c71380 --- /dev/null +++ b/drivers/media/platform/chips-media/coda/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_CODA + tristate "Chips&Media Coda multi-standard codec IP" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST) + select SRAM + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_JPEG_HELPER + select V4L2_MEM2MEM_DEV + select GENERIC_ALLOCATOR + help + Coda is a range of video codec IPs that supports + H.264, MPEG-4, and other video formats. + +config VIDEO_IMX_VDOA + def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST diff --git a/drivers/media/platform/chips-media/coda/Makefile b/drivers/media/platform/chips-media/coda/Makefile new file mode 100644 index 000000000000..bbb16425a875 --- /dev/null +++ b/drivers/media/platform/chips-media/coda/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o + +obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o +obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda/coda-bit.c similarity index 100% rename from drivers/media/platform/chips-media/coda-bit.c rename to drivers/media/platform/chips-media/coda/coda-bit.c diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c similarity index 100% rename from drivers/media/platform/chips-media/coda-common.c rename to drivers/media/platform/chips-media/coda/coda-common.c diff --git a/drivers/media/platform/chips-media/coda-gdi.c b/drivers/media/platform/chips-media/coda/coda-gdi.c similarity index 100% rename from drivers/media/platform/chips-media/coda-gdi.c rename to drivers/media/platform/chips-media/coda/coda-gdi.c diff --git a/drivers/media/platform/chips-media/coda-h264.c b/drivers/media/platform/chips-media/coda/coda-h264.c similarity index 100% rename from drivers/media/platform/chips-media/coda-h264.c rename to drivers/media/platform/chips-media/coda/coda-h264.c diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda/coda-jpeg.c similarity index 100% rename from drivers/media/platform/chips-media/coda-jpeg.c rename to drivers/media/platform/chips-media/coda/coda-jpeg.c diff --git a/drivers/media/platform/chips-media/coda-mpeg2.c b/drivers/media/platform/chips-media/coda/coda-mpeg2.c similarity index 100% rename from drivers/media/platform/chips-media/coda-mpeg2.c rename to drivers/media/platform/chips-media/coda/coda-mpeg2.c diff --git a/drivers/media/platform/chips-media/coda-mpeg4.c b/drivers/media/platform/chips-media/coda/coda-mpeg4.c similarity index 100% rename from drivers/media/platform/chips-media/coda-mpeg4.c rename to drivers/media/platform/chips-media/coda/coda-mpeg4.c diff --git a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda/coda.h similarity index 100% rename from drivers/media/platform/chips-media/coda.h rename to drivers/media/platform/chips-media/coda/coda.h diff --git a/drivers/media/platform/chips-media/coda_regs.h b/drivers/media/platform/chips-media/coda/coda_regs.h similarity index 100% rename from drivers/media/platform/chips-media/coda_regs.h rename to drivers/media/platform/chips-media/coda/coda_regs.h diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/coda/imx-vdoa.c similarity index 100% rename from drivers/media/platform/chips-media/imx-vdoa.c rename to drivers/media/platform/chips-media/coda/imx-vdoa.c diff --git a/drivers/media/platform/chips-media/imx-vdoa.h b/drivers/media/platform/chips-media/coda/imx-vdoa.h similarity index 100% rename from drivers/media/platform/chips-media/imx-vdoa.h rename to drivers/media/platform/chips-media/coda/imx-vdoa.h diff --git a/drivers/media/platform/chips-media/trace.h b/drivers/media/platform/chips-media/coda/trace.h similarity index 99% rename from drivers/media/platform/chips-media/trace.h rename to drivers/media/platform/chips-media/coda/trace.h index 19f98e6dafb9..abc6a01a74e9 100644 --- a/drivers/media/platform/chips-media/trace.h +++ b/drivers/media/platform/chips-media/coda/trace.h @@ -167,7 +167,7 @@ DEFINE_EVENT(coda_buf_class, coda_jpeg_done, #endif /* __CODA_TRACE_H__ */ #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media +#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media/coda #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace From 45d1a2b93277a24a90265055f5b87c7562d6acb9 Mon Sep 17 00:00:00 2001 From: Nas Chung Date: Wed, 8 Nov 2023 20:29:23 +0100 Subject: [PATCH 0725/7721] media: chips-media: wave5: Add vpuapi layer Add the vpuapi layer of the wave5 codec driver. This layer is used to configure the hardware according to the parameters. Signed-off-by: Sebastian Fricke Signed-off-by: Nicolas Dufresne Signed-off-by: Dafna Hirschfeld Signed-off-by: Robert Beckett Signed-off-by: Nas Chung Signed-off-by: Hans Verkuil --- .../platform/chips-media/wave5/wave5-hw.c | 2554 +++++++++++++++++ .../chips-media/wave5/wave5-regdefine.h | 732 +++++ .../platform/chips-media/wave5/wave5-vdi.c | 205 ++ .../platform/chips-media/wave5/wave5-vdi.h | 35 + .../platform/chips-media/wave5/wave5-vpuapi.c | 960 +++++++ .../platform/chips-media/wave5/wave5-vpuapi.h | 870 ++++++ .../chips-media/wave5/wave5-vpuconfig.h | 77 + .../chips-media/wave5/wave5-vpuerror.h | 292 ++ .../media/platform/chips-media/wave5/wave5.h | 114 + 9 files changed, 5839 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave5/wave5-hw.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-regdefine.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vdi.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vdi.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuapi.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuapi.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuerror.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5.h diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c new file mode 100644 index 000000000000..3fcb2d92add8 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c @@ -0,0 +1,2554 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - wave5 backend logic + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave5-vpu.h" +#include "wave5.h" +#include "wave5-regdefine.h" + +#define FIO_TIMEOUT 10000000 +#define FIO_CTRL_READY BIT(31) +#define FIO_CTRL_WRITE BIT(16) +#define VPU_BUSY_CHECK_TIMEOUT 10000000 +#define QUEUE_REPORT_MASK 0xffff + +/* Encoder support fields */ +#define FEATURE_HEVC10BIT_ENC BIT(3) +#define FEATURE_AVC10BIT_ENC BIT(11) +#define FEATURE_AVC_ENCODER BIT(1) +#define FEATURE_HEVC_ENCODER BIT(0) + +/* Decoder support fields */ +#define FEATURE_AVC_DECODER BIT(3) +#define FEATURE_HEVC_DECODER BIT(2) + +#define FEATURE_BACKBONE BIT(16) +#define FEATURE_VCORE_BACKBONE BIT(22) +#define FEATURE_VCPU_BACKBONE BIT(28) + +#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) +#define REMAP_CTRL_REGISTER_VALUE(index) ( \ + (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \ +) + +#define FASTIO_ADDRESS_MASK GENMASK(15, 0) +#define SEQ_PARAM_PROFILE_MASK GENMASK(30, 24) + +static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason, + const char *func); +#define PRINT_REG_ERR(dev, reason) _wave5_print_reg_err((dev), (reason), __func__) + +static inline const char *cmd_to_str(int cmd, bool is_dec) +{ + switch (cmd) { + case W5_INIT_VPU: + return "W5_INIT_VPU"; + case W5_WAKEUP_VPU: + return "W5_WAKEUP_VPU"; + case W5_SLEEP_VPU: + return "W5_SLEEP_VPU"; + case W5_CREATE_INSTANCE: + return "W5_CREATE_INSTANCE"; + case W5_FLUSH_INSTANCE: + return "W5_FLUSH_INSTANCE"; + case W5_DESTROY_INSTANCE: + return "W5_DESTROY_INSTANCE"; + case W5_INIT_SEQ: + return "W5_INIT_SEQ"; + case W5_SET_FB: + return "W5_SET_FB"; + case W5_DEC_ENC_PIC: + if (is_dec) + return "W5_DEC_PIC"; + return "W5_ENC_PIC"; + case W5_ENC_SET_PARAM: + return "W5_ENC_SET_PARAM"; + case W5_QUERY: + return "W5_QUERY"; + case W5_UPDATE_BS: + return "W5_UPDATE_BS"; + case W5_MAX_VPU_COMD: + return "W5_MAX_VPU_COMD"; + default: + return "UNKNOWN"; + } +} + +static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason, + const char *func) +{ + struct device *dev = vpu_dev->dev; + u32 reg_val; + + switch (reg_fail_reason) { + case WAVE5_SYSERR_QUEUEING_FAIL: + reg_val = vpu_read_reg(vpu_dev, W5_RET_QUEUE_FAIL_REASON); + dev_dbg(dev, "%s: queueing failure: 0x%x\n", func, reg_val); + break; + case WAVE5_SYSERR_RESULT_NOT_READY: + dev_err(dev, "%s: result not ready: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_ACCESS_VIOLATION_HW: + dev_err(dev, "%s: access violation: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_WATCHDOG_TIMEOUT: + dev_err(dev, "%s: watchdog timeout: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_BUS_ERROR: + dev_err(dev, "%s: bus error: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_DOUBLE_FAULT: + dev_err(dev, "%s: double fault: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_VPU_STILL_RUNNING: + dev_err(dev, "%s: still running: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_VLC_BUF_FULL: + dev_err(dev, "%s: vlc buf full: 0x%x\n", func, reg_fail_reason); + break; + default: + dev_err(dev, "%s: failure:: 0x%x\n", func, reg_fail_reason); + break; + } +} + +static int wave5_wait_fio_readl(struct vpu_device *vpu_dev, u32 addr, u32 val) +{ + u32 ctrl; + int ret; + + ctrl = addr & 0xffff; + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl); + ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY, + 0, FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR); + if (ret) + return ret; + + if (wave5_vdi_read_register(vpu_dev, W5_VPU_FIO_DATA) != val) + return -ETIMEDOUT; + + return 0; +} + +static void wave5_fio_writel(struct vpu_device *vpu_dev, unsigned int addr, unsigned int data) +{ + int ret; + unsigned int ctrl; + + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_DATA, data); + ctrl = FIELD_GET(FASTIO_ADDRESS_MASK, addr); + ctrl |= FIO_CTRL_WRITE; + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl); + ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY, 0, + FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR); + if (ret) + dev_dbg_ratelimited(vpu_dev->dev, "FIO write timeout: addr=0x%x data=%x\n", + ctrl, data); +} + +static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + u32 gdi_status_check_value = 0x3f; + + if (vpu_dev->product_code == WAVE521C_CODE || + vpu_dev->product_code == WAVE521_CODE || + vpu_dev->product_code == WAVE521E1_CODE) + gdi_status_check_value = 0x00ff1f3f; + + return wave5_wait_fio_readl(vpu_dev, addr, gdi_status_check_value); +} + +static int wave5_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + u32 data; + + return read_poll_timeout(wave5_vdi_read_register, data, data == 0, + 0, VPU_BUSY_CHECK_TIMEOUT, false, vpu_dev, addr); +} + +static int wave5_wait_vcpu_bus_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + return wave5_wait_fio_readl(vpu_dev, addr, 0); +} + +bool wave5_vpu_is_init(struct vpu_device *vpu_dev) +{ + return vpu_read_reg(vpu_dev, W5_VCPU_CUR_PC) != 0; +} + +unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev) +{ + u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER); + + switch (val) { + case WAVE521C_CODE: + return PRODUCT_ID_521; + case WAVE521_CODE: + case WAVE521C_DUAL_CODE: + case WAVE521E1_CODE: + case WAVE511_CODE: + case WAVE517_CODE: + case WAVE537_CODE: + dev_err(vpu_dev->dev, "Unsupported product id (%x)\n", val); + break; + default: + dev_err(vpu_dev->dev, "Invalid product id (%x)\n", val); + break; + } + + return PRODUCT_ID_NONE; +} + +static void wave5_bit_issue_command(struct vpu_device *vpu_dev, struct vpu_instance *inst, u32 cmd) +{ + u32 instance_index; + u32 codec_mode; + + if (inst) { + instance_index = inst->id; + codec_mode = inst->std; + + vpu_write_reg(vpu_dev, W5_CMD_INSTANCE_INFO, (codec_mode << 16) | + (instance_index & 0xffff)); + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + } + + vpu_write_reg(vpu_dev, W5_COMMAND, cmd); + + if (inst) { + dev_dbg(vpu_dev->dev, "%s: cmd=0x%x (%s)\n", __func__, cmd, + cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC)); + } else { + dev_dbg(vpu_dev->dev, "%s: cmd=0x%x\n", __func__, cmd); + } + + vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1); +} + +static int wave5_vpu_firmware_command_queue_error_check(struct vpu_device *dev, u32 *fail_res) +{ + u32 reason = 0; + + /* Check if we were able to add a command into the VCPU QUEUE */ + if (!vpu_read_reg(dev, W5_RET_SUCCESS)) { + reason = vpu_read_reg(dev, W5_RET_FAIL_REASON); + PRINT_REG_ERR(dev, reason); + + /* + * The fail_res argument will be either NULL or 0. + * If the fail_res argument is NULL, then just return -EIO. + * Otherwise, assign the reason to fail_res, so that the + * calling function can use it. + */ + if (fail_res) + *fail_res = reason; + else + return -EIO; + + if (reason == WAVE5_SYSERR_VPU_STILL_RUNNING) + return -EBUSY; + } + return 0; +} + +static int send_firmware_command(struct vpu_instance *inst, u32 cmd, bool check_success, + u32 *queue_status, u32 *fail_result) +{ + int ret; + + wave5_bit_issue_command(inst->dev, inst, cmd); + ret = wave5_wait_vpu_busy(inst->dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_warn(inst->dev->dev, "%s: command: '%s', timed out\n", __func__, + cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC)); + return -ETIMEDOUT; + } + + if (queue_status) + *queue_status = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + /* In some cases we want to send multiple commands before checking + * whether they are queued properly + */ + if (!check_success) + return 0; + + return wave5_vpu_firmware_command_queue_error_check(inst->dev, fail_result); +} + +static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *inst, + enum query_opt query_opt) +{ + int ret; + + vpu_write_reg(vpu_dev, W5_QUERY_OPTION, query_opt); + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + wave5_bit_issue_command(vpu_dev, inst, W5_QUERY); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_warn(vpu_dev->dev, "command: 'W5_QUERY', timed out opt=0x%x\n", query_opt); + return ret; + } + + return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); +} + +static int setup_wave5_properties(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + struct vpu_attr *p_attr = &vpu_dev->attr; + u32 reg_val; + u8 *str; + int ret; + u32 hw_config_def0, hw_config_def1, hw_config_feature; + + ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO); + if (ret) + return ret; + + reg_val = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_NAME); + str = (u8 *)®_val; + p_attr->product_name[0] = str[3]; + p_attr->product_name[1] = str[2]; + p_attr->product_name[2] = str[1]; + p_attr->product_name[3] = str[0]; + p_attr->product_name[4] = 0; + + p_attr->product_id = wave5_vpu_get_product_id(vpu_dev); + p_attr->product_version = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_VERSION); + p_attr->fw_version = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION); + p_attr->customer_id = vpu_read_reg(vpu_dev, W5_RET_CUSTOMER_ID); + hw_config_def0 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF0); + hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1); + hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE); + + p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature); + p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature); + + p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC; + p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC; + p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC; + p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC; + + p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0); + p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0); + p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0); + + return 0; +} + +int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision) +{ + u32 reg_val; + int ret; + + ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO); + if (ret) + return ret; + + reg_val = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION); + if (revision) { + *revision = reg_val; + return 0; + } + + return -EINVAL; +} + +static void remap_page(struct vpu_device *vpu_dev, dma_addr_t code_base, u32 index) +{ + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CTRL, REMAP_CTRL_REGISTER_VALUE(index)); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_VADDR, index * W5_REMAP_MAX_SIZE); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_PADDR, code_base + index * W5_REMAP_MAX_SIZE); +} + +int wave5_vpu_init(struct device *dev, u8 *fw, size_t size) +{ + struct vpu_buf *common_vb; + dma_addr_t code_base, temp_base; + u32 code_size, temp_size; + u32 i, reg_val, reason_code; + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) + return -EINVAL; + + temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; + temp_size = WAVE5_TEMPBUF_SIZE; + + ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); + if (ret < 0) { + dev_err(vpu_dev->dev, "VPU init, Writing firmware to common buffer, fail: %d\n", + ret); + return ret; + } + + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + /* clear registers */ + + for (i = W5_CMD_REG_BASE; i < W5_CMD_REG_END; i += 4) + vpu_write_reg(vpu_dev, i, 0x00); + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base); + vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU init(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + + return setup_wave5_properties(dev); +} + +int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, + struct dec_open_param *param) +{ + int ret; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct vpu_device *vpu_dev = inst->dev; + + p_dec_info->cycle_per_tick = 256; + if (vpu_dev->sram_buf.size) { + p_dec_info->sec_axi_info.use_bit_enable = 1; + p_dec_info->sec_axi_info.use_ip_enable = 1; + p_dec_info->sec_axi_info.use_lf_row_enable = 1; + } + switch (inst->std) { + case W_HEVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC; + break; + case W_AVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC; + break; + default: + return -EINVAL; + } + + p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE; + ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work); + if (ret) + return ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1); + + wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work); + + vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr); + vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size); + + vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); + vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); + + vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size); + + /* NOTE: SDMA reads MSB first */ + vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN); + /* This register must be reset explicitly */ + vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); + + ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); + if (ret) { + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work); + return ret; + } + + p_dec_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER); + + return 0; +} + +int wave5_vpu_hw_flush_instance(struct vpu_instance *inst) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 instance_queue_count, report_queue_count; + u32 reg_val = 0; + u32 fail_res = 0; + int ret; + + ret = send_firmware_command(inst, W5_FLUSH_INSTANCE, true, ®_val, &fail_res); + if (ret) + return ret; + + instance_queue_count = (reg_val >> 16) & 0xff; + report_queue_count = (reg_val & QUEUE_REPORT_MASK); + if (instance_queue_count != 0 || report_queue_count != 0) { + dev_warn(inst->dev->dev, + "FLUSH_INSTANCE cmd didn't reset the amount of queued commands & reports"); + } + + /* reset our local copy of the counts */ + p_dec_info->instance_queue_count = 0; + p_dec_info->report_queue_count = 0; + + return 0; +} + +static u32 get_bitstream_options(struct dec_info *info) +{ + u32 bs_option = BSOPTION_ENABLE_EXPLICIT_END; + + if (info->stream_endflag) + bs_option |= BSOPTION_HIGHLIGHT_STREAM_END; + return bs_option; +} + +int wave5_vpu_dec_init_seq(struct vpu_instance *inst) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 cmd_option = INIT_SEQ_NORMAL; + u32 reg_val, fail_res; + int ret; + + if (!inst->codec_info) + return -EINVAL; + + vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + + vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option); + vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); + + ret = send_firmware_command(inst, W5_INIT_SEQ, true, ®_val, &fail_res); + if (ret) + return ret; + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: init seq sent (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + if (ret) + return ret; + + return 0; +} + +static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info) +{ + u32 reg_val; + u32 profile_compatibility_flag; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst); + info->rd_ptr = p_dec_info->stream_rd_ptr; + + p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE); + info->pic_width = ((reg_val >> 16) & 0xffff); + info->pic_height = (reg_val & 0xffff); + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_DEC_NUM_REQUIRED_FB); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_LEFT_RIGHT); + info->pic_crop_rect.left = (reg_val >> 16) & 0xffff; + info->pic_crop_rect.right = reg_val & 0xffff; + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_TOP_BOTTOM); + info->pic_crop_rect.top = (reg_val >> 16) & 0xffff; + info->pic_crop_rect.bottom = reg_val & 0xffff; + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_COLOR_SAMPLE_INFO); + info->luma_bitdepth = reg_val & 0xf; + info->chroma_bitdepth = (reg_val >> 4) & 0xf; + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_SEQ_PARAM); + profile_compatibility_flag = (reg_val >> 12) & 0xff; + info->profile = (reg_val >> 24) & 0x1f; + + if (inst->std == W_HEVC_DEC) { + /* guessing profile */ + if (!info->profile) { + if ((profile_compatibility_flag & 0x06) == 0x06) + info->profile = HEVC_PROFILE_MAIN; /* main profile */ + else if (profile_compatibility_flag & 0x04) + info->profile = HEVC_PROFILE_MAIN10; /* main10 profile */ + else if (profile_compatibility_flag & 0x08) + /* main still picture profile */ + info->profile = HEVC_PROFILE_STILLPICTURE; + else + info->profile = HEVC_PROFILE_MAIN; /* for old version HM */ + } + } else if (inst->std == W_AVC_DEC) { + info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val); + } + + info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); + info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); + p_dec_info->vlc_buf_size = info->vlc_buf_size; + p_dec_info->param_buf_size = info->param_buf_size; +} + +int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info) +{ + int ret; + u32 reg_val; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN); + + /* send QUERY cmd */ + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: init seq complete (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + /* this is not a fatal error, set ret to -EIO but don't return immediately */ + if (vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_SUCCESS) != 1) { + info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_DEC_ERR_INFO); + ret = -EIO; + } + + wave5_get_dec_seq_result(inst, info); + + return ret; +} + +int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_buffer *fb_arr, + enum tiled_map_type map_type, unsigned int count) +{ + int ret; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct dec_initial_info *init_info = &p_dec_info->initial_info; + size_t remain, idx, j, i, cnt_8_chunk, size; + u32 start_no, end_no; + u32 reg_val, cbcr_interleave, nv21, pic_size; + u32 addr_y, addr_cb, addr_cr; + u32 mv_col_size, frame_width, frame_height, fbc_y_tbl_size, fbc_c_tbl_size; + struct vpu_buf vb_buf; + bool justified = WTL_RIGHT_JUSTIFIED; + u32 format_no = WTL_PIXEL_8BIT; + u32 color_format = 0; + u32 pixel_order = 1; + u32 bwb_flag = (map_type == LINEAR_FRAME_MAP) ? 1 : 0; + + cbcr_interleave = inst->cbcr_interleave; + nv21 = inst->nv21; + mv_col_size = 0; + fbc_y_tbl_size = 0; + fbc_c_tbl_size = 0; + + if (map_type >= COMPRESSED_FRAME_MAP) { + cbcr_interleave = 0; + nv21 = 0; + + switch (inst->std) { + case W_HEVC_DEC: + mv_col_size = WAVE5_DEC_HEVC_BUF_SIZE(init_info->pic_width, + init_info->pic_height); + break; + case W_AVC_DEC: + mv_col_size = WAVE5_DEC_AVC_BUF_SIZE(init_info->pic_width, + init_info->pic_height); + break; + default: + return -EINVAL; + } + + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) { + size = ALIGN(ALIGN(mv_col_size, 16), BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_mv, count, size); + if (ret) + goto free_mv_buffers; + } + + frame_width = init_info->pic_width; + frame_height = init_info->pic_height; + fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(frame_width, frame_height), 16); + fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(frame_width, frame_height), 16); + + size = ALIGN(fbc_y_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_y_tbl, count, size); + if (ret) + goto free_fbc_y_tbl_buffers; + + size = ALIGN(fbc_c_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_c_tbl, count, size); + if (ret) + goto free_fbc_c_tbl_buffers; + + pic_size = (init_info->pic_width << 16) | (init_info->pic_height); + + vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) + + (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH); + vb_buf.daddr = 0; + + if (vb_buf.size != p_dec_info->vb_task.size) { + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); + ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf); + if (ret) + goto free_fbc_c_tbl_buffers; + + p_dec_info->vb_task = vb_buf; + } + + vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, + p_dec_info->vb_task.daddr); + vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size); + } else { + pic_size = (init_info->pic_width << 16) | (init_info->pic_height); + + if (inst->output_format == FORMAT_422) + color_format = 1; + } + vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size); + + reg_val = (bwb_flag << 28) | + (pixel_order << 23) | + (justified << 22) | + (format_no << 20) | + (color_format << 19) | + (nv21 << 17) | + (cbcr_interleave << 16) | + (fb_arr[0].stride); + vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, reg_val); + + remain = count; + cnt_8_chunk = DIV_ROUND_UP(count, 8); + idx = 0; + for (j = 0; j < cnt_8_chunk; j++) { + reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3); + vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val); + start_no = j * 8; + end_no = start_no + ((remain >= 8) ? 8 : remain) - 1; + + vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no); + + for (i = 0; i < 8 && i < remain; i++) { + addr_y = fb_arr[i + start_no].buf_y; + addr_cb = fb_arr[i + start_no].buf_cb; + addr_cr = fb_arr[i + start_no].buf_cr; + vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), addr_y); + vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4), addr_cb); + if (map_type >= COMPRESSED_FRAME_MAP) { + /* luma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4), + p_dec_info->vb_fbc_y_tbl[idx].daddr); + /* chroma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), + p_dec_info->vb_fbc_c_tbl[idx].daddr); + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), + p_dec_info->vb_mv[idx].daddr); + } else { + vpu_write_reg(inst->dev, W5_ADDR_CR_BASE0 + (i << 4), addr_cr); + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), 0); + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), 0); + } + idx++; + } + remain -= i; + + ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL); + if (ret) + goto free_buffers; + } + + reg_val = vpu_read_reg(inst->dev, W5_RET_SUCCESS); + if (!reg_val) { + ret = -EIO; + goto free_buffers; + } + + return 0; + +free_buffers: + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); +free_fbc_c_tbl_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[i]); +free_fbc_y_tbl_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[i]); +free_mv_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[i]); + return ret; +} + +int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) +{ + u32 reg_val; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + + vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + + /* secondary AXI */ + reg_val = p_dec_info->sec_axi_info.use_bit_enable | + (p_dec_info->sec_axi_info.use_ip_enable << 9) | + (p_dec_info->sec_axi_info.use_lf_row_enable << 15); + vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val); + + /* set attributes of user buffer */ + vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); + + vpu_write_reg(inst->dev, W5_COMMAND_OPTION, DEC_PIC_NORMAL); + vpu_write_reg(inst->dev, W5_CMD_DEC_TEMPORAL_ID_PLUS1, + (p_dec_info->target_spatial_id << 9) | + (p_dec_info->temp_id_select_mode << 8) | p_dec_info->target_temp_id); + vpu_write_reg(inst->dev, W5_CMD_SEQ_CHANGE_ENABLE_FLAG, p_dec_info->seq_change_mask); + /* When reordering is disabled we force the latency of the framebuffers */ + vpu_write_reg(inst->dev, W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1, !p_dec_info->reorder_enable); + + ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, ®_val, fail_res); + if (ret == -ETIMEDOUT) + return ret; + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: dec pic sent (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result) +{ + int ret; + u32 index, nal_unit_type, reg_val, sub_layer_info; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct vpu_device *vpu_dev = inst->dev; + + vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN); + + /* send QUERY cmd */ + ret = wave5_send_query(vpu_dev, inst, GET_RESULT); + if (ret) + return ret; + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: dec pic complete (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_TYPE); + + nal_unit_type = (reg_val >> 4) & 0x3f; + + if (inst->std == W_HEVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type == PIC_TYPE_I) + /* IDR_W_RADL, IDR_N_LP */ + result->pic_type = PIC_TYPE_IDR; + } else if (inst->std == W_AVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I) + result->pic_type = PIC_TYPE_IDR; + } + index = vpu_read_reg(inst->dev, W5_RET_DEC_DISPLAY_INDEX); + result->index_frame_display = index; + index = vpu_read_reg(inst->dev, W5_RET_DEC_DECODED_INDEX); + result->index_frame_decoded = index; + result->index_frame_decoded_for_tiled = index; + + sub_layer_info = vpu_read_reg(inst->dev, W5_RET_DEC_SUB_LAYER_INFO); + result->temporal_id = sub_layer_info & 0x7; + + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) { + result->decoded_poc = -1; + if (result->index_frame_decoded >= 0 || + result->index_frame_decoded == DECODED_IDX_FLAG_SKIP) + result->decoded_poc = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_POC); + } + + result->sequence_changed = vpu_read_reg(inst->dev, W5_RET_DEC_NOTIFICATION); + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE); + result->dec_pic_width = reg_val >> 16; + result->dec_pic_height = reg_val & 0xffff; + + if (result->sequence_changed) { + memcpy((void *)&p_dec_info->new_seq_info, (void *)&p_dec_info->initial_info, + sizeof(struct dec_initial_info)); + wave5_get_dec_seq_result(inst, &p_dec_info->new_seq_info); + } + + result->dec_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_DEC_HOST_CMD_TICK); + result->dec_decode_end_tick = vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_ENC_TICK); + + if (!p_dec_info->first_cycle_check) { + result->frame_cycle = + (result->dec_decode_end_tick - result->dec_host_cmd_tick) * + p_dec_info->cycle_per_tick; + vpu_dev->last_performance_cycles = result->dec_decode_end_tick; + p_dec_info->first_cycle_check = true; + } else if (result->index_frame_decoded_for_tiled != -1) { + result->frame_cycle = + (result->dec_decode_end_tick - vpu_dev->last_performance_cycles) * + p_dec_info->cycle_per_tick; + vpu_dev->last_performance_cycles = result->dec_decode_end_tick; + if (vpu_dev->last_performance_cycles < result->dec_host_cmd_tick) + result->frame_cycle = + (result->dec_decode_end_tick - result->dec_host_cmd_tick) * + p_dec_info->cycle_per_tick; + } + + /* no remaining command. reset frame cycle. */ + if (p_dec_info->instance_queue_count == 0 && p_dec_info->report_queue_count == 0) + p_dec_info->first_cycle_check = false; + + return 0; +} + +int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) +{ + struct vpu_buf *common_vb; + dma_addr_t code_base, temp_base; + dma_addr_t old_code_base, temp_size; + u32 code_size, reason_code; + u32 reg_val; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) + return -EINVAL; + temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; + temp_size = WAVE5_TEMPBUF_SIZE; + + old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR); + + if (old_code_base != code_base + W5_REMAP_INDEX1 * W5_REMAP_MAX_SIZE) { + int ret; + + ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); + if (ret < 0) { + dev_err(vpu_dev->dev, + "VPU init, Writing firmware to common buffer, fail: %d\n", ret); + return ret; + } + + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT); + if (ret < 0) { + dev_err(vpu_dev->dev, "VPU init, Resetting the VPU, fail: %d\n", ret); + return ret; + } + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base); + vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU reinit(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + } + + return setup_wave5_properties(dev); +} + +static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size) +{ + u32 reg_val; + struct vpu_buf *common_vb; + dma_addr_t code_base; + u32 code_size, reason_code; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret; + + if (i_sleep_wake) { + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) + return ret; + + /* + * Declare who has ownership for the host interface access + * 1 = VPU + * 0 = Host processor + */ + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_SLEEP_VPU); + /* Send an interrupt named HOST to the VPU */ + vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) + return ret; + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + } else { /* restore */ + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) { + dev_err(dev, "size too small\n"); + return -EINVAL; + } + + /* Power on without DEBUG mode */ + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU); + /* Start VPU after settings */ + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU wakeup(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + return wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + } + + return 0; +} + +int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode) +{ + u32 val = 0; + int ret = 0; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + struct vpu_attr *p_attr = &vpu_dev->attr; + /* VPU doesn't send response. force to set BUSY flag to 0. */ + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 0); + + if (reset_mode == SW_RESET_SAFETY) { + ret = wave5_vpu_sleep_wake(dev, true, NULL, 0); + if (ret) + return ret; + } + + val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if ((val >> 16) & 0x1) + p_attr->support_backbone = true; + if ((val >> 22) & 0x1) + p_attr->support_vcore_backbone = true; + if ((val >> 28) & 0x1) + p_attr->support_vcpu_backbone = true; + + /* waiting for completion of bus transaction */ + if (p_attr->support_backbone) { + dev_dbg(dev, "%s: backbone supported\n", __func__); + + if (p_attr->support_vcore_backbone) { + if (p_attr->support_vcpu_backbone) { + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0xFF); + + /* step2 : waiting for completion of bus transaction */ + ret = wave5_wait_vcpu_bus_busy(vpu_dev, + W5_BACKBONE_BUS_STATUS_VCPU); + if (ret) { + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00); + return ret; + } + } + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x7); + + /* step2 : waiting for completion of bus transaction */ + if (wave5_wait_bus_busy(vpu_dev, W5_BACKBONE_BUS_STATUS_VCORE0)) { + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00); + return -EBUSY; + } + } else { + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x7); + + /* step2 : waiting for completion of bus transaction */ + if (wave5_wait_bus_busy(vpu_dev, W5_COMBINED_BACKBONE_BUS_STATUS)) { + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00); + return -EBUSY; + } + } + } else { + dev_dbg(dev, "%s: backbone NOT supported\n", __func__); + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x100); + + /* step2 : waiting for completion of bus transaction */ + ret = wave5_wait_bus_busy(vpu_dev, W5_GDI_BUS_STATUS); + if (ret) { + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00); + return ret; + } + } + + switch (reset_mode) { + case SW_RESET_ON_BOOT: + case SW_RESET_FORCE: + case SW_RESET_SAFETY: + val = W5_RST_BLOCK_ALL; + break; + default: + return -EINVAL; + } + + if (val) { + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, val); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_RESET_STATUS); + if (ret) { + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0); + return ret; + } + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0); + } + /* step3 : must clear GDI_BUS_CTRL after done SW_RESET */ + if (p_attr->support_backbone) { + if (p_attr->support_vcore_backbone) { + if (p_attr->support_vcpu_backbone) + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00); + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00); + } else { + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00); + } + } else { + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00); + } + if (reset_mode == SW_RESET_SAFETY || reset_mode == SW_RESET_FORCE) + ret = wave5_vpu_sleep_wake(dev, false, NULL, 0); + + return ret; +} + +int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res) +{ + return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res); +} + +int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + p_dec_info->stream_endflag = eos ? 1 : 0; + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + return send_firmware_command(inst, W5_UPDATE_BS, true, NULL, NULL); +} + +int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, BIT(index)); + vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, 0); + + ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG); + if (ret) + return ret; + + p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC); + + return 0; +} + +int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index) +{ + int ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, 0); + vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, BIT(index)); + + ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG); + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags) +{ + u32 interrupt_reason; + + interrupt_reason = vpu_read_reg(inst->dev, W5_VPU_VINT_REASON_USR); + interrupt_reason &= ~flags; + vpu_write_reg(inst->dev, W5_VPU_VINT_REASON_USR, interrupt_reason); + + return 0; +} + +dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst) +{ + int ret; + + ret = wave5_send_query(inst->dev, inst, GET_BS_RD_PTR); + if (ret) + return inst->codec_info->dec_info.stream_rd_ptr; + + return vpu_read_reg(inst->dev, W5_RET_QUERY_DEC_BS_RD_PTR); +} + +int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr) +{ + int ret; + + vpu_write_reg(inst->dev, W5_RET_QUERY_DEC_SET_BS_RD_PTR, addr); + + ret = wave5_send_query(inst->dev, inst, SET_BS_RD_PTR); + + return ret; +} + +/************************************************************************/ +/* ENCODER functions */ +/************************************************************************/ + +int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *open_param) +{ + int ret; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 reg_val; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + dma_addr_t buffer_addr; + size_t buffer_size; + + p_enc_info->cycle_per_tick = 256; + if (vpu_dev->sram_buf.size) { + p_enc_info->sec_axi_info.use_enc_rdo_enable = 1; + p_enc_info->sec_axi_info.use_enc_lf_enable = 1; + } + + p_enc_info->vb_work.size = WAVE521ENC_WORKBUF_SIZE; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &p_enc_info->vb_work); + if (ret) { + memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work)); + return ret; + } + + wave5_vdi_clear_memory(vpu_dev, &p_enc_info->vb_work); + + vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_enc_info->vb_work.daddr); + vpu_write_reg(inst->dev, W5_WORK_SIZE, p_enc_info->vb_work.size); + + vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); + vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); + + reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN; + vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val); + vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); + + /* This register must be reset explicitly */ + vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_VCORE_INFO, 1); + + ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); + if (ret) + goto free_vb_work; + + buffer_addr = open_param->bitstream_buffer; + buffer_size = open_param->bitstream_buffer_size; + p_enc_info->stream_rd_ptr = buffer_addr; + p_enc_info->stream_wr_ptr = buffer_addr; + p_enc_info->line_buf_int_en = open_param->line_buf_int_en; + p_enc_info->stream_buf_start_addr = buffer_addr; + p_enc_info->stream_buf_size = buffer_size; + p_enc_info->stream_buf_end_addr = buffer_addr + buffer_size; + p_enc_info->stride = 0; + p_enc_info->initial_info_obtained = false; + p_enc_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER); + + return 0; +free_vb_work: + if (wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work)) + memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work)); + return ret; +} + +static void wave5_set_enc_crop_info(u32 codec, struct enc_wave_param *param, int rot_mode, + int src_width, int src_height) +{ + int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(src_width, 32) : ALIGN(src_width, 16); + int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(src_height, 32) : ALIGN(src_height, 16); + int pad_right, pad_bot; + int crop_right, crop_left, crop_top, crop_bot; + int prp_mode = rot_mode >> 1; /* remove prp_enable bit */ + + if (codec == W_HEVC_ENC && + (!rot_mode || prp_mode == 14)) /* prp_mode 14 : hor_mir && ver_mir && rot_180 */ + return; + + pad_right = aligned_width - src_width; + pad_bot = aligned_height - src_height; + + if (param->conf_win_right > 0) + crop_right = param->conf_win_right + pad_right; + else + crop_right = pad_right; + + if (param->conf_win_bot > 0) + crop_bot = param->conf_win_bot + pad_bot; + else + crop_bot = pad_bot; + + crop_top = param->conf_win_top; + crop_left = param->conf_win_left; + + param->conf_win_top = crop_top; + param->conf_win_left = crop_left; + param->conf_win_bot = crop_bot; + param->conf_win_right = crop_right; + + switch (prp_mode) { + case 0: + return; + case 1: + case 15: + param->conf_win_top = crop_right; + param->conf_win_left = crop_top; + param->conf_win_bot = crop_left; + param->conf_win_right = crop_bot; + break; + case 2: + case 12: + param->conf_win_top = crop_bot; + param->conf_win_left = crop_right; + param->conf_win_bot = crop_top; + param->conf_win_right = crop_left; + break; + case 3: + case 13: + param->conf_win_top = crop_left; + param->conf_win_left = crop_bot; + param->conf_win_bot = crop_right; + param->conf_win_right = crop_top; + break; + case 4: + case 10: + param->conf_win_top = crop_bot; + param->conf_win_bot = crop_top; + break; + case 8: + case 6: + param->conf_win_left = crop_right; + param->conf_win_right = crop_left; + break; + case 5: + case 11: + param->conf_win_top = crop_left; + param->conf_win_left = crop_top; + param->conf_win_bot = crop_right; + param->conf_win_right = crop_bot; + break; + case 7: + case 9: + param->conf_win_top = crop_right; + param->conf_win_left = crop_bot; + param->conf_win_bot = crop_left; + param->conf_win_right = crop_top; + break; + default: + WARN(1, "Invalid prp_mode: %d, must be in range of 1 - 15\n", prp_mode); + } +} + +int wave5_vpu_enc_init_seq(struct vpu_instance *inst) +{ + u32 reg_val = 0, rot_mir_mode, fixed_cu_size_mode = 0x7; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct enc_open_param *p_open_param = &p_enc_info->open_param; + struct enc_wave_param *p_param = &p_open_param->wave_param; + + /* + * OPT_COMMON: + * the last SET_PARAM command should be called with OPT_COMMON + */ + rot_mir_mode = 0; + if (p_enc_info->rotation_enable) { + switch (p_enc_info->rotation_angle) { + case 0: + rot_mir_mode |= NONE_ROTATE; + break; + case 90: + rot_mir_mode |= ROT_CLOCKWISE_90; + break; + case 180: + rot_mir_mode |= ROT_CLOCKWISE_180; + break; + case 270: + rot_mir_mode |= ROT_CLOCKWISE_270; + break; + } + } + + if (p_enc_info->mirror_enable) { + switch (p_enc_info->mirror_direction) { + case MIRDIR_NONE: + rot_mir_mode |= NONE_ROTATE; + break; + case MIRDIR_VER: + rot_mir_mode |= MIR_VER_FLIP; + break; + case MIRDIR_HOR: + rot_mir_mode |= MIR_HOR_FLIP; + break; + case MIRDIR_HOR_VER: + rot_mir_mode |= MIR_HOR_VER_FLIP; + break; + } + } + + wave5_set_enc_crop_info(inst->std, p_param, rot_mir_mode, p_open_param->pic_width, + p_open_param->pic_height); + + /* SET_PARAM + COMMON */ + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SET_PARAM_OPTION, OPT_COMMON); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SRC_SIZE, p_open_param->pic_height << 16 + | p_open_param->pic_width); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN, VDI_LITTLE_ENDIAN); + + reg_val = p_param->profile | + (p_param->level << 3) | + (p_param->internal_bit_depth << 14); + if (inst->std == W_HEVC_ENC) + reg_val |= (p_param->tier << 12) | + (p_param->tmvp_enable << 23) | + (p_param->sao_enable << 24) | + (p_param->skip_intra_trans << 25) | + (p_param->strong_intra_smooth_enable << 27) | + (p_param->en_still_picture << 30); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SPS_PARAM, reg_val); + + reg_val = (p_param->lossless_enable) | + (p_param->const_intra_pred_flag << 1) | + (p_param->lf_cross_slice_boundary_enable << 2) | + (p_param->wpp_enable << 4) | + (p_param->disable_deblk << 5) | + ((p_param->beta_offset_div2 & 0xF) << 6) | + ((p_param->tc_offset_div2 & 0xF) << 10) | + ((p_param->chroma_cb_qp_offset & 0x1F) << 14) | + ((p_param->chroma_cr_qp_offset & 0x1F) << 19) | + (p_param->transform8x8_enable << 29) | + (p_param->entropy_coding_mode << 30); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_PPS_PARAM, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_GOP_PARAM, p_param->gop_preset_idx); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp | + ((p_param->intra_period & 0x7ff) << 6) | + ((p_param->avc_idr_period & 0x7ff) << 17)); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, + p_param->decoding_refresh_type | (p_param->intra_qp << 3) | + (p_param->intra_period << 16)); + + reg_val = (p_param->rdo_skip << 2) | + (p_param->lambda_scaling_enable << 3) | + (fixed_cu_size_mode << 5) | + (p_param->intra_nx_n_enable << 8) | + (p_param->max_num_merge << 18); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RDO_PARAM, reg_val); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH, + p_param->intra_mb_refresh_arg << 16 | p_param->intra_mb_refresh_mode); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH, + p_param->intra_refresh_arg << 16 | p_param->intra_refresh_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_FRAME_RATE, p_open_param->frame_rate_info); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_TARGET_RATE, p_open_param->bit_rate); + + reg_val = p_open_param->rc_enable | + (p_param->hvs_qp_enable << 2) | + (p_param->hvs_qp_scale << 4) | + ((p_param->initial_rc_qp & 0x3F) << 14) | + (p_open_param->vbv_buffer_size << 20); + if (inst->std == W_AVC_ENC) + reg_val |= (p_param->mb_level_rc_enable << 1); + else if (inst->std == W_HEVC_ENC) + reg_val |= (p_param->cu_level_rc_enable << 1); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_PARAM, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM, + p_param->rc_weight_buf << 8 | p_param->rc_weight_param); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_MIN_MAX_QP, p_param->min_qp_i | + (p_param->max_qp_i << 6) | (p_param->hvs_max_delta_qp << 12)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP, p_param->min_qp_p | + (p_param->max_qp_p << 6) | (p_param->min_qp_b << 12) | + (p_param->max_qp_b << 18)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_ROT_PARAM, rot_mir_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_BG_PARAM, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT, + p_param->conf_win_bot << 16 | p_param->conf_win_top); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT, + p_param->conf_win_right << 16 | p_param->conf_win_left); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE, + p_param->avc_slice_arg << 16 | p_param->avc_slice_mode); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE, + p_param->independ_slice_mode_arg << 16 | + p_param->independ_slice_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_TIME_SCALE, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE, 0); + + if (inst->std == W_HEVC_ENC) { + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU04, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU08, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU16, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU32, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU08, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU16, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU32, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_DEPENDENT_SLICE, + p_param->depend_slice_mode_arg << 16 | p_param->depend_slice_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_PARAM, 0); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_WEIGHT, + p_param->nr_intra_weight_y | + (p_param->nr_intra_weight_cb << 5) | + (p_param->nr_intra_weight_cr << 10) | + (p_param->nr_inter_weight_y << 15) | + (p_param->nr_inter_weight_cb << 20) | + (p_param->nr_inter_weight_cr << 25)); + } + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_VUI_HRD_PARAM, 0); + + return send_firmware_command(inst, W5_ENC_SET_PARAM, true, NULL, NULL); +} + +int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info) +{ + int ret; + u32 reg_val; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + /* send QUERY cmd */ + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: init seq\n", __func__); + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + if (vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS) != 1) { + info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO); + ret = -EIO; + } else { + info->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO); + } + + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_ENC_NUM_REQUIRED_FB); + info->min_src_frame_count = vpu_read_reg(inst->dev, W5_RET_ENC_MIN_SRC_BUF_NUM); + info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); + info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); + p_enc_info->vlc_buf_size = info->vlc_buf_size; + p_enc_info->param_buf_size = info->param_buf_size; + + return ret; +} + +static u32 calculate_luma_stride(u32 width, u32 bit_depth) +{ + return ALIGN(ALIGN(width, 16) * ((bit_depth > 8) ? 5 : 4), 32); +} + +static u32 calculate_chroma_stride(u32 width, u32 bit_depth) +{ + return ALIGN(ALIGN(width / 2, 16) * ((bit_depth > 8) ? 5 : 4), 32); +} + +int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret = 0; + u32 stride; + u32 start_no, end_no; + size_t remain, idx, j, i, cnt_8_chunk; + u32 reg_val = 0, pic_size = 0, mv_col_size, fbc_y_tbl_size, fbc_c_tbl_size; + u32 sub_sampled_size = 0; + u32 luma_stride, chroma_stride; + u32 buf_height = 0, buf_width = 0; + u32 bit_depth; + bool avc_encoding = (inst->std == W_AVC_ENC); + struct vpu_buf vb_mv = {0}; + struct vpu_buf vb_fbc_y_tbl = {0}; + struct vpu_buf vb_fbc_c_tbl = {0}; + struct vpu_buf vb_sub_sam_buf = {0}; + struct vpu_buf vb_task = {0}; + struct enc_open_param *p_open_param; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + p_open_param = &p_enc_info->open_param; + mv_col_size = 0; + fbc_y_tbl_size = 0; + fbc_c_tbl_size = 0; + stride = p_enc_info->stride; + bit_depth = p_open_param->wave_param.internal_bit_depth; + + if (avc_encoding) { + buf_width = ALIGN(p_open_param->pic_width, 16); + buf_height = ALIGN(p_open_param->pic_height, 16); + + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + buf_width = ALIGN(p_open_param->pic_width, 16); + buf_height = ALIGN(p_open_param->pic_height, 16); + } + + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_open_param->pic_height, 16); + buf_height = ALIGN(p_open_param->pic_width, 16); + } + } else { + buf_width = ALIGN(p_open_param->pic_width, 8); + buf_height = ALIGN(p_open_param->pic_height, 8); + + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + buf_width = ALIGN(p_open_param->pic_width, 32); + buf_height = ALIGN(p_open_param->pic_height, 32); + } + + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_open_param->pic_height, 32); + buf_height = ALIGN(p_open_param->pic_width, 32); + } + } + + pic_size = (buf_width << 16) | buf_height; + + if (avc_encoding) { + mv_col_size = WAVE5_ENC_AVC_BUF_SIZE(buf_width, buf_height); + vb_mv.daddr = 0; + vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + } else { + mv_col_size = WAVE5_ENC_HEVC_BUF_SIZE(buf_width, buf_height); + mv_col_size = ALIGN(mv_col_size, 16); + vb_mv.daddr = 0; + vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + } + + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_mv); + if (ret) + return ret; + + p_enc_info->vb_mv = vb_mv; + + fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(buf_width, buf_height), 16); + fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(buf_width, buf_height), 16); + + vb_fbc_y_tbl.daddr = 0; + vb_fbc_y_tbl.size = ALIGN(fbc_y_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_y_tbl); + if (ret) + goto free_vb_fbc_y_tbl; + + p_enc_info->vb_fbc_y_tbl = vb_fbc_y_tbl; + + vb_fbc_c_tbl.daddr = 0; + vb_fbc_c_tbl.size = ALIGN(fbc_c_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_c_tbl); + if (ret) + goto free_vb_fbc_c_tbl; + + p_enc_info->vb_fbc_c_tbl = vb_fbc_c_tbl; + + if (avc_encoding) + sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE_AVC(buf_width, buf_height); + else + sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE(buf_width, buf_height); + vb_sub_sam_buf.size = ALIGN(sub_sampled_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + vb_sub_sam_buf.daddr = 0; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_sub_sam_buf); + if (ret) + goto free_vb_sam_buf; + + p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf; + + vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) + + (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH); + vb_task.daddr = 0; + if (p_enc_info->vb_task.size == 0) { + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task); + if (ret) + goto free_vb_task; + + p_enc_info->vb_task = vb_task; + + vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, + p_enc_info->vb_task.daddr); + vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_task.size); + } + + /* set sub-sampled buffer base addr */ + vpu_write_reg(inst->dev, W5_ADDR_SUB_SAMPLED_FB_BASE, vb_sub_sam_buf.daddr); + /* set sub-sampled buffer size for one frame */ + vpu_write_reg(inst->dev, W5_SUB_SAMPLED_ONE_FB_SIZE, sub_sampled_size); + + vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size); + + /* set stride of luma/chroma for compressed buffer */ + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + luma_stride = calculate_luma_stride(buf_width, bit_depth); + chroma_stride = calculate_chroma_stride(buf_width / 2, bit_depth); + } else { + luma_stride = calculate_luma_stride(p_open_param->pic_width, bit_depth); + chroma_stride = calculate_chroma_stride(p_open_param->pic_width / 2, bit_depth); + } + + vpu_write_reg(inst->dev, W5_FBC_STRIDE, luma_stride << 16 | chroma_stride); + vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, stride); + + remain = count; + cnt_8_chunk = DIV_ROUND_UP(count, 8); + idx = 0; + for (j = 0; j < cnt_8_chunk; j++) { + reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3); + vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val); + start_no = j * 8; + end_no = start_no + ((remain >= 8) ? 8 : remain) - 1; + + vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no); + + for (i = 0; i < 8 && i < remain; i++) { + vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), fb_arr[i + + start_no].buf_y); + vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4), + fb_arr[i + start_no].buf_cb); + /* luma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4), + vb_fbc_y_tbl.daddr + idx * fbc_y_tbl_size); + /* chroma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), + vb_fbc_c_tbl.daddr + idx * fbc_c_tbl_size); + + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), + vb_mv.daddr + idx * mv_col_size); + idx++; + } + remain -= i; + + ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL); + if (ret) + goto free_vb_mem; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); + if (ret) + goto free_vb_mem; + + return ret; + +free_vb_mem: + wave5_vdi_free_dma_memory(vpu_dev, &vb_task); +free_vb_task: + wave5_vdi_free_dma_memory(vpu_dev, &vb_sub_sam_buf); +free_vb_sam_buf: + wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_c_tbl); +free_vb_fbc_c_tbl: + wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_y_tbl); +free_vb_fbc_y_tbl: + wave5_vdi_free_dma_memory(vpu_dev, &vb_mv); + return ret; +} + +int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) +{ + u32 src_frame_format; + u32 reg_val = 0; + u32 src_stride_c = 0; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct frame_buffer *p_src_frame = option->source_frame; + struct enc_open_param *p_open_param = &p_enc_info->open_param; + bool justified = WTL_RIGHT_JUSTIFIED; + u32 format_no = WTL_PIXEL_8BIT; + int ret; + + vpu_write_reg(inst->dev, W5_CMD_ENC_BS_START_ADDR, option->pic_stream_buffer_addr); + vpu_write_reg(inst->dev, W5_CMD_ENC_BS_SIZE, option->pic_stream_buffer_size); + p_enc_info->stream_buf_start_addr = option->pic_stream_buffer_addr; + p_enc_info->stream_buf_size = option->pic_stream_buffer_size; + p_enc_info->stream_buf_end_addr = + option->pic_stream_buffer_addr + option->pic_stream_buffer_size; + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI); + /* secondary AXI */ + reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) | + (p_enc_info->sec_axi_info.use_enc_lf_enable << 15); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0); + + /* + * CODEOPT_ENC_VCL is used to implicitly encode header/headers to generate bitstream. + * (use ENC_PUT_VIDEO_HEADER for give_command to encode only a header) + */ + if (option->code_option.implicit_header_encode) + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION, + CODEOPT_ENC_HEADER_IMPLICIT | CODEOPT_ENC_VCL | + (option->code_option.encode_aud << 5) | + (option->code_option.encode_eos << 6) | + (option->code_option.encode_eob << 7)); + else + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION, + option->code_option.implicit_header_encode | + (option->code_option.encode_vcl << 1) | + (option->code_option.encode_vps << 2) | + (option->code_option.encode_sps << 3) | + (option->code_option.encode_pps << 4) | + (option->code_option.encode_aud << 5) | + (option->code_option.encode_eos << 6) | + (option->code_option.encode_eob << 7)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PIC_PARAM, 0); + + if (option->src_end_flag) + /* no more source images. */ + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, 0xFFFFFFFF); + else + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, option->src_idx); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_Y, p_src_frame->buf_y); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_U, p_src_frame->buf_cb); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_V, p_src_frame->buf_cr); + + switch (p_open_param->src_format) { + case FORMAT_420: + case FORMAT_422: + case FORMAT_YUYV: + case FORMAT_YVYU: + case FORMAT_UYVY: + case FORMAT_VYUY: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_8BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == FORMAT_422) ? src_stride_c * 2 : + src_stride_c; + break; + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_YUYV_P10_16BIT_MSB: + case FORMAT_YVYU_P10_16BIT_MSB: + case FORMAT_UYVY_P10_16BIT_MSB: + case FORMAT_VYUY_P10_16BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_16BIT_MSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_YUYV_P10_16BIT_LSB: + case FORMAT_YVYU_P10_16BIT_LSB: + case FORMAT_UYVY_P10_16BIT_LSB: + case FORMAT_VYUY_P10_16BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_16BIT_LSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_YUYV_P10_32BIT_MSB: + case FORMAT_YVYU_P10_32BIT_MSB: + case FORMAT_UYVY_P10_32BIT_MSB: + case FORMAT_VYUY_P10_32BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_32BIT_MSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_32BIT_LSB: + case FORMAT_422_P10_32BIT_LSB: + case FORMAT_YUYV_P10_32BIT_LSB: + case FORMAT_YVYU_P10_32BIT_LSB: + case FORMAT_UYVY_P10_32BIT_LSB: + case FORMAT_VYUY_P10_32BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_32BIT_LSB) ? src_stride_c * 2 : src_stride_c; + break; + default: + return -EINVAL; + } + + src_frame_format = (inst->cbcr_interleave << 1) | (inst->nv21); + switch (p_open_param->packed_format) { + case PACKED_YUYV: + src_frame_format = 4; + break; + case PACKED_YVYU: + src_frame_format = 5; + break; + case PACKED_UYVY: + src_frame_format = 6; + break; + case PACKED_VYUY: + src_frame_format = 7; + break; + default: + break; + } + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_STRIDE, + (p_src_frame->stride << 16) | src_stride_c); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_FORMAT, src_frame_format | + (format_no << 3) | (justified << 5) | (PIC_SRC_ENDIANNESS_BIG_ENDIAN << 6)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_LONGTERM_PIC, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_INFO, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_INFO, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR, 0); + + ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, ®_val, fail_res); + if (ret == -ETIMEDOUT) + return ret; + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result) +{ + int ret; + u32 encoding_success; + u32 reg_val; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: enc pic complete\n", __func__); + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + encoding_success = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS); + if (!encoding_success) { + result->error_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO); + return -EIO; + } + + result->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO); + + reg_val = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_TYPE); + result->pic_type = reg_val & 0xFFFF; + + result->enc_vcl_nut = vpu_read_reg(inst->dev, W5_RET_ENC_VCL_NUT); + /* + * To get the reconstructed frame use the following index on + * inst->frame_buf + */ + result->recon_frame_index = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_IDX); + result->enc_pic_byte = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_BYTE); + result->enc_src_idx = vpu_read_reg(inst->dev, W5_RET_ENC_USED_SRC_IDX); + p_enc_info->stream_wr_ptr = vpu_read_reg(inst->dev, W5_RET_ENC_WR_PTR); + p_enc_info->stream_rd_ptr = vpu_read_reg(inst->dev, W5_RET_ENC_RD_PTR); + + result->bitstream_buffer = vpu_read_reg(inst->dev, W5_RET_ENC_RD_PTR); + result->rd_ptr = p_enc_info->stream_rd_ptr; + result->wr_ptr = p_enc_info->stream_wr_ptr; + + /*result for header only(no vcl) encoding */ + if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY) + result->bitstream_size = result->enc_pic_byte; + else if (result->recon_frame_index < 0) + result->bitstream_size = 0; + else + result->bitstream_size = result->enc_pic_byte; + + result->enc_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_ENC_HOST_CMD_TICK); + result->enc_encode_end_tick = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_END_TICK); + + if (!p_enc_info->first_cycle_check) { + result->frame_cycle = (result->enc_encode_end_tick - result->enc_host_cmd_tick) * + p_enc_info->cycle_per_tick; + p_enc_info->first_cycle_check = true; + } else { + result->frame_cycle = + (result->enc_encode_end_tick - vpu_dev->last_performance_cycles) * + p_enc_info->cycle_per_tick; + if (vpu_dev->last_performance_cycles < result->enc_host_cmd_tick) + result->frame_cycle = (result->enc_encode_end_tick - + result->enc_host_cmd_tick) * p_enc_info->cycle_per_tick; + } + vpu_dev->last_performance_cycles = result->enc_encode_end_tick; + + return 0; +} + +int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res) +{ + return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res); +} + +static bool wave5_vpu_enc_check_common_param_valid(struct vpu_instance *inst, + struct enc_open_param *open_param) +{ + bool low_delay = true; + struct enc_wave_param *param = &open_param->wave_param; + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + u32 num_ctu_row = (open_param->pic_height + 64 - 1) / 64; + u32 num_ctu_col = (open_param->pic_width + 64 - 1) / 64; + u32 ctu_sz = num_ctu_col * num_ctu_row; + + if (inst->std == W_HEVC_ENC && low_delay && + param->decoding_refresh_type == DEC_REFRESH_TYPE_CRA) { + dev_warn(dev, + "dec_refresh_type(CRA) shouldn't be used together with low delay GOP\n"); + dev_warn(dev, "Suggested configuration parameter: decoding refresh type (IDR)\n"); + param->decoding_refresh_type = 2; + } + + if (param->wpp_enable && param->independ_slice_mode) { + unsigned int num_ctb_in_width = ALIGN(open_param->pic_width, 64) >> 6; + + if (param->independ_slice_mode_arg % num_ctb_in_width) { + dev_err(dev, "independ_slice_mode_arg %u must be a multiple of %u\n", + param->independ_slice_mode_arg, num_ctb_in_width); + return false; + } + } + + /* multi-slice & wpp */ + if (param->wpp_enable && param->depend_slice_mode) { + dev_err(dev, "wpp_enable && depend_slice_mode cannot be used simultaneously\n"); + return false; + } + + if (!param->independ_slice_mode && param->depend_slice_mode) { + dev_err(dev, "depend_slice_mode requires independ_slice_mode\n"); + return false; + } else if (param->independ_slice_mode && + param->depend_slice_mode == DEPEND_SLICE_MODE_RECOMMENDED && + param->independ_slice_mode_arg < param->depend_slice_mode_arg) { + dev_err(dev, "independ_slice_mode_arg: %u must be smaller than %u\n", + param->independ_slice_mode_arg, param->depend_slice_mode_arg); + return false; + } + + if (param->independ_slice_mode && param->independ_slice_mode_arg > 65535) { + dev_err(dev, "independ_slice_mode_arg: %u must be smaller than 65535\n", + param->independ_slice_mode_arg); + return false; + } + + if (param->depend_slice_mode && param->depend_slice_mode_arg > 65535) { + dev_err(dev, "depend_slice_mode_arg: %u must be smaller than 65535\n", + param->depend_slice_mode_arg); + return false; + } + + if (param->conf_win_top % 2) { + dev_err(dev, "conf_win_top: %u, must be a multiple of 2\n", param->conf_win_top); + return false; + } + + if (param->conf_win_bot % 2) { + dev_err(dev, "conf_win_bot: %u, must be a multiple of 2\n", param->conf_win_bot); + return false; + } + + if (param->conf_win_left % 2) { + dev_err(dev, "conf_win_left: %u, must be a multiple of 2\n", param->conf_win_left); + return false; + } + + if (param->conf_win_right % 2) { + dev_err(dev, "conf_win_right: %u, Must be a multiple of 2\n", + param->conf_win_right); + return false; + } + + if (param->lossless_enable && open_param->rc_enable) { + dev_err(dev, "option rate_control cannot be used with lossless_coding\n"); + return false; + } + + if (param->lossless_enable && !param->skip_intra_trans) { + dev_err(dev, "option intra_trans_skip must be enabled with lossless_coding\n"); + return false; + } + + /* intra refresh */ + if (param->intra_refresh_mode && param->intra_refresh_arg == 0) { + dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u must be > 0\n", + param->intra_refresh_mode, param->intra_refresh_arg); + return false; + } + switch (param->intra_refresh_mode) { + case REFRESH_MODE_CTU_ROWS: + if (param->intra_mb_refresh_arg > num_ctu_row) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTU_COLUMNS: + if (param->intra_refresh_arg > num_ctu_col) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTU_STEP_SIZE: + if (param->intra_refresh_arg > ctu_sz) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTUS: + if (param->intra_refresh_arg > ctu_sz) + goto invalid_refresh_argument; + if (param->lossless_enable) { + dev_err(dev, "mode: %u cannot be used lossless_enable", + param->intra_refresh_mode); + return false; + } + }; + return true; + +invalid_refresh_argument: + dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u > W(%u)xH(%u)\n", + param->intra_refresh_mode, param->intra_refresh_arg, + num_ctu_row, num_ctu_col); + return false; +} + +static bool wave5_vpu_enc_check_param_valid(struct vpu_device *vpu_dev, + struct enc_open_param *open_param) +{ + struct enc_wave_param *param = &open_param->wave_param; + + if (open_param->rc_enable) { + if (param->min_qp_i > param->max_qp_i || param->min_qp_p > param->max_qp_p || + param->min_qp_b > param->max_qp_b) { + dev_err(vpu_dev->dev, "Configuration failed because min_qp is greater than max_qp\n"); + dev_err(vpu_dev->dev, "Suggested configuration parameters: min_qp = max_qp\n"); + return false; + } + + if (open_param->bit_rate <= (int)open_param->frame_rate_info) { + dev_err(vpu_dev->dev, + "enc_bit_rate: %u must be greater than the frame_rate: %u\n", + open_param->bit_rate, (int)open_param->frame_rate_info); + return false; + } + } + + return true; +} + +int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param) +{ + u32 pic_width; + u32 pic_height; + s32 product_id = inst->dev->product; + struct vpu_attr *p_attr = &inst->dev->attr; + struct enc_wave_param *param; + + if (!open_param) + return -EINVAL; + + param = &open_param->wave_param; + pic_width = open_param->pic_width; + pic_height = open_param->pic_height; + + if (inst->id >= MAX_NUM_INSTANCE) { + dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n", + inst->id, MAX_NUM_INSTANCE); + return -EOPNOTSUPP; + } + + if (inst->std != W_HEVC_ENC && + !(inst->std == W_AVC_ENC && product_id == PRODUCT_ID_521)) { + dev_err(inst->dev->dev, "Unsupported encoder-codec & product combination\n"); + return -EOPNOTSUPP; + } + + if (param->internal_bit_depth == 10) { + if (inst->std == W_HEVC_ENC && !p_attr->support_hevc10bit_enc) { + dev_err(inst->dev->dev, + "Flag support_hevc10bit_enc must be set to encode 10bit HEVC\n"); + return -EOPNOTSUPP; + } else if (inst->std == W_AVC_ENC && !p_attr->support_avc10bit_enc) { + dev_err(inst->dev->dev, + "Flag support_avc10bit_enc must be set to encode 10bit AVC\n"); + return -EOPNOTSUPP; + } + } + + if (!open_param->frame_rate_info) { + dev_err(inst->dev->dev, "No frame rate information.\n"); + return -EINVAL; + } + + if (open_param->bit_rate > MAX_BIT_RATE) { + dev_err(inst->dev->dev, "Invalid encoding bit-rate: %u (valid: 0-%u)\n", + open_param->bit_rate, MAX_BIT_RATE); + return -EINVAL; + } + + if (pic_width < W5_MIN_ENC_PIC_WIDTH || pic_width > W5_MAX_ENC_PIC_WIDTH || + pic_height < W5_MIN_ENC_PIC_HEIGHT || pic_height > W5_MAX_ENC_PIC_HEIGHT) { + dev_err(inst->dev->dev, "Invalid encoding dimension: %ux%u\n", + pic_width, pic_height); + return -EINVAL; + } + + if (param->profile) { + if (inst->std == W_HEVC_ENC) { + if ((param->profile != HEVC_PROFILE_MAIN || + (param->profile == HEVC_PROFILE_MAIN && + param->internal_bit_depth > 8)) && + (param->profile != HEVC_PROFILE_MAIN10 || + (param->profile == HEVC_PROFILE_MAIN10 && + param->internal_bit_depth < 10)) && + param->profile != HEVC_PROFILE_STILLPICTURE) { + dev_err(inst->dev->dev, + "Invalid HEVC encoding profile: %u (bit-depth: %u)\n", + param->profile, param->internal_bit_depth); + return -EINVAL; + } + } else if (inst->std == W_AVC_ENC) { + if ((param->internal_bit_depth > 8 && + param->profile != H264_PROFILE_HIGH10)) { + dev_err(inst->dev->dev, + "Invalid AVC encoding profile: %u (bit-depth: %u)\n", + param->profile, param->internal_bit_depth); + return -EINVAL; + } + } + } + + if (param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) { + dev_err(inst->dev->dev, "Invalid decoding refresh type: %u (valid: 0-2)\n", + param->decoding_refresh_type); + return -EINVAL; + } + + if (param->intra_refresh_mode > REFRESH_MODE_CTUS) { + dev_err(inst->dev->dev, "Invalid intra refresh mode: %d (valid: 0-4)\n", + param->intra_refresh_mode); + return -EINVAL; + } + + if (inst->std == W_HEVC_ENC && param->independ_slice_mode && + param->depend_slice_mode > DEPEND_SLICE_MODE_BOOST) { + dev_err(inst->dev->dev, + "Can't combine slice modes: independent and fast dependent for HEVC\n"); + return -EINVAL; + } + + if (!param->disable_deblk) { + if (param->beta_offset_div2 < -6 || param->beta_offset_div2 > 6) { + dev_err(inst->dev->dev, "Invalid beta offset: %d (valid: -6-6)\n", + param->beta_offset_div2); + return -EINVAL; + } + + if (param->tc_offset_div2 < -6 || param->tc_offset_div2 > 6) { + dev_err(inst->dev->dev, "Invalid tc offset: %d (valid: -6-6)\n", + param->tc_offset_div2); + return -EINVAL; + } + } + + if (param->intra_qp > MAX_INTRA_QP) { + dev_err(inst->dev->dev, + "Invalid intra quantization parameter: %u (valid: 0-%u)\n", + param->intra_qp, MAX_INTRA_QP); + return -EINVAL; + } + + if (open_param->rc_enable) { + if (param->min_qp_i > MAX_INTRA_QP || param->max_qp_i > MAX_INTRA_QP || + param->min_qp_p > MAX_INTRA_QP || param->max_qp_p > MAX_INTRA_QP || + param->min_qp_b > MAX_INTRA_QP || param->max_qp_b > MAX_INTRA_QP) { + dev_err(inst->dev->dev, + "Invalid quantization parameter min/max values: " + "I: %u-%u, P: %u-%u, B: %u-%u (valid for each: 0-%u)\n", + param->min_qp_i, param->max_qp_i, param->min_qp_p, param->max_qp_p, + param->min_qp_b, param->max_qp_b, MAX_INTRA_QP); + return -EINVAL; + } + + if (param->hvs_qp_enable && param->hvs_max_delta_qp > MAX_HVS_MAX_DELTA_QP) { + dev_err(inst->dev->dev, + "Invalid HVS max delta quantization parameter: %u (valid: 0-%u)\n", + param->hvs_max_delta_qp, MAX_HVS_MAX_DELTA_QP); + return -EINVAL; + } + + if (open_param->vbv_buffer_size < MIN_VBV_BUFFER_SIZE || + open_param->vbv_buffer_size > MAX_VBV_BUFFER_SIZE) { + dev_err(inst->dev->dev, "VBV buffer size: %u (valid: %u-%u)\n", + open_param->vbv_buffer_size, MIN_VBV_BUFFER_SIZE, + MAX_VBV_BUFFER_SIZE); + return -EINVAL; + } + } + + if (!wave5_vpu_enc_check_common_param_valid(inst, open_param)) + return -EINVAL; + + if (!wave5_vpu_enc_check_param_valid(inst->dev, open_param)) + return -EINVAL; + + if (param->chroma_cb_qp_offset < -12 || param->chroma_cb_qp_offset > 12) { + dev_err(inst->dev->dev, + "Invalid chroma Cb quantization parameter offset: %d (valid: -12-12)\n", + param->chroma_cb_qp_offset); + return -EINVAL; + } + + if (param->chroma_cr_qp_offset < -12 || param->chroma_cr_qp_offset > 12) { + dev_err(inst->dev->dev, + "Invalid chroma Cr quantization parameter offset: %d (valid: -12-12)\n", + param->chroma_cr_qp_offset); + return -EINVAL; + } + + if (param->intra_refresh_mode == REFRESH_MODE_CTU_STEP_SIZE && !param->intra_refresh_arg) { + dev_err(inst->dev->dev, + "Intra refresh mode CTU step-size requires an argument\n"); + return -EINVAL; + } + + if (inst->std == W_HEVC_ENC) { + if (param->nr_intra_weight_y > MAX_INTRA_WEIGHT || + param->nr_intra_weight_cb > MAX_INTRA_WEIGHT || + param->nr_intra_weight_cr > MAX_INTRA_WEIGHT) { + dev_err(inst->dev->dev, + "Invalid intra weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n", + param->nr_intra_weight_y, param->nr_intra_weight_cb, + param->nr_intra_weight_cr, MAX_INTRA_WEIGHT); + return -EINVAL; + } + + if (param->nr_inter_weight_y > MAX_INTER_WEIGHT || + param->nr_inter_weight_cb > MAX_INTER_WEIGHT || + param->nr_inter_weight_cr > MAX_INTER_WEIGHT) { + dev_err(inst->dev->dev, + "Invalid inter weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n", + param->nr_inter_weight_y, param->nr_inter_weight_cb, + param->nr_inter_weight_cr, MAX_INTER_WEIGHT); + return -EINVAL; + } + } + + return 0; +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h new file mode 100644 index 000000000000..a15c6b2c3d8b --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h @@ -0,0 +1,732 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - wave5 register definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE5_REGISTER_DEFINE_H__ +#define __WAVE5_REGISTER_DEFINE_H__ + +enum W5_VPU_COMMAND { + W5_INIT_VPU = 0x0001, + W5_WAKEUP_VPU = 0x0002, + W5_SLEEP_VPU = 0x0004, + W5_CREATE_INSTANCE = 0x0008, /* queuing command */ + W5_FLUSH_INSTANCE = 0x0010, + W5_DESTROY_INSTANCE = 0x0020, /* queuing command */ + W5_INIT_SEQ = 0x0040, /* queuing command */ + W5_SET_FB = 0x0080, + W5_DEC_ENC_PIC = 0x0100, /* queuing command */ + W5_ENC_SET_PARAM = 0x0200, /* queuing command */ + W5_QUERY = 0x4000, + W5_UPDATE_BS = 0x8000, + W5_MAX_VPU_COMD = 0x10000, +}; + +enum query_opt { + GET_VPU_INFO = 0, + SET_WRITE_PROT = 1, + GET_RESULT = 2, + UPDATE_DISP_FLAG = 3, + GET_BW_REPORT = 4, + GET_BS_RD_PTR = 5, /* for decoder */ + GET_BS_WR_PTR = 6, /* for encoder */ + GET_SRC_BUF_FLAG = 7, /* for encoder */ + SET_BS_RD_PTR = 8, /* for decoder */ + GET_DEBUG_INFO = 0x61, +}; + +#define W5_REG_BASE 0x00000000 +#define W5_CMD_REG_BASE 0x00000100 +#define W5_CMD_REG_END 0x00000200 + +/* + * COMMON + * + * ---- + * + * Power on configuration + * PO_DEBUG_MODE [0] 1 - power on with debug mode + * USE_PO_CONF [3] 1 - use power-on-configuration + */ +#define W5_PO_CONF (W5_REG_BASE + 0x0000) +#define W5_VCPU_CUR_PC (W5_REG_BASE + 0x0004) +#define W5_VCPU_CUR_LR (W5_REG_BASE + 0x0008) +#define W5_VPU_PDBG_STEP_MASK_V (W5_REG_BASE + 0x000C) +#define W5_VPU_PDBG_CTRL (W5_REG_BASE + 0x0010) /* v_cpu debugger ctrl register */ +#define W5_VPU_PDBG_IDX_REG (W5_REG_BASE + 0x0014) /* v_cpu debugger index register */ +#define W5_VPU_PDBG_WDATA_REG (W5_REG_BASE + 0x0018) /* v_cpu debugger write data reg */ +#define W5_VPU_PDBG_RDATA_REG (W5_REG_BASE + 0x001C) /* v_cpu debugger read data reg */ + +#define W5_VPU_FIO_CTRL_ADDR (W5_REG_BASE + 0x0020) +#define W5_VPU_FIO_DATA (W5_REG_BASE + 0x0024) +#define W5_VPU_VINT_REASON_USR (W5_REG_BASE + 0x0030) +#define W5_VPU_VINT_REASON_CLR (W5_REG_BASE + 0x0034) +#define W5_VPU_HOST_INT_REQ (W5_REG_BASE + 0x0038) +#define W5_VPU_VINT_CLEAR (W5_REG_BASE + 0x003C) +#define W5_VPU_HINT_CLEAR (W5_REG_BASE + 0x0040) +#define W5_VPU_VPU_INT_STS (W5_REG_BASE + 0x0044) +#define W5_VPU_VINT_ENABLE (W5_REG_BASE + 0x0048) +#define W5_VPU_VINT_REASON (W5_REG_BASE + 0x004C) +#define W5_VPU_RESET_REQ (W5_REG_BASE + 0x0050) +#define W5_RST_BLOCK_CCLK(_core) BIT((_core)) +#define W5_RST_BLOCK_CCLK_ALL (0xff) +#define W5_RST_BLOCK_BCLK(_core) (0x100 << (_core)) +#define W5_RST_BLOCK_BCLK_ALL (0xff00) +#define W5_RST_BLOCK_ACLK(_core) (0x10000 << (_core)) +#define W5_RST_BLOCK_ACLK_ALL (0xff0000) +#define W5_RST_BLOCK_VCPU_ALL (0x3f000000) +#define W5_RST_BLOCK_ALL (0x3fffffff) +#define W5_VPU_RESET_STATUS (W5_REG_BASE + 0x0054) + +#define W5_VCPU_RESTART (W5_REG_BASE + 0x0058) +#define W5_VPU_CLK_MASK (W5_REG_BASE + 0x005C) + +/* REMAP_CTRL + * PAGE SIZE: [8:0] 0x001 - 4K + * 0x002 - 8K + * 0x004 - 16K + * ... + * 0x100 - 1M + * REGION ATTR1 [10] 0 - normal + * 1 - make bus error for the region + * REGION ATTR2 [11] 0 - normal + * 1 - bypass region + * REMAP INDEX [15:12] - 0 ~ 3 + * ENDIAN [19:16] - NOTE: Currently not supported in this driver + * AXI-ID [23:20] - upper AXI-ID + * BUS_ERROR [29] 0 - bypass + * 1 - make BUS_ERROR for unmapped region + * BYPASS_ALL [30] 1 - bypass all + * ENABLE [31] 1 - update control register[30:16] + */ +#define W5_VPU_REMAP_CTRL (W5_REG_BASE + 0x0060) +#define W5_VPU_REMAP_VADDR (W5_REG_BASE + 0x0064) +#define W5_VPU_REMAP_PADDR (W5_REG_BASE + 0x0068) +#define W5_VPU_REMAP_CORE_START (W5_REG_BASE + 0x006C) +#define W5_VPU_BUSY_STATUS (W5_REG_BASE + 0x0070) +#define W5_VPU_HALT_STATUS (W5_REG_BASE + 0x0074) +#define W5_VPU_VCPU_STATUS (W5_REG_BASE + 0x0078) +#define W5_VPU_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0094) +/* + * assign vpu_config0 = {conf_map_converter_reg, // [31] + * conf_map_converter_sig, // [30] + * 8'd0, // [29:22] + * conf_std_switch_en, // [21] + * conf_bg_detect, // [20] + * conf_3dnr_en, // [19] + * conf_one_axi_en, // [18] + * conf_sec_axi_en, // [17] + * conf_bus_info, // [16] + * conf_afbc_en, // [15] + * conf_afbc_version_id, // [14:12] + * conf_fbc_en, // [11] + * conf_fbc_version_id, // [10:08] + * conf_scaler_en, // [07] + * conf_scaler_version_id, // [06:04] + * conf_bwb_en, // [03] + * 3'd0}; // [02:00] + */ +#define W5_VPU_RET_VPU_CONFIG0 (W5_REG_BASE + 0x0098) +/* + * assign vpu_config1 = {4'd0, // [31:28] + * conf_perf_timer_en, // [27] + * conf_multi_core_en, // [26] + * conf_gcu_en, // [25] + * conf_cu_report, // [24] + * 4'd0, // [23:20] + * conf_vcore_id_3, // [19] + * conf_vcore_id_2, // [18] + * conf_vcore_id_1, // [17] + * conf_vcore_id_0, // [16] + * conf_bwb_opt, // [15] + * 7'd0, // [14:08] + * conf_cod_std_en_reserved_7, // [7] + * conf_cod_std_en_reserved_6, // [6] + * conf_cod_std_en_reserved_5, // [5] + * conf_cod_std_en_reserved_4, // [4] + * conf_cod_std_en_reserved_3, // [3] + * conf_cod_std_en_reserved_2, // [2] + * conf_cod_std_en_vp9, // [1] + * conf_cod_std_en_hevc}; // [0] + * } + */ +#define W5_VPU_RET_VPU_CONFIG1 (W5_REG_BASE + 0x009C) + +#define W5_VPU_DBG_REG0 (W5_REG_BASE + 0x00f0) +#define W5_VPU_DBG_REG1 (W5_REG_BASE + 0x00f4) +#define W5_VPU_DBG_REG2 (W5_REG_BASE + 0x00f8) +#define W5_VPU_DBG_REG3 (W5_REG_BASE + 0x00fc) + +/************************************************************************/ +/* PRODUCT INFORMATION */ +/************************************************************************/ +#define W5_PRODUCT_NAME (W5_REG_BASE + 0x1040) +#define W5_PRODUCT_NUMBER (W5_REG_BASE + 0x1044) + +/************************************************************************/ +/* DECODER/ENCODER COMMON */ +/************************************************************************/ +#define W5_COMMAND (W5_REG_BASE + 0x0100) +#define W5_COMMAND_OPTION (W5_REG_BASE + 0x0104) +#define W5_QUERY_OPTION (W5_REG_BASE + 0x0104) +#define W5_RET_SUCCESS (W5_REG_BASE + 0x0108) +#define W5_RET_FAIL_REASON (W5_REG_BASE + 0x010C) +#define W5_RET_QUEUE_FAIL_REASON (W5_REG_BASE + 0x0110) +#define W5_CMD_INSTANCE_INFO (W5_REG_BASE + 0x0110) + +#define W5_RET_QUEUE_STATUS (W5_REG_BASE + 0x01E0) +#define W5_RET_BS_EMPTY_INST (W5_REG_BASE + 0x01E4) +#define W5_RET_QUEUE_CMD_DONE_INST (W5_REG_BASE + 0x01E8) +#define W5_RET_STAGE0_INSTANCE_INFO (W5_REG_BASE + 0x01EC) +#define W5_RET_STAGE1_INSTANCE_INFO (W5_REG_BASE + 0x01F0) +#define W5_RET_STAGE2_INSTANCE_INFO (W5_REG_BASE + 0x01F4) + +#define W5_RET_SEQ_DONE_INSTANCE_INFO (W5_REG_BASE + 0x01FC) + +#define W5_BS_OPTION (W5_REG_BASE + 0x0120) + +/* return info when QUERY (GET_RESULT) for en/decoder */ +#define W5_RET_VLC_BUF_SIZE (W5_REG_BASE + 0x01B0) +/* return info when QUERY (GET_RESULT) for en/decoder */ +#define W5_RET_PARAM_BUF_SIZE (W5_REG_BASE + 0x01B4) + +/* set when SET_FB for en/decoder */ +#define W5_CMD_SET_FB_ADDR_TASK_BUF (W5_REG_BASE + 0x01D4) +#define W5_CMD_SET_FB_TASK_BUF_SIZE (W5_REG_BASE + 0x01D8) +/************************************************************************/ +/* INIT_VPU - COMMON */ +/************************************************************************/ +/* note: W5_ADDR_CODE_BASE should be aligned to 4KB */ +#define W5_ADDR_CODE_BASE (W5_REG_BASE + 0x0110) +#define W5_CODE_SIZE (W5_REG_BASE + 0x0114) +#define W5_CODE_PARAM (W5_REG_BASE + 0x0118) +#define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C) +#define W5_TEMP_SIZE (W5_REG_BASE + 0x0120) +#define W5_HW_OPTION (W5_REG_BASE + 0x012C) +#define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180) + +/************************************************************************/ +/* CREATE_INSTANCE - COMMON */ +/************************************************************************/ +#define W5_ADDR_WORK_BASE (W5_REG_BASE + 0x0114) +#define W5_WORK_SIZE (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_BS_START_ADDR (W5_REG_BASE + 0x011C) +#define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120) +#define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124) +#define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130) +#define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134) +#define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138) +#define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C) +#define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140) + +/************************************************************************/ +/* DECODER - INIT_SEQ */ +/************************************************************************/ +#define W5_BS_RD_PTR (W5_REG_BASE + 0x0118) +#define W5_BS_WR_PTR (W5_REG_BASE + 0x011C) +/************************************************************************/ +/* SET_FRAME_BUF */ +/************************************************************************/ +/* SET_FB_OPTION 0x00 REGISTER FRAMEBUFFERS + * 0x01 UPDATE FRAMEBUFFER, just one framebuffer(linear, fbc and mvcol) + */ +#define W5_SFB_OPTION (W5_REG_BASE + 0x0104) +#define W5_COMMON_PIC_INFO (W5_REG_BASE + 0x0118) +#define W5_PIC_SIZE (W5_REG_BASE + 0x011C) +#define W5_SET_FB_NUM (W5_REG_BASE + 0x0120) +#define W5_EXTRA_PIC_INFO (W5_REG_BASE + 0x0124) + +#define W5_ADDR_LUMA_BASE0 (W5_REG_BASE + 0x0134) +#define W5_ADDR_CB_BASE0 (W5_REG_BASE + 0x0138) +#define W5_ADDR_CR_BASE0 (W5_REG_BASE + 0x013C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET0 (W5_REG_BASE + 0x013C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET0 (W5_REG_BASE + 0x0140) +#define W5_ADDR_LUMA_BASE1 (W5_REG_BASE + 0x0144) +#define W5_ADDR_CB_ADDR1 (W5_REG_BASE + 0x0148) +#define W5_ADDR_CR_ADDR1 (W5_REG_BASE + 0x014C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET1 (W5_REG_BASE + 0x014C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET1 (W5_REG_BASE + 0x0150) +#define W5_ADDR_LUMA_BASE2 (W5_REG_BASE + 0x0154) +#define W5_ADDR_CB_ADDR2 (W5_REG_BASE + 0x0158) +#define W5_ADDR_CR_ADDR2 (W5_REG_BASE + 0x015C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET2 (W5_REG_BASE + 0x015C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET2 (W5_REG_BASE + 0x0160) +#define W5_ADDR_LUMA_BASE3 (W5_REG_BASE + 0x0164) +#define W5_ADDR_CB_ADDR3 (W5_REG_BASE + 0x0168) +#define W5_ADDR_CR_ADDR3 (W5_REG_BASE + 0x016C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET3 (W5_REG_BASE + 0x016C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET3 (W5_REG_BASE + 0x0170) +#define W5_ADDR_LUMA_BASE4 (W5_REG_BASE + 0x0174) +#define W5_ADDR_CB_ADDR4 (W5_REG_BASE + 0x0178) +#define W5_ADDR_CR_ADDR4 (W5_REG_BASE + 0x017C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET4 (W5_REG_BASE + 0x017C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET4 (W5_REG_BASE + 0x0180) +#define W5_ADDR_LUMA_BASE5 (W5_REG_BASE + 0x0184) +#define W5_ADDR_CB_ADDR5 (W5_REG_BASE + 0x0188) +#define W5_ADDR_CR_ADDR5 (W5_REG_BASE + 0x018C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET5 (W5_REG_BASE + 0x018C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET5 (W5_REG_BASE + 0x0190) +#define W5_ADDR_LUMA_BASE6 (W5_REG_BASE + 0x0194) +#define W5_ADDR_CB_ADDR6 (W5_REG_BASE + 0x0198) +#define W5_ADDR_CR_ADDR6 (W5_REG_BASE + 0x019C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET6 (W5_REG_BASE + 0x019C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET6 (W5_REG_BASE + 0x01A0) +#define W5_ADDR_LUMA_BASE7 (W5_REG_BASE + 0x01A4) +#define W5_ADDR_CB_ADDR7 (W5_REG_BASE + 0x01A8) +#define W5_ADDR_CR_ADDR7 (W5_REG_BASE + 0x01AC) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET7 (W5_REG_BASE + 0x01AC) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET7 (W5_REG_BASE + 0x01B0) +#define W5_ADDR_MV_COL0 (W5_REG_BASE + 0x01B4) +#define W5_ADDR_MV_COL1 (W5_REG_BASE + 0x01B8) +#define W5_ADDR_MV_COL2 (W5_REG_BASE + 0x01BC) +#define W5_ADDR_MV_COL3 (W5_REG_BASE + 0x01C0) +#define W5_ADDR_MV_COL4 (W5_REG_BASE + 0x01C4) +#define W5_ADDR_MV_COL5 (W5_REG_BASE + 0x01C8) +#define W5_ADDR_MV_COL6 (W5_REG_BASE + 0x01CC) +#define W5_ADDR_MV_COL7 (W5_REG_BASE + 0x01D0) + +/* UPDATE_FB */ +/* CMD_SET_FB_STRIDE [15:0] - FBC framebuffer stride + * [31:15] - linear framebuffer stride + */ +#define W5_CMD_SET_FB_STRIDE (W5_REG_BASE + 0x0118) +#define W5_CMD_SET_FB_INDEX (W5_REG_BASE + 0x0120) +#define W5_ADDR_LUMA_BASE (W5_REG_BASE + 0x0134) +#define W5_ADDR_CB_BASE (W5_REG_BASE + 0x0138) +#define W5_ADDR_CR_BASE (W5_REG_BASE + 0x013C) +#define W5_ADDR_MV_COL (W5_REG_BASE + 0x0140) +#define W5_ADDR_FBC_Y_BASE (W5_REG_BASE + 0x0144) +#define W5_ADDR_FBC_C_BASE (W5_REG_BASE + 0x0148) +#define W5_ADDR_FBC_Y_OFFSET (W5_REG_BASE + 0x014C) +#define W5_ADDR_FBC_C_OFFSET (W5_REG_BASE + 0x0150) + +/************************************************************************/ +/* DECODER - DEC_PIC */ +/************************************************************************/ +#define W5_CMD_DEC_VCORE_INFO (W5_REG_BASE + 0x0194) +/* sequence change enable mask register + * CMD_SEQ_CHANGE_ENABLE_FLAG [5] profile_idc + * [16] pic_width/height_in_luma_sample + * [19] sps_max_dec_pic_buffering, max_num_reorder, max_latency_increase + */ +#define W5_CMD_SEQ_CHANGE_ENABLE_FLAG (W5_REG_BASE + 0x0128) +#define W5_CMD_DEC_USER_MASK (W5_REG_BASE + 0x012C) +#define W5_CMD_DEC_TEMPORAL_ID_PLUS1 (W5_REG_BASE + 0x0130) +#define W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1 (W5_REG_BASE + 0x0134) +#define W5_USE_SEC_AXI (W5_REG_BASE + 0x0150) + +/************************************************************************/ +/* DECODER - QUERY : GET_VPU_INFO */ +/************************************************************************/ +#define W5_RET_FW_VERSION (W5_REG_BASE + 0x0118) +#define W5_RET_PRODUCT_NAME (W5_REG_BASE + 0x011C) +#define W5_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0120) +#define W5_RET_STD_DEF0 (W5_REG_BASE + 0x0124) +#define W5_RET_STD_DEF1 (W5_REG_BASE + 0x0128) +#define W5_RET_CONF_FEATURE (W5_REG_BASE + 0x012C) +#define W5_RET_CONF_DATE (W5_REG_BASE + 0x0130) +#define W5_RET_CONF_REVISION (W5_REG_BASE + 0x0134) +#define W5_RET_CONF_TYPE (W5_REG_BASE + 0x0138) +#define W5_RET_PRODUCT_ID (W5_REG_BASE + 0x013C) +#define W5_RET_CUSTOMER_ID (W5_REG_BASE + 0x0140) + +/************************************************************************/ +/* DECODER - QUERY : GET_RESULT */ +/************************************************************************/ +#define W5_CMD_DEC_ADDR_REPORT_BASE (W5_REG_BASE + 0x0114) +#define W5_CMD_DEC_REPORT_SIZE (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_REPORT_PARAM (W5_REG_BASE + 0x011C) + +#define W5_RET_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C) +#define W5_RET_DEC_SEQ_PARAM (W5_REG_BASE + 0x0120) +#define W5_RET_DEC_COLOR_SAMPLE_INFO (W5_REG_BASE + 0x0124) +#define W5_RET_DEC_ASPECT_RATIO (W5_REG_BASE + 0x0128) +#define W5_RET_DEC_BIT_RATE (W5_REG_BASE + 0x012C) +#define W5_RET_DEC_FRAME_RATE_NR (W5_REG_BASE + 0x0130) +#define W5_RET_DEC_FRAME_RATE_DR (W5_REG_BASE + 0x0134) +#define W5_RET_DEC_NUM_REQUIRED_FB (W5_REG_BASE + 0x0138) +#define W5_RET_DEC_NUM_REORDER_DELAY (W5_REG_BASE + 0x013C) +#define W5_RET_DEC_SUB_LAYER_INFO (W5_REG_BASE + 0x0140) +#define W5_RET_DEC_NOTIFICATION (W5_REG_BASE + 0x0144) +/* + * USER_DATA_FLAGS for HEVC/H264 only. + * Bits: + * [1] - User data buffer full boolean + * [2] - VUI parameter flag + * [4] - Pic_timing SEI flag + * [5] - 1st user_data_registed_itu_t_t35 prefix SEI flag + * [6] - user_data_unregistered prefix SEI flag + * [7] - 1st user_data_registed_itu_t_t35 suffix SEI flag + * [8] - user_data_unregistered suffix SEI flag + * [10]- mastering_display_color_volume prefix SEI flag + * [11]- chroma_resampling_display_color_volume prefix SEI flag + * [12]- knee_function_info SEI flag + * [13]- tone_mapping_info prefix SEI flag + * [14]- film_grain_characteristics_info prefix SEI flag + * [15]- content_light_level_info prefix SEI flag + * [16]- color_remapping_info prefix SEI flag + * [28]- 2nd user_data_registed_itu_t_t35 prefix SEI flag + * [29]- 3rd user_data_registed_itu_t_t35 prefix SEI flag + * [30]- 2nd user_data_registed_itu_t_t35 suffix SEI flag + * [31]- 3rd user_data_registed_itu_t_t35 suffix SEI flag + */ +#define W5_RET_DEC_USERDATA_IDC (W5_REG_BASE + 0x0148) +#define W5_RET_DEC_PIC_SIZE (W5_REG_BASE + 0x014C) +#define W5_RET_DEC_CROP_TOP_BOTTOM (W5_REG_BASE + 0x0150) +#define W5_RET_DEC_CROP_LEFT_RIGHT (W5_REG_BASE + 0x0154) +/* + * #define W5_RET_DEC_AU_START_POS (W5_REG_BASE + 0x0158) + * => Access unit (AU) Bitstream start position + * #define W5_RET_DEC_AU_END_POS (W5_REG_BASE + 0x015C) + * => Access unit (AU) Bitstream end position + */ + +/* + * Decoded picture type: + * reg_val & 0x7 => picture type + * (reg_val >> 4) & 0x3f => VCL NAL unit type + * (reg_val >> 31) & 0x1 => output_flag + * 16 << ((reg_val >> 10) & 0x3) => ctu_size + */ +#define W5_RET_DEC_PIC_TYPE (W5_REG_BASE + 0x0160) +#define W5_RET_DEC_PIC_POC (W5_REG_BASE + 0x0164) +/* + * #define W5_RET_DEC_RECOVERY_POINT (W5_REG_BASE + 0x0168) + * => HEVC recovery point + * reg_val & 0xff => number of signed recovery picture order counts + * (reg_val >> 16) & 0x1 => exact match flag + * (reg_val >> 17) & 0x1 => broken link flag + * (reg_val >> 18) & 0x1 => exist flag + */ +#define W5_RET_DEC_DEBUG_INDEX (W5_REG_BASE + 0x016C) +#define W5_RET_DEC_DECODED_INDEX (W5_REG_BASE + 0x0170) +#define W5_RET_DEC_DISPLAY_INDEX (W5_REG_BASE + 0x0174) +/* + * #define W5_RET_DEC_REALLOC_INDEX (W5_REG_BASE + 0x0178) + * => display picture index in decoded picture buffer + * reg_val & 0xf => display picture index for FBC buffer (by reordering) + */ +#define W5_RET_DEC_DISP_IDC (W5_REG_BASE + 0x017C) +/* + * #define W5_RET_DEC_ERR_CTB_NUM (W5_REG_BASE + 0x0180) + * => Number of error CTUs + * reg_val >> 16 => erroneous CTUs in bitstream + * reg_val & 0xffff => total CTUs in bitstream + * + * #define W5_RET_DEC_PIC_PARAM (W5_REG_BASE + 0x01A0) + * => Bitstream sequence/picture parameter information (AV1 only) + * reg_val & 0x1 => intrabc tool enable + * (reg_val >> 1) & 0x1 => screen content tools enable + */ +#define W5_RET_DEC_HOST_CMD_TICK (W5_REG_BASE + 0x01B8) +/* + * #define W5_RET_DEC_SEEK_START_TICK (W5_REG_BASE + 0x01BC) + * #define W5_RET_DEC_SEEK_END_TICK (W5_REG_BASE + 0x01C0) + * => Start and end ticks for seeking slices of the picture + * #define W5_RET_DEC_PARSING_START_TICK (W5_REG_BASE + 0x01C4) + * #define W5_RET_DEC_PARSING_END_TICK (W5_REG_BASE + 0x01C8) + * => Start and end ticks for parsing slices of the picture + * #define W5_RET_DEC_DECODING_START_TICK (W5_REG_BASE + 0x01CC) + * => Start tick for decoding slices of the picture + */ +#define W5_RET_DEC_DECODING_ENC_TICK (W5_REG_BASE + 0x01D0) +#define W5_RET_DEC_WARN_INFO (W5_REG_BASE + 0x01D4) +#define W5_RET_DEC_ERR_INFO (W5_REG_BASE + 0x01D8) +#define W5_RET_DEC_DECODING_SUCCESS (W5_REG_BASE + 0x01DC) + +/************************************************************************/ +/* DECODER - FLUSH_INSTANCE */ +/************************************************************************/ +#define W5_CMD_FLUSH_INST_OPT (W5_REG_BASE + 0x104) + +/************************************************************************/ +/* DECODER - QUERY : UPDATE_DISP_FLAG */ +/************************************************************************/ +#define W5_CMD_DEC_SET_DISP_IDC (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_CLR_DISP_IDC (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* DECODER - QUERY : SET_BS_RD_PTR */ +/************************************************************************/ +#define W5_RET_QUERY_DEC_SET_BS_RD_PTR (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* DECODER - QUERY : GET_BS_RD_PTR */ +/************************************************************************/ +#define W5_RET_QUERY_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* QUERY : GET_DEBUG_INFO */ +/************************************************************************/ +#define W5_RET_QUERY_DEBUG_PRI_REASON (W5_REG_BASE + 0x114) + +/************************************************************************/ +/* GDI register for debugging */ +/************************************************************************/ +#define W5_GDI_BASE 0x8800 +#define W5_GDI_BUS_CTRL (W5_GDI_BASE + 0x0F0) +#define W5_GDI_BUS_STATUS (W5_GDI_BASE + 0x0F4) + +#define W5_BACKBONE_BASE_VCPU 0xFE00 +#define W5_BACKBONE_BUS_CTRL_VCPU (W5_BACKBONE_BASE_VCPU + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCPU (W5_BACKBONE_BASE_VCPU + 0x014) +#define W5_BACKBONE_PROG_AXI_ID (W5_BACKBONE_BASE_VCPU + 0x00C) + +#define W5_BACKBONE_PROC_EXT_ADDR (W5_BACKBONE_BASE_VCPU + 0x0C0) +#define W5_BACKBONE_AXI_PARAM (W5_BACKBONE_BASE_VCPU + 0x0E0) + +#define W5_BACKBONE_BASE_VCORE0 0x8E00 +#define W5_BACKBONE_BUS_CTRL_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x014) + +#define W5_BACKBONE_BASE_VCORE1 0x9E00 /* for dual-core product */ +#define W5_BACKBONE_BUS_CTRL_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x014) + +#define W5_COMBINED_BACKBONE_BASE 0xFE00 +#define W5_COMBINED_BACKBONE_BUS_CTRL (W5_COMBINED_BACKBONE_BASE + 0x010) +#define W5_COMBINED_BACKBONE_BUS_STATUS (W5_COMBINED_BACKBONE_BASE + 0x014) + +/************************************************************************/ +/* */ +/* for ENCODER */ +/* */ +/************************************************************************/ +#define W5_RET_STAGE3_INSTANCE_INFO (W5_REG_BASE + 0x1F8) +/************************************************************************/ +/* ENCODER - CREATE_INSTANCE */ +/************************************************************************/ +/* 0x114 ~ 0x124 : defined above (CREATE_INSTANCE COMMON) */ +#define W5_CMD_ENC_VCORE_INFO (W5_REG_BASE + 0x0194) +#define W5_CMD_ENC_SRC_OPTIONS (W5_REG_BASE + 0x0128) + +/************************************************************************/ +/* ENCODER - SET_FB */ +/************************************************************************/ +#define W5_FBC_STRIDE (W5_REG_BASE + 0x128) +#define W5_ADDR_SUB_SAMPLED_FB_BASE (W5_REG_BASE + 0x12C) +#define W5_SUB_SAMPLED_ONE_FB_SIZE (W5_REG_BASE + 0x130) + +/************************************************************************/ +/* ENCODER - ENC_SET_PARAM (COMMON & CHANGE_PARAM) */ +/************************************************************************/ +#define W5_CMD_ENC_SEQ_SET_PARAM_OPTION (W5_REG_BASE + 0x104) +#define W5_CMD_ENC_SEQ_SET_PARAM_ENABLE (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_SEQ_SRC_SIZE (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN (W5_REG_BASE + 0x120) +#define W5_CMD_ENC_SEQ_SPS_PARAM (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_SEQ_PPS_PARAM (W5_REG_BASE + 0x128) +#define W5_CMD_ENC_SEQ_GOP_PARAM (W5_REG_BASE + 0x12C) +#define W5_CMD_ENC_SEQ_INTRA_PARAM (W5_REG_BASE + 0x130) +#define W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT (W5_REG_BASE + 0x134) +#define W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_SEQ_RDO_PARAM (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_SEQ_INDEPENDENT_SLICE (W5_REG_BASE + 0x140) +#define W5_CMD_ENC_SEQ_DEPENDENT_SLICE (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_SEQ_INTRA_REFRESH (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_SEQ_INPUT_SRC_PARAM (W5_REG_BASE + 0x14C) + +#define W5_CMD_ENC_SEQ_RC_FRAME_RATE (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_SEQ_RC_TARGET_RATE (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_SEQ_RC_PARAM (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_SEQ_RC_MIN_MAX_QP (W5_REG_BASE + 0x15C) +#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3 (W5_REG_BASE + 0x160) +#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7 (W5_REG_BASE + 0x164) +#define W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP (W5_REG_BASE + 0x168) +#define W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM (W5_REG_BASE + 0x16C) + +#define W5_CMD_ENC_SEQ_ROT_PARAM (W5_REG_BASE + 0x170) +#define W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK (W5_REG_BASE + 0x174) +#define W5_CMD_ENC_SEQ_TIME_SCALE (W5_REG_BASE + 0x178) +#define W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE (W5_REG_BASE + 0x17C) + +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU04 (W5_REG_BASE + 0x184) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU08 (W5_REG_BASE + 0x188) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU16 (W5_REG_BASE + 0x18C) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU32 (W5_REG_BASE + 0x190) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU08 (W5_REG_BASE + 0x194) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU16 (W5_REG_BASE + 0x198) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU32 (W5_REG_BASE + 0x19C) +#define W5_CMD_ENC_SEQ_NR_PARAM (W5_REG_BASE + 0x1A0) +#define W5_CMD_ENC_SEQ_NR_WEIGHT (W5_REG_BASE + 0x1A4) +#define W5_CMD_ENC_SEQ_BG_PARAM (W5_REG_BASE + 0x1A8) +#define W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR (W5_REG_BASE + 0x1AC) +#define W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR (W5_REG_BASE + 0x1B0) +#define W5_CMD_ENC_SEQ_VUI_HRD_PARAM (W5_REG_BASE + 0x180) +#define W5_CMD_ENC_SEQ_VUI_RBSP_ADDR (W5_REG_BASE + 0x1B8) +#define W5_CMD_ENC_SEQ_HRD_RBSP_ADDR (W5_REG_BASE + 0x1BC) + +/************************************************************************/ +/* ENCODER - ENC_SET_PARAM (CUSTOM_GOP) */ +/************************************************************************/ +#define W5_CMD_ENC_CUSTOM_GOP_PARAM (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_0 (W5_REG_BASE + 0x120) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_1 (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_2 (W5_REG_BASE + 0x128) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_3 (W5_REG_BASE + 0x12C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_4 (W5_REG_BASE + 0x130) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_5 (W5_REG_BASE + 0x134) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_6 (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_7 (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_8 (W5_REG_BASE + 0x140) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_9 (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_10 (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_11 (W5_REG_BASE + 0x14C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_12 (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_13 (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_14 (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_15 (W5_REG_BASE + 0x15C) + +/************************************************************************/ +/* ENCODER - ENC_PIC */ +/************************************************************************/ +#define W5_CMD_ENC_BS_START_ADDR (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_BS_SIZE (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_PIC_USE_SEC_AXI (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_PIC_REPORT_PARAM (W5_REG_BASE + 0x128) + +#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_PIC_SRC_PIC_IDX (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_PIC_SRC_ADDR_Y (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_PIC_SRC_ADDR_U (W5_REG_BASE + 0x14C) +#define W5_CMD_ENC_PIC_SRC_ADDR_V (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_PIC_SRC_STRIDE (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_PIC_SRC_FORMAT (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_PIC_SRC_AXI_SEL (W5_REG_BASE + 0x160) +#define W5_CMD_ENC_PIC_CODE_OPTION (W5_REG_BASE + 0x164) +#define W5_CMD_ENC_PIC_PIC_PARAM (W5_REG_BASE + 0x168) +#define W5_CMD_ENC_PIC_LONGTERM_PIC (W5_REG_BASE + 0x16C) +#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y (W5_REG_BASE + 0x170) +#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C (W5_REG_BASE + 0x174) +#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y (W5_REG_BASE + 0x178) +#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C (W5_REG_BASE + 0x17C) +#define W5_CMD_ENC_PIC_CF50_Y_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x190) +#define W5_CMD_ENC_PIC_CF50_CB_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x194) +#define W5_CMD_ENC_PIC_CF50_CR_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x198) +#define W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x180) +#define W5_CMD_ENC_PIC_PREFIX_SEI_INFO (W5_REG_BASE + 0x184) +#define W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x188) +#define W5_CMD_ENC_PIC_SUFFIX_SEI_INFO (W5_REG_BASE + 0x18c) + +/************************************************************************/ +/* ENCODER - QUERY (GET_RESULT) */ +/************************************************************************/ +#define W5_RET_ENC_NUM_REQUIRED_FB (W5_REG_BASE + 0x11C) +#define W5_RET_ENC_MIN_SRC_BUF_NUM (W5_REG_BASE + 0x120) +#define W5_RET_ENC_PIC_TYPE (W5_REG_BASE + 0x124) +/* + * #define W5_RET_ENC_PIC_POC (W5_REG_BASE + 0x128) + * => picture order count value of current encoded picture + */ +#define W5_RET_ENC_PIC_IDX (W5_REG_BASE + 0x12C) +/* + * #define W5_RET_ENC_PIC_SLICE_NUM (W5_REG_BASE + 0x130) + * reg_val & 0xffff = total independent slice segment number (16 bits) + * (reg_val >> 16) & 0xffff = total dependent slice segment number (16 bits) + * + * #define W5_RET_ENC_PIC_SKIP (W5_REG_BASE + 0x134) + * reg_val & 0xfe = picture skip flag (7 bits) + * + * #define W5_RET_ENC_PIC_NUM_INTRA (W5_REG_BASE + 0x138) + * => number of intra blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_NUM_MERGE (W5_REG_BASE + 0x13C) + * => number of merge blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_NUM_SKIP (W5_REG_BASE + 0x144) + * => number of skip blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_AVG_CTU_QP (W5_REG_BASE + 0x148) + * => Average CTU QP value (32 bits) + */ +#define W5_RET_ENC_PIC_BYTE (W5_REG_BASE + 0x14C) +/* + * #define W5_RET_ENC_GOP_PIC_IDX (W5_REG_BASE + 0x150) + * => picture index in group of pictures + */ +#define W5_RET_ENC_USED_SRC_IDX (W5_REG_BASE + 0x154) +/* + * #define W5_RET_ENC_PIC_NUM (W5_REG_BASE + 0x158) + * => encoded picture number + */ +#define W5_RET_ENC_VCL_NUT (W5_REG_BASE + 0x15C) +/* + * Only for H264: + * #define W5_RET_ENC_PIC_DIST_LOW (W5_REG_BASE + 0x164) + * => lower 32 bits of the sum of squared difference between source Y picture + * and reconstructed Y picture + * #define W5_RET_ENC_PIC_DIST_HIGH (W5_REG_BASE + 0x168) + * => upper 32 bits of the sum of squared difference between source Y picture + * and reconstructed Y picture + */ +#define W5_RET_ENC_PIC_MAX_LATENCY_PICS (W5_REG_BASE + 0x16C) + +#define W5_RET_ENC_HOST_CMD_TICK (W5_REG_BASE + 0x1B8) +/* + * #define W5_RET_ENC_PREPARE_START_TICK (W5_REG_BASE + 0x1BC) + * #define W5_RET_ENC_PREPARE_END_TICK (W5_REG_BASE + 0x1C0) + * => Start and end ticks for preparing slices of the picture + * #define W5_RET_ENC_PROCESSING_START_TICK (W5_REG_BASE + 0x1C4) + * #define W5_RET_ENC_PROCESSING_END_TICK (W5_REG_BASE + 0x1C8) + * => Start and end ticks for processing slices of the picture + * #define W5_RET_ENC_ENCODING_START_TICK (W5_REG_BASE + 0x1CC) + * => Start tick for encoding slices of the picture + */ +#define W5_RET_ENC_ENCODING_END_TICK (W5_REG_BASE + 0x1D0) + +#define W5_RET_ENC_WARN_INFO (W5_REG_BASE + 0x1D4) +#define W5_RET_ENC_ERR_INFO (W5_REG_BASE + 0x1D8) +#define W5_RET_ENC_ENCODING_SUCCESS (W5_REG_BASE + 0x1DC) + +/************************************************************************/ +/* ENCODER - QUERY (GET_BS_WR_PTR) */ +/************************************************************************/ +#define W5_RET_ENC_RD_PTR (W5_REG_BASE + 0x114) +#define W5_RET_ENC_WR_PTR (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_REASON_SEL (W5_REG_BASE + 0x11C) + +/************************************************************************/ +/* ENCODER - QUERY (GET_BW_REPORT) */ +/************************************************************************/ +#define RET_QUERY_BW_PRP_AXI_READ (W5_REG_BASE + 0x118) +#define RET_QUERY_BW_PRP_AXI_WRITE (W5_REG_BASE + 0x11C) +#define RET_QUERY_BW_FBD_Y_AXI_READ (W5_REG_BASE + 0x120) +#define RET_QUERY_BW_FBC_Y_AXI_WRITE (W5_REG_BASE + 0x124) +#define RET_QUERY_BW_FBD_C_AXI_READ (W5_REG_BASE + 0x128) +#define RET_QUERY_BW_FBC_C_AXI_WRITE (W5_REG_BASE + 0x12C) +#define RET_QUERY_BW_PRI_AXI_READ (W5_REG_BASE + 0x130) +#define RET_QUERY_BW_PRI_AXI_WRITE (W5_REG_BASE + 0x134) +#define RET_QUERY_BW_SEC_AXI_READ (W5_REG_BASE + 0x138) +#define RET_QUERY_BW_SEC_AXI_WRITE (W5_REG_BASE + 0x13C) +#define RET_QUERY_BW_PROC_AXI_READ (W5_REG_BASE + 0x140) +#define RET_QUERY_BW_PROC_AXI_WRITE (W5_REG_BASE + 0x144) +#define RET_QUERY_BW_BWB_AXI_WRITE (W5_REG_BASE + 0x148) +#define W5_CMD_BW_OPTION (W5_REG_BASE + 0x14C) + +/************************************************************************/ +/* ENCODER - QUERY (GET_SRC_FLAG) */ +/************************************************************************/ +#define W5_RET_RELEASED_SRC_INSTANCE (W5_REG_BASE + 0x1EC) + +#define W5_ENC_PIC_SUB_FRAME_SYNC_IF (W5_REG_BASE + 0x0300) + +#endif /* __WAVE5_REGISTER_DEFINE_H__ */ diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.c b/drivers/media/platform/chips-media/wave5/wave5-vdi.c new file mode 100644 index 000000000000..3809f70bc0b4 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - low level access functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include "wave5-vdi.h" +#include "wave5-vpu.h" +#include "wave5-regdefine.h" +#include + +static int wave5_vdi_allocate_common_memory(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + if (!vpu_dev->common_mem.vaddr) { + int ret; + + vpu_dev->common_mem.size = SIZE_COMMON; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem); + if (ret) { + dev_err(dev, "unable to allocate common buffer\n"); + return ret; + } + } + + dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n", + &vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr); + + return 0; +} + +int wave5_vdi_init(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret; + + ret = wave5_vdi_allocate_common_memory(dev); + if (ret < 0) { + dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n"); + return ret; + } + + if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) { + WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code); + return -EOPNOTSUPP; + } + + /* if BIT processor is not running. */ + if (wave5_vdi_read_register(vpu_dev, W5_VCPU_CUR_PC) == 0) { + int i; + + for (i = 0; i < 64; i++) + wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0); + } + + dev_dbg(dev, "[VDI] driver initialized successfully\n"); + + return 0; +} + +int wave5_vdi_release(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + vpu_dev->vdb_register = NULL; + wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem); + + return 0; +} + +void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data) +{ + writel(data, vpu_dev->vdb_register + addr); +} + +unsigned int wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr) +{ + return readl(vpu_dev->vdb_register + addr); +} + +int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + if (!vb || !vb->vaddr) { + dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__); + return -EINVAL; + } + + memset(vb->vaddr, 0, vb->size); + return vb->size; +} + +int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset, + u8 *data, size_t len) +{ + if (!vb || !vb->vaddr) { + dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__); + return -EINVAL; + } + + if (offset > vb->size || len > vb->size || offset + len > vb->size) { + dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__); + return -ENOSPC; + } + + memcpy(vb->vaddr + offset, data, len); + + return len; +} + +int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + void *vaddr; + dma_addr_t daddr; + + if (!vb->size) { + dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__); + return -EINVAL; + } + + vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + vb->vaddr = vaddr; + vb->daddr = daddr; + + return 0; +} + +int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + if (vb->size == 0) + return -EINVAL; + + if (!vb->vaddr) + dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__); + else + dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr); + + memset(vb, 0, sizeof(*vb)); + + return 0; +} + +int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count, + size_t size) +{ + struct vpu_buf vb_buf; + int i, ret = 0; + + vb_buf.size = size; + + for (i = 0; i < count; i++) { + if (array[i].size == size) + continue; + + if (array[i].size != 0) + wave5_vdi_free_dma_memory(vpu_dev, &array[i]); + + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_buf); + if (ret) + return -ENOMEM; + array[i] = vb_buf; + } + + for (i = count; i < MAX_REG_FRAME; i++) + wave5_vdi_free_dma_memory(vpu_dev, &array[i]); + + return 0; +} + +void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev) +{ + struct vpu_buf *vb = &vpu_dev->sram_buf; + + if (!vpu_dev->sram_pool || !vpu_dev->sram_size) + return; + + if (!vb->vaddr) { + vb->size = vpu_dev->sram_size; + vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size, + &vb->daddr); + if (!vb->vaddr) + vb->size = 0; + } + + dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n", + __func__, &vb->daddr, vb->size, vb->vaddr); +} + +void wave5_vdi_free_sram(struct vpu_device *vpu_dev) +{ + struct vpu_buf *vb = &vpu_dev->sram_buf; + + if (!vb->size || !vb->vaddr) + return; + + if (vb->vaddr) + gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, + vb->size); + + memset(vb, 0, sizeof(*vb)); +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.h b/drivers/media/platform/chips-media/wave5/wave5-vdi.h new file mode 100644 index 000000000000..3984ef3f1f96 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - low level access functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef _VDI_H_ +#define _VDI_H_ + +#include "wave5-vpuconfig.h" +#include +#include +#include + +/************************************************************************/ +/* COMMON REGISTERS */ +/************************************************************************/ +#define VPU_PRODUCT_CODE_REGISTER 0x1044 + +/* system register write */ +#define vpu_write_reg(VPU_INST, ADDR, DATA) wave5_vdi_write_register(VPU_INST, ADDR, DATA) +/* system register read */ +#define vpu_read_reg(CORE, ADDR) wave5_vdi_read_register(CORE, ADDR) + +struct vpu_buf { + size_t size; + dma_addr_t daddr; + void *vaddr; +}; + +int wave5_vdi_init(struct device *dev); +int wave5_vdi_release(struct device *dev); //this function may be called only at system off. + +#endif //#ifndef _VDI_H_ diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c new file mode 100644 index 000000000000..86b3993722db --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c @@ -0,0 +1,960 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - helper functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include "wave5-vpuapi.h" +#include "wave5-regdefine.h" +#include "wave5.h" + +#define DECODE_ALL_TEMPORAL_LAYERS 0 +#define DECODE_ALL_SPATIAL_LAYERS 0 + +static int wave5_initialize_vpu(struct device *dev, u8 *code, size_t size) +{ + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (wave5_vpu_is_init(vpu_dev)) { + wave5_vpu_re_init(dev, (void *)code, size); + ret = -EBUSY; + goto err_out; + } + + ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT); + if (ret) + goto err_out; + + ret = wave5_vpu_init(dev, (void *)code, size); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + return ret; +} + +int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size) +{ + if (!bitcode || size == 0) + return -EINVAL; + + return wave5_initialize_vpu(dev, bitcode, size); +} + +int wave5_vpu_flush_instance(struct vpu_instance *inst) +{ + int ret = 0; + int retry = 0; + + ret = mutex_lock_interruptible(&inst->dev->hw_lock); + if (ret) + return ret; + do { + /* + * Repeat the FLUSH command until the firmware reports that the + * VPU isn't running anymore + */ + ret = wave5_vpu_hw_flush_instance(inst); + if (ret < 0 && ret != -EBUSY) { + dev_warn(inst->dev->dev, "Flush of %s instance with id: %d fail: %d\n", + inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id, + ret); + mutex_unlock(&inst->dev->hw_lock); + return ret; + } + if (ret == -EBUSY && retry++ >= MAX_FIRMWARE_CALL_RETRY) { + dev_warn(inst->dev->dev, "Flush of %s instance with id: %d timed out!\n", + inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id); + mutex_unlock(&inst->dev->hw_lock); + return -ETIMEDOUT; + } + } while (ret != 0); + mutex_unlock(&inst->dev->hw_lock); + + return ret; +} + +int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id) +{ + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + ret = -EINVAL; + goto err_out; + } + + if (product_id) + *product_id = vpu_dev->product; + ret = wave5_vpu_get_version(vpu_dev, revision); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + return ret; +} + +static int wave5_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param) +{ + if (inst->id >= MAX_NUM_INSTANCE) { + dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n", + inst->id, MAX_NUM_INSTANCE); + return -EOPNOTSUPP; + } + + if (param->bitstream_buffer % 8) { + dev_err(inst->dev->dev, + "Bitstream buffer must be aligned to a multiple of 8\n"); + return -EINVAL; + } + + if (param->bitstream_buffer_size % 1024 || + param->bitstream_buffer_size < MIN_BITSTREAM_BUFFER_SIZE) { + dev_err(inst->dev->dev, + "Bitstream buffer size must be aligned to a multiple of 1024 and have a minimum size of %d\n", + MIN_BITSTREAM_BUFFER_SIZE); + return -EINVAL; + } + + return 0; +} + +int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + dma_addr_t buffer_addr; + size_t buffer_size; + + ret = wave5_check_dec_open_param(inst, open_param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + p_dec_info = &inst->codec_info->dec_info; + memcpy(&p_dec_info->open_param, open_param, sizeof(struct dec_open_param)); + + buffer_addr = open_param->bitstream_buffer; + buffer_size = open_param->bitstream_buffer_size; + p_dec_info->stream_wr_ptr = buffer_addr; + p_dec_info->stream_rd_ptr = buffer_addr; + p_dec_info->stream_buf_start_addr = buffer_addr; + p_dec_info->stream_buf_size = buffer_size; + p_dec_info->stream_buf_end_addr = buffer_addr + buffer_size; + p_dec_info->reorder_enable = TRUE; + p_dec_info->temp_id_select_mode = TEMPORAL_ID_MODE_ABSOLUTE; + p_dec_info->target_temp_id = DECODE_ALL_TEMPORAL_LAYERS; + p_dec_info->target_spatial_id = DECODE_ALL_SPATIAL_LAYERS; + + ret = wave5_vpu_build_up_dec_param(inst, open_param); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +static int reset_auxiliary_buffers(struct vpu_instance *inst, unsigned int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + if (index >= MAX_REG_FRAME) + return 1; + + if (p_dec_info->vb_mv[index].size == 0 && p_dec_info->vb_fbc_y_tbl[index].size == 0 && + p_dec_info->vb_fbc_c_tbl[index].size == 0) + return 1; + + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[index]); + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[index]); + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[index]); + + return 0; +} + +int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + int retry = 0; + struct vpu_device *vpu_dev = inst->dev; + int i; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + do { + ret = wave5_vpu_dec_finish_seq(inst, fail_res); + if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_warn(inst->dev->dev, "dec_finish_seq timed out\n"); + goto unlock_and_return; + } + + if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && + retry++ >= MAX_FIRMWARE_CALL_RETRY) { + ret = -ETIMEDOUT; + goto unlock_and_return; + } + } while (ret != 0); + + dev_dbg(inst->dev->dev, "%s: dec_finish_seq complete\n", __func__); + + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work); + + for (i = 0 ; i < MAX_REG_FRAME; i++) { + ret = reset_auxiliary_buffers(inst, i); + if (ret) { + ret = 0; + break; + } + } + + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task); + +unlock_and_return: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_dec_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_dec_get_seq_info(inst, info); + if (!ret) + p_dec_info->initial_info_obtained = true; + + info->rd_ptr = wave5_dec_get_rd_ptr(inst); + info->wr_ptr = p_dec_info->stream_wr_ptr; + + p_dec_info->initial_info = *info; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs, + int num_of_display_fbs, int stride, int height) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + struct frame_buffer *fb; + + if (num_of_decoding_fbs >= WAVE5_MAX_FBS || num_of_display_fbs >= WAVE5_MAX_FBS) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + p_dec_info->num_of_decoding_fbs = num_of_decoding_fbs; + p_dec_info->num_of_display_fbs = num_of_display_fbs; + p_dec_info->stride = stride; + + if (!p_dec_info->initial_info_obtained) + return -EINVAL; + + if (stride < p_dec_info->initial_info.pic_width || (stride % 8 != 0) || + height < p_dec_info->initial_info.pic_height) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + fb = inst->frame_buf; + ret = wave5_vpu_dec_register_framebuffer(inst, &fb[p_dec_info->num_of_decoding_fbs], + LINEAR_FRAME_MAP, p_dec_info->num_of_display_fbs); + if (ret) + goto err_out; + + ret = wave5_vpu_dec_register_framebuffer(inst, &fb[0], COMPRESSED_FRAME_MAP, + p_dec_info->num_of_decoding_fbs); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr, + dma_addr_t *pwr_ptr, size_t *size) +{ + struct dec_info *p_dec_info; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + int room; + struct vpu_device *vpu_dev = inst->dev; + int ret; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + rd_ptr = wave5_dec_get_rd_ptr(inst); + mutex_unlock(&vpu_dev->hw_lock); + + wr_ptr = p_dec_info->stream_wr_ptr; + + if (wr_ptr < rd_ptr) + room = rd_ptr - wr_ptr; + else + room = (p_dec_info->stream_buf_end_addr - wr_ptr) + + (rd_ptr - p_dec_info->stream_buf_start_addr); + room--; + + if (prd_ptr) + *prd_ptr = rd_ptr; + if (pwr_ptr) + *pwr_ptr = wr_ptr; + if (size) + *size = room; + + return 0; +} + +int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size) +{ + struct dec_info *p_dec_info; + dma_addr_t wr_ptr; + dma_addr_t rd_ptr; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!inst->codec_info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + wr_ptr = p_dec_info->stream_wr_ptr; + rd_ptr = p_dec_info->stream_rd_ptr; + + if (size > 0) { + if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size) + return -EINVAL; + + wr_ptr += size; + + if (wr_ptr > p_dec_info->stream_buf_end_addr) { + u32 room = wr_ptr - p_dec_info->stream_buf_end_addr; + + wr_ptr = p_dec_info->stream_buf_start_addr; + wr_ptr += room; + } else if (wr_ptr == p_dec_info->stream_buf_end_addr) { + wr_ptr = p_dec_info->stream_buf_start_addr; + } + + p_dec_info->stream_wr_ptr = wr_ptr; + p_dec_info->stream_rd_ptr = rd_ptr; + } + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_vpu_dec_set_bitstream_flag(inst, (size == 0)); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (p_dec_info->stride == 0) /* this means frame buffers have not been registered. */ + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_decode(inst, res_fail); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_dec_set_rd_ptr(inst, addr); + + p_dec_info->stream_rd_ptr = addr; + if (update_wr_ptr) + p_dec_info->stream_wr_ptr = addr; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst) +{ + int ret; + dma_addr_t rd_ptr; + + ret = mutex_lock_interruptible(&inst->dev->hw_lock); + if (ret) + return ret; + + rd_ptr = wave5_dec_get_rd_ptr(inst); + + mutex_unlock(&inst->dev->hw_lock); + + return rd_ptr; +} + +int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_rect rect_info; + u32 val; + u32 decoded_index; + u32 disp_idx; + u32 max_dec_index; + struct vpu_device *vpu_dev = inst->dev; + struct dec_output_info *disp_info; + + if (!info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + memset(info, 0, sizeof(*info)); + + ret = wave5_vpu_dec_get_result(inst, info); + if (ret) { + info->rd_ptr = p_dec_info->stream_rd_ptr; + info->wr_ptr = p_dec_info->stream_wr_ptr; + goto err_out; + } + + decoded_index = info->index_frame_decoded; + + /* calculate display frame region */ + val = 0; + rect_info.left = 0; + rect_info.right = 0; + rect_info.top = 0; + rect_info.bottom = 0; + + if (decoded_index < WAVE5_MAX_FBS) { + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) + rect_info = p_dec_info->initial_info.pic_crop_rect; + + if (inst->std == W_HEVC_DEC) + p_dec_info->dec_out_info[decoded_index].decoded_poc = info->decoded_poc; + + p_dec_info->dec_out_info[decoded_index].rc_decoded = rect_info; + } + info->rc_decoded = rect_info; + + disp_idx = info->index_frame_display; + disp_info = &p_dec_info->dec_out_info[disp_idx]; + if (info->index_frame_display >= 0 && info->index_frame_display < WAVE5_MAX_FBS) { + if (info->index_frame_display != info->index_frame_decoded) { + /* + * when index_frame_decoded < 0, and index_frame_display >= 0 + * info->dec_pic_width and info->dec_pic_height are still valid + * but those of p_dec_info->dec_out_info[disp_idx] are invalid in VP9 + */ + info->disp_pic_width = disp_info->dec_pic_width; + info->disp_pic_height = disp_info->dec_pic_height; + } else { + info->disp_pic_width = info->dec_pic_width; + info->disp_pic_height = info->dec_pic_height; + } + + info->rc_display = disp_info->rc_decoded; + + } else { + info->rc_display.left = 0; + info->rc_display.right = 0; + info->rc_display.top = 0; + info->rc_display.bottom = 0; + info->disp_pic_width = 0; + info->disp_pic_height = 0; + } + + p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst); + p_dec_info->frame_display_flag = vpu_read_reg(vpu_dev, W5_RET_DEC_DISP_IDC); + + val = p_dec_info->num_of_decoding_fbs; //fb_offset + + max_dec_index = (p_dec_info->num_of_decoding_fbs > p_dec_info->num_of_display_fbs) ? + p_dec_info->num_of_decoding_fbs : p_dec_info->num_of_display_fbs; + + if (info->index_frame_display >= 0 && + info->index_frame_display < (int)max_dec_index) + info->disp_frame = inst->frame_buf[val + info->index_frame_display]; + + info->rd_ptr = p_dec_info->stream_rd_ptr; + info->wr_ptr = p_dec_info->stream_wr_ptr; + info->frame_display_flag = p_dec_info->frame_display_flag; + + info->sequence_no = p_dec_info->initial_info.sequence_no; + if (decoded_index < WAVE5_MAX_FBS) + p_dec_info->dec_out_info[decoded_index] = *info; + + if (disp_idx < WAVE5_MAX_FBS) + info->disp_frame.sequence_no = info->sequence_no; + + if (info->sequence_changed) { + memcpy((void *)&p_dec_info->initial_info, (void *)&p_dec_info->new_seq_info, + sizeof(struct dec_initial_info)); + p_dec_info->initial_info.sequence_no++; + } + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (index >= p_dec_info->num_of_display_fbs) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_dec_clr_disp_flag(inst, index); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret = 0; + struct vpu_device *vpu_dev = inst->dev; + + if (index >= p_dec_info->num_of_display_fbs) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_dec_set_disp_flag(inst, index); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index) +{ + if (index >= MAX_REG_FRAME) + return -EINVAL; + + if (inst->frame_vbuf[index].size == 0) + return -EINVAL; + + wave5_vdi_free_dma_memory(inst->dev, &inst->frame_vbuf[index]); + + return 0; +} + +int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret = 0; + + switch (cmd) { + case DEC_GET_QUEUE_STATUS: { + struct queue_status_info *queue_info = parameter; + + queue_info->instance_queue_count = p_dec_info->instance_queue_count; + queue_info->report_queue_count = p_dec_info->report_queue_count; + break; + } + case DEC_RESET_FRAMEBUF_INFO: { + int i; + + for (i = 0; i < MAX_REG_FRAME; i++) { + ret = wave5_vpu_dec_reset_framebuffer(inst, i); + if (ret) + break; + } + + for (i = 0; i < MAX_REG_FRAME; i++) { + ret = reset_auxiliary_buffers(inst, i); + if (ret) + break; + } + + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); + break; + } + case DEC_GET_SEQ_INFO: { + struct dec_initial_info *seq_info = parameter; + + *seq_info = p_dec_info->initial_info; + break; + } + + default: + return -EINVAL; + } + + return ret; +} + +int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param) +{ + struct enc_info *p_enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave5_vpu_enc_check_open_param(inst, open_param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + p_enc_info = &inst->codec_info->enc_info; + p_enc_info->open_param = *open_param; + + ret = wave5_vpu_build_up_enc_param(vpu_dev->dev, inst, open_param); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + int retry = 0; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + do { + ret = wave5_vpu_enc_finish_seq(inst, fail_res); + if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_warn(inst->dev->dev, "enc_finish_seq timed out\n"); + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + + if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && + retry++ >= MAX_FIRMWARE_CALL_RETRY) { + mutex_unlock(&vpu_dev->hw_lock); + return -ETIMEDOUT; + } + } while (ret != 0); + + dev_dbg(inst->dev->dev, "%s: enc_finish_seq complete\n", __func__); + + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work); + + if (inst->std == W_HEVC_ENC || inst->std == W_AVC_ENC) { + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_sub_sam_buf); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_mv); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_y_tbl); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_c_tbl); + } + + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task); + + mutex_unlock(&vpu_dev->hw_lock); + + return 0; +} + +int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num, + unsigned int stride, int height, + enum tiled_map_type map_type) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + unsigned int size_luma, size_chroma; + int i; + + if (p_enc_info->stride) + return -EINVAL; + + if (!p_enc_info->initial_info_obtained) + return -EINVAL; + + if (num < p_enc_info->initial_info.min_frame_buffer_count) + return -EINVAL; + + if (stride == 0 || stride % 8 != 0) + return -EINVAL; + + if (height <= 0) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_enc_info->num_frame_buffers = num; + p_enc_info->stride = stride; + + size_luma = stride * height; + size_chroma = ALIGN(stride / 2, 16) * height; + + for (i = 0; i < num; i++) { + if (!inst->frame_buf[i].update_fb_info) + continue; + + inst->frame_buf[i].update_fb_info = false; + inst->frame_buf[i].stride = stride; + inst->frame_buf[i].height = height; + inst->frame_buf[i].map_type = COMPRESSED_FRAME_MAP; + inst->frame_buf[i].buf_y_size = size_luma; + inst->frame_buf[i].buf_cb = inst->frame_buf[i].buf_y + size_luma; + inst->frame_buf[i].buf_cb_size = size_chroma; + inst->frame_buf[i].buf_cr_size = 0; + } + + ret = wave5_vpu_enc_register_framebuffer(inst->dev->dev, inst, &inst->frame_buf[0], + COMPRESSED_FRAME_MAP, + p_enc_info->num_frame_buffers); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +static int wave5_check_enc_param(struct vpu_instance *inst, struct enc_param *param) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + if (!param) + return -EINVAL; + + if (!param->source_frame) + return -EINVAL; + + if (p_enc_info->open_param.bit_rate == 0 && inst->std == W_HEVC_ENC) { + if (param->pic_stream_buffer_addr % 16 || param->pic_stream_buffer_size == 0) + return -EINVAL; + } + if (param->pic_stream_buffer_addr % 8 || param->pic_stream_buffer_size == 0) + return -EINVAL; + + return 0; +} + +int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, u32 *fail_res) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + + if (p_enc_info->stride == 0) /* this means frame buffers have not been registered. */ + return -EINVAL; + + ret = wave5_check_enc_param(inst, param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_enc_info->pts_map[param->src_idx] = param->pts; + + ret = wave5_vpu_encode(inst, param, fail_res); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_get_result(inst, info); + if (ret) { + info->pts = 0; + goto unlock; + } + + if (info->recon_frame_index >= 0) + info->pts = p_enc_info->pts_map[info->enc_src_idx]; + +unlock: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + switch (cmd) { + case ENABLE_ROTATION: + p_enc_info->rotation_enable = true; + break; + case ENABLE_MIRRORING: + p_enc_info->mirror_enable = true; + break; + case SET_MIRROR_DIRECTION: { + enum mirror_direction mir_dir; + + mir_dir = *(enum mirror_direction *)parameter; + if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR && + mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER) + return -EINVAL; + p_enc_info->mirror_direction = mir_dir; + break; + } + case SET_ROTATION_ANGLE: { + int angle; + + angle = *(int *)parameter; + if (angle && angle != 90 && angle != 180 && angle != 270) + return -EINVAL; + if (p_enc_info->initial_info_obtained && (angle == 90 || angle == 270)) + return -EINVAL; + p_enc_info->rotation_angle = angle; + break; + } + case ENC_GET_QUEUE_STATUS: { + struct queue_status_info *queue_info = parameter; + + queue_info->instance_queue_count = p_enc_info->instance_queue_count; + queue_info->report_queue_count = p_enc_info->report_queue_count; + break; + } + default: + return -EINVAL; + } + return 0; +} + +int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_get_seq_info(inst, info); + if (ret) { + p_enc_info->initial_info_obtained = false; + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + + p_enc_info->initial_info_obtained = true; + p_enc_info->initial_info = *info; + + mutex_unlock(&vpu_dev->hw_lock); + + return 0; +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h new file mode 100644 index 000000000000..352f6e904e50 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h @@ -0,0 +1,870 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - helper definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef VPUAPI_H_INCLUDED +#define VPUAPI_H_INCLUDED + +#include +#include +#include +#include +#include +#include "wave5-vpuerror.h" +#include "wave5-vpuconfig.h" +#include "wave5-vdi.h" + +enum product_id { + PRODUCT_ID_521, + PRODUCT_ID_511, + PRODUCT_ID_517, + PRODUCT_ID_NONE, +}; + +struct vpu_attr; + +enum vpu_instance_type { + VPU_INST_TYPE_DEC = 0, + VPU_INST_TYPE_ENC = 1 +}; + +enum vpu_instance_state { + VPU_INST_STATE_NONE = 0, + VPU_INST_STATE_OPEN = 1, + VPU_INST_STATE_INIT_SEQ = 2, + VPU_INST_STATE_PIC_RUN = 3, + VPU_INST_STATE_STOP = 4 +}; + +/* Maximum available on hardware. */ +#define WAVE5_MAX_FBS 32 + +#define MAX_REG_FRAME (WAVE5_MAX_FBS * 2) + +#define WAVE5_DEC_HEVC_BUF_SIZE(_w, _h) (DIV_ROUND_UP(_w, 64) * DIV_ROUND_UP(_h, 64) * 256 + 64) +#define WAVE5_DEC_AVC_BUF_SIZE(_w, _h) ((((ALIGN(_w, 256) / 16) * (ALIGN(_h, 16) / 16)) + 16) * 80) + +#define WAVE5_FBC_LUMA_TABLE_SIZE(_w, _h) (ALIGN(_h, 64) * ALIGN(_w, 256) / 32) +#define WAVE5_FBC_CHROMA_TABLE_SIZE(_w, _h) (ALIGN((_h), 64) * ALIGN((_w) / 2, 256) / 32) +#define WAVE5_ENC_AVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) * ALIGN(_h, 64) / 32) +#define WAVE5_ENC_HEVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) / 64 * ALIGN(_h, 64) / 64 * 128) + +/* + * common struct and definition + */ +enum cod_std { + STD_AVC = 0, + STD_HEVC = 12, + STD_MAX +}; + +enum wave_std { + W_HEVC_DEC = 0x00, + W_HEVC_ENC = 0x01, + W_AVC_DEC = 0x02, + W_AVC_ENC = 0x03, + STD_UNKNOWN = 0xFF +}; + +enum set_param_option { + OPT_COMMON = 0, /* SET_PARAM command option for encoding sequence */ + OPT_CUSTOM_GOP = 1, /* SET_PARAM command option for setting custom GOP */ + OPT_CUSTOM_HEADER = 2, /* SET_PARAM command option for setting custom VPS/SPS/PPS */ + OPT_VUI = 3, /* SET_PARAM command option for encoding VUI */ + OPT_CHANGE_PARAM = 0x10, +}; + +/************************************************************************/ +/* PROFILE & LEVEL */ +/************************************************************************/ +/* HEVC */ +#define HEVC_PROFILE_MAIN 1 +#define HEVC_PROFILE_MAIN10 2 +#define HEVC_PROFILE_STILLPICTURE 3 +#define HEVC_PROFILE_MAIN10_STILLPICTURE 2 + +/* H.264 profile for encoder*/ +#define H264_PROFILE_BP 1 +#define H264_PROFILE_MP 2 +#define H264_PROFILE_EXTENDED 3 +#define H264_PROFILE_HP 4 +#define H264_PROFILE_HIGH10 5 +#define H264_PROFILE_HIGH422 6 +#define H264_PROFILE_HIGH444 7 + +/************************************************************************/ +/* error codes */ +/************************************************************************/ + +/************************************************************************/ +/* utility macros */ +/************************************************************************/ + +/* Initialize sequence firmware command mode */ +#define INIT_SEQ_NORMAL 1 + +/* Decode firmware command mode */ +#define DEC_PIC_NORMAL 0 + +/* bit_alloc_mode */ +#define BIT_ALLOC_MODE_FIXED_RATIO 2 + +/* bit_rate */ +#define MAX_BIT_RATE 700000000 + +/* decoding_refresh_type */ +#define DEC_REFRESH_TYPE_NON_IRAP 0 +#define DEC_REFRESH_TYPE_CRA 1 +#define DEC_REFRESH_TYPE_IDR 2 + +/* depend_slice_mode */ +#define DEPEND_SLICE_MODE_RECOMMENDED 1 +#define DEPEND_SLICE_MODE_BOOST 2 +#define DEPEND_SLICE_MODE_FAST 3 + +/* hvs_max_delta_qp */ +#define MAX_HVS_MAX_DELTA_QP 51 + +/* intra_refresh_mode */ +#define REFRESH_MODE_CTU_ROWS 1 +#define REFRESH_MODE_CTU_COLUMNS 2 +#define REFRESH_MODE_CTU_STEP_SIZE 3 +#define REFRESH_MODE_CTUS 4 + +/* intra_mb_refresh_mode */ +#define REFRESH_MB_MODE_NONE 0 +#define REFRESH_MB_MODE_CTU_ROWS 1 +#define REFRESH_MB_MODE_CTU_COLUMNS 2 +#define REFRESH_MB_MODE_CTU_STEP_SIZE 3 + +/* intra_qp */ +#define MAX_INTRA_QP 63 + +/* nr_inter_weight_* */ +#define MAX_INTER_WEIGHT 31 + +/* nr_intra_weight_* */ +#define MAX_INTRA_WEIGHT 31 + +/* nr_noise_sigma_* */ +#define MAX_NOISE_SIGMA 255 + +/* bitstream_buffer_size */ +#define MIN_BITSTREAM_BUFFER_SIZE 1024 +#define MIN_BITSTREAM_BUFFER_SIZE_WAVE521 (1024 * 64) + +/* vbv_buffer_size */ +#define MIN_VBV_BUFFER_SIZE 10 +#define MAX_VBV_BUFFER_SIZE 3000 + +#define BUFFER_MARGIN 4096 + +#define MAX_FIRMWARE_CALL_RETRY 10 + +#define VDI_LITTLE_ENDIAN 0x0 + +/* + * Parameters of DEC_SET_SEQ_CHANGE_MASK + */ +#define SEQ_CHANGE_ENABLE_PROFILE BIT(5) +#define SEQ_CHANGE_ENABLE_SIZE BIT(16) +#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18) +#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19) +#define SEQ_CHANGE_ENABLE_ASPECT_RATIO BIT(21) +#define SEQ_CHANGE_ENABLE_VIDEO_SIGNAL BIT(23) +#define SEQ_CHANGE_ENABLE_VUI_TIMING_INFO BIT(29) + +#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE | \ + SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT) + +#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT | \ + SEQ_CHANGE_ENABLE_ASPECT_RATIO | \ + SEQ_CHANGE_ENABLE_VIDEO_SIGNAL | \ + SEQ_CHANGE_ENABLE_VUI_TIMING_INFO) + +#define DISPLAY_IDX_FLAG_SEQ_END -1 +#define DISPLAY_IDX_FLAG_NO_FB -3 +#define DECODED_IDX_FLAG_NO_FB -1 +#define DECODED_IDX_FLAG_SKIP -2 + +#define RECON_IDX_FLAG_ENC_END -1 +#define RECON_IDX_FLAG_ENC_DELAY -2 +#define RECON_IDX_FLAG_HEADER_ONLY -3 +#define RECON_IDX_FLAG_CHANGE_PARAM -4 + +enum codec_command { + ENABLE_ROTATION, + ENABLE_MIRRORING, + SET_MIRROR_DIRECTION, + SET_ROTATION_ANGLE, + DEC_GET_QUEUE_STATUS, + ENC_GET_QUEUE_STATUS, + DEC_RESET_FRAMEBUF_INFO, + DEC_GET_SEQ_INFO, +}; + +enum mirror_direction { + MIRDIR_NONE, /* no mirroring */ + MIRDIR_VER, /* vertical mirroring */ + MIRDIR_HOR, /* horizontal mirroring */ + MIRDIR_HOR_VER /* horizontal and vertical mirroring */ +}; + +enum frame_buffer_format { + FORMAT_ERR = -1, + FORMAT_420 = 0, /* 8bit */ + FORMAT_422, /* 8bit */ + FORMAT_224, /* 8bit */ + FORMAT_444, /* 8bit */ + FORMAT_400, /* 8bit */ + + /* little endian perspective */ + /* | addr 0 | addr 1 | */ + FORMAT_420_P10_16BIT_MSB = 5, /* lsb |000000xx|xxxxxxxx | msb */ + FORMAT_420_P10_16BIT_LSB, /* lsb |xxxxxxx |xx000000 | msb */ + FORMAT_420_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */ + FORMAT_420_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */ + + /* 4:2:2 packed format */ + /* little endian perspective */ + /* | addr 0 | addr 1 | */ + FORMAT_422_P10_16BIT_MSB, /* lsb |000000xx |xxxxxxxx | msb */ + FORMAT_422_P10_16BIT_LSB, /* lsb |xxxxxxxx |xx000000 | msb */ + FORMAT_422_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */ + FORMAT_422_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */ + + FORMAT_YUYV, /* 8bit packed format : Y0U0Y1V0 Y2U1Y3V1 ... */ + FORMAT_YUYV_P10_16BIT_MSB, + FORMAT_YUYV_P10_16BIT_LSB, + FORMAT_YUYV_P10_32BIT_MSB, + FORMAT_YUYV_P10_32BIT_LSB, + + FORMAT_YVYU, /* 8bit packed format : Y0V0Y1U0 Y2V1Y3U1 ... */ + FORMAT_YVYU_P10_16BIT_MSB, + FORMAT_YVYU_P10_16BIT_LSB, + FORMAT_YVYU_P10_32BIT_MSB, + FORMAT_YVYU_P10_32BIT_LSB, + + FORMAT_UYVY, /* 8bit packed format : U0Y0V0Y1 U1Y2V1Y3 ... */ + FORMAT_UYVY_P10_16BIT_MSB, + FORMAT_UYVY_P10_16BIT_LSB, + FORMAT_UYVY_P10_32BIT_MSB, + FORMAT_UYVY_P10_32BIT_LSB, + + FORMAT_VYUY, /* 8bit packed format : V0Y0U0Y1 V1Y2U1Y3 ... */ + FORMAT_VYUY_P10_16BIT_MSB, + FORMAT_VYUY_P10_16BIT_LSB, + FORMAT_VYUY_P10_32BIT_MSB, + FORMAT_VYUY_P10_32BIT_LSB, + + FORMAT_MAX, +}; + +enum packed_format_num { + NOT_PACKED = 0, + PACKED_YUYV, + PACKED_YVYU, + PACKED_UYVY, + PACKED_VYUY, +}; + +enum wave5_interrupt_bit { + INT_WAVE5_INIT_VPU = 0, + INT_WAVE5_WAKEUP_VPU = 1, + INT_WAVE5_SLEEP_VPU = 2, + INT_WAVE5_CREATE_INSTANCE = 3, + INT_WAVE5_FLUSH_INSTANCE = 4, + INT_WAVE5_DESTROY_INSTANCE = 5, + INT_WAVE5_INIT_SEQ = 6, + INT_WAVE5_SET_FRAMEBUF = 7, + INT_WAVE5_DEC_PIC = 8, + INT_WAVE5_ENC_PIC = 8, + INT_WAVE5_ENC_SET_PARAM = 9, + INT_WAVE5_DEC_QUERY = 14, + INT_WAVE5_BSBUF_EMPTY = 15, + INT_WAVE5_BSBUF_FULL = 15, +}; + +enum pic_type { + PIC_TYPE_I = 0, + PIC_TYPE_P = 1, + PIC_TYPE_B = 2, + PIC_TYPE_IDR = 5, /* H.264/H.265 IDR (Instantaneous Decoder Refresh) picture */ + PIC_TYPE_MAX /* no meaning */ +}; + +enum sw_reset_mode { + SW_RESET_SAFETY, + SW_RESET_FORCE, + SW_RESET_ON_BOOT +}; + +enum tiled_map_type { + LINEAR_FRAME_MAP = 0, /* linear frame map type */ + COMPRESSED_FRAME_MAP = 17, /* compressed frame map type*/ +}; + +enum temporal_id_mode { + TEMPORAL_ID_MODE_ABSOLUTE, + TEMPORAL_ID_MODE_RELATIVE, +}; + +struct vpu_attr { + u32 product_id; + char product_name[8]; /* product name in ascii code */ + u32 product_version; + u32 fw_version; + u32 customer_id; + u32 support_decoders; /* bitmask */ + u32 support_encoders; /* bitmask */ + u32 support_backbone: 1; + u32 support_avc10bit_enc: 1; + u32 support_hevc10bit_enc: 1; + u32 support_vcore_backbone: 1; + u32 support_vcpu_backbone: 1; +}; + +struct frame_buffer { + dma_addr_t buf_y; + dma_addr_t buf_cb; + dma_addr_t buf_cr; + unsigned int buf_y_size; + unsigned int buf_cb_size; + unsigned int buf_cr_size; + enum tiled_map_type map_type; + unsigned int stride; /* horizontal stride for the given frame buffer */ + unsigned int width; /* width of the given frame buffer */ + unsigned int height; /* height of the given frame buffer */ + size_t size; /* size of the given frame buffer */ + unsigned int sequence_no; + bool update_fb_info; +}; + +struct vpu_rect { + unsigned int left; /* horizontal pixel offset from left edge */ + unsigned int top; /* vertical pixel offset from top edge */ + unsigned int right; /* horizontal pixel offset from right edge */ + unsigned int bottom; /* vertical pixel offset from bottom edge */ +}; + +/* + * decode struct and definition + */ + +struct dec_open_param { + dma_addr_t bitstream_buffer; + size_t bitstream_buffer_size; +}; + +struct dec_initial_info { + u32 pic_width; + u32 pic_height; + struct vpu_rect pic_crop_rect; + u32 min_frame_buffer_count; /* between 1 to 16 */ + + u32 profile; + u32 luma_bitdepth; /* bit-depth of the luma sample */ + u32 chroma_bitdepth; /* bit-depth of the chroma sample */ + u32 seq_init_err_reason; + dma_addr_t rd_ptr; /* read pointer of bitstream buffer */ + dma_addr_t wr_ptr; /* write pointer of bitstream buffer */ + u32 sequence_no; + u32 vlc_buf_size; + u32 param_buf_size; +}; + +struct dec_output_info { + /** + * This is a frame buffer index for the picture to be displayed at the moment + * among frame buffers which are registered using vpu_dec_register_frame_buffer(). + * Frame data that will be displayed is stored in the frame buffer with this index + * When there is no display delay, this index is always the equal to + * index_frame_decoded, however, if displaying is delayed (for display + * reordering in AVC or B-frames in VC1), this index might be different to + * index_frame_decoded. By checking this index, HOST applications can easily figure + * out whether sequence decoding has been finished or not. + * + * -3(0xFFFD) or -2(0xFFFE) : when a display output cannot be given due to picture + * reordering or skip option + * -1(0xFFFF) : when there is no more output for display at the end of sequence + * decoding + */ + s32 index_frame_display; + /** + * This is the frame buffer index of the decoded picture among the frame buffers which were + * registered using vpu_dec_register_frame_buffer(). The currently decoded frame is stored + * into the frame buffer specified by this index. + * + * -2 : indicates that no decoded output is generated because decoder meets EOS + * (end of sequence) or skip + * -1 : indicates that the decoder fails to decode a picture because there is no available + * frame buffer + */ + s32 index_frame_decoded; + s32 index_frame_decoded_for_tiled; + u32 nal_type; + unsigned int pic_type; + struct vpu_rect rc_display; + unsigned int disp_pic_width; + unsigned int disp_pic_height; + struct vpu_rect rc_decoded; + u32 dec_pic_width; + u32 dec_pic_height; + s32 decoded_poc; + int temporal_id; /* temporal ID of the picture */ + dma_addr_t rd_ptr; /* stream buffer read pointer for the current decoder instance */ + dma_addr_t wr_ptr; /* stream buffer write pointer for the current decoder instance */ + struct frame_buffer disp_frame; + u32 frame_display_flag; /* it reports a frame buffer flag to be displayed */ + /** + * this variable reports that sequence has been changed while H.264/AVC stream decoding. + * if it is 1, HOST application can get the new sequence information by calling + * vpu_dec_get_initial_info() or wave5_vpu_dec_issue_seq_init(). + * + * for H.265/HEVC decoder, each bit has a different meaning as follows. + * + * sequence_changed[5] : it indicates that the profile_idc has been changed + * sequence_changed[16] : it indicates that the resolution has been changed + * sequence_changed[19] : it indicates that the required number of frame buffer has + * been changed. + */ + unsigned int frame_cycle; /* reports the number of cycles for processing a frame */ + u32 sequence_no; + + u32 dec_host_cmd_tick; /* tick of DEC_PIC command for the picture */ + u32 dec_decode_end_tick; /* end tick of decoding slices of the picture */ + + u32 sequence_changed; +}; + +struct queue_status_info { + u32 instance_queue_count; + u32 report_queue_count; +}; + +/* + * encode struct and definition + */ + +#define MAX_NUM_TEMPORAL_LAYER 7 +#define MAX_NUM_SPATIAL_LAYER 3 +#define MAX_GOP_NUM 8 + +struct custom_gop_pic_param { + u32 pic_type; /* picture type of nth picture in the custom GOP */ + u32 poc_offset; /* POC of nth picture in the custom GOP */ + u32 pic_qp; /* quantization parameter of nth picture in the custom GOP */ + u32 use_multi_ref_p; /* use multiref pic for P picture. valid only if PIC_TYPE is P */ + u32 ref_poc_l0; /* POC of reference L0 of nth picture in the custom GOP */ + u32 ref_poc_l1; /* POC of reference L1 of nth picture in the custom GOP */ + s32 temporal_id; /* temporal ID of nth picture in the custom GOP */ +}; + +struct enc_wave_param { + /* + * profile indicator (HEVC only) + * + * 0 : the firmware determines a profile according to the internal_bit_depth + * 1 : main profile + * 2 : main10 profile + * 3 : main still picture profile + * In the AVC encoder, a profile cannot be set by the host application. + * The firmware decides it based on internal_bit_depth. + * profile = HIGH (bitdepth 8) profile = HIGH10 (bitdepth 10) + */ + u32 profile; + u32 level; /* level indicator (level * 10) */ + u32 internal_bit_depth: 4; /* 8/10 */ + u32 gop_preset_idx: 4; /* 0 - 9 */ + u32 decoding_refresh_type: 2; /* 0=non-IRAP, 1=CRA, 2=IDR */ + u32 intra_qp; /* quantization parameter of intra picture */ + u32 intra_period; /* period of intra picture in GOP size */ + u32 conf_win_top; /* top offset of conformance window */ + u32 conf_win_bot; /* bottom offset of conformance window */ + u32 conf_win_left; /* left offset of conformance window */ + u32 conf_win_right; /* right offset of conformance window */ + u32 intra_refresh_mode: 3; + /* + * Argument for intra_ctu_refresh_mode. + * + * Depending on intra_refresh_mode, it can mean one of the following: + * - intra_ctu_refresh_mode (1) -> number of consecutive CTU rows + * - intra_ctu_refresh_mode (2) -> the number of consecutive CTU columns + * - intra_ctu_refresh_mode (3) -> step size in CTU + * - intra_ctu_refresh_mode (4) -> number of intra ct_us to be encoded in a picture + */ + u32 intra_refresh_arg; + /* + * 0 : custom setting + * 1 : recommended encoder parameters (slow encoding speed, highest picture quality) + * 2 : boost mode (normal encoding speed, moderate picture quality) + * 3 : fast mode (fast encoding speed, low picture quality) + */ + u32 depend_slice_mode : 2; + u32 depend_slice_mode_arg; + u32 independ_slice_mode : 1; /* 0=no-multi-slice, 1=slice-in-ctu-number*/ + u32 independ_slice_mode_arg; + u32 max_num_merge: 2; + s32 beta_offset_div2: 4; /* sets beta_offset_div2 for deblocking filter */ + s32 tc_offset_div2: 4; /* sets tc_offset_div3 for deblocking filter */ + u32 hvs_qp_scale: 4; /* QP scaling factor for CU QP adjust if hvs_qp_scale_enable is 1 */ + u32 hvs_max_delta_qp; /* maximum delta QP for HVS */ + s32 chroma_cb_qp_offset; /* the value of chroma(cb) QP offset */ + s32 chroma_cr_qp_offset; /* the value of chroma(cr) QP offset */ + s32 initial_rc_qp; + u32 nr_intra_weight_y; + u32 nr_intra_weight_cb; /* weight to cb noise level for intra picture (0 ~ 31) */ + u32 nr_intra_weight_cr; /* weight to cr noise level for intra picture (0 ~ 31) */ + u32 nr_inter_weight_y; + u32 nr_inter_weight_cb; /* weight to cb noise level for inter picture (0 ~ 31) */ + u32 nr_inter_weight_cr; /* weight to cr noise level for inter picture (0 ~ 31) */ + u32 min_qp_i; /* minimum QP of I picture for rate control */ + u32 max_qp_i; /* maximum QP of I picture for rate control */ + u32 min_qp_p; /* minimum QP of P picture for rate control */ + u32 max_qp_p; /* maximum QP of P picture for rate control */ + u32 min_qp_b; /* minimum QP of B picture for rate control */ + u32 max_qp_b; /* maximum QP of B picture for rate control */ + u32 avc_idr_period; /* period of IDR picture (0 ~ 1024). 0 - implies an infinite period */ + u32 avc_slice_arg; /* the number of MB for a slice when avc_slice_mode is set with 1 */ + u32 intra_mb_refresh_mode: 2; /* 0=none, 1=row, 2=column, 3=step-size-in-mb */ + /** + * Argument for intra_mb_refresh_mode. + * + * intra_mb_refresh_mode (1) -> number of consecutive MB rows + * intra_mb_refresh_mode (2) ->the number of consecutive MB columns + * intra_mb_refresh_mode (3) -> step size in MB + */ + u32 intra_mb_refresh_arg; + u32 rc_weight_param; + u32 rc_weight_buf; + + /* flags */ + u32 en_still_picture: 1; /* still picture profile */ + u32 tier: 1; /* 0=main, 1=high */ + u32 avc_slice_mode: 1; /* 0=none, 1=slice-in-mb-number */ + u32 entropy_coding_mode: 1; /* 0=CAVLC, 1=CABAC */ + u32 lossless_enable: 1; /* enable lossless encoding */ + u32 const_intra_pred_flag: 1; /* enable constrained intra prediction */ + u32 tmvp_enable: 1; /* enable temporal motion vector prediction */ + u32 wpp_enable: 1; + u32 disable_deblk: 1; /* disable in-loop deblocking filtering */ + u32 lf_cross_slice_boundary_enable: 1; + u32 skip_intra_trans: 1; + u32 sao_enable: 1; /* enable SAO (sample adaptive offset) */ + u32 intra_nx_n_enable: 1; /* enables intra nx_n p_us */ + u32 cu_level_rc_enable: 1; /* enable CU level rate control */ + u32 hvs_qp_enable: 1; /* enable CU QP adjustment for subjective quality enhancement */ + u32 strong_intra_smooth_enable: 1; /* enable strong intra smoothing */ + u32 rdo_skip: 1; /* skip RDO (rate distortion optimization) */ + u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */ + u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */ + u32 mb_level_rc_enable: 1; /* enable MB-level rate control */ +}; + +struct enc_open_param { + dma_addr_t bitstream_buffer; + unsigned int bitstream_buffer_size; + u32 pic_width; /* width of a picture to be encoded in unit of sample */ + u32 pic_height; /* height of a picture to be encoded in unit of sample */ + u32 frame_rate_info;/* desired fps */ + u32 vbv_buffer_size; + u32 bit_rate; /* target bitrate in bps */ + struct enc_wave_param wave_param; + enum packed_format_num packed_format; /* <> */ + enum frame_buffer_format src_format; + bool line_buf_int_en; + u32 rc_enable : 1; /* rate control */ +}; + +struct enc_initial_info { + u32 min_frame_buffer_count; /* minimum number of frame buffers */ + u32 min_src_frame_count; /* minimum number of source buffers */ + u32 seq_init_err_reason; + u32 warn_info; + u32 vlc_buf_size; /* size of task buffer */ + u32 param_buf_size; /* size of task buffer */ +}; + +/* + * Flags to encode NAL units explicitly + */ +struct enc_code_opt { + u32 implicit_header_encode: 1; + u32 encode_vcl: 1; + u32 encode_vps: 1; + u32 encode_sps: 1; + u32 encode_pps: 1; + u32 encode_aud: 1; + u32 encode_eos: 1; + u32 encode_eob: 1; + u32 encode_vui: 1; +}; + +struct enc_param { + struct frame_buffer *source_frame; + u32 pic_stream_buffer_addr; + u64 pic_stream_buffer_size; + u32 src_idx; /* source frame buffer index */ + struct enc_code_opt code_option; + u64 pts; /* presentation timestamp (PTS) of the input source */ + bool src_end_flag; +}; + +struct enc_output_info { + u32 bitstream_buffer; + u32 bitstream_size; /* byte size of encoded bitstream */ + u32 pic_type: 2; /* <> */ + s32 recon_frame_index; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + u32 enc_pic_byte; /* number of encoded picture bytes */ + s32 enc_src_idx; /* source buffer index of the currently encoded picture */ + u32 enc_vcl_nut; + u32 error_reason; /* error reason of the currently encoded picture */ + u32 warn_info; /* warning information on the currently encoded picture */ + unsigned int frame_cycle; /* param for reporting the cycle number of encoding one frame*/ + u64 pts; + u32 enc_host_cmd_tick; /* tick of ENC_PIC command for the picture */ + u32 enc_encode_end_tick; /* end tick of encoding slices of the picture */ +}; + +enum enc_pic_code_option { + CODEOPT_ENC_HEADER_IMPLICIT = BIT(0), + CODEOPT_ENC_VCL = BIT(1), /* flag to encode VCL nal unit explicitly */ +}; + +enum gop_preset_idx { + PRESET_IDX_CUSTOM_GOP = 0, /* user defined GOP structure */ + PRESET_IDX_ALL_I = 1, /* all intra, gopsize = 1 */ + PRESET_IDX_IPP = 2, /* consecutive P, cyclic gopsize = 1 */ + PRESET_IDX_IBBB = 3, /* consecutive B, cyclic gopsize = 1 */ + PRESET_IDX_IBPBP = 4, /* gopsize = 2 */ + PRESET_IDX_IBBBP = 5, /* gopsize = 4 */ + PRESET_IDX_IPPPP = 6, /* consecutive P, cyclic gopsize = 4 */ + PRESET_IDX_IBBBB = 7, /* consecutive B, cyclic gopsize = 4 */ + PRESET_IDX_RA_IB = 8, /* random access, cyclic gopsize = 8 */ + PRESET_IDX_IPP_SINGLE = 9, /* consecutive P, cyclic gopsize = 1, with single ref */ +}; + +struct sec_axi_info { + u32 use_ip_enable; + u32 use_bit_enable; + u32 use_lf_row_enable: 1; + u32 use_enc_rdo_enable: 1; + u32 use_enc_lf_enable: 1; +}; + +struct dec_info { + struct dec_open_param open_param; + struct dec_initial_info initial_info; + struct dec_initial_info new_seq_info; /* temporal new sequence information */ + u32 stream_wr_ptr; + u32 stream_rd_ptr; + u32 frame_display_flag; + dma_addr_t stream_buf_start_addr; + dma_addr_t stream_buf_end_addr; + u32 stream_buf_size; + struct vpu_buf vb_mv[MAX_REG_FRAME]; + struct vpu_buf vb_fbc_y_tbl[MAX_REG_FRAME]; + struct vpu_buf vb_fbc_c_tbl[MAX_REG_FRAME]; + unsigned int num_of_decoding_fbs: 7; + unsigned int num_of_display_fbs: 7; + unsigned int stride; + struct sec_axi_info sec_axi_info; + dma_addr_t user_data_buf_addr; + u32 user_data_enable; + u32 user_data_buf_size; + struct vpu_buf vb_work; + struct vpu_buf vb_task; + struct dec_output_info dec_out_info[WAVE5_MAX_FBS]; + u32 seq_change_mask; + enum temporal_id_mode temp_id_select_mode; + u32 target_temp_id; + u32 target_spatial_id; + u32 instance_queue_count; + u32 report_queue_count; + u32 cycle_per_tick; + u32 product_code; + u32 vlc_buf_size; + u32 param_buf_size; + bool initial_info_obtained; + bool reorder_enable; + bool first_cycle_check; + u32 stream_endflag: 1; +}; + +struct enc_info { + struct enc_open_param open_param; + struct enc_initial_info initial_info; + u32 stream_rd_ptr; + u32 stream_wr_ptr; + dma_addr_t stream_buf_start_addr; + dma_addr_t stream_buf_end_addr; + u32 stream_buf_size; + unsigned int num_frame_buffers; + unsigned int stride; + bool rotation_enable; + bool mirror_enable; + enum mirror_direction mirror_direction; + unsigned int rotation_angle; + bool initial_info_obtained; + struct sec_axi_info sec_axi_info; + bool line_buf_int_en; + struct vpu_buf vb_work; + struct vpu_buf vb_mv; /* col_mv buffer */ + struct vpu_buf vb_fbc_y_tbl; /* FBC luma table buffer */ + struct vpu_buf vb_fbc_c_tbl; /* FBC chroma table buffer */ + struct vpu_buf vb_sub_sam_buf; /* sub-sampled buffer for ME */ + struct vpu_buf vb_task; + u64 cur_pts; /* current timestamp in 90_k_hz */ + u64 pts_map[32]; /* PTS mapped with source frame index */ + u32 instance_queue_count; + u32 report_queue_count; + bool first_cycle_check; + u32 cycle_per_tick; + u32 product_code; + u32 vlc_buf_size; + u32 param_buf_size; +}; + +struct vpu_device { + struct device *dev; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *v4l2_m2m_dec_dev; + struct v4l2_m2m_dev *v4l2_m2m_enc_dev; + struct list_head instances; + struct video_device *video_dev_dec; + struct video_device *video_dev_enc; + struct mutex dev_lock; /* lock for the src, dst v4l2 queues */ + struct mutex hw_lock; /* lock hw configurations */ + int irq; + enum product_id product; + struct vpu_attr attr; + struct vpu_buf common_mem; + u32 last_performance_cycles; + u32 sram_size; + struct gen_pool *sram_pool; + struct vpu_buf sram_buf; + void __iomem *vdb_register; + u32 product_code; + struct ida inst_ida; + struct clk_bulk_data *clks; + int num_clks; +}; + +struct vpu_instance; + +struct vpu_instance_ops { + void (*finish_process)(struct vpu_instance *inst); +}; + +struct vpu_instance { + struct list_head list; + struct v4l2_fh v4l2_fh; + struct v4l2_m2m_dev *v4l2_m2m_dev; + struct v4l2_ctrl_handler v4l2_ctrl_hdl; + struct vpu_device *dev; + struct completion irq_done; + + struct v4l2_pix_format_mplane src_fmt; + struct v4l2_pix_format_mplane dst_fmt; + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + + enum vpu_instance_state state; + enum vpu_instance_type type; + const struct vpu_instance_ops *ops; + spinlock_t state_spinlock; /* This protects the instance state */ + + enum wave_std std; + s32 id; + union { + struct enc_info enc_info; + struct dec_info dec_info; + } *codec_info; + struct frame_buffer frame_buf[MAX_REG_FRAME]; + struct vpu_buf frame_vbuf[MAX_REG_FRAME]; + u32 fbc_buf_count; + u32 queued_src_buf_num; + u32 queued_dst_buf_num; + struct list_head avail_src_bufs; + struct list_head avail_dst_bufs; + struct v4l2_rect conf_win; + u64 timestamp; + enum frame_buffer_format output_format; + bool cbcr_interleave; + bool nv21; + bool eos; + struct vpu_buf bitstream_vbuf; + dma_addr_t last_rd_ptr; + size_t remaining_consumed_bytes; + bool needs_reallocation; + + unsigned int min_src_buf_count; + unsigned int rot_angle; + unsigned int mirror_direction; + unsigned int bit_depth; + unsigned int frame_rate; + unsigned int vbv_buf_size; + unsigned int rc_mode; + unsigned int rc_enable; + unsigned int bit_rate; + unsigned int encode_aud; + struct enc_wave_param enc_param; +}; + +void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data); +u32 wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr); +int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count, + size_t size); +int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset, + u8 *data, size_t len); +int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev); +void wave5_vdi_free_sram(struct vpu_device *vpu_dev); + +int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size); +int wave5_vpu_flush_instance(struct vpu_instance *inst); +int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id); +int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param); +int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res); +int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst); +int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info); +int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs, + int num_of_display_fbs, int stride, int height); +int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail); +int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info); +int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr); +dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst); +int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index); +int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); +int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr, + dma_addr_t *pwr_ptr, size_t *size); +int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size); +int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index); +int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index); + +int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param); +int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res); +int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst); +int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info); +int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num, + unsigned int stride, int height, + enum tiled_map_type map_type); +int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, + u32 *fail_res); +int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info); +int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); + +#endif diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h new file mode 100644 index 000000000000..d9751eedb0f9 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - product config definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef _VPU_CONFIG_H_ +#define _VPU_CONFIG_H_ + +#define WAVE517_CODE 0x5170 +#define WAVE537_CODE 0x5370 +#define WAVE511_CODE 0x5110 +#define WAVE521_CODE 0x5210 +#define WAVE521C_CODE 0x521c +#define WAVE521C_DUAL_CODE 0x521d // wave521 dual core +#define WAVE521E1_CODE 0x5211 + +#define PRODUCT_CODE_W_SERIES(x) ({ \ + int c = x; \ + ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \ + (c) == WAVE511_CODE || (c) == WAVE521_CODE || \ + (c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \ + (c) == WAVE521C_DUAL_CODE); \ +}) + +#define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024) +#define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K +#define WAVE521DEC_WORKBUF_SIZE (1784 * 1024) + +#define MAX_NUM_INSTANCE 32 + +#define W5_MIN_ENC_PIC_WIDTH 256 +#define W5_MIN_ENC_PIC_HEIGHT 128 +#define W5_MAX_ENC_PIC_WIDTH 8192 +#define W5_MAX_ENC_PIC_HEIGHT 8192 + +// application specific configuration +#define VPU_ENC_TIMEOUT 60000 +#define VPU_DEC_TIMEOUT 60000 + +// for WAVE encoder +#define USE_SRC_PRP_AXI 0 +#define USE_SRC_PRI_AXI 1 +#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI + +/************************************************************************/ +/* VPU COMMON MEMORY */ +/************************************************************************/ +#define VLC_BUF_NUM (2) + +#define COMMAND_QUEUE_DEPTH (2) + +#define W5_REMAP_INDEX0 0 +#define W5_REMAP_INDEX1 1 +#define W5_REMAP_MAX_SIZE (1024 * 1024) + +#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) +#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE +#define WAVE5_TEMPBUF_SIZE (1024 * 1024) + +#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE) + +//=====4. VPU REPORT MEMORY ======================// + +#define WAVE5_UPPER_PROC_AXI_ID 0x0 + +#define WAVE5_PROC_AXI_ID 0x0 +#define WAVE5_PRP_AXI_ID 0x0 +#define WAVE5_FBD_Y_AXI_ID 0x0 +#define WAVE5_FBC_Y_AXI_ID 0x0 +#define WAVE5_FBD_C_AXI_ID 0x0 +#define WAVE5_FBC_C_AXI_ID 0x0 +#define WAVE5_SEC_AXI_ID 0x0 +#define WAVE5_PRI_AXI_ID 0x0 + +#endif /* _VPU_CONFIG_H_ */ diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h new file mode 100644 index 000000000000..905d5c34fd4e --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - error values + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef ERROR_CODE_H_INCLUDED +#define ERROR_CODE_H_INCLUDED + +/* + * WAVE5 + */ + +/************************************************************************/ +/* WAVE5 COMMON SYSTEM ERROR (FAIL_REASON) */ +/************************************************************************/ +#define WAVE5_SYSERR_QUEUEING_FAIL 0x00000001 +#define WAVE5_SYSERR_ACCESS_VIOLATION_HW 0x00000040 +#define WAVE5_SYSERR_BUS_ERROR 0x00000200 +#define WAVE5_SYSERR_DOUBLE_FAULT 0x00000400 +#define WAVE5_SYSERR_RESULT_NOT_READY 0x00000800 +#define WAVE5_SYSERR_VPU_STILL_RUNNING 0x00001000 +#define WAVE5_SYSERR_UNKNOWN_CMD 0x00002000 +#define WAVE5_SYSERR_UNKNOWN_CODEC_STD 0x00004000 +#define WAVE5_SYSERR_UNKNOWN_QUERY_OPTION 0x00008000 +#define WAVE5_SYSERR_VLC_BUF_FULL 0x00010000 +#define WAVE5_SYSERR_WATCHDOG_TIMEOUT 0x00020000 +#define WAVE5_SYSERR_VCPU_TIMEOUT 0x00080000 +#define WAVE5_SYSERR_TEMP_SEC_BUF_OVERFLOW 0x00200000 +#define WAVE5_SYSERR_NEED_MORE_TASK_BUF 0x00400000 +#define WAVE5_SYSERR_PRESCAN_ERR 0x00800000 +#define WAVE5_SYSERR_ENC_GBIN_OVERCONSUME 0x01000000 +#define WAVE5_SYSERR_ENC_MAX_ZERO_DETECT 0x02000000 +#define WAVE5_SYSERR_ENC_LVL_FIRST_ERROR 0x04000000 +#define WAVE5_SYSERR_ENC_EG_RANGE_OVER 0x08000000 +#define WAVE5_SYSERR_ENC_IRB_FRAME_DROP 0x10000000 +#define WAVE5_SYSERR_INPLACE_V 0x20000000 +#define WAVE5_SYSERR_FATAL_VPU_HANGUP 0xf0000000 + +/************************************************************************/ +/* WAVE5 COMMAND QUEUE ERROR (FAIL_REASON) */ +/************************************************************************/ +#define WAVE5_CMDQ_ERR_NOT_QUEABLE_CMD 0x00000001 +#define WAVE5_CMDQ_ERR_SKIP_MODE_ENABLE 0x00000002 +#define WAVE5_CMDQ_ERR_INST_FLUSHING 0x00000003 +#define WAVE5_CMDQ_ERR_INST_INACTIVE 0x00000004 +#define WAVE5_CMDQ_ERR_QUEUE_FAIL 0x00000005 +#define WAVE5_CMDQ_ERR_CMD_BUF_FULL 0x00000006 + +/************************************************************************/ +/* WAVE5 ERROR ON DECODER (ERR_INFO) */ +/************************************************************************/ +// HEVC +#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define HEVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 0x0000100A +#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE 0x0000100D +#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3 0x0000100E +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE 0x0000100F +#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2 0x00001010 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE 0x00001011 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER 0x00001012 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA 0x00001013 +#define HEVC_SPSERR_SCALING_LIST 0x00001014 +#define HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3 0x00001015 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE 0x00001016 +#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS 0x00001017 +#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS 0x00001018 +#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A +#define HEVC_SPSERR_VUI_ERROR 0x0000101B +#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH 0x00002005 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1 0x00002008 +#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1 0x00002009 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1 0x0000200A +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D +#define HEVC_PPSERR_SCALING_LIST 0x0000200E +#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2 0x0000200F +#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT 0x00002010 +#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT 0x00002011 +#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT 0x00002019 +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT 0x00002020 +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT 0x00002021 +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT 0x00002022 +#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define HEVC_SHERR_ACTIVATE_PPS 0x00003001 +#define HEVC_SHERR_ACTIVATE_SPS 0x00003002 +#define HEVC_SHERR_SLICE_TYPE 0x00003003 +#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE 0x00003004 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG 0x00003005 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET 0x00003006 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX 0x00003007 +#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008 +#define HEVC_SHERR_NUM_LONG_TERM_PICS 0x00003009 +#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT 0x0000300B +#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E +#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND 0x00003010 +#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE 0x00003012 +#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013 +#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014 +#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS 0x00003017 +#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018 +#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH 0x00003019 +#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE 0x0000301A +#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE 0x0000301B +#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE 0x0000301C +#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define HEVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define HEVC_ETCERR_INPLACE_V 0x0000500F + +// AVC +#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define AVC_SPSERR_SCALING_LIST 0x00001014 +#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define AVC_SPSERR_VUI_ERROR 0x0000101B +#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define AVC_PPSERR_SCALING_LIST 0x0000200E +#define AVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define AVC_SHERR_ACTIVATE_PPS 0x00003001 +#define AVC_SHERR_ACTIVATE_SPS 0x00003002 +#define AVC_SHERR_SLICE_TYPE 0x00003003 +#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004 +#define AVC_SHERR_RPLM 0x00003006 +#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define AVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC 0x00003017 +#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define AVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define AVC_ETCERR_ASO 0x00005004 +#define AVC_ETCERR_FMO 0x00005005 +#define AVC_ETCERR_INPLACE_V 0x0000500F + +/************************************************************************/ +/* WAVE5 WARNING ON DECODER (WARN_INFO) */ +/************************************************************************/ +// HEVC +#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1 0x00000001 +#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS 0x00000002 +#define HEVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS 0x00000008 +#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER 0x00000020 +#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080 +#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000 +#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS 0x02000000 +#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS 0x00000200 +#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG 0x00001000 +#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000 +#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT 0x00008000 +#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define HEVC_ETCWARN_WRONG_TEMPORAL_ID 0x00040000 +#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define HEVC_SPECWARN_OVER_PROFILE 0x00100000 +#define HEVC_SPECWARN_OVER_LEVEL 0x00200000 +#define HEVC_PRESWARN_PARSING_ERR 0x04000000 +#define HEVC_PRESWARN_MVD_OUT_OF_RANGE 0x08000000 +#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE 0x09000000 +#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE 0x0A000000 +#define HEVC_PRESWARN_PCM_ERR 0x0B000000 +#define HEVC_PRESWARN_OVERCONSUME 0x0C000000 +#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR 0x10000000 +#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG 0x20000000 + +// AVC +#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define AVC_SPECWARN_OVER_PROFILE 0x00100000 +#define AVC_SPECWARN_OVER_LEVEL 0x00200000 +#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000 +#define AVC_PRESWARN_MB_QPD_RANGE_OUT 0x00500000 +#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000 +#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000 +#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT 0x00800000 +#define AVC_PRESWARN_MB_TYPE_RANGE_OUT 0x00900000 +#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT 0x00A00000 +#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000 +#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT 0x00C00000 +#define AVC_PRESWARN_REF_IDX_RANGE_OUT 0x00D00000 +#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT 0x00E00000 +#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT 0x00F00000 +#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT 0x01000000 +#define AVC_PRESWARN_OVERCONSUME 0x01100000 +#define AVC_PRESWARN_MISSING_SLICE 0x01200000 + +/************************************************************************/ +/* WAVE5 ERROR ON ENCODER (ERR_INFO) */ +/************************************************************************/ + +/************************************************************************/ +/* WAVE5 WARNING ON ENCODER (WARN_INFO) */ +/************************************************************************/ +#define WAVE5_ETCWARN_FORCED_SPLIT_BY_CU8X8 0x000000001 + +/************************************************************************/ +/* WAVE5 debug info (PRI_REASON) */ +/************************************************************************/ +#define WAVE5_DEC_VCORE_VCE_HANGUP 0x0001 +#define WAVE5_DEC_VCORE_UNDETECTED_SYNTAX_ERR 0x0002 +#define WAVE5_DEC_VCORE_MIB_BUSY 0x0003 +#define WAVE5_DEC_VCORE_VLC_BUSY 0x0004 + +#endif /* ERROR_CODE_H_INCLUDED */ diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h new file mode 100644 index 000000000000..063028eccd3b --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - wave5 backend definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE5_FUNCTION_H__ +#define __WAVE5_FUNCTION_H__ + +#define WAVE5_SUBSAMPLED_ONE_SIZE(_w, _h) (ALIGN((_w) / 4, 16) * ALIGN((_h) / 4, 8)) +#define WAVE5_SUBSAMPLED_ONE_SIZE_AVC(_w, _h) (ALIGN((_w) / 4, 32) * ALIGN((_h) / 4, 4)) + +/* + * Bitstream buffer option: Explicit End + * When set to 1 the VPU assumes that the bitstream has at least one frame and + * will read until the end of the bitstream buffer. + * When set to 0 the VPU will not read the last few bytes. + * This option can be set anytime but cannot be cleared during processing. + * It can be set to force finish decoding even though there is not enough + * bitstream data for a full frame. + */ +#define BSOPTION_ENABLE_EXPLICIT_END BIT(0) +#define BSOPTION_HIGHLIGHT_STREAM_END BIT(1) + +/* + * Currently the driver only supports hardware with little endian but for source + * picture format, the bitstream and the report parameter the hardware works + * with the opposite endianness, thus hard-code big endian for the register + * writes + */ +#define PIC_SRC_ENDIANNESS_BIG_ENDIAN 0xf +#define BITSTREAM_ENDIANNESS_BIG_ENDIAN 0xf +#define REPORT_PARAM_ENDIANNESS_BIG_ENDIAN 0xf + +#define WTL_RIGHT_JUSTIFIED 0 +#define WTL_LEFT_JUSTIFIED 1 +#define WTL_PIXEL_8BIT 0 +#define WTL_PIXEL_16BIT 1 +#define WTL_PIXEL_32BIT 2 + +/* Mirror & rotation modes of the PRP (pre-processing) module */ +#define NONE_ROTATE 0x0 +#define ROT_CLOCKWISE_90 0x3 +#define ROT_CLOCKWISE_180 0x5 +#define ROT_CLOCKWISE_270 0x7 +#define MIR_HOR_FLIP 0x11 +#define MIR_VER_FLIP 0x9 +#define MIR_HOR_VER_FLIP (MIR_HOR_FLIP | MIR_VER_FLIP) + +bool wave5_vpu_is_init(struct vpu_device *vpu_dev); + +unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev); + +int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision); + +int wave5_vpu_init(struct device *dev, u8 *fw, size_t size); + +int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode); + +int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param); + +int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos); + +int wave5_vpu_hw_flush_instance(struct vpu_instance *inst); + +int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count); + +int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size); + +int wave5_vpu_dec_init_seq(struct vpu_instance *inst); + +int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info); + +int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res); + +int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result); + +int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res); + +int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index); + +int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index); + +int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags); + +dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst); + +int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr); + +/***< WAVE5 encoder >******/ + +int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *open_param); + +int wave5_vpu_enc_init_seq(struct vpu_instance *inst); + +int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info); + +int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count); + +int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res); + +int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result); + +int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res); + +int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param); + +#endif /* __WAVE5_FUNCTION_H__ */ From 9707a6254a8a6b978bde811a44fe07d86c229d1c Mon Sep 17 00:00:00 2001 From: Nas Chung Date: Wed, 8 Nov 2023 20:29:24 +0100 Subject: [PATCH 0726/7721] media: chips-media: wave5: Add the v4l2 layer Add the decoder and encoder implementing the v4l2 API. This patch also adds the Makefile and the VIDEO_WAVE_VPU config Signed-off-by: Sebastian Fricke Signed-off-by: Nicolas Dufresne Signed-off-by: Robert Beckett Signed-off-by: Dafna Hirschfeld Signed-off-by: Nas Chung Signed-off-by: Hans Verkuil --- drivers/media/platform/chips-media/Kconfig | 1 + drivers/media/platform/chips-media/Makefile | 1 + .../media/platform/chips-media/wave5/Kconfig | 12 + .../media/platform/chips-media/wave5/Makefile | 10 + .../platform/chips-media/wave5/wave5-helper.c | 213 ++ .../platform/chips-media/wave5/wave5-helper.h | 31 + .../chips-media/wave5/wave5-vpu-dec.c | 1932 +++++++++++++++++ .../chips-media/wave5/wave5-vpu-enc.c | 1794 +++++++++++++++ .../platform/chips-media/wave5/wave5-vpu.c | 291 +++ .../platform/chips-media/wave5/wave5-vpu.h | 83 + 10 files changed, 4368 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave5/Kconfig create mode 100644 drivers/media/platform/chips-media/wave5/Makefile create mode 100644 drivers/media/platform/chips-media/wave5/wave5-helper.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-helper.h create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpu.c create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpu.h diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig index f87a0d693df7..ad350eb6b1fc 100644 --- a/drivers/media/platform/chips-media/Kconfig +++ b/drivers/media/platform/chips-media/Kconfig @@ -3,3 +3,4 @@ comment "Chips&Media media platform drivers" source "drivers/media/platform/chips-media/coda/Kconfig" +source "drivers/media/platform/chips-media/wave5/Kconfig" diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile index 5ee693f651c1..6b5d99de8b54 100644 --- a/drivers/media/platform/chips-media/Makefile +++ b/drivers/media/platform/chips-media/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += coda/ +obj-y += wave5/ diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig new file mode 100644 index 000000000000..a3b949356cd5 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_WAVE_VPU + tristate "Chips&Media Wave Codec Driver" + depends on VIDEO_DEV + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + help + Chips&Media stateful encoder and decoder driver. + The driver supports HEVC and H264 formats. + To compile this driver as modules, choose M here: the + modules will be called wave5. diff --git a/drivers/media/platform/chips-media/wave5/Makefile b/drivers/media/platform/chips-media/wave5/Makefile new file mode 100644 index 000000000000..3d738a03bd8e --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o +wave5-objs += wave5-hw.o \ + wave5-vpuapi.o \ + wave5-vdi.o \ + wave5-vpu-dec.o \ + wave5-vpu.o \ + wave5-vpu-enc.o \ + wave5-helper.o diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c new file mode 100644 index 000000000000..8433ecab230c --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - decoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include "wave5-helper.h" + +const char *state_to_str(enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + return "NONE"; + case VPU_INST_STATE_OPEN: + return "OPEN"; + case VPU_INST_STATE_INIT_SEQ: + return "INIT_SEQ"; + case VPU_INST_STATE_PIC_RUN: + return "PIC_RUN"; + case VPU_INST_STATE_STOP: + return "STOP"; + default: + return "UNKNOWN"; + } +} + +void wave5_cleanup_instance(struct vpu_instance *inst) +{ + int i; + + if (list_is_singular(&inst->list)) + wave5_vdi_free_sram(inst->dev); + + for (i = 0; i < inst->fbc_buf_count; i++) + wave5_vpu_dec_reset_framebuffer(inst, i); + + wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); + if (inst->v4l2_fh.vdev) { + v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_exit(&inst->v4l2_fh); + } + list_del_init(&inst->list); + ida_free(&inst->dev->inst_ida, inst->id); + kfree(inst->codec_info); + kfree(inst); +} + +int wave5_vpu_release_device(struct file *filp, + int (*close_func)(struct vpu_instance *inst, u32 *fail_res), + char *name) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); + + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); + if (inst->state != VPU_INST_STATE_NONE) { + u32 fail_res; + int ret; + + ret = close_func(inst, &fail_res); + if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_err(inst->dev->dev, "%s close failed, device is still running\n", + name); + return -EBUSY; + } + if (ret && ret != -EIO) { + dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret); + return ret; + } + } + + wave5_cleanup_instance(inst); + + return 0; +} + +int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, + const struct vb2_ops *ops) +{ + struct vpu_instance *inst = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->ops = ops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->buf_struct_size = sizeof(struct vpu_src_buffer); + src_vq->drv_priv = inst; + src_vq->lock = &inst->dev->dev_lock; + src_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->ops = ops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer); + dst_vq->drv_priv = inst; + dst_vq->lock = &inst->dev->dev_lock; + dst_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(dst_vq); + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + bool is_decoder = inst->type == VPU_INST_TYPE_DEC; + + dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__, + is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags); + + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (is_decoder) + return v4l2_src_change_event_subscribe(fh, sub); + return -EINVAL; + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->src_fmt.width; + f->fmt.pix_mp.height = inst->src_fmt.height; + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + f->fmt.pix_mp.field = inst->src_fmt.field; + f->fmt.pix_mp.flags = inst->src_fmt.flags; + f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, + const struct vpu_format fmt_list[MAX_FMTS]) +{ + unsigned int index; + + for (index = 0; index < MAX_FMTS; index++) { + if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt) + return &fmt_list[index]; + } + + return NULL; +} + +const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, + const struct vpu_format fmt_list[MAX_FMTS]) +{ + if (idx >= MAX_FMTS) + return NULL; + + if (!fmt_list[idx].v4l2_pix_fmt) + return NULL; + + return &fmt_list[idx]; +} + +enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type) +{ + switch (v4l2_pix_fmt) { + case V4L2_PIX_FMT_H264: + return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC; + case V4L2_PIX_FMT_HEVC: + return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC; + default: + return STD_UNKNOWN; + } +} + +void wave5_return_bufs(struct vb2_queue *q, u32 state) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl; + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + vbuf = v4l2_m2m_src_buf_remove(m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!vbuf) + return; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl); + v4l2_m2m_buf_done(vbuf, state); + } +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h new file mode 100644 index 000000000000..6cee1c14d3ce --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - basic types + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE_HELPER_H__ +#define __WAVE_HELPER_H__ + +#include "wave5-vpu.h" + +#define FMT_TYPES 2 +#define MAX_FMTS 12 + +const char *state_to_str(enum vpu_instance_state state); +void wave5_cleanup_instance(struct vpu_instance *inst); +int wave5_vpu_release_device(struct file *filp, + int (*close_func)(struct vpu_instance *inst, u32 *fail_res), + char *name); +int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, + const struct vb2_ops *ops); +int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); +int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f); +const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, + const struct vpu_format fmt_list[MAX_FMTS]); +const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, + const struct vpu_format fmt_list[MAX_FMTS]); +enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type); +void wave5_return_bufs(struct vb2_queue *q, u32 state); +#endif diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c new file mode 100644 index 000000000000..8b1417ece96e --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -0,0 +1,1932 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - decoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include "wave5-helper.h" + +#define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder" +#define VPU_DEC_DRV_NAME "wave5-dec" + +#define DEFAULT_SRC_SIZE(width, height) ({ \ + (width) * (height) / 8 * 3; \ +}) + +static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .max_width = 8192, + .min_width = 32, + .max_height = 4320, + .min_height = 32, + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + .max_width = 8192, + .min_width = 8, + .max_height = 4320, + .min_height = 8, + }, + } +}; + +/* + * Make sure that the state switch is allowed and add logging for debugging + * purposes + */ +static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + break; + case VPU_INST_STATE_OPEN: + if (inst->state != VPU_INST_STATE_NONE) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_INIT_SEQ: + if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_PIC_RUN: + if (inst->state != VPU_INST_STATE_INIT_SEQ) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_STOP: + goto valid_state_switch; + } +invalid_state_switch: + WARN(1, "Invalid state switch from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + return -EINVAL; +valid_state_switch: + dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + inst->state = state; + return 0; +} + +static int wave5_vpu_dec_set_eos_on_firmware(struct vpu_instance *inst) +{ + int ret; + + ret = wave5_vpu_dec_update_bitstream_buffer(inst, 0); + if (ret) { + /* + * To set the EOS flag, a command is sent to the firmware. + * That command may never return (timeout) or may report an error. + */ + dev_err(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); + return ret; + } + return 0; +} + +static bool wave5_last_src_buffer_consumed(struct v4l2_m2m_ctx *m2m_ctx) +{ + struct vpu_src_buffer *vpu_buf; + + if (!m2m_ctx->last_src_buf) + return false; + + vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf); + return vpu_buf->consumed; +} + +static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + size_t consumed_bytes = 0; + + if (rd_ptr >= inst->last_rd_ptr) { + consumed_bytes = rd_ptr - inst->last_rd_ptr; + } else { + size_t rd_offs = rd_ptr - inst->bitstream_vbuf.daddr; + size_t last_rd_offs = inst->last_rd_ptr - inst->bitstream_vbuf.daddr; + + consumed_bytes = rd_offs + (inst->bitstream_vbuf.size - last_rd_offs); + } + + inst->last_rd_ptr = rd_ptr; + consumed_bytes += inst->remaining_consumed_bytes; + + dev_dbg(inst->dev->dev, "%s: %zu bytes of bitstream was consumed", __func__, + consumed_bytes); + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *src_buf = &buf->vb; + size_t src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + + if (src_size > consumed_bytes) + break; + + dev_dbg(inst->dev->dev, "%s: removing src buffer %i", + __func__, src_buf->vb2_buf.index); + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + inst->timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + consumed_bytes -= src_size; + + /* Handle the case the last bitstream buffer has been picked */ + if (src_buf == m2m_ctx->last_src_buf) { + int ret; + + m2m_ctx->last_src_buf = NULL; + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + dev_warn(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); + break; + } + } + + inst->remaining_consumed_bytes = consumed_bytes; +} + +static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, + unsigned int height) +{ + switch (pix_mp->pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2; + break; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height * 2; + break; + case V4L2_PIX_FMT_YUV420M: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[1].sizeimage = width * height / 4; + pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[2].sizeimage = width * height / 4; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[1].sizeimage = width * height / 2; + break; + case V4L2_PIX_FMT_YUV422M: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[1].sizeimage = width * height / 2; + pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[2].sizeimage = width * height / 2; + break; + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_NV61M: + pix_mp->width = round_up(width, 32); + pix_mp->height = round_up(height, 16); + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = width * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[1].sizeimage = width * height; + break; + default: + pix_mp->width = width; + pix_mp->height = height; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height), + pix_mp->plane_fmt[0].sizeimage); + break; + } +} + +static int start_decode(struct vpu_instance *inst, u32 *fail_res) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + ret = wave5_vpu_dec_start_one_frame(inst, fail_res); + if (ret) { + struct vb2_v4l2_buffer *src_buf; + + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + if (src_buf) + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + switch_state(inst, VPU_INST_STATE_STOP); + + dev_dbg(inst->dev->dev, "%s: pic run failed / finish job", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } + + return ret; +} + +static void flag_last_buffer_done(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *vb; + int i; + + lockdep_assert_held(&inst->state_spinlock); + + vb = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!vb) { + m2m_ctx->is_draining = true; + m2m_ctx->next_buf_last = true; + return; + } + + for (i = 0; i < vb->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&vb->vb2_buf, i, 0); + vb->field = V4L2_FIELD_NONE; + + v4l2_m2m_last_buffer_done(m2m_ctx, vb); +} + +static void send_eos_event(struct vpu_instance *inst) +{ + static const struct v4l2_event vpu_event_eos = { + .type = V4L2_EVENT_EOS + }; + + lockdep_assert_held(&inst->state_spinlock); + + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos); + inst->eos = false; +} + +static int handle_dynamic_resolution_change(struct vpu_instance *inst) +{ + struct v4l2_fh *fh = &inst->v4l2_fh; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + static const struct v4l2_event vpu_event_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info; + + lockdep_assert_held(&inst->state_spinlock); + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad", __func__, &initial_info->rd_ptr); + + dev_dbg(inst->dev->dev, "%s: width: %u height: %u profile: %u | minbuffer: %u\n", + __func__, initial_info->pic_width, initial_info->pic_height, + initial_info->profile, initial_info->min_frame_buffer_count); + + inst->needs_reallocation = true; + inst->fbc_buf_count = initial_info->min_frame_buffer_count + 1; + if (inst->fbc_buf_count != v4l2_m2m_num_dst_bufs_ready(m2m_ctx)) { + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->fbc_buf_count); + } + + if (p_dec_info->initial_info_obtained) { + inst->conf_win.left = initial_info->pic_crop_rect.left; + inst->conf_win.top = initial_info->pic_crop_rect.top; + inst->conf_win.width = initial_info->pic_width - + initial_info->pic_crop_rect.left - initial_info->pic_crop_rect.right; + inst->conf_win.height = initial_info->pic_height - + initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom; + + wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width, + initial_info->pic_height); + wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width, + initial_info->pic_height); + } + + v4l2_event_queue_fh(fh, &vpu_event_src_ch); + + return 0; +} + +static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct dec_output_info dec_info; + int ret; + struct vb2_v4l2_buffer *dec_buf = NULL; + struct vb2_v4l2_buffer *disp_buf = NULL; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + struct queue_status_info q_status; + + dev_dbg(inst->dev->dev, "%s: Fetch output info from firmware.", __func__); + + ret = wave5_vpu_dec_get_output_info(inst, &dec_info); + if (ret) { + dev_warn(inst->dev->dev, "%s: could not get output info.", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &dec_info.rd_ptr, + &dec_info.wr_ptr); + wave5_handle_src_buffer(inst, dec_info.rd_ptr); + + dev_dbg(inst->dev->dev, "%s: dec_info dec_idx %i disp_idx %i", __func__, + dec_info.index_frame_decoded, dec_info.index_frame_display); + + if (!vb2_is_streaming(dst_vq)) { + dev_dbg(inst->dev->dev, "%s: capture is not streaming..", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + /* Remove decoded buffer from the ready queue now that it has been + * decoded. + */ + if (dec_info.index_frame_decoded >= 0) { + struct vb2_buffer *vb = vb2_get_buffer(dst_vq, + dec_info.index_frame_decoded); + if (vb) { + dec_buf = to_vb2_v4l2_buffer(vb); + dec_buf->vb2_buf.timestamp = inst->timestamp; + } else { + dev_warn(inst->dev->dev, "%s: invalid decoded frame index %i", + __func__, dec_info.index_frame_decoded); + } + } + + if (dec_info.index_frame_display >= 0) { + disp_buf = v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, dec_info.index_frame_display); + if (!disp_buf) + dev_warn(inst->dev->dev, "%s: invalid display frame index %i", + __func__, dec_info.index_frame_display); + } + + /* If there is anything to display, do that now */ + if (disp_buf) { + struct vpu_dst_buffer *dst_vpu_buf = wave5_to_vpu_dst_buf(disp_buf); + + if (inst->dst_fmt.num_planes == 1) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + } else if (inst->dst_fmt.num_planes == 2) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + } else if (inst->dst_fmt.num_planes == 3) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 2, + inst->dst_fmt.plane_fmt[2].sizeimage); + } + + /* TODO implement interlace support */ + disp_buf->field = V4L2_FIELD_NONE; + dst_vpu_buf->display = true; + v4l2_m2m_buf_done(disp_buf, VB2_BUF_STATE_DONE); + + dev_dbg(inst->dev->dev, "%s: frame_cycle %8u (payload %lu)\n", + __func__, dec_info.frame_cycle, + vb2_get_plane_payload(&disp_buf->vb2_buf, 0)); + } + + if ((dec_info.index_frame_display == DISPLAY_IDX_FLAG_SEQ_END || + dec_info.sequence_changed)) { + unsigned long flags; + + spin_lock_irqsave(&inst->state_spinlock, flags); + if (!v4l2_m2m_has_stopped(m2m_ctx)) { + switch_state(inst, VPU_INST_STATE_STOP); + + if (dec_info.sequence_changed) + handle_dynamic_resolution_change(inst); + else + send_eos_event(inst); + + flag_last_buffer_done(inst); + } + spin_unlock_irqrestore(&inst->state_spinlock, flags); + } + + /* + * During a resolution change and while draining, the firmware may flush + * the reorder queue regardless of having a matching decoding operation + * pending. Only terminate the job if there are no more IRQ coming. + */ + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + if (q_status.report_queue_count == 0 && + (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) { + dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } +} + +static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card)); + + return 0; +} + +static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = vpu_fmt->min_width; + fsize->stepwise.max_width = vpu_fmt->max_width; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = vpu_fmt->min_height; + fsize->stepwise.max_height = vpu_fmt->max_height; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int wave5_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + const struct vpu_format *vpu_fmt; + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u nm planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + } else { + const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); + + width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); + height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + f->fmt.pix_mp.num_planes = info->mem_planes; + } + + if (p_dec_info->initial_info_obtained) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + } + + wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + f->fmt.pix_mp.flags = 0; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + ret = wave5_vpu_dec_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->dst_fmt.width = f->fmt.pix_mp.width; + inst->dst_fmt.height = f->fmt.pix_mp.height; + inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->dst_fmt.field = f->fmt.pix_mp.field; + inst->dst_fmt.flags = f->fmt.pix_mp.flags; + inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + inst->output_format = FORMAT_420; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + inst->output_format = FORMAT_420; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + inst->output_format = FORMAT_422; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + inst->output_format = FORMAT_422; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422P || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422M) { + inst->cbcr_interleave = false; + inst->nv21 = false; + inst->output_format = FORMAT_422; + } else { + inst->cbcr_interleave = false; + inst->nv21 = false; + inst->output_format = FORMAT_420; + } + + return 0; +} + +static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->dst_fmt.width; + f->fmt.pix_mp.height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.field = inst->dst_fmt.field; + f->fmt.pix_mp.flags = inst->dst_fmt.flags; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED; + + return 0; +} + +static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; + wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + } else { + int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); + int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + f->fmt.pix_mp.num_planes = 1; + wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + } + + f->fmt.pix_mp.flags = 0; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + + return 0; +} + +static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_dec_try_fmt_out(file, fh, f); + if (ret) + return ret; + + inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type); + if (inst->std == STD_UNKNOWN) { + dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + inst->src_fmt.width = f->fmt.pix_mp.width; + inst->src_fmt.height = f->fmt.pix_mp.height; + inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->src_fmt.field = f->fmt.pix_mp.field; + inst->src_fmt.flags = f->fmt.pix_mp.flags; + inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + inst->colorspace = f->fmt.pix_mp.colorspace; + inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + inst->quantization = f->fmt.pix_mp.quantization; + inst->xfer_func = f->fmt.pix_mp.xfer_func; + + wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + + return 0; +} + +static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + break; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.left = 0; + s->r.top = 0; + if (inst->state > VPU_INST_STATE_OPEN) { + s->r = inst->conf_win; + } else { + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_COMPOSE w: %u h: %u\n", + s->r.width, s->r.height); + + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + + return 0; +} + +static int wave5_vpu_dec_stop(struct vpu_instance *inst) +{ + int ret = 0; + unsigned long flags; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + spin_lock_irqsave(&inst->state_spinlock, flags); + + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + + if (inst->state != VPU_INST_STATE_NONE) { + /* + * Temporarily release the state_spinlock so that subsequent + * calls do not block on a mutex while inside this spinlock. + */ + spin_unlock_irqrestore(&inst->state_spinlock, flags); + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + return ret; + + spin_lock_irqsave(&inst->state_spinlock, flags); + /* + * TODO eliminate this check by using a separate check for + * draining triggered by a resolution change. + */ + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + } + + /* + * Used to remember the EOS state after the streamoff/on transition on + * the capture queue. + */ + inst->eos = true; + + if (m2m_ctx->has_stopped) + goto unlock_and_return; + + m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); + m2m_ctx->is_draining = true; + + /* + * Deferred to device run in case it wasn't in the ring buffer + * yet. In other case, we have to send the EOS signal to the + * firmware so that any pending PIC_RUN ends without new + * bitstream buffer. + */ + if (m2m_ctx->last_src_buf) + goto unlock_and_return; + + if (inst->state == VPU_INST_STATE_NONE) { + send_eos_event(inst); + flag_last_buffer_done(inst); + } + +unlock_and_return: + spin_unlock_irqrestore(&inst->state_spinlock, flags); + return ret; +} + +static int wave5_vpu_dec_start(struct vpu_instance *inst) +{ + int ret = 0; + unsigned long flags; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + + spin_lock_irqsave(&inst->state_spinlock, flags); + + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + + if (m2m_ctx->has_stopped) + m2m_ctx->has_stopped = false; + + vb2_clear_last_buffer_dequeued(dst_vq); + inst->eos = false; + +unlock_and_return: + spin_unlock_irqrestore(&inst->state_spinlock, flags); + return ret; +} + +static int wave5_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + dev_dbg(inst->dev->dev, "decoder command: %u\n", dc->cmd); + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + if (ret) + return ret; + + switch (dc->cmd) { + case V4L2_DEC_CMD_STOP: + ret = wave5_vpu_dec_stop(inst); + /* Just in case we don't have anything to decode anymore */ + v4l2_m2m_try_schedule(m2m_ctx); + break; + case V4L2_DEC_CMD_START: + ret = wave5_vpu_dec_start(inst); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops wave5_vpu_dec_ioctl_ops = { + .vidioc_querycap = wave5_vpu_dec_querycap, + .vidioc_enum_framesizes = wave5_vpu_dec_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave5_vpu_dec_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_dec_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_dec_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_dec_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave5_vpu_dec_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave5_vpu_dec_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave5_vpu_dec_try_fmt_out, + + .vidioc_g_selection = wave5_vpu_dec_g_selection, + .vidioc_s_selection = wave5_vpu_dec_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + /* + * Firmware does not support CREATE_BUFS for CAPTURE queue. Since + * there is no immediate use-case for supporting CREATE_BUFS on + * just the OUTPUT queue, disable CREATE_BUFS altogether. + */ + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = wave5_vpu_dec_decoder_cmd, + + .vidioc_subscribe_event = wave5_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + + dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, + *num_buffers, *num_planes, q->type); + + *num_planes = inst_format.num_planes; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + sizes[0] = inst_format.plane_fmt[0].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (*num_buffers < inst->fbc_buf_count) + *num_buffers = inst->fbc_buf_count; + + if (*num_planes == 1) { + if (inst->output_format == FORMAT_422) + sizes[0] = inst_format.width * inst_format.height * 2; + else + sizes[0] = inst_format.width * inst_format.height * 3 / 2; + dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]); + } else if (*num_planes == 2) { + sizes[0] = inst_format.width * inst_format.height; + if (inst->output_format == FORMAT_422) + sizes[1] = inst_format.width * inst_format.height; + else + sizes[1] = inst_format.width * inst_format.height / 2; + dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n", + __func__, sizes[0], sizes[1]); + } else if (*num_planes == 3) { + sizes[0] = inst_format.width * inst_format.height; + if (inst->output_format == FORMAT_422) { + sizes[1] = inst_format.width * inst_format.height / 2; + sizes[2] = inst_format.width * inst_format.height / 2; + } else { + sizes[1] = inst_format.width * inst_format.height / 4; + sizes[2] = inst_format.width * inst_format.height / 4; + } + dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n", + __func__, sizes[0], sizes[1], sizes[2]); + } + } + + return 0; +} + +static int wave5_prepare_fb(struct vpu_instance *inst) +{ + int linear_num; + int non_linear_num; + int fb_stride = 0, fb_height = 0; + int luma_size, chroma_size; + int ret, i; + struct v4l2_m2m_buffer *buf, *n; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx); + non_linear_num = inst->fbc_buf_count; + + for (i = 0; i < non_linear_num; i++) { + struct frame_buffer *frame = &inst->frame_buf[i]; + struct vpu_buf *vframe = &inst->frame_vbuf[i]; + + fb_stride = inst->dst_fmt.width; + fb_height = ALIGN(inst->dst_fmt.height, 32); + luma_size = fb_stride * fb_height; + + chroma_size = ALIGN(fb_stride / 2, 16) * fb_height; + + if (vframe->size == (luma_size + chroma_size)) + continue; + + if (vframe->size) + wave5_vpu_dec_reset_framebuffer(inst, i); + + vframe->size = luma_size + chroma_size; + ret = wave5_vdi_allocate_dma_memory(inst->dev, vframe); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Allocating FBC buf of size %zu, fail: %d\n", + __func__, vframe->size, ret); + return ret; + } + + frame->buf_y = vframe->daddr; + frame->buf_cb = vframe->daddr + luma_size; + frame->buf_cr = (dma_addr_t)-1; + frame->size = vframe->size; + frame->width = inst->src_fmt.width; + frame->stride = fb_stride; + frame->map_type = COMPRESSED_FRAME_MAP; + frame->update_fb_info = true; + } + /* In case the count has reduced, clean up leftover framebuffer memory */ + for (i = non_linear_num; i < MAX_REG_FRAME; i++) { + ret = wave5_vpu_dec_reset_framebuffer(inst, i); + if (ret) + break; + } + + for (i = 0; i < linear_num; i++) { + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + struct vb2_buffer *vb = vb2_get_buffer(dst_vq, i); + struct frame_buffer *frame = &inst->frame_buf[non_linear_num + i]; + dma_addr_t buf_addr_y = 0, buf_addr_cb = 0, buf_addr_cr = 0; + u32 buf_size = 0; + u32 fb_stride = inst->dst_fmt.width; + u32 luma_size = fb_stride * inst->dst_fmt.height; + u32 chroma_size; + + if (inst->output_format == FORMAT_422) + chroma_size = fb_stride * inst->dst_fmt.height / 2; + else + chroma_size = fb_stride * inst->dst_fmt.height / 4; + + if (inst->dst_fmt.num_planes == 1) { + buf_size = vb2_plane_size(vb, 0); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = buf_addr_y + luma_size; + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 2) { + buf_size = vb2_plane_size(vb, 0) + + vb2_plane_size(vb, 1); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1); + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 3) { + buf_size = vb2_plane_size(vb, 0) + + vb2_plane_size(vb, 1) + + vb2_plane_size(vb, 2); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1); + buf_addr_cr = vb2_dma_contig_plane_dma_addr(vb, 2); + } + + frame->buf_y = buf_addr_y; + frame->buf_cb = buf_addr_cb; + frame->buf_cr = buf_addr_cr; + frame->size = buf_size; + frame->width = inst->src_fmt.width; + frame->stride = fb_stride; + frame->map_type = LINEAR_FRAME_MAP; + frame->update_fb_info = true; + } + + ret = wave5_vpu_dec_register_frame_buffer_ex(inst, non_linear_num, linear_num, + fb_stride, inst->dst_fmt.height); + if (ret) { + dev_dbg(inst->dev->dev, "%s: vpu_dec_register_frame_buffer_ex fail: %d", + __func__, ret); + return ret; + } + + /* + * Mark all frame buffers as out of display, to avoid using them before + * the application have them queued. + */ + for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) { + ret = wave5_vpu_dec_set_disp_flag(inst, i); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Setting display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + } + + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *vbuf = &buf->vb; + + ret = wave5_vpu_dec_clr_disp_flag(inst, vbuf->vb2_buf.index); + if (ret) + dev_dbg(inst->dev->dev, + "%s: Clearing display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + + return 0; +} + +static int write_to_ringbuffer(struct vpu_instance *inst, void *buffer, size_t buffer_size, + struct vpu_buf *ring_buffer, dma_addr_t wr_ptr) +{ + size_t size; + size_t offset = wr_ptr - ring_buffer->daddr; + int ret; + + if (wr_ptr + buffer_size > ring_buffer->daddr + ring_buffer->size) { + size = ring_buffer->daddr + ring_buffer->size - wr_ptr; + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer, size); + if (ret < 0) + return ret; + + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, 0, (u8 *)buffer + size, + buffer_size - size); + if (ret < 0) + return ret; + } else { + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer, + buffer_size); + if (ret < 0) + return ret; + } + + return 0; +} + +static int fill_ringbuffer(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + int ret; + + if (m2m_ctx->last_src_buf) { + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf); + + if (vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "last src buffer already written\n"); + return 0; + } + } + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *vbuf = &buf->vb; + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf); + struct vpu_buf *ring_buffer = &inst->bitstream_vbuf; + size_t src_size = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + void *src_buf = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + dma_addr_t rd_ptr = 0; + dma_addr_t wr_ptr = 0; + size_t remain_size = 0; + + if (vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "already copied src buf (%u) to the ring buffer\n", + vbuf->vb2_buf.index); + continue; + } + + if (!src_buf) { + dev_dbg(inst->dev->dev, + "%s: Acquiring kernel pointer to src buf (%u), fail\n", + __func__, vbuf->vb2_buf.index); + break; + } + + ret = wave5_vpu_dec_get_bitstream_buffer(inst, &rd_ptr, &wr_ptr, &remain_size); + if (ret) { + /* Unable to acquire the mutex */ + dev_err(inst->dev->dev, "Getting the bitstream buffer, fail: %d\n", + ret); + return ret; + } + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &rd_ptr, &wr_ptr); + + if (remain_size < src_size) { + dev_dbg(inst->dev->dev, + "%s: remaining size: %zu < source size: %zu for src buf (%u)\n", + __func__, remain_size, src_size, vbuf->vb2_buf.index); + break; + } + + ret = write_to_ringbuffer(inst, src_buf, src_size, ring_buffer, wr_ptr); + if (ret) { + dev_err(inst->dev->dev, "Write src buf (%u) to ring buffer, fail: %d\n", + vbuf->vb2_buf.index, ret); + return ret; + } + + ret = wave5_vpu_dec_update_bitstream_buffer(inst, src_size); + if (ret) { + dev_dbg(inst->dev->dev, + "update_bitstream_buffer fail: %d for src buf (%u)\n", + ret, vbuf->vb2_buf.index); + break; + } + + vpu_buf->consumed = true; + + /* Don't write buffers passed the last one while draining. */ + if (v4l2_m2m_is_last_draining_src_buf(m2m_ctx, vbuf)) { + dev_dbg(inst->dev->dev, "last src buffer written to the ring bufferur\n"); + break; + } + } + + return 0; +} + +static void wave5_vpu_dec_buf_queue_src(struct vb2_buffer *vb) +{ + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf); + + vpu_buf->consumed = false; + vbuf->sequence = inst->queued_src_buf_num++; + + v4l2_m2m_buf_queue(m2m_ctx, vbuf); +} + +static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + vbuf->sequence = inst->queued_dst_buf_num++; + + if (inst->state == VPU_INST_STATE_PIC_RUN) { + struct vpu_dst_buffer *vpu_buf = wave5_to_vpu_dst_buf(vbuf); + int ret; + + /* + * The buffer is already registered just clear the display flag + * to let the firmware know it can be used. + */ + vpu_buf->display = false; + ret = wave5_vpu_dec_clr_disp_flag(inst, vb->index); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Clearing the display flag of buffer index: %u, fail: %d\n", + __func__, vb->index, ret); + } + } + + if (vb2_is_streaming(vb->vb2_queue) && v4l2_m2m_dst_buf_is_last(m2m_ctx)) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb2_set_plane_payload(vb, i, 0); + + vbuf->field = V4L2_FIELD_NONE; + + send_eos_event(inst); + v4l2_m2m_last_buffer_done(m2m_ctx, vbuf); + } else { + v4l2_m2m_buf_queue(m2m_ctx, vbuf); + } +} + +static void wave5_vpu_dec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + + dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n", + __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + wave5_vpu_dec_buf_queue_src(vb); + else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + wave5_vpu_dec_buf_queue_dst(vb); +} + +static int wave5_vpu_dec_allocate_ring_buffer(struct vpu_instance *inst) +{ + int ret; + struct vpu_buf *ring_buffer = &inst->bitstream_vbuf; + + ring_buffer->size = ALIGN(inst->src_fmt.plane_fmt[0].sizeimage, 1024) * 4; + ret = wave5_vdi_allocate_dma_memory(inst->dev, ring_buffer); + if (ret) { + dev_dbg(inst->dev->dev, "%s: allocate ring buffer of size %zu fail: %d\n", + __func__, ring_buffer->size, ret); + return ret; + } + + inst->last_rd_ptr = ring_buffer->daddr; + + return 0; +} + +static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + + v4l2_m2m_update_start_streaming_state(m2m_ctx, q); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && inst->state == VPU_INST_STATE_NONE) { + struct dec_open_param open_param; + + memset(&open_param, 0, sizeof(struct dec_open_param)); + + ret = wave5_vpu_dec_allocate_ring_buffer(inst); + if (ret) + goto return_buffers; + + open_param.bitstream_buffer = inst->bitstream_vbuf.daddr; + open_param.bitstream_buffer_size = inst->bitstream_vbuf.size; + + ret = wave5_vpu_dec_open(inst, &open_param); + if (ret) { + dev_dbg(inst->dev->dev, "%s: decoder opening, fail: %d\n", + __func__, ret); + goto free_bitstream_vbuf; + } + + ret = switch_state(inst, VPU_INST_STATE_OPEN); + if (ret) + goto free_bitstream_vbuf; + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + struct dec_initial_info *initial_info = + &inst->codec_info->dec_info.initial_info; + + if (inst->state == VPU_INST_STATE_STOP) + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + goto return_buffers; + + if (inst->state == VPU_INST_STATE_INIT_SEQ) { + if (initial_info->luma_bitdepth != 8) { + dev_info(inst->dev->dev, "%s: no support for %d bit depth", + __func__, initial_info->luma_bitdepth); + ret = -EINVAL; + goto return_buffers; + } + } + } + + return ret; + +free_bitstream_vbuf: + wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); +return_buffers: + wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + return ret; +} + +static int streamoff_output(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + int ret; + dma_addr_t new_rd_ptr; + + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: (Multiplanar) buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + ret = wave5_vpu_flush_instance(inst); + if (ret) + return ret; + + /* Reset the ring buffer information */ + new_rd_ptr = wave5_vpu_dec_get_rd_ptr(inst); + inst->last_rd_ptr = new_rd_ptr; + inst->codec_info->dec_info.stream_rd_ptr = new_rd_ptr; + inst->codec_info->dec_info.stream_wr_ptr = new_rd_ptr; + + if (v4l2_m2m_has_stopped(m2m_ctx)) + send_eos_event(inst); + + /* streamoff on output cancels any draining operation */ + inst->eos = false; + + return 0; +} + +static int streamoff_capture(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + unsigned int i; + int ret = 0; + + for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) { + ret = wave5_vpu_dec_set_disp_flag(inst, i); + if (ret) + dev_dbg(inst->dev->dev, + "%s: Setting display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) { + u32 plane; + + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + + for (plane = 0; plane < inst->dst_fmt.num_planes; plane++) + vb2_set_plane_payload(&buf->vb2_buf, plane, 0); + + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + if (inst->needs_reallocation) { + wave5_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO, NULL); + inst->needs_reallocation = false; + } + + if (v4l2_m2m_has_stopped(m2m_ctx)) { + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + return ret; + } + + return 0; +} + +static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + bool check_cmd = TRUE; + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + + while (check_cmd) { + struct queue_status_info q_status; + struct dec_output_info dec_output_info; + + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + + if (q_status.report_queue_count == 0) + break; + + if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0) + break; + + if (wave5_vpu_dec_get_output_info(inst, &dec_output_info)) + dev_dbg(inst->dev->dev, "Getting decoding results from fw, fail\n"); + } + + v4l2_m2m_update_stop_streaming_state(m2m_ctx, q); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + streamoff_output(q); + else + streamoff_capture(q); +} + +static const struct vb2_ops wave5_vpu_dec_vb2_ops = { + .queue_setup = wave5_vpu_dec_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave5_vpu_dec_buf_queue, + .start_streaming = wave5_vpu_dec_start_streaming, + .stop_streaming = wave5_vpu_dec_stop_streaming, +}; + +static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt); + + src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; + src_fmt->field = V4L2_FIELD_NONE; + src_fmt->flags = 0; + src_fmt->num_planes = 1; + wave5_update_pix_fmt(src_fmt, 720, 480); + + dst_fmt->pixelformat = dst_pix_fmt; + dst_fmt->field = V4L2_FIELD_NONE; + dst_fmt->flags = 0; + dst_fmt->num_planes = dst_fmt_info->mem_planes; + wave5_update_pix_fmt(dst_fmt, 736, 480); +} + +static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_dec_vb2_ops); +} + +static const struct vpu_instance_ops wave5_vpu_dec_inst_ops = { + .finish_process = wave5_vpu_dec_finish_decode, +}; + +static int initialize_sequence(struct vpu_instance *inst) +{ + struct dec_initial_info initial_info; + int ret = 0; + + memset(&initial_info, 0, sizeof(struct dec_initial_info)); + + ret = wave5_vpu_dec_issue_seq_init(inst); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_dec_issue_seq_init, fail: %d\n", + __func__, ret); + return ret; + } + + if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0) + dev_dbg(inst->dev->dev, "%s: failed to call vpu_wait_interrupt()\n", __func__); + + ret = wave5_vpu_dec_complete_seq_init(inst, &initial_info); + if (ret) { + dev_dbg(inst->dev->dev, "%s: vpu_dec_complete_seq_init, fail: %d, reason: %u\n", + __func__, ret, initial_info.seq_init_err_reason); + wave5_handle_src_buffer(inst, initial_info.rd_ptr); + return ret; + } + + handle_dynamic_resolution_change(inst); + + return 0; +} + +static bool wave5_is_draining_or_eos(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + lockdep_assert_held(&inst->state_spinlock); + return m2m_ctx->is_draining || inst->eos; +} + +static void wave5_vpu_dec_device_run(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct queue_status_info q_status; + u32 fail_res = 0; + int ret = 0; + + dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); + + ret = fill_ringbuffer(inst); + if (ret) { + dev_warn(inst->dev->dev, "Filling ring buffer failed\n"); + goto finish_job_and_return; + } + + switch (inst->state) { + case VPU_INST_STATE_OPEN: + ret = initialize_sequence(inst); + if (ret) { + unsigned long flags; + + spin_lock_irqsave(&inst->state_spinlock, flags); + if (wave5_is_draining_or_eos(inst) && + wave5_last_src_buffer_consumed(m2m_ctx)) { + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + + switch_state(inst, VPU_INST_STATE_STOP); + + if (vb2_is_streaming(dst_vq)) + send_eos_event(inst); + else + handle_dynamic_resolution_change(inst); + + flag_last_buffer_done(inst); + } + spin_unlock_irqrestore(&inst->state_spinlock, flags); + } else { + switch_state(inst, VPU_INST_STATE_INIT_SEQ); + } + + break; + + case VPU_INST_STATE_INIT_SEQ: + /* + * Do this early, preparing the fb can trigger an IRQ before + * we had a chance to switch, which leads to an invalid state + * change. + */ + switch_state(inst, VPU_INST_STATE_PIC_RUN); + + /* + * During DRC, the picture decoding remains pending, so just leave the job + * active until this decode operation completes. + */ + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + + /* + * The sequence must be analyzed first to calculate the proper + * size of the auxiliary buffers. + */ + ret = wave5_prepare_fb(inst); + if (ret) { + dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret); + switch_state(inst, VPU_INST_STATE_STOP); + break; + } + + if (q_status.instance_queue_count) { + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + return; + } + + fallthrough; + case VPU_INST_STATE_PIC_RUN: + ret = start_decode(inst, &fail_res); + if (ret) { + dev_err(inst->dev->dev, + "Frame decoding on m2m context (%p), fail: %d (result: %d)\n", + m2m_ctx, ret, fail_res); + break; + } + /* Return so that we leave this job active */ + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + return; + default: + WARN(1, "Execution of a job in state %s illegal.\n", state_to_str(inst->state)); + break; + } + +finish_job_and_return: + dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); +} + +static void wave5_vpu_dec_job_abort(void *priv) +{ + struct vpu_instance *inst = priv; + int ret; + + ret = switch_state(inst, VPU_INST_STATE_STOP); + if (ret) + return; + + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + dev_warn(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); +} + +static int wave5_vpu_dec_job_ready(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&inst->state_spinlock, flags); + + switch (inst->state) { + case VPU_INST_STATE_NONE: + dev_dbg(inst->dev->dev, "Decoder must be open to start queueing M2M jobs!\n"); + break; + case VPU_INST_STATE_OPEN: + if (wave5_is_draining_or_eos(inst) || !v4l2_m2m_has_stopped(m2m_ctx) || + v4l2_m2m_num_src_bufs_ready(m2m_ctx) > 0) { + ret = 1; + break; + } + + dev_dbg(inst->dev->dev, + "Decoder must be draining or >= 1 OUTPUT queue buffer must be queued!\n"); + break; + case VPU_INST_STATE_INIT_SEQ: + case VPU_INST_STATE_PIC_RUN: + if (!m2m_ctx->cap_q_ctx.q.streaming) { + dev_dbg(inst->dev->dev, "CAPTURE queue must be streaming to queue jobs!\n"); + break; + } else if (v4l2_m2m_num_dst_bufs_ready(m2m_ctx) < (inst->fbc_buf_count - 1)) { + dev_dbg(inst->dev->dev, + "No capture buffer ready to decode!\n"); + break; + } else if (!wave5_is_draining_or_eos(inst) && + !v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, + "No bitstream data to decode!\n"); + break; + } + ret = 1; + break; + case VPU_INST_STATE_STOP: + dev_dbg(inst->dev->dev, "Decoder is stopped, not running.\n"); + break; + } + + spin_unlock_irqrestore(&inst->state_spinlock, flags); + + return ret; +} + +static const struct v4l2_m2m_ops wave5_vpu_dec_m2m_ops = { + .device_run = wave5_vpu_dec_device_run, + .job_abort = wave5_vpu_dec_job_abort, + .job_ready = wave5_vpu_dec_job_ready, +}; + +static int wave5_vpu_open_dec(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + struct v4l2_m2m_ctx *m2m_ctx; + int ret = 0; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_DEC; + inst->ops = &wave5_vpu_dec_inst_ops; + + spin_lock_init(&inst->state_spinlock); + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) + return -ENOMEM; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + INIT_LIST_HEAD(&inst->list); + list_add_tail(&inst->list, &dev->instances); + + inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_dec_dev; + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_dec_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto cleanup_inst; + } + m2m_ctx = inst->v4l2_fh.m2m_ctx; + + v4l2_m2m_set_src_buffered(m2m_ctx, true); + v4l2_m2m_set_dst_buffered(m2m_ctx, true); + /* + * We use the M2M job queue to ensure synchronization of steps where + * needed, as IOCTLs can occur at anytime and we need to run commands on + * the firmware in a specified order. + * In order to initialize the sequence on the firmware within an M2M + * job, the M2M framework needs to be able to queue jobs before + * the CAPTURE queue has been started, because we need the results of the + * initialization to properly prepare the CAPTURE queue with the correct + * amount of buffers. + * By setting ignore_cap_streaming to true the m2m framework will call + * job_ready as soon as the OUTPUT queue is streaming, instead of + * waiting until both the CAPTURE and OUTPUT queues are streaming. + */ + m2m_ctx->ignore_cap_streaming = true; + + v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10); + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1); + + if (inst->v4l2_ctrl_hdl.error) { + ret = -ENODEV; + goto cleanup_inst; + } + + inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl); + + wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->colorspace = V4L2_COLORSPACE_REC709; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + init_completion(&inst->irq_done); + + inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL); + if (inst->id < 0) { + dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id); + ret = inst->id; + goto cleanup_inst; + } + + wave5_vdi_allocate_sram(inst->dev); + + return 0; + +cleanup_inst: + wave5_cleanup_instance(inst); + return ret; +} + +static int wave5_vpu_dec_release(struct file *filp) +{ + return wave5_vpu_release_device(filp, wave5_vpu_dec_close, "decoder"); +} + +static const struct v4l2_file_operations wave5_vpu_dec_fops = { + .owner = THIS_MODULE, + .open = wave5_vpu_open_dec, + .release = wave5_vpu_dec_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave5_vpu_dec_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_dec; + int ret; + + vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); + if (!vdev_dec) + return -ENOMEM; + + dev->v4l2_m2m_dec_dev = v4l2_m2m_init(&wave5_vpu_dec_m2m_ops); + if (IS_ERR(dev->v4l2_m2m_dec_dev)) { + ret = PTR_ERR(dev->v4l2_m2m_dec_dev); + dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret); + return -EINVAL; + } + + dev->video_dev_dec = vdev_dec; + + strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec->name)); + vdev_dec->fops = &wave5_vpu_dec_fops; + vdev_dec->ioctl_ops = &wave5_vpu_dec_ioctl_ops; + vdev_dec->release = video_device_release_empty; + vdev_dec->v4l2_dev = &dev->v4l2_dev; + vdev_dec->vfl_dir = VFL_DIR_M2M; + vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_dec->lock = &dev->dev_lock; + + ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + video_set_drvdata(vdev_dec, dev); + + return 0; +} + +void wave5_vpu_dec_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_dec); + if (dev->v4l2_m2m_dec_dev) + v4l2_m2m_release(dev->v4l2_m2m_dec_dev); +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c new file mode 100644 index 000000000000..f29cfa3af94a --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -0,0 +1,1794 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - encoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include "wave5-helper.h" + +#define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder" +#define VPU_ENC_DRV_NAME "wave5-enc" + +static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + }, + } +}; + +static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + goto invalid_state_switch; + case VPU_INST_STATE_OPEN: + if (inst->state != VPU_INST_STATE_NONE) + goto invalid_state_switch; + break; + case VPU_INST_STATE_INIT_SEQ: + if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP) + goto invalid_state_switch; + break; + case VPU_INST_STATE_PIC_RUN: + if (inst->state != VPU_INST_STATE_INIT_SEQ) + goto invalid_state_switch; + break; + case VPU_INST_STATE_STOP: + break; + }; + + dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + inst->state = state; + return 0; + +invalid_state_switch: + WARN(1, "Invalid state switch from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + return -EINVAL; +} + +static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, + unsigned int height) +{ + switch (pix_mp->pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + pix_mp->width = width; + pix_mp->height = height; + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2; + break; + case V4L2_PIX_FMT_YUV420M: + pix_mp->width = width; + pix_mp->height = height; + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4; + pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; + pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + pix_mp->width = width; + pix_mp->height = height; + pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; + pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); + pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2; + break; + default: + pix_mp->width = width; + pix_mp->height = height; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3; + break; + } +} + +static int start_encode(struct vpu_instance *inst, u32 *fail_res) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct frame_buffer frame_buf; + struct enc_param pic_param; + u32 stride = ALIGN(inst->dst_fmt.width, 32); + u32 luma_size = (stride * inst->dst_fmt.height); + u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2)); + + memset(&pic_param, 0, sizeof(struct enc_param)); + memset(&frame_buf, 0, sizeof(struct frame_buffer)); + + dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); + if (!dst_buf) { + dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__); + return -EAGAIN; + } + + pic_param.pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + pic_param.pic_stream_buffer_size = + vb2_plane_size(&dst_buf->vb2_buf, 0); + + src_buf = v4l2_m2m_next_src_buf(m2m_ctx); + if (!src_buf) { + dev_dbg(inst->dev->dev, "%s: No source buffer found\n", __func__); + if (m2m_ctx->is_draining) + pic_param.src_end_flag = 1; + else + return -EAGAIN; + } else { + if (inst->src_fmt.num_planes == 1) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = frame_buf.buf_y + luma_size; + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 2) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1); + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 3) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1); + frame_buf.buf_cr = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 2); + } + frame_buf.stride = stride; + pic_param.src_idx = src_buf->vb2_buf.index; + } + + pic_param.source_frame = &frame_buf; + pic_param.code_option.implicit_header_encode = 1; + pic_param.code_option.encode_aud = inst->encode_aud; + ret = wave5_vpu_enc_start_one_frame(inst, &pic_param, fail_res); + if (ret) { + if (*fail_res == WAVE5_SYSERR_QUEUEING_FAIL) + return -EINVAL; + + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n", + __func__, ret); + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + if (!src_buf) { + dev_dbg(inst->dev->dev, + "%s: Removing src buf failed, the queue is empty\n", + __func__); + return -EINVAL; + } + dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!dst_buf) { + dev_dbg(inst->dev->dev, + "%s: Removing dst buf failed, the queue is empty\n", + __func__); + return -EINVAL; + } + switch_state(inst, VPU_INST_STATE_STOP); + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + } else { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n", + __func__); + /* + * Remove the source buffer from the ready-queue now and finish + * it in the videobuf2 framework once the index is returned by the + * firmware in finish_encode + */ + if (src_buf) + v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, src_buf->vb2_buf.index); + } + + return 0; +} + +static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + struct enc_output_info enc_output_info; + struct vb2_v4l2_buffer *src_buf = NULL; + struct vb2_v4l2_buffer *dst_buf = NULL; + + ret = wave5_vpu_enc_get_output_info(inst, &enc_output_info); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: vpu_enc_get_output_info fail: %d reason: %u | info: %u\n", + __func__, ret, enc_output_info.error_reason, enc_output_info.warn_info); + return; + } + + dev_dbg(inst->dev->dev, + "%s: pic_type %i recon_idx %i src_idx %i pic_byte %u pts %llu\n", + __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index, + enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts); + + /* + * The source buffer will not be found in the ready-queue as it has been + * dropped after sending of the encode firmware command, locate it in + * the videobuf2 queue directly + */ + if (enc_output_info.enc_src_idx >= 0) { + struct vb2_buffer *vb = vb2_get_buffer(v4l2_m2m_get_src_vq(m2m_ctx), + enc_output_info.enc_src_idx); + if (vb->state != VB2_BUF_STATE_ACTIVE) + dev_warn(inst->dev->dev, + "%s: encoded buffer (%d) was not in ready queue %i.", + __func__, enc_output_info.enc_src_idx, vb->state); + else + src_buf = to_vb2_v4l2_buffer(vb); + + if (src_buf) { + inst->timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n", + __func__, enc_output_info.enc_src_idx); + } + } + + dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_ENC_END) { + static const struct v4l2_event vpu_event_eos = { + .type = V4L2_EVENT_EOS + }; + + if (!WARN_ON(!dst_buf)) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->field = V4L2_FIELD_NONE; + v4l2_m2m_last_buffer_done(m2m_ctx, dst_buf); + } + + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos); + + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } else { + if (!dst_buf) { + dev_warn(inst->dev->dev, "No bitstream buffer."); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_output_info.bitstream_size); + + dst_buf->vb2_buf.timestamp = inst->timestamp; + dst_buf->field = V4L2_FIELD_NONE; + if (enc_output_info.pic_type == PIC_TYPE_I) { + if (enc_output_info.enc_vcl_nut == 19 || + enc_output_info.enc_vcl_nut == 20) + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + } else if (enc_output_info.pic_type == PIC_TYPE_P) { + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + } else if (enc_output_info.pic_type == PIC_TYPE_B) { + dst_buf->flags |= V4L2_BUF_FLAG_BFRAME; + } + + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + dev_dbg(inst->dev->dev, "%s: frame_cycle %8u\n", + __func__, enc_output_info.frame_cycle); + + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } +} + +static int wave5_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card)); + + return 0; +} + +static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = vpu_fmt->min_width; + fsize->stepwise.max_width = vpu_fmt->max_width; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = vpu_fmt->min_height; + fsize->stepwise.max_height = vpu_fmt->max_height; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height); + } else { + int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); + int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + f->fmt.pix_mp.num_planes = 1; + wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + } + + f->fmt.pix_mp.flags = 0; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_enc_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type); + if (inst->std == STD_UNKNOWN) { + dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + inst->dst_fmt.width = f->fmt.pix_mp.width; + inst->dst_fmt.height = f->fmt.pix_mp.height; + inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->dst_fmt.field = f->fmt.pix_mp.field; + inst->dst_fmt.flags = f->fmt.pix_mp.flags; + inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + return 0; +} + +static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->dst_fmt.width; + f->fmt.pix_mp.height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.field = inst->dst_fmt.field; + f->fmt.pix_mp.flags = inst->dst_fmt.flags; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) { + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; + wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + } else { + int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); + int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); + + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + f->fmt.pix_mp.num_planes = info->mem_planes; + wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + } + + f->fmt.pix_mp.flags = 0; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + + return 0; +} + +static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_enc_try_fmt_out(file, fh, f); + if (ret) + return ret; + + inst->src_fmt.width = f->fmt.pix_mp.width; + inst->src_fmt.height = f->fmt.pix_mp.height; + inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->src_fmt.field = f->fmt.pix_mp.field; + inst->src_fmt.flags = f->fmt.pix_mp.flags; + inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + } else { + inst->cbcr_interleave = false; + inst->nv21 = false; + } + + inst->colorspace = f->fmt.pix_mp.colorspace; + inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + inst->quantization = f->fmt.pix_mp.quantization; + inst->xfer_func = f->fmt.pix_mp.xfer_func; + + wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + + return 0; +} + +static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + dev_dbg(inst->dev->dev, "%s: V4L2_SEL_TGT_CROP width: %u | height: %u\n", + __func__, s->r.width, s->r.height); + + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + + return 0; +} + +static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + if (ret) + return ret; + + if (!wave5_vpu_both_queues_are_streaming(inst)) + return 0; + + switch (ec->cmd) { + case V4L2_ENC_CMD_STOP: + if (m2m_ctx->is_draining) + return -EBUSY; + + if (m2m_ctx->has_stopped) + return 0; + + m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); + m2m_ctx->is_draining = true; + break; + case V4L2_ENC_CMD_START: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + + dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n", + __func__, a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) { + inst->frame_rate = a->parm.output.timeperframe.denominator / + a->parm.output.timeperframe.numerator; + } else { + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + } + + dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n", + __func__, a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static const struct v4l2_ioctl_ops wave5_vpu_enc_ioctl_ops = { + .vidioc_querycap = wave5_vpu_enc_querycap, + .vidioc_enum_framesizes = wave5_vpu_enc_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave5_vpu_enc_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_enc_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_enc_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_enc_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave5_vpu_enc_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave5_vpu_enc_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave5_vpu_enc_try_fmt_out, + + .vidioc_g_selection = wave5_vpu_enc_g_selection, + .vidioc_s_selection = wave5_vpu_enc_s_selection, + + .vidioc_g_parm = wave5_vpu_enc_g_parm, + .vidioc_s_parm = wave5_vpu_enc_s_parm, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = wave5_vpu_enc_encoder_cmd, + + .vidioc_subscribe_event = wave5_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vpu_instance *inst = wave5_ctrl_to_vpu_inst(ctrl); + + dev_dbg(inst->dev->dev, "%s: name: %s | value: %d\n", __func__, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: + inst->encode_aud = ctrl->val; + break; + case V4L2_CID_HFLIP: + inst->mirror_direction |= (ctrl->val << 1); + break; + case V4L2_CID_VFLIP: + inst->mirror_direction |= ctrl->val; + break; + case V4L2_CID_ROTATE: + inst->rot_angle = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + inst->vbv_buf_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + inst->rc_mode = 0; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + inst->rc_mode = 1; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + inst->bit_rate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + inst->enc_param.avc_idr_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + inst->enc_param.independ_slice_mode = ctrl->val; + inst->enc_param.avc_slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + inst->enc_param.independ_slice_mode_arg = ctrl->val; + inst->enc_param.avc_slice_arg = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + inst->rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + inst->enc_param.mb_level_rc_enable = ctrl->val; + inst->enc_param.cu_level_rc_enable = ctrl->val; + inst->enc_param.hvs_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + inst->enc_param.profile = HEVC_PROFILE_MAIN; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + inst->enc_param.profile = HEVC_PROFILE_STILLPICTURE; + inst->enc_param.en_still_picture = 1; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + inst->enc_param.profile = HEVC_PROFILE_MAIN10; + inst->bit_depth = 10; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + inst->enc_param.level = 10 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + inst->enc_param.level = 20 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + inst->enc_param.level = 21 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + inst->enc_param.level = 30 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + inst->enc_param.level = 31 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + inst->enc_param.level = 40 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + inst->enc_param.level = 41 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + inst->enc_param.level = 50 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + inst->enc_param.level = 51 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: + inst->enc_param.level = 52 * 3; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + inst->enc_param.min_qp_i = ctrl->val; + inst->enc_param.min_qp_p = ctrl->val; + inst->enc_param.min_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + inst->enc_param.max_qp_i = ctrl->val; + inst->enc_param.max_qp_p = ctrl->val; + inst->enc_param.max_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + inst->enc_param.intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + inst->enc_param.disable_deblk = 1; + inst->enc_param.sao_enable = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + inst->enc_param.disable_deblk = 0; + inst->enc_param.sao_enable = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + inst->enc_param.disable_deblk = 0; + inst->enc_param.sao_enable = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + inst->enc_param.beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + inst->enc_param.tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE: + inst->enc_param.decoding_refresh_type = 0; + break; + case V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA: + inst->enc_param.decoding_refresh_type = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR: + inst->enc_param.decoding_refresh_type = 2; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + inst->enc_param.intra_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + inst->enc_param.lossless_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + inst->enc_param.const_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + inst->enc_param.wpp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + inst->enc_param.strong_intra_smooth_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + inst->enc_param.max_num_merge = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + inst->enc_param.tmvp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + inst->enc_param.profile = H264_PROFILE_BP; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + inst->enc_param.profile = H264_PROFILE_MP; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + inst->enc_param.profile = H264_PROFILE_EXTENDED; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + inst->enc_param.profile = H264_PROFILE_HP; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + inst->enc_param.profile = H264_PROFILE_HIGH10; + inst->bit_depth = 10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + inst->enc_param.profile = H264_PROFILE_HIGH422; + inst->bit_depth = 10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + inst->enc_param.profile = H264_PROFILE_HIGH444; + inst->bit_depth = 10; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + inst->enc_param.level = 10; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + inst->enc_param.level = 9; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + inst->enc_param.level = 11; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + inst->enc_param.level = 12; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + inst->enc_param.level = 13; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + inst->enc_param.level = 20; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + inst->enc_param.level = 21; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + inst->enc_param.level = 22; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + inst->enc_param.level = 30; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + inst->enc_param.level = 31; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + inst->enc_param.level = 32; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + inst->enc_param.level = 40; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + inst->enc_param.level = 41; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + inst->enc_param.level = 42; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + inst->enc_param.level = 50; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + inst->enc_param.level = 51; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + inst->enc_param.min_qp_i = ctrl->val; + inst->enc_param.min_qp_p = ctrl->val; + inst->enc_param.min_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + inst->enc_param.max_qp_i = ctrl->val; + inst->enc_param.max_qp_p = ctrl->val; + inst->enc_param.max_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + inst->enc_param.intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + inst->enc_param.disable_deblk = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + inst->enc_param.disable_deblk = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + inst->enc_param.disable_deblk = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + inst->enc_param.beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + inst->enc_param.tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + inst->enc_param.transform8x8_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + inst->enc_param.const_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + inst->enc_param.chroma_cb_qp_offset = ctrl->val; + inst->enc_param.chroma_cr_qp_offset = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: + inst->enc_param.intra_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + inst->enc_param.entropy_coding_mode = ctrl->val; + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops wave5_vpu_enc_ctrl_ops = { + .s_ctrl = wave5_vpu_enc_s_ctrl, +}; + +static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; + + dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, + *num_buffers, *num_planes, q->type); + + if (*num_planes) { + if (inst_format.num_planes != *num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < inst_format.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = inst_format.num_planes; + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]); + } + } + + dev_dbg(inst->dev->dev, "%s: size: %u\n", __func__, sizes[0]); + + return 0; +} + +static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n", + __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + vbuf->sequence = inst->queued_src_buf_num++; + else + vbuf->sequence = inst->queued_dst_buf_num++; + + v4l2_m2m_buf_queue(m2m_ctx, vbuf); +} + +static void wave5_set_enc_openparam(struct enc_open_param *open_param, + struct vpu_instance *inst) +{ + struct enc_wave_param input = inst->enc_param; + u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64; + u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16; + + open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE; + open_param->wave_param.hvs_qp_scale = 2; + open_param->wave_param.hvs_max_delta_qp = 10; + open_param->wave_param.skip_intra_trans = 1; + open_param->wave_param.intra_nx_n_enable = 1; + open_param->wave_param.nr_intra_weight_y = 7; + open_param->wave_param.nr_intra_weight_cb = 7; + open_param->wave_param.nr_intra_weight_cr = 7; + open_param->wave_param.nr_inter_weight_y = 4; + open_param->wave_param.nr_inter_weight_cb = 4; + open_param->wave_param.nr_inter_weight_cr = 4; + open_param->wave_param.rdo_skip = 1; + open_param->wave_param.lambda_scaling_enable = 1; + + open_param->line_buf_int_en = true; + open_param->pic_width = inst->dst_fmt.width; + open_param->pic_height = inst->dst_fmt.height; + open_param->frame_rate_info = inst->frame_rate; + open_param->rc_enable = inst->rc_enable; + if (inst->rc_enable) { + open_param->wave_param.initial_rc_qp = -1; + open_param->wave_param.rc_weight_param = 16; + open_param->wave_param.rc_weight_buf = 128; + } + open_param->wave_param.mb_level_rc_enable = input.mb_level_rc_enable; + open_param->wave_param.cu_level_rc_enable = input.cu_level_rc_enable; + open_param->wave_param.hvs_qp_enable = input.hvs_qp_enable; + open_param->bit_rate = inst->bit_rate; + open_param->vbv_buffer_size = inst->vbv_buf_size; + if (inst->rc_mode == 0) + open_param->vbv_buffer_size = 3000; + open_param->wave_param.profile = input.profile; + open_param->wave_param.en_still_picture = input.en_still_picture; + open_param->wave_param.level = input.level; + open_param->wave_param.internal_bit_depth = inst->bit_depth; + open_param->wave_param.intra_qp = input.intra_qp; + open_param->wave_param.min_qp_i = input.min_qp_i; + open_param->wave_param.max_qp_i = input.max_qp_i; + open_param->wave_param.min_qp_p = input.min_qp_p; + open_param->wave_param.max_qp_p = input.max_qp_p; + open_param->wave_param.min_qp_b = input.min_qp_b; + open_param->wave_param.max_qp_b = input.max_qp_b; + open_param->wave_param.disable_deblk = input.disable_deblk; + open_param->wave_param.lf_cross_slice_boundary_enable = + input.lf_cross_slice_boundary_enable; + open_param->wave_param.tc_offset_div2 = input.tc_offset_div2; + open_param->wave_param.beta_offset_div2 = input.beta_offset_div2; + open_param->wave_param.decoding_refresh_type = input.decoding_refresh_type; + open_param->wave_param.intra_period = input.intra_period; + if (inst->std == W_HEVC_ENC) { + if (input.intra_period == 0) { + open_param->wave_param.decoding_refresh_type = DEC_REFRESH_TYPE_IDR; + open_param->wave_param.intra_period = input.avc_idr_period; + } + } else { + open_param->wave_param.avc_idr_period = input.avc_idr_period; + } + open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode; + open_param->wave_param.lossless_enable = input.lossless_enable; + open_param->wave_param.const_intra_pred_flag = input.const_intra_pred_flag; + open_param->wave_param.wpp_enable = input.wpp_enable; + open_param->wave_param.strong_intra_smooth_enable = input.strong_intra_smooth_enable; + open_param->wave_param.max_num_merge = input.max_num_merge; + open_param->wave_param.tmvp_enable = input.tmvp_enable; + open_param->wave_param.transform8x8_enable = input.transform8x8_enable; + open_param->wave_param.chroma_cb_qp_offset = input.chroma_cb_qp_offset; + open_param->wave_param.chroma_cr_qp_offset = input.chroma_cr_qp_offset; + open_param->wave_param.independ_slice_mode = input.independ_slice_mode; + open_param->wave_param.independ_slice_mode_arg = input.independ_slice_mode_arg; + open_param->wave_param.avc_slice_mode = input.avc_slice_mode; + open_param->wave_param.avc_slice_arg = input.avc_slice_arg; + open_param->wave_param.intra_mb_refresh_mode = input.intra_mb_refresh_mode; + if (input.intra_mb_refresh_mode != REFRESH_MB_MODE_NONE) { + if (num_mb_row >= input.intra_mb_refresh_arg) + open_param->wave_param.intra_mb_refresh_arg = + num_mb_row / input.intra_mb_refresh_arg; + else + open_param->wave_param.intra_mb_refresh_arg = num_mb_row; + } + open_param->wave_param.intra_refresh_mode = input.intra_refresh_mode; + if (input.intra_refresh_mode != 0) { + if (num_ctu_row >= input.intra_refresh_arg) + open_param->wave_param.intra_refresh_arg = + num_ctu_row / input.intra_refresh_arg; + else + open_param->wave_param.intra_refresh_arg = num_ctu_row; + } +} + +static int initialize_sequence(struct vpu_instance *inst) +{ + struct enc_initial_info initial_info; + struct v4l2_ctrl *ctrl; + int ret; + + ret = wave5_vpu_enc_issue_seq_init(inst); + if (ret) { + dev_err(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n", + __func__, ret); + return ret; + } + + if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) { + dev_err(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__); + return -EINVAL; + } + + ret = wave5_vpu_enc_complete_seq_init(inst, &initial_info); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n", + __func__, initial_info.min_frame_buffer_count, + initial_info.min_src_frame_count); + inst->min_src_buf_count = initial_info.min_src_frame_count + + COMMAND_QUEUE_DEPTH; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->min_src_buf_count); + + inst->fbc_buf_count = initial_info.min_frame_buffer_count; + + return 0; +} + +static int prepare_fb(struct vpu_instance *inst) +{ + u32 fb_stride = ALIGN(inst->dst_fmt.width, 32); + u32 fb_height = ALIGN(inst->dst_fmt.height, 32); + int i, ret = 0; + + for (i = 0; i < inst->fbc_buf_count; i++) { + u32 luma_size = fb_stride * fb_height; + u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height; + + inst->frame_vbuf[i].size = luma_size + chroma_size; + ret = wave5_vdi_allocate_dma_memory(inst->dev, &inst->frame_vbuf[i]); + if (ret < 0) { + dev_err(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n", + __func__, inst->frame_vbuf[i].size); + goto free_buffers; + } + + inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr; + inst->frame_buf[i].buf_cb = (dma_addr_t)-1; + inst->frame_buf[i].buf_cr = (dma_addr_t)-1; + inst->frame_buf[i].update_fb_info = true; + inst->frame_buf[i].size = inst->frame_vbuf[i].size; + } + + ret = wave5_vpu_enc_register_frame_buffer(inst, inst->fbc_buf_count, fb_stride, + fb_height, COMPRESSED_FRAME_MAP); + if (ret) { + dev_err(inst->dev->dev, + "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n", + __func__, ret); + goto free_buffers; + } + + return 0; +free_buffers: + for (i = 0; i < inst->fbc_buf_count; i++) + wave5_vpu_dec_reset_framebuffer(inst, i); + return ret; +} + +static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + v4l2_m2m_update_start_streaming_state(m2m_ctx, q); + + if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct enc_open_param open_param; + + memset(&open_param, 0, sizeof(struct enc_open_param)); + + wave5_set_enc_openparam(&open_param, inst); + + ret = wave5_vpu_enc_open(inst, &open_param); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_open, fail: %d\n", + __func__, ret); + goto return_buffers; + } + + if (inst->mirror_direction) { + wave5_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL); + wave5_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION, + &inst->mirror_direction); + } + if (inst->rot_angle) { + wave5_vpu_enc_give_command(inst, ENABLE_ROTATION, NULL); + wave5_vpu_enc_give_command(inst, SET_ROTATION_ANGLE, &inst->rot_angle); + } + + ret = switch_state(inst, VPU_INST_STATE_OPEN); + if (ret) + goto return_buffers; + } + if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) { + ret = initialize_sequence(inst); + if (ret) { + dev_warn(inst->dev->dev, "Sequence not found: %d\n", ret); + goto return_buffers; + } + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + goto return_buffers; + /* + * The sequence must be analyzed first to calculate the proper + * size of the auxiliary buffers. + */ + ret = prepare_fb(inst); + if (ret) { + dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret); + goto return_buffers; + } + + ret = switch_state(inst, VPU_INST_STATE_PIC_RUN); + } + if (ret) + goto return_buffers; + + return 0; +return_buffers: + wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void streamoff_output(struct vpu_instance *inst, struct vb2_queue *q) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } +} + +static void streamoff_capture(struct vpu_instance *inst, struct vb2_queue *q) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + vb2_set_plane_payload(&buf->vb2_buf, 0, 0); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + v4l2_m2m_clear_state(m2m_ctx); +} + +static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + bool check_cmd = true; + + /* + * Note that we don't need m2m_ctx->next_buf_last for this driver, so we + * don't call v4l2_m2m_update_stop_streaming_state(). + */ + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + + if (wave5_vpu_both_queues_are_streaming(inst)) + switch_state(inst, VPU_INST_STATE_STOP); + + while (check_cmd) { + struct queue_status_info q_status; + struct enc_output_info enc_output_info; + + wave5_vpu_enc_give_command(inst, ENC_GET_QUEUE_STATUS, &q_status); + + if (q_status.report_queue_count == 0) + break; + + if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) + break; + + if (wave5_vpu_enc_get_output_info(inst, &enc_output_info)) + dev_dbg(inst->dev->dev, "Getting encoding results from fw, fail\n"); + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + streamoff_output(inst, q); + else + streamoff_capture(inst, q); +} + +static const struct vb2_ops wave5_vpu_enc_vb2_ops = { + .queue_setup = wave5_vpu_enc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave5_vpu_enc_buf_queue, + .start_streaming = wave5_vpu_enc_start_streaming, + .stop_streaming = wave5_vpu_enc_stop_streaming, +}; + +static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt); + + src_fmt->pixelformat = src_pix_fmt; + src_fmt->field = V4L2_FIELD_NONE; + src_fmt->flags = 0; + src_fmt->num_planes = src_fmt_info->mem_planes; + wave5_update_pix_fmt(src_fmt, 416, 240); + + dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; + dst_fmt->field = V4L2_FIELD_NONE; + dst_fmt->flags = 0; + dst_fmt->num_planes = 1; + wave5_update_pix_fmt(dst_fmt, 416, 240); +} + +static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_enc_vb2_ops); +} + +static const struct vpu_instance_ops wave5_vpu_enc_inst_ops = { + .finish_process = wave5_vpu_enc_finish_encode, +}; + +static void wave5_vpu_enc_device_run(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + u32 fail_res = 0; + int ret = 0; + + switch (inst->state) { + case VPU_INST_STATE_PIC_RUN: + ret = start_encode(inst, &fail_res); + if (ret) { + if (ret == -EINVAL) + dev_err(inst->dev->dev, + "Frame encoding on m2m context (%p), fail: %d (res: %d)\n", + m2m_ctx, ret, fail_res); + else if (ret == -EAGAIN) + dev_dbg(inst->dev->dev, "Missing buffers for encode, try again\n"); + break; + } + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + return; + default: + WARN(1, "Execution of a job in state %s is invalid.\n", + state_to_str(inst->state)); + break; + } + dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); +} + +static int wave5_vpu_enc_job_ready(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + switch (inst->state) { + case VPU_INST_STATE_NONE: + dev_dbg(inst->dev->dev, "Encoder must be open to start queueing M2M jobs!\n"); + return false; + case VPU_INST_STATE_PIC_RUN: + if (m2m_ctx->is_draining || v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, "Encoder ready for a job, state: %s\n", + state_to_str(inst->state)); + return true; + } + fallthrough; + default: + dev_dbg(inst->dev->dev, + "Encoder not ready for a job, state: %s, %s draining, %d src bufs ready\n", + state_to_str(inst->state), m2m_ctx->is_draining ? "is" : "is not", + v4l2_m2m_num_src_bufs_ready(m2m_ctx)); + break; + } + return false; +} + +static const struct v4l2_m2m_ops wave5_vpu_enc_m2m_ops = { + .device_run = wave5_vpu_enc_device_run, + .job_ready = wave5_vpu_enc_job_ready, +}; + +static int wave5_vpu_open_enc(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + struct v4l2_ctrl_handler *v4l2_ctrl_hdl; + int ret = 0; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_ENC; + inst->ops = &wave5_vpu_enc_inst_ops; + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) + return -ENOMEM; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + INIT_LIST_HEAD(&inst->list); + list_add_tail(&inst->list, &dev->instances); + + inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev; + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_enc_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto cleanup_inst; + } + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true); + + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, 0, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + 0, 63, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + 0, 63, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + 0, 63, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, 0, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + 1, 2, 1, 2); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + 0, 1, 1, 1); + + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE, 0, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + 0, 63, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + 0, 63, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + 0, 63, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + -12, 12, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_ROTATE, + 0, 270, 90, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, + 10, 3000, 1, 1000); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, 700000000, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 0, 2047, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + 0, 0xFFFF, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1); + + if (v4l2_ctrl_hdl->error) { + ret = -ENODEV; + goto cleanup_inst; + } + + inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); + + wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->colorspace = V4L2_COLORSPACE_REC709; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + inst->frame_rate = 30; + + init_completion(&inst->irq_done); + + inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL); + if (inst->id < 0) { + dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id); + ret = inst->id; + goto cleanup_inst; + } + + wave5_vdi_allocate_sram(inst->dev); + + return 0; + +cleanup_inst: + wave5_cleanup_instance(inst); + return ret; +} + +static int wave5_vpu_enc_release(struct file *filp) +{ + return wave5_vpu_release_device(filp, wave5_vpu_enc_close, "encoder"); +} + +static const struct v4l2_file_operations wave5_vpu_enc_fops = { + .owner = THIS_MODULE, + .open = wave5_vpu_open_enc, + .release = wave5_vpu_enc_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave5_vpu_enc_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_enc; + int ret; + + vdev_enc = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_enc), GFP_KERNEL); + if (!vdev_enc) + return -ENOMEM; + + dev->v4l2_m2m_enc_dev = v4l2_m2m_init(&wave5_vpu_enc_m2m_ops); + if (IS_ERR(dev->v4l2_m2m_enc_dev)) { + ret = PTR_ERR(dev->v4l2_m2m_enc_dev); + dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret); + return -EINVAL; + } + + dev->video_dev_enc = vdev_enc; + + strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name)); + vdev_enc->fops = &wave5_vpu_enc_fops; + vdev_enc->ioctl_ops = &wave5_vpu_enc_ioctl_ops; + vdev_enc->release = video_device_release_empty; + vdev_enc->v4l2_dev = &dev->v4l2_dev; + vdev_enc->vfl_dir = VFL_DIR_M2M; + vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_enc->lock = &dev->dev_lock; + + ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + video_set_drvdata(vdev_enc, dev); + + return 0; +} + +void wave5_vpu_enc_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_enc); + if (dev->v4l2_m2m_enc_dev) + v4l2_m2m_release(dev->v4l2_m2m_enc_dev); +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c new file mode 100644 index 000000000000..bfe4caa79cc9 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - platform driver + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ +#include +#include +#include +#include +#include +#include +#include "wave5-vpu.h" +#include "wave5-regdefine.h" +#include "wave5-vpuconfig.h" +#include "wave5.h" + +#define VPU_PLATFORM_DEVICE_NAME "vdec" +#define VPU_CLK_NAME "vcodec" + +#define WAVE5_IS_ENC BIT(0) +#define WAVE5_IS_DEC BIT(1) + +struct wave5_match_data { + int flags; + const char *fw_name; +}; + +int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout) +{ + int ret; + + ret = wait_for_completion_timeout(&inst->irq_done, + msecs_to_jiffies(timeout)); + if (!ret) + return -ETIMEDOUT; + + reinit_completion(&inst->irq_done); + + return 0; +} + +static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id) +{ + u32 seq_done; + u32 cmd_done; + u32 irq_reason; + struct vpu_instance *inst; + struct vpu_device *dev = dev_id; + + if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) { + irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON); + wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason); + wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1); + + list_for_each_entry(inst, &dev->instances, list) { + seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO); + cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST); + + if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || + irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { + if (seq_done & BIT(inst->id)) { + seq_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, + seq_done); + complete(&inst->irq_done); + } + } + + if (irq_reason & BIT(INT_WAVE5_DEC_PIC) || + irq_reason & BIT(INT_WAVE5_ENC_PIC)) { + if (cmd_done & BIT(inst->id)) { + cmd_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST, + cmd_done); + inst->ops->finish_process(inst); + } + } + + wave5_vpu_clear_interrupt(inst, irq_reason); + } + } + + return IRQ_HANDLED; +} + +static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name, + u32 *revision) +{ + const struct firmware *fw; + int ret; + unsigned int product_id; + + ret = request_firmware(&fw, fw_name, dev); + if (ret) { + dev_err(dev, "request_firmware, fail: %d\n", ret); + return ret; + } + + ret = wave5_vpu_init_with_bitcode(dev, (u8 *)fw->data, fw->size); + if (ret) { + dev_err(dev, "vpu_init_with_bitcode, fail: %d\n", ret); + release_firmware(fw); + return ret; + } + release_firmware(fw); + + ret = wave5_vpu_get_version_info(dev, revision, &product_id); + if (ret) { + dev_err(dev, "vpu_get_version_info fail: %d\n", ret); + return ret; + } + + dev_dbg(dev, "%s: enum product_id: %08x, fw revision: %u\n", + __func__, product_id, *revision); + + return 0; +} + +static int wave5_vpu_probe(struct platform_device *pdev) +{ + int ret; + struct vpu_device *dev; + const struct wave5_match_data *match_data; + u32 fw_revision; + + match_data = device_get_match_data(&pdev->dev); + if (!match_data) { + dev_err(&pdev->dev, "missing device match data\n"); + return -EINVAL; + } + + /* physical addresses limited to 32 bits */ + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "Failed to set DMA mask: %d\n", ret); + return ret; + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->vdb_register = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->vdb_register)) + return PTR_ERR(dev->vdb_register); + ida_init(&dev->inst_ida); + + mutex_init(&dev->dev_lock); + mutex_init(&dev->hw_lock); + dev_set_drvdata(&pdev->dev, dev); + dev->dev = &pdev->dev; + + ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); + + /* continue without clock, assume externally managed */ + if (ret < 0) { + dev_warn(&pdev->dev, "Getting clocks, fail: %d\n", ret); + ret = 0; + } + dev->num_clks = ret; + + ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks); + if (ret) { + dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "sram-size", + &dev->sram_size); + if (ret) { + dev_warn(&pdev->dev, "sram-size not found\n"); + dev->sram_size = 0; + } + + dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (!dev->sram_pool) + dev_warn(&pdev->dev, "sram node not found\n"); + + dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER); + ret = wave5_vdi_init(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "wave5_vdi_init, fail: %d\n", ret); + goto err_clk_dis; + } + dev->product = wave5_vpu_get_product_id(dev); + + INIT_LIST_HEAD(&dev->instances); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "v4l2_device_register, fail: %d\n", ret); + goto err_vdi_release; + } + + if (match_data->flags & WAVE5_IS_DEC) { + ret = wave5_vpu_dec_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_dec_register_device, fail: %d\n", ret); + goto err_v4l2_unregister; + } + } + if (match_data->flags & WAVE5_IS_ENC) { + ret = wave5_vpu_enc_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_enc_register_device, fail: %d\n", ret); + goto err_dec_unreg; + } + } + + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + ret = -ENXIO; + goto err_enc_unreg; + } + + ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL, + wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev); + if (ret) { + dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret); + goto err_enc_unreg; + } + + ret = wave5_vpu_load_firmware(&pdev->dev, match_data->fw_name, &fw_revision); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_load_firmware, fail: %d\n", ret); + goto err_enc_unreg; + } + + dev_info(&pdev->dev, "Added wave5 driver with caps: %s %s\n", + (match_data->flags & WAVE5_IS_ENC) ? "'ENCODE'" : "", + (match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : ""); + dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code); + dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision); + return 0; + +err_enc_unreg: + if (match_data->flags & WAVE5_IS_ENC) + wave5_vpu_enc_unregister_device(dev); +err_dec_unreg: + if (match_data->flags & WAVE5_IS_DEC) + wave5_vpu_dec_unregister_device(dev); +err_v4l2_unregister: + v4l2_device_unregister(&dev->v4l2_dev); +err_vdi_release: + wave5_vdi_release(&pdev->dev); +err_clk_dis: + clk_bulk_disable_unprepare(dev->num_clks, dev->clks); + + return ret; +} + +static int wave5_vpu_remove(struct platform_device *pdev) +{ + struct vpu_device *dev = dev_get_drvdata(&pdev->dev); + + mutex_destroy(&dev->dev_lock); + mutex_destroy(&dev->hw_lock); + clk_bulk_disable_unprepare(dev->num_clks, dev->clks); + wave5_vpu_enc_unregister_device(dev); + wave5_vpu_dec_unregister_device(dev); + v4l2_device_unregister(&dev->v4l2_dev); + wave5_vdi_release(&pdev->dev); + ida_destroy(&dev->inst_ida); + + return 0; +} + +static const struct wave5_match_data ti_wave521c_data = { + .flags = WAVE5_IS_ENC | WAVE5_IS_DEC, + .fw_name = "cnm/wave521c_k3_codec_fw.bin", +}; + +static const struct of_device_id wave5_dt_ids[] = { + { .compatible = "ti,k3-j721s2-wave521c", .data = &ti_wave521c_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wave5_dt_ids); + +static struct platform_driver wave5_vpu_driver = { + .driver = { + .name = VPU_PLATFORM_DEVICE_NAME, + .of_match_table = of_match_ptr(wave5_dt_ids), + }, + .probe = wave5_vpu_probe, + .remove = wave5_vpu_remove, +}; + +module_platform_driver(wave5_vpu_driver); +MODULE_DESCRIPTION("chips&media VPU V4L2 driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h new file mode 100644 index 000000000000..32b7fd3730b5 --- /dev/null +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - basic types + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ +#ifndef __VPU_DRV_H__ +#define __VPU_DRV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "wave5-vpuconfig.h" +#include "wave5-vpuapi.h" + +#define VPU_BUF_SYNC_TO_DEVICE 0 +#define VPU_BUF_SYNC_FROM_DEVICE 1 + +struct vpu_src_buffer { + struct v4l2_m2m_buffer v4l2_m2m_buf; + struct list_head list; + bool consumed; +}; + +struct vpu_dst_buffer { + struct v4l2_m2m_buffer v4l2_m2m_buf; + bool display; +}; + +enum vpu_fmt_type { + VPU_FMT_TYPE_CODEC = 0, + VPU_FMT_TYPE_RAW = 1 +}; + +struct vpu_format { + unsigned int v4l2_pix_fmt; + unsigned int max_width; + unsigned int min_width; + unsigned int max_height; + unsigned int min_height; +}; + +static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) +{ + return container_of(vfh, struct vpu_instance, v4l2_fh); +} + +static inline struct vpu_instance *wave5_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl) +{ + return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl); +} + +static inline struct vpu_src_buffer *wave5_to_vpu_src_buf(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct vpu_src_buffer, v4l2_m2m_buf.vb); +} + +static inline struct vpu_dst_buffer *wave5_to_vpu_dst_buf(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct vpu_dst_buffer, v4l2_m2m_buf.vb); +} + +int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout); + +int wave5_vpu_dec_register_device(struct vpu_device *dev); +void wave5_vpu_dec_unregister_device(struct vpu_device *dev); +int wave5_vpu_enc_register_device(struct vpu_device *dev); +void wave5_vpu_enc_unregister_device(struct vpu_device *dev); +static inline bool wave5_vpu_both_queues_are_streaming(struct vpu_instance *inst) +{ + struct vb2_queue *vq_cap = + v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + struct vb2_queue *vq_out = + v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out); +} + +#endif From de4b9f7e371a53842b646aafa0b72c7467108ab2 Mon Sep 17 00:00:00 2001 From: Robert Beckett Date: Wed, 8 Nov 2023 20:29:25 +0100 Subject: [PATCH 0727/7721] dt-bindings: media: wave5: add yaml devicetree bindings Add bindings for the wave5 chips&media codec driver Signed-off-by: Robert Beckett Signed-off-by: Dafna Hirschfeld Signed-off-by: Sebastian Fricke Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil --- .../bindings/media/cnm,wave521c.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/cnm,wave521c.yaml diff --git a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml new file mode 100644 index 000000000000..6d5569e77b7a --- /dev/null +++ b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cnm,wave521c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chips&Media Wave 5 Series multi-standard codec IP + +maintainers: + - Nas Chung + - Jackson Lee + +description: + The Chips&Media WAVE codec IP is a multi format video encoder/decoder + +properties: + compatible: + items: + - enum: + - ti,k3-j721s2-wave521c + - const: cnm,wave521c + + reg: + maxItems: 1 + + clocks: + items: + - description: VCODEC clock + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The VPU uses the SRAM to store some of the reference data instead of + storing it on DMA memory. It is mainly used for the purpose of reducing + bandwidth. + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + vpu: video-codec@12345678 { + compatible = "ti,k3-j721s2-wave521c", "cnm,wave521c"; + reg = <0x12345678 0x1000>; + clocks = <&clks 42>; + interrupts = <42>; + sram = <&sram>; + }; From 26dde1beb359bd7ac7b37f741ba64d11611d106a Mon Sep 17 00:00:00 2001 From: Robert Beckett Date: Wed, 8 Nov 2023 20:29:26 +0100 Subject: [PATCH 0728/7721] media: chips-media: wave5: Add wave5 driver to maintainers file Add the Chips&Media wave5 encoder/decoder driver to the maintainers file Signed-off-by: Robert Beckett Signed-off-by: Dafna Hirschfeld Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6ed7462367ce..c5029341b1d6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23444,6 +23444,14 @@ F: include/linux/watchdog.h F: include/trace/events/watchdog.h F: include/uapi/linux/watchdog.h +WAVE5 VPU CODEC DRIVER +M: Nas Chung +M: Jackson Lee +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/cnm,wave5.yaml +F: drivers/media/platform/chips-media/wave5/ + WHISKEYCOVE PMIC GPIO DRIVER M: Kuppuswamy Sathyanarayanan L: linux-gpio@vger.kernel.org From 57bdac8ee2998d6bba091326e16967b4e5f74ae8 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 15 Nov 2023 13:10:33 +0100 Subject: [PATCH 0729/7721] drm/i915/gt: add missing new-line to GT_TRACE Trace requires new-line at the end of message (in opposition to printk), otherwise trace dump becomes messy. Signed-off-by: Andrzej Hajda Acked-by: Janusz Krzysztofik Reviewed-by: Nirmoy Das Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231115-eols-v1-1-d47a2f52b807@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index f5899d503e23..471b7cdc10ba 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -167,7 +167,7 @@ static void gt_sanitize(struct intel_gt *gt, bool force) enum intel_engine_id id; intel_wakeref_t wakeref; - GT_TRACE(gt, "force:%s", str_yes_no(force)); + GT_TRACE(gt, "force:%s\n", str_yes_no(force)); /* Use a raw wakeref to avoid calling intel_display_power_get early */ wakeref = intel_runtime_pm_get(gt->uncore->rpm); From e899505533852bf1da133f2f4c9a9655ff77f7e5 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 15 Nov 2023 11:54:03 +0100 Subject: [PATCH 0730/7721] drm/i915: do not clean GT table on error path The only task of intel_gt_release_all is to zero gt table. Calling it on error path prevents intel_gt_driver_late_release_all (called from i915_driver_late_release) to cleanup GTs, causing leakage. After i915_driver_late_release GT array is not used anymore so it does not need cleaning at all. Sample leak report: BUG i915_request (...): Objects remaining in i915_request on __kmem_cache_shutdown() ... Object 0xffff888113420040 @offset=64 Allocated in __i915_request_create+0x75/0x610 [i915] age=18339 cpu=1 pid=1454 kmem_cache_alloc+0x25b/0x270 __i915_request_create+0x75/0x610 [i915] i915_request_create+0x109/0x290 [i915] __engines_record_defaults+0xca/0x440 [i915] intel_gt_init+0x275/0x430 [i915] i915_gem_init+0x135/0x2c0 [i915] i915_driver_probe+0x8d1/0xdc0 [i915] v2: removed whole intel_gt_release_all Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/8489 Fixes: bec68cc9ea42 ("drm/i915: Prepare for multiple GTs") Signed-off-by: Andrzej Hajda Reviewed-by: Tvrtko Ursulin Reviewed-by: Nirmoy Das Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231115-dont_clean_gt_on_error_path-v2-1-54250125470a@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 11 ----------- drivers/gpu/drm/i915/i915_driver.c | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index ea814ea5f700..a425db5ed3a2 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -982,8 +982,6 @@ int intel_gt_probe_all(struct drm_i915_private *i915) err: i915_probe_error(i915, "Failed to initialize %s! (%d)\n", gtdef->name, ret); - intel_gt_release_all(i915); - return ret; } @@ -1002,15 +1000,6 @@ int intel_gt_tiles_init(struct drm_i915_private *i915) return 0; } -void intel_gt_release_all(struct drm_i915_private *i915) -{ - struct intel_gt *gt; - unsigned int id; - - for_each_gt(gt, i915, id) - i915->gt[id] = NULL; -} - void intel_gt_info_print(const struct intel_gt_info *info, struct drm_printer *p) { diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 8a0e2c745e1f..802de2c6decb 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -782,7 +782,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ret = i915_driver_mmio_probe(i915); if (ret < 0) - goto out_tiles_cleanup; + goto out_runtime_pm_put; ret = i915_driver_hw_probe(i915); if (ret < 0) @@ -842,8 +842,6 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i915_ggtt_driver_late_release(i915); out_cleanup_mmio: i915_driver_mmio_release(i915); -out_tiles_cleanup: - intel_gt_release_all(i915); out_runtime_pm_put: enable_rpm_wakeref_asserts(&i915->runtime_pm); i915_driver_late_release(i915); From 043a2d5d71d87553985816065da41cff72f5f2df Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 13 Nov 2023 18:02:48 +0100 Subject: [PATCH 0731/7721] accel/ivpu: Rename cons->rx_msg_lock Now the cons->rx_msg_lock also protects 'abort' field so rename the lock. Signed-off-by: Stanislaw Gruszka Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231113170252.758137-2-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 27 +++++++++++++-------------- drivers/accel/ivpu/ivpu_ipc.h | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 88453762c9d5..31ae0e71a8a3 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -150,7 +150,7 @@ ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, cons->tx_vpu_addr = 0; cons->request_id = 0; cons->aborted = false; - spin_lock_init(&cons->rx_msg_lock); + spin_lock_init(&cons->rx_lock); INIT_LIST_HEAD(&cons->rx_msg_list); init_waitqueue_head(&cons->rx_msg_wq); @@ -168,7 +168,7 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c list_del(&cons->link); spin_unlock_irq(&ipc->cons_list_lock); - spin_lock_irq(&cons->rx_msg_lock); + spin_lock_irq(&cons->rx_lock); list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) { list_del(&rx_msg->link); if (!cons->aborted) @@ -176,7 +176,7 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); } - spin_unlock_irq(&cons->rx_msg_lock); + spin_unlock_irq(&cons->rx_lock); ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr); } @@ -212,9 +212,9 @@ static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) if (IS_KTHREAD()) ret |= (kthread_should_stop() || kthread_should_park()); - spin_lock_irq(&cons->rx_msg_lock); + spin_lock_irq(&cons->rx_lock); ret |= !list_empty(&cons->rx_msg_list) || cons->aborted; - spin_unlock_irq(&cons->rx_msg_lock); + spin_unlock_irq(&cons->rx_lock); return ret; } @@ -237,20 +237,19 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, if (wait_ret == 0) return -ETIMEDOUT; - spin_lock_irq(&cons->rx_msg_lock); + spin_lock_irq(&cons->rx_lock); rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link); if (!rx_msg) { - spin_unlock_irq(&cons->rx_msg_lock); + spin_unlock_irq(&cons->rx_lock); return -EAGAIN; } list_del(&rx_msg->link); if (cons->aborted) { - spin_unlock_irq(&cons->rx_msg_lock); + spin_unlock_irq(&cons->rx_lock); ret = -ECANCELED; goto out; } - - spin_unlock_irq(&cons->rx_msg_lock); + spin_unlock_irq(&cons->rx_lock); if (ipc_buf) memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf)); @@ -383,9 +382,9 @@ ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, rx_msg->ipc_hdr = ipc_hdr; rx_msg->jsm_msg = jsm_msg; - spin_lock_irqsave(&cons->rx_msg_lock, flags); + spin_lock_irqsave(&cons->rx_lock, flags); list_add_tail(&rx_msg->link, &cons->rx_msg_list); - spin_unlock_irqrestore(&cons->rx_msg_lock, flags); + spin_unlock_irqrestore(&cons->rx_lock, flags); wake_up(&cons->rx_msg_wq); } @@ -529,9 +528,9 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) spin_lock_irqsave(&ipc->cons_list_lock, flags); list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { - spin_lock(&cons->rx_msg_lock); + spin_lock(&cons->rx_lock); cons->aborted = true; - spin_unlock(&cons->rx_msg_lock); + spin_unlock(&cons->rx_lock); wake_up(&cons->rx_msg_wq); } spin_unlock_irqrestore(&ipc->cons_list_lock, flags); diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index a380787f7222..71b2e648dffd 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -49,7 +49,7 @@ struct ivpu_ipc_consumer { u32 request_id; bool aborted; - spinlock_t rx_msg_lock; /* Protects rx_msg_list and aborted */ + spinlock_t rx_lock; /* Protects rx_msg_list and aborted */ struct list_head rx_msg_list; wait_queue_head_t rx_msg_wq; }; From 12fbf8ac39b08f810b767e2e3dc32258907ce890 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 13 Nov 2023 18:02:49 +0100 Subject: [PATCH 0732/7721] accel/ivpu: Do not use irqsave in ivpu_ipc_dispatch ivpu_ipc_dispatch is always called with irqs disabled. Add lockdep assertion and remove unneeded _irqsave/_irqrestore. Signed-off-by: Stanislaw Gruszka Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231113170252.758137-3-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 31ae0e71a8a3..781c7e40505a 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -367,9 +367,9 @@ ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, { struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_rx_msg *rx_msg; - unsigned long flags; lockdep_assert_held(&ipc->cons_list_lock); + lockdep_assert_irqs_disabled(); rx_msg = kzalloc(sizeof(*rx_msg), GFP_ATOMIC); if (!rx_msg) { @@ -382,9 +382,9 @@ ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, rx_msg->ipc_hdr = ipc_hdr; rx_msg->jsm_msg = jsm_msg; - spin_lock_irqsave(&cons->rx_lock, flags); + spin_lock(&cons->rx_lock); list_add_tail(&rx_msg->link, &cons->rx_msg_list); - spin_unlock_irqrestore(&cons->rx_lock, flags); + spin_unlock(&cons->rx_lock); wake_up(&cons->rx_msg_wq); } From b3c10b71a61c3a0412b7c390831c88405be3d24f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 13 Nov 2023 18:02:50 +0100 Subject: [PATCH 0733/7721] accel/ivpu: Do not use cons->aborted for job_done_thread This allow to simplify ivpu_ipc_receive() as now we do not have to process all messages in aborted state - they will be freed in ivpu_ipc_consumer_del(). Signed-off-by: Stanislaw Gruszka Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231113170252.758137-4-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 18 +++++++++--------- drivers/accel/ivpu/ivpu_job.c | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 781c7e40505a..1dd4413dc88f 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -238,17 +238,16 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, return -ETIMEDOUT; spin_lock_irq(&cons->rx_lock); + if (cons->aborted) { + spin_unlock_irq(&cons->rx_lock); + return -ECANCELED; + } rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link); if (!rx_msg) { spin_unlock_irq(&cons->rx_lock); return -EAGAIN; } list_del(&rx_msg->link); - if (cons->aborted) { - spin_unlock_irq(&cons->rx_lock); - ret = -ECANCELED; - goto out; - } spin_unlock_irq(&cons->rx_lock); if (ipc_buf) @@ -266,7 +265,6 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, } ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); -out: atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); @@ -528,9 +526,11 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) spin_lock_irqsave(&ipc->cons_list_lock, flags); list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { - spin_lock(&cons->rx_lock); - cons->aborted = true; - spin_unlock(&cons->rx_lock); + if (cons->channel != VPU_IPC_CHAN_JOB_RET) { + spin_lock(&cons->rx_lock); + cons->aborted = true; + spin_unlock(&cons->rx_lock); + } wake_up(&cons->rx_msg_wq); } spin_unlock_irqrestore(&ipc->cons_list_lock, flags); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 02acd8dba02a..77b1b8abadd6 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -578,7 +578,6 @@ static int ivpu_job_done_thread(void *arg) ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET); while (!kthread_should_stop()) { - cons.aborted = false; timeout = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; jobs_submitted = !xa_empty(&vdev->submitted_jobs_xa); ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout); From 58cde80f45a2b1683ea3c24a9a9a4b0e1005336b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 13 Nov 2023 18:02:51 +0100 Subject: [PATCH 0734/7721] accel/ivpu: Use dedicated work for job timeout detection Change to use work for timeout detection. Needed for thread_irq conversion. Signed-off-by: Stanislaw Gruszka Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231113170252.758137-5-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_job.c | 24 +++++++++--------------- drivers/accel/ivpu/ivpu_pm.c | 31 +++++++++++++++++++++++++++++++ drivers/accel/ivpu/ivpu_pm.h | 3 +++ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 77b1b8abadd6..796366d67984 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -24,10 +24,6 @@ #define JOB_ID_CONTEXT_MASK GENMASK(31, 8) #define JOB_MAX_BUFFER_COUNT 65535 -static unsigned int ivpu_tdr_timeout_ms; -module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, uint, 0644); -MODULE_PARM_DESC(tdr_timeout_ms, "Timeout for device hang detection, in milliseconds, 0 - default"); - static void ivpu_cmdq_ring_db(struct ivpu_device *vdev, struct ivpu_cmdq *cmdq) { ivpu_hw_reg_db_set(vdev, cmdq->db_id); @@ -342,6 +338,8 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n", job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status); + ivpu_stop_job_timeout_detection(vdev); + job_put(job); return 0; } @@ -357,6 +355,9 @@ static void ivpu_job_done_message(struct ivpu_device *vdev, void *msg) ret = ivpu_job_done(vdev, payload->job_id, payload->job_status); if (ret) ivpu_err(vdev, "Failed to finish job %d: %d\n", payload->job_id, ret); + + if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) + ivpu_start_job_timeout_detection(vdev); } void ivpu_jobs_abort_all(struct ivpu_device *vdev) @@ -400,6 +401,8 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) if (ret) goto err_xa_erase; + ivpu_start_job_timeout_detection(vdev); + ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n", job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, job->engine_idx, cmdq->jobq->header.tail); @@ -569,7 +572,6 @@ static int ivpu_job_done_thread(void *arg) struct ivpu_device *vdev = (struct ivpu_device *)arg; struct ivpu_ipc_consumer cons; struct vpu_jsm_msg jsm_msg; - bool jobs_submitted; unsigned int timeout; int ret; @@ -578,18 +580,10 @@ static int ivpu_job_done_thread(void *arg) ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET); while (!kthread_should_stop()) { - timeout = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; - jobs_submitted = !xa_empty(&vdev->submitted_jobs_xa); ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout); - if (!ret) { + if (!ret) ivpu_job_done_message(vdev, &jsm_msg); - } else if (ret == -ETIMEDOUT) { - if (jobs_submitted && !xa_empty(&vdev->submitted_jobs_xa)) { - ivpu_err(vdev, "TDR detected, timeout %d ms", timeout); - ivpu_hw_diagnose_failure(vdev); - ivpu_pm_schedule_recovery(vdev); - } - } + if (kthread_should_park()) { ivpu_dbg(vdev, JOB, "Parked %s\n", __func__); kthread_parkme(); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index d915f3c2991f..0af8864cb3b5 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -23,6 +23,10 @@ static bool ivpu_disable_recovery; module_param_named_unsafe(disable_recovery, ivpu_disable_recovery, bool, 0644); MODULE_PARM_DESC(disable_recovery, "Disables recovery when VPU hang is detected"); +static unsigned long ivpu_tdr_timeout_ms; +module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, ulong, 0644); +MODULE_PARM_DESC(tdr_timeout_ms, "Timeout for device hang detection, in milliseconds, 0 - default"); + #define PM_RESCHEDULE_LIMIT 5 static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev) @@ -141,6 +145,31 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) } } +static void ivpu_job_timeout_work(struct work_struct *work) +{ + struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work); + struct ivpu_device *vdev = pm->vdev; + unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; + + ivpu_err(vdev, "TDR detected, timeout %lu ms", timeout_ms); + ivpu_hw_diagnose_failure(vdev); + + ivpu_pm_schedule_recovery(vdev); +} + +void ivpu_start_job_timeout_detection(struct ivpu_device *vdev) +{ + unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; + + /* No-op if already queued */ + queue_delayed_work(system_wq, &vdev->pm->job_timeout_work, msecs_to_jiffies(timeout_ms)); +} + +void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev) +{ + cancel_delayed_work_sync(&vdev->pm->job_timeout_work); +} + int ivpu_pm_suspend_cb(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); @@ -317,6 +346,7 @@ void ivpu_pm_init(struct ivpu_device *vdev) atomic_set(&pm->in_reset, 0); INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work); + INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work); if (ivpu_disable_recovery) delay = -1; @@ -331,6 +361,7 @@ void ivpu_pm_init(struct ivpu_device *vdev) void ivpu_pm_cancel_recovery(struct ivpu_device *vdev) { + drm_WARN_ON(&vdev->drm, delayed_work_pending(&vdev->pm->job_timeout_work)); cancel_work_sync(&vdev->pm->recovery_work); } diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index 044db150be07..97c6e0b0aa42 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -12,6 +12,7 @@ struct ivpu_device; struct ivpu_pm_info { struct ivpu_device *vdev; + struct delayed_work job_timeout_work; struct work_struct recovery_work; atomic_t in_reset; atomic_t reset_counter; @@ -37,5 +38,7 @@ int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev); void ivpu_rpm_put(struct ivpu_device *vdev); void ivpu_pm_schedule_recovery(struct ivpu_device *vdev); +void ivpu_start_job_timeout_detection(struct ivpu_device *vdev); +void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev); #endif /* __IVPU_PM_H__ */ From 3b434a3445fff3149128db0169da864d67057325 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Mon, 13 Nov 2023 18:02:52 +0100 Subject: [PATCH 0735/7721] accel/ivpu: Use threaded IRQ to handle JOB done messages Remove job_done thread and replace it with generic callback based mechanism. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Link: https://patchwork.freedesktop.org/patch/msgid/20231113170252.758137-6-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 30 +++-- drivers/accel/ivpu/ivpu_drv.h | 3 +- drivers/accel/ivpu/ivpu_hw_37xx.c | 29 +++-- drivers/accel/ivpu/ivpu_hw_40xx.c | 30 ++--- drivers/accel/ivpu/ivpu_ipc.c | 196 +++++++++++++++++------------- drivers/accel/ivpu/ivpu_ipc.h | 22 +++- drivers/accel/ivpu/ivpu_job.c | 84 +++---------- drivers/accel/ivpu/ivpu_job.h | 6 +- 8 files changed, 199 insertions(+), 201 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index bc15b06e1744..64927682161b 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -318,13 +318,11 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST) return 0; - ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG); + ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG, NULL); timeout = jiffies + msecs_to_jiffies(vdev->timeout.boot); while (1) { - ret = ivpu_ipc_irq_handler(vdev); - if (ret) - break; + ivpu_ipc_irq_handler(vdev, NULL); ret = ivpu_ipc_receive(vdev, &cons, &ipc_hdr, NULL, 0); if (ret != -ETIMEDOUT || time_after_eq(jiffies, timeout)) break; @@ -378,7 +376,6 @@ int ivpu_boot(struct ivpu_device *vdev) enable_irq(vdev->irq); ivpu_hw_irq_enable(vdev); ivpu_ipc_enable(vdev); - ivpu_job_done_thread_enable(vdev); return 0; } @@ -388,7 +385,6 @@ void ivpu_prepare_for_reset(struct ivpu_device *vdev) disable_irq(vdev->irq); ivpu_ipc_disable(vdev); ivpu_mmu_disable(vdev); - ivpu_job_done_thread_disable(vdev); } int ivpu_shutdown(struct ivpu_device *vdev) @@ -429,6 +425,13 @@ static const struct drm_driver driver = { .minor = DRM_IVPU_DRIVER_MINOR, }; +static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg) +{ + struct ivpu_device *vdev = arg; + + return ivpu_ipc_irq_thread_handler(vdev); +} + static int ivpu_irq_init(struct ivpu_device *vdev) { struct pci_dev *pdev = to_pci_dev(vdev->drm.dev); @@ -442,8 +445,8 @@ static int ivpu_irq_init(struct ivpu_device *vdev) vdev->irq = pci_irq_vector(pdev, 0); - ret = devm_request_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler, - IRQF_NO_AUTOEN, DRIVER_NAME, vdev); + ret = devm_request_threaded_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler, + ivpu_irq_thread_handler, IRQF_NO_AUTOEN, DRIVER_NAME, vdev); if (ret) ivpu_err(vdev, "Failed to request an IRQ %d\n", ret); @@ -581,20 +584,15 @@ static int ivpu_dev_init(struct ivpu_device *vdev) ivpu_pm_init(vdev); - ret = ivpu_job_done_thread_init(vdev); + ret = ivpu_boot(vdev); if (ret) goto err_ipc_fini; - ret = ivpu_boot(vdev); - if (ret) - goto err_job_done_thread_fini; - + ivpu_job_done_consumer_init(vdev); ivpu_pm_enable(vdev); return 0; -err_job_done_thread_fini: - ivpu_job_done_thread_fini(vdev); err_ipc_fini: ivpu_ipc_fini(vdev); err_fw_fini: @@ -619,7 +617,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) ivpu_shutdown(vdev); if (IVPU_WA(d3hot_after_power_off)) pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); - ivpu_job_done_thread_fini(vdev); + ivpu_job_done_consumer_fini(vdev); ivpu_pm_cancel_recovery(vdev); ivpu_ipc_fini(vdev); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index f1e7072449f1..ebc4b84f27b2 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -17,6 +17,7 @@ #include #include "ivpu_mmu_context.h" +#include "ivpu_ipc.h" #define DRIVER_NAME "intel_vpu" #define DRIVER_DESC "Driver for Intel NPU (Neural Processing Unit)" @@ -120,7 +121,7 @@ struct ivpu_device { struct list_head bo_list; struct xarray submitted_jobs_xa; - struct task_struct *job_done_thread; + struct ivpu_ipc_consumer job_done_consumer; atomic64_t unique_id_counter; diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index a172cfb1c31f..4ab1f14cf360 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -891,17 +891,20 @@ static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev) } /* Handler for IRQs from VPU core (irqV) */ -static u32 ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq, bool *wake_thread) { u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK; + if (!status) + return false; + REGV_WR32(VPU_37XX_HOST_SS_ICB_CLEAR_0, status); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status)) ivpu_mmu_irq_evtq_handler(vdev); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status)) - ivpu_ipc_irq_handler(vdev); + ivpu_ipc_irq_handler(vdev, wake_thread); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status)) ivpu_dbg(vdev, IRQ, "MMU sync complete\n"); @@ -918,17 +921,17 @@ static u32 ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status)) ivpu_hw_37xx_irq_noc_firewall_handler(vdev); - return status; + return true; } /* Handler for IRQs from Buttress core (irqB) */ -static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) { u32 status = REGB_RD32(VPU_37XX_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK; bool schedule_recovery = false; - if (status == 0) - return 0; + if (!status) + return false; if (REG_TEST_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", @@ -964,23 +967,27 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) if (schedule_recovery) ivpu_pm_schedule_recovery(vdev); - return status; + return true; } static irqreturn_t ivpu_hw_37xx_irq_handler(int irq, void *ptr) { struct ivpu_device *vdev = ptr; - u32 ret_irqv, ret_irqb; + bool irqv_handled, irqb_handled, wake_thread = false; REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - ret_irqv = ivpu_hw_37xx_irqv_handler(vdev, irq); - ret_irqb = ivpu_hw_37xx_irqb_handler(vdev, irq); + irqv_handled = ivpu_hw_37xx_irqv_handler(vdev, irq, &wake_thread); + irqb_handled = ivpu_hw_37xx_irqb_handler(vdev, irq); /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - return IRQ_RETVAL(ret_irqb | ret_irqv); + if (wake_thread) + return IRQ_WAKE_THREAD; + if (irqv_handled || irqb_handled) + return IRQ_HANDLED; + return IRQ_NONE; } static void ivpu_hw_37xx_diagnose_failure(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index f7e1f5c0667b..eba2fdef2ace 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -1047,13 +1047,12 @@ static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev) } /* Handler for IRQs from VPU core (irqV) */ -static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq, bool *wake_thread) { u32 status = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK; - irqreturn_t ret = IRQ_NONE; if (!status) - return IRQ_NONE; + return false; REGV_WR32(VPU_40XX_HOST_SS_ICB_CLEAR_0, status); @@ -1061,7 +1060,7 @@ static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) ivpu_mmu_irq_evtq_handler(vdev); if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status)) - ret |= ivpu_ipc_irq_handler(vdev); + ivpu_ipc_irq_handler(vdev, wake_thread); if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status)) ivpu_dbg(vdev, IRQ, "MMU sync complete\n"); @@ -1078,17 +1077,17 @@ static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status)) ivpu_hw_40xx_irq_noc_firewall_handler(vdev); - return ret; + return true; } /* Handler for IRQs from Buttress core (irqB) */ -static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) { bool schedule_recovery = false; u32 status = REGB_RD32(VPU_40XX_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK; - if (status == 0) - return IRQ_NONE; + if (!status) + return false; if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE"); @@ -1140,26 +1139,27 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) if (schedule_recovery) ivpu_pm_schedule_recovery(vdev); - return IRQ_HANDLED; + return true; } static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr) { + bool irqv_handled, irqb_handled, wake_thread = false; struct ivpu_device *vdev = ptr; - irqreturn_t ret = IRQ_NONE; REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - ret |= ivpu_hw_40xx_irqv_handler(vdev, irq); - ret |= ivpu_hw_40xx_irqb_handler(vdev, irq); + irqv_handled = ivpu_hw_40xx_irqv_handler(vdev, irq, &wake_thread); + irqb_handled = ivpu_hw_40xx_irqb_handler(vdev, irq); /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - if (ret & IRQ_WAKE_THREAD) + if (wake_thread) return IRQ_WAKE_THREAD; - - return ret; + if (irqv_handled || irqb_handled) + return IRQ_HANDLED; + return IRQ_NONE; } static void ivpu_hw_40xx_diagnose_failure(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 1dd4413dc88f..e86621f16f85 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -18,19 +17,12 @@ #include "ivpu_pm.h" #define IPC_MAX_RX_MSG 128 -#define IS_KTHREAD() (get_current()->flags & PF_KTHREAD) struct ivpu_ipc_tx_buf { struct ivpu_ipc_hdr ipc; struct vpu_jsm_msg jsm; }; -struct ivpu_ipc_rx_msg { - struct list_head link; - struct ivpu_ipc_hdr *ipc_hdr; - struct vpu_jsm_msg *jsm_msg; -}; - static void ivpu_ipc_msg_dump(struct ivpu_device *vdev, char *c, struct ivpu_ipc_hdr *ipc_hdr, u32 vpu_addr) { @@ -140,8 +132,49 @@ static void ivpu_ipc_tx(struct ivpu_device *vdev, u32 vpu_addr) ivpu_hw_reg_ipc_tx_set(vdev, vpu_addr); } -void -ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, u32 channel) +static void +ivpu_ipc_rx_msg_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, + struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg) +{ + struct ivpu_ipc_info *ipc = vdev->ipc; + struct ivpu_ipc_rx_msg *rx_msg; + + lockdep_assert_held(&ipc->cons_lock); + lockdep_assert_irqs_disabled(); + + rx_msg = kzalloc(sizeof(*rx_msg), GFP_ATOMIC); + if (!rx_msg) { + ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg); + return; + } + + atomic_inc(&ipc->rx_msg_count); + + rx_msg->ipc_hdr = ipc_hdr; + rx_msg->jsm_msg = jsm_msg; + rx_msg->callback = cons->rx_callback; + + if (rx_msg->callback) { + list_add_tail(&rx_msg->link, &ipc->cb_msg_list); + } else { + spin_lock(&cons->rx_lock); + list_add_tail(&rx_msg->link, &cons->rx_msg_list); + spin_unlock(&cons->rx_lock); + wake_up(&cons->rx_msg_wq); + } +} + +static void +ivpu_ipc_rx_msg_del(struct ivpu_device *vdev, struct ivpu_ipc_rx_msg *rx_msg) +{ + list_del(&rx_msg->link); + ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + atomic_dec(&vdev->ipc->rx_msg_count); + kfree(rx_msg); +} + +void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, + u32 channel, ivpu_ipc_rx_callback_t rx_callback) { struct ivpu_ipc_info *ipc = vdev->ipc; @@ -150,13 +183,14 @@ ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, cons->tx_vpu_addr = 0; cons->request_id = 0; cons->aborted = false; + cons->rx_callback = rx_callback; spin_lock_init(&cons->rx_lock); INIT_LIST_HEAD(&cons->rx_msg_list); init_waitqueue_head(&cons->rx_msg_wq); - spin_lock_irq(&ipc->cons_list_lock); + spin_lock_irq(&ipc->cons_lock); list_add_tail(&cons->link, &ipc->cons_list); - spin_unlock_irq(&ipc->cons_list_lock); + spin_unlock_irq(&ipc->cons_lock); } void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons) @@ -164,18 +198,13 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_rx_msg *rx_msg, *r; - spin_lock_irq(&ipc->cons_list_lock); + spin_lock_irq(&ipc->cons_lock); list_del(&cons->link); - spin_unlock_irq(&ipc->cons_list_lock); + spin_unlock_irq(&ipc->cons_lock); spin_lock_irq(&cons->rx_lock); - list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) { - list_del(&rx_msg->link); - if (!cons->aborted) - ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); - atomic_dec(&ipc->rx_msg_count); - kfree(rx_msg); - } + list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) + ivpu_ipc_rx_msg_del(vdev, rx_msg); spin_unlock_irq(&cons->rx_lock); ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr); @@ -205,15 +234,12 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct v return ret; } -static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) +static bool ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) { - int ret = 0; - - if (IS_KTHREAD()) - ret |= (kthread_should_stop() || kthread_should_park()); + bool ret; spin_lock_irq(&cons->rx_lock); - ret |= !list_empty(&cons->rx_msg_list) || cons->aborted; + ret = !list_empty(&cons->rx_msg_list) || cons->aborted; spin_unlock_irq(&cons->rx_lock); return ret; @@ -221,19 +247,18 @@ static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, - struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms) + struct vpu_jsm_msg *jsm_msg, unsigned long timeout_ms) { - struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_rx_msg *rx_msg; int wait_ret, ret = 0; + if (drm_WARN_ONCE(&vdev->drm, cons->rx_callback, "Consumer works only in async mode\n")) + return -EINVAL; + wait_ret = wait_event_timeout(cons->rx_msg_wq, ivpu_ipc_rx_need_wakeup(cons), msecs_to_jiffies(timeout_ms)); - if (IS_KTHREAD() && kthread_should_stop()) - return -EINTR; - if (wait_ret == 0) return -ETIMEDOUT; @@ -247,27 +272,23 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, spin_unlock_irq(&cons->rx_lock); return -EAGAIN; } - list_del(&rx_msg->link); - spin_unlock_irq(&cons->rx_lock); if (ipc_buf) memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf)); if (rx_msg->jsm_msg) { - u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*ipc_payload)); + u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg)); if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { ivpu_dbg(vdev, IPC, "IPC resp result error: %d\n", rx_msg->jsm_msg->result); ret = -EBADMSG; } - if (ipc_payload) - memcpy(ipc_payload, rx_msg->jsm_msg, size); + if (jsm_msg) + memcpy(jsm_msg, rx_msg->jsm_msg, size); } - ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); - atomic_dec(&ipc->rx_msg_count); - kfree(rx_msg); - + ivpu_ipc_rx_msg_del(vdev, rx_msg); + spin_unlock_irq(&cons->rx_lock); return ret; } @@ -280,7 +301,7 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req struct ivpu_ipc_consumer cons; int ret; - ivpu_ipc_consumer_add(vdev, &cons, channel); + ivpu_ipc_consumer_add(vdev, &cons, channel, NULL); ret = ivpu_ipc_send(vdev, &cons, req); if (ret) { @@ -359,35 +380,7 @@ ivpu_ipc_match_consumer(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons return false; } -static void -ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, - struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg) -{ - struct ivpu_ipc_info *ipc = vdev->ipc; - struct ivpu_ipc_rx_msg *rx_msg; - - lockdep_assert_held(&ipc->cons_list_lock); - lockdep_assert_irqs_disabled(); - - rx_msg = kzalloc(sizeof(*rx_msg), GFP_ATOMIC); - if (!rx_msg) { - ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg); - return; - } - - atomic_inc(&ipc->rx_msg_count); - - rx_msg->ipc_hdr = ipc_hdr; - rx_msg->jsm_msg = jsm_msg; - - spin_lock(&cons->rx_lock); - list_add_tail(&rx_msg->link, &cons->rx_msg_list); - spin_unlock(&cons->rx_lock); - - wake_up(&cons->rx_msg_wq); -} - -int ivpu_ipc_irq_handler(struct ivpu_device *vdev) +void ivpu_ipc_irq_handler(struct ivpu_device *vdev, bool *wake_thread) { struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_consumer *cons; @@ -405,7 +398,7 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) vpu_addr = ivpu_hw_reg_ipc_rx_addr_get(vdev); if (vpu_addr == REG_IO_ERROR) { ivpu_err_ratelimited(vdev, "Failed to read IPC rx addr register\n"); - return -EIO; + return; } ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr); @@ -435,15 +428,15 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) } dispatched = false; - spin_lock_irqsave(&ipc->cons_list_lock, flags); + spin_lock_irqsave(&ipc->cons_lock, flags); list_for_each_entry(cons, &ipc->cons_list, link) { if (ivpu_ipc_match_consumer(vdev, cons, ipc_hdr, jsm_msg)) { - ivpu_ipc_dispatch(vdev, cons, ipc_hdr, jsm_msg); + ivpu_ipc_rx_msg_add(vdev, cons, ipc_hdr, jsm_msg); dispatched = true; break; } } - spin_unlock_irqrestore(&ipc->cons_list_lock, flags); + spin_unlock_irqrestore(&ipc->cons_lock, flags); if (!dispatched) { ivpu_dbg(vdev, IPC, "IPC RX msg 0x%x dropped (no consumer)\n", vpu_addr); @@ -451,7 +444,28 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) } } - return 0; + if (wake_thread) + *wake_thread = !list_empty(&ipc->cb_msg_list); +} + +irqreturn_t ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev) +{ + struct ivpu_ipc_info *ipc = vdev->ipc; + struct ivpu_ipc_rx_msg *rx_msg, *r; + struct list_head cb_msg_list; + + INIT_LIST_HEAD(&cb_msg_list); + + spin_lock_irq(&ipc->cons_lock); + list_splice_tail_init(&ipc->cb_msg_list, &cb_msg_list); + spin_unlock_irq(&ipc->cons_lock); + + list_for_each_entry_safe(rx_msg, r, &cb_msg_list, link) { + rx_msg->callback(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + ivpu_ipc_rx_msg_del(vdev, rx_msg); + } + + return IRQ_HANDLED; } int ivpu_ipc_init(struct ivpu_device *vdev) @@ -486,10 +500,10 @@ int ivpu_ipc_init(struct ivpu_device *vdev) goto err_free_rx; } + spin_lock_init(&ipc->cons_lock); INIT_LIST_HEAD(&ipc->cons_list); - spin_lock_init(&ipc->cons_list_lock); + INIT_LIST_HEAD(&ipc->cb_msg_list); drmm_mutex_init(&vdev->drm, &ipc->lock); - ivpu_ipc_reset(vdev); return 0; @@ -502,6 +516,13 @@ int ivpu_ipc_init(struct ivpu_device *vdev) void ivpu_ipc_fini(struct ivpu_device *vdev) { + struct ivpu_ipc_info *ipc = vdev->ipc; + + drm_WARN_ON(&vdev->drm, ipc->on); + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cons_list)); + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cb_msg_list)); + drm_WARN_ON(&vdev->drm, atomic_read(&ipc->rx_msg_count) > 0); + ivpu_ipc_mem_fini(vdev); } @@ -518,22 +539,27 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) { struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_consumer *cons, *c; - unsigned long flags; + struct ivpu_ipc_rx_msg *rx_msg, *r; + + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cb_msg_list)); mutex_lock(&ipc->lock); ipc->on = false; mutex_unlock(&ipc->lock); - spin_lock_irqsave(&ipc->cons_list_lock, flags); + spin_lock_irq(&ipc->cons_lock); list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { - if (cons->channel != VPU_IPC_CHAN_JOB_RET) { - spin_lock(&cons->rx_lock); + spin_lock(&cons->rx_lock); + if (!cons->rx_callback) cons->aborted = true; - spin_unlock(&cons->rx_lock); - } + list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) + ivpu_ipc_rx_msg_del(vdev, rx_msg); + spin_unlock(&cons->rx_lock); wake_up(&cons->rx_msg_wq); } - spin_unlock_irqrestore(&ipc->cons_list_lock, flags); + spin_unlock_irq(&ipc->cons_lock); + + drm_WARN_ON(&vdev->drm, atomic_read(&ipc->rx_msg_count) > 0); } void ivpu_ipc_reset(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 71b2e648dffd..40ca3cc4e61f 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -42,12 +42,24 @@ struct ivpu_ipc_hdr { u8 status; } __packed __aligned(IVPU_IPC_ALIGNMENT); +typedef void (*ivpu_ipc_rx_callback_t)(struct ivpu_device *vdev, + struct ivpu_ipc_hdr *ipc_hdr, + struct vpu_jsm_msg *jsm_msg); + +struct ivpu_ipc_rx_msg { + struct list_head link; + struct ivpu_ipc_hdr *ipc_hdr; + struct vpu_jsm_msg *jsm_msg; + ivpu_ipc_rx_callback_t callback; +}; + struct ivpu_ipc_consumer { struct list_head link; u32 channel; u32 tx_vpu_addr; u32 request_id; bool aborted; + ivpu_ipc_rx_callback_t rx_callback; spinlock_t rx_lock; /* Protects rx_msg_list and aborted */ struct list_head rx_msg_list; @@ -61,8 +73,9 @@ struct ivpu_ipc_info { atomic_t rx_msg_count; - spinlock_t cons_list_lock; /* Protects cons_list */ + spinlock_t cons_lock; /* Protects cons_list and cb_msg_list */ struct list_head cons_list; + struct list_head cb_msg_list; atomic_t request_id; struct mutex lock; /* Lock on status */ @@ -76,14 +89,15 @@ void ivpu_ipc_enable(struct ivpu_device *vdev); void ivpu_ipc_disable(struct ivpu_device *vdev); void ivpu_ipc_reset(struct ivpu_device *vdev); -int ivpu_ipc_irq_handler(struct ivpu_device *vdev); +void ivpu_ipc_irq_handler(struct ivpu_device *vdev, bool *wake_thread); +irqreturn_t ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev); void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, - u32 channel); + u32 channel, ivpu_ipc_rx_callback_t callback); void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons); int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, - struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, + struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *jsm_msg, unsigned long timeout_ms); int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 796366d67984..7206cf9cdb4a 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -344,22 +343,6 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) return 0; } -static void ivpu_job_done_message(struct ivpu_device *vdev, void *msg) -{ - struct vpu_ipc_msg_payload_job_done *payload; - struct vpu_jsm_msg *job_ret_msg = msg; - int ret; - - payload = (struct vpu_ipc_msg_payload_job_done *)&job_ret_msg->payload; - - ret = ivpu_job_done(vdev, payload->job_id, payload->job_status); - if (ret) - ivpu_err(vdev, "Failed to finish job %d: %d\n", payload->job_id, ret); - - if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) - ivpu_start_job_timeout_detection(vdev); -} - void ivpu_jobs_abort_all(struct ivpu_device *vdev) { struct ivpu_job *job; @@ -567,65 +550,36 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) return ret; } -static int ivpu_job_done_thread(void *arg) +static void +ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, + struct vpu_jsm_msg *jsm_msg) { - struct ivpu_device *vdev = (struct ivpu_device *)arg; - struct ivpu_ipc_consumer cons; - struct vpu_jsm_msg jsm_msg; - unsigned int timeout; + struct vpu_ipc_msg_payload_job_done *payload; int ret; - ivpu_dbg(vdev, JOB, "Started %s\n", __func__); - - ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET); - - while (!kthread_should_stop()) { - ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout); - if (!ret) - ivpu_job_done_message(vdev, &jsm_msg); - - if (kthread_should_park()) { - ivpu_dbg(vdev, JOB, "Parked %s\n", __func__); - kthread_parkme(); - ivpu_dbg(vdev, JOB, "Unparked %s\n", __func__); - } + if (!jsm_msg) { + ivpu_err(vdev, "IPC message has no JSM payload\n"); + return; } - ivpu_ipc_consumer_del(vdev, &cons); - - ivpu_jobs_abort_all(vdev); - - ivpu_dbg(vdev, JOB, "Stopped %s\n", __func__); - return 0; -} - -int ivpu_job_done_thread_init(struct ivpu_device *vdev) -{ - struct task_struct *thread; - - thread = kthread_run(&ivpu_job_done_thread, (void *)vdev, "ivpu_job_done_thread"); - if (IS_ERR(thread)) { - ivpu_err(vdev, "Failed to start job completion thread\n"); - return -EIO; + if (jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { + ivpu_err(vdev, "Invalid JSM message result: %d\n", jsm_msg->result); + return; } - vdev->job_done_thread = thread; - - return 0; + payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload; + ret = ivpu_job_done(vdev, payload->job_id, payload->job_status); + if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) + ivpu_start_job_timeout_detection(vdev); } -void ivpu_job_done_thread_fini(struct ivpu_device *vdev) +void ivpu_job_done_consumer_init(struct ivpu_device *vdev) { - kthread_unpark(vdev->job_done_thread); - kthread_stop(vdev->job_done_thread); + ivpu_ipc_consumer_add(vdev, &vdev->job_done_consumer, + VPU_IPC_CHAN_JOB_RET, ivpu_job_done_callback); } -void ivpu_job_done_thread_disable(struct ivpu_device *vdev) +void ivpu_job_done_consumer_fini(struct ivpu_device *vdev) { - kthread_park(vdev->job_done_thread); -} - -void ivpu_job_done_thread_enable(struct ivpu_device *vdev) -{ - kthread_unpark(vdev->job_done_thread); + ivpu_ipc_consumer_del(vdev, &vdev->job_done_consumer); } diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index 4b604c90041e..45a2f2ec82e5 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -59,10 +59,8 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv); void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); -int ivpu_job_done_thread_init(struct ivpu_device *vdev); -void ivpu_job_done_thread_fini(struct ivpu_device *vdev); -void ivpu_job_done_thread_disable(struct ivpu_device *vdev); -void ivpu_job_done_thread_enable(struct ivpu_device *vdev); +void ivpu_job_done_consumer_init(struct ivpu_device *vdev); +void ivpu_job_done_consumer_fini(struct ivpu_device *vdev); void ivpu_jobs_abort_all(struct ivpu_device *vdev); From 7d21a2df45a6718b8ff402ab8a5e6c2936ac9799 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Oct 2023 16:13:31 -0500 Subject: [PATCH 0736/7721] media: ir-hix5hd2: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/ir-hix5hd2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 0034f615b466..de5bb9a08ea4 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -9,7 +9,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -251,7 +253,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct hix5hd2_ir_priv *priv; struct device_node *node = pdev->dev.of_node; - const struct of_device_id *of_id; const char *map_name; int ret; @@ -259,12 +260,11 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - of_id = of_match_device(hix5hd2_ir_table, dev); - if (!of_id) { + priv->socdata = device_get_match_data(dev); + if (!priv->socdata) { dev_err(dev, "Unable to initialize IR data\n"); return -ENODEV; } - priv->socdata = of_id->data; priv->regmap = syscon_regmap_lookup_by_phandle(node, "hisilicon,power-syscon"); From 12be815fbfd4c31aae4b23491b6dcf88a1e69299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 26 Oct 2023 12:18:18 +0200 Subject: [PATCH 0737/7721] media: meson-ir-tx: Convert to use devm_rc_register_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With that the remove callback can go away and also setting driver data becomes superfluous. Signed-off-by: Uwe Kleine-König Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/meson-ir-tx.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index 6355b79893fb..dab548dc6302 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -360,25 +360,16 @@ static int __init meson_irtx_probe(struct platform_device *pdev) rc->s_tx_carrier = meson_irtx_set_carrier; rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle; - ret = rc_register_device(rc); + ret = devm_rc_register_device(dev, rc); if (ret < 0) { dev_err(dev, "rc_dev registration failed\n"); rc_free_device(rc); return ret; } - platform_set_drvdata(pdev, rc); - return 0; } -static void meson_irtx_remove(struct platform_device *pdev) -{ - struct rc_dev *rc = platform_get_drvdata(pdev); - - rc_unregister_device(rc); -} - static const struct of_device_id meson_irtx_dt_match[] = { { .compatible = "amlogic,meson-g12a-ir-tx", @@ -388,7 +379,6 @@ static const struct of_device_id meson_irtx_dt_match[] = { MODULE_DEVICE_TABLE(of, meson_irtx_dt_match); static struct platform_driver meson_irtx_pd = { - .remove_new = meson_irtx_remove, .driver = { .name = DRIVER_NAME, .of_match_table = meson_irtx_dt_match, From 9af7c980f3ea3e85418beb25dc4d34939183e436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 26 Oct 2023 12:18:19 +0200 Subject: [PATCH 0738/7721] media: meson-ir-tx: Simplify and improve using dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With dev_err_probe() the error paths can be implemented in a more condensed way with the added benefit that the error code is added to the error messages by name. Signed-off-by: Uwe Kleine-König Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/meson-ir-tx.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index dab548dc6302..bd85361d561f 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -333,20 +333,17 @@ static int __init meson_irtx_probe(struct platform_device *pdev) spin_lock_init(&ir->lock); ret = meson_irtx_mod_clock_probe(ir, &clk_nr); - if (ret) { - dev_err(dev, "modulator clock setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "modulator clock setup failed\n"); + meson_irtx_setup(ir, clk_nr); ret = devm_request_irq(dev, irq, meson_irtx_irqhandler, IRQF_TRIGGER_RISING, DRIVER_NAME, ir); - if (ret) { - dev_err(dev, "irq request failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "irq request failed\n"); rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX); if (!rc) @@ -362,9 +359,8 @@ static int __init meson_irtx_probe(struct platform_device *pdev) ret = devm_rc_register_device(dev, rc); if (ret < 0) { - dev_err(dev, "rc_dev registration failed\n"); rc_free_device(rc); - return ret; + return dev_err_probe(dev, ret, "rc_dev registration failed\n"); } return 0; From 1865913dd590ca6d5e3207b15099a1210dd62f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 26 Oct 2023 12:18:20 +0200 Subject: [PATCH 0739/7721] media: meson-ir-tx: Drop usage of platform_driver_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The benefit of platform_driver_probe() here is only that the probe function can be discarded after the driver is loaded. For an ARCH=arm allmodconfig that's 952 bytes, for an allnoconfig + IR_MESON_TX=y it's only 452 bytes. The downside is that the driver isn't dynamically bindable and unbindable. There are considerations to drop platform_driver_probe() as a concept that isn't relevant any more today. It comes with an added complexity that makes many users hold it wrong. (E.g. this driver didn't benefit as much as it could as of v6.6-rc1 as meson_irtx_remove() could have been marked with __exit.) The advantages are not that relevant any more today, so convert this driver to an ordinary platform driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/meson-ir-tx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index bd85361d561f..fded2c256f2a 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -305,7 +305,7 @@ static int meson_irtx_mod_clock_probe(struct meson_irtx *ir, return 0; } -static int __init meson_irtx_probe(struct platform_device *pdev) +static int meson_irtx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct meson_irtx *ir; @@ -375,13 +375,13 @@ static const struct of_device_id meson_irtx_dt_match[] = { MODULE_DEVICE_TABLE(of, meson_irtx_dt_match); static struct platform_driver meson_irtx_pd = { + .probe = meson_irtx_probe, .driver = { .name = DRIVER_NAME, .of_match_table = meson_irtx_dt_match, }, }; - -module_platform_driver_probe(meson_irtx_pd, meson_irtx_probe); +module_platform_driver(meson_irtx_pd); MODULE_DESCRIPTION("Meson IR TX driver"); MODULE_AUTHOR("Viktor Prutyanov "); From e9cdebbe23f1aa9a1caea169862f479ab3fa2773 Mon Sep 17 00:00:00 2001 From: Jordan Rife Date: Mon, 6 Nov 2023 15:24:38 -0600 Subject: [PATCH 0740/7721] dlm: use kernel_connect() and kernel_bind() Recent changes to kernel_connect() and kernel_bind() ensure that callers are insulated from changes to the address parameter made by BPF SOCK_ADDR hooks. This patch wraps direct calls to ops->connect() and ops->bind() with kernel_connect() and kernel_bind() to protect callers in such cases. Link: https://lore.kernel.org/netdev/9944248dba1bce861375fcce9de663934d933ba9.camel@redhat.com/ Fixes: d74bad4e74ee ("bpf: Hooks for sys_connect") Fixes: 4fbac77d2d09 ("bpf: Hooks for sys_bind") Cc: stable@vger.kernel.org Signed-off-by: Jordan Rife Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 67f8dd8a05ef..6296c62c10fa 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1817,8 +1817,8 @@ static int dlm_tcp_bind(struct socket *sock) memcpy(&src_addr, &dlm_local_addr[0], sizeof(src_addr)); make_sockaddr(&src_addr, 0, &addr_len); - result = sock->ops->bind(sock, (struct sockaddr *)&src_addr, - addr_len); + result = kernel_bind(sock, (struct sockaddr *)&src_addr, + addr_len); if (result < 0) { /* This *may* not indicate a critical error */ log_print("could not bind for connect: %d", result); @@ -1830,7 +1830,7 @@ static int dlm_tcp_bind(struct socket *sock) static int dlm_tcp_connect(struct connection *con, struct socket *sock, struct sockaddr *addr, int addr_len) { - return sock->ops->connect(sock, addr, addr_len, O_NONBLOCK); + return kernel_connect(sock, addr, addr_len, O_NONBLOCK); } static int dlm_tcp_listen_validate(void) @@ -1862,8 +1862,8 @@ static int dlm_tcp_listen_bind(struct socket *sock) /* Bind to our port */ make_sockaddr(&dlm_local_addr[0], dlm_config.ci_tcp_port, &addr_len); - return sock->ops->bind(sock, (struct sockaddr *)&dlm_local_addr[0], - addr_len); + return kernel_bind(sock, (struct sockaddr *)&dlm_local_addr[0], + addr_len); } static const struct dlm_proto_ops dlm_tcp_ops = { @@ -1888,12 +1888,12 @@ static int dlm_sctp_connect(struct connection *con, struct socket *sock, int ret; /* - * Make sock->ops->connect() function return in specified time, + * Make kernel_connect() function return in specified time, * since O_NONBLOCK argument in connect() function does not work here, * then, we should restore the default value of this attribute. */ sock_set_sndtimeo(sock->sk, 5); - ret = sock->ops->connect(sock, addr, addr_len, 0); + ret = kernel_connect(sock, addr, addr_len, 0); sock_set_sndtimeo(sock->sk, 0); return ret; } From dbee1adeb7e6d31c9afbad8e9248c15694f1cc0c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 13 Nov 2023 16:24:09 -0500 Subject: [PATCH 0741/7721] dlm: use fl_owner from lockd This patch is changing the fl_owner value in case of an nfs lock request to not be the pid of lockd. Instead this patch changes it to be the owner value that nfs is giving us. Currently there exists proved problems with this behaviour. One nfsd server was created to export a gfs2 filesystem mount. Two nfs clients doing a nfs mount of this export. Those two clients should conflict each other operating on the same nfs file. A small test program was written: int main(int argc, const char *argv[]) { struct flock fl = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 1L, .l_len = 1L, }; int fd; fd = open("filename", O_RDWR | O_CREAT, 0700); printf("try to lock...\n"); fcntl(fd, F_SETLKW, &fl); printf("locked!\n"); getc(stdin); return 0; } Running on both clients at the same time and don't interrupting by pressing any key. It will show that both clients are able to acquire the lock which shouldn't be the case. The issue is here that the fl_owner value is the same and the lock context of both clients should be separated. This patch lets lockd define how to deal with lock contexts and chose hopefully the right fl_owner value. A test after this patch was made and the locks conflicts each other which should be the case. Acked-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/plock.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index e6b4c1a21446..ee6e0236d4f8 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -145,6 +145,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, op->info.number = number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; + op->info.owner = (__u64)(long)fl->fl_owner; /* async handling */ if (fl->fl_lmops && fl->fl_lmops->lm_grant) { op_data = kzalloc(sizeof(*op_data), GFP_NOFS); @@ -154,9 +155,6 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, goto out; } - /* fl_owner is lockd which doesn't distinguish - processes on the nfs client */ - op->info.owner = (__u64) fl->fl_pid; op_data->callback = fl->fl_lmops->lm_grant; locks_init_lock(&op_data->flc); locks_copy_lock(&op_data->flc, fl); @@ -168,8 +166,6 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, send_op(op); rv = FILE_LOCK_DEFERRED; goto out; - } else { - op->info.owner = (__u64)(long) fl->fl_owner; } send_op(op); @@ -326,10 +322,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file, op->info.number = number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; - if (fl->fl_lmops && fl->fl_lmops->lm_grant) - op->info.owner = (__u64) fl->fl_pid; - else - op->info.owner = (__u64)(long) fl->fl_owner; + op->info.owner = (__u64)(long)fl->fl_owner; if (fl->fl_flags & FL_CLOSE) { op->info.flags |= DLM_PLOCK_FL_CLOSE; @@ -389,7 +382,7 @@ int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file, info.number = number; info.start = fl->fl_start; info.end = fl->fl_end; - info.owner = (__u64)fl->fl_pid; + info.owner = (__u64)(long)fl->fl_owner; rv = do_lock_cancel(&info); switch (rv) { @@ -450,10 +443,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file, op->info.number = number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; - if (fl->fl_lmops && fl->fl_lmops->lm_grant) - op->info.owner = (__u64) fl->fl_pid; - else - op->info.owner = (__u64)(long) fl->fl_owner; + op->info.owner = (__u64)(long)fl->fl_owner; send_op(op); wait_event(recv_wq, (op->done != 0)); From 6bd4a2bfe568d963af721cc5efa52091bf1a3746 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 13 Nov 2023 16:24:10 -0500 Subject: [PATCH 0742/7721] dlm: use FL_SLEEP to determine blocking vs non-blocking This patch uses the FL_SLEEP flag in struct file_lock to determine if the lock request is a blocking or non-blocking request. Before dlm was using IS_SETLKW() was being used which is not usable for lock requests coming from lockd when EXPORT_OP_SAFE_ASYNC_LOCK inside the export flags is set. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/plock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index ee6e0236d4f8..d814c5121367 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -140,7 +140,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, op->info.optype = DLM_PLOCK_OP_LOCK; op->info.pid = fl->fl_pid; op->info.ex = (fl->fl_type == F_WRLCK); - op->info.wait = IS_SETLKW(cmd); + op->info.wait = !!(fl->fl_flags & FL_SLEEP); op->info.fsid = ls->ls_global_id; op->info.number = number; op->info.start = fl->fl_start; From 0c08699744d20ce0bac22b9f291a646a0302e51f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 13 Nov 2023 16:24:11 -0500 Subject: [PATCH 0743/7721] dlm: implement EXPORT_OP_ASYNC_LOCK This patch is activating the EXPORT_OP_ASYNC_LOCK export flag to signal lockd that both filesystems are able to handle async lock requests. The cluster filesystems gfs2 and ocfs2 will redirect their lock requests to DLMs plock implementation that can handle async lock requests. Reviewed-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/gfs2/export.c | 1 + fs/ocfs2/export.c | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index cf40895233f5..ef1013eff936 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -192,5 +192,6 @@ const struct export_operations gfs2_export_ops = { .fh_to_parent = gfs2_fh_to_parent, .get_name = gfs2_get_name, .get_parent = gfs2_get_parent, + .flags = EXPORT_OP_ASYNC_LOCK, }; diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index eaa8c80ace3c..b8b6a191b5cb 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -280,4 +280,5 @@ const struct export_operations ocfs2_export_ops = { .fh_to_dentry = ocfs2_fh_to_dentry, .fh_to_parent = ocfs2_fh_to_parent, .get_parent = ocfs2_get_parent, + .flags = EXPORT_OP_ASYNC_LOCK, }; From d1d53909bb5fbc9bf618ab78515fdbd5d6b691c6 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 9 Nov 2023 13:09:24 -0600 Subject: [PATCH 0744/7721] clk: samsung: Fix kernel-doc comments Fix some issues found in kernel-doc comments in Samsung CCF framework. It makes scripts/kernel-doc happy, which can be checked with: $ find drivers/clk/samsung/ -name '*.[ch]' -exec \ scripts/kernel-doc -v -none {} \; Signed-off-by: Sam Protsenko Fixes: ddeac8d968d4 ("clk: samsung: add infrastructure to register cpu clocks") Fixes: 721c42a351b1 ("clk: samsung: add common clock framework helper functions for Samsung platforms") Fixes: 3ff6e0d8d64d ("clk: samsung: Add support to register rate_table for samsung plls") Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Link: https://lore.kernel.org/r/20231109190925.2066-1-semen.protsenko@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-cpu.h | 2 +- drivers/clk/samsung/clk.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h index fc9f67a3b22e..103f64193e42 100644 --- a/drivers/clk/samsung/clk-cpu.h +++ b/drivers/clk/samsung/clk-cpu.h @@ -11,7 +11,7 @@ #include "clk.h" /** - * struct exynos_cpuclk_data: config data to setup cpu clocks. + * struct exynos_cpuclk_cfg_data: config data to setup cpu clocks. * @prate: frequency of the primary parent clock (in KHz). * @div0: value to be programmed in the div_cpu0 register. * @div1: value to be programmed in the div_cpu1 register. diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index ab9c3d7a25b3..4f17d5890a81 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -55,7 +55,7 @@ struct samsung_clock_alias { * @name: name of this fixed-rate clock. * @parent_name: optional parent clock name. * @flags: optional fixed-rate clock flags. - * @fixed-rate: fixed clock rate of this clock. + * @fixed_rate: fixed clock rate of this clock. */ struct samsung_fixed_rate_clock { unsigned int id; @@ -74,7 +74,7 @@ struct samsung_fixed_rate_clock { .fixed_rate = frate, \ } -/* +/** * struct samsung_fixed_factor_clock: information about fixed-factor clock * @id: platform specific id of the clock. * @name: name of this fixed-factor clock. @@ -146,14 +146,16 @@ struct samsung_mux_clock { __MUX(_id, cname, pnames, o, s, w, f, mf) /** - * @id: platform specific id of the clock. * struct samsung_div_clock: information about div clock + * @id: platform specific id of the clock. * @name: name of this div clock. * @parent_name: name of the parent clock. * @flags: optional flags for basic clock. * @offset: offset of the register for configuring the div. * @shift: starting bit location of the div control bit-field in @reg. + * @width: width of the bitfield. * @div_flags: flags for div-type clock. + * @table: array of divider/value pairs ending with a div set to 0. */ struct samsung_div_clock { unsigned int id; @@ -244,6 +246,7 @@ struct samsung_clk_reg_dump { * @con_offset: offset of the register for configuring the PLL. * @lock_offset: offset of the register for locking the PLL. * @type: Type of PLL to be registered. + * @rate_table: array of PLL settings for possible PLL rates. */ struct samsung_pll_clock { unsigned int id; From 5583e92be5c45448e6ea461e1780d46c17d14963 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 9 Nov 2023 13:09:25 -0600 Subject: [PATCH 0745/7721] clk: samsung: Improve kernel-doc comments Unify and improve the style of kernel-doc comments in Samsung CCF framework. Resemble more idiomatic style described in [1] and commonly used throughout most of the kernel code. [1] Documentation/doc-guide/kernel-doc.rst Signed-off-by: Sam Protsenko Acked-by: Randy Dunlap Tested-by: Randy Dunlap Link: https://lore.kernel.org/r/20231109190925.2066-2-semen.protsenko@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-cpu.h | 30 +++---- drivers/clk/samsung/clk.h | 158 ++++++++++++++++++---------------- 2 files changed, 100 insertions(+), 88 deletions(-) diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h index 103f64193e42..0164bd9ad021 100644 --- a/drivers/clk/samsung/clk-cpu.h +++ b/drivers/clk/samsung/clk-cpu.h @@ -11,10 +11,10 @@ #include "clk.h" /** - * struct exynos_cpuclk_cfg_data: config data to setup cpu clocks. - * @prate: frequency of the primary parent clock (in KHz). - * @div0: value to be programmed in the div_cpu0 register. - * @div1: value to be programmed in the div_cpu1 register. + * struct exynos_cpuclk_cfg_data - config data to setup cpu clocks + * @prate: frequency of the primary parent clock (in KHz) + * @div0: value to be programmed in the div_cpu0 register + * @div1: value to be programmed in the div_cpu1 register * * This structure holds the divider configuration data for dividers in the CPU * clock domain. The parent frequency at which these divider values are valid is @@ -29,17 +29,17 @@ struct exynos_cpuclk_cfg_data { }; /** - * struct exynos_cpuclk: information about clock supplied to a CPU core. - * @hw: handle between CCF and CPU clock. - * @alt_parent: alternate parent clock to use when switching the speed - * of the primary parent clock. - * @ctrl_base: base address of the clock controller. - * @lock: cpu clock domain register access lock. - * @cfg: cpu clock rate configuration data. - * @num_cfgs: number of array elements in @cfg array. - * @clk_nb: clock notifier registered for changes in clock speed of the - * primary parent clock. - * @flags: configuration flags for the CPU clock. + * struct exynos_cpuclk - information about clock supplied to a CPU core + * @hw: handle between CCF and CPU clock + * @alt_parent: alternate parent clock to use when switching the speed + * of the primary parent clock + * @ctrl_base: base address of the clock controller + * @lock: cpu clock domain register access lock + * @cfg: cpu clock rate configuration data + * @num_cfgs: number of array elements in @cfg array + * @clk_nb: clock notifier registered for changes in clock speed of the + * primary parent clock + * @flags: configuration flags for the CPU clock * * This structure holds information required for programming the CPU clock for * various clock speeds. diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 4f17d5890a81..516b716407e5 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -14,11 +14,11 @@ #include "clk-pll.h" /** - * struct samsung_clk_provider: information about clock provider - * @reg_base: virtual address for the register base. - * @dev: clock provider device needed for runtime PM. - * @lock: maintains exclusion between callbacks for a given clock-provider. - * @clk_data: holds clock related data like clk_hw* and number of clocks. + * struct samsung_clk_provider - information about clock provider + * @reg_base: virtual address for the register base + * @dev: clock provider device needed for runtime PM + * @lock: maintains exclusion between callbacks for a given clock-provider + * @clk_data: holds clock related data like clk_hw* and number of clocks */ struct samsung_clk_provider { void __iomem *reg_base; @@ -29,10 +29,10 @@ struct samsung_clk_provider { }; /** - * struct samsung_clock_alias: information about mux clock - * @id: platform specific id of the clock. - * @dev_name: name of the device to which this clock belongs. - * @alias: optional clock alias name to be assigned to this clock. + * struct samsung_clock_alias - information about mux clock + * @id: platform specific id of the clock + * @dev_name: name of the device to which this clock belongs + * @alias: optional clock alias name to be assigned to this clock */ struct samsung_clock_alias { unsigned int id; @@ -50,12 +50,12 @@ struct samsung_clock_alias { #define MHZ (1000 * 1000) /** - * struct samsung_fixed_rate_clock: information about fixed-rate clock - * @id: platform specific id of the clock. - * @name: name of this fixed-rate clock. - * @parent_name: optional parent clock name. - * @flags: optional fixed-rate clock flags. - * @fixed_rate: fixed clock rate of this clock. + * struct samsung_fixed_rate_clock - information about fixed-rate clock + * @id: platform specific id of the clock + * @name: name of this fixed-rate clock + * @parent_name: optional parent clock name + * @flags: optional fixed-rate clock flags + * @fixed_rate: fixed clock rate of this clock */ struct samsung_fixed_rate_clock { unsigned int id; @@ -75,13 +75,13 @@ struct samsung_fixed_rate_clock { } /** - * struct samsung_fixed_factor_clock: information about fixed-factor clock - * @id: platform specific id of the clock. - * @name: name of this fixed-factor clock. - * @parent_name: parent clock name. - * @mult: fixed multiplication factor. - * @div: fixed division factor. - * @flags: optional fixed-factor clock flags. + * struct samsung_fixed_factor_clock - information about fixed-factor clock + * @id: platform specific id of the clock + * @name: name of this fixed-factor clock + * @parent_name: parent clock name + * @mult: fixed multiplication factor + * @div: fixed division factor + * @flags: optional fixed-factor clock flags */ struct samsung_fixed_factor_clock { unsigned int id; @@ -103,16 +103,16 @@ struct samsung_fixed_factor_clock { } /** - * struct samsung_mux_clock: information about mux clock - * @id: platform specific id of the clock. - * @name: name of this mux clock. - * @parent_names: array of pointer to parent clock names. - * @num_parents: number of parents listed in @parent_names. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the mux. - * @shift: starting bit location of the mux control bit-field in @reg. - * @width: width of the mux control bit-field in @reg. - * @mux_flags: flags for mux-type clock. + * struct samsung_mux_clock - information about mux clock + * @id: platform specific id of the clock + * @name: name of this mux clock + * @parent_names: array of pointer to parent clock names + * @num_parents: number of parents listed in @parent_names + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the mux + * @shift: starting bit location of the mux control bit-field in @reg + * @width: width of the mux control bit-field in @reg + * @mux_flags: flags for mux-type clock */ struct samsung_mux_clock { unsigned int id; @@ -146,16 +146,16 @@ struct samsung_mux_clock { __MUX(_id, cname, pnames, o, s, w, f, mf) /** - * struct samsung_div_clock: information about div clock - * @id: platform specific id of the clock. - * @name: name of this div clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the div. - * @shift: starting bit location of the div control bit-field in @reg. - * @width: width of the bitfield. - * @div_flags: flags for div-type clock. - * @table: array of divider/value pairs ending with a div set to 0. + * struct samsung_div_clock - information about div clock + * @id: platform specific id of the clock + * @name: name of this div clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the div + * @shift: starting bit location of the div control bit-field in @reg + * @width: width of the bitfield + * @div_flags: flags for div-type clock + * @table: array of divider/value pairs ending with a div set to 0 */ struct samsung_div_clock { unsigned int id; @@ -192,14 +192,14 @@ struct samsung_div_clock { __DIV(_id, cname, pname, o, s, w, 0, 0, t) /** - * struct samsung_gate_clock: information about gate clock - * @id: platform specific id of the clock. - * @name: name of this gate clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the gate. - * @bit_idx: bit index of the gate control bit-field in @reg. - * @gate_flags: flags for gate-type clock. + * struct samsung_gate_clock - information about gate clock + * @id: platform specific id of the clock + * @name: name of this gate clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the gate + * @bit_idx: bit index of the gate control bit-field in @reg + * @gate_flags: flags for gate-type clock */ struct samsung_gate_clock { unsigned int id; @@ -228,9 +228,9 @@ struct samsung_gate_clock { #define PNAME(x) static const char * const x[] __initconst /** - * struct samsung_clk_reg_dump: register dump of clock controller registers. - * @offset: clock register offset from the controller base address. - * @value: the value to be register at offset. + * struct samsung_clk_reg_dump - register dump of clock controller registers + * @offset: clock register offset from the controller base address + * @value: the value to be register at offset */ struct samsung_clk_reg_dump { u32 offset; @@ -238,15 +238,15 @@ struct samsung_clk_reg_dump { }; /** - * struct samsung_pll_clock: information about pll clock - * @id: platform specific id of the clock. - * @name: name of this pll clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @con_offset: offset of the register for configuring the PLL. - * @lock_offset: offset of the register for locking the PLL. - * @type: Type of PLL to be registered. - * @rate_table: array of PLL settings for possible PLL rates. + * struct samsung_pll_clock - information about pll clock + * @id: platform specific id of the clock + * @name: name of this pll clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @con_offset: offset of the register for configuring the PLL + * @lock_offset: offset of the register for locking the PLL + * @type: type of PLL to be registered + * @rate_table: array of PLL settings for possible PLL rates */ struct samsung_pll_clock { unsigned int id; @@ -305,39 +305,51 @@ struct samsung_clock_reg_cache { unsigned int rsuspend_num; }; +/** + * struct samsung_cmu_info - all clocks information needed for CMU registration + * @pll_clks: list of PLL clocks + * @nr_pll_clks: count of clocks in @pll_clks + * @mux_clks: list of mux clocks + * @nr_mux_clks: count of clocks in @mux_clks + * @div_clks: list of div clocks + * @nr_div_clks: count of clocks in @div_clks + * @gate_clks: list of gate clocks + * @nr_gate_clks: count of clocks in @gate_clks + * @fixed_clks: list of fixed clocks + * @nr_fixed_clks: count clocks in @fixed_clks + * @fixed_factor_clks: list of fixed factor clocks + * @nr_fixed_factor_clks: count of clocks in @fixed_factor_clks + * @nr_clk_ids: total number of clocks with IDs assigned + * @cpu_clks: list of CPU clocks + * @nr_cpu_clks: count of clocks in @cpu_clks + * @clk_regs: list of clock registers + * @nr_clk_regs: count of clock registers in @clk_regs + * @suspend_regs: list of clock registers to set before suspend + * @nr_suspend_regs: count of clock registers in @suspend_regs + * @clk_name: name of the parent clock needed for CMU register access + */ struct samsung_cmu_info { - /* list of pll clocks and respective count */ const struct samsung_pll_clock *pll_clks; unsigned int nr_pll_clks; - /* list of mux clocks and respective count */ const struct samsung_mux_clock *mux_clks; unsigned int nr_mux_clks; - /* list of div clocks and respective count */ const struct samsung_div_clock *div_clks; unsigned int nr_div_clks; - /* list of gate clocks and respective count */ const struct samsung_gate_clock *gate_clks; unsigned int nr_gate_clks; - /* list of fixed clocks and respective count */ const struct samsung_fixed_rate_clock *fixed_clks; unsigned int nr_fixed_clks; - /* list of fixed factor clocks and respective count */ const struct samsung_fixed_factor_clock *fixed_factor_clks; unsigned int nr_fixed_factor_clks; - /* total number of clocks with IDs assigned*/ unsigned int nr_clk_ids; - /* list of cpu clocks and respective count */ const struct samsung_cpu_clock *cpu_clks; unsigned int nr_cpu_clks; - /* list and number of clocks registers */ const unsigned long *clk_regs; unsigned int nr_clk_regs; - /* list and number of clocks registers to set before suspend */ const struct samsung_clk_reg_dump *suspend_regs; unsigned int nr_suspend_regs; - /* name of the parent clock needed for CMU register access */ const char *clk_name; }; From 7d562ac331ddc4f798e6185a858bc98c22ee7d1b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 15 Nov 2023 21:33:58 +0000 Subject: [PATCH 0746/7721] ASoC: dt-bindings: renesas,rz-ssi: Document RZ/Five SoC The SSI block on the RZ/Five SoC is identical to one found on the RZ/G2UL SoC. "renesas,r9a07g043-ssi" compatible string will be used on the RZ/Five SoC so to make this clear and to keep this file consistent, update the comment to include RZ/Five SoC. No driver changes are required as generic compatible string "renesas,rz-ssi" will be used as a fallback on RZ/Five SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231115213358.33400-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml index 3b5ae45eee4a..8b9695f5decc 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml @@ -16,7 +16,7 @@ properties: compatible: items: - enum: - - renesas,r9a07g043-ssi # RZ/G2UL + - renesas,r9a07g043-ssi # RZ/G2UL and RZ/Five - renesas,r9a07g044-ssi # RZ/G2{L,LC} - renesas,r9a07g054-ssi # RZ/V2L - const: renesas,rz-ssi From 97c39c7a0965b3eba87baa2b7d51443a46e21b8f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 9 Nov 2023 19:44:44 +0100 Subject: [PATCH 0747/7721] arm64: dts: rockchip: add analog audio to RK3588 EVB1 Add support for the EVB1 analog audio to its devicetree. Only the headphone has been tested, since I don't have matching peripherals to test headset or speakers. I also didn't manage to record sound from the onboard microphone, but that also fails with the vendor kernel. Thus I assume the microphone on my board is fried. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20231109184453.108676-2-sebastian.reichel@collabora.com Signed-off-by: Heiko Stuebner --- .../boot/dts/rockchip/rk3588-evb1-v10.dts | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts index b9d789d57862..3369065f897d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts @@ -56,6 +56,63 @@ button-escape { }; }; + analog-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; + pinctrl-0 = <&hp_detect>; + simple-audio-card,name = "RK3588 EVB1 Audio"; + simple-audio-card,aux-devs = <&_headphone>, <&_speaker>; + simple-audio-card,bitclock-master = <&masterdai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&masterdai>; + simple-audio-card,hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,pin-switches = "Headphones", "Speaker"; + simple-audio-card,routing = + "Speaker Amplifier INL", "LOUT2", + "Speaker Amplifier INR", "ROUT2", + "Speaker", "Speaker Amplifier OUTL", + "Speaker", "Speaker Amplifier OUTR", + "Headphones Amplifier INL", "LOUT1", + "Headphones Amplifier INR", "ROUT1", + "Headphones", "Headphones Amplifier OUTL", + "Headphones", "Headphones Amplifier OUTR", + "LINPUT1", "Onboard Microphone", + "RINPUT1", "Onboard Microphone", + "LINPUT2", "Microphone Jack", + "RINPUT2", "Microphone Jack"; + simple-audio-card,widgets = + "Microphone", "Microphone Jack", + "Microphone", "Onboard Microphone", + "Headphone", "Headphones", + "Speaker", "Speaker"; + + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + + masterdai: simple-audio-card,codec { + sound-dai = <&es8388>; + system-clock-frequency = <12288000>; + }; + }; + + amp_headphone: headphone-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&headphone_amplifier_en>; + sound-name-prefix = "Headphones Amplifier"; + }; + + amp_speaker: speaker-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&speaker_amplifier_en>; + sound-name-prefix = "Speaker Amplifier"; + }; + backlight: backlight { compatible = "pwm-backlight"; power-supply = <&vcc12v_dcin>; @@ -240,6 +297,32 @@ hym8563: rtc@51 { }; }; +&i2c7 { + status = "okay"; + + es8388: audio-codec@11 { + compatible = "everest,es8388"; + reg = <0x11>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + AVDD-supply = <&avcc_1v8_codec_s0>; + DVDD-supply = <&avcc_1v8_codec_s0>; + HPVDD-supply = <&vcc_3v3_s0>; + PVDD-supply = <&vcc_3v3_s0>; + #sound-dai-cells = <0>; + }; +}; + +&i2s0_8ch { + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; +}; + &mdio0 { rgmii_phy: ethernet-phy@1 { /* RTL8211F */ @@ -273,6 +356,20 @@ &pcie3x4 { }; &pinctrl { + audio { + hp_detect: headphone-detect { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + headphone_amplifier_en: headphone-amplifier-en { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + speaker_amplifier_en: speaker-amplifier-en { + rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + rtl8111 { rtl8111_isolate: rtl8111-isolate { rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; From 48794cd57a67246acc53a3edfdececdbb5b98453 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Wed, 18 Oct 2023 11:18:46 -0500 Subject: [PATCH 0748/7721] clk: rockchip: rk3568: Add PLL rate for 115.2MHz Add support for a PLL rate of 115.2MHz so that the Powkiddy RK2023 panel can run at a requested 60hz (59.99, close enough). I have confirmed this rate fits with all the constraints listed in the TRM for the VPLL (as an integer PLL) in Part 1 "Chapter 2 Clock & Reset Unit (CRU)." Signed-off-by: Chris Morgan Link: https://lore.kernel.org/r/20231018161848.346947-4-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 16dabe2b9c47..43185668daf6 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -78,6 +78,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { RK3036_PLL_RATE(148500000, 1, 99, 4, 4, 1, 0), RK3036_PLL_RATE(135000000, 2, 45, 4, 1, 1, 0), RK3036_PLL_RATE(119000000, 3, 119, 4, 2, 1, 0), + RK3036_PLL_RATE(115200000, 1, 24, 5, 1, 1, 0), RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0), RK3036_PLL_RATE(101000000, 1, 101, 6, 4, 1, 0), RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0), From d3715a6471c8f0a90fb852c10a5a84948d6a1ff5 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 9 Nov 2023 15:54:36 -0800 Subject: [PATCH 0749/7721] drm/i915/huc: Stop printing about unsupported HuC on MTL On MTL, the HuC is only supported on the media GT, so our validation check on the module parameter detects an inconsistency on the root GT (the modparams asks to enable HuC, but the support is not there) and prints the following info message: [drm] GT0: Incompatible option enable_guc=3 - HuC is not supported! This can be confusing to the user and make them think that something is wrong when it isn't, so we need to silence it. Given that any platform that supports HuC also supports GuC, if a user tries to enable HuC on a platform that really doesn't support it they'll already see a message about GuC not being supported, so instead of just silencing the HuC message on newer platforms we can just get rid of it entirely. Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20231109235436.2349963-1-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index 27f6561dd731..3872d309ed31 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -106,11 +106,6 @@ static void __confirm_options(struct intel_uc *uc) gt_info(gt, "Incompatible option enable_guc=%d - %s\n", i915->params.enable_guc, "GuC is not supported!"); - if (i915->params.enable_guc & ENABLE_GUC_LOAD_HUC && - !intel_uc_supports_huc(uc)) - gt_info(gt, "Incompatible option enable_guc=%d - %s\n", - i915->params.enable_guc, "HuC is not supported!"); - if (i915->params.enable_guc & ENABLE_GUC_SUBMISSION && !intel_uc_supports_guc_submission(uc)) gt_info(gt, "Incompatible option enable_guc=%d - %s\n", From 5827fe2bc9c4bade6af994676c9823908e091877 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 14 Nov 2023 05:45:32 -0800 Subject: [PATCH 0750/7721] octeon_ep: add padding for small packets Pad small packets to ETH_ZLEN before transmit, as hardware cannot pad and requires software padding to ensure minimum ethernet frame length. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeon_ep/octep_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 552970c7dec0..2c86b911a380 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -820,6 +820,9 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, u16 nr_frags, si; u16 q_no, wi; + if (skb_put_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + q_no = skb_get_queue_mapping(skb); if (q_no >= oct->num_iqs) { netdev_err(netdev, "Invalid Tx skb->queue_mapping=%d\n", q_no); From 2fba5069959c50c0e5be95e8d67356c63909cbc2 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 14 Nov 2023 05:45:33 -0800 Subject: [PATCH 0751/7721] octeon_ep: remove dma sync in trasmit path Cleanup dma sync calls for scatter gather mappings, since they are coherent allocations and do not need explicit sync to be called. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeon_ep/octep_main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 2c86b911a380..1c02304677c9 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -872,9 +872,6 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, if (dma_mapping_error(iq->dev, dma)) goto dma_map_err; - dma_sync_single_for_cpu(iq->dev, tx_buffer->sglist_dma, - OCTEP_SGLIST_SIZE_PER_PKT, - DMA_TO_DEVICE); memset(sglist, 0, OCTEP_SGLIST_SIZE_PER_PKT); sglist[0].len[3] = len; sglist[0].dma_ptr[0] = dma; @@ -894,10 +891,6 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, frag++; si++; } - dma_sync_single_for_device(iq->dev, tx_buffer->sglist_dma, - OCTEP_SGLIST_SIZE_PER_PKT, - DMA_TO_DEVICE); - hw_desc->dptr = tx_buffer->sglist_dma; } From 373d9a55ba746c579ca98222d2b4308d06978ca5 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 14 Nov 2023 05:45:34 -0800 Subject: [PATCH 0752/7721] octeon_ep: implement xmit_more in transmit Add xmit_more handling in tx datapath for octeon_ep pf. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../ethernet/marvell/octeon_ep/octep_config.h | 2 +- .../ethernet/marvell/octeon_ep/octep_main.c | 36 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h index 1622a6ebf036..ed8b1ace56b9 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h @@ -15,7 +15,7 @@ /* Tx Queue: maximum descriptors per ring */ #define OCTEP_IQ_MAX_DESCRIPTORS 1024 /* Minimum input (Tx) requests to be enqueued to ring doorbell */ -#define OCTEP_DB_MIN 1 +#define OCTEP_DB_MIN 8 /* Packet threshold for Tx queue interrupt */ #define OCTEP_IQ_INTR_THRESHOLD 0x0 diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 1c02304677c9..2d1bcdc589f3 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -784,6 +784,13 @@ static inline int octep_iq_full_check(struct octep_iq *iq) /* Stop the queue if unable to send */ netif_stop_subqueue(iq->netdev, iq->q_no); + /* Allow for pending updates in write index + * from iq_process_completion in other cpus + * to reflect, in case queue gets free + * entries. + */ + smp_mb(); + /* check again and restart the queue, in case NAPI has just freed * enough Tx ring entries. */ @@ -818,6 +825,7 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, struct octep_iq *iq; skb_frag_t *frag; u16 nr_frags, si; + int xmit_more; u16 q_no, wi; if (skb_put_padto(skb, ETH_ZLEN)) @@ -830,10 +838,6 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, } iq = oct->iq[q_no]; - if (octep_iq_full_check(iq)) { - iq->stats.tx_busy++; - return NETDEV_TX_BUSY; - } shinfo = skb_shinfo(skb); nr_frags = shinfo->nr_frags; @@ -894,19 +898,33 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, hw_desc->dptr = tx_buffer->sglist_dma; } - netdev_tx_sent_queue(iq->netdev_q, skb->len); + xmit_more = netdev_xmit_more(); + + __netdev_tx_sent_queue(iq->netdev_q, skb->len, xmit_more); + skb_tx_timestamp(skb); atomic_inc(&iq->instr_pending); + iq->fill_cnt++; wi++; if (wi == iq->max_count) wi = 0; iq->host_write_index = wi; + + /* octep_iq_full_check stops the queue and returns + * true if so, in case the queue has become full + * by inserting current packet. If so, we can + * go ahead and ring doorbell. + */ + if (!octep_iq_full_check(iq) && xmit_more && + iq->fill_cnt < iq->fill_threshold) + return NETDEV_TX_OK; + /* Flush the hw descriptor before writing to doorbell */ wmb(); - - /* Ring Doorbell to notify the NIC there is a new packet */ - writel(1, iq->doorbell_reg); - iq->stats.instr_posted++; + /* Ring Doorbell to notify the NIC of new packets */ + writel(iq->fill_cnt, iq->doorbell_reg); + iq->stats.instr_posted += iq->fill_cnt; + iq->fill_cnt = 0; return NETDEV_TX_OK; dma_map_sg_err: From dc9c02b7faa0f37a1dd52752192a665319657d14 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 14 Nov 2023 05:45:35 -0800 Subject: [PATCH 0753/7721] octeon_ep: remove atomic variable usage in Tx data path Replace atomic variable "instr_pending" which represents number of posted tx instructions pending completion, with host_write_idx and flush_index variables in the xmit and completion processing respectively. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeon_ep/octep_config.h | 1 + drivers/net/ethernet/marvell/octeon_ep/octep_main.c | 9 +++------ drivers/net/ethernet/marvell/octeon_ep/octep_main.h | 9 +++++++++ drivers/net/ethernet/marvell/octeon_ep/octep_tx.c | 5 +---- drivers/net/ethernet/marvell/octeon_ep/octep_tx.h | 3 --- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h index ed8b1ace56b9..91cfa19c65b9 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h @@ -13,6 +13,7 @@ #define OCTEP_64BYTE_INSTR 64 /* Tx Queue: maximum descriptors per ring */ +/* This needs to be a power of 2 */ #define OCTEP_IQ_MAX_DESCRIPTORS 1024 /* Minimum input (Tx) requests to be enqueued to ring doorbell */ #define OCTEP_DB_MIN 8 diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 2d1bcdc589f3..974a34be9ffa 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -777,7 +777,7 @@ static int octep_stop(struct net_device *netdev) */ static inline int octep_iq_full_check(struct octep_iq *iq) { - if (likely((iq->max_count - atomic_read(&iq->instr_pending)) >= + if (likely((IQ_INSTR_SPACE(iq)) > OCTEP_WAKE_QUEUE_THRESHOLD)) return 0; @@ -794,7 +794,7 @@ static inline int octep_iq_full_check(struct octep_iq *iq) /* check again and restart the queue, in case NAPI has just freed * enough Tx ring entries. */ - if (unlikely((iq->max_count - atomic_read(&iq->instr_pending)) >= + if (unlikely(IQ_INSTR_SPACE(iq) > OCTEP_WAKE_QUEUE_THRESHOLD)) { netif_start_subqueue(iq->netdev, iq->q_no); iq->stats.restart_cnt++; @@ -903,12 +903,9 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, __netdev_tx_sent_queue(iq->netdev_q, skb->len, xmit_more); skb_tx_timestamp(skb); - atomic_inc(&iq->instr_pending); iq->fill_cnt++; wi++; - if (wi == iq->max_count) - wi = 0; - iq->host_write_index = wi; + iq->host_write_index = wi & iq->ring_size_mask; /* octep_iq_full_check stops the queue and returns * true if so, in case the queue has become full diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h index 6df902ebb7f3..c33e046b69a4 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h @@ -40,6 +40,15 @@ #define OCTEP_OQ_INTR_RESEND_BIT 59 #define OCTEP_MMIO_REGIONS 3 + +#define IQ_INSTR_PENDING(iq) ({ typeof(iq) iq__ = (iq); \ + ((iq__)->host_write_index - (iq__)->flush_index) & \ + (iq__)->ring_size_mask; \ + }) +#define IQ_INSTR_SPACE(iq) ({ typeof(iq) iq_ = (iq); \ + (iq_)->max_count - IQ_INSTR_PENDING(iq_); \ + }) + /* PCI address space mapping information. * Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of * Octeon gets mapped to different physical address spaces in diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c index d0adb82d65c3..06851b78aa28 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c @@ -21,7 +21,6 @@ static void octep_iq_reset_indices(struct octep_iq *iq) iq->flush_index = 0; iq->pkts_processed = 0; iq->pkt_in_done = 0; - atomic_set(&iq->instr_pending, 0); } /** @@ -82,7 +81,6 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget) } iq->pkts_processed += compl_pkts; - atomic_sub(compl_pkts, &iq->instr_pending); iq->stats.instr_completed += compl_pkts; iq->stats.bytes_sent += compl_bytes; iq->stats.sgentry_sent += compl_sg; @@ -91,7 +89,7 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget) netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes); if (unlikely(__netif_subqueue_stopped(iq->netdev, iq->q_no)) && - ((iq->max_count - atomic_read(&iq->instr_pending)) > + (IQ_INSTR_SPACE(iq) > OCTEP_WAKE_QUEUE_THRESHOLD)) netif_wake_subqueue(iq->netdev, iq->q_no); return !budget; @@ -144,7 +142,6 @@ static void octep_iq_free_pending(struct octep_iq *iq) dev_kfree_skb_any(skb); } - atomic_set(&iq->instr_pending, 0); iq->flush_index = fi; netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no)); } diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h index 86c98b13fc44..1ba4ff65e54d 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h @@ -172,9 +172,6 @@ struct octep_iq { /* Statistics for this input queue. */ struct octep_iq_stats stats; - /* This field keeps track of the instructions pending in this queue. */ - atomic_t instr_pending; - /* Pointer to the Virtual Base addr of the input ring. */ struct octep_tx_desc_hw *desc_ring; From d2213db3f49bce8e7a87c8de05b9a091f78f654e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 14 Nov 2023 15:08:41 +0100 Subject: [PATCH 0754/7721] net: phy: aquantia: move to separate directory Move aquantia PHY driver to separate driectory in preparation for firmware loading support to keep things tidy. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 +---- drivers/net/phy/Makefile | 6 +----- drivers/net/phy/aquantia/Kconfig | 5 +++++ drivers/net/phy/aquantia/Makefile | 6 ++++++ drivers/net/phy/{ => aquantia}/aquantia.h | 0 drivers/net/phy/{ => aquantia}/aquantia_hwmon.c | 0 drivers/net/phy/{ => aquantia}/aquantia_main.c | 0 7 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 drivers/net/phy/aquantia/Kconfig create mode 100644 drivers/net/phy/aquantia/Makefile rename drivers/net/phy/{ => aquantia}/aquantia.h (100%) rename drivers/net/phy/{ => aquantia}/aquantia_hwmon.c (100%) rename drivers/net/phy/{ => aquantia}/aquantia_main.c (100%) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 421d2b62918f..25cfc5ded1da 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" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index c945ed9bd14b..f65e85c91fc1 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,11 +35,7 @@ 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 -endif -obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o +obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_AX88796B_PHY) += ax88796b.o obj-$(CONFIG_BCM54140_PHY) += bcm54140.o diff --git a/drivers/net/phy/aquantia/Kconfig b/drivers/net/phy/aquantia/Kconfig new file mode 100644 index 000000000000..226146417a6a --- /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 000000000000..346f350bc084 --- /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.h b/drivers/net/phy/aquantia/aquantia.h similarity index 100% rename from drivers/net/phy/aquantia.h rename to drivers/net/phy/aquantia/aquantia.h diff --git a/drivers/net/phy/aquantia_hwmon.c b/drivers/net/phy/aquantia/aquantia_hwmon.c similarity index 100% rename from drivers/net/phy/aquantia_hwmon.c rename to drivers/net/phy/aquantia/aquantia_hwmon.c diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c similarity index 100% rename from drivers/net/phy/aquantia_main.c rename to drivers/net/phy/aquantia/aquantia_main.c From e1fbfa4a995d42e02e22b0dff2f8b4fdee1504b3 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 14 Nov 2023 15:08:42 +0100 Subject: [PATCH 0755/7721] net: phy: aquantia: move MMD_VEND define to header Move MMD_VEND define to header to clean things up and in preparation for firmware loading support that require some define placed in aquantia_main. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/aquantia/aquantia.h | 69 +++++++++++++++++++++++ drivers/net/phy/aquantia/aquantia_hwmon.c | 14 ----- drivers/net/phy/aquantia/aquantia_main.c | 55 ------------------ 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index c684b65c642c..f0c767c4fad1 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -9,6 +9,75 @@ #include #include +/* 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) + +/* 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 + +/* 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) + +#define VEND1_GLOBAL_GEN_STAT2 0xc831 +#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15) + +#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) + #if IS_REACHABLE(CONFIG_HWMON) int aqr_hwmon_probe(struct phy_device *phydev); #else diff --git a/drivers/net/phy/aquantia/aquantia_hwmon.c b/drivers/net/phy/aquantia/aquantia_hwmon.c index 0da451e46f69..7b3c49c3bf49 100644 --- a/drivers/net/phy/aquantia/aquantia_hwmon.c +++ b/drivers/net/phy/aquantia/aquantia_hwmon.c @@ -13,20 +13,6 @@ #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, diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 334a6904ca5a..4498426e9a52 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -91,61 +91,6 @@ #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 */ From e93984ebc1c82bd34f7a1b3391efaceee0a8ae96 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 14 Nov 2023 15:08:43 +0100 Subject: [PATCH 0756/7721] net: phy: aquantia: add firmware load support Aquantia PHY-s require firmware to be loaded before they start operating. It can be automatically loaded in case when there is a SPI-NOR connected to Aquantia PHY-s or can be loaded from the host via MDIO. This patch adds support for loading the firmware via MDIO as in most cases there is no SPI-NOR being used to save on cost. Firmware loading code itself is ported from mainline U-boot with cleanups. The firmware has mixed values both in big and little endian. PHY core itself is big-endian but it expects values to be in little-endian. The firmware is little-endian but CRC-16 value for it is stored at the end of firmware in big-endian. It seems the PHY does the conversion internally from firmware that is little-endian to the PHY that is big-endian on using the mailbox but mailbox returns a big-endian CRC-16 to verify the written data integrity. Co-developed-by: Christian Marangi Signed-off-by: Robert Marko Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/aquantia/Kconfig | 1 + drivers/net/phy/aquantia/Makefile | 2 +- drivers/net/phy/aquantia/aquantia.h | 32 ++ drivers/net/phy/aquantia/aquantia_firmware.c | 370 +++++++++++++++++++ drivers/net/phy/aquantia/aquantia_main.c | 6 + 5 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/aquantia/aquantia_firmware.c diff --git a/drivers/net/phy/aquantia/Kconfig b/drivers/net/phy/aquantia/Kconfig index 226146417a6a..a35de4b9b554 100644 --- a/drivers/net/phy/aquantia/Kconfig +++ b/drivers/net/phy/aquantia/Kconfig @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config AQUANTIA_PHY tristate "Aquantia PHYs" + select CRC_CCITT help Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 diff --git a/drivers/net/phy/aquantia/Makefile b/drivers/net/phy/aquantia/Makefile index 346f350bc084..aa77fb63c8ec 100644 --- a/drivers/net/phy/aquantia/Makefile +++ b/drivers/net/phy/aquantia/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -aquantia-objs += aquantia_main.o +aquantia-objs += aquantia_main.o aquantia_firmware.o ifdef CONFIG_HWMON aquantia-objs += aquantia_hwmon.o endif diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index f0c767c4fad1..9ed38972abdb 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -10,10 +10,35 @@ #include /* Vendor specific 1, MDIO_MMD_VEND1 */ +#define VEND1_GLOBAL_SC 0x0 +#define VEND1_GLOBAL_SC_SOFT_RESET BIT(15) +#define VEND1_GLOBAL_SC_LOW_POWER BIT(11) + #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_MAILBOX_INTERFACE1 0x0200 +#define VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE BIT(15) +#define VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE BIT(14) +#define VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET BIT(12) +#define VEND1_GLOBAL_MAILBOX_INTERFACE1_BUSY BIT(8) + +#define VEND1_GLOBAL_MAILBOX_INTERFACE2 0x0201 +#define VEND1_GLOBAL_MAILBOX_INTERFACE3 0x0202 +#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK GENMASK(15, 0) +#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK, (u16)((x) >> 16)) +#define VEND1_GLOBAL_MAILBOX_INTERFACE4 0x0203 +#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK GENMASK(15, 2) +#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK, (u16)(x)) + +#define VEND1_GLOBAL_MAILBOX_INTERFACE5 0x0204 +#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK GENMASK(15, 0) +#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK, (u16)((x) >> 16)) +#define VEND1_GLOBAL_MAILBOX_INTERFACE6 0x0205 +#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK GENMASK(15, 0) +#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK, (u16)(x)) + /* The following registers all have similar layouts; first the registers... */ #define VEND1_GLOBAL_CFG_10M 0x0310 #define VEND1_GLOBAL_CFG_100M 0x031b @@ -28,6 +53,11 @@ #define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2 /* Vendor specific 1, MDIO_MMD_VEND2 */ +#define VEND1_GLOBAL_CONTROL2 0xc001 +#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST BIT(15) +#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6) +#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0) + #define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421 #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422 #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423 @@ -83,3 +113,5 @@ int aqr_hwmon_probe(struct phy_device *phydev); #else static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } #endif + +int aqr_firmware_load(struct phy_device *phydev); diff --git a/drivers/net/phy/aquantia/aquantia_firmware.c b/drivers/net/phy/aquantia/aquantia_firmware.c new file mode 100644 index 000000000000..c5f292b1c4c8 --- /dev/null +++ b/drivers/net/phy/aquantia/aquantia_firmware.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +#include + +#include "aquantia.h" + +#define UP_RESET_SLEEP 100 + +/* addresses of memory segments in the phy */ +#define DRAM_BASE_ADDR 0x3FFE0000 +#define IRAM_BASE_ADDR 0x40000000 + +/* firmware image format constants */ +#define VERSION_STRING_SIZE 0x40 +#define VERSION_STRING_OFFSET 0x0200 +/* primary offset is written at an offset from the start of the fw blob */ +#define PRIMARY_OFFSET_OFFSET 0x8 +/* primary offset needs to be then added to a base offset */ +#define PRIMARY_OFFSET_SHIFT 12 +#define PRIMARY_OFFSET(x) ((x) << PRIMARY_OFFSET_SHIFT) +#define HEADER_OFFSET 0x300 + +struct aqr_fw_header { + u32 padding; + u8 iram_offset[3]; + u8 iram_size[3]; + u8 dram_offset[3]; + u8 dram_size[3]; +} __packed; + +enum aqr_fw_src { + AQR_FW_SRC_NVMEM = 0, + AQR_FW_SRC_FS, +}; + +static const char * const aqr_fw_src_string[] = { + [AQR_FW_SRC_NVMEM] = "NVMEM", + [AQR_FW_SRC_FS] = "FS", +}; + +/* AQR firmware doesn't have fixed offsets for iram and dram section + * but instead provide an header with the offset to use on reading + * and parsing the firmware. + * + * AQR firmware can't be trusted and each offset is validated to be + * not negative and be in the size of the firmware itself. + */ +static bool aqr_fw_validate_get(size_t size, size_t offset, size_t get_size) +{ + return offset + get_size <= size; +} + +static int aqr_fw_get_be16(const u8 *data, size_t offset, size_t size, u16 *value) +{ + if (!aqr_fw_validate_get(size, offset, sizeof(u16))) + return -EINVAL; + + *value = get_unaligned_be16(data + offset); + + return 0; +} + +static int aqr_fw_get_le16(const u8 *data, size_t offset, size_t size, u16 *value) +{ + if (!aqr_fw_validate_get(size, offset, sizeof(u16))) + return -EINVAL; + + *value = get_unaligned_le16(data + offset); + + return 0; +} + +static int aqr_fw_get_le24(const u8 *data, size_t offset, size_t size, u32 *value) +{ + if (!aqr_fw_validate_get(size, offset, sizeof(u8) * 3)) + return -EINVAL; + + *value = get_unaligned_le24(data + offset); + + return 0; +} + +/* load data into the phy's memory */ +static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr, + const u8 *data, size_t len) +{ + u16 crc = 0, up_crc; + size_t pos; + + /* PHY expect addr in LE */ + addr = (__force u32)cpu_to_le32(addr); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_MAILBOX_INTERFACE1, + VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET); + phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_MAILBOX_INTERFACE3, + VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(addr)); + phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_MAILBOX_INTERFACE4, + VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(addr)); + + /* We assume and enforce the size to be word aligned. + * If a firmware that is not word aligned is found, please report upstream. + */ + for (pos = 0; pos < len; pos += sizeof(u32)) { + u32 word; + + /* FW data is always stored in little-endian */ + word = get_unaligned((const u32 *)(data + pos)); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5, + VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word)); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE6, + VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(word)); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE1, + VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE | + VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE); + + /* calculate CRC as we load data to the mailbox. + * We convert word to big-endian as PHY is BE and mailbox will + * return a BE CRC. + */ + word = (__force u32)cpu_to_be32(word); + crc = crc_ccitt_false(crc, (u8 *)&word, sizeof(word)); + } + + up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2); + if (crc != up_crc) { + phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n", + crc, up_crc); + return -EINVAL; + } + + return 0; +} + +static int aqr_fw_boot(struct phy_device *phydev, const u8 *data, size_t size, + enum aqr_fw_src fw_src) +{ + u16 calculated_crc, read_crc, read_primary_offset; + u32 iram_offset = 0, iram_size = 0; + u32 dram_offset = 0, dram_size = 0; + char version[VERSION_STRING_SIZE]; + u32 primary_offset = 0; + int ret; + + /* extract saved CRC at the end of the fw + * CRC is saved in big-endian as PHY is BE + */ + ret = aqr_fw_get_be16(data, size - sizeof(u16), size, &read_crc); + if (ret) { + phydev_err(phydev, "bad firmware CRC in firmware\n"); + return ret; + } + calculated_crc = crc_ccitt_false(0, data, size - sizeof(u16)); + if (read_crc != calculated_crc) { + phydev_err(phydev, "bad firmware CRC: file 0x%04x calculated 0x%04x\n", + read_crc, calculated_crc); + return -EINVAL; + } + + /* Get the primary offset to extract DRAM and IRAM sections. */ + ret = aqr_fw_get_le16(data, PRIMARY_OFFSET_OFFSET, size, &read_primary_offset); + if (ret) { + phydev_err(phydev, "bad primary offset in firmware\n"); + return ret; + } + primary_offset = PRIMARY_OFFSET(read_primary_offset); + + /* Find the DRAM and IRAM sections within the firmware file. + * Make sure the fw_header is correctly in the firmware. + */ + if (!aqr_fw_validate_get(size, primary_offset + HEADER_OFFSET, + sizeof(struct aqr_fw_header))) { + phydev_err(phydev, "bad fw_header in firmware\n"); + return -EINVAL; + } + + /* offset are in LE and values needs to be converted to cpu endian */ + ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET + + offsetof(struct aqr_fw_header, iram_offset), + size, &iram_offset); + if (ret) { + phydev_err(phydev, "bad iram offset in firmware\n"); + return ret; + } + ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET + + offsetof(struct aqr_fw_header, iram_size), + size, &iram_size); + if (ret) { + phydev_err(phydev, "invalid iram size in firmware\n"); + return ret; + } + ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET + + offsetof(struct aqr_fw_header, dram_offset), + size, &dram_offset); + if (ret) { + phydev_err(phydev, "bad dram offset in firmware\n"); + return ret; + } + ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET + + offsetof(struct aqr_fw_header, dram_size), + size, &dram_size); + if (ret) { + phydev_err(phydev, "invalid dram size in firmware\n"); + return ret; + } + + /* Increment the offset with the primary offset. + * Validate iram/dram offset and size. + */ + iram_offset += primary_offset; + if (iram_size % sizeof(u32)) { + phydev_err(phydev, "iram size if not aligned to word size. Please report this upstream!\n"); + return -EINVAL; + } + if (!aqr_fw_validate_get(size, iram_offset, iram_size)) { + phydev_err(phydev, "invalid iram offset for iram size\n"); + return -EINVAL; + } + + dram_offset += primary_offset; + if (dram_size % sizeof(u32)) { + phydev_err(phydev, "dram size if not aligned to word size. Please report this upstream!\n"); + return -EINVAL; + } + if (!aqr_fw_validate_get(size, dram_offset, dram_size)) { + phydev_err(phydev, "invalid iram offset for iram size\n"); + return -EINVAL; + } + + phydev_dbg(phydev, "primary %d IRAM offset=%d size=%d DRAM offset=%d size=%d\n", + primary_offset, iram_offset, iram_size, dram_offset, dram_size); + + if (!aqr_fw_validate_get(size, dram_offset + VERSION_STRING_OFFSET, + VERSION_STRING_SIZE)) { + phydev_err(phydev, "invalid version in firmware\n"); + return -EINVAL; + } + strscpy(version, (char *)data + dram_offset + VERSION_STRING_OFFSET, + VERSION_STRING_SIZE); + if (version[0] == '\0') { + phydev_err(phydev, "invalid version in firmware\n"); + return -EINVAL; + } + phydev_info(phydev, "loading firmware version '%s' from '%s'\n", version, + aqr_fw_src_string[fw_src]); + + /* stall the microcprocessor */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2, + VEND1_GLOBAL_CONTROL2_UP_RUN_STALL | VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD); + + phydev_dbg(phydev, "loading DRAM 0x%08x from offset=%d size=%d\n", + DRAM_BASE_ADDR, dram_offset, dram_size); + ret = aqr_fw_load_memory(phydev, DRAM_BASE_ADDR, data + dram_offset, + dram_size); + if (ret) + return ret; + + phydev_dbg(phydev, "loading IRAM 0x%08x from offset=%d size=%d\n", + IRAM_BASE_ADDR, iram_offset, iram_size); + ret = aqr_fw_load_memory(phydev, IRAM_BASE_ADDR, data + iram_offset, + iram_size); + if (ret) + return ret; + + /* make sure soft reset and low power mode are clear */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC, + VEND1_GLOBAL_SC_SOFT_RESET | VEND1_GLOBAL_SC_LOW_POWER); + + /* Release the microprocessor. UP_RESET must be held for 100 usec. */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2, + VEND1_GLOBAL_CONTROL2_UP_RUN_STALL | + VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD | + VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST); + usleep_range(UP_RESET_SLEEP, UP_RESET_SLEEP * 2); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2, + VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD); + + return 0; +} + +static int aqr_firmware_load_nvmem(struct phy_device *phydev) +{ + struct nvmem_cell *cell; + size_t size; + u8 *buf; + int ret; + + cell = nvmem_cell_get(&phydev->mdio.dev, "firmware"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = nvmem_cell_read(cell, &size); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto exit; + } + + ret = aqr_fw_boot(phydev, buf, size, AQR_FW_SRC_NVMEM); + if (ret) + phydev_err(phydev, "firmware loading failed: %d\n", ret); + + kfree(buf); +exit: + nvmem_cell_put(cell); + + return ret; +} + +static int aqr_firmware_load_fs(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw; + const char *fw_name; + int ret; + + ret = of_property_read_string(dev->of_node, "firmware-name", + &fw_name); + if (ret) + return ret; + + ret = request_firmware(&fw, fw_name, dev); + if (ret) { + phydev_err(phydev, "failed to find FW file %s (%d)\n", + fw_name, ret); + return ret; + } + + ret = aqr_fw_boot(phydev, fw->data, fw->size, AQR_FW_SRC_FS); + if (ret) + phydev_err(phydev, "firmware loading failed: %d\n", ret); + + release_firmware(fw); + + return ret; +} + +int aqr_firmware_load(struct phy_device *phydev) +{ + int ret; + + /* Check if the firmware is not already loaded by pooling + * the current version returned by the PHY. If 0 is returned, + * no firmware is loaded. + */ + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); + if (ret > 0) + goto exit; + + ret = aqr_firmware_load_nvmem(phydev); + if (!ret) + goto exit; + + ret = aqr_firmware_load_fs(phydev); + if (ret) + return ret; + +exit: + return 0; +} diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 4498426e9a52..cc4a97741c4a 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -658,11 +658,17 @@ static int aqr107_resume(struct phy_device *phydev) static int aqr107_probe(struct phy_device *phydev) { + int ret; + phydev->priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct aqr107_priv), GFP_KERNEL); if (!phydev->priv) return -ENOMEM; + ret = aqr_firmware_load(phydev); + if (ret) + return ret; + return aqr_hwmon_probe(phydev); } From 0fbe92b9fd4d3287f291e8f1b03d63dc4a2f38a4 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 14 Nov 2023 15:08:44 +0100 Subject: [PATCH 0757/7721] dt-bindings: Document Marvell Aquantia PHY Document bindings for Marvell Aquantia PHY. The Marvell Aquantia PHY require a firmware to work correctly and there at least 3 way to load this firmware. Describe all the different way and document the binding "firmware-name" to load the PHY firmware from userspace. Signed-off-by: Christian Marangi Reviewed-by: Conor Dooley Acked-by: Rob Herring Signed-off-by: David S. Miller --- .../bindings/net/marvell,aquantia.yaml | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/marvell,aquantia.yaml diff --git a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml new file mode 100644 index 000000000000..9854fab4c4db --- /dev/null +++ b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/marvell,aquantia.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Aquantia Ethernet PHY + +maintainers: + - Christian Marangi + +description: | + Marvell Aquantia Ethernet PHY require a firmware to be loaded to actually + work. + + This can be done and is implemented by OEM in 3 different way: + - Attached SPI flash directly to the PHY with the firmware. The PHY + will self load the firmware in the presence of this configuration. + - Read from a dedicated partition on system NAND declared in an + NVMEM cell, and loaded to the PHY using its mailbox interface. + - Manually provided firmware loaded from a file in the filesystem. + +allOf: + - $ref: ethernet-phy.yaml# + +select: + properties: + compatible: + contains: + enum: + - ethernet-phy-id03a1.b445 + - ethernet-phy-id03a1.b460 + - ethernet-phy-id03a1.b4a2 + - ethernet-phy-id03a1.b4d0 + - ethernet-phy-id03a1.b4e0 + - ethernet-phy-id03a1.b5c2 + - ethernet-phy-id03a1.b4b0 + - ethernet-phy-id03a1.b662 + - ethernet-phy-id03a1.b712 + - ethernet-phy-id31c3.1c12 + required: + - compatible + +properties: + reg: + maxItems: 1 + + firmware-name: + description: specify the name of PHY firmware to load + + nvmem-cells: + description: phandle to the firmware nvmem cell + maxItems: 1 + + nvmem-cell-names: + const: firmware + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@0 { + compatible = "ethernet-phy-id31c3.1c12", + "ethernet-phy-ieee802.3-c45"; + + reg = <0>; + firmware-name = "AQR-G4_v5.4.C-AQR_CIG_WF-1945_0x8_ID44776_VER1630.cld"; + }; + + ethernet-phy@1 { + compatible = "ethernet-phy-id31c3.1c12", + "ethernet-phy-ieee802.3-c45"; + + reg = <1>; + nvmem-cells = <&aqr_fw>; + nvmem-cell-names = "firmware"; + }; + }; + + flash { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* ... */ + + partition@650000 { + compatible = "nvmem-cells"; + label = "0:ethphyfw"; + reg = <0x650000 0x80000>; + read-only; + #address-cells = <1>; + #size-cells = <1>; + + aqr_fw: aqr_fw@0 { + reg = <0x0 0x5f42a>; + }; + }; + + /* ... */ + + }; + }; From 9ffa01cab0699476be12ed4917c7d282cedc5ddf Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 13:04:39 -0300 Subject: [PATCH 0758/7721] selftests: tc-testing: drop '-N' argument from nsPlugin This argument would bypass the net namespace creation and run the test in the root namespace, even if nsPlugin was specified. Drop it as it's the same as commenting out the nsPlugin from a test and adds additional complexity to the plugin code. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../tc-testing/plugin-lib/nsPlugin.py | 49 +++++-------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index b62429b0fcdb..2297b4568ca9 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -28,10 +28,7 @@ def prepare_suite(obj, test): shadow['DEV2'] = original['DEV2'] obj.args.NAMES = shadow - if obj.args.namespace: - obj._ns_create() - else: - obj._ports_create() + obj._ns_create() # Make sure the netns is visible in the fs while True: @@ -75,10 +72,7 @@ class SubPlugin(TdcPlugin): if self.args.verbose: print('{}.post_case'.format(self.sub_class)) - if self.args.namespace: - self._ns_destroy() - else: - self._ports_destroy() + self._ns_destroy() def post_suite(self, index): if self.args.verbose: @@ -93,24 +87,11 @@ class SubPlugin(TdcPlugin): subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - def add_args(self, parser): - super().add_args(parser) - self.argparser_group = self.argparser.add_argument_group( - 'netns', - 'options for nsPlugin(run commands in net namespace)') - self.argparser_group.add_argument( - '-N', '--no-namespace', action='store_false', default=True, - dest='namespace', help='Don\'t run commands in namespace') - return self.argparser - def adjust_command(self, stage, command): super().adjust_command(stage, command) cmdform = 'list' cmdlist = list() - if not self.args.namespace: - return command - if self.args.verbose: print('{}.adjust_command'.format(self.sub_class)) @@ -144,8 +125,6 @@ class SubPlugin(TdcPlugin): cmds.append(self._replace_keywords('link add $DEV0 type veth peer name $DEV1')) cmds.append(self._replace_keywords('link set $DEV0 up')) cmds.append(self._replace_keywords('link add $DUMMY type dummy')) - if not self.args.namespace: - cmds.append(self._replace_keywords('link set $DEV1 up')) return cmds @@ -161,18 +140,17 @@ class SubPlugin(TdcPlugin): def _ns_create_cmds(self): cmds = [] - if self.args.namespace: - ns = self.args.NAMES['NS'] + ns = self.args.NAMES['NS'] - cmds.append(self._replace_keywords('netns add {}'.format(ns))) - cmds.append(self._replace_keywords('link set $DEV1 netns {}'.format(ns))) - cmds.append(self._replace_keywords('link set $DUMMY netns {}'.format(ns))) - cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV1 up'.format(ns))) - cmds.append(self._replace_keywords('netns exec {} $IP link set $DUMMY up'.format(ns))) + cmds.append(self._replace_keywords('netns add {}'.format(ns))) + cmds.append(self._replace_keywords('link set $DEV1 netns {}'.format(ns))) + cmds.append(self._replace_keywords('link set $DUMMY netns {}'.format(ns))) + cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV1 up'.format(ns))) + cmds.append(self._replace_keywords('netns exec {} $IP link set $DUMMY up'.format(ns))) - if self.args.device: - cmds.append(self._replace_keywords('link set $DEV2 netns {}'.format(ns))) - cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV2 up'.format(ns))) + if self.args.device: + cmds.append(self._replace_keywords('link set $DEV2 netns {}'.format(ns))) + cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV2 up'.format(ns))) return cmds @@ -192,9 +170,8 @@ class SubPlugin(TdcPlugin): Destroy the network namespace for testing (and any associated network devices as well) ''' - if self.args.namespace: - self._exec_cmd('post', self._ns_destroy_cmd()) - self._ports_destroy() + self._exec_cmd('post', self._ns_destroy_cmd()) + self._ports_destroy() @cached_property def _proc(self): From fa63d353ddfb8a2d7688220a45b84e1507d211cf Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 13:04:40 -0300 Subject: [PATCH 0759/7721] selftests: tc-testing: rework namespaces and devices setup As mentioned in the TC Workshop 0x17, our recent changes to tdc broke downstream CI systems like tuxsuite. The issue is the classic problem with rcu/workqueue objects where you can miss them if not enough wall time has passed. The latter is subjective to the system and kernel config, in my machine could be nanoseconds while in another could be microseconds or more. In order to make the suite deterministic, poll for the existence of the objects in a reasonable manner. Talking netlink directly is the the best solution in order to avoid paying the cost of multiple 'fork()' calls, so introduce a netlink based setup routine using pyroute2. We leave the iproute2 one as a fallback when pyroute2 is not available. Also rework the iproute2 side to mimic the netlink routine where it creates DEV0 as the peer of DEV1 and moves DEV1 into the net namespace. This way when the namespace is deleted DEV0 is also deleted automatically, leaving no margin for resource leaks. Another bonus of this change is that our setup time sped up by a factor of 2 when using netlink. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../tc-testing/plugin-lib/nsPlugin.py | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 2297b4568ca9..62974bd3a4a5 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -9,6 +9,14 @@ from TdcPlugin import TdcPlugin from tdc_config import * +try: + from pyroute2 import netns + from pyroute2 import IPRoute + netlink = True +except ImportError: + netlink = False + print("!!! Consider installing pyroute2 !!!") + def prepare_suite(obj, test): original = obj.args.NAMES @@ -28,7 +36,10 @@ def prepare_suite(obj, test): shadow['DEV2'] = original['DEV2'] obj.args.NAMES = shadow - obj._ns_create() + if netlink == True: + obj._nl_ns_create() + else: + obj._ns_create() # Make sure the netns is visible in the fs while True: @@ -67,7 +78,6 @@ class SubPlugin(TdcPlugin): if test_skip: return - def post_case(self): if self.args.verbose: print('{}.post_case'.format(self.sub_class)) @@ -119,23 +129,41 @@ class SubPlugin(TdcPlugin): print('adjust_command: return command [{}]'.format(command)) return command - def _ports_create_cmds(self): - cmds = [] + def _nl_ns_create(self): + ns = self.args.NAMES["NS"]; + dev0 = self.args.NAMES["DEV0"]; + dev1 = self.args.NAMES["DEV1"]; + dummy = self.args.NAMES["DUMMY"]; - cmds.append(self._replace_keywords('link add $DEV0 type veth peer name $DEV1')) - cmds.append(self._replace_keywords('link set $DEV0 up')) - cmds.append(self._replace_keywords('link add $DUMMY type dummy')) + if self.args.verbose: + print('{}._nl_ns_create'.format(self.sub_class)) - return cmds + netns.create(ns) + netns.pushns(newns=ns) + with IPRoute() as ip: + ip.link('add', ifname=dev1, kind='veth', peer={'ifname': dev0, 'net_ns_fd':'/proc/1/ns/net'}) + ip.link('add', ifname=dummy, kind='dummy') + while True: + try: + dev1_idx = ip.link_lookup(ifname=dev1)[0] + dummy_idx = ip.link_lookup(ifname=dummy)[0] + ip.link('set', index=dev1_idx, state='up') + ip.link('set', index=dummy_idx, state='up') + break + except: + time.sleep(0.1) + continue + netns.popns() - def _ports_create(self): - self._exec_cmd_batched('pre', self._ports_create_cmds()) - - def _ports_destroy_cmd(self): - return self._replace_keywords('link del $DEV0') - - def _ports_destroy(self): - self._exec_cmd('post', self._ports_destroy_cmd()) + with IPRoute() as ip: + while True: + try: + dev0_idx = ip.link_lookup(ifname=dev0)[0] + ip.link('set', index=dev0_idx, state='up') + break + except: + time.sleep(0.1) + continue def _ns_create_cmds(self): cmds = [] @@ -143,10 +171,13 @@ class SubPlugin(TdcPlugin): ns = self.args.NAMES['NS'] cmds.append(self._replace_keywords('netns add {}'.format(ns))) + cmds.append(self._replace_keywords('link add $DEV1 type veth peer name $DEV0')) cmds.append(self._replace_keywords('link set $DEV1 netns {}'.format(ns))) + cmds.append(self._replace_keywords('link add $DUMMY type dummy'.format(ns))) cmds.append(self._replace_keywords('link set $DUMMY netns {}'.format(ns))) cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV1 up'.format(ns))) cmds.append(self._replace_keywords('netns exec {} $IP link set $DUMMY up'.format(ns))) + cmds.append(self._replace_keywords('link set $DEV0 up'.format(ns))) if self.args.device: cmds.append(self._replace_keywords('link set $DEV2 netns {}'.format(ns))) @@ -159,7 +190,6 @@ class SubPlugin(TdcPlugin): Create the network namespace in which the tests will be run and set up the required network devices for it. ''' - self._ports_create() self._exec_cmd_batched('pre', self._ns_create_cmds()) def _ns_destroy_cmd(self): @@ -171,7 +201,6 @@ class SubPlugin(TdcPlugin): devices as well) ''' self._exec_cmd('post', self._ns_destroy_cmd()) - self._ports_destroy() @cached_property def _proc(self): From bb9623c337f5d13b15d700127281c9607d1f8ec2 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 13:04:41 -0300 Subject: [PATCH 0760/7721] selftests: tc-testing: preload all modules in kselftests While running tdc tests in parallel it can race over the module loading done by tc and fail the run with random errors. So avoid this by preloading all modules before running tdc in kselftests. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.sh | 65 ++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tdc.sh b/tools/testing/selftests/tc-testing/tdc.sh index eb357bd7923c..ae08b7a47c42 100755 --- a/tools/testing/selftests/tc-testing/tdc.sh +++ b/tools/testing/selftests/tc-testing/tdc.sh @@ -1,7 +1,68 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -modprobe netdevsim -modprobe sch_teql +# If a module is required and was not compiled +# the test that requires it will fail anyways +try_modprobe() { + modprobe -q -R "$1" + if [ $? -ne 0 ]; then + echo "Module $1 not found... skipping." + else + modprobe "$1" + fi +} + +try_modprobe netdevsim +try_modprobe act_bpf +try_modprobe act_connmark +try_modprobe act_csum +try_modprobe act_ct +try_modprobe act_ctinfo +try_modprobe act_gact +try_modprobe act_gate +try_modprobe act_ipt +try_modprobe act_mirred +try_modprobe act_mpls +try_modprobe act_nat +try_modprobe act_pedit +try_modprobe act_police +try_modprobe act_sample +try_modprobe act_simple +try_modprobe act_skbedit +try_modprobe act_skbmod +try_modprobe act_tunnel_key +try_modprobe act_vlan +try_modprobe cls_basic +try_modprobe cls_bpf +try_modprobe cls_cgroup +try_modprobe cls_flow +try_modprobe cls_flower +try_modprobe cls_fw +try_modprobe cls_matchall +try_modprobe cls_route +try_modprobe cls_u32 +try_modprobe em_canid +try_modprobe em_cmp +try_modprobe em_ipset +try_modprobe em_ipt +try_modprobe em_meta +try_modprobe em_nbyte +try_modprobe em_text +try_modprobe em_u32 +try_modprobe sch_cake +try_modprobe sch_cbs +try_modprobe sch_choke +try_modprobe sch_codel +try_modprobe sch_drr +try_modprobe sch_etf +try_modprobe sch_ets +try_modprobe sch_fq +try_modprobe sch_fq_codel +try_modprobe sch_fq_pie +try_modprobe sch_gred +try_modprobe sch_hfsc +try_modprobe sch_hhf +try_modprobe sch_htb +try_modprobe sch_teql ./tdc.py -c actions --nobuildebpf ./tdc.py -c qdisc From 04fd47bf70f95533c2b8387c19c7e11c085945d2 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 13:04:42 -0300 Subject: [PATCH 0761/7721] selftests: tc-testing: use parallel tdc in kselftests Leverage parallel tests in kselftests using all the available cpus. We tested this in tuxsuite and locally extensively and it seems it's ready for prime time. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tdc.sh b/tools/testing/selftests/tc-testing/tdc.sh index ae08b7a47c42..4dbe50bde5a0 100755 --- a/tools/testing/selftests/tc-testing/tdc.sh +++ b/tools/testing/selftests/tc-testing/tdc.sh @@ -64,5 +64,5 @@ try_modprobe sch_hfsc try_modprobe sch_hhf try_modprobe sch_htb try_modprobe sch_teql -./tdc.py -c actions --nobuildebpf -./tdc.py -c qdisc +./tdc.py -J`nproc` -c actions --nobuildebpf +./tdc.py -J`nproc` -c qdisc From 3bdd9fd29cb0f136b307559a19c107210ad5c314 Mon Sep 17 00:00:00 2001 From: Lucas Karpinski Date: Tue, 14 Nov 2023 10:11:31 -0500 Subject: [PATCH 0762/7721] selftests/net: synchronize udpgro tests' tx and rx connection The sockets used by udpgso_bench_tx aren't always ready when udpgso_bench_tx transmits packets. This issue is more prevalent in -rt kernels, but can occur in both. Replace the hacky sleep calls with a function that checks whether the ports in the namespace are ready for use. Suggested-by: Paolo Abeni Signed-off-by: Lucas Karpinski Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/net_helper.sh | 22 +++++++++++++++++++ tools/testing/selftests/net/udpgro.sh | 13 +++++------ tools/testing/selftests/net/udpgro_bench.sh | 5 +++-- tools/testing/selftests/net/udpgro_frglist.sh | 5 +++-- 4 files changed, 34 insertions(+), 11 deletions(-) create mode 100755 tools/testing/selftests/net/net_helper.sh diff --git a/tools/testing/selftests/net/net_helper.sh b/tools/testing/selftests/net/net_helper.sh new file mode 100755 index 000000000000..4fe0befa13fb --- /dev/null +++ b/tools/testing/selftests/net/net_helper.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Helper functions + +wait_local_port_listen() +{ + local listener_ns="${1}" + local port="${2}" + local protocol="${3}" + local port_hex + local i + + port_hex="$(printf "%04X" "${port}")" + for i in $(seq 10); do + if ip netns exec "${listener_ns}" cat /proc/net/"${protocol}"* | \ + grep -q "${port_hex}"; then + break + fi + sleep 0.1 + done +} diff --git a/tools/testing/selftests/net/udpgro.sh b/tools/testing/selftests/net/udpgro.sh index 0c743752669a..af5dc57c8ce9 100755 --- a/tools/testing/selftests/net/udpgro.sh +++ b/tools/testing/selftests/net/udpgro.sh @@ -3,6 +3,8 @@ # # Run a series of udpgro functional tests. +source net_helper.sh + readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" BPF_FILE="../bpf/xdp_dummy.bpf.o" @@ -51,8 +53,7 @@ run_one() { echo "ok" || \ echo "failed" & - # Hack: let bg programs complete the startup - sleep 0.2 + wait_local_port_listen ${PEER_NS} 8000 udp ./udpgso_bench_tx ${tx_args} ret=$? wait $(jobs -p) @@ -97,7 +98,7 @@ run_one_nat() { echo "ok" || \ echo "failed"& - sleep 0.1 + wait_local_port_listen "${PEER_NS}" 8000 udp ./udpgso_bench_tx ${tx_args} ret=$? kill -INT $pid @@ -118,11 +119,9 @@ run_one_2sock() { echo "ok" || \ echo "failed" & - # Hack: let bg programs complete the startup - sleep 0.2 + wait_local_port_listen "${PEER_NS}" 12345 udp ./udpgso_bench_tx ${tx_args} -p 12345 - sleep 0.1 - # first UDP GSO socket should be closed at this point + wait_local_port_listen "${PEER_NS}" 8000 udp ./udpgso_bench_tx ${tx_args} ret=$? wait $(jobs -p) diff --git a/tools/testing/selftests/net/udpgro_bench.sh b/tools/testing/selftests/net/udpgro_bench.sh index 894972877e8b..cb664679b434 100755 --- a/tools/testing/selftests/net/udpgro_bench.sh +++ b/tools/testing/selftests/net/udpgro_bench.sh @@ -3,6 +3,8 @@ # # Run a series of udpgro benchmarks +source net_helper.sh + readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" BPF_FILE="../bpf/xdp_dummy.bpf.o" @@ -40,8 +42,7 @@ run_one() { ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r & ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r & - # Hack: let bg programs complete the startup - sleep 0.2 + wait_local_port_listen "${PEER_NS}" 8000 udp ./udpgso_bench_tx ${tx_args} } diff --git a/tools/testing/selftests/net/udpgro_frglist.sh b/tools/testing/selftests/net/udpgro_frglist.sh index 0a6359bed0b9..dd47fa96f6b3 100755 --- a/tools/testing/selftests/net/udpgro_frglist.sh +++ b/tools/testing/selftests/net/udpgro_frglist.sh @@ -3,6 +3,8 @@ # # Run a series of udpgro benchmarks +source net_helper.sh + readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" BPF_FILE="../bpf/xdp_dummy.bpf.o" @@ -45,8 +47,7 @@ run_one() { echo ${rx_args} ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r & - # Hack: let bg programs complete the startup - sleep 0.2 + wait_local_port_listen "${PEER_NS}" 8000 udp ./udpgso_bench_tx ${tx_args} } From c6e9dba3be5ef3b701b29b143609561915e5d0e9 Mon Sep 17 00:00:00 2001 From: Alce Lafranque Date: Tue, 14 Nov 2023 11:36:57 -0600 Subject: [PATCH 0763/7721] vxlan: add support for flowlabel inherit By default, VXLAN encapsulation over IPv6 sets the flow label to 0, with an option for a fixed value. This commits add the ability to inherit the flow label from the inner packet, like for other tunnel implementations. This enables devices using only L3 headers for ECMP to correctly balance VXLAN-encapsulated IPv6 packets. ``` $ ./ip/ip link add dummy1 type dummy $ ./ip/ip addr add 2001:db8::2/64 dev dummy1 $ ./ip/ip link set up dev dummy1 $ ./ip/ip link add vxlan1 type vxlan id 100 flowlabel inherit remote 2001:db8::1 local 2001:db8::2 $ ./ip/ip link set up dev vxlan1 $ ./ip/ip addr add 2001:db8:1::2/64 dev vxlan1 $ ./ip/ip link set arp off dev vxlan1 $ ping -q 2001:db8:1::1 & $ tshark -d udp.port==8472,vxlan -Vpni dummy1 -c1 [...] Internet Protocol Version 6, Src: 2001:db8::2, Dst: 2001:db8::1 0110 .... = Version: 6 .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT) .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0) .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0) .... 1011 0001 1010 1111 1011 = Flow Label: 0xb1afb [...] Virtual eXtensible Local Area Network Flags: 0x0800, VXLAN Network ID (VNI) Group Policy ID: 0 VXLAN Network Identifier (VNI): 100 [...] Internet Protocol Version 6, Src: 2001:db8:1::2, Dst: 2001:db8:1::1 0110 .... = Version: 6 .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT) .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0) .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0) .... 1011 0001 1010 1111 1011 = Flow Label: 0xb1afb ``` Signed-off-by: Alce Lafranque Co-developed-by: Vincent Bernat Signed-off-by: Vincent Bernat Reviewed-by: Ido Schimmel Reviewed-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 23 ++++++++++++++++++++++- include/net/ip_tunnels.h | 11 +++++++++++ include/net/vxlan.h | 33 +++++++++++++++++---------------- include/uapi/linux/if_link.h | 8 ++++++++ 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 412c3c0b6990..764ea02ff911 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2379,7 +2379,17 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, else udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); #if IS_ENABLED(CONFIG_IPV6) - key.label = vxlan->cfg.label; + switch (vxlan->cfg.label_policy) { + case VXLAN_LABEL_FIXED: + key.label = vxlan->cfg.label; + break; + case VXLAN_LABEL_INHERIT: + key.label = ip_tunnel_get_flowlabel(old_iph, skb); + break; + default: + DEBUG_NET_WARN_ON_ONCE(1); + goto drop; + } #endif } else { if (!info) { @@ -3366,6 +3376,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_DF] = { .type = NLA_U8 }, [IFLA_VXLAN_VNIFILTER] = { .type = NLA_U8 }, [IFLA_VXLAN_LOCALBYPASS] = NLA_POLICY_MAX(NLA_U8, 1), + [IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX), }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], @@ -3740,6 +3751,12 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, return -EINVAL; } + if (conf->label_policy && !use_ipv6) { + NL_SET_ERR_MSG(extack, + "Label policy only applies to IPv6 VXLAN devices"); + return -EINVAL; + } + if (conf->remote_ifindex) { struct net_device *lowerdev; @@ -4082,6 +4099,8 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], if (data[IFLA_VXLAN_LABEL]) conf->label = nla_get_be32(data[IFLA_VXLAN_LABEL]) & IPV6_FLOWLABEL_MASK; + if (data[IFLA_VXLAN_LABEL_POLICY]) + conf->label_policy = nla_get_u32(data[IFLA_VXLAN_LABEL_POLICY]); if (data[IFLA_VXLAN_LEARNING]) { err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LEARNING, @@ -4398,6 +4417,7 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TOS */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_DF */ nla_total_size(sizeof(__be32)) + /* IFLA_VXLAN_LABEL */ + nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LABEL_POLICY */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_PROXY */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */ @@ -4471,6 +4491,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || nla_put_u8(skb, IFLA_VXLAN_DF, vxlan->cfg.df) || nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) || + nla_put_u32(skb, IFLA_VXLAN_LABEL_POLICY, vxlan->cfg.label_policy) || nla_put_u8(skb, IFLA_VXLAN_LEARNING, !!(vxlan->cfg.flags & VXLAN_F_LEARN)) || nla_put_u8(skb, IFLA_VXLAN_PROXY, diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index f346b4efbc30..2d746f4c9a0a 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -416,6 +416,17 @@ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, return 0; } +static inline __be32 ip_tunnel_get_flowlabel(const struct iphdr *iph, + const struct sk_buff *skb) +{ + __be16 payload_protocol = skb_protocol(skb, true); + + if (payload_protocol == htons(ETH_P_IPV6)) + return ip6_flowlabel((const struct ipv6hdr *)iph); + else + return 0; +} + static inline u8 ip_tunnel_get_ttl(const struct iphdr *iph, const struct sk_buff *skb) { diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 6a9f8a5f387c..33ba6fc151cf 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -210,22 +210,23 @@ struct vxlan_rdst { }; struct vxlan_config { - union vxlan_addr remote_ip; - union vxlan_addr saddr; - __be32 vni; - int remote_ifindex; - int mtu; - __be16 dst_port; - u16 port_min; - u16 port_max; - u8 tos; - u8 ttl; - __be32 label; - u32 flags; - unsigned long age_interval; - unsigned int addrmax; - bool no_share; - enum ifla_vxlan_df df; + union vxlan_addr remote_ip; + union vxlan_addr saddr; + __be32 vni; + int remote_ifindex; + int mtu; + __be16 dst_port; + u16 port_min; + u16 port_max; + u8 tos; + u8 ttl; + __be32 label; + enum ifla_vxlan_label_policy label_policy; + u32 flags; + unsigned long age_interval; + unsigned int addrmax; + bool no_share; + enum ifla_vxlan_df df; }; enum { diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 29ff80da2775..8181ef23a7a2 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -856,6 +856,7 @@ enum { IFLA_VXLAN_DF, IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ IFLA_VXLAN_LOCALBYPASS, + IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -873,6 +874,13 @@ enum ifla_vxlan_df { VXLAN_DF_MAX = __VXLAN_DF_END - 1, }; +enum ifla_vxlan_label_policy { + VXLAN_LABEL_FIXED = 0, + VXLAN_LABEL_INHERIT = 1, + __VXLAN_LABEL_END, + VXLAN_LABEL_MAX = __VXLAN_LABEL_END - 1, +}; + /* GENEVE section */ enum { IFLA_GENEVE_UNSPEC, From 14dd92d0a1174d3fe052bf87a3ae3a6914946170 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 14 Nov 2023 17:23:40 +0000 Subject: [PATCH 0764/7721] tcp: use tp->total_rto to track number of linear timeouts in SYN_SENT state In commit ccce324dabfe ("tcp: make the first N SYN RTO backoffs linear") David used icsk->icsk_backoff field to track the number of linear timeouts. Since then, tp->total_rto has been added. This commit uses tp->total_rto instead of icsk->icsk_backoff so that tcp_ld_RTO_revert() no longer can trigger an overflow in inet_csk_rto_backoff(). Other than the potential UBSAN report, there was no issue because receiving an ICMP message currently aborts the connect(). In the following patch, we want to adhere to RFC 6069 and RFC 1122 4.2.3.9. Signed-off-by: Eric Dumazet Cc: David Morley Cc: Neal Cardwell Cc: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 1f9f6c1c196b..d1ad20ce1c8c 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -626,7 +626,6 @@ void tcp_retransmit_timer(struct sock *sk) * implemented ftp to mars will work nicely. We will have to fix * the 120 second clamps though! */ - icsk->icsk_backoff++; out_reset_timer: /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is @@ -647,11 +646,12 @@ void tcp_retransmit_timer(struct sock *sk) tcp_rto_min(sk), TCP_RTO_MAX); } else if (sk->sk_state != TCP_SYN_SENT || - icsk->icsk_backoff > + tp->total_rto > READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) { /* Use normal (exponential) backoff unless linear timeouts are * activated. */ + icsk->icsk_backoff++; icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); } inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, From 0a8de364ff7a14558e9676f424283148110384d6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 14 Nov 2023 17:23:41 +0000 Subject: [PATCH 0765/7721] tcp: no longer abort SYN_SENT when receiving some ICMP Currently, non fatal ICMP messages received on behalf of SYN_SENT sockets do call tcp_ld_RTO_revert() to implement RFC 6069, but immediately call tcp_done(), thus aborting the connect() attempt. This violates RFC 1122 following requirement: 4.2.3.9 ICMP Messages ... o Destination Unreachable -- codes 0, 1, 5 Since these Unreachable messages indicate soft error conditions, TCP MUST NOT abort the connection, and it SHOULD make the information available to the application. This patch makes sure non 'fatal' ICMP[v6] messages do not abort the connection attempt. It enables RFC 6069 for SYN_SENT sockets as a result. Signed-off-by: Eric Dumazet Cc: David Morley Cc: Neal Cardwell Cc: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 6 ++++++ net/ipv6/tcp_ipv6.c | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5f693bbd578d..86cc6d36f818 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -482,6 +482,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) const int code = icmp_hdr(skb)->code; struct sock *sk; struct request_sock *fastopen; + bool harderr = false; u32 seq, snd_una; int err; struct net *net = dev_net(skb->dev); @@ -555,6 +556,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) goto out; case ICMP_PARAMETERPROB: err = EPROTO; + harderr = true; break; case ICMP_DEST_UNREACH: if (code > NR_ICMP_UNREACH) @@ -579,6 +581,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) } err = icmp_err_convert[code].errno; + harderr = icmp_err_convert[code].fatal; /* check if this ICMP message allows revert of backoff. * (see RFC 6069) */ @@ -604,6 +607,9 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th); + if (!harderr) + break; + if (!sock_owned_by_user(sk)) { WRITE_ONCE(sk->sk_err, err); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 937a02c2e534..43deda49cc52 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -381,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct tcp_sock *tp; __u32 seq, snd_una; struct sock *sk; - bool fatal; + bool harderr; int err; sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, @@ -402,9 +402,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return 0; } seq = ntohl(th->seq); - fatal = icmpv6_err_convert(type, code, &err); + harderr = icmpv6_err_convert(type, code, &err); if (sk->sk_state == TCP_NEW_SYN_RECV) { - tcp_req_err(sk, seq, fatal); + tcp_req_err(sk, seq, harderr); return 0; } @@ -489,6 +489,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th); + if (!harderr) + break; + if (!sock_owned_by_user(sk)) { WRITE_ONCE(sk->sk_err, err); sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ From 96fa96e198f9707285003075fbbce7db6a485112 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 15 Nov 2023 11:39:18 +0000 Subject: [PATCH 0766/7721] net: linkmode: add linkmode_fill() helper Add a linkmode_fill() helper, which will allow us to convert phylink's open coded bitmap_fill() operations. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- include/linux/linkmode.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h index 7303b4bc2ce0..287f590ed56b 100644 --- a/include/linux/linkmode.h +++ b/include/linux/linkmode.h @@ -10,6 +10,11 @@ static inline void linkmode_zero(unsigned long *dst) bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); } +static inline void linkmode_fill(unsigned long *dst) +{ + bitmap_fill(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + static inline void linkmode_copy(unsigned long *dst, const unsigned long *src) { bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS); From ba50a8d40258081325db15f5a86cbb301867a3ba Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 15 Nov 2023 11:39:23 +0000 Subject: [PATCH 0767/7721] net: phylink: use linkmode_fill() Use linkmode_fill() rather than open coding the bitmap operation. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 25c19496a336..d2fa949ff1ea 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -805,7 +805,7 @@ static int phylink_parse_fixedlink(struct phylink *pl, phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n", pl->link_config.speed); - bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + linkmode_fill(pl->supported); linkmode_copy(pl->link_config.advertising, pl->supported); phylink_validate(pl, pl->supported, &pl->link_config); @@ -1640,7 +1640,7 @@ struct phylink *phylink_create(struct phylink_config *config, __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); timer_setup(&pl->link_poll, phylink_fixed_poll, 0); - bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + linkmode_fill(pl->supported); linkmode_copy(pl->link_config.advertising, pl->supported); phylink_validate(pl, pl->supported, &pl->link_config); From 466b97b1871a49c272757f7527db2f85ea6338b4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 15 Nov 2023 11:39:28 +0000 Subject: [PATCH 0768/7721] net: sfp: use linkmode_*() rather than open coding Use the linkmode_*() helpers rather than open coding the calls to the bitmap operators. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 208a9393c2df..6fa679b36290 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -328,7 +328,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, * modules use 2500Mbaud rather than 3100 or 3200Mbaud for * 2500BASE-X, so we allow some slack here. */ - if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) { + if (linkmode_empty(modes) && br_nom) { if (br_min <= 1300 && br_max >= 1200) { phylink_set(modes, 1000baseX_Full); __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); From 7c93d177d913a3a43bcb8f8edd4e2f78074a18a3 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 15 Nov 2023 21:04:48 +0000 Subject: [PATCH 0769/7721] dt-bindings: net: renesas,etheravb: Document RZ/Five SoC The Gigabit Ethernet IP block on the RZ/Five SoC is identical to one found on the RZ/G2UL SoC. "renesas,r9a07g043-gbeth" compatible string will be used on the RZ/Five SoC so to make this clear and to keep this file consistent, update the comment to include RZ/Five SoC. No driver changes are required as generic compatible string "renesas,rzg2l-gbeth" will be used as a fallback on RZ/Five SoC. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Sergey Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/renesas,etheravb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml index 5d074f27d462..d3306b186000 100644 --- a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml +++ b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml @@ -55,7 +55,7 @@ properties: - items: - enum: - - renesas,r9a07g043-gbeth # RZ/G2UL + - renesas,r9a07g043-gbeth # RZ/G2UL and RZ/Five - renesas,r9a07g044-gbeth # RZ/G2{L,LC} - renesas,r9a07g054-gbeth # RZ/V2L - const: renesas,rzg2l-gbeth # RZ/{G2L,G2UL,V2L} family From d580d265e9abb8c4e1e891051c7b03f3eac86055 Mon Sep 17 00:00:00 2001 From: Shigeru Yoshida Date: Fri, 17 Nov 2023 09:37:04 +0900 Subject: [PATCH 0770/7721] tipc: Remove redundant call to TLV_SPACE() The purpose of TLV_SPACE() is to add the TLV descriptor size to the size of the TLV value passed as argument and align the resulting size to TLV_ALIGNTO. tipc_tlv_alloc() calls TLV_SPACE() on its argument. In other words, tipc_tlv_alloc() takes its argument as the size of the TLV value. So the call to TLV_SPACE() in tipc_get_err_tlv() is redundant. Let's remove this redundancy. Acked-by: Paolo Abeni Signed-off-by: Shigeru Yoshida Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index c763008a8adb..079aebb16ed8 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -168,7 +168,7 @@ static struct sk_buff *tipc_get_err_tlv(char *str) int str_len = strlen(str) + 1; struct sk_buff *buf; - buf = tipc_tlv_alloc(TLV_SPACE(str_len)); + buf = tipc_tlv_alloc(str_len); if (buf) tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len); From 380b50ae3a04222334a3779b3787eba844b1177f Mon Sep 17 00:00:00 2001 From: Marco von Rosenberg Date: Thu, 16 Nov 2023 20:32:31 +0100 Subject: [PATCH 0771/7721] net: phy: broadcom: Wire suspend/resume for BCM54612E The BCM54612E ethernet PHY supports IDDQ-SR. Therefore wire-up the suspend and resume callbacks to point to bcm54xx_suspend() and bcm54xx_resume(). Signed-off-by: Marco von Rosenberg Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 3a627105675a..312a8bb35d78 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -1135,6 +1135,8 @@ static struct phy_driver broadcom_drivers[] = { .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, .led_brightness_set = bcm_phy_led_brightness_set, + .suspend = bcm54xx_suspend, + .resume = bcm54xx_resume, }, { .phy_id = PHY_ID_BCM54616S, .phy_id_mask = 0xfffffff0, From 18de1e517ed37ebaf33e771e46faf052e966e163 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 16 Nov 2023 08:57:07 +0000 Subject: [PATCH 0772/7721] gve: add gve_features_check() It is suboptimal to attempt skb linearization from ndo_start_xmit() if a gso skb has pathological layout, or if host stack does not have access to the payload (TCP direct). Linearization of large skbs can also fail under memory pressure. We should instead have an ndo_features_check() so that we can fallback to GSO, which is supported even for TCP direct, and generally much more efficient (no payload copy). Signed-off-by: Eric Dumazet Cc: Bailey Forrest Cc: Willem de Bruijn Cc: Jeroen de Borst Cc: Praveen Kaligineedi Cc: Shailend Chand Cc: Ziwei Xiao Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve_dqo.h | 3 ++ drivers/net/ethernet/google/gve/gve_main.c | 13 +++++++ drivers/net/ethernet/google/gve/gve_tx_dqo.c | 37 ++++++++------------ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h index 1eb4d5fd8561..c36b93f0de15 100644 --- a/drivers/net/ethernet/google/gve/gve_dqo.h +++ b/drivers/net/ethernet/google/gve/gve_dqo.h @@ -33,6 +33,9 @@ #define GVE_DEALLOCATE_COMPL_TIMEOUT 60 netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev); +netdev_features_t gve_features_check_dqo(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features); bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean); int gve_rx_poll_dqo(struct gve_notify_block *block, int budget); int gve_tx_alloc_rings_dqo(struct gve_priv *priv); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 2d42e733837b..cc169748ffa2 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -79,6 +79,18 @@ static int gve_verify_driver_compatibility(struct gve_priv *priv) return err; } +static netdev_features_t gve_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + struct gve_priv *priv = netdev_priv(dev); + + if (!gve_is_gqi(priv)) + return gve_features_check_dqo(skb, dev, features); + + return features; +} + static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gve_priv *priv = netdev_priv(dev); @@ -1879,6 +1891,7 @@ static int gve_set_features(struct net_device *netdev, static const struct net_device_ops gve_netdev_ops = { .ndo_start_xmit = gve_start_xmit, + .ndo_features_check = gve_features_check, .ndo_open = gve_open, .ndo_stop = gve_close, .ndo_get_stats64 = gve_get_stats, diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index 1e19b834a613..f59c4710f118 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -843,6 +843,16 @@ static bool gve_can_send_tso(const struct sk_buff *skb) return true; } +netdev_features_t gve_features_check_dqo(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + if (skb_is_gso(skb) && !gve_can_send_tso(skb)) + return features & ~NETIF_F_GSO_MASK; + + return features; +} + /* Attempt to transmit specified SKB. * * Returns 0 if the SKB was transmitted or dropped. @@ -854,11 +864,10 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx, int num_buffer_descs; int total_num_descs; - if (tx->dqo.qpl) { - if (skb_is_gso(skb)) - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) - goto drop; + if (skb_is_gso(skb) && unlikely(ipv6_hopopt_jumbo_remove(skb))) + goto drop; + if (tx->dqo.qpl) { /* We do not need to verify the number of buffers used per * packet or per segment in case of TSO as with 2K size buffers * none of the TX packet rules would be violated. @@ -868,24 +877,8 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx, */ num_buffer_descs = DIV_ROUND_UP(skb->len, GVE_TX_BUF_SIZE_DQO); } else { - if (skb_is_gso(skb)) { - /* If TSO doesn't meet HW requirements, attempt to linearize the - * packet. - */ - if (unlikely(!gve_can_send_tso(skb) && - skb_linearize(skb) < 0)) { - net_err_ratelimited("%s: Failed to transmit TSO packet\n", - priv->dev->name); - goto drop; - } - - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) - goto drop; - - num_buffer_descs = gve_num_buffer_descs_needed(skb); - } else { - num_buffer_descs = gve_num_buffer_descs_needed(skb); - + num_buffer_descs = gve_num_buffer_descs_needed(skb); + if (!skb_is_gso(skb)) { if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) { if (unlikely(skb_linearize(skb) < 0)) goto drop; From 27832a9baad58144e184fd8f38260dc9404105e7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:26:26 +0200 Subject: [PATCH 0773/7721] dt-bindings: crypto: qcom,inline-crypto-engine: document the SM8650 ICE Document the Inline Crypto Engine (ICE) on the SM8650 Platform. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index ca4f7d1cefaa..09e43157cc71 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -16,6 +16,7 @@ properties: - qcom,sa8775p-inline-crypto-engine - qcom,sm8450-inline-crypto-engine - qcom,sm8550-inline-crypto-engine + - qcom,sm8650-inline-crypto-engine - const: qcom,inline-crypto-engine reg: From 8c74562b7104bf46304cc6ce476631e3da8ddf74 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:28:22 +0200 Subject: [PATCH 0774/7721] dt-bindings: crypto: qcom-qce: document the SM8650 crypto engine Document the crypto engine on the SM8650 Platform. Signed-off-by: Neil Armstrong Acked-by: Rob Herring Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index 8e665d910e6e..eeb8a956d7cb 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -48,6 +48,7 @@ properties: - qcom,sm8350-qce - qcom,sm8450-qce - qcom,sm8550-qce + - qcom,sm8650-qce - const: qcom,sm8150-qce - const: qcom,qce From 03f8f3cb6e2280866a9d53b77b6ee1c1b9ffb2a4 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:28:54 +0200 Subject: [PATCH 0775/7721] dt-bindings: crypto: qcom,prng: document SM8650 Document SM8650 compatible for the True Random Number Generator. Signed-off-by: Neil Armstrong Acked-by: Rob Herring Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom,prng.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index 13070db0f70c..89c88004b41b 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -21,6 +21,7 @@ properties: - qcom,sc7280-trng - qcom,sm8450-trng - qcom,sm8550-trng + - qcom,sm8650-trng - const: qcom,trng reg: From 239e27a983316e4746e2ad45ba65fafaf3bbc15d Mon Sep 17 00:00:00 2001 From: Sagar Vashnav Date: Wed, 25 Oct 2023 08:57:07 -0400 Subject: [PATCH 0776/7721] crypto: lib/aesgcm - Add kernel docs for aesgcm_mac Add kernel documentation for the aesgcm_mac. This function generates the authentication tag using the AES-GCM algorithm. Signed-off-by: Sagar Vashnav Signed-off-by: Herbert Xu --- lib/crypto/aesgcm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/crypto/aesgcm.c b/lib/crypto/aesgcm.c index c632d6e17af8..6bba6473fdf3 100644 --- a/lib/crypto/aesgcm.c +++ b/lib/crypto/aesgcm.c @@ -73,6 +73,19 @@ static void aesgcm_ghash(be128 *ghash, const be128 *key, const void *src, } } +/** + * aesgcm_mac - Generates the authentication tag using AES-GCM algorithm. + * @ctx: The data structure that will hold the AES-GCM key schedule + * @src: The input source data. + * @src_len: Length of the source data. + * @assoc: Points to the associated data. + * @assoc_len: Length of the associated data values. + * @ctr: Points to the counter value. + * @authtag: The output buffer for the authentication tag. + * + * It takes in the AES-GCM context, source data, associated data, counter value, + * and an output buffer for the authentication tag. + */ static void aesgcm_mac(const struct aesgcm_ctx *ctx, const u8 *src, int src_len, const u8 *assoc, int assoc_len, __be32 *ctr, u8 *authtag) { From 6d51b9ae4d5e43457f459222d9105e683ae15a0c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 25 Oct 2023 11:20:34 -0500 Subject: [PATCH 0777/7721] hwrng: ingenic - Replace of_device.h with explicit of.h include The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other and pull in various other headers. In preparation to fix this, adjust the includes for what is actually needed. of_device.h isn't needed, but of.h is and was implicitly included by it. Signed-off-by: Rob Herring Signed-off-by: Herbert Xu --- drivers/char/hw_random/ingenic-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/ingenic-rng.c b/drivers/char/hw_random/ingenic-rng.c index 4f18c3fa5427..c74ded64fbe3 100644 --- a/drivers/char/hw_random/ingenic-rng.c +++ b/drivers/char/hw_random/ingenic-rng.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include From 588a90ac252c7cd0434859e749eeed1f8e5a1f90 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 27 Oct 2023 18:25:48 +0800 Subject: [PATCH 0778/7721] crypto: ccree - Silence gcc format-truncation false positive warnings The heuristics used by gcc triggers false positive truncation warnings in hifn_alg_alloc. The warning triggered by the strings here are clearly false positives (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95755). Add checks on snprintf calls to silence these warnings, including the one for cra_driver_name even though it does not currently trigger a gcc warning. Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_aead.c | 10 +++++++--- drivers/crypto/ccree/cc_cipher.c | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index 109ffb375fc6..5ef39d682389 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -2569,9 +2569,13 @@ static struct cc_crypto_alg *cc_create_aead_alg(struct cc_alg_template *tmpl, alg = &tmpl->template_aead; - snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); - snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name); + if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + alg->base.cra_module = THIS_MODULE; alg->base.cra_priority = CC_CRA_PRIO; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index 2cd44d7457a4..d229e54fa935 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -1427,9 +1427,13 @@ static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl, memcpy(alg, &tmpl->template_skcipher, sizeof(*alg)); - snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); - snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name); + if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + alg->base.cra_module = THIS_MODULE; alg->base.cra_priority = CC_CRA_PRIO; alg->base.cra_blocksize = tmpl->blocksize; From 0501d0d14949004301012b82914791937c4fbb25 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 27 Oct 2023 18:35:17 +0800 Subject: [PATCH 0779/7721] crypto: marvell/cesa - Silence gcc format-truncation false positive warnings The heuristics used by gcc triggers false positive truncation warnings in hifn_alg_alloc. The warnings are false positives because nengines is at most 2. Make the buffer bigger and change the snprintf to use unsigned integers to eliminate these warnings. Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa/cesa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c index 5744df30c838..5fd31ba715c2 100644 --- a/drivers/crypto/marvell/cesa/cesa.c +++ b/drivers/crypto/marvell/cesa/cesa.c @@ -488,7 +488,7 @@ static int mv_cesa_probe(struct platform_device *pdev) for (i = 0; i < caps->nengines; i++) { struct mv_cesa_engine *engine = &cesa->engines[i]; - char res_name[7]; + char res_name[16]; engine->id = i; spin_lock_init(&engine->lock); @@ -509,7 +509,7 @@ static int mv_cesa_probe(struct platform_device *pdev) * Not all platforms can gate the CESA clocks: do not complain * if the clock does not exist. */ - snprintf(res_name, sizeof(res_name), "cesa%d", i); + snprintf(res_name, sizeof(res_name), "cesa%u", i); engine->clk = devm_clk_get(dev, res_name); if (IS_ERR(engine->clk)) { engine->clk = devm_clk_get(dev, NULL); @@ -517,7 +517,7 @@ static int mv_cesa_probe(struct platform_device *pdev) engine->clk = NULL; } - snprintf(res_name, sizeof(res_name), "cesaz%d", i); + snprintf(res_name, sizeof(res_name), "cesaz%u", i); engine->zclk = devm_clk_get(dev, res_name); if (IS_ERR(engine->zclk)) engine->zclk = NULL; From 8c20982caca4b10ca79aea8134a16ea98989ca03 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 27 Oct 2023 18:44:34 +0800 Subject: [PATCH 0780/7721] crypto: n2 - Silence gcc format-truncation false positive warnings The heuristics used by gcc triggers false positive truncation warnings in hifn_alg_alloc. Add checks on snprintf calls to silence these warnings, including the one for cra_driver_name even though it does not currently trigger a gcc warning. Signed-off-by: Herbert Xu --- drivers/crypto/n2_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index caea98622c33..37d958cfa9bb 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1382,8 +1382,12 @@ static int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) ahash->setkey = n2_hmac_async_setkey; base = &ahash->halg.base; - snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg); - snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg); + if (snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", + p->child_alg) >= CRYPTO_MAX_ALG_NAME) + goto out_free_p; + if (snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", + p->child_alg) >= CRYPTO_MAX_ALG_NAME) + goto out_free_p; base->cra_ctxsize = sizeof(struct n2_hmac_ctx); base->cra_init = n2_hmac_cra_init; @@ -1394,6 +1398,7 @@ static int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) if (err) { pr_err("%s alg registration failed\n", base->cra_name); list_del(&p->derived.entry); +out_free_p: kfree(p); } else { pr_info("%s alg registered\n", base->cra_name); From 66e6fb1eb972d93c3ab9f27f0c0901b842e1152a Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 28 Oct 2023 18:22:44 +0800 Subject: [PATCH 0781/7721] crypto: hisilicon/qm - print device abnormal information When device is abnormal and reports abnormal interrupt event to driver, the driver can print device information for error analysis. This patch adds some device error-related information output after the device reports an abnormal interrupt. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 18599f3634c3..4d91a249be74 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -129,16 +129,21 @@ #define QM_FIFO_OVERFLOW_TYPE 0xc0 #define QM_FIFO_OVERFLOW_TYPE_SHIFT 6 #define QM_FIFO_OVERFLOW_VF 0x3f +#define QM_FIFO_OVERFLOW_QP_SHIFT 16 #define QM_ABNORMAL_INF01 0x100014 #define QM_DB_TIMEOUT_TYPE 0xc0 #define QM_DB_TIMEOUT_TYPE_SHIFT 6 #define QM_DB_TIMEOUT_VF 0x3f +#define QM_DB_TIMEOUT_QP_SHIFT 16 +#define QM_ABNORMAL_INF02 0x100018 +#define QM_AXI_POISON_ERR BIT(22) #define QM_RAS_CE_ENABLE 0x1000ec #define QM_RAS_FE_ENABLE 0x1000f0 #define QM_RAS_NFE_ENABLE 0x1000f4 #define QM_RAS_CE_THRESHOLD 0x1000f8 #define QM_RAS_CE_TIMES_PER_IRQ 1 #define QM_OOO_SHUTDOWN_SEL 0x1040f8 +#define QM_AXI_RRESP_ERR BIT(0) #define QM_ECC_MBIT BIT(2) #define QM_DB_TIMEOUT BIT(10) #define QM_OF_FIFO_OF BIT(11) @@ -1406,7 +1411,7 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) { const struct hisi_qm_hw_error *err; struct device *dev = &qm->pdev->dev; - u32 reg_val, type, vf_num; + u32 reg_val, type, vf_num, qp_id; int i; for (i = 0; i < ARRAY_SIZE(qm_hw_error); i++) { @@ -1422,19 +1427,24 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) type = (reg_val & QM_DB_TIMEOUT_TYPE) >> QM_DB_TIMEOUT_TYPE_SHIFT; vf_num = reg_val & QM_DB_TIMEOUT_VF; - dev_err(dev, "qm %s doorbell timeout in function %u\n", - qm_db_timeout[type], vf_num); + qp_id = reg_val >> QM_DB_TIMEOUT_QP_SHIFT; + dev_err(dev, "qm %s doorbell timeout in function %u qp %u\n", + qm_db_timeout[type], vf_num, qp_id); } else if (err->int_msk & QM_OF_FIFO_OF) { reg_val = readl(qm->io_base + QM_ABNORMAL_INF00); type = (reg_val & QM_FIFO_OVERFLOW_TYPE) >> QM_FIFO_OVERFLOW_TYPE_SHIFT; vf_num = reg_val & QM_FIFO_OVERFLOW_VF; - + qp_id = reg_val >> QM_FIFO_OVERFLOW_QP_SHIFT; if (type < ARRAY_SIZE(qm_fifo_overflow)) - dev_err(dev, "qm %s fifo overflow in function %u\n", - qm_fifo_overflow[type], vf_num); + dev_err(dev, "qm %s fifo overflow in function %u qp %u\n", + qm_fifo_overflow[type], vf_num, qp_id); else dev_err(dev, "unknown error type\n"); + } else if (err->int_msk & QM_AXI_RRESP_ERR) { + reg_val = readl(qm->io_base + QM_ABNORMAL_INF02); + if (reg_val & QM_AXI_POISON_ERR) + dev_err(dev, "qm axi poison error happened\n"); } } } From a61fb707599e8d26d1b6838021108dbde1a67ce8 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 28 Oct 2023 18:40:11 +0800 Subject: [PATCH 0782/7721] crypto: hisilicon/qm - remove incorrect type cast The 'offset' type is unsigned long in 'struct debugfs_reg32', so type of values casts to unsigned long long is incorrect, and the values do not require type cast, remove them. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/debugfs.c | 50 +++++++++++------------ drivers/crypto/hisilicon/zip/zip_main.c | 54 ++++++++++++------------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 7e8186fe0512..415139b4abc1 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -53,34 +53,34 @@ static struct qm_dfx_item qm_dfx_files[] = { #define CNT_CYC_REGS_NUM 10 static const struct debugfs_reg32 qm_dfx_regs[] = { /* XXX_CNT are reading clear register */ - {"QM_ECC_1BIT_CNT ", 0x104000ull}, - {"QM_ECC_MBIT_CNT ", 0x104008ull}, - {"QM_DFX_MB_CNT ", 0x104018ull}, - {"QM_DFX_DB_CNT ", 0x104028ull}, - {"QM_DFX_SQE_CNT ", 0x104038ull}, - {"QM_DFX_CQE_CNT ", 0x104048ull}, - {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050ull}, - {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058ull}, - {"QM_DFX_ACC_FINISH_CNT ", 0x104060ull}, - {"QM_DFX_CQE_ERR_CNT ", 0x1040b4ull}, - {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, - {"QM_ECC_1BIT_INF ", 0x104004ull}, - {"QM_ECC_MBIT_INF ", 0x10400cull}, - {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0ull}, - {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4ull}, - {"QM_DFX_AXI_RDY_VLD ", 0x1040a8ull}, - {"QM_DFX_FF_ST0 ", 0x1040c8ull}, - {"QM_DFX_FF_ST1 ", 0x1040ccull}, - {"QM_DFX_FF_ST2 ", 0x1040d0ull}, - {"QM_DFX_FF_ST3 ", 0x1040d4ull}, - {"QM_DFX_FF_ST4 ", 0x1040d8ull}, - {"QM_DFX_FF_ST5 ", 0x1040dcull}, - {"QM_DFX_FF_ST6 ", 0x1040e0ull}, - {"QM_IN_IDLE_ST ", 0x1040e4ull}, + {"QM_ECC_1BIT_CNT ", 0x104000}, + {"QM_ECC_MBIT_CNT ", 0x104008}, + {"QM_DFX_MB_CNT ", 0x104018}, + {"QM_DFX_DB_CNT ", 0x104028}, + {"QM_DFX_SQE_CNT ", 0x104038}, + {"QM_DFX_CQE_CNT ", 0x104048}, + {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050}, + {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058}, + {"QM_DFX_ACC_FINISH_CNT ", 0x104060}, + {"QM_DFX_CQE_ERR_CNT ", 0x1040b4}, + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, + {"QM_ECC_1BIT_INF ", 0x104004}, + {"QM_ECC_MBIT_INF ", 0x10400c}, + {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0}, + {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4}, + {"QM_DFX_AXI_RDY_VLD ", 0x1040a8}, + {"QM_DFX_FF_ST0 ", 0x1040c8}, + {"QM_DFX_FF_ST1 ", 0x1040cc}, + {"QM_DFX_FF_ST2 ", 0x1040d0}, + {"QM_DFX_FF_ST3 ", 0x1040d4}, + {"QM_DFX_FF_ST4 ", 0x1040d8}, + {"QM_DFX_FF_ST5 ", 0x1040dc}, + {"QM_DFX_FF_ST6 ", 0x1040e0}, + {"QM_IN_IDLE_ST ", 0x1040e4}, }; static const struct debugfs_reg32 qm_vf_dfx_regs[] = { - {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, }; /* define the QM's dfx regs region and region length */ diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index db4c964cd649..d6672b777efc 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -270,28 +270,28 @@ static const u64 core_offsets[] = { }; static const struct debugfs_reg32 hzip_dfx_regs[] = { - {"HZIP_GET_BD_NUM ", 0x00ull}, - {"HZIP_GET_RIGHT_BD ", 0x04ull}, - {"HZIP_GET_ERROR_BD ", 0x08ull}, - {"HZIP_DONE_BD_NUM ", 0x0cull}, - {"HZIP_WORK_CYCLE ", 0x10ull}, - {"HZIP_IDLE_CYCLE ", 0x18ull}, - {"HZIP_MAX_DELAY ", 0x20ull}, - {"HZIP_MIN_DELAY ", 0x24ull}, - {"HZIP_AVG_DELAY ", 0x28ull}, - {"HZIP_MEM_VISIBLE_DATA ", 0x30ull}, - {"HZIP_MEM_VISIBLE_ADDR ", 0x34ull}, - {"HZIP_CONSUMED_BYTE ", 0x38ull}, - {"HZIP_PRODUCED_BYTE ", 0x40ull}, - {"HZIP_COMP_INF ", 0x70ull}, - {"HZIP_PRE_OUT ", 0x78ull}, - {"HZIP_BD_RD ", 0x7cull}, - {"HZIP_BD_WR ", 0x80ull}, - {"HZIP_GET_BD_AXI_ERR_NUM ", 0x84ull}, - {"HZIP_GET_BD_PARSE_ERR_NUM ", 0x88ull}, - {"HZIP_ADD_BD_AXI_ERR_NUM ", 0x8cull}, - {"HZIP_DECOMP_STF_RELOAD_CURR_ST ", 0x94ull}, - {"HZIP_DECOMP_LZ77_CURR_ST ", 0x9cull}, + {"HZIP_GET_BD_NUM ", 0x00}, + {"HZIP_GET_RIGHT_BD ", 0x04}, + {"HZIP_GET_ERROR_BD ", 0x08}, + {"HZIP_DONE_BD_NUM ", 0x0c}, + {"HZIP_WORK_CYCLE ", 0x10}, + {"HZIP_IDLE_CYCLE ", 0x18}, + {"HZIP_MAX_DELAY ", 0x20}, + {"HZIP_MIN_DELAY ", 0x24}, + {"HZIP_AVG_DELAY ", 0x28}, + {"HZIP_MEM_VISIBLE_DATA ", 0x30}, + {"HZIP_MEM_VISIBLE_ADDR ", 0x34}, + {"HZIP_CONSUMED_BYTE ", 0x38}, + {"HZIP_PRODUCED_BYTE ", 0x40}, + {"HZIP_COMP_INF ", 0x70}, + {"HZIP_PRE_OUT ", 0x78}, + {"HZIP_BD_RD ", 0x7c}, + {"HZIP_BD_WR ", 0x80}, + {"HZIP_GET_BD_AXI_ERR_NUM ", 0x84}, + {"HZIP_GET_BD_PARSE_ERR_NUM ", 0x88}, + {"HZIP_ADD_BD_AXI_ERR_NUM ", 0x8c}, + {"HZIP_DECOMP_STF_RELOAD_CURR_ST ", 0x94}, + {"HZIP_DECOMP_LZ77_CURR_ST ", 0x9c}, }; static const struct debugfs_reg32 hzip_com_dfx_regs[] = { @@ -303,11 +303,11 @@ static const struct debugfs_reg32 hzip_com_dfx_regs[] = { }; static const struct debugfs_reg32 hzip_dump_dfx_regs[] = { - {"HZIP_GET_BD_NUM ", 0x00ull}, - {"HZIP_GET_RIGHT_BD ", 0x04ull}, - {"HZIP_GET_ERROR_BD ", 0x08ull}, - {"HZIP_DONE_BD_NUM ", 0x0cull}, - {"HZIP_MAX_DELAY ", 0x20ull}, + {"HZIP_GET_BD_NUM ", 0x00}, + {"HZIP_GET_RIGHT_BD ", 0x04}, + {"HZIP_GET_ERROR_BD ", 0x08}, + {"HZIP_DONE_BD_NUM ", 0x0c}, + {"HZIP_MAX_DELAY ", 0x20}, }; /* define the ZIP's dfx regs region and region length */ From 84d0217336d76fc4ba5dcd71ca195f4dc71c1d4d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 28 Oct 2023 21:56:13 -0700 Subject: [PATCH 0783/7721] crypto: sun8i-ss - use crypto_shash_tfm_digest() in sun8i_ss_hashkey() Simplify sun8i_ss_hashkey() by using crypto_shash_tfm_digest() instead of an alloc+init+update+final sequence. This should also improve performance. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- .../crypto/allwinner/sun8i-ss/sun8i-ss-hash.c | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c index d70b105dcfa1..753f67a36dc5 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -30,33 +30,16 @@ static int sun8i_ss_hashkey(struct sun8i_ss_hash_tfm_ctx *tfmctx, const u8 *key, unsigned int keylen) { struct crypto_shash *xtfm; - struct shash_desc *sdesc; - size_t len; - int ret = 0; + int ret; xtfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(xtfm)) return PTR_ERR(xtfm); - len = sizeof(*sdesc) + crypto_shash_descsize(xtfm); - sdesc = kmalloc(len, GFP_KERNEL); - if (!sdesc) { - ret = -ENOMEM; - goto err_hashkey_sdesc; - } - sdesc->tfm = xtfm; - - ret = crypto_shash_init(sdesc); - if (ret) { - dev_err(tfmctx->ss->dev, "shash init error ret=%d\n", ret); - goto err_hashkey; - } - ret = crypto_shash_finup(sdesc, key, keylen, tfmctx->key); + ret = crypto_shash_tfm_digest(xtfm, key, keylen, tfmctx->key); if (ret) - dev_err(tfmctx->ss->dev, "shash finup error\n"); -err_hashkey: - kfree(sdesc); -err_hashkey_sdesc: + dev_err(tfmctx->ss->dev, "shash digest error ret=%d\n", ret); + crypto_free_shash(xtfm); return ret; } From fea845fd79b534948a707511591c059d293668c1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 28 Oct 2023 22:16:59 -0700 Subject: [PATCH 0784/7721] crypto: shash - don't exclude async statuses from error stats EINPROGRESS and EBUSY have special meaning for async operations. However, shash is always synchronous, so these statuses have no special meaning for shash and don't need to be excluded when handling errors. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/shash.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crypto/shash.c b/crypto/shash.c index d5194221c88c..c3f7f6a25280 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -23,12 +23,8 @@ static inline struct crypto_istat_hash *shash_get_stat(struct shash_alg *alg) static inline int crypto_shash_errstat(struct shash_alg *alg, int err) { - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) + if (IS_ENABLED(CONFIG_CRYPTO_STATS) && err) atomic64_inc(&shash_get_stat(alg)->err_cnt); - return err; } From d872ca165cb67112f2841ef9c37d51ef7e63d1e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 30 Oct 2023 12:02:59 +0300 Subject: [PATCH 0785/7721] crypto: rsa - add a check for allocation failure Static checkers insist that the mpi_alloc() allocation can fail so add a check to prevent a NULL dereference. Small allocations like this can't actually fail in current kernels, but adding a check is very simple and makes the static checkers happy. Fixes: 6637e11e4ad2 ("crypto: rsa - allow only odd e and restrict value in FIPS mode") Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- crypto/rsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/rsa.c b/crypto/rsa.c index c79613cdce6e..b9cd11fb7d36 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -220,6 +220,8 @@ static int rsa_check_exponent_fips(MPI e) } e_max = mpi_alloc(0); + if (!e_max) + return -ENOMEM; mpi_set_bit(e_max, 256); if (mpi_cmp(e, e_max) >= 0) { From 7ee44f1b59df29419e1bfdfd118fbcdd83c5398c Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 30 Oct 2023 14:05:13 +0200 Subject: [PATCH 0786/7721] crypto: drbg - ensure most preferred type is FIPS health checked drbg supports multiple types of drbg, and multiple parameters of each. Health check sanity only checks one drbg of a single type. One can enable all three types of drbg. And instead of checking the most preferred algorithm (last one wins), it is currently checking first one instead. Update ifdef to ensure that healthcheck prefers HMAC, over HASH, over CTR, last one wins, like all other code and functions. This patch updates code from 541af946fe ("crypto: drbg - SP800-90A Deterministic Random Bit Generator"), but is not interesting to cherry-pick for stable updates, because it doesn't affect regular builds, nor has any tangible effect on FIPS certifcation. Signed-off-by: Dimitri John Ledkov Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index e01f8c7769d0..e3baaa5777f9 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -2018,9 +2018,11 @@ static inline int __init drbg_healthcheck_sanity(void) #ifdef CONFIG_CRYPTO_DRBG_CTR drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref, &pr); -#elif defined CONFIG_CRYPTO_DRBG_HASH +#endif +#ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); -#else +#endif +#ifdef CONFIG_CRYPTO_DRBG_HMAC drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref, &pr); #endif From a9dc62988600e57cabcca9b357cde4df8ee61fb5 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 30 Oct 2023 14:05:14 +0200 Subject: [PATCH 0787/7721] crypto: drbg - update FIPS CTR self-checks to aes256 When originally drbg was introduced FIPS self-checks for all types but CTR were using the most preferred parameters for each type of DRBG. Update CTR self-check to use aes256. This patch updates code from 541af946fe ("crypto: drbg - SP800-90A Deterministic Random Bit Generator"), but is not interesting to cherry-pick for stable updates, because it doesn't affect regular builds, nor has any tangible effect on FIPS certifcation. Signed-off-by: Dimitri John Ledkov Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index e3baaa5777f9..52731bc57e70 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1478,8 +1478,8 @@ static int drbg_generate(struct drbg_state *drbg, err = alg_test("drbg_pr_hmac_sha256", "drbg_pr_hmac_sha256", 0, 0); else if (drbg->core->flags & DRBG_CTR) - err = alg_test("drbg_pr_ctr_aes128", - "drbg_pr_ctr_aes128", 0, 0); + err = alg_test("drbg_pr_ctr_aes256", + "drbg_pr_ctr_aes256", 0, 0); else err = alg_test("drbg_pr_sha256", "drbg_pr_sha256", 0, 0); @@ -2017,7 +2017,7 @@ static inline int __init drbg_healthcheck_sanity(void) return 0; #ifdef CONFIG_CRYPTO_DRBG_CTR - drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref, &pr); + drbg_convert_tfm_core("drbg_nopr_ctr_aes256", &coreref, &pr); #endif #ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); From dd9af7046d815a4d6ee77c2958d98de2af294309 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 30 Oct 2023 14:05:15 +0200 Subject: [PATCH 0788/7721] crypto: drbg - ensure drbg hmac sha512 is used in FIPS selftests Update code comment, self test & healthcheck to use HMAC SHA512, instead of HMAC SHA256. These changes are in dead-code, or FIPS enabled code-paths only and have not effect on usual kernel builds. On systems booting in FIPS mode that has the effect of switch sanity selftest to HMAC sha512 based (which has been the default DRBG). This patch updates code from 9b7b94683a ("crypto: DRBG - switch to HMAC SHA512 DRBG as default DRBG"), but is not interesting to cherry-pick for stable updates, because it doesn't affect regular builds, nor has any tangible effect on FIPS certifcation. Signed-off-by: Dimitri John Ledkov Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 52731bc57e70..9ac034bb23fa 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -111,9 +111,9 @@ * as stdrng. Each DRBG receives an increasing cra_priority values the later * they are defined in this array (see drbg_fill_array). * - * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and - * the SHA256 / AES 256 over other ciphers. Thus, the favored - * DRBGs are the latest entries in this array. + * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and the + * HMAC-SHA512 / SHA256 / AES 256 over other ciphers. Thus, the + * favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { #ifdef CONFIG_CRYPTO_DRBG_CTR @@ -1475,8 +1475,8 @@ static int drbg_generate(struct drbg_state *drbg, int err = 0; pr_devel("DRBG: start to perform self test\n"); if (drbg->core->flags & DRBG_HMAC) - err = alg_test("drbg_pr_hmac_sha256", - "drbg_pr_hmac_sha256", 0, 0); + err = alg_test("drbg_pr_hmac_sha512", + "drbg_pr_hmac_sha512", 0, 0); else if (drbg->core->flags & DRBG_CTR) err = alg_test("drbg_pr_ctr_aes256", "drbg_pr_ctr_aes256", 0, 0); @@ -2023,7 +2023,7 @@ static inline int __init drbg_healthcheck_sanity(void) drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); #endif #ifdef CONFIG_CRYPTO_DRBG_HMAC - drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref, &pr); + drbg_convert_tfm_core("drbg_nopr_hmac_sha512", &coreref, &pr); #endif drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); From bc197f5760025b61a33565301f4390886e0483db Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 30 Oct 2023 14:05:16 +0200 Subject: [PATCH 0789/7721] crypto: drbg - Remove SHA1 from drbg SP800-90C 3rd draft states that SHA-1 will be removed from all specifications, including drbg by end of 2030. Given kernels built today will be operating past that date, start complying with upcoming requirements. No functional change, as SHA-256 / SHA-512 based DRBG have always been the preferred ones. Signed-off-by: Dimitri John Ledkov Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 16 ---------------- crypto/testmgr.c | 25 ++++--------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 9ac034bb23fa..3addce90930c 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -139,12 +139,6 @@ static const struct drbg_core drbg_cores[] = { #endif /* CONFIG_CRYPTO_DRBG_CTR */ #ifdef CONFIG_CRYPTO_DRBG_HASH { - .flags = DRBG_HASH | DRBG_STRENGTH128, - .statelen = 55, /* 440 bits */ - .blocklen_bytes = 20, - .cra_name = "sha1", - .backend_cra_name = "sha1", - }, { .flags = DRBG_HASH | DRBG_STRENGTH256, .statelen = 111, /* 888 bits */ .blocklen_bytes = 48, @@ -166,12 +160,6 @@ static const struct drbg_core drbg_cores[] = { #endif /* CONFIG_CRYPTO_DRBG_HASH */ #ifdef CONFIG_CRYPTO_DRBG_HMAC { - .flags = DRBG_HMAC | DRBG_STRENGTH128, - .statelen = 20, /* block length of cipher */ - .blocklen_bytes = 20, - .cra_name = "hmac_sha1", - .backend_cra_name = "hmac(sha1)", - }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ .blocklen_bytes = 48, @@ -648,8 +636,6 @@ MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384"); MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, @@ -768,8 +754,6 @@ MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha1"); /* * Increment buffer diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 15c7a3011269..59f0540d442e 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4845,14 +4845,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_ctr_aes256_tv_template) } - }, { - /* - * There is no need to specifically test the DRBG with every - * backend cipher -- covered by drbg_nopr_hmac_sha256 test - */ - .alg = "drbg_nopr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_nopr_hmac_sha256", .test = alg_test_drbg, @@ -4861,7 +4853,10 @@ static const struct alg_test_desc alg_test_descs[] = { .drbg = __VECS(drbg_nopr_hmac_sha256_tv_template) } }, { - /* covered by drbg_nopr_hmac_sha256 test */ + /* + * There is no need to specifically test the DRBG with every + * backend cipher -- covered by drbg_nopr_hmac_sha512 test + */ .alg = "drbg_nopr_hmac_sha384", .test = alg_test_null, }, { @@ -4871,10 +4866,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_nopr_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_nopr_sha256", .test = alg_test_drbg, @@ -4906,10 +4897,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_ctr_aes256", .fips_allowed = 1, .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, @@ -4925,10 +4912,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_hmac_sha512", .test = alg_test_null, .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_sha256", .test = alg_test_drbg, From e53c741303a59ee1682e11f61b7772863e02526d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 31 Oct 2023 11:58:32 +0300 Subject: [PATCH 0790/7721] crypto: qat - prevent underflow in rp2srv_store() The "ring" variable has an upper bounds check but nothing checks for negatives. This code uses kstrtouint() already and it was obviously intended to be declared as unsigned int. Make it so. Fixes: dbc8876dd873 ("crypto: qat - add rp2svc sysfs attribute") Signed-off-by: Dan Carpenter Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c index ddffc98119c6..6f0b3629da13 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c @@ -242,7 +242,8 @@ static ssize_t rp2srv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adf_accel_dev *accel_dev; - int ring, num_rings, ret; + int num_rings, ret; + unsigned int ring; accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); if (!accel_dev) From 20342e3f64fb8eea86e490f57a3c0a4ace4284c1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 31 Oct 2023 20:17:24 -0700 Subject: [PATCH 0791/7721] crypto: x86/sha1 - autoload if SHA-NI detected The x86 SHA-1 module contains four implementations: SSSE3, AVX, AVX2, and SHA-NI. Commit 1c43c0f1f84a ("crypto: x86/sha - load modules based on CPU features") made the module be autoloaded when SSSE3, AVX, or AVX2 is detected. The omission of SHA-NI appears to be an oversight, perhaps because of the outdated file-level comment. This patch fixes this, though in practice this makes no difference because SSSE3 is a subset of the other three features anyway. Indeed, sha1_ni_transform() executes SSSE3 instructions such as pshufb. Reviewed-by: Roxana Nicolescu Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/x86/crypto/sha1_ssse3_glue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c index 959afa705e95..ab8bc54f254d 100644 --- a/arch/x86/crypto/sha1_ssse3_glue.c +++ b/arch/x86/crypto/sha1_ssse3_glue.c @@ -2,8 +2,8 @@ /* * Cryptographic API. * - * Glue code for the SHA1 Secure Hash Algorithm assembler implementation using - * Supplemental SSE3 instructions. + * Glue code for the SHA1 Secure Hash Algorithm assembler implementations + * using SSSE3, AVX, AVX2, and SHA-NI instructions. * * This file is based on sha1_generic.c * @@ -28,6 +28,9 @@ #include static const struct x86_cpu_id module_cpu_ids[] = { +#ifdef CONFIG_AS_SHA1_NI + X86_MATCH_FEATURE(X86_FEATURE_SHA_NI, NULL), +#endif X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), From ba5a434d5a1e799defd964537bdd406318ef5f7d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 31 Oct 2023 20:18:11 -0700 Subject: [PATCH 0792/7721] crypto: x86/sha256 - autoload if SHA-NI detected The x86 SHA-256 module contains four implementations: SSSE3, AVX, AVX2, and SHA-NI. Commit 1c43c0f1f84a ("crypto: x86/sha - load modules based on CPU features") made the module be autoloaded when SSSE3, AVX, or AVX2 is detected. The omission of SHA-NI appears to be an oversight, perhaps because of the outdated file-level comment. This patch fixes this, though in practice this makes no difference because SSSE3 is a subset of the other three features anyway. Indeed, sha256_ni_transform() executes SSSE3 instructions such as pshufb. Reviewed-by: Roxana Nicolescu Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/x86/crypto/sha256_ssse3_glue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 4c0383a90e11..e04a43d9f7d5 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -1,8 +1,8 @@ /* * Cryptographic API. * - * Glue code for the SHA256 Secure Hash Algorithm assembler - * implementation using supplemental SSE3 / AVX / AVX2 instructions. + * Glue code for the SHA256 Secure Hash Algorithm assembler implementations + * using SSSE3, AVX, AVX2, and SHA-NI instructions. * * This file is based on sha256_generic.c * @@ -45,6 +45,9 @@ asmlinkage void sha256_transform_ssse3(struct sha256_state *state, const u8 *data, int blocks); static const struct x86_cpu_id module_cpu_ids[] = { +#ifdef CONFIG_AS_SHA256_NI + X86_MATCH_FEATURE(X86_FEATURE_SHA_NI, NULL), +#endif X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), From d57343022b71b9f41e731282dbe0baf0cff6ada8 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Thu, 9 Nov 2023 15:32:59 +0900 Subject: [PATCH 0793/7721] crypto: jh7110 - Correct deferred probe return This fixes list_add corruption error when the driver is returned with -EPROBE_DEFER. It is also required to roll back the previous probe sequences in case of deferred_probe. So, this removes 'err_probe_defer" goto label and just use err_dma_init instead. Fixes: 42ef0e944b01 ("crypto: starfive - Add crypto engine support") Signed-off-by: Chanho Park Reviewed-by: Jia Jie Ho Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-cryp.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index 08e974e0dd12..3a67ddc4d936 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -180,12 +180,8 @@ static int starfive_cryp_probe(struct platform_device *pdev) spin_unlock(&dev_list.lock); ret = starfive_dma_init(cryp); - if (ret) { - if (ret == -EPROBE_DEFER) - goto err_probe_defer; - else - goto err_dma_init; - } + if (ret) + goto err_dma_init; /* Initialize crypto engine */ cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); @@ -233,7 +229,7 @@ static int starfive_cryp_probe(struct platform_device *pdev) tasklet_kill(&cryp->aes_done); tasklet_kill(&cryp->hash_done); -err_probe_defer: + return ret; } From 7c18e3c6b309aebc0fde38bda5ff30ea22c8a56c Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 12 Nov 2023 17:52:41 +0100 Subject: [PATCH 0794/7721] hwrng: virtio - remove #ifdef guards for PM functions Use pm_sleep_ptr for the freeze and restore functions instead of putting them under #ifdef CONFIG_PM_SLEEP. The resulting code is slightly simpler. pm_sleep_ptr lets the compiler see the functions but also allows removing them as unused code if !CONFIG_PM_SLEEP. Signed-off-by: Martin Kaiser Signed-off-by: Herbert Xu --- drivers/char/hw_random/virtio-rng.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index e41a84e6b4b5..58d92d62ddfe 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -208,7 +208,6 @@ static void virtrng_scan(struct virtio_device *vdev) vi->hwrng_register_done = true; } -#ifdef CONFIG_PM_SLEEP static int virtrng_freeze(struct virtio_device *vdev) { remove_common(vdev); @@ -238,7 +237,6 @@ static int virtrng_restore(struct virtio_device *vdev) return err; } -#endif static const struct virtio_device_id id_table[] = { { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, @@ -252,10 +250,8 @@ static struct virtio_driver virtio_rng_driver = { .probe = virtrng_probe, .remove = virtrng_remove, .scan = virtrng_scan, -#ifdef CONFIG_PM_SLEEP - .freeze = virtrng_freeze, - .restore = virtrng_restore, -#endif + .freeze = pm_sleep_ptr(virtrng_freeze), + .restore = pm_sleep_ptr(virtrng_restore), }; module_virtio_driver(virtio_rng_driver); From 9a626c1f36cfc409707528b53e36069c46aa5a9f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 14 Nov 2023 17:55:28 +0200 Subject: [PATCH 0795/7721] drm/i915/display: keep struct intel_display members sorted Like the comment says, /* Grouping using anonymous structs. Keep sorted. */ Stick to it. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231114155528.96935-1-jani.nikula@intel.com --- .../gpu/drm/i915/display/intel_display_core.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index f2c84ae52217..3308f07968ff 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -345,15 +345,6 @@ struct intel_display { struct intel_global_obj obj; } dbuf; - struct { - wait_queue_head_t waitqueue; - - /* mutex to protect pmdemand programming sequence */ - struct mutex lock; - - struct intel_global_obj obj; - } pmdemand; - struct { /* * dkl.phy_lock protects against concurrent access of the @@ -441,6 +432,15 @@ struct intel_display { bool false_color; } ips; + struct { + wait_queue_head_t waitqueue; + + /* mutex to protect pmdemand programming sequence */ + struct mutex lock; + + struct intel_global_obj obj; + } pmdemand; + struct { struct i915_power_domains domains; From 9d6953335284fc37f25bf8488a15ee9444198248 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 14 Nov 2023 12:45:32 +0200 Subject: [PATCH 0796/7721] drm/i915: move *_crtc_clock_get() to intel_dpll.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Considering what the functions do, intel_dpll.c is a more suitable location, and lets us make some functions static while at it. This also means intel_display.c no longer does any DPIO access. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231114104534.4180144-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 171 ----------------- drivers/gpu/drm/i915/display/intel_display.h | 2 - drivers/gpu/drm/i915/display/intel_dpll.c | 175 +++++++++++++++++- drivers/gpu/drm/i915/display/intel_dpll.h | 9 +- .../gpu/drm/i915/display/intel_pch_display.c | 1 + 5 files changed, 181 insertions(+), 177 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 125903007a29..959db3f61e84 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -73,7 +73,6 @@ #include "intel_dp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" -#include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_dpt.h" @@ -2859,67 +2858,6 @@ static void i9xx_get_pfit_config(struct intel_crtc_state *crtc_state) intel_de_read(dev_priv, PFIT_PGM_RATIOS); } -static void vlv_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - struct dpll clock; - u32 mdiv; - int refclk = 100000; - - /* In case of DSI, DPLL will not be used */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); - vlv_dpio_put(dev_priv); - - clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; - clock.m2 = mdiv & DPIO_M2DIV_MASK; - clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; - clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; - clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - - pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); -} - -static void chv_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - struct dpll clock; - u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; - int refclk = 100000; - - /* In case of DSI, DPLL will not be used */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port)); - pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); - pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); - pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); - pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); - vlv_dpio_put(dev_priv); - - clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; - clock.m2 = (pll_dw0 & 0xff) << 22; - if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) - clock.m2 |= pll_dw2 & 0x3fffff; - clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; - clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; - clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; - - pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); -} - static enum intel_output_format bdw_get_pipe_misc_output_format(struct intel_crtc *crtc) { @@ -3840,115 +3778,6 @@ bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state) return true; } -static int i9xx_pll_refclk(struct drm_device *dev, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(dev); - u32 dpll = pipe_config->dpll_hw_state.dpll; - - if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) - return dev_priv->display.vbt.lvds_ssc_freq; - else if (HAS_PCH_SPLIT(dev_priv)) - return 120000; - else if (DISPLAY_VER(dev_priv) != 2) - return 96000; - else - return 48000; -} - -/* Returns the clock of the currently programmed mode of the given pipe. */ -void i9xx_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - u32 dpll = pipe_config->dpll_hw_state.dpll; - u32 fp; - struct dpll clock; - int port_clock; - int refclk = i9xx_pll_refclk(dev, pipe_config); - - if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = pipe_config->dpll_hw_state.fp0; - else - fp = pipe_config->dpll_hw_state.fp1; - - clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; - if (IS_PINEVIEW(dev_priv)) { - clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; - clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; - } else { - clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; - clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; - } - - if (DISPLAY_VER(dev_priv) != 2) { - if (IS_PINEVIEW(dev_priv)) - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> - DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); - else - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> - DPLL_FPA01_P1_POST_DIV_SHIFT); - - switch (dpll & DPLL_MODE_MASK) { - case DPLLB_MODE_DAC_SERIAL: - clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? - 5 : 10; - break; - case DPLLB_MODE_LVDS: - clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? - 7 : 14; - break; - default: - drm_dbg_kms(&dev_priv->drm, - "Unknown DPLL mode %08x in programmed " - "mode\n", (int)(dpll & DPLL_MODE_MASK)); - return; - } - - if (IS_PINEVIEW(dev_priv)) - port_clock = pnv_calc_dpll_params(refclk, &clock); - else - port_clock = i9xx_calc_dpll_params(refclk, &clock); - } else { - enum pipe lvds_pipe; - - if (IS_I85X(dev_priv) && - intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) && - lvds_pipe == crtc->pipe) { - u32 lvds = intel_de_read(dev_priv, LVDS); - - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> - DPLL_FPA01_P1_POST_DIV_SHIFT); - - if (lvds & LVDS_CLKB_POWER_UP) - clock.p2 = 7; - else - clock.p2 = 14; - } else { - if (dpll & PLL_P1_DIVIDE_BY_TWO) - clock.p1 = 2; - else { - clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> - DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; - } - if (dpll & PLL_P2_DIVIDE_BY_4) - clock.p2 = 4; - else - clock.p2 = 2; - } - - port_clock = i9xx_calc_dpll_params(refclk, &clock); - } - - /* - * This value includes pixel_multiplier. We will use - * port_clock to compute adjusted_mode.crtc_clock in the - * encoder's get_config() function. - */ - pipe_config->port_clock = port_clock; -} - int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n) { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 6d0636acb725..8548f49e3972 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -481,8 +481,6 @@ void intel_cpu_transcoder_get_m1_n1(struct intel_crtc *crtc, void intel_cpu_transcoder_get_m2_n2(struct intel_crtc *crtc, enum transcoder cpu_transcoder, struct intel_link_m_n *m_n); -void i9xx_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config); int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config); enum intel_display_power_domain intel_port_to_power_domain(struct intel_digital_port *dig_port); diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 509b862f9e60..ac732a3a70a8 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -16,6 +16,7 @@ #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_lvds.h" +#include "intel_lvds_regs.h" #include "intel_panel.h" #include "intel_pps.h" #include "intel_snps_phy.h" @@ -311,7 +312,7 @@ static const struct intel_limit intel_limits_bxt = { * divided-down version of it. */ /* m1 is reserved as 0 in Pineview, n is a ring counter */ -int pnv_calc_dpll_params(int refclk, struct dpll *clock) +static int pnv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; @@ -342,7 +343,7 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock) return clock->dot; } -int vlv_calc_dpll_params(int refclk, struct dpll *clock) +static int vlv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; @@ -368,6 +369,176 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock) return clock->dot; } +static int i9xx_pll_refclk(struct drm_device *dev, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + u32 dpll = pipe_config->dpll_hw_state.dpll; + + if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) + return dev_priv->display.vbt.lvds_ssc_freq; + else if (HAS_PCH_SPLIT(dev_priv)) + return 120000; + else if (DISPLAY_VER(dev_priv) != 2) + return 96000; + else + return 48000; +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + u32 dpll = pipe_config->dpll_hw_state.dpll; + u32 fp; + struct dpll clock; + int port_clock; + int refclk = i9xx_pll_refclk(dev, pipe_config); + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = pipe_config->dpll_hw_state.fp0; + else + fp = pipe_config->dpll_hw_state.fp1; + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + if (IS_PINEVIEW(dev_priv)) { + clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; + clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; + } else { + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + } + + if (DISPLAY_VER(dev_priv) != 2) { + if (IS_PINEVIEW(dev_priv)) + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> + DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); + else + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? + 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? + 7 : 14; + break; + default: + drm_dbg_kms(&dev_priv->drm, + "Unknown DPLL mode %08x in programmed " + "mode\n", (int)(dpll & DPLL_MODE_MASK)); + return; + } + + if (IS_PINEVIEW(dev_priv)) + port_clock = pnv_calc_dpll_params(refclk, &clock); + else + port_clock = i9xx_calc_dpll_params(refclk, &clock); + } else { + enum pipe lvds_pipe; + + if (IS_I85X(dev_priv) && + intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) && + lvds_pipe == crtc->pipe) { + u32 lvds = intel_de_read(dev_priv, LVDS); + + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) + clock.p1 = 2; + else { + clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + } + + port_clock = i9xx_calc_dpll_params(refclk, &clock); + } + + /* + * This value includes pixel_multiplier. We will use + * port_clock to compute adjusted_mode.crtc_clock in the + * encoder's get_config() function. + */ + pipe_config->port_clock = port_clock; +} + +void vlv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + struct dpll clock; + u32 mdiv; + int refclk = 100000; + + /* In case of DSI, DPLL will not be used */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); + vlv_dpio_put(dev_priv); + + clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; + clock.m2 = mdiv & DPIO_M2DIV_MASK; + clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; + clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; + clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; + + pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); +} + +void chv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + enum dpio_channel port = vlv_pipe_to_channel(pipe); + struct dpll clock; + u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; + int refclk = 100000; + + /* In case of DSI, DPLL will not be used */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port)); + pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); + pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); + pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); + pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + vlv_dpio_put(dev_priv); + + clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; + clock.m2 = (pll_dw0 & 0xff) << 22; + if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) + clock.m2 |= pll_dw2 & 0x3fffff; + clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; + clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; + clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; + + pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); +} + /* * Returns whether the given set of divisors are valid for a given refclk with * the given connectors. diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index bbc30542f29f..ac01bb19cc6c 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -20,8 +20,6 @@ int intel_dpll_crtc_compute_clock(struct intel_atomic_state *state, struct intel_crtc *crtc); int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc); -int vlv_calc_dpll_params(int refclk, struct dpll *clock); -int pnv_calc_dpll_params(int refclk, struct dpll *clock); int i9xx_calc_dpll_params(int refclk, struct dpll *clock); u32 i9xx_dpll_compute_fp(const struct dpll *dpll); void vlv_compute_dpll(struct intel_crtc_state *crtc_state); @@ -41,6 +39,13 @@ bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, struct dpll *best_clock); int chv_calc_dpll_params(int refclk, struct dpll *pll_clock); +void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); +void vlv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); +void chv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); + void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe); void assert_pll_disabled(struct drm_i915_private *i915, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c index 866786e6b32f..baf679759e00 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.c +++ b/drivers/gpu/drm/i915/display/intel_pch_display.c @@ -8,6 +8,7 @@ #include "intel_crt.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dpll.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" #include "intel_lvds.h" From 9fda18c2c32a42e6c9fb68893b9628d6a5319555 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 14 Nov 2023 12:45:33 +0200 Subject: [PATCH 0797/7721] drm/i915: add vlv_pipe_to_phy() helper to replace DPIO_PHY() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a helper with better typing and handing for bogus input, and better in line with vlv_dig_port_to_channel(), vlv_dig_port_to_phy(), and vlv_pipe_to_channel(). Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231114104534.4180144-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 14 ++++++++++++++ drivers/gpu/drm/i915/display/intel_dpio_phy.h | 5 +++++ drivers/gpu/drm/i915/display/intel_pps.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 2 -- drivers/gpu/drm/i915/vlv_sideband.c | 6 ++++-- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 62b93d097e44..d6af46e33424 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -666,6 +666,20 @@ enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port) } } +enum dpio_phy vlv_pipe_to_phy(enum pipe pipe) +{ + switch (pipe) { + default: + MISSING_CASE(pipe); + fallthrough; + case PIPE_A: + case PIPE_B: + return DPIO_PHY0; + case PIPE_C: + return DPIO_PHY1; + } +} + enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) { switch (pipe) { diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 4d43dbbdf81c..9adc4e8c1738 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -44,6 +44,7 @@ u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder); enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port); enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port); +enum dpio_phy vlv_pipe_to_phy(enum pipe pipe); enum dpio_channel vlv_pipe_to_channel(enum pipe pipe); void chv_set_phy_signal_level(struct intel_encoder *encoder, @@ -116,6 +117,10 @@ static inline enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_p { return DPIO_PHY0; } +static inline enum dpio_phy vlv_pipe_to_phy(enum pipe pipe) +{ + return DPIO_PHY0; +} static inline enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) { return DPIO_CH0; diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index 73f0f1714b37..a8fa3a20990e 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -90,7 +90,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum pipe pipe = intel_dp->pps.pps_pipe; bool pll_enabled, release_cl_override = false; - enum dpio_phy phy = DPIO_PHY(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); enum dpio_channel ch = vlv_pipe_to_channel(pipe); u32 DP; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 135e8d8dbdf0..27dc903f0553 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -195,8 +195,6 @@ #define DPIO_SFR_BYPASS (1 << 1) #define DPIO_CMNRST (1 << 0) -#define DPIO_PHY(pipe) ((pipe) >> 1) - /* * Per pipe/PLL DPIO regs */ diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c index b98dec3ad817..f7df55217845 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.c +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -229,7 +229,8 @@ static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy p u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) { - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); + u32 port = vlv_dpio_phy_iosf_port(i915, phy); u32 val = 0; vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); @@ -248,7 +249,8 @@ u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) void vlv_dpio_write(struct drm_i915_private *i915, enum pipe pipe, int reg, u32 val) { - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); + u32 port = vlv_dpio_phy_iosf_port(i915, phy); vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); } From f70a68bc1d18b7af52d368b80d1d0fed747ef2a9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 14 Nov 2023 12:45:34 +0200 Subject: [PATCH 0798/7721] drm/i915: convert vlv_dpio_read()/write() from pipe to phy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vlv_dpio_read() and vlv_dpio_write() really operate on the phy, not pipe. Passing the pipe instead of the phy as parameter is supposed to be a convenience, but when the caller has the phy, it becomes an inconvenience. See e.g. chv_dpio_cmn_power_well_enable() and assert_chv_phy_powergate(). Figure out the phy in the callers, and pass phy to the dpio functions. v2: retract one overzealous pipe->phy change (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231114104534.4180144-3-jani.nikula@intel.com --- .../i915/display/intel_display_power_well.c | 23 +-- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 157 +++++++++--------- drivers/gpu/drm/i915/display/intel_dpll.c | 106 ++++++------ drivers/gpu/drm/i915/vlv_sideband.c | 10 +- drivers/gpu/drm/i915/vlv_sideband.h | 6 +- 5 files changed, 151 insertions(+), 151 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 07d650050099..47cd6bb04366 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -1400,20 +1400,16 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, { enum i915_power_well_id id = i915_power_well_instance(power_well)->id; enum dpio_phy phy; - enum pipe pipe; u32 tmp; drm_WARN_ON_ONCE(&dev_priv->drm, id != VLV_DISP_PW_DPIO_CMN_BC && id != CHV_DISP_PW_DPIO_CMN_D); - if (id == VLV_DISP_PW_DPIO_CMN_BC) { - pipe = PIPE_A; + if (id == VLV_DISP_PW_DPIO_CMN_BC) phy = DPIO_PHY0; - } else { - pipe = PIPE_C; + else phy = DPIO_PHY1; - } /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -1428,24 +1424,24 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, vlv_dpio_get(dev_priv); /* Enable dynamic power down */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW28); tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN | DPIO_SUS_CLK_CONFIG_GATE_CLKREQ; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW28, tmp); if (id == VLV_DISP_PW_DPIO_CMN_BC) { - tmp = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW6_CH1); + tmp = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW6_CH1); tmp |= DPIO_DYNPWRDOWNEN_CH1; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW6_CH1, tmp); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW6_CH1, tmp); } else { /* * Force the non-existing CL2 off. BXT does this * too, so maybe it saves some power even though * CL2 doesn't exist? */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW30); tmp |= DPIO_CL2_LDOFUSE_PWRENB; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW30, tmp); } vlv_dpio_put(dev_priv); @@ -1499,7 +1495,6 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpio_phy phy, enum dpio_channel ch, bool override, unsigned int mask) { - enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C; u32 reg, val, expected, actual; /* @@ -1518,7 +1513,7 @@ static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpi reg = _CHV_CMN_DW6_CH1; vlv_dpio_get(dev_priv); - val = vlv_dpio_read(dev_priv, pipe, reg); + val = vlv_dpio_read(dev_priv, phy, reg); vlv_dpio_put(dev_priv); /* diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index d6af46e33424..4ca910874a4f 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -703,50 +703,50 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 val; int i; vlv_dpio_get(dev_priv); /* Clear calc init */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW10(ch), val); } - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW9(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW9(ch), val); } /* Program swing deemph */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW4(ch, i)); val &= ~DPIO_SWING_DEEMPH9P5_MASK; val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW4(ch, i), val); } /* Program swing margin */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW2(ch, i)); val &= ~DPIO_SWING_MARGIN000_MASK; val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT; @@ -759,7 +759,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT); val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW2(ch, i), val); } /* @@ -769,23 +769,23 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, * 27 for ch0 and ch1. */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW3(ch, i)); if (uniq_trans_scale) val |= DPIO_TX_UNIQ_TRANS_SCALE_EN; else val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW3(ch, i), val); } /* Start swing calculation */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW10(ch), val); } vlv_dpio_put(dev_priv); @@ -796,43 +796,43 @@ void chv_data_lane_soft_reset(struct intel_encoder *encoder, bool reset) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum dpio_channel ch = vlv_dig_port_to_channel(enc_to_dig_port(encoder)); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - enum pipe pipe = crtc->pipe; + enum dpio_channel ch = vlv_dig_port_to_channel(enc_to_dig_port(encoder)); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 val; - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW0(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW0(ch), val); } - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW1(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW1(ch), val); } } @@ -843,6 +843,7 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); enum pipe pipe = crtc->pipe; unsigned int lane_mask = intel_dp_unused_lane_mask(crtc_state->lane_count); @@ -865,40 +866,40 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, /* program left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA1_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA1_FORCE; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA2_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA2_FORCE; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW1_CH1, val); } /* program clock channel usage */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW8(ch)); val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe != PIPE_B) val &= ~CHV_PCS_USEDCLKCHANNEL; else val |= CHV_PCS_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW8(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW8(ch)); val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe != PIPE_B) val &= ~CHV_PCS_USEDCLKCHANNEL; else val |= CHV_PCS_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW8(ch), val); } /* @@ -906,12 +907,12 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, * matches the pipe, but here we need to * pick the CL based on the port. */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch)); + val = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW19(ch)); if (pipe != PIPE_B) val &= ~CHV_CMN_USEDCLKCHANNEL; else val |= CHV_CMN_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW19(ch), val); vlv_dpio_put(dev_priv); } @@ -924,21 +925,21 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); int data, i, stagger; u32 val; vlv_dpio_get(dev_priv); /* allow hardware to manage TX FIFO reset source */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW11(ch), val); } /* Program Tx lane latency optimal setting*/ @@ -948,7 +949,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, data = 0x0; else data = (i == 1) ? 0x0 : 0x1; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), + vlv_dpio_write(dev_priv, phy, CHV_TX_DW14(ch, i), data << DPIO_UPAR_SHIFT); } @@ -964,17 +965,17 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, else stagger = 0x2; - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW11(ch), val); } - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -982,7 +983,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, DPIO_TX2_STAGGER_MULT(0)); if (crtc_state->lane_count > 2) { - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -1012,19 +1013,20 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum pipe pipe = to_intel_crtc(old_crtc_state->uapi.crtc)->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; vlv_dpio_get(dev_priv); /* disable left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW1_CH1, val); } vlv_dpio_put(dev_priv); @@ -1050,22 +1052,22 @@ void vlv_set_phy_signal_level(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), + vlv_dpio_write(dev_priv, phy, VLV_TX_DW5(port), 0x00000000); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW4(port), demph_reg_value); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW2(port), uniqtranscale_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW3(port), 0x0C782040); if (tx3_demph) - vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), tx3_demph); + vlv_dpio_write(dev_priv, phy, VLV_TX3_DW4(port), tx3_demph); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW9(port), preemph_reg_value); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); vlv_dpio_put(dev_priv); } @@ -1077,24 +1079,24 @@ void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); /* Program Tx lane resets to default */ vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; vlv_dpio_get(dev_priv); /* Enable clock channels for this port */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW8(port), val); /* Program lane clock */ - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW23(port), 0x00400888); vlv_dpio_put(dev_priv); } @@ -1136,10 +1139,10 @@ void vlv_phy_reset_lanes(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW0(port), 0x00000000); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW1(port), 0x00e00060); vlv_dpio_put(dev_priv); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index ac732a3a70a8..3038655377ea 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -483,7 +483,7 @@ void vlv_crtc_clock_get(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); struct dpll clock; u32 mdiv; int refclk = 100000; @@ -493,7 +493,7 @@ void vlv_crtc_clock_get(struct intel_crtc *crtc, return; vlv_dpio_get(dev_priv); - mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); + mdiv = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW3(crtc->pipe)); vlv_dpio_put(dev_priv); clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; @@ -510,8 +510,8 @@ void chv_crtc_clock_get(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_channel port = vlv_pipe_to_channel(crtc->pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); struct dpll clock; u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; int refclk = 100000; @@ -521,11 +521,11 @@ void chv_crtc_clock_get(struct intel_crtc *crtc, return; vlv_dpio_get(dev_priv); - cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port)); - pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); - pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); - pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); - pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + cmn_dw13 = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW13(port)); + pll_dw0 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW0(port)); + pll_dw1 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW1(port)); + pll_dw2 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW2(port)); + pll_dw3 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW3(port)); vlv_dpio_put(dev_priv); clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; @@ -1811,7 +1811,7 @@ void i9xx_enable_pll(const struct intel_crtc_state *crtc_state) } static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, - enum pipe pipe) + enum dpio_phy phy) { u32 reg_val; @@ -1819,30 +1819,31 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0x8c000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + vlv_dpio_write(dev_priv, phy, VLV_REF_DW13, reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + vlv_dpio_write(dev_priv, phy, VLV_REF_DW13, reg_val); } static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); enum pipe pipe = crtc->pipe; u32 mdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; @@ -1860,18 +1861,18 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) /* PLL B needs special handling */ if (pipe == PIPE_B) - vlv_pllb_recal_opamp(dev_priv, pipe); + vlv_pllb_recal_opamp(dev_priv, phy); /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW8(pipe)); reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW8(pipe), reg_val); /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); + vlv_dpio_write(dev_priv, phy, VLV_CMN_DW0, 0x610); /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); @@ -1885,46 +1886,46 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) * Note: don't use the DAC post divider as it seems unstable. */ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW3(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW3(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ if (crtc_state->port_clock == 162000 || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG) || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW10(pipe), 0x009f0003); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW10(pipe), 0x00d0000f); if (intel_crtc_has_dp_encoder(crtc_state)) { /* Use SSC source */ if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df40000); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df70000); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df40000); } - coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); + coreclk = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW7(pipe)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_crtc_has_dp_encoder(crtc_state)) coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW7(pipe), coreclk); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW11(pipe), 0x87871000); vlv_dpio_put(dev_priv); } @@ -1975,6 +1976,7 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 loopfilter, tribuf_calcntr; u32 bestm2, bestp1, bestp2, bestm2_frac; u32 dpio_val; @@ -1991,39 +1993,39 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) vlv_dpio_get(dev_priv); /* p1 and p2 divider */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW13(port), 5 << DPIO_CHV_S1_DIV_SHIFT | bestp1 << DPIO_CHV_P1_DIV_SHIFT | bestp2 << DPIO_CHV_P2_DIV_SHIFT | 1 << DPIO_CHV_K_DIV_SHIFT); /* Feedback post-divider - m2 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW0(port), bestm2); /* Feedback refclk divider - n and m1 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW1(port), DPIO_CHV_M1_DIV_BY_2 | 1 << DPIO_CHV_N_DIV_SHIFT); /* M2 fraction division */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW2(port), bestm2_frac); /* M2 fraction division enable */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW3(port)); dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); if (bestm2_frac) dpio_val |= DPIO_CHV_FRAC_DIV_EN; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW3(port), dpio_val); /* Program digital lock detect threshold */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW9(port)); dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); if (!bestm2_frac) dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW9(port), dpio_val); /* Loop filter */ if (vco == 5400000) { @@ -2048,16 +2050,16 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); tribuf_calcntr = 0; } - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW6(port), loopfilter); - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW8(port)); dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW8(port), dpio_val); /* AFC Recal */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), - vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), + vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)) | DPIO_AFC_RECAL); vlv_dpio_put(dev_priv); @@ -2069,14 +2071,15 @@ static void _chv_enable_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 tmp; vlv_dpio_get(dev_priv); /* Enable back the 10bit clock to display controller */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)); tmp |= DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), tmp); vlv_dpio_put(dev_priv); @@ -2197,6 +2200,7 @@ void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; /* Make sure the pipe isn't still relying on us */ @@ -2213,9 +2217,9 @@ void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) vlv_dpio_get(dev_priv); /* Disable 10bit clock to display controller */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + val = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)); val &= ~DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), val); vlv_dpio_put(dev_priv); } diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c index f7df55217845..63a795876309 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.c +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -227,9 +227,8 @@ static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy p return IOSF_PORT_DPIO; } -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) +u32 vlv_dpio_read(struct drm_i915_private *i915, enum dpio_phy phy, int reg) { - enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 port = vlv_dpio_phy_iosf_port(i915, phy); u32 val = 0; @@ -240,16 +239,15 @@ u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) * so ideally we should check the register offset instead... */ drm_WARN(&i915->drm, val == 0xffffffff, - "DPIO read pipe %c reg 0x%x == 0x%x\n", - pipe_name(pipe), reg, val); + "DPIO PHY%d read reg 0x%x == 0x%x\n", + phy, reg, val); return val; } void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val) + enum dpio_phy phy, int reg, u32 val) { - enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 port = vlv_dpio_phy_iosf_port(i915, phy); vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); diff --git a/drivers/gpu/drm/i915/vlv_sideband.h b/drivers/gpu/drm/i915/vlv_sideband.h index 9ce283d96b80..4073966860e2 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.h +++ b/drivers/gpu/drm/i915/vlv_sideband.h @@ -11,7 +11,7 @@ #include "vlv_sideband_reg.h" -enum pipe; +enum dpio_phy; struct drm_i915_private; enum { @@ -75,9 +75,9 @@ static inline void vlv_dpio_get(struct drm_i915_private *i915) vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_DPIO)); } -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg); +u32 vlv_dpio_read(struct drm_i915_private *i915, enum dpio_phy phy, int reg); void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val); + enum dpio_phy phy, int reg, u32 val); static inline void vlv_dpio_put(struct drm_i915_private *i915) { From c8031019dc95e3ab7cc0b09f1894c5f52dc0c187 Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Tue, 10 Oct 2023 07:35:06 -0700 Subject: [PATCH 0799/7721] drm/amdgpu: Implement a new 64bit sequence memory driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Developed a new driver which allocates a 64bit memory on each request in sequence order. At the moment, user queue fence memory is the main consumer of this seq64 driver. v2: Worked on review comments from Christian for the following modifications - Move driver name from "semaphore" to "seq64" - Remove unnecessary PT/PD mapping - Move enable_mes check into init/fini functions. v3: Worked on review comments from Christian - drop enable_mes check - use DECLARE_BITMAP for bit array - added kerneldoc for seq64 v4: Worked on review comments from Christian - Rename amdgpu_seq64_get name with amdgpu_seq64_alloc v5: Worked on review comments from Christian - Fix seq64 lockdep warning - move fpriv->seq64_va check into amdgpu_seq64_unmap() - make the function amdgpu_seq64_unmap() return as void. - reserve the buffers as not interruptible. v6: port to drm_exec (Alex) v7: disable for now (Arun) Signed-off-by: Arunpravin Paneer Selvam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/Makefile | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 7 + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c | 247 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h | 49 ++++ 6 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 2afecc55090f..260e32ef7bae 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -80,7 +80,7 @@ amdgpu-y += amdgpu_device.o amdgpu_doorbell_mgr.o amdgpu_kms.o \ amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o \ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \ - amdgpu_ring_mux.o amdgpu_xcp.o + amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9d92ca157677..4d100f8d75bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -109,6 +109,7 @@ #include "amdgpu_mca.h" #include "amdgpu_ras.h" #include "amdgpu_xcp.h" +#include "amdgpu_seq64.h" #define MAX_GPU_INSTANCE 64 @@ -468,6 +469,7 @@ struct amdgpu_fpriv { struct amdgpu_vm vm; struct amdgpu_bo_va *prt_va; struct amdgpu_bo_va *csa_va; + struct amdgpu_bo_va *seq64_va; struct mutex bo_list_lock; struct idr bo_list_handles; struct amdgpu_ctx_mgr ctx_mgr; @@ -986,6 +988,9 @@ struct amdgpu_device { /* GDS */ struct amdgpu_gds gds; + /* for userq and VM fences */ + struct amdgpu_seq64 seq64; + /* KFD */ struct amdgpu_kfd_dev kfd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 7eeaf0aa7f81..151f8b950b72 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2676,6 +2676,12 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) goto init_failed; } } + + r = amdgpu_seq64_init(adev); + if (r) { + DRM_ERROR("allocate seq64 failed %d\n", r); + goto init_failed; + } } } @@ -3138,6 +3144,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) amdgpu_device_wb_fini(adev); amdgpu_device_mem_scratch_fini(adev); amdgpu_ib_pool_fini(adev); + amdgpu_seq64_fini(adev); } r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 583cf03950cd..b5ebafd4a3ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1428,6 +1428,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, fpriv->csa_va = NULL; } + amdgpu_seq64_unmap(adev, fpriv); + pasid = fpriv->vm.pasid; pd = amdgpu_bo_ref(fpriv->vm.root.bo); if (!WARN_ON(amdgpu_bo_reserve(pd, true))) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c new file mode 100644 index 000000000000..f3de02193138 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "amdgpu.h" +#include "amdgpu_seq64.h" + +#include + +/** + * DOC: amdgpu_seq64 + * + * amdgpu_seq64 allocates a 64bit memory on each request in sequence order. + * seq64 driver is required for user queue fence memory allocation, TLB + * counters and VM updates. It has maximum count of 32768 64 bit slots. + */ + +/** + * amdgpu_seq64_map - Map the seq64 memory to VM + * + * @adev: amdgpu_device pointer + * @vm: vm pointer + * @bo_va: bo_va pointer + * @seq64_addr: seq64 vaddr start address + * @size: seq64 pool size + * + * Map the seq64 memory to the given VM. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct amdgpu_bo_va **bo_va, u64 seq64_addr, + uint32_t size) +{ + struct amdgpu_bo *bo; + struct drm_exec exec; + int r; + + bo = adev->seq64.sbo; + if (!bo) + return -EINVAL; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_until_all_locked(&exec) { + r = amdgpu_vm_lock_pd(vm, &exec, 0); + if (likely(!r)) + r = drm_exec_lock_obj(&exec, &bo->tbo.base); + drm_exec_retry_on_contention(&exec); + if (unlikely(r)) + goto error; + } + + *bo_va = amdgpu_vm_bo_add(adev, vm, bo); + if (!*bo_va) { + r = -ENOMEM; + goto error; + } + + r = amdgpu_vm_bo_map(adev, *bo_va, seq64_addr, 0, size, + AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | + AMDGPU_PTE_EXECUTABLE); + if (r) { + DRM_ERROR("failed to do bo_map on userq sem, err=%d\n", r); + amdgpu_vm_bo_del(adev, *bo_va); + goto error; + } + + r = amdgpu_vm_bo_update(adev, *bo_va, false); + if (r) { + DRM_ERROR("failed to do vm_bo_update on userq sem\n"); + amdgpu_vm_bo_del(adev, *bo_va); + goto error; + } + +error: + drm_exec_fini(&exec); + return r; +} + +/** + * amdgpu_seq64_unmap - Unmap the seq64 memory + * + * @adev: amdgpu_device pointer + * @fpriv: DRM file private + * + * Unmap the seq64 memory from the given VM. + */ +void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv) +{ + struct amdgpu_vm *vm; + struct amdgpu_bo *bo; + struct drm_exec exec; + int r; + + if (!fpriv->seq64_va) + return; + + bo = adev->seq64.sbo; + if (!bo) + return; + + vm = &fpriv->vm; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_until_all_locked(&exec) { + r = amdgpu_vm_lock_pd(vm, &exec, 0); + if (likely(!r)) + r = drm_exec_lock_obj(&exec, &bo->tbo.base); + drm_exec_retry_on_contention(&exec); + if (unlikely(r)) + goto error; + } + + amdgpu_vm_bo_del(adev, fpriv->seq64_va); + + fpriv->seq64_va = NULL; + +error: + drm_exec_fini(&exec); +} + +/** + * amdgpu_seq64_alloc - Allocate a 64 bit memory + * + * @adev: amdgpu_device pointer + * @gpu_addr: allocated gpu VA start address + * @cpu_addr: allocated cpu VA start address + * + * Alloc a 64 bit memory from seq64 pool. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, + u64 **cpu_addr) +{ + unsigned long bit_pos; + u32 offset; + + bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem); + + if (bit_pos < adev->seq64.num_sem) { + __set_bit(bit_pos, adev->seq64.used); + offset = bit_pos << 6; /* convert to qw offset */ + } else { + return -EINVAL; + } + + *gpu_addr = offset + AMDGPU_SEQ64_VADDR_START; + *cpu_addr = offset + adev->seq64.cpu_base_addr; + + return 0; +} + +/** + * amdgpu_seq64_free - Free the given 64 bit memory + * + * @adev: amdgpu_device pointer + * @gpu_addr: gpu start address to be freed + * + * Free the given 64 bit memory from seq64 pool. + * + */ +void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr) +{ + u32 offset; + + offset = gpu_addr - AMDGPU_SEQ64_VADDR_START; + + offset >>= 6; + if (offset < adev->seq64.num_sem) + __clear_bit(offset, adev->seq64.used); +} + +/** + * amdgpu_seq64_fini - Cleanup seq64 driver + * + * @adev: amdgpu_device pointer + * + * Free the memory space allocated for seq64. + * + */ +void amdgpu_seq64_fini(struct amdgpu_device *adev) +{ + amdgpu_bo_free_kernel(&adev->seq64.sbo, + NULL, + (void **)&adev->seq64.cpu_base_addr); +} + +/** + * amdgpu_seq64_init - Initialize seq64 driver + * + * @adev: amdgpu_device pointer + * + * Allocate the required memory space for seq64. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_init(struct amdgpu_device *adev) +{ + int r; + + if (adev->seq64.sbo) + return 0; + + /* + * AMDGPU_MAX_SEQ64_SLOTS * sizeof(u64) * 8 = AMDGPU_MAX_SEQ64_SLOTS + * 64bit slots + */ + r = amdgpu_bo_create_kernel(adev, AMDGPU_SEQ64_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, + &adev->seq64.sbo, NULL, + (void **)&adev->seq64.cpu_base_addr); + if (r) { + dev_warn(adev->dev, "(%d) create seq64 failed\n", r); + return r; + } + + memset(adev->seq64.cpu_base_addr, 0, AMDGPU_SEQ64_SIZE); + + adev->seq64.num_sem = AMDGPU_MAX_SEQ64_SLOTS; + memset(&adev->seq64.used, 0, sizeof(adev->seq64.used)); + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h new file mode 100644 index 000000000000..2196e72be508 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __AMDGPU_SEQ64_H__ +#define __AMDGPU_SEQ64_H__ + +#define AMDGPU_SEQ64_SIZE (2ULL << 20) +#define AMDGPU_MAX_SEQ64_SLOTS (AMDGPU_SEQ64_SIZE / (sizeof(u64) * 8)) +#define AMDGPU_SEQ64_VADDR_OFFSET 0x50000 +#define AMDGPU_SEQ64_VADDR_START (AMDGPU_VA_RESERVED_SIZE + AMDGPU_SEQ64_VADDR_OFFSET) + +struct amdgpu_seq64 { + struct amdgpu_bo *sbo; + u32 num_sem; + u64 *cpu_base_addr; + DECLARE_BITMAP(used, AMDGPU_MAX_SEQ64_SLOTS); +}; + +void amdgpu_seq64_fini(struct amdgpu_device *adev); +int amdgpu_seq64_init(struct amdgpu_device *adev); +int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, u64 **cpu_addr); +void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr); +int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct amdgpu_bo_va **bo_va, u64 seq64_addr, uint32_t size); +void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv); + +#endif + From e6ed364efae39455cb1d6b1895a1d31599608a2b Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Wed, 16 Mar 2022 18:46:56 -0400 Subject: [PATCH 0800/7721] drm/amdgpu: update mappings not managed by KFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When restoring after an eviction, use amdgpu_vm_handle_moved to update BO VA mappings in KFD VMs that are not managed through the KFD API. This should allow using the render node API to create more flexible memory mappings in KFD VMs. v2: rebase on drm_exec changes (Alex) Signed-off-by: Felix Kuehling Acked-by: Christian König Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 41fbc4fd0fac..b98c0969d3be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2825,12 +2825,6 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) if (ret) goto validate_map_fail; - ret = process_sync_pds_resv(process_info, &sync_obj); - if (ret) { - pr_debug("Memory eviction: Failed to sync to PD BO moving fence. Try again\n"); - goto validate_map_fail; - } - /* Validate BOs and map them to GPUVM (update VM page tables). */ list_for_each_entry(mem, &process_info->kfd_bo_list, validate_list) { @@ -2881,6 +2875,19 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) if (failed_size) pr_debug("0x%lx/0x%lx in system\n", failed_size, total_size); + /* Update mappings not managed by KFD */ + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + struct amdgpu_device *adev = amdgpu_ttm_adev( + peer_vm->root.bo->tbo.bdev); + + ret = amdgpu_vm_handle_moved(adev, peer_vm, &exec.ticket); + if (ret) { + pr_debug("Memory eviction: handle moved failed. Try again\n"); + goto validate_map_fail; + } + } + /* Update page directories */ ret = process_update_pds(process_info, &sync_obj); if (ret) { @@ -2888,6 +2895,15 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) goto validate_map_fail; } + /* Sync with fences on all the page tables. They implicitly depend on any + * move fences from amdgpu_vm_handle_moved above. + */ + ret = process_sync_pds_resv(process_info, &sync_obj); + if (ret) { + pr_debug("Memory eviction: Failed to sync to PD BO moving fence. Try again\n"); + goto validate_map_fail; + } + /* Wait for validate and PT updates to finish */ amdgpu_sync_wait(&sync_obj, false); From 94e2dae0a8bfd456abfd866f1eee8342f0858012 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Fri, 24 Feb 2023 18:22:32 -0500 Subject: [PATCH 0801/7721] drm/amdkfd: Move TLB flushing logic into amdgpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make it possible for amdgpu GEM ioctls to flush TLBs on compute VMs. This removes VMID-based TLB flushing and always uses PASID-based flushing. This still works because it scans the VMID-PASID mapping registers to find the right VMID. It's only slightly less efficient. This is not a production use case. Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 29 -------------- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 5 --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 44 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 5 +++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 10 ++++- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 31 --------------- 6 files changed, 57 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index b8412202a1b0..6ab17330a6ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -710,35 +710,6 @@ bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) return false; } -int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct amdgpu_device *adev, - uint16_t vmid) -{ - if (adev->family == AMDGPU_FAMILY_AI) { - int i; - - for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS) - amdgpu_gmc_flush_gpu_tlb(adev, vmid, i, 0); - } else { - amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB(0), 0); - } - - return 0; -} - -int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct amdgpu_device *adev, - uint16_t pasid, - enum TLB_FLUSH_TYPE flush_type, - uint32_t inst) -{ - bool all_hub = false; - - if (adev->family == AMDGPU_FAMILY_AI || - adev->family == AMDGPU_FAMILY_RV) - all_hub = true; - - return amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, flush_type, all_hub, inst); -} - bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev) { return adev->have_atomics_support; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index dac983da961d..16794c2eea35 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -162,11 +162,6 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, uint32_t *ib_cmd, uint32_t ib_len); void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle); bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev); -int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct amdgpu_device *adev, - uint16_t vmid); -int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct amdgpu_device *adev, - uint16_t pasid, enum TLB_FLUSH_TYPE flush_type, - uint32_t inst); bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d1b8afd105c9..d59154ddaaed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1437,6 +1437,50 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, return 0; } +/** + * amdgpu_vm_flush_compute_tlb - Flush TLB on compute VM + * + * @adev: amdgpu_device pointer + * @vm: requested vm + * @flush_type: flush type + * + * Flush TLB if needed for a compute VM. + * + * Returns: + * 0 for success. + */ +int amdgpu_vm_flush_compute_tlb(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + uint32_t flush_type, + uint32_t xcc_mask) +{ + uint64_t tlb_seq = amdgpu_vm_tlb_seq(vm); + bool all_hub = false; + int xcc = 0, r = 0; + + WARN_ON_ONCE(!vm->is_compute_context); + + /* + * It can be that we race and lose here, but that is extremely unlikely + * and the worst thing which could happen is that we flush the changes + * into the TLB once more which is harmless. + */ + if (atomic64_xchg(&vm->kfd_last_flushed_seq, tlb_seq) == tlb_seq) + return 0; + + if (adev->family == AMDGPU_FAMILY_AI || + adev->family == AMDGPU_FAMILY_RV) + all_hub = true; + + for_each_inst(xcc, xcc_mask) { + r = amdgpu_gmc_flush_gpu_tlb_pasid(adev, vm->pasid, flush_type, + all_hub, xcc); + if (r) + break; + } + return r; +} + /** * amdgpu_vm_bo_add - add a bo to a specific vm * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 2cd86d2bf73f..b6cd565562ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -324,6 +324,7 @@ struct amdgpu_vm { /* Last finished delayed update */ atomic64_t tlb_seq; struct dma_fence *last_tlb_flush; + atomic64_t kfd_last_flushed_seq; /* How many times we had to re-generate the page tables */ uint64_t generation; @@ -445,6 +446,10 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, int amdgpu_vm_handle_moved(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket); +int amdgpu_vm_flush_compute_tlb(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + uint32_t flush_type, + uint32_t xcc_mask); void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, struct amdgpu_vm *vm, struct amdgpu_bo *bo); int amdgpu_vm_update_range(struct amdgpu_device *adev, struct amdgpu_vm *vm, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 9cc32f577e38..a40f8cfc6aa5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -748,7 +748,6 @@ struct kfd_process_device { /* VM context for GPUVM allocations */ struct file *drm_file; void *drm_priv; - atomic64_t tlb_seq; /* GPUVM allocations storage */ struct idr alloc_idr; @@ -1462,7 +1461,14 @@ void kfd_signal_reset_event(struct kfd_node *dev); void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid); -void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type); +static inline void kfd_flush_tlb(struct kfd_process_device *pdd, + enum TLB_FLUSH_TYPE type) +{ + struct amdgpu_device *adev = pdd->dev->adev; + struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv); + + amdgpu_vm_flush_compute_tlb(adev, vm, type, pdd->dev->xcc_mask); +} static inline bool kfd_flush_tlb_after_unmap(struct kfd_dev *dev) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 7a33e06f5c90..c10d050e1a61 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1667,7 +1667,6 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, return ret; } pdd->drm_priv = drm_file->private_data; - atomic64_set(&pdd->tlb_seq, 0); ret = kfd_process_device_reserve_ib_mem(pdd); if (ret) @@ -2059,36 +2058,6 @@ int kfd_reserved_mem_mmap(struct kfd_node *dev, struct kfd_process *process, KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot); } -void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type) -{ - struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv); - uint64_t tlb_seq = amdgpu_vm_tlb_seq(vm); - struct kfd_node *dev = pdd->dev; - uint32_t xcc_mask = dev->xcc_mask; - int xcc = 0; - - /* - * It can be that we race and lose here, but that is extremely unlikely - * and the worst thing which could happen is that we flush the changes - * into the TLB once more which is harmless. - */ - if (atomic64_xchg(&pdd->tlb_seq, tlb_seq) == tlb_seq) - return; - - if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) { - /* Nothing to flush until a VMID is assigned, which - * only happens when the first queue is created. - */ - if (pdd->qpd.vmid) - amdgpu_amdkfd_flush_gpu_tlb_vmid(dev->adev, - pdd->qpd.vmid); - } else { - for_each_inst(xcc, xcc_mask) - amdgpu_amdkfd_flush_gpu_tlb_pasid( - dev->adev, pdd->process->pasid, type, xcc); - } -} - /* assumes caller holds process lock. */ int kfd_process_drain_interrupts(struct kfd_process_device *pdd) { From fbbcb3f2b7c269c92218f315d22d6ab00524798a Mon Sep 17 00:00:00 2001 From: Ma Jun Date: Thu, 2 Nov 2023 11:19:46 +0800 Subject: [PATCH 0802/7721] drm/amd/pm: Fix return value and drop redundant param Fix the return value and drop redundant parameter of get_asic_baco_capability function. Signed-off-by: Ma Jun Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 +- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 8 +++----- drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 11 ++++------- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c | 7 +++---- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h | 2 +- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c | 9 ++++----- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h | 2 +- drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c | 9 ++++----- drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h | 2 +- drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 2 +- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 12 +++++------- 11 files changed, 28 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index cd3c40a86029..b14231f470dc 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -421,7 +421,7 @@ struct amd_pm_funcs { int (*set_hard_min_dcefclk_by_freq)(void *handle, uint32_t clock); int (*set_hard_min_fclk_by_freq)(void *handle, uint32_t clock); int (*set_min_deep_sleep_dcefclk)(void *handle, uint32_t clock); - int (*get_asic_baco_capability)(void *handle, bool *cap); + bool (*get_asic_baco_capability)(void *handle); int (*get_asic_baco_state)(void *handle, int *state); int (*set_asic_baco_state)(void *handle, int state); int (*get_ppfeature_status)(void *handle, char *buf); diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 08cb79401410..1ae3b81548fa 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -185,8 +185,7 @@ bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; void *pp_handle = adev->powerplay.pp_handle; - bool baco_cap; - int ret = 0; + bool ret; if (!pp_funcs || !pp_funcs->get_asic_baco_capability) return false; @@ -204,12 +203,11 @@ bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) mutex_lock(&adev->pm.mutex); - ret = pp_funcs->get_asic_baco_capability(pp_handle, - &baco_cap); + ret = pp_funcs->get_asic_baco_capability(pp_handle); mutex_unlock(&adev->pm.mutex); - return ret ? false : baco_cap; + return ret; } int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 914c15387157..aed0e2cefbf9 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -1371,21 +1371,18 @@ static int pp_set_active_display_count(void *handle, uint32_t count) return phm_set_active_display_count(hwmgr, count); } -static int pp_get_asic_baco_capability(void *handle, bool *cap) +static bool pp_get_asic_baco_capability(void *handle) { struct pp_hwmgr *hwmgr = handle; - *cap = false; if (!hwmgr) - return -EINVAL; + return false; if (!(hwmgr->not_vf && amdgpu_dpm) || !hwmgr->hwmgr_func->get_asic_baco_capability) - return 0; + return false; - hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr, cap); - - return 0; + return hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr); } static int pp_get_asic_baco_state(void *handle, int *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c index 044cda005aed..e8a9471c1898 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c @@ -33,21 +33,20 @@ #include "smu/smu_7_1_2_d.h" #include "smu/smu_7_1_2_sh_mask.h" -int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool smu7_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) return 0; reg = RREG32(mmCC_BIF_BX_FUSESTRAP0); if (reg & CC_BIF_BX_FUSESTRAP0__STRAP_BIF_PX_CAPABLE_MASK) - *cap = true; + return true; - return 0; + return false; } int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h index be0d98abb536..73a773f4ce2e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool smu7_baco_get_capability(struct pp_hwmgr *hwmgr); extern int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); extern int smu7_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c index de0a37f7c632..c66ef9741535 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c @@ -28,14 +28,13 @@ #include "vega10_inc.h" #include "smu9_baco.h" -int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool smu9_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg, data; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) - return 0; + return false; WREG32(0x12074, 0xFFF0003B); data = RREG32(0x12075); @@ -44,10 +43,10 @@ int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0); if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) - *cap = true; + return true; } - return 0; + return false; } int smu9_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h index 84e90f801ac3..9ff7c2ea1b58 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool smu9_baco_get_capability(struct pp_hwmgr *hwmgr); extern int smu9_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); #endif diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c index 994c0d374bfa..dad4c80aee58 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c @@ -36,23 +36,22 @@ static const struct soc15_baco_cmd_entry clean_baco_tbl[] = { {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_7), 0, 0, 0, 0}, }; -int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool vega20_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) - return 0; + return false; if (((RREG32(0x17569) & 0x20000000) >> 29) == 0x1) { reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0); if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) - *cap = true; + return true; } - return 0; + return false; } int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h index f06471e712dc..bdad9c915631 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool vega20_baco_get_capability(struct pp_hwmgr *hwmgr); extern int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); extern int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); extern int vega20_baco_apply_vdci_flush_workaround(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 81650727a5de..6f536159df4d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -351,7 +351,7 @@ struct pp_hwmgr_func { int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); int (*set_hard_min_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); int (*set_soft_max_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); - int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); + bool (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr); int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf); diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 1ead323f1c78..37c2605f9b35 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -3005,19 +3005,17 @@ static int smu_set_xgmi_pstate(void *handle, return ret; } -static int smu_get_baco_capability(void *handle, bool *cap) +static bool smu_get_baco_capability(void *handle) { struct smu_context *smu = handle; - *cap = false; - if (!smu->pm_enabled) - return 0; + return false; - if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) - *cap = smu->ppt_funcs->baco_is_support(smu); + if (!smu->ppt_funcs || !smu->ppt_funcs->baco_is_support) + return false; - return 0; + return smu->ppt_funcs->baco_is_support(smu); } static int smu_baco_set_state(void *handle, int state) From b5a52d2afe1b75f9d51461bb235ca40735e99fe7 Mon Sep 17 00:00:00 2001 From: Sam James Date: Sun, 5 Nov 2023 16:06:50 +0000 Subject: [PATCH 0803/7721] amdgpu: Adjust kmalloc_array calls for new -Walloc-size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 14 introduces a new -Walloc-size included in -Wextra which errors out on various files in drivers/gpu/drm/amd/amdgpu like: ``` amdgpu_amdkfd_gfx_v8.c:241:15: error: allocation of insufficient size ‘4’ for type ‘uint32_t[2]’ {aka ‘unsigned int[2]'} with size ‘8’ [-Werror=alloc-size] ``` This is because each HQD_N_REGS is actually a uint32_t[2]. Move the * 2 to the size argument so GCC sees we're allocating enough. Originally did 'sizeof(uint32_t) * 2' for the size but a friend suggested 'sizeof(**dump)' better communicates the intent. Link: https://lore.kernel.org/all/87wmuwo7i3.fsf@gentoo.org/ Signed-off-by: Sam James Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 625db444df1c..0ba15dcbe4e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -200,7 +200,7 @@ int kgd_arcturus_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+6+7+10) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c index f6598b9e4faa..a5c7259cf2a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c @@ -141,7 +141,7 @@ static int kgd_gfx_v9_4_3_hqd_sdma_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 6bf448ab3dff..ca4a6b82817f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -214,7 +214,7 @@ static int kgd_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -301,7 +301,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+4) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index cd06e4a6d1da..0f3e2944edd7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -238,7 +238,7 @@ static int kgd_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -324,7 +324,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+4+2+3+7) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 00fbc0f44c92..5a35a8ca8922 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -363,7 +363,7 @@ int kgd_gfx_v9_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -460,7 +460,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+6+7+10) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; From d8a3813713c3843351123138c8b191142c266521 Mon Sep 17 00:00:00 2001 From: Abhinav Singh Date: Fri, 3 Nov 2023 21:20:13 +0530 Subject: [PATCH 0804/7721] drm/radeon: Fix warning using plain integer as NULL sparse static analysis tools generate a warning with this message "Using plain integer as NULL pointer". In this case this warning is being shown because we are trying to intialize a pointer to NULL using integer value 0. Signed-off-by: Abhinav Singh Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/clearstate_evergreen.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/clearstate_evergreen.h b/drivers/gpu/drm/radeon/clearstate_evergreen.h index 63a1ffbb3ced..3b645558f133 100644 --- a/drivers/gpu/drm/radeon/clearstate_evergreen.h +++ b/drivers/gpu/drm/radeon/clearstate_evergreen.h @@ -1049,7 +1049,7 @@ static const struct cs_extent_def SECT_CONTEXT_defs[] = {SECT_CONTEXT_def_5, 0x0000a29e, 5 }, {SECT_CONTEXT_def_6, 0x0000a2a5, 56 }, {SECT_CONTEXT_def_7, 0x0000a2de, 290 }, - { 0, 0, 0 } + { NULL, 0, 0 } }; static const u32 SECT_CLEAR_def_1[] = { @@ -1060,7 +1060,7 @@ static const u32 SECT_CLEAR_def_1[] = static const struct cs_extent_def SECT_CLEAR_defs[] = { {SECT_CLEAR_def_1, 0x0000ffc0, 3 }, - { 0, 0, 0 } + { NULL, 0, 0 } }; static const u32 SECT_CTRLCONST_def_1[] = { @@ -1070,11 +1070,11 @@ static const u32 SECT_CTRLCONST_def_1[] = static const struct cs_extent_def SECT_CTRLCONST_defs[] = { {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 }, - { 0, 0, 0 } + { NULL, 0, 0 } }; static const struct cs_section_def evergreen_cs_data[] = { { SECT_CONTEXT_defs, SECT_CONTEXT }, { SECT_CLEAR_defs, SECT_CLEAR }, { SECT_CTRLCONST_defs, SECT_CTRLCONST }, - { 0, SECT_NONE } + { NULL, SECT_NONE } }; From 857c838c782728318c581cb656fddd74faa89ad2 Mon Sep 17 00:00:00 2001 From: Ma Jun Date: Fri, 3 Nov 2023 09:48:06 +0800 Subject: [PATCH 0805/7721] drm/amd/pm: Move some functions to smu_v13_0.c as generic code Use generic functions and remove the duplicate code Signed-off-by: Ma Jun Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 38 ++++++++++++++----- .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 36 +----------------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 36 +----------------- 3 files changed, 32 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index cf1b84060bc3..b446f860baf6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -2283,22 +2283,40 @@ int smu_v13_0_baco_set_state(struct smu_context *smu, int smu_v13_0_baco_enter(struct smu_context *smu) { - int ret = 0; + struct smu_baco_context *smu_baco = &smu->smu_baco; + struct amdgpu_device *adev = smu->adev; + int ret; + + if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { + return smu_v13_0_baco_set_armd3_sequence(smu, + (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? + BACO_SEQ_BAMACO : BACO_SEQ_BACO); + } else { + ret = smu_v13_0_baco_set_state(smu, SMU_BACO_STATE_ENTER); + if (!ret) + usleep_range(10000, 11000); - ret = smu_v13_0_baco_set_state(smu, - SMU_BACO_STATE_ENTER); - if (ret) return ret; - - msleep(10); - - return ret; + } } int smu_v13_0_baco_exit(struct smu_context *smu) { - return smu_v13_0_baco_set_state(smu, - SMU_BACO_STATE_EXIT); + struct amdgpu_device *adev = smu->adev; + int ret; + + if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { + /* Wait for PMFW handling for the Dstate change */ + usleep_range(10000, 11000); + ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); + } else { + ret = smu_v13_0_baco_set_state(smu, SMU_BACO_STATE_EXIT); + } + + if (!ret) + adev->gfx.is_poweron = false; + + return ret; } int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 82c4e1f1c6f0..a4debd7ab8bd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -2558,38 +2558,6 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, NULL); } -static int smu_v13_0_0_baco_enter(struct smu_context *smu) -{ - struct smu_baco_context *smu_baco = &smu->smu_baco; - struct amdgpu_device *adev = smu->adev; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) - return smu_v13_0_baco_set_armd3_sequence(smu, - (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? - BACO_SEQ_BAMACO : BACO_SEQ_BACO); - else - return smu_v13_0_baco_enter(smu); -} - -static int smu_v13_0_0_baco_exit(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { - /* Wait for PMFW handling for the Dstate change */ - usleep_range(10000, 11000); - ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); - } else { - ret = smu_v13_0_baco_exit(smu); - } - - if (!ret) - adev->gfx.is_poweron = false; - - return ret; -} - static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -3037,8 +3005,8 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .baco_is_support = smu_v13_0_baco_is_support, .baco_get_state = smu_v13_0_baco_get_state, .baco_set_state = smu_v13_0_baco_set_state, - .baco_enter = smu_v13_0_0_baco_enter, - .baco_exit = smu_v13_0_0_baco_exit, + .baco_enter = smu_v13_0_baco_enter, + .baco_exit = smu_v13_0_baco_exit, .mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported, .mode1_reset = smu_v13_0_0_mode1_reset, .mode2_reset = smu_v13_0_0_mode2_reset, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 81eafed76045..f5596f031d00 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -2515,38 +2515,6 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu, return ret; } -static int smu_v13_0_7_baco_enter(struct smu_context *smu) -{ - struct smu_baco_context *smu_baco = &smu->smu_baco; - struct amdgpu_device *adev = smu->adev; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) - return smu_v13_0_baco_set_armd3_sequence(smu, - (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? - BACO_SEQ_BAMACO : BACO_SEQ_BACO); - else - return smu_v13_0_baco_enter(smu); -} - -static int smu_v13_0_7_baco_exit(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { - /* Wait for PMFW handling for the Dstate change */ - usleep_range(10000, 11000); - ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); - } else { - ret = smu_v13_0_baco_exit(smu); - } - - if (!ret) - adev->gfx.is_poweron = false; - - return ret; -} - static bool smu_v13_0_7_is_mode1_reset_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2628,8 +2596,8 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .baco_is_support = smu_v13_0_baco_is_support, .baco_get_state = smu_v13_0_baco_get_state, .baco_set_state = smu_v13_0_baco_set_state, - .baco_enter = smu_v13_0_7_baco_enter, - .baco_exit = smu_v13_0_7_baco_exit, + .baco_enter = smu_v13_0_baco_enter, + .baco_exit = smu_v13_0_baco_exit, .mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, .set_mp1_state = smu_v13_0_7_set_mp1_state, From 5ce8eccd53a357f91f2c2fe29918f9c65a1fe970 Mon Sep 17 00:00:00 2001 From: Ma Jun Date: Wed, 8 Nov 2023 16:00:30 +0800 Subject: [PATCH 0806/7721] drm/amd/pm: Make smu_v13_0_baco_set_armd3_sequence() static smu_v13_0_baco_set_armd3_sequence is not used by other files, so make it as static type. Signed-off-by: Ma Jun Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 95cb919718ae..48f5926d8153 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -210,9 +210,6 @@ int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu); int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks); -int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, - enum smu_baco_seq baco_seq); - bool smu_v13_0_baco_is_support(struct smu_context *smu); enum smu_baco_state smu_v13_0_baco_get_state(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index b446f860baf6..86fc7273d588 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -2199,7 +2199,7 @@ int smu_v13_0_gfx_ulv_control(struct smu_context *smu, return ret; } -int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, +static int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_baco_seq baco_seq) { struct smu_baco_context *smu_baco = &smu->smu_baco; From 8a1de314d1890793bbf9e77542574ceda007564e Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Wed, 2 Aug 2023 07:49:14 +0530 Subject: [PATCH 0807/7721] drm/amdgpu: Refactor 'amdgpu_connector_dvi_detect' in amdgpu_connectors.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the below: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' WARNING: Missing a blank line after declarations WARNING: Too many leading tabs - consider code refactoring + if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { WARNING: Too many leading tabs - consider code refactoring + if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { Cc: Guchun Chen Cc: Christian König Cc: Alex Deucher Cc: "Pan, Xinhui" Cc: Rodrigo Siqueira Cc: Aurabindo Pillai Signed-off-by: Srinivasan Shanmugam Acked-by: Guchun Chen Reviewed-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_connectors.c | 69 +++++++++++-------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 7473a42f7d45..96f63fd39b9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -103,7 +103,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector_atom_dig *dig_connector; int bpc = 8; - unsigned mode_clock, max_tmds_clock; + unsigned int mode_clock, max_tmds_clock; switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: @@ -255,6 +255,7 @@ struct edid *amdgpu_connector_edid(struct drm_connector *connector) return amdgpu_connector->edid; } else if (edid_blob) { struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); + if (edid) amdgpu_connector->edid = edid; } @@ -581,6 +582,7 @@ static int amdgpu_connector_set_property(struct drm_connector *connector, amdgpu_encoder = to_amdgpu_encoder(connector->encoder); } else { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); } @@ -797,6 +799,7 @@ static int amdgpu_connector_set_lcd_property(struct drm_connector *connector, amdgpu_encoder = to_amdgpu_encoder(connector->encoder); else { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); } @@ -979,6 +982,41 @@ amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector) return false; } +static void amdgpu_connector_shared_ddc(enum drm_connector_status *status, + struct drm_connector *connector, + struct amdgpu_connector *amdgpu_connector) +{ + struct drm_connector *list_connector; + struct drm_connector_list_iter iter; + struct amdgpu_connector *list_amdgpu_connector; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + + if (amdgpu_connector->shared_ddc && *status == connector_status_connected) { + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(list_connector, + &iter) { + if (connector == list_connector) + continue; + list_amdgpu_connector = to_amdgpu_connector(list_connector); + if (list_amdgpu_connector->shared_ddc && + list_amdgpu_connector->ddc_bus->rec.i2c_id == + amdgpu_connector->ddc_bus->rec.i2c_id) { + /* cases where both connectors are digital */ + if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { + /* hpd is our only option in this case */ + if (!amdgpu_display_hpd_sense(adev, + amdgpu_connector->hpd.hpd)) { + amdgpu_connector_free_edid(connector); + *status = connector_status_disconnected; + } + } + } + } + drm_connector_list_iter_end(&iter); + } +} + /* * DVI is complicated * Do a DDC probe, if DDC probe passes, get the full EDID so @@ -1065,32 +1103,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) * DDC line. The latter is more complex because with DVI<->HDMI adapters * you don't really know what's connected to which port as both are digital. */ - if (amdgpu_connector->shared_ddc && (ret == connector_status_connected)) { - struct drm_connector *list_connector; - struct drm_connector_list_iter iter; - struct amdgpu_connector *list_amdgpu_connector; - - drm_connector_list_iter_begin(dev, &iter); - drm_for_each_connector_iter(list_connector, - &iter) { - if (connector == list_connector) - continue; - list_amdgpu_connector = to_amdgpu_connector(list_connector); - if (list_amdgpu_connector->shared_ddc && - (list_amdgpu_connector->ddc_bus->rec.i2c_id == - amdgpu_connector->ddc_bus->rec.i2c_id)) { - /* cases where both connectors are digital */ - if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { - /* hpd is our only option in this case */ - if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { - amdgpu_connector_free_edid(connector); - ret = connector_status_disconnected; - } - } - } - } - drm_connector_list_iter_end(&iter); - } + amdgpu_connector_shared_ddc(&ret, connector, amdgpu_connector); } } @@ -1192,6 +1205,7 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector) static void amdgpu_connector_dvi_force(struct drm_connector *connector) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); + if (connector->force == DRM_FORCE_ON) amdgpu_connector->use_digital = false; if (connector->force == DRM_FORCE_ON_DIGITAL) @@ -1426,6 +1440,7 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; else if (amdgpu_connector->dac_load_detect) { /* try load detection */ const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); } } From f4fac4163c2f99aada9cc60292f2ea377afe6c71 Mon Sep 17 00:00:00 2001 From: Laurent Morichetti Date: Wed, 8 Nov 2023 16:16:18 -0800 Subject: [PATCH 0808/7721] drm/amdkfd: Clear the VALU exception state in the trap handler The trap handler could be entered with pending VALU exceptions, so clear the exception state before issuing vector instructions. Reviewed-by: Jay Cornwall Acked-by: Alex Deucher Signed-off-by: Laurent Morichetti Tested-by: Lancelot Six Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdkfd/cwsr_trap_handler.h | 692 +++++++++--------- .../amd/amdkfd/cwsr_trap_handler_gfx10.asm | 6 + 2 files changed, 352 insertions(+), 346 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index d7cd5fa313ff..df75863393fc 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -2069,7 +2069,7 @@ static const uint32_t cwsr_trap_aldebaran_hex[] = { }; static const uint32_t cwsr_trap_gfx10_hex[] = { - 0xbf820001, 0xbf820220, + 0xbf820001, 0xbf820221, 0xb0804004, 0xb978f802, 0x8a78ff78, 0x00020006, 0xb97bf803, 0x876eff78, @@ -2118,391 +2118,391 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xbf900004, 0xbf8cc07f, 0x877aff7f, 0x04000000, 0x8f7a857a, 0x886d7a6d, - 0xbefa037e, 0x877bff7f, - 0x0000ffff, 0xbefe03c1, - 0xbeff03c1, 0xdc5f8000, - 0x007a0000, 0x7e000280, - 0xbefe037a, 0xbeff037b, - 0xb97b02dc, 0x8f7b997b, - 0xb97a3a05, 0x807a817a, - 0xbf0d997b, 0xbf850002, - 0x8f7a897a, 0xbf820001, - 0x8f7a8a7a, 0xb97b1e06, - 0x8f7b8a7b, 0x807a7b7a, + 0x7e008200, 0xbefa037e, 0x877bff7f, 0x0000ffff, - 0x807aff7a, 0x00000200, - 0x807a7e7a, 0x827b807b, - 0xd7610000, 0x00010870, - 0xd7610000, 0x00010a71, - 0xd7610000, 0x00010c72, - 0xd7610000, 0x00010e73, - 0xd7610000, 0x00011074, - 0xd7610000, 0x00011275, - 0xd7610000, 0x00011476, - 0xd7610000, 0x00011677, - 0xd7610000, 0x00011a79, - 0xd7610000, 0x00011c7e, - 0xd7610000, 0x00011e7f, - 0xbefe03ff, 0x00003fff, - 0xbeff0380, 0xdc5f8040, - 0x007a0000, 0xd760007a, - 0x00011d00, 0xd760007b, - 0x00011f00, 0xbefe037a, - 0xbeff037b, 0xbef4037e, - 0x8775ff7f, 0x0000ffff, - 0x8875ff75, 0x00040000, - 0xbef60380, 0xbef703ff, - 0x10807fac, 0xbef1037c, - 0xbef00380, 0xb97302dc, - 0x8f739973, 0xbefe03c1, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820002, - 0xbeff03c1, 0xbf820009, + 0xbefe03c1, 0xbeff03c1, + 0xdc5f8000, 0x007a0000, + 0x7e000280, 0xbefe037a, + 0xbeff037b, 0xb97b02dc, + 0x8f7b997b, 0xb97a3a05, + 0x807a817a, 0xbf0d997b, + 0xbf850002, 0x8f7a897a, + 0xbf820001, 0x8f7a8a7a, + 0xb97b1e06, 0x8f7b8a7b, + 0x807a7b7a, 0x877bff7f, + 0x0000ffff, 0x807aff7a, + 0x00000200, 0x807a7e7a, + 0x827b807b, 0xd7610000, + 0x00010870, 0xd7610000, + 0x00010a71, 0xd7610000, + 0x00010c72, 0xd7610000, + 0x00010e73, 0xd7610000, + 0x00011074, 0xd7610000, + 0x00011275, 0xd7610000, + 0x00011476, 0xd7610000, + 0x00011677, 0xd7610000, + 0x00011a79, 0xd7610000, + 0x00011c7e, 0xd7610000, + 0x00011e7f, 0xbefe03ff, + 0x00003fff, 0xbeff0380, + 0xdc5f8040, 0x007a0000, + 0xd760007a, 0x00011d00, + 0xd760007b, 0x00011f00, + 0xbefe037a, 0xbeff037b, + 0xbef4037e, 0x8775ff7f, + 0x0000ffff, 0x8875ff75, + 0x00040000, 0xbef60380, + 0xbef703ff, 0x10807fac, + 0xbef1037c, 0xbef00380, + 0xb97302dc, 0x8f739973, + 0xbefe03c1, 0x907c9973, + 0x877c817c, 0xbf06817c, + 0xbf850002, 0xbeff0380, + 0xbf820002, 0xbeff03c1, + 0xbf820009, 0xbef603ff, + 0x01000000, 0xe0704080, + 0x705d0100, 0xe0704100, + 0x705d0200, 0xe0704180, + 0x705d0300, 0xbf820008, 0xbef603ff, 0x01000000, - 0xe0704080, 0x705d0100, - 0xe0704100, 0x705d0200, - 0xe0704180, 0x705d0300, - 0xbf820008, 0xbef603ff, - 0x01000000, 0xe0704100, - 0x705d0100, 0xe0704200, - 0x705d0200, 0xe0704300, - 0x705d0300, 0xb9703a05, - 0x80708170, 0xbf0d9973, - 0xbf850002, 0x8f708970, - 0xbf820001, 0x8f708a70, - 0xb97a1e06, 0x8f7a8a7a, - 0x80707a70, 0x8070ff70, - 0x00000200, 0xbef603ff, - 0x01000000, 0x7e000280, - 0x7e020280, 0x7e040280, - 0xbefc0380, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xd7610002, 0x0000f86c, - 0x807c817c, 0x8a7aff6d, - 0x80000000, 0xd7610002, - 0x0000f87a, 0x807c817c, - 0xd7610002, 0x0000f86e, - 0x807c817c, 0xd7610002, - 0x0000f86f, 0x807c817c, - 0xd7610002, 0x0000f878, - 0x807c817c, 0xb97af803, - 0xd7610002, 0x0000f87a, - 0x807c817c, 0xd7610002, - 0x0000f87b, 0x807c817c, - 0xb971f801, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xb971f814, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xb971f815, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xbefe03ff, 0x0000ffff, - 0xbeff0380, 0xe0704000, - 0x705d0200, 0xbefe03c1, + 0xe0704100, 0x705d0100, + 0xe0704200, 0x705d0200, + 0xe0704300, 0x705d0300, 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, 0xb97a1e06, 0x8f7a8a7a, 0x80707a70, + 0x8070ff70, 0x00000200, 0xbef603ff, 0x01000000, - 0xbef90380, 0xbefc0380, - 0xbf800000, 0xbe802f00, - 0xbe822f02, 0xbe842f04, - 0xbe862f06, 0xbe882f08, - 0xbe8a2f0a, 0xbe8c2f0c, - 0xbe8e2f0e, 0xd7610002, - 0x0000f200, 0x80798179, - 0xd7610002, 0x0000f201, - 0x80798179, 0xd7610002, - 0x0000f202, 0x80798179, - 0xd7610002, 0x0000f203, - 0x80798179, 0xd7610002, - 0x0000f204, 0x80798179, - 0xd7610002, 0x0000f205, - 0x80798179, 0xd7610002, - 0x0000f206, 0x80798179, - 0xd7610002, 0x0000f207, - 0x80798179, 0xd7610002, - 0x0000f208, 0x80798179, - 0xd7610002, 0x0000f209, - 0x80798179, 0xd7610002, - 0x0000f20a, 0x80798179, - 0xd7610002, 0x0000f20b, - 0x80798179, 0xd7610002, - 0x0000f20c, 0x80798179, - 0xd7610002, 0x0000f20d, - 0x80798179, 0xd7610002, - 0x0000f20e, 0x80798179, - 0xd7610002, 0x0000f20f, - 0x80798179, 0xbf06a079, - 0xbf840006, 0xe0704000, - 0x705d0200, 0x8070ff70, - 0x00000080, 0xbef90380, - 0x7e040280, 0x807c907c, - 0xbf0aff7c, 0x00000060, - 0xbf85ffbc, 0xbe802f00, - 0xbe822f02, 0xbe842f04, - 0xbe862f06, 0xbe882f08, - 0xbe8a2f0a, 0xd7610002, - 0x0000f200, 0x80798179, - 0xd7610002, 0x0000f201, - 0x80798179, 0xd7610002, - 0x0000f202, 0x80798179, - 0xd7610002, 0x0000f203, - 0x80798179, 0xd7610002, - 0x0000f204, 0x80798179, - 0xd7610002, 0x0000f205, - 0x80798179, 0xd7610002, - 0x0000f206, 0x80798179, - 0xd7610002, 0x0000f207, - 0x80798179, 0xd7610002, - 0x0000f208, 0x80798179, - 0xd7610002, 0x0000f209, - 0x80798179, 0xd7610002, - 0x0000f20a, 0x80798179, - 0xd7610002, 0x0000f20b, - 0x80798179, 0xe0704000, - 0x705d0200, 0xbefe03c1, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820001, - 0xbeff03c1, 0xb97b4306, - 0x877bc17b, 0xbf840044, - 0xbf8a0000, 0x877aff6d, - 0x80000000, 0xbf840040, - 0x8f7b867b, 0x8f7b827b, - 0xbef6037b, 0xb9703a05, + 0x7e000280, 0x7e020280, + 0x7e040280, 0xbefc0380, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xd7610002, + 0x0000f86c, 0x807c817c, + 0x8a7aff6d, 0x80000000, + 0xd7610002, 0x0000f87a, + 0x807c817c, 0xd7610002, + 0x0000f86e, 0x807c817c, + 0xd7610002, 0x0000f86f, + 0x807c817c, 0xd7610002, + 0x0000f878, 0x807c817c, + 0xb97af803, 0xd7610002, + 0x0000f87a, 0x807c817c, + 0xd7610002, 0x0000f87b, + 0x807c817c, 0xb971f801, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xb971f814, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xb971f815, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xbefe03ff, + 0x0000ffff, 0xbeff0380, + 0xe0704000, 0x705d0200, + 0xbefe03c1, 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, 0xb97a1e06, 0x8f7a8a7a, - 0x80707a70, 0x8070ff70, - 0x00000200, 0x8070ff70, - 0x00000080, 0xbef603ff, - 0x01000000, 0xd7650000, - 0x000100c1, 0xd7660000, - 0x000200c1, 0x16000084, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbefc0380, - 0xbf850012, 0xbe8303ff, - 0x00000080, 0xbf800000, - 0xbf800000, 0xbf800000, - 0xd8d80000, 0x01000000, - 0xbf8c0000, 0xe0704000, - 0x705d0100, 0x807c037c, - 0x80700370, 0xd5250000, - 0x0001ff00, 0x00000080, - 0xbf0a7b7c, 0xbf85fff4, - 0xbf820011, 0xbe8303ff, - 0x00000100, 0xbf800000, - 0xbf800000, 0xbf800000, - 0xd8d80000, 0x01000000, - 0xbf8c0000, 0xe0704000, - 0x705d0100, 0x807c037c, - 0x80700370, 0xd5250000, - 0x0001ff00, 0x00000100, - 0xbf0a7b7c, 0xbf85fff4, + 0x80707a70, 0xbef603ff, + 0x01000000, 0xbef90380, + 0xbefc0380, 0xbf800000, + 0xbe802f00, 0xbe822f02, + 0xbe842f04, 0xbe862f06, + 0xbe882f08, 0xbe8a2f0a, + 0xbe8c2f0c, 0xbe8e2f0e, + 0xd7610002, 0x0000f200, + 0x80798179, 0xd7610002, + 0x0000f201, 0x80798179, + 0xd7610002, 0x0000f202, + 0x80798179, 0xd7610002, + 0x0000f203, 0x80798179, + 0xd7610002, 0x0000f204, + 0x80798179, 0xd7610002, + 0x0000f205, 0x80798179, + 0xd7610002, 0x0000f206, + 0x80798179, 0xd7610002, + 0x0000f207, 0x80798179, + 0xd7610002, 0x0000f208, + 0x80798179, 0xd7610002, + 0x0000f209, 0x80798179, + 0xd7610002, 0x0000f20a, + 0x80798179, 0xd7610002, + 0x0000f20b, 0x80798179, + 0xd7610002, 0x0000f20c, + 0x80798179, 0xd7610002, + 0x0000f20d, 0x80798179, + 0xd7610002, 0x0000f20e, + 0x80798179, 0xd7610002, + 0x0000f20f, 0x80798179, + 0xbf06a079, 0xbf840006, + 0xe0704000, 0x705d0200, + 0x8070ff70, 0x00000080, + 0xbef90380, 0x7e040280, + 0x807c907c, 0xbf0aff7c, + 0x00000060, 0xbf85ffbc, + 0xbe802f00, 0xbe822f02, + 0xbe842f04, 0xbe862f06, + 0xbe882f08, 0xbe8a2f0a, + 0xd7610002, 0x0000f200, + 0x80798179, 0xd7610002, + 0x0000f201, 0x80798179, + 0xd7610002, 0x0000f202, + 0x80798179, 0xd7610002, + 0x0000f203, 0x80798179, + 0xd7610002, 0x0000f204, + 0x80798179, 0xd7610002, + 0x0000f205, 0x80798179, + 0xd7610002, 0x0000f206, + 0x80798179, 0xd7610002, + 0x0000f207, 0x80798179, + 0xd7610002, 0x0000f208, + 0x80798179, 0xd7610002, + 0x0000f209, 0x80798179, + 0xd7610002, 0x0000f20a, + 0x80798179, 0xd7610002, + 0x0000f20b, 0x80798179, + 0xe0704000, 0x705d0200, 0xbefe03c1, 0x907c9973, 0x877c817c, 0xbf06817c, - 0xbf850004, 0xbef003ff, - 0x00000200, 0xbeff0380, - 0xbf820003, 0xbef003ff, - 0x00000400, 0xbeff03c1, - 0xb97b3a05, 0x807b817b, - 0x8f7b827b, 0x907c9973, + 0xbf850002, 0xbeff0380, + 0xbf820001, 0xbeff03c1, + 0xb97b4306, 0x877bc17b, + 0xbf840044, 0xbf8a0000, + 0x877aff6d, 0x80000000, + 0xbf840040, 0x8f7b867b, + 0x8f7b827b, 0xbef6037b, + 0xb9703a05, 0x80708170, + 0xbf0d9973, 0xbf850002, + 0x8f708970, 0xbf820001, + 0x8f708a70, 0xb97a1e06, + 0x8f7a8a7a, 0x80707a70, + 0x8070ff70, 0x00000200, + 0x8070ff70, 0x00000080, + 0xbef603ff, 0x01000000, + 0xd7650000, 0x000100c1, + 0xd7660000, 0x000200c1, + 0x16000084, 0x907c9973, 0x877c817c, 0xbf06817c, - 0xbf850017, 0xbef603ff, + 0xbefc0380, 0xbf850012, + 0xbe8303ff, 0x00000080, + 0xbf800000, 0xbf800000, + 0xbf800000, 0xd8d80000, + 0x01000000, 0xbf8c0000, + 0xe0704000, 0x705d0100, + 0x807c037c, 0x80700370, + 0xd5250000, 0x0001ff00, + 0x00000080, 0xbf0a7b7c, + 0xbf85fff4, 0xbf820011, + 0xbe8303ff, 0x00000100, + 0xbf800000, 0xbf800000, + 0xbf800000, 0xd8d80000, + 0x01000000, 0xbf8c0000, + 0xe0704000, 0x705d0100, + 0x807c037c, 0x80700370, + 0xd5250000, 0x0001ff00, + 0x00000100, 0xbf0a7b7c, + 0xbf85fff4, 0xbefe03c1, + 0x907c9973, 0x877c817c, + 0xbf06817c, 0xbf850004, + 0xbef003ff, 0x00000200, + 0xbeff0380, 0xbf820003, + 0xbef003ff, 0x00000400, + 0xbeff03c1, 0xb97b3a05, + 0x807b817b, 0x8f7b827b, + 0x907c9973, 0x877c817c, + 0xbf06817c, 0xbf850017, + 0xbef603ff, 0x01000000, + 0xbefc0384, 0xbf0a7b7c, + 0xbf840037, 0x7e008700, + 0x7e028701, 0x7e048702, + 0x7e068703, 0xe0704000, + 0x705d0000, 0xe0704080, + 0x705d0100, 0xe0704100, + 0x705d0200, 0xe0704180, + 0x705d0300, 0x807c847c, + 0x8070ff70, 0x00000200, + 0xbf0a7b7c, 0xbf85ffef, + 0xbf820025, 0xbef603ff, 0x01000000, 0xbefc0384, - 0xbf0a7b7c, 0xbf840037, + 0xbf0a7b7c, 0xbf840011, 0x7e008700, 0x7e028701, 0x7e048702, 0x7e068703, 0xe0704000, 0x705d0000, - 0xe0704080, 0x705d0100, - 0xe0704100, 0x705d0200, - 0xe0704180, 0x705d0300, + 0xe0704100, 0x705d0100, + 0xe0704200, 0x705d0200, + 0xe0704300, 0x705d0300, 0x807c847c, 0x8070ff70, - 0x00000200, 0xbf0a7b7c, - 0xbf85ffef, 0xbf820025, - 0xbef603ff, 0x01000000, - 0xbefc0384, 0xbf0a7b7c, - 0xbf840011, 0x7e008700, - 0x7e028701, 0x7e048702, - 0x7e068703, 0xe0704000, - 0x705d0000, 0xe0704100, - 0x705d0100, 0xe0704200, - 0x705d0200, 0xe0704300, - 0x705d0300, 0x807c847c, - 0x8070ff70, 0x00000400, - 0xbf0a7b7c, 0xbf85ffef, - 0xb97b1e06, 0x877bc17b, - 0xbf84000c, 0x8f7b837b, - 0x807b7c7b, 0xbefe03c1, - 0xbeff0380, 0x7e008700, - 0xe0704000, 0x705d0000, - 0x807c817c, 0x8070ff70, - 0x00000080, 0xbf0a7b7c, - 0xbf85fff8, 0xbf82013b, - 0xbef4037e, 0x8775ff7f, - 0x0000ffff, 0x8875ff75, - 0x00040000, 0xbef60380, - 0xbef703ff, 0x10807fac, - 0xb97202dc, 0x8f729972, - 0x876eff7f, 0x04000000, - 0xbf840034, 0xbefe03c1, - 0x907c9972, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820001, - 0xbeff03c1, 0xb96f4306, - 0x876fc16f, 0xbf840029, - 0x8f6f866f, 0x8f6f826f, - 0xbef6036f, 0xb9783a05, - 0x80788178, 0xbf0d9972, - 0xbf850002, 0x8f788978, - 0xbf820001, 0x8f788a78, - 0xb96e1e06, 0x8f6e8a6e, - 0x80786e78, 0x8078ff78, - 0x00000200, 0x8078ff78, - 0x00000080, 0xbef603ff, - 0x01000000, 0x907c9972, - 0x877c817c, 0xbf06817c, - 0xbefc0380, 0xbf850009, - 0xe0310000, 0x781d0000, - 0x807cff7c, 0x00000080, - 0x8078ff78, 0x00000080, - 0xbf0a6f7c, 0xbf85fff8, - 0xbf820008, 0xe0310000, - 0x781d0000, 0x807cff7c, - 0x00000100, 0x8078ff78, - 0x00000100, 0xbf0a6f7c, - 0xbf85fff8, 0xbef80380, + 0x00000400, 0xbf0a7b7c, + 0xbf85ffef, 0xb97b1e06, + 0x877bc17b, 0xbf84000c, + 0x8f7b837b, 0x807b7c7b, + 0xbefe03c1, 0xbeff0380, + 0x7e008700, 0xe0704000, + 0x705d0000, 0x807c817c, + 0x8070ff70, 0x00000080, + 0xbf0a7b7c, 0xbf85fff8, + 0xbf82013b, 0xbef4037e, + 0x8775ff7f, 0x0000ffff, + 0x8875ff75, 0x00040000, + 0xbef60380, 0xbef703ff, + 0x10807fac, 0xb97202dc, + 0x8f729972, 0x876eff7f, + 0x04000000, 0xbf840034, 0xbefe03c1, 0x907c9972, 0x877c817c, 0xbf06817c, 0xbf850002, 0xbeff0380, 0xbf820001, 0xbeff03c1, - 0xb96f3a05, 0x806f816f, - 0x8f6f826f, 0x907c9972, - 0x877c817c, 0xbf06817c, - 0xbf850024, 0xbef603ff, - 0x01000000, 0xbeee0378, - 0x8078ff78, 0x00000200, - 0xbefc0384, 0xbf0a6f7c, - 0xbf840050, 0xe0304000, - 0x785d0000, 0xe0304080, - 0x785d0100, 0xe0304100, - 0x785d0200, 0xe0304180, - 0x785d0300, 0xbf8c3f70, - 0x7e008500, 0x7e028501, - 0x7e048502, 0x7e068503, - 0x807c847c, 0x8078ff78, - 0x00000200, 0xbf0a6f7c, - 0xbf85ffee, 0xe0304000, - 0x6e5d0000, 0xe0304080, - 0x6e5d0100, 0xe0304100, - 0x6e5d0200, 0xe0304180, - 0x6e5d0300, 0xbf8c3f70, - 0xbf820034, 0xbef603ff, - 0x01000000, 0xbeee0378, - 0x8078ff78, 0x00000400, - 0xbefc0384, 0xbf0a6f7c, - 0xbf840012, 0xe0304000, - 0x785d0000, 0xe0304100, - 0x785d0100, 0xe0304200, - 0x785d0200, 0xe0304300, - 0x785d0300, 0xbf8c3f70, - 0x7e008500, 0x7e028501, - 0x7e048502, 0x7e068503, - 0x807c847c, 0x8078ff78, - 0x00000400, 0xbf0a6f7c, - 0xbf85ffee, 0xb96f1e06, - 0x876fc16f, 0xbf84000e, - 0x8f6f836f, 0x806f7c6f, - 0xbefe03c1, 0xbeff0380, - 0xe0304000, 0x785d0000, - 0xbf8c3f70, 0x7e008500, - 0x807c817c, 0x8078ff78, - 0x00000080, 0xbf0a6f7c, - 0xbf85fff7, 0xbeff03c1, - 0xe0304000, 0x6e5d0000, - 0xe0304100, 0x6e5d0100, - 0xe0304200, 0x6e5d0200, - 0xe0304300, 0x6e5d0300, - 0xbf8c3f70, 0xb9783a05, - 0x80788178, 0xbf0d9972, - 0xbf850002, 0x8f788978, - 0xbf820001, 0x8f788a78, - 0xb96e1e06, 0x8f6e8a6e, - 0x80786e78, 0x8078ff78, - 0x00000200, 0x80f8ff78, - 0x00000050, 0xbef603ff, - 0x01000000, 0xbefc03ff, - 0x0000006c, 0x80f89078, - 0xf429003a, 0xf0000000, - 0xbf8cc07f, 0x80fc847c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0x80f8a078, - 0xf42d003a, 0xf0000000, - 0xbf8cc07f, 0x80fc887c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0xbe843104, - 0xbe863106, 0x80f8c078, - 0xf431003a, 0xf0000000, - 0xbf8cc07f, 0x80fc907c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0xbe843104, - 0xbe863106, 0xbe883108, - 0xbe8a310a, 0xbe8c310c, - 0xbe8e310e, 0xbf06807c, - 0xbf84fff0, 0xba80f801, - 0x00000000, 0xbf8a0000, + 0xb96f4306, 0x876fc16f, + 0xbf840029, 0x8f6f866f, + 0x8f6f826f, 0xbef6036f, 0xb9783a05, 0x80788178, 0xbf0d9972, 0xbf850002, 0x8f788978, 0xbf820001, 0x8f788a78, 0xb96e1e06, 0x8f6e8a6e, 0x80786e78, 0x8078ff78, 0x00000200, + 0x8078ff78, 0x00000080, 0xbef603ff, 0x01000000, - 0xf4211bfa, 0xf0000000, - 0x80788478, 0xf4211b3a, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbefc0380, + 0xbf850009, 0xe0310000, + 0x781d0000, 0x807cff7c, + 0x00000080, 0x8078ff78, + 0x00000080, 0xbf0a6f7c, + 0xbf85fff8, 0xbf820008, + 0xe0310000, 0x781d0000, + 0x807cff7c, 0x00000100, + 0x8078ff78, 0x00000100, + 0xbf0a6f7c, 0xbf85fff8, + 0xbef80380, 0xbefe03c1, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbf850002, + 0xbeff0380, 0xbf820001, + 0xbeff03c1, 0xb96f3a05, + 0x806f816f, 0x8f6f826f, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbf850024, + 0xbef603ff, 0x01000000, + 0xbeee0378, 0x8078ff78, + 0x00000200, 0xbefc0384, + 0xbf0a6f7c, 0xbf840050, + 0xe0304000, 0x785d0000, + 0xe0304080, 0x785d0100, + 0xe0304100, 0x785d0200, + 0xe0304180, 0x785d0300, + 0xbf8c3f70, 0x7e008500, + 0x7e028501, 0x7e048502, + 0x7e068503, 0x807c847c, + 0x8078ff78, 0x00000200, + 0xbf0a6f7c, 0xbf85ffee, + 0xe0304000, 0x6e5d0000, + 0xe0304080, 0x6e5d0100, + 0xe0304100, 0x6e5d0200, + 0xe0304180, 0x6e5d0300, + 0xbf8c3f70, 0xbf820034, + 0xbef603ff, 0x01000000, + 0xbeee0378, 0x8078ff78, + 0x00000400, 0xbefc0384, + 0xbf0a6f7c, 0xbf840012, + 0xe0304000, 0x785d0000, + 0xe0304100, 0x785d0100, + 0xe0304200, 0x785d0200, + 0xe0304300, 0x785d0300, + 0xbf8c3f70, 0x7e008500, + 0x7e028501, 0x7e048502, + 0x7e068503, 0x807c847c, + 0x8078ff78, 0x00000400, + 0xbf0a6f7c, 0xbf85ffee, + 0xb96f1e06, 0x876fc16f, + 0xbf84000e, 0x8f6f836f, + 0x806f7c6f, 0xbefe03c1, + 0xbeff0380, 0xe0304000, + 0x785d0000, 0xbf8c3f70, + 0x7e008500, 0x807c817c, + 0x8078ff78, 0x00000080, + 0xbf0a6f7c, 0xbf85fff7, + 0xbeff03c1, 0xe0304000, + 0x6e5d0000, 0xe0304100, + 0x6e5d0100, 0xe0304200, + 0x6e5d0200, 0xe0304300, + 0x6e5d0300, 0xbf8c3f70, + 0xb9783a05, 0x80788178, + 0xbf0d9972, 0xbf850002, + 0x8f788978, 0xbf820001, + 0x8f788a78, 0xb96e1e06, + 0x8f6e8a6e, 0x80786e78, + 0x8078ff78, 0x00000200, + 0x80f8ff78, 0x00000050, + 0xbef603ff, 0x01000000, + 0xbefc03ff, 0x0000006c, + 0x80f89078, 0xf429003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc847c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0x80f8a078, 0xf42d003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc887c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0xbe843104, 0xbe863106, + 0x80f8c078, 0xf431003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc907c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0xbe843104, 0xbe863106, + 0xbe883108, 0xbe8a310a, + 0xbe8c310c, 0xbe8e310e, + 0xbf06807c, 0xbf84fff0, + 0xba80f801, 0x00000000, + 0xbf8a0000, 0xb9783a05, + 0x80788178, 0xbf0d9972, + 0xbf850002, 0x8f788978, + 0xbf820001, 0x8f788a78, + 0xb96e1e06, 0x8f6e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0xbef603ff, + 0x01000000, 0xf4211bfa, 0xf0000000, 0x80788478, - 0xf4211b7a, 0xf0000000, - 0x80788478, 0xf4211c3a, + 0xf4211b3a, 0xf0000000, + 0x80788478, 0xf4211b7a, 0xf0000000, 0x80788478, - 0xf4211c7a, 0xf0000000, - 0x80788478, 0xf4211eba, + 0xf4211c3a, 0xf0000000, + 0x80788478, 0xf4211c7a, 0xf0000000, 0x80788478, - 0xf4211efa, 0xf0000000, - 0x80788478, 0xf4211e7a, + 0xf4211eba, 0xf0000000, + 0x80788478, 0xf4211efa, 0xf0000000, 0x80788478, - 0xf4211cfa, 0xf0000000, - 0x80788478, 0xf4211bba, + 0xf4211e7a, 0xf0000000, + 0x80788478, 0xf4211cfa, 0xf0000000, 0x80788478, - 0xbf8cc07f, 0xb9eef814, 0xf4211bba, 0xf0000000, 0x80788478, 0xbf8cc07f, - 0xb9eef815, 0xbefc036f, - 0xbefe0370, 0xbeff0371, - 0x876f7bff, 0x000003ff, - 0xb9ef4803, 0x876f7bff, - 0xfffff800, 0x906f8b6f, - 0xb9efa2c3, 0xb9f3f801, - 0xb96e3a05, 0x806e816e, - 0xbf0d9972, 0xbf850002, - 0x8f6e896e, 0xbf820001, - 0x8f6e8a6e, 0xb96f1e06, - 0x8f6f8a6f, 0x806e6f6e, - 0x806eff6e, 0x00000200, - 0x806e746e, 0x826f8075, - 0x876fff6f, 0x0000ffff, - 0xf4091c37, 0xfa000050, - 0xf4091d37, 0xfa000060, - 0xf4011e77, 0xfa000074, - 0xbf8cc07f, 0x876dff6d, - 0x0000ffff, 0x87fe7e7e, - 0x87ea6a6a, 0xb9faf802, - 0xbe80226c, 0xbf810000, + 0xb9eef814, 0xf4211bba, + 0xf0000000, 0x80788478, + 0xbf8cc07f, 0xb9eef815, + 0xbefc036f, 0xbefe0370, + 0xbeff0371, 0x876f7bff, + 0x000003ff, 0xb9ef4803, + 0x876f7bff, 0xfffff800, + 0x906f8b6f, 0xb9efa2c3, + 0xb9f3f801, 0xb96e3a05, + 0x806e816e, 0xbf0d9972, + 0xbf850002, 0x8f6e896e, + 0xbf820001, 0x8f6e8a6e, + 0xb96f1e06, 0x8f6f8a6f, + 0x806e6f6e, 0x806eff6e, + 0x00000200, 0x806e746e, + 0x826f8075, 0x876fff6f, + 0x0000ffff, 0xf4091c37, + 0xfa000050, 0xf4091d37, + 0xfa000060, 0xf4011e77, + 0xfa000074, 0xbf8cc07f, + 0x876dff6d, 0x0000ffff, + 0x87fe7e7e, 0x87ea6a6a, + 0xb9faf802, 0xbe80226c, + 0xbf810000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, - 0xbf9f0000, 0x00000000, }; static const uint32_t cwsr_trap_gfx11_hex[] = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm index fdab64624422..e0140df0b0ec 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm @@ -369,6 +369,12 @@ L_SLEEP: s_or_b32 s_save_pc_hi, s_save_pc_hi, s_save_tmp #if NO_SQC_STORE +#if ASIC_FAMILY <= CHIP_SIENNA_CICHLID + // gfx10: If there was a VALU exception, the exception state must be + // cleared before executing the VALU instructions below. + v_clrexcp +#endif + // Trap temporaries must be saved via VGPR but all VGPRs are in use. // There is no ttmp space to hold the resource constant for VGPR save. // Save v0 by itself since it requires only two SGPRs. From efb91fea652a42fcc037d2a9ef4ecd1ffc5ff4b7 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Fri, 27 Oct 2023 15:59:48 -0400 Subject: [PATCH 0809/7721] drm/amd/display: Fix a debugfs null pointer error [WHY & HOW] Check whether get_subvp_en() callback exists before calling it. Cc: Mario Limonciello Cc: Alex Deucher Cc: stable@vger.kernel.org Reviewed-by: Alex Hung Acked-by: Alex Hung Signed-off-by: Aurabindo Pillai Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 13a177d34376..45c972f2630d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -3647,12 +3647,16 @@ static int capabilities_show(struct seq_file *m, void *unused) bool mall_supported = dc->caps.mall_size_total; bool subvp_supported = dc->caps.subvp_fw_processing_delay_us; unsigned int mall_in_use = false; - unsigned int subvp_in_use = dc->cap_funcs.get_subvp_en(dc, dc->current_state); + unsigned int subvp_in_use = false; + struct hubbub *hubbub = dc->res_pool->hubbub; if (hubbub->funcs->get_mall_en) hubbub->funcs->get_mall_en(hubbub, &mall_in_use); + if (dc->cap_funcs.get_subvp_en) + subvp_in_use = dc->cap_funcs.get_subvp_en(dc, dc->current_state); + seq_printf(m, "mall supported: %s, enabled: %s\n", mall_supported ? "yes" : "no", mall_in_use ? "yes" : "no"); seq_printf(m, "sub-viewport supported: %s, enabled: %s\n", From ef71bb4119c786f6f1d132b8863698874321798b Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Fri, 10 Nov 2023 13:14:41 +0800 Subject: [PATCH 0810/7721] drm/amdgpu: correct mca ipid die/socket/addr decode correct mca ipid die/socket/addr decode v2: squash in fix from Yang Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 0e5a77c3c2e2..f723a4190ee5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -2392,8 +2392,8 @@ static const struct mca_bank_ipid smu_v13_0_6_mca_ipid_table[AMDGPU_MCA_IP_COUNT static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_bank_info *info) { - uint64_t ipid = entry->regs[MCA_REG_IDX_IPID]; - uint32_t insthi; + u64 ipid = entry->regs[MCA_REG_IDX_IPID]; + u32 instidhi, instid; /* NOTE: All MCA IPID register share the same format, * so the driver can share the MCMP1 register header file. @@ -2402,9 +2402,15 @@ static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_ info->hwid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, HardwareID); info->mcatype = REG_GET_FIELD(ipid, MCMP1_IPIDT0, McaType); - insthi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi); - info->aid = ((insthi >> 2) & 0x03); - info->socket_id = insthi & 0x03; + /* + * Unfied DieID Format: SAASS. A:AID, S:Socket. + * Unfied DieID[4] = InstanceId[0] + * Unfied DieID[0:3] = InstanceIdHi[0:3] + */ + instidhi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi); + instid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo); + info->aid = ((instidhi >> 2) & 0x03); + info->socket_id = ((instid & 0x1) << 2) | (instidhi & 0x03); } static int mca_bank_read_reg(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, @@ -2578,6 +2584,7 @@ static bool mca_gfx_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct uint32_t instlo; instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); + instlo &= GENMASK(31, 1); switch (instlo) { case 0x36430400: /* SMNAID XCD 0 */ case 0x38430400: /* SMNAID XCD 1 */ @@ -2596,6 +2603,7 @@ static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amd uint32_t errcode, instlo; instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); + instlo &= GENMASK(31, 1); if (instlo != 0x03b30400) return false; From fcfc6ceec3ebb725a0d6381a1120e7cd546e1df4 Mon Sep 17 00:00:00 2001 From: Yihan Zhu Date: Mon, 30 Oct 2023 13:29:51 -0400 Subject: [PATCH 0811/7721] drm/amd/display: Enable CM low mem power optimization [WHY & HOW] MPC MCM low mem power optimization still causes color distortion on first SCE enablement, only forces light sleep for it. DPP low memory power optimization still needs this bit to save power. Reviewed-by: Nicholas Kazlauskas Acked-by: Alex Hung Signed-off-by: Yihan Zhu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c | 13 ++++++++----- .../gpu/drm/amd/display/dc/dcn35/dcn35_resource.c | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 994b21ed272f..1a2adb354718 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -71,21 +71,24 @@ void mpc32_power_on_blnd_lut( { struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); +/* if (mpc->ctx->dc->debug.enable_mem_low_power.bits.cm) { if (power_on) { REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0); REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5); } else if (!mpc->ctx->dc->debug.disable_mem_low_power) { - ASSERT(false); - /* TODO: change to mpc - * dpp_base->ctx->dc->optimized_required = true; - * dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; - */ + //TODO: change to mpc + dpp_base->ctx->dc->optimized_required = true; + dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; } } else { REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, MPCC_MCM_1DLUT_MEM_PWR_FORCE, power_on == true ? 0 : 1); } +*/ + + REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, + MPCC_MCM_1DLUT_MEM_PWR_FORCE, power_on == true ? 0 : 1); } static enum dc_lut_mode mpc32_get_post1dlut_current(struct mpc *mpc, uint32_t mpcc_id) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c index c7e011d26d41..7a3faf2b1f06 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c @@ -724,7 +724,7 @@ static const struct dc_debug_options debug_defaults_drv = { .i2c = true, .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled .dscl = true, - .cm = false, + .cm = true, .mpc = true, .optc = true, .vpg = true, From c41028a2a16303e5a59e11338d6ef5475945c79d Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Thu, 9 Nov 2023 16:42:32 -0500 Subject: [PATCH 0812/7721] drm/amd/display: add a debugfs interface for the DMUB trace mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For features that are implemented primarily in DMUB (e.g. PSR), it is useful to be able to trace them at a DMUB level from the kernel, especially when debugging issues. So, introduce a debugfs interface that is able to read and set the DMUB trace mask dynamically at runtime and document how to use it. Cc: Alex Deucher Cc: Mario Limonciello Reviewed-by: Aurabindo Pillai Acked-by: Christian König Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- Documentation/gpu/amdgpu/display/dc-debug.rst | 41 +++++++ .../gpu/amdgpu/display/trace-groups-table.csv | 29 +++++ .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 101 ++++++++++++++++++ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 40 ++++++- 4 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 Documentation/gpu/amdgpu/display/trace-groups-table.csv diff --git a/Documentation/gpu/amdgpu/display/dc-debug.rst b/Documentation/gpu/amdgpu/display/dc-debug.rst index 40c55a618918..817631b1dbf3 100644 --- a/Documentation/gpu/amdgpu/display/dc-debug.rst +++ b/Documentation/gpu/amdgpu/display/dc-debug.rst @@ -75,3 +75,44 @@ change in real-time by using something like:: When reporting a bug related to DC, consider attaching this log before and after you reproduce the bug. + +DMUB Firmware Debug +=================== + +Sometimes, dmesg logs aren't enough. This is especially true if a feature is +implemented primarily in DMUB firmware. In such cases, all we see in dmesg when +an issue arises is some generic timeout error. So, to get more relevant +information, we can trace DMUB commands by enabling the relevant bits in +`amdgpu_dm_dmub_trace_mask`. + +Currently, we support the tracing of the following groups: + +Trace Groups +------------ + +.. csv-table:: + :header-rows: 1 + :widths: 1, 1 + :file: ./trace-groups-table.csv + +**Note: Not all ASICs support all of the listed trace groups** + +So, to enable just PSR tracing you can use the following command:: + + # echo 0x8020 > /sys/kernel/debug/dri/0/amdgpu_dm_dmub_trace_mask + +Then, you need to enable logging trace events to the buffer, which you can do +using the following:: + + # echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en + +Lastly, after you are able to reproduce the issue you are trying to debug, +you can disable tracing and read the trace log by using the following:: + + # echo 0 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en + # cat /sys/kernel/debug/dri/0/amdgpu_dm_dmub_tracebuffer + +So, when reporting bugs related to features such as PSR and ABM, consider +enabling the relevant bits in the mask before reproducing the issue and +attach the log that you obtain from the trace buffer in any bug reports that you +create. diff --git a/Documentation/gpu/amdgpu/display/trace-groups-table.csv b/Documentation/gpu/amdgpu/display/trace-groups-table.csv new file mode 100644 index 000000000000..3f6a50d1d883 --- /dev/null +++ b/Documentation/gpu/amdgpu/display/trace-groups-table.csv @@ -0,0 +1,29 @@ +Name, Mask Value +INFO, 0x1 +IRQ SVC, 0x2 +VBIOS, 0x4 +REGISTER, 0x8 +PHY DBG, 0x10 +PSR, 0x20 +AUX, 0x40 +SMU, 0x80 +MALL, 0x100 +ABM, 0x200 +ALPM, 0x400 +TIMER, 0x800 +HW LOCK MGR, 0x1000 +INBOX1, 0x2000 +PHY SEQ, 0x4000 +PSR STATE, 0x8000 +ZSTATE, 0x10000 +TRANSMITTER CTL, 0x20000 +PANEL CNTL, 0x40000 +FAMS, 0x80000 +DPIA, 0x100000 +SUBVP, 0x200000 +INBOX0, 0x400000 +SDP, 0x4000000 +REPLAY, 0x8000000 +REPLAY RESIDENCY, 0x20000000 +CURSOR INFO, 0x80000000 +IPS, 0x100000000 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 45c972f2630d..98b41ec7288e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -2971,6 +2971,104 @@ static int allow_edp_hotplug_detection_set(void *data, u64 val) return 0; } +static int dmub_trace_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = data; + struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub; + enum dmub_gpint_command cmd; + enum dmub_status status; + u64 mask = 0xffff; + u8 shift = 0; + u32 res; + int i; + + if (!srv->fw_version) + return -EINVAL; + + for (i = 0; i < 4; i++) { + res = (val & mask) >> shift; + + switch (i) { + case 0: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0; + break; + case 1: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1; + break; + case 2: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD2; + break; + case 3: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD3; + break; + } + + status = dmub_srv_send_gpint_command(srv, cmd, res, 30); + + if (status == DMUB_STATUS_TIMEOUT) + return -ETIMEDOUT; + else if (status == DMUB_STATUS_INVALID) + return -EINVAL; + else if (status != DMUB_STATUS_OK) + return -EIO; + + usleep_range(100, 1000); + + mask <<= 16; + shift += 16; + } + + return 0; +} + +static int dmub_trace_mask_show(void *data, u64 *val) +{ + enum dmub_gpint_command cmd = DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD0; + struct amdgpu_device *adev = data; + struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub; + enum dmub_status status; + u8 shift = 0; + u64 raw = 0; + u64 res = 0; + int i = 0; + + if (!srv->fw_version) + return -EINVAL; + + while (i < 4) { + status = dmub_srv_send_gpint_command(srv, cmd, 0, 30); + + if (status == DMUB_STATUS_OK) { + status = dmub_srv_get_gpint_response(srv, (u32 *) &raw); + + if (status == DMUB_STATUS_INVALID) + return -EINVAL; + else if (status != DMUB_STATUS_OK) + return -EIO; + } else if (status == DMUB_STATUS_TIMEOUT) { + return -ETIMEDOUT; + } else if (status == DMUB_STATUS_INVALID) { + return -EINVAL; + } else { + return -EIO; + } + + usleep_range(100, 1000); + + cmd++; + res |= (raw << shift); + shift += 16; + i++; + } + + *val = res; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(dmub_trace_mask_fops, dmub_trace_mask_show, + dmub_trace_mask_set, "0x%llx\n"); + /* * Set dmcub trace event IRQ enable or disable. * Usage to enable dmcub trace event IRQ: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en @@ -3884,6 +3982,9 @@ void dtn_debugfs_init(struct amdgpu_device *adev) debugfs_create_file_unsafe("amdgpu_dm_force_timing_sync", 0644, root, adev, &force_timing_sync_ops); + debugfs_create_file_unsafe("amdgpu_dm_dmub_trace_mask", 0644, root, + adev, &dmub_trace_mask_fops); + debugfs_create_file_unsafe("amdgpu_dm_dmcub_trace_event_en", 0644, root, adev, &dmcub_trace_event_state_fops); diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index ed4379c04715..aa6e6923afed 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -818,18 +818,54 @@ enum dmub_gpint_command { * RETURN: Lower 32-bit mask. */ DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK = 101, + /** - * DESC: Updates the trace buffer lower 32-bit mask. + * DESC: Updates the trace buffer mask bit0~bit15. * ARGS: The new mask * RETURN: Lower 32-bit mask. */ DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0 = 102, + /** - * DESC: Updates the trace buffer mask bi0~bit15. + * DESC: Updates the trace buffer mask bit16~bit31. * ARGS: The new mask * RETURN: Lower 32-bit mask. */ DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1 = 103, + + /** + * DESC: Updates the trace buffer mask bit32~bit47. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD2 = 114, + + /** + * DESC: Updates the trace buffer mask bit48~bit63. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD3 = 115, + + /** + * DESC: Read the trace buffer mask bi0~bit15. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD0 = 116, + + /** + * DESC: Read the trace buffer mask bit16~bit31. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD1 = 117, + + /** + * DESC: Read the trace buffer mask bi32~bit47. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD2 = 118, + + /** + * DESC: Updates the trace buffer mask bit32~bit63. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD3 = 119, }; /** From 8b8eed05a1c650c27e78bc47d07f7d6c9ba779e8 Mon Sep 17 00:00:00 2001 From: Mounika Adhuri Date: Fri, 6 Oct 2023 15:05:42 +0530 Subject: [PATCH 0813/7721] drm/amd/display: Refactor resource into component directory [WHY] Move all resource files to unique folder resource. [HOW] Created resource folder in dc, moved the dcnxx_resource.c and dcnxx_resource.h files into corresponding new folders inside the resource and made appropriate changes for compilation in Makefiles. Reviewed-by: Martin Leung Acked-by: Alex Hung Signed-off-by: Mounika Adhuri Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Makefile | 1 + .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- drivers/gpu/drm/amd/display/dc/Makefile | 5 +- .../gpu/drm/amd/display/dc/core/dc_resource.c | 4 +- .../gpu/drm/amd/display/dc/dce100/Makefile | 46 ---- .../gpu/drm/amd/display/dc/dce110/Makefile | 4 +- .../gpu/drm/amd/display/dc/dce112/Makefile | 3 +- .../gpu/drm/amd/display/dc/dce120/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dce80/Makefile | 3 +- drivers/gpu/drm/amd/display/dc/dcn10/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn20/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn201/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn21/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn30/Makefile | 1 - .../gpu/drm/amd/display/dc/dcn301/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn302/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn303/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn31/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn314/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn315/Makefile | 30 --- .../gpu/drm/amd/display/dc/dcn316/Makefile | 30 --- drivers/gpu/drm/amd/display/dc/dcn32/Makefile | 2 +- .../display/dc/dcn32/dcn32_resource_helpers.c | 2 +- .../gpu/drm/amd/display/dc/dcn321/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn35/Makefile | 2 +- .../drm/amd/display/dc/dml/calcs/dcn_calcs.c | 2 +- .../gpu/drm/amd/display/dc/resource/Makefile | 199 ++++++++++++++++++ .../{ => resource}/dce100/dce100_resource.c | 0 .../{ => resource}/dce100/dce100_resource.h | 0 .../{ => resource}/dce110/dce110_resource.c | 0 .../{ => resource}/dce110/dce110_resource.h | 0 .../{ => resource}/dce112/dce112_resource.c | 0 .../{ => resource}/dce112/dce112_resource.h | 0 .../{ => resource}/dce120/dce120_resource.c | 2 +- .../{ => resource}/dce120/dce120_resource.h | 0 .../display/dc/resource/dce80/CMakeLists.txt | 4 + .../dc/{ => resource}/dce80/dce80_resource.c | 0 .../dc/{ => resource}/dce80/dce80_resource.h | 0 .../dc/{ => resource}/dcn10/dcn10_resource.c | 25 ++- .../dc/{ => resource}/dcn10/dcn10_resource.h | 0 .../dc/{ => resource}/dcn20/dcn20_resource.c | 24 +-- .../dc/{ => resource}/dcn20/dcn20_resource.h | 0 .../{ => resource}/dcn201/dcn201_resource.c | 14 +- .../{ => resource}/dcn201/dcn201_resource.h | 0 .../dc/{ => resource}/dcn21/dcn21_resource.c | 6 +- .../dc/{ => resource}/dcn21/dcn21_resource.h | 0 .../dc/{ => resource}/dcn30/dcn30_resource.c | 2 +- .../dc/{ => resource}/dcn30/dcn30_resource.h | 0 .../{ => resource}/dcn301/dcn301_resource.c | 4 +- .../{ => resource}/dcn301/dcn301_resource.h | 0 .../{ => resource}/dcn302/dcn302_resource.c | 4 +- .../{ => resource}/dcn302/dcn302_resource.h | 0 .../{ => resource}/dcn303/dcn303_resource.c | 4 +- .../{ => resource}/dcn303/dcn303_resource.h | 0 .../dc/{ => resource}/dcn31/dcn31_resource.c | 2 +- .../dc/{ => resource}/dcn31/dcn31_resource.h | 0 .../{ => resource}/dcn314/dcn314_resource.c | 0 .../{ => resource}/dcn314/dcn314_resource.h | 0 .../{ => resource}/dcn315/dcn315_resource.c | 0 .../{ => resource}/dcn315/dcn315_resource.h | 0 .../{ => resource}/dcn316/dcn316_resource.c | 0 .../{ => resource}/dcn316/dcn316_resource.h | 0 .../dc/{ => resource}/dcn32/dcn32_resource.c | 4 +- .../dc/{ => resource}/dcn32/dcn32_resource.h | 0 .../{ => resource}/dcn321/dcn321_resource.c | 2 +- .../{ => resource}/dcn321/dcn321_resource.h | 0 .../dc/{ => resource}/dcn35/dcn35_resource.c | 2 +- .../dc/{ => resource}/dcn35/dcn35_resource.h | 0 68 files changed, 276 insertions(+), 181 deletions(-) delete mode 100644 drivers/gpu/drm/amd/display/dc/dce100/Makefile delete mode 100644 drivers/gpu/drm/amd/display/dc/dcn315/Makefile delete mode 100644 drivers/gpu/drm/amd/display/dc/dcn316/Makefile create mode 100644 drivers/gpu/drm/amd/display/dc/resource/Makefile rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce100/dce100_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce100/dce100_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce110/dce110_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce110/dce110_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce112/dce112_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce112/dce112_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce120/dce120_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce120/dce120_resource.h (100%) create mode 100644 drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce80/dce80_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dce80/dce80_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn10/dcn10_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn10/dcn10_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn20/dcn20_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn20/dcn20_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn201/dcn201_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn201/dcn201_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn21/dcn21_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn21/dcn21_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn30/dcn30_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn30/dcn30_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn301/dcn301_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn301/dcn301_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn302/dcn302_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn302/dcn302_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn303/dcn303_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn303/dcn303_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn31/dcn31_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn31/dcn31_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn314/dcn314_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn314/dcn314_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn315/dcn315_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn315/dcn315_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn316/dcn316_resource.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn316/dcn316_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn32/dcn32_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn32/dcn32_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn321/dcn321_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn321/dcn321_resource.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn35/dcn35_resource.c (99%) rename drivers/gpu/drm/amd/display/dc/{ => resource}/dcn35/dcn35_resource.h (100%) diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index af17ab8027df..71192fc81a20 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -30,6 +30,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/clk_mgr subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hwss +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/resource subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 11da0eebee6c..ec87e31c6fe8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -44,7 +44,7 @@ #include "amdgpu_dm_debugfs.h" #endif -#include "dc/dcn20/dcn20_resource.h" +#include "dc/resource/dcn20/dcn20_resource.h" #define PEAK_FACTOR_X1000 1006 diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 3a169b78e7e4..ab51a065cf0e 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -22,7 +22,7 @@ # # Makefile for Display Core (dc) component. -DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc +DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc resource ifdef CONFIG_DRM_AMD_DC_FP @@ -38,8 +38,6 @@ DC_LIBS += dcn302 DC_LIBS += dcn303 DC_LIBS += dcn31 DC_LIBS += dcn314 -DC_LIBS += dcn315 -DC_LIBS += dcn316 DC_LIBS += dcn32 DC_LIBS += dcn321 DC_LIBS += dcn35 @@ -51,7 +49,6 @@ DC_LIBS += dce120 DC_LIBS += dce112 DC_LIBS += dce110 -DC_LIBS += dce100 DC_LIBS += dce80 ifdef CONFIG_DRM_AMD_DC_SI diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index a1f1d1003992..6159d819c5c5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -69,8 +69,8 @@ #include "dcn314/dcn314_resource.h" #include "dcn315/dcn315_resource.h" #include "dcn316/dcn316_resource.h" -#include "../dcn32/dcn32_resource.h" -#include "../dcn321/dcn321_resource.h" +#include "dcn32/dcn32_resource.h" +#include "dcn321/dcn321_resource.h" #include "dcn35/dcn35_resource.h" #define VISUAL_CONFIRM_BASE_DEFAULT 3 diff --git a/drivers/gpu/drm/amd/display/dc/dce100/Makefile b/drivers/gpu/drm/amd/display/dc/dce100/Makefile deleted file mode 100644 index 0d2f6bbf7558..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright 2017 Advanced Micro Devices, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# -# Makefile for the 'controller' sub-component of DAL. -# It provides the control and status of HW CRTC block. - -CFLAGS_$(AMDDALPATH)/dc/dce100/dce100_resource.o = $(call cc-disable-warning, override-init) - -DCE100 = dce100_resource.o - -AMD_DAL_DCE100 = $(addprefix $(AMDDALPATH)/dc/dce100/,$(DCE100)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCE100) - - -############################################################################### -# DCE 10x -############################################################################### -ifdef 0#CONFIG_DRM_AMD_DC_DCE11_0 -TG_DCE100 = dce100_resource.o - -AMD_DAL_TG_DCE100 = $(addprefix \ - $(AMDDALPATH)/dc/dce100/,$(TG_DCE100)) - -AMD_DISPLAY_FILES += $(AMD_DAL_TG_DCE100) -endif - diff --git a/drivers/gpu/drm/amd/display/dc/dce110/Makefile b/drivers/gpu/drm/amd/display/dc/dce110/Makefile index 695a50ed5ad2..f0777d61c2cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce110/Makefile @@ -26,8 +26,8 @@ CFLAGS_$(AMDDALPATH)/dc/dce110/dce110_resource.o = $(call cc-disable-warning, override-init) DCE110 = dce110_timing_generator.o \ -dce110_compressor.o dce110_resource.o \ -dce110_opp_regamma_v.o dce110_opp_csc_v.o dce110_timing_generator_v.o \ +dce110_compressor.o dce110_opp_regamma_v.o \ +dce110_opp_csc_v.o dce110_timing_generator_v.o \ dce110_mem_input_v.o dce110_opp_v.o dce110_transform_v.o AMD_DAL_DCE110 = $(addprefix $(AMDDALPATH)/dc/dce110/,$(DCE110)) diff --git a/drivers/gpu/drm/amd/display/dc/dce112/Makefile b/drivers/gpu/drm/amd/display/dc/dce112/Makefile index e846ef58cab3..7e92effec894 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce112/Makefile @@ -25,8 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce112/dce112_resource.o = $(call cc-disable-warning, override-init) -DCE112 = dce112_compressor.o \ -dce112_resource.o +DCE112 = dce112_compressor.o AMD_DAL_DCE112 = $(addprefix $(AMDDALPATH)/dc/dce112/,$(DCE112)) diff --git a/drivers/gpu/drm/amd/display/dc/dce120/Makefile b/drivers/gpu/drm/amd/display/dc/dce120/Makefile index 097cf407a15d..1e3ef68a452a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce120/Makefile @@ -26,7 +26,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce120/dce120_resource.o = $(call cc-disable-warning, override-init) -DCE120 = dce120_resource.o dce120_timing_generator.o \ +DCE120 = dce120_timing_generator.o AMD_DAL_DCE120 = $(addprefix $(AMDDALPATH)/dc/dce120/,$(DCE120)) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/Makefile b/drivers/gpu/drm/amd/display/dc/dce80/Makefile index 93dd68c31275..7eefffbdc925 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce80/Makefile @@ -25,8 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce80/dce80_resource.o = $(call cc-disable-warning, override-init) -DCE80 = dce80_timing_generator.o \ - dce80_resource.o +DCE80 = dce80_timing_generator.o AMD_DAL_DCE80 = $(addprefix $(AMDDALPATH)/dc/dce80/,$(DCE80)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 2d2007c3e2b6..1eb7418ced3a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -22,7 +22,7 @@ # # Makefile for DCN. -DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o \ +DCN10 = dcn10_init.o dcn10_ipp.o \ dcn10_hw_sequencer_debug.o \ dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ dcn10_hubp.o dcn10_mpc.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index d7dc9696a8c8..1cac1eca8111 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -2,7 +2,7 @@ # # Makefile for DCN. -DCN20 = dcn20_resource.o dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ +DCN20 = dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile index 3a41a97b0729..c069a894db92 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # # Makefile for DCN. -DCN201 = dcn201_init.o dcn201_resource.o \ +DCN201 = dcn201_init.o \ dcn201_hubbub.o\ dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_optc.o dcn201_dpp.o \ dcn201_dccg.o dcn201_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile index ce1be0afae4a..dd1eea7212f4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -2,7 +2,7 @@ # # Makefile for DCN21. -DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o \ +DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o \ dcn21_link_encoder.o dcn21_dccg.o AMD_DAL_DCN21 = $(addprefix $(AMDDALPATH)/dc/dcn21/,$(DCN21)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile index af4d2065d2c1..9dcf06c0954d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile @@ -38,7 +38,6 @@ DCN30 := \ dcn30_dwb_cm.o \ dcn30_cm_common.o \ dcn30_mmhubbub.o \ - dcn30_resource.o \ dcn30_dio_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile index 30fbc5e06dca..cbf59d7e78c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn30. -DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \ +DCN301 = dcn301_init.o dcn301_dccg.o \ dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o \ dcn301_optc.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile index 95b66baf39e9..0fcd03569d74 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile @@ -5,7 +5,7 @@ # # Makefile for dcn302. -DCN3_02 = dcn302_init.o dcn302_resource.o +DCN3_02 = dcn302_init.o AMD_DAL_DCN3_02 = $(addprefix $(AMDDALPATH)/dc/dcn302/,$(DCN3_02)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile index d7b3ad780e5d..a954e316aca2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile @@ -6,7 +6,7 @@ # # Makefile for dcn303. -DCN3_03 = dcn303_init.o dcn303_resource.o +DCN3_03 = dcn303_init.o AMD_DAL_DCN3_03 = $(addprefix $(AMDDALPATH)/dc/dcn303/,$(DCN3_03)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile index 96e45c9efb46..212287008c0a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn31. -DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_init.o dcn31_hubp.o \ +DCN31 = dcn31_hubbub.o dcn31_init.o dcn31_hubp.o \ dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o \ dcn31_afmt.o dcn31_vpg.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile index 72456debb99f..6ea47e00d62d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn314. -DCN314 = dcn314_resource.o dcn314_init.o \ +DCN314 = dcn314_init.o \ dcn314_dio_stream_encoder.o dcn314_dccg.o dcn314_optc.o AMD_DAL_DCN314 = $(addprefix $(AMDDALPATH)/dc/dcn314/,$(DCN314)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/Makefile b/drivers/gpu/drm/amd/display/dc/dcn315/Makefile deleted file mode 100644 index 59381d24800b..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn315/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright © 2021 Advanced Micro Devices, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# Authors: AMD -# -# Makefile for dcn315. - -DCN315 = dcn315_resource.o - -AMD_DAL_DCN315 = $(addprefix $(AMDDALPATH)/dc/dcn315/,$(DCN315)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCN315) diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/Makefile b/drivers/gpu/drm/amd/display/dc/dcn316/Makefile deleted file mode 100644 index 819d44a9439b..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn316/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright 2021 Advanced Micro Devices, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# Authors: AMD -# -# Makefile for dcn316. - -DCN316 = dcn316_resource.o - -AMD_DAL_DCN316 = $(addprefix $(AMDDALPATH)/dc/dcn316/,$(DCN316)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCN316) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile index 8bb251307247..3bb17dd01e4c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn32. -DCN32 = dcn32_resource.o dcn32_hubbub.o dcn32_init.o dcn32_dccg.o \ +DCN32 = dcn32_hubbub.o dcn32_init.o dcn32_dccg.o \ dcn32_dccg.o dcn32_optc.o dcn32_mmhubbub.o dcn32_hubp.o dcn32_dpp.o \ dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_hpo_dp_link_encoder.o \ dcn32_resource_helpers.o dcn32_mpc.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index bc5f0db23d0c..ef0a2b01734d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -24,7 +24,7 @@ */ // header file of functions being implemented -#include "dcn32_resource.h" +#include "dcn32/dcn32_resource.h" #include "dcn20/dcn20_resource.h" #include "dml/dcn32/display_mode_vba_util_32.h" #include "dml/dcn32/dcn32_fpu.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile index 0a199c83bb5b..c195c47f58b4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn321. -DCN321 = dcn321_resource.o dcn321_dio_link_encoder.o +DCN321 = dcn321_dio_link_encoder.o AMD_DAL_DCN321 = $(addprefix $(AMDDALPATH)/dc/dcn321/,$(DCN321)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile index 20d0eef1a13b..719afb5a3b12 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile @@ -10,7 +10,7 @@ # # Makefile for DCN35. -DCN35 = dcn35_resource.o dcn35_init.o dcn35_dio_stream_encoder.o \ +DCN35 = dcn35_init.o dcn35_dio_stream_encoder.o \ dcn35_dio_link_encoder.o dcn35_dccg.o dcn35_optc.o \ dcn35_dsc.o dcn35_hubp.o dcn35_hubbub.o \ dcn35_mmhubbub.o dcn35_opp.o dcn35_dpp.o dcn35_pg_cntl.o dcn35_dwb.o diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index 50b0434354f8..0c4a8fe8e5ca 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -30,7 +30,7 @@ #include "dcn_calc_auto.h" #include "dal_asic_id.h" #include "resource.h" -#include "dcn10/dcn10_resource.h" +#include "resource/dcn10/dcn10_resource.h" #include "dcn10/dcn10_hubbub.h" #include "dml/dml1_display_rq_dlg_calc.h" diff --git a/drivers/gpu/drm/amd/display/dc/resource/Makefile b/drivers/gpu/drm/amd/display/dc/resource/Makefile new file mode 100644 index 000000000000..0a75ed8962a5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/Makefile @@ -0,0 +1,199 @@ + +# Copyright 2022 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Makefile for the 'resource' sub-component of DAL. +# + + +############################################################################### +# DCE +############################################################################### + +RESOURCE_DCE100 = dce100_resource.o + +AMD_DAL_RESOURCE_DCE100 = $(addprefix $(AMDDALPATH)/dc/resource/dce100/,$(RESOURCE_DCE100)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE100) + +############################################################################### + +RESOURCE_DCE110 = dce110_resource.o + +AMD_DAL_RESOURCE_DCE110 = $(addprefix $(AMDDALPATH)/dc/resource/dce110/,$(RESOURCE_DCE110)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE110) + +############################################################################### + +RESOURCE_DCE112 = dce112_resource.o + +AMD_DAL_RESOURCE_DCE112 = $(addprefix $(AMDDALPATH)/dc/resource/dce112/,$(RESOURCE_DCE112)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE112) + +############################################################################### + +RESOURCE_DCE120 = dce120_resource.o + +AMD_DAL_RESOURCE_DCE120 = $(addprefix $(AMDDALPATH)/dc/resource/dce120/,$(RESOURCE_DCE120)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE120) + +############################################################################### + +RESOURCE_DCE80 = dce80_resource.o + +AMD_DAL_RESOURCE_DCE80 = $(addprefix $(AMDDALPATH)/dc/resource/dce80/,$(RESOURCE_DCE80)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE80) + +ifdef CONFIG_DRM_AMD_DC_FP +############################################################################### +# DCN +############################################################################### + +RESOURCE_DCN10 = dcn10_resource.o + +AMD_DAL_RESOURCE_DCN10 = $(addprefix $(AMDDALPATH)/dc/resource/dcn10/,$(RESOURCE_DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN10) + +############################################################################### + +RESOURCE_DCN20 = dcn20_resource.o + +AMD_DAL_RESOURCE_DCN20 = $(addprefix $(AMDDALPATH)/dc/resource/dcn20/,$(RESOURCE_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN20) + +############################################################################### + +RESOURCE_DCN201 = dcn201_resource.o + +AMD_DAL_RESOURCE_DCN201 = $(addprefix $(AMDDALPATH)/dc/resource/dcn201/,$(RESOURCE_DCN201)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN201) + +############################################################################### + +RESOURCE_DCN21 = dcn21_resource.o + +AMD_DAL_RESOURCE_DCN21 = $(addprefix $(AMDDALPATH)/dc/resource/dcn21/,$(RESOURCE_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN21) + +############################################################################### + +############################################################################### + +############################################################################### + +RESOURCE_DCN30 = dcn30_resource.o + +AMD_DAL_RESOURCE_DCN30 = $(addprefix $(AMDDALPATH)/dc/resource/dcn30/,$(RESOURCE_DCN30)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN30) + +############################################################################### + +RESOURCE_DCN301 = dcn301_resource.o + +AMD_DAL_RESOURCE_DCN301 = $(addprefix $(AMDDALPATH)/dc/resource/dcn301/,$(RESOURCE_DCN301)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN301) + +############################################################################### + +RESOURCE_DCN302 = dcn302_resource.o + +AMD_DAL_RESOURCE_DCN302 = $(addprefix $(AMDDALPATH)/dc/resource/dcn302/,$(RESOURCE_DCN302)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN302) + +############################################################################### + +RESOURCE_DCN303 = dcn303_resource.o + +AMD_DAL_RESOURCE_DCN303 = $(addprefix $(AMDDALPATH)/dc/resource/dcn303/,$(RESOURCE_DCN303)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN303) + +############################################################################### + +RESOURCE_DCN31 = dcn31_resource.o + +AMD_DAL_RESOURCE_DCN31 = $(addprefix $(AMDDALPATH)/dc/resource/dcn31/,$(RESOURCE_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN31) + +############################################################################### + +RESOURCE_DCN314 = dcn314_resource.o + +AMD_DAL_RESOURCE_DCN314 = $(addprefix $(AMDDALPATH)/dc/resource/dcn314/,$(RESOURCE_DCN314)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN314) + +############################################################################### + +RESOURCE_DCN315 = dcn315_resource.o + +AMD_DAL_RESOURCE_DCN315 = $(addprefix $(AMDDALPATH)/dc/resource/dcn315/,$(RESOURCE_DCN315)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN315) + +############################################################################### + +RESOURCE_DCN316 = dcn316_resource.o + +AMD_DAL_RESOURCE_DCN316 = $(addprefix $(AMDDALPATH)/dc/resource/dcn316/,$(RESOURCE_DCN316)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN316) + +############################################################################### + +RESOURCE_DCN32 = dcn32_resource.o + +AMD_DAL_RESOURCE_DCN32 = $(addprefix $(AMDDALPATH)/dc/resource/dcn32/,$(RESOURCE_DCN32)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN32) + +############################################################################### + +RESOURCE_DCN321 = dcn321_resource.o + +AMD_DAL_RESOURCE_DCN321 = $(addprefix $(AMDDALPATH)/dc/resource/dcn321/,$(RESOURCE_DCN321)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN321) + +############################################################################### + +RESOURCE_DCN35 = dcn35_resource.o + +AMD_DAL_RESOURCE_DCN35 = $(addprefix $(AMDDALPATH)/dc/resource/dcn35/,$(RESOURCE_DCN35)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN35) + +############################################################################### + +############################################################################### + +endif diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c index 962de79be169..20662edd0ae4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c @@ -36,7 +36,7 @@ #include "dce110/dce110_resource.h" #include "virtual/virtual_stream_encoder.h" -#include "dce120_timing_generator.h" +#include "dce120/dce120_timing_generator.h" #include "irq/dce120/irq_service_dce120.h" #include "dce/dce_opp.h" #include "dce/dce_clock_source.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt b/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt new file mode 100644 index 000000000000..19dd73bc9ab0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt @@ -0,0 +1,4 @@ +dal3_subdirectory_sources( + dce80_resource.c + dce80_resource.h + ) \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index b94c5c97eee7..af1b31f4e69a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -26,29 +26,32 @@ #include "dm_services.h" #include "dc.h" -#include "dcn10_init.h" +#include "dcn10/dcn10_init.h" #include "resource.h" #include "include/irq_service_interface.h" -#include "dcn10_resource.h" -#include "dcn10_ipp.h" -#include "dcn10_mpc.h" +#include "dcn10/dcn10_resource.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn10/dcn10_mpc.h" + +#include "dcn10/dcn10_dwb.h" + #include "irq/dcn10/irq_service_dcn10.h" -#include "dcn10_dpp.h" -#include "dcn10_optc.h" +#include "dcn10/dcn10_dpp.h" +#include "dcn10/dcn10_optc.h" #include "dcn10/dcn10_hwseq.h" #include "dce110/dce110_hwseq.h" -#include "dcn10_opp.h" -#include "dcn10_link_encoder.h" -#include "dcn10_stream_encoder.h" +#include "dcn10/dcn10_opp.h" +#include "dcn10/dcn10_link_encoder.h" +#include "dcn10/dcn10_stream_encoder.h" #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dce112/dce112_resource.h" -#include "dcn10_hubp.h" -#include "dcn10_hubbub.h" +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_hubbub.h" #include "dce/dce_panel_cntl.h" #include "soc15_hw_ip.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index 0a422fbb14bc..f04bb5b1471d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -29,7 +29,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn20_init.h" +#include "dcn20/dcn20_init.h" #include "resource.h" #include "include/irq_service_interface.h" @@ -39,29 +39,29 @@ #include "dcn10/dcn10_hubp.h" #include "dcn10/dcn10_ipp.h" -#include "dcn20_hubbub.h" -#include "dcn20_mpc.h" -#include "dcn20_hubp.h" +#include "dcn20/dcn20_hubbub.h" +#include "dcn20/dcn20_mpc.h" +#include "dcn20/dcn20_hubp.h" #include "irq/dcn20/irq_service_dcn20.h" -#include "dcn20_dpp.h" -#include "dcn20_optc.h" +#include "dcn20/dcn20_dpp.h" +#include "dcn20/dcn20_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dce110/dce110_hwseq.h" #include "dcn10/dcn10_resource.h" -#include "dcn20_opp.h" +#include "dcn20/dcn20_opp.h" -#include "dcn20_dsc.h" +#include "dcn20/dcn20_dsc.h" -#include "dcn20_link_encoder.h" -#include "dcn20_stream_encoder.h" +#include "dcn20/dcn20_link_encoder.h" +#include "dcn20/dcn20_stream_encoder.h" #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" -#include "dcn20_dccg.h" -#include "dcn20_vmid.h" +#include "dcn20/dcn20_dccg.h" +#include "dcn20/dcn20_vmid.h" #include "dce/dce_panel_cntl.h" #include "navi10_ip_offset.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c index bca22d867696..914b234d7f6b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -26,7 +26,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn201_init.h" +#include "dcn201/dcn201_init.h" #include "dml/dcn20/dcn20_fpu.h" #include "resource.h" #include "include/irq_service_interface.h" @@ -36,16 +36,16 @@ #include "dcn10/dcn10_hubp.h" #include "dcn10/dcn10_ipp.h" -#include "dcn201_mpc.h" -#include "dcn201_hubp.h" +#include "dcn201/dcn201_mpc.h" +#include "dcn201/dcn201_hubp.h" #include "irq/dcn201/irq_service_dcn201.h" #include "dcn201/dcn201_dpp.h" #include "dcn201/dcn201_hubbub.h" -#include "dcn201_dccg.h" -#include "dcn201_optc.h" +#include "dcn201/dcn201_dccg.h" +#include "dcn201/dcn201_optc.h" #include "dcn201/dcn201_hwseq.h" #include "dce110/dce110_hwseq.h" -#include "dcn201_opp.h" +#include "dcn201/dcn201_opp.h" #include "dcn201/dcn201_link_encoder.h" #include "dcn20/dcn20_stream_encoder.h" #include "dce/dce_clock_source.h" @@ -55,7 +55,7 @@ #include "dce110/dce110_resource.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" -#include "dcn201_hubbub.h" +#include "dcn201/dcn201_hubbub.h" #include "dcn10/dcn10_resource.h" #include "cyan_skillfish_ip_offset.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index 42277b280586..c07da45e1e2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -29,7 +29,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn21_init.h" +#include "dcn21/dcn21_init.h" #include "resource.h" #include "include/irq_service_interface.h" @@ -44,7 +44,7 @@ #include "dcn20/dcn20_hubbub.h" #include "dcn20/dcn20_mpc.h" #include "dcn20/dcn20_hubp.h" -#include "dcn21_hubp.h" +#include "dcn21/dcn21_hubp.h" #include "irq/dcn21/irq_service_dcn21.h" #include "dcn20/dcn20_dpp.h" #include "dcn20/dcn20_optc.h" @@ -61,7 +61,7 @@ #include "dml/display_mode_vba.h" #include "dcn20/dcn20_dccg.h" #include "dcn21/dcn21_dccg.h" -#include "dcn21_hubbub.h" +#include "dcn21/dcn21_hubbub.h" #include "dcn10/dcn10_resource.h" #include "dce/dce_panel_cntl.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 7b259cb5f418..2b6dcb489b90 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -27,7 +27,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn30_init.h" +#include "dcn30/dcn30_init.h" #include "resource.h" #include "include/irq_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index f3b75f283aa2..511ff6b5b985 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -27,7 +27,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn301_init.h" +#include "dcn301/dcn301_init.h" #include "resource.h" #include "include/irq_service_interface.h" @@ -61,7 +61,7 @@ #include "dcn10/dcn10_resource.h" #include "dcn30/dcn30_dio_stream_encoder.h" #include "dcn301/dcn301_dio_link_encoder.h" -#include "dcn301_panel_cntl.h" +#include "dcn301/dcn301_panel_cntl.h" #include "vangogh_ip_offset.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index 63ac984a04f7..5791b5cc2875 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -23,9 +23,9 @@ * */ -#include "dcn302_init.h" +#include "dcn302/dcn302_init.h" #include "dcn302_resource.h" -#include "dcn302_dccg.h" +#include "dcn302/dcn302_dccg.h" #include "irq/dcn302/irq_service_dcn302.h" #include "dcn30/dcn30_dio_link_encoder.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index 49cb7fde416a..25cd6236b054 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -23,9 +23,9 @@ * Authors: AMD */ -#include "dcn303_init.h" +#include "dcn303/dcn303_init.h" #include "dcn303_resource.h" -#include "dcn303_dccg.h" +#include "dcn303/dcn303_dccg.h" #include "irq/dcn303/irq_service_dcn303.h" #include "dcn30/dcn30_dio_link_encoder.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 79416cfb22f0..31035fc3d868 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -70,7 +70,7 @@ #include "dml/dcn31/dcn31_fpu.h" #include "dcn31/dcn31_dccg.h" #include "dcn10/dcn10_resource.h" -#include "dcn31_panel_cntl.h" +#include "dcn31/dcn31_panel_cntl.h" #include "dcn30/dcn30_dwb.h" #include "dcn30/dcn30_mmhubbub.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index 89b072447dba..36e4c7bef403 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -27,7 +27,7 @@ #include "dm_services.h" #include "dc.h" -#include "dcn32_init.h" +#include "dcn32/dcn32_init.h" #include "resource.h" #include "include/irq_service_interface.h" @@ -41,7 +41,7 @@ #include "dcn31/dcn31_hubbub.h" #include "dcn32/dcn32_hubbub.h" #include "dcn32/dcn32_mpc.h" -#include "dcn32_hubp.h" +#include "dcn32/dcn32_hubp.h" #include "irq/dcn32/irq_service_dcn32.h" #include "dcn32/dcn32_dpp.h" #include "dcn32/dcn32_optc.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index f7de3eca1225..bedb70b98162 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -63,7 +63,7 @@ #include "dcn31/dcn31_apg.h" #include "dcn31/dcn31_dio_link_encoder.h" #include "dcn32/dcn32_dio_link_encoder.h" -#include "dcn321_dio_link_encoder.h" +#include "dcn321/dcn321_dio_link_encoder.h" #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c rename to drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 7a3faf2b1f06..a4027bf053c5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -78,7 +78,7 @@ #include "dcn10/dcn10_resource.h" #include "dcn31/dcn31_panel_cntl.h" #include "dcn35/dcn35_hwseq.h" -#include "dcn35_dio_link_encoder.h" +#include "dcn35/dcn35_dio_link_encoder.h" #include "dml/dcn31/dcn31_fpu.h" /*todo*/ #include "dml/dcn35/dcn35_fpu.h" #include "dcn35/dcn35_dwb.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.h rename to drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h From 68cfc5d8e459f50e5f46dca3b0f3c97a75f39975 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 20 Oct 2023 16:26:19 -0400 Subject: [PATCH 0814/7721] drm/amd/display: Try to acquire a free OTG master not used in cur ctx first [WHY & HOW] The current otg master pipe allocation logic is not optimized based current resource context. We should try to acquire a free OTG master not used in cur cts first to avoid unnecessary pipe switch from current state. Acked-by: Alex Hung Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 6159d819c5c5..49f8c90f0d2b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -3586,6 +3586,7 @@ static void mark_seamless_boot_stream( * |________|_______________|___________|_____________| */ static bool acquire_otg_master_pipe_for_stream( + const struct dc_state *cur_ctx, struct dc_state *new_ctx, const struct resource_pool *pool, struct dc_stream_state *stream) @@ -3599,7 +3600,10 @@ static bool acquire_otg_master_pipe_for_stream( int pipe_idx; struct pipe_ctx *pipe_ctx = NULL; - pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); + pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); + if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; memset(pipe_ctx, 0, sizeof(*pipe_ctx)); @@ -3659,7 +3663,7 @@ enum dc_status resource_map_pool_resources( if (!acquired) /* acquire new resources */ - acquired = acquire_otg_master_pipe_for_stream( + acquired = acquire_otg_master_pipe_for_stream(dc->current_state, context, pool, stream); pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); From 673d6d73eba79a1205ac403b68ef63da1c823da2 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Mon, 30 Oct 2023 15:21:12 -0400 Subject: [PATCH 0815/7721] drm/amd/display: Prefer currently used OTG master when acquiring free pipe [WHY & HOW] When acquiring an OTG master pipe we should prefer currently enabled OTG master pipes first. If there are no free pipes used as current OTG master pipe then we will try to acquire a currently unused free pipe as new OTG master instead of tearing down current secondary pipes from ODM or MPC combine. Reviewed-by: Alvin Lee Reviewed-by: Dillon Varone Acked-by: Alex Hung Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 37 ++++++++++++++++++- drivers/gpu/drm/amd/display/dc/inc/resource.h | 12 ++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 49f8c90f0d2b..42a927710743 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1764,6 +1764,29 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx( return free_pipe_idx; } +int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool) +{ + int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; + const struct pipe_ctx *new_pipe, *cur_pipe; + int i; + + for (i = 0; i < pool->pipe_count; i++) { + cur_pipe = &cur_res_ctx->pipe_ctx[i]; + new_pipe = &new_res_ctx->pipe_ctx[i]; + + if (resource_is_pipe_type(cur_pipe, OTG_MASTER) && + resource_is_pipe_type(new_pipe, FREE_PIPE)) { + free_pipe_idx = i; + break; + } + } + + return free_pipe_idx; +} + int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( const struct resource_context *cur_res_ctx, struct resource_context *new_res_ctx, @@ -3600,8 +3623,20 @@ static bool acquire_otg_master_pipe_for_stream( int pipe_idx; struct pipe_ctx *pipe_ctx = NULL; - pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + /* + * Upper level code is responsible to optimize unnecessary addition and + * removal for unchanged streams. So unchanged stream will keep the same + * OTG master instance allocated. When current stream is removed and a + * new stream is added, we want to reuse the OTG instance made available + * by the removed stream first. If not found, we try to avoid of using + * any free pipes already used in current context as this could tear + * down exiting ODM/MPC/MPO configuration unnecessarily. + */ + pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); + if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 06ca8bfb91e7..0458d2d749f4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -500,6 +500,18 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx( struct resource_context *new_res_ctx, const struct resource_pool *pool); +/* + * Look for a free pipe in new resource context that is used in current resource + * context as an OTG master pipe. + * + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ +int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool); + /* * Look for a free pipe in new resource context that is used as a secondary DPP * pipe in any MPCC combine in current resource context. From 5f70d4ff8095a2ad362d2a00eb8d9f7e20f3daa1 Mon Sep 17 00:00:00 2001 From: Daniel Miess Date: Thu, 12 Oct 2023 12:55:47 -0400 Subject: [PATCH 0816/7721] drm/amd/display: Enable DCN clock gating for DCN35 [WHY & HOW] Enable DCN clock gating for DCN35. Disable DTBCLK gate before link training and re-enable afterwards Reviewed-by: Nicholas Kazlauskas Acked-by: Alex Hung Signed-off-by: Daniel Miess Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 6 ++- .../gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c | 30 ++++++++++++++ .../gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h | 7 +++- .../drm/amd/display/dc/dcn35/dcn35_pg_cntl.c | 10 +---- .../drm/amd/display/dc/dcn35/dcn35_pg_cntl.h | 1 - .../drm/amd/display/dc/hwss/dce/dce_hwseq.h | 15 ++++++- .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 40 +++++++++++++------ .../gpu/drm/amd/display/dc/inc/hw/pg_cntl.h | 2 - .../dc/resource/dcn35/dcn35_resource.c | 16 +++++++- .../dc/resource/dcn35/dcn35_resource.h | 1 + .../include/asic_reg/dcn/dcn_3_5_0_sh_mask.h | 8 ++++ 11 files changed, 107 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index ab6d09c6fe34..76da59d8caaf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -291,7 +291,11 @@ type SYMCLKB_FE_SRC_SEL;\ type SYMCLKC_FE_SRC_SEL;\ type SYMCLKD_FE_SRC_SEL;\ - type SYMCLKE_FE_SRC_SEL; + type SYMCLKE_FE_SRC_SEL;\ + type DTBCLK_P0_GATE_DISABLE;\ + type DTBCLK_P1_GATE_DISABLE;\ + type DTBCLK_P2_GATE_DISABLE;\ + type DTBCLK_P3_GATE_DISABLE;\ struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c index 479f3683c0b7..142efd390d86 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c @@ -256,6 +256,21 @@ static void dccg35_set_dtbclk_dto( if (params->ref_dtbclk_khz && req_dtbclk_khz) { uint32_t modulo, phase; + switch (params->otg_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 1); + break; + case 1: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 1); + break; + case 2: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 1); + break; + case 3: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 1); + break; + } + // phase / modulo = dtbclk / dtbclk ref modulo = params->ref_dtbclk_khz * 1000; phase = req_dtbclk_khz * 1000; @@ -280,6 +295,21 @@ static void dccg35_set_dtbclk_dto( REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst], PIPE_DTO_SRC_SEL[params->otg_inst], 2); } else { + switch (params->otg_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 0); + break; + case 1: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 0); + break; + case 2: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 0); + break; + case 3: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 0); + break; + } + REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst], DTBCLK_DTO_ENABLE[params->otg_inst], 0, PIPE_DTO_SRC_SEL[params->otg_inst], params->is_hdmi ? 0 : 1); diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h index 423feb4c2f3f..bde48bee0119 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h @@ -34,6 +34,7 @@ #define DCCG_REG_LIST_DCN35() \ DCCG_REG_LIST_DCN314(),\ SR(DPPCLK_CTRL),\ + SR(DCCG_GATE_DISABLE_CNTL5),\ SR(DCCG_GATE_DISABLE_CNTL6),\ SR(DCCG_GLOBAL_FGCG_REP_CNTL),\ SR(SYMCLKA_CLOCK_ENABLE),\ @@ -174,7 +175,11 @@ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh) + DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\ struct dccg *dccg35_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c index 46f71ff08fd1..0f60c40e1fc5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c @@ -332,13 +332,6 @@ void pg_cntl35_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) pg_cntl->pg_res_enable[PG_DCIO] = power_on; } -void pg_cntl35_set_force_poweron_domain22(struct pg_cntl *pg_cntl, bool power_on) -{ - struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); - - REG_UPDATE(DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, power_on ? 1 : 0); -} - static bool pg_cntl35_plane_otg_status(struct pg_cntl *pg_cntl) { struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); @@ -508,8 +501,7 @@ static const struct pg_cntl_funcs pg_cntl35_funcs = { .mpcc_pg_control = pg_cntl35_mpcc_pg_control, .opp_pg_control = pg_cntl35_opp_pg_control, .optc_pg_control = pg_cntl35_optc_pg_control, - .dwb_pg_control = pg_cntl35_dwb_pg_control, - .set_force_poweron_domain22 = pg_cntl35_set_force_poweron_domain22 + .dwb_pg_control = pg_cntl35_dwb_pg_control }; struct pg_cntl *pg_cntl35_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h index 069dae08e222..3de240884d22 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h @@ -183,7 +183,6 @@ void pg_cntl35_optc_pg_control(struct pg_cntl *pg_cntl, unsigned int optc_inst, bool power_on); void pg_cntl35_dwb_pg_control(struct pg_cntl *pg_cntl, bool power_on); void pg_cntl35_init_pg_status(struct pg_cntl *pg_cntl); -void pg_cntl35_set_force_poweron_domain22(struct pg_cntl *pg_cntl, bool power_on); struct pg_cntl *pg_cntl35_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h index 44b4df6469d1..52f045cfd52a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h @@ -682,6 +682,7 @@ struct dce_hwseq_registers { uint32_t DCHUBBUB_ARB_HOSTVM_CNTL; uint32_t HPO_TOP_HW_CONTROL; uint32_t DMU_CLK_CNTL; + uint32_t DCCG_GATE_DISABLE_CNTL4; uint32_t DCCG_GATE_DISABLE_CNTL5; }; /* set field name */ @@ -1199,7 +1200,19 @@ struct dce_hwseq_registers { type PHYBSYMCLK_ROOT_GATE_DISABLE;\ type PHYCSYMCLK_ROOT_GATE_DISABLE;\ type PHYDSYMCLK_ROOT_GATE_DISABLE;\ - type PHYESYMCLK_ROOT_GATE_DISABLE; + type PHYESYMCLK_ROOT_GATE_DISABLE;\ + type DTBCLK_P0_GATE_DISABLE;\ + type DTBCLK_P1_GATE_DISABLE;\ + type DTBCLK_P2_GATE_DISABLE;\ + type DTBCLK_P3_GATE_DISABLE;\ + type DPSTREAMCLK0_GATE_DISABLE;\ + type DPSTREAMCLK1_GATE_DISABLE;\ + type DPSTREAMCLK2_GATE_DISABLE;\ + type DPSTREAMCLK3_GATE_DISABLE;\ + type DPIASYMCLK0_GATE_DISABLE;\ + type DPIASYMCLK1_GATE_DISABLE;\ + type DPIASYMCLK2_GATE_DISABLE;\ + type DPIASYMCLK3_GATE_DISABLE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 5a8258287438..39260371beb9 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -145,17 +145,36 @@ void dcn35_init_hw(struct dc *dc) hws->funcs.bios_golden_init(dc); } - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (!dc->debug.disable_clock_gate) { + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - /* Disable gating for PHYASYMCLK. This will be enabled in dccg if needed */ - REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, 1, - PHYBSYMCLK_ROOT_GATE_DISABLE, 1, - PHYCSYMCLK_ROOT_GATE_DISABLE, 1, - PHYDSYMCLK_ROOT_GATE_DISABLE, 1, - PHYESYMCLK_ROOT_GATE_DISABLE, 1); + /* Disable gating for PHYASYMCLK. This will be enabled in dccg if needed */ + REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, 1, + PHYBSYMCLK_ROOT_GATE_DISABLE, 1, + PHYCSYMCLK_ROOT_GATE_DISABLE, 1, + PHYDSYMCLK_ROOT_GATE_DISABLE, 1, + PHYESYMCLK_ROOT_GATE_DISABLE, 1); - REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0x1f7c3fcf); + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL4, + DPIASYMCLK0_GATE_DISABLE, 0, + DPIASYMCLK1_GATE_DISABLE, 0, + DPIASYMCLK2_GATE_DISABLE, 0, + DPIASYMCLK3_GATE_DISABLE, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0xFFFFFFFF); + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL5, + DTBCLK_P0_GATE_DISABLE, 0, + DTBCLK_P1_GATE_DISABLE, 0, + DTBCLK_P2_GATE_DISABLE, 0, + DTBCLK_P3_GATE_DISABLE, 0); + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL5, + DPSTREAMCLK0_GATE_DISABLE, 0, + DPSTREAMCLK1_GATE_DISABLE, 0, + DPSTREAMCLK2_GATE_DISABLE, 0, + DPSTREAMCLK3_GATE_DISABLE, 0); + + } // Initialize the dccg if (res_pool->dccg->funcs->dccg_init) @@ -332,9 +351,6 @@ void dcn35_init_hw(struct dc *dc) if (dc->res_pool->pg_cntl) { if (dc->res_pool->pg_cntl->funcs->init_pg_status) dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl); - - if (dc->res_pool->pg_cntl->funcs->set_force_poweron_domain22) - dc->res_pool->pg_cntl->funcs->set_force_poweron_domain22(dc->res_pool->pg_cntl, false); } } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h index b9812afb886b..00ea3864dd4d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h @@ -47,8 +47,6 @@ struct pg_cntl_funcs { void (*optc_pg_control)(struct pg_cntl *pg_cntl, unsigned int optc_inst, bool power_on); void (*dwb_pg_control)(struct pg_cntl *pg_cntl, bool power_on); void (*init_pg_status)(struct pg_cntl *pg_cntl); - - void (*set_force_poweron_domain22)(struct pg_cntl *pg_cntl, bool power_on); }; #endif //__DC_PG_CNTL_H__ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index a4027bf053c5..5c935d94a95c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -626,7 +626,19 @@ static struct dce_hwseq_registers hwseq_reg; HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh) + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK3_GATE_DISABLE, mask_sh) static const struct dce_hwseq_shift hwseq_shift = { HWSEQ_DCN35_MASK_SH_LIST(__SHIFT) @@ -705,7 +717,7 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_dcc = DCC_ENABLE, .disable_dpp_power_gate = true, .disable_hubp_power_gate = true, - .disable_clock_gate = true, + .disable_clock_gate = false, .disable_dsc_power_gate = true, .vsr_support = true, .performance_trace = false, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h index 99aea102e3f7..a51c4a9eaafe 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h @@ -166,6 +166,7 @@ struct resource_pool *dcn35_create_resource_pool( SR(MMHUBBUB_MEM_PWR_CNTL), \ SR(DCCG_GATE_DISABLE_CNTL), \ SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCCG_GATE_DISABLE_CNTL4), \ SR(DCCG_GATE_DISABLE_CNTL5), \ SR(DCFCLK_CNTL),\ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h index b64664879211..fca72e2ec929 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h @@ -6220,12 +6220,20 @@ #define DCCG_GATE_DISABLE_CNTL4__PHYD_REFCLK_ROOT_GATE_DISABLE__SHIFT 0x3 #define DCCG_GATE_DISABLE_CNTL4__PHYE_REFCLK_ROOT_GATE_DISABLE__SHIFT 0x4 #define DCCG_GATE_DISABLE_CNTL4__HDMICHARCLK0_ROOT_GATE_DISABLE__SHIFT 0x11 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK0_GATE_DISABLE__SHIFT 0x17 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK1_GATE_DISABLE__SHIFT 0x18 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK2_GATE_DISABLE__SHIFT 0x19 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK3_GATE_DISABLE__SHIFT 0x1a #define DCCG_GATE_DISABLE_CNTL4__PHYA_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000001L #define DCCG_GATE_DISABLE_CNTL4__PHYB_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000002L #define DCCG_GATE_DISABLE_CNTL4__PHYC_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000004L #define DCCG_GATE_DISABLE_CNTL4__PHYD_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000008L #define DCCG_GATE_DISABLE_CNTL4__PHYE_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000010L #define DCCG_GATE_DISABLE_CNTL4__HDMICHARCLK0_ROOT_GATE_DISABLE_MASK 0x00020000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK0_GATE_DISABLE_MASK 0x00800000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK1_GATE_DISABLE_MASK 0x01000000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK2_GATE_DISABLE_MASK 0x02000000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK3_GATE_DISABLE_MASK 0x04000000L #define DPSTREAMCLK_CNTL__DPSTREAMCLK0_SRC_SEL__SHIFT 0x0 #define DPSTREAMCLK_CNTL__DPSTREAMCLK0_EN__SHIFT 0x3 #define DPSTREAMCLK_CNTL__DPSTREAMCLK1_SRC_SEL__SHIFT 0x4 From cc6201b773f12388c234aa10145322ccc429959e Mon Sep 17 00:00:00 2001 From: Duncan Ma Date: Tue, 31 Oct 2023 16:57:36 -0400 Subject: [PATCH 0817/7721] drm/amd/display: Add disable timeout option [WHY] Driver continues running whenever there is is timeout from smu or dmcub. It is difficult to track failure state when dcn, dc or dmcub changes on root failure. [HOW] Add disable_timeout option to halt driver whenever there is a failure in response. Reviewed-by: Charlene Liu Acked-by: Alex Hung Signed-off-by: Duncan Ma Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/clk_mgr/dcn35/dcn35_smu.c | 3 ++ drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 29 +++++++++++++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c index b6b8c3ca1572..af0a0f292595 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c @@ -116,6 +116,9 @@ static uint32_t dcn35_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, un msleep(delay_us/1000); else if (delay_us > 0) udelay(delay_us); + + if (clk_mgr->base.ctx->dc->debug.disable_timeout) + max_retries++; } while (max_retries--); return res_val; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 9316b737a8ba..ae54ef6837f9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -978,6 +978,7 @@ struct dc_debug_options { bool psp_disabled_wa; unsigned int ips2_eval_delay_us; unsigned int ips2_entry_delay_us; + bool disable_timeout; }; struct gpu_info_soc_bounding_box_v1_0; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 0e07699c1e83..53400cc05b5b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -241,7 +241,12 @@ bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int coun // Wait for DMUB to process command if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) { - status = dmub_srv_wait_for_idle(dmub, 100000); + if (dc_dmub_srv->ctx->dc->debug.disable_timeout) { + do { + status = dmub_srv_wait_for_idle(dmub, 100000); + } while (status != DMUB_STATUS_OK); + } else + status = dmub_srv_wait_for_idle(dmub, 100000); if (status != DMUB_STATUS_OK) { DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); @@ -1147,10 +1152,16 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait) return true; if (wait) { - status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); - if (status != DMUB_STATUS_OK) { - DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status); - return false; + if (dc_dmub_srv->ctx->dc->debug.disable_timeout) { + do { + status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); + } while (status != DMUB_STATUS_OK); + } else { + status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); + if (status != DMUB_STATUS_OK) { + DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status); + return false; + } } } else return dmub_srv_is_hw_pwr_up(dc_dmub_srv->dmub); @@ -1187,7 +1198,7 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) const uint32_t max_num_polls = 10000; uint32_t allow_state = 0; uint32_t commit_state = 0; - uint32_t i; + int i; if (dc->debug.dmcub_emulation) return; @@ -1220,6 +1231,9 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) break; udelay(1); + + if (dc->debug.disable_timeout) + i--; } ASSERT(i < max_num_polls); @@ -1242,6 +1256,9 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) break; udelay(1); + + if (dc->debug.disable_timeout) + i--; } ASSERT(i < max_num_polls); } From c21a764a98cb59d673cad3da64f35f4dec951951 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac Date: Wed, 1 Nov 2023 15:59:56 -0400 Subject: [PATCH 0818/7721] drm/amd/display: Send PQ bit in AMD VSIF [WHY & HOW] PB9 bit 5 was added to signal PQ EOTF in AMD vendor specific infoframe. This change sets it when appropriate. Reviewed-by: Aric Cyr Acked-by: Alex Hung Signed-off-by: Krunoslav Kovac Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/freesync/freesync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index ccecddafeb05..47296d155c3a 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -693,10 +693,12 @@ static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, if (app_tf != TRANSFER_FUNC_UNKNOWN) { infopacket->valid = true; - if (app_tf != TRANSFER_FUNC_PQ2084) { + if (app_tf == TRANSFER_FUNC_PQ2084) + infopacket->sb[9] |= 0x20; // PB9 = [Bit 5 = PQ EOTF Active] + else { infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] if (app_tf == TRANSFER_FUNC_GAMMA_22) - infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] + infopacket->sb[9] |= 0x04; // PB9 = [Bit 2 = Gamma 2.2 EOTF Active] } } } From c29085d29562990559163302d9e28d1e88223d90 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Mon, 30 Oct 2023 16:23:08 -0400 Subject: [PATCH 0819/7721] drm/amd/display: Enable DSC Flag in MST Mode Validation [WHY & HOW] When dsc is possible, MST mode validation includes: 1. if maximum dsc compression cannot fit into end to end bw, mode pruned 2. if native bw cannot fit into end to end bw, try to enabled dsc to see whether a feasible dsc config can be found 3. if native bw can fit into end to end bw, mode supported Reviewed-by: Wayne Lin Acked-by: Alex Hung Signed-off-by: Fangzhi Zuo Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index ec87e31c6fe8..8d7d4024f285 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1602,9 +1602,8 @@ enum dc_status dm_dp_mst_is_port_support_mode( struct dc_link_settings cur_link_settings; unsigned int end_to_end_bw_in_kbps = 0; unsigned int upper_link_bw_in_kbps = 0, down_link_bw_in_kbps = 0; - unsigned int max_compressed_bw_in_kbps = 0; struct dc_dsc_bw_range bw_range = {0}; - uint16_t full_pbn = aconnector->mst_output_port->full_pbn; + struct dc_dsc_config_options dsc_options = {0}; /* * Consider the case with the depth of the mst topology tree is equal or less than 2 @@ -1620,30 +1619,39 @@ enum dc_status dm_dp_mst_is_port_support_mode( (aconnector->mst_output_port->passthrough_aux || aconnector->dsc_aux == &aconnector->mst_output_port->aux)) { cur_link_settings = stream->link->verified_link_cap; + upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings); + down_link_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); - upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, - &cur_link_settings); - down_link_bw_in_kbps = kbps_from_pbn(full_pbn); + /* pick the end to end bw bottleneck */ + end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps, down_link_bw_in_kbps); - /* pick the bottleneck */ - end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps, - down_link_bw_in_kbps); - - /* - * use the maximum dsc compression bandwidth as the required - * bandwidth for the mode - */ - max_compressed_bw_in_kbps = bw_range.min_kbps; - - if (end_to_end_bw_in_kbps < max_compressed_bw_in_kbps) { - DRM_DEBUG_DRIVER("Mode does not fit into DSC pass-through bandwidth validation\n"); + if (end_to_end_bw_in_kbps < bw_range.min_kbps) { + DRM_DEBUG_DRIVER("maximum dsc compression cannot fit into end-to-end bandwidth\n"); return DC_FAIL_BANDWIDTH_VALIDATE; } + + if (end_to_end_bw_in_kbps < bw_range.stream_kbps) { + dc_dsc_get_default_config_option(stream->link->dc, &dsc_options); + dsc_options.max_target_bpp_limit_override_x16 = aconnector->base.display_info.max_dsc_bpp * 16; + if (dc_dsc_compute_config(stream->sink->ctx->dc->res_pool->dscs[0], + &stream->sink->dsc_caps.dsc_dec_caps, + &dsc_options, + end_to_end_bw_in_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(stream->link), + &stream->timing.dsc_cfg)) { + stream->timing.flags.DSC = 1; + DRM_DEBUG_DRIVER("end-to-end bandwidth require dsc and dsc config found\n"); + } else { + DRM_DEBUG_DRIVER("end-to-end bandwidth require dsc but dsc config not found\n"); + return DC_FAIL_BANDWIDTH_VALIDATE; + } + } } else { /* check if mode could be supported within full_pbn */ bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3; pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp, false); - if (pbn > full_pbn) + if (pbn > aconnector->mst_output_port->full_pbn) return DC_FAIL_BANDWIDTH_VALIDATE; } From ed4ae8f77f2c4ff05244db99330d1eff828d9f7d Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 4 Nov 2023 01:53:13 -0400 Subject: [PATCH 0820/7721] drm/amd/display: Add new command to disable replay timing resync [WHY & HOW] Add new command to disable replay timing resync Acked-by: Alex Hung Signed-off-by: Anthony Koo Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index aa6e6923afed..55573083bc31 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -2876,6 +2876,10 @@ enum dmub_cmd_replay_type { * Set power opt and coasting vtotal. */ DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL = 4, + /** + * Set disabled iiming sync. + */ + DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED = 5, }; /** @@ -3038,6 +3042,27 @@ struct dmub_cmd_replay_set_power_opt_data { uint32_t power_opt; }; +/** + * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ +struct dmub_cmd_replay_set_timing_sync_data { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[3]; + /** + * REPLAY set_timing_sync + */ + bool timing_sync_supported; +}; + /** * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. */ @@ -3104,6 +3129,20 @@ struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal { struct dmub_cmd_replay_set_coasting_vtotal_data replay_set_coasting_vtotal_data; }; +/** + * Definition of a DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ +struct dmub_rb_cmd_replay_set_timing_sync { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ + struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; +}; + /** * Set of HW components that can be locked. * @@ -4237,6 +4276,8 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL command. */ struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal replay_set_power_opt_and_coasting_vtotal; + + struct dmub_rb_cmd_replay_set_timing_sync replay_set_timing_sync; }; /** From 8a2553d5c7ade00d1b508bbd418d5c4803c12fdd Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Mon, 6 Nov 2023 19:30:51 -0700 Subject: [PATCH 0821/7721] drm/amd/display: Add missing chips for HDCP [WHAT] Add missing HDCP ID in the message id enum. Acked-by: Alex Hung Signed-off-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/include/hdcp_msg_types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h b/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h index 42229b4effdc..eced9ad91f1d 100644 --- a/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h +++ b/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h @@ -69,6 +69,11 @@ enum hdcp_message_id { HDCP_MESSAGE_ID_READ_RXSTATUS, HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE, + /* PS175 chip */ + + HDCP_MESSAGE_ID_WRITE_PS175_CMD, + HDCP_MESSAGE_ID_READ_PS175_RSP, + HDCP_MESSAGE_ID_MAX }; From 466a7d115326ece682c2b60d1c77d1d0b9010b4f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Nov 2023 16:34:51 -0600 Subject: [PATCH 0822/7721] drm/amd: Use the first non-dGPU PCI device for BW limits When bandwidth limits are looked up using pcie_bandwidth_available() virtual links such as USB4 are analyzed which might not represent the real speed. Furthermore devices may change speeds autonomously which may introduce conditional variation to the results reported in the status registers. Instead look at the capabilities of first PCI device outside of dGPU to decide upper limits that the dGPU will work at. For eGPU this effectively means that it will use the speed of the link partner. Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2925#note_2145860 Link: https://www.usb.org/document-library/usb4r-specification-v20 USB4 V2 with Errata and ECN through June 2023 Section 11.2.1 Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 37 ++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 151f8b950b72..ec3bf949ee2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5737,6 +5737,39 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, return r; } +/** + * amdgpu_device_partner_bandwidth - find the bandwidth of appropriate partner + * + * @adev: amdgpu_device pointer + * @speed: pointer to the speed of the link + * @width: pointer to the width of the link + * + * Evaluate the hierarchy to find the speed and bandwidth capabilities of the + * first physical partner to an AMD dGPU. + * This will exclude any virtual switches and links. + */ +static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev, + enum pci_bus_speed *speed, + enum pcie_link_width *width) +{ + struct pci_dev *parent = adev->pdev; + + if (!speed || !width) + return; + + *speed = PCI_SPEED_UNKNOWN; + *width = PCIE_LNK_WIDTH_UNKNOWN; + + while ((parent = pci_upstream_bridge(parent))) { + /* skip upstream/downstream switches internal to dGPU*/ + if (parent->vendor == PCI_VENDOR_ID_ATI) + continue; + *speed = pcie_get_speed_cap(parent); + *width = pcie_get_width_cap(parent); + break; + } +} + /** * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot * @@ -5770,8 +5803,8 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask) return; - pcie_bandwidth_available(adev->pdev, NULL, - &platform_speed_cap, &platform_link_width); + amdgpu_device_partner_bandwidth(adev, &platform_speed_cap, + &platform_link_width); if (adev->pm.pcie_gen_mask == 0) { /* asic caps */ From d9b3a066dfcd3fe50b4dc561d8510c43c0ad8863 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Nov 2023 16:34:52 -0600 Subject: [PATCH 0823/7721] drm/amd: Exclude dGPUs in eGPU enclosures from DPM quirks The PCIe speed capabilities advertised by a USB4 or TBT3 link are limited to PCIe gen 1 per the USB4 spec. In reality the speed will change dynamically based on fabric conditions and other traffic. DPM is disabled when dGPUs are connected directly to Intel hosts since the PCIe root port isn't able to handle dynamic speed switching. As this limitation is specifically for PCIe root ports in the SoC, don't apply it when connected to an eGPU enclosure connected to an Intel host. Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2885 Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ec3bf949ee2f..b5edf40b5d03 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1551,11 +1551,15 @@ bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev) * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/ * https://gitlab.freedesktop.org/drm/amd/-/issues/2663 */ -static bool amdgpu_device_pcie_dynamic_switching_supported(void) +static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev) { #if IS_ENABLED(CONFIG_X86) struct cpuinfo_x86 *c = &cpu_data(0); + /* eGPU change speeds based on USB4 fabric conditions */ + if (dev_is_removable(adev->dev)) + return true; + if (c->x86_vendor == X86_VENDOR_INTEL) return false; #endif @@ -2395,7 +2399,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) adev->pm.pp_feature &= ~PP_GFXOFF_MASK; if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID) adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK; - if (!amdgpu_device_pcie_dynamic_switching_supported()) + if (!amdgpu_device_pcie_dynamic_switching_supported(adev)) adev->pm.pp_feature &= ~PP_PCIE_DPM_MASK; total = true; From 59e4db5375f587954eb779ac9c7888a6c81c306b Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Sun, 5 Nov 2023 20:22:06 -0500 Subject: [PATCH 0824/7721] drm/amd/display: Promote DC to 3.2.260 - Add missing chips for HDCP - Add new command to disable replay timing resync - Fix encoder disable logic - Enable DSC Flag in MST Mode Validation - Change the DMCUB mailbox memory location from FB to inbox - Add disable timeout option - Negate IPS allow and commit bits - Enable DCN clock gating for DCN35 - Prefer currently used OTG master when acquiring free pipe - Try to acquire a free OTG master not used in cur ctx first - Clear dpcd_sink_ext_caps if not set - Enable fast plane updates on DCN3.2 and above - Add null checks for 8K60 lightup - Refactor resource into component directory - Fix DSC not Enabled on Direct MST Sink - Guard against invalid RPTR/WPTR being set - Enable CM low mem power optimization - Fix a debugfs null pointer error Acked-by: Alex Hung Signed-off-by: Aric Cyr Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ae54ef6837f9..541e781267b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -49,7 +49,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.259" +#define DC_VER "3.2.260" #define MAX_SURFACES 3 #define MAX_PLANES 6 From 75fb313c55fa102f973c440f55dc63ffc61f3b54 Mon Sep 17 00:00:00 2001 From: Shiwu Zhang Date: Tue, 31 Oct 2023 12:32:54 +0800 Subject: [PATCH 0825/7721] drm/amdgpu: expose the connected port num info through sysfs By catting the xgmi_port_num sysfs node, it prints out the info in the format of : -> : for one xgmi link. For example, in case of 4 sockets fully and evenly connected setup, it would be like as below for the first node in the hive. 01:02 -> 02:03 01:03 -> 02:02 01:07 -> 03:04 01:04 -> 03:07 01:06 -> 04:05 01:05 -> 04:06 Based on the fact that there is two xgmi links between each socket pair, "01:02 -> 02:03" means that the current socket in question use the port 2 to connect with port 3 of the second node in the hive and so on. v2: print out the src/dst node id for each xgmi link (lijo) v3: replace the current_node++ with +1 to align with dst node (le) and use the dev_err instead of pr_err (lijo) v4: fix checkpatch warning (alex) Signed-off-by: Shiwu Zhang Acked-by: Lijo Lazar Reviewed-by: Le Ma Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index bd20cb3b9819..44d8c1a11e1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -413,6 +413,38 @@ static ssize_t amdgpu_xgmi_show_num_links(struct device *dev, return sysfs_emit(buf, "%s\n", buf); } +static ssize_t amdgpu_xgmi_show_connected_port_num(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info; + int i, j, size = 0; + int current_node; + /* + * get the node id in the sysfs for the current socket and show + * it in the port num info output in the sysfs for easy reading. + * it is NOT the one retrieved from xgmi ta. + */ + for (i = 0; i < top->num_nodes; i++) { + if (top->nodes[i].node_id == adev->gmc.xgmi.node_id) { + current_node = i; + break; + } + } + + for (i = 0; i < top->num_nodes; i++) { + for (j = 0; j < top->nodes[i].num_links; j++) + /* node id in sysfs starts from 1 rather than 0 so +1 here */ + size += sysfs_emit_at(buf, size, "%02x:%02x -> %02x:%02x\n", current_node + 1, + top->nodes[i].port_num[j].src_xgmi_port_num, i + 1, + top->nodes[i].port_num[j].dst_xgmi_port_num); + } + + return size; +} + #define AMDGPU_XGMI_SET_FICAA(o) ((o) | 0x456801) static ssize_t amdgpu_xgmi_show_error(struct device *dev, struct device_attribute *attr, @@ -452,6 +484,7 @@ static DEVICE_ATTR(xgmi_physical_id, 0444, amdgpu_xgmi_show_physical_id, NULL); static DEVICE_ATTR(xgmi_error, S_IRUGO, amdgpu_xgmi_show_error, NULL); static DEVICE_ATTR(xgmi_num_hops, S_IRUGO, amdgpu_xgmi_show_num_hops, NULL); static DEVICE_ATTR(xgmi_num_links, S_IRUGO, amdgpu_xgmi_show_num_links, NULL); +static DEVICE_ATTR(xgmi_port_num, S_IRUGO, amdgpu_xgmi_show_connected_port_num, NULL); static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, struct amdgpu_hive_info *hive) @@ -487,6 +520,13 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, if (ret) pr_err("failed to create xgmi_num_links\n"); + /* Create xgmi port num file if supported */ + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) { + ret = device_create_file(adev->dev, &dev_attr_xgmi_port_num); + if (ret) + dev_err(adev->dev, "failed to create xgmi_port_num\n"); + } + /* Create sysfs link to hive info folder on the first device */ if (hive->kobj.parent != (&adev->dev->kobj)) { ret = sysfs_create_link(&adev->dev->kobj, &hive->kobj, @@ -517,6 +557,8 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, device_remove_file(adev->dev, &dev_attr_xgmi_error); device_remove_file(adev->dev, &dev_attr_xgmi_num_hops); device_remove_file(adev->dev, &dev_attr_xgmi_num_links); + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) + device_remove_file(adev->dev, &dev_attr_xgmi_port_num); success: return ret; @@ -533,6 +575,8 @@ static void amdgpu_xgmi_sysfs_rem_dev_info(struct amdgpu_device *adev, device_remove_file(adev->dev, &dev_attr_xgmi_error); device_remove_file(adev->dev, &dev_attr_xgmi_num_hops); device_remove_file(adev->dev, &dev_attr_xgmi_num_links); + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) + device_remove_file(adev->dev, &dev_attr_xgmi_port_num); if (hive->kobj.parent != (&adev->dev->kobj)) sysfs_remove_link(&adev->dev->kobj,"xgmi_hive_info"); From a3cc7dbe9957f856b84a504687a85e22e02a49db Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 28 Sep 2023 15:18:16 +0530 Subject: [PATCH 0826/7721] drm/amdgpu: add pm metrics structure definition Define the pm metrics structures to be exposed via sysfs. Signed-off-by: Alex Deucher Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Yang Wang --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index b14231f470dc..f9c438d16c56 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -1127,4 +1127,19 @@ struct gpu_metrics_v3_0 { /* Metrics table alpha filter time constant [us] */ uint32_t time_filter_alphavalue; }; + +struct amdgpu_pmmetrics_header { + uint16_t structure_size; + uint16_t pad; + uint32_t mp1_ip_discovery_version; + uint32_t pmfw_version; + uint32_t pmmetrics_version; +}; + +struct amdgpu_pm_metrics { + struct amdgpu_pmmetrics_header common_header; + + uint8_t data[]; +}; + #endif From 425285d39afddaf4a9dab36045b816af0cc3e400 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Thu, 9 Nov 2023 11:37:18 +0800 Subject: [PATCH 0827/7721] drm/amdgpu: add amdgpu runpm usage trace for separate funcs Add trace for amdgpu runpm separate funcs usage and this will help debugging on the case of runpm usage missed to dereference. In the normal case the runpm usage count referred by one kind of functionality pairwise and usage should be changed from 1 to 0, otherwise there will be an issue in the amdgpu runpm usage dereference. Signed-off-by: Prike Liang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 4 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 15 +++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index e7e87a3b2601..decbbe3d4f06 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -42,6 +42,7 @@ #include #include #include +#include "amdgpu_trace.h" /** * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation @@ -63,6 +64,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, attach->peer2peer = false; r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(1, __func__); if (r < 0) goto out; @@ -70,6 +72,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, out: pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); return r; } @@ -90,6 +93,7 @@ static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf, pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index dc230212746a..70bff8cecfda 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -183,6 +183,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, seq, flags | AMDGPU_FENCE_FLAG_INT); pm_runtime_get_noresume(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(1, __func__); ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; if (unlikely(rcu_dereference_protected(*ptr, 1))) { struct dma_fence *old; @@ -310,6 +311,7 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) dma_fence_put(fence); pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); } while (last_seq != seq); return true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 2fd1bfb35916..f539b1d00234 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -554,6 +554,21 @@ TRACE_EVENT(amdgpu_reset_reg_dumps, __entry->value) ); +TRACE_EVENT(amdgpu_runpm_reference_dumps, + TP_PROTO(uint32_t index, const char *func), + TP_ARGS(index, func), + TP_STRUCT__entry( + __field(uint32_t, index) + __string(func, func) + ), + TP_fast_assign( + __entry->index = index; + __assign_str(func, func); + ), + TP_printk("amdgpu runpm reference dump 0x%x: 0x%s\n", + __entry->index, + __get_str(func)) +); #undef AMDGPU_JOB_GET_TIMELINE_NAME #endif From 699d392903c3cebb7d2a2a3505ec9047c419dcd7 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Sun, 12 Nov 2023 10:09:44 +0530 Subject: [PATCH 0828/7721] drm/amdgpu: Add function parameter 'xcc_mask' not described in 'amdgpu_vm_flush_compute_tlb' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the below: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1373: warning: Function parameter or member 'xcc_mask' not described in 'amdgpu_vm_flush_compute_tlb' Cc: Felix Kuehling Cc: Christian König Cc: Alex Deucher Cc: "Pan, Xinhui" Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d59154ddaaed..7da71b6a9dc6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1443,6 +1443,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, * @adev: amdgpu_device pointer * @vm: requested vm * @flush_type: flush type + * @xcc_mask: mask of XCCs that belong to the compute partition in need of a TLB flush. * * Flush TLB if needed for a compute VM. * From 077798da028e81ada39a256969207c91db66ebaf Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 30 Oct 2023 09:48:09 +0100 Subject: [PATCH 0829/7721] tee: optee: system thread call property Adds an argument to do_call_with_arg() handler to tell whether the call is a system thread call or not. This change always sets this info to false hence no functional change. This change prepares management of system invocation proposed in a later change. Reviewed-by: Sumit Garg Co-developed-by: Jens Wiklander Signed-off-by: Etienne Carriere [jw: clarified that it's system thread calls] Signed-off-by: Jens Wiklander --- drivers/tee/optee/call.c | 24 +++++++++++++++++------- drivers/tee/optee/core.c | 5 +++-- drivers/tee/optee/ffa_abi.c | 11 +++++++---- drivers/tee/optee/optee_private.h | 9 ++++++--- drivers/tee/optee/smc_abi.c | 16 +++++++++------- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index df5fb5410b72..152ae9bb1785 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -40,7 +40,7 @@ struct optee_shm_arg_entry { }; void optee_cq_wait_init(struct optee_call_queue *cq, - struct optee_call_waiter *w) + struct optee_call_waiter *w, bool sys_thread) { /* * We're preparing to make a call to secure world. In case we can't @@ -328,7 +328,8 @@ int optee_open_session(struct tee_context *ctx, goto out; } - if (optee->ops->do_call_with_arg(ctx, shm, offs)) { + if (optee->ops->do_call_with_arg(ctx, shm, offs, + sess->use_sys_thread)) { msg_arg->ret = TEEC_ERROR_COMMUNICATION; msg_arg->ret_origin = TEEC_ORIGIN_COMMS; } @@ -360,7 +361,8 @@ int optee_open_session(struct tee_context *ctx, return rc; } -int optee_close_session_helper(struct tee_context *ctx, u32 session) +int optee_close_session_helper(struct tee_context *ctx, u32 session, + bool system_thread) { struct optee *optee = tee_get_drvdata(ctx->teedev); struct optee_shm_arg_entry *entry; @@ -374,7 +376,7 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session) msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION; msg_arg->session = session; - optee->ops->do_call_with_arg(ctx, shm, offs); + optee->ops->do_call_with_arg(ctx, shm, offs, system_thread); optee_free_msg_arg(ctx, entry, offs); @@ -385,6 +387,7 @@ int optee_close_session(struct tee_context *ctx, u32 session) { struct optee_context_data *ctxdata = ctx->data; struct optee_session *sess; + bool system_thread; /* Check that the session is valid and remove it from the list */ mutex_lock(&ctxdata->mutex); @@ -394,9 +397,10 @@ int optee_close_session(struct tee_context *ctx, u32 session) mutex_unlock(&ctxdata->mutex); if (!sess) return -EINVAL; + system_thread = sess->use_sys_thread; kfree(sess); - return optee_close_session_helper(ctx, session); + return optee_close_session_helper(ctx, session, system_thread); } int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, @@ -408,12 +412,15 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct optee_msg_arg *msg_arg; struct optee_session *sess; struct tee_shm *shm; + bool system_thread; u_int offs; int rc; /* Check that the session is valid */ mutex_lock(&ctxdata->mutex); sess = find_session(ctxdata, arg->session); + if (sess) + system_thread = sess->use_sys_thread; mutex_unlock(&ctxdata->mutex); if (!sess) return -EINVAL; @@ -432,7 +439,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, if (rc) goto out; - if (optee->ops->do_call_with_arg(ctx, shm, offs)) { + if (optee->ops->do_call_with_arg(ctx, shm, offs, system_thread)) { msg_arg->ret = TEEC_ERROR_COMMUNICATION; msg_arg->ret_origin = TEEC_ORIGIN_COMMS; } @@ -457,12 +464,15 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) struct optee_shm_arg_entry *entry; struct optee_msg_arg *msg_arg; struct optee_session *sess; + bool system_thread; struct tee_shm *shm; u_int offs; /* Check that the session is valid */ mutex_lock(&ctxdata->mutex); sess = find_session(ctxdata, session); + if (sess) + system_thread = sess->use_sys_thread; mutex_unlock(&ctxdata->mutex); if (!sess) return -EINVAL; @@ -474,7 +484,7 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) msg_arg->cmd = OPTEE_MSG_CMD_CANCEL; msg_arg->session = session; msg_arg->cancel_id = cancel_id; - optee->ops->do_call_with_arg(ctx, shm, offs); + optee->ops->do_call_with_arg(ctx, shm, offs, system_thread); optee_free_msg_arg(ctx, entry, offs); return 0; diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 2a258bd3b6b5..d01ca47f7bde 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -129,7 +129,8 @@ int optee_open(struct tee_context *ctx, bool cap_memref_null) static void optee_release_helper(struct tee_context *ctx, int (*close_session)(struct tee_context *ctx, - u32 session)) + u32 session, + bool system_thread)) { struct optee_context_data *ctxdata = ctx->data; struct optee_session *sess; @@ -141,7 +142,7 @@ static void optee_release_helper(struct tee_context *ctx, list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list, list_node) { list_del(&sess->list_node); - close_session(ctx, sess->session_id); + close_session(ctx, sess->session_id, sess->use_sys_thread); kfree(sess); } kfree(ctxdata); diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index 0828240f27e6..721fd4d24f47 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -528,7 +528,8 @@ static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee, static int optee_ffa_yielding_call(struct tee_context *ctx, struct ffa_send_direct_data *data, - struct optee_msg_arg *rpc_arg) + struct optee_msg_arg *rpc_arg, + bool system_thread) { struct optee *optee = tee_get_drvdata(ctx->teedev); struct ffa_device *ffa_dev = optee->ffa.ffa_dev; @@ -541,7 +542,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx, int rc; /* Initialize waiter */ - optee_cq_wait_init(&optee->call_queue, &w); + optee_cq_wait_init(&optee->call_queue, &w, system_thread); while (true) { rc = msg_ops->sync_send_receive(ffa_dev, data); if (rc) @@ -604,6 +605,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx, * @ctx: calling context * @shm: shared memory holding the message to pass to secure world * @offs: offset of the message in @shm + * @system_thread: true if caller requests TEE system thread support * * Does a FF-A call to OP-TEE in secure world and handles eventual resulting * Remote Procedure Calls (RPC) from OP-TEE. @@ -612,7 +614,8 @@ static int optee_ffa_yielding_call(struct tee_context *ctx, */ static int optee_ffa_do_call_with_arg(struct tee_context *ctx, - struct tee_shm *shm, u_int offs) + struct tee_shm *shm, u_int offs, + bool system_thread) { struct ffa_send_direct_data data = { .data0 = OPTEE_FFA_YIELDING_CALL_WITH_ARG, @@ -642,7 +645,7 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx, if (IS_ERR(rpc_arg)) return PTR_ERR(rpc_arg); - return optee_ffa_yielding_call(ctx, &data, rpc_arg); + return optee_ffa_yielding_call(ctx, &data, rpc_arg, system_thread); } /* diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 6bb5cae09688..b659a6f521df 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -154,7 +154,8 @@ struct optee; */ struct optee_ops { int (*do_call_with_arg)(struct tee_context *ctx, - struct tee_shm *shm_arg, u_int offs); + struct tee_shm *shm_arg, u_int offs, + bool system_thread); int (*to_msg_param)(struct optee *optee, struct optee_msg_param *msg_params, size_t num_params, const struct tee_param *params); @@ -204,6 +205,7 @@ struct optee { struct optee_session { struct list_head list_node; u32 session_id; + bool use_sys_thread; }; struct optee_context_data { @@ -250,7 +252,8 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, int optee_open_session(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, struct tee_param *param); -int optee_close_session_helper(struct tee_context *ctx, u32 session); +int optee_close_session_helper(struct tee_context *ctx, u32 session, + bool system_thread); int optee_close_session(struct tee_context *ctx, u32 session); int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); @@ -299,7 +302,7 @@ static inline void optee_to_msg_param_value(struct optee_msg_param *mp, } void optee_cq_wait_init(struct optee_call_queue *cq, - struct optee_call_waiter *w); + struct optee_call_waiter *w, bool sys_thread); void optee_cq_wait_for_completion(struct optee_call_queue *cq, struct optee_call_waiter *w); void optee_cq_wait_final(struct optee_call_queue *cq, diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index d5b28fd35d66..8ae5e1047650 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -283,7 +283,7 @@ static void optee_enable_shm_cache(struct optee *optee) struct optee_call_waiter w; /* We need to retry until secure world isn't busy. */ - optee_cq_wait_init(&optee->call_queue, &w); + optee_cq_wait_init(&optee->call_queue, &w, false); while (true) { struct arm_smccc_res res; @@ -308,7 +308,7 @@ static void __optee_disable_shm_cache(struct optee *optee, bool is_mapped) struct optee_call_waiter w; /* We need to retry until secure world isn't busy. */ - optee_cq_wait_init(&optee->call_queue, &w); + optee_cq_wait_init(&optee->call_queue, &w, false); while (true) { union { struct arm_smccc_res smccc; @@ -507,7 +507,7 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm, msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) | (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1)); - if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) || + if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) || msg_arg->ret != TEEC_SUCCESS) rc = -EINVAL; @@ -550,7 +550,7 @@ static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm) msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm; - if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) || + if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) || msg_arg->ret != TEEC_SUCCESS) rc = -EINVAL; out: @@ -878,6 +878,7 @@ static void optee_handle_rpc(struct tee_context *ctx, * @ctx: calling context * @shm: shared memory holding the message to pass to secure world * @offs: offset of the message in @shm + * @system_thread: true if caller requests TEE system thread support * * Does and SMC to OP-TEE in secure world and handles eventual resulting * Remote Procedure Calls (RPC) from OP-TEE. @@ -885,7 +886,8 @@ static void optee_handle_rpc(struct tee_context *ctx, * Returns return code from secure world, 0 is OK */ static int optee_smc_do_call_with_arg(struct tee_context *ctx, - struct tee_shm *shm, u_int offs) + struct tee_shm *shm, u_int offs, + bool system_thread) { struct optee *optee = tee_get_drvdata(ctx->teedev); struct optee_call_waiter w; @@ -926,7 +928,7 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx, reg_pair_from_64(¶m.a1, ¶m.a2, parg); } /* Initialize waiter */ - optee_cq_wait_init(&optee->call_queue, &w); + optee_cq_wait_init(&optee->call_queue, &w, system_thread); while (true) { struct arm_smccc_res res; @@ -977,7 +979,7 @@ static int simple_call_with_arg(struct tee_context *ctx, u32 cmd) return PTR_ERR(msg_arg); msg_arg->cmd = cmd; - optee_smc_do_call_with_arg(ctx, shm, offs); + optee_smc_do_call_with_arg(ctx, shm, offs, false); optee_free_msg_arg(ctx, entry, offs); return 0; From a9214a8883ceb82df55aa90d1c49ddb85fc1e3d5 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 30 Oct 2023 09:48:10 +0100 Subject: [PATCH 0830/7721] tee: system session Adds kernel client API function tee_client_system_session() for a client to request a system service entry in TEE context. This feature is needed to prevent a system deadlock when several TEE client applications invoke TEE, consuming all TEE thread contexts available in the secure world. The deadlock can happen in the OP-TEE driver for example if all these TEE threads issue an RPC call from TEE to Linux OS to access an eMMC RPMB partition (TEE secure storage) which device clock or regulator controller is accessed through an OP-TEE SCMI services. In that case, Linux SCMI driver must reach OP-TEE SCMI service without waiting until one of the consumed TEE threads is freed. Reviewed-by: Sumit Garg Co-developed-by: Jens Wiklander Signed-off-by: Etienne Carriere Signed-off-by: Jens Wiklander --- drivers/tee/tee_core.c | 8 ++++++++ include/linux/tee_drv.h | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 5ddfd5d9ac7f..792d6fae4354 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -1173,6 +1173,14 @@ int tee_client_close_session(struct tee_context *ctx, u32 session) } EXPORT_SYMBOL_GPL(tee_client_close_session); +int tee_client_system_session(struct tee_context *ctx, u32 session) +{ + if (!ctx->teedev->desc->ops->system_session) + return -EINVAL; + return ctx->teedev->desc->ops->system_session(ctx, session); +} +EXPORT_SYMBOL_GPL(tee_client_system_session); + int tee_client_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param) diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index 17eb1c5205d3..911ddf92dcee 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -84,6 +84,7 @@ struct tee_param { * @release: release this open file * @open_session: open a new session * @close_session: close a session + * @system_session: declare session as a system session * @invoke_func: invoke a trusted function * @cancel_req: request cancel of an ongoing invoke or open * @supp_recv: called for supplicant to get a command @@ -100,6 +101,7 @@ struct tee_driver_ops { struct tee_ioctl_open_session_arg *arg, struct tee_param *param); int (*close_session)(struct tee_context *ctx, u32 session); + int (*system_session)(struct tee_context *ctx, u32 session); int (*invoke_func)(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); @@ -429,6 +431,20 @@ int tee_client_open_session(struct tee_context *ctx, */ int tee_client_close_session(struct tee_context *ctx, u32 session); +/** + * tee_client_system_session() - Declare session as a system session + * @ctx: TEE Context + * @session: Session id + * + * This function requests TEE to provision an entry context ready to use for + * that session only. The provisioned entry context is used for command + * invocation and session closure, not for command cancelling requests. + * TEE releases the provisioned context upon session closure. + * + * Return < 0 on error else 0 if an entry context has been provisioned. + */ +int tee_client_system_session(struct tee_context *ctx, u32 session); + /** * tee_client_invoke_func() - Invoke a function in a Trusted Application * @ctx: TEE Context From 45bc2c9b5b230b95cad10f44204d7b28f52b74c0 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 30 Oct 2023 09:48:11 +0100 Subject: [PATCH 0831/7721] tee: optee: support tracking system threads Adds support in the OP-TEE driver to keep track of reserved system threads. The logic allows one OP-TEE thread to be reserved to TEE system sessions. The optee_cq_*() functions are updated to handle this if enabled, that is when TEE describes how many thread context it supports and when at least 1 session has registered as a system session (using tee_client_system_session()). For sake of simplicity, initialization of call queue management is factorized into new helper function optee_cq_init(). The SMC ABI part of the driver enables this tracking, but the FF-A ABI part does not. Co-developed-by: Jens Wiklander Co-developed-by: Sumit Garg Signed-off-by: Sumit Garg Signed-off-by: Etienne Carriere Signed-off-by: Jens Wiklander --- drivers/tee/optee/call.c | 106 ++++++++++++++++++++++++++++++ drivers/tee/optee/ffa_abi.c | 3 +- drivers/tee/optee/optee_private.h | 20 ++++++ drivers/tee/optee/smc_abi.c | 16 ++++- 4 files changed, 141 insertions(+), 4 deletions(-) diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 152ae9bb1785..b04c49c69619 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -39,9 +39,29 @@ struct optee_shm_arg_entry { DECLARE_BITMAP(map, MAX_ARG_COUNT_PER_ENTRY); }; +void optee_cq_init(struct optee_call_queue *cq, int thread_count) +{ + mutex_init(&cq->mutex); + INIT_LIST_HEAD(&cq->waiters); + + /* + * If cq->total_thread_count is 0 then we're not trying to keep + * track of how many free threads we have, instead we're relying on + * the secure world to tell us when we're out of thread and have to + * wait for another thread to become available. + */ + cq->total_thread_count = thread_count; + cq->free_thread_count = thread_count; +} + void optee_cq_wait_init(struct optee_call_queue *cq, struct optee_call_waiter *w, bool sys_thread) { + unsigned int free_thread_threshold; + bool need_wait = false; + + memset(w, 0, sizeof(*w)); + /* * We're preparing to make a call to secure world. In case we can't * allocate a thread in secure world we'll end up waiting in @@ -60,8 +80,38 @@ void optee_cq_wait_init(struct optee_call_queue *cq, */ init_completion(&w->c); list_add_tail(&w->list_node, &cq->waiters); + w->sys_thread = sys_thread; + + if (cq->total_thread_count) { + if (sys_thread || !cq->sys_thread_req_count) + free_thread_threshold = 0; + else + free_thread_threshold = 1; + + if (cq->free_thread_count > free_thread_threshold) + cq->free_thread_count--; + else + need_wait = true; + } mutex_unlock(&cq->mutex); + + while (need_wait) { + optee_cq_wait_for_completion(cq, w); + mutex_lock(&cq->mutex); + + if (sys_thread || !cq->sys_thread_req_count) + free_thread_threshold = 0; + else + free_thread_threshold = 1; + + if (cq->free_thread_count > free_thread_threshold) { + cq->free_thread_count--; + need_wait = false; + } + + mutex_unlock(&cq->mutex); + } } void optee_cq_wait_for_completion(struct optee_call_queue *cq, @@ -83,6 +133,14 @@ static void optee_cq_complete_one(struct optee_call_queue *cq) { struct optee_call_waiter *w; + /* Wake a waiting system session if any, prior to a normal session */ + list_for_each_entry(w, &cq->waiters, list_node) { + if (w->sys_thread && !completion_done(&w->c)) { + complete(&w->c); + return; + } + } + list_for_each_entry(w, &cq->waiters, list_node) { if (!completion_done(&w->c)) { complete(&w->c); @@ -104,6 +162,8 @@ void optee_cq_wait_final(struct optee_call_queue *cq, /* Get out of the list */ list_del(&w->list_node); + cq->free_thread_count++; + /* Wake up one eventual waiting task */ optee_cq_complete_one(cq); @@ -119,6 +179,28 @@ void optee_cq_wait_final(struct optee_call_queue *cq, mutex_unlock(&cq->mutex); } +/* Count registered system sessions to reserved a system thread or not */ +static bool optee_cq_incr_sys_thread_count(struct optee_call_queue *cq) +{ + if (cq->total_thread_count <= 1) + return false; + + mutex_lock(&cq->mutex); + cq->sys_thread_req_count++; + mutex_unlock(&cq->mutex); + + return true; +} + +static void optee_cq_decr_sys_thread_count(struct optee_call_queue *cq) +{ + mutex_lock(&cq->mutex); + cq->sys_thread_req_count--; + /* If there's someone waiting, let it resume */ + optee_cq_complete_one(cq); + mutex_unlock(&cq->mutex); +} + /* Requires the filpstate mutex to be held */ static struct optee_session *find_session(struct optee_context_data *ctxdata, u32 session_id) @@ -361,6 +443,27 @@ int optee_open_session(struct tee_context *ctx, return rc; } +int optee_system_session(struct tee_context *ctx, u32 session) +{ + struct optee *optee = tee_get_drvdata(ctx->teedev); + struct optee_context_data *ctxdata = ctx->data; + struct optee_session *sess; + int rc = -EINVAL; + + mutex_lock(&ctxdata->mutex); + + sess = find_session(ctxdata, session); + if (sess && (sess->use_sys_thread || + optee_cq_incr_sys_thread_count(&optee->call_queue))) { + sess->use_sys_thread = true; + rc = 0; + } + + mutex_unlock(&ctxdata->mutex); + + return rc; +} + int optee_close_session_helper(struct tee_context *ctx, u32 session, bool system_thread) { @@ -380,6 +483,9 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session, optee_free_msg_arg(ctx, entry, offs); + if (system_thread) + optee_cq_decr_sys_thread_count(&optee->call_queue); + return 0; } diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index 721fd4d24f47..d73396ed5b93 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -853,8 +853,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) if (rc) goto err_unreg_supp_teedev; mutex_init(&optee->ffa.mutex); - mutex_init(&optee->call_queue.mutex); - INIT_LIST_HEAD(&optee->call_queue.waiters); + optee_cq_init(&optee->call_queue, 0); optee_supp_init(&optee->supp); optee_shm_arg_cache_init(optee, arg_cache_flags); ffa_dev_set_drvdata(ffa_dev, optee); diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index b659a6f521df..7832ccefe6d0 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -40,15 +40,33 @@ typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, struct arm_smccc_res *); +/* + * struct optee_call_waiter - TEE entry may need to wait for a free TEE thread + * @list_node Reference in waiters list + * @c Waiting completion reference + * @sys_thread True if waiter belongs to a system thread + */ struct optee_call_waiter { struct list_head list_node; struct completion c; + bool sys_thread; }; +/* + * struct optee_call_queue - OP-TEE call queue management + * @mutex Serializes access to this struct + * @waiters List of threads waiting to enter OP-TEE + * @total_thread_count Overall number of thread context in OP-TEE or 0 + * @free_thread_count Number of threads context free in OP-TEE + * @sys_thread_req_count Number of registered system thread sessions + */ struct optee_call_queue { /* Serializes access to this struct */ struct mutex mutex; struct list_head waiters; + int total_thread_count; + int free_thread_count; + int sys_thread_req_count; }; struct optee_notif { @@ -252,6 +270,7 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, int optee_open_session(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, struct tee_param *param); +int optee_system_session(struct tee_context *ctx, u32 session); int optee_close_session_helper(struct tee_context *ctx, u32 session, bool system_thread); int optee_close_session(struct tee_context *ctx, u32 session); @@ -301,6 +320,7 @@ static inline void optee_to_msg_param_value(struct optee_msg_param *mp, mp->u.value.c = p->u.value.c; } +void optee_cq_init(struct optee_call_queue *cq, int thread_count); void optee_cq_wait_init(struct optee_call_queue *cq, struct optee_call_waiter *w, bool sys_thread); void optee_cq_wait_for_completion(struct optee_call_queue *cq, diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index 8ae5e1047650..3b60acc15cf0 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -1212,6 +1212,7 @@ static const struct tee_driver_ops optee_clnt_ops = { .release = optee_release, .open_session = optee_open_session, .close_session = optee_close_session, + .system_session = optee_system_session, .invoke_func = optee_invoke_func, .cancel_req = optee_cancel_req, .shm_register = optee_shm_register, @@ -1359,6 +1360,16 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, return true; } +static unsigned int optee_msg_get_thread_count(optee_invoke_fn *invoke_fn) +{ + struct arm_smccc_res res; + + invoke_fn(OPTEE_SMC_GET_THREAD_COUNT, 0, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return 0; + return res.a1; +} + static struct tee_shm_pool * optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) { @@ -1611,6 +1622,7 @@ static int optee_probe(struct platform_device *pdev) struct optee *optee = NULL; void *memremaped_shm = NULL; unsigned int rpc_param_count; + unsigned int thread_count; struct tee_device *teedev; struct tee_context *ctx; u32 max_notif_value; @@ -1638,6 +1650,7 @@ static int optee_probe(struct platform_device *pdev) return -EINVAL; } + thread_count = optee_msg_get_thread_count(invoke_fn); if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps, &max_notif_value, &rpc_param_count)) { @@ -1727,8 +1740,7 @@ static int optee_probe(struct platform_device *pdev) if (rc) goto err_unreg_supp_teedev; - mutex_init(&optee->call_queue.mutex); - INIT_LIST_HEAD(&optee->call_queue.waiters); + optee_cq_init(&optee->call_queue, thread_count); optee_supp_init(&optee->supp); optee->smc.memremaped_shm = memremaped_shm; optee->pool = pool; From 4b391c9c37646f25118355f414b9e6d9fefe782f Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 30 Oct 2023 09:48:12 +0100 Subject: [PATCH 0832/7721] firmware: arm_scmi: optee: use optee system invocation Changes SCMI optee transport to call tee_client_system_session() to request optee driver to provision an entry context in OP-TEE for processing OP-TEE messages. This prevents possible deadlock in case OP-TEE threads are all consumed while these may be waiting for a clock or regulator to be enable which SCMI OP-TEE service which requires a free thread context to execute. Cc: Sudeep Holla Cc: Cristian Marussi Acked-by: Sudeep Holla Reviewed-by: Sumit Garg Signed-off-by: Etienne Carriere Signed-off-by: Jens Wiklander --- drivers/firmware/arm_scmi/optee.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index e123de6e8c67..25bfb465484d 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -440,6 +440,10 @@ static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *de if (ret) goto err_free_shm; + ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session); + if (ret) + dev_warn(dev, "Could not switch to system session, do best effort\n"); + ret = get_channel(channel); if (ret) goto err_close_sess; From 6dea6352bec3ab9f8f71d1694ca91002844a5067 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Thu, 7 Sep 2023 12:55:58 +0200 Subject: [PATCH 0833/7721] optee: provide optee_do_bottom_half() as a common function Provides optee_do_bottom_half() and optee_stop_async_notif() as common functions callable from the FF-A ABI part of the driver too. Signed-off-by: Jens Wiklander Reviewed-by: Sumit Garg --- drivers/tee/optee/call.c | 31 +++++++++++++++++++++++++- drivers/tee/optee/optee_private.h | 5 ++++- drivers/tee/optee/smc_abi.c | 36 ++++--------------------------- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index b04c49c69619..a91e50be11be 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2021, Linaro Limited + * Copyright (c) 2015-2021, 2023 Linaro Limited */ #include #include @@ -640,3 +640,32 @@ int optee_check_mem_type(unsigned long start, size_t num_pages) return rc; } + +static int simple_call_with_arg(struct tee_context *ctx, u32 cmd) +{ + struct optee *optee = tee_get_drvdata(ctx->teedev); + struct optee_shm_arg_entry *entry; + struct optee_msg_arg *msg_arg; + struct tee_shm *shm; + u_int offs; + + msg_arg = optee_get_msg_arg(ctx, 0, &entry, &shm, &offs); + if (IS_ERR(msg_arg)) + return PTR_ERR(msg_arg); + + msg_arg->cmd = cmd; + optee->ops->do_call_with_arg(ctx, shm, offs, false); + + optee_free_msg_arg(ctx, entry, offs); + return 0; +} + +int optee_do_bottom_half(struct tee_context *ctx) +{ + return simple_call_with_arg(ctx, OPTEE_MSG_CMD_DO_BOTTOM_HALF); +} + +int optee_stop_async_notif(struct tee_context *ctx) +{ + return simple_call_with_arg(ctx, OPTEE_MSG_CMD_STOP_ASYNC_NOTIF); +} diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 7832ccefe6d0..0dcc39349509 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2021, Linaro Limited + * Copyright (c) 2015-2021, 2023 Linaro Limited */ #ifndef OPTEE_PRIVATE_H @@ -346,6 +346,9 @@ void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm); void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee, struct optee_msg_arg *arg); +int optee_do_bottom_half(struct tee_context *ctx); +int optee_stop_async_notif(struct tee_context *ctx); + /* * Small helpers */ diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index 3b60acc15cf0..e158f3136c26 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2021, Linaro Limited + * Copyright (c) 2015-2021, 2023 Linaro Limited * Copyright (c) 2016, EPAM Systems */ @@ -967,34 +967,6 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx, return rc; } -static int simple_call_with_arg(struct tee_context *ctx, u32 cmd) -{ - struct optee_shm_arg_entry *entry; - struct optee_msg_arg *msg_arg; - struct tee_shm *shm; - u_int offs; - - msg_arg = optee_get_msg_arg(ctx, 0, &entry, &shm, &offs); - if (IS_ERR(msg_arg)) - return PTR_ERR(msg_arg); - - msg_arg->cmd = cmd; - optee_smc_do_call_with_arg(ctx, shm, offs, false); - - optee_free_msg_arg(ctx, entry, offs); - return 0; -} - -static int optee_smc_do_bottom_half(struct tee_context *ctx) -{ - return simple_call_with_arg(ctx, OPTEE_MSG_CMD_DO_BOTTOM_HALF); -} - -static int optee_smc_stop_async_notif(struct tee_context *ctx) -{ - return simple_call_with_arg(ctx, OPTEE_MSG_CMD_STOP_ASYNC_NOTIF); -} - /* * 5. Asynchronous notification */ @@ -1050,7 +1022,7 @@ static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id) { struct optee *optee = dev_id; - optee_smc_do_bottom_half(optee->ctx); + optee_do_bottom_half(optee->ctx); return IRQ_HANDLED; } @@ -1088,7 +1060,7 @@ static void notif_pcpu_irq_work_fn(struct work_struct *work) notif_pcpu_work); struct optee *optee = container_of(optee_smc, struct optee, smc); - optee_smc_do_bottom_half(optee->ctx); + optee_do_bottom_half(optee->ctx); } static int init_pcpu_irq(struct optee *optee, u_int irq) @@ -1160,7 +1132,7 @@ static void uninit_pcpu_irq(struct optee *optee) static void optee_smc_notif_uninit_irq(struct optee *optee) { if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) { - optee_smc_stop_async_notif(optee->ctx); + optee_stop_async_notif(optee->ctx); if (optee->smc.notif_irq) { if (irq_is_percpu_devid(optee->smc.notif_irq)) uninit_pcpu_irq(optee); From d0476a59de064205f4aaa8f7c6d6f32bc28a44d4 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Thu, 7 Sep 2023 13:27:42 +0200 Subject: [PATCH 0834/7721] optee: ffa_abi: add asynchronous notifications Adds support for asynchronous notifications from OP-TEE in secure world when communicating via FF-A. In principle from OP-TEE and kernel driver point of view this works in the same way as for the SMC ABI based implementation. The OP-TEE FF-A ABI is expanded in OPTEE_FFA_EXCHANGE_CAPABILITIES with the capability OPTEE_FFA_SEC_CAP_ASYNC_NOTIF to indicate that OP-TEE supports asynchronous notifications. OPTEE_FFA_ENABLE_ASYNC_NOTIF is also added to tell that the driver has successfully initialized these notifications. Notification capability is negotiated while the driver is initialized. If both sides supports these notifications then they are enabled. The notification concept in this driver is merged with the FF-A concept, the lower 64 values are reserved for FF-A as asynchronous notifications while the synchronous notifications use the higher values. So a FF-A notification has to be allocated for each discrete asynchronous notification value needed. Only one asynchronous notification value is used at the moment, the "do bottom half" notification. Signed-off-by: Jens Wiklander Reviewed-by: Sumit Garg Tested-by: Sudeep Holla --- drivers/tee/optee/ffa_abi.c | 93 ++++++++++++++++++++++++++++++- drivers/tee/optee/optee_ffa.h | 28 ++++++++-- drivers/tee/optee/optee_private.h | 4 +- 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index d73396ed5b93..ecb5eb079408 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021, Linaro Limited + * Copyright (c) 2021, 2023 Linaro Limited */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -695,7 +695,8 @@ static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev, static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev, const struct ffa_ops *ops, u32 *sec_caps, - unsigned int *rpc_param_count) + unsigned int *rpc_param_count, + unsigned int *max_notif_value) { struct ffa_send_direct_data data = { OPTEE_FFA_EXCHANGE_CAPABILITIES }; int rc; @@ -712,10 +713,39 @@ static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev, *rpc_param_count = (u8)data.data1; *sec_caps = data.data2; + if (data.data3) + *max_notif_value = data.data3; + else + *max_notif_value = OPTEE_DEFAULT_MAX_NOTIF_VALUE; return true; } +static void notif_callback(int notify_id, void *cb_data) +{ + struct optee *optee = cb_data; + + if (notify_id == optee->ffa.bottom_half_value) + optee_do_bottom_half(optee->ctx); + else + optee_notif_send(optee, notify_id); +} + +static int enable_async_notif(struct optee *optee) +{ + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; + struct ffa_send_direct_data data = { + .data0 = OPTEE_FFA_ENABLE_ASYNC_NOTIF, + .data1 = optee->ffa.bottom_half_value, + }; + int rc; + + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &data); + if (rc) + return rc; + return data.data0; +} + static void optee_ffa_get_version(struct tee_device *teedev, struct tee_ioctl_version_data *vers) { @@ -778,7 +808,11 @@ static const struct optee_ops optee_ffa_ops = { static void optee_ffa_remove(struct ffa_device *ffa_dev) { struct optee *optee = ffa_dev_get_drvdata(ffa_dev); + u32 bottom_half_id = optee->ffa.bottom_half_value; + if (bottom_half_id != U32_MAX) + ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev, + bottom_half_id); optee_remove_common(optee); mutex_destroy(&optee->ffa.mutex); @@ -787,9 +821,51 @@ static void optee_ffa_remove(struct ffa_device *ffa_dev) kfree(optee); } +static int optee_ffa_async_notif_init(struct ffa_device *ffa_dev, + struct optee *optee) +{ + bool is_per_vcpu = false; + u32 notif_id = 0; + int rc; + + while (true) { + rc = ffa_dev->ops->notifier_ops->notify_request(ffa_dev, + is_per_vcpu, + notif_callback, + optee, + notif_id); + if (!rc) + break; + /* + * -EACCES means that the notification ID was + * already bound, try the next one as long as we + * haven't reached the max. Any other error is a + * permanent error, so skip asynchronous + * notifications in that case. + */ + if (rc != -EACCES) + return rc; + notif_id++; + if (notif_id >= OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE) + return rc; + } + optee->ffa.bottom_half_value = notif_id; + + rc = enable_async_notif(optee); + if (rc < 0) { + ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev, + notif_id); + optee->ffa.bottom_half_value = U32_MAX; + } + + return rc; +} + static int optee_ffa_probe(struct ffa_device *ffa_dev) { + const struct ffa_notifier_ops *notif_ops; const struct ffa_ops *ffa_ops; + unsigned int max_notif_value; unsigned int rpc_param_count; struct tee_shm_pool *pool; struct tee_device *teedev; @@ -800,12 +876,13 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) int rc; ffa_ops = ffa_dev->ops; + notif_ops = ffa_ops->notifier_ops; if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops)) return -EINVAL; if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps, - &rpc_param_count)) + &rpc_param_count, &max_notif_value)) return -EINVAL; if (sec_caps & OPTEE_FFA_SEC_CAP_ARG_OFFSET) arg_cache_flags |= OPTEE_SHM_ARG_SHARED; @@ -823,6 +900,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) optee->ops = &optee_ffa_ops; optee->ffa.ffa_dev = ffa_dev; + optee->ffa.bottom_half_value = U32_MAX; optee->rpc_param_count = rpc_param_count; teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool, @@ -866,6 +944,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE); if (rc) goto err_close_ctx; + if (sec_caps & OPTEE_FFA_SEC_CAP_ASYNC_NOTIF) { + rc = optee_ffa_async_notif_init(ffa_dev, optee); + if (rc < 0) + pr_err("Failed to initialize async notifications: %d", + rc); + } rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES); if (rc) @@ -876,6 +960,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) err_unregister_devices: optee_unregister_devices(); + if (optee->ffa.bottom_half_value != U32_MAX) + notif_ops->notify_relinquish(ffa_dev, + optee->ffa.bottom_half_value); optee_notif_uninit(optee); err_close_ctx: teedev_close_context(ctx); diff --git a/drivers/tee/optee/optee_ffa.h b/drivers/tee/optee/optee_ffa.h index 97266243deaa..5db779dc00de 100644 --- a/drivers/tee/optee/optee_ffa.h +++ b/drivers/tee/optee/optee_ffa.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* - * Copyright (c) 2019-2021, Linaro Limited + * Copyright (c) 2019-2021, 2023 Linaro Limited */ /* @@ -73,7 +73,7 @@ * * Call register usage: * w3: Service ID, OPTEE_FFA_EXCHANGE_CAPABILITIES - * w4-w7: Note used (MBZ) + * w4-w7: Not used (MBZ) * * Return register usage: * w3: Error code, 0 on success @@ -82,14 +82,16 @@ * OPTEE_FFA_YIELDING_CALL_WITH_ARG. * Bit[31:8]: Reserved (MBZ) * w5: Bitfield of secure world capabilities OPTEE_FFA_SEC_CAP_* below, - * unused bits MBZ. - * w6-w7: Not used (MBZ) + * w6: The maximum secure world notification number + * w7: Not used (MBZ) */ /* * Secure world supports giving an offset into the argument shared memory * object, see also OPTEE_FFA_YIELDING_CALL_WITH_ARG */ #define OPTEE_FFA_SEC_CAP_ARG_OFFSET BIT(0) +/* OP-TEE supports asynchronous notification via FF-A */ +#define OPTEE_FFA_SEC_CAP_ASYNC_NOTIF BIT(1) #define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2) @@ -108,6 +110,24 @@ */ #define OPTEE_FFA_UNREGISTER_SHM OPTEE_FFA_BLOCKING_CALL(3) +/* + * Inform OP-TEE that the normal world is able to receive asynchronous + * notifications. + * + * Call register usage: + * w3: Service ID, OPTEE_FFA_ENABLE_ASYNC_NOTIF + * w4: Notification value to request bottom half processing, should be + * less than OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE. + * w5-w7: Not used (MBZ) + * + * Return register usage: + * w3: Error code, 0 on success + * w4-w7: Note used (MBZ) + */ +#define OPTEE_FFA_ENABLE_ASYNC_NOTIF OPTEE_FFA_BLOCKING_CALL(5) + +#define OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE 64 + /* * Call with struct optee_msg_arg as argument in the supplied shared memory * with a zero internal offset and normal cached memory attributes. diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 0dcc39349509..a5a2d6e63782 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -147,12 +147,14 @@ struct optee_smc { * struct optee_ffa_data - FFA communication struct * @ffa_dev FFA device, contains the destination id, the id of * OP-TEE in secure world - * @ffa_ops FFA operations + * @bottom_half_value Notification ID used for bottom half signalling or + * U32_MAX if unused * @mutex Serializes access to @global_ids * @global_ids FF-A shared memory global handle translation */ struct optee_ffa { struct ffa_device *ffa_dev; + u32 bottom_half_value; /* Serializes access to @global_ids */ struct mutex mutex; struct rhashtable global_ids; From ed23b1b201ec324f8287328e9fd7eb929b4349c3 Mon Sep 17 00:00:00 2001 From: Carlos Bilbao Date: Tue, 31 Oct 2023 10:13:25 -0500 Subject: [PATCH 0835/7721] docs/sp_SP: Add translation of process/handling-regressions Translate Documentation/process/handling-regressions.rst into Spanish. Co-developed-by: Sergio Gonzalez Signed-off-by: Sergio Gonzalez Signed-off-by: Carlos Bilbao Signed-off-by: Jonathan Corbet Message-ID: <20231031151325.2903088-1-carlos.bilbao@amd.com> --- .../sp_SP/process/handling-regressions.rst | 797 ++++++++++++++++++ .../translations/sp_SP/process/index.rst | 1 + 2 files changed, 798 insertions(+) create mode 100644 Documentation/translations/sp_SP/process/handling-regressions.rst diff --git a/Documentation/translations/sp_SP/process/handling-regressions.rst b/Documentation/translations/sp_SP/process/handling-regressions.rst new file mode 100644 index 000000000000..aa0988985c55 --- /dev/null +++ b/Documentation/translations/sp_SP/process/handling-regressions.rst @@ -0,0 +1,797 @@ +.. include:: ../disclaimer-sp.rst + +:Translator: Sergio González Collado + +.. _sp_handling_regressions: + +Gestión de regresiones +++++++++++++++++++++++ + +*No causamos regresiones* -- este documento describe la que es la "primera +regla del desarrollo del kernel de Linux" y que implica en la práctica para +los desarrolladores. Y complementa la documentación: +Documentation/admin-guide/reporting-regressions.rst, que cubre el tema +desde el punto de vista de un usuario; si nunca ha leído ese texto, realice +al menos una lectura rápida del mismo antes de continuar. + +Las partes importantes (el "TL;DR") +=================================== + +#. Asegúrese de que los suscriptores a la lista `regression mailing list + `_ (regressions@lists.linux.dev) + son conocedores con rapidez de cualquier nuevo informe de regresión: + + * Cuando se reciba un correo que no incluyó a la lista, inclúyalo en la + conversación de los correos, mandando un breve "Reply-all" con la + lista en CCed. + + * Mande o redirija cualquier informe originado en los gestores de bugs + a la lista. + +#. Haga que el bot del kernel de Linux "regzbot" realice el seguimiento del + incidente (esto es opcional, pero recomendado). + + * Para reportes enviados por correo, verificar si contiene alguna línea + como ``#regzbot introduced v5.13..v5.14-rc1``. Si no, mandar una + respuesta (con la lista de regresiones en CC) que contenga un párrafo + como el siguiente, lo que le indica a regzbot cuando empezó a suceder + el incidente:: + + #regzbot ^introduced 1f2e3d4c5b6a + + * Cuando se mandan informes desde un gestor de incidentes a la lista de + regresiones(ver más arriba), incluir un párrafo como el siguiente:: + + #regzbot introduced: v5.13..v5.14-rc1 + #regzbot from: Some N. Ice Human + #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789 + +#. Cuando se manden correcciones para las regresiones, añadir etiquetas + "Link:" a la descripción, apuntado a todos los sitios donde se informó + del incidente, como se indica en el documento: + Documentation/process/submitting-patches.rst y + :ref:`Documentation/process/5.Posting.rst `. + +#. Intente arreglar las regresiones rápidamente una vez la causa haya sido + identificada; las correcciones para la mayor parte de las regresiones + deberían ser integradas en menos de dos semanas, pero algunas pueden + resolverse en dos o tres días. + +Detalles importantes para desarrolladores en la regresiones de kernel de Linux +============================================================================== + +Puntos básicos importantes más en detalle +----------------------------------------- + +Qué hacer cuando se recibe un aviso de regresión. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Asegúrese de que el programa de gestión de regresiones del kernel de Linux +y los subscritos a la lista de correo `regression mailing list +`_ (regressions@lists.linux.dev) son +conocedores de cualquier nuevo informe de regresión: + + * Cuando se recibe un informe por email que no tiene en CC la lista, + inmediatamente meterla en el la cadena de emails mandado al menos un + breve "Reply-all" con la lista en CC; Intentar asegurar que la lista es + añadida en CC de nuevo en caso de que alguna respuesta la omita de la + lista. + + * Si un informe enviado a un gestor de defectos, llega a su correo, + reenvíelo o redirijalo a la lista. Considere verificar los archivos de + la lista de antemano, si la persona que lo ha informado, lo ha enviado + anteriormente, como se indica en: + Documentation/admin-guide/reporting-issues.rst. + +Cuando se realice cualquiera de las acciones anteriores, considere +inmediatamente iniciar el seguimiento de la regresión con "regzbot" el +gestor de regresiones del kernel de Linux. + + * Para los informes enviados por email, verificar si se ha incluido un + comando a "regzbot", como ``#regzbot introduced 1f2e3d4c5b6a``. Si no es + así, envíe una respuesta (con la lista de regresiones en CC) con un + párrafo como el siguiente:: + + #regzbot ^introduced: v5.13..v5.14-rc1 + + Esto indica a regzbot el rango de versiones en el cual es defecto + comenzó a suceder; Puede especificar un rango usando los identificadores + de los commits así como un único commit, en caso en el que el informante + haya identificado el commit causante con 'bisect'. + + Tenga en cuenta que el acento circunflejo (^) antes de "introduced": + Esto indica a regzbot, que debe tratar el email padre (el que ha sido + respondido) como el informeinicial para la regresión que quiere ser + seguida. Esto es importante, ya que regzbot buscará más tarde parches + con etiquetas "Link:" que apunten al al informe de losarchivos de + lore.kernel.org. + + * Cuando mande informes de regresiones a un gestor de defectos, incluya un + párrafo con los siguientes comandos a regzbot:: + + #regzbot introduced: 1f2e3d4c5b6a + #regzbot from: Some N. Ice Human + #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789 + + Regzbot asociará automáticamente parches con el informe que contengan + las etiquetas "Link:" apuntando a su email o el ticket indicado. + +Qué es importante cuando se corrigen regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +No se necesita hacer nada especial cuando se mandan las correcciones para +las regresiones únicamente recordar lo que se explica en los documentos: +Documentation/process/submitting-patches.rst, +:ref:`Documentation/process/5.Posting.rst `, y +Documentation/process/stable-kernel-rules.rst + + * Apunte a todos los lugares donde el incidente se reportó usando la + etiqueta "Link:" :: + + Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/ + Link: https://bugzilla.kernel.org/show_bug.cgi?id=1234567890 + + * Añada la etiqueta "Fixes:" para indicar el commit causante de la + regresión. + + * Si el culpable ha sido "mergeado" en un ciclo de desarrollo anterior, + marque explícitamente el fix para retro-importarlo usando la etiqueta + ``Cc: stable@vger.kernel.org`` tag. + +Todo esto se espera y es importante en una regresión, ya que estas +etiquetas son de gran valor para todos (incluido usted) que pueda estar +mirando en ese incidente semanas, meses o años después. Estas etiquetas son +también cruciales para las herramientas y scripts usados por otros +desarrolladores del kernel o distribuciones de Linux; una de esas +herramientas es regzbot, el cual depende mucho de las etiquetas "Link:" +para asociar los informes por regresiones con los cambios que las +resuelven. + + +Priorización del trabajo en arreglar regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Al final, los desarrolladores deberían hacer lo posible para evitar a los +usuarios situaciones donde una regresión les deje solo tres opciones: + + * Ejecutar el kernel con una regresión que afecta seriamente al uso. + + * Cambiar a un kernel nuevo o mas antiguo -- rebajarse a una versión + soportada del kernel que no tenga las funcionalidades requeridas. + + * Continuar ejecutando una versión desfasada y potencialmente insegura del + kernel por más de dos semanas después de que el causante de una regresión + fuese identificado. + +Cómo se ejecuta esto depende mucho de la situación. A continuación se +presentan unas reglas generales, en orden de importancia: + + * Priorice el trabajo en la gestión de los informes de la regresión y + arreglar la regresión por encima de cualquier otro trabajo en el kernel + de Linux, a menos que lo último afecte profundamente a efectos de + seguridad, o cause errores en los que haya pérdida o daño de datos. + + * Considere siempre revertir los commits responsables y re-aplicarlos + después, junto con las correcciones necesarias, ya que esto puede la + forma menos peligrosa y más rápida de arreglar la regresión. + + * Los desarrolladores deberían gestionar la regresión en todos los kernels + soportados de la serie, pero son libres de delegar el trabajo al equipo + permanente el incidente no hubiese ocurrido en la línea principal. + + * Intente resolver cualquier regresión que apareciera en el ciclo de + desarrollo antes de que este acabe. Si se teme que una corrección + pudiera ser demasiado arriesgada para aplicarla días antes de una + liberación de la línea principal de desarrollo, dejar decidir a Linus: + mande la corrección a él de forma separada, tan pronto como sea posible + con una explicación de la situación. El podrá decidir, y posponer la + liberación si fuese necesario, por ejemplo si aparecieran múltiples + cambios como ese. + + * Gestione las regresiones en la rama estable, de largo término, o la + propia rama principal de las versiones, con más urgencia que la + regresiones en las preliberaciones. Esto cambia después de la liberación + de la quinta pre-liberación, aka "-rc5": la rama principal entonces se + vuelve más importante, asegurar que todas las mejoras y correcciones son + idealmente testeados juntos por al menos una semana antes de que Linux + libere la nueva versión en la rama principal. + + * Intente arreglar regresiones en un intervalo de una semana después de + que se ha identificado el responsable, si el incidente fue introducido + en alguno de los siguientes casos: + + * una versión estable/largo-plazo reciente + + * en el último ciclo de desarrollo de la rama principal + + En el último caso (por ejemplo v5.14), intentar gestionar las + regresiones incluso más rápido, si la versión estable precedente (v5.13) + ha de ser abandonada pronto o ya se ha etiquetado como de final de vida + (EOL de las siglas en inglés End-of-Life) -- esto sucede usualmente + sobre tres o cuatro semanas después de una liberación de una versión en + la rama principal. + + * Intente arreglar cualquier otra regresión en un periodo de dos semanas + después de que el culpable haya sido identificado. Dos o tres semanas + adicionales son aceptables para regresiones de rendimiento y otros + incidentes que son molestos, pero no bloquean a nadie la ejecución de + Linux (a menos que se un incidente en el ciclo de desarrollo actual, en + ese caso se debería gestionar antes de la liberación de la versión). + Unas semanas son aceptables si la regresión únicamente puede ser + arreglada con un cambio arriesgado y al mismo tiempo únicamente afecta a + unos pocos usuarios; también está bien si se usa tanto tiempo como fuera + necesario si la regresión está presente en la segunda versión más nueva + de largo plazo del kernel. + +Nota: Los intervalos de tiempo mencionados anteriormente para la resolución +de las regresiones, incluyen la verificación de esta, revisión e inclusión +en la rama principal, idealmente con la corrección incluida en la rama +"linux-next" al menos brevemente. Esto conllevará retrasos que también se +tienen tener en cuenta. + +Se espera que los maintainers de los subsistemas, ayuden en conseguir esos +tiempos, haciendo revisiones con prontitud y gestionando con rapidez los +parches aceptados. Esto puede resultar en tener que mandar peticiones de +git-pull antes o de forma más frecuente que lo normal; dependiendo del +arreglo, podría incluso ser aceptable saltarse la verificación en +linux-next. Especialmente para las correcciones en las ramas de los kernels +estable y de largo plazo necesitan ser gestionadas rápidamente, y las +correcciones necesitan ser incluidas en la rama principal antes de que +puedan ser incluidas posteriormente a las series precedentes. + + +Más aspectos sobre regresiones que los desarrolladores deben saber +------------------------------------------------------------------ + +Cómo tratar con cambios donde se sabe que hay riesgo de regresión +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Evalué cómo de grande es el riesgo de una regresión, por ejemplo realizando +una búsqueda en las distribuciones de linux y en Git forges. Considere +también preguntar a otros desarrolladores o proyectos que pudieran ser +afectados para evaluar o incluso testear el cambio propuesto; si +apareciesen problemas, quizás se pudiera encontrar una solución aceptable +para todos. + +Si al final, el riesgo de la regresión parece ser relativamente pequeño, +entonces adelante con el cambio, pero siempre informe a todas las partes +involucradas del posible riesgo. Por tanto, asegúrese de que la descripción +del parche, se hace explícito este hecho. Una vez el cambio ha sido +integrado, informe al gestor de regresiones de Linux y a las listas de +correo de regresiones sobre el riesgo, de manera que cualquiera que tenga +el cambio en el radar, en el caso de que aparezcan reportes. Dependiendo +del riesgo, quizás se quiera preguntar al mantenedor del subsistema, que +mencione el hecho en su línea principal de desarrollo. + +¿Qué más hay que saber sobre regresiones? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Repase la documentación: Documentation/admin-guide/reporting-regressions.rst, +esta cubre otros aspectos a tener a en cuenta y conocer: + + * la finalidad de la "regla de no regresión" + + * qué incidencias no se califican como regresión + + * quién es el responsable de identificar la causa raíz de una regresión + + * cómo gestionar situaciones difíciles, como por ejemplo cuando una + regresión es causada por una corrección de seguridad o cuando una + regresión causa otra regresión + +A quién preguntar por consejo cuando se trata de regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mande un email a la lista de correo de regresiones +(regressions@lists.linux.dev) y CC al seguidor de regresiones del kernel de +Linux (regressions@leemhuis.info); Si el incidente pudiera ser mejor +gestionarlo en privado, puede omitirse la lista. + + +Más sobre la gestión de regresiones con regzbot +----------------------------------------------- + +¿Por qué el kernel de Linux tiene un gestor de regresiones, y por qué se usa regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Reglas como "no regresiones" necesitan asegurar que se cumplen, de otro +modo se romperían accidentalmente o a propósito. La historia ha mostrado +que esto es verdad también para el kernel de Linux. Esto es por lo que +Thorsten Leemhuis se ofreció como voluntario para dar una solución a esto, +con el gestor de regresiones del kernel de Linux. A nadie se le paga por +hacer esto, y esa es la razón por la gestión de regresiones es un servicio +con el "mejor esfuerzo". + +Intentos iniciales de gestionar manualmente las regresiones han demostrado +que es una tarea extenuante y frustrante, y por esa razón se dejaron de +hacer después de un tiempo. Para evitar que volviese a suceder esto, +Thorsten desarrollo regbot para facilitar el trabajo, con el objetivo a +largo plazo de automatizar la gestión de regresiones tanto como fuese +posible para cualquiera que estuviese involucrado. + +¿Cómo funciona el seguimiento de regresiones con regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +El bot monitoriza las respuestas de los informes de las regresiones +identificadas. Adicionalmente mira si se han publicado o enviado parches +que hagan referencia a esos informes con la etiqueta: "Link:"; respuestas a +esos parches también se siguen. Combinando esta información, también +proporciona una buena imagen del estado actual del proceso de corrección. + +Regzbot intenta hacer todo este trabajo con tan poco retraso como sea +posible tanto para la gente que lo reporta, como para los desarrolladores. +De hecho, solo los informantes son requeridos para una tarea adicional: +necesitan informar a regzbot con el comando ``#regzbot introduced`` +indicado anteriormente; si no hacen esto, alguien más puede hacerlo usando +``#regzbot ^introduced``. + +Para los desarrolladores normalmente no hay un trabajo adicional que +realizar, únicamente necesitan asegurarse una cosa, que ya se hacía mucho +antes de que regzbot apareciera: añadir las etiquetas "Link:" a la +descripción del parche apuntando a todos los informes sobre el error +corregido. + +¿Tengo que usar regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~ + +Hacerlo es por el bien de todo el mundo, tanto los mantenedores del kernel, +como Linus Torvalds dependen parcialmente en regzbot para seguir su trabajo +-- por ejemplo cuando deciden liberar una nueva versión o ampliar la fase de +desarrollo. Para esto necesitan conocer todas las regresiones que están sin +corregir; para esto, es conocido que Linux mira los informes semanales que +manda regzbot. + +¿He de informar a regzbot cada regresión que encuentre? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Idealmente, sí: todos somos humanos y olvidamos fácilmente los problemas +cuando algo más importante aparece inesperadamente -- por ejemplo un +problema mayor en el kernel de Linux o algo en la vida real que nos mantenga +alejados de los teclados por un tiempo. Por eso es mejor informar a regzbot +sobre cada regresión, excepto cuando inmediatamente escribimos un parche y +los mandamos al árbol de desarrollo en el que se integran habitualmente a +la serie del kernel. + +¿Cómo ver qué regresiones esta siguiendo regbot actualmente? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Verifique el `interfaz web de regzbot `_ +para ver la última información; o `busque el último informe de regresiones +`_, +el cual suele ser enviado por regzbot una vez a la semana el domingo por la +noche (UTC), lo cual es unas horas antes de que Linus normalmente anuncie +las "(pre-)releases". + +¿Qué sitios supervisa regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Regzbot supervisa las listas de correo más importantes de Linux, como +también las de los repositorios linux-next, mainline y stable/longterm. + + +¿Qué tipos de incidentes han de ser monitorizados por regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +El bot debe hacer seguimiento de las regresiones, y por tanto por favor, +no involucre a regzbot para incidencias normales. Pero es correcto para +el gestor de incidencias de kernel de Linux, monitorizar incidentes +graves, como informes sobre cuelgues, corrupción de datos o errores +internos (Panic, Oops, BUG(), warning, ...). + + +¿Puedo añadir una regresión detectada por un sistema de CI al seguimiento de regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Siéntase libre de hacerlo, si la regresión en concreto puede tener un +impacto en casos de uso prácticos y por tanto ser detectado por los usuarios; +Así, por favor no involucre a regzbot en regresiones teóricas que +difícilmente pudieran manifestarse en un uso real. + +¿Cómo interactuar con regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Usando el comando 'regzbot' en una respuesta directa o indirecta al correo +con el informe de regresión. Ese comando necesita estar en su propio +párrafo (debe estar separado del resto del texto usando líneas en blanco): + +Por ejemplo ``#regzbot introduced ``, que hace que regzbot +considere el correo como un informe de regressión que se ha de añadir al +seguimiento, como se ha descrito anteriormente; ``#regzbot ^introduced `` +es otro ejemplo del comando, el cual indica a regzbot que considere el email +anterior como el informe de una regresión que se ha de comenzar a monitorizar. + +Una vez uno de esos dos comandos se ha utilizado, se pueden usar otros +comandos regzbot en respuestas directas o indirectas al informe. Puede +escribirlos debajo de uno de los comandos anteriormente usados o en las +respuestas al correo en el que se uso como respuesta a ese correo: + + * Definir o actualizar el título:: + + #regzbot title: foo + + * Monitorizar una discusión o un tiquet de bugzilla.kernel.org donde + aspectos adicionales del incidente o de la corrección se están + comentando -- por ejemplo presentar un parche que corrige la regresión:: + + #regzbot monitor: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/ + + Monitorizar solamente funciona para lore.kernel.org y bugzilla.kernel.org; + regzbot considerará todos los mensajes en ese hilo o el tiquet como + relacionados al proceso de corrección. + + * Indicar a un lugar donde más detalles de interés, como un mensaje en una + lista de correo o un tiquet en un gestor de incidencias que pueden estar + levemente relacionados, pero con un tema diferente:: + + #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789 + + * Identificar una regresión como corregida por un commit que se ha mandado + aguas arriba o se ha publicado:: + + #regzbot fixed-by: 1f2e3d4c5d + + + * Identificar una regresión como un duplicado de otra que ya es seguida + por regzbot:: + + #regzbot dup-of: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/ + + * Identificar una regresión como inválida:: + + #regzbot invalid: wasn't a regression, problem has always existed + + +¿Algo más que decir sobre regzbot y sus comandos? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hay información más detallada y actualizada sobre el bot de seguimiento de +regresiones del kernel de Linux en: `project page `_, +y entre otros contiene una `guia de inicio `_ +y `documentación de referencia `_ +Ambos contienen más detalles que las secciones anteriores. + + +Citas de Linus sobre regresiones +-------------------------------- + +A continuación se encuentran unos ejemplos reales (traducidos) de como +Linus Torvalds espera que se gestionen las regresiones: + + + * De 2017-10-26 (1/2) + `_:: + + Si rompes la configuración de los espacios de usuario ESO ES UNA REGRESIÓN. + + No está bien decir "pero nosotros arreglaremos la configuración del espacio + de usuario". + + Realmente. NO ESTÁ BIEN. + + [...] + + La primera regla es: + + - no causamos regresiones + + y el corolario es que cuando una regresión pasa, lo admitimos y lo + arreglamos, en vez de echar la culpa al espacio de usuario. + + El hecho de que aparentemente se haya negado la regresión durante + tres semanas, significa que lo revertiré y dejaré de integrar peticiones + de apparmor hasta que la gente involucrada entienda como se hace + el desarrollo del kernel. + + + * De `2017-10-26 (2/2) + `_:: + + La gente debería sentirse libre de actualizar su kernel y simplemente + no preocuparse por ello. + + Me niego a imponer una limitación del tipo "solo puede actualizar + el kernel si actualiza otro programa". Si el kernel trabaja para tí, + la regla es que continúe trabajando para tí. + + Ha habido algunas excepciones, pero son pocas y separadas entre sí, y + generalmente tienen una razón fundamental para haber sucedido, que era + básicamente inevitable, y la gente intentó evitarlas por todos los + medios. Quizás no podamos mantener el hardware más, después de que han + pasado décadas y nadie los usacon kernel modernos. Quizás haya un + problema de seguridad serio con cómo hicimos las cosas, y la gente + depende de un modelo fundamentalmente roto. Quizás haya algún otro roto + fundamental, que tenga que tener una _flag_ y por razones internas y + fundamentales. + + Y nótese que esto trata sobre *romper* los entornos de la gente. + + Cambios de comportamiento pasan, y quizás no se mantengan algunas + funcionalidades más. Hay un número de campos en /proc//stat que + se imprimen como ceros, simplemente porque ni siquiera existen ya en + kernel, o porque mostrarlos era un error (típica una fuga de + información). Pero los números se sustituyeron por ceros, así que + el código que se usaba para parsear esos campos todavía existe. El + usuario puede no ver todo lo que podía ver antes, y por eso el + omportamiento es claramente diferente, pero las cosas todavía + _funcionan_, incluso si no se puede mostrar información sensible + (o que no es ya importante). + + Pero si algo realmente se rompe, entonces el cambio debe de arreglarse + o revertirse. Y se arregla en el *kernel*. No diciendo "bueno, arreglaremos + tu espacio de usuario". Ha sido un cambio en el kernel el que creo + el problema, entonces ha de ser el kernel el que lo corrija, porque + tenemos un modelo de "actualización". Pero no tenemos una "actualización + con el nuevo espacio de usuario". + + Y yo seriamente me negaré a coger código de gente que no entiende y + honre esta sencilla regla. + + Y esta regla no va a cambiar. + + Y sí, me doy cuenta que el kernel es "especial" en este respecto. Y + estoy orgulloso de ello. + + Y he visto, y puedo señalar, muchos proyectos que dicen "Tenemos que + romper ese caso de uso para poder hacer progresos" o "estabas basandote + en comportamientos no documentados, debe ser duro ser tú" o "hay una + forma mejor de hacer lo que quieres hacer, y tienes que cambiar a esa + nueva forma", y yo simplemente no pienso que eso sea aceptable fuera + de una fase alfa muy temprana que tenga usuarios experimentales que + saben a lo que se han apuntado. El kernel no ha estado en esta + situación en las dos últimas décadas. + + Nosotros rompemos la API _dentro_ del kernel todo el tiempo. Y + arreglaremos los problemas internos diciendo "tú ahora necesitas + hacer XYZ", pero entonces es sobre la API interna del kernel y la + gente que hace esto entonces tendrá obviamente que arreglar todos + los usos de esa API del kernel. Nadie puede decir "ahora, yo he roto + la API que usas, y ahora tú necesitas arreglarlo". Quién rompa algo, + lo arregla también. + + Y nosotros, simplemente, no rompemos el espacio de usuario. + + * De `2020-05-21 + `_:: + + Las reglas sobre regresiones nunca han sido sobre ningún tipo de + comportamiento documentado, o dónde está situado el código. + + Las reglas sobre regresiones son siempre sobre "roturas en el + flujo de trabajo del usuario". + + Los usuarios son literalmente la _única_ cosa que importa. + + Argumentaciones como "no debería haber usado esto" o "ese + comportamiento es indefinido, es su culpa que su aplicación no + funcione" o "eso solía funcionar únicamente por un bug del kernel" son + irrelevantes. + + Ahora, la realidad nunca es blanca o negra. Así hemos tenido situaciones + como "un serio incidente de seguridad" etc que solamente nos fuerza + a hacer cambios que pueden romper el espacio de usuario. Pero incluso + entonces la regla es que realmente no hay otras opciones para que + las cosas sigan funcionando. + + Y obviamente, si los usuarios tardan años en darse cuenta que algo + se ha roto, o si hay formas adecuadas para sortear la rotura que + no causen muchos problemas para los usuarios (por ejemplo: "hay un + puñado de usuarios, y estos pueden usar la línea de comandos del + kernel para evitarlos"; ese tipo de casos), en esos casos se ha sido + un poco menos estricto. + + Pero no, "eso que está documentado que está roto" (si es dado a que + el código estaba en preparación o porque el manual dice otra cosa) eso + es irrelevante. Si preparar el código es tan útil que la gente, + acaba usando, esto implica que básicamente es código del kernel con + una señal diciendo "por favor limpiar esto". + + El otro lado de la moneda es que la gente que habla sobre "estabilidad + de las APIs" están totalmente equivocados. Las APIs tampoco importan. + Se puede hacer cualquier cambio que se quiera a una API ... siempre y + cuando nadie se de cuenta. + + De nuevo, la regla de las regresiones no trata sobre la documentación, + tampoco sobre las APIs y tampoco sobre las fases de la Luna. + + Únicamente trata sobre "hemos causado problemas al espacio de usuario que + antes funcionaba". + + * De `2017-11-05 + `_:: + + Y nuestra regla sobre las regresiones nunca ha sido "el comportamiento + no cambia". Eso podría significar que nunca podríamos hacer ningún + cambio. + + Por ejemplo, hacemos cosas como añadir una nueva gestión de + errores etc todo el tiempo, con lo cual a veces incluso añadimos + tests en el directorio de kselftest. + + Así que claramente cambia el comportamiento todo el tiempo y + nosotros no consideramos eso una regresión per se. + + La regla para regresiones para el kernel es para cuando se + rompe algo en el espacio de usuario. No en algún test. No en + "mira, antes podía hacer X, y ahora no puedo". + + * De `2018-08-03 + `_:: + + ESTÁS OLVIDANDO LA REGLA #1 DEL KERNEL. + + No hacemos regresiones, y no hacemos regresiones porque estás 100% + equivocado. + + Y la razón que apuntas en tú opinión es exactamente *PORQUÉ* estás + equivocado. + + Tus "buenas razones" son honradas y pura basura. + + El punto de "no hacemos regresiones" es para que la gente pueda + actualizar el kernel y nunca tengan que preocuparse por ello. + + > El kernel tiene un bug que ha de ser arreglado + + Eso es *TOTALMENTE* insustancial. + + Chicos, si algo estaba roto o no, NO IMPORTA. + + ¿Porqué? + + Los errores pasan. Eso es un hecho de la vida. Discutir que + "tenemos que romper algo porque estábamos arreglando un error" es + una locura. Arreglamos decenas de errores cada dia, pensando que + "arreglando un bug" significa que podemos romper otra cosa es algo + que simplemente NO ES VERDAD. + + Así que los bugs no son realmente relevantes para la discusión. Estos + suceden y se detectan, se arreglan, y no tienen nada que ver con + "rompemos a los usuarios". + + Porque la única cosa que importa ES EL USUARIO. + + ¿Cómo de complicado es eso de comprender? + + Cualquier persona que use "pero no funcionaba correctamente" es + un argumento no tiene la razón. Con respecto al USUARIO, no era + erróneo - funcionaba para él/ella. + + Quizás funcionaba *porque* el usuario había tenido el bug en cuenta, + y quizás funcionaba porque el usuario no lo había notado - de nuevo + no importa. Funcionaba para el usuario. + + Romper el flujo del trabajo de un usuario, debido a un "bug" es la + PEOR razón que se pueda usar. + + Es básicamente decir "He cogido algo que funcionaba, y lo he roto, + pero ahora es mejor". ¿No ves que un argumento como este es j*didamente + absurdo? + + y sin usuarios, tu programa no es un programa, es una pieza de + código sin finalidad que puedes perfectamente tirar a la basura. + + Seriamente. Esto es *porque* la regla #1 para el desarrollo del + kernel es "no rompemos el espacio de usuario". Porque "He arreglado + un error" PARA NADA ES UN ARGUMENTO si esa corrección del código + rompe el espacio de usuario. + + si actualizamos el kernel TODO EL TIEMPO, sin actualizar ningún otro + programa en absoluto. Y esto es absolutamente necesario, porque + las dependencias son terribles. + + Y esto es necesario simplemente porque yo como desarrollador del + kernel no actualizo al azar otras herramientas que ni siquiera me + importan como desarrollador del kernel, y yo quiero que mis usuarios + se sientan a salvo haciendo lo mismo. + + Así que no. Tu regla está COMPLETAMENTE equivocada. Si no puedes + actualizar el kernel sin actualizar otro binario al azar, entonces + tenemos un problema. + + * De `2021-06-05 + `_:: + + NO HAY ARGUMENTOS VÁLIDOS PARA UNA REGRESIÓN. + + Honestamente, la gente de seguridad necesita entender que "no funciona" + no es un caso de éxito sobre seguridad. Es un caso de fallo. + + Sí, "no funciona" puede ser seguro. Pero en este caso es totalmente + inutil. + + * De `2011-05-06 (1/3) + `_:: + + La compatibilidad de los binarios es más importante. + + Y si los binarios no usan el interfaz para parsear el formato + (o justamente lo parsea incorrectamente - como el reciente ejemplo + de añadir uuid al /proc/self/mountinfo), entonces es una regresión. + + Y las regresiones se revierten, a menos que haya problemas de + seguridad o similares que nos hagan decir "Dios mío, realmente + tenemos que romper las cosas". + + No entiendo porqué esta simple lógica es tan difícil para algunos + desarrolladores del kernel. La realidad importa. Sus deseos personales + NO IMPORTAN NADA. + + Si se crea un interface que puede usarse sin parsear la + descripción del interface, entonces estaḿos atascados en el interface. + La teoría simplemente no importa. + + Podrias alludar a arreglar las herramientas, e intentar evitar los + errores de compatibilidad de ese modo. No hay tampoco tantos de esos. + + De `2011-05-06 (2/3) + `_:: + + Esto claramente NO es un tracepoint interno. Por definición. Y está + siendo usado por powertop. + + De `2011-05-06 (3/3) + `_:: + + Tenemos programas que usan esa ABI y si eso se rompe eso es una + regresión. + + * De `2012-07-06 `_:: + + > Ahora esto me ha dejado preguntandome si Debian _inestable_ + realmente califica + > como espacio de usuario estándar. + + Oh, si el kernel rompe algún espacio de usuario estándar, eso cuenta. + Muchísima gente usa Debian inestable. + + * De `2019-09-15 + `_:: + + Una reversión _en particular_ en el último minuto en el último commit + (no teniendo en cuenta el propio cambio de versión) justo antes + de la liberación, y aunque es bastante incómodo, quizás también es + instructivo. + + Lo que es instructivo sobre esto es que he revertido un commit que no + tenía ningún error. De hecho, hacía exactamente lo que pretendía, y lo + hacía muy bien. De hecho lo hacía _tan_ bien que los muy mejorados + patrones de IO que causaba han acabado revelando una regresión observable + desde el espacio de usuario, debido a un error real en un componente + no relacionado en absoluto. + + De todas maneras, los detalles actuales de esta regresión no son la + razón por la que señalo esto como instructivo. Es más que es un ejemplo + ilustrativo sobre lo que cuenta como una regresión, y lo que conlleva + la regla del kernel de "no regresiones". El commit que ha sido revertido + no cambiaba ninguna API, y no introducía ningún error nuevo en el código. + Pero acabó exponiendo otro problema, y como eso causaba que la + actualización del kernel fallara para el usuario. Así que ha sido + revertido. + + El foco aquí, es que hemos hecho la reversión basándonos en el + comportamiento reportado en el espacio de usuario, no basado en + conceptos como "cambios de ABI" o "provocaba un error". Los mejores + patrones de IO que se han presentado debido al cambio únicamente han + expuesto un viejo error, y la gente ya dependía del benigno + comportamiento de ese viejo error. + + Y que no haya miedo, reintroduciremos el arreglo que mejoraba los + patrones de IO una vez hayamos decidido cómo gestionar el hecho de + que hay una interacción incorrecta con un interfaz en el que la + gente dependía de ese comportamiento previo. Es únicamente que + tenemos que ver cómo gestionamos y cómo lo hacemos (no hay menos de + tres parches diferentes de tres desarrolladores distintos que estamos + evaluando, ... puede haber más por llegar). Mientras tanto, he + revertido lo que exponía el problema a los usuarios de esta release, + incluso cuando espero que el fix será reintroducido (quizás insertado + a posteriormente como un parche estable) una vez lleguemos a un + acuerdo sobre cómo se ha de exponer el error. + + Lo que hay que recordar de todo el asunto no es sobre si el cambio + de kernel-espacio-de-usuario ABI, o la corrección de un error, o si + el código antiguo "en primer lugar nunca debería haber estado ahí". + Es sobre si algo rompe el actual flujo de trabajo del usuario. + + De todas formas, esto era mi pequeña aclaración en todo este + tema de la regresión. Ya que es la "primera regla de la programación + del kernel", me ha parecido que quizás es bueno mencionarlo de + vez en cuando. diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst index d6f3ccfb160e..a082e162168a 100644 --- a/Documentation/translations/sp_SP/process/index.rst +++ b/Documentation/translations/sp_SP/process/index.rst @@ -24,3 +24,4 @@ contribution-maturity-model security-bugs embargoed-hardware-issues + handling-regressions From 4746be1d222d7cdfdbe90a71370ffd2e0baa24d0 Mon Sep 17 00:00:00 2001 From: Ariel Miculas Date: Fri, 27 Oct 2023 18:21:01 +0300 Subject: [PATCH 0836/7721] docs: vfs: fix typo in struct xattr_handlers The structure is called struct xattr_handler, singular, not plural. Fixing the typo also makes it greppable with the whole word matching flag. Signed-off-by: Ariel Miculas Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20231027152101.226296-1-amiculas@cisco.com> --- Documentation/filesystems/vfs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 99acc2e98673..276a219ff8d9 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -437,7 +437,7 @@ field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. -struct xattr_handlers +struct xattr_handler --------------------- On filesystems that support extended attributes (xattrs), the s_xattr From 407434939b072a4bc14f3e2b83823ba073cf8f42 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Wed, 1 Nov 2023 15:02:01 +0800 Subject: [PATCH 0837/7721] docs: dma: update a reference to a moved document Documentation/DMA-API.txt has moved to Documentation/core-api/dma-api.rst Signed-off-by: Li Zhijian Message-ID: <20231101070201.4066998-1-lizhijian@fujitsu.com> Signed-off-by: Jonathan Corbet --- Documentation/core-api/dma-api-howto.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/dma-api-howto.rst b/Documentation/core-api/dma-api-howto.rst index 72f6cdb6be1c..e8a55f9d61db 100644 --- a/Documentation/core-api/dma-api-howto.rst +++ b/Documentation/core-api/dma-api-howto.rst @@ -8,7 +8,7 @@ Dynamic DMA mapping Guide This is a guide to device driver writers on how to use the DMA API with example pseudo-code. For a concise description of the API, see -DMA-API.txt. +Documentation/core-api/dma-api.rst. CPU and DMA addresses ===================== From 5483cc3dfd8da2d82603cc4a18db21866d58308e Mon Sep 17 00:00:00 2001 From: Brian Johannesmeyer Date: Fri, 3 Nov 2023 17:21:20 +0100 Subject: [PATCH 0838/7721] docs: dma-api: Fix description of the sync_sg API Fix the description of the parameters to dma_sync_sg*. They should be the same as the parameters to dma_map_sg(), not dma_map_single(). Signed-off-by: Brian Johannesmeyer Signed-off-by: Jonathan Corbet Message-ID: <20231103162120.3474026-1-bjohannesmeyer@gmail.com> --- Documentation/core-api/dma-api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/dma-api.rst b/Documentation/core-api/dma-api.rst index 829f20a193ca..8e3cce3d0a23 100644 --- a/Documentation/core-api/dma-api.rst +++ b/Documentation/core-api/dma-api.rst @@ -448,7 +448,7 @@ DMA address entries returned. Synchronise a single contiguous or scatter/gather mapping for the CPU and device. With the sync_sg API, all the parameters must be the same -as those passed into the single mapping API. With the sync_single API, +as those passed into the sg mapping API. With the sync_single API, you can use dma_handle and size parameters that aren't identical to those passed into the single mapping API to do a partial sync. From 335bbdf01d25517ae832ac1807fd8323c1f4f3b9 Mon Sep 17 00:00:00 2001 From: Hu Haowen <2023002089@link.tyut.edu.cn> Date: Mon, 6 Nov 2023 22:01:40 +0800 Subject: [PATCH 0839/7721] docs/zh_TW: replace my email address The Gmail address will not be used often from now on, and replace it with the email which is more frequently accessed by myself. Signed-off-by: Hu Haowen <2023002089@link.tyut.edu.cn> Signed-off-by: Jonathan Corbet Message-ID: <20231106140140.25455-1-2023002089@link.tyut.edu.cn> --- .../translations/zh_CN/dev-tools/testing-overview.rst | 2 +- Documentation/translations/zh_TW/IRQ.txt | 8 ++++---- .../translations/zh_TW/admin-guide/README.rst | 2 +- .../translations/zh_TW/admin-guide/bug-bisect.rst | 2 +- .../translations/zh_TW/admin-guide/bug-hunting.rst | 2 +- .../zh_TW/admin-guide/clearing-warn-once.rst | 2 +- .../translations/zh_TW/admin-guide/cpu-load.rst | 2 +- Documentation/translations/zh_TW/admin-guide/index.rst | 2 +- Documentation/translations/zh_TW/admin-guide/init.rst | 2 +- .../zh_TW/admin-guide/reporting-issues.rst | 2 +- .../translations/zh_TW/admin-guide/security-bugs.rst | 2 +- .../translations/zh_TW/admin-guide/tainted-kernels.rst | 2 +- .../translations/zh_TW/admin-guide/unicode.rst | 2 +- Documentation/translations/zh_TW/arch/arm64/amu.rst | 2 +- .../translations/zh_TW/arch/arm64/booting.txt | 4 ++-- .../translations/zh_TW/arch/arm64/elf_hwcaps.rst | 2 +- .../translations/zh_TW/arch/arm64/hugetlbpage.rst | 2 +- Documentation/translations/zh_TW/arch/arm64/index.rst | 2 +- .../zh_TW/arch/arm64/legacy_instructions.txt | 4 ++-- Documentation/translations/zh_TW/arch/arm64/memory.txt | 4 ++-- Documentation/translations/zh_TW/arch/arm64/perf.rst | 2 +- .../translations/zh_TW/arch/arm64/silicon-errata.txt | 4 ++-- .../translations/zh_TW/arch/arm64/tagged-pointers.txt | 4 ++-- Documentation/translations/zh_TW/dev-tools/sparse.rst | 10 +++++----- .../translations/zh_TW/dev-tools/testing-overview.rst | 2 +- Documentation/translations/zh_TW/disclaimer-zh_TW.rst | 2 +- .../translations/zh_TW/filesystems/debugfs.rst | 2 +- Documentation/translations/zh_TW/filesystems/index.rst | 2 +- Documentation/translations/zh_TW/filesystems/sysfs.txt | 2 +- .../translations/zh_TW/filesystems/virtiofs.rst | 2 +- Documentation/translations/zh_TW/gpio.txt | 8 ++++---- Documentation/translations/zh_TW/index.rst | 2 +- Documentation/translations/zh_TW/io_ordering.txt | 8 ++++---- Documentation/translations/zh_TW/process/1.Intro.rst | 2 +- Documentation/translations/zh_TW/process/2.Process.rst | 2 +- .../translations/zh_TW/process/3.Early-stage.rst | 2 +- Documentation/translations/zh_TW/process/4.Coding.rst | 2 +- Documentation/translations/zh_TW/process/5.Posting.rst | 2 +- .../translations/zh_TW/process/6.Followthrough.rst | 2 +- .../translations/zh_TW/process/7.AdvancedTopics.rst | 2 +- .../translations/zh_TW/process/8.Conclusion.rst | 2 +- .../zh_TW/process/code-of-conduct-interpretation.rst | 2 +- .../translations/zh_TW/process/code-of-conduct.rst | 2 +- .../translations/zh_TW/process/coding-style.rst | 2 +- .../translations/zh_TW/process/development-process.rst | 2 +- .../translations/zh_TW/process/email-clients.rst | 2 +- .../zh_TW/process/embargoed-hardware-issues.rst | 2 +- Documentation/translations/zh_TW/process/howto.rst | 2 +- Documentation/translations/zh_TW/process/index.rst | 2 +- .../zh_TW/process/kernel-driver-statement.rst | 2 +- .../zh_TW/process/kernel-enforcement-statement.rst | 2 +- .../translations/zh_TW/process/license-rules.rst | 2 +- .../translations/zh_TW/process/magic-number.rst | 2 +- .../translations/zh_TW/process/management-style.rst | 2 +- .../zh_TW/process/programming-language.rst | 2 +- .../translations/zh_TW/process/stable-api-nonsense.rst | 2 +- .../translations/zh_TW/process/stable-kernel-rules.rst | 2 +- .../translations/zh_TW/process/submit-checklist.rst | 2 +- .../translations/zh_TW/process/submitting-patches.rst | 2 +- .../zh_TW/process/volatile-considered-harmful.rst | 2 +- MAINTAINERS | 2 +- 61 files changed, 79 insertions(+), 79 deletions(-) diff --git a/Documentation/translations/zh_CN/dev-tools/testing-overview.rst b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst index 69e7e4cb2002..c91f9b60f9f1 100644 --- a/Documentation/translations/zh_CN/dev-tools/testing-overview.rst +++ b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst @@ -3,7 +3,7 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/dev-tools/testing-overview.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ============ 内核测试指南 diff --git a/Documentation/translations/zh_TW/IRQ.txt b/Documentation/translations/zh_TW/IRQ.txt index fd78ca720298..8115a7618307 100644 --- a/Documentation/translations/zh_TW/IRQ.txt +++ b/Documentation/translations/zh_TW/IRQ.txt @@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Eric W. Biederman -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/core-api/irq/index.rst 的繁體中文翻譯 @@ -16,9 +16,9 @@ Documentation/core-api/irq/index.rst 的繁體中文翻譯 者翻譯存在問題,請聯繫繁體中文版維護者。 英文版維護者: Eric W. Biederman -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/admin-guide/README.rst b/Documentation/translations/zh_TW/admin-guide/README.rst index 4cb581f5994a..a6e34c200ea3 100644 --- a/Documentation/translations/zh_TW/admin-guide/README.rst +++ b/Documentation/translations/zh_TW/admin-guide/README.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux內核6.x版本 ========================================= diff --git a/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst index 3f10a9f8f223..1efe913b8da0 100644 --- a/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst +++ b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 二分(bisect)缺陷 +++++++++++++++++++ diff --git a/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst index 631fd2650929..c139ec99cab1 100644 --- a/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst +++ b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 追蹤缺陷 ========= diff --git a/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst index 6961006b4a2d..a3e82ff9daac 100644 --- a/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst +++ b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst @@ -2,7 +2,7 @@ .. include:: ../disclaimer-zh_TW.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 清除 WARN_ONCE -------------- diff --git a/Documentation/translations/zh_TW/admin-guide/cpu-load.rst b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst index cc046f3b7ffa..4c25a2105b39 100644 --- a/Documentation/translations/zh_TW/admin-guide/cpu-load.rst +++ b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst @@ -2,7 +2,7 @@ .. include:: ../disclaimer-zh_TW.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ======== CPU 負載 diff --git a/Documentation/translations/zh_TW/admin-guide/index.rst b/Documentation/translations/zh_TW/admin-guide/index.rst index aba8939351e0..9335c0e9105d 100644 --- a/Documentation/translations/zh_TW/admin-guide/index.rst +++ b/Documentation/translations/zh_TW/admin-guide/index.rst @@ -4,7 +4,7 @@ :Original: :doc:`../../../admin-guide/index` :Translator: Alex Shi - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核用戶和管理員指南 ========================== diff --git a/Documentation/translations/zh_TW/admin-guide/init.rst b/Documentation/translations/zh_TW/admin-guide/init.rst index be6e34f5f7fa..4cef1994c650 100644 --- a/Documentation/translations/zh_TW/admin-guide/init.rst +++ b/Documentation/translations/zh_TW/admin-guide/init.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 解釋“No working init found.”啓動掛起消息 ========================================= diff --git a/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst index fe5a5a07d51a..bc132b25f2ae 100644 --- a/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst +++ b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst @@ -9,7 +9,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 報告問題 diff --git a/Documentation/translations/zh_TW/admin-guide/security-bugs.rst b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst index c0e9fc247695..cfe1e58e116b 100644 --- a/Documentation/translations/zh_TW/admin-guide/security-bugs.rst +++ b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 安全缺陷 ========= diff --git a/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst index 47629f6b05de..0d8046576d04 100644 --- a/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst +++ b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 受污染的內核 ------------- diff --git a/Documentation/translations/zh_TW/admin-guide/unicode.rst b/Documentation/translations/zh_TW/admin-guide/unicode.rst index a2b48b5d0a64..f43edb2b5ed0 100644 --- a/Documentation/translations/zh_TW/admin-guide/unicode.rst +++ b/Documentation/translations/zh_TW/admin-guide/unicode.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Unicode(統一碼)支持 ====================== diff --git a/Documentation/translations/zh_TW/arch/arm64/amu.rst b/Documentation/translations/zh_TW/arch/arm64/amu.rst index 1b451eae2bee..3726c1671ab6 100644 --- a/Documentation/translations/zh_TW/arch/arm64/amu.rst +++ b/Documentation/translations/zh_TW/arch/arm64/amu.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/amu.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ================================== AArch64 Linux 中擴展的活動監控單元 diff --git a/Documentation/translations/zh_TW/arch/arm64/booting.txt b/Documentation/translations/zh_TW/arch/arm64/booting.txt index be0de91ecebd..f1ac96370ace 100644 --- a/Documentation/translations/zh_TW/arch/arm64/booting.txt +++ b/Documentation/translations/zh_TW/arch/arm64/booting.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. M: Will Deacon zh_CN: Fu Wei -zh_TW: Hu Haowen +zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn> C: 55f058e7574c3615dea4615573a19bdb258696c6 --------------------------------------------------------------------- Documentation/arch/arm64/booting.rst 的中文翻譯 @@ -23,7 +23,7 @@ Documentation/arch/arm64/booting.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 本文翻譯提交時的 Git 檢出點爲: 55f058e7574c3615dea4615573a19bdb258696c6 以下爲正文 diff --git a/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst index d2c1c2f23812..cada25303e8d 100644 --- a/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst +++ b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/elf_hwcaps.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ================ ARM64 ELF hwcaps diff --git a/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst index a17858c978d6..b6849935e028 100644 --- a/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst +++ b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/hugetlbpage.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ===================== ARM64中的 HugeTLBpage diff --git a/Documentation/translations/zh_TW/arch/arm64/index.rst b/Documentation/translations/zh_TW/arch/arm64/index.rst index a62b5f06b66c..86014346792e 100644 --- a/Documentation/translations/zh_TW/arch/arm64/index.rst +++ b/Documentation/translations/zh_TW/arch/arm64/index.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/arch/arm64/index.rst ` :Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_arm64_index: diff --git a/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt index 7d1f0593d7ca..5c664555a71a 100644 --- a/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt +++ b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt @@ -11,7 +11,7 @@ or if there is a problem with the translation. Maintainer: Punit Agrawal Suzuki K. Poulose Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/legacy_instructions.rst 的中文翻譯 @@ -26,7 +26,7 @@ Documentation/arch/arm64/legacy_instructions.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者:胡皓文 Hu Haowen +繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/arch/arm64/memory.txt b/Documentation/translations/zh_TW/arch/arm64/memory.txt index e41c518e71c6..6ee2239c293f 100644 --- a/Documentation/translations/zh_TW/arch/arm64/memory.txt +++ b/Documentation/translations/zh_TW/arch/arm64/memory.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. Maintainer: Catalin Marinas Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/memory.rst 的中文翻譯 @@ -24,7 +24,7 @@ Documentation/arch/arm64/memory.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/arch/arm64/perf.rst b/Documentation/translations/zh_TW/arch/arm64/perf.rst index 405d5f66964f..ce083ba63872 100644 --- a/Documentation/translations/zh_TW/arch/arm64/perf.rst +++ b/Documentation/translations/zh_TW/arch/arm64/perf.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/perf.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ============= Perf 事件屬性 diff --git a/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt index 70371807ca83..16d73b6c309f 100644 --- a/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt +++ b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. M: Will Deacon zh_CN: Fu Wei -zh_TW: Hu Haowen +zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn> C: 1926e54f115725a9248d0c4c65c22acaf94de4c4 --------------------------------------------------------------------- Documentation/arch/arm64/silicon-errata.rst 的中文翻譯 @@ -23,7 +23,7 @@ Documentation/arch/arm64/silicon-errata.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 本文翻譯提交時的 Git 檢出點爲: 1926e54f115725a9248d0c4c65c22acaf94de4c4 以下爲正文 diff --git a/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt index 9812d99549ba..e86ffa893ef6 100644 --- a/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt +++ b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. Maintainer: Will Deacon Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/tagged-pointers.rst 的中文翻譯 @@ -22,7 +22,7 @@ Documentation/arch/arm64/tagged-pointers.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/dev-tools/sparse.rst b/Documentation/translations/zh_TW/dev-tools/sparse.rst index 11d64709d6a4..55f0ad2c0beb 100644 --- a/Documentation/translations/zh_TW/dev-tools/sparse.rst +++ b/Documentation/translations/zh_TW/dev-tools/sparse.rst @@ -6,19 +6,19 @@ communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. -Traditional Chinese maintainer: Hu Haowen ---------------------------------------------------------------------- +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> +------------------------------------------------------------------------- Documentation/dev-tools/sparse.rst 的繁體中文翻譯 如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 者翻譯存在問題,請聯繫繁體中文版維護者。 -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 ---------------------------------------------------------------------- +------------------------------------------------------------------------- Copyright 2004 Linus Torvalds Copyright 2004 Pavel Machek diff --git a/Documentation/translations/zh_TW/dev-tools/testing-overview.rst b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst index fb3f691f46c3..3b08aad1da00 100644 --- a/Documentation/translations/zh_TW/dev-tools/testing-overview.rst +++ b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst @@ -3,7 +3,7 @@ .. include:: ../disclaimer-zh_TW.rst :Original: Documentation/dev-tools/testing-overview.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ============ 內核測試指南 diff --git a/Documentation/translations/zh_TW/disclaimer-zh_TW.rst b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst index 0d0ffb1ca4e8..28b734c223b6 100644 --- a/Documentation/translations/zh_TW/disclaimer-zh_TW.rst +++ b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst @@ -7,5 +7,5 @@ .. note:: 如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者, - 或者發送電子郵件給胡皓文以獲取幫助:。 + 或者發送電子郵件給胡皓文以獲取幫助:<2023002089@link.tyut.edu.cn>。 diff --git a/Documentation/translations/zh_TW/filesystems/debugfs.rst b/Documentation/translations/zh_TW/filesystems/debugfs.rst index 78e2e08af95e..cda7d0e18b9b 100644 --- a/Documentation/translations/zh_TW/filesystems/debugfs.rst +++ b/Documentation/translations/zh_TW/filesystems/debugfs.rst @@ -14,7 +14,7 @@ Debugfs 中文版維護者: 羅楚成 Chucheng Luo 中文版翻譯者: 羅楚成 Chucheng Luo 中文版校譯者: 羅楚成 Chucheng Luo - 繁體中文版校譯者: 胡皓文 Hu Haowen + 繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> diff --git a/Documentation/translations/zh_TW/filesystems/index.rst b/Documentation/translations/zh_TW/filesystems/index.rst index d7f9d61f654c..88f0e632bfe2 100644 --- a/Documentation/translations/zh_TW/filesystems/index.rst +++ b/Documentation/translations/zh_TW/filesystems/index.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/filesystems/index.rst ` :Translator: Wang Wenhu - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_filesystems_index: diff --git a/Documentation/translations/zh_TW/filesystems/sysfs.txt b/Documentation/translations/zh_TW/filesystems/sysfs.txt index ebe90651fc3b..978462d5fe14 100644 --- a/Documentation/translations/zh_TW/filesystems/sysfs.txt +++ b/Documentation/translations/zh_TW/filesystems/sysfs.txt @@ -22,7 +22,7 @@ Documentation/filesystems/sysfs.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者:胡皓文 Hu Haowen +繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/filesystems/virtiofs.rst b/Documentation/translations/zh_TW/filesystems/virtiofs.rst index 6150ad964e78..704a0ee44fd2 100644 --- a/Documentation/translations/zh_TW/filesystems/virtiofs.rst +++ b/Documentation/translations/zh_TW/filesystems/virtiofs.rst @@ -10,7 +10,7 @@ 中文版維護者: 王文虎 Wang Wenhu 中文版翻譯者: 王文虎 Wang Wenhu 中文版校譯者: 王文虎 Wang Wenhu - 繁體中文版校譯者:胡皓文 Hu Haowen + 繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> =========================================== virtiofs: virtio-fs 主機<->客機共享文件系統 diff --git a/Documentation/translations/zh_TW/gpio.txt b/Documentation/translations/zh_TW/gpio.txt index 555e4b11a5c7..b9b48012c62e 100644 --- a/Documentation/translations/zh_TW/gpio.txt +++ b/Documentation/translations/zh_TW/gpio.txt @@ -8,7 +8,7 @@ or if there is a problem with the translation. Maintainer: Grant Likely Linus Walleij -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/admin-guide/gpio 的繁體中文翻譯 @@ -18,9 +18,9 @@ Documentation/admin-guide/gpio 的繁體中文翻譯 英文版維護者: Grant Likely Linus Walleij -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst index 563ac9bfc66b..660a74d2023c 100644 --- a/Documentation/translations/zh_TW/index.rst +++ b/Documentation/translations/zh_TW/index.rst @@ -15,7 +15,7 @@ .. note:: 內核文檔繁體中文版的翻譯工作正在進行中。如果您願意並且有時間參與這項工 - 作,歡迎提交補丁給胡皓文 。 + 作,歡迎提交補丁給胡皓文 <2023002089@link.tyut.edu.cn>。 與Linux 內核社區一起工作 ------------------------ diff --git a/Documentation/translations/zh_TW/io_ordering.txt b/Documentation/translations/zh_TW/io_ordering.txt index 03f86840c139..00b374092d7e 100644 --- a/Documentation/translations/zh_TW/io_ordering.txt +++ b/Documentation/translations/zh_TW/io_ordering.txt @@ -6,7 +6,7 @@ communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/driver-api/io_ordering.rst 的繁體中文翻譯 @@ -14,9 +14,9 @@ Documentation/driver-api/io_ordering.rst 的繁體中文翻譯 交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 者翻譯存在問題,請聯繫繁體中文版維護者。 -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/process/1.Intro.rst b/Documentation/translations/zh_TW/process/1.Intro.rst index 6e754ac48964..345c4cbe9b55 100644 --- a/Documentation/translations/zh_TW/process/1.Intro.rst +++ b/Documentation/translations/zh_TW/process/1.Intro.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process_intro: diff --git a/Documentation/translations/zh_TW/process/2.Process.rst b/Documentation/translations/zh_TW/process/2.Process.rst index 49385d65c216..f45ddba6238f 100644 --- a/Documentation/translations/zh_TW/process/2.Process.rst +++ b/Documentation/translations/zh_TW/process/2.Process.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process: diff --git a/Documentation/translations/zh_TW/process/3.Early-stage.rst b/Documentation/translations/zh_TW/process/3.Early-stage.rst index a6959e6350f4..a58fc9e0ea99 100644 --- a/Documentation/translations/zh_TW/process/3.Early-stage.rst +++ b/Documentation/translations/zh_TW/process/3.Early-stage.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_early_stage: diff --git a/Documentation/translations/zh_TW/process/4.Coding.rst b/Documentation/translations/zh_TW/process/4.Coding.rst index 7a4e01eabd81..bdd2abe4daf4 100644 --- a/Documentation/translations/zh_TW/process/4.Coding.rst +++ b/Documentation/translations/zh_TW/process/4.Coding.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_coding: diff --git a/Documentation/translations/zh_TW/process/5.Posting.rst b/Documentation/translations/zh_TW/process/5.Posting.rst index d398dda427aa..7d66a1c638be 100644 --- a/Documentation/translations/zh_TW/process/5.Posting.rst +++ b/Documentation/translations/zh_TW/process/5.Posting.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_posting: diff --git a/Documentation/translations/zh_TW/process/6.Followthrough.rst b/Documentation/translations/zh_TW/process/6.Followthrough.rst index bcc885ae1b8e..f3b195966632 100644 --- a/Documentation/translations/zh_TW/process/6.Followthrough.rst +++ b/Documentation/translations/zh_TW/process/6.Followthrough.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_followthrough: diff --git a/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst index db74d8ca3f3b..b449d67e3ad9 100644 --- a/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst +++ b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_advancedtopics: diff --git a/Documentation/translations/zh_TW/process/8.Conclusion.rst b/Documentation/translations/zh_TW/process/8.Conclusion.rst index a0c00741f912..d1634421b62c 100644 --- a/Documentation/translations/zh_TW/process/8.Conclusion.rst +++ b/Documentation/translations/zh_TW/process/8.Conclusion.rst @@ -10,7 +10,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_conclusion: diff --git a/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst index 48df918000e9..fbe66b001322 100644 --- a/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst +++ b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/code-of-conduct-interpretation.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_code_of_conduct_interpretation: diff --git a/Documentation/translations/zh_TW/process/code-of-conduct.rst b/Documentation/translations/zh_TW/process/code-of-conduct.rst index a7a31de03526..d24f1695bd02 100644 --- a/Documentation/translations/zh_TW/process/code-of-conduct.rst +++ b/Documentation/translations/zh_TW/process/code-of-conduct.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/code-of-conduct.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_code_of_conduct: diff --git a/Documentation/translations/zh_TW/process/coding-style.rst b/Documentation/translations/zh_TW/process/coding-style.rst index 5749363de421..f11dbb65ca21 100644 --- a/Documentation/translations/zh_TW/process/coding-style.rst +++ b/Documentation/translations/zh_TW/process/coding-style.rst @@ -17,7 +17,7 @@ - 管旭東 Xudong Guan - Li Zefan - Wang Chen - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核代碼風格 ================== diff --git a/Documentation/translations/zh_TW/process/development-process.rst b/Documentation/translations/zh_TW/process/development-process.rst index 7d803d3db89e..6eb49d317046 100644 --- a/Documentation/translations/zh_TW/process/development-process.rst +++ b/Documentation/translations/zh_TW/process/development-process.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/development-process.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process_main: diff --git a/Documentation/translations/zh_TW/process/email-clients.rst b/Documentation/translations/zh_TW/process/email-clients.rst index 55e10d3fc28a..a5ac9400a9f5 100644 --- a/Documentation/translations/zh_TW/process/email-clients.rst +++ b/Documentation/translations/zh_TW/process/email-clients.rst @@ -15,7 +15,7 @@ - Yinglin Luan - Xiaochen Wang - yaxinsn - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> Linux郵件客戶端配置信息 ======================= diff --git a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst index b9f6ab7b6666..3cce7db2ab7e 100644 --- a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst +++ b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/embargoed-hardware-issues.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> 被限制的硬件問題 ================ diff --git a/Documentation/translations/zh_TW/process/howto.rst b/Documentation/translations/zh_TW/process/howto.rst index 306f5b77b4b8..80c416483e73 100644 --- a/Documentation/translations/zh_TW/process/howto.rst +++ b/Documentation/translations/zh_TW/process/howto.rst @@ -16,7 +16,7 @@ 鍾宇 TripleX Chung 陳琦 Maggie Chen 王聰 Wang Cong - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 如何參與Linux內核開發 ===================== diff --git a/Documentation/translations/zh_TW/process/index.rst b/Documentation/translations/zh_TW/process/index.rst index 6a0d98b2f9ee..65922d9faa20 100644 --- a/Documentation/translations/zh_TW/process/index.rst +++ b/Documentation/translations/zh_TW/process/index.rst @@ -9,7 +9,7 @@ :Original: :ref:`Documentation/process/index.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_process_index: diff --git a/Documentation/translations/zh_TW/process/kernel-driver-statement.rst b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst index e967089d2e1f..23d5cae9685b 100644 --- a/Documentation/translations/zh_TW/process/kernel-driver-statement.rst +++ b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst @@ -6,7 +6,7 @@ :Original: :ref:`Documentation/process/kernel-driver-statement.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> 內核驅動聲明 ------------ diff --git a/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst index 2861f4a15721..524eb4ac26cc 100644 --- a/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst +++ b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst @@ -6,7 +6,7 @@ :Original: :ref:`Documentation/process/kernel-enforcement-statement.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核執行聲明 ------------------ diff --git a/Documentation/translations/zh_TW/process/license-rules.rst b/Documentation/translations/zh_TW/process/license-rules.rst index 2c43bcf2ac79..594255856b68 100644 --- a/Documentation/translations/zh_TW/process/license-rules.rst +++ b/Documentation/translations/zh_TW/process/license-rules.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/license-rules.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_kernel_licensing: diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst index 5657d5cd18d4..199cd5d63973 100644 --- a/Documentation/translations/zh_TW/process/magic-number.rst +++ b/Documentation/translations/zh_TW/process/magic-number.rst @@ -12,7 +12,7 @@ 中文版維護者: 賈威威 Jia Wei Wei 中文版翻譯者: 賈威威 Jia Wei Wei 中文版校譯者: 賈威威 Jia Wei Wei - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 魔術數 ============ diff --git a/Documentation/translations/zh_TW/process/management-style.rst b/Documentation/translations/zh_TW/process/management-style.rst index f3913e3c159d..7cb912e89032 100644 --- a/Documentation/translations/zh_TW/process/management-style.rst +++ b/Documentation/translations/zh_TW/process/management-style.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/management-style.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_managementstyle: diff --git a/Documentation/translations/zh_TW/process/programming-language.rst b/Documentation/translations/zh_TW/process/programming-language.rst index e33389676eed..d2c64a5599e8 100644 --- a/Documentation/translations/zh_TW/process/programming-language.rst +++ b/Documentation/translations/zh_TW/process/programming-language.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/programming-language.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_programming_language: diff --git a/Documentation/translations/zh_TW/process/stable-api-nonsense.rst b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst index 6839d25bb22a..4b8597fed5ae 100644 --- a/Documentation/translations/zh_TW/process/stable-api-nonsense.rst +++ b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst @@ -12,7 +12,7 @@ 中文版維護者: 鍾宇 TripleX Chung 中文版翻譯者: 鍾宇 TripleX Chung 中文版校譯者: 李陽 Li Yang - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核驅動接口 ================== diff --git a/Documentation/translations/zh_TW/process/stable-kernel-rules.rst b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst index bd82a8ff3969..2f8f064f8629 100644 --- a/Documentation/translations/zh_TW/process/stable-kernel-rules.rst +++ b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst @@ -15,7 +15,7 @@ 中文版校譯者: - 李陽 Li Yang - Kangkai Yin - - 胡皓文 Hu Haowen + - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 所有你想知道的事情 - 關於linux穩定版發佈 ======================================== diff --git a/Documentation/translations/zh_TW/process/submit-checklist.rst b/Documentation/translations/zh_TW/process/submit-checklist.rst index 942962d1e2f4..e57ef0f99e0c 100644 --- a/Documentation/translations/zh_TW/process/submit-checklist.rst +++ b/Documentation/translations/zh_TW/process/submit-checklist.rst @@ -6,7 +6,7 @@ :Translator: - Alex Shi - Wu XiangCheng - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_submitchecklist: diff --git a/Documentation/translations/zh_TW/process/submitting-patches.rst b/Documentation/translations/zh_TW/process/submitting-patches.rst index 8272b3218b54..99fa0f2fe6f4 100644 --- a/Documentation/translations/zh_TW/process/submitting-patches.rst +++ b/Documentation/translations/zh_TW/process/submitting-patches.rst @@ -14,7 +14,7 @@ :校譯: - 李陽 Li Yang - 王聰 Wang Cong - - 胡皓文 Hu Haowen + - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 提交補丁:如何讓你的改動進入內核 diff --git a/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst index a609620affb0..e2723f3cbbb0 100644 --- a/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst +++ b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst @@ -17,7 +17,7 @@ 中文版校譯者: 張漢輝 Eugene Teo 楊瑞 Dave Young 時奎亮 Alex Shi - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 爲什麼不應該使用“volatile”類型 ============================== diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..48fc02d3a1d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22110,7 +22110,7 @@ F: kernel/trace/trace_osnoise.c F: kernel/trace/trace_sched_wakeup.c TRADITIONAL CHINESE DOCUMENTATION -M: Hu Haowen +M: Hu Haowen <2023002089@link.tyut.edu.cn> S: Maintained W: https://github.com/srcres258/linux-doc T: git git://github.com/srcres258/linux-doc.git doc-zh-tw From 7c49ca6b021380f7be67ec9896392ff316a8ac71 Mon Sep 17 00:00:00 2001 From: Yuanhsi Chung Date: Sat, 4 Nov 2023 18:33:30 +0800 Subject: [PATCH 0840/7721] Documentation: Fix filename typo in ftrace doc The filename for setting the cpumask should be `tracing_cpumask`, instead of `tracing_cpu_mask`. Signed-off-by: Yuanhsi Chung Signed-off-by: Jonathan Corbet Message-ID: <20231104103329.215139-1-freshliver.cys@gmail.com> --- Documentation/trace/ftrace.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 23572f6697c0..9ef362dae9df 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -2574,7 +2574,7 @@ want, depending on your needs. - The cpu number on which the function executed is default enabled. It is sometimes better to only trace one cpu (see - tracing_cpu_mask file) or you might sometimes see unordered + tracing_cpumask file) or you might sometimes see unordered function calls while cpu tracing switch. - hide: echo nofuncgraph-cpu > trace_options From 36062b91838753f444235842197feb7d78c87096 Mon Sep 17 00:00:00 2001 From: zhangxirui Date: Sat, 21 Oct 2023 06:19:07 -0600 Subject: [PATCH 0841/7721] f2fs: use inode_lock_shared instead of inode_lock in f2fs_seek_block() inode_lock_shared() -> down_read(&inode->i_rwsem) inode_lock() -> down_write(&inode->i_rwsem) Inode is not updated in f2fs_seek_block(), so there is no need to hold write lock, use read lock for more efficiency. Signed-off-by: zhangxirui Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index e50363583f01..325dab01a29d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -418,7 +418,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) loff_t isize; int err = 0; - inode_lock(inode); + inode_lock_shared(inode); isize = i_size_read(inode); if (offset >= isize) @@ -483,10 +483,10 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) found: if (whence == SEEK_HOLE && data_ofs > isize) data_ofs = isize; - inode_unlock(inode); + inode_unlock_shared(inode); return vfs_setpos(file, data_ofs, maxbytes); fail: - inode_unlock(inode); + inode_unlock_shared(inode); return -ENXIO; } From 5e4166461cf66a26f925011d90017da74e410747 Mon Sep 17 00:00:00 2001 From: Yang Hubin Date: Sat, 4 Nov 2023 00:45:01 -0700 Subject: [PATCH 0842/7721] f2fs: the name of a struct is wrong in a comment. The macro SUMMARY_SIZE represents the size of the struct f2fs_summary, instead of the size of the struct summary. Signed-off-by: Yang Hubin Signed-off-by: Qian Haolai Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- include/linux/f2fs_fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 039fe0ce8d83..053137a0fe45 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -441,7 +441,7 @@ struct f2fs_sit_block { * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) */ #define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8) -#define SUMMARY_SIZE (7) /* sizeof(struct summary) */ +#define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */ #define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ #define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) From e26b6d39270f5eab0087453d9b544189a38c8564 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 6 Nov 2023 20:44:34 -0800 Subject: [PATCH 0843/7721] f2fs: explicitly null-terminate the xattr list When setting an xattr, explicitly null-terminate the xattr list. This eliminates the fragile assumption that the unused xattr space is always zeroed. Signed-off-by: Eric Biggers Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/xattr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 47e88b4d4e7d..a8fc2cac6879 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -754,6 +754,12 @@ static int __f2fs_setxattr(struct inode *inode, int index, memcpy(pval, value, size); last->e_value_size = cpu_to_le16(size); new_hsize += newsize; + /* + * Explicitly add the null terminator. The unused xattr space + * is supposed to always be zeroed, which would make this + * unnecessary, but don't depend on that. + */ + *(u32 *)((u8 *)last + newsize) = 0; } error = write_all_xattrs(inode, new_hsize, base_addr, ipage); From ff6584ac2c4b4ee8e1fca20bffaaa387d8fe2974 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 16 Nov 2023 14:25:54 +0800 Subject: [PATCH 0844/7721] f2fs: clean up w/ dotdot_name Just cleanup, no logic changes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index d0053b0284d8..a9360ee02da1 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -459,7 +459,6 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct qstr dot = QSTR_INIT(".", 1); - struct qstr dotdot = QSTR_INIT("..", 2); struct f2fs_dir_entry *de; struct page *page; int err = 0; @@ -497,13 +496,13 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) goto out; } - de = f2fs_find_entry(dir, &dotdot, &page); + de = f2fs_find_entry(dir, &dotdot_name, &page); if (de) f2fs_put_page(page, 0); else if (IS_ERR(page)) err = PTR_ERR(page); else - err = f2fs_do_add_link(dir, &dotdot, NULL, pino, S_IFDIR); + err = f2fs_do_add_link(dir, &dotdot_name, NULL, pino, S_IFDIR); out: if (!err) clear_inode_flag(dir, FI_INLINE_DOTS); From 9458915036ddef536d4abdd01b9b3c067f7d7a9f Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 16 Nov 2023 14:25:55 +0800 Subject: [PATCH 0845/7721] f2fs: use shared inode lock during f2fs_fiemap() f2fs_fiemap() will only traverse metadata of inode, let's use shared inode lock for it to avoid unnecessary race on inode lock. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 4e42b5f24deb..42f0f6184f73 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1992,7 +1992,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (ret) return ret; - inode_lock(inode); + inode_lock_shared(inode); maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS; if (start > maxbytes) { @@ -2112,7 +2112,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (ret == 1) ret = 0; - inode_unlock(inode); + inode_unlock_shared(inode); return ret; } From 956fa1ddc132e028f3b7d4cf17e6bfc8cb36c7fd Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 16 Nov 2023 14:25:56 +0800 Subject: [PATCH 0846/7721] f2fs: fix to check return value of f2fs_reserve_new_block() Let's check return value of f2fs_reserve_new_block() in do_recover_data() rather than letting it fails silently. Also refactoring check condition on return value of f2fs_reserve_new_block() as below: - trigger f2fs_bug_on() only for ENOSPC case; - use do-while statement to avoid redundant codes; Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index b56d0f1078a7..16415c770b45 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -712,7 +712,16 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, */ if (dest == NEW_ADDR) { f2fs_truncate_data_blocks_range(&dn, 1); - f2fs_reserve_new_block(&dn); + do { + err = f2fs_reserve_new_block(&dn); + if (err == -ENOSPC) { + f2fs_bug_on(sbi, 1); + break; + } + } while (err && + IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION)); + if (err) + goto err; continue; } @@ -720,12 +729,14 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) { if (src == NULL_ADDR) { - err = f2fs_reserve_new_block(&dn); - while (err && - IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION)) + do { err = f2fs_reserve_new_block(&dn); - /* We should not get -ENOSPC */ - f2fs_bug_on(sbi, err); + if (err == -ENOSPC) { + f2fs_bug_on(sbi, 1); + break; + } + } while (err && + IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION)); if (err) goto err; } From 47fbee5f27ed9ef43340db03ba2b58a673a6e72b Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 3 Nov 2023 09:33:02 -0600 Subject: [PATCH 0847/7721] accel/qaic: Update MAX_ORDER use to be inclusive MAX_ORDER was redefined so that valid allocations to the page allocator are in the range of 0..MAX_ORDER, inclusive in the commit 23baf831a32c ("mm, treewide: redefine MAX_ORDER sanely"). We are treating MAX_ORDER as an exclusive value, and thus could be requesting larger allocations. Update our use to match the redefinition of MAX_ORDER. Signed-off-by: Jeffrey Hugo Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Carl Vanderlip Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231103153302.20642-1-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 8da81768f2ab..8998c28e566e 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -452,7 +452,7 @@ static int create_sgt(struct qaic_device *qdev, struct sg_table **sgt_out, u64 s * later */ buf_extra = (PAGE_SIZE - size % PAGE_SIZE) % PAGE_SIZE; - max_order = min(MAX_ORDER - 1, get_order(size)); + max_order = min(MAX_ORDER, get_order(size)); } else { /* allocate a single page for book keeping */ nr_pages = 1; From ff8867af01daa7ea770bebf5f91199b7434b74e5 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 09:14:04 -0800 Subject: [PATCH 0848/7721] bpf: rename BPF_F_TEST_SANITY_STRICT to BPF_F_TEST_REG_INVARIANTS Rename verifier internal flag BPF_F_TEST_SANITY_STRICT to more neutral BPF_F_TEST_REG_INVARIANTS. This is a follow up to [0]. A few selftests and veristat need to be adjusted in the same patch as well. [0] https://patchwork.kernel.org/project/netdevbpf/patch/20231112010609.848406-5-andrii@kernel.org/ Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231117171404.225508-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 2 +- include/uapi/linux/bpf.h | 2 +- kernel/bpf/syscall.c | 2 +- kernel/bpf/verifier.c | 6 +++--- tools/include/uapi/linux/bpf.h | 2 +- .../selftests/bpf/prog_tests/bpf_verif_scale.c | 2 +- tools/testing/selftests/bpf/prog_tests/reg_bounds.c | 2 +- tools/testing/selftests/bpf/progs/verifier_bounds.c | 4 ++-- tools/testing/selftests/bpf/test_loader.c | 6 +++--- tools/testing/selftests/bpf/test_sock_addr.c | 3 +-- tools/testing/selftests/bpf/test_verifier.c | 2 +- tools/testing/selftests/bpf/testing_helpers.c | 4 ++-- tools/testing/selftests/bpf/veristat.c | 12 ++++++------ 13 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 402b6bc44a1b..52a4012b8255 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -602,7 +602,7 @@ struct bpf_verifier_env { int stack_size; /* number of states to be processed */ bool strict_alignment; /* perform strict pointer alignment checks */ bool test_state_freq; /* test verifier with different pruning frequency */ - bool test_sanity_strict; /* fail verification on sanity violations */ + bool test_reg_invariants; /* fail verification on register invariants violations */ struct bpf_verifier_state *cur_state; /* current verifier state */ struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ struct bpf_verifier_state_list *free_list; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 8a5855fcee69..7a5498242eaa 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1201,7 +1201,7 @@ enum bpf_perf_event_type { #define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6) /* The verifier internal test flag. Behavior is undefined */ -#define BPF_F_TEST_SANITY_STRICT (1U << 7) +#define BPF_F_TEST_REG_INVARIANTS (1U << 7) /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f266e03ba342..5e43ddd1b83f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2574,7 +2574,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_TEST_RND_HI32 | BPF_F_XDP_HAS_FRAGS | BPF_F_XDP_DEV_BOUND_ONLY | - BPF_F_TEST_SANITY_STRICT)) + BPF_F_TEST_REG_INVARIANTS)) return -EINVAL; if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 59505881e7a7..7c3461b89513 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2608,14 +2608,14 @@ static int reg_bounds_sanity_check(struct bpf_verifier_env *env, return 0; out: - verbose(env, "REG SANITY VIOLATION (%s): %s u64=[%#llx, %#llx] " + verbose(env, "REG INVARIANTS VIOLATION (%s): %s u64=[%#llx, %#llx] " "s64=[%#llx, %#llx] u32=[%#x, %#x] s32=[%#x, %#x] var_off=(%#llx, %#llx)\n", ctx, msg, reg->umin_value, reg->umax_value, reg->smin_value, reg->smax_value, reg->u32_min_value, reg->u32_max_value, reg->s32_min_value, reg->s32_max_value, reg->var_off.value, reg->var_off.mask); - if (env->test_sanity_strict) + if (env->test_reg_invariants) return -EFAULT; __mark_reg_unbounded(reg); return 0; @@ -20791,7 +20791,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (is_priv) env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ; - env->test_sanity_strict = attr->prog_flags & BPF_F_TEST_SANITY_STRICT; + env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS; env->explored_states = kvcalloc(state_htab_size(env), sizeof(struct bpf_verifier_state_list *), diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 8a5855fcee69..7a5498242eaa 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1201,7 +1201,7 @@ enum bpf_perf_event_type { #define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6) /* The verifier internal test flag. Behavior is undefined */ -#define BPF_F_TEST_SANITY_STRICT (1U << 7) +#define BPF_F_TEST_REG_INVARIANTS (1U << 7) /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index 3f2d70831873..e770912fc1d2 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c @@ -35,7 +35,7 @@ static int check_load(const char *file, enum bpf_prog_type type) } bpf_program__set_type(prog, type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT); + bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags); err = bpf_object__load(obj); diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index fe0cb906644b..7a8b0bf0a7f8 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -838,7 +838,7 @@ static int load_range_cmp_prog(struct range x, struct range y, enum op op, .log_level = 2, .log_buf = log_buf, .log_size = log_sz, - .prog_flags = BPF_F_TEST_SANITY_STRICT, + .prog_flags = BPF_F_TEST_REG_INVARIANTS, ); /* ; skip exit block below diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c index 0c1460936373..ec430b71730b 100644 --- a/tools/testing/selftests/bpf/progs/verifier_bounds.c +++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c @@ -965,7 +965,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP_JSLT for crossing 64-bit signed boundary") __success __retval(0) -__flag(!BPF_F_TEST_SANITY_STRICT) /* known sanity violation */ +__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ __naked void crossing_64_bit_signed_boundary_2(void) { asm volatile (" \ @@ -1047,7 +1047,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary") __success __retval(0) -__flag(!BPF_F_TEST_SANITY_STRICT) /* known sanity violation */ +__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ __naked void crossing_32_bit_signed_boundary_2(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c index 57e27b1a73a6..a350ecdfba4a 100644 --- a/tools/testing/selftests/bpf/test_loader.c +++ b/tools/testing/selftests/bpf/test_loader.c @@ -179,7 +179,7 @@ static int parse_test_spec(struct test_loader *tester, memset(spec, 0, sizeof(*spec)); spec->prog_name = bpf_program__name(prog); - spec->prog_flags = BPF_F_TEST_SANITY_STRICT; /* by default be strict */ + spec->prog_flags = BPF_F_TEST_REG_INVARIANTS; /* by default be strict */ btf = bpf_object__btf(obj); if (!btf) { @@ -280,8 +280,8 @@ static int parse_test_spec(struct test_loader *tester, update_flags(&spec->prog_flags, BPF_F_SLEEPABLE, clear); } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { update_flags(&spec->prog_flags, BPF_F_XDP_HAS_FRAGS, clear); - } else if (strcmp(val, "BPF_F_TEST_SANITY_STRICT") == 0) { - update_flags(&spec->prog_flags, BPF_F_TEST_SANITY_STRICT, clear); + } else if (strcmp(val, "BPF_F_TEST_REG_INVARIANTS") == 0) { + update_flags(&spec->prog_flags, BPF_F_TEST_REG_INVARIANTS, clear); } else /* assume numeric value */ { err = parse_int(val, &flags, "test prog flags"); if (err) diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index 878c077e0fa7..b0068a9d2cfe 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -679,8 +679,7 @@ static int load_path(const struct sock_addr_test *test, const char *path) bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); bpf_program__set_expected_attach_type(prog, test->expected_attach_type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); - bpf_program__set_flags(prog, BPF_F_TEST_SANITY_STRICT); + bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); err = bpf_object__load(obj); if (err) { diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 4992022f3137..f36e41435be7 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1588,7 +1588,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (fixup_skips != skips) return; - pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT; + pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) pflags |= BPF_F_STRICT_ALIGNMENT; if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 9786a94a666c..d2458c1b1671 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -276,7 +276,7 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type, if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) bpf_program__set_type(prog, type); - flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT; + flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; bpf_program__set_flags(prog, flags); err = bpf_object__load(obj); @@ -299,7 +299,7 @@ int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, { LIBBPF_OPTS(bpf_prog_load_opts, opts, .kern_version = kern_version, - .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_SANITY_STRICT, + .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS, .log_level = extra_prog_load_log_flags, .log_buf = log_buf, .log_size = log_buf_sz, diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 609fd9753af0..1d418d66e375 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -145,7 +145,7 @@ static struct env { bool debug; bool quiet; bool force_checkpoints; - bool strict_range_sanity; + bool force_reg_invariants; enum resfmt out_fmt; bool show_version; bool comparison_mode; @@ -225,8 +225,8 @@ static const struct argp_option opts[] = { { "filter", 'f', "FILTER", 0, "Filter expressions (or @filename for file with expressions)." }, { "test-states", 't', NULL, 0, "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, - { "test-sanity", 'r', NULL, 0, - "Force strict BPF verifier register sanity behavior (BPF_F_TEST_SANITY_STRICT program flag)" }, + { "test-reg-invariants", 'r', NULL, 0, + "Force BPF verifier failure on register invariant violation (BPF_F_TEST_REG_INVARIANTS program flag)" }, {}, }; @@ -299,7 +299,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) env.force_checkpoints = true; break; case 'r': - env.strict_range_sanity = true; + env.force_reg_invariants = true; break; case 'n': errno = 0; @@ -1028,8 +1028,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf if (env.force_checkpoints) bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_STATE_FREQ); - if (env.strict_range_sanity) - bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_SANITY_STRICT); + if (env.force_reg_invariants) + bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_REG_INVARIANTS); err = bpf_object__load(obj); env.progs_processed++; From eed94315555a441028238a4d05c6f86997d9e68e Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:20 +0200 Subject: [PATCH 0849/7721] docs: style toctree captions as headings The rtd theme already styles toctree captions as headings, but the alabaster theme doesn't. Add this in. Cc: Mauro Carvalho Chehab Cc: Jonathan Corbet Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-2-vegard.nossum@oracle.com --- Documentation/sphinx-static/custom.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css index 084a884f6fb7..c7439349dda6 100644 --- a/Documentation/sphinx-static/custom.css +++ b/Documentation/sphinx-static/custom.css @@ -8,6 +8,9 @@ div.body h1 { font-size: 180%; } div.body h2 { font-size: 150%; } div.body h3 { font-size: 130%; } +/* toctree captions are styled like h2 */ +div.toctree-wrapper p.caption[role=heading] { font-size: 150%; } + /* Tighten up the layout slightly */ div.body { padding: 0 15px 0 10px; } div.sphinxsidebarwrapper { padding: 1em 0.4em; } From 074f81506d9869d2750e3be2cecec163e8c0b1f1 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:21 +0200 Subject: [PATCH 0850/7721] doc: userspace-api: properly format ToC headings "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Rui Li Cc: Yanteng Si Cc: Wu XiangCheng Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-3-vegard.nossum@oracle.com --- Documentation/translations/zh_CN/userspace-api/index.rst | 5 +---- Documentation/userspace-api/index.rst | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Documentation/translations/zh_CN/userspace-api/index.rst b/Documentation/translations/zh_CN/userspace-api/index.rst index 5dc0f2e69c17..5b14721c8264 100644 --- a/Documentation/translations/zh_CN/userspace-api/index.rst +++ b/Documentation/translations/zh_CN/userspace-api/index.rst @@ -17,11 +17,8 @@ Linux 内核用户空间API指南 在代码树中仍然可以找到有关用户空间的部分信息。这个手册意在成为这些信息 聚集的地方。 -.. class:: toc-title - - 目录 - .. toctree:: + :caption: 目录 :maxdepth: 2 no_new_privs diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst index 72a65db0c498..5b32a461c2dd 100644 --- a/Documentation/userspace-api/index.rst +++ b/Documentation/userspace-api/index.rst @@ -9,11 +9,8 @@ While much of the kernel's user-space API is documented elsewhere also be found in the kernel tree itself. This manual is intended to be the place where this information is gathered. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 no_new_privs From a37a44572fbb5c3ef65502b76705113dde6eafbf Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:22 +0200 Subject: [PATCH 0851/7721] media: admin-guide: properly format ToC heading "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Mauro Carvalho Chehab Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-4-vegard.nossum@oracle.com --- Documentation/admin-guide/media/index.rst | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Documentation/admin-guide/media/index.rst b/Documentation/admin-guide/media/index.rst index 43f4a292b245..be7e0e4482ca 100644 --- a/Documentation/admin-guide/media/index.rst +++ b/Documentation/admin-guide/media/index.rst @@ -20,16 +20,8 @@ Documentation/driver-api/media/index.rst - for driver development information and Kernel APIs used by media devices; -The media subsystem -=================== - -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: From 1f821382818a0dab85dbfff698b0fa0fff18cb36 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:23 +0200 Subject: [PATCH 0852/7721] crypto: doc: properly format ToC headings "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Mauro Carvalho Chehab Cc: Stephan Mueller Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-5-vegard.nossum@oracle.com --- Documentation/crypto/api.rst | 5 +---- Documentation/crypto/index.rst | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Documentation/crypto/api.rst b/Documentation/crypto/api.rst index b91b31736df8..ff31c30561d4 100644 --- a/Documentation/crypto/api.rst +++ b/Documentation/crypto/api.rst @@ -1,11 +1,8 @@ Programming Interface ===================== -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 api-skcipher diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst index da5d5ad2bdf3..10647c5ae2ea 100644 --- a/Documentation/crypto/index.rst +++ b/Documentation/crypto/index.rst @@ -9,11 +9,8 @@ This documentation outlines the Linux kernel crypto API with its concepts, details about developing cipher implementations, employment of the API for cryptographic use cases, as well as programming examples. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 intro From 93f85555a89904afa215f50971eedfead0f0181b Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:24 +0200 Subject: [PATCH 0853/7721] Documentation: dev-tools: properly format ToC headingss "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Mauro Carvalho Chehab Cc: gaochao Cc: Yanteng Si Cc: Wu XiangCheng Cc: Fangrui Song Cc: Wan Jiabing Cc: Alex Shi Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-6-vegard.nossum@oracle.com --- Documentation/dev-tools/index.rst | 5 +---- Documentation/translations/zh_CN/dev-tools/index.rst | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 6b0663075dc0..3d2286c683bc 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -10,11 +10,8 @@ whole; patches welcome! A brief overview of testing-specific tools can be found in Documentation/dev-tools/testing-overview.rst -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 testing-overview diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index 02577c379007..c2db3e566b1b 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -14,11 +14,8 @@ 有关测试专用工具的简要概述,参见 Documentation/translations/zh_CN/dev-tools/testing-overview.rst -.. class:: toc-title - - 目录 - .. toctree:: + :caption: 目录 :maxdepth: 2 testing-overview From f85f5ae45ad945270a8884261de8249431e8b5a6 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:25 +0200 Subject: [PATCH 0854/7721] docs: driver-api: properly format ToC headings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Mauro Carvalho Chehab Cc: Richard Cochran Cc: SeongJae Park Cc: Hans de Goede Cc: Armin Wolf Cc: Iwona Winiarska Cc: Ricardo Cañuelo Cc: Tomas Winkler Cc: linux-media@vger.kernel.org Cc: Yanteng Si Cc: Alex Shi Cc: Wu XiangCheng Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-7-vegard.nossum@oracle.com --- Documentation/driver-api/index.rst | 5 +---- Documentation/driver-api/media/index.rst | 7 +------ Documentation/driver-api/mei/index.rst | 7 +------ Documentation/driver-api/pci/index.rst | 5 +---- Documentation/translations/zh_CN/driver-api/gpio/index.rst | 3 +-- Documentation/translations/zh_CN/driver-api/index.rst | 5 +---- 6 files changed, 6 insertions(+), 26 deletions(-) diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 1e16a40da3ba..4540f79a34a9 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -9,11 +9,8 @@ of device drivers. This document is an only somewhat organized collection of some of those interfaces — it will hopefully get better over time! The available subsections can be seen below. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 driver-model/index diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst index 08e206567408..d5593182a3f9 100644 --- a/Documentation/driver-api/media/index.rst +++ b/Documentation/driver-api/media/index.rst @@ -20,13 +20,8 @@ Documentation/userspace-api/media/index.rst - for the userspace APIs used on media devices. -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/driver-api/mei/index.rst b/Documentation/driver-api/mei/index.rst index 3a22b522ee78..eae6f18f18cf 100644 --- a/Documentation/driver-api/mei/index.rst +++ b/Documentation/driver-api/mei/index.rst @@ -9,13 +9,8 @@ Intel(R) Management Engine Interface (Intel(R) MEI) **Copyright** |copy| 2019 Intel Corporation -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 3 mei diff --git a/Documentation/driver-api/pci/index.rst b/Documentation/driver-api/pci/index.rst index c6cf1fef61ce..a38e475cdbe3 100644 --- a/Documentation/driver-api/pci/index.rst +++ b/Documentation/driver-api/pci/index.rst @@ -4,11 +4,8 @@ The Linux PCI driver implementer's API guide ============================================ -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 pci diff --git a/Documentation/translations/zh_CN/driver-api/gpio/index.rst b/Documentation/translations/zh_CN/driver-api/gpio/index.rst index 9ab64e94aced..9a6a14162a6c 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/index.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/index.rst @@ -14,9 +14,8 @@ 通用型输入/输出(GPIO) ======================= -目录: - .. toctree:: + :caption: 目录 :maxdepth: 2 legacy diff --git a/Documentation/translations/zh_CN/driver-api/index.rst b/Documentation/translations/zh_CN/driver-api/index.rst index ba354e1f4e6d..92ff1b7fc3d3 100644 --- a/Documentation/translations/zh_CN/driver-api/index.rst +++ b/Documentation/translations/zh_CN/driver-api/index.rst @@ -17,11 +17,8 @@ Linux驱动实现者的API指南 内核提供了各种各样的接口来支持设备驱动的开发。这份文档只是对其中一些接口进行了 一定程度的整理——希望随着时间的推移,它能变得更好!可用的小节可以在下面看到。 -.. class:: toc-title - - 目录列表: - .. toctree:: + :caption: 目录列表 :maxdepth: 2 gpio/index From 0dfbd35ed43de622032c80c74e04fca2d1f7ec69 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:26 +0200 Subject: [PATCH 0855/7721] input: docs: properly format ToC headings "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Dmitry Torokhov Cc: linux-input@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-8-vegard.nossum@oracle.com --- Documentation/input/input_kapi.rst | 5 +---- Documentation/input/input_uapi.rst | 5 +---- Documentation/input/joydev/index.rst | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Documentation/input/input_kapi.rst b/Documentation/input/input_kapi.rst index 41f1b7e6b78e..9937522daa9b 100644 --- a/Documentation/input/input_kapi.rst +++ b/Documentation/input/input_kapi.rst @@ -4,11 +4,8 @@ Linux Input Subsystem kernel API ################################ -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: diff --git a/Documentation/input/input_uapi.rst b/Documentation/input/input_uapi.rst index 4a0391609327..8275b4223a84 100644 --- a/Documentation/input/input_uapi.rst +++ b/Documentation/input/input_uapi.rst @@ -4,11 +4,8 @@ Linux Input Subsystem userspace API ################################### -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: diff --git a/Documentation/input/joydev/index.rst b/Documentation/input/joydev/index.rst index ebcff43056e2..d03d6f6cbfab 100644 --- a/Documentation/input/joydev/index.rst +++ b/Documentation/input/joydev/index.rst @@ -6,11 +6,8 @@ Linux Joystick support :Copyright: |copy| 1996-2000 Vojtech Pavlik - Sponsored by SuSE -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 3 joystick From 0419ee1b62f37bf9d654bfacd9a4991f588d03ad Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:27 +0200 Subject: [PATCH 0856/7721] doc: misc-device: properly format ToC heading "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Greg Kroah-Hartman Cc: Julien Panis Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-9-vegard.nossum@oracle.com --- Documentation/misc-devices/index.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index ecc40fbbcfb8..1fc89d664830 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -7,11 +7,8 @@ Assorted Miscellaneous Devices Documentation This documentation contains information for assorted devices that do not fit into other categories. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 ad525x_dpot From 58af66464440c755001a74826f185e0b4bd159db Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:28 +0200 Subject: [PATCH 0857/7721] media: doc: properly format ToC headings "class:: toc-title" was a workaround for older Sphinx versions that are no longer supported. The canonical way to add a heading to the ToC is to use :caption:. Do that. Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-10-vegard.nossum@oracle.com --- Documentation/userspace-api/media/cec/cec-api.rst | 7 +------ Documentation/userspace-api/media/drivers/index.rst | 7 +------ Documentation/userspace-api/media/dvb/dvbapi.rst | 7 +------ Documentation/userspace-api/media/index.rst | 7 +------ .../userspace-api/media/mediactl/media-controller.rst | 7 +------ .../userspace-api/media/rc/remote_controllers.rst | 7 +------ Documentation/userspace-api/media/v4l/v4l2.rst | 7 +------ 7 files changed, 7 insertions(+), 42 deletions(-) diff --git a/Documentation/userspace-api/media/cec/cec-api.rst b/Documentation/userspace-api/media/cec/cec-api.rst index 4d229ed8a1d9..578303d484f3 100644 --- a/Documentation/userspace-api/media/cec/cec-api.rst +++ b/Documentation/userspace-api/media/cec/cec-api.rst @@ -10,13 +10,8 @@ Part V - Consumer Electronics Control API This part describes the CEC: Consumer Electronics Control -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 6708d649afd7..d4338dc506dd 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -21,13 +21,8 @@ more details. For more details see the file COPYING in the source distribution of Linux. -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/dvb/dvbapi.rst b/Documentation/userspace-api/media/dvb/dvbapi.rst index 1dda69343f34..4ac0c1bc54ca 100644 --- a/Documentation/userspace-api/media/dvb/dvbapi.rst +++ b/Documentation/userspace-api/media/dvb/dvbapi.rst @@ -27,13 +27,8 @@ Part II - Digital TV API **Version 5.10** -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/index.rst b/Documentation/userspace-api/media/index.rst index d839904be085..337ef6c7c47f 100644 --- a/Documentation/userspace-api/media/index.rst +++ b/Documentation/userspace-api/media/index.rst @@ -21,13 +21,8 @@ Documentation/driver-api/media/index.rst media devices; -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 1 intro diff --git a/Documentation/userspace-api/media/mediactl/media-controller.rst b/Documentation/userspace-api/media/mediactl/media-controller.rst index 508dd693bf6c..73a87f82f92d 100644 --- a/Documentation/userspace-api/media/mediactl/media-controller.rst +++ b/Documentation/userspace-api/media/mediactl/media-controller.rst @@ -7,13 +7,8 @@ Part IV - Media Controller API ############################## -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/rc/remote_controllers.rst b/Documentation/userspace-api/media/rc/remote_controllers.rst index f89291838637..483f9ae92a90 100644 --- a/Documentation/userspace-api/media/rc/remote_controllers.rst +++ b/Documentation/userspace-api/media/rc/remote_controllers.rst @@ -7,13 +7,8 @@ Part III - Remote Controller API ################################ -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/v4l/v4l2.rst b/Documentation/userspace-api/media/v4l/v4l2.rst index ad7a2bf0cf26..cf8ae56a008c 100644 --- a/Documentation/userspace-api/media/v4l/v4l2.rst +++ b/Documentation/userspace-api/media/v4l/v4l2.rst @@ -11,13 +11,8 @@ This part describes the Video for Linux API version 2 (V4L2 API) specification. **Revision 4.5** -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :numbered: :maxdepth: 5 From 2b7703e15a55890664e57a7a1395589ef70182c1 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:29 +0200 Subject: [PATCH 0858/7721] docs: use toctree :caption: and move introduction The canonical way to add a heading to the ToC is to use :caption:. Do that. Let's also move the introduction to the top of the document to be consistent with most other documents. Cc: Jonathan Corbet Cc: Mauro Carvalho Chehab Cc: Federico Vaga Cc: Alex Shi Cc: Yanteng Si Cc: Hu Haowen Cc: workflows@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-11-vegard.nossum@oracle.com --- Documentation/process/development-process.rst | 19 +++++++++---------- .../it_IT/process/development-process.rst | 19 +++++++++---------- .../zh_CN/process/development-process.rst | 5 ++--- .../zh_TW/process/development-process.rst | 5 ++--- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Documentation/process/development-process.rst b/Documentation/process/development-process.rst index 61c627e41ba8..e34d7da58b7f 100644 --- a/Documentation/process/development-process.rst +++ b/Documentation/process/development-process.rst @@ -3,9 +3,17 @@ A guide to the Kernel Development Process ========================================= -Contents: +The purpose of this document is to help developers (and their managers) +work with the development community with a minimum of frustration. It is +an attempt to document how this community works in a way which is +accessible to those who are not intimately familiar with Linux kernel +development (or, indeed, free software development in general). While +there is some technical material here, this is very much a process-oriented +discussion which does not require a deep knowledge of kernel programming to +understand. .. toctree:: + :caption: Contents :numbered: :maxdepth: 2 @@ -17,12 +25,3 @@ Contents: 6.Followthrough 7.AdvancedTopics 8.Conclusion - -The purpose of this document is to help developers (and their managers) -work with the development community with a minimum of frustration. It is -an attempt to document how this community works in a way which is -accessible to those who are not intimately familiar with Linux kernel -development (or, indeed, free software development in general). While -there is some technical material here, this is very much a process-oriented -discussion which does not require a deep knowledge of kernel programming to -understand. diff --git a/Documentation/translations/it_IT/process/development-process.rst b/Documentation/translations/it_IT/process/development-process.rst index f1a6eca30824..20e77c9816a1 100644 --- a/Documentation/translations/it_IT/process/development-process.rst +++ b/Documentation/translations/it_IT/process/development-process.rst @@ -8,9 +8,17 @@ Una guida al processo di sviluppo del Kernel ============================================ -Contenuti: +Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro +supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È +un tentativo di documentare il funzionamento di questa communità in modo che +sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del +Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè +qui sia presente del materiale tecnico, questa è una discussione rivolta in +particolare al procedimento, e quindi per essere compreso non richiede una +conoscenza approfondità sullo sviluppo del kernel. .. toctree:: + :caption: Contenuti :numbered: :maxdepth: 2 @@ -22,12 +30,3 @@ Contenuti: 6.Followthrough 7.AdvancedTopics 8.Conclusion - -Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro -supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È -un tentativo di documentare il funzionamento di questa communità in modo che -sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del -Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè -qui sia presente del materiale tecnico, questa è una discussione rivolta in -particolare al procedimento, e quindi per essere compreso non richiede una -conoscenza approfondità sullo sviluppo del kernel. diff --git a/Documentation/translations/zh_CN/process/development-process.rst b/Documentation/translations/zh_CN/process/development-process.rst index 30cffe66c075..c10d8e2e21eb 100644 --- a/Documentation/translations/zh_CN/process/development-process.rst +++ b/Documentation/translations/zh_CN/process/development-process.rst @@ -8,9 +8,10 @@ 内核开发过程指南 ================ -内容: +本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。 .. toctree:: + :caption: 内容 :numbered: :maxdepth: 2 @@ -22,5 +23,3 @@ 6.Followthrough 7.AdvancedTopics 8.Conclusion - -本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。 diff --git a/Documentation/translations/zh_TW/process/development-process.rst b/Documentation/translations/zh_TW/process/development-process.rst index f4cf5c2bbc82..c4db0e3e72ce 100644 --- a/Documentation/translations/zh_TW/process/development-process.rst +++ b/Documentation/translations/zh_TW/process/development-process.rst @@ -11,9 +11,10 @@ 內核開發過程指南 ================ -內容: +本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟體開發)的人可以訪問的方式工作。雖然這裡有一些技術資料,但這是一個面向過程的討論,不需要深入了解內核編程就可以理解。 .. toctree:: + :caption: 內容 :numbered: :maxdepth: 2 @@ -26,5 +27,3 @@ 7.AdvancedTopics 8.Conclusion -本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟體開發)的人可以訪問的方式工作。雖然這裡有一些技術資料,但這是一個面向過程的討論,不需要深入了解內核編程就可以理解。 - From a4f58d70f238fd1761b4d048f512afccb5129888 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 10:18:30 +0200 Subject: [PATCH 0859/7721] docs: remove .toc-title class The "toc-title" class was introduced in commit ef88f10eb877 ("[media] doc-rst: backward compatibility with older Sphinx versions") as a workaround for Sphinx versions older than 1.4.x. However, these old versions have been deprecated since commit 31abfdda6527 ("docs: Deprecate use of Sphinx < 2.4.x"). Having now changed all the toc-title users to use the :caption: attribute, we can also remove the custom style. Note that the toc-title class is separate from the "kernel-toc" logic that was introduced in commit c404f5d4f099 ("docs: Add more information to the HTML sidebar"). Cc: Mauro Carvalho Chehab Cc: Jonathan Corbet Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027081830.195056-12-vegard.nossum@oracle.com --- Documentation/sphinx-static/theme_overrides.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/sphinx-static/theme_overrides.css b/Documentation/sphinx-static/theme_overrides.css index f6f2b941a5d6..79000b26e64e 100644 --- a/Documentation/sphinx-static/theme_overrides.css +++ b/Documentation/sphinx-static/theme_overrides.css @@ -81,11 +81,6 @@ div[class^="highlight"] pre { * - hide the permalink symbol as long as link is not hovered */ - .toc-title { - font-size: 150%; - font-weight: bold; - } - caption, .wy-table caption, .rst-content table.field-list caption { font-size: 100%; } From 86b17aaf2e887355e4f70dd9c4897f6a06fa9b32 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 27 Oct 2023 13:54:20 +0200 Subject: [PATCH 0860/7721] docs: automarkup: linkify git revs There aren't a ton of references to commits in the documentation, but they do exist, and we can use automarkup to linkify them to make them easier to follow. Use something like this to find references to commits: git grep -P 'commit.*[0-9a-f]{8,}' Documentation/ Also fix a few of these to standardize on the exact format that is already used in changelogs. Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231027115420.205279-1-vegard.nossum@oracle.com --- Documentation/arch/x86/boot.rst | 2 +- Documentation/bpf/btf.rst | 6 ++---- Documentation/doc-guide/sphinx.rst | 9 +++++++++ Documentation/livepatch/callbacks.rst | 4 ++-- Documentation/networking/snmp_counter.rst | 16 ++++++---------- Documentation/sphinx/automarkup.py | 20 +++++++++++++++++++- 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst index f5d2f2414de8..04376280e58f 100644 --- a/Documentation/arch/x86/boot.rst +++ b/Documentation/arch/x86/boot.rst @@ -71,7 +71,7 @@ Protocol 2.13 (Kernel 3.14) Support 32- and 64-bit flags being set in Protocol 2.14 BURNT BY INCORRECT COMMIT ae7e1238e68f2a472a125673ab506d49158c1889 - (x86/boot: Add ACPI RSDP address to setup_header) + ("x86/boot: Add ACPI RSDP address to setup_header") DO NOT USE!!! ASSUME SAME AS 2.13. Protocol 2.15 (Kernel 5.5) Added the kernel_info and kernel_info.setup_type_max. diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst index e43c2fdafcd7..257a7e1cdf5d 100644 --- a/Documentation/bpf/btf.rst +++ b/Documentation/bpf/btf.rst @@ -272,10 +272,8 @@ In this case, if the base type is an int type, it must be a regular int type: * ``BTF_INT_OFFSET()`` must be 0. * ``BTF_INT_BITS()`` must be equal to ``{1,2,4,8,16} * 8``. -The following kernel patch introduced ``kind_flag`` and explained why both -modes exist: - - https://github.com/torvalds/linux/commit/9d5f9f701b1891466fb3dbb1806ad97716f95cc3#diff-fa650a64fdd3968396883d2fe8215ff3 +Commit 9d5f9f701b18 introduced ``kind_flag`` and explains why both modes +exist. 2.2.6 BTF_KIND_ENUM ~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst index cd8ad7904491..bb7971643fcf 100644 --- a/Documentation/doc-guide/sphinx.rst +++ b/Documentation/doc-guide/sphinx.rst @@ -435,6 +435,15 @@ path. For information on cross-referencing to kernel-doc functions or types, see Documentation/doc-guide/kernel-doc.rst. +Referencing commits +~~~~~~~~~~~~~~~~~~~ + +References to git commits are automatically hyperlinked given that they are +written in one of these formats:: + + commit 72bf4f1767f0 + commit 72bf4f1767f0 ("net: do not leave an empty skb in write queue") + .. _sphinx_kfigure: Figures & Images diff --git a/Documentation/livepatch/callbacks.rst b/Documentation/livepatch/callbacks.rst index 470944aa8658..914445784ce4 100644 --- a/Documentation/livepatch/callbacks.rst +++ b/Documentation/livepatch/callbacks.rst @@ -110,7 +110,7 @@ Global data update ------------------ A pre-patch callback can be useful to update a global variable. For -example, 75ff39ccc1bd ("tcp: make challenge acks less predictable") +example, commit 75ff39ccc1bd ("tcp: make challenge acks less predictable") changes a global sysctl, as well as patches the tcp_send_challenge_ack() function. @@ -126,7 +126,7 @@ Although __init and probe functions are not directly livepatch-able, it may be possible to implement similar updates via pre/post-patch callbacks. -The commit ``48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST")`` change the way that +The commit 48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST") change the way that virtnet_probe() initialized its driver's net_device features. A pre/post-patch callback could iterate over all such devices, making a similar change to their hw_features value. (Client functions of the diff --git a/Documentation/networking/snmp_counter.rst b/Documentation/networking/snmp_counter.rst index 213637474478..ff1e6a8ffe21 100644 --- a/Documentation/networking/snmp_counter.rst +++ b/Documentation/networking/snmp_counter.rst @@ -313,7 +313,7 @@ https://lwn.net/Articles/576263/ * TcpExtTCPOrigDataSent -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPOrigDataSent: number of outgoing packets with original data (excluding @@ -323,7 +323,7 @@ explanation below:: * TCPSynRetrans -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPSynRetrans: number of SYN and SYN/ACK retransmits to break down @@ -331,14 +331,12 @@ explanation below:: * TCPFastOpenActiveFail -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPFastOpenActiveFail: Fast Open attempts (SYN/data) failed because the remote does not accept it or the attempts timed out. -.. _kernel commit f19c29e3e391: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f19c29e3e391a66a273e9afebaf01917245148cd - * TcpExtListenOverflows and TcpExtListenDrops When kernel receives a SYN from a client, and if the TCP accept queue @@ -698,11 +696,9 @@ number of the SACK block. For more details, please refer the comment of the function tcp_is_sackblock_valid in the kernel source code. A SACK option could have up to 4 blocks, they are checked individually. E.g., if 3 blocks of a SACk is invalid, the -corresponding counter would be updated 3 times. The comment of the -`Add counters for discarded SACK blocks`_ patch has additional -explanation: - -.. _Add counters for discarded SACK blocks: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=18f02545a9a16c9a89778b91a162ad16d510bb32 +corresponding counter would be updated 3 times. The comment of commit +18f02545a9a1 ("[TCP] MIB: Add counters for discarded SACK blocks") +has additional explanation: * TcpExtTCPSACKDiscard diff --git a/Documentation/sphinx/automarkup.py b/Documentation/sphinx/automarkup.py index 06b34740bf90..acc6d55718bd 100644 --- a/Documentation/sphinx/automarkup.py +++ b/Documentation/sphinx/automarkup.py @@ -74,6 +74,12 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap', c_namespace = '' +# +# Detect references to commits. +# +RE_git = re.compile(r'commit\s+(?P[0-9a-f]{12,40})(?:\s+\(".*?"\))?', + flags=re.IGNORECASE | re.DOTALL) + def markup_refs(docname, app, node): t = node.astext() done = 0 @@ -90,7 +96,8 @@ def markup_refs(docname, app, node): RE_struct: markup_c_ref, RE_union: markup_c_ref, RE_enum: markup_c_ref, - RE_typedef: markup_c_ref} + RE_typedef: markup_c_ref, + RE_git: markup_git} if sphinx.version_info[0] >= 3: markup_func = markup_func_sphinx3 @@ -276,6 +283,17 @@ def get_c_namespace(app, docname): return match.group(1) return '' +def markup_git(docname, app, match): + # While we could probably assume that we are running in a git + # repository, we can't know for sure, so let's just mechanically + # turn them into git.kernel.org links without checking their + # validity. (Maybe we can do something in the future to warn about + # these references if this is explicitly requested.) + text = match.group(0) + rev = match.group('rev') + return nodes.reference('', nodes.Text(text), + refuri=f'https://git.kernel.org/torvalds/c/{rev}') + def auto_markup(app, doctree, name): global c_namespace c_namespace = get_c_namespace(app, name) From 552206add94dd7977bad32c37eba16e23756a0f9 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Fri, 17 Nov 2023 14:13:41 +0000 Subject: [PATCH 0861/7721] ASoC: cs43130: Store device in private struct and use it more consistently Also remove one unnecessary debug print Signed-off-by: Maciej Strozek Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20231117141344.64320-5-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 151 ++++++++++++++++++------------------- sound/soc/codecs/cs43130.h | 1 + 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index d8ec325b9cc9..cdf26f9a72a3 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -238,7 +238,7 @@ static int cs43130_pll_config(struct snd_soc_component *component) struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); const struct cs43130_pll_params *pll_entry; - dev_dbg(component->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", + dev_dbg(cs43130->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", cs43130->mclk, cs43130->mclk_int); pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int); @@ -303,7 +303,7 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int cs43130->mclk = freq_in; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported pll input reference clock:%d\n", freq_in); return -EINVAL; } @@ -316,13 +316,13 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int cs43130->mclk_int = freq_out; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported pll output ref clock: %u\n", freq_out); return -EINVAL; } ret = cs43130_pll_config(component); - dev_dbg(component->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); + dev_dbg(cs43130->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); return ret; } @@ -346,7 +346,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, mclk_int_decoded = CS43130_MCLK_24P5; break; default: - dev_err(component->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); + dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); return -EINVAL; } @@ -370,7 +370,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); if (ret == 0) { - dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n"); + dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n"); return -ETIMEDOUT; } } @@ -406,7 +406,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); if (ret == 0) { - dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n"); + dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n"); return -ETIMEDOUT; } } @@ -422,7 +422,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_PLL_RDY_INT_MASK, 1 << CS43130_PLL_RDY_INT_SHIFT); if (ret == 0) { - dev_err(component->dev, "Timeout waiting for PLL_READY interrupt\n"); + dev_err(cs43130->dev, "Timeout waiting for PLL_READY interrupt\n"); return -ETIMEDOUT; } @@ -453,7 +453,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, 1 << CS43130_PDN_PLL_SHIFT); break; default: - dev_err(component->dev, "Invalid MCLK source value\n"); + dev_err(cs43130->dev, "Invalid MCLK source value\n"); return -EINVAL; } @@ -804,7 +804,7 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, dsd_speed = 1; break; default: - dev_err(component->dev, "Rate(%u) not supported\n", + dev_err(cs43130->dev, "Rate(%u) not supported\n", params_rate(params)); return -EINVAL; } @@ -875,7 +875,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, dsd_speed = 1; break; default: - dev_err(component->dev, "Rate(%u) not supported\n", + dev_err(cs43130->dev, "Rate(%u) not supported\n", params_rate(params)); return -EINVAL; } @@ -892,7 +892,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val); break; default: - dev_err(component->dev, "Invalid DAI (%d)\n", dai->id); + dev_err(cs43130->dev, "Invalid DAI (%d)\n", dai->id); return -EINVAL; } @@ -916,21 +916,21 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, if (!sclk) { /* at this point, SCLK must be set */ - dev_err(component->dev, "SCLK freq is not set\n"); + dev_err(cs43130->dev, "SCLK freq is not set\n"); return -EINVAL; } bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params); if (bitwidth_sclk < bitwidth_dai) { - dev_err(component->dev, "Format not supported: SCLK freq is too low\n"); + dev_err(cs43130->dev, "Format not supported: SCLK freq is too low\n"); return -EINVAL; } - dev_dbg(component->dev, + dev_dbg(cs43130->dev, "sclk = %u, fs = %d, bitwidth_dai = %u\n", sclk, params_rate(params), bitwidth_dai); - dev_dbg(component->dev, + dev_dbg(cs43130->dev, "bitwidth_sclk = %u, num_ch = %u\n", bitwidth_sclk, params_channels(params)); @@ -1189,7 +1189,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1246,7 +1246,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1322,7 +1322,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid DAC event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid DAC event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1360,7 +1360,7 @@ static int cs43130_hpin_event(struct snd_soc_dapm_widget *w, ARRAY_SIZE(hpin_postpmu_seq)); break; default: - dev_err(component->dev, "Invalid HPIN event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid HPIN event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1479,7 +1479,7 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; break; default: - dev_err(component->dev, "unsupported mode\n"); + dev_err(cs43130->dev, "unsupported mode\n"); return -EINVAL; } @@ -1497,12 +1497,12 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported audio format\n"); return -EINVAL; } - dev_dbg(component->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", + dev_dbg(cs43130->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", codec_dai->id, cs43130->dais[codec_dai->id].dai_mode, cs43130->dais[codec_dai->id].dai_format); @@ -1523,11 +1523,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; break; default: - dev_err(component->dev, "Unsupported DAI format.\n"); + dev_err(cs43130->dev, "Unsupported DAI format.\n"); return -EINVAL; } - dev_dbg(component->dev, "dai_mode = 0x%x\n", + dev_dbg(cs43130->dev, "dai_mode = 0x%x\n", cs43130->dais[codec_dai->id].dai_mode); return 0; @@ -1540,7 +1540,7 @@ static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai, struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); cs43130->dais[codec_dai->id].sclk = freq; - dev_dbg(component->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, + dev_dbg(cs43130->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, cs43130->dais[codec_dai->id].sclk); return 0; @@ -1630,7 +1630,7 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component, { struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); - dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", + dev_dbg(cs43130->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", clk_id, source, freq, dir); switch (freq) { @@ -1639,14 +1639,14 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component, cs43130->mclk = freq; break; default: - dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq); + dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", freq); return -EINVAL; } if (source == CS43130_MCLK_SRC_EXT) { cs43130->pll_bypass = true; } else { - dev_err(component->dev, "Invalid MCLK source\n"); + dev_err(cs43130->dev, "Invalid MCLK source\n"); return -EINVAL; } @@ -1933,7 +1933,6 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, unsigned int reg; u32 addr; u16 impedance; - struct snd_soc_component *component = cs43130->component; switch (msk) { case CS43130_HPLOAD_DC_INT: @@ -1963,7 +1962,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, else cs43130->hpload_dc[HP_RIGHT] = impedance; - dev_dbg(component->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, + dev_dbg(cs43130->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, impedance); } else { if (left_ch) @@ -1971,7 +1970,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, else cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance; - dev_dbg(component->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", + dev_dbg(cs43130->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", cs43130->ac_freq[ac_idx], !left_ch, impedance); } @@ -1985,7 +1984,6 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130, int ret; unsigned int msk; u16 ac_reg_val; - struct snd_soc_component *component = cs43130->component; reinit_completion(&cs43130->hpload_evt); @@ -2008,17 +2006,17 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130, msecs_to_jiffies(1000)); regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk); if (!ret) { - dev_err(component->dev, "Timeout waiting for HPLOAD interrupt\n"); + dev_err(cs43130->dev, "Timeout waiting for HPLOAD interrupt\n"); return -1; } - dev_dbg(component->dev, "HP load stat: %x, INT_MASK_4: %x\n", + dev_dbg(cs43130->dev, "HP load stat: %x, INT_MASK_4: %x\n", cs43130->hpload_stat, msk); if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT | CS43130_HPLOAD_UNPLUG_INT | CS43130_HPLOAD_OOR_INT)) || !(cs43130->hpload_stat & rslt_msk)) { - dev_dbg(component->dev, "HP load measure failed\n"); + dev_dbg(cs43130->dev, "HP load measure failed\n"); return -1; } @@ -2129,9 +2127,9 @@ static void cs43130_imp_meas(struct work_struct *wk) snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE, CS43130_JACK_MASK); - dev_dbg(component->dev, "Set HP output control. DC threshold\n"); + dev_dbg(cs43130->dev, "Set HP output control. DC threshold\n"); for (i = 0; i < CS43130_DC_THRESHOLD; i++) - dev_dbg(component->dev, "DC threshold[%d]: %u.\n", i, + dev_dbg(cs43130->dev, "DC threshold[%d]: %u.\n", i, cs43130->dc_threshold[i]); cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT], @@ -2165,7 +2163,6 @@ static void cs43130_imp_meas(struct work_struct *wk) static irqreturn_t cs43130_irq_thread(int irq, void *data) { struct cs43130_private *cs43130 = (struct cs43130_private *)data; - struct snd_soc_component *component = cs43130->component; unsigned int stickies[CS43130_NUM_INT]; unsigned int irq_occurrence = 0; unsigned int masks[CS43130_NUM_INT]; @@ -2183,8 +2180,6 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) for (j = 0; j < 8; j++) irq_occurrence += (stickies[i] >> j) & 1; } - dev_dbg(component->dev, "number of interrupts occurred (%u)\n", - irq_occurrence); if (!irq_occurrence) return IRQ_NONE; @@ -2201,7 +2196,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, + dev_err(cs43130->dev, "DC load has not completed before AC load (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); @@ -2210,7 +2205,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, "HP unplugged during measurement (%x)\n", + dev_err(cs43130->dev, "HP unplugged during measurement (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2218,7 +2213,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_OOR_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, "HP load out of range (%x)\n", + dev_err(cs43130->dev, "HP load out of range (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2226,7 +2221,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_AC_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP AC load measurement done (%x)\n", + dev_dbg(cs43130->dev, "HP AC load measurement done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2234,7 +2229,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_DC_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP DC load measurement done (%x)\n", + dev_dbg(cs43130->dev, "HP DC load measurement done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2242,7 +2237,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_ON_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP load state machine on done (%x)\n", + dev_dbg(cs43130->dev, "HP load state machine on done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2250,19 +2245,19 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_OFF_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP load state machine off done (%x)\n", + dev_dbg(cs43130->dev, "HP load state machine off done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; } if (stickies[0] & CS43130_XTAL_ERR_INT) { - dev_err(component->dev, "Crystal err: clock is not running\n"); + dev_err(cs43130->dev, "Crystal err: clock is not running\n"); return IRQ_HANDLED; } if (stickies[0] & CS43130_HP_UNPLUG_INT) { - dev_dbg(component->dev, "HP unplugged\n"); + dev_dbg(cs43130->dev, "HP unplugged\n"); cs43130->hpload_done = false; snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK); return IRQ_HANDLED; @@ -2271,7 +2266,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[0] & CS43130_HP_PLUG_INT) { if (cs43130->dc_meas && !cs43130->hpload_done && !work_busy(&cs43130->work)) { - dev_dbg(component->dev, "HP load queue work\n"); + dev_dbg(cs43130->dev, "HP load queue work\n"); queue_work(cs43130->wq, &cs43130->work); } @@ -2303,19 +2298,19 @@ static int cs43130_probe(struct snd_soc_component *component) ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, &cs43130->jack); if (ret < 0) { - dev_err(component->dev, "Cannot create jack\n"); + dev_err(cs43130->dev, "Cannot create jack\n"); return ret; } cs43130->hpload_done = false; if (cs43130->dc_meas) { - ret = sysfs_create_groups(&component->dev->kobj, hpload_groups); + ret = sysfs_create_groups(&cs43130->dev->kobj, hpload_groups); if (ret) return ret; cs43130->wq = create_singlethread_workqueue("cs43130_hp"); if (!cs43130->wq) { - sysfs_remove_groups(&component->dev->kobj, hpload_groups); + sysfs_remove_groups(&cs43130->dev->kobj, hpload_groups); return -ENOMEM; } INIT_WORK(&cs43130->work, cs43130_imp_meas); @@ -2391,7 +2386,7 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client, cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA; break; default: - dev_err(&i2c_client->dev, + dev_err(cs43130->dev, "Invalid cirrus,xtal-ibias value: %d\n", val); return -EINVAL; } @@ -2426,6 +2421,8 @@ static int cs43130_i2c_probe(struct i2c_client *client) if (!cs43130) return -ENOMEM; + cs43130->dev = &client->dev; + i2c_set_clientdata(client, cs43130); cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap); @@ -2434,7 +2431,7 @@ static int cs43130_i2c_probe(struct i2c_client *client) return ret; } - if (client->dev.of_node) { + if (cs43130->dev->of_node) { ret = cs43130_handle_device_data(client, cs43130); if (ret != 0) return ret; @@ -2442,21 +2439,21 @@ static int cs43130_i2c_probe(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) cs43130->supplies[i].supply = cs43130_supply_names[i]; - ret = devm_regulator_bulk_get(&client->dev, + ret = devm_regulator_bulk_get(cs43130->dev, ARRAY_SIZE(cs43130->supplies), cs43130->supplies); if (ret != 0) { - dev_err(&client->dev, "Failed to request supplies: %d\n", ret); + dev_err(cs43130->dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies), cs43130->supplies); if (ret != 0) { - dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); + dev_err(cs43130->dev, "Failed to enable supplies: %d\n", ret); return ret; } - cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, + cs43130->reset_gpio = devm_gpiod_get_optional(cs43130->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs43130->reset_gpio)) { ret = PTR_ERR(cs43130->reset_gpio); @@ -2470,7 +2467,7 @@ static int cs43130_i2c_probe(struct i2c_client *client) devid = cirrus_read_device_id(cs43130->regmap, CS43130_DEVID_AB); if (devid < 0) { ret = devid; - dev_err(&client->dev, "Failed to read device ID: %d\n", ret); + dev_err(cs43130->dev, "Failed to read device ID: %d\n", ret); goto err; } @@ -2481,7 +2478,7 @@ static int cs43130_i2c_probe(struct i2c_client *client) case CS43198_CHIP_ID: break; default: - dev_err(&client->dev, + dev_err(cs43130->dev, "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n", devid, CS43130_CHIP_ID, CS4399_CHIP_ID, CS43131_CHIP_ID, CS43198_CHIP_ID); @@ -2492,11 +2489,11 @@ static int cs43130_i2c_probe(struct i2c_client *client) cs43130->dev_id = devid; ret = regmap_read(cs43130->regmap, CS43130_REV_ID, ®); if (ret < 0) { - dev_err(&client->dev, "Get Revision ID failed\n"); + dev_err(cs43130->dev, "Get Revision ID failed\n"); goto err; } - dev_info(&client->dev, + dev_info(cs43130->dev, "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid, reg & 0xFF); @@ -2506,21 +2503,21 @@ static int cs43130_i2c_probe(struct i2c_client *client) init_completion(&cs43130->pll_rdy); init_completion(&cs43130->hpload_evt); - ret = devm_request_threaded_irq(&client->dev, client->irq, + ret = devm_request_threaded_irq(cs43130->dev, client->irq, NULL, cs43130_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs43130", cs43130); if (ret != 0) { - dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); + dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret); goto err; } cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; - pm_runtime_set_autosuspend_delay(&client->dev, 100); - pm_runtime_use_autosuspend(&client->dev); - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(cs43130->dev, 100); + pm_runtime_use_autosuspend(cs43130->dev); + pm_runtime_set_active(cs43130->dev); + pm_runtime_enable(cs43130->dev); switch (cs43130->dev_id) { case CS43130_CHIP_ID: @@ -2556,11 +2553,11 @@ static int cs43130_i2c_probe(struct i2c_client *client) break; } - ret = devm_snd_soc_register_component(&client->dev, + ret = devm_snd_soc_register_component(cs43130->dev, &soc_component_dev_cs43130, cs43130_dai, ARRAY_SIZE(cs43130_dai)); if (ret < 0) { - dev_err(&client->dev, + dev_err(cs43130->dev, "snd_soc_register_component failed with ret = %d\n", ret); goto err; } @@ -2598,15 +2595,15 @@ static void cs43130_i2c_remove(struct i2c_client *client) cancel_work_sync(&cs43130->work); flush_workqueue(cs43130->wq); - device_remove_file(&client->dev, &dev_attr_hpload_dc_l); - device_remove_file(&client->dev, &dev_attr_hpload_dc_r); - device_remove_file(&client->dev, &dev_attr_hpload_ac_l); - device_remove_file(&client->dev, &dev_attr_hpload_ac_r); + device_remove_file(cs43130->dev, &dev_attr_hpload_dc_l); + device_remove_file(cs43130->dev, &dev_attr_hpload_dc_r); + device_remove_file(cs43130->dev, &dev_attr_hpload_ac_l); + device_remove_file(cs43130->dev, &dev_attr_hpload_ac_r); } gpiod_set_value_cansleep(cs43130->reset_gpio, 0); - pm_runtime_disable(&client->dev); + pm_runtime_disable(cs43130->dev); regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); } diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index 90e8895275e7..2f5ec3888103 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -500,6 +500,7 @@ struct cs43130_dai { }; struct cs43130_private { + struct device *dev; struct snd_soc_component *component; struct regmap *regmap; struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES]; From ce7944b73e7729dc702b6741cff2b26886bb723c Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Fri, 17 Nov 2023 14:13:42 +0000 Subject: [PATCH 0862/7721] ASoC: cs43130: Add handling of ACPI Signed-off-by: Maciej Strozek Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20231117141344.64320-6-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 44 ++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index cdf26f9a72a3..a51d77947964 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -2362,14 +2362,12 @@ static const u16 cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { 120, }; -static int cs43130_handle_device_data(struct i2c_client *i2c_client, - struct cs43130_private *cs43130) +static int cs43130_handle_device_data(struct cs43130_private *cs43130) { - struct device_node *np = i2c_client->dev.of_node; unsigned int val; int i; - if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) { + if (device_property_read_u32(cs43130->dev, "cirrus,xtal-ibias", &val) < 0) { /* Crystal is unused. System clock is used for external MCLK */ cs43130->xtal_ibias = CS43130_XTAL_UNUSED; return 0; @@ -2391,18 +2389,18 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client, return -EINVAL; } - cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure"); - cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure"); + cs43130->dc_meas = device_property_read_bool(cs43130->dev, "cirrus,dc-measure"); + cs43130->ac_meas = device_property_read_bool(cs43130->dev, "cirrus,ac-measure"); - if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq, - CS43130_AC_FREQ) < 0) { + if (!device_property_read_u16_array(cs43130->dev, "cirrus,ac-freq", cs43130->ac_freq, + CS43130_AC_FREQ)) { for (i = 0; i < CS43130_AC_FREQ; i++) cs43130->ac_freq[i] = cs43130_ac_freq[i]; } - if (of_property_read_u16_array(np, "cirrus,dc-threshold", + if (!device_property_read_u16_array(cs43130->dev, "cirrus,dc-threshold", cs43130->dc_threshold, - CS43130_DC_THRESHOLD) < 0) { + CS43130_DC_THRESHOLD)) { for (i = 0; i < CS43130_DC_THRESHOLD; i++) cs43130->dc_threshold[i] = cs43130_dc_threshold[i]; } @@ -2431,11 +2429,12 @@ static int cs43130_i2c_probe(struct i2c_client *client) return ret; } - if (cs43130->dev->of_node) { - ret = cs43130_handle_device_data(client, cs43130); + if (dev_fwnode(cs43130->dev)) { + ret = cs43130_handle_device_data(cs43130); if (ret != 0) return ret; } + for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) cs43130->supplies[i].supply = cs43130_supply_names[i]; @@ -2666,6 +2665,7 @@ static const struct dev_pm_ops cs43130_runtime_pm = { NULL) }; +#if IS_ENABLED(CONFIG_OF) static const struct of_device_id cs43130_of_match[] = { {.compatible = "cirrus,cs43130",}, {.compatible = "cirrus,cs4399",}, @@ -2675,6 +2675,17 @@ static const struct of_device_id cs43130_of_match[] = { }; MODULE_DEVICE_TABLE(of, cs43130_of_match); +#endif + +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id cs43130_acpi_match[] = { + { "CSC4399", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(acpi, cs43130_acpi_match); +#endif + static const struct i2c_device_id cs43130_i2c_id[] = { {"cs43130", 0}, @@ -2688,9 +2699,10 @@ MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id); static struct i2c_driver cs43130_i2c_driver = { .driver = { - .name = "cs43130", - .of_match_table = cs43130_of_match, - .pm = &cs43130_runtime_pm, + .name = "cs43130", + .of_match_table = of_match_ptr(cs43130_of_match), + .acpi_match_table = ACPI_PTR(cs43130_acpi_match), + .pm = &cs43130_runtime_pm, }, .id_table = cs43130_i2c_id, .probe = cs43130_i2c_probe, From 9158221bf2aa5f7bfb916452c079b2fe63ca76e8 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Fri, 17 Nov 2023 14:13:44 +0000 Subject: [PATCH 0863/7721] ASoC: cs43130: Add switch to control normal and alt hp inputs Make sure these inputs are mutually exclusive as recommended by the datasheet Signed-off-by: Maciej Strozek Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20231117141344.64320-8-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index a51d77947964..845611afed85 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -1366,7 +1366,15 @@ static int cs43130_hpin_event(struct snd_soc_dapm_widget *w, return 0; } +static const char * const bypass_mux_text[] = { + "Internal", + "Alternative", +}; +static SOC_ENUM_SINGLE_DECL(bypass_enum, SND_SOC_NOPM, 0, bypass_mux_text); +static const struct snd_kcontrol_new bypass_ctrl = SOC_DAPM_ENUM("Switch", bypass_enum); + static const struct snd_soc_dapm_widget digital_hp_widgets[] = { + SND_SOC_DAPM_MUX("Bypass Switch", SND_SOC_NOPM, 0, 0, &bypass_ctrl), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -1419,13 +1427,13 @@ static const struct snd_soc_dapm_route digital_hp_routes[] = { {"DSD", NULL, "XSPIN DSD"}, {"HiFi DAC", NULL, "ASPIN PCM"}, {"HiFi DAC", NULL, "DSD"}, - {"HPOUTA", NULL, "HiFi DAC"}, - {"HPOUTB", NULL, "HiFi DAC"}, + {"Bypass Switch", "Internal", "HiFi DAC"}, + {"HPOUTA", NULL, "Bypass Switch"}, + {"HPOUTB", NULL, "Bypass Switch"}, }; static const struct snd_soc_dapm_route analog_hp_routes[] = { - {"HPOUTA", NULL, "Analog Playback"}, - {"HPOUTB", NULL, "Analog Playback"}, + {"Bypass Switch", "Alternative", "Analog Playback"}, }; static struct snd_soc_dapm_route all_hp_routes[ From d49af114421104ffc3378e932f474096e3f9598e Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Sun, 29 Oct 2023 08:42:07 +0100 Subject: [PATCH 0864/7721] Documentation: add tux logo We already have the logo, let's use it. Testing: make htmldocs Cc: Miguel Ojeda Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231029074207.297663-1-vegard.nossum@oracle.com --- Documentation/conf.py | 4 ++++ Documentation/sphinx-static/custom.css | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/Documentation/conf.py b/Documentation/conf.py index d4fdf6a3875a..20bd74edcca9 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -357,6 +357,10 @@ html_sidebars = { '**': ['searchbox.html', 'kernel-toc.html', 'sourcelink.html'] if html_theme == 'alabaster': html_sidebars['**'].insert(0, 'about.html') +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = 'images/logo.svg' + # Output file base name for HTML help builder. htmlhelp_basename = 'TheLinuxKerneldoc' diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css index c7439349dda6..c992b1946edc 100644 --- a/Documentation/sphinx-static/custom.css +++ b/Documentation/sphinx-static/custom.css @@ -23,6 +23,12 @@ div.document { width: auto; } +/* Size the logo appropriately */ +img.logo { + width: 104px; + margin-bottom: 20px; +} + /* * Parameters for the display of function prototypes and such included * from C source files. From 89a410b2e416f2216b29183d6b8537abeccc7abb Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 15 Nov 2023 10:21:18 -0800 Subject: [PATCH 0865/7721] drm/i915/dg2: Wa_18028616096 now applies to all DG2 The workaround database was just updated to extend this workaround to DG2-G11 (whereas previously it applied only to G10 and G12). Signed-off-by: Matt Roper Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231115182117.2551522-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 63205edfea50..9bc0654efdc0 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2937,6 +2937,9 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li * Wa_22015475538:dg2 */ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + + /* Wa_18028616096 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3); } if (IS_DG2_G11(i915)) { @@ -2965,11 +2968,6 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li true); } - if (IS_DG2_G10(i915) || IS_DG2_G12(i915)) { - /* Wa_18028616096 */ - wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3); - } - if (IS_XEHPSDV(i915)) { /* Wa_1409954639 */ wa_mcr_masked_en(wal, From 3c7a5eb700661e8905ab4e50c2d09c6568125280 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Thu, 16 Nov 2023 13:25:11 -0800 Subject: [PATCH 0866/7721] drm/i915/mtl: Update Wa_22018931422 Commit 78cc55e0b64c ("drm/i915/mcr: Hold GT forcewake during steering operations") introduced the workaround which was in early stages. With a valid lineage number update Workaround for future tracking. Cc: Matt Roper Signed-off-by: Radhakrishna Sripada Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231116212511.1760446-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 34913912d8ae..e253750a51c5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -388,8 +388,7 @@ void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags) * registers. This wakeref will be released in the unlock * routine. * - * This is expected to become a formally documented/numbered - * workaround soon. + * Wa_22018931422 */ intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_GT); From 446e2305827b76e8081057ce56bbd2703b4da8a9 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:29 +0100 Subject: [PATCH 0867/7721] net: Convert PHYs hwtstamp callback to use kernel_hwtstamp_config The PHYs hwtstamp callback are still getting the timestamp config from ifreq and using copy_from/to_user. Get rid of these functions by using timestamp configuration in parameter. This also allow to move on to kernel_hwtstamp_config and be similar to net devices using the new ndo_hwstamp_get/set. This adds the possibility to manipulate the timestamp configuration from the kernel which was not possible with the copy_from/to_user. Signed-off-by: Kory Maincent Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-ptp.c | 15 +++++------- drivers/net/phy/dp83640.c | 24 +++++++++---------- drivers/net/phy/micrel.c | 38 ++++++++++++++----------------- drivers/net/phy/mscc/mscc_ptp.c | 18 +++++++-------- drivers/net/phy/nxp-c45-tja11xx.c | 17 ++++++-------- drivers/net/phy/phy.c | 21 +++++++++++++++-- drivers/ptp/ptp_ines.c | 16 ++++++------- include/linux/mii_timestamper.h | 4 +++- include/linux/phy.h | 6 +++-- 9 files changed, 82 insertions(+), 77 deletions(-) diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c index cb4b91af5e17..617d384d4551 100644 --- a/drivers/net/phy/bcm-phy-ptp.c +++ b/drivers/net/phy/bcm-phy-ptp.c @@ -782,16 +782,13 @@ static void bcm_ptp_txtstamp(struct mii_timestamper *mii_ts, } static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts, - struct ifreq *ifr) + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { struct bcm_ptp_private *priv = mii2priv(mii_ts); - struct hwtstamp_config cfg; u16 mode, ctrl; - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: priv->hwts_rx = false; break; @@ -804,14 +801,14 @@ static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; priv->hwts_rx = true; break; default: return -ERANGE; } - priv->tx_type = cfg.tx_type; + priv->tx_type = cfg->tx_type; ctrl = priv->hwts_rx ? SLICE_RX_EN : 0; ctrl |= priv->tx_type != HWTSTAMP_TX_OFF ? SLICE_TX_EN : 0; @@ -840,7 +837,7 @@ static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts, /* purge existing data */ skb_queue_purge(&priv->tx_queue); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static int bcm_ptp_ts_info(struct mii_timestamper *mii_ts, diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 2657be7cc049..5c42c47dc564 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1207,22 +1207,20 @@ static irqreturn_t dp83640_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } -static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { struct dp83640_private *dp83640 = container_of(mii_ts, struct dp83640_private, mii_ts); - struct hwtstamp_config cfg; u16 txcfg0, rxcfg0; - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC) + if (cfg->tx_type < 0 || cfg->tx_type > HWTSTAMP_TX_ONESTEP_SYNC) return -ERANGE; - dp83640->hwts_tx_en = cfg.tx_type; + dp83640->hwts_tx_en = cfg->tx_type; - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: dp83640->hwts_rx_en = 0; dp83640->layer = 0; @@ -1234,7 +1232,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) dp83640->hwts_rx_en = 1; dp83640->layer = PTP_CLASS_L4; dp83640->version = PTP_CLASS_V1; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: @@ -1242,7 +1240,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) dp83640->hwts_rx_en = 1; dp83640->layer = PTP_CLASS_L4; dp83640->version = PTP_CLASS_V2; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: @@ -1250,7 +1248,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) dp83640->hwts_rx_en = 1; dp83640->layer = PTP_CLASS_L2; dp83640->version = PTP_CLASS_V2; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: @@ -1258,7 +1256,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) dp83640->hwts_rx_en = 1; dp83640->layer = PTP_CLASS_L4 | PTP_CLASS_L2; dp83640->version = PTP_CLASS_V2; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; default: return -ERANGE; @@ -1292,7 +1290,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) mutex_unlock(&dp83640->clock->extreg_lock); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static void rx_timestamp_work(struct work_struct *work) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 08e3915001c3..99af1e500c6c 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -2395,24 +2395,22 @@ static void lan8814_flush_fifo(struct phy_device *phydev, bool egress) lanphy_read_page_reg(phydev, 5, PTP_TSU_INT_STS); } -static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); struct phy_device *phydev = ptp_priv->phydev; struct lan8814_shared_priv *shared = phydev->shared->priv; struct lan8814_ptp_rx_ts *rx_ts, *tmp; - struct hwtstamp_config config; int txcfg = 0, rxcfg = 0; int pkt_ts_enable; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; + ptp_priv->hwts_tx_type = config->tx_type; + ptp_priv->rx_filter = config->rx_filter; - ptp_priv->hwts_tx_type = config.tx_type; - ptp_priv->rx_filter = config.rx_filter; - - switch (config.rx_filter) { + switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: ptp_priv->layer = 0; ptp_priv->version = 0; @@ -2458,13 +2456,13 @@ static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_TX_MOD, PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_); - if (config.rx_filter != HWTSTAMP_FILTER_NONE) + if (config->rx_filter != HWTSTAMP_FILTER_NONE) lan8814_config_ts_intr(ptp_priv->phydev, true); else lan8814_config_ts_intr(ptp_priv->phydev, false); mutex_lock(&shared->shared_lock); - if (config.rx_filter != HWTSTAMP_FILTER_NONE) + if (config->rx_filter != HWTSTAMP_FILTER_NONE) shared->ref++; else shared->ref--; @@ -2488,7 +2486,7 @@ static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) lan8814_flush_fifo(ptp_priv->phydev, false); lan8814_flush_fifo(ptp_priv->phydev, true); - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + return 0; } static void lan8814_txtstamp(struct mii_timestamper *mii_ts, @@ -3703,21 +3701,19 @@ static void lan8841_ptp_enable_processing(struct kszphy_ptp_priv *ptp_priv, #define LAN8841_PTP_TX_TIMESTAMP_EN 443 #define LAN8841_PTP_TX_MOD 445 -static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); struct phy_device *phydev = ptp_priv->phydev; - struct hwtstamp_config config; int txcfg = 0, rxcfg = 0; int pkt_ts_enable; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; + ptp_priv->hwts_tx_type = config->tx_type; + ptp_priv->rx_filter = config->rx_filter; - ptp_priv->hwts_tx_type = config.tx_type; - ptp_priv->rx_filter = config.rx_filter; - - switch (config.rx_filter) { + switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: ptp_priv->layer = 0; ptp_priv->version = 0; @@ -3771,13 +3767,13 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) /* Now enable/disable the timestamping */ lan8841_ptp_enable_processing(ptp_priv, - config.rx_filter != HWTSTAMP_FILTER_NONE); + config->rx_filter != HWTSTAMP_FILTER_NONE); skb_queue_purge(&ptp_priv->tx_queue); lan8841_ptp_flush_fifo(ptp_priv); - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + return 0; } static bool lan8841_rxtstamp(struct mii_timestamper *mii_ts, diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index cf728bfd83e2..eb0b032cb613 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -1045,19 +1045,17 @@ static void vsc85xx_ts_reset_fifo(struct phy_device *phydev) val); } -static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { struct vsc8531_private *vsc8531 = container_of(mii_ts, struct vsc8531_private, mii_ts); struct phy_device *phydev = vsc8531->ptp->phydev; - struct hwtstamp_config cfg; bool one_step = false; u32 val; - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - switch (cfg.tx_type) { + switch (cfg->tx_type) { case HWTSTAMP_TX_ONESTEP_SYNC: one_step = true; break; @@ -1069,9 +1067,9 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) return -ERANGE; } - vsc8531->ptp->tx_type = cfg.tx_type; + vsc8531->ptp->tx_type = cfg->tx_type; - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: @@ -1084,7 +1082,7 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) return -ERANGE; } - vsc8531->ptp->rx_filter = cfg.rx_filter; + vsc8531->ptp->rx_filter = cfg->rx_filter; mutex_lock(&vsc8531->ts_lock); @@ -1132,7 +1130,7 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) vsc8531->ptp->configured = 1; mutex_unlock(&vsc8531->ts_lock); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static int vsc85xx_ts_info(struct mii_timestamper *mii_ts, diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 7ab080ff02df..780ad353cf55 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -1022,24 +1022,21 @@ static bool nxp_c45_rxtstamp(struct mii_timestamper *mii_ts, } static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, - struct ifreq *ifreq) + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, mii_ts); struct phy_device *phydev = priv->phydev; const struct nxp_c45_phy_data *data; - struct hwtstamp_config cfg; - if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg))) - return -EFAULT; - - if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON) + if (cfg->tx_type < 0 || cfg->tx_type > HWTSTAMP_TX_ON) return -ERANGE; data = nxp_c45_get_data(phydev); - priv->hwts_tx = cfg.tx_type; + priv->hwts_tx = cfg->tx_type; - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: priv->hwts_rx = 0; break; @@ -1047,7 +1044,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: priv->hwts_rx = 1; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; default: return -ERANGE; @@ -1074,7 +1071,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, nxp_c45_clear_reg_field(phydev, &data->regmap->irq_egr_ts_en); nxp_c45_no_ptp_irq: - return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static int nxp_c45_ts_info(struct mii_timestamper *mii_ts, diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index a5fa077650e8..d058316666ba 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -325,9 +325,13 @@ EXPORT_SYMBOL(phy_ethtool_ksettings_get); int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *mii_data = if_mii(ifr); + struct kernel_hwtstamp_config kernel_cfg; + struct netlink_ext_ack extack = {}; u16 val = mii_data->val_in; bool change_autoneg = false; + struct hwtstamp_config cfg; int prtad, devad; + int ret; switch (cmd) { case SIOCGMIIPHY: @@ -411,8 +415,21 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) return 0; case SIOCSHWTSTAMP: - if (phydev->mii_ts && phydev->mii_ts->hwtstamp) - return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr); + if (phydev->mii_ts && phydev->mii_ts->hwtstamp) { + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + hwtstamp_config_to_kernel(&kernel_cfg, &cfg); + ret = phydev->mii_ts->hwtstamp(phydev->mii_ts, &kernel_cfg, &extack); + if (ret) + return ret; + + hwtstamp_config_from_kernel(&cfg, &kernel_cfg); + if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) + return -EFAULT; + + return 0; + } fallthrough; default: diff --git a/drivers/ptp/ptp_ines.c b/drivers/ptp/ptp_ines.c index ed215b458183..1d2940a78455 100644 --- a/drivers/ptp/ptp_ines.c +++ b/drivers/ptp/ptp_ines.c @@ -328,17 +328,15 @@ static u64 ines_find_txts(struct ines_port *port, struct sk_buff *skb) return ns; } -static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static int ines_hwtstamp(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { struct ines_port *port = container_of(mii_ts, struct ines_port, mii_ts); u32 cm_one_step = 0, port_conf, ts_stat_rx, ts_stat_tx; - struct hwtstamp_config cfg; unsigned long flags; - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - switch (cfg.tx_type) { + switch (cfg->tx_type) { case HWTSTAMP_TX_OFF: ts_stat_tx = 0; break; @@ -353,7 +351,7 @@ static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) return -ERANGE; } - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: ts_stat_rx = 0; break; @@ -372,7 +370,7 @@ static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: ts_stat_rx = TS_ENABLE; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; default: return -ERANGE; @@ -393,7 +391,7 @@ static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) spin_unlock_irqrestore(&port->lock, flags); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static void ines_link_state(struct mii_timestamper *mii_ts, diff --git a/include/linux/mii_timestamper.h b/include/linux/mii_timestamper.h index fa940bbaf8ae..26b04f73f214 100644 --- a/include/linux/mii_timestamper.h +++ b/include/linux/mii_timestamper.h @@ -9,6 +9,7 @@ #include #include #include +#include struct phy_device; @@ -51,7 +52,8 @@ struct mii_timestamper { struct sk_buff *skb, int type); int (*hwtstamp)(struct mii_timestamper *mii_ts, - struct ifreq *ifreq); + struct kernel_hwtstamp_config *kernel_config, + struct netlink_ext_ack *extack); void (*link_state)(struct mii_timestamper *mii_ts, struct phy_device *phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 3cc52826f18e..e5f1f41e399c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1560,9 +1560,11 @@ static inline bool phy_has_txtstamp(struct phy_device *phydev) return phydev && phydev->mii_ts && phydev->mii_ts->txtstamp; } -static inline int phy_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) +static inline int phy_hwtstamp(struct phy_device *phydev, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { - return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr); + return phydev->mii_ts->hwtstamp(phydev->mii_ts, cfg, extack); } static inline bool phy_rxtstamp(struct phy_device *phydev, struct sk_buff *skb, From 430dc3256d5790361135c69af5de1aaa07248e8a Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:30 +0100 Subject: [PATCH 0868/7721] net: phy: Remove the call to phy_mii_ioctl in phy_hwstamp_get/set __phy_hwtstamp_set function were calling the phy_mii_ioctl function which will then use the ifreq pointer to call the hwtstamp callback. Now that ifreq has been removed from the hwstamp callback parameters it seems more logical to not go through the phy_mii_ioctl function and pass directly kernel_hwtstamp_config parameter to the hwtstamp callback. Lets do the same for __phy_hwtstamp_get function and return directly EOPNOTSUPP as SIOCGHWTSTAMP is not supported for now for the PHYs. Signed-off-by: Kory Maincent Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d058316666ba..3376e58e2b88 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -486,7 +486,7 @@ int __phy_hwtstamp_get(struct phy_device *phydev, if (!phydev) return -ENODEV; - return phy_mii_ioctl(phydev, config->ifr, SIOCGHWTSTAMP); + return -EOPNOTSUPP; } /** @@ -503,7 +503,10 @@ int __phy_hwtstamp_set(struct phy_device *phydev, if (!phydev) return -ENODEV; - return phy_mii_ioctl(phydev, config->ifr, SIOCSHWTSTAMP); + if (phydev->mii_ts && phydev->mii_ts->hwtstamp) + return phydev->mii_ts->hwtstamp(phydev->mii_ts, config, extack); + + return -EOPNOTSUPP; } /** From b8768dc4077712915f045ba1b198f521493c7914 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Tue, 14 Nov 2023 12:28:31 +0100 Subject: [PATCH 0869/7721] net: ethtool: Refactor identical get_ts_info implementations. The vlan, macvlan and the bonding drivers call their "real" device driver in order to report the time stamping capabilities. Provide a core ethtool helper function to avoid copy/paste in the stack. Signed-off-by: Richard Cochran Signed-off-by: Kory Maincent Reviewed-by: Florian Fainelli Reviewed-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 29 ++--------------------------- drivers/net/macvlan.c | 14 +------------- include/linux/ethtool.h | 8 ++++++++ net/8021q/vlan_dev.c | 15 +-------------- net/ethtool/common.c | 6 ++++++ 5 files changed, 18 insertions(+), 54 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8e6cc0e133b7..4e0600c7b050 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5755,10 +5755,8 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev, { struct bonding *bond = netdev_priv(bond_dev); struct ethtool_ts_info ts_info; - const struct ethtool_ops *ops; struct net_device *real_dev; bool sw_tx_support = false; - struct phy_device *phydev; struct list_head *iter; struct slave *slave; int ret = 0; @@ -5769,29 +5767,12 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev, rcu_read_unlock(); if (real_dev) { - ops = real_dev->ethtool_ops; - phydev = real_dev->phydev; - - if (phy_has_tsinfo(phydev)) { - ret = phy_ts_info(phydev, info); - goto out; - } else if (ops->get_ts_info) { - ret = ops->get_ts_info(real_dev, info); - goto out; - } + ret = ethtool_get_ts_info_by_layer(real_dev, info); } else { /* Check if all slaves support software tx timestamping */ rcu_read_lock(); bond_for_each_slave_rcu(bond, slave, iter) { - ret = -1; - ops = slave->dev->ethtool_ops; - phydev = slave->dev->phydev; - - if (phy_has_tsinfo(phydev)) - ret = phy_ts_info(phydev, &ts_info); - else if (ops->get_ts_info) - ret = ops->get_ts_info(slave->dev, &ts_info); - + ret = ethtool_get_ts_info_by_layer(slave->dev, &ts_info); if (!ret && (ts_info.so_timestamping & SOF_TIMESTAMPING_TX_SOFTWARE)) { sw_tx_support = true; continue; @@ -5803,15 +5784,9 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev, rcu_read_unlock(); } - ret = 0; - info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; if (sw_tx_support) info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE; - info->phc_index = -1; - -out: dev_put(real_dev); return ret; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c8da94af4161..88dd8a2245b0 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1086,20 +1086,8 @@ static int macvlan_ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { struct net_device *real_dev = macvlan_dev_real_dev(dev); - const struct ethtool_ops *ops = real_dev->ethtool_ops; - struct phy_device *phydev = real_dev->phydev; - if (phy_has_tsinfo(phydev)) { - return phy_ts_info(phydev, info); - } else if (ops->get_ts_info) { - return ops->get_ts_info(real_dev, info); - } else { - info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; - info->phc_index = -1; - } - - return 0; + return ethtool_get_ts_info_by_layer(real_dev, info); } static netdev_features_t macvlan_fix_features(struct net_device *dev, diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 689028257fcc..c2bb74143eda 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -1043,6 +1043,14 @@ static inline int ethtool_mm_frag_size_min_to_add(u32 val_min, u32 *val_add, return -EINVAL; } +/** + * ethtool_get_ts_info_by_layer - Obtains time stamping capabilities from the MAC or PHY layer. + * @dev: pointer to net_device structure + * @info: buffer to hold the result + * Returns zero on success, non-zero otherwise. + */ +int ethtool_get_ts_info_by_layer(struct net_device *dev, struct ethtool_ts_info *info); + /** * ethtool_sprintf - Write formatted string to ethtool string data * @data: Pointer to a pointer to the start of string to update diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 2a7f1b15714a..407b2335f091 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -702,20 +702,7 @@ static int vlan_ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); - const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops; - struct phy_device *phydev = vlan->real_dev->phydev; - - if (phy_has_tsinfo(phydev)) { - return phy_ts_info(phydev, info); - } else if (ops->get_ts_info) { - return ops->get_ts_info(vlan->real_dev, info); - } else { - info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; - info->phc_index = -1; - } - - return 0; + return ethtool_get_ts_info_by_layer(vlan->real_dev, info); } static void vlan_dev_get_stats64(struct net_device *dev, diff --git a/net/ethtool/common.c b/net/ethtool/common.c index b4419fb6df6a..11d8797f63f6 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -661,6 +661,12 @@ int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index) } EXPORT_SYMBOL(ethtool_get_phc_vclocks); +int ethtool_get_ts_info_by_layer(struct net_device *dev, struct ethtool_ts_info *info) +{ + return __ethtool_get_ts_info(dev, info); +} +EXPORT_SYMBOL(ethtool_get_ts_info_by_layer); + const struct ethtool_phy_ops *ethtool_phy_ops; void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops) From 202cb220026e4dabb592852e7555e264656445ac Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:32 +0100 Subject: [PATCH 0870/7721] net: macb: Convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() The hardware timestamping through ndo_eth_ioctl() is going away. Convert the macb driver to the new API before that can be removed. Signed-off-by: Kory Maincent Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 15 ++++++--- drivers/net/ethernet/cadence/macb_main.c | 42 +++++++++++++++++++----- drivers/net/ethernet/cadence/macb_ptp.c | 28 ++++++---------- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 78c972bb1d96..aa5700ac9c00 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1165,9 +1165,10 @@ struct macb_ptp_info { int (*get_ts_info)(struct net_device *dev, struct ethtool_ts_info *info); int (*get_hwtst)(struct net_device *netdev, - struct ifreq *ifr); + struct kernel_hwtstamp_config *tstamp_config); int (*set_hwtst)(struct net_device *netdev, - struct ifreq *ifr, int cmd); + struct kernel_hwtstamp_config *tstamp_config, + struct netlink_ext_ack *extack); }; struct macb_pm_data { @@ -1314,7 +1315,7 @@ struct macb { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_clock_info; struct tsu_incr tsu_incr; - struct hwtstamp_config tstamp_config; + struct kernel_hwtstamp_config tstamp_config; /* RX queue filer rule set*/ struct ethtool_rx_fs_list rx_fs_list; @@ -1363,8 +1364,12 @@ static inline void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb, stru gem_ptp_rxstamp(bp, skb, desc); } -int gem_get_hwtst(struct net_device *dev, struct ifreq *rq); -int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd); + +int gem_get_hwtst(struct net_device *dev, + struct kernel_hwtstamp_config *tstamp_config); +int gem_set_hwtst(struct net_device *dev, + struct kernel_hwtstamp_config *tstamp_config, + struct netlink_ext_ack *extack); #else static inline void gem_ptp_init(struct net_device *ndev) { } static inline void gem_ptp_remove(struct net_device *ndev) { } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index cebae0f418f2..898debfd4db3 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3773,18 +3773,38 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!netif_running(dev)) return -EINVAL; - if (bp->ptp_info) { - switch (cmd) { - case SIOCSHWTSTAMP: - return bp->ptp_info->set_hwtst(dev, rq, cmd); - case SIOCGHWTSTAMP: - return bp->ptp_info->get_hwtst(dev, rq); - } - } - return phylink_mii_ioctl(bp->phylink, rq, cmd); } +static int macb_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *cfg) +{ + struct macb *bp = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!bp->ptp_info) + return -EOPNOTSUPP; + + return bp->ptp_info->get_hwtst(dev, cfg); +} + +static int macb_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) +{ + struct macb *bp = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!bp->ptp_info) + return -EOPNOTSUPP; + + return bp->ptp_info->set_hwtst(dev, cfg, extack); +} + static inline void macb_set_txcsum_feature(struct macb *bp, netdev_features_t features) { @@ -3884,6 +3904,8 @@ static const struct net_device_ops macb_netdev_ops = { #endif .ndo_set_features = macb_set_features, .ndo_features_check = macb_features_check, + .ndo_hwtstamp_set = macb_hwtstamp_set, + .ndo_hwtstamp_get = macb_hwtstamp_get, }; /* Configure peripheral capabilities according to device tree @@ -4539,6 +4561,8 @@ static const struct net_device_ops at91ether_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = at91ether_poll_controller, #endif + .ndo_hwtstamp_set = macb_hwtstamp_set, + .ndo_hwtstamp_get = macb_hwtstamp_get, }; static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk, diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index 51d26fa190d7..a63bf29c4fa8 100644 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -374,19 +374,16 @@ static int gem_ptp_set_ts_mode(struct macb *bp, return 0; } -int gem_get_hwtst(struct net_device *dev, struct ifreq *rq) +int gem_get_hwtst(struct net_device *dev, + struct kernel_hwtstamp_config *tstamp_config) { - struct hwtstamp_config *tstamp_config; struct macb *bp = netdev_priv(dev); - tstamp_config = &bp->tstamp_config; + *tstamp_config = bp->tstamp_config; if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) return -EOPNOTSUPP; - if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config))) - return -EFAULT; - else - return 0; + return 0; } static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable) @@ -401,22 +398,18 @@ static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable) macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE)); } -int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd) +int gem_set_hwtst(struct net_device *dev, + struct kernel_hwtstamp_config *tstamp_config, + struct netlink_ext_ack *extack) { enum macb_bd_control tx_bd_control = TSTAMP_DISABLED; enum macb_bd_control rx_bd_control = TSTAMP_DISABLED; - struct hwtstamp_config *tstamp_config; struct macb *bp = netdev_priv(dev); u32 regval; - tstamp_config = &bp->tstamp_config; if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) return -EOPNOTSUPP; - if (copy_from_user(tstamp_config, ifr->ifr_data, - sizeof(*tstamp_config))) - return -EFAULT; - switch (tstamp_config->tx_type) { case HWTSTAMP_TX_OFF: break; @@ -463,12 +456,11 @@ int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd) return -ERANGE; } + bp->tstamp_config = *tstamp_config; + if (gem_ptp_set_ts_mode(bp, tx_bd_control, rx_bd_control) != 0) return -ERANGE; - if (copy_to_user(ifr->ifr_data, tstamp_config, sizeof(*tstamp_config))) - return -EFAULT; - else - return 0; + return 0; } From 011dd3b3f83f9c89605c640424e05845b84f2dad Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:33 +0100 Subject: [PATCH 0871/7721] net: Make dev_set_hwtstamp_phylib accessible Make the dev_set_hwtstamp_phylib function accessible in prevision to use it from ethtool to reset the tstamp current configuration. Reviewed-by: Florian Fainelli Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +++ net/core/dev_ioctl.c | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a16c9cc063fe..2d840d7056f2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3942,6 +3942,9 @@ int generic_hwtstamp_get_lower(struct net_device *dev, int generic_hwtstamp_set_lower(struct net_device *dev, struct kernel_hwtstamp_config *kernel_cfg, struct netlink_ext_ack *extack); +int dev_set_hwtstamp_phylib(struct net_device *dev, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack); int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata); unsigned int dev_get_flags(const struct net_device *); int __dev_change_flags(struct net_device *dev, unsigned int flags, diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index feeddf95f450..9a66cf5015f2 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -322,9 +322,9 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) * frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in * dev->priv_flags. */ -static int dev_set_hwtstamp_phylib(struct net_device *dev, - struct kernel_hwtstamp_config *cfg, - struct netlink_ext_ack *extack) +int dev_set_hwtstamp_phylib(struct net_device *dev, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) { const struct net_device_ops *ops = dev->netdev_ops; bool phy_ts = phy_has_hwtstamp(dev->phydev); @@ -363,6 +363,7 @@ static int dev_set_hwtstamp_phylib(struct net_device *dev, return 0; } +EXPORT_SYMBOL_GPL(dev_set_hwtstamp_phylib); static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr) { From 915d25a9d69be969c1cc6c1dd0c3861f6da7b55e Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:34 +0100 Subject: [PATCH 0872/7721] net: phy: micrel: fix ts_info value in case of no phc In case of no phc we should not return SOFTWARE TIMESTAMPING flags as we do not know whether the netdev supports of timestamping. Remove it from the lan8841_ts_info and simply return 0. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 99af1e500c6c..bd4cd082662f 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -3629,12 +3629,8 @@ static int lan8841_ts_info(struct mii_timestamper *mii_ts, info->phc_index = ptp_priv->ptp_clock ? ptp_clock_index(ptp_priv->ptp_clock) : -1; - if (info->phc_index == -1) { - info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; + if (info->phc_index == -1) return 0; - } info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | From acec05fb78abb74fdab2195bfca9a6d38a732643 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:35 +0100 Subject: [PATCH 0873/7721] net_tstamp: Add TIMESTAMPING SOFTWARE and HARDWARE mask Timestamping software or hardware flags are often used as a group, therefore adding these masks will easier future use. I did not use SOF_TIMESTAMPING_SYS_HARDWARE flag as it is deprecated and not use at all. Signed-off-by: Kory Maincent Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/uapi/linux/net_tstamp.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index a2c66b3d7f0f..df8091998c8d 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -48,6 +48,14 @@ enum { SOF_TIMESTAMPING_TX_SCHED | \ SOF_TIMESTAMPING_TX_ACK) +#define SOF_TIMESTAMPING_SOFTWARE_MASK (SOF_TIMESTAMPING_RX_SOFTWARE | \ + SOF_TIMESTAMPING_TX_SOFTWARE | \ + SOF_TIMESTAMPING_SOFTWARE) + +#define SOF_TIMESTAMPING_HARDWARE_MASK (SOF_TIMESTAMPING_RX_HARDWARE | \ + SOF_TIMESTAMPING_TX_HARDWARE | \ + SOF_TIMESTAMPING_RAW_HARDWARE) + /** * struct so_timestamping - SO_TIMESTAMPING parameter * From 11d55be06df0aedf19b05ab61c2d26b31a3c7e64 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:36 +0100 Subject: [PATCH 0874/7721] net: ethtool: Add a command to expose current time stamping layer Time stamping on network packets may happen either in the MAC or in the PHY, but not both. In preparation for making the choice selectable, expose both the current layers via ethtool. In accordance with the kernel implementation as it stands, the current layer will always read as "phy" when a PHY time stamping device is present. Future patches will allow changing the current layer administratively. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/networking/ethtool-netlink.rst | 23 +++++ include/uapi/linux/ethtool_netlink.h | 14 ++++ include/uapi/linux/net_tstamp.h | 10 +++ net/ethtool/Makefile | 2 +- net/ethtool/common.h | 1 + net/ethtool/netlink.c | 10 +++ net/ethtool/netlink.h | 2 + net/ethtool/ts.c | 88 ++++++++++++++++++++ 8 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 net/ethtool/ts.c diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 2540c70952ff..644b3b764044 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -225,6 +225,7 @@ Userspace to kernel: ``ETHTOOL_MSG_RSS_GET`` get RSS settings ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters + ``ETHTOOL_MSG_TS_GET`` get current timestamping ===================================== ================================= Kernel to userspace: @@ -268,6 +269,7 @@ Kernel to userspace: ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status + ``ETHTOOL_MSG_TS_GET_REPLY`` current timestamping ======================================== ================================= ``GET`` requests are sent by userspace applications to retrieve device @@ -1994,6 +1996,26 @@ The attributes are propagated to the driver through the following structure: .. kernel-doc:: include/linux/ethtool.h :identifiers: ethtool_mm_cfg +TS_GET +====== + +Gets current timestamping. + +Request contents: + + ================================= ====== ==================== + ``ETHTOOL_A_TS_HEADER`` nested request header + ================================= ====== ==================== + +Kernel response contents: + + ======================= ====== ============================== + ``ETHTOOL_A_TS_HEADER`` nested reply header + ``ETHTOOL_A_TS_LAYER`` u32 current timestamping + ======================= ====== ============================== + +This command get the current timestamp layer. + Request translation =================== @@ -2100,4 +2122,5 @@ are netlink only. n/a ``ETHTOOL_MSG_PLCA_GET_STATUS`` n/a ``ETHTOOL_MSG_MM_GET`` n/a ``ETHTOOL_MSG_MM_SET`` + n/a ``ETHTOOL_MSG_TS_GET`` =================================== ===================================== diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 73e2c10dc2cc..cb51136328cf 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -57,6 +57,7 @@ enum { ETHTOOL_MSG_PLCA_GET_STATUS, ETHTOOL_MSG_MM_GET, ETHTOOL_MSG_MM_SET, + ETHTOOL_MSG_TS_GET, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, @@ -109,6 +110,7 @@ enum { ETHTOOL_MSG_PLCA_NTF, ETHTOOL_MSG_MM_GET_REPLY, ETHTOOL_MSG_MM_NTF, + ETHTOOL_MSG_TS_GET_REPLY, /* add new constants above here */ __ETHTOOL_MSG_KERNEL_CNT, @@ -975,6 +977,18 @@ enum { ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1) }; +/* TS LAYER */ + +enum { + ETHTOOL_A_TS_UNSPEC, + ETHTOOL_A_TS_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_TS_LAYER, /* u32 */ + + /* add new constants above here */ + __ETHTOOL_A_TS_CNT, + ETHTOOL_A_TS_MAX = (__ETHTOOL_A_TS_CNT - 1) +}; + /* generic netlink info */ #define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_VERSION 1 diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index df8091998c8d..4551fb3d7720 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -13,6 +13,16 @@ #include #include /* for SO_TIMESTAMPING */ +/* Layer of the TIMESTAMPING provider */ +enum timestamping_layer { + NO_TIMESTAMPING, + SOFTWARE_TIMESTAMPING, + MAC_TIMESTAMPING, + PHY_TIMESTAMPING, + + __TIMESTAMPING_COUNT, +}; + /* SO_TIMESTAMPING flags */ enum { SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile index 504f954a1b28..4ea64c080639 100644 --- a/net/ethtool/Makefile +++ b/net/ethtool/Makefile @@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \ linkstate.o debug.o wol.o features.o privflags.o rings.o \ channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ - module.o pse-pd.o plca.o mm.o + module.o pse-pd.o plca.o mm.o ts.o diff --git a/net/ethtool/common.h b/net/ethtool/common.h index 28b8aaaf9bcb..a264b635f7d3 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -35,6 +35,7 @@ extern const char wol_mode_names[][ETH_GSTRING_LEN]; extern const char sof_timestamping_names[][ETH_GSTRING_LEN]; extern const char ts_tx_type_names[][ETH_GSTRING_LEN]; extern const char ts_rx_filter_names[][ETH_GSTRING_LEN]; +extern const char ts_layer_names[][ETH_GSTRING_LEN]; extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN]; int __ethtool_get_link(struct net_device *dev); diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 3bbd5afb7b31..561c0931d055 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -306,6 +306,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, + [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -1128,6 +1129,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .policy = ethnl_mm_set_policy, .maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1, }, + { + .cmd = ETHTOOL_MSG_TS_GET, + .doit = ethnl_default_doit, + .start = ethnl_default_start, + .dumpit = ethnl_default_dumpit, + .done = ethnl_default_done, + .policy = ethnl_ts_get_policy, + .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, + }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 9a333a8d04c1..1e6085198acc 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -395,6 +395,7 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops; extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; extern const struct ethnl_request_ops ethnl_plca_status_request_ops; extern const struct ethnl_request_ops ethnl_mm_request_ops; +extern const struct ethnl_request_ops ethnl_ts_request_ops; extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; @@ -441,6 +442,7 @@ extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1] extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; +extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1]; int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c new file mode 100644 index 000000000000..066cb06f4d0b --- /dev/null +++ b/net/ethtool/ts.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include "netlink.h" +#include "common.h" +#include "bitset.h" + +struct ts_req_info { + struct ethnl_req_info base; +}; + +struct ts_reply_data { + struct ethnl_reply_data base; + enum timestamping_layer ts_layer; +}; + +#define TS_REPDATA(__reply_base) \ + container_of(__reply_base, struct ts_reply_data, base) + +/* TS_GET */ +const struct nla_policy ethnl_ts_get_policy[] = { + [ETHTOOL_A_TS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), +}; + +static int ts_prepare_data(const struct ethnl_req_info *req_base, + struct ethnl_reply_data *reply_base, + const struct genl_info *info) +{ + struct ts_reply_data *data = TS_REPDATA(reply_base); + struct net_device *dev = reply_base->dev; + const struct ethtool_ops *ops = dev->ethtool_ops; + int ret; + + ret = ethnl_ops_begin(dev); + if (ret < 0) + return ret; + + if (phy_has_tsinfo(dev->phydev)) { + data->ts_layer = PHY_TIMESTAMPING; + } else if (ops->get_ts_info) { + struct ethtool_ts_info ts_info = {0}; + + ops->get_ts_info(dev, &ts_info); + if (ts_info.so_timestamping & + SOF_TIMESTAMPING_HARDWARE_MASK) + data->ts_layer = MAC_TIMESTAMPING; + + if (ts_info.so_timestamping & + SOF_TIMESTAMPING_SOFTWARE_MASK) + data->ts_layer = SOFTWARE_TIMESTAMPING; + } else { + data->ts_layer = NO_TIMESTAMPING; + } + + ethnl_ops_complete(dev); + + return ret; +} + +static int ts_reply_size(const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + return nla_total_size(sizeof(u32)); +} + +static int ts_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + struct ts_reply_data *data = TS_REPDATA(reply_base); + + return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer); +} + +const struct ethnl_request_ops ethnl_ts_request_ops = { + .request_cmd = ETHTOOL_MSG_TS_GET, + .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY, + .hdr_attr = ETHTOOL_A_TS_HEADER, + .req_info_size = sizeof(struct ts_req_info), + .reply_data_size = sizeof(struct ts_reply_data), + + .prepare_data = ts_prepare_data, + .reply_size = ts_reply_size, + .fill_reply = ts_fill_reply, +}; From bb8645b00ced1db036adf9ad7d9baaf1890aa2e6 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:37 +0100 Subject: [PATCH 0875/7721] netlink: specs: Introduce new netlink command to get current timestamp Add a new commands allowing to get the current time stamping on a netdevice's link. Example usage : ./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema --do ts-get \ --json '{"header":{"dev-name":"eth0"}}' {'header': {'dev-index': 3, 'dev-name': 'eth0'}, 'ts-layer': 1} Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 5c7a65b009b4..61b30701fdad 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -939,6 +939,16 @@ attribute-sets: - name: burst-tmr type: u32 + - + name: ts + attributes: + - + name: header + type: nest + nested-attributes: header + - + name: ts-layer + type: u32 operations: enum-model: directional @@ -1689,3 +1699,17 @@ operations: name: mm-ntf doc: Notification for change in MAC Merge configuration. notify: mm-get + - + name: ts-get + doc: Get current timestamp + + attribute-set: ts + + do: + request: + attributes: + - header + reply: + attributes: &ts + - header + - ts-layer From d905f9c753295ee5a30af265f4b724f10050e7d3 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:38 +0100 Subject: [PATCH 0876/7721] net: ethtool: Add a command to list available time stamping layers Introduce a new netlink message that lists all available time stamping layers on a given interface. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/networking/ethtool-netlink.rst | 23 ++++++ include/uapi/linux/ethtool_netlink.h | 14 ++++ net/ethtool/netlink.c | 10 +++ net/ethtool/netlink.h | 1 + net/ethtool/ts.c | 73 ++++++++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 644b3b764044..b8d00676ed82 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -226,6 +226,7 @@ Userspace to kernel: ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters ``ETHTOOL_MSG_TS_GET`` get current timestamping + ``ETHTOOL_MSG_TS_LIST_GET`` list available timestampings ===================================== ================================= Kernel to userspace: @@ -270,6 +271,7 @@ Kernel to userspace: ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status ``ETHTOOL_MSG_TS_GET_REPLY`` current timestamping + ``ETHTOOL_MSG_TS_LIST_GET_REPLY`` available timestampings ======================================== ================================= ``GET`` requests are sent by userspace applications to retrieve device @@ -2016,6 +2018,26 @@ Kernel response contents: This command get the current timestamp layer. +TS_LIST_GET +=========== + +Get the list of available timestampings. + +Request contents: + + ================================= ====== ==================== + ``ETHTOOL_A_TS_HEADER`` nested request header + ================================= ====== ==================== + +Kernel response contents: + + =========================== ====== ============================== + ``ETHTOOL_A_TS_HEADER`` nested reply header + ``ETHTOOL_A_TS_LIST_LAYER`` binary available timestampings + =========================== ====== ============================== + +This command lists all the possible timestamp layer available. + Request translation =================== @@ -2123,4 +2145,5 @@ are netlink only. n/a ``ETHTOOL_MSG_MM_GET`` n/a ``ETHTOOL_MSG_MM_SET`` n/a ``ETHTOOL_MSG_TS_GET`` + n/a ``ETHTOOL_MSG_TS_LIST_GET`` =================================== ===================================== diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index cb51136328cf..62b885d44d06 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -58,6 +58,7 @@ enum { ETHTOOL_MSG_MM_GET, ETHTOOL_MSG_MM_SET, ETHTOOL_MSG_TS_GET, + ETHTOOL_MSG_TS_LIST_GET, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, @@ -111,6 +112,7 @@ enum { ETHTOOL_MSG_MM_GET_REPLY, ETHTOOL_MSG_MM_NTF, ETHTOOL_MSG_TS_GET_REPLY, + ETHTOOL_MSG_TS_LIST_GET_REPLY, /* add new constants above here */ __ETHTOOL_MSG_KERNEL_CNT, @@ -989,6 +991,18 @@ enum { ETHTOOL_A_TS_MAX = (__ETHTOOL_A_TS_CNT - 1) }; +/* TS LIST LAYER */ + +enum { + ETHTOOL_A_TS_LIST_UNSPEC, + ETHTOOL_A_TS_LIST_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_TS_LIST_LAYER, /* array, u32 */ + + /* add new constants above here */ + __ETHTOOL_A_TS_LIST_CNT, + ETHTOOL_A_TS_LIST_MAX = (__ETHTOOL_A_TS_LIST_CNT - 1) +}; + /* generic netlink info */ #define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_VERSION 1 diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 561c0931d055..842c9db1531f 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -307,6 +307,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, + [ETHTOOL_MSG_TS_LIST_GET] = ðnl_ts_list_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -1138,6 +1139,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .policy = ethnl_ts_get_policy, .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, }, + { + .cmd = ETHTOOL_MSG_TS_LIST_GET, + .doit = ethnl_default_doit, + .start = ethnl_default_start, + .dumpit = ethnl_default_dumpit, + .done = ethnl_default_done, + .policy = ethnl_ts_get_policy, + .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, + }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 1e6085198acc..ea8c312db3af 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -396,6 +396,7 @@ extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; extern const struct ethnl_request_ops ethnl_plca_status_request_ops; extern const struct ethnl_request_ops ethnl_mm_request_ops; extern const struct ethnl_request_ops ethnl_ts_request_ops; +extern const struct ethnl_request_ops ethnl_ts_list_request_ops; extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c index 066cb06f4d0b..f2dd65a2e69c 100644 --- a/net/ethtool/ts.c +++ b/net/ethtool/ts.c @@ -86,3 +86,76 @@ const struct ethnl_request_ops ethnl_ts_request_ops = { .reply_size = ts_reply_size, .fill_reply = ts_fill_reply, }; + +/* TS_LIST_GET */ +struct ts_list_reply_data { + struct ethnl_reply_data base; + enum timestamping_layer ts_layer[__TIMESTAMPING_COUNT]; + u8 num_ts; +}; + +#define TS_LIST_REPDATA(__reply_base) \ + container_of(__reply_base, struct ts_list_reply_data, base) + +static int ts_list_prepare_data(const struct ethnl_req_info *req_base, + struct ethnl_reply_data *reply_base, + const struct genl_info *info) +{ + struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); + struct net_device *dev = reply_base->dev; + const struct ethtool_ops *ops = dev->ethtool_ops; + int ret, i = 0; + + ret = ethnl_ops_begin(dev); + if (ret < 0) + return ret; + + if (phy_has_tsinfo(dev->phydev)) + data->ts_layer[i++] = PHY_TIMESTAMPING; + if (ops->get_ts_info) { + struct ethtool_ts_info ts_info = {0}; + + ops->get_ts_info(dev, &ts_info); + if (ts_info.so_timestamping & + SOF_TIMESTAMPING_HARDWARE_MASK) + data->ts_layer[i++] = MAC_TIMESTAMPING; + + if (ts_info.so_timestamping & + SOF_TIMESTAMPING_SOFTWARE_MASK) + data->ts_layer[i++] = SOFTWARE_TIMESTAMPING; + } + + data->num_ts = i; + ethnl_ops_complete(dev); + + return ret; +} + +static int ts_list_reply_size(const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); + + return nla_total_size(sizeof(u32)) * data->num_ts; +} + +static int ts_list_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); + + return nla_put(skb, ETHTOOL_A_TS_LIST_LAYER, sizeof(u32) * data->num_ts, data->ts_layer); +} + +const struct ethnl_request_ops ethnl_ts_list_request_ops = { + .request_cmd = ETHTOOL_MSG_TS_LIST_GET, + .reply_cmd = ETHTOOL_MSG_TS_LIST_GET_REPLY, + .hdr_attr = ETHTOOL_A_TS_HEADER, + .req_info_size = sizeof(struct ts_req_info), + .reply_data_size = sizeof(struct ts_list_reply_data), + + .prepare_data = ts_list_prepare_data, + .reply_size = ts_list_reply_size, + .fill_reply = ts_list_fill_reply, +}; From aed5004ee7a0e6f198a6b26fb6a1aa21588a9539 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:39 +0100 Subject: [PATCH 0877/7721] netlink: specs: Introduce new netlink command to list available time stamping layers Add a new commands allowing to list available time stamping layers on a netdevice's link. Example usage : ./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema \ --do ts-list-get \ --json '{"header":{"dev-name":"eth0"}}' {'header': {'dev-index': 3, 'dev-name': 'eth0'}, 'ts-list-layer': b'\x01\x00\x00\x00\x05\x00\x00\x00'} Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 61b30701fdad..591425f7fa76 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -949,6 +949,16 @@ attribute-sets: - name: ts-layer type: u32 + - + name: ts-list + attributes: + - + name: header + type: nest + nested-attributes: header + - + name: ts-list-layer + type: binary operations: enum-model: directional @@ -1713,3 +1723,17 @@ operations: attributes: &ts - header - ts-layer + - + name: ts-list-get + doc: Get list of timestamp devices available on an interface + + attribute-set: ts-list + + do: + request: + attributes: + - header + reply: + attributes: + - header + - ts-list-layer From 51bdf3165f012827644c474a6d905baa3de3f1ea Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:40 +0100 Subject: [PATCH 0878/7721] net: Replace hwtstamp_source by timestamping layer Replace hwtstamp_source which is only used by the kernel_hwtstamp_config structure by the more widely use timestamp_layer structure. This is done to prepare the support of selectable timestamping source. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 6 +++--- include/linux/net_tstamp.h | 11 +++-------- net/core/dev_ioctl.c | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 2635ef8958c8..fbe56b1bb386 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -470,15 +470,15 @@ static int lan966x_port_hwtstamp_set(struct net_device *dev, struct lan966x_port *port = netdev_priv(dev); int err; - if (cfg->source != HWTSTAMP_SOURCE_NETDEV && - cfg->source != HWTSTAMP_SOURCE_PHYLIB) + if (cfg->source != MAC_TIMESTAMPING && + cfg->source != PHY_TIMESTAMPING) return -EOPNOTSUPP; err = lan966x_ptp_setup_traps(port, cfg); if (err) return err; - if (cfg->source == HWTSTAMP_SOURCE_NETDEV) { + if (cfg->source == MAC_TIMESTAMPING) { if (!port->lan966x->ptp) return -EOPNOTSUPP; diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h index eb01c37e71e0..bb289c2ad376 100644 --- a/include/linux/net_tstamp.h +++ b/include/linux/net_tstamp.h @@ -5,11 +5,6 @@ #include -enum hwtstamp_source { - HWTSTAMP_SOURCE_NETDEV, - HWTSTAMP_SOURCE_PHYLIB, -}; - /** * struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config * @@ -20,8 +15,8 @@ enum hwtstamp_source { * a legacy implementation of a lower driver * @copied_to_user: request was passed to a legacy implementation which already * copied the ioctl request back to user space - * @source: indication whether timestamps should come from the netdev or from - * an attached phylib PHY + * @source: indication whether timestamps should come from software, the netdev + * or from an attached phylib PHY * * Prefer using this structure for in-kernel processing of hardware * timestamping configuration, over the inextensible struct hwtstamp_config @@ -33,7 +28,7 @@ struct kernel_hwtstamp_config { int rx_filter; struct ifreq *ifr; bool copied_to_user; - enum hwtstamp_source source; + enum timestamping_layer source; }; static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg, diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 9a66cf5015f2..267cd00269d0 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -332,7 +332,7 @@ int dev_set_hwtstamp_phylib(struct net_device *dev, bool changed = false; int err; - cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV; + cfg->source = phy_ts ? PHY_TIMESTAMPING : MAC_TIMESTAMPING; if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { err = ops->ndo_hwtstamp_get(dev, &old_cfg); From 0f7f463d4821a4f52fa5c0a961389e651d50c384 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:41 +0100 Subject: [PATCH 0879/7721] net: Change the API of PHY default timestamp to MAC Change the API to select MAC default time stamping instead of the PHY. Indeed the PHY is closer to the wire therefore theoretically it has less delay than the MAC timestamping but the reality is different. Due to lower time stamping clock frequency, latency in the MDIO bus and no PHC hardware synchronization between different PHY, the PHY PTP is often less precise than the MAC. The exception is for PHY designed specially for PTP case but these devices are not very widespread. For not breaking the compatibility I introduce a default_timestamp flag in phy_device that is set by the phy driver to know we are using the old API behavior. The phy_set_timestamp function is called at each call of phy_attach_direct. In case of MAC driver using phylink this function is called when the interface is turned up. Then if the interface goes down and up again the last choice of timestamp will be overwritten by the default choice. A solution could be to cache the timestamp status but it can bring other issues. In case of SFP, if we change the module, it doesn't make sense to blindly re-set the timestamp back to PHY, if the new module has a PHY with mediocre timestamping capabilities. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-ptp.c | 3 +++ drivers/net/phy/dp83640.c | 3 +++ drivers/net/phy/micrel.c | 6 +++++ drivers/net/phy/mscc/mscc_ptp.c | 2 ++ drivers/net/phy/nxp-c45-tja11xx.c | 3 +++ drivers/net/phy/phy_device.c | 37 ++++++++++++++++++++++++++++++ include/linux/netdevice.h | 5 ++++ include/linux/phy.h | 4 ++++ net/core/dev.c | 3 +++ net/core/dev_ioctl.c | 38 +++++++++++++++++++------------ net/core/timestamping.c | 10 ++++++++ net/ethtool/common.c | 19 ++++++++++++++-- 12 files changed, 116 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c index 617d384d4551..d3e825c951ee 100644 --- a/drivers/net/phy/bcm-phy-ptp.c +++ b/drivers/net/phy/bcm-phy-ptp.c @@ -931,6 +931,9 @@ struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev) return ERR_CAST(clock); priv->ptp_clock = clock; + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; + priv->phydev = phydev; bcm_ptp_init(priv); diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 5c42c47dc564..64fd1a109c0f 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1450,6 +1450,9 @@ static int dp83640_probe(struct phy_device *phydev) phydev->mii_ts = &dp83640->mii_ts; phydev->priv = dp83640; + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; + spin_lock_init(&dp83640->rx_lock); skb_queue_head_init(&dp83640->rx_queue); skb_queue_head_init(&dp83640->tx_queue); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index bd4cd082662f..2b8dd0131926 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -3158,6 +3158,9 @@ static void lan8814_ptp_init(struct phy_device *phydev) ptp_priv->mii_ts.ts_info = lan8814_ts_info; phydev->mii_ts = &ptp_priv->mii_ts; + + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; } static int lan8814_ptp_probe_once(struct phy_device *phydev) @@ -4586,6 +4589,9 @@ static int lan8841_probe(struct phy_device *phydev) phydev->mii_ts = &ptp_priv->mii_ts; + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; + return 0; } diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index eb0b032cb613..fd174eb06d4a 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -1570,6 +1570,8 @@ int vsc8584_ptp_probe(struct phy_device *phydev) return PTR_ERR(vsc8531->load_save); } + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; vsc8531->ptp->phydev = phydev; return 0; diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 780ad353cf55..0515c7b979db 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -1658,6 +1658,9 @@ static int nxp_c45_probe(struct phy_device *phydev) priv->mii_ts.ts_info = nxp_c45_ts_info; phydev->mii_ts = &priv->mii_ts; ret = nxp_c45_init_ptp_clock(priv); + + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; } else { phydev_dbg(phydev, "PTP support not enabled even if the phy supports it"); } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2ce74593d6e4..8c4794631daa 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1411,6 +1411,26 @@ int phy_sfp_probe(struct phy_device *phydev, } EXPORT_SYMBOL(phy_sfp_probe); +/** + * phy_set_timestamp - set the default selected timestamping device + * @dev: Pointer to net_device + * @phydev: Pointer to phy_device + * + * This is used to set default timestamping device taking into account + * the new API choice, which is selecting the timestamping from MAC by + * default if the phydev does not have default_timestamp flag enabled. + */ +static void phy_set_timestamp(struct net_device *dev, struct phy_device *phydev) +{ + const struct ethtool_ops *ops = dev->ethtool_ops; + + if (!phy_has_tsinfo(phydev)) + return; + + if (!ops->get_ts_info || phydev->default_timestamp) + dev->ts_layer = PHY_TIMESTAMPING; +} + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1484,6 +1504,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->phy_link_change = phy_link_change; if (dev) { + phy_set_timestamp(dev, phydev); phydev->attached_dev = dev; dev->phydev = phydev; @@ -1812,6 +1833,22 @@ void phy_detach(struct phy_device *phydev) phy_suspend(phydev); if (dev) { + const struct ethtool_ops *ops = dev->ethtool_ops; + struct ethtool_ts_info ts_info = {0}; + + if (ops->get_ts_info) { + ops->get_ts_info(dev, &ts_info); + if ((ts_info.so_timestamping & + SOF_TIMESTAMPING_HARDWARE_MASK) == + SOF_TIMESTAMPING_HARDWARE_MASK) + dev->ts_layer = MAC_TIMESTAMPING; + else if ((ts_info.so_timestamping & + SOF_TIMESTAMPING_SOFTWARE_MASK) == + SOF_TIMESTAMPING_SOFTWARE_MASK) + dev->ts_layer = SOFTWARE_TIMESTAMPING; + } else { + dev->ts_layer = NO_TIMESTAMPING; + } phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2d840d7056f2..f020d2790c12 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -2074,6 +2075,8 @@ enum netdev_ml_priv_type { * * @dpll_pin: Pointer to the SyncE source pin of a DPLL subsystem, * where the clock is recovered. + * @ts_layer: Tracks which network device + * performs packet time stamping. * * FIXME: cleanup struct net_device such that network protocol info * moves out. @@ -2435,6 +2438,8 @@ struct net_device { #if IS_ENABLED(CONFIG_DPLL) struct dpll_pin *dpll_pin; #endif + + enum timestamping_layer ts_layer; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/include/linux/phy.h b/include/linux/phy.h index e5f1f41e399c..317def2a7843 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -604,6 +604,8 @@ struct macsec_ops; * handling shall be postponed until PHY has resumed * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended, * requiring a rerun of the interrupt handler after resume + * @default_timestamp: Flag indicating whether we are using the phy + * timestamp as the default one * @interface: enum phy_interface_t value * @skb: Netlink message for cable diagnostics * @nest: Netlink nest used for cable diagnostics @@ -667,6 +669,8 @@ struct phy_device { unsigned irq_suspended:1; unsigned irq_rerun:1; + unsigned default_timestamp:1; + int rate_matching; enum phy_state state; diff --git a/net/core/dev.c b/net/core/dev.c index af53f6d838ce..05ce00632892 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10212,6 +10212,9 @@ int register_netdevice(struct net_device *dev) dev->rtnl_link_state == RTNL_LINK_INITIALIZED) rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL, 0, NULL); + if (dev->ethtool_ops->get_ts_info) + dev->ts_layer = MAC_TIMESTAMPING; + out: return ret; diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 267cd00269d0..bc8be9749376 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -259,9 +259,7 @@ static int dev_eth_ioctl(struct net_device *dev, * @dev: Network device * @cfg: Timestamping configuration structure * - * Helper for enforcing a common policy that phylib timestamping, if available, - * should take precedence in front of hardware timestamping provided by the - * netdev. + * Helper for calling the selected hardware provider timestamping. * * Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and * there only exists a phydev->mii_ts->hwtstamp() method. So this will return @@ -271,10 +269,14 @@ static int dev_eth_ioctl(struct net_device *dev, static int dev_get_hwtstamp_phylib(struct net_device *dev, struct kernel_hwtstamp_config *cfg) { - if (phy_has_hwtstamp(dev->phydev)) - return phy_hwtstamp_get(dev->phydev, cfg); + enum timestamping_layer ts_layer = dev->ts_layer; - return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); + if (ts_layer == PHY_TIMESTAMPING) + return phy_hwtstamp_get(dev->phydev, cfg); + else if (ts_layer == MAC_TIMESTAMPING) + return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); + + return -EOPNOTSUPP; } static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) @@ -315,9 +317,8 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) * @cfg: Timestamping configuration structure * @extack: Netlink extended ack message structure, for error reporting * - * Helper for enforcing a common policy that phylib timestamping, if available, - * should take precedence in front of hardware timestamping provided by the - * netdev. If the netdev driver needs to perform specific actions even for PHY + * Helper for calling the selected hardware provider timestamping. + * If the netdev driver needs to perform specific actions even for PHY * timestamping to work properly (a switch port must trap the timestamped * frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in * dev->priv_flags. @@ -327,20 +328,26 @@ int dev_set_hwtstamp_phylib(struct net_device *dev, struct netlink_ext_ack *extack) { const struct net_device_ops *ops = dev->netdev_ops; - bool phy_ts = phy_has_hwtstamp(dev->phydev); + enum timestamping_layer ts_layer = dev->ts_layer; struct kernel_hwtstamp_config old_cfg = {}; bool changed = false; int err; - cfg->source = phy_ts ? PHY_TIMESTAMPING : MAC_TIMESTAMPING; + cfg->source = ts_layer; - if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { + if (ts_layer != PHY_TIMESTAMPING && + ts_layer != MAC_TIMESTAMPING) + return -EOPNOTSUPP; + + if (ts_layer == PHY_TIMESTAMPING && + dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) { err = ops->ndo_hwtstamp_get(dev, &old_cfg); if (err) return err; } - if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { + if (ts_layer == MAC_TIMESTAMPING || + dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) { err = ops->ndo_hwtstamp_set(dev, cfg, extack); if (err) { if (extack->_msg) @@ -349,10 +356,11 @@ int dev_set_hwtstamp_phylib(struct net_device *dev, } } - if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) + if (ts_layer == PHY_TIMESTAMPING && + dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) changed = kernel_hwtstamp_config_changed(&old_cfg, cfg); - if (phy_ts) { + if (ts_layer == PHY_TIMESTAMPING) { err = phy_hwtstamp_set(dev->phydev, cfg, extack); if (err) { if (changed) diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 04840697fe79..5cf51a523fb3 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -21,6 +21,7 @@ static unsigned int classify(const struct sk_buff *skb) void skb_clone_tx_timestamp(struct sk_buff *skb) { + enum timestamping_layer ts_layer; struct mii_timestamper *mii_ts; struct sk_buff *clone; unsigned int type; @@ -28,6 +29,10 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) if (!skb->sk) return; + ts_layer = skb->dev->ts_layer; + if (ts_layer != PHY_TIMESTAMPING) + return; + type = classify(skb); if (type == PTP_CLASS_NONE) return; @@ -44,12 +49,17 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); bool skb_defer_rx_timestamp(struct sk_buff *skb) { + enum timestamping_layer ts_layer; struct mii_timestamper *mii_ts; unsigned int type; if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->mii_ts) return false; + ts_layer = skb->dev->ts_layer; + if (ts_layer != PHY_TIMESTAMPING) + return false; + if (skb_headroom(skb) < ETH_HLEN) return false; diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 11d8797f63f6..9f6e3b2c74e2 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -633,13 +633,28 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { const struct ethtool_ops *ops = dev->ethtool_ops; struct phy_device *phydev = dev->phydev; + enum timestamping_layer ts_layer; + int ret; memset(info, 0, sizeof(*info)); info->cmd = ETHTOOL_GET_TS_INFO; - if (phy_has_tsinfo(phydev)) + ts_layer = dev->ts_layer; + if (ts_layer == SOFTWARE_TIMESTAMPING) { + ret = ops->get_ts_info(dev, info); + if (ret) + return ret; + info->so_timestamping &= ~SOF_TIMESTAMPING_HARDWARE_MASK; + info->phc_index = -1; + info->rx_filters = 0; + info->tx_types = 0; + return 0; + } + + if (ts_layer == PHY_TIMESTAMPING) return phy_ts_info(phydev, info); - if (ops->get_ts_info) + + if (ts_layer == MAC_TIMESTAMPING) return ops->get_ts_info(dev, info); info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | From 091fab122869a39e1bac2cc34df9b737a6f6f36d Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:42 +0100 Subject: [PATCH 0880/7721] net: ethtool: ts: Update GET_TS to reply the current selected timestamp As the default selected timestamp API change we have to change also the timestamp return by ethtool. This patch return now the current selected timestamp. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- net/ethtool/ts.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c index f2dd65a2e69c..bd219512b8de 100644 --- a/net/ethtool/ts.c +++ b/net/ethtool/ts.c @@ -31,29 +31,13 @@ static int ts_prepare_data(const struct ethnl_req_info *req_base, { struct ts_reply_data *data = TS_REPDATA(reply_base); struct net_device *dev = reply_base->dev; - const struct ethtool_ops *ops = dev->ethtool_ops; int ret; ret = ethnl_ops_begin(dev); if (ret < 0) return ret; - if (phy_has_tsinfo(dev->phydev)) { - data->ts_layer = PHY_TIMESTAMPING; - } else if (ops->get_ts_info) { - struct ethtool_ts_info ts_info = {0}; - - ops->get_ts_info(dev, &ts_info); - if (ts_info.so_timestamping & - SOF_TIMESTAMPING_HARDWARE_MASK) - data->ts_layer = MAC_TIMESTAMPING; - - if (ts_info.so_timestamping & - SOF_TIMESTAMPING_SOFTWARE_MASK) - data->ts_layer = SOFTWARE_TIMESTAMPING; - } else { - data->ts_layer = NO_TIMESTAMPING; - } + data->ts_layer = dev->ts_layer; ethnl_ops_complete(dev); From 152c75e1d00200edc4da1beb67dd099a462ea86b Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:43 +0100 Subject: [PATCH 0881/7721] net: ethtool: ts: Let the active time stamping layer be selectable Now that the current timestamp is saved in a variable lets add the ETHTOOL_MSG_TS_SET ethtool netlink socket to make it selectable. Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/networking/ethtool-netlink.rst | 17 ++++ include/uapi/linux/ethtool_netlink.h | 1 + net/ethtool/netlink.c | 8 ++ net/ethtool/netlink.h | 1 + net/ethtool/ts.c | 99 ++++++++++++++++++++ 5 files changed, 126 insertions(+) diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index b8d00676ed82..530c1775e5f4 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -227,6 +227,7 @@ Userspace to kernel: ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters ``ETHTOOL_MSG_TS_GET`` get current timestamping ``ETHTOOL_MSG_TS_LIST_GET`` list available timestampings + ``ETHTOOL_MSG_TS_SET`` set current timestamping ===================================== ================================= Kernel to userspace: @@ -2038,6 +2039,21 @@ Kernel response contents: This command lists all the possible timestamp layer available. +TS_SET +====== + +Modify the selected timestamping. + +Request contents: + + ======================= ====== =================== + ``ETHTOOL_A_TS_HEADER`` nested reply header + ``ETHTOOL_A_TS_LAYER`` u32 timestamping + ======================= ====== =================== + +This command set the timestamping with one that should be listed by the +TSLIST_GET command. + Request translation =================== @@ -2146,4 +2162,5 @@ are netlink only. n/a ``ETHTOOL_MSG_MM_SET`` n/a ``ETHTOOL_MSG_TS_GET`` n/a ``ETHTOOL_MSG_TS_LIST_GET`` + n/a ``ETHTOOL_MSG_TS_SET`` =================================== ===================================== diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 62b885d44d06..df6c4fcc62c1 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -59,6 +59,7 @@ enum { ETHTOOL_MSG_MM_SET, ETHTOOL_MSG_TS_GET, ETHTOOL_MSG_TS_LIST_GET, + ETHTOOL_MSG_TS_SET, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 842c9db1531f..8322bf71f80d 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -308,6 +308,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, [ETHTOOL_MSG_TS_LIST_GET] = ðnl_ts_list_request_ops, + [ETHTOOL_MSG_TS_SET] = ðnl_ts_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -1148,6 +1149,13 @@ static const struct genl_ops ethtool_genl_ops[] = { .policy = ethnl_ts_get_policy, .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, }, + { + .cmd = ETHTOOL_MSG_TS_SET, + .flags = GENL_UNS_ADMIN_PERM, + .doit = ethnl_default_set_doit, + .policy = ethnl_ts_set_policy, + .maxattr = ARRAY_SIZE(ethnl_ts_set_policy) - 1, + }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index ea8c312db3af..8fedf234b824 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -444,6 +444,7 @@ extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADE extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1]; +extern const struct nla_policy ethnl_ts_set_policy[ETHTOOL_A_TS_MAX + 1]; int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c index bd219512b8de..357265e74e08 100644 --- a/net/ethtool/ts.c +++ b/net/ethtool/ts.c @@ -59,6 +59,102 @@ static int ts_fill_reply(struct sk_buff *skb, return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer); } +/* TS_SET */ +const struct nla_policy ethnl_ts_set_policy[] = { + [ETHTOOL_A_TS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), + [ETHTOOL_A_TS_LAYER] = NLA_POLICY_RANGE(NLA_U32, 0, + __TIMESTAMPING_COUNT - 1) +}; + +static int ethnl_set_ts_validate(struct ethnl_req_info *req_info, + struct genl_info *info) +{ + struct nlattr **tb = info->attrs; + const struct net_device_ops *ops = req_info->dev->netdev_ops; + + if (!ops->ndo_hwtstamp_set) + return -EOPNOTSUPP; + + if (!tb[ETHTOOL_A_TS_LAYER]) + return 0; + + return 1; +} + +static int ethnl_set_ts(struct ethnl_req_info *req_info, struct genl_info *info) +{ + struct net_device *dev = req_info->dev; + const struct ethtool_ops *ops = dev->ethtool_ops; + struct kernel_hwtstamp_config config = {0}; + struct nlattr **tb = info->attrs; + enum timestamping_layer ts_layer; + bool mod = false; + int ret; + + ts_layer = dev->ts_layer; + ethnl_update_u32(&ts_layer, tb[ETHTOOL_A_TS_LAYER], &mod); + + if (!mod) + return 0; + + if (ts_layer == SOFTWARE_TIMESTAMPING) { + struct ethtool_ts_info ts_info = {0}; + + if (!ops->get_ts_info) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_TS_LAYER], + "this net device cannot support timestamping"); + return -EINVAL; + } + + ops->get_ts_info(dev, &ts_info); + if ((ts_info.so_timestamping & + SOF_TIMESTAMPING_SOFTWARE_MASK) != + SOF_TIMESTAMPING_SOFTWARE_MASK) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_TS_LAYER], + "this net device cannot support software timestamping"); + return -EINVAL; + } + } else if (ts_layer == MAC_TIMESTAMPING) { + struct ethtool_ts_info ts_info = {0}; + + if (!ops->get_ts_info) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_TS_LAYER], + "this net device cannot support timestamping"); + return -EINVAL; + } + + ops->get_ts_info(dev, &ts_info); + if ((ts_info.so_timestamping & + SOF_TIMESTAMPING_HARDWARE_MASK) != + SOF_TIMESTAMPING_HARDWARE_MASK) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_TS_LAYER], + "this net device cannot support hardware timestamping"); + return -EINVAL; + } + } else if (ts_layer == PHY_TIMESTAMPING && !phy_has_tsinfo(dev->phydev)) { + NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_TS_LAYER], + "this phy device cannot support timestamping"); + return -EINVAL; + } + + /* Disable time stamping in the current layer. */ + if (netif_device_present(dev) && + (dev->ts_layer == PHY_TIMESTAMPING || + dev->ts_layer == MAC_TIMESTAMPING)) { + ret = dev_set_hwtstamp_phylib(dev, &config, info->extack); + if (ret < 0) + return ret; + } + + dev->ts_layer = ts_layer; + + return 1; +} + const struct ethnl_request_ops ethnl_ts_request_ops = { .request_cmd = ETHTOOL_MSG_TS_GET, .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY, @@ -69,6 +165,9 @@ const struct ethnl_request_ops ethnl_ts_request_ops = { .prepare_data = ts_prepare_data, .reply_size = ts_reply_size, .fill_reply = ts_fill_reply, + + .set_validate = ethnl_set_ts_validate, + .set = ethnl_set_ts, }; /* TS_LIST_GET */ From ee60ea6be0d3a96e57edf07da923a9c0f27f37ce Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 14 Nov 2023 12:28:44 +0100 Subject: [PATCH 0882/7721] netlink: specs: Introduce time stamping set command Add a new commands allowing to set the time stamping. Example usage : ./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema \ --do ts-list-get \ --json '{"header":{"dev-name":"eth0"}}' {'header': {'dev-index': 3, 'dev-name': 'eth0'}, 'ts-list-layer': b'\x02\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00'} ./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema --do ts-set \ --json '{"header":{"dev-name":"eth0"}, "ts-layer":5}' none ./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema --do ts-get \ --json '{"header":{"dev-name":"eth0"}}' {'header': {'dev-index': 3, 'dev-name': 'eth0'}, 'ts-layer': 5} Signed-off-by: Kory Maincent Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 591425f7fa76..06d9120543d3 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -1737,3 +1737,12 @@ operations: attributes: - header - ts-list-layer + - + name: ts-set + doc: Set the timestamp device + + attribute-set: ts + + do: + request: + attributes: *ts From c797ce168930ce3d62a9b7fc4d7040963ee6a01e Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 14 Nov 2023 10:07:33 -0600 Subject: [PATCH 0883/7721] net/ncsi: Simplify Kconfig/dts control flow Background: 1. CONFIG_NCSI_OEM_CMD_KEEP_PHY If this is enabled, we send an extra OEM Intel command in the probe sequence immediately after discovering a channel (e.g. after "Clear Initial State"). 2. CONFIG_NCSI_OEM_CMD_GET_MAC If this is enabled, we send one of 3 OEM "Get MAC Address" commands from Broadcom, Mellanox (Nvidida), and Intel in the *configuration* sequence for a channel. 3. mellanox,multi-host (or mlx,multi-host) Introduced by this patch: https://lore.kernel.org/all/20200108234341.2590674-1-vijaykhemka@fb.com/ Which was actually originally from cosmo.chou@quantatw.com: https://github.com/facebook/openbmc-linux/commit/9f132a10ec48db84613519258cd8a317fb9c8f1b Cosmo claimed that the Nvidia ConnectX-4 and ConnectX-6 NIC's don't respond to Get Version ID, et. al in the probe sequence unless you send the Set MC Affinity command first. Problem Statement: We've been using a combination of #ifdef code blocks and IS_ENABLED() conditions to conditionally send these OEM commands. It makes adding any new code around these commands hard to understand. Solution: In this patch, I just want to remove the conditionally compiled blocks of code, and always use IS_ENABLED(...) to do dynamic control flow. I don't think the small amount of code this adds to non-users of the OEM Kconfigs is a big deal. Signed-off-by: Peter Delevoryas Signed-off-by: David S. Miller --- net/ncsi/ncsi-manage.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index d9da942ad53d..f3d7fe86fea1 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -689,8 +689,6 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, return 0; } -#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) - static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) { unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; @@ -716,10 +714,6 @@ static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) return ret; } -#endif - -#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) - /* NCSI OEM Command APIs */ static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) { @@ -856,8 +850,6 @@ static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id) return nch->handler(nca); } -#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ - /* Determine if a given channel from the channel_queue should be used for Tx */ static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc) @@ -1039,20 +1031,18 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) goto error; } - nd->state = ncsi_dev_state_config_oem_gma; + nd->state = IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + ? ncsi_dev_state_config_oem_gma + : ncsi_dev_state_config_clear_vids; break; case ncsi_dev_state_config_oem_gma: nd->state = ncsi_dev_state_config_clear_vids; - ret = -1; -#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) nca.type = NCSI_PKT_CMD_OEM; nca.package = np->id; nca.channel = nc->id; ndp->pending_req_num = 1; ret = ncsi_gma_handler(&nca, nc->version.mf_id); -#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ - if (ret < 0) schedule_work(&ndp->work); @@ -1404,7 +1394,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) schedule_work(&ndp->work); break; -#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) case ncsi_dev_state_probe_mlx_gma: ndp->pending_req_num = 1; @@ -1429,7 +1418,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) nd->state = ncsi_dev_state_probe_cis; break; -#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ case ncsi_dev_state_probe_cis: ndp->pending_req_num = NCSI_RESERVED_CHANNEL; @@ -1447,7 +1435,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) nd->state = ncsi_dev_state_probe_keep_phy; break; -#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) case ncsi_dev_state_probe_keep_phy: ndp->pending_req_num = 1; @@ -1460,7 +1447,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) nd->state = ncsi_dev_state_probe_gvi; break; -#endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ case ncsi_dev_state_probe_gvi: case ncsi_dev_state_probe_gc: case ncsi_dev_state_probe_gls: From 3084b58bfd0b9e4b5e034f31f31b42977db35f12 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 14 Nov 2023 10:07:34 -0600 Subject: [PATCH 0884/7721] net/ncsi: Fix netlink major/minor version numbers The netlink interface for major and minor version numbers doesn't actually return the major and minor version numbers. It reports a u32 that contains the (major, minor, update, alpha1) components as the major version number, and then alpha2 as the minor version number. For whatever reason, the u32 byte order was reversed (ntohl): maybe it was assumed that the encoded value was a single big-endian u32, and alpha2 was the minor version. The correct way to get the supported NC-SI version from the network controller is to parse the Get Version ID response as described in 8.4.44 of the NC-SI spec[1]. Get Version ID Response Packet Format Bits +--------+--------+--------+--------+ Bytes | 31..24 | 23..16 | 15..8 | 7..0 | +-------+--------+--------+--------+--------+ | 0..15 | NC-SI Header | +-------+--------+--------+--------+--------+ | 16..19| Response code | Reason code | +-------+--------+--------+--------+--------+ |20..23 | Major | Minor | Update | Alpha1 | +-------+--------+--------+--------+--------+ |24..27 | reserved | Alpha2 | +-------+--------+--------+--------+--------+ | .... other stuff .... | The major, minor, and update fields are all binary-coded decimal (BCD) encoded [2]. The spec provides examples below the Get Version ID response format in section 8.4.44.1, but for practical purposes, this is an example from a live network card: root@bmc:~# ncsi-util 0x15 NC-SI Command Response: cmd: GET_VERSION_ID(0x15) Response: COMMAND_COMPLETED(0x0000) Reason: NO_ERROR(0x0000) Payload length = 40 20: 0xf1 0xf1 0xf0 0x00 <<<<<<<<< (major, minor, update, alpha1) 24: 0x00 0x00 0x00 0x00 <<<<<<<<< (_, _, _, alpha2) 28: 0x6d 0x6c 0x78 0x30 32: 0x2e 0x31 0x00 0x00 36: 0x00 0x00 0x00 0x00 40: 0x16 0x1d 0x07 0xd2 44: 0x10 0x1d 0x15 0xb3 48: 0x00 0x17 0x15 0xb3 52: 0x00 0x00 0x81 0x19 This should be parsed as "1.1.0". "f" in the upper-nibble means to ignore it, contributing zero. If both nibbles are "f", I think the whole field is supposed to be ignored. Major and minor are "required", meaning they're not supposed to be "ff", but the update field is "optional" so I think it can be ff. I think the simplest thing to do is just set the major and minor to zero instead of juggling some conditional logic or something. bcd2bin() from "include/linux/bcd.h" seems to assume both nibbles are 0-9, so I've provided a custom BCD decoding function. Alpha1 and alpha2 are ISO/IEC 8859-1 encoded, which just means ASCII characters as far as I can tell, although the full encoding table for non-alphabetic characters is slightly different (I think). I imagine the alpha fields are just supposed to be alphabetic characters, but I haven't seen any network cards actually report a non-zero value for either. If people wrote software against this netlink behavior, and were parsing the major and minor versions themselves from the u32, then this would definitely break their code. [1] https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.0.0.pdf [2] https://en.wikipedia.org/wiki/Binary-coded_decimal [2] https://en.wikipedia.org/wiki/ISO/IEC_8859-1 Signed-off-by: Peter Delevoryas Fixes: 138635cc27c9 ("net/ncsi: NCSI response packet handler") Signed-off-by: David S. Miller --- net/ncsi/internal.h | 7 +++++-- net/ncsi/ncsi-netlink.c | 4 ++-- net/ncsi/ncsi-pkt.h | 7 +++++-- net/ncsi/ncsi-rsp.c | 26 ++++++++++++++++++++++++-- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 03757e76bb6b..374412ed780b 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -105,8 +105,11 @@ enum { struct ncsi_channel_version { - u32 version; /* Supported BCD encoded NCSI version */ - u32 alpha2; /* Supported BCD encoded NCSI version */ + u8 major; /* NCSI version major */ + u8 minor; /* NCSI version minor */ + u8 update; /* NCSI version update */ + char alpha1; /* NCSI version alpha1 */ + char alpha2; /* NCSI version alpha2 */ u8 fw_name[12]; /* Firmware name string */ u32 fw_version; /* Firmware version */ u16 pci_ids[4]; /* PCI identification */ diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c index a3a6753a1db7..2f872d064396 100644 --- a/net/ncsi/ncsi-netlink.c +++ b/net/ncsi/ncsi-netlink.c @@ -71,8 +71,8 @@ static int ncsi_write_channel_info(struct sk_buff *skb, if (nc == nc->package->preferred_channel) nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); - nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); - nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); + nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.major); + nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.minor); nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h index ba66c7dc3a21..c9d1da34dc4d 100644 --- a/net/ncsi/ncsi-pkt.h +++ b/net/ncsi/ncsi-pkt.h @@ -197,9 +197,12 @@ struct ncsi_rsp_gls_pkt { /* Get Version ID */ struct ncsi_rsp_gvi_pkt { struct ncsi_rsp_pkt_hdr rsp; /* Response header */ - __be32 ncsi_version; /* NCSI version */ + unsigned char major; /* NCSI version major */ + unsigned char minor; /* NCSI version minor */ + unsigned char update; /* NCSI version update */ + unsigned char alpha1; /* NCSI version alpha1 */ unsigned char reserved[3]; /* Reserved */ - unsigned char alpha2; /* NCSI version */ + unsigned char alpha2; /* NCSI version alpha2 */ unsigned char fw_name[12]; /* f/w name string */ __be32 fw_version; /* f/w version */ __be16 pci_ids[4]; /* PCI IDs */ diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 069c2659074b..480e80e3c283 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -19,6 +19,19 @@ #include "ncsi-pkt.h" #include "ncsi-netlink.h" +/* Nibbles within [0xA, 0xF] add zero "0" to the returned value. + * Optional fields (encoded as 0xFF) will default to zero. + */ +static u8 decode_bcd_u8(u8 x) +{ + int lo = x & 0xF; + int hi = x >> 4; + + lo = lo < 0xA ? lo : 0; + hi = hi < 0xA ? hi : 0; + return lo + hi * 10; +} + static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, unsigned short payload) { @@ -755,9 +768,18 @@ static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) if (!nc) return -ENODEV; - /* Update to channel's version info */ + /* Update channel's version info + * + * Major, minor, and update fields are supposed to be + * unsigned integers encoded as packed BCD. + * + * Alpha1 and alpha2 are ISO/IEC 8859-1 characters. + */ ncv = &nc->version; - ncv->version = ntohl(rsp->ncsi_version); + ncv->major = decode_bcd_u8(rsp->major); + ncv->minor = decode_bcd_u8(rsp->minor); + ncv->update = decode_bcd_u8(rsp->update); + ncv->alpha1 = rsp->alpha1; ncv->alpha2 = rsp->alpha2; memcpy(ncv->fw_name, rsp->fw_name, 12); ncv->fw_version = ntohl(rsp->fw_version); From b8291cf3d1180b5b61299922f17c9441616a805a Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 14 Nov 2023 10:07:35 -0600 Subject: [PATCH 0885/7721] net/ncsi: Add NC-SI 1.2 Get MC MAC Address command This change adds support for the NC-SI 1.2 Get MC MAC Address command, specified here: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.2.0.pdf It serves the exact same function as the existing OEM Get MAC Address commands, so if a channel reports that it supports NC-SI 1.2, we prefer to use the standard command rather than the OEM command. Verified with an invalid MAC address and 2 valid ones: [ 55.137072] ftgmac100 1e690000.ftgmac eth0: NCSI: Received 3 provisioned MAC addresses [ 55.137614] ftgmac100 1e690000.ftgmac eth0: NCSI: MAC address 0: 00:00:00:00:00:00 [ 55.138026] ftgmac100 1e690000.ftgmac eth0: NCSI: MAC address 1: fa:ce:b0:0c:20:22 [ 55.138528] ftgmac100 1e690000.ftgmac eth0: NCSI: MAC address 2: fa:ce:b0:0c:20:23 [ 55.139241] ftgmac100 1e690000.ftgmac eth0: NCSI: Unable to assign 00:00:00:00:00:00 to device [ 55.140098] ftgmac100 1e690000.ftgmac eth0: NCSI: Set MAC address to fa:ce:b0:0c:20:22 Signed-off-by: Peter Delevoryas Signed-off-by: Patrick Williams Signed-off-by: David S. Miller --- net/ncsi/ncsi-cmd.c | 3 ++- net/ncsi/ncsi-manage.c | 9 +++++++-- net/ncsi/ncsi-pkt.h | 10 ++++++++++ net/ncsi/ncsi-rsp.c | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c index fd2236ee9a79..b3ff37a181d7 100644 --- a/net/ncsi/ncsi-cmd.c +++ b/net/ncsi/ncsi-cmd.c @@ -270,7 +270,8 @@ static struct ncsi_cmd_handler { { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default }, { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem }, { NCSI_PKT_CMD_PLDM, 0, NULL }, - { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default } + { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }, + { NCSI_PKT_CMD_GMCMA, 0, ncsi_cmd_handler_default } }; static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca) diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index f3d7fe86fea1..745c788f1d1d 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -1038,11 +1038,16 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) case ncsi_dev_state_config_oem_gma: nd->state = ncsi_dev_state_config_clear_vids; - nca.type = NCSI_PKT_CMD_OEM; nca.package = np->id; nca.channel = nc->id; ndp->pending_req_num = 1; - ret = ncsi_gma_handler(&nca, nc->version.mf_id); + if (nc->version.major >= 1 && nc->version.minor >= 2) { + nca.type = NCSI_PKT_CMD_GMCMA; + ret = ncsi_xmit_cmd(&nca); + } else { + nca.type = NCSI_PKT_CMD_OEM; + ret = ncsi_gma_handler(&nca, nc->version.mf_id); + } if (ret < 0) schedule_work(&ndp->work); diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h index c9d1da34dc4d..f2f3b5c1b941 100644 --- a/net/ncsi/ncsi-pkt.h +++ b/net/ncsi/ncsi-pkt.h @@ -338,6 +338,14 @@ struct ncsi_rsp_gpuuid_pkt { __be32 checksum; }; +/* Get MC MAC Address */ +struct ncsi_rsp_gmcma_pkt { + struct ncsi_rsp_pkt_hdr rsp; + unsigned char address_count; + unsigned char reserved[3]; + unsigned char addresses[][ETH_ALEN]; +}; + /* AEN: Link State Change */ struct ncsi_aen_lsc_pkt { struct ncsi_aen_pkt_hdr aen; /* AEN header */ @@ -398,6 +406,7 @@ struct ncsi_aen_hncdsc_pkt { #define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */ #define NCSI_PKT_CMD_QPNPR 0x56 /* Query Pending NC PLDM request */ #define NCSI_PKT_CMD_SNPR 0x57 /* Send NC PLDM Reply */ +#define NCSI_PKT_CMD_GMCMA 0x58 /* Get MC MAC Address */ /* NCSI packet responses */ @@ -433,6 +442,7 @@ struct ncsi_aen_hncdsc_pkt { #define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80) #define NCSI_PKT_RSP_QPNPR (NCSI_PKT_CMD_QPNPR + 0x80) #define NCSI_PKT_RSP_SNPR (NCSI_PKT_CMD_SNPR + 0x80) +#define NCSI_PKT_RSP_GMCMA (NCSI_PKT_CMD_GMCMA + 0x80) /* NCSI response code/reason */ #define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */ diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 480e80e3c283..bee290d0f48b 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -1091,6 +1091,44 @@ static int ncsi_rsp_handler_netlink(struct ncsi_request *nr) return ret; } +static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr) +{ + struct ncsi_dev_priv *ndp = nr->ndp; + struct net_device *ndev = ndp->ndev.dev; + struct ncsi_rsp_gmcma_pkt *rsp; + struct sockaddr saddr; + int ret = -1; + int i; + + rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp); + saddr.sa_family = ndev->type; + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + + netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n", + rsp->address_count); + for (i = 0; i < rsp->address_count; i++) { + netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n", + i, rsp->addresses[i][0], rsp->addresses[i][1], + rsp->addresses[i][2], rsp->addresses[i][3], + rsp->addresses[i][4], rsp->addresses[i][5]); + } + + for (i = 0; i < rsp->address_count; i++) { + memcpy(saddr.sa_data, &rsp->addresses[i], ETH_ALEN); + ret = ndev->netdev_ops->ndo_set_mac_address(ndev, &saddr); + if (ret < 0) { + netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n", + saddr.sa_data); + continue; + } + netdev_warn(ndev, "NCSI: Set MAC address to %pM\n", saddr.sa_data); + break; + } + + ndp->gma_flag = ret == 0; + return ret; +} + static struct ncsi_rsp_handler { unsigned char type; int payload; @@ -1127,7 +1165,8 @@ static struct ncsi_rsp_handler { { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm }, { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }, { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm }, - { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm } + { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm }, + { NCSI_PKT_RSP_GMCMA, -1, ncsi_rsp_handler_gmcma }, }; int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, From 526dd6d7877b80b1f56d87156b65b8227c69d59f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:10 +0100 Subject: [PATCH 0886/7721] devlink: Move private netlink flags to C file The flags are not used outside of the C file so move them there. Suggested-by: Jiri Pirko Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/devlink/devl_internal.h | 3 --- net/devlink/netlink.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 183dbe3807ab..2a9b263300a4 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -111,9 +111,6 @@ int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink, bool *msg_updated); /* Netlink */ -#define DEVLINK_NL_FLAG_NEED_PORT BIT(0) -#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) - enum devlink_multicast_groups { DEVLINK_MCGRP_CONFIG, }; diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index d0b90ebc8b15..7350138c8bb4 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -9,6 +9,9 @@ #include "devl_internal.h" +#define DEVLINK_NL_FLAG_NEED_PORT BIT(0) +#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) + static const struct genl_multicast_group devlink_nl_mcgrps[] = { [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, }; From e21c52d7814f5768f05224e773644629fe124af2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:11 +0100 Subject: [PATCH 0887/7721] devlink: Acquire device lock during netns dismantle Device drivers register with devlink from their probe routines (under the device lock) by acquiring the devlink instance lock and calling devl_register(). Drivers that support a devlink reload usually implement the reload_{down, up}() operations in a similar fashion to their remove and probe routines, respectively. However, while the remove and probe routines are invoked with the device lock held, the reload operations are only invoked with the devlink instance lock held. It is therefore impossible for drivers to acquire the device lock from their reload operations, as this would result in lock inversion. The motivating use case for invoking the reload operations with the device lock held is in mlxsw which needs to trigger a PCI reset as part of the reload. The driver cannot call pci_reset_function() as this function acquires the device lock. Instead, it needs to call __pci_reset_function_locked which expects the device lock to be held. To that end, adjust devlink to always acquire the device lock before the devlink instance lock when performing a reload. For now, only do that when reload is triggered as part of netns dismantle. Subsequent patches will handle the case where reload is explicitly triggered by user space. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/devlink/core.c | 4 ++-- net/devlink/devl_internal.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/devlink/core.c b/net/devlink/core.c index 6984877e9f10..4275a2bc6d8e 100644 --- a/net/devlink/core.c +++ b/net/devlink/core.c @@ -503,14 +503,14 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net) * all devlink instances from this namespace into init_net. */ devlinks_xa_for_each_registered_get(net, index, devlink) { - devl_lock(devlink); + devl_dev_lock(devlink, true); err = 0; if (devl_is_registered(devlink)) err = devlink_reload(devlink, &init_net, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, DEVLINK_RELOAD_LIMIT_UNSPEC, &actions_performed, NULL); - devl_unlock(devlink); + devl_dev_unlock(devlink, true); devlink_put(devlink); if (err && err != -EOPNOTSUPP) pr_warn("Failed to reload devlink instance into init_net\n"); diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 2a9b263300a4..178abaf74a10 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -3,6 +3,7 @@ * Copyright (c) 2016 Jiri Pirko */ +#include #include #include #include @@ -96,6 +97,20 @@ static inline bool devl_is_registered(struct devlink *devlink) return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); } +static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock) +{ + if (dev_lock) + device_lock(devlink->dev); + devl_lock(devlink); +} + +static inline void devl_dev_unlock(struct devlink *devlink, bool dev_lock) +{ + devl_unlock(devlink); + if (dev_lock) + device_unlock(devlink->dev); +} + typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index); typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index, u32 rel_index); From c8d0a7d6152bec970552786b77626f4b4c562f4d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:12 +0100 Subject: [PATCH 0888/7721] devlink: Enable the use of private flags in post_doit operations Currently, private flags (e.g., 'DEVLINK_NL_FLAG_NEED_PORT') are only used in pre_doit operations, but a subsequent patch will need to conditionally lock and unlock the device lock in pre and post doit operations, respectively. As a preparation, enable the use of private flags in post_doit operations in a similar fashion to how it is done for pre_doit operations. No functional changes intended. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/devlink/netlink.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index 7350138c8bb4..5bb6624f3288 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -141,8 +141,8 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT); } -void devlink_nl_post_doit(const struct genl_split_ops *ops, - struct sk_buff *skb, struct genl_info *info) +static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info, + u8 flags) { struct devlink *devlink; @@ -151,6 +151,12 @@ void devlink_nl_post_doit(const struct genl_split_ops *ops, devlink_put(devlink); } +void devlink_nl_post_doit(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info) +{ + __devlink_nl_post_doit(skb, info, 0); +} + static int devlink_nl_inst_single_dumpit(struct sk_buff *msg, struct netlink_callback *cb, int flags, devlink_nl_dump_one_func_t *dump_one, From d32c38256db30a2d55b849e2c77342bc70d58c6e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:13 +0100 Subject: [PATCH 0889/7721] devlink: Allow taking device lock in pre_doit operations Introduce a new private flag ('DEVLINK_NL_FLAG_NEED_DEV_LOCK') to allow netlink commands to specify that they need to acquire the device lock in their pre_doit operation and release it in their post_doit operation. The reload command will use this flag in the subsequent patch. No functional changes intended. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/devlink/devl_internal.h | 3 ++- net/devlink/health.c | 3 ++- net/devlink/netlink.c | 19 ++++++++++++------- net/devlink/region.c | 3 ++- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 178abaf74a10..5ea2e2012e93 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -152,7 +152,8 @@ typedef int devlink_nl_dump_one_func_t(struct sk_buff *msg, int flags); struct devlink * -devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs); +devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, + bool dev_lock); int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, devlink_nl_dump_one_func_t *dump_one); diff --git a/net/devlink/health.c b/net/devlink/health.c index 695df61f8ac2..71ae121dc739 100644 --- a/net/devlink/health.c +++ b/net/devlink/health.c @@ -1151,7 +1151,8 @@ devlink_health_reporter_get_from_cb_lock(struct netlink_callback *cb) struct nlattr **attrs = info->attrs; struct devlink *devlink; - devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs); + devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs, + false); if (IS_ERR(devlink)) return NULL; diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index 5bb6624f3288..86f12531bf99 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -11,6 +11,7 @@ #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) +#define DEVLINK_NL_FLAG_NEED_DEV_LOCK BIT(2) static const struct genl_multicast_group devlink_nl_mcgrps[] = { [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, @@ -64,7 +65,8 @@ int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info) } struct devlink * -devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs) +devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, + bool dev_lock) { struct devlink *devlink; unsigned long index; @@ -78,12 +80,12 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs) devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); devlinks_xa_for_each_registered_get(net, index, devlink) { - devl_lock(devlink); + devl_dev_lock(devlink, dev_lock); if (devl_is_registered(devlink) && strcmp(devlink->dev->bus->name, busname) == 0 && strcmp(dev_name(devlink->dev), devname) == 0) return devlink; - devl_unlock(devlink); + devl_dev_unlock(devlink, dev_lock); devlink_put(devlink); } @@ -93,11 +95,13 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs) static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info, u8 flags) { + bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; struct devlink_port *devlink_port; struct devlink *devlink; int err; - devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs); + devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs, + dev_lock); if (IS_ERR(devlink)) return PTR_ERR(devlink); @@ -117,7 +121,7 @@ static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info, return 0; unlock: - devl_unlock(devlink); + devl_dev_unlock(devlink, dev_lock); devlink_put(devlink); return err; } @@ -144,10 +148,11 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info, u8 flags) { + bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; struct devlink *devlink; devlink = info->user_ptr[0]; - devl_unlock(devlink); + devl_dev_unlock(devlink, dev_lock); devlink_put(devlink); } @@ -165,7 +170,7 @@ static int devlink_nl_inst_single_dumpit(struct sk_buff *msg, struct devlink *devlink; int err; - devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs); + devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs, false); if (IS_ERR(devlink)) return PTR_ERR(devlink); err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED); diff --git a/net/devlink/region.c b/net/devlink/region.c index 0aab7b82d678..e3bab458db94 100644 --- a/net/devlink/region.c +++ b/net/devlink/region.c @@ -883,7 +883,8 @@ int devlink_nl_region_read_dumpit(struct sk_buff *skb, start_offset = state->start_offset; - devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs); + devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs, + false); if (IS_ERR(devlink)) return PTR_ERR(devlink); From bf6b200bc80d18480f8d0fb61e185bb0587e633c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:14 +0100 Subject: [PATCH 0890/7721] devlink: Acquire device lock during reload command Device drivers register with devlink from their probe routines (under the device lock) by acquiring the devlink instance lock and calling devl_register(). Drivers that support a devlink reload usually implement the reload_{down, up}() operations in a similar fashion to their remove and probe routines, respectively. However, while the remove and probe routines are invoked with the device lock held, the reload operations are only invoked with the devlink instance lock held. It is therefore impossible for drivers to acquire the device lock from their reload operations, as this would result in lock inversion. The motivating use case for invoking the reload operations with the device lock held is in mlxsw which needs to trigger a PCI reset as part of the reload. The driver cannot call pci_reset_function() as this function acquires the device lock. Instead, it needs to call __pci_reset_function_locked which expects the device lock to be held. To that end, adjust devlink to always acquire the device lock before the devlink instance lock when performing a reload. Do that when reload is explicitly triggered by user space by specifying the 'DEVLINK_NL_FLAG_NEED_DEV_LOCK' flag in the pre_doit and post_doit operations of the reload command. A previous patch already handled the case where reload is invoked as part of netns dismantle. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- Documentation/netlink/specs/devlink.yaml | 4 ++-- net/devlink/netlink.c | 13 +++++++++++++ net/devlink/netlink_gen.c | 4 ++-- net/devlink/netlink_gen.h | 5 +++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index 572d83a414d0..43067e1f63aa 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -1484,8 +1484,8 @@ operations: dont-validate: [ strict ] flags: [ admin-perm ] do: - pre: devlink-nl-pre-doit - post: devlink-nl-post-doit + pre: devlink-nl-pre-doit-dev-lock + post: devlink-nl-post-doit-dev-lock request: attributes: - bus-name diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index 86f12531bf99..fa9afe3e6d9b 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -138,6 +138,12 @@ int devlink_nl_pre_doit_port(const struct genl_split_ops *ops, return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT); } +int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info) +{ + return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK); +} + int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) @@ -162,6 +168,13 @@ void devlink_nl_post_doit(const struct genl_split_ops *ops, __devlink_nl_post_doit(skb, info, 0); } +void +devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info) +{ + __devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK); +} + static int devlink_nl_inst_single_dumpit(struct sk_buff *msg, struct netlink_callback *cb, int flags, devlink_nl_dump_one_func_t *dump_one, diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c index 788dfdc498a9..95f9b4350ab7 100644 --- a/net/devlink/netlink_gen.c +++ b/net/devlink/netlink_gen.c @@ -846,9 +846,9 @@ const struct genl_split_ops devlink_nl_ops[73] = { { .cmd = DEVLINK_CMD_RELOAD, .validate = GENL_DONT_VALIDATE_STRICT, - .pre_doit = devlink_nl_pre_doit, + .pre_doit = devlink_nl_pre_doit_dev_lock, .doit = devlink_nl_reload_doit, - .post_doit = devlink_nl_post_doit, + .post_doit = devlink_nl_post_doit_dev_lock, .policy = devlink_reload_nl_policy, .maxattr = DEVLINK_ATTR_RELOAD_LIMITS, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h index 0e9e89c31c31..02f3c0bfae0e 100644 --- a/net/devlink/netlink_gen.h +++ b/net/devlink/netlink_gen.h @@ -22,12 +22,17 @@ int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); int devlink_nl_pre_doit_port(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); +int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info); int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); void devlink_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); +void +devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info); int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); From 527a07e176eab0f61b1beec9e29b99c9a5ec219f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:15 +0100 Subject: [PATCH 0891/7721] devlink: Add device lock assert in reload operation Add an assert to verify that the device lock is always held throughout reload operations. Tested the following flows with netdevsim and mlxsw while lockdep is enabled: netdevsim: # echo "10 1" > /sys/bus/netdevsim/new_device # devlink dev reload netdevsim/netdevsim10 # ip netns add bla # devlink dev reload netdevsim/netdevsim10 netns bla # ip netns del bla # echo 10 > /sys/bus/netdevsim/del_device mlxsw: # devlink dev reload pci/0000:01:00.0 # ip netns add bla # devlink dev reload pci/0000:01:00.0 netns bla # ip netns del bla # echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/remove # echo 1 > /sys/bus/pci/rescan Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/devlink/dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/devlink/dev.c b/net/devlink/dev.c index 4fc7adb32663..ea6a92f2e6a2 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -4,6 +4,7 @@ * Copyright (c) 2016 Jiri Pirko */ +#include #include #include #include "devl_internal.h" @@ -433,6 +434,13 @@ int devlink_reload(struct devlink *devlink, struct net *dest_net, struct net *curr_net; int err; + /* Make sure the reload operations are invoked with the device lock + * held to allow drivers to trigger functionality that expects it + * (e.g., PCI reset) and to close possible races between these + * operations and probe/remove. + */ + device_lock_assert(devlink->dev); + memcpy(remote_reload_stats, devlink->stats.remote_reload_stats, sizeof(remote_reload_stats)); From 3ed48c80b28d8dcd584d6ddaf00c75b7673e1a05 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:16 +0100 Subject: [PATCH 0892/7721] PCI: Add no PM reset quirk for NVIDIA Spectrum devices Spectrum-{1,2,3,4} devices report that a D3hot->D0 transition causes a reset (i.e., they advertise NoSoftRst-). However, this transition does not have any effect on the device: It continues to be operational and network ports remain up. Advertising this support makes it seem as if a PM reset is viable for these devices. Mark it as unavailable to skip it when testing reset methods. Before: # cat /sys/bus/pci/devices/0000\:03\:00.0/reset_method pm bus After: # cat /sys/bus/pci/devices/0000\:03\:00.0/reset_method bus Signed-off-by: Ido Schimmel Acked-by: Bjorn Helgaas Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/pci/quirks.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ea476252280a..d208047d1b8f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3786,6 +3786,19 @@ static void quirk_no_pm_reset(struct pci_dev *dev) DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset); +/* + * Spectrum-{1,2,3,4} devices report that a D3hot->D0 transition causes a reset + * (i.e., they advertise NoSoftRst-). However, this transition does not have + * any effect on the device: It continues to be operational and network ports + * remain up. Advertising this support makes it seem as if a PM reset is viable + * for these devices. Mark it as unavailable to skip it when testing reset + * methods. + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, 0xcb84, quirk_no_pm_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, 0xcf6c, quirk_no_pm_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, 0xcf70, quirk_no_pm_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, 0xcf80, quirk_no_pm_reset); + /* * Thunderbolt controllers with broken MSI hotplug signaling: * Entire 1st generation (Light Ridge, Eagle Ridge, Light Peak) and part From 0a5ef95923e01aa93210d22e0d62d66b601238d7 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:17 +0100 Subject: [PATCH 0893/7721] PCI: Add debug print for device ready delay Currently, the time it took a PCI device to become ready after reset is only printed if it was longer than 1000ms ('PCI_RESET_WAIT'). However, for debugging purposes it is useful to know this time even if it was shorter. For example, with the device I am working on, hardware engineers asked to verify that it becomes ready on the first try (no delay). To that end, add a debug level print that can be enabled using dynamic debug. Example: # echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/reset # dmesg -c | grep ready # echo "file drivers/pci/pci.c +p" > /sys/kernel/debug/dynamic_debug/control # echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/reset # dmesg -c | grep ready [ 396.060335] mlxsw_spectrum4 0000:01:00.0: ready 0ms after bus reset # echo "file drivers/pci/pci.c -p" > /sys/kernel/debug/dynamic_debug/control # echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/reset # dmesg -c | grep ready Signed-off-by: Ido Schimmel Acked-by: Bjorn Helgaas Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/pci/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 55bc3576a985..69d20d585f88 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1219,6 +1219,9 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) if (delay > PCI_RESET_WAIT) pci_info(dev, "ready %dms after %s\n", delay - 1, reset_type); + else + pci_dbg(dev, "ready %dms after %s\n", delay - 1, + reset_type); return 0; } From e6dbab40fa096ed5e882e25cab54c3bdad57762c Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Wed, 15 Nov 2023 13:17:18 +0100 Subject: [PATCH 0894/7721] mlxsw: Extend MRSR pack() function to support new commands Currently mlxsw_reg_mrsr_pack() always sets 'command=1'. As preparation for support of new reset flow, pass the command as an argument to the function and add an enum for this field. For now, always pass 'command=1' to the pack() function. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/reg.h | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index e4b25e187467..7af37f78ed1a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1491,7 +1491,7 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, return err; } - mlxsw_reg_mrsr_pack(mrsr_pl); + mlxsw_reg_mrsr_pack(mrsr_pl, MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET); err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 25b294fdeb3d..13c0ff994537 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -10122,6 +10122,15 @@ mlxsw_reg_mgir_unpack(char *payload, u32 *hw_rev, char *fw_info_psid, MLXSW_REG_DEFINE(mrsr, MLXSW_REG_MRSR_ID, MLXSW_REG_MRSR_LEN); +enum mlxsw_reg_mrsr_command { + /* Switch soft reset, does not reset PCI firmware. */ + MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET = 1, + /* Reset will be done when PCI link will be disabled. + * This command will reset PCI firmware also. + */ + MLXSW_REG_MRSR_COMMAND_RESET_AT_PCI_DISABLE = 6, +}; + /* reg_mrsr_command * Reset/shutdown command * 0 - do nothing @@ -10130,10 +10139,11 @@ MLXSW_REG_DEFINE(mrsr, MLXSW_REG_MRSR_ID, MLXSW_REG_MRSR_LEN); */ MLXSW_ITEM32(reg, mrsr, command, 0x00, 0, 4); -static inline void mlxsw_reg_mrsr_pack(char *payload) +static inline void mlxsw_reg_mrsr_pack(char *payload, + enum mlxsw_reg_mrsr_command command) { MLXSW_REG_ZERO(mrsr, payload); - mlxsw_reg_mrsr_command_set(payload, 1); + mlxsw_reg_mrsr_command_set(payload, command); } /* MLCR - Management LED Control Register From bdf85f3a695ff8b9709658e576299fa5a3f6326d Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Wed, 15 Nov 2023 13:17:19 +0100 Subject: [PATCH 0895/7721] mlxsw: pci: Rename mlxsw_pci_sw_reset() In the next patches, mlxsw_pci_sw_reset() will be extended to support more reset types and will not necessarily issue a software reset. Rename the function to reflect that. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 7af37f78ed1a..fe0b8a38d44e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1476,8 +1476,8 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, return -EBUSY; } -static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, - const struct pci_device_id *id) +static int +mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) { struct pci_dev *pdev = mlxsw_pci->pdev; char mrsr_pl[MLXSW_REG_MRSR_LEN]; @@ -1537,9 +1537,9 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, if (!mbox) return -ENOMEM; - err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id); + err = mlxsw_pci_reset(mlxsw_pci, mlxsw_pci->id); if (err) - goto err_sw_reset; + goto err_reset; err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci); if (err < 0) { @@ -1672,7 +1672,7 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, err_query_fw: mlxsw_pci_free_irq_vectors(mlxsw_pci); err_alloc_irq: -err_sw_reset: +err_reset: mbox_put: mlxsw_cmd_mbox_free(mbox); return err; From 8d9da4672f94b4914d3b9318d911bfd1fcbfc9a1 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Wed, 15 Nov 2023 13:17:20 +0100 Subject: [PATCH 0896/7721] mlxsw: pci: Move software reset code to a separate function In general, the existing flow of software reset in the driver is: 1. Wait for system ready status. 2. Send MRSR command, to start the reset. 3. Wait for system ready status. This flow will be extended once a new reset command is supported. As a preparation, move step #2 to a separate function. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index fe0b8a38d44e..080881c94c5a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1476,11 +1476,18 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, return -EBUSY; } +static int mlxsw_pci_reset_sw(struct mlxsw_pci *mlxsw_pci) +{ + char mrsr_pl[MLXSW_REG_MRSR_LEN]; + + mlxsw_reg_mrsr_pack(mrsr_pl, MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET); + return mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); +} + static int mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) { struct pci_dev *pdev = mlxsw_pci->pdev; - char mrsr_pl[MLXSW_REG_MRSR_LEN]; u32 sys_status; int err; @@ -1491,8 +1498,7 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) return err; } - mlxsw_reg_mrsr_pack(mrsr_pl, MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET); - err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); + err = mlxsw_pci_reset_sw(mlxsw_pci); if (err) return err; From f257c73e53561f6c223c4bce883138e9f18b5f50 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:21 +0100 Subject: [PATCH 0897/7721] mlxsw: pci: Add support for new reset flow The driver resets the device during probe and during a devlink reload. The current reset method reloads the current firmware version or a pending one, if one was previously flashed using devlink. However, the current reset method does not result in a PCI hot reset, preventing the PCI firmware from being upgraded, unless the system is rebooted. To solve this problem, a new reset command (6) was implemented in the firmware. Unlike the current command (1), after issuing the new command the device will not start the reset immediately, but only after a PCI hot reset. Implement the new reset method by first verifying that it is supported by the current firmware version by querying the Management Capabilities Mask (MCAM) register. If supported, issue the new reset command (6) via MRSR register followed by a PCI reset by calling __pci_reset_function_locked(). Once the PCI firmware is operational, go back to the regular reset flow and wait for the entire device to become ready. That is, repeatedly read the "system_status" register from the BAR until a value of "FW_READY" (0x5E) appears. Tested: # for i in $(seq 1 10); do devlink dev reload pci/0000:01:00.0; done Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 44 ++++++++++++++++++++++- drivers/net/ethernet/mellanox/mlxsw/reg.h | 2 ++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 080881c94c5a..726ed707e27b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1476,6 +1476,33 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, return -EBUSY; } +static int mlxsw_pci_reset_at_pci_disable(struct mlxsw_pci *mlxsw_pci) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + char mrsr_pl[MLXSW_REG_MRSR_LEN]; + int err; + + mlxsw_reg_mrsr_pack(mrsr_pl, + MLXSW_REG_MRSR_COMMAND_RESET_AT_PCI_DISABLE); + err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); + if (err) + return err; + + device_lock_assert(&pdev->dev); + + pci_cfg_access_lock(pdev); + pci_save_state(pdev); + + err = __pci_reset_function_locked(pdev); + if (err) + pci_err(pdev, "PCI function reset failed with %d\n", err); + + pci_restore_state(pdev); + pci_cfg_access_unlock(pdev); + + return err; +} + static int mlxsw_pci_reset_sw(struct mlxsw_pci *mlxsw_pci) { char mrsr_pl[MLXSW_REG_MRSR_LEN]; @@ -1488,6 +1515,8 @@ static int mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) { struct pci_dev *pdev = mlxsw_pci->pdev; + char mcam_pl[MLXSW_REG_MCAM_LEN]; + bool pci_reset_supported; u32 sys_status; int err; @@ -1498,10 +1527,23 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) return err; } - err = mlxsw_pci_reset_sw(mlxsw_pci); + mlxsw_reg_mcam_pack(mcam_pl, + MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES); + err = mlxsw_reg_query(mlxsw_pci->core, MLXSW_REG(mcam), mcam_pl); if (err) return err; + mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_PCI_RESET, + &pci_reset_supported); + + if (pci_reset_supported) { + pci_dbg(pdev, "Starting PCI reset flow\n"); + err = mlxsw_pci_reset_at_pci_disable(mlxsw_pci); + } else { + pci_dbg(pdev, "Starting software reset flow\n"); + err = mlxsw_pci_reset_sw(mlxsw_pci); + } + err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); if (err) { dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n", diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 13c0ff994537..e26e9d06bd72 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -10594,6 +10594,8 @@ MLXSW_ITEM32(reg, mcam, feature_group, 0x00, 16, 8); enum mlxsw_reg_mcam_mng_feature_cap_mask_bits { /* If set, MCIA supports 128 bytes payloads. Otherwise, 48 bytes. */ MLXSW_REG_MCAM_MCIA_128B = 34, + /* If set, MRSR.command=6 is supported. */ + MLXSW_REG_MCAM_PCI_RESET = 48, }; #define MLXSW_REG_BYTES_PER_DWORD 0x4 From 5e12d0898583026581e4f0506ff7c0b15a73a1c5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:22 +0100 Subject: [PATCH 0898/7721] mlxsw: pci: Implement PCI reset handlers Implement reset_prepare() and reset_done() handlers that are invoked by the PCI core before and after issuing a PCI reset, respectively. Specifically, implement reset_prepare() by calling mlxsw_core_bus_device_unregister() and reset_done() by calling mlxsw_core_bus_device_register(). This is the same implementation as the reload_{down,up}() devlink operations with the following differences: 1. The devlink instance is unregistered and then registered again after the reset. 2. A reset via the device's command interface (using MRSR register) is not issued during reset_done() as PCI core already issued a PCI reset. Tested: # for i in $(seq 1 10); do echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/reset; done Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 726ed707e27b..5b1f2483a3cc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -130,6 +130,7 @@ struct mlxsw_pci { const struct pci_device_id *id; enum mlxsw_pci_cqe_v max_cqe_ver; /* Maximal supported CQE version */ u8 num_sdq_cqs; /* Number of CQs used for SDQs */ + bool skip_reset; }; static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q) @@ -1527,6 +1528,10 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) return err; } + /* PCI core already issued a PCI reset, do not issue another reset. */ + if (mlxsw_pci->skip_reset) + return 0; + mlxsw_reg_mcam_pack(mcam_pl, MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES); err = mlxsw_reg_query(mlxsw_pci->core, MLXSW_REG(mcam), mcam_pl); @@ -2107,11 +2112,34 @@ static void mlxsw_pci_remove(struct pci_dev *pdev) kfree(mlxsw_pci); } +static void mlxsw_pci_reset_prepare(struct pci_dev *pdev) +{ + struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); + + mlxsw_core_bus_device_unregister(mlxsw_pci->core, false); +} + +static void mlxsw_pci_reset_done(struct pci_dev *pdev) +{ + struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); + + mlxsw_pci->skip_reset = true; + mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, &mlxsw_pci_bus, + mlxsw_pci, false, NULL, NULL); + mlxsw_pci->skip_reset = false; +} + +static const struct pci_error_handlers mlxsw_pci_err_handler = { + .reset_prepare = mlxsw_pci_reset_prepare, + .reset_done = mlxsw_pci_reset_done, +}; + int mlxsw_pci_driver_register(struct pci_driver *pci_driver) { pci_driver->probe = mlxsw_pci_probe; pci_driver->remove = mlxsw_pci_remove; pci_driver->shutdown = mlxsw_pci_remove; + pci_driver->err_handler = &mlxsw_pci_err_handler; return pci_register_driver(pci_driver); } EXPORT_SYMBOL(mlxsw_pci_driver_register); From af51d6bd0b130b06fc58b35fee8f93b0a5c77f21 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 15 Nov 2023 13:17:23 +0100 Subject: [PATCH 0899/7721] selftests: mlxsw: Add PCI reset test Test that PCI reset works correctly by verifying that only the expected reset methods are supported and that after issuing the reset the ifindex of the port changes. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../selftests/drivers/net/mlxsw/pci_reset.sh | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/mlxsw/pci_reset.sh diff --git a/tools/testing/selftests/drivers/net/mlxsw/pci_reset.sh b/tools/testing/selftests/drivers/net/mlxsw/pci_reset.sh new file mode 100755 index 000000000000..fe0343b95e6c --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/pci_reset.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test that PCI reset works correctly by verifying that only the expected reset +# methods are supported and that after issuing the reset the ifindex of the +# port changes. + +lib_dir=$(dirname $0)/../../../net/forwarding + +ALL_TESTS=" + pci_reset_test +" +NUM_NETIFS=1 +source $lib_dir/lib.sh +source $lib_dir/devlink_lib.sh + +pci_reset_test() +{ + RET=0 + + local bus=$(echo $DEVLINK_DEV | cut -d '/' -f 1) + local bdf=$(echo $DEVLINK_DEV | cut -d '/' -f 2) + + if [ $bus != "pci" ]; then + check_err 1 "devlink device is not a PCI device" + log_test "pci reset" + return + fi + + if [ ! -f /sys/bus/pci/devices/$bdf/reset_method ]; then + check_err 1 "reset is not supported" + log_test "pci reset" + return + fi + + [[ $(cat /sys/bus/pci/devices/$bdf/reset_method) == "bus" ]] + check_err $? "only \"bus\" reset method should be supported" + + local ifindex_pre=$(ip -j link show dev $swp1 | jq '.[]["ifindex"]') + + echo 1 > /sys/bus/pci/devices/$bdf/reset + check_err $? "reset failed" + + # Wait for udev to rename newly created netdev. + udevadm settle + + local ifindex_post=$(ip -j link show dev $swp1 | jq '.[]["ifindex"]') + + [[ $ifindex_pre != $ifindex_post ]] + check_err $? "reset not performed" + + log_test "pci reset" +} + +swp1=${NETIFS[p1]} +tests_run + +exit $EXIT_STATUS From db840d389bad60ce6f3aadc1079da13e7e993a16 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:16 -0800 Subject: [PATCH 0900/7721] bpf: move verbose_linfo() into kernel/bpf/log.c verifier.c is huge. Let's try to move out parts that are logging-related into log.c, as we previously did with bpf_log() and other related stuff. This patch moves line info verbose output routines: it's pretty self-contained and isolated code, so there is no problem with this. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 4 +++ kernel/bpf/log.c | 59 ++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 57 ---------------------------------- 3 files changed, 63 insertions(+), 57 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 52a4012b8255..d896f3db6a22 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -680,6 +680,10 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos); int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual); +__printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, + u32 insn_off, + const char *prefix_fmt, ...); + static inline struct bpf_func_state *cur_func(struct bpf_verifier_env *env) { struct bpf_verifier_state *cur = env->cur_state; diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 850494423530..f20e1449c882 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -10,6 +10,8 @@ #include #include +#define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args) + static bool bpf_verifier_log_attr_valid(const struct bpf_verifier_log *log) { /* ubuf and len_total should both be specified (or not) together */ @@ -325,3 +327,60 @@ __printf(2, 3) void bpf_log(struct bpf_verifier_log *log, va_end(args); } EXPORT_SYMBOL_GPL(bpf_log); + +static const struct bpf_line_info * +find_linfo(const struct bpf_verifier_env *env, u32 insn_off) +{ + const struct bpf_line_info *linfo; + const struct bpf_prog *prog; + u32 i, nr_linfo; + + prog = env->prog; + nr_linfo = prog->aux->nr_linfo; + + if (!nr_linfo || insn_off >= prog->len) + return NULL; + + linfo = prog->aux->linfo; + for (i = 1; i < nr_linfo; i++) + if (insn_off < linfo[i].insn_off) + break; + + return &linfo[i - 1]; +} + +static const char *ltrim(const char *s) +{ + while (isspace(*s)) + s++; + + return s; +} + +__printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, + u32 insn_off, + const char *prefix_fmt, ...) +{ + const struct bpf_line_info *linfo; + + if (!bpf_verifier_log_needed(&env->log)) + return; + + linfo = find_linfo(env, insn_off); + if (!linfo || linfo == env->prev_linfo) + return; + + if (prefix_fmt) { + va_list args; + + va_start(args, prefix_fmt); + bpf_verifier_vlog(&env->log, prefix_fmt, args); + va_end(args); + } + + verbose(env, "%s\n", + ltrim(btf_name_by_offset(env->prog->aux->btf, + linfo->line_off))); + + env->prev_linfo = linfo; +} diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7c3461b89513..683fdda25c13 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -337,27 +337,6 @@ struct btf *btf_vmlinux; static DEFINE_MUTEX(bpf_verifier_lock); -static const struct bpf_line_info * -find_linfo(const struct bpf_verifier_env *env, u32 insn_off) -{ - const struct bpf_line_info *linfo; - const struct bpf_prog *prog; - u32 i, nr_linfo; - - prog = env->prog; - nr_linfo = prog->aux->nr_linfo; - - if (!nr_linfo || insn_off >= prog->len) - return NULL; - - linfo = prog->aux->linfo; - for (i = 1; i < nr_linfo; i++) - if (insn_off < linfo[i].insn_off) - break; - - return &linfo[i - 1]; -} - __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) { struct bpf_verifier_env *env = private_data; @@ -371,42 +350,6 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) va_end(args); } -static const char *ltrim(const char *s) -{ - while (isspace(*s)) - s++; - - return s; -} - -__printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env, - u32 insn_off, - const char *prefix_fmt, ...) -{ - const struct bpf_line_info *linfo; - - if (!bpf_verifier_log_needed(&env->log)) - return; - - linfo = find_linfo(env, insn_off); - if (!linfo || linfo == env->prev_linfo) - return; - - if (prefix_fmt) { - va_list args; - - va_start(args, prefix_fmt); - bpf_verifier_vlog(&env->log, prefix_fmt, args); - va_end(args); - } - - verbose(env, "%s\n", - ltrim(btf_name_by_offset(env->prog->aux->btf, - linfo->line_off))); - - env->prev_linfo = linfo; -} - static void verbose_invalid_scalar(struct bpf_verifier_env *env, struct bpf_reg_state *reg, struct tnum *range, const char *ctx, From 42feb6620accded89cad5f455665e21281813d79 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:17 -0800 Subject: [PATCH 0901/7721] bpf: move verifier state printing code to kernel/bpf/log.c Move a good chunk of code from verifier.c to log.c: verifier state verbose printing logic. This is an important and very much logging/debugging oriented code. It fits the overlall log.c's focus on verifier logging, and moving it allows to keep growing it without unnecessarily adding to verifier.c code that otherwise contains a core verification logic. There are not many shared dependencies between this code and the rest of verifier.c code, except a few single-line helpers for various register type checks and a bit of state "scratching" helpers. We move all such trivial helpers into include/bpf/bpf_verifier.h as static inlines. No functional changes in this patch. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 72 +++++++ kernel/bpf/log.c | 342 +++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 403 ----------------------------------- 3 files changed, 414 insertions(+), 403 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index d896f3db6a22..39edc76f436e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -783,4 +783,76 @@ static inline bool bpf_type_has_unsafe_modifiers(u32 type) return type_flag(type) & ~BPF_REG_TRUSTED_MODIFIERS; } +static inline bool type_is_ptr_alloc_obj(u32 type) +{ + return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC; +} + +static inline bool type_is_non_owning_ref(u32 type) +{ + return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF; +} + +static inline bool type_is_pkt_pointer(enum bpf_reg_type type) +{ + type = base_type(type); + return type == PTR_TO_PACKET || + type == PTR_TO_PACKET_META; +} + +static inline bool type_is_sk_pointer(enum bpf_reg_type type) +{ + return type == PTR_TO_SOCKET || + type == PTR_TO_SOCK_COMMON || + type == PTR_TO_TCP_SOCK || + type == PTR_TO_XDP_SOCK; +} + +static inline void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno) +{ + env->scratched_regs |= 1U << regno; +} + +static inline void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi) +{ + env->scratched_stack_slots |= 1ULL << spi; +} + +static inline bool reg_scratched(const struct bpf_verifier_env *env, u32 regno) +{ + return (env->scratched_regs >> regno) & 1; +} + +static inline bool stack_slot_scratched(const struct bpf_verifier_env *env, u64 regno) +{ + return (env->scratched_stack_slots >> regno) & 1; +} + +static inline bool verifier_state_scratched(const struct bpf_verifier_env *env) +{ + return env->scratched_regs || env->scratched_stack_slots; +} + +static inline void mark_verifier_state_clean(struct bpf_verifier_env *env) +{ + env->scratched_regs = 0U; + env->scratched_stack_slots = 0ULL; +} + +/* Used for printing the entire verifier state. */ +static inline void mark_verifier_state_scratched(struct bpf_verifier_env *env) +{ + env->scratched_regs = ~0U; + env->scratched_stack_slots = ~0ULL; +} + +const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type); +const char *dynptr_type_str(enum bpf_dynptr_type type); +const char *iter_type_str(const struct btf *btf, u32 btf_id); +const char *iter_state_str(enum bpf_iter_state state); + +void print_verifier_state(struct bpf_verifier_env *env, + const struct bpf_func_state *state, bool print_all); +void print_insn_state(struct bpf_verifier_env *env, const struct bpf_func_state *state); + #endif /* _LINUX_BPF_VERIFIER_H */ diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index f20e1449c882..c1b257eac21b 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -384,3 +384,345 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, env->prev_linfo = linfo; } + +static const char *btf_type_name(const struct btf *btf, u32 id) +{ + return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off); +} + +/* string representation of 'enum bpf_reg_type' + * + * Note that reg_type_str() can not appear more than once in a single verbose() + * statement. + */ +const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type) +{ + char postfix[16] = {0}, prefix[64] = {0}; + static const char * const str[] = { + [NOT_INIT] = "?", + [SCALAR_VALUE] = "scalar", + [PTR_TO_CTX] = "ctx", + [CONST_PTR_TO_MAP] = "map_ptr", + [PTR_TO_MAP_VALUE] = "map_value", + [PTR_TO_STACK] = "fp", + [PTR_TO_PACKET] = "pkt", + [PTR_TO_PACKET_META] = "pkt_meta", + [PTR_TO_PACKET_END] = "pkt_end", + [PTR_TO_FLOW_KEYS] = "flow_keys", + [PTR_TO_SOCKET] = "sock", + [PTR_TO_SOCK_COMMON] = "sock_common", + [PTR_TO_TCP_SOCK] = "tcp_sock", + [PTR_TO_TP_BUFFER] = "tp_buffer", + [PTR_TO_XDP_SOCK] = "xdp_sock", + [PTR_TO_BTF_ID] = "ptr_", + [PTR_TO_MEM] = "mem", + [PTR_TO_BUF] = "buf", + [PTR_TO_FUNC] = "func", + [PTR_TO_MAP_KEY] = "map_key", + [CONST_PTR_TO_DYNPTR] = "dynptr_ptr", + }; + + if (type & PTR_MAYBE_NULL) { + if (base_type(type) == PTR_TO_BTF_ID) + strncpy(postfix, "or_null_", 16); + else + strncpy(postfix, "_or_null", 16); + } + + snprintf(prefix, sizeof(prefix), "%s%s%s%s%s%s%s", + type & MEM_RDONLY ? "rdonly_" : "", + type & MEM_RINGBUF ? "ringbuf_" : "", + type & MEM_USER ? "user_" : "", + type & MEM_PERCPU ? "percpu_" : "", + type & MEM_RCU ? "rcu_" : "", + type & PTR_UNTRUSTED ? "untrusted_" : "", + type & PTR_TRUSTED ? "trusted_" : "" + ); + + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s", + prefix, str[base_type(type)], postfix); + return env->tmp_str_buf; +} + +const char *dynptr_type_str(enum bpf_dynptr_type type) +{ + switch (type) { + case BPF_DYNPTR_TYPE_LOCAL: + return "local"; + case BPF_DYNPTR_TYPE_RINGBUF: + return "ringbuf"; + case BPF_DYNPTR_TYPE_SKB: + return "skb"; + case BPF_DYNPTR_TYPE_XDP: + return "xdp"; + case BPF_DYNPTR_TYPE_INVALID: + return ""; + default: + WARN_ONCE(1, "unknown dynptr type %d\n", type); + return ""; + } +} + +const char *iter_type_str(const struct btf *btf, u32 btf_id) +{ + if (!btf || btf_id == 0) + return ""; + + /* we already validated that type is valid and has conforming name */ + return btf_type_name(btf, btf_id) + sizeof(ITER_PREFIX) - 1; +} + +const char *iter_state_str(enum bpf_iter_state state) +{ + switch (state) { + case BPF_ITER_STATE_ACTIVE: + return "active"; + case BPF_ITER_STATE_DRAINED: + return "drained"; + case BPF_ITER_STATE_INVALID: + return ""; + default: + WARN_ONCE(1, "unknown iter state %d\n", state); + return ""; + } +} + +static char slot_type_char[] = { + [STACK_INVALID] = '?', + [STACK_SPILL] = 'r', + [STACK_MISC] = 'm', + [STACK_ZERO] = '0', + [STACK_DYNPTR] = 'd', + [STACK_ITER] = 'i', +}; + +static void print_liveness(struct bpf_verifier_env *env, + enum bpf_reg_liveness live) +{ + if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE)) + verbose(env, "_"); + if (live & REG_LIVE_READ) + verbose(env, "r"); + if (live & REG_LIVE_WRITTEN) + verbose(env, "w"); + if (live & REG_LIVE_DONE) + verbose(env, "D"); +} + +static void print_scalar_ranges(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, + const char **sep) +{ + struct { + const char *name; + u64 val; + bool omit; + } minmaxs[] = { + {"smin", reg->smin_value, reg->smin_value == S64_MIN}, + {"smax", reg->smax_value, reg->smax_value == S64_MAX}, + {"umin", reg->umin_value, reg->umin_value == 0}, + {"umax", reg->umax_value, reg->umax_value == U64_MAX}, + {"smin32", (s64)reg->s32_min_value, reg->s32_min_value == S32_MIN}, + {"smax32", (s64)reg->s32_max_value, reg->s32_max_value == S32_MAX}, + {"umin32", reg->u32_min_value, reg->u32_min_value == 0}, + {"umax32", reg->u32_max_value, reg->u32_max_value == U32_MAX}, + }, *m1, *m2, *mend = &minmaxs[ARRAY_SIZE(minmaxs)]; + bool neg1, neg2; + + for (m1 = &minmaxs[0]; m1 < mend; m1++) { + if (m1->omit) + continue; + + neg1 = m1->name[0] == 's' && (s64)m1->val < 0; + + verbose(env, "%s%s=", *sep, m1->name); + *sep = ","; + + for (m2 = m1 + 2; m2 < mend; m2 += 2) { + if (m2->omit || m2->val != m1->val) + continue; + /* don't mix negatives with positives */ + neg2 = m2->name[0] == 's' && (s64)m2->val < 0; + if (neg2 != neg1) + continue; + m2->omit = true; + verbose(env, "%s=", m2->name); + } + + verbose(env, m1->name[0] == 's' ? "%lld" : "%llu", m1->val); + } +} + +void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_state *state, + bool print_all) +{ + const struct bpf_reg_state *reg; + enum bpf_reg_type t; + int i; + + if (state->frameno) + verbose(env, " frame%d:", state->frameno); + for (i = 0; i < MAX_BPF_REG; i++) { + reg = &state->regs[i]; + t = reg->type; + if (t == NOT_INIT) + continue; + if (!print_all && !reg_scratched(env, i)) + continue; + verbose(env, " R%d", i); + print_liveness(env, reg->live); + verbose(env, "="); + if (t == SCALAR_VALUE && reg->precise) + verbose(env, "P"); + if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && + tnum_is_const(reg->var_off)) { + /* reg->off should be 0 for SCALAR_VALUE */ + verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); + verbose(env, "%lld", reg->var_off.value + reg->off); + } else { + const char *sep = ""; + + verbose(env, "%s", reg_type_str(env, t)); + if (base_type(t) == PTR_TO_BTF_ID) + verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); + verbose(env, "("); +/* + * _a stands for append, was shortened to avoid multiline statements below. + * This macro is used to output a comma separated list of attributes. + */ +#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; }) + + if (reg->id) + verbose_a("id=%d", reg->id); + if (reg->ref_obj_id) + verbose_a("ref_obj_id=%d", reg->ref_obj_id); + if (type_is_non_owning_ref(reg->type)) + verbose_a("%s", "non_own_ref"); + if (t != SCALAR_VALUE) + verbose_a("off=%d", reg->off); + if (type_is_pkt_pointer(t)) + verbose_a("r=%d", reg->range); + else if (base_type(t) == CONST_PTR_TO_MAP || + base_type(t) == PTR_TO_MAP_KEY || + base_type(t) == PTR_TO_MAP_VALUE) + verbose_a("ks=%d,vs=%d", + reg->map_ptr->key_size, + reg->map_ptr->value_size); + if (tnum_is_const(reg->var_off)) { + /* Typically an immediate SCALAR_VALUE, but + * could be a pointer whose offset is too big + * for reg->off + */ + verbose_a("imm=%llx", reg->var_off.value); + } else { + print_scalar_ranges(env, reg, &sep); + if (!tnum_is_unknown(reg->var_off)) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose_a("var_off=%s", tn_buf); + } + } +#undef verbose_a + + verbose(env, ")"); + } + } + for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { + char types_buf[BPF_REG_SIZE + 1]; + bool valid = false; + int j; + + for (j = 0; j < BPF_REG_SIZE; j++) { + if (state->stack[i].slot_type[j] != STACK_INVALID) + valid = true; + types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; + } + types_buf[BPF_REG_SIZE] = 0; + if (!valid) + continue; + if (!print_all && !stack_slot_scratched(env, i)) + continue; + switch (state->stack[i].slot_type[BPF_REG_SIZE - 1]) { + case STACK_SPILL: + reg = &state->stack[i].spilled_ptr; + t = reg->type; + + verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); + print_liveness(env, reg->live); + verbose(env, "=%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); + if (t == SCALAR_VALUE && reg->precise) + verbose(env, "P"); + if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) + verbose(env, "%lld", reg->var_off.value + reg->off); + break; + case STACK_DYNPTR: + i += BPF_DYNPTR_NR_SLOTS - 1; + reg = &state->stack[i].spilled_ptr; + + verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); + print_liveness(env, reg->live); + verbose(env, "=dynptr_%s", dynptr_type_str(reg->dynptr.type)); + if (reg->ref_obj_id) + verbose(env, "(ref_id=%d)", reg->ref_obj_id); + break; + case STACK_ITER: + /* only main slot has ref_obj_id set; skip others */ + reg = &state->stack[i].spilled_ptr; + if (!reg->ref_obj_id) + continue; + + verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); + print_liveness(env, reg->live); + verbose(env, "=iter_%s(ref_id=%d,state=%s,depth=%u)", + iter_type_str(reg->iter.btf, reg->iter.btf_id), + reg->ref_obj_id, iter_state_str(reg->iter.state), + reg->iter.depth); + break; + case STACK_MISC: + case STACK_ZERO: + default: + reg = &state->stack[i].spilled_ptr; + + for (j = 0; j < BPF_REG_SIZE; j++) + types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; + types_buf[BPF_REG_SIZE] = 0; + + verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); + print_liveness(env, reg->live); + verbose(env, "=%s", types_buf); + break; + } + } + if (state->acquired_refs && state->refs[0].id) { + verbose(env, " refs=%d", state->refs[0].id); + for (i = 1; i < state->acquired_refs; i++) + if (state->refs[i].id) + verbose(env, ",%d", state->refs[i].id); + } + if (state->in_callback_fn) + verbose(env, " cb"); + if (state->in_async_callback_fn) + verbose(env, " async_cb"); + verbose(env, "\n"); + if (!print_all) + mark_verifier_state_clean(env); +} + +static inline u32 vlog_alignment(u32 pos) +{ + return round_up(max(pos + BPF_LOG_MIN_ALIGNMENT / 2, BPF_LOG_ALIGNMENT), + BPF_LOG_MIN_ALIGNMENT) - pos - 1; +} + +void print_insn_state(struct bpf_verifier_env *env, const struct bpf_func_state *state) +{ + if (env->prev_log_pos && env->prev_log_pos == env->log.end_pos) { + /* remove new line character */ + bpf_vlog_reset(&env->log, env->prev_log_pos - 1); + verbose(env, "%*c;", vlog_alignment(env->prev_insn_print_pos), ' '); + } else { + verbose(env, "%d:", env->insn_idx); + } + print_verifier_state(env, state, false); +} diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 683fdda25c13..8c2d31aa3d31 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -368,21 +368,6 @@ static void verbose_invalid_scalar(struct bpf_verifier_env *env, verbose(env, " should have been in %s\n", tn_buf); } -static bool type_is_pkt_pointer(enum bpf_reg_type type) -{ - type = base_type(type); - return type == PTR_TO_PACKET || - type == PTR_TO_PACKET_META; -} - -static bool type_is_sk_pointer(enum bpf_reg_type type) -{ - return type == PTR_TO_SOCKET || - type == PTR_TO_SOCK_COMMON || - type == PTR_TO_TCP_SOCK || - type == PTR_TO_XDP_SOCK; -} - static bool type_may_be_null(u32 type) { return type & PTR_MAYBE_NULL; @@ -406,16 +391,6 @@ static bool reg_not_null(const struct bpf_reg_state *reg) type == PTR_TO_MEM; } -static bool type_is_ptr_alloc_obj(u32 type) -{ - return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC; -} - -static bool type_is_non_owning_ref(u32 type) -{ - return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF; -} - static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) { struct btf_record *rec = NULL; @@ -532,83 +507,6 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn) insn->imm == BPF_CMPXCHG; } -/* string representation of 'enum bpf_reg_type' - * - * Note that reg_type_str() can not appear more than once in a single verbose() - * statement. - */ -static const char *reg_type_str(struct bpf_verifier_env *env, - enum bpf_reg_type type) -{ - char postfix[16] = {0}, prefix[64] = {0}; - static const char * const str[] = { - [NOT_INIT] = "?", - [SCALAR_VALUE] = "scalar", - [PTR_TO_CTX] = "ctx", - [CONST_PTR_TO_MAP] = "map_ptr", - [PTR_TO_MAP_VALUE] = "map_value", - [PTR_TO_STACK] = "fp", - [PTR_TO_PACKET] = "pkt", - [PTR_TO_PACKET_META] = "pkt_meta", - [PTR_TO_PACKET_END] = "pkt_end", - [PTR_TO_FLOW_KEYS] = "flow_keys", - [PTR_TO_SOCKET] = "sock", - [PTR_TO_SOCK_COMMON] = "sock_common", - [PTR_TO_TCP_SOCK] = "tcp_sock", - [PTR_TO_TP_BUFFER] = "tp_buffer", - [PTR_TO_XDP_SOCK] = "xdp_sock", - [PTR_TO_BTF_ID] = "ptr_", - [PTR_TO_MEM] = "mem", - [PTR_TO_BUF] = "buf", - [PTR_TO_FUNC] = "func", - [PTR_TO_MAP_KEY] = "map_key", - [CONST_PTR_TO_DYNPTR] = "dynptr_ptr", - }; - - if (type & PTR_MAYBE_NULL) { - if (base_type(type) == PTR_TO_BTF_ID) - strncpy(postfix, "or_null_", 16); - else - strncpy(postfix, "_or_null", 16); - } - - snprintf(prefix, sizeof(prefix), "%s%s%s%s%s%s%s", - type & MEM_RDONLY ? "rdonly_" : "", - type & MEM_RINGBUF ? "ringbuf_" : "", - type & MEM_USER ? "user_" : "", - type & MEM_PERCPU ? "percpu_" : "", - type & MEM_RCU ? "rcu_" : "", - type & PTR_UNTRUSTED ? "untrusted_" : "", - type & PTR_TRUSTED ? "trusted_" : "" - ); - - snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s", - prefix, str[base_type(type)], postfix); - return env->tmp_str_buf; -} - -static char slot_type_char[] = { - [STACK_INVALID] = '?', - [STACK_SPILL] = 'r', - [STACK_MISC] = 'm', - [STACK_ZERO] = '0', - [STACK_DYNPTR] = 'd', - [STACK_ITER] = 'i', -}; - -static void print_liveness(struct bpf_verifier_env *env, - enum bpf_reg_liveness live) -{ - if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE)) - verbose(env, "_"); - if (live & REG_LIVE_READ) - verbose(env, "r"); - if (live & REG_LIVE_WRITTEN) - verbose(env, "w"); - if (live & REG_LIVE_DONE) - verbose(env, "D"); -} - static int __get_spi(s32 off) { return (-off - 1) / BPF_REG_SIZE; @@ -678,87 +576,6 @@ static const char *btf_type_name(const struct btf *btf, u32 id) return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off); } -static const char *dynptr_type_str(enum bpf_dynptr_type type) -{ - switch (type) { - case BPF_DYNPTR_TYPE_LOCAL: - return "local"; - case BPF_DYNPTR_TYPE_RINGBUF: - return "ringbuf"; - case BPF_DYNPTR_TYPE_SKB: - return "skb"; - case BPF_DYNPTR_TYPE_XDP: - return "xdp"; - case BPF_DYNPTR_TYPE_INVALID: - return ""; - default: - WARN_ONCE(1, "unknown dynptr type %d\n", type); - return ""; - } -} - -static const char *iter_type_str(const struct btf *btf, u32 btf_id) -{ - if (!btf || btf_id == 0) - return ""; - - /* we already validated that type is valid and has conforming name */ - return btf_type_name(btf, btf_id) + sizeof(ITER_PREFIX) - 1; -} - -static const char *iter_state_str(enum bpf_iter_state state) -{ - switch (state) { - case BPF_ITER_STATE_ACTIVE: - return "active"; - case BPF_ITER_STATE_DRAINED: - return "drained"; - case BPF_ITER_STATE_INVALID: - return ""; - default: - WARN_ONCE(1, "unknown iter state %d\n", state); - return ""; - } -} - -static void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno) -{ - env->scratched_regs |= 1U << regno; -} - -static void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi) -{ - env->scratched_stack_slots |= 1ULL << spi; -} - -static bool reg_scratched(const struct bpf_verifier_env *env, u32 regno) -{ - return (env->scratched_regs >> regno) & 1; -} - -static bool stack_slot_scratched(const struct bpf_verifier_env *env, u64 regno) -{ - return (env->scratched_stack_slots >> regno) & 1; -} - -static bool verifier_state_scratched(const struct bpf_verifier_env *env) -{ - return env->scratched_regs || env->scratched_stack_slots; -} - -static void mark_verifier_state_clean(struct bpf_verifier_env *env) -{ - env->scratched_regs = 0U; - env->scratched_stack_slots = 0ULL; -} - -/* Used for printing the entire verifier state. */ -static void mark_verifier_state_scratched(struct bpf_verifier_env *env) -{ - env->scratched_regs = ~0U; - env->scratched_stack_slots = ~0ULL; -} - static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) { switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { @@ -1298,226 +1115,6 @@ static void scrub_spilled_slot(u8 *stype) *stype = STACK_MISC; } -static void print_scalar_ranges(struct bpf_verifier_env *env, - const struct bpf_reg_state *reg, - const char **sep) -{ - struct { - const char *name; - u64 val; - bool omit; - } minmaxs[] = { - {"smin", reg->smin_value, reg->smin_value == S64_MIN}, - {"smax", reg->smax_value, reg->smax_value == S64_MAX}, - {"umin", reg->umin_value, reg->umin_value == 0}, - {"umax", reg->umax_value, reg->umax_value == U64_MAX}, - {"smin32", (s64)reg->s32_min_value, reg->s32_min_value == S32_MIN}, - {"smax32", (s64)reg->s32_max_value, reg->s32_max_value == S32_MAX}, - {"umin32", reg->u32_min_value, reg->u32_min_value == 0}, - {"umax32", reg->u32_max_value, reg->u32_max_value == U32_MAX}, - }, *m1, *m2, *mend = &minmaxs[ARRAY_SIZE(minmaxs)]; - bool neg1, neg2; - - for (m1 = &minmaxs[0]; m1 < mend; m1++) { - if (m1->omit) - continue; - - neg1 = m1->name[0] == 's' && (s64)m1->val < 0; - - verbose(env, "%s%s=", *sep, m1->name); - *sep = ","; - - for (m2 = m1 + 2; m2 < mend; m2 += 2) { - if (m2->omit || m2->val != m1->val) - continue; - /* don't mix negatives with positives */ - neg2 = m2->name[0] == 's' && (s64)m2->val < 0; - if (neg2 != neg1) - continue; - m2->omit = true; - verbose(env, "%s=", m2->name); - } - - verbose(env, m1->name[0] == 's' ? "%lld" : "%llu", m1->val); - } -} - -static void print_verifier_state(struct bpf_verifier_env *env, - const struct bpf_func_state *state, - bool print_all) -{ - const struct bpf_reg_state *reg; - enum bpf_reg_type t; - int i; - - if (state->frameno) - verbose(env, " frame%d:", state->frameno); - for (i = 0; i < MAX_BPF_REG; i++) { - reg = &state->regs[i]; - t = reg->type; - if (t == NOT_INIT) - continue; - if (!print_all && !reg_scratched(env, i)) - continue; - verbose(env, " R%d", i); - print_liveness(env, reg->live); - verbose(env, "="); - if (t == SCALAR_VALUE && reg->precise) - verbose(env, "P"); - if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && - tnum_is_const(reg->var_off)) { - /* reg->off should be 0 for SCALAR_VALUE */ - verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); - verbose(env, "%lld", reg->var_off.value + reg->off); - } else { - const char *sep = ""; - - verbose(env, "%s", reg_type_str(env, t)); - if (base_type(t) == PTR_TO_BTF_ID) - verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); - verbose(env, "("); -/* - * _a stands for append, was shortened to avoid multiline statements below. - * This macro is used to output a comma separated list of attributes. - */ -#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; }) - - if (reg->id) - verbose_a("id=%d", reg->id); - if (reg->ref_obj_id) - verbose_a("ref_obj_id=%d", reg->ref_obj_id); - if (type_is_non_owning_ref(reg->type)) - verbose_a("%s", "non_own_ref"); - if (t != SCALAR_VALUE) - verbose_a("off=%d", reg->off); - if (type_is_pkt_pointer(t)) - verbose_a("r=%d", reg->range); - else if (base_type(t) == CONST_PTR_TO_MAP || - base_type(t) == PTR_TO_MAP_KEY || - base_type(t) == PTR_TO_MAP_VALUE) - verbose_a("ks=%d,vs=%d", - reg->map_ptr->key_size, - reg->map_ptr->value_size); - if (tnum_is_const(reg->var_off)) { - /* Typically an immediate SCALAR_VALUE, but - * could be a pointer whose offset is too big - * for reg->off - */ - verbose_a("imm=%llx", reg->var_off.value); - } else { - print_scalar_ranges(env, reg, &sep); - if (!tnum_is_unknown(reg->var_off)) { - char tn_buf[48]; - - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose_a("var_off=%s", tn_buf); - } - } -#undef verbose_a - - verbose(env, ")"); - } - } - for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { - char types_buf[BPF_REG_SIZE + 1]; - bool valid = false; - int j; - - for (j = 0; j < BPF_REG_SIZE; j++) { - if (state->stack[i].slot_type[j] != STACK_INVALID) - valid = true; - types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; - } - types_buf[BPF_REG_SIZE] = 0; - if (!valid) - continue; - if (!print_all && !stack_slot_scratched(env, i)) - continue; - switch (state->stack[i].slot_type[BPF_REG_SIZE - 1]) { - case STACK_SPILL: - reg = &state->stack[i].spilled_ptr; - t = reg->type; - - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); - print_liveness(env, reg->live); - verbose(env, "=%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); - if (t == SCALAR_VALUE && reg->precise) - verbose(env, "P"); - if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) - verbose(env, "%lld", reg->var_off.value + reg->off); - break; - case STACK_DYNPTR: - i += BPF_DYNPTR_NR_SLOTS - 1; - reg = &state->stack[i].spilled_ptr; - - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); - print_liveness(env, reg->live); - verbose(env, "=dynptr_%s", dynptr_type_str(reg->dynptr.type)); - if (reg->ref_obj_id) - verbose(env, "(ref_id=%d)", reg->ref_obj_id); - break; - case STACK_ITER: - /* only main slot has ref_obj_id set; skip others */ - reg = &state->stack[i].spilled_ptr; - if (!reg->ref_obj_id) - continue; - - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); - print_liveness(env, reg->live); - verbose(env, "=iter_%s(ref_id=%d,state=%s,depth=%u)", - iter_type_str(reg->iter.btf, reg->iter.btf_id), - reg->ref_obj_id, iter_state_str(reg->iter.state), - reg->iter.depth); - break; - case STACK_MISC: - case STACK_ZERO: - default: - reg = &state->stack[i].spilled_ptr; - - for (j = 0; j < BPF_REG_SIZE; j++) - types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; - types_buf[BPF_REG_SIZE] = 0; - - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); - print_liveness(env, reg->live); - verbose(env, "=%s", types_buf); - break; - } - } - if (state->acquired_refs && state->refs[0].id) { - verbose(env, " refs=%d", state->refs[0].id); - for (i = 1; i < state->acquired_refs; i++) - if (state->refs[i].id) - verbose(env, ",%d", state->refs[i].id); - } - if (state->in_callback_fn) - verbose(env, " cb"); - if (state->in_async_callback_fn) - verbose(env, " async_cb"); - verbose(env, "\n"); - if (!print_all) - mark_verifier_state_clean(env); -} - -static inline u32 vlog_alignment(u32 pos) -{ - return round_up(max(pos + BPF_LOG_MIN_ALIGNMENT / 2, BPF_LOG_ALIGNMENT), - BPF_LOG_MIN_ALIGNMENT) - pos - 1; -} - -static void print_insn_state(struct bpf_verifier_env *env, - const struct bpf_func_state *state) -{ - if (env->prev_log_pos && env->prev_log_pos == env->log.end_pos) { - /* remove new line character */ - bpf_vlog_reset(&env->log, env->prev_log_pos - 1); - verbose(env, "%*c;", vlog_alignment(env->prev_insn_print_pos), ' '); - } else { - verbose(env, "%d:", env->insn_idx); - } - print_verifier_state(env, state, false); -} - /* copy array src of length n * size bytes to dst. dst is reallocated if it's too * small to hold src. This is different from krealloc since we don't want to preserve * the contents of dst. From 009f5465be3636e9ce795cfbd5d3109d8978774d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:18 -0800 Subject: [PATCH 0902/7721] bpf: extract register state printing Extract printing register state representation logic into a separate helper, as we are going to reuse it for spilled register state printing in the next patch. This also nicely reduces code nestedness. No functional changes. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 120 +++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index c1b257eac21b..05d737e2fab3 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -553,6 +553,67 @@ static void print_scalar_ranges(struct bpf_verifier_env *env, } } +static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_state *reg) +{ + enum bpf_reg_type t; + const char *sep = ""; + + t = reg->type; + if (t == SCALAR_VALUE && reg->precise) + verbose(env, "P"); + if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && + tnum_is_const(reg->var_off)) { + /* reg->off should be 0 for SCALAR_VALUE */ + verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); + verbose(env, "%lld", reg->var_off.value + reg->off); + return; + } +/* + * _a stands for append, was shortened to avoid multiline statements below. + * This macro is used to output a comma separated list of attributes. + */ +#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; }) + + verbose(env, "%s", reg_type_str(env, t)); + if (base_type(t) == PTR_TO_BTF_ID) + verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); + verbose(env, "("); + if (reg->id) + verbose_a("id=%d", reg->id); + if (reg->ref_obj_id) + verbose_a("ref_obj_id=%d", reg->ref_obj_id); + if (type_is_non_owning_ref(reg->type)) + verbose_a("%s", "non_own_ref"); + if (t != SCALAR_VALUE) + verbose_a("off=%d", reg->off); + if (type_is_pkt_pointer(t)) + verbose_a("r=%d", reg->range); + else if (base_type(t) == CONST_PTR_TO_MAP || + base_type(t) == PTR_TO_MAP_KEY || + base_type(t) == PTR_TO_MAP_VALUE) + verbose_a("ks=%d,vs=%d", + reg->map_ptr->key_size, + reg->map_ptr->value_size); + if (tnum_is_const(reg->var_off)) { + /* Typically an immediate SCALAR_VALUE, but + * could be a pointer whose offset is too big + * for reg->off + */ + verbose_a("imm=%llx", reg->var_off.value); + } else { + print_scalar_ranges(env, reg, &sep); + if (!tnum_is_unknown(reg->var_off)) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose_a("var_off=%s", tn_buf); + } + } + verbose(env, ")"); + +#undef verbose_a +} + void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_state *state, bool print_all) { @@ -564,69 +625,14 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st verbose(env, " frame%d:", state->frameno); for (i = 0; i < MAX_BPF_REG; i++) { reg = &state->regs[i]; - t = reg->type; - if (t == NOT_INIT) + if (reg->type == NOT_INIT) continue; if (!print_all && !reg_scratched(env, i)) continue; verbose(env, " R%d", i); print_liveness(env, reg->live); verbose(env, "="); - if (t == SCALAR_VALUE && reg->precise) - verbose(env, "P"); - if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && - tnum_is_const(reg->var_off)) { - /* reg->off should be 0 for SCALAR_VALUE */ - verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); - verbose(env, "%lld", reg->var_off.value + reg->off); - } else { - const char *sep = ""; - - verbose(env, "%s", reg_type_str(env, t)); - if (base_type(t) == PTR_TO_BTF_ID) - verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); - verbose(env, "("); -/* - * _a stands for append, was shortened to avoid multiline statements below. - * This macro is used to output a comma separated list of attributes. - */ -#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; }) - - if (reg->id) - verbose_a("id=%d", reg->id); - if (reg->ref_obj_id) - verbose_a("ref_obj_id=%d", reg->ref_obj_id); - if (type_is_non_owning_ref(reg->type)) - verbose_a("%s", "non_own_ref"); - if (t != SCALAR_VALUE) - verbose_a("off=%d", reg->off); - if (type_is_pkt_pointer(t)) - verbose_a("r=%d", reg->range); - else if (base_type(t) == CONST_PTR_TO_MAP || - base_type(t) == PTR_TO_MAP_KEY || - base_type(t) == PTR_TO_MAP_VALUE) - verbose_a("ks=%d,vs=%d", - reg->map_ptr->key_size, - reg->map_ptr->value_size); - if (tnum_is_const(reg->var_off)) { - /* Typically an immediate SCALAR_VALUE, but - * could be a pointer whose offset is too big - * for reg->off - */ - verbose_a("imm=%llx", reg->var_off.value); - } else { - print_scalar_ranges(env, reg, &sep); - if (!tnum_is_unknown(reg->var_off)) { - char tn_buf[48]; - - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose_a("var_off=%s", tn_buf); - } - } -#undef verbose_a - - verbose(env, ")"); - } + print_reg_state(env, reg); } for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { char types_buf[BPF_REG_SIZE + 1]; From 67d43dfbb42d6575304daea67733c88fbf536a1c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:19 -0800 Subject: [PATCH 0903/7721] bpf: print spilled register state in stack slot Print the same register state representation when printing stack state, as we do for normal registers. Note that if stack slot contains subregister spill (1, 2, or 4 byte long), we'll still emit "m0?" mask for those bytes that are not part of spilled register. While means we can get something like fp-8=0000scalar() for a 4-byte spill with other 4 bytes still being STACK_ZERO. Some example before and after, taken from the log of pyperf_subprogs.bpf.o: 49: (7b) *(u64 *)(r10 -256) = r1 ; frame1: R1_w=ctx(off=0,imm=0) R10=fp0 fp-256_w=ctx 49: (7b) *(u64 *)(r10 -256) = r1 ; frame1: R1_w=ctx(off=0,imm=0) R10=fp0 fp-256_w=ctx(off=0,imm=0) 150: (7b) *(u64 *)(r10 -264) = r0 ; frame1: R0_w=map_value_or_null(id=6,off=0,ks=192,vs=4,imm=0) R10=fp0 fp-264_w=map_value_or_null 150: (7b) *(u64 *)(r10 -264) = r0 ; frame1: R0_w=map_value_or_null(id=6,off=0,ks=192,vs=4,imm=0) R10=fp0 fp-264_w=map_value_or_null(id=6,off=0,ks=192,vs=4,imm=0) 5192: (61) r1 = *(u32 *)(r10 -272) ; frame1: R1_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf)) R10=fp0 fp-272= 5192: (61) r1 = *(u32 *)(r10 -272) ; frame1: R1_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf)) R10=fp0 fp-272=????scalar(smin=smin32=0,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf)) While at it, do a few other simple clean ups: - skip slot if it's not scratched before detecting whether it's valid; - move taking spilled_reg pointer outside of switch (only DYNPTR has to adjust that to get to the "main" slot); - don't recalculate types_buf second time for MISC/ZERO/default case. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 05d737e2fab3..97a1641e848e 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -618,7 +618,6 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st bool print_all) { const struct bpf_reg_state *reg; - enum bpf_reg_type t; int i; if (state->frameno) @@ -637,32 +636,38 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { char types_buf[BPF_REG_SIZE + 1]; bool valid = false; + u8 slot_type; int j; + if (!print_all && !stack_slot_scratched(env, i)) + continue; + for (j = 0; j < BPF_REG_SIZE; j++) { - if (state->stack[i].slot_type[j] != STACK_INVALID) + slot_type = state->stack[i].slot_type[j]; + if (slot_type != STACK_INVALID) valid = true; - types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; + types_buf[j] = slot_type_char[slot_type]; } types_buf[BPF_REG_SIZE] = 0; if (!valid) continue; - if (!print_all && !stack_slot_scratched(env, i)) - continue; + + reg = &state->stack[i].spilled_ptr; switch (state->stack[i].slot_type[BPF_REG_SIZE - 1]) { case STACK_SPILL: - reg = &state->stack[i].spilled_ptr; - t = reg->type; + /* print MISC/ZERO/INVALID slots above subreg spill */ + for (j = 0; j < BPF_REG_SIZE; j++) + if (state->stack[i].slot_type[j] == STACK_SPILL) + break; + types_buf[j] = '\0'; verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); print_liveness(env, reg->live); - verbose(env, "=%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); - if (t == SCALAR_VALUE && reg->precise) - verbose(env, "P"); - if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) - verbose(env, "%lld", reg->var_off.value + reg->off); + verbose(env, "=%s", types_buf); + print_reg_state(env, reg); break; case STACK_DYNPTR: + /* skip to main dynptr slot */ i += BPF_DYNPTR_NR_SLOTS - 1; reg = &state->stack[i].spilled_ptr; @@ -674,7 +679,6 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st break; case STACK_ITER: /* only main slot has ref_obj_id set; skip others */ - reg = &state->stack[i].spilled_ptr; if (!reg->ref_obj_id) continue; @@ -688,12 +692,6 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st case STACK_MISC: case STACK_ZERO: default: - reg = &state->stack[i].spilled_ptr; - - for (j = 0; j < BPF_REG_SIZE; j++) - types_buf[j] = slot_type_char[state->stack[i].slot_type[j]]; - types_buf[BPF_REG_SIZE] = 0; - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); print_liveness(env, reg->live); verbose(env, "=%s", types_buf); From 0c95c9fdb696f35c7864785ba84cb9a50152daff Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:20 -0800 Subject: [PATCH 0904/7721] bpf: emit map name in register state if applicable and available In complicated real-world applications, whenever debugging some verification error through verifier log, it often would be very useful to see map name for PTR_TO_MAP_VALUE register. Usually this needs to be inferred from key/value sizes and maybe trying to guess C code location, but it's not always clear. Given verifier has the name, and it's never too long, let's just emit it for ptr_to_map_key, ptr_to_map_value, and const_ptr_to_map registers. We reshuffle the order a bit, so that map name, key size, and value size appear before offset and immediate values, which seems like a more logical order. Current output: R1_w=map_ptr(map=array_map,ks=4,vs=8,off=0,imm=0) But we'll get rid of useless off=0 and imm=0 parts in the next patch. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 24 ++++++++++++++----- .../selftests/bpf/prog_tests/spin_lock.c | 10 ++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 97a1641e848e..c209ab1ec2b5 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -553,6 +553,17 @@ static void print_scalar_ranges(struct bpf_verifier_env *env, } } +static bool type_is_map_ptr(enum bpf_reg_type t) { + switch (base_type(t)) { + case CONST_PTR_TO_MAP: + case PTR_TO_MAP_KEY: + case PTR_TO_MAP_VALUE: + return true; + default: + return false; + } +} + static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_state *reg) { enum bpf_reg_type t; @@ -584,16 +595,17 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s verbose_a("ref_obj_id=%d", reg->ref_obj_id); if (type_is_non_owning_ref(reg->type)) verbose_a("%s", "non_own_ref"); + if (type_is_map_ptr(t)) { + if (reg->map_ptr->name[0]) + verbose_a("map=%s", reg->map_ptr->name); + verbose_a("ks=%d,vs=%d", + reg->map_ptr->key_size, + reg->map_ptr->value_size); + } if (t != SCALAR_VALUE) verbose_a("off=%d", reg->off); if (type_is_pkt_pointer(t)) verbose_a("r=%d", reg->range); - else if (base_type(t) == CONST_PTR_TO_MAP || - base_type(t) == PTR_TO_MAP_KEY || - base_type(t) == PTR_TO_MAP_VALUE) - verbose_a("ks=%d,vs=%d", - reg->map_ptr->key_size, - reg->map_ptr->value_size); if (tnum_is_const(reg->var_off)) { /* Typically an immediate SCALAR_VALUE, but * could be a pointer whose offset is too big diff --git a/tools/testing/selftests/bpf/prog_tests/spin_lock.c b/tools/testing/selftests/bpf/prog_tests/spin_lock.c index f29c08d93beb..ace65224286f 100644 --- a/tools/testing/selftests/bpf/prog_tests/spin_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/spin_lock.c @@ -17,18 +17,18 @@ static struct { "R1_w=ptr_foo(id=2,ref_obj_id=2,off=0,imm=0) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" "R1 type=ptr_ expected=percpu_ptr_" }, { "lock_id_global_zero", - "; R1_w=map_value(off=0,ks=4,vs=4,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n" + "; R1_w=map_value(map=.data.A,ks=4,vs=4,off=0,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)" - " R1_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)\n" + " R0_w=map_value(id=1,map=array_map,ks=4,vs=8,off=0,imm=0)" + " R1_w=map_value(id=1,map=array_map,ks=4,vs=8,off=0,imm=0)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_innermapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0=map_value(id=2,off=0,ks=4,vs=8,imm=0)" - " R1_w=map_value(id=2,off=0,ks=4,vs=8,imm=0)\n" + " R0=map_value(id=2,ks=4,vs=8,off=0,imm=0)" + " R1_w=map_value(id=2,ks=4,vs=8,off=0,imm=0)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" }, From 1db747d75b1dbe17bf4283ed87bd3b7a92010f34 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:21 -0800 Subject: [PATCH 0905/7721] bpf: omit default off=0 and imm=0 in register state log Simplify BPF verifier log further by omitting default (and frequently irrelevant) off=0 and imm=0 parts for non-SCALAR_VALUE registers. As can be seen from fixed tests, this is often a visual noise for PTR_TO_CTX register and even for PTR_TO_PACKET registers. Omitting default values follows the rest of register state logic: we omit default values to keep verifier log succinct and to highlight interesting state that deviates from default one. E.g., we do the same for var_off, when it's unknown, which gives no additional information. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 10 ++--- .../testing/selftests/bpf/prog_tests/align.c | 42 +++++++++---------- .../selftests/bpf/prog_tests/log_buf.c | 4 +- .../selftests/bpf/prog_tests/spin_lock.c | 14 +++---- .../selftests/bpf/progs/exceptions_assert.c | 10 ++--- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index c209ab1ec2b5..20b4f81087da 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -602,16 +602,14 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s reg->map_ptr->key_size, reg->map_ptr->value_size); } - if (t != SCALAR_VALUE) + if (t != SCALAR_VALUE && reg->off) verbose_a("off=%d", reg->off); if (type_is_pkt_pointer(t)) verbose_a("r=%d", reg->range); if (tnum_is_const(reg->var_off)) { - /* Typically an immediate SCALAR_VALUE, but - * could be a pointer whose offset is too big - * for reg->off - */ - verbose_a("imm=%llx", reg->var_off.value); + /* a pointer register with fixed offset */ + if (reg->var_off.value) + verbose_a("imm=%llx", reg->var_off.value); } else { print_scalar_ranges(env, reg, &sep); if (!tnum_is_unknown(reg->var_off)) { diff --git a/tools/testing/selftests/bpf/prog_tests/align.c b/tools/testing/selftests/bpf/prog_tests/align.c index 465c1c3a3d3c..4ebd0da898f5 100644 --- a/tools/testing/selftests/bpf/prog_tests/align.c +++ b/tools/testing/selftests/bpf/prog_tests/align.c @@ -40,7 +40,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "2"}, {1, "R3_w", "4"}, @@ -68,7 +68,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "1"}, {1, "R3_w", "2"}, @@ -97,7 +97,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "4"}, {1, "R3_w", "8"}, @@ -119,7 +119,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "7"}, {1, "R3_w", "7"}, @@ -162,13 +162,13 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {6, "R0_w", "pkt(off=8,r=8,imm=0)"}, + {6, "R0_w", "pkt(off=8,r=8)"}, {6, "R3_w", "var_off=(0x0; 0xff)"}, {7, "R3_w", "var_off=(0x0; 0x1fe)"}, {8, "R3_w", "var_off=(0x0; 0x3fc)"}, {9, "R3_w", "var_off=(0x0; 0x7f8)"}, {10, "R3_w", "var_off=(0x0; 0xff0)"}, - {12, "R3_w", "pkt_end(off=0,imm=0)"}, + {12, "R3_w", "pkt_end()"}, {17, "R4_w", "var_off=(0x0; 0xff)"}, {18, "R4_w", "var_off=(0x0; 0x1fe0)"}, {19, "R4_w", "var_off=(0x0; 0xff0)"}, @@ -235,11 +235,11 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {2, "R5_w", "pkt(off=0,r=0,imm=0)"}, - {4, "R5_w", "pkt(off=14,r=0,imm=0)"}, - {5, "R4_w", "pkt(off=14,r=0,imm=0)"}, - {9, "R2", "pkt(off=0,r=18,imm=0)"}, - {10, "R5", "pkt(off=14,r=18,imm=0)"}, + {2, "R5_w", "pkt(r=0)"}, + {4, "R5_w", "pkt(off=14,r=0)"}, + {5, "R4_w", "pkt(off=14,r=0)"}, + {9, "R2", "pkt(r=18)"}, + {10, "R5", "pkt(off=14,r=18)"}, {10, "R4_w", "var_off=(0x0; 0xff)"}, {13, "R4_w", "var_off=(0x0; 0xffff)"}, {14, "R4_w", "var_off=(0x0; 0xffff)"}, @@ -299,7 +299,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {7, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Offset is added to packet pointer R5, resulting in * known fixed offset, and variable offset from R6. @@ -337,7 +337,7 @@ static struct bpf_align_test tests[] = { /* Constant offset is added to R5 packet pointer, * resulting in reg->off value of 14. */ - {26, "R5_w", "pkt(off=14,r=8,"}, + {26, "R5_w", "pkt(off=14,r=8)"}, /* Variable offset is added to R5, resulting in a * variable offset of (4n). See comment for insn #18 * for R4 = R5 trick. @@ -397,7 +397,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {7, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Adding 14 makes R6 be (4n+2) */ {8, "R6_w", "var_off=(0x2; 0x7fc)"}, @@ -459,7 +459,7 @@ static struct bpf_align_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = REJECT, .matches = { - {3, "R5_w", "pkt_end(off=0,imm=0)"}, + {3, "R5_w", "pkt_end()"}, /* (ptr - ptr) << 2 == unknown, (4n) */ {5, "R5_w", "var_off=(0x0; 0xfffffffffffffffc)"}, /* (4n) + 14 == (4n+2). We blow our bounds, because @@ -513,7 +513,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {8, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Adding 14 makes R6 be (4n+2) */ {9, "R6_w", "var_off=(0x2; 0x7fc)"}, @@ -566,7 +566,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {9, "R6_w", "var_off=(0x0; 0x3c)"}, /* Adding 14 makes R6 be (4n+2) */ {10, "R6_w", "var_off=(0x2; 0x7c)"}, @@ -659,14 +659,14 @@ static int do_test_single(struct bpf_align_test *test) /* Check the next line as well in case the previous line * did not have a corresponding bpf insn. Example: * func#0 @0 - * 0: R1=ctx(off=0,imm=0) R10=fp0 + * 0: R1=ctx() R10=fp0 * 0: (b7) r3 = 2 ; R3_w=2 * * Sometimes it's actually two lines below, e.g. when * searching for "6: R3_w=scalar(umax=255,var_off=(0x0; 0xff))": - * from 4 to 6: R0_w=pkt(off=8,r=8,imm=0) R1=ctx(off=0,imm=0) R2_w=pkt(off=0,r=8,imm=0) R3_w=pkt_end(off=0,imm=0) R10=fp0 - * 6: R0_w=pkt(off=8,r=8,imm=0) R1=ctx(off=0,imm=0) R2_w=pkt(off=0,r=8,imm=0) R3_w=pkt_end(off=0,imm=0) R10=fp0 - * 6: (71) r3 = *(u8 *)(r2 +0) ; R2_w=pkt(off=0,r=8,imm=0) R3_w=scalar(umax=255,var_off=(0x0; 0xff)) + * from 4 to 6: R0_w=pkt(off=8,r=8) R1=ctx() R2_w=pkt(r=8) R3_w=pkt_end() R10=fp0 + * 6: R0_w=pkt(off=8,r=8) R1=ctx() R2_w=pkt(r=8) R3_w=pkt_end() R10=fp0 + * 6: (71) r3 = *(u8 *)(r2 +0) ; R2_w=pkt(r=8) R3_w=scalar(umax=255,var_off=(0x0; 0xff)) */ while (!(p = strstr(line_ptr, m.reg)) || !strstr(p, m.match)) { cur_line = -1; diff --git a/tools/testing/selftests/bpf/prog_tests/log_buf.c b/tools/testing/selftests/bpf/prog_tests/log_buf.c index fe9a23e65ef4..0f7ea4d7d9f6 100644 --- a/tools/testing/selftests/bpf/prog_tests/log_buf.c +++ b/tools/testing/selftests/bpf/prog_tests/log_buf.c @@ -78,7 +78,7 @@ static void obj_load_log_buf(void) ASSERT_OK_PTR(strstr(libbpf_log_buf, "prog 'bad_prog': BPF program load failed"), "libbpf_log_not_empty"); ASSERT_OK_PTR(strstr(obj_log_buf, "DATASEC license"), "obj_log_not_empty"); - ASSERT_OK_PTR(strstr(good_log_buf, "0: R1=ctx(off=0,imm=0) R10=fp0"), + ASSERT_OK_PTR(strstr(good_log_buf, "0: R1=ctx() R10=fp0"), "good_log_verbose"); ASSERT_OK_PTR(strstr(bad_log_buf, "invalid access to map value, value_size=16 off=16000 size=4"), "bad_log_not_empty"); @@ -175,7 +175,7 @@ static void bpf_prog_load_log_buf(void) opts.log_level = 2; fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "good_prog", "GPL", good_prog_insns, good_prog_insn_cnt, &opts); - ASSERT_OK_PTR(strstr(log_buf, "0: R1=ctx(off=0,imm=0) R10=fp0"), "good_log_2"); + ASSERT_OK_PTR(strstr(log_buf, "0: R1=ctx() R10=fp0"), "good_log_2"); ASSERT_GE(fd, 0, "good_fd2"); if (fd >= 0) close(fd); diff --git a/tools/testing/selftests/bpf/prog_tests/spin_lock.c b/tools/testing/selftests/bpf/prog_tests/spin_lock.c index ace65224286f..18d451be57c8 100644 --- a/tools/testing/selftests/bpf/prog_tests/spin_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/spin_lock.c @@ -13,22 +13,22 @@ static struct { const char *err_msg; } spin_lock_fail_tests[] = { { "lock_id_kptr_preserve", - "5: (bf) r1 = r0 ; R0_w=ptr_foo(id=2,ref_obj_id=2,off=0,imm=0) " - "R1_w=ptr_foo(id=2,ref_obj_id=2,off=0,imm=0) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" + "5: (bf) r1 = r0 ; R0_w=ptr_foo(id=2,ref_obj_id=2) " + "R1_w=ptr_foo(id=2,ref_obj_id=2) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" "R1 type=ptr_ expected=percpu_ptr_" }, { "lock_id_global_zero", - "; R1_w=map_value(map=.data.A,ks=4,vs=4,off=0,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n" + "; R1_w=map_value(map=.data.A,ks=4,vs=4)\n2: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0_w=map_value(id=1,map=array_map,ks=4,vs=8,off=0,imm=0)" - " R1_w=map_value(id=1,map=array_map,ks=4,vs=8,off=0,imm=0)\n" + " R0_w=map_value(id=1,map=array_map,ks=4,vs=8)" + " R1_w=map_value(id=1,map=array_map,ks=4,vs=8)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_innermapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0=map_value(id=2,ks=4,vs=8,off=0,imm=0)" - " R1_w=map_value(id=2,ks=4,vs=8,off=0,imm=0)\n" + " R0=map_value(id=2,ks=4,vs=8)" + " R1_w=map_value(id=2,ks=4,vs=8)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" }, diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c index e1e5c54a6a11..26f7d67432cc 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_assert.c +++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c @@ -59,7 +59,7 @@ check_assert(s64, ge, neg, INT_MIN); SEC("?tc") __log_level(2) __failure -__msg(": R0=0 R1=ctx(off=0,imm=0) R2=scalar(smin=smin32=-2147483646,smax=smax32=2147483645) R10=fp0") +__msg(": R0=0 R1=ctx() R2=scalar(smin=smin32=-2147483646,smax=smax32=2147483645) R10=fp0") int check_assert_range_s64(struct __sk_buff *ctx) { struct bpf_sock *sk = ctx->sk; @@ -75,7 +75,7 @@ int check_assert_range_s64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=ctx(off=0,imm=0) R2=scalar(smin=umin=smin32=umin32=4096,smax=umax=smax32=umax32=8192,var_off=(0x0; 0x3fff))") +__msg(": R1=ctx() R2=scalar(smin=umin=smin32=umin32=4096,smax=umax=smax32=umax32=8192,var_off=(0x0; 0x3fff))") int check_assert_range_u64(struct __sk_buff *ctx) { u64 num = ctx->len; @@ -86,7 +86,7 @@ int check_assert_range_u64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R0=0 R1=ctx(off=0,imm=0) R2=4096 R10=fp0") +__msg(": R0=0 R1=ctx() R2=4096 R10=fp0") int check_assert_single_range_s64(struct __sk_buff *ctx) { struct bpf_sock *sk = ctx->sk; @@ -103,7 +103,7 @@ int check_assert_single_range_s64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=ctx(off=0,imm=0) R2=4096 R10=fp0") +__msg(": R1=ctx() R2=4096 R10=fp0") int check_assert_single_range_u64(struct __sk_buff *ctx) { u64 num = ctx->len; @@ -114,7 +114,7 @@ int check_assert_single_range_u64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=pkt(off=64,r=64,imm=0) R2=pkt_end(off=0,imm=0) R6=pkt(off=0,r=64,imm=0) R10=fp0") +__msg(": R1=pkt(off=64,r=64) R2=pkt_end() R6=pkt(r=64) R10=fp0") int check_assert_generic(struct __sk_buff *ctx) { u8 *data_end = (void *)(long)ctx->data_end; From 0f8dbdbc641b45a5fa31d497f9fc83ffe1174fa3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:22 -0800 Subject: [PATCH 0906/7721] bpf: smarter verifier log number printing logic Instead of always printing numbers as either decimals (and in some cases, like for "imm=%llx", in hexadecimals), decide the form based on actual values. For numbers in a reasonably small range (currently, [0, U16_MAX] for unsigned values, and [S16_MIN, S16_MAX] for signed ones), emit them as decimals. In all other cases, even for signed values, emit them in hexadecimals. For large values hex form is often times way more useful: it's easier to see an exact difference between 0xffffffff80000000 and 0xffffffff7fffffff, than between 18446744071562067966 and 18446744071562067967, as one particular example. Small values representing small pointer offsets or application constants, on the other hand, are way more useful to be represented in decimal notation. Adjust reg_bounds register state parsing logic to take into account this change. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 79 ++++++++++++++++--- .../selftests/bpf/prog_tests/reg_bounds.c | 53 ++++++++----- .../selftests/bpf/progs/exceptions_assert.c | 32 ++++---- 3 files changed, 118 insertions(+), 46 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 20b4f81087da..87105aa482ed 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -509,10 +509,52 @@ static void print_liveness(struct bpf_verifier_env *env, verbose(env, "D"); } +#define UNUM_MAX_DECIMAL U16_MAX +#define SNUM_MAX_DECIMAL S16_MAX +#define SNUM_MIN_DECIMAL S16_MIN + +static bool is_unum_decimal(u64 num) +{ + return num <= UNUM_MAX_DECIMAL; +} + +static bool is_snum_decimal(s64 num) +{ + return num >= SNUM_MIN_DECIMAL && num <= SNUM_MAX_DECIMAL; +} + +static void verbose_unum(struct bpf_verifier_env *env, u64 num) +{ + if (is_unum_decimal(num)) + verbose(env, "%llu", num); + else + verbose(env, "%#llx", num); +} + +static void verbose_snum(struct bpf_verifier_env *env, s64 num) +{ + if (is_snum_decimal(num)) + verbose(env, "%lld", num); + else + verbose(env, "%#llx", num); +} + static void print_scalar_ranges(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, const char **sep) { + /* For signed ranges, we want to unify 64-bit and 32-bit values in the + * output as much as possible, but there is a bit of a complication. + * If we choose to print values as decimals, this is natural to do, + * because negative 64-bit and 32-bit values >= -S32_MIN have the same + * representation due to sign extension. But if we choose to print + * them in hex format (see is_snum_decimal()), then sign extension is + * misleading. + * E.g., smin=-2 and smin32=-2 are exactly the same in decimal, but in + * hex they will be smin=0xfffffffffffffffe and smin32=0xfffffffe, two + * very different numbers. + * So we avoid sign extension if we choose to print values in hex. + */ struct { const char *name; u64 val; @@ -522,8 +564,14 @@ static void print_scalar_ranges(struct bpf_verifier_env *env, {"smax", reg->smax_value, reg->smax_value == S64_MAX}, {"umin", reg->umin_value, reg->umin_value == 0}, {"umax", reg->umax_value, reg->umax_value == U64_MAX}, - {"smin32", (s64)reg->s32_min_value, reg->s32_min_value == S32_MIN}, - {"smax32", (s64)reg->s32_max_value, reg->s32_max_value == S32_MAX}, + {"smin32", + is_snum_decimal((s64)reg->s32_min_value) + ? (s64)reg->s32_min_value + : (u32)reg->s32_min_value, reg->s32_min_value == S32_MIN}, + {"smax32", + is_snum_decimal((s64)reg->s32_max_value) + ? (s64)reg->s32_max_value + : (u32)reg->s32_max_value, reg->s32_max_value == S32_MAX}, {"umin32", reg->u32_min_value, reg->u32_min_value == 0}, {"umax32", reg->u32_max_value, reg->u32_max_value == U32_MAX}, }, *m1, *m2, *mend = &minmaxs[ARRAY_SIZE(minmaxs)]; @@ -549,7 +597,10 @@ static void print_scalar_ranges(struct bpf_verifier_env *env, verbose(env, "%s=", m2->name); } - verbose(env, m1->name[0] == 's' ? "%lld" : "%llu", m1->val); + if (m1->name[0] == 's') + verbose_snum(env, m1->val); + else + verbose_unum(env, m1->val); } } @@ -576,14 +627,14 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s tnum_is_const(reg->var_off)) { /* reg->off should be 0 for SCALAR_VALUE */ verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); - verbose(env, "%lld", reg->var_off.value + reg->off); + verbose_snum(env, reg->var_off.value + reg->off); return; } /* * _a stands for append, was shortened to avoid multiline statements below. * This macro is used to output a comma separated list of attributes. */ -#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; }) +#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, ##__VA_ARGS__); sep = ","; }) verbose(env, "%s", reg_type_str(env, t)); if (base_type(t) == PTR_TO_BTF_ID) @@ -602,14 +653,20 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s reg->map_ptr->key_size, reg->map_ptr->value_size); } - if (t != SCALAR_VALUE && reg->off) - verbose_a("off=%d", reg->off); - if (type_is_pkt_pointer(t)) - verbose_a("r=%d", reg->range); + if (t != SCALAR_VALUE && reg->off) { + verbose_a("off="); + verbose_snum(env, reg->off); + } + if (type_is_pkt_pointer(t)) { + verbose_a("r="); + verbose_unum(env, reg->range); + } if (tnum_is_const(reg->var_off)) { /* a pointer register with fixed offset */ - if (reg->var_off.value) - verbose_a("imm=%llx", reg->var_off.value); + if (reg->var_off.value) { + verbose_a("imm="); + verbose_snum(env, reg->var_off.value); + } } else { print_scalar_ranges(env, reg, &sep); if (!tnum_is_unknown(reg->var_off)) { diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index 7a8b0bf0a7f8..fd4ab23e6f54 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -13,10 +13,13 @@ */ #define U64_MAX ((u64)UINT64_MAX) #define U32_MAX ((u32)UINT_MAX) +#define U16_MAX ((u32)UINT_MAX) #define S64_MIN ((s64)INT64_MIN) #define S64_MAX ((s64)INT64_MAX) #define S32_MIN ((s32)INT_MIN) #define S32_MAX ((s32)INT_MAX) +#define S16_MIN ((s16)0x80000000) +#define S16_MAX ((s16)0x7fffffff) typedef unsigned long long ___u64; typedef unsigned int ___u32; @@ -138,13 +141,17 @@ static enum num_t t_unsigned(enum num_t t) } } +#define UNUM_MAX_DECIMAL U16_MAX +#define SNUM_MAX_DECIMAL S16_MAX +#define SNUM_MIN_DECIMAL S16_MIN + static bool num_is_small(enum num_t t, u64 x) { switch (t) { - case U64: return (u64)x <= 256; - case U32: return (u32)x <= 256; - case S64: return (s64)x >= -256 && (s64)x <= 256; - case S32: return (s32)x >= -256 && (s32)x <= 256; + case U64: return (u64)x <= UNUM_MAX_DECIMAL; + case U32: return (u32)x <= UNUM_MAX_DECIMAL; + case S64: return (s64)x >= SNUM_MIN_DECIMAL && (s64)x <= SNUM_MAX_DECIMAL; + case S32: return (s32)x >= SNUM_MIN_DECIMAL && (s32)x <= SNUM_MAX_DECIMAL; default: printf("num_is_small!\n"); exit(1); } } @@ -1023,20 +1030,19 @@ static int parse_reg_state(const char *s, struct reg_state *reg) */ struct { const char *pfx; - const char *fmt; u64 *dst, def; bool is_32, is_set; } *f, fields[8] = { - {"smin=", "%lld", ®->r[S64].a, S64_MIN}, - {"smax=", "%lld", ®->r[S64].b, S64_MAX}, - {"umin=", "%llu", ®->r[U64].a, 0}, - {"umax=", "%llu", ®->r[U64].b, U64_MAX}, - {"smin32=", "%lld", ®->r[S32].a, (u32)S32_MIN, true}, - {"smax32=", "%lld", ®->r[S32].b, (u32)S32_MAX, true}, - {"umin32=", "%llu", ®->r[U32].a, 0, true}, - {"umax32=", "%llu", ®->r[U32].b, U32_MAX, true}, + {"smin=", ®->r[S64].a, S64_MIN}, + {"smax=", ®->r[S64].b, S64_MAX}, + {"umin=", ®->r[U64].a, 0}, + {"umax=", ®->r[U64].b, U64_MAX}, + {"smin32=", ®->r[S32].a, (u32)S32_MIN, true}, + {"smax32=", ®->r[S32].b, (u32)S32_MAX, true}, + {"umin32=", ®->r[U32].a, 0, true}, + {"umax32=", ®->r[U32].b, U32_MAX, true}, }; - const char *p, *fmt; + const char *p; int i; p = strchr(s, '='); @@ -1050,8 +1056,13 @@ static int parse_reg_state(const char *s, struct reg_state *reg) long long sval; enum num_t t; - if (sscanf(p, "%lld", &sval) != 1) - return -EINVAL; + if (p[0] == '0' && p[1] == 'x') { + if (sscanf(p, "%llx", &sval) != 1) + return -EINVAL; + } else { + if (sscanf(p, "%lld", &sval) != 1) + return -EINVAL; + } reg->valid = true; for (t = first_t; t <= last_t; t++) { @@ -1075,9 +1086,13 @@ static int parse_reg_state(const char *s, struct reg_state *reg) if (mcnt) { /* populate all matched fields */ - fmt = fields[midxs[0]].fmt; - if (sscanf(p, fmt, &val) != 1) - return -EINVAL; + if (p[0] == '0' && p[1] == 'x') { + if (sscanf(p, "%llx", &val) != 1) + return -EINVAL; + } else { + if (sscanf(p, "%lld", &val) != 1) + return -EINVAL; + } for (i = 0; i < mcnt; i++) { f = &fields[midxs[i]]; diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c index 26f7d67432cc..49efaed143fc 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_assert.c +++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c @@ -18,48 +18,48 @@ return *(u64 *)num; \ } -__msg(": R0_w=-2147483648 R10=fp0") +__msg(": R0_w=0xffffffff80000000 R10=fp0") check_assert(s64, eq, int_min, INT_MIN); -__msg(": R0_w=2147483647 R10=fp0") +__msg(": R0_w=0x7fffffff R10=fp0") check_assert(s64, eq, int_max, INT_MAX); __msg(": R0_w=0 R10=fp0") check_assert(s64, eq, zero, 0); -__msg(": R0_w=-9223372036854775808 R1_w=-9223372036854775808 R10=fp0") +__msg(": R0_w=0x8000000000000000 R1_w=0x8000000000000000 R10=fp0") check_assert(s64, eq, llong_min, LLONG_MIN); -__msg(": R0_w=9223372036854775807 R1_w=9223372036854775807 R10=fp0") +__msg(": R0_w=0x7fffffffffffffff R1_w=0x7fffffffffffffff R10=fp0") check_assert(s64, eq, llong_max, LLONG_MAX); -__msg(": R0_w=scalar(smax=2147483646) R10=fp0") +__msg(": R0_w=scalar(smax=0x7ffffffe) R10=fp0") check_assert(s64, lt, pos, INT_MAX); -__msg(": R0_w=scalar(smax=-1,umin=9223372036854775808,var_off=(0x8000000000000000; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") check_assert(s64, lt, zero, 0); -__msg(": R0_w=scalar(smax=-2147483649,umin=9223372036854775808,umax=18446744071562067967,var_off=(0x8000000000000000; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smax=0xffffffff7fffffff,umin=0x8000000000000000,umax=0xffffffff7fffffff,var_off=(0x8000000000000000; 0x7fffffffffffffff))") check_assert(s64, lt, neg, INT_MIN); -__msg(": R0_w=scalar(smax=2147483647) R10=fp0") +__msg(": R0_w=scalar(smax=0x7fffffff) R10=fp0") check_assert(s64, le, pos, INT_MAX); __msg(": R0_w=scalar(smax=0) R10=fp0") check_assert(s64, le, zero, 0); -__msg(": R0_w=scalar(smax=-2147483648,umin=9223372036854775808,umax=18446744071562067968,var_off=(0x8000000000000000; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smax=0xffffffff80000000,umin=0x8000000000000000,umax=0xffffffff80000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") check_assert(s64, le, neg, INT_MIN); -__msg(": R0_w=scalar(smin=umin=2147483648,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") check_assert(s64, gt, pos, INT_MAX); -__msg(": R0_w=scalar(smin=umin=1,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") check_assert(s64, gt, zero, 0); -__msg(": R0_w=scalar(smin=-2147483647) R10=fp0") +__msg(": R0_w=scalar(smin=0xffffffff80000001) R10=fp0") check_assert(s64, gt, neg, INT_MIN); -__msg(": R0_w=scalar(smin=umin=2147483647,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") +__msg(": R0_w=scalar(smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") check_assert(s64, ge, pos, INT_MAX); -__msg(": R0_w=scalar(smin=0,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) R10=fp0") +__msg(": R0_w=scalar(smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff)) R10=fp0") check_assert(s64, ge, zero, 0); -__msg(": R0_w=scalar(smin=-2147483648) R10=fp0") +__msg(": R0_w=scalar(smin=0xffffffff80000000) R10=fp0") check_assert(s64, ge, neg, INT_MIN); SEC("?tc") __log_level(2) __failure -__msg(": R0=0 R1=ctx() R2=scalar(smin=smin32=-2147483646,smax=smax32=2147483645) R10=fp0") +__msg(": R0=0 R1=ctx() R2=scalar(smin=0xffffffff80000002,smax=smax32=0x7ffffffd,smin32=0x80000002) R10=fp0") int check_assert_range_s64(struct __sk_buff *ctx) { struct bpf_sock *sk = ctx->sk; From 46862ee854b4f5a315d63b677ca3af14a89aefeb Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 17 Nov 2023 19:46:23 -0800 Subject: [PATCH 0907/7721] bpf: emit frameno for PTR_TO_STACK regs if it differs from current one It's possible to pass a pointer to parent's stack to child subprogs. In such case verifier state output is ambiguous not showing whether register container a pointer to "current" stack, belonging to current subprog (frame), or it's actually a pointer to one of parent frames. So emit this information if frame number differs between the state which register is part of. E.g., if current state is in frame 2 and it has a register pointing to stack in grand parent state (frame #0), we'll see something like 'R1=fp[0]-16', while "local stack pointer" will be just 'R2=fp-16'. Acked-by: Eduard Zingerman Acked-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231118034623.3320920-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 87105aa482ed..3505f3e5ae96 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -615,7 +615,9 @@ static bool type_is_map_ptr(enum bpf_reg_type t) { } } -static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_state *reg) +static void print_reg_state(struct bpf_verifier_env *env, + const struct bpf_func_state *state, + const struct bpf_reg_state *reg) { enum bpf_reg_type t; const char *sep = ""; @@ -623,10 +625,8 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s t = reg->type; if (t == SCALAR_VALUE && reg->precise) verbose(env, "P"); - if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && - tnum_is_const(reg->var_off)) { + if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) { /* reg->off should be 0 for SCALAR_VALUE */ - verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t)); verbose_snum(env, reg->var_off.value + reg->off); return; } @@ -637,6 +637,14 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s #define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, ##__VA_ARGS__); sep = ","; }) verbose(env, "%s", reg_type_str(env, t)); + if (t == PTR_TO_STACK) { + if (state->frameno != reg->frameno) + verbose(env, "[%d]", reg->frameno); + if (tnum_is_const(reg->var_off)) { + verbose_snum(env, reg->var_off.value + reg->off); + return; + } + } if (base_type(t) == PTR_TO_BTF_ID) verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); verbose(env, "("); @@ -698,7 +706,7 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st verbose(env, " R%d", i); print_liveness(env, reg->live); verbose(env, "="); - print_reg_state(env, reg); + print_reg_state(env, state, reg); } for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { char types_buf[BPF_REG_SIZE + 1]; @@ -731,7 +739,7 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); print_liveness(env, reg->live); verbose(env, "=%s", types_buf); - print_reg_state(env, reg); + print_reg_state(env, state, reg); break; case STACK_DYNPTR: /* skip to main dynptr slot */ From 484d4fbfdafea581fdc2fd04df6781c3a59122c9 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 12 Nov 2023 08:55:57 +0200 Subject: [PATCH 0908/7721] ovl: stop using d_alloc_anon()/d_instantiate_anon() Commit f9c34674bc60 ("vfs: factor out helpers d_instantiate_anon() and d_alloc_anon()") was introduced so overlayfs could initialize a non-dir disconnected overlay dentry before overlay inode is attached to it. Since commit ("0af950f57fef ovl: move ovl_entry into ovl_inode"), all ovl_obtain_alias() can do is set DCACHE_OP_*REVALIDATE flags in ->d_flags and OVL_E_UPPER_ALIAS flag in ->d_fsdata. The DCACHE_OP_*REVALIDATE flags and OVL_E_UPPER_ALIAS flag are irrelevant for a disconnected non-dir dentry, so it is better to use d_obtain_alias() instead of open coding it. Suggested-by: Al Viro Signed-off-by: Amir Goldstein Signed-off-by: Al Viro --- fs/overlayfs/export.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 7e16bbcad95e..9e316d5f936e 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -289,7 +289,6 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, { struct dentry *lower = lowerpath ? lowerpath->dentry : NULL; struct dentry *upper = upper_alias ?: index; - struct dentry *dentry; struct inode *inode = NULL; struct ovl_entry *oe; struct ovl_inode_params oip = { @@ -320,27 +319,7 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, if (upper) ovl_set_flag(OVL_UPPERDATA, inode); - dentry = d_find_any_alias(inode); - if (dentry) - goto out_iput; - - dentry = d_alloc_anon(inode->i_sb); - if (unlikely(!dentry)) - goto nomem; - - if (upper_alias) - ovl_dentry_set_upper_alias(dentry); - - ovl_dentry_init_reval(dentry, upper, OVL_I_E(inode)); - - return d_instantiate_anon(dentry, inode); - -nomem: - dput(dentry); - dentry = ERR_PTR(-ENOMEM); -out_iput: - iput(inode); - return dentry; + return d_obtain_alias(inode); } /* Get the upper or lower dentry in stack whose on layer @idx */ From acfde6e8abee6b23e53b08606f861d9124288030 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 4 Nov 2023 00:10:18 -0400 Subject: [PATCH 0909/7721] struct dentry: get rid of randomize_layout idiocy This is beyond ridiculous. There is a reason why that thing is cacheline-aligned... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- include/linux/dcache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 3da2f0545d5d..1d9f7f132055 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -111,7 +111,7 @@ struct dentry { struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */ struct rcu_head d_rcu; } d_u; -} __randomize_layout; +}; /* * dentry->d_lock spinlock nesting subclasses: From 6d73c9ce0285adff18b54a5acadfbbbf8ba40dd5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Oct 2023 13:41:06 -0400 Subject: [PATCH 0910/7721] get rid of __dget() fold into the sole remaining caller Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index c82ae731df9a..b8f1b54a1492 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -948,11 +948,6 @@ static inline void __dget_dlock(struct dentry *dentry) dentry->d_lockref.count++; } -static inline void __dget(struct dentry *dentry) -{ - lockref_get(&dentry->d_lockref); -} - struct dentry *dget_parent(struct dentry *dentry) { int gotref; @@ -1002,7 +997,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode) if (hlist_empty(&inode->i_dentry)) return NULL; alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); - __dget(alias); + lockref_get(&alias->d_lockref); return alias; } From 641c3ef5cb68a1426d42e6d3aba16db9bdfbe94f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 12:46:30 -0500 Subject: [PATCH 0911/7721] DCACHE_... ->d_flags bits: switch to BIT() For bits 20..22 (inode type cached in ->d_flags) turn the definitions into expressions like (5 << 20); everything else turns into straight use of BIT() Signed-off-by: Al Viro --- include/linux/dcache.h | 70 +++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 1d9f7f132055..d9c314cc93b8 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -151,13 +151,13 @@ struct dentry_operations { */ /* d_flags entries */ -#define DCACHE_OP_HASH 0x00000001 -#define DCACHE_OP_COMPARE 0x00000002 -#define DCACHE_OP_REVALIDATE 0x00000004 -#define DCACHE_OP_DELETE 0x00000008 -#define DCACHE_OP_PRUNE 0x00000010 +#define DCACHE_OP_HASH BIT(0) +#define DCACHE_OP_COMPARE BIT(1) +#define DCACHE_OP_REVALIDATE BIT(2) +#define DCACHE_OP_DELETE BIT(3) +#define DCACHE_OP_PRUNE BIT(4) -#define DCACHE_DISCONNECTED 0x00000020 +#define DCACHE_DISCONNECTED BIT(5) /* This dentry is possibly not currently connected to the dcache tree, in * which case its parent will either be itself, or will have this flag as * well. nfsd will not use a dentry with this bit set, but will first @@ -168,50 +168,50 @@ struct dentry_operations { * dentry into place and return that dentry rather than the passed one, * typically using d_splice_alias. */ -#define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */ +#define DCACHE_REFERENCED BIT(6) /* Recently used, don't discard. */ -#define DCACHE_DONTCACHE 0x00000080 /* Purge from memory on final dput() */ +#define DCACHE_DONTCACHE BIT(7) /* Purge from memory on final dput() */ -#define DCACHE_CANT_MOUNT 0x00000100 -#define DCACHE_GENOCIDE 0x00000200 -#define DCACHE_SHRINK_LIST 0x00000400 +#define DCACHE_CANT_MOUNT BIT(8) +#define DCACHE_GENOCIDE BIT(9) +#define DCACHE_SHRINK_LIST BIT(10) -#define DCACHE_OP_WEAK_REVALIDATE 0x00000800 +#define DCACHE_OP_WEAK_REVALIDATE BIT(11) -#define DCACHE_NFSFS_RENAMED 0x00001000 +#define DCACHE_NFSFS_RENAMED BIT(12) /* this dentry has been "silly renamed" and has to be deleted on the last * dput() */ -#define DCACHE_COOKIE 0x00002000 /* For use by dcookie subsystem */ -#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x00004000 +#define DCACHE_COOKIE BIT(13) /* For use by dcookie subsystem */ +#define DCACHE_FSNOTIFY_PARENT_WATCHED BIT(14) /* Parent inode is watched by some fsnotify listener */ -#define DCACHE_DENTRY_KILLED 0x00008000 +#define DCACHE_DENTRY_KILLED BIT(15) -#define DCACHE_MOUNTED 0x00010000 /* is a mountpoint */ -#define DCACHE_NEED_AUTOMOUNT 0x00020000 /* handle automount on this dir */ -#define DCACHE_MANAGE_TRANSIT 0x00040000 /* manage transit from this dirent */ +#define DCACHE_MOUNTED BIT(16) /* is a mountpoint */ +#define DCACHE_NEED_AUTOMOUNT BIT(17) /* handle automount on this dir */ +#define DCACHE_MANAGE_TRANSIT BIT(18) /* manage transit from this dirent */ #define DCACHE_MANAGED_DENTRY \ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) -#define DCACHE_LRU_LIST 0x00080000 +#define DCACHE_LRU_LIST BIT(19) -#define DCACHE_ENTRY_TYPE 0x00700000 -#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry (maybe fallthru to nowhere) */ -#define DCACHE_WHITEOUT_TYPE 0x00100000 /* Whiteout dentry (stop pathwalk) */ -#define DCACHE_DIRECTORY_TYPE 0x00200000 /* Normal directory */ -#define DCACHE_AUTODIR_TYPE 0x00300000 /* Lookupless directory (presumed automount) */ -#define DCACHE_REGULAR_TYPE 0x00400000 /* Regular file type (or fallthru to such) */ -#define DCACHE_SPECIAL_TYPE 0x00500000 /* Other file type (or fallthru to such) */ -#define DCACHE_SYMLINK_TYPE 0x00600000 /* Symlink (or fallthru to such) */ +#define DCACHE_ENTRY_TYPE (7 << 20) /* bits 20..22 are for storing type: */ +#define DCACHE_MISS_TYPE (0 << 20) /* Negative dentry (maybe fallthru to nowhere) */ +#define DCACHE_WHITEOUT_TYPE (1 << 20) /* Whiteout dentry (stop pathwalk) */ +#define DCACHE_DIRECTORY_TYPE (2 << 20) /* Normal directory */ +#define DCACHE_AUTODIR_TYPE (3 << 20) /* Lookupless directory (presumed automount) */ +#define DCACHE_REGULAR_TYPE (4 << 20) /* Regular file type (or fallthru to such) */ +#define DCACHE_SPECIAL_TYPE (5 << 20) /* Other file type (or fallthru to such) */ +#define DCACHE_SYMLINK_TYPE (6 << 20) /* Symlink (or fallthru to such) */ -#define DCACHE_MAY_FREE 0x00800000 -#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ -#define DCACHE_NOKEY_NAME 0x02000000 /* Encrypted name encoded without key */ -#define DCACHE_OP_REAL 0x04000000 +#define DCACHE_MAY_FREE BIT(23) +#define DCACHE_FALLTHRU BIT(24) /* Fall through to lower layer */ +#define DCACHE_NOKEY_NAME BIT(25) /* Encrypted name encoded without key */ +#define DCACHE_OP_REAL BIT(26) -#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ -#define DCACHE_DENTRY_CURSOR 0x20000000 -#define DCACHE_NORCU 0x40000000 /* No RCU delay for freeing */ +#define DCACHE_PAR_LOOKUP BIT(28) /* being looked up (with parent locked shared) */ +#define DCACHE_DENTRY_CURSOR BIT(29) +#define DCACHE_NORCU BIT(30) /* No RCU delay for freeing */ extern seqlock_t rename_lock; From 0bec65a80f1b1ebcda05286e539a204713b70353 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 12:50:29 -0500 Subject: [PATCH 0912/7721] DCACHE_COOKIE: RIP the last user gone in 2021... Signed-off-by: Al Viro --- include/linux/dcache.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index d9c314cc93b8..92c0b2a1ae2e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -181,7 +181,6 @@ struct dentry_operations { #define DCACHE_NFSFS_RENAMED BIT(12) /* this dentry has been "silly renamed" and has to be deleted on the last * dput() */ -#define DCACHE_COOKIE BIT(13) /* For use by dcookie subsystem */ #define DCACHE_FSNOTIFY_PARENT_WATCHED BIT(14) /* Parent inode is watched by some fsnotify listener */ From 8219cb58feddcf28909072015f4e17e29f68c41a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 14:32:05 -0500 Subject: [PATCH 0913/7721] kill d_{is,set}_fallthru() Introduced in 2015 and never had any in-tree users... Signed-off-by: Al Viro --- fs/dcache.c | 20 ++------------------ include/linux/dcache.h | 17 ++++------------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index b8f1b54a1492..9f5b2b5c1e6d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -344,7 +344,7 @@ static inline void __d_set_inode_and_type(struct dentry *dentry, dentry->d_inode = inode; flags = READ_ONCE(dentry->d_flags); - flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + flags &= ~DCACHE_ENTRY_TYPE; flags |= type_flags; smp_store_release(&dentry->d_flags, flags); } @@ -353,7 +353,7 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry) { unsigned flags = READ_ONCE(dentry->d_flags); - flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + flags &= ~DCACHE_ENTRY_TYPE; WRITE_ONCE(dentry->d_flags, flags); dentry->d_inode = NULL; if (dentry->d_flags & DCACHE_LRU_LIST) @@ -1936,22 +1936,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) } EXPORT_SYMBOL(d_set_d_op); - -/* - * d_set_fallthru - Mark a dentry as falling through to a lower layer - * @dentry - The dentry to mark - * - * Mark a dentry as falling through to the lower layer (as set with - * d_pin_lower()). This flag may be recorded on the medium. - */ -void d_set_fallthru(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_FALLTHRU; - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(d_set_fallthru); - static unsigned d_flags_for_inode(struct inode *inode) { unsigned add_flags = DCACHE_REGULAR_TYPE; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 92c0b2a1ae2e..8cd937bb2292 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -195,16 +195,15 @@ struct dentry_operations { #define DCACHE_LRU_LIST BIT(19) #define DCACHE_ENTRY_TYPE (7 << 20) /* bits 20..22 are for storing type: */ -#define DCACHE_MISS_TYPE (0 << 20) /* Negative dentry (maybe fallthru to nowhere) */ +#define DCACHE_MISS_TYPE (0 << 20) /* Negative dentry */ #define DCACHE_WHITEOUT_TYPE (1 << 20) /* Whiteout dentry (stop pathwalk) */ #define DCACHE_DIRECTORY_TYPE (2 << 20) /* Normal directory */ #define DCACHE_AUTODIR_TYPE (3 << 20) /* Lookupless directory (presumed automount) */ -#define DCACHE_REGULAR_TYPE (4 << 20) /* Regular file type (or fallthru to such) */ -#define DCACHE_SPECIAL_TYPE (5 << 20) /* Other file type (or fallthru to such) */ -#define DCACHE_SYMLINK_TYPE (6 << 20) /* Symlink (or fallthru to such) */ +#define DCACHE_REGULAR_TYPE (4 << 20) /* Regular file type */ +#define DCACHE_SPECIAL_TYPE (5 << 20) /* Other file type */ +#define DCACHE_SYMLINK_TYPE (6 << 20) /* Symlink */ #define DCACHE_MAY_FREE BIT(23) -#define DCACHE_FALLTHRU BIT(24) /* Fall through to lower layer */ #define DCACHE_NOKEY_NAME BIT(25) /* Encrypted name encoded without key */ #define DCACHE_OP_REAL BIT(26) @@ -489,14 +488,6 @@ static inline int simple_positive(const struct dentry *dentry) return d_really_is_positive(dentry) && !d_unhashed(dentry); } -extern void d_set_fallthru(struct dentry *dentry); - -static inline bool d_is_fallthru(const struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_FALLTHRU; -} - - extern int sysctl_vfs_cache_pressure; static inline unsigned long vfs_pressure_ratio(unsigned long val) From 0d486510f86eb8162022ed61e6dc424a10909a10 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 15:22:40 -0500 Subject: [PATCH 0914/7721] dentry.h: trim externs d_instantiate_unique() had been gone for 7 years; __d_lookup...() and shrink_dcache_for_umount() are fs/internal.h fodder. Signed-off-by: Al Viro --- fs/internal.h | 4 ++++ include/linux/dcache.h | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index 58e43341aebf..9e9fc629f935 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -215,6 +215,10 @@ extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *) extern char *simple_dname(struct dentry *, char *, int); extern void dput_to_list(struct dentry *, struct list_head *); extern void shrink_dentry_list(struct list_head *); +extern void shrink_dcache_for_umount(struct super_block *); +extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); +extern struct dentry *__d_lookup_rcu(const struct dentry *parent, + const struct qstr *name, unsigned *seq); /* * pipe.c diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 8cd937bb2292..9706bf1dc5de 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -218,7 +218,6 @@ extern seqlock_t rename_lock; */ extern void d_instantiate(struct dentry *, struct inode *); extern void d_instantiate_new(struct dentry *, struct inode *); -extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *); extern void __d_drop(struct dentry *dentry); extern void d_drop(struct dentry *dentry); @@ -240,7 +239,6 @@ extern struct dentry * d_obtain_alias(struct inode *); extern struct dentry * d_obtain_root(struct inode *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); -extern void shrink_dcache_for_umount(struct super_block *); extern void d_invalidate(struct dentry *); /* only used at mount-time */ @@ -275,9 +273,6 @@ extern struct dentry *d_ancestor(struct dentry *, struct dentry *); /* appendix may either be NULL or be used for transname suffixes */ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *); extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *); -extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); -extern struct dentry *__d_lookup_rcu(const struct dentry *parent, - const struct qstr *name, unsigned *seq); static inline unsigned d_count(const struct dentry *dentry) { From 2fcd38f4de7256e2b5cb23ad22a6e3ebfea7dd18 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 15:24:45 -0500 Subject: [PATCH 0915/7721] [software coproarchaeology] dentry.h: kill a mysterious comment there's a strange comment in front of d_lookup() declaration: /* appendix may either be NULL or be used for transname suffixes */ Looks like nobody had been curious enough to track its history; it predates git, it predates bitkeeper and if you look through the pre-BK trees, you finally arrive at this in 2.1.44-for-davem: /* appendix may either be NULL or be used for transname suffixes */ -extern struct dentry * d_lookup(struct inode * dir, struct qstr * name, - struct qstr * appendix); +extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name); In other words, it refers to the third argument d_lookup() used to have back then. It had been introduced in 2.1.43-pre, on June 12 1997, along with d_lookup(), only to be removed by July 4 1997, presumably when the Cthulhu-awful thing it used to be used for (look for CONFIG_TRANS_NAMES in 2.1.43-pre, and keep a heavy-duty barfbag ready) had been, er, noticed and recognized for what it had been. Despite the appendectomy, the comment remained. Some things really need to be put out of their misery... Signed-off-by: Al Viro --- include/linux/dcache.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 9706bf1dc5de..a5e5e274eee0 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -270,7 +270,6 @@ extern void d_move(struct dentry *, struct dentry *); extern void d_exchange(struct dentry *, struct dentry *); extern struct dentry *d_ancestor(struct dentry *, struct dentry *); -/* appendix may either be NULL or be used for transname suffixes */ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *); extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *); From 698f1e2b71736977b04f951e2e2ef1c9a80696ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 16:19:59 -0500 Subject: [PATCH 0916/7721] kill d_backing_dentry() no users left Signed-off-by: Al Viro --- include/linux/dcache.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index a5e5e274eee0..fa0414cff85c 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -530,21 +530,6 @@ static inline struct inode *d_backing_inode(const struct dentry *upper) return inode; } -/** - * d_backing_dentry - Get upper or lower dentry we should be using - * @upper: The upper layer - * - * This is the helper that should be used to get the dentry of the inode that - * will be used if this dentry were opened as a file. It may be the upper - * dentry or it may be a lower dentry pinned by the upper. - * - * Normal filesystems should not use this to access their own dentries. - */ -static inline struct dentry *d_backing_dentry(struct dentry *upper) -{ - return upper; -} - /** * d_real - Return the real dentry * @dentry: the dentry to query From 3589e6d9f6e929339692585d1169f149e789d229 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 20 Oct 2023 15:57:05 +0100 Subject: [PATCH 0917/7721] dt-bindings: arm: sunxi: add Orange Pi Zero 2W The Orange Pi Zero 2W is a small board with an Allwinner H618 SoC. Add the compatible string to the binding documents. Signed-off-by: Andre Przywara Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231020145706.705420-2-andre.przywara@arm.com Signed-off-by: Jernej Skrabec --- Documentation/devicetree/bindings/arm/sunxi.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 11c5ce941dd7..6f481e8bb4bf 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -1013,6 +1013,11 @@ properties: - const: xunlong,orangepi-zero2 - const: allwinner,sun50i-h616 + - description: Xunlong OrangePi Zero 2W + items: + - const: xunlong,orangepi-zero2w + - const: allwinner,sun50i-h618 + - description: Xunlong OrangePi Zero 3 items: - const: xunlong,orangepi-zero3 From c505ee1eae18fb7b32d792e4470d5ef1934376bd Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 20 Oct 2023 15:57:06 +0100 Subject: [PATCH 0918/7721] arm64: dts: allwinner: h616: add Orange Pi Zero 2W support The Orange Pi Zero 2W is a board based on the Allwinner H618 SoC. It uses the RaspberryPi Zero form factor, with an optional expansion board, connected via an FPC connector, to provide more connectors. The base board features: - Allwinner H618 SoC (quad Cortex-A53 cores, with 1MB L2 cache) - 1, 2 or 4GB of LPDDR4 DRAM - SD card socket - two USB-C sockets, one UFP, one DFP - HDMI connector - (yet unsupported) WiFi module - 16 MiB SPI flash - power supply via the UFP USB-C port The FPC connector provides access to two more USB host ports, Fast Ethernet, some GPIOs, Audio Line out and the IR receiver pin. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/20231020145706.705420-3-andre.przywara@arm.com Signed-off-by: Jernej Skrabec --- .../allwinner/sun50i-h618-orangepi-zero2w.dts | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts new file mode 100644 index 000000000000..21ca1977055d --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Arm Ltd. + */ + +/dts-v1/; + +#include "sun50i-h616.dtsi" + +#include +#include +#include + +/ { + model = "OrangePi Zero 2W"; + compatible = "xunlong,orangepi-zero2w", "allwinner,sun50i-h618"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */ + }; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the USB-C socket */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_vcc3v3: vcc3v3 { + /* SY8089 DC/DC converter */ + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_vcc5v>; + regulator-always-on; + }; +}; + +&ehci1 { + status = "okay"; +}; + +/* USB 2 & 3 are on the FPC connector (or the exansion board) */ + +&mmc0 { + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + bus-width = <4>; + vmmc-supply = <®_vcc3v3>; + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&pio { + vcc-pc-supply = <®_dldo1>; + vcc-pf-supply = <®_dldo1>; /* internally via VCC-IO */ + vcc-pg-supply = <®_aldo1>; + vcc-ph-supply = <®_dldo1>; /* internally via VCC-IO */ + vcc-pi-supply = <®_dldo1>; +}; + +&r_i2c { + status = "okay"; + + axp313: pmic@36 { + compatible = "x-powers,axp313a"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&pio>; + interrupts = <2 9 IRQ_TYPE_LEVEL_LOW>; /* PC9 */ + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + /* Supplies VCC-PLL and DRAM */ + reg_aldo1: aldo1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc1v8"; + }; + + /* Supplies VCC-IO, so needs to be always on. */ + reg_dldo1: dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3"; + }; + + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <990000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-cpu"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-dram"; + }; + }; + }; +}; + +&spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>, <&spi0_cs0_pin>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; + status = "okay"; +}; + +&usbotg { + /* + * PHY0 pins are connected to a USB-C socket, but a role switch + * is not implemented: both CC pins are pulled to GND. + * The VBUS pins power the device, so a fixed peripheral mode + * is the best choice. + * The board can be powered via GPIOs, in this case port0 *can* + * act as a host (with a cable/adapter ignoring CC), as VBUS is + * then provided by the GPIOs. Any user of this setup would + * need to adjust the DT accordingly: dr_mode set to "host", + * enabling OHCI0 and EHCI0. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + usb1_vbus-supply = <®_vcc5v>; + status = "okay"; +}; From 055dd7511f675d26fa283b35bb3dadfc7f77ed97 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 13 Nov 2023 20:13:26 +0100 Subject: [PATCH 0919/7721] r8169: improve RTL8411b phy-down fixup Mirsad proposed a patch to reduce the number of spinlock lock/unlock operations and the function code size. This can be further improved because the function sets a consecutive register block. Suggested-by: Mirsad Todorovac Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Reviewed-by: Mirsad Todorovac Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 139 +++++----------------- 1 file changed, 28 insertions(+), 111 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index b9bb1d2f0237..a8b623145efc 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -3102,6 +3102,33 @@ static void rtl_hw_start_8168g_2(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168g_2); } +static void rtl8411b_fix_phy_down(struct rtl8169_private *tp) +{ + static const u16 fix_data[] = { +/* 0xf800 */ 0xe008, 0xe00a, 0xe00c, 0xe00e, 0xe027, 0xe04f, 0xe05e, 0xe065, +/* 0xf810 */ 0xc602, 0xbe00, 0x0000, 0xc502, 0xbd00, 0x074c, 0xc302, 0xbb00, +/* 0xf820 */ 0x080a, 0x6420, 0x48c2, 0x8c20, 0xc516, 0x64a4, 0x49c0, 0xf009, +/* 0xf830 */ 0x74a2, 0x8ca5, 0x74a0, 0xc50e, 0x9ca2, 0x1c11, 0x9ca0, 0xe006, +/* 0xf840 */ 0x74f8, 0x48c4, 0x8cf8, 0xc404, 0xbc00, 0xc403, 0xbc00, 0x0bf2, +/* 0xf850 */ 0x0c0a, 0xe434, 0xd3c0, 0x49d9, 0xf01f, 0xc526, 0x64a5, 0x1400, +/* 0xf860 */ 0xf007, 0x0c01, 0x8ca5, 0x1c15, 0xc51b, 0x9ca0, 0xe013, 0xc519, +/* 0xf870 */ 0x74a0, 0x48c4, 0x8ca0, 0xc516, 0x74a4, 0x48c8, 0x48ca, 0x9ca4, +/* 0xf880 */ 0xc512, 0x1b00, 0x9ba0, 0x1b1c, 0x483f, 0x9ba2, 0x1b04, 0xc508, +/* 0xf890 */ 0x9ba0, 0xc505, 0xbd00, 0xc502, 0xbd00, 0x0300, 0x051e, 0xe434, +/* 0xf8a0 */ 0xe018, 0xe092, 0xde20, 0xd3c0, 0xc50f, 0x76a4, 0x49e3, 0xf007, +/* 0xf8b0 */ 0x49c0, 0xf103, 0xc607, 0xbe00, 0xc606, 0xbe00, 0xc602, 0xbe00, +/* 0xf8c0 */ 0x0c4c, 0x0c28, 0x0c2c, 0xdc00, 0xc707, 0x1d00, 0x8de2, 0x48c1, +/* 0xf8d0 */ 0xc502, 0xbd00, 0x00aa, 0xe0c0, 0xc502, 0xbd00, 0x0132 + }; + unsigned long flags; + int i; + + raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags); + for (i = 0; i < ARRAY_SIZE(fix_data); i++) + __r8168_mac_ocp_write(tp, 0xf800 + 2 * i, fix_data[i]); + raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); +} + static void rtl_hw_start_8411_2(struct rtl8169_private *tp) { static const struct ephy_info e_info_8411_2[] = { @@ -3135,117 +3162,7 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp) mdelay(3); r8168_mac_ocp_write(tp, 0xFC26, 0x0000); - r8168_mac_ocp_write(tp, 0xF800, 0xE008); - r8168_mac_ocp_write(tp, 0xF802, 0xE00A); - r8168_mac_ocp_write(tp, 0xF804, 0xE00C); - r8168_mac_ocp_write(tp, 0xF806, 0xE00E); - r8168_mac_ocp_write(tp, 0xF808, 0xE027); - r8168_mac_ocp_write(tp, 0xF80A, 0xE04F); - r8168_mac_ocp_write(tp, 0xF80C, 0xE05E); - r8168_mac_ocp_write(tp, 0xF80E, 0xE065); - r8168_mac_ocp_write(tp, 0xF810, 0xC602); - r8168_mac_ocp_write(tp, 0xF812, 0xBE00); - r8168_mac_ocp_write(tp, 0xF814, 0x0000); - r8168_mac_ocp_write(tp, 0xF816, 0xC502); - r8168_mac_ocp_write(tp, 0xF818, 0xBD00); - r8168_mac_ocp_write(tp, 0xF81A, 0x074C); - r8168_mac_ocp_write(tp, 0xF81C, 0xC302); - r8168_mac_ocp_write(tp, 0xF81E, 0xBB00); - r8168_mac_ocp_write(tp, 0xF820, 0x080A); - r8168_mac_ocp_write(tp, 0xF822, 0x6420); - r8168_mac_ocp_write(tp, 0xF824, 0x48C2); - r8168_mac_ocp_write(tp, 0xF826, 0x8C20); - r8168_mac_ocp_write(tp, 0xF828, 0xC516); - r8168_mac_ocp_write(tp, 0xF82A, 0x64A4); - r8168_mac_ocp_write(tp, 0xF82C, 0x49C0); - r8168_mac_ocp_write(tp, 0xF82E, 0xF009); - r8168_mac_ocp_write(tp, 0xF830, 0x74A2); - r8168_mac_ocp_write(tp, 0xF832, 0x8CA5); - r8168_mac_ocp_write(tp, 0xF834, 0x74A0); - r8168_mac_ocp_write(tp, 0xF836, 0xC50E); - r8168_mac_ocp_write(tp, 0xF838, 0x9CA2); - r8168_mac_ocp_write(tp, 0xF83A, 0x1C11); - r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0); - r8168_mac_ocp_write(tp, 0xF83E, 0xE006); - r8168_mac_ocp_write(tp, 0xF840, 0x74F8); - r8168_mac_ocp_write(tp, 0xF842, 0x48C4); - r8168_mac_ocp_write(tp, 0xF844, 0x8CF8); - r8168_mac_ocp_write(tp, 0xF846, 0xC404); - r8168_mac_ocp_write(tp, 0xF848, 0xBC00); - r8168_mac_ocp_write(tp, 0xF84A, 0xC403); - r8168_mac_ocp_write(tp, 0xF84C, 0xBC00); - r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2); - r8168_mac_ocp_write(tp, 0xF850, 0x0C0A); - r8168_mac_ocp_write(tp, 0xF852, 0xE434); - r8168_mac_ocp_write(tp, 0xF854, 0xD3C0); - r8168_mac_ocp_write(tp, 0xF856, 0x49D9); - r8168_mac_ocp_write(tp, 0xF858, 0xF01F); - r8168_mac_ocp_write(tp, 0xF85A, 0xC526); - r8168_mac_ocp_write(tp, 0xF85C, 0x64A5); - r8168_mac_ocp_write(tp, 0xF85E, 0x1400); - r8168_mac_ocp_write(tp, 0xF860, 0xF007); - r8168_mac_ocp_write(tp, 0xF862, 0x0C01); - r8168_mac_ocp_write(tp, 0xF864, 0x8CA5); - r8168_mac_ocp_write(tp, 0xF866, 0x1C15); - r8168_mac_ocp_write(tp, 0xF868, 0xC51B); - r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0); - r8168_mac_ocp_write(tp, 0xF86C, 0xE013); - r8168_mac_ocp_write(tp, 0xF86E, 0xC519); - r8168_mac_ocp_write(tp, 0xF870, 0x74A0); - r8168_mac_ocp_write(tp, 0xF872, 0x48C4); - r8168_mac_ocp_write(tp, 0xF874, 0x8CA0); - r8168_mac_ocp_write(tp, 0xF876, 0xC516); - r8168_mac_ocp_write(tp, 0xF878, 0x74A4); - r8168_mac_ocp_write(tp, 0xF87A, 0x48C8); - r8168_mac_ocp_write(tp, 0xF87C, 0x48CA); - r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4); - r8168_mac_ocp_write(tp, 0xF880, 0xC512); - r8168_mac_ocp_write(tp, 0xF882, 0x1B00); - r8168_mac_ocp_write(tp, 0xF884, 0x9BA0); - r8168_mac_ocp_write(tp, 0xF886, 0x1B1C); - r8168_mac_ocp_write(tp, 0xF888, 0x483F); - r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2); - r8168_mac_ocp_write(tp, 0xF88C, 0x1B04); - r8168_mac_ocp_write(tp, 0xF88E, 0xC508); - r8168_mac_ocp_write(tp, 0xF890, 0x9BA0); - r8168_mac_ocp_write(tp, 0xF892, 0xC505); - r8168_mac_ocp_write(tp, 0xF894, 0xBD00); - r8168_mac_ocp_write(tp, 0xF896, 0xC502); - r8168_mac_ocp_write(tp, 0xF898, 0xBD00); - r8168_mac_ocp_write(tp, 0xF89A, 0x0300); - r8168_mac_ocp_write(tp, 0xF89C, 0x051E); - r8168_mac_ocp_write(tp, 0xF89E, 0xE434); - r8168_mac_ocp_write(tp, 0xF8A0, 0xE018); - r8168_mac_ocp_write(tp, 0xF8A2, 0xE092); - r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20); - r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0); - r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F); - r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4); - r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3); - r8168_mac_ocp_write(tp, 0xF8AE, 0xF007); - r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0); - r8168_mac_ocp_write(tp, 0xF8B2, 0xF103); - r8168_mac_ocp_write(tp, 0xF8B4, 0xC607); - r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00); - r8168_mac_ocp_write(tp, 0xF8B8, 0xC606); - r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00); - r8168_mac_ocp_write(tp, 0xF8BC, 0xC602); - r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00); - r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C); - r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28); - r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C); - r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00); - r8168_mac_ocp_write(tp, 0xF8C8, 0xC707); - r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00); - r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2); - r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1); - r8168_mac_ocp_write(tp, 0xF8D0, 0xC502); - r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00); - r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA); - r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0); - r8168_mac_ocp_write(tp, 0xF8D8, 0xC502); - r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00); - r8168_mac_ocp_write(tp, 0xF8DC, 0x0132); + rtl8411b_fix_phy_down(tp); r8168_mac_ocp_write(tp, 0xFC26, 0x8000); From 89e00444cb894a42c33ba88738eaae788b05b924 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 23 Oct 2023 14:35:02 +0100 Subject: [PATCH 0920/7721] clk: sunxi-ng: nkm: remove redundant initialization of tmp_parent Variable tmp_parent is being ininitialized with a value that is never read, the initialization is redundant and can be removed. Move the initialization and move the variable to the inner loop scope. Signed-off-by: Colin Ian King Reviewed-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/20231023133502.666559-1-colin.i.king@gmail.com Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi-ng/ccu_nkm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index eed64547ad42..853f84398e2b 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -21,17 +21,16 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common unsigned long *parent, unsigned long rate, struct _ccu_nkm *nkm) { - unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent; + unsigned long best_rate = 0, best_parent_rate = *parent; unsigned long best_n = 0, best_k = 0, best_m = 0; unsigned long _n, _k, _m; for (_k = nkm->min_k; _k <= nkm->max_k; _k++) { for (_n = nkm->min_n; _n <= nkm->max_n; _n++) { for (_m = nkm->min_m; _m <= nkm->max_m; _m++) { - unsigned long tmp_rate; + unsigned long tmp_rate, tmp_parent; tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k)); - tmp_rate = tmp_parent * _n * _k / _m; if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) || From b7a14708aafeb12730ab23de8ecedd14f401a30c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Nov 2023 14:35:16 -0400 Subject: [PATCH 0921/7721] switch nfsd_client_rmdir() to use of simple_recursive_removal() nfsd_client_rmdir() open-codes a subset of simple_recursive_removal(). Conversion to calling simple_recursive_removal() allows to clean things up quite a bit. While we are at it, nfsdfs_create_files() doesn't need to mess with "pick the reference to struct nfsdfs_client from the already created parent" - the caller already knows it (that's where the parent got it from, after all), so we might as well just pass it as an explicit argument. So __get_nfsdfs_client() is only needed in get_nfsdfs_client() and can be folded in there. Incidentally, the locking in get_nfsdfs_client() is too heavy - we don't need ->i_rwsem for that, ->i_lock serves just fine. Reviewed-by: Jeff Layton Tested-by: Jeff Layton Acked-by: Chuck Lever Acked-by: Christian Brauner Signed-off-by: Al Viro --- fs/nfsd/nfsctl.c | 70 ++++++++++-------------------------------------- 1 file changed, 14 insertions(+), 56 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 3e15b72f421d..50df5e9d0069 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1236,63 +1236,34 @@ static inline void _nfsd_symlink(struct dentry *parent, const char *name, #endif -static void clear_ncl(struct inode *inode) +static void clear_ncl(struct dentry *dentry) { + struct inode *inode = d_inode(dentry); struct nfsdfs_client *ncl = inode->i_private; + spin_lock(&inode->i_lock); inode->i_private = NULL; + spin_unlock(&inode->i_lock); kref_put(&ncl->cl_ref, ncl->cl_release); } -static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode) -{ - struct nfsdfs_client *nc = inode->i_private; - - if (nc) - kref_get(&nc->cl_ref); - return nc; -} - struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) { struct nfsdfs_client *nc; - inode_lock_shared(inode); - nc = __get_nfsdfs_client(inode); - inode_unlock_shared(inode); + spin_lock(&inode->i_lock); + nc = inode->i_private; + if (nc) + kref_get(&nc->cl_ref); + spin_unlock(&inode->i_lock); return nc; } -/* from __rpc_unlink */ -static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry) -{ - int ret; - - clear_ncl(d_inode(dentry)); - dget(dentry); - ret = simple_unlink(dir, dentry); - d_drop(dentry); - fsnotify_unlink(dir, dentry); - dput(dentry); - WARN_ON_ONCE(ret); -} - -static void nfsdfs_remove_files(struct dentry *root) -{ - struct dentry *dentry, *tmp; - - list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) { - if (!simple_positive(dentry)) { - WARN_ON_ONCE(1); /* I think this can't happen? */ - continue; - } - nfsdfs_remove_file(d_inode(root), dentry); - } -} /* XXX: cut'n'paste from simple_fill_super; figure out if we could share * code instead. */ static int nfsdfs_create_files(struct dentry *root, const struct tree_descr *files, + struct nfsdfs_client *ncl, struct dentry **fdentries) { struct inode *dir = d_inode(root); @@ -1311,8 +1282,9 @@ static int nfsdfs_create_files(struct dentry *root, dput(dentry); goto out; } + kref_get(&ncl->cl_ref); inode->i_fop = files->ops; - inode->i_private = __get_nfsdfs_client(dir); + inode->i_private = ncl; d_add(dentry, inode); fsnotify_create(dir, dentry); if (fdentries) @@ -1321,7 +1293,6 @@ static int nfsdfs_create_files(struct dentry *root, inode_unlock(dir); return 0; out: - nfsdfs_remove_files(root); inode_unlock(dir); return -ENOMEM; } @@ -1341,7 +1312,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); if (IS_ERR(dentry)) /* XXX: tossing errors? */ return NULL; - ret = nfsdfs_create_files(dentry, files, fdentries); + ret = nfsdfs_create_files(dentry, files, ncl, fdentries); if (ret) { nfsd_client_rmdir(dentry); return NULL; @@ -1352,20 +1323,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, /* Taken from __rpc_rmdir: */ void nfsd_client_rmdir(struct dentry *dentry) { - struct inode *dir = d_inode(dentry->d_parent); - struct inode *inode = d_inode(dentry); - int ret; - - inode_lock(dir); - nfsdfs_remove_files(dentry); - clear_ncl(inode); - dget(dentry); - ret = simple_rmdir(dir, dentry); - WARN_ON_ONCE(ret); - d_drop(dentry); - fsnotify_rmdir(dir, dentry); - dput(dentry); - inode_unlock(dir); + simple_recursive_removal(dentry, clear_ncl); } static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) From 289354f21b2c3fac93e956efd45f256a88a4d997 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 18 Nov 2023 18:38:05 -0800 Subject: [PATCH 0922/7721] net: partial revert of the "Make timestamping selectable: series Revert following commits: commit acec05fb78ab ("net_tstamp: Add TIMESTAMPING SOFTWARE and HARDWARE mask") commit 11d55be06df0 ("net: ethtool: Add a command to expose current time stamping layer") commit bb8645b00ced ("netlink: specs: Introduce new netlink command to get current timestamp") commit d905f9c75329 ("net: ethtool: Add a command to list available time stamping layers") commit aed5004ee7a0 ("netlink: specs: Introduce new netlink command to list available time stamping layers") commit 51bdf3165f01 ("net: Replace hwtstamp_source by timestamping layer") commit 0f7f463d4821 ("net: Change the API of PHY default timestamp to MAC") commit 091fab122869 ("net: ethtool: ts: Update GET_TS to reply the current selected timestamp") commit 152c75e1d002 ("net: ethtool: ts: Let the active time stamping layer be selectable") commit ee60ea6be0d3 ("netlink: specs: Introduce time stamping set command") They need more time for reviews. Link: https://lore.kernel.org/all/20231118183529.6e67100c@kernel.org/ Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/ethtool.yaml | 57 ---- Documentation/networking/ethtool-netlink.rst | 63 ----- .../ethernet/microchip/lan966x/lan966x_main.c | 6 +- drivers/net/phy/bcm-phy-ptp.c | 3 - drivers/net/phy/dp83640.c | 3 - drivers/net/phy/micrel.c | 6 - drivers/net/phy/mscc/mscc_ptp.c | 2 - drivers/net/phy/nxp-c45-tja11xx.c | 3 - drivers/net/phy/phy_device.c | 37 --- include/linux/net_tstamp.h | 11 +- include/linux/netdevice.h | 5 - include/linux/phy.h | 4 - include/uapi/linux/ethtool_netlink.h | 29 --- include/uapi/linux/net_tstamp.h | 18 -- net/core/dev.c | 3 - net/core/dev_ioctl.c | 36 +-- net/core/timestamping.c | 10 - net/ethtool/Makefile | 2 +- net/ethtool/common.c | 19 +- net/ethtool/common.h | 1 - net/ethtool/netlink.c | 28 -- net/ethtool/netlink.h | 4 - net/ethtool/ts.c | 244 ------------------ 23 files changed, 28 insertions(+), 566 deletions(-) delete mode 100644 net/ethtool/ts.c diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 06d9120543d3..5c7a65b009b4 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -939,26 +939,6 @@ attribute-sets: - name: burst-tmr type: u32 - - - name: ts - attributes: - - - name: header - type: nest - nested-attributes: header - - - name: ts-layer - type: u32 - - - name: ts-list - attributes: - - - name: header - type: nest - nested-attributes: header - - - name: ts-list-layer - type: binary operations: enum-model: directional @@ -1709,40 +1689,3 @@ operations: name: mm-ntf doc: Notification for change in MAC Merge configuration. notify: mm-get - - - name: ts-get - doc: Get current timestamp - - attribute-set: ts - - do: - request: - attributes: - - header - reply: - attributes: &ts - - header - - ts-layer - - - name: ts-list-get - doc: Get list of timestamp devices available on an interface - - attribute-set: ts-list - - do: - request: - attributes: - - header - reply: - attributes: - - header - - ts-list-layer - - - name: ts-set - doc: Set the timestamp device - - attribute-set: ts - - do: - request: - attributes: *ts diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 530c1775e5f4..2540c70952ff 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -225,9 +225,6 @@ Userspace to kernel: ``ETHTOOL_MSG_RSS_GET`` get RSS settings ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters - ``ETHTOOL_MSG_TS_GET`` get current timestamping - ``ETHTOOL_MSG_TS_LIST_GET`` list available timestampings - ``ETHTOOL_MSG_TS_SET`` set current timestamping ===================================== ================================= Kernel to userspace: @@ -271,8 +268,6 @@ Kernel to userspace: ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status - ``ETHTOOL_MSG_TS_GET_REPLY`` current timestamping - ``ETHTOOL_MSG_TS_LIST_GET_REPLY`` available timestampings ======================================== ================================= ``GET`` requests are sent by userspace applications to retrieve device @@ -1999,61 +1994,6 @@ The attributes are propagated to the driver through the following structure: .. kernel-doc:: include/linux/ethtool.h :identifiers: ethtool_mm_cfg -TS_GET -====== - -Gets current timestamping. - -Request contents: - - ================================= ====== ==================== - ``ETHTOOL_A_TS_HEADER`` nested request header - ================================= ====== ==================== - -Kernel response contents: - - ======================= ====== ============================== - ``ETHTOOL_A_TS_HEADER`` nested reply header - ``ETHTOOL_A_TS_LAYER`` u32 current timestamping - ======================= ====== ============================== - -This command get the current timestamp layer. - -TS_LIST_GET -=========== - -Get the list of available timestampings. - -Request contents: - - ================================= ====== ==================== - ``ETHTOOL_A_TS_HEADER`` nested request header - ================================= ====== ==================== - -Kernel response contents: - - =========================== ====== ============================== - ``ETHTOOL_A_TS_HEADER`` nested reply header - ``ETHTOOL_A_TS_LIST_LAYER`` binary available timestampings - =========================== ====== ============================== - -This command lists all the possible timestamp layer available. - -TS_SET -====== - -Modify the selected timestamping. - -Request contents: - - ======================= ====== =================== - ``ETHTOOL_A_TS_HEADER`` nested reply header - ``ETHTOOL_A_TS_LAYER`` u32 timestamping - ======================= ====== =================== - -This command set the timestamping with one that should be listed by the -TSLIST_GET command. - Request translation =================== @@ -2160,7 +2100,4 @@ are netlink only. n/a ``ETHTOOL_MSG_PLCA_GET_STATUS`` n/a ``ETHTOOL_MSG_MM_GET`` n/a ``ETHTOOL_MSG_MM_SET`` - n/a ``ETHTOOL_MSG_TS_GET`` - n/a ``ETHTOOL_MSG_TS_LIST_GET`` - n/a ``ETHTOOL_MSG_TS_SET`` =================================== ===================================== diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index fbe56b1bb386..2635ef8958c8 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -470,15 +470,15 @@ static int lan966x_port_hwtstamp_set(struct net_device *dev, struct lan966x_port *port = netdev_priv(dev); int err; - if (cfg->source != MAC_TIMESTAMPING && - cfg->source != PHY_TIMESTAMPING) + if (cfg->source != HWTSTAMP_SOURCE_NETDEV && + cfg->source != HWTSTAMP_SOURCE_PHYLIB) return -EOPNOTSUPP; err = lan966x_ptp_setup_traps(port, cfg); if (err) return err; - if (cfg->source == MAC_TIMESTAMPING) { + if (cfg->source == HWTSTAMP_SOURCE_NETDEV) { if (!port->lan966x->ptp) return -EOPNOTSUPP; diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c index d3e825c951ee..617d384d4551 100644 --- a/drivers/net/phy/bcm-phy-ptp.c +++ b/drivers/net/phy/bcm-phy-ptp.c @@ -931,9 +931,6 @@ struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev) return ERR_CAST(clock); priv->ptp_clock = clock; - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; - priv->phydev = phydev; bcm_ptp_init(priv); diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 64fd1a109c0f..5c42c47dc564 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1450,9 +1450,6 @@ static int dp83640_probe(struct phy_device *phydev) phydev->mii_ts = &dp83640->mii_ts; phydev->priv = dp83640; - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; - spin_lock_init(&dp83640->rx_lock); skb_queue_head_init(&dp83640->rx_queue); skb_queue_head_init(&dp83640->tx_queue); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2b8dd0131926..bd4cd082662f 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -3158,9 +3158,6 @@ static void lan8814_ptp_init(struct phy_device *phydev) ptp_priv->mii_ts.ts_info = lan8814_ts_info; phydev->mii_ts = &ptp_priv->mii_ts; - - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; } static int lan8814_ptp_probe_once(struct phy_device *phydev) @@ -4589,9 +4586,6 @@ static int lan8841_probe(struct phy_device *phydev) phydev->mii_ts = &ptp_priv->mii_ts; - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; - return 0; } diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index fd174eb06d4a..eb0b032cb613 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -1570,8 +1570,6 @@ int vsc8584_ptp_probe(struct phy_device *phydev) return PTR_ERR(vsc8531->load_save); } - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; vsc8531->ptp->phydev = phydev; return 0; diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 0515c7b979db..780ad353cf55 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -1658,9 +1658,6 @@ static int nxp_c45_probe(struct phy_device *phydev) priv->mii_ts.ts_info = nxp_c45_ts_info; phydev->mii_ts = &priv->mii_ts; ret = nxp_c45_init_ptp_clock(priv); - - /* Timestamp selected by default to keep legacy API */ - phydev->default_timestamp = true; } else { phydev_dbg(phydev, "PTP support not enabled even if the phy supports it"); } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8c4794631daa..2ce74593d6e4 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1411,26 +1411,6 @@ int phy_sfp_probe(struct phy_device *phydev, } EXPORT_SYMBOL(phy_sfp_probe); -/** - * phy_set_timestamp - set the default selected timestamping device - * @dev: Pointer to net_device - * @phydev: Pointer to phy_device - * - * This is used to set default timestamping device taking into account - * the new API choice, which is selecting the timestamping from MAC by - * default if the phydev does not have default_timestamp flag enabled. - */ -static void phy_set_timestamp(struct net_device *dev, struct phy_device *phydev) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (!phy_has_tsinfo(phydev)) - return; - - if (!ops->get_ts_info || phydev->default_timestamp) - dev->ts_layer = PHY_TIMESTAMPING; -} - /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1504,7 +1484,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->phy_link_change = phy_link_change; if (dev) { - phy_set_timestamp(dev, phydev); phydev->attached_dev = dev; dev->phydev = phydev; @@ -1833,22 +1812,6 @@ void phy_detach(struct phy_device *phydev) phy_suspend(phydev); if (dev) { - const struct ethtool_ops *ops = dev->ethtool_ops; - struct ethtool_ts_info ts_info = {0}; - - if (ops->get_ts_info) { - ops->get_ts_info(dev, &ts_info); - if ((ts_info.so_timestamping & - SOF_TIMESTAMPING_HARDWARE_MASK) == - SOF_TIMESTAMPING_HARDWARE_MASK) - dev->ts_layer = MAC_TIMESTAMPING; - else if ((ts_info.so_timestamping & - SOF_TIMESTAMPING_SOFTWARE_MASK) == - SOF_TIMESTAMPING_SOFTWARE_MASK) - dev->ts_layer = SOFTWARE_TIMESTAMPING; - } else { - dev->ts_layer = NO_TIMESTAMPING; - } phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; } diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h index bb289c2ad376..eb01c37e71e0 100644 --- a/include/linux/net_tstamp.h +++ b/include/linux/net_tstamp.h @@ -5,6 +5,11 @@ #include +enum hwtstamp_source { + HWTSTAMP_SOURCE_NETDEV, + HWTSTAMP_SOURCE_PHYLIB, +}; + /** * struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config * @@ -15,8 +20,8 @@ * a legacy implementation of a lower driver * @copied_to_user: request was passed to a legacy implementation which already * copied the ioctl request back to user space - * @source: indication whether timestamps should come from software, the netdev - * or from an attached phylib PHY + * @source: indication whether timestamps should come from the netdev or from + * an attached phylib PHY * * Prefer using this structure for in-kernel processing of hardware * timestamping configuration, over the inextensible struct hwtstamp_config @@ -28,7 +33,7 @@ struct kernel_hwtstamp_config { int rx_filter; struct ifreq *ifr; bool copied_to_user; - enum timestamping_layer source; + enum hwtstamp_source source; }; static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f020d2790c12..2d840d7056f2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -2075,8 +2074,6 @@ enum netdev_ml_priv_type { * * @dpll_pin: Pointer to the SyncE source pin of a DPLL subsystem, * where the clock is recovered. - * @ts_layer: Tracks which network device - * performs packet time stamping. * * FIXME: cleanup struct net_device such that network protocol info * moves out. @@ -2438,8 +2435,6 @@ struct net_device { #if IS_ENABLED(CONFIG_DPLL) struct dpll_pin *dpll_pin; #endif - - enum timestamping_layer ts_layer; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/include/linux/phy.h b/include/linux/phy.h index 317def2a7843..e5f1f41e399c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -604,8 +604,6 @@ struct macsec_ops; * handling shall be postponed until PHY has resumed * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended, * requiring a rerun of the interrupt handler after resume - * @default_timestamp: Flag indicating whether we are using the phy - * timestamp as the default one * @interface: enum phy_interface_t value * @skb: Netlink message for cable diagnostics * @nest: Netlink nest used for cable diagnostics @@ -669,8 +667,6 @@ struct phy_device { unsigned irq_suspended:1; unsigned irq_rerun:1; - unsigned default_timestamp:1; - int rate_matching; enum phy_state state; diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index df6c4fcc62c1..73e2c10dc2cc 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -57,9 +57,6 @@ enum { ETHTOOL_MSG_PLCA_GET_STATUS, ETHTOOL_MSG_MM_GET, ETHTOOL_MSG_MM_SET, - ETHTOOL_MSG_TS_GET, - ETHTOOL_MSG_TS_LIST_GET, - ETHTOOL_MSG_TS_SET, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, @@ -112,8 +109,6 @@ enum { ETHTOOL_MSG_PLCA_NTF, ETHTOOL_MSG_MM_GET_REPLY, ETHTOOL_MSG_MM_NTF, - ETHTOOL_MSG_TS_GET_REPLY, - ETHTOOL_MSG_TS_LIST_GET_REPLY, /* add new constants above here */ __ETHTOOL_MSG_KERNEL_CNT, @@ -980,30 +975,6 @@ enum { ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1) }; -/* TS LAYER */ - -enum { - ETHTOOL_A_TS_UNSPEC, - ETHTOOL_A_TS_HEADER, /* nest - _A_HEADER_* */ - ETHTOOL_A_TS_LAYER, /* u32 */ - - /* add new constants above here */ - __ETHTOOL_A_TS_CNT, - ETHTOOL_A_TS_MAX = (__ETHTOOL_A_TS_CNT - 1) -}; - -/* TS LIST LAYER */ - -enum { - ETHTOOL_A_TS_LIST_UNSPEC, - ETHTOOL_A_TS_LIST_HEADER, /* nest - _A_HEADER_* */ - ETHTOOL_A_TS_LIST_LAYER, /* array, u32 */ - - /* add new constants above here */ - __ETHTOOL_A_TS_LIST_CNT, - ETHTOOL_A_TS_LIST_MAX = (__ETHTOOL_A_TS_LIST_CNT - 1) -}; - /* generic netlink info */ #define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_VERSION 1 diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index 4551fb3d7720..a2c66b3d7f0f 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -13,16 +13,6 @@ #include #include /* for SO_TIMESTAMPING */ -/* Layer of the TIMESTAMPING provider */ -enum timestamping_layer { - NO_TIMESTAMPING, - SOFTWARE_TIMESTAMPING, - MAC_TIMESTAMPING, - PHY_TIMESTAMPING, - - __TIMESTAMPING_COUNT, -}; - /* SO_TIMESTAMPING flags */ enum { SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), @@ -58,14 +48,6 @@ enum { SOF_TIMESTAMPING_TX_SCHED | \ SOF_TIMESTAMPING_TX_ACK) -#define SOF_TIMESTAMPING_SOFTWARE_MASK (SOF_TIMESTAMPING_RX_SOFTWARE | \ - SOF_TIMESTAMPING_TX_SOFTWARE | \ - SOF_TIMESTAMPING_SOFTWARE) - -#define SOF_TIMESTAMPING_HARDWARE_MASK (SOF_TIMESTAMPING_RX_HARDWARE | \ - SOF_TIMESTAMPING_TX_HARDWARE | \ - SOF_TIMESTAMPING_RAW_HARDWARE) - /** * struct so_timestamping - SO_TIMESTAMPING parameter * diff --git a/net/core/dev.c b/net/core/dev.c index 05ce00632892..af53f6d838ce 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10212,9 +10212,6 @@ int register_netdevice(struct net_device *dev) dev->rtnl_link_state == RTNL_LINK_INITIALIZED) rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL, 0, NULL); - if (dev->ethtool_ops->get_ts_info) - dev->ts_layer = MAC_TIMESTAMPING; - out: return ret; diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index bc8be9749376..9a66cf5015f2 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -259,7 +259,9 @@ static int dev_eth_ioctl(struct net_device *dev, * @dev: Network device * @cfg: Timestamping configuration structure * - * Helper for calling the selected hardware provider timestamping. + * Helper for enforcing a common policy that phylib timestamping, if available, + * should take precedence in front of hardware timestamping provided by the + * netdev. * * Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and * there only exists a phydev->mii_ts->hwtstamp() method. So this will return @@ -269,14 +271,10 @@ static int dev_eth_ioctl(struct net_device *dev, static int dev_get_hwtstamp_phylib(struct net_device *dev, struct kernel_hwtstamp_config *cfg) { - enum timestamping_layer ts_layer = dev->ts_layer; - - if (ts_layer == PHY_TIMESTAMPING) + if (phy_has_hwtstamp(dev->phydev)) return phy_hwtstamp_get(dev->phydev, cfg); - else if (ts_layer == MAC_TIMESTAMPING) - return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); - return -EOPNOTSUPP; + return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); } static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) @@ -317,8 +315,9 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) * @cfg: Timestamping configuration structure * @extack: Netlink extended ack message structure, for error reporting * - * Helper for calling the selected hardware provider timestamping. - * If the netdev driver needs to perform specific actions even for PHY + * Helper for enforcing a common policy that phylib timestamping, if available, + * should take precedence in front of hardware timestamping provided by the + * netdev. If the netdev driver needs to perform specific actions even for PHY * timestamping to work properly (a switch port must trap the timestamped * frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in * dev->priv_flags. @@ -328,26 +327,20 @@ int dev_set_hwtstamp_phylib(struct net_device *dev, struct netlink_ext_ack *extack) { const struct net_device_ops *ops = dev->netdev_ops; - enum timestamping_layer ts_layer = dev->ts_layer; + bool phy_ts = phy_has_hwtstamp(dev->phydev); struct kernel_hwtstamp_config old_cfg = {}; bool changed = false; int err; - cfg->source = ts_layer; + cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV; - if (ts_layer != PHY_TIMESTAMPING && - ts_layer != MAC_TIMESTAMPING) - return -EOPNOTSUPP; - - if (ts_layer == PHY_TIMESTAMPING && - dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) { + if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { err = ops->ndo_hwtstamp_get(dev, &old_cfg); if (err) return err; } - if (ts_layer == MAC_TIMESTAMPING || - dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) { + if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { err = ops->ndo_hwtstamp_set(dev, cfg, extack); if (err) { if (extack->_msg) @@ -356,11 +349,10 @@ int dev_set_hwtstamp_phylib(struct net_device *dev, } } - if (ts_layer == PHY_TIMESTAMPING && - dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) + if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) changed = kernel_hwtstamp_config_changed(&old_cfg, cfg); - if (ts_layer == PHY_TIMESTAMPING) { + if (phy_ts) { err = phy_hwtstamp_set(dev->phydev, cfg, extack); if (err) { if (changed) diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 5cf51a523fb3..04840697fe79 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -21,7 +21,6 @@ static unsigned int classify(const struct sk_buff *skb) void skb_clone_tx_timestamp(struct sk_buff *skb) { - enum timestamping_layer ts_layer; struct mii_timestamper *mii_ts; struct sk_buff *clone; unsigned int type; @@ -29,10 +28,6 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) if (!skb->sk) return; - ts_layer = skb->dev->ts_layer; - if (ts_layer != PHY_TIMESTAMPING) - return; - type = classify(skb); if (type == PTP_CLASS_NONE) return; @@ -49,17 +44,12 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); bool skb_defer_rx_timestamp(struct sk_buff *skb) { - enum timestamping_layer ts_layer; struct mii_timestamper *mii_ts; unsigned int type; if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->mii_ts) return false; - ts_layer = skb->dev->ts_layer; - if (ts_layer != PHY_TIMESTAMPING) - return false; - if (skb_headroom(skb) < ETH_HLEN) return false; diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile index 4ea64c080639..504f954a1b28 100644 --- a/net/ethtool/Makefile +++ b/net/ethtool/Makefile @@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \ linkstate.o debug.o wol.o features.o privflags.o rings.o \ channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ - module.o pse-pd.o plca.o mm.o ts.o + module.o pse-pd.o plca.o mm.o diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 9f6e3b2c74e2..11d8797f63f6 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -633,28 +633,13 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { const struct ethtool_ops *ops = dev->ethtool_ops; struct phy_device *phydev = dev->phydev; - enum timestamping_layer ts_layer; - int ret; memset(info, 0, sizeof(*info)); info->cmd = ETHTOOL_GET_TS_INFO; - ts_layer = dev->ts_layer; - if (ts_layer == SOFTWARE_TIMESTAMPING) { - ret = ops->get_ts_info(dev, info); - if (ret) - return ret; - info->so_timestamping &= ~SOF_TIMESTAMPING_HARDWARE_MASK; - info->phc_index = -1; - info->rx_filters = 0; - info->tx_types = 0; - return 0; - } - - if (ts_layer == PHY_TIMESTAMPING) + if (phy_has_tsinfo(phydev)) return phy_ts_info(phydev, info); - - if (ts_layer == MAC_TIMESTAMPING) + if (ops->get_ts_info) return ops->get_ts_info(dev, info); info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | diff --git a/net/ethtool/common.h b/net/ethtool/common.h index a264b635f7d3..28b8aaaf9bcb 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -35,7 +35,6 @@ extern const char wol_mode_names[][ETH_GSTRING_LEN]; extern const char sof_timestamping_names[][ETH_GSTRING_LEN]; extern const char ts_tx_type_names[][ETH_GSTRING_LEN]; extern const char ts_rx_filter_names[][ETH_GSTRING_LEN]; -extern const char ts_layer_names[][ETH_GSTRING_LEN]; extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN]; int __ethtool_get_link(struct net_device *dev); diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 8322bf71f80d..3bbd5afb7b31 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -306,9 +306,6 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, - [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, - [ETHTOOL_MSG_TS_LIST_GET] = ðnl_ts_list_request_ops, - [ETHTOOL_MSG_TS_SET] = ðnl_ts_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -1131,31 +1128,6 @@ static const struct genl_ops ethtool_genl_ops[] = { .policy = ethnl_mm_set_policy, .maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1, }, - { - .cmd = ETHTOOL_MSG_TS_GET, - .doit = ethnl_default_doit, - .start = ethnl_default_start, - .dumpit = ethnl_default_dumpit, - .done = ethnl_default_done, - .policy = ethnl_ts_get_policy, - .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, - }, - { - .cmd = ETHTOOL_MSG_TS_LIST_GET, - .doit = ethnl_default_doit, - .start = ethnl_default_start, - .dumpit = ethnl_default_dumpit, - .done = ethnl_default_done, - .policy = ethnl_ts_get_policy, - .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, - }, - { - .cmd = ETHTOOL_MSG_TS_SET, - .flags = GENL_UNS_ADMIN_PERM, - .doit = ethnl_default_set_doit, - .policy = ethnl_ts_set_policy, - .maxattr = ARRAY_SIZE(ethnl_ts_set_policy) - 1, - }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 8fedf234b824..9a333a8d04c1 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -395,8 +395,6 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops; extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; extern const struct ethnl_request_ops ethnl_plca_status_request_ops; extern const struct ethnl_request_ops ethnl_mm_request_ops; -extern const struct ethnl_request_ops ethnl_ts_request_ops; -extern const struct ethnl_request_ops ethnl_ts_list_request_ops; extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; @@ -443,8 +441,6 @@ extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1] extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; -extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1]; -extern const struct nla_policy ethnl_ts_set_policy[ETHTOOL_A_TS_MAX + 1]; int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c deleted file mode 100644 index 357265e74e08..000000000000 --- a/net/ethtool/ts.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include - -#include "netlink.h" -#include "common.h" -#include "bitset.h" - -struct ts_req_info { - struct ethnl_req_info base; -}; - -struct ts_reply_data { - struct ethnl_reply_data base; - enum timestamping_layer ts_layer; -}; - -#define TS_REPDATA(__reply_base) \ - container_of(__reply_base, struct ts_reply_data, base) - -/* TS_GET */ -const struct nla_policy ethnl_ts_get_policy[] = { - [ETHTOOL_A_TS_HEADER] = - NLA_POLICY_NESTED(ethnl_header_policy), -}; - -static int ts_prepare_data(const struct ethnl_req_info *req_base, - struct ethnl_reply_data *reply_base, - const struct genl_info *info) -{ - struct ts_reply_data *data = TS_REPDATA(reply_base); - struct net_device *dev = reply_base->dev; - int ret; - - ret = ethnl_ops_begin(dev); - if (ret < 0) - return ret; - - data->ts_layer = dev->ts_layer; - - ethnl_ops_complete(dev); - - return ret; -} - -static int ts_reply_size(const struct ethnl_req_info *req_base, - const struct ethnl_reply_data *reply_base) -{ - return nla_total_size(sizeof(u32)); -} - -static int ts_fill_reply(struct sk_buff *skb, - const struct ethnl_req_info *req_base, - const struct ethnl_reply_data *reply_base) -{ - struct ts_reply_data *data = TS_REPDATA(reply_base); - - return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer); -} - -/* TS_SET */ -const struct nla_policy ethnl_ts_set_policy[] = { - [ETHTOOL_A_TS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), - [ETHTOOL_A_TS_LAYER] = NLA_POLICY_RANGE(NLA_U32, 0, - __TIMESTAMPING_COUNT - 1) -}; - -static int ethnl_set_ts_validate(struct ethnl_req_info *req_info, - struct genl_info *info) -{ - struct nlattr **tb = info->attrs; - const struct net_device_ops *ops = req_info->dev->netdev_ops; - - if (!ops->ndo_hwtstamp_set) - return -EOPNOTSUPP; - - if (!tb[ETHTOOL_A_TS_LAYER]) - return 0; - - return 1; -} - -static int ethnl_set_ts(struct ethnl_req_info *req_info, struct genl_info *info) -{ - struct net_device *dev = req_info->dev; - const struct ethtool_ops *ops = dev->ethtool_ops; - struct kernel_hwtstamp_config config = {0}; - struct nlattr **tb = info->attrs; - enum timestamping_layer ts_layer; - bool mod = false; - int ret; - - ts_layer = dev->ts_layer; - ethnl_update_u32(&ts_layer, tb[ETHTOOL_A_TS_LAYER], &mod); - - if (!mod) - return 0; - - if (ts_layer == SOFTWARE_TIMESTAMPING) { - struct ethtool_ts_info ts_info = {0}; - - if (!ops->get_ts_info) { - NL_SET_ERR_MSG_ATTR(info->extack, - tb[ETHTOOL_A_TS_LAYER], - "this net device cannot support timestamping"); - return -EINVAL; - } - - ops->get_ts_info(dev, &ts_info); - if ((ts_info.so_timestamping & - SOF_TIMESTAMPING_SOFTWARE_MASK) != - SOF_TIMESTAMPING_SOFTWARE_MASK) { - NL_SET_ERR_MSG_ATTR(info->extack, - tb[ETHTOOL_A_TS_LAYER], - "this net device cannot support software timestamping"); - return -EINVAL; - } - } else if (ts_layer == MAC_TIMESTAMPING) { - struct ethtool_ts_info ts_info = {0}; - - if (!ops->get_ts_info) { - NL_SET_ERR_MSG_ATTR(info->extack, - tb[ETHTOOL_A_TS_LAYER], - "this net device cannot support timestamping"); - return -EINVAL; - } - - ops->get_ts_info(dev, &ts_info); - if ((ts_info.so_timestamping & - SOF_TIMESTAMPING_HARDWARE_MASK) != - SOF_TIMESTAMPING_HARDWARE_MASK) { - NL_SET_ERR_MSG_ATTR(info->extack, - tb[ETHTOOL_A_TS_LAYER], - "this net device cannot support hardware timestamping"); - return -EINVAL; - } - } else if (ts_layer == PHY_TIMESTAMPING && !phy_has_tsinfo(dev->phydev)) { - NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_TS_LAYER], - "this phy device cannot support timestamping"); - return -EINVAL; - } - - /* Disable time stamping in the current layer. */ - if (netif_device_present(dev) && - (dev->ts_layer == PHY_TIMESTAMPING || - dev->ts_layer == MAC_TIMESTAMPING)) { - ret = dev_set_hwtstamp_phylib(dev, &config, info->extack); - if (ret < 0) - return ret; - } - - dev->ts_layer = ts_layer; - - return 1; -} - -const struct ethnl_request_ops ethnl_ts_request_ops = { - .request_cmd = ETHTOOL_MSG_TS_GET, - .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY, - .hdr_attr = ETHTOOL_A_TS_HEADER, - .req_info_size = sizeof(struct ts_req_info), - .reply_data_size = sizeof(struct ts_reply_data), - - .prepare_data = ts_prepare_data, - .reply_size = ts_reply_size, - .fill_reply = ts_fill_reply, - - .set_validate = ethnl_set_ts_validate, - .set = ethnl_set_ts, -}; - -/* TS_LIST_GET */ -struct ts_list_reply_data { - struct ethnl_reply_data base; - enum timestamping_layer ts_layer[__TIMESTAMPING_COUNT]; - u8 num_ts; -}; - -#define TS_LIST_REPDATA(__reply_base) \ - container_of(__reply_base, struct ts_list_reply_data, base) - -static int ts_list_prepare_data(const struct ethnl_req_info *req_base, - struct ethnl_reply_data *reply_base, - const struct genl_info *info) -{ - struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); - struct net_device *dev = reply_base->dev; - const struct ethtool_ops *ops = dev->ethtool_ops; - int ret, i = 0; - - ret = ethnl_ops_begin(dev); - if (ret < 0) - return ret; - - if (phy_has_tsinfo(dev->phydev)) - data->ts_layer[i++] = PHY_TIMESTAMPING; - if (ops->get_ts_info) { - struct ethtool_ts_info ts_info = {0}; - - ops->get_ts_info(dev, &ts_info); - if (ts_info.so_timestamping & - SOF_TIMESTAMPING_HARDWARE_MASK) - data->ts_layer[i++] = MAC_TIMESTAMPING; - - if (ts_info.so_timestamping & - SOF_TIMESTAMPING_SOFTWARE_MASK) - data->ts_layer[i++] = SOFTWARE_TIMESTAMPING; - } - - data->num_ts = i; - ethnl_ops_complete(dev); - - return ret; -} - -static int ts_list_reply_size(const struct ethnl_req_info *req_base, - const struct ethnl_reply_data *reply_base) -{ - struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); - - return nla_total_size(sizeof(u32)) * data->num_ts; -} - -static int ts_list_fill_reply(struct sk_buff *skb, - const struct ethnl_req_info *req_base, - const struct ethnl_reply_data *reply_base) -{ - struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base); - - return nla_put(skb, ETHTOOL_A_TS_LIST_LAYER, sizeof(u32) * data->num_ts, data->ts_layer); -} - -const struct ethnl_request_ops ethnl_ts_list_request_ops = { - .request_cmd = ETHTOOL_MSG_TS_LIST_GET, - .reply_cmd = ETHTOOL_MSG_TS_LIST_GET_REPLY, - .hdr_attr = ETHTOOL_A_TS_HEADER, - .req_info_size = sizeof(struct ts_req_info), - .reply_data_size = sizeof(struct ts_list_reply_data), - - .prepare_data = ts_list_prepare_data, - .reply_size = ts_list_reply_size, - .fill_reply = ts_list_fill_reply, -}; From 6b78debe1c07e6aa3c91ca0b1384bf3cb8217c50 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 11:18:55 -0300 Subject: [PATCH 0923/7721] net/sched: cls_u32: replace int refcounts with proper refcounts Proper refcounts will always warn splat when something goes wrong, be it underflow, saturation or object resurrection. As these are always a source of bugs, use it in cls_u32 as a safeguard to prevent/catch issues. Another benefit is that the refcount API self documents the code, making clear when transitions to dead are expected. For such an update we had to make minor adaptations on u32 to fit the refcount API. First we set explicitly to '1' when objects are created, then the objects are alive until a 1 -> 0 happens, which is then released appropriately. The above made clear some redundant operations in the u32 code around the root_ht handling that were removed. The root_ht is created with a refcnt set to 1. Then when it's associated with tcf_proto it increments the refcnt to 2. Throughout the entire code the root_ht is an exceptional case and can never be referenced, therefore the refcnt never incremented/decremented. Its lifetime is always bound to tcf_proto, meaning if you delete tcf_proto the root_ht is deleted as well. The code made up for the fact that root_ht refcnt is 2 and did a double decrement to free it, which is not a fit for the refcount API. Even though refcount_t is implemented using atomics, we should observe a negligible control plane impact. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231114141856.974326-2-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/cls_u32.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index d5bdfd4a7655..289e1755c26b 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -71,7 +71,7 @@ struct tc_u_hnode { struct tc_u_hnode __rcu *next; u32 handle; u32 prio; - int refcnt; + refcount_t refcnt; unsigned int divisor; struct idr handle_idr; bool is_root; @@ -86,7 +86,7 @@ struct tc_u_hnode { struct tc_u_common { struct tc_u_hnode __rcu *hlist; void *ptr; - int refcnt; + refcount_t refcnt; struct idr handle_idr; struct hlist_node hnode; long knodes; @@ -359,7 +359,7 @@ static int u32_init(struct tcf_proto *tp) if (root_ht == NULL) return -ENOBUFS; - root_ht->refcnt++; + refcount_set(&root_ht->refcnt, 1); root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000; root_ht->prio = tp->prio; root_ht->is_root = true; @@ -371,18 +371,20 @@ static int u32_init(struct tcf_proto *tp) kfree(root_ht); return -ENOBUFS; } + refcount_set(&tp_c->refcnt, 1); tp_c->ptr = key; INIT_HLIST_NODE(&tp_c->hnode); idr_init(&tp_c->handle_idr); hlist_add_head(&tp_c->hnode, tc_u_hash(key)); + } else { + refcount_inc(&tp_c->refcnt); } - tp_c->refcnt++; RCU_INIT_POINTER(root_ht->next, tp_c->hlist); rcu_assign_pointer(tp_c->hlist, root_ht); - root_ht->refcnt++; + /* root_ht must be destroyed when tcf_proto is destroyed */ rcu_assign_pointer(tp->root, root_ht); tp->data = tp_c; return 0; @@ -393,7 +395,7 @@ static void __u32_destroy_key(struct tc_u_knode *n) struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); tcf_exts_destroy(&n->exts); - if (ht && --ht->refcnt == 0) + if (ht && refcount_dec_and_test(&ht->refcnt)) kfree(ht); kfree(n); } @@ -601,8 +603,6 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, struct tc_u_hnode __rcu **hn; struct tc_u_hnode *phn; - WARN_ON(--ht->refcnt); - u32_clear_hnode(tp, ht, extack); hn = &tp_c->hlist; @@ -630,10 +630,10 @@ static void u32_destroy(struct tcf_proto *tp, bool rtnl_held, WARN_ON(root_ht == NULL); - if (root_ht && --root_ht->refcnt == 1) + if (root_ht && refcount_dec_and_test(&root_ht->refcnt)) u32_destroy_hnode(tp, root_ht, extack); - if (--tp_c->refcnt == 0) { + if (refcount_dec_and_test(&tp_c->refcnt)) { struct tc_u_hnode *ht; hlist_del(&tp_c->hnode); @@ -645,7 +645,7 @@ static void u32_destroy(struct tcf_proto *tp, bool rtnl_held, /* u32_destroy_key() will later free ht for us, if it's * still referenced by some knode */ - if (--ht->refcnt == 0) + if (refcount_dec_and_test(&ht->refcnt)) kfree_rcu(ht, rcu); } @@ -674,7 +674,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, return -EINVAL; } - if (ht->refcnt == 1) { + if (refcount_dec_if_one(&ht->refcnt)) { u32_destroy_hnode(tp, ht, extack); } else { NL_SET_ERR_MSG_MOD(extack, "Can not delete in-use filter"); @@ -682,7 +682,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, } out: - *last = tp_c->refcnt == 1 && tp_c->knodes == 0; + *last = refcount_read(&tp_c->refcnt) == 1 && tp_c->knodes == 0; return ret; } @@ -766,14 +766,14 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, NL_SET_ERR_MSG_MOD(extack, "Not linking to root node"); return -EINVAL; } - ht_down->refcnt++; + refcount_inc(&ht_down->refcnt); } ht_old = rtnl_dereference(n->ht_down); rcu_assign_pointer(n->ht_down, ht_down); if (ht_old) - ht_old->refcnt--; + refcount_dec(&ht_old->refcnt); } if (ifindex >= 0) @@ -852,7 +852,7 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, /* bump reference count as long as we hold pointer to structure */ if (ht) - ht->refcnt++; + refcount_inc(&ht->refcnt); return new; } @@ -932,7 +932,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ht_old = rtnl_dereference(n->ht_down); if (ht_old) - ht_old->refcnt++; + refcount_inc(&ht_old->refcnt); } __u32_destroy_key(new); return err; @@ -980,7 +980,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return err; } } - ht->refcnt = 1; + refcount_set(&ht->refcnt, 1); ht->divisor = divisor; ht->handle = handle; ht->prio = tp->prio; From 54293e4d6a629befb0b0d93aa416a658678f7f01 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 14 Nov 2023 11:18:56 -0300 Subject: [PATCH 0924/7721] selftests/tc-testing: add hashtable tests for u32 Add tests to specifically check for the refcount interactions of hashtables created by u32. These tables should not be deleted when referenced and the flush order should respect a tree like composition. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231114141856.974326-3-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/filters/u32.json | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json b/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json index ddc7c355be0a..24bd0c2a3014 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json @@ -272,5 +272,62 @@ "teardown": [ "$TC qdisc del dev $DEV1 parent root drr" ] + }, + { + "id": "bd32", + "name": "Try to delete hashtable referenced by another u32 filter", + "category": [ + "filter", + "u32" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "$TC qdisc add dev $DEV1 parent root handle 10: drr", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 handle 1: u32 divisor 1", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 800: match ip src any link 1:" + ], + "cmdUnderTest": "$TC filter delete dev $DEV1 parent 10: prio 2 handle 1: u32", + "expExitCode": "2", + "verifyCmd": "$TC filter show dev $DEV1", + "matchPattern": "protocol ip pref 2 u32 chain 0 fh 1:", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 parent root drr" + ] + }, + { + "id": "4585", + "name": "Delete small tree of u32 hashtables and filters", + "category": [ + "filter", + "u32" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "$TC qdisc add dev $DEV1 parent root handle 10: drr", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 handle 1: u32 divisor 1", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 handle 2: u32 divisor 1", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 handle 3: u32 divisor 2", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 handle 4: u32 divisor 1", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 1: match ip src any action drop", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 2: match ip src any action drop", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 3: match ip src any link 2:", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 3: match ip src any link 1:", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 4: match ip src any action drop", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 800: match ip src any link 3:", + "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 ht 800: match ip src any link 4:" + ], + "cmdUnderTest": "$TC filter delete dev $DEV1 parent 10:", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1", + "matchPattern": "protocol ip pref 2 u32", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 parent root drr" + ] } ] From ac40916a3f7243efbe6e129ebf495b5c33a3adfe Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Wed, 15 Nov 2023 20:01:08 +0800 Subject: [PATCH 0925/7721] rtnetlink: introduce nlmsg_new_large and use it in rtnl_getlink if a PF has 256 or more VFs, ip link command will allocate an order 3 memory or more, and maybe trigger OOM due to memory fragment, the VFs needed memory size is computed in rtnl_vfinfo_size. so introduce nlmsg_new_large which calls netlink_alloc_large_skb in which vmalloc is used for large memory, to avoid the failure of allocating memory ip invoked oom-killer: gfp_mask=0xc2cc0(GFP_KERNEL|__GFP_NOWARN|\ __GFP_COMP|__GFP_NOMEMALLOC), order=3, oom_score_adj=0 CPU: 74 PID: 204414 Comm: ip Kdump: loaded Tainted: P OE Call Trace: dump_stack+0x57/0x6a dump_header+0x4a/0x210 oom_kill_process+0xe4/0x140 out_of_memory+0x3e8/0x790 __alloc_pages_slowpath.constprop.116+0x953/0xc50 __alloc_pages_nodemask+0x2af/0x310 kmalloc_large_node+0x38/0xf0 __kmalloc_node_track_caller+0x417/0x4d0 __kmalloc_reserve.isra.61+0x2e/0x80 __alloc_skb+0x82/0x1c0 rtnl_getlink+0x24f/0x370 rtnetlink_rcv_msg+0x12c/0x350 netlink_rcv_skb+0x50/0x100 netlink_unicast+0x1b2/0x280 netlink_sendmsg+0x355/0x4a0 sock_sendmsg+0x5b/0x60 ____sys_sendmsg+0x1ea/0x250 ___sys_sendmsg+0x88/0xd0 __sys_sendmsg+0x5e/0xa0 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7f95a65a5b70 Cc: Yunsheng Lin Signed-off-by: Li RongQing Link: https://lore.kernel.org/r/20231115120108.3711-1-lirongqing@baidu.com Signed-off-by: Jakub Kicinski --- include/linux/netlink.h | 1 + include/net/netlink.h | 14 ++++++++++++++ net/core/rtnetlink.c | 2 +- net/netlink/af_netlink.c | 3 +-- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 75d7de34c908..abe91ed6b9aa 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -351,5 +351,6 @@ bool netlink_ns_capable(const struct sk_buff *skb, struct user_namespace *ns, int cap); bool netlink_capable(const struct sk_buff *skb, int cap); bool netlink_net_capable(const struct sk_buff *skb, int cap); +struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast); #endif /* __LINUX_NETLINK_H */ diff --git a/include/net/netlink.h b/include/net/netlink.h index 83bdf787aeee..167b91348e57 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -1010,6 +1010,20 @@ static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) return alloc_skb(nlmsg_total_size(payload), flags); } +/** + * nlmsg_new_large - Allocate a new netlink message with non-contiguous + * physical memory + * @payload: size of the message payload + * + * The allocated skb is unable to have frag page for shinfo->frags*, + * as the NULL setting for skb->head in netlink_skb_destructor() will + * bypass most of the handling in skb_release_data() + */ +static inline struct sk_buff *nlmsg_new_large(size_t payload) +{ + return netlink_alloc_large_skb(nlmsg_total_size(payload), 0); +} + /** * nlmsg_end - Finalize a netlink message * @skb: socket buffer the message is stored in diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e8431c6c8490..592164c2a540 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3849,7 +3849,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; err = -ENOBUFS; - nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL); + nskb = nlmsg_new_large(if_nlmsg_size(dev, ext_filter_mask)); if (nskb == NULL) goto out; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index eb086b06d60d..177126fb0484 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1204,8 +1204,7 @@ struct sock *netlink_getsockbyfilp(struct file *filp) return sock; } -static struct sk_buff *netlink_alloc_large_skb(unsigned int size, - int broadcast) +struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast) { struct sk_buff *skb; void *data; From aa1cfba75b77ca93ab9a0b03c2c9124a16d96479 Mon Sep 17 00:00:00 2001 From: Thomas Perrot Date: Fri, 20 Oct 2023 15:02:19 +0200 Subject: [PATCH 0926/7721] ARM: at91: pm: set soc_pm.data.mode in at91_pm_secure_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In non secure mode, soc_pm.data.mode is set when entering pm in at91_pm_begin(). This value is used (not only) to determine if the system is going into slow clock mode (at91_suspend_entering_slow_clock()). This function is called from various drivers to check this and act accordingly. If not set, the driver might enter an incorrect suspend mode. When using secure suspend mode, at91_pm_begin() is not called and thus soc_pm.data.mode is not set. Since when using secure suspend, only one suspend mode is supported, set this value directly in at91_pm_secure_init(). Signed-off-by: Clément Léger Signed-off-by: Thomas Perrot Acked-by: Nicolas Ferre Link: https://lore.kernel.org/r/20231020130219.1255937-1-thomas.perrot@bootlin.com Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 1a26af0fabc7..345b91dc6627 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -1103,6 +1103,7 @@ static void __init at91_pm_secure_init(void) if (res.a0 == 0) { pr_info("AT91: Secure PM: suspend mode set to %s\n", pm_modes[suspend_mode].pattern); + soc_pm.data.mode = suspend_mode; return; } @@ -1112,6 +1113,7 @@ static void __init at91_pm_secure_init(void) res = sam_smccc_call(SAMA5_SMC_SIP_GET_SUSPEND_MODE, 0, 0); if (res.a0 == 0) { pr_warn("AT91: Secure PM: failed to get default mode\n"); + soc_pm.data.mode = -1; return; } @@ -1119,6 +1121,7 @@ static void __init at91_pm_secure_init(void) pm_modes[suspend_mode].pattern); soc_pm.data.suspend_mode = res.a1; + soc_pm.data.mode = soc_pm.data.suspend_mode; } static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, From e83bcc62287bdec9ffc9e4bf83271a0c1742d0a3 Mon Sep 17 00:00:00 2001 From: Mihai Sain Date: Thu, 9 Nov 2023 15:11:48 +0200 Subject: [PATCH 0927/7721] ARM: dts: microchip: sam9x60_curiosity: Add IRQ support for ethernet PHY Add interrupt support for ethernet phy subnode. Add PB8 definition to macb0 pinctrl. Signed-off-by: Mihai Sain Link: https://lore.kernel.org/r/20231109131149.46397-2-mihai.sain@microchip.com [claudiu.beznea: s/at91/microchip in commit title to match dts directory] Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts index 83372c1f291b..c6fbdd29019f 100644 --- a/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts +++ b/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts @@ -249,6 +249,8 @@ &macb0 { ethernet-phy@0 { reg = <0x0>; + interrupt-parent = <&pioB>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -353,6 +355,7 @@ AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB4 periph A */ AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB5 periph A */ AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB6 periph A */ AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB7 periph A */ + AT91_PIOB 8 AT91_PERIPH_GPIO AT91_PINCTRL_NONE /* PB8 IRQ GPIO */ AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB9 periph A */ AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* PB10 periph A */ }; From 6dc4309df40549e20df89823e4b0212cff316eed Mon Sep 17 00:00:00 2001 From: Mihai Sain Date: Thu, 9 Nov 2023 15:11:49 +0200 Subject: [PATCH 0928/7721] ARM: dts: microchip: sam9x60ek: Add IRQ support for ethernet PHY Add interrupt support for ethernet phy subnode. Add PB8 definition to macb0 pinctrl. Signed-off-by: Mihai Sain Link: https://lore.kernel.org/r/20231109131149.46397-3-mihai.sain@microchip.com [claudiu.beznea: s/at91/microchip in commit title to match dts directory] Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/at91-sam9x60ek.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts index 5cd593028aff..f3cbb675cea4 100644 --- a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts @@ -292,6 +292,8 @@ &macb0 { ethernet-phy@0 { reg = <0x0>; + interrupt-parent = <&pioB>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -465,6 +467,7 @@ AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB4 periph A */ AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB5 periph A */ AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB6 periph A */ AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB7 periph A */ + AT91_PIOB 8 AT91_PERIPH_GPIO AT91_PINCTRL_NONE /* PB8 IRQ GPIO */ AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB9 periph A */ AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* PB10 periph A */ }; From f45b83ad39f8033e717b1eee57e81811113d5a84 Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Tue, 14 Nov 2023 20:34:47 +0800 Subject: [PATCH 0929/7721] RDMA/hns: Fix inappropriate err code for unsupported operations EOPNOTSUPP is more situable than EINVAL for allocating XRCD while XRC is not supported and unsupported resizing SRQ. Fixes: 32548870d438 ("RDMA/hns: Add support for XRC on HIP09") Fixes: 221109e64316 ("RDMA/hns: Add interception for resizing SRQs") Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231114123449.1106162-2-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 2 +- drivers/infiniband/hw/hns/hns_roce_pd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 0cd2612a4987..c01307be06ab 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -5666,7 +5666,7 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq, /* Resizing SRQs is not supported yet */ if (srq_attr_mask & IB_SRQ_MAX_WR) - return -EINVAL; + return -EOPNOTSUPP; if (srq_attr_mask & IB_SRQ_LIMIT) { if (srq_attr->srq_limit > srq->wqe_cnt) diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index 783e71852c50..bd1fe89ca205 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -150,7 +150,7 @@ int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata) int ret; if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)) - return -EINVAL; + return -EOPNOTSUPP; ret = hns_roce_xrcd_alloc(hr_dev, &xrcd->xrcdn); if (ret) From ca7ad04cd5d2f8070cd34c2c428cea36de516afc Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Tue, 14 Nov 2023 20:34:48 +0800 Subject: [PATCH 0930/7721] RDMA/hns: Add debugfs to hns RoCE Add debugfs to hns RoCE. This patch only adds an empty directory "hns_roce" to debugs root directory. Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231114123449.1106162-3-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/Makefile | 3 +- drivers/infiniband/hw/hns/hns_roce_debugfs.c | 63 ++++++++++++++++++++ drivers/infiniband/hw/hns/hns_roce_debugfs.h | 27 +++++++++ drivers/infiniband/hw/hns/hns_roce_device.h | 2 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 2 + drivers/infiniband/hw/hns/hns_roce_main.c | 3 + 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/hns/hns_roce_debugfs.c create mode 100644 drivers/infiniband/hw/hns/hns_roce_debugfs.h diff --git a/drivers/infiniband/hw/hns/Makefile b/drivers/infiniband/hw/hns/Makefile index a7d259238305..be1e1cdbcfa8 100644 --- a/drivers/infiniband/hw/hns/Makefile +++ b/drivers/infiniband/hw/hns/Makefile @@ -7,7 +7,8 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3 hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_pd.o \ hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \ - hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o + hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o \ + hns_roce_debugfs.o ifdef CONFIG_INFINIBAND_HNS_HIP08 hns-roce-hw-v2-objs := hns_roce_hw_v2.o $(hns-roce-objs) diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.c b/drivers/infiniband/hw/hns/hns_roce_debugfs.c new file mode 100644 index 000000000000..79825570cc35 --- /dev/null +++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Hisilicon Limited. + */ + +#include +#include + +#include "hns_roce_device.h" + +static struct dentry *hns_roce_dbgfs_root; + +static int hns_debugfs_seqfile_open(struct inode *inode, struct file *f) +{ + struct hns_debugfs_seqfile *seqfile = inode->i_private; + + return single_open(f, seqfile->read, seqfile->data); +} + +static const struct file_operations hns_debugfs_seqfile_fops = { + .owner = THIS_MODULE, + .open = hns_debugfs_seqfile_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek +}; + +static void init_debugfs_seqfile(struct hns_debugfs_seqfile *seq, + const char *name, struct dentry *parent, + int (*read_fn)(struct seq_file *, void *), + void *data) +{ + debugfs_create_file(name, 0400, parent, seq, &hns_debugfs_seqfile_fops); + + seq->read = read_fn; + seq->data = data; +} + +/* debugfs for device */ +void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev) +{ + struct hns_roce_dev_debugfs *dbgfs = &hr_dev->dbgfs; + + dbgfs->root = debugfs_create_dir(dev_name(&hr_dev->ib_dev.dev), + hns_roce_dbgfs_root); +} + +void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev) +{ + debugfs_remove_recursive(hr_dev->dbgfs.root); +} + +/* debugfs for hns module */ +void hns_roce_init_debugfs(void) +{ + hns_roce_dbgfs_root = debugfs_create_dir("hns_roce", NULL); +} + +void hns_roce_cleanup_debugfs(void) +{ + debugfs_remove_recursive(hns_roce_dbgfs_root); + hns_roce_dbgfs_root = NULL; +} diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.h b/drivers/infiniband/hw/hns/hns_roce_debugfs.h new file mode 100644 index 000000000000..ece71fe6730c --- /dev/null +++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 Hisilicon Limited. + */ + +#ifndef __HNS_ROCE_DEBUGFS_H +#define __HNS_ROCE_DEBUGFS_H + +/* debugfs seqfile */ +struct hns_debugfs_seqfile { + int (*read)(struct seq_file *seq, void *data); + void *data; +}; + +/* Debugfs for device */ +struct hns_roce_dev_debugfs { + struct dentry *root; +}; + +struct hns_roce_dev; + +void hns_roce_init_debugfs(void); +void hns_roce_cleanup_debugfs(void); +void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev); +void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev); + +#endif diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 1627f3b0ef28..a847cdfb4ad6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -35,6 +35,7 @@ #include #include +#include "hns_roce_debugfs.h" #define PCI_REVISION_ID_HIP08 0x21 #define PCI_REVISION_ID_HIP09 0x30 @@ -979,6 +980,7 @@ struct hns_roce_dev { u32 is_vf; u32 cong_algo_tmpl_id; u64 dwqe_page; + struct hns_roce_dev_debugfs dbgfs; }; static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index c01307be06ab..8a5432bb0e85 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -6958,12 +6958,14 @@ static struct hnae3_client hns_roce_hw_v2_client = { static int __init hns_roce_hw_v2_init(void) { + hns_roce_init_debugfs(); return hnae3_register_client(&hns_roce_hw_v2_client); } static void __exit hns_roce_hw_v2_exit(void) { hnae3_unregister_client(&hns_roce_hw_v2_client); + hns_roce_cleanup_debugfs(); } module_init(hns_roce_hw_v2_init); diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index a4a10a4e1aab..c9f93ba522c9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -1079,6 +1079,8 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) if (ret) goto error_failed_register_device; + hns_roce_register_debugfs(hr_dev); + return 0; error_failed_register_device: @@ -1108,6 +1110,7 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) void hns_roce_exit(struct hns_roce_dev *hr_dev) { + hns_roce_unregister_debugfs(hr_dev); hns_roce_unregister_device(hr_dev); if (hr_dev->hw->hw_exit) From eb7854d63db543caeb8cadb5c3ae5296d0cb7b8f Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Tue, 14 Nov 2023 20:34:49 +0800 Subject: [PATCH 0931/7721] RDMA/hns: Support SW stats with debugfs Support SW stats with debugfs. Query output: $ cat /sys/kernel/debug/hns_roce/hns_0/sw_stat/sw_stat aeqe --- 3341 ceqe --- 0 cmds --- 6764 cmds_err --- 0 posted_mbx --- 3344 polled_mbx --- 3 mbx_event --- 3341 qp_create_err --- 0 qp_modify_err --- 0 cq_create_err --- 0 cq_modify_err --- 0 srq_create_err --- 0 srq_modify_err --- 0 xrcd_alloc_err --- 0 mr_reg_err --- 0 mr_rereg_err --- 0 ah_create_err --- 0 mmap_err --- 0 uctx_alloc_err --- 0 Signed-off-by: Junxian Huang Signed-off-by: Chengchang Tang Link: https://lore.kernel.org/r/20231114123449.1106162-4-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_ah.c | 6 ++- drivers/infiniband/hw/hns/hns_roce_cmd.c | 19 +++++++- drivers/infiniband/hw/hns/hns_roce_cq.c | 17 ++++--- drivers/infiniband/hw/hns/hns_roce_debugfs.c | 47 ++++++++++++++++++++ drivers/infiniband/hw/hns/hns_roce_debugfs.h | 6 +++ drivers/infiniband/hw/hns/hns_roce_device.h | 24 ++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 47 ++++++++++++++------ drivers/infiniband/hw/hns/hns_roce_main.c | 45 ++++++++++++++++--- drivers/infiniband/hw/hns/hns_roce_mr.c | 26 ++++++++--- drivers/infiniband/hw/hns/hns_roce_pd.c | 14 +++--- drivers/infiniband/hw/hns/hns_roce_qp.c | 8 +++- drivers/infiniband/hw/hns/hns_roce_srq.c | 6 ++- 12 files changed, 221 insertions(+), 44 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c index 3df032ddda18..fbf046982374 100644 --- a/drivers/infiniband/hw/hns/hns_roce_ah.c +++ b/drivers/infiniband/hw/hns/hns_roce_ah.c @@ -92,11 +92,15 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, ret = rdma_read_gid_l2_fields(ah_attr->grh.sgid_attr, &ah->av.vlan_id, NULL); if (ret) - return ret; + goto err_out; ah->av.vlan_en = ah->av.vlan_id < VLAN_N_VID; } +err_out: + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_AH_CREATE_ERR_CNT]); + return ret; } diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.c b/drivers/infiniband/hw/hns/hns_roce_cmd.c index 864413607571..873e8a69a1b9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cmd.c +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.c @@ -41,7 +41,15 @@ static int hns_roce_cmd_mbox_post_hw(struct hns_roce_dev *hr_dev, struct hns_roce_mbox_msg *mbox_msg) { - return hr_dev->hw->post_mbox(hr_dev, mbox_msg); + int ret; + + ret = hr_dev->hw->post_mbox(hr_dev, mbox_msg); + if (ret) + return ret; + + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_POSTED_CNT]); + + return 0; } /* this should be called with "poll_sem" */ @@ -58,7 +66,13 @@ static int __hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev, return ret; } - return hr_dev->hw->poll_mbox_done(hr_dev); + ret = hr_dev->hw->poll_mbox_done(hr_dev); + if (ret) + return ret; + + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_POLLED_CNT]); + + return 0; } static int hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev, @@ -89,6 +103,7 @@ void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status, context->result = (status == HNS_ROCE_CMD_SUCCESS) ? 0 : (-EIO); context->out_param = out_param; complete(&context->done); + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_EVENT_CNT]); } static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 736dc2f993b4..1b6d16af8c12 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -363,29 +363,31 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr, struct hns_roce_ib_create_cq ucmd = {}; int ret; - if (attr->flags) - return -EOPNOTSUPP; + if (attr->flags) { + ret = -EOPNOTSUPP; + goto err_out; + } ret = verify_cq_create_attr(hr_dev, attr); if (ret) - return ret; + goto err_out; if (udata) { ret = get_cq_ucmd(hr_cq, udata, &ucmd); if (ret) - return ret; + goto err_out; } set_cq_param(hr_cq, attr->cqe, attr->comp_vector, &ucmd); ret = set_cqe_size(hr_cq, udata, &ucmd); if (ret) - return ret; + goto err_out; ret = alloc_cq_buf(hr_dev, hr_cq, udata, ucmd.buf_addr); if (ret) { ibdev_err(ibdev, "failed to alloc CQ buf, ret = %d.\n", ret); - return ret; + goto err_out; } ret = alloc_cq_db(hr_dev, hr_cq, udata, ucmd.db_addr, &resp); @@ -430,6 +432,9 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr, free_cq_db(hr_dev, hr_cq, udata); err_cq_buf: free_cq_buf(hr_dev, hr_cq); +err_out: + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CQ_CREATE_ERR_CNT]); + return ret; } diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.c b/drivers/infiniband/hw/hns/hns_roce_debugfs.c index 79825570cc35..e8febb40f645 100644 --- a/drivers/infiniband/hw/hns/hns_roce_debugfs.c +++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.c @@ -36,6 +36,51 @@ static void init_debugfs_seqfile(struct hns_debugfs_seqfile *seq, seq->data = data; } +static const char * const sw_stat_info[] = { + [HNS_ROCE_DFX_AEQE_CNT] = "aeqe", + [HNS_ROCE_DFX_CEQE_CNT] = "ceqe", + [HNS_ROCE_DFX_CMDS_CNT] = "cmds", + [HNS_ROCE_DFX_CMDS_ERR_CNT] = "cmds_err", + [HNS_ROCE_DFX_MBX_POSTED_CNT] = "posted_mbx", + [HNS_ROCE_DFX_MBX_POLLED_CNT] = "polled_mbx", + [HNS_ROCE_DFX_MBX_EVENT_CNT] = "mbx_event", + [HNS_ROCE_DFX_QP_CREATE_ERR_CNT] = "qp_create_err", + [HNS_ROCE_DFX_QP_MODIFY_ERR_CNT] = "qp_modify_err", + [HNS_ROCE_DFX_CQ_CREATE_ERR_CNT] = "cq_create_err", + [HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT] = "cq_modify_err", + [HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT] = "srq_create_err", + [HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT] = "srq_modify_err", + [HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT] = "xrcd_alloc_err", + [HNS_ROCE_DFX_MR_REG_ERR_CNT] = "mr_reg_err", + [HNS_ROCE_DFX_MR_REREG_ERR_CNT] = "mr_rereg_err", + [HNS_ROCE_DFX_AH_CREATE_ERR_CNT] = "ah_create_err", + [HNS_ROCE_DFX_MMAP_ERR_CNT] = "mmap_err", + [HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT] = "uctx_alloc_err", +}; + +static int sw_stat_debugfs_show(struct seq_file *file, void *offset) +{ + struct hns_roce_dev *hr_dev = file->private; + int i; + + for (i = 0; i < HNS_ROCE_DFX_CNT_TOTAL; i++) + seq_printf(file, "%-20s --- %lld\n", sw_stat_info[i], + atomic64_read(&hr_dev->dfx_cnt[i])); + + return 0; +} + +static void create_sw_stat_debugfs(struct hns_roce_dev *hr_dev, + struct dentry *parent) +{ + struct hns_sw_stat_debugfs *dbgfs = &hr_dev->dbgfs.sw_stat_root; + + dbgfs->root = debugfs_create_dir("sw_stat", parent); + + init_debugfs_seqfile(&dbgfs->sw_stat, "sw_stat", dbgfs->root, + sw_stat_debugfs_show, hr_dev); +} + /* debugfs for device */ void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev) { @@ -43,6 +88,8 @@ void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev) dbgfs->root = debugfs_create_dir(dev_name(&hr_dev->ib_dev.dev), hns_roce_dbgfs_root); + + create_sw_stat_debugfs(hr_dev, dbgfs->root); } void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev) diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.h b/drivers/infiniband/hw/hns/hns_roce_debugfs.h index ece71fe6730c..98e87bd3161e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_debugfs.h +++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.h @@ -12,9 +12,15 @@ struct hns_debugfs_seqfile { void *data; }; +struct hns_sw_stat_debugfs { + struct dentry *root; + struct hns_debugfs_seqfile sw_stat; +}; + /* Debugfs for device */ struct hns_roce_dev_debugfs { struct dentry *root; + struct hns_sw_stat_debugfs sw_stat_root; }; struct hns_roce_dev; diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index a847cdfb4ad6..b1fce5ddf631 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -870,6 +870,29 @@ enum hns_roce_hw_pkt_stat_index { HNS_ROCE_HW_CNT_TOTAL }; +enum hns_roce_sw_dfx_stat_index { + HNS_ROCE_DFX_AEQE_CNT, + HNS_ROCE_DFX_CEQE_CNT, + HNS_ROCE_DFX_CMDS_CNT, + HNS_ROCE_DFX_CMDS_ERR_CNT, + HNS_ROCE_DFX_MBX_POSTED_CNT, + HNS_ROCE_DFX_MBX_POLLED_CNT, + HNS_ROCE_DFX_MBX_EVENT_CNT, + HNS_ROCE_DFX_QP_CREATE_ERR_CNT, + HNS_ROCE_DFX_QP_MODIFY_ERR_CNT, + HNS_ROCE_DFX_CQ_CREATE_ERR_CNT, + HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT, + HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT, + HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT, + HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT, + HNS_ROCE_DFX_MR_REG_ERR_CNT, + HNS_ROCE_DFX_MR_REREG_ERR_CNT, + HNS_ROCE_DFX_AH_CREATE_ERR_CNT, + HNS_ROCE_DFX_MMAP_ERR_CNT, + HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT, + HNS_ROCE_DFX_CNT_TOTAL +}; + struct hns_roce_hw { int (*cmq_init)(struct hns_roce_dev *hr_dev); void (*cmq_exit)(struct hns_roce_dev *hr_dev); @@ -981,6 +1004,7 @@ struct hns_roce_dev { u32 cong_algo_tmpl_id; u64 dwqe_page; struct hns_roce_dev_debugfs dbgfs; + atomic64_t *dfx_cnt; }; static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 8a5432bb0e85..5d0a7a1394fc 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1297,6 +1297,8 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev, /* Write to hardware */ roce_write(hr_dev, ROCEE_TX_CMQ_PI_REG, csq->head); + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CMDS_CNT]); + do { if (hns_roce_cmq_csq_done(hr_dev)) break; @@ -1334,6 +1336,9 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev, spin_unlock_bh(&csq->lock); + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CMDS_ERR_CNT]); + return ret; } @@ -5662,19 +5667,25 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq, struct hns_roce_srq_context *srq_context; struct hns_roce_srq_context *srqc_mask; struct hns_roce_cmd_mailbox *mailbox; - int ret; + int ret = 0; /* Resizing SRQs is not supported yet */ - if (srq_attr_mask & IB_SRQ_MAX_WR) - return -EOPNOTSUPP; + if (srq_attr_mask & IB_SRQ_MAX_WR) { + ret = -EOPNOTSUPP; + goto out; + } if (srq_attr_mask & IB_SRQ_LIMIT) { - if (srq_attr->srq_limit > srq->wqe_cnt) - return -EINVAL; + if (srq_attr->srq_limit > srq->wqe_cnt) { + ret = -EINVAL; + goto out; + } mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); + if (IS_ERR(mailbox)) { + ret = PTR_ERR(mailbox); + goto out; + } srq_context = mailbox->buf; srqc_mask = (struct hns_roce_srq_context *)mailbox->buf + 1; @@ -5687,15 +5698,17 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq, ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, HNS_ROCE_CMD_MODIFY_SRQC, srq->srqn); hns_roce_free_cmd_mailbox(hr_dev, mailbox); - if (ret) { + if (ret) ibdev_err(&hr_dev->ib_dev, "failed to handle cmd of modifying SRQ, ret = %d.\n", ret); - return ret; - } } - return 0; +out: + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT]); + + return ret; } static int hns_roce_v2_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) @@ -5739,8 +5752,9 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) int ret; mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); + ret = PTR_ERR_OR_ZERO(mailbox); + if (ret) + goto err_out; cq_context = mailbox->buf; cqc_mask = (struct hns_roce_v2_cq_context *)mailbox->buf + 1; @@ -5770,6 +5784,10 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) "failed to process cmd when modifying CQ, ret = %d.\n", ret); +err_out: + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT]); + return ret; } @@ -6009,6 +6027,8 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, ++eq->cons_index; aeqe_found = IRQ_HANDLED; + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_AEQE_CNT]); + hns_roce_v2_init_irq_work(hr_dev, eq, queue_num); aeqe = next_aeqe_sw_v2(eq); @@ -6050,6 +6070,7 @@ static irqreturn_t hns_roce_v2_ceq_int(struct hns_roce_dev *hr_dev, ++eq->cons_index; ceqe_found = IRQ_HANDLED; + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CEQE_CNT]); ceqe = next_ceqe_sw_v2(eq); } diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index c9f93ba522c9..b55fe6911f9f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -361,10 +361,10 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, struct hns_roce_dev *hr_dev = to_hr_dev(uctx->device); struct hns_roce_ib_alloc_ucontext_resp resp = {}; struct hns_roce_ib_alloc_ucontext ucmd = {}; - int ret; + int ret = -EAGAIN; if (!hr_dev->active) - return -EAGAIN; + goto error_out; resp.qp_tab_size = hr_dev->caps.num_qps; resp.srq_tab_size = hr_dev->caps.num_srqs; @@ -372,7 +372,7 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, ret = ib_copy_from_udata(&ucmd, udata, min(udata->inlen, sizeof(ucmd))); if (ret) - return ret; + goto error_out; if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) context->config = ucmd.config & HNS_ROCE_EXSGE_FLAGS; @@ -396,7 +396,7 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, ret = hns_roce_uar_alloc(hr_dev, &context->uar); if (ret) - goto error_fail_uar_alloc; + goto error_out; ret = hns_roce_alloc_uar_entry(uctx); if (ret) @@ -423,7 +423,9 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, error_fail_uar_entry: ida_free(&hr_dev->uar_ida.ida, (int)context->uar.logic_idx); -error_fail_uar_alloc: +error_out: + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT]); + return ret; } @@ -439,6 +441,7 @@ static void hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext) static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma) { + struct hns_roce_dev *hr_dev = to_hr_dev(uctx->device); struct rdma_user_mmap_entry *rdma_entry; struct hns_user_mmap_entry *entry; phys_addr_t pfn; @@ -446,8 +449,10 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma) int ret; rdma_entry = rdma_user_mmap_entry_get_pgoff(uctx, vma->vm_pgoff); - if (!rdma_entry) + if (!rdma_entry) { + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]); return -EINVAL; + } entry = to_hns_mmap(rdma_entry); pfn = entry->address >> PAGE_SHIFT; @@ -467,6 +472,9 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma) out: rdma_user_mmap_entry_put(rdma_entry); + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]); + return ret; } @@ -1009,6 +1017,21 @@ void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev) spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags); } +static int hns_roce_alloc_dfx_cnt(struct hns_roce_dev *hr_dev) +{ + hr_dev->dfx_cnt = kvcalloc(HNS_ROCE_DFX_CNT_TOTAL, sizeof(atomic64_t), + GFP_KERNEL); + if (!hr_dev->dfx_cnt) + return -ENOMEM; + + return 0; +} + +static void hns_roce_dealloc_dfx_cnt(struct hns_roce_dev *hr_dev) +{ + kvfree(hr_dev->dfx_cnt); +} + int hns_roce_init(struct hns_roce_dev *hr_dev) { struct device *dev = hr_dev->dev; @@ -1016,11 +1039,15 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) hr_dev->is_reset = false; + ret = hns_roce_alloc_dfx_cnt(hr_dev); + if (ret) + return ret; + if (hr_dev->hw->cmq_init) { ret = hr_dev->hw->cmq_init(hr_dev); if (ret) { dev_err(dev, "init RoCE Command Queue failed!\n"); - return ret; + goto error_failed_alloc_dfx_cnt; } } @@ -1105,6 +1132,9 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) if (hr_dev->hw->cmq_exit) hr_dev->hw->cmq_exit(hr_dev); +error_failed_alloc_dfx_cnt: + hns_roce_dealloc_dfx_cnt(hr_dev); + return ret; } @@ -1125,6 +1155,7 @@ void hns_roce_exit(struct hns_roce_dev *hr_dev) hns_roce_cmd_cleanup(hr_dev); if (hr_dev->hw->cmq_exit) hr_dev->hw->cmq_exit(hr_dev); + hns_roce_dealloc_dfx_cnt(hr_dev); } MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 14376490ac22..d68074b6ca17 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -228,8 +228,10 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int ret; mr = kzalloc(sizeof(*mr), GFP_KERNEL); - if (!mr) - return ERR_PTR(-ENOMEM); + if (!mr) { + ret = -ENOMEM; + goto err_out; + } mr->iova = virt_addr; mr->size = length; @@ -259,6 +261,9 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, free_mr_key(hr_dev, mr); err_alloc_mr: kfree(mr); +err_out: + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MR_REG_ERR_CNT]); + return ERR_PTR(ret); } @@ -274,12 +279,15 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start, unsigned long mtpt_idx; int ret; - if (!mr->enabled) - return ERR_PTR(-EINVAL); + if (!mr->enabled) { + ret = -EINVAL; + goto err_out; + } mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); - if (IS_ERR(mailbox)) - return ERR_CAST(mailbox); + ret = PTR_ERR_OR_ZERO(mailbox); + if (ret) + goto err_out; mtpt_idx = key_to_hw_index(mr->key) & (hr_dev->caps.num_mtpts - 1); @@ -331,8 +339,12 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start, free_cmd_mbox: hns_roce_free_cmd_mailbox(hr_dev, mailbox); - if (ret) +err_out: + if (ret) { + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MR_REREG_ERR_CNT]); return ERR_PTR(ret); + } + return NULL; } diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index bd1fe89ca205..d35cf59d0f43 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -149,14 +149,18 @@ int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata) struct hns_roce_xrcd *xrcd = to_hr_xrcd(ib_xrcd); int ret; - if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)) - return -EOPNOTSUPP; + if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)) { + ret = -EOPNOTSUPP; + goto err_out; + } ret = hns_roce_xrcd_alloc(hr_dev, &xrcd->xrcdn); - if (ret) - return ret; - return 0; +err_out: + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT]); + + return ret; } int hns_roce_dealloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 828b58534aa9..31b147210688 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -1216,7 +1216,7 @@ int hns_roce_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *init_attr, ret = check_qp_type(hr_dev, init_attr->qp_type, !!udata); if (ret) - return ret; + goto err_out; if (init_attr->qp_type == IB_QPT_XRC_TGT) hr_qp->xrcdn = to_hr_xrcd(init_attr->xrcd)->xrcdn; @@ -1231,6 +1231,10 @@ int hns_roce_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *init_attr, ibdev_err(ibdev, "create QP type 0x%x failed(%d)\n", init_attr->qp_type, ret); +err_out: + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_QP_CREATE_ERR_CNT]); + return ret; } @@ -1366,6 +1370,8 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, out: mutex_unlock(&hr_qp->mutex); + if (ret) + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_QP_MODIFY_ERR_CNT]); return ret; } diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index 4e2d1c8e164a..4abae9477854 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -475,11 +475,11 @@ int hns_roce_create_srq(struct ib_srq *ib_srq, ret = set_srq_param(srq, init_attr, udata); if (ret) - return ret; + goto err_out; ret = alloc_srq_buf(hr_dev, srq, udata); if (ret) - return ret; + goto err_out; ret = alloc_srq_db(hr_dev, srq, udata, &resp); if (ret) @@ -517,6 +517,8 @@ int hns_roce_create_srq(struct ib_srq *ib_srq, free_srq_db(hr_dev, srq, udata); err_srq_buf: free_srq_buf(hr_dev, srq); +err_out: + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT]); return ret; } From 0529e26d8b7b51da99c9d7234700f4041d20c0e4 Mon Sep 17 00:00:00 2001 From: Md Haris Iqbal Date: Wed, 15 Nov 2023 16:27:41 +0100 Subject: [PATCH 0932/7721] RDMA/rtrs-clt: Add warning logs for RDMA events Some RDMA CM events can trigger connection close or recovery for a certain rtrs_clt_path. Such close/recovery triggers should happen after an appropriate log message, since they can lead to IO failures. Signed-off-by: Md Haris Iqbal Signed-off-by: Jack Wang Signed-off-by: Grzegorz Prajsner Link: https://lore.kernel.org/r/20231115152749.424301-2-haris.iqbal@ionos.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 07261523c554..984a4a1db3c8 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -2025,6 +2025,8 @@ static int rtrs_clt_rdma_cm_handler(struct rdma_cm_id *cm_id, /* * Device removal is a special case. Queue close and return 0. */ + rtrs_wrn_rl(s, "CM event: %s, status: %d\n", rdma_event_msg(ev->event), + ev->status); rtrs_clt_close_conns(clt_path, false); return 0; default: From 2d1618054f25e11c44d189dbff4a60342a4cfb4b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 14 Nov 2023 17:32:34 +0100 Subject: [PATCH 0933/7721] bpf: task_group_seq_get_next: use __next_thread() rather than next_thread() Lockless use of next_thread() should be avoided, kernel/bpf/task_iter.c is the last user and the usage is wrong. task_group_seq_get_next() can return the group leader twice if it races with mt-thread exec which changes the group->leader's pid. Change the main loop to use __next_thread(), kill "next_tid == common->pid" check. __next_thread() can't loop forever, we can also change this code to retry if next_tid == 0. Signed-off-by: Oleg Nesterov Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231114163234.GA890@redhat.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/task_iter.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c index 26082b97894d..51ae15e2b290 100644 --- a/kernel/bpf/task_iter.c +++ b/kernel/bpf/task_iter.c @@ -70,15 +70,13 @@ static struct task_struct *task_group_seq_get_next(struct bpf_iter_seq_task_comm return NULL; retry: - task = next_thread(task); + task = __next_thread(task); + if (!task) + return NULL; next_tid = __task_pid_nr_ns(task, PIDTYPE_PID, common->ns); - if (!next_tid || next_tid == common->pid) { - /* Run out of tasks of a process. The tasks of a - * thread_group are linked as circular linked list. - */ - return NULL; - } + if (!next_tid) + goto retry; if (skip_if_dup_files && task->files == task->group_leader->files) goto retry; From 5a34f9dabd9aa567e2d37e1aa27a67f80acfaa1c Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 14 Nov 2023 17:32:37 +0100 Subject: [PATCH 0934/7721] bpf: bpf_iter_task_next: use __next_thread() rather than next_thread() Lockless use of next_thread() should be avoided, kernel/bpf/task_iter.c is the last user and the usage is wrong. bpf_iter_task_next() can loop forever, "kit->pos == kit->task" can never happen if kit->pos execs. Change this code to use __next_thread(). With or without this change the usage of kit->pos/task and next_task() doesn't look nice, see the next patch. Signed-off-by: Oleg Nesterov Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231114163237.GA897@redhat.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/task_iter.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c index 51ae15e2b290..d42e08d0d0b7 100644 --- a/kernel/bpf/task_iter.c +++ b/kernel/bpf/task_iter.c @@ -1015,12 +1015,11 @@ __bpf_kfunc struct task_struct *bpf_iter_task_next(struct bpf_iter_task *it) if (flags == BPF_TASK_ITER_ALL_PROCS) goto get_next_task; - kit->pos = next_thread(kit->pos); - if (kit->pos == kit->task) { - if (flags == BPF_TASK_ITER_PROC_THREADS) { - kit->pos = NULL; + kit->pos = __next_thread(kit->pos); + if (!kit->pos) { + if (flags == BPF_TASK_ITER_PROC_THREADS) return pos; - } + kit->pos = kit->task; } else return pos; From ac8148d957f50434411a0c15a2e4f352b5bb4ff2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 14 Nov 2023 17:32:39 +0100 Subject: [PATCH 0935/7721] bpf: bpf_iter_task_next: use next_task(kit->task) rather than next_task(kit->pos) This looks more clear and simplifies the code. While at it, remove the unnecessary initialization of pos/task at the start of bpf_iter_task_new(). Note that we can even kill kit->task, we can just use pos->group_leader, but I don't understand the BUILD_BUG_ON() checks in bpf_iter_task_new(). Signed-off-by: Oleg Nesterov Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231114163239.GA903@redhat.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/task_iter.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c index d42e08d0d0b7..e5c3500443c6 100644 --- a/kernel/bpf/task_iter.c +++ b/kernel/bpf/task_iter.c @@ -978,7 +978,6 @@ __bpf_kfunc int bpf_iter_task_new(struct bpf_iter_task *it, BUILD_BUG_ON(__alignof__(struct bpf_iter_task_kern) != __alignof__(struct bpf_iter_task)); - kit->task = kit->pos = NULL; switch (flags) { case BPF_TASK_ITER_ALL_THREADS: case BPF_TASK_ITER_ALL_PROCS: @@ -1016,18 +1015,15 @@ __bpf_kfunc struct task_struct *bpf_iter_task_next(struct bpf_iter_task *it) goto get_next_task; kit->pos = __next_thread(kit->pos); - if (!kit->pos) { - if (flags == BPF_TASK_ITER_PROC_THREADS) - return pos; - kit->pos = kit->task; - } else + if (kit->pos || flags == BPF_TASK_ITER_PROC_THREADS) return pos; get_next_task: - kit->pos = next_task(kit->pos); - kit->task = kit->pos; - if (kit->pos == &init_task) + kit->task = next_task(kit->task); + if (kit->task == &init_task) kit->pos = NULL; + else + kit->pos = kit->task; return pos; } From 67372d7a85fcdb9761194f70c88aa3fab0ce1449 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Nov 2023 14:17:52 +0200 Subject: [PATCH 0936/7721] net: ethernet: am65-cpsw: Add standard Ethernet MAC stats to ethtool Gets 'ethtool -S eth0 --groups eth-mac' command to work. Signed-off-by: Roger Quadros Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-ethtool.c | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c index c51e2af91f69..b9e1d568604b 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c +++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c @@ -662,6 +662,31 @@ static void am65_cpsw_get_ethtool_stats(struct net_device *ndev, hw_stats[i].offset); } +static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev, + struct ethtool_eth_mac_stats *s) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_stats_regs __iomem *stats; + + stats = port->stat_base; + + s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames); + s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames); + s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames); + s->FramesReceivedOK = readl_relaxed(&stats->rx_good_frames); + s->FrameCheckSequenceErrors = readl_relaxed(&stats->rx_crc_errors); + s->AlignmentErrors = readl_relaxed(&stats->rx_align_code_errors); + s->OctetsTransmittedOK = readl_relaxed(&stats->tx_octets); + s->FramesWithDeferredXmissions = readl_relaxed(&stats->tx_deferred_frames); + s->LateCollisions = readl_relaxed(&stats->tx_late_collisions); + s->CarrierSenseErrors = readl_relaxed(&stats->tx_carrier_sense_errors); + s->OctetsReceivedOK = readl_relaxed(&stats->rx_octets); + s->MulticastFramesXmittedOK = readl_relaxed(&stats->tx_multicast_frames); + s->BroadcastFramesXmittedOK = readl_relaxed(&stats->tx_broadcast_frames); + s->MulticastFramesReceivedOK = readl_relaxed(&stats->rx_multicast_frames); + s->BroadcastFramesReceivedOK = readl_relaxed(&stats->rx_broadcast_frames); +}; + static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) { @@ -729,6 +754,7 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = { .get_sset_count = am65_cpsw_get_sset_count, .get_strings = am65_cpsw_get_strings, .get_ethtool_stats = am65_cpsw_get_ethtool_stats, + .get_eth_mac_stats = am65_cpsw_get_eth_mac_stats, .get_ts_info = am65_cpsw_get_ethtool_ts_info, .get_priv_flags = am65_cpsw_get_ethtool_priv_flags, .set_priv_flags = am65_cpsw_set_ethtool_priv_flags, From ac099466961b27ee069c5fd606f228c3df7303e8 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Nov 2023 14:17:53 +0200 Subject: [PATCH 0937/7721] net: ethernet: ti: am65-cpsw: Re-arrange functions to avoid forward declaration Re-arrange am65_cpsw_nuss_rx_cleanup(), am65_cpsw_nuss_xmit_free() and am65_cpsw_nuss_tx_cleanup() to avoid forward declaration. No functional change. Signed-off-by: Roger Quadros Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 145 +++++++++++------------ 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index ece9f8df98ae..adb29e8e8026 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -367,6 +367,77 @@ static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common); static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port); static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port); +static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct am65_cpsw_rx_chn *rx_chn = data; + struct cppi5_host_desc_t *desc_rx; + struct sk_buff *skb; + dma_addr_t buf_dma; + u32 buf_dma_len; + void **swdata; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_rx); + skb = *swdata; + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); + + dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + dev_kfree_skb_any(skb); +} + +static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn, + struct cppi5_host_desc_t *desc) +{ + struct cppi5_host_desc_t *first_desc, *next_desc; + dma_addr_t buf_dma, next_desc_dma; + u32 buf_dma_len; + + first_desc = desc; + next_desc = first_desc; + + cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + while (next_desc_dma) { + next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + next_desc_dma); + cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + } + + k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); +} + +static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct am65_cpsw_tx_chn *tx_chn = data; + struct cppi5_host_desc_t *desc_tx; + struct sk_buff *skb; + void **swdata; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + skb = *(swdata); + am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); + + dev_kfree_skb_any(skb); +} + static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) { struct am65_cpsw_host *host_p = am65_common_get_host(common); @@ -470,9 +541,6 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) return 0; } -static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma); -static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma); - static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common) { int i; @@ -646,27 +714,6 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) return ret; } -static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) -{ - struct am65_cpsw_rx_chn *rx_chn = data; - struct cppi5_host_desc_t *desc_rx; - struct sk_buff *skb; - dma_addr_t buf_dma; - u32 buf_dma_len; - void **swdata; - - desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_rx); - skb = *swdata; - cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); - k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); - - dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - - dev_kfree_skb_any(skb); -} - static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata) { struct skb_shared_hwtstamps *ssh; @@ -840,56 +887,6 @@ static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget) return num_rx; } -static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn, - struct cppi5_host_desc_t *desc) -{ - struct cppi5_host_desc_t *first_desc, *next_desc; - dma_addr_t buf_dma, next_desc_dma; - u32 buf_dma_len; - - first_desc = desc; - next_desc = first_desc; - - cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - while (next_desc_dma) { - next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, - next_desc_dma); - cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, - DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - - k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); - } - - k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); -} - -static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) -{ - struct am65_cpsw_tx_chn *tx_chn = data; - struct cppi5_host_desc_t *desc_tx; - struct sk_buff *skb; - void **swdata; - - desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_tx); - skb = *(swdata); - am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); - - dev_kfree_skb_any(skb); -} - static struct sk_buff * am65_cpsw_nuss_tx_compl_packet(struct am65_cpsw_tx_chn *tx_chn, dma_addr_t desc_dma) From be397ea3473d24ce596f3aaa22a55af9b004fed8 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Nov 2023 14:17:54 +0200 Subject: [PATCH 0938/7721] net: ethernet: am65-cpsw: Set default TX channels to maximum am65-cpsw supports 8 TX hardware queues. Set this as default. The rationale is that some am65-cpsw devices can have up to 4 ethernet ports. If the number of TX channels have to be changed then all interfaces have to be brought down and up as the old default of 1 TX channel is too restrictive for any mqprio/taprio usage. Another reason for this change is to allow testing using kselftest:net/forwarding:ethtool_mm.sh out of the box. Signed-off-by: Roger Quadros Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index adb29e8e8026..78b3e69fbccb 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -136,6 +136,8 @@ NETIF_MSG_IFUP | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | \ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) +#define AM65_CPSW_DEFAULT_TX_CHNS 8 + static void am65_cpsw_port_set_sl_mac(struct am65_cpsw_port *slave, const u8 *dev_addr) { @@ -2894,7 +2896,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) common->rx_flow_id_base = -1; init_completion(&common->tdown_complete); - common->tx_ch_num = 1; + common->tx_ch_num = AM65_CPSW_DEFAULT_TX_CHNS; common->pf_p0_rx_ptype_rrobin = false; common->default_vlan = 1; From ebd7bf60e21c567a7fbe0e2a7bc4be8406ff8093 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Nov 2023 14:17:55 +0200 Subject: [PATCH 0939/7721] net: ethernet: ti: am65-cpsw: Fix error handling in am65_cpsw_nuss_common_open() k3_udma_glue_enable_rx/tx_chn returns error code on failure. Bail out on error while enabling TX/RX channel. In the error path, clean up the RX descriptors and SKBs. Get rid of kmemleak_not_leak() as it seems unnecessary now. Fixes: 93a76530316a ("net: ethernet: ti: introduce am65x/j721e gigabit eth subsystem driver") Signed-off-by: Roger Quadros Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 48 +++++++++++++++++++----- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 78b3e69fbccb..7992a76ed4d8 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -443,7 +443,7 @@ static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) { struct am65_cpsw_host *host_p = am65_common_get_host(common); - int port_idx, i, ret; + int port_idx, i, ret, tx; struct sk_buff *skb; u32 val, port_mask; @@ -510,8 +510,12 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) AM65_CPSW_MAX_PACKET_SIZE, GFP_KERNEL); if (!skb) { + ret = -ENOMEM; dev_err(common->dev, "cannot allocate skb\n"); - return -ENOMEM; + if (i) + goto fail_rx; + + return ret; } ret = am65_cpsw_nuss_rx_push(common, skb); @@ -520,17 +524,28 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) "cannot submit skb to channel rx, error %d\n", ret); kfree_skb(skb); + if (i) + goto fail_rx; + return ret; } - kmemleak_not_leak(skb); } - k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn); - for (i = 0; i < common->tx_ch_num; i++) { - ret = k3_udma_glue_enable_tx_chn(common->tx_chns[i].tx_chn); - if (ret) - return ret; - napi_enable(&common->tx_chns[i].napi_tx); + ret = k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn); + if (ret) { + dev_err(common->dev, "couldn't enable rx chn: %d\n", ret); + goto fail_rx; + } + + for (tx = 0; tx < common->tx_ch_num; tx++) { + ret = k3_udma_glue_enable_tx_chn(common->tx_chns[tx].tx_chn); + if (ret) { + dev_err(common->dev, "couldn't enable tx chn %d: %d\n", + tx, ret); + tx--; + goto fail_tx; + } + napi_enable(&common->tx_chns[tx].napi_tx); } napi_enable(&common->napi_rx); @@ -541,6 +556,21 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) dev_dbg(common->dev, "cpsw_nuss started\n"); return 0; + +fail_tx: + while (tx >= 0) { + napi_disable(&common->tx_chns[tx].napi_tx); + k3_udma_glue_disable_tx_chn(common->tx_chns[tx].tx_chn); + tx--; + } + + k3_udma_glue_disable_rx_chn(common->rx_chns.rx_chn); + +fail_rx: + k3_udma_glue_reset_rx_chn(common->rx_chns.rx_chn, 0, + &common->rx_chns, + am65_cpsw_nuss_rx_cleanup, 0); + return ret; } static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common) From 94c81c62668954269ec852ab0284256db20ed9b4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Nov 2023 17:39:22 +0100 Subject: [PATCH 0940/7721] net: ethernet: mtk_wed: rely on __dev_alloc_page in mtk_wed_tx_buffer_alloc Simplify the code and use __dev_alloc_page() instead of __dev_alloc_pages() with order 0 in mtk_wed_tx_buffer_alloc routine Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_wed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 9a6744c0d458..2ac35543fcfb 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -670,7 +670,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) void *buf; int s; - page = __dev_alloc_pages(GFP_KERNEL, 0); + page = __dev_alloc_page(GFP_KERNEL); if (!page) return -ENOMEM; From 804901fdd637c7af8b767c329fd84aa0d3d617ec Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Nov 2023 09:42:07 +0100 Subject: [PATCH 0941/7721] ata: pata_pxa: convert not to use dma_request_slave_channel() dma_request_slave_channel() is deprecated. dma_request_chan() should be used directly instead. Switch to the preferred function and update the error handling accordingly. While at it, also propagate the error code that is now available. Signed-off-by: Christophe JAILLET Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_pxa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index 5275c6464f57..538bd3423d85 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -274,10 +274,9 @@ static int pxa_ata_probe(struct platform_device *pdev) /* * Request the DMA channel */ - data->dma_chan = - dma_request_slave_channel(&pdev->dev, "data"); - if (!data->dma_chan) - return -EBUSY; + data->dma_chan = dma_request_chan(&pdev->dev, "data"); + if (IS_ERR(data->dma_chan)) + return PTR_ERR(data->dma_chan); ret = dmaengine_slave_config(data->dma_chan, &config); if (ret < 0) { dev_err(&pdev->dev, "dma configuration failed: %d\n", ret); From e04d24c4e8062b5ed0bee7a871423a454d24ffed Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 16 Nov 2023 22:44:53 -0500 Subject: [PATCH 0942/7721] drm/print: Handle NULL drm device in __drm_printk() drm_{err,warn,...}() use __drm_printk() which takes a drm device pointer and uses the embedded device pointer to print the device. This facility handles NULL device pointer, but not NULL drm device pointer. This patch makes __drm_printk() also handle a NULL drm device pointer. The printed output is identical to if drm->dev had been NULL. Signed-off-by: Luben Tuikov Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231117035427.68125-2-ltuikov89@gmail.com --- include/drm/drm_print.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index a93a387f8a1a..dd4883df876a 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -453,7 +453,7 @@ void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev, /* Helper for struct drm_device based logging. */ #define __drm_printk(drm, level, type, fmt, ...) \ - dev_##level##type((drm)->dev, "[drm] " fmt, ##__VA_ARGS__) + dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__) #define drm_info(drm, fmt, ...) \ From 02d70090e0e020eff440dbe51e93fe2fc94d9835 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 19 Nov 2023 20:55:00 +0200 Subject: [PATCH 0943/7721] ovl: remove redundant ofs->indexdir member When the index feature is disabled, ofs->indexdir is NULL. When the index feature is enabled, ofs->indexdir has the same value as ofs->workdir and takes an extra reference. This makes the code harder to understand when it is not always clear that ofs->indexdir in one function is the same dentry as ofs->workdir in another function. Remove this redundancy, by referencing ofs->workdir directly in index helpers and by using the ovl_indexdir() accessor in generic code. Signed-off-by: Amir Goldstein --- fs/overlayfs/export.c | 4 ++-- fs/overlayfs/namei.c | 4 ++-- fs/overlayfs/ovl_entry.h | 5 +---- fs/overlayfs/params.c | 2 -- fs/overlayfs/readdir.c | 2 +- fs/overlayfs/super.c | 19 ++++++++----------- fs/overlayfs/util.c | 2 +- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 7e16bbcad95e..6909c4a5da56 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -460,7 +460,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb, * For decoded lower dir file handle, lookup index by origin to check * if lower dir was copied up and and/or removed. */ - if (!this && layer->idx && ofs->indexdir && !WARN_ON(!d_is_dir(real))) { + if (!this && layer->idx && ovl_indexdir(sb) && !WARN_ON(!d_is_dir(real))) { index = ovl_lookup_index(ofs, NULL, real, false); if (IS_ERR(index)) return index; @@ -733,7 +733,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, } /* Then lookup indexed upper/whiteout by origin fh */ - if (ofs->indexdir) { + if (ovl_indexdir(sb)) { index = ovl_get_index_fh(ofs, fh); err = PTR_ERR(index); if (IS_ERR(index)) { diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 03bc8d5dfa31..984ffdaeed6c 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -754,7 +754,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh) if (err) return ERR_PTR(err); - index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len); + index = lookup_positive_unlocked(name.name, ofs->workdir, name.len); kfree(name.name); if (IS_ERR(index)) { if (PTR_ERR(index) == -ENOENT) @@ -787,7 +787,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, return ERR_PTR(err); index = lookup_one_positive_unlocked(ovl_upper_mnt_idmap(ofs), name.name, - ofs->indexdir, name.len); + ofs->workdir, name.len); if (IS_ERR(index)) { err = PTR_ERR(index); if (err == -ENOENT) { diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index d82d2a043da2..5fa9c58af65f 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -63,10 +63,8 @@ struct ovl_fs { struct ovl_sb *fs; /* workbasedir is the path at workdir= mount option */ struct dentry *workbasedir; - /* workdir is the 'work' directory under workbasedir */ + /* workdir is the 'work' or 'index' directory under workbasedir */ struct dentry *workdir; - /* index directory listing overlay inodes by origin file handle */ - struct dentry *indexdir; long namelen; /* pathnames of lower and upper dirs, for show_options */ struct ovl_config config; @@ -81,7 +79,6 @@ struct ovl_fs { /* Traps in ovl inode cache */ struct inode *workbasedir_trap; struct inode *workdir_trap; - struct inode *indexdir_trap; /* -1: disabled, 0: same fs, 1..32: number of unused ino bits */ int xino_mode; /* For allocation of non-persistent inode numbers */ diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c index 3fe2dde1598f..112b4b12f825 100644 --- a/fs/overlayfs/params.c +++ b/fs/overlayfs/params.c @@ -743,10 +743,8 @@ void ovl_free_fs(struct ovl_fs *ofs) unsigned i; iput(ofs->workbasedir_trap); - iput(ofs->indexdir_trap); iput(ofs->workdir_trap); dput(ofs->whiteout); - dput(ofs->indexdir); dput(ofs->workdir); if (ofs->workdir_locked) ovl_inuse_unlock(ofs->workbasedir); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index a490fc47c3e7..e71156baa7bc 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -1169,7 +1169,7 @@ int ovl_workdir_cleanup(struct ovl_fs *ofs, struct inode *dir, int ovl_indexdir_cleanup(struct ovl_fs *ofs) { int err; - struct dentry *indexdir = ofs->indexdir; + struct dentry *indexdir = ofs->workdir; struct dentry *index = NULL; struct inode *dir = indexdir->d_inode; struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = indexdir }; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index a0967bb25003..f78161cf8388 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -853,10 +853,8 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, if (IS_ERR(indexdir)) { err = PTR_ERR(indexdir); } else if (indexdir) { - ofs->indexdir = indexdir; - ofs->workdir = dget(indexdir); - - err = ovl_setup_trap(sb, ofs->indexdir, &ofs->indexdir_trap, + ofs->workdir = indexdir; + err = ovl_setup_trap(sb, indexdir, &ofs->workdir_trap, "indexdir"); if (err) goto out; @@ -869,16 +867,15 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, * ".overlay.upper" to indicate that index may have * directory entries. */ - if (ovl_check_origin_xattr(ofs, ofs->indexdir)) { - err = ovl_verify_origin_xattr(ofs, ofs->indexdir, + if (ovl_check_origin_xattr(ofs, indexdir)) { + err = ovl_verify_origin_xattr(ofs, indexdir, OVL_XATTR_ORIGIN, upperpath->dentry, true, false); if (err) pr_err("failed to verify index dir 'origin' xattr\n"); } - err = ovl_verify_upper(ofs, ofs->indexdir, upperpath->dentry, - true); + err = ovl_verify_upper(ofs, indexdir, upperpath->dentry, true); if (err) pr_err("failed to verify index dir 'upper' xattr\n"); @@ -886,7 +883,7 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, if (!err) err = ovl_indexdir_cleanup(ofs); } - if (err || !ofs->indexdir) + if (err || !indexdir) pr_warn("try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); out: @@ -1406,7 +1403,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) goto out_free_oe; /* Force r/o mount with no index dir */ - if (!ofs->indexdir) + if (!ofs->workdir) sb->s_flags |= SB_RDONLY; } @@ -1415,7 +1412,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) goto out_free_oe; /* Show index=off in /proc/mounts for forced r/o mount */ - if (!ofs->indexdir) { + if (!ofs->workdir) { ofs->config.index = false; if (ovl_upper_mnt(ofs) && ofs->config.nfs_export) { pr_warn("NFS export requires an index dir, falling back to nfs_export=off.\n"); diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index c3f020ca13a8..22b519763267 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -91,7 +91,7 @@ struct dentry *ovl_indexdir(struct super_block *sb) { struct ovl_fs *ofs = OVL_FS(sb); - return ofs->indexdir; + return ofs->config.index ? ofs->workdir : NULL; } /* Index all files on copy up. For now only enabled for NFS export */ From f154ef08ca637c26178cb7a5c8e7b75952a47ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 31 Oct 2023 15:57:39 +0100 Subject: [PATCH 0944/7721] clk: renesas: r8a779g0: Add EtherTSN clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the TSN module clock, which is used by the EtherTSN module on the Renesas R-Car V4H (R8A779G0) SoC. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231031145739.657638-1-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779g0-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index 7cc580d67362..affc5fc60332 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -235,6 +235,7 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M), DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M), DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M), + DEF_MOD("tsn", 2723, R8A779G0_CLK_S0D4_HSC), DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER), DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER), }; From 5ab16198b431ca4885dbcc3433527fdf5b66be3c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 14 Nov 2023 21:22:52 +0900 Subject: [PATCH 0945/7721] clk: renesas: r8a779g0: Add PCIe clocks Add the PCIe module clocks, which are used by the PCIe modules on the Renesas R-Car V4H (R8A779G0) SoC. Note that the following descriptions in the hardware manual Rev.0.81 about the PCIe module clocks are incorrect: 9.2.1.7 Software Reset Register 6 (SRCR6) 9.2.1.12 Software Reset Register 11 (SRCR11) 9.2.3.7 Module Stop Control Register 6 (MSTPCR6) Please refer to Figures 104.3[ab] instead. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231114122252.2266799-1-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779g0-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index affc5fc60332..5974adcef3ed 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -192,6 +192,8 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("msi3", 621, R8A779G0_CLK_MSO), DEF_MOD("msi4", 622, R8A779G0_CLK_MSO), DEF_MOD("msi5", 623, R8A779G0_CLK_MSO), + DEF_MOD("pciec0", 624, R8A779G0_CLK_S0D2_HSC), + DEF_MOD("pscie1", 625, R8A779G0_CLK_S0D2_HSC), DEF_MOD("pwm", 628, R8A779G0_CLK_SASYNCPERD4), DEF_MOD("rpc-if", 629, R8A779G0_CLK_RPCD2), DEF_MOD("scif0", 702, R8A779G0_CLK_SASYNCPERD4), From 00cbba479142a3c962a44b127db4ab6cdc2b2b70 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 16 Oct 2023 13:53:43 +0300 Subject: [PATCH 0946/7721] arm64: dts: renesas: rzg3s-smarc-som: Enable SDHI2 Add SDHI2 to RZ/G3S Smarc SoM. SDHI2 pins are multiplexed with SCIF1, SSI0, IRQ0, IRQ1. The selection b/w SDHI2 and SCIF1, SSI0, IRQ0, IRQ1 is done with a switch button. To be able to select b/w these a compilation flag has been added (SW_SD2_EN) at the moment being instantiated to select SDHI2. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231016105344.294096-2-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../boot/dts/renesas/rzg3s-smarc-som.dtsi | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi index a199de8f8b02..01a4a9da7afc 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi @@ -13,14 +13,21 @@ * @SW_SD0_DEV_SEL: * 0 - SD0 is connected to eMMC * 1 - SD0 is connected to uSD0 card + * @SW_SD2_EN: + * 0 - SCIF1, SSI0, IRQ0, IRQ1 connected to SoC + * 1 - SD2 is connected to SoC */ #define SW_SD0_DEV_SEL 1 +#define SW_SD2_EN 1 / { compatible = "renesas,rzg3s-smarcm", "renesas,r9a08g045s33", "renesas,r9a08g045"; aliases { mmc0 = &sdhi0; +#if SW_SD2_EN + mmc2 = &sdhi2; +#endif }; chosen { @@ -63,6 +70,15 @@ reg_1p8v: regulator1 { regulator-always-on; }; #endif + + vcc_sdhi2: regulator2 { + compatible = "regulator-fixed"; + regulator-name = "SDHI2 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(8, 1) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; }; &extal_clk { @@ -100,6 +116,17 @@ &sdhi0 { }; #endif +#if SW_SD2_EN +&sdhi2 { + pinctrl-0 = <&sdhi2_pins>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_sdhi2>; + bus-width = <4>; + max-frequency = <50000000>; + status = "okay"; +}; +#endif + &pinctrl { sdhi0_pins: sd0 { data { @@ -139,4 +166,26 @@ sdhi0_emmc_pins: sd0-emmc { "SD0_CLK", "SD0_CMD", "SD0_RST#"; power-source = <1800>; }; + + sdhi2_pins: sd2 { + data { + pins = "P11_2", "P11_3", "P12_0", "P12_1"; + input-enable; + }; + + ctrl { + pins = "P11_1"; + input-enable; + }; + + mux { + pinmux = , /* SD2_CLK */ + , /* SD2_CMD */ + , /* SD2_DATA0 */ + , /* SD2_DATA1 */ + , /* SD2_DATA2 */ + , /* SD2_DATA3 */ + ; /* SD2_CD# */ + }; + }; }; From 993a207c114e137159c8d255576badfcd9defba8 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 16 Oct 2023 13:53:44 +0300 Subject: [PATCH 0947/7721] arm64: dts: renesas: rzg3s-smarc: Enable SDHI1 Add SDHI1 to RZ/G3S Smarc Carrier-II board. This is connected to a uSD interface. Although Vccq doesn't cross the boundary of SoM it has been added to RZ/G3S Smarc Carrier-II dtsi to have all the bits related to SDHI1 in a single place. At the moment SoM is used only with RZ/G3S Smarc Carrier-II board. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231016105344.294096-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi index e7073a09ed2e..214520137230 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi @@ -11,6 +11,26 @@ / { aliases { serial0 = &scif0; + mmc1 = &sdhi1; + }; + + vcc_sdhi1: regulator-vcc-sdhi1 { + compatible = "regulator-fixed"; + regulator-name = "SDHI1 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(2, 3) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhi1: regulator-vccq-sdhi1 { + compatible = "regulator-gpio"; + regulator-name = "SDHI1 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(4, 2) GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1>, <1800000 0>; }; }; @@ -19,6 +39,38 @@ scif0_pins: scif0 { pinmux = , /* RXD */ ; /* TXD */ }; + + sdhi1_pins: sd1 { + data { + pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; + power-source = <3300>; + }; + + ctrl { + pins = "SD1_CLK", "SD1_CMD"; + power-source = <3300>; + }; + + cd { + pinmux = ; /* SD1_CD */ + }; + }; + + sdhi1_pins_uhs: sd1-uhs { + data { + pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; + power-source = <1800>; + }; + + ctrl { + pins = "SD1_CLK", "SD1_CMD"; + power-source = <1800>; + }; + + cd { + pinmux = ; /* SD1_CD */ + }; + }; }; &scif0 { @@ -26,3 +78,16 @@ &scif0 { pinctrl-0 = <&scif0_pins>; status = "okay"; }; + +&sdhi1 { + pinctrl-0 = <&sdhi1_pins>; + pinctrl-1 = <&sdhi1_pins_uhs>; + pinctrl-names = "default", "state_uhs"; + vmmc-supply = <&vcc_sdhi1>; + vqmmc-supply = <&vccq_sdhi1>; + bus-width = <4>; + sd-uhs-sdr50; + sd-uhs-sdr104; + max-frequency = <125000000>; + status = "okay"; +}; From 8bcac1be55e188e5bac3353b550c9cddb70fbbed Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:31 -0600 Subject: [PATCH 0948/7721] dt-bindings: display: nv3051d: Update NewVision NV3051D compatibles Update the NewVision NV3051D compatible strings by adding a new panel, the powkiddy,rk2023-panel, and removing another entry, the anbernic,rg353v-panel. The rk2023-panel is similar to the rg353p-panel but has slightly different timings so it needs a new string. The rg353v-panel is duplicate to the rg353p-panel, so remove it. No current devices use it and changes to the driver mean it is no longer valid as a compatible string. Signed-off-by: Chris Morgan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231117202536.1387815-2-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117202536.1387815-2-macroalpha82@gmail.com --- .../devicetree/bindings/display/panel/newvision,nv3051d.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml index cce775a87f87..7a634fbc465e 100644 --- a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml +++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml @@ -21,7 +21,7 @@ properties: - enum: - anbernic,rg351v-panel - anbernic,rg353p-panel - - anbernic,rg353v-panel + - powkiddy,rk2023-panel - const: newvision,nv3051d reg: true From 697ebc319b942403a6fee894607fd2cd47cca069 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:32 -0600 Subject: [PATCH 0949/7721] drm/panel: nv3051d: Hold panel in reset for unprepare Improve the panel's ability to restore from suspend by holding the panel in suspend after unprepare. Fixes: b1d39f0f4264 ("drm/panel: Add NewVision NV3051D MIPI-DSI LCD panel") Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231117202536.1387815-3-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117202536.1387815-3-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-newvision-nv3051d.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index 79de6c886292..c44c6945662f 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -261,6 +261,8 @@ static int panel_nv3051d_unprepare(struct drm_panel *panel) usleep_range(10000, 15000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_disable(ctx->vdd); return 0; From 0aa1cfa3d287930cbecc52cd2b38683a4bf98463 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:33 -0600 Subject: [PATCH 0950/7721] drm/panel: nv3051d: Add Powkiddy RK2023 Panel Support Refactor the driver to add support for the powkiddy,rk2023-panel panel. This panel is extremely similar to the rg353p-panel but requires a smaller vertical back porch and isn't as tolerant of higher speeds. Note that while all of these panels are identical in size (70x57) it is possible future panels may not be. Tested on my RG351V, RG353P, RG353V, and RK2023. Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231117202536.1387815-4-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117202536.1387815-4-macroalpha82@gmail.com --- .../gpu/drm/panel/panel-newvision-nv3051d.c | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index c44c6945662f..94d89ffd596b 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -28,6 +28,7 @@ struct nv3051d_panel_info { unsigned int num_modes; u16 width_mm, height_mm; u32 bus_flags; + u32 mode_flags; }; struct panel_nv3051d { @@ -387,15 +388,7 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - - /* - * The panel in the RG351V is identical to the 353P, except it - * requires MIPI_DSI_CLOCK_NON_CONTINUOUS to operate correctly. - */ - if (of_device_is_compatible(dev->of_node, "anbernic,rg351v-panel")) - dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; + dsi->mode_flags = ctx->panel_info->mode_flags; drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs, DRM_MODE_CONNECTOR_DSI); @@ -483,16 +476,56 @@ static const struct drm_display_mode nv3051d_rgxx3_modes[] = { }, }; -static const struct nv3051d_panel_info nv3051d_rgxx3_info = { +static const struct drm_display_mode nv3051d_rk2023_modes[] = { + { + .hdisplay = 640, + .hsync_start = 640 + 40, + .hsync_end = 640 + 40 + 2, + .htotal = 640 + 40 + 2 + 80, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 2, + .vtotal = 480 + 18 + 2 + 4, + .clock = 24150, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, +}; + +static const struct nv3051d_panel_info nv3051d_rg351v_info = { .display_modes = nv3051d_rgxx3_modes, .num_modes = ARRAY_SIZE(nv3051d_rgxx3_modes), .width_mm = 70, .height_mm = 57, .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + +static const struct nv3051d_panel_info nv3051d_rg353p_info = { + .display_modes = nv3051d_rgxx3_modes, + .num_modes = ARRAY_SIZE(nv3051d_rgxx3_modes), + .width_mm = 70, + .height_mm = 57, + .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, +}; + +static const struct nv3051d_panel_info nv3051d_rk2023_info = { + .display_modes = nv3051d_rk2023_modes, + .num_modes = ARRAY_SIZE(nv3051d_rk2023_modes), + .width_mm = 70, + .height_mm = 57, + .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; static const struct of_device_id newvision_nv3051d_of_match[] = { - { .compatible = "newvision,nv3051d", .data = &nv3051d_rgxx3_info }, + { .compatible = "anbernic,rg351v-panel", .data = &nv3051d_rg351v_info }, + { .compatible = "anbernic,rg353p-panel", .data = &nv3051d_rg353p_info }, + { .compatible = "powkiddy,rk2023-panel", .data = &nv3051d_rk2023_info }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, newvision_nv3051d_of_match); From c18b1b49764a1db824ed74286338b6283b619286 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 13:44:01 -0600 Subject: [PATCH 0951/7721] drm/panel-elida-kd35t133: trival: update panel size from 5.5 to 3.5 The comments at the top of the driver state the panel size incorrectly as 5.5" instead of 3.5". Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231117194405.1386265-2-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117194405.1386265-2-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-elida-kd35t133.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index e7be15b68102..6cd8536c09ff 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Elida kd35t133 5.5" MIPI-DSI panel driver + * Elida kd35t133 3.5" MIPI-DSI panel driver * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH * * based on From 03c5b2a5f6c39fe4e090346536cf1c14ee18b61e Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 13:44:02 -0600 Subject: [PATCH 0952/7721] drm/panel-elida-kd35t133: hold panel in reset for unprepare For devices like the Anbernic RG351M and RG351P the panel is wired to an always on regulator. When the device suspends and wakes up, there are some slight artifacts on the screen that go away over time. If instead we hold the panel in reset status after it is unprepared, this does not happen. Fixes: 5b6603360c12 ("drm/panel: add panel driver for Elida KD35T133 panels") Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231117194405.1386265-3-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117194405.1386265-3-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-elida-kd35t133.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index 6cd8536c09ff..f1fc4a26f447 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -104,6 +104,8 @@ static int kd35t133_unprepare(struct drm_panel *panel) return ret; } + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_disable(ctx->iovcc); regulator_disable(ctx->vdd); From 3fc828b8ce2362982237f46a7cd46677f9094a8e Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 13:44:03 -0600 Subject: [PATCH 0953/7721] drm/panel-elida-kd35t133: drop drm_connector_set_orientation_from_panel Stop calling drm_connector_set_orientation_from_panel() as its now called by the panel bridge directly when it is initialized. Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231117194405.1386265-4-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117194405.1386265-4-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-elida-kd35t133.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index f1fc4a26f447..29b4ee63d83b 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -211,11 +211,6 @@ static int kd35t133_get_modes(struct drm_panel *panel, connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; drm_mode_probed_add(connector, mode); - /* - * TODO: Remove once all drm drivers call - * drm_connector_set_orientation_from_panel() - */ - drm_connector_set_panel_orientation(connector, ctx->orientation); return 1; } From 5dea0c3fedee65413271a5700e653eff633e9a7f Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 13:44:04 -0600 Subject: [PATCH 0954/7721] drm/panel-elida-kd35t133: Drop shutdown logic The driver shutdown is duplicate as it calls drm_unprepare and drm_disable which are called anyway when associated drivers are shutdown/removed. Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231117194405.1386265-5-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117194405.1386265-5-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-elida-kd35t133.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index 29b4ee63d83b..fea3d9e84905 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -296,27 +296,11 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) return 0; } -static void kd35t133_shutdown(struct mipi_dsi_device *dsi) -{ - struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); - - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); -} - static void kd35t133_remove(struct mipi_dsi_device *dsi) { struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi); int ret; - kd35t133_shutdown(dsi); - ret = mipi_dsi_detach(dsi); if (ret < 0) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); @@ -337,7 +321,6 @@ static struct mipi_dsi_driver kd35t133_driver = { }, .probe = kd35t133_probe, .remove = kd35t133_remove, - .shutdown = kd35t133_shutdown, }; module_mipi_dsi_driver(kd35t133_driver); From 9f5ac1969df6dc0c2282454b147138c32d065b41 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 13:44:05 -0600 Subject: [PATCH 0955/7721] drm/panel-elida-kd35t133: Drop prepare/unprepare logic Drop the prepare/unprepare logic, as this is now tracked elsewhere since this commit [1]. [1] commit d2aacaf07395 ("drm/panel: Check for already prepared/enabled in drm_panel") Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231117194405.1386265-6-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231117194405.1386265-6-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-elida-kd35t133.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index fea3d9e84905..00791ea81e90 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -43,7 +43,6 @@ struct kd35t133 { struct regulator *vdd; struct regulator *iovcc; enum drm_panel_orientation orientation; - bool prepared; }; static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel) @@ -91,9 +90,6 @@ static int kd35t133_unprepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (!ctx->prepared) - return 0; - ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) dev_err(ctx->dev, "failed to set display off: %d\n", ret); @@ -109,8 +105,6 @@ static int kd35t133_unprepare(struct drm_panel *panel) regulator_disable(ctx->iovcc); regulator_disable(ctx->vdd); - ctx->prepared = false; - return 0; } @@ -120,9 +114,6 @@ static int kd35t133_prepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (ctx->prepared) - return 0; - dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vdd); if (ret < 0) { @@ -166,8 +157,6 @@ static int kd35t133_prepare(struct drm_panel *panel) msleep(50); - ctx->prepared = true; - return 0; disable_iovcc: From 99d8a4a283c92bc9976674adce456dab1715c48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:59:32 +0100 Subject: [PATCH 0956/7721] ieee802154: fakelb: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Stefan Schmidt Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-wpan/20231117095922.876489-10-u.kleine-koenig@pengutronix.de --- drivers/net/ieee802154/fakelb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 523d13ee02bf..35e55f198e05 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -221,7 +221,7 @@ static int fakelb_probe(struct platform_device *pdev) return err; } -static int fakelb_remove(struct platform_device *pdev) +static void fakelb_remove(struct platform_device *pdev) { struct fakelb_phy *phy, *tmp; @@ -229,14 +229,13 @@ static int fakelb_remove(struct platform_device *pdev) list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); mutex_unlock(&fakelb_phys_lock); - return 0; } static struct platform_device *ieee802154fake_dev; static struct platform_driver ieee802154fake_driver = { .probe = fakelb_probe, - .remove = fakelb_remove, + .remove_new = fakelb_remove, .driver = { .name = "ieee802154fakelb", }, From 9d4ccdefcb3e0dfbe3af029015cccb437785070f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:59:33 +0100 Subject: [PATCH 0957/7721] ieee802154: hwsim: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Stefan Schmidt Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-wpan/20231117095922.876489-11-u.kleine-koenig@pengutronix.de --- drivers/net/ieee802154/mac802154_hwsim.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c index 31cba9aa7636..2c2483bbe780 100644 --- a/drivers/net/ieee802154/mac802154_hwsim.c +++ b/drivers/net/ieee802154/mac802154_hwsim.c @@ -1035,7 +1035,7 @@ static int hwsim_probe(struct platform_device *pdev) return err; } -static int hwsim_remove(struct platform_device *pdev) +static void hwsim_remove(struct platform_device *pdev) { struct hwsim_phy *phy, *tmp; @@ -1043,13 +1043,11 @@ static int hwsim_remove(struct platform_device *pdev) list_for_each_entry_safe(phy, tmp, &hwsim_phys, list) hwsim_del(phy); mutex_unlock(&hwsim_phys_lock); - - return 0; } static struct platform_driver mac802154hwsim_driver = { .probe = hwsim_probe, - .remove = hwsim_remove, + .remove_new = hwsim_remove, .driver = { .name = "mac802154_hwsim", }, From 5260adf86b6732c75136fc1b159bb370062ddfa8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:04 +0200 Subject: [PATCH 0958/7721] ieee802154: Let PAN IDs be reset Soon association and disassociation will be implemented, which will require to be able to either change the PAN ID from 0xFFFF to a real value when association succeeded, or to reset the PAN ID to 0xFFFF upon disassociation. Let's allow to do that manually for now. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-2-miquel.raynal@bootlin.com --- net/ieee802154/nl802154.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 1a265a421308..1b6a9f27a6e4 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1087,16 +1087,6 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); - /* TODO - * I am not sure about to check here on broadcast pan_id. - * Broadcast is a valid setting, comment from 802.15.4: - * If this value is 0xffff, the device is not associated. - * - * This could useful to simple deassociate an device. - */ - if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)) - return -EINVAL; - return rdev_set_pan_id(rdev, wpan_dev, pan_id); } From 2e7ed75e92fc493ff5484f61aed6489262c78f3e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:05 +0200 Subject: [PATCH 0959/7721] ieee802154: Internal PAN management Introduce structures to describe peer devices in a PAN as well as a few related helpers. We basically care about: - Our unique parent after associating with a coordinator. - Peer devices, children, which successfully associated with us. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-3-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 47 ++++++++++++++++++++++++++++++ net/ieee802154/Makefile | 2 +- net/ieee802154/core.c | 2 ++ net/ieee802154/pan.c | 63 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 net/ieee802154/pan.c diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index f79ce133e51a..a89f1c9cea3f 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -303,6 +303,22 @@ struct ieee802154_coord_desc { bool gts_permit; }; +/** + * struct ieee802154_pan_device - PAN device information + * @pan_id: the PAN ID of this device + * @mode: the preferred mode to reach the device + * @short_addr: the short address of this device + * @extended_addr: the extended address of this device + * @node: the list node + */ +struct ieee802154_pan_device { + __le16 pan_id; + u8 mode; + __le16 short_addr; + __le64 extended_addr; + struct list_head node; +}; + /** * struct cfg802154_scan_request - Scan request * @@ -478,6 +494,11 @@ struct wpan_dev { /* fallback for acknowledgment bit setting */ bool ackreq; + + /* Associations */ + struct mutex association_lock; + struct ieee802154_pan_device *parent; + struct list_head children; }; #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) @@ -529,4 +550,30 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy) void ieee802154_configure_durations(struct wpan_phy *phy, unsigned int page, unsigned int channel); +/** + * cfg802154_device_is_associated - Checks whether we are associated to any device + * @wpan_dev: the wpan device + * @return: true if we are associated + */ +bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev); + +/** + * cfg802154_device_is_parent - Checks if a device is our coordinator + * @wpan_dev: the wpan device + * @target: the expected parent + * @return: true if @target is our coordinator + */ +bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev, + struct ieee802154_addr *target); + +/** + * cfg802154_device_is_child - Checks whether a device is associated to us + * @wpan_dev: the wpan device + * @target: the expected child + * @return: the PAN device + */ +struct ieee802154_pan_device * +cfg802154_device_is_child(struct wpan_dev *wpan_dev, + struct ieee802154_addr *target); + #endif /* __NET_CFG802154_H */ diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index f05b7bdae2aa..7bce67673e83 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o obj-y += 6lowpan/ ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ - header_ops.o sysfs.o nl802154.o trace.o + header_ops.o sysfs.o nl802154.o trace.o pan.o ieee802154_socket-y := socket.o CFLAGS_trace.o := -I$(src) diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 57546e07e06a..cd69bdbfd59f 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -276,6 +276,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb, wpan_dev->identifier = ++rdev->wpan_dev_id; list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list); rdev->devlist_generation++; + mutex_init(&wpan_dev->association_lock); + INIT_LIST_HEAD(&wpan_dev->children); wpan_dev->netdev = dev; break; diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c new file mode 100644 index 000000000000..2b30e7b19ac3 --- /dev/null +++ b/net/ieee802154/pan.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IEEE 802.15.4 PAN management + * + * Copyright (C) 2023 Qorvo US, Inc + * Authors: + * - David Girault + * - Miquel Raynal + */ + +#include +#include +#include + +/* Checks whether a device address matches one from the PAN list. + * This helper is meant to be used only during PAN management, when we expect + * extended addresses to be used. + */ +static bool cfg802154_pan_device_is_matching(struct ieee802154_pan_device *pan_dev, + struct ieee802154_addr *ext_dev) +{ + if (!pan_dev || !ext_dev) + return false; + + if (ext_dev->mode == IEEE802154_ADDR_SHORT) + return false; + + return pan_dev->extended_addr == ext_dev->extended_addr; +} + +bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev) +{ + bool is_assoc; + + mutex_lock(&wpan_dev->association_lock); + is_assoc = !list_empty(&wpan_dev->children) || wpan_dev->parent; + mutex_unlock(&wpan_dev->association_lock); + + return is_assoc; +} + +bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev, + struct ieee802154_addr *target) +{ + lockdep_assert_held(&wpan_dev->association_lock); + + return cfg802154_pan_device_is_matching(wpan_dev->parent, target); +} + +struct ieee802154_pan_device * +cfg802154_device_is_child(struct wpan_dev *wpan_dev, + struct ieee802154_addr *target) +{ + struct ieee802154_pan_device *child; + + lockdep_assert_held(&wpan_dev->association_lock); + + list_for_each_entry(child, &wpan_dev->children, node) + if (cfg802154_pan_device_is_matching(child, target)) + return child; + + return NULL; +} From 05db59a0619969a47ab87050985344177c662cab Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:06 +0200 Subject: [PATCH 0960/7721] ieee802154: Add support for user association requests Users may decide to associate with a peer, which becomes our parent coordinator. Let's add the necessary netlink support for this. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-4-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 4 +++ include/net/ieee802154_netdev.h | 38 +++++++++++++++++++++++++++++ include/net/nl802154.h | 1 + net/ieee802154/nl802154.c | 43 +++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 15 ++++++++++++ net/ieee802154/trace.h | 19 +++++++++++++++ 6 files changed, 120 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index a89f1c9cea3f..d0c033176220 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -20,6 +20,7 @@ struct wpan_phy; struct wpan_phy_cca; struct cfg802154_scan_request; struct cfg802154_beacon_request; +struct ieee802154_addr; #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL struct ieee802154_llsec_device_key; @@ -77,6 +78,9 @@ struct cfg802154_ops { struct cfg802154_beacon_request *request); int (*stop_beacons)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev); + int (*associate)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *coord); #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL void (*get_llsec_table)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 063313df447d..ca8c827d0d7f 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -125,6 +125,30 @@ struct ieee802154_hdr_fc { #endif }; +struct ieee802154_assoc_req_pl { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 reserved1:1, + device_type:1, + power_source:1, + rx_on_when_idle:1, + assoc_type:1, + reserved2:1, + security_cap:1, + alloc_addr:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 alloc_addr:1, + security_cap:1, + reserved2:1, + assoc_type:1, + rx_on_when_idle:1, + power_source:1, + device_type:1, + reserved1:1; +#else +#error "Please fix " +#endif +} __packed; + enum ieee802154_frame_version { IEEE802154_2003_STD, IEEE802154_2006_STD, @@ -140,6 +164,14 @@ enum ieee802154_addressing_mode { IEEE802154_EXTENDED_ADDRESSING, }; +enum ieee802154_association_status { + IEEE802154_ASSOCIATION_SUCCESSFUL = 0x00, + IEEE802154_PAN_AT_CAPACITY = 0x01, + IEEE802154_PAN_ACCESS_DENIED = 0x02, + IEEE802154_HOPPING_SEQUENCE_OFFSET_DUP = 0x03, + IEEE802154_FAST_ASSOCIATION_SUCCESSFUL = 0x80, +}; + struct ieee802154_hdr { struct ieee802154_hdr_fc fc; u8 seq; @@ -163,6 +195,12 @@ struct ieee802154_beacon_req_frame { struct ieee802154_mac_cmd_pl mac_pl; }; +struct ieee802154_association_req_frame { + struct ieee802154_hdr mhr; + struct ieee802154_mac_cmd_pl mac_pl; + struct ieee802154_assoc_req_pl assoc_req_pl; +}; + /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from * the contents of hdr will be, and the actual value of those bits in * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 8cd9d141f5af..830e1c51d3df 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -78,6 +78,7 @@ enum nl802154_commands { NL802154_CMD_SCAN_DONE, NL802154_CMD_SEND_BEACONS, NL802154_CMD_STOP_BEACONS, + NL802154_CMD_ASSOCIATE, /* add new commands above here */ diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 1b6a9f27a6e4..e430dbf66d00 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1628,6 +1628,41 @@ nl802154_stop_beacons(struct sk_buff *skb, struct genl_info *info) return rdev_stop_beacons(rdev, wpan_dev); } +static int nl802154_associate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev; + struct wpan_phy *wpan_phy; + struct ieee802154_addr coord; + int err; + + wpan_dev = dev->ieee802154_ptr; + wpan_phy = &rdev->wpan_phy; + + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); + return -EOPNOTSUPP; + } + + if (!info->attrs[NL802154_ATTR_PAN_ID] || + !info->attrs[NL802154_ATTR_EXTENDED_ADDR]) + return -EINVAL; + + coord.pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); + coord.mode = IEEE802154_ADDR_LONG; + coord.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]); + + mutex_lock(&wpan_dev->association_lock); + err = rdev_associate(rdev, wpan_dev, &coord); + mutex_unlock(&wpan_dev->association_lock); + if (err) + pr_err("Association with PAN ID 0x%x failed (%d)\n", + le16_to_cpu(coord.pan_id), err); + + return err; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2749,6 +2784,14 @@ static const struct genl_ops nl802154_ops[] = { NL802154_FLAG_CHECK_NETDEV_UP | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_ASSOCIATE, + .doit = nl802154_associate, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_CHECK_NETDEV_UP | + NL802154_FLAG_NEED_RTNL, + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 5eaae15c610e..4843d52f1ee0 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -265,6 +265,21 @@ static inline int rdev_stop_beacons(struct cfg802154_registered_device *rdev, return ret; } +static inline int rdev_associate(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *coord) +{ + int ret; + + if (!rdev->ops->associate) + return -EOPNOTSUPP; + + trace_802154_rdev_associate(&rdev->wpan_phy, wpan_dev, coord); + ret = rdev->ops->associate(&rdev->wpan_phy, wpan_dev, coord); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL /* TODO this is already a nl802154, so move into ieee802154 */ static inline void diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index c16db0b326fa..2e1d4f456316 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -356,6 +356,25 @@ DEFINE_EVENT(802154_wdev_template, 802154_rdev_stop_beacons, TP_ARGS(wpan_phy, wpan_dev) ); +TRACE_EVENT(802154_rdev_associate, + TP_PROTO(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *coord), + TP_ARGS(wpan_phy, wpan_dev, coord), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(__le64, addr) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->addr = coord->extended_addr; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", associating with: 0x%llx", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr) +); + TRACE_EVENT(802154_rdev_return_int, TP_PROTO(struct wpan_phy *wpan_phy, int ret), TP_ARGS(wpan_phy, ret), From fefd19807fe9c65002366c749e809996a1ca4e68 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:07 +0200 Subject: [PATCH 0961/7721] mac802154: Handle associating Joining a PAN officially goes by associating with a coordinator. This coordinator may have been discovered thanks to the beacons it sent in the past. Add support to the MAC layer for these associations, which require: - Sending an association request - Receiving an association response The association response contains the association status, eventually a reason if the association was unsuccessful, and finally a short address that we should use for intra-PAN communication from now on, if we required one (which is the default, and not yet configurable). Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-5-miquel.raynal@bootlin.com --- include/net/ieee802154_netdev.h | 5 ++ net/ieee802154/core.c | 12 +++ net/mac802154/cfg.c | 69 +++++++++++++++++ net/mac802154/ieee802154_i.h | 19 +++++ net/mac802154/main.c | 2 + net/mac802154/rx.c | 9 +++ net/mac802154/scan.c | 127 ++++++++++++++++++++++++++++++++ 7 files changed, 243 insertions(+) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index ca8c827d0d7f..e26ffd079556 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -149,6 +149,11 @@ struct ieee802154_assoc_req_pl { #endif } __packed; +struct ieee802154_assoc_resp_pl { + __le16 short_addr; + u8 status; +} __packed; + enum ieee802154_frame_version { IEEE802154_2003_STD, IEEE802154_2006_STD, diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index cd69bdbfd59f..a08d75dd56ad 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -198,6 +198,16 @@ void wpan_phy_free(struct wpan_phy *phy) } EXPORT_SYMBOL(wpan_phy_free); +static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev) +{ + mutex_lock(&wpan_dev->association_lock); + + kfree(wpan_dev->parent); + wpan_dev->parent = NULL; + + mutex_unlock(&wpan_dev->association_lock); +} + int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, struct net *net) { @@ -293,6 +303,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb, rdev->opencount++; break; case NETDEV_UNREGISTER: + cfg802154_free_peer_structures(wpan_dev); + /* It is possible to get NETDEV_UNREGISTER * multiple times. To detect that, check * that the interface is still on the list diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 5c3cb019f751..0e8bb1486430 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -315,6 +315,74 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy, return mac802154_stop_beacons_locked(local, sdata); } +static int mac802154_associate(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *coord) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + u64 ceaddr = swab64((__force u64)coord->extended_addr); + struct ieee802154_sub_if_data *sdata; + struct ieee802154_pan_device *parent; + __le16 short_addr; + int ret; + + ASSERT_RTNL(); + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); + + if (wpan_dev->parent) { + dev_err(&sdata->dev->dev, + "Device %8phC is already associated\n", &ceaddr); + return -EPERM; + } + + if (coord->mode == IEEE802154_SHORT_ADDRESSING) + return -EINVAL; + + parent = kzalloc(sizeof(*parent), GFP_KERNEL); + if (!parent) + return -ENOMEM; + + parent->pan_id = coord->pan_id; + parent->mode = coord->mode; + parent->extended_addr = coord->extended_addr; + parent->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); + + /* Set the PAN ID hardware address filter beforehand to avoid dropping + * the association response with a destination PAN ID field set to the + * "new" PAN ID. + */ + if (local->hw.flags & IEEE802154_HW_AFILT) { + ret = drv_set_pan_id(local, coord->pan_id); + if (ret < 0) + goto free_parent; + } + + ret = mac802154_perform_association(sdata, parent, &short_addr); + if (ret) + goto reset_panid; + + if (local->hw.flags & IEEE802154_HW_AFILT) { + ret = drv_set_short_addr(local, short_addr); + if (ret < 0) + goto reset_panid; + } + + wpan_dev->pan_id = coord->pan_id; + wpan_dev->short_addr = short_addr; + wpan_dev->parent = parent; + + return 0; + +reset_panid: + if (local->hw.flags & IEEE802154_HW_AFILT) + drv_set_pan_id(local, cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)); + +free_parent: + kfree(parent); + return ret; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static void ieee802154_get_llsec_table(struct wpan_phy *wpan_phy, @@ -526,6 +594,7 @@ const struct cfg802154_ops mac802154_config_ops = { .abort_scan = mac802154_abort_scan, .send_beacons = mac802154_send_beacons, .stop_beacons = mac802154_stop_beacons, + .associate = mac802154_associate, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL .get_llsec_table = ieee802154_get_llsec_table, .lock_llsec_table = ieee802154_lock_llsec_table, diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index c347ec9ff8c9..fff67676b400 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -24,6 +24,7 @@ enum ieee802154_ongoing { IEEE802154_IS_SCANNING = BIT(0), IEEE802154_IS_BEACONING = BIT(1), + IEEE802154_IS_ASSOCIATING = BIT(2), }; /* mac802154 device private data */ @@ -74,6 +75,13 @@ struct ieee802154_local { struct list_head rx_mac_cmd_list; struct work_struct rx_mac_cmd_work; + /* Association */ + struct ieee802154_pan_device *assoc_dev; + struct completion assoc_done; + __le16 assoc_addr; + u8 assoc_status; + struct work_struct assoc_work; + bool started; bool suspended; unsigned long ongoing; @@ -296,6 +304,17 @@ static inline bool mac802154_is_beaconing(struct ieee802154_local *local) void mac802154_rx_mac_cmd_worker(struct work_struct *work); +int mac802154_perform_association(struct ieee802154_sub_if_data *sdata, + struct ieee802154_pan_device *coord, + __le16 *short_addr); +int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb); + +static inline bool mac802154_is_associating(struct ieee802154_local *local) +{ + return test_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); +} + /* interface handling */ int ieee802154_iface_init(void); void ieee802154_iface_exit(void); diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 357ece67432b..9ab7396668d2 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -103,6 +103,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker); INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker); + init_completion(&local->assoc_done); + /* init supported flags with 802.15.4 default ranges */ phy->supported.max_minbe = 8; phy->supported.min_maxbe = 3; diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index e2434b4fe514..d0e08613a36b 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -93,6 +93,15 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work) queue_delayed_work(local->mac_wq, &local->beacon_work, 0); break; + + case IEEE802154_CMD_ASSOCIATION_RESP: + dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC RESP\n"); + if (!mac802154_is_associating(local)) + break; + + mac802154_process_association_resp(mac_pkt->sdata, mac_pkt->skb); + break; + default: break; } diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index d9658f2c4ae6..5dd50e1ce329 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -510,3 +510,130 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata, return 0; } + +int mac802154_perform_association(struct ieee802154_sub_if_data *sdata, + struct ieee802154_pan_device *coord, + __le16 *short_addr) +{ + u64 ceaddr = swab64((__force u64)coord->extended_addr); + struct ieee802154_association_req_frame frame = {}; + struct ieee802154_local *local = sdata->local; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct sk_buff *skb; + int ret; + + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; + frame.mhr.fc.security_enabled = 0; + frame.mhr.fc.frame_pending = 0; + frame.mhr.fc.ack_request = 1; /* We always expect an ack here */ + frame.mhr.fc.intra_pan = 0; + frame.mhr.fc.dest_addr_mode = (coord->mode == IEEE802154_ADDR_LONG) ? + IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING; + frame.mhr.fc.version = IEEE802154_2003_STD; + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; + frame.mhr.source.mode = IEEE802154_ADDR_LONG; + frame.mhr.source.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); + frame.mhr.source.extended_addr = wpan_dev->extended_addr; + frame.mhr.dest.mode = coord->mode; + frame.mhr.dest.pan_id = coord->pan_id; + if (coord->mode == IEEE802154_ADDR_LONG) + frame.mhr.dest.extended_addr = coord->extended_addr; + else + frame.mhr.dest.short_addr = coord->short_addr; + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; + frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_REQ; + frame.assoc_req_pl.device_type = 1; + frame.assoc_req_pl.power_source = 1; + frame.assoc_req_pl.rx_on_when_idle = 1; + frame.assoc_req_pl.alloc_addr = 1; + + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.assoc_req_pl), + GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + skb->dev = sdata->dev; + + ret = ieee802154_mac_cmd_push(skb, &frame, &frame.assoc_req_pl, + sizeof(frame.assoc_req_pl)); + if (ret) { + kfree_skb(skb); + return ret; + } + + local->assoc_dev = coord; + reinit_completion(&local->assoc_done); + set_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); + + ret = ieee802154_mlme_tx_one_locked(local, sdata, skb); + if (ret) { + if (ret > 0) + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; + dev_warn(&sdata->dev->dev, + "No ASSOC REQ ACK received from %8phC\n", &ceaddr); + goto clear_assoc; + } + + ret = wait_for_completion_killable_timeout(&local->assoc_done, 10 * HZ); + if (ret <= 0) { + dev_warn(&sdata->dev->dev, + "No ASSOC RESP received from %8phC\n", &ceaddr); + ret = -ETIMEDOUT; + goto clear_assoc; + } + + if (local->assoc_status != IEEE802154_ASSOCIATION_SUCCESSFUL) { + if (local->assoc_status == IEEE802154_PAN_AT_CAPACITY) + ret = -ERANGE; + else + ret = -EPERM; + + dev_warn(&sdata->dev->dev, + "Negative ASSOC RESP received from %8phC: %s\n", &ceaddr, + local->assoc_status == IEEE802154_PAN_AT_CAPACITY ? + "PAN at capacity" : "access denied"); + } + + ret = 0; + *short_addr = local->assoc_addr; + +clear_assoc: + clear_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); + local->assoc_dev = NULL; + + return ret; +} + +int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee802154_addr *src = &mac_cb(skb)->source; + struct ieee802154_addr *dest = &mac_cb(skb)->dest; + u64 deaddr = swab64((__force u64)dest->extended_addr); + struct ieee802154_local *local = sdata->local; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct ieee802154_assoc_resp_pl resp_pl = {}; + + if (skb->len != sizeof(resp_pl)) + return -EINVAL; + + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING || + dest->mode != IEEE802154_EXTENDED_ADDRESSING)) + return -EINVAL; + + if (unlikely(dest->extended_addr != wpan_dev->extended_addr || + src->extended_addr != local->assoc_dev->extended_addr)) + return -ENODEV; + + memcpy(&resp_pl, skb->data, sizeof(resp_pl)); + local->assoc_addr = resp_pl.short_addr; + local->assoc_status = resp_pl.status; + + dev_dbg(&skb->dev->dev, + "ASSOC RESP 0x%x received from %8phC, getting short address %04x\n", + local->assoc_status, &deaddr, local->assoc_addr); + + complete(&local->assoc_done); + + return 0; +} From 7b18313e84eb62c3e4071f9679480159d8da5107 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:08 +0200 Subject: [PATCH 0962/7721] ieee802154: Add support for user disassociation requests A device may decide at some point to disassociate from a PAN, let's introduce a netlink command for this purpose. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-6-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 3 +++ include/net/ieee802154_netdev.h | 11 +++++++++ include/net/nl802154.h | 1 + net/ieee802154/nl802154.c | 41 +++++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 15 ++++++++++++ net/ieee802154/trace.h | 19 +++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index d0c033176220..9b036ab20079 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -81,6 +81,9 @@ struct cfg802154_ops { int (*associate)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, struct ieee802154_addr *coord); + int (*disassociate)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *target); #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL void (*get_llsec_table)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index e26ffd079556..16194356cfe7 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -177,6 +177,11 @@ enum ieee802154_association_status { IEEE802154_FAST_ASSOCIATION_SUCCESSFUL = 0x80, }; +enum ieee802154_disassociation_reason { + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE = 0x1, + IEEE802154_DEVICE_WISHES_TO_LEAVE = 0x2, +}; + struct ieee802154_hdr { struct ieee802154_hdr_fc fc; u8 seq; @@ -206,6 +211,12 @@ struct ieee802154_association_req_frame { struct ieee802154_assoc_req_pl assoc_req_pl; }; +struct ieee802154_disassociation_notif_frame { + struct ieee802154_hdr mhr; + struct ieee802154_mac_cmd_pl mac_pl; + u8 disassoc_pl; +}; + /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from * the contents of hdr will be, and the actual value of those bits in * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 830e1c51d3df..8a47c14c72f0 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -79,6 +79,7 @@ enum nl802154_commands { NL802154_CMD_SEND_BEACONS, NL802154_CMD_STOP_BEACONS, NL802154_CMD_ASSOCIATE, + NL802154_CMD_DISASSOCIATE, /* add new commands above here */ diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index e430dbf66d00..dd86ecd7b193 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1663,6 +1663,39 @@ static int nl802154_associate(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + struct wpan_phy *wpan_phy = &rdev->wpan_phy; + struct ieee802154_addr target; + + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); + return -EOPNOTSUPP; + } + + target.pan_id = wpan_dev->pan_id; + + if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) { + target.mode = IEEE802154_ADDR_LONG; + target.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]); + } else if (info->attrs[NL802154_ATTR_SHORT_ADDR]) { + target.mode = IEEE802154_ADDR_SHORT; + target.short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); + } else { + NL_SET_ERR_MSG(info->extack, "Device address is missing"); + return -EINVAL; + } + + mutex_lock(&wpan_dev->association_lock); + rdev_disassociate(rdev, wpan_dev, &target); + mutex_unlock(&wpan_dev->association_lock); + + return 0; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2792,6 +2825,14 @@ static const struct genl_ops nl802154_ops[] = { NL802154_FLAG_CHECK_NETDEV_UP | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_DISASSOCIATE, + .doit = nl802154_disassociate, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_CHECK_NETDEV_UP | + NL802154_FLAG_NEED_RTNL, + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 4843d52f1ee0..64071ef6f57b 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -280,6 +280,21 @@ static inline int rdev_associate(struct cfg802154_registered_device *rdev, return ret; } +static inline int rdev_disassociate(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *target) +{ + int ret; + + if (!rdev->ops->disassociate) + return -EOPNOTSUPP; + + trace_802154_rdev_disassociate(&rdev->wpan_phy, wpan_dev, target); + ret = rdev->ops->disassociate(&rdev->wpan_phy, wpan_dev, target); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL /* TODO this is already a nl802154, so move into ieee802154 */ static inline void diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index 2e1d4f456316..62aa6465253a 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -375,6 +375,25 @@ TRACE_EVENT(802154_rdev_associate, WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr) ); +TRACE_EVENT(802154_rdev_disassociate, + TP_PROTO(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *target), + TP_ARGS(wpan_phy, wpan_dev, target), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(__le64, addr) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->addr = target->extended_addr; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", disassociating with: 0x%llx", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr) +); + TRACE_EVENT(802154_rdev_return_int, TP_PROTO(struct wpan_phy *wpan_phy, int ret), TP_ARGS(wpan_phy, ret), From 9860d9be89f420f3793fb798faadea11c723e08a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:09 +0200 Subject: [PATCH 0963/7721] mac802154: Handle disassociations Devices may decide to disassociate from their coordinator for different reasons (device turning off, coordinator signal strength too low, etc), the MAC layer just has to send a disassociation notification. If the ack of the disassociation notification is not received, the device may consider itself disassociated anyway. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-7-miquel.raynal@bootlin.com --- net/ieee802154/pan.c | 2 + net/mac802154/cfg.c | 100 +++++++++++++++++++++++++++++++++++ net/mac802154/ieee802154_i.h | 4 ++ net/mac802154/scan.c | 60 +++++++++++++++++++++ 4 files changed, 166 insertions(+) diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c index 2b30e7b19ac3..43b8d2df2186 100644 --- a/net/ieee802154/pan.c +++ b/net/ieee802154/pan.c @@ -46,6 +46,7 @@ bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev, return cfg802154_pan_device_is_matching(wpan_dev->parent, target); } +EXPORT_SYMBOL_GPL(cfg802154_device_is_parent); struct ieee802154_pan_device * cfg802154_device_is_child(struct wpan_dev *wpan_dev, @@ -61,3 +62,4 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev, return NULL; } +EXPORT_SYMBOL_GPL(cfg802154_device_is_child); diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 0e8bb1486430..083de2d3fe37 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -383,6 +383,105 @@ static int mac802154_associate(struct wpan_phy *wpan_phy, return ret; } +static int mac802154_disassociate_from_parent(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + struct ieee802154_pan_device *child, *tmp; + struct ieee802154_sub_if_data *sdata; + u64 eaddr; + int ret; + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); + + /* Start by disassociating all the children and preventing new ones to + * attempt associations. + */ + list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) { + ret = mac802154_send_disassociation_notif(sdata, child, + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE); + if (ret) { + eaddr = swab64((__force u64)child->extended_addr); + dev_err(&sdata->dev->dev, + "Disassociation with %8phC may have failed (%d)\n", + &eaddr, ret); + } + + list_del(&child->node); + } + + ret = mac802154_send_disassociation_notif(sdata, wpan_dev->parent, + IEEE802154_DEVICE_WISHES_TO_LEAVE); + if (ret) { + eaddr = swab64((__force u64)wpan_dev->parent->extended_addr); + dev_err(&sdata->dev->dev, + "Disassociation from %8phC may have failed (%d)\n", + &eaddr, ret); + } + + ret = 0; + + kfree(wpan_dev->parent); + wpan_dev->parent = NULL; + wpan_dev->pan_id = cpu_to_le16(IEEE802154_PAN_ID_BROADCAST); + wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); + + if (local->hw.flags & IEEE802154_HW_AFILT) { + ret = drv_set_pan_id(local, wpan_dev->pan_id); + if (ret < 0) + return ret; + + ret = drv_set_short_addr(local, wpan_dev->short_addr); + if (ret < 0) + return ret; + } + + return 0; +} + +static int mac802154_disassociate_child(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_pan_device *child) +{ + struct ieee802154_sub_if_data *sdata; + int ret; + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); + + ret = mac802154_send_disassociation_notif(sdata, child, + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE); + if (ret) + return ret; + + list_del(&child->node); + kfree(child); + + return 0; +} + +static int mac802154_disassociate(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, + struct ieee802154_addr *target) +{ + u64 teaddr = swab64((__force u64)target->extended_addr); + struct ieee802154_pan_device *pan_device; + + ASSERT_RTNL(); + + if (cfg802154_device_is_parent(wpan_dev, target)) + return mac802154_disassociate_from_parent(wpan_phy, wpan_dev); + + pan_device = cfg802154_device_is_child(wpan_dev, target); + if (pan_device) + return mac802154_disassociate_child(wpan_phy, wpan_dev, + pan_device); + + dev_err(&wpan_dev->netdev->dev, + "Device %8phC is not associated with us\n", &teaddr); + + return -EINVAL; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static void ieee802154_get_llsec_table(struct wpan_phy *wpan_phy, @@ -595,6 +694,7 @@ const struct cfg802154_ops mac802154_config_ops = { .send_beacons = mac802154_send_beacons, .stop_beacons = mac802154_stop_beacons, .associate = mac802154_associate, + .disassociate = mac802154_disassociate, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL .get_llsec_table = ieee802154_get_llsec_table, .lock_llsec_table = ieee802154_lock_llsec_table, diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index fff67676b400..92252f86c69c 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -315,6 +315,10 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local) return test_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); } +int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, + struct ieee802154_pan_device *target, + u8 reason); + /* interface handling */ int ieee802154_iface_init(void); void ieee802154_iface_exit(void); diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index 5dd50e1ce329..e2f2e1235ec6 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -637,3 +637,63 @@ int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata, return 0; } + +int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, + struct ieee802154_pan_device *target, + u8 reason) +{ + struct ieee802154_disassociation_notif_frame frame = {}; + u64 teaddr = swab64((__force u64)target->extended_addr); + struct ieee802154_local *local = sdata->local; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct sk_buff *skb; + int ret; + + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; + frame.mhr.fc.security_enabled = 0; + frame.mhr.fc.frame_pending = 0; + frame.mhr.fc.ack_request = 1; + frame.mhr.fc.intra_pan = 1; + frame.mhr.fc.dest_addr_mode = (target->mode == IEEE802154_ADDR_LONG) ? + IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING; + frame.mhr.fc.version = IEEE802154_2003_STD; + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; + frame.mhr.source.mode = IEEE802154_ADDR_LONG; + frame.mhr.source.pan_id = wpan_dev->pan_id; + frame.mhr.source.extended_addr = wpan_dev->extended_addr; + frame.mhr.dest.mode = target->mode; + frame.mhr.dest.pan_id = wpan_dev->pan_id; + if (target->mode == IEEE802154_ADDR_LONG) + frame.mhr.dest.extended_addr = target->extended_addr; + else + frame.mhr.dest.short_addr = target->short_addr; + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; + frame.mac_pl.cmd_id = IEEE802154_CMD_DISASSOCIATION_NOTIFY; + frame.disassoc_pl = reason; + + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.disassoc_pl), + GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + skb->dev = sdata->dev; + + ret = ieee802154_mac_cmd_push(skb, &frame, &frame.disassoc_pl, + sizeof(frame.disassoc_pl)); + if (ret) { + kfree_skb(skb); + return ret; + } + + ret = ieee802154_mlme_tx_one_locked(local, sdata, skb); + if (ret) { + dev_warn(&sdata->dev->dev, + "No DISASSOC ACK received from %8phC\n", &teaddr); + if (ret > 0) + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; + return ret; + } + + dev_dbg(&sdata->dev->dev, "DISASSOC ACK received from %8phC\n", &teaddr); + return 0; +} From 601f160b61b2152ef84a663f856350d5dd9e752a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:10 +0200 Subject: [PATCH 0964/7721] mac802154: Handle association requests from peers Coordinators may have to handle association requests from peers which want to join the PAN. The logic involves: - Acknowledging the request (done by hardware) - If requested, a random short address that is free on this PAN should be chosen for the device. - Sending an association response with the short address allocated for the peer and expecting it to be ack'ed. If anything fails during this procedure, the peer is considered not associated. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-8-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 7 ++ include/net/ieee802154_netdev.h | 6 ++ net/ieee802154/core.c | 7 ++ net/ieee802154/pan.c | 30 +++++++ net/mac802154/ieee802154_i.h | 2 + net/mac802154/rx.c | 8 ++ net/mac802154/scan.c | 142 ++++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 9b036ab20079..c844ae63bc04 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -583,4 +583,11 @@ struct ieee802154_pan_device * cfg802154_device_is_child(struct wpan_dev *wpan_dev, struct ieee802154_addr *target); +/** + * cfg802154_get_free_short_addr - Get a free address among the known devices + * @wpan_dev: the wpan device + * @return: a random short address expectedly unused on our PAN + */ +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev); + #endif /* __NET_CFG802154_H */ diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 16194356cfe7..4de858f9929e 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -211,6 +211,12 @@ struct ieee802154_association_req_frame { struct ieee802154_assoc_req_pl assoc_req_pl; }; +struct ieee802154_association_resp_frame { + struct ieee802154_hdr mhr; + struct ieee802154_mac_cmd_pl mac_pl; + struct ieee802154_assoc_resp_pl assoc_resp_pl; +}; + struct ieee802154_disassociation_notif_frame { struct ieee802154_hdr mhr; struct ieee802154_mac_cmd_pl mac_pl; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index a08d75dd56ad..1670a71327a7 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -200,11 +200,18 @@ EXPORT_SYMBOL(wpan_phy_free); static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev) { + struct ieee802154_pan_device *child, *tmp; + mutex_lock(&wpan_dev->association_lock); kfree(wpan_dev->parent); wpan_dev->parent = NULL; + list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) { + list_del(&child->node); + kfree(child); + } + mutex_unlock(&wpan_dev->association_lock); } diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c index 43b8d2df2186..545461069197 100644 --- a/net/ieee802154/pan.c +++ b/net/ieee802154/pan.c @@ -63,3 +63,33 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev, return NULL; } EXPORT_SYMBOL_GPL(cfg802154_device_is_child); + +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev) +{ + struct ieee802154_pan_device *child; + __le16 addr; + + lockdep_assert_held(&wpan_dev->association_lock); + + do { + get_random_bytes(&addr, 2); + if (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST) || + addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC)) + continue; + + if (wpan_dev->short_addr == addr) + continue; + + if (wpan_dev->parent && wpan_dev->parent->short_addr == addr) + continue; + + list_for_each_entry(child, &wpan_dev->children, node) + if (child->short_addr == addr) + continue; + + break; + } while (1); + + return addr; +} +EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr); diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 92252f86c69c..432bfa87249e 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -318,6 +318,8 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local) int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, struct ieee802154_pan_device *target, u8 reason); +int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb); /* interface handling */ int ieee802154_iface_init(void); diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index d0e08613a36b..96040b63a4fc 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -102,6 +102,14 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work) mac802154_process_association_resp(mac_pkt->sdata, mac_pkt->skb); break; + case IEEE802154_CMD_ASSOCIATION_REQ: + dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC REQ\n"); + if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD) + break; + + mac802154_process_association_req(mac_pkt->sdata, mac_pkt->skb); + break; + default: break; } diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index e2f2e1235ec6..d5f66c204bc5 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -697,3 +697,145 @@ int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, dev_dbg(&sdata->dev->dev, "DISASSOC ACK received from %8phC\n", &teaddr); return 0; } + +static int +mac802154_send_association_resp_locked(struct ieee802154_sub_if_data *sdata, + struct ieee802154_pan_device *target, + struct ieee802154_assoc_resp_pl *assoc_resp_pl) +{ + u64 teaddr = swab64((__force u64)target->extended_addr); + struct ieee802154_association_resp_frame frame = {}; + struct ieee802154_local *local = sdata->local; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct sk_buff *skb; + int ret; + + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; + frame.mhr.fc.security_enabled = 0; + frame.mhr.fc.frame_pending = 0; + frame.mhr.fc.ack_request = 1; /* We always expect an ack here */ + frame.mhr.fc.intra_pan = 1; + frame.mhr.fc.dest_addr_mode = IEEE802154_EXTENDED_ADDRESSING; + frame.mhr.fc.version = IEEE802154_2003_STD; + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; + frame.mhr.source.mode = IEEE802154_ADDR_LONG; + frame.mhr.source.extended_addr = wpan_dev->extended_addr; + frame.mhr.dest.mode = IEEE802154_ADDR_LONG; + frame.mhr.dest.pan_id = wpan_dev->pan_id; + frame.mhr.dest.extended_addr = target->extended_addr; + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; + frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_RESP; + + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(*assoc_resp_pl), + GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + skb->dev = sdata->dev; + + ret = ieee802154_mac_cmd_push(skb, &frame, assoc_resp_pl, + sizeof(*assoc_resp_pl)); + if (ret) { + kfree_skb(skb); + return ret; + } + + ret = ieee802154_mlme_tx_locked(local, sdata, skb); + if (ret) { + dev_warn(&sdata->dev->dev, + "No ASSOC RESP ACK received from %8phC\n", &teaddr); + if (ret > 0) + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; + return ret; + } + + return 0; +} + +int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct ieee802154_addr *src = &mac_cb(skb)->source; + struct ieee802154_addr *dest = &mac_cb(skb)->dest; + struct ieee802154_assoc_resp_pl assoc_resp_pl = {}; + struct ieee802154_assoc_req_pl assoc_req_pl; + struct ieee802154_pan_device *child, *exchild; + struct ieee802154_addr tmp = {}; + u64 ceaddr; + int ret; + + if (skb->len != sizeof(assoc_req_pl)) + return -EINVAL; + + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING)) + return -EINVAL; + + if (unlikely(dest->pan_id != wpan_dev->pan_id)) + return -ENODEV; + + if (dest->mode == IEEE802154_EXTENDED_ADDRESSING && + unlikely(dest->extended_addr != wpan_dev->extended_addr)) + return -ENODEV; + else if (dest->mode == IEEE802154_SHORT_ADDRESSING && + unlikely(dest->short_addr != wpan_dev->short_addr)) + return -ENODEV; + + mutex_lock(&wpan_dev->association_lock); + + memcpy(&assoc_req_pl, skb->data, sizeof(assoc_req_pl)); + if (assoc_req_pl.assoc_type) { + dev_err(&skb->dev->dev, "Fast associations not supported yet\n"); + ret = -EOPNOTSUPP; + goto unlock; + } + + child = kzalloc(sizeof(*child), GFP_KERNEL); + if (!child) { + ret = -ENOMEM; + goto unlock; + } + + child->extended_addr = src->extended_addr; + child->mode = IEEE802154_EXTENDED_ADDRESSING; + ceaddr = swab64((__force u64)child->extended_addr); + + assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL; + if (assoc_req_pl.alloc_addr) { + assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev); + child->mode = IEEE802154_SHORT_ADDRESSING; + } else { + assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC); + } + child->short_addr = assoc_resp_pl.short_addr; + dev_dbg(&sdata->dev->dev, + "Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n", + &ceaddr, le16_to_cpu(child->short_addr)); + + ret = mac802154_send_association_resp_locked(sdata, child, &assoc_resp_pl); + if (ret) { + kfree(child); + goto unlock; + } + + dev_dbg(&sdata->dev->dev, + "Successful association with new child %8phC\n", &ceaddr); + + /* Ensure this child is not already associated (might happen due to + * retransmissions), in this case drop the ex structure. + */ + tmp.mode = child->mode; + tmp.extended_addr = child->extended_addr; + exchild = cfg802154_device_is_child(wpan_dev, &tmp); + if (exchild) { + dev_dbg(&sdata->dev->dev, + "Child %8phC was already known\n", &ceaddr); + list_del(&exchild->node); + } + + list_add(&child->node, &wpan_dev->children); + +unlock: + mutex_unlock(&wpan_dev->association_lock); + return ret; +} From ce93b9378c306e6bcc4e0bd817acf4195b4a0288 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:11 +0200 Subject: [PATCH 0965/7721] ieee802154: Add support for limiting the number of associated devices Coordinators may refuse associations. We need a user input for that. Let's add a new netlink command which can provide a maximum number of devices we accept to associate with as a first step. Later, we could also forward the request to userspace and check whether the association should be accepted or not. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-9-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 8 ++++++++ include/net/nl802154.h | 2 ++ net/ieee802154/core.c | 1 + net/ieee802154/nl802154.c | 28 ++++++++++++++++++++++++++++ net/ieee802154/pan.c | 8 ++++++++ 5 files changed, 47 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index c844ae63bc04..0d3e9af00198 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -506,6 +506,7 @@ struct wpan_dev { struct mutex association_lock; struct ieee802154_pan_device *parent; struct list_head children; + unsigned int max_associations; }; #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) @@ -583,6 +584,13 @@ struct ieee802154_pan_device * cfg802154_device_is_child(struct wpan_dev *wpan_dev, struct ieee802154_addr *target); +/** + * cfg802154_set_max_associations - Limit the number of future associations + * @wpan_dev: the wpan device + * @max: the maximum number of devices we accept to associate + */ +void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max); + /** * cfg802154_get_free_short_addr - Get a free address among the known devices * @wpan_dev: the wpan device diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 8a47c14c72f0..8b26faae49e8 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -80,6 +80,7 @@ enum nl802154_commands { NL802154_CMD_STOP_BEACONS, NL802154_CMD_ASSOCIATE, NL802154_CMD_DISASSOCIATE, + NL802154_CMD_SET_MAX_ASSOCIATIONS, /* add new commands above here */ @@ -149,6 +150,7 @@ enum nl802154_attrs { NL802154_ATTR_SCAN_DURATION, NL802154_ATTR_SCAN_DONE_REASON, NL802154_ATTR_BEACON_INTERVAL, + NL802154_ATTR_MAX_ASSOCIATIONS, /* add attributes here, update the policy in nl802154.c */ diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 1670a71327a7..2d6fe45efa05 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -295,6 +295,7 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb, rdev->devlist_generation++; mutex_init(&wpan_dev->association_lock); INIT_LIST_HEAD(&wpan_dev->children); + wpan_dev->max_associations = SZ_16K; wpan_dev->netdev = dev; break; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index dd86ecd7b193..06e0bd6ffcca 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -234,6 +234,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { NL802154_SCAN_DONE_REASON_ABORTED), [NL802154_ATTR_BEACON_INTERVAL] = NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION), + [NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, @@ -1696,6 +1697,26 @@ static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info) return 0; } +static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + unsigned int max_assoc; + + if (!info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]) { + NL_SET_ERR_MSG(info->extack, "No maximum number of association given"); + return -EINVAL; + } + + max_assoc = nla_get_u32(info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]); + + mutex_lock(&wpan_dev->association_lock); + cfg802154_set_max_associations(wpan_dev, max_assoc); + mutex_unlock(&wpan_dev->association_lock); + + return 0; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2833,6 +2854,13 @@ static const struct genl_ops nl802154_ops[] = { NL802154_FLAG_CHECK_NETDEV_UP | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_MAX_ASSOCIATIONS, + .doit = nl802154_set_max_associations, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c index 545461069197..fb5b0af2ef68 100644 --- a/net/ieee802154/pan.c +++ b/net/ieee802154/pan.c @@ -93,3 +93,11 @@ __le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev) return addr; } EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr); + +void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max) +{ + lockdep_assert_held(&wpan_dev->association_lock); + + wpan_dev->max_associations = max; +} +EXPORT_SYMBOL_GPL(cfg802154_set_max_associations); From 80f8bf9a2a7f603662e08f7663643a58087a2cd4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:12 +0200 Subject: [PATCH 0966/7721] mac802154: Follow the number of associated devices Track the count of associated devices. Limit the number of associations using the value provided by the user if any. If we reach the maximum number of associations, we tell the device we are at capacity. If the user do not want to accept any more associations, it may specify the value 0 to the maximum number of associations, which will lead to an access denied error status returned to the peers trying to associate. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-10-miquel.raynal@bootlin.com --- include/net/cfg802154.h | 1 + net/ieee802154/core.c | 2 ++ net/mac802154/cfg.c | 1 + net/mac802154/scan.c | 33 +++++++++++++++++++++++---------- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 0d3e9af00198..a64bbcd71f10 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -507,6 +507,7 @@ struct wpan_dev { struct ieee802154_pan_device *parent; struct list_head children; unsigned int max_associations; + unsigned int nchildren; }; #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 2d6fe45efa05..60e8fff1347e 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -212,6 +212,8 @@ static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev) kfree(child); } + wpan_dev->nchildren = 0; + mutex_unlock(&wpan_dev->association_lock); } diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 083de2d3fe37..17e2032fac24 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -454,6 +454,7 @@ static int mac802154_disassociate_child(struct wpan_phy *wpan_phy, return ret; list_del(&child->node); + wpan_dev->nchildren--; kfree(child); return 0; diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index d5f66c204bc5..81d2c2bb1f09 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -800,20 +800,32 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, child->mode = IEEE802154_EXTENDED_ADDRESSING; ceaddr = swab64((__force u64)child->extended_addr); - assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL; - if (assoc_req_pl.alloc_addr) { - assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev); - child->mode = IEEE802154_SHORT_ADDRESSING; + if (wpan_dev->nchildren >= wpan_dev->max_associations) { + if (!wpan_dev->max_associations) + assoc_resp_pl.status = IEEE802154_PAN_ACCESS_DENIED; + else + assoc_resp_pl.status = IEEE802154_PAN_AT_CAPACITY; + assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); + dev_dbg(&sdata->dev->dev, + "Refusing ASSOC REQ from child %8phC, %s\n", &ceaddr, + assoc_resp_pl.status == IEEE802154_PAN_ACCESS_DENIED ? + "access denied" : "too many children"); } else { - assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC); + assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL; + if (assoc_req_pl.alloc_addr) { + assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev); + child->mode = IEEE802154_SHORT_ADDRESSING; + } else { + assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC); + } + child->short_addr = assoc_resp_pl.short_addr; + dev_dbg(&sdata->dev->dev, + "Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n", + &ceaddr, le16_to_cpu(child->short_addr)); } - child->short_addr = assoc_resp_pl.short_addr; - dev_dbg(&sdata->dev->dev, - "Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n", - &ceaddr, le16_to_cpu(child->short_addr)); ret = mac802154_send_association_resp_locked(sdata, child, &assoc_resp_pl); - if (ret) { + if (ret || assoc_resp_pl.status != IEEE802154_ASSOCIATION_SUCCESSFUL) { kfree(child); goto unlock; } @@ -834,6 +846,7 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, } list_add(&child->node, &wpan_dev->children); + wpan_dev->nchildren++; unlock: mutex_unlock(&wpan_dev->association_lock); From 1e2a45f1f854ce63c114b42298ea686dce9ae4fd Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:13 +0200 Subject: [PATCH 0967/7721] mac802154: Handle disassociation notifications from peers Peers may decided to disassociate from us, their coordinator, in this case they will send a disassociation notification which we must acknowledge. If we don't, the peer device considers itself disassociated anyway. We also need to drop the reference to this child from our internal structures. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-11-miquel.raynal@bootlin.com --- net/mac802154/ieee802154_i.h | 2 ++ net/mac802154/rx.c | 8 ++++++ net/mac802154/scan.c | 55 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 432bfa87249e..08dd521a51a5 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -318,6 +318,8 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local) int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, struct ieee802154_pan_device *target, u8 reason); +int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb); int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, struct sk_buff *skb); diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index 96040b63a4fc..0024341ef9c5 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -110,6 +110,14 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work) mac802154_process_association_req(mac_pkt->sdata, mac_pkt->skb); break; + case IEEE802154_CMD_DISASSOCIATION_NOTIFY: + dev_dbg(&mac_pkt->sdata->dev->dev, "processing DISASSOC NOTIF\n"); + if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD) + break; + + mac802154_process_disassociation_notif(mac_pkt->sdata, mac_pkt->skb); + break; + default: break; } diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index 81d2c2bb1f09..7597072aed57 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -852,3 +852,58 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, mutex_unlock(&wpan_dev->association_lock); return ret; } + +int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee802154_addr *src = &mac_cb(skb)->source; + struct ieee802154_addr *dest = &mac_cb(skb)->dest; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct ieee802154_pan_device *child; + struct ieee802154_addr target; + bool parent; + u64 teaddr; + + if (skb->len != sizeof(u8)) + return -EINVAL; + + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING)) + return -EINVAL; + + if (dest->mode == IEEE802154_EXTENDED_ADDRESSING && + unlikely(dest->extended_addr != wpan_dev->extended_addr)) + return -ENODEV; + else if (dest->mode == IEEE802154_SHORT_ADDRESSING && + unlikely(dest->short_addr != wpan_dev->short_addr)) + return -ENODEV; + + if (dest->pan_id != wpan_dev->pan_id) + return -ENODEV; + + target.mode = IEEE802154_EXTENDED_ADDRESSING; + target.extended_addr = src->extended_addr; + teaddr = swab64((__force u64)target.extended_addr); + dev_dbg(&skb->dev->dev, "Processing DISASSOC NOTIF from %8phC\n", &teaddr); + + mutex_lock(&wpan_dev->association_lock); + parent = cfg802154_device_is_parent(wpan_dev, &target); + if (!parent) + child = cfg802154_device_is_child(wpan_dev, &target); + if (!parent && !child) { + mutex_unlock(&wpan_dev->association_lock); + return -EINVAL; + } + + if (parent) { + kfree(wpan_dev->parent); + wpan_dev->parent = NULL; + } else { + list_del(&child->node); + kfree(child); + wpan_dev->nchildren--; + } + + mutex_unlock(&wpan_dev->association_lock); + + return 0; +} From 83fcf26b00d77e4a0ec920524fe85350a27e9c05 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 27 Sep 2023 20:12:14 +0200 Subject: [PATCH 0968/7721] ieee802154: Give the user the association list Upon request, we must be able to provide to the user the list of associations currently in place. Let's add a new netlink command and attribute for this purpose. Signed-off-by: Miquel Raynal Acked-by: Stefan Schmidt Acked-by: Alexander Aring Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-12-miquel.raynal@bootlin.com --- include/net/nl802154.h | 18 ++++++- net/ieee802154/nl802154.c | 103 +++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 4 deletions(-) diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 8b26faae49e8..4c752f799957 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -81,6 +81,7 @@ enum nl802154_commands { NL802154_CMD_ASSOCIATE, NL802154_CMD_DISASSOCIATE, NL802154_CMD_SET_MAX_ASSOCIATIONS, + NL802154_CMD_LIST_ASSOCIATIONS, /* add new commands above here */ @@ -151,6 +152,7 @@ enum nl802154_attrs { NL802154_ATTR_SCAN_DONE_REASON, NL802154_ATTR_BEACON_INTERVAL, NL802154_ATTR_MAX_ASSOCIATIONS, + NL802154_ATTR_PEER, /* add attributes here, update the policy in nl802154.c */ @@ -389,8 +391,6 @@ enum nl802154_supported_bool_states { NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 }; -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - enum nl802154_dev_addr_modes { NL802154_DEV_ADDR_NONE, __NL802154_DEV_ADDR_INVALID, @@ -410,12 +410,26 @@ enum nl802154_dev_addr_attrs { NL802154_DEV_ADDR_ATTR_SHORT, NL802154_DEV_ADDR_ATTR_EXTENDED, NL802154_DEV_ADDR_ATTR_PAD, + NL802154_DEV_ADDR_ATTR_PEER_TYPE, /* keep last */ __NL802154_DEV_ADDR_ATTR_AFTER_LAST, NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 }; +enum nl802154_peer_type { + NL802154_PEER_TYPE_UNSPEC, + + NL802154_PEER_TYPE_PARENT, + NL802154_PEER_TYPE_CHILD, + + /* keep last */ + __NL802154_PEER_TYPE_AFTER_LAST, + NL802154_PEER_TYPE_MAX = __NL802154_PEER_TYPE_AFTER_LAST - 1 +}; + +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL + enum nl802154_key_id_modes { NL802154_KEY_ID_MODE_IMPLICIT, NL802154_KEY_ID_MODE_INDEX, diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 06e0bd6ffcca..822cf025120a 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -235,6 +235,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_BEACON_INTERVAL] = NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION), [NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 }, + [NL802154_ATTR_PEER] = { .type = NLA_NESTED }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, @@ -249,7 +250,6 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ }; -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static int nl802154_prepare_wpan_dev_dump(struct sk_buff *skb, struct netlink_callback *cb, @@ -308,7 +308,6 @@ nl802154_finish_wpan_dev_dump(struct cfg802154_registered_device *rdev) { rtnl_unlock(); } -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ /* message building helper */ static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, @@ -1717,6 +1716,101 @@ static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info * return 0; } +static int nl802154_send_peer_info(struct sk_buff *msg, + struct netlink_callback *cb, + u32 seq, int flags, + struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, + struct ieee802154_pan_device *peer, + enum nl802154_peer_type type) +{ + struct nlattr *nla; + void *hdr; + + ASSERT_RTNL(); + + hdr = nl802154hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags, + NL802154_CMD_LIST_ASSOCIATIONS); + if (!hdr) + return -ENOBUFS; + + genl_dump_check_consistent(cb, hdr); + + nla = nla_nest_start_noflag(msg, NL802154_ATTR_PEER); + if (!nla) + goto nla_put_failure; + + if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_PEER_TYPE, type)) + goto nla_put_failure; + + if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_MODE, peer->mode)) + goto nla_put_failure; + + if (nla_put(msg, NL802154_DEV_ADDR_ATTR_SHORT, + IEEE802154_SHORT_ADDR_LEN, &peer->short_addr)) + goto nla_put_failure; + + if (nla_put(msg, NL802154_DEV_ADDR_ATTR_EXTENDED, + IEEE802154_EXTENDED_ADDR_LEN, &peer->extended_addr)) + goto nla_put_failure; + + nla_nest_end(msg, nla); + + genlmsg_end(msg, hdr); + + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl802154_list_associations(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct cfg802154_registered_device *rdev; + struct ieee802154_pan_device *child; + struct wpan_dev *wpan_dev; + int err; + + err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev); + if (err) + return err; + + mutex_lock(&wpan_dev->association_lock); + + if (cb->args[2]) + goto out; + + if (wpan_dev->parent) { + err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq, + NLM_F_MULTI, rdev, wpan_dev, + wpan_dev->parent, + NL802154_PEER_TYPE_PARENT); + if (err < 0) + goto out_err; + } + + list_for_each_entry(child, &wpan_dev->children, node) { + err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq, + NLM_F_MULTI, rdev, wpan_dev, + child, + NL802154_PEER_TYPE_CHILD); + if (err < 0) + goto out_err; + } + + cb->args[2] = 1; +out: + err = skb->len; +out_err: + mutex_unlock(&wpan_dev->association_lock); + + nl802154_finish_wpan_dev_dump(rdev); + + return err; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2861,6 +2955,11 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_LIST_ASSOCIATIONS, + .dumpit = nl802154_list_associations, + /* can be retrieved by unprivileged users */ + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, From 44eea8d08078bbce4d0f76c16706ab57ec38da62 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 13 Nov 2023 08:54:56 +0000 Subject: [PATCH 0969/7721] drm/i915: Remove return type from i915_drm_client_remove_object There is no need to return anything in the version which was merged and also the implementation of the !CONFIG_PROC_FS wasn't returning anything, causing a build failure there. Signed-off-by: Tvrtko Ursulin Fixes: e4ae85e364fc ("drm/i915: Add ability for tracking buffer objects per client") Cc: Aravind Iddamsetty Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311110104.8TlHVxUI-lkp@intel.com/ Reviewed-by: Jani Nikula Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231113085457.199053-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_drm_client.c | 6 ++---- drivers/gpu/drm/i915/i915_drm_client.h | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index 7efffdaa508d..be9acfd9410e 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -191,22 +191,20 @@ void i915_drm_client_add_object(struct i915_drm_client *client, spin_unlock_irqrestore(&client->objects_lock, flags); } -bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +void i915_drm_client_remove_object(struct drm_i915_gem_object *obj) { struct i915_drm_client *client = fetch_and_zero(&obj->client); unsigned long flags; /* Object may not be associated with a client. */ if (!client) - return false; + return; spin_lock_irqsave(&client->objects_lock, flags); list_del_rcu(&obj->client_link); spin_unlock_irqrestore(&client->objects_lock, flags); i915_drm_client_put(client); - - return true; } void i915_drm_client_add_context_objects(struct i915_drm_client *client, diff --git a/drivers/gpu/drm/i915/i915_drm_client.h b/drivers/gpu/drm/i915/i915_drm_client.h index 69cedfcd3d69..a439dd789936 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.h +++ b/drivers/gpu/drm/i915/i915_drm_client.h @@ -70,7 +70,7 @@ void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file); #ifdef CONFIG_PROC_FS void i915_drm_client_add_object(struct i915_drm_client *client, struct drm_i915_gem_object *obj); -bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj); +void i915_drm_client_remove_object(struct drm_i915_gem_object *obj); void i915_drm_client_add_context_objects(struct i915_drm_client *client, struct intel_context *ce); #else @@ -79,7 +79,8 @@ static inline void i915_drm_client_add_object(struct i915_drm_client *client, { } -static inline bool i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +static inline void +i915_drm_client_remove_object(struct drm_i915_gem_object *obj) { } From e31b380741bfa27d274a9f9610fd732e1204ea24 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 13 Nov 2023 08:54:57 +0000 Subject: [PATCH 0970/7721] drm/i915: Add __rcu annotation to cursor when iterating client objects __rcu annotation is needed to avoid the sparse warnings such as: .../i915_drm_client.c:92:9: sparse: sparse: incompatible types in comparison expression (different address spaces): .../i915_drm_client.c:92:9: sparse: struct list_head [noderef] __rcu * .../i915_drm_client.c:92:9: sparse: struct list_head * Signed-off-by: Tvrtko Ursulin Fixes: 968853033d8a ("drm/i915: Implement fdinfo memory stats printing") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311110610.h0m6ydI5-lkp@intel.com/ Cc: Andi Shyti Cc: Aravind Iddamsetty Reviewed-by: Jani Nikula Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231113085457.199053-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_drm_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index be9acfd9410e..fa6852713bee 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -78,7 +78,7 @@ static void show_meminfo(struct drm_printer *p, struct drm_file *file) struct drm_i915_private *i915 = fpriv->i915; struct drm_i915_gem_object *obj; struct intel_memory_region *mr; - struct list_head *pos; + struct list_head __rcu *pos; unsigned int id; /* Public objects. */ From dfed6b58d54f3a5d7e6bc1fb060e2c936330eba2 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 16 Nov 2023 08:44:56 +0000 Subject: [PATCH 0971/7721] drm/i915/gsc: Mark internal GSC engine with reserved uabi class The GSC CS is not exposed to the user, so we skipped assigning a uabi class number for it. However, the trace logs use the uabi class and instance to identify the engine, so leaving uabi class unset makes the GSC CS show up as the RCS in those logs. Given that the engine is not exposed to the user, we can't add a new case in the uabi enum, so we insted internally define a kernel internal class as -1. At the same time remove special handling for the name and complete the uabi_classes array so internal class is automatically correctly assigned. Engine will show as 65535:0 other0 in the logs/traces which should be unique enough. v2: * Fix uabi class u8 vs u16 type confusion. Signed-off-by: Tvrtko Ursulin Fixes: 194babe26bdc ("drm/i915/mtl: don't expose GSC command streamer to the user") Cc: Daniele Ceraolo Spurio Cc: Alan Previn Cc: Matt Roper Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20231116084456.291533-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_engine_user.c | 39 ++++++++++++--------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c index 118164ddbb2e..833987015b8b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_user.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c @@ -41,12 +41,15 @@ void intel_engine_add_user(struct intel_engine_cs *engine) llist_add(&engine->uabi_llist, &engine->i915->uabi_engines_llist); } -static const u8 uabi_classes[] = { +#define I915_NO_UABI_CLASS ((u16)(-1)) + +static const u16 uabi_classes[] = { [RENDER_CLASS] = I915_ENGINE_CLASS_RENDER, [COPY_ENGINE_CLASS] = I915_ENGINE_CLASS_COPY, [VIDEO_DECODE_CLASS] = I915_ENGINE_CLASS_VIDEO, [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE, [COMPUTE_CLASS] = I915_ENGINE_CLASS_COMPUTE, + [OTHER_CLASS] = I915_NO_UABI_CLASS, /* Not exposed to users, no uabi class. */ }; static int engine_cmp(void *priv, const struct list_head *A, @@ -200,6 +203,7 @@ static void engine_rename(struct intel_engine_cs *engine, const char *name, u16 void intel_engines_driver_register(struct drm_i915_private *i915) { + u16 name_instance, other_instance = 0; struct legacy_ring ring = {}; struct list_head *it, *next; struct rb_node **p, *prev; @@ -216,27 +220,28 @@ void intel_engines_driver_register(struct drm_i915_private *i915) if (intel_gt_has_unrecoverable_error(engine->gt)) continue; /* ignore incomplete engines */ - /* - * We don't want to expose the GSC engine to the users, but we - * still rename it so it is easier to identify in the debug logs - */ - if (engine->id == GSC0) { - engine_rename(engine, "gsc", 0); - continue; - } - GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes)); engine->uabi_class = uabi_classes[engine->class]; + if (engine->uabi_class == I915_NO_UABI_CLASS) { + name_instance = other_instance++; + } else { + GEM_BUG_ON(engine->uabi_class >= + ARRAY_SIZE(i915->engine_uabi_class_count)); + name_instance = + i915->engine_uabi_class_count[engine->uabi_class]++; + } + engine->uabi_instance = name_instance; - GEM_BUG_ON(engine->uabi_class >= - ARRAY_SIZE(i915->engine_uabi_class_count)); - engine->uabi_instance = - i915->engine_uabi_class_count[engine->uabi_class]++; - - /* Replace the internal name with the final user facing name */ + /* + * Replace the internal name with the final user and log facing + * name. + */ engine_rename(engine, intel_engine_class_repr(engine->class), - engine->uabi_instance); + name_instance); + + if (engine->uabi_class == I915_NO_UABI_CLASS) + continue; rb_link_node(&engine->uabi_node, prev, p); rb_insert_color(&engine->uabi_node, &i915->uabi_engines); From 92fc925f838660eec25862a7fa7e6ef79d22f3ea Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Sat, 18 Nov 2023 12:50:37 +0530 Subject: [PATCH 0972/7721] gpio: tangier: simplify locking using cleanup helpers Use lock guards from cleanup.h to simplify locking. Signed-off-by: Raag Jadav Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-tangier.c | 54 ++++++++++--------------------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c index 158fa9054e9c..b75e0b12087a 100644 --- a/drivers/gpio/gpio-tangier.c +++ b/drivers/gpio/gpio-tangier.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -92,37 +93,31 @@ static int tng_gpio_get(struct gpio_chip *chip, unsigned int offset) static void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *reg; u8 shift; reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); writel(BIT(shift), reg); - - raw_spin_unlock_irqrestore(&priv->lock, flags); } static int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gpdr; u32 value; u8 shift; gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gpdr); value &= ~BIT(shift); writel(value, gpdr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -130,21 +125,18 @@ static int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset int value) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gpdr; u8 shift; gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); tng_gpio_set(chip, offset, value); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gpdr); value |= BIT(shift); writel(value, gpdr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -165,14 +157,13 @@ static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, unsigned int debounce) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gfbr; u32 value; u8 shift; gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gfbr); if (debounce) @@ -181,8 +172,6 @@ static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, value |= BIT(shift); writel(value, gfbr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -208,27 +197,25 @@ static void tng_irq_ack(struct irq_data *d) { struct tng_gpio *priv = irq_data_get_irq_chip_data(d); irq_hw_number_t gpio = irqd_to_hwirq(d); - unsigned long flags; void __iomem *gisr; u8 shift; gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); + writel(BIT(shift), gisr); - raw_spin_unlock_irqrestore(&priv->lock, flags); } static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) { - unsigned long flags; void __iomem *gimr; u32 value; u8 shift; gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gimr); if (unmask) @@ -236,8 +223,6 @@ static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) else value &= ~BIT(shift); writel(value, gimr); - - raw_spin_unlock_irqrestore(&priv->lock, flags); } static void tng_irq_mask(struct irq_data *d) @@ -268,10 +253,9 @@ static int tng_irq_set_type(struct irq_data *d, unsigned int type) void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); u8 shift = gpio % 32; - unsigned long flags; u32 value; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(grer); if (type & IRQ_TYPE_EDGE_RISING) @@ -312,8 +296,6 @@ static int tng_irq_set_type(struct irq_data *d, unsigned int type) irq_set_handler_locked(d, handle_edge_irq); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -325,10 +307,11 @@ static int tng_irq_set_wake(struct irq_data *d, unsigned int on) void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr); void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr); u8 shift = gpio % 32; - unsigned long flags; u32 value; - raw_spin_lock_irqsave(&priv->lock, flags); + dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio); + + guard(raw_spinlock_irqsave)(&priv->lock); /* Clear the existing wake status */ writel(BIT(shift), gwsr); @@ -340,9 +323,6 @@ static int tng_irq_set_wake(struct irq_data *d, unsigned int on) value &= ~BIT(shift); writel(value, gwmr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - - dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio); return 0; } @@ -482,10 +462,9 @@ static int tng_gpio_suspend(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; - unsigned long flags; unsigned int base; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { /* GPLR is RO, values read will be restored using GPSR */ @@ -499,8 +478,6 @@ static int tng_gpio_suspend(struct device *dev) ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -508,10 +485,9 @@ static int tng_gpio_resume(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; - unsigned long flags; unsigned int base; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { /* GPLR is RO, values read will be restored using GPSR */ @@ -525,8 +501,6 @@ static int tng_gpio_resume(struct device *dev) writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } From b49e894c3fd83f67aae2a4778b98ea3838e41020 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 30 Oct 2023 18:40:12 +0100 Subject: [PATCH 0973/7721] drm/i915: Replace custom intel runtime_pm tracker with ref_tracker library Beside reusing existing code, the main advantage of ref_tracker is tracking per instance of wakeref. It allows also to catch double put. On the other side we lose information about the first acquire and the last release, but the advantages outweigh it. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231030-ref_tracker_i915-v1-1-006fe6b96421@intel.com --- drivers/gpu/drm/i915/Kconfig.debug | 4 + .../drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/i915_driver.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 221 ++---------------- drivers/gpu/drm/i915/intel_runtime_pm.h | 11 +- drivers/gpu/drm/i915/intel_wakeref.c | 28 +++ drivers/gpu/drm/i915/intel_wakeref.h | 35 ++- 7 files changed, 86 insertions(+), 217 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 2d21930d5501..8d82d7a1a9c5 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -24,7 +24,9 @@ config DRM_I915_DEBUG select DEBUG_FS select PREEMPT_COUNT select I2C_CHARDEV + select REF_TRACKER select STACKDEPOT + select STACKTRACE select DRM_DP_AUX_CHARDEV select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) @@ -231,7 +233,9 @@ config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT + select STACKTRACE help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e25785ae1c20..f78bfcf2ce00 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -405,7 +405,7 @@ print_async_put_domains_state(struct i915_power_domains *power_domains) struct drm_i915_private, display.power.domains); - drm_dbg(&i915->drm, "async_put_wakeref %u\n", + drm_dbg(&i915->drm, "async_put_wakeref %lu\n", power_domains->async_put_wakeref); print_power_domains(power_domains, "async_put_domains[0]", diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 802de2c6decb..db6f7c30adde 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1037,7 +1037,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_power_domains_driver_remove(i915); enable_rpm_wakeref_asserts(&i915->runtime_pm); - intel_runtime_pm_driver_release(&i915->runtime_pm); + intel_runtime_pm_driver_last_release(&i915->runtime_pm); } static bool suspend_to_idle(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8743153fad87..91491111dbd5 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -52,182 +52,37 @@ #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) -#include - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) -{ - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n = stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); -} - static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - spin_lock_init(&rpm->debug.lock); - stack_depot_init(); + ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm->kdev)); } -static noinline depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - if (rpm->no_wakeref_tracking) + if (!rpm->available || rpm->no_wakeref_tracking) return -1; - stack = __save_depot_stack(); - if (!stack) - return -1; - - spin_lock_irqsave(&rpm->debug.lock, flags); - - if (!rpm->debug.count) - rpm->debug.last_acquire = stack; - - stacks = krealloc(rpm->debug.owners, - (rpm->debug.count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[rpm->debug.count++] = stack; - rpm->debug.owners = stacks; - } else { - stack = -1; - } - - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - return stack; + return intel_ref_tracker_alloc(&rpm->debug); } static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - depot_stack_handle_t stack) + intel_wakeref_t wakeref) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); - unsigned long flags, n; - bool found = false; - - if (unlikely(stack == -1)) + if (!rpm->available || rpm->no_wakeref_tracking) return; - spin_lock_irqsave(&rpm->debug.lock, flags); - for (n = rpm->debug.count; n--; ) { - if (rpm->debug.owners[n] == stack) { - memmove(rpm->debug.owners + n, - rpm->debug.owners + n + 1, - (--rpm->debug.count - n) * sizeof(stack)); - found = true; - break; - } - } - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (drm_WARN(&i915->drm, !found, - "Unmatched wakeref (tracking %lu), count %u\n", - rpm->debug.count, atomic_read(&rpm->wakeref_count))) { - char *buf; - - buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref %x from\n%s", stack, buf); - - stack = READ_ONCE(rpm->debug.last_release); - if (stack) { - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref last released at\n%s", buf); - } - - kfree(buf); - } + intel_ref_tracker_free(&rpm->debug, wakeref); } -static int cmphandle(const void *_a, const void *_b) +static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) { - const depot_stack_handle_t * const a = _a, * const b = _b; - - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -static void -__print_intel_runtime_pm_wakeref(struct drm_printer *p, - const struct intel_runtime_pm_debug *dbg) -{ - unsigned long i; - char *buf; - - buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (dbg->last_acquire) { - stack_depot_snprint(dbg->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (dbg->last_release) { - stack_depot_snprint(dbg->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", dbg->count); - - sort(dbg->owners, dbg->count, sizeof(*dbg->owners), cmphandle, NULL); - - for (i = 0; i < dbg->count; i++) { - depot_stack_handle_t stack = dbg->owners[i]; - unsigned long rep; - - rep = 1; - while (i + 1 < dbg->count && dbg->owners[i + 1] == stack) - rep++, i++; - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -static noinline void -__untrack_all_wakerefs(struct intel_runtime_pm_debug *debug, - struct intel_runtime_pm_debug *saved) -{ - *saved = *debug; - - debug->owners = NULL; - debug->count = 0; - debug->last_release = __save_depot_stack(); -} - -static void -dump_and_free_wakeref_tracking(struct intel_runtime_pm_debug *debug) -{ - if (debug->count) { - struct drm_printer p = drm_debug_printer("i915"); - - __print_intel_runtime_pm_wakeref(&p, debug); - } - - kfree(debug->owners); + ref_tracker_dir_exit(&rpm->debug); } static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_runtime_pm_debug dbg = {}; unsigned long flags; if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -235,60 +90,14 @@ __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) flags)) return; - __untrack_all_wakerefs(&rpm->debug, &dbg); + ref_tracker_dir_print_locked(&rpm->debug, INTEL_REFTRACK_PRINT_LIMIT); spin_unlock_irqrestore(&rpm->debug.lock, flags); - - dump_and_free_wakeref_tracking(&dbg); -} - -static noinline void -untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) -{ - struct intel_runtime_pm_debug dbg = {}; - unsigned long flags; - - spin_lock_irqsave(&rpm->debug.lock, flags); - __untrack_all_wakerefs(&rpm->debug, &dbg); - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - dump_and_free_wakeref_tracking(&dbg); } void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, struct drm_printer *p) { - struct intel_runtime_pm_debug dbg = {}; - - do { - unsigned long alloc = dbg.count; - depot_stack_handle_t *s; - - spin_lock_irq(&rpm->debug.lock); - dbg.count = rpm->debug.count; - if (dbg.count <= alloc) { - memcpy(dbg.owners, - rpm->debug.owners, - dbg.count * sizeof(*s)); - } - dbg.last_acquire = rpm->debug.last_acquire; - dbg.last_release = rpm->debug.last_release; - spin_unlock_irq(&rpm->debug.lock); - if (dbg.count <= alloc) - break; - - s = krealloc(dbg.owners, - dbg.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - dbg.owners = s; - } while (1); - - __print_intel_runtime_pm_wakeref(p, &dbg); - -out: - kfree(dbg.owners); + intel_ref_tracker_show(&rpm->debug, p); } #else @@ -297,14 +106,14 @@ static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { } -static depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { return -1; } static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - intel_wakeref_t wref) + intel_wakeref_t wakeref) { } @@ -639,7 +448,11 @@ void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) "i915 raw-wakerefs=%d wakelocks=%d on cleanup\n", intel_rpm_raw_wakeref_count(count), intel_rpm_wakelock_count(count)); +} +void intel_runtime_pm_driver_last_release(struct intel_runtime_pm *rpm) +{ + intel_runtime_pm_driver_release(rpm); untrack_all_intel_runtime_pm_wakerefs(rpm); } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index f79cda7a2503..f3cb7d4c7000 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -77,15 +77,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_runtime_pm_debug { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; - } debug; + struct ref_tracker_dir debug; #endif }; @@ -189,6 +181,7 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm); void intel_runtime_pm_enable(struct intel_runtime_pm *rpm); void intel_runtime_pm_disable(struct intel_runtime_pm *rpm); void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm); +void intel_runtime_pm_driver_last_release(struct intel_runtime_pm *rpm); intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm); intel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm); diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 623a69089386..2401b88b55a4 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -191,3 +191,31 @@ void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf) intel_wakeref_auto(wf, 0); INTEL_WAKEREF_BUG_ON(wf->wakeref); } + +void intel_ref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p) +{ + const size_t buf_size = PAGE_SIZE; + char *buf, *sb, *se; + size_t count; + + buf = kmalloc(buf_size, GFP_NOWAIT); + if (!buf) + return; + + count = ref_tracker_dir_snprint(dir, buf, buf_size); + if (!count) + goto free; + /* printk does not like big buffers, so we split it */ + for (sb = buf; *sb; sb = se + 1) { + se = strchrnul(sb, '\n'); + drm_printf(p, "%.*s", (int)(se - sb + 1), sb); + if (!*se) + break; + } + if (count >= buf_size) + drm_printf(p, "\n...dropped %zd extra bytes of leak report.\n", + count + 1 - buf_size); +free: + kfree(buf); +} diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h index ec881b097368..909cad13ac1f 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -7,16 +7,25 @@ #ifndef INTEL_WAKEREF_H #define INTEL_WAKEREF_H +#include + #include #include #include #include #include #include +#include +#include #include #include #include +typedef unsigned long intel_wakeref_t; + +#define INTEL_REFTRACK_DEAD_COUNT 16 +#define INTEL_REFTRACK_PRINT_LIMIT 16 + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) #else @@ -26,8 +35,6 @@ struct intel_runtime_pm; struct intel_wakeref; -typedef depot_stack_handle_t intel_wakeref_t; - struct intel_wakeref_ops { int (*get)(struct intel_wakeref *wf); int (*put)(struct intel_wakeref *wf); @@ -261,6 +268,30 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); +#define INTEL_WAKEREF_DEF ((intel_wakeref_t)(-1)) + +static inline intel_wakeref_t intel_ref_tracker_alloc(struct ref_tracker_dir *dir) +{ + struct ref_tracker *user = NULL; + + ref_tracker_alloc(dir, &user, GFP_NOWAIT); + + return (intel_wakeref_t)user ?: INTEL_WAKEREF_DEF; +} + +static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, + intel_wakeref_t handle) +{ + struct ref_tracker *user; + + user = (handle == INTEL_WAKEREF_DEF) ? NULL : (void *)handle; + + ref_tracker_free(dir, &user); +} + +void intel_ref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p); + struct intel_wakeref_auto { struct drm_i915_private *i915; struct timer_list timer; From 5e4e06e4087eb91b0e5405ed42e792415d055e45 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 30 Oct 2023 18:40:13 +0100 Subject: [PATCH 0974/7721] drm/i915: Track gt pm wakerefs Track every intel_gt_pm_get() until its corresponding release in intel_gt_pm_put() by returning a cookie to the caller for acquire that must be passed by on released. When there is an imbalance, we can see who either tried to free a stale wakeref, or who forgot to free theirs. v2: track recently added calls in gen8_ggtt_bind_get_ce and destroyed_worker_func Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231030-ref_tracker_i915-v1-2-006fe6b96421@intel.com --- drivers/gpu/drm/i915/Kconfig.debug | 14 +++++++ .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 14 ++++--- .../i915/gem/selftests/i915_gem_coherency.c | 10 +++-- .../drm/i915/gem/selftests/i915_gem_mman.c | 14 ++++--- drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 13 +++++-- .../gpu/drm/i915/gt/intel_breadcrumbs_types.h | 3 +- drivers/gpu/drm/i915/gt/intel_context.h | 4 +- drivers/gpu/drm/i915/gt/intel_context_types.h | 2 + drivers/gpu/drm/i915/gt/intel_engine_pm.c | 7 ++-- drivers/gpu/drm/i915/gt/intel_engine_types.h | 2 + .../drm/i915/gt/intel_execlists_submission.c | 2 +- drivers/gpu/drm/i915/gt/intel_ggtt.c | 16 ++++---- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 12 +++--- drivers/gpu/drm/i915/gt/intel_gt_pm.h | 38 ++++++++++++++----- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 4 +- drivers/gpu/drm/i915/gt/selftest_engine_cs.c | 20 ++++++---- drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 5 ++- drivers/gpu/drm/i915/gt/selftest_reset.c | 10 +++-- drivers/gpu/drm/i915/gt/selftest_rps.c | 17 +++++---- drivers/gpu/drm/i915/gt/selftest_slpc.c | 5 ++- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 14 ++++--- drivers/gpu/drm/i915/i915_pmu.c | 16 ++++---- drivers/gpu/drm/i915/intel_wakeref.c | 7 +++- drivers/gpu/drm/i915/intel_wakeref.h | 38 +++++++++++++++++-- 24 files changed, 197 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 8d82d7a1a9c5..5b7162076850 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -40,6 +40,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO select DRM_I915_DEBUG_RUNTIME_PM + select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST default n @@ -244,3 +245,16 @@ config DRM_I915_DEBUG_RUNTIME_PM Recommended for driver developers only. If in doubt, say "N" + +config DRM_I915_DEBUG_WAKEREF + bool "Enable extra tracking for wakerefs" + depends on DRM_I915 + select REF_TRACKER + select STACKDEPOT + select STACKTRACE + help + Choose this option to turn on extra state checking and usage + tracking for the wakerefPM functionality. This may introduce + overhead during driver runtime. + + If in doubt, say "N" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 45b9d9e34b8b..b1aa62dfb155 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -253,6 +253,8 @@ struct i915_execbuffer { struct intel_gt *gt; /* gt for the execbuf */ struct intel_context *context; /* logical state for the request */ struct i915_gem_context *gem_context; /** caller's context */ + intel_wakeref_t wakeref; + intel_wakeref_t wakeref_gt0; /** our requests to build */ struct i915_request *requests[MAX_ENGINE_INSTANCE + 1]; @@ -2719,13 +2721,13 @@ eb_select_engine(struct i915_execbuffer *eb) for_each_child(ce, child) intel_context_get(child); - intel_gt_pm_get(gt); + eb->wakeref = intel_gt_pm_get(ce->engine->gt); /* * Keep GT0 active on MTL so that i915_vma_parked() doesn't * free VMAs while execbuf ioctl is validating VMAs. */ if (gt->info.id) - intel_gt_pm_get(to_gt(gt->i915)); + eb->wakeref_gt0 = intel_gt_pm_get(to_gt(gt->i915)); if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { err = intel_context_alloc_state(ce); @@ -2765,9 +2767,9 @@ eb_select_engine(struct i915_execbuffer *eb) err: if (gt->info.id) - intel_gt_pm_put(to_gt(gt->i915)); + intel_gt_pm_put(to_gt(gt->i915), eb->wakeref_gt0); - intel_gt_pm_put(gt); + intel_gt_pm_put(ce->engine->gt, eb->wakeref); for_each_child(ce, child) intel_context_put(child); intel_context_put(ce); @@ -2785,8 +2787,8 @@ eb_put_engine(struct i915_execbuffer *eb) * i915_vma_parked() from interfering while execbuf validates vmas. */ if (eb->gt->info.id) - intel_gt_pm_put(to_gt(eb->gt->i915)); - intel_gt_pm_put(eb->gt); + intel_gt_pm_put(to_gt(eb->gt->i915), eb->wakeref_gt0); + intel_gt_pm_put(eb->context->engine->gt, eb->wakeref); for_each_child(eb->context, child) intel_context_put(child); intel_context_put(eb->context); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c index 3bef1beec7cb..3fd68a099a85 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c @@ -85,6 +85,7 @@ static int cpu_get(struct context *ctx, unsigned long offset, u32 *v) static int gtt_set(struct context *ctx, unsigned long offset, u32 v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err = 0; @@ -99,7 +100,7 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -112,12 +113,13 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v) i915_vma_unpin_iomap(vma); out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err = 0; @@ -132,7 +134,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -145,7 +147,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) i915_vma_unpin_iomap(vma); out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 72957a36a36b..2c51a2c452fc 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -630,14 +630,14 @@ static bool assert_mmap_offset(struct drm_i915_private *i915, static void disable_retire_worker(struct drm_i915_private *i915) { i915_gem_driver_unregister__shrinker(i915); - intel_gt_pm_get(to_gt(i915)); + intel_gt_pm_get_untracked(to_gt(i915)); cancel_delayed_work_sync(&to_gt(i915)->requests.retire_work); } static void restore_retire_worker(struct drm_i915_private *i915) { igt_flush_test(i915); - intel_gt_pm_put(to_gt(i915)); + intel_gt_pm_put_untracked(to_gt(i915)); i915_gem_driver_register__shrinker(i915); } @@ -778,6 +778,7 @@ static int igt_mmap_offset_exhaustion(void *arg) static int gtt_set(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err = 0; @@ -786,7 +787,7 @@ static int gtt_set(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -798,12 +799,13 @@ static int gtt_set(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } static int gtt_check(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err = 0; @@ -812,7 +814,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -828,7 +830,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index ecc990ec1b95..d650beb8ed22 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -28,11 +28,14 @@ static void irq_disable(struct intel_breadcrumbs *b) static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref; + /* * Since we are waiting on a request, the GPU should be busy * and should have its own rpm reference. */ - if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) + wakeref = intel_gt_pm_get_if_awake(b->irq_engine->gt); + if (GEM_WARN_ON(!wakeref)) return; /* @@ -41,7 +44,7 @@ static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) * which we can add a new waiter and avoid the cost of re-enabling * the irq. */ - WRITE_ONCE(b->irq_armed, true); + WRITE_ONCE(b->irq_armed, wakeref); /* Requests may have completed before we could enable the interrupt. */ if (!b->irq_enabled++ && b->irq_enable(b)) @@ -61,12 +64,14 @@ static void intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref = b->irq_armed; + GEM_BUG_ON(!b->irq_enabled); if (!--b->irq_enabled) b->irq_disable(b); - WRITE_ONCE(b->irq_armed, false); - intel_gt_pm_put_async(b->irq_engine->gt); + WRITE_ONCE(b->irq_armed, 0); + intel_gt_pm_put_async(b->irq_engine->gt, wakeref); } static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h index 72dfd3748c4c..bdf09fd67b6e 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h @@ -13,6 +13,7 @@ #include #include "intel_engine_types.h" +#include "intel_wakeref.h" /* * Rather than have every client wait upon all user interrupts, @@ -43,7 +44,7 @@ struct intel_breadcrumbs { spinlock_t irq_lock; /* protects the interrupt from hardirq context */ struct irq_work irq_work; /* for use from inside irq_lock */ unsigned int irq_enabled; - bool irq_armed; + intel_wakeref_t irq_armed; /* Not all breadcrumbs are attached to physical HW */ intel_engine_mask_t engine_mask; diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index a80e3b7c24ff..25564c01507e 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -212,7 +212,7 @@ static inline void intel_context_enter(struct intel_context *ce) return; ce->ops->enter(ce); - intel_gt_pm_get(ce->vm->gt); + ce->wakeref = intel_gt_pm_get(ce->vm->gt); } static inline void intel_context_mark_active(struct intel_context *ce) @@ -229,7 +229,7 @@ static inline void intel_context_exit(struct intel_context *ce) if (--ce->active_count) return; - intel_gt_pm_put_async(ce->vm->gt); + intel_gt_pm_put_async(ce->vm->gt, ce->wakeref); ce->ops->exit(ce); } diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index aceaac28a33e..7eccbd70d89f 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -17,6 +17,7 @@ #include "i915_utils.h" #include "intel_engine_types.h" #include "intel_sseu.h" +#include "intel_wakeref.h" #include "uc/intel_guc_fwif.h" @@ -112,6 +113,7 @@ struct intel_context { u32 ring_size; struct intel_ring *ring; struct intel_timeline *timeline; + intel_wakeref_t wakeref; unsigned long flags; #define CONTEXT_BARRIER_BIT 0 diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index e91fc881dbf1..96bdb93a948d 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -63,7 +63,7 @@ static int __engine_unpark(struct intel_wakeref *wf) ENGINE_TRACE(engine, "\n"); - intel_gt_pm_get(engine->gt); + engine->wakeref_track = intel_gt_pm_get(engine->gt); /* Discard stale context state from across idling */ ce = engine->kernel_context; @@ -122,6 +122,7 @@ __queue_and_release_pm(struct i915_request *rq, */ GEM_BUG_ON(rq->context->active_count != 1); __intel_gt_pm_get(engine->gt); + rq->context->wakeref = intel_wakeref_track(&engine->gt->wakeref); /* * We have to serialise all potential retirement paths with our @@ -285,7 +286,7 @@ static int __engine_park(struct intel_wakeref *wf) engine->park(engine); /* While gt calls i915_vma_parked(), we have to break the lock cycle */ - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async(engine->gt, engine->wakeref_track); return 0; } @@ -296,7 +297,7 @@ static const struct intel_wakeref_ops wf_ops = { void intel_engine_init__pm(struct intel_engine_cs *engine) { - intel_wakeref_init(&engine->wakeref, engine->i915, &wf_ops); + intel_wakeref_init(&engine->wakeref, engine->i915, &wf_ops, engine->name); intel_engine_init_heartbeat(engine); intel_gsc_idle_msg_enable(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index 8769760257fd..960e6be2042f 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -446,7 +446,9 @@ struct intel_engine_cs { unsigned long serial; unsigned long wakeref_serial; + intel_wakeref_t wakeref_track; struct intel_wakeref wakeref; + struct file *default_state; struct { diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index e8f42ec6b1b4..42aade0faf2d 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -630,7 +630,7 @@ static void __execlists_schedule_out(struct i915_request * const rq, execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT); if (engine->fw_domain && !--engine->fw_active) intel_uncore_forcewake_put(engine->uncore, engine->fw_domain); - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async_untracked(engine->gt); /* * If this is part of a virtual engine, its next request may diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 76b0ee2b906b..21a7e3191c18 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -296,7 +296,7 @@ static bool should_update_ggtt_with_bind(struct i915_ggtt *ggtt) return intel_gt_is_bind_context_ready(gt); } -static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) +static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt, intel_wakeref_t *wakeref) { struct intel_context *ce; struct intel_gt *gt = ggtt->vm.gt; @@ -313,7 +313,8 @@ static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) * would conflict with fs_reclaim trying to allocate memory while * doing rpm_resume(). */ - if (!intel_gt_pm_get_if_awake(gt)) + *wakeref = intel_gt_pm_get_if_awake(gt); + if (!*wakeref) return NULL; intel_engine_pm_get(ce->engine); @@ -321,10 +322,10 @@ static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) return ce; } -static void gen8_ggtt_bind_put_ce(struct intel_context *ce) +static void gen8_ggtt_bind_put_ce(struct intel_context *ce, intel_wakeref_t wakeref) { intel_engine_pm_put(ce->engine); - intel_gt_pm_put(ce->engine->gt); + intel_gt_pm_put(ce->engine->gt, wakeref); } static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, @@ -337,12 +338,13 @@ static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, struct sgt_iter iter; struct i915_request *rq; struct intel_context *ce; + intel_wakeref_t wakeref; u32 *cs; if (!num_entries) return true; - ce = gen8_ggtt_bind_get_ce(ggtt); + ce = gen8_ggtt_bind_get_ce(ggtt, &wakeref); if (!ce) return false; @@ -418,13 +420,13 @@ static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, offset += n_ptes; } - gen8_ggtt_bind_put_ce(ce); + gen8_ggtt_bind_put_ce(ce, wakeref); return true; err_rq: i915_request_put(rq); put_ce: - gen8_ggtt_bind_put_ce(ce); + gen8_ggtt_bind_put_ce(ce, wakeref); return false; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index 471b7cdc10ba..220ac4f92edf 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -28,19 +28,20 @@ static void user_forcewake(struct intel_gt *gt, bool suspend) { int count = atomic_read(>->user_wakeref); + intel_wakeref_t wakeref; /* Inside suspend/resume so single threaded, no races to worry about. */ if (likely(!count)) return; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); if (suspend) { GEM_BUG_ON(count > atomic_read(>->wakeref.count)); atomic_sub(count, >->wakeref.count); } else { atomic_add(count, >->wakeref.count); } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); } static void runtime_begin(struct intel_gt *gt) @@ -138,7 +139,7 @@ void intel_gt_pm_init_early(struct intel_gt *gt) * runtime_pm is per-device rather than per-tile, so this is still the * correct structure. */ - intel_wakeref_init(>->wakeref, gt->i915, &wf_ops); + intel_wakeref_init(>->wakeref, gt->i915, &wf_ops, "GT"); seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); } @@ -236,6 +237,7 @@ int intel_gt_resume(struct intel_gt *gt) { struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err; err = intel_gt_has_unrecoverable_error(gt); @@ -252,7 +254,7 @@ int intel_gt_resume(struct intel_gt *gt) */ gt_sanitize(gt, true); - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); intel_rc6_sanitize(>->rc6); @@ -295,7 +297,7 @@ int intel_gt_resume(struct intel_gt *gt) out_fw: intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); intel_gt_bind_context_set_ready(gt); return err; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h index b1eeb5b33918..911fd0160221 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -16,19 +16,28 @@ static inline bool intel_gt_pm_is_awake(const struct intel_gt *gt) return intel_wakeref_is_active(>->wakeref); } -static inline void intel_gt_pm_get(struct intel_gt *gt) +static inline void intel_gt_pm_get_untracked(struct intel_gt *gt) { intel_wakeref_get(>->wakeref); } +static inline intel_wakeref_t intel_gt_pm_get(struct intel_gt *gt) +{ + intel_gt_pm_get_untracked(gt); + return intel_wakeref_track(>->wakeref); +} + static inline void __intel_gt_pm_get(struct intel_gt *gt) { __intel_wakeref_get(>->wakeref); } -static inline bool intel_gt_pm_get_if_awake(struct intel_gt *gt) +static inline intel_wakeref_t intel_gt_pm_get_if_awake(struct intel_gt *gt) { - return intel_wakeref_get_if_active(>->wakeref); + if (!intel_wakeref_get_if_active(>->wakeref)) + return 0; + + return intel_wakeref_track(>->wakeref); } static inline void intel_gt_pm_might_get(struct intel_gt *gt) @@ -36,12 +45,18 @@ static inline void intel_gt_pm_might_get(struct intel_gt *gt) intel_wakeref_might_get(>->wakeref); } -static inline void intel_gt_pm_put(struct intel_gt *gt) +static inline void intel_gt_pm_put_untracked(struct intel_gt *gt) { intel_wakeref_put(>->wakeref); } -static inline void intel_gt_pm_put_async(struct intel_gt *gt) +static inline void intel_gt_pm_put(struct intel_gt *gt, intel_wakeref_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_untracked(gt); +} + +static inline void intel_gt_pm_put_async_untracked(struct intel_gt *gt) { intel_wakeref_put_async(>->wakeref); } @@ -51,9 +66,14 @@ static inline void intel_gt_pm_might_put(struct intel_gt *gt) intel_wakeref_might_put(>->wakeref); } -#define with_intel_gt_pm(gt, tmp) \ - for (tmp = 1, intel_gt_pm_get(gt); tmp; \ - intel_gt_pm_put(gt), tmp = 0) +static inline void intel_gt_pm_put_async(struct intel_gt *gt, intel_wakeref_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_async_untracked(gt); +} + +#define with_intel_gt_pm(gt, wf) \ + for (wf = intel_gt_pm_get(gt); wf; intel_gt_pm_put(gt, wf), wf = 0) /** * with_intel_gt_pm_if_awake - if GT is PM awake, get a reference to prevent @@ -64,7 +84,7 @@ static inline void intel_gt_pm_might_put(struct intel_gt *gt) * @wf: pointer to a temporary wakeref. */ #define with_intel_gt_pm_if_awake(gt, wf) \ - for (wf = intel_gt_pm_get_if_awake(gt); wf; intel_gt_pm_put_async(gt), wf = 0) + for (wf = intel_gt_pm_get_if_awake(gt); wf; intel_gt_pm_put_async(gt, wf), wf = 0) static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index f900cc68d6d9..7114c116e928 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -27,7 +27,7 @@ void intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) { atomic_inc(>->user_wakeref); - intel_gt_pm_get(gt); + intel_gt_pm_get_untracked(gt); if (GRAPHICS_VER(gt->i915) >= 6) intel_uncore_forcewake_user_get(gt->uncore); } @@ -36,7 +36,7 @@ void intel_gt_pm_debugfs_forcewake_user_release(struct intel_gt *gt) { if (GRAPHICS_VER(gt->i915) >= 6) intel_uncore_forcewake_user_put(gt->uncore); - intel_gt_pm_put(gt); + intel_gt_pm_put_untracked(gt); atomic_dec(>->user_wakeref); } diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c index 86cecf7a1105..5ffa5e30f419 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -21,20 +21,22 @@ static int cmp_u32(const void *A, const void *B) return *a - *b; } -static void perf_begin(struct intel_gt *gt) +static intel_wakeref_t perf_begin(struct intel_gt *gt) { - intel_gt_pm_get(gt); + intel_wakeref_t wakeref = intel_gt_pm_get(gt); /* Boost gpufreq to max [waitboost] and keep it fixed */ atomic_inc(>->rps.num_waiters); queue_work(gt->i915->unordered_wq, >->rps.work); flush_work(>->rps.work); + + return wakeref; } -static int perf_end(struct intel_gt *gt) +static int perf_end(struct intel_gt *gt, intel_wakeref_t wakeref) { atomic_dec(>->rps.num_waiters); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return igt_flush_test(gt->i915); } @@ -133,12 +135,13 @@ static int perf_mi_bb_start(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - perf_begin(gt); + wakeref = perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce = engine->kernel_context; struct i915_vma *batch; @@ -207,7 +210,7 @@ static int perf_mi_bb_start(void *arg) pr_info("%s: MI_BB_START cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err = -EIO; return err; @@ -260,12 +263,13 @@ static int perf_mi_noop(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - perf_begin(gt); + wakeref = perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce = engine->kernel_context; struct i915_vma *base, *nop; @@ -364,7 +368,7 @@ static int perf_mi_noop(void *arg) pr_info("%s: 16K MI_NOOP cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err = -EIO; return err; diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c index 0971241707ce..33351deeea4f 100644 --- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c @@ -81,6 +81,7 @@ static int live_gt_clocks(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (!gt->clock_frequency) { /* unknown */ @@ -91,7 +92,7 @@ static int live_gt_clocks(void *arg) if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); for_each_engine(engine, gt, id) { @@ -128,7 +129,7 @@ static int live_gt_clocks(void *arg) } intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c index 79aa6ac66ad2..f40de408cd3a 100644 --- a/drivers/gpu/drm/i915/gt/selftest_reset.c +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c @@ -261,11 +261,12 @@ static int igt_atomic_reset(void *arg) { struct intel_gt *gt = arg; const typeof(*igt_atomic_phases) *p; + intel_wakeref_t wakeref; int err = 0; /* Check that the resets are usable from atomic context */ - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); igt_global_reset_lock(gt); /* Flush any requests before we get started and check basics */ @@ -296,7 +297,7 @@ static int igt_atomic_reset(void *arg) unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } @@ -307,6 +308,7 @@ static int igt_atomic_engine_reset(void *arg) const typeof(*igt_atomic_phases) *p; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; /* Check that the resets are usable from atomic context */ @@ -317,7 +319,7 @@ static int igt_atomic_engine_reset(void *arg) if (intel_uc_uses_guc_submission(>->uc)) return 0; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); igt_global_reset_lock(gt); /* Flush any requests before we get started and check basics */ @@ -365,7 +367,7 @@ static int igt_atomic_engine_reset(void *arg) out_unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c index fb30f733b036..dcef8d498919 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -224,6 +224,7 @@ int live_rps_clock_interval(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err = 0; if (!intel_rps_is_enabled(rps) || GRAPHICS_VER(gt->i915) < 6) @@ -236,7 +237,7 @@ int live_rps_clock_interval(void *arg) saved_work = rps->work.func; rps->work.func = dummy_rps_work; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_rps_disable(>->rps); intel_gt_check_clock_frequency(gt); @@ -355,7 +356,7 @@ int live_rps_clock_interval(void *arg) } intel_rps_enable(>->rps); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); @@ -376,6 +377,7 @@ int live_rps_control(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err = 0; /* @@ -398,7 +400,7 @@ int live_rps_control(void *arg) saved_work = rps->work.func; rps->work.func = dummy_rps_work; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; ktime_t min_dt, max_dt; @@ -488,7 +490,7 @@ int live_rps_control(void *arg) break; } } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); @@ -1023,6 +1025,7 @@ int live_rps_interrupt(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; u32 pm_events; int err = 0; @@ -1033,9 +1036,9 @@ int live_rps_interrupt(void *arg) if (!intel_rps_has_interrupts(rps) || GRAPHICS_VER(gt->i915) < 6) return 0; - intel_gt_pm_get(gt); - pm_events = rps->pm_events; - intel_gt_pm_put(gt); + pm_events = 0; + with_intel_gt_pm(gt, wakeref) + pm_events = rps->pm_events; if (!pm_events) { pr_err("No RPS PM events registered, but RPS is enabled?\n"); return -ENODEV; diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c index 952c8d52d68a..302d0540295d 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -266,6 +266,7 @@ static int run_test(struct intel_gt *gt, int test_type) struct intel_rps *rps = >->rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; u32 slpc_min_freq, slpc_max_freq; int err = 0; @@ -311,7 +312,7 @@ static int run_test(struct intel_gt *gt, int test_type) } intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 max_act_freq; @@ -397,7 +398,7 @@ static int run_test(struct intel_gt *gt, int test_type) if (igt_flush_test(gt->i915)) err = -EIO; - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index d37698bd6b91..04f8377fd7a3 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1107,7 +1107,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc) if (deregister) guc_signal_context_fence(ce); if (destroyed) { - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } @@ -1303,6 +1303,7 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) unsigned long flags; u32 reset_count; bool in_reset; + intel_wakeref_t wakeref; spin_lock_irqsave(&guc->timestamp.lock, flags); @@ -1325,7 +1326,8 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) * start_gt_clk is derived from GuC state. To get a consistent * view of activity, we query the GuC state only if gt is awake. */ - if (!in_reset && intel_gt_pm_get_if_awake(gt)) { + wakeref = in_reset ? 0 : intel_gt_pm_get_if_awake(gt); + if (wakeref) { stats_saved = *stats; gt_stamp_saved = guc->timestamp.gt_stamp; /* @@ -1334,7 +1336,7 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) */ guc_update_engine_gt_clks(engine); guc_update_pm_timestamp(guc, now); - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); if (i915_reset_count(gpu_error) != reset_count) { *stats = stats_saved; guc->timestamp.gt_stamp = gt_stamp_saved; @@ -3385,9 +3387,9 @@ static void destroyed_worker_func(struct work_struct *w) struct intel_guc *guc = container_of(w, struct intel_guc, submission_state.destroyed_worker); struct intel_gt *gt = guc_to_gt(guc); - int tmp; + intel_wakeref_t wakeref; - with_intel_gt_pm(gt, tmp) + with_intel_gt_pm(gt, wakeref) deregister_destroyed_contexts(guc); } @@ -4894,7 +4896,7 @@ int intel_guc_deregister_done_process_msg(struct intel_guc *guc, intel_context_put(ce); } else if (context_destroyed(ce)) { /* Context has been destroyed */ - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 878a27e1c8ef..21eb0c5b320d 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -223,19 +223,19 @@ static u64 get_rc6(struct intel_gt *gt) struct drm_i915_private *i915 = gt->i915; const unsigned int gt_id = gt->info.id; struct i915_pmu *pmu = &i915->pmu; + intel_wakeref_t wakeref; unsigned long flags; - bool awake = false; u64 val; - if (intel_gt_pm_get_if_awake(gt)) { + wakeref = intel_gt_pm_get_if_awake(gt); + if (wakeref) { val = __get_rc6(gt); - intel_gt_pm_put_async(gt); - awake = true; + intel_gt_pm_put_async(gt, wakeref); } spin_lock_irqsave(&pmu->lock, flags); - if (awake) { + if (wakeref) { store_sample(pmu, gt_id, __I915_SAMPLE_RC6, val); } else { /* @@ -439,12 +439,14 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) const unsigned int gt_id = gt->info.id; struct i915_pmu *pmu = &i915->pmu; struct intel_rps *rps = >->rps; + intel_wakeref_t wakeref; if (!frequency_sampling_enabled(pmu, gt_id)) return; /* Report 0/0 (actual/requested) frequency while parked. */ - if (!intel_gt_pm_get_if_awake(gt)) + wakeref = intel_gt_pm_get_if_awake(gt); + if (!wakeref) return; if (pmu->enable & config_mask(__I915_PMU_ACTUAL_FREQUENCY(gt_id))) { @@ -473,7 +475,7 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) period_ns / 1000); } - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); } static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 2401b88b55a4..dea2f63184f8 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -99,7 +99,8 @@ static void __intel_wakeref_put_work(struct work_struct *wrk) void __intel_wakeref_init(struct intel_wakeref *wf, struct drm_i915_private *i915, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key) + struct intel_wakeref_lockclass *key, + const char *name) { wf->i915 = i915; wf->ops = ops; @@ -111,6 +112,10 @@ void __intel_wakeref_init(struct intel_wakeref *wf, INIT_DELAYED_WORK(&wf->work, __intel_wakeref_put_work); lockdep_init_map(&wf->work.work.lockdep_map, "wakeref.work", &key->work, 0); + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name); +#endif } int intel_wakeref_wait_for_idle(struct intel_wakeref *wf) diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h index 909cad13ac1f..68aa3be48251 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -50,6 +50,10 @@ struct intel_wakeref { const struct intel_wakeref_ops *ops; struct delayed_work work; + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + struct ref_tracker_dir debug; +#endif }; struct intel_wakeref_lockclass { @@ -60,11 +64,12 @@ struct intel_wakeref_lockclass { void __intel_wakeref_init(struct intel_wakeref *wf, struct drm_i915_private *i915, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key); -#define intel_wakeref_init(wf, i915, ops) do { \ + struct intel_wakeref_lockclass *key, + const char *name); +#define intel_wakeref_init(wf, i915, ops, name) do { \ static struct intel_wakeref_lockclass __key; \ \ - __intel_wakeref_init((wf), (i915), (ops), &__key); \ + __intel_wakeref_init((wf), (i915), (ops), &__key, name); \ } while (0) int __intel_wakeref_get_first(struct intel_wakeref *wf); @@ -292,6 +297,33 @@ static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, void intel_ref_tracker_show(struct ref_tracker_dir *dir, struct drm_printer *p); +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return intel_ref_tracker_alloc(&wf->debug); +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ + intel_ref_tracker_free(&wf->debug, handle); +} + +#else + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return -1; +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ +} + +#endif + struct intel_wakeref_auto { struct drm_i915_private *i915; struct timer_list timer; From 5a77457232fa0453da4d3d5a7d530129944aeeb5 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 2 Nov 2023 20:03:10 +0100 Subject: [PATCH 0975/7721] ALSA: wavefront: copy userspace array safely wavefront_fx.c utilizes memdup_user() to copy a userspace array. This does not check for an overflow. Use the new wrapper memdup_array_user() to copy the array more safely. Suggested-by: Dave Airlie Signed-off-by: Philipp Stanner Link: https://lore.kernel.org/r/20231102190309.50891-2-pstanner@redhat.com Signed-off-by: Takashi Iwai --- sound/isa/wavefront/wavefront_fx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 3c21324b2a0e..0273b7dfaf12 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -191,9 +191,9 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, "> 512 bytes to FX\n"); return -EIO; } - page_data = memdup_user((unsigned char __user *) - r.data[3], - r.data[2] * sizeof(short)); + page_data = memdup_array_user((unsigned char __user *) + r.data[3], + r.data[2], sizeof(short)); if (IS_ERR(page_data)) return PTR_ERR(page_data); pd = page_data; From cac15dc25f416972f8dd0b6a8d74daa79dc3a998 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sun, 19 Nov 2023 10:45:14 +0000 Subject: [PATCH 0976/7721] ASoC: fsl_mqs: Remove duplicate linux/of.h header Remove linux/of.h as is included more than once. Reported by make includecheck. Signed-off-by: Lucas Tanure Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20231119104514.25536-1-tanure@linux.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index f2d74ec05cdf..86704ba5f6f0 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include From d652049e118ffe9227155f7b9b85faf15fc91f8f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 15 Nov 2023 17:29:01 +0100 Subject: [PATCH 0977/7721] gpio: mockup: initialize a managed pointer in place The preferred pattern for autopointers is to initialize them when they're declared unless it doesn't make sense. Move the declaration of the managed device pointer to where it's initialized. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mockup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 4870e267a402..455eecf6380e 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -354,7 +354,6 @@ static const struct file_operations gpio_mockup_debugfs_ops = { static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { - struct device *child __free(put_device) = NULL; struct gpio_mockup_dbgfs_private *priv; struct gpio_chip *gc; const char *devname; @@ -367,7 +366,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev, * There can only be a single GPIO device per platform device in * gpio-mockup so using device_find_any_child() is OK. */ - child = device_find_any_child(dev); + struct device *child __free(put_device) = device_find_any_child(dev); if (!child) return; From fcd479a79120bf0cd507d85f898297a3b868dda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 14 Nov 2023 16:23:33 +0200 Subject: [PATCH 0978/7721] drm/i915: Also check for VGA converter in eDP probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately even the HPD based detection added in commit cfe5bdfb27fa ("drm/i915: Check HPD live state during eDP probe") fails to detect that the VBT's eDP/DDI-A is a ghost on Asus B360M-A (CFL+CNP). On that board eDP/DDI-A has its HPD asserted despite nothing being actually connected there :( The straps/fuses also indicate that the eDP port is present. So if one boots with a VGA monitor connected the eDP probe will mistake the DP->VGA converter hooked to DDI-E for an eDP panel on DDI-A. As a last resort check what kind of DP device we've detected, and if it looks like a DP->VGA converter then conclude that the eDP port should be ignored. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9636 Fixes: cfe5bdfb27fa ("drm/i915: Check HPD live state during eDP probe") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231114142333.15799-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index effb3da291e1..3867a0d9e004 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6270,8 +6270,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, * (eg. Acer Chromebook C710), so we'll check it only if multiple * ports are attempting to use the same AUX CH, according to VBT. */ - if (intel_bios_dp_has_shared_aux_ch(encoder->devdata) && - !intel_digital_port_connected(encoder)) { + if (intel_bios_dp_has_shared_aux_ch(encoder->devdata)) { /* * If this fails, presume the DPCD answer came * from some other port using the same AUX CH. @@ -6279,10 +6278,27 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, * FIXME maybe cleaner to check this before the * DPCD read? Would need sort out the VDD handling... */ - drm_info(&dev_priv->drm, - "[ENCODER:%d:%s] HPD is down, disabling eDP\n", - encoder->base.base.id, encoder->base.name); - goto out_vdd_off; + if (!intel_digital_port_connected(encoder)) { + drm_info(&dev_priv->drm, + "[ENCODER:%d:%s] HPD is down, disabling eDP\n", + encoder->base.base.id, encoder->base.name); + goto out_vdd_off; + } + + /* + * Unfortunately even the HPD based detection fails on + * eg. Asus B360M-A (CFL+CNP), so as a last resort fall + * back to checking for a VGA branch device. Only do this + * on known affected platforms to minimize false positives. + */ + if (DISPLAY_VER(dev_priv) == 9 && drm_dp_is_branch(intel_dp->dpcd) && + (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) == + DP_DWN_STRM_PORT_TYPE_ANALOG) { + drm_info(&dev_priv->drm, + "[ENCODER:%d:%s] VGA converter detected, disabling eDP\n", + encoder->base.base.id, encoder->base.name); + goto out_vdd_off; + } } mutex_lock(&dev_priv->drm.mode_config.mutex); From 7521c8a657ba5c48ccd39cde7102a001fb0d9c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Nov 2023 19:18:31 +0200 Subject: [PATCH 0979/7721] drm/i915/fbc: Split plane size vs. surface size checks apart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do separate checks for the visible plane size vs. the surface size (which I take to mean offset+size). For now both use the same max w/h, but we can relax the surface size limits as a followup. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231117171833.25816-1-ville.syrjala@linux.intel.com Reviewed-by: Juha-Pekka Heikkila --- drivers/gpu/drm/i915/display/intel_fbc.c | 32 +++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index b73cf1c5ba33..fe21371db38c 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1050,6 +1050,31 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * return effective_w <= max_w && effective_h <= max_h; } +static bool intel_fbc_plane_size_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + unsigned int w, h, max_w, max_h; + + if (DISPLAY_VER(i915) >= 10) { + max_w = 5120; + max_h = 4096; + } else if (DISPLAY_VER(i915) >= 8 || IS_HASWELL(i915)) { + max_w = 4096; + max_h = 4096; + } else if (IS_G4X(i915) || DISPLAY_VER(i915) >= 5) { + max_w = 4096; + max_h = 2048; + } else { + max_w = 2048; + max_h = 1536; + } + + w = drm_rect_width(&plane_state->uapi.src) >> 16; + h = drm_rect_height(&plane_state->uapi.src) >> 16; + + return w <= max_w && h <= max_h; +} + static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -1247,11 +1272,16 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (!intel_fbc_hw_tracking_covers_screen(plane_state)) { + if (!intel_fbc_plane_size_valid(plane_state)) { plane_state->no_fbc_reason = "plane size too big"; return 0; } + if (!intel_fbc_hw_tracking_covers_screen(plane_state)) { + plane_state->no_fbc_reason = "surface size too big"; + return 0; + } + /* * Work around a problem on GEN9+ HW, where enabling FBC on a plane * having a Y offset that isn't divisible by 4 causes FIFO underrun From 5c38280cb73ef351c4f92ea06e0fa65847f87185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Nov 2023 19:18:32 +0200 Subject: [PATCH 0980/7721] drm/i915/fbc: Bump max surface size to 8kx4k on icl+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FBC on icl+ should supposedly be fine with surface sizes up to 8kx4k. Bump up the limit. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231117171833.25816-2-ville.syrjala@linux.intel.com Reviewed-by: Juha-Pekka Heikkila --- drivers/gpu/drm/i915/display/intel_fbc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index fe21371db38c..0ac222eaddd2 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1028,7 +1028,10 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); unsigned int effective_w, effective_h, max_w, max_h; - if (DISPLAY_VER(i915) >= 10) { + if (DISPLAY_VER(i915) >= 11) { + max_w = 8192; + max_h = 4096; + } else if (DISPLAY_VER(i915) >= 10) { max_w = 5120; max_h = 4096; } else if (DISPLAY_VER(i915) >= 8 || IS_HASWELL(i915)) { From f1dfb517cc5731b10aab3309629bfe80596a0d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Nov 2023 19:18:33 +0200 Subject: [PATCH 0981/7721] drm/i915/fbc: Bump ivb FBC max surface size to 4kx4k MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IVB Bspec says: "Frame Buffer Compression is only supported with memory surfaces of 4096 lines or less and pipe source sizes of 4096 pixels by 2048 lines or less. " so seems like we should be able to bump the offset+size limit to at least 4kx4k. Make it so. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231117171833.25816-3-ville.syrjala@linux.intel.com Reviewed-by: Juha-Pekka Heikkila --- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 0ac222eaddd2..63f389a1707d 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1034,7 +1034,7 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * } else if (DISPLAY_VER(i915) >= 10) { max_w = 5120; max_h = 4096; - } else if (DISPLAY_VER(i915) >= 8 || IS_HASWELL(i915)) { + } else if (DISPLAY_VER(i915) >= 7) { max_w = 4096; max_h = 4096; } else if (IS_G4X(i915) || DISPLAY_VER(i915) >= 5) { From 2c3ef4f89ced1a9d3a6fd4f6457be5c440c89362 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Mon, 20 Nov 2023 15:43:34 +0200 Subject: [PATCH 0982/7721] ovl: initialize ovl_copy_up_ctx.destname inside ovl_do_copy_up() The ->destname member of struct ovl_copy_up_ctx is initialized inside ovl_copy_up_one() to ->d_name of the overlayfs dentry being copied up and then it may be overridden by index name inside ovl_do_copy_up(). ovl_inode_lock() in ovl_copy_up_start() and ovl_copy_up() in ovl_rename() effectively stabilze ->d_name of the overlayfs dentry being copied up, but ovl_inode_lock() is not held when ->d_name is being read. It is not a correctness bug, because if ovl_do_copy_up() races with ovl_rename() and ctx.destname is freed, we will not end up calling ovl_do_copy_up() with the dead name reference. The code becomes much easier to understand and to document if the initialization of c->destname is always done inside ovl_do_copy_up(), either to the index entry name, or to the overlay dentry ->d_name. Signed-off-by: Amir Goldstein --- fs/overlayfs/copy_up.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 4382881b0709..500c555792ff 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -929,6 +929,13 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) err = -EIO; goto out_free_fh; } else { + /* + * c->dentry->d_name is stabilzed by ovl_copy_up_start(), + * because if we got here, it means that c->dentry has no upper + * alias and changing ->d_name means going through ovl_rename() + * that will call ovl_copy_up() on source and target dentry. + */ + c->destname = c->dentry->d_name; /* * Mark parent "impure" because it may now contain non-pure * upper @@ -1109,7 +1116,6 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, if (parent) { ovl_path_upper(parent, &parentpath); ctx.destdir = parentpath.dentry; - ctx.destname = dentry->d_name; err = vfs_getattr(&parentpath, &ctx.pstat, STATX_ATIME | STATX_MTIME, From 213615d742f0c039ab73f8946ae18000cf2c7b65 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:34 -0600 Subject: [PATCH 0983/7721] dt-bindings: arm: rockchip: Add Powkiddy RK2023 The Powkiddy RK2023 is a handheld gaming device made by Powkiddy and powered by the Rockchip RK3566 SoC. Group the Powkiddy RK3566 based devices together as they are both extremely similar. Signed-off-by: Chris Morgan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231117202536.1387815-5-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 5f7c6c4aad8f..5b015c4ed775 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -674,9 +674,11 @@ properties: - const: pine64,soquartz - const: rockchip,rk3566 - - description: Powkiddy RGB30 + - description: Powkiddy RK3566 Handheld Gaming Console items: - - const: powkiddy,rgb30 + - enum: + - powkiddy,rgb30 + - powkiddy,rk2023 - const: rockchip,rk3566 - description: Radxa Compute Module 3(CM3) From 46d84ceb7eec85b60e8a5eb0dfb2fae6a1bf4166 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:35 -0600 Subject: [PATCH 0984/7721] arm64: dts: rockchip: Update powkiddy,rgb30 include to rk2023 DTSI The Powkiddy RGB30 device is similar to the Anbernic RGxx3 series, however there are several differences which require deleting nodes in order to properly define the hardware. This was deemed unacceptable for the RK2023, so instead create a common include file for the Powkiddy RGB30 and the Powkiddy RK2023. The only notable difference between these Powkiddy devices are the panel in use, the device name, and the PLL_VPLL frequency necessary to support the different panels. Since the RK2023 was released on the market first, name the common include file after it. Signed-off-by: Chris Morgan Link: https://lore.kernel.org/r/20231117202536.1387815-6-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- .../dts/rockchip/rk3566-powkiddy-rgb30.dts | 152 +-- .../dts/rockchip/rk3566-powkiddy-rk2023.dtsi | 875 ++++++++++++++++++ 2 files changed, 890 insertions(+), 137 deletions(-) create mode 100644 arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts index 1ead3c5c24b3..0ac64f043b80 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts @@ -5,67 +5,11 @@ #include #include #include -#include "rk3566-anbernic-rg353x.dtsi" +#include "rk3566-powkiddy-rk2023.dtsi" / { model = "RGB30"; compatible = "powkiddy,rgb30", "rockchip,rk3566"; - - aliases { - mmc1 = &sdmmc0; - mmc2 = &sdmmc1; - mmc3 = &sdmmc2; - }; - - battery: battery { - compatible = "simple-battery"; - charge-full-design-microamp-hours = <3151000>; - charge-term-current-microamp = <300000>; - constant-charge-current-max-microamp = <2000000>; - constant-charge-voltage-max-microvolt = <4250000>; - factory-internal-resistance-micro-ohms = <117000>; - voltage-max-design-microvolt = <4172000>; - voltage-min-design-microvolt = <3400000>; - - ocv-capacity-celsius = <20>; - ocv-capacity-table-0 = <4172000 100>, <4092000 95>, <4035000 90>, <3990000 85>, - <3939000 80>, <3895000 75>, <3852000 70>, <3807000 65>, - <3762000 60>, <3713000 55>, <3672000 50>, <3647000 45>, - <3629000 40>, <3613000 35>, <3598000 30>, <3578000 25>, - <3550000 20>, <3519000 15>, <3479000 10>, <3438000 5>, - <3400000 0>; - }; - - /* - * Channels reversed for speakers. Headphones automatically switch via hardware when - * detected with no ability to control output in software. Headphones appear to be mono - * (each output channel receives all audio). No microphone support on 3.5mm jack. - */ - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "rk817_ext"; - simple-audio-card,format = "i2s"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,widgets = - "Headphone", "Headphones"; - simple-audio-card,routing = - "Headphones", "HPOL", - "Headphones", "HPOR"; - - simple-audio-card,codec { - sound-dai = <&rk817>; - }; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - }; -}; - -/delete-node/ &adc_keys; - -&chosen { - /delete-property/ stdout-path; }; &cru { @@ -75,87 +19,21 @@ &cru { <200000000>, <292500000>; }; -&gpio_keys_control { - button-r1 { - gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; - label = "TR"; - linux,code = ; - }; +&dsi0 { + panel: panel@0 { + compatible = "powkiddy,rgb30-panel"; + reg = <0>; + backlight = <&backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + vcc-supply = <&vcc3v3_lcd0_n>; + iovcc-supply = <&vcc3v3_lcd0_n>; - button-r2 { - gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; - label = "TR2"; - linux,code = ; - }; -}; - -/delete-node/ &{/i2c@fdd40000/regulator@40}; - -&i2c0 { - vdd_cpu: regulator@1c { - compatible = "tcs,tcs4525"; - reg = <0x1c>; - fcs,suspend-voltage-selector = <1>; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1390000>; - regulator-name = "vdd_cpu"; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc_sys>; - regulator-state-mem { - regulator-off-in-suspend; + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; }; }; }; - -/* - * Device has 2 red LEDs instead of an amber and a red. Relabel LEDs as - * red_led0 and red_led1. - */ -/delete-node/ &{/pwm-leds/led-1}; -/delete-node/ &{/pwm-leds/led-2}; - -&leds { - red_led0: led-1 { - color = ; - function = LED_FUNCTION_CHARGING; - max-brightness = <255>; - pwms = <&pwm7 0 25000 0>; - }; - - red_led1: led-2 { - color = ; - default-state = "off"; - function = LED_FUNCTION_STATUS; - max-brightness = <255>; - pwms = <&pwm0 0 25000 0>; - }; -}; - -&panel { - compatible = "powkiddy,rgb30-panel"; - vcc-supply = <&vcc3v3_lcd0_n>; - iovcc-supply = <&vcc3v3_lcd0_n>; - /delete-property/ vdd-supply; -}; - -&pwm5 { - status = "disabled"; -}; - -&rk817 { - rk817_charger: charger { - monitored-battery = <&battery>; - rockchip,resistor-sense-micro-ohms = <10000>; - rockchip,sleep-enter-current-microamp = <300000>; - rockchip,sleep-filter-current-microamp = <100000>; - }; -}; - -/* There is no UART header visible on the board for this device. */ -&uart2 { - status = "disabled"; -}; - -/delete-node/ &vibrator; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi new file mode 100644 index 000000000000..0fa8f06f94cd --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include +#include "rk3566.dtsi" + +/ { + aliases { + mmc1 = &sdmmc0; + mmc2 = &sdmmc1; + mmc3 = &sdmmc2; + }; + + adc-joystick { + compatible = "adc-joystick"; + io-channels = <&adc_mux 0>, + <&adc_mux 1>, + <&adc_mux 2>, + <&adc_mux 3>; + pinctrl-0 = <&joy_mux_en>; + pinctrl-names = "default"; + poll-interval = <60>; + #address-cells = <1>; + #size-cells = <0>; + + axis@0 { + reg = <0>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <1023 15>; + linux,code = ; + }; + + axis@1 { + reg = <1>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@2 { + reg = <2>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@3 { + reg = <3>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <1023 15>; + linux,code = ; + }; + }; + + adc_mux: adc-mux { + compatible = "io-channel-mux"; + channels = "left_x", "right_x", "left_y", "right_y"; + #io-channel-cells = <1>; + io-channels = <&saradc 3>; + io-channel-names = "parent"; + mux-controls = <&gpio_mux>; + settle-time-us = <100>; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc_sys>; + pwms = <&pwm4 0 25000 0>; + }; + + battery: battery { + compatible = "simple-battery"; + charge-full-design-microamp-hours = <3151000>; + charge-term-current-microamp = <300000>; + constant-charge-current-max-microamp = <2000000>; + constant-charge-voltage-max-microvolt = <4250000>; + factory-internal-resistance-micro-ohms = <117000>; + voltage-max-design-microvolt = <4172000>; + voltage-min-design-microvolt = <3400000>; + + ocv-capacity-celsius = <20>; + ocv-capacity-table-0 = <4172000 100>, <4092000 95>, <4035000 90>, <3990000 85>, + <3939000 80>, <3895000 75>, <3852000 70>, <3807000 65>, + <3762000 60>, <3713000 55>, <3672000 50>, <3647000 45>, + <3629000 40>, <3613000 35>, <3598000 30>, <3578000 25>, + <3550000 20>, <3519000 15>, <3479000 10>, <3438000 5>, + <3400000 0>; + }; + + gpio_keys_control: gpio-keys-control { + compatible = "gpio-keys"; + pinctrl-0 = <&btn_pins_ctrl>; + pinctrl-names = "default"; + + button-a { + gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>; + label = "EAST"; + linux,code = ; + }; + + button-b { + gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>; + label = "SOUTH"; + linux,code = ; + }; + + button-down { + gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>; + label = "DPAD-DOWN"; + linux,code = ; + }; + + button-l1 { + gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>; + label = "TL"; + linux,code = ; + }; + + button-l2 { + gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>; + label = "TL2"; + linux,code = ; + }; + + button-left { + gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; + label = "DPAD-LEFT"; + linux,code = ; + }; + + button-r1 { + gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; + label = "TR"; + linux,code = ; + }; + + button-r2 { + gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; + label = "TR2"; + linux,code = ; + }; + + button-right { + gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>; + label = "DPAD-RIGHT"; + linux,code = ; + }; + + button-select { + gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>; + label = "SELECT"; + linux,code = ; + }; + + button-start { + gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>; + label = "START"; + linux,code = ; + }; + + button-thumbl { + gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; + label = "THUMBL"; + linux,code = ; + }; + + button-thumbr { + gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>; + label = "THUMBR"; + linux,code = ; + }; + + button-up { + gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>; + label = "DPAD-UP"; + linux,code = ; + }; + + button-x { + gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>; + label = "NORTH"; + linux,code = ; + }; + + button-y { + gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>; + label = "WEST"; + linux,code = ; + }; + }; + + gpio_keys_vol: gpio-keys-vol { + compatible = "gpio-keys"; + autorepeat; + pinctrl-0 = <&btn_pins_vol>; + pinctrl-names = "default"; + + button-vol-down { + gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>; + label = "VOLUMEDOWN"; + linux,code = ; + }; + + button-vol-up { + gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>; + label = "VOLUMEUP"; + linux,code = ; + }; + }; + + gpio_mux: mux-controller { + compatible = "gpio-mux"; + mux-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>, + <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>; + #mux-control-cells = <0>; + }; + + hdmi-con { + compatible = "hdmi-connector"; + ddc-i2c-bus = <&i2c5>; + type = "c"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + /* + * Device also includes an always on LED that is wired to the 5V input + * voltage and is on when the device is plugged in. + */ + leds: pwm-leds { + compatible = "pwm-leds"; + + green_led: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + max-brightness = <255>; + pwms = <&pwm6 0 25000 0>; + }; + + red_led: led-1 { + color = ; + function = LED_FUNCTION_CHARGING; + max-brightness = <255>; + pwms = <&pwm7 0 25000 0>; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + pinctrl-0 = <&wifi_enable_h>; + pinctrl-names = "default"; + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_LOW>; + }; + + /* + * Channels reversed for speakers. Headphones automatically switch via hardware when + * detected with no ability to control output in software. Headphones appear to be mono + * (each output channel receives all audio). No microphone support on 3.5mm jack. + */ + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "rk817_ext"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,widgets = + "Headphone", "Headphones"; + simple-audio-card,routing = + "Headphones", "HPOL", + "Headphones", "HPOR"; + + simple-audio-card,codec { + sound-dai = <&rk817>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1_8ch>; + }; + }; + + vcc3v3_lcd0_n: regulator-vcc3v3-lcd0 { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&vcc_lcd_h>; + pinctrl-names = "default"; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_lcd0_n"; + vin-supply = <&vcc_3v3>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + regulator-name = "vcc_sys"; + }; + + vcc_wifi: regulator-vcc-wifi { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&vcc_wifi_h>; + pinctrl-names = "default"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_wifi"; + }; +}; + +&combphy1 { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu1 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu2 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu3 { + cpu-supply = <&vdd_cpu>; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + dsi0_in: port@0 { + reg = <0>; + dsi0_in_vp1: endpoint { + remote-endpoint = <&vp1_out_dsi0>; + }; + }; + + dsi0_out: port@1 { + reg = <1>; + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; +}; + +&dsi_dphy0 { + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&hdmi { + ddc-i2c-bus = <&i2c5>; + pinctrl-0 = <&hdmitxm0_cec>; + pinctrl-names = "default"; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = ; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + clock-names = "mclk"; + clocks = <&cru I2S1_MCLKOUT_TX>; + assigned-clocks = <&cru I2S1_MCLKOUT_TX>; + assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>; + #clock-cells = <1>; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1m0_mclk>, <&pmic_int_l>; + wakeup-source; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&dcdc_boost>; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_gpu"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_ddr"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_3v3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_pmu: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_0v9: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda_0v9"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda0v9_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_acodec"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_1v8: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_dvp: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc1v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc2v8_dvp: LDO_REG9 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc2v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + dcdc_boost: BOOST { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <5400000>; + regulator-name = "boost"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + rk817_charger: charger { + monitored-battery = <&battery>; + rockchip,resistor-sense-micro-ohms = <10000>; + rockchip,sleep-enter-current-microamp = <300000>; + rockchip,sleep-filter-current-microamp = <100000>; + }; + }; + + vdd_cpu: regulator@1c { + compatible = "tcs,tcs4525"; + reg = <0x1c>; + fcs,suspend-voltage-selector = <1>; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1390000>; + regulator-name = "vdd_cpu"; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c5 { + pinctrl-0 = <&i2c5m1_xfer>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2s0_8ch { + status = "okay"; +}; + +&i2s1_8ch { + pinctrl-0 = <&i2s1m0_sclktx + &i2s1m0_lrcktx + &i2s1m0_sdi0 + &i2s1m0_sdo0>; + pinctrl-names = "default"; + rockchip,trcm-sync-tx-only; + status = "okay"; +}; + +&pinctrl { + gpio-btns { + btn_pins_ctrl: btn-pins-ctrl { + rockchip,pins = + <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + btn_pins_vol: btn-pins-vol { + rockchip,pins = + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + joy-mux { + joy_mux_en: joy-mux-en { + rockchip,pins = + <0 RK_PB5 RK_FUNC_GPIO &pcfg_output_low>; + }; + }; + + gpio-lcd { + lcd_rst: lcd-rst { + rockchip,pins = + <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = + <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = + <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + vcc3v3-lcd { + vcc_lcd_h: vcc-lcd-h { + rockchip,pins = + <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + vcc-wifi { + vcc_wifi_h: vcc-wifi-h { + rockchip,pins = + <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + status = "okay"; + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcc3v3_pmu>; + vccio1-supply = <&vccio_acodec>; + vccio3-supply = <&vccio_sd>; + vccio4-supply = <&vcc_1v8>; + vccio5-supply = <&vcc_3v3>; + vccio6-supply = <&vcc1v8_dvp>; + vccio7-supply = <&vcc_3v3>; +}; + +&pwm4 { + status = "okay"; +}; + +&pwm6 { + status = "okay"; +}; + +&pwm7 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdmmc0 { + bus-width = <4>; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&sdmmc1 { + bus-width = <4>; + cap-sd-highspeed; + cd-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_LOW>; + disable-wp; + pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk &sdmmc1_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vcc1v8_dvp>; + status = "okay"; +}; + +&sdmmc2 { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-0 = <&sdmmc2m0_bus4 &sdmmc2m0_cmd &sdmmc2m0_clk>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_wifi>; + vqmmc-supply = <&vcca1v8_pmu>; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&uart1 { + pinctrl-0 = <&uart1m1_xfer &uart1m1_ctsn &uart1m1_rtsn>; + pinctrl-names = "default"; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8821cs-bt", "realtek,rtl8723bs-bt"; + device-wake-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + host-wake-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&usb_host0_xhci { + dr_mode = "peripheral"; + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host1_xhci { + phy-names = "usb2-phy", "usb3-phy"; + phys = <&usb2phy1_host>, <&combphy1 PHY_TYPE_USB3>; + status = "okay"; +}; + +&usb2phy0 { + status = "okay"; +}; + +&usb2phy0_otg { + status = "okay"; +}; + +&usb2phy1 { + status = "okay"; +}; + +&usb2phy1_host { + status = "okay"; +}; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi_in_vp0>; + }; +}; + +&vp1 { + vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 { + reg = ; + remote-endpoint = <&dsi0_in_vp1>; + }; +}; From e926380ea2a2b10d01069917e6d678ca818f6ad8 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 17 Nov 2023 14:25:36 -0600 Subject: [PATCH 0985/7721] arm64: dts: rockchip: Add Powkiddy RK2023 Add support for the Powkiddy RK2023. The Powkiddy RK2023 is a handheld gaming device with a 3.5 inch screen powered by the Rockchip RK3566 SoC. The device looks physically different from the Powkiddy RGB30, but is functionally identical except for the panel. Signed-off-by: Chris Morgan Link: https://lore.kernel.org/r/20231117202536.1387815-7-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../dts/rockchip/rk3566-powkiddy-rk2023.dts | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index a18f33bf0c0e..f969618da352 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -78,6 +78,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg503.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb30.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rk2023.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-a.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-radxa-cm3-io.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts new file mode 100644 index 000000000000..ba32d0793dca --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include "rk3566-powkiddy-rk2023.dtsi" + +/ { + model = "RK2023"; + compatible = "powkiddy,rk2023", "rockchip,rk3566"; +}; + +&cru { + assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, + <&pmucru PLL_PPLL>, <&cru PLL_VPLL>; + assigned-clock-rates = <32768>, <1200000000>, + <200000000>, <115200000>; +}; + +&dsi0 { + panel: panel@0 { + compatible = "powkiddy,rk2023-panel", "newvision,nv3051d"; + reg = <0>; + backlight = <&backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + vdd-supply = <&vcc3v3_lcd0_n>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; +}; From e5fc1f038355634087f6a178454341dcfd50b89b Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 14:03:51 +0100 Subject: [PATCH 0986/7721] dt-bindings: arm: rockchip: Add Geniatech XPI-3128 Add Geniatech XPI-3128, a RK3128 based single board computer. Signed-off-by: Alex Bee Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231119130351.112261-4-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 5f7c6c4aad8f..d3c5b25fc2fd 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -237,6 +237,11 @@ properties: - const: geekbuying,geekbox - const: rockchip,rk3368 + - description: Geniatech XPI-3128 + items: + - const: geniatech,xpi-3128 + - const: rockchip,rk3128 + - description: Google Bob (Asus Chromebook Flip C101PA) items: - const: google,bob-rev13 From cdc86eeebbd26c60bcee1c81598ecf684852a733 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 14:03:53 +0100 Subject: [PATCH 0987/7721] ARM: dts: rockchip: Add sdmmc_det pinctrl for RK3128 The pincontrol for sd card detection is currently missing. Add it. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231119130351.112261-6-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 7bf557c99561..797906ba321d 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -843,6 +843,10 @@ sdmmc_cmd: sdmmc-cmd { rockchip,pins = <1 RK_PB7 1 &pcfg_pull_default>; }; + sdmmc_det: sdmmc-det { + rockchip,pins = <1 RK_PC1 1 &pcfg_pull_default>; + }; + sdmmc_wp: sdmmc-wp { rockchip,pins = <1 RK_PA7 1 &pcfg_pull_default>; }; From 6135ac43309f5ef91ad60c688931027226779fed Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 14:03:55 +0100 Subject: [PATCH 0988/7721] ARM: dts: rockchip: Add Geniatech XPI-3128 RK3128 board XPI-3128 is RK3128 based SBC form Geniatec in RPi form factor Specs: - Rockchip RK3128 - 512MB/1 GB DDR3 DRAM - 8/16 GB eMMC - TF card slot - 100 MBit ethernet / RJ45 (TI DP83848C phy) - optional Marvell 88W8897 (USB version) - 3 x USB host (onboard GL852G hub connected to SoC ehci host) - 1 x USB otg - 1 x Type-C (solely for powering the board) - HDMI 1.4 out - ADC button - IR receiver - Artasie AM1805 RTC - 40 pin header Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231119130351.112261-8-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/Makefile | 1 + .../arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 397 ++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts diff --git a/arch/arm/boot/dts/rockchip/Makefile b/arch/arm/boot/dts/rockchip/Makefile index 0f46e18fe275..58868cf0510b 100644 --- a/arch/arm/boot/dts/rockchip/Makefile +++ b/arch/arm/boot/dts/rockchip/Makefile @@ -10,6 +10,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3066a-mk808.dtb \ rk3066a-rayeager.dtb \ rk3128-evb.dtb \ + rk3128-xpi-3128.dtb \ rk3188-bqedison2qc.dtb \ rk3188-px3-evb.dtb \ rk3188-radxarock.dtb \ diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts new file mode 100644 index 000000000000..61b9f069c8a2 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include "rk3128.dtsi" + +/ { + model = "Geniatech XPI-3128"; + compatible = "geniatech,xpi-3128", "rockchip,rk3128"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + mmc0 = &emmc; + mmc1 = &sdmmc; + serial0 = &uart1; + }; + + memory@60000000 { + device_type = "memory"; + reg = <0x60000000 0x40000000>; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <3300000>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <0>; + }; + }; + + dc_5v: dc-5v-regulator { + compatible = "regulator-fixed"; + regulator-name = "DC_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + /* + * This is a vbus-supply, which also supplies the GL852G usb hub, + * thus has to be always-on + */ + host_pwr_5v: host-pwr-5v-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; + startup-delay-us = <1500>; + regulator-name = "HOST_PWR_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_5v>; + pinctrl-names = "default"; + pinctrl-0 = <&host_drv>; + enable-active-high; + regulator-always-on; + }; + + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_int>; + }; + + leds { + compatible = "gpio-leds"; + + led-power { + gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_POWER; + color = ; + default-state = "on"; + pinctrl-names = "default"; + pinctrl-0 = <&power_led>; + }; + + led-spd { + gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_LAN; + color = ; + /* + * currently not allowed to be set as per + * https://www.kernel.org/doc/Documentation/devicetree/bindings/leds/common.yaml + * and needs to set in userspace: + * + * linux,default-trigger = "netdev"; + */ + pinctrl-names = "default"; + pinctrl-0 = <&spd_led>; + }; + }; + + mcu3v3: mcu3v3-regulator { + compatible = "regulator-fixed"; + regulator-name = "MCU3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_ddr: vcc-ddr-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_DDR"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_io: vcc-io-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_IO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_lan: vcc-lan-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_LAN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_sd: vcc-sd-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>; + startup-delay-us = <500>; + regulator-name = "VCC_SD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_pwren>; + }; + + vcc_sys: vcc-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_SYS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_5v>; + regulator-always-on; + regulator-boot-on; + }; + + vcc33_hdmi: vcc33-hdmi-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC33_HDMI"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcca_33>; + regulator-always-on; + regulator-boot-on; + }; + + vcca_33: vcca-33-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCCA_33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_11: vdd-11-regulator { + compatible = "regulator-fixed"; + regulator-name = "VDD_11"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vdd11_hdmi: vdd11-hdmi-regulator { + compatible = "regulator-fixed"; + regulator-name = "VDD11_HDMI"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vdd_11>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_arm: vdd-arm-regulator { + compatible = "pwm-regulator"; + regulator-name = "VDD_ARM"; + pwms = <&pwm1 0 25000 1>; + pwm-supply = <&vcc_sys>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; + + /* + * As per schematics vdd_log is minimum 900 mV, maximum 1400 mV. + * Since there are HW blocks in PD_LOGIC (which are all driven by + * this supply), that either do not have a driver at all or the + * driver does not implement regulator support we have to make + * sure here that the voltage never drops below 1050 mV. + */ + vdd_log: vdd-log-regulator { + compatible = "pwm-regulator"; + regulator-name = "VDD_LOG"; + pwms = <&pwm2 0 25000 1>; + pwm-dutycycle-range = <30 100>; + pwm-supply = <&vcc_sys>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <4000>; + regulator-always-on; + regulator-boot-on; + }; + +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&emmc { + bus-width = <8>; + vmmc-supply = <&vcc_io>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + cap-mmc-highspeed; + mmc-ddr-3_3v; + no-sd; + no-sdio; + status = "okay"; +}; + +&gpio0 { + gpio-line-names = /* GPIO0 A0-A7 */ + "", "", "HEADER_5", "HEADER_3", + "", "", "", "", + /* GPIO0 B0-B7 */ + "HEADER_22", "HEADER_23", "", "HEADER_19", + "HEADER_26", "HEADER_21", "HEADER_24", "", + /* GPIO0 C0-C7 */ + "", "HEADER_18", "", "", + "", "", "", "", + /* GPIO0 D0-D7 */ + "HEADER_36", "", "", "", + "", "", "HEADER_13", ""; +}; + +&gpio1 { + gpio-line-names = /* GPIO1 A0-A7 */ + "HEADER_7", "HEADER_35", "HEADER_33", "HEADER_37", + "HEADER_40", "HEADER_38", "", "", + /* GPIO1 B0-B7 */ + "HEADER_11", "", "", "HEADER_29", + "HEADER_31", "", "", "", + /* GPIO1 C0-C7 */ + "", "", "", "", + "", "", "", "", + /* GPIO1 D0-D7 */ + "", "", "", "", + "", "", "", ""; +}; + +&gpio2 { + gpio-line-names = /* GPIO2 A0-A7 */ + "", "", "", "", + "", "", "", "", + /* GPIO2 B0-B7 */ + "", "", "", "", + "", "", "", "", + /* GPIO2 C0-C7 */ + "", "", "", "", + "HEADER_27", "", "", "", + /* GPIO2 D0-D7 */ + "", "", "HEADER_8", "HEADER_10", + "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = /* GPIO3 A0-A7 */ + "", "", "", "", + "", "", "", "", + /* GPIO3 B0-B7 */ + "", "", "", "", + "", "", "", "", + /* GPIO3 C0-C7 */ + "", "HEADER_32", "", "", + "", "", "", "HEADER_12", + /* GPIO3 D0-D7 */ + "", "", "", "HEADER_15", + "", "", "", ""; +}; + +&pinctrl { + dp83848c { + dp83848c_rst: dp83848c-rst { + rockchip,pins = <2 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + ir-receiver { + ir_int: ir-int { + rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + power_led: power-led { + rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + spd_led: spd-led { + rockchip,pins = <3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb2 { + host_drv: host-drv { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_io>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + vmmc-supply = <&vcc_sd>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_bus4 &sdmmc_clk &sdmmc_cmd &sdmmc_det>; + disable-wp; + cap-sd-highspeed; + no-mmc; + no-sdio; + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&usb_host_ehci { + status = "okay"; +}; + +&usb_otg { + vusb_a-supply = <&vcc_io>; + vusb_d-supply = <&vdd_11>; + status = "okay"; +}; + +&usb2phy { + status = "okay"; +}; + +&usb2phy_host { + status = "okay"; +}; + +&usb2phy_otg { + status = "okay"; +}; From 759d6bd9ef94f0e658202947d44b939c6e3ed363 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 13:13:38 +0100 Subject: [PATCH 0989/7721] ARM: dts: rockchip: Add USB host clocks for RK3128 Add the required AHB clocks for both the ehci and ohci controller. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231119121340.109025-4-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 797906ba321d..a057e52a0fb5 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -163,6 +163,7 @@ usb_host_ehci: usb@101c0000 { compatible = "generic-ehci"; reg = <0x101c0000 0x20000>; interrupts = ; + clocks = <&cru HCLK_HOST2>; phys = <&usb2phy_host>; phy-names = "usb"; status = "disabled"; @@ -172,6 +173,7 @@ usb_host_ohci: usb@101e0000 { compatible = "generic-ohci"; reg = <0x101e0000 0x20000>; interrupts = ; + clocks = <&cru HCLK_HOST2>; phys = <&usb2phy_host>; phy-names = "usb"; status = "disabled"; From 4b12245e59efea81e19d1aa118f6f835b3e27b3a Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 13:13:39 +0100 Subject: [PATCH 0990/7721] ARM: dts: rockchip: Add dwc2 otg fifo siztes for RK3128 The driver currently won't probe correctly if those values are missing. They have been taken from dowstream kernel and match those of other Rockchip SoCs. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231119121340.109025-5-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index a057e52a0fb5..b5dac1322631 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -154,6 +154,9 @@ usb_otg: usb@10180000 { clocks = <&cru HCLK_OTG>; clock-names = "otg"; dr_mode = "otg"; + g-np-tx-fifo-size = <16>; + g-rx-fifo-size = <280>; + g-tx-fifo-size = <256 128 128 64 32 16>; phys = <&usb2phy_otg>; phy-names = "usb2-phy"; status = "disabled"; From fd610e604837936440ef7c64ab6998b004631647 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 19 Nov 2023 13:13:40 +0100 Subject: [PATCH 0991/7721] ARM: dts: rockchip: Make usbphy the parent of SCLK_USB480M for RK3128 Without setting the parent for SCLK_USB480M the clock will use xin24m as it's default parent. While this is generally not an issue for the usb blocks to work, it becomes an issue for RK3128 since SCLK_USB480M can be a parent for other HW blocks (GPU, VPU, VIO), but they will never chose it, since it is currently always running at OSC frequency which is to slow for their needs. This sets the usb2 phy's output as SCLK_USB480M's parent and it's users can chose it if desired. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231119121340.109025-6-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index b5dac1322631..4e8b38604ecd 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -266,6 +266,8 @@ usb2phy: usb2phy@17c { clocks = <&cru SCLK_OTGPHY0>; clock-names = "phyclk"; clock-output-names = "usb480m_phy"; + assigned-clocks = <&cru SCLK_USB480M>; + assigned-clock-parents = <&usb2phy>; #clock-cells = <0>; status = "disabled"; From a32324280474b8279ac28aee672f45de6ab755a5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 16 Nov 2023 11:14:10 -0800 Subject: [PATCH 0992/7721] dma-buf: Replace strlcpy() with strscpy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated[1]. Additionally, it returns the size of the source string, not the resulting size of the destination string. In an effort to remove strlcpy() completely[2], replace strlcpy() here with strscpy(). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1] Link: https://github.com/KSPP/linux/issues/89 [2] Cc: Sumit Semwal Cc: "Christian König" Cc: Azeem Shaikh Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Signed-off-by: Kees Cook Reviewed-by: T.J. Mercier Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20231116191409.work.634-kees@kernel.org Signed-off-by: Christian König --- drivers/dma-buf/dma-buf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 21916bba77d5..8fe5aa67b167 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -46,12 +46,12 @@ static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) { struct dma_buf *dmabuf; char name[DMA_BUF_NAME_LEN]; - size_t ret = 0; + ssize_t ret = 0; dmabuf = dentry->d_fsdata; spin_lock(&dmabuf->name_lock); if (dmabuf->name) - ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); + ret = strscpy(name, dmabuf->name, sizeof(name)); spin_unlock(&dmabuf->name_lock); return dynamic_dname(buffer, buflen, "/%s:%s", From bbd3efed3383e332191c665786c61653826d2ac3 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 13 Nov 2023 18:51:57 -0800 Subject: [PATCH 0993/7721] f2fs: skip adding a discard command if exists When recovering zoned UFS, sometimes we add the same zone to discard multiple times. Simple workaround is to bypass adding it. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 727d016318f9..f4ffd64b44b2 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1380,7 +1380,8 @@ static void __insert_discard_cmd(struct f2fs_sb_info *sbi, p = &(*p)->rb_right; leftmost = false; } else { - f2fs_bug_on(sbi, 1); + /* Let's skip to add, if exists */ + return; } } From 482543590fc9d405697b01b1b11af8a97ffd553a Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 8 Nov 2023 14:44:06 +0100 Subject: [PATCH 0994/7721] ARM: dts: stm32: use the same 3v3 for SD and DSI nodes on stm32f469-disco In the board schematic, the power supply for the SD card is the same 3.3 volts used to power the LCD panel and other peripherals. By generalizing the name of the voltage regulator, it simplifies the device tree and makes it more readable. Link: https://www.st.com/en/evaluation-tools/32f469idiscovery.html#cad-resources Signed-off-by: Dario Binacchi Signed-off-by: Alexandre Torgue --- arch/arm/boot/dts/st/stm32f469-disco.dts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/st/stm32f469-disco.dts b/arch/arm/boot/dts/st/stm32f469-disco.dts index cbbd521bf010..8a4f8ddd083d 100644 --- a/arch/arm/boot/dts/st/stm32f469-disco.dts +++ b/arch/arm/boot/dts/st/stm32f469-disco.dts @@ -69,16 +69,9 @@ aliases { serial0 = &usart3; }; - mmc_vcard: mmc_vcard { + vcc_3v3: vcc-3v3 { compatible = "regulator-fixed"; - regulator-name = "mmc_vcard"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_dsi: vdd-dsi { - compatible = "regulator-fixed"; - regulator-name = "vdd_dsi"; + regulator-name = "vcc_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; @@ -164,7 +157,7 @@ panel@0 { compatible = "orisetech,otm8009a"; reg = <0>; /* dsi virtual channel (0..3) */ reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; - power-supply = <&vdd_dsi>; + power-supply = <&vcc_3v3>; status = "okay"; port { @@ -219,7 +212,7 @@ timer@2 { &sdio { status = "okay"; - vmmc-supply = <&mmc_vcard>; + vmmc-supply = <&vcc_3v3>; cd-gpios = <&gpiog 2 GPIO_ACTIVE_LOW>; broken-cd; pinctrl-names = "default", "opendrain"; From 5fc6aa7db080fd90ef00846aac04e8a211088132 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 25 Oct 2023 21:32:46 +0000 Subject: [PATCH 0995/7721] drm/rockchip: vop2: Add NV20 and NV30 support Add support for the 10-bit 4:2:2 and 4:4:4 formats NV20 and NV30. These formats can be tested using modetest [1]: modetest -P @:1920x1080@ e.g. on a ROCK 3 Model A (rk3568): modetest -P 43@67:1920x1080@NV20 -F tiles,tiles modetest -P 43@67:1920x1080@NV30 -F smpte,smpte [1] https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/329 Signed-off-by: Jonas Karlman Reviewed-by: Christopher Obbard Tested-by: Christopher Obbard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231025213248.2641962-1-jonas@kwiboo.se --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 5 +++++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 6862fb146ace..312da5783362 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -325,11 +325,14 @@ static enum vop2_data_format vop2_convert_format(u32 format) case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: return VOP2_FMT_YUV422SP; + case DRM_FORMAT_NV20: case DRM_FORMAT_Y210: return VOP2_FMT_YUV422SP_10; case DRM_FORMAT_NV24: case DRM_FORMAT_NV42: return VOP2_FMT_YUV444SP; + case DRM_FORMAT_NV30: + return VOP2_FMT_YUV444SP_10; case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: return VOP2_FMT_VYUY422; @@ -414,6 +417,8 @@ static bool vop2_win_uv_swap(u32 format) case DRM_FORMAT_NV16: case DRM_FORMAT_NV24: case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV30: case DRM_FORMAT_YUYV: case DRM_FORMAT_UYVY: return true; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 22288ad7f326..2c45d81983a5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -48,8 +48,10 @@ static const uint32_t formats_rk356x_esmart[] = { DRM_FORMAT_NV15, /* yuv420_10bit linear mode, 2 plane, no padding */ DRM_FORMAT_NV16, /* yuv422_8bit linear mode, 2 plane */ DRM_FORMAT_NV61, /* yuv422_8bit linear mode, 2 plane */ + DRM_FORMAT_NV20, /* yuv422_10bit linear mode, 2 plane, no padding */ DRM_FORMAT_NV24, /* yuv444_8bit linear mode, 2 plane */ DRM_FORMAT_NV42, /* yuv444_8bit linear mode, 2 plane */ + DRM_FORMAT_NV30, /* yuv444_10bit linear mode, 2 plane, no padding */ DRM_FORMAT_YVYU, /* yuv422_8bit[YVYU] linear mode */ DRM_FORMAT_VYUY, /* yuv422_8bit[VYUY] linear mode */ }; From 1044f4a31734eef000f42cdaaf35bb2f76286be5 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Thu, 2 Nov 2023 14:41:48 +0100 Subject: [PATCH 0996/7721] drm/rockchip: rk3066_hdmi: Remove useless mode_fixup The mode_fixup implementation doesn't do anything, so we can simply remove it. Signed-off-by: Johan Jonker Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/5649ac03-db92-42a9-d86a-76dfa1af7c64@gmail.com --- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index fa6e592e0276..5c269081c691 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -434,14 +434,6 @@ static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder) rk3066_hdmi_set_power_mode(hdmi, HDMI_SYS_POWER_MODE_A); } -static bool -rk3066_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - return true; -} - static int rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -459,7 +451,6 @@ static const struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = { .enable = rk3066_hdmi_encoder_enable, .disable = rk3066_hdmi_encoder_disable, - .mode_fixup = rk3066_hdmi_encoder_mode_fixup, .mode_set = rk3066_hdmi_encoder_mode_set, .atomic_check = rk3066_hdmi_encoder_atomic_check, }; From ae3436a5e7c2ef4f92938133bd99f92fc47ea34e Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Thu, 2 Nov 2023 14:42:04 +0100 Subject: [PATCH 0997/7721] drm/rockchip: rk3066_hdmi: Switch encoder hooks to atomic The rk3066_hdmi encoder still uses the non atomic variants of enable and disable. Convert to their atomic equivalents. In atomic mode there is no need to save the adjusted mode, so remove the mode_set function. Signed-off-by: Johan Jonker Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/034c3446-d619-f4c3-3aaa-ab51dc19d07f@gmail.com --- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 37 +++++++++++++------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 5c269081c691..0e7aae341960 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -55,7 +55,6 @@ struct rk3066_hdmi { unsigned int tmdsclk; struct hdmi_data_info hdmi_data; - struct drm_display_mode previous_mode; }; static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder) @@ -387,22 +386,22 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi, return 0; } -static void -rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); - - /* Store the display mode for plugin/DPMS poweron events. */ - drm_mode_copy(&hdmi->previous_mode, adj_mode); -} - -static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder) +static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; int mux, val; + conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); if (mux) val = (HDMI_VIDEO_SEL << 16) | HDMI_VIDEO_SEL; @@ -414,10 +413,11 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder) DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder enable select: vop%s\n", (mux) ? "1" : "0"); - rk3066_hdmi_setup(hdmi, &hdmi->previous_mode); + rk3066_hdmi_setup(hdmi, &crtc_state->adjusted_mode); } -static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder) +static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); @@ -449,10 +449,9 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder, static const struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = { - .enable = rk3066_hdmi_encoder_enable, - .disable = rk3066_hdmi_encoder_disable, - .mode_set = rk3066_hdmi_encoder_mode_set, - .atomic_check = rk3066_hdmi_encoder_atomic_check, + .atomic_check = rk3066_hdmi_encoder_atomic_check, + .atomic_enable = rk3066_hdmi_encoder_enable, + .atomic_disable = rk3066_hdmi_encoder_disable, }; static enum drm_connector_status From af524e9dcb43f5914cecb3a3f4b79081d2e3f7f8 Mon Sep 17 00:00:00 2001 From: David Lin Date: Mon, 20 Nov 2023 16:42:28 +0800 Subject: [PATCH 0998/7721] ASoC: nau8810: Fix incorrect type in assignment and cast to restricted __be16 This issue is reproduced when W=1 build in compiler gcc-12. The following are sparse warnings: sound/soc/codecs/nau8810.c:183:25: sparse: warning: incorrect type in assignment sound/soc/codecs/nau8810.c:183:25: sparse: expected int sound/soc/codecs/nau8810.c:183:25: sparse: got restricted __be16 sound/soc/codecs/nau8810.c:219:25: sparse: warning: cast to restricted __be16 sound/soc/codecs/nau8810.c:219:25: sparse: warning: cast to restricted __be16 sound/soc/codecs/nau8810.c:219:25: sparse: warning: cast to restricted __be16 sound/soc/codecs/nau8810.c:219:25: sparse: warning: cast to restricted __be16 This issue is not still actively checked by kernel test robot. Actually, it is same with nau8822's sparse warnings issue. Signed-off-by: David Lin Link: https://lore.kernel.org/r/20231120084227.1766633-1-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8810.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 47f000cd4d99..97a54059474c 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -169,6 +169,7 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *params = (void *)kcontrol->private_value; int i, reg, reg_val; u16 *val; + __be16 tmp; val = (u16 *)ucontrol->value.bytes.data; reg = NAU8810_REG_EQ1; @@ -177,8 +178,8 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol, /* conversion of 16-bit integers between native CPU format * and big endian format */ - reg_val = cpu_to_be16(reg_val); - memcpy(val + i, ®_val, sizeof(reg_val)); + tmp = cpu_to_be16(reg_val); + memcpy(val + i, &tmp, sizeof(tmp)); } return 0; @@ -201,6 +202,7 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol, void *data; u16 *val, value; int i, reg, ret; + __be16 *tmp; data = kmemdup(ucontrol->value.bytes.data, params->max, GFP_KERNEL | GFP_DMA); @@ -213,7 +215,8 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol, /* conversion of 16-bit integers between native CPU format * and big endian format */ - value = be16_to_cpu(*(val + i)); + tmp = (__be16 *)(val + i); + value = be16_to_cpup(tmp); ret = regmap_write(nau8810->regmap, reg + i, value); if (ret) { dev_err(component->dev, "EQ configuration fail, register: %x ret: %d\n", From 57b97ecb40caeb116c22451bbdaaa9a1d12c0b43 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 20 Nov 2023 10:04:52 -0800 Subject: [PATCH 0999/7721] selftests/bpf: reduce verboseness of reg_bounds selftest logs Reduce verboseness of test_progs' output in reg_bounds set of tests with two changes. First, instead of each different operator (<, <=, >, ...) being it's own subtest, combine all different ops for the same (x, y, init_t, cond_t) values into single subtest. Instead of getting 6 subtests, we get one generic one, e.g.: #192/53 reg_bounds_crafted/(s64)[0xffffffffffffffff; 0] (s64) 0xffffffff00000000:OK Second, for random generated test cases, treat all of them as a single test to eliminate very verbose output with random values in them. So now we'll just get one line per each combination of (init_t, cond_t), instead of 6 x 25 = 150 subtests before this change: #225 reg_bounds_rand_consts_s32_s32:OK Given we reduce verboseness so much, it makes sense to do a bit more random testing, so we also bump default number of random tests to 100, up from 25. This doesn't increase runtime significantly, especially in parallelized mode. With all the above changes we still make sure that we have all the information necessary for reproducing test case if it happens to fail. That includes reporting random seed and specific operator that is failing. Those will only be printed to console if related test/subtest fails, so it doesn't have any added verboseness implications. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231120180452.145849-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/reg_bounds.c | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index fd4ab23e6f54..0c9abd279e18 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -1361,11 +1361,11 @@ struct subtest_case { enum op op; }; -static void subtest_case_str(struct strbuf *sb, struct subtest_case *t) +static void subtest_case_str(struct strbuf *sb, struct subtest_case *t, bool use_op) { snappendf(sb, "(%s)", t_str(t->init_t)); snprintf_range(t->init_t, sb, t->x); - snappendf(sb, " (%s)%s ", t_str(t->cond_t), op_str(t->op)); + snappendf(sb, " (%s)%s ", t_str(t->cond_t), use_op ? op_str(t->op) : ""); snprintf_range(t->init_t, sb, t->y); } @@ -1440,8 +1440,8 @@ static int verify_case_op(enum num_t init_t, enum num_t cond_t, /* Given setup ranges and number types, go over all supported operations, * generating individual subtest for each allowed combination */ -static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, - struct range x, struct range y) +static int verify_case_opt(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, bool is_subtest) { DEFINE_STRBUF(sb, 256); int err; @@ -1452,11 +1452,14 @@ static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, .y = y, }; + sb->pos = 0; /* reset position in strbuf */ + subtest_case_str(sb, &sub, false /* ignore op */); + if (is_subtest && !test__start_subtest(sb->buf)) + return 0; + for (sub.op = first_op; sub.op <= last_op; sub.op++) { sb->pos = 0; /* reset position in strbuf */ - subtest_case_str(sb, &sub); - if (!test__start_subtest(sb->buf)) - continue; + subtest_case_str(sb, &sub, true /* print op */); if (env.verbosity >= VERBOSE_NORMAL) /* this speeds up debugging */ printf("TEST CASE: %s\n", sb->buf); @@ -1491,6 +1494,12 @@ static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, return 0; } +static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, + struct range x, struct range y) +{ + return verify_case_opt(ctx, init_t, cond_t, x, y, true /* is_subtest */); +} + /* ================================ * GENERATED CASES FROM SEED VALUES * ================================ @@ -1913,7 +1922,7 @@ void test_reg_bounds_gen_ranges_s32_s64(void) { validate_gen_range_vs_range(S32, void test_reg_bounds_gen_ranges_s32_u32(void) { validate_gen_range_vs_range(S32, U32); } void test_reg_bounds_gen_ranges_s32_s32(void) { validate_gen_range_vs_range(S32, S32); } -#define DEFAULT_RAND_CASE_CNT 25 +#define DEFAULT_RAND_CASE_CNT 100 #define RAND_21BIT_MASK ((1 << 22) - 1) @@ -1968,7 +1977,6 @@ static void validate_rand_ranges(enum num_t init_t, enum num_t cond_t, bool cons "[RANDOM SEED %u] RANGE x %s, %s -> %s", ctx.rand_seed, const_range ? "CONST" : "RANGE", t_str(init_t), t_str(cond_t)); - fprintf(env.stdout, "%s\n", ctx.progress_ctx); for (i = 0; i < ctx.rand_case_cnt; i++) { range1 = rand_range(init_t); @@ -1980,14 +1988,16 @@ static void validate_rand_ranges(enum num_t init_t, enum num_t cond_t, bool cons } /* x */ - if (verify_case(&ctx, init_t, cond_t, range1, range2)) + if (verify_case_opt(&ctx, init_t, cond_t, range1, range2, false /* !is_subtest */)) goto cleanup; /* x */ - if (verify_case(&ctx, init_t, cond_t, range2, range1)) + if (verify_case_opt(&ctx, init_t, cond_t, range2, range1, false /* !is_subtest */)) goto cleanup; } cleanup: + /* make sure we report random seed for reproducing */ + ASSERT_TRUE(true, ctx.progress_ctx); cleanup_ctx(&ctx); } From 5f35a624c1e30b5bae5023b3c256e94e0ad4f806 Mon Sep 17 00:00:00 2001 From: Abhinav Singh Date: Tue, 14 Nov 2023 00:43:03 +0530 Subject: [PATCH 1000/7721] drm/nouveau/fence:: fix warning directly dereferencing a rcu pointer Fix a sparse warning with this message "warning:dereference of noderef expression". In this context it means we are dereferencing a __rcu tagged pointer directly. We should not be directly dereferencing a rcu pointer. To get a normal (non __rcu tagged pointer) from a __rcu tagged pointer we are using the function unrcu_pointer(...). The non __rcu tagged pointer then can be dereferenced just like a normal pointer. I tested with qemu with this command qemu-system-x86_64 \ -m 2G \ -smp 2 \ -kernel bzImage \ -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0" \ -drive file=bullseye.img,format=raw \ -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ -net nic,model=e1000 \ -enable-kvm \ -nographic \ -pidfile vm.pid \ 2>&1 | tee vm.log with lockdep enabled. Fixes: 0ec5f02f0e2c ("drm/nouveau: prevent stale fence->channel pointers, and protect with rcu") Signed-off-by: Abhinav Singh Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231113191303.3277733-1-singhabhinav9051571833@gmail.com --- drivers/gpu/drm/nouveau/nv04_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index 5b71a5a5cd85..cdbc75e3d1f6 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c @@ -39,7 +39,7 @@ struct nv04_fence_priv { static int nv04_fence_emit(struct nouveau_fence *fence) { - struct nvif_push *push = fence->channel->chan.push; + struct nvif_push *push = unrcu_pointer(fence->channel)->chan.push; int ret = PUSH_WAIT(push, 2); if (ret == 0) { PUSH_NVSQ(push, NV_SW, 0x0150, fence->base.seqno); From 548b61a8ce18dec8757fcc112eac5bd125161408 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 15 Nov 2023 14:44:09 -0800 Subject: [PATCH 1001/7721] drm/msm/gpu: Move gpu devcore's to gpu device The dpu devcore's are already associated with the dpu device. So we should associate the gpu devcore's with the gpu device, for easier classification. Signed-off-by: Rob Clark Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/567738/ --- drivers/gpu/drm/msm/msm_gpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7f64c6667300..2b7c9db3ded3 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -292,8 +292,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, /* Set the active crash state to be dumped on failure */ gpu->crashstate = state; - /* FIXME: Release the crashstate if this errors out? */ - dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, + dev_coredumpm(&gpu->pdev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); } #else From 4bea53b9c7c72fd12a0ceebe88a71723c0a514b8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 17 Nov 2023 07:14:19 -0800 Subject: [PATCH 1002/7721] drm/msm: Reduce fallout of fence signaling vs reclaim hangs Until various PM devfreq/QoS and interconnect patches land, we could potentially trigger reclaim from gpu scheduler thread, and under enough memory pressure that could trigger a sort of deadlock. Eventually the wait will timeout and we'll move on to consider other GEM objects. But given that there is still a potential for deadlock/stalling, we should reduce the timeout to contain the damage. Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/568031/ --- drivers/gpu/drm/msm/msm_gem_shrinker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 5a7d48c02c4b..07ca4ddfe4e3 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -75,7 +75,7 @@ static bool wait_for_idle(struct drm_gem_object *obj) { enum dma_resv_usage usage = dma_resv_usage_rw(true); - return dma_resv_wait_timeout(obj->resv, usage, false, 1000) > 0; + return dma_resv_wait_timeout(obj->resv, usage, false, 10) > 0; } static bool From 12578c075f89d6bd1b8af21751fbc2e1f78d2ce0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 17 Nov 2023 07:24:28 -0800 Subject: [PATCH 1003/7721] drm/msm/gpu: Skip retired submits in recover worker If we somehow raced with submit retiring, either while waiting for worker to have a chance to run or acquiring the gpu lock, then the recover worker should just bail. Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/568034/ --- drivers/gpu/drm/msm/msm_gpu.c | 41 +++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 2b7c9db3ded3..095390774f22 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -365,29 +365,31 @@ static void recover_worker(struct kthread_work *work) DRM_DEV_ERROR(dev->dev, "%s: hangcheck recover!\n", gpu->name); submit = find_submit(cur_ring, cur_ring->memptrs->fence + 1); - if (submit) { - /* Increment the fault counts */ - submit->queue->faults++; - if (submit->aspace) - submit->aspace->faults++; - get_comm_cmdline(submit, &comm, &cmd); + /* + * If the submit retired while we were waiting for the worker to run, + * or waiting to acquire the gpu lock, then nothing more to do. + */ + if (!submit) + goto out_unlock; - if (comm && cmd) { - DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n", - gpu->name, comm, cmd); + /* Increment the fault counts */ + submit->queue->faults++; + if (submit->aspace) + submit->aspace->faults++; - msm_rd_dump_submit(priv->hangrd, submit, - "offending task: %s (%s)", comm, cmd); - } else { - msm_rd_dump_submit(priv->hangrd, submit, NULL); - } + get_comm_cmdline(submit, &comm, &cmd); + + if (comm && cmd) { + DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n", + gpu->name, comm, cmd); + + msm_rd_dump_submit(priv->hangrd, submit, + "offending task: %s (%s)", comm, cmd); } else { - /* - * We couldn't attribute this fault to any particular context, - * so increment the global fault count instead. - */ - gpu->global_faults++; + DRM_DEV_ERROR(dev->dev, "%s: offending task: unknown\n", gpu->name); + + msm_rd_dump_submit(priv->hangrd, submit, NULL); } /* Record the crash state */ @@ -440,6 +442,7 @@ static void recover_worker(struct kthread_work *work) pm_runtime_put(&gpu->pdev->dev); +out_unlock: mutex_unlock(&gpu->lock); msm_gpu_retire(gpu); From 45933b2db91b9ee7c812b03f455316a1a61f7985 Mon Sep 17 00:00:00 2001 From: Vishvambar Panth S Date: Thu, 16 Nov 2023 11:13:50 +0530 Subject: [PATCH 1004/7721] net: microchip: lan743x : bidirectional throughput improvement The LAN743x/PCI11xxx DMA descriptors are always 4 dwords long, but the device supports placing the descriptors in memory back to back or reserving space in between them using its DMA_DESCRIPTOR_SPACE (DSPACE) configurable hardware setting. Currently DSPACE is unnecessarily set to match the host's L1 cache line size, resulting in space reserved in between descriptors in most platforms and causing a suboptimal behavior (single PCIe Mem transaction per descriptor). By changing the setting to DSPACE=16 many descriptors can be packed in a single PCIe Mem transaction resulting in a massive performance improvement in bidirectional tests without any negative effects. Tested and verified improvements on x64 PC and several ARM platforms (typical data below) Test setup 1: x64 PC with LAN7430 ---> x64 PC iperf3 UDP bidirectional with DSPACE set to L1 CACHE Size: - - - - - - - - - - - - - - - - - - - - - - - - - [ ID][Role] Interval Transfer Bitrate [ 5][TX-C] 0.00-10.00 sec 170 MBytes 143 Mbits/sec sender [ 5][TX-C] 0.00-10.04 sec 169 MBytes 141 Mbits/sec receiver [ 7][RX-C] 0.00-10.00 sec 1.02 GBytes 876 Mbits/sec sender [ 7][RX-C] 0.00-10.04 sec 1.02 GBytes 870 Mbits/sec receiver iperf3 UDP bidirectional with DSPACE set to 16 Bytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID][Role] Interval Transfer Bitrate [ 5][TX-C] 0.00-10.00 sec 1.11 GBytes 956 Mbits/sec sender [ 5][TX-C] 0.00-10.04 sec 1.11 GBytes 951 Mbits/sec receiver [ 7][RX-C] 0.00-10.00 sec 1.10 GBytes 948 Mbits/sec sender [ 7][RX-C] 0.00-10.04 sec 1.10 GBytes 942 Mbits/sec receiver Test setup 2 : RK3399 with LAN7430 ---> x64 PC RK3399 Spec: The SOM-RK3399 is ARM module designed and developed by FriendlyElec. Cores: 64-bit Dual Core Cortex-A72 + Quad Core Cortex-A53 Frequency: Cortex-A72(up to 2.0GHz), Cortex-A53(up to 1.5GHz) PCIe: PCIe x4, compatible with PCIe 2.1, Dual operation mode iperf3 UDP bidirectional with DSPACE set to L1 CACHE Size: - - - - - - - - - - - - - - - - - - - - - - - - - [ ID][Role] Interval Transfer Bitrate [ 5][TX-C] 0.00-10.00 sec 534 MBytes 448 Mbits/sec sender [ 5][TX-C] 0.00-10.05 sec 534 MBytes 446 Mbits/sec receiver [ 7][RX-C] 0.00-10.00 sec 1.12 GBytes 961 Mbits/sec sender [ 7][RX-C] 0.00-10.05 sec 1.11 GBytes 946 Mbits/sec receiver iperf3 UDP bidirectional with DSPACE set to 16 Bytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID][Role] Interval Transfer Bitrate [ 5][TX-C] 0.00-10.00 sec 966 MBytes 810 Mbits/sec sender [ 5][TX-C] 0.00-10.04 sec 965 MBytes 806 Mbits/sec receiver [ 7][RX-C] 0.00-10.00 sec 1.11 GBytes 956 Mbits/sec sender [ 7][RX-C] 0.00-10.04 sec 1.07 GBytes 919 Mbits/sec receiver Signed-off-by: Vishvambar Panth S Reviewed-by: Simon Horman Reviewed-by: Florian Fainelli Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231116054350.620420-1-vishvambarpanth.s@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan743x_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h index b648461787d2..be79cb0ae5af 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.h +++ b/drivers/net/ethernet/microchip/lan743x_main.h @@ -1075,7 +1075,7 @@ struct lan743x_adapter { #define DMA_DESCRIPTOR_SPACING_32 (32) #define DMA_DESCRIPTOR_SPACING_64 (64) #define DMA_DESCRIPTOR_SPACING_128 (128) -#define DEFAULT_DMA_DESCRIPTOR_SPACING (L1_CACHE_BYTES) +#define DEFAULT_DMA_DESCRIPTOR_SPACING (DMA_DESCRIPTOR_SPACING_16) #define DMAC_CHANNEL_STATE_SET(start_bit, stop_bit) \ (((start_bit) ? 2 : 0) | ((stop_bit) ? 1 : 0)) From a0bc96c0cd6e61fcaebff34432791a4b5118fc68 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 16 Nov 2023 15:34:43 -0500 Subject: [PATCH 1005/7721] selftests: net: verify fq per-band packet limit Commit 29f834aa326e ("net_sched: sch_fq: add 3 bands and WRR scheduling") introduces multiple traffic bands, and per-band maximum packet count. Per-band limits ensures that packets in one class cannot fill the entire qdisc and so cause DoS to the traffic in the other classes. Verify this behavior: 1. set the limit to 10 per band 2. send 20 pkts on band A: verify that 10 are queued, 10 dropped 3. send 20 pkts on band A: verify that 0 are queued, 20 dropped 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped Packets must remain queued for a period to trigger this behavior. Use SO_TXTIME to store packets for 100 msec. The test reuses existing upstream test infra. The script is a fork of cmsg_time.sh. The scripts call cmsg_sender. The test extends cmsg_sender with two arguments: * '-P' SO_PRIORITY There is a subtle difference between IPv4 and IPv6 stack behavior: PF_INET/IP_TOS sets IP header bits and sk_priority PF_INET6/IPV6_TCLASS sets IP header bits BUT NOT sk_priority * '-n' num pkts Send multiple packets in quick succession. I first attempted a for loop in the script, but this is too slow in virtualized environments, causing flakiness as the 100ms timeout is reached and packets are dequeued. Also do not wait for timestamps to be queued unless timestamps are requested. Signed-off-by: Willem de Bruijn Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231116203449.2627525-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/cmsg_sender.c | 50 ++++++++++------ .../testing/selftests/net/fq_band_pktlimit.sh | 57 +++++++++++++++++++ 3 files changed, 91 insertions(+), 17 deletions(-) create mode 100755 tools/testing/selftests/net/fq_band_pktlimit.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 5b2aca4c5f10..9274edfb76ff 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -91,6 +91,7 @@ TEST_PROGS += test_bridge_neigh_suppress.sh TEST_PROGS += test_vxlan_nolocalbypass.sh TEST_PROGS += test_bridge_backup_port.sh TEST_PROGS += fdb_flush.sh +TEST_PROGS += fq_band_pktlimit.sh TEST_FILES := settings diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c index 24b21b15ed3f..8d7575389f58 100644 --- a/tools/testing/selftests/net/cmsg_sender.c +++ b/tools/testing/selftests/net/cmsg_sender.c @@ -45,11 +45,13 @@ struct options { const char *host; const char *service; unsigned int size; + unsigned int num_pkt; struct { unsigned int mark; unsigned int dontfrag; unsigned int tclass; unsigned int hlimit; + unsigned int priority; } sockopt; struct { unsigned int family; @@ -72,6 +74,7 @@ struct options { } v6; } opt = { .size = 13, + .num_pkt = 1, .sock = { .family = AF_UNSPEC, .type = SOCK_DGRAM, @@ -112,7 +115,7 @@ static void cs_parse_args(int argc, char *argv[]) { int o; - while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:H:")) != -1) { + while ((o = getopt(argc, argv, "46sS:p:P:m:M:n:d:tf:F:c:C:l:L:H:")) != -1) { switch (o) { case 's': opt.silent_send = true; @@ -138,7 +141,9 @@ static void cs_parse_args(int argc, char *argv[]) cs_usage(argv[0]); } break; - + case 'P': + opt.sockopt.priority = atoi(optarg); + break; case 'm': opt.mark.ena = true; opt.mark.val = atoi(optarg); @@ -146,6 +151,9 @@ static void cs_parse_args(int argc, char *argv[]) case 'M': opt.sockopt.mark = atoi(optarg); break; + case 'n': + opt.num_pkt = atoi(optarg); + break; case 'd': opt.txtime.ena = true; opt.txtime.delay = atoi(optarg); @@ -410,6 +418,10 @@ static void ca_set_sockopts(int fd) setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &opt.sockopt.hlimit, sizeof(opt.sockopt.hlimit))) error(ERN_SOCKOPT, errno, "setsockopt IPV6_HOPLIMIT"); + if (opt.sockopt.priority && + setsockopt(fd, SOL_SOCKET, SO_PRIORITY, + &opt.sockopt.priority, sizeof(opt.sockopt.priority))) + error(ERN_SOCKOPT, errno, "setsockopt SO_PRIORITY"); } int main(int argc, char *argv[]) @@ -421,6 +433,7 @@ int main(int argc, char *argv[]) char *buf; int err; int fd; + int i; cs_parse_args(argc, argv); @@ -480,24 +493,27 @@ int main(int argc, char *argv[]) cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf)); - err = sendmsg(fd, &msg, 0); - if (err < 0) { - if (!opt.silent_send) - fprintf(stderr, "send failed: %s\n", strerror(errno)); - err = ERN_SEND; - goto err_out; - } else if (err != (int)opt.size) { - fprintf(stderr, "short send\n"); - err = ERN_SEND_SHORT; - goto err_out; - } else { - err = ERN_SUCCESS; + for (i = 0; i < opt.num_pkt; i++) { + err = sendmsg(fd, &msg, 0); + if (err < 0) { + if (!opt.silent_send) + fprintf(stderr, "send failed: %s\n", strerror(errno)); + err = ERN_SEND; + goto err_out; + } else if (err != (int)opt.size) { + fprintf(stderr, "short send\n"); + err = ERN_SEND_SHORT; + goto err_out; + } } + err = ERN_SUCCESS; - /* Make sure all timestamps have time to loop back */ - usleep(opt.txtime.delay); + if (opt.ts.ena) { + /* Make sure all timestamps have time to loop back */ + usleep(opt.txtime.delay); - cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf)); + cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf)); + } err_out: close(fd); diff --git a/tools/testing/selftests/net/fq_band_pktlimit.sh b/tools/testing/selftests/net/fq_band_pktlimit.sh new file mode 100755 index 000000000000..24b77bdf41ff --- /dev/null +++ b/tools/testing/selftests/net/fq_band_pktlimit.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Verify that FQ has a packet limit per band: +# +# 1. set the limit to 10 per band +# 2. send 20 pkts on band A: verify that 10 are queued, 10 dropped +# 3. send 20 pkts on band A: verify that 0 are queued, 20 dropped +# 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped +# +# Send packets with a 100ms delay to ensure that previously sent +# packets are still queued when later ones are sent. +# Use SO_TXTIME for this. + +die() { + echo "$1" + exit 1 +} + +# run inside private netns +if [[ $# -eq 0 ]]; then + ./in_netns.sh "$0" __subprocess + exit +fi + +ip link add type dummy +ip link set dev dummy0 up +ip -6 addr add fdaa::1/128 dev dummy0 +ip -6 route add fdaa::/64 dev dummy0 +tc qdisc replace dev dummy0 root handle 1: fq quantum 1514 initial_quantum 1514 limit 10 + +./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000 +OUT1="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" + +./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000 +OUT2="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" + +./cmsg_sender -6 -p u -d 100000 -n 20 -P 7 fdaa::2 8000 +OUT3="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" + +# Initial stats will report zero sent, as all packets are still +# queued in FQ. Sleep for the delay period (100ms) and see that +# twenty are now sent. +sleep 0.1 +OUT4="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" + +# Log the output after the test +echo "${OUT1}" +echo "${OUT2}" +echo "${OUT3}" +echo "${OUT4}" + +# Test the output for expected values +echo "${OUT1}" | grep -q '0\ pkt\ (dropped\ 10' || die "unexpected drop count at 1" +echo "${OUT2}" | grep -q '0\ pkt\ (dropped\ 30' || die "unexpected drop count at 2" +echo "${OUT3}" | grep -q '0\ pkt\ (dropped\ 40' || die "unexpected drop count at 3" +echo "${OUT4}" | grep -q '20\ pkt\ (dropped\ 40' || die "unexpected accept count at 4" From 5e63c5ef7a99d4cc13ddb4964bdeaff45c0364a0 Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Thu, 16 Nov 2023 00:26:51 +0530 Subject: [PATCH 1006/7721] dt-bindings: net: xlnx,axi-ethernet: Introduce DMA support Xilinx 1G/2.5G Ethernet Subsystem provides 32-bit AXI4-Stream buses to move transmit and receive Ethernet data to and from the subsystem. These buses are designed to be used with an AXI Direct Memory Access(DMA) IP or AXI Multichannel Direct Memory Access (MCDMA) IP core, AXI4-Stream Data FIFO, or any other custom logic in any supported device. Primary high-speed DMA data movement between system memory and stream target is through the AXI4 Read Master to AXI4 memory-mapped to stream (MM2S) Master, and AXI stream to memory-mapped (S2MM) Slave to AXI4 Write Master. AXI DMA/MCDMA enables channel of data movement on both MM2S and S2MM paths in scatter/gather mode. AXI DMA has two channels where as MCDMA has 16 Tx and 16 Rx channels. To uniquely identify each channel use 'chan' suffix. Depending on the usecase AXI ethernet driver can request any combination of multichannel DMA channels using generic dmas, dma-names properties. Example: dma-names = tx_chan0, rx_chan0, tx_chan1, rx_chan1; Signed-off-by: Radhey Shyam Pandey Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1700074613-1977070-2-git-send-email-radhey.shyam.pandey@amd.com Signed-off-by: Jakub Kicinski --- .../bindings/net/xlnx,axi-ethernet.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml index 1d33d80af11c..bbe89ea9590c 100644 --- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml +++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml @@ -122,6 +122,20 @@ properties: and "phy-handle" should point to an external PHY if exists. maxItems: 1 + dmas: + minItems: 2 + maxItems: 32 + description: TX and RX DMA channel phandle + + dma-names: + items: + pattern: "^[tr]x_chan([0-9]|1[0-5])$" + description: + Should be "tx_chan0", "tx_chan1" ... "tx_chan15" for DMA Tx channel + Should be "rx_chan0", "rx_chan1" ... "rx_chan15" for DMA Rx channel + minItems: 2 + maxItems: 32 + required: - compatible - interrupts @@ -143,6 +157,8 @@ examples: clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; phy-mode = "mii"; reg = <0x40c00000 0x40000>,<0x50c00000 0x40000>; + dmas = <&xilinx_dma 0>, <&xilinx_dma 1>; + dma-names = "tx_chan0", "rx_chan0"; xlnx,rxcsum = <0x2>; xlnx,rxmem = <0x800>; xlnx,txcsum = <0x2>; From 6b1b40f704fc39db70098a1908ab2309b29831b6 Mon Sep 17 00:00:00 2001 From: Sarath Babu Naidu Gaddam Date: Thu, 16 Nov 2023 00:26:52 +0530 Subject: [PATCH 1007/7721] net: axienet: Preparatory changes for dmaengine support The axiethernet driver has inbuilt dma programming. In order to add dmaengine support and make it's integration seamless the current axidma inbuilt programming code is put under use_dmaengine check. It also performs minor code reordering to minimize conditional use_dmaengine checks and there is no functional change. It uses "dmas" property to identify whether it should use a dmaengine framework or inbuilt axidma programming. Signed-off-by: Sarath Babu Naidu Gaddam Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/1700074613-1977070-3-git-send-email-radhey.shyam.pandey@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/xilinx_axienet.h | 2 + .../net/ethernet/xilinx/xilinx_axienet_main.c | 290 ++++++++++-------- 2 files changed, 165 insertions(+), 127 deletions(-) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 575ff9de8985..3ead0bac597b 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -435,6 +435,7 @@ struct axidma_bd { * @coalesce_usec_rx: IRQ coalesce delay for RX * @coalesce_count_tx: Store the irq coalesce on TX side. * @coalesce_usec_tx: IRQ coalesce delay for TX + * @use_dmaengine: flag to check dmaengine framework usage. */ struct axienet_local { struct net_device *ndev; @@ -499,6 +500,7 @@ struct axienet_local { u32 coalesce_usec_rx; u32 coalesce_count_tx; u32 coalesce_usec_tx; + u8 use_dmaengine; }; /** diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 82d0d44b2b02..188b03e86263 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -589,10 +589,6 @@ static int axienet_device_reset(struct net_device *ndev) struct axienet_local *lp = netdev_priv(ndev); int ret; - ret = __axienet_device_reset(lp); - if (ret) - return ret; - lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE; lp->options |= XAE_OPTION_VLAN; lp->options &= (~XAE_OPTION_JUMBO); @@ -606,11 +602,17 @@ static int axienet_device_reset(struct net_device *ndev) lp->options |= XAE_OPTION_JUMBO; } - ret = axienet_dma_bd_init(ndev); - if (ret) { - netdev_err(ndev, "%s: descriptor allocation failed\n", - __func__); - return ret; + if (!lp->use_dmaengine) { + ret = __axienet_device_reset(lp); + if (ret) + return ret; + + ret = axienet_dma_bd_init(ndev); + if (ret) { + netdev_err(ndev, "%s: descriptor allocation failed\n", + __func__); + return ret; + } } axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET); @@ -1125,41 +1127,21 @@ static irqreturn_t axienet_eth_irq(int irq, void *_ndev) static void axienet_dma_err_handler(struct work_struct *work); /** - * axienet_open - Driver open routine. - * @ndev: Pointer to net_device structure + * axienet_init_legacy_dma - init the dma legacy code. + * @ndev: Pointer to net_device structure * * Return: 0, on success. - * non-zero error value on failure + * non-zero error value on failure + * + * This is the dma initialization code. It also allocates interrupt + * service routines, enables the interrupt lines and ISR handling. * - * This is the driver open routine. It calls phylink_start to start the - * PHY device. - * It also allocates interrupt service routines, enables the interrupt lines - * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer - * descriptors are initialized. */ -static int axienet_open(struct net_device *ndev) +static int axienet_init_legacy_dma(struct net_device *ndev) { int ret; struct axienet_local *lp = netdev_priv(ndev); - dev_dbg(&ndev->dev, "axienet_open()\n"); - - /* When we do an Axi Ethernet reset, it resets the complete core - * including the MDIO. MDIO must be disabled before resetting. - * Hold MDIO bus lock to avoid MDIO accesses during the reset. - */ - axienet_lock_mii(lp); - ret = axienet_device_reset(ndev); - axienet_unlock_mii(lp); - - ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0); - if (ret) { - dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret); - return ret; - } - - phylink_start(lp->phylink); - /* Enable worker thread for Axi DMA error handling */ INIT_WORK(&lp->dma_err_task, axienet_dma_err_handler); @@ -1193,13 +1175,61 @@ static int axienet_open(struct net_device *ndev) err_tx_irq: napi_disable(&lp->napi_tx); napi_disable(&lp->napi_rx); - phylink_stop(lp->phylink); - phylink_disconnect_phy(lp->phylink); cancel_work_sync(&lp->dma_err_task); dev_err(lp->dev, "request_irq() failed\n"); return ret; } +/** + * axienet_open - Driver open routine. + * @ndev: Pointer to net_device structure + * + * Return: 0, on success. + * non-zero error value on failure + * + * This is the driver open routine. It calls phylink_start to start the + * PHY device. + * It also allocates interrupt service routines, enables the interrupt lines + * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer + * descriptors are initialized. + */ +static int axienet_open(struct net_device *ndev) +{ + int ret; + struct axienet_local *lp = netdev_priv(ndev); + + dev_dbg(&ndev->dev, "%s\n", __func__); + + /* When we do an Axi Ethernet reset, it resets the complete core + * including the MDIO. MDIO must be disabled before resetting. + * Hold MDIO bus lock to avoid MDIO accesses during the reset. + */ + axienet_lock_mii(lp); + ret = axienet_device_reset(ndev); + axienet_unlock_mii(lp); + + ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0); + if (ret) { + dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret); + return ret; + } + + phylink_start(lp->phylink); + + if (!lp->use_dmaengine) { + ret = axienet_init_legacy_dma(ndev); + if (ret) + goto err_phy; + } + + return 0; + +err_phy: + phylink_stop(lp->phylink); + phylink_disconnect_phy(lp->phylink); + return ret; +} + /** * axienet_stop - Driver stop routine. * @ndev: Pointer to net_device structure @@ -1216,8 +1246,10 @@ static int axienet_stop(struct net_device *ndev) dev_dbg(&ndev->dev, "axienet_close()\n"); - napi_disable(&lp->napi_tx); - napi_disable(&lp->napi_rx); + if (!lp->use_dmaengine) { + napi_disable(&lp->napi_tx); + napi_disable(&lp->napi_rx); + } phylink_stop(lp->phylink); phylink_disconnect_phy(lp->phylink); @@ -1225,18 +1257,18 @@ static int axienet_stop(struct net_device *ndev) axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - axienet_dma_stop(lp); + if (!lp->use_dmaengine) { + axienet_dma_stop(lp); + cancel_work_sync(&lp->dma_err_task); + free_irq(lp->tx_irq, ndev); + free_irq(lp->rx_irq, ndev); + axienet_dma_bd_release(ndev); + } axienet_iow(lp, XAE_IE_OFFSET, 0); - cancel_work_sync(&lp->dma_err_task); - if (lp->eth_irq > 0) free_irq(lp->eth_irq, ndev); - free_irq(lp->tx_irq, ndev); - free_irq(lp->rx_irq, ndev); - - axienet_dma_bd_release(ndev); return 0; } @@ -1412,14 +1444,16 @@ static void axienet_ethtools_get_regs(struct net_device *ndev, data[29] = axienet_ior(lp, XAE_FMI_OFFSET); data[30] = axienet_ior(lp, XAE_AF0_OFFSET); data[31] = axienet_ior(lp, XAE_AF1_OFFSET); - data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); - data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET); - data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET); - data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); - data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET); - data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET); + if (!lp->use_dmaengine) { + data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); + data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); + data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET); + data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET); + data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); + data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); + data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET); + data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET); + } } static void @@ -1880,9 +1914,6 @@ static int axienet_probe(struct platform_device *pdev) u64_stats_init(&lp->rx_stat_sync); u64_stats_init(&lp->tx_stat_sync); - netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll); - netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll); - lp->axi_clk = devm_clk_get_optional(&pdev->dev, "s_axi_lite_clk"); if (!lp->axi_clk) { /* For backward compatibility, if named AXI clock is not present, @@ -2008,80 +2039,85 @@ static int axienet_probe(struct platform_device *pdev) goto cleanup_clk; } - /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ - np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0); - if (np) { - struct resource dmares; + if (!of_find_property(pdev->dev.of_node, "dmas", NULL)) { + /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ + np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0); - ret = of_address_to_resource(np, 0, &dmares); - if (ret) { - dev_err(&pdev->dev, - "unable to get DMA resource\n"); + if (np) { + struct resource dmares; + + ret = of_address_to_resource(np, 0, &dmares); + if (ret) { + dev_err(&pdev->dev, + "unable to get DMA resource\n"); + of_node_put(np); + goto cleanup_clk; + } + lp->dma_regs = devm_ioremap_resource(&pdev->dev, + &dmares); + lp->rx_irq = irq_of_parse_and_map(np, 1); + lp->tx_irq = irq_of_parse_and_map(np, 0); of_node_put(np); + lp->eth_irq = platform_get_irq_optional(pdev, 0); + } else { + /* Check for these resources directly on the Ethernet node. */ + lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); + lp->rx_irq = platform_get_irq(pdev, 1); + lp->tx_irq = platform_get_irq(pdev, 0); + lp->eth_irq = platform_get_irq_optional(pdev, 2); + } + if (IS_ERR(lp->dma_regs)) { + dev_err(&pdev->dev, "could not map DMA regs\n"); + ret = PTR_ERR(lp->dma_regs); goto cleanup_clk; } - lp->dma_regs = devm_ioremap_resource(&pdev->dev, - &dmares); - lp->rx_irq = irq_of_parse_and_map(np, 1); - lp->tx_irq = irq_of_parse_and_map(np, 0); - of_node_put(np); - lp->eth_irq = platform_get_irq_optional(pdev, 0); - } else { - /* Check for these resources directly on the Ethernet node. */ - lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); - lp->rx_irq = platform_get_irq(pdev, 1); - lp->tx_irq = platform_get_irq(pdev, 0); - lp->eth_irq = platform_get_irq_optional(pdev, 2); - } - if (IS_ERR(lp->dma_regs)) { - dev_err(&pdev->dev, "could not map DMA regs\n"); - ret = PTR_ERR(lp->dma_regs); - goto cleanup_clk; - } - if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) { - dev_err(&pdev->dev, "could not determine irqs\n"); - ret = -ENOMEM; - goto cleanup_clk; - } - - /* Reset core now that clocks are enabled, prior to accessing MDIO */ - ret = __axienet_device_reset(lp); - if (ret) - goto cleanup_clk; - - /* Autodetect the need for 64-bit DMA pointers. - * When the IP is configured for a bus width bigger than 32 bits, - * writing the MSB registers is mandatory, even if they are all 0. - * We can detect this case by writing all 1's to one such register - * and see if that sticks: when the IP is configured for 32 bits - * only, those registers are RES0. - * Those MSB registers were introduced in IP v7.1, which we check first. - */ - if ((axienet_ior(lp, XAE_ID_OFFSET) >> 24) >= 0x9) { - void __iomem *desc = lp->dma_regs + XAXIDMA_TX_CDESC_OFFSET + 4; - - iowrite32(0x0, desc); - if (ioread32(desc) == 0) { /* sanity check */ - iowrite32(0xffffffff, desc); - if (ioread32(desc) > 0) { - lp->features |= XAE_FEATURE_DMA_64BIT; - addr_width = 64; - dev_info(&pdev->dev, - "autodetected 64-bit DMA range\n"); - } - iowrite32(0x0, desc); + if (lp->rx_irq <= 0 || lp->tx_irq <= 0) { + dev_err(&pdev->dev, "could not determine irqs\n"); + ret = -ENOMEM; + goto cleanup_clk; } - } - if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) { - dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n"); - ret = -EINVAL; - goto cleanup_clk; - } - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width)); - if (ret) { - dev_err(&pdev->dev, "No suitable DMA available\n"); - goto cleanup_clk; + /* Reset core now that clocks are enabled, prior to accessing MDIO */ + ret = __axienet_device_reset(lp); + if (ret) + goto cleanup_clk; + + /* Autodetect the need for 64-bit DMA pointers. + * When the IP is configured for a bus width bigger than 32 bits, + * writing the MSB registers is mandatory, even if they are all 0. + * We can detect this case by writing all 1's to one such register + * and see if that sticks: when the IP is configured for 32 bits + * only, those registers are RES0. + * Those MSB registers were introduced in IP v7.1, which we check first. + */ + if ((axienet_ior(lp, XAE_ID_OFFSET) >> 24) >= 0x9) { + void __iomem *desc = lp->dma_regs + XAXIDMA_TX_CDESC_OFFSET + 4; + + iowrite32(0x0, desc); + if (ioread32(desc) == 0) { /* sanity check */ + iowrite32(0xffffffff, desc); + if (ioread32(desc) > 0) { + lp->features |= XAE_FEATURE_DMA_64BIT; + addr_width = 64; + dev_info(&pdev->dev, + "autodetected 64-bit DMA range\n"); + } + iowrite32(0x0, desc); + } + } + if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) { + dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n"); + ret = -EINVAL; + goto cleanup_clk; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width)); + if (ret) { + dev_err(&pdev->dev, "No suitable DMA available\n"); + goto cleanup_clk; + } + netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll); + netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll); } /* Check for Ethernet core IRQ (optional) */ @@ -2099,8 +2135,8 @@ static int axienet_probe(struct platform_device *pdev) } lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD; - lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC; lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; + lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC; lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC; ret = axienet_mdio_setup(lp); From 6a91b846af85a24241decd686269e8e038eb13d1 Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Thu, 16 Nov 2023 00:26:53 +0530 Subject: [PATCH 1008/7721] net: axienet: Introduce dmaengine support Add dmaengine framework to communicate with the xilinx DMAengine driver(AXIDMA). Axi ethernet driver uses separate channels for transmit and receive. Add support for these channels to handle TX and RX with skb and appropriate callbacks. Also add axi ethernet core interrupt for dmaengine framework support. The dmaengine framework was extended for metadata API support. However it still needs further enhancements to make it well suited for ethernet usecases. The ethernet features i.e ethtool set/get of DMA IP properties, ndo_poll_controller,(mentioned in TODO) are not supported and it requires follow-up discussions. dmaengine support has a dependency on xilinx_dma as it uses xilinx_vdma_channel_set_config() API to reset the DMA IP which internally reset MAC prior to accessing MDIO. Benchmark with netperf: xilinx-zcu102-20232:~$ netperf -H 192.168.10.20 -t TCP_STREAM MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.10.20 () port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 131072 16384 16384 10.02 886.69 xilinx-zcu102-20232:~$ netperf -H 192.168.10.20 -t UDP_STREAM MIGRATED UDP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.10.20 () port 0 AF_INET Socket Message Elapsed Messages Size Size Time Okay Errors Throughput bytes bytes secs # # 10^6bits/sec 212992 65507 10.00 15851 0 830.66 212992 10.00 15851 830.66 Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/1700074613-1977070-4-git-send-email-radhey.shyam.pandey@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/Kconfig | 1 + drivers/net/ethernet/xilinx/xilinx_axienet.h | 33 ++ .../net/ethernet/xilinx/xilinx_axienet_main.c | 393 +++++++++++++++++- 3 files changed, 425 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 0014729b8865..35d96c633a33 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -26,6 +26,7 @@ config XILINX_EMACLITE config XILINX_AXI_EMAC tristate "Xilinx 10/100/1000 AXI Ethernet support" depends on HAS_IOMEM + depends on XILINX_DMA select PHYLINK help This driver supports the 10/100/1000 Ethernet from Xilinx for the diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 3ead0bac597b..807ead678551 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -14,6 +14,7 @@ #include #include #include +#include /* Packet size info */ #define XAE_HDR_SIZE 14 /* Size of Ethernet header */ @@ -378,6 +379,22 @@ struct axidma_bd { #define XAE_NUM_MISC_CLOCKS 3 +/** + * struct skbuf_dma_descriptor - skb for each dma descriptor + * @sgl: Pointer for sglist. + * @desc: Pointer to dma descriptor. + * @dma_address: dma address of sglist. + * @skb: Pointer to SKB transferred using DMA + * @sg_len: number of entries in the sglist. + */ +struct skbuf_dma_descriptor { + struct scatterlist sgl[MAX_SKB_FRAGS + 1]; + struct dma_async_tx_descriptor *desc; + dma_addr_t dma_address; + struct sk_buff *skb; + int sg_len; +}; + /** * struct axienet_local - axienet private per device data * @ndev: Pointer for net_device to which it will be attached. @@ -436,6 +453,14 @@ struct axidma_bd { * @coalesce_count_tx: Store the irq coalesce on TX side. * @coalesce_usec_tx: IRQ coalesce delay for TX * @use_dmaengine: flag to check dmaengine framework usage. + * @tx_chan: TX DMA channel. + * @rx_chan: RX DMA channel. + * @tx_skb_ring: Pointer to TX skb ring buffer array. + * @rx_skb_ring: Pointer to RX skb ring buffer array. + * @tx_ring_head: TX skb ring buffer head index. + * @tx_ring_tail: TX skb ring buffer tail index. + * @rx_ring_head: RX skb ring buffer head index. + * @rx_ring_tail: RX skb ring buffer tail index. */ struct axienet_local { struct net_device *ndev; @@ -501,6 +526,14 @@ struct axienet_local { u32 coalesce_count_tx; u32 coalesce_usec_tx; u8 use_dmaengine; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + struct skbuf_dma_descriptor **tx_skb_ring; + struct skbuf_dma_descriptor **rx_skb_ring; + int tx_ring_head; + int tx_ring_tail; + int rx_ring_head; + int rx_ring_tail; }; /** diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 188b03e86263..7d8e22929385 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -38,6 +38,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "xilinx_axienet.h" @@ -47,6 +52,9 @@ #define TX_BD_NUM_MIN (MAX_SKB_FRAGS + 1) #define TX_BD_NUM_MAX 4096 #define RX_BD_NUM_MAX 4096 +#define DMA_NUM_APP_WORDS 5 +#define LEN_APP 4 +#define RX_BUF_NUM_DEFAULT 128 /* Must be shorter than length of ethtool_drvinfo.driver field to fit */ #define DRIVER_NAME "xaxienet" @@ -55,6 +63,8 @@ #define AXIENET_REGS_N 40 +static void axienet_rx_submit_desc(struct net_device *ndev); + /* Match table for of_platform binding */ static const struct of_device_id axienet_of_match[] = { { .compatible = "xlnx,axi-ethernet-1.00.a", }, @@ -120,6 +130,16 @@ static struct axienet_option axienet_options[] = { {} }; +static struct skbuf_dma_descriptor *axienet_get_rx_desc(struct axienet_local *lp, int i) +{ + return lp->rx_skb_ring[i & (RX_BUF_NUM_DEFAULT - 1)]; +} + +static struct skbuf_dma_descriptor *axienet_get_tx_desc(struct axienet_local *lp, int i) +{ + return lp->tx_skb_ring[i & (TX_BD_NUM_MAX - 1)]; +} + /** * axienet_dma_in32 - Memory mapped Axi DMA register read * @lp: Pointer to axienet local structure @@ -727,6 +747,128 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp, return 0; } +/** + * axienet_dma_tx_cb - DMA engine callback for TX channel. + * @data: Pointer to the axienet_local structure. + * @result: error reporting through dmaengine_result. + * This function is called by dmaengine driver for TX channel to notify + * that the transmit is done. + */ +static void axienet_dma_tx_cb(void *data, const struct dmaengine_result *result) +{ + struct skbuf_dma_descriptor *skbuf_dma; + struct axienet_local *lp = data; + struct netdev_queue *txq; + int len; + + skbuf_dma = axienet_get_tx_desc(lp, lp->tx_ring_tail++); + len = skbuf_dma->skb->len; + txq = skb_get_tx_queue(lp->ndev, skbuf_dma->skb); + u64_stats_update_begin(&lp->tx_stat_sync); + u64_stats_add(&lp->tx_bytes, len); + u64_stats_add(&lp->tx_packets, 1); + u64_stats_update_end(&lp->tx_stat_sync); + dma_unmap_sg(lp->dev, skbuf_dma->sgl, skbuf_dma->sg_len, DMA_TO_DEVICE); + dev_consume_skb_any(skbuf_dma->skb); + netif_txq_completed_wake(txq, 1, len, + CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX), + 2 * MAX_SKB_FRAGS); +} + +/** + * axienet_start_xmit_dmaengine - Starts the transmission. + * @skb: sk_buff pointer that contains data to be Txed. + * @ndev: Pointer to net_device structure. + * + * Return: NETDEV_TX_OK on success or any non space errors. + * NETDEV_TX_BUSY when free element in TX skb ring buffer + * is not available. + * + * This function is invoked to initiate transmission. The + * function sets the skbs, register dma callback API and submit + * the dma transaction. + * Additionally if checksum offloading is supported, + * it populates AXI Stream Control fields with appropriate values. + */ +static netdev_tx_t +axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev) +{ + struct dma_async_tx_descriptor *dma_tx_desc = NULL; + struct axienet_local *lp = netdev_priv(ndev); + u32 app_metadata[DMA_NUM_APP_WORDS] = {0}; + struct skbuf_dma_descriptor *skbuf_dma; + struct dma_device *dma_dev; + struct netdev_queue *txq; + u32 csum_start_off; + u32 csum_index_off; + int sg_len; + int ret; + + dma_dev = lp->tx_chan->device; + sg_len = skb_shinfo(skb)->nr_frags + 1; + if (CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX) <= sg_len) { + netif_stop_queue(ndev); + if (net_ratelimit()) + netdev_warn(ndev, "TX ring unexpectedly full\n"); + return NETDEV_TX_BUSY; + } + + skbuf_dma = axienet_get_tx_desc(lp, lp->tx_ring_head); + if (!skbuf_dma) + goto xmit_error_drop_skb; + + lp->tx_ring_head++; + sg_init_table(skbuf_dma->sgl, sg_len); + ret = skb_to_sgvec(skb, skbuf_dma->sgl, 0, skb->len); + if (ret < 0) + goto xmit_error_drop_skb; + + ret = dma_map_sg(lp->dev, skbuf_dma->sgl, sg_len, DMA_TO_DEVICE); + if (!ret) + goto xmit_error_drop_skb; + + /* Fill up app fields for checksum */ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (lp->features & XAE_FEATURE_FULL_TX_CSUM) { + /* Tx Full Checksum Offload Enabled */ + app_metadata[0] |= 2; + } else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) { + csum_start_off = skb_transport_offset(skb); + csum_index_off = csum_start_off + skb->csum_offset; + /* Tx Partial Checksum Offload Enabled */ + app_metadata[0] |= 1; + app_metadata[1] = (csum_start_off << 16) | csum_index_off; + } + } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + app_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */ + } + + dma_tx_desc = dma_dev->device_prep_slave_sg(lp->tx_chan, skbuf_dma->sgl, + sg_len, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT, (void *)app_metadata); + if (!dma_tx_desc) + goto xmit_error_unmap_sg; + + skbuf_dma->skb = skb; + skbuf_dma->sg_len = sg_len; + dma_tx_desc->callback_param = lp; + dma_tx_desc->callback_result = axienet_dma_tx_cb; + dmaengine_submit(dma_tx_desc); + dma_async_issue_pending(lp->tx_chan); + txq = skb_get_tx_queue(lp->ndev, skb); + netdev_tx_sent_queue(txq, skb->len); + netif_txq_maybe_stop(txq, CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX), + MAX_SKB_FRAGS + 1, 2 * MAX_SKB_FRAGS); + + return NETDEV_TX_OK; + +xmit_error_unmap_sg: + dma_unmap_sg(lp->dev, skbuf_dma->sgl, sg_len, DMA_TO_DEVICE); +xmit_error_drop_skb: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + /** * axienet_tx_poll - Invoked once a transmit is completed by the * Axi DMA Tx channel. @@ -893,6 +1035,42 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } +/** + * axienet_dma_rx_cb - DMA engine callback for RX channel. + * @data: Pointer to the skbuf_dma_descriptor structure. + * @result: error reporting through dmaengine_result. + * This function is called by dmaengine driver for RX channel to notify + * that the packet is received. + */ +static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result) +{ + struct skbuf_dma_descriptor *skbuf_dma; + size_t meta_len, meta_max_len, rx_len; + struct axienet_local *lp = data; + struct sk_buff *skb; + u32 *app_metadata; + + skbuf_dma = axienet_get_rx_desc(lp, lp->rx_ring_tail++); + skb = skbuf_dma->skb; + app_metadata = dmaengine_desc_get_metadata_ptr(skbuf_dma->desc, &meta_len, + &meta_max_len); + dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size, + DMA_FROM_DEVICE); + /* TODO: Derive app word index programmatically */ + rx_len = (app_metadata[LEN_APP] & 0xFFFF); + skb_put(skb, rx_len); + skb->protocol = eth_type_trans(skb, lp->ndev); + skb->ip_summed = CHECKSUM_NONE; + + __netif_rx(skb); + u64_stats_update_begin(&lp->rx_stat_sync); + u64_stats_add(&lp->rx_packets, 1); + u64_stats_add(&lp->rx_bytes, rx_len); + u64_stats_update_end(&lp->rx_stat_sync); + axienet_rx_submit_desc(lp->ndev); + dma_async_issue_pending(lp->rx_chan); +} + /** * axienet_rx_poll - Triggered by RX ISR to complete the BD processing. * @napi: Pointer to NAPI structure. @@ -1126,6 +1304,144 @@ static irqreturn_t axienet_eth_irq(int irq, void *_ndev) static void axienet_dma_err_handler(struct work_struct *work); +/** + * axienet_rx_submit_desc - Submit the rx descriptors to dmaengine. + * allocate skbuff, map the scatterlist and obtain a descriptor + * and then add the callback information and submit descriptor. + * + * @ndev: net_device pointer + * + */ +static void axienet_rx_submit_desc(struct net_device *ndev) +{ + struct dma_async_tx_descriptor *dma_rx_desc = NULL; + struct axienet_local *lp = netdev_priv(ndev); + struct skbuf_dma_descriptor *skbuf_dma; + struct sk_buff *skb; + dma_addr_t addr; + + skbuf_dma = axienet_get_rx_desc(lp, lp->rx_ring_head); + if (!skbuf_dma) + return; + + lp->rx_ring_head++; + skb = netdev_alloc_skb(ndev, lp->max_frm_size); + if (!skb) + return; + + sg_init_table(skbuf_dma->sgl, 1); + addr = dma_map_single(lp->dev, skb->data, lp->max_frm_size, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(lp->dev, addr))) { + if (net_ratelimit()) + netdev_err(ndev, "DMA mapping error\n"); + goto rx_submit_err_free_skb; + } + sg_dma_address(skbuf_dma->sgl) = addr; + sg_dma_len(skbuf_dma->sgl) = lp->max_frm_size; + dma_rx_desc = dmaengine_prep_slave_sg(lp->rx_chan, skbuf_dma->sgl, + 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!dma_rx_desc) + goto rx_submit_err_unmap_skb; + + skbuf_dma->skb = skb; + skbuf_dma->dma_address = sg_dma_address(skbuf_dma->sgl); + skbuf_dma->desc = dma_rx_desc; + dma_rx_desc->callback_param = lp; + dma_rx_desc->callback_result = axienet_dma_rx_cb; + dmaengine_submit(dma_rx_desc); + + return; + +rx_submit_err_unmap_skb: + dma_unmap_single(lp->dev, addr, lp->max_frm_size, DMA_FROM_DEVICE); +rx_submit_err_free_skb: + dev_kfree_skb(skb); +} + +/** + * axienet_init_dmaengine - init the dmaengine code. + * @ndev: Pointer to net_device structure + * + * Return: 0, on success. + * non-zero error value on failure + * + * This is the dmaengine initialization code. + */ +static int axienet_init_dmaengine(struct net_device *ndev) +{ + struct axienet_local *lp = netdev_priv(ndev); + struct skbuf_dma_descriptor *skbuf_dma; + int i, ret; + + lp->tx_chan = dma_request_chan(lp->dev, "tx_chan0"); + if (IS_ERR(lp->tx_chan)) { + dev_err(lp->dev, "No Ethernet DMA (TX) channel found\n"); + return PTR_ERR(lp->tx_chan); + } + + lp->rx_chan = dma_request_chan(lp->dev, "rx_chan0"); + if (IS_ERR(lp->rx_chan)) { + ret = PTR_ERR(lp->rx_chan); + dev_err(lp->dev, "No Ethernet DMA (RX) channel found\n"); + goto err_dma_release_tx; + } + + lp->tx_ring_tail = 0; + lp->tx_ring_head = 0; + lp->rx_ring_tail = 0; + lp->rx_ring_head = 0; + lp->tx_skb_ring = kcalloc(TX_BD_NUM_MAX, sizeof(*lp->tx_skb_ring), + GFP_KERNEL); + if (!lp->tx_skb_ring) { + ret = -ENOMEM; + goto err_dma_release_rx; + } + for (i = 0; i < TX_BD_NUM_MAX; i++) { + skbuf_dma = kzalloc(sizeof(*skbuf_dma), GFP_KERNEL); + if (!skbuf_dma) { + ret = -ENOMEM; + goto err_free_tx_skb_ring; + } + lp->tx_skb_ring[i] = skbuf_dma; + } + + lp->rx_skb_ring = kcalloc(RX_BUF_NUM_DEFAULT, sizeof(*lp->rx_skb_ring), + GFP_KERNEL); + if (!lp->rx_skb_ring) { + ret = -ENOMEM; + goto err_free_tx_skb_ring; + } + for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) { + skbuf_dma = kzalloc(sizeof(*skbuf_dma), GFP_KERNEL); + if (!skbuf_dma) { + ret = -ENOMEM; + goto err_free_rx_skb_ring; + } + lp->rx_skb_ring[i] = skbuf_dma; + } + /* TODO: Instead of BD_NUM_DEFAULT use runtime support */ + for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) + axienet_rx_submit_desc(ndev); + dma_async_issue_pending(lp->rx_chan); + + return 0; + +err_free_rx_skb_ring: + for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) + kfree(lp->rx_skb_ring[i]); + kfree(lp->rx_skb_ring); +err_free_tx_skb_ring: + for (i = 0; i < TX_BD_NUM_MAX; i++) + kfree(lp->tx_skb_ring[i]); + kfree(lp->tx_skb_ring); +err_dma_release_rx: + dma_release_channel(lp->rx_chan); +err_dma_release_tx: + dma_release_channel(lp->tx_chan); + return ret; +} + /** * axienet_init_legacy_dma - init the dma legacy code. * @ndev: Pointer to net_device structure @@ -1216,7 +1532,19 @@ static int axienet_open(struct net_device *ndev) phylink_start(lp->phylink); - if (!lp->use_dmaengine) { + if (lp->use_dmaengine) { + /* Enable interrupts for Axi Ethernet core (if defined) */ + if (lp->eth_irq > 0) { + ret = request_irq(lp->eth_irq, axienet_eth_irq, IRQF_SHARED, + ndev->name, ndev); + if (ret) + goto err_phy; + } + + ret = axienet_init_dmaengine(ndev); + if (ret < 0) + goto err_free_eth_irq; + } else { ret = axienet_init_legacy_dma(ndev); if (ret) goto err_phy; @@ -1224,6 +1552,9 @@ static int axienet_open(struct net_device *ndev) return 0; +err_free_eth_irq: + if (lp->eth_irq > 0) + free_irq(lp->eth_irq, ndev); err_phy: phylink_stop(lp->phylink); phylink_disconnect_phy(lp->phylink); @@ -1243,6 +1574,7 @@ static int axienet_open(struct net_device *ndev) static int axienet_stop(struct net_device *ndev) { struct axienet_local *lp = netdev_priv(ndev); + int i; dev_dbg(&ndev->dev, "axienet_close()\n"); @@ -1263,6 +1595,21 @@ static int axienet_stop(struct net_device *ndev) free_irq(lp->tx_irq, ndev); free_irq(lp->rx_irq, ndev); axienet_dma_bd_release(ndev); + } else { + dmaengine_terminate_sync(lp->tx_chan); + dmaengine_synchronize(lp->tx_chan); + dmaengine_terminate_sync(lp->rx_chan); + dmaengine_synchronize(lp->rx_chan); + + for (i = 0; i < TX_BD_NUM_MAX; i++) + kfree(lp->tx_skb_ring[i]); + kfree(lp->tx_skb_ring); + for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) + kfree(lp->rx_skb_ring[i]); + kfree(lp->rx_skb_ring); + + dma_release_channel(lp->rx_chan); + dma_release_channel(lp->tx_chan); } axienet_iow(lp, XAE_IE_OFFSET, 0); @@ -1365,6 +1712,18 @@ static const struct net_device_ops axienet_netdev_ops = { #endif }; +static const struct net_device_ops axienet_netdev_dmaengine_ops = { + .ndo_open = axienet_open, + .ndo_stop = axienet_stop, + .ndo_start_xmit = axienet_start_xmit_dmaengine, + .ndo_get_stats64 = axienet_get_stats64, + .ndo_change_mtu = axienet_change_mtu, + .ndo_set_mac_address = netdev_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_eth_ioctl = axienet_ioctl, + .ndo_set_rx_mode = axienet_set_multicast_list, +}; + /** * axienet_ethtools_get_drvinfo - Get various Axi Ethernet driver information. * @ndev: Pointer to net_device structure @@ -1897,7 +2256,6 @@ static int axienet_probe(struct platform_device *pdev) SET_NETDEV_DEV(ndev, &pdev->dev); ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ ndev->features = NETIF_F_SG; - ndev->netdev_ops = &axienet_netdev_ops; ndev->ethtool_ops = &axienet_ethtool_ops; /* MTU range: 64 - 9000 */ @@ -2118,8 +2476,39 @@ static int axienet_probe(struct platform_device *pdev) } netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll); netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll); + } else { + struct xilinx_vdma_config cfg; + struct dma_chan *tx_chan; + + lp->eth_irq = platform_get_irq_optional(pdev, 0); + if (lp->eth_irq < 0 && lp->eth_irq != -ENXIO) { + ret = lp->eth_irq; + goto cleanup_clk; + } + tx_chan = dma_request_chan(lp->dev, "tx_chan0"); + if (IS_ERR(tx_chan)) { + ret = PTR_ERR(tx_chan); + dev_err_probe(lp->dev, ret, "No Ethernet DMA (TX) channel found\n"); + goto cleanup_clk; + } + + cfg.reset = 1; + /* As name says VDMA but it has support for DMA channel reset */ + ret = xilinx_vdma_channel_set_config(tx_chan, &cfg); + if (ret < 0) { + dev_err(&pdev->dev, "Reset channel failed\n"); + dma_release_channel(tx_chan); + goto cleanup_clk; + } + + dma_release_channel(tx_chan); + lp->use_dmaengine = 1; } + if (lp->use_dmaengine) + ndev->netdev_ops = &axienet_netdev_dmaengine_ops; + else + ndev->netdev_ops = &axienet_netdev_ops; /* Check for Ethernet core IRQ (optional) */ if (lp->eth_irq <= 0) dev_info(&pdev->dev, "Ethernet core IRQ not defined\n"); From 9eb03bb1c035ff6e2c3a34046419446588253dda Mon Sep 17 00:00:00 2001 From: Yinjun Zhang Date: Fri, 17 Nov 2023 09:11:13 +0200 Subject: [PATCH 1009/7721] nfp: add ethtool flow steering callbacks This is the first part to implement flow steering. The communication between ethtool and driver is done. User can use following commands to display and set flows: ethtool -n ethtool -N flow-type ... Signed-off-by: Yinjun Zhang Signed-off-by: Louis Peens Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231117071114.10667-2-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 36 ++ .../ethernet/netronome/nfp/nfp_net_common.c | 24 ++ .../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 1 + .../ethernet/netronome/nfp/nfp_net_ethtool.c | 369 ++++++++++++++++++ 4 files changed, 430 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 939cfce15830..bd0e26524417 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -621,6 +621,9 @@ struct nfp_net_dp { * @mbox_amsg.lock: Protect message list * @mbox_amsg.list: List of message to process * @mbox_amsg.work: Work to process message asynchronously + * @fs: Flow steering + * @fs.count: Flow count + * @fs.list: List of flows * @app_priv: APP private data for this vNIC */ struct nfp_net { @@ -728,9 +731,39 @@ struct nfp_net { struct work_struct work; } mbox_amsg; + struct { + u16 count; + struct list_head list; + } fs; + void *app_priv; }; +struct nfp_fs_entry { + struct list_head node; + u32 flow_type; + u32 loc; + struct { + union { + struct { + __be32 sip4; + __be32 dip4; + }; + struct { + __be32 sip6[4]; + __be32 dip6[4]; + }; + }; + union { + __be16 l3_proto; + u8 l4_proto; + }; + __be16 sport; + __be16 dport; + } key, msk; + u64 action; +}; + struct nfp_mbox_amsg_entry { struct list_head list; int (*cfg)(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry); @@ -987,6 +1020,9 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn); int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new, struct netlink_ext_ack *extack); +int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry); +int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry); + #ifdef CONFIG_NFP_DEBUG void nfp_net_debugfs_create(void); void nfp_net_debugfs_destroy(void); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index de0a5d5ded30..12eda2c2ac23 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1763,6 +1763,27 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) return nfp_net_mbox_reconfig_and_unlock(nn, cmd); } +int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry) +{ + return -EOPNOTSUPP; +} + +int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry) +{ + return -EOPNOTSUPP; +} + +static void nfp_net_fs_clean(struct nfp_net *nn) +{ + struct nfp_fs_entry *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, &nn->fs.list, node) { + nfp_net_fs_del_hw(nn, entry); + list_del(&entry->node); + kfree(entry); + } +} + static void nfp_net_stat64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { @@ -2740,6 +2761,8 @@ int nfp_net_init(struct nfp_net *nn) INIT_LIST_HEAD(&nn->mbox_amsg.list); INIT_WORK(&nn->mbox_amsg.work, nfp_net_mbox_amsg_work); + INIT_LIST_HEAD(&nn->fs.list); + return register_netdev(nn->dp.netdev); err_clean_mbox: @@ -2759,6 +2782,7 @@ void nfp_net_clean(struct nfp_net *nn) unregister_netdev(nn->dp.netdev); nfp_net_ipsec_clean(nn); nfp_ccm_mbox_clean(nn); + nfp_net_fs_clean(nn); flush_work(&nn->mbox_amsg.work); nfp_net_reconfig_wait_posted(nn); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 3e63f6d6a563..515472924a5d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -269,6 +269,7 @@ #define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /* IPsec offload */ #define NFP_NET_CFG_CTRL_MCAST_FILTER (0x1 << 2) /* Multicast Filter */ #define NFP_NET_CFG_CTRL_FREELIST_EN (0x1 << 6) /* Freelist enable flag bit */ +#define NFP_NET_CFG_CTRL_FLOW_STEER (0x1 << 8) /* Flow steering */ #define NFP_NET_CFG_CAP_WORD1 0x00a4 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index e75cbb287625..d7896391b8ba 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -1317,6 +1317,116 @@ static int nfp_net_get_rss_hash_opts(struct nfp_net *nn, return 0; } +#define NFP_FS_MAX_ENTRY 1024 + +static int nfp_net_fs_to_ethtool(struct nfp_fs_entry *entry, struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fs = &cmd->fs; + unsigned int i; + + switch (entry->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + fs->h_u.tcp_ip4_spec.ip4src = entry->key.sip4; + fs->h_u.tcp_ip4_spec.ip4dst = entry->key.dip4; + fs->h_u.tcp_ip4_spec.psrc = entry->key.sport; + fs->h_u.tcp_ip4_spec.pdst = entry->key.dport; + fs->m_u.tcp_ip4_spec.ip4src = entry->msk.sip4; + fs->m_u.tcp_ip4_spec.ip4dst = entry->msk.dip4; + fs->m_u.tcp_ip4_spec.psrc = entry->msk.sport; + fs->m_u.tcp_ip4_spec.pdst = entry->msk.dport; + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + for (i = 0; i < 4; i++) { + fs->h_u.tcp_ip6_spec.ip6src[i] = entry->key.sip6[i]; + fs->h_u.tcp_ip6_spec.ip6dst[i] = entry->key.dip6[i]; + fs->m_u.tcp_ip6_spec.ip6src[i] = entry->msk.sip6[i]; + fs->m_u.tcp_ip6_spec.ip6dst[i] = entry->msk.dip6[i]; + } + fs->h_u.tcp_ip6_spec.psrc = entry->key.sport; + fs->h_u.tcp_ip6_spec.pdst = entry->key.dport; + fs->m_u.tcp_ip6_spec.psrc = entry->msk.sport; + fs->m_u.tcp_ip6_spec.pdst = entry->msk.dport; + break; + case IPV4_USER_FLOW: + fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + fs->h_u.usr_ip4_spec.ip4src = entry->key.sip4; + fs->h_u.usr_ip4_spec.ip4dst = entry->key.dip4; + fs->h_u.usr_ip4_spec.proto = entry->key.l4_proto; + fs->m_u.usr_ip4_spec.ip4src = entry->msk.sip4; + fs->m_u.usr_ip4_spec.ip4dst = entry->msk.dip4; + fs->m_u.usr_ip4_spec.proto = entry->msk.l4_proto; + break; + case IPV6_USER_FLOW: + for (i = 0; i < 4; i++) { + fs->h_u.usr_ip6_spec.ip6src[i] = entry->key.sip6[i]; + fs->h_u.usr_ip6_spec.ip6dst[i] = entry->key.dip6[i]; + fs->m_u.usr_ip6_spec.ip6src[i] = entry->msk.sip6[i]; + fs->m_u.usr_ip6_spec.ip6dst[i] = entry->msk.dip6[i]; + } + fs->h_u.usr_ip6_spec.l4_proto = entry->key.l4_proto; + fs->m_u.usr_ip6_spec.l4_proto = entry->msk.l4_proto; + break; + case ETHER_FLOW: + fs->h_u.ether_spec.h_proto = entry->key.l3_proto; + fs->m_u.ether_spec.h_proto = entry->msk.l3_proto; + break; + default: + return -EINVAL; + } + + fs->flow_type = entry->flow_type; + fs->ring_cookie = entry->action; + + if (fs->flow_type & FLOW_RSS) { + /* Only rss_context of 0 is supported. */ + cmd->rss_context = 0; + /* RSS is used, mask the ring. */ + fs->ring_cookie |= ETHTOOL_RX_FLOW_SPEC_RING; + } + + return 0; +} + +static int nfp_net_get_fs_rule(struct nfp_net *nn, struct ethtool_rxnfc *cmd) +{ + struct nfp_fs_entry *entry; + + if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER)) + return -EOPNOTSUPP; + + if (cmd->fs.location >= NFP_FS_MAX_ENTRY) + return -EINVAL; + + list_for_each_entry(entry, &nn->fs.list, node) { + if (entry->loc == cmd->fs.location) + return nfp_net_fs_to_ethtool(entry, cmd); + + if (entry->loc > cmd->fs.location) + /* no need to continue */ + return -ENOENT; + } + + return -ENOENT; +} + +static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs) +{ + struct nfp_fs_entry *entry; + u32 count = 0; + + if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER)) + return -EOPNOTSUPP; + + list_for_each_entry(entry, &nn->fs.list, node) + rule_locs[count++] = entry->loc; + + return 0; +} + static int nfp_net_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, u32 *rule_locs) { @@ -1326,6 +1436,14 @@ static int nfp_net_get_rxnfc(struct net_device *netdev, case ETHTOOL_GRXRINGS: cmd->data = nn->dp.num_rx_rings; return 0; + case ETHTOOL_GRXCLSRLCNT: + cmd->rule_cnt = nn->fs.count; + return 0; + case ETHTOOL_GRXCLSRULE: + return nfp_net_get_fs_rule(nn, cmd); + case ETHTOOL_GRXCLSRLALL: + cmd->data = NFP_FS_MAX_ENTRY; + return nfp_net_get_fs_loc(nn, rule_locs); case ETHTOOL_GRXFH: return nfp_net_get_rss_hash_opts(nn, cmd); default: @@ -1385,6 +1503,253 @@ static int nfp_net_set_rss_hash_opt(struct nfp_net *nn, return 0; } +static int nfp_net_fs_from_ethtool(struct nfp_fs_entry *entry, struct ethtool_rx_flow_spec *fs) +{ + unsigned int i; + + /* FLOW_EXT/FLOW_MAC_EXT is not supported. */ + switch (fs->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + entry->msk.sip4 = fs->m_u.tcp_ip4_spec.ip4src; + entry->msk.dip4 = fs->m_u.tcp_ip4_spec.ip4dst; + entry->msk.sport = fs->m_u.tcp_ip4_spec.psrc; + entry->msk.dport = fs->m_u.tcp_ip4_spec.pdst; + entry->key.sip4 = fs->h_u.tcp_ip4_spec.ip4src & entry->msk.sip4; + entry->key.dip4 = fs->h_u.tcp_ip4_spec.ip4dst & entry->msk.dip4; + entry->key.sport = fs->h_u.tcp_ip4_spec.psrc & entry->msk.sport; + entry->key.dport = fs->h_u.tcp_ip4_spec.pdst & entry->msk.dport; + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + for (i = 0; i < 4; i++) { + entry->msk.sip6[i] = fs->m_u.tcp_ip6_spec.ip6src[i]; + entry->msk.dip6[i] = fs->m_u.tcp_ip6_spec.ip6dst[i]; + entry->key.sip6[i] = fs->h_u.tcp_ip6_spec.ip6src[i] & entry->msk.sip6[i]; + entry->key.dip6[i] = fs->h_u.tcp_ip6_spec.ip6dst[i] & entry->msk.dip6[i]; + } + entry->msk.sport = fs->m_u.tcp_ip6_spec.psrc; + entry->msk.dport = fs->m_u.tcp_ip6_spec.pdst; + entry->key.sport = fs->h_u.tcp_ip6_spec.psrc & entry->msk.sport; + entry->key.dport = fs->h_u.tcp_ip6_spec.pdst & entry->msk.dport; + break; + case IPV4_USER_FLOW: + entry->msk.sip4 = fs->m_u.usr_ip4_spec.ip4src; + entry->msk.dip4 = fs->m_u.usr_ip4_spec.ip4dst; + entry->msk.l4_proto = fs->m_u.usr_ip4_spec.proto; + entry->key.sip4 = fs->h_u.usr_ip4_spec.ip4src & entry->msk.sip4; + entry->key.dip4 = fs->h_u.usr_ip4_spec.ip4dst & entry->msk.dip4; + entry->key.l4_proto = fs->h_u.usr_ip4_spec.proto & entry->msk.l4_proto; + break; + case IPV6_USER_FLOW: + for (i = 0; i < 4; i++) { + entry->msk.sip6[i] = fs->m_u.usr_ip6_spec.ip6src[i]; + entry->msk.dip6[i] = fs->m_u.usr_ip6_spec.ip6dst[i]; + entry->key.sip6[i] = fs->h_u.usr_ip6_spec.ip6src[i] & entry->msk.sip6[i]; + entry->key.dip6[i] = fs->h_u.usr_ip6_spec.ip6dst[i] & entry->msk.dip6[i]; + } + entry->msk.l4_proto = fs->m_u.usr_ip6_spec.l4_proto; + entry->key.l4_proto = fs->h_u.usr_ip6_spec.l4_proto & entry->msk.l4_proto; + break; + case ETHER_FLOW: + entry->msk.l3_proto = fs->m_u.ether_spec.h_proto; + entry->key.l3_proto = fs->h_u.ether_spec.h_proto & entry->msk.l3_proto; + break; + default: + return -EINVAL; + } + + switch (fs->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case TCP_V6_FLOW: + entry->key.l4_proto = IPPROTO_TCP; + entry->msk.l4_proto = 0xff; + break; + case UDP_V4_FLOW: + case UDP_V6_FLOW: + entry->key.l4_proto = IPPROTO_UDP; + entry->msk.l4_proto = 0xff; + break; + case SCTP_V4_FLOW: + case SCTP_V6_FLOW: + entry->key.l4_proto = IPPROTO_SCTP; + entry->msk.l4_proto = 0xff; + break; + } + + entry->flow_type = fs->flow_type; + entry->action = fs->ring_cookie; + entry->loc = fs->location; + + return 0; +} + +static int nfp_net_fs_check_existing(struct nfp_net *nn, struct nfp_fs_entry *new) +{ + struct nfp_fs_entry *entry; + + list_for_each_entry(entry, &nn->fs.list, node) { + if (new->loc != entry->loc && + !((new->flow_type ^ entry->flow_type) & ~FLOW_RSS) && + !memcmp(&new->key, &entry->key, sizeof(new->key)) && + !memcmp(&new->msk, &entry->msk, sizeof(new->msk))) + return entry->loc; + } + + /* -1 means no duplicates */ + return -1; +} + +static int nfp_net_fs_add(struct nfp_net *nn, struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fs = &cmd->fs; + struct nfp_fs_entry *new, *entry; + bool unsupp_mask; + int err, id; + + if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER)) + return -EOPNOTSUPP; + + /* Only default RSS context(0) is supported. */ + if ((fs->flow_type & FLOW_RSS) && cmd->rss_context) + return -EOPNOTSUPP; + + if (fs->location >= NFP_FS_MAX_ENTRY) + return -EINVAL; + + if (fs->ring_cookie != RX_CLS_FLOW_DISC && + fs->ring_cookie >= nn->dp.num_rx_rings) + return -EINVAL; + + /* FLOW_EXT/FLOW_MAC_EXT is not supported. */ + switch (fs->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + unsupp_mask = !!fs->m_u.tcp_ip4_spec.tos; + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + unsupp_mask = !!fs->m_u.tcp_ip6_spec.tclass; + break; + case IPV4_USER_FLOW: + unsupp_mask = !!fs->m_u.usr_ip4_spec.l4_4_bytes || + !!fs->m_u.usr_ip4_spec.tos || + !!fs->m_u.usr_ip4_spec.ip_ver; + /* ip_ver must be ETH_RX_NFC_IP4. */ + unsupp_mask |= fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4; + break; + case IPV6_USER_FLOW: + unsupp_mask = !!fs->m_u.usr_ip6_spec.l4_4_bytes || + !!fs->m_u.usr_ip6_spec.tclass; + break; + case ETHER_FLOW: + if (fs->h_u.ether_spec.h_proto == htons(ETH_P_IP) || + fs->h_u.ether_spec.h_proto == htons(ETH_P_IPV6)) { + nn_err(nn, "Please use ip4/ip6 flow type instead.\n"); + return -EOPNOTSUPP; + } + /* Only unmasked ethtype is supported. */ + unsupp_mask = !is_zero_ether_addr(fs->m_u.ether_spec.h_dest) || + !is_zero_ether_addr(fs->m_u.ether_spec.h_source) || + (fs->m_u.ether_spec.h_proto != htons(0xffff)); + break; + default: + return -EOPNOTSUPP; + } + + if (unsupp_mask) + return -EOPNOTSUPP; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + nfp_net_fs_from_ethtool(new, fs); + + id = nfp_net_fs_check_existing(nn, new); + if (id >= 0) { + nn_err(nn, "Identical rule is existing in %d.\n", id); + err = -EINVAL; + goto err; + } + + /* Insert to list in ascending order of location. */ + list_for_each_entry(entry, &nn->fs.list, node) { + if (entry->loc == fs->location) { + err = nfp_net_fs_del_hw(nn, entry); + if (err) + goto err; + + nn->fs.count--; + err = nfp_net_fs_add_hw(nn, new); + if (err) + goto err; + + nn->fs.count++; + list_replace(&entry->node, &new->node); + kfree(entry); + + return 0; + } + + if (entry->loc > fs->location) + break; + } + + if (nn->fs.count == NFP_FS_MAX_ENTRY) { + err = -ENOSPC; + goto err; + } + + err = nfp_net_fs_add_hw(nn, new); + if (err) + goto err; + + list_add_tail(&new->node, &entry->node); + nn->fs.count++; + + return 0; + +err: + kfree(new); + return err; +} + +static int nfp_net_fs_del(struct nfp_net *nn, struct ethtool_rxnfc *cmd) +{ + struct nfp_fs_entry *entry; + int err; + + if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER)) + return -EOPNOTSUPP; + + if (!nn->fs.count || cmd->fs.location >= NFP_FS_MAX_ENTRY) + return -EINVAL; + + list_for_each_entry(entry, &nn->fs.list, node) { + if (entry->loc == cmd->fs.location) { + err = nfp_net_fs_del_hw(nn, entry); + if (err) + return err; + + list_del(&entry->node); + kfree(entry); + nn->fs.count--; + + return 0; + } else if (entry->loc > cmd->fs.location) { + /* no need to continue */ + break; + } + } + + return -ENOENT; +} + static int nfp_net_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) { @@ -1393,6 +1758,10 @@ static int nfp_net_set_rxnfc(struct net_device *netdev, switch (cmd->cmd) { case ETHTOOL_SRXFH: return nfp_net_set_rss_hash_opt(nn, cmd); + case ETHTOOL_SRXCLSRLINS: + return nfp_net_fs_add(nn, cmd); + case ETHTOOL_SRXCLSRLDEL: + return nfp_net_fs_del(nn, cmd); default: return -EOPNOTSUPP; } From c38fb3dcd53dbfc68eb429e8ecb0ec795f0d6ba1 Mon Sep 17 00:00:00 2001 From: Yinjun Zhang Date: Fri, 17 Nov 2023 09:11:14 +0200 Subject: [PATCH 1010/7721] nfp: offload flow steering to the nfp This is the second part to implement flow steering. Mailbox is used for the communication between driver and HW. Signed-off-by: Yinjun Zhang Signed-off-by: Louis Peens Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231117071114.10667-3-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- .../ethernet/netronome/nfp/nfp_net_common.c | 163 +++++++++++++++++- .../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 14 ++ 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 12eda2c2ac23..ac1f4514b1d0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1763,14 +1763,173 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) return nfp_net_mbox_reconfig_and_unlock(nn, cmd); } +static void +nfp_net_fs_fill_v4(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr) +{ + unsigned int i; + + union { + struct { + __be16 loc; + u8 k_proto, m_proto; + __be32 k_sip, m_sip, k_dip, m_dip; + __be16 k_sport, m_sport, k_dport, m_dport; + }; + __be32 val[7]; + } v4_rule; + + nn_writel(nn, *addr, op); + *addr += sizeof(u32); + + v4_rule.loc = cpu_to_be16(entry->loc); + v4_rule.k_proto = entry->key.l4_proto; + v4_rule.m_proto = entry->msk.l4_proto; + v4_rule.k_sip = entry->key.sip4; + v4_rule.m_sip = entry->msk.sip4; + v4_rule.k_dip = entry->key.dip4; + v4_rule.m_dip = entry->msk.dip4; + v4_rule.k_sport = entry->key.sport; + v4_rule.m_sport = entry->msk.sport; + v4_rule.k_dport = entry->key.dport; + v4_rule.m_dport = entry->msk.dport; + + for (i = 0; i < ARRAY_SIZE(v4_rule.val); i++, *addr += sizeof(__be32)) + nn_writel(nn, *addr, be32_to_cpu(v4_rule.val[i])); +} + +static void +nfp_net_fs_fill_v6(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr) +{ + unsigned int i; + + union { + struct { + __be16 loc; + u8 k_proto, m_proto; + __be32 k_sip[4], m_sip[4], k_dip[4], m_dip[4]; + __be16 k_sport, m_sport, k_dport, m_dport; + }; + __be32 val[19]; + } v6_rule; + + nn_writel(nn, *addr, op); + *addr += sizeof(u32); + + v6_rule.loc = cpu_to_be16(entry->loc); + v6_rule.k_proto = entry->key.l4_proto; + v6_rule.m_proto = entry->msk.l4_proto; + for (i = 0; i < 4; i++) { + v6_rule.k_sip[i] = entry->key.sip6[i]; + v6_rule.m_sip[i] = entry->msk.sip6[i]; + v6_rule.k_dip[i] = entry->key.dip6[i]; + v6_rule.m_dip[i] = entry->msk.dip6[i]; + } + v6_rule.k_sport = entry->key.sport; + v6_rule.m_sport = entry->msk.sport; + v6_rule.k_dport = entry->key.dport; + v6_rule.m_dport = entry->msk.dport; + + for (i = 0; i < ARRAY_SIZE(v6_rule.val); i++, *addr += sizeof(__be32)) + nn_writel(nn, *addr, be32_to_cpu(v6_rule.val[i])); +} + +#define NFP_FS_QUEUE_ID GENMASK(22, 16) +#define NFP_FS_ACT GENMASK(15, 0) +#define NFP_FS_ACT_DROP BIT(0) +#define NFP_FS_ACT_Q BIT(1) +static void +nfp_net_fs_fill_act(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 addr) +{ + u32 action = 0; /* 0 means default passthrough */ + + if (entry->action == RX_CLS_FLOW_DISC) + action = NFP_FS_ACT_DROP; + else if (!(entry->flow_type & FLOW_RSS)) + action = FIELD_PREP(NFP_FS_QUEUE_ID, entry->action) | NFP_FS_ACT_Q; + + nn_writel(nn, addr, action); +} + int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry) { - return -EOPNOTSUPP; + u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL; + int err; + + err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ); + if (err) + return err; + + switch (entry->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + case IPV4_USER_FLOW: + nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V4, &addr); + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + case IPV6_USER_FLOW: + nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V6, &addr); + break; + case ETHER_FLOW: + nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE); + addr += sizeof(u32); + nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto)); + addr += sizeof(u32); + break; + } + + nfp_net_fs_fill_act(nn, entry, addr); + + err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER); + if (err) { + nn_err(nn, "Add new fs rule failed with %d\n", err); + return -EIO; + } + + return 0; } int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry) { - return -EOPNOTSUPP; + u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL; + int err; + + err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ); + if (err) + return err; + + switch (entry->flow_type & ~FLOW_RSS) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + case IPV4_USER_FLOW: + nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V4, &addr); + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + case IPV6_USER_FLOW: + nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V6, &addr); + break; + case ETHER_FLOW: + nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE); + addr += sizeof(u32); + nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto)); + addr += sizeof(u32); + break; + } + + nfp_net_fs_fill_act(nn, entry, addr); + + err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER); + if (err) { + nn_err(nn, "Delete fs rule failed with %d\n", err); + return -EIO; + } + + return 0; } static void nfp_net_fs_clean(struct nfp_net *nn) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 515472924a5d..eaf4d3c499d1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -419,6 +419,8 @@ #define NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD 8 #define NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL 9 +#define NFP_NET_CFG_MBOX_CMD_FLOW_STEER 10 + /* VLAN filtering using general use mailbox * %NFP_NET_CFG_VLAN_FILTER: Base address of VLAN filter mailbox * %NFP_NET_CFG_VLAN_FILTER_VID: VLAN ID to filter @@ -441,6 +443,18 @@ #define NFP_NET_CFG_MULTICAST_MAC_LO (NFP_NET_CFG_MULTICAST + 6) #define NFP_NET_CFG_MULTICAST_SZ 0x0006 +/* Max size of FS rules in bytes */ +#define NFP_NET_CFG_FS_SZ 0x0054 +/* Sub commands for FS */ +enum { + NFP_NET_CFG_MBOX_CMD_FS_ADD_V4, + NFP_NET_CFG_MBOX_CMD_FS_DEL_V4, + NFP_NET_CFG_MBOX_CMD_FS_ADD_V6, + NFP_NET_CFG_MBOX_CMD_FS_DEL_V6, + NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE, + NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE, +}; + /* TLV capabilities * %NFP_NET_CFG_TLV_TYPE: Offset of type within the TLV * %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV From 025de7b6a6dd44e78d0d45b4f3b4f104ed54b0fd Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:03 -0300 Subject: [PATCH 1011/7721] selftests: tc-testing: cap parallel tdc to 4 cores We have observed a lot of lock contention and test instability when running with >8 cores. Enough to actually make the tests run slower than with fewer cores. Cap the maximum cores of parallel tdc to 4 which showed in testing to be a reasonable number for efficiency and stability in different kernel config scenarios. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-2-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tdc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index a6718192aff3..f764b43f112b 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -1017,6 +1017,7 @@ def main(): parser = pm.call_add_args(parser) (args, remaining) = parser.parse_known_args() args.NAMES = NAMES + args.mp = min(args.mp, 4) pm.set_args(args) check_default_settings(args, remaining, pm) if args.verbose > 2: From 50a5988a7a540fb1ad4e620e1bbf11cc646e3dc7 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:04 -0300 Subject: [PATCH 1012/7721] selftests: tc-testing: move back to per test ns setup Surprisingly in kernel configs with most of the debug knobs turned on, pre-allocating the test resources makes tdc run much slower overall than when allocating resources on a per test basis. As these knobs are used in kselftests in downstream CIs, let's go back to the old way of doing things to avoid kselftests timeouts. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202311161129.3b45ed53-oliver.sang@intel.com Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-3-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/plugin-lib/nsPlugin.py | 68 +++++++------------ 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 62974bd3a4a5..2b8cbfdf1083 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -17,44 +17,6 @@ except ImportError: netlink = False print("!!! Consider installing pyroute2 !!!") -def prepare_suite(obj, test): - original = obj.args.NAMES - - if 'skip' in test and test['skip'] == 'yes': - return - - if 'nsPlugin' not in test['plugins']: - return - - shadow = {} - shadow['IP'] = original['IP'] - shadow['TC'] = original['TC'] - shadow['NS'] = '{}-{}'.format(original['NS'], test['random']) - shadow['DEV0'] = '{}id{}'.format(original['DEV0'], test['id']) - shadow['DEV1'] = '{}id{}'.format(original['DEV1'], test['id']) - shadow['DUMMY'] = '{}id{}'.format(original['DUMMY'], test['id']) - shadow['DEV2'] = original['DEV2'] - obj.args.NAMES = shadow - - if netlink == True: - obj._nl_ns_create() - else: - obj._ns_create() - - # Make sure the netns is visible in the fs - while True: - obj._proc_check() - try: - ns = obj.args.NAMES['NS'] - f = open('/run/netns/{}'.format(ns)) - f.close() - break - except: - time.sleep(0.1) - continue - - obj.args.NAMES = original - class SubPlugin(TdcPlugin): def __init__(self): self.sub_class = 'ns/SubPlugin' @@ -65,19 +27,39 @@ class SubPlugin(TdcPlugin): super().pre_suite(testcount, testlist) - print("Setting up namespaces and devices...") + def prepare_test(self, test): + if 'skip' in test and test['skip'] == 'yes': + return - with Pool(self.args.mp) as p: - it = zip(cycle([self]), testlist) - p.starmap(prepare_suite, it) + if 'nsPlugin' not in test['plugins']: + return - def pre_case(self, caseinfo, test_skip): + if netlink == True: + self._nl_ns_create() + else: + self._ns_create() + + # Make sure the netns is visible in the fs + while True: + self._proc_check() + try: + ns = self.args.NAMES['NS'] + f = open('/run/netns/{}'.format(ns)) + f.close() + break + except: + time.sleep(0.1) + continue + + def pre_case(self, test, test_skip): if self.args.verbose: print('{}.pre_case'.format(self.sub_class)) if test_skip: return + self.prepare_test(test) + def post_case(self): if self.args.verbose: print('{}.post_case'.format(self.sub_class)) From 3d5026fc5adbc796a0547fcef19d997786e0bb31 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:05 -0300 Subject: [PATCH 1013/7721] selftests: tc-testing: use netns delete from pyroute2 When pyroute2 is available, use the native netns delete routine instead of calling iproute2 to do it. As forks are expensive with some kernel configs, minimize its usage to avoid kselftests timeouts. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-4-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/tc-testing/plugin-lib/nsPlugin.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 2b8cbfdf1083..920dcbedc395 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -64,7 +64,10 @@ class SubPlugin(TdcPlugin): if self.args.verbose: print('{}.post_case'.format(self.sub_class)) - self._ns_destroy() + if netlink == True: + self._nl_ns_destroy() + else: + self._ns_destroy() def post_suite(self, index): if self.args.verbose: @@ -174,6 +177,10 @@ class SubPlugin(TdcPlugin): ''' self._exec_cmd_batched('pre', self._ns_create_cmds()) + def _nl_ns_destroy(self): + ns = self.args.NAMES['NS'] + netns.remove(ns) + def _ns_destroy_cmd(self): return self._replace_keywords('netns delete {}'.format(self.args.NAMES['NS'])) From 3f2d94a4ff489ebbc6b66cc33f9775cb33c00533 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:06 -0300 Subject: [PATCH 1014/7721] selftests: tc-testing: leverage -all in suite ns teardown Instead of listing lingering ns pinned files and delete them one by one, leverage '-all' from iproute2 to do it in a single process fork. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-5-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/tc-testing/plugin-lib/nsPlugin.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 920dcbedc395..7b674befceec 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -74,13 +74,12 @@ class SubPlugin(TdcPlugin): print('{}.post_suite'.format(self.sub_class)) # Make sure we don't leak resources - for f in os.listdir('/run/netns/'): - cmd = self._replace_keywords("$IP netns del {}".format(f)) + cmd = "$IP -a netns del" - if self.args.verbose > 3: - print('_exec_cmd: command "{}"'.format(cmd)) + if self.args.verbose > 3: + print('_exec_cmd: command "{}"'.format(cmd)) - subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def adjust_command(self, stage, command): super().adjust_command(stage, command) From 4b480cfb1066a8394017697ff4a58a970641e9b7 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:07 -0300 Subject: [PATCH 1015/7721] selftests: tc-testing: timeout on unbounded loops In the spirit of failing early, timeout on unbounded loops that take longer than 20 ticks to complete. Such loops are to ensure that objects created are already visible so tests can proceed without any issues. If a test setup takes more than 20 ticks to see an object, there's definetely something wrong. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-6-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/plugin-lib/nsPlugin.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 7b674befceec..65c8f3f983b9 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -40,7 +40,10 @@ class SubPlugin(TdcPlugin): self._ns_create() # Make sure the netns is visible in the fs + ticks = 20 while True: + if ticks == 0: + raise TimeoutError self._proc_check() try: ns = self.args.NAMES['NS'] @@ -49,6 +52,7 @@ class SubPlugin(TdcPlugin): break except: time.sleep(0.1) + ticks -= 1 continue def pre_case(self, test, test_skip): @@ -127,7 +131,10 @@ class SubPlugin(TdcPlugin): with IPRoute() as ip: ip.link('add', ifname=dev1, kind='veth', peer={'ifname': dev0, 'net_ns_fd':'/proc/1/ns/net'}) ip.link('add', ifname=dummy, kind='dummy') + ticks = 20 while True: + if ticks == 0: + raise TimeoutError try: dev1_idx = ip.link_lookup(ifname=dev1)[0] dummy_idx = ip.link_lookup(ifname=dummy)[0] @@ -136,17 +143,22 @@ class SubPlugin(TdcPlugin): break except: time.sleep(0.1) + ticks -= 1 continue netns.popns() with IPRoute() as ip: + ticks = 20 while True: + if ticks == 0: + raise TimeoutError try: dev0_idx = ip.link_lookup(ifname=dev0)[0] ip.link('set', index=dev0_idx, state='up') break except: time.sleep(0.1) + ticks -= 1 continue def _ns_create_cmds(self): From 4968afa0143dbff8a84b5ce3c302dd7d0bdcfa48 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 17 Nov 2023 14:12:08 -0300 Subject: [PATCH 1016/7721] selftests: tc-testing: report number of workers in use Report the number of workers in use to process the test batches. Since the number is now subject to a limit, avoid users getting confused. Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231117171208.2066136-7-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tdc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index f764b43f112b..669ec89ebfe1 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -616,7 +616,7 @@ def test_runner_mp(pm, args, alltests): batches.insert(0, serial) print("Executing {} tests in parallel and {} in serial".format(len(parallel), len(serial))) - print("Using {} batches".format(len(batches))) + print("Using {} batches and {} workers".format(len(batches), args.mp)) # We can't pickle these objects so workaround them global mp_pm From 31c54867fdea452023cc5faba939a6afec1b9d7e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Nov 2023 17:42:59 +0100 Subject: [PATCH 1017/7721] net: ethernet: mtk_wed: add support for devices with more than 4GB of dram Introduce WED offloading support for boards with more than 4GB of memory. Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/1c7efdf5d384ea7af3c0209723e40b2ee0f956bf.1700239272.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 ++++- drivers/net/ethernet/mediatek/mtk_wed.c | 8 +++++--- drivers/net/ethernet/mediatek/mtk_wed_wo.c | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 3cf6589cfdac..a6e91573f8da 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1159,15 +1159,18 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); for (i = 0; i < cnt; i++) { + dma_addr_t addr = dma_addr + i * MTK_QDMA_PAGE_SIZE; struct mtk_tx_dma_v2 *txd; txd = eth->scratch_ring + i * soc->txrx.txd_size; - txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; + txd->txd1 = addr; if (i < cnt - 1) txd->txd2 = eth->phy_scratch_ring + (i + 1) * soc->txrx.txd_size; txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); + if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA)) + txd->txd3 |= TX_DMA_PREP_ADDR64(addr); txd->txd4 = 0; if (mtk_is_netsys_v2_or_greater(eth)) { txd->txd5 = 0; diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 2ac35543fcfb..c895e265ae0e 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -691,10 +691,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) { struct mtk_wdma_desc *desc = desc_ptr; + u32 ctrl; desc->buf0 = cpu_to_le32(buf_phys); if (!mtk_wed_is_v3_or_greater(dev->hw)) { - u32 txd_size, ctrl; + u32 txd_size; txd_size = dev->wlan.init_buf(buf, buf_phys, token++); @@ -708,11 +709,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 | FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2, MTK_WED_BUF_SIZE - txd_size); - desc->ctrl = cpu_to_le32(ctrl); desc->info = 0; } else { - desc->ctrl = cpu_to_le32(token << 16); + ctrl = token << 16 | TX_DMA_PREP_ADDR64(buf_phys); } + desc->ctrl = cpu_to_le32(ctrl); desc_ptr += desc_size; buf += MTK_WED_BUF_SIZE; @@ -811,6 +812,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev) buf_phys = page_phys; for (s = 0; s < MTK_WED_RX_BUF_PER_PAGE; s++) { desc->buf0 = cpu_to_le32(buf_phys); + desc->token = cpu_to_le32(RX_DMA_PREP_ADDR64(buf_phys)); buf_phys += MTK_WED_PAGE_BUF_SIZE; desc++; } diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c index 3bd51a3d6650..7ffbd4fca881 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c @@ -142,7 +142,8 @@ mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, dma_addr_t addr; void *buf; - buf = page_frag_alloc(&q->cache, q->buf_size, GFP_ATOMIC); + buf = page_frag_alloc(&q->cache, q->buf_size, + GFP_ATOMIC | GFP_DMA32); if (!buf) break; From f6afe4f09f6605b725b39670b3568ab2927c9b43 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 10 Oct 2023 08:54:25 +0300 Subject: [PATCH 1018/7721] drm/msm: don't create GPU-related debugfs files with no GPU present If there is no GPU present, skip creation of the GPU-related debugfs files, making the MSM's debugfs more usable. Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/561742/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_debugfs.c | 41 +++++++++++++++++++------------ drivers/gpu/drm/msm/msm_rd.c | 3 +++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 04d304eed223..4494f6d1c7cb 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -304,36 +304,21 @@ int msm_debugfs_late_init(struct drm_device *dev) return ret; } -void msm_debugfs_init(struct drm_minor *minor) +static void msm_debugfs_gpu_init(struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct msm_drm_private *priv = dev->dev_private; struct dentry *gpu_devfreq; - drm_debugfs_create_files(msm_debugfs_list, - ARRAY_SIZE(msm_debugfs_list), - minor->debugfs_root, minor); - debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, dev, &msm_gpu_fops); - if (priv->kms) { - drm_debugfs_create_files(msm_kms_debugfs_list, - ARRAY_SIZE(msm_kms_debugfs_list), - minor->debugfs_root, minor); - debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, - dev, &msm_kms_fops); - } - debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root, &priv->hangcheck_period); debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root, &priv->disable_err_irq); - debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, - dev, &shrink_fops); - gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root); debugfs_create_bool("idle_clamp",0600, gpu_devfreq, @@ -344,6 +329,30 @@ void msm_debugfs_init(struct drm_minor *minor) debugfs_create_u32("downdifferential",0600, gpu_devfreq, &priv->gpu_devfreq_config.downdifferential); +} + +void msm_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + + drm_debugfs_create_files(msm_debugfs_list, + ARRAY_SIZE(msm_debugfs_list), + minor->debugfs_root, minor); + + if (priv->gpu_pdev) + msm_debugfs_gpu_init(minor); + + if (priv->kms) { + drm_debugfs_create_files(msm_kms_debugfs_list, + ARRAY_SIZE(msm_kms_debugfs_list), + minor->debugfs_root, minor); + debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, + dev, &msm_kms_fops); + } + + debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, + dev, &shrink_fops); if (priv->kms && priv->kms->funcs->debugfs_init) priv->kms->funcs->debugfs_init(priv->kms, minor); diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 5adc51f7ab59..ca44fd291c5b 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -270,6 +270,9 @@ int msm_rd_debugfs_init(struct drm_minor *minor) struct msm_rd_state *rd; int ret; + if (!priv->gpu_pdev) + return 0; + /* only create on first minor: */ if (priv->rd) return 0; From d1912f6972b857e63577e8094f5f1242d9fe3c7d Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 6 Nov 2023 10:50:25 -0800 Subject: [PATCH 1019/7721] drm/msm: Small uabi fixes Correct the minor version exposed and error return value for MSM_INFO_GET_NAME. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/566155/ --- drivers/gpu/drm/msm/msm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 2aae7d107f33..d751d2023f84 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -39,7 +39,7 @@ * - 1.11.0 - Add wait boost (MSM_WAIT_FENCE_BOOST, MSM_PREP_BOOST) */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 10 +#define MSM_VERSION_MINOR 11 #define MSM_VERSION_PATCHLEVEL 0 static void msm_deinit_vram(struct drm_device *ddev); @@ -620,7 +620,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, break; case MSM_INFO_GET_NAME: if (args->value && (args->len < strlen(msm_obj->name))) { - ret = -EINVAL; + ret = -ETOOSMALL; break; } args->len = strlen(msm_obj->name); From 9902cb999e4e913d98e8afe4b36c08e4a793e1ce Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 6 Nov 2023 10:50:26 -0800 Subject: [PATCH 1020/7721] drm/msm/gem: Add metadata The EXT_external_objects extension is a bit awkward as it doesn't pass explicit modifiers, leaving the importer to guess with incomplete information. In the case of vk (turnip) exporting and gl (freedreno) importing, the "OPTIMAL_TILING_EXT" layout depends on VkImageCreateInfo flags (among other things), which the importer does not know. Which unfortunately leaves us with the need for a metadata back-channel. The contents of the metadata are defined by userspace. The EXT_external_objects extension is only required to work between compatible versions of gl and vk drivers, as defined by device and driver UUIDs. v2: add missing metadata kfree v3: Rework to move copy_from/to_user out from under gem obj lock to avoid angering lockdep about deadlocks against fs-reclaim Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/566157/ --- drivers/gpu/drm/msm/msm_drv.c | 92 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/msm_gem.c | 1 + drivers/gpu/drm/msm/msm_gem.h | 4 ++ include/uapi/drm/msm_drm.h | 2 + 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d751d2023f84..75d60aab5780 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -37,9 +37,10 @@ * - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT * - 1.11.0 - Add wait boost (MSM_WAIT_FENCE_BOOST, MSM_PREP_BOOST) + * - 1.12.0 - Add MSM_INFO_SET_METADATA and MSM_INFO_GET_METADATA */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 11 +#define MSM_VERSION_MINOR 12 #define MSM_VERSION_PATCHLEVEL 0 static void msm_deinit_vram(struct drm_device *ddev); @@ -546,6 +547,85 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev, return msm_gem_set_iova(obj, ctx->aspace, iova); } +static int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, + __user void *metadata, + u32 metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *buf; + int ret; + + /* Impose a moderate upper bound on metadata size: */ + if (metadata_size > 128) { + return -EOVERFLOW; + } + + /* Use a temporary buf to keep copy_from_user() outside of gem obj lock: */ + buf = memdup_user(metadata, metadata_size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = msm_gem_lock_interruptible(obj); + if (ret) + goto out; + + msm_obj->metadata = + krealloc(msm_obj->metadata, metadata_size, GFP_KERNEL); + msm_obj->metadata_size = metadata_size; + memcpy(msm_obj->metadata, buf, metadata_size); + + msm_gem_unlock(obj); + +out: + kfree(buf); + + return ret; +} + +static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, + __user void *metadata, + u32 *metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *buf; + int ret, len; + + if (!metadata) { + /* + * Querying the size is inherently racey, but + * EXT_external_objects expects the app to confirm + * via device and driver UUIDs that the exporter and + * importer versions match. All we can do from the + * kernel side is check the length under obj lock + * when userspace tries to retrieve the metadata + */ + *metadata_size = msm_obj->metadata_size; + return 0; + } + + ret = msm_gem_lock_interruptible(obj); + if (ret) + return ret; + + /* Avoid copy_to_user() under gem obj lock: */ + len = msm_obj->metadata_size; + buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); + + msm_gem_unlock(obj); + + if (*metadata_size < len) { + ret = -ETOOSMALL; + } else if (copy_to_user(metadata, buf, len)) { + ret = -EFAULT; + } else { + *metadata_size = len; + } + + kfree(buf); + + return 0; +} + static int msm_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) { @@ -568,6 +648,8 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, break; case MSM_INFO_SET_NAME: case MSM_INFO_GET_NAME: + case MSM_INFO_SET_METADATA: + case MSM_INFO_GET_METADATA: break; default: return -EINVAL; @@ -630,6 +712,14 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, ret = -EFAULT; } break; + case MSM_INFO_SET_METADATA: + ret = msm_ioctl_gem_info_set_metadata( + obj, u64_to_user_ptr(args->value), args->len); + break; + case MSM_INFO_GET_METADATA: + ret = msm_ioctl_gem_info_get_metadata( + obj, u64_to_user_ptr(args->value), &args->len); + break; } drm_gem_object_put(obj); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index db1e748daa75..32303cc8e646 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1058,6 +1058,7 @@ static void msm_gem_free_object(struct drm_gem_object *obj) drm_gem_object_release(obj); + kfree(msm_obj->metadata); kfree(msm_obj); } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8ddef5443140..6352bd3cc5ed 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -108,6 +108,10 @@ struct msm_gem_object { char name[32]; /* Identifier to print for the debugfs files */ + /* userspace metadata backchannel */ + void *metadata; + u32 metadata_size; + /** * pin_count: Number of times the pages are pinned * diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 6c34272a13fd..6f2a7ad04aa4 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -139,6 +139,8 @@ struct drm_msm_gem_new { #define MSM_INFO_GET_NAME 0x03 /* get debug name, returned by pointer */ #define MSM_INFO_SET_IOVA 0x04 /* set the iova, passed by value */ #define MSM_INFO_GET_FLAGS 0x05 /* get the MSM_BO_x flags */ +#define MSM_INFO_SET_METADATA 0x06 /* set userspace metadata */ +#define MSM_INFO_GET_METADATA 0x07 /* get userspace metadata */ struct drm_msm_gem_info { __u32 handle; /* in */ From b2acb89af1a400be721bcb14f137aa22b509caba Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 24 Oct 2023 10:08:04 -0700 Subject: [PATCH 1021/7721] drm/msm/gem: Demote userspace errors to DRM_UT_DRIVER Error messages resulting from incorrect usage of the kernel uabi should not spam dmesg by default. But it is useful to enable them to debug userspace. So demote to DRM_UT_DRIVER. Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/564189/ --- drivers/gpu/drm/msm/msm_gem.c | 6 ++--- drivers/gpu/drm/msm/msm_gem_submit.c | 36 ++++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 32303cc8e646..175ee4ab8a6f 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -226,9 +226,9 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj, msm_gem_assert_locked(obj); - if (GEM_WARN_ON(msm_obj->madv > madv)) { - DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n", - msm_obj->madv, madv); + if (msm_obj->madv > madv) { + DRM_DEV_DEBUG_DRIVER(obj->dev->dev, "Invalid madv state: %u vs %u\n", + msm_obj->madv, madv); return ERR_PTR(-EBUSY); } diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 99744de6c05a..207b6ba1565d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -17,6 +17,12 @@ #include "msm_gem.h" #include "msm_gpu_trace.h" +/* For userspace errors, use DRM_UT_DRIVER.. so that userspace can enable + * error msgs for debugging, but we don't spam dmesg by default + */ +#define SUBMIT_ERROR(submit, fmt, ...) \ + DRM_DEV_DEBUG_DRIVER((submit)->dev->dev, fmt, ##__VA_ARGS__) + /* * Cmdstream submission: */ @@ -136,7 +142,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) || !(submit_bo.flags & MANDATORY_FLAGS)) { - DRM_ERROR("invalid flags: %x\n", submit_bo.flags); + SUBMIT_ERROR(submit, "invalid flags: %x\n", submit_bo.flags); ret = -EINVAL; i = 0; goto out; @@ -158,7 +164,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, */ obj = idr_find(&file->object_idr, submit->bos[i].handle); if (!obj) { - DRM_ERROR("invalid handle %u at index %u\n", submit->bos[i].handle, i); + SUBMIT_ERROR(submit, "invalid handle %u at index %u\n", submit->bos[i].handle, i); ret = -EINVAL; goto out_unlock; } @@ -202,13 +208,13 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: break; default: - DRM_ERROR("invalid type: %08x\n", submit_cmd.type); + SUBMIT_ERROR(submit, "invalid type: %08x\n", submit_cmd.type); return -EINVAL; } if (submit_cmd.size % 4) { - DRM_ERROR("non-aligned cmdstream buffer size: %u\n", - submit_cmd.size); + SUBMIT_ERROR(submit, "non-aligned cmdstream buffer size: %u\n", + submit_cmd.size); ret = -EINVAL; goto out; } @@ -306,8 +312,8 @@ static int submit_lock_objects(struct msm_gem_submit *submit) fail: if (ret == -EALREADY) { - DRM_ERROR("handle %u at index %u already on submit list\n", - submit->bos[i].handle, i); + SUBMIT_ERROR(submit, "handle %u at index %u already on submit list\n", + submit->bos[i].handle, i); ret = -EINVAL; } @@ -448,8 +454,8 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, struct drm_gem_object **obj, uint64_t *iova, bool *valid) { if (idx >= submit->nr_bos) { - DRM_ERROR("invalid buffer index: %u (out of %u)\n", - idx, submit->nr_bos); + SUBMIT_ERROR(submit, "invalid buffer index: %u (out of %u)\n", + idx, submit->nr_bos); return -EINVAL; } @@ -475,7 +481,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob return 0; if (offset % 4) { - DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset); + SUBMIT_ERROR(submit, "non-aligned cmdstream buffer: %u\n", offset); return -EINVAL; } @@ -497,8 +503,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob bool valid; if (submit_reloc.submit_offset % 4) { - DRM_ERROR("non-aligned reloc offset: %u\n", - submit_reloc.submit_offset); + SUBMIT_ERROR(submit, "non-aligned reloc offset: %u\n", + submit_reloc.submit_offset); ret = -EINVAL; goto out; } @@ -508,7 +514,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob if ((off >= (obj->size / 4)) || (off < last_offset)) { - DRM_ERROR("invalid offset %u at reloc %u\n", off, i); + SUBMIT_ERROR(submit, "invalid offset %u at reloc %u\n", off, i); ret = -EINVAL; goto out; } @@ -881,7 +887,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (!submit->cmd[i].size || ((submit->cmd[i].size + submit->cmd[i].offset) > obj->size / 4)) { - DRM_ERROR("invalid cmdstream size: %u\n", submit->cmd[i].size * 4); + SUBMIT_ERROR(submit, "invalid cmdstream size: %u\n", submit->cmd[i].size * 4); ret = -EINVAL; goto out; } @@ -893,7 +899,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (!gpu->allow_relocs) { if (submit->cmd[i].nr_relocs) { - DRM_ERROR("relocs not allowed\n"); + SUBMIT_ERROR(submit, "relocs not allowed\n"); ret = -EINVAL; goto out; } From 6c15808d9b7640c3209d53cd2d8d56cfbf9f7175 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 24 Oct 2023 10:08:05 -0700 Subject: [PATCH 1022/7721] drm/msm/gem: Demote allocations to __GFP_NOWARN For allocations with userspace controlled size, we should not warn on allocation failure. Fixes KASAN splat: WARNING: CPU: 6 PID: 29557 at mm/page_alloc.c:5398 __alloc_pages+0x160c/0x2204 Modules linked in: bridge stp llc hci_vhci tun veth xt_cgroup uinput xt_MASQUERADE rfcomm ip6table_nat fuse 8021q r8153_ecm cdc_ether usbnet r8152 mii venus_enc venus_dec uvcvideo algif_hash algif_skcipher af_alg qcom_spmi_adc_tm5 qcom_spmi_adc5 qcom_vadc_common qcom_spmi_temp_alarm cros_ec_typec typec hci_uart btqca qcom_stats snd_soc_sc7180 venus_core ath10k_snoc ath10k_core ath coresight_tmc coresight_replicator coresight_etm4x coresight_funnel snd_soc_lpass_sc7180 mac80211 coresight bluetooth ecdh_generic ecc cfg80211 cros_ec_sensorhub lzo_rle lzo_compress zram joydev CPU: 6 PID: 29557 Comm: syz-executor Not tainted 5.15.110-lockdep-19320-g89d010b0a9df #1 45bdd400697a78353f2927c116615abba810e5dd Hardware name: Google Kingoftown (DT) pstate: 20400009 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __alloc_pages+0x160c/0x2204 lr : __alloc_pages+0x58/0x2204 sp : ffffffc0214176c0 x29: ffffffc0214178a0 x28: ffffff801f7b4000 x27: 0000000000000000 x26: ffffff808a4fa000 x25: 1ffffff011290781 x24: ffffff808a59c000 x23: 0000000000000010 x22: ffffffc0080e6980 x21: 0000000000000010 x20: 0000000000000000 x19: 00000000080001f8 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000020000500 x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000001 x11: 0000000000000000 x10: 1ffffff804282f06 x9 : 0000000000000000 x8 : ffffffc021417848 x7 : 0000000000000000 x6 : ffffffc0082ac788 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000010 x2 : 0000000000000008 x1 : 0000000000000000 x0 : ffffffc021417830 Call trace: __alloc_pages+0x160c/0x2204 kmalloc_order+0x50/0xf4 kmalloc_order_trace+0x38/0x18c __kmalloc+0x300/0x45c msm_ioctl_gem_submit+0x284/0x5988 drm_ioctl_kernel+0x270/0x418 drm_ioctl+0x5e0/0xbf8 __arm64_sys_ioctl+0x154/0x1d0 invoke_syscall+0x98/0x278 el0_svc_common+0x214/0x274 do_el0_svc+0x9c/0x19c el0_svc+0x5c/0xc0 el0t_64_sync_handler+0x78/0x108 el0t_64_sync+0x1a4/0x1a8 Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/564191/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 207b6ba1565d..30d72191cee6 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -43,7 +43,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, if (sz > SIZE_MAX) return ERR_PTR(-ENOMEM); - submit = kzalloc(sz, GFP_KERNEL); + submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN); if (!submit) return ERR_PTR(-ENOMEM); @@ -234,7 +234,7 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, ret = -ENOMEM; goto out; } - submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL); + submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN); if (!submit->cmd[i].relocs) { ret = -ENOMEM; goto out; From ce3e112e7ae854249d8755906acc5f27e1542114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:42 +0100 Subject: [PATCH 1023/7721] drm/bridge: tpd12s015: Drop buggy __exit annotation for remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With tpd12s015_remove() marked with __exit this function is discarded when the driver is compiled as a built-in. The result is that when the driver unbinds there is no cleanup done which results in resource leakage or worse. Fixes: cff5e6f7e83f ("drm/bridge: Add driver for the TI TPD12S015 HDMI level shifter") Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-19-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/bridge/ti-tpd12s015.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c index e0e015243a60..b588fea12502 100644 --- a/drivers/gpu/drm/bridge/ti-tpd12s015.c +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -179,7 +179,7 @@ static int tpd12s015_probe(struct platform_device *pdev) return 0; } -static int __exit tpd12s015_remove(struct platform_device *pdev) +static int tpd12s015_remove(struct platform_device *pdev) { struct tpd12s015_device *tpd = platform_get_drvdata(pdev); @@ -197,7 +197,7 @@ MODULE_DEVICE_TABLE(of, tpd12s015_of_match); static struct platform_driver tpd12s015_driver = { .probe = tpd12s015_probe, - .remove = __exit_p(tpd12s015_remove), + .remove = tpd12s015_remove, .driver = { .name = "tpd12s015", .of_match_table = tpd12s015_of_match, From da20c383de2aa6bfa4c36ed4311e16051aaeab43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:43 +0100 Subject: [PATCH 1024/7721] drm/arcpgu: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-20-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/tiny/arcpgu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c index e5b10e41554a..4f8f3172379e 100644 --- a/drivers/gpu/drm/tiny/arcpgu.c +++ b/drivers/gpu/drm/tiny/arcpgu.c @@ -404,14 +404,12 @@ static int arcpgu_probe(struct platform_device *pdev) return ret; } -static int arcpgu_remove(struct platform_device *pdev) +static void arcpgu_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); drm_dev_unregister(drm); arcpgu_unload(drm); - - return 0; } static const struct of_device_id arcpgu_of_table[] = { @@ -423,7 +421,7 @@ MODULE_DEVICE_TABLE(of, arcpgu_of_table); static struct platform_driver arcpgu_platform_driver = { .probe = arcpgu_probe, - .remove = arcpgu_remove, + .remove_new = arcpgu_remove, .driver = { .name = "arcpgu", .of_match_table = arcpgu_of_table, From b47914741a80f59483cba0b59c43a92c01bc4b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:44 +0100 Subject: [PATCH 1025/7721] drm/armada: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert the armada drm drivers from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-21-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/armada/armada_crtc.c | 5 ++--- drivers/gpu/drm/armada/armada_drv.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 15dd667aa2e7..52d2c942d3d2 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1066,10 +1066,9 @@ static int armada_lcd_probe(struct platform_device *pdev) return component_add(&pdev->dev, &armada_lcd_ops); } -static int armada_lcd_remove(struct platform_device *pdev) +static void armada_lcd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &armada_lcd_ops); - return 0; } static const struct of_device_id armada_lcd_of_match[] = { @@ -1095,7 +1094,7 @@ MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids); struct platform_driver armada_lcd_platform_driver = { .probe = armada_lcd_probe, - .remove = armada_lcd_remove, + .remove_new = armada_lcd_remove, .driver = { .name = "armada-lcd", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index fa1c67598706..e51ecc4f7ef4 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -226,10 +226,9 @@ static int armada_drm_probe(struct platform_device *pdev) match); } -static int armada_drm_remove(struct platform_device *pdev) +static void armada_drm_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &armada_master_ops); - return 0; } static void armada_drm_shutdown(struct platform_device *pdev) @@ -249,7 +248,7 @@ MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids); static struct platform_driver armada_drm_platform_driver = { .probe = armada_drm_probe, - .remove = armada_drm_remove, + .remove_new = armada_drm_remove, .shutdown = armada_drm_shutdown, .driver = { .name = "armada-drm", From be79252e7c83885bd0043168954b8400a42153ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:45 +0100 Subject: [PATCH 1026/7721] drm/bridge: cdns-mhdp8546: Improve error reporting in remove callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the generic error message issued by the driver core when the remove callback returns non-zero ("remove callback returned a non-zero value. This will be ignored.") by a message that tells the actual problem. Also simplify a bit by checking the return value of wait_event_timeout a bit later. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-22-u.kleine-koenig@pengutronix.de --- .../drm/bridge/cadence/cdns-mhdp8546-core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 6af565ac307a..66c87d36ce51 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2600,7 +2600,6 @@ static int cdns_mhdp_remove(struct platform_device *pdev) { struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev); unsigned long timeout = msecs_to_jiffies(100); - bool stop_fw = false; int ret; drm_bridge_remove(&mhdp->bridge); @@ -2608,18 +2607,19 @@ static int cdns_mhdp_remove(struct platform_device *pdev) ret = wait_event_timeout(mhdp->fw_load_wq, mhdp->hw_state == MHDP_HW_READY, timeout); - if (ret == 0) - dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n", - __func__); - else - stop_fw = true; - spin_lock(&mhdp->start_lock); mhdp->hw_state = MHDP_HW_STOPPED; spin_unlock(&mhdp->start_lock); - if (stop_fw) + if (ret == 0) { + dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n", + __func__); + } else { ret = cdns_mhdp_set_firmware_active(mhdp, false); + if (ret) + dev_err(mhdp->dev, "Failed to stop firmware (%pe)\n", + ERR_PTR(ret)); + } phy_exit(mhdp->phy); @@ -2635,7 +2635,7 @@ static int cdns_mhdp_remove(struct platform_device *pdev) clk_disable_unprepare(mhdp->clk); - return ret; + return 0; } static const struct of_device_id mhdp_ids[] = { From 3438cf177ae51f11255d36a94b17939b06ce1717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:46 +0100 Subject: [PATCH 1027/7721] drm/bridge: cdns-mhdp8546: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-23-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 66c87d36ce51..7d470527455b 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2596,7 +2596,7 @@ static int cdns_mhdp_probe(struct platform_device *pdev) return ret; } -static int cdns_mhdp_remove(struct platform_device *pdev) +static void cdns_mhdp_remove(struct platform_device *pdev) { struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev); unsigned long timeout = msecs_to_jiffies(100); @@ -2634,8 +2634,6 @@ static int cdns_mhdp_remove(struct platform_device *pdev) /* Ignoring mhdp->hdcp.check_work and mhdp->hdcp.prop_work here. */ clk_disable_unprepare(mhdp->clk); - - return 0; } static const struct of_device_id mhdp_ids[] = { @@ -2658,7 +2656,7 @@ static struct platform_driver mhdp_driver = { .of_match_table = mhdp_ids, }, .probe = cdns_mhdp_probe, - .remove = cdns_mhdp_remove, + .remove_new = cdns_mhdp_remove, }; module_platform_driver(mhdp_driver); From 3cdbe59868ef5228b561bb30bde13cc1021ee8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:47 +0100 Subject: [PATCH 1028/7721] drm/bridge: tpd12s015: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-24-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/bridge/ti-tpd12s015.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c index b588fea12502..f9fb35683a27 100644 --- a/drivers/gpu/drm/bridge/ti-tpd12s015.c +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -179,13 +179,11 @@ static int tpd12s015_probe(struct platform_device *pdev) return 0; } -static int tpd12s015_remove(struct platform_device *pdev) +static void tpd12s015_remove(struct platform_device *pdev) { struct tpd12s015_device *tpd = platform_get_drvdata(pdev); drm_bridge_remove(&tpd->bridge); - - return 0; } static const struct of_device_id tpd12s015_of_match[] = { @@ -197,7 +195,7 @@ MODULE_DEVICE_TABLE(of, tpd12s015_of_match); static struct platform_driver tpd12s015_driver = { .probe = tpd12s015_probe, - .remove = tpd12s015_remove, + .remove_new = tpd12s015_remove, .driver = { .name = "tpd12s015", .of_match_table = tpd12s015_of_match, From d437dab5b06e3dc73f6a58a6c9fd0b13d1ed80e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:48 +0100 Subject: [PATCH 1029/7721] drm/etnaviv: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert the etnaviv drm driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Reviewed-by: Christian Gmeiner Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-25-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 6 ++---- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a8d3fa81e4ec..6228ce603248 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -640,16 +640,14 @@ static int etnaviv_pdev_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &etnaviv_master_ops, match); } -static int etnaviv_pdev_remove(struct platform_device *pdev) +static void etnaviv_pdev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &etnaviv_master_ops); - - return 0; } static struct platform_driver etnaviv_platform_driver = { .probe = etnaviv_pdev_probe, - .remove = etnaviv_pdev_remove, + .remove_new = etnaviv_pdev_remove, .driver = { .name = "etnaviv", }, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 5105d290e72e..9b8445d2a128 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1904,11 +1904,10 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) return 0; } -static int etnaviv_gpu_platform_remove(struct platform_device *pdev) +static void etnaviv_gpu_platform_remove(struct platform_device *pdev) { component_del(&pdev->dev, &gpu_ops); pm_runtime_disable(&pdev->dev); - return 0; } static int etnaviv_gpu_rpm_suspend(struct device *dev) @@ -1970,6 +1969,6 @@ struct platform_driver etnaviv_gpu_driver = { .of_match_table = etnaviv_gpu_match, }, .probe = etnaviv_gpu_platform_probe, - .remove = etnaviv_gpu_platform_remove, + .remove_new = etnaviv_gpu_platform_remove, .id_table = gpu_ids, }; From 60096f0a77600ac2cc92b82fee279d1905576950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:50 +0100 Subject: [PATCH 1030/7721] drm/imx/dcss: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-27-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/imx/dcss/dcss-drv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c index b61cec0cc79d..ad5f29ea8f6a 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-drv.c +++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c @@ -80,7 +80,7 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) return err; } -static int dcss_drv_platform_remove(struct platform_device *pdev) +static void dcss_drv_platform_remove(struct platform_device *pdev) { struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); @@ -88,8 +88,6 @@ static int dcss_drv_platform_remove(struct platform_device *pdev) dcss_dev_destroy(mdrv->dcss); kfree(mdrv); - - return 0; } static void dcss_drv_platform_shutdown(struct platform_device *pdev) @@ -120,7 +118,7 @@ MODULE_DEVICE_TABLE(of, dcss_of_match); static struct platform_driver dcss_platform_driver = { .probe = dcss_drv_platform_probe, - .remove = dcss_drv_platform_remove, + .remove_new = dcss_drv_platform_remove, .shutdown = dcss_drv_platform_shutdown, .driver = { .name = "imx-dcss", From a7e43c0a1a70e0d71fdda5d315927e1b3bc7e8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:51 +0100 Subject: [PATCH 1031/7721] drm/imx: lcdc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-28-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index 22b65f4a0e30..0902983374d0 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -515,14 +515,12 @@ static int imx_lcdc_probe(struct platform_device *pdev) return 0; } -static int imx_lcdc_remove(struct platform_device *pdev) +static void imx_lcdc_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); drm_dev_unregister(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void imx_lcdc_shutdown(struct platform_device *pdev) @@ -536,7 +534,7 @@ static struct platform_driver imx_lcdc_driver = { .of_match_table = imx_lcdc_of_dev_id, }, .probe = imx_lcdc_probe, - .remove = imx_lcdc_remove, + .remove_new = imx_lcdc_remove, .shutdown = imx_lcdc_shutdown, }; module_platform_driver(imx_lcdc_driver); From 8c67c9a4e4582c30408308cfdfd8719180075f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:52 +0100 Subject: [PATCH 1032/7721] drm/kmb: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-29-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/kmb/kmb_drv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 24035b53441c..169b83987ce2 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -448,7 +448,7 @@ static const struct drm_driver kmb_driver = { .minor = DRIVER_MINOR, }; -static int kmb_remove(struct platform_device *pdev) +static void kmb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct drm_device *drm = dev_get_drvdata(dev); @@ -473,7 +473,6 @@ static int kmb_remove(struct platform_device *pdev) /* Unregister DSI host */ kmb_dsi_host_unregister(kmb->kmb_dsi); drm_atomic_helper_shutdown(drm); - return 0; } static int kmb_probe(struct platform_device *pdev) @@ -621,7 +620,7 @@ static SIMPLE_DEV_PM_OPS(kmb_pm_ops, kmb_pm_suspend, kmb_pm_resume); static struct platform_driver kmb_platform_driver = { .probe = kmb_probe, - .remove = kmb_remove, + .remove_new = kmb_remove, .driver = { .name = "kmb-drm", .pm = &kmb_pm_ops, From 30b749adb13db8e672d1a53266876732b8a2edb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:53 +0100 Subject: [PATCH 1033/7721] drm/mediatek: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-30-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 5 ++--- drivers/gpu/drm/mediatek/mtk_ethdr.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c index 6bf6367853fb..3fdef3ad4ffd 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c @@ -531,16 +531,15 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev) return ret; } -static int mtk_disp_ovl_adaptor_remove(struct platform_device *pdev) +static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops); pm_runtime_disable(&pdev->dev); - return 0; } struct platform_driver mtk_disp_ovl_adaptor_driver = { .probe = mtk_disp_ovl_adaptor_probe, - .remove = mtk_disp_ovl_adaptor_remove, + .remove_new = mtk_disp_ovl_adaptor_remove, .driver = { .name = "mediatek-disp-ovl-adaptor", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c index db7ac666ec5e..6a5d0c345aab 100644 --- a/drivers/gpu/drm/mediatek/mtk_ethdr.c +++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c @@ -346,10 +346,9 @@ static int mtk_ethdr_probe(struct platform_device *pdev) return ret; } -static int mtk_ethdr_remove(struct platform_device *pdev) +static void mtk_ethdr_remove(struct platform_device *pdev) { component_del(&pdev->dev, &mtk_ethdr_component_ops); - return 0; } static const struct of_device_id mtk_ethdr_driver_dt_match[] = { @@ -361,7 +360,7 @@ MODULE_DEVICE_TABLE(of, mtk_ethdr_driver_dt_match); struct platform_driver mtk_ethdr_driver = { .probe = mtk_ethdr_probe, - .remove = mtk_ethdr_remove, + .remove_new = mtk_ethdr_remove, .driver = { .name = "mediatek-disp-ethdr", .owner = THIS_MODULE, From ac96555768099bf3e87b59abe9f156bb6fffbbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:54 +0100 Subject: [PATCH 1034/7721] drm/meson: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-31-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/meson/meson_dw_mipi_dsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index e5fe4e994f43..a6bc1bdb3d0d 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -323,13 +323,11 @@ static int meson_dw_mipi_dsi_probe(struct platform_device *pdev) return 0; } -static int meson_dw_mipi_dsi_remove(struct platform_device *pdev) +static void meson_dw_mipi_dsi_remove(struct platform_device *pdev) { struct meson_dw_mipi_dsi *mipi_dsi = platform_get_drvdata(pdev); dw_mipi_dsi_remove(mipi_dsi->dmd); - - return 0; } static const struct of_device_id meson_dw_mipi_dsi_of_table[] = { @@ -340,7 +338,7 @@ MODULE_DEVICE_TABLE(of, meson_dw_mipi_dsi_of_table); static struct platform_driver meson_dw_mipi_dsi_platform_driver = { .probe = meson_dw_mipi_dsi_probe, - .remove = meson_dw_mipi_dsi_remove, + .remove_new = meson_dw_mipi_dsi_remove, .driver = { .name = DRIVER_NAME, .of_match_table = meson_dw_mipi_dsi_of_table, From 0fa2db3bc7498d7b88e6742571cb832f749d625f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:55 +0100 Subject: [PATCH 1035/7721] drm/nouveau: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-32-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/nouveau/nouveau_platform.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index 23cd43a7fd19..bf2dc7567ea4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -43,11 +43,10 @@ static int nouveau_platform_probe(struct platform_device *pdev) return 0; } -static int nouveau_platform_remove(struct platform_device *pdev) +static void nouveau_platform_remove(struct platform_device *pdev) { struct drm_device *dev = platform_get_drvdata(pdev); nouveau_drm_device_remove(dev); - return 0; } #if IS_ENABLED(CONFIG_OF) @@ -93,5 +92,5 @@ struct platform_driver nouveau_platform_driver = { .of_match_table = of_match_ptr(nouveau_platform_match), }, .probe = nouveau_platform_probe, - .remove = nouveau_platform_remove, + .remove_new = nouveau_platform_remove, }; From 16b01df3c5db447e05cff60c2f612d76c0cd7baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:56 +0100 Subject: [PATCH 1036/7721] drm/sprd: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert the sprd drm drivers from always returning zero in the remove callback to the void returning variant. Reviewed-by: Thomas Zimmermann Reviewed-by: Jyri Sarha Signed-off-by: Uwe Kleine-König Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-33-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/sprd/sprd_dpu.c | 6 ++---- drivers/gpu/drm/sprd/sprd_drm.c | 5 ++--- drivers/gpu/drm/sprd/sprd_dsi.c | 6 ++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/sprd_dpu.c index 48183bbd0590..deb3bb96e2a8 100644 --- a/drivers/gpu/drm/sprd/sprd_dpu.c +++ b/drivers/gpu/drm/sprd/sprd_dpu.c @@ -859,16 +859,14 @@ static int sprd_dpu_probe(struct platform_device *pdev) return component_add(&pdev->dev, &dpu_component_ops); } -static int sprd_dpu_remove(struct platform_device *pdev) +static void sprd_dpu_remove(struct platform_device *pdev) { component_del(&pdev->dev, &dpu_component_ops); - - return 0; } struct platform_driver sprd_dpu_driver = { .probe = sprd_dpu_probe, - .remove = sprd_dpu_remove, + .remove_new = sprd_dpu_remove, .driver = { .name = "sprd-dpu-drv", .of_match_table = dpu_match_table, diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c index 0aa39156f2fa..a74cd0caf645 100644 --- a/drivers/gpu/drm/sprd/sprd_drm.c +++ b/drivers/gpu/drm/sprd/sprd_drm.c @@ -138,10 +138,9 @@ static int sprd_drm_probe(struct platform_device *pdev) return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops); } -static int sprd_drm_remove(struct platform_device *pdev) +static void sprd_drm_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &drm_component_ops); - return 0; } static void sprd_drm_shutdown(struct platform_device *pdev) @@ -164,7 +163,7 @@ MODULE_DEVICE_TABLE(of, drm_match_table); static struct platform_driver sprd_drm_driver = { .probe = sprd_drm_probe, - .remove = sprd_drm_remove, + .remove_new = sprd_drm_remove, .shutdown = sprd_drm_shutdown, .driver = { .name = "sprd-drm-drv", diff --git a/drivers/gpu/drm/sprd/sprd_dsi.c b/drivers/gpu/drm/sprd/sprd_dsi.c index d7b143a75601..0b69c140eab3 100644 --- a/drivers/gpu/drm/sprd/sprd_dsi.c +++ b/drivers/gpu/drm/sprd/sprd_dsi.c @@ -1051,18 +1051,16 @@ static int sprd_dsi_probe(struct platform_device *pdev) return mipi_dsi_host_register(&dsi->host); } -static int sprd_dsi_remove(struct platform_device *pdev) +static void sprd_dsi_remove(struct platform_device *pdev) { struct sprd_dsi *dsi = dev_get_drvdata(&pdev->dev); mipi_dsi_host_unregister(&dsi->host); - - return 0; } struct platform_driver sprd_dsi_driver = { .probe = sprd_dsi_probe, - .remove = sprd_dsi_remove, + .remove_new = sprd_dsi_remove, .driver = { .name = "sprd-dsi-drv", .of_match_table = dsi_match_table, From 740329d7120f8608ead64b0f3417c02ca1d6b32f Mon Sep 17 00:00:00 2001 From: Johannes Roith Date: Thu, 21 Sep 2023 18:49:28 +0200 Subject: [PATCH 1037/7721] HID: mcp2200: added driver for GPIOs of MCP2200 Added a gpiochip compatible driver to control the 8 GPIOs of the MCP2200 by using the HID interface. Using GPIOs with alternative functions (GP0<->SSPND, GP1<->USBCFG, GP6<->RXLED, GP7<->TXLED) will reset the functions, if set (unset by default). The driver was tested while also using the UART of the chip. Setting and reading the GPIOs has no effect on the UART communication. However, a reset is triggered after the CONFIGURE command. If the GPIO Direction is constantly changed, this will affect the communication at low baud rates. This is a hardware problem of the MCP2200 and is not caused by the driver. Signed-off-by: Johannes Roith Reviewed-by: Rahul Rameshbabu Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 9 + drivers/hid/Makefile | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-mcp2200.c | 392 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 403 insertions(+) create mode 100644 drivers/hid/hid-mcp2200.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4ce74af79657..03e7fc3d05a5 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1296,6 +1296,15 @@ config HID_ALPS Say Y here if you have a Alps touchpads over i2c-hid or usbhid and want support for its special functionalities. +config HID_MCP2200 + tristate "Microchip MCP2200 HID USB-to-GPIO bridge" + depends on USB_HID && GPIOLIB + help + Provides GPIO functionality over USB-HID through MCP2200 device. + + To compile this driver as a module, choose M here: the module + will be called hid-mcp2200.ko. + config HID_MCP2221 tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support" depends on USB_HID && I2C diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 8a06d0f840bc..082a728eac60 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_MACALLY) += hid-macally.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MALTRON) += hid-maltron.o +obj-$(CONFIG_HID_MCP2200) += hid-mcp2200.o obj-$(CONFIG_HID_MCP2221) += hid-mcp2221.o obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MEGAWORLD_FF) += hid-megaworld.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f7973ccd84a2..f63e16095c10 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -917,6 +917,7 @@ #define USB_DEVICE_ID_PICK16F1454 0x0042 #define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7 #define USB_DEVICE_ID_LUXAFOR 0xf372 +#define USB_DEVICE_ID_MCP2200 0x00df #define USB_DEVICE_ID_MCP2221 0x00dd #define USB_VENDOR_ID_MICROSOFT 0x045e diff --git a/drivers/hid/hid-mcp2200.c b/drivers/hid/hid-mcp2200.c new file mode 100644 index 000000000000..bf57f7f6caa0 --- /dev/null +++ b/drivers/hid/hid-mcp2200.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MCP2200 - Microchip USB to GPIO bridge + * + * Copyright (c) 2023, Johannes Roith + * + * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22228A.pdf + * App Note for HID: https://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "hid-ids.h" + +/* Commands codes in a raw output report */ +#define SET_CLEAR_OUTPUTS 0x08 +#define CONFIGURE 0x10 +#define READ_EE 0x20 +#define WRITE_EE 0x40 +#define READ_ALL 0x80 + +/* MCP GPIO direction encoding */ +enum MCP_IO_DIR { + MCP2200_DIR_OUT = 0x00, + MCP2200_DIR_IN = 0x01, +}; + +/* Altternative pin assignments */ +#define TXLED 2 +#define RXLED 3 +#define USBCFG 6 +#define SSPND 7 +#define MCP_NGPIO 8 + +/* CMD to set or clear a GPIO output */ +struct mcp_set_clear_outputs { + u8 cmd; + u8 dummys1[10]; + u8 set_bmap; + u8 clear_bmap; + u8 dummys2[3]; +} __packed; + +/* CMD to configure the IOs */ +struct mcp_configure { + u8 cmd; + u8 dummys1[3]; + u8 io_bmap; + u8 config_alt_pins; + u8 io_default_val_bmap; + u8 config_alt_options; + u8 baud_h; + u8 baud_l; + u8 dummys2[6]; +} __packed; + +/* CMD to read all parameters */ +struct mcp_read_all { + u8 cmd; + u8 dummys[15]; +} __packed; + +/* Response to the read all cmd */ +struct mcp_read_all_resp { + u8 cmd; + u8 eep_addr; + u8 dummy; + u8 eep_val; + u8 io_bmap; + u8 config_alt_pins; + u8 io_default_val_bmap; + u8 config_alt_options; + u8 baud_h; + u8 baud_l; + u8 io_port_val_bmap; + u8 dummys[5]; +} __packed; + +struct mcp2200 { + struct hid_device *hdev; + struct mutex lock; + struct completion wait_in_report; + u8 gpio_dir; + u8 gpio_val; + u8 gpio_inval; + u8 baud_h; + u8 baud_l; + u8 config_alt_pins; + u8 gpio_reset_val; + u8 config_alt_options; + int status; + struct gpio_chip gc; + u8 hid_report[16]; +}; + +/* this executes the READ_ALL cmd */ +static int mcp_cmd_read_all(struct mcp2200 *mcp) +{ + struct mcp_read_all *read_all; + int len, t; + + reinit_completion(&mcp->wait_in_report); + + mutex_lock(&mcp->lock); + + read_all = (struct mcp_read_all *) mcp->hid_report; + read_all->cmd = READ_ALL; + len = hid_hw_output_report(mcp->hdev, (u8 *) read_all, + sizeof(struct mcp_read_all)); + + mutex_unlock(&mcp->lock); + + if (len != sizeof(struct mcp_read_all)) + return -EINVAL; + + t = wait_for_completion_timeout(&mcp->wait_in_report, + msecs_to_jiffies(4000)); + if (!t) + return -ETIMEDOUT; + + /* return status, negative value if wrong response was received */ + return mcp->status; +} + +static void mcp_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct mcp2200 *mcp = gpiochip_get_data(gc); + u8 value; + int status; + struct mcp_set_clear_outputs *cmd; + + mutex_lock(&mcp->lock); + cmd = (struct mcp_set_clear_outputs *) mcp->hid_report; + + value = mcp->gpio_val & ~*mask; + value |= (*mask & *bits); + + cmd->cmd = SET_CLEAR_OUTPUTS; + cmd->set_bmap = value; + cmd->clear_bmap = ~(value); + + status = hid_hw_output_report(mcp->hdev, (u8 *) cmd, + sizeof(struct mcp_set_clear_outputs)); + + if (status == sizeof(struct mcp_set_clear_outputs)) + mcp->gpio_val = value; + + mutex_unlock(&mcp->lock); +} + +static void mcp_set(struct gpio_chip *gc, unsigned int gpio_nr, int value) +{ + unsigned long mask = 1 << gpio_nr; + unsigned long bmap_value = value << gpio_nr; + + mcp_set_multiple(gc, &mask, &bmap_value); +} + +static int mcp_get_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + u32 val; + struct mcp2200 *mcp = gpiochip_get_data(gc); + int status; + + status = mcp_cmd_read_all(mcp); + if (status) + return status; + + val = mcp->gpio_inval; + *bits = (val & *mask); + return 0; +} + +static int mcp_get(struct gpio_chip *gc, unsigned int gpio_nr) +{ + unsigned long mask = 0, bits = 0; + + mask = (1 << gpio_nr); + mcp_get_multiple(gc, &mask, &bits); + return bits > 0; +} + +static int mcp_get_direction(struct gpio_chip *gc, unsigned int gpio_nr) +{ + struct mcp2200 *mcp = gpiochip_get_data(gc); + + return (mcp->gpio_dir & (MCP2200_DIR_IN << gpio_nr)) + ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; +} + +static int mcp_set_direction(struct gpio_chip *gc, unsigned int gpio_nr, + enum MCP_IO_DIR io_direction) +{ + struct mcp2200 *mcp = gpiochip_get_data(gc); + struct mcp_configure *conf; + int status; + /* after the configure cmd we will need to set the outputs again */ + unsigned long mask = ~(mcp->gpio_dir); /* only set outputs */ + unsigned long bits = mcp->gpio_val; + /* Offsets of alternative pins in config_alt_pins, 0 is not used */ + u8 alt_pin_conf[8] = {SSPND, USBCFG, 0, 0, 0, 0, RXLED, TXLED}; + u8 config_alt_pins = mcp->config_alt_pins; + + /* Read in the reset baudrate first, we need it later */ + status = mcp_cmd_read_all(mcp); + if (status != 0) + return status; + + mutex_lock(&mcp->lock); + conf = (struct mcp_configure *) mcp->hid_report; + + /* configure will reset the chip! */ + conf->cmd = CONFIGURE; + conf->io_bmap = (mcp->gpio_dir & ~(1 << gpio_nr)) + | (io_direction << gpio_nr); + /* Don't overwrite the reset parameters */ + conf->baud_h = mcp->baud_h; + conf->baud_l = mcp->baud_l; + conf->config_alt_options = mcp->config_alt_options; + conf->io_default_val_bmap = mcp->gpio_reset_val; + /* Adjust alt. func if necessary */ + if (alt_pin_conf[gpio_nr]) + config_alt_pins &= ~(1 << alt_pin_conf[gpio_nr]); + conf->config_alt_pins = config_alt_pins; + + status = hid_hw_output_report(mcp->hdev, (u8 *) conf, + sizeof(struct mcp_set_clear_outputs)); + + if (status == sizeof(struct mcp_set_clear_outputs)) { + mcp->gpio_dir = conf->io_bmap; + mcp->config_alt_pins = config_alt_pins; + } else { + mutex_unlock(&mcp->lock); + return -EIO; + } + + mutex_unlock(&mcp->lock); + + /* Configure CMD will clear all IOs -> rewrite them */ + mcp_set_multiple(gc, &mask, &bits); + return 0; +} + +static int mcp_direction_input(struct gpio_chip *gc, unsigned int gpio_nr) +{ + return mcp_set_direction(gc, gpio_nr, MCP2200_DIR_IN); +} + +static int mcp_direction_output(struct gpio_chip *gc, unsigned int gpio_nr, + int value) +{ + int ret; + unsigned long mask, bmap_value; + + mask = 1 << gpio_nr; + bmap_value = value << gpio_nr; + + ret = mcp_set_direction(gc, gpio_nr, MCP2200_DIR_OUT); + if (!ret) + mcp_set_multiple(gc, &mask, &bmap_value); + return ret; +} + +static const struct gpio_chip template_chip = { + .label = "mcp2200", + .owner = THIS_MODULE, + .get_direction = mcp_get_direction, + .direction_input = mcp_direction_input, + .direction_output = mcp_direction_output, + .set = mcp_set, + .set_multiple = mcp_set_multiple, + .get = mcp_get, + .get_multiple = mcp_get_multiple, + .base = -1, + .ngpio = MCP_NGPIO, + .can_sleep = true, +}; + +/* + * MCP2200 uses interrupt endpoint for input reports. This function + * is called by HID layer when it receives i/p report from mcp2200, + * which is actually a response to the previously sent command. + */ +static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + struct mcp2200 *mcp = hid_get_drvdata(hdev); + struct mcp_read_all_resp *all_resp; + + switch (data[0]) { + case READ_ALL: + all_resp = (struct mcp_read_all_resp *) data; + mcp->status = 0; + mcp->gpio_inval = all_resp->io_port_val_bmap; + mcp->baud_h = all_resp->baud_h; + mcp->baud_l = all_resp->baud_l; + mcp->gpio_reset_val = all_resp->io_default_val_bmap; + mcp->config_alt_pins = all_resp->config_alt_pins; + mcp->config_alt_options = all_resp->config_alt_options; + break; + default: + mcp->status = -EIO; + break; + } + + complete(&mcp->wait_in_report); + return 0; +} + +static int mcp2200_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mcp2200 *mcp; + + mcp = devm_kzalloc(&hdev->dev, sizeof(*mcp), GFP_KERNEL); + if (!mcp) + return -ENOMEM; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "can't parse reports\n"); + return ret; + } + + ret = hid_hw_start(hdev, 0); + if (ret) { + hid_err(hdev, "can't start hardware\n"); + return ret; + } + + hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n", hdev->version >> 8, + hdev->version & 0xff, hdev->name, hdev->phys); + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "can't open device\n"); + hid_hw_stop(hdev); + return ret; + } + + mutex_init(&mcp->lock); + init_completion(&mcp->wait_in_report); + hid_set_drvdata(hdev, mcp); + mcp->hdev = hdev; + + mcp->gc = template_chip; + mcp->gc.parent = &hdev->dev; + + ret = devm_gpiochip_add_data(&hdev->dev, &mcp->gc, mcp); + if (ret < 0) { + hid_err(hdev, "Unable to register gpiochip\n"); + hid_hw_close(hdev); + hid_hw_stop(hdev); + return ret; + } + + return 0; +} + +static void mcp2200_remove(struct hid_device *hdev) +{ + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id mcp2200_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_MCP2200) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mcp2200_devices); + +static struct hid_driver mcp2200_driver = { + .name = "mcp2200", + .id_table = mcp2200_devices, + .probe = mcp2200_probe, + .remove = mcp2200_remove, + .raw_event = mcp2200_raw_event, +}; + +/* Register with HID core */ +module_hid_driver(mcp2200_driver); + +MODULE_AUTHOR("Johannes Roith "); +MODULE_DESCRIPTION("MCP2200 Microchip HID USB to GPIO bridge"); +MODULE_LICENSE("GPL"); From d9786159d229cdc1f579f7cf3abf464efb453e40 Mon Sep 17 00:00:00 2001 From: Hamish Martin Date: Wed, 25 Oct 2023 16:55:12 +1300 Subject: [PATCH 1038/7721] HID: mcp2221: Set ACPI companion In scenarios where an I2C device tree is defined in ACPI and exists off the MCP2221 I2C bus, the devices could not be instantiated. Mark the USB port that the MCP2221 is connected to as its ACPI companion so that the USB device can be bound to the ACPI tree when enumerated. With this change the downstream I2C tree devices can be instantiated on ACPI systems. Signed-off-by: Hamish Martin Signed-off-by: Jiri Kosina --- drivers/hid/hid-mcp2221.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 72883e0ce757..90e23bba2130 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -1154,6 +1154,7 @@ static int mcp2221_probe(struct hid_device *hdev, mcp->adapter.algo = &mcp_i2c_algo; mcp->adapter.retries = 1; mcp->adapter.dev.parent = &hdev->dev; + ACPI_COMPANION_SET(&mcp->adapter.dev, ACPI_COMPANION(hdev->dev.parent)); snprintf(mcp->adapter.name, sizeof(mcp->adapter.name), "MCP2221 usb-i2c bridge"); From 02a46753601a24e1673d9c28173121055e8e6cc9 Mon Sep 17 00:00:00 2001 From: Hamish Martin Date: Wed, 25 Oct 2023 16:55:13 +1300 Subject: [PATCH 1039/7721] HID: mcp2221: Don't set bus speed on every transfer Since the initial commit of this driver the I2C bus speed has been reconfigured for every single transfer. This is despite the fact that we never change the speed and it is never "lost" by the chip. Upon investigation we find that what was really happening was that the setting of the bus speed had the side effect of cancelling a previous failed command if there was one, thereby freeing the bus. This is the part that was actually required to keep the bus operational in the face of failed commands. Instead of always setting the speed, we now correctly cancel any failed commands as they are detected. This means we can just set the bus speed at probe time and remove the previous speed sets on each transfer. This has the effect of improving performance and reducing the number of commands required to complete transfers. Signed-off-by: Hamish Martin Signed-off-by: Jiri Kosina --- drivers/hid/hid-mcp2221.c | 41 ++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 90e23bba2130..ecd830ce0acf 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -187,6 +187,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp) return mcp_send_data_req_status(mcp, mcp->txbuf, 8); } +/* Check if the last command succeeded or failed and return the result. + * If the command did fail, cancel that command which will free the i2c bus. + */ +static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp) +{ + int ret; + + ret = mcp_chk_last_cmd_status(mcp); + if (ret) { + /* The last command was a failure. + * Send a cancel which will also free the bus. + */ + usleep_range(980, 1000); + mcp_cancel_last_cmd(mcp); + } + + return ret; +} + static int mcp_set_i2c_speed(struct mcp2221 *mcp) { int ret; @@ -241,7 +260,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp, usleep_range(980, 1000); if (last_status) { - ret = mcp_chk_last_cmd_status(mcp); + ret = mcp_chk_last_cmd_status_free_bus(mcp); if (ret) return ret; } @@ -308,7 +327,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, if (ret) return ret; - ret = mcp_chk_last_cmd_status(mcp); + ret = mcp_chk_last_cmd_status_free_bus(mcp); if (ret) return ret; @@ -328,11 +347,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter, mutex_lock(&mcp->lock); - /* Setting speed before every transaction is required for mcp2221 */ - ret = mcp_set_i2c_speed(mcp); - if (ret) - goto exit; - if (num == 1) { if (msgs->flags & I2C_M_RD) { ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA, @@ -417,9 +431,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr, if (last_status) { usleep_range(980, 1000); - ret = mcp_chk_last_cmd_status(mcp); - if (ret) - return ret; + ret = mcp_chk_last_cmd_status_free_bus(mcp); } return ret; @@ -437,10 +449,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr, mutex_lock(&mcp->lock); - ret = mcp_set_i2c_speed(mcp); - if (ret) - goto exit; - switch (size) { case I2C_SMBUS_QUICK: @@ -1148,6 +1156,11 @@ static int mcp2221_probe(struct hid_device *hdev, if (i2c_clk_freq < 50) i2c_clk_freq = 50; mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3; + ret = mcp_set_i2c_speed(mcp); + if (ret) { + hid_err(hdev, "can't set i2c speed: %d\n", ret); + return ret; + } mcp->adapter.owner = THIS_MODULE; mcp->adapter.class = I2C_CLASS_HWMON; From 2682468671aa0b4d52ae09779b48212a80d71b91 Mon Sep 17 00:00:00 2001 From: Hamish Martin Date: Wed, 25 Oct 2023 16:55:14 +1300 Subject: [PATCH 1040/7721] HID: mcp2221: Handle reads greater than 60 bytes When a user requests more than 60 bytes of data the MCP2221 must chunk the data in chunks up to 60 bytes long (see command/response code 0x40 in the datasheet). In order to signal that the device has more data the (undocumented) byte at byte index 2 of the Get I2C Data response uses the value 0x54. This contrasts with the case for the final data chunk where the value returned is 0x55 (MCP2221_I2C_READ_COMPL). The fact that 0x55 was not returned in the response was interpreted by the driver as a failure meaning that all reads of more than 60 bytes would fail. Add support for reads that are split over multiple chunks by looking for the response code indicating that more data is expected and continuing the read as the code intended. Some timing delays are required to ensure the chip has time to refill its FIFO as data is read in from the I2C bus. This timing has been tested in my system when configured for bus speeds of 50KHz, 100KHz, and 400KHz and operates well. Signed-off-by: Hamish Martin Signed-off-by: Jiri Kosina --- drivers/hid/hid-mcp2221.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index ecd830ce0acf..b242a312c377 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -49,6 +49,7 @@ enum { MCP2221_I2C_MASK_ADDR_NACK = 0x40, MCP2221_I2C_WRADDRL_SEND = 0x21, MCP2221_I2C_ADDR_NACK = 0x25, + MCP2221_I2C_READ_PARTIAL = 0x54, MCP2221_I2C_READ_COMPL = 0x55, MCP2221_ALT_F_NOT_GPIOV = 0xEE, MCP2221_ALT_F_NOT_GPIOD = 0xEF, @@ -297,6 +298,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, { int ret; u16 total_len; + int retries = 0; mcp->txbuf[0] = type; if (msg) { @@ -320,20 +322,31 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, mcp->rxbuf_idx = 0; do { + /* Wait for the data to be read by the device */ + usleep_range(980, 1000); + memset(mcp->txbuf, 0, 4); mcp->txbuf[0] = MCP2221_I2C_GET_DATA; ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); - if (ret) - return ret; - - ret = mcp_chk_last_cmd_status_free_bus(mcp); - if (ret) - return ret; - - usleep_range(980, 1000); + if (ret) { + if (retries < 5) { + /* The data wasn't ready to read. + * Wait a bit longer and try again. + */ + usleep_range(90, 100); + retries++; + } else { + return ret; + } + } else { + retries = 0; + } } while (mcp->rxbuf_idx < total_len); + usleep_range(980, 1000); + ret = mcp_chk_last_cmd_status_free_bus(mcp); + return ret; } @@ -799,7 +812,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, mcp->status = -EIO; break; } - if (data[2] == MCP2221_I2C_READ_COMPL) { + if (data[2] == MCP2221_I2C_READ_COMPL || + data[2] == MCP2221_I2C_READ_PARTIAL) { buf = mcp->rxbuf; memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]); mcp->rxbuf_idx = mcp->rxbuf_idx + data[3]; From fe3b082a6eb8b1526ed7397c849d6b2a6baeb6a1 Mon Sep 17 00:00:00 2001 From: Ashish Mhetre Date: Tue, 7 Nov 2023 16:57:12 +0530 Subject: [PATCH 1041/7721] memory: tegra: Add SID override programming for MC clients For some devices the bootloader/firmware may set up the device in bypass. Memory clients like display needs kernel to program SID after resume because bootloader/firmware programs the SID of display device to bypass. In order to make sure that kernel IOMMU mappings for these devices work after resume, add SID override programming support for all memory clients on memory controller resume. This partially reverts 'commit ef86b2c2807f ("memory: tegra: Remove clients SID override programming")' Signed-off-by: Ashish Mhetre Link: https://lore.kernel.org/r/20231107112713.21399-1-amhetre@nvidia.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra186.c | 14 ++++++++++++++ include/soc/tegra/mc.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 533f85a4b2bd..8203f0db1350 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -136,9 +136,23 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) return 0; } +static int tegra186_mc_resume(struct tegra_mc *mc) +{ + unsigned int i; + + for (i = 0; i < mc->soc->num_clients; i++) { + const struct tegra_mc_client *client = &mc->soc->clients[i]; + + tegra186_mc_client_sid_override(mc, client, client->sid); + } + + return 0; +} + const struct tegra_mc_ops tegra186_mc_ops = { .probe = tegra186_mc_probe, .remove = tegra186_mc_remove, + .resume = tegra186_mc_resume, .probe_device = tegra186_mc_probe_device, .handle_irq = tegra30_mc_handle_irq, }; diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index 71ae37d3bedd..af1d73a7f0cd 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -162,6 +162,7 @@ struct tegra_mc_ops { */ int (*probe)(struct tegra_mc *mc); void (*remove)(struct tegra_mc *mc); + int (*resume)(struct tegra_mc *mc); irqreturn_t (*handle_irq)(int irq, void *data); int (*probe_device)(struct tegra_mc *mc, struct device *dev); }; From 0d6c918011ce4764ed277de4726a468b7ffe5fed Mon Sep 17 00:00:00 2001 From: Ashish Mhetre Date: Tue, 7 Nov 2023 16:57:13 +0530 Subject: [PATCH 1042/7721] memory: tegra: Skip SID programming if SID registers aren't set There are few MC clients where SID security and override register offsets are not specified like "sw_cluster0" in tegra234. Don't program SID override for such clients because it leads to access to invalid addresses. Signed-off-by: Ashish Mhetre Link: https://lore.kernel.org/r/20231107112713.21399-2-amhetre@nvidia.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra186.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 8203f0db1350..d1f1dfb42716 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -75,6 +75,9 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc, { u32 value, old; + if (client->regs.sid.security == 0 && client->regs.sid.override == 0) + return; + value = readl(mc->regs + client->regs.sid.security); if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) { /* From 38360bf96d816e175bc602c4ee76953cd303b71d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 19 Sep 2023 10:12:50 +0300 Subject: [PATCH 1043/7721] drm/tilcdc: Fix irq free on unload The driver only frees the reserved irq if priv->irq_enabled is set to true. However, the driver mistakenly sets priv->irq_enabled to false, instead of true, in tilcdc_irq_install(), and thus the driver never frees the irq, causing issues on loading the driver a second time. Fixes: b6366814fa77 ("drm/tilcdc: Convert to Linux IRQ interfaces") Cc: Thomas Zimmermann Reviewed-by: Aradhya Bhatia Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20230919-lcdc-v1-1-ba60da7421e1@ideasonboard.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 8ebd7134ee21..2f6eaac7f659 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -138,7 +138,7 @@ static int tilcdc_irq_install(struct drm_device *dev, unsigned int irq) if (ret) return ret; - priv->irq_enabled = false; + priv->irq_enabled = true; return 0; } From 0807dc76f3bf500f9a22465eedd2290da7357efb Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Fri, 17 Nov 2023 02:38:10 -0800 Subject: [PATCH 1044/7721] octeon_ep: support Octeon CN10K devices Add PCI Endpoint NIC support for Octeon CN10K devices. CN10K devices are part of Octeon 10 family products with similar PCI NIC characteristics. These include: - CN10KA - CNF10KA - CNF10KB - CN10KB Update supported device list in Documentation Signed-off-by: Shinas Rasheed Link: https://lore.kernel.org/r/20231117103817.2468176-1-srasheed@marvell.com Signed-off-by: Paolo Abeni --- .../ethernet/marvell/octeon_ep.rst | 4 + .../net/ethernet/marvell/octeon_ep/Makefile | 3 +- .../marvell/octeon_ep/octep_cnxk_pf.c | 886 ++++++++++++++++++ .../ethernet/marvell/octeon_ep/octep_main.c | 20 + .../ethernet/marvell/octeon_ep/octep_main.h | 6 + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 400 ++++++++ 6 files changed, 1318 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst index cad96c8d1f97..613a818d5db6 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst @@ -24,6 +24,10 @@ Supported Devices Currently, this driver support following devices: * Network controller: Cavium, Inc. Device b200 * Network controller: Cavium, Inc. Device b400 + * Network controller: Cavium, Inc. Device b900 + * Network controller: Cavium, Inc. Device ba00 + * Network controller: Cavium, Inc. Device bc00 + * Network controller: Cavium, Inc. Device bd00 Interface Control ================= diff --git a/drivers/net/ethernet/marvell/octeon_ep/Makefile b/drivers/net/ethernet/marvell/octeon_ep/Makefile index 2026c8118158..02a4a21bc298 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/Makefile +++ b/drivers/net/ethernet/marvell/octeon_ep/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_OCTEON_EP) += octeon_ep.o octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \ - octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o + octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \ + octep_cnxk_pf.o diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c new file mode 100644 index 000000000000..abb03e9119e7 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c @@ -0,0 +1,886 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include +#include + +#include "octep_config.h" +#include "octep_main.h" +#include "octep_regs_cnxk_pf.h" + +/* We will support 128 pf's in control mbox */ +#define CTRL_MBOX_MAX_PF 128 +#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF)) + +/* Names of Hardware non-queue generic interrupts */ +static char *cnxk_non_ioq_msix_names[] = { + "epf_ire_rint", + "epf_ore_rint", + "epf_vfire_rint", + "epf_rsvd0", + "epf_vfore_rint", + "epf_rsvd1", + "epf_mbox_rint", + "epf_rsvd2_0", + "epf_rsvd2_1", + "epf_dma_rint", + "epf_dma_vf_rint", + "epf_rsvd3", + "epf_pp_vf_rint", + "epf_rsvd3", + "epf_misc_rint", + "epf_rsvd5", + /* Next 16 are for OEI_RINT */ + "epf_oei_rint0", + "epf_oei_rint1", + "epf_oei_rint2", + "epf_oei_rint3", + "epf_oei_rint4", + "epf_oei_rint5", + "epf_oei_rint6", + "epf_oei_rint7", + "epf_oei_rint8", + "epf_oei_rint9", + "epf_oei_rint10", + "epf_oei_rint11", + "epf_oei_rint12", + "epf_oei_rint13", + "epf_oei_rint14", + "epf_oei_rint15", + /* IOQ interrupt */ + "octeon_ep" +}; + +/* Dump useful hardware CSRs for debug purpose */ +static void cnxk_dump_regs(struct octep_device *oct, int qno) +{ + struct device *dev = &oct->pdev->dev; + + dev_info(dev, "IQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_INSTR_DBELL(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(qno))); + dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_CONTROL(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(qno))); + dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_ENABLE(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(qno))); + dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_INSTR_BADDR(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(qno))); + dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_INSTR_RSIZE(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(qno))); + dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_CNTS(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_CNTS(qno))); + dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_INT_LEVELS(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_PKT_CNT(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(qno))); + dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_IN_BYTE_CNT(qno), + octep_read_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(qno))); + + dev_info(dev, "OQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_SLIST_DBELL(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(qno))); + dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_CONTROL(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(qno))); + dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_ENABLE(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_SLIST_BADDR(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_SLIST_RSIZE(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(qno))); + dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_CNTS(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_CNTS(qno))); + dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_INT_LEVELS(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_PKT_CNT(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(qno))); + dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_OUT_BYTE_CNT(qno), + octep_read_csr64(oct, CNXK_SDP_R_OUT_BYTE_CNT(qno))); + dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n", + qno, CNXK_SDP_R_ERR_TYPE(qno), + octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(qno))); +} + +/* Reset Hardware Tx queue */ +static int cnxk_reset_iq(struct octep_device *oct, int q_no) +{ + struct octep_config *conf = oct->conf; + u64 val = 0ULL; + + dev_dbg(&oct->pdev->dev, "Reset PF IQ-%d\n", q_no); + + /* Get absolute queue number */ + q_no += conf->pf_ring_cfg.srn; + + /* Disable the Tx/Instruction Ring */ + octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(q_no), val); + + /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ + octep_write_csr64(oct, CNXK_SDP_R_IN_CNTS(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(q_no), val); + + val = 0xFFFFFFFF; + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(q_no), val); + + return 0; +} + +/* Reset Hardware Rx queue */ +static void cnxk_reset_oq(struct octep_device *oct, int q_no) +{ + u64 val = 0ULL; + + q_no += CFG_GET_PORTS_PF_SRN(oct->conf); + + /* Disable Output (Rx) Ring */ + octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(q_no), val); + octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(q_no), val); + + /* Clear count CSRs */ + val = octep_read_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no)); + octep_write_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no), val); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL); + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF); +} + +/* Reset all hardware Tx/Rx queues */ +static void octep_reset_io_queues_cnxk_pf(struct octep_device *oct) +{ + struct pci_dev *pdev = oct->pdev; + int q; + + dev_dbg(&pdev->dev, "Reset OCTEP_CNXK PF IO Queues\n"); + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + cnxk_reset_iq(oct, q); + cnxk_reset_oq(oct, q); + } +} + +/* Initialize windowed addresses to access some hardware registers */ +static void octep_setup_pci_window_regs_cnxk_pf(struct octep_device *oct) +{ + u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr; + + oct->pci_win_regs.pci_win_wr_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_ADDR64); + oct->pci_win_regs.pci_win_rd_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_ADDR64); + oct->pci_win_regs.pci_win_wr_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_DATA64); + oct->pci_win_regs.pci_win_rd_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_DATA64); +} + +/* Configure Hardware mapping: inform hardware which rings belong to PF. */ +static void octep_configure_ring_mapping_cnxk_pf(struct octep_device *oct) +{ + struct octep_config *conf = oct->conf; + struct pci_dev *pdev = oct->pdev; + u64 pf_srn = CFG_GET_PORTS_PF_SRN(oct->conf); + int q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(conf); q++) { + u64 regval = 0; + + if (oct->pcie_port) + regval = 8 << CNXK_SDP_FUNC_SEL_EPF_BIT_POS; + + octep_write_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q), regval); + + regval = octep_read_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q)); + dev_dbg(&pdev->dev, "Write SDP_EPVF_RING[0x%llx] = 0x%llx\n", + CNXK_SDP_EPVF_RING(pf_srn + q), regval); + } +} + +/* Initialize configuration limits and initial active config */ +static void octep_init_config_cnxk_pf(struct octep_device *oct) +{ + struct octep_config *conf = oct->conf; + struct pci_dev *pdev = oct->pdev; + u8 link = 0; + u64 val; + int pos; + + /* Read ring configuration: + * PF ring count, number of VFs and rings per VF supported + */ + val = octep_read_csr64(oct, CNXK_SDP_EPF_RINFO); + dev_info(&pdev->dev, "SDP_EPF_RINFO[0x%x]:0x%llx\n", CNXK_SDP_EPF_RINFO, val); + conf->sriov_cfg.max_rings_per_vf = CNXK_SDP_EPF_RINFO_RPVF(val); + conf->sriov_cfg.active_rings_per_vf = conf->sriov_cfg.max_rings_per_vf; + conf->sriov_cfg.max_vfs = CNXK_SDP_EPF_RINFO_NVFS(val); + conf->sriov_cfg.active_vfs = conf->sriov_cfg.max_vfs; + conf->sriov_cfg.vf_srn = CNXK_SDP_EPF_RINFO_SRN(val); + + val = octep_read_csr64(oct, CNXK_SDP_MAC_PF_RING_CTL(oct->pcie_port)); + dev_info(&pdev->dev, "SDP_MAC_PF_RING_CTL[%d]:0x%llx\n", oct->pcie_port, val); + conf->pf_ring_cfg.srn = CNXK_SDP_MAC_PF_RING_CTL_SRN(val); + conf->pf_ring_cfg.max_io_rings = CNXK_SDP_MAC_PF_RING_CTL_RPPF(val); + conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings; + dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n", + conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf, + conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings); + + conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS; + conf->iq.instr_type = OCTEP_64BYTE_INSTR; + conf->iq.db_min = OCTEP_DB_MIN; + conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD; + + conf->oq.num_descs = OCTEP_OQ_MAX_DESCRIPTORS; + conf->oq.buf_size = OCTEP_OQ_BUF_SIZE; + conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD; + conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD; + conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD; + + conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR; + conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings; + conf->msix_cfg.non_ioq_msix_names = cnxk_non_ioq_msix_names; + + pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV); + if (pos) { + pci_read_config_byte(oct->pdev, + pos + PCI_SRIOV_FUNC_LINK, + &link); + link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link); + } + conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr + + CNXK_PEM_BAR4_INDEX_OFFSET + + (link * CTRL_MBOX_SZ); + + conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL; + conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT; +} + +/* Setup registers for a hardware Tx Queue */ +static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) +{ + struct octep_iq *iq = oct->iq[iq_no]; + u32 reset_instr_cnt; + u64 reg_val; + + iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CNXK_R_IN_CTL_IDLE)) { + do { + reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no)); + } while (!(reg_val & CNXK_R_IN_CTL_IDLE)); + } + + reg_val |= CNXK_R_IN_CTL_RDSIZE; + reg_val |= CNXK_R_IN_CTL_IS_64B; + reg_val |= CNXK_R_IN_CTL_ESR; + octep_write_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no), reg_val); + + /* Write the start of the input queue's ring and its size */ + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(iq_no), + iq->desc_ring_dma); + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(iq_no), + iq->max_count); + + /* Remember the doorbell & instruction count register addr + * for this queue + */ + iq->doorbell_reg = oct->mmio[0].hw_addr + + CNXK_SDP_R_IN_INSTR_DBELL(iq_no); + iq->inst_cnt_reg = oct->mmio[0].hw_addr + + CNXK_SDP_R_IN_CNTS(iq_no); + iq->intr_lvl_reg = oct->mmio[0].hw_addr + + CNXK_SDP_R_IN_INT_LEVELS(iq_no); + + /* Store the current instruction counter (used in flush_iq calculation) */ + reset_instr_cnt = readl(iq->inst_cnt_reg); + writel(reset_instr_cnt, iq->inst_cnt_reg); + + /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ + reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff; + octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val); +} + +/* Setup registers for a hardware Rx Queue */ +static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) +{ + u64 reg_val; + u64 oq_ctl = 0ULL; + u32 time_threshold = 0; + struct octep_oq *oq = oct->oq[oq_no]; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CNXK_R_OUT_CTL_IDLE)) { + do { + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); + } + + reg_val &= ~(CNXK_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); + reg_val &= ~(CNXK_R_OUT_CTL_NSR_P); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_I); + reg_val &= ~(CNXK_R_OUT_CTL_NSR_I); + reg_val &= ~(CNXK_R_OUT_CTL_ES_I); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_D); + reg_val &= ~(CNXK_R_OUT_CTL_NSR_D); + reg_val &= ~(CNXK_R_OUT_CTL_ES_D); + reg_val |= (CNXK_R_OUT_CTL_ES_P); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), + oq->desc_ring_dma); + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), + oq->max_count); + + oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + + /* Clear the ISIZE and BSIZE (22-0) */ + oq_ctl &= ~0x7fffffULL; + + /* Populate the BSIZE (15-0) */ + oq_ctl |= (oq->buffer_size & 0xffff); + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), oq_ctl); + + /* Get the mapped address of the pkt_sent and pkts_credit regs */ + oq->pkts_sent_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_OUT_CNTS(oq_no); + oq->pkts_credit_reg = oct->mmio[0].hw_addr + + CNXK_SDP_R_OUT_SLIST_DBELL(oq_no); + + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); +} + +/* Setup registers for a PF mailbox */ +static void octep_setup_mbox_regs_cnxk_pf(struct octep_device *oct, int q_no) +{ + struct octep_mbox *mbox = oct->mbox[q_no]; + + mbox->q_no = q_no; + + /* PF mbox interrupt reg */ + mbox->mbox_int_reg = oct->mmio[0].hw_addr + CNXK_SDP_EPF_MBOX_RINT(0); + + /* PF to VF DATA reg. PF writes into this reg */ + mbox->mbox_write_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_PF_VF_DATA(q_no); + + /* VF to PF DATA reg. PF reads from this reg */ + mbox->mbox_read_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_VF_PF_DATA(q_no); +} + +/* Poll OEI events like heartbeat */ +static void octep_poll_oei_cnxk_pf(struct octep_device *oct) +{ + u64 reg0; + + /* Check for OEI INTR */ + reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_OEI_RINT); + if (reg0) { + octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT, reg0); + if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX) + queue_work(octep_wq, &oct->ctrl_mbox_task); + if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT) + atomic_set(&oct->hb_miss_cnt, 0); + } +} + +/* OEI interrupt handler */ +static irqreturn_t octep_oei_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + + octep_poll_oei_cnxk_pf(oct); + return IRQ_HANDLED; +} + +/* Process non-ioq interrupts required to keep pf interface running. + * OEI_RINT is needed for control mailbox + * MBOX_RINT is needed for pfvf mailbox + */ +static void octep_poll_non_ioq_interrupts_cnxk_pf(struct octep_device *oct) +{ + octep_poll_oei_cnxk_pf(oct); +} + +/* Interrupt handler for input ring error interrupts. */ +static irqreturn_t octep_ire_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + int i = 0; + + /* Check for IRERR INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_IRERR_RINT); + if (reg_val) { + dev_info(&pdev->dev, + "received IRERR_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT, reg_val); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + reg_val = octep_read_csr64(oct, + CNXK_SDP_R_ERR_TYPE(i)); + if (reg_val) { + dev_info(&pdev->dev, + "Received err type on IQ-%d: 0x%llx\n", + i, reg_val); + octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i), + reg_val); + } + } + } + return IRQ_HANDLED; +} + +/* Interrupt handler for output ring error interrupts. */ +static irqreturn_t octep_ore_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + int i = 0; + + /* Check for ORERR INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_ORERR_RINT); + if (reg_val) { + dev_info(&pdev->dev, + "Received ORERR_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT, reg_val); + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + reg_val = octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(i)); + if (reg_val) { + dev_info(&pdev->dev, + "Received err type on OQ-%d: 0x%llx\n", + i, reg_val); + octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i), + reg_val); + } + } + } + return IRQ_HANDLED; +} + +/* Interrupt handler for vf input ring error interrupts. */ +static irqreturn_t octep_vfire_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + + /* Check for VFIRE INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0)); + if (reg_val) { + dev_info(&pdev->dev, + "Received VFIRE_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0), reg_val); + } + return IRQ_HANDLED; +} + +/* Interrupt handler for vf output ring error interrupts. */ +static irqreturn_t octep_vfore_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + + /* Check for VFORE INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0)); + if (reg_val) { + dev_info(&pdev->dev, + "Received VFORE_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0), reg_val); + } + return IRQ_HANDLED; +} + +/* Interrupt handler for dpi dma related interrupts. */ +static irqreturn_t octep_dma_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + u64 reg_val = 0; + + /* Check for DMA INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_RINT); + if (reg_val) + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT, reg_val); + + return IRQ_HANDLED; +} + +/* Interrupt handler for dpi dma transaction error interrupts for VFs */ +static irqreturn_t octep_dma_vf_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + + /* Check for DMA VF INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0)); + if (reg_val) { + dev_info(&pdev->dev, + "Received DMA_VF_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0), reg_val); + } + return IRQ_HANDLED; +} + +/* Interrupt handler for pp transaction error interrupts for VFs */ +static irqreturn_t octep_pp_vf_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + + /* Check for PPVF INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0)); + if (reg_val) { + dev_info(&pdev->dev, + "Received PP_VF_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0), reg_val); + } + return IRQ_HANDLED; +} + +/* Interrupt handler for mac related interrupts. */ +static irqreturn_t octep_misc_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + u64 reg_val = 0; + + /* Check for MISC INTR */ + reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_MISC_RINT); + if (reg_val) { + dev_info(&pdev->dev, + "Received MISC_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT, reg_val); + } + return IRQ_HANDLED; +} + +/* Interrupts handler for all reserved interrupts. */ +static irqreturn_t octep_rsvd_intr_handler_cnxk_pf(void *dev) +{ + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; + + dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n"); + return IRQ_HANDLED; +} + +/* Tx/Rx queue interrupt handler */ +static irqreturn_t octep_ioq_intr_handler_cnxk_pf(void *data) +{ + struct octep_ioq_vector *vector = (struct octep_ioq_vector *)data; + struct octep_oq *oq = vector->oq; + + napi_schedule_irqoff(oq->napi); + return IRQ_HANDLED; +} + +/* soft reset */ +static int octep_soft_reset_cnxk_pf(struct octep_device *oct) +{ + dev_info(&oct->pdev->dev, "CNXKXX: Doing soft reset\n"); + + octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF); + + /* Firmware status CSR is supposed to be cleared by + * core domain reset, but due to a hw bug, it is not. + * Set it to RUNNING right before reset so that it is not + * left in READY (1) state after a reset. This is required + * in addition to the early setting to handle the case where + * the OcteonTX is unexpectedly reset, reboots, and then + * the module is removed. + */ + OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL), + FW_STATUS_RUNNING); + + /* Set chip domain reset bit */ + OCTEP_PCI_WIN_WRITE(oct, CNXK_RST_CHIP_DOMAIN_W1S, 1); + /* Wait till Octeon resets. */ + mdelay(10); + /* restore the reset value */ + octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF); + + return 0; +} + +/* Re-initialize Octeon hardware registers */ +static void octep_reinit_regs_cnxk_pf(struct octep_device *oct) +{ + u32 i; + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_iq_regs(oct, i); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_oq_regs(oct, i); + + oct->hw_ops.enable_interrupts(oct); + oct->hw_ops.enable_io_queues(oct); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); +} + +/* Enable all interrupts */ +static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) +{ + u64 intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + + for (i = 0; i < num_rings; i++) + intr_mask |= (0x1ULL << (srn + i)); + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL); + + octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL); + octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL); + + octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask); + + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL); + octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL); +} + +/* Disable all interrupts */ +static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) +{ + u64 intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + + for (i = 0; i < num_rings; i++) + intr_mask |= (0x1ULL << (srn + i)); + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL); + + octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL); + octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL); + + octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask); + + octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL); + octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL); +} + +/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ +static u32 octep_update_iq_read_index_cnxk_pf(struct octep_iq *iq) +{ + u32 pkt_in_done = readl(iq->inst_cnt_reg); + u32 last_done, new_idx; + + last_done = pkt_in_done - iq->pkt_in_done; + iq->pkt_in_done = pkt_in_done; + + new_idx = (iq->octep_read_index + last_done) % iq->max_count; + + return new_idx; +} + +/* Enable a hardware Tx Queue */ +static void octep_enable_iq_cnxk_pf(struct octep_device *oct, int iq_no) +{ + u64 loop = HZ; + u64 reg_val; + + iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + + octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF); + + while (octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no)) && + loop--) { + schedule_timeout_interruptible(1); + } + + reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no)); + reg_val |= (0x1ULL << 62); + octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val); + + reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no)); + reg_val |= 0x1ULL; + octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val); +} + +/* Enable a hardware Rx Queue */ +static void octep_enable_oq_cnxk_pf(struct octep_device *oct, int oq_no) +{ + u64 reg_val = 0ULL; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no)); + reg_val |= (0x1ULL << 62); + octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF); + + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no)); + reg_val |= 0x1ULL; + octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val); +} + +/* Enable all hardware Tx/Rx Queues assined to PF */ +static void octep_enable_io_queues_cnxk_pf(struct octep_device *oct) +{ + u8 q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_enable_iq_cnxk_pf(oct, q); + octep_enable_oq_cnxk_pf(oct, q); + } +} + +/* Disable a hardware Tx Queue assined to PF */ +static void octep_disable_iq_cnxk_pf(struct octep_device *oct, int iq_no) +{ + u64 reg_val = 0ULL; + + iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + + reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no)); + reg_val &= ~0x1ULL; + octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val); +} + +/* Disable a hardware Rx Queue assined to PF */ +static void octep_disable_oq_cnxk_pf(struct octep_device *oct, int oq_no) +{ + u64 reg_val = 0ULL; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no)); + reg_val &= ~0x1ULL; + octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val); +} + +/* Disable all hardware Tx/Rx Queues assined to PF */ +static void octep_disable_io_queues_cnxk_pf(struct octep_device *oct) +{ + int q = 0; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_disable_iq_cnxk_pf(oct, q); + octep_disable_oq_cnxk_pf(oct, q); + } +} + +/* Dump hardware registers (including Tx/Rx queues) for debugging. */ +static void octep_dump_registers_cnxk_pf(struct octep_device *oct) +{ + u8 srn, num_rings, q; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + + for (q = srn; q < srn + num_rings; q++) + cnxk_dump_regs(oct, q); +} + +/** + * octep_device_setup_cnxk_pf() - Setup Octeon device. + * + * @oct: Octeon device private data structure. + * + * - initialize hardware operations. + * - get target side pcie port number for the device. + * - setup window access to hardware registers. + * - set initial configuration and max limits. + * - setup hardware mapping of rings to the PF device. + */ +void octep_device_setup_cnxk_pf(struct octep_device *oct) +{ + oct->hw_ops.setup_iq_regs = octep_setup_iq_regs_cnxk_pf; + oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cnxk_pf; + oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cnxk_pf; + + oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cnxk_pf; + oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cnxk_pf; + oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cnxk_pf; + oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cnxk_pf; + oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cnxk_pf; + oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cnxk_pf; + oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cnxk_pf; + oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cnxk_pf; + oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cnxk_pf; + oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cnxk_pf; + oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cnxk_pf; + oct->hw_ops.soft_reset = octep_soft_reset_cnxk_pf; + oct->hw_ops.reinit_regs = octep_reinit_regs_cnxk_pf; + + oct->hw_ops.enable_interrupts = octep_enable_interrupts_cnxk_pf; + oct->hw_ops.disable_interrupts = octep_disable_interrupts_cnxk_pf; + oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cnxk_pf; + + oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cnxk_pf; + + oct->hw_ops.enable_iq = octep_enable_iq_cnxk_pf; + oct->hw_ops.enable_oq = octep_enable_oq_cnxk_pf; + oct->hw_ops.enable_io_queues = octep_enable_io_queues_cnxk_pf; + + oct->hw_ops.disable_iq = octep_disable_iq_cnxk_pf; + oct->hw_ops.disable_oq = octep_disable_oq_cnxk_pf; + oct->hw_ops.disable_io_queues = octep_disable_io_queues_cnxk_pf; + oct->hw_ops.reset_io_queues = octep_reset_io_queues_cnxk_pf; + + oct->hw_ops.dump_registers = octep_dump_registers_cnxk_pf; + + octep_setup_pci_window_regs_cnxk_pf(oct); + + oct->pcie_port = octep_read_csr64(oct, CNXK_SDP_MAC_NUMBER) & 0xff; + dev_info(&oct->pdev->dev, + "Octeon device using PCIE Port %d\n", oct->pcie_port); + + octep_init_config_cnxk_pf(oct); + octep_configure_ring_mapping_cnxk_pf(oct); + + /* Firmware status CSR is supposed to be cleared by + * core domain reset, but due to IPBUPEM-38842, it is not. + * Set it to RUNNING early in boot, so that unexpected resets + * leave it in a state that is not READY (1). + */ + OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL), + FW_STATUS_RUNNING); +} diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 974a34be9ffa..2da00a701df2 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -24,6 +24,10 @@ struct workqueue_struct *octep_wq; static const struct pci_device_id octep_pci_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_PF)}, {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_PF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_PF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_PF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_PF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_PF)}, {0, }, }; MODULE_DEVICE_TABLE(pci, octep_pci_id_tbl); @@ -1147,6 +1151,14 @@ static const char *octep_devid_to_str(struct octep_device *oct) return "CN93XX"; case OCTEP_PCI_DEVICE_ID_CNF95N_PF: return "CNF95N"; + case OCTEP_PCI_DEVICE_ID_CN10KA_PF: + return "CN10KA"; + case OCTEP_PCI_DEVICE_ID_CNF10KA_PF: + return "CNF10KA"; + case OCTEP_PCI_DEVICE_ID_CNF10KB_PF: + return "CNF10KB"; + case OCTEP_PCI_DEVICE_ID_CN10KB_PF: + return "CN10KB"; default: return "Unsupported"; } @@ -1192,6 +1204,14 @@ int octep_device_setup(struct octep_device *oct) OCTEP_MINOR_REV(oct)); octep_device_setup_cn93_pf(oct); break; + case OCTEP_PCI_DEVICE_ID_CNF10KA_PF: + case OCTEP_PCI_DEVICE_ID_CN10KA_PF: + case OCTEP_PCI_DEVICE_ID_CNF10KB_PF: + case OCTEP_PCI_DEVICE_ID_CN10KB_PF: + dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n", + octep_devid_to_str(oct), OCTEP_MAJOR_REV(oct), OCTEP_MINOR_REV(oct)); + octep_device_setup_cnxk_pf(oct); + break; default: dev_err(&pdev->dev, "%s: unsupported device\n", __func__); diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h index c33e046b69a4..e2fe8b28eb0e 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h @@ -23,6 +23,11 @@ #define OCTEP_PCI_DEVICE_ID_CNF95N_PF 0xB400 //95N PF +#define OCTEP_PCI_DEVICE_ID_CN10KA_PF 0xB900 //CN10KA PF +#define OCTEP_PCI_DEVICE_ID_CNF10KA_PF 0xBA00 //CNF10KA PF +#define OCTEP_PCI_DEVICE_ID_CNF10KB_PF 0xBC00 //CNF10KB PF +#define OCTEP_PCI_DEVICE_ID_CN10KB_PF 0xBD00 //CN10KB PF + #define OCTEP_MAX_QUEUES 63 #define OCTEP_MAX_IQ OCTEP_MAX_QUEUES #define OCTEP_MAX_OQ OCTEP_MAX_QUEUES @@ -386,6 +391,7 @@ int octep_setup_oqs(struct octep_device *oct); void octep_free_oqs(struct octep_device *oct); void octep_oq_dbell_init(struct octep_device *oct); void octep_device_setup_cn93_pf(struct octep_device *oct); +void octep_device_setup_cnxk_pf(struct octep_device *oct); int octep_iq_process_completions(struct octep_iq *iq, u16 budget); int octep_oq_process_rx(struct octep_oq *oq, int budget); void octep_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h new file mode 100644 index 000000000000..abe02df8af11 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#ifndef _OCTEP_REGS_CNXK_PF_H_ +#define _OCTEP_REGS_CNXK_PF_H_ + +/* ############################ RST ######################### */ +#define CNXK_RST_BOOT 0x000087E006001600ULL +#define CNXK_RST_CHIP_DOMAIN_W1S 0x000087E006001810ULL +#define CNXK_RST_CORE_DOMAIN_W1S 0x000087E006001820ULL +#define CNXK_RST_CORE_DOMAIN_W1C 0x000087E006001828ULL + +#define CNXK_CONFIG_XPANSION_BAR 0x38 +#define CNXK_CONFIG_PCIE_CAP 0x70 +#define CNXK_CONFIG_PCIE_DEVCAP 0x74 +#define CNXK_CONFIG_PCIE_DEVCTL 0x78 +#define CNXK_CONFIG_PCIE_LINKCAP 0x7C +#define CNXK_CONFIG_PCIE_LINKCTL 0x80 +#define CNXK_CONFIG_PCIE_SLOTCAP 0x84 +#define CNXK_CONFIG_PCIE_SLOTCTL 0x88 + +#define CNXK_PCIE_SRIOV_FDL 0x188 /* 0x98 */ +#define CNXK_PCIE_SRIOV_FDL_BIT_POS 0x10 +#define CNXK_PCIE_SRIOV_FDL_MASK 0xFF + +#define CNXK_CONFIG_PCIE_FLTMSK 0x720 + +/* ################# Offsets of RING, EPF, MAC ######################### */ +#define CNXK_RING_OFFSET (0x1ULL << 17) +#define CNXK_EPF_OFFSET (0x1ULL << 25) +#define CNXK_MAC_OFFSET (0x1ULL << 4) +#define CNXK_BIT_ARRAY_OFFSET (0x1ULL << 4) +#define CNXK_EPVF_RING_OFFSET (0x1ULL << 4) + +/* ################# Scratch Registers ######################### */ +#define CNXK_SDP_EPF_SCRATCH 0x209E0 + +/* ################# Window Registers ######################### */ +#define CNXK_SDP_WIN_WR_ADDR64 0x20000 +#define CNXK_SDP_WIN_RD_ADDR64 0x20010 +#define CNXK_SDP_WIN_WR_DATA64 0x20020 +#define CNXK_SDP_WIN_WR_MASK_REG 0x20030 +#define CNXK_SDP_WIN_RD_DATA64 0x20040 + +#define CNXK_SDP_MAC_NUMBER 0x2C100 + +/* ################# Global Previliged registers ######################### */ +#define CNXK_SDP_EPF_RINFO 0x209F0 + +#define CNXK_SDP_EPF_RINFO_SRN(val) ((val) & 0x7F) +#define CNXK_SDP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF) +#define CNXK_SDP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F) + +/* SDP Function select */ +#define CNXK_SDP_FUNC_SEL_EPF_BIT_POS 7 +#define CNXK_SDP_FUNC_SEL_FUNC_BIT_POS 0 + +/* ##### RING IN (Into device from PCI: Tx Ring) REGISTERS #### */ +#define CNXK_SDP_R_IN_CONTROL_START 0x10000 +#define CNXK_SDP_R_IN_ENABLE_START 0x10010 +#define CNXK_SDP_R_IN_INSTR_BADDR_START 0x10020 +#define CNXK_SDP_R_IN_INSTR_RSIZE_START 0x10030 +#define CNXK_SDP_R_IN_INSTR_DBELL_START 0x10040 +#define CNXK_SDP_R_IN_CNTS_START 0x10050 +#define CNXK_SDP_R_IN_INT_LEVELS_START 0x10060 +#define CNXK_SDP_R_IN_PKT_CNT_START 0x10080 +#define CNXK_SDP_R_IN_BYTE_CNT_START 0x10090 + +#define CNXK_SDP_R_IN_CONTROL(ring) \ + (CNXK_SDP_R_IN_CONTROL_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_ENABLE(ring) \ + (CNXK_SDP_R_IN_ENABLE_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INSTR_BADDR(ring) \ + (CNXK_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INSTR_RSIZE(ring) \ + (CNXK_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INSTR_DBELL(ring) \ + (CNXK_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_CNTS(ring) \ + (CNXK_SDP_R_IN_CNTS_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INT_LEVELS(ring) \ + (CNXK_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_PKT_CNT(ring) \ + (CNXK_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_BYTE_CNT(ring) \ + (CNXK_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET)) + +/* Rings per Virtual Function */ +#define CNXK_R_IN_CTL_RPVF_MASK (0xF) +#define CNXK_R_IN_CTL_RPVF_POS (48) + +/* Number of instructions to be read in one MAC read request. + * setting to Max value(4) + */ +#define CNXK_R_IN_CTL_IDLE (0x1ULL << 28) +#define CNXK_R_IN_CTL_RDSIZE (0x3ULL << 25) +#define CNXK_R_IN_CTL_IS_64B (0x1ULL << 24) +#define CNXK_R_IN_CTL_D_NSR (0x1ULL << 8) +#define CNXK_R_IN_CTL_D_ESR (0x1ULL << 6) +#define CNXK_R_IN_CTL_D_ROR (0x1ULL << 5) +#define CNXK_R_IN_CTL_NSR (0x1ULL << 3) +#define CNXK_R_IN_CTL_ESR (0x1ULL << 1) +#define CNXK_R_IN_CTL_ROR (0x1ULL << 0) + +#define CNXK_R_IN_CTL_MASK (CNXK_R_IN_CTL_RDSIZE | CNXK_R_IN_CTL_IS_64B) + +/* ##### RING OUT (out from device to PCI host: Rx Ring) REGISTERS #### */ +#define CNXK_SDP_R_OUT_CNTS_START 0x10100 +#define CNXK_SDP_R_OUT_INT_LEVELS_START 0x10110 +#define CNXK_SDP_R_OUT_SLIST_BADDR_START 0x10120 +#define CNXK_SDP_R_OUT_SLIST_RSIZE_START 0x10130 +#define CNXK_SDP_R_OUT_SLIST_DBELL_START 0x10140 +#define CNXK_SDP_R_OUT_CONTROL_START 0x10150 +#define CNXK_SDP_R_OUT_WMARK_START 0x10160 +#define CNXK_SDP_R_OUT_ENABLE_START 0x10170 +#define CNXK_SDP_R_OUT_PKT_CNT_START 0x10180 +#define CNXK_SDP_R_OUT_BYTE_CNT_START 0x10190 + +#define CNXK_SDP_R_OUT_CONTROL(ring) \ + (CNXK_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_ENABLE(ring) \ + (CNXK_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_SLIST_BADDR(ring) \ + (CNXK_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_SLIST_RSIZE(ring) \ + (CNXK_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \ + (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_CNTS(ring) \ + (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_INT_LEVELS(ring) \ + (CNXK_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_PKT_CNT(ring) \ + (CNXK_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_BYTE_CNT(ring) \ + (CNXK_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET)) + +/*------------------ R_OUT Masks ----------------*/ +#define CNXK_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) +#define CNXK_R_OUT_INT_LEVELS_TIMET (32) + +#define CNXK_R_OUT_CTL_IDLE BIT_ULL(40) +#define CNXK_R_OUT_CTL_ES_I BIT_ULL(34) +#define CNXK_R_OUT_CTL_NSR_I BIT_ULL(33) +#define CNXK_R_OUT_CTL_ROR_I BIT_ULL(32) +#define CNXK_R_OUT_CTL_ES_D BIT_ULL(30) +#define CNXK_R_OUT_CTL_NSR_D BIT_ULL(29) +#define CNXK_R_OUT_CTL_ROR_D BIT_ULL(28) +#define CNXK_R_OUT_CTL_ES_P BIT_ULL(26) +#define CNXK_R_OUT_CTL_NSR_P BIT_ULL(25) +#define CNXK_R_OUT_CTL_ROR_P BIT_ULL(24) +#define CNXK_R_OUT_CTL_IMODE BIT_ULL(23) + +/* ############### Interrupt Moderation Registers ############### */ +#define CNXK_SDP_R_IN_INT_MDRT_CTL0_START 0x10280 +#define CNXK_SDP_R_IN_INT_MDRT_CTL1_START 0x102A0 +#define CNXK_SDP_R_IN_INT_MDRT_DBG_START 0x102C0 + +#define CNXK_SDP_R_OUT_INT_MDRT_CTL0_START 0x10380 +#define CNXK_SDP_R_OUT_INT_MDRT_CTL1_START 0x103A0 +#define CNXK_SDP_R_OUT_INT_MDRT_DBG_START 0x103C0 + +#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510 +#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520 + +#define CNXK_SDP_R_IN_INT_MDRT_CTL0(ring) \ + (CNXK_SDP_R_IN_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INT_MDRT_CTL1(ring) \ + (CNXK_SDP_R_IN_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_INT_MDRT_DBG(ring) \ + (CNXK_SDP_R_IN_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_INT_MDRT_CTL0(ring) \ + (CNXK_SDP_R_OUT_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_INT_MDRT_CTL1(ring) \ + (CNXK_SDP_R_OUT_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_INT_MDRT_DBG(ring) \ + (CNXK_SDP_R_OUT_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \ + (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_CNTS_ISM(ring) \ + (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) + +/* ##################### Mail Box Registers ########################## */ +/* INT register for VF. when a MBOX write from PF happed to a VF, + * corresponding bit will be set in this register as well as in + * PF_VF_INT register. + * + * This is a RO register, the int can be cleared by writing 1 to PF_VF_INT + */ +/* Basically first 3 are from PF to VF. The last one is data from VF to PF */ +#define CNXK_SDP_R_MBOX_PF_VF_DATA_START 0x10210 +#define CNXK_SDP_R_MBOX_PF_VF_INT_START 0x10220 +#define CNXK_SDP_R_MBOX_VF_PF_DATA_START 0x10230 + +#define CNXK_SDP_R_MBOX_PF_VF_DATA(ring) \ + (CNXK_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_MBOX_PF_VF_INT(ring) \ + (CNXK_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_MBOX_VF_PF_DATA(ring) \ + (CNXK_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_RING_OFFSET)) + +/* ##################### Interrupt Registers ########################## */ +#define CNXK_SDP_R_ERR_TYPE_START 0x10400 + +#define CNXK_SDP_R_ERR_TYPE(ring) \ + (CNXK_SDP_R_ERR_TYPE_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_MBOX_ISM_START 0x10500 +#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510 +#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520 + +#define CNXK_SDP_R_MBOX_ISM(ring) \ + (CNXK_SDP_R_MBOX_ISM_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \ + (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_R_IN_CNTS_ISM(ring) \ + (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) + +#define CNXK_SDP_EPF_MBOX_RINT_START 0x20100 +#define CNXK_SDP_EPF_MBOX_RINT_W1S_START 0x20120 +#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START 0x20140 +#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START 0x20160 + +#define CNXK_SDP_EPF_VFIRE_RINT_START 0x20180 +#define CNXK_SDP_EPF_VFIRE_RINT_W1S_START 0x201A0 +#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START 0x201C0 +#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START 0x201E0 + +#define CNXK_SDP_EPF_IRERR_RINT 0x20200 +#define CNXK_SDP_EPF_IRERR_RINT_W1S 0x20210 +#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1C 0x20220 +#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1S 0x20230 + +#define CNXK_SDP_EPF_VFORE_RINT_START 0x20240 +#define CNXK_SDP_EPF_VFORE_RINT_W1S_START 0x20260 +#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START 0x20280 +#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START 0x202A0 + +#define CNXK_SDP_EPF_ORERR_RINT 0x20320 +#define CNXK_SDP_EPF_ORERR_RINT_W1S 0x20330 +#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1C 0x20340 +#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1S 0x20350 + +#define CNXK_SDP_EPF_OEI_RINT 0x20400 +#define CNXK_SDP_EPF_OEI_RINT_W1S 0x20500 +#define CNXK_SDP_EPF_OEI_RINT_ENA_W1C 0x20600 +#define CNXK_SDP_EPF_OEI_RINT_ENA_W1S 0x20700 + +#define CNXK_SDP_EPF_DMA_RINT 0x20800 +#define CNXK_SDP_EPF_DMA_RINT_W1S 0x20810 +#define CNXK_SDP_EPF_DMA_RINT_ENA_W1C 0x20820 +#define CNXK_SDP_EPF_DMA_RINT_ENA_W1S 0x20830 + +#define CNXK_SDP_EPF_DMA_INT_LEVEL_START 0x20840 +#define CNXK_SDP_EPF_DMA_CNT_START 0x20860 +#define CNXK_SDP_EPF_DMA_TIM_START 0x20880 + +#define CNXK_SDP_EPF_MISC_RINT 0x208A0 +#define CNXK_SDP_EPF_MISC_RINT_W1S 0x208B0 +#define CNXK_SDP_EPF_MISC_RINT_ENA_W1C 0x208C0 +#define CNXK_SDP_EPF_MISC_RINT_ENA_W1S 0x208D0 + +#define CNXK_SDP_EPF_DMA_VF_RINT_START 0x208E0 +#define CNXK_SDP_EPF_DMA_VF_RINT_W1S_START 0x20900 +#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START 0x20920 +#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START 0x20940 + +#define CNXK_SDP_EPF_PP_VF_RINT_START 0x20960 +#define CNXK_SDP_EPF_PP_VF_RINT_W1S_START 0x20980 +#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START 0x209A0 +#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START 0x209C0 + +#define CNXK_SDP_EPF_MBOX_RINT(index) \ + (CNXK_SDP_EPF_MBOX_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_MBOX_RINT_W1S(index) \ + (CNXK_SDP_EPF_MBOX_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(index) \ + (CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(index) \ + (CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) + +#define CNXK_SDP_EPF_VFIRE_RINT(index) \ + (CNXK_SDP_EPF_VFIRE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFIRE_RINT_W1S(index) \ + (CNXK_SDP_EPF_VFIRE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(index) \ + (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(index) \ + (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) + +#define CNXK_SDP_EPF_VFORE_RINT(index) \ + (CNXK_SDP_EPF_VFORE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFORE_RINT_W1S(index) \ + (CNXK_SDP_EPF_VFORE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(index) \ + (CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(index) \ + (CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) + +#define CNXK_SDP_EPF_DMA_VF_RINT(index) \ + (CNXK_SDP_EPF_DMA_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_DMA_VF_RINT_W1S(index) \ + (CNXK_SDP_EPF_DMA_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(index) \ + (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(index) \ + (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) + +#define CNXK_SDP_EPF_PP_VF_RINT(index) \ + (CNXK_SDP_EPF_PP_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_PP_VF_RINT_W1S(index) \ + (CNXK_SDP_EPF_PP_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(index) \ + (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) +#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(index) \ + (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) + +/*------------------ Interrupt Masks ----------------*/ +#define CNXK_INTR_R_SEND_ISM BIT_ULL(63) +#define CNXK_INTR_R_OUT_INT BIT_ULL(62) +#define CNXK_INTR_R_IN_INT BIT_ULL(61) +#define CNXK_INTR_R_MBOX_INT BIT_ULL(60) +#define CNXK_INTR_R_RESEND BIT_ULL(59) +#define CNXK_INTR_R_CLR_TIM BIT_ULL(58) + +/* ####################### Ring Mapping Registers ################################## */ +#define CNXK_SDP_EPVF_RING_START 0x26000 +#define CNXK_SDP_IN_RING_TB_MAP_START 0x28000 +#define CNXK_SDP_IN_RATE_LIMIT_START 0x2A000 +#define CNXK_SDP_MAC_PF_RING_CTL_START 0x2C000 + +#define CNXK_SDP_EPVF_RING(ring) \ + (CNXK_SDP_EPVF_RING_START + ((ring) * CNXK_EPVF_RING_OFFSET)) +#define CNXK_SDP_IN_RING_TB_MAP(ring) \ + (CNXK_SDP_N_RING_TB_MAP_START + ((ring) * CNXK_EPVF_RING_OFFSET)) +#define CNXK_SDP_IN_RATE_LIMIT(ring) \ + (CNXK_SDP_IN_RATE_LIMIT_START + ((ring) * CNXK_EPVF_RING_OFFSET)) +#define CNXK_SDP_MAC_PF_RING_CTL(mac) \ + (CNXK_SDP_MAC_PF_RING_CTL_START + ((mac) * CNXK_MAC_OFFSET)) + +#define CNXK_SDP_MAC_PF_RING_CTL_NPFS(val) ((val) & 0x3) +#define CNXK_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0x7F) +#define CNXK_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F) + +/* Number of non-queue interrupts in CNXKxx */ +#define CNXK_NUM_NON_IOQ_INTR 32 + +/* bit 0 for control mbox interrupt */ +#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX BIT_ULL(0) +/* bit 1 for firmware heartbeat interrupt */ +#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1) +#define FW_STATUS_RUNNING 2ULL +#define CNXK_PEMX_PFX_CSX_PFCFGX(pem, pf, offset) ({ typeof(offset) _off = (offset); \ + ((0x8e0000008000 | \ + (uint64_t)(pem) << 36 \ + | (pf) << 18 \ + | ((_off >> 16) & 1) << 16 \ + | (_off >> 3) << 3) \ + + (((_off >> 2) & 1) << 2)); \ + }) + +/* Register defines for use with CNXK_PEMX_PFX_CSX_PFCFGX */ +#define CNXK_PCIEEP_VSECST_CTL 0x418 + +#define CNXK_PEM_BAR4_INDEX 7 +#define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL +#define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) + +#endif /* _OCTEP_REGS_CNXK_PF_H_ */ From a4dea9a06f72c7885f8d4dccedec7e477878d798 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 14 Nov 2023 17:14:06 +0200 Subject: [PATCH 1045/7721] drm/edid/firmware: drop drm_kms_helper.edid_firmware backward compat Since the edid_firmware module parameter was moved from drm_kms_helper.ko to drm.ko in v4.15, we've had a backwards compatibility helper in place, with a DRM_NOTE() suggesting to migrate to drm.edid_firmware. This was added in commit ac6c35a4d8c7 ("drm: add backwards compatibility support for drm_kms_helper.edid_firmware"). More than five years and 30+ kernel releases later, drop the backward compatibility. v2: Drop the warnings too Acked-by: Daniel Vetter Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231114151406.61230-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_edid_load.c | 16 ------------- drivers/gpu/drm/drm_kms_helper_common.c | 32 ------------------------- include/drm/drm_edid.h | 5 ---- 3 files changed, 53 deletions(-) diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 5d9ef267ebb3..60fcb80bce61 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -23,22 +23,6 @@ module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " "from built-in data or /lib/firmware instead. "); -/* Use only for backward compatibility with drm_kms_helper.edid_firmware */ -int __drm_set_edid_firmware_path(const char *path) -{ - scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path); - - return 0; -} -EXPORT_SYMBOL(__drm_set_edid_firmware_path); - -/* Use only for backward compatibility with drm_kms_helper.edid_firmware */ -int __drm_get_edid_firmware_path(char *buf, size_t bufsize) -{ - return scnprintf(buf, bufsize, "%s", edid_firmware); -} -EXPORT_SYMBOL(__drm_get_edid_firmware_path); - #define GENERIC_EDIDS 6 static const char * const generic_edid_name[GENERIC_EDIDS] = { "edid/800x600.bin", diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 0bf0fc1abf54..0c7550c0462b 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -27,38 +27,6 @@ #include -#include -#include - -#include "drm_crtc_helper_internal.h" - MODULE_AUTHOR("David Airlie, Jesse Barnes"); MODULE_DESCRIPTION("DRM KMS helper"); MODULE_LICENSE("GPL and additional rights"); - -#if IS_ENABLED(CONFIG_DRM_LOAD_EDID_FIRMWARE) - -/* Backward compatibility for drm_kms_helper.edid_firmware */ -static int edid_firmware_set(const char *val, const struct kernel_param *kp) -{ - DRM_NOTE("drm_kms_helper.edid_firmware is deprecated, please use drm.edid_firmware instead.\n"); - - return __drm_set_edid_firmware_path(val); -} - -static int edid_firmware_get(char *buffer, const struct kernel_param *kp) -{ - return __drm_get_edid_firmware_path(buffer, PAGE_SIZE); -} - -static const struct kernel_param_ops edid_firmware_ops = { - .set = edid_firmware_set, - .get = edid_firmware_get, -}; - -module_param_cb(edid_firmware, &edid_firmware_ops, NULL, 0644); -__MODULE_PARM_TYPE(edid_firmware, "charp"); -MODULE_PARM_DESC(edid_firmware, - "DEPRECATED. Use drm.edid_firmware module parameter instead."); - -#endif diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index e98aa6818700..518d1b8106c7 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -329,11 +329,6 @@ int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb); int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); -#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE -int __drm_set_edid_firmware_path(const char *path); -int __drm_get_edid_firmware_path(char *buf, size_t bufsize); -#endif - bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); int From d6b83f1e3707c4d60acfa58afd3515e17e5d5384 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Sat, 18 Nov 2023 16:16:53 +0800 Subject: [PATCH 1046/7721] bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk If failed to allocate "tags" or could not find the final upper device from start_dev's upper list in bond_verify_device_path(), only the loopback detection of the current upper device should be affected, and the system is no need to be panic. So return -ENOMEM in alb_upper_dev_walk to stop walking, print some warn information when failed to allocate memory for vlan tags in bond_verify_device_path. I also think that the following function calls netdev_walk_all_upper_dev_rcu ---->>>alb_upper_dev_walk ---------->>>bond_verify_device_path From this way, "end device" can eventually be obtained from "start device" in bond_verify_device_path, IS_ERR(tags) could be instead of IS_ERR_OR_NULL(tags) in alb_upper_dev_walk. Signed-off-by: Zhengchao Shao Acked-by: Jay Vosburgh Link: https://lore.kernel.org/r/20231118081653.1481260-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni --- drivers/net/bonding/bond_alb.c | 3 ++- drivers/net/bonding/bond_main.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index dc2c7b979656..7edf0fd58c34 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -985,7 +985,8 @@ static int alb_upper_dev_walk(struct net_device *upper, if (netif_is_macvlan(upper) && !strict_match) { tags = bond_verify_device_path(bond->dev, upper, 0); if (IS_ERR_OR_NULL(tags)) - BUG(); + return -ENOMEM; + alb_send_lp_vid(slave, upper->dev_addr, tags[0].vlan_proto, tags[0].vlan_id); kfree(tags); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4e0600c7b050..d987432cee3b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2973,8 +2973,11 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, if (start_dev == end_dev) { tags = kcalloc(level + 1, sizeof(*tags), GFP_ATOMIC); - if (!tags) + if (!tags) { + net_err_ratelimited("%s: %s: Failed to allocate tags\n", + __func__, start_dev->name); return ERR_PTR(-ENOMEM); + } tags[level].vlan_proto = BOND_VLAN_PROTO_NONE; return tags; } From 7911deba293da98353569c9d19464a440b418ad0 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 19 Nov 2023 07:39:40 +0200 Subject: [PATCH 1047/7721] net: stmmac: remove extra newline from descriptors display One newline per line should be enough. Reduce the verbosity of descriptors dump. Reviewed-by: Serge Semin Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/444f3b1dd409fdb14ed2a1ae7679a86b110dadcd.1700372381.git.baruch@tkos.co.il Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 2afb2bd25977..8ab99c65ac59 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -6203,7 +6203,6 @@ static void sysfs_display_ring(void *head, int size, int extend_desc, le32_to_cpu(p->des2), le32_to_cpu(p->des3)); p++; } - seq_printf(seq, "\n"); } } From 79a4f4dfa69a8379ab34675be976c2f866c77403 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 19 Nov 2023 07:39:41 +0200 Subject: [PATCH 1048/7721] net: stmmac: reduce dma ring display code duplication The code to show extended descriptor is identical to normal one. Consolidate the code to remove duplication. Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/a2a5c5ce9338bdea60ec71d7eeb00fe757281557.1700372381.git.baruch@tkos.co.il Signed-off-by: Paolo Abeni --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8ab99c65ac59..97598c1497ea 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -6180,29 +6180,23 @@ static struct dentry *stmmac_fs_dir; static void sysfs_display_ring(void *head, int size, int extend_desc, struct seq_file *seq, dma_addr_t dma_phy_addr) { - int i; struct dma_extended_desc *ep = (struct dma_extended_desc *)head; struct dma_desc *p = (struct dma_desc *)head; + unsigned int desc_size; dma_addr_t dma_addr; + int i; + desc_size = extend_desc ? sizeof(*ep) : sizeof(*p); for (i = 0; i < size; i++) { - if (extend_desc) { - dma_addr = dma_phy_addr + i * sizeof(*ep); - seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n", - i, &dma_addr, - le32_to_cpu(ep->basic.des0), - le32_to_cpu(ep->basic.des1), - le32_to_cpu(ep->basic.des2), - le32_to_cpu(ep->basic.des3)); - ep++; - } else { - dma_addr = dma_phy_addr + i * sizeof(*p); - seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n", - i, &dma_addr, - le32_to_cpu(p->des0), le32_to_cpu(p->des1), - le32_to_cpu(p->des2), le32_to_cpu(p->des3)); + dma_addr = dma_phy_addr + i * desc_size; + seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n", + i, &dma_addr, + le32_to_cpu(p->des0), le32_to_cpu(p->des1), + le32_to_cpu(p->des2), le32_to_cpu(p->des3)); + if (extend_desc) + p = &(++ep)->basic; + else p++; - } } } From 335662889f5a5f4d5668ed6c8b5fd58913d91d15 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 19 Nov 2023 21:07:43 +0000 Subject: [PATCH 1049/7721] net: phylink: use for_each_set_bit() Use for_each_set_bit() rather than open coding the for() test_bit() loop. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Reviewed-by: Wojciech Drewek Link: https://lore.kernel.org/r/E1r4p15-00Cpxe-C7@rmk-PC.armlinux.org.uk Signed-off-by: Paolo Abeni --- drivers/net/phy/phylink.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index d2fa949ff1ea..c276f9482f78 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -697,18 +697,16 @@ static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; __ETHTOOL_DECLARE_LINK_MODE_MASK(s); struct phylink_link_state t; - int intf; + int interface; - for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { - if (test_bit(intf, interfaces)) { - linkmode_copy(s, supported); + for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) { + linkmode_copy(s, supported); - t = *state; - t.interface = intf; - if (!phylink_validate_mac_and_pcs(pl, s, &t)) { - linkmode_or(all_s, all_s, s); - linkmode_or(all_adv, all_adv, t.advertising); - } + t = *state; + t.interface = interface; + if (!phylink_validate_mac_and_pcs(pl, s, &t)) { + linkmode_or(all_s, all_s, s); + linkmode_or(all_adv, all_adv, t.advertising); } } From 86f15a5a6c13e1f01fd15975274f8e47458c185a Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Wed, 1 Nov 2023 11:51:54 -0400 Subject: [PATCH 1050/7721] ARM: dts: stm32: add STM32F746 syscfg clock The syscfg syscon was missing its clock, therefore any attempt to read/write it after clk_disable_unused() silently failed. This was preventing external pin interrupts from working if they were initialized after this point. Signed-off-by: Ben Wolsieffer Signed-off-by: Alexandre Torgue --- arch/arm/boot/dts/st/stm32f746.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/st/stm32f746.dtsi b/arch/arm/boot/dts/st/stm32f746.dtsi index 53a8e2dec9a4..d6f09dd16efc 100644 --- a/arch/arm/boot/dts/st/stm32f746.dtsi +++ b/arch/arm/boot/dts/st/stm32f746.dtsi @@ -494,6 +494,7 @@ sdio1: mmc@40012c00 { syscfg: syscon@40013800 { compatible = "st,stm32-syscfg", "syscon"; reg = <0x40013800 0x400>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SYSCFG)>; }; exti: interrupt-controller@40013c00 { From 9a7308232a118b3837800337381bb1cbae30ae1d Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Thu, 2 Nov 2023 15:37:22 -0400 Subject: [PATCH 1051/7721] ARM: dts: stm32: add SPI support on STM32F746 Add device tree nodes for the STM32F746 SPI controllers. Signed-off-by: Ben Wolsieffer Signed-off-by: Alexandre Torgue --- arch/arm/boot/dts/st/stm32f746.dtsi | 60 +++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/arm/boot/dts/st/stm32f746.dtsi b/arch/arm/boot/dts/st/stm32f746.dtsi index d6f09dd16efc..65c72b6fcc83 100644 --- a/arch/arm/boot/dts/st/stm32f746.dtsi +++ b/arch/arm/boot/dts/st/stm32f746.dtsi @@ -274,6 +274,26 @@ gcan3: gcan@40003600 { clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN3)>; }; + spi2: spi@40003800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(SPI2)>; + status = "disabled"; + }; + + spi3: spi@40003c00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40003c00 0x400>; + interrupts = <51>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(SPI3)>; + status = "disabled"; + }; + usart2: serial@40004400 { compatible = "st,stm32f7-uart"; reg = <0x40004400 0x400>; @@ -491,6 +511,26 @@ sdio1: mmc@40012c00 { status = "disabled"; }; + spi1: spi@40013000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40013000 0x400>; + interrupts = <35>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI1)>; + status = "disabled"; + }; + + spi4: spi@40013400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40013400 0x400>; + interrupts = <84>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI4)>; + status = "disabled"; + }; + syscfg: syscon@40013800 { compatible = "st,stm32-syscfg", "syscon"; reg = <0x40013800 0x400>; @@ -555,6 +595,26 @@ pwm { }; }; + spi5: spi@40015000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40015000 0x400>; + interrupts = <85>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI5)>; + status = "disabled"; + }; + + spi6: spi@40015400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40015400 0x400>; + interrupts = <86>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI6)>; + status = "disabled"; + }; + ltdc: display-controller@40016800 { compatible = "st,stm32-ltdc"; reg = <0x40016800 0x200>; From 191dc43935d1ece82bc6c9653463b3b1cd8198fb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:31 +0200 Subject: [PATCH 1052/7721] drm/dp_mst: Store the MST PBN divider value in fixed point format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On UHBR links the PBN divider is a fractional number, accordingly store it in fixed point format. For now drm_dp_get_vc_payload_bw() always returns a whole number and all callers will use only the integer part of it which should preserve the current behavior. The next patch will fix drm_dp_get_vc_payload_bw() for UHBR rates returning a fractional number for those (also accounting for the channel coding efficiency correctly). Cc: Lyude Paul Cc: Harry Wentland Cc: Alex Deucher Cc: Wayne Lin Cc: amd-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Ville Syrjälä Acked-by: Daniel Vetter Acked-by: Maarten Lankhorst [Rebased changes in dm_helpers_construct_old_payload() on drm-intel-next] Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-2-imre.deak@intel.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +++-- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 4 +++- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 5 +++-- drivers/gpu/drm/display/drm_dp_mst_topology.c | 22 +++++++++++++------ drivers/gpu/drm/i915/display/intel_dp_mst.c | 3 ++- drivers/gpu/drm/nouveau/dispnv50/disp.c | 6 +++-- include/drm/display/drm_dp_mst_helper.h | 7 +++--- 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index df3c42bb9274..2253e8fd2d18 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -6863,8 +6864,8 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, if (IS_ERR(mst_state)) return PTR_ERR(mst_state); - if (!mst_state->pbn_div) - mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); + if (!mst_state->pbn_div.full) + mst_state->pbn_div.full = dfixed_const(dm_mst_get_pbn_divider(aconnector->mst_root->dc_link)); if (!state->duplicated) { int max_bpc = conn_state->max_requested_bpc; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index baf7e5254fb3..53e323b71d26 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "dm_services.h" #include "amdgpu.h" @@ -205,13 +206,14 @@ void dm_helpers_dp_update_branch_info( static void dm_helpers_construct_old_payload( struct dc_link *link, - int pbn_per_slot, + fixed20_12 pbn_per_slot_fp, struct drm_dp_mst_atomic_payload *new_payload, struct drm_dp_mst_atomic_payload *old_payload) { struct link_mst_stream_allocation_table current_link_table = link->mst_stream_alloc_table; struct link_mst_stream_allocation *dc_alloc; + int pbn_per_slot = dfixed_trunc(pbn_per_slot_fp); int i; *old_payload = *new_payload; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 2afd1bc74978..d80f19e442bf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dm_services.h" #include "amdgpu.h" #include "amdgpu_dm.h" @@ -935,10 +936,10 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, link_timeslots_used = 0; for (i = 0; i < count; i++) - link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, mst_state->pbn_div); + link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, dfixed_trunc(mst_state->pbn_div)); fair_pbn_alloc = - (63 - link_timeslots_used) / remaining_to_increase * mst_state->pbn_div; + (63 - link_timeslots_used) / remaining_to_increase * dfixed_trunc(mst_state->pbn_div); if (initial_slack[next_index] > fair_pbn_alloc) { vars[next_index].pbn += fair_pbn_alloc; diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 0854fe428f17..7efbd8ef664f 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -3578,16 +3579,22 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, * value is in units of PBNs/(timeslots/1 MTP). This value can be used to * convert the number of PBNs required for a given stream to the number of * timeslots this stream requires in each MTP. + * + * Returns the BW / timeslot value in 20.12 fixed point format. */ -int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, - int link_rate, int link_lane_count) +fixed20_12 drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, + int link_rate, int link_lane_count) { + fixed20_12 ret; + if (link_rate == 0 || link_lane_count == 0) drm_dbg_kms(mgr->dev, "invalid link rate/lane count: (%d / %d)\n", link_rate, link_lane_count); /* See DP v2.0 2.6.4.2, VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ - return link_rate * link_lane_count / 54000; + ret.full = dfixed_const(link_rate * link_lane_count / 54000); + + return ret; } EXPORT_SYMBOL(drm_dp_get_vc_payload_bw); @@ -4335,7 +4342,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, } } - req_slots = DIV_ROUND_UP(pbn, topology_state->pbn_div); + req_slots = DIV_ROUND_UP(pbn, dfixed_trunc(topology_state->pbn_div)); drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] TU %d -> %d\n", port->connector->base.id, port->connector->name, @@ -4872,7 +4879,8 @@ void drm_dp_mst_dump_topology(struct seq_file *m, state = to_drm_dp_mst_topology_state(mgr->base.state); seq_printf(m, "\n*** Atomic state info ***\n"); seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n", - state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div); + state->payload_mask, mgr->max_payloads, state->start_slot, + dfixed_trunc(state->pbn_div)); seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | status | sink name |\n"); for (i = 0; i < mgr->max_payloads; i++) { @@ -5330,10 +5338,10 @@ drm_dp_mst_atomic_check_payload_alloc_limits(struct drm_dp_mst_topology_mgr *mgr } if (!payload_count) - mst_state->pbn_div = 0; + mst_state->pbn_div.full = dfixed_const(0); drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p TU pbn_div=%d avail=%d used=%d\n", - mgr, mst_state, mst_state->pbn_div, avail_slots, + mgr, mst_state, dfixed_trunc(mst_state->pbn_div), avail_slots, mst_state->total_avail_slots - avail_slots); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0cb9405f59ea..e5d6b811c22e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "i915_drv.h" @@ -202,7 +203,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, */ drm_WARN_ON(&i915->drm, remote_m_n.tu < crtc_state->dp_m_n.tu); crtc_state->dp_m_n.tu = remote_m_n.tu; - crtc_state->pbn = remote_m_n.tu * mst_state->pbn_div; + crtc_state->pbn = remote_m_n.tu * dfixed_trunc(mst_state->pbn_div); slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 3d390f5029f6..95fb097e5453 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -945,7 +946,8 @@ nv50_msto_prepare(struct drm_atomic_state *state, if (ret == 0) { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, payload->vc_start_slot, payload->time_slots, - payload->pbn, payload->time_slots * mst_state->pbn_div); + payload->pbn, + payload->time_slots * dfixed_trunc(mst_state->pbn_div)); } else { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } @@ -989,7 +991,7 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, if (IS_ERR(mst_state)) return PTR_ERR(mst_state); - if (!mst_state->pbn_div) { + if (!mst_state->pbn_div.full) { struct nouveau_encoder *outp = mstc->mstm->outp; mst_state->pbn_div = drm_dp_get_vc_payload_bw(&mstm->mgr, diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index a4aad6df71f1..9b19d8bd520a 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -25,6 +25,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) #include @@ -617,7 +618,7 @@ struct drm_dp_mst_topology_state { * @pbn_div: The current PBN divisor for this topology. The driver is expected to fill this * out itself. */ - int pbn_div; + fixed20_12 pbn_div; }; #define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base) @@ -839,8 +840,8 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); -int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, - int link_rate, int link_lane_count); +fixed20_12 drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, + int link_rate, int link_lane_count); int drm_dp_calc_pbn_mode(int clock, int bpp); From d389989ed530b3d8944974b7ee866b089720bc9c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 17 Nov 2023 17:09:27 +0200 Subject: [PATCH 1053/7721] drm/dp_mst: Fix PBN divider calculation for UHBR rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current way of calculating the pbn_div value, the link BW per each MTP slot, worked only for DP 1.4 link rates. Fix things up for UHBR rates calculating with the correct channel coding efficiency based on the link rate. v2: - Return the fractional pbn_div value from drm_dp_get_vc_payload_bw(). v3: - Fix rounding up quotient while calculating req_slots. (Ville) Cc: Ville Syrjälä Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Reviewed-by: Ville Syrjälä Acked-by: Daniel Vetter Acked-by: Maarten Lankhorst Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231117150929.1767227-1-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 10 +++++++--- include/drm/display/drm_dp_helper.h | 13 +++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 7efbd8ef664f..ab39c7ad9b89 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3585,14 +3585,18 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, fixed20_12 drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, int link_rate, int link_lane_count) { + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(link_rate)); fixed20_12 ret; if (link_rate == 0 || link_lane_count == 0) drm_dbg_kms(mgr->dev, "invalid link rate/lane count: (%d / %d)\n", link_rate, link_lane_count); - /* See DP v2.0 2.6.4.2, VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ - ret.full = dfixed_const(link_rate * link_lane_count / 54000); + /* See DP v2.0 2.6.4.2, 2.7.6.3 VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ + ret.full = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_rate * link_lane_count, + ch_coding_efficiency), + (1000000ULL * 8 * 5400) >> 12); return ret; } @@ -4342,7 +4346,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, } } - req_slots = DIV_ROUND_UP(pbn, dfixed_trunc(topology_state->pbn_div)); + req_slots = DIV_ROUND_UP(dfixed_const(pbn), topology_state->pbn_div.full); drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] TU %d -> %d\n", port->connector->base.id, port->connector->name, diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 194715083399..b88cc53425e0 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -252,6 +252,19 @@ drm_edp_backlight_supported(const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]) return !!(edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP); } +/** + * drm_dp_is_uhbr_rate - Determine if a link rate is UHBR + * @link_rate: link rate in 10kbits/s units + * + * Determine if the provided link rate is an UHBR rate. + * + * Returns: %True if @link_rate is an UHBR rate. + */ +static inline bool drm_dp_is_uhbr_rate(int link_rate) +{ + return link_rate >= 1000000; +} + /* * DisplayPort AUX channel */ From 94c80946ee27c9c56eb4ba3e6c024ba13ad06b9e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 20 Nov 2023 14:52:56 +0200 Subject: [PATCH 1054/7721] drm/dp_mst: Add kunit tests for drm_dp_get_vc_payload_bw() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add kunit test cases for drm_dp_get_vc_payload_bw() with all the DP1.4 and UHBR link configurations. v2: - List test cases in decreasing rate,lane count order matching the corresponding DP Standard tables. (Ville) - Add references to the DP Standard tables. v3: - Sort the testcases properly. v4: - Avoid 'stack frame size x exceeds limit y in drm_test_dp_mst_calc_pbn_div()' compiler warn. (LKP) Cc: Ville Syrjälä Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Cc: kernel test robot Acked-by: Daniel Vetter Acked-by: Maarten Lankhorst Reviewed-by: Ville Syrjälä (v3) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231120125256.2433782-1-imre.deak@intel.com --- .../gpu/drm/tests/drm_dp_mst_helper_test.c | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index e3c818dfc0e6..d916e548fcb1 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -68,6 +68,152 @@ static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases, dp_mst_calc_pbn_mode_desc); +struct drm_dp_mst_calc_pbn_div_test { + int link_rate; + int lane_count; + fixed20_12 expected; +}; + +#define fp_init(__int, __frac) { \ + .full = (__int) * (1 << 12) + \ + (__frac) * (1 << 12) / 100000 \ +} + +static const struct drm_dp_mst_calc_pbn_div_test drm_dp_mst_calc_pbn_div_dp1_4_cases[] = { + /* + * UHBR rates (DP Standard v2.1 2.7.6.3, specifying the rounded to + * closest value to 2 decimal places): + * .expected = .link_rate * .lane_count * 0.9671 / 8 / 54 / 100 + * DP1.4 rates (DP Standard v2.1 2.6.4.2): + * .expected = .link_rate * .lane_count * 0.8000 / 8 / 54 / 100 + * + * truncated to 5 decimal places. + */ + { + .link_rate = 2000000, + .lane_count = 4, + .expected = fp_init(179, 9259), /* 179.09259 */ + }, + { + .link_rate = 2000000, + .lane_count = 2, + .expected = fp_init(89, 54629), + }, + { + .link_rate = 2000000, + .lane_count = 1, + .expected = fp_init(44, 77314), + }, + { + .link_rate = 1350000, + .lane_count = 4, + .expected = fp_init(120, 88750), + }, + { + .link_rate = 1350000, + .lane_count = 2, + .expected = fp_init(60, 44375), + }, + { + .link_rate = 1350000, + .lane_count = 1, + .expected = fp_init(30, 22187), + }, + { + .link_rate = 1000000, + .lane_count = 4, + .expected = fp_init(89, 54629), + }, + { + .link_rate = 1000000, + .lane_count = 2, + .expected = fp_init(44, 77314), + }, + { + .link_rate = 1000000, + .lane_count = 1, + .expected = fp_init(22, 38657), + }, + { + .link_rate = 810000, + .lane_count = 4, + .expected = fp_init(60, 0), + }, + { + .link_rate = 810000, + .lane_count = 2, + .expected = fp_init(30, 0), + }, + { + .link_rate = 810000, + .lane_count = 1, + .expected = fp_init(15, 0), + }, + { + .link_rate = 540000, + .lane_count = 4, + .expected = fp_init(40, 0), + }, + { + .link_rate = 540000, + .lane_count = 2, + .expected = fp_init(20, 0), + }, + { + .link_rate = 540000, + .lane_count = 1, + .expected = fp_init(10, 0), + }, + { + .link_rate = 270000, + .lane_count = 4, + .expected = fp_init(20, 0), + }, + { + .link_rate = 270000, + .lane_count = 2, + .expected = fp_init(10, 0), + }, + { + .link_rate = 270000, + .lane_count = 1, + .expected = fp_init(5, 0), + }, + { + .link_rate = 162000, + .lane_count = 4, + .expected = fp_init(12, 0), + }, + { + .link_rate = 162000, + .lane_count = 2, + .expected = fp_init(6, 0), + }, + { + .link_rate = 162000, + .lane_count = 1, + .expected = fp_init(3, 0), + }, +}; + +static void drm_test_dp_mst_calc_pbn_div(struct kunit *test) +{ + const struct drm_dp_mst_calc_pbn_div_test *params = test->param_value; + /* mgr->dev is only needed by drm_dbg_kms(), but it's not called for the test cases. */ + struct drm_dp_mst_topology_mgr *mgr = test->priv; + + KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(mgr, params->link_rate, params->lane_count).full, + params->expected.full); +} + +static void dp_mst_calc_pbn_div_desc(const struct drm_dp_mst_calc_pbn_div_test *t, char *desc) +{ + sprintf(desc, "Link rate %d lane count %d", t->link_rate, t->lane_count); +} + +KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_dp1_4_cases, + dp_mst_calc_pbn_div_desc); + static u8 data[] = { 0xff, 0x00, 0xdd }; struct drm_dp_mst_sideband_msg_req_test { @@ -416,13 +562,27 @@ KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases static struct kunit_case drm_dp_mst_helper_tests[] = { KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params), + KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_gen_params), KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode, drm_dp_mst_sideband_msg_req_gen_params), { } }; +static int drm_dp_mst_helper_tests_init(struct kunit *test) +{ + struct drm_dp_mst_topology_mgr *mgr; + + mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mgr); + + test->priv = mgr; + + return 0; +} + static struct kunit_suite drm_dp_mst_helper_test_suite = { .name = "drm_dp_mst_helper", + .init = drm_dp_mst_helper_tests_init, .test_cases = drm_dp_mst_helper_tests, }; From 3c460872d2a3e6915a475e6c04cb30fcb2b87115 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:34 +0200 Subject: [PATCH 1055/7721] drm/i915/dp: Replace intel_dp_is_uhbr_rate() with drm_dp_is_uhbr_rate() Replace intel_dp_is_uhbr_rate() with the recently added drm_dp_is_uhbr_rate(). Reviewed-by: Arun R Murthy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_dp.c | 7 +------ drivers/gpu/drm/i915/display/intel_dp.h | 1 - 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 959db3f61e84..625b1ba93229 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2393,7 +2393,7 @@ add_bw_alloc_overhead(int link_clock, int bw_overhead, int pixel_data_rate, int link_data_rate, u32 *data_m, u32 *data_n) { - bool is_uhbr = intel_dp_is_uhbr_rate(link_clock); + bool is_uhbr = drm_dp_is_uhbr_rate(link_clock); int ch_coding_efficiency = drm_dp_bw_channel_coding_efficiency(is_uhbr); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3867a0d9e004..fb1557912791 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -121,15 +121,10 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) static void intel_dp_unset_edid(struct intel_dp *intel_dp); -bool intel_dp_is_uhbr_rate(int rate) -{ - return rate >= 1000000; -} - /* Is link rate UHBR and thus 128b/132b? */ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) { - return intel_dp_is_uhbr_rate(crtc_state->port_clock); + return drm_dp_is_uhbr_rate(crtc_state->port_clock); } static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index e80da6755419..664fa93bbf53 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -80,7 +80,6 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state); bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); -bool intel_dp_is_uhbr_rate(int rate); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, From c7ae0978f71222641059c20b2b025de0d8e989c7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:35 +0200 Subject: [PATCH 1056/7721] drm/i915/dp: Account for channel coding efficiency on UHBR links Apply the correct BW allocation overhead and channel coding efficiency on UHBR link rates, similarly to DP1.4 link rates. Reviewed-by: Arun R Murthy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 625b1ba93229..dd8ac647fe0e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2397,16 +2397,6 @@ add_bw_alloc_overhead(int link_clock, int bw_overhead, int ch_coding_efficiency = drm_dp_bw_channel_coding_efficiency(is_uhbr); - /* - * TODO: adjust for actual UHBR channel coding efficiency and BW - * overhead. - */ - if (is_uhbr) { - *data_m = pixel_data_rate; - *data_n = link_data_rate * 8 / 10; - return; - } - *data_m = DIV_ROUND_UP_ULL(mul_u32_u32(pixel_data_rate, bw_overhead), 1000000); *data_n = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_data_rate, ch_coding_efficiency), From 7e17537719107e7b3b942d76919d020f8c779271 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:36 +0200 Subject: [PATCH 1057/7721] drm/i915/dp: Fix UHBR link M/N values The link M/N ratio is the data rate / link symbol clock rate, fix things up accordingly. On DP 1.4 this ratio was correct as the link symbol clock rate in that case matched the link data rate (in bytes/sec units, the symbol size being 8 bits), however it wasn't correct for UHBR rates where the symbol size is 32 bits. Kudos to Arun noticing in Bspec the incorrect use of link data rate in the ratio's N value. Reviewed-by: Arun R Murthy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 16 ++++++++----- drivers/gpu/drm/i915/display/intel_dp.c | 24 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index dd8ac647fe0e..c6a2e217a7dc 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2410,6 +2410,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, struct intel_link_m_n *m_n) { u32 data_clock = DIV_ROUND_UP(bits_per_pixel_x16 * pixel_clock, 16); + u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock); u32 data_m; u32 data_n; @@ -2430,7 +2431,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, 0x8000000); compute_m_n(&m_n->link_m, &m_n->link_n, - pixel_clock, link_clock, + pixel_clock, link_symbol_clock, 0x80000); } @@ -3772,20 +3773,23 @@ int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n) { /* - * The calculation for the data clock is: + * The calculation for the data clock -> pixel clock is: * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp * But we want to avoid losing precison if possible, so: * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp)) * - * and the link clock is simpler: - * link_clock = (m * link_clock) / n + * and for link freq (10kbs units) -> pixel clock it is: + * link_symbol_clock = link_freq * 10 / link_symbol_size + * pixel_clock = (m * link_symbol_clock) / n + * or for more precision: + * pixel_clock = (m * link_freq * 10) / (n * link_symbol_size) */ if (!m_n->link_n) return 0; - return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq), - m_n->link_n); + return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq * 10), + m_n->link_n * intel_dp_link_symbol_size(link_freq)); } int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index fb1557912791..d58acc36e3be 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -127,6 +127,30 @@ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) return drm_dp_is_uhbr_rate(crtc_state->port_clock); } +/** + * intel_dp_link_symbol_size - get the link symbol size for a given link rate + * @rate: link rate in 10kbit/s units + * + * Returns the link symbol size in bits/symbol units depending on the link + * rate -> channel coding. + */ +int intel_dp_link_symbol_size(int rate) +{ + return drm_dp_is_uhbr_rate(rate) ? 32 : 10; +} + +/** + * intel_dp_link_symbol_clock - convert link rate to link symbol clock + * @rate: link rate in 10kbit/s units + * + * Returns the link symbol clock frequency in kHz units depending on the + * link rate and channel coding. + */ +int intel_dp_link_symbol_clock(int rate) +{ + return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate)); +} + static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) { intel_dp->sink_rates[0] = 162000; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 664fa93bbf53..777aa858f899 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -81,6 +81,8 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); +int intel_dp_link_symbol_size(int rate); +int intel_dp_link_symbol_clock(int rate); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd); From e86fb4dcfb3c4e9da8855312ada0f22629423b00 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:37 +0200 Subject: [PATCH 1058/7721] drm/i915/dp_mst: Calculate the BW overhead in intel_dp_mst_find_vcpi_slots_for_bpp() The next patch will calculate the PBN value directly from the pixel data rate and the BW allocation overhead, not requiring the data, link M/N and TU values for this. To prepare for that move the calculation of BW overheads from intel_dp_mst_compute_m_n() to intel_dp_mst_find_vcpi_slots_for_bpp(). While at it store link_bpp in a .4 fixed point format. Reviewed-by: Arun R Murthy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-8-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 27 ++++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index e5d6b811c22e..a5ddd1781969 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -108,15 +108,12 @@ static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, const struct intel_connector *connector, - bool ssc, bool dsc, + int overhead, int bpp_x16, struct intel_link_m_n *m_n) { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - int overhead = intel_dp_mst_bw_overhead(crtc_state, - connector, - ssc, dsc, bpp_x16); intel_link_compute_m_n(bpp_x16, crtc_state->lane_count, adjusted_mode->crtc_clock, @@ -171,7 +168,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { struct intel_link_m_n remote_m_n; - int link_bpp; + int local_bw_overhead; + int remote_bw_overhead; + int link_bpp_x16; drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); @@ -179,12 +178,22 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, if (ret) continue; - link_bpp = dsc ? bpp : - intel_dp_output_bpp(crtc_state->output_format, bpp); + link_bpp_x16 = to_bpp_x16(dsc ? bpp : + intel_dp_output_bpp(crtc_state->output_format, bpp)); - intel_dp_mst_compute_m_n(crtc_state, connector, false, dsc, to_bpp_x16(link_bpp), + local_bw_overhead = intel_dp_mst_bw_overhead(crtc_state, connector, + false, dsc, link_bpp_x16); + remote_bw_overhead = intel_dp_mst_bw_overhead(crtc_state, connector, + true, dsc, link_bpp_x16); + + intel_dp_mst_compute_m_n(crtc_state, connector, + local_bw_overhead, + link_bpp_x16, &crtc_state->dp_m_n); - intel_dp_mst_compute_m_n(crtc_state, connector, true, dsc, to_bpp_x16(link_bpp), + + intel_dp_mst_compute_m_n(crtc_state, connector, + remote_bw_overhead, + link_bpp_x16, &remote_m_n); /* From 9069b77545ca5afc222effa994c65a64ac5e6462 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 17 Nov 2023 17:09:29 +0200 Subject: [PATCH 1059/7721] drm/i915/dp_mst: Fix PBN / MTP_TU size calculation for UHBR rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm the allocated MST PBN value is calculated from the TU size (number of allocated MTP slots) as PBN = TU * pbn_div pbn_div being the link BW for each MTP slot. For DP 1.4 link rates this worked, as pbn_div there is guraranteed to be an integer number, however on UHBR this isn't the case. To get a PBN, TU pair where TU is a properly rounded-up value covering all the BW corresponding to PBN, calculate first PBN and from PBN the TU value. Calculate PBN directly from the effective pixel data rate, instead of calculating it indirectly from the corresponding TU and pbn_div values (which are in turn derived from the pixel data rate and BW overhead). Add a helper function to calculate the effective data rate, also adding a note that callers of intel_dp_link_required() may also need to check the effective data rate (vs. the data rate w/o the BW overhead). While at it add a note to check if WA#14013163432 is applicable. v2: - Fix PBN calculation, deriving it from the effective data rate directly instead of using the indirect TU and pbn_div values for this. - Add a note about WA#14013163432. (Arun) v3: - Fix rounding up quotient while calculating remote_tu. (Ville) Cc: Ville Syrjälä Reviewed-by: Arun R Murthy (v1) Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231117150929.1767227-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 19 ++++++++++++ drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 33 ++++++++++++++------- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d58acc36e3be..e7502a824047 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -355,6 +355,9 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp) /* * The required data bandwidth for a mode with given pixel clock and bpp. This * is the required net bandwidth independent of the data bandwidth efficiency. + * + * TODO: check if callers of this functions should use + * intel_dp_effective_data_rate() instead. */ int intel_dp_link_required(int pixel_clock, int bpp) @@ -363,6 +366,22 @@ intel_dp_link_required(int pixel_clock, int bpp) return DIV_ROUND_UP(pixel_clock * bpp, 8); } +/** + * intel_dp_effective_data_rate - Return the pixel data rate accounting for BW allocation overhead + * @pixel_clock: pixel clock in kHz + * @bpp_x16: bits per pixel .4 fixed point format + * @bw_overhead: BW allocation overhead in 1ppm units + * + * Return the effective pixel data rate in kB/sec units taking into account + * the provided SSC, FEC, DSC BW allocation overhead. + */ +int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, + int bw_overhead) +{ + return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_clock * bpp_x16, bw_overhead), + 1000000 * 16 * 8); +} + /* * Given a link rate and lanes, get the data bandwidth. * diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 777aa858f899..05db46b111f2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -103,6 +103,8 @@ bool intel_dp_source_supports_tps4(struct drm_i915_private *i915); bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); +int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, + int bw_overhead); int intel_dp_max_data_rate(int max_link_rate, int max_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index a5ddd1781969..d3d53e1b4489 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -115,6 +115,7 @@ static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + /* TODO: Check WA 14013163432 to set data M/N for full BW utilization. */ intel_link_compute_m_n(bpp_x16, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, @@ -124,6 +125,18 @@ static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, m_n->tu = DIV_ROUND_UP_ULL(mul_u32_u32(m_n->data_m, 64), m_n->data_n); } +static int intel_dp_mst_calc_pbn(int pixel_clock, int bpp_x16, int bw_overhead) +{ + int effective_data_rate = + intel_dp_effective_data_rate(pixel_clock, bpp_x16, bw_overhead); + + /* + * TODO: Use drm_dp_calc_pbn_mode() instead, once it's converted + * to calculate PBN with the BW overhead passed to it. + */ + return DIV_ROUND_UP(effective_data_rate * 64, 54 * 1000); +} + static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int max_bpp, @@ -167,10 +180,10 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, min_bpp, max_bpp); for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { - struct intel_link_m_n remote_m_n; int local_bw_overhead; int remote_bw_overhead; int link_bpp_x16; + int remote_tu; drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); @@ -191,11 +204,6 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, link_bpp_x16, &crtc_state->dp_m_n); - intel_dp_mst_compute_m_n(crtc_state, connector, - remote_bw_overhead, - link_bpp_x16, - &remote_m_n); - /* * The TU size programmed to the HW determines which slots in * an MTP frame are used for this stream, which needs to match @@ -210,9 +218,14 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, * crtc_state->dp_m_n.tu), provided that the driver doesn't * enable SSC on the corresponding link. */ - drm_WARN_ON(&i915->drm, remote_m_n.tu < crtc_state->dp_m_n.tu); - crtc_state->dp_m_n.tu = remote_m_n.tu; - crtc_state->pbn = remote_m_n.tu * dfixed_trunc(mst_state->pbn_div); + crtc_state->pbn = intel_dp_mst_calc_pbn(adjusted_mode->crtc_clock, + link_bpp_x16, + remote_bw_overhead); + + remote_tu = DIV_ROUND_UP(dfixed_const(crtc_state->pbn), mst_state->pbn_div.full); + + drm_WARN_ON(&i915->drm, remote_tu < crtc_state->dp_m_n.tu); + crtc_state->dp_m_n.tu = remote_tu; slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, @@ -221,7 +234,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, return slots; if (slots >= 0) { - drm_WARN_ON(&i915->drm, slots != remote_m_n.tu); + drm_WARN_ON(&i915->drm, slots != crtc_state->dp_m_n.tu); break; } From 5ee4badb4b195bd871ba6d5a2d43aac03587230a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:39 +0200 Subject: [PATCH 1060/7721] drm/i915/dp: Report a rounded-down value as the maximum data rate Callers of intel_dp_max_data_rate() use the return value as an upper bound for the BW a given mode requires. As such the rounding shouldn't result in a bigger value than the actual upper bound. Use round-down instead of -closest accordingly. Cc: Jani Nikula Reviewed-by: Stanislav Lisovskiy Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-10-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index e7502a824047..7fd883b954a6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -413,7 +413,7 @@ intel_dp_max_data_rate(int max_link_rate, int max_lanes) */ int max_link_rate_kbps = max_link_rate * 10; - max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(max_link_rate_kbps, 9671), 10000); + max_link_rate_kbps = DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps, 9671), 10000); max_link_rate = max_link_rate_kbps / 8; } @@ -423,7 +423,7 @@ intel_dp_max_data_rate(int max_link_rate, int max_lanes) * out to be a nop by coincidence, and can be skipped: * * int max_link_rate_kbps = max_link_rate * 10; - * max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 8, 10); + * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10); * max_link_rate = max_link_rate_kbps / 8; */ From b9de01d85a62ddc4fce8f28eeba64b5682431158 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:40 +0200 Subject: [PATCH 1061/7721] drm/i915/dp: Simplify intel_dp_max_data_rate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify intel_dp_max_data_rate() using drm_dp_bw_channel_coding_efficiency() to calculate the max data rate for both DP1.4 and UHBR link rates. This trades a redundant multiply/divide for readability. Cc: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-11-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 26 ++++++++++++------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7fd883b954a6..6d5a794b6b71 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -405,29 +405,27 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, int intel_dp_max_data_rate(int max_link_rate, int max_lanes) { - if (max_link_rate >= 1000000) { - /* - * UHBR rates always use 128b/132b channel encoding, and have - * 97.71% data bandwidth efficiency. Consider max_link_rate the - * link bit rate in units of 10000 bps. - */ - int max_link_rate_kbps = max_link_rate * 10; - - max_link_rate_kbps = DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps, 9671), 10000); - max_link_rate = max_link_rate_kbps / 8; - } + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate)); + int max_link_rate_kbps = max_link_rate * 10; + /* + * UHBR rates always use 128b/132b channel encoding, and have + * 97.71% data bandwidth efficiency. Consider max_link_rate the + * link bit rate in units of 10000 bps. + */ /* * Lower than UHBR rates always use 8b/10b channel encoding, and have * 80% data bandwidth efficiency for SST non-FEC. However, this turns - * out to be a nop by coincidence, and can be skipped: + * out to be a nop by coincidence: * * int max_link_rate_kbps = max_link_rate * 10; * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10); * max_link_rate = max_link_rate_kbps / 8; */ - - return max_link_rate * max_lanes; + return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes, + ch_coding_efficiency), + 1000000 * 8); } bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) From 297c76d94c8911b5d7b58afc51cfde715dd155fe Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Nov 2023 15:18:41 +0200 Subject: [PATCH 1062/7721] drm/i915/dp: Reuse intel_dp_{max,effective}_data_rate in intel_link_compute_m_n() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse intel_dp_max_data_rate() and intel_dp_effective_data_rate() in intel_link_compute_m_n(), instead of open-coding the equivalent. Note the kbit/sec -> kByte/sec unit change in the M/N values, but this not reducing the precision, as the link rate value is based anyway on a less precise 10 kbit/sec value. Suggested-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-12-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 25 +++----------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c6a2e217a7dc..f8503d917c3d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2388,36 +2388,17 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n, intel_reduce_m_n_ratio(ret_m, ret_n); } -static void -add_bw_alloc_overhead(int link_clock, int bw_overhead, - int pixel_data_rate, int link_data_rate, - u32 *data_m, u32 *data_n) -{ - bool is_uhbr = drm_dp_is_uhbr_rate(link_clock); - int ch_coding_efficiency = - drm_dp_bw_channel_coding_efficiency(is_uhbr); - - *data_m = DIV_ROUND_UP_ULL(mul_u32_u32(pixel_data_rate, bw_overhead), - 1000000); - *data_n = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_data_rate, ch_coding_efficiency), - 1000000); -} - void intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, int pixel_clock, int link_clock, int bw_overhead, struct intel_link_m_n *m_n) { - u32 data_clock = DIV_ROUND_UP(bits_per_pixel_x16 * pixel_clock, 16); u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock); - u32 data_m; - u32 data_n; + u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16, + bw_overhead); + u32 data_n = intel_dp_max_data_rate(link_clock, nlanes); - add_bw_alloc_overhead(link_clock, bw_overhead, - data_clock, - link_clock * 10 * nlanes, - &data_m, &data_n); /* * Windows/BIOS uses fixed M/N values always. Follow suit. * From 27c69d7da1084af0b8b3a20ef9ff01e9eda5270c Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 21 Nov 2023 13:25:11 +0800 Subject: [PATCH 1063/7721] ASoC: dt-bindings: sound-card-common: List sound widgets ignoring system suspend Add a property to list audio sound widgets which are marked ignoring system suspend. Paths between these endpoints are still active over suspend of the main application processor that the current operating system is running. Signed-off-by: Chancel Liu Link: https://lore.kernel.org/r/20231121052512.20235-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sound-card-common.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sound-card-common.yaml b/Documentation/devicetree/bindings/sound/sound-card-common.yaml index 3a941177f684..721950f65748 100644 --- a/Documentation/devicetree/bindings/sound/sound-card-common.yaml +++ b/Documentation/devicetree/bindings/sound/sound-card-common.yaml @@ -17,6 +17,13 @@ properties: pair of strings, the first being the connection's sink, the second being the connection's source. + ignore-suspend-widgets: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of audio sound widgets which are marked ignoring system suspend. + Paths between these endpoints are still active over suspend of the main + application processor that the current operating system is running. + model: $ref: /schemas/types.yaml#/definitions/string description: User specified audio sound card name From 5d9f746ca64c3ebfba3b650dbc4b0de705c83f3b Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 21 Nov 2023 13:25:12 +0800 Subject: [PATCH 1064/7721] ASoC: imx-rpmsg: Force codec power on in low power audio mode Low power audio mode requires binding codec still power on while Acore enters into suspend so Mcore can continue playback music. ASoC machine driver acquires DAPM endpoints through reading "ignore-suspend-widgets" property from DT and then forces the path between these endpoints ignoring suspend. If the rpmsg sound card is in low power audio mode, the suspend/resume callback of binding codec is overridden to disable the suspend/resume. Signed-off-by: Chancel Liu Link: https://lore.kernel.org/r/20231121052512.20235-2-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-rpmsg.c | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index a0c5c35817dd..e5bd63dab10c 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -2,9 +2,8 @@ // Copyright 2017-2020 NXP #include -#include +#include #include -#include #include #include #include @@ -21,8 +20,11 @@ struct imx_rpmsg { struct snd_soc_dai_link dai; struct snd_soc_card card; unsigned long sysclk; + bool lpa; }; +static struct dev_pm_ops lpa_pm; + static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), @@ -39,6 +41,58 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card) struct device *dev = card->dev; int ret; + if (data->lpa) { + struct snd_soc_component *codec_comp; + struct device_node *codec_np; + struct device_driver *codec_drv; + struct device *codec_dev = NULL; + + codec_np = data->dai.codecs->of_node; + if (codec_np) { + struct platform_device *codec_pdev; + struct i2c_client *codec_i2c; + + codec_i2c = of_find_i2c_device_by_node(codec_np); + if (codec_i2c) + codec_dev = &codec_i2c->dev; + if (!codec_dev) { + codec_pdev = of_find_device_by_node(codec_np); + if (codec_pdev) + codec_dev = &codec_pdev->dev; + } + } + if (codec_dev) { + codec_comp = snd_soc_lookup_component_nolocked(codec_dev, NULL); + if (codec_comp) { + int i, num_widgets; + const char *widgets; + struct snd_soc_dapm_context *dapm; + + num_widgets = of_property_count_strings(data->card.dev->of_node, + "ignore-suspend-widgets"); + for (i = 0; i < num_widgets; i++) { + of_property_read_string_index(data->card.dev->of_node, + "ignore-suspend-widgets", + i, &widgets); + dapm = snd_soc_component_get_dapm(codec_comp); + snd_soc_dapm_ignore_suspend(dapm, widgets); + } + } + codec_drv = codec_dev->driver; + if (codec_drv->pm) { + memcpy(&lpa_pm, codec_drv->pm, sizeof(lpa_pm)); + lpa_pm.suspend = NULL; + lpa_pm.resume = NULL; + lpa_pm.freeze = NULL; + lpa_pm.thaw = NULL; + lpa_pm.poweroff = NULL; + lpa_pm.restore = NULL; + codec_drv->pm = &lpa_pm; + } + put_device(codec_dev); + } + } + if (!data->sysclk) return 0; @@ -138,6 +192,9 @@ static int imx_rpmsg_probe(struct platform_device *pdev) goto fail; } + if (of_property_read_bool(np, "fsl,enable-lpa")) + data->lpa = true; + data->card.dev = &pdev->dev; data->card.owner = THIS_MODULE; data->card.dapm_widgets = imx_rpmsg_dapm_widgets; From 26257869672fd4a06a60c2da841e15fb2cb47bbe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Nov 2023 16:41:25 +0100 Subject: [PATCH 1065/7721] ALSA: hda: Refer to correct stream index at loops In a couple of loops over the all streams, we check the bitmap against the loop counter. A more correct reference would be, however, the index of each stream, instead. This patch corrects the check of bitmaps to the stream index. Note that this change doesn't fix anything for now; all existing drivers set up the stream indices properly, hence the loop count is always equal with the stream index. That said, this change is only for consistency. Link: https://lore.kernel.org/r/20231121154125.4888-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 6ce24e248f8e..610ea7a33cd8 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -671,17 +671,15 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, struct hdac_stream *s; bool inited = false; u64 cycle_last = 0; - int i = 0; list_for_each_entry(s, &bus->stream_list, list) { - if (streams & (1 << i)) { + if ((streams & (1 << s->index))) { azx_timecounter_init(s, inited, cycle_last); if (!inited) { inited = true; cycle_last = s->tc.cycle_last; } } - i++; } snd_pcm_gettime(runtime, &runtime->trigger_tstamp); @@ -726,14 +724,13 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, unsigned int streams) { struct hdac_bus *bus = azx_dev->bus; - int i, nwait, timeout; + int nwait, timeout; struct hdac_stream *s; for (timeout = 5000; timeout; timeout--) { nwait = 0; - i = 0; list_for_each_entry(s, &bus->stream_list, list) { - if (!(streams & (1 << i++))) + if (!(streams & (1 << s->index))) continue; if (start) { From 67c7666fe808c3a7af3cc6f9d0a3dd3acfd26115 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 21 Nov 2023 14:07:51 +0200 Subject: [PATCH 1066/7721] ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument The virtual widget example makes use of an undefined SND_SOC_DAPM_NOPM argument passed to SND_SOC_DAPM_MIXER(). Replace with the correct SND_SOC_NOPM definition. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20231121120751.77355-1-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- Documentation/sound/soc/dapm.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst index 8e44107933ab..c3154ce6e1b2 100644 --- a/Documentation/sound/soc/dapm.rst +++ b/Documentation/sound/soc/dapm.rst @@ -234,7 +234,7 @@ corresponding soft power control. In this case it is necessary to create a virtual widget - a widget with no control bits e.g. :: - SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), This can be used to merge to signal paths together in software. From 5032c607e886e0c40749a05d37b835c1757d38ff Mon Sep 17 00:00:00 2001 From: Haridhar Kalvala Date: Mon, 20 Nov 2023 17:07:31 +0530 Subject: [PATCH 1067/7721] drm/i915: ATS-M device ID update ATS-M device ID update. BSpec: 44477 Signed-off-by: Haridhar Kalvala Reviewed-by: Matt Roper Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20231120113731.1570589-1-haridhar.kalvala@intel.com --- include/drm/i915_pciids.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 1c9ea6ab3eb9..fcf1849aa47c 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -738,7 +738,8 @@ INTEL_DG2_G12_IDS(info) #define INTEL_ATS_M150_IDS(info) \ - INTEL_VGA_DEVICE(0x56C0, info) + INTEL_VGA_DEVICE(0x56C0, info), \ + INTEL_VGA_DEVICE(0x56C2, info) #define INTEL_ATS_M75_IDS(info) \ INTEL_VGA_DEVICE(0x56C1, info) From b0e2a0395312f4e53504ae84eeb5902e5518d1d7 Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Tue, 21 Nov 2023 05:35:39 +0530 Subject: [PATCH 1068/7721] selftests/bpf: Replaces the usage of CHECK calls for ASSERTs in bpf_tcp_ca bpf_tcp_ca uses the `CHECK` calls even though the use of ASSERT_ series of macros is preferred in the bpf selftests. This patch replaces all `CHECK` calls for equivalent `ASSERT_` macro calls. Signed-off-by: Yuran Pereira Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/GV1PR10MB6563F180C0F2BB4F6CFA5130E8BBA@GV1PR10MB6563.EURPRD10.PROD.OUTLOOK.COM --- .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c index 4aabeaa525d4..a88e6e07e4f5 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c @@ -20,15 +20,14 @@ static const unsigned int total_bytes = 10 * 1024 * 1024; static int expected_stg = 0xeB9F; -static int stop, duration; +static int stop; static int settcpca(int fd, const char *tcp_ca) { int err; err = setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, tcp_ca, strlen(tcp_ca)); - if (CHECK(err == -1, "setsockopt(fd, TCP_CONGESTION)", "errno:%d\n", - errno)) + if (!ASSERT_NEQ(err, -1, "setsockopt")) return -1; return 0; @@ -65,8 +64,7 @@ static void *server(void *arg) bytes += nr_sent; } - CHECK(bytes != total_bytes, "send", "%zd != %u nr_sent:%zd errno:%d\n", - bytes, total_bytes, nr_sent, errno); + ASSERT_EQ(bytes, total_bytes, "send"); done: if (fd >= 0) @@ -92,10 +90,11 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) WRITE_ONCE(stop, 0); lfd = socket(AF_INET6, SOCK_STREAM, 0); - if (CHECK(lfd == -1, "socket", "errno:%d\n", errno)) + if (!ASSERT_NEQ(lfd, -1, "socket")) return; + fd = socket(AF_INET6, SOCK_STREAM, 0); - if (CHECK(fd == -1, "socket", "errno:%d\n", errno)) { + if (!ASSERT_NEQ(fd, -1, "socket")) { close(lfd); return; } @@ -108,26 +107,27 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) sa6.sin6_family = AF_INET6; sa6.sin6_addr = in6addr_loopback; err = bind(lfd, (struct sockaddr *)&sa6, addrlen); - if (CHECK(err == -1, "bind", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "bind")) goto done; + err = getsockname(lfd, (struct sockaddr *)&sa6, &addrlen); - if (CHECK(err == -1, "getsockname", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "getsockname")) goto done; + err = listen(lfd, 1); - if (CHECK(err == -1, "listen", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "listen")) goto done; if (sk_stg_map) { err = bpf_map_update_elem(bpf_map__fd(sk_stg_map), &fd, &expected_stg, BPF_NOEXIST); - if (CHECK(err, "bpf_map_update_elem(sk_stg_map)", - "err:%d errno:%d\n", err, errno)) + if (!ASSERT_OK(err, "bpf_map_update_elem(sk_stg_map)")) goto done; } /* connect to server */ err = connect(fd, (struct sockaddr *)&sa6, addrlen); - if (CHECK(err == -1, "connect", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "connect")) goto done; if (sk_stg_map) { @@ -135,14 +135,13 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) err = bpf_map_lookup_elem(bpf_map__fd(sk_stg_map), &fd, &tmp_stg); - if (CHECK(!err || errno != ENOENT, - "bpf_map_lookup_elem(sk_stg_map)", - "err:%d errno:%d\n", err, errno)) + if (!ASSERT_ERR(err, "bpf_map_lookup_elem(sk_stg_map)") || + !ASSERT_EQ(errno, ENOENT, "bpf_map_lookup_elem(sk_stg_map)")) goto done; } err = pthread_create(&srv_thread, NULL, server, (void *)(long)lfd); - if (CHECK(err != 0, "pthread_create", "err:%d errno:%d\n", err, errno)) + if (!ASSERT_OK(err, "pthread_create")) goto done; /* recv total_bytes */ @@ -156,13 +155,12 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) bytes += nr_recv; } - CHECK(bytes != total_bytes, "recv", "%zd != %u nr_recv:%zd errno:%d\n", - bytes, total_bytes, nr_recv, errno); + ASSERT_EQ(bytes, total_bytes, "recv"); WRITE_ONCE(stop, 1); pthread_join(srv_thread, &thread_ret); - CHECK(IS_ERR(thread_ret), "pthread_join", "thread_ret:%ld", - PTR_ERR(thread_ret)); + ASSERT_OK(IS_ERR(thread_ret), "thread_ret"); + done: close(lfd); close(fd); @@ -174,7 +172,7 @@ static void test_cubic(void) struct bpf_link *link; cubic_skel = bpf_cubic__open_and_load(); - if (CHECK(!cubic_skel, "bpf_cubic__open_and_load", "failed\n")) + if (!ASSERT_OK_PTR(cubic_skel, "bpf_cubic__open_and_load")) return; link = bpf_map__attach_struct_ops(cubic_skel->maps.cubic); @@ -197,7 +195,7 @@ static void test_dctcp(void) struct bpf_link *link; dctcp_skel = bpf_dctcp__open_and_load(); - if (CHECK(!dctcp_skel, "bpf_dctcp__open_and_load", "failed\n")) + if (!ASSERT_OK_PTR(dctcp_skel, "bpf_dctcp__open_and_load")) return; link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp); @@ -207,9 +205,7 @@ static void test_dctcp(void) } do_test("bpf_dctcp", dctcp_skel->maps.sk_stg_map); - CHECK(dctcp_skel->bss->stg_result != expected_stg, - "Unexpected stg_result", "stg_result (%x) != expected_stg (%x)\n", - dctcp_skel->bss->stg_result, expected_stg); + ASSERT_EQ(dctcp_skel->bss->stg_result, expected_stg, "stg_result"); bpf_link__destroy(link); bpf_dctcp__destroy(dctcp_skel); From 3ec1114a97457398077e45b231d502d1cc30439d Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Tue, 21 Nov 2023 05:37:43 +0530 Subject: [PATCH 1069/7721] selftests/bpf: Replaces the usage of CHECK calls for ASSERTs in bind_perm bind_perm uses the `CHECK` calls even though the use of ASSERT_ series of macros is preferred in the bpf selftests. This patch replaces all `CHECK` calls for equivalent `ASSERT_` macro calls. Signed-off-by: Yuran Pereira Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/GV1PR10MB656314F467E075A106CA02BFE8BBA@GV1PR10MB6563.EURPRD10.PROD.OUTLOOK.COM --- tools/testing/selftests/bpf/prog_tests/bind_perm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bind_perm.c b/tools/testing/selftests/bpf/prog_tests/bind_perm.c index a1766a298bb7..f7cd129cb82b 100644 --- a/tools/testing/selftests/bpf/prog_tests/bind_perm.c +++ b/tools/testing/selftests/bpf/prog_tests/bind_perm.c @@ -9,8 +9,6 @@ #include "cap_helpers.h" #include "bind_perm.skel.h" -static int duration; - static int create_netns(void) { if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) @@ -27,7 +25,7 @@ void try_bind(int family, int port, int expected_errno) int fd = -1; fd = socket(family, SOCK_STREAM, 0); - if (CHECK(fd < 0, "fd", "errno %d", errno)) + if (!ASSERT_GE(fd, 0, "socket")) goto close_socket; if (family == AF_INET) { @@ -60,7 +58,7 @@ void test_bind_perm(void) return; cgroup_fd = test__join_cgroup("/bind_perm"); - if (CHECK(cgroup_fd < 0, "cg-join", "errno %d", errno)) + if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) return; skel = bind_perm__open_and_load(); From f125d09b99fc0ee43f865810390f10b8f23a2c98 Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Tue, 21 Nov 2023 05:39:25 +0530 Subject: [PATCH 1070/7721] selftests/bpf: Replaces the usage of CHECK calls for ASSERTs in bpf_obj_id bpf_obj_id uses the `CHECK` calls even though the use of ASSERT_ series of macros is preferred in the bpf selftests. This patch replaces all `CHECK` calls for equivalent `ASSERT_` macro calls. Signed-off-by: Yuran Pereira Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/GV1PR10MB65639AA3A10B4BBAA79952C7E8BBA@GV1PR10MB6563.EURPRD10.PROD.OUTLOOK.COM --- .../selftests/bpf/prog_tests/bpf_obj_id.c | 210 +++++++----------- 1 file changed, 76 insertions(+), 134 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c index 675b90b15280..f09d6ac2ef09 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c @@ -25,7 +25,7 @@ void serial_test_bpf_obj_id(void) */ __u32 map_ids[nr_iters + 1]; char jited_insns[128], xlated_insns[128], zeros[128], tp_name[128]; - __u32 i, next_id, info_len, nr_id_found, duration = 0; + __u32 i, next_id, info_len, nr_id_found; struct timespec real_time_ts, boot_time_ts; int err = 0; __u64 array_value; @@ -33,16 +33,16 @@ void serial_test_bpf_obj_id(void) time_t now, load_time; err = bpf_prog_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-prog-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_prog_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_prog_get_fd_by_id"); err = bpf_map_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); err = bpf_link_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-link-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); /* Check bpf_map_get_info_by_fd() */ bzero(zeros, sizeof(zeros)); @@ -53,25 +53,26 @@ void serial_test_bpf_obj_id(void) /* test_obj_id.o is a dumb prog. It should never fail * to load. */ - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "bpf_prog_test_load")) continue; /* Insert a magic value to the map */ map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); - if (CHECK_FAIL(map_fds[i] < 0)) - goto done; - err = bpf_map_update_elem(map_fds[i], &array_key, - &array_magic_value, 0); - if (CHECK_FAIL(err)) + if (!ASSERT_GE(map_fds[i], 0, "bpf_find_map")) goto done; - prog = bpf_object__find_program_by_name(objs[i], - "test_obj_id"); - if (CHECK_FAIL(!prog)) + err = bpf_map_update_elem(map_fds[i], &array_key, + &array_magic_value, 0); + if (!ASSERT_OK(err, "bpf_map_update_elem")) goto done; + + prog = bpf_object__find_program_by_name(objs[i], "test_obj_id"); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto done; + links[i] = bpf_program__attach(prog); err = libbpf_get_error(links[i]); - if (CHECK(err, "prog_attach", "prog #%d, err %d\n", i, err)) { + if (!ASSERT_OK(err, "bpf_program__attach")) { links[i] = NULL; goto done; } @@ -81,24 +82,14 @@ void serial_test_bpf_obj_id(void) bzero(&map_infos[i], info_len); err = bpf_map_get_info_by_fd(map_fds[i], &map_infos[i], &info_len); - if (CHECK(err || - map_infos[i].type != BPF_MAP_TYPE_ARRAY || - map_infos[i].key_size != sizeof(__u32) || - map_infos[i].value_size != sizeof(__u64) || - map_infos[i].max_entries != 1 || - map_infos[i].map_flags != 0 || - info_len != sizeof(struct bpf_map_info) || - strcmp((char *)map_infos[i].name, expected_map_name), - "get-map-info(fd)", - "err %d errno %d type %d(%d) info_len %u(%zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n", - err, errno, - map_infos[i].type, BPF_MAP_TYPE_ARRAY, - info_len, sizeof(struct bpf_map_info), - map_infos[i].key_size, - map_infos[i].value_size, - map_infos[i].max_entries, - map_infos[i].map_flags, - map_infos[i].name, expected_map_name)) + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd") || + !ASSERT_EQ(map_infos[i].type, BPF_MAP_TYPE_ARRAY, "map_type") || + !ASSERT_EQ(map_infos[i].key_size, sizeof(__u32), "key_size") || + !ASSERT_EQ(map_infos[i].value_size, sizeof(__u64), "value_size") || + !ASSERT_EQ(map_infos[i].max_entries, 1, "max_entries") || + !ASSERT_EQ(map_infos[i].map_flags, 0, "map_flags") || + !ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "map_info_len") || + !ASSERT_STREQ((char *)map_infos[i].name, expected_map_name, "map_name")) goto done; /* Check getting prog info */ @@ -112,48 +103,34 @@ void serial_test_bpf_obj_id(void) prog_infos[i].xlated_prog_len = sizeof(xlated_insns); prog_infos[i].map_ids = ptr_to_u64(map_ids + i); prog_infos[i].nr_map_ids = 2; + err = clock_gettime(CLOCK_REALTIME, &real_time_ts); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "clock_gettime")) goto done; + err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "clock_gettime")) goto done; + err = bpf_prog_get_info_by_fd(prog_fds[i], &prog_infos[i], &info_len); load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + (prog_infos[i].load_time / nsec_per_sec); - if (CHECK(err || - prog_infos[i].type != BPF_PROG_TYPE_RAW_TRACEPOINT || - info_len != sizeof(struct bpf_prog_info) || - (env.jit_enabled && !prog_infos[i].jited_prog_len) || - (env.jit_enabled && - !memcmp(jited_insns, zeros, sizeof(zeros))) || - !prog_infos[i].xlated_prog_len || - !memcmp(xlated_insns, zeros, sizeof(zeros)) || - load_time < now - 60 || load_time > now + 60 || - prog_infos[i].created_by_uid != my_uid || - prog_infos[i].nr_map_ids != 1 || - *(int *)(long)prog_infos[i].map_ids != map_infos[i].id || - strcmp((char *)prog_infos[i].name, expected_prog_name), - "get-prog-info(fd)", - "err %d errno %d i %d type %d(%d) info_len %u(%zu) " - "jit_enabled %d jited_prog_len %u xlated_prog_len %u " - "jited_prog %d xlated_prog %d load_time %lu(%lu) " - "uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) " - "name %s(%s)\n", - err, errno, i, - prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, - info_len, sizeof(struct bpf_prog_info), - env.jit_enabled, - prog_infos[i].jited_prog_len, - prog_infos[i].xlated_prog_len, - !!memcmp(jited_insns, zeros, sizeof(zeros)), - !!memcmp(xlated_insns, zeros, sizeof(zeros)), - load_time, now, - prog_infos[i].created_by_uid, my_uid, - prog_infos[i].nr_map_ids, 1, - *(int *)(long)prog_infos[i].map_ids, map_infos[i].id, - prog_infos[i].name, expected_prog_name)) + + if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") || + !ASSERT_EQ(prog_infos[i].type, BPF_PROG_TYPE_RAW_TRACEPOINT, "prog_type") || + !ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len") || + !ASSERT_FALSE((env.jit_enabled && !prog_infos[i].jited_prog_len), "jited_prog_len") || + !ASSERT_FALSE((env.jit_enabled && !memcmp(jited_insns, zeros, sizeof(zeros))), + "jited_insns") || + !ASSERT_NEQ(prog_infos[i].xlated_prog_len, 0, "xlated_prog_len") || + !ASSERT_NEQ(memcmp(xlated_insns, zeros, sizeof(zeros)), 0, "xlated_insns") || + !ASSERT_GE(load_time, (now - 60), "load_time") || + !ASSERT_LE(load_time, (now + 60), "load_time") || + !ASSERT_EQ(prog_infos[i].created_by_uid, my_uid, "created_by_uid") || + !ASSERT_EQ(prog_infos[i].nr_map_ids, 1, "nr_map_ids") || + !ASSERT_EQ(*(int *)(long)prog_infos[i].map_ids, map_infos[i].id, "map_ids") || + !ASSERT_STREQ((char *)prog_infos[i].name, expected_prog_name, "prog_name")) goto done; /* Check getting link info */ @@ -163,25 +140,12 @@ void serial_test_bpf_obj_id(void) link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name); err = bpf_link_get_info_by_fd(bpf_link__fd(links[i]), &link_infos[i], &info_len); - if (CHECK(err || - link_infos[i].type != BPF_LINK_TYPE_RAW_TRACEPOINT || - link_infos[i].prog_id != prog_infos[i].id || - link_infos[i].raw_tracepoint.tp_name != ptr_to_u64(&tp_name) || - strcmp(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), - "sys_enter") || - info_len != sizeof(struct bpf_link_info), - "get-link-info(fd)", - "err %d errno %d info_len %u(%zu) type %d(%d) id %d " - "prog_id %d (%d) tp_name %s(%s)\n", - err, errno, - info_len, sizeof(struct bpf_link_info), - link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, - link_infos[i].id, - link_infos[i].prog_id, prog_infos[i].id, - (const char *)u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), - "sys_enter")) + if (!ASSERT_OK(err, "bpf_link_get_info_by_fd") || + !ASSERT_EQ(link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, "link_type") || + !ASSERT_EQ(link_infos[i].prog_id, prog_infos[i].id, "prog_id") || + !ASSERT_EQ(link_infos[i].raw_tracepoint.tp_name, ptr_to_u64(&tp_name), "&tp_name") || + !ASSERT_STREQ(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), "sys_enter", "tp_name")) goto done; - } /* Check bpf_prog_get_next_id() */ @@ -190,7 +154,7 @@ void serial_test_bpf_obj_id(void) while (!bpf_prog_get_next_id(next_id, &next_id)) { struct bpf_prog_info prog_info = {}; __u32 saved_map_id; - int prog_fd; + int prog_fd, cmp_res; info_len = sizeof(prog_info); @@ -198,9 +162,7 @@ void serial_test_bpf_obj_id(void) if (prog_fd < 0 && errno == ENOENT) /* The bpf_prog is in the dead row */ continue; - if (CHECK(prog_fd < 0, "get-prog-fd(next_id)", - "prog_fd %d next_id %d errno %d\n", - prog_fd, next_id, errno)) + if (!ASSERT_GE(prog_fd, 0, "bpf_prog_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -218,9 +180,8 @@ void serial_test_bpf_obj_id(void) */ prog_info.nr_map_ids = 1; err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); - if (CHECK(!err || errno != EFAULT, - "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)", - err, errno, EFAULT)) + if (!ASSERT_ERR(err, "bpf_prog_get_info_by_fd") || + !ASSERT_EQ(errno, EFAULT, "bpf_prog_get_info_by_fd")) break; bzero(&prog_info, sizeof(prog_info)); info_len = sizeof(prog_info); @@ -231,27 +192,22 @@ void serial_test_bpf_obj_id(void) err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); prog_infos[i].jited_prog_insns = 0; prog_infos[i].xlated_prog_insns = 0; - CHECK(err || info_len != sizeof(struct bpf_prog_info) || - memcmp(&prog_info, &prog_infos[i], info_len) || - *(int *)(long)prog_info.map_ids != saved_map_id, - "get-prog-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d map_id %u(%u)\n", - err, errno, info_len, sizeof(struct bpf_prog_info), - memcmp(&prog_info, &prog_infos[i], info_len), - *(int *)(long)prog_info.map_ids, saved_map_id); + cmp_res = memcmp(&prog_info, &prog_infos[i], info_len); + + ASSERT_OK(err, "bpf_prog_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len"); + ASSERT_OK(cmp_res, "memcmp"); + ASSERT_EQ(*(int *)(long)prog_info.map_ids, saved_map_id, "map_id"); close(prog_fd); } - CHECK(nr_id_found != nr_iters, - "check total prog id found by get_next_id", - "nr_id_found %u(%u)\n", - nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "prog_nr_id_found"); /* Check bpf_map_get_next_id() */ nr_id_found = 0; next_id = 0; while (!bpf_map_get_next_id(next_id, &next_id)) { struct bpf_map_info map_info = {}; - int map_fd; + int map_fd, cmp_res; info_len = sizeof(map_info); @@ -259,9 +215,7 @@ void serial_test_bpf_obj_id(void) if (map_fd < 0 && errno == ENOENT) /* The bpf_map is in the dead row */ continue; - if (CHECK(map_fd < 0, "get-map-fd(next_id)", - "map_fd %d next_id %u errno %d\n", - map_fd, next_id, errno)) + if (!ASSERT_GE(map_fd, 0, "bpf_map_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -274,25 +228,19 @@ void serial_test_bpf_obj_id(void) nr_id_found++; err = bpf_map_lookup_elem(map_fd, &array_key, &array_value); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "bpf_map_lookup_elem")) goto done; err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len); - CHECK(err || info_len != sizeof(struct bpf_map_info) || - memcmp(&map_info, &map_infos[i], info_len) || - array_value != array_magic_value, - "check get-map-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d array_value %llu(%llu)\n", - err, errno, info_len, sizeof(struct bpf_map_info), - memcmp(&map_info, &map_infos[i], info_len), - array_value, array_magic_value); + cmp_res = memcmp(&map_info, &map_infos[i], info_len); + ASSERT_OK(err, "bpf_map_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "info_len"); + ASSERT_OK(cmp_res, "memcmp"); + ASSERT_EQ(array_value, array_magic_value, "array_value"); close(map_fd); } - CHECK(nr_id_found != nr_iters, - "check total map id found by get_next_id", - "nr_id_found %u(%u)\n", - nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "map_nr_id_found"); /* Check bpf_link_get_next_id() */ nr_id_found = 0; @@ -308,9 +256,7 @@ void serial_test_bpf_obj_id(void) if (link_fd < 0 && errno == ENOENT) /* The bpf_link is in the dead row */ continue; - if (CHECK(link_fd < 0, "get-link-fd(next_id)", - "link_fd %d next_id %u errno %d\n", - link_fd, next_id, errno)) + if (!ASSERT_GE(link_fd, 0, "bpf_link_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -325,17 +271,13 @@ void serial_test_bpf_obj_id(void) err = bpf_link_get_info_by_fd(link_fd, &link_info, &info_len); cmp_res = memcmp(&link_info, &link_infos[i], offsetof(struct bpf_link_info, raw_tracepoint)); - CHECK(err || info_len != sizeof(link_info) || cmp_res, - "check get-link-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d\n", - err, errno, info_len, sizeof(struct bpf_link_info), - cmp_res); + ASSERT_OK(err, "bpf_link_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(link_info), "info_len"); + ASSERT_OK(cmp_res, "memcmp"); close(link_fd); } - CHECK(nr_id_found != nr_iters, - "check total link id found by get_next_id", - "nr_id_found %u(%u)\n", nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "link_nr_id_found"); done: for (i = 0; i < nr_iters; i++) { From 3ece0e85f679c23d2a5128993846c58a2f5f890e Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Tue, 21 Nov 2023 05:40:41 +0530 Subject: [PATCH 1071/7721] selftests/bpf: Replaces the usage of CHECK calls for ASSERTs in vmlinux vmlinux.c uses the `CHECK` calls even though the use of ASSERT_ series of macros is preferred in the bpf selftests. This patch replaces all `CHECK` calls for equivalent `ASSERT_` macro calls. Signed-off-by: Yuran Pereira Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/GV1PR10MB6563ED1023A2A3AEF30BDA5DE8BBA@GV1PR10MB6563.EURPRD10.PROD.OUTLOOK.COM --- tools/testing/selftests/bpf/prog_tests/vmlinux.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/vmlinux.c b/tools/testing/selftests/bpf/prog_tests/vmlinux.c index 72310cfc6474..6fb2217d940b 100644 --- a/tools/testing/selftests/bpf/prog_tests/vmlinux.c +++ b/tools/testing/selftests/bpf/prog_tests/vmlinux.c @@ -16,27 +16,27 @@ static void nsleep() void test_vmlinux(void) { - int duration = 0, err; + int err; struct test_vmlinux* skel; struct test_vmlinux__bss *bss; skel = test_vmlinux__open_and_load(); - if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) + if (!ASSERT_OK_PTR(skel, "test_vmlinux__open_and_load")) return; bss = skel->bss; err = test_vmlinux__attach(skel); - if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err)) + if (!ASSERT_OK(err, "test_vmlinux__attach")) goto cleanup; /* trigger everything */ nsleep(); - CHECK(!bss->tp_called, "tp", "not called\n"); - CHECK(!bss->raw_tp_called, "raw_tp", "not called\n"); - CHECK(!bss->tp_btf_called, "tp_btf", "not called\n"); - CHECK(!bss->kprobe_called, "kprobe", "not called\n"); - CHECK(!bss->fentry_called, "fentry", "not called\n"); + ASSERT_TRUE(bss->tp_called, "tp"); + ASSERT_TRUE(bss->raw_tp_called, "raw_tp"); + ASSERT_TRUE(bss->tp_btf_called, "tp_btf"); + ASSERT_TRUE(bss->kprobe_called, "kprobe"); + ASSERT_TRUE(bss->fentry_called, "fentry"); cleanup: test_vmlinux__destroy(skel); From 9862ec7ac1cbc6eb5ee4a045b5d5b8edbb2f7e68 Mon Sep 17 00:00:00 2001 From: Osama Muhammad Date: Wed, 11 Oct 2023 23:46:37 +0500 Subject: [PATCH 1072/7721] FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree Syzkaller reported the following issue: UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dmap.c:2867:6 index 196694 is out of range for type 's8[1365]' (aka 'signed char[1365]') CPU: 1 PID: 109 Comm: jfsCommit Not tainted 6.6.0-rc3-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/04/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1e7/0x2d0 lib/dump_stack.c:106 ubsan_epilogue lib/ubsan.c:217 [inline] __ubsan_handle_out_of_bounds+0x11c/0x150 lib/ubsan.c:348 dbAdjTree+0x474/0x4f0 fs/jfs/jfs_dmap.c:2867 dbJoin+0x210/0x2d0 fs/jfs/jfs_dmap.c:2834 dbFreeBits+0x4eb/0xda0 fs/jfs/jfs_dmap.c:2331 dbFreeDmap fs/jfs/jfs_dmap.c:2080 [inline] dbFree+0x343/0x650 fs/jfs/jfs_dmap.c:402 txFreeMap+0x798/0xd50 fs/jfs/jfs_txnmgr.c:2534 txUpdateMap+0x342/0x9e0 txLazyCommit fs/jfs/jfs_txnmgr.c:2664 [inline] jfs_lazycommit+0x47a/0xb70 fs/jfs/jfs_txnmgr.c:2732 kthread+0x2d3/0x370 kernel/kthread.c:388 ret_from_fork+0x48/0x80 arch/x86/kernel/process.c:147 ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:304 ================================================================================ Kernel panic - not syncing: UBSAN: panic_on_warn set ... CPU: 1 PID: 109 Comm: jfsCommit Not tainted 6.6.0-rc3-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/04/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1e7/0x2d0 lib/dump_stack.c:106 panic+0x30f/0x770 kernel/panic.c:340 check_panic_on_warn+0x82/0xa0 kernel/panic.c:236 ubsan_epilogue lib/ubsan.c:223 [inline] __ubsan_handle_out_of_bounds+0x13c/0x150 lib/ubsan.c:348 dbAdjTree+0x474/0x4f0 fs/jfs/jfs_dmap.c:2867 dbJoin+0x210/0x2d0 fs/jfs/jfs_dmap.c:2834 dbFreeBits+0x4eb/0xda0 fs/jfs/jfs_dmap.c:2331 dbFreeDmap fs/jfs/jfs_dmap.c:2080 [inline] dbFree+0x343/0x650 fs/jfs/jfs_dmap.c:402 txFreeMap+0x798/0xd50 fs/jfs/jfs_txnmgr.c:2534 txUpdateMap+0x342/0x9e0 txLazyCommit fs/jfs/jfs_txnmgr.c:2664 [inline] jfs_lazycommit+0x47a/0xb70 fs/jfs/jfs_txnmgr.c:2732 kthread+0x2d3/0x370 kernel/kthread.c:388 ret_from_fork+0x48/0x80 arch/x86/kernel/process.c:147 ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:304 Kernel Offset: disabled Rebooting in 86400 seconds.. The issue is caused when the value of lp becomes greater than CTLTREESIZE which is the max size of stree. Adding a simple check solves this issue. Dave: As the function returns a void, good error handling would require a more intrusive code reorganization, so I modified Osama's patch at use WARN_ON_ONCE for lack of a cleaner option. The patch is tested via syzbot. Reported-by: syzbot+39ba34a099ac2e9bd3cb@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=39ba34a099ac2e9bd3cb Signed-off-by: Osama Muhammad Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 11c77757ead9..d55f0dd8d754 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -2871,6 +2871,9 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval) /* is the current value the same as the old value ? if so, * there is nothing to do. */ + if (WARN_ON_ONCE(lp >= CTLTREESIZE)) + return; + if (tp->dmt_stree[lp] == newval) return; From 27e56f59bab5ddafbcfe69ad7a4a6ea1279c1b16 Mon Sep 17 00:00:00 2001 From: Osama Muhammad Date: Sat, 14 Oct 2023 00:10:28 +0500 Subject: [PATCH 1073/7721] UBSAN: array-index-out-of-bounds in dtSplitRoot Syzkaller reported the following issue: oop0: detected capacity change from 0 to 32768 UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:1971:9 index -2 is out of range for type 'struct dtslot [128]' CPU: 0 PID: 3613 Comm: syz-executor270 Not tainted 6.0.0-syzkaller-09423-g493ffd6605b2 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/22/2022 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1b1/0x28e lib/dump_stack.c:106 ubsan_epilogue lib/ubsan.c:151 [inline] __ubsan_handle_out_of_bounds+0xdb/0x130 lib/ubsan.c:283 dtSplitRoot+0x8d8/0x1900 fs/jfs/jfs_dtree.c:1971 dtSplitUp fs/jfs/jfs_dtree.c:985 [inline] dtInsert+0x1189/0x6b80 fs/jfs/jfs_dtree.c:863 jfs_mkdir+0x757/0xb00 fs/jfs/namei.c:270 vfs_mkdir+0x3b3/0x590 fs/namei.c:4013 do_mkdirat+0x279/0x550 fs/namei.c:4038 __do_sys_mkdirat fs/namei.c:4053 [inline] __se_sys_mkdirat fs/namei.c:4051 [inline] __x64_sys_mkdirat+0x85/0x90 fs/namei.c:4051 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7fcdc0113fd9 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffeb8bc67d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000102 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcdc0113fd9 RDX: 0000000000000000 RSI: 0000000020000340 RDI: 0000000000000003 RBP: 00007fcdc00d37a0 R08: 0000000000000000 R09: 00007fcdc00d37a0 R10: 00005555559a72c0 R11: 0000000000000246 R12: 00000000f8008000 R13: 0000000000000000 R14: 00083878000000f8 R15: 0000000000000000 The issue is caused when the value of fsi becomes less than -1. The check to break the loop when fsi value becomes -1 is present but syzbot was able to produce value less than -1 which cause the error. This patch simply add the change for the values less than 0. The patch is tested via syzbot. Reported-and-tested-by: syzbot+d4b1df2e9d4ded6488ec@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=d4b1df2e9d4ded6488ec Signed-off-by: Osama Muhammad Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 92b7c533407c..f3d3e8b3f50c 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1970,7 +1970,7 @@ static int dtSplitRoot(tid_t tid, do { f = &rp->slot[fsi]; fsi = f->next; - } while (fsi != -1); + } while (fsi >= 0); f->next = n; } From fa5492ee89463a7590a1449358002ff7ef63529f Mon Sep 17 00:00:00 2001 From: Manas Ghandat Date: Wed, 25 Oct 2023 11:39:07 +0530 Subject: [PATCH 1074/7721] jfs: fix slab-out-of-bounds Read in dtSearch Currently while searching for current page in the sorted entry table of the page there is a out of bound access. Added a bound check to fix the error. Dave: Set return code to -EIO Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202310241724.Ed02yUz9-lkp@intel.com/ Signed-off-by: Manas Ghandat Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dtree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index f3d3e8b3f50c..031d8f570f58 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -633,6 +633,11 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) { index = base + (lim >> 1); + if (stbl[index] < 0) { + rc = -EIO; + goto out; + } + if (p->header.flag & BT_LEAF) { /* uppercase leaf name to compare */ cmp = From 74ecdda68242b174920fe7c6133a856fb7d8559b Mon Sep 17 00:00:00 2001 From: Manas Ghandat Date: Tue, 17 Oct 2023 17:33:56 +0530 Subject: [PATCH 1075/7721] jfs: fix array-index-out-of-bounds in dbAdjTree Currently there is a bound check missing in the dbAdjTree while accessing the dmt_stree. To add the required check added the bool is_ctl which is required to determine the size as suggest in the following commit. https://lore.kernel.org/linux-kernel-mentees/f9475918-2186-49b8-b801-6f0f9e75f4fa@oracle.com/ Reported-by: syzbot+39ba34a099ac2e9bd3cb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=39ba34a099ac2e9bd3cb Signed-off-by: Manas Ghandat Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dmap.c | 60 ++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index d55f0dd8d754..cb3cda1390ad 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -63,10 +63,10 @@ */ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks); -static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval); -static int dbBackSplit(dmtree_t * tp, int leafno); -static int dbJoin(dmtree_t * tp, int leafno, int newval); -static void dbAdjTree(dmtree_t * tp, int leafno, int newval); +static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl); +static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl); +static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl); +static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl); static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level); static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results); @@ -2103,7 +2103,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, * system. */ if (dp->tree.stree[word] == NOFREE) - dbBackSplit((dmtree_t *) & dp->tree, word); + dbBackSplit((dmtree_t *)&dp->tree, word, false); dbAllocBits(bmp, dp, blkno, nblocks); } @@ -2189,7 +2189,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, * the binary system of the leaves if need be. */ dbSplit(tp, word, BUDMIN, - dbMaxBud((u8 *) & dp->wmap[word])); + dbMaxBud((u8 *)&dp->wmap[word]), false); word += 1; } else { @@ -2229,7 +2229,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, * system of the leaves to reflect the current * allocation (size). */ - dbSplit(tp, word, size, NOFREE); + dbSplit(tp, word, size, NOFREE, false); /* get the number of dmap words handled */ nw = BUDSIZE(size, BUDMIN); @@ -2336,7 +2336,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, /* update the leaf for this dmap word. */ rc = dbJoin(tp, word, - dbMaxBud((u8 *) & dp->wmap[word])); + dbMaxBud((u8 *)&dp->wmap[word]), false); if (rc) return rc; @@ -2369,7 +2369,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, /* update the leaf. */ - rc = dbJoin(tp, word, size); + rc = dbJoin(tp, word, size, false); if (rc) return rc; @@ -2521,16 +2521,16 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) * that it is at the front of a binary buddy system. */ if (oldval == NOFREE) { - rc = dbBackSplit((dmtree_t *) dcp, leafno); + rc = dbBackSplit((dmtree_t *)dcp, leafno, true); if (rc) { release_metapage(mp); return rc; } oldval = dcp->stree[ti]; } - dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval); + dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval, true); } else { - rc = dbJoin((dmtree_t *) dcp, leafno, newval); + rc = dbJoin((dmtree_t *) dcp, leafno, newval, true); if (rc) { release_metapage(mp); return rc; @@ -2561,7 +2561,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) */ if (alloc) { dbJoin((dmtree_t *) dcp, leafno, - oldval); + oldval, true); } else { /* the dbJoin() above might have * caused a larger binary buddy system @@ -2571,9 +2571,9 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) */ if (dcp->stree[ti] == NOFREE) dbBackSplit((dmtree_t *) - dcp, leafno); + dcp, leafno, true); dbSplit((dmtree_t *) dcp, leafno, - dcp->budmin, oldval); + dcp->budmin, oldval, true); } /* release the buffer and return the error. @@ -2621,7 +2621,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ -static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) +static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl) { int budsz; int cursz; @@ -2643,7 +2643,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) while (cursz >= splitsz) { /* update the buddy's leaf with its new value. */ - dbAdjTree(tp, leafno ^ budsz, cursz); + dbAdjTree(tp, leafno ^ budsz, cursz, is_ctl); /* on to the next size and buddy. */ @@ -2655,7 +2655,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) /* adjust the dmap tree to reflect the specified leaf's new * value. */ - dbAdjTree(tp, leafno, newval); + dbAdjTree(tp, leafno, newval, is_ctl); } @@ -2686,7 +2686,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ -static int dbBackSplit(dmtree_t * tp, int leafno) +static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl) { int budsz, bud, w, bsz, size; int cursz; @@ -2737,7 +2737,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno) * system in two. */ cursz = leaf[bud] - 1; - dbSplit(tp, bud, cursz, cursz); + dbSplit(tp, bud, cursz, cursz, is_ctl); break; } } @@ -2765,7 +2765,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno) * * RETURN VALUES: none */ -static int dbJoin(dmtree_t * tp, int leafno, int newval) +static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl) { int budsz, buddy; s8 *leaf; @@ -2820,12 +2820,12 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) if (leafno < buddy) { /* leafno is the left buddy. */ - dbAdjTree(tp, buddy, NOFREE); + dbAdjTree(tp, buddy, NOFREE, is_ctl); } else { /* buddy is the left buddy and becomes * leafno. */ - dbAdjTree(tp, leafno, NOFREE); + dbAdjTree(tp, leafno, NOFREE, is_ctl); leafno = buddy; } @@ -2838,7 +2838,7 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) /* update the leaf value. */ - dbAdjTree(tp, leafno, newval); + dbAdjTree(tp, leafno, newval, is_ctl); return 0; } @@ -2859,21 +2859,23 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) * * RETURN VALUES: none */ -static void dbAdjTree(dmtree_t * tp, int leafno, int newval) +static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl) { int lp, pp, k; - int max; + int max, size; + + size = is_ctl ? CTLTREESIZE : TREESIZE; /* pick up the index of the leaf for this leafno. */ lp = leafno + le32_to_cpu(tp->dmt_leafidx); + if (WARN_ON_ONCE(lp >= size || lp < 0)) + return; + /* is the current value the same as the old value ? if so, * there is nothing to do. */ - if (WARN_ON_ONCE(lp >= CTLTREESIZE)) - return; - if (tp->dmt_stree[lp] == newval) return; From e0e1958f4c365e380b17ccb35617345b31ef7bf3 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 31 Oct 2023 13:39:04 +0800 Subject: [PATCH 1076/7721] jfs: fix uaf in jfs_evict_inode When the execution of diMount(ipimap) fails, the object ipimap that has been released may be accessed in diFreeSpecial(). Asynchronous ipimap release occurs when rcu_core() calls jfs_free_node(). Therefore, when diMount(ipimap) fails, sbi->ipimap should not be initialized as ipimap. Reported-and-tested-by: syzbot+01cf2dbcbe2022454388@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_mount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c index 415eb65a36ff..9b5c6a20b30c 100644 --- a/fs/jfs/jfs_mount.c +++ b/fs/jfs/jfs_mount.c @@ -172,15 +172,15 @@ int jfs_mount(struct super_block *sb) } jfs_info("jfs_mount: ipimap:0x%p", ipimap); - /* map further access of per fileset inodes by the fileset inode */ - sbi->ipimap = ipimap; - /* initialize fileset inode allocation map */ if ((rc = diMount(ipimap))) { jfs_err("jfs_mount: diMount failed w/rc = %d", rc); goto err_ipimap; } + /* map further access of per fileset inodes by the fileset inode */ + sbi->ipimap = ipimap; + return rc; /* From cca974daeb6c43ea971f8ceff5a7080d7d49ee30 Mon Sep 17 00:00:00 2001 From: Manas Ghandat Date: Wed, 11 Oct 2023 20:09:37 +0530 Subject: [PATCH 1077/7721] jfs: fix shift-out-of-bounds in dbJoin Currently while joining the leaf in a buddy system there is shift out of bound error in calculation of BUDSIZE. Added the required check to the BUDSIZE and fixed the documentation as well. Reported-by: syzbot+411debe54d318eaed386@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=411debe54d318eaed386 Signed-off-by: Manas Ghandat Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dmap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index cb3cda1390ad..8eec84c651bf 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -2763,7 +2763,9 @@ static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl) * leafno - the number of the leaf to be updated. * newval - the new value for the leaf. * - * RETURN VALUES: none + * RETURN VALUES: + * 0 - success + * -EIO - i/o error */ static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl) { @@ -2790,6 +2792,10 @@ static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl) * get the buddy size (number of words covered) of * the new value. */ + + if ((newval - tp->dmt_budmin) > BUDMIN) + return -EIO; + budsz = BUDSIZE(newval, tp->dmt_budmin); /* try to join. From d2689b6a86b9d23574bd4b654bf770b6034e2c7e Mon Sep 17 00:00:00 2001 From: Jose Ignacio Tornos Martinez Date: Mon, 20 Nov 2023 13:11:41 +0100 Subject: [PATCH 1078/7721] net: usb: ax88179_178a: avoid two consecutive device resets The device is always reset two consecutive times (ax88179_reset is called twice), one from usbnet_probe during the device binding and the other from usbnet_open. Remove the non-necessary reset during the device binding and let the reset operation from open to keep the normal behavior (tested with generic ASIX Electronics Corp. AX88179 Gigabit Ethernet device). Reported-by: Herb Wei Tested-by: Herb Wei Signed-off-by: Jose Ignacio Tornos Martinez Link: https://lore.kernel.org/r/20231120121239.54504-1-jtornosm@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/ax88179_178a.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index aff39bf3161d..fb0903ad6de3 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1298,8 +1298,6 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) netif_set_tso_max_size(dev->net, 16384); - ax88179_reset(dev); - return 0; } From dd891b5b106fa7346d75b3ee3448fa0071422f3d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 20 Nov 2023 10:41:40 -0800 Subject: [PATCH 1079/7721] net: do not send a MOVE event when netdev changes netns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Networking supports changing netdevice's netns and name at the same time. This allows avoiding name conflicts and having to rename the interface in multiple steps. E.g. netns1={eth0, eth1}, netns2={eth1} - we want to move netns1:eth1 to netns2 and call it eth0 there. If we can't rename "in flight" we'd need to (1) rename eth1 -> $tmp, (2) change netns, (3) rename $tmp -> eth0. To rename the underlying struct device we have to call device_rename(). The rename()'s MOVE event, however, doesn't "belong" to either the old or the new namespace. If there are conflicts on both sides it's actually impossible to issue a real MOVE (old name -> new name) without confusing user space. And Daniel reports that such confusions do in fact happen for systemd, in real life. Since we already issue explicit REMOVE and ADD events manually - suppress the MOVE event completely. Move the ADD after the rename, so that the REMOVE uses the old name, and the ADD the new one. If there is no rename this changes the picture as follows: Before: old ns | KERNEL[213.399289] remove /devices/virtual/net/eth0 (net) new ns | KERNEL[213.401302] add /devices/virtual/net/eth0 (net) new ns | KERNEL[213.401397] move /devices/virtual/net/eth0 (net) After: old ns | KERNEL[266.774257] remove /devices/virtual/net/eth0 (net) new ns | KERNEL[266.774509] add /devices/virtual/net/eth0 (net) If there is a rename and a conflict (using the exact eth0/eth1 example explained above) we get this: Before: old ns | KERNEL[224.316833] remove /devices/virtual/net/eth1 (net) new ns | KERNEL[224.318551] add /devices/virtual/net/eth1 (net) new ns | KERNEL[224.319662] move /devices/virtual/net/eth0 (net) After: old ns | KERNEL[333.033166] remove /devices/virtual/net/eth1 (net) new ns | KERNEL[333.035098] add /devices/virtual/net/eth0 (net) Note that "in flight" rename is only performed when needed. If there is no conflict for old name in the target netns - the rename will be performed separately by dev_change_name(), as if the rename was a different command, and there will still be a MOVE event for the rename: Before: old ns | KERNEL[194.416429] remove /devices/virtual/net/eth0 (net) new ns | KERNEL[194.418809] add /devices/virtual/net/eth0 (net) new ns | KERNEL[194.418869] move /devices/virtual/net/eth0 (net) new ns | KERNEL[194.420866] move /devices/virtual/net/eth1 (net) After: old ns | KERNEL[71.917520] remove /devices/virtual/net/eth0 (net) new ns | KERNEL[71.919155] add /devices/virtual/net/eth0 (net) new ns | KERNEL[71.920729] move /devices/virtual/net/eth1 (net) If deleting the MOVE event breaks some user space we should insert an explicit kobject_uevent(MOVE) after the ADD, like this: @@ -11192,6 +11192,12 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net, kobject_uevent(&dev->dev.kobj, KOBJ_ADD); netdev_adjacent_add_links(dev); + /* User space wants an explicit MOVE event, issue one unless + * dev_change_name() will get called later and issue one. + */ + if (!pat || new_name[0]) + kobject_uevent(&dev->dev.kobj, KOBJ_MOVE); + /* Adapt owner in case owning user namespace of target network * namespace is different from the original one. */ Reported-by: Daniel Gröber Link: https://lore.kernel.org/all/20231010121003.x3yi6fihecewjy4e@House.clients.dxld.at/ Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/all/20231120184140.578375-1-kuba@kernel.org/ Signed-off-by: Jakub Kicinski --- net/core/dev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index af53f6d838ce..0bdc6bf758f3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11181,17 +11181,19 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net, dev_net_set(dev, net); dev->ifindex = new_ifindex; - /* Send a netdev-add uevent to the new namespace */ - kobject_uevent(&dev->dev.kobj, KOBJ_ADD); - netdev_adjacent_add_links(dev); - if (new_name[0]) /* Rename the netdev to prepared name */ strscpy(dev->name, new_name, IFNAMSIZ); /* Fixup kobjects */ + dev_set_uevent_suppress(&dev->dev, 1); err = device_rename(&dev->dev, dev->name); + dev_set_uevent_suppress(&dev->dev, 0); WARN_ON(err); + /* Send a netdev-add uevent to the new namespace */ + kobject_uevent(&dev->dev.kobj, KOBJ_ADD); + netdev_adjacent_add_links(dev); + /* Adapt owner in case owning user namespace of target network * namespace is different from the original one. */ From 8405d6626289160fcd21b0f0c827144556be52be Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:18 +0100 Subject: [PATCH 1080/7721] mlxsw: cmd: Add cmd_mbox.query_fw.cff_support PGT, a port-group table is an in-HW block of specialized memory that holds sets of ports. Allocated within the PGT are series of flood tables that describe to which ports traffic of various types (unknown UC, BC, MC) should be flooded from which FID. The hitherto-used layout of these flood tables is being replaced with a more flexible scheme, called compressed FID flooding (CFF). CFF can be configured through CONFIG_PROFILE.flood_mode. cff_support determines whether CONFIG_PROFILE.flood_mode can be set to CFF. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/af727d0e1095e30fa45c7e60404637cdc491aeec.1700503643.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/cmd.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h index e827c78be114..b45c9a04fcc4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h +++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h @@ -282,6 +282,12 @@ MLXSW_ITEM32(cmd_mbox, query_fw, fw_day, 0x14, 0, 8); */ MLXSW_ITEM32(cmd_mbox, query_fw, lag_mode_support, 0x18, 1, 1); +/* cmd_mbox_query_fw_cff_support + * 0: CONFIG_PROFILE.flood_mode = 5 (CFF) is not supported by FW + * 1: CONFIG_PROFILE.flood_mode = 5 (CFF) is supported by FW + */ +MLXSW_ITEM32(cmd_mbox, query_fw, cff_support, 0x18, 2, 1); + /* cmd_mbox_query_fw_clr_int_base_offset * Clear Interrupt register's offset from clr_int_bar register * in PCI address space. From 50ee67789b823ffb052f3be20349c05c30bee2e6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:19 +0100 Subject: [PATCH 1081/7721] mlxsw: cmd: Add MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF PGT, a port-group table is an in-HW block of specialized memory that holds sets of ports. Allocated within the PGT are series of flood tables that describe to which ports traffic of various types (unknown UC, BC, MC) should be flooded from which FID. The hitherto-used layout of these flood tables is being replaced with a more flexible scheme, called compressed FID flooding (CFF). CFF can be configured through CONFIG_PROFILE.flood_mode. In this patch, add MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF, the value to use to enable the CFF mode. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/fc2e063742856492f8f22b0b87abf431ea6d53d0.1700503643.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/cmd.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h index b45c9a04fcc4..e3271c845ee6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h +++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h @@ -785,6 +785,11 @@ enum mlxsw_cmd_mbox_config_profile_flood_mode { * used. */ MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED = 4, + /* CFF - Compressed FID Flood (CFF) mode. + * Reserved when legacy bridge model is used. + * Supported only by Spectrum-2+. + */ + MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF = 5, }; /* cmd_mbox_config_profile_flood_mode From 2d19da9277199ec69b555ca32042be2a7cd493c6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:20 +0100 Subject: [PATCH 1082/7721] mlxsw: resources: Add max_cap_nve_flood_prf max_cap_nve_flood_prf describes maximum number of NVE flooding profiles. The same value then applies for flooding profiles for flooding in CFF mode. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/064a2e013d879e5f5494167a6c120c4bb85a2204.1700503643.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/resources.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 89dd2777ec4d..9d7977ebe186 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -27,6 +27,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_FID, MLXSW_RES_ID_MAX_LAG, MLXSW_RES_ID_MAX_LAG_MEMBERS, + MLXSW_RES_ID_MAX_NVE_FLOOD_PRF, MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, MLXSW_RES_ID_CELL_SIZE, MLXSW_RES_ID_MAX_HEADROOM_SIZE, @@ -88,6 +89,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_FID] = 0x2512, [MLXSW_RES_ID_MAX_LAG] = 0x2520, [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, + [MLXSW_RES_ID_MAX_NVE_FLOOD_PRF] = 0x2522, [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ [MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */ From e1e4ce6c6d54ff206e55bd8c89c00bfee891458c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:21 +0100 Subject: [PATCH 1083/7721] mlxsw: reg: Add Switch FID Flooding Profiles Register The SFFP register populates the fid flooding profile tables used for the NVE flooding and Compressed-FID Flooding (CFF). Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/ca42eb67763bd0c7cf035afc62ef73632f3f61a6.1700503643.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index e26e9d06bd72..3472f70b2482 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -2168,6 +2168,50 @@ static inline void mlxsw_reg_spvc_pack(char *payload, u16 local_port, bool et1, mlxsw_reg_spvc_et0_set(payload, et0); } +/* SFFP - Switch FID Flooding Profiles Register + * -------------------------------------------- + * The SFFP register populates the fid flooding profile tables used for the NVE + * flooding and Compressed-FID Flooding (CFF). + * + * Reserved on Spectrum-1. + */ +#define MLXSW_REG_SFFP_ID 0x2029 +#define MLXSW_REG_SFFP_LEN 0x0C + +MLXSW_REG_DEFINE(sffp, MLXSW_REG_SFFP_ID, MLXSW_REG_SFFP_LEN); + +/* reg_sffp_profile_id + * Profile ID a.k.a. SFMR.nve_flood_prf_id or SFMR.cff_prf_id + * Range 0..max_cap_nve_flood_prf-1 + * Access: Index + */ +MLXSW_ITEM32(reg, sffp, profile_id, 0x00, 16, 2); + +/* reg_sffp_type + * The traffic type to reach the flooding table. + * Same as SFGC.type + * Access: Index + */ +MLXSW_ITEM32(reg, sffp, type, 0x00, 0, 4); + +/* reg_sffp_flood_offset + * Flood offset. Offset to add to SFMR.cff_mid_base to get the final PGT address + * for FID flood; or offset to add to SFMR.nve_tunnel_flood_ptr to get KVD + * pointer for NVE underlay. + * Access: RW + */ +MLXSW_ITEM32(reg, sffp, flood_offset, 0x04, 0, 3); + +static inline void mlxsw_reg_sffp_pack(char *payload, u8 profile_id, + enum mlxsw_reg_sfgc_type type, + u8 flood_offset) +{ + MLXSW_REG_ZERO(sffp, payload); + mlxsw_reg_sffp_profile_id_set(payload, profile_id); + mlxsw_reg_sffp_type_set(payload, type); + mlxsw_reg_sffp_flood_offset_set(payload, flood_offset); +} + /* SPEVET - Switch Port Egress VLAN EtherType * ------------------------------------------ * The switch port egress VLAN EtherType configures which EtherType to push at @@ -12946,6 +12990,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(spvmlr), MLXSW_REG(spfsr), MLXSW_REG(spvc), + MLXSW_REG(sffp), MLXSW_REG(spevet), MLXSW_REG(smpe), MLXSW_REG(smid2), From 7eb902954b624ee338303ad735235429e036b31b Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:22 +0100 Subject: [PATCH 1084/7721] mlxsw: reg: Mark SFGC & some SFMR fields as reserved in CFF mode Some existing fields and the whole register of SFGC are reserved in CFF mode. Backport the reservation note to these fields. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/e1d5977a8cb778227e4ea2fd1515529957ce5de7.1700503643.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 3472f70b2482..ec0adddd4598 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1024,6 +1024,8 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u16 local_port, * ------------------------------------------ * The following register controls the association of flooding tables and MIDs * to packet types used for flooding. + * + * Reserved when CONFIG_PROFILE.flood_mode = CFF. */ #define MLXSW_REG_SFGC_ID 0x2011 #define MLXSW_REG_SFGC_LEN 0x14 @@ -1862,6 +1864,7 @@ MLXSW_ITEM32(reg, sfmr, fid, 0x00, 0, 16); * Access: RW * * Note: Reserved when legacy bridge model is used. + * Reserved when CONFIG_PROFILE.flood_mode = CFF. */ MLXSW_ITEM32(reg, sfmr, flood_rsp, 0x08, 31, 1); @@ -1872,6 +1875,7 @@ MLXSW_ITEM32(reg, sfmr, flood_rsp, 0x08, 31, 1); * Access: RW * * Note: Reserved when legacy bridge model is used and when flood_rsp=1. + * Reserved when CONFIG_PROFILE.flood_mode = CFF */ MLXSW_ITEM32(reg, sfmr, flood_bridge_type, 0x08, 28, 1); @@ -1880,6 +1884,8 @@ MLXSW_ITEM32(reg, sfmr, flood_bridge_type, 0x08, 28, 1); * Used to point into the flooding table selected by SFGC register if * the table is of type FID-Offset. Otherwise, this field is reserved. * Access: RW + * + * Note: Reserved when CONFIG_PROFILE.flood_mode = CFF */ MLXSW_ITEM32(reg, sfmr, fid_offset, 0x08, 0, 16); From 642d6a2033d85797e0f8807d0e48bb007d5e73ca Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:23 +0100 Subject: [PATCH 1085/7721] mlxsw: reg: Drop unnecessary writes from mlxsw_reg_sfmr_pack() The MLXSW_REG_ZERO at the beginning of the function wipes the whole payload. There's no need to set vtfp and vv to false explicitly. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/04a51ea7cf31eea0ef7707311d8e864e2d9ef307.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index ec0adddd4598..e8f7a4741bd3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1973,8 +1973,6 @@ static inline void mlxsw_reg_sfmr_pack(char *payload, mlxsw_reg_sfmr_op_set(payload, op); mlxsw_reg_sfmr_fid_set(payload, fid); mlxsw_reg_sfmr_fid_offset_set(payload, fid_offset); - mlxsw_reg_sfmr_vtfp_set(payload, false); - mlxsw_reg_sfmr_vv_set(payload, false); mlxsw_reg_sfmr_flood_rsp_set(payload, flood_rsp); mlxsw_reg_sfmr_flood_bridge_type_set(payload, bridge_type); mlxsw_reg_sfmr_smpe_valid_set(payload, smpe_valid); From 446bc1e9dec63b419751b8bdecba06fee631672e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:24 +0100 Subject: [PATCH 1086/7721] mlxsw: reg: Extract flood-mode specific part of mlxsw_reg_sfmr_pack() In CFF mode, it is necessary to set a different set of SFMR fields. Leave in mlxsw_reg_sfmr_pack() only the common bits, and move the parts relevant to controlled flood mode directly to the call site. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/6f29639ebc3ca0722272e6c644ca910096469413.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 5 ----- .../net/ethernet/mellanox/mlxsw/spectrum_fid.c | 15 ++++++++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index e8f7a4741bd3..bd709f7fcae1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1965,16 +1965,11 @@ MLXSW_ITEM32(reg, sfmr, smpe, 0x28, 0, 16); static inline void mlxsw_reg_sfmr_pack(char *payload, enum mlxsw_reg_sfmr_op op, u16 fid, - u16 fid_offset, bool flood_rsp, - enum mlxsw_reg_bridge_type bridge_type, bool smpe_valid, u16 smpe) { MLXSW_REG_ZERO(sfmr, payload); mlxsw_reg_sfmr_op_set(payload, op); mlxsw_reg_sfmr_fid_set(payload, fid); - mlxsw_reg_sfmr_fid_offset_set(payload, fid_offset); - mlxsw_reg_sfmr_flood_rsp_set(payload, flood_rsp); - mlxsw_reg_sfmr_flood_bridge_type_set(payload, bridge_type); mlxsw_reg_sfmr_smpe_valid_set(payload, smpe_valid); mlxsw_reg_sfmr_smpe_set(payload, smpe); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index e954b8cd2ee8..6a509913bdc7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -433,9 +433,12 @@ static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index, - fid->fid_offset, fid->fid_family->flood_rsp, - fid->fid_family->bridge_type, fid->fid_family->smpe_index_valid, smpe); + mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset); + mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp); + mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl, + fid->fid_family->bridge_type); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } @@ -449,10 +452,12 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid, smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, - fid->fid_index, fid->fid_offset, - fid->fid_family->flood_rsp, - fid->fid_family->bridge_type, + fid->fid_index, fid->fid_family->smpe_index_valid, smpe); + mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset); + mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp); + mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl, + fid->fid_family->bridge_type); mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid); mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni)); mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid); From 6b10371c386c381651e2ea42ae11be6c35004b55 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:25 +0100 Subject: [PATCH 1087/7721] mlxsw: reg: Add to SFMR register the fields related to CFF flood mode Add the field cff_mid_base, which specifies at which point in PGT the per-FID flood table is stored. Add cff_prf_id, the profile ID, which determines on which row of the flood table a flood vector can be found for a given traffic type. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/3ad7ae38cf6534bedcd876f16090d109a814b3e3.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index bd709f7fcae1..3aae4467e431 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1944,6 +1944,26 @@ MLXSW_ITEM32(reg, sfmr, irif_v, 0x14, 24, 1); */ MLXSW_ITEM32(reg, sfmr, irif, 0x14, 0, 16); +/* reg_sfmr_cff_mid_base + * Pointer to PGT table. + * Range: 0..(cap_max_pgt-1) + * Access: RW + * + * Note: Reserved when SwitchX/-2 and Spectrum-1. + * Supported when CONFIG_PROFILE.flood_mode = CFF. + */ +MLXSW_ITEM32(reg, sfmr, cff_mid_base, 0x20, 0, 16); + +/* reg_sfmr_cff_prf_id + * Compressed Fid Flooding profile_id + * Range 0..(max_cap_nve_flood_prf-1) + * Access: RW + * + * Note: Reserved when SwitchX/-2 and Spectrum-1 + * Supported only when CONFIG_PROFLE.flood_mode = CFF. + */ +MLXSW_ITEM32(reg, sfmr, cff_prf_id, 0x24, 0, 2); + /* reg_sfmr_smpe_valid * SMPE is valid. * Access: RW From 09591595686750b68c6d40c5349e737d78f6da47 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:26 +0100 Subject: [PATCH 1088/7721] mlxsw: core, pci: Add plumbing related to CFF mode CFF mode, for Compressed FID Flooding, is a way of organizing flood vectors in the PGT table. The bus module determines whether CFF is supported, can configure flood mode to CFF if it is, and knows what flood mode has been configured. Therefore add a bus callback to determine the configured flood mode. Also add to core an API to query it. Since after this patch, we rely on mlxsw_pci->flood_mode being set, it becomes a coding error if a driver invokes this function with a set of fields that misses the initialization. Warn and bail out in that case. The CFF mode is not used as of this patch. The code to actually use it will be added later. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/889d58759dd40f5037f2206b9fc4a78a9240da80.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/core.c | 7 +++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 3 +++ drivers/net/ethernet/mellanox/mlxsw/pci.c | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index f23421f038f3..e4d7739bd7c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -211,6 +211,13 @@ mlxsw_core_lag_mode(struct mlxsw_core *mlxsw_core) } EXPORT_SYMBOL(mlxsw_core_lag_mode); +enum mlxsw_cmd_mbox_config_profile_flood_mode +mlxsw_core_flood_mode(struct mlxsw_core *mlxsw_core) +{ + return mlxsw_core->bus->flood_mode(mlxsw_core->bus_priv); +} +EXPORT_SYMBOL(mlxsw_core_flood_mode); + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) { return mlxsw_core->driver_priv; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 764d14bd5bc0..a93e9c38848a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -38,6 +38,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); int mlxsw_core_max_lag(struct mlxsw_core *mlxsw_core, u16 *p_max_lag); enum mlxsw_cmd_mbox_config_profile_lag_mode mlxsw_core_lag_mode(struct mlxsw_core *mlxsw_core); +enum mlxsw_cmd_mbox_config_profile_flood_mode +mlxsw_core_flood_mode(struct mlxsw_core *mlxsw_core); void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); @@ -489,6 +491,7 @@ struct mlxsw_bus { u32 (*read_utc_sec)(void *bus_priv); u32 (*read_utc_nsec)(void *bus_priv); enum mlxsw_cmd_mbox_config_profile_lag_mode (*lag_mode)(void *bus_priv); + enum mlxsw_cmd_mbox_config_profile_flood_mode (*flood_mode)(void *priv); u8 features; }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 5b1f2483a3cc..845edd43032b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -106,7 +106,9 @@ struct mlxsw_pci { u64 utc_sec_offset; u64 utc_nsec_offset; bool lag_mode_support; + bool cff_support; enum mlxsw_cmd_mbox_config_profile_lag_mode lag_mode; + enum mlxsw_cmd_mbox_config_profile_flood_mode flood_mode; struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT]; u32 doorbell_offset; struct mlxsw_core *core; @@ -1251,6 +1253,10 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, mbox, 1); mlxsw_cmd_mbox_config_profile_flood_mode_set( mbox, profile->flood_mode); + mlxsw_pci->flood_mode = profile->flood_mode; + } else { + WARN_ON(1); + return -EINVAL; } if (profile->used_max_ib_mc) { mlxsw_cmd_mbox_config_profile_set_max_ib_mc_set( @@ -1654,6 +1660,9 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, mlxsw_pci->lag_mode_support = mlxsw_cmd_mbox_query_fw_lag_mode_support_get(mbox); + mlxsw_pci->cff_support = + mlxsw_cmd_mbox_query_fw_cff_support_get(mbox); + num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox); err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages); if (err) @@ -1970,6 +1979,14 @@ mlxsw_pci_lag_mode(void *bus_priv) return mlxsw_pci->lag_mode; } +static enum mlxsw_cmd_mbox_config_profile_flood_mode +mlxsw_pci_flood_mode(void *bus_priv) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + + return mlxsw_pci->flood_mode; +} + static const struct mlxsw_bus mlxsw_pci_bus = { .kind = "pci", .init = mlxsw_pci_init, @@ -1982,6 +1999,7 @@ static const struct mlxsw_bus mlxsw_pci_bus = { .read_utc_sec = mlxsw_pci_read_utc_sec, .read_utc_nsec = mlxsw_pci_read_utc_nsec, .lag_mode = mlxsw_pci_lag_mode, + .flood_mode = mlxsw_pci_flood_mode, .features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET, }; From 9aad19a363f68470ac5af677cda7120393e94a06 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:27 +0100 Subject: [PATCH 1089/7721] mlxsw: pci: Permit enabling CFF mode There are FW versions out there that do not support CFF flood mode, and on Spectrum-1 in particular, there is no plan to support it at all. mlxsw will therefore have to support both controlled flood mode as well as CFF. There are also FW versions out there that claim to support CFF flood mode, but then reject or ignore configurations enabling the same. The driver thus has to have a say in whether an attempt to configure CFF flood mode should even be made, and what to use as a fallback. Hence express the feature in terms of "does the driver prefer CFF flood mode?", and "what flood mode the PCI module managed to configure the FW with". This gives to the driver a chance to determine whether CFF flood mode configuration should be attempted. The latter bit was added in previous patches. In this patch, add the bit that allows the driver to determine whether CFF enablement should be attempted, and the enablement code itself. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/41640a0ee58e0a9538f820f7b601a0e35f6449e4.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/core.h | 6 ++++++ drivers/net/ethernet/mellanox/mlxsw/pci.c | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index a93e9c38848a..6d11225594dd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -324,7 +324,12 @@ struct mlxsw_config_profile { u16 max_regions; u8 max_flood_tables; u8 max_vid_flood_tables; + + /* Flood mode to use if used_flood_mode. If flood_mode_prefer_cff, + * the backup flood mode (if any) when CFF unsupported. + */ u8 flood_mode; + u8 max_fid_offset_flood_tables; u16 fid_offset_flood_table_size; u8 max_fid_flood_tables; @@ -340,6 +345,7 @@ struct mlxsw_config_profile { u8 kvd_hash_double_parts; u8 cqe_time_stamp_type; bool lag_mode_prefer_sw; + bool flood_mode_prefer_cff; struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT]; }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 845edd43032b..0d58f13a7c7d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1248,7 +1248,14 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, mlxsw_cmd_mbox_config_profile_fid_flood_table_size_set( mbox, profile->fid_flood_table_size); } - if (profile->used_flood_mode) { + if (profile->flood_mode_prefer_cff && mlxsw_pci->cff_support) { + enum mlxsw_cmd_mbox_config_profile_flood_mode flood_mode = + MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF; + + mlxsw_cmd_mbox_config_profile_set_flood_mode_set(mbox, 1); + mlxsw_cmd_mbox_config_profile_flood_mode_set(mbox, flood_mode); + mlxsw_pci->flood_mode = flood_mode; + } else if (profile->used_flood_mode) { mlxsw_cmd_mbox_config_profile_set_flood_mode_set( mbox, 1); mlxsw_cmd_mbox_config_profile_flood_mode_set( From b51c876c2297f8b32ca579712e3ab1490114d1ee Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:28 +0100 Subject: [PATCH 1090/7721] mlxsw: spectrum_fid: Drop unnecessary conditions The caller already only calls mlxsw_sp_fid_flood_tables_init() and mlxsw_sp_fid_flood_tables_fini() if (fid_family->flood_tables). There is no configuration where the pointer is non-NULL, but the number of tables is zero. So drop the conditions. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/897c6841bc756ac632b797bf67ac83c6a66ba359.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 6a509913bdc7..d7fc579f3b29 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -1692,9 +1692,6 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) int err; int i; - if (!fid_family->nr_flood_tables) - return 0; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base, pgt_size); @@ -1723,9 +1720,6 @@ mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family) struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; u16 pgt_size; - if (!fid_family->nr_flood_tables) - return; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size); } From 2b7bccd1f167aa056206cc2551514b35c9fd30ab Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:29 +0100 Subject: [PATCH 1091/7721] mlxsw: spectrum_fid: Extract SFMR packing into a helper Both mlxsw_sp_fid_op() and mlxsw_sp_fid_edit_op() pack the core of SFMR the same way. Extract the common code into a helper and call that. Extract out of that a wrapper that just calls mlxsw_reg_sfmr_pack(), because it will be useful for the dummy family later on. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/31f32b4d767183f6cb197148d0792feab2efadba.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index d7fc579f3b29..aad4bb17dfb1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -424,21 +424,35 @@ static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) MLXSW_REG_SFMR_OP_DESTROY_FID; } -static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) +static void mlxsw_sp_fid_pack(char *sfmr_pl, + const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op) { - struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; - char sfmr_pl[MLXSW_REG_SFMR_LEN]; u16 smpe; smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; - mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index, + mlxsw_reg_sfmr_pack(sfmr_pl, op, fid->fid_index, fid->fid_family->smpe_index_valid, smpe); +} + +static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl, + const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op) +{ + mlxsw_sp_fid_pack(sfmr_pl, fid, op); mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset); mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp); mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl, fid->fid_family->bridge_type); +} +static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + char sfmr_pl[MLXSW_REG_SFMR_LEN]; + + mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, mlxsw_sp_sfmr_op(valid)); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } @@ -447,17 +461,8 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid, { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - u16 smpe; - smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; - - mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, - fid->fid_index, - fid->fid_family->smpe_index_valid, smpe); - mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset); - mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp); - mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl, - fid->fid_family->bridge_type); + mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, MLXSW_REG_SFMR_OP_CREATE_FID); mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid); mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni)); mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid); From 27851dfaa3d608ae13557a2684a0bd5e2aa5bff1 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:30 +0100 Subject: [PATCH 1092/7721] mlxsw: spectrum_router: Add a helper to get subport number from a RIF In the CFF flood mode, responsibility for management of the PGT entries for rFIDs is moved from FW to the driver. All rFIDs are based off either a front panel port, or a LAG port. The flood vectors for port-based rFIDs enable just the port itself, the ones for LAG-based rFIDs enable all member ports of the LAG in question. Since all rFIDs based off the same port have the same flood vector, and similarly for LAG-based rFIDs, the flood entries are shared. The PGT address of the flood vector is therefore determined based on the port (or LAG) number of the RIF connected with the rFID. Add a helper to determine subport number given a RIF, to be used in these calculations. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/d7ab43cf5b021f785f363f236e4b6780d10eea93.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++ .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index c70333b460ea..800c461deefa 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -753,6 +753,8 @@ union mlxsw_sp_l3addr { }; u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif); +int mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif *rif, + u16 *port, bool *is_lag); int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 82a95125d9ca..a358ceb4e1d0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8660,6 +8660,20 @@ mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif) return container_of(rif, struct mlxsw_sp_rif_subport, common); } +int mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif *rif, + u16 *port, bool *is_lag) +{ + struct mlxsw_sp_rif_subport *rif_subport; + + if (WARN_ON(rif->ops->type != MLXSW_SP_RIF_TYPE_SUBPORT)) + return -EINVAL; + + rif_subport = mlxsw_sp_rif_subport_rif(rif); + *is_lag = rif_subport->lag; + *port = *is_lag ? rif_subport->lag_id : rif_subport->system_port; + return 0; +} + static struct mlxsw_sp_rif * mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif_params *params, From f7ebb4023765e728a984c628fb6b929db2a3f76b Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 20 Nov 2023 19:25:31 +0100 Subject: [PATCH 1093/7721] mlxsw: spectrum_router: Call RIF setup before obtaining FID For subport RIFs, the setup initializes, among other things, RIF port and LAG numbers. Those are important to determine where in the PGT the RIF FID will be stored. Therefore, call the RIF setup before fid_get. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/f24d8cad7e4748b8e8e0e16894ca6a20704dea32.1700503644.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a358ceb4e1d0..2c255ed9b8a9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8419,6 +8419,9 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, rif->ops = ops; rif->rif_entries = rif_entries; + if (ops->setup) + ops->setup(rif, params); + if (ops->fid_get) { fid = ops->fid_get(rif, params, extack); if (IS_ERR(fid)) { @@ -8428,9 +8431,6 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, rif->fid = fid; } - if (ops->setup) - ops->setup(rif, params); - err = ops->configure(rif, extack); if (err) goto err_configure; From 5027ec19f1049a07df5b0a37b1f462514cf2724b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 20 Nov 2023 16:00:34 -0800 Subject: [PATCH 1094/7721] net: page_pool: split the page_pool_params into fast and slow struct page_pool is rather performance critical and we use 16B of the first cache line to store 2 pointers used only by test code. Future patches will add more informational (non-fast path) attributes. It's convenient for the user of the API to not have to worry which fields are fast and which are slow path. Use struct groups to split the params into the two categories internally. Acked-by: Jesper Dangaard Brouer Reviewed-by: Mina Almasry Reviewed-by: Ilias Apalodimas Link: https://lore.kernel.org/r/20231121000048.789613-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/net/page_pool/types.h | 31 +++++++++++++++++++------------ net/core/page_pool.c | 7 ++++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 6fc5134095ed..23950fcc4eca 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -54,18 +54,22 @@ struct pp_alloc_cache { * @offset: DMA sync address offset for PP_FLAG_DMA_SYNC_DEV */ struct page_pool_params { - unsigned int flags; - unsigned int order; - unsigned int pool_size; - int nid; - struct device *dev; - struct napi_struct *napi; - enum dma_data_direction dma_dir; - unsigned int max_len; - unsigned int offset; + struct_group_tagged(page_pool_params_fast, fast, + unsigned int flags; + unsigned int order; + unsigned int pool_size; + int nid; + struct device *dev; + struct napi_struct *napi; + enum dma_data_direction dma_dir; + unsigned int max_len; + unsigned int offset; + ); + struct_group_tagged(page_pool_params_slow, slow, /* private: used by test code only */ - void (*init_callback)(struct page *page, void *arg); - void *init_arg; + void (*init_callback)(struct page *page, void *arg); + void *init_arg; + ); }; #ifdef CONFIG_PAGE_POOL_STATS @@ -119,7 +123,7 @@ struct page_pool_stats { #endif struct page_pool { - struct page_pool_params p; + struct page_pool_params_fast p; long frag_users; struct page *frag_page; @@ -178,6 +182,9 @@ struct page_pool { refcount_t user_cnt; u64 destroy_cnt; + + /* Slow/Control-path information follows */ + struct page_pool_params_slow slow; }; struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); diff --git a/net/core/page_pool.c b/net/core/page_pool.c index dec544337236..ab22a2fdae57 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -173,7 +173,8 @@ static int page_pool_init(struct page_pool *pool, { unsigned int ring_qsize = 1024; /* Default */ - memcpy(&pool->p, params, sizeof(pool->p)); + memcpy(&pool->p, ¶ms->fast, sizeof(pool->p)); + memcpy(&pool->slow, ¶ms->slow, sizeof(pool->slow)); /* Validate only known flags were used */ if (pool->p.flags & ~(PP_FLAG_ALL)) @@ -388,8 +389,8 @@ static void page_pool_set_pp_info(struct page_pool *pool, * the overhead is negligible. */ page_pool_fragment_page(page, 1); - if (pool->p.init_callback) - pool->p.init_callback(page, pool->p.init_arg); + if (pool->slow.init_callback) + pool->slow.init_callback(page, pool->slow.init_arg); } static void page_pool_clear_pp_info(struct page *page) From 2da0cac1e9494f34c5a3438e5c4c7e662e1b7445 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 20 Nov 2023 16:00:35 -0800 Subject: [PATCH 1095/7721] net: page_pool: avoid touching slow on the fastpath To fully benefit from previous commit add one byte of state in the first cache line recording if we need to look at the slow part. The packing isn't all that impressive right now, we create a 7B hole. I'm expecting Olek's rework will reshuffle this, anyway. Acked-by: Jesper Dangaard Brouer Reviewed-by: Ilias Apalodimas Reviewed-by: Mina Almasry Link: https://lore.kernel.org/r/20231121000048.789613-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/net/page_pool/types.h | 2 ++ net/core/page_pool.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 23950fcc4eca..e1bb92c192de 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -125,6 +125,8 @@ struct page_pool_stats { struct page_pool { struct page_pool_params_fast p; + bool has_init_callback; + long frag_users; struct page *frag_page; unsigned int frag_offset; diff --git a/net/core/page_pool.c b/net/core/page_pool.c index ab22a2fdae57..df2a06d7da52 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -212,6 +212,8 @@ static int page_pool_init(struct page_pool *pool, */ } + pool->has_init_callback = !!pool->slow.init_callback; + #ifdef CONFIG_PAGE_POOL_STATS pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); if (!pool->recycle_stats) @@ -389,7 +391,7 @@ static void page_pool_set_pp_info(struct page_pool *pool, * the overhead is negligible. */ page_pool_fragment_page(page, 1); - if (pool->slow.init_callback) + if (pool->has_init_callback) pool->slow.init_callback(page, pool->slow.init_arg); } From aa8460bacf49e06d5024bb26c591b5fda91ca6c1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:53 -0800 Subject: [PATCH 1096/7721] bnxt_en: The caller of bnxt_alloc_ctx_mem() should always free bp->ctx bnxt_alloc_ctx_mem() calls bnxt_hwrm_func_backing_store_qcaps() to allocate the memory for bp->ctx. Initialize bp->ctx with the allocated memory and let the caller free it during unwind. The unwind logic is already there, we just need to always set bp->ctx to the allocated memory so the caller will always free it. This simplifies the logic and makes it easier to expand on the backing store logic. Reviewed-by: Pavan Chebbi Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e6ac1bd21bb3..6b19d5b8d95a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7233,6 +7233,8 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) rc = -ENOMEM; goto ctx_err; } + bp->ctx = ctx; + ctx->qp_max_entries = le32_to_cpu(resp->qp_max_entries); ctx->qp_min_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries); ctx->qp_max_l2_entries = le16_to_cpu(resp->qp_max_l2_entries); @@ -7276,13 +7278,11 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) tqm_rings = ctx->tqm_fp_rings_count + BNXT_MAX_TQM_SP_RINGS; ctx_pg = kcalloc(tqm_rings, sizeof(*ctx_pg), GFP_KERNEL); if (!ctx_pg) { - kfree(ctx); rc = -ENOMEM; goto ctx_err; } for (i = 0; i < tqm_rings; i++, ctx_pg++) ctx->tqm_mem[i] = ctx_pg; - bp->ctx = ctx; } else { rc = 0; } From e50dc4c2206e3eeed10c799db37bb51bc545f28a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:54 -0800 Subject: [PATCH 1097/7721] bnxt_en: Free bp->ctx inside bnxt_free_ctx_mem() We always free bp->ctx right after calling bnxt_free_ctx_mem(), so just free it at the end of that function to make things simpler. Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 ++------------ drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 -- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6b19d5b8d95a..8ff21768e592 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7552,6 +7552,8 @@ void bnxt_free_ctx_mem(struct bnxt *bp) bnxt_free_ctx_pg_tbls(bp, &ctx->srq_mem); bnxt_free_ctx_pg_tbls(bp, &ctx->qp_mem); ctx->flags &= ~BNXT_CTX_FLAG_INITED; + kfree(ctx); + bp->ctx = NULL; } static int bnxt_alloc_ctx_mem(struct bnxt *bp) @@ -10321,8 +10323,6 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up) if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) bnxt_ulp_stop(bp); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; bnxt_dcb_free(bp); rc = bnxt_fw_init_one(bp); if (rc) { @@ -11948,8 +11948,6 @@ static void bnxt_fw_reset_close(struct bnxt *bp) if (pci_is_enabled(bp->pdev)) pci_disable_device(bp->pdev); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; } static bool is_bnxt_fw_ok(struct bnxt *bp) @@ -13368,8 +13366,6 @@ static void bnxt_remove_one(struct pci_dev *pdev) bp->fw_health = NULL; bnxt_cleanup_pci(bp); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; kfree(bp->rss_indir_tbl); bp->rss_indir_tbl = NULL; bnxt_free_port_stats(bp); @@ -13969,8 +13965,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bp->fw_health = NULL; bnxt_cleanup_pci(bp); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; kfree(bp->rss_indir_tbl); bp->rss_indir_tbl = NULL; @@ -14023,8 +14017,6 @@ static int bnxt_suspend(struct device *device) bnxt_hwrm_func_drv_unrgtr(bp); pci_disable_device(bp->pdev); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; rtnl_unlock(); return rc; } @@ -14121,8 +14113,6 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev, if (pci_is_enabled(pdev)) pci_disable_device(pdev); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; rtnl_unlock(); /* Request a slot slot reset. */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index f302dac56599..10b842539b08 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -469,8 +469,6 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change, } bnxt_cancel_reservations(bp, false); bnxt_free_ctx_mem(bp); - kfree(bp->ctx); - bp->ctx = NULL; break; } case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: { From 76087d997a849618935c46a23fa16363be89da68 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:55 -0800 Subject: [PATCH 1098/7721] bnxt_en: Restructure context memory data structures The current code uses a flat bnxt_ctx_mem_info structure to store 8 types of context memory for the NIC. All the context memory types are very similar and have similar parameters. They can all share a common structure to improve the organization. Also, new firmware interface will provide a new API to retrieve each type of context memory by calling the API repeatedly. This patch reorganizes the bnxt_ctx_mem_info structure to fit better with the new firmware interface. It will also work with the legacy firmware interface. The flat fields in bnxt_ctx_mem_info are replaced by the bnxt_ctx_mem_type array. The bnxt_mem_init array info will no longer be needed. Reviewed-by: Somnath Kotur Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-4-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 327 ++++++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 101 ++++--- 2 files changed, 244 insertions(+), 184 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8ff21768e592..df25b559ee45 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3121,20 +3121,20 @@ static void bnxt_free_skbs(struct bnxt *bp) bnxt_free_rx_skbs(bp); } -static void bnxt_init_ctx_mem(struct bnxt_mem_init *mem_init, void *p, int len) +static void bnxt_init_ctx_mem(struct bnxt_ctx_mem_type *ctxm, void *p, int len) { - u8 init_val = mem_init->init_val; - u16 offset = mem_init->offset; + u8 init_val = ctxm->init_value; + u16 offset = ctxm->init_offset; u8 *p2 = p; int i; if (!init_val) return; - if (offset == BNXT_MEM_INVALID_OFFSET) { + if (offset == BNXT_CTX_INIT_INVALID_OFFSET) { memset(p, init_val, len); return; } - for (i = 0; i < len; i += mem_init->size) + for (i = 0; i < len; i += ctxm->entry_size) *(p2 + i + offset) = init_val; } @@ -3201,8 +3201,8 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) if (!rmem->pg_arr[i]) return -ENOMEM; - if (rmem->mem_init) - bnxt_init_ctx_mem(rmem->mem_init, rmem->pg_arr[i], + if (rmem->ctx_mem) + bnxt_init_ctx_mem(rmem->ctx_mem, rmem->pg_arr[i], rmem->page_size); if (rmem->nr_pages > 1 || rmem->depth > 0) { if (i == rmem->nr_pages - 2 && @@ -7175,37 +7175,16 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) return rc; } -static void bnxt_init_ctx_initializer(struct bnxt_ctx_mem_info *ctx, - struct hwrm_func_backing_store_qcaps_output *resp) +static void bnxt_init_ctx_initializer(struct bnxt_ctx_mem_type *ctxm, + u8 init_val, u8 init_offset, + bool init_mask_set) { - struct bnxt_mem_init *mem_init; - u16 init_mask; - u8 init_val; - u8 *offset; - int i; - - init_val = resp->ctx_kind_initializer; - init_mask = le16_to_cpu(resp->ctx_init_mask); - offset = &resp->qp_init_offset; - mem_init = &ctx->mem_init[BNXT_CTX_MEM_INIT_QP]; - for (i = 0; i < BNXT_CTX_MEM_INIT_MAX; i++, mem_init++, offset++) { - mem_init->init_val = init_val; - mem_init->offset = BNXT_MEM_INVALID_OFFSET; - if (!init_mask) - continue; - if (i == BNXT_CTX_MEM_INIT_STAT) - offset = &resp->stat_init_offset; - if (init_mask & (1 << i)) - mem_init->offset = *offset * 4; - else - mem_init->init_val = 0; - } - ctx->mem_init[BNXT_CTX_MEM_INIT_QP].size = ctx->qp_entry_size; - ctx->mem_init[BNXT_CTX_MEM_INIT_SRQ].size = ctx->srq_entry_size; - ctx->mem_init[BNXT_CTX_MEM_INIT_CQ].size = ctx->cq_entry_size; - ctx->mem_init[BNXT_CTX_MEM_INIT_VNIC].size = ctx->vnic_entry_size; - ctx->mem_init[BNXT_CTX_MEM_INIT_STAT].size = ctx->stat_entry_size; - ctx->mem_init[BNXT_CTX_MEM_INIT_MRAV].size = ctx->mrav_entry_size; + ctxm->init_value = init_val; + ctxm->init_offset = BNXT_CTX_INIT_INVALID_OFFSET; + if (init_mask_set) + ctxm->init_offset = init_offset * 4; + else + ctxm->init_value = 0; } static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) @@ -7225,8 +7204,11 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) rc = hwrm_req_send_silent(bp, req); if (!rc) { struct bnxt_ctx_pg_info *ctx_pg; + struct bnxt_ctx_mem_type *ctxm; struct bnxt_ctx_mem_info *ctx; + u8 init_val, init_idx = 0; int i, tqm_rings; + u16 init_mask; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { @@ -7235,39 +7217,69 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) } bp->ctx = ctx; - ctx->qp_max_entries = le32_to_cpu(resp->qp_max_entries); - ctx->qp_min_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries); - ctx->qp_max_l2_entries = le16_to_cpu(resp->qp_max_l2_entries); - ctx->qp_entry_size = le16_to_cpu(resp->qp_entry_size); - ctx->srq_max_l2_entries = le16_to_cpu(resp->srq_max_l2_entries); - ctx->srq_max_entries = le32_to_cpu(resp->srq_max_entries); - ctx->srq_entry_size = le16_to_cpu(resp->srq_entry_size); - ctx->cq_max_l2_entries = le16_to_cpu(resp->cq_max_l2_entries); - ctx->cq_max_entries = le32_to_cpu(resp->cq_max_entries); - ctx->cq_entry_size = le16_to_cpu(resp->cq_entry_size); - ctx->vnic_max_vnic_entries = - le16_to_cpu(resp->vnic_max_vnic_entries); - ctx->vnic_max_ring_table_entries = - le16_to_cpu(resp->vnic_max_ring_table_entries); - ctx->vnic_entry_size = le16_to_cpu(resp->vnic_entry_size); - ctx->stat_max_entries = le32_to_cpu(resp->stat_max_entries); - ctx->stat_entry_size = le16_to_cpu(resp->stat_entry_size); - ctx->tqm_entry_size = le16_to_cpu(resp->tqm_entry_size); - ctx->tqm_min_entries_per_ring = - le32_to_cpu(resp->tqm_min_entries_per_ring); - ctx->tqm_max_entries_per_ring = - le32_to_cpu(resp->tqm_max_entries_per_ring); - ctx->tqm_entries_multiple = resp->tqm_entries_multiple; - if (!ctx->tqm_entries_multiple) - ctx->tqm_entries_multiple = 1; - ctx->mrav_max_entries = le32_to_cpu(resp->mrav_max_entries); - ctx->mrav_entry_size = le16_to_cpu(resp->mrav_entry_size); - ctx->mrav_num_entries_units = - le16_to_cpu(resp->mrav_num_entries_units); - ctx->tim_entry_size = le16_to_cpu(resp->tim_entry_size); - ctx->tim_max_entries = le32_to_cpu(resp->tim_max_entries); + init_val = resp->ctx_kind_initializer; + init_mask = le16_to_cpu(resp->ctx_init_mask); - bnxt_init_ctx_initializer(ctx, resp); + ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; + ctxm->max_entries = le32_to_cpu(resp->qp_max_entries); + ctxm->qp_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries); + ctxm->qp_l2_entries = le16_to_cpu(resp->qp_max_l2_entries); + ctxm->entry_size = le16_to_cpu(resp->qp_entry_size); + bnxt_init_ctx_initializer(ctxm, init_val, resp->qp_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; + ctxm->srq_l2_entries = le16_to_cpu(resp->srq_max_l2_entries); + ctxm->max_entries = le32_to_cpu(resp->srq_max_entries); + ctxm->entry_size = le16_to_cpu(resp->srq_entry_size); + bnxt_init_ctx_initializer(ctxm, init_val, resp->srq_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; + ctxm->cq_l2_entries = le16_to_cpu(resp->cq_max_l2_entries); + ctxm->max_entries = le32_to_cpu(resp->cq_max_entries); + ctxm->entry_size = le16_to_cpu(resp->cq_entry_size); + bnxt_init_ctx_initializer(ctxm, init_val, resp->cq_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; + ctxm->vnic_entries = le16_to_cpu(resp->vnic_max_vnic_entries); + ctxm->max_entries = ctxm->vnic_entries + + le16_to_cpu(resp->vnic_max_ring_table_entries); + ctxm->entry_size = le16_to_cpu(resp->vnic_entry_size); + bnxt_init_ctx_initializer(ctxm, init_val, + resp->vnic_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; + ctxm->max_entries = le32_to_cpu(resp->stat_max_entries); + ctxm->entry_size = le16_to_cpu(resp->stat_entry_size); + bnxt_init_ctx_initializer(ctxm, init_val, + resp->stat_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_STQM]; + ctxm->entry_size = le16_to_cpu(resp->tqm_entry_size); + ctxm->min_entries = le32_to_cpu(resp->tqm_min_entries_per_ring); + ctxm->max_entries = le32_to_cpu(resp->tqm_max_entries_per_ring); + ctxm->entry_multiple = resp->tqm_entries_multiple; + if (!ctxm->entry_multiple) + ctxm->entry_multiple = 1; + + memcpy(&ctx->ctx_arr[BNXT_CTX_FTQM], ctxm, sizeof(*ctxm)); + + ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; + ctxm->max_entries = le32_to_cpu(resp->mrav_max_entries); + ctxm->entry_size = le16_to_cpu(resp->mrav_entry_size); + ctxm->mrav_num_entries_units = + le16_to_cpu(resp->mrav_num_entries_units); + bnxt_init_ctx_initializer(ctxm, init_val, + resp->mrav_init_offset, + (init_mask & (1 << init_idx++)) != 0); + + ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; + ctxm->entry_size = le16_to_cpu(resp->tim_entry_size); + ctxm->max_entries = le32_to_cpu(resp->tim_max_entries); ctx->tqm_fp_rings_count = resp->tqm_fp_rings_count; if (!ctx->tqm_fp_rings_count) @@ -7275,6 +7287,9 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) else if (ctx->tqm_fp_rings_count > BNXT_MAX_TQM_FP_RINGS) ctx->tqm_fp_rings_count = BNXT_MAX_TQM_FP_RINGS; + ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM]; + ctxm->instance_bmap = (1 << ctx->tqm_fp_rings_count) - 1; + tqm_rings = ctx->tqm_fp_rings_count + BNXT_MAX_TQM_SP_RINGS; ctx_pg = kcalloc(tqm_rings, sizeof(*ctx_pg), GFP_KERNEL); if (!ctx_pg) { @@ -7321,6 +7336,7 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) struct hwrm_func_backing_store_cfg_input *req; struct bnxt_ctx_mem_info *ctx = bp->ctx; struct bnxt_ctx_pg_info *ctx_pg; + struct bnxt_ctx_mem_type *ctxm; void **__req = (void **)&req; u32 req_len = sizeof(*req); __le32 *num_entries; @@ -7343,70 +7359,86 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) req->enables = cpu_to_le32(enables); if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP) { ctx_pg = &ctx->qp_mem; + ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; req->qp_num_entries = cpu_to_le32(ctx_pg->entries); - req->qp_num_qp1_entries = cpu_to_le16(ctx->qp_min_qp1_entries); - req->qp_num_l2_entries = cpu_to_le16(ctx->qp_max_l2_entries); - req->qp_entry_size = cpu_to_le16(ctx->qp_entry_size); + req->qp_num_qp1_entries = cpu_to_le16(ctxm->qp_qp1_entries); + req->qp_num_l2_entries = cpu_to_le16(ctxm->qp_l2_entries); + req->qp_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->qpc_pg_size_qpc_lvl, &req->qpc_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ) { ctx_pg = &ctx->srq_mem; + ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; req->srq_num_entries = cpu_to_le32(ctx_pg->entries); - req->srq_num_l2_entries = cpu_to_le16(ctx->srq_max_l2_entries); - req->srq_entry_size = cpu_to_le16(ctx->srq_entry_size); + req->srq_num_l2_entries = cpu_to_le16(ctxm->srq_l2_entries); + req->srq_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->srq_pg_size_srq_lvl, &req->srq_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ) { ctx_pg = &ctx->cq_mem; + ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; req->cq_num_entries = cpu_to_le32(ctx_pg->entries); - req->cq_num_l2_entries = cpu_to_le16(ctx->cq_max_l2_entries); - req->cq_entry_size = cpu_to_le16(ctx->cq_entry_size); + req->cq_num_l2_entries = cpu_to_le16(ctxm->cq_l2_entries); + req->cq_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->cq_pg_size_cq_lvl, &req->cq_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC) { ctx_pg = &ctx->vnic_mem; - req->vnic_num_vnic_entries = - cpu_to_le16(ctx->vnic_max_vnic_entries); + ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; + req->vnic_num_vnic_entries = cpu_to_le16(ctxm->vnic_entries); req->vnic_num_ring_table_entries = - cpu_to_le16(ctx->vnic_max_ring_table_entries); - req->vnic_entry_size = cpu_to_le16(ctx->vnic_entry_size); + cpu_to_le16(ctxm->max_entries - ctxm->vnic_entries); + req->vnic_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->vnic_pg_size_vnic_lvl, &req->vnic_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) { ctx_pg = &ctx->stat_mem; - req->stat_num_entries = cpu_to_le32(ctx->stat_max_entries); - req->stat_entry_size = cpu_to_le16(ctx->stat_entry_size); + ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; + req->stat_num_entries = cpu_to_le32(ctxm->max_entries); + req->stat_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->stat_pg_size_stat_lvl, &req->stat_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV) { + u32 units; + ctx_pg = &ctx->mrav_mem; + ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; req->mrav_num_entries = cpu_to_le32(ctx_pg->entries); - if (ctx->mrav_num_entries_units) - flags |= - FUNC_BACKING_STORE_CFG_REQ_FLAGS_MRAV_RESERVATION_SPLIT; - req->mrav_entry_size = cpu_to_le16(ctx->mrav_entry_size); + units = ctxm->mrav_num_entries_units; + if (units) { + u32 num_mr, num_ah = ctxm->mrav_av_entries; + u32 entries; + + num_mr = ctx_pg->entries - num_ah; + entries = ((num_mr / units) << 16) | (num_ah / units); + req->mrav_num_entries = cpu_to_le32(entries); + flags |= FUNC_BACKING_STORE_CFG_REQ_FLAGS_MRAV_RESERVATION_SPLIT; + } + req->mrav_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->mrav_pg_size_mrav_lvl, &req->mrav_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) { ctx_pg = &ctx->tim_mem; + ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; req->tim_num_entries = cpu_to_le32(ctx_pg->entries); - req->tim_entry_size = cpu_to_le16(ctx->tim_entry_size); + req->tim_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req->tim_pg_size_tim_lvl, &req->tim_page_dir); } + ctxm = &ctx->ctx_arr[BNXT_CTX_STQM]; for (i = 0, num_entries = &req->tqm_sp_num_entries, pg_attr = &req->tqm_sp_pg_size_tqm_sp_lvl, pg_dir = &req->tqm_sp_page_dir, @@ -7416,7 +7448,7 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) if (!(enables & ena)) continue; - req->tqm_entry_size = cpu_to_le16(ctx->tqm_entry_size); + req->tqm_entry_size = cpu_to_le16(ctxm->entry_size); ctx_pg = ctx->tqm_mem[i]; *num_entries = cpu_to_le32(ctx_pg->entries); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, pg_attr, pg_dir); @@ -7441,7 +7473,7 @@ static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp, static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size, - u8 depth, struct bnxt_mem_init *mem_init) + u8 depth, struct bnxt_ctx_mem_type *ctxm) { struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem; int rc; @@ -7479,7 +7511,7 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, rmem->pg_tbl_map = ctx_pg->ctx_dma_arr[i]; rmem->depth = 1; rmem->nr_pages = MAX_CTX_PAGES; - rmem->mem_init = mem_init; + rmem->ctx_mem = ctxm; if (i == (nr_tbls - 1)) { int rem = ctx_pg->nr_pages % MAX_CTX_PAGES; @@ -7494,7 +7526,7 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, rmem->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE); if (rmem->nr_pages > 1 || depth) rmem->depth = 1; - rmem->mem_init = mem_init; + rmem->ctx_mem = ctxm; rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg); } return rc; @@ -7559,10 +7591,12 @@ void bnxt_free_ctx_mem(struct bnxt *bp) static int bnxt_alloc_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_pg_info *ctx_pg; + struct bnxt_ctx_mem_type *ctxm; struct bnxt_ctx_mem_info *ctx; - struct bnxt_mem_init *init; + u32 l2_qps, qp1_qps, max_qps; u32 mem_size, ena, entries; u32 entries_sp, min; + u32 srqs, max_srqs; u32 num_mr, num_ah; u32 extra_srqs = 0; u32 extra_qps = 0; @@ -7579,60 +7613,65 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) if (!ctx || (ctx->flags & BNXT_CTX_FLAG_INITED)) return 0; + ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; + l2_qps = ctxm->qp_l2_entries; + qp1_qps = ctxm->qp_qp1_entries; + max_qps = ctxm->max_entries; + ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; + srqs = ctxm->srq_l2_entries; + max_srqs = ctxm->max_entries; if ((bp->flags & BNXT_FLAG_ROCE_CAP) && !is_kdump_kernel()) { pg_lvl = 2; - extra_qps = 65536; - extra_srqs = 8192; + extra_qps = min_t(u32, 65536, max_qps - l2_qps - qp1_qps); + extra_srqs = min_t(u32, 8192, max_srqs - srqs); } + ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; ctx_pg = &ctx->qp_mem; - ctx_pg->entries = ctx->qp_min_qp1_entries + ctx->qp_max_l2_entries + - extra_qps; - if (ctx->qp_entry_size) { - mem_size = ctx->qp_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_QP]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init); + ctx_pg->entries = l2_qps + qp1_qps + extra_qps; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); if (rc) return rc; } + ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; ctx_pg = &ctx->srq_mem; - ctx_pg->entries = ctx->srq_max_l2_entries + extra_srqs; - if (ctx->srq_entry_size) { - mem_size = ctx->srq_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_SRQ]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init); + ctx_pg->entries = srqs + extra_srqs; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); if (rc) return rc; } + ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; ctx_pg = &ctx->cq_mem; - ctx_pg->entries = ctx->cq_max_l2_entries + extra_qps * 2; - if (ctx->cq_entry_size) { - mem_size = ctx->cq_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_CQ]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init); + ctx_pg->entries = ctxm->cq_l2_entries + extra_qps * 2; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); if (rc) return rc; } + ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; ctx_pg = &ctx->vnic_mem; - ctx_pg->entries = ctx->vnic_max_vnic_entries + - ctx->vnic_max_ring_table_entries; - if (ctx->vnic_entry_size) { - mem_size = ctx->vnic_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_VNIC]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, init); + ctx_pg->entries = ctxm->max_entries; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, ctxm); if (rc) return rc; } + ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; ctx_pg = &ctx->stat_mem; - ctx_pg->entries = ctx->stat_max_entries; - if (ctx->stat_entry_size) { - mem_size = ctx->stat_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_STAT]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, init); + ctx_pg->entries = ctxm->max_entries; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, ctxm); if (rc) return rc; } @@ -7641,30 +7680,31 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) goto skip_rdma; + ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; ctx_pg = &ctx->mrav_mem; /* 128K extra is needed to accommodate static AH context * allocation by f/w. */ - num_mr = 1024 * 256; - num_ah = 1024 * 128; + num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256); + num_ah = min_t(u32, num_mr, 1024 * 128); + ctxm->split_entry_cnt = BNXT_CTX_MRAV_AV_SPLIT_ENTRY + 1; + if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah) + ctxm->mrav_av_entries = num_ah; + ctx_pg->entries = num_mr + num_ah; - if (ctx->mrav_entry_size) { - mem_size = ctx->mrav_entry_size * ctx_pg->entries; - init = &ctx->mem_init[BNXT_CTX_MEM_INIT_MRAV]; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2, init); + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2, ctxm); if (rc) return rc; } ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; - if (ctx->mrav_num_entries_units) - ctx_pg->entries = - ((num_mr / ctx->mrav_num_entries_units) << 16) | - (num_ah / ctx->mrav_num_entries_units); + ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; ctx_pg = &ctx->tim_mem; - ctx_pg->entries = ctx->qp_mem.entries; - if (ctx->tim_entry_size) { - mem_size = ctx->tim_entry_size * ctx_pg->entries; + ctx_pg->entries = l2_qps + qp1_qps + extra_qps; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, NULL); if (rc) return rc; @@ -7672,18 +7712,19 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM; skip_rdma: - min = ctx->tqm_min_entries_per_ring; - entries_sp = ctx->vnic_max_vnic_entries + ctx->qp_max_l2_entries + - 2 * (extra_qps + ctx->qp_min_qp1_entries) + min; - entries_sp = roundup(entries_sp, ctx->tqm_entries_multiple); - entries = ctx->qp_max_l2_entries + 2 * (extra_qps + ctx->qp_min_qp1_entries); - entries = roundup(entries, ctx->tqm_entries_multiple); - entries = clamp_t(u32, entries, min, ctx->tqm_max_entries_per_ring); + ctxm = &ctx->ctx_arr[BNXT_CTX_STQM]; + min = ctxm->min_entries; + entries_sp = ctx->ctx_arr[BNXT_CTX_VNIC].vnic_entries + l2_qps + + 2 * (extra_qps + qp1_qps) + min; + entries_sp = roundup(entries_sp, ctxm->entry_multiple); + entries = l2_qps + 2 * (extra_qps + qp1_qps); + entries = roundup(entries, ctxm->entry_multiple); + entries = clamp_t(u32, entries, min, ctxm->max_entries); for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) { ctx_pg = ctx->tqm_mem[i]; ctx_pg->entries = i ? entries : entries_sp; - if (ctx->tqm_entry_size) { - mem_size = ctx->tqm_entry_size * ctx_pg->entries; + if (ctxm->entry_size) { + mem_size = ctxm->entry_size * ctx_pg->entries; rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, NULL); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4ce993943924..757d2edb8c05 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -762,13 +762,6 @@ struct bnxt_sw_rx_agg_bd { dma_addr_t mapping; }; -struct bnxt_mem_init { - u8 init_val; - u16 offset; -#define BNXT_MEM_INVALID_OFFSET 0xffff - u16 size; -}; - struct bnxt_ring_mem_info { int nr_pages; int page_size; @@ -778,7 +771,7 @@ struct bnxt_ring_mem_info { #define BNXT_RMEM_USE_FULL_PAGE_FLAG 4 u16 depth; - struct bnxt_mem_init *mem_init; + struct bnxt_ctx_mem_type *ctx_mem; void **pg_arr; dma_addr_t *dma_arr; @@ -1551,35 +1544,70 @@ do { \ attr = FUNC_BACKING_STORE_CFG_REQ_QPC_PG_SIZE_PG_4K; \ } while (0) +struct bnxt_ctx_mem_type { + u16 type; + u16 entry_size; + u32 flags; + u32 instance_bmap; + u8 init_value; + u8 entry_multiple; + u16 init_offset; +#define BNXT_CTX_INIT_INVALID_OFFSET 0xffff + u32 max_entries; + u32 min_entries; + u8 last:1; + u8 split_entry_cnt; +#define BNXT_MAX_SPLIT_ENTRY 4 + union { + struct { + u32 qp_l2_entries; + u32 qp_qp1_entries; + u32 qp_fast_qpmd_entries; + }; + u32 srq_l2_entries; + u32 cq_l2_entries; + u32 vnic_entries; + struct { + u32 mrav_av_entries; + u32 mrav_num_entries_units; + }; + u32 split[BNXT_MAX_SPLIT_ENTRY]; + }; +}; + +#define BNXT_CTX_MRAV_AV_SPLIT_ENTRY 0 + +#define BNXT_CTX_QP FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QP +#define BNXT_CTX_SRQ FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ +#define BNXT_CTX_CQ FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ +#define BNXT_CTX_VNIC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_VNIC +#define BNXT_CTX_STAT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_STAT +#define BNXT_CTX_STQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SP_TQM_RING +#define BNXT_CTX_FTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING +#define BNXT_CTX_MRAV FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV +#define BNXT_CTX_TIM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM +#define BNXT_CTX_TKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC +#define BNXT_CTX_RKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC +#define BNXT_CTX_MTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING +#define BNXT_CTX_SQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW +#define BNXT_CTX_RQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW +#define BNXT_CTX_SRQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ_DB_SHADOW +#define BNXT_CTX_CQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ_DB_SHADOW +#define BNXT_CTX_QTKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_TKC +#define BNXT_CTX_QRKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_RKC +#define BNXT_CTX_TBLSC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TBL_SCOPE +#define BNXT_CTX_XPAR FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_XID_PARTITION + +#define BNXT_CTX_MAX (BNXT_CTX_TIM + 1) +#define BNXT_CTX_V2_MAX (BNXT_CTX_XPAR + 1) +#define BNXT_CTX_INV ((u16)-1) + struct bnxt_ctx_mem_info { - u32 qp_max_entries; - u16 qp_min_qp1_entries; - u16 qp_max_l2_entries; - u16 qp_entry_size; - u16 srq_max_l2_entries; - u32 srq_max_entries; - u16 srq_entry_size; - u16 cq_max_l2_entries; - u32 cq_max_entries; - u16 cq_entry_size; - u16 vnic_max_vnic_entries; - u16 vnic_max_ring_table_entries; - u16 vnic_entry_size; - u32 stat_max_entries; - u16 stat_entry_size; - u16 tqm_entry_size; - u32 tqm_min_entries_per_ring; - u32 tqm_max_entries_per_ring; - u32 mrav_max_entries; - u16 mrav_entry_size; - u16 tim_entry_size; - u32 tim_max_entries; - u16 mrav_num_entries_units; - u8 tqm_entries_multiple; u8 tqm_fp_rings_count; u32 flags; #define BNXT_CTX_FLAG_INITED 0x01 + struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_MAX]; struct bnxt_ctx_pg_info qp_mem; struct bnxt_ctx_pg_info srq_mem; @@ -1589,15 +1617,6 @@ struct bnxt_ctx_mem_info { struct bnxt_ctx_pg_info mrav_mem; struct bnxt_ctx_pg_info tim_mem; struct bnxt_ctx_pg_info *tqm_mem[BNXT_MAX_TQM_RINGS]; - -#define BNXT_CTX_MEM_INIT_QP 0 -#define BNXT_CTX_MEM_INIT_SRQ 1 -#define BNXT_CTX_MEM_INIT_CQ 2 -#define BNXT_CTX_MEM_INIT_VNIC 3 -#define BNXT_CTX_MEM_INIT_STAT 4 -#define BNXT_CTX_MEM_INIT_MRAV 5 -#define BNXT_CTX_MEM_INIT_MAX 6 - struct bnxt_mem_init mem_init[BNXT_CTX_MEM_INIT_MAX]; }; enum bnxt_health_severity { From 035c57615982897da32bdbf311cd025001468f90 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:56 -0800 Subject: [PATCH 1099/7721] bnxt_en: Add page info to struct bnxt_ctx_mem_type This will further improve the organization of the bnxt_ctx_mem_info structure by moving the standalone page info structures into the bnxt_ctx_mem_type array. Add the allocation and free logic first and the next patch will migrate to use the new infrastructure. Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-5-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 31 +++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 32 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index df25b559ee45..3b18bcee151a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7187,6 +7187,27 @@ static void bnxt_init_ctx_initializer(struct bnxt_ctx_mem_type *ctxm, ctxm->init_value = 0; } +static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max) +{ + struct bnxt_ctx_mem_info *ctx = bp->ctx; + u16 type; + + for (type = 0; type < ctx_max; type++) { + struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; + int n = 1; + + if (!ctxm->max_entries) + continue; + + if (ctxm->instance_bmap) + n = hweight32(ctxm->instance_bmap); + ctxm->pg_info = kcalloc(n, sizeof(*ctxm->pg_info), GFP_KERNEL); + if (!ctxm->pg_info) + return -ENOMEM; + } + return 0; +} + static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) { struct hwrm_func_backing_store_qcaps_output *resp; @@ -7298,6 +7319,7 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) } for (i = 0; i < tqm_rings; i++, ctx_pg++) ctx->tqm_mem[i] = ctx_pg; + rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_MAX); } else { rc = 0; } @@ -7564,6 +7586,7 @@ static void bnxt_free_ctx_pg_tbls(struct bnxt *bp, void bnxt_free_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_mem_info *ctx = bp->ctx; + u16 type; int i; if (!ctx) @@ -7583,6 +7606,14 @@ void bnxt_free_ctx_mem(struct bnxt *bp) bnxt_free_ctx_pg_tbls(bp, &ctx->cq_mem); bnxt_free_ctx_pg_tbls(bp, &ctx->srq_mem); bnxt_free_ctx_pg_tbls(bp, &ctx->qp_mem); + + for (type = 0; type < BNXT_CTX_MAX; type++) { + struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; + + kfree(ctxm->pg_info); + ctxm->pg_info = NULL; + } + ctx->flags &= ~BNXT_CTX_FLAG_INITED; kfree(ctx); bp->ctx = NULL; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 757d2edb8c05..7e67df57b8af 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1573,6 +1573,7 @@ struct bnxt_ctx_mem_type { }; u32 split[BNXT_MAX_SPLIT_ENTRY]; }; + struct bnxt_ctx_pg_info *pg_info; }; #define BNXT_CTX_MRAV_AV_SPLIT_ENTRY 0 From 2ad67aea11f256c7ad7bdc66c0521d7ff71dd8da Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:57 -0800 Subject: [PATCH 1100/7721] bnxt_en: Use the pg_info field in bnxt_ctx_mem_type struct Use the newly added pg_info field in bnxt_ctx_mem_type struct and remove the standalone page info structures in bnxt_ctx_mem_info. This now completes the reorganization of the context memory structures to work better with the new and more flexible firmware interface for newer chips. Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-6-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 74 +++++++++-------------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 9 --- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 3b18bcee151a..524023b8e959 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7224,11 +7224,9 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) resp = hwrm_req_hold(bp, req); rc = hwrm_req_send_silent(bp, req); if (!rc) { - struct bnxt_ctx_pg_info *ctx_pg; struct bnxt_ctx_mem_type *ctxm; struct bnxt_ctx_mem_info *ctx; u8 init_val, init_idx = 0; - int i, tqm_rings; u16 init_mask; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -7311,14 +7309,6 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM]; ctxm->instance_bmap = (1 << ctx->tqm_fp_rings_count) - 1; - tqm_rings = ctx->tqm_fp_rings_count + BNXT_MAX_TQM_SP_RINGS; - ctx_pg = kcalloc(tqm_rings, sizeof(*ctx_pg), GFP_KERNEL); - if (!ctx_pg) { - rc = -ENOMEM; - goto ctx_err; - } - for (i = 0; i < tqm_rings; i++, ctx_pg++) - ctx->tqm_mem[i] = ctx_pg; rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_MAX); } else { rc = 0; @@ -7380,8 +7370,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) req->enables = cpu_to_le32(enables); if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP) { - ctx_pg = &ctx->qp_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; + ctx_pg = ctxm->pg_info; req->qp_num_entries = cpu_to_le32(ctx_pg->entries); req->qp_num_qp1_entries = cpu_to_le16(ctxm->qp_qp1_entries); req->qp_num_l2_entries = cpu_to_le16(ctxm->qp_l2_entries); @@ -7391,8 +7381,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) &req->qpc_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ) { - ctx_pg = &ctx->srq_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; + ctx_pg = ctxm->pg_info; req->srq_num_entries = cpu_to_le32(ctx_pg->entries); req->srq_num_l2_entries = cpu_to_le16(ctxm->srq_l2_entries); req->srq_entry_size = cpu_to_le16(ctxm->entry_size); @@ -7401,8 +7391,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) &req->srq_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ) { - ctx_pg = &ctx->cq_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; + ctx_pg = ctxm->pg_info; req->cq_num_entries = cpu_to_le32(ctx_pg->entries); req->cq_num_l2_entries = cpu_to_le16(ctxm->cq_l2_entries); req->cq_entry_size = cpu_to_le16(ctxm->entry_size); @@ -7411,8 +7401,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) &req->cq_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC) { - ctx_pg = &ctx->vnic_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; + ctx_pg = ctxm->pg_info; req->vnic_num_vnic_entries = cpu_to_le16(ctxm->vnic_entries); req->vnic_num_ring_table_entries = cpu_to_le16(ctxm->max_entries - ctxm->vnic_entries); @@ -7422,8 +7412,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) &req->vnic_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) { - ctx_pg = &ctx->stat_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; + ctx_pg = ctxm->pg_info; req->stat_num_entries = cpu_to_le32(ctxm->max_entries); req->stat_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, @@ -7433,8 +7423,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV) { u32 units; - ctx_pg = &ctx->mrav_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; + ctx_pg = ctxm->pg_info; req->mrav_num_entries = cpu_to_le32(ctx_pg->entries); units = ctxm->mrav_num_entries_units; if (units) { @@ -7452,8 +7442,8 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) &req->mrav_page_dir); } if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) { - ctx_pg = &ctx->tim_mem; ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; + ctx_pg = ctxm->pg_info; req->tim_num_entries = cpu_to_le32(ctx_pg->entries); req->tim_entry_size = cpu_to_le16(ctxm->entry_size); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, @@ -7464,14 +7454,15 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) for (i = 0, num_entries = &req->tqm_sp_num_entries, pg_attr = &req->tqm_sp_pg_size_tqm_sp_lvl, pg_dir = &req->tqm_sp_page_dir, - ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP; + ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP, + ctx_pg = ctxm->pg_info; i < BNXT_MAX_TQM_RINGS; + ctx_pg = &ctx->ctx_arr[BNXT_CTX_FTQM].pg_info[i], i++, num_entries++, pg_attr++, pg_dir++, ena <<= 1) { if (!(enables & ena)) continue; req->tqm_entry_size = cpu_to_le16(ctxm->entry_size); - ctx_pg = ctx->tqm_mem[i]; *num_entries = cpu_to_le32(ctx_pg->entries); bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, pg_attr, pg_dir); } @@ -7587,30 +7578,23 @@ void bnxt_free_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_mem_info *ctx = bp->ctx; u16 type; - int i; if (!ctx) return; - if (ctx->tqm_mem[0]) { - for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) - bnxt_free_ctx_pg_tbls(bp, ctx->tqm_mem[i]); - kfree(ctx->tqm_mem[0]); - ctx->tqm_mem[0] = NULL; - } - - bnxt_free_ctx_pg_tbls(bp, &ctx->tim_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->mrav_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->stat_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->vnic_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->cq_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->srq_mem); - bnxt_free_ctx_pg_tbls(bp, &ctx->qp_mem); - for (type = 0; type < BNXT_CTX_MAX; type++) { struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; + struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; + int i, n = 1; - kfree(ctxm->pg_info); + if (!ctx_pg) + continue; + if (ctxm->instance_bmap) + n = hweight32(ctxm->instance_bmap); + for (i = 0; i < n; i++) + bnxt_free_ctx_pg_tbls(bp, &ctx_pg[i]); + + kfree(ctx_pg); ctxm->pg_info = NULL; } @@ -7658,7 +7642,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; - ctx_pg = &ctx->qp_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = l2_qps + qp1_qps + extra_qps; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7668,7 +7652,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; - ctx_pg = &ctx->srq_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = srqs + extra_srqs; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7678,7 +7662,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; - ctx_pg = &ctx->cq_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = ctxm->cq_l2_entries + extra_qps * 2; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7688,7 +7672,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; - ctx_pg = &ctx->vnic_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = ctxm->max_entries; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7698,7 +7682,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; - ctx_pg = &ctx->stat_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = ctxm->max_entries; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7712,7 +7696,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) goto skip_rdma; ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; - ctx_pg = &ctx->mrav_mem; + ctx_pg = ctxm->pg_info; /* 128K extra is needed to accommodate static AH context * allocation by f/w. */ @@ -7732,7 +7716,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; - ctx_pg = &ctx->tim_mem; + ctx_pg = ctxm->pg_info; ctx_pg->entries = l2_qps + qp1_qps + extra_qps; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; @@ -7751,8 +7735,8 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) entries = l2_qps + 2 * (extra_qps + qp1_qps); entries = roundup(entries, ctxm->entry_multiple); entries = clamp_t(u32, entries, min, ctxm->max_entries); - for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) { - ctx_pg = ctx->tqm_mem[i]; + for (i = 0, ctx_pg = ctxm->pg_info; i < ctx->tqm_fp_rings_count + 1; + ctx_pg = &ctx->ctx_arr[BNXT_CTX_FTQM].pg_info[i], i++) { ctx_pg->entries = i ? entries : entries_sp; if (ctxm->entry_size) { mem_size = ctxm->entry_size * ctx_pg->entries; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 7e67df57b8af..067a66eedf36 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1609,15 +1609,6 @@ struct bnxt_ctx_mem_info { u32 flags; #define BNXT_CTX_FLAG_INITED 0x01 struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_MAX]; - - struct bnxt_ctx_pg_info qp_mem; - struct bnxt_ctx_pg_info srq_mem; - struct bnxt_ctx_pg_info cq_mem; - struct bnxt_ctx_pg_info vnic_mem; - struct bnxt_ctx_pg_info stat_mem; - struct bnxt_ctx_pg_info mrav_mem; - struct bnxt_ctx_pg_info tim_mem; - struct bnxt_ctx_pg_info *tqm_mem[BNXT_MAX_TQM_RINGS]; }; enum bnxt_health_severity { From b098dc5a3357e5791dd397716737cd8bdfd9a8f5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:58 -0800 Subject: [PATCH 1101/7721] bnxt_en: Add bnxt_setup_ctxm_pg_tbls() helper function In bnxt_alloc_ctx_mem(), the logic to set up the context memory entries and to allocate the context memory tables is done repetitively. Add a helper function to simplify the code. The setup of the Fast Path TQM entries relies on some information from the Slow Path TQM entries. Copy the SP_TQM entries to the FP_TQM entries to simplify the logic. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-7-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 133 ++++++++++------------ 1 file changed, 59 insertions(+), 74 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 524023b8e959..e42c82ed0fd5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7307,6 +7307,7 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) ctx->tqm_fp_rings_count = BNXT_MAX_TQM_FP_RINGS; ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM]; + memcpy(ctxm, &ctx->ctx_arr[BNXT_CTX_STQM], sizeof(*ctxm)); ctxm->instance_bmap = (1 << ctx->tqm_fp_rings_count) - 1; rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_MAX); @@ -7574,6 +7575,30 @@ static void bnxt_free_ctx_pg_tbls(struct bnxt *bp, ctx_pg->nr_pages = 0; } +static int bnxt_setup_ctxm_pg_tbls(struct bnxt *bp, + struct bnxt_ctx_mem_type *ctxm, u32 entries, + u8 pg_lvl) +{ + struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; + int i, rc = 0, n = 1; + u32 mem_size; + + if (!ctxm->entry_size || !ctx_pg) + return -EINVAL; + if (ctxm->instance_bmap) + n = hweight32(ctxm->instance_bmap); + if (ctxm->entry_multiple) + entries = roundup(entries, ctxm->entry_multiple); + entries = clamp_t(u32, entries, ctxm->min_entries, ctxm->max_entries); + mem_size = entries * ctxm->entry_size; + for (i = 0; i < n && !rc; i++) { + ctx_pg[i].entries = entries; + rc = bnxt_alloc_ctx_pg_tbls(bp, &ctx_pg[i], mem_size, pg_lvl, + ctxm->init_value ? ctxm : NULL); + } + return rc; +} + void bnxt_free_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_mem_info *ctx = bp->ctx; @@ -7605,13 +7630,11 @@ void bnxt_free_ctx_mem(struct bnxt *bp) static int bnxt_alloc_ctx_mem(struct bnxt *bp) { - struct bnxt_ctx_pg_info *ctx_pg; struct bnxt_ctx_mem_type *ctxm; struct bnxt_ctx_mem_info *ctx; u32 l2_qps, qp1_qps, max_qps; - u32 mem_size, ena, entries; - u32 entries_sp, min; - u32 srqs, max_srqs; + u32 ena, entries_sp, entries; + u32 srqs, max_srqs, min; u32 num_mr, num_ah; u32 extra_srqs = 0; u32 extra_qps = 0; @@ -7642,61 +7665,37 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) } ctxm = &ctx->ctx_arr[BNXT_CTX_QP]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = l2_qps + qp1_qps + extra_qps; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, l2_qps + qp1_qps + extra_qps, + pg_lvl); + if (rc) + return rc; ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = srqs + extra_srqs; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, srqs + extra_srqs, pg_lvl); + if (rc) + return rc; ctxm = &ctx->ctx_arr[BNXT_CTX_CQ]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = ctxm->cq_l2_entries + extra_qps * 2; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->cq_l2_entries + + extra_qps * 2, pg_lvl); + if (rc) + return rc; ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = ctxm->max_entries; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->max_entries, 1); + if (rc) + return rc; ctxm = &ctx->ctx_arr[BNXT_CTX_STAT]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = ctxm->max_entries; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->max_entries, 1); + if (rc) + return rc; ena = 0; if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) goto skip_rdma; ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV]; - ctx_pg = ctxm->pg_info; /* 128K extra is needed to accommodate static AH context * allocation by f/w. */ @@ -7706,24 +7705,15 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah) ctxm->mrav_av_entries = num_ah; - ctx_pg->entries = num_mr + num_ah; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2, ctxm); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, num_mr + num_ah, 2); + if (rc) + return rc; ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; ctxm = &ctx->ctx_arr[BNXT_CTX_TIM]; - ctx_pg = ctxm->pg_info; - ctx_pg->entries = l2_qps + qp1_qps + extra_qps; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, NULL); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, l2_qps + qp1_qps + extra_qps, 1); + if (rc) + return rc; ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM; skip_rdma: @@ -7731,22 +7721,17 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) min = ctxm->min_entries; entries_sp = ctx->ctx_arr[BNXT_CTX_VNIC].vnic_entries + l2_qps + 2 * (extra_qps + qp1_qps) + min; - entries_sp = roundup(entries_sp, ctxm->entry_multiple); + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, entries_sp, 2); + if (rc) + return rc; + + ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM]; entries = l2_qps + 2 * (extra_qps + qp1_qps); - entries = roundup(entries, ctxm->entry_multiple); - entries = clamp_t(u32, entries, min, ctxm->max_entries); - for (i = 0, ctx_pg = ctxm->pg_info; i < ctx->tqm_fp_rings_count + 1; - ctx_pg = &ctx->ctx_arr[BNXT_CTX_FTQM].pg_info[i], i++) { - ctx_pg->entries = i ? entries : entries_sp; - if (ctxm->entry_size) { - mem_size = ctxm->entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, - NULL); - if (rc) - return rc; - } + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, entries, 2); + if (rc) + return rc; + for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i; - } ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES; rc = bnxt_hwrm_func_backing_store_cfg(bp, ena); if (rc) { From 6a4d0774f02d61f8c75ffe2e38a8553410fe52e9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:43:59 -0800 Subject: [PATCH 1102/7721] bnxt_en: Add support for new backing store query firmware API Use the new v2 firmware API if supported by the firmware. We now have the infrastructure to support the v2 API. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-8-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 85 +++++++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 +- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e42c82ed0fd5..19da6c8f8650 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7208,6 +7208,72 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max) return 0; } +#define BNXT_CTX_INIT_VALID(flags) \ + (!!((flags) & \ + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ENABLE_CTX_KIND_INIT)) + +static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) +{ + struct hwrm_func_backing_store_qcaps_v2_output *resp; + struct hwrm_func_backing_store_qcaps_v2_input *req; + u16 last_valid_type = BNXT_CTX_INV; + struct bnxt_ctx_mem_info *ctx; + u16 type; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2); + if (rc) + return rc; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + bp->ctx = ctx; + + resp = hwrm_req_hold(bp, req); + + for (type = 0; type < BNXT_CTX_V2_MAX; ) { + struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; + u8 init_val, init_off, i; + __le32 *p; + u32 flags; + + req->type = cpu_to_le16(type); + rc = hwrm_req_send(bp, req); + if (rc) + goto ctx_done; + flags = le32_to_cpu(resp->flags); + type = le16_to_cpu(resp->next_valid_type); + if (!(flags & FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID)) + continue; + + ctxm->type = le16_to_cpu(resp->type); + last_valid_type = ctxm->type; + ctxm->entry_size = le16_to_cpu(resp->entry_size); + ctxm->flags = flags; + ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map); + ctxm->entry_multiple = resp->entry_multiple; + ctxm->max_entries = le32_to_cpu(resp->max_num_entries); + ctxm->min_entries = le32_to_cpu(resp->min_num_entries); + init_val = resp->ctx_init_value; + init_off = resp->ctx_init_offset; + bnxt_init_ctx_initializer(ctxm, init_val, init_off, + BNXT_CTX_INIT_VALID(flags)); + ctxm->split_entry_cnt = min_t(u8, resp->subtype_valid_cnt, + BNXT_MAX_SPLIT_ENTRY); + for (i = 0, p = &resp->split_entry_0; i < ctxm->split_entry_cnt; + i++, p++) + ctxm->split[i] = le32_to_cpu(*p); + } + if (last_valid_type < BNXT_CTX_V2_MAX) + ctx->ctx_arr[last_valid_type].last = true; + rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_V2_MAX); + +ctx_done: + hwrm_req_drop(bp, req); + return rc; +} + static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) { struct hwrm_func_backing_store_qcaps_output *resp; @@ -7217,6 +7283,9 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || bp->ctx) return 0; + if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2) + return bnxt_hwrm_func_backing_store_qcaps_v2(bp); + rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS); if (rc) return rc; @@ -7229,13 +7298,15 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) u8 init_val, init_idx = 0; u16 init_mask; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + ctx = bp->ctx; if (!ctx) { - rc = -ENOMEM; - goto ctx_err; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto ctx_err; + } + bp->ctx = ctx; } - bp->ctx = ctx; - init_val = resp->ctx_kind_initializer; init_mask = le16_to_cpu(resp->ctx_init_mask); @@ -7607,7 +7678,7 @@ void bnxt_free_ctx_mem(struct bnxt *bp) if (!ctx) return; - for (type = 0; type < BNXT_CTX_MAX; type++) { + for (type = 0; type < BNXT_CTX_V2_MAX; type++) { struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; int i, n = 1; @@ -7914,6 +7985,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF; if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED)) bp->fw_cap |= BNXT_FW_CAP_LIVEPATCH; + if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_BS_V2_SUPPORTED) + bp->fw_cap |= BNXT_FW_CAP_BACKING_STORE_V2; flags_ext2 = le32_to_cpu(resp->flags_ext2); if (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 067a66eedf36..0dbf854530f1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1608,7 +1608,7 @@ struct bnxt_ctx_mem_info { u32 flags; #define BNXT_CTX_FLAG_INITED 0x01 - struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_MAX]; + struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_V2_MAX]; }; enum bnxt_health_severity { @@ -2070,6 +2070,7 @@ struct bnxt { #define BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED BIT_ULL(33) #define BNXT_FW_CAP_DFLT_VLAN_TPID_PCP BIT_ULL(34) #define BNXT_FW_CAP_PRE_RESV_VNICS BIT_ULL(35) + #define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(36) u32 fw_dbg_cap; From 236e237f8ffe77c704cee1e63beb9578922bcc5c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:44:00 -0800 Subject: [PATCH 1103/7721] bnxt_en: Add support for HWRM_FUNC_BACKING_STORE_CFG_V2 firmware calls Newer chips starting with 57600 will use this new firmware HWRM call to configure backing store memory. Add this new call if it is supported by the firmware. Reviewed-by: Hongguang Gao Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-9-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 71 ++++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 19da6c8f8650..85d1fdb616ca 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7670,6 +7670,71 @@ static int bnxt_setup_ctxm_pg_tbls(struct bnxt *bp, return rc; } +static int bnxt_hwrm_func_backing_store_cfg_v2(struct bnxt *bp, + struct bnxt_ctx_mem_type *ctxm, + bool last) +{ + struct hwrm_func_backing_store_cfg_v2_input *req; + u32 instance_bmap = ctxm->instance_bmap; + int i, j, rc = 0, n = 1; + __le32 *p; + + if (!(ctxm->flags & BNXT_CTX_MEM_TYPE_VALID) || !ctxm->pg_info) + return 0; + + if (instance_bmap) + n = hweight32(ctxm->instance_bmap); + else + instance_bmap = 1; + + rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_CFG_V2); + if (rc) + return rc; + hwrm_req_hold(bp, req); + req->type = cpu_to_le16(ctxm->type); + req->entry_size = cpu_to_le16(ctxm->entry_size); + req->subtype_valid_cnt = ctxm->split_entry_cnt; + for (i = 0, p = &req->split_entry_0; i < ctxm->split_entry_cnt; i++) + p[i] = cpu_to_le32(ctxm->split[i]); + for (i = 0, j = 0; j < n && !rc; i++) { + struct bnxt_ctx_pg_info *ctx_pg; + + if (!(instance_bmap & (1 << i))) + continue; + req->instance = cpu_to_le16(i); + ctx_pg = &ctxm->pg_info[j++]; + if (!ctx_pg->entries) + continue; + req->num_entries = cpu_to_le32(ctx_pg->entries); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, + &req->page_size_pbl_level, + &req->page_dir); + if (last && j == n) + req->flags = + cpu_to_le32(FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_CFG_ALL_DONE); + rc = hwrm_req_send(bp, req); + } + hwrm_req_drop(bp, req); + return rc; +} + +static int bnxt_backing_store_cfg_v2(struct bnxt *bp) +{ + struct bnxt_ctx_mem_info *ctx = bp->ctx; + struct bnxt_ctx_mem_type *ctxm; + int rc = 0; + u16 type; + + for (type = 0 ; type < BNXT_CTX_V2_MAX; type++) { + ctxm = &ctx->ctx_arr[type]; + + rc = bnxt_hwrm_func_backing_store_cfg_v2(bp, ctxm, ctxm->last); + if (rc) + return rc; + } + return 0; +} + void bnxt_free_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_mem_info *ctx = bp->ctx; @@ -7804,7 +7869,11 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i; ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES; - rc = bnxt_hwrm_func_backing_store_cfg(bp, ena); + + if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2) + rc = bnxt_backing_store_cfg_v2(bp); + else + rc = bnxt_hwrm_func_backing_store_cfg(bp, ena); if (rc) { netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n", rc); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 0dbf854530f1..a591f950ce14 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1548,6 +1548,7 @@ struct bnxt_ctx_mem_type { u16 type; u16 entry_size; u32 flags; +#define BNXT_CTX_MEM_TYPE_VALID FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID u32 instance_bmap; u8 init_value; u8 entry_multiple; From b9e0c47ee2ec588fa0d0527e62c0405b15ecdb25 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:44:01 -0800 Subject: [PATCH 1104/7721] bnxt_en: Add db_ring_mask and related macro to bnxt_db_info struct. This allows the doorbell related logic to mask the doorbell index to the proper range before writing the doorbell. The current code masks the doorbell index immediately to keep it in the legal ranges for the most part. Subsequent patches will change the logic so that the index increments unbounded and it only gets masked before use. This is preparation work for the new chip that requires an additional Epoch bit in the doorbell that needs to toggle when the index has wrapped around. This patch just adds the basic infrastructure and the logic is largely unchanged. We now replace RING_CMP() with the new DB_RING_IDX() at appropriate places where we mask the completion ring index before writing the doorbell. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-10-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 39 ++++++++++++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 13 +++++--- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 85d1fdb616ca..48c443d52344 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -254,18 +254,18 @@ static bool bnxt_vf_pciid(enum board_idx idx) writel(DB_CP_IRQ_DIS_FLAGS, db) #define BNXT_DB_CQ(db, idx) \ - writel(DB_CP_FLAGS | RING_CMP(idx), (db)->doorbell) + writel(DB_CP_FLAGS | DB_RING_IDX(db, idx), (db)->doorbell) #define BNXT_DB_NQ_P5(db, idx) \ - bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ | RING_CMP(idx), \ + bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ | DB_RING_IDX(db, idx),\ (db)->doorbell) #define BNXT_DB_CQ_ARM(db, idx) \ - writel(DB_CP_REARM_FLAGS | RING_CMP(idx), (db)->doorbell) + writel(DB_CP_REARM_FLAGS | DB_RING_IDX(db, idx), (db)->doorbell) #define BNXT_DB_NQ_ARM_P5(db, idx) \ - bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_ARM | RING_CMP(idx),\ - (db)->doorbell) + bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_ARM | \ + DB_RING_IDX(db, idx), (db)->doorbell) static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { @@ -287,7 +287,7 @@ static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { if (bp->flags & BNXT_FLAG_CHIP_P5) bnxt_writeq(bp, db->db_key64 | DBR_TYPE_CQ_ARMALL | - RING_CMP(idx), db->doorbell); + DB_RING_IDX(db, idx), db->doorbell); else BNXT_DB_CQ(db, idx); } @@ -526,7 +526,8 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(txbd, tx_push1, sizeof(*txbd)); prod = NEXT_TX(prod); tx_push->doorbell = - cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | prod); + cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | + DB_RING_IDX(&txr->tx_db, prod)); WRITE_ONCE(txr->tx_prod, prod); tx_buf->is_push = 1; @@ -2871,7 +2872,8 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, if (cpr2->had_work_done) { db = &cpr2->cp_db; bnxt_writeq(bp, db->db_key64 | dbr_type | - RING_CMP(cpr2->cp_raw_cons), db->doorbell); + DB_RING_IDX(db, cpr2->cp_raw_cons), + db->doorbell); cpr2->had_work_done = 0; } } @@ -5987,6 +5989,26 @@ static int bnxt_hwrm_set_async_event_cr(struct bnxt *bp, int idx) } } +static void bnxt_set_db_mask(struct bnxt *bp, struct bnxt_db_info *db, + u32 ring_type) +{ + switch (ring_type) { + case HWRM_RING_ALLOC_TX: + db->db_ring_mask = bp->tx_ring_mask; + break; + case HWRM_RING_ALLOC_RX: + db->db_ring_mask = bp->rx_ring_mask; + break; + case HWRM_RING_ALLOC_AGG: + db->db_ring_mask = bp->rx_agg_ring_mask; + break; + case HWRM_RING_ALLOC_CMPL: + case HWRM_RING_ALLOC_NQ: + db->db_ring_mask = bp->cp_ring_mask; + break; + } +} + static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, u32 map_idx, u32 xid) { @@ -6026,6 +6048,7 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, break; } } + bnxt_set_db_mask(bp, db, ring_type); } static int bnxt_hwrm_ring_alloc(struct bnxt *bp) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a591f950ce14..7d79a2c8d3c3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -813,8 +813,11 @@ struct bnxt_db_info { u64 db_key64; u32 db_key32; }; + u32 db_ring_mask; }; +#define DB_RING_IDX(db, idx) ((idx) & (db)->db_ring_mask) + struct bnxt_tx_ring_info { struct bnxt_napi *bnapi; struct bnxt_cp_ring_info *tx_cpr; @@ -2353,9 +2356,10 @@ static inline void bnxt_db_write_relaxed(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { if (bp->flags & BNXT_FLAG_CHIP_P5) { - bnxt_writeq_relaxed(bp, db->db_key64 | idx, db->doorbell); + bnxt_writeq_relaxed(bp, db->db_key64 | DB_RING_IDX(db, idx), + db->doorbell); } else { - u32 db_val = db->db_key32 | idx; + u32 db_val = db->db_key32 | DB_RING_IDX(db, idx); writel_relaxed(db_val, db->doorbell); if (bp->flags & BNXT_FLAG_DOUBLE_DB) @@ -2368,9 +2372,10 @@ static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { if (bp->flags & BNXT_FLAG_CHIP_P5) { - bnxt_writeq(bp, db->db_key64 | idx, db->doorbell); + bnxt_writeq(bp, db->db_key64 | DB_RING_IDX(db, idx), + db->doorbell); } else { - u32 db_val = db->db_key32 | idx; + u32 db_val = db->db_key32 | DB_RING_IDX(db, idx); writel(db_val, db->doorbell); if (bp->flags & BNXT_FLAG_DOUBLE_DB) From 6d1add95536bafe585c500ad8114af7ed4225a0f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:44:02 -0800 Subject: [PATCH 1105/7721] bnxt_en: Modify TX ring indexing logic. Change the TX ring logic so that the index increments unbounded and mask it only when needed. Modify the existing macros so that the index is not masked. Add a new macro RING_TX() to mask it only when needed to get the index of txr->tx_buf_ring[]. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-11-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 22 +++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 5 +++-- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 14 ++++++------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 48c443d52344..c83450564765 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -432,9 +432,9 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb_headlen(skb); last_frag = skb_shinfo(skb)->nr_frags; - txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; - tx_buf = &txr->tx_buf_ring[prod]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; tx_buf->skb = skb; tx_buf->nr_frags = last_frag; @@ -522,7 +522,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2); prod = NEXT_TX(prod); tx_push->tx_bd_opaque = txbd->tx_bd_opaque; - txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; memcpy(txbd, tx_push1, sizeof(*txbd)); prod = NEXT_TX(prod); tx_push->doorbell = @@ -569,7 +569,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) prod = NEXT_TX(prod); txbd1 = (struct tx_bd_ext *) - &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; txbd1->tx_bd_hsize_lflags = lflags; if (skb_is_gso(skb)) { @@ -610,7 +610,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; prod = NEXT_TX(prod); - txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; len = skb_frag_size(frag); mapping = skb_frag_dma_map(&pdev->dev, frag, 0, len, @@ -619,7 +619,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(dma_mapping_error(&pdev->dev, mapping))) goto tx_dma_error; - tx_buf = &txr->tx_buf_ring[prod]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; dma_unmap_addr_set(tx_buf, mapping, mapping); txbd->tx_bd_haddr = cpu_to_le64(mapping); @@ -668,7 +668,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* start back at beginning and unmap skb */ prod = txr->tx_prod; - tx_buf = &txr->tx_buf_ring[prod]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; dma_unmap_single(&pdev->dev, dma_unmap_addr(tx_buf, mapping), skb_headlen(skb), DMA_TO_DEVICE); prod = NEXT_TX(prod); @@ -676,7 +676,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* unmap remaining mapped pages */ for (i = 0; i < last_frag; i++) { prod = NEXT_TX(prod); - tx_buf = &txr->tx_buf_ring[prod]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; dma_unmap_page(&pdev->dev, dma_unmap_addr(tx_buf, mapping), skb_frag_size(&skb_shinfo(skb)->frags[i]), DMA_TO_DEVICE); @@ -702,12 +702,12 @@ static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr, u16 cons = txr->tx_cons; int tx_pkts = 0; - while (cons != hw_cons) { + while (RING_TX(bp, cons) != hw_cons) { struct bnxt_sw_tx_bd *tx_buf; struct sk_buff *skb; int j, last; - tx_buf = &txr->tx_buf_ring[cons]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, cons)]; cons = NEXT_TX(cons); skb = tx_buf->skb; tx_buf->skb = NULL; @@ -731,7 +731,7 @@ static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr, for (j = 0; j < last; j++) { cons = NEXT_TX(cons); - tx_buf = &txr->tx_buf_ring[cons]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, cons)]; dma_unmap_page( &pdev->dev, dma_unmap_addr(tx_buf, mapping), diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 7d79a2c8d3c3..1b04510f677b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -689,7 +689,7 @@ struct nqe_cn { #define RX_RING(x) (((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4)) #define RX_IDX(x) ((x) & (RX_DESC_CNT - 1)) -#define TX_RING(x) (((x) & ~(TX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4)) +#define TX_RING(bp, x) (((x) & (bp)->tx_ring_mask) >> (BNXT_PAGE_SHIFT - 4)) #define TX_IDX(x) ((x) & (TX_DESC_CNT - 1)) #define CP_RING(x) (((x) & ~(CP_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4)) @@ -720,7 +720,8 @@ struct nqe_cn { #define NEXT_RX_AGG(idx) (((idx) + 1) & bp->rx_agg_ring_mask) -#define NEXT_TX(idx) (((idx) + 1) & bp->tx_ring_mask) +#define RING_TX(bp, idx) ((idx) & (bp)->tx_ring_mask) +#define NEXT_TX(idx) ((idx) + 1) #define ADV_RAW_CMP(idx, n) ((idx) + (n)) #define NEXT_RAW_CMP(idx) ADV_RAW_CMP(idx, 1) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 9d428eb3fdb9..4791f6a14e55 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -42,12 +42,12 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, /* fill up the first buffer */ prod = txr->tx_prod; - tx_buf = &txr->tx_buf_ring[prod]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; tx_buf->nr_frags = num_frags; if (xdp) tx_buf->page = virt_to_head_page(xdp->data); - txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; flags = (len << TX_BD_LEN_SHIFT) | ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) | bnxt_lhint_arr[len >> 9]; @@ -67,10 +67,10 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, WRITE_ONCE(txr->tx_prod, prod); /* first fill up the first buffer */ - frag_tx_buf = &txr->tx_buf_ring[prod]; + frag_tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)]; frag_tx_buf->page = skb_frag_page(frag); - txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; frag_len = skb_frag_size(frag); frag_mapping = skb_frag_dma_map(&pdev->dev, frag, 0, @@ -139,8 +139,8 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) if (!budget) return; - while (tx_cons != tx_hw_cons) { - tx_buf = &txr->tx_buf_ring[tx_cons]; + while (RING_TX(bp, tx_cons) != tx_hw_cons) { + tx_buf = &txr->tx_buf_ring[RING_TX(bp, tx_cons)]; if (tx_buf->action == XDP_REDIRECT) { struct pci_dev *pdev = bp->pdev; @@ -160,7 +160,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) frags = tx_buf->nr_frags; for (j = 0; j < frags; j++) { tx_cons = NEXT_TX(tx_cons); - tx_buf = &txr->tx_buf_ring[tx_cons]; + tx_buf = &txr->tx_buf_ring[RING_TX(bp, tx_cons)]; page_pool_recycle_direct(rxr->page_pool, tx_buf->page); } } else { From c09d22674b9420abaaaf946bab471c63369c6509 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:44:03 -0800 Subject: [PATCH 1106/7721] bnxt_en: Modify RX ring indexing logic. Modify the RX indexing logic for both RX ring and RX aggregation ring just like the TX logic. Change it so that the index increments unbounded and mask it only when needed. Modify the existing RX macros so that the index is not masked. Add new macros RING_RX()/RING_RX_AGG() to mask it only when needed to get the index of rxr->rx_buf_ring[] and rxr->rx_agg_ring[]. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-12-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 29 ++++++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 10 +++++--- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c83450564765..b2cf42953130 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -821,8 +821,8 @@ static inline u8 *__bnxt_alloc_rx_frag(struct bnxt *bp, dma_addr_t *mapping, int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 prod, gfp_t gfp) { - struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; - struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[prod]; + struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)]; + struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)]; dma_addr_t mapping; if (BNXT_RX_PAGE_MODE(bp)) { @@ -855,9 +855,10 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data) { u16 prod = rxr->rx_prod; struct bnxt_sw_rx_bd *cons_rx_buf, *prod_rx_buf; + struct bnxt *bp = rxr->bnapi->bp; struct rx_bd *cons_bd, *prod_bd; - prod_rx_buf = &rxr->rx_buf_ring[prod]; + prod_rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)]; cons_rx_buf = &rxr->rx_buf_ring[cons]; prod_rx_buf->data = data; @@ -865,8 +866,8 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data) prod_rx_buf->mapping = cons_rx_buf->mapping; - prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; - cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)]; + cons_bd = &rxr->rx_desc_ring[RX_RING(bp, cons)][RX_IDX(cons)]; prod_bd->rx_bd_haddr = cons_bd->rx_bd_haddr; } @@ -886,7 +887,7 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, u16 prod, gfp_t gfp) { struct rx_bd *rxbd = - &rxr->rx_agg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + &rxr->rx_agg_desc_ring[RX_AGG_RING(bp, prod)][RX_IDX(prod)]; struct bnxt_sw_rx_agg_bd *rx_agg_buf; struct page *page; dma_addr_t mapping; @@ -903,7 +904,7 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, __set_bit(sw_prod, rxr->rx_agg_bmap); rx_agg_buf = &rxr->rx_agg_ring[sw_prod]; - rxr->rx_sw_agg_prod = NEXT_RX_AGG(sw_prod); + rxr->rx_sw_agg_prod = RING_RX_AGG(bp, NEXT_RX_AGG(sw_prod)); rx_agg_buf->page = page; rx_agg_buf->offset = offset; @@ -979,13 +980,13 @@ static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 idx, prod_rx_buf->mapping = cons_rx_buf->mapping; - prod_bd = &rxr->rx_agg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + prod_bd = &rxr->rx_agg_desc_ring[RX_AGG_RING(bp, prod)][RX_IDX(prod)]; prod_bd->rx_bd_haddr = cpu_to_le64(cons_rx_buf->mapping); prod_bd->rx_bd_opaque = sw_prod; prod = NEXT_RX_AGG(prod); - sw_prod = NEXT_RX_AGG(sw_prod); + sw_prod = RING_RX_AGG(bp, NEXT_RX_AGG(sw_prod)); } rxr->rx_agg_prod = prod; rxr->rx_sw_agg_prod = sw_prod; @@ -1327,7 +1328,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, cons = tpa_start->rx_tpa_start_cmp_opaque; prod = rxr->rx_prod; cons_rx_buf = &rxr->rx_buf_ring[cons]; - prod_rx_buf = &rxr->rx_buf_ring[prod]; + prod_rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)]; tpa_info = &rxr->rx_tpa[agg_id]; if (unlikely(cons != rxr->rx_next_cons || @@ -1348,7 +1349,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, mapping = tpa_info->mapping; prod_rx_buf->mapping = mapping; - prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)]; prod_bd->rx_bd_haddr = cpu_to_le64(mapping); @@ -1381,8 +1382,8 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, tpa_info->agg_count = 0; rxr->rx_prod = NEXT_RX(prod); - cons = NEXT_RX(cons); - rxr->rx_next_cons = NEXT_RX(cons); + cons = RING_RX(bp, NEXT_RX(cons)); + rxr->rx_next_cons = RING_RX(bp, NEXT_RX(cons)); cons_rx_buf = &rxr->rx_buf_ring[cons]; bnxt_reuse_rx_data(rxr, cons, cons_rx_buf->data); @@ -2050,7 +2051,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, next_rx_no_len: rxr->rx_prod = NEXT_RX(prod); - rxr->rx_next_cons = NEXT_RX(cons); + rxr->rx_next_cons = RING_RX(bp, NEXT_RX(cons)); next_rx_no_prod_no_len: *raw_cons = tmp_raw_cons; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 1b04510f677b..17e1881c8a27 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -686,7 +686,9 @@ struct nqe_cn { */ #define BNXT_MIN_TX_DESC_CNT (MAX_SKB_FRAGS + 2) -#define RX_RING(x) (((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4)) +#define RX_RING(bp, x) (((x) & (bp)->rx_ring_mask) >> (BNXT_PAGE_SHIFT - 4)) +#define RX_AGG_RING(bp, x) (((x) & (bp)->rx_agg_ring_mask) >> \ + (BNXT_PAGE_SHIFT - 4)) #define RX_IDX(x) ((x) & (RX_DESC_CNT - 1)) #define TX_RING(bp, x) (((x) & (bp)->tx_ring_mask) >> (BNXT_PAGE_SHIFT - 4)) @@ -716,9 +718,11 @@ struct nqe_cn { #define RX_CMP_TYPE(rxcmp) \ (le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_CMP_TYPE) -#define NEXT_RX(idx) (((idx) + 1) & bp->rx_ring_mask) +#define RING_RX(bp, idx) ((idx) & (bp)->rx_ring_mask) +#define NEXT_RX(idx) ((idx) + 1) -#define NEXT_RX_AGG(idx) (((idx) + 1) & bp->rx_agg_ring_mask) +#define RING_RX_AGG(bp, idx) ((idx) & (bp)->rx_agg_ring_mask) +#define NEXT_RX_AGG(idx) ((idx) + 1) #define RING_TX(bp, idx) ((idx) & (bp)->tx_ring_mask) #define NEXT_TX(idx) ((idx) + 1) From f94471f3ce74a5fbe2dc5d9687748d9127174eca Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Nov 2023 15:44:04 -0800 Subject: [PATCH 1107/7721] bnxt_en: Modify the NAPI logic for the new P7 chips Modify the NAPI logic for the new doorbell mechanism on P7 chips. These changes are compatible with the current P5 chips. In the current logic, bnxt_poll_p5() services 1 or more CQs for each MSIX. Each MSIX has an associated NQ and each NQ has 1 or more associated CQs. If any CQ reaches NAPI budget, we'll stay in polling mode and will unconditionally check and service all CQs until we exit polling. We always re-arm all CQs when we exit polling. To be compatible with the new Toggle bit mechanism in P7 chips, we need to modify the logic so that we service and re-arm the CQ only if we receive an NQE notification for work for that CQ. We add a new had_nqe_notify bit to the cp_ring_info structure and it gets set when we see the NQE notification for that CQ anytime during polling. We'll service and re-arm only the CQs with the had_nqe_notify bits set. Reviewed-by: Somnath Kotur Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-13-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b2cf42953130..f968bf12989b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2854,8 +2854,11 @@ static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) for (i = 0; i < cpr->cp_ring_count; i++) { struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[i]; - work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); - cpr->has_more_work |= cpr2->has_more_work; + if (cpr2->had_nqe_notify) { + work_done += __bnxt_poll_work(bp, cpr2, + budget - work_done); + cpr->has_more_work |= cpr2->has_more_work; + } } return work_done; } @@ -2876,6 +2879,8 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, DB_RING_IDX(db, cpr2->cp_raw_cons), db->doorbell); cpr2->had_work_done = 0; + if (dbr_type == DBR_TYPE_CQ_ARMALL) + cpr2->had_nqe_notify = 0; } } __bnxt_poll_work_done(bp, bnapi, budget); @@ -2934,6 +2939,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) idx = BNXT_NQ_HDL_IDX(idx); cpr2 = &cpr->cp_ring_arr[idx]; + cpr2->had_nqe_notify = 1; work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); cpr->has_more_work |= cpr2->has_more_work; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 17e1881c8a27..b287e4a9adff 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1017,6 +1017,8 @@ struct bnxt_cp_ring_info { u8 had_work_done:1; u8 has_more_work:1; + u8 had_nqe_notify:1; + u8 cp_ring_type; u8 cp_idx; From 1c7fd6ee2fe4ec6b808d10c8757fb1c76efa4a52 Mon Sep 17 00:00:00 2001 From: Randy Schacher Date: Mon, 20 Nov 2023 15:44:05 -0800 Subject: [PATCH 1108/7721] bnxt_en: Rename some macros for the P5 chips In preparation to support a new P7 chip which has a lot of similarities with the P5 chip, rename the BNXT_FLAG_CHIP_P5 flag to BNXT_FLAG_CHIP_P5_PLUS. This will make it clear that the flag is for P5 and newer chips. Also, since there are no additional P5 variants in production, rename BNXT_FLAG_CHIP_P5_THOR() to BNXT_FLAG_CHIP_P5() to keep the naming more simple. Reviewed-by: Andy Gospodarek Reviewed-by: Ajit Khaparde Signed-off-by: Randy Schacher Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231120234405.194542-14-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 184 +++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 18 +- .../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 8 +- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 4 +- .../net/ethernet/broadcom/bnxt/bnxt_sriov.c | 8 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 +- 7 files changed, 116 insertions(+), 114 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index f968bf12989b..d8cf7b30bd03 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -269,7 +269,7 @@ static bool bnxt_vf_pciid(enum board_idx idx) static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) BNXT_DB_NQ_P5(db, idx); else BNXT_DB_CQ(db, idx); @@ -277,7 +277,7 @@ static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) BNXT_DB_NQ_ARM_P5(db, idx); else BNXT_DB_CQ_ARM(db, idx); @@ -285,7 +285,7 @@ static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) bnxt_writeq(bp, db->db_key64 | DBR_TYPE_CQ_ARMALL | DB_RING_IDX(db, idx), db->doorbell); else @@ -321,7 +321,7 @@ static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) { if (!rxr->bnapi->in_reset) { rxr->bnapi->in_reset = true; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event); else set_bit(BNXT_RST_RING_SP_EVENT, &bp->sp_event); @@ -739,7 +739,7 @@ static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr, DMA_TO_DEVICE); } if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (BNXT_CHIP_P5(bp)) { /* PTP worker takes ownership of the skb */ if (!bnxt_get_tx_ts_p5(bp, skb)) skb = NULL; @@ -946,7 +946,7 @@ static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 idx, bool p5_tpa = false; u32 i; - if ((bp->flags & BNXT_FLAG_CHIP_P5) && tpa) + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && tpa) p5_tpa = true; for (i = 0; i < agg_bufs; i++) { @@ -1113,7 +1113,7 @@ static u32 __bnxt_rx_agg_pages(struct bnxt *bp, u32 i, total_frag_len = 0; bool p5_tpa = false; - if ((bp->flags & BNXT_FLAG_CHIP_P5) && tpa) + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && tpa) p5_tpa = true; for (i = 0; i < agg_bufs; i++) { @@ -1268,7 +1268,7 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) { struct rx_tpa_end_cmp *tpa_end = cmp; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return 0; agg_bufs = TPA_END_AGG_BUFS(tpa_end); @@ -1319,7 +1319,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, struct rx_bd *prod_bd; dma_addr_t mapping; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { agg_id = TPA_START_AGG_ID_P5(tpa_start); agg_id = bnxt_alloc_agg_idx(rxr, agg_id); } else { @@ -1582,7 +1582,7 @@ static inline struct sk_buff *bnxt_gro_skb(struct bnxt *bp, skb_shinfo(skb)->gso_size = le32_to_cpu(tpa_end1->rx_tpa_end_cmp_seg_len); skb_shinfo(skb)->gso_type = tpa_info->gso_type; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) payload_off = TPA_END_PAYLOAD_OFF_P5(tpa_end1); else payload_off = TPA_END_PAYLOAD_OFF(tpa_end); @@ -1630,7 +1630,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, return NULL; } - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { agg_id = TPA_END_AGG_ID_P5(tpa_end); agg_id = bnxt_lookup_agg_idx(rxr, agg_id); agg_bufs = TPA_END_AGG_BUFS_P5(tpa_end1); @@ -1895,7 +1895,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, rc = -EIO; if (rx_err & RX_CMPL_ERRORS_BUFFER_ERROR_MASK) { bnapi->cp_ring.sw_stats.rx.rx_buf_errors++; - if (!(bp->flags & BNXT_FLAG_CHIP_P5) && + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && !(bp->fw_cap & BNXT_FW_CAP_RING_MONITOR)) { netdev_warn_once(bp->dev, "RX buffer error %x\n", rx_err); @@ -2026,7 +2026,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, if (unlikely((flags & RX_CMP_FLAGS_ITYPES_MASK) == RX_CMP_FLAGS_ITYPE_PTP_W_TS) || bp->ptp_all_rx_tstamp) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { u32 cmpl_ts = le32_to_cpu(rxcmp1->rx_cmp_timestamp); u64 ns, ts; @@ -2434,7 +2434,7 @@ static int bnxt_async_event_process(struct bnxt *bp, struct bnxt_rx_ring_info *rxr; u16 grp_idx; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) goto async_event_process_exit; netdev_warn(bp->dev, "Ring monitor event, ring type %lu id 0x%x\n", @@ -3258,7 +3258,7 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp) int i, j; bp->max_tpa = MAX_TPA; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { if (!bp->max_tpa_v2) return 0; bp->max_tpa = max_t(u16, bp->max_tpa_v2, MAX_TPA_P5); @@ -3273,7 +3273,7 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp) if (!rxr->rx_tpa) return -ENOMEM; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) continue; for (j = 0; j < bp->max_tpa; j++) { agg = kcalloc(MAX_SKB_FRAGS, sizeof(*agg), GFP_KERNEL); @@ -3651,7 +3651,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) else ring->map_idx = i; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) continue; if (i < bp->rx_nr_rings) { @@ -3965,7 +3965,7 @@ static int bnxt_alloc_vnics(struct bnxt *bp) int num_vnics = 1; #ifdef CONFIG_RFS_ACCEL - if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS) + if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == BNXT_FLAG_RFS) num_vnics += bp->rx_nr_rings; #endif @@ -4238,7 +4238,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp) } } - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) goto vnic_skip_grps; if (vnic->flags & BNXT_VNIC_RSS_FLAG) @@ -4258,7 +4258,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp) /* Allocate rss table and hash key */ size = L1_CACHE_ALIGN(HW_HASH_INDEX_SIZE * sizeof(u16)); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) size = L1_CACHE_ALIGN(BNXT_MAX_RSS_TABLE_SIZE_P5); vnic->rss_table_size = size + HW_HASH_KEY_SIZE; @@ -4368,7 +4368,7 @@ static int bnxt_hwrm_func_qstat_ext(struct bnxt *bp, int rc; if (!(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED) || - !(bp->flags & BNXT_FLAG_CHIP_P5)) + !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return -EOPNOTSUPP; rc = hwrm_req_init(bp, req, HWRM_FUNC_QSTATS_EXT); @@ -4406,7 +4406,7 @@ static void bnxt_init_stats(struct bnxt *bp) stats = &cpr->stats; rc = bnxt_hwrm_func_qstat_ext(bp, stats); if (rc) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) mask = (1ULL << 48) - 1; else mask = -1ULL; @@ -4686,7 +4686,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) bp->bnapi[i] = bnapi; bp->bnapi[i]->index = i; bp->bnapi[i]->bp = bp; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring; @@ -4704,7 +4704,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { rxr->rx_ring_struct.ring_mem.flags = BNXT_RMEM_RING_PTE_FLAG; rxr->rx_agg_ring_struct.ring_mem.flags = @@ -4737,7 +4737,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; struct bnxt_napi *bnapi2; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) txr->tx_ring_struct.ring_mem.flags = BNXT_RMEM_RING_PTE_FLAG; bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i; @@ -4758,7 +4758,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) j++; } txr->bnapi = bnapi2; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) txr->tx_cpr = &bnapi2->cp_ring; } @@ -5284,7 +5284,7 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags) nsegs = (MAX_SKB_FRAGS - n) / n; } - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { segs = MAX_TPA_SEGS_P5; max_aggs = bp->max_tpa; } else { @@ -5310,7 +5310,7 @@ static u16 bnxt_cp_ring_from_grp(struct bnxt *bp, struct bnxt_ring_struct *ring) static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return rxr->rx_cpr->cp_ring_struct.fw_ring_id; else return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct); @@ -5318,7 +5318,7 @@ static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return txr->tx_cpr->cp_ring_struct.fw_ring_id; else return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct); @@ -5328,7 +5328,7 @@ static int bnxt_alloc_rss_indir_tbl(struct bnxt *bp) { int entries; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) entries = BNXT_MAX_RSS_TABLE_ENTRIES_P5; else entries = HW_HASH_INDEX_SIZE; @@ -5378,7 +5378,7 @@ static u16 bnxt_get_max_rss_ring(struct bnxt *bp) int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return DIV_ROUND_UP(rx_rings, BNXT_RSS_TABLE_ENTRIES_P5); if (BNXT_CHIP_TYPE_NITRO_A0(bp)) return 2; @@ -5424,7 +5424,7 @@ static void __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req, struct bnxt_vnic_info *vnic) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) bnxt_fill_hw_rss_tbl_p5(bp, vnic); else bnxt_fill_hw_rss_tbl(bp, vnic); @@ -5449,7 +5449,7 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) struct hwrm_vnic_rss_cfg_input *req; int rc; - if ((bp->flags & BNXT_FLAG_CHIP_P5) || + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) || vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID) return 0; @@ -5614,7 +5614,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) if (rc) return rc; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; req->default_rx_ring_id = @@ -5714,7 +5714,7 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id, if (rc) return rc; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) goto vnic_no_ring_grps; /* map ring groups to this vnic */ @@ -5762,7 +5762,7 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) if (!rc) { u32 flags = le32_to_cpu(resp->flags); - if (!(bp->flags & BNXT_FLAG_CHIP_P5) && + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP)) bp->flags |= BNXT_FLAG_NEW_RSS_CAP; if (flags & @@ -5773,14 +5773,14 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) * VLAN_STRIP_CAP properly. */ if ((flags & VNIC_QCAPS_RESP_FLAGS_VLAN_STRIP_CAP) || - (BNXT_CHIP_P5_THOR(bp) && + (BNXT_CHIP_P5(bp) && !(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED))) bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP; if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_HASH_TYPE_DELTA_CAP) bp->fw_cap |= BNXT_FW_CAP_RSS_HASH_TYPE_DELTA; bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); if (bp->max_tpa_v2) { - if (BNXT_CHIP_P5_THOR(bp)) + if (BNXT_CHIP_P5(bp)) bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5; else bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5_SR2; @@ -5797,7 +5797,7 @@ static int bnxt_hwrm_ring_grp_alloc(struct bnxt *bp) int rc; u16 i; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return 0; rc = hwrm_req_init(bp, req, HWRM_RING_GRP_ALLOC); @@ -5830,7 +5830,7 @@ static void bnxt_hwrm_ring_grp_free(struct bnxt *bp) struct hwrm_ring_grp_free_input *req; u16 i; - if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5)) + if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return; if (hwrm_req_init(bp, req, HWRM_RING_GRP_FREE)) @@ -5895,7 +5895,7 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, case HWRM_RING_ALLOC_RX: req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX; req->length = cpu_to_le32(bp->rx_ring_mask + 1); - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { u16 flags = 0; /* Association of rx ring with stats context */ @@ -5910,7 +5910,7 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, } break; case HWRM_RING_ALLOC_AGG: - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG; /* Association of agg ring with rx ring */ grp_info = &bp->grp_info[ring->grp_idx]; @@ -5928,7 +5928,7 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, case HWRM_RING_ALLOC_CMPL: req->ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL; req->length = cpu_to_le32(bp->cp_ring_mask + 1); - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { /* Association of cp ring with nq */ grp_info = &bp->grp_info[map_index]; req->nq_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id); @@ -6019,7 +6019,7 @@ static void bnxt_set_db_mask(struct bnxt *bp, struct bnxt_db_info *db, static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, u32 map_idx, u32 xid) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { if (BNXT_PF(bp)) db->doorbell = bp->bar1 + DB_PF_OFFSET_P5; else @@ -6064,7 +6064,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) int i, rc = 0; u32 type; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) type = HWRM_RING_ALLOC_NQ; else type = HWRM_RING_ALLOC_CMPL; @@ -6100,7 +6100,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) struct bnxt_ring_struct *ring; u32 map_idx; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { struct bnxt_cp_ring_info *cpr2 = txr->tx_cpr; struct bnxt_napi *bnapi = txr->bnapi; u32 type2 = HWRM_RING_ALLOC_CMPL; @@ -6138,7 +6138,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) if (!agg_rings) bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { struct bnxt_cp_ring_info *cpr2 = rxr->rx_cpr; u32 type2 = HWRM_RING_ALLOC_CMPL; @@ -6251,7 +6251,7 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) } } - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) type = RING_FREE_REQ_RING_TYPE_RX_AGG; else type = RING_FREE_REQ_RING_TYPE_RX; @@ -6278,7 +6278,7 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) */ bnxt_disable_int_sync(bp); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) type = RING_FREE_REQ_RING_TYPE_NQ; else type = RING_FREE_REQ_RING_TYPE_L2_CMPL; @@ -6345,7 +6345,7 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp) cp = le16_to_cpu(resp->alloc_cmpl_rings); stats = le16_to_cpu(resp->alloc_stat_ctx); hw_resc->resv_irqs = cp; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { int rx = hw_resc->resv_rx_rings; int tx = hw_resc->resv_tx_rings; @@ -6410,7 +6410,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, if (BNXT_NEW_RM(bp)) { enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0; enables |= stats ? FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; enables |= tx_rings + ring_grps ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; @@ -6426,7 +6426,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, enables |= vnics ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0; req->num_rx_rings = cpu_to_le16(rx_rings); - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); req->num_msix = cpu_to_le16(cp_rings); req->num_rsscos_ctxs = @@ -6461,7 +6461,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS | FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; enables |= stats ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { enables |= tx_rings + ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; } else { @@ -6476,7 +6476,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); req->num_tx_rings = cpu_to_le16(tx_rings); req->num_rx_rings = cpu_to_le16(rx_rings); - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); req->num_rsscos_ctxs = cpu_to_le16(DIV_ROUND_UP(ring_grps, 64)); } else { @@ -6572,7 +6572,7 @@ static int bnxt_cp_rings_in_use(struct bnxt *bp) { int cp; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return bnxt_nq_rings_in_use(bp); cp = bp->tx_nr_rings + bp->rx_nr_rings; @@ -6629,7 +6629,8 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp) bnxt_check_rss_tbl_no_rmgr(bp); return false; } - if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5)) + if ((bp->flags & BNXT_FLAG_RFS) && + !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) vnic = rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; @@ -6637,9 +6638,9 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp) if (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp || hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat || (hw_resc->resv_hw_ring_grps != grp && - !(bp->flags & BNXT_FLAG_CHIP_P5))) + !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))) return true; - if ((bp->flags & BNXT_FLAG_CHIP_P5) && BNXT_PF(bp) && + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && BNXT_PF(bp) && hw_resc->resv_irqs != nq) return true; return false; @@ -6661,7 +6662,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp) if (bp->flags & BNXT_FLAG_SHARED_RINGS) sh = true; - if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5)) + if ((bp->flags & BNXT_FLAG_RFS) && + !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) vnic = rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; @@ -6752,7 +6754,7 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) flags |= FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST; req->flags = cpu_to_le32(flags); @@ -6774,7 +6776,7 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_NQ_ASSETS_TEST; else @@ -6993,7 +6995,7 @@ bnxt_hwrm_set_tx_coal(struct bnxt *bp, struct bnxt_napi *bnapi, rc = hwrm_req_send(bp, req); if (rc) return rc; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return 0; } return 0; @@ -7030,7 +7032,7 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) if (rc) break; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) continue; if (bnapi->rx_ring && bnapi->tx_ring[0]) { @@ -7188,7 +7190,7 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) if (bp->db_size) goto func_qcfg_exit; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { if (BNXT_PF(bp)) min_db_offset = DB_PF_OFFSET_P5; else @@ -7951,7 +7953,7 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all) hw_resc->min_stat_ctxs = le16_to_cpu(resp->min_stat_ctx); hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx); - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { u16 max_msix = le16_to_cpu(resp->max_msix); hw_resc->max_nqs = max_msix; @@ -7980,7 +7982,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp) u8 flags; int rc; - if (bp->hwrm_spec_code < 0x10801 || !BNXT_CHIP_P5_THOR(bp)) { + if (bp->hwrm_spec_code < 0x10801 || !BNXT_CHIP_P5(bp)) { rc = -ENODEV; goto no_ptp; } @@ -8012,7 +8014,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp) if (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK) { ptp->refclk_regs[0] = le32_to_cpu(resp->ts_ref_clock_reg_lower); ptp->refclk_regs[1] = le32_to_cpu(resp->ts_ref_clock_reg_upper); - } else if (bp->flags & BNXT_FLAG_CHIP_P5) { + } else if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { ptp->refclk_regs[0] = BNXT_TS_REG_TIMESYNC_TS0_LOWER; ptp->refclk_regs[1] = BNXT_TS_REG_TIMESYNC_TS0_UPPER; } else { @@ -8721,7 +8723,7 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp) int i; /* Chip bug. Counter intermittently becomes 0. */ - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) ignore_zero = true; for (i = 0; i < bp->cp_nr_rings; i++) { @@ -8915,7 +8917,7 @@ static void bnxt_clear_vnic(struct bnxt *bp) return; bnxt_hwrm_clear_vnic_filter(bp); - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) { + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) { /* clear all RSS setting before free vnic ctx */ bnxt_hwrm_clear_vnic_rss(bp); bnxt_hwrm_vnic_ctx_free(bp); @@ -8924,7 +8926,7 @@ static void bnxt_clear_vnic(struct bnxt *bp) if (bp->flags & BNXT_FLAG_TPA) bnxt_set_tpa(bp, false); bnxt_hwrm_vnic_free(bp); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) bnxt_hwrm_vnic_ctx_free(bp); } @@ -9081,7 +9083,7 @@ static int __bnxt_setup_vnic_p5(struct bnxt *bp, u16 vnic_id) static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) { - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return __bnxt_setup_vnic_p5(bp, vnic_id); else return __bnxt_setup_vnic(bp, vnic_id); @@ -9092,7 +9094,7 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) #ifdef CONFIG_RFS_ACCEL int i, rc = 0; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return 0; for (i = 0; i < bp->rx_nr_rings; i++) { @@ -9474,7 +9476,7 @@ static unsigned int bnxt_get_max_func_cp_rings_for_en(struct bnxt *bp) { unsigned int cp = bp->hw_resc.max_cp_rings; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) cp -= bnxt_get_ulp_msix_num(bp); return cp; @@ -9484,7 +9486,7 @@ static unsigned int bnxt_get_max_func_irqs(struct bnxt *bp) { struct bnxt_hw_resc *hw_resc = &bp->hw_resc; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return min_t(unsigned int, hw_resc->max_irqs, hw_resc->max_nqs); return min_t(unsigned int, hw_resc->max_irqs, hw_resc->max_cp_rings); @@ -9500,7 +9502,7 @@ unsigned int bnxt_get_avail_cp_rings_for_en(struct bnxt *bp) unsigned int cp; cp = bnxt_get_max_func_cp_rings_for_en(bp); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return cp - bp->rx_nr_rings - bp->tx_nr_rings; else return cp - bp->cp_nr_rings; @@ -9519,7 +9521,7 @@ int bnxt_get_avail_msix(struct bnxt *bp, int num) int max_idx, avail_msix; max_idx = bp->total_irqs; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) max_idx = min_t(int, bp->total_irqs, max_cp); avail_msix = max_idx - bp->cp_nr_rings; if (!BNXT_NEW_RM(bp) || avail_msix >= num) @@ -9798,7 +9800,7 @@ static void bnxt_init_napi(struct bnxt *bp) if (bp->flags & BNXT_FLAG_USING_MSIX) { int (*poll_fn)(struct napi_struct *, int) = bnxt_poll; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) poll_fn = bnxt_poll_p5; else if (BNXT_CHIP_TYPE_NITRO_A0(bp)) cp_nr_rings--; @@ -11517,7 +11519,7 @@ static bool bnxt_can_reserve_rings(struct bnxt *bp) /* If the chip and firmware supports RFS */ static bool bnxt_rfs_supported(struct bnxt *bp) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) return true; return false; @@ -11538,7 +11540,7 @@ static bool bnxt_rfs_capable(struct bnxt *bp) #ifdef CONFIG_RFS_ACCEL int vnics, max_vnics, max_rss_ctxs; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return bnxt_rfs_supported(bp); if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings) return false; @@ -11640,7 +11642,7 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) update_tpa = true; if ((bp->flags & BNXT_FLAG_TPA) == 0 || (flags & BNXT_FLAG_TPA) == 0 || - (bp->flags & BNXT_FLAG_CHIP_P5)) + (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) re_init = true; } @@ -12051,8 +12053,7 @@ static void bnxt_timer(struct timer_list *t) if (test_bit(BNXT_STATE_L2_FILTER_RETRY, &bp->state)) bnxt_queue_sp_work(bp, BNXT_RX_MASK_SP_EVENT); - if ((bp->flags & BNXT_FLAG_CHIP_P5) && !bp->chip_rev && - netif_carrier_ok(dev)) + if ((BNXT_CHIP_P5(bp)) && !bp->chip_rev && netif_carrier_ok(dev)) bnxt_queue_sp_work(bp, BNXT_RING_COAL_NOW_SP_EVENT); bnxt_restart_timer: @@ -12303,7 +12304,7 @@ static void bnxt_chk_missed_irq(struct bnxt *bp) { int i; - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return; for (i = 0; i < bp->cp_nr_rings; i++) { @@ -12507,7 +12508,8 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, return -ENOMEM; vnics = 1; - if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS) + if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == + BNXT_FLAG_RFS) vnics += rx; tx_cp = __bnxt_num_tx_to_cp(bp, tx_rings_needed, tx_sets, tx_xdp); @@ -12588,10 +12590,10 @@ static bool bnxt_fw_pre_resv_vnics(struct bnxt *bp) { u16 fw_maj = BNXT_FW_MAJ(bp), fw_bld = BNXT_FW_BLD(bp); - if (!(bp->flags & BNXT_FLAG_CHIP_P5) && + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && (fw_maj > 218 || (fw_maj == 218 && fw_bld >= 18))) return true; - if ((bp->flags & BNXT_FLAG_CHIP_P5) && + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && (fw_maj > 216 || (fw_maj == 216 && fw_bld >= 172))) return true; return false; @@ -13647,7 +13649,7 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx, max_irq = min_t(int, bnxt_get_max_func_irqs(bp) - bnxt_get_ulp_msix_num(bp), hw_resc->max_stat_ctxs - bnxt_get_ulp_stat_ctxs(bp)); - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) *max_cp = min_t(int, *max_cp, max_irq); max_ring_grps = hw_resc->max_hw_ring_grps; if (BNXT_CHIP_TYPE_NITRO_A0(bp) && BNXT_PF(bp)) { @@ -13656,7 +13658,7 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx, } if (bp->flags & BNXT_FLAG_AGG_RINGS) *max_rx >>= 1; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { if (*max_cp < (*max_rx + *max_tx)) { *max_rx = *max_cp / 2; *max_tx = *max_rx; @@ -14004,8 +14006,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (BNXT_PF(bp)) bnxt_vpd_read_info(bp); - if (BNXT_CHIP_P5(bp)) { - bp->flags |= BNXT_FLAG_CHIP_P5; + if (BNXT_CHIP_P5_PLUS(bp)) { + bp->flags |= BNXT_FLAG_CHIP_P5_PLUS; if (BNXT_CHIP_SR2(bp)) bp->flags |= BNXT_FLAG_CHIP_SR2; } @@ -14070,7 +14072,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bp->gro_func = bnxt_gro_func_5730x; if (BNXT_CHIP_P4(bp)) bp->gro_func = bnxt_gro_func_5731x; - else if (BNXT_CHIP_P5(bp)) + else if (BNXT_CHIP_P5_PLUS(bp)) bp->gro_func = bnxt_gro_func_5750x; } if (!BNXT_CHIP_P4_PLUS(bp)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index b287e4a9adff..94b3627406c4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1430,7 +1430,7 @@ struct bnxt_test_info { }; #define CHIMP_REG_VIEW_ADDR \ - ((bp->flags & BNXT_FLAG_CHIP_P5) ? 0x80000000 : 0xb1000000) + ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) ? 0x80000000 : 0xb1000000) #define BNXT_GRCPF_REG_CHIMP_COMM 0x0 #define BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER 0x100 @@ -1859,7 +1859,7 @@ struct bnxt { atomic_t intr_sem; u32 flags; - #define BNXT_FLAG_CHIP_P5 0x1 + #define BNXT_FLAG_CHIP_P5_PLUS 0x1 #define BNXT_FLAG_VF 0x2 #define BNXT_FLAG_LRO 0x4 #ifdef CONFIG_INET @@ -1913,21 +1913,21 @@ struct bnxt { #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0) #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) #define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_TYPE_NITRO_A0(bp) && \ - (!((bp)->flags & BNXT_FLAG_CHIP_P5) || \ + (!((bp)->flags & BNXT_FLAG_CHIP_P5_PLUS) ||\ (bp)->max_tpa_v2) && !is_kdump_kernel()) #define BNXT_RX_JUMBO_MODE(bp) ((bp)->flags & BNXT_FLAG_JUMBO) #define BNXT_CHIP_SR2(bp) \ ((bp)->chip_num == CHIP_NUM_58818) -#define BNXT_CHIP_P5_THOR(bp) \ +#define BNXT_CHIP_P5(bp) \ ((bp)->chip_num == CHIP_NUM_57508 || \ (bp)->chip_num == CHIP_NUM_57504 || \ (bp)->chip_num == CHIP_NUM_57502) /* Chip class phase 5 */ -#define BNXT_CHIP_P5(bp) \ - (BNXT_CHIP_P5_THOR(bp) || BNXT_CHIP_SR2(bp)) +#define BNXT_CHIP_P5_PLUS(bp) \ + (BNXT_CHIP_P5(bp) || BNXT_CHIP_SR2(bp)) /* Chip class phase 4.x */ #define BNXT_CHIP_P4(bp) \ @@ -1938,7 +1938,7 @@ struct bnxt { !BNXT_CHIP_TYPE_NITRO_A0(bp))) #define BNXT_CHIP_P4_PLUS(bp) \ - (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp)) + (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5_PLUS(bp)) struct bnxt_aux_priv *aux_priv; struct bnxt_en_dev *edev; @@ -2362,7 +2362,7 @@ static inline void bnxt_writeq_relaxed(struct bnxt *bp, u64 val, static inline void bnxt_db_write_relaxed(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { bnxt_writeq_relaxed(bp, db->db_key64 | DB_RING_IDX(db, idx), db->doorbell); } else { @@ -2378,7 +2378,7 @@ static inline void bnxt_db_write_relaxed(struct bnxt *bp, static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { bnxt_writeq(bp, db->db_key64 | DB_RING_IDX(db, idx), db->doorbell); } else { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 10b842539b08..ae1bdda56d22 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -739,7 +739,7 @@ static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver) } /* earlier devices present as an array of raw bytes */ - if (!BNXT_CHIP_P5(bp)) { + if (!BNXT_CHIP_P5_PLUS(bp)) { dim = 0; i = 0; bits *= 3; /* array of 3 version components */ @@ -759,7 +759,7 @@ static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver) goto exit; bnxt_copy_from_nvm_data(&ver, data, bits, bytes); - if (BNXT_CHIP_P5(bp)) { + if (BNXT_CHIP_P5_PLUS(bp)) { *nvm_cfg_ver <<= 8; *nvm_cfg_ver |= ver.vu8; } else { @@ -779,7 +779,7 @@ static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req, if (!strlen(buf)) return 0; - if ((bp->flags & BNXT_FLAG_CHIP_P5) && + if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) || !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE))) return 0; @@ -1005,7 +1005,7 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, if (rc) return rc; - if (BNXT_CHIP_P5(bp)) { + if (BNXT_CHIP_P5_PLUS(bp)) { rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH); if (rc) return rc; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 585044310141..b0cea5b600cc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -511,7 +511,7 @@ static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) { if (BNXT_SUPPORTS_TPA(bp)) { if (bp->max_tpa_v2) { - if (BNXT_CHIP_P5_THOR(bp)) + if (BNXT_CHIP_P5(bp)) return BNXT_NUM_TPA_RING_STATS_P5; return BNXT_NUM_TPA_RING_STATS_P5_SR2; } @@ -1322,7 +1322,7 @@ u32 bnxt_get_rxfh_indir_size(struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); return HW_HASH_INDEX_SIZE; } @@ -3943,7 +3943,7 @@ static int bnxt_run_loopback(struct bnxt *bp) int rc; cpr = &rxr->bnapi->cp_ring; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) cpr = rxr->rx_cpr; pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); skb = netdev_alloc_skb(bp->dev, pkt_size); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c index f3886710e778..a1ec39b46518 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c @@ -650,7 +650,7 @@ static int bnxt_map_ptp_regs(struct bnxt *bp) int rc, i; reg_arr = ptp->refclk_regs; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (BNXT_CHIP_P5(bp)) { rc = bnxt_map_regs(bp, reg_arr, 2, BNXT_PTP_GRC_WIN); if (rc) return rc; @@ -967,7 +967,7 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg) rc = err; goto out; } - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (BNXT_CHIP_P5(bp)) { spin_lock_bh(&ptp->ptp_lock); bnxt_refclk_read(bp, NULL, &ptp->current_time); WRITE_ONCE(ptp->old_time, ptp->current_time); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index c722b3b41730..175192ebaa77 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -536,7 +536,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) if (rc) return rc; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { vf_msix = hw_resc->max_nqs - bnxt_nq_rings_in_use(bp); vf_ring_grps = 0; } else { @@ -565,7 +565,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) req->min_l2_ctxs = cpu_to_le16(min); req->min_vnics = cpu_to_le16(min); req->min_stat_ctx = cpu_to_le16(min); - if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) req->min_hw_ring_grps = cpu_to_le16(min); } else { vf_cp_rings /= num_vfs; @@ -602,7 +602,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) req->max_stat_ctx = cpu_to_le16(vf_stat_ctx); req->max_hw_ring_grps = cpu_to_le16(vf_ring_grps); req->max_rsscos_ctx = cpu_to_le16(vf_rss); - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) req->max_msix = cpu_to_le16(vf_msix / num_vfs); hwrm_req_hold(bp, req); @@ -630,7 +630,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) le16_to_cpu(req->min_rsscos_ctx) * n; hw_resc->max_stat_ctxs -= le16_to_cpu(req->min_stat_ctx) * n; hw_resc->max_vnics -= le16_to_cpu(req->min_vnics) * n; - if (bp->flags & BNXT_FLAG_CHIP_P5) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) hw_resc->max_nqs -= vf_msix; rc = pf->active_vfs; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 6ba2b9398633..e89731492f5e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -42,7 +42,7 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent) for (i = 0; i < num_msix; i++) { ent[i].vector = bp->irq_tbl[idx + i].vector; ent[i].ring_idx = idx + i; - if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { ent[i].db_offset = DB_PF_OFFSET_P5; if (BNXT_VF(bp)) ent[i].db_offset = DB_VF_OFFSET_P5; From 9c6894320f49c146270623bb37cd700db7cf13df Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Tue, 21 Nov 2023 19:54:59 -0500 Subject: [PATCH 1109/7721] fbdev/simplefb: Suppress error on missing power domains When the power domains are missing, the call to of_count_phandle_with_args fails with -ENOENT. The power domains are not required and there are some device trees that do not specify them. Suppress this error to fix devices without power domains attached to simplefb. Fixes: 92a511a568e4 ("fbdev/simplefb: Add support for generic power-domains") Closes: https://lore.kernel.org/linux-fbdev/ZVwFNfkqjrvhFHM0@radian Signed-off-by: Richard Acayan Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231122005457.330066-3-mailingradian@gmail.com --- drivers/video/fbdev/simplefb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index fe682af63827..6f58ee276ad1 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -466,6 +466,10 @@ static int simplefb_attach_genpds(struct simplefb_par *par, err = of_count_phandle_with_args(dev->of_node, "power-domains", "#power-domain-cells"); if (err < 0) { + /* Nothing wrong if optional PDs are missing */ + if (err == -ENOENT) + return 0; + dev_info(dev, "failed to parse power-domains: %d\n", err); return err; } From a274f4d1e5af404fcc7b5554521913590c9d7b08 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 14 Oct 2023 20:56:00 +0300 Subject: [PATCH 1110/7721] media: ccs: Ensure control handlers have been set up after probe If the sensor remains powered on after probe when it is needed again and the runtime PM usage_count is incremented, the control handler setup for neither control handler is run. As this is, in most cases, a needless operation in probe, track the status of sensor power handling after probe and set up control handlers even if the device was already active right after probe. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 5 ++++- drivers/media/i2c/ccs/ccs.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 12e6f0a26fc8..31769ff95d67 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1878,9 +1878,11 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor) goto error; /* Device was already active, so don't set controls */ - if (rval == 1) + if (rval == 1 && !sensor->handler_setup_needed) return 0; + sensor->handler_setup_needed = false; + /* Restore V4L2 controls to the previously suspended device */ rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); if (rval) @@ -3532,6 +3534,7 @@ static int ccs_probe(struct i2c_client *client) sensor->streaming = false; sensor->dev_init_done = true; + sensor->handler_setup_needed = true; rval = ccs_write_msr_regs(sensor); if (rval) diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 9c3587b2fbe7..2c013d96adcc 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -236,6 +236,7 @@ struct ccs_sensor { bool streaming; bool dev_init_done; + bool handler_setup_needed; u8 compressed_min_bpp; struct ccs_module_info minfo; From 153cbfc8bdc55642578d0b513c04496ee27b6430 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:18:29 +0300 Subject: [PATCH 1111/7721] media: ivsc: csi: Don't parse remote endpoints The driver parsed, besides its own endpoint on the sink, the remote upstream endpoint that most likely is a sensor, and took the number of lanes from that. Instead obtain the number of lanes from the local endpoint. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 2a6b828fd8dd..790b1101d579 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -662,6 +662,8 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) return -EINVAL; } + csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; + fwnode = fwnode_graph_get_remote_endpoint(ep); fwnode_handle_put(ep); @@ -675,18 +677,12 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) return PTR_ERR(asd); } - ret = v4l2_fwnode_endpoint_alloc_parse(fwnode, &v4l2_ep); fwnode_handle_put(fwnode); - if (ret) - return ret; - csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; ret = v4l2_async_nf_register(&csi->notifier); if (ret) v4l2_async_nf_cleanup(&csi->notifier); - v4l2_fwnode_endpoint_free(&v4l2_ep); - return ret; } From e34660972b88e8d27f17e220fe13609b5cd52ec2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:23:22 +0300 Subject: [PATCH 1112/7721] media: ivsc: csi: Clean up V4L2 async notifier on error Clean up the V4L2 async notifier in error handling path, and add label to unify handling. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 790b1101d579..19f1a47ba52d 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -672,16 +672,20 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, struct v4l2_async_connection); - if (IS_ERR(asd)) { - fwnode_handle_put(fwnode); - return PTR_ERR(asd); - } - fwnode_handle_put(fwnode); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto out_nf_cleanup; + } ret = v4l2_async_nf_register(&csi->notifier); if (ret) - v4l2_async_nf_cleanup(&csi->notifier); + goto out_nf_cleanup; + + return 0; + +out_nf_cleanup: + v4l2_async_nf_cleanup(&csi->notifier); return ret; } From a6a42fada1e5ee0bcc1ce534ea196625d271dfd8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:27:34 +0300 Subject: [PATCH 1113/7721] media: ivsc: csi: Clean up notifier set-up Use v4l2_async_nf_add_fwnode_remote() to add an async fwnode remote sub-device sub-device to the notifier. This avoids dealing with remote endpoints. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 19f1a47ba52d..f11c7b25491d 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -645,7 +645,6 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) }; struct device *dev = &csi->cldev->dev; struct v4l2_async_connection *asd; - struct fwnode_handle *fwnode; struct fwnode_handle *ep; int ret; @@ -664,15 +663,12 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; - fwnode = fwnode_graph_get_remote_endpoint(ep); - fwnode_handle_put(ep); - v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); csi->notifier.ops = &mei_csi_notify_ops; - asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, - struct v4l2_async_connection); - fwnode_handle_put(fwnode); + asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, + struct v4l2_async_connection); + fwnode_handle_put(ep); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out_nf_cleanup; From 623017a4bb042777edf65bb8ea233ce5f06e0760 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:30:53 +0300 Subject: [PATCH 1114/7721] media: ivsc: csi: Clean up parsing firmware and setting up async notifier Set up async notifier right after obtaining the local endpoint. This makes error handling straightforward. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index f11c7b25491d..41ccc5fbe74a 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -654,21 +654,20 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) return -EINVAL; } + v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); + csi->notifier.ops = &mei_csi_notify_ops; + ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); if (ret) { dev_err(dev, "could not parse v4l2 endpoint\n"); - fwnode_handle_put(ep); - return -EINVAL; + ret = -EINVAL; + goto out_nf_cleanup; } csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; - v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); - csi->notifier.ops = &mei_csi_notify_ops; - asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, struct v4l2_async_connection); - fwnode_handle_put(ep); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out_nf_cleanup; @@ -678,10 +677,13 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) if (ret) goto out_nf_cleanup; + fwnode_handle_put(ep); + return 0; out_nf_cleanup: v4l2_async_nf_cleanup(&csi->notifier); + fwnode_handle_put(ep); return ret; } From 096bc4f14956c9e963419b292fc28f0dd4e52908 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:32:27 +0300 Subject: [PATCH 1115/7721] media: ivsc: csi: Don't mask v4l2_fwnode_endpoint_parse return value v4l2_fwnode_endpoint_parse already returns an error value, don't set return value to -EINVAL. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 41ccc5fbe74a..3f507d0170f9 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -660,7 +660,6 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); if (ret) { dev_err(dev, "could not parse v4l2 endpoint\n"); - ret = -EINVAL; goto out_nf_cleanup; } From 3c9202e88ffad78f57a418bace2d25f7824a7e4b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Oct 2023 10:38:43 +0300 Subject: [PATCH 1116/7721] media: ivsc: csi: Check number of lanes on source, too The IVSC has two CSI-2 ports, one receiver and one transmitter, for passing through the CSI-2 image data. Both have the same number of lanes and this information should be also present in firmware. Check this. Signed-off-by: Sakari Ailus Tested-by: Wentong Wu Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 40 ++++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 3f507d0170f9..2ca52390541d 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -645,27 +645,49 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) }; struct device *dev = &csi->cldev->dev; struct v4l2_async_connection *asd; - struct fwnode_handle *ep; + struct fwnode_handle *sink_ep, *source_ep; int ret; - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); - if (!ep) { - dev_err(dev, "not connected to subdevice\n"); + sink_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + if (!sink_ep) { + dev_err(dev, "can't obtain sink endpoint\n"); return -EINVAL; } v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); csi->notifier.ops = &mei_csi_notify_ops; - ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); + ret = v4l2_fwnode_endpoint_parse(sink_ep, &v4l2_ep); if (ret) { - dev_err(dev, "could not parse v4l2 endpoint\n"); + dev_err(dev, "could not parse v4l2 sink endpoint\n"); goto out_nf_cleanup; } csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; - asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, + source_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 1, 0, 0); + if (!source_ep) { + ret = -ENOTCONN; + dev_err(dev, "can't obtain source endpoint\n"); + goto out_nf_cleanup; + } + + ret = v4l2_fwnode_endpoint_parse(source_ep, &v4l2_ep); + fwnode_handle_put(source_ep); + if (ret) { + dev_err(dev, "could not parse v4l2 source endpoint\n"); + goto out_nf_cleanup; + } + + if (csi->nr_of_lanes != v4l2_ep.bus.mipi_csi2.num_data_lanes) { + ret = -EINVAL; + dev_err(dev, + "the number of lanes does not match (%u vs. %u)\n", + csi->nr_of_lanes, v4l2_ep.bus.mipi_csi2.num_data_lanes); + goto out_nf_cleanup; + } + + asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, sink_ep, struct v4l2_async_connection); if (IS_ERR(asd)) { ret = PTR_ERR(asd); @@ -676,13 +698,13 @@ static int mei_csi_parse_firmware(struct mei_csi *csi) if (ret) goto out_nf_cleanup; - fwnode_handle_put(ep); + fwnode_handle_put(sink_ep); return 0; out_nf_cleanup: v4l2_async_nf_cleanup(&csi->notifier); - fwnode_handle_put(ep); + fwnode_handle_put(sink_ep); return ret; } From 36b20fcdd9663ced36d3aef96f0eff8eb79de4b8 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 21 Nov 2023 11:07:53 +0530 Subject: [PATCH 1117/7721] net: hsr: Add support for MC filtering at the slave device When MC (multicast) list is updated by the networking layer due to a user command and as well as when allmulti flag is set, it needs to be passed to the enslaved Ethernet devices. This patch allows this to happen by implementing ndo_change_rx_flags() and ndo_set_rx_mode() API calls that in turns pass it to the slave devices using existing API calls. Signed-off-by: Murali Karicheri Signed-off-by: Ravi Gunasekaran Reviewed-by: Wojciech Drewek Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 67 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 306f942c3b28..7ceb9ac6e730 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -173,7 +173,24 @@ static int hsr_dev_open(struct net_device *dev) static int hsr_dev_close(struct net_device *dev) { - /* Nothing to do here. */ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + dev_uc_unsync(port->dev, dev); + dev_mc_unsync(port->dev, dev); + break; + default: + break; + } + } + return 0; } @@ -404,12 +421,60 @@ void hsr_del_ports(struct hsr_priv *hsr) hsr_del_port(port); } +static void hsr_set_rx_mode(struct net_device *dev) +{ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + dev_mc_sync_multiple(port->dev, dev); + dev_uc_sync_multiple(port->dev, dev); + break; + default: + break; + } + } +} + +static void hsr_change_rx_flags(struct net_device *dev, int change) +{ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + if (change & IFF_ALLMULTI) + dev_set_allmulti(port->dev, + dev->flags & + IFF_ALLMULTI ? 1 : -1); + break; + default: + break; + } + } +} + static const struct net_device_ops hsr_device_ops = { .ndo_change_mtu = hsr_dev_change_mtu, .ndo_open = hsr_dev_open, .ndo_stop = hsr_dev_close, .ndo_start_xmit = hsr_dev_xmit, + .ndo_change_rx_flags = hsr_change_rx_flags, .ndo_fix_features = hsr_fix_features, + .ndo_set_rx_mode = hsr_set_rx_mode, }; static struct device_type hsr_type = { From 750011e239a50873251c16207b0fe78eabf8577e Mon Sep 17 00:00:00 2001 From: "Gan, Yi Fang" Date: Tue, 21 Nov 2023 13:38:42 +0800 Subject: [PATCH 1118/7721] net: stmmac: Add support for HW-accelerated VLAN stripping Current implementation supports driver level VLAN tag stripping only. The features is always on if CONFIG_VLAN_8021Q is enabled in kernel config and is not user configurable. This patch add support to MAC level VLAN tag stripping and can be configured through ethtool. If the rx-vlan-offload is off, the VLAN tag will be stripped by driver. If the rx-vlan-offload is on, the VLAN tag will be stripped by MAC. Command: ethtool -K rx-vlan-offload off | on Signed-off-by: Lai Peter Jun Ann Signed-off-by: Gan, Yi Fang Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 35 +++++++++++++++++++ .../ethernet/stmicro/stmmac/dwmac4_descs.c | 13 +++++++ drivers/net/ethernet/stmicro/stmmac/hwif.h | 15 ++++++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 28 +++++++++++++-- 5 files changed, 90 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index e3f650e88f82..6b935922054d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -580,6 +580,7 @@ struct mac_device_info { u32 vlan_filter[32]; bool vlan_fail_q_en; u8 vlan_fail_q; + bool hw_vlan_en; }; struct stmmac_rx_routing { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index c6ff1fa0e04d..5f35faf90963 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -1134,6 +1134,35 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, return 0; } +static void dwmac4_rx_hw_vlan(struct mac_device_info *hw, + struct dma_desc *rx_desc, struct sk_buff *skb) +{ + if (hw->desc->get_rx_vlan_valid(rx_desc)) { + u16 vid = hw->desc->get_rx_vlan_tci(rx_desc); + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); + } +} + +static void dwmac4_set_hw_vlan_mode(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value = readl(ioaddr + GMAC_VLAN_TAG); + + value &= ~GMAC_VLAN_TAG_CTRL_EVLS_MASK; + + if (hw->hw_vlan_en) + /* Always strip VLAN on Receive */ + value |= GMAC_VLAN_TAG_STRIP_ALL; + else + /* Do not strip VLAN on Receive */ + value |= GMAC_VLAN_TAG_STRIP_NONE; + + /* Enable outer VLAN Tag in Rx DMA descriptor */ + value |= GMAC_VLAN_TAG_CTRL_EVLRXS; + writel(value, ioaddr + GMAC_VLAN_TAG); +} + const struct stmmac_ops dwmac4_ops = { .core_init = dwmac4_core_init, .phylink_get_caps = dwmac4_phylink_get_caps, @@ -1175,6 +1204,8 @@ const struct stmmac_ops dwmac4_ops = { .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, + .rx_hw_vlan = dwmac4_rx_hw_vlan, + .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; const struct stmmac_ops dwmac410_ops = { @@ -1224,6 +1255,8 @@ const struct stmmac_ops dwmac410_ops = { .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, + .rx_hw_vlan = dwmac4_rx_hw_vlan, + .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; const struct stmmac_ops dwmac510_ops = { @@ -1277,6 +1310,8 @@ const struct stmmac_ops dwmac510_ops = { .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, + .rx_hw_vlan = dwmac4_rx_hw_vlan, + .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; static u32 dwmac4_get_num_vlan(void __iomem *ioaddr) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index 89a14084c611..1c5802e0d7f4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -198,6 +198,17 @@ static int dwmac4_get_tx_ls(struct dma_desc *p) >> TDES3_LAST_DESCRIPTOR_SHIFT; } +static u16 dwmac4_wrback_get_rx_vlan_tci(struct dma_desc *p) +{ + return (le32_to_cpu(p->des0) & RDES0_VLAN_TAG_MASK); +} + +static bool dwmac4_wrback_get_rx_vlan_valid(struct dma_desc *p) +{ + return ((le32_to_cpu(p->des3) & RDES3_LAST_DESCRIPTOR) && + (le32_to_cpu(p->des3) & RDES3_RDES0_VALID)); +} + static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe) { return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK); @@ -551,6 +562,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = { .set_tx_owner = dwmac4_set_tx_owner, .set_rx_owner = dwmac4_set_rx_owner, .get_tx_ls = dwmac4_get_tx_ls, + .get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci, + .get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid, .get_rx_frame_len = dwmac4_wrback_get_rx_frame_len, .enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp, .get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index b95d3e137813..1d424c9bf037 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -56,6 +56,10 @@ struct stmmac_desc_ops { void (*set_tx_ic)(struct dma_desc *p); /* Last tx segment reports the transmit status */ int (*get_tx_ls)(struct dma_desc *p); + /* Get the tag of the descriptor */ + u16 (*get_rx_vlan_tci)(struct dma_desc *p); + /* Get the valid status of descriptor */ + bool (*get_rx_vlan_valid)(struct dma_desc *p); /* Return the transmit status looking at the TDES1 */ int (*tx_status)(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr); @@ -117,6 +121,10 @@ struct stmmac_desc_ops { stmmac_do_void_callback(__priv, desc, set_tx_ic, __args) #define stmmac_get_tx_ls(__priv, __args...) \ stmmac_do_callback(__priv, desc, get_tx_ls, __args) +#define stmmac_get_rx_vlan_tci(__priv, __args...) \ + stmmac_do_callback(__priv, desc, get_rx_vlan_tci, __args) +#define stmmac_get_rx_vlan_valid(__priv, __args...) \ + stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args) #define stmmac_tx_status(__priv, __args...) \ stmmac_do_callback(__priv, desc, tx_status, __args) #define stmmac_get_tx_len(__priv, __args...) \ @@ -388,6 +396,9 @@ struct stmmac_ops { void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, __le16 perfect_match, bool is_double); void (*enable_vlan)(struct mac_device_info *hw, u32 type); + void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc, + struct sk_buff *skb); + void (*set_hw_vlan_mode)(struct mac_device_info *hw); int (*add_hw_vlan_rx_fltr)(struct net_device *dev, struct mac_device_info *hw, __be16 proto, u16 vid); @@ -497,6 +508,10 @@ struct stmmac_ops { stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args) #define stmmac_enable_vlan(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, enable_vlan, __args) +#define stmmac_rx_hw_vlan(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args) +#define stmmac_set_hw_vlan_mode(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args) #define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \ stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args) #define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 97598c1497ea..8964fc8a955f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3469,6 +3469,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) /* Start the ball rolling... */ stmmac_start_all_dma(priv); + stmmac_set_hw_vlan_mode(priv, priv->hw); + if (priv->dma_cap.fpesel) { stmmac_fpe_start_wq(priv); @@ -4993,7 +4995,12 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, } stmmac_get_rx_hwtstamp(priv, p, np, skb); - stmmac_rx_vlan(priv->dev, skb); + if (priv->hw->hw_vlan_en) + /* MAC level stripping. */ + stmmac_rx_hw_vlan(priv, priv->hw, p, skb); + else + /* Driver level stripping. */ + stmmac_rx_vlan(priv->dev, skb); skb->protocol = eth_type_trans(skb, priv->dev); if (unlikely(!coe)) @@ -5509,7 +5516,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) /* Got entire packet into SKB. Finish it. */ stmmac_get_rx_hwtstamp(priv, p, np, skb); - stmmac_rx_vlan(priv->dev, skb); + + if (priv->hw->hw_vlan_en) + /* MAC level stripping. */ + stmmac_rx_hw_vlan(priv, priv->hw, p, skb); + else + /* Driver level stripping. */ + stmmac_rx_vlan(priv->dev, skb); + skb->protocol = eth_type_trans(skb, priv->dev); if (unlikely(!coe)) @@ -5818,6 +5832,13 @@ static int stmmac_set_features(struct net_device *netdev, stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan); } + if (features & NETIF_F_HW_VLAN_CTAG_RX) + priv->hw->hw_vlan_en = true; + else + priv->hw->hw_vlan_en = false; + + stmmac_set_hw_vlan_mode(priv, priv->hw); + return 0; } @@ -7509,6 +7530,9 @@ int stmmac_dvr_probe(struct device *device, #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; + ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; + priv->hw->hw_vlan_en = true; + if (priv->dma_cap.vlhash) { ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER; From 9996cd782a602f2542e110e2a4035dd6627bd520 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 22 Nov 2023 18:19:59 +0800 Subject: [PATCH 1119/7721] ASoC: dt-bindings: fsl,mqs: Convert format to json-schema Convert NXP medium quality sound (MQS) device tree binding documentation to json-schema. Signed-off-by: Chancel Liu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20231122101959.30264-4-chancel.liu@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,mqs.txt | 36 ------ .../devicetree/bindings/sound/fsl,mqs.yaml | 105 ++++++++++++++++++ 2 files changed, 105 insertions(+), 36 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/fsl,mqs.txt create mode 100644 Documentation/devicetree/bindings/sound/fsl,mqs.yaml diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.txt b/Documentation/devicetree/bindings/sound/fsl,mqs.txt deleted file mode 100644 index d66284b8bef2..000000000000 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.txt +++ /dev/null @@ -1,36 +0,0 @@ -fsl,mqs audio CODEC - -Required properties: - - compatible : Must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs" - "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs", "fsl,imx93-mqs". - - clocks : A list of phandles + clock-specifiers, one for each entry in - clock-names - - clock-names : "mclk" - must required. - "core" - required if compatible is "fsl,imx8qm-mqs", it - is for register access. - - gpr : A phandle of General Purpose Registers in IOMUX Controller. - Required if compatible is "fsl,imx6sx-mqs". - -Required if compatible is "fsl,imx8qm-mqs": - - power-domains: A phandle of PM domain provider node. - - reg: Offset and length of the register set for the device. - -Example: - -mqs: mqs { - compatible = "fsl,imx6sx-mqs"; - gpr = <&gpr>; - clocks = <&clks IMX6SX_CLK_SAI1>; - clock-names = "mclk"; - status = "disabled"; -}; - -mqs: mqs@59850000 { - compatible = "fsl,imx8qm-mqs"; - reg = <0x59850000 0x10000>; - clocks = <&clk IMX8QM_AUD_MQS_IPG>, - <&clk IMX8QM_AUD_MQS_HMCLK>; - clock-names = "core", "mclk"; - power-domains = <&pd_mqs0>; - status = "disabled"; -}; diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml new file mode 100644 index 000000000000..8b33353a80ca --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,mqs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP Medium Quality Sound (MQS) + +maintainers: + - Shengjiu Wang + - Chancel Liu + +description: | + Medium quality sound (MQS) is used to generate medium quality audio + via a standard GPIO in the pinmux, allowing the user to connect + stereo speakers or headphones to a power amplifier without an + additional DAC chip. + +properties: + compatible: + enum: + - fsl,imx6sx-mqs + - fsl,imx8qm-mqs + - fsl,imx8qxp-mqs + - fsl,imx93-mqs + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + gpr: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle to the General Purpose Register (GPR) node + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8qm-mqs + - fsl,imx8qxp-mqs + then: + properties: + clocks: + items: + - description: Master clock + - description: Clock for register access + clock-names: + items: + - const: mclk + - const: core + required: + - reg + - power-domains + else: + properties: + clocks: + items: + - description: Master clock + clock-names: + items: + - const: mclk + required: + - gpr + +additionalProperties: false + +examples: + - | + #include + mqs0: mqs { + compatible = "fsl,imx6sx-mqs"; + gpr = <&gpr>; + clocks = <&clks IMX6SX_CLK_SAI1>; + clock-names = "mclk"; + }; + + - | + #include + mqs1: mqs@59850000 { + compatible = "fsl,imx8qm-mqs"; + reg = <0x59850000 0x10000>; + clocks = <&mqs0_lpcg 0>, <&mqs0_lpcg 1>; + clock-names = "mclk", "core"; + power-domains = <&pd IMX_SC_R_MQS_0>; + }; From e76f514dc9fdacf8522e6efcabf883514e5299e5 Mon Sep 17 00:00:00 2001 From: Supriti Singh Date: Mon, 20 Nov 2023 16:41:45 +0100 Subject: [PATCH 1120/7721] RDMA/rtrs-clt: Use %pe to print errors While printing error, replace %ld by %pe. %pe prints a string whereas %ld would print an error code. Signed-off-by: Supriti Singh Signed-off-by: Jack Wang Signed-off-by: Grzegorz Prajsner Signed-off-by: Md Haris Iqbal Link: https://lore.kernel.org/r/20231120154146.920486-9-haris.iqbal@ionos.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 984a4a1db3c8..f7a5ec396554 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1391,9 +1391,9 @@ static int alloc_path_reqs(struct rtrs_clt_path *clt_path) clt_path->max_pages_per_mr); if (IS_ERR(req->mr)) { err = PTR_ERR(req->mr); + pr_err("Failed to alloc clt_path->max_pages_per_mr %d: %pe\n", + clt_path->max_pages_per_mr, req->mr); req->mr = NULL; - pr_err("Failed to alloc clt_path->max_pages_per_mr %d\n", - clt_path->max_pages_per_mr); goto out; } @@ -2060,10 +2060,8 @@ static int create_cm(struct rtrs_clt_con *con) clt_path->s.dst_addr.ss_family == AF_IB ? RDMA_PS_IB : RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(cm_id)) { - err = PTR_ERR(cm_id); - rtrs_err(s, "Failed to create CM ID, err: %d\n", err); - - return err; + rtrs_err(s, "Failed to create CM ID, err: %pe\n", cm_id); + return PTR_ERR(cm_id); } con->c.cm_id = cm_id; con->cm_err = 0; From 640233258e5b61fed10b382af691b6a852f00392 Mon Sep 17 00:00:00 2001 From: Supriti Singh Date: Mon, 20 Nov 2023 16:41:46 +0100 Subject: [PATCH 1121/7721] RDMA/rtrs: Use %pe to print errors While printing error, replace %ld by %pe. %pe prints a string whereas %ld would print an error code. Signed-off-by: Supriti Singh Signed-off-by: Jack Wang Signed-off-by: Grzegorz Prajsner Signed-off-by: Md Haris Iqbal Link: https://lore.kernel.org/r/20231120154146.920486-10-haris.iqbal@ionos.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/rtrs/rtrs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/rtrs/rtrs.c b/drivers/infiniband/ulp/rtrs/rtrs.c index d80edfffd2e4..4e17d546d4cc 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs.c +++ b/drivers/infiniband/ulp/rtrs/rtrs.c @@ -242,8 +242,8 @@ static int create_cq(struct rtrs_con *con, int cq_vector, int nr_cqe, cq = ib_cq_pool_get(cm_id->device, nr_cqe, cq_vector, poll_ctx); if (IS_ERR(cq)) { - rtrs_err(con->path, "Creating completion queue failed, errno: %ld\n", - PTR_ERR(cq)); + rtrs_err(con->path, "Creating completion queue failed, errno: %pe\n", + cq); return PTR_ERR(cq); } con->cq = cq; From 971f128bb2d9314203d365b7f163a5c35167bb6b Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Thu, 12 Oct 2023 10:22:09 +0100 Subject: [PATCH 1122/7721] soc: sifive: shunt ccache driver to drivers/cache Move the ccache driver over to drivers/cache, out of the drivers/soc dumping ground, to this new collection point for cache controller drivers. Reviewed-by: Samuel Holland Tested-by: Samuel Holland Signed-off-by: Conor Dooley --- MAINTAINERS | 14 +++++++------- drivers/cache/Kconfig | 6 ++++++ drivers/cache/Makefile | 3 ++- drivers/{soc/sifive => cache}/sifive_ccache.c | 0 drivers/soc/Kconfig | 1 - drivers/soc/Makefile | 1 - drivers/soc/sifive/Kconfig | 10 ---------- drivers/soc/sifive/Makefile | 3 --- 8 files changed, 15 insertions(+), 23 deletions(-) rename drivers/{soc/sifive => cache}/sifive_ccache.c (100%) delete mode 100644 drivers/soc/sifive/Kconfig delete mode 100644 drivers/soc/sifive/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..3135ec3de6ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19785,6 +19785,13 @@ S: Supported N: sifive K: [^@]sifive +SIFIVE CACHE DRIVER +M: Conor Dooley +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml +F: drivers/cache/sifive_ccache.c + SIFIVE FU540 SYSTEM-ON-CHIP M: Paul Walmsley M: Palmer Dabbelt @@ -19800,13 +19807,6 @@ S: Maintained F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml F: drivers/dma/sf-pdma/ -SIFIVE SOC DRIVERS -M: Conor Dooley -L: linux-riscv@lists.infradead.org -S: Maintained -T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ -F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml -F: drivers/soc/sifive/ SILEAD TOUCHSCREEN DRIVER M: Hans de Goede diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index d6e5e3abaad8..9345ce4976d7 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -8,4 +8,10 @@ config AX45MP_L2_CACHE help Support for the L2 cache controller on Andes Technology AX45MP platforms. +config SIFIVE_CCACHE + bool "Sifive Composable Cache controller" + depends on ARCH_SIFIVE || ARCH_STARFIVE + help + Support for the composable cache controller on SiFive platforms. + endmenu diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 2012e7fb978d..7657cff3bd6c 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o +obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o +obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o diff --git a/drivers/soc/sifive/sifive_ccache.c b/drivers/cache/sifive_ccache.c similarity index 100% rename from drivers/soc/sifive/sifive_ccache.c rename to drivers/cache/sifive_ccache.c diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 10a9ff84ff41..5d924e946507 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -22,7 +22,6 @@ source "drivers/soc/qcom/Kconfig" source "drivers/soc/renesas/Kconfig" source "drivers/soc/rockchip/Kconfig" source "drivers/soc/samsung/Kconfig" -source "drivers/soc/sifive/Kconfig" source "drivers/soc/sunxi/Kconfig" source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 0706a27d13be..ba8f5b5460e1 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -28,7 +28,6 @@ obj-y += qcom/ obj-y += renesas/ obj-y += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ -obj-y += sifive/ obj-y += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig deleted file mode 100644 index 139884addc41..000000000000 --- a/drivers/soc/sifive/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -if ARCH_SIFIVE || ARCH_STARFIVE - -config SIFIVE_CCACHE - bool "Sifive Composable Cache controller" - help - Support for the composable cache controller on SiFive platforms. - -endif diff --git a/drivers/soc/sifive/Makefile b/drivers/soc/sifive/Makefile deleted file mode 100644 index 1f5dc339bf82..000000000000 --- a/drivers/soc/sifive/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o From 3d70b9853b44d3f034acaf5e3be7d5228daddef4 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Tue, 31 Oct 2023 15:14:43 +0100 Subject: [PATCH 1123/7721] dt-bindings: cache: sifive,ccache0: Add StarFive JH7100 compatible This cache controller is also used on the StarFive JH7100 SoC. Unfortunately it needs a quirk to work properly, so add dedicated compatible string to be able to match it. Signed-off-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- Documentation/devicetree/bindings/cache/sifive,ccache0.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml b/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml index 8a6a78e1a7ab..7e8cebe21584 100644 --- a/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml +++ b/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml @@ -38,7 +38,9 @@ properties: - sifive,fu740-c000-ccache - const: cache - items: - - const: starfive,jh7110-ccache + - enum: + - starfive,jh7100-ccache + - starfive,jh7110-ccache - const: sifive,ccache0 - const: cache - items: @@ -88,6 +90,7 @@ allOf: contains: enum: - sifive,fu740-c000-ccache + - starfive,jh7100-ccache - starfive,jh7110-ccache - microchip,mpfs-ccache @@ -111,6 +114,7 @@ allOf: contains: enum: - sifive,fu740-c000-ccache + - starfive,jh7100-ccache - starfive,jh7110-ccache then: From 0d5701dc9cd653ae757cc06e39b3a39272863395 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Tue, 31 Oct 2023 15:14:44 +0100 Subject: [PATCH 1124/7721] soc: sifive: ccache: Add StarFive JH7100 support This adds support for the StarFive JH7100 SoC which also features this SiFive cache controller. The JH7100 has non-coherent DMAs but predate the standard RISC-V Zicbom exension, so instead we need to use this cache controller for non-standard cache management operations. Unfortunately the interrupt for uncorrected data is broken on the JH7100 and fires continuously, so add a quirk to not register a handler for it. Signed-off-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- drivers/cache/sifive_ccache.c | 62 +++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/cache/sifive_ccache.c b/drivers/cache/sifive_ccache.c index 3684f5b40a80..89ed6cd6b059 100644 --- a/drivers/cache/sifive_ccache.c +++ b/drivers/cache/sifive_ccache.c @@ -8,13 +8,16 @@ #define pr_fmt(fmt) "CCACHE: " fmt +#include #include #include #include #include #include #include +#include #include +#include #include #define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100 @@ -39,10 +42,14 @@ #define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16) #define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24) +#define SIFIVE_CCACHE_FLUSH64 0x200 +#define SIFIVE_CCACHE_FLUSH32 0x240 + #define SIFIVE_CCACHE_WAYENABLE 0x08 #define SIFIVE_CCACHE_ECCINJECTERR 0x40 #define SIFIVE_CCACHE_MAX_ECCINTR 4 +#define SIFIVE_CCACHE_LINE_SIZE 64 static void __iomem *ccache_base; static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR]; @@ -56,6 +63,11 @@ enum { DIR_UNCORR, }; +enum { + QUIRK_NONSTANDARD_CACHE_OPS = BIT(0), + QUIRK_BROKEN_DATA_UNCORR = BIT(1), +}; + #ifdef CONFIG_DEBUG_FS static struct dentry *sifive_test; @@ -106,6 +118,8 @@ static void ccache_config_read(void) static const struct of_device_id sifive_ccache_ids[] = { { .compatible = "sifive,fu540-c000-ccache" }, { .compatible = "sifive,fu740-c000-ccache" }, + { .compatible = "starfive,jh7100-ccache", + .data = (void *)(QUIRK_NONSTANDARD_CACHE_OPS | QUIRK_BROKEN_DATA_UNCORR) }, { .compatible = "sifive,ccache0" }, { /* end of table */ } }; @@ -124,6 +138,34 @@ int unregister_sifive_ccache_error_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier); +#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS +static void ccache_flush_range(phys_addr_t start, size_t len) +{ + phys_addr_t end = start + len; + phys_addr_t line; + + if (!len) + return; + + mb(); + for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end; + line += SIFIVE_CCACHE_LINE_SIZE) { +#ifdef CONFIG_32BIT + writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32); +#else + writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64); +#endif + mb(); + } +} + +static const struct riscv_nonstd_cache_ops ccache_mgmt_ops __initconst = { + .wback = &ccache_flush_range, + .inv = &ccache_flush_range, + .wback_inv = &ccache_flush_range, +}; +#endif /* CONFIG_RISCV_NONSTANDARD_CACHE_OPS */ + static int ccache_largest_wayenabled(void) { return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF; @@ -210,11 +252,15 @@ static int __init sifive_ccache_init(void) struct device_node *np; struct resource res; int i, rc, intr_num; + const struct of_device_id *match; + unsigned long quirks; - np = of_find_matching_node(NULL, sifive_ccache_ids); + np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match); if (!np) return -ENODEV; + quirks = (uintptr_t)match->data; + if (of_address_to_resource(np, 0, &res)) { rc = -ENODEV; goto err_node_put; @@ -240,6 +286,10 @@ static int __init sifive_ccache_init(void) for (i = 0; i < intr_num; i++) { g_irq[i] = irq_of_parse_and_map(np, i); + + if (i == DATA_UNCORR && (quirks & QUIRK_BROKEN_DATA_UNCORR)) + continue; + rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc", NULL); if (rc) { @@ -249,6 +299,14 @@ static int __init sifive_ccache_init(void) } of_node_put(np); +#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS + if (quirks & QUIRK_NONSTANDARD_CACHE_OPS) { + riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE; + riscv_noncoherent_supported(); + riscv_noncoherent_register_cache_ops(&ccache_mgmt_ops); + } +#endif + ccache_config_read(); ccache_cache_ops.get_priv_group = ccache_get_priv_group; @@ -269,4 +327,4 @@ static int __init sifive_ccache_init(void) return rc; } -device_initcall(sifive_ccache_init); +arch_initcall(sifive_ccache_init); From d12292fdea21f9f4ae5865fd41b730c5e32d45a9 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Wed, 19 Jan 2022 23:44:32 +0100 Subject: [PATCH 1125/7721] s390/sysinfo: add variable capacity information If available, add machine variable capacity information to /proc/sysinfo Acked-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Alexander Gordeev --- arch/s390/include/asm/sysinfo.h | 4 ++++ arch/s390/kernel/sysinfo.c | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index ab1c6316055c..edca5a751df4 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -40,6 +40,10 @@ struct sysinfo_1_1_1 { unsigned int ncr; unsigned int npr; unsigned int ntr; + char reserved_3[4]; + char model_var_cap[16]; + unsigned int model_var_cap_rating; + unsigned int nvr; }; struct sysinfo_1_2_1 { diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index b5e364358ce4..f6f8f498c9be 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -81,10 +81,12 @@ static bool convert_ext_name(unsigned char encoding, char *name, size_t len) static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) { + bool has_var_cap; int i; if (stsi(info, 1, 1, 1)) return; + has_var_cap = !!info->model_var_cap[0]; EBCASC(info->manufacturer, sizeof(info->manufacturer)); EBCASC(info->type, sizeof(info->type)); EBCASC(info->model, sizeof(info->model)); @@ -93,6 +95,8 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) EBCASC(info->model_capacity, sizeof(info->model_capacity)); EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); + if (has_var_cap) + EBCASC(info->model_var_cap, sizeof(info->model_var_cap)); seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer); seq_printf(m, "Type: %-4.4s\n", info->type); if (info->lic) @@ -120,12 +124,18 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n", info->model_temp_cap, info->model_temp_cap_rating); + if (has_var_cap && info->model_var_cap_rating) + seq_printf(m, "Model Var. Capacity: %-16.16s %08u\n", + info->model_var_cap, + info->model_var_cap_rating); if (info->ncr) seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr); if (info->npr) seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr); if (info->ntr) seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr); + if (has_var_cap && info->nvr) + seq_printf(m, "Nominal Var. Rating: %08u\n", info->nvr); if (info->cai) { seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai); seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr); From 65f8780e2d70257200547b5a7654974aa7c37ce1 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 16 Jul 2023 10:56:00 +0200 Subject: [PATCH 1126/7721] s390/boot: always align vmalloc area on segment boundary The size of vmalloc area depends from various factors on boot and could be set to: 1. Default size as determined by VMALLOC_DEFAULT_SIZE macro; 2. One half of the virtual address space not occupied by modules and fixed mappings; 3. The size provided by user with vmalloc= kernel command line parameter; In cases [1] and [2] the vmalloc area base address is aligned on Region3 table type boundary, while in case [3] in might get aligned on page boundary. Limit the waste of page tables and always align vmalloc area size and base address on segment boundary. Acked-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- arch/s390/boot/ipl_parm.c | 2 +- arch/s390/boot/startup.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 2ab4872fbee1..b24de9aabf7d 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -274,7 +274,7 @@ void parse_boot_command_line(void) memory_limit = round_down(memparse(val, NULL), PAGE_SIZE); if (!strcmp(param, "vmalloc") && val) { - vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); + vmalloc_size = round_up(memparse(val, NULL), _SEGMENT_SIZE); vmalloc_size_set = 1; } diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 8104e0e3d188..9cc76e631759 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -255,7 +255,8 @@ static unsigned long setup_kernel_memory_layout(void) VMALLOC_END = MODULES_VADDR; /* allow vmalloc area to occupy up to about 1/2 of the rest virtual space left */ - vmalloc_size = min(vmalloc_size, round_down(VMALLOC_END / 2, _REGION3_SIZE)); + vsize = round_down(VMALLOC_END / 2, _SEGMENT_SIZE); + vmalloc_size = min(vmalloc_size, vsize); VMALLOC_START = VMALLOC_END - vmalloc_size; /* split remaining virtual space between 1:1 mapping & vmemmap array */ From b1cea462a79316bd619173f1ded8b28202b5ce3a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 22 Nov 2023 17:27:11 +1100 Subject: [PATCH 1127/7721] ASoC: fsl: mpc8610_hpcd: Remove unused driver The mpc8610_hpcd.c driver depends on CONFIG_MPC8610_HPCD which was removed in commit 248667f8bbde ("powerpc: drop HPCD/MPC8610 evaluation platform support"). That makes the driver unbuildable and unusable, so remove it. Depends-on: 248667f8bbde ("powerpc: drop HPCD/MPC8610 evaluation platform support") Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20231122062712.2250426-1-mpe@ellerman.id.au Signed-off-by: Mark Brown --- MAINTAINERS | 1 - sound/soc/fsl/Kconfig | 13 - sound/soc/fsl/Makefile | 4 - sound/soc/fsl/mpc8610_hpcd.c | 451 ----------------------------------- 4 files changed, 469 deletions(-) delete mode 100644 sound/soc/fsl/mpc8610_hpcd.c diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..3943ad3ca346 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8581,7 +8581,6 @@ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: sound/soc/fsl/fsl* F: sound/soc/fsl/imx* -F: sound/soc/fsl/mpc8610_hpcd.c FREESCALE SOC SOUND QMC DRIVER M: Herve Codina diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 725c530a3636..bec2aa561930 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -183,19 +183,6 @@ config SND_SOC_POWERPC_QMC_AUDIO comment "SoC Audio support for Freescale PPC boards:" -config SND_SOC_MPC8610_HPCD - tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" - # I2C is necessary for the CS4270 driver - depends on MPC8610_HPCD && I2C - select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_POWERPC_DMA - select SND_SOC_CS4270 - select SND_SOC_CS4270_VD33_ERRATA - default y if MPC8610_HPCD - help - Say Y if you want to enable audio on the Freescale MPC8610 HPCD. - config SND_SOC_P1022_DS tristate "ALSA SoC support for the Freescale P1022 DS board" # I2C is necessary for the WM8776 driver diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8db7e97d0bd5..b45eda80c196 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -1,8 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# MPC8610 HPCD Machine Support -snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o -obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o - # P1022 DS Machine Support snd-soc-p1022-ds-objs := p1022_ds.o obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c deleted file mode 100644 index 52fb9e7bcca4..000000000000 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ /dev/null @@ -1,451 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Freescale MPC8610HPCD ALSA SoC Machine driver -// -// Author: Timur Tabi -// -// Copyright 2007-2010 Freescale Semiconductor, Inc. - -#include -#include -#include -#include -#include -#include -#include - -#include "fsl_dma.h" -#include "fsl_ssi.h" -#include "fsl_utils.h" - -/* There's only one global utilities register */ -static phys_addr_t guts_phys; - -/** - * mpc8610_hpcd_data: machine-specific ASoC device data - * - * This structure contains data for a single sound platform device on an - * MPC8610 HPCD. Some of the data is taken from the device tree. - */ -struct mpc8610_hpcd_data { - struct snd_soc_dai_link dai[2]; - struct snd_soc_card card; - unsigned int dai_format; - unsigned int codec_clk_direction; - unsigned int cpu_clk_direction; - unsigned int clk_frequency; - unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */ - unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ - unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ - char codec_dai_name[DAI_NAME_SIZE]; - char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ -}; - -/** - * mpc8610_hpcd_machine_probe: initialize the board - * - * This function is used to initialize the board-specific hardware. - * - * Here we program the DMACR and PMUXCR registers. - */ -static int mpc8610_hpcd_machine_probe(struct snd_soc_card *card) -{ - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); - if (!guts) { - dev_err(card->dev, "could not map global utilities\n"); - return -ENOMEM; - } - - /* Program the signal routing between the SSI and the DMA */ - guts_set_dmacr(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], - CCSR_GUTS_DMACR_DEV_SSI); - guts_set_dmacr(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], - CCSR_GUTS_DMACR_DEV_SSI); - - guts_set_pmuxcr_dma(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], 0); - guts_set_pmuxcr_dma(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], 0); - - switch (machine_data->ssi_id) { - case 0: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI); - break; - case 1: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI); - break; - } - - iounmap(guts); - - return 0; -} - -/** - * mpc8610_hpcd_startup: program the board with various hardware parameters - * - * This function takes board-specific information, like clock frequencies - * and serial data formats, and passes that information to the codec and - * transport drivers. - */ -static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct mpc8610_hpcd_data *machine_data = - container_of(rtd->card, struct mpc8610_hpcd_data, card); - struct device *dev = rtd->card->dev; - int ret = 0; - - /* Tell the codec driver what the serial protocol is. */ - ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), machine_data->dai_format); - if (ret < 0) { - dev_err(dev, "could not set codec driver audio format\n"); - return ret; - } - - /* - * Tell the codec driver what the MCLK frequency is, and whether it's - * a slave or master. - */ - ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, - machine_data->clk_frequency, - machine_data->codec_clk_direction); - if (ret < 0) { - dev_err(dev, "could not set codec driver clock params\n"); - return ret; - } - - return 0; -} - -/** - * mpc8610_hpcd_machine_remove: Remove the sound device - * - * This function is called to remove the sound device for one SSI. We - * de-program the DMACR and PMUXCR register. - */ -static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card) -{ - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); - if (!guts) { - dev_err(card->dev, "could not map global utilities\n"); - return -ENOMEM; - } - - /* Restore the signal routing */ - - guts_set_dmacr(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], 0); - guts_set_dmacr(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], 0); - - switch (machine_data->ssi_id) { - case 0: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); - break; - case 1: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); - break; - } - - iounmap(guts); - - return 0; -} - -/** - * mpc8610_hpcd_ops: ASoC machine driver operations - */ -static const struct snd_soc_ops mpc8610_hpcd_ops = { - .startup = mpc8610_hpcd_startup, -}; - -/** - * mpc8610_hpcd_probe: platform probe function for the machine driver - * - * Although this is a machine driver, the SSI node is the "master" node with - * respect to audio hardware connections. Therefore, we create a new ASoC - * device for each new SSI node that has a codec attached. - */ -static int mpc8610_hpcd_probe(struct platform_device *pdev) -{ - struct device *dev = pdev->dev.parent; - /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = to_platform_device(dev); - struct device_node *np = ssi_pdev->dev.of_node; - struct device_node *codec_np = NULL; - struct mpc8610_hpcd_data *machine_data; - struct snd_soc_dai_link_component *comp; - int ret; - const char *sprop; - const u32 *iprop; - - /* Find the codec node for this SSI. */ - codec_np = of_parse_phandle(np, "codec-handle", 0); - if (!codec_np) { - dev_err(dev, "invalid codec node\n"); - return -EINVAL; - } - - machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); - if (!machine_data) { - ret = -ENOMEM; - goto error_alloc; - } - - comp = devm_kzalloc(&pdev->dev, 6 * sizeof(*comp), GFP_KERNEL); - if (!comp) { - ret = -ENOMEM; - goto error_alloc; - } - - machine_data->dai[0].cpus = &comp[0]; - machine_data->dai[0].codecs = &comp[1]; - machine_data->dai[0].platforms = &comp[2]; - - machine_data->dai[0].num_cpus = 1; - machine_data->dai[0].num_codecs = 1; - machine_data->dai[0].num_platforms = 1; - - machine_data->dai[1].cpus = &comp[3]; - machine_data->dai[1].codecs = &comp[4]; - machine_data->dai[1].platforms = &comp[5]; - - machine_data->dai[1].num_cpus = 1; - machine_data->dai[1].num_codecs = 1; - machine_data->dai[1].num_platforms = 1; - - machine_data->dai[0].cpus->dai_name = dev_name(&ssi_pdev->dev); - machine_data->dai[0].ops = &mpc8610_hpcd_ops; - - /* ASoC core can match codec with device node */ - machine_data->dai[0].codecs->of_node = codec_np; - - /* The DAI name from the codec (snd_soc_dai_driver.name) */ - machine_data->dai[0].codecs->dai_name = "cs4270-hifi"; - - /* We register two DAIs per SSI, one for playback and the other for - * capture. Currently, we only support codecs that have one DAI for - * both playback and capture. - */ - memcpy(&machine_data->dai[1], &machine_data->dai[0], - sizeof(struct snd_soc_dai_link)); - - /* Get the device ID */ - iprop = of_get_property(np, "cell-index", NULL); - if (!iprop) { - dev_err(&pdev->dev, "cell-index property not found\n"); - ret = -EINVAL; - goto error; - } - machine_data->ssi_id = be32_to_cpup(iprop); - - /* Get the serial format and clock direction. */ - sprop = of_get_property(np, "fsl,mode", NULL); - if (!sprop) { - dev_err(&pdev->dev, "fsl,mode property not found\n"); - ret = -EINVAL; - goto error; - } - - if (strcasecmp(sprop, "i2s-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - - /* In i2s-slave mode, the codec has its own clock source, so we - * need to get the frequency from the device tree and pass it to - * the codec driver. - */ - iprop = of_get_property(codec_np, "clock-frequency", NULL); - if (!iprop || !*iprop) { - dev_err(&pdev->dev, "codec bus-frequency " - "property is missing or invalid\n"); - ret = -EINVAL; - goto error; - } - machine_data->clk_frequency = be32_to_cpup(iprop); - } else if (strcasecmp(sprop, "i2s-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "lj-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "lj-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "rj-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "rj-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "ac97-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "ac97-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else { - dev_err(&pdev->dev, - "unrecognized fsl,mode property '%s'\n", sprop); - ret = -EINVAL; - goto error; - } - - if (!machine_data->clk_frequency) { - dev_err(&pdev->dev, "unknown clock frequency\n"); - ret = -EINVAL; - goto error; - } - - /* Find the playback DMA channel to use. */ - machine_data->dai[0].platforms->name = machine_data->platform_name[0]; - ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", - &machine_data->dai[0], - &machine_data->dma_channel_id[0], - &machine_data->dma_id[0]); - if (ret) { - dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); - goto error; - } - - /* Find the capture DMA channel to use. */ - machine_data->dai[1].platforms->name = machine_data->platform_name[1]; - ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", - &machine_data->dai[1], - &machine_data->dma_channel_id[1], - &machine_data->dma_id[1]); - if (ret) { - dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); - goto error; - } - - /* Initialize our DAI data structure. */ - machine_data->dai[0].stream_name = "playback"; - machine_data->dai[1].stream_name = "capture"; - machine_data->dai[0].name = machine_data->dai[0].stream_name; - machine_data->dai[1].name = machine_data->dai[1].stream_name; - - machine_data->card.probe = mpc8610_hpcd_machine_probe; - machine_data->card.remove = mpc8610_hpcd_machine_remove; - machine_data->card.name = pdev->name; /* The platform driver name */ - machine_data->card.owner = THIS_MODULE; - machine_data->card.dev = &pdev->dev; - machine_data->card.num_links = 2; - machine_data->card.dai_link = machine_data->dai; - - /* Register with ASoC */ - ret = snd_soc_register_card(&machine_data->card); - if (ret) { - dev_err(&pdev->dev, "could not register card\n"); - goto error; - } - - of_node_put(codec_np); - - return 0; - -error: - kfree(machine_data); -error_alloc: - of_node_put(codec_np); - return ret; -} - -/** - * mpc8610_hpcd_remove: remove the platform device - * - * This function is called when the platform device is removed. - */ -static void mpc8610_hpcd_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - - snd_soc_unregister_card(card); - kfree(machine_data); -} - -static struct platform_driver mpc8610_hpcd_driver = { - .probe = mpc8610_hpcd_probe, - .remove_new = mpc8610_hpcd_remove, - .driver = { - /* The name must match 'compatible' property in the device tree, - * in lowercase letters. - */ - .name = "snd-soc-mpc8610hpcd", - }, -}; - -/** - * mpc8610_hpcd_init: machine driver initialization. - * - * This function is called when this module is loaded. - */ -static int __init mpc8610_hpcd_init(void) -{ - struct device_node *guts_np; - struct resource res; - - pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n"); - - /* Get the physical address of the global utilities registers */ - guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); - if (of_address_to_resource(guts_np, 0, &res)) { - pr_err("mpc8610-hpcd: missing/invalid global utilities node\n"); - of_node_put(guts_np); - return -EINVAL; - } - guts_phys = res.start; - of_node_put(guts_np); - - return platform_driver_register(&mpc8610_hpcd_driver); -} - -/** - * mpc8610_hpcd_exit: machine driver exit - * - * This function is called when this driver is unloaded. - */ -static void __exit mpc8610_hpcd_exit(void) -{ - platform_driver_unregister(&mpc8610_hpcd_driver); -} - -module_init(mpc8610_hpcd_init); -module_exit(mpc8610_hpcd_exit); - -MODULE_AUTHOR("Timur Tabi "); -MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver"); -MODULE_LICENSE("GPL v2"); From 2c4e9acbe3a50ab4a1a2fb5eb8258befda1764cb Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 13 Nov 2023 17:47:30 +0300 Subject: [PATCH 1128/7721] wifi: rtlwifi: simplify rtl_action_proc() and rtl_tx_agg_start() Since 'drv_priv' is an in-place member allocated at the end of 'struct ieee80211_sta', it can't be NULL and so relevant checks in 'rtl_action_proc()' and 'rtl_tx_agg_start()' may be dropped. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231113144734.197359-2-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/base.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 7ce37fb4fdbf..1a8d715b7c07 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1402,10 +1402,6 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) { - rcu_read_unlock(); - return true; - } capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & @@ -1760,8 +1756,6 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG, @@ -1818,8 +1812,6 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, } sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_RECV, DBG_DMESG, From 665ecff7dd1481c97d36d7761c0eab3b1dde3d22 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 14 Nov 2023 17:13:57 +0800 Subject: [PATCH 1129/7721] wifi: rtw89: acpi: process 6 GHz band policy from DSM Realtek ACPI DSM func 4, RTW89_ACPI_DSM_FUNC_6G_BP, accepts a configuration via ACPI buffer as below. | index | description | ------------------------- | [0-2] | signature | | [3] | reserved | | [4] | policy mode | | [5] | country count | | [6-] | country list | Through this function, BIOS can indicate to allow/block 6 GHz on some specific countries. Still, driver should follow regd first before taking this configuration into account. Besides, add a bit in debug mask for ACPI. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231114091359.50664-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 81 ++++++++++++++++++---- drivers/net/wireless/realtek/rtw89/acpi.h | 32 ++++++++- drivers/net/wireless/realtek/rtw89/debug.h | 1 + drivers/net/wireless/realtek/rtw89/regd.c | 10 ++- drivers/net/wireless/realtek/rtw89/sar.c | 4 +- 5 files changed, 109 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 8aaf83a2a6b4..2e7326a8e3e4 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -12,27 +12,74 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, 0x82, 0xBD, 0xFE, 0x86, 0x07, 0x80, 0x3A, 0xA7); -static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj, - u8 *value) +static +int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj, + u8 *value) { - switch (obj->type) { - case ACPI_TYPE_INTEGER: - *value = (u8)obj->integer.value; - break; - case ACPI_TYPE_BUFFER: - *value = obj->buffer.pointer[0]; - break; - default: - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, - "acpi dsm return unhandled type: %d\n", obj->type); + if (obj->type != ACPI_TYPE_INTEGER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect integer but type: %d\n", obj->type); return -EINVAL; } + *value = (u8)obj->integer.value; + return 0; +} + +static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p) +{ + return p->signature[0] == 0x00 && + p->signature[1] == 0xE0 && + p->signature[2] == 0x4C; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz **policy_6ghz) +{ + const struct rtw89_acpi_policy_6ghz *ptr; + u32 expect_len; + u32 len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + len = obj->buffer.length; + if (len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + expect_len = struct_size(ptr, country_list, ptr->country_count); + if (len < expect_len) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n", + __func__, expect_len, len); + return -EINVAL; + } + + *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL); + if (!*policy_6ghz) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz, + expect_len); return 0; } int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value) + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res) { union acpi_object *obj; int ret; @@ -40,12 +87,16 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid, 0, func, NULL); if (!obj) { - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi dsm fail to evaluate func: %d\n", func); return -ENOENT; } - ret = rtw89_acpi_dsm_get(rtwdev, obj, value); + if (func == RTW89_ACPI_DSM_FUNC_6G_BP) + ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj, + &res->u.policy_6ghz); + else + ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); ACPI_FREE(obj); return ret; diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index ed74d8ceb733..fe85b40cf076 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -15,7 +15,37 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_59G_EN = 6, }; +enum rtw89_acpi_policy_mode { + RTW89_ACPI_POLICY_BLOCK = 0, + RTW89_ACPI_POLICY_ALLOW = 1, +}; + +struct rtw89_acpi_country_code { + /* below are allowed: + * * ISO alpha2 country code + * * EU for countries in Europe + */ + char alpha2[2]; +} __packed; + +struct rtw89_acpi_policy_6ghz { + u8 signature[3]; + u8 rsvd; + u8 policy_mode; + u8 country_count; + struct rtw89_acpi_country_code country_list[] __counted_by(country_count); +} __packed; + +struct rtw89_acpi_dsm_result { + union { + u8 value; + /* caller needs to free it after using */ + struct rtw89_acpi_policy_6ghz *policy_6ghz; + } u; +}; + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value); + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res); #endif diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index 079269bb5251..b663ee24555a 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -29,6 +29,7 @@ enum rtw89_debug_mask { RTW89_DBG_WOW = BIT(18), RTW89_DBG_UL_TB = BIT(19), RTW89_DBG_CHAN = BIT(20), + RTW89_DBG_ACPI = BIT(21), RTW89_DBG_UNEXP = BIT(31), }; diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index ca99422e600f..e86480c625c5 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -291,19 +291,22 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; bool regd_allow_unii_4 = chip->support_unii4; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip->support_unii4) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii 4: %d\n", val); @@ -338,19 +341,22 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ); bool regd_allow_6ghz = chip_support_6ghz; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip_support_6ghz) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval 6ghz: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if disallow 6ghz: %d\n", val); diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index aed05b026c6c..1b2a400406ae 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -404,16 +404,18 @@ static void rtw89_tas_state_update(struct rtw89_dev *rtwdev) void rtw89_tas_init(struct rtw89_dev *rtwdev) { struct rtw89_tas_info *tas = &rtwdev->tas; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_SAR, "acpi: cannot get TAS: %d\n", ret); return; } + val = res.u.value; switch (val) { case 0: tas->enable = false; From b2774a916ab95f678c2a365b276870bb68bf3b01 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 14 Nov 2023 17:13:58 +0800 Subject: [PATCH 1130/7721] wifi: rtw89: regd: handle policy of 6 GHz according to BIOS According to BIOS configuration of Realtek ACPI DSM function 4, RTW89_ACPI_DSM_FUNC_6G_BP, we handle the regd policy of 6 GHz. Policy defines two modes as below. 1. `BLOCK` mode: The countries in configured list are blocked. 2. `ALLOW` mode: _Only_ the countries in configured list are allowed. (i.e. others are all blocked.) Then, when receiving regulatory notification at runtime, if 6 GHz is blocked on the country, 6 GHz channels will be disabled. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231114091359.50664-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 + drivers/net/wireless/realtek/rtw89/regd.c | 159 +++++++++++++++++++++- 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 07b529a76396..9c9e8427abd5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4327,9 +4327,12 @@ struct rtw89_regd { u8 txpwr_regd[RTW89_BAND_NUM]; }; +#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX + struct rtw89_regulatory_info { const struct rtw89_regd *regd; enum rtw89_reg_6ghz_power reg_6ghz_power; + DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index e86480c625c5..d9d13887604b 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -257,7 +257,42 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), }; -static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2) +static const char rtw89_alpha2_list_eu[][3] = { + "AT", + "BE", + "CY", + "CZ", + "DK", + "EE", + "FI", + "FR", + "DE", + "GR", + "HU", + "IS", + "IE", + "IT", + "LV", + "LI", + "LT", + "LU", + "MT", + "MC", + "NL", + "NO", + "PL", + "PT", + "SK", + "SI", + "ES", + "SE", + "CH", + "BG", + "HR", + "RO", +}; + +static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2) { u32 i; @@ -274,6 +309,24 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd) return regd == &rtw89_ww_regd; } +static u8 rtw89_regd_get_index(const struct rtw89_regd *regd) +{ + BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM); + + if (rtw89_regd_is_ww(regd)) + return RTW89_REGD_MAX_COUNTRY_NUM; + + return regd - rtw89_regd_map; +} + +static u8 rtw89_regd_get_index_by_name(const char *alpha2) +{ + const struct rtw89_regd *regd; + + regd = rtw89_regd_find_reg_by_name(alpha2); + return rtw89_regd_get_index(regd); +} + #define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \ do { \ typeof(_regd) __r = _regd; \ @@ -335,6 +388,77 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, sband->n_channels -= 3; } +static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, + const char *alpha2) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + u8 index; + + index = rtw89_regd_get_index_by_name(alpha2); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n", + __func__, alpha2[0], alpha2[1]); + return; + } + + if (block) + set_bit(index, regulatory->block_6ghz); + else + clear_bit(index, regulatory->block_6ghz); +} + +static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_country_code *country; + const struct rtw89_acpi_policy_6ghz *ptr; + struct rtw89_acpi_dsm_result res = {}; + bool to_block; + int i, j; + int ret; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz: %d\n", ret); + return; + } + + ptr = res.u.policy_6ghz; + + switch (ptr->policy_mode) { + case RTW89_ACPI_POLICY_BLOCK: + to_block = true; + break; + case RTW89_ACPI_POLICY_ALLOW: + to_block = false; + /* only below list is allowed; block all first */ + bitmap_fill(regulatory->block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown policy mode: %d\n", __func__, + ptr->policy_mode); + goto out; + } + + for (i = 0; i < ptr->country_count; i++) { + country = &ptr->country_list[i]; + if (memcmp("EU", country->alpha2, 2) != 0) { + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + country->alpha2); + continue; + } + + for (j = 0; j < ARRAY_SIZE(rtw89_alpha2_list_eu); j++) + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + rtw89_alpha2_list_eu[j]); + } + +out: + kfree(ptr); +} + static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -375,8 +499,10 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n", regd_allow_6ghz); - if (regd_allow_6ghz) + if (regd_allow_6ghz) { + rtw89_regd_setup_policy_6ghz(rtwdev); return; + } sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) @@ -436,6 +562,33 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev, return 0; } +static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + struct ieee80211_supported_band *sband; + u8 index; + int i; + + index = rtw89_regd_get_index(regd); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) + return; + + if (!test_bit(index, regulatory->block_6ghz)) + return; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1]); + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) + sband->channels[i].flags |= IEEE80211_CHAN_DISABLED; +} + static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, struct wiphy *wiphy, struct regulatory_request *request) @@ -450,6 +603,8 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; else wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; + + rtw89_regd_apply_policy_6ghz(rtwdev, wiphy); } void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) From c212abfbd19fe5ca43fa80981d86e9d7a49f5d45 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 14 Nov 2023 17:13:59 +0800 Subject: [PATCH 1131/7721] wifi: rtw89: regd: update regulatory map to R65-R44 Sync Realtek Regulatory R44 and Realtek Channel Plan R65. Configure 6 GHz field of Realtek regd on SG, TW, GD. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231114091359.50664-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/regd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index d9d13887604b..d0857ef60ea6 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -112,9 +112,9 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_ETSI), COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_THAILAND), COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA), @@ -179,7 +179,7 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), From a85198c9f068baeef6d4a56c389b11a2035a8ea3 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Wed, 15 Nov 2023 17:23:29 +0800 Subject: [PATCH 1132/7721] wifi: mwifiex: mwifiex_process_sleep_confirm_resp(): remove unused priv variable Clang static analyzer complains that value stored to 'priv' is never read. 'priv' is useless, so remove it to save space. Signed-off-by: Su Hui Acked-by: Brian Norris Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231115092328.1048103-1-suhui@nfschina.com --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 3756aa247e77..9eff29a25544 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1244,8 +1244,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, u8 *pbuf, u32 upld_len) { struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); uint16_t result = le16_to_cpu(cmd->result); uint16_t command = le16_to_cpu(cmd->command); uint16_t seq_num = le16_to_cpu(cmd->seq_num); @@ -1260,12 +1258,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", command, result, le16_to_cpu(cmd->size), seq_num); - /* Get BSS number and corresponding priv */ - priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), - HostCmd_GET_BSS_TYPE(seq_num)); - if (!priv) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - /* Update sequence number */ seq_num = HostCmd_GET_SEQ_NO(seq_num); /* Clear RET_BIT from HostCmd */ From f60df12aaaddc865a38480a48e8dba756dffb2b2 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 16 Nov 2023 12:05:29 -0600 Subject: [PATCH 1133/7721] wifi: rtlwifi: drop unused const_amdpci_aspm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused "const_amdpci_aspm" member of struct rtl_pci and struct rtl_ps_ctl. Signed-off-by: Bjorn Helgaas Acked-by: Ping-Ke Shih Reviewed-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231116180529.52752-1-helgaas@kernel.org --- drivers/net/wireless/realtek/rtlwifi/pci.c | 1 - drivers/net/wireless/realtek/rtlwifi/pci.h | 1 - drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 3 --- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 11 files changed, 28 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 9886e719739b..b163a069660b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -70,7 +70,6 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) ppsc->support_aspm = false; /*Update PCI ASPM setting */ - ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; switch (rtlpci->const_pci_aspm) { case 0: /*No ASPM */ diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index 866861626a0a..4725d43609fd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -195,7 +195,6 @@ struct rtl_pci { u32 reg_bcn_ctrl_val; /*ASPM*/ u8 const_pci_aspm; - u8 const_amdpci_aspm; u8 const_hwsw_rfoff_d3; u8 const_support_pciaspm; /*pci-e bridge */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index b77937fe2448..37bb59fa8bfa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -21,9 +21,6 @@ static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index e452275d8789..e20f2bec45c4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -24,9 +24,6 @@ static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 11f319c97124..afd685ed460a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -21,9 +21,6 @@ static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 011ce82efeff..7bde20fdbeab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -24,9 +24,6 @@ static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 30bce381c3bb..675bdd32feb1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -21,9 +21,6 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index c821436a1991..dd7505e2f22c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -26,9 +26,6 @@ static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 43b611d5288d..162c34f0e9b7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -26,9 +26,6 @@ static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 0bca542e103f..7b911695db33 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -23,9 +23,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 171a461cd812..ac8dfda7099d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2008,8 +2008,6 @@ struct rtl_ps_ctl { u32 cur_ps_level; u32 reg_rfps_level; - /*just for PCIE ASPM */ - u8 const_amdpci_aspm; bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; From c0a04552e36e1bac2bdf862342ddfbbfd65aae52 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:24 +0800 Subject: [PATCH 1134/7721] wifi: rtw89: 8922a: add 8922A basic chip info 8922A is a 802.11be chip that can support 2/5/6 GHz bands 160MHz bandwidth. Introduce the basic info such as firmware file name, some hardware address and size, supported spatial stream, TX descriptor and so on, and then we can add more attributes by later patches. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 9 ++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 113 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.h | 15 +++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 2 + 4 files changed, 139 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922a.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922a.h diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 080db70b87d2..7698fd3922f3 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4045,6 +4045,12 @@ #define R_BE_LTR_LATENCY_IDX2_V1 0x361C #define R_BE_LTR_LATENCY_IDX3_V1 0x3620 +#define R_BE_HCI_FUNC_EN 0x7880 +#define B_BE_HCI_CR_PROTECT BIT(31) +#define B_BE_HCI_TRXBUF_EN BIT(2) +#define B_BE_HCI_RXDMA_EN BIT(1) +#define B_BE_HCI_TXDMA_EN BIT(0) + #define R_BE_LTR_CTRL_0 0x8410 #define B_BE_LTR_REQ_FW BIT(18) #define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16) @@ -4975,6 +4981,7 @@ #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac #define R_BSS_CLR_MAP_V1 0x43B0 +#define R_BSS_CLR_MAP_V2 0x4EB0 #define B_BSS_CLR_MAP_VLD0 BIT(28) #define B_BSS_CLR_MAP_TGT GENMASK(27, 22) #define B_BSS_CLR_MAP_STAID GENMASK(21, 11) @@ -5268,6 +5275,8 @@ #define R_BMODE_PDTH_EN_V1 0x4B74 #define R_BMODE_PDTH_EN_V2 0x6718 #define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30) +#define R_BSS_CLR_VLD_V2 0x4EBC +#define B_BSS_CLR_VLD0_V2 BIT(2) #define R_CFO_COMP_SEG1_L 0x5384 #define R_CFO_COMP_SEG1_H 0x5388 #define R_CFO_COMP_SEG1_CTRL 0x538C diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c new file mode 100644 index 000000000000..e6f804b4907e --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8922a.h" + +#define RTW8922A_FW_FORMAT_MAX 0 +#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" +#define RTW8922A_MODULE_FIRMWARE \ + RTW8922A_FW_BASENAME ".bin" + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + +static const struct rtw89_chip_ops rtw8922a_chip_ops = { +}; + +const struct rtw89_chip_info rtw8922a_chip_info = { + .chip_id = RTL8922A, + .chip_gen = RTW89_CHIP_BE, + .ops = &rtw8922a_chip_ops, + .mac_def = &rtw89_mac_gen_be, + .phy_def = &rtw89_phy_gen_be, + .fw_basename = RTW8922A_FW_BASENAME, + .fw_format_max = RTW8922A_FW_FORMAT_MAX, + .try_ce_fw = false, + .bbmcu_nr = 1, + .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS, + .fifo_size = 589824, + .small_fifo_size = false, + .dle_scc_rsvd_size = 0, + .max_amsdu_limit = 8000, + .dis_2g_40m_ul_ofdma = false, + .rsvd_ple_ofst = 0x8f800, + .rf_base_addr = {0xe000, 0xf000}, + .pwr_on_seq = NULL, + .pwr_off_seq = NULL, + .bb_table = NULL, + .bb_gain_table = NULL, + .rf_table = {}, + .nctl_table = NULL, + .nctl_post_table = NULL, + .dflt_parms = NULL, /* load parm from fw */ + .rfe_parms_conf = NULL, /* load parm from fw */ + .txpwr_factor_rf = 2, + .txpwr_factor_mac = 1, + .dig_table = NULL, + .tssi_dbw_table = NULL, + .support_chanctx_num = 1, + .support_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ) | + BIT(NL80211_BAND_6GHZ), + .support_unii4 = true, + .ul_tb_waveform_ctrl = false, + .ul_tb_pwr_diff = false, + .hw_sec_hdr = true, + .rf_path_num = 2, + .tx_nss = 2, + .rx_nss = 2, + .acam_num = 128, + .bcam_num = 20, + .scam_num = 32, + .bacam_num = 8, + .bacam_dynamic_num = 8, + .bacam_ver = RTW89_BACAM_V1, + .ppdu_max_usr = 16, + .sec_ctrl_efuse_size = 4, + .physical_efuse_size = 0x1300, + .logical_efuse_size = 0x70000, + .limit_efuse_size = 0x40000, + .dav_phy_efuse_size = 0, + .dav_log_efuse_size = 0, + .phycap_addr = 0x1700, + .phycap_size = 0x38, + + .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | + BIT(RTW89_PS_MODE_CLK_GATED) | + BIT(RTW89_PS_MODE_PWR_GATED), + .low_power_hci_modes = 0, + .hci_func_en_addr = R_BE_HCI_FUNC_EN, + .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), + .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), + .txwd_info_size = sizeof(struct rtw89_txwd_info_v2), + .cfo_src_fd = true, + .cfo_hw_comp = true, + .dcfo_comp = NULL, + .dcfo_comp_sft = 0, + .imr_info = NULL, + .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, + .bss_clr_map_reg = R_BSS_CLR_MAP_V2, + .dma_ch_mask = 0, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8922a, +#endif + .xtal_info = NULL, +}; +EXPORT_SYMBOL(rtw8922a_chip_info); + +MODULE_FIRMWARE(RTW8922A_MODULE_FIRMWARE); +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922A driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h new file mode 100644 index 000000000000..eae70b1f8d01 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2023 Realtek Corporation + */ + +#ifndef __RTW89_8922A_H__ +#define __RTW89_8922A_H__ + +#include "core.h" + +#define RF_PATH_NUM_8922A 2 +#define BB_PATH_NUM_8922A 2 + +extern const struct rtw89_chip_info rtw8922a_chip_info; + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 414635d301aa..7b3d98d2c402 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -7,6 +7,7 @@ #include "pci.h" #include "reg.h" +#include "rtw8922a.h" static const struct rtw89_pci_info rtw8922a_pci_info = { .gen_def = &rtw89_pci_gen_be, @@ -58,6 +59,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { }; static const struct rtw89_driver_info rtw89_8922ae_info = { + .chip = &rtw8922a_chip_info, .bus = { .pci = &rtw8922a_pci_info, }, From 88e6a923bbfbdd4fd2e92ff50902251884927dac Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:25 +0800 Subject: [PATCH 1135/7721] wifi: rtw89: mac: use mac_gen pointer to access about efuse Use function pointers to abstract efuse access, and introduce an new function to convert efuse power state that is needed by WiFi 7 chips. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 5 +++-- drivers/net/wireless/realtek/rtw89/efuse.c | 9 +++++++-- drivers/net/wireless/realtek/rtw89/efuse.h | 5 +++-- drivers/net/wireless/realtek/rtw89/mac.c | 16 +++++++++++++--- drivers/net/wireless/realtek/rtw89/mac.h | 3 +++ 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index b18f54b16f9a..74bf29643823 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4216,17 +4216,18 @@ static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev) static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_mac_partial_init(rtwdev, false); if (ret) return ret; - ret = rtw89_parse_efuse_map(rtwdev); + ret = mac->parse_efuse_map(rtwdev); if (ret) return ret; - ret = rtw89_parse_phycap_map(rtwdev); + ret = mac->parse_phycap_map(rtwdev); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 2aaf4d013e46..b2e8c6cc12d9 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -114,6 +114,11 @@ static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map, return 0; } +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle) +{ + return 0; +} + static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, u32 dump_addr, u32 dump_size) { @@ -231,7 +236,7 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map, return 0; } -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev) { u32 phy_size = rtwdev->chip->physical_efuse_size; u32 log_size = rtwdev->chip->logical_efuse_size; @@ -300,7 +305,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) return ret; } -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev) +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev) { u32 phycap_addr = rtwdev->chip->phycap_addr; u32 phycap_size = rtwdev->chip->phycap_size; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 79071aff28de..24173b3dc085 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -7,8 +7,9 @@ #include "core.h" -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev); -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev); +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0c5768f41d55..9ec307051611 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5,6 +5,7 @@ #include "cam.h" #include "chan.h" #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "pci.h" @@ -2626,20 +2627,26 @@ static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev, struct rtw89_mac_c2h_info *c2h_info) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_mac_h2c_info h2c_info = {0}; u32 ret; + mac->cnv_efuse_state(rtwdev, false); + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE; h2c_info.content_len = 0; ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, c2h_info); if (ret) - return ret; + goto out; if (c2h_info->id != RTW89_FWCMD_C2HREG_FUNC_PHY_CAP) - return -EINVAL; + ret = -EINVAL; - return 0; +out: + mac->cnv_efuse_state(rtwdev, true); + + return ret; } int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) @@ -5775,6 +5782,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax, + .parse_efuse_map = rtw89_parse_efuse_map_ax, + .parse_phycap_map = rtw89_parse_phycap_map_ax, + .cnv_efuse_state = rtw89_cnv_efuse_state_ax, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index cd2e9b850c72..f47a42387a6a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -873,6 +873,9 @@ struct rtw89_mac_gen_def { bool dlfw, bool include_bb); u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl); + int (*parse_efuse_map)(struct rtw89_dev *rtwdev); + int (*parse_phycap_map)(struct rtw89_dev *rtwdev); + int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, From f28eab6ae4ff016d01226364c9099d4eacffbb1a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:26 +0800 Subject: [PATCH 1136/7721] wifi: rtw89: mac: add to access efuse for WiFi 7 chips MAC address, hardware type, calibration values and etc are stored in efuse, so we read them at probe stage and use them as capabilities to register hardware. There are two physical efuse -- one is the main efuse for digital hardware part, and the other is for analog part. Because they are very similar, we only describe the main efuse below. The main efuse is split into two regions -- one is for logic map, and the other is for physical map. For both regions, we use the same method to read data, but need additional parser to get logic map. To allow reading operation, we need to convert power state to active, and turn to idle state after reading. For WiFi 7 chips, we introduce efuse blocks to define feature group easier, and these blocks are discontinue. For example, RF block is from 0x1_0000 ~ 0x1_0240, and the next block PCIE_SDIO is starting from 0x2_0000. Comparing to old one used by WiFi 6 chips, there is only single one logic map, it would be a little hard to add an new field to a group if we don't reserve a room in advance. The relationship between efuse, region and block is shown as below: (logical map) +------------+ +---------------+ +-----------------+ | main efuse | | region 1 | | block 0x1_0000~ | | (digital) | |(to logcal map)| +-----------------+ | | | | => +-----------------+ | | => | | | block 0x2_0000~ | | | | | +-----------------+ | | |---------------| : | | | region 2 | +------------+ +---------------+ +------------+ +-----------------+ | 2nd efuse | ======================> | block 0x7_0000~ | | (analog) | +-----------------+ +------------+ The parser converting from raw data to logic map is to decode block page, block page offset, and word_en bits. Each word_en bit indicates two following bytes as data of logic map, so total four word_en bits can represent eight bytes. Thus, block page offset is 8-byte alignment. The layout of a tuple is shown as below +--------+--------+--------+--------+--------+--------+ | fixed 3 byte header | | | | | | | | | | [19:17] block_page | | | ... | | [16:4] block_page_offset| | | | | [3:0] word_en | ^ | ^ | | +----|---+--------+--------+---|----+----|---+--------+ | | | +-------------------------+---------+ a word_en bit indicates two bytes as data For example, block_page = 0x3 block_page_offset = 0x80 (must 8-byte alignment) word_en = 0x6 (b'0110; 0 means data is presented) following 4 bytes = 34 56 78 90 Then, 0x3_0080 = 34 56 0x3_0086 = 78 90 A special block page is RTW89_EFUSE_BLOCK_ADIE (7) that uses different but similar format, because its real efuse size is smaller than main efuse. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 19 +- drivers/net/wireless/realtek/rtw89/efuse.c | 2 +- drivers/net/wireless/realtek/rtw89/efuse.h | 12 + drivers/net/wireless/realtek/rtw89/efuse_be.c | 420 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac_be.c | 4 + drivers/net/wireless/realtek/rtw89/reg.h | 72 +++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 13 + 11 files changed, 552 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw89/efuse_be.c diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 9c9e8427abd5..e7246eebcd99 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -16,6 +16,7 @@ struct rtw89_dev; struct rtw89_pci_info; struct rtw89_mac_gen_def; struct rtw89_phy_gen_def; +struct rtw89_efuse_block_cfg; extern const struct ieee80211_ops rtw89_ops; @@ -2777,6 +2778,20 @@ enum rtw89_rx_frame_type { RTW89_RX_TYPE_RSVD = 3, }; +enum rtw89_efuse_block { + RTW89_EFUSE_BLOCK_SYS = 0, + RTW89_EFUSE_BLOCK_RF = 1, + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO = 2, + RTW89_EFUSE_BLOCK_HCI_DIG_USB = 3, + RTW89_EFUSE_BLOCK_HCI_PHY_PCIE = 4, + RTW89_EFUSE_BLOCK_HCI_PHY_USB3 = 5, + RTW89_EFUSE_BLOCK_HCI_PHY_USB2 = 6, + RTW89_EFUSE_BLOCK_ADIE = 7, + + RTW89_EFUSE_BLOCK_NUM, + RTW89_EFUSE_BLOCK_IGNORE, +}; + struct rtw89_ra_info { u8 is_dis_ra:1; /* Bit0 : CCK @@ -3119,7 +3134,8 @@ struct rtw89_chip_ops { const struct rtw89_chan *chan, enum rtw89_mac_idx mac_idx, enum rtw89_phy_idx phy_idx); - int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map); + int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block); int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); void (*fem_setup)(struct rtw89_dev *rtwdev); void (*rfe_gpio)(struct rtw89_dev *rtwdev); @@ -3655,6 +3671,7 @@ struct rtw89_chip_info { u32 dav_log_efuse_size; u32 phycap_addr; u32 phycap_size; + const struct rtw89_efuse_block_cfg *efuse_blocks; const struct rtw89_pwr_cfg * const *pwr_on_seq; const struct rtw89_pwr_cfg * const *pwr_off_seq; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index b2e8c6cc12d9..e1236079a84a 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -291,7 +291,7 @@ int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev) rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size); - ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map); + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE); if (ret) { rtw89_warn(rtwdev, "failed to read efuse map\n"); goto out_free; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 24173b3dc085..5c6787179bad 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -7,9 +7,21 @@ #include "core.h" +#define RTW89_EFUSE_BLOCK_ID_MASK GENMASK(31, 16) +#define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0) +#define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000 + +struct rtw89_efuse_block_cfg { + u32 offset; + u32 size; +}; + int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev); int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev); int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle); +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c new file mode 100644 index 000000000000..8e8b7cd315f7 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "efuse.h" +#include "mac.h" +#include "reg.h" + +static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + mdelay(1); + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + } + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + mdelay(1); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + } + + rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 efuse_ctl; + u32 addr; + u32 data; + int ret; + + if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) { + rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n", + dump_addr, dump_size); + return -EINVAL; + } + + rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev); + + for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) { + efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK); + rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY); + + ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl, + efuse_ctl & B_BE_EF_RDY, 1, 1000000, + true, rtwdev, R_BE_EFUSE_CTRL); + if (ret) + return -EBUSY; + + data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1); + *((__le32 *)map) = cpu_to_le32(data); + } + + rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev); + + return 0; +} + +static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 addr; + u8 val8; + int err; + int ret; + + for (addr = dump_addr; addr < dump_addr + dump_size; addr++) { + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, + FULL_BIT_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff, + XTAL_SI_LOW_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8, + XTAL_SI_HIGH_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0, + XTAL_SI_MODE_SEL_MASK); + if (ret) + return ret; + + ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err, + !err && (val8 & XTAL_SI_RDY), + 1, 10000, false, + rtwdev, XTAL_SI_CTRL, &val8); + if (ret) { + rtw89_warn(rtwdev, "failed to read dav efuse\n"); + return ret; + } + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8); + if (ret) + return ret; + *map++ = val8; + } + + return 0; +} + +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle) +{ + u32 val; + int ret = 0; + + if (idle) { + rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + } else { + rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val, + val == MAC_AX_SYS_ACT, 50, 5000, + false, rtwdev, R_BE_IC_PWR_STATE, + B_BE_WHOLE_SYS_PWR_STE_MASK); + if (ret) + rtw89_warn(rtwdev, "failed to convert efuse state\n"); + } + + return ret; +} + +static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size, bool dav) +{ + int ret; + + if (!map || dump_size == 0) + return 0; + + rtw89_cnv_efuse_state_be(rtwdev, false); + + if (dav) { + ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size); + } else { + ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size); + } + + rtw89_cnv_efuse_state_be(rtwdev, true); + + return 0; +} + +#define EFUSE_HDR_CONST_MASK GENMASK(23, 20) +#define EFUSE_HDR_PAGE_MASK GENMASK(19, 17) +#define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4) +#define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4) +#define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0) + +#define invalid_efuse_header_be(hdr1, hdr2, hdr3) \ + ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff) +#define invalid_efuse_content_be(word_en, i) \ + (((word_en) & BIT(i)) != 0x0) +#define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \ + (((hdr1) << 16) | ((hdr2) << 8) | (hdr3)) +#define block_idx_to_logical_idx_be(blk_idx, i) \ + (((blk_idx) << 3) + ((i) << 1)) + +#define invalid_efuse_header_dav_be(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) +#define get_efuse_blk_idx_dav_be(hdr1, hdr2) \ + (((hdr1) << 8) | (hdr2)) + +static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, u8 *log_map, + const struct rtw89_efuse_block_cfg *efuse_block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + enum rtw89_efuse_block blk_page, page; + u32 size = efuse_block->size; + u32 phy_idx, log_idx; + u32 hdr, page_offset; + u8 hdr1, hdr2, hdr3; + u8 i, val0, val1; + u32 min, max; + u16 blk_idx; + u8 word_en; + + page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK); + page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK); + + min = ALIGN_DOWN(page_offset, 2); + max = ALIGN(page_offset + size, 2); + + memset(log_map, 0xff, size); + + phy_idx = chip->sec_ctrl_efuse_size; + + do { + if (page == RTW89_EFUSE_BLOCK_ADIE) { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + if (invalid_efuse_header_dav_be(hdr1, hdr2)) + break; + + phy_idx += 2; + + hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2); + + blk_page = RTW89_EFUSE_BLOCK_ADIE; + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } else { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + hdr3 = phy_map[phy_idx + 2]; + if (invalid_efuse_header_be(hdr1, hdr2, hdr3)) + break; + + phy_idx += 3; + + hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3); + + blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK); + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } + + if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) { + rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3); + rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr); + return -EINVAL; + } + + for (i = 0; i < 4; i++) { + if (invalid_efuse_content_be(word_en, i)) + continue; + + if (phy_idx >= phy_size - 1) + return -EINVAL; + + log_idx = block_idx_to_logical_idx_be(blk_idx, i); + + if (blk_page == page && log_idx >= min && log_idx < max) { + val0 = phy_map[phy_idx]; + val1 = phy_map[phy_idx + 1]; + + if (log_idx == min && page_offset > min) { + log_map[log_idx - page_offset + 1] = val1; + } else if (log_idx + 2 == max && + page_offset + size < max) { + log_map[log_idx - page_offset] = val0; + } else { + log_map[log_idx - page_offset] = val0; + log_map[log_idx - page_offset + 1] = val1; + } + } + phy_idx += 2; + } + } while (phy_idx < phy_size); + + return 0; +} + +static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, + enum rtw89_efuse_block block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_efuse_block_cfg *efuse_block; + u8 *log_map; + int ret; + + efuse_block = &chip->efuse_blocks[block]; + + log_map = kmalloc(efuse_block->size, GFP_KERNEL); + if (!log_map) + return -ENOMEM; + + ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block); + goto out_free; + } + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size); + + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block); + if (ret) { + rtw89_warn(rtwdev, "failed to read efuse map\n"); + goto out_free; + } + +out_free: + kfree(log_map); + + return ret; +} + +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev) +{ + u32 phy_size = rtwdev->chip->physical_efuse_size; + u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size; + enum rtw89_efuse_block block; + u8 *phy_map = NULL; + u8 *dav_phy_map = NULL; + int ret; + + if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS) + rtwdev->efuse.valid = true; + else + rtw89_warn(rtwdev, "failed to check efuse autoload\n"); + + phy_map = kmalloc(phy_size, GFP_KERNEL); + if (dav_phy_size) + dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL); + + if (!phy_map || (dav_phy_size && !dav_phy_map)) { + ret = -ENOMEM; + goto out_free; + } + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse physical map\n"); + goto out_free; + } + ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n"); + goto out_free; + } + + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + block = RTW89_EFUSE_BLOCK_HCI_DIG_USB; + else + block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO; + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO); + goto out_free; + } + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, + RTW89_EFUSE_BLOCK_RF); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_RF); + goto out_free; + } + +out_free: + kfree(dav_phy_map); + kfree(phy_map); + + return ret; +} + +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + u32 phycap_size = rtwdev->chip->phycap_size; + u8 *phycap_map = NULL; + int ret = 0; + + if (!phycap_size) + return 0; + + phycap_map = kmalloc(phycap_size, GFP_KERNEL); + if (!phycap_map) + return -ENOMEM; + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map, + phycap_addr, phycap_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump phycap map\n"); + goto out_free; + } + + ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map); + if (ret) { + rtw89_warn(rtwdev, "failed to read phycap map\n"); + goto out_free; + } + +out_free: + kfree(phycap_map); + + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 3278f241db6e..1c607316f652 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -3,6 +3,7 @@ */ #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "reg.h" @@ -429,6 +430,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be, + .parse_efuse_map = rtw89_parse_efuse_map_be, + .parse_phycap_map = rtw89_parse_phycap_map_be, + .cnv_efuse_state = rtw89_cnv_efuse_state_be, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, }; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 7698fd3922f3..7a9ae6cd86e5 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3630,6 +3630,23 @@ #define B_AX_GNT_BT_TX_SW_VAL BIT(1) #define B_AX_GNT_BT_TX_SW_CTRL BIT(0) +#define R_BE_SYS_ISO_CTRL 0x0000 +#define B_BE_PWC_EV2EF_B BIT(15) +#define B_BE_PWC_EV2EF_S BIT(14) +#define B_BE_PA33V_EN BIT(13) +#define B_BE_PA12V_EN BIT(12) +#define B_BE_PAOOBS33V_EN BIT(11) +#define B_BE_PAOOBS12V_EN BIT(10) +#define B_BE_ISO_RFDIO BIT(9) +#define B_BE_ISO_EB2CORE BIT(8) +#define B_BE_ISO_DIOE BIT(7) +#define B_BE_ISO_WLPON2PP BIT(6) +#define B_BE_ISO_IP2MAC_WA02PP BIT(5) +#define B_BE_ISO_PD2CORE BIT(4) +#define B_BE_ISO_PA2PCIE BIT(3) +#define B_BE_ISO_PAOOBS2PCIE BIT(1) +#define B_BE_ISO_WD2PP BIT(0) + #define R_BE_SYS_PW_CTRL 0x0004 #define B_BE_SOP_ASWRM BIT(31) #define B_BE_SOP_EASWR BIT(30) @@ -3667,6 +3684,16 @@ #define B_BE_ANA_CLK_DIVISION_2 BIT(1) #define B_BE_CNTD16V_EN BIT(0) +#define R_BE_SYS_WL_EFUSE_CTRL 0x000A +#define B_BE_OTP_B_PWC_RPT BIT(15) +#define B_BE_OTP_S_PWC_RPT BIT(14) +#define B_BE_OTP_ISO_RPT BIT(13) +#define B_BE_OTP_BURST_RPT BIT(12) +#define B_BE_OTP_AUTOLOAD_RPT BIT(11) +#define B_BE_AUTOLOAD_DIS_A_DIE BIT(6) +#define B_BE_AUTOLOAD_SUS BIT(5) +#define B_BE_AUTOLOAD_DIS BIT(4) + #define R_BE_SYS_PAGE_CLK_GATED 0x000C #define B_BE_USB_APHY_PC_DLP_OP BIT(27) #define B_BE_PCIE_APHY_PC_DLP_OP BIT(26) @@ -3696,6 +3723,38 @@ #define B_BE_DIS_CLK_REG1_GATE BIT(1) #define B_BE_DIS_CLK_REG0_GATE BIT(0) +#define R_BE_EFUSE_CTRL 0x0030 +#define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) +#define B_BE_EF_RDY BIT(29) +#define B_BE_EF_COMP_RESULT BIT(28) +#define B_BE_EF_ADDR_MASK GENMASK(15, 0) + +#define R_BE_EFUSE_CTRL_1_V1 0x0034 +#define B_BE_EF_DATA_MASK GENMASK(31, 0) + +#define R_BE_WL_BT_PWR_CTRL 0x0068 +#define B_BE_ISO_BD2PP BIT(31) +#define B_BE_LDOV12B_EN BIT(30) +#define B_BE_CKEN_BT BIT(29) +#define B_BE_FEN_BT BIT(28) +#define B_BE_BTCPU_BOOTSEL BIT(27) +#define B_BE_SPI_SPEEDUP BIT(26) +#define B_BE_BT_LDO_MODE BIT(25) +#define B_BE_ISO_BTPON2PP BIT(22) +#define B_BE_BT_FUNC_EN BIT(18) +#define B_BE_BT_HWPDN_SL BIT(17) +#define B_BE_BT_DISN_EN BIT(16) +#define B_BE_SDM_SRC_SEL BIT(12) +#define B_BE_ISO_BA2PP BIT(11) +#define B_BE_BT_AFE_LDO_EN BIT(10) +#define B_BE_BT_AFE_PLL_EN BIT(9) +#define B_BE_WLAN_32K_SEL BIT(6) +#define B_BE_WL_DRV_EXIST_IDX BIT(5) +#define B_BE_DOP_EHPAD BIT(4) +#define B_BE_WL_FUNC_EN BIT(2) +#define B_BE_WL_HWPDN_SL BIT(1) +#define B_BE_WL_HWPDN_EN BIT(0) + #define R_BE_SYS_SDIO_CTRL 0x0070 #define B_BE_MCM_FLASH_EN BIT(28) #define B_BE_PCIE_SEC_LOAD BIT(26) @@ -3780,6 +3839,19 @@ #define B_BE_EF_DSB_EN BIT(11) #define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) +#define R_BE_PMC_DBG_CTRL2 0x00CC +#define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24) +#define B_BE_DIS_IOWRAP_TIMEOUT BIT(16) +#define B_BE_STOP_WL_PMC BIT(9) +#define B_BE_STOP_SYM_PMC BIT(8) +#define B_BE_SYM_REG_PCIE_WRMSK BIT(7) +#define B_BE_BT_ACCESS_WL_PAGE0 BIT(6) +#define B_BE_R_BE_RST_WLPMC BIT(5) +#define B_BE_R_BE_RST_PD12N BIT(4) +#define B_BE_SYSON_DIS_WLR_BE_WRMSK BIT(3) +#define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) +#define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index ffc464b2ac10..dd15b904cd2f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -500,7 +500,8 @@ static void rtw8851b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8851b_efuse *map; @@ -2400,6 +2401,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .limit_efuse_size = 1280, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0d6f87b900d5..2bddd0acb195 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -537,7 +537,8 @@ static void rtw8852a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, } } -static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852a_efuse *map; @@ -2136,6 +2137,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .limit_efuse_size = 1152, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0x0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 62c2feab569c..a576e4f47880 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -638,7 +638,8 @@ static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852b_efuse *map; @@ -2570,6 +2571,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 7bb5d359a06a..1d655ce1fd5f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -430,7 +430,8 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852c_efuse *map; @@ -2884,6 +2885,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x590, .phycap_size = 0x60, .para_ver = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index e6f804b4907e..4a431640a1ce 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -3,6 +3,7 @@ */ #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "phy.h" @@ -14,6 +15,17 @@ #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME ".bin" +static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { + [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, + [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, + [RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO] = {.offset = 0x20000, .size = 0x4800}, + [RTW89_EFUSE_BLOCK_HCI_DIG_USB] = {.offset = 0x30000, .size = 0x890}, + [RTW89_EFUSE_BLOCK_HCI_PHY_PCIE] = {.offset = 0x40000, .size = 0x200}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB3] = {.offset = 0x50000, .size = 0x80}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB2] = {.offset = 0x60000, .size = 0x0}, + [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -81,6 +93,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .limit_efuse_size = 0x40000, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = rtw8922a_efuse_blocks, .phycap_addr = 0x1700, .phycap_size = 0x38, From e102ff4b3579016361f092027782f1a3a7fa2055 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:27 +0800 Subject: [PATCH 1137/7721] wifi: rtw89: 8852c: read RX gain offset from efuse for 6GHz channels Read calibration values of RX gain offset from efuse, and set them to registers to normalize RX gain for all hardware modules. Then, PHY dynamic mechanism can get expected values to adjust hardware parameters to yield expected performance. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 8 +++++++ drivers/net/wireless/realtek/rtw89/phy.h | 16 +++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8852c.c | 24 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8852c.h | 20 ++++++++++++++-- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e7246eebcd99..73b2e74885d0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -104,6 +104,14 @@ enum rtw89_gain_offset { RTW89_GAIN_OFFSET_5G_LOW, RTW89_GAIN_OFFSET_5G_MID, RTW89_GAIN_OFFSET_5G_HIGH, + RTW89_GAIN_OFFSET_6G_L0, + RTW89_GAIN_OFFSET_6G_L1, + RTW89_GAIN_OFFSET_6G_M0, + RTW89_GAIN_OFFSET_6G_M1, + RTW89_GAIN_OFFSET_6G_H0, + RTW89_GAIN_OFFSET_6G_H1, + RTW89_GAIN_OFFSET_6G_UH0, + RTW89_GAIN_OFFSET_6G_UH1, RTW89_GAIN_OFFSET_NR, }; diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5c85122e7bb5..2d9cf5c02b92 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -591,6 +591,22 @@ enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subb return RTW89_GAIN_OFFSET_5G_MID; case RTW89_CH_5G_BAND_4: return RTW89_GAIN_OFFSET_5G_HIGH; + case RTW89_CH_6G_BAND_IDX0: + return RTW89_GAIN_OFFSET_6G_L0; + case RTW89_CH_6G_BAND_IDX1: + return RTW89_GAIN_OFFSET_6G_L1; + case RTW89_CH_6G_BAND_IDX2: + return RTW89_GAIN_OFFSET_6G_M0; + case RTW89_CH_6G_BAND_IDX3: + return RTW89_GAIN_OFFSET_6G_M1; + case RTW89_CH_6G_BAND_IDX4: + return RTW89_GAIN_OFFSET_6G_H0; + case RTW89_CH_6G_BAND_IDX5: + return RTW89_GAIN_OFFSET_6G_H1; + case RTW89_CH_6G_BAND_IDX6: + return RTW89_GAIN_OFFSET_6G_UH0; + case RTW89_CH_6G_BAND_IDX7: + return RTW89_GAIN_OFFSET_6G_UH1; } } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 1d655ce1fd5f..ea152a4613f2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -426,6 +426,30 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, valid |= _decode_efuse_gain(map->rx_gain_5g_high, &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1]); gain->offset_valid = valid; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h index ac642808a81f..77b05daedd10 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h @@ -73,9 +73,25 @@ struct rtw8852c_efuse { u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; u8 rsvd14[10]; u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; - u8 rsvd15[110]; + u8 rsvd15[94]; + u8 rx_gain_6g_l0; + u8 rsvd16; + u8 rx_gain_6g_l1; + u8 rsvd17; + u8 rx_gain_6g_m0; + u8 rsvd18; + u8 rx_gain_6g_m1; + u8 rsvd19; + u8 rx_gain_6g_h0; + u8 rsvd20; + u8 rx_gain_6g_h1; + u8 rsvd21; + u8 rx_gain_6g_uh0; + u8 rsvd22; + u8 rx_gain_6g_uh1; + u8 rsvd23; u8 channel_plan_6g; - u8 rsvd16[71]; + u8 rsvd24[71]; union { struct rtw8852c_u_efuse u; struct rtw8852c_e_efuse e; From c7ccb2402ebb567016b09bf50e225066c72a9c09 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:28 +0800 Subject: [PATCH 1138/7721] wifi: rtw89: 8922a: read efuse content via efuse map struct from logic map Define efuse map struct of RTW89_EFUSE_BLOCK_RF block, and read needed data from efuse logic map into driver. Also, with efuse power-on state, read MAC address via register interface according to HCI interface. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 150 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.h | 58 +++++++ 2 files changed, 208 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 4a431640a1ce..bed74ab4a7c2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -26,6 +26,155 @@ static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, }; +static void rtw8922a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw8922a_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; + u8 *bw40_1s_tssi_6g_ofst[] = {map->bw40_1s_tssi_6g_a, map->bw40_1s_tssi_6g_b}; + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + u8 i, j; + + tssi->thermal[RF_PATH_A] = map->path_a_therm; + tssi->thermal[RF_PATH_B] = map->path_b_therm; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, + sizeof(ofst[i]->cck_tssi)); + + for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", + i, j, tssi->tssi_cck[i][j]); + + memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, + sizeof(ofst[i]->bw40_tssi)); + memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, + ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); + memcpy(tssi->tssi_6g_mcs[i], bw40_1s_tssi_6g_ofst[i], + sizeof(tssi->tssi_6g_mcs[i])); + + for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", + i, j, tssi->tssi_mcs[i][j]); + } +} + +static void rtw8922a_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + bool all_0xff = true, all_0x00 = true; + int i, j; + u8 t; + + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_a._2g_cck; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_b._2g_cck; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_a._2g_ofdm; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_b._2g_ofdm; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_a._5g_low; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_b._5g_low; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_a._5g_mid; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_b._5g_mid; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_a._5g_high; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_b._5g_high; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_a._6g_l0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_b._6g_l0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_a._6g_l1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_b._6g_l1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_a._6g_m0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_b._6g_m0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_a._6g_m1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_b._6g_m1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_a._6g_h0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_b._6g_h0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_a._6g_h1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_b._6g_h1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_a._6g_uh0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_b._6g_uh0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_a._6g_uh1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_b._6g_uh1; + + for (i = RF_PATH_A; i <= RF_PATH_B; i++) + for (j = 0; j < RTW89_GAIN_OFFSET_NR; j++) { + t = gain->offset[i][j]; + if (t != 0xff) + all_0xff = false; + if (t != 0x0) + all_0x00 = false; + + /* transform: sign-bit + U(7,2) to S(8,2) */ + if (t & 0x80) + gain->offset[i][j] = (t ^ 0x7f) + 1; + } + + gain->offset_valid = !all_0xff && !all_0x00; +} + +static void rtw8922a_read_efuse_mac_addr(struct rtw89_dev *rtwdev, u32 addr) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + u16 val; + int i; + + for (i = 0; i < ETH_ALEN; i += 2, addr += 2) { + val = rtw89_read16(rtwdev, addr); + efuse->addr[i] = val & 0xff; + efuse->addr[i + 1] = val >> 8; + } +} + +static int rtw8922a_read_efuse_pci_sdio(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw8922a_read_efuse_mac_addr(rtwdev, 0x3104); + else + ether_addr_copy(efuse->addr, log_map + 0x001A); + + return 0; +} + +static int rtw8922a_read_efuse_usb(struct rtw89_dev *rtwdev, u8 *log_map) +{ + rtw8922a_read_efuse_mac_addr(rtwdev, 0x4078); + + return 0; +} + +static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw8922a_efuse *map = (struct rtw8922a_efuse *)log_map; + struct rtw89_efuse *efuse = &rtwdev->efuse; + + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + rtw8922a_efuse_parsing_tssi(rtwdev, map); + rtw8922a_efuse_parsing_gain_offset(rtwdev, map); + + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); + + return 0; +} + +static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) +{ + switch (block) { + case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO: + return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_HCI_DIG_USB: + return rtw8922a_read_efuse_usb(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_RF: + return rtw8922a_read_efuse_rf(rtwdev, log_map); + default: + return 0; + } +} + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -36,6 +185,7 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { #endif static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .read_efuse = rtw8922a_read_efuse, }; const struct rtw89_chip_info rtw8922a_chip_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h index eae70b1f8d01..597317ab6af7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h @@ -10,6 +10,64 @@ #define RF_PATH_NUM_8922A 2 #define BB_PATH_NUM_8922A 2 +struct rtw8922a_tssi_offset { + u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; + u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; + u8 rsvd[7]; + u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; + u8 bw_diff_5g[10]; +} __packed; + +struct rtw8922a_rx_gain { + u8 _2g_ofdm; + u8 _2g_cck; + u8 _5g_low; + u8 _5g_mid; + u8 _5g_high; +} __packed; + +struct rtw8922a_rx_gain_6g { + u8 _6g_l0; + u8 _6g_l1; + u8 _6g_m0; + u8 _6g_m1; + u8 _6g_h0; + u8 _6g_h1; + u8 _6g_uh0; + u8 _6g_uh1; +} __packed; + +struct rtw8922a_efuse { + u8 country_code[2]; + u8 rsvd[0xe]; + struct rtw8922a_tssi_offset path_a_tssi; + struct rtw8922a_tssi_offset path_b_tssi; + u8 rsvd1[0x54]; + u8 channel_plan; + u8 xtal_k; + u8 rsvd2[0x7]; + u8 board_info; + u8 rsvd3[0x8]; + u8 rfe_type; + u8 rsvd4[0x5]; + u8 path_a_therm; + u8 path_b_therm; + u8 rsvd5[0x2]; + struct rtw8922a_rx_gain rx_gain_a; + struct rtw8922a_rx_gain rx_gain_b; + u8 rsvd6[0x22]; + u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd7[0xa]; + u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd8[0xa]; + u8 bw40_1s_tssi_6g_c[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd9[0xa]; + u8 bw40_1s_tssi_6g_d[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd10[0xa]; + struct rtw8922a_rx_gain_6g rx_gain_6g_a; + struct rtw8922a_rx_gain_6g rx_gain_6g_b; +} __packed; + extern const struct rtw89_chip_info rtw8922a_chip_info; #endif From 52471877a2e7211603f57c74102e8ba2aa06fe48 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 17 Nov 2023 10:40:29 +0800 Subject: [PATCH 1139/7721] wifi: rtw89: 8922a: read efuse content from physical map The calibration values of thermal and bias are programmed in invariable physical map. Read them into driver and will set them to registers later. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117024029.113845-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 73b2e74885d0..6948ffe0f206 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4345,6 +4345,7 @@ struct rtw89_power_trim_info { bool pg_pa_bias_trim; u8 thermal_trim[RF_PATH_MAX]; u8 pa_bias_trim[RF_PATH_MAX]; + u8 pad_bias_trim[RF_PATH_MAX]; }; struct rtw89_regd { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index bed74ab4a7c2..d190f095a5a8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -175,6 +175,92 @@ static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, } } +#define THM_TRIM_POSITIVE_MASK BIT(6) +#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0) + +static void rtw8922a_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 thm_trim_addr[RF_PATH_NUM_8922A] = {0x1706, 0x1733}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + bool pg = true; + u8 pg_th; + s8 val; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pg_th = phycap_map[thm_trim_addr[i] - addr]; + if (pg_th == 0xff) { + info->thermal_trim[i] = 0; + pg = false; + break; + } + + val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK); + + if (!(pg_th & THM_TRIM_POSITIVE_MASK)) + val *= -1; + + info->thermal_trim[i] = val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n", + i, pg_th, val); + } + + info->pg_thermal_trim = pg; +} + +static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pabias_trim_addr[RF_PATH_NUM_8922A] = {0x1707, 0x1734}; + static const u32 check_pa_pad_trim_addr = 0x1700; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 val; + u8 i; + + val = phycap_map[check_pa_pad_trim_addr - addr]; + if (val != 0xff) + info->pg_pa_bias_trim = true; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", + i, info->pa_bias_trim[i]); + } +} + +static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922A] = {0x1708, 0x1735}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n", + i, info->pad_bias_trim[i]); + } +} + +static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pad_bias_trim(rtwdev, phycap_map); + + return 0; +} + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -186,6 +272,7 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_efuse = rtw8922a_read_efuse, + .read_phycap = rtw8922a_read_phycap, }; const struct rtw89_chip_info rtw8922a_chip_info = { From 211ed0b3ac9a29aa228d3cbb5f2a4d6c7ddadcaf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 3 Nov 2023 22:18:16 +0200 Subject: [PATCH 1140/7721] drm/i915/dsi: assume BXT gpio works for non-native GPIO Purely a guess. Drop the nop function. Cc: Andy Shevchenko Cc: Hans de Goede Signed-off-by: Jani Nikula Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-2-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 24b2cbcfc1ef..b2c0cc11f8c1 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -372,14 +372,6 @@ static void bxt_exec_gpio(struct intel_connector *connector, gpiod_set_value(gpio_desc, value); } -static void icl_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n"); -} - enum { MIPI_RESET_1 = 0, MIPI_AVDD_EN_1, @@ -491,7 +483,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) if (native) icl_native_gpio_set_value(dev_priv, gpio_number, value); else if (DISPLAY_VER(dev_priv) >= 11) - icl_exec_gpio(connector, gpio_source, gpio_index, value); + bxt_exec_gpio(connector, gpio_source, gpio_index, value); else if (IS_VALLEYVIEW(dev_priv)) vlv_exec_gpio(connector, gpio_source, gpio_number, value); else if (IS_CHERRYVIEW(dev_priv)) From 03930e3d97565b6640a3a552d2b41252aae33f25 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 3 Nov 2023 22:18:17 +0200 Subject: [PATCH 1141/7721] drm/i915/dsi: switch mipi_exec_gpio() from dev_priv to i915 Follow the contemporary conventions. Cc: Andy Shevchenko Cc: Hans de Goede Signed-off-by: Jani Nikula Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-3-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index b2c0cc11f8c1..8b962f2ac475 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -454,11 +454,11 @@ static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv, static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) { struct drm_device *dev = intel_dsi->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *i915 = to_i915(dev); struct intel_connector *connector = intel_dsi->attached_connector; u8 gpio_source, gpio_index = 0, gpio_number; bool value; - bool native = DISPLAY_VER(dev_priv) >= 11; + bool native = DISPLAY_VER(i915) >= 11; if (connector->panel.vbt.dsi.seq_version >= 3) gpio_index = *data++; @@ -477,16 +477,16 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) /* pull up/down */ value = *data++ & 1; - drm_dbg_kms(&dev_priv->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", + drm_dbg_kms(&i915->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", gpio_index, gpio_number, gpio_source, str_yes_no(native), str_on_off(value)); if (native) - icl_native_gpio_set_value(dev_priv, gpio_number, value); - else if (DISPLAY_VER(dev_priv) >= 11) + icl_native_gpio_set_value(i915, gpio_number, value); + else if (DISPLAY_VER(i915) >= 11) bxt_exec_gpio(connector, gpio_source, gpio_index, value); - else if (IS_VALLEYVIEW(dev_priv)) + else if (IS_VALLEYVIEW(i915)) vlv_exec_gpio(connector, gpio_source, gpio_number, value); - else if (IS_CHERRYVIEW(dev_priv)) + else if (IS_CHERRYVIEW(i915)) chv_exec_gpio(connector, gpio_source, gpio_number, value); else bxt_exec_gpio(connector, gpio_source, gpio_index, value); From 703a7d2b77f74e5f53545a6d0788cd1b9d0167d6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 3 Nov 2023 22:18:18 +0200 Subject: [PATCH 1142/7721] drm/i915/dsi: clarify GPIO exec sequence With the various sequence versions and pointer increments interleaved, it's a bit hard to decipher what's going on. Add separate paths for different sequence versions. Cc: Andy Shevchenko Cc: Hans de Goede Signed-off-by: Jani Nikula Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-4-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 31 +++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 8b962f2ac475..11073efe26c0 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -456,26 +456,29 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) struct drm_device *dev = intel_dsi->base.base.dev; struct drm_i915_private *i915 = to_i915(dev); struct intel_connector *connector = intel_dsi->attached_connector; - u8 gpio_source, gpio_index = 0, gpio_number; + u8 gpio_source = 0, gpio_index = 0, gpio_number; bool value; + int size; bool native = DISPLAY_VER(i915) >= 11; - if (connector->panel.vbt.dsi.seq_version >= 3) - gpio_index = *data++; + if (connector->panel.vbt.dsi.seq_version >= 3) { + size = 3; - gpio_number = *data++; + gpio_index = data[0]; + gpio_number = data[1]; + value = data[2] & BIT(0); - /* gpio source in sequence v2 only */ - if (connector->panel.vbt.dsi.seq_version == 2) - gpio_source = (*data >> 1) & 3; - else - gpio_source = 0; + if (connector->panel.vbt.dsi.seq_version >= 4 && data[2] & BIT(1)) + native = false; + } else { + size = 2; - if (connector->panel.vbt.dsi.seq_version >= 4 && *data & BIT(1)) - native = false; + gpio_number = data[0]; + value = data[1] & BIT(0); - /* pull up/down */ - value = *data++ & 1; + if (connector->panel.vbt.dsi.seq_version == 2) + gpio_source = (data[1] >> 1) & 3; + } drm_dbg_kms(&i915->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", gpio_index, gpio_number, gpio_source, str_yes_no(native), str_on_off(value)); @@ -491,7 +494,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) else bxt_exec_gpio(connector, gpio_source, gpio_index, value); - return data; + return data + size; } #ifdef CONFIG_ACPI From ba24d15859e0277f036266bacdde031625c2dd8a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 3 Nov 2023 22:18:19 +0200 Subject: [PATCH 1143/7721] drm/i915/dsi: rename platform specific *_exec_gpio() to *_gpio_set_value() The lowest level functions are about setting GPIO values, not about executing any sequences anymore. Cc: Andy Shevchenko Cc: Hans de Goede Signed-off-by: Jani Nikula Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-5-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 11073efe26c0..f977d63a0ad4 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -243,8 +243,8 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) return data; } -static void vlv_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void vlv_gpio_set_value(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct gpio_map *map; @@ -291,8 +291,8 @@ static void vlv_exec_gpio(struct intel_connector *connector, vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); } -static void chv_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void chv_gpio_set_value(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); u16 cfg0, cfg1; @@ -345,8 +345,8 @@ static void chv_exec_gpio(struct intel_connector *connector, vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); } -static void bxt_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void bxt_gpio_set_value(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); /* XXX: this table is a quick ugly hack. */ @@ -486,13 +486,13 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) if (native) icl_native_gpio_set_value(i915, gpio_number, value); else if (DISPLAY_VER(i915) >= 11) - bxt_exec_gpio(connector, gpio_source, gpio_index, value); + bxt_gpio_set_value(connector, gpio_source, gpio_index, value); else if (IS_VALLEYVIEW(i915)) - vlv_exec_gpio(connector, gpio_source, gpio_number, value); + vlv_gpio_set_value(connector, gpio_source, gpio_number, value); else if (IS_CHERRYVIEW(i915)) - chv_exec_gpio(connector, gpio_source, gpio_number, value); + chv_gpio_set_value(connector, gpio_source, gpio_number, value); else - bxt_exec_gpio(connector, gpio_source, gpio_index, value); + bxt_gpio_set_value(connector, gpio_source, gpio_index, value); return data + size; } From acc06840fb9e22e3f7febec1ec1a976a04929cde Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 3 Nov 2023 22:18:20 +0200 Subject: [PATCH 1144/7721] drm/i915/dsi: bxt/icl GPIO set value do not need gpio source Drop the unused parameter. Cc: Andy Shevchenko Cc: Hans de Goede Signed-off-by: Jani Nikula Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-6-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index f977d63a0ad4..4af43cf3cee0 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -346,7 +346,7 @@ static void chv_gpio_set_value(struct intel_connector *connector, } static void bxt_gpio_set_value(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) + u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); /* XXX: this table is a quick ugly hack. */ @@ -486,13 +486,13 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) if (native) icl_native_gpio_set_value(i915, gpio_number, value); else if (DISPLAY_VER(i915) >= 11) - bxt_gpio_set_value(connector, gpio_source, gpio_index, value); + bxt_gpio_set_value(connector, gpio_index, value); else if (IS_VALLEYVIEW(i915)) vlv_gpio_set_value(connector, gpio_source, gpio_number, value); else if (IS_CHERRYVIEW(i915)) chv_gpio_set_value(connector, gpio_source, gpio_number, value); else - bxt_gpio_set_value(connector, gpio_source, gpio_index, value); + bxt_gpio_set_value(connector, gpio_index, value); return data + size; } From 1c8953b27d11269c9a9fa2d1bbd62bf3415749c0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:21 +0200 Subject: [PATCH 1145/7721] drm/i915/dsi: Replace while(1) with one with clear exit condition Move existing condition to while(), so it will be clear on what circumstances the loop is successfully finishing. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-7-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 4af43cf3cee0..290a112f1b63 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -702,13 +702,10 @@ static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, if (connector->panel.vbt.dsi.seq_version >= 3) data += 4; - while (1) { + while (*data != MIPI_SEQ_ELEM_END) { u8 operation_byte = *data++; u8 operation_size = 0; - if (operation_byte == MIPI_SEQ_ELEM_END) - break; - if (operation_byte < ARRAY_SIZE(exec_elem)) mipi_elem_exec = exec_elem[operation_byte]; else From a1f763fe869c6875a6649bb0c145e589e08087a0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:22 +0200 Subject: [PATCH 1146/7721] drm/i915/dsi: Get rid of redundant 'else' In the snippets like the following if (...) return / goto / break / continue ...; else ... the 'else' is redundant. Get rid of it. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-8-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 58 ++++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 290a112f1b63..4ed5ede9ec5b 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -142,7 +142,7 @@ static enum port intel_dsi_seq_port_to_port(struct intel_dsi *intel_dsi, if (seq_port) { if (intel_dsi->ports & BIT(PORT_B)) return PORT_B; - else if (intel_dsi->ports & BIT(PORT_C)) + if (intel_dsi->ports & BIT(PORT_C)) return PORT_C; } @@ -670,8 +670,8 @@ static const char *sequence_name(enum mipi_seq seq_id) { if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id]) return seq_name[seq_id]; - else - return "(unknown)"; + + return "(unknown)"; } static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, @@ -865,36 +865,34 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) * multiply by 100 to preserve remainder */ if (intel_dsi->video_mode == BURST_MODE) { - if (mipi_config->target_burst_mode_freq) { - u32 bitrate = intel_dsi_bitrate(intel_dsi); + u32 bitrate; - /* - * Sometimes the VBT contains a slightly lower clock, - * then the bitrate we have calculated, in this case - * just replace it with the calculated bitrate. - */ - if (mipi_config->target_burst_mode_freq < bitrate && - intel_fuzzy_clock_check( - mipi_config->target_burst_mode_freq, - bitrate)) - mipi_config->target_burst_mode_freq = bitrate; - - if (mipi_config->target_burst_mode_freq < bitrate) { - drm_err(&dev_priv->drm, - "Burst mode freq is less than computed\n"); - return false; - } - - burst_mode_ratio = DIV_ROUND_UP( - mipi_config->target_burst_mode_freq * 100, - bitrate); - - intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100); - } else { - drm_err(&dev_priv->drm, - "Burst mode target is not set\n"); + if (mipi_config->target_burst_mode_freq == 0) { + drm_err(&dev_priv->drm, "Burst mode target is not set\n"); return false; } + + bitrate = intel_dsi_bitrate(intel_dsi); + + /* + * Sometimes the VBT contains a slightly lower clock, then + * the bitrate we have calculated, in this case just replace it + * with the calculated bitrate. + */ + if (mipi_config->target_burst_mode_freq < bitrate && + intel_fuzzy_clock_check(mipi_config->target_burst_mode_freq, + bitrate)) + mipi_config->target_burst_mode_freq = bitrate; + + if (mipi_config->target_burst_mode_freq < bitrate) { + drm_err(&dev_priv->drm, "Burst mode freq is less than computed\n"); + return false; + } + + burst_mode_ratio = + DIV_ROUND_UP(mipi_config->target_burst_mode_freq * 100, bitrate); + + intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100); } else burst_mode_ratio = 100; From 246bcae104475136cd3eb87793726b5cc4320ad1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:23 +0200 Subject: [PATCH 1147/7721] drm/i915/dsi: Replace check with a (missing) MIPI sequence name Names of the MIPI sequence steps are sequential and defined, no need to check for the gaps. However in seq_name the MIPI_SEQ_END is missing. Add it there, and drop unneeded NULL check in sequence_name(). Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-9-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 4ed5ede9ec5b..d270437217b3 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -653,6 +653,7 @@ static const fn_mipi_elem_exec exec_elem[] = { */ static const char * const seq_name[] = { + [MIPI_SEQ_END] = "MIPI_SEQ_END", [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP", [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON", @@ -668,7 +669,7 @@ static const char * const seq_name[] = { static const char *sequence_name(enum mipi_seq seq_id) { - if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id]) + if (seq_id < ARRAY_SIZE(seq_name)) return seq_name[seq_id]; return "(unknown)"; From e2a97a08ce179ee2ac33a0e24b890fb0638ac3f5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Nov 2023 22:18:24 +0200 Subject: [PATCH 1148/7721] drm/i915/dsi: Remove GPIO lookup table at the end of intel_dsi_vbt_gpio_init() To properly deal with GPIOs used in MIPI panel sequences a temporary GPIO lookup will be used. Since there can only be 1 GPIO lookup table for the "0000:00:02.0" device this will not work if the GPIO lookup table used by intel_dsi_vbt_gpio_init() is still registered. After getting the "backlight" and "panel" GPIOs the lookup table registered by intel_dsi_vbt_gpio_init() is no longer necessary, remove it so that another temporary lookup-table for the "0000:00:02.0" device can be added. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-10-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 25 +++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index d270437217b3..8e6beef90e5e 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -955,6 +955,7 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) struct intel_connector *connector = intel_dsi->attached_connector; struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; enum gpiod_flags flags = panel_is_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + struct gpiod_lookup_table *gpiod_lookup_table = NULL; bool want_backlight_gpio = false; bool want_panel_gpio = false; struct pinctrl *pinctrl; @@ -962,12 +963,12 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && mipi_config->pwm_blc == PPS_BLC_PMIC) { - gpiod_add_lookup_table(&pmic_panel_gpio_table); + gpiod_lookup_table = &pmic_panel_gpio_table; want_panel_gpio = true; } if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { - gpiod_add_lookup_table(&soc_panel_gpio_table); + gpiod_lookup_table = &soc_panel_gpio_table; want_panel_gpio = true; want_backlight_gpio = true; @@ -984,6 +985,9 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) "Failed to set pinmux to PWM\n"); } + if (gpiod_lookup_table) + gpiod_add_lookup_table(gpiod_lookup_table); + if (want_panel_gpio) { intel_dsi->gpio_panel = gpiod_get(dev->dev, "panel", flags); if (IS_ERR(intel_dsi->gpio_panel)) { @@ -1002,15 +1006,13 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) intel_dsi->gpio_backlight = NULL; } } + + if (gpiod_lookup_table) + gpiod_remove_lookup_table(gpiod_lookup_table); } void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) { - struct drm_device *dev = intel_dsi->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_connector *connector = intel_dsi->attached_connector; - struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; - if (intel_dsi->gpio_panel) { gpiod_put(intel_dsi->gpio_panel); intel_dsi->gpio_panel = NULL; @@ -1020,13 +1022,4 @@ void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) gpiod_put(intel_dsi->gpio_backlight); intel_dsi->gpio_backlight = NULL; } - - if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - mipi_config->pwm_blc == PPS_BLC_PMIC) - gpiod_remove_lookup_table(&pmic_panel_gpio_table); - - if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { - pinctrl_unregister_mappings(soc_pwm_pinctrl_map); - gpiod_remove_lookup_table(&soc_panel_gpio_table); - } } From 61442d610f771ec4c45c3882c006644bee2cf38c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Nov 2023 22:18:25 +0200 Subject: [PATCH 1149/7721] drm/i915/dsi: Fix wrong initial value for GPIOs in bxt_gpio_set_value() Fix wrong initial value for GPIOs in bxt_gpio_set_value(). Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-11-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 8e6beef90e5e..0f9da0168a7b 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -356,9 +356,7 @@ static void bxt_gpio_set_value(struct intel_connector *connector, if (!gpio_desc) { gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, NULL, gpio_index, - value ? GPIOD_OUT_LOW : - GPIOD_OUT_HIGH); - + value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); if (IS_ERR_OR_NULL(gpio_desc)) { drm_err(&dev_priv->drm, "GPIO index %u request failed (%ld)\n", From 47ab0203946a57e3451b4b3e2b23634b27e32440 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:26 +0200 Subject: [PATCH 1150/7721] drm/i915/dsi: Extract common soc_gpio_set_value() helper Extract a common soc_gpio_set_value() helper that may be used by a few SoCs. Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-12-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 46 +++++++++++--------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 0f9da0168a7b..9847a92fdfc3 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -243,6 +243,31 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) return data; } +static void soc_gpio_set_value(struct intel_connector *connector, const char *con_id, + u8 gpio_index, bool value) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + /* XXX: this table is a quick ugly hack. */ + static struct gpio_desc *soc_gpio_table[U8_MAX + 1]; + struct gpio_desc *gpio_desc = soc_gpio_table[gpio_index]; + + if (gpio_desc) { + gpiod_set_value(gpio_desc, value); + } else { + gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, + con_id, gpio_index, + value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); + if (IS_ERR(gpio_desc)) { + drm_err(&dev_priv->drm, + "GPIO index %u request failed (%pe)\n", + gpio_index, gpio_desc); + return; + } + + soc_gpio_table[gpio_index] = gpio_desc; + } +} + static void vlv_gpio_set_value(struct intel_connector *connector, u8 gpio_source, u8 gpio_index, bool value) { @@ -348,26 +373,7 @@ static void chv_gpio_set_value(struct intel_connector *connector, static void bxt_gpio_set_value(struct intel_connector *connector, u8 gpio_index, bool value) { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - /* XXX: this table is a quick ugly hack. */ - static struct gpio_desc *bxt_gpio_table[U8_MAX + 1]; - struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index]; - - if (!gpio_desc) { - gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, - NULL, gpio_index, - value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); - if (IS_ERR_OR_NULL(gpio_desc)) { - drm_err(&dev_priv->drm, - "GPIO index %u request failed (%ld)\n", - gpio_index, PTR_ERR(gpio_desc)); - return; - } - - bxt_gpio_table[gpio_index] = gpio_desc; - } - - gpiod_set_value(gpio_desc, value); + soc_gpio_set_value(connector, NULL, gpio_index, value); } enum { From 8241b55f1ded100295ea95d72fd2e95e69776923 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:27 +0200 Subject: [PATCH 1151/7721] drm/i915/dsi: Replace poking of VLV GPIOs behind the driver's back It's a dirty hack in the driver that pokes GPIO registers behind the driver's back. Moreoever it might be problematic as simultaneous I/O may hang the system, see the commit 40ecab551232 ("pinctrl: baytrail: Really serialize all register accesses") for the details. Taking all this into consideration replace the hack with proper GPIO APIs being used. Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-13-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 98 ++++++-------------- 1 file changed, 28 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 9847a92fdfc3..552bc6564d79 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -55,43 +55,6 @@ #define MIPI_VIRTUAL_CHANNEL_SHIFT 1 #define MIPI_PORT_SHIFT 3 -/* base offsets for gpio pads */ -#define VLV_GPIO_NC_0_HV_DDI0_HPD 0x4130 -#define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA 0x4120 -#define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL 0x4110 -#define VLV_GPIO_NC_3_PANEL0_VDDEN 0x4140 -#define VLV_GPIO_NC_4_PANEL0_BKLTEN 0x4150 -#define VLV_GPIO_NC_5_PANEL0_BKLTCTL 0x4160 -#define VLV_GPIO_NC_6_HV_DDI1_HPD 0x4180 -#define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA 0x4190 -#define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL 0x4170 -#define VLV_GPIO_NC_9_PANEL1_VDDEN 0x4100 -#define VLV_GPIO_NC_10_PANEL1_BKLTEN 0x40E0 -#define VLV_GPIO_NC_11_PANEL1_BKLTCTL 0x40F0 - -#define VLV_GPIO_PCONF0(base_offset) (base_offset) -#define VLV_GPIO_PAD_VAL(base_offset) ((base_offset) + 8) - -struct gpio_map { - u16 base_offset; - bool init; -}; - -static struct gpio_map vlv_gpio_table[] = { - { VLV_GPIO_NC_0_HV_DDI0_HPD }, - { VLV_GPIO_NC_1_HV_DDI0_DDC_SDA }, - { VLV_GPIO_NC_2_HV_DDI0_DDC_SCL }, - { VLV_GPIO_NC_3_PANEL0_VDDEN }, - { VLV_GPIO_NC_4_PANEL0_BKLTEN }, - { VLV_GPIO_NC_5_PANEL0_BKLTCTL }, - { VLV_GPIO_NC_6_HV_DDI1_HPD }, - { VLV_GPIO_NC_7_HV_DDI1_DDC_SDA }, - { VLV_GPIO_NC_8_HV_DDI1_DDC_SCL }, - { VLV_GPIO_NC_9_PANEL1_VDDEN }, - { VLV_GPIO_NC_10_PANEL1_BKLTEN }, - { VLV_GPIO_NC_11_PANEL1_BKLTCTL }, -}; - struct i2c_adapter_lookup { u16 slave_addr; struct intel_dsi *intel_dsi; @@ -268,52 +231,47 @@ static void soc_gpio_set_value(struct intel_connector *connector, const char *co } } +static void soc_opaque_gpio_set_value(struct intel_connector *connector, + const char *chip, const char *con_id, + u8 gpio_index, bool value) +{ + struct gpiod_lookup_table *lookup; + + lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL); + if (!lookup) + return; + + lookup->dev_id = "0000:00:02.0"; + lookup->table[0] = + GPIO_LOOKUP_IDX(chip, gpio_index, con_id, gpio_index, GPIO_ACTIVE_HIGH); + + gpiod_add_lookup_table(lookup); + + soc_gpio_set_value(connector, con_id, gpio_index, value); + + gpiod_remove_lookup_table(lookup); + kfree(lookup); +} + static void vlv_gpio_set_value(struct intel_connector *connector, u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct gpio_map *map; - u16 pconf0, padval; - u32 tmp; - u8 port; - if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) { - drm_dbg_kms(&dev_priv->drm, "unknown gpio index %u\n", - gpio_index); - return; - } - - map = &vlv_gpio_table[gpio_index]; - - if (connector->panel.vbt.dsi.seq_version >= 3) { - /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */ - port = IOSF_PORT_GPIO_NC; - } else { - if (gpio_source == 0) { - port = IOSF_PORT_GPIO_NC; - } else if (gpio_source == 1) { + /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */ + if (connector->panel.vbt.dsi.seq_version < 3) { + if (gpio_source == 1) { drm_dbg_kms(&dev_priv->drm, "SC gpio not supported\n"); return; - } else { + } + if (gpio_source > 1) { drm_dbg_kms(&dev_priv->drm, "unknown gpio source %u\n", gpio_source); return; } } - pconf0 = VLV_GPIO_PCONF0(map->base_offset); - padval = VLV_GPIO_PAD_VAL(map->base_offset); - - vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO)); - if (!map->init) { - /* FIXME: remove constant below */ - vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00); - map->init = true; - } - - tmp = 0x4 | value; - vlv_iosf_sb_write(dev_priv, port, padval, tmp); - vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); + soc_opaque_gpio_set_value(connector, "INT33FC:01", "Panel N", gpio_index, value); } static void chv_gpio_set_value(struct intel_connector *connector, From bd079b19b417d835a671649a27271918700f2fd9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:28 +0200 Subject: [PATCH 1152/7721] drm/i915/dsi: Prepare soc_gpio_set_value() to distinguish GPIO communities Currently soc_gpio_set_value() supports only a single indexing for GPIO pin. For CHV case, for example, we will need to distinguish community based index from the one that VBT is using. Introduce an additional parameter to soc_gpio_set_value() and its callers. Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-14-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 552bc6564d79..b1736c1301ea 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -206,8 +206,8 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) return data; } -static void soc_gpio_set_value(struct intel_connector *connector, const char *con_id, - u8 gpio_index, bool value) +static void soc_gpio_set_value(struct intel_connector *connector, u8 gpio_index, + const char *con_id, u8 idx, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); /* XXX: this table is a quick ugly hack. */ @@ -217,8 +217,7 @@ static void soc_gpio_set_value(struct intel_connector *connector, const char *co if (gpio_desc) { gpiod_set_value(gpio_desc, value); } else { - gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, - con_id, gpio_index, + gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, con_id, idx, value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); if (IS_ERR(gpio_desc)) { drm_err(&dev_priv->drm, @@ -232,8 +231,8 @@ static void soc_gpio_set_value(struct intel_connector *connector, const char *co } static void soc_opaque_gpio_set_value(struct intel_connector *connector, - const char *chip, const char *con_id, - u8 gpio_index, bool value) + u8 gpio_index, const char *chip, + const char *con_id, u8 idx, bool value) { struct gpiod_lookup_table *lookup; @@ -243,11 +242,11 @@ static void soc_opaque_gpio_set_value(struct intel_connector *connector, lookup->dev_id = "0000:00:02.0"; lookup->table[0] = - GPIO_LOOKUP_IDX(chip, gpio_index, con_id, gpio_index, GPIO_ACTIVE_HIGH); + GPIO_LOOKUP_IDX(chip, idx, con_id, idx, GPIO_ACTIVE_HIGH); gpiod_add_lookup_table(lookup); - soc_gpio_set_value(connector, con_id, gpio_index, value); + soc_gpio_set_value(connector, gpio_index, con_id, idx, value); gpiod_remove_lookup_table(lookup); kfree(lookup); @@ -271,7 +270,8 @@ static void vlv_gpio_set_value(struct intel_connector *connector, } } - soc_opaque_gpio_set_value(connector, "INT33FC:01", "Panel N", gpio_index, value); + soc_opaque_gpio_set_value(connector, gpio_index, + "INT33FC:01", "Panel N", gpio_index, value); } static void chv_gpio_set_value(struct intel_connector *connector, @@ -331,7 +331,7 @@ static void chv_gpio_set_value(struct intel_connector *connector, static void bxt_gpio_set_value(struct intel_connector *connector, u8 gpio_index, bool value) { - soc_gpio_set_value(connector, NULL, gpio_index, value); + soc_gpio_set_value(connector, gpio_index, NULL, gpio_index, value); } enum { From a23e60938a7dfdac11bbacf1f5da4a99c46432e1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:29 +0200 Subject: [PATCH 1153/7721] drm/i915/dsi: Replace poking of CHV GPIOs behind the driver's back It's a dirty hack in the driver that pokes GPIO registers behind the driver's back. Moreoever it might be problematic as simultaneous I/O may hang the system, see the commit 0bd50d719b00 ("pinctrl: cherryview: prevent concurrent access to GPIO controllers") for the details. Taking all this into consideration replace the hack with proper GPIO APIs being used. Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-15-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 47 +++++--------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index b1736c1301ea..9c6946ccb193 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -66,19 +66,6 @@ struct i2c_adapter_lookup { #define CHV_GPIO_IDX_START_SW 100 #define CHV_GPIO_IDX_START_SE 198 -#define CHV_VBT_MAX_PINS_PER_FMLY 15 - -#define CHV_GPIO_PAD_CFG0(f, i) (0x4400 + (f) * 0x400 + (i) * 8) -#define CHV_GPIO_GPIOEN (1 << 15) -#define CHV_GPIO_GPIOCFG_GPIO (0 << 8) -#define CHV_GPIO_GPIOCFG_GPO (1 << 8) -#define CHV_GPIO_GPIOCFG_GPI (2 << 8) -#define CHV_GPIO_GPIOCFG_HIZ (3 << 8) -#define CHV_GPIO_GPIOTXSTATE(state) ((!!(state)) << 1) - -#define CHV_GPIO_PAD_CFG1(f, i) (0x4400 + (f) * 0x400 + (i) * 8 + 4) -#define CHV_GPIO_CFGLOCK (1 << 31) - /* ICL DSI Display GPIO Pins */ #define ICL_GPIO_DDSP_HPD_A 0 #define ICL_GPIO_L_VDDEN_1 1 @@ -278,23 +265,21 @@ static void chv_gpio_set_value(struct intel_connector *connector, u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - u16 cfg0, cfg1; - u16 family_num; - u8 port; if (connector->panel.vbt.dsi.seq_version >= 3) { if (gpio_index >= CHV_GPIO_IDX_START_SE) { /* XXX: it's unclear whether 255->57 is part of SE. */ - gpio_index -= CHV_GPIO_IDX_START_SE; - port = CHV_IOSF_PORT_GPIO_SE; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:03", "Panel SE", + gpio_index - CHV_GPIO_IDX_START_SE, value); } else if (gpio_index >= CHV_GPIO_IDX_START_SW) { - gpio_index -= CHV_GPIO_IDX_START_SW; - port = CHV_IOSF_PORT_GPIO_SW; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:00", "Panel SW", + gpio_index - CHV_GPIO_IDX_START_SW, value); } else if (gpio_index >= CHV_GPIO_IDX_START_E) { - gpio_index -= CHV_GPIO_IDX_START_E; - port = CHV_IOSF_PORT_GPIO_E; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:02", "Panel E", + gpio_index - CHV_GPIO_IDX_START_E, value); } else { - port = CHV_IOSF_PORT_GPIO_N; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:01", "Panel N", + gpio_index - CHV_GPIO_IDX_START_N, value); } } else { /* XXX: The spec is unclear about CHV GPIO on seq v2 */ @@ -311,21 +296,9 @@ static void chv_gpio_set_value(struct intel_connector *connector, return; } - port = CHV_IOSF_PORT_GPIO_N; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:01", "Panel N", + gpio_index - CHV_GPIO_IDX_START_N, value); } - - family_num = gpio_index / CHV_VBT_MAX_PINS_PER_FMLY; - gpio_index = gpio_index % CHV_VBT_MAX_PINS_PER_FMLY; - - cfg0 = CHV_GPIO_PAD_CFG0(family_num, gpio_index); - cfg1 = CHV_GPIO_PAD_CFG1(family_num, gpio_index); - - vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO)); - vlv_iosf_sb_write(dev_priv, port, cfg1, 0); - vlv_iosf_sb_write(dev_priv, port, cfg0, - CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO | - CHV_GPIO_GPIOTXSTATE(value)); - vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); } static void bxt_gpio_set_value(struct intel_connector *connector, From 08c3d1f91f41d930f7cca3672d9aa1eec68e2c4b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:30 +0200 Subject: [PATCH 1154/7721] drm/i915/dsi: Combine checks in mipi_exec_gpio() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a couple of cases the branches call the same bxt_gpio_set_value(). As Ville suggested they can be combined by dropping the DISPLAY_VER() check from Gen 11 to Gen 9. Do it that way. Suggested-by: Ville Syrjälä Signed-off-by: Andy Shevchenko Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-16-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 9c6946ccb193..275d0218394c 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -420,14 +420,12 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) if (native) icl_native_gpio_set_value(i915, gpio_number, value); - else if (DISPLAY_VER(i915) >= 11) + else if (DISPLAY_VER(i915) >= 9) bxt_gpio_set_value(connector, gpio_index, value); else if (IS_VALLEYVIEW(i915)) vlv_gpio_set_value(connector, gpio_source, gpio_number, value); else if (IS_CHERRYVIEW(i915)) chv_gpio_set_value(connector, gpio_source, gpio_number, value); - else - bxt_gpio_set_value(connector, gpio_index, value); return data + size; } From f52ffea0745943bb6af674f30f4243b3721b7cd6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2023 22:18:31 +0200 Subject: [PATCH 1155/7721] drm/i915/iosf: Drop unused APIs Drop unused vlv_iosf_sb_read() and vlv_iosf_sb_write(). Signed-off-by: Andy Shevchenko Acked-by: Jani Nikula Tested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231103201831.1037416-17-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/vlv_sideband.c | 17 ----------------- drivers/gpu/drm/i915/vlv_sideband.h | 3 --- 2 files changed, 20 deletions(-) diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c index 63a795876309..ffa195560d0d 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.c +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -166,23 +166,6 @@ u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr) return val; } -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRWRDA_NP, reg, &val); -} - u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg) { u32 val = 0; diff --git a/drivers/gpu/drm/i915/vlv_sideband.h b/drivers/gpu/drm/i915/vlv_sideband.h index 4073966860e2..c20cf41b2d39 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.h +++ b/drivers/gpu/drm/i915/vlv_sideband.h @@ -26,9 +26,6 @@ enum { }; void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports); -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg); -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val); void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports); static inline void vlv_bunit_get(struct drm_i915_private *i915) From 08500f6eaa914019d36861a1e1f868d3ccd73781 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 2 Nov 2023 14:54:52 +0300 Subject: [PATCH 1156/7721] wifi: ath10k: simplify __ath10k_htt_tx_txq_recalc() Since 'ieee80211_txq_get_depth()' allows NULL for 2nd and 3rd arguments, simplify '__ath10k_htt_tx_txq_recalc()' by dropping unused 'frame_cnt'. Compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231102115459.69791-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath10k/htt_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index be4d4536aaa8..5d814162e02b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -40,7 +40,6 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_sta *arsta; struct ath10k_vif *arvif = (void *)txq->vif->drv_priv; - unsigned long frame_cnt; unsigned long byte_cnt; int idx; u32 bit; @@ -67,7 +66,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, bit = BIT(peer_id % 32); idx = peer_id / 32; - ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + ieee80211_txq_get_depth(txq, NULL, &byte_cnt); count = ath10k_htt_tx_txq_calc_size(byte_cnt); if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) || From 2bc76fef1a9a649e11b2dac6205bb8177128fc21 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 3 Nov 2023 15:05:36 -0700 Subject: [PATCH 1157/7721] wifi: ath10k: Remove unused struct ath10k_htc_frame struct ath10k_htc_frame is unused, and since it illogically contains two consecutive flexible arrays, it could never be used, so remove it. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231103-ath10k_htc_frame-v1-1-ff00b38a9630@quicinc.com --- drivers/net/wireless/ath/ath10k/htc.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 0d180faf3b77..0eaa21ad86ac 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -253,19 +253,6 @@ struct ath10k_htc_record { }; } __packed __aligned(4); -/* - * note: the trailer offset is dynamic depending - * on payload length. this is only a struct layout draft - */ -struct ath10k_htc_frame { - struct ath10k_htc_hdr hdr; - union { - struct ath10k_htc_msg msg; - u8 payload[0]; - }; - struct ath10k_htc_record trailer[0]; -} __packed __aligned(4); - /*******************/ /* Host-side stuff */ /*******************/ From 199a78565cc2bf3fee530cade297e309de5a1f3a Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:21:04 -0800 Subject: [PATCH 1158/7721] wifi: ath11k: Remove struct ath11k::ops Currently struct ath11k defines the following member: struct ieee80211_ops *ops; This is being flagged by checkpatch.pl: WARNING: struct ieee80211_ops should normally be const The original plan was to add the const qualifier. However, it turns out this is actually unused, so remove it. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath12k-remove-ieee80211_ops-v1-1-d72cef1a855b@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index f12b606e2d2e..7e3b6779f4e9 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -599,7 +599,6 @@ struct ath11k { struct ath11k_base *ab; struct ath11k_pdev *pdev; struct ieee80211_hw *hw; - struct ieee80211_ops *ops; struct ath11k_pdev_wmi *wmi; struct ath11k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; From 3b6ec0409fe8c95e74fa64ee717fb7c7e6e9b32f Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:21:05 -0800 Subject: [PATCH 1159/7721] wifi: ath12k: Remove struct ath12k::ops Currently struct ath12k defines the following member: struct ieee80211_ops *ops; This is being flagged by checkpatch.pl: WARNING: struct ieee80211_ops should normally be const The original plan was to add the const qualifier. However, it turns out this is actually unused, so remove it. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath12k-remove-ieee80211_ops-v1-2-d72cef1a855b@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 68c42ca44fcb..6dbe817d2ec7 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -467,7 +467,6 @@ struct ath12k { struct ath12k_base *ab; struct ath12k_pdev *pdev; struct ieee80211_hw *hw; - struct ieee80211_ops *ops; struct ath12k_wmi_pdev *wmi; struct ath12k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; From 53bcb41d9eda23123924d25fc2a024b85b3adc0e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:26:03 -0800 Subject: [PATCH 1160/7721] wifi: ath11k: Remove obsolete struct wmi_peer_flags_map *peer_flags Currently both struct ath11k_pdev_wmi and struct ath11k_wmi_base define: const struct wmi_peer_flags_map *peer_flags; But that member is not used, and in fact, struct wmi_peer_flags_map is not defined within ath11k; these are obsolete remnants inherited from ath10k. So remove them. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath-peer-flags-v1-1-781e83b7e8e8@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 100bb816b592..42e4234be69b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2580,7 +2580,6 @@ struct wmi_service_available_event { struct ath11k_pdev_wmi { struct ath11k_wmi_base *wmi_ab; enum ath11k_htc_ep_id eid; - const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; wait_queue_head_t tx_ce_desc_wq; }; @@ -5754,7 +5753,6 @@ struct ath11k_wmi_base { struct completion unified_ready; DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; - const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; u32 rx_decap_mode; struct wmi_host_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; From 69bc79faa616c7e7258a06b1141b7b4cffb7823c Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:26:04 -0800 Subject: [PATCH 1161/7721] wifi: ath12k: Remove obsolete struct wmi_peer_flags_map *peer_flags Currently both struct ath12k_wmi_pdev and struct ath12k_wmi_base define: const struct wmi_peer_flags_map *peer_flags; But that member is not used, and in fact, struct wmi_peer_flags_map is not defined within ath12k; these are obsolete remnants inherited from ath11k. So remove them. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath-peer-flags-v1-2-781e83b7e8e8@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 629373d67421..7d295330e6f1 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4770,7 +4770,6 @@ struct wmi_probe_tmpl_cmd { struct ath12k_wmi_pdev { struct ath12k_wmi_base *wmi_ab; enum ath12k_htc_ep_id eid; - const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; }; @@ -4784,7 +4783,6 @@ struct ath12k_wmi_base { struct completion unified_ready; DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; - const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; u32 rx_decap_mode; struct ath12k_wmi_host_mem_chunk_arg mem_chunks[WMI_MAX_MEM_REQS]; From 7d4a70201204def2d771571518efcbe37ee6b85d Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:26:05 -0800 Subject: [PATCH 1162/7721] wifi: ath11k: Consolidate WMI peer flags Currently wmi.h has two separate set of definitions for peer flags. One set of flags is defined in enum wmi_tlv_peer_flags, and, except for the last three, are named WMI_TLV_PEER_*. The other set of flags are defined as macros, and are named WMI_PEER_*. The last three macros have the same name as the last three wmi_tlv_peer_flags enumerators. The code only uses the WMI_PEER_* names; the WMI_TLV_PEER_* names are unused. So as a first step in consolidation, remove all the WMI_TLV_PEER_* names. But since having an enum to define all the flags is actually a good thing since that provides a handle by which to refer to the entire set of flags, recast the WMI_PEER_* macros into enumerators. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath-peer-flags-v1-3-781e83b7e8e8@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.h | 59 ++++++++------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 42e4234be69b..3ad29d5d0999 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1096,25 +1096,27 @@ enum wmi_tlv_vdev_param { }; enum wmi_tlv_peer_flags { - WMI_TLV_PEER_AUTH = 0x00000001, - WMI_TLV_PEER_QOS = 0x00000002, - WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004, - WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010, - WMI_TLV_PEER_APSD = 0x00000800, - WMI_TLV_PEER_HT = 0x00001000, - WMI_TLV_PEER_40MHZ = 0x00002000, - WMI_TLV_PEER_STBC = 0x00008000, - WMI_TLV_PEER_LDPC = 0x00010000, - WMI_TLV_PEER_DYN_MIMOPS = 0x00020000, - WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000, - WMI_TLV_PEER_SPATIAL_MUX = 0x00200000, - WMI_TLV_PEER_VHT = 0x02000000, - WMI_TLV_PEER_80MHZ = 0x04000000, - WMI_TLV_PEER_PMF = 0x08000000, + WMI_PEER_AUTH = 0x00000001, + WMI_PEER_QOS = 0x00000002, + WMI_PEER_NEED_PTK_4_WAY = 0x00000004, + WMI_PEER_NEED_GTK_2_WAY = 0x00000010, + WMI_PEER_HE = 0x00000400, + WMI_PEER_APSD = 0x00000800, + WMI_PEER_HT = 0x00001000, + WMI_PEER_40MHZ = 0x00002000, + WMI_PEER_STBC = 0x00008000, + WMI_PEER_LDPC = 0x00010000, + WMI_PEER_DYN_MIMOPS = 0x00020000, + WMI_PEER_STATIC_MIMOPS = 0x00040000, + WMI_PEER_SPATIAL_MUX = 0x00200000, + WMI_PEER_TWT_REQ = 0x00400000, + WMI_PEER_TWT_RESP = 0x00800000, + WMI_PEER_VHT = 0x02000000, + WMI_PEER_80MHZ = 0x04000000, + WMI_PEER_PMF = 0x08000000, WMI_PEER_IS_P2P_CAPABLE = 0x20000000, WMI_PEER_160MHZ = 0x40000000, WMI_PEER_SAFEMODE_EN = 0x80000000, - }; /** Enum list of TLV Tags for each parameter structure type. */ @@ -4061,31 +4063,6 @@ struct wmi_unit_test_cmd { #define MAX_SUPPORTED_RATES 128 -#define WMI_PEER_AUTH 0x00000001 -#define WMI_PEER_QOS 0x00000002 -#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 -#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 -#define WMI_PEER_HE 0x00000400 -#define WMI_PEER_APSD 0x00000800 -#define WMI_PEER_HT 0x00001000 -#define WMI_PEER_40MHZ 0x00002000 -#define WMI_PEER_STBC 0x00008000 -#define WMI_PEER_LDPC 0x00010000 -#define WMI_PEER_DYN_MIMOPS 0x00020000 -#define WMI_PEER_STATIC_MIMOPS 0x00040000 -#define WMI_PEER_SPATIAL_MUX 0x00200000 -#define WMI_PEER_TWT_REQ 0x00400000 -#define WMI_PEER_TWT_RESP 0x00800000 -#define WMI_PEER_VHT 0x02000000 -#define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 -/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. - * Need to be cleaned up - */ -#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 -#define WMI_PEER_160MHZ 0x40000000 -#define WMI_PEER_SAFEMODE_EN 0x80000000 - struct beacon_tmpl_params { u8 vdev_id; u32 tim_ie_offset; From 51516d9842a35809cb8b9238d61b07355a61f0ec Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Nov 2023 10:26:06 -0800 Subject: [PATCH 1163/7721] wifi: ath12k: Consolidate WMI peer flags Currently wmi.h has two separate set of definitions for peer flags. One set of flags is defined in enum wmi_tlv_peer_flags, and, except for the last three, are named WMI_TLV_PEER_*. The other set of flags are defined as macros, and are named WMI_PEER_*. The last three macros have the same name as the last three wmi_tlv_peer_flags enumerators. The code only uses the WMI_PEER_* names; the WMI_TLV_PEER_* names are unused. So as a first step in consolidation, remove all the WMI_TLV_PEER_* names. But since having an enum to define all the flags is actually a good thing since that provides a handle by which to refer to the entire set of flags, recast the WMI_PEER_* macros into enumerators. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231106-ath-peer-flags-v1-4-781e83b7e8e8@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 61 +++++++++------------------ 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 7d295330e6f1..811aeea34e34 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_WMI_H @@ -1146,25 +1146,27 @@ enum wmi_tlv_vdev_param { }; enum wmi_tlv_peer_flags { - WMI_TLV_PEER_AUTH = 0x00000001, - WMI_TLV_PEER_QOS = 0x00000002, - WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004, - WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010, - WMI_TLV_PEER_APSD = 0x00000800, - WMI_TLV_PEER_HT = 0x00001000, - WMI_TLV_PEER_40MHZ = 0x00002000, - WMI_TLV_PEER_STBC = 0x00008000, - WMI_TLV_PEER_LDPC = 0x00010000, - WMI_TLV_PEER_DYN_MIMOPS = 0x00020000, - WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000, - WMI_TLV_PEER_SPATIAL_MUX = 0x00200000, - WMI_TLV_PEER_VHT = 0x02000000, - WMI_TLV_PEER_80MHZ = 0x04000000, - WMI_TLV_PEER_PMF = 0x08000000, + WMI_PEER_AUTH = 0x00000001, + WMI_PEER_QOS = 0x00000002, + WMI_PEER_NEED_PTK_4_WAY = 0x00000004, + WMI_PEER_NEED_GTK_2_WAY = 0x00000010, + WMI_PEER_HE = 0x00000400, + WMI_PEER_APSD = 0x00000800, + WMI_PEER_HT = 0x00001000, + WMI_PEER_40MHZ = 0x00002000, + WMI_PEER_STBC = 0x00008000, + WMI_PEER_LDPC = 0x00010000, + WMI_PEER_DYN_MIMOPS = 0x00020000, + WMI_PEER_STATIC_MIMOPS = 0x00040000, + WMI_PEER_SPATIAL_MUX = 0x00200000, + WMI_PEER_TWT_REQ = 0x00400000, + WMI_PEER_TWT_RESP = 0x00800000, + WMI_PEER_VHT = 0x02000000, + WMI_PEER_80MHZ = 0x04000000, + WMI_PEER_PMF = 0x08000000, WMI_PEER_IS_P2P_CAPABLE = 0x20000000, WMI_PEER_160MHZ = 0x40000000, WMI_PEER_SAFEMODE_EN = 0x80000000, - }; enum wmi_tlv_peer_flags_ext { @@ -3844,31 +3846,6 @@ struct wmi_unit_test_cmd { #define MAX_SUPPORTED_RATES 128 -#define WMI_PEER_AUTH 0x00000001 -#define WMI_PEER_QOS 0x00000002 -#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 -#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 -#define WMI_PEER_HE 0x00000400 -#define WMI_PEER_APSD 0x00000800 -#define WMI_PEER_HT 0x00001000 -#define WMI_PEER_40MHZ 0x00002000 -#define WMI_PEER_STBC 0x00008000 -#define WMI_PEER_LDPC 0x00010000 -#define WMI_PEER_DYN_MIMOPS 0x00020000 -#define WMI_PEER_STATIC_MIMOPS 0x00040000 -#define WMI_PEER_SPATIAL_MUX 0x00200000 -#define WMI_PEER_TWT_REQ 0x00400000 -#define WMI_PEER_TWT_RESP 0x00800000 -#define WMI_PEER_VHT 0x02000000 -#define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 -/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. - * Need to be cleaned up - */ -#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 -#define WMI_PEER_160MHZ 0x40000000 -#define WMI_PEER_SAFEMODE_EN 0x80000000 - struct ath12k_wmi_vht_rate_set_params { __le32 tlv_header; __le32 rx_max_rate; From b3c5a7de9aeb51cb19160f3f61343ed87487abde Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 22 Nov 2023 08:49:26 +0800 Subject: [PATCH 1164/7721] drm/nouveau/fifo: Remove duplicated include in chan.c ./drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c: chid.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7603 Signed-off-by: Yang Li Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20231122004926.84933-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 87a62d4ff4bd..7d4716dcd512 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -24,7 +24,6 @@ #include "chan.h" #include "chid.h" #include "cgrp.h" -#include "chid.h" #include "runl.h" #include "priv.h" From 1080b5c0c1a62a36dc29eb6e4dfedf7c9eaf8679 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Nov 2023 18:16:28 +0100 Subject: [PATCH 1165/7721] of: fix recursion typo in kernel doc Fix a typo in the kernel doc for the of_platform_depopulate() functions, which remove children "recursively". Signed-off-by: Johan Hovold Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20231117171628.20139-1-johan+linaro@kernel.org Signed-off-by: Rob Herring --- drivers/of/platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 126d265aa7d8..2293059758d1 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -668,7 +668,7 @@ EXPORT_SYMBOL_GPL(of_platform_device_destroy); * @parent: device which children will be removed * * Complementary to of_platform_populate(), this function removes children - * of the given device (and, recurrently, their children) that have been + * of the given device (and, recursively, their children) that have been * created from their respective device tree nodes (and only those, * leaving others - eg. manually created - unharmed). */ @@ -737,7 +737,7 @@ static int devm_of_platform_match(struct device *dev, void *res, void *data) * @dev: device that requested to depopulate from device tree data * * Complementary to devm_of_platform_populate(), this function removes children - * of the given device (and, recurrently, their children) that have been + * of the given device (and, recursively, their children) that have been * created from their respective device tree nodes (and only those, * leaving others - eg. manually created - unharmed). */ From f4814c20d14ca168382e8887c768f290e4a2a861 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 22 Nov 2023 23:18:29 +0100 Subject: [PATCH 1166/7721] drm/rockchip: rk3066_hdmi: include drm/drm_atomic.h Without this header, the newly added code fails to build: drivers/gpu/drm/rockchip/rk3066_hdmi.c: In function 'rk3066_hdmi_encoder_enable': drivers/gpu/drm/rockchip/rk3066_hdmi.c:397:22: error: implicit declaration of function 'drm_atomic_get_new_connector_state'; did you mean 'drm_atomic_helper_connector_reset'? [-Werror=implicit-function-declaration] 397 | conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | drm_atomic_helper_connector_reset drivers/gpu/drm/rockchip/rk3066_hdmi.c:397:20: error: assignment to 'struct drm_connector_state *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion] 397 | conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); | ^ drivers/gpu/drm/rockchip/rk3066_hdmi.c:401:22: error: implicit declaration of function 'drm_atomic_get_new_crtc_state'; did you mean 'drm_atomic_helper_swap_state'? [-Werror=implicit-function-declaration] 401 | crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | drm_atomic_helper_swap_state drivers/gpu/drm/rockchip/rk3066_hdmi.c:401:20: error: assignment to 'struct drm_crtc_state *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion] 401 | crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); | ^ Fixes: ae3436a5e7c2 ("drm/rockchip: rk3066_hdmi: Switch encoder hooks to atomic") Signed-off-by: Arnd Bergmann Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231122221838.3164349-1-arnd@kernel.org --- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 0e7aae341960..7d561c5a650f 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -4,6 +4,7 @@ * Zheng Yang */ +#include #include #include #include From 69dcbbd80421a5d8230c178e01869f8e2edb2317 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Oct 2023 09:52:19 -0700 Subject: [PATCH 1167/7721] locktorture: Increase Hamming distance between call_rcu_chain and rcu_call_chains One letter difference is really not enough, so this commit changes call_rcu_chain to call_rcu_chain_list. Reported-by: Dan Carpenter Signed-off-by: Paul E. McKenney Signed-off-by: Neeraj Upadhyay (AMD) --- kernel/locking/locktorture.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index 69d3cd2cfc3b..415d81e6ce70 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -124,7 +124,7 @@ struct call_rcu_chain { struct rcu_head crc_rh; bool crc_stop; }; -struct call_rcu_chain *call_rcu_chain; +struct call_rcu_chain *call_rcu_chain_list; /* Forward reference. */ static void lock_torture_cleanup(void); @@ -1074,12 +1074,12 @@ static int call_rcu_chain_init(void) if (call_rcu_chains <= 0) return 0; - call_rcu_chain = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain), GFP_KERNEL); - if (!call_rcu_chain) + call_rcu_chain_list = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain_list), GFP_KERNEL); + if (!call_rcu_chain_list) return -ENOMEM; for (i = 0; i < call_rcu_chains; i++) { - call_rcu_chain[i].crc_stop = false; - call_rcu(&call_rcu_chain[i].crc_rh, call_rcu_chain_cb); + call_rcu_chain_list[i].crc_stop = false; + call_rcu(&call_rcu_chain_list[i].crc_rh, call_rcu_chain_cb); } return 0; } @@ -1089,13 +1089,13 @@ static void call_rcu_chain_cleanup(void) { int i; - if (!call_rcu_chain) + if (!call_rcu_chain_list) return; for (i = 0; i < call_rcu_chains; i++) - smp_store_release(&call_rcu_chain[i].crc_stop, true); + smp_store_release(&call_rcu_chain_list[i].crc_stop, true); rcu_barrier(); - kfree(call_rcu_chain); - call_rcu_chain = NULL; + kfree(call_rcu_chain_list); + call_rcu_chain_list = NULL; } static void lock_torture_cleanup(void) From 454723b1615f7423fcba0b8f722cef4992a1846f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 16 Oct 2023 00:25:14 +0200 Subject: [PATCH 1168/7721] rcutorture: add nolibc init support for mips, ppc and rv64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use nolibc for all support architectures. Signed-off-by: Thomas Weißschuh Signed-off-by: Paul E. McKenney Signed-off-by: Neeraj Upadhyay (AMD) --- tools/testing/selftests/rcutorture/bin/mkinitrd.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh index 212c52ca90b5..f3f867129560 100755 --- a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh +++ b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh @@ -67,7 +67,10 @@ ___EOF___ # build using nolibc on supported archs (smaller executable) and fall # back to regular glibc on other ones. if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \ - "||__ARM_EABI__||__aarch64__||__s390x__||__loongarch__\nyes\n#endif" \ + "||__ARM_EABI__||__aarch64__||(__mips__ && _ABIO32)" \ + "||__powerpc__||(__riscv && __riscv_xlen == 64)" \ + "||__s390x__||__loongarch__" \ + "\nyes\n#endif" \ | ${CROSS_COMPILE}gcc -E -nostdlib -xc - \ | grep -q '^yes'; then # architecture supported by nolibc From af19a2526cba92082723b98fcf191a595054a952 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 1 Nov 2023 10:30:56 -0700 Subject: [PATCH 1169/7721] rcutorture: Add mid-sized stall to TREE07 There is code in rcu_implicit_dynticks_qs() that checks for the current grace period being halfway to the RCU CPU stall timeout, but rcutorture currently does not test this code. This commit therefore adds a 14-second stall to the TREE07 scenario in order to test this code given the default RCU CPU stall warning timeout of 21 seconds. Signed-off-by: Paul E. McKenney Signed-off-by: Neeraj Upadhyay (AMD) --- tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot index d44609937503..979edbf4c820 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot @@ -1 +1,4 @@ nohz_full=2-9 +rcutorture.stall_cpu=14 +rcutorture.stall_cpu_holdoff=90 +rcutorture.fwd_progress=0 From 90f1015dfee3d33f8ca7bfe03296d100d465e385 Mon Sep 17 00:00:00 2001 From: Zqiang Date: Fri, 3 Nov 2023 15:26:39 +0800 Subject: [PATCH 1170/7721] rcutorture: Add fqs_holdoff check before fqs_task is created For rcutorture tests on RCU implementations that support force-quiescent-state operations and that set the fqs_duration module parameter greater than zero, the fqs_task kthread will be created. However, if the fqs_holdoff module parameter is not set, then its default value of zero will cause fqs_task enter a long-term busy loop until stopped by kthread_stop(). This commit therefore adds a fqs_holdoff check before the fqs_task is created, making sure that whenever the fqs_task is created, the fqs_holdoff will be greater than zero. Signed-off-by: Zqiang Signed-off-by: Paul E. McKenney Signed-off-by: Neeraj Upadhyay (AMD) --- kernel/rcu/rcutorture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 30fc9d34e329..a0b2520bd32b 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -3872,7 +3872,9 @@ rcu_torture_init(void) } if (fqs_duration < 0) fqs_duration = 0; - if (fqs_duration) { + if (fqs_holdoff < 0) + fqs_holdoff = 0; + if (fqs_duration && fqs_holdoff) { /* Create the fqs thread */ firsterr = torture_create_kthread(rcu_torture_fqs, NULL, fqs_task); From 2bb7a27bd7c311c4928d6a8b5edf4b2aaa948ea8 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Thu, 16 Nov 2023 11:05:12 +0200 Subject: [PATCH 1171/7721] drm/i915/display: Use int type for entry_setup_frames entry_setup_frames variable is defined as u8. However, the function call intel_psr_entry_setup_frames() can return negative error code. There is a type mismatch here, so let's switch to use int here as well. Fixes: 2b981d57e480 ("drm/i915/display: Support PSR entry VSC packet to be transmitted one frame earlier") Signed-off-by: Mika Kahola Reviewed-by: Vinod Govindapillai Link: https://patchwork.freedesktop.org/patch/msgid/20231116090512.480373-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 8d180132a74b..204da50e3f28 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1319,7 +1319,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp, { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - u8 entry_setup_frames; + int entry_setup_frames; /* * Current PSR panels don't work reliably with VRR enabled From 8a9fd9ecc4f1f72839c94cc2ec6846d6d9a71987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 20 Nov 2023 15:02:14 +0200 Subject: [PATCH 1172/7721] drm/i915/display: Do not check psr2 if psr/panel replay is not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not continue to psr2 checks if psr or panel replay is not supported. Cc: Animesh Manna Fixes: b8cf5b5d266e ("drm/i915/panelreplay: Initializaton and compute config for panel replay") Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9670 Signed-off-by: Jouni Högander Reviewed-by: Animesh Manna Link: https://patchwork.freedesktop.org/patch/msgid/20231120130214.3332726-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 204da50e3f28..15c1804dcd59 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1373,6 +1373,9 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, else crtc_state->has_psr = _psr_compute_config(intel_dp, crtc_state); + if (!(crtc_state->has_panel_replay || crtc_state->has_psr)) + return; + crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); From 66b73e9a402d822723b3af5263eb12d735628eac Mon Sep 17 00:00:00 2001 From: Matt Coster Date: Wed, 22 Nov 2023 16:34:22 +0000 Subject: [PATCH 1173/7721] sizes.h: Add entries between SZ_32G and SZ_64T sizes.h has a gap in defines between SZ_32G and SZ_64T. Add the missing defines so they can be used in drivers. Signed-off-by: Matt Coster Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/58b227d96f27859b453caf0ceaaac81a6616304b.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- include/linux/sizes.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/sizes.h b/include/linux/sizes.h index 84aa448d8bb3..c3a00b967d18 100644 --- a/include/linux/sizes.h +++ b/include/linux/sizes.h @@ -47,8 +47,17 @@ #define SZ_8G _AC(0x200000000, ULL) #define SZ_16G _AC(0x400000000, ULL) #define SZ_32G _AC(0x800000000, ULL) +#define SZ_64G _AC(0x1000000000, ULL) +#define SZ_128G _AC(0x2000000000, ULL) +#define SZ_256G _AC(0x4000000000, ULL) +#define SZ_512G _AC(0x8000000000, ULL) #define SZ_1T _AC(0x10000000000, ULL) +#define SZ_2T _AC(0x20000000000, ULL) +#define SZ_4T _AC(0x40000000000, ULL) +#define SZ_8T _AC(0x80000000000, ULL) +#define SZ_16T _AC(0x100000000000, ULL) +#define SZ_32T _AC(0x200000000000, ULL) #define SZ_64T _AC(0x400000000000, ULL) #endif /* __LINUX_SIZES_H__ */ From a191f73d85484f804284674c14f2d9f572c18adb Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Wed, 22 Nov 2023 16:34:23 +0000 Subject: [PATCH 1174/7721] drm/gpuvm: Helper to get range of unmap from a remap op. Determining the start and range of the unmap stage of a remap op is a common piece of code currently implemented by multiple drivers. Add a helper for this. Changes since v7: - Renamed helper to drm_gpuva_op_remap_to_unmap_range() - Improved documentation Changes since v6: - Remove use of __always_inline Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Reviewed-by: Danilo Krummrich Link: https://lore.kernel.org/r/8a0a5b5eeec459d3c60fcdaa5a638ad14a18a59e.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- include/drm/drm_gpuvm.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 8ca10461d8ac..f94fec9a8517 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -1213,4 +1213,32 @@ void drm_gpuva_remap(struct drm_gpuva *prev, void drm_gpuva_unmap(struct drm_gpuva_op_unmap *op); +/** + * drm_gpuva_op_remap_to_unmap_range() - Helper to get the start and range of + * the unmap stage of a remap op. + * @op: Remap op. + * @start_addr: Output pointer for the start of the required unmap. + * @range: Output pointer for the length of the required unmap. + * + * The given start address and range will be set such that they represent the + * range of the address space that was previously covered by the mapping being + * re-mapped, but is now empty. + */ +static inline void +drm_gpuva_op_remap_to_unmap_range(const struct drm_gpuva_op_remap *op, + u64 *start_addr, u64 *range) +{ + const u64 va_start = op->prev ? + op->prev->va.addr + op->prev->va.range : + op->unmap->va->va.addr; + const u64 va_end = op->next ? + op->next->va.addr : + op->unmap->va->va.addr + op->unmap->va->va.range; + + if (start_addr) + *start_addr = va_start; + if (range) + *range = va_end - va_start; +} + #endif /* __DRM_GPUVM_H__ */ From 6a85c3b14728f0d5cb59ca0d38894db2a9839fce Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:24 +0000 Subject: [PATCH 1175/7721] dt-bindings: gpu: Add Imagination Technologies PowerVR/IMG GPU Add the device tree binding documentation for the IMG AXE GPU used in TI AM62 SoCs. Co-developed-by: Frank Binns Signed-off-by: Frank Binns Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/deb0a4659423a3b8a74addee7178b6df7679575d.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- .../devicetree/bindings/gpu/img,powervr.yaml | 73 +++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/img,powervr.yaml diff --git a/Documentation/devicetree/bindings/gpu/img,powervr.yaml b/Documentation/devicetree/bindings/gpu/img,powervr.yaml new file mode 100644 index 000000000000..a13298f1a182 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/img,powervr.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Imagination Technologies Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/img,powervr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagination Technologies PowerVR and IMG GPU + +maintainers: + - Frank Binns + +properties: + compatible: + items: + - enum: + - ti,am62-gpu + - const: img,img-axe # IMG AXE GPU model/revision is fully discoverable + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + items: + - const: core + - const: mem + - const: sys + minItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62-gpu + then: + properties: + clocks: + maxItems: 1 + +examples: + - | + #include + #include + #include + + gpu@fd00000 { + compatible = "ti,am62-gpu", "img,img-axe"; + reg = <0x0fd00000 0x20000>; + clocks = <&k3_clks 187 0>; + clock-names = "core"; + interrupts = ; + power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 8a70be8f08ee..59c60abf341e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10392,6 +10392,13 @@ IMGTEC IR DECODER DRIVER S: Orphan F: drivers/media/rc/img-ir/ +IMGTEC POWERVR DRM DRIVER +M: Frank Binns +M: Donald Robson +M: Matt Coster +S: Supported +F: Documentation/devicetree/bindings/gpu/img,powervr.yaml + IMON SOUNDGRAPH USB IR RECEIVER M: Sean Young L: linux-media@vger.kernel.org From 1088d89e551530a9f5128770d74a1516090f1e41 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:25 +0000 Subject: [PATCH 1176/7721] drm/imagination/uapi: Add PowerVR driver UAPI Add the UAPI implementation for the PowerVR driver. Changes from v8: - Fixed documentation for unmapping, which previously suggested the size was not used - Corrected license identifier Changes from v7: - Remove prefixes from DRM_PVR_BO_* flags - Improve struct drm_pvr_ioctl_create_hwrt_dataset_args documentation - Remove references to static area carveouts - CREATE_BO ioctl now returns an error if provided size isn't page aligned - Clarify documentation for DRM_PVR_STATIC_DATA_AREA_EOT Changes from v6: - Add padding to struct drm_pvr_dev_query_gpu_info - Improve BYPASS_CACHE flag documentation - Add SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE flag Changes from v4: - Remove CREATE_ZEROED flag for BO creation (all buffers are now zeroed) Co-developed-by: Frank Binns Signed-off-by: Frank Binns Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon Co-developed-by: Matt Coster Signed-off-by: Matt Coster Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Reviewed-by: Faith Ekstrand Link: https://lore.kernel.org/r/8c95a3a1d685e2b44d361b95a19eae5a478fb9d1.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- MAINTAINERS | 1 + include/uapi/drm/pvr_drm.h | 1297 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1298 insertions(+) create mode 100644 include/uapi/drm/pvr_drm.h diff --git a/MAINTAINERS b/MAINTAINERS index 59c60abf341e..37642011c319 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10398,6 +10398,7 @@ M: Donald Robson M: Matt Coster S: Supported F: Documentation/devicetree/bindings/gpu/img,powervr.yaml +F: include/uapi/drm/pvr_drm.h IMON SOUNDGRAPH USB IR RECEIVER M: Sean Young diff --git a/include/uapi/drm/pvr_drm.h b/include/uapi/drm/pvr_drm.h new file mode 100644 index 000000000000..1834375390c4 --- /dev/null +++ b/include/uapi/drm/pvr_drm.h @@ -0,0 +1,1297 @@ +/* SPDX-License-Identifier: (GPL-2.0-only WITH Linux-syscall-note) OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DRM_UAPI_H +#define PVR_DRM_UAPI_H + +#include "drm.h" + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * DOC: PowerVR UAPI + * + * The PowerVR IOCTL argument structs have a few limitations in place, in + * addition to the standard kernel restrictions: + * + * - All members must be type-aligned. + * - The overall struct must be padded to 64-bit alignment. + * - Explicit padding is almost always required. This takes the form of + * ``_padding_[x]`` members of sufficient size to pad to the next power-of-two + * alignment, where [x] is the offset into the struct in hexadecimal. Arrays + * are never used for alignment. Padding fields must be zeroed; this is + * always checked. + * - Unions may only appear as the last member of a struct. + * - Individual union members may grow in the future. The space between the + * end of a union member and the end of its containing union is considered + * "implicit padding" and must be zeroed. This is always checked. + * + * In addition to the IOCTL argument structs, the PowerVR UAPI makes use of + * DEV_QUERY argument structs. These are used to fetch information about the + * device and runtime. These structs are subject to the same rules set out + * above. + */ + +/** + * struct drm_pvr_obj_array - Container used to pass arrays of objects + * + * It is not unusual to have to extend objects to pass new parameters, and the DRM + * ioctl infrastructure is supporting that by padding ioctl arguments with zeros + * when the data passed by userspace is smaller than the struct defined in the + * drm_ioctl_desc, thus keeping things backward compatible. This type is just + * applying the same concepts to indirect objects passed through arrays referenced + * from the main ioctl arguments structure: the stride basically defines the size + * of the object passed by userspace, which allows the kernel driver to pad with + * zeros when it's smaller than the size of the object it expects. + * + * Use ``DRM_PVR_OBJ_ARRAY()`` to fill object array fields, unless you + * have a very good reason not to. + */ +struct drm_pvr_obj_array { + /** @stride: Stride of object struct. Used for versioning. */ + __u32 stride; + + /** @count: Number of objects in the array. */ + __u32 count; + + /** @array: User pointer to an array of objects. */ + __u64 array; +}; + +/** + * DRM_PVR_OBJ_ARRAY() - Helper macro for filling &struct drm_pvr_obj_array. + * @cnt: Number of elements pointed to py @ptr. + * @ptr: Pointer to start of a C array. + * + * Return: Literal of type &struct drm_pvr_obj_array. + */ +#define DRM_PVR_OBJ_ARRAY(cnt, ptr) \ + { .stride = sizeof((ptr)[0]), .count = (cnt), .array = (__u64)(uintptr_t)(ptr) } + +/** + * DOC: PowerVR IOCTL interface + */ + +/** + * PVR_IOCTL() - Build a PowerVR IOCTL number + * @_ioctl: An incrementing id for this IOCTL. Added to %DRM_COMMAND_BASE. + * @_mode: Must be one of %DRM_IOR, %DRM_IOW or %DRM_IOWR. + * @_data: The type of the args struct passed by this IOCTL. + * + * The struct referred to by @_data must have a ``drm_pvr_ioctl_`` prefix and an + * ``_args suffix``. They are therefore omitted from @_data. + * + * This should only be used to build the constants described below; it should + * never be used to call an IOCTL directly. + * + * Return: An IOCTL number to be passed to ioctl() from userspace. + */ +#define PVR_IOCTL(_ioctl, _mode, _data) \ + _mode(DRM_COMMAND_BASE + (_ioctl), struct drm_pvr_ioctl_##_data##_args) + +#define DRM_IOCTL_PVR_DEV_QUERY PVR_IOCTL(0x00, DRM_IOWR, dev_query) +#define DRM_IOCTL_PVR_CREATE_BO PVR_IOCTL(0x01, DRM_IOWR, create_bo) +#define DRM_IOCTL_PVR_GET_BO_MMAP_OFFSET PVR_IOCTL(0x02, DRM_IOWR, get_bo_mmap_offset) +#define DRM_IOCTL_PVR_CREATE_VM_CONTEXT PVR_IOCTL(0x03, DRM_IOWR, create_vm_context) +#define DRM_IOCTL_PVR_DESTROY_VM_CONTEXT PVR_IOCTL(0x04, DRM_IOW, destroy_vm_context) +#define DRM_IOCTL_PVR_VM_MAP PVR_IOCTL(0x05, DRM_IOW, vm_map) +#define DRM_IOCTL_PVR_VM_UNMAP PVR_IOCTL(0x06, DRM_IOW, vm_unmap) +#define DRM_IOCTL_PVR_CREATE_CONTEXT PVR_IOCTL(0x07, DRM_IOWR, create_context) +#define DRM_IOCTL_PVR_DESTROY_CONTEXT PVR_IOCTL(0x08, DRM_IOW, destroy_context) +#define DRM_IOCTL_PVR_CREATE_FREE_LIST PVR_IOCTL(0x09, DRM_IOWR, create_free_list) +#define DRM_IOCTL_PVR_DESTROY_FREE_LIST PVR_IOCTL(0x0a, DRM_IOW, destroy_free_list) +#define DRM_IOCTL_PVR_CREATE_HWRT_DATASET PVR_IOCTL(0x0b, DRM_IOWR, create_hwrt_dataset) +#define DRM_IOCTL_PVR_DESTROY_HWRT_DATASET PVR_IOCTL(0x0c, DRM_IOW, destroy_hwrt_dataset) +#define DRM_IOCTL_PVR_SUBMIT_JOBS PVR_IOCTL(0x0d, DRM_IOW, submit_jobs) + +/** + * DOC: PowerVR IOCTL DEV_QUERY interface + */ + +/** + * struct drm_pvr_dev_query_gpu_info - Container used to fetch information about + * the graphics processor. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_QUERY_GPU_INFO_GET. + */ +struct drm_pvr_dev_query_gpu_info { + /** + * @gpu_id: GPU identifier. + * + * For all currently supported GPUs this is the BVNC encoded as a 64-bit + * value as follows: + * + * +--------+--------+--------+-------+ + * | 63..48 | 47..32 | 31..16 | 15..0 | + * +========+========+========+=======+ + * | B | V | N | C | + * +--------+--------+--------+-------+ + */ + __u64 gpu_id; + + /** + * @num_phantoms: Number of Phantoms present. + */ + __u32 num_phantoms; + + /** @_padding_c: Reserved. This field must be zeroed. */ + __u32 _padding_c; +}; + +/** + * struct drm_pvr_dev_query_runtime_info - Container used to fetch information + * about the graphics runtime. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET. + */ +struct drm_pvr_dev_query_runtime_info { + /** + * @free_list_min_pages: Minimum allowed free list size, + * in PM physical pages. + */ + __u64 free_list_min_pages; + + /** + * @free_list_max_pages: Maximum allowed free list size, + * in PM physical pages. + */ + __u64 free_list_max_pages; + + /** + * @common_store_alloc_region_size: Size of the Allocation + * Region within the Common Store used for coefficient and shared + * registers, in dwords. + */ + __u32 common_store_alloc_region_size; + + /** + * @common_store_partition_space_size: Size of the + * Partition Space within the Common Store for output buffers, in + * dwords. + */ + __u32 common_store_partition_space_size; + + /** + * @max_coeffs: Maximum coefficients, in dwords. + */ + __u32 max_coeffs; + + /** + * @cdm_max_local_mem_size_regs: Maximum amount of local + * memory available to a compute kernel, in dwords. + */ + __u32 cdm_max_local_mem_size_regs; +}; + +/** + * struct drm_pvr_dev_query_quirks - Container used to fetch information about + * hardware fixes for which the device may require support in the user mode + * driver. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_QUERY_QUIRKS_GET. + */ +struct drm_pvr_dev_query_quirks { + /** + * @quirks: A userspace address for the hardware quirks __u32 array. + * + * The first @musthave_count items in the list are quirks that the + * client must support for this device. If userspace does not support + * all these quirks then functionality is not guaranteed and client + * initialisation must fail. + * The remaining quirks in the list affect userspace and the kernel or + * firmware. They are disabled by default and require userspace to + * opt-in. The opt-in mechanism depends on the quirk. + */ + __u64 quirks; + + /** @count: Length of @quirks (number of __u32). */ + __u16 count; + + /** + * @musthave_count: The number of entries in @quirks that are + * mandatory, starting at index 0. + */ + __u16 musthave_count; + + /** @_padding_c: Reserved. This field must be zeroed. */ + __u32 _padding_c; +}; + +/** + * struct drm_pvr_dev_query_enhancements - Container used to fetch information + * about optional enhancements supported by the device that require support in + * the user mode driver. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_ENHANCEMENTS_GET. + */ +struct drm_pvr_dev_query_enhancements { + /** + * @enhancements: A userspace address for the hardware enhancements + * __u32 array. + * + * These enhancements affect userspace and the kernel or firmware. They + * are disabled by default and require userspace to opt-in. The opt-in + * mechanism depends on the enhancement. + */ + __u64 enhancements; + + /** @count: Length of @enhancements (number of __u32). */ + __u16 count; + + /** @_padding_a: Reserved. This field must be zeroed. */ + __u16 _padding_a; + + /** @_padding_c: Reserved. This field must be zeroed. */ + __u32 _padding_c; +}; + +/** + * enum drm_pvr_heap_id - Array index for heap info data returned by + * %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + * + * For compatibility reasons all indices will be present in the returned array, + * however some heaps may not be present. These are indicated where + * &struct drm_pvr_heap.size is set to zero. + */ +enum drm_pvr_heap_id { + /** @DRM_PVR_HEAP_GENERAL: General purpose heap. */ + DRM_PVR_HEAP_GENERAL = 0, + /** @DRM_PVR_HEAP_PDS_CODE_DATA: PDS code and data heap. */ + DRM_PVR_HEAP_PDS_CODE_DATA, + /** @DRM_PVR_HEAP_USC_CODE: USC code heap. */ + DRM_PVR_HEAP_USC_CODE, + /** @DRM_PVR_HEAP_RGNHDR: Region header heap. Only used if GPU has BRN63142. */ + DRM_PVR_HEAP_RGNHDR, + /** @DRM_PVR_HEAP_VIS_TEST: Visibility test heap. */ + DRM_PVR_HEAP_VIS_TEST, + /** @DRM_PVR_HEAP_TRANSFER_FRAG: Transfer fragment heap. */ + DRM_PVR_HEAP_TRANSFER_FRAG, + + /** + * @DRM_PVR_HEAP_COUNT: The number of heaps returned by + * %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + * + * More heaps may be added, so this also serves as the copy limit when + * sent by the caller. + */ + DRM_PVR_HEAP_COUNT + /* Please only add additional heaps above DRM_PVR_HEAP_COUNT! */ +}; + +/** + * struct drm_pvr_heap - Container holding information about a single heap. + * + * This will always be fetched as an array. + */ +struct drm_pvr_heap { + /** @base: Base address of heap. */ + __u64 base; + + /** @size: Size of heap, in bytes. Will be 0 if the heap is not present. */ + __u64 size; + + /** @flags: Flags for this heap. Currently always 0. */ + __u32 flags; + + /** @page_size_log2: Log2 of page size. */ + __u32 page_size_log2; +}; + +/** + * struct drm_pvr_dev_query_heap_info - Container used to fetch information + * about heaps supported by the device driver. + * + * Please note all driver-supported heaps will be returned up to &heaps.count. + * Some heaps will not be present in all devices, which will be indicated by + * &struct drm_pvr_heap.size being set to zero. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + */ +struct drm_pvr_dev_query_heap_info { + /** + * @heaps: Array of &struct drm_pvr_heap. If pointer is NULL, the count + * and stride will be updated with those known to the driver version, to + * facilitate allocation by the caller. + */ + struct drm_pvr_obj_array heaps; +}; + +/** + * enum drm_pvr_static_data_area_usage - Array index for static data area info + * returned by %DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET. + * + * For compatibility reasons all indices will be present in the returned array, + * however some areas may not be present. These are indicated where + * &struct drm_pvr_static_data_area.size is set to zero. + */ +enum drm_pvr_static_data_area_usage { + /** + * @DRM_PVR_STATIC_DATA_AREA_EOT: End of Tile PDS program code segment. + * + * The End of Tile PDS task runs at completion of a tile during a fragment job, and is + * responsible for emitting the tile to the Pixel Back End. + */ + DRM_PVR_STATIC_DATA_AREA_EOT = 0, + + /** + * @DRM_PVR_STATIC_DATA_AREA_FENCE: MCU fence area, used during cache flush and + * invalidation. + * + * This must point to valid physical memory but the contents otherwise are not used. + */ + DRM_PVR_STATIC_DATA_AREA_FENCE, + + /** + * @DRM_PVR_STATIC_DATA_AREA_VDM_SYNC: VDM sync program. + * + * The VDM sync program is used to synchronise multiple areas of the GPU hardware. + */ + DRM_PVR_STATIC_DATA_AREA_VDM_SYNC, + + /** + * @DRM_PVR_STATIC_DATA_AREA_YUV_CSC: YUV coefficients. + * + * Area contains up to 16 slots with stride of 64 bytes. Each is a 3x4 matrix of u16 fixed + * point numbers, with 1 sign bit, 2 integer bits and 13 fractional bits. + * + * The slots are : + * 0 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR + * 1 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR (full range) + * 2 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR (conformant range) + * 3 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR (full range) + * 4 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR (conformant range) + * 5 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR (full range) + * 6 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR (conformant range) + * 7 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR (full range) + * 8 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR (conformant range) + * 9 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR (conformant range, 10 bit) + * 10 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR (conformant range, 10 bit) + * 11 = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR (conformant range, 10 bit) + * 14 = Identity (biased) + * 15 = Identity + */ + DRM_PVR_STATIC_DATA_AREA_YUV_CSC, +}; + +/** + * struct drm_pvr_static_data_area - Container holding information about a + * single static data area. + * + * This will always be fetched as an array. + */ +struct drm_pvr_static_data_area { + /** + * @area_usage: Usage of static data area. + * See &enum drm_pvr_static_data_area_usage. + */ + __u16 area_usage; + + /** + * @location_heap_id: Array index of heap where this of static data + * area is located. This array is fetched using + * %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + */ + __u16 location_heap_id; + + /** @size: Size of static data area. Not present if set to zero. */ + __u32 size; + + /** @offset: Offset of static data area from start of heap. */ + __u64 offset; +}; + +/** + * struct drm_pvr_dev_query_static_data_areas - Container used to fetch + * information about the static data areas in heaps supported by the device + * driver. + * + * Please note all driver-supported static data areas will be returned up to + * &static_data_areas.count. Some will not be present for all devices which, + * will be indicated by &struct drm_pvr_static_data_area.size being set to zero. + * + * Further, some heaps will not be present either. See &struct + * drm_pvr_dev_query_heap_info. + * + * When fetching this type &struct drm_pvr_ioctl_dev_query_args.type must be set + * to %DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET. + */ +struct drm_pvr_dev_query_static_data_areas { + /** + * @static_data_areas: Array of &struct drm_pvr_static_data_area. If + * pointer is NULL, the count and stride will be updated with those + * known to the driver version, to facilitate allocation by the caller. + */ + struct drm_pvr_obj_array static_data_areas; +}; + +/** + * enum drm_pvr_dev_query - For use with &drm_pvr_ioctl_dev_query_args.type to + * indicate the type of the receiving container. + * + * Append only. Do not reorder. + */ +enum drm_pvr_dev_query { + /** + * @DRM_PVR_DEV_QUERY_GPU_INFO_GET: The dev query args contain a pointer + * to &struct drm_pvr_dev_query_gpu_info. + */ + DRM_PVR_DEV_QUERY_GPU_INFO_GET = 0, + + /** + * @DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET: The dev query args contain a + * pointer to &struct drm_pvr_dev_query_runtime_info. + */ + DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET, + + /** + * @DRM_PVR_DEV_QUERY_QUIRKS_GET: The dev query args contain a pointer + * to &struct drm_pvr_dev_query_quirks. + */ + DRM_PVR_DEV_QUERY_QUIRKS_GET, + + /** + * @DRM_PVR_DEV_QUERY_ENHANCEMENTS_GET: The dev query args contain a + * pointer to &struct drm_pvr_dev_query_enhancements. + */ + DRM_PVR_DEV_QUERY_ENHANCEMENTS_GET, + + /** + * @DRM_PVR_DEV_QUERY_HEAP_INFO_GET: The dev query args contain a + * pointer to &struct drm_pvr_dev_query_heap_info. + */ + DRM_PVR_DEV_QUERY_HEAP_INFO_GET, + + /** + * @DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET: The dev query args contain + * a pointer to &struct drm_pvr_dev_query_static_data_areas. + */ + DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET, +}; + +/** + * struct drm_pvr_ioctl_dev_query_args - Arguments for %DRM_IOCTL_PVR_DEV_QUERY. + */ +struct drm_pvr_ioctl_dev_query_args { + /** + * @type: Type of query and output struct. See &enum drm_pvr_dev_query. + */ + __u32 type; + + /** + * @size: Size of the receiving struct, see @type. + * + * After a successful call this will be updated to the written byte + * length. + * Can also be used to get the minimum byte length (see @pointer). + * This allows additional fields to be appended to the structs in + * future. + */ + __u32 size; + + /** + * @pointer: Pointer to struct @type. + * + * Must be large enough to contain @size bytes. + * If pointer is NULL, the expected size will be returned in the @size + * field, but no other data will be written. + */ + __u64 pointer; +}; + +/** + * DOC: PowerVR IOCTL CREATE_BO interface + */ + +/** + * DOC: Flags for CREATE_BO + * + * We use "device" to refer to the GPU here because of the ambiguity between CPU and GPU in some + * fonts. + * + * Device mapping options + * :DRM_PVR_BO_BYPASS_DEVICE_CACHE: Specify that device accesses to this memory will bypass the + * cache. This is used for buffers that will either be regularly updated by the CPU (eg free + * lists) or will be accessed only once and therefore isn't worth caching (eg partial render + * buffers). + * By default, the device flushes its memory caches after every job, so this is not normally + * required for coherency. + * :DRM_PVR_BO_PM_FW_PROTECT: Specify that only the Parameter Manager (PM) and/or firmware + * processor should be allowed to access this memory when mapped to the device. It is not + * valid to specify this flag with DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS. + * + * CPU mapping options + * :DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS: Allow userspace to map and access the contents of this + * memory. It is not valid to specify this flag with DRM_PVR_BO_PM_FW_PROTECT. + */ +#define DRM_PVR_BO_BYPASS_DEVICE_CACHE _BITULL(0) +#define DRM_PVR_BO_PM_FW_PROTECT _BITULL(1) +#define DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS _BITULL(2) +/* Bits 3..63 are reserved. */ + +#define DRM_PVR_BO_FLAGS_MASK (DRM_PVR_BO_BYPASS_DEVICE_CACHE | DRM_PVR_BO_PM_FW_PROTECT | \ + DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS) + +/** + * struct drm_pvr_ioctl_create_bo_args - Arguments for %DRM_IOCTL_PVR_CREATE_BO + */ +struct drm_pvr_ioctl_create_bo_args { + /** + * @size: [IN] Size of buffer object to create. This must be page size + * aligned. + */ + __u64 size; + + /** + * @handle: [OUT] GEM handle of the new buffer object for use in + * userspace. + */ + __u32 handle; + + /** @_padding_c: Reserved. This field must be zeroed. */ + __u32 _padding_c; + + /** + * @flags: [IN] Options which will affect the behaviour of this + * creation operation and future mapping operations on the created + * object. This field must be a valid combination of ``DRM_PVR_BO_*`` + * values, with all bits marked as reserved set to zero. + */ + __u64 flags; +}; + +/** + * DOC: PowerVR IOCTL GET_BO_MMAP_OFFSET interface + */ + +/** + * struct drm_pvr_ioctl_get_bo_mmap_offset_args - Arguments for + * %DRM_IOCTL_PVR_GET_BO_MMAP_OFFSET + * + * Like other DRM drivers, the "mmap" IOCTL doesn't actually map any memory. + * Instead, it allocates a fake offset which refers to the specified buffer + * object. This offset can be used with a real mmap call on the DRM device + * itself. + */ +struct drm_pvr_ioctl_get_bo_mmap_offset_args { + /** @handle: [IN] GEM handle of the buffer object to be mapped. */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; + + /** @offset: [OUT] Fake offset to use in the real mmap call. */ + __u64 offset; +}; + +/** + * DOC: PowerVR IOCTL CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT interfaces + */ + +/** + * struct drm_pvr_ioctl_create_vm_context_args - Arguments for + * %DRM_IOCTL_PVR_CREATE_VM_CONTEXT + */ +struct drm_pvr_ioctl_create_vm_context_args { + /** @handle: [OUT] Handle for new VM context. */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; +}; + +/** + * struct drm_pvr_ioctl_destroy_vm_context_args - Arguments for + * %DRM_IOCTL_PVR_DESTROY_VM_CONTEXT + */ +struct drm_pvr_ioctl_destroy_vm_context_args { + /** + * @handle: [IN] Handle for VM context to be destroyed. + */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; +}; + +/** + * DOC: PowerVR IOCTL VM_MAP and VM_UNMAP interfaces + * + * The VM UAPI allows userspace to create buffer object mappings in GPU virtual address space. + * + * The client is responsible for managing GPU address space. It should allocate mappings within + * the heaps returned by %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + * + * %DRM_IOCTL_PVR_VM_MAP creates a new mapping. The client provides the target virtual address for + * the mapping. Size and offset within the mapped buffer object can be specified, so the client can + * partially map a buffer. + * + * %DRM_IOCTL_PVR_VM_UNMAP removes a mapping. The entire mapping will be removed from GPU address + * space only if the size of the mapping matches that known to the driver. + */ + +/** + * struct drm_pvr_ioctl_vm_map_args - Arguments for %DRM_IOCTL_PVR_VM_MAP. + */ +struct drm_pvr_ioctl_vm_map_args { + /** + * @vm_context_handle: [IN] Handle for VM context for this mapping to + * exist in. + */ + __u32 vm_context_handle; + + /** @flags: [IN] Flags which affect this mapping. Currently always 0. */ + __u32 flags; + + /** + * @device_addr: [IN] Requested device-virtual address for the mapping. + * This must be non-zero and aligned to the device page size for the + * heap containing the requested address. It is an error to specify an + * address which is not contained within one of the heaps returned by + * %DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + */ + __u64 device_addr; + + /** + * @handle: [IN] Handle of the target buffer object. This must be a + * valid handle returned by %DRM_IOCTL_PVR_CREATE_BO. + */ + __u32 handle; + + /** @_padding_14: Reserved. This field must be zeroed. */ + __u32 _padding_14; + + /** + * @offset: [IN] Offset into the target bo from which to begin the + * mapping. + */ + __u64 offset; + + /** + * @size: [IN] Size of the requested mapping. Must be aligned to + * the device page size for the heap containing the requested address, + * as well as the host page size. When added to @device_addr, the + * result must not overflow the heap which contains @device_addr (i.e. + * the range specified by @device_addr and @size must be completely + * contained within a single heap specified by + * %DRM_PVR_DEV_QUERY_HEAP_INFO_GET). + */ + __u64 size; +}; + +/** + * struct drm_pvr_ioctl_vm_unmap_args - Arguments for %DRM_IOCTL_PVR_VM_UNMAP. + */ +struct drm_pvr_ioctl_vm_unmap_args { + /** + * @vm_context_handle: [IN] Handle for VM context that this mapping + * exists in. + */ + __u32 vm_context_handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; + + /** + * @device_addr: [IN] Device-virtual address at the start of the target + * mapping. This must be non-zero. + */ + __u64 device_addr; + + /** + * @size: Size in bytes of the target mapping. This must be non-zero. + */ + __u64 size; +}; + +/** + * DOC: PowerVR IOCTL CREATE_CONTEXT and DESTROY_CONTEXT interfaces + */ + +/** + * enum drm_pvr_ctx_priority - Arguments for + * &drm_pvr_ioctl_create_context_args.priority + */ +enum drm_pvr_ctx_priority { + /** @DRM_PVR_CTX_PRIORITY_LOW: Priority below normal. */ + DRM_PVR_CTX_PRIORITY_LOW = -512, + + /** @DRM_PVR_CTX_PRIORITY_NORMAL: Normal priority. */ + DRM_PVR_CTX_PRIORITY_NORMAL = 0, + + /** + * @DRM_PVR_CTX_PRIORITY_HIGH: Priority above normal. + * Note this requires ``CAP_SYS_NICE`` or ``DRM_MASTER``. + */ + DRM_PVR_CTX_PRIORITY_HIGH = 512, +}; + +/** + * enum drm_pvr_ctx_type - Arguments for + * &struct drm_pvr_ioctl_create_context_args.type + */ +enum drm_pvr_ctx_type { + /** + * @DRM_PVR_CTX_TYPE_RENDER: Render context. Use &struct + * drm_pvr_ioctl_create_render_context_args for context creation arguments. + */ + DRM_PVR_CTX_TYPE_RENDER = 0, + + /** + * @DRM_PVR_CTX_TYPE_COMPUTE: Compute context. Use &struct + * drm_pvr_ioctl_create_compute_context_args for context creation arguments. + */ + DRM_PVR_CTX_TYPE_COMPUTE, + + /** + * @DRM_PVR_CTX_TYPE_TRANSFER_FRAG: Transfer context for fragment data masters. Use + * &struct drm_pvr_ioctl_create_transfer_context_args for context creation arguments. + */ + DRM_PVR_CTX_TYPE_TRANSFER_FRAG, +}; + +/** + * struct drm_pvr_ioctl_create_context_args - Arguments for + * %DRM_IOCTL_PVR_CREATE_CONTEXT + */ +struct drm_pvr_ioctl_create_context_args { + /** + * @type: [IN] Type of context to create. + * + * This must be one of the values defined by &enum drm_pvr_ctx_type. + */ + __u32 type; + + /** @flags: [IN] Flags for context. */ + __u32 flags; + + /** + * @priority: [IN] Priority of new context. + * + * This must be one of the values defined by &enum drm_pvr_ctx_priority. + */ + __s32 priority; + + /** @handle: [OUT] Handle for new context. */ + __u32 handle; + + /** + * @static_context_state: [IN] Pointer to static context state stream. + */ + __u64 static_context_state; + + /** + * @static_context_state_len: [IN] Length of static context state, in bytes. + */ + __u32 static_context_state_len; + + /** + * @vm_context_handle: [IN] Handle for VM context that this context is + * associated with. + */ + __u32 vm_context_handle; + + /** + * @callstack_addr: [IN] Address for initial call stack pointer. Only valid + * if @type is %DRM_PVR_CTX_TYPE_RENDER, otherwise must be 0. + */ + __u64 callstack_addr; +}; + +/** + * struct drm_pvr_ioctl_destroy_context_args - Arguments for + * %DRM_IOCTL_PVR_DESTROY_CONTEXT + */ +struct drm_pvr_ioctl_destroy_context_args { + /** + * @handle: [IN] Handle for context to be destroyed. + */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; +}; + +/** + * DOC: PowerVR IOCTL CREATE_FREE_LIST and DESTROY_FREE_LIST interfaces + */ + +/** + * struct drm_pvr_ioctl_create_free_list_args - Arguments for + * %DRM_IOCTL_PVR_CREATE_FREE_LIST + * + * Free list arguments have the following constraints : + * + * - @max_num_pages must be greater than zero. + * - @grow_threshold must be between 0 and 100. + * - @grow_num_pages must be less than or equal to &max_num_pages. + * - @initial_num_pages, @max_num_pages and @grow_num_pages must be multiples + * of 4. + * - When &grow_num_pages is 0, @initial_num_pages must be equal to + * @max_num_pages. + * - When &grow_num_pages is non-zero, @initial_num_pages must be less than + * @max_num_pages. + */ +struct drm_pvr_ioctl_create_free_list_args { + /** + * @free_list_gpu_addr: [IN] Address of GPU mapping of buffer object + * containing memory to be used by free list. + * + * The mapped region of the buffer object must be at least + * @max_num_pages * ``sizeof(__u32)``. + * + * The buffer object must have been created with + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT set and + * %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS not set. + */ + __u64 free_list_gpu_addr; + + /** @initial_num_pages: [IN] Pages initially allocated to free list. */ + __u32 initial_num_pages; + + /** @max_num_pages: [IN] Maximum number of pages in free list. */ + __u32 max_num_pages; + + /** @grow_num_pages: [IN] Pages to grow free list by per request. */ + __u32 grow_num_pages; + + /** + * @grow_threshold: [IN] Percentage of FL memory used that should + * trigger a new grow request. + */ + __u32 grow_threshold; + + /** + * @vm_context_handle: [IN] Handle for VM context that the free list buffer + * object is mapped in. + */ + __u32 vm_context_handle; + + /** + * @handle: [OUT] Handle for created free list. + */ + __u32 handle; +}; + +/** + * struct drm_pvr_ioctl_destroy_free_list_args - Arguments for + * %DRM_IOCTL_PVR_DESTROY_FREE_LIST + */ +struct drm_pvr_ioctl_destroy_free_list_args { + /** + * @handle: [IN] Handle for free list to be destroyed. + */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; +}; + +/** + * DOC: PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces + */ + +/** + * struct drm_pvr_create_hwrt_geom_data_args - Geometry data arguments used for + * &struct drm_pvr_ioctl_create_hwrt_dataset_args.geom_data_args. + */ +struct drm_pvr_create_hwrt_geom_data_args { + /** @tpc_dev_addr: [IN] Tail pointer cache GPU virtual address. */ + __u64 tpc_dev_addr; + + /** @tpc_size: [IN] Size of TPC, in bytes. */ + __u32 tpc_size; + + /** @tpc_stride: [IN] Stride between layers in TPC, in pages */ + __u32 tpc_stride; + + /** @vheap_table_dev_addr: [IN] VHEAP table GPU virtual address. */ + __u64 vheap_table_dev_addr; + + /** @rtc_dev_addr: [IN] Render Target Cache virtual address. */ + __u64 rtc_dev_addr; +}; + +/** + * struct drm_pvr_create_hwrt_rt_data_args - Render target arguments used for + * &struct drm_pvr_ioctl_create_hwrt_dataset_args.rt_data_args. + */ +struct drm_pvr_create_hwrt_rt_data_args { + /** @pm_mlist_dev_addr: [IN] PM MLIST GPU virtual address. */ + __u64 pm_mlist_dev_addr; + + /** @macrotile_array_dev_addr: [IN] Macrotile array GPU virtual address. */ + __u64 macrotile_array_dev_addr; + + /** @region_header_dev_addr: [IN] Region header array GPU virtual address. */ + __u64 region_header_dev_addr; +}; + +#define PVR_DRM_HWRT_FREE_LIST_LOCAL 0 +#define PVR_DRM_HWRT_FREE_LIST_GLOBAL 1U + +/** + * struct drm_pvr_ioctl_create_hwrt_dataset_args - Arguments for + * %DRM_IOCTL_PVR_CREATE_HWRT_DATASET + */ +struct drm_pvr_ioctl_create_hwrt_dataset_args { + /** @geom_data_args: [IN] Geometry data arguments. */ + struct drm_pvr_create_hwrt_geom_data_args geom_data_args; + + /** + * @rt_data_args: [IN] Array of render target arguments. + * + * Each entry in this array represents a render target in a double buffered + * setup. + */ + struct drm_pvr_create_hwrt_rt_data_args rt_data_args[2]; + + /** + * @free_list_handles: [IN] Array of free list handles. + * + * free_list_handles[PVR_DRM_HWRT_FREE_LIST_LOCAL] must have initial + * size of at least that reported by + * &drm_pvr_dev_query_runtime_info.free_list_min_pages. + */ + __u32 free_list_handles[2]; + + /** @width: [IN] Width in pixels. */ + __u32 width; + + /** @height: [IN] Height in pixels. */ + __u32 height; + + /** @samples: [IN] Number of samples. */ + __u32 samples; + + /** @layers: [IN] Number of layers. */ + __u32 layers; + + /** @isp_merge_lower_x: [IN] Lower X coefficient for triangle merging. */ + __u32 isp_merge_lower_x; + + /** @isp_merge_lower_y: [IN] Lower Y coefficient for triangle merging. */ + __u32 isp_merge_lower_y; + + /** @isp_merge_scale_x: [IN] Scale X coefficient for triangle merging. */ + __u32 isp_merge_scale_x; + + /** @isp_merge_scale_y: [IN] Scale Y coefficient for triangle merging. */ + __u32 isp_merge_scale_y; + + /** @isp_merge_upper_x: [IN] Upper X coefficient for triangle merging. */ + __u32 isp_merge_upper_x; + + /** @isp_merge_upper_y: [IN] Upper Y coefficient for triangle merging. */ + __u32 isp_merge_upper_y; + + /** + * @region_header_size: [IN] Size of region header array. This common field is used by + * both render targets in this data set. + * + * The units for this field differ depending on what version of the simple internal + * parameter format the device uses. If format 2 is in use then this is interpreted as the + * number of region headers. For other formats it is interpreted as the size in dwords. + */ + __u32 region_header_size; + + /** + * @handle: [OUT] Handle for created HWRT dataset. + */ + __u32 handle; +}; + +/** + * struct drm_pvr_ioctl_destroy_hwrt_dataset_args - Arguments for + * %DRM_IOCTL_PVR_DESTROY_HWRT_DATASET + */ +struct drm_pvr_ioctl_destroy_hwrt_dataset_args { + /** + * @handle: [IN] Handle for HWRT dataset to be destroyed. + */ + __u32 handle; + + /** @_padding_4: Reserved. This field must be zeroed. */ + __u32 _padding_4; +}; + +/** + * DOC: PowerVR IOCTL SUBMIT_JOBS interface + */ + +/** + * DOC: Flags for the drm_pvr_sync_op object. + * + * .. c:macro:: DRM_PVR_SYNC_OP_HANDLE_TYPE_MASK + * + * Handle type mask for the drm_pvr_sync_op::flags field. + * + * .. c:macro:: DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ + * + * Indicates the handle passed in drm_pvr_sync_op::handle is a syncobj handle. + * This is the default type. + * + * .. c:macro:: DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_TIMELINE_SYNCOBJ + * + * Indicates the handle passed in drm_pvr_sync_op::handle is a timeline syncobj handle. + * + * .. c:macro:: DRM_PVR_SYNC_OP_FLAG_SIGNAL + * + * Signal operation requested. The out-fence bound to the job will be attached to + * the syncobj whose handle is passed in drm_pvr_sync_op::handle. + * + * .. c:macro:: DRM_PVR_SYNC_OP_FLAG_WAIT + * + * Wait operation requested. The job will wait for this particular syncobj or syncobj + * point to be signaled before being started. + * This is the default operation. + */ +#define DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_MASK 0xf +#define DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ 0 +#define DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_TIMELINE_SYNCOBJ 1 +#define DRM_PVR_SYNC_OP_FLAG_SIGNAL _BITULL(31) +#define DRM_PVR_SYNC_OP_FLAG_WAIT 0 + +#define DRM_PVR_SYNC_OP_FLAGS_MASK (DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_MASK | \ + DRM_PVR_SYNC_OP_FLAG_SIGNAL) + +/** + * struct drm_pvr_sync_op - Object describing a sync operation + */ +struct drm_pvr_sync_op { + /** @handle: Handle of sync object. */ + __u32 handle; + + /** @flags: Combination of ``DRM_PVR_SYNC_OP_FLAG_`` flags. */ + __u32 flags; + + /** @value: Timeline value for this drm_syncobj. MBZ for a binary syncobj. */ + __u64 value; +}; + +/** + * DOC: Flags for SUBMIT_JOB ioctl geometry command. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST + * + * Indicates if this the first command to be issued for a render. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST + * + * Indicates if this the last command to be issued for a render. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE + * + * Forces to use single core in a multi core device. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_GEOM_CMD_FLAGS_MASK + * + * Logical OR of all the geometry cmd flags. + */ +#define DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST _BITULL(0) +#define DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST _BITULL(1) +#define DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE _BITULL(2) +#define DRM_PVR_SUBMIT_JOB_GEOM_CMD_FLAGS_MASK \ + (DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST | \ + DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST | \ + DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE) + +/** + * DOC: Flags for SUBMIT_JOB ioctl fragment command. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE + * + * Use single core in a multi core setup. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER + * + * Indicates whether a depth buffer is present. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER + * + * Indicates whether a stencil buffer is present. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP + * + * Disallow compute overlapped with this render. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS + * + * Indicates whether this render produces visibility results. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER + * + * Indicates whether partial renders write to a scratch buffer instead of + * the final surface. It also forces the full screen copy expected to be + * present on the last render after all partial renders have completed. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE + * + * Disable pixel merging for this render. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_FRAG_CMD_FLAGS_MASK + * + * Logical OR of all the fragment cmd flags. + */ +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE _BITULL(0) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER _BITULL(1) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER _BITULL(2) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP _BITULL(3) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER _BITULL(4) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS _BITULL(5) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER _BITULL(6) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE _BITULL(7) +#define DRM_PVR_SUBMIT_JOB_FRAG_CMD_FLAGS_MASK \ + (DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER | \ + DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE) + +/** + * DOC: Flags for SUBMIT_JOB ioctl compute command. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP + * + * Disallow other jobs overlapped with this compute. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE + * + * Forces to use single core in a multi core device. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_FLAGS_MASK + * + * Logical OR of all the compute cmd flags. + */ +#define DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP _BITULL(0) +#define DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE _BITULL(1) +#define DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_FLAGS_MASK \ + (DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP | \ + DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE) + +/** + * DOC: Flags for SUBMIT_JOB ioctl transfer command. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE + * + * Forces job to use a single core in a multi core device. + * + * .. c:macro:: DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_FLAGS_MASK + * + * Logical OR of all the transfer cmd flags. + */ +#define DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE _BITULL(0) + +#define DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_FLAGS_MASK \ + DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE + +/** + * enum drm_pvr_job_type - Arguments for &struct drm_pvr_job.job_type + */ +enum drm_pvr_job_type { + /** @DRM_PVR_JOB_TYPE_GEOMETRY: Job type is geometry. */ + DRM_PVR_JOB_TYPE_GEOMETRY = 0, + + /** @DRM_PVR_JOB_TYPE_FRAGMENT: Job type is fragment. */ + DRM_PVR_JOB_TYPE_FRAGMENT, + + /** @DRM_PVR_JOB_TYPE_COMPUTE: Job type is compute. */ + DRM_PVR_JOB_TYPE_COMPUTE, + + /** @DRM_PVR_JOB_TYPE_TRANSFER_FRAG: Job type is a fragment transfer. */ + DRM_PVR_JOB_TYPE_TRANSFER_FRAG, +}; + +/** + * struct drm_pvr_hwrt_data_ref - Reference HWRT data + */ +struct drm_pvr_hwrt_data_ref { + /** @set_handle: HWRT data set handle. */ + __u32 set_handle; + + /** @data_index: Index of the HWRT data inside the data set. */ + __u32 data_index; +}; + +/** + * struct drm_pvr_job - Job arguments passed to the %DRM_IOCTL_PVR_SUBMIT_JOBS ioctl + */ +struct drm_pvr_job { + /** + * @type: [IN] Type of job being submitted + * + * This must be one of the values defined by &enum drm_pvr_job_type. + */ + __u32 type; + + /** + * @context_handle: [IN] Context handle. + * + * When @job_type is %DRM_PVR_JOB_TYPE_RENDER, %DRM_PVR_JOB_TYPE_COMPUTE or + * %DRM_PVR_JOB_TYPE_TRANSFER_FRAG, this must be a valid handle returned by + * %DRM_IOCTL_PVR_CREATE_CONTEXT. The type of context must be compatible + * with the type of job being submitted. + * + * When @job_type is %DRM_PVR_JOB_TYPE_NULL, this must be zero. + */ + __u32 context_handle; + + /** + * @flags: [IN] Flags for command. + * + * Those are job-dependent. See all ``DRM_PVR_SUBMIT_JOB_*``. + */ + __u32 flags; + + /** + * @cmd_stream_len: [IN] Length of command stream, in bytes. + */ + __u32 cmd_stream_len; + + /** + * @cmd_stream: [IN] Pointer to command stream for command. + * + * The command stream must be u64-aligned. + */ + __u64 cmd_stream; + + /** @sync_ops: [IN] Fragment sync operations. */ + struct drm_pvr_obj_array sync_ops; + + /** + * @hwrt: [IN] HWRT data used by render jobs (geometry or fragment). + * + * Must be zero for non-render jobs. + */ + struct drm_pvr_hwrt_data_ref hwrt; +}; + +/** + * struct drm_pvr_ioctl_submit_jobs_args - Arguments for %DRM_IOCTL_PVR_SUBMIT_JOB + * + * If the syscall returns an error it is important to check the value of + * @jobs.count. This indicates the index into @jobs.array where the + * error occurred. + */ +struct drm_pvr_ioctl_submit_jobs_args { + /** @jobs: [IN] Array of jobs to submit. */ + struct drm_pvr_obj_array jobs; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* PVR_DRM_UAPI_H */ From 4babef0708656c54e67ee0ee3994ee98898f51d1 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:26 +0000 Subject: [PATCH 1177/7721] drm/imagination: Add skeleton PowerVR driver This adds the basic skeleton of the driver. The driver registers itself with DRM on probe. Ioctl handlers are currently implemented as stubs. Changes since v8: - Corrected license identifiers Changes since v5: - Update compatible string & description to match marketing name - Checkpatch fixes in to/from_pvr_device/file macros Changes since v3: - Clarify supported GPU generations in driver description - Use drm_dev_unplug() when removing device - Change from_* and to_* functions to macros - Fix IS_PTR/PTR_ERR confusion in pvr_probe() - Remove err_out labels in favour of direct returning - Remove specific am62 compatible match string - Drop MODULE_FIRMWARE() Co-developed-by: Frank Binns Signed-off-by: Frank Binns Co-developed-by: Matt Coster Signed-off-by: Matt Coster Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/fed8a77e29620a61aed2684f802339759082cf1b.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- MAINTAINERS | 1 + drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/imagination/Kconfig | 15 + drivers/gpu/drm/imagination/Makefile | 9 + drivers/gpu/drm/imagination/pvr_device.h | 153 +++++++ drivers/gpu/drm/imagination/pvr_drv.c | 509 +++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_drv.h | 22 + 8 files changed, 712 insertions(+) create mode 100644 drivers/gpu/drm/imagination/Kconfig create mode 100644 drivers/gpu/drm/imagination/Makefile create mode 100644 drivers/gpu/drm/imagination/pvr_device.h create mode 100644 drivers/gpu/drm/imagination/pvr_drv.c create mode 100644 drivers/gpu/drm/imagination/pvr_drv.h diff --git a/MAINTAINERS b/MAINTAINERS index 37642011c319..debbc1956b8e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10398,6 +10398,7 @@ M: Donald Robson M: Matt Coster S: Supported F: Documentation/devicetree/bindings/gpu/img,powervr.yaml +F: drivers/gpu/drm/imagination/ F: include/uapi/drm/pvr_drm.h IMON SOUNDGRAPH USB IR RECEIVER diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index cdbc56e07649..740c1c0bd068 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -394,6 +394,8 @@ source "drivers/gpu/drm/solomon/Kconfig" source "drivers/gpu/drm/sprd/Kconfig" +source "drivers/gpu/drm/imagination/Kconfig" + config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cdbe91ac0bfc..b4cb0835620a 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -199,3 +199,4 @@ obj-$(CONFIG_DRM_HYPERV) += hyperv/ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-$(CONFIG_DRM_LOONGSON) += loongson/ +obj-$(CONFIG_DRM_POWERVR) += imagination/ diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imagination/Kconfig new file mode 100644 index 000000000000..03d0a5031f5c --- /dev/null +++ b/drivers/gpu/drm/imagination/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +# Copyright (c) 2023 Imagination Technologies Ltd. + +config DRM_POWERVR + tristate "Imagination Technologies PowerVR (Series 6 and later) & IMG Graphics" + depends on ARM64 + depends on DRM + select DRM_GEM_SHMEM_HELPER + select DRM_SCHED + select FW_LOADER + help + Choose this option if you have a system that has an Imagination + Technologies PowerVR (Series 6 or later) or IMG GPU. + + If "M" is selected, the module will be called powervr. diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile new file mode 100644 index 000000000000..f12a06ada9ec --- /dev/null +++ b/drivers/gpu/drm/imagination/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +# Copyright (c) 2023 Imagination Technologies Ltd. + +subdir-ccflags-y := -I$(srctree)/$(src) + +powervr-y := \ + pvr_drv.o \ + +obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h new file mode 100644 index 000000000000..d3629164a629 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEVICE_H +#define PVR_DEVICE_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * struct pvr_device - powervr-specific wrapper for &struct drm_device + */ +struct pvr_device { + /** + * @base: The underlying &struct drm_device. + * + * Do not access this member directly, instead call + * from_pvr_device(). + */ + struct drm_device base; +}; + +/** + * struct pvr_file - powervr-specific data to be assigned to &struct + * drm_file.driver_priv + */ +struct pvr_file { + /** + * @file: A reference to the parent &struct drm_file. + * + * Do not access this member directly, instead call from_pvr_file(). + */ + struct drm_file *file; + + /** + * @pvr_dev: A reference to the powervr-specific wrapper for the + * associated device. Saves on repeated calls to + * to_pvr_device(). + */ + struct pvr_device *pvr_dev; +}; + +#define from_pvr_device(pvr_dev) (&(pvr_dev)->base) + +#define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base) + +#define from_pvr_file(pvr_file) ((pvr_file)->file) + +#define to_pvr_file(file) ((file)->driver_priv) + +/** + * DOC: IOCTL validation helpers + * + * To validate the constraints imposed on IOCTL argument structs, a collection + * of macros and helper functions exist in ``pvr_device.h``. + * + * Of the current helpers, it should only be necessary to call + * PVR_IOCTL_UNION_PADDING_CHECK() directly. This macro should be used once in + * every code path which extracts a union member from a struct passed from + * userspace. + */ + +/** + * pvr_ioctl_union_padding_check() - Validate that the implicit padding between + * the end of a union member and the end of the union itself is zeroed. + * @instance: Pointer to the instance of the struct to validate. + * @union_offset: Offset into the type of @instance of the target union. Must + * be 64-bit aligned. + * @union_size: Size of the target union in the type of @instance. Must be + * 64-bit aligned. + * @member_size: Size of the target member in the target union specified by + * @union_offset and @union_size. It is assumed that the offset of the target + * member is zero relative to @union_offset. Must be 64-bit aligned. + * + * You probably want to use PVR_IOCTL_UNION_PADDING_CHECK() instead of calling + * this function directly, since that macro abstracts away much of the setup, + * and also provides some static validation. See its docs for details. + * + * Return: + * * %true if every byte between the end of the used member of the union and + * the end of that union is zeroed, or + * * %false otherwise. + */ +static __always_inline bool +pvr_ioctl_union_padding_check(void *instance, size_t union_offset, + size_t union_size, size_t member_size) +{ + /* + * void pointer arithmetic is technically illegal - cast to a byte + * pointer so this addition works safely. + */ + void *padding_start = ((u8 *)instance) + union_offset + member_size; + size_t padding_size = union_size - member_size; + + return !memchr_inv(padding_start, 0, padding_size); +} + +/** + * PVR_STATIC_ASSERT_64BIT_ALIGNED() - Inline assertion for 64-bit alignment. + * @static_expr_: Target expression to evaluate. + * + * If @static_expr_ does not evaluate to a constant integer which would be a + * 64-bit aligned address (i.e. a multiple of 8), compilation will fail. + * + * Return: + * The value of @static_expr_. + */ +#define PVR_STATIC_ASSERT_64BIT_ALIGNED(static_expr_) \ + ({ \ + static_assert(((static_expr_) & (sizeof(u64) - 1)) == 0); \ + (static_expr_); \ + }) + +/** + * PVR_IOCTL_UNION_PADDING_CHECK() - Validate that the implicit padding between + * the end of a union member and the end of the union itself is zeroed. + * @struct_instance_: An expression which evaluates to a pointer to a UAPI data + * struct. + * @union_: The name of the union member of @struct_instance_ to check. If the + * union member is nested within the type of @struct_instance_, this may + * contain the member access operator ("."). + * @member_: The name of the member of @union_ to assess. + * + * This is a wrapper around pvr_ioctl_union_padding_check() which performs + * alignment checks and simplifies things for the caller. + * + * Return: + * * %true if every byte in @struct_instance_ between the end of @member_ and + * the end of @union_ is zeroed, or + * * %false otherwise. + */ +#define PVR_IOCTL_UNION_PADDING_CHECK(struct_instance_, union_, member_) \ + ({ \ + typeof(struct_instance_) __instance = (struct_instance_); \ + size_t __union_offset = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + offsetof(typeof(*__instance), union_)); \ + size_t __union_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + sizeof(__instance->union_)); \ + size_t __member_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + sizeof(__instance->union_.member_)); \ + pvr_ioctl_union_padding_check(__instance, __union_offset, \ + __union_size, __member_size); \ + }) + +#endif /* PVR_DEVICE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c new file mode 100644 index 000000000000..3d4f2ba2c015 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_drv.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: PowerVR (Series 6 and later) and IMG Graphics Driver + * + * This driver supports the following PowerVR/IMG graphics cores from Imagination Technologies: + * + * * AXE-1-16M (found in Texas Instruments AM62) + */ + +/** + * pvr_ioctl_create_bo() - IOCTL to create a GEM buffer object. + * @drm_dev: [IN] Target DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_bo_args. + * @file: [IN] DRM file-private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_BO. + * + * Return: + * * 0 on success, + * * -%EINVAL if the value of &drm_pvr_ioctl_create_bo_args.size is zero + * or wider than &typedef size_t, + * * -%EINVAL if any bits in &drm_pvr_ioctl_create_bo_args.flags that are + * reserved or undefined are set, + * * -%EINVAL if any padding fields in &drm_pvr_ioctl_create_bo_args are not + * zero, + * * Any error encountered while creating the object (see + * pvr_gem_object_create()), or + * * Any error encountered while transferring ownership of the object into a + * userspace-accessible handle (see pvr_gem_object_into_handle()). + */ +static int +pvr_ioctl_create_bo(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_get_bo_mmap_offset() - IOCTL to generate a "fake" offset to be + * used when calling mmap() from userspace to map the given GEM buffer object + * @drm_dev: [IN] DRM device (unused). + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_get_bo_mmap_offset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_GET_BO_MMAP_OFFSET. + * + * This IOCTL does *not* perform an mmap. See the docs on + * &struct drm_pvr_ioctl_get_bo_mmap_offset_args for details. + * + * Return: + * * 0 on success, + * * -%ENOENT if the handle does not reference a valid GEM buffer object, + * * -%EINVAL if any padding fields in &struct + * drm_pvr_ioctl_get_bo_mmap_offset_args are not zero, or + * * Any error returned by drm_gem_create_mmap_offset(). + */ +static int +pvr_ioctl_get_bo_mmap_offset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_dev_query() - IOCTL to copy information about a device + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_dev_query_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DEV_QUERY. + * If the given receiving struct pointer is NULL, or the indicated size is too + * small, the expected size of the struct type will be returned in the size + * argument field. + * + * Return: + * * 0 on success or when fetching the size with args->pointer == NULL, or + * * -%E2BIG if the indicated size of the receiving struct is less than is + * required to contain the copied data, or + * * -%EINVAL if the indicated struct type is unknown, or + * * -%ENOMEM if local memory could not be allocated, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_ioctl_dev_query(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_create_context() - IOCTL to create a context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_CONTEXT. + * + * Return: + * * 0 on success, or + * * -%EINVAL if provided arguments are invalid, or + * * -%EFAULT if arguments can't be copied from userspace, or + * * Any error returned by pvr_create_render_context(). + */ +static int +pvr_ioctl_create_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_destroy_context() - IOCTL to destroy a context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_CONTEXT. + * + * Return: + * * 0 on success, or + * * -%EINVAL if context not in context list. + */ +static int +pvr_ioctl_destroy_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_create_free_list() - IOCTL to create a free list + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_free_list_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_FREE_LIST. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_free_list_create(). + */ +static int +pvr_ioctl_create_free_list(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_destroy_free_list() - IOCTL to destroy a free list + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_free_list_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_FREE_LIST. + * + * Return: + * * 0 on success, or + * * -%EINVAL if free list not in object list. + */ +static int +pvr_ioctl_destroy_free_list(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_create_hwrt_dataset() - IOCTL to create a HWRT dataset + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_hwrt_dataset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_HWRT_DATASET. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_hwrt_dataset_create(). + */ +static int +pvr_ioctl_create_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_destroy_hwrt_dataset() - IOCTL to destroy a HWRT dataset + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_hwrt_dataset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_HWRT_DATASET. + * + * Return: + * * 0 on success, or + * * -%EINVAL if HWRT dataset not in object list. + */ +static int +pvr_ioctl_destroy_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_create_vm_context() - IOCTL to create a VM context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_vm_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_VM_CONTEXT. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_vm_create_context(). + */ +static int +pvr_ioctl_create_vm_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_destroy_vm_context() - IOCTL to destroy a VM context +* @drm_dev: [IN] DRM device. +* @raw_args: [IN] Arguments passed to this IOCTL. This must be of type +* &struct drm_pvr_ioctl_destroy_vm_context_args. +* @file: [IN] DRM file private data. +* +* Called from userspace with %DRM_IOCTL_PVR_DESTROY_VM_CONTEXT. +* +* Return: +* * 0 on success, or +* * -%EINVAL if object not in object list. + */ +static int +pvr_ioctl_destroy_vm_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_vm_map() - IOCTL to map buffer to GPU address space. + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_vm_map_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_VM_MAP. + * + * Return: + * * 0 on success, + * * -%EINVAL if &drm_pvr_ioctl_vm_op_map_args.flags is not zero, + * * -%EINVAL if the bounds specified by &drm_pvr_ioctl_vm_op_map_args.offset + * and &drm_pvr_ioctl_vm_op_map_args.size are not valid or do not fall + * within the buffer object specified by + * &drm_pvr_ioctl_vm_op_map_args.handle, + * * -%EINVAL if the bounds specified by + * &drm_pvr_ioctl_vm_op_map_args.device_addr and + * &drm_pvr_ioctl_vm_op_map_args.size do not form a valid device-virtual + * address range which falls entirely within a single heap, or + * * -%ENOENT if &drm_pvr_ioctl_vm_op_map_args.handle does not refer to a + * valid PowerVR buffer object. + */ +static int +pvr_ioctl_vm_map(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/** + * pvr_ioctl_vm_unmap() - IOCTL to unmap buffer from GPU address space. + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_vm_unmap_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_VM_UNMAP. + * + * Return: + * * 0 on success, + * * -%EINVAL if &drm_pvr_ioctl_vm_op_unmap_args.device_addr is not a valid + * device page-aligned device-virtual address, or + * * -%ENOENT if there is currently no PowerVR buffer object mapped at + * &drm_pvr_ioctl_vm_op_unmap_args.device_addr. + */ +static int +pvr_ioctl_vm_unmap(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +/* + * pvr_ioctl_submit_job() - IOCTL to submit a job to the GPU + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_submit_job_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_SUBMIT_JOB. + * + * Return: + * * 0 on success, or + * * -%EINVAL if arguments are invalid. + */ +static int +pvr_ioctl_submit_jobs(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + return -ENOTTY; +} + +#define DRM_PVR_IOCTL(_name, _func, _flags) \ + DRM_IOCTL_DEF_DRV(PVR_##_name, pvr_ioctl_##_func, _flags) + +/* clang-format off */ + +static const struct drm_ioctl_desc pvr_drm_driver_ioctls[] = { + DRM_PVR_IOCTL(DEV_QUERY, dev_query, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(GET_BO_MMAP_OFFSET, get_bo_mmap_offset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_VM_CONTEXT, create_vm_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_VM_CONTEXT, destroy_vm_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(VM_MAP, vm_map, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(VM_UNMAP, vm_unmap, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_CONTEXT, create_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_CONTEXT, destroy_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_FREE_LIST, create_free_list, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_FREE_LIST, destroy_free_list, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_HWRT_DATASET, create_hwrt_dataset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_HWRT_DATASET, destroy_hwrt_dataset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(SUBMIT_JOBS, submit_jobs, DRM_RENDER_ALLOW), +}; + +/* clang-format on */ + +#undef DRM_PVR_IOCTL + +/** + * pvr_drm_driver_open() - Driver callback when a new &struct drm_file is opened + * @drm_dev: [IN] DRM device. + * @file: [IN] DRM file private data. + * + * Allocates powervr-specific file private data (&struct pvr_file). + * + * Registered in &pvr_drm_driver. + * + * Return: + * * 0 on success, + * * -%ENOMEM if the allocation of a &struct ipvr_file fails, or + * * Any error returned by pvr_memory_context_init(). + */ +static int +pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file; + + pvr_file = kzalloc(sizeof(*pvr_file), GFP_KERNEL); + if (!pvr_file) + return -ENOMEM; + + /* + * Store reference to base DRM file private data for use by + * from_pvr_file. + */ + pvr_file->file = file; + + /* + * Store reference to powervr-specific outer device struct in file + * private data for convenient access. + */ + pvr_file->pvr_dev = pvr_dev; + + /* + * Store reference to powervr-specific file private data in DRM file + * private data. + */ + file->driver_priv = pvr_file; + + return 0; +} + +/** + * pvr_drm_driver_postclose() - One of the driver callbacks when a &struct + * drm_file is closed. + * @drm_dev: [IN] DRM device (unused). + * @file: [IN] DRM file private data. + * + * Frees powervr-specific file private data (&struct pvr_file). + * + * Registered in &pvr_drm_driver. + */ +static void +pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, + struct drm_file *file) +{ + struct pvr_file *pvr_file = to_pvr_file(file); + + kfree(pvr_file); + file->driver_priv = NULL; +} + +DEFINE_DRM_GEM_FOPS(pvr_drm_driver_fops); + +static struct drm_driver pvr_drm_driver = { + .driver_features = DRIVER_RENDER, + .open = pvr_drm_driver_open, + .postclose = pvr_drm_driver_postclose, + .ioctls = pvr_drm_driver_ioctls, + .num_ioctls = ARRAY_SIZE(pvr_drm_driver_ioctls), + .fops = &pvr_drm_driver_fops, + + .name = PVR_DRIVER_NAME, + .desc = PVR_DRIVER_DESC, + .date = PVR_DRIVER_DATE, + .major = PVR_DRIVER_MAJOR, + .minor = PVR_DRIVER_MINOR, + .patchlevel = PVR_DRIVER_PATCHLEVEL, + +}; + +static int +pvr_probe(struct platform_device *plat_dev) +{ + struct pvr_device *pvr_dev; + struct drm_device *drm_dev; + + pvr_dev = devm_drm_dev_alloc(&plat_dev->dev, &pvr_drm_driver, + struct pvr_device, base); + if (IS_ERR(pvr_dev)) + return PTR_ERR(pvr_dev); + + drm_dev = &pvr_dev->base; + + platform_set_drvdata(plat_dev, drm_dev); + + return drm_dev_register(drm_dev, 0); +} + +static int +pvr_remove(struct platform_device *plat_dev) +{ + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + + drm_dev_unplug(drm_dev); + + return 0; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "img,img-axe", .data = NULL }, + {} +}; +MODULE_DEVICE_TABLE(of, dt_match); + +static struct platform_driver pvr_driver = { + .probe = pvr_probe, + .remove = pvr_remove, + .driver = { + .name = PVR_DRIVER_NAME, + .of_match_table = dt_match, + }, +}; +module_platform_driver(pvr_driver); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION(PVR_DRIVER_DESC); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_IMPORT_NS(DMA_BUF); diff --git a/drivers/gpu/drm/imagination/pvr_drv.h b/drivers/gpu/drm/imagination/pvr_drv.h new file mode 100644 index 000000000000..c29d11af88fe --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_drv.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DRV_H +#define PVR_DRV_H + +#include "linux/compiler_attributes.h" +#include + +#define PVR_DRIVER_NAME "powervr" +#define PVR_DRIVER_DESC "Imagination PowerVR (Series 6 and later) & IMG Graphics" +#define PVR_DRIVER_DATE "20230904" + +/* + * Driver interface version: + * - 1.0: Initial interface + */ +#define PVR_DRIVER_MAJOR 1 +#define PVR_DRIVER_MINOR 0 +#define PVR_DRIVER_PATCHLEVEL 0 + +#endif /* PVR_DRV_H */ From 1f88f017e6499261f46d3468befac7b1cdc96e52 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:27 +0000 Subject: [PATCH 1178/7721] drm/imagination: Get GPU resources Acquire clock and register resources, and enable/map as appropriate. Changes since v8: - Corrected license identifiers Changes since v3: - Remove regulator resource (not used on supported platform) - Use devm helpers - Use devm_clk_get_optional() for optional clocks - Don't prepare clocks on resource acquisition - Drop pvr_device_clk_core_get_freq() helper - Drop pvr_device_reg_fini() - Drop NULLing of clocks in pvr_device_clk_init() - Use dev_err_probe() on clock acquisition failure - Remove PVR_CR_READ/WRITE helper macros - Improve documentation for GPU clocks - Remove regs resource (not used in this commit) Co-developed-by: Frank Binns Signed-off-by: Frank Binns Co-developed-by: Matt Coster Signed-off-by: Matt Coster Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/579027bd5be4eb3218c9784050ded2326ecbc352.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 1 + drivers/gpu/drm/imagination/pvr_device.c | 147 ++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_device.h | 152 +++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_drv.c | 18 ++- 4 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/imagination/pvr_device.c diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index f12a06ada9ec..d36007f2825c 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -4,6 +4,7 @@ subdir-ccflags-y := -I$(srctree)/$(src) powervr-y := \ + pvr_device.o \ pvr_drv.o \ obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c new file mode 100644 index 000000000000..abcdf733f57b --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * pvr_device_reg_init() - Initialize kernel access to a PowerVR device's + * control registers. + * @pvr_dev: Target PowerVR device. + * + * Sets struct pvr_device->regs. + * + * This method of mapping the device control registers into memory ensures that + * they are unmapped when the driver is detached (i.e. no explicit cleanup is + * required). + * + * Return: + * * 0 on success, or + * * Any error returned by devm_platform_ioremap_resource(). + */ +static int +pvr_device_reg_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct platform_device *plat_dev = to_platform_device(drm_dev->dev); + void __iomem *regs; + + pvr_dev->regs = NULL; + + regs = devm_platform_ioremap_resource(plat_dev, 0); + if (IS_ERR(regs)) + return dev_err_probe(drm_dev->dev, PTR_ERR(regs), + "failed to ioremap gpu registers\n"); + + pvr_dev->regs = regs; + + return 0; +} + +/** + * pvr_device_clk_init() - Initialize clocks required by a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * Sets struct pvr_device->core_clk, struct pvr_device->sys_clk and + * struct pvr_device->mem_clk. + * + * Three clocks are required by the PowerVR device: core, sys and mem. On + * return, this function guarantees that the clocks are in one of the following + * states: + * + * * All successfully initialized, + * * Core errored, sys and mem uninitialized, + * * Core deinitialized, sys errored, mem uninitialized, or + * * Core and sys deinitialized, mem errored. + * + * Return: + * * 0 on success, + * * Any error returned by devm_clk_get(), or + * * Any error returned by devm_clk_get_optional(). + */ +static int pvr_device_clk_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct clk *core_clk; + struct clk *sys_clk; + struct clk *mem_clk; + + core_clk = devm_clk_get(drm_dev->dev, "core"); + if (IS_ERR(core_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + "failed to get core clock\n"); + + sys_clk = devm_clk_get_optional(drm_dev->dev, "sys"); + if (IS_ERR(sys_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + "failed to get sys clock\n"); + + mem_clk = devm_clk_get_optional(drm_dev->dev, "mem"); + if (IS_ERR(mem_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + "failed to get mem clock\n"); + + pvr_dev->core_clk = core_clk; + pvr_dev->sys_clk = sys_clk; + pvr_dev->mem_clk = mem_clk; + + return 0; +} + +/** + * pvr_device_init() - Initialize a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * If this function returns successfully, the device will have been fully + * initialized. Otherwise, any parts of the device initialized before an error + * occurs will be de-initialized before returning. + * + * NOTE: The initialization steps currently taken are the bare minimum required + * to read from the control registers. The device is unlikely to function + * until further initialization steps are added. [This note should be + * removed when that happens.] + * + * Return: + * * 0 on success, + * * Any error returned by pvr_device_reg_init(), + * * Any error returned by pvr_device_clk_init(), or + * * Any error returned by pvr_device_gpu_init(). + */ +int +pvr_device_init(struct pvr_device *pvr_dev) +{ + int err; + + /* Enable and initialize clocks required for the device to operate. */ + err = pvr_device_clk_init(pvr_dev); + if (err) + return err; + + /* Map the control registers into memory. */ + return pvr_device_reg_init(pvr_dev); +} + +/** + * pvr_device_fini() - Deinitialize a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +void +pvr_device_fini(struct pvr_device *pvr_dev) +{ + /* + * Deinitialization stages are performed in reverse order compared to + * the initialization stages in pvr_device_init(). + */ +} diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index d3629164a629..d9d2804f4454 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -11,9 +11,22 @@ #include #include #include +#include +#include #include +#include +#include +#include #include #include +#include +#include + +/* Forward declaration from . */ +struct clk; + +/* Forward declaration from . */ +struct firmware; /** * struct pvr_device - powervr-specific wrapper for &struct drm_device @@ -26,6 +39,37 @@ struct pvr_device { * from_pvr_device(). */ struct drm_device base; + + /** + * @regs: Device control registers. + * + * These are mapped into memory when the device is initialized; that + * location is where this pointer points. + */ + void __iomem *regs; + + /** + * @core_clk: General core clock. + * + * This is the primary clock used by the entire GPU core. + */ + struct clk *core_clk; + + /** + * @sys_clk: Optional system bus clock. + * + * This may be used on some platforms to provide an independent clock to the SoC Interface + * (SOCIF). If present, this needs to be enabled/disabled together with @core_clk. + */ + struct clk *sys_clk; + + /** + * @mem_clk: Optional memory clock. + * + * This may be used on some platforms to provide an independent clock to the Memory + * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk. + */ + struct clk *mem_clk; }; /** @@ -56,6 +100,114 @@ struct pvr_file { #define to_pvr_file(file) ((file)->driver_priv) +int pvr_device_init(struct pvr_device *pvr_dev); +void pvr_device_fini(struct pvr_device *pvr_dev); + +/** + * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register + * @val: Value of the target register. + * @field: Field specifier, as defined in "pvr_rogue_cr_defs.h". + * + * Return: The extracted field. + */ +#define PVR_CR_FIELD_GET(val, field) FIELD_GET(~ROGUE_CR_##field##_CLRMSK, val) + +/** + * pvr_cr_read32() - Read a 32-bit register from a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * + * Return: The value of the requested register. + */ +static __always_inline u32 +pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg) +{ + return ioread32(pvr_dev->regs + reg); +} + +/** + * pvr_cr_read64() - Read a 64-bit register from a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * + * Return: The value of the requested register. + */ +static __always_inline u64 +pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg) +{ + return ioread64(pvr_dev->regs + reg); +} + +/** + * pvr_cr_write32() - Write to a 32-bit register in a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * @val: Value to write. + */ +static __always_inline void +pvr_cr_write32(struct pvr_device *pvr_dev, u32 reg, u32 val) +{ + iowrite32(val, pvr_dev->regs + reg); +} + +/** + * pvr_cr_write64() - Write to a 64-bit register in a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * @val: Value to write. + */ +static __always_inline void +pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val) +{ + iowrite64(val, pvr_dev->regs + reg); +} + +/** + * pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by + * polling + * @pvr_dev: Target PowerVR device. + * @reg_addr: Address of register. + * @reg_value: Expected register value (after masking). + * @reg_mask: Mask of bits valid for comparison with @reg_value. + * @timeout_usec: Timeout length, in us. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT on timeout. + */ +static __always_inline int +pvr_cr_poll_reg32(struct pvr_device *pvr_dev, u32 reg_addr, u32 reg_value, + u32 reg_mask, u64 timeout_usec) +{ + u32 value; + + return readl_poll_timeout(pvr_dev->regs + reg_addr, value, + (value & reg_mask) == reg_value, 0, timeout_usec); +} + +/** + * pvr_cr_poll_reg64() - Wait for a 64-bit register to match a given value by + * polling + * @pvr_dev: Target PowerVR device. + * @reg_addr: Address of register. + * @reg_value: Expected register value (after masking). + * @reg_mask: Mask of bits valid for comparison with @reg_value. + * @timeout_usec: Timeout length, in us. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT on timeout. + */ +static __always_inline int +pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value, + u64 reg_mask, u64 timeout_usec) +{ + u64 value; + + return readq_poll_timeout(pvr_dev->regs + reg_addr, value, + (value & reg_mask) == reg_value, 0, timeout_usec); +} + /** * DOC: IOCTL validation helpers * diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 3d4f2ba2c015..597188b31f96 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -464,6 +464,7 @@ pvr_probe(struct platform_device *plat_dev) { struct pvr_device *pvr_dev; struct drm_device *drm_dev; + int err; pvr_dev = devm_drm_dev_alloc(&plat_dev->dev, &pvr_drm_driver, struct pvr_device, base); @@ -474,14 +475,29 @@ pvr_probe(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, drm_dev); - return drm_dev_register(drm_dev, 0); + err = pvr_device_init(pvr_dev); + if (err) + return err; + + err = drm_dev_register(drm_dev, 0); + if (err) + goto err_device_fini; + + return 0; + +err_device_fini: + pvr_device_fini(pvr_dev); + + return err; } static int pvr_remove(struct platform_device *plat_dev) { struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + pvr_device_fini(pvr_dev); drm_dev_unplug(drm_dev); return 0; From b41ae495207eaab1363ac3d424e67f3f354ca2ce Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:28 +0000 Subject: [PATCH 1179/7721] drm/imagination: Add GPU register headers Changes since v8: - Corrected license identifiers Changes since v5: - Split up header commit due to size Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/9f1fbf6c18e9644ac10712e05893701f06aee6ae.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- .../gpu/drm/imagination/pvr_rogue_cr_defs.h | 6193 +++++++++++++++++ .../imagination/pvr_rogue_cr_defs_client.h | 159 + drivers/gpu/drm/imagination/pvr_rogue_defs.h | 179 + 3 files changed, 6531 insertions(+) create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_defs.h diff --git a/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h new file mode 100644 index 000000000000..2a90d02796d3 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h @@ -0,0 +1,6193 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +/* *** Autogenerated C -- do not edit *** */ + +#ifndef PVR_ROGUE_CR_DEFS_H +#define PVR_ROGUE_CR_DEFS_H + +/* clang-format off */ + +#define ROGUE_CR_DEFS_REVISION 1 + +/* Register ROGUE_CR_RASTERISATION_INDIRECT */ +#define ROGUE_CR_RASTERISATION_INDIRECT 0x8238U +#define ROGUE_CR_RASTERISATION_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_RASTERISATION_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_RASTERISATION_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_PBE_INDIRECT */ +#define ROGUE_CR_PBE_INDIRECT 0x83E0U +#define ROGUE_CR_PBE_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_PBE_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_PBE_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_PBE_PERF_INDIRECT */ +#define ROGUE_CR_PBE_PERF_INDIRECT 0x83D8U +#define ROGUE_CR_PBE_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_PBE_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_PBE_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_TPU_PERF_INDIRECT */ +#define ROGUE_CR_TPU_PERF_INDIRECT 0x83F0U +#define ROGUE_CR_TPU_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TPU_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TPU_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_RASTERISATION_PERF_INDIRECT */ +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT 0x8318U +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT */ +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT 0x8028U +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_USC_PERF_INDIRECT */ +#define ROGUE_CR_USC_PERF_INDIRECT 0x8030U +#define ROGUE_CR_USC_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_USC_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_USC_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_BLACKPEARL_INDIRECT */ +#define ROGUE_CR_BLACKPEARL_INDIRECT 0x8388U +#define ROGUE_CR_BLACKPEARL_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BLACKPEARL_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_BLACKPEARL_PERF_INDIRECT */ +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT 0x83F8U +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_TEXAS3_PERF_INDIRECT */ +#define ROGUE_CR_TEXAS3_PERF_INDIRECT 0x83D0U +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_TEXAS_PERF_INDIRECT */ +#define ROGUE_CR_TEXAS_PERF_INDIRECT 0x8288U +#define ROGUE_CR_TEXAS_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_TEXAS_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_BX_TU_PERF_INDIRECT */ +#define ROGUE_CR_BX_TU_PERF_INDIRECT 0xC900U +#define ROGUE_CR_BX_TU_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BX_TU_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BX_TU_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_CLK_CTRL */ +#define ROGUE_CR_CLK_CTRL 0x0000U +#define ROGUE_CR_CLK_CTRL__PBE2_XE__MASKFULL 0xFFFFFF003F3FFFFFULL +#define ROGUE_CR_CLK_CTRL__S7_TOP__MASKFULL 0xCFCF03000F3F3F0FULL +#define ROGUE_CR_CLK_CTRL_MASKFULL 0xFFFFFF003F3FFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_SHIFT 62U +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_CLRMSK 0x3FFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_ON 0x4000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_AUTO 0x8000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_SHIFT 60U +#define ROGUE_CR_CLK_CTRL_IPP_CLRMSK 0xCFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_IPP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_ON 0x1000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_AUTO 0x2000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_SHIFT 58U +#define ROGUE_CR_CLK_CTRL_FBC_CLRMSK 0xF3FFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FBC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_ON 0x0400000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_AUTO 0x0800000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_SHIFT 56U +#define ROGUE_CR_CLK_CTRL_FBDC_CLRMSK 0xFCFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FBDC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_ON 0x0100000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_AUTO 0x0200000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_SHIFT 54U +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_CLRMSK 0xFF3FFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_ON 0x0040000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_AUTO 0x0080000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_SHIFT 52U +#define ROGUE_CR_CLK_CTRL_USCS_CLRMSK 0xFFCFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_USCS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_ON 0x0010000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_AUTO 0x0020000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_SHIFT 50U +#define ROGUE_CR_CLK_CTRL_PBE_CLRMSK 0xFFF3FFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_PBE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_ON 0x0004000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_AUTO 0x0008000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_SHIFT 48U +#define ROGUE_CR_CLK_CTRL_MCU_L1_CLRMSK 0xFFFCFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_ON 0x0001000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_AUTO 0x0002000000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_SHIFT 46U +#define ROGUE_CR_CLK_CTRL_CDM_CLRMSK 0xFFFF3FFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_CDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_ON 0x0000400000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_AUTO 0x0000800000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_SHIFT 44U +#define ROGUE_CR_CLK_CTRL_SIDEKICK_CLRMSK 0xFFFFCFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_ON 0x0000100000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_AUTO 0x0000200000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_SHIFT 42U +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_CLRMSK 0xFFFFF3FFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_ON 0x0000040000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_AUTO 0x0000080000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SHIFT 40U +#define ROGUE_CR_CLK_CTRL_BIF_CLRMSK 0xFFFFFCFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_ON 0x0000010000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_AUTO 0x0000020000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_SHIFT 28U +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFCFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_ON 0x0000000010000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_AUTO 0x0000000020000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_SHIFT 26U +#define ROGUE_CR_CLK_CTRL_MCU_L0_CLRMSK 0xFFFFFFFFF3FFFFFFULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_ON 0x0000000004000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_AUTO 0x0000000008000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_SHIFT 24U +#define ROGUE_CR_CLK_CTRL_TPU_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_CLK_CTRL_TPU_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_ON 0x0000000001000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_AUTO 0x0000000002000000ULL +#define ROGUE_CR_CLK_CTRL_USC_SHIFT 20U +#define ROGUE_CR_CLK_CTRL_USC_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_CLK_CTRL_USC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_USC_ON 0x0000000000100000ULL +#define ROGUE_CR_CLK_CTRL_USC_AUTO 0x0000000000200000ULL +#define ROGUE_CR_CLK_CTRL_TLA_SHIFT 18U +#define ROGUE_CR_CLK_CTRL_TLA_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_CLK_CTRL_TLA_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TLA_ON 0x0000000000040000ULL +#define ROGUE_CR_CLK_CTRL_TLA_AUTO 0x0000000000080000ULL +#define ROGUE_CR_CLK_CTRL_SLC_SHIFT 16U +#define ROGUE_CR_CLK_CTRL_SLC_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_CLK_CTRL_SLC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_SLC_ON 0x0000000000010000ULL +#define ROGUE_CR_CLK_CTRL_SLC_AUTO 0x0000000000020000ULL +#define ROGUE_CR_CLK_CTRL_UVS_SHIFT 14U +#define ROGUE_CR_CLK_CTRL_UVS_CLRMSK 0xFFFFFFFFFFFF3FFFULL +#define ROGUE_CR_CLK_CTRL_UVS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_UVS_ON 0x0000000000004000ULL +#define ROGUE_CR_CLK_CTRL_UVS_AUTO 0x0000000000008000ULL +#define ROGUE_CR_CLK_CTRL_PDS_SHIFT 12U +#define ROGUE_CR_CLK_CTRL_PDS_CLRMSK 0xFFFFFFFFFFFFCFFFULL +#define ROGUE_CR_CLK_CTRL_PDS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PDS_ON 0x0000000000001000ULL +#define ROGUE_CR_CLK_CTRL_PDS_AUTO 0x0000000000002000ULL +#define ROGUE_CR_CLK_CTRL_VDM_SHIFT 10U +#define ROGUE_CR_CLK_CTRL_VDM_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_CLK_CTRL_VDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_VDM_ON 0x0000000000000400ULL +#define ROGUE_CR_CLK_CTRL_VDM_AUTO 0x0000000000000800ULL +#define ROGUE_CR_CLK_CTRL_PM_SHIFT 8U +#define ROGUE_CR_CLK_CTRL_PM_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_CLK_CTRL_PM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PM_ON 0x0000000000000100ULL +#define ROGUE_CR_CLK_CTRL_PM_AUTO 0x0000000000000200ULL +#define ROGUE_CR_CLK_CTRL_GPP_SHIFT 6U +#define ROGUE_CR_CLK_CTRL_GPP_CLRMSK 0xFFFFFFFFFFFFFF3FULL +#define ROGUE_CR_CLK_CTRL_GPP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_GPP_ON 0x0000000000000040ULL +#define ROGUE_CR_CLK_CTRL_GPP_AUTO 0x0000000000000080ULL +#define ROGUE_CR_CLK_CTRL_TE_SHIFT 4U +#define ROGUE_CR_CLK_CTRL_TE_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_CLK_CTRL_TE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TE_ON 0x0000000000000010ULL +#define ROGUE_CR_CLK_CTRL_TE_AUTO 0x0000000000000020ULL +#define ROGUE_CR_CLK_CTRL_TSP_SHIFT 2U +#define ROGUE_CR_CLK_CTRL_TSP_CLRMSK 0xFFFFFFFFFFFFFFF3ULL +#define ROGUE_CR_CLK_CTRL_TSP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TSP_ON 0x0000000000000004ULL +#define ROGUE_CR_CLK_CTRL_TSP_AUTO 0x0000000000000008ULL +#define ROGUE_CR_CLK_CTRL_ISP_SHIFT 0U +#define ROGUE_CR_CLK_CTRL_ISP_CLRMSK 0xFFFFFFFFFFFFFFFCULL +#define ROGUE_CR_CLK_CTRL_ISP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_ISP_ON 0x0000000000000001ULL +#define ROGUE_CR_CLK_CTRL_ISP_AUTO 0x0000000000000002ULL + +/* Register ROGUE_CR_CLK_STATUS */ +#define ROGUE_CR_CLK_STATUS 0x0008U +#define ROGUE_CR_CLK_STATUS__PBE2_XE__MASKFULL 0x00000001FFF077FFULL +#define ROGUE_CR_CLK_STATUS__S7_TOP__MASKFULL 0x00000001B3101773ULL +#define ROGUE_CR_CLK_STATUS_MASKFULL 0x00000001FFF077FFULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_SHIFT 32U +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_RUNNING 0x0000000100000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_SHIFT 31U +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_RUNNING 0x0000000080000000ULL +#define ROGUE_CR_CLK_STATUS_IPP_SHIFT 30U +#define ROGUE_CR_CLK_STATUS_IPP_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_IPP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_IPP_RUNNING 0x0000000040000000ULL +#define ROGUE_CR_CLK_STATUS_FBC_SHIFT 29U +#define ROGUE_CR_CLK_STATUS_FBC_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_FBC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FBC_RUNNING 0x0000000020000000ULL +#define ROGUE_CR_CLK_STATUS_FBDC_SHIFT 28U +#define ROGUE_CR_CLK_STATUS_FBDC_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_FBDC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FBDC_RUNNING 0x0000000010000000ULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_SHIFT 27U +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_RUNNING 0x0000000008000000ULL +#define ROGUE_CR_CLK_STATUS_USCS_SHIFT 26U +#define ROGUE_CR_CLK_STATUS_USCS_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_CLK_STATUS_USCS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_USCS_RUNNING 0x0000000004000000ULL +#define ROGUE_CR_CLK_STATUS_PBE_SHIFT 25U +#define ROGUE_CR_CLK_STATUS_PBE_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_CLK_STATUS_PBE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PBE_RUNNING 0x0000000002000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_SHIFT 24U +#define ROGUE_CR_CLK_STATUS_MCU_L1_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_RUNNING 0x0000000001000000ULL +#define ROGUE_CR_CLK_STATUS_CDM_SHIFT 23U +#define ROGUE_CR_CLK_STATUS_CDM_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_CLK_STATUS_CDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_CDM_RUNNING 0x0000000000800000ULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_SHIFT 22U +#define ROGUE_CR_CLK_STATUS_SIDEKICK_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_RUNNING 0x0000000000400000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_SHIFT 21U +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_RUNNING 0x0000000000200000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SHIFT 20U +#define ROGUE_CR_CLK_STATUS_BIF_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_RUNNING 0x0000000000100000ULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_SHIFT 14U +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_RUNNING 0x0000000000004000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_SHIFT 13U +#define ROGUE_CR_CLK_STATUS_MCU_L0_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_RUNNING 0x0000000000002000ULL +#define ROGUE_CR_CLK_STATUS_TPU_SHIFT 12U +#define ROGUE_CR_CLK_STATUS_TPU_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_CLK_STATUS_TPU_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TPU_RUNNING 0x0000000000001000ULL +#define ROGUE_CR_CLK_STATUS_USC_SHIFT 10U +#define ROGUE_CR_CLK_STATUS_USC_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_CLK_STATUS_USC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_USC_RUNNING 0x0000000000000400ULL +#define ROGUE_CR_CLK_STATUS_TLA_SHIFT 9U +#define ROGUE_CR_CLK_STATUS_TLA_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_CLK_STATUS_TLA_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TLA_RUNNING 0x0000000000000200ULL +#define ROGUE_CR_CLK_STATUS_SLC_SHIFT 8U +#define ROGUE_CR_CLK_STATUS_SLC_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_CLK_STATUS_SLC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_SLC_RUNNING 0x0000000000000100ULL +#define ROGUE_CR_CLK_STATUS_UVS_SHIFT 7U +#define ROGUE_CR_CLK_STATUS_UVS_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_CLK_STATUS_UVS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_UVS_RUNNING 0x0000000000000080ULL +#define ROGUE_CR_CLK_STATUS_PDS_SHIFT 6U +#define ROGUE_CR_CLK_STATUS_PDS_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_CLK_STATUS_PDS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PDS_RUNNING 0x0000000000000040ULL +#define ROGUE_CR_CLK_STATUS_VDM_SHIFT 5U +#define ROGUE_CR_CLK_STATUS_VDM_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_CLK_STATUS_VDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_VDM_RUNNING 0x0000000000000020ULL +#define ROGUE_CR_CLK_STATUS_PM_SHIFT 4U +#define ROGUE_CR_CLK_STATUS_PM_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_STATUS_PM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PM_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_STATUS_GPP_SHIFT 3U +#define ROGUE_CR_CLK_STATUS_GPP_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_CLK_STATUS_GPP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_GPP_RUNNING 0x0000000000000008ULL +#define ROGUE_CR_CLK_STATUS_TE_SHIFT 2U +#define ROGUE_CR_CLK_STATUS_TE_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_STATUS_TE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TE_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_STATUS_TSP_SHIFT 1U +#define ROGUE_CR_CLK_STATUS_TSP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_CLK_STATUS_TSP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TSP_RUNNING 0x0000000000000002ULL +#define ROGUE_CR_CLK_STATUS_ISP_SHIFT 0U +#define ROGUE_CR_CLK_STATUS_ISP_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_STATUS_ISP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_ISP_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_CORE_ID */ +#define ROGUE_CR_CORE_ID__PBVNC 0x0020U +#define ROGUE_CR_CORE_ID__PBVNC__MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__BRANCH_ID_SHIFT 48U +#define ROGUE_CR_CORE_ID__PBVNC__BRANCH_ID_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__VERSION_ID_SHIFT 32U +#define ROGUE_CR_CORE_ID__PBVNC__VERSION_ID_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS_SHIFT 16U +#define ROGUE_CR_CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__CONFIG_ID_SHIFT 0U +#define ROGUE_CR_CORE_ID__PBVNC__CONFIG_ID_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_CORE_ID */ +#define ROGUE_CR_CORE_ID 0x0018U +#define ROGUE_CR_CORE_ID_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CORE_ID_ID_SHIFT 16U +#define ROGUE_CR_CORE_ID_ID_CLRMSK 0x0000FFFFU +#define ROGUE_CR_CORE_ID_CONFIG_SHIFT 0U +#define ROGUE_CR_CORE_ID_CONFIG_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_CORE_REVISION */ +#define ROGUE_CR_CORE_REVISION 0x0020U +#define ROGUE_CR_CORE_REVISION_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CORE_REVISION_DESIGNER_SHIFT 24U +#define ROGUE_CR_CORE_REVISION_DESIGNER_CLRMSK 0x00FFFFFFU +#define ROGUE_CR_CORE_REVISION_MAJOR_SHIFT 16U +#define ROGUE_CR_CORE_REVISION_MAJOR_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CORE_REVISION_MINOR_SHIFT 8U +#define ROGUE_CR_CORE_REVISION_MINOR_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CORE_REVISION_MAINTENANCE_SHIFT 0U +#define ROGUE_CR_CORE_REVISION_MAINTENANCE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_DESIGNER_REV_FIELD1 */ +#define ROGUE_CR_DESIGNER_REV_FIELD1 0x0028U +#define ROGUE_CR_DESIGNER_REV_FIELD1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0U +#define ROGUE_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_CLRMSK 0x00000000U + +/* Register ROGUE_CR_DESIGNER_REV_FIELD2 */ +#define ROGUE_CR_DESIGNER_REV_FIELD2 0x0030U +#define ROGUE_CR_DESIGNER_REV_FIELD2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0U +#define ROGUE_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_CHANGESET_NUMBER */ +#define ROGUE_CR_CHANGESET_NUMBER 0x0040U +#define ROGUE_CR_CHANGESET_NUMBER_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CHANGESET_NUMBER_CHANGESET_NUMBER_SHIFT 0U +#define ROGUE_CR_CHANGESET_NUMBER_CHANGESET_NUMBER_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_CLK_XTPLUS_CTRL */ +#define ROGUE_CR_CLK_XTPLUS_CTRL 0x0080U +#define ROGUE_CR_CLK_XTPLUS_CTRL_MASKFULL 0x0000003FFFFF0000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_SHIFT 36U +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_CLRMSK 0xFFFFFFCFFFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_ON 0x0000001000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_AUTO 0x0000002000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_SHIFT 34U +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_CLRMSK 0xFFFFFFF3FFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_ON 0x0000000400000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_AUTO 0x0000000800000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_SHIFT 32U +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_CLRMSK 0xFFFFFFFCFFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_ON 0x0000000100000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_AUTO 0x0000000200000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_SHIFT 30U +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_CLRMSK 0xFFFFFFFF3FFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_ON 0x0000000040000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_AUTO 0x0000000080000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_SHIFT 28U +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_CLRMSK 0xFFFFFFFFCFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_ON 0x0000000010000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_AUTO 0x0000000020000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_SHIFT 26U +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_CLRMSK 0xFFFFFFFFF3FFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_ON 0x0000000004000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_AUTO 0x0000000008000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_SHIFT 24U +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_ON 0x0000000001000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_AUTO 0x0000000002000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_SHIFT 22U +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_CLRMSK 0xFFFFFFFFFF3FFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_ON 0x0000000000400000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_AUTO 0x0000000000800000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_SHIFT 20U +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_ON 0x0000000000100000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_AUTO 0x0000000000200000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_SHIFT 18U +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_ON 0x0000000000040000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_AUTO 0x0000000000080000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_SHIFT 16U +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_ON 0x0000000000010000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_AUTO 0x0000000000020000ULL + +/* Register ROGUE_CR_CLK_XTPLUS_STATUS */ +#define ROGUE_CR_CLK_XTPLUS_STATUS 0x0088U +#define ROGUE_CR_CLK_XTPLUS_STATUS_MASKFULL 0x00000000000007FFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_SHIFT 10U +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_RUNNING 0x0000000000000400ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_SHIFT 9U +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_RUNNING 0x0000000000000200ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_SHIFT 8U +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_RUNNING 0x0000000000000100ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_SHIFT 7U +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_RUNNING 0x0000000000000080ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_SHIFT 6U +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_RUNNING 0x0000000000000040ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_SHIFT 5U +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_RUNNING 0x0000000000000020ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_SHIFT 4U +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_SHIFT 3U +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_RUNNING 0x0000000000000008ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_SHIFT 2U +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_SHIFT 1U +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_RUNNING 0x0000000000000002ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_SHIFT 0U +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_SOFT_RESET */ +#define ROGUE_CR_SOFT_RESET 0x0100U +#define ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL 0xFFEFFFFFFFFFFC3DULL +#define ROGUE_CR_SOFT_RESET_MASKFULL 0x00E7FFFFFFFFFC3DULL +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_SHIFT 63U +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_EN 0x8000000000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_SHIFT 62U +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_EN 0x4000000000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_SHIFT 61U +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_EN 0x2000000000000000ULL +#define ROGUE_CR_SOFT_RESET_JONES_CORE_SHIFT 60U +#define ROGUE_CR_SOFT_RESET_JONES_CORE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_JONES_CORE_EN 0x1000000000000000ULL +#define ROGUE_CR_SOFT_RESET_TILING_CORE_SHIFT 59U +#define ROGUE_CR_SOFT_RESET_TILING_CORE_CLRMSK 0xF7FFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TILING_CORE_EN 0x0800000000000000ULL +#define ROGUE_CR_SOFT_RESET_TE3_SHIFT 58U +#define ROGUE_CR_SOFT_RESET_TE3_CLRMSK 0xFBFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TE3_EN 0x0400000000000000ULL +#define ROGUE_CR_SOFT_RESET_VCE_SHIFT 57U +#define ROGUE_CR_SOFT_RESET_VCE_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VCE_EN 0x0200000000000000ULL +#define ROGUE_CR_SOFT_RESET_VBS_SHIFT 56U +#define ROGUE_CR_SOFT_RESET_VBS_CLRMSK 0xFEFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VBS_EN 0x0100000000000000ULL +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_SHIFT 55U +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_CLRMSK 0xFF7FFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_EN 0x0080000000000000ULL +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_SHIFT 54U +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_CLRMSK 0xFFBFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_EN 0x0040000000000000ULL +#define ROGUE_CR_SOFT_RESET_FBA_SHIFT 53U +#define ROGUE_CR_SOFT_RESET_FBA_CLRMSK 0xFFDFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBA_EN 0x0020000000000000ULL +#define ROGUE_CR_SOFT_RESET_FB_CDC_SHIFT 51U +#define ROGUE_CR_SOFT_RESET_FB_CDC_CLRMSK 0xFFF7FFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FB_CDC_EN 0x0008000000000000ULL +#define ROGUE_CR_SOFT_RESET_SH_SHIFT 50U +#define ROGUE_CR_SOFT_RESET_SH_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_SH_EN 0x0004000000000000ULL +#define ROGUE_CR_SOFT_RESET_VRDM_SHIFT 49U +#define ROGUE_CR_SOFT_RESET_VRDM_CLRMSK 0xFFFDFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VRDM_EN 0x0002000000000000ULL +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_SHIFT 48U +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_CLRMSK 0xFFFEFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_EN 0x0001000000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_SHIFT 47U +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_CLRMSK 0xFFFF7FFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_EN 0x0000800000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_SHIFT 46U +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_CLRMSK 0xFFFFBFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_EN 0x0000400000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_SHIFT 45U +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_EN 0x0000200000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_SHIFT 44U +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_CLRMSK 0xFFFFEFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_EN 0x0000100000000000ULL +#define ROGUE_CR_SOFT_RESET_IPP_SHIFT 43U +#define ROGUE_CR_SOFT_RESET_IPP_CLRMSK 0xFFFFF7FFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_IPP_EN 0x0000080000000000ULL +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_SHIFT 42U +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_EN 0x0000040000000000ULL +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_SHIFT 41U +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_CLRMSK 0xFFFFFDFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_EN 0x0000020000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_SHIFT 40U +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_EN 0x0000010000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_SHIFT 39U +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_CLRMSK 0xFFFFFF7FFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_EN 0x0000008000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_SHIFT 38U +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_EN 0x0000004000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_SHIFT 37U +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_EN 0x0000002000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_SHIFT 36U +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_EN 0x0000001000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_SHIFT 35U +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_EN 0x0000000800000000ULL +#define ROGUE_CR_SOFT_RESET_MMU_SHIFT 34U +#define ROGUE_CR_SOFT_RESET_MMU_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_MMU_EN 0x0000000400000000ULL +#define ROGUE_CR_SOFT_RESET_BIF1_SHIFT 33U +#define ROGUE_CR_SOFT_RESET_BIF1_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF1_EN 0x0000000200000000ULL +#define ROGUE_CR_SOFT_RESET_GARTEN_SHIFT 32U +#define ROGUE_CR_SOFT_RESET_GARTEN_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_GARTEN_EN 0x0000000100000000ULL +#define ROGUE_CR_SOFT_RESET_CPU_SHIFT 32U +#define ROGUE_CR_SOFT_RESET_CPU_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_CPU_EN 0x0000000100000000ULL +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_SHIFT 31U +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_EN 0x0000000080000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_SHIFT 30U +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_EN 0x0000000040000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_SHIFT 29U +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_EN 0x0000000020000000ULL +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_SHIFT 28U +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_EN 0x0000000010000000ULL +#define ROGUE_CR_SOFT_RESET_SLC_SHIFT 27U +#define ROGUE_CR_SOFT_RESET_SLC_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_SOFT_RESET_SLC_EN 0x0000000008000000ULL +#define ROGUE_CR_SOFT_RESET_TLA_SHIFT 26U +#define ROGUE_CR_SOFT_RESET_TLA_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TLA_EN 0x0000000004000000ULL +#define ROGUE_CR_SOFT_RESET_UVS_SHIFT 25U +#define ROGUE_CR_SOFT_RESET_UVS_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_SOFT_RESET_UVS_EN 0x0000000002000000ULL +#define ROGUE_CR_SOFT_RESET_TE_SHIFT 24U +#define ROGUE_CR_SOFT_RESET_TE_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TE_EN 0x0000000001000000ULL +#define ROGUE_CR_SOFT_RESET_GPP_SHIFT 23U +#define ROGUE_CR_SOFT_RESET_GPP_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_SOFT_RESET_GPP_EN 0x0000000000800000ULL +#define ROGUE_CR_SOFT_RESET_FBDC_SHIFT 22U +#define ROGUE_CR_SOFT_RESET_FBDC_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBDC_EN 0x0000000000400000ULL +#define ROGUE_CR_SOFT_RESET_FBC_SHIFT 21U +#define ROGUE_CR_SOFT_RESET_FBC_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBC_EN 0x0000000000200000ULL +#define ROGUE_CR_SOFT_RESET_PM_SHIFT 20U +#define ROGUE_CR_SOFT_RESET_PM_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_SOFT_RESET_PM_EN 0x0000000000100000ULL +#define ROGUE_CR_SOFT_RESET_PBE_SHIFT 19U +#define ROGUE_CR_SOFT_RESET_PBE_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_SOFT_RESET_PBE_EN 0x0000000000080000ULL +#define ROGUE_CR_SOFT_RESET_USC_SHARED_SHIFT 18U +#define ROGUE_CR_SOFT_RESET_USC_SHARED_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_SOFT_RESET_USC_SHARED_EN 0x0000000000040000ULL +#define ROGUE_CR_SOFT_RESET_MCU_L1_SHIFT 17U +#define ROGUE_CR_SOFT_RESET_MCU_L1_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_SOFT_RESET_MCU_L1_EN 0x0000000000020000ULL +#define ROGUE_CR_SOFT_RESET_BIF_SHIFT 16U +#define ROGUE_CR_SOFT_RESET_BIF_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF_EN 0x0000000000010000ULL +#define ROGUE_CR_SOFT_RESET_CDM_SHIFT 15U +#define ROGUE_CR_SOFT_RESET_CDM_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_SOFT_RESET_CDM_EN 0x0000000000008000ULL +#define ROGUE_CR_SOFT_RESET_VDM_SHIFT 14U +#define ROGUE_CR_SOFT_RESET_VDM_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_SOFT_RESET_VDM_EN 0x0000000000004000ULL +#define ROGUE_CR_SOFT_RESET_TESS_SHIFT 13U +#define ROGUE_CR_SOFT_RESET_TESS_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_SOFT_RESET_TESS_EN 0x0000000000002000ULL +#define ROGUE_CR_SOFT_RESET_PDS_SHIFT 12U +#define ROGUE_CR_SOFT_RESET_PDS_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_SOFT_RESET_PDS_EN 0x0000000000001000ULL +#define ROGUE_CR_SOFT_RESET_ISP_SHIFT 11U +#define ROGUE_CR_SOFT_RESET_ISP_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_SOFT_RESET_ISP_EN 0x0000000000000800ULL +#define ROGUE_CR_SOFT_RESET_TSP_SHIFT 10U +#define ROGUE_CR_SOFT_RESET_TSP_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_SOFT_RESET_TSP_EN 0x0000000000000400ULL +#define ROGUE_CR_SOFT_RESET_SYSARB_SHIFT 5U +#define ROGUE_CR_SOFT_RESET_SYSARB_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_SOFT_RESET_SYSARB_EN 0x0000000000000020ULL +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_SHIFT 4U +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_EN 0x0000000000000010ULL +#define ROGUE_CR_SOFT_RESET_MCU_L0_SHIFT 3U +#define ROGUE_CR_SOFT_RESET_MCU_L0_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SOFT_RESET_MCU_L0_EN 0x0000000000000008ULL +#define ROGUE_CR_SOFT_RESET_TPU_SHIFT 2U +#define ROGUE_CR_SOFT_RESET_TPU_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SOFT_RESET_TPU_EN 0x0000000000000004ULL +#define ROGUE_CR_SOFT_RESET_USC_SHIFT 0U +#define ROGUE_CR_SOFT_RESET_USC_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SOFT_RESET_USC_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SOFT_RESET2 */ +#define ROGUE_CR_SOFT_RESET2 0x0108U +#define ROGUE_CR_SOFT_RESET2_MASKFULL 0x00000000001FFFFFULL +#define ROGUE_CR_SOFT_RESET2_SPFILTER_SHIFT 12U +#define ROGUE_CR_SOFT_RESET2_SPFILTER_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_SOFT_RESET2_TDM_SHIFT 11U +#define ROGUE_CR_SOFT_RESET2_TDM_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_SOFT_RESET2_TDM_EN 0x00000800U +#define ROGUE_CR_SOFT_RESET2_ASTC_SHIFT 10U +#define ROGUE_CR_SOFT_RESET2_ASTC_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_SOFT_RESET2_ASTC_EN 0x00000400U +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_SHIFT 9U +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_EN 0x00000200U +#define ROGUE_CR_SOFT_RESET2_USCPS_SHIFT 8U +#define ROGUE_CR_SOFT_RESET2_USCPS_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SOFT_RESET2_USCPS_EN 0x00000100U +#define ROGUE_CR_SOFT_RESET2_IPF_SHIFT 7U +#define ROGUE_CR_SOFT_RESET2_IPF_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SOFT_RESET2_IPF_EN 0x00000080U +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_SHIFT 6U +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_EN 0x00000040U +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_SHIFT 5U +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_EN 0x00000020U +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_SHIFT 4U +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_EN 0x00000010U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_SHIFT 3U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_EN 0x00000008U +#define ROGUE_CR_SOFT_RESET2_PIXEL_SHIFT 2U +#define ROGUE_CR_SOFT_RESET2_PIXEL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SOFT_RESET2_PIXEL_EN 0x00000004U +#define ROGUE_CR_SOFT_RESET2_CDM_SHIFT 1U +#define ROGUE_CR_SOFT_RESET2_CDM_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SOFT_RESET2_CDM_EN 0x00000002U +#define ROGUE_CR_SOFT_RESET2_VERTEX_SHIFT 0U +#define ROGUE_CR_SOFT_RESET2_VERTEX_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SOFT_RESET2_VERTEX_EN 0x00000001U + +/* Register ROGUE_CR_EVENT_STATUS */ +#define ROGUE_CR_EVENT_STATUS 0x0130U +#define ROGUE_CR_EVENT_STATUS__ROGUEXE__MASKFULL 0x00000000E01DFFFFULL +#define ROGUE_CR_EVENT_STATUS__SIGNALS__MASKFULL 0x00000000E007FFFFULL +#define ROGUE_CR_EVENT_STATUS_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_SHIFT 31U +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_EN 0x80000000U +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_SHIFT 30U +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_EN 0x40000000U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_SHIFT 29U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_EN 0x20000000U +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_SHIFT 28U +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_EN 0x10000000U +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_SHIFT 27U +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_EN 0x08000000U +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_SHIFT 26U +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_EN 0x04000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_SHIFT 25U +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_EN 0x02000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_SHIFT 24U +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_CLRMSK 0xFEFFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_EN 0x01000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_SHIFT 23U +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_CLRMSK 0xFF7FFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_EN 0x00800000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_SHIFT 22U +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_EN 0x00400000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_SHIFT 21U +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_EN 0x00200000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_SHIFT 20U +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_EN 0x00100000U +#define ROGUE_CR_EVENT_STATUS_SAFETY_SHIFT 20U +#define ROGUE_CR_EVENT_STATUS_SAFETY_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_EVENT_STATUS_SAFETY_EN 0x00100000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_SHIFT 19U +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_EN 0x00080000U +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_SHIFT 19U +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_EN 0x00080000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_SHIFT 18U +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_EN 0x00040000U +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_SHIFT 18U +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_EN 0x00040000U +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_SHIFT 17U +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_EN 0x00020000U +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_SHIFT 17U +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_EN 0x00020000U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_SHIFT 16U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_EN 0x00010000U +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_SHIFT 15U +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_CLRMSK 0xFFFF7FFFU +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_EN 0x00008000U +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_SHIFT 14U +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_CLRMSK 0xFFFFBFFFU +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_EN 0x00004000U +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_SHIFT 13U +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_CLRMSK 0xFFFFDFFFU +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_EN 0x00002000U +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_SHIFT 12U +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_CLRMSK 0xFFFFEFFFU +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_EN 0x00001000U +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_SHIFT 11U +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_EN 0x00000800U +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_SHIFT 10U +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_EN 0x00000400U +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_SHIFT 9U +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_EN 0x00000200U +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_SHIFT 8U +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_EN 0x00000100U +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_SHIFT 7U +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_EN 0x00000080U +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_SHIFT 6U +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_EN 0x00000040U +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_SHIFT 5U +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_EN 0x00000020U +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_SHIFT 4U +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_EN 0x00000010U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_SHIFT 3U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_EN 0x00000008U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_SHIFT 2U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_EN 0x00000004U +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_SHIFT 1U +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_EN 0x00000002U +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_SHIFT 0U +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_TIMER */ +#define ROGUE_CR_TIMER 0x0160U +#define ROGUE_CR_TIMER_MASKFULL 0x8000FFFFFFFFFFFFULL +#define ROGUE_CR_TIMER_BIT31_SHIFT 63U +#define ROGUE_CR_TIMER_BIT31_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_TIMER_BIT31_EN 0x8000000000000000ULL +#define ROGUE_CR_TIMER_VALUE_SHIFT 0U +#define ROGUE_CR_TIMER_VALUE_CLRMSK 0xFFFF000000000000ULL + +/* Register ROGUE_CR_TLA_STATUS */ +#define ROGUE_CR_TLA_STATUS 0x0178U +#define ROGUE_CR_TLA_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_TLA_STATUS_BLIT_COUNT_SHIFT 39U +#define ROGUE_CR_TLA_STATUS_BLIT_COUNT_CLRMSK 0x0000007FFFFFFFFFULL +#define ROGUE_CR_TLA_STATUS_REQUEST_SHIFT 7U +#define ROGUE_CR_TLA_STATUS_REQUEST_CLRMSK 0xFFFFFF800000007FULL +#define ROGUE_CR_TLA_STATUS_FIFO_FULLNESS_SHIFT 1U +#define ROGUE_CR_TLA_STATUS_FIFO_FULLNESS_CLRMSK 0xFFFFFFFFFFFFFF81ULL +#define ROGUE_CR_TLA_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_TLA_STATUS_BUSY_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_TLA_STATUS_BUSY_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_PM_PARTIAL_RENDER_ENABLE */ +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE 0x0338U +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_SHIFT 0U +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_EN 0x00000001U + +/* Register ROGUE_CR_SIDEKICK_IDLE */ +#define ROGUE_CR_SIDEKICK_IDLE 0x03C8U +#define ROGUE_CR_SIDEKICK_IDLE_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_SHIFT 6U +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_EN 0x00000040U +#define ROGUE_CR_SIDEKICK_IDLE_MMU_SHIFT 5U +#define ROGUE_CR_SIDEKICK_IDLE_MMU_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SIDEKICK_IDLE_MMU_EN 0x00000020U +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_SHIFT 4U +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_EN 0x00000010U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_SHIFT 3U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_EN 0x00000008U +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_SHIFT 2U +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN 0x00000004U +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_SHIFT 1U +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN 0x00000002U +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_SHIFT 0U +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN 0x00000001U + +/* Register ROGUE_CR_MARS_IDLE */ +#define ROGUE_CR_MARS_IDLE 0x08F8U +#define ROGUE_CR_MARS_IDLE_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_SHIFT 2U +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_EN 0x00000004U +#define ROGUE_CR_MARS_IDLE_CPU_SHIFT 1U +#define ROGUE_CR_MARS_IDLE_CPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MARS_IDLE_CPU_EN 0x00000002U +#define ROGUE_CR_MARS_IDLE_SOCIF_SHIFT 0U +#define ROGUE_CR_MARS_IDLE_SOCIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MARS_IDLE_SOCIF_EN 0x00000001U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_STATUS */ +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS 0x0430U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_MASKFULL 0x00000000000000F3ULL +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_LAST_PIPE_SHIFT 4U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_LAST_PIPE_CLRMSK 0xFFFFFF0FU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_SHIFT 1U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_EN 0x00000002U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK0 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0 0x0438U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE1_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE1_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE0_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE0_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK1 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1 0x0440U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_PDS_STATE2_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_PDS_STATE2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK2 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2 0x0448U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT2_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT2_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT1_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT1_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK0 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0 0x0450U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE1_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE1_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE0_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE0_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK1 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1 0x0458U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_PDS_STATE2_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_PDS_STATE2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK2 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2 0x0460U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT2_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT2_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT1_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT1_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_CDM_CONTEXT_STORE_STATUS */ +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS 0x04A0U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_EN 0x00000002U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_CONTEXT_PDS0 */ +#define ROGUE_CR_CDM_CONTEXT_PDS0 0x04A8U +#define ROGUE_CR_CDM_CONTEXT_PDS0_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_CONTEXT_PDS1 */ +#define ROGUE_CR_CDM_CONTEXT_PDS1 0x04B0U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_CONTEXT_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_TERMINATE_PDS */ +#define ROGUE_CR_CDM_TERMINATE_PDS 0x04B8U +#define ROGUE_CR_CDM_TERMINATE_PDS_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_TERMINATE_PDS1 */ +#define ROGUE_CR_CDM_TERMINATE_PDS1 0x04C0U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_TERMINATE_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_TERMINATE_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_TERMINATE_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_CONTEXT_LOAD_PDS0 */ +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0 0x04D8U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_CONTEXT_LOAD_PDS1 */ +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1 0x04E0U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_CONFIG */ +#define ROGUE_CR_MIPS_WRAPPER_CONFIG 0x0810U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_MASKFULL 0x000001030F01FFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_SHIFT 40U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_EN 0x0000010000000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_SHIFT 33U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_EN 0x0000000200000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_SHIFT 32U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_EN 0x0000000100000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_OS_ID_SHIFT 25U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_OS_ID_CLRMSK 0xFFFFFFFFF1FFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_SHIFT 24U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_EN 0x0000000001000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_SHIFT 16U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MIPS32 0x0000000000000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MICROMIPS 0x0000000000010000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_REGBANK_BASE_ADDR_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_REGBANK_BASE_ADDR_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1 0x0818U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2 0x0820U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1 0x0828U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2 0x0830U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1 0x0838U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2 0x0840U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1 0x0848U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2 0x0850U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1 0x0858U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2 0x0860U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS */ +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS 0x0868U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_MASKFULL 0x00000001FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_EN 0x0000000100000000ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_ADDRESS_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_ADDRESS_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR */ +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR 0x0870U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG 0x0878U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MASKFULL 0xFFFFFFF7FFFFFFBFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ADDR_OUT_SHIFT 36U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ADDR_OUT_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_OS_ID_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_OS_ID_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_SHIFT 11U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_EN 0x0000000000000800ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_SHIFT 7U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_CLRMSK 0xFFFFFFFFFFFFF87FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_4KB 0x0000000000000000ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_16KB 0x0000000000000080ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_64KB 0x0000000000000100ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_256KB 0x0000000000000180ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_1MB 0x0000000000000200ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_4MB 0x0000000000000280ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_16MB 0x0000000000000300ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_64MB 0x0000000000000380ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_256MB 0x0000000000000400ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ENTRY_SHIFT 1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ENTRY_CLRMSK 0xFFFFFFFFFFFFFFC1ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ 0x0880U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_MASKFULL 0x000000000000003FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_ENTRY_SHIFT 1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_ENTRY_CLRMSK 0xFFFFFFC1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA 0x0888U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MASKFULL 0xFFFFFFF7FFFFFF81ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_ADDR_OUT_SHIFT 36U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_ADDR_OUT_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_OS_ID_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_OS_ID_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_SHIFT 11U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_EN 0x0000000000000800ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_REGION_SIZE_SHIFT 7U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_REGION_SIZE_CLRMSK 0xFFFFFFFFFFFFF87FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE 0x08A0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS 0x08A8U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR 0x08B0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE */ +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE 0x08B8U +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_NMI_EVENT */ +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT 0x08C0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_DEBUG_CONFIG */ +#define ROGUE_CR_MIPS_DEBUG_CONFIG 0x08C8U +#define ROGUE_CR_MIPS_DEBUG_CONFIG_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_SHIFT 0U +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_EXCEPTION_STATUS */ +#define ROGUE_CR_MIPS_EXCEPTION_STATUS 0x08D0U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_MASKFULL 0x000000000000003FULL +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_SHIFT 5U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_EN 0x00000020U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_SHIFT 4U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_EN 0x00000010U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_SHIFT 3U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_EN 0x00000008U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_SHIFT 2U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_EN 0x00000004U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_SHIFT 1U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_EN 0x00000002U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_SHIFT 0U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_STATUS */ +#define ROGUE_CR_MIPS_WRAPPER_STATUS 0x08E8U +#define ROGUE_CR_MIPS_WRAPPER_STATUS_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MIPS_WRAPPER_STATUS_OUTSTANDING_REQUESTS_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_STATUS_OUTSTANDING_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_XPU_BROADCAST */ +#define ROGUE_CR_XPU_BROADCAST 0x0890U +#define ROGUE_CR_XPU_BROADCAST_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_XPU_BROADCAST_MASK_SHIFT 0U +#define ROGUE_CR_XPU_BROADCAST_MASK_CLRMSK 0xFFFFFE00U + +/* Register ROGUE_CR_META_SP_MSLVDATAX */ +#define ROGUE_CR_META_SP_MSLVDATAX 0x0A00U +#define ROGUE_CR_META_SP_MSLVDATAX_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVDATAX_MSLVDATAX_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVDATAX_MSLVDATAX_CLRMSK 0x00000000U + +/* Register ROGUE_CR_META_SP_MSLVDATAT */ +#define ROGUE_CR_META_SP_MSLVDATAT 0x0A08U +#define ROGUE_CR_META_SP_MSLVDATAT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVDATAT_MSLVDATAT_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVDATAT_MSLVDATAT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_META_SP_MSLVCTRL0 */ +#define ROGUE_CR_META_SP_MSLVCTRL0 0x0A10U +#define ROGUE_CR_META_SP_MSLVCTRL0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVCTRL0_ADDR_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVCTRL0_ADDR_CLRMSK 0x00000003U +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_SHIFT 1U +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_EN 0x00000002U +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_EN 0x00000001U + +/* Register ROGUE_CR_META_SP_MSLVCTRL1 */ +#define ROGUE_CR_META_SP_MSLVCTRL1 0x0A18U +#define ROGUE_CR_META_SP_MSLVCTRL1_MASKFULL 0x00000000F7F4003FULL +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRTHREAD_SHIFT 30U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRTHREAD_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_SHIFT 29U +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_EN 0x20000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_SHIFT 28U +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_EN 0x10000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_SHIFT 26U +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN 0x04000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_SHIFT 25U +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_EN 0x02000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_SHIFT 24U +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_CLRMSK 0xFEFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_EN 0x01000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRID_SHIFT 21U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRID_CLRMSK 0xFF1FFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_SHIFT 20U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_EN 0x00100000U +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_SHIFT 18U +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_EN 0x00040000U +#define ROGUE_CR_META_SP_MSLVCTRL1_THREAD_SHIFT 4U +#define ROGUE_CR_META_SP_MSLVCTRL1_THREAD_CLRMSK 0xFFFFFFCFU +#define ROGUE_CR_META_SP_MSLVCTRL1_TRANS_SIZE_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVCTRL1_TRANS_SIZE_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_META_SP_MSLVCTRL1_BYTE_ROUND_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVCTRL1_BYTE_ROUND_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_META_SP_MSLVHANDSHKE */ +#define ROGUE_CR_META_SP_MSLVHANDSHKE 0x0A50U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_META_SP_MSLVHANDSHKE_INPUT_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_INPUT_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_OUTPUT_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_OUTPUT_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_META_SP_MSLVT0KICK */ +#define ROGUE_CR_META_SP_MSLVT0KICK 0x0A80U +#define ROGUE_CR_META_SP_MSLVT0KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT0KICK_MSLVT0KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT0KICK_MSLVT0KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT0KICKI */ +#define ROGUE_CR_META_SP_MSLVT0KICKI 0x0A88U +#define ROGUE_CR_META_SP_MSLVT0KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT0KICKI_MSLVT0KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT0KICKI_MSLVT0KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT1KICK */ +#define ROGUE_CR_META_SP_MSLVT1KICK 0x0A90U +#define ROGUE_CR_META_SP_MSLVT1KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT1KICK_MSLVT1KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT1KICK_MSLVT1KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT1KICKI */ +#define ROGUE_CR_META_SP_MSLVT1KICKI 0x0A98U +#define ROGUE_CR_META_SP_MSLVT1KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT1KICKI_MSLVT1KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT1KICKI_MSLVT1KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT2KICK */ +#define ROGUE_CR_META_SP_MSLVT2KICK 0x0AA0U +#define ROGUE_CR_META_SP_MSLVT2KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT2KICK_MSLVT2KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT2KICK_MSLVT2KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT2KICKI */ +#define ROGUE_CR_META_SP_MSLVT2KICKI 0x0AA8U +#define ROGUE_CR_META_SP_MSLVT2KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT2KICKI_MSLVT2KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT2KICKI_MSLVT2KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT3KICK */ +#define ROGUE_CR_META_SP_MSLVT3KICK 0x0AB0U +#define ROGUE_CR_META_SP_MSLVT3KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT3KICK_MSLVT3KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT3KICK_MSLVT3KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT3KICKI */ +#define ROGUE_CR_META_SP_MSLVT3KICKI 0x0AB8U +#define ROGUE_CR_META_SP_MSLVT3KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT3KICKI_MSLVT3KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT3KICKI_MSLVT3KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVRST */ +#define ROGUE_CR_META_SP_MSLVRST 0x0AC0U +#define ROGUE_CR_META_SP_MSLVRST_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_EN 0x00000001U + +/* Register ROGUE_CR_META_SP_MSLVIRQSTATUS */ +#define ROGUE_CR_META_SP_MSLVIRQSTATUS 0x0AC8U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_MASKFULL 0x000000000000000CULL +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_SHIFT 3U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_EN 0x00000008U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN 0x00000004U + +/* Register ROGUE_CR_META_SP_MSLVIRQENABLE */ +#define ROGUE_CR_META_SP_MSLVIRQENABLE 0x0AD0U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_MASKFULL 0x000000000000000CULL +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_SHIFT 3U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_EN 0x00000008U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_EN 0x00000004U + +/* Register ROGUE_CR_META_SP_MSLVIRQLEVEL */ +#define ROGUE_CR_META_SP_MSLVIRQLEVEL 0x0AD8U +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_EN 0x00000001U + +/* Register ROGUE_CR_MTS_SCHEDULE */ +#define ROGUE_CR_MTS_SCHEDULE 0x0B00U +#define ROGUE_CR_MTS_SCHEDULE_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE1 */ +#define ROGUE_CR_MTS_SCHEDULE1 0x10B00U +#define ROGUE_CR_MTS_SCHEDULE1_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE1_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE1_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE1_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE1_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE1_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE1_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE2 */ +#define ROGUE_CR_MTS_SCHEDULE2 0x20B00U +#define ROGUE_CR_MTS_SCHEDULE2_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE2_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE2_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE2_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE2_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE2_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE2_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE3 */ +#define ROGUE_CR_MTS_SCHEDULE3 0x30B00U +#define ROGUE_CR_MTS_SCHEDULE3_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE3_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE3_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE3_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE3_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE3_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE3_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE4 */ +#define ROGUE_CR_MTS_SCHEDULE4 0x40B00U +#define ROGUE_CR_MTS_SCHEDULE4_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE4_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE4_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE4_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE4_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE4_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE4_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE5 */ +#define ROGUE_CR_MTS_SCHEDULE5 0x50B00U +#define ROGUE_CR_MTS_SCHEDULE5_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE5_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE5_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE5_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE5_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE5_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE5_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE6 */ +#define ROGUE_CR_MTS_SCHEDULE6 0x60B00U +#define ROGUE_CR_MTS_SCHEDULE6_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE6_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE6_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE6_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE6_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE6_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE6_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE7 */ +#define ROGUE_CR_MTS_SCHEDULE7 0x70B00U +#define ROGUE_CR_MTS_SCHEDULE7_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE7_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE7_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE7_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE7_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE7_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE7_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC */ +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC 0x0B30U +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC */ +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC 0x0B38U +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC */ +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC 0x0B40U +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC */ +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC 0x0B48U +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG */ +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG 0x0B50U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__MASKFULL 0x000FF0FFFFFFF701ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_MASKFULL 0x0000FFFFFFFFF001ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_SHIFT 44U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_CLRMSK 0xFFFF0FFFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__FENCE_PC_BASE_SHIFT 44U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__FENCE_PC_BASE_CLRMSK 0xFFF00FFFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_SHIFT 40U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_ADDR_SHIFT 12U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PERSISTENCE_SHIFT 9U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PERSISTENCE_CLRMSK 0xFFFFFFFFFFFFF9FFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_SHIFT 8U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_EN 0x0000000000000100ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_SHIFT 0U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META 0x0000000000000000ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_MTS 0x0000000000000001ULL + +/* Register ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE 0x0B58U +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE 0x0B60U +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE 0x0B68U +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE 0x0B70U +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE 0x0B78U +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE 0x0B80U +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_INTCTX */ +#define ROGUE_CR_MTS_INTCTX 0x0B98U +#define ROGUE_CR_MTS_INTCTX_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_MTS_INTCTX_DM_HOST_SCHEDULE_SHIFT 22U +#define ROGUE_CR_MTS_INTCTX_DM_HOST_SCHEDULE_CLRMSK 0xC03FFFFFU +#define ROGUE_CR_MTS_INTCTX_DM_PTR_SHIFT 18U +#define ROGUE_CR_MTS_INTCTX_DM_PTR_CLRMSK 0xFFC3FFFFU +#define ROGUE_CR_MTS_INTCTX_THREAD_ACTIVE_SHIFT 16U +#define ROGUE_CR_MTS_INTCTX_THREAD_ACTIVE_CLRMSK 0xFFFCFFFFU +#define ROGUE_CR_MTS_INTCTX_DM_TIMER_SCHEDULE_SHIFT 8U +#define ROGUE_CR_MTS_INTCTX_DM_TIMER_SCHEDULE_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_MTS_INTCTX_DM_INTERRUPT_SCHEDULE_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_DM_INTERRUPT_SCHEDULE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MTS_BGCTX */ +#define ROGUE_CR_MTS_BGCTX 0x0BA0U +#define ROGUE_CR_MTS_BGCTX_MASKFULL 0x0000000000003FFFULL +#define ROGUE_CR_MTS_BGCTX_DM_PTR_SHIFT 10U +#define ROGUE_CR_MTS_BGCTX_DM_PTR_CLRMSK 0xFFFFC3FFU +#define ROGUE_CR_MTS_BGCTX_THREAD_ACTIVE_SHIFT 8U +#define ROGUE_CR_MTS_BGCTX_THREAD_ACTIVE_CLRMSK 0xFFFFFCFFU +#define ROGUE_CR_MTS_BGCTX_DM_NONCOUNTED_SCHEDULE_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_DM_NONCOUNTED_SCHEDULE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE */ +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE 0x0BA8U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM7_SHIFT 56U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM7_CLRMSK 0x00FFFFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM6_SHIFT 48U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM6_CLRMSK 0xFF00FFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM5_SHIFT 40U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM5_CLRMSK 0xFFFF00FFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM4_SHIFT 32U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM4_CLRMSK 0xFFFFFF00FFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM3_SHIFT 24U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM3_CLRMSK 0xFFFFFFFF00FFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM2_SHIFT 16U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM2_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM1_SHIFT 8U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM1_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM0_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM0_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_MTS_GPU_INT_STATUS */ +#define ROGUE_CR_MTS_GPU_INT_STATUS 0x0BB0U +#define ROGUE_CR_MTS_GPU_INT_STATUS_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_GPU_INT_STATUS_STATUS_SHIFT 0U +#define ROGUE_CR_MTS_GPU_INT_STATUS_STATUS_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_SCHEDULE_ENABLE */ +#define ROGUE_CR_MTS_SCHEDULE_ENABLE 0x0BC8U +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASK_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASK_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_IRQ_OS0_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS 0x0BD8U +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS0_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR 0x0BE8U +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS1_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS 0x10BD8U +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS1_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR 0x10BE8U +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS2_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS 0x20BD8U +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS2_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR 0x20BE8U +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS3_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS 0x30BD8U +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS3_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR 0x30BE8U +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS4_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS 0x40BD8U +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS4_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR 0x40BE8U +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS5_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS 0x50BD8U +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS5_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR 0x50BE8U +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS6_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS 0x60BD8U +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS6_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR 0x60BE8U +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS7_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS 0x70BD8U +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS7_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR 0x70BE8U +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_META_BOOT */ +#define ROGUE_CR_META_BOOT 0x0BF8U +#define ROGUE_CR_META_BOOT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_BOOT_MODE_SHIFT 0U +#define ROGUE_CR_META_BOOT_MODE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_BOOT_MODE_EN 0x00000001U + +/* Register ROGUE_CR_GARTEN_SLC */ +#define ROGUE_CR_GARTEN_SLC 0x0BB8U +#define ROGUE_CR_GARTEN_SLC_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_SHIFT 0U +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_EN 0x00000001U + +/* Register ROGUE_CR_PPP */ +#define ROGUE_CR_PPP 0x0CD0U +#define ROGUE_CR_PPP_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_CHECKSUM_SHIFT 0U +#define ROGUE_CR_PPP_CHECKSUM_CLRMSK 0x00000000U + +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_MASK 0x00000003U +/* Top-left to bottom-right */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_TL2BR 0x00000000U +/* Top-right to bottom-left */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_TR2BL 0x00000001U +/* Bottom-left to top-right */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_BL2TR 0x00000002U +/* Bottom-right to top-left */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_BR2TL 0x00000003U + +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_MASK 0x00000003U +/* Normal render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_NORM 0x00000000U +/* Fast 2D render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_FAST_2D 0x00000002U +/* Fast scale render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_FAST_SCALE 0x00000003U + +/* Register ROGUE_CR_ISP_RENDER */ +#define ROGUE_CR_ISP_RENDER 0x0F08U +#define ROGUE_CR_ISP_RENDER_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_SHIFT 8U +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_EN 0x00000100U +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_SHIFT 7U +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_EN 0x00000080U +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_SHIFT 6U +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_EN 0x00000040U +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_SHIFT 5U +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_EN 0x00000020U +#define ROGUE_CR_ISP_RENDER_RESUME_SHIFT 4U +#define ROGUE_CR_ISP_RENDER_RESUME_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ISP_RENDER_RESUME_EN 0x00000010U +#define ROGUE_CR_ISP_RENDER_DIR_SHIFT 2U +#define ROGUE_CR_ISP_RENDER_DIR_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_ISP_RENDER_DIR_TL2BR 0x00000000U +#define ROGUE_CR_ISP_RENDER_DIR_TR2BL 0x00000004U +#define ROGUE_CR_ISP_RENDER_DIR_BL2TR 0x00000008U +#define ROGUE_CR_ISP_RENDER_DIR_BR2TL 0x0000000CU +#define ROGUE_CR_ISP_RENDER_MODE_SHIFT 0U +#define ROGUE_CR_ISP_RENDER_MODE_CLRMSK 0xFFFFFFFCU +#define ROGUE_CR_ISP_RENDER_MODE_NORM 0x00000000U +#define ROGUE_CR_ISP_RENDER_MODE_FAST_2D 0x00000002U +#define ROGUE_CR_ISP_RENDER_MODE_FAST_SCALE 0x00000003U + +/* Register ROGUE_CR_ISP_CTL */ +#define ROGUE_CR_ISP_CTL 0x0F38U +#define ROGUE_CR_ISP_CTL_MASKFULL 0x00000000FFFFF3FFULL +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_SHIFT 31U +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_EN 0x80000000U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_SHIFT 30U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_ISP_CTL_LINE_STYLE_EN 0x40000000U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_SHIFT 29U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_EN 0x20000000U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_SHIFT 28U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_EN 0x10000000U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_SHIFT 27U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_ISP_CTL_PAIR_TILES_EN 0x08000000U +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_SHIFT 26U +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_EN 0x04000000U +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_SHIFT 25U +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_EN 0x02000000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_SHIFT 23U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_CLRMSK 0xFE7FFFFFU +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_DX9 0x00000000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_DX10 0x00800000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_OGL 0x01000000U +#define ROGUE_CR_ISP_CTL_NUM_TILES_PER_USC_SHIFT 21U +#define ROGUE_CR_ISP_CTL_NUM_TILES_PER_USC_CLRMSK 0xFF9FFFFFU +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_SHIFT 20U +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_EN 0x00100000U +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_SHIFT 19U +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_EN 0x00080000U +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_SHIFT 18U +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_EN 0x00040000U +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_SHIFT 17U +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_EN 0x00020000U +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_SHIFT 16U +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_EN 0x00010000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_SHIFT 12U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_ONE 0x00000000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TWO 0x00001000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_THREE 0x00002000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FOUR 0x00003000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FIVE 0x00004000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SIX 0x00005000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SEVEN 0x00006000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_EIGHT 0x00007000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_NINE 0x00008000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TEN 0x00009000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_ELEVEN 0x0000A000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TWELVE 0x0000B000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_THIRTEEN 0x0000C000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FOURTEEN 0x0000D000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FIFTEEN 0x0000E000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SIXTEEN 0x0000F000U +#define ROGUE_CR_ISP_CTL_VALID_ID_SHIFT 4U +#define ROGUE_CR_ISP_CTL_VALID_ID_CLRMSK 0xFFFFFC0FU +#define ROGUE_CR_ISP_CTL_UPASS_START_SHIFT 0U +#define ROGUE_CR_ISP_CTL_UPASS_START_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_ISP_STATUS */ +#define ROGUE_CR_ISP_STATUS 0x1038U +#define ROGUE_CR_ISP_STATUS_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_SHIFT 2U +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_EN 0x00000004U +#define ROGUE_CR_ISP_STATUS_ACTIVE_SHIFT 1U +#define ROGUE_CR_ISP_STATUS_ACTIVE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ISP_STATUS_ACTIVE_EN 0x00000002U +#define ROGUE_CR_ISP_STATUS_EOR_SHIFT 0U +#define ROGUE_CR_ISP_STATUS_EOR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ISP_STATUS_EOR_EN 0x00000001U + +/* Register group: ROGUE_CR_ISP_XTP_RESUME, with 64 repeats */ +#define ROGUE_CR_ISP_XTP_RESUME_REPEATCOUNT 64U +/* Register ROGUE_CR_ISP_XTP_RESUME0 */ +#define ROGUE_CR_ISP_XTP_RESUME0 0x3A00U +#define ROGUE_CR_ISP_XTP_RESUME0_MASKFULL 0x00000000003FF3FFULL +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_X_SHIFT 12U +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_X_CLRMSK 0xFFC00FFFU +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_Y_SHIFT 0U +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_Y_CLRMSK 0xFFFFFC00U + +/* Register group: ROGUE_CR_ISP_XTP_STORE, with 32 repeats */ +#define ROGUE_CR_ISP_XTP_STORE_REPEATCOUNT 32U +/* Register ROGUE_CR_ISP_XTP_STORE0 */ +#define ROGUE_CR_ISP_XTP_STORE0 0x3C00U +#define ROGUE_CR_ISP_XTP_STORE0_MASKFULL 0x000000007F3FF3FFULL +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_SHIFT 30U +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_EN 0x40000000U +#define ROGUE_CR_ISP_XTP_STORE0_EOR_SHIFT 29U +#define ROGUE_CR_ISP_XTP_STORE0_EOR_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_EOR_EN 0x20000000U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_SHIFT 28U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_EN 0x10000000U +#define ROGUE_CR_ISP_XTP_STORE0_MT_SHIFT 24U +#define ROGUE_CR_ISP_XTP_STORE0_MT_CLRMSK 0xF0FFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_X_SHIFT 12U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_X_CLRMSK 0xFFC00FFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_Y_SHIFT 0U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_Y_CLRMSK 0xFFFFFC00U + +/* Register group: ROGUE_CR_BIF_CAT_BASE, with 8 repeats */ +#define ROGUE_CR_BIF_CAT_BASE_REPEATCOUNT 8U +/* Register ROGUE_CR_BIF_CAT_BASE0 */ +#define ROGUE_CR_BIF_CAT_BASE0 0x1200U +#define ROGUE_CR_BIF_CAT_BASE0_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE1 */ +#define ROGUE_CR_BIF_CAT_BASE1 0x1208U +#define ROGUE_CR_BIF_CAT_BASE1_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE2 */ +#define ROGUE_CR_BIF_CAT_BASE2 0x1210U +#define ROGUE_CR_BIF_CAT_BASE2_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE3 */ +#define ROGUE_CR_BIF_CAT_BASE3 0x1218U +#define ROGUE_CR_BIF_CAT_BASE3_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE4 */ +#define ROGUE_CR_BIF_CAT_BASE4 0x1220U +#define ROGUE_CR_BIF_CAT_BASE4_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE5 */ +#define ROGUE_CR_BIF_CAT_BASE5 0x1228U +#define ROGUE_CR_BIF_CAT_BASE5_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE6 */ +#define ROGUE_CR_BIF_CAT_BASE6 0x1230U +#define ROGUE_CR_BIF_CAT_BASE6_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE7 */ +#define ROGUE_CR_BIF_CAT_BASE7 0x1238U +#define ROGUE_CR_BIF_CAT_BASE7_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE_INDEX */ +#define ROGUE_CR_BIF_CAT_BASE_INDEX 0x1240U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_MASKFULL 0x00070707073F0707ULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RVTX_SHIFT 48U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RVTX_CLRMSK 0xFFF8FFFFFFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RAY_SHIFT 40U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RAY_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_HOST_SHIFT 32U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_HOST_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TLA_SHIFT 24U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TLA_CLRMSK 0xFFFFFFFFF8FFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TDM_SHIFT 19U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TDM_CLRMSK 0xFFFFFFFFFFC7FFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_CDM_SHIFT 16U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_CDM_CLRMSK 0xFFFFFFFFFFF8FFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_PIXEL_SHIFT 8U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_PIXEL_CLRMSK 0xFFFFFFFFFFFFF8FFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TA_SHIFT 0U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TA_CLRMSK 0xFFFFFFFFFFFFFFF8ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_VCE0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0 0x1248U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_TE0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0 0x1250U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_ALIST0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0 0x1260U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_VCE1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1 0x1268U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_TE1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1 0x1270U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_ALIST1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1 0x1280U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_MMU_ENTRY_STATUS */ +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS 0x1288U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_MASKFULL 0x000000FFFFFFF0F3ULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_SHIFT 12U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_SHIFT 4U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_CLRMSK 0xFFFFFFFFFFFFFF0FULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_SHIFT 0U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_CLRMSK 0xFFFFFFFFFFFFFFFCULL + +/* Register ROGUE_CR_BIF_MMU_ENTRY */ +#define ROGUE_CR_BIF_MMU_ENTRY 0x1290U +#define ROGUE_CR_BIF_MMU_ENTRY_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_SHIFT 1U +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_EN 0x00000002U +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_SHIFT 0U +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_EN 0x00000001U + +/* Register ROGUE_CR_BIF_CTRL_INVAL */ +#define ROGUE_CR_BIF_CTRL_INVAL 0x12A0U +#define ROGUE_CR_BIF_CTRL_INVAL_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_SHIFT 3U +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_EN 0x00000008U +#define ROGUE_CR_BIF_CTRL_INVAL_PC_SHIFT 2U +#define ROGUE_CR_BIF_CTRL_INVAL_PC_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_CTRL_INVAL_PC_EN 0x00000004U +#define ROGUE_CR_BIF_CTRL_INVAL_PD_SHIFT 1U +#define ROGUE_CR_BIF_CTRL_INVAL_PD_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_CTRL_INVAL_PD_EN 0x00000002U +#define ROGUE_CR_BIF_CTRL_INVAL_PT_SHIFT 0U +#define ROGUE_CR_BIF_CTRL_INVAL_PT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_CTRL_INVAL_PT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_CTRL */ +#define ROGUE_CR_BIF_CTRL 0x12A8U +#define ROGUE_CR_BIF_CTRL__XE_MEM__MASKFULL 0x000000000000033FULL +#define ROGUE_CR_BIF_CTRL_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_SHIFT 9U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_EN 0x00000200U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_SHIFT 8U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_EN 0x00000100U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_SHIFT 7U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_EN 0x00000080U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_SHIFT 6U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_EN 0x00000040U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_SHIFT 5U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_EN 0x00000020U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_SHIFT 4U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_EN 0x00000010U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_SHIFT 3U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_EN 0x00000008U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_SHIFT 2U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_EN 0x00000004U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_SHIFT 1U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_EN 0x00000002U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_SHIFT 0U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS 0x12B0U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS 0x12B8U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__MASKFULL 0x001FFFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_SHIFT 52U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_EN 0x0010000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_SHIFT 46U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_CLRMSK 0xFFF03FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_CLRMSK 0xFFFFC0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS 0x12C0U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS 0x12C8U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_BIF_MMU_STATUS */ +#define ROGUE_CR_BIF_MMU_STATUS 0x12D0U +#define ROGUE_CR_BIF_MMU_STATUS__XE_MEM__MASKFULL 0x000000001FFFFFF7ULL +#define ROGUE_CR_BIF_MMU_STATUS_MASKFULL 0x000000001FFFFFF7ULL +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_SHIFT 28U +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_EN 0x10000000U +#define ROGUE_CR_BIF_MMU_STATUS_PC_DATA_SHIFT 20U +#define ROGUE_CR_BIF_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define ROGUE_CR_BIF_MMU_STATUS_PD_DATA_SHIFT 12U +#define ROGUE_CR_BIF_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define ROGUE_CR_BIF_MMU_STATUS_PT_DATA_SHIFT 4U +#define ROGUE_CR_BIF_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_SHIFT 2U +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_EN 0x00000004U +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_SHIFT 1U +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_EN 0x00000002U +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register group: ROGUE_CR_BIF_TILING_CFG, with 8 repeats */ +#define ROGUE_CR_BIF_TILING_CFG_REPEATCOUNT 8U +/* Register ROGUE_CR_BIF_TILING_CFG0 */ +#define ROGUE_CR_BIF_TILING_CFG0 0x12D8U +#define ROGUE_CR_BIF_TILING_CFG0_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG0_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG1 */ +#define ROGUE_CR_BIF_TILING_CFG1 0x12E0U +#define ROGUE_CR_BIF_TILING_CFG1_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG1_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG2 */ +#define ROGUE_CR_BIF_TILING_CFG2 0x12E8U +#define ROGUE_CR_BIF_TILING_CFG2_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG2_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG3 */ +#define ROGUE_CR_BIF_TILING_CFG3 0x12F0U +#define ROGUE_CR_BIF_TILING_CFG3_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG3_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG4 */ +#define ROGUE_CR_BIF_TILING_CFG4 0x12F8U +#define ROGUE_CR_BIF_TILING_CFG4_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG4_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG5 */ +#define ROGUE_CR_BIF_TILING_CFG5 0x1300U +#define ROGUE_CR_BIF_TILING_CFG5_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG5_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG6 */ +#define ROGUE_CR_BIF_TILING_CFG6 0x1308U +#define ROGUE_CR_BIF_TILING_CFG6_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG6_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG7 */ +#define ROGUE_CR_BIF_TILING_CFG7 0x1310U +#define ROGUE_CR_BIF_TILING_CFG7_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG7_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_READS_EXT_STATUS */ +#define ROGUE_CR_BIF_READS_EXT_STATUS 0x1320U +#define ROGUE_CR_BIF_READS_EXT_STATUS_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_BIF_READS_EXT_STATUS_MMU_SHIFT 16U +#define ROGUE_CR_BIF_READS_EXT_STATUS_MMU_CLRMSK 0xF000FFFFU +#define ROGUE_CR_BIF_READS_EXT_STATUS_BANK1_SHIFT 0U +#define ROGUE_CR_BIF_READS_EXT_STATUS_BANK1_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_READS_INT_STATUS */ +#define ROGUE_CR_BIF_READS_INT_STATUS 0x1328U +#define ROGUE_CR_BIF_READS_INT_STATUS_MASKFULL 0x0000000007FFFFFFULL +#define ROGUE_CR_BIF_READS_INT_STATUS_MMU_SHIFT 16U +#define ROGUE_CR_BIF_READS_INT_STATUS_MMU_CLRMSK 0xF800FFFFU +#define ROGUE_CR_BIF_READS_INT_STATUS_BANK1_SHIFT 0U +#define ROGUE_CR_BIF_READS_INT_STATUS_BANK1_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_READS_INT_STATUS */ +#define ROGUE_CR_BIFPM_READS_INT_STATUS 0x1330U +#define ROGUE_CR_BIFPM_READS_INT_STATUS_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIFPM_READS_INT_STATUS_BANK0_SHIFT 0U +#define ROGUE_CR_BIFPM_READS_INT_STATUS_BANK0_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_READS_EXT_STATUS */ +#define ROGUE_CR_BIFPM_READS_EXT_STATUS 0x1338U +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_BANK0_SHIFT 0U +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_BANK0_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_STATUS_MMU */ +#define ROGUE_CR_BIFPM_STATUS_MMU 0x1350U +#define ROGUE_CR_BIFPM_STATUS_MMU_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIFPM_STATUS_MMU_REQUESTS_SHIFT 0U +#define ROGUE_CR_BIFPM_STATUS_MMU_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_STATUS_MMU */ +#define ROGUE_CR_BIF_STATUS_MMU 0x1358U +#define ROGUE_CR_BIF_STATUS_MMU_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIF_STATUS_MMU_REQUESTS_SHIFT 0U +#define ROGUE_CR_BIF_STATUS_MMU_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_FAULT_READ */ +#define ROGUE_CR_BIF_FAULT_READ 0x13E0U +#define ROGUE_CR_BIF_FAULT_READ_MASKFULL 0x000000FFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS */ +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS 0x1430U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS */ +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS 0x1438U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_MCU_FENCE */ +#define ROGUE_CR_MCU_FENCE 0x1740U +#define ROGUE_CR_MCU_FENCE_MASKFULL 0x000007FFFFFFFFE0ULL +#define ROGUE_CR_MCU_FENCE_DM_SHIFT 40U +#define ROGUE_CR_MCU_FENCE_DM_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_MCU_FENCE_DM_VERTEX 0x0000000000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_PIXEL 0x0000010000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_COMPUTE 0x0000020000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_RAY_VERTEX 0x0000030000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_RAY 0x0000040000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_FASTRENDER 0x0000050000000000ULL +#define ROGUE_CR_MCU_FENCE_ADDR_SHIFT 5U +#define ROGUE_CR_MCU_FENCE_ADDR_CLRMSK 0xFFFFFF000000001FULL +#define ROGUE_CR_MCU_FENCE_ADDR_ALIGNSHIFT 5U +#define ROGUE_CR_MCU_FENCE_ADDR_ALIGNSIZE 32U + +/* Register group: ROGUE_CR_SCRATCH, with 16 repeats */ +#define ROGUE_CR_SCRATCH_REPEATCOUNT 16U +/* Register ROGUE_CR_SCRATCH0 */ +#define ROGUE_CR_SCRATCH0 0x1A00U +#define ROGUE_CR_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH1 */ +#define ROGUE_CR_SCRATCH1 0x1A08U +#define ROGUE_CR_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH2 */ +#define ROGUE_CR_SCRATCH2 0x1A10U +#define ROGUE_CR_SCRATCH2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH2_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH3 */ +#define ROGUE_CR_SCRATCH3 0x1A18U +#define ROGUE_CR_SCRATCH3_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH3_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH4 */ +#define ROGUE_CR_SCRATCH4 0x1A20U +#define ROGUE_CR_SCRATCH4_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH4_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH4_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH5 */ +#define ROGUE_CR_SCRATCH5 0x1A28U +#define ROGUE_CR_SCRATCH5_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH5_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH5_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH6 */ +#define ROGUE_CR_SCRATCH6 0x1A30U +#define ROGUE_CR_SCRATCH6_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH6_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH6_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH7 */ +#define ROGUE_CR_SCRATCH7 0x1A38U +#define ROGUE_CR_SCRATCH7_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH7_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH7_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH8 */ +#define ROGUE_CR_SCRATCH8 0x1A40U +#define ROGUE_CR_SCRATCH8_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH8_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH8_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH9 */ +#define ROGUE_CR_SCRATCH9 0x1A48U +#define ROGUE_CR_SCRATCH9_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH9_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH9_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH10 */ +#define ROGUE_CR_SCRATCH10 0x1A50U +#define ROGUE_CR_SCRATCH10_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH10_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH10_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH11 */ +#define ROGUE_CR_SCRATCH11 0x1A58U +#define ROGUE_CR_SCRATCH11_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH11_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH11_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH12 */ +#define ROGUE_CR_SCRATCH12 0x1A60U +#define ROGUE_CR_SCRATCH12_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH12_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH12_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH13 */ +#define ROGUE_CR_SCRATCH13 0x1A68U +#define ROGUE_CR_SCRATCH13_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH13_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH13_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH14 */ +#define ROGUE_CR_SCRATCH14 0x1A70U +#define ROGUE_CR_SCRATCH14_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH14_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH14_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH15 */ +#define ROGUE_CR_SCRATCH15 0x1A78U +#define ROGUE_CR_SCRATCH15_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH15_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH15_DATA_CLRMSK 0x00000000U + +/* Register group: ROGUE_CR_OS0_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS0_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS0_SCRATCH0 */ +#define ROGUE_CR_OS0_SCRATCH0 0x1A80U +#define ROGUE_CR_OS0_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS0_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS0_SCRATCH1 */ +#define ROGUE_CR_OS0_SCRATCH1 0x1A88U +#define ROGUE_CR_OS0_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS0_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS0_SCRATCH2 */ +#define ROGUE_CR_OS0_SCRATCH2 0x1A90U +#define ROGUE_CR_OS0_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS0_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS0_SCRATCH3 */ +#define ROGUE_CR_OS0_SCRATCH3 0x1A98U +#define ROGUE_CR_OS0_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS0_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS1_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS1_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS1_SCRATCH0 */ +#define ROGUE_CR_OS1_SCRATCH0 0x11A80U +#define ROGUE_CR_OS1_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS1_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS1_SCRATCH1 */ +#define ROGUE_CR_OS1_SCRATCH1 0x11A88U +#define ROGUE_CR_OS1_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS1_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS1_SCRATCH2 */ +#define ROGUE_CR_OS1_SCRATCH2 0x11A90U +#define ROGUE_CR_OS1_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS1_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS1_SCRATCH3 */ +#define ROGUE_CR_OS1_SCRATCH3 0x11A98U +#define ROGUE_CR_OS1_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS1_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS2_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS2_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS2_SCRATCH0 */ +#define ROGUE_CR_OS2_SCRATCH0 0x21A80U +#define ROGUE_CR_OS2_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS2_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS2_SCRATCH1 */ +#define ROGUE_CR_OS2_SCRATCH1 0x21A88U +#define ROGUE_CR_OS2_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS2_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS2_SCRATCH2 */ +#define ROGUE_CR_OS2_SCRATCH2 0x21A90U +#define ROGUE_CR_OS2_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS2_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS2_SCRATCH3 */ +#define ROGUE_CR_OS2_SCRATCH3 0x21A98U +#define ROGUE_CR_OS2_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS2_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS3_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS3_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS3_SCRATCH0 */ +#define ROGUE_CR_OS3_SCRATCH0 0x31A80U +#define ROGUE_CR_OS3_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS3_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS3_SCRATCH1 */ +#define ROGUE_CR_OS3_SCRATCH1 0x31A88U +#define ROGUE_CR_OS3_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS3_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS3_SCRATCH2 */ +#define ROGUE_CR_OS3_SCRATCH2 0x31A90U +#define ROGUE_CR_OS3_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS3_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS3_SCRATCH3 */ +#define ROGUE_CR_OS3_SCRATCH3 0x31A98U +#define ROGUE_CR_OS3_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS3_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS4_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS4_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS4_SCRATCH0 */ +#define ROGUE_CR_OS4_SCRATCH0 0x41A80U +#define ROGUE_CR_OS4_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS4_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS4_SCRATCH1 */ +#define ROGUE_CR_OS4_SCRATCH1 0x41A88U +#define ROGUE_CR_OS4_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS4_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS4_SCRATCH2 */ +#define ROGUE_CR_OS4_SCRATCH2 0x41A90U +#define ROGUE_CR_OS4_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS4_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS4_SCRATCH3 */ +#define ROGUE_CR_OS4_SCRATCH3 0x41A98U +#define ROGUE_CR_OS4_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS4_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS5_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS5_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS5_SCRATCH0 */ +#define ROGUE_CR_OS5_SCRATCH0 0x51A80U +#define ROGUE_CR_OS5_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS5_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS5_SCRATCH1 */ +#define ROGUE_CR_OS5_SCRATCH1 0x51A88U +#define ROGUE_CR_OS5_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS5_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS5_SCRATCH2 */ +#define ROGUE_CR_OS5_SCRATCH2 0x51A90U +#define ROGUE_CR_OS5_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS5_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS5_SCRATCH3 */ +#define ROGUE_CR_OS5_SCRATCH3 0x51A98U +#define ROGUE_CR_OS5_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS5_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS6_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS6_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS6_SCRATCH0 */ +#define ROGUE_CR_OS6_SCRATCH0 0x61A80U +#define ROGUE_CR_OS6_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS6_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS6_SCRATCH1 */ +#define ROGUE_CR_OS6_SCRATCH1 0x61A88U +#define ROGUE_CR_OS6_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS6_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS6_SCRATCH2 */ +#define ROGUE_CR_OS6_SCRATCH2 0x61A90U +#define ROGUE_CR_OS6_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS6_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS6_SCRATCH3 */ +#define ROGUE_CR_OS6_SCRATCH3 0x61A98U +#define ROGUE_CR_OS6_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS6_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS7_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS7_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS7_SCRATCH0 */ +#define ROGUE_CR_OS7_SCRATCH0 0x71A80U +#define ROGUE_CR_OS7_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS7_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS7_SCRATCH1 */ +#define ROGUE_CR_OS7_SCRATCH1 0x71A88U +#define ROGUE_CR_OS7_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS7_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS7_SCRATCH2 */ +#define ROGUE_CR_OS7_SCRATCH2 0x71A90U +#define ROGUE_CR_OS7_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS7_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS7_SCRATCH3 */ +#define ROGUE_CR_OS7_SCRATCH3 0x71A98U +#define ROGUE_CR_OS7_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS7_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_SPFILTER_SIGNAL_DESCR */ +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR 0x2700U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_SHIFT 0U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_CLRMSK 0xFFFF0000U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_ALIGNSHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_ALIGNSIZE 16U + +/* Register ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN */ +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN 0x2708U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_MASKFULL 0x000000FFFFFFFFF0ULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_SHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_ALIGNSIZE 16U + +/* Register group: ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG, with 16 repeats */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG_REPEATCOUNT 16U +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0 0x3000U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1 0x3008U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2 0x3010U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3 0x3018U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4 0x3020U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5 0x3028U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6 0x3030U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7 0x3038U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8 0x3040U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9 0x3048U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10 0x3050U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11 0x3058U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12 0x3060U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13 0x3068U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14 0x3070U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15 0x3078U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_BOOT */ +#define ROGUE_CR_FWCORE_BOOT 0x3090U +#define ROGUE_CR_FWCORE_BOOT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_BOOT_ENABLE_SHIFT 0U +#define ROGUE_CR_FWCORE_BOOT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_BOOT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_RESET_ADDR */ +#define ROGUE_CR_FWCORE_RESET_ADDR 0x3098U +#define ROGUE_CR_FWCORE_RESET_ADDR_MASKFULL 0x00000000FFFFFFFEULL +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_SHIFT 1U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_CLRMSK 0x00000001U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_ALIGNSHIFT 1U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_ALIGNSIZE 2U + +/* Register ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR */ +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR 0x30A0U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_MASKFULL 0x00000000FFFFFFFEULL +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_SHIFT 1U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_CLRMSK 0x00000001U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_ALIGNSHIFT 1U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_ALIGNSIZE 2U + +/* Register ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT */ +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT 0x30A8U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_SHIFT 0U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS */ +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS 0x30B0U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_MASKFULL 0x000000000000F771ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS */ +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS 0x30B8U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_MASKFULL 0x001FFFFFFFFFFFF0ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_SHIFT 52U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_EN 0x0010000000000000ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_SB_SHIFT 46U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_SB_CLRMSK 0xFFF03FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFC0FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_FWCORE_MEM_CTRL_INVAL */ +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL 0x30C0U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_SHIFT 3U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_EN 0x00000008U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_SHIFT 2U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_EN 0x00000004U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_SHIFT 1U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_EN 0x00000002U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_MMU_STATUS */ +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS 0x30C8U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_MASKFULL 0x000000000FFFFFF7ULL +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PC_DATA_SHIFT 20U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PD_DATA_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PT_DATA_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_SHIFT 2U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_EN 0x00000004U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_SHIFT 1U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_EN 0x00000002U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS */ +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS 0x30D8U +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MASKFULL 0x0000000000000FFFULL +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MMU_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MMU_CLRMSK 0xFFFFF000U + +/* Register ROGUE_CR_FWCORE_MEM_READS_INT_STATUS */ +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS 0x30E0U +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MASKFULL 0x00000000000007FFULL +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MMU_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MMU_CLRMSK 0xFFFFF800U + +/* Register ROGUE_CR_FWCORE_WRAPPER_FENCE */ +#define ROGUE_CR_FWCORE_WRAPPER_FENCE 0x30E8U +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_SHIFT 0U +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_EN 0x00000001U + +/* Register group: ROGUE_CR_FWCORE_MEM_CAT_BASE, with 8 repeats */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE_REPEATCOUNT 8U +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE0 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0 0x30F0U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE1 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1 0x30F8U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE2 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2 0x3100U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE3 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3 0x3108U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE4 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4 0x3110U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE5 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5 0x3118U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE6 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6 0x3120U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE7 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7 0x3128U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_WDT_RESET */ +#define ROGUE_CR_FWCORE_WDT_RESET 0x3130U +#define ROGUE_CR_FWCORE_WDT_RESET_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WDT_RESET_EN_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_RESET_EN_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WDT_RESET_EN_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_WDT_CTRL */ +#define ROGUE_CR_FWCORE_WDT_CTRL 0x3138U +#define ROGUE_CR_FWCORE_WDT_CTRL_MASKFULL 0x00000000FFFF1F01ULL +#define ROGUE_CR_FWCORE_WDT_CTRL_PROT_SHIFT 16U +#define ROGUE_CR_FWCORE_WDT_CTRL_PROT_CLRMSK 0x0000FFFFU +#define ROGUE_CR_FWCORE_WDT_CTRL_THRESHOLD_SHIFT 8U +#define ROGUE_CR_FWCORE_WDT_CTRL_THRESHOLD_CLRMSK 0xFFFFE0FFU +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_WDT_COUNT */ +#define ROGUE_CR_FWCORE_WDT_COUNT 0x3140U +#define ROGUE_CR_FWCORE_WDT_COUNT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FWCORE_WDT_COUNT_VALUE_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_COUNT_VALUE_CLRMSK 0x00000000U + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED0, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED0_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED00 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED00 0x3400U +#define ROGUE_CR_FWCORE_DMI_RESERVED00_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED01 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED01 0x3408U +#define ROGUE_CR_FWCORE_DMI_RESERVED01_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED02 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED02 0x3410U +#define ROGUE_CR_FWCORE_DMI_RESERVED02_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED03 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED03 0x3418U +#define ROGUE_CR_FWCORE_DMI_RESERVED03_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DATA0 */ +#define ROGUE_CR_FWCORE_DMI_DATA0 0x3420U +#define ROGUE_CR_FWCORE_DMI_DATA0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DATA1 */ +#define ROGUE_CR_FWCORE_DMI_DATA1 0x3428U +#define ROGUE_CR_FWCORE_DMI_DATA1_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED1, with 5 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED1_REPEATCOUNT 5U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED10 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED10 0x3430U +#define ROGUE_CR_FWCORE_DMI_RESERVED10_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED11 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED11 0x3438U +#define ROGUE_CR_FWCORE_DMI_RESERVED11_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED12 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED12 0x3440U +#define ROGUE_CR_FWCORE_DMI_RESERVED12_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED13 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED13 0x3448U +#define ROGUE_CR_FWCORE_DMI_RESERVED13_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED14 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED14 0x3450U +#define ROGUE_CR_FWCORE_DMI_RESERVED14_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DMCONTROL */ +#define ROGUE_CR_FWCORE_DMI_DMCONTROL 0x3480U +#define ROGUE_CR_FWCORE_DMI_DMCONTROL_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DMSTATUS */ +#define ROGUE_CR_FWCORE_DMI_DMSTATUS 0x3488U +#define ROGUE_CR_FWCORE_DMI_DMSTATUS_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED2, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED2_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED20 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED20 0x3490U +#define ROGUE_CR_FWCORE_DMI_RESERVED20_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED21 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED21 0x3498U +#define ROGUE_CR_FWCORE_DMI_RESERVED21_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED22 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED22 0x34A0U +#define ROGUE_CR_FWCORE_DMI_RESERVED22_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED23 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED23 0x34A8U +#define ROGUE_CR_FWCORE_DMI_RESERVED23_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_ABSTRACTCS */ +#define ROGUE_CR_FWCORE_DMI_ABSTRACTCS 0x34B0U +#define ROGUE_CR_FWCORE_DMI_ABSTRACTCS_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_COMMAND */ +#define ROGUE_CR_FWCORE_DMI_COMMAND 0x34B8U +#define ROGUE_CR_FWCORE_DMI_COMMAND_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBCS */ +#define ROGUE_CR_FWCORE_DMI_SBCS 0x35C0U +#define ROGUE_CR_FWCORE_DMI_SBCS_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBADDRESS0 */ +#define ROGUE_CR_FWCORE_DMI_SBADDRESS0 0x35C8U +#define ROGUE_CR_FWCORE_DMI_SBADDRESS0_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED3, with 2 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED3_REPEATCOUNT 2U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED30 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED30 0x34D0U +#define ROGUE_CR_FWCORE_DMI_RESERVED30_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED31 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED31 0x34D8U +#define ROGUE_CR_FWCORE_DMI_RESERVED31_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_SBDATA, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_SBDATA_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_SBDATA0 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA0 0x35E0U +#define ROGUE_CR_FWCORE_DMI_SBDATA0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA1 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA1 0x35E8U +#define ROGUE_CR_FWCORE_DMI_SBDATA1_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA2 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA2 0x35F0U +#define ROGUE_CR_FWCORE_DMI_SBDATA2_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA3 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA3 0x35F8U +#define ROGUE_CR_FWCORE_DMI_SBDATA3_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_HALTSUM0 */ +#define ROGUE_CR_FWCORE_DMI_HALTSUM0 0x3600U +#define ROGUE_CR_FWCORE_DMI_HALTSUM0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC_CTRL_MISC */ +#define ROGUE_CR_SLC_CTRL_MISC 0x3800U +#define ROGUE_CR_SLC_CTRL_MISC_MASKFULL 0xFFFFFFFF01FF010FULL +#define ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS_SHIFT 32U +#define ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_SHIFT 24U +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_EN 0x0000000001000000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SHIFT 16U +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_INTERLEAVED_64_BYTE 0x0000000000000000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_INTERLEAVED_128_BYTE 0x0000000000010000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SIMPLE_HASH1 0x0000000000100000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SIMPLE_HASH2 0x0000000000110000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH1 0x0000000000200000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH2_SCRAMBLE 0x0000000000210000ULL +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_EN 0x0000000000000100ULL +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_EN 0x0000000000000008ULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_EN 0x0000000000000004ULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_EN 0x0000000000000002ULL +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC_CTRL_FLUSH_INVAL */ +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL 0x3818U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_MASKFULL 0x0000000080000FFFULL +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_SHIFT 31U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_EN 0x80000000U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_SHIFT 11U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_EN 0x00000800U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_SHIFT 10U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_EN 0x00000400U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_SHIFT 9U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_EN 0x00000200U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_EN 0x00000100U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_SHIFT 7U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_EN 0x00000080U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_SHIFT 6U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_EN 0x00000040U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_SHIFT 5U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_EN 0x00000020U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_SHIFT 4U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_EN 0x00000010U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_EN 0x00000008U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_EN 0x00000004U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_EN 0x00000002U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_EN 0x00000001U + +/* Register ROGUE_CR_SLC_STATUS0 */ +#define ROGUE_CR_SLC_STATUS0 0x3820U +#define ROGUE_CR_SLC_STATUS0_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_SHIFT 2U +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_EN 0x00000004U +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_SHIFT 1U +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_EN 0x00000002U +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_SHIFT 0U +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_EN 0x00000001U + +/* Register ROGUE_CR_SLC_CTRL_BYPASS */ +#define ROGUE_CR_SLC_CTRL_BYPASS 0x3828U +#define ROGUE_CR_SLC_CTRL_BYPASS__XE_MEM__MASKFULL 0x0FFFFFFFFFFF7FFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_SHIFT 59U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_CLRMSK 0xF7FFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_EN 0x0800000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_SHIFT 58U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_CLRMSK 0xFBFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_EN 0x0400000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_SHIFT 57U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_EN 0x0200000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_SHIFT 56U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_CLRMSK 0xFEFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_EN 0x0100000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_SHIFT 55U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_CLRMSK 0xFF7FFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_EN 0x0080000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_SHIFT 54U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_CLRMSK 0xFFBFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_EN 0x0040000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_SHIFT 53U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_CLRMSK 0xFFDFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_EN 0x0020000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_SHIFT 52U +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_EN 0x0010000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_SHIFT 51U +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_CLRMSK 0xFFF7FFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_EN 0x0008000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_SHIFT 50U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_EN 0x0004000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_SHIFT 49U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_CLRMSK 0xFFFDFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_EN 0x0002000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_SHIFT 48U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_CLRMSK 0xFFFEFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_EN 0x0001000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_SHIFT 47U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_CLRMSK 0xFFFF7FFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_EN 0x0000800000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_SHIFT 46U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_CLRMSK 0xFFFFBFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_EN 0x0000400000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_SHIFT 45U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_EN 0x0000200000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_SHIFT 44U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_CLRMSK 0xFFFFEFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_EN 0x0000100000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_SHIFT 43U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_CLRMSK 0xFFFFF7FFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_EN 0x0000080000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_SHIFT 42U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_EN 0x0000040000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_SHIFT 41U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_CLRMSK 0xFFFFFDFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_EN 0x0000020000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_SHIFT 40U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_EN 0x0000010000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_SHIFT 39U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_CLRMSK 0xFFFFFF7FFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_EN 0x0000008000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_SHIFT 38U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_EN 0x0000004000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_SHIFT 37U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_EN 0x0000002000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_SHIFT 36U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_EN 0x0000001000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_SHIFT 35U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_EN 0x0000000800000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_SHIFT 34U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_EN 0x0000000400000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_SHIFT 33U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_EN 0x0000000200000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_SHIFT 32U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_EN 0x0000000100000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_SHIFT 31U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_EN 0x0000000080000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_SHIFT 30U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_EN 0x0000000040000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_SHIFT 29U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_EN 0x0000000020000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_SHIFT 28U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_EN 0x0000000010000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_SHIFT 27U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_EN 0x0000000008000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_SHIFT 26U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_EN 0x0000000004000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_SHIFT 25U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_EN 0x0000000002000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_SHIFT 24U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_EN 0x0000000001000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_SHIFT 23U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_EN 0x0000000000800000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_SHIFT 22U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_EN 0x0000000000400000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_SHIFT 21U +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_EN 0x0000000000200000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_SHIFT 20U +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_EN 0x0000000000100000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_SHIFT 19U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_EN 0x0000000000080000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_SHIFT 18U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_EN 0x0000000000040000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_SHIFT 17U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_EN 0x0000000000020000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_SHIFT 16U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_EN 0x0000000000010000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_SHIFT 15U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_EN 0x0000000000008000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_SHIFT 14U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_EN 0x0000000000004000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_SHIFT 13U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_EN 0x0000000000002000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_SHIFT 12U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_EN 0x0000000000001000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_SHIFT 11U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_EN 0x0000000000000800ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_SHIFT 10U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_EN 0x0000000000000400ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_SHIFT 9U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_EN 0x0000000000000200ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_EN 0x0000000000000100ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_SHIFT 7U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_EN 0x0000000000000080ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_SHIFT 6U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_EN 0x0000000000000040ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_SHIFT 5U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_EN 0x0000000000000020ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_SHIFT 4U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_EN 0x0000000000000010ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_EN 0x0000000000000008ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_EN 0x0000000000000004ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_EN 0x0000000000000002ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC_STATUS1 */ +#define ROGUE_CR_SLC_STATUS1 0x3870U +#define ROGUE_CR_SLC_STATUS1_MASKFULL 0x800003FF03FFFFFFULL +#define ROGUE_CR_SLC_STATUS1_PAUSED_SHIFT 63U +#define ROGUE_CR_SLC_STATUS1_PAUSED_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_STATUS1_PAUSED_EN 0x8000000000000000ULL +#define ROGUE_CR_SLC_STATUS1_READS1_SHIFT 32U +#define ROGUE_CR_SLC_STATUS1_READS1_CLRMSK 0xFFFFFC00FFFFFFFFULL +#define ROGUE_CR_SLC_STATUS1_READS0_SHIFT 16U +#define ROGUE_CR_SLC_STATUS1_READS0_CLRMSK 0xFFFFFFFFFC00FFFFULL +#define ROGUE_CR_SLC_STATUS1_READS1_EXT_SHIFT 8U +#define ROGUE_CR_SLC_STATUS1_READS1_EXT_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_SLC_STATUS1_READS0_EXT_SHIFT 0U +#define ROGUE_CR_SLC_STATUS1_READS0_EXT_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_SLC_IDLE */ +#define ROGUE_CR_SLC_IDLE 0x3898U +#define ROGUE_CR_SLC_IDLE__XE_MEM__MASKFULL 0x00000000000003FFULL +#define ROGUE_CR_SLC_IDLE_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_SHIFT 9U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_EN 0x00000200U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_SHIFT 8U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_EN 0x00000100U +#define ROGUE_CR_SLC_IDLE_IMGBV4_SHIFT 7U +#define ROGUE_CR_SLC_IDLE_IMGBV4_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SLC_IDLE_IMGBV4_EN 0x00000080U +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_SHIFT 6U +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_EN 0x00000040U +#define ROGUE_CR_SLC_IDLE_RBOFIFO_SHIFT 5U +#define ROGUE_CR_SLC_IDLE_RBOFIFO_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SLC_IDLE_RBOFIFO_EN 0x00000020U +#define ROGUE_CR_SLC_IDLE_FRC_CONV_SHIFT 4U +#define ROGUE_CR_SLC_IDLE_FRC_CONV_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SLC_IDLE_FRC_CONV_EN 0x00000010U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_SHIFT 3U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_EN 0x00000008U +#define ROGUE_CR_SLC_IDLE_VXD_CONV_SHIFT 2U +#define ROGUE_CR_SLC_IDLE_VXD_CONV_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_IDLE_VXD_CONV_EN 0x00000004U +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_SHIFT 1U +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_EN 0x00000002U +#define ROGUE_CR_SLC_IDLE_CBAR_SHIFT 0U +#define ROGUE_CR_SLC_IDLE_CBAR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_IDLE_CBAR_EN 0x00000001U + +/* Register ROGUE_CR_SLC_STATUS2 */ +#define ROGUE_CR_SLC_STATUS2 0x3908U +#define ROGUE_CR_SLC_STATUS2_MASKFULL 0x000003FF03FFFFFFULL +#define ROGUE_CR_SLC_STATUS2_READS3_SHIFT 32U +#define ROGUE_CR_SLC_STATUS2_READS3_CLRMSK 0xFFFFFC00FFFFFFFFULL +#define ROGUE_CR_SLC_STATUS2_READS2_SHIFT 16U +#define ROGUE_CR_SLC_STATUS2_READS2_CLRMSK 0xFFFFFFFFFC00FFFFULL +#define ROGUE_CR_SLC_STATUS2_READS3_EXT_SHIFT 8U +#define ROGUE_CR_SLC_STATUS2_READS3_EXT_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_SLC_STATUS2_READS2_EXT_SHIFT 0U +#define ROGUE_CR_SLC_STATUS2_READS2_EXT_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_SLC_CTRL_MISC2 */ +#define ROGUE_CR_SLC_CTRL_MISC2 0x3930U +#define ROGUE_CR_SLC_CTRL_MISC2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC2_SCRAMBLE_BITS_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_MISC2_SCRAMBLE_BITS_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE */ +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE 0x3938U +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_SHIFT 0U +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_EN 0x00000001U + +/* Register ROGUE_CR_USC_UVS0_CHECKSUM */ +#define ROGUE_CR_USC_UVS0_CHECKSUM 0x5000U +#define ROGUE_CR_USC_UVS0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS1_CHECKSUM */ +#define ROGUE_CR_USC_UVS1_CHECKSUM 0x5008U +#define ROGUE_CR_USC_UVS1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS2_CHECKSUM */ +#define ROGUE_CR_USC_UVS2_CHECKSUM 0x5010U +#define ROGUE_CR_USC_UVS2_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS2_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS2_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS3_CHECKSUM */ +#define ROGUE_CR_USC_UVS3_CHECKSUM 0x5018U +#define ROGUE_CR_USC_UVS3_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS3_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS3_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PPP_SIGNATURE */ +#define ROGUE_CR_PPP_SIGNATURE 0x5020U +#define ROGUE_CR_PPP_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_PPP_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TE_SIGNATURE */ +#define ROGUE_CR_TE_SIGNATURE 0x5028U +#define ROGUE_CR_TE_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TE_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_TE_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TE_CHECKSUM */ +#define ROGUE_CR_TE_CHECKSUM 0x5110U +#define ROGUE_CR_TE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVB_CHECKSUM */ +#define ROGUE_CR_USC_UVB_CHECKSUM 0x5118U +#define ROGUE_CR_USC_UVB_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVB_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVB_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VCE_CHECKSUM */ +#define ROGUE_CR_VCE_CHECKSUM 0x5030U +#define ROGUE_CR_VCE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VCE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_VCE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_ISP_PDS_CHECKSUM */ +#define ROGUE_CR_ISP_PDS_CHECKSUM 0x5038U +#define ROGUE_CR_ISP_PDS_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_ISP_PDS_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_ISP_PDS_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_ISP_TPF_CHECKSUM */ +#define ROGUE_CR_ISP_TPF_CHECKSUM 0x5040U +#define ROGUE_CR_ISP_TPF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_ISP_TPF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_ISP_TPF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TFPU_PLANE0_CHECKSUM */ +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM 0x5048U +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TFPU_PLANE1_CHECKSUM */ +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM 0x5050U +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PBE_CHECKSUM */ +#define ROGUE_CR_PBE_CHECKSUM 0x5058U +#define ROGUE_CR_PBE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PBE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_PBE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PDS_DOUTM_STM_SIGNATURE */ +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE 0x5060U +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_IFPU_ISP_CHECKSUM */ +#define ROGUE_CR_IFPU_ISP_CHECKSUM 0x5068U +#define ROGUE_CR_IFPU_ISP_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_IFPU_ISP_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_IFPU_ISP_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS4_CHECKSUM */ +#define ROGUE_CR_USC_UVS4_CHECKSUM 0x5100U +#define ROGUE_CR_USC_UVS4_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS4_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS4_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS5_CHECKSUM */ +#define ROGUE_CR_USC_UVS5_CHECKSUM 0x5108U +#define ROGUE_CR_USC_UVS5_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS5_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS5_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PPP_CLIP_CHECKSUM */ +#define ROGUE_CR_PPP_CLIP_CHECKSUM 0x5120U +#define ROGUE_CR_PPP_CLIP_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_CLIP_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_PPP_CLIP_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_PHASE */ +#define ROGUE_CR_PERF_TA_PHASE 0x6008U +#define ROGUE_CR_PERF_TA_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_PHASE */ +#define ROGUE_CR_PERF_3D_PHASE 0x6010U +#define ROGUE_CR_PERF_3D_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_3D_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_COMPUTE_PHASE */ +#define ROGUE_CR_PERF_COMPUTE_PHASE 0x6018U +#define ROGUE_CR_PERF_COMPUTE_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_COMPUTE_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_COMPUTE_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_CYCLE */ +#define ROGUE_CR_PERF_TA_CYCLE 0x6020U +#define ROGUE_CR_PERF_TA_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_CYCLE */ +#define ROGUE_CR_PERF_3D_CYCLE 0x6028U +#define ROGUE_CR_PERF_3D_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_3D_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_COMPUTE_CYCLE */ +#define ROGUE_CR_PERF_COMPUTE_CYCLE 0x6030U +#define ROGUE_CR_PERF_COMPUTE_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_COMPUTE_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_COMPUTE_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_OR_3D_CYCLE */ +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE 0x6038U +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_INITIAL_TA_CYCLE */ +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE 0x6040U +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC0_READ_STALL */ +#define ROGUE_CR_PERF_SLC0_READ_STALL 0x60B8U +#define ROGUE_CR_PERF_SLC0_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC0_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC0_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC0_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC0_WRITE_STALL 0x60C0U +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC1_READ_STALL */ +#define ROGUE_CR_PERF_SLC1_READ_STALL 0x60E0U +#define ROGUE_CR_PERF_SLC1_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC1_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC1_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC1_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC1_WRITE_STALL 0x60E8U +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC2_READ_STALL */ +#define ROGUE_CR_PERF_SLC2_READ_STALL 0x6158U +#define ROGUE_CR_PERF_SLC2_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC2_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC2_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC2_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC2_WRITE_STALL 0x6160U +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC3_READ_STALL */ +#define ROGUE_CR_PERF_SLC3_READ_STALL 0x6180U +#define ROGUE_CR_PERF_SLC3_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC3_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC3_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC3_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC3_WRITE_STALL 0x6188U +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_SPINUP */ +#define ROGUE_CR_PERF_3D_SPINUP 0x6220U +#define ROGUE_CR_PERF_3D_SPINUP_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_SPINUP_CYCLES_SHIFT 0U +#define ROGUE_CR_PERF_3D_SPINUP_CYCLES_CLRMSK 0x00000000U + +/* Register ROGUE_CR_AXI_ACE_LITE_CONFIGURATION */ +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION 0x38C0U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_MASKFULL 0x00003FFFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_SHIFT 45U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_EN 0x0000200000000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_OSID_SECURITY_SHIFT 37U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_OSID_SECURITY_CLRMSK 0xFFFFE01FFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_SHIFT 36U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_CLRMSK \ + 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_EN \ + 0x0000001000000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_SHIFT 35U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_EN 0x0000000800000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_SHIFT 34U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_EN 0x0000000400000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_SHIFT 30U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_CLRMSK 0xFFFFFFFC3FFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_SHIFT 26U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_CLRMSK 0xFFFFFFFFC3FFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_SHIFT 22U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_CLRMSK 0xFFFFFFFFFC3FFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_BARRIER_SHIFT 20U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_BARRIER_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_BARRIER_SHIFT 18U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_BARRIER_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_SHIFT 16U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_SHIFT 14U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_CLRMSK 0xFFFFFFFFFFFF3FFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_SHIFT 12U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_CLRMSK 0xFFFFFFFFFFFFCFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_SHIFT 10U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_SHIFT 8U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_NON_SNOOPING_SHIFT 4U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFF0FULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_NON_SNOOPING_SHIFT 0U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFFF0ULL + +/* Register ROGUE_CR_POWER_ESTIMATE_RESULT */ +#define ROGUE_CR_POWER_ESTIMATE_RESULT 0x6328U +#define ROGUE_CR_POWER_ESTIMATE_RESULT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_POWER_ESTIMATE_RESULT_VALUE_SHIFT 0U +#define ROGUE_CR_POWER_ESTIMATE_RESULT_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF */ +#define ROGUE_CR_TA_PERF 0x7600U +#define ROGUE_CR_TA_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TA_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TA_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TA_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TA_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TA_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TA_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TA_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TA_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TA_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TA_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TA_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TA_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TA_PERF_SELECT0 */ +#define ROGUE_CR_TA_PERF_SELECT0 0x7608U +#define ROGUE_CR_TA_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT1 */ +#define ROGUE_CR_TA_PERF_SELECT1 0x7610U +#define ROGUE_CR_TA_PERF_SELECT1_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT1_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT1_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT1_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT1_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT2 */ +#define ROGUE_CR_TA_PERF_SELECT2 0x7618U +#define ROGUE_CR_TA_PERF_SELECT2_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT2_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT2_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT2_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT2_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT3 */ +#define ROGUE_CR_TA_PERF_SELECT3 0x7620U +#define ROGUE_CR_TA_PERF_SELECT3_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT3_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT3_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT3_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT3_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECTED_BITS */ +#define ROGUE_CR_TA_PERF_SELECTED_BITS 0x7648U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG3_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG3_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG2_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG2_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG1_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG1_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG0_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG0_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_COUNTER_0 */ +#define ROGUE_CR_TA_PERF_COUNTER_0 0x7650U +#define ROGUE_CR_TA_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_1 */ +#define ROGUE_CR_TA_PERF_COUNTER_1 0x7658U +#define ROGUE_CR_TA_PERF_COUNTER_1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_1_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_1_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_2 */ +#define ROGUE_CR_TA_PERF_COUNTER_2 0x7660U +#define ROGUE_CR_TA_PERF_COUNTER_2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_2_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_2_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_3 */ +#define ROGUE_CR_TA_PERF_COUNTER_3 0x7668U +#define ROGUE_CR_TA_PERF_COUNTER_3_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_3_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_3_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_RASTERISATION_PERF */ +#define ROGUE_CR_RASTERISATION_PERF 0x7700U +#define ROGUE_CR_RASTERISATION_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_RASTERISATION_PERF_SELECT0 */ +#define ROGUE_CR_RASTERISATION_PERF_SELECT0 0x7708U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_RASTERISATION_PERF_COUNTER_0 */ +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0 0x7750U +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF 0x7800U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0 */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0 0x7808U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0 */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0 0x7850U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF */ +#define ROGUE_CR_TPU_MCU_L0_PERF 0x7900U +#define ROGUE_CR_TPU_MCU_L0_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_SELECT0 */ +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0 0x7908U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0 */ +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0 0x7950U +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_PERF */ +#define ROGUE_CR_USC_PERF 0x8100U +#define ROGUE_CR_USC_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_USC_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_USC_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_USC_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_USC_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_USC_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_USC_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_USC_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_USC_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_USC_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_USC_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_USC_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_USC_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_USC_PERF_SELECT0 */ +#define ROGUE_CR_USC_PERF_SELECT0 0x8108U +#define ROGUE_CR_USC_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_USC_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_USC_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_USC_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_USC_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_USC_PERF_COUNTER_0 */ +#define ROGUE_CR_USC_PERF_COUNTER_0 0x8150U +#define ROGUE_CR_USC_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_USC_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_JONES_IDLE */ +#define ROGUE_CR_JONES_IDLE 0x8328U +#define ROGUE_CR_JONES_IDLE_MASKFULL 0x0000000000007FFFULL +#define ROGUE_CR_JONES_IDLE_TDM_SHIFT 14U +#define ROGUE_CR_JONES_IDLE_TDM_CLRMSK 0xFFFFBFFFU +#define ROGUE_CR_JONES_IDLE_TDM_EN 0x00004000U +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_SHIFT 13U +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_CLRMSK 0xFFFFDFFFU +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_EN 0x00002000U +#define ROGUE_CR_JONES_IDLE_FB_CDC_SHIFT 12U +#define ROGUE_CR_JONES_IDLE_FB_CDC_CLRMSK 0xFFFFEFFFU +#define ROGUE_CR_JONES_IDLE_FB_CDC_EN 0x00001000U +#define ROGUE_CR_JONES_IDLE_MMU_SHIFT 11U +#define ROGUE_CR_JONES_IDLE_MMU_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_JONES_IDLE_MMU_EN 0x00000800U +#define ROGUE_CR_JONES_IDLE_TLA_SHIFT 10U +#define ROGUE_CR_JONES_IDLE_TLA_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_JONES_IDLE_TLA_EN 0x00000400U +#define ROGUE_CR_JONES_IDLE_GARTEN_SHIFT 9U +#define ROGUE_CR_JONES_IDLE_GARTEN_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_JONES_IDLE_GARTEN_EN 0x00000200U +#define ROGUE_CR_JONES_IDLE_HOSTIF_SHIFT 8U +#define ROGUE_CR_JONES_IDLE_HOSTIF_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_JONES_IDLE_HOSTIF_EN 0x00000100U +#define ROGUE_CR_JONES_IDLE_SOCIF_SHIFT 7U +#define ROGUE_CR_JONES_IDLE_SOCIF_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_JONES_IDLE_SOCIF_EN 0x00000080U +#define ROGUE_CR_JONES_IDLE_TILING_SHIFT 6U +#define ROGUE_CR_JONES_IDLE_TILING_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_JONES_IDLE_TILING_EN 0x00000040U +#define ROGUE_CR_JONES_IDLE_IPP_SHIFT 5U +#define ROGUE_CR_JONES_IDLE_IPP_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_JONES_IDLE_IPP_EN 0x00000020U +#define ROGUE_CR_JONES_IDLE_USCS_SHIFT 4U +#define ROGUE_CR_JONES_IDLE_USCS_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_JONES_IDLE_USCS_EN 0x00000010U +#define ROGUE_CR_JONES_IDLE_PM_SHIFT 3U +#define ROGUE_CR_JONES_IDLE_PM_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_JONES_IDLE_PM_EN 0x00000008U +#define ROGUE_CR_JONES_IDLE_CDM_SHIFT 2U +#define ROGUE_CR_JONES_IDLE_CDM_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_JONES_IDLE_CDM_EN 0x00000004U +#define ROGUE_CR_JONES_IDLE_VDM_SHIFT 1U +#define ROGUE_CR_JONES_IDLE_VDM_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_JONES_IDLE_VDM_EN 0x00000002U +#define ROGUE_CR_JONES_IDLE_BIF_SHIFT 0U +#define ROGUE_CR_JONES_IDLE_BIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_JONES_IDLE_BIF_EN 0x00000001U + +/* Register ROGUE_CR_TORNADO_PERF */ +#define ROGUE_CR_TORNADO_PERF 0x8228U +#define ROGUE_CR_TORNADO_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TORNADO_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TORNADO_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TORNADO_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TORNADO_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TORNADO_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TORNADO_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TORNADO_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TORNADO_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TORNADO_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TORNADO_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TORNADO_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TORNADO_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TORNADO_PERF_SELECT0 */ +#define ROGUE_CR_TORNADO_PERF_SELECT0 0x8230U +#define ROGUE_CR_TORNADO_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TORNADO_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TORNADO_PERF_COUNTER_0 */ +#define ROGUE_CR_TORNADO_PERF_COUNTER_0 0x8268U +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TEXAS_PERF */ +#define ROGUE_CR_TEXAS_PERF 0x8290U +#define ROGUE_CR_TEXAS_PERF_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_TEXAS_PERF_CLR_5_SHIFT 6U +#define ROGUE_CR_TEXAS_PERF_CLR_5_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_TEXAS_PERF_CLR_5_EN 0x00000040U +#define ROGUE_CR_TEXAS_PERF_CLR_4_SHIFT 5U +#define ROGUE_CR_TEXAS_PERF_CLR_4_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_TEXAS_PERF_CLR_4_EN 0x00000020U +#define ROGUE_CR_TEXAS_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TEXAS_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TEXAS_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TEXAS_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TEXAS_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TEXAS_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TEXAS_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TEXAS_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TEXAS_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TEXAS_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TEXAS_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TEXAS_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TEXAS_PERF_SELECT0 */ +#define ROGUE_CR_TEXAS_PERF_SELECT0 0x8298U +#define ROGUE_CR_TEXAS_PERF_SELECT0_MASKFULL 0x3FFF3FFF803FFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_SHIFT 31U +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_EN 0x0000000080000000ULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TEXAS_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFC0FFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TEXAS_PERF_COUNTER_0 */ +#define ROGUE_CR_TEXAS_PERF_COUNTER_0 0x82D8U +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_JONES_PERF */ +#define ROGUE_CR_JONES_PERF 0x8330U +#define ROGUE_CR_JONES_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_JONES_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_JONES_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_JONES_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_JONES_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_JONES_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_JONES_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_JONES_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_JONES_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_JONES_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_JONES_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_JONES_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_JONES_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_JONES_PERF_SELECT0 */ +#define ROGUE_CR_JONES_PERF_SELECT0 0x8338U +#define ROGUE_CR_JONES_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_JONES_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_JONES_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_JONES_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_JONES_PERF_COUNTER_0 */ +#define ROGUE_CR_JONES_PERF_COUNTER_0 0x8368U +#define ROGUE_CR_JONES_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_JONES_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_JONES_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_BLACKPEARL_PERF */ +#define ROGUE_CR_BLACKPEARL_PERF 0x8400U +#define ROGUE_CR_BLACKPEARL_PERF_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_SHIFT 6U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_EN 0x00000040U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_SHIFT 5U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_EN 0x00000020U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_BLACKPEARL_PERF_SELECT0 */ +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0 0x8408U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MASKFULL 0x3FFF3FFF803FFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_SHIFT 31U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_EN 0x0000000080000000ULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFC0FFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_BLACKPEARL_PERF_COUNTER_0 */ +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0 0x8448U +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PBE_PERF */ +#define ROGUE_CR_PBE_PERF 0x8478U +#define ROGUE_CR_PBE_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_PBE_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_PBE_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_PBE_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_PBE_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_PBE_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_PBE_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_PBE_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_PBE_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_PBE_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_PBE_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_PBE_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_PBE_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_PBE_PERF_SELECT0 */ +#define ROGUE_CR_PBE_PERF_SELECT0 0x8480U +#define ROGUE_CR_PBE_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_PBE_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_PBE_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_PBE_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_PBE_PERF_COUNTER_0 */ +#define ROGUE_CR_PBE_PERF_COUNTER_0 0x84B0U +#define ROGUE_CR_PBE_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PBE_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_PBE_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OCP_REVINFO */ +#define ROGUE_CR_OCP_REVINFO 0x9000U +#define ROGUE_CR_OCP_REVINFO_MASKFULL 0x00000007FFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_SYSBUS_SHIFT 33U +#define ROGUE_CR_OCP_REVINFO_HWINFO_SYSBUS_CLRMSK 0xFFFFFFF9FFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_SHIFT 32U +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_EN 0x0000000100000000ULL +#define ROGUE_CR_OCP_REVINFO_REVISION_SHIFT 0U +#define ROGUE_CR_OCP_REVINFO_REVISION_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_OCP_SYSCONFIG */ +#define ROGUE_CR_OCP_SYSCONFIG 0x9010U +#define ROGUE_CR_OCP_SYSCONFIG_MASKFULL 0x0000000000000FFFULL +#define ROGUE_CR_OCP_SYSCONFIG_DUST2_STANDBY_MODE_SHIFT 10U +#define ROGUE_CR_OCP_SYSCONFIG_DUST2_STANDBY_MODE_CLRMSK 0xFFFFF3FFU +#define ROGUE_CR_OCP_SYSCONFIG_DUST1_STANDBY_MODE_SHIFT 8U +#define ROGUE_CR_OCP_SYSCONFIG_DUST1_STANDBY_MODE_CLRMSK 0xFFFFFCFFU +#define ROGUE_CR_OCP_SYSCONFIG_DUST0_STANDBY_MODE_SHIFT 6U +#define ROGUE_CR_OCP_SYSCONFIG_DUST0_STANDBY_MODE_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_OCP_SYSCONFIG_RASCAL_STANDBYMODE_SHIFT 4U +#define ROGUE_CR_OCP_SYSCONFIG_RASCAL_STANDBYMODE_CLRMSK 0xFFFFFFCFU +#define ROGUE_CR_OCP_SYSCONFIG_STANDBY_MODE_SHIFT 2U +#define ROGUE_CR_OCP_SYSCONFIG_STANDBY_MODE_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_OCP_SYSCONFIG_IDLE_MODE_SHIFT 0U +#define ROGUE_CR_OCP_SYSCONFIG_IDLE_MODE_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_0 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0 0x9020U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_1 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1 0x9028U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_2 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2 0x9030U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_0 */ +#define ROGUE_CR_OCP_IRQSTATUS_0 0x9038U +#define ROGUE_CR_OCP_IRQSTATUS_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_1 */ +#define ROGUE_CR_OCP_IRQSTATUS_1 0x9040U +#define ROGUE_CR_OCP_IRQSTATUS_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_2 */ +#define ROGUE_CR_OCP_IRQSTATUS_2 0x9048U +#define ROGUE_CR_OCP_IRQSTATUS_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_0 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_0 0x9050U +#define ROGUE_CR_OCP_IRQENABLE_SET_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_1 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_1 0x9058U +#define ROGUE_CR_OCP_IRQENABLE_SET_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_2 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_2 0x9060U +#define ROGUE_CR_OCP_IRQENABLE_SET_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_0 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_0 0x9068U +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_1 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_1 0x9070U +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_2 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_2 0x9078U +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQ_EVENT */ +#define ROGUE_CR_OCP_IRQ_EVENT 0x9080U +#define ROGUE_CR_OCP_IRQ_EVENT_MASKFULL 0x00000000000FFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_SHIFT 19U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_EN 0x0000000000080000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_SHIFT 18U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_EN 0x0000000000040000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_SHIFT 17U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_EN 0x0000000000020000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_SHIFT 16U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_EN 0x0000000000010000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_SHIFT 15U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000008000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_SHIFT 14U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_EN 0x0000000000004000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_SHIFT 13U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_EN 0x0000000000002000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_SHIFT 12U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_EN 0x0000000000001000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_SHIFT 11U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000800ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_SHIFT 10U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_EN 0x0000000000000400ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_SHIFT 9U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_EN 0x0000000000000200ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_SHIFT 8U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_EN 0x0000000000000100ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_SHIFT 7U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000080ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_SHIFT 6U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_EN 0x0000000000000040ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_SHIFT 5U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_EN 0x0000000000000020ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_SHIFT 4U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_EN 0x0000000000000010ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_SHIFT 3U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000008ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_SHIFT 2U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_EN 0x0000000000000004ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_SHIFT 1U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_EN 0x0000000000000002ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_SHIFT 0U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_OCP_DEBUG_CONFIG */ +#define ROGUE_CR_OCP_DEBUG_CONFIG 0x9088U +#define ROGUE_CR_OCP_DEBUG_CONFIG_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_SHIFT 0U +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_EN 0x00000001U + +/* Register ROGUE_CR_OCP_DEBUG_STATUS */ +#define ROGUE_CR_OCP_DEBUG_STATUS 0x9090U +#define ROGUE_CR_OCP_DEBUG_STATUS_MASKFULL 0x001F1F77FFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SDISCACK_SHIFT 51U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SDISCACK_CLRMSK 0xFFE7FFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_SHIFT 50U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_EN 0x0004000000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_MCONNECT_SHIFT 48U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_MCONNECT_CLRMSK 0xFFFCFFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SDISCACK_SHIFT 43U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SDISCACK_CLRMSK 0xFFFFE7FFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_SHIFT 42U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_EN 0x0000040000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_MCONNECT_SHIFT 40U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_MCONNECT_CLRMSK 0xFFFFFCFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_SHIFT 38U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_EN 0x0000004000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_SHIFT 37U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_EN 0x0000002000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_SHIFT 36U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_EN 0x0000001000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_SHIFT 34U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_EN 0x0000000400000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_SHIFT 33U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_EN 0x0000000200000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_SHIFT 32U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_EN 0x0000000100000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_SHIFT 31U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_EN 0x0000000080000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_SHIFT 30U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_EN 0x0000000040000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_SHIFT 29U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_EN 0x0000000020000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCACK_SHIFT 27U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCACK_CLRMSK 0xFFFFFFFFE7FFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_SHIFT 26U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_EN 0x0000000004000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MCONNECT_SHIFT 24U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MCONNECT_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_SHIFT 23U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_EN 0x0000000000800000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_SHIFT 22U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_EN 0x0000000000400000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_SHIFT 21U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_EN 0x0000000000200000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCACK_SHIFT 19U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCACK_CLRMSK 0xFFFFFFFFFFE7FFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_SHIFT 18U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_EN 0x0000000000040000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MCONNECT_SHIFT 16U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MCONNECT_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_SHIFT 15U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_EN 0x0000000000008000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_SHIFT 14U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_EN 0x0000000000004000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_SHIFT 13U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_EN 0x0000000000002000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCACK_SHIFT 11U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCACK_CLRMSK 0xFFFFFFFFFFFFE7FFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_SHIFT 10U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_EN 0x0000000000000400ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MCONNECT_SHIFT 8U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MCONNECT_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_SHIFT 7U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_EN 0x0000000000000080ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_SHIFT 6U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_EN 0x0000000000000040ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_SHIFT 5U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_EN 0x0000000000000020ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCACK_SHIFT 3U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCACK_CLRMSK 0xFFFFFFFFFFFFFFE7ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_SHIFT 2U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_EN 0x0000000000000004ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MCONNECT_SHIFT 0U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MCONNECT_CLRMSK 0xFFFFFFFFFFFFFFFCULL + +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_SHIFT 6U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_EN 0x00000040U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_SHIFT 5U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_EN 0x00000020U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_SHIFT 4U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_EN 0x00000010U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_SHIFT 3U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_EN 0x00000008U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_SHIFT 2U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_EN 0x00000004U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_SHIFT 1U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_EN 0x00000002U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_SHIFT 0U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_EN 0x00000001U + +#define ROGUE_CR_BIF_TRUST_DM_MASK 0x0000007FU + +/* Register ROGUE_CR_BIF_TRUST */ +#define ROGUE_CR_BIF_TRUST 0xA000U +#define ROGUE_CR_BIF_TRUST_MASKFULL 0x00000000001FFFFFULL +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_SHIFT 20U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_EN 0x00100000U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_SHIFT 19U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_EN 0x00080000U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_SHIFT 18U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_EN 0x00040000U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_SHIFT 17U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_EN 0x00020000U +#define ROGUE_CR_BIF_TRUST_ENABLE_SHIFT 16U +#define ROGUE_CR_BIF_TRUST_ENABLE_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_BIF_TRUST_ENABLE_EN 0x00010000U +#define ROGUE_CR_BIF_TRUST_DM_TRUSTED_SHIFT 9U +#define ROGUE_CR_BIF_TRUST_DM_TRUSTED_CLRMSK 0xFFFF01FFU +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_SHIFT 8U +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_EN 0x00000100U +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_SHIFT 7U +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_EN 0x00000080U +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_SHIFT 6U +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_EN 0x00000040U +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_SHIFT 5U +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_EN 0x00000020U +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_SHIFT 4U +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_EN 0x00000010U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_SHIFT 3U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_EN 0x00000008U +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_SHIFT 2U +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_EN 0x00000004U +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_SHIFT 1U +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_EN 0x00000002U +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_SHIFT 0U +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_EN 0x00000001U + +/* Register ROGUE_CR_SYS_BUS_SECURE */ +#define ROGUE_CR_SYS_BUS_SECURE 0xA100U +#define ROGUE_CR_SYS_BUS_SECURE__SECR__MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SYS_BUS_SECURE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_SHIFT 0U +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FBA_FC0_CHECKSUM */ +#define ROGUE_CR_FBA_FC0_CHECKSUM 0xD170U +#define ROGUE_CR_FBA_FC0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC1_CHECKSUM */ +#define ROGUE_CR_FBA_FC1_CHECKSUM 0xD178U +#define ROGUE_CR_FBA_FC1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC2_CHECKSUM */ +#define ROGUE_CR_FBA_FC2_CHECKSUM 0xD180U +#define ROGUE_CR_FBA_FC2_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC2_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC2_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC3_CHECKSUM */ +#define ROGUE_CR_FBA_FC3_CHECKSUM 0xD188U +#define ROGUE_CR_FBA_FC3_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC3_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC3_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_CLK_CTRL2 */ +#define ROGUE_CR_CLK_CTRL2 0xD200U +#define ROGUE_CR_CLK_CTRL2_MASKFULL 0x0000000000000F33ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_SHIFT 10U +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_ON 0x0000000000000400ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_AUTO 0x0000000000000800ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_SHIFT 8U +#define ROGUE_CR_CLK_CTRL2_VRDM_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_CLK_CTRL2_VRDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_ON 0x0000000000000100ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_AUTO 0x0000000000000200ULL +#define ROGUE_CR_CLK_CTRL2_SH_SHIFT 4U +#define ROGUE_CR_CLK_CTRL2_SH_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_CLK_CTRL2_SH_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_SH_ON 0x0000000000000010ULL +#define ROGUE_CR_CLK_CTRL2_SH_AUTO 0x0000000000000020ULL +#define ROGUE_CR_CLK_CTRL2_FBA_SHIFT 0U +#define ROGUE_CR_CLK_CTRL2_FBA_CLRMSK 0xFFFFFFFFFFFFFFFCULL +#define ROGUE_CR_CLK_CTRL2_FBA_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_FBA_ON 0x0000000000000001ULL +#define ROGUE_CR_CLK_CTRL2_FBA_AUTO 0x0000000000000002ULL + +/* Register ROGUE_CR_CLK_STATUS2 */ +#define ROGUE_CR_CLK_STATUS2 0xD208U +#define ROGUE_CR_CLK_STATUS2_MASKFULL 0x0000000000000015ULL +#define ROGUE_CR_CLK_STATUS2_VRDM_SHIFT 4U +#define ROGUE_CR_CLK_STATUS2_VRDM_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_STATUS2_VRDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_VRDM_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_STATUS2_SH_SHIFT 2U +#define ROGUE_CR_CLK_STATUS2_SH_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_STATUS2_SH_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_SH_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_STATUS2_FBA_SHIFT 0U +#define ROGUE_CR_CLK_STATUS2_FBA_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_STATUS2_FBA_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_FBA_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_RPM_SHF_FPL */ +#define ROGUE_CR_RPM_SHF_FPL 0xD520U +#define ROGUE_CR_RPM_SHF_FPL_MASKFULL 0x3FFFFFFFFFFFFFFCULL +#define ROGUE_CR_RPM_SHF_FPL_SIZE_SHIFT 40U +#define ROGUE_CR_RPM_SHF_FPL_SIZE_CLRMSK 0xC00000FFFFFFFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_BASE_SHIFT 2U +#define ROGUE_CR_RPM_SHF_FPL_BASE_CLRMSK 0xFFFFFF0000000003ULL +#define ROGUE_CR_RPM_SHF_FPL_BASE_ALIGNSHIFT 2U +#define ROGUE_CR_RPM_SHF_FPL_BASE_ALIGNSIZE 4U + +/* Register ROGUE_CR_RPM_SHF_FPL_READ */ +#define ROGUE_CR_RPM_SHF_FPL_READ 0xD528U +#define ROGUE_CR_RPM_SHF_FPL_READ_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHF_FPL_READ_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHF_FPL_READ_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHF_FPL_WRITE */ +#define ROGUE_CR_RPM_SHF_FPL_WRITE 0xD530U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHG_FPL */ +#define ROGUE_CR_RPM_SHG_FPL 0xD538U +#define ROGUE_CR_RPM_SHG_FPL_MASKFULL 0x3FFFFFFFFFFFFFFCULL +#define ROGUE_CR_RPM_SHG_FPL_SIZE_SHIFT 40U +#define ROGUE_CR_RPM_SHG_FPL_SIZE_CLRMSK 0xC00000FFFFFFFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_BASE_SHIFT 2U +#define ROGUE_CR_RPM_SHG_FPL_BASE_CLRMSK 0xFFFFFF0000000003ULL +#define ROGUE_CR_RPM_SHG_FPL_BASE_ALIGNSHIFT 2U +#define ROGUE_CR_RPM_SHG_FPL_BASE_ALIGNSIZE 4U + +/* Register ROGUE_CR_RPM_SHG_FPL_READ */ +#define ROGUE_CR_RPM_SHG_FPL_READ 0xD540U +#define ROGUE_CR_RPM_SHG_FPL_READ_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHG_FPL_READ_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHG_FPL_READ_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHG_FPL_WRITE */ +#define ROGUE_CR_RPM_SHG_FPL_WRITE 0xD548U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_SH_PERF */ +#define ROGUE_CR_SH_PERF 0xD5F8U +#define ROGUE_CR_SH_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_SH_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_SH_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SH_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_SH_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_SH_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SH_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_SH_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_SH_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SH_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_SH_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_SH_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SH_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_SH_PERF_SELECT0 */ +#define ROGUE_CR_SH_PERF_SELECT0 0xD600U +#define ROGUE_CR_SH_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_SH_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_SH_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_SH_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_SH_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_SH_PERF_COUNTER_0 */ +#define ROGUE_CR_SH_PERF_COUNTER_0 0xD628U +#define ROGUE_CR_SH_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SH_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_SH_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_SHG_CHECKSUM */ +#define ROGUE_CR_SHF_SHG_CHECKSUM 0xD1C0U +#define ROGUE_CR_SHF_SHG_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_SHG_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_SHG_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM */ +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM 0xD1C8U +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_VARY_BIF_CHECKSUM */ +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM 0xD1D0U +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_RPM_BIF_CHECKSUM */ +#define ROGUE_CR_RPM_BIF_CHECKSUM 0xD1D8U +#define ROGUE_CR_RPM_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_RPM_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_RPM_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHG_BIF_CHECKSUM */ +#define ROGUE_CR_SHG_BIF_CHECKSUM 0xD1E0U +#define ROGUE_CR_SHG_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHG_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHG_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHG_FE_BE_CHECKSUM */ +#define ROGUE_CR_SHG_FE_BE_CHECKSUM 0xD1E8U +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register DPX_CR_BF_PERF */ +#define DPX_CR_BF_PERF 0xC458U +#define DPX_CR_BF_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BF_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BF_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BF_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BF_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BF_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BF_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BF_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BF_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BF_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BF_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BF_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BF_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BF_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BF_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BF_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BF_PERF_SELECT0 */ +#define DPX_CR_BF_PERF_SELECT0 0xC460U +#define DPX_CR_BF_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BF_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BF_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BF_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BF_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BF_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BF_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BF_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BF_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BF_PERF_COUNTER_0 */ +#define DPX_CR_BF_PERF_COUNTER_0 0xC488U +#define DPX_CR_BF_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BF_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BF_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_BT_PERF */ +#define DPX_CR_BT_PERF 0xC3D0U +#define DPX_CR_BT_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BT_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BT_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BT_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BT_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BT_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BT_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BT_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BT_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BT_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BT_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BT_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BT_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BT_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BT_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BT_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BT_PERF_SELECT0 */ +#define DPX_CR_BT_PERF_SELECT0 0xC3D8U +#define DPX_CR_BT_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BT_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BT_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BT_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BT_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BT_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BT_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BT_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BT_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BT_PERF_COUNTER_0 */ +#define DPX_CR_BT_PERF_COUNTER_0 0xC420U +#define DPX_CR_BT_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BT_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BT_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_RQ_USC_DEBUG */ +#define DPX_CR_RQ_USC_DEBUG 0xC110U +#define DPX_CR_RQ_USC_DEBUG_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RQ_USC_DEBUG_CHECKSUM_SHIFT 0U +#define DPX_CR_RQ_USC_DEBUG_CHECKSUM_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register DPX_CR_BIF_FAULT_BANK_MMU_STATUS */ +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS 0xC5C8U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_CAT_BASE_SHIFT 12U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_SHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_SHIFT 0U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register DPX_CR_BIF_FAULT_BANK_REQ_STATUS */ +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS 0xC5D0U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_MASKFULL 0x03FFFFFFFFFFFFF0ULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_SHIFT 57U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_EN 0x0200000000000000ULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_SB_SHIFT 44U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_SB_CLRMSK 0xFE000FFFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_ID_SHIFT 40U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_SHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register DPX_CR_BIF_MMU_STATUS */ +#define DPX_CR_BIF_MMU_STATUS 0xC5D8U +#define DPX_CR_BIF_MMU_STATUS_MASKFULL 0x000000000FFFFFF7ULL +#define DPX_CR_BIF_MMU_STATUS_PC_DATA_SHIFT 20U +#define DPX_CR_BIF_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define DPX_CR_BIF_MMU_STATUS_PD_DATA_SHIFT 12U +#define DPX_CR_BIF_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define DPX_CR_BIF_MMU_STATUS_PT_DATA_SHIFT 4U +#define DPX_CR_BIF_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define DPX_CR_BIF_MMU_STATUS_STALLED_SHIFT 2U +#define DPX_CR_BIF_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BIF_MMU_STATUS_STALLED_EN 0x00000004U +#define DPX_CR_BIF_MMU_STATUS_PAUSED_SHIFT 1U +#define DPX_CR_BIF_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BIF_MMU_STATUS_PAUSED_EN 0x00000002U +#define DPX_CR_BIF_MMU_STATUS_BUSY_SHIFT 0U +#define DPX_CR_BIF_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BIF_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register DPX_CR_RT_PERF */ +#define DPX_CR_RT_PERF 0xC700U +#define DPX_CR_RT_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_RT_PERF_CLR_3_SHIFT 4U +#define DPX_CR_RT_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_RT_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_RT_PERF_CLR_2_SHIFT 3U +#define DPX_CR_RT_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_RT_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_RT_PERF_CLR_1_SHIFT 2U +#define DPX_CR_RT_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_RT_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_RT_PERF_CLR_0_SHIFT 1U +#define DPX_CR_RT_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_RT_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_RT_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_RT_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_RT_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_RT_PERF_SELECT0 */ +#define DPX_CR_RT_PERF_SELECT0 0xC708U +#define DPX_CR_RT_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_RT_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_RT_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_RT_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_RT_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_RT_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_RT_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_RT_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_RT_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_RT_PERF_COUNTER_0 */ +#define DPX_CR_RT_PERF_COUNTER_0 0xC730U +#define DPX_CR_RT_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RT_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_RT_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_BX_TU_PERF */ +#define DPX_CR_BX_TU_PERF 0xC908U +#define DPX_CR_BX_TU_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BX_TU_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BX_TU_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BX_TU_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BX_TU_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BX_TU_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BX_TU_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BX_TU_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BX_TU_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BX_TU_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BX_TU_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BX_TU_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BX_TU_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BX_TU_PERF_SELECT0 */ +#define DPX_CR_BX_TU_PERF_SELECT0 0xC910U +#define DPX_CR_BX_TU_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BX_TU_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BX_TU_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BX_TU_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BX_TU_PERF_COUNTER_0 */ +#define DPX_CR_BX_TU_PERF_COUNTER_0 0xC938U +#define DPX_CR_BX_TU_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BX_TU_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BX_TU_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_RS_PDS_RR_CHECKSUM */ +#define DPX_CR_RS_PDS_RR_CHECKSUM 0xC0F0U +#define DPX_CR_RS_PDS_RR_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RS_PDS_RR_CHECKSUM_VALUE_SHIFT 0U +#define DPX_CR_RS_PDS_RR_CHECKSUM_VALUE_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT */ +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT 0xE140U +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_ID_SHIFT 0U +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_ID_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MMU_CBASE_MAPPING */ +#define ROGUE_CR_MMU_CBASE_MAPPING 0xE148U +#define ROGUE_CR_MMU_CBASE_MAPPING_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_SHIFT 0U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_CLRMSK 0xF0000000U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_MMU_FAULT_STATUS */ +#define ROGUE_CR_MMU_FAULT_STATUS 0xE150U +#define ROGUE_CR_MMU_FAULT_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_ADDRESS_SHIFT 28U +#define ROGUE_CR_MMU_FAULT_STATUS_ADDRESS_CLRMSK 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_CONTEXT_SHIFT 20U +#define ROGUE_CR_MMU_FAULT_STATUS_CONTEXT_CLRMSK 0xFFFFFFFFF00FFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_TAG_SB_SHIFT 12U +#define ROGUE_CR_MMU_FAULT_STATUS_TAG_SB_CLRMSK 0xFFFFFFFFFFF00FFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_REQ_ID_SHIFT 6U +#define ROGUE_CR_MMU_FAULT_STATUS_REQ_ID_CLRMSK 0xFFFFFFFFFFFFF03FULL +#define ROGUE_CR_MMU_FAULT_STATUS_LEVEL_SHIFT 4U +#define ROGUE_CR_MMU_FAULT_STATUS_LEVEL_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_SHIFT 3U +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_EN 0x0000000000000008ULL +#define ROGUE_CR_MMU_FAULT_STATUS_TYPE_SHIFT 1U +#define ROGUE_CR_MMU_FAULT_STATUS_TYPE_CLRMSK 0xFFFFFFFFFFFFFFF9ULL +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MMU_FAULT_STATUS_META */ +#define ROGUE_CR_MMU_FAULT_STATUS_META 0xE158U +#define ROGUE_CR_MMU_FAULT_STATUS_META_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_ADDRESS_SHIFT 28U +#define ROGUE_CR_MMU_FAULT_STATUS_META_ADDRESS_CLRMSK 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_CONTEXT_SHIFT 20U +#define ROGUE_CR_MMU_FAULT_STATUS_META_CONTEXT_CLRMSK 0xFFFFFFFFF00FFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_TAG_SB_SHIFT 12U +#define ROGUE_CR_MMU_FAULT_STATUS_META_TAG_SB_CLRMSK 0xFFFFFFFFFFF00FFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_REQ_ID_SHIFT 6U +#define ROGUE_CR_MMU_FAULT_STATUS_META_REQ_ID_CLRMSK 0xFFFFFFFFFFFFF03FULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_LEVEL_SHIFT 4U +#define ROGUE_CR_MMU_FAULT_STATUS_META_LEVEL_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_SHIFT 3U +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_EN 0x0000000000000008ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_TYPE_SHIFT 1U +#define ROGUE_CR_MMU_FAULT_STATUS_META_TYPE_CLRMSK 0xFFFFFFFFFFFFFFF9ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_SHIFT 0U +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC3_CTRL_MISC */ +#define ROGUE_CR_SLC3_CTRL_MISC 0xE200U +#define ROGUE_CR_SLC3_CTRL_MISC_MASKFULL 0x0000000000000107ULL +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_SHIFT 8U +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_EN 0x00000100U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_SHIFT 0U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_CLRMSK 0xFFFFFFF8U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_LINEAR 0x00000000U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_IN_PAGE_HASH 0x00000001U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_FIXED_PVR_HASH 0x00000002U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_SCRAMBLE_PVR_HASH 0x00000003U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_WEAVED_HASH 0x00000004U + +/* Register ROGUE_CR_SLC3_SCRAMBLE */ +#define ROGUE_CR_SLC3_SCRAMBLE 0xE208U +#define ROGUE_CR_SLC3_SCRAMBLE_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE2 */ +#define ROGUE_CR_SLC3_SCRAMBLE2 0xE210U +#define ROGUE_CR_SLC3_SCRAMBLE2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE2_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE2_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE3 */ +#define ROGUE_CR_SLC3_SCRAMBLE3 0xE218U +#define ROGUE_CR_SLC3_SCRAMBLE3_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE3_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE3_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE4 */ +#define ROGUE_CR_SLC3_SCRAMBLE4 0xE260U +#define ROGUE_CR_SLC3_SCRAMBLE4_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE4_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE4_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_STATUS */ +#define ROGUE_CR_SLC3_STATUS 0xE220U +#define ROGUE_CR_SLC3_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_WRITES1_SHIFT 48U +#define ROGUE_CR_SLC3_STATUS_WRITES1_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_WRITES0_SHIFT 32U +#define ROGUE_CR_SLC3_STATUS_WRITES0_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_READS1_SHIFT 16U +#define ROGUE_CR_SLC3_STATUS_READS1_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_SLC3_STATUS_READS0_SHIFT 0U +#define ROGUE_CR_SLC3_STATUS_READS0_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_SLC3_IDLE */ +#define ROGUE_CR_SLC3_IDLE 0xE228U +#define ROGUE_CR_SLC3_IDLE_MASKFULL 0x00000000000FFFFFULL +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST2_SHIFT 18U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST2_CLRMSK 0xFFF3FFFFU +#define ROGUE_CR_SLC3_IDLE_MMU_SHIFT 17U +#define ROGUE_CR_SLC3_IDLE_MMU_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_SLC3_IDLE_MMU_EN 0x00020000U +#define ROGUE_CR_SLC3_IDLE_RDI_SHIFT 16U +#define ROGUE_CR_SLC3_IDLE_RDI_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_SLC3_IDLE_RDI_EN 0x00010000U +#define ROGUE_CR_SLC3_IDLE_IMGBV4_SHIFT 12U +#define ROGUE_CR_SLC3_IDLE_IMGBV4_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_SLC3_IDLE_CACHE_BANKS_SHIFT 4U +#define ROGUE_CR_SLC3_IDLE_CACHE_BANKS_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST_SHIFT 2U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_SHIFT 1U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_EN 0x00000002U +#define ROGUE_CR_SLC3_IDLE_XBAR_SHIFT 0U +#define ROGUE_CR_SLC3_IDLE_XBAR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC3_IDLE_XBAR_EN 0x00000001U + +/* Register ROGUE_CR_SLC3_FAULT_STOP_STATUS */ +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS 0xE248U +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_MASKFULL 0x0000000000001FFFULL +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_BIF_SHIFT 0U +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_BIF_CLRMSK 0xFFFFE000U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_MODE */ +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE 0xF048U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_CLRMSK 0xFFFFFFFCU +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_INDEX 0x00000000U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_INSTANCE 0x00000001U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_LIST 0x00000002U + +/* Register ROGUE_CR_CONTEXT_MAPPING0 */ +#define ROGUE_CR_CONTEXT_MAPPING0 0xF078U +#define ROGUE_CR_CONTEXT_MAPPING0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING0_2D_SHIFT 24U +#define ROGUE_CR_CONTEXT_MAPPING0_2D_CLRMSK 0x00FFFFFFU +#define ROGUE_CR_CONTEXT_MAPPING0_CDM_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING0_CDM_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING0_3D_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING0_3D_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING0_TA_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING0_TA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING1 */ +#define ROGUE_CR_CONTEXT_MAPPING1 0xF080U +#define ROGUE_CR_CONTEXT_MAPPING1_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_CONTEXT_MAPPING1_HOST_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING1_HOST_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING1_TLA_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING1_TLA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING2 */ +#define ROGUE_CR_CONTEXT_MAPPING2 0xF088U +#define ROGUE_CR_CONTEXT_MAPPING2_MASKFULL 0x0000000000FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING2_ALIST0_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING2_ALIST0_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING2_TE0_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING2_TE0_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING2_VCE0_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING2_VCE0_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING3 */ +#define ROGUE_CR_CONTEXT_MAPPING3 0xF090U +#define ROGUE_CR_CONTEXT_MAPPING3_MASKFULL 0x0000000000FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING3_ALIST1_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING3_ALIST1_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING3_TE1_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING3_TE1_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING3_VCE1_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING3_VCE1_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_JONES_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ 0xF098U +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ 0xF0A0U +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_DUST_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ 0xF0A8U +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_CONTEXT_MAPPING4 */ +#define ROGUE_CR_CONTEXT_MAPPING4 0xF210U +#define ROGUE_CR_CONTEXT_MAPPING4_MASKFULL 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_MMU_STACK_SHIFT 40U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_MMU_STACK_CLRMSK 0xFFFF00FFFFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_UFSTACK_SHIFT 32U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_UFSTACK_CLRMSK 0xFFFFFF00FFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_FSTACK_SHIFT 24U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_FSTACK_CLRMSK 0xFFFFFFFF00FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_MMU_STACK_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_MMU_STACK_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_UFSTACK_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_UFSTACK_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_FSTACK_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_FSTACK_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_MULTICORE_GPU */ +#define ROGUE_CR_MULTICORE_GPU 0xF300U +#define ROGUE_CR_MULTICORE_GPU_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_SHIFT 6U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_EN 0x00000040U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_SHIFT 5U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_EN 0x00000020U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_SHIFT 4U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_EN 0x00000010U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_SHIFT 3U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_EN 0x00000008U +#define ROGUE_CR_MULTICORE_GPU_ID_SHIFT 0U +#define ROGUE_CR_MULTICORE_GPU_ID_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_MULTICORE_SYSTEM */ +#define ROGUE_CR_MULTICORE_SYSTEM 0xF308U +#define ROGUE_CR_MULTICORE_SYSTEM_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_MULTICORE_SYSTEM_GPU_COUNT_SHIFT 0U +#define ROGUE_CR_MULTICORE_SYSTEM_GPU_COUNT_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON 0xF310U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON 0xF320U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON 0xF330U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_ECC_RAM_ERR_INJ */ +#define ROGUE_CR_ECC_RAM_ERR_INJ 0xF340U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_EN 0x00000001U + +/* Register ROGUE_CR_ECC_RAM_INIT_KICK */ +#define ROGUE_CR_ECC_RAM_INIT_KICK 0xF348U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_EN 0x00000001U + +/* Register ROGUE_CR_ECC_RAM_INIT_DONE */ +#define ROGUE_CR_ECC_RAM_INIT_DONE 0xF350U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_ENABLE */ +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE 0xF390U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_STATUS */ +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE 0xF398U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_CLEAR */ +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE 0xF3A0U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_MTS_SAFETY_EVENT_ENABLE */ +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE 0xF3D8U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* clang-format on */ + +#endif /* PVR_ROGUE_CR_DEFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h new file mode 100644 index 000000000000..46186b56effc --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_CR_DEFS_CLIENT_H +#define PVR_ROGUE_CR_DEFS_CLIENT_H + +/* clang-format off */ + +/* + * This register controls the anti-aliasing mode of the Tiling Co-Processor, independent control is + * provided in both X & Y axis. + * This register needs to be set based on the ISP Samples Per Pixel a core supports. + * + * When ISP Samples Per Pixel = 1: + * 2xmsaa is achieved by enabling Y - TE does AA on Y plane only + * 4xmsaa is achieved by enabling Y and X - TE does AA on X and Y plane + * 8xmsaa not supported by XE cores + * + * When ISP Samples Per Pixel = 2: + * 2xmsaa is achieved by enabling X2 - does not affect TE + * 4xmsaa is achieved by enabling Y and X2 - TE does AA on Y plane only + * 8xmsaa is achieved by enabling Y, X and X2 - TE does AA on X and Y plane + * 8xmsaa not supported by XE cores + * + * When ISP Samples Per Pixel = 4: + * 2xmsaa is achieved by enabling X2 - does not affect TE + * 4xmsaa is achieved by enabling Y2 and X2 - TE does AA on Y plane only + * 8xmsaa not supported by XE cores + */ +/* Register ROGUE_CR_TE_AA */ +#define ROGUE_CR_TE_AA 0x0C00U +#define ROGUE_CR_TE_AA_MASKFULL 0x000000000000000Full +/* Y2 + * Indicates 4xmsaa when X2 and Y2 are set to 1. This does not affect TE and is only used within + * TPW. + */ +#define ROGUE_CR_TE_AA_Y2_SHIFT 3 +#define ROGUE_CR_TE_AA_Y2_CLRMSK 0xFFFFFFF7 +#define ROGUE_CR_TE_AA_Y2_EN 0x00000008 +/* Y + * Anti-Aliasing in Y Plane Enabled + */ +#define ROGUE_CR_TE_AA_Y_SHIFT 2 +#define ROGUE_CR_TE_AA_Y_CLRMSK 0xFFFFFFFB +#define ROGUE_CR_TE_AA_Y_EN 0x00000004 +/* X + * Anti-Aliasing in X Plane Enabled + */ +#define ROGUE_CR_TE_AA_X_SHIFT 1 +#define ROGUE_CR_TE_AA_X_CLRMSK 0xFFFFFFFD +#define ROGUE_CR_TE_AA_X_EN 0x00000002 +/* X2 + * 2x Anti-Aliasing Enabled, affects PPP only + */ +#define ROGUE_CR_TE_AA_X2_SHIFT (0U) +#define ROGUE_CR_TE_AA_X2_CLRMSK (0xFFFFFFFEU) +#define ROGUE_CR_TE_AA_X2_EN (0x00000001U) + +/* MacroTile Boundaries X Plane */ +/* Register ROGUE_CR_TE_MTILE1 */ +#define ROGUE_CR_TE_MTILE1 0x0C08 +#define ROGUE_CR_TE_MTILE1_MASKFULL 0x0000000007FFFFFFull +/* X1 default: 0x00000004 + * X1 MacroTile boundary, left tile X for second column of macrotiles (16MT mode) - 32 pixels across + * tile + */ +#define ROGUE_CR_TE_MTILE1_X1_SHIFT 18 +#define ROGUE_CR_TE_MTILE1_X1_CLRMSK 0xF803FFFF +/* X2 default: 0x00000008 + * X2 MacroTile boundary, left tile X for third(16MT) column of macrotiles - 32 pixels across tile + */ +#define ROGUE_CR_TE_MTILE1_X2_SHIFT 9U +#define ROGUE_CR_TE_MTILE1_X2_CLRMSK 0xFFFC01FF +/* X3 default: 0x0000000c + * X3 MacroTile boundary, left tile X for fourth column of macrotiles (16MT) - 32 pixels across tile + */ +#define ROGUE_CR_TE_MTILE1_X3_SHIFT 0 +#define ROGUE_CR_TE_MTILE1_X3_CLRMSK 0xFFFFFE00 + +/* MacroTile Boundaries Y Plane. */ +/* Register ROGUE_CR_TE_MTILE2 */ +#define ROGUE_CR_TE_MTILE2 0x0C10 +#define ROGUE_CR_TE_MTILE2_MASKFULL 0x0000000007FFFFFFull +/* Y1 default: 0x00000004 + * X1 MacroTile boundary, ltop tile Y for second column of macrotiles (16MT mode) - 32 pixels tile + * height + */ +#define ROGUE_CR_TE_MTILE2_Y1_SHIFT 18 +#define ROGUE_CR_TE_MTILE2_Y1_CLRMSK 0xF803FFFF +/* Y2 default: 0x00000008 + * X2 MacroTile boundary, top tile Y for third(16MT) column of macrotiles - 32 pixels tile height + */ +#define ROGUE_CR_TE_MTILE2_Y2_SHIFT 9 +#define ROGUE_CR_TE_MTILE2_Y2_CLRMSK 0xFFFC01FF +/* Y3 default: 0x0000000c + * X3 MacroTile boundary, top tile Y for fourth column of macrotiles (16MT) - 32 pixels tile height + */ +#define ROGUE_CR_TE_MTILE2_Y3_SHIFT 0 +#define ROGUE_CR_TE_MTILE2_Y3_CLRMSK 0xFFFFFE00 + +/* + * In order to perform the tiling operation and generate the display list the maximum screen size + * must be configured in terms of the number of tiles in X & Y axis. + */ + +/* Register ROGUE_CR_TE_SCREEN */ +#define ROGUE_CR_TE_SCREEN 0x0C18U +#define ROGUE_CR_TE_SCREEN_MASKFULL 0x00000000001FF1FFull +/* YMAX default: 0x00000010 + * Maximum Y tile address visible on screen, 32 pixel tile height, 16Kx16K max screen size + */ +#define ROGUE_CR_TE_SCREEN_YMAX_SHIFT 12 +#define ROGUE_CR_TE_SCREEN_YMAX_CLRMSK 0xFFE00FFF +/* XMAX default: 0x00000010 + * Maximum X tile address visible on screen, 32 pixel tile width, 16Kx16K max screen size + */ +#define ROGUE_CR_TE_SCREEN_XMAX_SHIFT 0 +#define ROGUE_CR_TE_SCREEN_XMAX_CLRMSK 0xFFFFFE00 + +/* + * In order to perform the tiling operation and generate the display list the maximum screen size + * must be configured in terms of the number of pixels in X & Y axis since this may not be the same + * as the number of tiles defined in the RGX_CR_TE_SCREEN register. + */ +/* Register ROGUE_CR_PPP_SCREEN */ +#define ROGUE_CR_PPP_SCREEN 0x0C98 +#define ROGUE_CR_PPP_SCREEN_MASKFULL 0x000000007FFF7FFFull +/* PIXYMAX + * Screen height in pixels. (16K x 16K max screen size) + */ +#define ROGUE_CR_PPP_SCREEN_PIXYMAX_SHIFT 16 +#define ROGUE_CR_PPP_SCREEN_PIXYMAX_CLRMSK 0x8000FFFF +/* PIXXMAX + * Screen width in pixels.(16K x 16K max screen size) + */ +#define ROGUE_CR_PPP_SCREEN_PIXXMAX_SHIFT 0 +#define ROGUE_CR_PPP_SCREEN_PIXXMAX_CLRMSK 0xFFFF8000 + +/* Register ROGUE_CR_ISP_MTILE_SIZE */ +#define ROGUE_CR_ISP_MTILE_SIZE 0x0F18 +#define ROGUE_CR_ISP_MTILE_SIZE_MASKFULL 0x0000000003FF03FFull +/* X + * Macrotile width, in tiles. A value of zero corresponds to the maximum size + */ +#define ROGUE_CR_ISP_MTILE_SIZE_X_SHIFT 16 +#define ROGUE_CR_ISP_MTILE_SIZE_X_CLRMSK 0xFC00FFFF +#define ROGUE_CR_ISP_MTILE_SIZE_X_ALIGNSHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_X_ALIGNSIZE 1 +/* Y + * Macrotile height, in tiles. A value of zero corresponds to the maximum size + */ +#define ROGUE_CR_ISP_MTILE_SIZE_Y_SHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_CLRMSK 0xFFFFFC00 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_ALIGNSHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_ALIGNSIZE 1 + +/* clang-format on */ + +#endif /* PVR_ROGUE_CR_DEFS_CLIENT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_defs.h new file mode 100644 index 000000000000..932b01686008 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_defs.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_DEFS_H +#define PVR_ROGUE_DEFS_H + +#include "pvr_rogue_cr_defs.h" + +#include + +/* + ****************************************************************************** + * ROGUE Defines + ****************************************************************************** + */ + +#define ROGUE_FW_MAX_NUM_OS (8U) +#define ROGUE_FW_HOST_OS (0U) +#define ROGUE_FW_GUEST_OSID_START (1U) + +#define ROGUE_FW_THREAD_0 (0U) +#define ROGUE_FW_THREAD_1 (1U) + +#define GET_ROGUE_CACHE_LINE_SIZE(x) ((((s32)(x)) > 0) ? ((x) / 8) : (0)) + +#define MAX_HW_GEOM_FRAG_CONTEXTS 2U + +#define ROGUE_CR_CLK_CTRL_ALL_ON \ + (0x5555555555555555ull & ROGUE_CR_CLK_CTRL_MASKFULL) +#define ROGUE_CR_CLK_CTRL_ALL_AUTO \ + (0xaaaaaaaaaaaaaaaaull & ROGUE_CR_CLK_CTRL_MASKFULL) +#define ROGUE_CR_CLK_CTRL2_ALL_ON \ + (0x5555555555555555ull & ROGUE_CR_CLK_CTRL2_MASKFULL) +#define ROGUE_CR_CLK_CTRL2_ALL_AUTO \ + (0xaaaaaaaaaaaaaaaaull & ROGUE_CR_CLK_CTRL2_MASKFULL) + +#define ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN \ + (ROGUE_CR_SOFT_RESET_DUST_A_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_B_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_C_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_D_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_E_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_F_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_G_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_H_CORE_EN) + +/* SOFT_RESET Rascal and DUSTs bits */ +#define ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN \ + (ROGUE_CR_SOFT_RESET_RASCAL_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN) + +/* SOFT_RESET steps as defined in the TRM */ +#define ROGUE_S7_SOFT_RESET_DUSTS (ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN) + +#define ROGUE_S7_SOFT_RESET_JONES \ + (ROGUE_CR_SOFT_RESET_PM_EN | ROGUE_CR_SOFT_RESET_VDM_EN | \ + ROGUE_CR_SOFT_RESET_ISP_EN) + +#define ROGUE_S7_SOFT_RESET_JONES_ALL \ + (ROGUE_S7_SOFT_RESET_JONES | ROGUE_CR_SOFT_RESET_BIF_EN | \ + ROGUE_CR_SOFT_RESET_SLC_EN | ROGUE_CR_SOFT_RESET_GARTEN_EN) + +#define ROGUE_S7_SOFT_RESET2 \ + (ROGUE_CR_SOFT_RESET2_BLACKPEARL_EN | ROGUE_CR_SOFT_RESET2_PIXEL_EN | \ + ROGUE_CR_SOFT_RESET2_CDM_EN | ROGUE_CR_SOFT_RESET2_VERTEX_EN) + +#define ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT (12U) +#define ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE \ + BIT(ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT) + +#define ROGUE_BIF_PM_VIRTUAL_PAGE_ALIGNSHIFT (14U) +#define ROGUE_BIF_PM_VIRTUAL_PAGE_SIZE BIT(ROGUE_BIF_PM_VIRTUAL_PAGE_ALIGNSHIFT) + +#define ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE (16U) + +/* + * To get the number of required Dusts, divide the number of + * clusters by 2 and round up + */ +#define ROGUE_REQ_NUM_DUSTS(CLUSTERS) (((CLUSTERS) + 1U) / 2U) + +/* + * To get the number of required Bernado/Phantom(s), divide + * the number of clusters by 4 and round up + */ +#define ROGUE_REQ_NUM_PHANTOMS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) +#define ROGUE_REQ_NUM_BERNADOS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) +#define ROGUE_REQ_NUM_BLACKPEARLS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) + +/* + * FW MMU contexts + */ +#define MMU_CONTEXT_MAPPING_FWPRIV (0x0) /* FW code/private data */ +#define MMU_CONTEXT_MAPPING_FWIF (0x0) /* Host/FW data */ + +/* + * Utility macros to calculate CAT_BASE register addresses + */ +#define BIF_CAT_BASEX(n) \ + (ROGUE_CR_BIF_CAT_BASE0 + \ + (n) * (ROGUE_CR_BIF_CAT_BASE1 - ROGUE_CR_BIF_CAT_BASE0)) + +#define FWCORE_MEM_CAT_BASEX(n) \ + (ROGUE_CR_FWCORE_MEM_CAT_BASE0 + \ + (n) * (ROGUE_CR_FWCORE_MEM_CAT_BASE1 - \ + ROGUE_CR_FWCORE_MEM_CAT_BASE0)) + +/* + * FWCORE wrapper register defines + */ +#define FWCORE_ADDR_REMAP_CONFIG0_MMU_CONTEXT_SHIFT \ + ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_SHIFT +#define FWCORE_ADDR_REMAP_CONFIG0_MMU_CONTEXT_CLRMSK \ + ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_CLRMSK +#define FWCORE_ADDR_REMAP_CONFIG0_SIZE_ALIGNSHIFT (12U) + +#define ROGUE_MAX_COMPUTE_SHARED_REGISTERS (2 * 1024) +#define ROGUE_MAX_VERTEX_SHARED_REGISTERS 1024 +#define ROGUE_MAX_PIXEL_SHARED_REGISTERS 1024 +#define ROGUE_CSRM_LINE_SIZE_IN_DWORDS (64 * 4 * 4) + +#define ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE 64 +#define ROGUE_CDMCTRL_USC_COMMON_SIZE_UPPER 256 + +/* + * The maximum amount of local memory which can be allocated by a single kernel + * (in dwords/32-bit registers). + * + * ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE is in bytes so we divide by four. + */ +#define ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS ((ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE * \ + ROGUE_CDMCTRL_USC_COMMON_SIZE_UPPER) >> 2) + +/* + ****************************************************************************** + * WA HWBRNs + ****************************************************************************** + */ + +/* GPU CR timer tick in GPU cycles */ +#define ROGUE_CRTIME_TICK_IN_CYCLES (256U) + +/* for nohw multicore return max cores possible to client */ +#define ROGUE_MULTICORE_MAX_NOHW_CORES (4U) + +/* + * If the size of the SLC is less than this value then the TPU bypasses the SLC. + */ +#define ROGUE_TPU_CACHED_SLC_SIZE_THRESHOLD (128U * 1024U) + +/* + * If the size of the SLC is bigger than this value then the TCU must not be + * bypassed in the SLC. + * In XE_MEMORY_HIERARCHY cores, the TCU is bypassed by default. + */ +#define ROGUE_TCU_CACHED_SLC_SIZE_THRESHOLD (32U * 1024U) + +/* + * Register used by the FW to track the current boot stage (not used in MIPS) + */ +#define ROGUE_FW_BOOT_STAGE_REGISTER (ROGUE_CR_POWER_ESTIMATE_RESULT) + +/* + * Virtualisation definitions + */ +#define ROGUE_VIRTUALISATION_REG_SIZE_PER_OS \ + (ROGUE_CR_MTS_SCHEDULE1 - ROGUE_CR_MTS_SCHEDULE) + +/* + * Macro used to indicate which version of HWPerf is active + */ +#define ROGUE_FEATURE_HWPERF_ROGUE + +/* + * Maximum number of cores supported by TRP + */ +#define ROGUE_TRP_MAX_NUM_CORES (4U) + +#endif /* PVR_ROGUE_DEFS_H */ From 7900e00434eda5ebe7e0c6c995f8528929a8182c Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:29 +0000 Subject: [PATCH 1180/7721] drm/imagination: Add firmware and MMU related headers Changes since v8: - Corrected license identifiers Changes since v5: - Split up header commit due to size Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/23ee233dfbe6f2239328f8201fd6d8c1017cea58.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- .../drm/imagination/pvr_rogue_heap_config.h | 113 ++++++ drivers/gpu/drm/imagination/pvr_rogue_meta.h | 356 ++++++++++++++++++ drivers/gpu/drm/imagination/pvr_rogue_mips.h | 335 ++++++++++++++++ .../drm/imagination/pvr_rogue_mips_check.h | 58 +++ .../gpu/drm/imagination/pvr_rogue_mmu_defs.h | 136 +++++++ 5 files changed, 998 insertions(+) create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_heap_config.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_meta.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_mips.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_mips_check.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h diff --git a/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h b/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h new file mode 100644 index 000000000000..684766006703 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_HEAP_CONFIG_H +#define PVR_ROGUE_HEAP_CONFIG_H + +#include + +/* + * ROGUE Device Virtual Address Space Definitions + * + * This file defines the ROGUE virtual address heaps that are used in + * application memory contexts. It also shows where the Firmware memory heap + * fits into this, but the firmware heap is only ever created in the + * kernel driver and never exposed to userspace. + * + * ROGUE_PDSCODEDATA_HEAP_BASE and ROGUE_USCCODE_HEAP_BASE will be programmed, + * on a global basis, into ROGUE_CR_PDS_EXEC_BASE and ROGUE_CR_USC_CODE_BASE_* + * respectively. Therefore if client drivers use multiple configs they must + * still be consistent with their definitions for these heaps. + * + * Base addresses have to be a multiple of 4MiB. + * Heaps must not start at 0x0000000000, as this is reserved for internal + * use within the driver. + * Range comments, those starting in column 0 below are a section heading of + * sorts and are above the heaps in that range. Often this is the reserved + * size of the heap within the range. + */ + +/* 0x00_0000_0000 ************************************************************/ + +/* 0x00_0000_0000 - 0x00_0040_0000 */ +/* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */ + +/* 0x00_0040_0000 - 0x7F_FFC0_0000 **/ +/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED **/ + +/* 0x80_0000_0000 ************************************************************/ + +/* 0x80_0000_0000 - 0x9F_FFFF_FFFF **/ +/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP **/ +#define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull +#define ROGUE_GENERAL_HEAP_SIZE SZ_128G + +/* 0xA0_0000_0000 - 0xAF_FFFF_FFFF */ +/* 640 GiB to 704 GiB, size of 64 GiB : FREE */ + +/* B0_0000_0000 - 0xB7_FFFF_FFFF */ +/* 704 GiB to 736 GiB, size of 32 GiB : FREE */ + +/* 0xB8_0000_0000 - 0xBF_FFFF_FFFF */ +/* 736 GiB to 768 GiB, size of 32 GiB : RESERVED */ + +/* 0xC0_0000_0000 ************************************************************/ + +/* 0xC0_0000_0000 - 0xD9_FFFF_FFFF */ +/* 768 GiB to 872 GiB, size of 104 GiB : FREE */ + +/* 0xDA_0000_0000 - 0xDA_FFFF_FFFF */ +/* 872 GiB to 876 GiB, size of 4 GiB : PDSCODEDATA_HEAP */ +#define ROGUE_PDSCODEDATA_HEAP_BASE 0xDA00000000ull +#define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G + +/* 0xDB_0000_0000 - 0xDB_FFFF_FFFF */ +/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN **/ +/* + * The BRN63142 quirk workaround requires Region Header memory to be at the top + * of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the + * address will avoid aliasing PB addresses. Start at 879.75GiB. Size of 256MiB. + */ +#define ROGUE_RGNHDR_HEAP_BASE 0xDBF0000000ull +#define ROGUE_RGNHDR_HEAP_SIZE SZ_256M + +/* 0xDC_0000_0000 - 0xDF_FFFF_FFFF */ +/* 880 GiB to 896 GiB, size of 16 GiB : FREE */ + +/* 0xE0_0000_0000 - 0xE0_FFFF_FFFF */ +/* 896 GiB to 900 GiB, size of 4 GiB : USCCODE_HEAP */ +#define ROGUE_USCCODE_HEAP_BASE 0xE000000000ull +#define ROGUE_USCCODE_HEAP_SIZE SZ_4G + +/* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */ +/* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */ + +/* 0xE1_C000_000 - 0xE1_FFFF_FFFF */ +/* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */ +#define ROGUE_FW_HEAP_BASE 0xE1C0000000ull + +/* 0xE2_0000_0000 - 0xE3_FFFF_FFFF */ +/* 904 GiB to 912 GiB, size of 8 GiB : FREE */ + +/* 0xE4_0000_0000 - 0xE7_FFFF_FFFF */ +/* 912 GiB to 968 GiB, size of 16 GiB : TRANSFER_FRAG */ +#define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull +#define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G + +/* 0xE8_0000_0000 - 0xF1_FFFF_FFFF */ +/* 928 GiB to 968 GiB, size of 40 GiB : RESERVED */ + +/* 0xF2_0000_0000 - 0xF2_001F_FFFF **/ +/* 968 GiB to 969 GiB, size of 2 MiB : VISTEST_HEAP */ +#define ROGUE_VISTEST_HEAP_BASE 0xF200000000ull +#define ROGUE_VISTEST_HEAP_SIZE SZ_2M + +/* 0xF2_4000_0000 - 0xF2_FFFF_FFFF */ +/* 969 GiB to 972 GiB, size of 3 GiB : FREE */ + +/* 0xF3_0000_0000 - 0xFF_FFFF_FFFF */ +/* 972 GiB to 1024 GiB, size of 52 GiB : FREE */ + +/* 0xFF_FFFF_FFFF ************************************************************/ + +#endif /* PVR_ROGUE_HEAP_CONFIG_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_meta.h b/drivers/gpu/drm/imagination/pvr_rogue_meta.h new file mode 100644 index 000000000000..3020e6582daa --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_meta.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_META_H +#define PVR_ROGUE_META_H + +/***** The META HW register definitions in the file are updated manually *****/ + +#include +#include + +/* + ****************************************************************************** + * META registers and MACROS + ***************************************************************************** + */ +#define META_CR_CTRLREG_BASE(t) (0x04800000U + (0x1000U * (t))) + +#define META_CR_TXPRIVEXT (0x048000E8) +#define META_CR_TXPRIVEXT_MINIM_EN BIT(7) + +#define META_CR_SYSC_JTAG_THREAD (0x04830030) +#define META_CR_SYSC_JTAG_THREAD_PRIV_EN (0x00000004) + +#define META_CR_PERF_COUNT0 (0x0480FFE0) +#define META_CR_PERF_COUNT1 (0x0480FFE8) +#define META_CR_PERF_COUNT_CTRL_SHIFT (28) +#define META_CR_PERF_COUNT_CTRL_MASK (0xF0000000) +#define META_CR_PERF_COUNT_CTRL_DCACHEHITS (8 << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICACHEHITS (9 << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICACHEMISS \ + (0xA << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICORE (0xD << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_THR_SHIFT (24) +#define META_CR_PERF_COUNT_THR_MASK (0x0F000000) +#define META_CR_PERF_COUNT_THR_0 (0x1 << META_CR_PERF_COUNT_THR_SHIFT) +#define META_CR_PERF_COUNT_THR_1 (0x2 << META_CR_PERF_COUNT_THR_1) + +#define META_CR_TxVECINT_BHALT (0x04820500) +#define META_CR_PERF_ICORE0 (0x0480FFD0) +#define META_CR_PERF_ICORE1 (0x0480FFD8) +#define META_CR_PERF_ICORE_DCACHEMISS (0x8) + +#define META_CR_PERF_COUNT(ctrl, thr) \ + ((META_CR_PERF_COUNT_CTRL_##ctrl << META_CR_PERF_COUNT_CTRL_SHIFT) | \ + ((thr) << META_CR_PERF_COUNT_THR_SHIFT)) + +#define META_CR_TXUXXRXDT_OFFSET (META_CR_CTRLREG_BASE(0U) + 0x0000FFF0U) +#define META_CR_TXUXXRXRQ_OFFSET (META_CR_CTRLREG_BASE(0U) + 0x0000FFF8U) + +/* Poll for done. */ +#define META_CR_TXUXXRXRQ_DREADY_BIT (0x80000000U) +/* Set for read. */ +#define META_CR_TXUXXRXRQ_RDnWR_BIT (0x00010000U) +#define META_CR_TXUXXRXRQ_TX_S (12) +#define META_CR_TXUXXRXRQ_RX_S (4) +#define META_CR_TXUXXRXRQ_UXX_S (0) + +/* Internal ctrl regs. */ +#define META_CR_TXUIN_ID (0x0) +/* Data unit regs. */ +#define META_CR_TXUD0_ID (0x1) +/* Data unit regs. */ +#define META_CR_TXUD1_ID (0x2) +/* Address unit regs. */ +#define META_CR_TXUA0_ID (0x3) +/* Address unit regs. */ +#define META_CR_TXUA1_ID (0x4) +/* PC registers. */ +#define META_CR_TXUPC_ID (0x5) + +/* Macros to calculate register access values. */ +#define META_CR_CORE_REG(thr, reg_num, unit) \ + (((u32)(thr) << META_CR_TXUXXRXRQ_TX_S) | \ + ((u32)(reg_num) << META_CR_TXUXXRXRQ_RX_S) | \ + ((u32)(unit) << META_CR_TXUXXRXRQ_UXX_S)) + +#define META_CR_THR0_PC META_CR_CORE_REG(0, 0, META_CR_TXUPC_ID) +#define META_CR_THR0_PCX META_CR_CORE_REG(0, 1, META_CR_TXUPC_ID) +#define META_CR_THR0_SP META_CR_CORE_REG(0, 0, META_CR_TXUA0_ID) + +#define META_CR_THR1_PC META_CR_CORE_REG(1, 0, META_CR_TXUPC_ID) +#define META_CR_THR1_PCX META_CR_CORE_REG(1, 1, META_CR_TXUPC_ID) +#define META_CR_THR1_SP META_CR_CORE_REG(1, 0, META_CR_TXUA0_ID) + +#define SP_ACCESS(thread) META_CR_CORE_REG(thread, 0, META_CR_TXUA0_ID) +#define PC_ACCESS(thread) META_CR_CORE_REG(thread, 0, META_CR_TXUPC_ID) + +#define META_CR_COREREG_ENABLE (0x0000000U) +#define META_CR_COREREG_STATUS (0x0000010U) +#define META_CR_COREREG_DEFR (0x00000A0U) +#define META_CR_COREREG_PRIVEXT (0x00000E8U) + +#define META_CR_T0ENABLE_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_ENABLE) +#define META_CR_T0STATUS_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_STATUS) +#define META_CR_T0DEFR_OFFSET (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_DEFR) +#define META_CR_T0PRIVEXT_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_PRIVEXT) + +#define META_CR_T1ENABLE_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_ENABLE) +#define META_CR_T1STATUS_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_STATUS) +#define META_CR_T1DEFR_OFFSET (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_DEFR) +#define META_CR_T1PRIVEXT_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_PRIVEXT) + +#define META_CR_TXENABLE_ENABLE_BIT (0x00000001U) /* Set if running */ +#define META_CR_TXSTATUS_PRIV (0x00020000U) +#define META_CR_TXPRIVEXT_MINIM (0x00000080U) + +#define META_MEM_GLOBAL_RANGE_BIT (0x80000000U) + +#define META_CR_TXCLKCTRL (0x048000B0) +#define META_CR_TXCLKCTRL_ALL_ON (0x55111111) +#define META_CR_TXCLKCTRL_ALL_AUTO (0xAA222222) + +#define META_CR_MMCU_LOCAL_EBCTRL (0x04830600) +#define META_CR_MMCU_LOCAL_EBCTRL_ICWIN (0x3 << 14) +#define META_CR_MMCU_LOCAL_EBCTRL_DCWIN (0x3 << 6) +#define META_CR_SYSC_DCPART(n) (0x04830200 + (n) * 0x8) +#define META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE (0x1 << 31) +#define META_CR_SYSC_ICPART(n) (0x04830220 + (n) * 0x8) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_OFFSET_TOP_HALF (0x8 << 16) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE (0xF) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE (0x7) +#define META_CR_MMCU_DCACHE_CTRL (0x04830018) +#define META_CR_MMCU_ICACHE_CTRL (0x04830020) +#define META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN (0x1) + +/* + ****************************************************************************** + * META LDR Format + ****************************************************************************** + */ +/* Block header structure. */ +struct rogue_meta_ldr_block_hdr { + u32 dev_id; + u32 sl_code; + u32 sl_data; + u16 pc_ctrl; + u16 crc; +}; + +/* High level data stream block structure. */ +struct rogue_meta_ldr_l1_data_blk { + u16 cmd; + u16 length; + u32 next; + u32 cmd_data[4]; +}; + +/* High level data stream block structure. */ +struct rogue_meta_ldr_l2_data_blk { + u16 tag; + u16 length; + u32 block_data[4]; +}; + +/* Config command structure. */ +struct rogue_meta_ldr_cfg_blk { + u32 type; + u32 block_data[4]; +}; + +/* Block type definitions */ +#define ROGUE_META_LDR_COMMENT_TYPE_MASK (0x0010U) +#define ROGUE_META_LDR_BLK_IS_COMMENT(x) (((x) & ROGUE_META_LDR_COMMENT_TYPE_MASK) != 0U) + +/* + * Command definitions + * Value Name Description + * 0 LoadMem Load memory with binary data. + * 1 LoadCore Load a set of core registers. + * 2 LoadMMReg Load a set of memory mapped registers. + * 3 StartThreads Set each thread PC and SP, then enable threads. + * 4 ZeroMem Zeros a memory region. + * 5 Config Perform a configuration command. + */ +#define ROGUE_META_LDR_CMD_MASK (0x000FU) + +#define ROGUE_META_LDR_CMD_LOADMEM (0x0000U) +#define ROGUE_META_LDR_CMD_LOADCORE (0x0001U) +#define ROGUE_META_LDR_CMD_LOADMMREG (0x0002U) +#define ROGUE_META_LDR_CMD_START_THREADS (0x0003U) +#define ROGUE_META_LDR_CMD_ZEROMEM (0x0004U) +#define ROGUE_META_LDR_CMD_CONFIG (0x0005U) + +/* + * Config Command definitions + * Value Name Description + * 0 Pause Pause for x times 100 instructions + * 1 Read Read a value from register - No value return needed. + * Utilises effects of issuing reads to certain registers + * 2 Write Write to mem location + * 3 MemSet Set mem to value + * 4 MemCheck check mem for specific value. + */ +#define ROGUE_META_LDR_CFG_PAUSE (0x0000) +#define ROGUE_META_LDR_CFG_READ (0x0001) +#define ROGUE_META_LDR_CFG_WRITE (0x0002) +#define ROGUE_META_LDR_CFG_MEMSET (0x0003) +#define ROGUE_META_LDR_CFG_MEMCHECK (0x0004) + +/* + ****************************************************************************** + * ROGUE FW segmented MMU definitions + ****************************************************************************** + */ +/* All threads can access the segment. */ +#define ROGUE_FW_SEGMMU_ALLTHRS (0xf << 8U) +/* Writable. */ +#define ROGUE_FW_SEGMMU_WRITEABLE (0x1U << 1U) +/* All threads can access and writable. */ +#define ROGUE_FW_SEGMMU_ALLTHRS_WRITEABLE \ + (ROGUE_FW_SEGMMU_ALLTHRS | ROGUE_FW_SEGMMU_WRITEABLE) + +/* Direct map region 10 used for mapping GPU memory - max 8MB. */ +#define ROGUE_FW_SEGMMU_DMAP_GPU_ID (10U) +#define ROGUE_FW_SEGMMU_DMAP_GPU_ADDR_START (0x07000000U) +#define ROGUE_FW_SEGMMU_DMAP_GPU_MAX_SIZE (0x00800000U) + +/* Segment IDs. */ +#define ROGUE_FW_SEGMMU_DATA_ID (1U) +#define ROGUE_FW_SEGMMU_BOOTLDR_ID (2U) +#define ROGUE_FW_SEGMMU_TEXT_ID (ROGUE_FW_SEGMMU_BOOTLDR_ID) + +/* + * SLC caching strategy in S7 and volcanic is emitted through the segment MMU. + * All the segments configured through the macro ROGUE_FW_SEGMMU_OUTADDR_TOP are + * CACHED in the SLC. + * The interface has been kept the same to simplify the code changes. + * The bifdm argument is ignored (no longer relevant) in S7 and volcanic. + */ +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(pers, slc_policy, mmu_ctx) \ + ((((u64)((pers) & 0x3)) << 52) | (((u64)((mmu_ctx) & 0xFF)) << 44) | \ + (((u64)((slc_policy) & 0x1)) << 40)) +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC_CACHED(mmu_ctx) \ + ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(0x3, 0x0, mmu_ctx) +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC_UNCACHED(mmu_ctx) \ + ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(0x0, 0x1, mmu_ctx) + +/* + * To configure the Page Catalog and BIF-DM fed into the BIF for Garten + * accesses through this segment. + */ +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_SLC(pc, bifdm) \ + (((u64)((u64)(pc) & 0xFU) << 44U) | ((u64)((u64)(bifdm) & 0xFU) << 40U)) + +#define ROGUE_FW_SEGMMU_META_BIFDM_ID (0x7U) + +/* META segments have 4kB minimum size. */ +#define ROGUE_FW_SEGMMU_ALIGN (0x1000U) + +/* Segmented MMU registers (n = segment id). */ +#define META_CR_MMCU_SEGMENT_N_BASE(n) (0x04850000U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_LIMIT(n) (0x04850004U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_OUTA0(n) (0x04850008U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_OUTA1(n) (0x0485000CU + ((n) * 0x10U)) + +/* + * The following defines must be recalculated if the Meta MMU segments used + * to access Host-FW data are changed + * Current combinations are: + * - SLC uncached, META cached, FW base address 0x70000000 + * - SLC uncached, META uncached, FW base address 0xF0000000 + * - SLC cached, META cached, FW base address 0x10000000 + * - SLC cached, META uncached, FW base address 0x90000000 + */ +#define ROGUE_FW_SEGMMU_DATA_BASE_ADDRESS (0x10000000U) +#define ROGUE_FW_SEGMMU_DATA_META_CACHED (0x0U) +#define ROGUE_FW_SEGMMU_DATA_META_UNCACHED (META_MEM_GLOBAL_RANGE_BIT) +#define ROGUE_FW_SEGMMU_DATA_META_CACHE_MASK (META_MEM_GLOBAL_RANGE_BIT) +/* + * For non-VIVT SLCs the cacheability of the FW data in the SLC is selected in + * the PTEs for the FW data, not in the Meta Segment MMU, which means these + * defines have no real effect in those cases. + */ +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_CACHED (0x0U) +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_UNCACHED (0x60000000U) +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_CACHE_MASK (0x60000000U) + +/* + ****************************************************************************** + * ROGUE FW Bootloader defaults + ****************************************************************************** + */ +#define ROGUE_FW_BOOTLDR_META_ADDR (0x40000000U) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR_0 (0xC0000000U) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR_1 (0x000000E1) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR \ + ((((u64)ROGUE_FW_BOOTLDR_DEVV_ADDR_1) << 32) | \ + ROGUE_FW_BOOTLDR_DEVV_ADDR_0) +#define ROGUE_FW_BOOTLDR_LIMIT (0x1FFFF000) +#define ROGUE_FW_MAX_BOOTLDR_OFFSET (0x1000) + +/* Bootloader configuration offset is in dwords (512 bytes) */ +#define ROGUE_FW_BOOTLDR_CONF_OFFSET (0x80) + +/* + ****************************************************************************** + * ROGUE META Stack + ****************************************************************************** + */ +#define ROGUE_META_STACK_SIZE (0x1000U) + +/* + ****************************************************************************** + * ROGUE META Core memory + ****************************************************************************** + */ +/* Code and data both map to the same physical memory. */ +#define ROGUE_META_COREMEM_CODE_ADDR (0x80000000U) +#define ROGUE_META_COREMEM_DATA_ADDR (0x82000000U) +#define ROGUE_META_COREMEM_OFFSET_MASK (0x01ffffffU) + +#define ROGUE_META_IS_COREMEM_CODE(a, b) \ + ({ \ + u32 _a = (a), _b = (b); \ + ((_a) >= ROGUE_META_COREMEM_CODE_ADDR) && \ + ((_a) < (ROGUE_META_COREMEM_CODE_ADDR + (_b))); \ + }) +#define ROGUE_META_IS_COREMEM_DATA(a, b) \ + ({ \ + u32 _a = (a), _b = (b); \ + ((_a) >= ROGUE_META_COREMEM_DATA_ADDR) && \ + ((_a) < (ROGUE_META_COREMEM_DATA_ADDR + (_b))); \ + }) +/* + ****************************************************************************** + * 2nd thread + ****************************************************************************** + */ +#define ROGUE_FW_THR1_PC (0x18930000) +#define ROGUE_FW_THR1_SP (0x78890000) + +/* + ****************************************************************************** + * META compatibility + ****************************************************************************** + */ + +#define META_CR_CORE_ID (0x04831000) +#define META_CR_CORE_ID_VER_SHIFT (16U) +#define META_CR_CORE_ID_VER_CLRMSK (0XFF00FFFFU) + +#define ROGUE_CR_META_MTP218_CORE_ID_VALUE 0x19 +#define ROGUE_CR_META_MTP219_CORE_ID_VALUE 0x1E +#define ROGUE_CR_META_LTP218_CORE_ID_VALUE 0x1C +#define ROGUE_CR_META_LTP217_CORE_ID_VALUE 0x1F + +#define ROGUE_FW_PROCESSOR_META "META" + +#endif /* PVR_ROGUE_META_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mips.h b/drivers/gpu/drm/imagination/pvr_rogue_mips.h new file mode 100644 index 000000000000..41ed618fda3f --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mips.h @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_MIPS_H +#define PVR_ROGUE_MIPS_H + +#include +#include + +/* Utility defines for memory management. */ +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K (12) +#define ROGUE_MIPSFW_PAGE_SIZE_4K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) +#define ROGUE_MIPSFW_PAGE_MASK_4K (ROGUE_MIPSFW_PAGE_SIZE_4K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K (16) +#define ROGUE_MIPSFW_PAGE_SIZE_64K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K) +#define ROGUE_MIPSFW_PAGE_MASK_64K (ROGUE_MIPSFW_PAGE_SIZE_64K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_256K (18) +#define ROGUE_MIPSFW_PAGE_SIZE_256K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_256K) +#define ROGUE_MIPSFW_PAGE_MASK_256K (ROGUE_MIPSFW_PAGE_SIZE_256K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_1MB (20) +#define ROGUE_MIPSFW_PAGE_SIZE_1MB (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_1MB) +#define ROGUE_MIPSFW_PAGE_MASK_1MB (ROGUE_MIPSFW_PAGE_SIZE_1MB - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_4MB (22) +#define ROGUE_MIPSFW_PAGE_SIZE_4MB (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_4MB) +#define ROGUE_MIPSFW_PAGE_MASK_4MB (ROGUE_MIPSFW_PAGE_SIZE_4MB - 1) +#define ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE (2) +/* log2 page table sizes dependent on FW heap size and page size (for each OS). */ +#define ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_4K(pvr_dev) ((pvr_dev)->fw_dev.fw_heap_info.log2_size - \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K + \ + ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE) +#define ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_64K(pvr_dev) ((pvr_dev)->fw_dev.fw_heap_info.log2_size - \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K + \ + ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE) +/* Maximum number of page table pages (both Host and MIPS pages). */ +#define ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES (4) +/* Total number of TLB entries. */ +#define ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES (16) +/* "Uncached" caching policy. */ +#define ROGUE_MIPSFW_UNCACHED_CACHE_POLICY (2) +/* "Write-back write-allocate" caching policy. */ +#define ROGUE_MIPSFW_WRITEBACK_CACHE_POLICY (3) +/* "Write-through no write-allocate" caching policy. */ +#define ROGUE_MIPSFW_WRITETHROUGH_CACHE_POLICY (1) +/* Cached policy used by MIPS in case of physical bus on 32 bit. */ +#define ROGUE_MIPSFW_CACHED_POLICY (ROGUE_MIPSFW_WRITEBACK_CACHE_POLICY) +/* Cached policy used by MIPS in case of physical bus on more than 32 bit. */ +#define ROGUE_MIPSFW_CACHED_POLICY_ABOVE_32BIT (ROGUE_MIPSFW_WRITETHROUGH_CACHE_POLICY) +/* Total number of Remap entries. */ +#define ROGUE_MIPSFW_NUMBER_OF_REMAP_ENTRIES (2 * ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES) + +/* MIPS EntryLo/PTE format. */ + +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_SHIFT (31U) +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_CLRMSK (0X7FFFFFFF) +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_EN (0X80000000) + +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_SHIFT (30U) +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_CLRMSK (0XBFFFFFFF) +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_EN (0X40000000) + +/* Page Frame Number */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT (6) +#define ROGUE_MIPSFW_ENTRYLO_PFN_ALIGNSHIFT (12) +/* Mask used for the MIPS Page Table in case of physical bus on 32 bit. */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_MASK (0x03FFFFC0) +#define ROGUE_MIPSFW_ENTRYLO_PFN_SIZE (20) +/* Mask used for the MIPS Page Table in case of physical bus on more than 32 bit. */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT (0x3FFFFFC0) +#define ROGUE_MIPSFW_ENTRYLO_PFN_SIZE_ABOVE_32BIT (24) +#define ROGUE_MIPSFW_ADDR_TO_ENTRYLO_PFN_RSHIFT (ROGUE_MIPSFW_ENTRYLO_PFN_ALIGNSHIFT - \ + ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) + +#define ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT (3U) +#define ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_CLRMSK (0XFFFFFFC7) + +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_SHIFT (2U) +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_CLRMSK (0XFFFFFFFB) +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_EN (0X00000004) + +#define ROGUE_MIPSFW_ENTRYLO_VALID_SHIFT (1U) +#define ROGUE_MIPSFW_ENTRYLO_VALID_CLRMSK (0XFFFFFFFD) +#define ROGUE_MIPSFW_ENTRYLO_VALID_EN (0X00000002) + +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_SHIFT (0U) +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_CLRMSK (0XFFFFFFFE) +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN (0X00000001) + +#define ROGUE_MIPSFW_ENTRYLO_DVG (ROGUE_MIPSFW_ENTRYLO_DIRTY_EN | \ + ROGUE_MIPSFW_ENTRYLO_VALID_EN | \ + ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN) +#define ROGUE_MIPSFW_ENTRYLO_UNCACHED (ROGUE_MIPSFW_UNCACHED_CACHE_POLICY << \ + ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT) +#define ROGUE_MIPSFW_ENTRYLO_DVG_UNCACHED (ROGUE_MIPSFW_ENTRYLO_DVG | \ + ROGUE_MIPSFW_ENTRYLO_UNCACHED) + +/* Remap Range Config Addr Out. */ +/* These defines refer to the upper half of the Remap Range Config register. */ +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_MASK (0x0FFFFFF0) +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_SHIFT (4) /* wrt upper half of the register. */ +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_ALIGNSHIFT (12) +#define ROGUE_MIPSFW_ADDR_TO_RR_ADDR_OUT_RSHIFT (ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_ALIGNSHIFT - \ + ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_SHIFT) + +/* + * Pages to trampoline problematic physical addresses: + * - ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN : 0x1FC0_0000 + * - ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN : 0x1FC0_1000 + * - ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN : 0x1FC0_2000 + * - (benign trampoline) : 0x1FC0_3000 + * that would otherwise be erroneously remapped by the MIPS wrapper. + * (see "Firmware virtual layout and remap configuration" section below) + */ + +#define ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES (2) +#define ROGUE_MIPSFW_TRAMPOLINE_NUMPAGES BIT(ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES) +#define ROGUE_MIPSFW_TRAMPOLINE_SIZE (ROGUE_MIPSFW_TRAMPOLINE_NUMPAGES << \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) +#define ROGUE_MIPSFW_TRAMPOLINE_LOG2_SEGMENT_SIZE (ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES + \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) + +#define ROGUE_MIPSFW_TRAMPOLINE_TARGET_PHYS_ADDR (ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN) +#define ROGUE_MIPSFW_TRAMPOLINE_OFFSET(a) ((a) - ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN) + +#define ROGUE_MIPSFW_SENSITIVE_ADDR(a) (ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN == \ + (~((1 << ROGUE_MIPSFW_TRAMPOLINE_LOG2_SEGMENT_SIZE) - 1) \ + & (a))) + +/* Firmware virtual layout and remap configuration. */ +/* + * For each remap region we define: + * - the virtual base used by the Firmware to access code/data through that region + * - the microAptivAP physical address correspondent to the virtual base address, + * used as input address and remapped to the actual physical address + * - log2 of size of the region remapped by the MIPS wrapper, i.e. number of bits from + * the bottom of the base input address that survive onto the output address + * (this defines both the alignment and the maximum size of the remapped region) + * - one or more code/data segments within the remapped region. + */ + +/* Boot remap setup. */ +#define ROGUE_MIPSFW_BOOT_REMAP_VIRTUAL_BASE (0xBFC00000) +#define ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN (0x1FC00000) +#define ROGUE_MIPSFW_BOOT_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_BOOT_NMI_CODE_VIRTUAL_BASE (ROGUE_MIPSFW_BOOT_REMAP_VIRTUAL_BASE) + +/* Data remap setup. */ +#define ROGUE_MIPSFW_DATA_REMAP_VIRTUAL_BASE (0xBFC01000) +#define ROGUE_MIPSFW_DATA_CACHED_REMAP_VIRTUAL_BASE (0x9FC01000) +#define ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN (0x1FC01000) +#define ROGUE_MIPSFW_DATA_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_BOOT_NMI_DATA_VIRTUAL_BASE (ROGUE_MIPSFW_DATA_REMAP_VIRTUAL_BASE) + +/* Code remap setup. */ +#define ROGUE_MIPSFW_CODE_REMAP_VIRTUAL_BASE (0x9FC02000) +#define ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN (0x1FC02000) +#define ROGUE_MIPSFW_CODE_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_EXCEPTIONS_VIRTUAL_BASE (ROGUE_MIPSFW_CODE_REMAP_VIRTUAL_BASE) + +/* Permanent mappings setup. */ +#define ROGUE_MIPSFW_PT_VIRTUAL_BASE (0xCF000000) +#define ROGUE_MIPSFW_REGISTERS_VIRTUAL_BASE (0xCF800000) +#define ROGUE_MIPSFW_STACK_VIRTUAL_BASE (0xCF600000) + +/* Bootloader configuration data. */ +/* + * Bootloader configuration offset (where ROGUE_MIPSFW_BOOT_DATA lives) + * within the bootloader/NMI data page. + */ +#define ROGUE_MIPSFW_BOOTLDR_CONF_OFFSET (0x0) + +/* NMI shared data. */ +/* Base address of the shared data within the bootloader/NMI data page. */ +#define ROGUE_MIPSFW_NMI_SHARED_DATA_BASE (0x100) +/* Size used by Debug dump data. */ +#define ROGUE_MIPSFW_NMI_SHARED_SIZE (0x2B0) +/* Offsets in the NMI shared area in 32-bit words. */ +#define ROGUE_MIPSFW_NMI_SYNC_FLAG_OFFSET (0x0) +#define ROGUE_MIPSFW_NMI_STATE_OFFSET (0x1) +#define ROGUE_MIPSFW_NMI_ERROR_STATE_SET (0x1) + +/* MIPS boot stage. */ +#define ROGUE_MIPSFW_BOOT_STAGE_OFFSET (0x400) + +/* + * MIPS private data in the bootloader data page. + * Memory below this offset is used by the FW only, no interface data allowed. + */ +#define ROGUE_MIPSFW_PRIVATE_DATA_OFFSET (0x800) + +struct rogue_mipsfw_boot_data { + u64 stack_phys_addr; + u64 reg_base; + u64 pt_phys_addr[ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES]; + u32 pt_log2_page_size; + u32 pt_num_pages; + u32 reserved1; + u32 reserved2; +}; + +#define ROGUE_MIPSFW_GET_OFFSET_IN_DWORDS(offset) ((offset) / sizeof(u32)) +#define ROGUE_MIPSFW_GET_OFFSET_IN_QWORDS(offset) ((offset) / sizeof(u64)) + +/* Used for compatibility checks. */ +#define ROGUE_MIPSFW_ARCHTYPE_VER_CLRMSK (0xFFFFE3FFU) +#define ROGUE_MIPSFW_ARCHTYPE_VER_SHIFT (10U) +#define ROGUE_MIPSFW_CORE_ID_VALUE (0x001U) +#define ROGUE_FW_PROCESSOR_MIPS "MIPS" + +/* microAptivAP cache line size. */ +#define ROGUE_MIPSFW_MICROAPTIVEAP_CACHELINE_SIZE (16U) + +/* + * The SOCIF transactions are identified with the top 16 bits of the physical address emitted by + * the MIPS. + */ +#define ROGUE_MIPSFW_WRAPPER_CONFIG_REGBANK_ADDR_ALIGN (16U) + +/* Values to put in the MIPS selectors for performance counters. */ +/* Icache accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ICACHE_ACCESSES_C0 (9U) +/* Icache misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ICACHE_MISSES_C1 (9U) + +/* Dcache accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_DCACHE_ACCESSES_C0 (10U) +/* Dcache misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_DCACHE_MISSES_C1 (11U) + +/* ITLB instruction accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ITLB_INSTR_ACCESSES_C0 (5U) +/* JTLB instruction accesses misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_JTLB_INSTR_MISSES_C1 (7U) + + /* Instructions completed in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_INSTR_COMPLETED_C0 (1U) +/* JTLB data misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_JTLB_DATA_MISSES_C1 (8U) + +/* Shift for the Event field in the MIPS perf ctrl registers. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_EVENT_SHIFT (5U) + +/* Additional flags for performance counters. See MIPS manual for further reference. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_USER_MODE (8U) +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_KERNEL_MODE (2U) +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_EXL (1U) + +#define ROGUE_MIPSFW_C0_NBHWIRQ 8 + +/* Macros to decode C0_Cause register. */ +#define ROGUE_MIPSFW_C0_CAUSE_EXCCODE(cause) (((cause) & 0x7c) >> 2) +#define ROGUE_MIPSFW_C0_CAUSE_EXCCODE_FWERROR 9 +/* Use only when Coprocessor Unusable exception. */ +#define ROGUE_MIPSFW_C0_CAUSE_UNUSABLE_UNIT(cause) (((cause) >> 28) & 0x3) +#define ROGUE_MIPSFW_C0_CAUSE_PENDING_HWIRQ(cause) (((cause) & 0x3fc00) >> 10) +#define ROGUE_MIPSFW_C0_CAUSE_FDCIPENDING BIT(21) +#define ROGUE_MIPSFW_C0_CAUSE_IV BIT(23) +#define ROGUE_MIPSFW_C0_CAUSE_IC BIT(25) +#define ROGUE_MIPSFW_C0_CAUSE_PCIPENDING BIT(26) +#define ROGUE_MIPSFW_C0_CAUSE_TIPENDING BIT(30) +#define ROGUE_MIPSFW_C0_CAUSE_BRANCH_DELAY BIT(31) + +/* Macros to decode C0_Debug register. */ +#define ROGUE_MIPSFW_C0_DEBUG_EXCCODE(debug) (((debug) >> 10) & 0x1f) +#define ROGUE_MIPSFW_C0_DEBUG_DSS BIT(0) +#define ROGUE_MIPSFW_C0_DEBUG_DBP BIT(1) +#define ROGUE_MIPSFW_C0_DEBUG_DDBL BIT(2) +#define ROGUE_MIPSFW_C0_DEBUG_DDBS BIT(3) +#define ROGUE_MIPSFW_C0_DEBUG_DIB BIT(4) +#define ROGUE_MIPSFW_C0_DEBUG_DINT BIT(5) +#define ROGUE_MIPSFW_C0_DEBUG_DIBIMPR BIT(6) +#define ROGUE_MIPSFW_C0_DEBUG_DDBLIMPR BIT(18) +#define ROGUE_MIPSFW_C0_DEBUG_DDBSIMPR BIT(19) +#define ROGUE_MIPSFW_C0_DEBUG_IEXI BIT(20) +#define ROGUE_MIPSFW_C0_DEBUG_DBUSEP BIT(21) +#define ROGUE_MIPSFW_C0_DEBUG_CACHEEP BIT(22) +#define ROGUE_MIPSFW_C0_DEBUG_MCHECKP BIT(23) +#define ROGUE_MIPSFW_C0_DEBUG_IBUSEP BIT(24) +#define ROGUE_MIPSFW_C0_DEBUG_DM BIT(30) +#define ROGUE_MIPSFW_C0_DEBUG_DBD BIT(31) + +/* Macros to decode TLB entries. */ +#define ROGUE_MIPSFW_TLB_GET_MASK(page_mask) (((page_mask) >> 13) & 0XFFFFU) +/* Page size in KB. */ +#define ROGUE_MIPSFW_TLB_GET_PAGE_SIZE(page_mask) ((((page_mask) | 0x1FFF) + 1) >> 11) +/* Page size in KB. */ +#define ROGUE_MIPSFW_TLB_GET_PAGE_MASK(page_size) ((((page_size) << 11) - 1) & ~0x7FF) +#define ROGUE_MIPSFW_TLB_GET_VPN2(entry_hi) ((entry_hi) >> 13) +#define ROGUE_MIPSFW_TLB_GET_COHERENCY(entry_lo) (((entry_lo) >> 3) & 0x7U) +#define ROGUE_MIPSFW_TLB_GET_PFN(entry_lo) (((entry_lo) >> 6) & 0XFFFFFU) +/* GET_PA uses a non-standard PFN mask for 36 bit addresses. */ +#define ROGUE_MIPSFW_TLB_GET_PA(entry_lo) (((u64)(entry_lo) & \ + ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT) << 6) +#define ROGUE_MIPSFW_TLB_GET_INHIBIT(entry_lo) (((entry_lo) >> 30) & 0x3U) +#define ROGUE_MIPSFW_TLB_GET_DGV(entry_lo) ((entry_lo) & 0x7U) +#define ROGUE_MIPSFW_TLB_GLOBAL BIT(0) +#define ROGUE_MIPSFW_TLB_VALID BIT(1) +#define ROGUE_MIPSFW_TLB_DIRTY BIT(2) +#define ROGUE_MIPSFW_TLB_XI BIT(30) +#define ROGUE_MIPSFW_TLB_RI BIT(31) + +#define ROGUE_MIPSFW_REMAP_GET_REGION_SIZE(region_size_encoding) (1 << (((region_size_encoding) \ + + 1) << 1)) + +struct rogue_mips_tlb_entry { + u32 tlb_page_mask; + u32 tlb_hi; + u32 tlb_lo0; + u32 tlb_lo1; +}; + +struct rogue_mips_remap_entry { + u32 remap_addr_in; /* Always 4k aligned. */ + u32 remap_addr_out; /* Always 4k aligned. */ + u32 remap_region_size; +}; + +struct rogue_mips_state { + u32 error_state; /* This must come first in the structure. */ + u32 error_epc; + u32 status_register; + u32 cause_register; + u32 bad_register; + u32 epc; + u32 sp; + u32 debug; + u32 depc; + u32 bad_instr; + u32 unmapped_address; + struct rogue_mips_tlb_entry tlb[ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES]; + struct rogue_mips_remap_entry remap[ROGUE_MIPSFW_NUMBER_OF_REMAP_ENTRIES]; +}; + +#include "pvr_rogue_mips_check.h" + +#endif /* PVR_ROGUE_MIPS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h b/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h new file mode 100644 index 000000000000..824b4bf33ac1 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_MIPS_CHECK_H +#define PVR_ROGUE_MIPS_CHECK_H + +#include + +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) == 0, + "offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_hi) == 4, + "offsetof(struct rogue_mips_tlb_entry, tlb_hi) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo0) == 8, + "offsetof(struct rogue_mips_tlb_entry, tlb_lo0) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo1) == 12, + "offsetof(struct rogue_mips_tlb_entry, tlb_lo1) incorrect"); +static_assert(sizeof(struct rogue_mips_tlb_entry) == 16, + "struct rogue_mips_tlb_entry is incorrect size"); + +static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_in) == 0, + "offsetof(struct rogue_mips_remap_entry, remap_addr_in) incorrect"); +static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_out) == 4, + "offsetof(struct rogue_mips_remap_entry, remap_addr_out) incorrect"); +static_assert(offsetof(struct rogue_mips_remap_entry, remap_region_size) == 8, + "offsetof(struct rogue_mips_remap_entry, remap_region_size) incorrect"); +static_assert(sizeof(struct rogue_mips_remap_entry) == 12, + "struct rogue_mips_remap_entry is incorrect size"); + +static_assert(offsetof(struct rogue_mips_state, error_state) == 0, + "offsetof(struct rogue_mips_state, error_state) incorrect"); +static_assert(offsetof(struct rogue_mips_state, error_epc) == 4, + "offsetof(struct rogue_mips_state, error_epc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, status_register) == 8, + "offsetof(struct rogue_mips_state, status_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, cause_register) == 12, + "offsetof(struct rogue_mips_state, cause_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, bad_register) == 16, + "offsetof(struct rogue_mips_state, bad_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, epc) == 20, + "offsetof(struct rogue_mips_state, epc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, sp) == 24, + "offsetof(struct rogue_mips_state, sp) incorrect"); +static_assert(offsetof(struct rogue_mips_state, debug) == 28, + "offsetof(struct rogue_mips_state, debug) incorrect"); +static_assert(offsetof(struct rogue_mips_state, depc) == 32, + "offsetof(struct rogue_mips_state, depc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, bad_instr) == 36, + "offsetof(struct rogue_mips_state, bad_instr) incorrect"); +static_assert(offsetof(struct rogue_mips_state, unmapped_address) == 40, + "offsetof(struct rogue_mips_state, unmapped_address) incorrect"); +static_assert(offsetof(struct rogue_mips_state, tlb) == 44, + "offsetof(struct rogue_mips_state, tlb) incorrect"); +static_assert(offsetof(struct rogue_mips_state, remap) == 300, + "offsetof(struct rogue_mips_state, remap) incorrect"); +static_assert(sizeof(struct rogue_mips_state) == 684, + "struct rogue_mips_state is incorrect size"); + +#endif /* PVR_ROGUE_MIPS_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h new file mode 100644 index 000000000000..f361ccdd5405 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +/* *** Autogenerated C -- do not edit *** */ + +#ifndef PVR_ROGUE_MMU_DEFS_H +#define PVR_ROGUE_MMU_DEFS_H + +#define ROGUE_MMU_DEFS_REVISION 0 + +#define ROGUE_BIF_DM_ENCODING_VERTEX (0x00000000U) +#define ROGUE_BIF_DM_ENCODING_PIXEL (0x00000001U) +#define ROGUE_BIF_DM_ENCODING_COMPUTE (0x00000002U) +#define ROGUE_BIF_DM_ENCODING_TLA (0x00000003U) +#define ROGUE_BIF_DM_ENCODING_PB_VCE (0x00000004U) +#define ROGUE_BIF_DM_ENCODING_PB_TE (0x00000005U) +#define ROGUE_BIF_DM_ENCODING_META (0x00000007U) +#define ROGUE_BIF_DM_ENCODING_HOST (0x00000008U) +#define ROGUE_BIF_DM_ENCODING_PM_ALIST (0x00000009U) + +#define ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT (30U) +#define ROGUE_MMUCTRL_VADDR_PC_INDEX_CLRMSK (0xFFFFFF003FFFFFFFULL) +#define ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT (21U) +#define ROGUE_MMUCTRL_VADDR_PD_INDEX_CLRMSK (0xFFFFFFFFC01FFFFFULL) +#define ROGUE_MMUCTRL_VADDR_PT_INDEX_SHIFT (12U) +#define ROGUE_MMUCTRL_VADDR_PT_INDEX_CLRMSK (0xFFFFFFFFFFE00FFFULL) + +#define ROGUE_MMUCTRL_ENTRIES_PC_VALUE (0x00000400U) +#define ROGUE_MMUCTRL_ENTRIES_PD_VALUE (0x00000200U) +#define ROGUE_MMUCTRL_ENTRIES_PT_VALUE (0x00000200U) + +#define ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE (0x00000020U) +#define ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE (0x00000040U) +#define ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE (0x00000040U) + +#define ROGUE_MMUCTRL_PAGE_SIZE_MASK (0x00000007U) +#define ROGUE_MMUCTRL_PAGE_SIZE_4KB (0x00000000U) +#define ROGUE_MMUCTRL_PAGE_SIZE_16KB (0x00000001U) +#define ROGUE_MMUCTRL_PAGE_SIZE_64KB (0x00000002U) +#define ROGUE_MMUCTRL_PAGE_SIZE_256KB (0x00000003U) +#define ROGUE_MMUCTRL_PAGE_SIZE_1MB (0x00000004U) +#define ROGUE_MMUCTRL_PAGE_SIZE_2MB (0x00000005U) + +#define ROGUE_MMUCTRL_PAGE_4KB_RANGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PAGE_4KB_RANGE_CLRMSK (0xFFFFFF0000000FFFULL) + +#define ROGUE_MMUCTRL_PAGE_16KB_RANGE_SHIFT (14U) +#define ROGUE_MMUCTRL_PAGE_16KB_RANGE_CLRMSK (0xFFFFFF0000003FFFULL) + +#define ROGUE_MMUCTRL_PAGE_64KB_RANGE_SHIFT (16U) +#define ROGUE_MMUCTRL_PAGE_64KB_RANGE_CLRMSK (0xFFFFFF000000FFFFULL) + +#define ROGUE_MMUCTRL_PAGE_256KB_RANGE_SHIFT (18U) +#define ROGUE_MMUCTRL_PAGE_256KB_RANGE_CLRMSK (0xFFFFFF000003FFFFULL) + +#define ROGUE_MMUCTRL_PAGE_1MB_RANGE_SHIFT (20U) +#define ROGUE_MMUCTRL_PAGE_1MB_RANGE_CLRMSK (0xFFFFFF00000FFFFFULL) + +#define ROGUE_MMUCTRL_PAGE_2MB_RANGE_SHIFT (21U) +#define ROGUE_MMUCTRL_PAGE_2MB_RANGE_CLRMSK (0xFFFFFF00001FFFFFULL) + +#define ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_CLRMSK (0xFFFFFF0000000FFFULL) + +#define ROGUE_MMUCTRL_PT_BASE_16KB_RANGE_SHIFT (10U) +#define ROGUE_MMUCTRL_PT_BASE_16KB_RANGE_CLRMSK (0xFFFFFF00000003FFULL) + +#define ROGUE_MMUCTRL_PT_BASE_64KB_RANGE_SHIFT (8U) +#define ROGUE_MMUCTRL_PT_BASE_64KB_RANGE_CLRMSK (0xFFFFFF00000000FFULL) + +#define ROGUE_MMUCTRL_PT_BASE_256KB_RANGE_SHIFT (6U) +#define ROGUE_MMUCTRL_PT_BASE_256KB_RANGE_CLRMSK (0xFFFFFF000000003FULL) + +#define ROGUE_MMUCTRL_PT_BASE_1MB_RANGE_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_BASE_1MB_RANGE_CLRMSK (0xFFFFFF000000001FULL) + +#define ROGUE_MMUCTRL_PT_BASE_2MB_RANGE_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_BASE_2MB_RANGE_CLRMSK (0xFFFFFF000000001FULL) + +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_SHIFT (62U) +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_CLRMSK (0xBFFFFFFFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_EN (0x4000000000000000ULL) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_HI_SHIFT (40U) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_HI_CLRMSK (0xC00000FFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PT_DATA_PAGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PT_DATA_PAGE_CLRMSK (0xFFFFFF0000000FFFULL) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_LO_SHIFT (6U) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_LO_CLRMSK (0xFFFFFFFFFFFFF03FULL) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFFFFFFFFFFDFULL) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_EN (0x0000000000000020ULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_SHIFT (4U) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_CLRMSK (0xFFFFFFFFFFFFFFEFULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_EN (0x0000000000000010ULL) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_SHIFT (3U) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_CLRMSK (0xFFFFFFFFFFFFFFF7ULL) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_EN (0x0000000000000008ULL) +#define ROGUE_MMUCTRL_PT_DATA_CC_SHIFT (2U) +#define ROGUE_MMUCTRL_PT_DATA_CC_CLRMSK (0xFFFFFFFFFFFFFFFBULL) +#define ROGUE_MMUCTRL_PT_DATA_CC_EN (0x0000000000000004ULL) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_SHIFT (1U) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_CLRMSK (0xFFFFFFFFFFFFFFFDULL) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_EN (0x0000000000000002ULL) +#define ROGUE_MMUCTRL_PT_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PT_DATA_VALID_CLRMSK (0xFFFFFFFFFFFFFFFEULL) +#define ROGUE_MMUCTRL_PT_DATA_VALID_EN (0x0000000000000001ULL) + +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_SHIFT (40U) +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFEFFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_EN (0x0000010000000000ULL) +#define ROGUE_MMUCTRL_PD_DATA_PT_BASE_SHIFT (5U) +#define ROGUE_MMUCTRL_PD_DATA_PT_BASE_CLRMSK (0xFFFFFF000000001FULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_SHIFT (1U) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_CLRMSK (0xFFFFFFFFFFFFFFF1ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_4KB (0x0000000000000000ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_16KB (0x0000000000000002ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_64KB (0x0000000000000004ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_256KB (0x0000000000000006ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_1MB (0x0000000000000008ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_2MB (0x000000000000000aULL) +#define ROGUE_MMUCTRL_PD_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PD_DATA_VALID_CLRMSK (0xFFFFFFFFFFFFFFFEULL) +#define ROGUE_MMUCTRL_PD_DATA_VALID_EN (0x0000000000000001ULL) + +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_SHIFT (4U) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_CLRMSK (0x0000000FU) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSHIFT (12U) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSIZE (4096U) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_SHIFT (1U) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFFFDU) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_EN (0x00000002U) +#define ROGUE_MMUCTRL_PC_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PC_DATA_VALID_CLRMSK (0xFFFFFFFEU) +#define ROGUE_MMUCTRL_PC_DATA_VALID_EN (0x00000001U) + +#endif /* PVR_ROGUE_MMU_DEFS_H */ From a26f067feac1f6142c3ccbaeaee8f84078bca9d4 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:30 +0000 Subject: [PATCH 1181/7721] drm/imagination: Add FWIF headers Changes since v8: - Corrected license identifiers Changes since v7: - Add padding to struct rogue_fwif_ccb_ctl to place read and write offsets in different cache lines Changes since v5: - Split up header commit due to size - Add BRN 71242 to device info Changes since v4: - Add FW header device info Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/aa681533a02bd2d46af17a6a6010f4d6048fbb0a.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/pvr_rogue_fwif.h | 2188 +++++++++++++++++ .../drm/imagination/pvr_rogue_fwif_check.h | 493 ++++ .../drm/imagination/pvr_rogue_fwif_client.h | 373 +++ .../imagination/pvr_rogue_fwif_client_check.h | 133 + .../drm/imagination/pvr_rogue_fwif_common.h | 60 + .../drm/imagination/pvr_rogue_fwif_dev_info.h | 113 + .../pvr_rogue_fwif_resetframework.h | 28 + .../drm/imagination/pvr_rogue_fwif_shared.h | 258 ++ .../imagination/pvr_rogue_fwif_shared_check.h | 108 + .../drm/imagination/pvr_rogue_fwif_stream.h | 78 + 10 files changed, 3832 insertions(+) create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h new file mode 100644 index 000000000000..172886be4c82 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h @@ -0,0 +1,2188 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_H +#define PVR_ROGUE_FWIF_H + +#include +#include +#include +#include +#include + +#include "pvr_rogue_defs.h" +#include "pvr_rogue_fwif_common.h" +#include "pvr_rogue_fwif_shared.h" + +/* + **************************************************************************** + * Logging type + **************************************************************************** + */ +#define ROGUE_FWIF_LOG_TYPE_NONE 0x00000000U +#define ROGUE_FWIF_LOG_TYPE_TRACE 0x00000001U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MAIN 0x00000002U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MTS 0x00000004U +#define ROGUE_FWIF_LOG_TYPE_GROUP_CLEANUP 0x00000008U +#define ROGUE_FWIF_LOG_TYPE_GROUP_CSW 0x00000010U +#define ROGUE_FWIF_LOG_TYPE_GROUP_BIF 0x00000020U +#define ROGUE_FWIF_LOG_TYPE_GROUP_PM 0x00000040U +#define ROGUE_FWIF_LOG_TYPE_GROUP_RTD 0x00000080U +#define ROGUE_FWIF_LOG_TYPE_GROUP_SPM 0x00000100U +#define ROGUE_FWIF_LOG_TYPE_GROUP_POW 0x00000200U +#define ROGUE_FWIF_LOG_TYPE_GROUP_HWR 0x00000400U +#define ROGUE_FWIF_LOG_TYPE_GROUP_HWP 0x00000800U +#define ROGUE_FWIF_LOG_TYPE_GROUP_RPM 0x00001000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_DMA 0x00002000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MISC 0x00004000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_DEBUG 0x80000000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MASK 0x80007FFEU +#define ROGUE_FWIF_LOG_TYPE_MASK 0x80007FFFU + +/* String used in pvrdebug -h output */ +#define ROGUE_FWIF_LOG_GROUPS_STRING_LIST \ + "main,mts,cleanup,csw,bif,pm,rtd,spm,pow,hwr,hwp,rpm,dma,misc,debug" + +/* Table entry to map log group strings to log type value */ +struct rogue_fwif_log_group_map_entry { + const char *log_group_name; + u32 log_group_type; +}; + +/* + **************************************************************************** + * ROGUE FW signature checks + **************************************************************************** + */ +#define ROGUE_FW_SIG_BUFFER_SIZE_MIN (8192) + +#define ROGUE_FWIF_TIMEDIFF_ID ((0x1UL << 28) | ROGUE_CR_TIMER) + +/* + **************************************************************************** + * Trace Buffer + **************************************************************************** + */ + +/* Default size of ROGUE_FWIF_TRACEBUF_SPACE in DWords */ +#define ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS 12000U +#define ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE 200U +#define ROGUE_FW_THREAD_NUM 1U +#define ROGUE_FW_THREAD_MAX 2U + +#define ROGUE_FW_POLL_TYPE_SET 0x80000000U + +struct rogue_fwif_file_info_buf { + char path[ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE]; + char info[ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE]; + u32 line_num; + u32 padding; +} __aligned(8); + +struct rogue_fwif_tracebuf_space { + u32 trace_pointer; + + u32 trace_buffer_fw_addr; + + /* To be used by host when reading from trace buffer */ + u32 *trace_buffer; + + struct rogue_fwif_file_info_buf assert_buf; +} __aligned(8); + +/* Total number of FW fault logs stored */ +#define ROGUE_FWIF_FWFAULTINFO_MAX (8U) + +struct rogue_fw_fault_info { + aligned_u64 cr_timer; + aligned_u64 os_timer; + + u32 data __aligned(8); + u32 reserved; + struct rogue_fwif_file_info_buf fault_buf; +} __aligned(8); + +enum rogue_fwif_pow_state { + ROGUE_FWIF_POW_OFF, /* idle and ready to full power down */ + ROGUE_FWIF_POW_ON, /* running HW commands */ + ROGUE_FWIF_POW_FORCED_IDLE, /* forced idle */ + ROGUE_FWIF_POW_IDLE, /* idle waiting for host handshake */ +}; + +/* Firmware HWR states */ +/* The HW state is ok or locked up */ +#define ROGUE_FWIF_HWR_HARDWARE_OK BIT(0) +/* Tells if a HWR reset is in progress */ +#define ROGUE_FWIF_HWR_RESET_IN_PROGRESS BIT(1) +/* A DM unrelated lockup has been detected */ +#define ROGUE_FWIF_HWR_GENERAL_LOCKUP BIT(3) +/* At least one DM is running without being close to a lockup */ +#define ROGUE_FWIF_HWR_DM_RUNNING_OK BIT(4) +/* At least one DM is close to lockup */ +#define ROGUE_FWIF_HWR_DM_STALLING BIT(5) +/* The FW has faulted and needs to restart */ +#define ROGUE_FWIF_HWR_FW_FAULT BIT(6) +/* The FW has requested the host to restart it */ +#define ROGUE_FWIF_HWR_RESTART_REQUESTED BIT(7) + +#define ROGUE_FWIF_PHR_STATE_SHIFT (8U) +/* The FW has requested the host to restart it, per PHR configuration */ +#define ROGUE_FWIF_PHR_RESTART_REQUESTED ((1) << ROGUE_FWIF_PHR_STATE_SHIFT) +/* A PHR triggered GPU reset has just finished */ +#define ROGUE_FWIF_PHR_RESTART_FINISHED ((2) << ROGUE_FWIF_PHR_STATE_SHIFT) +#define ROGUE_FWIF_PHR_RESTART_MASK \ + (ROGUE_FWIF_PHR_RESTART_REQUESTED | ROGUE_FWIF_PHR_RESTART_FINISHED) + +#define ROGUE_FWIF_PHR_MODE_OFF (0UL) +#define ROGUE_FWIF_PHR_MODE_RD_RESET (1UL) +#define ROGUE_FWIF_PHR_MODE_FULL_RESET (2UL) + +/* Firmware per-DM HWR states */ +/* DM is working if all flags are cleared */ +#define ROGUE_FWIF_DM_STATE_WORKING (0) +/* DM is idle and ready for HWR */ +#define ROGUE_FWIF_DM_STATE_READY_FOR_HWR BIT(0) +/* DM need to skip to next cmd before resuming processing */ +#define ROGUE_FWIF_DM_STATE_NEEDS_SKIP BIT(2) +/* DM need partial render cleanup before resuming processing */ +#define ROGUE_FWIF_DM_STATE_NEEDS_PR_CLEANUP BIT(3) +/* DM need to increment Recovery Count once fully recovered */ +#define ROGUE_FWIF_DM_STATE_NEEDS_TRACE_CLEAR BIT(4) +/* DM was identified as locking up and causing HWR */ +#define ROGUE_FWIF_DM_STATE_GUILTY_LOCKUP BIT(5) +/* DM was innocently affected by another lockup which caused HWR */ +#define ROGUE_FWIF_DM_STATE_INNOCENT_LOCKUP BIT(6) +/* DM was identified as over-running and causing HWR */ +#define ROGUE_FWIF_DM_STATE_GUILTY_OVERRUNING BIT(7) +/* DM was innocently affected by another DM over-running which caused HWR */ +#define ROGUE_FWIF_DM_STATE_INNOCENT_OVERRUNING BIT(8) +/* DM was forced into HWR as it delayed more important workloads */ +#define ROGUE_FWIF_DM_STATE_HARD_CONTEXT_SWITCH BIT(9) +/* DM was forced into HWR due to an uncorrected GPU ECC error */ +#define ROGUE_FWIF_DM_STATE_GPU_ECC_HWR BIT(10) + +/* Firmware's connection state */ +enum rogue_fwif_connection_fw_state { + /* Firmware is offline */ + ROGUE_FW_CONNECTION_FW_OFFLINE = 0, + /* Firmware is initialised */ + ROGUE_FW_CONNECTION_FW_READY, + /* Firmware connection is fully established */ + ROGUE_FW_CONNECTION_FW_ACTIVE, + /* Firmware is clearing up connection data*/ + ROGUE_FW_CONNECTION_FW_OFFLOADING, + ROGUE_FW_CONNECTION_FW_STATE_COUNT +}; + +/* OS' connection state */ +enum rogue_fwif_connection_os_state { + /* OS is offline */ + ROGUE_FW_CONNECTION_OS_OFFLINE = 0, + /* OS's KM driver is setup and waiting */ + ROGUE_FW_CONNECTION_OS_READY, + /* OS connection is fully established */ + ROGUE_FW_CONNECTION_OS_ACTIVE, + ROGUE_FW_CONNECTION_OS_STATE_COUNT +}; + +struct rogue_fwif_os_runtime_flags { + unsigned int os_state : 3; + unsigned int fl_ok : 1; + unsigned int fl_grow_pending : 1; + unsigned int isolated_os : 1; + unsigned int reserved : 26; +}; + +#define PVR_SLR_LOG_ENTRIES 10 +/* MAX_CLIENT_CCB_NAME not visible to this header */ +#define PVR_SLR_LOG_STRLEN 30 + +struct rogue_fwif_slr_entry { + aligned_u64 timestamp; + u32 fw_ctx_addr; + u32 num_ufos; + char ccb_name[PVR_SLR_LOG_STRLEN]; + char padding[2]; +} __aligned(8); + +#define MAX_THREAD_NUM 2 + +/* firmware trace control data */ +struct rogue_fwif_tracebuf { + u32 log_type; + struct rogue_fwif_tracebuf_space tracebuf[MAX_THREAD_NUM]; + /* + * Member initialised only when sTraceBuf is actually allocated (in + * ROGUETraceBufferInitOnDemandResources) + */ + u32 tracebuf_size_in_dwords; + /* Compatibility and other flags */ + u32 tracebuf_flags; +} __aligned(8); + +/* firmware system data shared with the Host driver */ +struct rogue_fwif_sysdata { + /* Configuration flags from host */ + u32 config_flags; + /* Extended configuration flags from host */ + u32 config_flags_ext; + enum rogue_fwif_pow_state pow_state; + u32 hw_perf_ridx; + u32 hw_perf_widx; + u32 hw_perf_wrap_count; + /* Constant after setup, needed in FW */ + u32 hw_perf_size; + /* The number of times the FW drops a packet due to buffer full */ + u32 hw_perf_drop_count; + + /* + * ui32HWPerfUt, ui32FirstDropOrdinal, ui32LastDropOrdinal only valid + * when FW is built with ROGUE_HWPERF_UTILIZATION & + * ROGUE_HWPERF_DROP_TRACKING defined in rogue_fw_hwperf.c + */ + /* Buffer utilisation, high watermark of bytes in use */ + u32 hw_perf_ut; + /* The ordinal of the first packet the FW dropped */ + u32 first_drop_ordinal; + /* The ordinal of the last packet the FW dropped */ + u32 last_drop_ordinal; + /* State flags for each Operating System mirrored from Fw coremem */ + struct rogue_fwif_os_runtime_flags + os_runtime_flags_mirror[ROGUE_FW_MAX_NUM_OS]; + + struct rogue_fw_fault_info fault_info[ROGUE_FWIF_FWFAULTINFO_MAX]; + u32 fw_faults; + u32 cr_poll_addr[MAX_THREAD_NUM]; + u32 cr_poll_mask[MAX_THREAD_NUM]; + u32 cr_poll_count[MAX_THREAD_NUM]; + aligned_u64 start_idle_time; + +#if defined(SUPPORT_ROGUE_FW_STATS_FRAMEWORK) +# define ROGUE_FWIF_STATS_FRAMEWORK_LINESIZE (8) +# define ROGUE_FWIF_STATS_FRAMEWORK_MAX \ + (2048 * ROGUE_FWIF_STATS_FRAMEWORK_LINESIZE) + u32 fw_stats_buf[ROGUE_FWIF_STATS_FRAMEWORK_MAX] __aligned(8); +#endif + u32 hwr_state_flags; + u32 hwr_recovery_flags[PVR_FWIF_DM_MAX]; + /* Compatibility and other flags */ + u32 fw_sys_data_flags; + /* Identify whether MC config is P-P or P-S */ + u32 mc_config; +} __aligned(8); + +/* per-os firmware shared data */ +struct rogue_fwif_osdata { + /* Configuration flags from an OS */ + u32 fw_os_config_flags; + /* Markers to signal that the host should perform a full sync check */ + u32 fw_sync_check_mark; + u32 host_sync_check_mark; + + u32 forced_updates_requested; + u8 slr_log_wp; + struct rogue_fwif_slr_entry slr_log_first; + struct rogue_fwif_slr_entry slr_log[PVR_SLR_LOG_ENTRIES]; + aligned_u64 last_forced_update_time; + + /* Interrupt count from Threads > */ + u32 interrupt_count[MAX_THREAD_NUM]; + u32 kccb_cmds_executed; + u32 power_sync_fw_addr; + /* Compatibility and other flags */ + u32 fw_os_data_flags; + u32 padding; +} __aligned(8); + +/* Firmware trace time-stamp field breakup */ + +/* ROGUE_CR_TIMER register read (48 bits) value*/ +#define ROGUE_FWT_TIMESTAMP_TIME_SHIFT (0U) +#define ROGUE_FWT_TIMESTAMP_TIME_CLRMSK (0xFFFF000000000000ull) + +/* Extra debug-info (16 bits) */ +#define ROGUE_FWT_TIMESTAMP_DEBUG_INFO_SHIFT (48U) +#define ROGUE_FWT_TIMESTAMP_DEBUG_INFO_CLRMSK ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK + +/* Debug-info sub-fields */ +/* + * Bit 0: ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT bit from ROGUE_CR_EVENT_STATUS + * register + */ +#define ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SHIFT (0U) +#define ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SHIFT) + +/* Bit 1: ROGUE_CR_BIF_MMU_ENTRY_PENDING bit from ROGUE_CR_BIF_MMU_ENTRY register */ +#define ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SHIFT (1U) +#define ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SHIFT) + +/* Bit 2: ROGUE_CR_SLAVE_EVENT register is non-zero */ +#define ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SHIFT (2U) +#define ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SHIFT) + +/* Bit 3-15: Unused bits */ + +#define ROGUE_FWT_DEBUG_INFO_STR_MAXLEN 64 +#define ROGUE_FWT_DEBUG_INFO_STR_PREPEND " (debug info: " +#define ROGUE_FWT_DEBUG_INFO_STR_APPEND ")" + +/* + ****************************************************************************** + * HWR Data + ****************************************************************************** + */ +enum rogue_hwrtype { + ROGUE_HWRTYPE_UNKNOWNFAILURE = 0, + ROGUE_HWRTYPE_OVERRUN = 1, + ROGUE_HWRTYPE_POLLFAILURE = 2, + ROGUE_HWRTYPE_BIF0FAULT = 3, + ROGUE_HWRTYPE_BIF1FAULT = 4, + ROGUE_HWRTYPE_TEXASBIF0FAULT = 5, + ROGUE_HWRTYPE_MMUFAULT = 6, + ROGUE_HWRTYPE_MMUMETAFAULT = 7, + ROGUE_HWRTYPE_MIPSTLBFAULT = 8, + ROGUE_HWRTYPE_ECCFAULT = 9, + ROGUE_HWRTYPE_MMURISCVFAULT = 10, +}; + +#define ROGUE_FWIF_HWRTYPE_BIF_BANK_GET(hwr_type) \ + (((hwr_type) == ROGUE_HWRTYPE_BIF0FAULT) ? 0 : 1) + +#define ROGUE_FWIF_HWRTYPE_PAGE_FAULT_GET(hwr_type) \ + ((((hwr_type) == ROGUE_HWRTYPE_BIF0FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_BIF1FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_TEXASBIF0FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMUFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMUMETAFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MIPSTLBFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMURISCVFAULT)) \ + ? true \ + : false) + +struct rogue_bifinfo { + aligned_u64 bif_req_status; + aligned_u64 bif_mmu_status; + aligned_u64 pc_address; /* phys address of the page catalogue */ + aligned_u64 reserved; +}; + +struct rogue_eccinfo { + u32 fault_gpu; +}; + +struct rogue_mmuinfo { + aligned_u64 mmu_status[2]; + aligned_u64 pc_address; /* phys address of the page catalogue */ + aligned_u64 reserved; +}; + +struct rogue_pollinfo { + u32 thread_num; + u32 cr_poll_addr; + u32 cr_poll_mask; + u32 cr_poll_last_value; + aligned_u64 reserved; +} __aligned(8); + +struct rogue_tlbinfo { + u32 bad_addr; + u32 entry_lo; +}; + +struct rogue_hwrinfo { + union { + struct rogue_bifinfo bif_info; + struct rogue_mmuinfo mmu_info; + struct rogue_pollinfo poll_info; + struct rogue_tlbinfo tlb_info; + struct rogue_eccinfo ecc_info; + } hwr_data; + + aligned_u64 cr_timer; + aligned_u64 os_timer; + u32 frame_num; + u32 pid; + u32 active_hwrt_data; + u32 hwr_number; + u32 event_status; + u32 hwr_recovery_flags; + enum rogue_hwrtype hwr_type; + u32 dm; + u32 core_id; + aligned_u64 cr_time_of_kick; + aligned_u64 cr_time_hw_reset_start; + aligned_u64 cr_time_hw_reset_finish; + aligned_u64 cr_time_freelist_ready; + aligned_u64 reserved[2]; +} __aligned(8); + +/* Number of first HWR logs recorded (never overwritten by newer logs) */ +#define ROGUE_FWIF_HWINFO_MAX_FIRST 8U +/* Number of latest HWR logs (older logs are overwritten by newer logs) */ +#define ROGUE_FWIF_HWINFO_MAX_LAST 8U +/* Total number of HWR logs stored in a buffer */ +#define ROGUE_FWIF_HWINFO_MAX \ + (ROGUE_FWIF_HWINFO_MAX_FIRST + ROGUE_FWIF_HWINFO_MAX_LAST) +/* Index of the last log in the HWR log buffer */ +#define ROGUE_FWIF_HWINFO_LAST_INDEX (ROGUE_FWIF_HWINFO_MAX - 1U) + +struct rogue_fwif_hwrinfobuf { + struct rogue_hwrinfo hwr_info[ROGUE_FWIF_HWINFO_MAX]; + u32 hwr_counter; + u32 write_index; + u32 dd_req_count; + u32 hwr_info_buf_flags; /* Compatibility and other flags */ + u32 hwr_dm_locked_up_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_overran_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_recovered_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_false_detect_count[PVR_FWIF_DM_MAX]; +} __aligned(8); + +#define ROGUE_FWIF_CTXSWITCH_PROFILE_FAST_EN (1) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_MEDIUM_EN (2) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_SLOW_EN (3) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_NODELAY_EN (4) + +#define ROGUE_FWIF_CDM_ARBITRATION_TASK_DEMAND_EN (1) +#define ROGUE_FWIF_CDM_ARBITRATION_ROUND_ROBIN_EN (2) + +#define ROGUE_FWIF_ISP_SCHEDMODE_VER1_IPP (1) +#define ROGUE_FWIF_ISP_SCHEDMODE_VER2_ISP (2) +/* + ****************************************************************************** + * ROGUE firmware Init Config Data + ****************************************************************************** + */ + +/* Flag definitions affecting the firmware globally */ +#define ROGUE_FWIF_INICFG_CTXSWITCH_MODE_RAND BIT(0) +#define ROGUE_FWIF_INICFG_CTXSWITCH_SRESET_EN BIT(1) +#define ROGUE_FWIF_INICFG_HWPERF_EN BIT(2) +#define ROGUE_FWIF_INICFG_DM_KILL_MODE_RAND_EN BIT(3) +#define ROGUE_FWIF_INICFG_POW_RASCALDUST BIT(4) +/* Bit 5 is reserved. */ +#define ROGUE_FWIF_INICFG_FBCDC_V3_1_EN BIT(6) +#define ROGUE_FWIF_INICFG_CHECK_MLIST_EN BIT(7) +#define ROGUE_FWIF_INICFG_DISABLE_CLKGATING_EN BIT(8) +/* Bit 9 is reserved. */ +/* Bit 10 is reserved. */ +/* Bit 11 is reserved. */ +#define ROGUE_FWIF_INICFG_REGCONFIG_EN BIT(12) +#define ROGUE_FWIF_INICFG_ASSERT_ON_OUTOFMEMORY BIT(13) +#define ROGUE_FWIF_INICFG_HWP_DISABLE_FILTER BIT(14) +/* Bit 15 is reserved. */ +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT (16) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_FAST \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_FAST_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_MEDIUM \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_MEDIUM_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SLOW \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_SLOW_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_NODELAY \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_NODELAY_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_MASK \ + (7 << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_DISABLE_DM_OVERLAP BIT(19) +#define ROGUE_FWIF_INICFG_ASSERT_ON_HWR_TRIGGER BIT(20) +#define ROGUE_FWIF_INICFG_FABRIC_COHERENCY_ENABLED BIT(21) +#define ROGUE_FWIF_INICFG_VALIDATE_IRQ BIT(22) +#define ROGUE_FWIF_INICFG_DISABLE_PDP_EN BIT(23) +#define ROGUE_FWIF_INICFG_SPU_POWER_STATE_MASK_CHANGE_EN BIT(24) +#define ROGUE_FWIF_INICFG_WORKEST BIT(25) +#define ROGUE_FWIF_INICFG_PDVFS BIT(26) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT (27) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_TASK_DEMAND \ + (ROGUE_FWIF_CDM_ARBITRATION_TASK_DEMAND_EN \ + << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_ROUND_ROBIN \ + (ROGUE_FWIF_CDM_ARBITRATION_ROUND_ROBIN_EN \ + << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_MASK \ + (3 << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT (29) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_NONE (0) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER1_IPP \ + (ROGUE_FWIF_ISP_SCHEDMODE_VER1_IPP \ + << ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER2_ISP \ + (ROGUE_FWIF_ISP_SCHEDMODE_VER2_ISP \ + << ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_MASK \ + (ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER1_IPP | \ + ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER2_ISP) +#define ROGUE_FWIF_INICFG_VALIDATE_SOCUSC_TIMER BIT(31) + +#define ROGUE_FWIF_INICFG_ALL (0xFFFFFFFFU) + +/* Extended Flag definitions affecting the firmware globally */ +#define ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_SHIFT (0) +/* [7] YUV10 override + * [6:4] Quality + * [3] Quality enable + * [2:1] Compression scheme + * [0] Lossy group + */ +#define ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_MASK (0xFF) +#define ROGUE_FWIF_INICFG_EXT_ALL (ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_MASK) + +/* Flag definitions affecting only workloads submitted by a particular OS */ +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_TDM_EN BIT(0) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_GEOM_EN BIT(1) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_FRAG_EN BIT(2) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_CDM_EN BIT(3) + +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_TDM BIT(4) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_GEOM BIT(5) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_FRAG BIT(6) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_CDM BIT(7) + +#define ROGUE_FWIF_INICFG_OS_ALL (0xFF) + +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_DM_ALL \ + (ROGUE_FWIF_INICFG_OS_CTXSWITCH_TDM_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_GEOM_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_FRAG_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_CDM_EN) + +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_CLRMSK \ + ~(ROGUE_FWIF_INICFG_OS_CTXSWITCH_DM_ALL) + +#define ROGUE_FWIF_FILTCFG_TRUNCATE_HALF BIT(3) +#define ROGUE_FWIF_FILTCFG_TRUNCATE_INT BIT(2) +#define ROGUE_FWIF_FILTCFG_NEW_FILTER_MODE BIT(1) + +enum rogue_activepm_conf { + ROGUE_ACTIVEPM_FORCE_OFF = 0, + ROGUE_ACTIVEPM_FORCE_ON = 1, + ROGUE_ACTIVEPM_DEFAULT = 2 +}; + +enum rogue_rd_power_island_conf { + ROGUE_RD_POWER_ISLAND_FORCE_OFF = 0, + ROGUE_RD_POWER_ISLAND_FORCE_ON = 1, + ROGUE_RD_POWER_ISLAND_DEFAULT = 2 +}; + +struct rogue_fw_register_list { + /* Register number */ + u16 reg_num; + /* Indirect register number (or 0 if not used) */ + u16 indirect_reg_num; + /* Start value for indirect register */ + u16 indirect_start_val; + /* End value for indirect register */ + u16 indirect_end_val; +}; + +struct rogue_fwif_dllist_node { + u32 p; + u32 n; +}; + +/* + * This number is used to represent an invalid page catalogue physical address + */ +#define ROGUE_FWIF_INVALID_PC_PHYADDR 0xFFFFFFFFFFFFFFFFLLU + +/* This number is used to represent unallocated page catalog base register */ +#define ROGUE_FW_BIF_INVALID_PCSET 0xFFFFFFFFU + +/* Firmware memory context. */ +struct rogue_fwif_fwmemcontext { + /* device physical address of context's page catalogue */ + aligned_u64 pc_dev_paddr; + /* + * associated page catalog base register (ROGUE_FW_BIF_INVALID_PCSET == + * unallocated) + */ + u32 page_cat_base_reg_set; + /* breakpoint address */ + u32 breakpoint_addr; + /* breakpoint handler address */ + u32 bp_handler_addr; + /* DM and enable control for BP */ + u32 breakpoint_ctl; + /* Compatibility and other flags */ + u32 fw_mem_ctx_flags; + u32 padding; +} __aligned(8); + +/* + * FW context state flags + */ +#define ROGUE_FWIF_CONTEXT_FLAGS_NEED_RESUME (0x00000001U) +#define ROGUE_FWIF_CONTEXT_FLAGS_MC_NEED_RESUME_MASKFULL (0x000000FFU) +#define ROGUE_FWIF_CONTEXT_FLAGS_TDM_HEADER_STALE (0x00000100U) +#define ROGUE_FWIF_CONTEXT_FLAGS_LAST_KICK_SECURE (0x00000200U) + +#define ROGUE_NUM_GEOM_CORES_MAX 4 + +/* + * FW-accessible TA state which must be written out to memory on context store + */ +struct rogue_fwif_geom_ctx_state_per_geom { + /* To store in mid-TA */ + aligned_u64 geom_reg_vdm_call_stack_pointer; + /* Initial value (in case is 'lost' due to a lock-up */ + aligned_u64 geom_reg_vdm_call_stack_pointer_init; + u32 geom_reg_vbs_so_prim[4]; + u16 geom_current_idx; + u16 padding[3]; +} __aligned(8); + +struct rogue_fwif_geom_ctx_state { + /* FW-accessible TA state which must be written out to memory on context store */ + struct rogue_fwif_geom_ctx_state_per_geom geom_core[ROGUE_NUM_GEOM_CORES_MAX]; +} __aligned(8); + +/* + * FW-accessible ISP state which must be written out to memory on context store + */ +struct rogue_fwif_frag_ctx_state { + u32 frag_reg_pm_deallocated_mask_status; + u32 frag_reg_dm_pds_mtilefree_status; + /* Compatibility and other flags */ + u32 ctx_state_flags; + /* + * frag_reg_isp_store should be the last element of the structure as this + * is an array whose size is determined at runtime after detecting the + * ROGUE core + */ + u32 frag_reg_isp_store[]; +} __aligned(8); + +#define ROGUE_FWIF_CTX_USING_BUFFER_A (0) +#define ROGUE_FWIF_CTX_USING_BUFFER_B (1U) + +struct rogue_fwif_compute_ctx_state { + u32 ctx_state_flags; /* Target buffer and other flags */ +}; + +struct rogue_fwif_fwcommoncontext { + /* CCB details for this firmware context */ + u32 ccbctl_fw_addr; /* CCB control */ + u32 ccb_fw_addr; /* CCB base */ + struct rogue_fwif_dma_addr ccb_meta_dma_addr; + + /* Context suspend state */ + /* geom/frag context suspend state, read/written by FW */ + u32 context_state_addr __aligned(8); + + /* Flags e.g. for context switching */ + u32 fw_com_ctx_flags; + u32 priority; + u32 priority_seq_num; + + /* Framework state */ + /* Register updates for Framework */ + u32 rf_cmd_addr __aligned(8); + + /* Statistic updates waiting to be passed back to the host... */ + /* True when some stats are pending */ + bool stats_pending __aligned(4); + /* Number of stores on this context since last update */ + s32 stats_num_stores; + /* Number of OOMs on this context since last update */ + s32 stats_num_out_of_memory; + /* Number of PRs on this context since last update */ + s32 stats_num_partial_renders; + /* Data Master type */ + u32 dm; + /* Device Virtual Address of the signal the context is waiting on */ + aligned_u64 wait_signal_address; + /* List entry for the wait-signal list */ + struct rogue_fwif_dllist_node wait_signal_node __aligned(8); + /* List entry for the buffer stalled list */ + struct rogue_fwif_dllist_node buf_stalled_node __aligned(8); + /* Address of the circular buffer queue pointers */ + aligned_u64 cbuf_queue_ctrl_addr; + + aligned_u64 robustness_address; + /* Max HWR deadline limit in ms */ + u32 max_deadline_ms; + /* Following HWR circular buffer read-offset needs resetting */ + bool read_offset_needs_reset; + + /* List entry for the waiting list */ + struct rogue_fwif_dllist_node waiting_node __aligned(8); + /* List entry for the run list */ + struct rogue_fwif_dllist_node run_node __aligned(8); + /* UFO that last failed (or NULL) */ + struct rogue_fwif_ufo last_failed_ufo; + + /* Memory context */ + u32 fw_mem_context_fw_addr; + + /* References to the host side originators */ + /* the Server Common Context */ + u32 server_common_context_id; + /* associated process ID */ + u32 pid; + + /* True when Geom DM OOM is not allowed */ + bool geom_oom_disabled __aligned(4); +} __aligned(8); + +/* Firmware render context. */ +struct rogue_fwif_fwrendercontext { + /* Geometry firmware context. */ + struct rogue_fwif_fwcommoncontext geom_context; + /* Fragment firmware context. */ + struct rogue_fwif_fwcommoncontext frag_context; + + struct rogue_fwif_static_rendercontext_state static_render_context_state; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; + + /* Compatibility and other flags */ + u32 fw_render_ctx_flags; +} __aligned(8); + +/* Firmware compute context. */ +struct rogue_fwif_fwcomputecontext { + /* Firmware context for the CDM */ + struct rogue_fwif_fwcommoncontext cdm_context; + + struct rogue_fwif_static_computecontext_state + static_compute_context_state; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; + + /* Compatibility and other flags */ + u32 compute_ctx_flags; + + u32 wgp_state; + u32 wgp_checksum; + u32 core_mask_a; + u32 core_mask_b; +} __aligned(8); + +/* Firmware TDM context. */ +struct rogue_fwif_fwtdmcontext { + /* Firmware context for the TDM */ + struct rogue_fwif_fwcommoncontext tdm_context; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; +} __aligned(8); + +/* Firmware TQ3D context. */ +struct rogue_fwif_fwtransfercontext { + /* Firmware context for TQ3D. */ + struct rogue_fwif_fwcommoncontext tq_context; +} __aligned(8); + +/* + ****************************************************************************** + * Defines for CMD_TYPE corruption detection and forward compatibility check + ****************************************************************************** + */ + +/* + * CMD_TYPE 32bit contains: + * 31:16 Reserved for magic value to detect corruption (16 bits) + * 15 Reserved for ROGUE_CCB_TYPE_TASK (1 bit) + * 14:0 Bits available for CMD_TYPEs (15 bits) + */ + +/* Magic value to detect corruption */ +#define ROGUE_CMD_MAGIC_DWORD (0x2ABC) +#define ROGUE_CMD_MAGIC_DWORD_MASK (0xFFFF0000U) +#define ROGUE_CMD_MAGIC_DWORD_SHIFT (16U) +#define ROGUE_CMD_MAGIC_DWORD_SHIFTED \ + (ROGUE_CMD_MAGIC_DWORD << ROGUE_CMD_MAGIC_DWORD_SHIFT) + +/* Kernel CCB control for ROGUE */ +struct rogue_fwif_ccb_ctl { + /* write offset into array of commands (MUST be aligned to 16 bytes!) */ + u32 write_offset; + /* Padding to ensure read and write offsets are in separate cache lines. */ + u8 padding[128 - sizeof(u32)]; + /* read offset into array of commands */ + u32 read_offset; + /* Offset wrapping mask (Total capacity of the CCB - 1) */ + u32 wrap_mask; + /* size of each command in bytes */ + u32 cmd_size; + u32 padding2; +} __aligned(8); + +/* Kernel CCB command structure for ROGUE */ + +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PT (0x1U) /* MMU_CTRL_INVAL_PT_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PD (0x2U) /* MMU_CTRL_INVAL_PD_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PC (0x4U) /* MMU_CTRL_INVAL_PC_EN */ + +/* + * can't use PM_TLB0 bit from BIFPM_CTRL reg because it collides with PT + * bit from BIF_CTRL reg + */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PMTLB (0x10) +/* BIF_CTRL_INVAL_TLB1_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_TLB \ + (ROGUE_FWIF_MMUCACHEDATA_FLAGS_PMTLB | 0x8) +/* MMU_CTRL_INVAL_ALL_CONTEXTS_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_CTX_ALL (0x800) + +/* indicates FW should interrupt the host */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_INTERRUPT (0x4000000U) + +struct rogue_fwif_mmucachedata { + u32 cache_flags; + u32 mmu_cache_sync_fw_addr; + u32 mmu_cache_sync_update_value; +}; + +#define ROGUE_FWIF_BPDATA_FLAGS_ENABLE BIT(0) +#define ROGUE_FWIF_BPDATA_FLAGS_WRITE BIT(1) +#define ROGUE_FWIF_BPDATA_FLAGS_CTL BIT(2) +#define ROGUE_FWIF_BPDATA_FLAGS_REGS BIT(3) + +struct rogue_fwif_bpdata { + /* Memory context */ + u32 fw_mem_context_fw_addr; + /* Breakpoint address */ + u32 bp_addr; + /* Breakpoint handler */ + u32 bp_handler_addr; + /* Breakpoint control */ + u32 bp_dm; + u32 bp_data_flags; + /* Number of temporary registers to overallocate */ + u32 temp_regs; + /* Number of shared registers to overallocate */ + u32 shared_regs; + /* DM associated with the breakpoint */ + u32 dm; +}; + +#define ROGUE_FWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS \ + (ROGUE_FWIF_PRBUFFER_MAXSUPPORTED + 1U) /* +1 is RTDATASET cleanup */ + +struct rogue_fwif_kccb_cmd_kick_data { + /* address of the firmware context */ + u32 context_fw_addr; + /* Client CCB woff update */ + u32 client_woff_update; + /* Client CCB wrap mask update after CCCB growth */ + u32 client_wrap_mask_update; + /* number of CleanupCtl pointers attached */ + u32 num_cleanup_ctl; + /* CleanupCtl structures associated with command */ + u32 cleanup_ctl_fw_addr + [ROGUE_FWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS]; + /* + * offset to the CmdHeader which houses the workload estimation kick + * data. + */ + u32 work_est_cmd_header_offset; +}; + +struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data { + struct rogue_fwif_kccb_cmd_kick_data geom_cmd_kick_data; + struct rogue_fwif_kccb_cmd_kick_data frag_cmd_kick_data; +}; + +struct rogue_fwif_kccb_cmd_force_update_data { + /* address of the firmware context */ + u32 context_fw_addr; + /* Client CCB fence offset */ + u32 ccb_fence_offset; +}; + +enum rogue_fwif_cleanup_type { + /* FW common context cleanup */ + ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT, + /* FW HW RT data cleanup */ + ROGUE_FWIF_CLEANUP_HWRTDATA, + /* FW freelist cleanup */ + ROGUE_FWIF_CLEANUP_FREELIST, + /* FW ZS Buffer cleanup */ + ROGUE_FWIF_CLEANUP_ZSBUFFER, +}; + +struct rogue_fwif_cleanup_request { + /* Cleanup type */ + enum rogue_fwif_cleanup_type cleanup_type; + union { + /* FW common context to cleanup */ + u32 context_fw_addr; + /* HW RT to cleanup */ + u32 hwrt_data_fw_addr; + /* Freelist to cleanup */ + u32 freelist_fw_addr; + /* ZS Buffer to cleanup */ + u32 zs_buffer_fw_addr; + } cleanup_data; +}; + +enum rogue_fwif_power_type { + ROGUE_FWIF_POW_OFF_REQ = 1, + ROGUE_FWIF_POW_FORCED_IDLE_REQ, + ROGUE_FWIF_POW_NUM_UNITS_CHANGE, + ROGUE_FWIF_POW_APM_LATENCY_CHANGE +}; + +enum rogue_fwif_power_force_idle_type { + ROGUE_FWIF_POWER_FORCE_IDLE = 1, + ROGUE_FWIF_POWER_CANCEL_FORCED_IDLE, + ROGUE_FWIF_POWER_HOST_TIMEOUT, +}; + +struct rogue_fwif_power_request { + /* Type of power request */ + enum rogue_fwif_power_type pow_type; + union { + /* Number of active Dusts */ + u32 num_of_dusts; + /* If the operation is mandatory */ + bool forced __aligned(4); + /* + * Type of Request. Consolidating Force Idle, Cancel Forced + * Idle, Host Timeout + */ + enum rogue_fwif_power_force_idle_type pow_request_type; + } power_req_data; +}; + +struct rogue_fwif_slcflushinvaldata { + /* Context to fence on (only useful when bDMContext == TRUE) */ + u32 context_fw_addr; + /* Invalidate the cache as well as flushing */ + bool inval __aligned(4); + /* The data to flush/invalidate belongs to a specific DM context */ + bool dm_context __aligned(4); + /* Optional address of range (only useful when bDMContext == FALSE) */ + aligned_u64 address; + /* Optional size of range (only useful when bDMContext == FALSE) */ + aligned_u64 size; +}; + +enum rogue_fwif_hwperf_update_config { + ROGUE_FWIF_HWPERF_CTRL_TOGGLE = 0, + ROGUE_FWIF_HWPERF_CTRL_SET = 1, + ROGUE_FWIF_HWPERF_CTRL_EMIT_FEATURES_EV = 2 +}; + +struct rogue_fwif_hwperf_ctrl { + enum rogue_fwif_hwperf_update_config opcode; /* Control operation code */ + aligned_u64 mask; /* Mask of events to toggle */ +}; + +struct rogue_fwif_hwperf_config_enable_blks { + /* Number of ROGUE_HWPERF_CONFIG_MUX_CNTBLK in the array */ + u32 num_blocks; + /* Address of the ROGUE_HWPERF_CONFIG_MUX_CNTBLK array */ + u32 block_configs_fw_addr; +}; + +struct rogue_fwif_hwperf_config_da_blks { + /* Number of ROGUE_HWPERF_CONFIG_CNTBLK in the array */ + u32 num_blocks; + /* Address of the ROGUE_HWPERF_CONFIG_CNTBLK array */ + u32 block_configs_fw_addr; +}; + +struct rogue_fwif_coreclkspeedchange_data { + u32 new_clock_speed; /* New clock speed */ +}; + +#define ROGUE_FWIF_HWPERF_CTRL_BLKS_MAX 16 + +struct rogue_fwif_hwperf_ctrl_blks { + bool enable; + /* Number of block IDs in the array */ + u32 num_blocks; + /* Array of ROGUE_HWPERF_CNTBLK_ID values */ + u16 block_ids[ROGUE_FWIF_HWPERF_CTRL_BLKS_MAX]; +}; + +struct rogue_fwif_hwperf_select_custom_cntrs { + u16 custom_block; + u16 num_counters; + u32 custom_counter_ids_fw_addr; +}; + +struct rogue_fwif_zsbuffer_backing_data { + u32 zs_buffer_fw_addr; /* ZS-Buffer FW address */ + + bool done __aligned(4); /* action backing/unbacking succeeded */ +}; + +struct rogue_fwif_freelist_gs_data { + /* Freelist FW address */ + u32 freelist_fw_addr; + /* Amount of the Freelist change */ + u32 delta_pages; + /* New amount of pages on the freelist (including ready pages) */ + u32 new_pages; + /* Number of ready pages to be held in reserve until OOM */ + u32 ready_pages; +}; + +#define MAX_FREELISTS_SIZE 3 +#define MAX_HW_GEOM_FRAG_CONTEXTS_SIZE 3 + +#define ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT \ + (MAX_HW_GEOM_FRAG_CONTEXTS_SIZE * MAX_FREELISTS_SIZE * 2U) +#define ROGUE_FWIF_FREELISTS_RECONSTRUCTION_FAILED_FLAG 0x80000000U + +struct rogue_fwif_freelists_reconstruction_data { + u32 freelist_count; + u32 freelist_ids[ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT]; +}; + +struct rogue_fwif_write_offset_update_data { + /* + * Context to that may need to be resumed following write offset update + */ + u32 context_fw_addr; +} __aligned(8); + +/* + ****************************************************************************** + * Proactive DVFS Structures + ****************************************************************************** + */ +#define NUM_OPP_VALUES 16 + +struct pdvfs_opp { + u32 volt; /* V */ + u32 freq; /* Hz */ +} __aligned(8); + +struct rogue_fwif_pdvfs_opp { + struct pdvfs_opp opp_values[NUM_OPP_VALUES]; + u32 min_opp_point; + u32 max_opp_point; +} __aligned(8); + +struct rogue_fwif_pdvfs_max_freq_data { + u32 max_opp_point; +} __aligned(8); + +struct rogue_fwif_pdvfs_min_freq_data { + u32 min_opp_point; +} __aligned(8); + +/* + ****************************************************************************** + * Register configuration structures + ****************************************************************************** + */ + +#define ROGUE_FWIF_REG_CFG_MAX_SIZE 512 + +enum rogue_fwif_regdata_cmd_type { + ROGUE_FWIF_REGCFG_CMD_ADD = 101, + ROGUE_FWIF_REGCFG_CMD_CLEAR = 102, + ROGUE_FWIF_REGCFG_CMD_ENABLE = 103, + ROGUE_FWIF_REGCFG_CMD_DISABLE = 104 +}; + +enum rogue_fwif_reg_cfg_type { + /* Sidekick power event */ + ROGUE_FWIF_REG_CFG_TYPE_PWR_ON = 0, + /* Rascal / dust power event */ + ROGUE_FWIF_REG_CFG_TYPE_DUST_CHANGE, + /* Geometry kick */ + ROGUE_FWIF_REG_CFG_TYPE_GEOM, + /* Fragment kick */ + ROGUE_FWIF_REG_CFG_TYPE_FRAG, + /* Compute kick */ + ROGUE_FWIF_REG_CFG_TYPE_CDM, + /* TLA kick */ + ROGUE_FWIF_REG_CFG_TYPE_TLA, + /* TDM kick */ + ROGUE_FWIF_REG_CFG_TYPE_TDM, + /* Applies to all types. Keep as last element */ + ROGUE_FWIF_REG_CFG_TYPE_ALL +}; + +struct rogue_fwif_reg_cfg_rec { + u64 sddr; + u64 mask; + u64 value; +}; + +struct rogue_fwif_regconfig_data { + enum rogue_fwif_regdata_cmd_type cmd_type; + enum rogue_fwif_reg_cfg_type reg_config_type; + struct rogue_fwif_reg_cfg_rec reg_config __aligned(8); +}; + +struct rogue_fwif_reg_cfg { + /* + * PDump WRW command write granularity is 32 bits. + * Add padding to ensure array size is 32 bit granular. + */ + u8 num_regs_type[ALIGN((u32)ROGUE_FWIF_REG_CFG_TYPE_ALL, + sizeof(u32))] __aligned(8); + struct rogue_fwif_reg_cfg_rec + reg_configs[ROGUE_FWIF_REG_CFG_MAX_SIZE] __aligned(8); +} __aligned(8); + +enum rogue_fwif_os_state_change { + ROGUE_FWIF_OS_ONLINE = 1, + ROGUE_FWIF_OS_OFFLINE +}; + +struct rogue_fwif_os_state_change_data { + u32 osid; + enum rogue_fwif_os_state_change new_os_state; +} __aligned(8); + +enum rogue_fwif_counter_dump_request { + ROGUE_FWIF_PWR_COUNTER_DUMP_START = 1, + ROGUE_FWIF_PWR_COUNTER_DUMP_STOP, + ROGUE_FWIF_PWR_COUNTER_DUMP_SAMPLE, +}; + +struct rogue_fwif_counter_dump_data { + enum rogue_fwif_counter_dump_request counter_dump_request; +} __aligned(8); + +enum rogue_fwif_kccb_cmd_type { + /* Common commands */ + ROGUE_FWIF_KCCB_CMD_KICK = 101U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_KCCB_CMD_MMUCACHE = 102U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_KCCB_CMD_BP = 103U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* SLC flush and invalidation request */ + ROGUE_FWIF_KCCB_CMD_SLCFLUSHINVAL = 105U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Requests cleanup of a FW resource (type specified in the command + * data) + */ + ROGUE_FWIF_KCCB_CMD_CLEANUP = 106U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Power request */ + ROGUE_FWIF_KCCB_CMD_POW = 107U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Backing for on-demand ZS-Buffer done */ + ROGUE_FWIF_KCCB_CMD_ZSBUFFER_BACKING_UPDATE = + 108U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Unbacking for on-demand ZS-Buffer done */ + ROGUE_FWIF_KCCB_CMD_ZSBUFFER_UNBACKING_UPDATE = + 109U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Freelist Grow done */ + ROGUE_FWIF_KCCB_CMD_FREELIST_GROW_UPDATE = + 110U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Freelists Reconstruction done */ + ROGUE_FWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE = + 112U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Informs the firmware that the host has added more data to a CDM2 + * Circular Buffer + */ + ROGUE_FWIF_KCCB_CMD_NOTIFY_WRITE_OFFSET_UPDATE = + 114U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Health check request */ + ROGUE_FWIF_KCCB_CMD_HEALTH_CHECK = 115U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Forcing signalling of all unmet UFOs for a given CCB offset */ + ROGUE_FWIF_KCCB_CMD_FORCE_UPDATE = 116U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* There is a geometry and a fragment command in this single kick */ + ROGUE_FWIF_KCCB_CMD_COMBINED_GEOM_FRAG_KICK = 117U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Informs the FW that a Guest OS has come online / offline. */ + ROGUE_FWIF_KCCB_CMD_OS_ONLINE_STATE_CONFIGURE = 118U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Commands only permitted to the native or host OS */ + ROGUE_FWIF_KCCB_CMD_REGCONFIG = 200U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure HWPerf events (to be generated) and HWPerf buffer address (if required) */ + ROGUE_FWIF_KCCB_CMD_HWPERF_UPDATE_CONFIG = 201U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Enable or disable multiple HWPerf blocks (reusing existing configuration) */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CTRL_BLKS = 203U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Core clock speed change event */ + ROGUE_FWIF_KCCB_CMD_CORECLKSPEEDCHANGE = 204U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* + * Ask the firmware to update its cached ui32LogType value from the (shared) + * tracebuf control structure + */ + ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE = 206U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Set a maximum frequency/OPP point */ + ROGUE_FWIF_KCCB_CMD_PDVFS_LIMIT_MAX_FREQ = 207U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Changes the relative scheduling priority for a particular OSid. It can + * only be serviced for the Host DDK + */ + ROGUE_FWIF_KCCB_CMD_OSID_PRIORITY_CHANGE = 208U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Set or clear firmware state flags */ + ROGUE_FWIF_KCCB_CMD_STATEFLAGS_CTRL = 209U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Set a minimum frequency/OPP point */ + ROGUE_FWIF_KCCB_CMD_PDVFS_LIMIT_MIN_FREQ = 212U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure Periodic Hardware Reset behaviour */ + ROGUE_FWIF_KCCB_CMD_PHR_CFG = 213U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure Safety Firmware Watchdog */ + ROGUE_FWIF_KCCB_CMD_WDG_CFG = 215U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Controls counter dumping in the FW */ + ROGUE_FWIF_KCCB_CMD_COUNTER_DUMP = 216U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure, clear and enable multiple HWPerf blocks */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CONFIG_ENABLE_BLKS = 217U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure the custom counters for HWPerf */ + ROGUE_FWIF_KCCB_CMD_HWPERF_SELECT_CUSTOM_CNTRS = 218U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure directly addressable counters for HWPerf */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CONFIG_BLKS = 220U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, +}; + +#define ROGUE_FWIF_LAST_ALLOWED_GUEST_KCCB_CMD \ + (ROGUE_FWIF_KCCB_CMD_REGCONFIG - 1) + +/* Kernel CCB command packet */ +struct rogue_fwif_kccb_cmd { + /* Command type */ + enum rogue_fwif_kccb_cmd_type cmd_type; + /* Compatibility and other flags */ + u32 kccb_flags; + + /* + * NOTE: Make sure that uCmdData is the last member of this struct + * This is to calculate actual command size for device mem copy. + * (Refer ROGUEGetCmdMemCopySize()) + */ + union { + /* Data for Kick command */ + struct rogue_fwif_kccb_cmd_kick_data cmd_kick_data; + /* Data for combined geom/frag Kick command */ + struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data + combined_geom_frag_cmd_kick_data; + /* Data for MMU cache command */ + struct rogue_fwif_mmucachedata mmu_cache_data; + /* Data for Breakpoint Commands */ + struct rogue_fwif_bpdata bp_data; + /* Data for SLC Flush/Inval commands */ + struct rogue_fwif_slcflushinvaldata slc_flush_inval_data; + /* Data for cleanup commands */ + struct rogue_fwif_cleanup_request cleanup_data; + /* Data for power request commands */ + struct rogue_fwif_power_request pow_data; + /* Data for HWPerf control command */ + struct rogue_fwif_hwperf_ctrl hw_perf_ctrl; + /* + * Data for HWPerf configure, clear and enable performance + * counter block command + */ + struct rogue_fwif_hwperf_config_enable_blks + hw_perf_cfg_enable_blks; + /* + * Data for HWPerf enable or disable performance counter block + * commands + */ + struct rogue_fwif_hwperf_ctrl_blks hw_perf_ctrl_blks; + /* Data for HWPerf configure the custom counters to read */ + struct rogue_fwif_hwperf_select_custom_cntrs + hw_perf_select_cstm_cntrs; + /* Data for HWPerf configure Directly Addressable blocks */ + struct rogue_fwif_hwperf_config_da_blks hw_perf_cfg_da_blks; + /* Data for core clock speed change */ + struct rogue_fwif_coreclkspeedchange_data + core_clk_speed_change_data; + /* Feedback for Z/S Buffer backing/unbacking */ + struct rogue_fwif_zsbuffer_backing_data zs_buffer_backing_data; + /* Feedback for Freelist grow/shrink */ + struct rogue_fwif_freelist_gs_data free_list_gs_data; + /* Feedback for Freelists reconstruction*/ + struct rogue_fwif_freelists_reconstruction_data + free_lists_reconstruction_data; + /* Data for custom register configuration */ + struct rogue_fwif_regconfig_data reg_config_data; + /* Data for informing the FW about the write offset update */ + struct rogue_fwif_write_offset_update_data + write_offset_update_data; + /* Data for setting the max frequency/OPP */ + struct rogue_fwif_pdvfs_max_freq_data pdvfs_max_freq_data; + /* Data for setting the min frequency/OPP */ + struct rogue_fwif_pdvfs_min_freq_data pdvfs_min_freq_data; + /* Data for updating the Guest Online states */ + struct rogue_fwif_os_state_change_data cmd_os_online_state_data; + /* Dev address for TBI buffer allocated on demand */ + u32 tbi_buffer_fw_addr; + /* Data for dumping of register ranges */ + struct rogue_fwif_counter_dump_data counter_dump_config_data; + /* Data for signalling all unmet fences for a given CCB */ + struct rogue_fwif_kccb_cmd_force_update_data force_update_data; + } cmd_data __aligned(8); +} __aligned(8); + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_fwif_kccb_cmd); + +/* + ****************************************************************************** + * Firmware CCB command structure for ROGUE + ****************************************************************************** + */ + +struct rogue_fwif_fwccb_cmd_zsbuffer_backing_data { + u32 zs_buffer_id; +}; + +struct rogue_fwif_fwccb_cmd_freelist_gs_data { + u32 freelist_id; +}; + +struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { + u32 freelist_count; + u32 hwr_counter; + u32 freelist_ids[ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT]; +}; + +/* 1 if a page fault happened */ +#define ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_PF BIT(0) +/* 1 if applicable to all contexts */ +#define ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_ALL_CTXS BIT(1) + +struct rogue_fwif_fwccb_cmd_context_reset_data { + /* Context affected by the reset */ + u32 server_common_context_id; + /* Reason for reset */ + enum rogue_context_reset_reason reset_reason; + /* Data Master affected by the reset */ + u32 dm; + /* Job ref running at the time of reset */ + u32 reset_job_ref; + /* ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG bitfield */ + u32 flags; + /* At what page catalog address */ + aligned_u64 pc_address; + /* Page fault address (only when applicable) */ + aligned_u64 fault_address; +}; + +struct rogue_fwif_fwccb_cmd_fw_pagefault_data { + /* Page fault address */ + u64 fw_fault_addr; +}; + +enum rogue_fwif_fwccb_cmd_type { + /* Requests ZSBuffer to be backed with physical pages */ + ROGUE_FWIF_FWCCB_CMD_ZSBUFFER_BACKING = 101U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests ZSBuffer to be unbacked */ + ROGUE_FWIF_FWCCB_CMD_ZSBUFFER_UNBACKING = 102U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand freelist grow/shrink */ + ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW = 103U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests freelists reconstruction */ + ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION = + 104U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Notifies host of a HWR event on a context */ + ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_NOTIFICATION = + 105U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand debug dump */ + ROGUE_FWIF_FWCCB_CMD_DEBUG_DUMP = 106U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand update on process stats */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_STATS = 107U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + ROGUE_FWIF_FWCCB_CMD_CORE_CLK_RATE_CHANGE = + 108U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_FWCCB_CMD_REQUEST_GPU_RESTART = + 109U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Notifies host of a FW pagefault */ + ROGUE_FWIF_FWCCB_CMD_CONTEXT_FW_PF_NOTIFICATION = + 112U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, +}; + +enum rogue_fwif_fwccb_cmd_update_stats_type { + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32TotalNumPartialRenders stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_PARTIAL_RENDERS = 1, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32TotalNumOutOfMemory stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_OUT_OF_MEMORY, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumGeomStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_GEOM_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumFragStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_FRAG_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumCDMStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_CDM_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumTDMStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_TDM_STORES +}; + +struct rogue_fwif_fwccb_cmd_update_stats_data { + /* Element to update */ + enum rogue_fwif_fwccb_cmd_update_stats_type element_to_update; + /* The pid of the process whose stats are being updated */ + u32 pid_owner; + /* Adjustment to be made to the statistic */ + s32 adjustment_value; +}; + +struct rogue_fwif_fwccb_cmd_core_clk_rate_change_data { + u32 core_clk_rate; +} __aligned(8); + +struct rogue_fwif_fwccb_cmd { + /* Command type */ + enum rogue_fwif_fwccb_cmd_type cmd_type; + /* Compatibility and other flags */ + u32 fwccb_flags; + + union { + /* Data for Z/S-Buffer on-demand (un)backing*/ + struct rogue_fwif_fwccb_cmd_zsbuffer_backing_data + cmd_zs_buffer_backing; + /* Data for on-demand freelist grow/shrink */ + struct rogue_fwif_fwccb_cmd_freelist_gs_data cmd_free_list_gs; + /* Data for freelists reconstruction */ + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data + cmd_freelists_reconstruction; + /* Data for context reset notification */ + struct rogue_fwif_fwccb_cmd_context_reset_data + cmd_context_reset_notification; + /* Data for updating process stats */ + struct rogue_fwif_fwccb_cmd_update_stats_data + cmd_update_stats_data; + struct rogue_fwif_fwccb_cmd_core_clk_rate_change_data + cmd_core_clk_rate_change; + struct rogue_fwif_fwccb_cmd_fw_pagefault_data cmd_fw_pagefault; + } cmd_data __aligned(8); +} __aligned(8); + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_fwif_fwccb_cmd); + +/* + ****************************************************************************** + * Workload estimation Firmware CCB command structure for ROGUE + ****************************************************************************** + */ +struct rogue_fwif_workest_fwccb_cmd { + /* Index for return data array */ + u16 return_data_index; + /* The cycles the workload took on the hardware */ + u32 cycles_taken; +}; + +/* + ****************************************************************************** + * Client CCB commands for ROGUE + ****************************************************************************** + */ + +/* + * Required memory alignment for 64-bit variables accessible by Meta + * (The gcc meta aligns 64-bit variables to 64-bit; therefore, memory shared + * between the host and meta that contains 64-bit variables has to maintain + * this alignment) + */ +#define ROGUE_FWIF_FWALLOC_ALIGN sizeof(u64) + +#define ROGUE_CCB_TYPE_TASK BIT(15) +#define ROGUE_CCB_FWALLOC_ALIGN(size) \ + (((size) + (ROGUE_FWIF_FWALLOC_ALIGN - 1)) & \ + ~(ROGUE_FWIF_FWALLOC_ALIGN - 1)) + +#define ROGUE_FWIF_CCB_CMD_TYPE_GEOM \ + (201U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_3D \ + (202U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FRAG \ + (203U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR \ + (204U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_CDM \ + (205U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_TDM \ + (206U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FBSC_INVALIDATE \ + (207U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_2D \ + (208U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_PRE_TIMESTAMP \ + (209U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_NULL \ + (210U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_ABORT \ + (211U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) + +/* Leave a gap between CCB specific commands and generic commands */ +#define ROGUE_FWIF_CCB_CMD_TYPE_FENCE (212U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UPDATE (213U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_RMW_UPDATE \ + (214U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR (215U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_PRIORITY (216U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +/* + * Pre and Post timestamp commands are supposed to sandwich the DM cmd. The + * padding code with the CCB wrap upsets the FW if we don't have the task type + * bit cleared for POST_TIMESTAMPs. That's why we have 2 different cmd types. + */ +#define ROGUE_FWIF_CCB_CMD_TYPE_POST_TIMESTAMP \ + (217U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UNFENCED_UPDATE \ + (218U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UNFENCED_RMW_UPDATE \ + (219U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) + +#define ROGUE_FWIF_CCB_CMD_TYPE_PADDING (221U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) + +struct rogue_fwif_workest_kick_data { + /* Index for the KM Workload estimation return data array */ + u16 return_data_index __aligned(8); + /* Predicted time taken to do the work in cycles */ + u32 cycles_prediction __aligned(8); + /* Deadline for the workload */ + aligned_u64 deadline; +}; + +struct rogue_fwif_ccb_cmd_header { + u32 cmd_type; + u32 cmd_size; + /* + * external job reference - provided by client and used in debug for + * tracking submitted work + */ + u32 ext_job_ref; + /* + * internal job reference - generated by services and used in debug for + * tracking submitted work + */ + u32 int_job_ref; + /* Workload Estimation - Workload Estimation Data */ + struct rogue_fwif_workest_kick_data work_est_kick_data __aligned(8); +}; + +/* + ****************************************************************************** + * Client CCB commands which are only required by the kernel + ****************************************************************************** + */ +struct rogue_fwif_cmd_priority { + s32 priority; +}; + +/* + ****************************************************************************** + * Signature and Checksums Buffer + ****************************************************************************** + */ +struct rogue_fwif_sigbuf_ctl { + /* Ptr to Signature Buffer memory */ + u32 buffer_fw_addr; + /* Amount of space left for storing regs in the buffer */ + u32 left_size_in_regs; +} __aligned(8); + +struct rogue_fwif_counter_dump_ctl { + /* Ptr to counter dump buffer */ + u32 buffer_fw_addr; + /* Amount of space for storing in the buffer */ + u32 size_in_dwords; +} __aligned(8); + +struct rogue_fwif_firmware_gcov_ctl { + /* Ptr to firmware gcov buffer */ + u32 buffer_fw_addr; + /* Amount of space for storing in the buffer */ + u32 size; +} __aligned(8); + +/* + ***************************************************************************** + * ROGUE Compatibility checks + ***************************************************************************** + */ + +/* + * WARNING: Whenever the layout of ROGUE_FWIF_COMPCHECKS_BVNC changes, the + * following define should be increased by 1 to indicate to the compatibility + * logic that layout has changed. + */ +#define ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION 3 + +struct rogue_fwif_compchecks_bvnc { + /* WARNING: This field must be defined as first one in this structure */ + u32 layout_version; + aligned_u64 bvnc; +} __aligned(8); + +struct rogue_fwif_init_options { + u8 os_count_support; + u8 padding[7]; +} __aligned(8); + +#define ROGUE_FWIF_COMPCHECKS_BVNC_DECLARE_AND_INIT(name) \ + struct rogue_fwif_compchecks_bvnc(name) = { \ + ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION, \ + 0, \ + } + +static inline void rogue_fwif_compchecks_bvnc_init(struct rogue_fwif_compchecks_bvnc *compchecks) +{ + compchecks->layout_version = ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION; + compchecks->bvnc = 0; +} + +struct rogue_fwif_compchecks { + /* hardware BVNC (from the ROGUE registers) */ + struct rogue_fwif_compchecks_bvnc hw_bvnc; + /* firmware BVNC */ + struct rogue_fwif_compchecks_bvnc fw_bvnc; + /* identifier of the FW processor version */ + u32 fw_processor_version; + /* software DDK version */ + u32 ddk_version; + /* software DDK build no. */ + u32 ddk_build; + /* build options bit-field */ + u32 build_options; + /* initialisation options bit-field */ + struct rogue_fwif_init_options init_options; + /* Information is valid */ + bool updated __aligned(4); + u32 padding; +} __aligned(8); + +/* + ****************************************************************************** + * Updated configuration post FW data init. + ****************************************************************************** + */ +struct rogue_fwif_runtime_cfg { + /* APM latency in ms before signalling IDLE to the host */ + u32 active_pm_latency_ms; + /* Compatibility and other flags */ + u32 runtime_cfg_flags; + /* + * If set, APM latency does not reset to system default each GPU power + * transition + */ + bool active_pm_latency_persistant __aligned(4); + /* Core clock speed, currently only used to calculate timer ticks */ + u32 core_clock_speed; + /* Last number of dusts change requested by the host */ + u32 default_dusts_num_init; + /* Periodic Hardware Reset configuration values */ + u32 phr_mode; + /* New number of milliseconds C/S is allowed to last */ + u32 hcs_deadline_ms; + /* The watchdog period in microseconds */ + u32 wdg_period_us; + /* Array of priorities per OS */ + u32 osid_priority[ROGUE_FW_MAX_NUM_OS]; + /* On-demand allocated HWPerf buffer address, to be passed to the FW */ + u32 hwperf_buf_fw_addr; + + bool padding __aligned(4); +}; + +/* + ***************************************************************************** + * Control data for ROGUE + ***************************************************************************** + */ + +#define ROGUE_FWIF_HWR_DEBUG_DUMP_ALL (99999U) + +enum rogue_fwif_tpu_dm { + ROGUE_FWIF_TPU_DM_PDM = 0, + ROGUE_FWIF_TPU_DM_VDM = 1, + ROGUE_FWIF_TPU_DM_CDM = 2, + ROGUE_FWIF_TPU_DM_TDM = 3, + ROGUE_FWIF_TPU_DM_LAST +}; + +enum rogue_fwif_gpio_val_mode { + /* No GPIO validation */ + ROGUE_FWIF_GPIO_VAL_OFF = 0, + /* + * Simple test case that initiates by sending data via the GPIO and then + * sends back any data received over the GPIO + */ + ROGUE_FWIF_GPIO_VAL_GENERAL = 1, + /* + * More complex test case that writes and reads data across the entire + * GPIO AP address range. + */ + ROGUE_FWIF_GPIO_VAL_AP = 2, + /* Validates the GPIO Testbench. */ + ROGUE_FWIF_GPIO_VAL_TESTBENCH = 5, + /* Send and then receive each byte in the range 0-255. */ + ROGUE_FWIF_GPIO_VAL_LOOPBACK = 6, + /* Send and then receive each power-of-2 byte in the range 0-255. */ + ROGUE_FWIF_GPIO_VAL_LOOPBACK_LITE = 7, + ROGUE_FWIF_GPIO_VAL_LAST +}; + +enum fw_perf_conf { + FW_PERF_CONF_NONE = 0, + FW_PERF_CONF_ICACHE = 1, + FW_PERF_CONF_DCACHE = 2, + FW_PERF_CONF_JTLB_INSTR = 5, + FW_PERF_CONF_INSTRUCTIONS = 6 +}; + +enum fw_boot_stage { + FW_BOOT_STAGE_TLB_INIT_FAILURE = -2, + FW_BOOT_STAGE_NOT_AVAILABLE = -1, + FW_BOOT_NOT_STARTED = 0, + FW_BOOT_BLDR_STARTED = 1, + FW_BOOT_CACHE_DONE, + FW_BOOT_TLB_DONE, + FW_BOOT_MAIN_STARTED, + FW_BOOT_ALIGNCHECKS_DONE, + FW_BOOT_INIT_DONE, +}; + +/* + * Kernel CCB return slot responses. Usage of bit-fields instead of bare + * integers allows FW to possibly pack-in several responses for each single kCCB + * command. + */ +/* Command executed (return status from FW) */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_CMD_EXECUTED BIT(0) +/* A cleanup was requested but resource busy */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_CLEANUP_BUSY BIT(1) +/* Poll failed in FW for a HW operation to complete */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_POLL_FAILURE BIT(2) +/* Reset value of a kCCB return slot (set by host) */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_NO_RESPONSE 0x0U + +struct rogue_fwif_connection_ctl { + /* Fw-Os connection states */ + enum rogue_fwif_connection_fw_state connection_fw_state; + enum rogue_fwif_connection_os_state connection_os_state; + u32 alive_fw_token; + u32 alive_os_token; +} __aligned(8); + +struct rogue_fwif_osinit { + /* Kernel CCB */ + u32 kernel_ccbctl_fw_addr; + u32 kernel_ccb_fw_addr; + u32 kernel_ccb_rtn_slots_fw_addr; + + /* Firmware CCB */ + u32 firmware_ccbctl_fw_addr; + u32 firmware_ccb_fw_addr; + + /* Workload Estimation Firmware CCB */ + u32 work_est_firmware_ccbctl_fw_addr; + u32 work_est_firmware_ccb_fw_addr; + + u32 rogue_fwif_hwr_info_buf_ctl_fw_addr; + + u32 hwr_debug_dump_limit; + + u32 fw_os_data_fw_addr; + + /* Compatibility checks to be populated by the Firmware */ + struct rogue_fwif_compchecks rogue_comp_checks; +} __aligned(8); + +/* BVNC Features */ +struct rogue_hwperf_bvnc_block { + /* Counter block ID, see ROGUE_HWPERF_CNTBLK_ID */ + u16 block_id; + + /* Number of counters in this block type */ + u16 num_counters; + + /* Number of blocks of this type */ + u16 num_blocks; + + u16 reserved; +}; + +#define ROGUE_HWPERF_MAX_BVNC_LEN (24) + +#define ROGUE_HWPERF_MAX_BVNC_BLOCK_LEN (16U) + +/* BVNC Features */ +struct rogue_hwperf_bvnc { + /* BVNC string */ + char bvnc_string[ROGUE_HWPERF_MAX_BVNC_LEN]; + /* See ROGUE_HWPERF_FEATURE_FLAGS */ + u32 bvnc_km_feature_flags; + /* Number of blocks described in aBvncBlocks */ + u16 num_bvnc_blocks; + /* Number of GPU cores present */ + u16 bvnc_gpu_cores; + /* Supported Performance Blocks for BVNC */ + struct rogue_hwperf_bvnc_block + bvnc_blocks[ROGUE_HWPERF_MAX_BVNC_BLOCK_LEN]; +}; + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_hwperf_bvnc); + +struct rogue_fwif_sysinit { + /* Fault read address */ + aligned_u64 fault_phys_addr; + + /* PDS execution base */ + aligned_u64 pds_exec_base; + /* UCS execution base */ + aligned_u64 usc_exec_base; + /* FBCDC bindless texture state table base */ + aligned_u64 fbcdc_state_table_base; + aligned_u64 fbcdc_large_state_table_base; + /* Texture state base */ + aligned_u64 texture_heap_base; + + /* Event filter for Firmware events */ + u64 hw_perf_filter; + + aligned_u64 slc3_fence_dev_addr; + + u32 tpu_trilinear_frac_mask[ROGUE_FWIF_TPU_DM_LAST] __aligned(8); + + /* Signature and Checksum Buffers for DMs */ + struct rogue_fwif_sigbuf_ctl sigbuf_ctl[PVR_FWIF_DM_MAX]; + + struct rogue_fwif_pdvfs_opp pdvfs_opp_info; + + struct rogue_fwif_dma_addr coremem_data_store; + + struct rogue_fwif_counter_dump_ctl counter_dump_ctl; + + u32 filter_flags; + + u32 runtime_cfg_fw_addr; + + u32 trace_buf_ctl_fw_addr; + u32 fw_sys_data_fw_addr; + + u32 gpu_util_fw_cb_ctl_fw_addr; + u32 reg_cfg_fw_addr; + u32 hwperf_ctl_fw_addr; + + u32 align_checks; + + /* Core clock speed at FW boot time */ + u32 initial_core_clock_speed; + + /* APM latency in ms before signalling IDLE to the host */ + u32 active_pm_latency_ms; + + /* Flag to be set by the Firmware after successful start */ + bool firmware_started __aligned(4); + + /* Host/FW Trace synchronisation Partition Marker */ + u32 marker_val; + + /* Firmware initialization complete time */ + u32 firmware_started_timestamp; + + u32 jones_disable_mask; + + /* Firmware performance counter config */ + enum fw_perf_conf firmware_perf; + + /* + * FW Pointer to memory containing core clock rate in Hz. + * Firmware (PDVFS) updates the memory when running on non primary FW + * thread to communicate to host driver. + */ + u32 core_clock_rate_fw_addr; + + enum rogue_fwif_gpio_val_mode gpio_validation_mode; + + /* Used in HWPerf for decoding BVNC Features */ + struct rogue_hwperf_bvnc bvnc_km_feature_flags; + + /* Value to write into ROGUE_CR_TFBC_COMPRESSION_CONTROL */ + u32 tfbc_compression_control; +} __aligned(8); + +/* + ***************************************************************************** + * Timer correlation shared data and defines + ***************************************************************************** + */ + +struct rogue_fwif_time_corr { + aligned_u64 os_timestamp; + aligned_u64 os_mono_timestamp; + aligned_u64 cr_timestamp; + + /* + * Utility variable used to convert CR timer deltas to OS timer deltas + * (nS), where the deltas are relative to the timestamps above: + * deltaOS = (deltaCR * K) >> decimal_shift, see full explanation below + */ + aligned_u64 cr_delta_to_os_delta_kns; + + u32 core_clock_speed; + u32 reserved; +} __aligned(8); + +/* + * The following macros are used to help converting FW timestamps to the Host + * time domain. On the FW the ROGUE_CR_TIMER counter is used to keep track of + * time; it increments by 1 every 256 GPU clock ticks, so the general + * formula to perform the conversion is: + * + * [ GPU clock speed in Hz, if (scale == 10^9) then deltaOS is in nS, + * otherwise if (scale == 10^6) then deltaOS is in uS ] + * + * deltaCR * 256 256 * scale + * deltaOS = --------------- * scale = deltaCR * K [ K = --------------- ] + * GPUclockspeed GPUclockspeed + * + * The actual K is multiplied by 2^20 (and deltaCR * K is divided by 2^20) + * to get some better accuracy and to avoid returning 0 in the integer + * division 256000000/GPUfreq if GPUfreq is greater than 256MHz. + * This is the same as keeping K as a decimal number. + * + * The maximum deltaOS is slightly more than 5hrs for all GPU frequencies + * (deltaCR * K is more or less a constant), and it's relative to the base + * OS timestamp sampled as a part of the timer correlation data. + * This base is refreshed on GPU power-on, DVFS transition and periodic + * frequency calibration (executed every few seconds if the FW is doing + * some work), so as long as the GPU is doing something and one of these + * events is triggered then deltaCR * K will not overflow and deltaOS will be + * correct. + */ + +#define ROGUE_FWIF_CRDELTA_TO_OSDELTA_ACCURACY_SHIFT (20) + +#define ROGUE_FWIF_GET_DELTA_OSTIME_NS(delta_cr, k) \ + (((delta_cr) * (k)) >> ROGUE_FWIF_CRDELTA_TO_OSDELTA_ACCURACY_SHIFT) + +/* + ****************************************************************************** + * GPU Utilisation + ****************************************************************************** + */ + +/* See rogue_common.h for a list of GPU states */ +#define ROGUE_FWIF_GPU_UTIL_TIME_MASK \ + (0xFFFFFFFFFFFFFFFFull & ~ROGUE_FWIF_GPU_UTIL_STATE_MASK) + +#define ROGUE_FWIF_GPU_UTIL_GET_TIME(word) \ + ((word)(&ROGUE_FWIF_GPU_UTIL_TIME_MASK)) +#define ROGUE_FWIF_GPU_UTIL_GET_STATE(word) \ + ((word)(&ROGUE_FWIF_GPU_UTIL_STATE_MASK)) + +/* + * The OS timestamps computed by the FW are approximations of the real time, + * which means they could be slightly behind or ahead the real timer on the + * Host. In some cases we can perform subtractions between FW approximated + * timestamps and real OS timestamps, so we need a form of protection against + * negative results if for instance the FW one is a bit ahead of time. + */ +#define ROGUE_FWIF_GPU_UTIL_GET_PERIOD(newtime, oldtime) \ + (((newtime) > (oldtime)) ? ((newtime) - (oldtime)) : 0U) + +#define ROGUE_FWIF_GPU_UTIL_MAKE_WORD(time, state) \ + (ROGUE_FWIF_GPU_UTIL_GET_TIME(time) | \ + ROGUE_FWIF_GPU_UTIL_GET_STATE(state)) + +/* + * The timer correlation array must be big enough to ensure old entries won't be + * overwritten before all the HWPerf events linked to those entries are + * processed by the MISR. The update frequency of this array depends on how fast + * the system can change state (basically how small the APM latency is) and + * perform DVFS transitions. + * + * The minimum size is 2 (not 1) to avoid race conditions between the FW reading + * an entry while the Host is updating it. With 2 entries in the worst case the + * FW will read old data, which is still quite ok if the Host is updating the + * timer correlation at that time. + */ +#define ROGUE_FWIF_TIME_CORR_ARRAY_SIZE 256U +#define ROGUE_FWIF_TIME_CORR_CURR_INDEX(seqcount) \ + ((seqcount) % ROGUE_FWIF_TIME_CORR_ARRAY_SIZE) + +/* Make sure the timer correlation array size is a power of 2 */ +static_assert((ROGUE_FWIF_TIME_CORR_ARRAY_SIZE & + (ROGUE_FWIF_TIME_CORR_ARRAY_SIZE - 1U)) == 0U, + "ROGUE_FWIF_TIME_CORR_ARRAY_SIZE must be a power of two"); + +struct rogue_fwif_gpu_util_fwcb { + struct rogue_fwif_time_corr time_corr[ROGUE_FWIF_TIME_CORR_ARRAY_SIZE]; + u32 time_corr_seq_count; + + /* Compatibility and other flags */ + u32 gpu_util_flags; + + /* Last GPU state + OS time of the last state update */ + aligned_u64 last_word; + + /* Counters for the amount of time the GPU was active/idle/blocked */ + aligned_u64 stats_counters[PVR_FWIF_GPU_UTIL_STATE_NUM]; +} __aligned(8); + +struct rogue_fwif_rta_ctl { + /* Render number */ + u32 render_target_index; + /* index in RTA */ + u32 current_render_target; + /* total active RTs */ + u32 active_render_targets; + /* total active RTs from the first TA kick, for OOM */ + u32 cumul_active_render_targets; + /* Array of valid RT indices */ + u32 valid_render_targets_fw_addr; + /* Array of number of occurred partial renders per render target */ + u32 rta_num_partial_renders_fw_addr; + /* Number of render targets in the array */ + u32 max_rts; + /* Compatibility and other flags */ + u32 rta_ctl_flags; +} __aligned(8); + +struct rogue_fwif_freelist { + aligned_u64 freelist_dev_addr; + aligned_u64 current_dev_addr; + u32 current_stack_top; + u32 max_pages; + u32 grow_pages; + /* HW pages */ + u32 current_pages; + u32 allocated_page_count; + u32 allocated_mmu_page_count; + u32 freelist_id; + + bool grow_pending __aligned(4); + /* Pages that should be used only when OOM is reached */ + u32 ready_pages; + /* Compatibility and other flags */ + u32 freelist_flags; + /* PM Global PB on which Freelist is loaded */ + u32 pm_global_pb; + u32 padding; +} __aligned(8); + +/* + ****************************************************************************** + * HWRTData + ****************************************************************************** + */ + +/* HWRTData flags */ +/* Deprecated flags 1:0 */ +#define HWRTDATA_HAS_LAST_GEOM BIT(2) +#define HWRTDATA_PARTIAL_RENDERED BIT(3) +#define HWRTDATA_DISABLE_TILE_REORDERING BIT(4) +#define HWRTDATA_NEED_BRN65101_BLIT BIT(5) +#define HWRTDATA_FIRST_BRN65101_STRIP BIT(6) +#define HWRTDATA_NEED_BRN67182_2ND_RENDER BIT(7) + +enum rogue_fwif_rtdata_state { + ROGUE_FWIF_RTDATA_STATE_NONE = 0, + ROGUE_FWIF_RTDATA_STATE_KICK_GEOM, + ROGUE_FWIF_RTDATA_STATE_KICK_GEOM_FIRST, + ROGUE_FWIF_RTDATA_STATE_GEOM_FINISHED, + ROGUE_FWIF_RTDATA_STATE_KICK_FRAG, + ROGUE_FWIF_RTDATA_STATE_FRAG_FINISHED, + ROGUE_FWIF_RTDATA_STATE_FRAG_CONTEXT_STORED, + ROGUE_FWIF_RTDATA_STATE_GEOM_OUTOFMEM, + ROGUE_FWIF_RTDATA_STATE_PARTIALRENDERFINISHED, + /* + * In case of HWR, we can't set the RTDATA state to NONE, as this will + * cause any TA to become a first TA. To ensure all related TA's are + * skipped, we use the HWR state + */ + ROGUE_FWIF_RTDATA_STATE_HWR, + ROGUE_FWIF_RTDATA_STATE_UNKNOWN = 0x7FFFFFFFU +}; + +struct rogue_fwif_hwrtdata_common { + bool geom_caches_need_zeroing __aligned(4); + + u32 screen_pixel_max; + aligned_u64 multi_sample_ctl; + u64 flipped_multi_sample_ctl; + u32 tpc_stride; + u32 tpc_size; + u32 te_screen; + u32 mtile_stride; + u32 teaa; + u32 te_mtile1; + u32 te_mtile2; + u32 isp_merge_lower_x; + u32 isp_merge_lower_y; + u32 isp_merge_upper_x; + u32 isp_merge_upper_y; + u32 isp_merge_scale_x; + u32 isp_merge_scale_y; + u32 rgn_header_size; + u32 isp_mtile_size; + u32 padding; +} __aligned(8); + +struct rogue_fwif_hwrtdata { + /* MList Data Store */ + aligned_u64 pm_mlist_dev_addr; + + aligned_u64 vce_cat_base[4]; + aligned_u64 vce_last_cat_base[4]; + aligned_u64 te_cat_base[4]; + aligned_u64 te_last_cat_base[4]; + aligned_u64 alist_cat_base; + aligned_u64 alist_last_cat_base; + + aligned_u64 pm_alist_stack_pointer; + u32 pm_mlist_stack_pointer; + + u32 hwrt_data_common_fw_addr; + + u32 hwrt_data_flags; + enum rogue_fwif_rtdata_state state; + + u32 freelists_fw_addr[MAX_FREELISTS_SIZE] __aligned(8); + u32 freelist_hwr_snapshot[MAX_FREELISTS_SIZE]; + + aligned_u64 vheap_table_dev_addr; + + struct rogue_fwif_rta_ctl rta_ctl; + + aligned_u64 tail_ptrs_dev_addr; + aligned_u64 macrotile_array_dev_addr; + aligned_u64 rgn_header_dev_addr; + aligned_u64 rtc_dev_addr; + + u32 owner_geom_not_used_by_host __aligned(8); + + bool geom_caches_need_zeroing __aligned(4); + + struct rogue_fwif_cleanup_ctl cleanup_state __aligned(64); +} __aligned(8); + +/* + ****************************************************************************** + * Sync checkpoints + ****************************************************************************** + */ + +#define PVR_SYNC_CHECKPOINT_UNDEF 0x000 +#define PVR_SYNC_CHECKPOINT_ACTIVE 0xac1 /* Checkpoint has not signaled. */ +#define PVR_SYNC_CHECKPOINT_SIGNALED 0x519 /* Checkpoint has signaled. */ +#define PVR_SYNC_CHECKPOINT_ERRORED 0xeff /* Checkpoint has been errored. */ + +#include "pvr_rogue_fwif_check.h" + +#endif /* PVR_ROGUE_FWIF_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h new file mode 100644 index 000000000000..51dc37e78f41 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h @@ -0,0 +1,493 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CHECK_H +#define PVR_ROGUE_FWIF_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0); +OFFSET_CHECK(struct rogue_fwif_file_info_buf, info, 200); +OFFSET_CHECK(struct rogue_fwif_file_info_buf, line_num, 400); +SIZE_CHECK(struct rogue_fwif_file_info_buf, 408); + +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_pointer, 0); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_buffer_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_buffer, 8); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, assert_buf, 16); +SIZE_CHECK(struct rogue_fwif_tracebuf_space, 424); + +OFFSET_CHECK(struct rogue_fwif_tracebuf, log_type, 0); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf, 8); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf_size_in_dwords, 856); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf_flags, 860); +SIZE_CHECK(struct rogue_fwif_tracebuf, 864); + +OFFSET_CHECK(struct rogue_fw_fault_info, cr_timer, 0); +OFFSET_CHECK(struct rogue_fw_fault_info, os_timer, 8); +OFFSET_CHECK(struct rogue_fw_fault_info, data, 16); +OFFSET_CHECK(struct rogue_fw_fault_info, reserved, 20); +OFFSET_CHECK(struct rogue_fw_fault_info, fault_buf, 24); +SIZE_CHECK(struct rogue_fw_fault_info, 432); + +OFFSET_CHECK(struct rogue_fwif_sysdata, config_flags, 0); +OFFSET_CHECK(struct rogue_fwif_sysdata, config_flags_ext, 4); +OFFSET_CHECK(struct rogue_fwif_sysdata, pow_state, 8); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_ridx, 12); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_widx, 16); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_wrap_count, 20); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_size, 24); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_drop_count, 28); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_ut, 32); +OFFSET_CHECK(struct rogue_fwif_sysdata, first_drop_ordinal, 36); +OFFSET_CHECK(struct rogue_fwif_sysdata, last_drop_ordinal, 40); +OFFSET_CHECK(struct rogue_fwif_sysdata, os_runtime_flags_mirror, 44); +OFFSET_CHECK(struct rogue_fwif_sysdata, fault_info, 80); +OFFSET_CHECK(struct rogue_fwif_sysdata, fw_faults, 3536); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_addr, 3540); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_mask, 3548); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_count, 3556); +OFFSET_CHECK(struct rogue_fwif_sysdata, start_idle_time, 3568); +OFFSET_CHECK(struct rogue_fwif_sysdata, hwr_state_flags, 3576); +OFFSET_CHECK(struct rogue_fwif_sysdata, hwr_recovery_flags, 3580); +OFFSET_CHECK(struct rogue_fwif_sysdata, fw_sys_data_flags, 3616); +OFFSET_CHECK(struct rogue_fwif_sysdata, mc_config, 3620); +SIZE_CHECK(struct rogue_fwif_sysdata, 3624); + +OFFSET_CHECK(struct rogue_fwif_slr_entry, timestamp, 0); +OFFSET_CHECK(struct rogue_fwif_slr_entry, fw_ctx_addr, 8); +OFFSET_CHECK(struct rogue_fwif_slr_entry, num_ufos, 12); +OFFSET_CHECK(struct rogue_fwif_slr_entry, ccb_name, 16); +SIZE_CHECK(struct rogue_fwif_slr_entry, 48); + +OFFSET_CHECK(struct rogue_fwif_osdata, fw_os_config_flags, 0); +OFFSET_CHECK(struct rogue_fwif_osdata, fw_sync_check_mark, 4); +OFFSET_CHECK(struct rogue_fwif_osdata, host_sync_check_mark, 8); +OFFSET_CHECK(struct rogue_fwif_osdata, forced_updates_requested, 12); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log_wp, 16); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log_first, 24); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log, 72); +OFFSET_CHECK(struct rogue_fwif_osdata, last_forced_update_time, 552); +OFFSET_CHECK(struct rogue_fwif_osdata, interrupt_count, 560); +OFFSET_CHECK(struct rogue_fwif_osdata, kccb_cmds_executed, 568); +OFFSET_CHECK(struct rogue_fwif_osdata, power_sync_fw_addr, 572); +OFFSET_CHECK(struct rogue_fwif_osdata, fw_os_data_flags, 576); +SIZE_CHECK(struct rogue_fwif_osdata, 584); + +OFFSET_CHECK(struct rogue_bifinfo, bif_req_status, 0); +OFFSET_CHECK(struct rogue_bifinfo, bif_mmu_status, 8); +OFFSET_CHECK(struct rogue_bifinfo, pc_address, 16); +OFFSET_CHECK(struct rogue_bifinfo, reserved, 24); +SIZE_CHECK(struct rogue_bifinfo, 32); + +OFFSET_CHECK(struct rogue_eccinfo, fault_gpu, 0); +SIZE_CHECK(struct rogue_eccinfo, 4); + +OFFSET_CHECK(struct rogue_mmuinfo, mmu_status, 0); +OFFSET_CHECK(struct rogue_mmuinfo, pc_address, 16); +OFFSET_CHECK(struct rogue_mmuinfo, reserved, 24); +SIZE_CHECK(struct rogue_mmuinfo, 32); + +OFFSET_CHECK(struct rogue_pollinfo, thread_num, 0); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_addr, 4); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_mask, 8); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_last_value, 12); +OFFSET_CHECK(struct rogue_pollinfo, reserved, 16); +SIZE_CHECK(struct rogue_pollinfo, 24); + +OFFSET_CHECK(struct rogue_tlbinfo, bad_addr, 0); +OFFSET_CHECK(struct rogue_tlbinfo, entry_lo, 4); +SIZE_CHECK(struct rogue_tlbinfo, 8); + +OFFSET_CHECK(struct rogue_hwrinfo, hwr_data, 0); +OFFSET_CHECK(struct rogue_hwrinfo, cr_timer, 32); +OFFSET_CHECK(struct rogue_hwrinfo, os_timer, 40); +OFFSET_CHECK(struct rogue_hwrinfo, frame_num, 48); +OFFSET_CHECK(struct rogue_hwrinfo, pid, 52); +OFFSET_CHECK(struct rogue_hwrinfo, active_hwrt_data, 56); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_number, 60); +OFFSET_CHECK(struct rogue_hwrinfo, event_status, 64); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_recovery_flags, 68); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_type, 72); +OFFSET_CHECK(struct rogue_hwrinfo, dm, 76); +OFFSET_CHECK(struct rogue_hwrinfo, core_id, 80); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_of_kick, 88); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_hw_reset_start, 96); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_hw_reset_finish, 104); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_freelist_ready, 112); +OFFSET_CHECK(struct rogue_hwrinfo, reserved, 120); +SIZE_CHECK(struct rogue_hwrinfo, 136); + +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_info, 0); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_counter, 2176); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, write_index, 2180); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, dd_req_count, 2184); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_info_buf_flags, 2188); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_locked_up_count, 2192); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_overran_count, 2228); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_recovered_count, 2264); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_false_detect_count, 2300); +SIZE_CHECK(struct rogue_fwif_hwrinfobuf, 2336); + +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, pc_dev_paddr, 0); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, page_cat_base_reg_set, 8); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, breakpoint_addr, 12); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, bp_handler_addr, 16); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, breakpoint_ctl, 20); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, fw_mem_ctx_flags, 24); +SIZE_CHECK(struct rogue_fwif_fwmemcontext, 32); + +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vdm_call_stack_pointer, 0); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vdm_call_stack_pointer_init, 8); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vbs_so_prim, 16); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_current_idx, 32); +SIZE_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, 40); + +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state, geom_core, 0); +SIZE_CHECK(struct rogue_fwif_geom_ctx_state, 160); + +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_pm_deallocated_mask_status, 0); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_dm_pds_mtilefree_status, 4); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, ctx_state_flags, 8); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_isp_store, 12); +SIZE_CHECK(struct rogue_fwif_frag_ctx_state, 16); + +OFFSET_CHECK(struct rogue_fwif_compute_ctx_state, ctx_state_flags, 0); +SIZE_CHECK(struct rogue_fwif_compute_ctx_state, 4); + +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccbctl_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccb_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccb_meta_dma_addr, 8); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, context_state_addr, 24); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, fw_com_ctx_flags, 28); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, priority, 32); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, priority_seq_num, 36); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, rf_cmd_addr, 40); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_pending, 44); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_stores, 48); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_out_of_memory, 52); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_partial_renders, 56); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, dm, 60); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, wait_signal_address, 64); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, wait_signal_node, 72); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, buf_stalled_node, 80); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, cbuf_queue_ctrl_addr, 88); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, robustness_address, 96); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, max_deadline_ms, 104); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, read_offset_needs_reset, 108); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, waiting_node, 112); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, run_node, 120); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, last_failed_ufo, 128); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, fw_mem_context_fw_addr, 136); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, server_common_context_id, 140); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, pid, 144); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, geom_oom_disabled, 148); +SIZE_CHECK(struct rogue_fwif_fwcommoncontext, 152); + +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, write_offset, 0); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, padding, 4); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, read_offset, 128); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, wrap_mask, 132); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, cmd_size, 136); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, padding2, 140); +SIZE_CHECK(struct rogue_fwif_ccb_ctl, 144); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, client_woff_update, 4); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, client_wrap_mask_update, 8); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, num_cleanup_ctl, 12); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, cleanup_ctl_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, work_est_cmd_header_offset, 28); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_kick_data, 32); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, geom_cmd_kick_data, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, frag_cmd_kick_data, 32); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, 64); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, ccb_fence_offset, 4); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, 8); + +OFFSET_CHECK(struct rogue_fwif_cleanup_request, cleanup_type, 0); +OFFSET_CHECK(struct rogue_fwif_cleanup_request, cleanup_data, 4); +SIZE_CHECK(struct rogue_fwif_cleanup_request, 8); + +OFFSET_CHECK(struct rogue_fwif_power_request, pow_type, 0); +OFFSET_CHECK(struct rogue_fwif_power_request, power_req_data, 4); +SIZE_CHECK(struct rogue_fwif_power_request, 8); + +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, inval, 4); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, dm_context, 8); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, address, 16); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, size, 24); +SIZE_CHECK(struct rogue_fwif_slcflushinvaldata, 32); + +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl, opcode, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl, mask, 8); +SIZE_CHECK(struct rogue_fwif_hwperf_ctrl, 16); + +OFFSET_CHECK(struct rogue_fwif_hwperf_config_enable_blks, num_blocks, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_config_enable_blks, block_configs_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_config_enable_blks, 8); + +OFFSET_CHECK(struct rogue_fwif_hwperf_config_da_blks, num_blocks, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_config_da_blks, block_configs_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_config_da_blks, 8); + +OFFSET_CHECK(struct rogue_fwif_coreclkspeedchange_data, new_clock_speed, 0); +SIZE_CHECK(struct rogue_fwif_coreclkspeedchange_data, 4); + +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, enable, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, num_blocks, 4); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, block_ids, 8); +SIZE_CHECK(struct rogue_fwif_hwperf_ctrl_blks, 40); + +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, custom_block, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, num_counters, 2); +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, custom_counter_ids_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, 8); + +OFFSET_CHECK(struct rogue_fwif_zsbuffer_backing_data, zs_buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_zsbuffer_backing_data, done, 4); +SIZE_CHECK(struct rogue_fwif_zsbuffer_backing_data, 8); + +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, freelist_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, delta_pages, 4); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, new_pages, 8); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, ready_pages, 12); +SIZE_CHECK(struct rogue_fwif_freelist_gs_data, 16); + +OFFSET_CHECK(struct rogue_fwif_freelists_reconstruction_data, freelist_count, 0); +OFFSET_CHECK(struct rogue_fwif_freelists_reconstruction_data, freelist_ids, 4); +SIZE_CHECK(struct rogue_fwif_freelists_reconstruction_data, 76); + +OFFSET_CHECK(struct rogue_fwif_write_offset_update_data, context_fw_addr, 0); +SIZE_CHECK(struct rogue_fwif_write_offset_update_data, 8); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, kccb_flags, 4); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, cmd_data, 8); +SIZE_CHECK(struct rogue_fwif_kccb_cmd, 88); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, server_common_context_id, 0); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, reset_reason, 4); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, dm, 8); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, reset_job_ref, 12); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, flags, 16); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, pc_address, 24); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, fault_address, 32); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, 40); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_fw_pagefault_data, fw_fault_addr, 0); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd_fw_pagefault_data, 8); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, fwccb_flags, 4); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, cmd_data, 8); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd, 88); + +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, cmd_size, 4); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, ext_job_ref, 8); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, int_job_ref, 12); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, work_est_kick_data, 16); +SIZE_CHECK(struct rogue_fwif_ccb_cmd_header, 40); + +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, active_pm_latency_ms, 0); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, runtime_cfg_flags, 4); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, active_pm_latency_persistant, 8); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, core_clock_speed, 12); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, default_dusts_num_init, 16); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, phr_mode, 20); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, hcs_deadline_ms, 24); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, wdg_period_us, 28); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, osid_priority, 32); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, hwperf_buf_fw_addr, 64); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, padding, 68); +SIZE_CHECK(struct rogue_fwif_runtime_cfg, 72); + +OFFSET_CHECK(struct rogue_fwif_connection_ctl, connection_fw_state, 0); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, connection_os_state, 4); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, alive_fw_token, 8); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, alive_os_token, 12); +SIZE_CHECK(struct rogue_fwif_connection_ctl, 16); + +OFFSET_CHECK(struct rogue_fwif_compchecks_bvnc, layout_version, 0); +OFFSET_CHECK(struct rogue_fwif_compchecks_bvnc, bvnc, 8); +SIZE_CHECK(struct rogue_fwif_compchecks_bvnc, 16); + +OFFSET_CHECK(struct rogue_fwif_init_options, os_count_support, 0); +SIZE_CHECK(struct rogue_fwif_init_options, 8); + +OFFSET_CHECK(struct rogue_fwif_compchecks, hw_bvnc, 0); +OFFSET_CHECK(struct rogue_fwif_compchecks, fw_bvnc, 16); +OFFSET_CHECK(struct rogue_fwif_compchecks, fw_processor_version, 32); +OFFSET_CHECK(struct rogue_fwif_compchecks, ddk_version, 36); +OFFSET_CHECK(struct rogue_fwif_compchecks, ddk_build, 40); +OFFSET_CHECK(struct rogue_fwif_compchecks, build_options, 44); +OFFSET_CHECK(struct rogue_fwif_compchecks, init_options, 48); +OFFSET_CHECK(struct rogue_fwif_compchecks, updated, 56); +SIZE_CHECK(struct rogue_fwif_compchecks, 64); + +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccbctl_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccb_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccb_rtn_slots_fw_addr, 8); +OFFSET_CHECK(struct rogue_fwif_osinit, firmware_ccbctl_fw_addr, 12); +OFFSET_CHECK(struct rogue_fwif_osinit, firmware_ccb_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_osinit, work_est_firmware_ccbctl_fw_addr, 20); +OFFSET_CHECK(struct rogue_fwif_osinit, work_est_firmware_ccb_fw_addr, 24); +OFFSET_CHECK(struct rogue_fwif_osinit, rogue_fwif_hwr_info_buf_ctl_fw_addr, 28); +OFFSET_CHECK(struct rogue_fwif_osinit, hwr_debug_dump_limit, 32); +OFFSET_CHECK(struct rogue_fwif_osinit, fw_os_data_fw_addr, 36); +OFFSET_CHECK(struct rogue_fwif_osinit, rogue_comp_checks, 40); +SIZE_CHECK(struct rogue_fwif_osinit, 104); + +OFFSET_CHECK(struct rogue_fwif_sigbuf_ctl, buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_sigbuf_ctl, left_size_in_regs, 4); +SIZE_CHECK(struct rogue_fwif_sigbuf_ctl, 8); + +OFFSET_CHECK(struct pdvfs_opp, volt, 0); +OFFSET_CHECK(struct pdvfs_opp, freq, 4); +SIZE_CHECK(struct pdvfs_opp, 8); + +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, opp_values, 0); +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, min_opp_point, 128); +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, max_opp_point, 132); +SIZE_CHECK(struct rogue_fwif_pdvfs_opp, 136); + +OFFSET_CHECK(struct rogue_fwif_counter_dump_ctl, buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_counter_dump_ctl, size_in_dwords, 4); +SIZE_CHECK(struct rogue_fwif_counter_dump_ctl, 8); + +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_string, 0); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_km_feature_flags, 24); +OFFSET_CHECK(struct rogue_hwperf_bvnc, num_bvnc_blocks, 28); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_gpu_cores, 30); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_blocks, 32); +SIZE_CHECK(struct rogue_hwperf_bvnc, 160); + +OFFSET_CHECK(struct rogue_fwif_sysinit, fault_phys_addr, 0); +OFFSET_CHECK(struct rogue_fwif_sysinit, pds_exec_base, 8); +OFFSET_CHECK(struct rogue_fwif_sysinit, usc_exec_base, 16); +OFFSET_CHECK(struct rogue_fwif_sysinit, fbcdc_state_table_base, 24); +OFFSET_CHECK(struct rogue_fwif_sysinit, fbcdc_large_state_table_base, 32); +OFFSET_CHECK(struct rogue_fwif_sysinit, texture_heap_base, 40); +OFFSET_CHECK(struct rogue_fwif_sysinit, hw_perf_filter, 48); +OFFSET_CHECK(struct rogue_fwif_sysinit, slc3_fence_dev_addr, 56); +OFFSET_CHECK(struct rogue_fwif_sysinit, tpu_trilinear_frac_mask, 64); +OFFSET_CHECK(struct rogue_fwif_sysinit, sigbuf_ctl, 80); +OFFSET_CHECK(struct rogue_fwif_sysinit, pdvfs_opp_info, 152); +OFFSET_CHECK(struct rogue_fwif_sysinit, coremem_data_store, 288); +OFFSET_CHECK(struct rogue_fwif_sysinit, counter_dump_ctl, 304); +OFFSET_CHECK(struct rogue_fwif_sysinit, filter_flags, 312); +OFFSET_CHECK(struct rogue_fwif_sysinit, runtime_cfg_fw_addr, 316); +OFFSET_CHECK(struct rogue_fwif_sysinit, trace_buf_ctl_fw_addr, 320); +OFFSET_CHECK(struct rogue_fwif_sysinit, fw_sys_data_fw_addr, 324); +OFFSET_CHECK(struct rogue_fwif_sysinit, gpu_util_fw_cb_ctl_fw_addr, 328); +OFFSET_CHECK(struct rogue_fwif_sysinit, reg_cfg_fw_addr, 332); +OFFSET_CHECK(struct rogue_fwif_sysinit, hwperf_ctl_fw_addr, 336); +OFFSET_CHECK(struct rogue_fwif_sysinit, align_checks, 340); +OFFSET_CHECK(struct rogue_fwif_sysinit, initial_core_clock_speed, 344); +OFFSET_CHECK(struct rogue_fwif_sysinit, active_pm_latency_ms, 348); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_started, 352); +OFFSET_CHECK(struct rogue_fwif_sysinit, marker_val, 356); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_started_timestamp, 360); +OFFSET_CHECK(struct rogue_fwif_sysinit, jones_disable_mask, 364); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_perf, 368); +OFFSET_CHECK(struct rogue_fwif_sysinit, core_clock_rate_fw_addr, 372); +OFFSET_CHECK(struct rogue_fwif_sysinit, gpio_validation_mode, 376); +OFFSET_CHECK(struct rogue_fwif_sysinit, bvnc_km_feature_flags, 380); +OFFSET_CHECK(struct rogue_fwif_sysinit, tfbc_compression_control, 540); +SIZE_CHECK(struct rogue_fwif_sysinit, 544); + +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, time_corr, 0); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, time_corr_seq_count, 10240); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, gpu_util_flags, 10244); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, last_word, 10248); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, stats_counters, 10256); +SIZE_CHECK(struct rogue_fwif_gpu_util_fwcb, 10280); + +OFFSET_CHECK(struct rogue_fwif_rta_ctl, render_target_index, 0); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, current_render_target, 4); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, active_render_targets, 8); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, cumul_active_render_targets, 12); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, valid_render_targets_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, rta_num_partial_renders_fw_addr, 20); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, max_rts, 24); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, rta_ctl_flags, 28); +SIZE_CHECK(struct rogue_fwif_rta_ctl, 32); + +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_freelist, current_dev_addr, 8); +OFFSET_CHECK(struct rogue_fwif_freelist, current_stack_top, 16); +OFFSET_CHECK(struct rogue_fwif_freelist, max_pages, 20); +OFFSET_CHECK(struct rogue_fwif_freelist, grow_pages, 24); +OFFSET_CHECK(struct rogue_fwif_freelist, current_pages, 28); +OFFSET_CHECK(struct rogue_fwif_freelist, allocated_page_count, 32); +OFFSET_CHECK(struct rogue_fwif_freelist, allocated_mmu_page_count, 36); +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_id, 40); +OFFSET_CHECK(struct rogue_fwif_freelist, grow_pending, 44); +OFFSET_CHECK(struct rogue_fwif_freelist, ready_pages, 48); +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_flags, 52); +OFFSET_CHECK(struct rogue_fwif_freelist, pm_global_pb, 56); +SIZE_CHECK(struct rogue_fwif_freelist, 64); + +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, geom_caches_need_zeroing, 0); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, screen_pixel_max, 4); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, multi_sample_ctl, 8); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, flipped_multi_sample_ctl, 16); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, tpc_stride, 24); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, tpc_size, 28); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_screen, 32); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, mtile_stride, 36); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, teaa, 40); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_mtile1, 44); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_mtile2, 48); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_lower_x, 52); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_lower_y, 56); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_upper_x, 60); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_upper_y, 64); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_scale_x, 68); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_scale_y, 72); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, rgn_header_size, 76); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_mtile_size, 80); +SIZE_CHECK(struct rogue_fwif_hwrtdata_common, 88); + +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_mlist_dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vce_cat_base, 8); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vce_last_cat_base, 40); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, te_cat_base, 72); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, te_last_cat_base, 104); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, alist_cat_base, 136); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, alist_last_cat_base, 144); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_alist_stack_pointer, 152); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_mlist_stack_pointer, 160); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, hwrt_data_common_fw_addr, 164); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, hwrt_data_flags, 168); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, state, 172); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, freelists_fw_addr, 176); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, freelist_hwr_snapshot, 188); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vheap_table_dev_addr, 200); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rta_ctl, 208); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, tail_ptrs_dev_addr, 240); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, macrotile_array_dev_addr, 248); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rgn_header_dev_addr, 256); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rtc_dev_addr, 264); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, owner_geom_not_used_by_host, 272); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, geom_caches_need_zeroing, 276); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, cleanup_state, 320); +SIZE_CHECK(struct rogue_fwif_hwrtdata, 384); + +OFFSET_CHECK(struct rogue_fwif_sync_checkpoint, state, 0); +OFFSET_CHECK(struct rogue_fwif_sync_checkpoint, fw_ref_count, 4); +SIZE_CHECK(struct rogue_fwif_sync_checkpoint, 8); + +#endif /* PVR_ROGUE_FWIF_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h new file mode 100644 index 000000000000..6e224400083a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CLIENT_H +#define PVR_ROGUE_FWIF_CLIENT_H + +#include +#include +#include +#include + +#include "pvr_rogue_fwif_shared.h" + +/* + * Page size used for Parameter Management. + */ +#define ROGUE_PM_PAGE_SIZE SZ_4K + +/* + * Minimum/Maximum PB size. + * + * Base page size is dependent on core: + * S6/S6XT/S7 = 50 pages + * S8XE = 40 pages + * S8XE with BRN66011 fixed = 25 pages + * + * Minimum PB = Base Pages + (NUM_TE_PIPES-1)*16K + (NUM_VCE_PIPES-1)*64K + + * IF_PM_PREALLOC(NUM_TE_PIPES*16K + NUM_VCE_PIPES*16K) + * + * Maximum PB size must ensure that no PM address space can be fully used, + * because if the full address space was used it would wrap and corrupt itself. + * Since there are two freelists (local is always minimum sized) this can be + * described as following three conditions being met: + * + * (Minimum PB + Maximum PB) < ALIST PM address space size (16GB) + * (Minimum PB + Maximum PB) < TE PM address space size (16GB) / NUM_TE_PIPES + * (Minimum PB + Maximum PB) < VCE PM address space size (16GB) / NUM_VCE_PIPES + * + * Since the max of NUM_TE_PIPES and NUM_VCE_PIPES is 4, we have a hard limit + * of 4GB minus the Minimum PB. For convenience we take the smaller power-of-2 + * value of 2GB. This is far more than any current applications use. + */ +#define ROGUE_PM_MAX_FREELIST_SIZE SZ_2G + +/* + * Flags supported by the geometry DM command i.e. &struct rogue_fwif_cmd_geom. + */ + +#define ROGUE_GEOM_FLAGS_FIRSTKICK BIT_MASK(0) +#define ROGUE_GEOM_FLAGS_LASTKICK BIT_MASK(1) +/* Use single core in a multi core setup. */ +#define ROGUE_GEOM_FLAGS_SINGLE_CORE BIT_MASK(3) + +/* + * Flags supported by the fragment DM command i.e. &struct rogue_fwif_cmd_frag. + */ + +/* Use single core in a multi core setup. */ +#define ROGUE_FRAG_FLAGS_SINGLE_CORE BIT_MASK(3) +/* Indicates whether this render produces visibility results. */ +#define ROGUE_FRAG_FLAGS_GET_VIS_RESULTS BIT_MASK(5) +/* Indicates whether a depth buffer is present. */ +#define ROGUE_FRAG_FLAGS_DEPTHBUFFER BIT_MASK(7) +/* Indicates whether a stencil buffer is present. */ +#define ROGUE_FRAG_FLAGS_STENCILBUFFER BIT_MASK(8) +/* Disable pixel merging for this render. */ +#define ROGUE_FRAG_FLAGS_DISABLE_PIXELMERGE BIT_MASK(15) +/* Indicates whether a scratch buffer is present. */ +#define ROGUE_FRAG_FLAGS_SCRATCHBUFFER BIT_MASK(19) +/* Disallow compute overlapped with this render. */ +#define ROGUE_FRAG_FLAGS_PREVENT_CDM_OVERLAP BIT_MASK(26) + +/* + * Flags supported by the compute DM command i.e. &struct rogue_fwif_cmd_compute. + */ + +#define ROGUE_COMPUTE_FLAG_PREVENT_ALL_OVERLAP BIT_MASK(2) +/*!< Use single core in a multi core setup. */ +#define ROGUE_COMPUTE_FLAG_SINGLE_CORE BIT_MASK(5) + +/* + * Flags supported by the transfer DM command i.e. &struct rogue_fwif_cmd_transfer. + */ + +/*!< Use single core in a multi core setup. */ +#define ROGUE_TRANSFER_FLAGS_SINGLE_CORE BIT_MASK(1) + +/* + ************************************************ + * Parameter/HWRTData control structures. + ************************************************ + */ + +/* + * Configuration registers which need to be loaded by the firmware before a geometry + * job can be started. + */ +struct rogue_fwif_geom_regs { + u64 vdm_ctrl_stream_base; + u64 tpu_border_colour_table; + + /* Only used when feature VDM_DRAWINDIRECT present. */ + u64 vdm_draw_indirect0; + /* Only used when feature VDM_DRAWINDIRECT present. */ + u32 vdm_draw_indirect1; + + u32 ppp_ctrl; + u32 te_psg; + /* Only used when BRN 49927 present. */ + u32 tpu; + + u32 vdm_context_resume_task0_size; + /* Only used when feature VDM_OBJECT_LEVEL_LLS present. */ + u32 vdm_context_resume_task3_size; + + /* Only used when BRN 56279 or BRN 67381 present. */ + u32 pds_ctrl; + + u32 view_idx; + + /* Only used when feature TESSELLATION present */ + u32 pds_coeff_free_prog; + + u32 padding; +}; + +/* Only used when BRN 44455 or BRN 63027 present. */ +struct rogue_fwif_dummy_rgnhdr_init_geom_regs { + u64 te_psgregion_addr; +}; + +/* + * Represents a geometry command that can be used to tile a whole scene's objects as + * per TA behavior. + */ +struct rogue_fwif_cmd_geom { + /* + * rogue_fwif_cmd_geom_frag_shared field must always be at the beginning of the + * struct. + * + * The command struct (rogue_fwif_cmd_geom) is shared between Client and + * Firmware. Kernel is unable to perform read/write operations on the + * command struct, the SHARED region is the only exception from this rule. + * This region must be the first member so that Kernel can easily access it. + * For more info, see rogue_fwif_cmd_geom_frag_shared definition. + */ + struct rogue_fwif_cmd_geom_frag_shared cmd_shared; + + struct rogue_fwif_geom_regs regs __aligned(8); + u32 flags __aligned(8); + + /* + * Holds the geometry/fragment fence value to allow the fragment partial render command + * to go through. + */ + struct rogue_fwif_ufo partial_render_geom_frag_fence; + + /* Only used when BRN 44455 or BRN 63027 present. */ + struct rogue_fwif_dummy_rgnhdr_init_geom_regs dummy_rgnhdr_init_geom_regs __aligned(8); + + /* Only used when BRN 61484 or BRN 66333 present. */ + u32 brn61484_66333_live_rt; + + u32 padding; +}; + +/* + * Configuration registers which need to be loaded by the firmware before ISP + * can be started. + */ +struct rogue_fwif_frag_regs { + u32 usc_pixel_output_ctrl; + +#define ROGUE_MAXIMUM_OUTPUT_REGISTERS_PER_PIXEL 8U + u32 usc_clear_register[ROGUE_MAXIMUM_OUTPUT_REGISTERS_PER_PIXEL]; + + u32 isp_bgobjdepth; + u32 isp_bgobjvals; + u32 isp_aa; + /* Only used when feature S7_TOP_INFRASTRUCTURE present. */ + u32 isp_xtp_pipe_enable; + + u32 isp_ctl; + + /* Only used when BRN 49927 present. */ + u32 tpu; + + u32 event_pixel_pds_info; + + /* Only used when feature CLUSTER_GROUPING present. */ + u32 pixel_phantom; + + u32 view_idx; + + u32 event_pixel_pds_data; + + /* Only used when BRN 65101 present. */ + u32 brn65101_event_pixel_pds_data; + + /* Only used when feature GPU_MULTICORE_SUPPORT or BRN 47217 present. */ + u32 isp_oclqry_stride; + + /* Only used when feature ZLS_SUBTILE present. */ + u32 isp_zls_pixels; + + /* Only used when feature ISP_ZLS_D24_S8_PACKING_OGL_MODE present. */ + u32 rgx_cr_blackpearl_fix; + + /* All values below the ALIGN(8) must be 64 bit. */ + aligned_u64 isp_scissor_base; + u64 isp_dbias_base; + u64 isp_oclqry_base; + u64 isp_zlsctl; + u64 isp_zload_store_base; + u64 isp_stencil_load_store_base; + + /* + * Only used when feature FBCDC_ALGORITHM present and value < 3 or feature + * FB_CDC_V4 present. Additionally, BRNs 48754, 60227, 72310 and 72311 must + * not be present. + */ + u64 fb_cdc_zls; + +#define ROGUE_PBE_WORDS_REQUIRED_FOR_RENDERS 3U + u64 pbe_word[8U][ROGUE_PBE_WORDS_REQUIRED_FOR_RENDERS]; + u64 tpu_border_colour_table; + u64 pds_bgnd[3U]; + + /* Only used when BRN 65101 present. */ + u64 pds_bgnd_brn65101[3U]; + + u64 pds_pr_bgnd[3U]; + + /* Only used when BRN 62850 or 62865 present. */ + u64 isp_dummy_stencil_store_base; + + /* Only used when BRN 66193 present. */ + u64 isp_dummy_depth_store_base; + + /* Only used when BRN 67182 present. */ + u32 rgnhdr_single_rt_size; + /* Only used when BRN 67182 present. */ + u32 rgnhdr_scratch_offset; +}; + +struct rogue_fwif_cmd_frag { + struct rogue_fwif_cmd_geom_frag_shared cmd_shared __aligned(8); + + struct rogue_fwif_frag_regs regs __aligned(8); + /* command control flags. */ + u32 flags; + /* Stride IN BYTES for Z-Buffer in case of RTAs. */ + u32 zls_stride; + /* Stride IN BYTES for S-Buffer in case of RTAs. */ + u32 sls_stride; + + /* Only used if feature GPU_MULTICORE_SUPPORT present. */ + u32 execute_count; +}; + +/* + * Configuration registers which need to be loaded by the firmware before CDM + * can be started. + */ +struct rogue_fwif_compute_regs { + u64 tpu_border_colour_table; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb_queue; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb_base; + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb; + + /* Only used when feature CDM_USER_MODE_QUEUE is not present. */ + u64 cdm_ctrl_stream_base; + + u64 cdm_context_state_base_addr; + + /* Only used when BRN 49927 is present. */ + u32 tpu; + u32 cdm_resume_pds1; + + /* Only used when feature COMPUTE_MORTON_CAPABLE present. */ + u32 cdm_item; + + /* Only used when feature CLUSTER_GROUPING present. */ + u32 compute_cluster; + + /* Only used when feature TPU_DM_GLOBAL_REGISTERS present. */ + u32 tpu_tag_cdm_ctrl; + + u32 padding; +}; + +struct rogue_fwif_cmd_compute { + /* Common command attributes */ + struct rogue_fwif_cmd_common common __aligned(8); + + /* CDM registers */ + struct rogue_fwif_compute_regs regs; + + /* Control flags */ + u32 flags __aligned(8); + + /* Only used when feature UNIFIED_STORE_VIRTUAL_PARTITIONING present. */ + u32 num_temp_regions; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u32 stream_start_offset; + + /* Only used when feature GPU_MULTICORE_SUPPORT present. */ + u32 execute_count; +}; + +struct rogue_fwif_transfer_regs { + /* + * All 32 bit values should be added in the top section. This then requires only a + * single RGXFW_ALIGN to align all the 64 bit values in the second section. + */ + u32 isp_bgobjvals; + + u32 usc_pixel_output_ctrl; + u32 usc_clear_register0; + u32 usc_clear_register1; + u32 usc_clear_register2; + u32 usc_clear_register3; + + u32 isp_mtile_size; + u32 isp_render_origin; + u32 isp_ctl; + + /* Only used when feature S7_TOP_INFRASTRUCTURE present. */ + u32 isp_xtp_pipe_enable; + u32 isp_aa; + + u32 event_pixel_pds_info; + + u32 event_pixel_pds_code; + u32 event_pixel_pds_data; + + u32 isp_render; + u32 isp_rgn; + + /* Only used when feature GPU_MULTICORE_SUPPORT present. */ + u32 frag_screen; + + /* All values below the aligned_u64 must be 64 bit. */ + aligned_u64 pds_bgnd0_base; + u64 pds_bgnd1_base; + u64 pds_bgnd3_sizeinfo; + + u64 isp_mtile_base; +#define ROGUE_PBE_WORDS_REQUIRED_FOR_TQS 3 + /* TQ_MAX_RENDER_TARGETS * PBE_STATE_SIZE */ + u64 pbe_wordx_mrty[3U * ROGUE_PBE_WORDS_REQUIRED_FOR_TQS]; +}; + +struct rogue_fwif_cmd_transfer { + /* Common command attributes */ + struct rogue_fwif_cmd_common common __aligned(8); + + struct rogue_fwif_transfer_regs regs __aligned(8); + + u32 flags; + + u32 padding; +}; + +#include "pvr_rogue_fwif_client_check.h" + +#endif /* PVR_ROGUE_FWIF_CLIENT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h new file mode 100644 index 000000000000..54aa4474163e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H +#define PVR_ROGUE_FWIF_CLIENT_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0); +OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu_border_colour_table, 8); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_draw_indirect0, 16); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_draw_indirect1, 24); +OFFSET_CHECK(struct rogue_fwif_geom_regs, ppp_ctrl, 28); +OFFSET_CHECK(struct rogue_fwif_geom_regs, te_psg, 32); +OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu, 36); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_context_resume_task0_size, 40); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_context_resume_task3_size, 44); +OFFSET_CHECK(struct rogue_fwif_geom_regs, pds_ctrl, 48); +OFFSET_CHECK(struct rogue_fwif_geom_regs, view_idx, 52); +OFFSET_CHECK(struct rogue_fwif_geom_regs, pds_coeff_free_prog, 56); +SIZE_CHECK(struct rogue_fwif_geom_regs, 64); + +OFFSET_CHECK(struct rogue_fwif_dummy_rgnhdr_init_geom_regs, te_psgregion_addr, 0); +SIZE_CHECK(struct rogue_fwif_dummy_rgnhdr_init_geom_regs, 8); + +OFFSET_CHECK(struct rogue_fwif_cmd_geom, cmd_shared, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, regs, 16); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, flags, 80); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, partial_render_geom_frag_fence, 84); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, dummy_rgnhdr_init_geom_regs, 96); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, brn61484_66333_live_rt, 104); +SIZE_CHECK(struct rogue_fwif_cmd_geom, 112); + +OFFSET_CHECK(struct rogue_fwif_frag_regs, usc_pixel_output_ctrl, 0); +OFFSET_CHECK(struct rogue_fwif_frag_regs, usc_clear_register, 4); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_bgobjdepth, 36); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_bgobjvals, 40); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_aa, 44); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_xtp_pipe_enable, 48); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_ctl, 52); +OFFSET_CHECK(struct rogue_fwif_frag_regs, tpu, 56); +OFFSET_CHECK(struct rogue_fwif_frag_regs, event_pixel_pds_info, 60); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pixel_phantom, 64); +OFFSET_CHECK(struct rogue_fwif_frag_regs, view_idx, 68); +OFFSET_CHECK(struct rogue_fwif_frag_regs, event_pixel_pds_data, 72); +OFFSET_CHECK(struct rogue_fwif_frag_regs, brn65101_event_pixel_pds_data, 76); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_oclqry_stride, 80); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zls_pixels, 84); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgx_cr_blackpearl_fix, 88); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_scissor_base, 96); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dbias_base, 104); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_oclqry_base, 112); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zlsctl, 120); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zload_store_base, 128); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_stencil_load_store_base, 136); +OFFSET_CHECK(struct rogue_fwif_frag_regs, fb_cdc_zls, 144); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pbe_word, 152); +OFFSET_CHECK(struct rogue_fwif_frag_regs, tpu_border_colour_table, 344); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_bgnd, 352); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_bgnd_brn65101, 376); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_pr_bgnd, 400); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dummy_stencil_store_base, 424); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dummy_depth_store_base, 432); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgnhdr_single_rt_size, 440); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgnhdr_scratch_offset, 444); +SIZE_CHECK(struct rogue_fwif_frag_regs, 448); + +OFFSET_CHECK(struct rogue_fwif_cmd_frag, cmd_shared, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, regs, 16); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, flags, 464); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, zls_stride, 468); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, sls_stride, 472); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, execute_count, 476); +SIZE_CHECK(struct rogue_fwif_cmd_frag, 480); + +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu_border_colour_table, 0); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb_queue, 8); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb_base, 16); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb, 24); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_ctrl_stream_base, 32); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_context_state_base_addr, 40); +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu, 48); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_resume_pds1, 52); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_item, 56); +OFFSET_CHECK(struct rogue_fwif_compute_regs, compute_cluster, 60); +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu_tag_cdm_ctrl, 64); +SIZE_CHECK(struct rogue_fwif_compute_regs, 72); + +OFFSET_CHECK(struct rogue_fwif_cmd_compute, common, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, regs, 8); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, flags, 80); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, num_temp_regions, 84); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, stream_start_offset, 88); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, execute_count, 92); +SIZE_CHECK(struct rogue_fwif_cmd_compute, 96); + +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_bgobjvals, 0); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_pixel_output_ctrl, 4); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register0, 8); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register1, 12); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register2, 16); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register3, 20); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_mtile_size, 24); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_render_origin, 28); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_ctl, 32); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_xtp_pipe_enable, 36); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_aa, 40); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_info, 44); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_code, 48); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_data, 52); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_render, 56); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_rgn, 60); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, frag_screen, 64); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd0_base, 72); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd1_base, 80); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd3_sizeinfo, 88); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_mtile_base, 96); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pbe_wordx_mrty, 104); +SIZE_CHECK(struct rogue_fwif_transfer_regs, 176); + +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, common, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, regs, 8); +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, flags, 184); +SIZE_CHECK(struct rogue_fwif_cmd_transfer, 192); + +#endif /* PVR_ROGUE_FWIF_CLIENT_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h new file mode 100644 index 000000000000..6ebb95ba98a6 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_COMMON_H +#define PVR_ROGUE_FWIF_COMMON_H + +#include + +/* + * This macro represents a mask of LSBs that must be zero on data structure + * sizes and offsets to ensure they are 8-byte granular on types shared between + * the FW and host driver. + */ +#define PVR_FW_ALIGNMENT_LSB 7U + +/* Macro to test structure size alignment. */ +#define PVR_FW_STRUCT_SIZE_ASSERT(_a) \ + static_assert((sizeof(_a) & PVR_FW_ALIGNMENT_LSB) == 0U, \ + "Size of " #_a " is not properly aligned") + +/* The master definition for data masters known to the firmware. */ + +#define PVR_FWIF_DM_GP (0) +/* Either TDM or 2D DM is present. */ +/* When the 'tla' feature is present in the hw (as per @pvr_device_features). */ +#define PVR_FWIF_DM_2D (1) +/* + * When the 'fastrender_dm' feature is present in the hw (as per + * @pvr_device_features). + */ +#define PVR_FWIF_DM_TDM (1) + +#define PVR_FWIF_DM_GEOM (2) +#define PVR_FWIF_DM_FRAG (3) +#define PVR_FWIF_DM_CDM (4) +#define PVR_FWIF_DM_RAY (5) +#define PVR_FWIF_DM_GEOM2 (6) +#define PVR_FWIF_DM_GEOM3 (7) +#define PVR_FWIF_DM_GEOM4 (8) + +#define PVR_FWIF_DM_LAST PVR_FWIF_DM_GEOM4 + +/* Maximum number of DM in use: GP, 2D/TDM, GEOM, 3D, CDM, RAY, GEOM2, GEOM3, GEOM4 */ +#define PVR_FWIF_DM_MAX (PVR_FWIF_DM_LAST + 1U) + +/* GPU Utilisation states */ +#define PVR_FWIF_GPU_UTIL_STATE_IDLE 0U +#define PVR_FWIF_GPU_UTIL_STATE_ACTIVE 1U +#define PVR_FWIF_GPU_UTIL_STATE_BLOCKED 2U +#define PVR_FWIF_GPU_UTIL_STATE_NUM 3U +#define PVR_FWIF_GPU_UTIL_STATE_MASK 0x3ULL + +/* + * Maximum amount of register writes that can be done by the register + * programmer (FW or META DMA). This is not a HW limitation, it is only + * a protection against malformed inputs to the register programmer. + */ +#define PVR_MAX_NUM_REGISTER_PROGRAMMER_WRITES 128U + +#endif /* PVR_ROGUE_FWIF_COMMON_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h new file mode 100644 index 000000000000..168277bce948 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef __PVR_ROGUE_FWIF_DEV_INFO_H__ +#define __PVR_ROGUE_FWIF_DEV_INFO_H__ + +enum { + PVR_FW_HAS_BRN_44079 = 0, + PVR_FW_HAS_BRN_47217, + PVR_FW_HAS_BRN_48492, + PVR_FW_HAS_BRN_48545, + PVR_FW_HAS_BRN_49927, + PVR_FW_HAS_BRN_50767, + PVR_FW_HAS_BRN_51764, + PVR_FW_HAS_BRN_62269, + PVR_FW_HAS_BRN_63142, + PVR_FW_HAS_BRN_63553, + PVR_FW_HAS_BRN_66011, + PVR_FW_HAS_BRN_71242, + + PVR_FW_HAS_BRN_MAX +}; + +enum { + PVR_FW_HAS_ERN_35421 = 0, + PVR_FW_HAS_ERN_38020, + PVR_FW_HAS_ERN_38748, + PVR_FW_HAS_ERN_42064, + PVR_FW_HAS_ERN_42290, + PVR_FW_HAS_ERN_42606, + PVR_FW_HAS_ERN_47025, + PVR_FW_HAS_ERN_57596, + + PVR_FW_HAS_ERN_MAX +}; + +enum { + PVR_FW_HAS_FEATURE_AXI_ACELITE = 0, + PVR_FW_HAS_FEATURE_CDM_CONTROL_STREAM_FORMAT, + PVR_FW_HAS_FEATURE_CLUSTER_GROUPING, + PVR_FW_HAS_FEATURE_COMMON_STORE_SIZE_IN_DWORDS, + PVR_FW_HAS_FEATURE_COMPUTE, + PVR_FW_HAS_FEATURE_COMPUTE_MORTON_CAPABLE, + PVR_FW_HAS_FEATURE_COMPUTE_OVERLAP, + PVR_FW_HAS_FEATURE_COREID_PER_OS, + PVR_FW_HAS_FEATURE_DYNAMIC_DUST_POWER, + PVR_FW_HAS_FEATURE_ECC_RAMS, + PVR_FW_HAS_FEATURE_FBCDC, + PVR_FW_HAS_FEATURE_FBCDC_ALGORITHM, + PVR_FW_HAS_FEATURE_FBCDC_ARCHITECTURE, + PVR_FW_HAS_FEATURE_FBC_MAX_DEFAULT_DESCRIPTORS, + PVR_FW_HAS_FEATURE_FBC_MAX_LARGE_DESCRIPTORS, + PVR_FW_HAS_FEATURE_FB_CDC_V4, + PVR_FW_HAS_FEATURE_GPU_MULTICORE_SUPPORT, + PVR_FW_HAS_FEATURE_GPU_VIRTUALISATION, + PVR_FW_HAS_FEATURE_GS_RTA_SUPPORT, + PVR_FW_HAS_FEATURE_IRQ_PER_OS, + PVR_FW_HAS_FEATURE_ISP_MAX_TILES_IN_FLIGHT, + PVR_FW_HAS_FEATURE_ISP_SAMPLES_PER_PIXEL, + PVR_FW_HAS_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE, + PVR_FW_HAS_FEATURE_LAYOUT_MARS, + PVR_FW_HAS_FEATURE_MAX_PARTITIONS, + PVR_FW_HAS_FEATURE_META, + PVR_FW_HAS_FEATURE_META_COREMEM_SIZE, + PVR_FW_HAS_FEATURE_MIPS, + PVR_FW_HAS_FEATURE_NUM_CLUSTERS, + PVR_FW_HAS_FEATURE_NUM_ISP_IPP_PIPES, + PVR_FW_HAS_FEATURE_NUM_OSIDS, + PVR_FW_HAS_FEATURE_NUM_RASTER_PIPES, + PVR_FW_HAS_FEATURE_PBE2_IN_XE, + PVR_FW_HAS_FEATURE_PBVNC_COREID_REG, + PVR_FW_HAS_FEATURE_PERFBUS, + PVR_FW_HAS_FEATURE_PERF_COUNTER_BATCH, + PVR_FW_HAS_FEATURE_PHYS_BUS_WIDTH, + PVR_FW_HAS_FEATURE_RISCV_FW_PROCESSOR, + PVR_FW_HAS_FEATURE_ROGUEXE, + PVR_FW_HAS_FEATURE_S7_TOP_INFRASTRUCTURE, + PVR_FW_HAS_FEATURE_SIMPLE_INTERNAL_PARAMETER_FORMAT, + PVR_FW_HAS_FEATURE_SIMPLE_INTERNAL_PARAMETER_FORMAT_V2, + PVR_FW_HAS_FEATURE_SIMPLE_PARAMETER_FORMAT_VERSION, + PVR_FW_HAS_FEATURE_SLC_BANKS, + PVR_FW_HAS_FEATURE_SLC_CACHE_LINE_SIZE_BITS, + PVR_FW_HAS_FEATURE_SLC_SIZE_CONFIGURABLE, + PVR_FW_HAS_FEATURE_SLC_SIZE_IN_KILOBYTES, + PVR_FW_HAS_FEATURE_SOC_TIMER, + PVR_FW_HAS_FEATURE_SYS_BUS_SECURE_RESET, + PVR_FW_HAS_FEATURE_TESSELLATION, + PVR_FW_HAS_FEATURE_TILE_REGION_PROTECTION, + PVR_FW_HAS_FEATURE_TILE_SIZE_X, + PVR_FW_HAS_FEATURE_TILE_SIZE_Y, + PVR_FW_HAS_FEATURE_TLA, + PVR_FW_HAS_FEATURE_TPU_CEM_DATAMASTER_GLOBAL_REGISTERS, + PVR_FW_HAS_FEATURE_TPU_DM_GLOBAL_REGISTERS, + PVR_FW_HAS_FEATURE_TPU_FILTERING_MODE_CONTROL, + PVR_FW_HAS_FEATURE_USC_MIN_OUTPUT_REGISTERS_PER_PIX, + PVR_FW_HAS_FEATURE_VDM_DRAWINDIRECT, + PVR_FW_HAS_FEATURE_VDM_OBJECT_LEVEL_LLS, + PVR_FW_HAS_FEATURE_VIRTUAL_ADDRESS_SPACE_BITS, + PVR_FW_HAS_FEATURE_WATCHDOG_TIMER, + PVR_FW_HAS_FEATURE_WORKGROUP_PROTECTION, + PVR_FW_HAS_FEATURE_XE_ARCHITECTURE, + PVR_FW_HAS_FEATURE_XE_MEMORY_HIERARCHY, + PVR_FW_HAS_FEATURE_XE_TPU2, + PVR_FW_HAS_FEATURE_XPU_MAX_REGBANKS_ADDR_WIDTH, + PVR_FW_HAS_FEATURE_XPU_MAX_SLAVES, + PVR_FW_HAS_FEATURE_XPU_REGISTER_BROADCAST, + PVR_FW_HAS_FEATURE_XT_TOP_INFRASTRUCTURE, + PVR_FW_HAS_FEATURE_ZLS_SUBTILE, + + PVR_FW_HAS_FEATURE_MAX +}; + +#endif /* __PVR_ROGUE_FWIF_DEV_INFO_H__ */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h new file mode 100644 index 000000000000..1db1f4c532bc --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_RESETFRAMEWORK_H +#define PVR_ROGUE_FWIF_RESETFRAMEWORK_H + +#include +#include + +#include "pvr_rogue_fwif_shared.h" + +struct rogue_fwif_rf_registers { + union { + u64 cdmreg_cdm_cb_base; + u64 cdmreg_cdm_ctrl_stream_base; + }; + u64 cdmreg_cdm_cb_queue; + u64 cdmreg_cdm_cb; +}; + +struct rogue_fwif_rf_cmd { + /* THIS MUST BE THE LAST MEMBER OF THE CONTAINING STRUCTURE */ + struct rogue_fwif_rf_registers fw_registers __aligned(8); +}; + +#define ROGUE_FWIF_RF_CMD_SIZE sizeof(struct rogue_fwif_rf_cmd) + +#endif /* PVR_ROGUE_FWIF_RESETFRAMEWORK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h new file mode 100644 index 000000000000..6c09c15bf9bd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SHARED_H +#define PVR_ROGUE_FWIF_SHARED_H + +#include +#include + +#define ROGUE_FWIF_NUM_RTDATAS 2U +#define ROGUE_FWIF_NUM_GEOMDATAS 1U +#define ROGUE_FWIF_NUM_RTDATA_FREELISTS 2U +#define ROGUE_NUM_GEOM_CORES 1U + +#define ROGUE_NUM_GEOM_CORES_SIZE 2U + +/* + * Maximum number of UFOs in a CCB command. + * The number is based on having 32 sync prims (as originally), plus 32 sync + * checkpoints. + * Once the use of sync prims is no longer supported, we will retain + * the same total (64) as the number of sync checkpoints which may be + * supporting a fence is not visible to the client driver and has to + * allow for the number of different timelines involved in fence merges. + */ +#define ROGUE_FWIF_CCB_CMD_MAX_UFOS (32U + 32U) + +/* + * This is a generic limit imposed on any DM (GEOMETRY,FRAGMENT,CDM,TDM,2D,TRANSFER) + * command passed through the bridge. + * Just across the bridge in the server, any incoming kick command size is + * checked against this maximum limit. + * In case the incoming command size is larger than the specified limit, + * the bridge call is retired with error. + */ +#define ROGUE_FWIF_DM_INDEPENDENT_KICK_CMD_SIZE (1024U) + +#define ROGUE_FWIF_PRBUFFER_START (0) +#define ROGUE_FWIF_PRBUFFER_ZSBUFFER (0) +#define ROGUE_FWIF_PRBUFFER_MSAABUFFER (1) +#define ROGUE_FWIF_PRBUFFER_MAXSUPPORTED (2) + +struct rogue_fwif_dma_addr { + aligned_u64 dev_addr; + u32 fw_addr; + u32 padding; +} __aligned(8); + +struct rogue_fwif_ufo { + u32 addr; + u32 value; +}; + +#define ROGUE_FWIF_UFO_ADDR_IS_SYNC_CHECKPOINT (1) + +struct rogue_fwif_sync_checkpoint { + u32 state; + u32 fw_ref_count; +}; + +struct rogue_fwif_cleanup_ctl { + /* Number of commands received by the FW */ + u32 submitted_commands; + /* Number of commands executed by the FW */ + u32 executed_commands; +} __aligned(8); + +/* + * Used to share frame numbers across UM-KM-FW, + * frame number is set in UM, + * frame number is required in both KM for HTB and FW for FW trace. + * + * May be used to house Kick flags in the future. + */ +struct rogue_fwif_cmd_common { + /* associated frame number */ + u32 frame_num; +}; + +/* + * Geometry and fragment commands require set of firmware addresses that are stored in the Kernel. + * Client has handle(s) to Kernel containers storing these addresses, instead of raw addresses. We + * have to patch/write these addresses in KM to prevent UM from controlling FW addresses directly. + * Typedefs for geometry and fragment commands are shared between Client and Firmware (both + * single-BVNC). Kernel is implemented in a multi-BVNC manner, so it can't use geometry|fragment + * CMD type definitions directly. Therefore we have a SHARED block that is shared between UM-KM-FW + * across all BVNC configurations. + */ +struct rogue_fwif_cmd_geom_frag_shared { + /* Common command attributes */ + struct rogue_fwif_cmd_common cmn; + + /* + * RTData associated with this command, this is used for context + * selection and for storing out HW-context, when TA is switched out for + * continuing later + */ + u32 hwrt_data_fw_addr; + + /* Supported PR Buffers like Z/S/MSAA Scratch */ + u32 pr_buffer_fw_addr[ROGUE_FWIF_PRBUFFER_MAXSUPPORTED]; +}; + +/* + * Client Circular Command Buffer (CCCB) control structure. + * This is shared between the Server and the Firmware and holds byte offsets + * into the CCCB as well as the wrapping mask to aid wrap around. A given + * snapshot of this queue with Cmd 1 running on the GPU might be: + * + * Roff Doff Woff + * [..........|-1----------|=2===|=3===|=4===|~5~~~~|~6~~~~|~7~~~~|..........] + * < runnable commands >< !ready to run > + * + * Cmd 1 : Currently executing on the GPU data master. + * Cmd 2,3,4: Fence dependencies met, commands runnable. + * Cmd 5... : Fence dependency not met yet. + */ +struct rogue_fwif_cccb_ctl { + /* Host write offset into CCB. This must be aligned to 16 bytes. */ + u32 write_offset; + /* + * Firmware read offset into CCB. Points to the command that is runnable + * on GPU, if R!=W + */ + u32 read_offset; + /* + * Firmware fence dependency offset. Points to commands not ready, i.e. + * fence dependencies are not met. + */ + u32 dep_offset; + /* Offset wrapping mask, total capacity in bytes of the CCB-1 */ + u32 wrap_mask; + + /* Only used if SUPPORT_AGP is present. */ + u32 read_offset2; + + /* Only used if SUPPORT_AGP4 is present. */ + u32 read_offset3; + /* Only used if SUPPORT_AGP4 is present. */ + u32 read_offset4; + + u32 padding; +} __aligned(8); + +#define ROGUE_FW_LOCAL_FREELIST (0) +#define ROGUE_FW_GLOBAL_FREELIST (1) +#define ROGUE_FW_FREELIST_TYPE_LAST ROGUE_FW_GLOBAL_FREELIST +#define ROGUE_FW_MAX_FREELISTS (ROGUE_FW_FREELIST_TYPE_LAST + 1U) + +struct rogue_fwif_geom_registers_caswitch { + u64 geom_reg_vdm_context_state_base_addr; + u64 geom_reg_vdm_context_state_resume_addr; + u64 geom_reg_ta_context_state_base_addr; + + struct { + u64 geom_reg_vdm_context_store_task0; + u64 geom_reg_vdm_context_store_task1; + u64 geom_reg_vdm_context_store_task2; + + /* VDM resume state update controls */ + u64 geom_reg_vdm_context_resume_task0; + u64 geom_reg_vdm_context_resume_task1; + u64 geom_reg_vdm_context_resume_task2; + + u64 geom_reg_vdm_context_store_task3; + u64 geom_reg_vdm_context_store_task4; + + u64 geom_reg_vdm_context_resume_task3; + u64 geom_reg_vdm_context_resume_task4; + } geom_state[2]; +}; + +#define ROGUE_FWIF_GEOM_REGISTERS_CSWITCH_SIZE \ + sizeof(struct rogue_fwif_geom_registers_caswitch) + +struct rogue_fwif_cdm_registers_cswitch { + u64 cdmreg_cdm_context_pds0; + u64 cdmreg_cdm_context_pds1; + u64 cdmreg_cdm_terminate_pds; + u64 cdmreg_cdm_terminate_pds1; + + /* CDM resume controls */ + u64 cdmreg_cdm_resume_pds0; + u64 cdmreg_cdm_context_pds0_b; + u64 cdmreg_cdm_resume_pds0_b; +}; + +struct rogue_fwif_static_rendercontext_state { + /* Geom registers for ctx switch */ + struct rogue_fwif_geom_registers_caswitch ctxswitch_regs[ROGUE_NUM_GEOM_CORES_SIZE] + __aligned(8); +}; + +#define ROGUE_FWIF_STATIC_RENDERCONTEXT_SIZE \ + sizeof(struct rogue_fwif_static_rendercontext_state) + +struct rogue_fwif_static_computecontext_state { + /* CDM registers for ctx switch */ + struct rogue_fwif_cdm_registers_cswitch ctxswitch_regs __aligned(8); +}; + +#define ROGUE_FWIF_STATIC_COMPUTECONTEXT_SIZE \ + sizeof(struct rogue_fwif_static_computecontext_state) + +enum rogue_fwif_prbuffer_state { + ROGUE_FWIF_PRBUFFER_UNBACKED = 0, + ROGUE_FWIF_PRBUFFER_BACKED, + ROGUE_FWIF_PRBUFFER_BACKING_PENDING, + ROGUE_FWIF_PRBUFFER_UNBACKING_PENDING, +}; + +struct rogue_fwif_prbuffer { + /* Buffer ID*/ + u32 buffer_id; + /* Needs On-demand Z/S/MSAA Buffer allocation */ + bool on_demand __aligned(4); + /* Z/S/MSAA -Buffer state */ + enum rogue_fwif_prbuffer_state state; + /* Cleanup state */ + struct rogue_fwif_cleanup_ctl cleanup_sate; + /* Compatibility and other flags */ + u32 prbuffer_flags; +} __aligned(8); + +/* Last reset reason for a context. */ +enum rogue_context_reset_reason { + /* No reset reason recorded */ + ROGUE_CONTEXT_RESET_REASON_NONE = 0, + /* Caused a reset due to locking up */ + ROGUE_CONTEXT_RESET_REASON_GUILTY_LOCKUP = 1, + /* Affected by another context locking up */ + ROGUE_CONTEXT_RESET_REASON_INNOCENT_LOCKUP = 2, + /* Overran the global deadline */ + ROGUE_CONTEXT_RESET_REASON_GUILTY_OVERRUNING = 3, + /* Affected by another context overrunning */ + ROGUE_CONTEXT_RESET_REASON_INNOCENT_OVERRUNING = 4, + /* Forced reset to ensure scheduling requirements */ + ROGUE_CONTEXT_RESET_REASON_HARD_CONTEXT_SWITCH = 5, + /* FW Safety watchdog triggered */ + ROGUE_CONTEXT_RESET_REASON_FW_WATCHDOG = 12, + /* FW page fault (no HWR) */ + ROGUE_CONTEXT_RESET_REASON_FW_PAGEFAULT = 13, + /* FW execution error (GPU reset requested) */ + ROGUE_CONTEXT_RESET_REASON_FW_EXEC_ERR = 14, + /* Host watchdog detected FW error */ + ROGUE_CONTEXT_RESET_REASON_HOST_WDG_FW_ERR = 15, + /* Geometry DM OOM event is not allowed */ + ROGUE_CONTEXT_GEOM_OOM_DISABLED = 16, +}; + +struct rogue_context_reset_reason_data { + enum rogue_context_reset_reason reset_reason; + u32 reset_ext_job_ref; +}; + +#include "pvr_rogue_fwif_shared_check.h" + +#endif /* PVR_ROGUE_FWIF_SHARED_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h new file mode 100644 index 000000000000..597ed54bbd3a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H +#define PVR_ROGUE_FWIF_SHARED_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_dma_addr, fw_addr, 8); +SIZE_CHECK(struct rogue_fwif_dma_addr, 16); + +OFFSET_CHECK(struct rogue_fwif_ufo, addr, 0); +OFFSET_CHECK(struct rogue_fwif_ufo, value, 4); +SIZE_CHECK(struct rogue_fwif_ufo, 8); + +OFFSET_CHECK(struct rogue_fwif_cleanup_ctl, submitted_commands, 0); +OFFSET_CHECK(struct rogue_fwif_cleanup_ctl, executed_commands, 4); +SIZE_CHECK(struct rogue_fwif_cleanup_ctl, 8); + +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, write_offset, 0); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset, 4); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, dep_offset, 8); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, wrap_mask, 12); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset2, 16); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset3, 20); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset4, 24); +SIZE_CHECK(struct rogue_fwif_cccb_ctl, 32); + +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_base_addr, 0); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_resume_addr, 8); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_ta_context_state_base_addr, 16); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task0, 24); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task1, 32); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task2, 40); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task0, 48); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task1, 56); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task2, 64); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task3, 72); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task4, 80); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task3, 88); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task4, 96); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task0, 104); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task1, 112); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task2, 120); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task0, 128); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task1, 136); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task2, 144); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task3, 152); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task4, 160); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task3, 168); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task4, 176); +SIZE_CHECK(struct rogue_fwif_geom_registers_caswitch, 184); + +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0, 0); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds1, 8); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds, 16); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds1, 24); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0, 32); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0_b, 40); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0_b, 48); +SIZE_CHECK(struct rogue_fwif_cdm_registers_cswitch, 56); + +OFFSET_CHECK(struct rogue_fwif_static_rendercontext_state, ctxswitch_regs, 0); +SIZE_CHECK(struct rogue_fwif_static_rendercontext_state, 368); + +OFFSET_CHECK(struct rogue_fwif_static_computecontext_state, ctxswitch_regs, 0); +SIZE_CHECK(struct rogue_fwif_static_computecontext_state, 56); + +OFFSET_CHECK(struct rogue_fwif_cmd_common, frame_num, 0); +SIZE_CHECK(struct rogue_fwif_cmd_common, 4); + +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, cmn, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, hwrt_data_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, pr_buffer_fw_addr, 8); +SIZE_CHECK(struct rogue_fwif_cmd_geom_frag_shared, 16); + +#endif /* PVR_ROGUE_FWIF_SHARED_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h new file mode 100644 index 000000000000..1c2c4ebedc25 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_STREAM_H +#define PVR_ROGUE_FWIF_STREAM_H + +/** + * DOC: Streams + * + * Commands are submitted to the kernel driver in the form of streams. + * + * A command stream has the following layout : + * - A 64-bit header containing: + * * A u32 containing the length of the main stream inclusive of the length of the header. + * * A u32 for padding. + * - The main stream data. + * - The extension stream (optional), which is composed of: + * * One or more headers. + * * The extension stream data, corresponding to the extension headers. + * + * The main stream provides the base command data. This has a fixed layout based on the features + * supported by a given GPU. + * + * The extension stream provides the command parameters that are required for BRNs & ERNs for the + * current GPU. This stream is comprised of one or more headers, followed by data for each given + * BRN/ERN. + * + * Each header is a u32 containing a bitmask of quirks & enhancements in the extension stream, a + * "type" field determining the set of quirks & enhancements the bitmask represents, and a + * continuation bit determining whether any more headers are present. The headers are then followed + * by command data; this is specific to each quirk/enhancement. All unused / reserved bits in the + * header must be set to 0. + * + * All parameters and headers in the main and extension streams must be naturally aligned. + * + * If a parameter appears in both the main and extension streams, then the extension parameter is + * used. + */ + +/* + * Stream extension header definition + */ +#define PVR_STREAM_EXTHDR_TYPE_SHIFT 29U +#define PVR_STREAM_EXTHDR_TYPE_MASK (7U << PVR_STREAM_EXTHDR_TYPE_SHIFT) +#define PVR_STREAM_EXTHDR_TYPE_MAX 8U +#define PVR_STREAM_EXTHDR_CONTINUATION BIT(28U) + +#define PVR_STREAM_EXTHDR_DATA_MASK ~(PVR_STREAM_EXTHDR_TYPE_MASK | PVR_STREAM_EXTHDR_CONTINUATION) + +/* + * Stream extension header - Geometry 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_GEOM0 0U + +#define PVR_STREAM_EXTHDR_GEOM0_BRN49927 BIT(0U) + +#define PVR_STREAM_EXTHDR_GEOM0_VALID PVR_STREAM_EXTHDR_GEOM0_BRN49927 + +/* + * Stream extension header - Fragment 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_FRAG0 0U + +#define PVR_STREAM_EXTHDR_FRAG0_BRN47217 BIT(0U) +#define PVR_STREAM_EXTHDR_FRAG0_BRN49927 BIT(1U) + +#define PVR_STREAM_EXTHDR_FRAG0_VALID PVR_STREAM_EXTHDR_FRAG0_BRN49927 + +/* + * Stream extension header - Compute 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_COMPUTE0 0U + +#define PVR_STREAM_EXTHDR_COMPUTE0_BRN49927 BIT(0U) + +#define PVR_STREAM_EXTHDR_COMPUTE0_VALID PVR_STREAM_EXTHDR_COMPUTE0_BRN49927 + +#endif /* PVR_ROGUE_FWIF_STREAM_H */ From f99f5f3ea7efd54ba0529c4f2d7c72712918a522 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:31 +0000 Subject: [PATCH 1182/7721] drm/imagination: Add GPU ID parsing and firmware loading Read the GPU ID register at probe time and select the correct features/quirks/enhancements. Use the GPU ID to form the firmware file name and load the firmware. The features/quirks/enhancements arrays are currently hardcoded in the driver for the supported GPUs. We are looking at moving this information to the firmware image. Changes since v8: - Corrected license identifiers Changes since v7: - Fix kerneldoc for pvr_device_info_set_enhancements() Changes since v5: - Add BRN 71242 to device info Changes since v4: - Retrieve device information from firmware header - Pull forward firmware header parsing from FW infrastructure patch - Use devm_add_action_or_reset to release firmware Changes since v3: - Use drm_dev_{enter,exit} Co-developed-by: Frank Binns Signed-off-by: Frank Binns Co-developed-by: Matt Coster Signed-off-by: Matt Coster Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Link: https://lore.kernel.org/r/1ff76f7a5b45c742279c78910f8491b8a5e7f6e6.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 2 + drivers/gpu/drm/imagination/pvr_device.c | 323 ++++++++++- drivers/gpu/drm/imagination/pvr_device.h | 220 ++++++++ drivers/gpu/drm/imagination/pvr_device_info.c | 254 +++++++++ drivers/gpu/drm/imagination/pvr_device_info.h | 186 +++++++ drivers/gpu/drm/imagination/pvr_drv.c | 521 +++++++++++++++++- drivers/gpu/drm/imagination/pvr_drv.h | 107 ++++ drivers/gpu/drm/imagination/pvr_fw.c | 145 +++++ drivers/gpu/drm/imagination/pvr_fw.h | 34 ++ drivers/gpu/drm/imagination/pvr_fw_info.h | 135 +++++ 10 files changed, 1925 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_device_info.c create mode 100644 drivers/gpu/drm/imagination/pvr_device_info.h create mode 100644 drivers/gpu/drm/imagination/pvr_fw.c create mode 100644 drivers/gpu/drm/imagination/pvr_fw.h create mode 100644 drivers/gpu/drm/imagination/pvr_fw_info.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index d36007f2825c..0b863e9f51b8 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -5,6 +5,8 @@ subdir-ccflags-y := -I$(srctree)/$(src) powervr-y := \ pvr_device.o \ + pvr_device_info.o \ pvr_drv.o \ + pvr_fw.o obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index abcdf733f57b..05e382cacb27 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -2,19 +2,31 @@ /* Copyright (c) 2023 Imagination Technologies Ltd. */ #include "pvr_device.h" +#include "pvr_device_info.h" + +#include "pvr_fw.h" +#include "pvr_rogue_cr_defs.h" #include +#include #include #include #include #include #include +#include #include +#include #include +#include #include #include #include +#include + +/* Major number for the supported version of the firmware. */ +#define PVR_FW_VERSION_MAJOR 1 /** * pvr_device_reg_init() - Initialize kernel access to a PowerVR device's @@ -100,6 +112,209 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev) return 0; } +/** + * pvr_build_firmware_filename() - Construct a PowerVR firmware filename + * @pvr_dev: Target PowerVR device. + * @base: First part of the filename. + * @major: Major version number. + * + * A PowerVR firmware filename consists of three parts separated by underscores + * (``'_'``) along with a '.fw' file suffix. The first part is the exact value + * of @base, the second part is the hardware version string derived from @pvr_fw + * and the final part is the firmware version number constructed from @major with + * a 'v' prefix, e.g. powervr/rogue_4.40.2.51_v1.fw. + * + * The returned string will have been slab allocated and must be freed with + * kfree(). + * + * Return: + * * The constructed filename on success, or + * * Any error returned by kasprintf(). + */ +static char * +pvr_build_firmware_filename(struct pvr_device *pvr_dev, const char *base, + u8 major) +{ + struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; + + return kasprintf(GFP_KERNEL, "%s_%d.%d.%d.%d_v%d.fw", base, gpu_id->b, + gpu_id->v, gpu_id->n, gpu_id->c, major); +} + +static void +pvr_release_firmware(void *data) +{ + struct pvr_device *pvr_dev = data; + + release_firmware(pvr_dev->fw_dev.firmware); +} + +/** + * pvr_request_firmware() - Load firmware for a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * See pvr_build_firmware_filename() for details on firmware file naming. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_build_firmware_filename(), or + * * Any error returned by request_firmware(). + */ +static int +pvr_request_firmware(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = &pvr_dev->base; + char *filename; + const struct firmware *fw; + int err; + + filename = pvr_build_firmware_filename(pvr_dev, "powervr/rogue", + PVR_FW_VERSION_MAJOR); + if (IS_ERR(filename)) + return PTR_ERR(filename); + + /* + * This function takes a copy of &filename, meaning we can free our + * instance before returning. + */ + err = request_firmware(&fw, filename, pvr_dev->base.dev); + if (err) { + drm_err(drm_dev, "failed to load firmware %s (err=%d)\n", + filename, err); + goto err_free_filename; + } + + drm_info(drm_dev, "loaded firmware %s\n", filename); + kfree(filename); + + pvr_dev->fw_dev.firmware = fw; + + return devm_add_action_or_reset(drm_dev->dev, pvr_release_firmware, pvr_dev); + +err_free_filename: + kfree(filename); + + return err; +} + +/** + * pvr_load_gpu_id() - Load a PowerVR device's GPU ID (BVNC) from control registers. + * + * Sets struct pvr_dev.gpu_id. + * + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_load_gpu_id(struct pvr_device *pvr_dev) +{ + struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; + u64 bvnc; + + /* + * Try reading the BVNC using the newer (cleaner) method first. If the + * B value is zero, fall back to the older method. + */ + bvnc = pvr_cr_read64(pvr_dev, ROGUE_CR_CORE_ID__PBVNC); + + gpu_id->b = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__BRANCH_ID); + if (gpu_id->b != 0) { + gpu_id->v = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__VERSION_ID); + gpu_id->n = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS); + gpu_id->c = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__CONFIG_ID); + } else { + u32 core_rev = pvr_cr_read32(pvr_dev, ROGUE_CR_CORE_REVISION); + u32 core_id = pvr_cr_read32(pvr_dev, ROGUE_CR_CORE_ID); + u16 core_id_config = PVR_CR_FIELD_GET(core_id, CORE_ID_CONFIG); + + gpu_id->b = PVR_CR_FIELD_GET(core_rev, CORE_REVISION_MAJOR); + gpu_id->v = PVR_CR_FIELD_GET(core_rev, CORE_REVISION_MINOR); + gpu_id->n = FIELD_GET(0xFF00, core_id_config); + gpu_id->c = FIELD_GET(0x00FF, core_id_config); + } +} + +/** + * pvr_set_dma_info() - Set PowerVR device DMA information + * @pvr_dev: Target PowerVR device. + * + * Sets the DMA mask and max segment size for the PowerVR device. + * + * Return: + * * 0 on success, + * * Any error returned by PVR_FEATURE_VALUE(), or + * * Any error returned by dma_set_mask(). + */ + +static int +pvr_set_dma_info(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u16 phys_bus_width; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width); + if (err) { + drm_err(drm_dev, "Failed to get device physical bus width\n"); + return err; + } + + err = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(phys_bus_width)); + if (err) { + drm_err(drm_dev, "Failed to set DMA mask (err=%d)\n", err); + return err; + } + + dma_set_max_seg_size(drm_dev->dev, UINT_MAX); + + return 0; +} + +/** + * pvr_device_gpu_init() - GPU-specific initialization for a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * The following steps are taken to ensure the device is ready: + * + * 1. Read the hardware version information from control registers, + * 2. Initialise the hardware feature information, + * 3. Setup the device DMA information, + * 4. Setup the device-scoped memory context, and + * 5. Load firmware into the device. + * + * Return: + * * 0 on success, + * * -%ENODEV if the GPU is not supported, + * * Any error returned by pvr_set_dma_info(), + * * Any error returned by pvr_memory_context_init(), or + * * Any error returned by pvr_request_firmware(). + */ +static int +pvr_device_gpu_init(struct pvr_device *pvr_dev) +{ + int err; + + pvr_load_gpu_id(pvr_dev); + + err = pvr_request_firmware(pvr_dev); + if (err) + return err; + + err = pvr_fw_validate_init_device_info(pvr_dev); + if (err) + return err; + + if (PVR_HAS_FEATURE(pvr_dev, meta)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_META; + else if (PVR_HAS_FEATURE(pvr_dev, mips)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_MIPS; + else if (PVR_HAS_FEATURE(pvr_dev, riscv_fw_processor)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_RISCV; + else + return -EINVAL; + + return pvr_set_dma_info(pvr_dev); +} + /** * pvr_device_init() - Initialize a PowerVR device * @pvr_dev: Target PowerVR device. @@ -130,7 +345,12 @@ pvr_device_init(struct pvr_device *pvr_dev) return err; /* Map the control registers into memory. */ - return pvr_device_reg_init(pvr_dev); + err = pvr_device_reg_init(pvr_dev); + if (err) + return err; + + /* Perform GPU-specific initialization steps. */ + return pvr_device_gpu_init(pvr_dev); } /** @@ -145,3 +365,104 @@ pvr_device_fini(struct pvr_device *pvr_dev) * the initialization stages in pvr_device_init(). */ } + +bool +pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk) +{ + switch (quirk) { + case 47217: + return PVR_HAS_QUIRK(pvr_dev, 47217); + case 48545: + return PVR_HAS_QUIRK(pvr_dev, 48545); + case 49927: + return PVR_HAS_QUIRK(pvr_dev, 49927); + case 51764: + return PVR_HAS_QUIRK(pvr_dev, 51764); + case 62269: + return PVR_HAS_QUIRK(pvr_dev, 62269); + default: + return false; + }; +} + +bool +pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement) +{ + switch (enhancement) { + case 35421: + return PVR_HAS_ENHANCEMENT(pvr_dev, 35421); + case 42064: + return PVR_HAS_ENHANCEMENT(pvr_dev, 42064); + default: + return false; + }; +} + +/** + * pvr_device_has_feature() - Look up device feature based on feature definition + * @pvr_dev: Device pointer. + * @feature: Feature to look up. Should be one of %PVR_FEATURE_*. + * + * Returns: + * * %true if feature is present on device, or + * * %false if feature is not present on device. + */ +bool +pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature) +{ + switch (feature) { + case PVR_FEATURE_CLUSTER_GROUPING: + return PVR_HAS_FEATURE(pvr_dev, cluster_grouping); + + case PVR_FEATURE_COMPUTE_MORTON_CAPABLE: + return PVR_HAS_FEATURE(pvr_dev, compute_morton_capable); + + case PVR_FEATURE_FB_CDC_V4: + return PVR_HAS_FEATURE(pvr_dev, fb_cdc_v4); + + case PVR_FEATURE_GPU_MULTICORE_SUPPORT: + return PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support); + + case PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE: + return PVR_HAS_FEATURE(pvr_dev, isp_zls_d24_s8_packing_ogl_mode); + + case PVR_FEATURE_S7_TOP_INFRASTRUCTURE: + return PVR_HAS_FEATURE(pvr_dev, s7_top_infrastructure); + + case PVR_FEATURE_TESSELLATION: + return PVR_HAS_FEATURE(pvr_dev, tessellation); + + case PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS: + return PVR_HAS_FEATURE(pvr_dev, tpu_dm_global_registers); + + case PVR_FEATURE_VDM_DRAWINDIRECT: + return PVR_HAS_FEATURE(pvr_dev, vdm_drawindirect); + + case PVR_FEATURE_VDM_OBJECT_LEVEL_LLS: + return PVR_HAS_FEATURE(pvr_dev, vdm_object_level_lls); + + case PVR_FEATURE_ZLS_SUBTILE: + return PVR_HAS_FEATURE(pvr_dev, zls_subtile); + + /* Derived features. */ + case PVR_FEATURE_CDM_USER_MODE_QUEUE: { + u8 cdm_control_stream_format = 0; + + PVR_FEATURE_VALUE(pvr_dev, cdm_control_stream_format, &cdm_control_stream_format); + return (cdm_control_stream_format >= 2 && cdm_control_stream_format <= 4); + } + + case PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP: + if (PVR_HAS_FEATURE(pvr_dev, fbcdc_algorithm)) { + u8 fbcdc_algorithm = 0; + + PVR_FEATURE_VALUE(pvr_dev, fbcdc_algorithm, &fbcdc_algorithm); + return (fbcdc_algorithm < 3 || PVR_HAS_FEATURE(pvr_dev, fb_cdc_v4)); + } + return false; + + default: + WARN(true, "Looking up undefined feature %u\n", feature); + return false; + } +} diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index d9d2804f4454..36fe67bed27f 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -4,6 +4,9 @@ #ifndef PVR_DEVICE_H #define PVR_DEVICE_H +#include "pvr_device_info.h" +#include "pvr_fw.h" + #include #include #include @@ -28,6 +31,26 @@ struct clk; /* Forward declaration from . */ struct firmware; +/** + * struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device + * @b: Branch ID. + * @v: Version ID. + * @n: Number of scalable units. + * @c: Config ID. + */ +struct pvr_gpu_id { + u16 b, v, n, c; +}; + +/** + * struct pvr_fw_version - Firmware version information + * @major: Major version number. + * @minor: Minor version number. + */ +struct pvr_fw_version { + u16 major, minor; +}; + /** * struct pvr_device - powervr-specific wrapper for &struct drm_device */ @@ -40,6 +63,35 @@ struct pvr_device { */ struct drm_device base; + /** @gpu_id: GPU ID detected at runtime. */ + struct pvr_gpu_id gpu_id; + + /** + * @features: Hardware feature information. + * + * Do not access this member directly, instead use PVR_HAS_FEATURE() + * or PVR_FEATURE_VALUE() macros. + */ + struct pvr_device_features features; + + /** + * @quirks: Hardware quirk information. + * + * Do not access this member directly, instead use PVR_HAS_QUIRK(). + */ + struct pvr_device_quirks quirks; + + /** + * @enhancements: Hardware enhancement information. + * + * Do not access this member directly, instead use + * PVR_HAS_ENHANCEMENT(). + */ + struct pvr_device_enhancements enhancements; + + /** @fw_version: Firmware version detected at runtime. */ + struct pvr_fw_version fw_version; + /** * @regs: Device control registers. * @@ -70,6 +122,9 @@ struct pvr_device { * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk. */ struct clk *mem_clk; + + /** @fw_dev: Firmware related data. */ + struct pvr_fw_device fw_dev; }; /** @@ -92,6 +147,76 @@ struct pvr_file { struct pvr_device *pvr_dev; }; +/** + * PVR_HAS_FEATURE() - Tests whether a PowerVR device has a given feature + * @pvr_dev: [IN] Target PowerVR device. + * @feature: [IN] Hardware feature name. + * + * Feature names are derived from those found in &struct pvr_device_features by + * dropping the 'has_' prefix, which is applied by this macro. + * + * Return: + * * true if the named feature is present in the hardware + * * false if the named feature is not present in the hardware + */ +#define PVR_HAS_FEATURE(pvr_dev, feature) ((pvr_dev)->features.has_##feature) + +/** + * PVR_FEATURE_VALUE() - Gets a PowerVR device feature value + * @pvr_dev: [IN] Target PowerVR device. + * @feature: [IN] Feature name. + * @value_out: [OUT] Feature value. + * + * This macro will get a feature value for those features that have values. + * If the feature is not present, nothing will be stored to @value_out. + * + * Feature names are derived from those found in &struct pvr_device_features by + * dropping the 'has_' prefix. + * + * Return: + * * 0 on success, or + * * -%EINVAL if the named feature is not present in the hardware + */ +#define PVR_FEATURE_VALUE(pvr_dev, feature, value_out) \ + ({ \ + struct pvr_device *_pvr_dev = pvr_dev; \ + int _ret = -EINVAL; \ + if (_pvr_dev->features.has_##feature) { \ + *(value_out) = _pvr_dev->features.feature; \ + _ret = 0; \ + } \ + _ret; \ + }) + +/** + * PVR_HAS_QUIRK() - Tests whether a physical device has a given quirk + * @pvr_dev: [IN] Target PowerVR device. + * @quirk: [IN] Hardware quirk name. + * + * Quirk numbers are derived from those found in #pvr_device_quirks by + * dropping the 'has_brn' prefix, which is applied by this macro. + * + * Returns + * * true if the quirk is present in the hardware, or + * * false if the quirk is not present in the hardware. + */ +#define PVR_HAS_QUIRK(pvr_dev, quirk) ((pvr_dev)->quirks.has_brn##quirk) + +/** + * PVR_HAS_ENHANCEMENT() - Tests whether a physical device has a given + * enhancement + * @pvr_dev: [IN] Target PowerVR device. + * @enhancement: [IN] Hardware enhancement name. + * + * Enhancement numbers are derived from those found in #pvr_device_enhancements + * by dropping the 'has_ern' prefix, which is applied by this macro. + * + * Returns + * * true if the enhancement is present in the hardware, or + * * false if the enhancement is not present in the hardware. + */ +#define PVR_HAS_ENHANCEMENT(pvr_dev, enhancement) ((pvr_dev)->enhancements.has_ern##enhancement) + #define from_pvr_device(pvr_dev) (&(pvr_dev)->base) #define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base) @@ -100,9 +225,77 @@ struct pvr_file { #define to_pvr_file(file) ((file)->driver_priv) +/** + * PVR_PACKED_BVNC() - Packs B, V, N and C values into a 64-bit unsigned integer + * @b: Branch ID. + * @v: Version ID. + * @n: Number of scalable units. + * @c: Config ID. + * + * The packed layout is as follows: + * + * +--------+--------+--------+-------+ + * | 63..48 | 47..32 | 31..16 | 15..0 | + * +========+========+========+=======+ + * | B | V | N | C | + * +--------+--------+--------+-------+ + * + * pvr_gpu_id_to_packed_bvnc() should be used instead of this macro when a + * &struct pvr_gpu_id is available in order to ensure proper type checking. + * + * Return: Packed BVNC. + */ +/* clang-format off */ +#define PVR_PACKED_BVNC(b, v, n, c) \ + ((((u64)(b) & GENMASK_ULL(15, 0)) << 48) | \ + (((u64)(v) & GENMASK_ULL(15, 0)) << 32) | \ + (((u64)(n) & GENMASK_ULL(15, 0)) << 16) | \ + (((u64)(c) & GENMASK_ULL(15, 0)) << 0)) +/* clang-format on */ + +/** + * pvr_gpu_id_to_packed_bvnc() - Packs B, V, N and C values into a 64-bit + * unsigned integer + * @gpu_id: GPU ID. + * + * The packed layout is as follows: + * + * +--------+--------+--------+-------+ + * | 63..48 | 47..32 | 31..16 | 15..0 | + * +========+========+========+=======+ + * | B | V | N | C | + * +--------+--------+--------+-------+ + * + * This should be used in preference to PVR_PACKED_BVNC() when a &struct + * pvr_gpu_id is available in order to ensure proper type checking. + * + * Return: Packed BVNC. + */ +static __always_inline u64 +pvr_gpu_id_to_packed_bvnc(struct pvr_gpu_id *gpu_id) +{ + return PVR_PACKED_BVNC(gpu_id->b, gpu_id->v, gpu_id->n, gpu_id->c); +} + +static __always_inline void +packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id) +{ + gpu_id->b = (bvnc & GENMASK_ULL(63, 48)) >> 48; + gpu_id->v = (bvnc & GENMASK_ULL(47, 32)) >> 32; + gpu_id->n = (bvnc & GENMASK_ULL(31, 16)) >> 16; + gpu_id->c = bvnc & GENMASK_ULL(15, 0); +} + int pvr_device_init(struct pvr_device *pvr_dev); void pvr_device_fini(struct pvr_device *pvr_dev); +bool +pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk); +bool +pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement); +bool +pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature); + /** * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register * @val: Value of the target register. @@ -208,6 +401,29 @@ pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value, (value & reg_mask) == reg_value, 0, timeout_usec); } +/** + * pvr_round_up_to_cacheline_size() - Round up a provided size to be cacheline + * aligned + * @pvr_dev: Target PowerVR device. + * @size: Initial size, in bytes. + * + * Returns: + * * Size aligned to cacheline size. + */ +static __always_inline size_t +pvr_round_up_to_cacheline_size(struct pvr_device *pvr_dev, size_t size) +{ + u16 slc_cacheline_size_bits = 0; + u16 slc_cacheline_size_bytes; + + WARN_ON(!PVR_HAS_FEATURE(pvr_dev, slc_cache_line_size_bits)); + PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, + &slc_cacheline_size_bits); + slc_cacheline_size_bytes = slc_cacheline_size_bits / 8; + + return round_up(size, slc_cacheline_size_bytes); +} + /** * DOC: IOCTL validation helpers * @@ -302,4 +518,8 @@ pvr_ioctl_union_padding_check(void *instance, size_t union_offset, __union_size, __member_size); \ }) +#define PVR_FW_PROCESSOR_TYPE_META 0 +#define PVR_FW_PROCESSOR_TYPE_MIPS 1 +#define PVR_FW_PROCESSOR_TYPE_RISCV 2 + #endif /* PVR_DEVICE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device_info.c b/drivers/gpu/drm/imagination/pvr_device_info.c new file mode 100644 index 000000000000..11e6bef52ecd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device_info.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_device_info.h" +#include "pvr_rogue_fwif_dev_info.h" + +#include + +#include +#include +#include +#include + +#define QUIRK_MAPPING(quirk) \ + [PVR_FW_HAS_BRN_##quirk] = offsetof(struct pvr_device, quirks.has_brn##quirk) + +static const uintptr_t quirks_mapping[] = { + QUIRK_MAPPING(44079), + QUIRK_MAPPING(47217), + QUIRK_MAPPING(48492), + QUIRK_MAPPING(48545), + QUIRK_MAPPING(49927), + QUIRK_MAPPING(50767), + QUIRK_MAPPING(51764), + QUIRK_MAPPING(62269), + QUIRK_MAPPING(63142), + QUIRK_MAPPING(63553), + QUIRK_MAPPING(66011), + QUIRK_MAPPING(71242), +}; + +#undef QUIRK_MAPPING + +#define ENHANCEMENT_MAPPING(enhancement) \ + [PVR_FW_HAS_ERN_##enhancement] = offsetof(struct pvr_device, \ + enhancements.has_ern##enhancement) + +static const uintptr_t enhancements_mapping[] = { + ENHANCEMENT_MAPPING(35421), + ENHANCEMENT_MAPPING(38020), + ENHANCEMENT_MAPPING(38748), + ENHANCEMENT_MAPPING(42064), + ENHANCEMENT_MAPPING(42290), + ENHANCEMENT_MAPPING(42606), + ENHANCEMENT_MAPPING(47025), + ENHANCEMENT_MAPPING(57596), +}; + +#undef ENHANCEMENT_MAPPING + +static void pvr_device_info_set_common(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_size, const uintptr_t *mapping, u32 mapping_max) +{ + const u32 mapping_max_size = (mapping_max + 63) >> 6; + const u32 nr_bits = min(bitmask_size * 64, mapping_max); + + /* Warn if any unsupported values in the bitmask. */ + if (bitmask_size > mapping_max_size) { + if (mapping == quirks_mapping) + drm_warn(from_pvr_device(pvr_dev), "Unsupported quirks in firmware image"); + else + drm_warn(from_pvr_device(pvr_dev), + "Unsupported enhancements in firmware image"); + } else if (bitmask_size == mapping_max_size && (mapping_max & 63)) { + u64 invalid_mask = ~0ull << (mapping_max & 63); + + if (bitmask[bitmask_size - 1] & invalid_mask) { + if (mapping == quirks_mapping) + drm_warn(from_pvr_device(pvr_dev), + "Unsupported quirks in firmware image"); + else + drm_warn(from_pvr_device(pvr_dev), + "Unsupported enhancements in firmware image"); + } + } + + for (u32 i = 0; i < nr_bits; i++) { + if (bitmask[i >> 6] & BIT_ULL(i & 63)) + *(bool *)((u8 *)pvr_dev + mapping[i]) = true; + } +} + +/** + * pvr_device_info_set_quirks() - Set device quirks from device information in firmware + * @pvr_dev: Device pointer. + * @quirks: Pointer to quirks mask in device information. + * @quirks_size: Size of quirks mask, in u64s. + */ +void pvr_device_info_set_quirks(struct pvr_device *pvr_dev, const u64 *quirks, u32 quirks_size) +{ + BUILD_BUG_ON(ARRAY_SIZE(quirks_mapping) != PVR_FW_HAS_BRN_MAX); + + pvr_device_info_set_common(pvr_dev, quirks, quirks_size, quirks_mapping, + ARRAY_SIZE(quirks_mapping)); +} + +/** + * pvr_device_info_set_enhancements() - Set device enhancements from device information in firmware + * @pvr_dev: Device pointer. + * @enhancements: Pointer to enhancements mask in device information. + * @enhancements_size: Size of enhancements mask, in u64s. + */ +void pvr_device_info_set_enhancements(struct pvr_device *pvr_dev, const u64 *enhancements, + u32 enhancements_size) +{ + BUILD_BUG_ON(ARRAY_SIZE(enhancements_mapping) != PVR_FW_HAS_ERN_MAX); + + pvr_device_info_set_common(pvr_dev, enhancements, enhancements_size, + enhancements_mapping, ARRAY_SIZE(enhancements_mapping)); +} + +#define FEATURE_MAPPING(fw_feature, feature) \ + [PVR_FW_HAS_FEATURE_##fw_feature] = { \ + .flag_offset = offsetof(struct pvr_device, features.has_##feature), \ + .value_offset = 0 \ + } + +#define FEATURE_MAPPING_VALUE(fw_feature, feature) \ + [PVR_FW_HAS_FEATURE_##fw_feature] = { \ + .flag_offset = offsetof(struct pvr_device, features.has_##feature), \ + .value_offset = offsetof(struct pvr_device, features.feature) \ + } + +static const struct { + uintptr_t flag_offset; + uintptr_t value_offset; +} features_mapping[] = { + FEATURE_MAPPING(AXI_ACELITE, axi_acelite), + FEATURE_MAPPING_VALUE(CDM_CONTROL_STREAM_FORMAT, cdm_control_stream_format), + FEATURE_MAPPING(CLUSTER_GROUPING, cluster_grouping), + FEATURE_MAPPING_VALUE(COMMON_STORE_SIZE_IN_DWORDS, common_store_size_in_dwords), + FEATURE_MAPPING(COMPUTE, compute), + FEATURE_MAPPING(COMPUTE_MORTON_CAPABLE, compute_morton_capable), + FEATURE_MAPPING(COMPUTE_OVERLAP, compute_overlap), + FEATURE_MAPPING(COREID_PER_OS, coreid_per_os), + FEATURE_MAPPING(DYNAMIC_DUST_POWER, dynamic_dust_power), + FEATURE_MAPPING_VALUE(ECC_RAMS, ecc_rams), + FEATURE_MAPPING_VALUE(FBCDC, fbcdc), + FEATURE_MAPPING_VALUE(FBCDC_ALGORITHM, fbcdc_algorithm), + FEATURE_MAPPING_VALUE(FBCDC_ARCHITECTURE, fbcdc_architecture), + FEATURE_MAPPING_VALUE(FBC_MAX_DEFAULT_DESCRIPTORS, fbc_max_default_descriptors), + FEATURE_MAPPING_VALUE(FBC_MAX_LARGE_DESCRIPTORS, fbc_max_large_descriptors), + FEATURE_MAPPING(FB_CDC_V4, fb_cdc_v4), + FEATURE_MAPPING(GPU_MULTICORE_SUPPORT, gpu_multicore_support), + FEATURE_MAPPING(GPU_VIRTUALISATION, gpu_virtualisation), + FEATURE_MAPPING(GS_RTA_SUPPORT, gs_rta_support), + FEATURE_MAPPING(IRQ_PER_OS, irq_per_os), + FEATURE_MAPPING_VALUE(ISP_MAX_TILES_IN_FLIGHT, isp_max_tiles_in_flight), + FEATURE_MAPPING_VALUE(ISP_SAMPLES_PER_PIXEL, isp_samples_per_pixel), + FEATURE_MAPPING(ISP_ZLS_D24_S8_PACKING_OGL_MODE, isp_zls_d24_s8_packing_ogl_mode), + FEATURE_MAPPING_VALUE(LAYOUT_MARS, layout_mars), + FEATURE_MAPPING_VALUE(MAX_PARTITIONS, max_partitions), + FEATURE_MAPPING_VALUE(META, meta), + FEATURE_MAPPING_VALUE(META_COREMEM_SIZE, meta_coremem_size), + FEATURE_MAPPING(MIPS, mips), + FEATURE_MAPPING_VALUE(NUM_CLUSTERS, num_clusters), + FEATURE_MAPPING_VALUE(NUM_ISP_IPP_PIPES, num_isp_ipp_pipes), + FEATURE_MAPPING_VALUE(NUM_OSIDS, num_osids), + FEATURE_MAPPING_VALUE(NUM_RASTER_PIPES, num_raster_pipes), + FEATURE_MAPPING(PBE2_IN_XE, pbe2_in_xe), + FEATURE_MAPPING(PBVNC_COREID_REG, pbvnc_coreid_reg), + FEATURE_MAPPING(PERFBUS, perfbus), + FEATURE_MAPPING(PERF_COUNTER_BATCH, perf_counter_batch), + FEATURE_MAPPING_VALUE(PHYS_BUS_WIDTH, phys_bus_width), + FEATURE_MAPPING(RISCV_FW_PROCESSOR, riscv_fw_processor), + FEATURE_MAPPING(ROGUEXE, roguexe), + FEATURE_MAPPING(S7_TOP_INFRASTRUCTURE, s7_top_infrastructure), + FEATURE_MAPPING(SIMPLE_INTERNAL_PARAMETER_FORMAT, simple_internal_parameter_format), + FEATURE_MAPPING(SIMPLE_INTERNAL_PARAMETER_FORMAT_V2, simple_internal_parameter_format_v2), + FEATURE_MAPPING_VALUE(SIMPLE_PARAMETER_FORMAT_VERSION, simple_parameter_format_version), + FEATURE_MAPPING_VALUE(SLC_BANKS, slc_banks), + FEATURE_MAPPING_VALUE(SLC_CACHE_LINE_SIZE_BITS, slc_cache_line_size_bits), + FEATURE_MAPPING(SLC_SIZE_CONFIGURABLE, slc_size_configurable), + FEATURE_MAPPING_VALUE(SLC_SIZE_IN_KILOBYTES, slc_size_in_kilobytes), + FEATURE_MAPPING(SOC_TIMER, soc_timer), + FEATURE_MAPPING(SYS_BUS_SECURE_RESET, sys_bus_secure_reset), + FEATURE_MAPPING(TESSELLATION, tessellation), + FEATURE_MAPPING(TILE_REGION_PROTECTION, tile_region_protection), + FEATURE_MAPPING_VALUE(TILE_SIZE_X, tile_size_x), + FEATURE_MAPPING_VALUE(TILE_SIZE_Y, tile_size_y), + FEATURE_MAPPING(TLA, tla), + FEATURE_MAPPING(TPU_CEM_DATAMASTER_GLOBAL_REGISTERS, tpu_cem_datamaster_global_registers), + FEATURE_MAPPING(TPU_DM_GLOBAL_REGISTERS, tpu_dm_global_registers), + FEATURE_MAPPING(TPU_FILTERING_MODE_CONTROL, tpu_filtering_mode_control), + FEATURE_MAPPING_VALUE(USC_MIN_OUTPUT_REGISTERS_PER_PIX, usc_min_output_registers_per_pix), + FEATURE_MAPPING(VDM_DRAWINDIRECT, vdm_drawindirect), + FEATURE_MAPPING(VDM_OBJECT_LEVEL_LLS, vdm_object_level_lls), + FEATURE_MAPPING_VALUE(VIRTUAL_ADDRESS_SPACE_BITS, virtual_address_space_bits), + FEATURE_MAPPING(WATCHDOG_TIMER, watchdog_timer), + FEATURE_MAPPING(WORKGROUP_PROTECTION, workgroup_protection), + FEATURE_MAPPING_VALUE(XE_ARCHITECTURE, xe_architecture), + FEATURE_MAPPING(XE_MEMORY_HIERARCHY, xe_memory_hierarchy), + FEATURE_MAPPING(XE_TPU2, xe_tpu2), + FEATURE_MAPPING_VALUE(XPU_MAX_REGBANKS_ADDR_WIDTH, xpu_max_regbanks_addr_width), + FEATURE_MAPPING_VALUE(XPU_MAX_SLAVES, xpu_max_slaves), + FEATURE_MAPPING_VALUE(XPU_REGISTER_BROADCAST, xpu_register_broadcast), + FEATURE_MAPPING(XT_TOP_INFRASTRUCTURE, xt_top_infrastructure), + FEATURE_MAPPING(ZLS_SUBTILE, zls_subtile), +}; + +#undef FEATURE_MAPPING_VALUE +#undef FEATURE_MAPPING + +/** + * pvr_device_info_set_features() - Set device features from device information in firmware + * @pvr_dev: Device pointer. + * @features: Pointer to features mask in device information. + * @features_size: Size of features mask, in u64s. + * @feature_param_size: Size of feature parameters, in u64s. + * + * Returns: + * * 0 on success, or + * * -%EINVAL on malformed stream. + */ +int pvr_device_info_set_features(struct pvr_device *pvr_dev, const u64 *features, u32 features_size, + u32 feature_param_size) +{ + const u32 mapping_max = ARRAY_SIZE(features_mapping); + const u32 mapping_max_size = (mapping_max + 63) >> 6; + const u32 nr_bits = min(features_size * 64, mapping_max); + const u64 *feature_params = features + features_size; + u32 param_idx = 0; + + BUILD_BUG_ON(ARRAY_SIZE(features_mapping) != PVR_FW_HAS_FEATURE_MAX); + + /* Verify no unsupported values in the bitmask. */ + if (features_size > mapping_max_size) { + drm_warn(from_pvr_device(pvr_dev), "Unsupported features in firmware image"); + } else if (features_size == mapping_max_size && (mapping_max & 63)) { + u64 invalid_mask = ~0ull << (mapping_max & 63); + + if (features[features_size - 1] & invalid_mask) + drm_warn(from_pvr_device(pvr_dev), + "Unsupported features in firmware image"); + } + + for (u32 i = 0; i < nr_bits; i++) { + if (features[i >> 6] & BIT_ULL(i & 63)) { + *(bool *)((u8 *)pvr_dev + features_mapping[i].flag_offset) = true; + + if (features_mapping[i].value_offset) { + if (param_idx >= feature_param_size) + return -EINVAL; + + *(u64 *)((u8 *)pvr_dev + features_mapping[i].value_offset) = + feature_params[param_idx]; + param_idx++; + } + } + } + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_device_info.h b/drivers/gpu/drm/imagination/pvr_device_info.h new file mode 100644 index 000000000000..f61fb988b553 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device_info.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEVICE_INFO_H +#define PVR_DEVICE_INFO_H + +#include + +struct pvr_device; + +/* + * struct pvr_device_features - Hardware feature information + */ +struct pvr_device_features { + bool has_axi_acelite; + bool has_cdm_control_stream_format; + bool has_cluster_grouping; + bool has_common_store_size_in_dwords; + bool has_compute; + bool has_compute_morton_capable; + bool has_compute_overlap; + bool has_coreid_per_os; + bool has_dynamic_dust_power; + bool has_ecc_rams; + bool has_fb_cdc_v4; + bool has_fbc_max_default_descriptors; + bool has_fbc_max_large_descriptors; + bool has_fbcdc; + bool has_fbcdc_algorithm; + bool has_fbcdc_architecture; + bool has_gpu_multicore_support; + bool has_gpu_virtualisation; + bool has_gs_rta_support; + bool has_irq_per_os; + bool has_isp_max_tiles_in_flight; + bool has_isp_samples_per_pixel; + bool has_isp_zls_d24_s8_packing_ogl_mode; + bool has_layout_mars; + bool has_max_partitions; + bool has_meta; + bool has_meta_coremem_size; + bool has_mips; + bool has_num_clusters; + bool has_num_isp_ipp_pipes; + bool has_num_osids; + bool has_num_raster_pipes; + bool has_pbe2_in_xe; + bool has_pbvnc_coreid_reg; + bool has_perfbus; + bool has_perf_counter_batch; + bool has_phys_bus_width; + bool has_riscv_fw_processor; + bool has_roguexe; + bool has_s7_top_infrastructure; + bool has_simple_internal_parameter_format; + bool has_simple_internal_parameter_format_v2; + bool has_simple_parameter_format_version; + bool has_slc_banks; + bool has_slc_cache_line_size_bits; + bool has_slc_size_configurable; + bool has_slc_size_in_kilobytes; + bool has_soc_timer; + bool has_sys_bus_secure_reset; + bool has_tessellation; + bool has_tile_region_protection; + bool has_tile_size_x; + bool has_tile_size_y; + bool has_tla; + bool has_tpu_cem_datamaster_global_registers; + bool has_tpu_dm_global_registers; + bool has_tpu_filtering_mode_control; + bool has_usc_min_output_registers_per_pix; + bool has_vdm_drawindirect; + bool has_vdm_object_level_lls; + bool has_virtual_address_space_bits; + bool has_watchdog_timer; + bool has_workgroup_protection; + bool has_xe_architecture; + bool has_xe_memory_hierarchy; + bool has_xe_tpu2; + bool has_xpu_max_regbanks_addr_width; + bool has_xpu_max_slaves; + bool has_xpu_register_broadcast; + bool has_xt_top_infrastructure; + bool has_zls_subtile; + + u64 cdm_control_stream_format; + u64 common_store_size_in_dwords; + u64 ecc_rams; + u64 fbc_max_default_descriptors; + u64 fbc_max_large_descriptors; + u64 fbcdc; + u64 fbcdc_algorithm; + u64 fbcdc_architecture; + u64 isp_max_tiles_in_flight; + u64 isp_samples_per_pixel; + u64 layout_mars; + u64 max_partitions; + u64 meta; + u64 meta_coremem_size; + u64 num_clusters; + u64 num_isp_ipp_pipes; + u64 num_osids; + u64 num_raster_pipes; + u64 phys_bus_width; + u64 simple_parameter_format_version; + u64 slc_banks; + u64 slc_cache_line_size_bits; + u64 slc_size_in_kilobytes; + u64 tile_size_x; + u64 tile_size_y; + u64 usc_min_output_registers_per_pix; + u64 virtual_address_space_bits; + u64 xe_architecture; + u64 xpu_max_regbanks_addr_width; + u64 xpu_max_slaves; + u64 xpu_register_broadcast; +}; + +/* + * struct pvr_device_quirks - Hardware quirk information + */ +struct pvr_device_quirks { + bool has_brn44079; + bool has_brn47217; + bool has_brn48492; + bool has_brn48545; + bool has_brn49927; + bool has_brn50767; + bool has_brn51764; + bool has_brn62269; + bool has_brn63142; + bool has_brn63553; + bool has_brn66011; + bool has_brn71242; +}; + +/* + * struct pvr_device_enhancements - Hardware enhancement information + */ +struct pvr_device_enhancements { + bool has_ern35421; + bool has_ern38020; + bool has_ern38748; + bool has_ern42064; + bool has_ern42290; + bool has_ern42606; + bool has_ern47025; + bool has_ern57596; +}; + +void pvr_device_info_set_quirks(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_len); +void pvr_device_info_set_enhancements(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_len); +int pvr_device_info_set_features(struct pvr_device *pvr_dev, const u64 *features, u32 features_size, + u32 feature_param_size); + +/* + * Meta cores + * + * These are the values for the 'meta' feature when the feature is present + * (as per &struct pvr_device_features)/ + */ +#define PVR_META_MTP218 (1) +#define PVR_META_MTP219 (2) +#define PVR_META_LTP218 (3) +#define PVR_META_LTP217 (4) + +enum { + PVR_FEATURE_CDM_USER_MODE_QUEUE, + PVR_FEATURE_CLUSTER_GROUPING, + PVR_FEATURE_COMPUTE_MORTON_CAPABLE, + PVR_FEATURE_FB_CDC_V4, + PVR_FEATURE_GPU_MULTICORE_SUPPORT, + PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE, + PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE, + PVR_FEATURE_TESSELLATION, + PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS, + PVR_FEATURE_VDM_DRAWINDIRECT, + PVR_FEATURE_VDM_OBJECT_LEVEL_LLS, + PVR_FEATURE_ZLS_SUBTILE, +}; + +#endif /* PVR_DEVICE_INFO_H */ diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 597188b31f96..1e4408f33e94 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -3,6 +3,9 @@ #include "pvr_device.h" #include "pvr_drv.h" +#include "pvr_rogue_defs.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_rogue_fwif_shared.h" #include @@ -87,6 +90,382 @@ pvr_ioctl_get_bo_mmap_offset(struct drm_device *drm_dev, void *raw_args, return -ENOTTY; } +static __always_inline u64 +pvr_fw_version_packed(u32 major, u32 minor) +{ + return ((u64)major << 32) | minor; +} + +static u32 +rogue_get_common_store_partition_space_size(struct pvr_device *pvr_dev) +{ + u32 max_partitions = 0; + u32 tile_size_x = 0; + u32 tile_size_y = 0; + + PVR_FEATURE_VALUE(pvr_dev, tile_size_x, &tile_size_x); + PVR_FEATURE_VALUE(pvr_dev, tile_size_y, &tile_size_y); + PVR_FEATURE_VALUE(pvr_dev, max_partitions, &max_partitions); + + if (tile_size_x == 16 && tile_size_y == 16) { + u32 usc_min_output_registers_per_pix = 0; + + PVR_FEATURE_VALUE(pvr_dev, usc_min_output_registers_per_pix, + &usc_min_output_registers_per_pix); + + return tile_size_x * tile_size_y * max_partitions * + usc_min_output_registers_per_pix; + } + + return max_partitions * 1024; +} + +static u32 +rogue_get_common_store_alloc_region_size(struct pvr_device *pvr_dev) +{ + u32 common_store_size_in_dwords = 512 * 4 * 4; + u32 alloc_region_size; + + PVR_FEATURE_VALUE(pvr_dev, common_store_size_in_dwords, &common_store_size_in_dwords); + + alloc_region_size = common_store_size_in_dwords - (256U * 4U) - + rogue_get_common_store_partition_space_size(pvr_dev); + + if (PVR_HAS_QUIRK(pvr_dev, 44079)) { + u32 common_store_split_point = (768U * 4U * 4U); + + return min(common_store_split_point - (256U * 4U), alloc_region_size); + } + + return alloc_region_size; +} + +static inline u32 +rogue_get_num_phantoms(struct pvr_device *pvr_dev) +{ + u32 num_clusters = 1; + + PVR_FEATURE_VALUE(pvr_dev, num_clusters, &num_clusters); + + return ROGUE_REQ_NUM_PHANTOMS(num_clusters); +} + +static inline u32 +rogue_get_max_coeffs(struct pvr_device *pvr_dev) +{ + u32 max_coeff_additional_portion = ROGUE_MAX_VERTEX_SHARED_REGISTERS; + u32 pending_allocation_shared_regs = 2U * 1024U; + u32 pending_allocation_coeff_regs = 0U; + u32 num_phantoms = rogue_get_num_phantoms(pvr_dev); + u32 tiles_in_flight = 0; + u32 max_coeff_pixel_portion; + + PVR_FEATURE_VALUE(pvr_dev, isp_max_tiles_in_flight, &tiles_in_flight); + max_coeff_pixel_portion = DIV_ROUND_UP(tiles_in_flight, num_phantoms); + max_coeff_pixel_portion *= ROGUE_MAX_PIXEL_SHARED_REGISTERS; + + /* + * Compute tasks on cores with BRN48492 and without compute overlap may lock + * up without two additional lines of coeffs. + */ + if (PVR_HAS_QUIRK(pvr_dev, 48492) && !PVR_HAS_FEATURE(pvr_dev, compute_overlap)) + pending_allocation_coeff_regs = 2U * 1024U; + + if (PVR_HAS_ENHANCEMENT(pvr_dev, 38748)) + pending_allocation_shared_regs = 0; + + if (PVR_HAS_ENHANCEMENT(pvr_dev, 38020)) + max_coeff_additional_portion += ROGUE_MAX_COMPUTE_SHARED_REGISTERS; + + return rogue_get_common_store_alloc_region_size(pvr_dev) + pending_allocation_coeff_regs - + (max_coeff_pixel_portion + max_coeff_additional_portion + + pending_allocation_shared_regs); +} + +static inline u32 +rogue_get_cdm_max_local_mem_size_regs(struct pvr_device *pvr_dev) +{ + u32 available_coeffs_in_dwords = rogue_get_max_coeffs(pvr_dev); + + if (PVR_HAS_QUIRK(pvr_dev, 48492) && PVR_HAS_FEATURE(pvr_dev, roguexe) && + !PVR_HAS_FEATURE(pvr_dev, compute_overlap)) { + /* Driver must not use the 2 reserved lines. */ + available_coeffs_in_dwords -= ROGUE_CSRM_LINE_SIZE_IN_DWORDS * 2; + } + + /* + * The maximum amount of local memory available to a kernel is the minimum + * of the total number of coefficient registers available and the max common + * store allocation size which can be made by the CDM. + * + * If any coeff lines are reserved for tessellation or pixel then we need to + * subtract those too. + */ + return min(available_coeffs_in_dwords, (u32)ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS); +} + +/** + * pvr_dev_query_gpu_info_get() + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_gpu_info. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * + * Returns: + * * 0 on success, or if size is requested using a NULL pointer, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_gpu_info_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_gpu_info gpu_info = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_gpu_info); + return 0; + } + + gpu_info.gpu_id = + pvr_gpu_id_to_packed_bvnc(&pvr_dev->gpu_id); + gpu_info.num_phantoms = rogue_get_num_phantoms(pvr_dev); + + err = PVR_UOBJ_SET(args->pointer, args->size, gpu_info); + if (err < 0) + return err; + + if (args->size > sizeof(gpu_info)) + args->size = sizeof(gpu_info); + return 0; +} + +/** + * pvr_dev_query_runtime_info_get() + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_runtime_info. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * + * Returns: + * * 0 on success, or if size is requested using a NULL pointer, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_runtime_info_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_runtime_info runtime_info = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_runtime_info); + return 0; + } + + runtime_info.free_list_min_pages = 0; /* FIXME */ + runtime_info.free_list_max_pages = + ROGUE_PM_MAX_FREELIST_SIZE / ROGUE_PM_PAGE_SIZE; + runtime_info.common_store_alloc_region_size = + rogue_get_common_store_alloc_region_size(pvr_dev); + runtime_info.common_store_partition_space_size = + rogue_get_common_store_partition_space_size(pvr_dev); + runtime_info.max_coeffs = rogue_get_max_coeffs(pvr_dev); + runtime_info.cdm_max_local_mem_size_regs = + rogue_get_cdm_max_local_mem_size_regs(pvr_dev); + + err = PVR_UOBJ_SET(args->pointer, args->size, runtime_info); + if (err < 0) + return err; + + if (args->size > sizeof(runtime_info)) + args->size = sizeof(runtime_info); + return 0; +} + +/** + * pvr_dev_query_quirks_get() - Unpack array of quirks at the address given + * in a struct drm_pvr_dev_query_quirks, or gets the amount of space required + * for it. + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_query_quirks. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * If the userspace pointer in the query object is NULL, or the count is + * short, no data is copied. + * The count field will be updated to that copied, or if either pointer is + * NULL, that which would have been copied. + * The size field in the query object will be updated to the size copied. + * + * Returns: + * * 0 on success, or if size/count is requested using a NULL pointer, or + * * -%EINVAL if args contained non-zero reserved fields, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_quirks_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + /* + * @FIXME - hardcoding of numbers here is intended as an + * intermediate step so the UAPI can be fixed, but requires a + * a refactor in the future to store them in a more appropriate + * location + */ + static const u32 umd_quirks_musthave[] = { + 47217, + 49927, + 62269, + }; + static const u32 umd_quirks[] = { + 48545, + 51764, + }; + struct drm_pvr_dev_query_quirks query; + u32 out[ARRAY_SIZE(umd_quirks_musthave) + ARRAY_SIZE(umd_quirks)]; + size_t out_musthave_count = 0; + size_t out_count = 0; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_quirks); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + + if (err < 0) + return err; + if (query._padding_c) + return -EINVAL; + + for (int i = 0; i < ARRAY_SIZE(umd_quirks_musthave); i++) { + if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks_musthave[i])) { + out[out_count++] = umd_quirks_musthave[i]; + out_musthave_count++; + } + } + + for (int i = 0; i < ARRAY_SIZE(umd_quirks); i++) { + if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks[i])) + out[out_count++] = umd_quirks[i]; + } + + if (!query.quirks) + goto copy_out; + if (query.count < out_count) + return -E2BIG; + + if (copy_to_user(u64_to_user_ptr(query.quirks), out, + out_count * sizeof(u32))) { + return -EFAULT; + } + + query.musthave_count = out_musthave_count; + +copy_out: + query.count = out_count; + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +/** + * pvr_dev_query_enhancements_get() - Unpack array of enhancements at the + * address given in a struct drm_pvr_dev_query_enhancements, or gets the amount + * of space required for it. + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_enhancements. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * If the userspace pointer in the query object is NULL, or the count is + * short, no data is copied. + * The count field will be updated to that copied, or if either pointer is + * NULL, that which would have been copied. + * The size field in the query object will be updated to the size copied. + * + * Returns: + * * 0 on success, or if size/count is requested using a NULL pointer, or + * * -%EINVAL if args contained non-zero reserved fields, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_enhancements_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + /* + * @FIXME - hardcoding of numbers here is intended as an + * intermediate step so the UAPI can be fixed, but requires a + * a refactor in the future to store them in a more appropriate + * location + */ + const u32 umd_enhancements[] = { + 35421, + 42064, + }; + struct drm_pvr_dev_query_enhancements query; + u32 out[ARRAY_SIZE(umd_enhancements)]; + size_t out_idx = 0; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_enhancements); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + + if (err < 0) + return err; + if (query._padding_a) + return -EINVAL; + if (query._padding_c) + return -EINVAL; + + for (int i = 0; i < ARRAY_SIZE(umd_enhancements); i++) { + if (pvr_device_has_uapi_enhancement(pvr_dev, umd_enhancements[i])) + out[out_idx++] = umd_enhancements[i]; + } + + if (!query.enhancements) + goto copy_out; + if (query.count < out_idx) + return -E2BIG; + + if (copy_to_user(u64_to_user_ptr(query.enhancements), out, + out_idx * sizeof(u32))) { + return -EFAULT; + } + +copy_out: + query.count = out_idx; + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + /** * pvr_ioctl_dev_query() - IOCTL to copy information about a device * @drm_dev: [IN] DRM device. @@ -111,7 +490,41 @@ static int pvr_ioctl_dev_query(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct drm_pvr_ioctl_dev_query_args *args = raw_args; + int idx; + int ret = -EINVAL; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + switch ((enum drm_pvr_dev_query)args->type) { + case DRM_PVR_DEV_QUERY_GPU_INFO_GET: + ret = pvr_dev_query_gpu_info_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET: + ret = pvr_dev_query_runtime_info_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_QUIRKS_GET: + ret = pvr_dev_query_quirks_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_ENHANCEMENTS_GET: + ret = pvr_dev_query_enhancements_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_HEAP_INFO_GET: + return -EINVAL; + + case DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET: + return -EINVAL; + } + + drm_dev_exit(idx); + + return ret; } /** @@ -349,6 +762,112 @@ pvr_ioctl_submit_jobs(struct drm_device *drm_dev, void *raw_args, return -ENOTTY; } +int +pvr_get_uobj(u64 usr_ptr, u32 usr_stride, u32 min_stride, u32 obj_size, void *out) +{ + if (usr_stride < min_stride) + return -EINVAL; + + return copy_struct_from_user(out, obj_size, u64_to_user_ptr(usr_ptr), usr_stride); +} + +int +pvr_set_uobj(u64 usr_ptr, u32 usr_stride, u32 min_stride, u32 obj_size, const void *in) +{ + if (usr_stride < min_stride) + return -EINVAL; + + if (copy_to_user(u64_to_user_ptr(usr_ptr), in, min_t(u32, usr_stride, obj_size))) + return -EFAULT; + + if (usr_stride > obj_size && + clear_user(u64_to_user_ptr(usr_ptr + obj_size), usr_stride - obj_size)) { + return -EFAULT; + } + + return 0; +} + +int +pvr_get_uobj_array(const struct drm_pvr_obj_array *in, u32 min_stride, u32 obj_size, void **out) +{ + int ret = 0; + void *out_alloc; + + if (in->stride < min_stride) + return -EINVAL; + + if (!in->count) + return 0; + + out_alloc = kvmalloc_array(in->count, obj_size, GFP_KERNEL); + if (!out_alloc) + return -ENOMEM; + + if (obj_size == in->stride) { + if (copy_from_user(out_alloc, u64_to_user_ptr(in->array), + (unsigned long)obj_size * in->count)) + ret = -EFAULT; + } else { + void __user *in_ptr = u64_to_user_ptr(in->array); + void *out_ptr = out_alloc; + + for (u32 i = 0; i < in->count; i++) { + ret = copy_struct_from_user(out_ptr, obj_size, in_ptr, in->stride); + if (ret) + break; + + out_ptr += obj_size; + in_ptr += in->stride; + } + } + + if (ret) { + kvfree(out_alloc); + return ret; + } + + *out = out_alloc; + return 0; +} + +int +pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_size, + const void *in) +{ + if (out->stride < min_stride) + return -EINVAL; + + if (!out->count) + return 0; + + if (obj_size == out->stride) { + if (copy_to_user(u64_to_user_ptr(out->array), in, + (unsigned long)obj_size * out->count)) + return -EFAULT; + } else { + u32 cpy_elem_size = min_t(u32, out->stride, obj_size); + void __user *out_ptr = u64_to_user_ptr(out->array); + const void *in_ptr = in; + + for (u32 i = 0; i < out->count; i++) { + if (copy_to_user(out_ptr, in_ptr, cpy_elem_size)) + return -EFAULT; + + out_ptr += obj_size; + in_ptr += out->stride; + } + + if (out->stride > obj_size && + clear_user(u64_to_user_ptr(out->array + obj_size), + out->stride - obj_size)) { + return -EFAULT; + } + } + + return 0; +} + #define DRM_PVR_IOCTL(_name, _func, _flags) \ DRM_IOCTL_DEF_DRV(PVR_##_name, pvr_ioctl_##_func, _flags) diff --git a/drivers/gpu/drm/imagination/pvr_drv.h b/drivers/gpu/drm/imagination/pvr_drv.h index c29d11af88fe..378fe477b759 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.h +++ b/drivers/gpu/drm/imagination/pvr_drv.h @@ -19,4 +19,111 @@ #define PVR_DRIVER_MINOR 0 #define PVR_DRIVER_PATCHLEVEL 0 +int pvr_get_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 obj_size, void *out); +int pvr_set_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 obj_size, const void *in); +int pvr_get_uobj_array(const struct drm_pvr_obj_array *in, u32 min_stride, u32 obj_size, + void **out); +int pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_size, + const void *in); + +#define PVR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) \ + (offsetof(_typename, _last_mandatory_field) + \ + sizeof(((_typename *)NULL)->_last_mandatory_field)) + +/* NOLINTBEGIN(bugprone-macro-parentheses) */ +#define PVR_UOBJ_DECL(_typename, _last_mandatory_field) \ + , _typename : PVR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) +/* NOLINTEND(bugprone-macro-parentheses) */ + +/** + * DOC: PVR user objects. + * + * Macros used to aid copying structured and array data to and from + * userspace. Objects can differ in size, provided the minimum size + * allowed is specified (using the last mandatory field in the struct). + * All types used with PVR_UOBJ_GET/SET macros must be listed here under + * PVR_UOBJ_MIN_SIZE, with the last mandatory struct field specified. + */ + +/** + * PVR_UOBJ_MIN_SIZE() - Fetch the minimum copy size of a compatible type object. + * @_obj_name: The name of the object. Cannot be a typename - this is deduced. + * + * This cannot fail. Using the macro with an incompatible type will result in a + * compiler error. + * + * To add compatibility for a type, list it within the macro in an orderly + * fashion. The second argument is the name of the last mandatory field of the + * struct type, which is used to calculate the size. See also PVR_UOBJ_DECL(). + * + * Return: The minimum copy size. + */ +#define PVR_UOBJ_MIN_SIZE(_obj_name) _Generic(_obj_name \ + PVR_UOBJ_DECL(struct drm_pvr_job, hwrt) \ + PVR_UOBJ_DECL(struct drm_pvr_sync_op, value) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_gpu_info, num_phantoms) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_runtime_info, cdm_max_local_mem_size_regs) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_quirks, _padding_c) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_enhancements, _padding_c) \ + PVR_UOBJ_DECL(struct drm_pvr_heap, page_size_log2) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_heap_info, heaps) \ + PVR_UOBJ_DECL(struct drm_pvr_static_data_area, offset) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_static_data_areas, static_data_areas) \ + ) + +/** + * PVR_UOBJ_GET() - Copies from _src_usr_ptr to &_dest_obj. + * @_dest_obj: The destination container object in kernel space. + * @_usr_size: The size of the source container in user space. + * @_src_usr_ptr: __u64 raw pointer to the source container in user space. + * + * Return: Error code. See pvr_get_uobj(). + */ +#define PVR_UOBJ_GET(_dest_obj, _usr_size, _src_usr_ptr) \ + pvr_get_uobj(_src_usr_ptr, _usr_size, \ + PVR_UOBJ_MIN_SIZE(_dest_obj), \ + sizeof(_dest_obj), &(_dest_obj)) + +/** + * PVR_UOBJ_SET() - Copies from &_src_obj to _dest_usr_ptr. + * @_dest_usr_ptr: __u64 raw pointer to the destination container in user space. + * @_usr_size: The size of the destination container in user space. + * @_src_obj: The source container object in kernel space. + * + * Return: Error code. See pvr_set_uobj(). + */ +#define PVR_UOBJ_SET(_dest_usr_ptr, _usr_size, _src_obj) \ + pvr_set_uobj(_dest_usr_ptr, _usr_size, \ + PVR_UOBJ_MIN_SIZE(_src_obj), \ + sizeof(_src_obj), &(_src_obj)) + +/** + * PVR_UOBJ_GET_ARRAY() - Copies from @_src_drm_pvr_obj_array.array to + * alloced memory and returns a pointer in _dest_array. + * @_dest_array: The destination C array object in kernel space. + * @_src_drm_pvr_obj_array: The &struct drm_pvr_obj_array containing a __u64 raw + * pointer to the source C array in user space and the size of each array + * element in user space (the 'stride'). + * + * Return: Error code. See pvr_get_uobj_array(). + */ +#define PVR_UOBJ_GET_ARRAY(_dest_array, _src_drm_pvr_obj_array) \ + pvr_get_uobj_array(_src_drm_pvr_obj_array, \ + PVR_UOBJ_MIN_SIZE((_dest_array)[0]), \ + sizeof((_dest_array)[0]), (void **)&(_dest_array)) + +/** + * PVR_UOBJ_SET_ARRAY() - Copies from _src_array to @_dest_drm_pvr_obj_array.array. + * @_dest_drm_pvr_obj_array: The &struct drm_pvr_obj_array containing a __u64 raw + * pointer to the destination C array in user space and the size of each array + * element in user space (the 'stride'). + * @_src_array: The source C array object in kernel space. + * + * Return: Error code. See pvr_set_uobj_array(). + */ +#define PVR_UOBJ_SET_ARRAY(_dest_drm_pvr_obj_array, _src_array) \ + pvr_set_uobj_array(_dest_drm_pvr_obj_array, \ + PVR_UOBJ_MIN_SIZE((_src_array)[0]), \ + sizeof((_src_array)[0]), _src_array) + #endif /* PVR_DRV_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c new file mode 100644 index 000000000000..a9377c735c9c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_device_info.h" +#include "pvr_fw.h" + +#include +#include +#include + +#define FW_MAX_SUPPORTED_MAJOR_VERSION 1 + +/** + * pvr_fw_validate() - Parse firmware header and check compatibility + * @pvr_dev: Device pointer. + * + * Returns: + * * 0 on success, or + * * -EINVAL if firmware is incompatible. + */ +static int +pvr_fw_validate(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + const struct firmware *firmware = pvr_dev->fw_dev.firmware; + const struct pvr_fw_layout_entry *layout_entries; + const struct pvr_fw_info_header *header; + const u8 *fw = firmware->data; + u32 fw_offset = firmware->size - SZ_4K; + u32 layout_table_size; + u32 entry; + + if (firmware->size < SZ_4K || (firmware->size % FW_BLOCK_SIZE)) + return -EINVAL; + + header = (const struct pvr_fw_info_header *)&fw[fw_offset]; + + if (header->info_version != PVR_FW_INFO_VERSION) { + drm_err(drm_dev, "Unsupported fw info version %u\n", + header->info_version); + return -EINVAL; + } + + if (header->header_len != sizeof(struct pvr_fw_info_header) || + header->layout_entry_size != sizeof(struct pvr_fw_layout_entry) || + header->layout_entry_num > PVR_FW_INFO_MAX_NUM_ENTRIES) { + drm_err(drm_dev, "FW info format mismatch\n"); + return -EINVAL; + } + + if (!(header->flags & PVR_FW_FLAGS_OPEN_SOURCE) || + header->fw_version_major > FW_MAX_SUPPORTED_MAJOR_VERSION || + header->fw_version_major == 0) { + drm_err(drm_dev, "Unsupported FW version %u.%u (build: %u%s)\n", + header->fw_version_major, header->fw_version_minor, + header->fw_version_build, + (header->flags & PVR_FW_FLAGS_OPEN_SOURCE) ? " OS" : ""); + return -EINVAL; + } + + if (pvr_gpu_id_to_packed_bvnc(&pvr_dev->gpu_id) != header->bvnc) { + struct pvr_gpu_id fw_gpu_id; + + packed_bvnc_to_pvr_gpu_id(header->bvnc, &fw_gpu_id); + drm_err(drm_dev, "FW built for incorrect GPU ID %i.%i.%i.%i (expected %i.%i.%i.%i)\n", + fw_gpu_id.b, fw_gpu_id.v, fw_gpu_id.n, fw_gpu_id.c, + pvr_dev->gpu_id.b, pvr_dev->gpu_id.v, pvr_dev->gpu_id.n, pvr_dev->gpu_id.c); + return -EINVAL; + } + + fw_offset += header->header_len; + layout_table_size = + header->layout_entry_size * header->layout_entry_num; + if ((fw_offset + layout_table_size) > firmware->size) + return -EINVAL; + + layout_entries = (const struct pvr_fw_layout_entry *)&fw[fw_offset]; + for (entry = 0; entry < header->layout_entry_num; entry++) { + u32 start_addr = layout_entries[entry].base_addr; + u32 end_addr = start_addr + layout_entries[entry].alloc_size; + + if (start_addr >= end_addr) + return -EINVAL; + } + + fw_offset = (firmware->size - SZ_4K) - header->device_info_size; + + drm_info(drm_dev, "FW version v%u.%u (build %u OS)\n", header->fw_version_major, + header->fw_version_minor, header->fw_version_build); + + pvr_dev->fw_version.major = header->fw_version_major; + pvr_dev->fw_version.minor = header->fw_version_minor; + + pvr_dev->fw_dev.header = header; + pvr_dev->fw_dev.layout_entries = layout_entries; + + return 0; +} + +static int +pvr_fw_get_device_info(struct pvr_device *pvr_dev) +{ + const struct firmware *firmware = pvr_dev->fw_dev.firmware; + struct pvr_fw_device_info_header *header; + const u8 *fw = firmware->data; + const u64 *dev_info; + u32 fw_offset; + + fw_offset = (firmware->size - SZ_4K) - pvr_dev->fw_dev.header->device_info_size; + + header = (struct pvr_fw_device_info_header *)&fw[fw_offset]; + dev_info = (u64 *)(header + 1); + + pvr_device_info_set_quirks(pvr_dev, dev_info, header->brn_mask_size); + dev_info += header->brn_mask_size; + + pvr_device_info_set_enhancements(pvr_dev, dev_info, header->ern_mask_size); + dev_info += header->ern_mask_size; + + return pvr_device_info_set_features(pvr_dev, dev_info, header->feature_mask_size, + header->feature_param_size); +} + +/** + * pvr_fw_validate_init_device_info() - Validate firmware and initialise device information + * @pvr_dev: Target PowerVR device. + * + * This function must be called before querying device information. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if firmware validation fails. + */ +int +pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev) +{ + int err; + + err = pvr_fw_validate(pvr_dev); + if (err) + return err; + + return pvr_fw_get_device_info(pvr_dev); +} diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h new file mode 100644 index 000000000000..8331344e83ea --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_H +#define PVR_FW_H + +#include "pvr_fw_info.h" + +#include + +/* Forward declarations from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +struct pvr_fw_device { + /** @firmware: Handle to the firmware loaded into the device. */ + const struct firmware *firmware; + + /** @header: Pointer to firmware header. */ + const struct pvr_fw_info_header *header; + + /** @layout_entries: Pointer to firmware layout. */ + const struct pvr_fw_layout_entry *layout_entries; + + /** + * @processor_type: FW processor type for this device. Must be one of + * %PVR_FW_PROCESSOR_TYPE_*. + */ + u16 processor_type; +}; + +int pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev); + +#endif /* PVR_FW_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_info.h b/drivers/gpu/drm/imagination/pvr_fw_info.h new file mode 100644 index 000000000000..ad5d44a3067a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_info.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_INFO_H +#define PVR_FW_INFO_H + +#include +#include +#include + +/* + * Firmware binary block unit in bytes. + * Raw data stored in FW binary will be aligned to this size. + */ +#define FW_BLOCK_SIZE SZ_4K + +/* Maximum number of entries in firmware layout table. */ +#define PVR_FW_INFO_MAX_NUM_ENTRIES 8 + +enum pvr_fw_section_id { + META_CODE = 0, + META_PRIVATE_DATA, + META_COREMEM_CODE, + META_COREMEM_DATA, + MIPS_CODE, + MIPS_EXCEPTIONS_CODE, + MIPS_BOOT_CODE, + MIPS_PRIVATE_DATA, + MIPS_BOOT_DATA, + MIPS_STACK, + RISCV_UNCACHED_CODE, + RISCV_CACHED_CODE, + RISCV_PRIVATE_DATA, + RISCV_COREMEM_CODE, + RISCV_COREMEM_DATA, +}; + +enum pvr_fw_section_type { + NONE = 0, + FW_CODE, + FW_DATA, + FW_COREMEM_CODE, + FW_COREMEM_DATA, +}; + +/* + * FW binary format with FW info attached: + * + * Contents Offset + * +-----------------+ + * | | 0 + * | | + * | Original binary | + * | file | + * | (.ldr/.elf) | + * | | + * | | + * +-----------------+ + * | Device info | FILE_SIZE - 4K - device_info_size + * +-----------------+ + * | FW info header | FILE_SIZE - 4K + * +-----------------+ + * | | + * | FW layout table | + * | | + * +-----------------+ + * FILE_SIZE + */ + +#define PVR_FW_INFO_VERSION 3 + +#define PVR_FW_FLAGS_OPEN_SOURCE BIT(0) + +/** struct pvr_fw_info_header - Firmware header */ +struct pvr_fw_info_header { + /** @info_version: FW info header version. */ + u32 info_version; + /** @header_len: Header length. */ + u32 header_len; + /** @layout_entry_num: Number of entries in the layout table. */ + u32 layout_entry_num; + /** @layout_entry_size: Size of an entry in the layout table. */ + u32 layout_entry_size; + /** @bvnc: GPU ID supported by firmware. */ + aligned_u64 bvnc; + /** @fw_page_size: Page size of processor on which firmware executes. */ + u32 fw_page_size; + /** @flags: Compatibility flags. */ + u32 flags; + /** @fw_version_major: Firmware major version number. */ + u16 fw_version_major; + /** @fw_version_minor: Firmware minor version number. */ + u16 fw_version_minor; + /** @fw_version_build: Firmware build number. */ + u32 fw_version_build; + /** @device_info_size: Size of device info structure. */ + u32 device_info_size; + /** @padding: Padding. */ + u32 padding; +}; + +/** + * struct pvr_fw_layout_entry - Entry in firmware layout table, describing a + * section of the firmware image + */ +struct pvr_fw_layout_entry { + /** @id: Section ID. */ + enum pvr_fw_section_id id; + /** @type: Section type. */ + enum pvr_fw_section_type type; + /** @base_addr: Base address of section in FW address space. */ + u32 base_addr; + /** @max_size: Maximum size of section, in bytes. */ + u32 max_size; + /** @alloc_size: Allocation size of section, in bytes. */ + u32 alloc_size; + /** @alloc_offset: Allocation offset of section. */ + u32 alloc_offset; +}; + +/** + * struct pvr_fw_device_info_header - Device information header. + */ +struct pvr_fw_device_info_header { + /* BRN Mask size (in u64s). */ + u64 brn_mask_size; + /* ERN Mask size (in u64s). */ + u64 ern_mask_size; + /* Feature Mask size (in u64s). */ + u64 feature_mask_size; + /* Feature Parameter size (in u64s). */ + u64 feature_param_size; +}; + +#endif /* PVR_FW_INFO_H */ From ff5f643de0bf27874c4033cd57a0bd034b5c7d11 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Wed, 22 Nov 2023 16:34:32 +0000 Subject: [PATCH 1183/7721] drm/imagination: Add GEM and VM related code Add a GEM implementation based on drm_gem_shmem, and support code for the PowerVR GPU MMU. The GPU VA manager is used for address space management. Changes since v8: - Updated for changes to drm_gpuvm - Switched to dma_resv locking for vm ops - Removed linked lists for collecting BOs in vm_context and for freeing after ops. This is now done internally in drm_gpuvm - Corrected license identifiers Changes since v7: - kernel-doc fixes - Remove prefixes from DRM_PVR_BO_* flags - CREATE_BO ioctl now returns an error if provided size isn't page aligned - Optimised MMU flushes Changes since v6: - Don't initialise kernel_vm_ctx when using MIPS firmware processor - Rename drm_gpuva_manager uses to drm_gpuvm - Sync GEM object to device on creation Changes since v5: - Use WRITE_ONCE() when writing to page tables - Add memory barriers to page table insertion - Fixed double backing page alloc on page table objects - Fix BO mask checks in DRM_IOCTL_PVR_CREATE_BO handler - Document use of pvr_page_table_*_idx when preallocing page table objs - Remove pvr_vm_gpuva_mapping_init() - Remove NULL check for unmap op in remap function - Protect gem object with mutex during drm_gpuva_link/unlink - Defer free or release of page table pages until after TLB flush - Use drm_gpuva_op_remap_get_unmap_range() helper Changes since v4: - Correct sync function in vmap/vunmap function documentation - Update for upstream GPU VA manager - Fix missing frees when unmapping drm_gpuva objects - Always zero GEM BOs on creation Changes since v3: - Split MMU and VM code - Register page table allocations with kmemleak - Use drm_dev_{enter,exit} Changes since v2: - Use GPU VA manager - Use drm_gem_shmem Co-developed-by: Matt Coster Signed-off-by: Matt Coster Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Link: https://lore.kernel.org/r/3c96dd170efe759b73897e3675d7310a7c4b06d0.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Kconfig | 1 + drivers/gpu/drm/imagination/Makefile | 5 +- drivers/gpu/drm/imagination/pvr_device.c | 27 +- drivers/gpu/drm/imagination/pvr_device.h | 24 + drivers/gpu/drm/imagination/pvr_drv.c | 289 ++- drivers/gpu/drm/imagination/pvr_gem.c | 414 ++++ drivers/gpu/drm/imagination/pvr_gem.h | 170 ++ drivers/gpu/drm/imagination/pvr_mmu.c | 2573 ++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_mmu.h | 108 + drivers/gpu/drm/imagination/pvr_vm.c | 1091 +++++++++ drivers/gpu/drm/imagination/pvr_vm.h | 65 + 11 files changed, 4756 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_gem.c create mode 100644 drivers/gpu/drm/imagination/pvr_gem.h create mode 100644 drivers/gpu/drm/imagination/pvr_mmu.c create mode 100644 drivers/gpu/drm/imagination/pvr_mmu.h create mode 100644 drivers/gpu/drm/imagination/pvr_vm.c create mode 100644 drivers/gpu/drm/imagination/pvr_vm.h diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imagination/Kconfig index 03d0a5031f5c..6f82edf89144 100644 --- a/drivers/gpu/drm/imagination/Kconfig +++ b/drivers/gpu/drm/imagination/Kconfig @@ -7,6 +7,7 @@ config DRM_POWERVR depends on DRM select DRM_GEM_SHMEM_HELPER select DRM_SCHED + select DRM_GPUVM select FW_LOADER help Choose this option if you have a system that has an Imagination diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 0b863e9f51b8..678c3dbb4326 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -7,6 +7,9 @@ powervr-y := \ pvr_device.o \ pvr_device_info.o \ pvr_drv.o \ - pvr_fw.o + pvr_fw.o \ + pvr_gem.o \ + pvr_mmu.o \ + pvr_vm.o obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 05e382cacb27..201ae780494f 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -6,6 +6,7 @@ #include "pvr_fw.h" #include "pvr_rogue_cr_defs.h" +#include "pvr_vm.h" #include @@ -312,7 +313,30 @@ pvr_device_gpu_init(struct pvr_device *pvr_dev) else return -EINVAL; - return pvr_set_dma_info(pvr_dev); + err = pvr_set_dma_info(pvr_dev); + if (err) + return err; + + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + pvr_dev->kernel_vm_ctx = pvr_vm_create_context(pvr_dev, false); + if (IS_ERR(pvr_dev->kernel_vm_ctx)) + return PTR_ERR(pvr_dev->kernel_vm_ctx); + } + + return 0; +} + +/** + * pvr_device_gpu_fini() - GPU-specific deinitialization for a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_device_gpu_fini(struct pvr_device *pvr_dev) +{ + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + WARN_ON(!pvr_vm_context_put(pvr_dev->kernel_vm_ctx)); + pvr_dev->kernel_vm_ctx = NULL; + } } /** @@ -364,6 +388,7 @@ pvr_device_fini(struct pvr_device *pvr_dev) * Deinitialization stages are performed in reverse order compared to * the initialization stages in pvr_device_init(). */ + pvr_device_gpu_fini(pvr_dev); } bool diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index 36fe67bed27f..bfc853ffd58f 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -123,8 +123,24 @@ struct pvr_device { */ struct clk *mem_clk; + /** + * @kernel_vm_ctx: Virtual memory context used for kernel mappings. + * + * This is used for mappings in the firmware address region when a META firmware processor + * is in use. + * + * When a MIPS firmware processor is in use, this will be %NULL. + */ + struct pvr_vm_context *kernel_vm_ctx; + /** @fw_dev: Firmware related data. */ struct pvr_fw_device fw_dev; + + /** + * @mmu_flush_cache_flags: Records which MMU caches require flushing + * before submitting the next job. + */ + atomic_t mmu_flush_cache_flags; }; /** @@ -145,6 +161,14 @@ struct pvr_file { * to_pvr_device(). */ struct pvr_device *pvr_dev; + + /** + * @vm_ctx_handles: Array of VM contexts belonging to this file. Array + * members are of type "struct pvr_vm_context *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray vm_ctx_handles; }; /** diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 1e4408f33e94..6d3bc886e1c3 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -3,9 +3,12 @@ #include "pvr_device.h" #include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_mmu.h" #include "pvr_rogue_defs.h" #include "pvr_rogue_fwif_client.h" #include "pvr_rogue_fwif_shared.h" +#include "pvr_vm.h" #include @@ -60,7 +63,72 @@ static int pvr_ioctl_create_bo(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_create_bo_args *args = raw_args; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file = to_pvr_file(file); + + struct pvr_gem_object *pvr_obj; + size_t sanitized_size; + + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* All padding fields must be zeroed. */ + if (args->_padding_c != 0) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + /* + * On 64-bit platforms (our primary target), size_t is a u64. However, + * on other architectures we have to check for overflow when casting + * down to size_t from u64. + * + * We also disallow zero-sized allocations, and reserved (kernel-only) + * flags. + */ + if (args->size > SIZE_MAX || args->size == 0 || args->flags & + ~DRM_PVR_BO_FLAGS_MASK || args->size & (PVR_DEVICE_PAGE_SIZE - 1)) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + sanitized_size = (size_t)args->size; + + /* + * Create a buffer object and transfer ownership to a userspace- + * accessible handle. + */ + pvr_obj = pvr_gem_object_create(pvr_dev, sanitized_size, args->flags); + if (IS_ERR(pvr_obj)) { + err = PTR_ERR(pvr_obj); + goto err_drm_dev_exit; + } + + /* This function will not modify &args->handle unless it succeeds. */ + err = pvr_gem_object_into_handle(pvr_obj, pvr_file, &args->handle); + if (err) + goto err_destroy_obj; + + drm_dev_exit(idx); + + return 0; + +err_destroy_obj: + /* + * GEM objects are refcounted, so there is no explicit destructor + * function. Instead, we release the singular reference we currently + * hold on the object and let GEM take care of the rest. + */ + pvr_gem_object_put(pvr_obj); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** @@ -87,7 +155,61 @@ static int pvr_ioctl_get_bo_mmap_offset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_get_bo_mmap_offset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_gem_object *pvr_obj; + struct drm_gem_object *gem_obj; + int idx; + int ret; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* All padding fields must be zeroed. */ + if (args->_padding_4 != 0) { + ret = -EINVAL; + goto err_drm_dev_exit; + } + + /* + * Obtain a kernel reference to the buffer object. This reference is + * counted and must be manually dropped before returning. If a buffer + * object cannot be found for the specified handle, return -%ENOENT (No + * such file or directory). + */ + pvr_obj = pvr_gem_object_from_handle(pvr_file, args->handle); + if (!pvr_obj) { + ret = -ENOENT; + goto err_drm_dev_exit; + } + + gem_obj = gem_from_pvr_gem(pvr_obj); + + /* + * Allocate a fake offset which can be used in userspace calls to mmap + * on the DRM device file. If this fails, return the error code. This + * operation is idempotent. + */ + ret = drm_gem_create_mmap_offset(gem_obj); + if (ret != 0) { + /* Drop our reference to the buffer object. */ + drm_gem_object_put(gem_obj); + goto err_drm_dev_exit; + } + + /* + * Read out the fake offset allocated by the earlier call to + * drm_gem_create_mmap_offset. + */ + args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); + + /* Drop our reference to the buffer object. */ + pvr_gem_object_put(pvr_obj); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return ret; } static __always_inline u64 @@ -516,10 +638,12 @@ pvr_ioctl_dev_query(struct drm_device *drm_dev, void *raw_args, break; case DRM_PVR_DEV_QUERY_HEAP_INFO_GET: - return -EINVAL; + ret = pvr_heap_info_get(pvr_dev, args); + break; case DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET: - return -EINVAL; + ret = pvr_static_data_areas_get(pvr_dev, args); + break; } drm_dev_exit(idx); @@ -666,7 +790,46 @@ static int pvr_ioctl_create_vm_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_create_vm_context_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + if (args->_padding_4) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + vm_ctx = pvr_vm_create_context(pvr_file->pvr_dev, true); + if (IS_ERR(vm_ctx)) { + err = PTR_ERR(vm_ctx); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->vm_ctx_handles, + &args->handle, + vm_ctx, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_vm_context_put(vm_ctx); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** @@ -686,7 +849,19 @@ static int pvr_ioctl_destroy_vm_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_destroy_vm_context_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + + if (args->_padding_4) + return -EINVAL; + + vm_ctx = xa_erase(&pvr_file->vm_ctx_handles, args->handle); + if (!vm_ctx) + return -EINVAL; + + pvr_vm_context_put(vm_ctx); + return 0; } /** @@ -716,7 +891,79 @@ static int pvr_ioctl_vm_map(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct drm_pvr_ioctl_vm_map_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + + struct pvr_gem_object *pvr_obj; + size_t pvr_obj_size; + + u64 offset_plus_size; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* Initial validation of args. */ + if (args->_padding_14) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + if (args->flags != 0 || + check_add_overflow(args->offset, args->size, &offset_plus_size) || + !pvr_find_heap_containing(pvr_dev, args->device_addr, args->size)) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + pvr_obj = pvr_gem_object_from_handle(pvr_file, args->handle); + if (!pvr_obj) { + err = -ENOENT; + goto err_put_vm_context; + } + + pvr_obj_size = pvr_gem_object_size(pvr_obj); + + /* + * Validate offset and size args. The alignment of these will be + * checked when mapping; for now just check that they're within valid + * bounds + */ + if (args->offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) { + err = -EINVAL; + goto err_put_pvr_object; + } + + err = pvr_vm_map(vm_ctx, pvr_obj, args->offset, + args->device_addr, args->size); + if (err) + goto err_put_pvr_object; + + /* + * In order to set up the mapping, we needed a reference to &pvr_obj. + * However, pvr_vm_map() obtains and stores its own reference, so we + * must release ours before returning. + */ + +err_put_pvr_object: + pvr_gem_object_put(pvr_obj); + +err_put_vm_context: + pvr_vm_context_put(vm_ctx); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** @@ -739,7 +986,24 @@ static int pvr_ioctl_vm_unmap(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_vm_unmap_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + int err; + + /* Initial validation of args. */ + if (args->_padding_4) + return -EINVAL; + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) + return -EINVAL; + + err = pvr_vm_unmap(vm_ctx, args->device_addr, args->size); + + pvr_vm_context_put(vm_ctx); + + return err; } /* @@ -930,6 +1194,8 @@ pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file) */ pvr_file->pvr_dev = pvr_dev; + xa_init_flags(&pvr_file->vm_ctx_handles, XA_FLAGS_ALLOC1); + /* * Store reference to powervr-specific file private data in DRM file * private data. @@ -955,6 +1221,9 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, { struct pvr_file *pvr_file = to_pvr_file(file); + /* Drop references on any remaining objects. */ + pvr_destroy_vm_contexts_for_file(pvr_file); + kfree(pvr_file); file->driver_priv = NULL; } @@ -962,7 +1231,7 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, DEFINE_DRM_GEM_FOPS(pvr_drm_driver_fops); static struct drm_driver pvr_drm_driver = { - .driver_features = DRIVER_RENDER, + .driver_features = DRIVER_GEM | DRIVER_GEM_GPUVA | DRIVER_RENDER, .open = pvr_drm_driver_open, .postclose = pvr_drm_driver_postclose, .ioctls = pvr_drm_driver_ioctls, @@ -976,6 +1245,8 @@ static struct drm_driver pvr_drm_driver = { .minor = PVR_DRIVER_MINOR, .patchlevel = PVR_DRIVER_PATCHLEVEL, + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, + .gem_create_object = pvr_gem_create_object, }; static int diff --git a/drivers/gpu/drm/imagination/pvr_gem.c b/drivers/gpu/drm/imagination/pvr_gem.c new file mode 100644 index 000000000000..6a8c81fe8c1e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_gem.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_vm.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void pvr_gem_object_free(struct drm_gem_object *obj) +{ + drm_gem_shmem_object_free(obj); +} + +static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *vma) +{ + struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(gem_obj); + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + + if (!(pvr_obj->flags & DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS)) + return -EINVAL; + + return drm_gem_shmem_mmap(shmem_obj, vma); +} + +static const struct drm_gem_object_funcs pvr_gem_object_funcs = { + .free = pvr_gem_object_free, + .print_info = drm_gem_shmem_object_print_info, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = pvr_gem_mmap, + .vm_ops = &drm_gem_shmem_vm_ops, +}; + +/** + * pvr_gem_object_flags_validate() - Verify that a collection of PowerVR GEM + * mapping and/or creation flags form a valid combination. + * @flags: PowerVR GEM mapping/creation flags to validate. + * + * This function explicitly allows kernel-only flags. All ioctl entrypoints + * should do their own validation as well as relying on this function. + * + * Return: + * * %true if @flags contains valid mapping and/or creation flags, or + * * %false otherwise. + */ +static bool +pvr_gem_object_flags_validate(u64 flags) +{ + static const u64 invalid_combinations[] = { + /* + * Memory flagged as PM/FW-protected cannot be mapped to + * userspace. To make this explicit, we require that the two + * flags allowing each of these respective features are never + * specified together. + */ + (DRM_PVR_BO_PM_FW_PROTECT | + DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS), + }; + + int i; + + /* + * Check for bits set in undefined regions. Reserved regions refer to + * options that can only be set by the kernel. These are explicitly + * allowed in most cases, and must be checked specifically in IOCTL + * callback code. + */ + if ((flags & PVR_BO_UNDEFINED_MASK) != 0) + return false; + + /* + * Check for all combinations of flags marked as invalid in the array + * above. + */ + for (i = 0; i < ARRAY_SIZE(invalid_combinations); ++i) { + u64 combo = invalid_combinations[i]; + + if ((flags & combo) == combo) + return false; + } + + return true; +} + +/** + * pvr_gem_object_into_handle() - Convert a reference to an object into a + * userspace-accessible handle. + * @pvr_obj: [IN] Target PowerVR-specific object. + * @pvr_file: [IN] File to associate the handle with. + * @handle: [OUT] Pointer to store the created handle in. Remains unmodified if + * an error is encountered. + * + * If an error is encountered, ownership of @pvr_obj will not have been + * transferred. If this function succeeds, however, further use of @pvr_obj is + * considered undefined behaviour unless another reference to it is explicitly + * held. + * + * Return: + * * 0 on success, or + * * Any error encountered while attempting to allocate a handle on @pvr_file. + */ +int +pvr_gem_object_into_handle(struct pvr_gem_object *pvr_obj, + struct pvr_file *pvr_file, u32 *handle) +{ + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct drm_file *file = from_pvr_file(pvr_file); + + u32 new_handle; + int err; + + err = drm_gem_handle_create(file, gem_obj, &new_handle); + if (err) + return err; + + /* + * Release our reference to @pvr_obj, effectively transferring + * ownership to the handle. + */ + pvr_gem_object_put(pvr_obj); + + /* + * Do not store the new handle in @handle until no more errors can + * occur. + */ + *handle = new_handle; + + return 0; +} + +/** + * pvr_gem_object_from_handle() - Obtain a reference to an object from a + * userspace handle. + * @pvr_file: PowerVR-specific file to which @handle is associated. + * @handle: Userspace handle referencing the target object. + * + * On return, @handle always maintains its reference to the requested object + * (if it had one in the first place). If this function succeeds, the returned + * object will hold an additional reference. When the caller is finished with + * the returned object, they should call pvr_gem_object_put() on it to release + * this reference. + * + * Return: + * * A pointer to the requested PowerVR-specific object on success, or + * * %NULL otherwise. + */ +struct pvr_gem_object * +pvr_gem_object_from_handle(struct pvr_file *pvr_file, u32 handle) +{ + struct drm_file *file = from_pvr_file(pvr_file); + struct drm_gem_object *gem_obj; + + gem_obj = drm_gem_object_lookup(file, handle); + if (!gem_obj) + return NULL; + + return gem_to_pvr_gem(gem_obj); +} + +/** + * pvr_gem_object_vmap() - Map a PowerVR GEM object into CPU virtual address + * space. + * @pvr_obj: Target PowerVR GEM object. + * + * Once the caller is finished with the CPU mapping, they must call + * pvr_gem_object_vunmap() on @pvr_obj. + * + * If @pvr_obj is CPU-cached, dma_sync_sgtable_for_cpu() is called to make + * sure the CPU mapping is consistent. + * + * Return: + * * A pointer to the CPU mapping on success, + * * -%ENOMEM if the mapping fails, or + * * Any error encountered while attempting to acquire a reference to the + * backing pages for @pvr_obj. + */ +void * +pvr_gem_object_vmap(struct pvr_gem_object *pvr_obj) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); + struct iosys_map map; + int err; + + dma_resv_lock(obj->resv, NULL); + + err = drm_gem_shmem_vmap(shmem_obj, &map); + if (err) + goto err_unlock; + + if (pvr_obj->flags & PVR_BO_CPU_CACHED) { + struct device *dev = shmem_obj->base.dev->dev; + + /* If shmem_obj->sgt is NULL, that means the buffer hasn't been mapped + * in GPU space yet. + */ + if (shmem_obj->sgt) + dma_sync_sgtable_for_cpu(dev, shmem_obj->sgt, DMA_BIDIRECTIONAL); + } + + dma_resv_unlock(obj->resv); + + return map.vaddr; + +err_unlock: + dma_resv_unlock(obj->resv); + + return ERR_PTR(err); +} + +/** + * pvr_gem_object_vunmap() - Unmap a PowerVR memory object from CPU virtual + * address space. + * @pvr_obj: Target PowerVR GEM object. + * + * If @pvr_obj is CPU-cached, dma_sync_sgtable_for_device() is called to make + * sure the GPU mapping is consistent. + */ +void +pvr_gem_object_vunmap(struct pvr_gem_object *pvr_obj) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(shmem_obj->vaddr); + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); + + if (WARN_ON(!map.vaddr)) + return; + + dma_resv_lock(obj->resv, NULL); + + if (pvr_obj->flags & PVR_BO_CPU_CACHED) { + struct device *dev = shmem_obj->base.dev->dev; + + /* If shmem_obj->sgt is NULL, that means the buffer hasn't been mapped + * in GPU space yet. + */ + if (shmem_obj->sgt) + dma_sync_sgtable_for_device(dev, shmem_obj->sgt, DMA_BIDIRECTIONAL); + } + + drm_gem_shmem_vunmap(shmem_obj, &map); + + dma_resv_unlock(obj->resv); +} + +/** + * pvr_gem_object_zero() - Zeroes the physical memory behind an object. + * @pvr_obj: Target PowerVR GEM object. + * + * Return: + * * 0 on success, or + * * Any error encountered while attempting to map @pvr_obj to the CPU (see + * pvr_gem_object_vmap()). + */ +static int +pvr_gem_object_zero(struct pvr_gem_object *pvr_obj) +{ + void *cpu_ptr; + + cpu_ptr = pvr_gem_object_vmap(pvr_obj); + if (IS_ERR(cpu_ptr)) + return PTR_ERR(cpu_ptr); + + memset(cpu_ptr, 0, pvr_gem_object_size(pvr_obj)); + + /* Make sure the zero-ing is done before vumap-ing the object. */ + wmb(); + + pvr_gem_object_vunmap(pvr_obj); + + return 0; +} + +/** + * pvr_gem_create_object() - Allocate and pre-initializes a pvr_gem_object + * @drm_dev: DRM device creating this object. + * @size: Size of the object to allocate in bytes. + * + * Return: + * * The new pre-initialized GEM object on success, + * * -ENOMEM if the allocation failed. + */ +struct drm_gem_object *pvr_gem_create_object(struct drm_device *drm_dev, size_t size) +{ + struct drm_gem_object *gem_obj; + struct pvr_gem_object *pvr_obj; + + pvr_obj = kzalloc(sizeof(*pvr_obj), GFP_KERNEL); + if (!pvr_obj) + return ERR_PTR(-ENOMEM); + + gem_obj = gem_from_pvr_gem(pvr_obj); + gem_obj->funcs = &pvr_gem_object_funcs; + + return gem_obj; +} + +/** + * pvr_gem_object_create() - Creates a PowerVR-specific buffer object. + * @pvr_dev: Target PowerVR device. + * @size: Size of the object to allocate in bytes. Must be greater than zero. + * Any value which is not an exact multiple of the system page size will be + * rounded up to satisfy this condition. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * + * The created object may be larger than @size, but can never be smaller. To + * get the exact size, call pvr_gem_object_size() on the returned pointer. + * + * Return: + * * The newly-minted PowerVR-specific buffer object on success, + * * -%EINVAL if @size is zero or @flags is not valid, + * * -%ENOMEM if sufficient physical memory cannot be allocated, or + * * Any other error returned by drm_gem_create_mmap_offset(). + */ +struct pvr_gem_object * +pvr_gem_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags) +{ + struct drm_gem_shmem_object *shmem_obj; + struct pvr_gem_object *pvr_obj; + struct sg_table *sgt; + int err; + + /* Verify @size and @flags before continuing. */ + if (size == 0 || !pvr_gem_object_flags_validate(flags)) + return ERR_PTR(-EINVAL); + + shmem_obj = drm_gem_shmem_create(from_pvr_device(pvr_dev), size); + if (IS_ERR(shmem_obj)) + return ERR_CAST(shmem_obj); + + shmem_obj->pages_mark_dirty_on_put = true; + shmem_obj->map_wc = !(flags & PVR_BO_CPU_CACHED); + pvr_obj = shmem_gem_to_pvr_gem(shmem_obj); + pvr_obj->flags = flags; + + sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); + if (IS_ERR(sgt)) { + err = PTR_ERR(sgt); + goto err_shmem_object_free; + } + + dma_sync_sgtable_for_device(shmem_obj->base.dev->dev, sgt, + DMA_BIDIRECTIONAL); + + /* + * Do this last because pvr_gem_object_zero() requires a fully + * configured instance of struct pvr_gem_object. + */ + pvr_gem_object_zero(pvr_obj); + + return pvr_obj; + +err_shmem_object_free: + drm_gem_shmem_free(shmem_obj); + + return ERR_PTR(err); +} + +/** + * pvr_gem_get_dma_addr() - Get DMA address for given offset in object + * @pvr_obj: Pointer to object to lookup address in. + * @offset: Offset within object to lookup address at. + * @dma_addr_out: Pointer to location to store DMA address. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently backed, or if @offset is out of valid + * range for this object. + */ +int +pvr_gem_get_dma_addr(struct pvr_gem_object *pvr_obj, u32 offset, + dma_addr_t *dma_addr_out) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + u32 accumulated_offset = 0; + struct scatterlist *sgl; + unsigned int sgt_idx; + + WARN_ON(!shmem_obj->sgt); + for_each_sgtable_dma_sg(shmem_obj->sgt, sgl, sgt_idx) { + u32 new_offset = accumulated_offset + sg_dma_len(sgl); + + if (offset >= accumulated_offset && offset < new_offset) { + *dma_addr_out = sg_dma_address(sgl) + + (offset - accumulated_offset); + return 0; + } + + accumulated_offset = new_offset; + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/imagination/pvr_gem.h b/drivers/gpu/drm/imagination/pvr_gem.h new file mode 100644 index 000000000000..e0e5ea509a2e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_gem.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_GEM_H +#define PVR_GEM_H + +#include "pvr_rogue_heap_config.h" +#include "pvr_rogue_meta.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +/** + * DOC: Flags for DRM_IOCTL_PVR_CREATE_BO (kernel-only) + * + * Kernel-only values allowed in &pvr_gem_object->flags. The majority of options + * for this field are specified in the UAPI header "pvr_drm.h" with a + * DRM_PVR_BO_ prefix. To distinguish these internal options (which must exist + * in ranges marked as "reserved" in the UAPI header), we drop the DRM prefix. + * The public options should be used directly, DRM prefix and all. + * + * To avoid potentially confusing gaps in the UAPI options, these kernel-only + * options are specified "in reverse", starting at bit 63. + * + * We use "reserved" to refer to bits defined here and not exposed in the UAPI. + * Bits not defined anywhere are "undefined". + * + * CPU mapping options + * :PVR_BO_CPU_CACHED: By default, all GEM objects are mapped write-combined on the CPU. Set this + * flag to override this behaviour and map the object cached. + * + * Firmware options + * :PVR_BO_FW_NO_CLEAR_ON_RESET: By default, all FW objects are cleared and reinitialised on hard + * reset. Set this flag to override this behaviour and preserve buffer contents on reset. + */ +#define PVR_BO_CPU_CACHED BIT_ULL(63) + +#define PVR_BO_FW_NO_CLEAR_ON_RESET BIT_ULL(62) + +#define PVR_BO_KERNEL_FLAGS_MASK (PVR_BO_CPU_CACHED | PVR_BO_FW_NO_CLEAR_ON_RESET) + +/* Bits 61..3 are undefined. */ +/* Bits 2..0 are defined in the UAPI. */ + +/* Other utilities. */ +#define PVR_BO_UNDEFINED_MASK ~(PVR_BO_KERNEL_FLAGS_MASK | DRM_PVR_BO_FLAGS_MASK) + +/* + * All firmware-mapped memory uses (mostly) the same flags. Specifically, + * firmware-mapped memory should be: + * * Read/write on the device, + * * Read/write on the CPU, and + * * Write-combined on the CPU. + * + * The only variation is in caching on the device. + */ +#define PVR_BO_FW_FLAGS_DEVICE_CACHED (ULL(0)) +#define PVR_BO_FW_FLAGS_DEVICE_UNCACHED DRM_PVR_BO_BYPASS_DEVICE_CACHE + +/** + * struct pvr_gem_object - powervr-specific wrapper for &struct drm_gem_object + */ +struct pvr_gem_object { + /** + * @base: The underlying &struct drm_gem_shmem_object. + * + * Do not access this member directly, instead call + * shem_gem_from_pvr_gem(). + */ + struct drm_gem_shmem_object base; + + /** + * @flags: Options set at creation-time. Some of these options apply to + * the creation operation itself (which are stored here for reference) + * with the remainder used for mapping options to both the device and + * CPU. These are used every time this object is mapped, but may be + * changed after creation. + * + * Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags. + * + * .. note:: + * + * This member is declared const to indicate that none of these + * options may change or be changed throughout the object's + * lifetime. + */ + u64 flags; + +}; + +static_assert(offsetof(struct pvr_gem_object, base) == 0, + "offsetof(struct pvr_gem_object, base) not zero"); + +#define shmem_gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base) + +#define shmem_gem_to_pvr_gem(shmem_obj) container_of_const(shmem_obj, struct pvr_gem_object, base) + +#define gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base.base) + +#define gem_to_pvr_gem(gem_obj) container_of_const(gem_obj, struct pvr_gem_object, base.base) + +/* Functions defined in pvr_gem.c */ + +struct drm_gem_object *pvr_gem_create_object(struct drm_device *drm_dev, size_t size); + +struct pvr_gem_object *pvr_gem_object_create(struct pvr_device *pvr_dev, + size_t size, u64 flags); + +int pvr_gem_object_into_handle(struct pvr_gem_object *pvr_obj, + struct pvr_file *pvr_file, u32 *handle); +struct pvr_gem_object *pvr_gem_object_from_handle(struct pvr_file *pvr_file, + u32 handle); + +static __always_inline struct sg_table * +pvr_gem_object_get_pages_sgt(struct pvr_gem_object *pvr_obj) +{ + return drm_gem_shmem_get_pages_sgt(shmem_gem_from_pvr_gem(pvr_obj)); +} + +void *pvr_gem_object_vmap(struct pvr_gem_object *pvr_obj); +void pvr_gem_object_vunmap(struct pvr_gem_object *pvr_obj); + +int pvr_gem_get_dma_addr(struct pvr_gem_object *pvr_obj, u32 offset, + dma_addr_t *dma_addr_out); + +/** + * pvr_gem_object_get() - Acquire reference on pvr_gem_object + * @pvr_obj: Pointer to object to acquire reference on. + */ +static __always_inline void +pvr_gem_object_get(struct pvr_gem_object *pvr_obj) +{ + drm_gem_object_get(gem_from_pvr_gem(pvr_obj)); +} + +/** + * pvr_gem_object_put() - Release reference on pvr_gem_object + * @pvr_obj: Pointer to object to release reference on. + */ +static __always_inline void +pvr_gem_object_put(struct pvr_gem_object *pvr_obj) +{ + drm_gem_object_put(gem_from_pvr_gem(pvr_obj)); +} + +static __always_inline size_t +pvr_gem_object_size(struct pvr_gem_object *pvr_obj) +{ + return gem_from_pvr_gem(pvr_obj)->size; +} + +#endif /* PVR_GEM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c new file mode 100644 index 000000000000..7f77e03df912 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_mmu.c @@ -0,0 +1,2573 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_mmu.h" + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_gem.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_mmu_defs.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PVR_SHIFT_FROM_SIZE(size_) (__builtin_ctzll(size_)) +#define PVR_MASK_FROM_SIZE(size_) (~((size_) - U64_C(1))) + +/* + * The value of the device page size (%PVR_DEVICE_PAGE_SIZE) is currently + * pegged to the host page size (%PAGE_SIZE). This chunk of macro goodness both + * ensures that the selected host page size corresponds to a valid device page + * size and sets up values needed by the MMU code below. + */ +#if (PVR_DEVICE_PAGE_SIZE == SZ_4K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_4KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_4KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_4KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_16K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_16KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_16KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_16KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_64K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_64KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_64KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_64KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_256K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_256KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_256KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_256KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_1M) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_1MB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_1MB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_1MB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_2M) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_2MB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_2MB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_2MB_RANGE_CLRMSK +#else +# error Unsupported device page size PVR_DEVICE_PAGE_SIZE +#endif + +#define ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X \ + (ROGUE_MMUCTRL_ENTRIES_PT_VALUE >> \ + (PVR_DEVICE_PAGE_SHIFT - PVR_SHIFT_FROM_SIZE(SZ_4K))) + +enum pvr_mmu_sync_level { + PVR_MMU_SYNC_LEVEL_NONE = -1, + PVR_MMU_SYNC_LEVEL_0 = 0, + PVR_MMU_SYNC_LEVEL_1 = 1, + PVR_MMU_SYNC_LEVEL_2 = 2, +}; + +#define PVR_MMU_SYNC_LEVEL_0_FLAGS (ROGUE_FWIF_MMUCACHEDATA_FLAGS_PT | \ + ROGUE_FWIF_MMUCACHEDATA_FLAGS_INTERRUPT | \ + ROGUE_FWIF_MMUCACHEDATA_FLAGS_TLB) +#define PVR_MMU_SYNC_LEVEL_1_FLAGS (PVR_MMU_SYNC_LEVEL_0_FLAGS | ROGUE_FWIF_MMUCACHEDATA_FLAGS_PD) +#define PVR_MMU_SYNC_LEVEL_2_FLAGS (PVR_MMU_SYNC_LEVEL_1_FLAGS | ROGUE_FWIF_MMUCACHEDATA_FLAGS_PC) + +/** + * pvr_mmu_set_flush_flags() - Set MMU cache flush flags for next call to + * pvr_mmu_flush_exec(). + * @pvr_dev: Target PowerVR device. + * @flags: MMU flush flags. Must be one of %PVR_MMU_SYNC_LEVEL_*_FLAGS. + * + * This function must be called following any possible change to the MMU page + * tables. + */ +static void pvr_mmu_set_flush_flags(struct pvr_device *pvr_dev, u32 flags) +{ + atomic_fetch_or(flags, &pvr_dev->mmu_flush_cache_flags); +} + +/** + * pvr_mmu_flush_request_all() - Request flush of all MMU caches when + * subsequently calling pvr_mmu_flush_exec(). + * @pvr_dev: Target PowerVR device. + * + * This function must be called following any possible change to the MMU page + * tables. + */ +void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev) +{ + /* TODO: implement */ +} + +/** + * pvr_mmu_flush_exec() - Execute a flush of all MMU caches previously + * requested. + * @pvr_dev: Target PowerVR device. + * @wait: Do not return until the flush is completed. + * + * This function must be called prior to submitting any new GPU job. The flush + * will complete before the jobs are scheduled, so this can be called once after + * a series of maps. However, a single unmap should always be immediately + * followed by a flush and it should be explicitly waited by setting @wait. + * + * As a failure to flush the MMU caches could risk memory corruption, if the + * flush fails (implying the firmware is not responding) then the GPU device is + * marked as lost. + * + * Returns: + * * 0 on success when @wait is true, or + * * -%EIO if the device is unavailable, or + * * Any error encountered while submitting the flush command via the KCCB. + */ +int pvr_mmu_flush_exec(struct pvr_device *pvr_dev, bool wait) +{ + /* TODO: implement */ + return -ENODEV; +} + +/** + * DOC: PowerVR Virtual Memory Handling + */ +/** + * DOC: PowerVR Virtual Memory Handling (constants) + * + * .. c:macro:: PVR_IDX_INVALID + * + * Default value for a u16-based index. + * + * This value cannot be zero, since zero is a valid index value. + */ +#define PVR_IDX_INVALID ((u16)(-1)) + +/** + * DOC: MMU backing pages + */ +/** + * DOC: MMU backing pages (constants) + * + * .. c:macro:: PVR_MMU_BACKING_PAGE_SIZE + * + * Page size of a PowerVR device's integrated MMU. The CPU page size must be + * at least as large as this value for the current implementation; this is + * checked at compile-time. + */ +#define PVR_MMU_BACKING_PAGE_SIZE SZ_4K +static_assert(PAGE_SIZE >= PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_mmu_backing_page - Represents a single page used to back a page + * table of any level. + * @dma_addr: DMA address of this page. + * @host_ptr: CPU address of this page. + * @pvr_dev: The PowerVR device to which this page is associated. **For + * internal use only.** + */ +struct pvr_mmu_backing_page { + dma_addr_t dma_addr; + void *host_ptr; +/* private: internal use only */ + struct page *raw_page; + struct pvr_device *pvr_dev; +}; + +/** + * pvr_mmu_backing_page_init() - Initialize a MMU backing page. + * @page: Target backing page. + * @pvr_dev: Target PowerVR device. + * + * This function performs three distinct operations: + * + * 1. Allocate a single page, + * 2. Map the page to the CPU, and + * 3. Map the page to DMA-space. + * + * It is expected that @page be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * -%ENOMEM if allocation of the backing page or mapping of the backing + * page to DMA fails. + */ +static int +pvr_mmu_backing_page_init(struct pvr_mmu_backing_page *page, + struct pvr_device *pvr_dev) +{ + struct device *dev = from_pvr_device(pvr_dev)->dev; + + struct page *raw_page; + int err; + + dma_addr_t dma_addr; + void *host_ptr; + + raw_page = alloc_page(__GFP_ZERO | GFP_KERNEL); + if (!raw_page) + return -ENOMEM; + + host_ptr = vmap(&raw_page, 1, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!host_ptr) { + err = -ENOMEM; + goto err_free_page; + } + + dma_addr = dma_map_page(dev, raw_page, 0, PVR_MMU_BACKING_PAGE_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + err = -ENOMEM; + goto err_unmap_page; + } + + page->dma_addr = dma_addr; + page->host_ptr = host_ptr; + page->pvr_dev = pvr_dev; + page->raw_page = raw_page; + kmemleak_alloc(page->host_ptr, PAGE_SIZE, 1, GFP_KERNEL); + + return 0; + +err_unmap_page: + vunmap(host_ptr); + +err_free_page: + __free_page(raw_page); + + return err; +} + +/** + * pvr_mmu_backing_page_fini() - Teardown a MMU backing page. + * @page: Target backing page. + * + * This function performs the mirror operations to pvr_mmu_backing_page_init(), + * in reverse order: + * + * 1. Unmap the page from DMA-space, + * 2. Unmap the page from the CPU, and + * 3. Free the page. + * + * It also zeros @page. + * + * It is a no-op to call this function a second (or further) time on any @page. + */ +static void +pvr_mmu_backing_page_fini(struct pvr_mmu_backing_page *page) +{ + struct device *dev = from_pvr_device(page->pvr_dev)->dev; + + /* Do nothing if no allocation is present. */ + if (!page->pvr_dev) + return; + + dma_unmap_page(dev, page->dma_addr, PVR_MMU_BACKING_PAGE_SIZE, + DMA_TO_DEVICE); + + kmemleak_free(page->host_ptr); + vunmap(page->host_ptr); + + __free_page(page->raw_page); + + memset(page, 0, sizeof(*page)); +} + +/** + * pvr_mmu_backing_page_sync() - Flush a MMU backing page from the CPU to the + * device. + * @page: Target backing page. + * + * .. caution:: + * + * **This is potentially an expensive function call.** Only call + * pvr_mmu_backing_page_sync() once you're sure you have no more changes to + * make to the backing page in the immediate future. + */ +static void +pvr_mmu_backing_page_sync(struct pvr_mmu_backing_page *page, u32 flags) +{ + struct pvr_device *pvr_dev = page->pvr_dev; + struct device *dev; + + /* + * Do nothing if no allocation is present. This may be the case if + * we are unmapping pages. + */ + if (!pvr_dev) + return; + + dev = from_pvr_device(pvr_dev)->dev; + + dma_sync_single_for_device(dev, page->dma_addr, + PVR_MMU_BACKING_PAGE_SIZE, DMA_TO_DEVICE); + + pvr_mmu_set_flush_flags(pvr_dev, flags); +} + +/** + * DOC: Raw page tables + */ + +#define PVR_PAGE_TABLE_TYPEOF_ENTRY(level_) \ + typeof_member(struct pvr_page_table_l##level_##_entry_raw, val) + +#define PVR_PAGE_TABLE_FIELD_GET(level_, name_, field_, entry_) \ + (((entry_).val & \ + ~ROGUE_MMUCTRL_##name_##_DATA_##field_##_CLRMSK) >> \ + ROGUE_MMUCTRL_##name_##_DATA_##field_##_SHIFT) + +#define PVR_PAGE_TABLE_FIELD_PREP(level_, name_, field_, val_) \ + ((((PVR_PAGE_TABLE_TYPEOF_ENTRY(level_))(val_)) \ + << ROGUE_MMUCTRL_##name_##_DATA_##field_##_SHIFT) & \ + ~ROGUE_MMUCTRL_##name_##_DATA_##field_##_CLRMSK) + +/** + * struct pvr_page_table_l2_entry_raw - A single entry in a level 2 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 31..4 + * - **Level 1 Page Table Base Address:** Bits 39..12 of the L1 + * page table base address, which is 4KiB aligned. + * + * * - 3..2 + * - *(reserved)* + * + * * - 1 + * - **Pending:** When valid bit is not set, indicates that a valid + * entry is pending and the MMU should wait for the driver to map + * the entry. This is used to support page demand mapping of + * memory. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid L1 page + * table. If the valid bit is not set, then an attempted use of + * the page would result in a page fault. + */ +struct pvr_page_table_l2_entry_raw { + u32 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l2_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE); + +static bool +pvr_page_table_l2_entry_raw_is_valid(struct pvr_page_table_l2_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(2, PC, VALID, entry); +} + +/** + * pvr_page_table_l2_entry_raw_set() - Write a valid entry into a raw level 2 + * page table. + * @entry: Target raw level 2 page table entry. + * @child_table_dma_addr: DMA address of the level 1 page table to be + * associated with @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of %ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSIZE. + */ +static void +pvr_page_table_l2_entry_raw_set(struct pvr_page_table_l2_entry_raw *entry, + dma_addr_t child_table_dma_addr) +{ + child_table_dma_addr >>= ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSHIFT; + + WRITE_ONCE(entry->val, + PVR_PAGE_TABLE_FIELD_PREP(2, PC, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(2, PC, ENTRY_PENDING, false) | + PVR_PAGE_TABLE_FIELD_PREP(2, PC, PD_BASE, child_table_dma_addr)); +} + +static void +pvr_page_table_l2_entry_raw_clear(struct pvr_page_table_l2_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * struct pvr_page_table_l1_entry_raw - A single entry in a level 1 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 63..41 + * - *(reserved)* + * + * * - 40 + * - **Pending:** When valid bit is not set, indicates that a valid entry + * is pending and the MMU should wait for the driver to map the entry. + * This is used to support page demand mapping of memory. + * + * * - 39..5 + * - **Level 0 Page Table Base Address:** The way this value is + * interpreted depends on the page size. Bits not specified in the + * table below (e.g. bits 11..5 for page size 4KiB) should be + * considered reserved. + * + * This table shows the bits used in an L1 page table entry to + * represent the Physical Table Base Address for a given Page Size. + * Since each L1 page table entry covers 2MiB of address space, the + * maximum page size is 2MiB. + * + * .. flat-table:: + * :widths: 1 1 1 1 + * :header-rows: 1 + * :stub-columns: 1 + * + * * - Page size + * - L0 page table base address bits + * - Number of L0 page table entries + * - Size of L0 page table + * + * * - 4KiB + * - 39..12 + * - 512 + * - 4KiB + * + * * - 16KiB + * - 39..10 + * - 128 + * - 1KiB + * + * * - 64KiB + * - 39..8 + * - 32 + * - 256B + * + * * - 256KiB + * - 39..6 + * - 8 + * - 64B + * + * * - 1MiB + * - 39..5 (4 = '0') + * - 2 + * - 16B + * + * * - 2MiB + * - 39..5 (4..3 = '00') + * - 1 + * - 8B + * + * * - 4 + * - *(reserved)* + * + * * - 3..1 + * - **Page Size:** Sets the page size, from 4KiB to 2MiB. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid L0 page table. + * If the valid bit is not set, then an attempted use of the page would + * result in a page fault. + */ +struct pvr_page_table_l1_entry_raw { + u64 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l1_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE); + +static bool +pvr_page_table_l1_entry_raw_is_valid(struct pvr_page_table_l1_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(1, PD, VALID, entry); +} + +/** + * pvr_page_table_l1_entry_raw_set() - Write a valid entry into a raw level 1 + * page table. + * @entry: Target raw level 1 page table entry. + * @child_table_dma_addr: DMA address of the level 0 page table to be + * associated with @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of 4 KiB. + */ +static void +pvr_page_table_l1_entry_raw_set(struct pvr_page_table_l1_entry_raw *entry, + dma_addr_t child_table_dma_addr) +{ + WRITE_ONCE(entry->val, + PVR_PAGE_TABLE_FIELD_PREP(1, PD, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(1, PD, ENTRY_PENDING, false) | + PVR_PAGE_TABLE_FIELD_PREP(1, PD, PAGE_SIZE, ROGUE_MMUCTRL_PAGE_SIZE_X) | + /* + * The use of a 4K-specific macro here is correct. It is + * a future optimization to allocate sub-host-page-sized + * blocks for individual tables, so the condition that any + * page table address is aligned to the size of the + * largest (a 4KB) table currently holds. + */ + (child_table_dma_addr & ~ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_CLRMSK)); +} + +static void +pvr_page_table_l1_entry_raw_clear(struct pvr_page_table_l1_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * struct pvr_page_table_l0_entry_raw - A single entry in a level 0 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 63 + * - *(reserved)* + * + * * - 62 + * - **PM/FW Protect:** Indicates a protected region which only the + * Parameter Manager (PM) or firmware processor can write to. + * + * * - 61..40 + * - **VP Page (High):** Virtual-physical page used for Parameter Manager + * (PM) memory. This field is only used if the additional level of PB + * virtualization is enabled. The VP Page field is needed by the PM in + * order to correctly reconstitute the free lists after render + * completion. This (High) field holds bits 39..18 of the value; the + * Low field holds bits 17..12. Bits 11..0 are always zero because the + * value is always aligned to the 4KiB page size. + * + * * - 39..12 + * - **Physical Page Address:** The way this value is interpreted depends + * on the page size. Bits not specified in the table below (e.g. bits + * 20..12 for page size 2MiB) should be considered reserved. + * + * This table shows the bits used in an L0 page table entry to represent + * the Physical Page Address for a given page size (as defined in the + * associated L1 page table entry). + * + * .. flat-table:: + * :widths: 1 1 + * :header-rows: 1 + * :stub-columns: 1 + * + * * - Page size + * - Physical address bits + * + * * - 4KiB + * - 39..12 + * + * * - 16KiB + * - 39..14 + * + * * - 64KiB + * - 39..16 + * + * * - 256KiB + * - 39..18 + * + * * - 1MiB + * - 39..20 + * + * * - 2MiB + * - 39..21 + * + * * - 11..6 + * - **VP Page (Low):** Continuation of VP Page (High). + * + * * - 5 + * - **Pending:** When valid bit is not set, indicates that a valid entry + * is pending and the MMU should wait for the driver to map the entry. + * This is used to support page demand mapping of memory. + * + * * - 4 + * - **PM Src:** Set on Parameter Manager (PM) allocated page table + * entries when indicated by the PM. Note that this bit will only be set + * by the PM, not by the device driver. + * + * * - 3 + * - **SLC Bypass Control:** Specifies requests to this page should bypass + * the System Level Cache (SLC), if enabled in SLC configuration. + * + * * - 2 + * - **Cache Coherency:** Indicates that the page is coherent (i.e. it + * does not require a cache flush between operations on the CPU and the + * device). + * + * * - 1 + * - **Read Only:** If set, this bit indicates that the page is read only. + * An attempted write to this page would result in a write-protection + * fault. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid page. If the + * valid bit is not set, then an attempted use of the page would result + * in a page fault. + */ +struct pvr_page_table_l0_entry_raw { + u64 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l0_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE); + +/** + * struct pvr_page_flags_raw - The configurable flags from a single entry in a + * level 0 page table. + * @val: The raw value of these flags. Since these are a strict subset of + * &struct pvr_page_table_l0_entry_raw; use that type for our member here. + * + * The flags stored in this type are: PM/FW Protect; SLC Bypass Control; Cache + * Coherency, and Read Only (bits 62, 3, 2 and 1 respectively). + * + * This type should never be instantiated directly; instead use + * pvr_page_flags_raw_create() to ensure only valid bits of @val are set. + */ +struct pvr_page_flags_raw { + struct pvr_page_table_l0_entry_raw val; +} __packed; +static_assert(sizeof(struct pvr_page_flags_raw) == + sizeof(struct pvr_page_table_l0_entry_raw)); + +static bool +pvr_page_table_l0_entry_raw_is_valid(struct pvr_page_table_l0_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(0, PT, VALID, entry); +} + +/** + * pvr_page_table_l0_entry_raw_set() - Write a valid entry into a raw level 0 + * page table. + * @entry: Target raw level 0 page table entry. + * @dma_addr: DMA address of the physical page to be associated with @entry. + * @flags: Options to be set on @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of %PVR_DEVICE_PAGE_SIZE. + * + * The @flags parameter is directly assigned into @entry. It is the callers + * responsibility to ensure that only bits specified in + * &struct pvr_page_flags_raw are set in @flags. + */ +static void +pvr_page_table_l0_entry_raw_set(struct pvr_page_table_l0_entry_raw *entry, + dma_addr_t dma_addr, + struct pvr_page_flags_raw flags) +{ + WRITE_ONCE(entry->val, PVR_PAGE_TABLE_FIELD_PREP(0, PT, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, ENTRY_PENDING, false) | + (dma_addr & ~ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK) | + flags.val.val); +} + +static void +pvr_page_table_l0_entry_raw_clear(struct pvr_page_table_l0_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * pvr_page_flags_raw_create() - Initialize the flag bits of a raw level 0 page + * table entry. + * @read_only: This page is read-only (see: Read Only). + * @cache_coherent: This page does not require cache flushes (see: Cache + * Coherency). + * @slc_bypass: This page bypasses the device cache (see: SLC Bypass Control). + * @pm_fw_protect: This page is only for use by the firmware or Parameter + * Manager (see PM/FW Protect). + * + * For more details on the use of these four options, see their respective + * entries in the table under &struct pvr_page_table_l0_entry_raw. + * + * Return: + * A new &struct pvr_page_flags_raw instance which can be passed directly to + * pvr_page_table_l0_entry_raw_set() or pvr_page_table_l0_insert(). + */ +static struct pvr_page_flags_raw +pvr_page_flags_raw_create(bool read_only, bool cache_coherent, bool slc_bypass, + bool pm_fw_protect) +{ + struct pvr_page_flags_raw flags; + + flags.val.val = + PVR_PAGE_TABLE_FIELD_PREP(0, PT, READ_ONLY, read_only) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, CC, cache_coherent) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, SLC_BYPASS_CTRL, slc_bypass) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, PM_META_PROTECT, pm_fw_protect); + + return flags; +} + +/** + * struct pvr_page_table_l2_raw - The raw data of a level 2 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + */ +struct pvr_page_table_l2_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l2_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PC_VALUE]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l2_raw) == PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_page_table_l1_raw - The raw data of a level 1 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + */ +struct pvr_page_table_l1_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l1_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PD_VALUE]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l1_raw) == PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_page_table_l0_raw - The raw data of a level 0 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + * + * .. caution:: + * + * The size of level 0 page tables is variable depending on the page size + * specified in the associated level 1 page table entry. Since the device + * page size in use is pegged to the host page size, it cannot vary at + * runtime. This structure is therefore only defined to contain the required + * number of entries for the current device page size. **You should never + * read or write beyond the last supported entry.** + */ +struct pvr_page_table_l0_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l0_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l0_raw) <= PVR_MMU_BACKING_PAGE_SIZE); + +/** + * DOC: Mirror page tables + */ + +/* + * We pre-declare these types because they cross-depend on pointers to each + * other. + */ +struct pvr_page_table_l1; +struct pvr_page_table_l0; + +/** + * struct pvr_page_table_l2 - A wrapped level 2 page table. + * + * To access the raw part of this table, use pvr_page_table_l2_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l2_get_entry_raw(). + * + * A level 2 page table forms the root of the page table tree structure, so + * this type has no &parent or &parent_idx members. + */ +struct pvr_page_table_l2 { + /** + * @entries: The children of this node in the page table tree + * structure. These are also mirror tables. The indexing of this array + * is identical to that of the raw equivalent + * (&pvr_page_table_l1_raw.entries). + */ + struct pvr_page_table_l1 *entries[ROGUE_MMUCTRL_ENTRIES_PC_VALUE]; + + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l2_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l2_init() - Initialize a level 2 page table. + * @table: Target level 2 page table. + * @pvr_dev: Target PowerVR device + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l2_init(struct pvr_page_table_l2 *table, + struct pvr_device *pvr_dev) +{ + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l2_fini() - Teardown a level 2 page table. + * @table: Target level 2 page table. + * + * It is an error to attempt to use @table after calling this function. + */ +static void +pvr_page_table_l2_fini(struct pvr_page_table_l2 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); +} + +/** + * pvr_page_table_l2_sync() - Flush a level 2 page table from the CPU to the + * device. + * @table: Target level 2 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l2_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child level 1 page tables of @table also need to be flushed, this should + * be done first using pvr_page_table_l1_sync() *before* calling this function. + */ +static void +pvr_page_table_l2_sync(struct pvr_page_table_l2 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_2_FLAGS); +} + +/** + * pvr_page_table_l2_get_raw() - Access the raw equivalent of a mirror level 2 + * page table. + * @table: Target level 2 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l2_raw pointer. + * + * You probably want to call pvr_page_table_l2_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l2_raw * +pvr_page_table_l2_get_raw(struct pvr_page_table_l2 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l2_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 2 page table. + * @table: Target level 2 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 2 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l2_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. + * + * Return: + * A pointer to the requested raw level 2 page table entry. + */ +static struct pvr_page_table_l2_entry_raw * +pvr_page_table_l2_get_entry_raw(struct pvr_page_table_l2 *table, u16 idx) +{ + return &pvr_page_table_l2_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l2_entry_is_valid() - Check if a level 2 page table entry is + * marked as valid. + * @table: Target level 2 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l2_entry_is_valid(struct pvr_page_table_l2 *table, u16 idx) +{ + struct pvr_page_table_l2_entry_raw entry_raw = + *pvr_page_table_l2_get_entry_raw(table, idx); + + return pvr_page_table_l2_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_page_table_l1 - A wrapped level 1 page table. + * + * To access the raw part of this table, use pvr_page_table_l1_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l1_get_entry_raw(). + */ +struct pvr_page_table_l1 { + /** + * @entries: The children of this node in the page table tree + * structure. These are also mirror tables. The indexing of this array + * is identical to that of the raw equivalent + * (&pvr_page_table_l0_raw.entries). + */ + struct pvr_page_table_l0 *entries[ROGUE_MMUCTRL_ENTRIES_PD_VALUE]; + + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + union { + /** + * @parent: The parent of this node in the page table tree structure. + * + * This is also a mirror table. + * + * Only valid when the L1 page table is active. When the L1 page table + * has been removed and queued for destruction, the next_free field + * should be used instead. + */ + struct pvr_page_table_l2 *parent; + + /** + * @next_free: Pointer to the next L1 page table to take/free. + * + * Used to form a linked list of L1 page tables. This is used + * when preallocating tables and when the page table has been + * removed and queued for destruction. + */ + struct pvr_page_table_l1 *next_free; + }; + + /** + * @parent_idx: The index of the entry in the parent table (see + * @parent) which corresponds to this table. + */ + u16 parent_idx; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l1_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l1_init() - Initialize a level 1 page table. + * @table: Target level 1 page table. + * @pvr_dev: Target PowerVR device + * + * When this function returns successfully, @table is still not considered + * valid. It must be inserted into the page table tree structure with + * pvr_page_table_l2_insert() before it is ready for use. + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l1_init(struct pvr_page_table_l1 *table, + struct pvr_device *pvr_dev) +{ + table->parent_idx = PVR_IDX_INVALID; + + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l1_free() - Teardown a level 1 page table. + * @table: Target level 1 page table. + * + * It is an error to attempt to use @table after calling this function, even + * indirectly. This includes calling pvr_page_table_l2_remove(), which must + * be called *before* pvr_page_table_l1_free(). + */ +static void +pvr_page_table_l1_free(struct pvr_page_table_l1 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); + kfree(table); +} + +/** + * pvr_page_table_l1_sync() - Flush a level 1 page table from the CPU to the + * device. + * @table: Target level 1 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l1_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child level 0 page tables of @table also need to be flushed, this should + * be done first using pvr_page_table_l0_sync() *before* calling this function. + */ +static void +pvr_page_table_l1_sync(struct pvr_page_table_l1 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_1_FLAGS); +} + +/** + * pvr_page_table_l1_get_raw() - Access the raw equivalent of a mirror level 1 + * page table. + * @table: Target level 1 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l1_raw pointer. + * + * You probably want to call pvr_page_table_l1_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l1_raw * +pvr_page_table_l1_get_raw(struct pvr_page_table_l1 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l1_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 1 page table. + * @table: Target level 1 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 1 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l1_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. + * + * Return: + * A pointer to the requested raw level 1 page table entry. + */ +static struct pvr_page_table_l1_entry_raw * +pvr_page_table_l1_get_entry_raw(struct pvr_page_table_l1 *table, u16 idx) +{ + return &pvr_page_table_l1_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l1_entry_is_valid() - Check if a level 1 page table entry is + * marked as valid. + * @table: Target level 1 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l1_entry_is_valid(struct pvr_page_table_l1 *table, u16 idx) +{ + struct pvr_page_table_l1_entry_raw entry_raw = + *pvr_page_table_l1_get_entry_raw(table, idx); + + return pvr_page_table_l1_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_page_table_l0 - A wrapped level 0 page table. + * + * To access the raw part of this table, use pvr_page_table_l0_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l0_get_entry_raw(). + * + * There is no mirror representation of an individual page, so this type has no + * &entries member. + */ +struct pvr_page_table_l0 { + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + union { + /** + * @parent: The parent of this node in the page table tree structure. + * + * This is also a mirror table. + * + * Only valid when the L0 page table is active. When the L0 page table + * has been removed and queued for destruction, the next_free field + * should be used instead. + */ + struct pvr_page_table_l1 *parent; + + /** + * @next_free: Pointer to the next L0 page table to take/free. + * + * Used to form a linked list of L0 page tables. This is used + * when preallocating tables and when the page table has been + * removed and queued for destruction. + */ + struct pvr_page_table_l0 *next_free; + }; + + /** + * @parent_idx: The index of the entry in the parent table (see + * @parent) which corresponds to this table. + */ + u16 parent_idx; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l0_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l0_init() - Initialize a level 0 page table. + * @table: Target level 0 page table. + * @pvr_dev: Target PowerVR device + * + * When this function returns successfully, @table is still not considered + * valid. It must be inserted into the page table tree structure with + * pvr_page_table_l1_insert() before it is ready for use. + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l0_init(struct pvr_page_table_l0 *table, + struct pvr_device *pvr_dev) +{ + table->parent_idx = PVR_IDX_INVALID; + + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l0_free() - Teardown a level 0 page table. + * @table: Target level 0 page table. + * + * It is an error to attempt to use @table after calling this function, even + * indirectly. This includes calling pvr_page_table_l1_remove(), which must + * be called *before* pvr_page_table_l0_free(). + */ +static void +pvr_page_table_l0_free(struct pvr_page_table_l0 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); + kfree(table); +} + +/** + * pvr_page_table_l0_sync() - Flush a level 0 page table from the CPU to the + * device. + * @table: Target level 0 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l0_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child pages of @table also need to be flushed, this should be done first + * using a DMA sync function (e.g. dma_sync_sg_for_device()) *before* calling + * this function. + */ +static void +pvr_page_table_l0_sync(struct pvr_page_table_l0 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_0_FLAGS); +} + +/** + * pvr_page_table_l0_get_raw() - Access the raw equivalent of a mirror level 0 + * page table. + * @table: Target level 0 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l0_raw pointer. + * + * You probably want to call pvr_page_table_l0_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l0_raw * +pvr_page_table_l0_get_raw(struct pvr_page_table_l0 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l0_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 0 page table. + * @table: Target level 0 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 0 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l0_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. This is espcially important for level 0 page tables, which + * can have a variable number of entries. + * + * Return: + * A pointer to the requested raw level 0 page table entry. + */ +static struct pvr_page_table_l0_entry_raw * +pvr_page_table_l0_get_entry_raw(struct pvr_page_table_l0 *table, u16 idx) +{ + return &pvr_page_table_l0_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l0_entry_is_valid() - Check if a level 0 page table entry is + * marked as valid. + * @table: Target level 0 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l0_entry_is_valid(struct pvr_page_table_l0 *table, u16 idx) +{ + struct pvr_page_table_l0_entry_raw entry_raw = + *pvr_page_table_l0_get_entry_raw(table, idx); + + return pvr_page_table_l0_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_mmu_context - context holding data for operations at page + * catalogue level, intended for use with a VM context. + */ +struct pvr_mmu_context { + /** @pvr_dev: The PVR device associated with the owning VM context. */ + struct pvr_device *pvr_dev; + + /** @page_table_l2: The MMU table root. */ + struct pvr_page_table_l2 page_table_l2; +}; + +/** + * struct pvr_page_table_ptr - A reference to a single physical page as indexed + * by the page table structure. + * + * Intended for embedding in a &struct pvr_mmu_op_context. + */ +struct pvr_page_table_ptr { + /** + * @l1_table: A cached handle to the level 1 page table the + * context is currently traversing. + */ + struct pvr_page_table_l1 *l1_table; + + /** + * @l0_table: A cached handle to the level 0 page table the + * context is currently traversing. + */ + struct pvr_page_table_l0 *l0_table; + + /** + * @l2_idx: Index into the level 2 page table the context is + * currently referencing. + */ + u16 l2_idx; + + /** + * @l1_idx: Index into the level 1 page table the context is + * currently referencing. + */ + u16 l1_idx; + + /** + * @l0_idx: Index into the level 0 page table the context is + * currently referencing. + */ + u16 l0_idx; +}; + +/** + * struct pvr_mmu_op_context - context holding data for individual + * device-virtual mapping operations. Intended for use with a VM bind operation. + */ +struct pvr_mmu_op_context { + /** @mmu_ctx: The MMU context associated with the owning VM context. */ + struct pvr_mmu_context *mmu_ctx; + + /** @map: Data specifically for map operations. */ + struct { + /** + * @sgt: Scatter gather table containing pages pinned for use by + * this context - these are currently pinned when initialising + * the VM bind operation. + */ + struct sg_table *sgt; + + /** @sgt_offset: Start address of the device-virtual mapping. */ + u64 sgt_offset; + + /** + * @l1_prealloc_tables: Preallocated l1 page table objects + * use by this context when creating a page mapping. Linked list + * fully created during initialisation. + */ + struct pvr_page_table_l1 *l1_prealloc_tables; + + /** + * @l0_prealloc_tables: Preallocated l0 page table objects + * use by this context when creating a page mapping. Linked list + * fully created during initialisation. + */ + struct pvr_page_table_l0 *l0_prealloc_tables; + } map; + + /** @unmap: Data specifically for unmap operations. */ + struct { + /** + * @l1_free_tables: Collects page table objects freed by unmap + * ops. Linked list empty at creation. + */ + struct pvr_page_table_l1 *l1_free_tables; + + /** + * @l0_free_tables: Collects page table objects freed by unmap + * ops. Linked list empty at creation. + */ + struct pvr_page_table_l0 *l0_free_tables; + } unmap; + + /** + * @curr_page: A reference to a single physical page as indexed by the + * page table structure. + */ + struct pvr_page_table_ptr curr_page; + + /** + * @sync_level_required: The maximum level of the page table tree + * structure which has (possibly) been modified since it was last + * flushed to the device. + * + * This field should only be set with pvr_mmu_op_context_require_sync() + * or indirectly by pvr_mmu_op_context_sync_partial(). + */ + enum pvr_mmu_sync_level sync_level_required; +}; + +/** + * pvr_page_table_l2_insert() - Insert an entry referring to a level 1 page + * table into a level 2 page table. + * @op_ctx: Target MMU op context pointing at the entry to insert the L1 page + * table into. + * @child_table: Target level 1 page table to be referenced by the new entry. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L2 entry. + * + * It is the caller's responsibility to execute any memory barries to ensure + * that the creation of @child_table is ordered before the L2 entry is inserted. + */ +static void +pvr_page_table_l2_insert(struct pvr_mmu_op_context *op_ctx, + struct pvr_page_table_l1 *child_table) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l2_entry_raw *entry_raw = + pvr_page_table_l2_get_entry_raw(l2_table, + op_ctx->curr_page.l2_idx); + + pvr_page_table_l2_entry_raw_set(entry_raw, + child_table->backing_page.dma_addr); + + child_table->parent = l2_table; + child_table->parent_idx = op_ctx->curr_page.l2_idx; + l2_table->entries[op_ctx->curr_page.l2_idx] = child_table; + ++l2_table->entry_count; + op_ctx->curr_page.l1_table = child_table; +} + +/** + * pvr_page_table_l2_remove() - Remove a level 1 page table from a level 2 page + * table. + * @op_ctx: Target MMU op context pointing at the L2 entry to remove. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L2 entry. + */ +static void +pvr_page_table_l2_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l2_entry_raw *entry_raw = + pvr_page_table_l2_get_entry_raw(l2_table, + op_ctx->curr_page.l1_table->parent_idx); + + WARN_ON(op_ctx->curr_page.l1_table->parent != l2_table); + + pvr_page_table_l2_entry_raw_clear(entry_raw); + + l2_table->entries[op_ctx->curr_page.l1_table->parent_idx] = NULL; + op_ctx->curr_page.l1_table->parent_idx = PVR_IDX_INVALID; + op_ctx->curr_page.l1_table->next_free = op_ctx->unmap.l1_free_tables; + op_ctx->unmap.l1_free_tables = op_ctx->curr_page.l1_table; + op_ctx->curr_page.l1_table = NULL; + + --l2_table->entry_count; +} + +/** + * pvr_page_table_l1_insert() - Insert an entry referring to a level 0 page + * table into a level 1 page table. + * @op_ctx: Target MMU op context pointing at the entry to insert the L0 page + * table into. + * @child_table: L0 page table to insert. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L1 entry. + * + * It is the caller's responsibility to execute any memory barries to ensure + * that the creation of @child_table is ordered before the L1 entry is inserted. + */ +static void +pvr_page_table_l1_insert(struct pvr_mmu_op_context *op_ctx, + struct pvr_page_table_l0 *child_table) +{ + struct pvr_page_table_l1_entry_raw *entry_raw = + pvr_page_table_l1_get_entry_raw(op_ctx->curr_page.l1_table, + op_ctx->curr_page.l1_idx); + + pvr_page_table_l1_entry_raw_set(entry_raw, + child_table->backing_page.dma_addr); + + child_table->parent = op_ctx->curr_page.l1_table; + child_table->parent_idx = op_ctx->curr_page.l1_idx; + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l1_idx] = child_table; + ++op_ctx->curr_page.l1_table->entry_count; + op_ctx->curr_page.l0_table = child_table; +} + +/** + * pvr_page_table_l1_remove() - Remove a level 0 page table from a level 1 page + * table. + * @op_ctx: Target MMU op context pointing at the L1 entry to remove. + * + * If this function results in the L1 table becoming empty, it will be removed + * from its parent level 2 page table and destroyed. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L1 entry. + */ +static void +pvr_page_table_l1_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l1_entry_raw *entry_raw = + pvr_page_table_l1_get_entry_raw(op_ctx->curr_page.l0_table->parent, + op_ctx->curr_page.l0_table->parent_idx); + + WARN_ON(op_ctx->curr_page.l0_table->parent != + op_ctx->curr_page.l1_table); + + pvr_page_table_l1_entry_raw_clear(entry_raw); + + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l0_table->parent_idx] = NULL; + op_ctx->curr_page.l0_table->parent_idx = PVR_IDX_INVALID; + op_ctx->curr_page.l0_table->next_free = op_ctx->unmap.l0_free_tables; + op_ctx->unmap.l0_free_tables = op_ctx->curr_page.l0_table; + op_ctx->curr_page.l0_table = NULL; + + if (--op_ctx->curr_page.l1_table->entry_count == 0) { + /* Clear the parent L2 page table entry. */ + if (op_ctx->curr_page.l1_table->parent_idx != PVR_IDX_INVALID) + pvr_page_table_l2_remove(op_ctx); + } +} + +/** + * pvr_page_table_l0_insert() - Insert an entry referring to a physical page + * into a level 0 page table. + * @op_ctx: Target MMU op context pointing at the L0 entry to insert. + * @dma_addr: Target DMA address to be referenced by the new entry. + * @flags: Page options to be stored in the new entry. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L0 entry. + */ +static void +pvr_page_table_l0_insert(struct pvr_mmu_op_context *op_ctx, + dma_addr_t dma_addr, struct pvr_page_flags_raw flags) +{ + struct pvr_page_table_l0_entry_raw *entry_raw = + pvr_page_table_l0_get_entry_raw(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx); + + pvr_page_table_l0_entry_raw_set(entry_raw, dma_addr, flags); + + /* + * There is no entry to set here - we don't keep a mirror of + * individual pages. + */ + + ++op_ctx->curr_page.l0_table->entry_count; +} + +/** + * pvr_page_table_l0_remove() - Remove a physical page from a level 0 page + * table. + * @op_ctx: Target MMU op context pointing at the L0 entry to remove. + * + * If this function results in the L0 table becoming empty, it will be removed + * from its parent L1 page table and destroyed. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L0 entry. + */ +static void +pvr_page_table_l0_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l0_entry_raw *entry_raw = + pvr_page_table_l0_get_entry_raw(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx); + + pvr_page_table_l0_entry_raw_clear(entry_raw); + + /* + * There is no entry to clear here - we don't keep a mirror of + * individual pages. + */ + + if (--op_ctx->curr_page.l0_table->entry_count == 0) { + /* Clear the parent L1 page table entry. */ + if (op_ctx->curr_page.l0_table->parent_idx != PVR_IDX_INVALID) + pvr_page_table_l1_remove(op_ctx); + } +} + +/** + * DOC: Page table index utilities + */ + +/** + * pvr_page_table_l2_idx() - Calculate the level 2 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 2 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l2_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PC_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT; +} + +/** + * pvr_page_table_l1_idx() - Calculate the level 1 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 1 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l1_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PD_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT; +} + +/** + * pvr_page_table_l0_idx() - Calculate the level 0 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 0 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l0_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PT_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT; +} + +/** + * DOC: High-level page table operations + */ + +/** + * pvr_page_table_l1_get_or_insert() - Retrieves (optionally inserting if + * necessary) a level 1 page table from the specified level 2 page table entry. + * @op_ctx: Target MMU op context. + * @should_insert: [IN] Specifies whether new page tables should be inserted + * when empty page table entries are encountered during traversal. + * + * Return: + * * 0 on success, or + * + * If @should_insert is %false: + * * -%ENXIO if a level 1 page table would have been inserted. + * + * If @should_insert is %true: + * * Any error encountered while inserting the level 1 page table. + */ +static int +pvr_page_table_l1_get_or_insert(struct pvr_mmu_op_context *op_ctx, + bool should_insert) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l1 *table; + + if (pvr_page_table_l2_entry_is_valid(l2_table, + op_ctx->curr_page.l2_idx)) { + op_ctx->curr_page.l1_table = + l2_table->entries[op_ctx->curr_page.l2_idx]; + return 0; + } + + if (!should_insert) + return -ENXIO; + + /* Take a prealloced table. */ + table = op_ctx->map.l1_prealloc_tables; + if (!table) + return -ENOMEM; + + /* Pop */ + op_ctx->map.l1_prealloc_tables = table->next_free; + table->next_free = NULL; + + /* Ensure new table is fully written out before adding to L2 page table. */ + wmb(); + + pvr_page_table_l2_insert(op_ctx, table); + + return 0; +} + +/** + * pvr_page_table_l0_get_or_insert() - Retrieves (optionally inserting if + * necessary) a level 0 page table from the specified level 1 page table entry. + * @op_ctx: Target MMU op context. + * @should_insert: [IN] Specifies whether new page tables should be inserted + * when empty page table entries are encountered during traversal. + * + * Return: + * * 0 on success, + * + * If @should_insert is %false: + * * -%ENXIO if a level 0 page table would have been inserted. + * + * If @should_insert is %true: + * * Any error encountered while inserting the level 0 page table. + */ +static int +pvr_page_table_l0_get_or_insert(struct pvr_mmu_op_context *op_ctx, + bool should_insert) +{ + struct pvr_page_table_l0 *table; + + if (pvr_page_table_l1_entry_is_valid(op_ctx->curr_page.l1_table, + op_ctx->curr_page.l1_idx)) { + op_ctx->curr_page.l0_table = + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l1_idx]; + return 0; + } + + if (!should_insert) + return -ENXIO; + + /* Take a prealloced table. */ + table = op_ctx->map.l0_prealloc_tables; + if (!table) + return -ENOMEM; + + /* Pop */ + op_ctx->map.l0_prealloc_tables = table->next_free; + table->next_free = NULL; + + /* Ensure new table is fully written out before adding to L1 page table. */ + wmb(); + + pvr_page_table_l1_insert(op_ctx, table); + + return 0; +} + +/** + * pvr_mmu_context_create() - Create an MMU context. + * @pvr_dev: PVR device associated with owning VM context. + * + * Returns: + * * Newly created MMU context object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l2_init(). + */ +struct pvr_mmu_context *pvr_mmu_context_create(struct pvr_device *pvr_dev) +{ + struct pvr_mmu_context *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + int err; + + if (!ctx) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l2_init(&ctx->page_table_l2, pvr_dev); + if (err) + return ERR_PTR(err); + + ctx->pvr_dev = pvr_dev; + + return ctx; +} + +/** + * pvr_mmu_context_destroy() - Destroy an MMU context. + * @ctx: Target MMU context. + */ +void pvr_mmu_context_destroy(struct pvr_mmu_context *ctx) +{ + pvr_page_table_l2_fini(&ctx->page_table_l2); + kfree(ctx); +} + +/** + * pvr_mmu_get_root_table_dma_addr() - Get the DMA address of the root of the + * page table structure behind a VM context. + * @ctx: Target MMU context. + */ +dma_addr_t pvr_mmu_get_root_table_dma_addr(struct pvr_mmu_context *ctx) +{ + return ctx->page_table_l2.backing_page.dma_addr; +} + +/** + * pvr_page_table_l1_alloc() - Allocate a l1 page_table object. + * @ctx: MMU context of owning VM context. + * + * Returns: + * * Newly created page table object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l1_init(). + */ +static struct pvr_page_table_l1 * +pvr_page_table_l1_alloc(struct pvr_mmu_context *ctx) +{ + int err; + + struct pvr_page_table_l1 *table = + kzalloc(sizeof(*table), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l1_init(table, ctx->pvr_dev); + if (err) { + kfree(table); + return ERR_PTR(err); + } + + return table; +} + +/** + * pvr_page_table_l0_alloc() - Allocate a l0 page_table object. + * @ctx: MMU context of owning VM context. + * + * Returns: + * * Newly created page table object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l0_init(). + */ +static struct pvr_page_table_l0 * +pvr_page_table_l0_alloc(struct pvr_mmu_context *ctx) +{ + int err; + + struct pvr_page_table_l0 *table = + kzalloc(sizeof(*table), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l0_init(table, ctx->pvr_dev); + if (err) { + kfree(table); + return ERR_PTR(err); + } + + return table; +} + +/** + * pvr_mmu_op_context_require_sync() - Mark an MMU op context as requiring a + * sync operation for the referenced page tables up to a specified level. + * @op_ctx: Target MMU op context. + * @level: Maximum page table level for which a sync is required. + */ +static void +pvr_mmu_op_context_require_sync(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + if (op_ctx->sync_level_required < level) + op_ctx->sync_level_required = level; +} + +/** + * pvr_mmu_op_context_sync_manual() - Trigger a sync of some or all of the + * page tables referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @level: Maximum page table level to sync. + * + * Do not call this function directly. Instead use + * pvr_mmu_op_context_sync_partial() which is checked against the current + * value of &op_ctx->sync_level_required as set by + * pvr_mmu_op_context_require_sync(). + */ +static void +pvr_mmu_op_context_sync_manual(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + /* + * We sync the page table levels in ascending order (starting from the + * leaf node) to ensure consistency. + */ + + WARN_ON(level < PVR_MMU_SYNC_LEVEL_NONE); + + if (level <= PVR_MMU_SYNC_LEVEL_NONE) + return; + + if (op_ctx->curr_page.l0_table) + pvr_page_table_l0_sync(op_ctx->curr_page.l0_table); + + if (level < PVR_MMU_SYNC_LEVEL_1) + return; + + if (op_ctx->curr_page.l1_table) + pvr_page_table_l1_sync(op_ctx->curr_page.l1_table); + + if (level < PVR_MMU_SYNC_LEVEL_2) + return; + + pvr_page_table_l2_sync(&op_ctx->mmu_ctx->page_table_l2); +} + +/** + * pvr_mmu_op_context_sync_partial() - Trigger a sync of some or all of the + * page tables referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @level: Requested page table level to sync up to (inclusive). + * + * If @level is greater than the maximum level recorded by @op_ctx as requiring + * a sync operation, only the previously recorded maximum will be used. + * + * Additionally, if @level is greater than or equal to the maximum level + * recorded by @op_ctx as requiring a sync operation, that maximum level will be + * reset as a full sync will be performed. This is equivalent to calling + * pvr_mmu_op_context_sync(). + */ +static void +pvr_mmu_op_context_sync_partial(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + /* + * If the requested sync level is greater than or equal to the + * currently required sync level, we do two things: + * * Don't waste time syncing levels we haven't previously marked as + * requiring a sync, and + * * Reset the required sync level since we are about to sync + * everything that was previously marked as requiring a sync. + */ + if (level >= op_ctx->sync_level_required) { + level = op_ctx->sync_level_required; + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; + } + + pvr_mmu_op_context_sync_manual(op_ctx, level); +} + +/** + * pvr_mmu_op_context_sync() - Trigger a sync of every page table referenced by + * a MMU op context. + * @op_ctx: Target MMU op context. + * + * The maximum level marked internally as requiring a sync will be reset so + * that subsequent calls to this function will be no-ops unless @op_ctx is + * otherwise updated. + */ +static void +pvr_mmu_op_context_sync(struct pvr_mmu_op_context *op_ctx) +{ + pvr_mmu_op_context_sync_manual(op_ctx, op_ctx->sync_level_required); + + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; +} + +/** + * pvr_mmu_op_context_load_tables() - Load pointers to tables in each level of + * the page table tree structure needed to reference the physical page + * referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @should_create: Specifies whether new page tables should be created when + * empty page table entries are encountered during traversal. + * @load_level_required: Maximum page table level to load. + * + * If @should_create is %true, this function may modify the stored required + * sync level of @op_ctx as new page tables are created and inserted into their + * respective parents. + * + * Since there is only one root page table, it is technically incorrect to call + * this function with a value of @load_level_required greater than or equal to + * the root level number. However, this is not explicitly disallowed here. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_page_table_l1_get_or_create() if + * @load_level_required >= 1 except -%ENXIO, or + * * Any error returned by pvr_page_table_l0_get_or_create() if + * @load_level_required >= 0 except -%ENXIO. + */ +static int +pvr_mmu_op_context_load_tables(struct pvr_mmu_op_context *op_ctx, + bool should_create, + enum pvr_mmu_sync_level load_level_required) +{ + const struct pvr_page_table_l1 *l1_head_before = + op_ctx->map.l1_prealloc_tables; + const struct pvr_page_table_l0 *l0_head_before = + op_ctx->map.l0_prealloc_tables; + int err; + + /* Clear tables we're about to fetch in case of error states. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_1) + op_ctx->curr_page.l1_table = NULL; + + if (load_level_required >= PVR_MMU_SYNC_LEVEL_0) + op_ctx->curr_page.l0_table = NULL; + + /* Get or create L1 page table. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_1) { + err = pvr_page_table_l1_get_or_insert(op_ctx, should_create); + if (err) { + /* + * If @should_create is %false and no L1 page table was + * found, return early but without an error. Since + * pvr_page_table_l1_get_or_create() can only return + * -%ENXIO if @should_create is %false, there is no + * need to check it here. + */ + if (err == -ENXIO) + err = 0; + + return err; + } + } + + /* Get or create L0 page table. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_0) { + err = pvr_page_table_l0_get_or_insert(op_ctx, should_create); + if (err) { + /* + * If @should_create is %false and no L0 page table was + * found, return early but without an error. Since + * pvr_page_table_l0_get_or_insert() can only return + * -%ENXIO if @should_create is %false, there is no + * need to check it here. + */ + if (err == -ENXIO) + err = 0; + + /* + * At this point, an L1 page table could have been + * inserted but is now empty due to the failed attempt + * at inserting an L0 page table. In this instance, we + * must remove the empty L1 page table ourselves as + * pvr_page_table_l1_remove() is never called as part + * of the error path in + * pvr_page_table_l0_get_or_insert(). + */ + if (l1_head_before != op_ctx->map.l1_prealloc_tables) { + pvr_page_table_l2_remove(op_ctx); + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_2); + } + + return err; + } + } + + /* + * A sync is only needed if table objects were inserted. This can be + * inferred by checking if the pointer at the head of the linked list + * has changed. + */ + if (l1_head_before != op_ctx->map.l1_prealloc_tables) + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_2); + else if (l0_head_before != op_ctx->map.l0_prealloc_tables) + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_1); + + return 0; +} + +/** + * pvr_mmu_op_context_set_curr_page() - Reassign the current page of an MMU op + * context, syncing any page tables previously assigned to it which are no + * longer relevant. + * @op_ctx: Target MMU op context. + * @device_addr: New pointer target. + * @should_create: Specify whether new page tables should be created when + * empty page table entries are encountered during traversal. + * + * This function performs a full sync on the pointer, regardless of which + * levels are modified. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_op_context_load_tables(). + */ +static int +pvr_mmu_op_context_set_curr_page(struct pvr_mmu_op_context *op_ctx, + u64 device_addr, bool should_create) +{ + pvr_mmu_op_context_sync(op_ctx); + + op_ctx->curr_page.l2_idx = pvr_page_table_l2_idx(device_addr); + op_ctx->curr_page.l1_idx = pvr_page_table_l1_idx(device_addr); + op_ctx->curr_page.l0_idx = pvr_page_table_l0_idx(device_addr); + op_ctx->curr_page.l1_table = NULL; + op_ctx->curr_page.l0_table = NULL; + + return pvr_mmu_op_context_load_tables(op_ctx, should_create, + PVR_MMU_SYNC_LEVEL_1); +} + +/** + * pvr_mmu_op_context_next_page() - Advance the current page of an MMU op + * context. + * @op_ctx: Target MMU op context. + * @should_create: Specify whether new page tables should be created when + * empty page table entries are encountered during traversal. + * + * If @should_create is %false, it is the caller's responsibility to verify that + * the state of the table references in @op_ctx is valid on return. If -%ENXIO + * is returned, at least one of the table references is invalid. It should be + * noted that @op_ctx as a whole will be left in a valid state if -%ENXIO is + * returned, unlike other error codes. The caller should check which references + * are invalid by comparing them to %NULL. Only &@ptr->l2_table is guaranteed + * to be valid, since it represents the root of the page table tree structure. + * + * Return: + * * 0 on success, + * * -%EPERM if the operation would wrap at the top of the page table + * hierarchy, + * * -%ENXIO if @should_create is %false and a page table of any level would + * have otherwise been created, or + * * Any error returned while attempting to create missing page tables if + * @should_create is %true. + */ +static int +pvr_mmu_op_context_next_page(struct pvr_mmu_op_context *op_ctx, + bool should_create) +{ + s8 load_level_required = PVR_MMU_SYNC_LEVEL_NONE; + + if (++op_ctx->curr_page.l0_idx != ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X) + goto load_tables; + + op_ctx->curr_page.l0_idx = 0; + load_level_required = PVR_MMU_SYNC_LEVEL_0; + + if (++op_ctx->curr_page.l1_idx != ROGUE_MMUCTRL_ENTRIES_PD_VALUE) + goto load_tables; + + op_ctx->curr_page.l1_idx = 0; + load_level_required = PVR_MMU_SYNC_LEVEL_1; + + if (++op_ctx->curr_page.l2_idx != ROGUE_MMUCTRL_ENTRIES_PC_VALUE) + goto load_tables; + + /* + * If the pattern continued, we would set &op_ctx->curr_page.l2_idx to + * zero here. However, that would wrap the top layer of the page table + * hierarchy which is not a valid operation. Instead, we warn and return + * an error. + */ + WARN(true, + "%s(%p) attempted to loop the top of the page table hierarchy", + __func__, op_ctx); + return -EPERM; + + /* If indices have wrapped, we need to load new tables. */ +load_tables: + /* First, flush tables which will be unloaded. */ + pvr_mmu_op_context_sync_partial(op_ctx, load_level_required); + + /* Then load tables from the required level down. */ + return pvr_mmu_op_context_load_tables(op_ctx, should_create, + load_level_required); +} + +/** + * DOC: Single page operations + */ + +/** + * pvr_page_create() - Create a device-virtual memory page and insert it into + * a level 0 page table. + * @op_ctx: Target MMU op context pointing at the device-virtual address of the + * target page. + * @dma_addr: DMA address of the physical page backing the created page. + * @flags: Page options saved on the level 0 page table entry for reading by + * the device. + * + * Return: + * * 0 on success, or + * * -%EEXIST if the requested page already exists. + */ +static int +pvr_page_create(struct pvr_mmu_op_context *op_ctx, dma_addr_t dma_addr, + struct pvr_page_flags_raw flags) +{ + /* Do not create a new page if one already exists. */ + if (pvr_page_table_l0_entry_is_valid(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx)) { + return -EEXIST; + } + + pvr_page_table_l0_insert(op_ctx, dma_addr, flags); + + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); + + return 0; +} + +/** + * pvr_page_destroy() - Destroy a device page after removing it from its + * parent level 0 page table. + * @op_ctx: Target MMU op context. + */ +static void +pvr_page_destroy(struct pvr_mmu_op_context *op_ctx) +{ + /* Do nothing if the page does not exist. */ + if (!pvr_page_table_l0_entry_is_valid(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx)) { + return; + } + + /* Clear the parent L0 page table entry. */ + pvr_page_table_l0_remove(op_ctx); + + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); +} + +/** + * pvr_mmu_op_context_destroy() - Destroy an MMU op context. + * @op_ctx: Target MMU op context. + */ +void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx) +{ + const bool flush_caches = + op_ctx->sync_level_required != PVR_MMU_SYNC_LEVEL_NONE; + + pvr_mmu_op_context_sync(op_ctx); + + /* Unmaps should be flushed immediately. Map flushes can be deferred. */ + if (flush_caches && !op_ctx->map.sgt) + pvr_mmu_flush_exec(op_ctx->mmu_ctx->pvr_dev, true); + + while (op_ctx->map.l0_prealloc_tables) { + struct pvr_page_table_l0 *tmp = op_ctx->map.l0_prealloc_tables; + + op_ctx->map.l0_prealloc_tables = + op_ctx->map.l0_prealloc_tables->next_free; + pvr_page_table_l0_free(tmp); + } + + while (op_ctx->map.l1_prealloc_tables) { + struct pvr_page_table_l1 *tmp = op_ctx->map.l1_prealloc_tables; + + op_ctx->map.l1_prealloc_tables = + op_ctx->map.l1_prealloc_tables->next_free; + pvr_page_table_l1_free(tmp); + } + + while (op_ctx->unmap.l0_free_tables) { + struct pvr_page_table_l0 *tmp = op_ctx->unmap.l0_free_tables; + + op_ctx->unmap.l0_free_tables = + op_ctx->unmap.l0_free_tables->next_free; + pvr_page_table_l0_free(tmp); + } + + while (op_ctx->unmap.l1_free_tables) { + struct pvr_page_table_l1 *tmp = op_ctx->unmap.l1_free_tables; + + op_ctx->unmap.l1_free_tables = + op_ctx->unmap.l1_free_tables->next_free; + pvr_page_table_l1_free(tmp); + } + + kfree(op_ctx); +} + +/** + * pvr_mmu_op_context_create() - Create an MMU op context. + * @ctx: MMU context associated with owning VM context. + * @sgt: Scatter gather table containing pages pinned for use by this context. + * @sgt_offset: Start offset of the requested device-virtual memory mapping. + * @size: Size in bytes of the requested device-virtual memory mapping. For an + * unmapping, this should be zero so that no page tables are allocated. + * + * Returns: + * * Newly created MMU op context object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l2_init(). + */ +struct pvr_mmu_op_context * +pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt, + u64 sgt_offset, u64 size) +{ + int err; + + struct pvr_mmu_op_context *op_ctx = + kzalloc(sizeof(*op_ctx), GFP_KERNEL); + + if (!op_ctx) + return ERR_PTR(-ENOMEM); + + op_ctx->mmu_ctx = ctx; + op_ctx->map.sgt = sgt; + op_ctx->map.sgt_offset = sgt_offset; + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; + + if (size) { + /* + * The number of page table objects we need to prealloc is + * indicated by the mapping size, start offset and the sizes + * of the areas mapped per PT or PD. The range calculation is + * identical to that for the index into a table for a device + * address, so we reuse those functions here. + */ + const u32 l1_start_idx = pvr_page_table_l2_idx(sgt_offset); + const u32 l1_end_idx = pvr_page_table_l2_idx(sgt_offset + size); + const u32 l1_count = l1_end_idx - l1_start_idx + 1; + const u32 l0_start_idx = pvr_page_table_l1_idx(sgt_offset); + const u32 l0_end_idx = pvr_page_table_l1_idx(sgt_offset + size); + const u32 l0_count = l0_end_idx - l0_start_idx + 1; + + /* + * Alloc and push page table entries until we have enough of + * each type, ending with linked lists of l0 and l1 entries in + * reverse order. + */ + for (int i = 0; i < l1_count; i++) { + struct pvr_page_table_l1 *l1_tmp = + pvr_page_table_l1_alloc(ctx); + + err = PTR_ERR_OR_ZERO(l1_tmp); + if (err) + goto err_cleanup; + + l1_tmp->next_free = op_ctx->map.l1_prealloc_tables; + op_ctx->map.l1_prealloc_tables = l1_tmp; + } + + for (int i = 0; i < l0_count; i++) { + struct pvr_page_table_l0 *l0_tmp = + pvr_page_table_l0_alloc(ctx); + + err = PTR_ERR_OR_ZERO(l0_tmp); + if (err) + goto err_cleanup; + + l0_tmp->next_free = op_ctx->map.l0_prealloc_tables; + op_ctx->map.l0_prealloc_tables = l0_tmp; + } + } + + return op_ctx; + +err_cleanup: + pvr_mmu_op_context_destroy(op_ctx); + + return ERR_PTR(err); +} + +/** + * pvr_mmu_op_context_unmap_curr_page() - Unmap pages from a memory context + * starting from the current page of an MMU op context. + * @op_ctx: Target MMU op context pointing at the first page to unmap. + * @nr_pages: Number of pages to unmap. + * + * Return: + * * 0 on success, or + * * Any error encountered while advancing @op_ctx.curr_page with + * pvr_mmu_op_context_next_page() (except -%ENXIO). + */ +static int +pvr_mmu_op_context_unmap_curr_page(struct pvr_mmu_op_context *op_ctx, + u64 nr_pages) +{ + int err; + + if (nr_pages == 0) + return 0; + + /* + * Destroy first page outside loop, as it doesn't require a page + * advance beforehand. If the L0 page table reference in + * @op_ctx.curr_page is %NULL, there cannot be a mapped page at + * @op_ctx.curr_page (so skip ahead). + */ + if (op_ctx->curr_page.l0_table) + pvr_page_destroy(op_ctx); + + for (u64 page = 1; page < nr_pages; ++page) { + err = pvr_mmu_op_context_next_page(op_ctx, false); + /* + * If the page table tree structure at @op_ctx.curr_page is + * incomplete, skip ahead. We don't care about unmapping pages + * that cannot exist. + * + * FIXME: This could be made more efficient by jumping ahead + * using pvr_mmu_op_context_set_curr_page(). + */ + if (err == -ENXIO) + continue; + else if (err) + return err; + + pvr_page_destroy(op_ctx); + } + + return 0; +} + +/** + * pvr_mmu_unmap() - Unmap pages from a memory context. + * @op_ctx: Target MMU op context. + * @device_addr: First device-virtual address to unmap. + * @size: Size in bytes to unmap. + * + * The total amount of device-virtual memory unmapped is + * @nr_pages * %PVR_DEVICE_PAGE_SIZE. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_page_table_ptr_init(), or + * * Any error code returned by pvr_page_table_ptr_unmap(). + */ +int pvr_mmu_unmap(struct pvr_mmu_op_context *op_ctx, u64 device_addr, u64 size) +{ + int err = pvr_mmu_op_context_set_curr_page(op_ctx, device_addr, false); + + if (err) + return err; + + return pvr_mmu_op_context_unmap_curr_page(op_ctx, + size >> PVR_DEVICE_PAGE_SHIFT); +} + +/** + * pvr_mmu_map_sgl() - Map part of a scatter-gather table entry to + * device-virtual memory. + * @op_ctx: Target MMU op context pointing to the first page that should be + * mapped. + * @sgl: Target scatter-gather table entry. + * @offset: Offset into @sgl to map from. Must result in a starting address + * from @sgl which is CPU page-aligned. + * @size: Size of the memory to be mapped in bytes. Must be a non-zero multiple + * of the device page size. + * @page_flags: Page options to be applied to every device-virtual memory page + * in the created mapping. + * + * Return: + * * 0 on success, + * * -%EINVAL if the range specified by @offset and @size is not completely + * within @sgl, or + * * Any error encountered while creating a page with pvr_page_create(), or + * * Any error encountered while advancing @op_ctx.curr_page with + * pvr_mmu_op_context_next_page(). + */ +static int +pvr_mmu_map_sgl(struct pvr_mmu_op_context *op_ctx, struct scatterlist *sgl, + u64 offset, u64 size, struct pvr_page_flags_raw page_flags) +{ + const unsigned int pages = size >> PVR_DEVICE_PAGE_SHIFT; + dma_addr_t dma_addr = sg_dma_address(sgl) + offset; + const unsigned int dma_len = sg_dma_len(sgl); + struct pvr_page_table_ptr ptr_copy; + unsigned int page; + int err; + + if (size > dma_len || offset > dma_len - size) + return -EINVAL; + + /* + * Before progressing, save a copy of the start pointer so we can use + * it again if we enter an error state and have to destroy pages. + */ + memcpy(&ptr_copy, &op_ctx->curr_page, sizeof(ptr_copy)); + + /* + * Create first page outside loop, as it doesn't require a page advance + * beforehand. + */ + err = pvr_page_create(op_ctx, dma_addr, page_flags); + if (err) + return err; + + for (page = 1; page < pages; ++page) { + err = pvr_mmu_op_context_next_page(op_ctx, true); + if (err) + goto err_destroy_pages; + + dma_addr += PVR_DEVICE_PAGE_SIZE; + + err = pvr_page_create(op_ctx, dma_addr, page_flags); + if (err) + goto err_destroy_pages; + } + + return 0; + +err_destroy_pages: + memcpy(&op_ctx->curr_page, &ptr_copy, sizeof(op_ctx->curr_page)); + err = pvr_mmu_op_context_unmap_curr_page(op_ctx, page); + + return err; +} + +/** + * pvr_mmu_map() - Map an object's virtual memory to physical memory. + * @op_ctx: Target MMU op context. + * @size: Size of memory to be mapped in bytes. Must be a non-zero multiple + * of the device page size. + * @flags: Flags from pvr_gem_object associated with the mapping. + * @device_addr: Virtual device address to map to. Must be device page-aligned. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_page_table_ptr_init(), or + * * Any error code returned by pvr_mmu_map_sgl(), or + * * Any error code returned by pvr_page_table_ptr_next_page(). + */ +int pvr_mmu_map(struct pvr_mmu_op_context *op_ctx, u64 size, u64 flags, + u64 device_addr) +{ + struct pvr_page_table_ptr ptr_copy; + struct pvr_page_flags_raw flags_raw; + struct scatterlist *sgl; + u64 mapped_size = 0; + unsigned int count; + int err; + + if (!size) + return 0; + + if ((op_ctx->map.sgt_offset | size) & ~PVR_DEVICE_PAGE_MASK) + return -EINVAL; + + err = pvr_mmu_op_context_set_curr_page(op_ctx, device_addr, true); + if (err) + return -EINVAL; + + memcpy(&ptr_copy, &op_ctx->curr_page, sizeof(ptr_copy)); + + flags_raw = pvr_page_flags_raw_create(false, false, + flags & DRM_PVR_BO_BYPASS_DEVICE_CACHE, + flags & DRM_PVR_BO_PM_FW_PROTECT); + + /* Map scatter gather table */ + for_each_sgtable_dma_sg(op_ctx->map.sgt, sgl, count) { + const size_t sgl_len = sg_dma_len(sgl); + u64 sgl_offset, map_sgl_len; + + if (sgl_len <= op_ctx->map.sgt_offset) { + op_ctx->map.sgt_offset -= sgl_len; + continue; + } + + sgl_offset = op_ctx->map.sgt_offset; + map_sgl_len = min_t(u64, sgl_len - sgl_offset, size - mapped_size); + + err = pvr_mmu_map_sgl(op_ctx, sgl, sgl_offset, map_sgl_len, + flags_raw); + if (err) + break; + + /* + * Flag the L0 page table as requiring a flush when the MMU op + * context is destroyed. + */ + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); + + op_ctx->map.sgt_offset = 0; + mapped_size += map_sgl_len; + + if (mapped_size >= size) + break; + + err = pvr_mmu_op_context_next_page(op_ctx, true); + if (err) + break; + } + + if (err && mapped_size) { + memcpy(&op_ctx->curr_page, &ptr_copy, sizeof(op_ctx->curr_page)); + pvr_mmu_op_context_unmap_curr_page(op_ctx, + mapped_size >> PVR_DEVICE_PAGE_SHIFT); + } + + return err; +} diff --git a/drivers/gpu/drm/imagination/pvr_mmu.h b/drivers/gpu/drm/imagination/pvr_mmu.h new file mode 100644 index 000000000000..a8ecd460168d --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_mmu.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_MMU_H +#define PVR_MMU_H + +#include +#include + +/* Forward declaration from "pvr_device.h" */ +struct pvr_device; + +/* Forward declaration from "pvr_mmu.c" */ +struct pvr_mmu_context; +struct pvr_mmu_op_context; + +/* Forward declaration from "pvr_vm.c" */ +struct pvr_vm_context; + +/* Forward declaration from */ +struct sg_table; + +/** + * DOC: Public API (constants) + * + * .. c:macro:: PVR_DEVICE_PAGE_SIZE + * + * Fixed page size referenced by leaf nodes in the page table tree + * structure. In the current implementation, this value is pegged to the + * CPU page size (%PAGE_SIZE). It is therefore an error to specify a CPU + * page size which is not also a supported device page size. The supported + * device page sizes are: 4KiB, 16KiB, 64KiB, 256KiB, 1MiB and 2MiB. + * + * .. c:macro:: PVR_DEVICE_PAGE_SHIFT + * + * Shift value used to efficiently multiply or divide by + * %PVR_DEVICE_PAGE_SIZE. + * + * This value is derived from %PVR_DEVICE_PAGE_SIZE. + * + * .. c:macro:: PVR_DEVICE_PAGE_MASK + * + * Mask used to round a value down to the nearest multiple of + * %PVR_DEVICE_PAGE_SIZE. When bitwise negated, it will indicate whether a + * value is already a multiple of %PVR_DEVICE_PAGE_SIZE. + * + * This value is derived from %PVR_DEVICE_PAGE_SIZE. + */ + +/* PVR_DEVICE_PAGE_SIZE determines the page size */ +#define PVR_DEVICE_PAGE_SIZE (PAGE_SIZE) +#define PVR_DEVICE_PAGE_SHIFT (PAGE_SHIFT) +#define PVR_DEVICE_PAGE_MASK (PAGE_MASK) + +/** + * DOC: Page table index utilities (constants) + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_SPACE_SIZE + * + * Size of device-virtual address space which can be represented in the page + * table structure. + * + * This value is checked at runtime against + * &pvr_device_features.virtual_address_space_bits by + * pvr_vm_create_context(), which will return an error if the feature value + * does not match this constant. + * + * .. admonition:: Future work + * + * It should be possible to support other values of + * &pvr_device_features.virtual_address_space_bits, but so far no + * hardware has been created which advertises an unsupported value. + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_BITS + * + * Number of bits needed to represent any value less than + * %PVR_PAGE_TABLE_ADDR_SPACE_SIZE exactly. + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_MASK + * + * Bitmask of device-virtual addresses which are valid in the page table + * structure. + * + * This value is derived from %PVR_PAGE_TABLE_ADDR_SPACE_SIZE, so the same + * notes on that constant apply here. + */ +#define PVR_PAGE_TABLE_ADDR_SPACE_SIZE SZ_1T +#define PVR_PAGE_TABLE_ADDR_BITS __ffs(PVR_PAGE_TABLE_ADDR_SPACE_SIZE) +#define PVR_PAGE_TABLE_ADDR_MASK (PVR_PAGE_TABLE_ADDR_SPACE_SIZE - 1) + +void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev); +int pvr_mmu_flush_exec(struct pvr_device *pvr_dev, bool wait); + +struct pvr_mmu_context *pvr_mmu_context_create(struct pvr_device *pvr_dev); +void pvr_mmu_context_destroy(struct pvr_mmu_context *ctx); + +dma_addr_t pvr_mmu_get_root_table_dma_addr(struct pvr_mmu_context *ctx); + +void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx); +struct pvr_mmu_op_context * +pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, + struct sg_table *sgt, u64 sgt_offset, u64 size); + +int pvr_mmu_map(struct pvr_mmu_op_context *op_ctx, u64 size, u64 flags, + u64 device_addr); +int pvr_mmu_unmap(struct pvr_mmu_op_context *op_ctx, u64 device_addr, u64 size); + +#endif /* PVR_MMU_H */ diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c new file mode 100644 index 000000000000..4c48a208c390 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -0,0 +1,1091 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_vm.h" + +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_mmu.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_heap_config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: Memory context + * + * This is the "top level" datatype in the VM code. It's exposed in the public + * API as an opaque handle. + */ + +/** + * struct pvr_vm_context - Context type used to represent a single VM. + */ +struct pvr_vm_context { + /** + * @pvr_dev: The PowerVR device to which this context is bound. + * This binding is immutable for the life of the context. + */ + struct pvr_device *pvr_dev; + + /** @mmu_ctx: The context for binding to physical memory. */ + struct pvr_mmu_context *mmu_ctx; + + /** @gpuva_mgr: GPUVA manager object associated with this context. */ + struct drm_gpuvm gpuvm_mgr; + + /** @lock: Global lock on this VM. */ + struct mutex lock; + + /** + * @fw_mem_ctx_obj: Firmware object representing firmware memory + * context. + */ + struct pvr_fw_object *fw_mem_ctx_obj; + + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** + * @dummy_gem: GEM object to enable VM reservation. All private BOs + * should use the @dummy_gem.resv and not their own _resv field. + */ + struct drm_gem_object dummy_gem; +}; + +struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx) +{ + if (vm_ctx) + kref_get(&vm_ctx->ref_count); + + return vm_ctx; +} + +/** + * pvr_vm_get_page_table_root_addr() - Get the DMA address of the root of the + * page table structure behind a VM context. + * @vm_ctx: Target VM context. + */ +dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx) +{ + return pvr_mmu_get_root_table_dma_addr(vm_ctx->mmu_ctx); +} + +/** + * pvr_vm_get_dma_resv() - Expose the dma_resv owned by the VM context. + * @vm_ctx: Target VM context. + * + * This is used to allow private BOs to share a dma_resv for faster fence + * updates. + * + * Returns: The dma_resv pointer. + */ +struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx) +{ + return vm_ctx->dummy_gem.resv; +} + +/** + * DOC: Memory mappings + */ + +/** + * struct pvr_vm_gpuva - Wrapper type representing a single VM mapping. + */ +struct pvr_vm_gpuva { + /** @base: The wrapped drm_gpuva object. */ + struct drm_gpuva base; +}; + +static __always_inline +struct pvr_vm_gpuva *to_pvr_vm_gpuva(struct drm_gpuva *gpuva) +{ + return container_of(gpuva, struct pvr_vm_gpuva, base); +} + +enum pvr_vm_bind_type { + PVR_VM_BIND_TYPE_MAP, + PVR_VM_BIND_TYPE_UNMAP, +}; + +/** + * struct pvr_vm_bind_op - Context of a map/unmap operation. + */ +struct pvr_vm_bind_op { + /** @type: Map or unmap. */ + enum pvr_vm_bind_type type; + + /** @pvr_obj: Object associated with mapping (map only). */ + struct pvr_gem_object *pvr_obj; + + /** + * @vm_ctx: VM context where the mapping will be created or destroyed. + */ + struct pvr_vm_context *vm_ctx; + + /** @mmu_op_ctx: MMU op context. */ + struct pvr_mmu_op_context *mmu_op_ctx; + + /** @gpuvm_bo: Prealloced wrapped BO for attaching to the gpuvm. */ + struct drm_gpuvm_bo *gpuvm_bo; + + /** + * @new_va: Prealloced VA mapping object (init in callback). + * Used when creating a mapping. + */ + struct pvr_vm_gpuva *new_va; + + /** + * @prev_va: Prealloced VA mapping object (init in callback). + * Used when a mapping or unmapping operation overlaps an existing + * mapping and splits away the beginning into a new mapping. + */ + struct pvr_vm_gpuva *prev_va; + + /** + * @next_va: Prealloced VA mapping object (init in callback). + * Used when a mapping or unmapping operation overlaps an existing + * mapping and splits away the end into a new mapping. + */ + struct pvr_vm_gpuva *next_va; + + /** @offset: Offset into @pvr_obj to begin mapping from. */ + u64 offset; + + /** @device_addr: Device-virtual address at the start of the mapping. */ + u64 device_addr; + + /** @size: Size of the desired mapping. */ + u64 size; +}; + +/** + * pvr_vm_bind_op_exec() - Execute a single bind op. + * @bind_op: Bind op context. + * + * Returns: + * * 0 on success, + * * Any error code returned by drm_gpuva_sm_map(), drm_gpuva_sm_unmap(), or + * a callback function. + */ +static int pvr_vm_bind_op_exec(struct pvr_vm_bind_op *bind_op) +{ + switch (bind_op->type) { + case PVR_VM_BIND_TYPE_MAP: + return drm_gpuvm_sm_map(&bind_op->vm_ctx->gpuvm_mgr, + bind_op, bind_op->device_addr, + bind_op->size, + gem_from_pvr_gem(bind_op->pvr_obj), + bind_op->offset); + + case PVR_VM_BIND_TYPE_UNMAP: + return drm_gpuvm_sm_unmap(&bind_op->vm_ctx->gpuvm_mgr, + bind_op, bind_op->device_addr, + bind_op->size); + } + + /* + * This shouldn't happen unless something went wrong + * in drm_sched. + */ + WARN_ON(1); + return -EINVAL; +} + +static void pvr_vm_bind_op_fini(struct pvr_vm_bind_op *bind_op) +{ + drm_gpuvm_bo_put(bind_op->gpuvm_bo); + + kfree(bind_op->new_va); + kfree(bind_op->prev_va); + kfree(bind_op->next_va); + + if (bind_op->pvr_obj) + pvr_gem_object_put(bind_op->pvr_obj); + + if (bind_op->mmu_op_ctx) + pvr_mmu_op_context_destroy(bind_op->mmu_op_ctx); +} + +static int +pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, + struct pvr_vm_context *vm_ctx, + struct pvr_gem_object *pvr_obj, u64 offset, + u64 device_addr, u64 size) +{ + const bool is_user = vm_ctx == vm_ctx->pvr_dev->kernel_vm_ctx; + const u64 pvr_obj_size = pvr_gem_object_size(pvr_obj); + struct sg_table *sgt; + u64 offset_plus_size; + int err; + + if (check_add_overflow(offset, size, &offset_plus_size)) + return -EINVAL; + + if (is_user && + !pvr_find_heap_containing(vm_ctx->pvr_dev, device_addr, size)) { + return -EINVAL; + } + + if (!pvr_device_addr_and_size_are_valid(device_addr, size) || + offset & ~PAGE_MASK || size & ~PAGE_MASK || + offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) + return -EINVAL; + + bind_op->type = PVR_VM_BIND_TYPE_MAP; + + bind_op->gpuvm_bo = drm_gpuvm_bo_create(&vm_ctx->gpuvm_mgr, + gem_from_pvr_gem(pvr_obj)); + if (!bind_op->gpuvm_bo) + return -ENOMEM; + + bind_op->new_va = kzalloc(sizeof(*bind_op->new_va), GFP_KERNEL); + bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL); + bind_op->next_va = kzalloc(sizeof(*bind_op->next_va), GFP_KERNEL); + if (!bind_op->new_va || !bind_op->prev_va || !bind_op->next_va) { + err = -ENOMEM; + goto err_bind_op_fini; + } + + /* Pin pages so they're ready for use. */ + sgt = pvr_gem_object_get_pages_sgt(pvr_obj); + err = PTR_ERR_OR_ZERO(sgt); + if (err) + goto err_bind_op_fini; + + bind_op->mmu_op_ctx = + pvr_mmu_op_context_create(vm_ctx->mmu_ctx, sgt, offset, size); + err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx); + if (err) { + bind_op->mmu_op_ctx = NULL; + goto err_bind_op_fini; + } + + bind_op->pvr_obj = pvr_obj; + bind_op->vm_ctx = vm_ctx; + bind_op->device_addr = device_addr; + bind_op->size = size; + bind_op->offset = offset; + + return 0; + +err_bind_op_fini: + pvr_vm_bind_op_fini(bind_op); + + return err; +} + +static int +pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op, + struct pvr_vm_context *vm_ctx, u64 device_addr, + u64 size) +{ + int err; + + if (!pvr_device_addr_and_size_are_valid(device_addr, size)) + return -EINVAL; + + bind_op->type = PVR_VM_BIND_TYPE_UNMAP; + + bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL); + bind_op->next_va = kzalloc(sizeof(*bind_op->next_va), GFP_KERNEL); + if (!bind_op->prev_va || !bind_op->next_va) { + err = -ENOMEM; + goto err_bind_op_fini; + } + + bind_op->mmu_op_ctx = + pvr_mmu_op_context_create(vm_ctx->mmu_ctx, NULL, 0, 0); + err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx); + if (err) { + bind_op->mmu_op_ctx = NULL; + goto err_bind_op_fini; + } + + bind_op->vm_ctx = vm_ctx; + bind_op->device_addr = device_addr; + bind_op->size = size; + + return 0; + +err_bind_op_fini: + pvr_vm_bind_op_fini(bind_op); + + return err; +} + +static int +pvr_vm_bind_op_lock_resvs(struct drm_exec *exec, struct pvr_vm_bind_op *bind_op) +{ + drm_exec_until_all_locked(exec) { + struct drm_gem_object *r_obj = &bind_op->vm_ctx->dummy_gem; + struct drm_gpuvm *gpuvm = &bind_op->vm_ctx->gpuvm_mgr; + struct pvr_gem_object *pvr_obj = bind_op->pvr_obj; + struct drm_gpuvm_bo *gpuvm_bo; + + /* Acquire lock on the vm_context's reserve object. */ + int err = drm_exec_lock_obj(exec, r_obj); + + drm_exec_retry_on_contention(exec); + if (err) + return err; + + /* Acquire lock on all BOs in the context. */ + list_for_each_entry(gpuvm_bo, &gpuvm->extobj.list, + list.entry.extobj) { + err = drm_exec_lock_obj(exec, gpuvm_bo->obj); + + drm_exec_retry_on_contention(exec); + if (err) + return err; + } + + /* Unmap operations don't have an object to lock. */ + if (!pvr_obj) + break; + + /* Acquire lock on the GEM being mapped. */ + err = drm_exec_lock_obj(exec, + gem_from_pvr_gem(bind_op->pvr_obj)); + + drm_exec_retry_on_contention(exec); + if (err) + return err; + } + + return 0; +} + +/** + * pvr_vm_gpuva_map() - Insert a mapping into a memory context. + * @op: gpuva op containing the remap details. + * @op_ctx: Operation context. + * + * Context: Called by drm_gpuvm_sm_map following a successful mapping while + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_map(). + */ +static int +pvr_vm_gpuva_map(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_gem_object *pvr_gem = gem_to_pvr_gem(op->map.gem.obj); + struct pvr_vm_bind_op *ctx = op_ctx; + int err; + + if ((op->map.gem.offset | op->map.va.range) & ~PVR_DEVICE_PAGE_MASK) + return -EINVAL; + + err = pvr_mmu_map(ctx->mmu_op_ctx, op->map.va.range, pvr_gem->flags, + op->map.va.addr); + if (err) + return err; + + drm_gpuva_map(&ctx->vm_ctx->gpuvm_mgr, &ctx->new_va->base, &op->map); + drm_gpuva_link(&ctx->new_va->base, ctx->gpuvm_bo); + ctx->new_va = NULL; + + return 0; +} + +/** + * pvr_vm_gpuva_unmap() - Remove a mapping from a memory context. + * @op: gpuva op containing the unmap details. + * @op_ctx: Operation context. + * + * Context: Called by drm_gpuvm_sm_unmap following a successful unmapping while + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_unmap(). + */ +static int +pvr_vm_gpuva_unmap(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_vm_bind_op *ctx = op_ctx; + + int err = pvr_mmu_unmap(ctx->mmu_op_ctx, op->unmap.va->va.addr, + op->unmap.va->va.range); + + if (err) + return err; + + drm_gpuva_unmap(&op->unmap); + drm_gpuva_unlink(op->unmap.va); + + return 0; +} + +/** + * pvr_vm_gpuva_remap() - Remap a mapping within a memory context. + * @op: gpuva op containing the remap details. + * @op_ctx: Operation context. + * + * Context: Called by either drm_gpuvm_sm_map or drm_gpuvm_sm_unmap when a + * mapping or unmapping operation causes a region to be split. The + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_vm_gpuva_unmap() or pvr_vm_gpuva_unmap(). + */ +static int +pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_vm_bind_op *ctx = op_ctx; + u64 va_start = 0, va_range = 0; + int err; + + drm_gpuva_op_remap_to_unmap_range(&op->remap, &va_start, &va_range); + err = pvr_mmu_unmap(ctx->mmu_op_ctx, va_start, va_range); + if (err) + return err; + + /* No actual remap required: the page table tree depth is fixed to 3, + * and we use 4k page table entries only for now. + */ + drm_gpuva_remap(&ctx->prev_va->base, &ctx->next_va->base, &op->remap); + + if (op->remap.prev) { + pvr_gem_object_get(gem_to_pvr_gem(ctx->prev_va->base.gem.obj)); + drm_gpuva_link(&ctx->prev_va->base, ctx->gpuvm_bo); + ctx->prev_va = NULL; + } + + if (op->remap.next) { + pvr_gem_object_get(gem_to_pvr_gem(ctx->next_va->base.gem.obj)); + drm_gpuva_link(&ctx->next_va->base, ctx->gpuvm_bo); + ctx->next_va = NULL; + } + + drm_gpuva_unlink(op->remap.unmap->va); + + return 0; +} + +/* + * Public API + * + * For an overview of these functions, see *DOC: Public API* in "pvr_vm.h". + */ + +/** + * pvr_device_addr_is_valid() - Tests whether a device-virtual address + * is valid. + * @device_addr: Virtual device address to test. + * + * Return: + * * %true if @device_addr is within the valid range for a device page + * table and is aligned to the device page size, or + * * %false otherwise. + */ +bool +pvr_device_addr_is_valid(u64 device_addr) +{ + return (device_addr & ~PVR_PAGE_TABLE_ADDR_MASK) == 0 && + (device_addr & ~PVR_DEVICE_PAGE_MASK) == 0; +} + +/** + * pvr_device_addr_and_size_are_valid() - Tests whether a device-virtual + * address and associated size are both valid. + * @device_addr: Virtual device address to test. + * @size: Size of the range based at @device_addr to test. + * + * Calling pvr_device_addr_is_valid() twice (once on @size, and again on + * @device_addr + @size) to verify a device-virtual address range initially + * seems intuitive, but it produces a false-negative when the address range + * is right at the end of device-virtual address space. + * + * This function catches that corner case, as well as checking that + * @size is non-zero. + * + * Return: + * * %true if @device_addr is device page aligned; @size is device page + * aligned; the range specified by @device_addr and @size is within the + * bounds of the device-virtual address space, and @size is non-zero, or + * * %false otherwise. + */ +bool +pvr_device_addr_and_size_are_valid(u64 device_addr, u64 size) +{ + return pvr_device_addr_is_valid(device_addr) && + size != 0 && (size & ~PVR_DEVICE_PAGE_MASK) == 0 && + (device_addr + size <= PVR_PAGE_TABLE_ADDR_SPACE_SIZE); +} + +void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) +{ + +} + +static const struct drm_gpuvm_ops pvr_vm_gpuva_ops = { + .vm_free = pvr_gpuvm_free, + .sm_step_map = pvr_vm_gpuva_map, + .sm_step_remap = pvr_vm_gpuva_remap, + .sm_step_unmap = pvr_vm_gpuva_unmap, +}; + +/** + * pvr_vm_create_context() - Create a new VM context. + * @pvr_dev: Target PowerVR device. + * @is_userspace_context: %true if this context is for userspace. This will + * create a firmware memory context for the VM context + * and disable warnings when tearing down mappings. + * + * Return: + * * A handle to the newly-minted VM context on success, + * * -%EINVAL if the feature "virtual address space bits" on @pvr_dev is + * missing or has an unsupported value, + * * -%ENOMEM if allocation of the structure behind the opaque handle fails, + * or + * * Any error encountered while setting up internal structures. + */ +struct pvr_vm_context * +pvr_vm_create_context(struct pvr_device *pvr_dev, bool is_userspace_context) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + struct pvr_vm_context *vm_ctx; + u16 device_addr_bits; + + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, virtual_address_space_bits, + &device_addr_bits); + if (err) { + drm_err(drm_dev, + "Failed to get device virtual address space bits\n"); + return ERR_PTR(err); + } + + if (device_addr_bits != PVR_PAGE_TABLE_ADDR_BITS) { + drm_err(drm_dev, + "Device has unsupported virtual address space size\n"); + return ERR_PTR(-EINVAL); + } + + vm_ctx = kzalloc(sizeof(*vm_ctx), GFP_KERNEL); + if (!vm_ctx) + return ERR_PTR(-ENOMEM); + + drm_gem_private_object_init(&pvr_dev->base, &vm_ctx->dummy_gem, 0); + + vm_ctx->pvr_dev = pvr_dev; + kref_init(&vm_ctx->ref_count); + mutex_init(&vm_ctx->lock); + + drm_gpuvm_init(&vm_ctx->gpuvm_mgr, + is_userspace_context ? "PowerVR-user-VM" : "PowerVR-FW-VM", + 0, &pvr_dev->base, &vm_ctx->dummy_gem, + 0, 1ULL << device_addr_bits, 0, 0, &pvr_vm_gpuva_ops); + + vm_ctx->mmu_ctx = pvr_mmu_context_create(pvr_dev); + err = PTR_ERR_OR_ZERO(&vm_ctx->mmu_ctx); + if (err) { + vm_ctx->mmu_ctx = NULL; + goto err_put_ctx; + } + + if (is_userspace_context) { + /* TODO: Create FW mem context */ + err = -ENODEV; + goto err_put_ctx; + } + + return vm_ctx; + +err_put_ctx: + pvr_vm_context_put(vm_ctx); + + return ERR_PTR(err); +} + +/** + * pvr_vm_context_release() - Teardown a VM context. + * @ref_count: Pointer to reference counter of the VM context. + * + * This function ensures that no mappings are left dangling by unmapping them + * all in order of ascending device-virtual address. + */ +static void +pvr_vm_context_release(struct kref *ref_count) +{ + struct pvr_vm_context *vm_ctx = + container_of(ref_count, struct pvr_vm_context, ref_count); + + /* TODO: Destroy FW mem context */ + WARN_ON(vm_ctx->fw_mem_ctx_obj); + + WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, + vm_ctx->gpuvm_mgr.mm_range)); + + drm_gpuvm_put(&vm_ctx->gpuvm_mgr); + pvr_mmu_context_destroy(vm_ctx->mmu_ctx); + drm_gem_private_object_fini(&vm_ctx->dummy_gem); + mutex_destroy(&vm_ctx->lock); + + kfree(vm_ctx); +} + +/** + * pvr_vm_context_lookup() - Look up VM context from handle + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on VM context object. Call pvr_vm_context_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a VM context) + */ +struct pvr_vm_context * +pvr_vm_context_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_vm_context *vm_ctx; + + xa_lock(&pvr_file->vm_ctx_handles); + vm_ctx = xa_load(&pvr_file->vm_ctx_handles, handle); + if (vm_ctx) + kref_get(&vm_ctx->ref_count); + + xa_unlock(&pvr_file->vm_ctx_handles); + + return vm_ctx; +} + +/** + * pvr_vm_context_put() - Release a reference on a VM context + * @vm_ctx: Target VM context. + * + * Returns: + * * %true if the VM context was destroyed, or + * * %false if there are any references still remaining. + */ +bool +pvr_vm_context_put(struct pvr_vm_context *vm_ctx) +{ + if (vm_ctx) + return kref_put(&vm_ctx->ref_count, pvr_vm_context_release); + + return true; +} + +/** + * pvr_destroy_vm_contexts_for_file: Destroy any VM contexts associated with the + * given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all vm_contexts associated with @pvr_file from the device VM context + * list and drops initial references. vm_contexts will then be destroyed once + * all outstanding references are dropped. + */ +void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file) +{ + struct pvr_vm_context *vm_ctx; + unsigned long handle; + + xa_for_each(&pvr_file->vm_ctx_handles, handle, vm_ctx) { + /* vm_ctx is not used here because that would create a race with xa_erase */ + pvr_vm_context_put(xa_erase(&pvr_file->vm_ctx_handles, handle)); + } +} + +/** + * pvr_vm_map() - Map a section of physical memory into a section of + * device-virtual memory. + * @vm_ctx: Target VM context. + * @pvr_obj: Target PowerVR memory object. + * @pvr_obj_offset: Offset into @pvr_obj to map from. + * @device_addr: Virtual device address at the start of the requested mapping. + * @size: Size of the requested mapping. + * + * No handle is returned to represent the mapping. Instead, callers should + * remember @device_addr and use that as a handle. + * + * Return: + * * 0 on success, + * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual + * address; the region specified by @pvr_obj_offset and @size does not fall + * entirely within @pvr_obj, or any part of the specified region of @pvr_obj + * is not device-virtual page-aligned, + * * Any error encountered while performing internal operations required to + * destroy the mapping (returned from pvr_vm_gpuva_map or + * pvr_vm_gpuva_remap). + */ +int +pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, + u64 pvr_obj_offset, u64 device_addr, u64 size) +{ + struct pvr_vm_bind_op bind_op = {0}; + struct drm_exec exec; + + int err = pvr_vm_bind_op_map_init(&bind_op, vm_ctx, pvr_obj, + pvr_obj_offset, device_addr, + size); + + if (err) + return err; + + drm_exec_init(&exec, + DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); + + pvr_gem_object_get(pvr_obj); + + err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op); + if (err) + goto err_cleanup; + + err = pvr_vm_bind_op_exec(&bind_op); + + drm_exec_fini(&exec); + +err_cleanup: + pvr_vm_bind_op_fini(&bind_op); + + return err; +} + +/** + * pvr_vm_unmap() - Unmap an already mapped section of device-virtual memory. + * @vm_ctx: Target VM context. + * @device_addr: Virtual device address at the start of the target mapping. + * @size: Size of the target mapping. + * + * Return: + * * 0 on success, + * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual + * address, + * * Any error encountered while performing internal operations required to + * destroy the mapping (returned from pvr_vm_gpuva_unmap or + * pvr_vm_gpuva_remap). + */ +int +pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size) +{ + struct pvr_vm_bind_op bind_op = {0}; + struct drm_exec exec; + + int err = pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, device_addr, + size); + + if (err) + return err; + + drm_exec_init(&exec, + DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); + + err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op); + if (err) + goto err_cleanup; + + err = pvr_vm_bind_op_exec(&bind_op); + + drm_exec_fini(&exec); + +err_cleanup: + pvr_vm_bind_op_fini(&bind_op); + + return err; +} + +/* Static data areas are determined by firmware. */ +static const struct drm_pvr_static_data_area static_data_areas[] = { + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_FENCE, + .location_heap_id = DRM_PVR_HEAP_GENERAL, + .offset = 0, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_YUV_CSC, + .location_heap_id = DRM_PVR_HEAP_GENERAL, + .offset = 128, + .size = 1024, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_VDM_SYNC, + .location_heap_id = DRM_PVR_HEAP_PDS_CODE_DATA, + .offset = 0, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_EOT, + .location_heap_id = DRM_PVR_HEAP_PDS_CODE_DATA, + .offset = 128, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_VDM_SYNC, + .location_heap_id = DRM_PVR_HEAP_USC_CODE, + .offset = 0, + .size = 128, + }, +}; + +#define GET_RESERVED_SIZE(last_offset, last_size) round_up((last_offset) + (last_size), PAGE_SIZE) + +/* + * The values given to GET_RESERVED_SIZE() are taken from the last entry in the corresponding + * static data area for each heap. + */ +static const struct drm_pvr_heap pvr_heaps[] = { + [DRM_PVR_HEAP_GENERAL] = { + .base = ROGUE_GENERAL_HEAP_BASE, + .size = ROGUE_GENERAL_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_PDS_CODE_DATA] = { + .base = ROGUE_PDSCODEDATA_HEAP_BASE, + .size = ROGUE_PDSCODEDATA_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_USC_CODE] = { + .base = ROGUE_USCCODE_HEAP_BASE, + .size = ROGUE_USCCODE_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_RGNHDR] = { + .base = ROGUE_RGNHDR_HEAP_BASE, + .size = ROGUE_RGNHDR_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_VIS_TEST] = { + .base = ROGUE_VISTEST_HEAP_BASE, + .size = ROGUE_VISTEST_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_TRANSFER_FRAG] = { + .base = ROGUE_TRANSFER_FRAG_HEAP_BASE, + .size = ROGUE_TRANSFER_FRAG_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, +}; + +int +pvr_static_data_areas_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_static_data_areas query = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_static_data_areas); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + if (err < 0) + return err; + + if (!query.static_data_areas.array) { + query.static_data_areas.count = ARRAY_SIZE(static_data_areas); + query.static_data_areas.stride = sizeof(struct drm_pvr_static_data_area); + goto copy_out; + } + + if (query.static_data_areas.count > ARRAY_SIZE(static_data_areas)) + query.static_data_areas.count = ARRAY_SIZE(static_data_areas); + + err = PVR_UOBJ_SET_ARRAY(&query.static_data_areas, static_data_areas); + if (err < 0) + return err; + +copy_out: + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +int +pvr_heap_info_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_heap_info query = {0}; + u64 dest; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_heap_info); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + if (err < 0) + return err; + + if (!query.heaps.array) { + query.heaps.count = ARRAY_SIZE(pvr_heaps); + query.heaps.stride = sizeof(struct drm_pvr_heap); + goto copy_out; + } + + if (query.heaps.count > ARRAY_SIZE(pvr_heaps)) + query.heaps.count = ARRAY_SIZE(pvr_heaps); + + /* Region header heap is only present if BRN63142 is present. */ + dest = query.heaps.array; + for (size_t i = 0; i < query.heaps.count; i++) { + struct drm_pvr_heap heap = pvr_heaps[i]; + + if (i == DRM_PVR_HEAP_RGNHDR && !PVR_HAS_QUIRK(pvr_dev, 63142)) + heap.size = 0; + + err = PVR_UOBJ_SET(dest, query.heaps.stride, heap); + if (err < 0) + return err; + + dest += query.heaps.stride; + } + +copy_out: + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +/** + * pvr_heap_contains_range() - Determine if a given heap contains the specified + * device-virtual address range. + * @pvr_heap: Target heap. + * @start: Inclusive start of the target range. + * @end: Inclusive end of the target range. + * + * It is an error to call this function with values of @start and @end that do + * not satisfy the condition @start <= @end. + */ +static __always_inline bool +pvr_heap_contains_range(const struct drm_pvr_heap *pvr_heap, u64 start, u64 end) +{ + return pvr_heap->base <= start && end < pvr_heap->base + pvr_heap->size; +} + +/** + * pvr_find_heap_containing() - Find a heap which contains the specified + * device-virtual address range. + * @pvr_dev: Target PowerVR device. + * @start: Start of the target range. + * @size: Size of the target range. + * + * Return: + * * A pointer to a constant instance of struct drm_pvr_heap representing the + * heap containing the entire range specified by @start and @size on + * success, or + * * %NULL if no such heap exists. + */ +const struct drm_pvr_heap * +pvr_find_heap_containing(struct pvr_device *pvr_dev, u64 start, u64 size) +{ + u64 end; + + if (check_add_overflow(start, size - 1, &end)) + return NULL; + + /* + * There are no guarantees about the order of address ranges in + * &pvr_heaps, so iterate over the entire array for a heap whose + * range completely encompasses the given range. + */ + for (u32 heap_id = 0; heap_id < ARRAY_SIZE(pvr_heaps); heap_id++) { + /* Filter heaps that present only with an associated quirk */ + if (heap_id == DRM_PVR_HEAP_RGNHDR && + !PVR_HAS_QUIRK(pvr_dev, 63142)) { + continue; + } + + if (pvr_heap_contains_range(&pvr_heaps[heap_id], start, end)) + return &pvr_heaps[heap_id]; + } + + return NULL; +} + +/** + * pvr_vm_find_gem_object() - Look up a buffer object from a given + * device-virtual address. + * @vm_ctx: [IN] Target VM context. + * @device_addr: [IN] Virtual device address at the start of the required + * object. + * @mapped_offset_out: [OUT] Pointer to location to write offset of the start + * of the mapped region within the buffer object. May be + * %NULL if this information is not required. + * @mapped_size_out: [OUT] Pointer to location to write size of the mapped + * region. May be %NULL if this information is not required. + * + * If successful, a reference will be taken on the buffer object. The caller + * must drop the reference with pvr_gem_object_put(). + * + * Return: + * * The PowerVR buffer object mapped at @device_addr if one exists, or + * * %NULL otherwise. + */ +struct pvr_gem_object * +pvr_vm_find_gem_object(struct pvr_vm_context *vm_ctx, u64 device_addr, + u64 *mapped_offset_out, u64 *mapped_size_out) +{ + struct pvr_gem_object *pvr_obj; + struct drm_gpuva *va; + + mutex_lock(&vm_ctx->lock); + + va = drm_gpuva_find_first(&vm_ctx->gpuvm_mgr, device_addr, 1); + if (!va) + goto err_unlock; + + pvr_obj = gem_to_pvr_gem(va->gem.obj); + pvr_gem_object_get(pvr_obj); + + if (mapped_offset_out) + *mapped_offset_out = va->gem.offset; + if (mapped_size_out) + *mapped_size_out = va->va.range; + + mutex_unlock(&vm_ctx->lock); + + return pvr_obj; + +err_unlock: + mutex_unlock(&vm_ctx->lock); + + return NULL; +} + +/** + * pvr_vm_get_fw_mem_context: Get object representing firmware memory context + * @vm_ctx: Target VM context. + * + * Returns: + * * FW object representing firmware memory context, or + * * %NULL if this VM context does not have a firmware memory context. + */ +struct pvr_fw_object * +pvr_vm_get_fw_mem_context(struct pvr_vm_context *vm_ctx) +{ + return vm_ctx->fw_mem_ctx_obj; +} diff --git a/drivers/gpu/drm/imagination/pvr_vm.h b/drivers/gpu/drm/imagination/pvr_vm.h new file mode 100644 index 000000000000..cf8b97553dc8 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_VM_H +#define PVR_VM_H + +#include "pvr_rogue_mmu_defs.h" + +#include + +#include + +/* Forward declaration from "pvr_device.h" */ +struct pvr_device; +struct pvr_file; + +/* Forward declaration from "pvr_gem.h" */ +struct pvr_gem_object; + +/* Forward declaration from "pvr_vm.c" */ +struct pvr_vm_context; + +/* Forward declaration from */ +struct drm_pvr_ioctl_get_heap_info_args; + +/* Forward declaration from */ +struct drm_exec; + +/* Functions defined in pvr_vm.c */ + +bool pvr_device_addr_is_valid(u64 device_addr); +bool pvr_device_addr_and_size_are_valid(u64 device_addr, u64 size); + +struct pvr_vm_context *pvr_vm_create_context(struct pvr_device *pvr_dev, + bool is_userspace_context); + +int pvr_vm_map(struct pvr_vm_context *vm_ctx, + struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset, + u64 device_addr, u64 size); +int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size); + +dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx); +struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx); + +int pvr_static_data_areas_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args); +int pvr_heap_info_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args); +const struct drm_pvr_heap *pvr_find_heap_containing(struct pvr_device *pvr_dev, + u64 addr, u64 size); + +struct pvr_gem_object *pvr_vm_find_gem_object(struct pvr_vm_context *vm_ctx, + u64 device_addr, + u64 *mapped_offset_out, + u64 *mapped_size_out); + +struct pvr_fw_object * +pvr_vm_get_fw_mem_context(struct pvr_vm_context *vm_ctx); + +struct pvr_vm_context *pvr_vm_context_lookup(struct pvr_file *pvr_file, u32 handle); +struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx); +bool pvr_vm_context_put(struct pvr_vm_context *vm_ctx); +void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file); + +#endif /* PVR_VM_H */ From 727538a4bbff07736ecfd704efd7e21718fca3e4 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:33 +0000 Subject: [PATCH 1184/7721] drm/imagination: Implement power management Add power management to the driver, using runtime pm. The power off sequence depends on firmware commands which are not implemented in this patch. Changes since v8: - Corrected license identifiers Changes since v5: - Use RUNTIME_PM_OPS() to declare PM callbacks - Add Kconfig dependency on CONFIG_PM Changes since v4: - Suspend runtime PM before unplugging device on rmmod Changes since v3: - Don't power device when calling pvr_device_gpu_fini() - Documentation for pvr_dev->lost has been improved - pvr_power_init() renamed to pvr_watchdog_init() - Use drm_dev_{enter,exit} Changes since v2: - Use runtime PM - Implement watchdog Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/e09af4ef1ff514e1d6d7f97c7c5032c643c56f9c.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Kconfig | 1 + drivers/gpu/drm/imagination/Makefile | 1 + drivers/gpu/drm/imagination/pvr_device.c | 25 ++- drivers/gpu/drm/imagination/pvr_device.h | 22 ++ drivers/gpu/drm/imagination/pvr_drv.c | 20 +- drivers/gpu/drm/imagination/pvr_power.c | 271 +++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_power.h | 39 ++++ 7 files changed, 375 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_power.c create mode 100644 drivers/gpu/drm/imagination/pvr_power.h diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imagination/Kconfig index 6f82edf89144..0abd1b9bf3be 100644 --- a/drivers/gpu/drm/imagination/Kconfig +++ b/drivers/gpu/drm/imagination/Kconfig @@ -5,6 +5,7 @@ config DRM_POWERVR tristate "Imagination Technologies PowerVR (Series 6 and later) & IMG Graphics" depends on ARM64 depends on DRM + depends on PM select DRM_GEM_SHMEM_HELPER select DRM_SCHED select DRM_GPUVM diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 678c3dbb4326..d9e00a0db6b2 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -10,6 +10,7 @@ powervr-y := \ pvr_fw.o \ pvr_gem.o \ pvr_mmu.o \ + pvr_power.o \ pvr_vm.o obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 201ae780494f..e16282325178 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -5,6 +5,7 @@ #include "pvr_device_info.h" #include "pvr_fw.h" +#include "pvr_power.h" #include "pvr_rogue_cr_defs.h" #include "pvr_vm.h" @@ -361,6 +362,8 @@ pvr_device_gpu_fini(struct pvr_device *pvr_dev) int pvr_device_init(struct pvr_device *pvr_dev) { + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct device *dev = drm_dev->dev; int err; /* Enable and initialize clocks required for the device to operate. */ @@ -368,13 +371,29 @@ pvr_device_init(struct pvr_device *pvr_dev) if (err) return err; - /* Map the control registers into memory. */ - err = pvr_device_reg_init(pvr_dev); + /* Explicitly power the GPU so we can access control registers before the FW is booted. */ + err = pm_runtime_resume_and_get(dev); if (err) return err; + /* Map the control registers into memory. */ + err = pvr_device_reg_init(pvr_dev); + if (err) + goto err_pm_runtime_put; + /* Perform GPU-specific initialization steps. */ - return pvr_device_gpu_init(pvr_dev); + err = pvr_device_gpu_init(pvr_dev); + if (err) + goto err_pm_runtime_put; + + pm_runtime_put(dev); + + return 0; + +err_pm_runtime_put: + pm_runtime_put_sync_suspend(dev); + + return err; } /** diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index bfc853ffd58f..771ba879f02d 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -141,6 +141,28 @@ struct pvr_device { * before submitting the next job. */ atomic_t mmu_flush_cache_flags; + + struct { + /** @work: Work item for watchdog callback. */ + struct delayed_work work; + + /** @old_kccb_cmds_executed: KCCB command execution count at last watchdog poll. */ + u32 old_kccb_cmds_executed; + + /** @kccb_stall_count: Number of watchdog polls KCCB has been stalled for. */ + u32 kccb_stall_count; + } watchdog; + + /** + * @lost: %true if the device has been lost. + * + * This variable is set if the device has become irretrievably unavailable, e.g. if the + * firmware processor has stopped responding and can not be revived via a hard reset. + */ + bool lost; + + /** @sched_wq: Workqueue for schedulers. */ + struct workqueue_struct *sched_wq; }; /** diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 6d3bc886e1c3..12e136217c45 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -5,6 +5,7 @@ #include "pvr_drv.h" #include "pvr_gem.h" #include "pvr_mmu.h" +#include "pvr_power.h" #include "pvr_rogue_defs.h" #include "pvr_rogue_fwif_client.h" #include "pvr_rogue_fwif_shared.h" @@ -1265,9 +1266,16 @@ pvr_probe(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, drm_dev); + devm_pm_runtime_enable(&plat_dev->dev); + pm_runtime_mark_last_busy(&plat_dev->dev); + + pm_runtime_set_autosuspend_delay(&plat_dev->dev, 50); + pm_runtime_use_autosuspend(&plat_dev->dev); + pvr_watchdog_init(pvr_dev); + err = pvr_device_init(pvr_dev); if (err) - return err; + goto err_watchdog_fini; err = drm_dev_register(drm_dev, 0); if (err) @@ -1278,6 +1286,9 @@ pvr_probe(struct platform_device *plat_dev) err_device_fini: pvr_device_fini(pvr_dev); +err_watchdog_fini: + pvr_watchdog_fini(pvr_dev); + return err; } @@ -1287,8 +1298,10 @@ pvr_remove(struct platform_device *plat_dev) struct drm_device *drm_dev = platform_get_drvdata(plat_dev); struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + pm_runtime_suspend(drm_dev->dev); pvr_device_fini(pvr_dev); drm_dev_unplug(drm_dev); + pvr_watchdog_fini(pvr_dev); return 0; } @@ -1299,11 +1312,16 @@ static const struct of_device_id dt_match[] = { }; MODULE_DEVICE_TABLE(of, dt_match); +static const struct dev_pm_ops pvr_pm_ops = { + RUNTIME_PM_OPS(pvr_power_device_suspend, pvr_power_device_resume, pvr_power_device_idle) +}; + static struct platform_driver pvr_driver = { .probe = pvr_probe, .remove = pvr_remove, .driver = { .name = PVR_DRIVER_NAME, + .pm = &pvr_pm_ops, .of_match_table = dt_match, }, }; diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c new file mode 100644 index 000000000000..88f14a4d31ab --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define POWER_SYNC_TIMEOUT_US (1000000) /* 1s */ + +#define WATCHDOG_TIME_MS (500) + +static int +pvr_power_send_command(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *pow_cmd) +{ + /* TODO: implement */ + return -ENODEV; +} + +static int +pvr_power_request_idle(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_kccb_cmd pow_cmd; + + /* Send FORCED_IDLE request to FW. */ + pow_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_POW; + pow_cmd.cmd_data.pow_data.pow_type = ROGUE_FWIF_POW_FORCED_IDLE_REQ; + pow_cmd.cmd_data.pow_data.power_req_data.pow_request_type = ROGUE_FWIF_POWER_FORCE_IDLE; + + return pvr_power_send_command(pvr_dev, &pow_cmd); +} + +static int +pvr_power_request_pwr_off(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_kccb_cmd pow_cmd; + + /* Send POW_OFF request to firmware. */ + pow_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_POW; + pow_cmd.cmd_data.pow_data.pow_type = ROGUE_FWIF_POW_OFF_REQ; + pow_cmd.cmd_data.pow_data.power_req_data.forced = true; + + return pvr_power_send_command(pvr_dev, &pow_cmd); +} + +static int +pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset) +{ + if (!hard_reset) { + int err; + + cancel_delayed_work_sync(&pvr_dev->watchdog.work); + + err = pvr_power_request_idle(pvr_dev); + if (err) + return err; + + err = pvr_power_request_pwr_off(pvr_dev); + if (err) + return err; + } + + /* TODO: stop firmware */ + return -ENODEV; +} + +static int +pvr_power_fw_enable(struct pvr_device *pvr_dev) +{ + int err; + + /* TODO: start firmware */ + err = -ENODEV; + if (err) + return err; + + queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, + msecs_to_jiffies(WATCHDOG_TIME_MS)); + + return 0; +} + +bool +pvr_power_is_idle(struct pvr_device *pvr_dev) +{ + /* TODO: implement */ + return true; +} + +static bool +pvr_watchdog_kccb_stalled(struct pvr_device *pvr_dev) +{ + /* TODO: implement */ + return false; +} + +static void +pvr_watchdog_worker(struct work_struct *work) +{ + struct pvr_device *pvr_dev = container_of(work, struct pvr_device, + watchdog.work.work); + bool stalled; + + if (pvr_dev->lost) + return; + + if (pm_runtime_get_if_in_use(from_pvr_device(pvr_dev)->dev) <= 0) + goto out_requeue; + + stalled = pvr_watchdog_kccb_stalled(pvr_dev); + + if (stalled) { + drm_err(from_pvr_device(pvr_dev), "FW stalled, trying hard reset"); + + pvr_power_reset(pvr_dev, true); + /* Device may be lost at this point. */ + } + + pm_runtime_put(from_pvr_device(pvr_dev)->dev); + +out_requeue: + if (!pvr_dev->lost) { + queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, + msecs_to_jiffies(WATCHDOG_TIME_MS)); + } +} + +/** + * pvr_watchdog_init() - Initialise watchdog for device + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * -%ENOMEM on out of memory. + */ +int +pvr_watchdog_init(struct pvr_device *pvr_dev) +{ + INIT_DELAYED_WORK(&pvr_dev->watchdog.work, pvr_watchdog_worker); + + return 0; +} + +int +pvr_power_device_suspend(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + int idx; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + clk_disable_unprepare(pvr_dev->mem_clk); + clk_disable_unprepare(pvr_dev->sys_clk); + clk_disable_unprepare(pvr_dev->core_clk); + + drm_dev_exit(idx); + + return 0; +} + +int +pvr_power_device_resume(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + err = clk_prepare_enable(pvr_dev->core_clk); + if (err) + goto err_drm_dev_exit; + + err = clk_prepare_enable(pvr_dev->sys_clk); + if (err) + goto err_core_clk_disable; + + err = clk_prepare_enable(pvr_dev->mem_clk); + if (err) + goto err_sys_clk_disable; + + drm_dev_exit(idx); + + return 0; + +err_sys_clk_disable: + clk_disable_unprepare(pvr_dev->sys_clk); + +err_core_clk_disable: + clk_disable_unprepare(pvr_dev->core_clk); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +int +pvr_power_device_idle(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + + return pvr_power_is_idle(pvr_dev) ? 0 : -EBUSY; +} + +/** + * pvr_power_reset() - Reset the GPU + * @pvr_dev: Device pointer + * @hard_reset: %true for hard reset, %false for soft reset + * + * If @hard_reset is %false and the FW processor fails to respond during the reset process, this + * function will attempt a hard reset. + * + * If a hard reset fails then the GPU device is reported as lost. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_power_get, pvr_power_fw_disable or pvr_power_fw_enable(). + */ +int +pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) +{ + /* TODO: Implement hard reset. */ + int err; + + /* + * Take a power reference during the reset. This should prevent any interference with the + * power state during reset. + */ + WARN_ON(pvr_power_get(pvr_dev)); + + err = pvr_power_fw_disable(pvr_dev, false); + if (err) + goto err_power_put; + + err = pvr_power_fw_enable(pvr_dev); + +err_power_put: + pvr_power_put(pvr_dev); + + return err; +} + +/** + * pvr_watchdog_fini() - Shutdown watchdog for device + * @pvr_dev: Target PowerVR device. + */ +void +pvr_watchdog_fini(struct pvr_device *pvr_dev) +{ + cancel_delayed_work_sync(&pvr_dev->watchdog.work); +} diff --git a/drivers/gpu/drm/imagination/pvr_power.h b/drivers/gpu/drm/imagination/pvr_power.h new file mode 100644 index 000000000000..360980f454d7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_power.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_POWER_H +#define PVR_POWER_H + +#include "pvr_device.h" + +#include +#include + +int pvr_watchdog_init(struct pvr_device *pvr_dev); +void pvr_watchdog_fini(struct pvr_device *pvr_dev); + +bool pvr_power_is_idle(struct pvr_device *pvr_dev); + +int pvr_power_device_suspend(struct device *dev); +int pvr_power_device_resume(struct device *dev); +int pvr_power_device_idle(struct device *dev); + +int pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset); + +static __always_inline int +pvr_power_get(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + return pm_runtime_resume_and_get(drm_dev->dev); +} + +static __always_inline int +pvr_power_put(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + return pm_runtime_put(drm_dev->dev); +} + +#endif /* PVR_POWER_H */ From cc1aeedb98ad347c06ff59e991b2f94dfb4c565d Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:34 +0000 Subject: [PATCH 1185/7721] drm/imagination: Implement firmware infrastructure and META FW support The infrastructure includes parsing of the firmware image, initialising FW-side structures, handling the kernel and firmware command ringbuffers and starting & stopping the firmware processor. This patch also adds the necessary support code for the META firmware processor. Changes since v8: - Fix documentation for pvr_fwccb_process() - Corrected license identifiers Changes since v6: - Add a minimum retry count to pvr_kccb_reserve_slot_sync() Changes since v5: - Add workaround for BRN 71242 - Attempt to recover GPU on MMU flush command failure Changes since v4: - Remove use of drm_gem_shmem_get_pages() - Remove interrupt resource name Changes since v3: - Hard reset FW processor on watchdog timeout - Switch to threaded IRQ - Rework FW object creation/initialisation to aid hard reset - Added MODULE_FIRMWARE() - Use drm_dev_{enter,exit} Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/bb52a8dc84f296b37dc6668dfe8fbaf2ba551139.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 4 + drivers/gpu/drm/imagination/pvr_ccb.c | 635 ++++++++ drivers/gpu/drm/imagination/pvr_ccb.h | 71 + drivers/gpu/drm/imagination/pvr_device.c | 103 ++ drivers/gpu/drm/imagination/pvr_device.h | 60 + drivers/gpu/drm/imagination/pvr_drv.c | 1 + drivers/gpu/drm/imagination/pvr_fw.c | 1342 +++++++++++++++++ drivers/gpu/drm/imagination/pvr_fw.h | 474 ++++++ drivers/gpu/drm/imagination/pvr_fw_meta.c | 554 +++++++ drivers/gpu/drm/imagination/pvr_fw_meta.h | 14 + .../gpu/drm/imagination/pvr_fw_startstop.c | 306 ++++ .../gpu/drm/imagination/pvr_fw_startstop.h | 13 + drivers/gpu/drm/imagination/pvr_fw_trace.c | 120 ++ drivers/gpu/drm/imagination/pvr_fw_trace.h | 78 + drivers/gpu/drm/imagination/pvr_mmu.c | 70 +- drivers/gpu/drm/imagination/pvr_power.c | 166 +- drivers/gpu/drm/imagination/pvr_power.h | 2 + drivers/gpu/drm/imagination/pvr_vm.c | 26 +- 18 files changed, 4015 insertions(+), 24 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_ccb.c create mode 100644 drivers/gpu/drm/imagination/pvr_ccb.h create mode 100644 drivers/gpu/drm/imagination/pvr_fw_meta.c create mode 100644 drivers/gpu/drm/imagination/pvr_fw_meta.h create mode 100644 drivers/gpu/drm/imagination/pvr_fw_startstop.c create mode 100644 drivers/gpu/drm/imagination/pvr_fw_startstop.h create mode 100644 drivers/gpu/drm/imagination/pvr_fw_trace.c create mode 100644 drivers/gpu/drm/imagination/pvr_fw_trace.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index d9e00a0db6b2..5c1c918af7a3 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -4,10 +4,14 @@ subdir-ccflags-y := -I$(srctree)/$(src) powervr-y := \ + pvr_ccb.o \ pvr_device.o \ pvr_device_info.o \ pvr_drv.o \ pvr_fw.o \ + pvr_fw_meta.o \ + pvr_fw_startstop.o \ + pvr_fw_trace.o \ pvr_gem.o \ pvr_mmu.o \ pvr_power.o \ diff --git a/drivers/gpu/drm/imagination/pvr_ccb.c b/drivers/gpu/drm/imagination/pvr_ccb.c new file mode 100644 index 000000000000..48f06f58f3f1 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_ccb.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_ccb.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_fw.h" +#include "pvr_gem.h" +#include "pvr_power.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESERVE_SLOT_TIMEOUT (1 * HZ) /* 1s */ +#define RESERVE_SLOT_MIN_RETRIES 10 + +static void +ccb_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_ccb_ctl *ctrl = cpu_ptr; + struct pvr_ccb *pvr_ccb = priv; + + ctrl->write_offset = 0; + ctrl->read_offset = 0; + ctrl->wrap_mask = pvr_ccb->num_cmds - 1; + ctrl->cmd_size = pvr_ccb->cmd_size; +} + +/** + * pvr_ccb_init() - Initialise a CCB + * @pvr_dev: Device pointer. + * @pvr_ccb: Pointer to CCB structure to initialise. + * @num_cmds_log2: Log2 of number of commands in this CCB. + * @cmd_size: Command size for this CCB. + * + * Return: + * * Zero on success, or + * * Any error code returned by pvr_fw_object_create_and_map(). + */ +static int +pvr_ccb_init(struct pvr_device *pvr_dev, struct pvr_ccb *pvr_ccb, + u32 num_cmds_log2, size_t cmd_size) +{ + u32 num_cmds = 1 << num_cmds_log2; + u32 ccb_size = num_cmds * cmd_size; + int err; + + pvr_ccb->num_cmds = num_cmds; + pvr_ccb->cmd_size = cmd_size; + + err = drmm_mutex_init(from_pvr_device(pvr_dev), &pvr_ccb->lock); + if (err) + return err; + + /* + * Map CCB and control structure as uncached, so we don't have to flush + * CPU cache repeatedly when polling for space. + */ + pvr_ccb->ctrl = pvr_fw_object_create_and_map(pvr_dev, sizeof(*pvr_ccb->ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + ccb_ctrl_init, pvr_ccb, &pvr_ccb->ctrl_obj); + if (IS_ERR(pvr_ccb->ctrl)) + return PTR_ERR(pvr_ccb->ctrl); + + pvr_ccb->ccb = pvr_fw_object_create_and_map(pvr_dev, ccb_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_ccb->ccb_obj); + if (IS_ERR(pvr_ccb->ccb)) { + err = PTR_ERR(pvr_ccb->ccb); + goto err_free_ctrl; + } + + pvr_fw_object_get_fw_addr(pvr_ccb->ctrl_obj, &pvr_ccb->ctrl_fw_addr); + pvr_fw_object_get_fw_addr(pvr_ccb->ccb_obj, &pvr_ccb->ccb_fw_addr); + + WRITE_ONCE(pvr_ccb->ctrl->write_offset, 0); + WRITE_ONCE(pvr_ccb->ctrl->read_offset, 0); + WRITE_ONCE(pvr_ccb->ctrl->wrap_mask, num_cmds - 1); + WRITE_ONCE(pvr_ccb->ctrl->cmd_size, cmd_size); + + return 0; + +err_free_ctrl: + pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj); + + return err; +} + +/** + * pvr_ccb_fini() - Release CCB structure + * @pvr_ccb: CCB to release. + */ +void +pvr_ccb_fini(struct pvr_ccb *pvr_ccb) +{ + pvr_fw_object_unmap_and_destroy(pvr_ccb->ccb_obj); + pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj); +} + +/** + * pvr_ccb_slot_available_locked() - Test whether any slots are available in CCB + * @pvr_ccb: CCB to test. + * @write_offset: Address to store number of next available slot. May be %NULL. + * + * Caller must hold @pvr_ccb->lock. + * + * Return: + * * %true if a slot is available, or + * * %false if no slot is available. + */ +static __always_inline bool +pvr_ccb_slot_available_locked(struct pvr_ccb *pvr_ccb, u32 *write_offset) +{ + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 next_write_offset = (READ_ONCE(ctrl->write_offset) + 1) & READ_ONCE(ctrl->wrap_mask); + + lockdep_assert_held(&pvr_ccb->lock); + + if (READ_ONCE(ctrl->read_offset) != next_write_offset) { + if (write_offset) + *write_offset = next_write_offset; + return true; + } + + return false; +} + +static void +process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *cmd) +{ + switch (cmd->cmd_type) { + case ROGUE_FWIF_FWCCB_CMD_REQUEST_GPU_RESTART: + pvr_power_reset(pvr_dev, false); + break; + + default: + drm_info(from_pvr_device(pvr_dev), "Received unknown FWCCB command %x\n", + cmd->cmd_type); + break; + } +} + +/** + * pvr_fwccb_process() - Process any pending FWCCB commands + * @pvr_dev: Target PowerVR device + */ +void pvr_fwccb_process(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_fwccb_cmd *fwccb = pvr_dev->fwccb.ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->fwccb.ctrl; + u32 read_offset; + + mutex_lock(&pvr_dev->fwccb.lock); + + while ((read_offset = READ_ONCE(ctrl->read_offset)) != READ_ONCE(ctrl->write_offset)) { + struct rogue_fwif_fwccb_cmd cmd = fwccb[read_offset]; + + WRITE_ONCE(ctrl->read_offset, (read_offset + 1) & READ_ONCE(ctrl->wrap_mask)); + + /* Drop FWCCB lock while we process command. */ + mutex_unlock(&pvr_dev->fwccb.lock); + + process_fwccb_command(pvr_dev, &cmd); + + mutex_lock(&pvr_dev->fwccb.lock); + } + + mutex_unlock(&pvr_dev->fwccb.lock); +} + +/** + * pvr_kccb_capacity() - Returns the maximum number of usable KCCB slots. + * @pvr_dev: Target PowerVR device + * + * Return: + * * The maximum number of active slots. + */ +static u32 pvr_kccb_capacity(struct pvr_device *pvr_dev) +{ + /* Capacity is the number of slot minus one to cope with the wrapping + * mechanisms. If we were to use all slots, we might end up with + * read_offset == write_offset, which the FW considers as a KCCB-is-empty + * condition. + */ + return pvr_dev->kccb.slot_count - 1; +} + +/** + * pvr_kccb_used_slot_count_locked() - Get the number of used slots + * @pvr_dev: Device pointer. + * + * KCCB lock must be held. + * + * Return: + * * The number of slots currently used. + */ +static u32 +pvr_kccb_used_slot_count_locked(struct pvr_device *pvr_dev) +{ + struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 wr_offset = READ_ONCE(ctrl->write_offset); + u32 rd_offset = READ_ONCE(ctrl->read_offset); + u32 used_count; + + lockdep_assert_held(&pvr_ccb->lock); + + if (wr_offset >= rd_offset) + used_count = wr_offset - rd_offset; + else + used_count = wr_offset + pvr_dev->kccb.slot_count - rd_offset; + + return used_count; +} + +/** + * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref + * held and a slot pre-reserved + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + */ +void +pvr_kccb_send_cmd_reserved_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb; + struct rogue_fwif_kccb_cmd *kccb = pvr_ccb->ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 old_write_offset; + u32 new_write_offset; + + WARN_ON(pvr_dev->lost); + + mutex_lock(&pvr_ccb->lock); + + if (WARN_ON(!pvr_dev->kccb.reserved_count)) + goto out_unlock; + + old_write_offset = READ_ONCE(ctrl->write_offset); + + /* We reserved the slot, we should have one available. */ + if (WARN_ON(!pvr_ccb_slot_available_locked(pvr_ccb, &new_write_offset))) + goto out_unlock; + + memcpy(&kccb[old_write_offset], cmd, + sizeof(struct rogue_fwif_kccb_cmd)); + if (kccb_slot) { + *kccb_slot = old_write_offset; + /* Clear return status for this slot. */ + WRITE_ONCE(pvr_dev->kccb.rtn[old_write_offset], + ROGUE_FWIF_KCCB_RTN_SLOT_NO_RESPONSE); + } + mb(); /* memory barrier */ + WRITE_ONCE(ctrl->write_offset, new_write_offset); + pvr_dev->kccb.reserved_count--; + + /* Kick MTS */ + pvr_fw_mts_schedule(pvr_dev, + PVR_FWIF_DM_GP & ~ROGUE_CR_MTS_SCHEDULE_DM_CLRMSK); + +out_unlock: + mutex_unlock(&pvr_ccb->lock); +} + +/** + * pvr_kccb_try_reserve_slot() - Try to reserve a KCCB slot + * @pvr_dev: Device pointer. + * + * Return: + * * true if a KCCB slot was reserved, or + * * false otherwise. + */ +static bool pvr_kccb_try_reserve_slot(struct pvr_device *pvr_dev) +{ + bool reserved = false; + u32 used_count; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + if (pvr_dev->kccb.reserved_count < pvr_kccb_capacity(pvr_dev) - used_count) { + pvr_dev->kccb.reserved_count++; + reserved = true; + } + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return reserved; +} + +/** + * pvr_kccb_reserve_slot_sync() - Try to reserve a slot synchronously + * @pvr_dev: Device pointer. + * + * Return: + * * 0 on success, or + * * -EBUSY if no slots were reserved after %RESERVE_SLOT_TIMEOUT, with a minimum of + * %RESERVE_SLOT_MIN_RETRIES retries. + */ +static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev) +{ + unsigned long start_timestamp = jiffies; + bool reserved = false; + u32 retries = 0; + + while ((jiffies - start_timestamp) < (u32)RESERVE_SLOT_TIMEOUT || + retries < RESERVE_SLOT_MIN_RETRIES) { + reserved = pvr_kccb_try_reserve_slot(pvr_dev); + if (reserved) + break; + + usleep_range(1, 50); + + if (retries < U32_MAX) + retries++; + } + + return reserved ? 0 : -EBUSY; +} + +/** + * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -EBUSY if timeout while waiting for a free KCCB slot. + */ +int +pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + int err; + + err = pvr_kccb_reserve_slot_sync(pvr_dev); + if (err) + return err; + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, cmd, kccb_slot); + return 0; +} + +/** + * pvr_kccb_send_cmd() - Send command to the KCCB + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -EBUSY if timeout while waiting for a free KCCB slot. + */ +int +pvr_kccb_send_cmd(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + int err; + + err = pvr_power_get(pvr_dev); + if (err) + return err; + + err = pvr_kccb_send_cmd_powered(pvr_dev, cmd, kccb_slot); + + pvr_power_put(pvr_dev); + + return err; +} + +/** + * pvr_kccb_wait_for_completion() - Wait for a KCCB command to complete + * @pvr_dev: Device pointer. + * @slot_nr: KCCB slot to wait on. + * @timeout: Timeout length (in jiffies). + * @rtn_out: Location to store KCCB command result. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -ETIMEDOUT on timeout. + */ +int +pvr_kccb_wait_for_completion(struct pvr_device *pvr_dev, u32 slot_nr, + u32 timeout, u32 *rtn_out) +{ + int ret = wait_event_timeout(pvr_dev->kccb.rtn_q, READ_ONCE(pvr_dev->kccb.rtn[slot_nr]) & + ROGUE_FWIF_KCCB_RTN_SLOT_CMD_EXECUTED, timeout); + + if (ret && rtn_out) + *rtn_out = READ_ONCE(pvr_dev->kccb.rtn[slot_nr]); + + return ret ? 0 : -ETIMEDOUT; +} + +/** + * pvr_kccb_is_idle() - Returns whether the device's KCCB is idle + * @pvr_dev: Device pointer + * + * Returns: + * * %true if the KCCB is idle (contains no commands), or + * * %false if the KCCB contains pending commands. + */ +bool +pvr_kccb_is_idle(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->kccb.ccb.ctrl; + bool idle; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + idle = (READ_ONCE(ctrl->write_offset) == READ_ONCE(ctrl->read_offset)); + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return idle; +} + +static const char * +pvr_kccb_fence_get_driver_name(struct dma_fence *f) +{ + return PVR_DRIVER_NAME; +} + +static const char * +pvr_kccb_fence_get_timeline_name(struct dma_fence *f) +{ + return "kccb"; +} + +static const struct dma_fence_ops pvr_kccb_fence_ops = { + .get_driver_name = pvr_kccb_fence_get_driver_name, + .get_timeline_name = pvr_kccb_fence_get_timeline_name, +}; + +/** + * struct pvr_kccb_fence - Fence object used to wait for a KCCB slot + */ +struct pvr_kccb_fence { + /** @base: Base dma_fence object. */ + struct dma_fence base; + + /** @node: Node used to insert the fence in the pvr_device::kccb::waiters list. */ + struct list_head node; +}; + +/** + * pvr_kccb_wake_up_waiters() - Check the KCCB waiters + * @pvr_dev: Target PowerVR device + * + * Signal as many KCCB fences as we have slots available. + */ +void pvr_kccb_wake_up_waiters(struct pvr_device *pvr_dev) +{ + struct pvr_kccb_fence *fence, *tmp_fence; + u32 used_count, available_count; + + /* Wake up those waiting for KCCB slot execution. */ + wake_up_all(&pvr_dev->kccb.rtn_q); + + /* Then iterate over all KCCB fences and signal as many as we can. */ + mutex_lock(&pvr_dev->kccb.ccb.lock); + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + + if (WARN_ON(used_count + pvr_dev->kccb.reserved_count > pvr_kccb_capacity(pvr_dev))) + goto out_unlock; + + available_count = pvr_kccb_capacity(pvr_dev) - used_count - pvr_dev->kccb.reserved_count; + list_for_each_entry_safe(fence, tmp_fence, &pvr_dev->kccb.waiters, node) { + if (!available_count) + break; + + list_del(&fence->node); + pvr_dev->kccb.reserved_count++; + available_count--; + dma_fence_signal(&fence->base); + dma_fence_put(&fence->base); + } + +out_unlock: + mutex_unlock(&pvr_dev->kccb.ccb.lock); +} + +/** + * pvr_kccb_fini() - Cleanup device KCCB + * @pvr_dev: Target PowerVR device + */ +void pvr_kccb_fini(struct pvr_device *pvr_dev) +{ + pvr_ccb_fini(&pvr_dev->kccb.ccb); + WARN_ON(!list_empty(&pvr_dev->kccb.waiters)); + WARN_ON(pvr_dev->kccb.reserved_count); +} + +/** + * pvr_kccb_init() - Initialise device KCCB + * @pvr_dev: Target PowerVR device + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_ccb_init(). + */ +int +pvr_kccb_init(struct pvr_device *pvr_dev) +{ + pvr_dev->kccb.slot_count = 1 << ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT; + INIT_LIST_HEAD(&pvr_dev->kccb.waiters); + pvr_dev->kccb.fence_ctx.id = dma_fence_context_alloc(1); + spin_lock_init(&pvr_dev->kccb.fence_ctx.lock); + + return pvr_ccb_init(pvr_dev, &pvr_dev->kccb.ccb, + ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT, + sizeof(struct rogue_fwif_kccb_cmd)); +} + +/** + * pvr_kccb_fence_alloc() - Allocate a pvr_kccb_fence object + * + * Return: + * * NULL if the allocation fails, or + * * A valid dma_fence pointer otherwise. + */ +struct dma_fence *pvr_kccb_fence_alloc(void) +{ + struct pvr_kccb_fence *kccb_fence; + + kccb_fence = kzalloc(sizeof(*kccb_fence), GFP_KERNEL); + if (!kccb_fence) + return NULL; + + return &kccb_fence->base; +} + +/** + * pvr_kccb_fence_put() - Drop a KCCB fence reference + * @fence: The fence to drop the reference on. + * + * If the fence hasn't been initialized yet, dma_fence_free() is called. This + * way we have a single function taking care of both cases. + */ +void pvr_kccb_fence_put(struct dma_fence *fence) +{ + if (!fence) + return; + + if (!fence->ops) { + dma_fence_free(fence); + } else { + WARN_ON(fence->ops != &pvr_kccb_fence_ops); + dma_fence_put(fence); + } +} + +/** + * pvr_kccb_reserve_slot() - Reserve a KCCB slot for later use + * @pvr_dev: Target PowerVR device + * @f: KCCB fence object previously allocated with pvr_kccb_fence_alloc() + * + * Try to reserve a KCCB slot, and if there's no slot available, + * initializes the fence object and queue it to the waiters list. + * + * If NULL is returned, that means the slot is reserved. In that case, + * the @f is freed and shouldn't be accessed after that point. + * + * Return: + * * NULL if a slot was available directly, or + * * A valid dma_fence object to wait on if no slot was available. + */ +struct dma_fence * +pvr_kccb_reserve_slot(struct pvr_device *pvr_dev, struct dma_fence *f) +{ + struct pvr_kccb_fence *fence = container_of(f, struct pvr_kccb_fence, base); + struct dma_fence *out_fence = NULL; + u32 used_count; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + if (pvr_dev->kccb.reserved_count >= pvr_kccb_capacity(pvr_dev) - used_count) { + dma_fence_init(&fence->base, &pvr_kccb_fence_ops, + &pvr_dev->kccb.fence_ctx.lock, + pvr_dev->kccb.fence_ctx.id, + atomic_inc_return(&pvr_dev->kccb.fence_ctx.seqno)); + out_fence = dma_fence_get(&fence->base); + list_add_tail(&fence->node, &pvr_dev->kccb.waiters); + } else { + pvr_kccb_fence_put(f); + pvr_dev->kccb.reserved_count++; + } + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return out_fence; +} + +/** + * pvr_kccb_release_slot() - Release a KCCB slot reserved with + * pvr_kccb_reserve_slot() + * @pvr_dev: Target PowerVR device + * + * Should only be called if something failed after the + * pvr_kccb_reserve_slot() call and you know you won't call + * pvr_kccb_send_cmd_reserved(). + */ +void pvr_kccb_release_slot(struct pvr_device *pvr_dev) +{ + mutex_lock(&pvr_dev->kccb.ccb.lock); + if (!WARN_ON(!pvr_dev->kccb.reserved_count)) + pvr_dev->kccb.reserved_count--; + mutex_unlock(&pvr_dev->kccb.ccb.lock); +} + +/** + * pvr_fwccb_init() - Initialise device FWCCB + * @pvr_dev: Target PowerVR device + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_ccb_init(). + */ +int +pvr_fwccb_init(struct pvr_device *pvr_dev) +{ + return pvr_ccb_init(pvr_dev, &pvr_dev->fwccb, + ROGUE_FWIF_FWCCB_NUMCMDS_LOG2, + sizeof(struct rogue_fwif_fwccb_cmd)); +} diff --git a/drivers/gpu/drm/imagination/pvr_ccb.h b/drivers/gpu/drm/imagination/pvr_ccb.h new file mode 100644 index 000000000000..4c8aef31eeb0 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_ccb.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CCB_H +#define PVR_CCB_H + +#include "pvr_rogue_fwif.h" + +#include +#include + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +struct pvr_ccb { + /** @ctrl_obj: FW object representing CCB control structure. */ + struct pvr_fw_object *ctrl_obj; + /** @ccb_obj: FW object representing CCB. */ + struct pvr_fw_object *ccb_obj; + + /** @ctrl_fw_addr: FW virtual address of CCB control structure. */ + u32 ctrl_fw_addr; + /** @ccb_fw_addr: FW virtual address of CCB. */ + u32 ccb_fw_addr; + + /** @num_cmds: Number of commands in this CCB. */ + u32 num_cmds; + + /** @cmd_size: Size of each command in this CCB, in bytes. */ + u32 cmd_size; + + /** @lock: Mutex protecting @ctrl and @ccb. */ + struct mutex lock; + /** + * @ctrl: Kernel mapping of CCB control structure. @lock must be held + * when accessing. + */ + struct rogue_fwif_ccb_ctl *ctrl; + /** @ccb: Kernel mapping of CCB. @lock must be held when accessing. */ + void *ccb; +}; + +int pvr_kccb_init(struct pvr_device *pvr_dev); +void pvr_kccb_fini(struct pvr_device *pvr_dev); +int pvr_fwccb_init(struct pvr_device *pvr_dev); +void pvr_ccb_fini(struct pvr_ccb *ccb); + +void pvr_fwccb_process(struct pvr_device *pvr_dev); + +struct dma_fence *pvr_kccb_fence_alloc(void); +void pvr_kccb_fence_put(struct dma_fence *fence); +struct dma_fence * +pvr_kccb_reserve_slot(struct pvr_device *pvr_dev, struct dma_fence *f); +void pvr_kccb_release_slot(struct pvr_device *pvr_dev); +int pvr_kccb_send_cmd(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, u32 *kccb_slot); +int pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot); +void pvr_kccb_send_cmd_reserved_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot); +int pvr_kccb_wait_for_completion(struct pvr_device *pvr_dev, u32 slot_nr, u32 timeout, + u32 *rtn_out); +bool pvr_kccb_is_idle(struct pvr_device *pvr_dev); +void pvr_kccb_wake_up_waiters(struct pvr_device *pvr_dev); + +#endif /* PVR_CCB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index e16282325178..1be14cdbdace 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -114,6 +114,87 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev) return 0; } +static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data) +{ + struct pvr_device *pvr_dev = data; + irqreturn_t ret = IRQ_NONE; + + /* We are in the threaded handler, we can keep dequeuing events until we + * don't see any. This should allow us to reduce the number of interrupts + * when the GPU is receiving a massive amount of short jobs. + */ + while (pvr_fw_irq_pending(pvr_dev)) { + pvr_fw_irq_clear(pvr_dev); + + if (pvr_dev->fw_dev.booted) { + pvr_fwccb_process(pvr_dev); + pvr_kccb_wake_up_waiters(pvr_dev); + } + + pm_runtime_mark_last_busy(from_pvr_device(pvr_dev)->dev); + + ret = IRQ_HANDLED; + } + + /* Unmask FW irqs before returning, so new interrupts can be received. */ + pvr_fw_irq_enable(pvr_dev); + return ret; +} + +static irqreturn_t pvr_device_irq_handler(int irq, void *data) +{ + struct pvr_device *pvr_dev = data; + + if (!pvr_fw_irq_pending(pvr_dev)) + return IRQ_NONE; /* Spurious IRQ - ignore. */ + + /* Mask the FW interrupts before waking up the thread. Will be unmasked + * when the thread handler is done processing events. + */ + pvr_fw_irq_disable(pvr_dev); + return IRQ_WAKE_THREAD; +} + +/** + * pvr_device_irq_init() - Initialise IRQ required by a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, + * * Any error returned by platform_get_irq_byname(), or + * * Any error returned by request_irq(). + */ +static int +pvr_device_irq_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct platform_device *plat_dev = to_platform_device(drm_dev->dev); + + init_waitqueue_head(&pvr_dev->kccb.rtn_q); + + pvr_dev->irq = platform_get_irq(plat_dev, 0); + if (pvr_dev->irq < 0) + return pvr_dev->irq; + + /* Clear any pending events before requesting the IRQ line. */ + pvr_fw_irq_clear(pvr_dev); + pvr_fw_irq_enable(pvr_dev); + + return request_threaded_irq(pvr_dev->irq, pvr_device_irq_handler, + pvr_device_irq_thread_handler, + IRQF_SHARED, "gpu", pvr_dev); +} + +/** + * pvr_device_irq_fini() - Deinitialise IRQ required by a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_device_irq_fini(struct pvr_device *pvr_dev) +{ + free_irq(pvr_dev->irq, pvr_dev); +} + /** * pvr_build_firmware_filename() - Construct a PowerVR firmware filename * @pvr_dev: Target PowerVR device. @@ -324,7 +405,19 @@ pvr_device_gpu_init(struct pvr_device *pvr_dev) return PTR_ERR(pvr_dev->kernel_vm_ctx); } + err = pvr_fw_init(pvr_dev); + if (err) + goto err_vm_ctx_put; + return 0; + +err_vm_ctx_put: + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + pvr_vm_context_put(pvr_dev->kernel_vm_ctx); + pvr_dev->kernel_vm_ctx = NULL; + } + + return err; } /** @@ -334,6 +427,8 @@ pvr_device_gpu_init(struct pvr_device *pvr_dev) static void pvr_device_gpu_fini(struct pvr_device *pvr_dev) { + pvr_fw_fini(pvr_dev); + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { WARN_ON(!pvr_vm_context_put(pvr_dev->kernel_vm_ctx)); pvr_dev->kernel_vm_ctx = NULL; @@ -386,10 +481,17 @@ pvr_device_init(struct pvr_device *pvr_dev) if (err) goto err_pm_runtime_put; + err = pvr_device_irq_init(pvr_dev); + if (err) + goto err_device_gpu_fini; + pm_runtime_put(dev); return 0; +err_device_gpu_fini: + pvr_device_gpu_fini(pvr_dev); + err_pm_runtime_put: pm_runtime_put_sync_suspend(dev); @@ -407,6 +509,7 @@ pvr_device_fini(struct pvr_device *pvr_dev) * Deinitialization stages are performed in reverse order compared to * the initialization stages in pvr_device_init(). */ + pvr_device_irq_fini(pvr_dev); pvr_device_gpu_fini(pvr_dev); } diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index 771ba879f02d..39347595c6f0 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -4,6 +4,7 @@ #ifndef PVR_DEVICE_H #define PVR_DEVICE_H +#include "pvr_ccb.h" #include "pvr_device_info.h" #include "pvr_fw.h" @@ -123,6 +124,12 @@ struct pvr_device { */ struct clk *mem_clk; + /** @irq: IRQ number. */ + int irq; + + /** @fwccb: Firmware CCB. */ + struct pvr_ccb fwccb; + /** * @kernel_vm_ctx: Virtual memory context used for kernel mappings. * @@ -153,6 +160,49 @@ struct pvr_device { u32 kccb_stall_count; } watchdog; + struct { + /** @ccb: Kernel CCB. */ + struct pvr_ccb ccb; + + /** @rtn_q: Waitqueue for KCCB command return waiters. */ + wait_queue_head_t rtn_q; + + /** @rtn_obj: Object representing KCCB return slots. */ + struct pvr_fw_object *rtn_obj; + + /** + * @rtn: Pointer to CPU mapping of KCCB return slots. Must be accessed by + * READ_ONCE()/WRITE_ONCE(). + */ + u32 *rtn; + + /** @slot_count: Total number of KCCB slots available. */ + u32 slot_count; + + /** @reserved_count: Number of KCCB slots reserved for future use. */ + u32 reserved_count; + + /** + * @waiters: List of KCCB slot waiters. + */ + struct list_head waiters; + + /** @fence_ctx: KCCB fence context. */ + struct { + /** @id: KCCB fence context ID allocated with dma_fence_context_alloc(). */ + u64 id; + + /** @seqno: Sequence number incremented each time a fence is created. */ + atomic_t seqno; + + /** + * @lock: Lock used to synchronize access to fences allocated by this + * context. + */ + spinlock_t lock; + } fence_ctx; + } kccb; + /** * @lost: %true if the device has been lost. * @@ -161,6 +211,16 @@ struct pvr_device { */ bool lost; + /** + * @reset_sem: Reset semaphore. + * + * GPU reset code will lock this for writing. Any code that submits commands to the firmware + * that isn't in an IRQ handler or on the scheduler workqueue must lock this for reading. + * Once this has been successfully locked, &pvr_dev->lost _must_ be checked, and -%EIO must + * be returned if it is set. + */ + struct rw_semaphore reset_sem; + /** @sched_wq: Workqueue for schedulers. */ struct workqueue_struct *sched_wq; }; diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 12e136217c45..33b38c0d79c8 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -1331,3 +1331,4 @@ MODULE_AUTHOR("Imagination Technologies Ltd."); MODULE_DESCRIPTION(PVR_DRIVER_DESC); MODULE_LICENSE("Dual MIT/GPL"); MODULE_IMPORT_NS(DMA_BUF); +MODULE_FIRMWARE("powervr/rogue_33.15.11.3_v1.fw"); diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c index a9377c735c9c..f8ed981f1807 100644 --- a/drivers/gpu/drm/imagination/pvr_fw.c +++ b/drivers/gpu/drm/imagination/pvr_fw.c @@ -1,16 +1,84 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT /* Copyright (c) 2023 Imagination Technologies Ltd. */ +#include "pvr_ccb.h" #include "pvr_device.h" #include "pvr_device_info.h" #include "pvr_fw.h" +#include "pvr_fw_info.h" +#include "pvr_fw_startstop.h" +#include "pvr_fw_trace.h" +#include "pvr_gem.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif_dev_info.h" +#include "pvr_rogue_heap_config.h" +#include "pvr_vm.h" #include +#include +#include +#include #include +#include +#include #include #define FW_MAX_SUPPORTED_MAJOR_VERSION 1 +#define FW_BOOT_TIMEOUT_USEC 5000000 + +/* Config heap occupies top 192k of the firmware heap. */ +#define PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY SZ_64K +#define PVR_ROGUE_FW_CONFIG_HEAP_SIZE (3 * PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) + +/* Main firmware allocations should come from the remainder of the heap. */ +#define PVR_ROGUE_FW_MAIN_HEAP_BASE ROGUE_FW_HEAP_BASE + +/* Offsets from start of configuration area of FW heap. */ +#define PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET 0 +#define PVR_ROGUE_FWIF_OSINIT_OFFSET \ + (PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET + PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) +#define PVR_ROGUE_FWIF_SYSINIT_OFFSET \ + (PVR_ROGUE_FWIF_OSINIT_OFFSET + PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) + +#define PVR_ROGUE_FAULT_PAGE_SIZE SZ_4K + +#define PVR_SYNC_OBJ_SIZE sizeof(u32) + +const struct pvr_fw_layout_entry * +pvr_fw_find_layout_entry(struct pvr_device *pvr_dev, enum pvr_fw_section_id id) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 entry; + + for (entry = 0; entry < num_layout_entries; entry++) { + if (layout_entries[entry].id == id) + return &layout_entries[entry]; + } + + return NULL; +} + +static const struct pvr_fw_layout_entry * +pvr_fw_find_private_data(struct pvr_device *pvr_dev) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 entry; + + for (entry = 0; entry < num_layout_entries; entry++) { + if (layout_entries[entry].id == META_PRIVATE_DATA || + layout_entries[entry].id == MIPS_PRIVATE_DATA || + layout_entries[entry].id == RISCV_PRIVATE_DATA) + return &layout_entries[entry]; + } + + return NULL; +} + +#define DEV_INFO_MASK_SIZE(x) DIV_ROUND_UP(x, 64) + /** * pvr_fw_validate() - Parse firmware header and check compatibility * @pvr_dev: Device pointer. @@ -122,6 +190,704 @@ pvr_fw_get_device_info(struct pvr_device *pvr_dev) header->feature_param_size); } +static void +layout_get_sizes(struct pvr_device *pvr_dev) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + fw_mem->code_alloc_size = 0; + fw_mem->data_alloc_size = 0; + fw_mem->core_code_alloc_size = 0; + fw_mem->core_data_alloc_size = 0; + + /* Extract section sizes from FW layout table. */ + for (u32 entry = 0; entry < num_layout_entries; entry++) { + switch (layout_entries[entry].type) { + case FW_CODE: + fw_mem->code_alloc_size += layout_entries[entry].alloc_size; + break; + case FW_DATA: + fw_mem->data_alloc_size += layout_entries[entry].alloc_size; + break; + case FW_COREMEM_CODE: + fw_mem->core_code_alloc_size += + layout_entries[entry].alloc_size; + break; + case FW_COREMEM_DATA: + fw_mem->core_data_alloc_size += + layout_entries[entry].alloc_size; + break; + case NONE: + break; + } + } +} + +int +pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr, + void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr, + void **host_addr_out) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 end_addr = addr + size; + int entry = 0; + + /* Ensure requested range is not zero, and size is not causing addr to overflow. */ + if (end_addr <= addr) + return -EINVAL; + + for (entry = 0; entry < num_layout_entries; entry++) { + u32 entry_start_addr = layout_entries[entry].base_addr; + u32 entry_end_addr = entry_start_addr + layout_entries[entry].alloc_size; + + if (addr >= entry_start_addr && addr < entry_end_addr && + end_addr > entry_start_addr && end_addr <= entry_end_addr) { + switch (layout_entries[entry].type) { + case FW_CODE: + *host_addr_out = fw_code_ptr; + break; + + case FW_DATA: + *host_addr_out = fw_data_ptr; + break; + + case FW_COREMEM_CODE: + *host_addr_out = fw_core_code_ptr; + break; + + case FW_COREMEM_DATA: + *host_addr_out = fw_core_data_ptr; + break; + + default: + return -EINVAL; + } + /* Direct Mem write to mapped memory */ + addr -= layout_entries[entry].base_addr; + addr += layout_entries[entry].alloc_offset; + + /* + * Add offset to pointer to FW allocation only if that + * allocation is available + */ + *(u8 **)host_addr_out += addr; + return 0; + } + } + + return -EINVAL; +} + +static int +pvr_fw_create_fwif_connection_ctl(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->fwif_connection_ctl = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET, + sizeof(*fw_dev->fwif_connection_ctl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, + &fw_dev->mem.fwif_connection_ctl_obj); + if (IS_ERR(fw_dev->fwif_connection_ctl)) { + drm_err(drm_dev, + "Unable to allocate FWIF connection control memory\n"); + return PTR_ERR(fw_dev->fwif_connection_ctl); + } + + return 0; +} + +static void +pvr_fw_fini_fwif_connection_ctl(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + pvr_fw_object_unmap_and_destroy(fw_dev->mem.fwif_connection_ctl_obj); +} + +static void +fw_osinit_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_osinit *fwif_osinit = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + + fwif_osinit->kernel_ccbctl_fw_addr = pvr_dev->kccb.ccb.ctrl_fw_addr; + fwif_osinit->kernel_ccb_fw_addr = pvr_dev->kccb.ccb.ccb_fw_addr; + pvr_fw_object_get_fw_addr(pvr_dev->kccb.rtn_obj, + &fwif_osinit->kernel_ccb_rtn_slots_fw_addr); + + fwif_osinit->firmware_ccbctl_fw_addr = pvr_dev->fwccb.ctrl_fw_addr; + fwif_osinit->firmware_ccb_fw_addr = pvr_dev->fwccb.ccb_fw_addr; + + fwif_osinit->work_est_firmware_ccbctl_fw_addr = 0; + fwif_osinit->work_est_firmware_ccb_fw_addr = 0; + + pvr_fw_object_get_fw_addr(fw_mem->hwrinfobuf_obj, + &fwif_osinit->rogue_fwif_hwr_info_buf_ctl_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->osdata_obj, &fwif_osinit->fw_os_data_fw_addr); + + fwif_osinit->hwr_debug_dump_limit = 0; + + rogue_fwif_compchecks_bvnc_init(&fwif_osinit->rogue_comp_checks.hw_bvnc); + rogue_fwif_compchecks_bvnc_init(&fwif_osinit->rogue_comp_checks.fw_bvnc); +} + +static void +fw_osdata_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_osdata *fwif_osdata = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + pvr_fw_object_get_fw_addr(fw_mem->power_sync_obj, &fwif_osdata->power_sync_fw_addr); +} + +static void +fw_fault_page_init(void *cpu_ptr, void *priv) +{ + u32 *fault_page = cpu_ptr; + + for (int i = 0; i < PVR_ROGUE_FAULT_PAGE_SIZE / sizeof(*fault_page); i++) + fault_page[i] = 0xdeadbee0; +} + +static void +fw_sysinit_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_sysinit *fwif_sysinit = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + dma_addr_t fault_dma_addr = 0; + u32 clock_speed_hz = clk_get_rate(pvr_dev->core_clk); + + WARN_ON(!clock_speed_hz); + + WARN_ON(pvr_fw_object_get_dma_addr(fw_mem->fault_page_obj, 0, &fault_dma_addr)); + fwif_sysinit->fault_phys_addr = (u64)fault_dma_addr; + + fwif_sysinit->pds_exec_base = ROGUE_PDSCODEDATA_HEAP_BASE; + fwif_sysinit->usc_exec_base = ROGUE_USCCODE_HEAP_BASE; + + pvr_fw_object_get_fw_addr(fw_mem->runtime_cfg_obj, &fwif_sysinit->runtime_cfg_fw_addr); + pvr_fw_object_get_fw_addr(fw_dev->fw_trace.tracebuf_ctrl_obj, + &fwif_sysinit->trace_buf_ctl_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->sysdata_obj, &fwif_sysinit->fw_sys_data_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->gpu_util_fwcb_obj, + &fwif_sysinit->gpu_util_fw_cb_ctl_fw_addr); + if (fw_mem->core_data_obj) { + pvr_fw_object_get_fw_addr(fw_mem->core_data_obj, + &fwif_sysinit->coremem_data_store.fw_addr); + } + + /* Currently unsupported. */ + fwif_sysinit->counter_dump_ctl.buffer_fw_addr = 0; + fwif_sysinit->counter_dump_ctl.size_in_dwords = 0; + + /* Skip alignment checks. */ + fwif_sysinit->align_checks = 0; + + fwif_sysinit->filter_flags = 0; + fwif_sysinit->hw_perf_filter = 0; + fwif_sysinit->firmware_perf = FW_PERF_CONF_NONE; + fwif_sysinit->initial_core_clock_speed = clock_speed_hz; + fwif_sysinit->active_pm_latency_ms = 0; + fwif_sysinit->gpio_validation_mode = ROGUE_FWIF_GPIO_VAL_OFF; + fwif_sysinit->firmware_started = false; + fwif_sysinit->marker_val = 1; + + memset(&fwif_sysinit->bvnc_km_feature_flags, 0, + sizeof(fwif_sysinit->bvnc_km_feature_flags)); +} + +#define ROGUE_FWIF_SLC_MIN_SIZE_FOR_DM_OVERLAP_KB 4 + +static void +fw_sysdata_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_sysdata *fwif_sysdata = cpu_ptr; + struct pvr_device *pvr_dev = priv; + u32 slc_size_in_kilobytes = 0; + u32 config_flags = 0; + + WARN_ON(PVR_FEATURE_VALUE(pvr_dev, slc_size_in_kilobytes, &slc_size_in_kilobytes)); + + if (slc_size_in_kilobytes < ROGUE_FWIF_SLC_MIN_SIZE_FOR_DM_OVERLAP_KB) + config_flags |= ROGUE_FWIF_INICFG_DISABLE_DM_OVERLAP; + + fwif_sysdata->config_flags = config_flags; +} + +static void +fw_runtime_cfg_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_runtime_cfg *runtime_cfg = cpu_ptr; + struct pvr_device *pvr_dev = priv; + u32 clock_speed_hz = clk_get_rate(pvr_dev->core_clk); + + WARN_ON(!clock_speed_hz); + + runtime_cfg->core_clock_speed = clock_speed_hz; + runtime_cfg->active_pm_latency_ms = 0; + runtime_cfg->active_pm_latency_persistant = true; + WARN_ON(PVR_FEATURE_VALUE(pvr_dev, num_clusters, + &runtime_cfg->default_dusts_num_init) != 0); +} + +static void +fw_gpu_util_fwcb_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_gpu_util_fwcb *gpu_util_fwcb = cpu_ptr; + + gpu_util_fwcb->last_word = PVR_FWIF_GPU_UTIL_STATE_IDLE; +} + +static int +pvr_fw_create_structures(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + int err; + + fw_dev->power_sync = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->power_sync), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->power_sync_obj); + if (IS_ERR(fw_dev->power_sync)) { + drm_err(drm_dev, "Unable to allocate FW power_sync structure\n"); + return PTR_ERR(fw_dev->power_sync); + } + + fw_dev->hwrinfobuf = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->hwrinfobuf), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->hwrinfobuf_obj); + if (IS_ERR(fw_dev->hwrinfobuf)) { + drm_err(drm_dev, + "Unable to allocate FW hwrinfobuf structure\n"); + err = PTR_ERR(fw_dev->hwrinfobuf); + goto err_release_power_sync; + } + + err = pvr_fw_object_create(pvr_dev, PVR_SYNC_OBJ_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->mmucache_sync_obj); + if (err) { + drm_err(drm_dev, + "Unable to allocate MMU cache sync object\n"); + goto err_release_hwrinfobuf; + } + + fw_dev->fwif_sysdata = pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_dev->fwif_sysdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_sysdata_init, pvr_dev, + &fw_mem->sysdata_obj); + if (IS_ERR(fw_dev->fwif_sysdata)) { + drm_err(drm_dev, "Unable to allocate FW SYSDATA structure\n"); + err = PTR_ERR(fw_dev->fwif_sysdata); + goto err_release_mmucache_sync_obj; + } + + err = pvr_fw_object_create(pvr_dev, PVR_ROGUE_FAULT_PAGE_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_fault_page_init, NULL, &fw_mem->fault_page_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate FW fault page\n"); + goto err_release_sysdata; + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_gpu_util_fwcb), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_gpu_util_fwcb_init, pvr_dev, &fw_mem->gpu_util_fwcb_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate GPU util FWCB\n"); + goto err_release_fault_page; + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_runtime_cfg), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_runtime_cfg_init, pvr_dev, &fw_mem->runtime_cfg_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate FW runtime config\n"); + goto err_release_gpu_util_fwcb; + } + + err = pvr_fw_trace_init(pvr_dev); + if (err) + goto err_release_runtime_cfg; + + fw_dev->fwif_osdata = pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_dev->fwif_osdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_osdata_init, pvr_dev, + &fw_mem->osdata_obj); + if (IS_ERR(fw_dev->fwif_osdata)) { + drm_err(drm_dev, "Unable to allocate FW OSDATA structure\n"); + err = PTR_ERR(fw_dev->fwif_osdata); + goto err_fw_trace_fini; + } + + fw_dev->fwif_osinit = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_OSINIT_OFFSET, + sizeof(*fw_dev->fwif_osinit), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_osinit_init, pvr_dev, &fw_mem->osinit_obj); + if (IS_ERR(fw_dev->fwif_osinit)) { + drm_err(drm_dev, "Unable to allocate FW OSINIT structure\n"); + err = PTR_ERR(fw_dev->fwif_osinit); + goto err_release_osdata; + } + + fw_dev->fwif_sysinit = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_SYSINIT_OFFSET, + sizeof(*fw_dev->fwif_sysinit), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_sysinit_init, pvr_dev, &fw_mem->sysinit_obj); + if (IS_ERR(fw_dev->fwif_sysinit)) { + drm_err(drm_dev, "Unable to allocate FW SYSINIT structure\n"); + err = PTR_ERR(fw_dev->fwif_sysinit); + goto err_release_osinit; + } + + return 0; + +err_release_osinit: + pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj); + +err_release_osdata: + pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj); + +err_fw_trace_fini: + pvr_fw_trace_fini(pvr_dev); + +err_release_runtime_cfg: + pvr_fw_object_destroy(fw_mem->runtime_cfg_obj); + +err_release_gpu_util_fwcb: + pvr_fw_object_destroy(fw_mem->gpu_util_fwcb_obj); + +err_release_fault_page: + pvr_fw_object_destroy(fw_mem->fault_page_obj); + +err_release_sysdata: + pvr_fw_object_unmap_and_destroy(fw_mem->sysdata_obj); + +err_release_mmucache_sync_obj: + pvr_fw_object_destroy(fw_mem->mmucache_sync_obj); + +err_release_hwrinfobuf: + pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj); + +err_release_power_sync: + pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj); + + return err; +} + +static void +pvr_fw_destroy_structures(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + + pvr_fw_trace_fini(pvr_dev); + pvr_fw_object_destroy(fw_mem->runtime_cfg_obj); + pvr_fw_object_destroy(fw_mem->gpu_util_fwcb_obj); + pvr_fw_object_destroy(fw_mem->fault_page_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->sysdata_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->sysinit_obj); + + pvr_fw_object_destroy(fw_mem->mmucache_sync_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj); +} + +/** + * pvr_fw_process() - Process firmware image, allocate FW memory and create boot + * arguments + * @pvr_dev: Device pointer. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_object_create_and_map_offset(), or + * * Any error returned by pvr_fw_object_create_and_map(). + */ +static int +pvr_fw_process(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + const u8 *fw = pvr_dev->fw_dev.firmware->data; + const struct pvr_fw_layout_entry *private_data; + u8 *fw_code_ptr; + u8 *fw_data_ptr; + u8 *fw_core_code_ptr; + u8 *fw_core_data_ptr; + int err; + + layout_get_sizes(pvr_dev); + + private_data = pvr_fw_find_private_data(pvr_dev); + if (!private_data) + return -EINVAL; + + /* Allocate and map memory for firmware sections. */ + + /* + * Code allocation must be at the start of the firmware heap, otherwise + * firmware processor will be unable to boot. + * + * This has the useful side-effect that for every other object in the + * driver, a firmware address of 0 is invalid. + */ + fw_code_ptr = pvr_fw_object_create_and_map_offset(pvr_dev, 0, fw_mem->code_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->code_obj); + if (IS_ERR(fw_code_ptr)) { + drm_err(drm_dev, "Unable to allocate FW code memory\n"); + return PTR_ERR(fw_code_ptr); + } + + if (pvr_dev->fw_dev.defs->has_fixed_data_addr()) { + u32 base_addr = private_data->base_addr & pvr_dev->fw_dev.fw_heap_info.offset_mask; + + fw_data_ptr = + pvr_fw_object_create_and_map_offset(pvr_dev, base_addr, + fw_mem->data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->data_obj); + } else { + fw_data_ptr = pvr_fw_object_create_and_map(pvr_dev, fw_mem->data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->data_obj); + } + if (IS_ERR(fw_data_ptr)) { + drm_err(drm_dev, "Unable to allocate FW data memory\n"); + err = PTR_ERR(fw_data_ptr); + goto err_free_fw_code_obj; + } + + /* Core code and data sections are optional. */ + if (fw_mem->core_code_alloc_size) { + fw_core_code_ptr = + pvr_fw_object_create_and_map(pvr_dev, fw_mem->core_code_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->core_code_obj); + if (IS_ERR(fw_core_code_ptr)) { + drm_err(drm_dev, + "Unable to allocate FW core code memory\n"); + err = PTR_ERR(fw_core_code_ptr); + goto err_free_fw_data_obj; + } + } else { + fw_core_code_ptr = NULL; + } + + if (fw_mem->core_data_alloc_size) { + fw_core_data_ptr = + pvr_fw_object_create_and_map(pvr_dev, fw_mem->core_data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->core_data_obj); + if (IS_ERR(fw_core_data_ptr)) { + drm_err(drm_dev, + "Unable to allocate FW core data memory\n"); + err = PTR_ERR(fw_core_data_ptr); + goto err_free_fw_core_code_obj; + } + } else { + fw_core_data_ptr = NULL; + } + + fw_mem->code = kzalloc(fw_mem->code_alloc_size, GFP_KERNEL); + fw_mem->data = kzalloc(fw_mem->data_alloc_size, GFP_KERNEL); + if (fw_mem->core_code_alloc_size) + fw_mem->core_code = kzalloc(fw_mem->core_code_alloc_size, GFP_KERNEL); + if (fw_mem->core_data_alloc_size) + fw_mem->core_data = kzalloc(fw_mem->core_data_alloc_size, GFP_KERNEL); + + if (!fw_mem->code || !fw_mem->data || + (!fw_mem->core_code && fw_mem->core_code_alloc_size) || + (!fw_mem->core_data && fw_mem->core_data_alloc_size)) { + err = -ENOMEM; + goto err_free_kdata; + } + + err = pvr_dev->fw_dev.defs->fw_process(pvr_dev, fw, + fw_mem->code, fw_mem->data, fw_mem->core_code, + fw_mem->core_data, fw_mem->core_code_alloc_size); + + if (err) + goto err_free_fw_core_data_obj; + + memcpy(fw_code_ptr, fw_mem->code, fw_mem->code_alloc_size); + memcpy(fw_data_ptr, fw_mem->data, fw_mem->data_alloc_size); + if (fw_mem->core_code) + memcpy(fw_core_code_ptr, fw_mem->core_code, fw_mem->core_code_alloc_size); + if (fw_mem->core_data) + memcpy(fw_core_data_ptr, fw_mem->core_data, fw_mem->core_data_alloc_size); + + /* We're finished with the firmware section memory on the CPU, unmap. */ + if (fw_core_data_ptr) + pvr_fw_object_vunmap(fw_mem->core_data_obj); + if (fw_core_code_ptr) + pvr_fw_object_vunmap(fw_mem->core_code_obj); + pvr_fw_object_vunmap(fw_mem->data_obj); + fw_data_ptr = NULL; + pvr_fw_object_vunmap(fw_mem->code_obj); + fw_code_ptr = NULL; + + err = pvr_fw_create_fwif_connection_ctl(pvr_dev); + if (err) + goto err_free_fw_core_data_obj; + + return 0; + +err_free_kdata: + kfree(fw_mem->core_data); + kfree(fw_mem->core_code); + kfree(fw_mem->data); + kfree(fw_mem->code); + +err_free_fw_core_data_obj: + if (fw_core_data_ptr) + pvr_fw_object_unmap_and_destroy(fw_mem->core_data_obj); + +err_free_fw_core_code_obj: + if (fw_core_code_ptr) + pvr_fw_object_unmap_and_destroy(fw_mem->core_code_obj); + +err_free_fw_data_obj: + if (fw_data_ptr) + pvr_fw_object_vunmap(fw_mem->data_obj); + pvr_fw_object_destroy(fw_mem->data_obj); + +err_free_fw_code_obj: + if (fw_code_ptr) + pvr_fw_object_vunmap(fw_mem->code_obj); + pvr_fw_object_destroy(fw_mem->code_obj); + + return err; +} + +static int +pvr_copy_to_fw(struct pvr_fw_object *dest_obj, u8 *src_ptr, u32 size) +{ + u8 *dest_ptr = pvr_fw_object_vmap(dest_obj); + + if (IS_ERR(dest_ptr)) + return PTR_ERR(dest_ptr); + + memcpy(dest_ptr, src_ptr, size); + + pvr_fw_object_vunmap(dest_obj); + + return 0; +} + +static int +pvr_fw_reinit_code_data(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + int err; + + err = pvr_copy_to_fw(fw_mem->code_obj, fw_mem->code, fw_mem->code_alloc_size); + if (err) + return err; + + err = pvr_copy_to_fw(fw_mem->data_obj, fw_mem->data, fw_mem->data_alloc_size); + if (err) + return err; + + if (fw_mem->core_code) { + err = pvr_copy_to_fw(fw_mem->core_code_obj, fw_mem->core_code, + fw_mem->core_code_alloc_size); + if (err) + return err; + } + + if (fw_mem->core_data) { + err = pvr_copy_to_fw(fw_mem->core_data_obj, fw_mem->core_data, + fw_mem->core_data_alloc_size); + if (err) + return err; + } + + return 0; +} + +static void +pvr_fw_cleanup(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + pvr_fw_fini_fwif_connection_ctl(pvr_dev); + if (fw_mem->core_code_obj) + pvr_fw_object_destroy(fw_mem->core_code_obj); + if (fw_mem->core_data_obj) + pvr_fw_object_destroy(fw_mem->core_data_obj); + pvr_fw_object_destroy(fw_mem->code_obj); + pvr_fw_object_destroy(fw_mem->data_obj); +} + +/** + * pvr_wait_for_fw_boot() - Wait for firmware to finish booting + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT if firmware fails to boot within timeout. + */ +int +pvr_wait_for_fw_boot(struct pvr_device *pvr_dev) +{ + ktime_t deadline = ktime_add_us(ktime_get(), FW_BOOT_TIMEOUT_USEC); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + while (ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0) { + if (READ_ONCE(fw_dev->fwif_sysinit->firmware_started)) + return 0; + } + + return -ETIMEDOUT; +} + +/* + * pvr_fw_heap_info_init() - Calculate size and masks for FW heap + * @pvr_dev: Target PowerVR device. + * @log2_size: Log2 of raw heap size. + * @reserved_size: Size of reserved area of heap, in bytes. May be zero. + */ +void +pvr_fw_heap_info_init(struct pvr_device *pvr_dev, u32 log2_size, u32 reserved_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->fw_heap_info.gpu_addr = PVR_ROGUE_FW_MAIN_HEAP_BASE; + fw_dev->fw_heap_info.log2_size = log2_size; + fw_dev->fw_heap_info.reserved_size = reserved_size; + fw_dev->fw_heap_info.raw_size = 1 << fw_dev->fw_heap_info.log2_size; + fw_dev->fw_heap_info.offset_mask = fw_dev->fw_heap_info.raw_size - 1; + fw_dev->fw_heap_info.config_offset = fw_dev->fw_heap_info.raw_size - + PVR_ROGUE_FW_CONFIG_HEAP_SIZE; + fw_dev->fw_heap_info.size = fw_dev->fw_heap_info.raw_size - + (PVR_ROGUE_FW_CONFIG_HEAP_SIZE + reserved_size); +} + /** * pvr_fw_validate_init_device_info() - Validate firmware and initialise device information * @pvr_dev: Target PowerVR device. @@ -143,3 +909,579 @@ pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev) return pvr_fw_get_device_info(pvr_dev); } + +/** + * pvr_fw_init() - Initialise and boot firmware + * @pvr_dev: Target PowerVR device + * + * On successful completion of the function the PowerVR device will be + * initialised and ready to use. + * + * Returns: + * * 0 on success, + * * -%EINVAL on invalid firmware image, + * * -%ENOMEM on out of memory, or + * * -%ETIMEDOUT if firmware processor fails to boot or on register poll timeout. + */ +int +pvr_fw_init(struct pvr_device *pvr_dev) +{ + u32 kccb_size_log2 = ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT; + u32 kccb_rtn_size = (1 << kccb_size_log2) * sizeof(*pvr_dev->kccb.rtn); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + int err; + + if (fw_dev->processor_type == PVR_FW_PROCESSOR_TYPE_META) + fw_dev->defs = &pvr_fw_defs_meta; + else + return -EINVAL; + + err = fw_dev->defs->init(pvr_dev); + if (err) + return err; + + drm_mm_init(&fw_dev->fw_mm, ROGUE_FW_HEAP_BASE, fw_dev->fw_heap_info.raw_size); + fw_dev->fw_mm_base = ROGUE_FW_HEAP_BASE; + spin_lock_init(&fw_dev->fw_mm_lock); + + INIT_LIST_HEAD(&fw_dev->fw_objs.list); + err = drmm_mutex_init(from_pvr_device(pvr_dev), &fw_dev->fw_objs.lock); + if (err) + goto err_mm_takedown; + + err = pvr_fw_process(pvr_dev); + if (err) + goto err_mm_takedown; + + /* Initialise KCCB and FWCCB. */ + err = pvr_kccb_init(pvr_dev); + if (err) + goto err_fw_cleanup; + + err = pvr_fwccb_init(pvr_dev); + if (err) + goto err_kccb_fini; + + /* Allocate memory for KCCB return slots. */ + pvr_dev->kccb.rtn = pvr_fw_object_create_and_map(pvr_dev, kccb_rtn_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_dev->kccb.rtn_obj); + if (IS_ERR(pvr_dev->kccb.rtn)) { + err = PTR_ERR(pvr_dev->kccb.rtn); + goto err_fwccb_fini; + } + + err = pvr_fw_create_structures(pvr_dev); + if (err) + goto err_kccb_rtn_release; + + err = pvr_fw_start(pvr_dev); + if (err) + goto err_destroy_structures; + + err = pvr_wait_for_fw_boot(pvr_dev); + if (err) { + drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); + goto err_fw_stop; + } + + fw_dev->booted = true; + + return 0; + +err_fw_stop: + pvr_fw_stop(pvr_dev); + +err_destroy_structures: + pvr_fw_destroy_structures(pvr_dev); + +err_kccb_rtn_release: + pvr_fw_object_unmap_and_destroy(pvr_dev->kccb.rtn_obj); + +err_fwccb_fini: + pvr_ccb_fini(&pvr_dev->fwccb); + +err_kccb_fini: + pvr_kccb_fini(pvr_dev); + +err_fw_cleanup: + pvr_fw_cleanup(pvr_dev); + +err_mm_takedown: + drm_mm_takedown(&fw_dev->fw_mm); + + if (fw_dev->defs->fini) + fw_dev->defs->fini(pvr_dev); + + return err; +} + +/** + * pvr_fw_fini() - Shutdown firmware processor and free associated memory + * @pvr_dev: Target PowerVR device + */ +void +pvr_fw_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->booted = false; + + pvr_fw_destroy_structures(pvr_dev); + pvr_fw_object_unmap_and_destroy(pvr_dev->kccb.rtn_obj); + + /* + * Ensure FWCCB worker has finished executing before destroying FWCCB. The IRQ handler has + * been unregistered at this point so no new work should be being submitted. + */ + pvr_ccb_fini(&pvr_dev->fwccb); + pvr_kccb_fini(pvr_dev); + pvr_fw_cleanup(pvr_dev); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + WARN_ON(!list_empty(&pvr_dev->fw_dev.fw_objs.list)); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + drm_mm_takedown(&fw_dev->fw_mm); + + if (fw_dev->defs->fini) + fw_dev->defs->fini(pvr_dev); +} + +/** + * pvr_fw_mts_schedule() - Schedule work via an MTS kick + * @pvr_dev: Target PowerVR device + * @val: Kick mask. Should be a combination of %ROGUE_CR_MTS_SCHEDULE_* + */ +void +pvr_fw_mts_schedule(struct pvr_device *pvr_dev, u32 val) +{ + /* Ensure memory is flushed before kicking MTS. */ + wmb(); + + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_SCHEDULE, val); + + /* Ensure the MTS kick goes through before continuing. */ + mb(); +} + +/** + * pvr_fw_structure_cleanup() - Send FW cleanup request for an object + * @pvr_dev: Target PowerVR device. + * @type: Type of object to cleanup. Must be one of &enum rogue_fwif_cleanup_type. + * @fw_obj: Pointer to FW object containing object to cleanup. + * @offset: Offset within FW object of object to cleanup. + * + * Returns: + * * 0 on success, + * * -EBUSY if object is busy, + * * -ETIMEDOUT on timeout, or + * * -EIO if device is lost. + */ +int +pvr_fw_structure_cleanup(struct pvr_device *pvr_dev, u32 type, struct pvr_fw_object *fw_obj, + u32 offset) +{ + struct rogue_fwif_kccb_cmd cmd; + int slot_nr; + int idx; + int err; + u32 rtn; + + struct rogue_fwif_cleanup_request *cleanup_req = &cmd.cmd_data.cleanup_data; + + down_read(&pvr_dev->reset_sem); + + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) { + err = -EIO; + goto err_up_read; + } + + cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_CLEANUP; + cmd.kccb_flags = 0; + cleanup_req->cleanup_type = type; + + switch (type) { + case ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.context_fw_addr); + break; + case ROGUE_FWIF_CLEANUP_HWRTDATA: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.hwrt_data_fw_addr); + break; + case ROGUE_FWIF_CLEANUP_FREELIST: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.freelist_fw_addr); + break; + default: + err = -EINVAL; + goto err_drm_dev_exit; + } + + err = pvr_kccb_send_cmd(pvr_dev, &cmd, &slot_nr); + if (err) + goto err_drm_dev_exit; + + err = pvr_kccb_wait_for_completion(pvr_dev, slot_nr, HZ, &rtn); + if (err) + goto err_drm_dev_exit; + + if (rtn & ROGUE_FWIF_KCCB_RTN_SLOT_CLEANUP_BUSY) + err = -EBUSY; + +err_drm_dev_exit: + drm_dev_exit(idx); + +err_up_read: + up_read(&pvr_dev->reset_sem); + + return err; +} + +/** + * pvr_fw_object_fw_map() - Map a FW object in firmware address space + * @pvr_dev: Device pointer. + * @fw_obj: FW object to map. + * @dev_addr: Desired address in device space, if a specific address is + * required. 0 otherwise. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if @fw_obj is already mapped but has no references, or + * * Any error returned by DRM. + */ +static int +pvr_fw_object_fw_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj, u64 dev_addr) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + int err; + + spin_lock(&fw_dev->fw_mm_lock); + + if (drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + err = -EINVAL; + goto err_unlock; + } + + if (!dev_addr) { + /* + * Allocate from the main heap only (firmware heap minus + * config space). + */ + err = drm_mm_insert_node_in_range(&fw_dev->fw_mm, &fw_obj->fw_mm_node, + gem_obj->size, 0, 0, + fw_dev->fw_heap_info.gpu_addr, + fw_dev->fw_heap_info.gpu_addr + + fw_dev->fw_heap_info.size, 0); + if (err) + goto err_unlock; + } else { + fw_obj->fw_mm_node.start = dev_addr; + fw_obj->fw_mm_node.size = gem_obj->size; + err = drm_mm_reserve_node(&fw_dev->fw_mm, &fw_obj->fw_mm_node); + if (err) + goto err_unlock; + } + + spin_unlock(&fw_dev->fw_mm_lock); + + /* Map object on GPU. */ + err = fw_dev->defs->vm_map(pvr_dev, fw_obj); + if (err) + goto err_remove_node; + + fw_obj->fw_addr_offset = (u32)(fw_obj->fw_mm_node.start - fw_dev->fw_mm_base); + + return 0; + +err_remove_node: + spin_lock(&fw_dev->fw_mm_lock); + drm_mm_remove_node(&fw_obj->fw_mm_node); + +err_unlock: + spin_unlock(&fw_dev->fw_mm_lock); + + return err; +} + +/** + * pvr_fw_object_fw_unmap() - Unmap a previously mapped FW object + * @fw_obj: FW object to unmap. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently mapped. + */ +static int +pvr_fw_object_fw_unmap(struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_device *pvr_dev = to_pvr_device(gem_obj->dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->defs->vm_unmap(pvr_dev, fw_obj); + + spin_lock(&fw_dev->fw_mm_lock); + + if (!drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + spin_unlock(&fw_dev->fw_mm_lock); + return -EINVAL; + } + + drm_mm_remove_node(&fw_obj->fw_mm_node); + + spin_unlock(&fw_dev->fw_mm_lock); + + return 0; +} + +static void * +pvr_fw_object_create_and_map_common(struct pvr_device *pvr_dev, size_t size, + u64 flags, u64 dev_addr, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + struct pvr_fw_object *fw_obj; + void *cpu_ptr; + int err; + + /* %DRM_PVR_BO_PM_FW_PROTECT is implicit for FW objects. */ + flags |= DRM_PVR_BO_PM_FW_PROTECT; + + fw_obj = kzalloc(sizeof(*fw_obj), GFP_KERNEL); + if (!fw_obj) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&fw_obj->node); + fw_obj->init = init; + fw_obj->init_priv = init_priv; + + fw_obj->gem = pvr_gem_object_create(pvr_dev, size, flags); + if (IS_ERR(fw_obj->gem)) { + err = PTR_ERR(fw_obj->gem); + fw_obj->gem = NULL; + goto err_put_object; + } + + err = pvr_fw_object_fw_map(pvr_dev, fw_obj, dev_addr); + if (err) + goto err_put_object; + + cpu_ptr = pvr_fw_object_vmap(fw_obj); + if (IS_ERR(cpu_ptr)) { + err = PTR_ERR(cpu_ptr); + goto err_put_object; + } + + *fw_obj_out = fw_obj; + + if (fw_obj->init) + fw_obj->init(cpu_ptr, fw_obj->init_priv); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + list_add_tail(&fw_obj->node, &pvr_dev->fw_dev.fw_objs.list); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + return cpu_ptr; + +err_put_object: + pvr_fw_object_destroy(fw_obj); + + return ERR_PTR(err); +} + +/** + * pvr_fw_object_create() - Create a FW object and map to firmware + * @pvr_dev: PowerVR device pointer. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_object_create_common(). + */ +int +pvr_fw_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), void *init_priv, + struct pvr_fw_object **fw_obj_out) +{ + void *cpu_ptr; + + cpu_ptr = pvr_fw_object_create_and_map_common(pvr_dev, size, flags, 0, init, init_priv, + fw_obj_out); + if (IS_ERR(cpu_ptr)) + return PTR_ERR(cpu_ptr); + + pvr_fw_object_vunmap(*fw_obj_out); + + return 0; +} + +/** + * pvr_fw_object_create_and_map() - Create a FW object and map to firmware and CPU + * @pvr_dev: PowerVR device pointer. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Caller is responsible for calling pvr_fw_object_vunmap() to release the CPU + * mapping. + * + * Returns: + * * Pointer to CPU mapping of newly created object, or + * * Any error returned by pvr_fw_object_create(), or + * * Any error returned by pvr_fw_object_vmap(). + */ +void * +pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + return pvr_fw_object_create_and_map_common(pvr_dev, size, flags, 0, init, init_priv, + fw_obj_out); +} + +/** + * pvr_fw_object_create_and_map_offset() - Create a FW object and map to + * firmware at the provided offset and to the CPU. + * @pvr_dev: PowerVR device pointer. + * @dev_offset: Base address of desired FW mapping, offset from start of FW heap. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Caller is responsible for calling pvr_fw_object_vunmap() to release the CPU + * mapping. + * + * Returns: + * * Pointer to CPU mapping of newly created object, or + * * Any error returned by pvr_fw_object_create(), or + * * Any error returned by pvr_fw_object_vmap(). + */ +void * +pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, + u32 dev_offset, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + u64 dev_addr = pvr_dev->fw_dev.fw_mm_base + dev_offset; + + return pvr_fw_object_create_and_map_common(pvr_dev, size, flags, dev_addr, init, init_priv, + fw_obj_out); +} + +/** + * pvr_fw_object_destroy() - Destroy a pvr_fw_object + * @fw_obj: Pointer to object to destroy. + */ +void pvr_fw_object_destroy(struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_device *pvr_dev = to_pvr_device(gem_obj->dev); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + list_del(&fw_obj->node); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + if (drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + /* If we can't unmap, leak the memory. */ + if (WARN_ON(pvr_fw_object_fw_unmap(fw_obj))) + return; + } + + if (fw_obj->gem) + pvr_gem_object_put(fw_obj->gem); + + kfree(fw_obj); +} + +/** + * pvr_fw_object_get_fw_addr_offset() - Return address of object in firmware address space, with + * given offset. + * @fw_obj: Pointer to object. + * @offset: Desired offset from start of object. + * @fw_addr_out: Location to store address to. + */ +void pvr_fw_object_get_fw_addr_offset(struct pvr_fw_object *fw_obj, u32 offset, u32 *fw_addr_out) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(pvr_obj)->dev); + + *fw_addr_out = pvr_dev->fw_dev.defs->get_fw_addr_with_offset(fw_obj, offset); +} + +/* + * pvr_fw_hard_reset() - Re-initialise the FW code and data segments, and reset all global FW + * structures + * @pvr_dev: Device pointer + * + * If this function returns an error then the caller must regard the device as lost. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_init_dev_structures() or pvr_fw_reset_all(). + */ +int +pvr_fw_hard_reset(struct pvr_device *pvr_dev) +{ + struct list_head *pos; + int err; + + /* Reset all FW objects */ + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + + list_for_each(pos, &pvr_dev->fw_dev.fw_objs.list) { + struct pvr_fw_object *fw_obj = container_of(pos, struct pvr_fw_object, node); + void *cpu_ptr = pvr_fw_object_vmap(fw_obj); + + WARN_ON(IS_ERR(cpu_ptr)); + + if (!(fw_obj->gem->flags & PVR_BO_FW_NO_CLEAR_ON_RESET)) { + memset(cpu_ptr, 0, pvr_gem_object_size(fw_obj->gem)); + + if (fw_obj->init) + fw_obj->init(cpu_ptr, fw_obj->init_priv); + } + + pvr_fw_object_vunmap(fw_obj); + } + + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + err = pvr_fw_reinit_code_data(pvr_dev); + if (err) + return err; + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h index 8331344e83ea..5cd3ef08d82b 100644 --- a/drivers/gpu/drm/imagination/pvr_fw.h +++ b/drivers/gpu/drm/imagination/pvr_fw.h @@ -5,6 +5,10 @@ #define PVR_FW_H #include "pvr_fw_info.h" +#include "pvr_fw_trace.h" +#include "pvr_gem.h" + +#include #include @@ -12,6 +16,289 @@ struct pvr_device; struct pvr_file; +/* Forward declaration from "pvr_vm.h". */ +struct pvr_vm_context; + +#define ROGUE_FWIF_FWCCB_NUMCMDS_LOG2 5 + +#define ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT 7 + +/** + * struct pvr_fw_object - container for firmware memory allocations + */ +struct pvr_fw_object { + /** @ref_count: FW object reference counter. */ + struct kref ref_count; + + /** @gem: GEM object backing the FW object. */ + struct pvr_gem_object *gem; + + /** + * @fw_mm_node: Node representing mapping in FW address space. @pvr_obj->lock must + * be held when writing. + */ + struct drm_mm_node fw_mm_node; + + /** + * @fw_addr_offset: Virtual address offset of firmware mapping. Only + * valid if @flags has %PVR_GEM_OBJECT_FLAGS_FW_MAPPED + * set. + */ + u32 fw_addr_offset; + + /** + * @init: Initialisation callback. Will be called on object creation and FW hard reset. + * Object will have been zeroed before this is called. + */ + void (*init)(void *cpu_ptr, void *priv); + + /** @init_priv: Private data for initialisation callback. */ + void *init_priv; + + /** @node: Node for firmware object list. */ + struct list_head node; +}; + +/** + * struct pvr_fw_defs - FW processor function table and static definitions + */ +struct pvr_fw_defs { + /** + * @init: + * + * FW processor specific initialisation. + * @pvr_dev: Target PowerVR device. + * + * This function must call pvr_fw_heap_calculate() to initialise the firmware heap for this + * FW processor. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*init)(struct pvr_device *pvr_dev); + + /** + * @fini: + * + * FW processor specific finalisation. + * @pvr_dev: Target PowerVR device. + * + * This function is optional. + */ + void (*fini)(struct pvr_device *pvr_dev); + + /** + * @fw_process: + * + * Load and process firmware image. + * @pvr_dev: Target PowerVR device. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to firmware code section. + * @fw_data_ptr: Pointer to firmware data section. + * @fw_core_code_ptr: Pointer to firmware core code section. May be %NULL. + * @fw_core_data_ptr: Pointer to firmware core data section. May be %NULL. + * @core_code_alloc_size: Total allocation size of core code section. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*fw_process)(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, + u8 *fw_core_data_ptr, u32 core_code_alloc_size); + + /** + * @vm_map: + * + * Map FW object into FW processor address space. + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*vm_map)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + + /** + * @vm_unmap: + * + * Unmap FW object from FW processor address space. + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * This function is mandatory. + */ + void (*vm_unmap)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + + /** + * @get_fw_addr_with_offset: + * + * Called to get address of object in firmware address space, with offset. + * @fw_obj: Pointer to object. + * @offset: Desired offset from start of object. + * + * This function is mandatory. + * + * Returns: + * * Address in firmware address space. + */ + u32 (*get_fw_addr_with_offset)(struct pvr_fw_object *fw_obj, u32 offset); + + /** + * @wrapper_init: + * + * Called to initialise FW wrapper. + * @pvr_dev: Target PowerVR device. + * + * This function is mandatory. + * + * Returns: + * * 0 on success. + * * Any appropriate error on failure. + */ + int (*wrapper_init)(struct pvr_device *pvr_dev); + + /** + * @has_fixed_data_addr: + * + * Called to check if firmware fixed data must be loaded at the address given by the + * firmware layout table. + * + * This function is mandatory. + * + * Returns: + * * %true if firmware fixed data must be loaded at the address given by the firmware + * layout table. + * * %false otherwise. + */ + bool (*has_fixed_data_addr)(void); + + /** + * @irq: FW Interrupt information. + * + * Those are processor dependent, and should be initialized by the + * processor backend in pvr_fw_funcs::init(). + */ + struct { + /** @enable_reg: FW interrupt enable register. */ + u32 enable_reg; + + /** @status_reg: FW interrupt status register. */ + u32 status_reg; + + /** + * @clear_reg: FW interrupt clear register. + * + * If @status_reg == @clear_reg, we clear by write a bit to zero, + * otherwise we clear by writing a bit to one. + */ + u32 clear_reg; + + /** @event_mask: Bitmask of events to listen for. */ + u32 event_mask; + + /** @clear_mask: Value to write to the clear_reg in order to clear FW IRQs. */ + u32 clear_mask; + } irq; +}; + +/** + * struct pvr_fw_mem - FW memory allocations + */ +struct pvr_fw_mem { + /** @code_obj: Object representing firmware code. */ + struct pvr_fw_object *code_obj; + + /** @data_obj: Object representing firmware data. */ + struct pvr_fw_object *data_obj; + + /** + * @core_code_obj: Object representing firmware core code. May be + * %NULL if firmware does not contain this section. + */ + struct pvr_fw_object *core_code_obj; + + /** + * @core_data_obj: Object representing firmware core data. May be + * %NULL if firmware does not contain this section. + */ + struct pvr_fw_object *core_data_obj; + + /** @code: Driver-side copy of firmware code. */ + u8 *code; + + /** @data: Driver-side copy of firmware data. */ + u8 *data; + + /** + * @core_code: Driver-side copy of firmware core code. May be %NULL if firmware does not + * contain this section. + */ + u8 *core_code; + + /** + * @core_data: Driver-side copy of firmware core data. May be %NULL if firmware does not + * contain this section. + */ + u8 *core_data; + + /** @code_alloc_size: Allocation size of firmware code section. */ + u32 code_alloc_size; + + /** @data_alloc_size: Allocation size of firmware data section. */ + u32 data_alloc_size; + + /** @core_code_alloc_size: Allocation size of firmware core code section. */ + u32 core_code_alloc_size; + + /** @core_data_alloc_size: Allocation size of firmware core data section. */ + u32 core_data_alloc_size; + + /** + * @fwif_connection_ctl_obj: Object representing FWIF connection control + * structure. + */ + struct pvr_fw_object *fwif_connection_ctl_obj; + + /** @osinit_obj: Object representing FW OSINIT structure. */ + struct pvr_fw_object *osinit_obj; + + /** @sysinit_obj: Object representing FW SYSINIT structure. */ + struct pvr_fw_object *sysinit_obj; + + /** @osdata_obj: Object representing FW OSDATA structure. */ + struct pvr_fw_object *osdata_obj; + + /** @hwrinfobuf_obj: Object representing FW hwrinfobuf structure. */ + struct pvr_fw_object *hwrinfobuf_obj; + + /** @sysdata_obj: Object representing FW SYSDATA structure. */ + struct pvr_fw_object *sysdata_obj; + + /** @power_sync_obj: Object representing power sync state. */ + struct pvr_fw_object *power_sync_obj; + + /** @fault_page_obj: Object representing FW fault page. */ + struct pvr_fw_object *fault_page_obj; + + /** @gpu_util_fwcb_obj: Object representing FW GPU utilisation control structure. */ + struct pvr_fw_object *gpu_util_fwcb_obj; + + /** @runtime_cfg_obj: Object representing FW runtime config structure. */ + struct pvr_fw_object *runtime_cfg_obj; + + /** @mmucache_sync_obj: Object used as the sync parameter in an MMU cache operation. */ + struct pvr_fw_object *mmucache_sync_obj; +}; + struct pvr_fw_device { /** @firmware: Handle to the firmware loaded into the device. */ const struct firmware *firmware; @@ -22,13 +309,200 @@ struct pvr_fw_device { /** @layout_entries: Pointer to firmware layout. */ const struct pvr_fw_layout_entry *layout_entries; + /** @mem: Structure containing objects representing firmware memory allocations. */ + struct pvr_fw_mem mem; + + /** @booted: %true if the firmware has been booted, %false otherwise. */ + bool booted; + /** * @processor_type: FW processor type for this device. Must be one of * %PVR_FW_PROCESSOR_TYPE_*. */ u16 processor_type; + + /** @funcs: Function table for the FW processor used by this device. */ + const struct pvr_fw_defs *defs; + + /** @processor_data: Pointer to data specific to FW processor. */ + union { + /** @mips_data: Pointer to MIPS-specific data. */ + struct pvr_fw_mips_data *mips_data; + } processor_data; + + /** @fw_heap_info: Firmware heap information. */ + struct { + /** @gpu_addr: Base address of firmware heap in GPU address space. */ + u64 gpu_addr; + + /** @size: Size of main area of heap. */ + u32 size; + + /** @offset_mask: Mask for offsets within FW heap. */ + u32 offset_mask; + + /** @raw_size: Raw size of heap, including reserved areas. */ + u32 raw_size; + + /** @log2_size: Log2 of raw size of heap. */ + u32 log2_size; + + /** @config_offset: Offset of config area within heap. */ + u32 config_offset; + + /** @reserved_size: Size of reserved area in heap. */ + u32 reserved_size; + } fw_heap_info; + + /** @fw_mm: Firmware address space allocator. */ + struct drm_mm fw_mm; + + /** @fw_mm_lock: Lock protecting access to &fw_mm. */ + spinlock_t fw_mm_lock; + + /** @fw_mm_base: Base address of address space managed by @fw_mm. */ + u64 fw_mm_base; + + /** + * @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection + * control structure. + */ + struct rogue_fwif_connection_ctl *fwif_connection_ctl; + + /** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */ + struct rogue_fwif_sysinit *fwif_sysinit; + + /** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */ + struct rogue_fwif_sysdata *fwif_sysdata; + + /** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */ + struct rogue_fwif_osinit *fwif_osinit; + + /** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */ + struct rogue_fwif_osdata *fwif_osdata; + + /** @power_sync: Pointer to CPU mapping of power sync state. */ + u32 *power_sync; + + /** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */ + struct rogue_fwif_hwrinfobuf *hwrinfobuf; + + /** @fw_trace: Device firmware trace buffer state. */ + struct pvr_fw_trace fw_trace; + + /** @fw_objs: Structure tracking FW objects. */ + struct { + /** @list: Head of FW object list. */ + struct list_head list; + + /** @lock: Lock protecting access to FW object list. */ + struct mutex lock; + } fw_objs; }; +#define pvr_fw_irq_read_reg(pvr_dev, name) \ + pvr_cr_read32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg) + +#define pvr_fw_irq_write_reg(pvr_dev, name, value) \ + pvr_cr_write32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg, value) + +#define pvr_fw_irq_pending(pvr_dev) \ + (pvr_fw_irq_read_reg(pvr_dev, status) & (pvr_dev)->fw_dev.defs->irq.event_mask) + +#define pvr_fw_irq_clear(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, clear, (pvr_dev)->fw_dev.defs->irq.clear_mask) + +#define pvr_fw_irq_enable(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, enable, (pvr_dev)->fw_dev.defs->irq.event_mask) + +#define pvr_fw_irq_disable(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, enable, 0) + +extern const struct pvr_fw_defs pvr_fw_defs_meta; +extern const struct pvr_fw_defs pvr_fw_defs_mips; + int pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev); +int pvr_fw_init(struct pvr_device *pvr_dev); +void pvr_fw_fini(struct pvr_device *pvr_dev); + +int pvr_wait_for_fw_boot(struct pvr_device *pvr_dev); + +int +pvr_fw_hard_reset(struct pvr_device *pvr_dev); + +void pvr_fw_mts_schedule(struct pvr_device *pvr_dev, u32 val); + +void +pvr_fw_heap_info_init(struct pvr_device *pvr_dev, u32 log2_size, u32 reserved_size); + +const struct pvr_fw_layout_entry * +pvr_fw_find_layout_entry(struct pvr_device *pvr_dev, enum pvr_fw_section_id id); +int +pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr, + void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr, + void **host_addr_out); + +int +pvr_fw_structure_cleanup(struct pvr_device *pvr_dev, u32 type, struct pvr_fw_object *fw_obj, + u32 offset); + +int pvr_fw_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), void *init_priv, + struct pvr_fw_object **pvr_obj_out); + +void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **pvr_obj_out); + +void * +pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size, + u64 flags, void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **pvr_obj_out); + +static __always_inline void * +pvr_fw_object_vmap(struct pvr_fw_object *fw_obj) +{ + return pvr_gem_object_vmap(fw_obj->gem); +} + +static __always_inline void +pvr_fw_object_vunmap(struct pvr_fw_object *fw_obj) +{ + pvr_gem_object_vunmap(fw_obj->gem); +} + +void pvr_fw_object_destroy(struct pvr_fw_object *fw_obj); + +static __always_inline void +pvr_fw_object_unmap_and_destroy(struct pvr_fw_object *fw_obj) +{ + pvr_fw_object_vunmap(fw_obj); + pvr_fw_object_destroy(fw_obj); +} + +/** + * pvr_fw_get_dma_addr() - Get DMA address for given offset in firmware object + * @fw_obj: Pointer to object to lookup address in. + * @offset: Offset within object to lookup address at. + * @dma_addr_out: Pointer to location to store DMA address. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently backed, or if @offset is out of valid + * range for this object. + */ +static __always_inline int +pvr_fw_object_get_dma_addr(struct pvr_fw_object *fw_obj, u32 offset, dma_addr_t *dma_addr_out) +{ + return pvr_gem_get_dma_addr(fw_obj->gem, offset, dma_addr_out); +} + +void pvr_fw_object_get_fw_addr_offset(struct pvr_fw_object *fw_obj, u32 offset, u32 *fw_addr_out); + +static __always_inline void +pvr_fw_object_get_fw_addr(struct pvr_fw_object *fw_obj, u32 *fw_addr_out) +{ + pvr_fw_object_get_fw_addr_offset(fw_obj, 0, fw_addr_out); +} #endif /* PVR_FW_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.c b/drivers/gpu/drm/imagination/pvr_fw_meta.c new file mode 100644 index 000000000000..119934c36184 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_meta.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_info.h" +#include "pvr_gem.h" +#include "pvr_rogue_cr_defs.h" +#include "pvr_rogue_meta.h" +#include "pvr_vm.h" + +#include +#include +#include +#include +#include + +#define ROGUE_FW_HEAP_META_SHIFT 25 /* 32 MB */ + +#define POLL_TIMEOUT_USEC 1000000 + +/** + * pvr_meta_cr_read32() - Read a META register via the Slave Port + * @pvr_dev: Device pointer. + * @reg_addr: Address of register to read. + * @reg_value_out: Pointer to location to store register value. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_cr_poll_reg32(). + */ +int +pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out) +{ + int err; + + /* Wait for Slave Port to be Ready. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL1, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + + /* Issue a Read. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0, + reg_addr | ROGUE_CR_META_SP_MSLVCTRL0_RD_EN); + (void)pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0); /* Fence write. */ + + /* Wait for Slave Port to be Ready. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL1, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + + *reg_value_out = pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVDATAX); + + return 0; +} + +static int +pvr_meta_wrapper_init(struct pvr_device *pvr_dev) +{ + u64 garten_config; + + /* Configure META to Master boot. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_META_BOOT, ROGUE_CR_META_BOOT_MODE_EN); + + /* Set Garten IDLE to META idle and Set the Garten Wrapper BIF Fence address. */ + + /* Garten IDLE bit controlled by META. */ + garten_config = ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META; + + /* The fence addr is set during the fw init sequence. */ + + /* Set PC = 0 for fences. */ + garten_config &= + ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_CLRMSK; + garten_config |= + (u64)MMU_CONTEXT_MAPPING_FWPRIV + << ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_SHIFT; + + /* Set SLC DM=META. */ + garten_config |= ((u64)ROGUE_FW_SEGMMU_META_BIFDM_ID) + << ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_SHIFT; + + pvr_cr_write64(pvr_dev, ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG, garten_config); + + return 0; +} + +static __always_inline void +add_boot_arg(u32 **boot_conf, u32 param, u32 data) +{ + *(*boot_conf)++ = param; + *(*boot_conf)++ = data; +} + +static int +meta_ldr_cmd_loadmem(struct drm_device *drm_dev, const u8 *fw, + struct rogue_meta_ldr_l1_data_blk *l1_data, u32 coremem_size, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, const u32 fw_size) +{ + struct rogue_meta_ldr_l2_data_blk *l2_block = + (struct rogue_meta_ldr_l2_data_blk *)(fw + + l1_data->cmd_data[1]); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + u32 offset = l1_data->cmd_data[0]; + u32 data_size; + void *write_addr; + int err; + + /* Verify header is within bounds. */ + if (((u8 *)l2_block - fw) >= fw_size || ((u8 *)(l2_block + 1) - fw) >= fw_size) + return -EINVAL; + + data_size = l2_block->length - 6 /* L2 Tag length and checksum */; + + /* Verify data is within bounds. */ + if (((u8 *)l2_block->block_data - fw) >= fw_size || + ((((u8 *)l2_block->block_data) + data_size) - fw) >= fw_size) + return -EINVAL; + + if (!ROGUE_META_IS_COREMEM_CODE(offset, coremem_size) && + !ROGUE_META_IS_COREMEM_DATA(offset, coremem_size)) { + /* Global range is aliased to local range */ + offset &= ~META_MEM_GLOBAL_RANGE_BIT; + } + + err = pvr_fw_find_mmu_segment(pvr_dev, offset, data_size, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + offset, data_size); + return err; + } + + memcpy(write_addr, l2_block->block_data, data_size); + + return 0; +} + +static int +meta_ldr_cmd_zeromem(struct drm_device *drm_dev, + struct rogue_meta_ldr_l1_data_blk *l1_data, u32 coremem_size, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + u32 offset = l1_data->cmd_data[0]; + u32 byte_count = l1_data->cmd_data[1]; + void *write_addr; + int err; + + if (ROGUE_META_IS_COREMEM_DATA(offset, coremem_size)) { + /* cannot zero coremem directly */ + return 0; + } + + /* Global range is aliased to local range */ + offset &= ~META_MEM_GLOBAL_RANGE_BIT; + + err = pvr_fw_find_mmu_segment(pvr_dev, offset, byte_count, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + offset, byte_count); + return err; + } + + memset(write_addr, 0, byte_count); + + return 0; +} + +static int +meta_ldr_cmd_config(struct drm_device *drm_dev, const u8 *fw, + struct rogue_meta_ldr_l1_data_blk *l1_data, + const u32 fw_size, u32 **boot_conf_ptr) +{ + struct rogue_meta_ldr_l2_data_blk *l2_block = + (struct rogue_meta_ldr_l2_data_blk *)(fw + + l1_data->cmd_data[0]); + struct rogue_meta_ldr_cfg_blk *config_command; + u32 l2_block_size; + u32 curr_block_size = 0; + u32 *boot_conf = boot_conf_ptr ? *boot_conf_ptr : NULL; + + /* Verify block header is within bounds. */ + if (((u8 *)l2_block - fw) >= fw_size || ((u8 *)(l2_block + 1) - fw) >= fw_size) + return -EINVAL; + + l2_block_size = l2_block->length - 6 /* L2 Tag length and checksum */; + config_command = (struct rogue_meta_ldr_cfg_blk *)l2_block->block_data; + + if (((u8 *)config_command - fw) >= fw_size || + ((((u8 *)config_command) + l2_block_size) - fw) >= fw_size) + return -EINVAL; + + while (l2_block_size >= 12) { + if (config_command->type != ROGUE_META_LDR_CFG_WRITE) + return -EINVAL; + + /* + * Only write to bootloader if we got a valid pointer to the FW + * code allocation. + */ + if (boot_conf) { + u32 register_offset = config_command->block_data[0]; + u32 register_value = config_command->block_data[1]; + + /* Do register write */ + add_boot_arg(&boot_conf, register_offset, + register_value); + } + + curr_block_size = 12; + l2_block_size -= curr_block_size; + config_command = (struct rogue_meta_ldr_cfg_blk + *)((uintptr_t)config_command + + curr_block_size); + } + + if (boot_conf_ptr) + *boot_conf_ptr = boot_conf; + + return 0; +} + +/** + * process_ldr_command_stream() - Process LDR firmware image and populate + * firmware sections + * @pvr_dev: Device pointer. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to FW code section. + * @fw_data_ptr: Pointer to FW data section. + * @fw_core_code_ptr: Pointer to FW coremem code section. + * @fw_core_data_ptr: Pointer to FW coremem data section. + * @boot_conf_ptr: Pointer to boot config argument pointer. + * + * Returns : + * * 0 on success, or + * * -EINVAL on any error in LDR command stream. + */ +static int +process_ldr_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, + u8 *fw_core_data_ptr, u32 **boot_conf_ptr) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct rogue_meta_ldr_block_hdr *ldr_header = + (struct rogue_meta_ldr_block_hdr *)fw; + struct rogue_meta_ldr_l1_data_blk *l1_data = + (struct rogue_meta_ldr_l1_data_blk *)(fw + ldr_header->sl_data); + const u32 fw_size = pvr_dev->fw_dev.firmware->size; + int err; + + u32 *boot_conf = boot_conf_ptr ? *boot_conf_ptr : NULL; + u32 coremem_size; + + err = PVR_FEATURE_VALUE(pvr_dev, meta_coremem_size, &coremem_size); + if (err) + return err; + + coremem_size *= SZ_1K; + + while (l1_data) { + /* Verify block header is within bounds. */ + if (((u8 *)l1_data - fw) >= fw_size || ((u8 *)(l1_data + 1) - fw) >= fw_size) + return -EINVAL; + + if (ROGUE_META_LDR_BLK_IS_COMMENT(l1_data->cmd)) { + /* Don't process comment blocks */ + goto next_block; + } + + switch (l1_data->cmd & ROGUE_META_LDR_CMD_MASK) + case ROGUE_META_LDR_CMD_LOADMEM: { + err = meta_ldr_cmd_loadmem(drm_dev, fw, l1_data, + coremem_size, + fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, + fw_core_data_ptr, fw_size); + if (err) + return err; + break; + + case ROGUE_META_LDR_CMD_START_THREADS: + /* Don't process this block */ + break; + + case ROGUE_META_LDR_CMD_ZEROMEM: + err = meta_ldr_cmd_zeromem(drm_dev, l1_data, + coremem_size, + fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, + fw_core_data_ptr); + if (err) + return err; + break; + + case ROGUE_META_LDR_CMD_CONFIG: + err = meta_ldr_cmd_config(drm_dev, fw, l1_data, fw_size, + &boot_conf); + if (err) + return err; + break; + + default: + return -EINVAL; + } + +next_block: + if (l1_data->next == 0xFFFFFFFF) + break; + + l1_data = (struct rogue_meta_ldr_l1_data_blk *)(fw + + l1_data->next); + } + + if (boot_conf_ptr) + *boot_conf_ptr = boot_conf; + + return 0; +} + +static void +configure_seg_id(u64 seg_out_addr, u32 seg_base, u32 seg_limit, u32 seg_id, + u32 **boot_conf_ptr) +{ + u32 seg_out_addr0 = seg_out_addr & 0x00000000FFFFFFFFUL; + u32 seg_out_addr1 = (seg_out_addr >> 32) & 0x00000000FFFFFFFFUL; + u32 *boot_conf = *boot_conf_ptr; + + /* META segments have a minimum size. */ + u32 limit_off = max(seg_limit, ROGUE_FW_SEGMMU_ALIGN); + + /* The limit is an offset, therefore off = size - 1. */ + limit_off -= 1; + + seg_base |= ROGUE_FW_SEGMMU_ALLTHRS_WRITEABLE; + + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_BASE(seg_id), seg_base); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_LIMIT(seg_id), limit_off); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_OUTA0(seg_id), seg_out_addr0); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_OUTA1(seg_id), seg_out_addr1); + + *boot_conf_ptr = boot_conf; +} + +static u64 get_fw_obj_gpu_addr(struct pvr_fw_object *fw_obj) +{ + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(fw_obj->gem)->dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + return fw_obj->fw_addr_offset + fw_dev->fw_heap_info.gpu_addr; +} + +static void +configure_seg_mmu(struct pvr_device *pvr_dev, u32 **boot_conf_ptr) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u64 seg_out_addr_top; + u32 i; + + seg_out_addr_top = + ROGUE_FW_SEGMMU_OUTADDR_TOP_SLC(MMU_CONTEXT_MAPPING_FWPRIV, + ROGUE_FW_SEGMMU_META_BIFDM_ID); + + for (i = 0; i < num_layout_entries; i++) { + /* + * FW code is using the bootloader segment which is already + * configured on boot. FW coremem code and data don't use the + * segment MMU. Only the FW data segment needs to be configured. + */ + if (layout_entries[i].type == FW_DATA) { + u32 seg_id = ROGUE_FW_SEGMMU_DATA_ID; + u64 seg_out_addr = get_fw_obj_gpu_addr(pvr_dev->fw_dev.mem.data_obj); + + seg_out_addr += layout_entries[i].alloc_offset; + seg_out_addr |= seg_out_addr_top; + + /* Write the sequence to the bootldr. */ + configure_seg_id(seg_out_addr, + layout_entries[i].base_addr, + layout_entries[i].alloc_size, seg_id, + boot_conf_ptr); + + break; + } + } +} + +static void +configure_meta_caches(u32 **boot_conf_ptr) +{ + u32 *boot_conf = *boot_conf_ptr; + u32 d_cache_t0, i_cache_t0; + u32 d_cache_t1, i_cache_t1; + u32 d_cache_t2, i_cache_t2; + u32 d_cache_t3, i_cache_t3; + + /* Initialise I/Dcache settings */ + d_cache_t0 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t1 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t2 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t3 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + i_cache_t0 = 0; + i_cache_t1 = 0; + i_cache_t2 = 0; + i_cache_t3 = 0; + + d_cache_t0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE; + i_cache_t0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE; + + /* Local region MMU enhanced bypass: WIN-3 mode for code and data caches */ + add_boot_arg(&boot_conf, META_CR_MMCU_LOCAL_EBCTRL, + META_CR_MMCU_LOCAL_EBCTRL_ICWIN | + META_CR_MMCU_LOCAL_EBCTRL_DCWIN); + + /* Data cache partitioning thread 0 to 3 */ + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(0), d_cache_t0); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(1), d_cache_t1); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(2), d_cache_t2); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(3), d_cache_t3); + + /* Enable data cache hits */ + add_boot_arg(&boot_conf, META_CR_MMCU_DCACHE_CTRL, + META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN); + + /* Instruction cache partitioning thread 0 to 3 */ + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(0), i_cache_t0); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(1), i_cache_t1); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(2), i_cache_t2); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(3), i_cache_t3); + + /* Enable instruction cache hits */ + add_boot_arg(&boot_conf, META_CR_MMCU_ICACHE_CTRL, + META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN); + + add_boot_arg(&boot_conf, 0x040000C0, 0); + + *boot_conf_ptr = boot_conf; +} + +static int +pvr_meta_fw_process(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, + u32 core_code_alloc_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + u32 *boot_conf; + int err; + + boot_conf = ((u32 *)fw_code_ptr) + ROGUE_FW_BOOTLDR_CONF_OFFSET; + + /* Slave port and JTAG accesses are privileged. */ + add_boot_arg(&boot_conf, META_CR_SYSC_JTAG_THREAD, + META_CR_SYSC_JTAG_THREAD_PRIV_EN); + + configure_seg_mmu(pvr_dev, &boot_conf); + + /* Populate FW sections from LDR image. */ + err = process_ldr_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, fw_core_code_ptr, + fw_core_data_ptr, &boot_conf); + if (err) + return err; + + configure_meta_caches(&boot_conf); + + /* End argument list. */ + add_boot_arg(&boot_conf, 0, 0); + + if (fw_dev->mem.core_code_obj) { + u32 core_code_fw_addr; + + pvr_fw_object_get_fw_addr(fw_dev->mem.core_code_obj, &core_code_fw_addr); + add_boot_arg(&boot_conf, core_code_fw_addr, core_code_alloc_size); + } else { + add_boot_arg(&boot_conf, 0, 0); + } + /* None of the cores supported by this driver have META DMA. */ + add_boot_arg(&boot_conf, 0, 0); + + return 0; +} + +static int +pvr_meta_init(struct pvr_device *pvr_dev) +{ + pvr_fw_heap_info_init(pvr_dev, ROGUE_FW_HEAP_META_SHIFT, 0); + + return 0; +} + +static u32 +pvr_meta_get_fw_addr_with_offset(struct pvr_fw_object *fw_obj, u32 offset) +{ + u32 fw_addr = fw_obj->fw_addr_offset + offset + ROGUE_FW_SEGMMU_DATA_BASE_ADDRESS; + + /* META cacheability is determined by address. */ + if (fw_obj->gem->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED) + fw_addr |= ROGUE_FW_SEGMMU_DATA_META_UNCACHED | + ROGUE_FW_SEGMMU_DATA_VIVT_SLC_UNCACHED; + + return fw_addr; +} + +static int +pvr_meta_vm_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + + return pvr_vm_map(pvr_dev->kernel_vm_ctx, pvr_obj, 0, fw_obj->fw_mm_node.start, + pvr_gem_object_size(pvr_obj)); +} + +static void +pvr_meta_vm_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + pvr_vm_unmap(pvr_dev->kernel_vm_ctx, fw_obj->fw_mm_node.start, + fw_obj->fw_mm_node.size); +} + +static bool +pvr_meta_has_fixed_data_addr(void) +{ + return false; +} + +const struct pvr_fw_defs pvr_fw_defs_meta = { + .init = pvr_meta_init, + .fw_process = pvr_meta_fw_process, + .vm_map = pvr_meta_vm_map, + .vm_unmap = pvr_meta_vm_unmap, + .get_fw_addr_with_offset = pvr_meta_get_fw_addr_with_offset, + .wrapper_init = pvr_meta_wrapper_init, + .has_fixed_data_addr = pvr_meta_has_fixed_data_addr, + .irq = { + .enable_reg = ROGUE_CR_META_SP_MSLVIRQENABLE, + .status_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, + .clear_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, + .event_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN, + .clear_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK, + }, +}; diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.h b/drivers/gpu/drm/imagination/pvr_fw_meta.h new file mode 100644 index 000000000000..911ad700cba6 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_meta.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_META_H +#define PVR_FW_META_H + +#include + +/* Forward declaration from pvr_device.h */ +struct pvr_device; + +int pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out); + +#endif /* PVR_FW_META_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.c b/drivers/gpu/drm/imagination/pvr_fw_startstop.c new file mode 100644 index 000000000000..36cec227cfe3 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_meta.h" +#include "pvr_fw_startstop.h" +#include "pvr_rogue_cr_defs.h" +#include "pvr_rogue_meta.h" +#include "pvr_vm.h" + +#include +#include +#include +#include + +#define POLL_TIMEOUT_USEC 1000000 + +static void +rogue_axi_ace_list_init(struct pvr_device *pvr_dev) +{ + /* Setup AXI-ACE config. Set everything to outer cache. */ + u64 reg_val = + (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_SHIFT) | + (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_SHIFT); + + pvr_cr_write64(pvr_dev, ROGUE_CR_AXI_ACE_LITE_CONFIGURATION, reg_val); +} + +static void +rogue_bif_init(struct pvr_device *pvr_dev) +{ + dma_addr_t pc_dma_addr; + u64 pc_addr; + + /* Acquire the address of the Kernel Page Catalogue. */ + pc_dma_addr = pvr_vm_get_page_table_root_addr(pvr_dev->kernel_vm_ctx); + + /* Write the kernel catalogue base. */ + pc_addr = ((((u64)pc_dma_addr >> ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSHIFT) + << ROGUE_CR_BIF_CAT_BASE0_ADDR_SHIFT) & + ~ROGUE_CR_BIF_CAT_BASE0_ADDR_CLRMSK); + + pvr_cr_write64(pvr_dev, BIF_CAT_BASEX(MMU_CONTEXT_MAPPING_FWPRIV), + pc_addr); +} + +static int +rogue_slc_init(struct pvr_device *pvr_dev) +{ + u16 slc_cache_line_size_bits; + u32 reg_val; + int err; + + /* + * SLC Misc control. + * + * Note: This is a 64bit register and we set only the lower 32bits + * leaving the top 32bits (ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS) + * unchanged from the HW default. + */ + reg_val = (pvr_cr_read32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC) & + ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_EN) | + ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH1; + + err = PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, &slc_cache_line_size_bits); + if (err) + return err; + + /* Bypass burst combiner if SLC line size is smaller than 1024 bits. */ + if (slc_cache_line_size_bits < 1024) + reg_val |= ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_EN; + + if (PVR_HAS_QUIRK(pvr_dev, 71242) && !PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support)) + reg_val |= ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_EN; + + pvr_cr_write32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC, reg_val); + + return 0; +} + +/** + * pvr_fw_start() - Start FW processor and boot firmware + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * Any error returned by rogue_slc_init(). + */ +int +pvr_fw_start(struct pvr_device *pvr_dev) +{ + bool has_reset2 = PVR_HAS_FEATURE(pvr_dev, xe_tpu2); + u64 soft_reset_mask; + int err; + + if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe)) + soft_reset_mask = ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL; + else + soft_reset_mask = ROGUE_CR_SOFT_RESET_MASKFULL; + + if (PVR_HAS_FEATURE(pvr_dev, sys_bus_secure_reset)) { + /* + * Disable the default sys_bus_secure protection to perform + * minimal setup. + */ + pvr_cr_write32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE, 0); + (void)pvr_cr_read32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE); /* Fence write */ + } + + /* Set Rogue in soft-reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, ROGUE_CR_SOFT_RESET2_MASKFULL); + + /* Read soft-reset to fence previous write in order to clear the SOCIF pipeline. */ + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + /* Take Rascal and Dust out of reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, + soft_reset_mask ^ ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0); + + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + /* Take everything out of reset but the FW processor. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_GARTEN_EN); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0); + + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + err = rogue_slc_init(pvr_dev); + if (err) + goto err_reset; + + /* Initialise Firmware wrapper. */ + pvr_dev->fw_dev.defs->wrapper_init(pvr_dev); + + /* We must init the AXI-ACE interface before first BIF transaction. */ + rogue_axi_ace_list_init(pvr_dev); + + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + /* Initialise BIF. */ + rogue_bif_init(pvr_dev); + } + + /* Need to wait for at least 16 cycles before taking the FW processor out of reset ... */ + udelay(3); + + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, 0x0); + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + + /* ... and afterwards. */ + udelay(3); + + return 0; + +err_reset: + /* Put everything back into soft-reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask); + + return err; +} + +/** + * pvr_fw_stop() - Stop FW processor + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_cr_poll_reg32(). + */ +int +pvr_fw_stop(struct pvr_device *pvr_dev) +{ + const u32 sidekick_idle_mask = ROGUE_CR_SIDEKICK_IDLE_MASKFULL & + ~(ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN | + ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN | + ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN); + bool skip_garten_idle = false; + u32 reg_value; + int err; + + /* + * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. + * For cores with the LAYOUT_MARS feature, SIDEKICK would have been + * powered down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + + /* Unset MTS DM association with threads. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC, + ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC, + ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + + /* Extra Idle checks. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_STATUS_MMU, 0, + ROGUE_CR_BIF_STATUS_MMU_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_STATUS_MMU, 0, + ROGUE_CR_BIFPM_STATUS_MMU_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + if (!PVR_HAS_FEATURE(pvr_dev, xt_top_infrastructure)) { + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_READS_EXT_STATUS, 0, + ROGUE_CR_BIF_READS_EXT_STATUS_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + } + + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_READS_EXT_STATUS, 0, + ROGUE_CR_BIFPM_READS_EXT_STATUS_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + err = pvr_cr_poll_reg64(pvr_dev, ROGUE_CR_SLC_STATUS1, 0, + ROGUE_CR_SLC_STATUS1_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + /* + * Wait for SLC to signal IDLE. + * For cores with the LAYOUT_MARS feature, SLC would have been powered + * down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE, + ROGUE_CR_SLC_IDLE_MASKFULL, + ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC); + if (err) + return err; + + /* + * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. + * For cores with the LAYOUT_MARS feature, SIDEKICK would have been powered + * down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + + if (pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_META) { + err = pvr_meta_cr_read32(pvr_dev, META_CR_TxVECINT_BHALT, ®_value); + if (err) + return err; + + /* + * Wait for Sidekick/Jones to signal IDLE including the Garten + * Wrapper if there is no debugger attached (TxVECINT_BHALT = + * 0x0). + */ + if (reg_value) + skip_garten_idle = true; + } + + if (!skip_garten_idle) { + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + } + + if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe)) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, + ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL); + else + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_MASKFULL); + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.h b/drivers/gpu/drm/imagination/pvr_fw_startstop.h new file mode 100644 index 000000000000..a3cef061bd60 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_STARTSTOP_H +#define PVR_FW_STARTSTOP_H + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +int pvr_fw_start(struct pvr_device *pvr_dev); +int pvr_fw_stop(struct pvr_device *pvr_dev); + +#endif /* PVR_FW_STARTSTOP_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c new file mode 100644 index 000000000000..0a8340369f1a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_rogue_fwif.h" +#include "pvr_fw_trace.h" + +#include + +#include +#include +#include +#include + +static void +tracebuf_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr; + struct pvr_fw_trace *fw_trace = priv; + u32 thread_nr; + + tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; + tracebuf_ctrl->tracebuf_flags = 0; + + if (fw_trace->group_mask) + tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE; + else + tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct rogue_fwif_tracebuf_space *tracebuf_space = + &tracebuf_ctrl->tracebuf[thread_nr]; + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + pvr_fw_object_get_fw_addr(trace_buffer->buf_obj, + &tracebuf_space->trace_buffer_fw_addr); + + tracebuf_space->trace_buffer = trace_buffer->buf; + tracebuf_space->trace_pointer = 0; + } +} + +int pvr_fw_trace_init(struct pvr_device *pvr_dev) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u32 thread_nr; + int err; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + trace_buffer->buf = + pvr_fw_object_create_and_map(pvr_dev, + ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * + sizeof(*trace_buffer->buf), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED | + PVR_BO_FW_NO_CLEAR_ON_RESET, + NULL, NULL, &trace_buffer->buf_obj); + if (IS_ERR(trace_buffer->buf)) { + drm_err(drm_dev, "Unable to allocate trace buffer\n"); + err = PTR_ERR(trace_buffer->buf); + trace_buffer->buf = NULL; + goto err_free_buf; + } + } + + /* TODO: Provide control of group mask. */ + fw_trace->group_mask = 0; + + fw_trace->tracebuf_ctrl = + pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_trace->tracebuf_ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED | + PVR_BO_FW_NO_CLEAR_ON_RESET, + tracebuf_ctrl_init, fw_trace, + &fw_trace->tracebuf_ctrl_obj); + if (IS_ERR(fw_trace->tracebuf_ctrl)) { + drm_err(drm_dev, "Unable to allocate trace buffer control structure\n"); + err = PTR_ERR(fw_trace->tracebuf_ctrl); + goto err_free_buf; + } + + BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) != + ARRAY_SIZE(fw_trace->buffers)); + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct rogue_fwif_tracebuf_space *tracebuf_space = + &fw_trace->tracebuf_ctrl->tracebuf[thread_nr]; + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + trace_buffer->tracebuf_space = tracebuf_space; + } + + return 0; + +err_free_buf: + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + if (trace_buffer->buf) + pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); + } + + return err; +} + +void pvr_fw_trace_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + u32 thread_nr; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); + } + pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj); +} diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.h b/drivers/gpu/drm/imagination/pvr_fw_trace.h new file mode 100644 index 000000000000..0074d2b18da0 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_TRACE_H +#define PVR_FW_TRACE_H + +#include +#include + +#include "pvr_rogue_fwif.h" + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declarations from pvr_rogue_fwif.h */ +struct rogue_fwif_tracebuf; +struct rogue_fwif_tracebuf_space; + +/** + * struct pvr_fw_trace_buffer - Structure representing a trace buffer + */ +struct pvr_fw_trace_buffer { + /** @buf_obj: FW buffer object representing trace buffer. */ + struct pvr_fw_object *buf_obj; + + /** @buf: Pointer to CPU mapping of trace buffer. */ + u32 *buf; + + /** + * @tracebuf_space: Pointer to FW tracebuf_space structure for this + * trace buffer. + */ + struct rogue_fwif_tracebuf_space *tracebuf_space; +}; + +/** + * struct pvr_fw_trace - Device firmware trace data + */ +struct pvr_fw_trace { + /** + * @tracebuf_ctrl_obj: Object representing FW trace buffer control + * structure. + */ + struct pvr_fw_object *tracebuf_ctrl_obj; + + /** + * @tracebuf_ctrl: Pointer to CPU mapping of FW trace buffer control + * structure. + */ + struct rogue_fwif_tracebuf *tracebuf_ctrl; + + /** + * @buffers: Array representing the actual trace buffers owned by this + * device. + */ + struct pvr_fw_trace_buffer buffers[ROGUE_FW_THREAD_MAX]; + + /** @group_mask: Mask of enabled trace groups. */ + u32 group_mask; +}; + +int pvr_fw_trace_init(struct pvr_device *pvr_dev); +void pvr_fw_trace_fini(struct pvr_device *pvr_dev); + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from . */ +struct dentry; + +void pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, + u32 new_mask); + +void pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir); +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_FW_TRACE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c index 7f77e03df912..b71d30e5f380 100644 --- a/drivers/gpu/drm/imagination/pvr_mmu.c +++ b/drivers/gpu/drm/imagination/pvr_mmu.c @@ -3,9 +3,11 @@ #include "pvr_mmu.h" +#include "pvr_ccb.h" #include "pvr_device.h" #include "pvr_fw.h" #include "pvr_gem.h" +#include "pvr_power.h" #include "pvr_rogue_fwif.h" #include "pvr_rogue_mmu_defs.h" @@ -95,7 +97,7 @@ static void pvr_mmu_set_flush_flags(struct pvr_device *pvr_dev, u32 flags) */ void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev) { - /* TODO: implement */ + pvr_mmu_set_flush_flags(pvr_dev, PVR_MMU_SYNC_LEVEL_2_FLAGS); } /** @@ -120,8 +122,70 @@ void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev) */ int pvr_mmu_flush_exec(struct pvr_device *pvr_dev, bool wait) { - /* TODO: implement */ - return -ENODEV; + struct rogue_fwif_kccb_cmd cmd_mmu_cache = {}; + struct rogue_fwif_mmucachedata *cmd_mmu_cache_data = + &cmd_mmu_cache.cmd_data.mmu_cache_data; + int err = 0; + u32 slot; + int idx; + + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) + return -EIO; + + /* Can't flush MMU if the firmware hasn't booted yet. */ + if (!pvr_dev->fw_dev.booted) + goto err_drm_dev_exit; + + cmd_mmu_cache_data->cache_flags = + atomic_xchg(&pvr_dev->mmu_flush_cache_flags, 0); + + if (!cmd_mmu_cache_data->cache_flags) + goto err_drm_dev_exit; + + cmd_mmu_cache.cmd_type = ROGUE_FWIF_KCCB_CMD_MMUCACHE; + + pvr_fw_object_get_fw_addr(pvr_dev->fw_dev.mem.mmucache_sync_obj, + &cmd_mmu_cache_data->mmu_cache_sync_fw_addr); + cmd_mmu_cache_data->mmu_cache_sync_update_value = 0; + + err = pvr_kccb_send_cmd(pvr_dev, &cmd_mmu_cache, &slot); + if (err) + goto err_reset_and_retry; + + err = pvr_kccb_wait_for_completion(pvr_dev, slot, HZ, NULL); + if (err) + goto err_reset_and_retry; + + drm_dev_exit(idx); + + return 0; + +err_reset_and_retry: + /* + * Flush command failure is most likely the result of a firmware lockup. Hard + * reset the GPU and retry. + */ + err = pvr_power_reset(pvr_dev, true); + if (err) + goto err_drm_dev_exit; /* Device is lost. */ + + /* Retry sending flush request. */ + err = pvr_kccb_send_cmd(pvr_dev, &cmd_mmu_cache, &slot); + if (err) { + pvr_device_lost(pvr_dev); + goto err_drm_dev_exit; + } + + if (wait) { + err = pvr_kccb_wait_for_completion(pvr_dev, slot, HZ, NULL); + if (err) + pvr_device_lost(pvr_dev); + } + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c index 88f14a4d31ab..5f7cb7beb879 100644 --- a/drivers/gpu/drm/imagination/pvr_power.c +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -3,6 +3,7 @@ #include "pvr_device.h" #include "pvr_fw.h" +#include "pvr_fw_startstop.h" #include "pvr_power.h" #include "pvr_rogue_fwif.h" @@ -21,11 +22,38 @@ #define WATCHDOG_TIME_MS (500) +/** + * pvr_device_lost() - Mark GPU device as lost + * @pvr_dev: Target PowerVR device. + * + * This will cause the DRM device to be unplugged. + */ +void +pvr_device_lost(struct pvr_device *pvr_dev) +{ + if (!pvr_dev->lost) { + pvr_dev->lost = true; + drm_dev_unplug(from_pvr_device(pvr_dev)); + } +} + static int pvr_power_send_command(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *pow_cmd) { - /* TODO: implement */ - return -ENODEV; + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + u32 slot_nr; + u32 value; + int err; + + WRITE_ONCE(*fw_dev->power_sync, 0); + + err = pvr_kccb_send_cmd_powered(pvr_dev, pow_cmd, &slot_nr); + if (err) + return err; + + /* Wait for FW to acknowledge. */ + return readl_poll_timeout(pvr_dev->fw_dev.power_sync, value, value != 0, 100, + POWER_SYNC_TIMEOUT_US); } static int @@ -71,8 +99,7 @@ pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset) return err; } - /* TODO: stop firmware */ - return -ENODEV; + return pvr_fw_stop(pvr_dev); } static int @@ -80,11 +107,17 @@ pvr_power_fw_enable(struct pvr_device *pvr_dev) { int err; - /* TODO: start firmware */ - err = -ENODEV; + err = pvr_fw_start(pvr_dev); if (err) return err; + err = pvr_wait_for_fw_boot(pvr_dev); + if (err) { + drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); + pvr_fw_stop(pvr_dev); + return err; + } + queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, msecs_to_jiffies(WATCHDOG_TIME_MS)); @@ -94,14 +127,39 @@ pvr_power_fw_enable(struct pvr_device *pvr_dev) bool pvr_power_is_idle(struct pvr_device *pvr_dev) { - /* TODO: implement */ - return true; + /* + * FW power state can be out of date if a KCCB command has been submitted but the FW hasn't + * started processing it yet. So also check the KCCB status. + */ + enum rogue_fwif_pow_state pow_state = READ_ONCE(pvr_dev->fw_dev.fwif_sysdata->pow_state); + bool kccb_idle = pvr_kccb_is_idle(pvr_dev); + + return (pow_state == ROGUE_FWIF_POW_IDLE) && kccb_idle; } static bool pvr_watchdog_kccb_stalled(struct pvr_device *pvr_dev) { - /* TODO: implement */ + /* Check KCCB commands are progressing. */ + u32 kccb_cmds_executed = pvr_dev->fw_dev.fwif_osdata->kccb_cmds_executed; + bool kccb_is_idle = pvr_kccb_is_idle(pvr_dev); + + if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed && !kccb_is_idle) { + pvr_dev->watchdog.kccb_stall_count++; + + /* + * If we have commands pending with no progress for 2 consecutive polls then + * consider KCCB command processing stalled. + */ + if (pvr_dev->watchdog.kccb_stall_count == 2) { + pvr_dev->watchdog.kccb_stall_count = 0; + return true; + } + } else { + pvr_dev->watchdog.old_kccb_cmds_executed = kccb_cmds_executed; + pvr_dev->watchdog.kccb_stall_count = 0; + } + return false; } @@ -118,6 +176,9 @@ pvr_watchdog_worker(struct work_struct *work) if (pm_runtime_get_if_in_use(from_pvr_device(pvr_dev)->dev) <= 0) goto out_requeue; + if (!pvr_dev->fw_dev.booted) + goto out_pm_runtime_put; + stalled = pvr_watchdog_kccb_stalled(pvr_dev); if (stalled) { @@ -127,6 +188,7 @@ pvr_watchdog_worker(struct work_struct *work) /* Device may be lost at this point. */ } +out_pm_runtime_put: pm_runtime_put(from_pvr_device(pvr_dev)->dev); out_requeue: @@ -158,18 +220,26 @@ pvr_power_device_suspend(struct device *dev) struct platform_device *plat_dev = to_platform_device(dev); struct drm_device *drm_dev = platform_get_drvdata(plat_dev); struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + int err = 0; int idx; if (!drm_dev_enter(drm_dev, &idx)) return -EIO; + if (pvr_dev->fw_dev.booted) { + err = pvr_power_fw_disable(pvr_dev, false); + if (err) + goto err_drm_dev_exit; + } + clk_disable_unprepare(pvr_dev->mem_clk); clk_disable_unprepare(pvr_dev->sys_clk); clk_disable_unprepare(pvr_dev->core_clk); +err_drm_dev_exit: drm_dev_exit(idx); - return 0; + return err; } int @@ -196,10 +266,19 @@ pvr_power_device_resume(struct device *dev) if (err) goto err_sys_clk_disable; + if (pvr_dev->fw_dev.booted) { + err = pvr_power_fw_enable(pvr_dev); + if (err) + goto err_mem_clk_disable; + } + drm_dev_exit(idx); return 0; +err_mem_clk_disable: + clk_disable_unprepare(pvr_dev->mem_clk); + err_sys_clk_disable: clk_disable_unprepare(pvr_dev->sys_clk); @@ -239,7 +318,6 @@ pvr_power_device_idle(struct device *dev) int pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) { - /* TODO: Implement hard reset. */ int err; /* @@ -248,13 +326,69 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) */ WARN_ON(pvr_power_get(pvr_dev)); - err = pvr_power_fw_disable(pvr_dev, false); - if (err) - goto err_power_put; + down_write(&pvr_dev->reset_sem); - err = pvr_power_fw_enable(pvr_dev); + if (pvr_dev->lost) { + err = -EIO; + goto err_up_write; + } + + /* Disable IRQs for the duration of the reset. */ + disable_irq(pvr_dev->irq); + + do { + err = pvr_power_fw_disable(pvr_dev, hard_reset); + if (!err) { + if (hard_reset) { + pvr_dev->fw_dev.booted = false; + WARN_ON(pm_runtime_force_suspend(from_pvr_device(pvr_dev)->dev)); + + err = pvr_fw_hard_reset(pvr_dev); + if (err) + goto err_device_lost; + + err = pm_runtime_force_resume(from_pvr_device(pvr_dev)->dev); + pvr_dev->fw_dev.booted = true; + if (err) + goto err_device_lost; + } else { + /* Clear the FW faulted flags. */ + pvr_dev->fw_dev.fwif_sysdata->hwr_state_flags &= + ~(ROGUE_FWIF_HWR_FW_FAULT | + ROGUE_FWIF_HWR_RESTART_REQUESTED); + } + + pvr_fw_irq_clear(pvr_dev); + + err = pvr_power_fw_enable(pvr_dev); + } + + if (err && hard_reset) + goto err_device_lost; + + if (err && !hard_reset) { + drm_err(from_pvr_device(pvr_dev), "FW stalled, trying hard reset"); + hard_reset = true; + } + } while (err); + + enable_irq(pvr_dev->irq); + + up_write(&pvr_dev->reset_sem); + + pvr_power_put(pvr_dev); + + return 0; + +err_device_lost: + drm_err(from_pvr_device(pvr_dev), "GPU device lost"); + pvr_device_lost(pvr_dev); + + /* Leave IRQs disabled if the device is lost. */ + +err_up_write: + up_write(&pvr_dev->reset_sem); -err_power_put: pvr_power_put(pvr_dev); return err; diff --git a/drivers/gpu/drm/imagination/pvr_power.h b/drivers/gpu/drm/imagination/pvr_power.h index 360980f454d7..9a9312dcb2da 100644 --- a/drivers/gpu/drm/imagination/pvr_power.h +++ b/drivers/gpu/drm/imagination/pvr_power.h @@ -12,6 +12,8 @@ int pvr_watchdog_init(struct pvr_device *pvr_dev); void pvr_watchdog_fini(struct pvr_device *pvr_dev); +void pvr_device_lost(struct pvr_device *pvr_dev); + bool pvr_power_is_idle(struct pvr_device *pvr_dev); int pvr_power_device_suspend(struct device *dev); diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 4c48a208c390..3ad1366294b9 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -540,6 +540,16 @@ static const struct drm_gpuvm_ops pvr_vm_gpuva_ops = { .sm_step_unmap = pvr_vm_gpuva_unmap, }; +static void +fw_mem_context_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_fwmemcontext *fw_mem_ctx = cpu_ptr; + struct pvr_vm_context *vm_ctx = priv; + + fw_mem_ctx->pc_dev_paddr = pvr_vm_get_page_table_root_addr(vm_ctx); + fw_mem_ctx->page_cat_base_reg_set = ROGUE_FW_BIF_INVALID_PCSET; +} + /** * pvr_vm_create_context() - Create a new VM context. * @pvr_dev: Target PowerVR device. @@ -602,13 +612,19 @@ pvr_vm_create_context(struct pvr_device *pvr_dev, bool is_userspace_context) } if (is_userspace_context) { - /* TODO: Create FW mem context */ - err = -ENODEV; - goto err_put_ctx; + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_fwmemcontext), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_mem_context_init, vm_ctx, &vm_ctx->fw_mem_ctx_obj); + + if (err) + goto err_page_table_destroy; } return vm_ctx; +err_page_table_destroy: + pvr_mmu_context_destroy(vm_ctx->mmu_ctx); + err_put_ctx: pvr_vm_context_put(vm_ctx); @@ -628,8 +644,8 @@ pvr_vm_context_release(struct kref *ref_count) struct pvr_vm_context *vm_ctx = container_of(ref_count, struct pvr_vm_context, ref_count); - /* TODO: Destroy FW mem context */ - WARN_ON(vm_ctx->fw_mem_ctx_obj); + if (vm_ctx->fw_mem_ctx_obj) + pvr_fw_object_destroy(vm_ctx->fw_mem_ctx_obj); WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, vm_ctx->gpuvm_mgr.mm_range)); From 927f3e0253c11276f0237ca1a14e77c48957c069 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:35 +0000 Subject: [PATCH 1186/7721] drm/imagination: Implement MIPS firmware processor and MMU support Add support for the MIPS firmware processor, used in the Series AXE GPU. The MIPS firmware processor uses a separate MMU to the rest of the GPU, so this patch adds support for that as well. Changes since v8: - Corrected license identifiers Changes since v6: - Fix integer overflow in VM map error path Changes since v5: - Use alloc_page() when allocating MIPS pagetable Changes since v3: - Get regs resource (removed from GPU resources commit) Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/a114f7b3e97cb07460c7f2842901716a9207b0c4.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 4 +- drivers/gpu/drm/imagination/pvr_device.c | 5 +- drivers/gpu/drm/imagination/pvr_device.h | 3 + drivers/gpu/drm/imagination/pvr_fw.c | 2 + drivers/gpu/drm/imagination/pvr_fw_mips.c | 252 ++++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_fw_mips.h | 48 +++++ drivers/gpu/drm/imagination/pvr_vm_mips.c | 238 ++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_vm_mips.h | 22 ++ 8 files changed, 572 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_fw_mips.c create mode 100644 drivers/gpu/drm/imagination/pvr_fw_mips.h create mode 100644 drivers/gpu/drm/imagination/pvr_vm_mips.c create mode 100644 drivers/gpu/drm/imagination/pvr_vm_mips.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 5c1c918af7a3..71dc36cc6b9d 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -10,11 +10,13 @@ powervr-y := \ pvr_drv.o \ pvr_fw.o \ pvr_fw_meta.o \ + pvr_fw_mips.o \ pvr_fw_startstop.o \ pvr_fw_trace.o \ pvr_gem.o \ pvr_mmu.o \ pvr_power.o \ - pvr_vm.o + pvr_vm.o \ + pvr_vm_mips.o obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 1be14cdbdace..2d6db4715f85 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -50,16 +50,19 @@ pvr_device_reg_init(struct pvr_device *pvr_dev) { struct drm_device *drm_dev = from_pvr_device(pvr_dev); struct platform_device *plat_dev = to_platform_device(drm_dev->dev); + struct resource *regs_resource; void __iomem *regs; + pvr_dev->regs_resource = NULL; pvr_dev->regs = NULL; - regs = devm_platform_ioremap_resource(plat_dev, 0); + regs = devm_platform_get_and_ioremap_resource(plat_dev, 0, ®s_resource); if (IS_ERR(regs)) return dev_err_probe(drm_dev->dev, PTR_ERR(regs), "failed to ioremap gpu registers\n"); pvr_dev->regs = regs; + pvr_dev->regs_resource = regs_resource; return 0; } diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index 39347595c6f0..8853249f4884 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -93,6 +93,9 @@ struct pvr_device { /** @fw_version: Firmware version detected at runtime. */ struct pvr_fw_version fw_version; + /** @regs_resource: Resource representing device control registers. */ + struct resource *regs_resource; + /** * @regs: Device control registers. * diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c index f8ed981f1807..3debc9870a82 100644 --- a/drivers/gpu/drm/imagination/pvr_fw.c +++ b/drivers/gpu/drm/imagination/pvr_fw.c @@ -933,6 +933,8 @@ pvr_fw_init(struct pvr_device *pvr_dev) if (fw_dev->processor_type == PVR_FW_PROCESSOR_TYPE_META) fw_dev->defs = &pvr_fw_defs_meta; + else if (fw_dev->processor_type == PVR_FW_PROCESSOR_TYPE_MIPS) + fw_dev->defs = &pvr_fw_defs_mips; else return -EINVAL; diff --git a/drivers/gpu/drm/imagination/pvr_fw_mips.c b/drivers/gpu/drm/imagination/pvr_fw_mips.c new file mode 100644 index 000000000000..0bed0257e2ab --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_mips.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_mips.h" +#include "pvr_gem.h" +#include "pvr_rogue_mips.h" +#include "pvr_vm_mips.h" + +#include +#include +#include + +#define ROGUE_FW_HEAP_MIPS_BASE 0xC0000000 +#define ROGUE_FW_HEAP_MIPS_SHIFT 24 /* 16 MB */ +#define ROGUE_FW_HEAP_MIPS_RESERVED_SIZE SZ_1M + +/** + * process_elf_command_stream() - Process ELF firmware image and populate + * firmware sections + * @pvr_dev: Device pointer. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to FW code section. + * @fw_data_ptr: Pointer to FW data section. + * @fw_core_code_ptr: Pointer to FW coremem code section. + * @fw_core_data_ptr: Pointer to FW coremem data section. + * + * Returns : + * * 0 on success, or + * * -EINVAL on any error in ELF command stream. + */ +static int +process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) +{ + struct elf32_hdr *header = (struct elf32_hdr *)fw; + struct elf32_phdr *program_header = (struct elf32_phdr *)(fw + header->e_phoff); + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u32 entry; + int err; + + for (entry = 0; entry < header->e_phnum; entry++, program_header++) { + void *write_addr; + + /* Only consider loadable entries in the ELF segment table */ + if (program_header->p_type != PT_LOAD) + continue; + + err = pvr_fw_find_mmu_segment(pvr_dev, program_header->p_vaddr, + program_header->p_memsz, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + program_header->p_vaddr, program_header->p_memsz); + return err; + } + + /* Write to FW allocation only if available */ + if (write_addr) { + memcpy(write_addr, fw + program_header->p_offset, + program_header->p_filesz); + + memset((u8 *)write_addr + program_header->p_filesz, 0, + program_header->p_memsz - program_header->p_filesz); + } + } + + return 0; +} + +static int +pvr_mips_init(struct pvr_device *pvr_dev) +{ + pvr_fw_heap_info_init(pvr_dev, ROGUE_FW_HEAP_MIPS_SHIFT, ROGUE_FW_HEAP_MIPS_RESERVED_SIZE); + + return pvr_vm_mips_init(pvr_dev); +} + +static void +pvr_mips_fini(struct pvr_device *pvr_dev) +{ + pvr_vm_mips_fini(pvr_dev); +} + +static int +pvr_mips_fw_process(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, + u32 core_code_alloc_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + const struct pvr_fw_layout_entry *boot_code_entry; + const struct pvr_fw_layout_entry *boot_data_entry; + const struct pvr_fw_layout_entry *exception_code_entry; + const struct pvr_fw_layout_entry *stack_entry; + struct rogue_mipsfw_boot_data *boot_data; + dma_addr_t dma_addr; + u32 page_nr; + int err; + + err = process_elf_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, fw_core_code_ptr, + fw_core_data_ptr); + if (err) + return err; + + boot_code_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_BOOT_CODE); + boot_data_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_BOOT_DATA); + exception_code_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_EXCEPTIONS_CODE); + if (!boot_code_entry || !boot_data_entry || !exception_code_entry) + return -EINVAL; + + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.code_obj->gem, boot_code_entry->alloc_offset, + &mips_data->boot_code_dma_addr)); + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.data_obj->gem, boot_data_entry->alloc_offset, + &mips_data->boot_data_dma_addr)); + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.code_obj->gem, + exception_code_entry->alloc_offset, + &mips_data->exception_code_dma_addr)); + + stack_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_STACK); + if (!stack_entry) + return -EINVAL; + + boot_data = (struct rogue_mipsfw_boot_data *)(fw_data_ptr + boot_data_entry->alloc_offset + + ROGUE_MIPSFW_BOOTLDR_CONF_OFFSET); + + WARN_ON(pvr_fw_object_get_dma_addr(fw_dev->mem.data_obj, stack_entry->alloc_offset, + &dma_addr)); + boot_data->stack_phys_addr = dma_addr; + + boot_data->reg_base = pvr_dev->regs_resource->start; + + for (page_nr = 0; page_nr < ARRAY_SIZE(boot_data->pt_phys_addr); page_nr++) { + /* Firmware expects 4k pages, but host page size might be different. */ + u32 src_page_nr = (page_nr * ROGUE_MIPSFW_PAGE_SIZE_4K) >> PAGE_SHIFT; + u32 page_offset = (page_nr * ROGUE_MIPSFW_PAGE_SIZE_4K) & ~PAGE_MASK; + + boot_data->pt_phys_addr[page_nr] = mips_data->pt_dma_addr[src_page_nr] + + page_offset; + } + + boot_data->pt_log2_page_size = ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + boot_data->pt_num_pages = ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES; + boot_data->reserved1 = 0; + boot_data->reserved2 = 0; + + return 0; +} + +static int +pvr_mips_wrapper_init(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mips_data *mips_data = pvr_dev->fw_dev.processor_data.mips_data; + const u64 remap_settings = ROGUE_MIPSFW_BOOT_REMAP_LOG2_SEGMENT_SIZE; + u32 phys_bus_width; + + int err = PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width); + + if (WARN_ON(err)) + return err; + + /* Currently MIPS FW only supported with physical bus width > 32 bits. */ + if (WARN_ON(phys_bus_width <= 32)) + return -EINVAL; + + pvr_cr_write32(pvr_dev, ROGUE_CR_MIPS_WRAPPER_CONFIG, + (ROGUE_MIPSFW_REGISTERS_VIRTUAL_BASE >> + ROGUE_MIPSFW_WRAPPER_CONFIG_REGBANK_ADDR_ALIGN) | + ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MICROMIPS); + + /* Configure remap for boot code, boot data and exceptions code areas. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1, + ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2, + (mips_data->boot_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + if (PVR_HAS_QUIRK(pvr_dev, 63553)) { + /* + * WA always required on 36 bit cores, to avoid continuous unmapped memory accesses + * to address 0x0. + */ + WARN_ON(phys_bus_width != 36); + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1, + ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2, + (mips_data->boot_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_CLRMSK) | + remap_settings); + } + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1, + ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2, + (mips_data->boot_data_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1, + ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2, + (mips_data->exception_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + /* Garten IDLE bit controlled by MIPS. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG, + ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META); + + /* Turn on the EJTAG probe. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_MIPS_DEBUG_CONFIG, 0); + + return 0; +} + +static u32 +pvr_mips_get_fw_addr_with_offset(struct pvr_fw_object *fw_obj, u32 offset) +{ + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(fw_obj->gem)->dev); + + /* MIPS cacheability is determined by page table. */ + return ((fw_obj->fw_addr_offset + offset) & pvr_dev->fw_dev.fw_heap_info.offset_mask) | + ROGUE_FW_HEAP_MIPS_BASE; +} + +static bool +pvr_mips_has_fixed_data_addr(void) +{ + return true; +} + +const struct pvr_fw_defs pvr_fw_defs_mips = { + .init = pvr_mips_init, + .fini = pvr_mips_fini, + .fw_process = pvr_mips_fw_process, + .vm_map = pvr_vm_mips_map, + .vm_unmap = pvr_vm_mips_unmap, + .get_fw_addr_with_offset = pvr_mips_get_fw_addr_with_offset, + .wrapper_init = pvr_mips_wrapper_init, + .has_fixed_data_addr = pvr_mips_has_fixed_data_addr, + .irq = { + .enable_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE, + .status_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS, + .clear_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR, + .event_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN, + .clear_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN, + }, +}; diff --git a/drivers/gpu/drm/imagination/pvr_fw_mips.h b/drivers/gpu/drm/imagination/pvr_fw_mips.h new file mode 100644 index 000000000000..408dbe63a90c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_mips.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_MIPS_H +#define PVR_FW_MIPS_H + +#include "pvr_rogue_mips.h" + +#include +#include + +/* Forward declaration from pvr_gem.h. */ +struct pvr_gem_object; + +#define PVR_MIPS_PT_PAGE_COUNT ((ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * ROGUE_MIPSFW_PAGE_SIZE_4K) \ + >> PAGE_SHIFT) +/** + * struct pvr_fw_mips_data - MIPS-specific data + */ +struct pvr_fw_mips_data { + /** + * @pt_pages: Pages containing MIPS pagetable. + */ + struct page *pt_pages[PVR_MIPS_PT_PAGE_COUNT]; + + /** @pt: Pointer to CPU mapping of MIPS pagetable. */ + u32 *pt; + + /** @pt_dma_addr: DMA mappings of MIPS pagetable. */ + dma_addr_t pt_dma_addr[PVR_MIPS_PT_PAGE_COUNT]; + + /** @boot_code_dma_addr: DMA address of MIPS boot code. */ + dma_addr_t boot_code_dma_addr; + + /** @boot_data_dma_addr: DMA address of MIPS boot data. */ + dma_addr_t boot_data_dma_addr; + + /** @exception_code_dma_addr: DMA address of MIPS exception code. */ + dma_addr_t exception_code_dma_addr; + + /** @cache_policy: Cache policy for this processor. */ + u32 cache_policy; + + /** @pfn_mask: PFN mask for MIPS pagetable. */ + u32 pfn_mask; +}; + +#endif /* PVR_FW_MIPS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_vm_mips.c b/drivers/gpu/drm/imagination/pvr_vm_mips.c new file mode 100644 index 000000000000..7268cf6e630b --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm_mips.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw_mips.h" +#include "pvr_gem.h" +#include "pvr_mmu.h" +#include "pvr_rogue_mips.h" +#include "pvr_vm.h" +#include "pvr_vm_mips.h" + +#include +#include +#include +#include +#include + +/** + * pvr_vm_mips_init() - Initialise MIPS FW pagetable + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, + * * -%EINVAL, + * * Any error returned by pvr_gem_object_create(), or + * * And error returned by pvr_gem_object_vmap(). + */ +int +pvr_vm_mips_init(struct pvr_device *pvr_dev) +{ + u32 pt_size = 1 << ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_4K(pvr_dev); + struct device *dev = from_pvr_device(pvr_dev)->dev; + struct pvr_fw_mips_data *mips_data; + u32 phys_bus_width; + int page_nr; + int err; + + /* Page table size must be at most ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * 4k pages. */ + if (pt_size > ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * SZ_4K) + return -EINVAL; + + if (PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width)) + return -EINVAL; + + mips_data = drmm_kzalloc(from_pvr_device(pvr_dev), sizeof(*mips_data), GFP_KERNEL); + if (!mips_data) + return -ENOMEM; + + for (page_nr = 0; page_nr < ARRAY_SIZE(mips_data->pt_pages); page_nr++) { + mips_data->pt_pages[page_nr] = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!mips_data->pt_pages[page_nr]) { + err = -ENOMEM; + goto err_free_pages; + } + + mips_data->pt_dma_addr[page_nr] = dma_map_page(dev, mips_data->pt_pages[page_nr], 0, + PAGE_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dev, mips_data->pt_dma_addr[page_nr])) { + err = -ENOMEM; + goto err_free_pages; + } + } + + mips_data->pt = vmap(mips_data->pt_pages, pt_size >> PAGE_SHIFT, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!mips_data->pt) { + err = -ENOMEM; + goto err_free_pages; + } + + mips_data->pfn_mask = (phys_bus_width > 32) ? ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT : + ROGUE_MIPSFW_ENTRYLO_PFN_MASK; + + mips_data->cache_policy = (phys_bus_width > 32) ? ROGUE_MIPSFW_CACHED_POLICY_ABOVE_32BIT : + ROGUE_MIPSFW_CACHED_POLICY; + + pvr_dev->fw_dev.processor_data.mips_data = mips_data; + + return 0; + +err_free_pages: + for (; page_nr >= 0; page_nr--) { + if (mips_data->pt_dma_addr[page_nr]) + dma_unmap_page(from_pvr_device(pvr_dev)->dev, + mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); + + if (mips_data->pt_pages[page_nr]) + __free_page(mips_data->pt_pages[page_nr]); + } + + return err; +} + +/** + * pvr_vm_mips_fini() - Release MIPS FW pagetable + * @pvr_dev: Target PowerVR device. + */ +void +pvr_vm_mips_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + int page_nr; + + vunmap(mips_data->pt); + for (page_nr = ARRAY_SIZE(mips_data->pt_pages) - 1; page_nr >= 0; page_nr--) { + dma_unmap_page(from_pvr_device(pvr_dev)->dev, + mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); + + __free_page(mips_data->pt_pages[page_nr]); + } + + fw_dev->processor_data.mips_data = NULL; +} + +static u32 +get_mips_pte_flags(bool read, bool write, u32 cache_policy) +{ + u32 flags = 0; + + if (read && write) /* Read/write. */ + flags |= ROGUE_MIPSFW_ENTRYLO_DIRTY_EN; + else if (write) /* Write only. */ + flags |= ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_EN; + else + WARN_ON(!read); + + flags |= cache_policy << ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT; + + flags |= ROGUE_MIPSFW_ENTRYLO_VALID_EN | ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN; + + return flags; +} + +/** + * pvr_vm_mips_map() - Map a FW object into MIPS address space + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * Returns: + * * 0 on success, + * * -%EINVAL if object does not reside within FW address space, or + * * Any error returned by pvr_fw_object_get_dma_addr(). + */ +int +pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + struct pvr_gem_object *pvr_obj = fw_obj->gem; + const u64 start = fw_obj->fw_mm_node.start; + const u64 size = fw_obj->fw_mm_node.size; + u64 end; + u32 cache_policy; + u32 pte_flags; + u32 start_pfn; + u32 end_pfn; + s32 pfn; + int err; + + if (check_add_overflow(start, size - 1, &end)) + return -EINVAL; + + if (start < ROGUE_FW_HEAP_BASE || + start >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size || + end < ROGUE_FW_HEAP_BASE || + end >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size || + (start & ROGUE_MIPSFW_PAGE_MASK_4K) || + ((end + 1) & ROGUE_MIPSFW_PAGE_MASK_4K)) + return -EINVAL; + + start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + + if (pvr_obj->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED) + cache_policy = ROGUE_MIPSFW_UNCACHED_CACHE_POLICY; + else + cache_policy = mips_data->cache_policy; + + pte_flags = get_mips_pte_flags(true, true, cache_policy); + + for (pfn = start_pfn; pfn <= end_pfn; pfn++) { + dma_addr_t dma_addr; + u32 pte; + + err = pvr_fw_object_get_dma_addr(fw_obj, + (pfn - start_pfn) << + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K, + &dma_addr); + if (err) + goto err_unmap_pages; + + pte = ((dma_addr >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) + << ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) & mips_data->pfn_mask; + pte |= pte_flags; + + WRITE_ONCE(mips_data->pt[pfn], pte); + } + + pvr_mmu_flush_request_all(pvr_dev); + + return 0; + +err_unmap_pages: + for (; pfn >= start_pfn; pfn--) + WRITE_ONCE(mips_data->pt[pfn], 0); + + pvr_mmu_flush_request_all(pvr_dev); + WARN_ON(pvr_mmu_flush_exec(pvr_dev, true)); + + return err; +} + +/** + * pvr_vm_mips_unmap() - Unmap a FW object into MIPS address space + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to unmap. + */ +void +pvr_vm_mips_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + const u64 start = fw_obj->fw_mm_node.start; + const u64 size = fw_obj->fw_mm_node.size; + const u64 end = start + size; + + const u32 start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + const u32 end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + + for (u32 pfn = start_pfn; pfn < end_pfn; pfn++) + WRITE_ONCE(mips_data->pt[pfn], 0); + + pvr_mmu_flush_request_all(pvr_dev); + WARN_ON(pvr_mmu_flush_exec(pvr_dev, true)); +} diff --git a/drivers/gpu/drm/imagination/pvr_vm_mips.h b/drivers/gpu/drm/imagination/pvr_vm_mips.h new file mode 100644 index 000000000000..0fd59f68fb5b --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm_mips.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_VM_MIPS_H +#define PVR_VM_MIPS_H + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +int +pvr_vm_mips_init(struct pvr_device *pvr_dev); +void +pvr_vm_mips_fini(struct pvr_device *pvr_dev); +int +pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); +void +pvr_vm_mips_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + +#endif /* PVR_VM_MIPS_H */ From 6eedddab733b350886571f98b810108b13bf74ae Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:36 +0000 Subject: [PATCH 1187/7721] drm/imagination: Implement free list and HWRT create and destroy ioctls Implement ioctls to create and destroy free lists and HWRT datasets. Free lists are used for GPU-side memory allocation during geometry processing. HWRT datasets are the FW-side structures representing render targets. Changes since v8: - Corrected license identifiers Changes since v6: - Fix out-of-bounds shift in get_cr_multisamplectl_val() Changes since v4: - Remove use of drm_gem_shmem_get_pages() Changes since v3: - Support free list grow requests from FW - Use drm_dev_{enter,exit} Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Link: https://lore.kernel.org/r/919358c5887a7628da588c455a5bb7e3ea4b47ae.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 2 + drivers/gpu/drm/imagination/pvr_ccb.c | 10 + drivers/gpu/drm/imagination/pvr_device.h | 24 + drivers/gpu/drm/imagination/pvr_drv.c | 112 +++- drivers/gpu/drm/imagination/pvr_free_list.c | 625 ++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_free_list.h | 195 ++++++ drivers/gpu/drm/imagination/pvr_hwrt.c | 549 +++++++++++++++++ drivers/gpu/drm/imagination/pvr_hwrt.h | 165 ++++++ 8 files changed, 1678 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_free_list.c create mode 100644 drivers/gpu/drm/imagination/pvr_free_list.h create mode 100644 drivers/gpu/drm/imagination/pvr_hwrt.c create mode 100644 drivers/gpu/drm/imagination/pvr_hwrt.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 71dc36cc6b9d..2bd501018d5d 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -8,12 +8,14 @@ powervr-y := \ pvr_device.o \ pvr_device_info.o \ pvr_drv.o \ + pvr_free_list.o \ pvr_fw.o \ pvr_fw_meta.o \ pvr_fw_mips.o \ pvr_fw_startstop.o \ pvr_fw_trace.o \ pvr_gem.o \ + pvr_hwrt.o \ pvr_mmu.o \ pvr_power.o \ pvr_vm.o \ diff --git a/drivers/gpu/drm/imagination/pvr_ccb.c b/drivers/gpu/drm/imagination/pvr_ccb.c index 48f06f58f3f1..4deeac7ed40a 100644 --- a/drivers/gpu/drm/imagination/pvr_ccb.c +++ b/drivers/gpu/drm/imagination/pvr_ccb.c @@ -4,6 +4,7 @@ #include "pvr_ccb.h" #include "pvr_device.h" #include "pvr_drv.h" +#include "pvr_free_list.h" #include "pvr_fw.h" #include "pvr_gem.h" #include "pvr_power.h" @@ -139,6 +140,15 @@ process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *c pvr_power_reset(pvr_dev, false); break; + case ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION: + pvr_free_list_process_reconstruct_req(pvr_dev, + &cmd->cmd_data.cmd_freelists_reconstruction); + break; + + case ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW: + pvr_free_list_process_grow_req(pvr_dev, &cmd->cmd_data.cmd_free_list_gs); + break; + default: drm_info(from_pvr_device(pvr_dev), "Received unknown FWCCB command %x\n", cmd->cmd_type); diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index 8853249f4884..f5b82b793566 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -152,6 +152,14 @@ struct pvr_device { */ atomic_t mmu_flush_cache_flags; + /** + * @free_list_ids: Array of free lists belonging to this device. Array members + * are of type "struct pvr_free_list *". + * + * This array is used to allocate IDs used by the firmware. + */ + struct xarray free_list_ids; + struct { /** @work: Work item for watchdog callback. */ struct delayed_work work; @@ -247,6 +255,22 @@ struct pvr_file { */ struct pvr_device *pvr_dev; + /** + * @free_list_handles: Array of free lists belonging to this file. Array + * members are of type "struct pvr_free_list *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray free_list_handles; + + /** + * @hwrt_handles: Array of HWRT datasets belonging to this file. Array + * members are of type "struct pvr_hwrt_dataset *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray hwrt_handles; + /** * @vm_ctx_handles: Array of VM contexts belonging to this file. Array * members are of type "struct pvr_vm_context *". diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index 33b38c0d79c8..f485e2cc60f9 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -3,7 +3,9 @@ #include "pvr_device.h" #include "pvr_drv.h" +#include "pvr_free_list.h" #include "pvr_gem.h" +#include "pvr_hwrt.h" #include "pvr_mmu.h" #include "pvr_power.h" #include "pvr_rogue_defs.h" @@ -711,7 +713,41 @@ static int pvr_ioctl_create_free_list(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_create_free_list_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_free_list *free_list; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + free_list = pvr_free_list_create(pvr_file, args); + if (IS_ERR(free_list)) { + err = PTR_ERR(free_list); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->free_list_handles, + &args->handle, + free_list, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_free_list_put(free_list); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** @@ -731,7 +767,19 @@ static int pvr_ioctl_destroy_free_list(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_destroy_free_list_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_free_list *free_list; + + if (args->_padding_4) + return -EINVAL; + + free_list = xa_erase(&pvr_file->free_list_handles, args->handle); + if (!free_list) + return -EINVAL; + + pvr_free_list_put(free_list); + return 0; } /** @@ -751,7 +799,41 @@ static int pvr_ioctl_create_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_create_hwrt_dataset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_hwrt_dataset *hwrt; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + hwrt = pvr_hwrt_dataset_create(pvr_file, args); + if (IS_ERR(hwrt)) { + err = PTR_ERR(hwrt); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->hwrt_handles, + &args->handle, + hwrt, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_hwrt_dataset_put(hwrt); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; } /** @@ -771,7 +853,19 @@ static int pvr_ioctl_destroy_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_destroy_hwrt_dataset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_hwrt_dataset *hwrt; + + if (args->_padding_4) + return -EINVAL; + + hwrt = xa_erase(&pvr_file->hwrt_handles, args->handle); + if (!hwrt) + return -EINVAL; + + pvr_hwrt_dataset_put(hwrt); + return 0; } /** @@ -1195,6 +1289,8 @@ pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file) */ pvr_file->pvr_dev = pvr_dev; + xa_init_flags(&pvr_file->free_list_handles, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_file->hwrt_handles, XA_FLAGS_ALLOC1); xa_init_flags(&pvr_file->vm_ctx_handles, XA_FLAGS_ALLOC1); /* @@ -1223,6 +1319,8 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, struct pvr_file *pvr_file = to_pvr_file(file); /* Drop references on any remaining objects. */ + pvr_destroy_free_lists_for_file(pvr_file); + pvr_destroy_hwrt_datasets_for_file(pvr_file); pvr_destroy_vm_contexts_for_file(pvr_file); kfree(pvr_file); @@ -1281,6 +1379,8 @@ pvr_probe(struct platform_device *plat_dev) if (err) goto err_device_fini; + xa_init_flags(&pvr_dev->free_list_ids, XA_FLAGS_ALLOC1); + return 0; err_device_fini: @@ -1298,6 +1398,10 @@ pvr_remove(struct platform_device *plat_dev) struct drm_device *drm_dev = platform_get_drvdata(plat_dev); struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + WARN_ON(!xa_empty(&pvr_dev->free_list_ids)); + + xa_destroy(&pvr_dev->free_list_ids); + pm_runtime_suspend(drm_dev->dev); pvr_device_fini(pvr_dev); drm_dev_unplug(drm_dev); diff --git a/drivers/gpu/drm/imagination/pvr_free_list.c b/drivers/gpu/drm/imagination/pvr_free_list.c new file mode 100644 index 000000000000..c61fd417edcb --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_free_list.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_free_list.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" +#include "pvr_rogue_fwif.h" +#include "pvr_vm.h" + +#include +#include +#include +#include + +#define FREE_LIST_ENTRY_SIZE sizeof(u32) + +#define FREE_LIST_ALIGNMENT \ + ((ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE / FREE_LIST_ENTRY_SIZE) - 1) + +#define FREE_LIST_MIN_PAGES 50 +#define FREE_LIST_MIN_PAGES_BRN66011 40 +#define FREE_LIST_MIN_PAGES_ROGUEXE 25 + +/** + * pvr_get_free_list_min_pages() - Get minimum free list size for this device + * @pvr_dev: Device pointer. + * + * Returns: + * * Minimum free list size, in PM physical pages. + */ +u32 +pvr_get_free_list_min_pages(struct pvr_device *pvr_dev) +{ + u32 value; + + if (PVR_HAS_FEATURE(pvr_dev, roguexe)) { + if (PVR_HAS_QUIRK(pvr_dev, 66011)) + value = FREE_LIST_MIN_PAGES_BRN66011; + else + value = FREE_LIST_MIN_PAGES_ROGUEXE; + } else { + value = FREE_LIST_MIN_PAGES; + } + + return value; +} + +static int +free_list_create_kernel_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args, + struct pvr_free_list *free_list) +{ + struct pvr_gem_object *free_list_obj; + struct pvr_vm_context *vm_ctx; + u64 free_list_size; + int err; + + if (args->grow_threshold > 100 || + args->initial_num_pages > args->max_num_pages || + args->grow_num_pages > args->max_num_pages || + args->max_num_pages == 0 || + (args->initial_num_pages < args->max_num_pages && !args->grow_num_pages) || + (args->initial_num_pages == args->max_num_pages && args->grow_num_pages)) + return -EINVAL; + + if ((args->initial_num_pages & FREE_LIST_ALIGNMENT) || + (args->max_num_pages & FREE_LIST_ALIGNMENT) || + (args->grow_num_pages & FREE_LIST_ALIGNMENT)) + return -EINVAL; + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) + return -EINVAL; + + free_list_obj = pvr_vm_find_gem_object(vm_ctx, args->free_list_gpu_addr, + NULL, &free_list_size); + if (!free_list_obj) { + err = -EINVAL; + goto err_put_vm_context; + } + + if ((free_list_obj->flags & DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS) || + !(free_list_obj->flags & DRM_PVR_BO_PM_FW_PROTECT) || + free_list_size < (args->max_num_pages * FREE_LIST_ENTRY_SIZE)) { + err = -EINVAL; + goto err_put_free_list_obj; + } + + free_list->pvr_dev = pvr_file->pvr_dev; + free_list->current_pages = 0; + free_list->max_pages = args->max_num_pages; + free_list->grow_pages = args->grow_num_pages; + free_list->grow_threshold = args->grow_threshold; + free_list->obj = free_list_obj; + free_list->free_list_gpu_addr = args->free_list_gpu_addr; + free_list->initial_num_pages = args->initial_num_pages; + + pvr_vm_context_put(vm_ctx); + + return 0; + +err_put_free_list_obj: + pvr_gem_object_put(free_list_obj); + +err_put_vm_context: + pvr_vm_context_put(vm_ctx); + + return err; +} + +static void +free_list_destroy_kernel_structure(struct pvr_free_list *free_list) +{ + WARN_ON(!list_empty(&free_list->hwrt_list)); + + pvr_gem_object_put(free_list->obj); +} + +/** + * calculate_free_list_ready_pages_locked() - Function to work out the number of free + * list pages to reserve for growing within + * the FW without having to wait for the + * host to progress a grow request + * @free_list: Pointer to free list. + * @pages: Total pages currently in free list. + * + * If the threshold or grow size means less than the alignment size (4 pages on + * Rogue), then the feature is not used. + * + * Caller must hold &free_list->lock. + * + * Return: number of pages to reserve. + */ +static u32 +calculate_free_list_ready_pages_locked(struct pvr_free_list *free_list, u32 pages) +{ + u32 ready_pages; + + lockdep_assert_held(&free_list->lock); + + ready_pages = ((pages * free_list->grow_threshold) / 100); + + /* The number of pages must be less than the grow size. */ + ready_pages = min(ready_pages, free_list->grow_pages); + + /* + * The number of pages must be a multiple of the free list align size. + */ + ready_pages &= ~FREE_LIST_ALIGNMENT; + + return ready_pages; +} + +static u32 +calculate_free_list_ready_pages(struct pvr_free_list *free_list, u32 pages) +{ + u32 ret; + + mutex_lock(&free_list->lock); + + ret = calculate_free_list_ready_pages_locked(free_list, pages); + + mutex_unlock(&free_list->lock); + + return ret; +} + +static void +free_list_fw_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_freelist *fw_data = cpu_ptr; + struct pvr_free_list *free_list = priv; + u32 ready_pages; + + /* Fill out FW structure */ + ready_pages = calculate_free_list_ready_pages(free_list, + free_list->initial_num_pages); + + fw_data->max_pages = free_list->max_pages; + fw_data->current_pages = free_list->initial_num_pages - ready_pages; + fw_data->grow_pages = free_list->grow_pages; + fw_data->ready_pages = ready_pages; + fw_data->freelist_id = free_list->fw_id; + fw_data->grow_pending = false; + fw_data->current_stack_top = fw_data->current_pages - 1; + fw_data->freelist_dev_addr = free_list->free_list_gpu_addr; + fw_data->current_dev_addr = (fw_data->freelist_dev_addr + + ((fw_data->max_pages - fw_data->current_pages) * + FREE_LIST_ENTRY_SIZE)) & + ~((u64)ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE - 1); +} + +static int +free_list_create_fw_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args, + struct pvr_free_list *free_list) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + + /* + * Create and map the FW structure so we can initialise it. This is not + * accessed on the CPU side post-initialisation so the mapping lifetime + * is only for this function. + */ + free_list->fw_data = pvr_fw_object_create_and_map(pvr_dev, sizeof(*free_list->fw_data), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + free_list_fw_init, free_list, + &free_list->fw_obj); + if (IS_ERR(free_list->fw_data)) + return PTR_ERR(free_list->fw_data); + + return 0; +} + +static void +free_list_destroy_fw_structure(struct pvr_free_list *free_list) +{ + pvr_fw_object_unmap_and_destroy(free_list->fw_obj); +} + +static int +pvr_free_list_insert_pages_locked(struct pvr_free_list *free_list, + struct sg_table *sgt, u32 offset, u32 num_pages) +{ + struct sg_dma_page_iter dma_iter; + u32 *page_list; + + lockdep_assert_held(&free_list->lock); + + page_list = pvr_gem_object_vmap(free_list->obj); + if (IS_ERR(page_list)) + return PTR_ERR(page_list); + + offset /= FREE_LIST_ENTRY_SIZE; + /* clang-format off */ + for_each_sgtable_dma_page(sgt, &dma_iter, 0) { + dma_addr_t dma_addr = sg_page_iter_dma_address(&dma_iter); + u64 dma_pfn = dma_addr >> + ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT; + u32 dma_addr_offset; + + BUILD_BUG_ON(ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE > PAGE_SIZE); + + for (dma_addr_offset = 0; dma_addr_offset < PAGE_SIZE; + dma_addr_offset += ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE) { + WARN_ON_ONCE(dma_pfn >> 32); + + page_list[offset++] = (u32)dma_pfn; + dma_pfn++; + + num_pages--; + if (!num_pages) + break; + } + + if (!num_pages) + break; + }; + /* clang-format on */ + + /* Make sure our free_list update is flushed. */ + wmb(); + + pvr_gem_object_vunmap(free_list->obj); + + return 0; +} + +static int +pvr_free_list_insert_node_locked(struct pvr_free_list_node *free_list_node) +{ + struct pvr_free_list *free_list = free_list_node->free_list; + struct sg_table *sgt; + u32 start_page; + u32 offset; + int err; + + lockdep_assert_held(&free_list->lock); + + start_page = free_list->max_pages - free_list->current_pages - + free_list_node->num_pages; + offset = (start_page * FREE_LIST_ENTRY_SIZE) & + ~((u64)ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE - 1); + + sgt = drm_gem_shmem_get_pages_sgt(&free_list_node->mem_obj->base); + if (WARN_ON(IS_ERR(sgt))) + return PTR_ERR(sgt); + + err = pvr_free_list_insert_pages_locked(free_list, sgt, + offset, free_list_node->num_pages); + if (!err) + free_list->current_pages += free_list_node->num_pages; + + return err; +} + +static int +pvr_free_list_grow(struct pvr_free_list *free_list, u32 num_pages) +{ + struct pvr_device *pvr_dev = free_list->pvr_dev; + struct pvr_free_list_node *free_list_node; + int err; + + mutex_lock(&free_list->lock); + + if (num_pages & FREE_LIST_ALIGNMENT) { + err = -EINVAL; + goto err_unlock; + } + + free_list_node = kzalloc(sizeof(*free_list_node), GFP_KERNEL); + if (!free_list_node) { + err = -ENOMEM; + goto err_unlock; + } + + free_list_node->num_pages = num_pages; + free_list_node->free_list = free_list; + + free_list_node->mem_obj = pvr_gem_object_create(pvr_dev, + num_pages << + ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT, + PVR_BO_FW_FLAGS_DEVICE_CACHED); + if (IS_ERR(free_list_node->mem_obj)) { + err = PTR_ERR(free_list_node->mem_obj); + goto err_free; + } + + err = pvr_free_list_insert_node_locked(free_list_node); + if (err) + goto err_destroy_gem_object; + + list_add_tail(&free_list_node->node, &free_list->mem_block_list); + + /* + * Reserve a number ready pages to allow the FW to process OOM quickly + * and asynchronously request a grow. + */ + free_list->ready_pages = + calculate_free_list_ready_pages_locked(free_list, + free_list->current_pages); + free_list->current_pages -= free_list->ready_pages; + + mutex_unlock(&free_list->lock); + + return 0; + +err_destroy_gem_object: + pvr_gem_object_put(free_list_node->mem_obj); + +err_free: + kfree(free_list_node); + +err_unlock: + mutex_unlock(&free_list->lock); + + return err; +} + +void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelist_gs_data *req) +{ + struct pvr_free_list *free_list = pvr_free_list_lookup_id(pvr_dev, req->freelist_id); + struct rogue_fwif_kccb_cmd resp_cmd = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_FREELIST_GROW_UPDATE, + }; + struct rogue_fwif_freelist_gs_data *resp = &resp_cmd.cmd_data.free_list_gs_data; + u32 grow_pages = 0; + + /* If we don't have a freelist registered for this ID, we can't do much. */ + if (WARN_ON(!free_list)) + return; + + /* Since the FW made the request, it has already consumed the ready pages, + * update the host struct. + */ + free_list->current_pages += free_list->ready_pages; + free_list->ready_pages = 0; + + /* If the grow succeeds, update the grow_pages argument. */ + if (!pvr_free_list_grow(free_list, free_list->grow_pages)) + grow_pages = free_list->grow_pages; + + /* Now prepare the response and send it back to the FW. */ + pvr_fw_object_get_fw_addr(free_list->fw_obj, &resp->freelist_fw_addr); + resp->delta_pages = grow_pages; + resp->new_pages = free_list->current_pages + free_list->ready_pages; + resp->ready_pages = free_list->ready_pages; + pvr_free_list_put(free_list); + + WARN_ON(pvr_kccb_send_cmd(pvr_dev, &resp_cmd, NULL)); +} + +static void +pvr_free_list_free_node(struct pvr_free_list_node *free_list_node) +{ + pvr_gem_object_put(free_list_node->mem_obj); + + kfree(free_list_node); +} + +/** + * pvr_free_list_create() - Create a new free list and return an object pointer + * @pvr_file: Pointer to pvr_file structure. + * @args: Creation arguments from userspace. + * + * Return: + * * Pointer to new free_list, or + * * ERR_PTR(-%ENOMEM) on out of memory. + */ +struct pvr_free_list * +pvr_free_list_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args) +{ + struct pvr_free_list *free_list; + int err; + + /* Create and fill out the kernel structure */ + free_list = kzalloc(sizeof(*free_list), GFP_KERNEL); + + if (!free_list) + return ERR_PTR(-ENOMEM); + + kref_init(&free_list->ref_count); + INIT_LIST_HEAD(&free_list->mem_block_list); + INIT_LIST_HEAD(&free_list->hwrt_list); + mutex_init(&free_list->lock); + + err = free_list_create_kernel_structure(pvr_file, args, free_list); + if (err < 0) + goto err_free; + + /* Allocate global object ID for firmware. */ + err = xa_alloc(&pvr_file->pvr_dev->free_list_ids, + &free_list->fw_id, + free_list, + xa_limit_32b, + GFP_KERNEL); + if (err) + goto err_destroy_kernel_structure; + + err = free_list_create_fw_structure(pvr_file, args, free_list); + if (err < 0) + goto err_free_fw_id; + + err = pvr_free_list_grow(free_list, args->initial_num_pages); + if (err < 0) + goto err_fw_struct_cleanup; + + return free_list; + +err_fw_struct_cleanup: + WARN_ON(pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0)); + +err_free_fw_id: + xa_erase(&free_list->pvr_dev->free_list_ids, free_list->fw_id); + +err_destroy_kernel_structure: + free_list_destroy_kernel_structure(free_list); + +err_free: + mutex_destroy(&free_list->lock); + kfree(free_list); + + return ERR_PTR(err); +} + +static void +pvr_free_list_release(struct kref *ref_count) +{ + struct pvr_free_list *free_list = + container_of(ref_count, struct pvr_free_list, ref_count); + struct list_head *pos, *n; + int err; + + xa_erase(&free_list->pvr_dev->free_list_ids, free_list->fw_id); + + err = pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0); + if (err == -EBUSY) { + /* Flush the FWCCB to process any HWR or freelist reconstruction + * request that might keep the freelist busy, and try again. + */ + pvr_fwccb_process(free_list->pvr_dev); + err = pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0); + } + + WARN_ON(err); + + /* clang-format off */ + list_for_each_safe(pos, n, &free_list->mem_block_list) { + struct pvr_free_list_node *free_list_node = + container_of(pos, struct pvr_free_list_node, node); + + list_del(pos); + pvr_free_list_free_node(free_list_node); + } + /* clang-format on */ + + free_list_destroy_kernel_structure(free_list); + free_list_destroy_fw_structure(free_list); + mutex_destroy(&free_list->lock); + kfree(free_list); +} + +/** + * pvr_destroy_free_lists_for_file: Destroy any free lists associated with the + * given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all free lists associated with @pvr_file from the device free_list + * list and drops initial references. Free lists will then be destroyed once + * all outstanding references are dropped. + */ +void pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file) +{ + struct pvr_free_list *free_list; + unsigned long handle; + + xa_for_each(&pvr_file->free_list_handles, handle, free_list) { + (void)free_list; + pvr_free_list_put(xa_erase(&pvr_file->free_list_handles, handle)); + } +} + +/** + * pvr_free_list_put() - Release reference on free list + * @free_list: Pointer to list to release reference on + */ +void +pvr_free_list_put(struct pvr_free_list *free_list) +{ + if (free_list) + kref_put(&free_list->ref_count, pvr_free_list_release); +} + +void pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data) +{ + mutex_lock(&free_list->lock); + + list_add_tail(&hwrt_data->freelist_node, &free_list->hwrt_list); + + mutex_unlock(&free_list->lock); +} + +void pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data) +{ + mutex_lock(&free_list->lock); + + list_del(&hwrt_data->freelist_node); + + mutex_unlock(&free_list->lock); +} + +static void +pvr_free_list_reconstruct(struct pvr_device *pvr_dev, u32 freelist_id) +{ + struct pvr_free_list *free_list = pvr_free_list_lookup_id(pvr_dev, freelist_id); + struct pvr_free_list_node *free_list_node; + struct rogue_fwif_freelist *fw_data; + struct pvr_hwrt_data *hwrt_data; + + if (!free_list) + return; + + mutex_lock(&free_list->lock); + + /* Rebuild the free list based on the memory block list. */ + free_list->current_pages = 0; + + list_for_each_entry(free_list_node, &free_list->mem_block_list, node) + WARN_ON(pvr_free_list_insert_node_locked(free_list_node)); + + /* + * Remove the ready pages, which are reserved to allow the FW to process OOM quickly and + * asynchronously request a grow. + */ + free_list->current_pages -= free_list->ready_pages; + + fw_data = free_list->fw_data; + fw_data->current_stack_top = fw_data->current_pages - 1; + fw_data->allocated_page_count = 0; + fw_data->allocated_mmu_page_count = 0; + + /* Reset the state of any associated HWRTs. */ + list_for_each_entry(hwrt_data, &free_list->hwrt_list, freelist_node) { + struct rogue_fwif_hwrtdata *hwrt_fw_data = pvr_fw_object_vmap(hwrt_data->fw_obj); + + if (!WARN_ON(IS_ERR(hwrt_fw_data))) { + hwrt_fw_data->state = ROGUE_FWIF_RTDATA_STATE_HWR; + hwrt_fw_data->hwrt_data_flags &= ~HWRTDATA_HAS_LAST_GEOM; + } + + pvr_fw_object_vunmap(hwrt_data->fw_obj); + } + + mutex_unlock(&free_list->lock); + + pvr_free_list_put(free_list); +} + +void +pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req) +{ + struct rogue_fwif_kccb_cmd resp_cmd = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE, + }; + struct rogue_fwif_freelists_reconstruction_data *resp = + &resp_cmd.cmd_data.free_lists_reconstruction_data; + + for (u32 i = 0; i < req->freelist_count; i++) + pvr_free_list_reconstruct(pvr_dev, req->freelist_ids[i]); + + resp->freelist_count = req->freelist_count; + memcpy(resp->freelist_ids, req->freelist_ids, + req->freelist_count * sizeof(resp->freelist_ids[0])); + + WARN_ON(pvr_kccb_send_cmd(pvr_dev, &resp_cmd, NULL)); +} diff --git a/drivers/gpu/drm/imagination/pvr_free_list.h b/drivers/gpu/drm/imagination/pvr_free_list.h new file mode 100644 index 000000000000..bfb4f5fc622c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_free_list.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FREE_LIST_H +#define PVR_FREE_LIST_H + +#include +#include +#include +#include +#include +#include +#include + +#include "pvr_device.h" + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_gem_object; + +/* Forward declaration from pvr_hwrt.h. */ +struct pvr_hwrt_data; + +/** + * struct pvr_free_list_node - structure representing an allocation in the free + * list + */ +struct pvr_free_list_node { + /** @node: List node for &pvr_free_list.mem_block_list. */ + struct list_head node; + + /** @free_list: Pointer to owning free list. */ + struct pvr_free_list *free_list; + + /** @num_pages: Number of pages in this node. */ + u32 num_pages; + + /** @mem_obj: GEM object representing the pages in this node. */ + struct pvr_gem_object *mem_obj; +}; + +/** + * struct pvr_free_list - structure representing a free list + */ +struct pvr_free_list { + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to device that owns this object. */ + struct pvr_device *pvr_dev; + + /** @obj: GEM object representing the free list. */ + struct pvr_gem_object *obj; + + /** @fw_obj: FW object representing the FW-side structure. */ + struct pvr_fw_object *fw_obj; + + /** @fw_data: Pointer to CPU mapping of the FW-side structure. */ + struct rogue_fwif_freelist *fw_data; + + /** + * @lock: Mutex protecting modification of the free list. Must be held when accessing any + * of the members below. + */ + struct mutex lock; + + /** @fw_id: Firmware ID for this object. */ + u32 fw_id; + + /** @current_pages: Current number of pages in free list. */ + u32 current_pages; + + /** @max_pages: Maximum number of pages in free list. */ + u32 max_pages; + + /** @grow_pages: Pages to grow free list by per request. */ + u32 grow_pages; + + /** + * @grow_threshold: Percentage of FL memory used that should trigger a + * new grow request. + */ + u32 grow_threshold; + + /** + * @ready_pages: Number of pages reserved for FW to use while a grow + * request is being processed. + */ + u32 ready_pages; + + /** @mem_block_list: List of memory blocks in this free list. */ + struct list_head mem_block_list; + + /** @hwrt_list: List of HWRTs using this free list. */ + struct list_head hwrt_list; + + /** @initial_num_pages: Initial number of pages in free list. */ + u32 initial_num_pages; + + /** @free_list_gpu_addr: Address of free list in GPU address space. */ + u64 free_list_gpu_addr; +}; + +struct pvr_free_list * +pvr_free_list_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args); + +void +pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file); + +u32 +pvr_get_free_list_min_pages(struct pvr_device *pvr_dev); + +static __always_inline struct pvr_free_list * +pvr_free_list_get(struct pvr_free_list *free_list) +{ + if (free_list) + kref_get(&free_list->ref_count); + + return free_list; +} + +/** + * pvr_free_list_lookup() - Lookup free list pointer from handle and file + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on free list object. Call pvr_free_list_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, is not a free list, or + * does not belong to @pvr_file) + */ +static __always_inline struct pvr_free_list * +pvr_free_list_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_free_list *free_list; + + xa_lock(&pvr_file->free_list_handles); + free_list = pvr_free_list_get(xa_load(&pvr_file->free_list_handles, handle)); + xa_unlock(&pvr_file->free_list_handles); + + return free_list; +} + +/** + * pvr_free_list_lookup_id() - Lookup free list pointer from FW ID + * @pvr_dev: Device pointer. + * @id: FW object ID. + * + * Takes reference on free list object. Call pvr_free_list_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a free list) + */ +static __always_inline struct pvr_free_list * +pvr_free_list_lookup_id(struct pvr_device *pvr_dev, u32 id) +{ + struct pvr_free_list *free_list; + + xa_lock(&pvr_dev->free_list_ids); + + /* Contexts are removed from the ctx_ids set in the context release path, + * meaning the ref_count reached zero before they get removed. We need + * to make sure we're not trying to acquire a context that's being + * destroyed. + */ + free_list = xa_load(&pvr_dev->free_list_ids, id); + if (free_list && !kref_get_unless_zero(&free_list->ref_count)) + free_list = NULL; + xa_unlock(&pvr_dev->free_list_ids); + + return free_list; +} + +void +pvr_free_list_put(struct pvr_free_list *free_list); + +void +pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data); +void +pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data); + +void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelist_gs_data *req); + +void +pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req); + +#endif /* PVR_FREE_LIST_H */ diff --git a/drivers/gpu/drm/imagination/pvr_hwrt.c b/drivers/gpu/drm/imagination/pvr_hwrt.c new file mode 100644 index 000000000000..c4213c18489e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_hwrt.c @@ -0,0 +1,549 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_free_list.h" +#include "pvr_hwrt.h" +#include "pvr_gem.h" +#include "pvr_rogue_cr_defs_client.h" +#include "pvr_rogue_fwif.h" + +#include +#include +#include +#include +#include +#include + +static_assert(ROGUE_FWIF_NUM_RTDATAS == 2); +static_assert(ROGUE_FWIF_NUM_GEOMDATAS == 1); +static_assert(ROGUE_FWIF_NUM_RTDATA_FREELISTS == 2); + +/* + * struct pvr_rt_mtile_info - Render target macrotile information + */ +struct pvr_rt_mtile_info { + u32 mtile_x[3]; + u32 mtile_y[3]; + u32 tile_max_x; + u32 tile_max_y; + u32 tile_size_x; + u32 tile_size_y; + u32 num_tiles_x; + u32 num_tiles_y; +}; + +/* Size of Shadow Render Target Cache entry */ +#define SRTC_ENTRY_SIZE sizeof(u32) +/* Size of Renders Accumulation Array entry */ +#define RAA_ENTRY_SIZE sizeof(u32) + +static int +hwrt_init_kernel_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct pvr_hwrt_dataset *hwrt) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + int err; + int i; + + hwrt->pvr_dev = pvr_dev; + hwrt->max_rts = args->layers; + + /* Get pointers to the free lists */ + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + hwrt->free_lists[i] = pvr_free_list_lookup(pvr_file, args->free_list_handles[i]); + if (!hwrt->free_lists[i]) { + err = -EINVAL; + goto err_put_free_lists; + } + } + + if (hwrt->free_lists[ROGUE_FW_LOCAL_FREELIST]->current_pages < + pvr_get_free_list_min_pages(pvr_dev)) { + err = -EINVAL; + goto err_put_free_lists; + } + + return 0; + +err_put_free_lists: + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + pvr_free_list_put(hwrt->free_lists[i]); + hwrt->free_lists[i] = NULL; + } + + return err; +} + +static void +hwrt_fini_kernel_structure(struct pvr_hwrt_dataset *hwrt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + pvr_free_list_put(hwrt->free_lists[i]); + hwrt->free_lists[i] = NULL; + } +} + +static void +hwrt_fini_common_fw_structure(struct pvr_hwrt_dataset *hwrt) +{ + pvr_fw_object_destroy(hwrt->common_fw_obj); +} + +static int +get_cr_isp_mtile_size_val(struct pvr_device *pvr_dev, u32 samples, + struct pvr_rt_mtile_info *info, u32 *value_out) +{ + u32 x = info->mtile_x[0]; + u32 y = info->mtile_y[0]; + u32 samples_per_pixel; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, isp_samples_per_pixel, &samples_per_pixel); + if (err) + return err; + + if (samples_per_pixel == 1) { + if (samples >= 4) + x <<= 1; + if (samples >= 2) + y <<= 1; + } else if (samples_per_pixel == 2) { + if (samples >= 8) + x <<= 1; + if (samples >= 4) + y <<= 1; + } else if (samples_per_pixel == 4) { + if (samples >= 8) + y <<= 1; + } else { + WARN(true, "Unsupported ISP samples per pixel value"); + return -EINVAL; + } + + *value_out = ((x << ROGUE_CR_ISP_MTILE_SIZE_X_SHIFT) & ~ROGUE_CR_ISP_MTILE_SIZE_X_CLRMSK) | + ((y << ROGUE_CR_ISP_MTILE_SIZE_Y_SHIFT) & ~ROGUE_CR_ISP_MTILE_SIZE_Y_CLRMSK); + + return 0; +} + +static int +get_cr_multisamplectl_val(u32 samples, bool y_flip, u64 *value_out) +{ + static const struct { + u8 x[8]; + u8 y[8]; + } sample_positions[4] = { + /* 1 sample */ + { + .x = { 8 }, + .y = { 8 }, + }, + /* 2 samples */ + { + .x = { 12, 4 }, + .y = { 12, 4 }, + }, + /* 4 samples */ + { + .x = { 6, 14, 2, 10 }, + .y = { 2, 6, 10, 14 }, + }, + /* 8 samples */ + { + .x = { 9, 7, 13, 5, 3, 1, 11, 15 }, + .y = { 5, 11, 9, 3, 13, 7, 15, 1 }, + }, + }; + const int idx = fls(samples) - 1; + u64 value = 0; + + if (idx < 0 || idx > 3) + return -EINVAL; + + for (u32 i = 0; i < 8; i++) { + value |= ((u64)sample_positions[idx].x[i]) << (i * 8); + if (y_flip) + value |= (((u64)(16 - sample_positions[idx].y[i]) & 0xf)) << (i * 8 + 4); + else + value |= ((u64)sample_positions[idx].y[i]) << (i * 8 + 4); + } + + *value_out = value; + + return 0; +} + +static int +get_cr_te_aa_val(struct pvr_device *pvr_dev, u32 samples, u32 *value_out) +{ + u32 samples_per_pixel; + u32 value = 0; + int err = 0; + + err = PVR_FEATURE_VALUE(pvr_dev, isp_samples_per_pixel, &samples_per_pixel); + if (err) + return err; + + switch (samples_per_pixel) { + case 1: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_Y_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_X_EN; + break; + case 2: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_X2_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_Y_EN; + if (samples >= 8) + value |= ROGUE_CR_TE_AA_X_EN; + break; + case 4: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_X2_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_Y2_EN; + if (samples >= 8) + value |= ROGUE_CR_TE_AA_Y_EN; + break; + default: + WARN(true, "Unsupported ISP samples per pixel value"); + return -EINVAL; + } + + *value_out = value; + + return 0; +} + +static void +hwrtdata_common_init(void *cpu_ptr, void *priv) +{ + struct pvr_hwrt_dataset *hwrt = priv; + + memcpy(cpu_ptr, &hwrt->common, sizeof(hwrt->common)); +} + +static int +hwrt_init_common_fw_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct pvr_hwrt_dataset *hwrt) +{ + struct drm_pvr_create_hwrt_geom_data_args *geom_data_args = &args->geom_data_args; + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct pvr_rt_mtile_info info; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, tile_size_x, &info.tile_size_x); + if (WARN_ON(err)) + return err; + + err = PVR_FEATURE_VALUE(pvr_dev, tile_size_y, &info.tile_size_y); + if (WARN_ON(err)) + return err; + + info.num_tiles_x = DIV_ROUND_UP(args->width, info.tile_size_x); + info.num_tiles_y = DIV_ROUND_UP(args->height, info.tile_size_y); + + if (PVR_HAS_FEATURE(pvr_dev, simple_parameter_format_version)) { + u32 parameter_format; + + err = PVR_FEATURE_VALUE(pvr_dev, simple_parameter_format_version, + ¶meter_format); + if (WARN_ON(err)) + return err; + + WARN_ON(parameter_format != 2); + + /* + * Set up 16 macrotiles with a multiple of 2x2 tiles per macrotile, which is + * aligned to a tile group. + */ + info.mtile_x[0] = DIV_ROUND_UP(info.num_tiles_x, 8) * 2; + info.mtile_y[0] = DIV_ROUND_UP(info.num_tiles_y, 8) * 2; + info.mtile_x[1] = 0; + info.mtile_y[1] = 0; + info.mtile_x[2] = 0; + info.mtile_y[2] = 0; + info.tile_max_x = round_up(info.num_tiles_x, 2) - 1; + info.tile_max_y = round_up(info.num_tiles_y, 2) - 1; + } else { + /* Set up 16 macrotiles with a multiple of 4x4 tiles per macrotile. */ + info.mtile_x[0] = round_up(DIV_ROUND_UP(info.num_tiles_x, 4), 4); + info.mtile_y[0] = round_up(DIV_ROUND_UP(info.num_tiles_y, 4), 4); + info.mtile_x[1] = info.mtile_x[0] * 2; + info.mtile_y[1] = info.mtile_y[0] * 2; + info.mtile_x[2] = info.mtile_x[0] * 3; + info.mtile_y[2] = info.mtile_y[0] * 3; + info.tile_max_x = info.num_tiles_x - 1; + info.tile_max_y = info.num_tiles_y - 1; + } + + hwrt->common.geom_caches_need_zeroing = false; + + hwrt->common.isp_merge_lower_x = args->isp_merge_lower_x; + hwrt->common.isp_merge_lower_y = args->isp_merge_lower_y; + hwrt->common.isp_merge_upper_x = args->isp_merge_upper_x; + hwrt->common.isp_merge_upper_y = args->isp_merge_upper_y; + hwrt->common.isp_merge_scale_x = args->isp_merge_scale_x; + hwrt->common.isp_merge_scale_y = args->isp_merge_scale_y; + + err = get_cr_multisamplectl_val(args->samples, false, + &hwrt->common.multi_sample_ctl); + if (err) + return err; + + err = get_cr_multisamplectl_val(args->samples, true, + &hwrt->common.flipped_multi_sample_ctl); + if (err) + return err; + + hwrt->common.mtile_stride = info.mtile_x[0] * info.mtile_y[0]; + + err = get_cr_te_aa_val(pvr_dev, args->samples, &hwrt->common.teaa); + if (err) + return err; + + hwrt->common.screen_pixel_max = + (((args->width - 1) << ROGUE_CR_PPP_SCREEN_PIXXMAX_SHIFT) & + ~ROGUE_CR_PPP_SCREEN_PIXXMAX_CLRMSK) | + (((args->height - 1) << ROGUE_CR_PPP_SCREEN_PIXYMAX_SHIFT) & + ~ROGUE_CR_PPP_SCREEN_PIXYMAX_CLRMSK); + + hwrt->common.te_screen = + ((info.tile_max_x << ROGUE_CR_TE_SCREEN_XMAX_SHIFT) & + ~ROGUE_CR_TE_SCREEN_XMAX_CLRMSK) | + ((info.tile_max_y << ROGUE_CR_TE_SCREEN_YMAX_SHIFT) & + ~ROGUE_CR_TE_SCREEN_YMAX_CLRMSK); + hwrt->common.te_mtile1 = + ((info.mtile_x[0] << ROGUE_CR_TE_MTILE1_X1_SHIFT) & ~ROGUE_CR_TE_MTILE1_X1_CLRMSK) | + ((info.mtile_x[1] << ROGUE_CR_TE_MTILE1_X2_SHIFT) & ~ROGUE_CR_TE_MTILE1_X2_CLRMSK) | + ((info.mtile_x[2] << ROGUE_CR_TE_MTILE1_X3_SHIFT) & ~ROGUE_CR_TE_MTILE1_X3_CLRMSK); + hwrt->common.te_mtile2 = + ((info.mtile_y[0] << ROGUE_CR_TE_MTILE2_Y1_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y1_CLRMSK) | + ((info.mtile_y[1] << ROGUE_CR_TE_MTILE2_Y2_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y2_CLRMSK) | + ((info.mtile_y[2] << ROGUE_CR_TE_MTILE2_Y3_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y3_CLRMSK); + + err = get_cr_isp_mtile_size_val(pvr_dev, args->samples, &info, + &hwrt->common.isp_mtile_size); + if (err) + return err; + + hwrt->common.tpc_stride = geom_data_args->tpc_stride; + hwrt->common.tpc_size = geom_data_args->tpc_size; + + hwrt->common.rgn_header_size = args->region_header_size; + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrtdata_common), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, hwrtdata_common_init, hwrt, + &hwrt->common_fw_obj); + + return err; +} + +static void +hwrt_fw_data_init(void *cpu_ptr, void *priv) +{ + struct pvr_hwrt_data *hwrt_data = priv; + + memcpy(cpu_ptr, &hwrt_data->data, sizeof(hwrt_data->data)); +} + +static int +hwrt_data_init_fw_structure(struct pvr_file *pvr_file, + struct pvr_hwrt_dataset *hwrt, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct drm_pvr_create_hwrt_rt_data_args *rt_data_args, + struct pvr_hwrt_data *hwrt_data) +{ + struct drm_pvr_create_hwrt_geom_data_args *geom_data_args = &args->geom_data_args; + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct rogue_fwif_rta_ctl *rta_ctl; + int free_list_i; + int err; + + pvr_fw_object_get_fw_addr(hwrt->common_fw_obj, + &hwrt_data->data.hwrt_data_common_fw_addr); + + for (free_list_i = 0; free_list_i < ARRAY_SIZE(hwrt->free_lists); free_list_i++) { + pvr_fw_object_get_fw_addr(hwrt->free_lists[free_list_i]->fw_obj, + &hwrt_data->data.freelists_fw_addr[free_list_i]); + } + + hwrt_data->data.tail_ptrs_dev_addr = geom_data_args->tpc_dev_addr; + hwrt_data->data.vheap_table_dev_addr = geom_data_args->vheap_table_dev_addr; + hwrt_data->data.rtc_dev_addr = geom_data_args->rtc_dev_addr; + + hwrt_data->data.pm_mlist_dev_addr = rt_data_args->pm_mlist_dev_addr; + hwrt_data->data.macrotile_array_dev_addr = rt_data_args->macrotile_array_dev_addr; + hwrt_data->data.rgn_header_dev_addr = rt_data_args->region_header_dev_addr; + + rta_ctl = &hwrt_data->data.rta_ctl; + + rta_ctl->render_target_index = 0; + rta_ctl->active_render_targets = 0; + rta_ctl->valid_render_targets_fw_addr = 0; + rta_ctl->rta_num_partial_renders_fw_addr = 0; + rta_ctl->max_rts = args->layers; + + if (args->layers > 1) { + err = pvr_fw_object_create(pvr_dev, args->layers * SRTC_ENTRY_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &hwrt_data->srtc_obj); + if (err) + return err; + pvr_fw_object_get_fw_addr(hwrt_data->srtc_obj, + &rta_ctl->valid_render_targets_fw_addr); + + err = pvr_fw_object_create(pvr_dev, args->layers * RAA_ENTRY_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &hwrt_data->raa_obj); + if (err) + goto err_put_shadow_rt_cache; + pvr_fw_object_get_fw_addr(hwrt_data->raa_obj, + &rta_ctl->rta_num_partial_renders_fw_addr); + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrtdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + hwrt_fw_data_init, hwrt_data, &hwrt_data->fw_obj); + if (err) + goto err_put_raa_obj; + + pvr_free_list_add_hwrt(hwrt->free_lists[0], hwrt_data); + + return 0; + +err_put_raa_obj: + if (args->layers > 1) + pvr_fw_object_destroy(hwrt_data->raa_obj); + +err_put_shadow_rt_cache: + if (args->layers > 1) + pvr_fw_object_destroy(hwrt_data->srtc_obj); + + return err; +} + +static void +hwrt_data_fini_fw_structure(struct pvr_hwrt_dataset *hwrt, int hwrt_nr) +{ + struct pvr_hwrt_data *hwrt_data = &hwrt->data[hwrt_nr]; + + pvr_free_list_remove_hwrt(hwrt->free_lists[0], hwrt_data); + + if (hwrt->max_rts > 1) { + pvr_fw_object_destroy(hwrt_data->raa_obj); + pvr_fw_object_destroy(hwrt_data->srtc_obj); + } + + pvr_fw_object_destroy(hwrt_data->fw_obj); +} + +/** + * pvr_hwrt_dataset_create() - Create a new HWRT dataset + * @pvr_file: Pointer to pvr_file structure. + * @args: Creation arguments from userspace. + * + * Return: + * * Pointer to new HWRT, or + * * ERR_PTR(-%ENOMEM) on out of memory. + */ +struct pvr_hwrt_dataset * +pvr_hwrt_dataset_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args) +{ + struct pvr_hwrt_dataset *hwrt; + int err; + + /* Create and fill out the kernel structure */ + hwrt = kzalloc(sizeof(*hwrt), GFP_KERNEL); + + if (!hwrt) + return ERR_PTR(-ENOMEM); + + kref_init(&hwrt->ref_count); + + err = hwrt_init_kernel_structure(pvr_file, args, hwrt); + if (err < 0) + goto err_free; + + err = hwrt_init_common_fw_structure(pvr_file, args, hwrt); + if (err < 0) + goto err_free; + + for (int i = 0; i < ARRAY_SIZE(hwrt->data); i++) { + err = hwrt_data_init_fw_structure(pvr_file, hwrt, args, + &args->rt_data_args[i], + &hwrt->data[i]); + if (err < 0) { + i--; + /* Destroy already created structures. */ + for (; i >= 0; i--) + hwrt_data_fini_fw_structure(hwrt, i); + goto err_free; + } + + hwrt->data[i].hwrt_dataset = hwrt; + } + + return hwrt; + +err_free: + pvr_hwrt_dataset_put(hwrt); + + return ERR_PTR(err); +} + +static void +pvr_hwrt_dataset_release(struct kref *ref_count) +{ + struct pvr_hwrt_dataset *hwrt = + container_of(ref_count, struct pvr_hwrt_dataset, ref_count); + + for (int i = ARRAY_SIZE(hwrt->data) - 1; i >= 0; i--) { + WARN_ON(pvr_fw_structure_cleanup(hwrt->pvr_dev, ROGUE_FWIF_CLEANUP_HWRTDATA, + hwrt->data[i].fw_obj, 0)); + hwrt_data_fini_fw_structure(hwrt, i); + } + + hwrt_fini_common_fw_structure(hwrt); + hwrt_fini_kernel_structure(hwrt); + + kfree(hwrt); +} + +/** + * pvr_destroy_hwrt_datasets_for_file: Destroy any HWRT datasets associated + * with the given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all HWRT datasets associated with @pvr_file from the device + * hwrt_dataset list and drops initial references. HWRT datasets will then be + * destroyed once all outstanding references are dropped. + */ +void pvr_destroy_hwrt_datasets_for_file(struct pvr_file *pvr_file) +{ + struct pvr_hwrt_dataset *hwrt; + unsigned long handle; + + xa_for_each(&pvr_file->hwrt_handles, handle, hwrt) { + (void)hwrt; + pvr_hwrt_dataset_put(xa_erase(&pvr_file->hwrt_handles, handle)); + } +} + +/** + * pvr_hwrt_dataset_put() - Release reference on HWRT dataset + * @hwrt: Pointer to HWRT dataset to release reference on + */ +void +pvr_hwrt_dataset_put(struct pvr_hwrt_dataset *hwrt) +{ + if (hwrt) + kref_put(&hwrt->ref_count, pvr_hwrt_dataset_release); +} diff --git a/drivers/gpu/drm/imagination/pvr_hwrt.h b/drivers/gpu/drm/imagination/pvr_hwrt.h new file mode 100644 index 000000000000..76992948d047 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_hwrt.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_HWRT_H +#define PVR_HWRT_H + +#include +#include +#include +#include +#include +#include + +#include "pvr_device.h" +#include "pvr_rogue_fwif_shared.h" + +/* Forward declaration from pvr_free_list.h. */ +struct pvr_free_list; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/** + * struct pvr_hwrt_data - structure representing HWRT data + */ +struct pvr_hwrt_data { + /** @fw_obj: FW object representing the FW-side structure. */ + struct pvr_fw_object *fw_obj; + + /** @data: Local copy of FW-side structure. */ + struct rogue_fwif_hwrtdata data; + + /** @freelist_node: List node connecting this HWRT to the local freelist. */ + struct list_head freelist_node; + + /** + * @srtc_obj: FW object representing shadow render target cache. + * + * Only valid if @max_rts > 1. + */ + struct pvr_fw_object *srtc_obj; + + /** + * @raa_obj: FW object representing renders accumulation array. + * + * Only valid if @max_rts > 1. + */ + struct pvr_fw_object *raa_obj; + + /** @hwrt_dataset: Back pointer to owning HWRT dataset. */ + struct pvr_hwrt_dataset *hwrt_dataset; +}; + +/** + * struct pvr_hwrt_dataset - structure representing a HWRT data set. + */ +struct pvr_hwrt_dataset { + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to device that owns this object. */ + struct pvr_device *pvr_dev; + + /** @common_fw_obj: FW object representing common FW-side structure. */ + struct pvr_fw_object *common_fw_obj; + + struct rogue_fwif_hwrtdata_common common; + + /** @data: HWRT data structures belonging to this set. */ + struct pvr_hwrt_data data[ROGUE_FWIF_NUM_RTDATAS]; + + /** @free_lists: Free lists used by HWRT data set. */ + struct pvr_free_list *free_lists[ROGUE_FWIF_NUM_RTDATA_FREELISTS]; + + /** @max_rts: Maximum render targets for this HWRT data set. */ + u16 max_rts; +}; + +struct pvr_hwrt_dataset * +pvr_hwrt_dataset_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args); + +void +pvr_destroy_hwrt_datasets_for_file(struct pvr_file *pvr_file); + +/** + * pvr_hwrt_dataset_lookup() - Lookup HWRT dataset pointer from handle + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on dataset object. Call pvr_hwrt_dataset_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a HWRT + * dataset) + */ +static __always_inline struct pvr_hwrt_dataset * +pvr_hwrt_dataset_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_hwrt_dataset *hwrt; + + xa_lock(&pvr_file->hwrt_handles); + hwrt = xa_load(&pvr_file->hwrt_handles, handle); + + if (hwrt) + kref_get(&hwrt->ref_count); + + xa_unlock(&pvr_file->hwrt_handles); + + return hwrt; +} + +void +pvr_hwrt_dataset_put(struct pvr_hwrt_dataset *hwrt); + +/** + * pvr_hwrt_data_lookup() - Lookup HWRT data pointer from handle and index + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * @index: Index of RT data within dataset. + * + * Takes reference on dataset object. Call pvr_hwrt_data_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a HWRT + * dataset, or index is out of range) + */ +static __always_inline struct pvr_hwrt_data * +pvr_hwrt_data_lookup(struct pvr_file *pvr_file, u32 handle, u32 index) +{ + struct pvr_hwrt_dataset *hwrt_dataset = pvr_hwrt_dataset_lookup(pvr_file, handle); + + if (hwrt_dataset) { + if (index < ARRAY_SIZE(hwrt_dataset->data)) + return &hwrt_dataset->data[index]; + + pvr_hwrt_dataset_put(hwrt_dataset); + } + + return NULL; +} + +/** + * pvr_hwrt_data_put() - Release reference on HWRT data + * @hwrt: Pointer to HWRT data to release reference on + */ +static __always_inline void +pvr_hwrt_data_put(struct pvr_hwrt_data *hwrt) +{ + if (hwrt) + pvr_hwrt_dataset_put(hwrt->hwrt_dataset); +} + +static __always_inline struct pvr_hwrt_data * +pvr_hwrt_data_get(struct pvr_hwrt_data *hwrt) +{ + if (hwrt) + kref_get(&hwrt->hwrt_dataset->ref_count); + + return hwrt; +} + +#endif /* PVR_HWRT_H */ From d2d79d29bb98a32c511f7339a8e93b47544fdeac Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:37 +0000 Subject: [PATCH 1188/7721] drm/imagination: Implement context creation/destruction ioctls Implement ioctls for the creation and destruction of contexts. Contexts are used for job submission and each is associated with a particular job type. Changes since v8: - Fixed one error path in pvr_stream_process_1() - Corrected license identifiers Changes since v5: - Fix context release in final error path in pvr_context_create() Changes since v3: - Use drm_dev_{enter,exit} Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/ac474a1f7dda2582d290798e4837140a2989aa2a.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 4 + drivers/gpu/drm/imagination/pvr_cccb.c | 267 ++++++++++++++ drivers/gpu/drm/imagination/pvr_cccb.h | 109 ++++++ drivers/gpu/drm/imagination/pvr_context.c | 341 ++++++++++++++++++ drivers/gpu/drm/imagination/pvr_context.h | 161 +++++++++ drivers/gpu/drm/imagination/pvr_device.h | 21 ++ drivers/gpu/drm/imagination/pvr_drv.c | 29 +- drivers/gpu/drm/imagination/pvr_stream.c | 285 +++++++++++++++ drivers/gpu/drm/imagination/pvr_stream.h | 75 ++++ drivers/gpu/drm/imagination/pvr_stream_defs.c | 125 +++++++ drivers/gpu/drm/imagination/pvr_stream_defs.h | 16 + 11 files changed, 1431 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_cccb.c create mode 100644 drivers/gpu/drm/imagination/pvr_cccb.h create mode 100644 drivers/gpu/drm/imagination/pvr_context.c create mode 100644 drivers/gpu/drm/imagination/pvr_context.h create mode 100644 drivers/gpu/drm/imagination/pvr_stream.c create mode 100644 drivers/gpu/drm/imagination/pvr_stream.h create mode 100644 drivers/gpu/drm/imagination/pvr_stream_defs.c create mode 100644 drivers/gpu/drm/imagination/pvr_stream_defs.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 2bd501018d5d..7f7bea8c60c4 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -5,6 +5,8 @@ subdir-ccflags-y := -I$(srctree)/$(src) powervr-y := \ pvr_ccb.o \ + pvr_cccb.o \ + pvr_context.o \ pvr_device.o \ pvr_device_info.o \ pvr_drv.o \ @@ -18,6 +20,8 @@ powervr-y := \ pvr_hwrt.o \ pvr_mmu.o \ pvr_power.o \ + pvr_stream.o \ + pvr_stream_defs.o \ pvr_vm.o \ pvr_vm_mips.o diff --git a/drivers/gpu/drm/imagination/pvr_cccb.c b/drivers/gpu/drm/imagination/pvr_cccb.c new file mode 100644 index 000000000000..4fabab41bea7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_cccb.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_ccb.h" +#include "pvr_cccb.h" +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" + +#include +#include +#include +#include +#include + +static __always_inline u32 +get_ccb_space(u32 w_off, u32 r_off, u32 ccb_size) +{ + return (((r_off) - (w_off)) + ((ccb_size) - 1)) & ((ccb_size) - 1); +} + +static void +cccb_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_cccb_ctl *ctrl = cpu_ptr; + struct pvr_cccb *pvr_cccb = priv; + + WRITE_ONCE(ctrl->write_offset, 0); + WRITE_ONCE(ctrl->read_offset, 0); + WRITE_ONCE(ctrl->dep_offset, 0); + WRITE_ONCE(ctrl->wrap_mask, pvr_cccb->wrap_mask); +} + +/** + * pvr_cccb_init() - Initialise a Client CCB + * @pvr_dev: Device pointer. + * @pvr_cccb: Pointer to Client CCB structure to initialise. + * @size_log2: Log2 size of Client CCB in bytes. + * @name: Name of owner of Client CCB. Used for fence context. + * + * Return: + * * Zero on success, or + * * Any error code returned by pvr_fw_object_create_and_map(). + */ +int +pvr_cccb_init(struct pvr_device *pvr_dev, struct pvr_cccb *pvr_cccb, + u32 size_log2, const char *name) +{ + size_t size = 1 << size_log2; + int err; + + pvr_cccb->size = size; + pvr_cccb->write_offset = 0; + pvr_cccb->wrap_mask = size - 1; + + /* + * Map CCCB and control structure as uncached, so we don't have to flush + * CPU cache repeatedly when polling for space. + */ + pvr_cccb->ctrl = pvr_fw_object_create_and_map(pvr_dev, sizeof(*pvr_cccb->ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + cccb_ctrl_init, pvr_cccb, + &pvr_cccb->ctrl_obj); + if (IS_ERR(pvr_cccb->ctrl)) + return PTR_ERR(pvr_cccb->ctrl); + + pvr_cccb->cccb = pvr_fw_object_create_and_map(pvr_dev, size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_cccb->cccb_obj); + if (IS_ERR(pvr_cccb->cccb)) { + err = PTR_ERR(pvr_cccb->cccb); + goto err_free_ctrl; + } + + pvr_fw_object_get_fw_addr(pvr_cccb->ctrl_obj, &pvr_cccb->ctrl_fw_addr); + pvr_fw_object_get_fw_addr(pvr_cccb->cccb_obj, &pvr_cccb->cccb_fw_addr); + + return 0; + +err_free_ctrl: + pvr_fw_object_unmap_and_destroy(pvr_cccb->ctrl_obj); + + return err; +} + +/** + * pvr_cccb_fini() - Release Client CCB structure + * @pvr_cccb: Client CCB to release. + */ +void +pvr_cccb_fini(struct pvr_cccb *pvr_cccb) +{ + pvr_fw_object_unmap_and_destroy(pvr_cccb->cccb_obj); + pvr_fw_object_unmap_and_destroy(pvr_cccb->ctrl_obj); +} + +/** + * pvr_cccb_cmdseq_fits() - Check if a command sequence fits in the CCCB + * @pvr_cccb: Target Client CCB. + * @size: Size of the command sequence. + * + * Check if a command sequence fits in the CCCB we have at hand. + * + * Return: + * * true if the command sequence fits in the CCCB, or + * * false otherwise. + */ +bool pvr_cccb_cmdseq_fits(struct pvr_cccb *pvr_cccb, size_t size) +{ + struct rogue_fwif_cccb_ctl *ctrl = pvr_cccb->ctrl; + u32 read_offset, remaining; + bool fits = false; + + read_offset = READ_ONCE(ctrl->read_offset); + remaining = pvr_cccb->size - pvr_cccb->write_offset; + + /* Always ensure we have enough room for a padding command at the end of the CCCB. + * If our command sequence does not fit, reserve the remaining space for a padding + * command. + */ + if (size + PADDING_COMMAND_SIZE > remaining) + size += remaining; + + if (get_ccb_space(pvr_cccb->write_offset, read_offset, pvr_cccb->size) >= size) + fits = true; + + return fits; +} + +/** + * pvr_cccb_write_command_with_header() - Write a command + command header to a + * Client CCB + * @pvr_cccb: Target Client CCB. + * @cmd_type: Client CCB command type. Must be one of %ROGUE_FWIF_CCB_CMD_TYPE_*. + * @cmd_size: Size of command in bytes. + * @cmd_data: Pointer to command to write. + * @ext_job_ref: External job reference. + * @int_job_ref: Internal job reference. + * + * Caller must make sure there's enough space in CCCB to queue this command. This + * can be done by calling pvr_cccb_cmdseq_fits(). + * + * This function is not protected by any lock. The caller must ensure there's + * no concurrent caller, which should be guaranteed by the drm_sched model (job + * submission is serialized in drm_sched_main()). + */ +void +pvr_cccb_write_command_with_header(struct pvr_cccb *pvr_cccb, u32 cmd_type, u32 cmd_size, + void *cmd_data, u32 ext_job_ref, u32 int_job_ref) +{ + u32 sz_with_hdr = pvr_cccb_get_size_of_cmd_with_hdr(cmd_size); + struct rogue_fwif_ccb_cmd_header cmd_header = { + .cmd_type = cmd_type, + .cmd_size = ALIGN(cmd_size, 8), + .ext_job_ref = ext_job_ref, + .int_job_ref = int_job_ref, + }; + struct rogue_fwif_cccb_ctl *ctrl = pvr_cccb->ctrl; + u32 remaining = pvr_cccb->size - pvr_cccb->write_offset; + u32 required_size, cccb_space, read_offset; + + /* + * Always ensure we have enough room for a padding command at the end of + * the CCCB. + */ + if (remaining < sz_with_hdr + PADDING_COMMAND_SIZE) { + /* + * Command would need to wrap, so we need to pad the remainder + * of the CCCB. + */ + required_size = sz_with_hdr + remaining; + } else { + required_size = sz_with_hdr; + } + + read_offset = READ_ONCE(ctrl->read_offset); + cccb_space = get_ccb_space(pvr_cccb->write_offset, read_offset, pvr_cccb->size); + if (WARN_ON(cccb_space < required_size)) + return; + + if (required_size != sz_with_hdr) { + /* Add padding command */ + struct rogue_fwif_ccb_cmd_header pad_cmd = { + .cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_PADDING, + .cmd_size = remaining - sizeof(pad_cmd), + }; + + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset], &pad_cmd, sizeof(pad_cmd)); + pvr_cccb->write_offset = 0; + } + + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset], &cmd_header, sizeof(cmd_header)); + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset + sizeof(cmd_header)], cmd_data, cmd_size); + pvr_cccb->write_offset += sz_with_hdr; +} + +static void fill_cmd_kick_data(struct pvr_cccb *cccb, u32 ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + struct rogue_fwif_kccb_cmd_kick_data *k) +{ + k->context_fw_addr = ctx_fw_addr; + k->client_woff_update = cccb->write_offset; + k->client_wrap_mask_update = cccb->wrap_mask; + + if (hwrt) { + u32 cleanup_state_offset = offsetof(struct rogue_fwif_hwrtdata, cleanup_state); + + pvr_fw_object_get_fw_addr_offset(hwrt->fw_obj, cleanup_state_offset, + &k->cleanup_ctl_fw_addr[k->num_cleanup_ctl++]); + } +} + +/** + * pvr_cccb_send_kccb_kick: Send KCCB kick to trigger command processing + * @pvr_dev: Device pointer. + * @pvr_cccb: Pointer to CCCB to process. + * @cctx_fw_addr: FW virtual address for context owning this Client CCB. + * @hwrt: HWRT data set associated with this kick. May be %NULL. + * + * You must call pvr_kccb_reserve_slot() and wait for the returned fence to + * signal (if this function didn't return NULL) before calling + * pvr_cccb_send_kccb_kick(). + */ +void +pvr_cccb_send_kccb_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *pvr_cccb, u32 cctx_fw_addr, + struct pvr_hwrt_data *hwrt) +{ + struct rogue_fwif_kccb_cmd cmd_kick = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_KICK, + }; + + fill_cmd_kick_data(pvr_cccb, cctx_fw_addr, hwrt, &cmd_kick.cmd_data.cmd_kick_data); + + /* Make sure the writes to the CCCB are flushed before sending the KICK. */ + wmb(); + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, &cmd_kick, NULL); +} + +void +pvr_cccb_send_kccb_combined_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *geom_cccb, + struct pvr_cccb *frag_cccb, + u32 geom_ctx_fw_addr, + u32 frag_ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + bool frag_is_pr) +{ + struct rogue_fwif_kccb_cmd cmd_kick = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_COMBINED_GEOM_FRAG_KICK, + }; + + fill_cmd_kick_data(geom_cccb, geom_ctx_fw_addr, hwrt, + &cmd_kick.cmd_data.combined_geom_frag_cmd_kick_data.geom_cmd_kick_data); + + /* If this is a partial-render job, we don't attach resources to cleanup-ctl array, + * because the resources are already retained by the geometry job. + */ + fill_cmd_kick_data(frag_cccb, frag_ctx_fw_addr, frag_is_pr ? NULL : hwrt, + &cmd_kick.cmd_data.combined_geom_frag_cmd_kick_data.frag_cmd_kick_data); + + /* Make sure the writes to the CCCB are flushed before sending the KICK. */ + wmb(); + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, &cmd_kick, NULL); +} diff --git a/drivers/gpu/drm/imagination/pvr_cccb.h b/drivers/gpu/drm/imagination/pvr_cccb.h new file mode 100644 index 000000000000..f35b3d4c9575 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_cccb.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CCCB_H +#define PVR_CCCB_H + +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_shared.h" + +#include +#include + +#define PADDING_COMMAND_SIZE sizeof(struct rogue_fwif_ccb_cmd_header) + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declaration from pvr_hwrt.h. */ +struct pvr_hwrt_data; + +struct pvr_cccb { + /** @ctrl_obj: FW object representing CCCB control structure. */ + struct pvr_fw_object *ctrl_obj; + + /** @ccb_obj: FW object representing CCCB. */ + struct pvr_fw_object *cccb_obj; + + /** + * @ctrl: Kernel mapping of CCCB control structure. @lock must be held + * when accessing. + */ + struct rogue_fwif_cccb_ctl *ctrl; + + /** @cccb: Kernel mapping of CCCB. @lock must be held when accessing.*/ + u8 *cccb; + + /** @ctrl_fw_addr: FW virtual address of CCCB control structure. */ + u32 ctrl_fw_addr; + /** @ccb_fw_addr: FW virtual address of CCCB. */ + u32 cccb_fw_addr; + + /** @size: Size of CCCB in bytes. */ + size_t size; + + /** @write_offset: CCCB write offset. */ + u32 write_offset; + + /** @wrap_mask: CCCB wrap mask. */ + u32 wrap_mask; +}; + +int pvr_cccb_init(struct pvr_device *pvr_dev, struct pvr_cccb *cccb, + u32 size_log2, const char *name); +void pvr_cccb_fini(struct pvr_cccb *cccb); + +void pvr_cccb_write_command_with_header(struct pvr_cccb *pvr_cccb, + u32 cmd_type, u32 cmd_size, void *cmd_data, + u32 ext_job_ref, u32 int_job_ref); +void pvr_cccb_send_kccb_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *pvr_cccb, u32 cctx_fw_addr, + struct pvr_hwrt_data *hwrt); +void pvr_cccb_send_kccb_combined_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *geom_cccb, + struct pvr_cccb *frag_cccb, + u32 geom_ctx_fw_addr, + u32 frag_ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + bool frag_is_pr); +bool pvr_cccb_cmdseq_fits(struct pvr_cccb *pvr_cccb, size_t size); + +/** + * pvr_cccb_get_size_of_cmd_with_hdr() - Get the size of a command and its header. + * @cmd_size: Command size. + * + * Returns the size of the command and its header. + */ +static __always_inline u32 +pvr_cccb_get_size_of_cmd_with_hdr(u32 cmd_size) +{ + WARN_ON(!IS_ALIGNED(cmd_size, 8)); + return sizeof(struct rogue_fwif_ccb_cmd_header) + ALIGN(cmd_size, 8); +} + +/** + * pvr_cccb_cmdseq_can_fit() - Check if a command sequence can fit in the CCCB. + * @size: Command sequence size. + * + * Returns: + * * true it the CCCB is big enough to contain a command sequence, or + * * false otherwise. + */ +static __always_inline bool +pvr_cccb_cmdseq_can_fit(struct pvr_cccb *pvr_cccb, size_t size) +{ + /* We divide the capacity by two to simplify our CCCB fencing logic: + * we want to be sure that, no matter what we had queued before, we + * are able to either queue our command sequence at the end or add a + * padding command and queue the command sequence at the beginning + * of the CCCB. If the command sequence size is bigger than half the + * CCCB capacity, we'd have to queue the padding command and make sure + * the FW is done processing it before queueing our command sequence. + */ + return size + PADDING_COMMAND_SIZE <= pvr_cccb->size / 2; +} + +#endif /* PVR_CCCB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c new file mode 100644 index 000000000000..6cec5aa5a759 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_context.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_cccb.h" +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_common.h" +#include "pvr_rogue_fwif_resetframework.h" +#include "pvr_stream_defs.h" +#include "pvr_vm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +remap_priority(struct pvr_file *pvr_file, s32 uapi_priority, + enum pvr_context_priority *priority_out) +{ + switch (uapi_priority) { + case DRM_PVR_CTX_PRIORITY_LOW: + *priority_out = PVR_CTX_PRIORITY_LOW; + break; + case DRM_PVR_CTX_PRIORITY_NORMAL: + *priority_out = PVR_CTX_PRIORITY_MEDIUM; + break; + case DRM_PVR_CTX_PRIORITY_HIGH: + if (!capable(CAP_SYS_NICE) && !drm_is_current_master(from_pvr_file(pvr_file))) + return -EACCES; + *priority_out = PVR_CTX_PRIORITY_HIGH; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int get_fw_obj_size(enum drm_pvr_ctx_type type) +{ + switch (type) { + case DRM_PVR_CTX_TYPE_RENDER: + return sizeof(struct rogue_fwif_fwrendercontext); + case DRM_PVR_CTX_TYPE_COMPUTE: + return sizeof(struct rogue_fwif_fwcomputecontext); + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + return sizeof(struct rogue_fwif_fwtransfercontext); + } + + return -EINVAL; +} + +static int +process_static_context_state(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + u64 stream_user_ptr, u32 stream_size, void *dest) +{ + void *stream; + int err; + + stream = kzalloc(stream_size, GFP_KERNEL); + if (!stream) + return -ENOMEM; + + if (copy_from_user(stream, u64_to_user_ptr(stream_user_ptr), stream_size)) { + err = -EFAULT; + goto err_free; + } + + err = pvr_stream_process(pvr_dev, cmd_defs, stream, stream_size, dest); + if (err) + goto err_free; + + kfree(stream); + + return 0; + +err_free: + kfree(stream); + + return err; +} + +static int init_render_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + struct rogue_fwif_static_rendercontext_state *static_rendercontext_state; + struct rogue_fwif_fwrendercontext *fw_render_context = fw_ctx_map; + + if (!args->static_context_state_len) + return -EINVAL; + + static_rendercontext_state = &fw_render_context->static_render_context_state; + + /* Copy static render context state from userspace. */ + return process_static_context_state(ctx->pvr_dev, + &pvr_static_render_context_state_stream, + args->static_context_state, + args->static_context_state_len, + &static_rendercontext_state->ctxswitch_regs[0]); +} + +static int init_compute_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + struct rogue_fwif_fwcomputecontext *fw_compute_context = fw_ctx_map; + struct rogue_fwif_cdm_registers_cswitch *ctxswitch_regs; + + if (!args->static_context_state_len) + return -EINVAL; + + ctxswitch_regs = &fw_compute_context->static_compute_context_state.ctxswitch_regs; + + /* Copy static render context state from userspace. */ + return process_static_context_state(ctx->pvr_dev, + &pvr_static_compute_context_state_stream, + args->static_context_state, + args->static_context_state_len, + ctxswitch_regs); +} + +static int init_transfer_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + if (args->static_context_state_len) + return -EINVAL; + + return 0; +} + +static int init_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + return init_render_fw_objs(ctx, args, fw_ctx_map); + case DRM_PVR_CTX_TYPE_COMPUTE: + return init_compute_fw_objs(ctx, args, fw_ctx_map); + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + return init_transfer_fw_objs(ctx, args, fw_ctx_map); + } + + return -EINVAL; +} + +static void +ctx_fw_data_init(void *cpu_ptr, void *priv) +{ + struct pvr_context *ctx = priv; + + memcpy(cpu_ptr, ctx->data, ctx->data_size); +} + +/** + * pvr_context_create() - Create a context. + * @pvr_file: File to attach the created context to. + * @args: Context creation arguments. + * + * Return: + * * 0 on success, or + * * A negative error code on failure. + */ +int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_context_args *args) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct pvr_context *ctx; + int ctx_size; + int err; + + /* Context creation flags are currently unused and must be zero. */ + if (args->flags) + return -EINVAL; + + ctx_size = get_fw_obj_size(args->type); + if (ctx_size < 0) + return ctx_size; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->data_size = ctx_size; + ctx->type = args->type; + ctx->flags = args->flags; + ctx->pvr_dev = pvr_dev; + kref_init(&ctx->ref_count); + + err = remap_priority(pvr_file, args->priority, &ctx->priority); + if (err) + goto err_free_ctx; + + ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (IS_ERR(ctx->vm_ctx)) { + err = PTR_ERR(ctx->vm_ctx); + goto err_free_ctx; + } + + ctx->data = kzalloc(ctx_size, GFP_KERNEL); + if (!ctx->data) { + err = -ENOMEM; + goto err_put_vm; + } + + err = init_fw_objs(ctx, args, ctx->data); + if (err) + goto err_free_ctx_data; + + err = pvr_fw_object_create(pvr_dev, ctx_size, PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + ctx_fw_data_init, ctx, &ctx->fw_obj); + if (err) + goto err_free_ctx_data; + + err = xa_alloc(&pvr_dev->ctx_ids, &ctx->ctx_id, ctx, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_destroy_fw_obj; + + err = xa_alloc(&pvr_file->ctx_handles, &args->handle, ctx, xa_limit_32b, GFP_KERNEL); + if (err) { + /* + * It's possible that another thread could have taken a reference on the context at + * this point as it is in the ctx_ids xarray. Therefore instead of directly + * destroying the context, drop a reference instead. + */ + pvr_context_put(ctx); + return err; + } + + return 0; + +err_destroy_fw_obj: + pvr_fw_object_destroy(ctx->fw_obj); + +err_free_ctx_data: + kfree(ctx->data); + +err_put_vm: + pvr_vm_context_put(ctx->vm_ctx); + +err_free_ctx: + kfree(ctx); + return err; +} + +static void +pvr_context_release(struct kref *ref_count) +{ + struct pvr_context *ctx = + container_of(ref_count, struct pvr_context, ref_count); + struct pvr_device *pvr_dev = ctx->pvr_dev; + + xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id); + pvr_fw_object_destroy(ctx->fw_obj); + kfree(ctx->data); + pvr_vm_context_put(ctx->vm_ctx); + kfree(ctx); +} + +/** + * pvr_context_put() - Release reference on context + * @ctx: Target context. + */ +void +pvr_context_put(struct pvr_context *ctx) +{ + if (ctx) + kref_put(&ctx->ref_count, pvr_context_release); +} + +/** + * pvr_context_destroy() - Destroy context + * @pvr_file: Pointer to pvr_file structure. + * @handle: Userspace context handle. + * + * Removes context from context list and drops initial reference. Context will + * then be destroyed once all outstanding references are dropped. + * + * Return: + * * 0 on success, or + * * -%EINVAL if context not in context list. + */ +int +pvr_context_destroy(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_context *ctx = xa_erase(&pvr_file->ctx_handles, handle); + + if (!ctx) + return -EINVAL; + + /* Release the reference held by the handle set. */ + pvr_context_put(ctx); + + return 0; +} + +/** + * pvr_destroy_contexts_for_file: Destroy any contexts associated with the given file + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all contexts associated with @pvr_file from the device context list and drops initial + * references. Contexts will then be destroyed once all outstanding references are dropped. + */ +void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file) +{ + struct pvr_context *ctx; + unsigned long handle; + + xa_for_each(&pvr_file->ctx_handles, handle, ctx) + pvr_context_destroy(pvr_file, handle); +} + +/** + * pvr_context_device_init() - Device level initialization for queue related resources. + * @pvr_dev: The device to initialize. + */ +void pvr_context_device_init(struct pvr_device *pvr_dev) +{ + xa_init_flags(&pvr_dev->ctx_ids, XA_FLAGS_ALLOC1); +} + +/** + * pvr_context_device_fini() - Device level cleanup for queue related resources. + * @pvr_dev: The device to cleanup. + */ +void pvr_context_device_fini(struct pvr_device *pvr_dev) +{ + WARN_ON(!xa_empty(&pvr_dev->ctx_ids)); + xa_destroy(&pvr_dev->ctx_ids); +} diff --git a/drivers/gpu/drm/imagination/pvr_context.h b/drivers/gpu/drm/imagination/pvr_context.h new file mode 100644 index 000000000000..502dfad113e4 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_context.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CONTEXT_H +#define PVR_CONTEXT_H + +#include + +#include +#include +#include +#include +#include +#include + +#include "pvr_cccb.h" +#include "pvr_device.h" + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +enum pvr_context_priority { + PVR_CTX_PRIORITY_LOW = 0, + PVR_CTX_PRIORITY_MEDIUM, + PVR_CTX_PRIORITY_HIGH, +}; + +/** + * struct pvr_context - Context data + */ +struct pvr_context { + /** @ref_count: Refcount for context. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to owning device. */ + struct pvr_device *pvr_dev; + + /** @vm_ctx: Pointer to associated VM context. */ + struct pvr_vm_context *vm_ctx; + + /** @type: Type of context. */ + enum drm_pvr_ctx_type type; + + /** @flags: Context flags. */ + u32 flags; + + /** @priority: Context priority*/ + enum pvr_context_priority priority; + + /** @fw_obj: FW object representing FW-side context data. */ + struct pvr_fw_object *fw_obj; + + /** @data: Pointer to local copy of FW context data. */ + void *data; + + /** @data_size: Size of FW context data, in bytes. */ + u32 data_size; + + /** @ctx_id: FW context ID. */ + u32 ctx_id; +}; + +/** + * pvr_context_get() - Take additional reference on context. + * @ctx: Context pointer. + * + * Call pvr_context_put() to release. + * + * Returns: + * * The requested context on success, or + * * %NULL if no context pointer passed. + */ +static __always_inline struct pvr_context * +pvr_context_get(struct pvr_context *ctx) +{ + if (ctx) + kref_get(&ctx->ref_count); + + return ctx; +} + +/** + * pvr_context_lookup() - Lookup context pointer from handle and file. + * @pvr_file: Pointer to pvr_file structure. + * @handle: Context handle. + * + * Takes reference on context. Call pvr_context_put() to release. + * + * Return: + * * The requested context on success, or + * * %NULL on failure (context does not exist, or does not belong to @pvr_file). + */ +static __always_inline struct pvr_context * +pvr_context_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_context *ctx; + + /* Take the array lock to protect against context removal. */ + xa_lock(&pvr_file->ctx_handles); + ctx = pvr_context_get(xa_load(&pvr_file->ctx_handles, handle)); + xa_unlock(&pvr_file->ctx_handles); + + return ctx; +} + +/** + * pvr_context_lookup_id() - Lookup context pointer from ID. + * @pvr_dev: Device pointer. + * @id: FW context ID. + * + * Takes reference on context. Call pvr_context_put() to release. + * + * Return: + * * The requested context on success, or + * * %NULL on failure (context does not exist). + */ +static __always_inline struct pvr_context * +pvr_context_lookup_id(struct pvr_device *pvr_dev, u32 id) +{ + struct pvr_context *ctx; + + /* Take the array lock to protect against context removal. */ + xa_lock(&pvr_dev->ctx_ids); + + /* Contexts are removed from the ctx_ids set in the context release path, + * meaning the ref_count reached zero before they get removed. We need + * to make sure we're not trying to acquire a context that's being + * destroyed. + */ + ctx = xa_load(&pvr_dev->ctx_ids, id); + if (!kref_get_unless_zero(&ctx->ref_count)) + ctx = NULL; + + xa_unlock(&pvr_dev->ctx_ids); + + return ctx; +} + +static __always_inline u32 +pvr_context_get_fw_addr(struct pvr_context *ctx) +{ + u32 ctx_fw_addr = 0; + + pvr_fw_object_get_fw_addr(ctx->fw_obj, &ctx_fw_addr); + + return ctx_fw_addr; +} + +void pvr_context_put(struct pvr_context *ctx); + +int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_context_args *args); + +int pvr_context_destroy(struct pvr_file *pvr_file, u32 handle); + +void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file); + +void pvr_context_device_init(struct pvr_device *pvr_dev); + +void pvr_context_device_fini(struct pvr_device *pvr_dev); + +#endif /* PVR_CONTEXT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index f5b82b793566..299f3e022c82 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -7,6 +7,8 @@ #include "pvr_ccb.h" #include "pvr_device_info.h" #include "pvr_fw.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" #include #include @@ -146,12 +148,23 @@ struct pvr_device { /** @fw_dev: Firmware related data. */ struct pvr_fw_device fw_dev; + /** @stream_musthave_quirks: Bit array of "must-have" quirks for stream commands. */ + u32 stream_musthave_quirks[PVR_STREAM_TYPE_MAX][PVR_STREAM_EXTHDR_TYPE_MAX]; + /** * @mmu_flush_cache_flags: Records which MMU caches require flushing * before submitting the next job. */ atomic_t mmu_flush_cache_flags; + /** + * @ctx_ids: Array of contexts belonging to this device. Array members + * are of type "struct pvr_context *". + * + * This array is used to allocate IDs used by the firmware. + */ + struct xarray ctx_ids; + /** * @free_list_ids: Array of free lists belonging to this device. Array members * are of type "struct pvr_free_list *". @@ -255,6 +268,14 @@ struct pvr_file { */ struct pvr_device *pvr_dev; + /** + * @ctx_handles: Array of contexts belonging to this file. Array members + * are of type "struct pvr_context *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray ctx_handles; + /** * @free_list_handles: Array of free lists belonging to this file. Array * members are of type "struct pvr_free_list *". diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index f485e2cc60f9..e76363f7dbf7 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT /* Copyright (c) 2023 Imagination Technologies Ltd. */ +#include "pvr_context.h" #include "pvr_device.h" #include "pvr_drv.h" #include "pvr_free_list.h" @@ -673,7 +674,19 @@ static int pvr_ioctl_create_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_create_context_args *args = raw_args; + struct pvr_file *pvr_file = file->driver_priv; + int idx; + int ret; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + ret = pvr_context_create(pvr_file, args); + + drm_dev_exit(idx); + + return ret; } /** @@ -693,7 +706,13 @@ static int pvr_ioctl_destroy_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_destroy_context_args *args = raw_args; + struct pvr_file *pvr_file = file->driver_priv; + + if (args->_padding_4) + return -EINVAL; + + return pvr_context_destroy(pvr_file, args->handle); } /** @@ -1289,6 +1308,7 @@ pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file) */ pvr_file->pvr_dev = pvr_dev; + xa_init_flags(&pvr_file->ctx_handles, XA_FLAGS_ALLOC1); xa_init_flags(&pvr_file->free_list_handles, XA_FLAGS_ALLOC1); xa_init_flags(&pvr_file->hwrt_handles, XA_FLAGS_ALLOC1); xa_init_flags(&pvr_file->vm_ctx_handles, XA_FLAGS_ALLOC1); @@ -1318,6 +1338,9 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, { struct pvr_file *pvr_file = to_pvr_file(file); + /* Kill remaining contexts. */ + pvr_destroy_contexts_for_file(pvr_file); + /* Drop references on any remaining objects. */ pvr_destroy_free_lists_for_file(pvr_file); pvr_destroy_hwrt_datasets_for_file(pvr_file); @@ -1363,6 +1386,7 @@ pvr_probe(struct platform_device *plat_dev) drm_dev = &pvr_dev->base; platform_set_drvdata(plat_dev, drm_dev); + pvr_context_device_init(pvr_dev); devm_pm_runtime_enable(&plat_dev->dev); pm_runtime_mark_last_busy(&plat_dev->dev); @@ -1406,6 +1430,7 @@ pvr_remove(struct platform_device *plat_dev) pvr_device_fini(pvr_dev); drm_dev_unplug(drm_dev); pvr_watchdog_fini(pvr_dev); + pvr_context_device_fini(pvr_dev); return 0; } diff --git a/drivers/gpu/drm/imagination/pvr_stream.c b/drivers/gpu/drm/imagination/pvr_stream.c new file mode 100644 index 000000000000..975336a4facf --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" + +#include +#include +#include +#include + +static __always_inline bool +stream_def_is_supported(struct pvr_device *pvr_dev, const struct pvr_stream_def *stream_def) +{ + if (stream_def->feature == PVR_FEATURE_NONE) + return true; + + if (!(stream_def->feature & PVR_FEATURE_NOT) && + pvr_device_has_feature(pvr_dev, stream_def->feature)) { + return true; + } + + if ((stream_def->feature & PVR_FEATURE_NOT) && + !pvr_device_has_feature(pvr_dev, stream_def->feature & ~PVR_FEATURE_NOT)) { + return true; + } + + return false; +} + +static int +pvr_stream_get_data(u8 *stream, u32 *stream_offset, u32 stream_size, u32 data_size, u32 align_size, + void *dest) +{ + *stream_offset = ALIGN(*stream_offset, align_size); + + if ((*stream_offset + data_size) > stream_size) + return -EINVAL; + + memcpy(dest, stream + *stream_offset, data_size); + + (*stream_offset) += data_size; + + return 0; +} + +/** + * pvr_stream_process_1() - Process a single stream and fill destination structure + * @pvr_dev: Device pointer. + * @stream_def: Stream definition. + * @nr_entries: Number of entries in &stream_def. + * @stream: Pointer to stream. + * @stream_offset: Starting offset within stream. + * @stream_size: Size of input stream, in bytes. + * @dest: Pointer to destination structure. + * @dest_size: Size of destination structure. + * @stream_offset_out: Pointer to variable to write updated stream offset to. May be NULL. + * + * Returns: + * * 0 on success, or + * * -%EINVAL on malformed stream. + */ +static int +pvr_stream_process_1(struct pvr_device *pvr_dev, const struct pvr_stream_def *stream_def, + u32 nr_entries, u8 *stream, u32 stream_offset, u32 stream_size, + u8 *dest, u32 dest_size, u32 *stream_offset_out) +{ + int err = 0; + u32 i; + + for (i = 0; i < nr_entries; i++) { + if (stream_def[i].offset >= dest_size) { + err = -EINVAL; + break; + } + + if (!stream_def_is_supported(pvr_dev, &stream_def[i])) + continue; + + switch (stream_def[i].size) { + case PVR_STREAM_SIZE_8: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u8), + sizeof(u8), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_16: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u16), + sizeof(u16), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_32: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_64: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u64), + sizeof(u64), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_ARRAY: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, + stream_def[i].array_size, sizeof(u64), + dest + stream_def[i].offset); + if (err) + return err; + break; + } + } + + if (stream_offset_out) + *stream_offset_out = stream_offset; + + return err; +} + +static int +pvr_stream_process_ext_stream(struct pvr_device *pvr_dev, + const struct pvr_stream_cmd_defs *cmd_defs, void *ext_stream, + u32 stream_offset, u32 ext_stream_size, void *dest) +{ + u32 musthave_masks[PVR_STREAM_EXTHDR_TYPE_MAX]; + u32 ext_header; + int err = 0; + u32 i; + + /* Copy "must have" mask from device. We clear this as we process the stream. */ + memcpy(musthave_masks, pvr_dev->stream_musthave_quirks[cmd_defs->type], + sizeof(musthave_masks)); + + do { + const struct pvr_stream_ext_header *header; + u32 type; + u32 data; + + err = pvr_stream_get_data(ext_stream, &stream_offset, ext_stream_size, sizeof(u32), + sizeof(ext_header), &ext_header); + if (err) + return err; + + type = (ext_header & PVR_STREAM_EXTHDR_TYPE_MASK) >> PVR_STREAM_EXTHDR_TYPE_SHIFT; + data = ext_header & PVR_STREAM_EXTHDR_DATA_MASK; + + if (type >= cmd_defs->ext_nr_headers) + return -EINVAL; + + header = &cmd_defs->ext_headers[type]; + if (data & ~header->valid_mask) + return -EINVAL; + + musthave_masks[type] &= ~data; + + for (i = 0; i < header->ext_streams_num; i++) { + const struct pvr_stream_ext_def *ext_def = &header->ext_streams[i]; + + if (!(ext_header & ext_def->header_mask)) + continue; + + if (!pvr_device_has_uapi_quirk(pvr_dev, ext_def->quirk)) + return -EINVAL; + + err = pvr_stream_process_1(pvr_dev, ext_def->stream, ext_def->stream_len, + ext_stream, stream_offset, + ext_stream_size, dest, + cmd_defs->dest_size, &stream_offset); + if (err) + return err; + } + } while (ext_header & PVR_STREAM_EXTHDR_CONTINUATION); + + /* + * Verify that "must have" mask is now zero. If it isn't then one of the "must have" quirks + * for this command was not present. + */ + for (i = 0; i < cmd_defs->ext_nr_headers; i++) { + if (musthave_masks[i]) + return -EINVAL; + } + + return 0; +} + +/** + * pvr_stream_process() - Build FW structure from stream + * @pvr_dev: Device pointer. + * @cmd_defs: Stream definition. + * @stream: Pointer to command stream. + * @stream_size: Size of command stream, in bytes. + * @dest_out: Pointer to destination buffer. + * + * Caller is responsible for freeing the output structure. + * + * Returns: + * * 0 on success, + * * -%ENOMEM on out of memory, or + * * -%EINVAL on malformed stream. + */ +int +pvr_stream_process(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, void *dest_out) +{ + u32 stream_offset = 0; + u32 main_stream_len; + u32 padding; + int err; + + if (!stream || !stream_size) + return -EINVAL; + + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), &main_stream_len); + if (err) + return err; + + /* + * u32 after stream length is padding to ensure u64 alignment, but may be used for expansion + * in the future. Verify it's zero. + */ + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), &padding); + if (err) + return err; + + if (main_stream_len < stream_offset || main_stream_len > stream_size || padding) + return -EINVAL; + + err = pvr_stream_process_1(pvr_dev, cmd_defs->main_stream, cmd_defs->main_stream_len, + stream, stream_offset, main_stream_len, dest_out, + cmd_defs->dest_size, &stream_offset); + if (err) + return err; + + if (stream_offset < stream_size) { + err = pvr_stream_process_ext_stream(pvr_dev, cmd_defs, stream, stream_offset, + stream_size, dest_out); + if (err) + return err; + } else { + u32 i; + + /* + * If we don't have an extension stream then there must not be any "must have" + * quirks for this command. + */ + for (i = 0; i < cmd_defs->ext_nr_headers; i++) { + if (pvr_dev->stream_musthave_quirks[cmd_defs->type][i]) + return -EINVAL; + } + } + + return 0; +} + +/** + * pvr_stream_create_musthave_masks() - Create "must have" masks for streams based on current device + * quirks + * @pvr_dev: Device pointer. + */ +void +pvr_stream_create_musthave_masks(struct pvr_device *pvr_dev) +{ + memset(pvr_dev->stream_musthave_quirks, 0, sizeof(pvr_dev->stream_musthave_quirks)); + + if (pvr_device_has_uapi_quirk(pvr_dev, 47217)) + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_FRAG][0] |= + PVR_STREAM_EXTHDR_FRAG0_BRN47217; + + if (pvr_device_has_uapi_quirk(pvr_dev, 49927)) { + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_GEOM][0] |= + PVR_STREAM_EXTHDR_GEOM0_BRN49927; + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_FRAG][0] |= + PVR_STREAM_EXTHDR_FRAG0_BRN49927; + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_COMPUTE][0] |= + PVR_STREAM_EXTHDR_COMPUTE0_BRN49927; + } +} diff --git a/drivers/gpu/drm/imagination/pvr_stream.h b/drivers/gpu/drm/imagination/pvr_stream.h new file mode 100644 index 000000000000..d92acb3a61d7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_STREAM_H +#define PVR_STREAM_H + +#include +#include +#include + +struct pvr_device; + +struct pvr_job; + +enum pvr_stream_type { + PVR_STREAM_TYPE_GEOM = 0, + PVR_STREAM_TYPE_FRAG, + PVR_STREAM_TYPE_COMPUTE, + PVR_STREAM_TYPE_TRANSFER, + PVR_STREAM_TYPE_STATIC_RENDER_CONTEXT, + PVR_STREAM_TYPE_STATIC_COMPUTE_CONTEXT, + + PVR_STREAM_TYPE_MAX +}; + +enum pvr_stream_size { + PVR_STREAM_SIZE_8 = 0, + PVR_STREAM_SIZE_16, + PVR_STREAM_SIZE_32, + PVR_STREAM_SIZE_64, + PVR_STREAM_SIZE_ARRAY, +}; + +#define PVR_FEATURE_NOT BIT(31) +#define PVR_FEATURE_NONE U32_MAX + +struct pvr_stream_def { + u32 offset; + enum pvr_stream_size size; + u32 array_size; + u32 feature; +}; + +struct pvr_stream_ext_def { + const struct pvr_stream_def *stream; + u32 stream_len; + u32 header_mask; + u32 quirk; +}; + +struct pvr_stream_ext_header { + const struct pvr_stream_ext_def *ext_streams; + u32 ext_streams_num; + u32 valid_mask; +}; + +struct pvr_stream_cmd_defs { + enum pvr_stream_type type; + + const struct pvr_stream_def *main_stream; + u32 main_stream_len; + + u32 ext_nr_headers; + const struct pvr_stream_ext_header *ext_headers; + + size_t dest_size; +}; + +int +pvr_stream_process(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, void *dest_out); +void +pvr_stream_create_musthave_masks(struct pvr_device *pvr_dev); + +#endif /* PVR_STREAM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_stream_defs.c b/drivers/gpu/drm/imagination/pvr_stream_defs.c new file mode 100644 index 000000000000..59265a7accce --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream_defs.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device_info.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" +#include "pvr_stream_defs.h" + +#include +#include + +#define PVR_STREAM_DEF_SET(owner, member, _size, _array_size, _feature) \ + { .offset = offsetof(struct owner, member), \ + .size = (_size), \ + .array_size = (_array_size), \ + .feature = (_feature) } + +#define PVR_STREAM_DEF(owner, member, member_size) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, PVR_FEATURE_NONE) + +#define PVR_STREAM_DEF_FEATURE(owner, member, member_size, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, feature) + +#define PVR_STREAM_DEF_NOT_FEATURE(owner, member, member_size, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, \ + (feature) | PVR_FEATURE_NOT) + +#define PVR_STREAM_DEF_ARRAY(owner, member) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), PVR_FEATURE_NONE) + +#define PVR_STREAM_DEF_ARRAY_FEATURE(owner, member, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), feature) + +#define PVR_STREAM_DEF_ARRAY_NOT_FEATURE(owner, member, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), (feature) | PVR_FEATURE_NOT) + +/* + * When adding new parameters to the stream definition, the new parameters must go after the + * existing parameters, to preserve order. As parameters are naturally aligned, care must be taken + * with respect to implicit padding in the stream; padding should be minimised as much as possible. + */ +static const struct pvr_stream_def rogue_fwif_static_render_context_state_stream[] = { + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_resume_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_ta_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task4, 64), +}; + +const struct pvr_stream_cmd_defs pvr_static_render_context_state_stream = { + .type = PVR_STREAM_TYPE_STATIC_RENDER_CONTEXT, + + .main_stream = rogue_fwif_static_render_context_state_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_static_render_context_state_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_geom_registers_caswitch), +}; + +static const struct pvr_stream_def rogue_fwif_static_compute_context_state_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds1, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds1, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0_b, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0_b, 64), +}; + +const struct pvr_stream_cmd_defs pvr_static_compute_context_state_stream = { + .type = PVR_STREAM_TYPE_STATIC_COMPUTE_CONTEXT, + + .main_stream = rogue_fwif_static_compute_context_state_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_static_compute_context_state_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_cdm_registers_cswitch), +}; diff --git a/drivers/gpu/drm/imagination/pvr_stream_defs.h b/drivers/gpu/drm/imagination/pvr_stream_defs.h new file mode 100644 index 000000000000..f33b82165833 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream_defs.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_STREAM_DEFS_H +#define PVR_STREAM_DEFS_H + +#include "pvr_stream.h" + +extern const struct pvr_stream_cmd_defs pvr_cmd_geom_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_frag_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_compute_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_transfer_stream; +extern const struct pvr_stream_cmd_defs pvr_static_render_context_state_stream; +extern const struct pvr_stream_cmd_defs pvr_static_compute_context_state_stream; + +#endif /* PVR_STREAM_DEFS_H */ From eaf01ee5ba28b97f96a3d3eec4c5fbfb37ee4cde Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:38 +0000 Subject: [PATCH 1189/7721] drm/imagination: Implement job submission and scheduling Implement job submission ioctl. Job scheduling is implemented using drm_sched. Jobs are submitted in a stream format. This is intended to allow the UAPI data format to be independent of the actual FWIF structures in use, which vary depending on the GPU in use. The stream formats are documented at: https://gitlab.freedesktop.org/mesa/mesa/-/blob/f8d2b42ae65c2f16f36a43e0ae39d288431e4263/src/imagination/csbgen/rogue_kmd_stream.xml Changes since v8: - Updated for upstreamed DRM scheduler changes - Removed workaround code for the pending_list previously being updated after run_job() returned - Fixed null deref in pvr_queue_cleanup_fw_context() for bad stream ptr given to create_context ioctl - Corrected license identifiers Changes since v7: - Updated for v8 "DRM scheduler changes for XE" patchset Changes since v6: - Fix fence handling in pvr_sync_signal_array_add() - Add handling for SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE flag - Fix missing dma_resv locking in job submit path Changes since v5: - Fix leak in job creation error path Changes since v4: - Use a regular workqueue for job scheduling Changes since v3: - Support partial render jobs - Add job timeout handler - Split sync handling out of job code - Use drm_dev_{enter,exit} Changes since v2: - Use drm_sched for job scheduling Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Link: https://lore.kernel.org/r/c98dab7a5f5fb891fbed7e4990d19b5d13964365.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Kconfig | 1 + drivers/gpu/drm/imagination/Makefile | 3 + drivers/gpu/drm/imagination/pvr_context.c | 125 +- drivers/gpu/drm/imagination/pvr_context.h | 44 + drivers/gpu/drm/imagination/pvr_device.c | 31 + drivers/gpu/drm/imagination/pvr_device.h | 21 + drivers/gpu/drm/imagination/pvr_drv.c | 40 +- drivers/gpu/drm/imagination/pvr_job.c | 788 +++++++++ drivers/gpu/drm/imagination/pvr_job.h | 161 ++ drivers/gpu/drm/imagination/pvr_power.c | 28 + drivers/gpu/drm/imagination/pvr_queue.c | 1432 +++++++++++++++++ drivers/gpu/drm/imagination/pvr_queue.h | 169 ++ drivers/gpu/drm/imagination/pvr_stream_defs.c | 226 +++ drivers/gpu/drm/imagination/pvr_sync.c | 289 ++++ drivers/gpu/drm/imagination/pvr_sync.h | 84 + 15 files changed, 3438 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/imagination/pvr_job.c create mode 100644 drivers/gpu/drm/imagination/pvr_job.h create mode 100644 drivers/gpu/drm/imagination/pvr_queue.c create mode 100644 drivers/gpu/drm/imagination/pvr_queue.h create mode 100644 drivers/gpu/drm/imagination/pvr_sync.c create mode 100644 drivers/gpu/drm/imagination/pvr_sync.h diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imagination/Kconfig index 0abd1b9bf3be..3bfa2ac212dc 100644 --- a/drivers/gpu/drm/imagination/Kconfig +++ b/drivers/gpu/drm/imagination/Kconfig @@ -6,6 +6,7 @@ config DRM_POWERVR depends on ARM64 depends on DRM depends on PM + select DRM_EXEC select DRM_GEM_SHMEM_HELPER select DRM_SCHED select DRM_GPUVM diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 7f7bea8c60c4..7e3515c99caa 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -18,10 +18,13 @@ powervr-y := \ pvr_fw_trace.o \ pvr_gem.o \ pvr_hwrt.o \ + pvr_job.o \ pvr_mmu.o \ pvr_power.o \ + pvr_queue.o \ pvr_stream.o \ pvr_stream_defs.o \ + pvr_sync.o \ pvr_vm.o \ pvr_vm_mips.o diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c index 6cec5aa5a759..eded5e955cc0 100644 --- a/drivers/gpu/drm/imagination/pvr_context.c +++ b/drivers/gpu/drm/imagination/pvr_context.c @@ -6,10 +6,12 @@ #include "pvr_device.h" #include "pvr_drv.h" #include "pvr_gem.h" +#include "pvr_job.h" #include "pvr_power.h" #include "pvr_rogue_fwif.h" #include "pvr_rogue_fwif_common.h" #include "pvr_rogue_fwif_resetframework.h" +#include "pvr_stream.h" #include "pvr_stream_defs.h" #include "pvr_vm.h" @@ -164,6 +166,116 @@ ctx_fw_data_init(void *cpu_ptr, void *priv) memcpy(cpu_ptr, ctx->data, ctx->data_size); } +/** + * pvr_context_destroy_queues() - Destroy all queues attached to a context. + * @ctx: Context to destroy queues on. + * + * Should be called when the last reference to a context object is dropped. + * It releases all resources attached to the queues bound to this context. + */ +static void pvr_context_destroy_queues(struct pvr_context *ctx) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + pvr_queue_destroy(ctx->queues.fragment); + pvr_queue_destroy(ctx->queues.geometry); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + pvr_queue_destroy(ctx->queues.compute); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + pvr_queue_destroy(ctx->queues.transfer); + break; + } +} + +/** + * pvr_context_create_queues() - Create all queues attached to a context. + * @ctx: Context to create queues on. + * @args: Context creation arguments passed by userspace. + * @fw_ctx_map: CPU mapping of the FW context object. + * + * Return: + * * 0 on success, or + * * A negative error code otherwise. + */ +static int pvr_context_create_queues(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + int err; + + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + ctx->queues.geometry = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_GEOMETRY, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.geometry)) { + err = PTR_ERR(ctx->queues.geometry); + ctx->queues.geometry = NULL; + goto err_destroy_queues; + } + + ctx->queues.fragment = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_FRAGMENT, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.fragment)) { + err = PTR_ERR(ctx->queues.fragment); + ctx->queues.fragment = NULL; + goto err_destroy_queues; + } + return 0; + + case DRM_PVR_CTX_TYPE_COMPUTE: + ctx->queues.compute = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_COMPUTE, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.compute)) { + err = PTR_ERR(ctx->queues.compute); + ctx->queues.compute = NULL; + goto err_destroy_queues; + } + return 0; + + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + ctx->queues.transfer = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_TRANSFER_FRAG, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.transfer)) { + err = PTR_ERR(ctx->queues.transfer); + ctx->queues.transfer = NULL; + goto err_destroy_queues; + } + return 0; + } + + return -EINVAL; + +err_destroy_queues: + pvr_context_destroy_queues(ctx); + return err; +} + +/** + * pvr_context_kill_queues() - Kill queues attached to context. + * @ctx: Context to kill queues on. + * + * Killing the queues implies making them unusable for future jobs, while still + * letting the currently submitted jobs a chance to finish. Queue resources will + * stay around until pvr_context_destroy_queues() is called. + */ +static void pvr_context_kill_queues(struct pvr_context *ctx) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + pvr_queue_kill(ctx->queues.fragment); + pvr_queue_kill(ctx->queues.geometry); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + pvr_queue_kill(ctx->queues.compute); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + pvr_queue_kill(ctx->queues.transfer); + break; + } +} + /** * pvr_context_create() - Create a context. * @pvr_file: File to attach the created context to. @@ -214,10 +326,14 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co goto err_put_vm; } - err = init_fw_objs(ctx, args, ctx->data); + err = pvr_context_create_queues(ctx, args, ctx->data); if (err) goto err_free_ctx_data; + err = init_fw_objs(ctx, args, ctx->data); + if (err) + goto err_destroy_queues; + err = pvr_fw_object_create(pvr_dev, ctx_size, PVR_BO_FW_FLAGS_DEVICE_UNCACHED, ctx_fw_data_init, ctx, &ctx->fw_obj); if (err) @@ -243,6 +359,9 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co err_destroy_fw_obj: pvr_fw_object_destroy(ctx->fw_obj); +err_destroy_queues: + pvr_context_destroy_queues(ctx); + err_free_ctx_data: kfree(ctx->data); @@ -262,6 +381,7 @@ pvr_context_release(struct kref *ref_count) struct pvr_device *pvr_dev = ctx->pvr_dev; xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id); + pvr_context_destroy_queues(ctx); pvr_fw_object_destroy(ctx->fw_obj); kfree(ctx->data); pvr_vm_context_put(ctx->vm_ctx); @@ -299,6 +419,9 @@ pvr_context_destroy(struct pvr_file *pvr_file, u32 handle) if (!ctx) return -EINVAL; + /* Make sure nothing can be queued to the queues after that point. */ + pvr_context_kill_queues(ctx); + /* Release the reference held by the handle set. */ pvr_context_put(ctx); diff --git a/drivers/gpu/drm/imagination/pvr_context.h b/drivers/gpu/drm/imagination/pvr_context.h index 502dfad113e4..0c7b97dfa6ba 100644 --- a/drivers/gpu/drm/imagination/pvr_context.h +++ b/drivers/gpu/drm/imagination/pvr_context.h @@ -15,6 +15,7 @@ #include "pvr_cccb.h" #include "pvr_device.h" +#include "pvr_queue.h" /* Forward declaration from pvr_gem.h. */ struct pvr_fw_object; @@ -58,8 +59,51 @@ struct pvr_context { /** @ctx_id: FW context ID. */ u32 ctx_id; + + /** + * @faulty: Set to 1 when the context queues had unfinished job when + * a GPU reset happened. + * + * In that case, the context is in an inconsistent state and can't be + * used anymore. + */ + atomic_t faulty; + + /** @queues: Union containing all kind of queues. */ + union { + struct { + /** @geometry: Geometry queue. */ + struct pvr_queue *geometry; + + /** @fragment: Fragment queue. */ + struct pvr_queue *fragment; + }; + + /** @compute: Compute queue. */ + struct pvr_queue *compute; + + /** @compute: Transfer queue. */ + struct pvr_queue *transfer; + } queues; }; +static __always_inline struct pvr_queue * +pvr_context_get_queue_for_job(struct pvr_context *ctx, enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.geometry : NULL; + case DRM_PVR_JOB_TYPE_FRAGMENT: + return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.fragment : NULL; + case DRM_PVR_JOB_TYPE_COMPUTE: + return ctx->type == DRM_PVR_CTX_TYPE_COMPUTE ? ctx->queues.compute : NULL; + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return ctx->type == DRM_PVR_CTX_TYPE_TRANSFER_FRAG ? ctx->queues.transfer : NULL; + } + + return NULL; +} + /** * pvr_context_get() - Take additional reference on context. * @ctx: Context pointer. diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 2d6db4715f85..199f812d1ee7 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -6,7 +6,9 @@ #include "pvr_fw.h" #include "pvr_power.h" +#include "pvr_queue.h" #include "pvr_rogue_cr_defs.h" +#include "pvr_stream.h" #include "pvr_vm.h" #include @@ -117,6 +119,32 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev) return 0; } +/** + * pvr_device_process_active_queues() - Process all queue related events. + * @pvr_dev: PowerVR device to check + * + * This is called any time we receive a FW event. It iterates over all + * active queues and calls pvr_queue_process() on them. + */ +void pvr_device_process_active_queues(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue, *tmp_queue; + LIST_HEAD(active_queues); + + mutex_lock(&pvr_dev->queues.lock); + + /* Move all active queues to a temporary list. Queues that remain + * active after we're done processing them are re-inserted to + * the queues.active list by pvr_queue_process(). + */ + list_splice_init(&pvr_dev->queues.active, &active_queues); + + list_for_each_entry_safe(queue, tmp_queue, &active_queues, node) + pvr_queue_process(queue); + + mutex_unlock(&pvr_dev->queues.lock); +} + static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data) { struct pvr_device *pvr_dev = data; @@ -132,6 +160,7 @@ static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data) if (pvr_dev->fw_dev.booted) { pvr_fwccb_process(pvr_dev); pvr_kccb_wake_up_waiters(pvr_dev); + pvr_device_process_active_queues(pvr_dev); } pm_runtime_mark_last_busy(from_pvr_device(pvr_dev)->dev); @@ -398,6 +427,8 @@ pvr_device_gpu_init(struct pvr_device *pvr_dev) else return -EINVAL; + pvr_stream_create_musthave_masks(pvr_dev); + err = pvr_set_dma_info(pvr_dev); if (err) return err; diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index 299f3e022c82..b6e9a7e8072e 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -173,6 +173,26 @@ struct pvr_device { */ struct xarray free_list_ids; + /** + * @job_ids: Array of jobs belonging to this device. Array members + * are of type "struct pvr_job *". + */ + struct xarray job_ids; + + /** + * @queues: Queue-related fields. + */ + struct { + /** @active: Active queue list. */ + struct list_head active; + + /** @idle: Idle queue list. */ + struct list_head idle; + + /** @lock: Lock protecting access to the active/idle lists. */ + struct mutex lock; + } queues; + struct { /** @work: Work item for watchdog callback. */ struct delayed_work work; @@ -442,6 +462,7 @@ packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id) int pvr_device_init(struct pvr_device *pvr_dev); void pvr_device_fini(struct pvr_device *pvr_dev); +void pvr_device_reset(struct pvr_device *pvr_dev); bool pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk); diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index e76363f7dbf7..a6f1d52aaebb 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -7,6 +7,7 @@ #include "pvr_free_list.h" #include "pvr_gem.h" #include "pvr_hwrt.h" +#include "pvr_job.h" #include "pvr_mmu.h" #include "pvr_power.h" #include "pvr_rogue_defs.h" @@ -32,6 +33,8 @@ #include #include #include +#include +#include /** * DOC: PowerVR (Series 6 and later) and IMG Graphics Driver @@ -397,7 +400,8 @@ pvr_dev_query_runtime_info_get(struct pvr_device *pvr_dev, return 0; } - runtime_info.free_list_min_pages = 0; /* FIXME */ + runtime_info.free_list_min_pages = + pvr_get_free_list_min_pages(pvr_dev); runtime_info.free_list_max_pages = ROGUE_PM_MAX_FREELIST_SIZE / ROGUE_PM_PAGE_SIZE; runtime_info.common_store_alloc_region_size = @@ -1137,7 +1141,20 @@ static int pvr_ioctl_submit_jobs(struct drm_device *drm_dev, void *raw_args, struct drm_file *file) { - return -ENOTTY; + struct drm_pvr_ioctl_submit_jobs_args *args = raw_args; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file = to_pvr_file(file); + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + err = pvr_submit_jobs(pvr_dev, pvr_file, args); + + drm_dev_exit(idx); + + return err; } int @@ -1353,7 +1370,8 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, DEFINE_DRM_GEM_FOPS(pvr_drm_driver_fops); static struct drm_driver pvr_drm_driver = { - .driver_features = DRIVER_GEM | DRIVER_GEM_GPUVA | DRIVER_RENDER, + .driver_features = DRIVER_GEM | DRIVER_GEM_GPUVA | DRIVER_RENDER | + DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE, .open = pvr_drm_driver_open, .postclose = pvr_drm_driver_postclose, .ioctls = pvr_drm_driver_ioctls, @@ -1386,8 +1404,15 @@ pvr_probe(struct platform_device *plat_dev) drm_dev = &pvr_dev->base; platform_set_drvdata(plat_dev, drm_dev); + + init_rwsem(&pvr_dev->reset_sem); + pvr_context_device_init(pvr_dev); + err = pvr_queue_device_init(pvr_dev); + if (err) + goto err_context_fini; + devm_pm_runtime_enable(&plat_dev->dev); pm_runtime_mark_last_busy(&plat_dev->dev); @@ -1404,6 +1429,7 @@ pvr_probe(struct platform_device *plat_dev) goto err_device_fini; xa_init_flags(&pvr_dev->free_list_ids, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_dev->job_ids, XA_FLAGS_ALLOC1); return 0; @@ -1413,6 +1439,11 @@ pvr_probe(struct platform_device *plat_dev) err_watchdog_fini: pvr_watchdog_fini(pvr_dev); + pvr_queue_device_fini(pvr_dev); + +err_context_fini: + pvr_context_device_fini(pvr_dev); + return err; } @@ -1422,14 +1453,17 @@ pvr_remove(struct platform_device *plat_dev) struct drm_device *drm_dev = platform_get_drvdata(plat_dev); struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + WARN_ON(!xa_empty(&pvr_dev->job_ids)); WARN_ON(!xa_empty(&pvr_dev->free_list_ids)); + xa_destroy(&pvr_dev->job_ids); xa_destroy(&pvr_dev->free_list_ids); pm_runtime_suspend(drm_dev->dev); pvr_device_fini(pvr_dev); drm_dev_unplug(drm_dev); pvr_watchdog_fini(pvr_dev); + pvr_queue_device_fini(pvr_dev); pvr_context_device_fini(pvr_dev); return 0; diff --git a/drivers/gpu/drm/imagination/pvr_job.c b/drivers/gpu/drm/imagination/pvr_job.c new file mode 100644 index 000000000000..9d0812710295 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_job.c @@ -0,0 +1,788 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" +#include "pvr_job.h" +#include "pvr_mmu.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_stream.h" +#include "pvr_stream_defs.h" +#include "pvr_sync.h" + +#include +#include +#include +#include + +static void pvr_job_release(struct kref *kref) +{ + struct pvr_job *job = container_of(kref, struct pvr_job, ref_count); + + xa_erase(&job->pvr_dev->job_ids, job->id); + + pvr_hwrt_data_put(job->hwrt); + pvr_context_put(job->ctx); + + WARN_ON(job->paired_job); + + pvr_queue_job_cleanup(job); + pvr_job_release_pm_ref(job); + + kfree(job->cmd); + kfree(job); +} + +/** + * pvr_job_put() - Release reference on job + * @job: Target job. + */ +void +pvr_job_put(struct pvr_job *job) +{ + if (job) + kref_put(&job->ref_count, pvr_job_release); +} + +/** + * pvr_job_process_stream() - Build job FW structure from stream + * @pvr_dev: Device pointer. + * @cmd_defs: Stream definition. + * @stream: Pointer to command stream. + * @stream_size: Size of command stream, in bytes. + * @job: Pointer to job. + * + * Caller is responsible for freeing the output structure. + * + * Returns: + * * 0 on success, + * * -%ENOMEM on out of memory, or + * * -%EINVAL on malformed stream. + */ +static int +pvr_job_process_stream(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, struct pvr_job *job) +{ + int err; + + job->cmd = kzalloc(cmd_defs->dest_size, GFP_KERNEL); + if (!job->cmd) + return -ENOMEM; + + job->cmd_len = cmd_defs->dest_size; + + err = pvr_stream_process(pvr_dev, cmd_defs, stream, stream_size, job->cmd); + if (err) + kfree(job->cmd); + + return err; +} + +static int pvr_fw_cmd_init(struct pvr_device *pvr_dev, struct pvr_job *job, + const struct pvr_stream_cmd_defs *stream_def, + u64 stream_userptr, u32 stream_len) +{ + void *stream; + int err; + + stream = kzalloc(stream_len, GFP_KERNEL); + if (!stream) + return -ENOMEM; + + if (copy_from_user(stream, u64_to_user_ptr(stream_userptr), stream_len)) { + err = -EFAULT; + goto err_free_stream; + } + + err = pvr_job_process_stream(pvr_dev, stream_def, stream, stream_len, job); + +err_free_stream: + kfree(stream); + + return err; +} + +static u32 +convert_geom_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST) + out_flags |= ROGUE_GEOM_FLAGS_FIRSTKICK; + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST) + out_flags |= ROGUE_GEOM_FLAGS_LASTKICK; + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE) + out_flags |= ROGUE_GEOM_FLAGS_SINGLE_CORE; + + return out_flags; +} + +static u32 +convert_frag_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE) + out_flags |= ROGUE_FRAG_FLAGS_SINGLE_CORE; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_DEPTHBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_STENCILBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP) + out_flags |= ROGUE_FRAG_FLAGS_PREVENT_CDM_OVERLAP; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_SCRATCHBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS) + out_flags |= ROGUE_FRAG_FLAGS_GET_VIS_RESULTS; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE) + out_flags |= ROGUE_FRAG_FLAGS_DISABLE_PIXELMERGE; + + return out_flags; +} + +static int +pvr_geom_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_geom *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_GEOM_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER) + return -EINVAL; + + if (!job->hwrt) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_GEOM; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_geom_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->cmd_shared.cmn.frame_num = 0; + cmd->flags = convert_geom_flags(args->flags); + pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr); + return 0; +} + +static int +pvr_frag_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_frag *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_FRAG_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER) + return -EINVAL; + + if (!job->hwrt) + return -EINVAL; + + job->fw_ccb_cmd_type = (args->flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER) ? + ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR : + ROGUE_FWIF_CCB_CMD_TYPE_FRAG; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_frag_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->cmd_shared.cmn.frame_num = 0; + cmd->flags = convert_frag_flags(args->flags); + pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr); + return 0; +} + +static u32 +convert_compute_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP) + out_flags |= ROGUE_COMPUTE_FLAG_PREVENT_ALL_OVERLAP; + if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE) + out_flags |= ROGUE_COMPUTE_FLAG_SINGLE_CORE; + + return out_flags; +} + +static int +pvr_compute_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_compute *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_COMPUTE) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_CDM; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_compute_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->common.frame_num = 0; + cmd->flags = convert_compute_flags(args->flags); + return 0; +} + +static u32 +convert_transfer_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE) + out_flags |= ROGUE_TRANSFER_FLAGS_SINGLE_CORE; + + return out_flags; +} + +static int +pvr_transfer_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_transfer *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_TRANSFER_FRAG) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_TQ_3D; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_transfer_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->common.frame_num = 0; + cmd->flags = convert_transfer_flags(args->flags); + return 0; +} + +static int +pvr_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + switch (args->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return pvr_geom_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return pvr_frag_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_COMPUTE: + return pvr_compute_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return pvr_transfer_job_fw_cmd_init(job, args); + + default: + return -EINVAL; + } +} + +/** + * struct pvr_job_data - Helper container for pairing jobs with the + * sync_ops supplied for them by the user. + */ +struct pvr_job_data { + /** @job: Pointer to the job. */ + struct pvr_job *job; + + /** @sync_ops: Pointer to the sync_ops associated with @job. */ + struct drm_pvr_sync_op *sync_ops; + + /** @sync_op_count: Number of members of @sync_ops. */ + u32 sync_op_count; +}; + +/** + * prepare_job_syncs() - Prepare all sync objects for a single job. + * @pvr_file: PowerVR file. + * @job_data: Precreated job and sync_ops array. + * @signal_array: xarray to receive signal sync objects. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_sync_signal_array_collect_ops(), + * pvr_sync_add_deps_to_job(), drm_sched_job_add_resv_dependencies() or + * pvr_sync_signal_array_update_fences(). + */ +static int +prepare_job_syncs(struct pvr_file *pvr_file, + struct pvr_job_data *job_data, + struct xarray *signal_array) +{ + struct dma_fence *done_fence; + int err = pvr_sync_signal_array_collect_ops(signal_array, + from_pvr_file(pvr_file), + job_data->sync_op_count, + job_data->sync_ops); + + if (err) + return err; + + err = pvr_sync_add_deps_to_job(pvr_file, &job_data->job->base, + job_data->sync_op_count, + job_data->sync_ops, signal_array); + if (err) + return err; + + if (job_data->job->hwrt) { + /* The geometry job writes the HWRT region headers, which are + * then read by the fragment job. + */ + struct drm_gem_object *obj = + gem_from_pvr_gem(job_data->job->hwrt->fw_obj->gem); + enum dma_resv_usage usage = + dma_resv_usage_rw(job_data->job->type == + DRM_PVR_JOB_TYPE_GEOMETRY); + + dma_resv_lock(obj->resv, NULL); + err = drm_sched_job_add_resv_dependencies(&job_data->job->base, + obj->resv, usage); + dma_resv_unlock(obj->resv); + if (err) + return err; + } + + /* We need to arm the job to get the job done fence. */ + done_fence = pvr_queue_job_arm(job_data->job); + + err = pvr_sync_signal_array_update_fences(signal_array, + job_data->sync_op_count, + job_data->sync_ops, + done_fence); + return err; +} + +/** + * prepare_job_syncs_for_each() - Prepare all sync objects for an array of jobs. + * @file: PowerVR file. + * @job_data: Array of precreated jobs and their sync_ops. + * @job_count: Number of jobs. + * @signal_array: xarray to receive signal sync objects. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_vm_bind_job_prepare_syncs(). + */ +static int +prepare_job_syncs_for_each(struct pvr_file *pvr_file, + struct pvr_job_data *job_data, + u32 *job_count, + struct xarray *signal_array) +{ + for (u32 i = 0; i < *job_count; i++) { + int err = prepare_job_syncs(pvr_file, &job_data[i], + signal_array); + + if (err) { + *job_count = i; + return err; + } + } + + return 0; +} + +static struct pvr_job * +create_job(struct pvr_device *pvr_dev, + struct pvr_file *pvr_file, + struct drm_pvr_job *args) +{ + struct pvr_job *job = NULL; + int err; + + if (!args->cmd_stream || !args->cmd_stream_len) + return ERR_PTR(-EINVAL); + + if (args->type != DRM_PVR_JOB_TYPE_GEOMETRY && + args->type != DRM_PVR_JOB_TYPE_FRAGMENT && + (args->hwrt.set_handle || args->hwrt.data_index)) + return ERR_PTR(-EINVAL); + + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return ERR_PTR(-ENOMEM); + + kref_init(&job->ref_count); + job->type = args->type; + job->pvr_dev = pvr_dev; + + err = xa_alloc(&pvr_dev->job_ids, &job->id, job, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_put_job; + + job->ctx = pvr_context_lookup(pvr_file, args->context_handle); + if (!job->ctx) { + err = -EINVAL; + goto err_put_job; + } + + if (args->hwrt.set_handle) { + job->hwrt = pvr_hwrt_data_lookup(pvr_file, args->hwrt.set_handle, + args->hwrt.data_index); + if (!job->hwrt) { + err = -EINVAL; + goto err_put_job; + } + } + + err = pvr_job_fw_cmd_init(job, args); + if (err) + goto err_put_job; + + err = pvr_queue_job_init(job); + if (err) + goto err_put_job; + + return job; + +err_put_job: + pvr_job_put(job); + return ERR_PTR(err); +} + +/** + * pvr_job_data_fini() - Cleanup all allocs used to set up job submission. + * @job_data: Job data array. + * @job_count: Number of members of @job_data. + */ +static void +pvr_job_data_fini(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) { + pvr_job_put(job_data[i].job); + kvfree(job_data[i].sync_ops); + } +} + +/** + * pvr_job_data_init() - Init an array of created jobs, associating them with + * the appropriate sync_ops args, which will be copied in. + * @pvr_dev: Target PowerVR device. + * @pvr_file: Pointer to PowerVR file structure. + * @job_args: Job args array copied from user. + * @job_count: Number of members of @job_args. + * @job_data_out: Job data array. + */ +static int pvr_job_data_init(struct pvr_device *pvr_dev, + struct pvr_file *pvr_file, + struct drm_pvr_job *job_args, + u32 *job_count, + struct pvr_job_data *job_data_out) +{ + int err = 0, i = 0; + + for (; i < *job_count; i++) { + job_data_out[i].job = + create_job(pvr_dev, pvr_file, &job_args[i]); + err = PTR_ERR_OR_ZERO(job_data_out[i].job); + + if (err) { + *job_count = i; + job_data_out[i].job = NULL; + goto err_cleanup; + } + + err = PVR_UOBJ_GET_ARRAY(job_data_out[i].sync_ops, + &job_args[i].sync_ops); + if (err) { + *job_count = i; + + /* Ensure the job created above is also cleaned up. */ + i++; + goto err_cleanup; + } + + job_data_out[i].sync_op_count = job_args[i].sync_ops.count; + } + + return 0; + +err_cleanup: + pvr_job_data_fini(job_data_out, i); + + return err; +} + +static void +push_jobs(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) + pvr_queue_job_push(job_data[i].job); +} + +static int +prepare_fw_obj_resv(struct drm_exec *exec, struct pvr_fw_object *fw_obj) +{ + return drm_exec_prepare_obj(exec, gem_from_pvr_gem(fw_obj->gem), 1); +} + +static int +jobs_lock_all_objs(struct drm_exec *exec, struct pvr_job_data *job_data, + u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) { + struct pvr_job *job = job_data[i].job; + + /* Grab a lock on a the context, to guard against + * concurrent submission to the same queue. + */ + int err = drm_exec_lock_obj(exec, + gem_from_pvr_gem(job->ctx->fw_obj->gem)); + + if (err) + return err; + + if (job->hwrt) { + err = prepare_fw_obj_resv(exec, + job->hwrt->fw_obj); + if (err) + return err; + } + } + + return 0; +} + +static int +prepare_job_resvs_for_each(struct drm_exec *exec, struct pvr_job_data *job_data, + u32 job_count) +{ + drm_exec_until_all_locked(exec) { + int err = jobs_lock_all_objs(exec, job_data, job_count); + + drm_exec_retry_on_contention(exec); + if (err) + return err; + } + + return 0; +} + +static void +update_job_resvs(struct pvr_job *job) +{ + if (job->hwrt) { + enum dma_resv_usage usage = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? + DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ; + struct drm_gem_object *obj = gem_from_pvr_gem(job->hwrt->fw_obj->gem); + + dma_resv_add_fence(obj->resv, &job->base.s_fence->finished, usage); + } +} + +static void +update_job_resvs_for_each(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) + update_job_resvs(job_data[i].job); +} + +static bool can_combine_jobs(struct pvr_job *a, struct pvr_job *b) +{ + struct pvr_job *geom_job = a, *frag_job = b; + struct dma_fence *fence; + unsigned long index; + + /* Geometry and fragment jobs can be combined if they are queued to the + * same context and targeting the same HWRT. + */ + if (a->type != DRM_PVR_JOB_TYPE_GEOMETRY || + b->type != DRM_PVR_JOB_TYPE_FRAGMENT || + a->ctx != b->ctx || + a->hwrt != b->hwrt) + return false; + + xa_for_each(&frag_job->base.dependencies, index, fence) { + /* We combine when we see an explicit geom -> frag dep. */ + if (&geom_job->base.s_fence->scheduled == fence) + return true; + } + + return false; +} + +static struct dma_fence * +get_last_queued_job_scheduled_fence(struct pvr_queue *queue, + struct pvr_job_data *job_data, + u32 cur_job_pos) +{ + /* We iterate over the current job array in reverse order to grab the + * last to-be-queued job targeting the same queue. + */ + for (u32 i = cur_job_pos; i > 0; i--) { + struct pvr_job *job = job_data[i - 1].job; + + if (job->ctx == queue->ctx && job->type == queue->type) + return dma_fence_get(&job->base.s_fence->scheduled); + } + + /* If we didn't find any, we just return the last queued job scheduled + * fence attached to the queue. + */ + return dma_fence_get(queue->last_queued_job_scheduled_fence); +} + +static int +pvr_jobs_link_geom_frag(struct pvr_job_data *job_data, u32 *job_count) +{ + for (u32 i = 0; i < *job_count - 1; i++) { + struct pvr_job *geom_job = job_data[i].job; + struct pvr_job *frag_job = job_data[i + 1].job; + struct pvr_queue *frag_queue; + struct dma_fence *f; + + if (!can_combine_jobs(job_data[i].job, job_data[i + 1].job)) + continue; + + /* The fragment job will be submitted by the geometry queue. We + * need to make sure it comes after all the other fragment jobs + * queued before it. + */ + frag_queue = pvr_context_get_queue_for_job(frag_job->ctx, + frag_job->type); + f = get_last_queued_job_scheduled_fence(frag_queue, job_data, + i); + if (f) { + int err = drm_sched_job_add_dependency(&geom_job->base, + f); + if (err) { + *job_count = i; + return err; + } + } + + /* The KCCB slot will be reserved by the geometry job, so we can + * drop the KCCB fence on the fragment job. + */ + pvr_kccb_fence_put(frag_job->kccb_fence); + frag_job->kccb_fence = NULL; + + geom_job->paired_job = frag_job; + frag_job->paired_job = geom_job; + + /* Skip the fragment job we just paired to the geometry job. */ + i++; + } + + return 0; +} + +/** + * pvr_submit_jobs() - Submit jobs to the GPU + * @pvr_dev: Target PowerVR device. + * @pvr_file: Pointer to PowerVR file structure. + * @args: Ioctl args. + * @job_count: Number of jobs in @jobs_args. On error this will be updated + * with the index into @jobs_args where the error occurred. + * + * This initial implementation is entirely synchronous; on return the GPU will + * be idle. This will not be the case for future implementations. + * + * Returns: + * * 0 on success, + * * -%EFAULT if arguments can not be copied from user space, or + * * -%EINVAL on invalid arguments, or + * * Any other error. + */ +int +pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file, + struct drm_pvr_ioctl_submit_jobs_args *args) +{ + struct pvr_job_data *job_data = NULL; + struct drm_pvr_job *job_args; + struct xarray signal_array; + u32 jobs_alloced = 0; + struct drm_exec exec; + int err; + + if (!args->jobs.count) + return -EINVAL; + + err = PVR_UOBJ_GET_ARRAY(job_args, &args->jobs); + if (err) + return err; + + job_data = kvmalloc_array(args->jobs.count, sizeof(*job_data), + GFP_KERNEL | __GFP_ZERO); + if (!job_data) { + err = -ENOMEM; + goto out_free; + } + + err = pvr_job_data_init(pvr_dev, pvr_file, job_args, &args->jobs.count, + job_data); + if (err) + goto out_free; + + jobs_alloced = args->jobs.count; + + /* + * Flush MMU if needed - this has been deferred until now to avoid + * overuse of this expensive operation. + */ + err = pvr_mmu_flush_exec(pvr_dev, false); + if (err) + goto out_job_data_cleanup; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); + + xa_init_flags(&signal_array, XA_FLAGS_ALLOC); + + err = prepare_job_syncs_for_each(pvr_file, job_data, &args->jobs.count, + &signal_array); + if (err) + goto out_exec_fini; + + err = prepare_job_resvs_for_each(&exec, job_data, args->jobs.count); + if (err) + goto out_exec_fini; + + err = pvr_jobs_link_geom_frag(job_data, &args->jobs.count); + if (err) + goto out_exec_fini; + + /* Anything after that point must succeed because we start exposing job + * finished fences to the outside world. + */ + update_job_resvs_for_each(job_data, args->jobs.count); + push_jobs(job_data, args->jobs.count); + pvr_sync_signal_array_push_fences(&signal_array); + err = 0; + +out_exec_fini: + drm_exec_fini(&exec); + pvr_sync_signal_array_cleanup(&signal_array); + +out_job_data_cleanup: + pvr_job_data_fini(job_data, jobs_alloced); + +out_free: + kvfree(job_data); + kvfree(job_args); + + return err; +} diff --git a/drivers/gpu/drm/imagination/pvr_job.h b/drivers/gpu/drm/imagination/pvr_job.h new file mode 100644 index 000000000000..0ca003c5c475 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_job.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_JOB_H +#define PVR_JOB_H + +#include + +#include +#include + +#include +#include + +#include "pvr_power.h" + +/* Forward declaration from "pvr_context.h". */ +struct pvr_context; + +/* Forward declarations from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +/* Forward declarations from "pvr_hwrt.h". */ +struct pvr_hwrt_data; + +/* Forward declaration from "pvr_queue.h". */ +struct pvr_queue; + +struct pvr_job { + /** @base: drm_sched_job object. */ + struct drm_sched_job base; + + /** @ref_count: Refcount for job. */ + struct kref ref_count; + + /** @type: Type of job. */ + enum drm_pvr_job_type type; + + /** @id: Job ID number. */ + u32 id; + + /** + * @paired_job: Job paired to this job. + * + * This field is only meaningful for geometry and fragment jobs. + * + * Paired jobs are executed on the same context, and need to be submitted + * atomically to the FW, to make sure the partial render logic has a + * fragment job to execute when the Parameter Manager runs out of memory. + * + * The geometry job should point to the fragment job it's paired with, + * and the fragment job should point to the geometry job it's paired with. + */ + struct pvr_job *paired_job; + + /** @cccb_fence: Fence used to wait for CCCB space. */ + struct dma_fence *cccb_fence; + + /** @kccb_fence: Fence used to wait for KCCB space. */ + struct dma_fence *kccb_fence; + + /** @done_fence: Fence to signal when the job is done. */ + struct dma_fence *done_fence; + + /** @pvr_dev: Device pointer. */ + struct pvr_device *pvr_dev; + + /** @ctx: Pointer to owning context. */ + struct pvr_context *ctx; + + /** @cmd: Command data. Format depends on @type. */ + void *cmd; + + /** @cmd_len: Length of command data, in bytes. */ + u32 cmd_len; + + /** + * @fw_ccb_cmd_type: Firmware CCB command type. Must be one of %ROGUE_FWIF_CCB_CMD_TYPE_*. + */ + u32 fw_ccb_cmd_type; + + /** @hwrt: HWRT object. Will be NULL for compute and transfer jobs. */ + struct pvr_hwrt_data *hwrt; + + /** + * @has_pm_ref: True if the job has a power ref, thus forcing the GPU to stay on until + * the job is done. + */ + bool has_pm_ref; +}; + +/** + * pvr_job_get() - Take additional reference on job. + * @job: Job pointer. + * + * Call pvr_job_put() to release. + * + * Returns: + * * The requested job on success, or + * * %NULL if no job pointer passed. + */ +static __always_inline struct pvr_job * +pvr_job_get(struct pvr_job *job) +{ + if (job) + kref_get(&job->ref_count); + + return job; +} + +void pvr_job_put(struct pvr_job *job); + +/** + * pvr_job_release_pm_ref() - Release the PM ref if the job acquired it. + * @job: The job to release the PM ref on. + */ +static __always_inline void +pvr_job_release_pm_ref(struct pvr_job *job) +{ + if (job->has_pm_ref) { + pvr_power_put(job->pvr_dev); + job->has_pm_ref = false; + } +} + +/** + * pvr_job_get_pm_ref() - Get a PM ref and attach it to the job. + * @job: The job to attach the PM ref to. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_power_get() otherwise. + */ +static __always_inline int +pvr_job_get_pm_ref(struct pvr_job *job) +{ + int err; + + if (job->has_pm_ref) + return 0; + + err = pvr_power_get(job->pvr_dev); + if (!err) + job->has_pm_ref = true; + + return err; +} + +int pvr_job_wait_first_non_signaled_native_dep(struct pvr_job *job); + +bool pvr_job_non_native_deps_done(struct pvr_job *job); + +int pvr_job_fits_in_cccb(struct pvr_job *job, unsigned long native_dep_count); + +void pvr_job_submit(struct pvr_job *job); + +int pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file, + struct drm_pvr_ioctl_submit_jobs_args *args); + +#endif /* PVR_JOB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c index 5f7cb7beb879..ba7816fd28ec 100644 --- a/drivers/gpu/drm/imagination/pvr_power.c +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -5,6 +5,7 @@ #include "pvr_fw.h" #include "pvr_fw_startstop.h" #include "pvr_power.h" +#include "pvr_queue.h" #include "pvr_rogue_fwif.h" #include @@ -155,6 +156,21 @@ pvr_watchdog_kccb_stalled(struct pvr_device *pvr_dev) pvr_dev->watchdog.kccb_stall_count = 0; return true; } + } else if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed) { + bool has_active_contexts; + + mutex_lock(&pvr_dev->queues.lock); + has_active_contexts = list_empty(&pvr_dev->queues.active); + mutex_unlock(&pvr_dev->queues.lock); + + if (has_active_contexts) { + /* Send a HEALTH_CHECK command so we can verify FW is still alive. */ + struct rogue_fwif_kccb_cmd health_check_cmd; + + health_check_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_HEALTH_CHECK; + + pvr_kccb_send_cmd_powered(pvr_dev, &health_check_cmd, NULL); + } } else { pvr_dev->watchdog.old_kccb_cmds_executed = kccb_cmds_executed; pvr_dev->watchdog.kccb_stall_count = 0; @@ -318,6 +334,7 @@ pvr_power_device_idle(struct device *dev) int pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) { + bool queues_disabled = false; int err; /* @@ -337,6 +354,11 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) disable_irq(pvr_dev->irq); do { + if (hard_reset) { + pvr_queue_device_pre_reset(pvr_dev); + queues_disabled = true; + } + err = pvr_power_fw_disable(pvr_dev, hard_reset); if (!err) { if (hard_reset) { @@ -372,6 +394,9 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) } } while (err); + if (queues_disabled) + pvr_queue_device_post_reset(pvr_dev); + enable_irq(pvr_dev->irq); up_write(&pvr_dev->reset_sem); @@ -386,6 +411,9 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) /* Leave IRQs disabled if the device is lost. */ + if (queues_disabled) + pvr_queue_device_post_reset(pvr_dev); + err_up_write: up_write(&pvr_dev->reset_sem); diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c new file mode 100644 index 000000000000..d65c3fbedf5a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -0,0 +1,1432 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include +#include + +#include "pvr_cccb.h" +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_job.h" +#include "pvr_queue.h" +#include "pvr_vm.h" + +#include "pvr_rogue_fwif_client.h" + +#define MAX_DEADLINE_MS 30000 + +#define CTX_COMPUTE_CCCB_SIZE_LOG2 15 +#define CTX_FRAG_CCCB_SIZE_LOG2 15 +#define CTX_GEOM_CCCB_SIZE_LOG2 15 +#define CTX_TRANSFER_CCCB_SIZE_LOG2 15 + +static int get_xfer_ctx_state_size(struct pvr_device *pvr_dev) +{ + u32 num_isp_store_registers; + + if (PVR_HAS_FEATURE(pvr_dev, xe_memory_hierarchy)) { + num_isp_store_registers = 1; + } else { + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, num_isp_ipp_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + } + + return sizeof(struct rogue_fwif_frag_ctx_state) + + (num_isp_store_registers * + sizeof(((struct rogue_fwif_frag_ctx_state *)0)->frag_reg_isp_store[0])); +} + +static int get_frag_ctx_state_size(struct pvr_device *pvr_dev) +{ + u32 num_isp_store_registers; + int err; + + if (PVR_HAS_FEATURE(pvr_dev, xe_memory_hierarchy)) { + err = PVR_FEATURE_VALUE(pvr_dev, num_raster_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + + if (PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support)) { + u32 xpu_max_slaves; + + err = PVR_FEATURE_VALUE(pvr_dev, xpu_max_slaves, &xpu_max_slaves); + if (WARN_ON(err)) + return err; + + num_isp_store_registers *= (1 + xpu_max_slaves); + } + } else { + err = PVR_FEATURE_VALUE(pvr_dev, num_isp_ipp_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + } + + return sizeof(struct rogue_fwif_frag_ctx_state) + + (num_isp_store_registers * + sizeof(((struct rogue_fwif_frag_ctx_state *)0)->frag_reg_isp_store[0])); +} + +static int get_ctx_state_size(struct pvr_device *pvr_dev, enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return sizeof(struct rogue_fwif_geom_ctx_state); + case DRM_PVR_JOB_TYPE_FRAGMENT: + return get_frag_ctx_state_size(pvr_dev); + case DRM_PVR_JOB_TYPE_COMPUTE: + return sizeof(struct rogue_fwif_compute_ctx_state); + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return get_xfer_ctx_state_size(pvr_dev); + } + + WARN(1, "Invalid queue type"); + return -EINVAL; +} + +static u32 get_ctx_offset(enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return offsetof(struct rogue_fwif_fwrendercontext, geom_context); + case DRM_PVR_JOB_TYPE_FRAGMENT: + return offsetof(struct rogue_fwif_fwrendercontext, frag_context); + case DRM_PVR_JOB_TYPE_COMPUTE: + return offsetof(struct rogue_fwif_fwcomputecontext, cdm_context); + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return offsetof(struct rogue_fwif_fwtransfercontext, tq_context); + } + + return 0; +} + +static const char * +pvr_queue_fence_get_driver_name(struct dma_fence *f) +{ + return PVR_DRIVER_NAME; +} + +static void pvr_queue_fence_release(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + pvr_context_put(fence->queue->ctx); + dma_fence_free(f); +} + +static const char * +pvr_queue_job_fence_get_timeline_name(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + switch (fence->queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return "geometry"; + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return "fragment"; + + case DRM_PVR_JOB_TYPE_COMPUTE: + return "compute"; + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return "transfer"; + } + + WARN(1, "Invalid queue type"); + return "invalid"; +} + +static const char * +pvr_queue_cccb_fence_get_timeline_name(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + switch (fence->queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return "geometry-cccb"; + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return "fragment-cccb"; + + case DRM_PVR_JOB_TYPE_COMPUTE: + return "compute-cccb"; + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return "transfer-cccb"; + } + + WARN(1, "Invalid queue type"); + return "invalid"; +} + +static const struct dma_fence_ops pvr_queue_job_fence_ops = { + .get_driver_name = pvr_queue_fence_get_driver_name, + .get_timeline_name = pvr_queue_job_fence_get_timeline_name, + .release = pvr_queue_fence_release, +}; + +/** + * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is + * backed by a UFO. + * @f: The dma_fence to turn into a pvr_queue_fence. + * + * Return: + * * A non-NULL pvr_queue_fence object if the dma_fence is backed by a UFO, or + * * NULL otherwise. + */ +static struct pvr_queue_fence * +to_pvr_queue_job_fence(struct dma_fence *f) +{ + struct drm_sched_fence *sched_fence = to_drm_sched_fence(f); + + if (sched_fence) + f = sched_fence->parent; + + if (f && f->ops == &pvr_queue_job_fence_ops) + return container_of(f, struct pvr_queue_fence, base); + + return NULL; +} + +static const struct dma_fence_ops pvr_queue_cccb_fence_ops = { + .get_driver_name = pvr_queue_fence_get_driver_name, + .get_timeline_name = pvr_queue_cccb_fence_get_timeline_name, + .release = pvr_queue_fence_release, +}; + +/** + * pvr_queue_fence_put() - Put wrapper for pvr_queue_fence objects. + * @f: The dma_fence object to put. + * + * If the pvr_queue_fence has been initialized, we call dma_fence_put(), + * otherwise we free the object with dma_fence_free(). This allows us + * to do the right thing before and after pvr_queue_fence_init() had been + * called. + */ +static void pvr_queue_fence_put(struct dma_fence *f) +{ + if (!f) + return; + + if (WARN_ON(f->ops && + f->ops != &pvr_queue_cccb_fence_ops && + f->ops != &pvr_queue_job_fence_ops)) + return; + + /* If the fence hasn't been initialized yet, free the object directly. */ + if (f->ops) + dma_fence_put(f); + else + dma_fence_free(f); +} + +/** + * pvr_queue_fence_alloc() - Allocate a pvr_queue_fence fence object + * + * Call this function to allocate job CCCB and done fences. This only + * allocates the objects. Initialization happens when the underlying + * dma_fence object is to be returned to drm_sched (in prepare_job() or + * run_job()). + * + * Return: + * * A valid pointer if the allocation succeeds, or + * * NULL if the allocation fails. + */ +static struct dma_fence * +pvr_queue_fence_alloc(void) +{ + struct pvr_queue_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return NULL; + + return &fence->base; +} + +/** + * pvr_queue_fence_init() - Initializes a pvr_queue_fence object. + * @f: The fence to initialize + * @queue: The queue this fence belongs to. + * @fence_ops: The fence operations. + * @fence_ctx: The fence context. + * + * Wrapper around dma_fence_init() that takes care of initializing the + * pvr_queue_fence::queue field too. + */ +static void +pvr_queue_fence_init(struct dma_fence *f, + struct pvr_queue *queue, + const struct dma_fence_ops *fence_ops, + struct pvr_queue_fence_ctx *fence_ctx) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + pvr_context_get(queue->ctx); + fence->queue = queue; + dma_fence_init(&fence->base, fence_ops, + &fence_ctx->lock, fence_ctx->id, + atomic_inc_return(&fence_ctx->seqno)); +} + +/** + * pvr_queue_cccb_fence_init() - Initializes a CCCB fence object. + * @fence: The fence to initialize. + * @queue: The queue this fence belongs to. + * + * Initializes a fence that can be used to wait for CCCB space. + * + * Should be called in the ::prepare_job() path, so the fence returned to + * drm_sched is valid. + */ +static void +pvr_queue_cccb_fence_init(struct dma_fence *fence, struct pvr_queue *queue) +{ + pvr_queue_fence_init(fence, queue, &pvr_queue_cccb_fence_ops, + &queue->cccb_fence_ctx.base); +} + +/** + * pvr_queue_job_fence_init() - Initializes a job done fence object. + * @fence: The fence to initialize. + * @queue: The queue this fence belongs to. + * + * Initializes a fence that will be signaled when the GPU is done executing + * a job. + * + * Should be called *before* the ::run_job() path, so the fence is initialised + * before being placed in the pending_list. + */ +static void +pvr_queue_job_fence_init(struct dma_fence *fence, struct pvr_queue *queue) +{ + pvr_queue_fence_init(fence, queue, &pvr_queue_job_fence_ops, + &queue->job_fence_ctx); +} + +/** + * pvr_queue_fence_ctx_init() - Queue fence context initialization. + * @fence_ctx: The context to initialize + */ +static void +pvr_queue_fence_ctx_init(struct pvr_queue_fence_ctx *fence_ctx) +{ + spin_lock_init(&fence_ctx->lock); + fence_ctx->id = dma_fence_context_alloc(1); + atomic_set(&fence_ctx->seqno, 0); +} + +static u32 ufo_cmds_size(u32 elem_count) +{ + /* We can pass at most ROGUE_FWIF_CCB_CMD_MAX_UFOS per UFO-related command. */ + u32 full_cmd_count = elem_count / ROGUE_FWIF_CCB_CMD_MAX_UFOS; + u32 remaining_elems = elem_count % ROGUE_FWIF_CCB_CMD_MAX_UFOS; + u32 size = full_cmd_count * + pvr_cccb_get_size_of_cmd_with_hdr(ROGUE_FWIF_CCB_CMD_MAX_UFOS * + sizeof(struct rogue_fwif_ufo)); + + if (remaining_elems) { + size += pvr_cccb_get_size_of_cmd_with_hdr(remaining_elems * + sizeof(struct rogue_fwif_ufo)); + } + + return size; +} + +static u32 job_cmds_size(struct pvr_job *job, u32 ufo_wait_count) +{ + /* One UFO cmd for the fence signaling, one UFO cmd per native fence native, + * and a command for the job itself. + */ + return ufo_cmds_size(1) + ufo_cmds_size(ufo_wait_count) + + pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len); +} + +/** + * job_count_remaining_native_deps() - Count the number of non-signaled native dependencies. + * @job: Job to operate on. + * + * Returns: Number of non-signaled native deps remaining. + */ +static unsigned long job_count_remaining_native_deps(struct pvr_job *job) +{ + unsigned long remaining_count = 0; + struct dma_fence *fence = NULL; + unsigned long index; + + xa_for_each(&job->base.dependencies, index, fence) { + struct pvr_queue_fence *jfence; + + jfence = to_pvr_queue_job_fence(fence); + if (!jfence) + continue; + + if (!dma_fence_is_signaled(&jfence->base)) + remaining_count++; + } + + return remaining_count; +} + +/** + * pvr_queue_get_job_cccb_fence() - Get the CCCB fence attached to a job. + * @queue: The queue this job will be submitted to. + * @job: The job to get the CCCB fence on. + * + * The CCCB fence is a synchronization primitive allowing us to delay job + * submission until there's enough space in the CCCB to submit the job. + * + * Return: + * * NULL if there's enough space in the CCCB to submit this job, or + * * A valid dma_fence object otherwise. + */ +static struct dma_fence * +pvr_queue_get_job_cccb_fence(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_queue_fence *cccb_fence; + unsigned int native_deps_remaining; + + /* If the fence is NULL, that means we already checked that we had + * enough space in the cccb for our job. + */ + if (!job->cccb_fence) + return NULL; + + mutex_lock(&queue->cccb_fence_ctx.job_lock); + + /* Count remaining native dependencies and check if the job fits in the CCCB. */ + native_deps_remaining = job_count_remaining_native_deps(job); + if (pvr_cccb_cmdseq_fits(&queue->cccb, job_cmds_size(job, native_deps_remaining))) { + pvr_queue_fence_put(job->cccb_fence); + job->cccb_fence = NULL; + goto out_unlock; + } + + /* There should be no job attached to the CCCB fence context: + * drm_sched_entity guarantees that jobs are submitted one at a time. + */ + if (WARN_ON(queue->cccb_fence_ctx.job)) + pvr_job_put(queue->cccb_fence_ctx.job); + + queue->cccb_fence_ctx.job = pvr_job_get(job); + + /* Initialize the fence before returning it. */ + cccb_fence = container_of(job->cccb_fence, struct pvr_queue_fence, base); + if (!WARN_ON(cccb_fence->queue)) + pvr_queue_cccb_fence_init(job->cccb_fence, queue); + +out_unlock: + mutex_unlock(&queue->cccb_fence_ctx.job_lock); + + return dma_fence_get(job->cccb_fence); +} + +/** + * pvr_queue_get_job_kccb_fence() - Get the KCCB fence attached to a job. + * @queue: The queue this job will be submitted to. + * @job: The job to get the KCCB fence on. + * + * The KCCB fence is a synchronization primitive allowing us to delay job + * submission until there's enough space in the KCCB to submit the job. + * + * Return: + * * NULL if there's enough space in the KCCB to submit this job, or + * * A valid dma_fence object otherwise. + */ +static struct dma_fence * +pvr_queue_get_job_kccb_fence(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + struct dma_fence *kccb_fence = NULL; + + /* If the fence is NULL, that means we already checked that we had + * enough space in the KCCB for our job. + */ + if (!job->kccb_fence) + return NULL; + + if (!WARN_ON(job->kccb_fence->ops)) { + kccb_fence = pvr_kccb_reserve_slot(pvr_dev, job->kccb_fence); + job->kccb_fence = NULL; + } + + return kccb_fence; +} + +static struct dma_fence * +pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_job *frag_job = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? + job->paired_job : NULL; + struct dma_fence *f; + unsigned long index; + + if (!frag_job) + return NULL; + + xa_for_each(&frag_job->base.dependencies, index, f) { + /* Skip already signaled fences. */ + if (dma_fence_is_signaled(f)) + continue; + + /* Skip our own fence. */ + if (f == &job->base.s_fence->scheduled) + continue; + + return dma_fence_get(f); + } + + return frag_job->base.sched->ops->prepare_job(&frag_job->base, &queue->entity); +} + +/** + * pvr_queue_prepare_job() - Return the next internal dependencies expressed as a dma_fence. + * @sched_job: The job to query the next internal dependency on + * @s_entity: The entity this job is queue on. + * + * After iterating over drm_sched_job::dependencies, drm_sched let the driver return + * its own internal dependencies. We use this function to return our internal dependencies. + */ +static struct dma_fence * +pvr_queue_prepare_job(struct drm_sched_job *sched_job, + struct drm_sched_entity *s_entity) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + struct pvr_queue *queue = container_of(s_entity, struct pvr_queue, entity); + struct dma_fence *internal_dep = NULL; + + /* + * Initialize the done_fence, so we can signal it. This must be done + * here because otherwise by the time of run_job() the job will end up + * in the pending list without a valid fence. + */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + /* + * This will be called on a paired fragment job after being + * submitted to firmware. We can tell if this is the case and + * bail early from whether run_job() has been called on the + * geometry job, which would issue a pm ref. + */ + if (job->paired_job->has_pm_ref) + return NULL; + + /* + * In this case we need to use the job's own ctx to initialise + * the done_fence. The other steps are done in the ctx of the + * paired geometry job. + */ + pvr_queue_job_fence_init(job->done_fence, + job->ctx->queues.fragment); + } else { + pvr_queue_job_fence_init(job->done_fence, queue); + } + + /* CCCB fence is used to make sure we have enough space in the CCCB to + * submit our commands. + */ + internal_dep = pvr_queue_get_job_cccb_fence(queue, job); + + /* KCCB fence is used to make sure we have a KCCB slot to queue our + * CMD_KICK. + */ + if (!internal_dep) + internal_dep = pvr_queue_get_job_kccb_fence(queue, job); + + /* Any extra internal dependency should be added here, using the following + * pattern: + * + * if (!internal_dep) + * internal_dep = pvr_queue_get_job_xxxx_fence(queue, job); + */ + + /* The paired job fence should come last, when everything else is ready. */ + if (!internal_dep) + internal_dep = pvr_queue_get_paired_frag_job_dep(queue, job); + + return internal_dep; +} + +/** + * pvr_queue_update_active_state_locked() - Update the queue active state. + * @queue: Queue to update the state on. + * + * Locked version of pvr_queue_update_active_state(). Must be called with + * pvr_device::queue::lock held. + */ +static void pvr_queue_update_active_state_locked(struct pvr_queue *queue) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + + lockdep_assert_held(&pvr_dev->queues.lock); + + /* The queue is temporary out of any list when it's being reset, + * we don't want a call to pvr_queue_update_active_state_locked() + * to re-insert it behind our back. + */ + if (list_empty(&queue->node)) + return; + + if (!atomic_read(&queue->in_flight_job_count)) + list_move_tail(&queue->node, &pvr_dev->queues.idle); + else + list_move_tail(&queue->node, &pvr_dev->queues.active); +} + +/** + * pvr_queue_update_active_state() - Update the queue active state. + * @queue: Queue to update the state on. + * + * Active state is based on the in_flight_job_count value. + * + * Updating the active state implies moving the queue in or out of the + * active queue list, which also defines whether the queue is checked + * or not when a FW event is received. + * + * This function should be called any time a job is submitted or it done + * fence is signaled. + */ +static void pvr_queue_update_active_state(struct pvr_queue *queue) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + + mutex_lock(&pvr_dev->queues.lock); + pvr_queue_update_active_state_locked(queue); + mutex_unlock(&pvr_dev->queues.lock); +} + +static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) +{ + struct pvr_queue *queue = container_of(job->base.sched, struct pvr_queue, scheduler); + struct rogue_fwif_ufo ufos[ROGUE_FWIF_CCB_CMD_MAX_UFOS]; + struct pvr_cccb *cccb = &queue->cccb; + struct pvr_queue_fence *jfence; + struct dma_fence *fence; + unsigned long index; + u32 ufo_count = 0; + + /* We need to add the queue to the active list before updating the CCCB, + * otherwise we might miss the FW event informing us that something + * happened on this queue. + */ + atomic_inc(&queue->in_flight_job_count); + pvr_queue_update_active_state(queue); + + xa_for_each(&job->base.dependencies, index, fence) { + jfence = to_pvr_queue_job_fence(fence); + if (!jfence) + continue; + + /* Skip the partial render fence, we will place it at the end. */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job && + &job->paired_job->base.s_fence->scheduled == fence) + continue; + + if (dma_fence_is_signaled(&jfence->base)) + continue; + + pvr_fw_object_get_fw_addr(jfence->queue->timeline_ufo.fw_obj, + &ufos[ufo_count].addr); + ufos[ufo_count++].value = jfence->base.seqno; + + if (ufo_count == ARRAY_SIZE(ufos)) { + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR, + sizeof(ufos), ufos, 0, 0); + ufo_count = 0; + } + } + + /* Partial render fence goes last. */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + jfence = to_pvr_queue_job_fence(job->paired_job->done_fence); + if (!WARN_ON(!jfence)) { + pvr_fw_object_get_fw_addr(jfence->queue->timeline_ufo.fw_obj, + &ufos[ufo_count].addr); + ufos[ufo_count++].value = job->paired_job->done_fence->seqno; + } + } + + if (ufo_count) { + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR, + sizeof(ufos[0]) * ufo_count, ufos, 0, 0); + } + + if (job->type == DRM_PVR_JOB_TYPE_GEOMETRY && job->paired_job) { + struct rogue_fwif_cmd_geom *cmd = job->cmd; + + /* Reference value for the partial render test is the current queue fence + * seqno minus one. + */ + pvr_fw_object_get_fw_addr(queue->timeline_ufo.fw_obj, + &cmd->partial_render_geom_frag_fence.addr); + cmd->partial_render_geom_frag_fence.value = job->done_fence->seqno - 1; + } + + /* Submit job to FW */ + pvr_cccb_write_command_with_header(cccb, job->fw_ccb_cmd_type, job->cmd_len, job->cmd, + job->id, job->id); + + /* Signal the job fence. */ + pvr_fw_object_get_fw_addr(queue->timeline_ufo.fw_obj, &ufos[0].addr); + ufos[0].value = job->done_fence->seqno; + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_UPDATE, + sizeof(ufos[0]), ufos, 0, 0); +} + +/** + * pvr_queue_run_job() - Submit a job to the FW. + * @sched_job: The job to submit. + * + * This function is called when all non-native dependencies have been met and + * when the commands resulting from this job are guaranteed to fit in the CCCB. + */ +static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + struct pvr_device *pvr_dev = job->pvr_dev; + int err; + + /* The fragment job is issued along the geometry job when we use combined + * geom+frag kicks. When we get there, we should simply return the + * done_fence that's been initialized earlier. + */ + if (job->paired_job && job->type == DRM_PVR_JOB_TYPE_FRAGMENT && + job->done_fence->ops) { + return dma_fence_get(job->done_fence); + } + + /* The only kind of jobs that can be paired are geometry and fragment, and + * we bail out early if we see a fragment job that's paired with a geomtry + * job. + * Paired jobs must also target the same context and point to the same + * HWRT. + */ + if (WARN_ON(job->paired_job && + (job->type != DRM_PVR_JOB_TYPE_GEOMETRY || + job->paired_job->type != DRM_PVR_JOB_TYPE_FRAGMENT || + job->hwrt != job->paired_job->hwrt || + job->ctx != job->paired_job->ctx))) + return ERR_PTR(-EINVAL); + + err = pvr_job_get_pm_ref(job); + if (WARN_ON(err)) + return ERR_PTR(err); + + if (job->paired_job) { + err = pvr_job_get_pm_ref(job->paired_job); + if (WARN_ON(err)) + return ERR_PTR(err); + } + + /* Submit our job to the CCCB */ + pvr_queue_submit_job_to_cccb(job); + + if (job->paired_job) { + struct pvr_job *geom_job = job; + struct pvr_job *frag_job = job->paired_job; + struct pvr_queue *geom_queue = job->ctx->queues.geometry; + struct pvr_queue *frag_queue = job->ctx->queues.fragment; + + /* Submit the fragment job along the geometry job and send a combined kick. */ + pvr_queue_submit_job_to_cccb(frag_job); + pvr_cccb_send_kccb_combined_kick(pvr_dev, + &geom_queue->cccb, &frag_queue->cccb, + pvr_context_get_fw_addr(geom_job->ctx) + + geom_queue->ctx_offset, + pvr_context_get_fw_addr(frag_job->ctx) + + frag_queue->ctx_offset, + job->hwrt, + frag_job->fw_ccb_cmd_type == + ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR); + } else { + struct pvr_queue *queue = container_of(job->base.sched, + struct pvr_queue, scheduler); + + pvr_cccb_send_kccb_kick(pvr_dev, &queue->cccb, + pvr_context_get_fw_addr(job->ctx) + queue->ctx_offset, + job->hwrt); + } + + return dma_fence_get(job->done_fence); +} + +static void pvr_queue_stop(struct pvr_queue *queue, struct pvr_job *bad_job) +{ + drm_sched_stop(&queue->scheduler, bad_job ? &bad_job->base : NULL); +} + +static void pvr_queue_start(struct pvr_queue *queue) +{ + struct pvr_job *job; + + /* Make sure we CPU-signal the UFO object, so other queues don't get + * blocked waiting on it. + */ + *queue->timeline_ufo.value = atomic_read(&queue->job_fence_ctx.seqno); + + list_for_each_entry(job, &queue->scheduler.pending_list, base.list) { + if (dma_fence_is_signaled(job->done_fence)) { + /* Jobs might have completed after drm_sched_stop() was called. + * In that case, re-assign the parent field to the done_fence. + */ + WARN_ON(job->base.s_fence->parent); + job->base.s_fence->parent = dma_fence_get(job->done_fence); + } else { + /* If we had unfinished jobs, flag the entity as guilty so no + * new job can be submitted. + */ + atomic_set(&queue->ctx->faulty, 1); + } + } + + drm_sched_start(&queue->scheduler, true); +} + +/** + * pvr_queue_timedout_job() - Handle a job timeout event. + * @s_job: The job this timeout occurred on. + * + * FIXME: We don't do anything here to unblock the situation, we just stop+start + * the scheduler, and re-assign parent fences in the middle. + * + * Return: + * * DRM_GPU_SCHED_STAT_NOMINAL. + */ +static enum drm_gpu_sched_stat +pvr_queue_timedout_job(struct drm_sched_job *s_job) +{ + struct drm_gpu_scheduler *sched = s_job->sched; + struct pvr_queue *queue = container_of(sched, struct pvr_queue, scheduler); + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + struct pvr_job *job; + u32 job_count = 0; + + dev_err(sched->dev, "Job timeout\n"); + + /* Before we stop the scheduler, make sure the queue is out of any list, so + * any call to pvr_queue_update_active_state_locked() that might happen + * until the scheduler is really stopped doesn't end up re-inserting the + * queue in the active list. This would cause + * pvr_queue_signal_done_fences() and drm_sched_stop() to race with each + * other when accessing the pending_list, since drm_sched_stop() doesn't + * grab the job_list_lock when modifying the list (it's assuming the + * only other accessor is the scheduler, and it's safe to not grab the + * lock since it's stopped). + */ + mutex_lock(&pvr_dev->queues.lock); + list_del_init(&queue->node); + mutex_unlock(&pvr_dev->queues.lock); + + drm_sched_stop(sched, s_job); + + /* Re-assign job parent fences. */ + list_for_each_entry(job, &sched->pending_list, base.list) { + job->base.s_fence->parent = dma_fence_get(job->done_fence); + job_count++; + } + WARN_ON(atomic_read(&queue->in_flight_job_count) != job_count); + + /* Re-insert the queue in the proper list, and kick a queue processing + * operation if there were jobs pending. + */ + mutex_lock(&pvr_dev->queues.lock); + if (!job_count) { + list_move_tail(&queue->node, &pvr_dev->queues.idle); + } else { + atomic_set(&queue->in_flight_job_count, job_count); + list_move_tail(&queue->node, &pvr_dev->queues.active); + pvr_queue_process(queue); + } + mutex_unlock(&pvr_dev->queues.lock); + + drm_sched_start(sched, true); + + return DRM_GPU_SCHED_STAT_NOMINAL; +} + +/** + * pvr_queue_free_job() - Release the reference the scheduler had on a job object. + * @sched_job: Job object to free. + */ +static void pvr_queue_free_job(struct drm_sched_job *sched_job) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + + drm_sched_job_cleanup(sched_job); + job->paired_job = NULL; + pvr_job_put(job); +} + +static const struct drm_sched_backend_ops pvr_queue_sched_ops = { + .prepare_job = pvr_queue_prepare_job, + .run_job = pvr_queue_run_job, + .timedout_job = pvr_queue_timedout_job, + .free_job = pvr_queue_free_job, +}; + +/** + * pvr_queue_fence_is_ufo_backed() - Check if a dma_fence is backed by a UFO object + * @f: Fence to test. + * + * A UFO-backed fence is a fence that can be signaled or waited upon FW-side. + * pvr_job::done_fence objects are backed by the timeline UFO attached to the queue + * they are pushed to, but those fences are not directly exposed to the outside + * world, so we also need to check if the fence we're being passed is a + * drm_sched_fence that was coming from our driver. + */ +bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f) +{ + struct drm_sched_fence *sched_fence = f ? to_drm_sched_fence(f) : NULL; + + if (sched_fence && + sched_fence->sched->ops == &pvr_queue_sched_ops) + return true; + + if (f && f->ops == &pvr_queue_job_fence_ops) + return true; + + return false; +} + +/** + * pvr_queue_signal_done_fences() - Signal done fences. + * @queue: Queue to check. + * + * Signal done fences of jobs whose seqno is less than the current value of + * the UFO object attached to the queue. + */ +static void +pvr_queue_signal_done_fences(struct pvr_queue *queue) +{ + struct pvr_job *job, *tmp_job; + u32 cur_seqno; + + spin_lock(&queue->scheduler.job_list_lock); + cur_seqno = *queue->timeline_ufo.value; + list_for_each_entry_safe(job, tmp_job, &queue->scheduler.pending_list, base.list) { + if ((int)(cur_seqno - lower_32_bits(job->done_fence->seqno)) < 0) + break; + + if (!dma_fence_is_signaled(job->done_fence)) { + dma_fence_signal(job->done_fence); + pvr_job_release_pm_ref(job); + atomic_dec(&queue->in_flight_job_count); + } + } + spin_unlock(&queue->scheduler.job_list_lock); +} + +/** + * pvr_queue_check_job_waiting_for_cccb_space() - Check if the job waiting for CCCB space + * can be unblocked + * pushed to the CCCB + * @queue: Queue to check + * + * If we have a job waiting for CCCB, and this job now fits in the CCCB, we signal + * its CCCB fence, which should kick drm_sched. + */ +static void +pvr_queue_check_job_waiting_for_cccb_space(struct pvr_queue *queue) +{ + struct pvr_queue_fence *cccb_fence; + u32 native_deps_remaining; + struct pvr_job *job; + + mutex_lock(&queue->cccb_fence_ctx.job_lock); + job = queue->cccb_fence_ctx.job; + if (!job) + goto out_unlock; + + /* If we have a job attached to the CCCB fence context, its CCCB fence + * shouldn't be NULL. + */ + if (WARN_ON(!job->cccb_fence)) { + job = NULL; + goto out_unlock; + } + + /* If we get there, CCCB fence has to be initialized. */ + cccb_fence = container_of(job->cccb_fence, struct pvr_queue_fence, base); + if (WARN_ON(!cccb_fence->queue)) { + job = NULL; + goto out_unlock; + } + + /* Evict signaled dependencies before checking for CCCB space. + * If the job fits, signal the CCCB fence, this should unblock + * the drm_sched_entity. + */ + native_deps_remaining = job_count_remaining_native_deps(job); + if (!pvr_cccb_cmdseq_fits(&queue->cccb, job_cmds_size(job, native_deps_remaining))) { + job = NULL; + goto out_unlock; + } + + dma_fence_signal(job->cccb_fence); + pvr_queue_fence_put(job->cccb_fence); + job->cccb_fence = NULL; + queue->cccb_fence_ctx.job = NULL; + +out_unlock: + mutex_unlock(&queue->cccb_fence_ctx.job_lock); + + pvr_job_put(job); +} + +/** + * pvr_queue_process() - Process events that happened on a queue. + * @queue: Queue to check + * + * Signal job fences and check if jobs waiting for CCCB space can be unblocked. + */ +void pvr_queue_process(struct pvr_queue *queue) +{ + lockdep_assert_held(&queue->ctx->pvr_dev->queues.lock); + + pvr_queue_check_job_waiting_for_cccb_space(queue); + pvr_queue_signal_done_fences(queue); + pvr_queue_update_active_state_locked(queue); +} + +static u32 get_dm_type(struct pvr_queue *queue) +{ + switch (queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return PVR_FWIF_DM_GEOM; + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + case DRM_PVR_JOB_TYPE_FRAGMENT: + return PVR_FWIF_DM_FRAG; + case DRM_PVR_JOB_TYPE_COMPUTE: + return PVR_FWIF_DM_CDM; + } + + return ~0; +} + +/** + * init_fw_context() - Initializes the queue part of a FW context. + * @queue: Queue object to initialize the FW context for. + * @fw_ctx_map: The FW context CPU mapping. + * + * FW contexts are containing various states, one of them being a per-queue state + * that needs to be initialized for each queue being exposed by a context. This + * function takes care of that. + */ +static void init_fw_context(struct pvr_queue *queue, void *fw_ctx_map) +{ + struct pvr_context *ctx = queue->ctx; + struct pvr_fw_object *fw_mem_ctx_obj = pvr_vm_get_fw_mem_context(ctx->vm_ctx); + struct rogue_fwif_fwcommoncontext *cctx_fw; + struct pvr_cccb *cccb = &queue->cccb; + + cctx_fw = fw_ctx_map + queue->ctx_offset; + cctx_fw->ccbctl_fw_addr = cccb->ctrl_fw_addr; + cctx_fw->ccb_fw_addr = cccb->cccb_fw_addr; + + cctx_fw->dm = get_dm_type(queue); + cctx_fw->priority = ctx->priority; + cctx_fw->priority_seq_num = 0; + cctx_fw->max_deadline_ms = MAX_DEADLINE_MS; + cctx_fw->pid = task_tgid_nr(current); + cctx_fw->server_common_context_id = ctx->ctx_id; + + pvr_fw_object_get_fw_addr(fw_mem_ctx_obj, &cctx_fw->fw_mem_context_fw_addr); + + pvr_fw_object_get_fw_addr(queue->reg_state_obj, &cctx_fw->context_state_addr); +} + +/** + * pvr_queue_cleanup_fw_context() - Wait for the FW context to be idle and clean it up. + * @queue: Queue on FW context to clean up. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_fw_structure_cleanup() otherwise. + */ +static int pvr_queue_cleanup_fw_context(struct pvr_queue *queue) +{ + if (!queue->ctx->fw_obj) + return 0; + + return pvr_fw_structure_cleanup(queue->ctx->pvr_dev, + ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT, + queue->ctx->fw_obj, queue->ctx_offset); +} + +/** + * pvr_queue_job_init() - Initialize queue related fields in a pvr_job object. + * @job: The job to initialize. + * + * Bind the job to a queue and allocate memory to guarantee pvr_queue_job_arm() + * and pvr_queue_job_push() can't fail. We also make sure the context type is + * valid and the job can fit in the CCCB. + * + * Return: + * * 0 on success, or + * * An error code if something failed. + */ +int pvr_queue_job_init(struct pvr_job *job) +{ + /* Fragment jobs need at least one native fence wait on the geometry job fence. */ + u32 min_native_dep_count = job->type == DRM_PVR_JOB_TYPE_FRAGMENT ? 1 : 0; + struct pvr_queue *queue; + int err; + + if (atomic_read(&job->ctx->faulty)) + return -EIO; + + queue = pvr_context_get_queue_for_job(job->ctx, job->type); + if (!queue) + return -EINVAL; + + if (!pvr_cccb_cmdseq_can_fit(&queue->cccb, job_cmds_size(job, min_native_dep_count))) + return -E2BIG; + + err = drm_sched_job_init(&job->base, &queue->entity, 1, THIS_MODULE); + if (err) + return err; + + job->cccb_fence = pvr_queue_fence_alloc(); + job->kccb_fence = pvr_kccb_fence_alloc(); + job->done_fence = pvr_queue_fence_alloc(); + if (!job->cccb_fence || !job->kccb_fence || !job->done_fence) + return -ENOMEM; + + return 0; +} + +/** + * pvr_queue_job_arm() - Arm a job object. + * @job: The job to arm. + * + * Initializes fences and return the drm_sched finished fence so it can + * be exposed to the outside world. Once this function is called, you should + * make sure the job is pushed using pvr_queue_job_push(), or guarantee that + * no one grabbed a reference to the returned fence. The latter can happen if + * we do multi-job submission, and something failed when creating/initializing + * a job. In that case, we know the fence didn't leave the driver, and we + * can thus guarantee nobody will wait on an dead fence object. + * + * Return: + * * A dma_fence object. + */ +struct dma_fence *pvr_queue_job_arm(struct pvr_job *job) +{ + drm_sched_job_arm(&job->base); + + return &job->base.s_fence->finished; +} + +/** + * pvr_queue_job_cleanup() - Cleanup fence/scheduler related fields in the job object. + * @job: The job to cleanup. + * + * Should be called in the job release path. + */ +void pvr_queue_job_cleanup(struct pvr_job *job) +{ + pvr_queue_fence_put(job->done_fence); + pvr_queue_fence_put(job->cccb_fence); + pvr_kccb_fence_put(job->kccb_fence); + + if (job->base.s_fence) + drm_sched_job_cleanup(&job->base); +} + +/** + * pvr_queue_job_push() - Push a job to its queue. + * @job: The job to push. + * + * Must be called after pvr_queue_job_init() and after all dependencies + * have been added to the job. This will effectively queue the job to + * the drm_sched_entity attached to the queue. We grab a reference on + * the job object, so the caller is free to drop its reference when it's + * done accessing the job object. + */ +void pvr_queue_job_push(struct pvr_job *job) +{ + struct pvr_queue *queue = container_of(job->base.sched, struct pvr_queue, scheduler); + + /* Keep track of the last queued job scheduled fence for combined submit. */ + dma_fence_put(queue->last_queued_job_scheduled_fence); + queue->last_queued_job_scheduled_fence = dma_fence_get(&job->base.s_fence->scheduled); + + pvr_job_get(job); + drm_sched_entity_push_job(&job->base); +} + +static void reg_state_init(void *cpu_ptr, void *priv) +{ + struct pvr_queue *queue = priv; + + if (queue->type == DRM_PVR_JOB_TYPE_GEOMETRY) { + struct rogue_fwif_geom_ctx_state *geom_ctx_state_fw = cpu_ptr; + + geom_ctx_state_fw->geom_core[0].geom_reg_vdm_call_stack_pointer_init = + queue->callstack_addr; + } +} + +/** + * pvr_queue_create() - Create a queue object. + * @ctx: The context this queue will be attached to. + * @type: The type of jobs being pushed to this queue. + * @args: The arguments passed to the context creation function. + * @fw_ctx_map: CPU mapping of the FW context object. + * + * Create a queue object that will be used to queue and track jobs. + * + * Return: + * * A valid pointer to a pvr_queue object, or + * * An error pointer if the creation/initialization failed. + */ +struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, + enum drm_pvr_job_type type, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + static const struct { + u32 cccb_size; + const char *name; + } props[] = { + [DRM_PVR_JOB_TYPE_GEOMETRY] = { + .cccb_size = CTX_GEOM_CCCB_SIZE_LOG2, + .name = "geometry", + }, + [DRM_PVR_JOB_TYPE_FRAGMENT] = { + .cccb_size = CTX_FRAG_CCCB_SIZE_LOG2, + .name = "fragment" + }, + [DRM_PVR_JOB_TYPE_COMPUTE] = { + .cccb_size = CTX_COMPUTE_CCCB_SIZE_LOG2, + .name = "compute" + }, + [DRM_PVR_JOB_TYPE_TRANSFER_FRAG] = { + .cccb_size = CTX_TRANSFER_CCCB_SIZE_LOG2, + .name = "transfer_frag" + }, + }; + struct pvr_device *pvr_dev = ctx->pvr_dev; + struct drm_gpu_scheduler *sched; + struct pvr_queue *queue; + int ctx_state_size, err; + void *cpu_map; + + if (WARN_ON(type >= sizeof(props))) + return ERR_PTR(-EINVAL); + + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + if (type != DRM_PVR_JOB_TYPE_GEOMETRY && + type != DRM_PVR_JOB_TYPE_FRAGMENT) + return ERR_PTR(-EINVAL); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + if (type != DRM_PVR_JOB_TYPE_COMPUTE) + return ERR_PTR(-EINVAL); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + if (type != DRM_PVR_JOB_TYPE_TRANSFER_FRAG) + return ERR_PTR(-EINVAL); + break; + default: + return ERR_PTR(-EINVAL); + } + + ctx_state_size = get_ctx_state_size(pvr_dev, type); + if (ctx_state_size < 0) + return ERR_PTR(ctx_state_size); + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + return ERR_PTR(-ENOMEM); + + queue->type = type; + queue->ctx_offset = get_ctx_offset(type); + queue->ctx = ctx; + queue->callstack_addr = args->callstack_addr; + sched = &queue->scheduler; + INIT_LIST_HEAD(&queue->node); + mutex_init(&queue->cccb_fence_ctx.job_lock); + pvr_queue_fence_ctx_init(&queue->cccb_fence_ctx.base); + pvr_queue_fence_ctx_init(&queue->job_fence_ctx); + + err = pvr_cccb_init(pvr_dev, &queue->cccb, props[type].cccb_size, props[type].name); + if (err) + goto err_free_queue; + + err = pvr_fw_object_create(pvr_dev, ctx_state_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + reg_state_init, queue, &queue->reg_state_obj); + if (err) + goto err_cccb_fini; + + init_fw_context(queue, fw_ctx_map); + + if (type != DRM_PVR_JOB_TYPE_GEOMETRY && type != DRM_PVR_JOB_TYPE_FRAGMENT && + args->callstack_addr) { + err = -EINVAL; + goto err_release_reg_state; + } + + cpu_map = pvr_fw_object_create_and_map(pvr_dev, sizeof(*queue->timeline_ufo.value), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &queue->timeline_ufo.fw_obj); + if (IS_ERR(cpu_map)) { + err = PTR_ERR(cpu_map); + goto err_release_reg_state; + } + + queue->timeline_ufo.value = cpu_map; + + err = drm_sched_init(&queue->scheduler, + &pvr_queue_sched_ops, + pvr_dev->sched_wq, 1, 64 * 1024, 1, + msecs_to_jiffies(500), + pvr_dev->sched_wq, NULL, "pvr-queue", + pvr_dev->base.dev); + if (err) + goto err_release_ufo; + + err = drm_sched_entity_init(&queue->entity, + DRM_SCHED_PRIORITY_MIN, + &sched, 1, &ctx->faulty); + if (err) + goto err_sched_fini; + + mutex_lock(&pvr_dev->queues.lock); + list_add_tail(&queue->node, &pvr_dev->queues.idle); + mutex_unlock(&pvr_dev->queues.lock); + + return queue; + +err_sched_fini: + drm_sched_fini(&queue->scheduler); + +err_release_ufo: + pvr_fw_object_unmap_and_destroy(queue->timeline_ufo.fw_obj); + +err_release_reg_state: + pvr_fw_object_destroy(queue->reg_state_obj); + +err_cccb_fini: + pvr_cccb_fini(&queue->cccb); + +err_free_queue: + mutex_destroy(&queue->cccb_fence_ctx.job_lock); + kfree(queue); + + return ERR_PTR(err); +} + +void pvr_queue_device_pre_reset(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue; + + mutex_lock(&pvr_dev->queues.lock); + list_for_each_entry(queue, &pvr_dev->queues.idle, node) + pvr_queue_stop(queue, NULL); + list_for_each_entry(queue, &pvr_dev->queues.active, node) + pvr_queue_stop(queue, NULL); + mutex_unlock(&pvr_dev->queues.lock); +} + +void pvr_queue_device_post_reset(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue; + + mutex_lock(&pvr_dev->queues.lock); + list_for_each_entry(queue, &pvr_dev->queues.active, node) + pvr_queue_start(queue); + list_for_each_entry(queue, &pvr_dev->queues.idle, node) + pvr_queue_start(queue); + mutex_unlock(&pvr_dev->queues.lock); +} + +/** + * pvr_queue_kill() - Kill a queue. + * @queue: The queue to kill. + * + * Kill the queue so no new jobs can be pushed. Should be called when the + * context handle is destroyed. The queue object might last longer if jobs + * are still in flight and holding a reference to the context this queue + * belongs to. + */ +void pvr_queue_kill(struct pvr_queue *queue) +{ + drm_sched_entity_destroy(&queue->entity); + dma_fence_put(queue->last_queued_job_scheduled_fence); + queue->last_queued_job_scheduled_fence = NULL; +} + +/** + * pvr_queue_destroy() - Destroy a queue. + * @queue: The queue to destroy. + * + * Cleanup the queue and free the resources attached to it. Should be + * called from the context release function. + */ +void pvr_queue_destroy(struct pvr_queue *queue) +{ + if (!queue) + return; + + mutex_lock(&queue->ctx->pvr_dev->queues.lock); + list_del_init(&queue->node); + mutex_unlock(&queue->ctx->pvr_dev->queues.lock); + + drm_sched_fini(&queue->scheduler); + drm_sched_entity_fini(&queue->entity); + + if (WARN_ON(queue->last_queued_job_scheduled_fence)) + dma_fence_put(queue->last_queued_job_scheduled_fence); + + pvr_queue_cleanup_fw_context(queue); + + pvr_fw_object_unmap_and_destroy(queue->timeline_ufo.fw_obj); + pvr_fw_object_destroy(queue->reg_state_obj); + pvr_cccb_fini(&queue->cccb); + mutex_destroy(&queue->cccb_fence_ctx.job_lock); + kfree(queue); +} + +/** + * pvr_queue_device_init() - Device-level initialization of queue related fields. + * @pvr_dev: The device to initialize. + * + * Initializes all fields related to queue management in pvr_device. + * + * Return: + * * 0 on success, or + * * An error code on failure. + */ +int pvr_queue_device_init(struct pvr_device *pvr_dev) +{ + int err; + + INIT_LIST_HEAD(&pvr_dev->queues.active); + INIT_LIST_HEAD(&pvr_dev->queues.idle); + err = drmm_mutex_init(from_pvr_device(pvr_dev), &pvr_dev->queues.lock); + if (err) + return err; + + pvr_dev->sched_wq = alloc_workqueue("powervr-sched", WQ_UNBOUND, 0); + if (!pvr_dev->sched_wq) + return -ENOMEM; + + return 0; +} + +/** + * pvr_queue_device_fini() - Device-level cleanup of queue related fields. + * @pvr_dev: The device to cleanup. + * + * Cleanup/free all queue-related resources attached to a pvr_device object. + */ +void pvr_queue_device_fini(struct pvr_device *pvr_dev) +{ + destroy_workqueue(pvr_dev->sched_wq); +} diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h new file mode 100644 index 000000000000..b5ce2c742150 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_queue.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_QUEUE_H +#define PVR_QUEUE_H + +#include + +#include "pvr_cccb.h" +#include "pvr_device.h" + +struct pvr_context; +struct pvr_queue; + +/** + * struct pvr_queue_fence_ctx - Queue fence context + * + * Used to implement dma_fence_ops for pvr_job::{done,cccb}_fence. + */ +struct pvr_queue_fence_ctx { + /** @id: Fence context ID allocated with dma_fence_context_alloc(). */ + u64 id; + + /** @seqno: Sequence number incremented each time a fence is created. */ + atomic_t seqno; + + /** @lock: Lock used to synchronize access to fences allocated by this context. */ + spinlock_t lock; +}; + +/** + * struct pvr_queue_cccb_fence_ctx - CCCB fence context + * + * Context used to manage fences controlling access to the CCCB. No fences are + * issued if there's enough space in the CCCB to push job commands. + */ +struct pvr_queue_cccb_fence_ctx { + /** @base: Base queue fence context. */ + struct pvr_queue_fence_ctx base; + + /** + * @job: Job waiting for CCCB space. + * + * Thanks to the serializationg done at the drm_sched_entity level, + * there's no more than one job waiting for CCCB at a given time. + * + * This field is NULL if no jobs are currently waiting for CCCB space. + * + * Must be accessed with @job_lock held. + */ + struct pvr_job *job; + + /** @lock: Lock protecting access to the job object. */ + struct mutex job_lock; +}; + +/** + * struct pvr_queue_fence - Queue fence object + */ +struct pvr_queue_fence { + /** @base: Base dma_fence. */ + struct dma_fence base; + + /** @queue: Queue that created this fence. */ + struct pvr_queue *queue; +}; + +/** + * struct pvr_queue - Job queue + * + * Used to queue and track execution of pvr_job objects. + */ +struct pvr_queue { + /** @scheduler: Single entity scheduler use to push jobs to this queue. */ + struct drm_gpu_scheduler scheduler; + + /** @entity: Scheduling entity backing this queue. */ + struct drm_sched_entity entity; + + /** @type: Type of jobs queued to this queue. */ + enum drm_pvr_job_type type; + + /** @ctx: Context object this queue is bound to. */ + struct pvr_context *ctx; + + /** @node: Used to add the queue to the active/idle queue list. */ + struct list_head node; + + /** + * @in_flight_job_count: Number of jobs submitted to the CCCB that + * have not been processed yet. + */ + atomic_t in_flight_job_count; + + /** + * @cccb_fence_ctx: CCCB fence context. + * + * Used to control access to the CCCB is full, such that we don't + * end up trying to push commands to the CCCB if there's not enough + * space to receive all commands needed for a job to complete. + */ + struct pvr_queue_cccb_fence_ctx cccb_fence_ctx; + + /** @job_fence_ctx: Job fence context object. */ + struct pvr_queue_fence_ctx job_fence_ctx; + + /** @timeline_ufo: Timeline UFO for the context queue. */ + struct { + /** @fw_obj: FW object representing the UFO value. */ + struct pvr_fw_object *fw_obj; + + /** @value: CPU mapping of the UFO value. */ + u32 *value; + } timeline_ufo; + + /** + * last_queued_job_scheduled_fence: The scheduled fence of the last + * job queued to this queue. + * + * We use it to insert frag -> geom dependencies when issuing combined + * geom+frag jobs, to guarantee that the fragment job that's part of + * the combined operation comes after all fragment jobs that were queued + * before it. + */ + struct dma_fence *last_queued_job_scheduled_fence; + + /** @cccb: Client Circular Command Buffer. */ + struct pvr_cccb cccb; + + /** @reg_state_obj: FW object representing the register state of this queue. */ + struct pvr_fw_object *reg_state_obj; + + /** @ctx_offset: Offset of the queue context in the FW context object. */ + u32 ctx_offset; + + /** @callstack_addr: Initial call stack address for register state object. */ + u64 callstack_addr; +}; + +bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f); + +int pvr_queue_job_init(struct pvr_job *job); + +void pvr_queue_job_cleanup(struct pvr_job *job); + +void pvr_queue_job_push(struct pvr_job *job); + +struct dma_fence *pvr_queue_job_arm(struct pvr_job *job); + +struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, + enum drm_pvr_job_type type, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map); + +void pvr_queue_kill(struct pvr_queue *queue); + +void pvr_queue_destroy(struct pvr_queue *queue); + +void pvr_queue_process(struct pvr_queue *queue); + +void pvr_queue_device_pre_reset(struct pvr_device *pvr_dev); + +void pvr_queue_device_post_reset(struct pvr_device *pvr_dev); + +int pvr_queue_device_init(struct pvr_device *pvr_dev); + +void pvr_queue_device_fini(struct pvr_device *pvr_dev); + +#endif /* PVR_QUEUE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_stream_defs.c b/drivers/gpu/drm/imagination/pvr_stream_defs.c index 59265a7accce..f8bd1a8c01db 100644 --- a/drivers/gpu/drm/imagination/pvr_stream_defs.c +++ b/drivers/gpu/drm/imagination/pvr_stream_defs.c @@ -43,6 +43,232 @@ * existing parameters, to preserve order. As parameters are naturally aligned, care must be taken * with respect to implicit padding in the stream; padding should be minimised as much as possible. */ +static const struct pvr_stream_def rogue_fwif_cmd_geom_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.vdm_ctrl_stream_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_draw_indirect0, 64, + PVR_FEATURE_VDM_DRAWINDIRECT), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_draw_indirect1, 32, + PVR_FEATURE_VDM_DRAWINDIRECT), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.ppp_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.te_psg, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.vdm_context_resume_task0_size, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_context_resume_task3_size, 32, + PVR_FEATURE_VDM_OBJECT_LEVEL_LLS), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.view_idx, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.pds_coeff_free_prog, 32, + PVR_FEATURE_TESSELLATION), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_geom_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_geom_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_geom_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_geom_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_GEOM0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_geom_ext_headers[] = { + { + .ext_streams = cmd_geom_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_geom_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_GEOM0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_geom_stream = { + .type = PVR_STREAM_TYPE_GEOM, + + .main_stream = rogue_fwif_cmd_geom_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_geom_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_geom_ext_headers), + .ext_headers = cmd_geom_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_geom), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_scissor_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_dbias_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_oclqry_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_zlsctl, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_zload_store_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_stencil_load_store_base, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.fb_cdc_zls, 64, + PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pbe_word), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pds_bgnd), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pds_pr_bgnd), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.usc_clear_register), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.usc_pixel_output_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_bgobjdepth, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_bgobjvals, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_aa, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_xtp_pipe_enable, 32, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_ctl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.event_pixel_pds_info, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.pixel_phantom, 32, + PVR_FEATURE_CLUSTER_GROUPING), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.view_idx, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.event_pixel_pds_data, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_oclqry_stride, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_zls_pixels, 32, + PVR_FEATURE_ZLS_SUBTILE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.rgx_cr_blackpearl_fix, 32, + PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, zls_stride, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, sls_stride, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, execute_count, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream_brn47217[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_oclqry_stride, 32), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_frag_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_frag_stream_brn47217, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream_brn47217), + .header_mask = PVR_STREAM_EXTHDR_FRAG0_BRN47217, + .quirk = 47217, + }, + { + .stream = rogue_fwif_cmd_frag_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_FRAG0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_frag_ext_headers[] = { + { + .ext_streams = cmd_frag_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_frag_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_FRAG0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_frag_stream = { + .type = PVR_STREAM_TYPE_FRAG, + + .main_stream = rogue_fwif_cmd_frag_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_frag_ext_headers), + .ext_headers = cmd_frag_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_frag), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_compute_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb_queue, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb_base, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_NOT_FEATURE(rogue_fwif_cmd_compute, regs.cdm_ctrl_stream_base, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.cdm_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.cdm_resume_pds1, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_item, 32, + PVR_FEATURE_COMPUTE_MORTON_CAPABLE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.compute_cluster, 32, + PVR_FEATURE_CLUSTER_GROUPING), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.tpu_tag_cdm_ctrl, 32, + PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, stream_start_offset, 32, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, execute_count, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_compute_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_compute_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_compute_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_compute_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_COMPUTE0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_compute_ext_headers[] = { + { + .ext_streams = cmd_compute_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_compute_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_COMPUTE0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_compute_stream = { + .type = PVR_STREAM_TYPE_COMPUTE, + + .main_stream = rogue_fwif_cmd_compute_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_compute_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_compute_ext_headers), + .ext_headers = cmd_compute_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_compute), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_transfer_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd0_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd1_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd3_sizeinfo, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_mtile_base, 64), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_transfer, regs.pbe_wordx_mrty), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_bgobjvals, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_pixel_output_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register0, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register1, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register2, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register3, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_mtile_size, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_render_origin, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_ctl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_aa, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_info, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_code, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_data, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_render, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_rgn, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_transfer, regs.isp_xtp_pipe_enable, 32, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_transfer, regs.frag_screen, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +const struct pvr_stream_cmd_defs pvr_cmd_transfer_stream = { + .type = PVR_STREAM_TYPE_TRANSFER, + + .main_stream = rogue_fwif_cmd_transfer_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_transfer_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_cmd_transfer), +}; + static const struct pvr_stream_def rogue_fwif_static_render_context_state_stream[] = { PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, geom_reg_vdm_context_state_base_addr, 64), diff --git a/drivers/gpu/drm/imagination/pvr_sync.c b/drivers/gpu/drm/imagination/pvr_sync.c new file mode 100644 index 000000000000..129f646d14ba --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_sync.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include + +#include +#include +#include +#include + +#include "pvr_device.h" +#include "pvr_queue.h" +#include "pvr_sync.h" + +static int +pvr_check_sync_op(const struct drm_pvr_sync_op *sync_op) +{ + u8 handle_type; + + if (sync_op->flags & ~DRM_PVR_SYNC_OP_FLAGS_MASK) + return -EINVAL; + + handle_type = sync_op->flags & DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_MASK; + if (handle_type != DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ && + handle_type != DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_TIMELINE_SYNCOBJ) + return -EINVAL; + + if (handle_type == DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ && + sync_op->value != 0) + return -EINVAL; + + return 0; +} + +static void +pvr_sync_signal_free(struct pvr_sync_signal *sig_sync) +{ + if (!sig_sync) + return; + + drm_syncobj_put(sig_sync->syncobj); + dma_fence_chain_free(sig_sync->chain); + dma_fence_put(sig_sync->fence); + kfree(sig_sync); +} + +void +pvr_sync_signal_array_cleanup(struct xarray *array) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) + pvr_sync_signal_free(sig_sync); + + xa_destroy(array); +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_add(struct xarray *array, struct drm_file *file, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + struct dma_fence *cur_fence; + int err; + u32 id; + + sig_sync = kzalloc(sizeof(*sig_sync), GFP_KERNEL); + if (!sig_sync) + return ERR_PTR(-ENOMEM); + + sig_sync->handle = handle; + sig_sync->point = point; + + if (point > 0) { + sig_sync->chain = dma_fence_chain_alloc(); + if (!sig_sync->chain) { + err = -ENOMEM; + goto err_free_sig_sync; + } + } + + sig_sync->syncobj = drm_syncobj_find(file, handle); + if (!sig_sync->syncobj) { + err = -EINVAL; + goto err_free_sig_sync; + } + + /* Retrieve the current fence attached to that point. It's + * perfectly fine to get a NULL fence here, it just means there's + * no fence attached to that point yet. + */ + if (!drm_syncobj_find_fence(file, handle, point, 0, &cur_fence)) + sig_sync->fence = cur_fence; + + err = xa_alloc(array, &id, sig_sync, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_free_sig_sync; + + return sig_sync; + +err_free_sig_sync: + pvr_sync_signal_free(sig_sync); + return ERR_PTR(err); +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_search(struct xarray *array, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) { + if (handle == sig_sync->handle && point == sig_sync->point) + return sig_sync; + } + + return NULL; +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_get(struct xarray *array, struct drm_file *file, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + + sig_sync = pvr_sync_signal_array_search(array, handle, point); + if (sig_sync) + return sig_sync; + + return pvr_sync_signal_array_add(array, file, handle, point); +} + +int +pvr_sync_signal_array_collect_ops(struct xarray *array, + struct drm_file *file, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops) +{ + for (u32 i = 0; i < sync_op_count; i++) { + struct pvr_sync_signal *sig_sync; + int ret; + + if (!(sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL)) + continue; + + ret = pvr_check_sync_op(&sync_ops[i]); + if (ret) + return ret; + + sig_sync = pvr_sync_signal_array_get(array, file, + sync_ops[i].handle, + sync_ops[i].value); + if (IS_ERR(sig_sync)) + return PTR_ERR(sig_sync); + } + + return 0; +} + +int +pvr_sync_signal_array_update_fences(struct xarray *array, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct dma_fence *done_fence) +{ + for (u32 i = 0; i < sync_op_count; i++) { + struct dma_fence *old_fence; + struct pvr_sync_signal *sig_sync; + + if (!(sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL)) + continue; + + sig_sync = pvr_sync_signal_array_search(array, sync_ops[i].handle, + sync_ops[i].value); + if (WARN_ON(!sig_sync)) + return -EINVAL; + + old_fence = sig_sync->fence; + sig_sync->fence = dma_fence_get(done_fence); + dma_fence_put(old_fence); + + if (WARN_ON(!sig_sync->fence)) + return -EINVAL; + } + + return 0; +} + +void +pvr_sync_signal_array_push_fences(struct xarray *array) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) { + if (sig_sync->chain) { + drm_syncobj_add_point(sig_sync->syncobj, sig_sync->chain, + sig_sync->fence, sig_sync->point); + sig_sync->chain = NULL; + } else { + drm_syncobj_replace_fence(sig_sync->syncobj, sig_sync->fence); + } + } +} + +static int +pvr_sync_add_dep_to_job(struct drm_sched_job *job, struct dma_fence *f) +{ + struct dma_fence_unwrap iter; + u32 native_fence_count = 0; + struct dma_fence *uf; + int err = 0; + + dma_fence_unwrap_for_each(uf, &iter, f) { + if (pvr_queue_fence_is_ufo_backed(uf)) + native_fence_count++; + } + + /* No need to unwrap the fence if it's fully non-native. */ + if (!native_fence_count) + return drm_sched_job_add_dependency(job, f); + + dma_fence_unwrap_for_each(uf, &iter, f) { + /* There's no dma_fence_unwrap_stop() helper cleaning up the refs + * owned by dma_fence_unwrap(), so let's just iterate over all + * entries without doing anything when something failed. + */ + if (err) + continue; + + if (pvr_queue_fence_is_ufo_backed(uf)) { + struct drm_sched_fence *s_fence = to_drm_sched_fence(uf); + + /* If this is a native dependency, we wait for the scheduled fence, + * and we will let pvr_queue_run_job() issue FW waits. + */ + err = drm_sched_job_add_dependency(job, + dma_fence_get(&s_fence->scheduled)); + } else { + err = drm_sched_job_add_dependency(job, dma_fence_get(uf)); + } + } + + dma_fence_put(f); + return err; +} + +int +pvr_sync_add_deps_to_job(struct pvr_file *pvr_file, struct drm_sched_job *job, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct xarray *signal_array) +{ + int err = 0; + + if (!sync_op_count) + return 0; + + for (u32 i = 0; i < sync_op_count; i++) { + struct pvr_sync_signal *sig_sync; + struct dma_fence *fence; + + if (sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL) + continue; + + err = pvr_check_sync_op(&sync_ops[i]); + if (err) + return err; + + sig_sync = pvr_sync_signal_array_search(signal_array, sync_ops[i].handle, + sync_ops[i].value); + if (sig_sync) { + if (WARN_ON(!sig_sync->fence)) + return -EINVAL; + + fence = dma_fence_get(sig_sync->fence); + } else { + err = drm_syncobj_find_fence(from_pvr_file(pvr_file), sync_ops[i].handle, + sync_ops[i].value, 0, &fence); + if (err) + return err; + } + + err = pvr_sync_add_dep_to_job(job, fence); + if (err) + return err; + } + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_sync.h b/drivers/gpu/drm/imagination/pvr_sync.h new file mode 100644 index 000000000000..db6ccfda104a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_sync.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_SYNC_H +#define PVR_SYNC_H + +#include + +/* Forward declaration from . */ +struct xarray; + +/* Forward declaration from . */ +struct drm_file; + +/* Forward declaration from . */ +struct drm_sched_job; + +/* Forward declaration from "pvr_device.h". */ +struct pvr_file; + +/** + * struct pvr_sync_signal - Object encoding a syncobj signal operation + * + * The job submission logic collects all signal operations in an array of + * pvr_sync_signal objects. This array also serves as a cache to get the + * latest dma_fence when multiple jobs are submitted at once, and one job + * signals a syncobj point that's later waited on by a subsequent job. + */ +struct pvr_sync_signal { + /** @handle: Handle of the syncobj to signal. */ + u32 handle; + + /** + * @point: Point to signal in the syncobj. + * + * Only relevant for timeline syncobjs. + */ + u64 point; + + /** @syncobj: Syncobj retrieved from the handle. */ + struct drm_syncobj *syncobj; + + /** + * @chain: Chain object used to link the new fence with the + * existing timeline syncobj. + * + * Should be zero when manipulating a regular syncobj. + */ + struct dma_fence_chain *chain; + + /** + * @fence: New fence object to attach to the syncobj. + * + * This pointer starts with the current fence bound to + * the pair. + */ + struct dma_fence *fence; +}; + +void +pvr_sync_signal_array_cleanup(struct xarray *array); + +int +pvr_sync_signal_array_collect_ops(struct xarray *array, + struct drm_file *file, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops); + +int +pvr_sync_signal_array_update_fences(struct xarray *array, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct dma_fence *done_fence); + +void +pvr_sync_signal_array_push_fences(struct xarray *array); + +int +pvr_sync_add_deps_to_job(struct pvr_file *pvr_file, struct drm_sched_job *job, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct xarray *signal_array); + +#endif /* PVR_SYNC_H */ From 6b17baabf6d306f85021b9a081dcd0a1a5c6f846 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:39 +0000 Subject: [PATCH 1190/7721] drm/imagination: Add firmware trace header Changes since v8: - Corrected license identifiers Changes since v5: - Split up header commit due to size Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/c0fc28b2df394584afe3cc1b320140b01e17b322.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- .../gpu/drm/imagination/pvr_rogue_fwif_sf.h | 1648 +++++++++++++++++ 1 file changed, 1648 insertions(+) create mode 100644 drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h new file mode 100644 index 000000000000..571954182f33 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h @@ -0,0 +1,1648 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SF_H +#define PVR_ROGUE_FWIF_SF_H + +/* + ****************************************************************************** + * *DO*NOT* rearrange or delete lines in rogue_fw_log_sfgroups or stid_fmts + * WILL BREAK fw tracing message compatibility with previous + * fw versions. Only add new ones, if so required. + ****************************************************************************** + */ + +/* Available log groups. */ +enum rogue_fw_log_sfgroups { + ROGUE_FW_GROUP_NULL, + ROGUE_FW_GROUP_MAIN, + ROGUE_FW_GROUP_CLEANUP, + ROGUE_FW_GROUP_CSW, + ROGUE_FW_GROUP_PM, + ROGUE_FW_GROUP_RTD, + ROGUE_FW_GROUP_SPM, + ROGUE_FW_GROUP_MTS, + ROGUE_FW_GROUP_BIF, + ROGUE_FW_GROUP_MISC, + ROGUE_FW_GROUP_POW, + ROGUE_FW_GROUP_HWR, + ROGUE_FW_GROUP_HWP, + ROGUE_FW_GROUP_RPM, + ROGUE_FW_GROUP_DMA, + ROGUE_FW_GROUP_DBG, +}; + +#define PVR_SF_STRING_MAX_SIZE 256U + +/* pair of string format id and string formats */ +struct rogue_fw_stid_fmt { + u32 id; + char name[PVR_SF_STRING_MAX_SIZE]; +}; + +/* + * The symbolic names found in the table above are assigned an u32 value of + * the following format: + * 31 30 28 27 20 19 16 15 12 11 0 bits + * - --- ---- ---- ---- ---- ---- ---- ---- + * 0-11: id number + * 12-15: group id number + * 16-19: number of parameters + * 20-27: unused + * 28-30: active: identify SF packet, otherwise regular int32 + * 31: reserved for signed/unsigned compatibility + * + * The following macro assigns those values to the enum generated SF ids list. + */ +#define ROGUE_FW_LOG_IDMARKER (0x70000000U) +#define ROGUE_FW_LOG_CREATESFID(a, b, e) ((u32)(a) | ((u32)(b) << 12) | ((u32)(e) << 16) | \ + ROGUE_FW_LOG_IDMARKER) + +#define ROGUE_FW_LOG_IDMASK (0xFFF00000) +#define ROGUE_FW_LOG_VALIDID(I) (((I) & ROGUE_FW_LOG_IDMASK) == ROGUE_FW_LOG_IDMARKER) + +/* Return the group id that the given (enum generated) id belongs to */ +#define ROGUE_FW_SF_GID(x) (((u32)(x) >> 12) & 0xfU) +/* Returns how many arguments the SF(string format) for the given (enum generated) id requires */ +#define ROGUE_FW_SF_PARAMNUM(x) (((u32)(x) >> 16) & 0xfU) + +/* pair of string format id and string formats */ +struct rogue_km_stid_fmt { + u32 id; + const char *name; +}; + +static const struct rogue_km_stid_fmt stid_fmts[] = { + { ROGUE_FW_LOG_CREATESFID(0, ROGUE_FW_GROUP_NULL, 0), + "You should not use this string" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MAIN, 6), + "Kick 3D: FWCtx 0x%08.8x @ %d, RTD 0x%08x. Partial render:%d, CSW resume:%d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MAIN, 2), + "3D finished, HWRTData0State=%x, HWRTData1State=%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MAIN, 4), + "Kick 3D TQ: FWCtx 0x%08.8x @ %d, CSW resume:%d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MAIN, 0), + "3D Transfer finished" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MAIN, 3), + "Kick Compute: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MAIN, 0), + "Compute finished" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MAIN, 7), + "Kick TA: FWCtx 0x%08.8x @ %d, RTD 0x%08x. First kick:%d, Last kick:%d, CSW resume:%d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MAIN, 0), + "TA finished" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MAIN, 0), + "Restart TA after partial render" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MAIN, 0), + "Resume TA without partial render" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MAIN, 2), + "Out of memory! Context 0x%08x, HWRTData 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MAIN, 3), + "Kick TLA: FWCtx 0x%08.8x @ %d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MAIN, 0), + "TLA finished" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MAIN, 3), + "cCCB Woff update = %d, DM = %d, FWCtx = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MAIN, 2), + "UFO Checks for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MAIN, 3), + "UFO Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MAIN, 0), + "UFO Checks succeeded" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MAIN, 3), + "UFO PR-Check: [0x%08.8x] is 0x%08.8x requires >= 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MAIN, 1), + "UFO SPM PR-Checks for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MAIN, 4), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires >= ????????, [0x%08.8x] is ???????? requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_MAIN, 2), + "UFO Updates for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_MAIN, 2), + "UFO Update: [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MAIN, 1), + "ASSERT Failed: line %d of:" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_MAIN, 2), + "HWR: Lockup detected on DM%d, FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_MAIN, 3), + "HWR: Reset fw state for DM%d, FWCtx: 0x%08.8x, MemCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_MAIN, 0), + "HWR: Reset HW" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_MAIN, 0), + "HWR: Lockup recovered." }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_MAIN, 1), + "HWR: False lockup detected for DM%u" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_MAIN, 3), + "Alignment check %d failed: host = 0x%x, fw = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_MAIN, 0), + "GP USC triggered" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_MAIN, 2), + "Overallocating %u temporary registers and %u shared registers for breakpoint handler" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_MAIN, 1), + "Setting breakpoint: Addr 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_MAIN, 0), + "Store breakpoint state" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_MAIN, 0), + "Unsetting BP Registers" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_MAIN, 1), + "Active RTs expected to be zero, actually %u" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_MAIN, 1), + "RTC present, %u active render targets" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_MAIN, 1), + "Estimated Power 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_MAIN, 1), + "RTA render target %u" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_MAIN, 2), + "Kick RTA render %u of %u" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_MAIN, 3), + "HWR sizes check %d failed: addresses = %d, sizes = %d" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_MAIN, 1), + "Pow: DUSTS_ENABLE = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_MAIN, 2), + "Pow: On(1)/Off(0): %d, Units: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_MAIN, 2), + "Pow: Changing number of dusts from %d to %d" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_MAIN, 0), + "Pow: Sidekick ready to be powered down" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_MAIN, 2), + "Pow: Request to change num of dusts to %d (bPowRascalDust=%d)" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_MAIN, 0), + "No ZS Buffer used for partial render (store)" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_MAIN, 0), + "No Depth/Stencil Buffer used for partial render (load)" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_MAIN, 2), + "HWR: Lock-up DM%d FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_MAIN, 7), + "MLIST%d checker: CatBase TE=0x%08x (%d Pages), VCE=0x%08x (%d Pages), ALIST=0x%08x, IsTA=%d" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_MAIN, 3), + "MLIST%d checker: MList[%d] = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_MAIN, 1), + "MLIST%d OK" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_MAIN, 1), + "MLIST%d is empty" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_MAIN, 8), + "MLIST%d checker: CatBase TE=0x%08x%08x, VCE=0x%08x%08x, ALIST=0x%08x%08x, IsTA=%d" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_MAIN, 0), + "3D OQ flush kick" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_MAIN, 1), + "HWPerf block ID (0x%x) unsupported by device" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_MAIN, 2), + "Setting breakpoint: Addr 0x%08.8x DM%u" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_MAIN, 3), + "Kick RTU: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_MAIN, 1), + "RDM finished on context %u" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_MAIN, 3), + "Kick SHG: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_MAIN, 0), + "SHG finished" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_MAIN, 1), + "FBA finished on context %u" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_MAIN, 0), + "UFO Checks failed" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d start" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d complete" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_MAIN, 2), + "FC%u cCCB Woff update = %u" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_MAIN, 4), + "Kick RTU: FWCtx 0x%08.8x @ %d, prio: %d, Frame Context: %d" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_MAIN, 0), + "GPU init" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_MAIN, 1), + "GPU Units init (# mask: 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_MAIN, 3), + "Register access cycles: read: %d cycles, write: %d cycles, iterations: %d" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_MAIN, 3), + "Register configuration added. Address: 0x%x Value: 0x%x%x" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_MAIN, 1), + "Register configuration applied to type %d. (0:pow on, 1:Rascal/dust init, 2-5: TA,3D,CDM,TLA, 6:All)" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_MAIN, 0), + "Perform TPC flush." }, + { ROGUE_FW_LOG_CREATESFID(74, ROGUE_FW_GROUP_MAIN, 0), + "GPU has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(75, ROGUE_FW_GROUP_MAIN, 0), + "HWR has been triggered - GPU has overrun its deadline (see HWR logs)" }, + { ROGUE_FW_LOG_CREATESFID(76, ROGUE_FW_GROUP_MAIN, 0), + "HWR has been triggered - GPU has failed a poll (see HWR logs)" }, + { ROGUE_FW_LOG_CREATESFID(77, ROGUE_FW_GROUP_MAIN, 1), + "Doppler out of memory event for FC %u" }, + { ROGUE_FW_LOG_CREATESFID(78, ROGUE_FW_GROUP_MAIN, 3), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires >= 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(79, ROGUE_FW_GROUP_MAIN, 3), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(80, ROGUE_FW_GROUP_MAIN, 1), + "TIMESTAMP -> [0x%08.8x]" }, + { ROGUE_FW_LOG_CREATESFID(81, ROGUE_FW_GROUP_MAIN, 2), + "UFO RMW Updates for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(82, ROGUE_FW_GROUP_MAIN, 2), + "UFO Update: [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(83, ROGUE_FW_GROUP_MAIN, 2), + "Kick Null cmd: FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(84, ROGUE_FW_GROUP_MAIN, 2), + "RPM Out of memory! Context 0x%08x, SH requestor %d" }, + { ROGUE_FW_LOG_CREATESFID(85, ROGUE_FW_GROUP_MAIN, 4), + "Discard RTU due to RPM abort: FWCtx 0x%08.8x @ %d, prio: %d, Frame Context: %d" }, + { ROGUE_FW_LOG_CREATESFID(86, ROGUE_FW_GROUP_MAIN, 4), + "Deferring DM%u from running context 0x%08x @ %d (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(87, ROGUE_FW_GROUP_MAIN, 4), + "Deferring DM%u from running context 0x%08x @ %d to let other deferred DMs run (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(88, ROGUE_FW_GROUP_MAIN, 4), + "No longer deferring DM%u from running context = 0x%08x @ %d (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(89, ROGUE_FW_GROUP_MAIN, 3), + "FWCCB for DM%u is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(90, ROGUE_FW_GROUP_MAIN, 3), + "FWCCB for OSid %u is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(91, ROGUE_FW_GROUP_MAIN, 1), + "Host Sync Partition marker: %d" }, + { ROGUE_FW_LOG_CREATESFID(92, ROGUE_FW_GROUP_MAIN, 1), + "Host Sync Partition repeat: %d" }, + { ROGUE_FW_LOG_CREATESFID(93, ROGUE_FW_GROUP_MAIN, 1), + "Core clock set to %d Hz" }, + { ROGUE_FW_LOG_CREATESFID(94, ROGUE_FW_GROUP_MAIN, 7), + "Compute Queue: FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(95, ROGUE_FW_GROUP_MAIN, 3), + "Signal check failed, Required Data: 0x%x, Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(96, ROGUE_FW_GROUP_MAIN, 5), + "Signal update, Snoop Filter: %u, MMU Ctx: %u, Signal Id: %u, Signals Base: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(97, ROGUE_FW_GROUP_MAIN, 4), + "Signalled the previously waiting FWCtx: 0x%08.8x, OSId: %u, Signal Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(98, ROGUE_FW_GROUP_MAIN, 0), + "Compute stalled" }, + { ROGUE_FW_LOG_CREATESFID(99, ROGUE_FW_GROUP_MAIN, 3), + "Compute stalled (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(100, ROGUE_FW_GROUP_MAIN, 3), + "Compute resumed (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(101, ROGUE_FW_GROUP_MAIN, 4), + "Signal update notification from the host, PC Physical Address: 0x%08x%08x, Signal Virtual Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(102, ROGUE_FW_GROUP_MAIN, 4), + "Signal update from DM: %u, OSId: %u, PC Physical Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(103, ROGUE_FW_GROUP_MAIN, 1), + "DM: %u signal check failed" }, + { ROGUE_FW_LOG_CREATESFID(104, ROGUE_FW_GROUP_MAIN, 3), + "Kick TDM: FWCtx 0x%08.8x @ %d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(105, ROGUE_FW_GROUP_MAIN, 0), + "TDM finished" }, + { ROGUE_FW_LOG_CREATESFID(106, ROGUE_FW_GROUP_MAIN, 4), + "MMU_PM_CAT_BASE_TE[%d]_PIPE[%d]: 0x%08x 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(107, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 HIT" }, + { ROGUE_FW_LOG_CREATESFID(108, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 Dummy TA kicked" }, + { ROGUE_FW_LOG_CREATESFID(109, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 resume TA" }, + { ROGUE_FW_LOG_CREATESFID(110, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 double hit after applying WA" }, + { ROGUE_FW_LOG_CREATESFID(111, ROGUE_FW_GROUP_MAIN, 2), + "BRN 54141 Dummy TA VDM base address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(112, ROGUE_FW_GROUP_MAIN, 4), + "Signal check failed, Required Data: 0x%x, Current Data: 0x%x, Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(113, ROGUE_FW_GROUP_MAIN, 2), + "TDM stalled (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(114, ROGUE_FW_GROUP_MAIN, 1), + "Write Offset update notification for stalled FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(115, ROGUE_FW_GROUP_MAIN, 3), + "Changing OSid %d's priority from %u to %u" }, + { ROGUE_FW_LOG_CREATESFID(116, ROGUE_FW_GROUP_MAIN, 0), + "Compute resumed" }, + { ROGUE_FW_LOG_CREATESFID(117, ROGUE_FW_GROUP_MAIN, 7), + "Kick TLA: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(118, ROGUE_FW_GROUP_MAIN, 7), + "Kick TDM: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(119, ROGUE_FW_GROUP_MAIN, 11), + "Kick TA: FWCtx 0x%08.8x @ %d, RTD 0x%08x, First kick:%d, Last kick:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(120, ROGUE_FW_GROUP_MAIN, 10), + "Kick 3D: FWCtx 0x%08.8x @ %d, RTD 0x%08x, Partial render:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(121, ROGUE_FW_GROUP_MAIN, 8), + "Kick 3D TQ: FWCtx 0x%08.8x @ %d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(122, ROGUE_FW_GROUP_MAIN, 6), + "Kick Compute: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(123, ROGUE_FW_GROUP_MAIN, 8), + "Kick RTU: FWCtx 0x%08.8x @ %d, Frame Context:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(124, ROGUE_FW_GROUP_MAIN, 7), + "Kick SHG: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(125, ROGUE_FW_GROUP_MAIN, 1), + "Reconfigure CSRM: special coeff support enable %d." }, + { ROGUE_FW_LOG_CREATESFID(127, ROGUE_FW_GROUP_MAIN, 1), + "TA requires max coeff mode, deferring: %d." }, + { ROGUE_FW_LOG_CREATESFID(128, ROGUE_FW_GROUP_MAIN, 1), + "3D requires max coeff mode, deferring: %d." }, + { ROGUE_FW_LOG_CREATESFID(129, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d failed" }, + { ROGUE_FW_LOG_CREATESFID(130, ROGUE_FW_GROUP_MAIN, 2), + "Thread Queue is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(131, ROGUE_FW_GROUP_MAIN, 3), + "Thread Queue is fencing, we are waiting for Roff = %d (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(132, ROGUE_FW_GROUP_MAIN, 1), + "DM %d failed to Context Switch on time. Triggered HCS (see HWR logs)." }, + { ROGUE_FW_LOG_CREATESFID(133, ROGUE_FW_GROUP_MAIN, 1), + "HCS changed to %d ms" }, + { ROGUE_FW_LOG_CREATESFID(134, ROGUE_FW_GROUP_MAIN, 4), + "Updating Tiles In Flight (Dusts=%d, PartitionMask=0x%08x, ISPCtl=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(135, ROGUE_FW_GROUP_MAIN, 2), + " Phantom %d: USCTiles=%d" }, + { ROGUE_FW_LOG_CREATESFID(136, ROGUE_FW_GROUP_MAIN, 0), + "Isolation grouping is disabled" }, + { ROGUE_FW_LOG_CREATESFID(137, ROGUE_FW_GROUP_MAIN, 1), + "Isolation group configured with a priority threshold of %d" }, + { ROGUE_FW_LOG_CREATESFID(138, ROGUE_FW_GROUP_MAIN, 1), + "OS %d has come online" }, + { ROGUE_FW_LOG_CREATESFID(139, ROGUE_FW_GROUP_MAIN, 1), + "OS %d has gone offline" }, + { ROGUE_FW_LOG_CREATESFID(140, ROGUE_FW_GROUP_MAIN, 4), + "Signalled the previously stalled FWCtx: 0x%08.8x, OSId: %u, Signal Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(141, ROGUE_FW_GROUP_MAIN, 7), + "TDM Queue: FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(142, ROGUE_FW_GROUP_MAIN, 6), + "Reset TDM Queue Read Offset: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u becomes 0, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(143, ROGUE_FW_GROUP_MAIN, 5), + "User Mode Queue mismatched stream start: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u, StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(144, ROGUE_FW_GROUP_MAIN, 0), + "GPU deinit" }, + { ROGUE_FW_LOG_CREATESFID(145, ROGUE_FW_GROUP_MAIN, 0), + "GPU units deinit" }, + { ROGUE_FW_LOG_CREATESFID(146, ROGUE_FW_GROUP_MAIN, 2), + "Initialised OS %d with config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(147, ROGUE_FW_GROUP_MAIN, 2), + "UFO limit exceeded %d/%d" }, + { ROGUE_FW_LOG_CREATESFID(148, ROGUE_FW_GROUP_MAIN, 0), + "3D Dummy stencil store" }, + { ROGUE_FW_LOG_CREATESFID(149, ROGUE_FW_GROUP_MAIN, 3), + "Initialised OS %d with config flags 0x%08x and extended config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(150, ROGUE_FW_GROUP_MAIN, 1), + "Unknown Command (eCmdType=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(151, ROGUE_FW_GROUP_MAIN, 4), + "UFO forced update: FWCtx 0x%08.8x @ %d [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(152, ROGUE_FW_GROUP_MAIN, 5), + "UFO forced update NOP: FWCtx 0x%08.8x @ %d [0x%08.8x] = 0x%08.8x, reason %d" }, + { ROGUE_FW_LOG_CREATESFID(153, ROGUE_FW_GROUP_MAIN, 3), + "TDM context switch check: Roff %u points to 0x%08x, Match=%u" }, + { ROGUE_FW_LOG_CREATESFID(154, ROGUE_FW_GROUP_MAIN, 6), + "OSid %d CCB init status: %d (1-ok 0-fail): kCCBCtl@0x%x kCCB@0x%x fwCCBCtl@0x%x fwCCB@0x%x" }, + { ROGUE_FW_LOG_CREATESFID(155, ROGUE_FW_GROUP_MAIN, 2), + "FW IRQ # %u @ %u" }, + { ROGUE_FW_LOG_CREATESFID(156, ROGUE_FW_GROUP_MAIN, 3), + "Setting breakpoint: Addr 0x%08.8x DM%u usc_breakpoint_ctrl_dm = %u" }, + { ROGUE_FW_LOG_CREATESFID(157, ROGUE_FW_GROUP_MAIN, 3), + "Invalid KCCB setup for OSid %u: KCCB 0x%08x, KCCB Ctrl 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(158, ROGUE_FW_GROUP_MAIN, 3), + "Invalid KCCB cmd (%u) for OSid %u @ KCCB 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(159, ROGUE_FW_GROUP_MAIN, 4), + "FW FAULT: At line %d in file 0x%08x%08x, additional data=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(160, ROGUE_FW_GROUP_MAIN, 4), + "Invalid breakpoint: MemCtx 0x%08x Addr 0x%08.8x DM%u usc_breakpoint_ctrl_dm = %u" }, + { ROGUE_FW_LOG_CREATESFID(161, ROGUE_FW_GROUP_MAIN, 3), + "Discarding invalid SLC flushinval command for OSid %u: DM %u, FWCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(162, ROGUE_FW_GROUP_MAIN, 4), + "Invalid Write Offset update notification from OSid %u to DM %u: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(163, ROGUE_FW_GROUP_MAIN, 4), + "Null FWCtx in KCCB kick cmd for OSid %u: KCCB 0x%08x, ROff %u, WOff %u" }, + { ROGUE_FW_LOG_CREATESFID(164, ROGUE_FW_GROUP_MAIN, 3), + "Checkpoint CCB for OSid %u is full, signalling host for full check state (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(165, ROGUE_FW_GROUP_MAIN, 8), + "OSid %d CCB init status: %d (1-ok 0-fail): kCCBCtl@0x%x kCCB@0x%x fwCCBCtl@0x%x fwCCB@0x%x chptCCBCtl@0x%x chptCCB@0x%x" }, + { ROGUE_FW_LOG_CREATESFID(166, ROGUE_FW_GROUP_MAIN, 4), + "OSid %d fw state transition request: from %d to %d (0-offline 1-ready 2-active 3-offloading). Status %d (1-ok 0-fail)" }, + { ROGUE_FW_LOG_CREATESFID(167, ROGUE_FW_GROUP_MAIN, 2), + "OSid %u has %u stale commands in its KCCB" }, + { ROGUE_FW_LOG_CREATESFID(168, ROGUE_FW_GROUP_MAIN, 0), + "Applying VCE pause" }, + { ROGUE_FW_LOG_CREATESFID(169, ROGUE_FW_GROUP_MAIN, 3), + "OSid %u KCCB slot %u value updated to %u" }, + { ROGUE_FW_LOG_CREATESFID(170, ROGUE_FW_GROUP_MAIN, 7), + "Unknown KCCB Command: KCCBCtl=0x%08x, KCCB=0x%08x, Roff=%u, Woff=%u, Wrap=%u, Cmd=0x%08x, CmdType=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(171, ROGUE_FW_GROUP_MAIN, 10), + "Unknown Client CCB Command processing fences: FWCtx=0x%08x, CCBCtl=0x%08x, CCB=0x%08x, Roff=%u, Doff=%u, Woff=%u, Wrap=%u, CmdHdr=0x%08x, CmdType=0x%08x, CmdSize=%u" }, + { ROGUE_FW_LOG_CREATESFID(172, ROGUE_FW_GROUP_MAIN, 10), + "Unknown Client CCB Command executing kick: FWCtx=0x%08x, CCBCtl=0x%08x, CCB=0x%08x, Roff=%u, Doff=%u, Woff=%u, Wrap=%u, CmdHdr=0x%08x, CmdType=0x%08x, CmdSize=%u" }, + { ROGUE_FW_LOG_CREATESFID(173, ROGUE_FW_GROUP_MAIN, 2), + "Null FWCtx in KCCB kick cmd for OSid %u with WOff %u" }, + { ROGUE_FW_LOG_CREATESFID(174, ROGUE_FW_GROUP_MAIN, 2), + "Discarding invalid SLC flushinval command for OSid %u, FWCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(175, ROGUE_FW_GROUP_MAIN, 3), + "Invalid Write Offset update notification from OSid %u: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(176, ROGUE_FW_GROUP_MAIN, 2), + "Initialised Firmware with config flags 0x%08x and extended config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(177, ROGUE_FW_GROUP_MAIN, 1), + "Set Periodic Hardware Reset Mode: %d" }, + { ROGUE_FW_LOG_CREATESFID(179, ROGUE_FW_GROUP_MAIN, 3), + "PHR mode %d, FW state: 0x%08x, HWR flags: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(180, ROGUE_FW_GROUP_MAIN, 1), + "PHR mode %d triggered a reset" }, + { ROGUE_FW_LOG_CREATESFID(181, ROGUE_FW_GROUP_MAIN, 2), + "Signal update, Snoop Filter: %u, Signal Id: %u" }, + { ROGUE_FW_LOG_CREATESFID(182, ROGUE_FW_GROUP_MAIN, 1), + "WARNING: Skipping FW KCCB Cmd type %d which is not yet supported on Series8." }, + { ROGUE_FW_LOG_CREATESFID(183, ROGUE_FW_GROUP_MAIN, 4), + "MMU context cache data NULL, but cache flags=0x%x (sync counter=%u, update value=%u) OSId=%u" }, + { ROGUE_FW_LOG_CREATESFID(184, ROGUE_FW_GROUP_MAIN, 5), + "SLC range based flush: Context=%u VAddr=0x%02x%08x, Size=0x%08x, Invalidate=%d" }, + { ROGUE_FW_LOG_CREATESFID(185, ROGUE_FW_GROUP_MAIN, 3), + "FBSC invalidate for Context Set [0x%08x]: Entry mask 0x%08x%08x." }, + { ROGUE_FW_LOG_CREATESFID(186, ROGUE_FW_GROUP_MAIN, 3), + "TDM context switch check: Roff %u was not valid for kick starting at %u, moving back to %u" }, + { ROGUE_FW_LOG_CREATESFID(187, ROGUE_FW_GROUP_MAIN, 2), + "Signal updates: FIFO: %u, Signals: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(188, ROGUE_FW_GROUP_MAIN, 2), + "Invalid FBSC cmd: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(189, ROGUE_FW_GROUP_MAIN, 0), + "Insert BRN68497 WA blit after TDM Context store." }, + { ROGUE_FW_LOG_CREATESFID(190, ROGUE_FW_GROUP_MAIN, 1), + "UFO Updates for previously finished FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(191, ROGUE_FW_GROUP_MAIN, 1), + "RTC with RTA present, %u active render targets" }, + { ROGUE_FW_LOG_CREATESFID(192, ROGUE_FW_GROUP_MAIN, 0), + "Invalid RTA Set-up. The ValidRenderTargets array in RTACtl is Null!" }, + { ROGUE_FW_LOG_CREATESFID(193, ROGUE_FW_GROUP_MAIN, 2), + "Block 0x%x / Counter 0x%x INVALID and ignored" }, + { ROGUE_FW_LOG_CREATESFID(194, ROGUE_FW_GROUP_MAIN, 2), + "ECC fault GPU=0x%08x FW=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(195, ROGUE_FW_GROUP_MAIN, 1), + "Processing XPU event on DM = %d" }, + { ROGUE_FW_LOG_CREATESFID(196, ROGUE_FW_GROUP_MAIN, 2), + "OSid %u failed to respond to the virtualisation watchdog in time. Timestamp of its last input = %u" }, + { ROGUE_FW_LOG_CREATESFID(197, ROGUE_FW_GROUP_MAIN, 1), + "GPU-%u has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(198, ROGUE_FW_GROUP_MAIN, 3), + "Updating Tiles In Flight (Dusts=%d, PartitionMask=0x%08x, ISPCtl=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(199, ROGUE_FW_GROUP_MAIN, 0), + "GPU has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(200, ROGUE_FW_GROUP_MAIN, 1), + "Reprocessing outstanding XPU events from cores 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(201, ROGUE_FW_GROUP_MAIN, 3), + "Secondary XPU event on DM=%d, CoreMask=0x%02x, Raised=0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(202, ROGUE_FW_GROUP_MAIN, 8), + "TDM Queue: Core %u, FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(203, ROGUE_FW_GROUP_MAIN, 3), + "TDM stalled Core %u (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(204, ROGUE_FW_GROUP_MAIN, 8), + "Compute Queue: Core %u, FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(205, ROGUE_FW_GROUP_MAIN, 4), + "Compute stalled core %u (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(206, ROGUE_FW_GROUP_MAIN, 6), + "User Mode Queue mismatched stream start: Core %u, FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u, StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(207, ROGUE_FW_GROUP_MAIN, 3), + "TDM resumed core %u (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(208, ROGUE_FW_GROUP_MAIN, 4), + "Compute resumed core %u (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(209, ROGUE_FW_GROUP_MAIN, 2), + " Updated permission for OSid %u to perform MTS kicks: %u (1 = allowed, 0 = not allowed)" }, + { ROGUE_FW_LOG_CREATESFID(210, ROGUE_FW_GROUP_MAIN, 2), + "Mask = 0x%X, mask2 = 0x%X" }, + { ROGUE_FW_LOG_CREATESFID(211, ROGUE_FW_GROUP_MAIN, 3), + " core %u, reg = %u, mask = 0x%X)" }, + { ROGUE_FW_LOG_CREATESFID(212, ROGUE_FW_GROUP_MAIN, 1), + "ECC fault received from safety bus: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(213, ROGUE_FW_GROUP_MAIN, 1), + "Safety Watchdog threshold period set to 0x%x clock cycles" }, + { ROGUE_FW_LOG_CREATESFID(214, ROGUE_FW_GROUP_MAIN, 0), + "MTS Safety Event trigged by the safety watchdog." }, + { ROGUE_FW_LOG_CREATESFID(215, ROGUE_FW_GROUP_MAIN, 3), + "DM%d USC tasks range limit 0 - %d, stride %d" }, + { ROGUE_FW_LOG_CREATESFID(216, ROGUE_FW_GROUP_MAIN, 1), + "ECC fault GPU=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(217, ROGUE_FW_GROUP_MAIN, 0), + "GPU Hardware units reset to prevent transient faults." }, + { ROGUE_FW_LOG_CREATESFID(218, ROGUE_FW_GROUP_MAIN, 2), + "Kick Abort cmd: FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(219, ROGUE_FW_GROUP_MAIN, 7), + "Kick Ray: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(220, ROGUE_FW_GROUP_MAIN, 0), + "Ray finished" }, + { ROGUE_FW_LOG_CREATESFID(221, ROGUE_FW_GROUP_MAIN, 2), + "State of firmware's private data at boot time: %d (0 = uninitialised, 1 = initialised); Fw State Flags = 0x%08X" }, + { ROGUE_FW_LOG_CREATESFID(222, ROGUE_FW_GROUP_MAIN, 2), + "CFI Timeout detected (%d increasing to %d)" }, + { ROGUE_FW_LOG_CREATESFID(223, ROGUE_FW_GROUP_MAIN, 2), + "CFI Timeout detected for FBM (%d increasing to %d)" }, + { ROGUE_FW_LOG_CREATESFID(224, ROGUE_FW_GROUP_MAIN, 0), + "Geom OOM event not allowed" }, + { ROGUE_FW_LOG_CREATESFID(225, ROGUE_FW_GROUP_MAIN, 4), + "Changing OSid %d's priority from %u to %u; Isolation = %u (0 = off; 1 = on)" }, + { ROGUE_FW_LOG_CREATESFID(226, ROGUE_FW_GROUP_MAIN, 2), + "Skipping already executed TA FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(227, ROGUE_FW_GROUP_MAIN, 2), + "Attempt to execute TA FWCtx 0x%08.8x @ %d ahead of time on other GEOM" }, + { ROGUE_FW_LOG_CREATESFID(228, ROGUE_FW_GROUP_MAIN, 8), + "Kick TDM: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(229, ROGUE_FW_GROUP_MAIN, 12), + "Kick TA: Kick ID %u FWCtx 0x%08.8x @ %d, RTD 0x%08x, First kick:%d, Last kick:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(230, ROGUE_FW_GROUP_MAIN, 11), + "Kick 3D: Kick ID %u FWCtx 0x%08.8x @ %d, RTD 0x%08x, Partial render:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(231, ROGUE_FW_GROUP_MAIN, 7), + "Kick Compute: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(232, ROGUE_FW_GROUP_MAIN, 1), + "TDM finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(233, ROGUE_FW_GROUP_MAIN, 1), + "TA finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(234, ROGUE_FW_GROUP_MAIN, 3), + "3D finished: Kick ID %u , HWRTData0State=%x, HWRTData1State=%x" }, + { ROGUE_FW_LOG_CREATESFID(235, ROGUE_FW_GROUP_MAIN, 1), + "Compute finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(236, ROGUE_FW_GROUP_MAIN, 10), + "Kick TDM: Kick ID %u FWCtx 0x%08.8x @ %d, Base 0x%08x%08x. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(237, ROGUE_FW_GROUP_MAIN, 8), + "Kick Ray: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(238, ROGUE_FW_GROUP_MAIN, 1), + "Ray finished: Kick ID %u " }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MTS, 2), + "Bg Task DM = %u, counted = %d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MTS, 1), + "Bg Task complete DM = %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MTS, 3), + "Irq Task DM = %u, Breq = %d, SBIrq = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MTS, 1), + "Irq Task complete DM = %u" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MTS, 0), + "Kick MTS Bg task DM=All" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MTS, 1), + "Kick MTS Irq task DM=%d" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MTS, 2), + "Ready queue debug DM = %u, celltype = %d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MTS, 2), + "Ready-to-run debug DM = %u, item = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MTS, 3), + "Client command header DM = %u, client CCB = 0x%x, cmd = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MTS, 3), + "Ready-to-run debug OSid = %u, DM = %u, item = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MTS, 3), + "Ready queue debug DM = %u, celltype = %d, OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MTS, 3), + "Bg Task DM = %u, counted = %d, OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MTS, 1), + "Bg Task complete DM Bitfield: %u" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MTS, 0), + "Irq Task complete." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_MTS, 7), + "Discarded Command Type: %d OS ID = %d PID = %d context = 0x%08x cccb ROff = 0x%x, due to USC breakpoint hit by OS ID = %d PID = %d." }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MTS, 4), + "KCCB Slot %u: DM=%u, Cmd=0x%08x, OSid=%u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MTS, 2), + "KCCB Slot %u: Return value %u" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MTS, 1), + "Bg Task OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MTS, 3), + "KCCB Slot %u: Cmd=0x%08x, OSid=%u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MTS, 1), + "Irq Task (EVENT_STATUS=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MTS, 2), + "VZ sideband test, kicked with OSid=%u from MTS, OSid for test=%u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_CLEANUP, 1), + "FwCommonContext [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_CLEANUP, 3), + "FwCommonContext [0x%08x] is busy: ReadOffset = %d, WriteOffset = %d" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] for DM=%d, received cleanup request" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context cleaned for DM%u, executed commands = %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] HW Context for DM%u is busy" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] HW Context %u cleaned" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_CLEANUP, 1), + "Freelist [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_CLEANUP, 1), + "ZSBuffer [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_CLEANUP, 3), + "ZSBuffer [0x%08x] is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_CLEANUP, 4), + "HWRTData [0x%08x] HW Context for DM%u is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_CLEANUP, 2), + "HW Ray Frame data [0x%08x] for DM=%d, received cleanup request" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_CLEANUP, 3), + "HW Ray Frame Data [0x%08x] cleaned for DM%u, executed commands = %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_CLEANUP, 4), + "HW Ray Frame Data [0x%08x] for DM%u is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_CLEANUP, 2), + "HW Ray Frame Data [0x%08x] HW Context %u cleaned" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_CLEANUP, 1), + "Discarding invalid cleanup request of type 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_CLEANUP, 1), + "Received cleanup request for HWRTData [0x%08x]" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context %u cleaned, executed commands = %d" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_CSW, 1), + "CDM FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_CSW, 3), + "*** CDM FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_CSW, 1), + "CDM FWCtx shared alloc size load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_CSW, 0), + "*** CDM FWCtx store complete" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_CSW, 0), + "*** CDM FWCtx store start" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_CSW, 0), + "CDM Soft Reset" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_CSW, 1), + "3D FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_CSW, 1), + "*** 3D FWCtx 0x%08.8x resume" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store complete" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe state: 0x%08.8x 0x%08.8x 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store start" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_CSW, 1), + "*** 3D TQ FWCtx 0x%08.8x resume" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_CSW, 1), + "TA FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_CSW, 3), + "*** TA FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_CSW, 2), + "TA context shared alloc size store 0x%x, load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_CSW, 0), + "*** TA context store complete" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_CSW, 0), + "*** TA context store start" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_CSW, 3), + "Higher priority context scheduled for DM %u, old prio:%d, new prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_CSW, 2), + "Set FWCtx 0x%x priority to %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_CSW, 2), + "3D context store pipe%d state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_CSW, 2), + "3D context resume pipe%d state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_CSW, 1), + "SHG FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_CSW, 3), + "*** SHG FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_CSW, 2), + "SHG context shared alloc size store 0x%x, load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_CSW, 0), + "*** SHG context store complete" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_CSW, 0), + "*** SHG context store start" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_CSW, 1), + "Performing TA indirection, last used pipe %d" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_CSW, 0), + "CDM context store hit ctrl stream terminate. Skip resume." }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_CSW, 4), + "*** CDM FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x, shader state %u" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_CSW, 2), + "TA PDS/USC state buffer flip (%d->%d)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_CSW, 0), + "TA context store hit BRN 52563: vertex store tasks outstanding" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_CSW, 1), + "TA USC poll failed (USC vertex task count: %d)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_CSW, 0), + "TA context store deferred due to BRN 54141." }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_CSW, 7), + "Higher priority context scheduled for DM %u. Prios (OSid, OSid Prio, Context Prio): Current: %u, %u, %u New: %u, %u, %u" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_CSW, 0), + "*** TDM context store start" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_CSW, 0), + "*** TDM context store complete" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_CSW, 2), + "TDM context needs resume, header [0x%08.8x, 0x%08.8x]" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_CSW, 8), + "Higher priority context scheduled for DM %u. Prios (OSid, OSid Prio, Context Prio): Current: %u, %u, %u New: %u, %u, %u. Hard Context Switching: %u" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe %2d (%2d) state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_CSW, 3), + "3D context resume pipe %2d (%2d) state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_CSW, 1), + "*** 3D context store start version %d (1=IPP_TILE, 2=ISP_TILE)" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_CSW, 3), + "3D context resume pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_CSW, 2), + "3D context resume IPP state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_CSW, 1), + "All 3D pipes empty after ISP tile mode store! IPP_status: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_CSW, 3), + "TDM context resume pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store start version 4" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_CSW, 2), + "Multicore context resume on DM%d active core mask 0x%04.4x" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_CSW, 2), + "Multicore context store on DM%d active core mask 0x%04.4x" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_CSW, 5), + "TDM context resume Core %d, pipe%d state: 0x%08.8x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_CSW, 0), + "*** RDM FWCtx store complete" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_CSW, 0), + "*** RDM FWCtx store start" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_CSW, 1), + "RDM FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_CSW, 1), + "RDM FWCtx 0x%08.8x resume" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_BIF, 3), + "Activate MemCtx=0x%08x BIFreq=%d secure=%d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_BIF, 1), + "Deactivate MemCtx=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_BIF, 1), + "Alloc PC reg %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_BIF, 2), + "Grab reg set %d refcount now %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_BIF, 2), + "Ungrab reg set %d refcount now %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_BIF, 6), + "Setup reg=%d BIFreq=%d, expect=0x%08x%08x, actual=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_BIF, 2), + "Trust enabled:%d, for BIFreq=%d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_BIF, 9), + "BIF Tiling Cfg %d base 0x%08x%08x len 0x%08x%08x enable %d stride %d --> 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_BIF, 4), + "Wrote the Value %d to OSID0, Cat Base %d, Register's contents are now 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_BIF, 3), + "Wrote the Value %d to OSID1, Context %d, Register's contents are now 0x%04x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_BIF, 7), + "ui32OSid = %u, Catbase = %u, Reg Address = 0x%x, Reg index = %u, Bitshift index = %u, Val = 0x%08x%08x" }, \ + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_BIF, 5), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u, BIFREQ %u" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_BIF, 1), + "Unmap GPU memory (event status 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_BIF, 3), + "Activate MemCtx=0x%08x DM=%d secure=%d" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_BIF, 6), + "Setup reg=%d DM=%d, expect=0x%08x%08x, actual=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_BIF, 4), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_BIF, 2), + "Trust enabled:%d, for DM=%d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_BIF, 5), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u, DM %u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_BIF, 6), + "Setup register set=%d DM=%d, PC address=0x%08x%08x, OSid=%u, NewPCRegRequired=%d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_BIF, 3), + "Alloc PC set %d as register range [%u - %u]" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MISC, 1), + "GPIO write 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MISC, 1), + "GPIO read 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MISC, 0), + "GPIO enabled" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MISC, 0), + "GPIO disabled" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MISC, 1), + "GPIO status=%d (0=OK, 1=Disabled)" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MISC, 2), + "GPIO_AP: Read address=0x%02x (%d byte(s))" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MISC, 2), + "GPIO_AP: Write address=0x%02x (%d byte(s))" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MISC, 0), + "GPIO_AP timeout!" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MISC, 1), + "GPIO_AP error. GPIO status=%d (0=OK, 1=Disabled)" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MISC, 1), + "GPIO already read 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MISC, 2), + "SR: Check buffer %d available returned %d" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MISC, 1), + "SR: Waiting for buffer %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MISC, 2), + "SR: Timeout waiting for buffer %d (after %d ticks)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MISC, 2), + "SR: Skip frame check for strip %d returned %d (0=No skip, 1=Skip frame)" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_MISC, 1), + "SR: Skip remaining strip %d in frame" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MISC, 1), + "SR: Inform HW that strip %d is a new frame" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MISC, 1), + "SR: Timeout waiting for INTERRUPT_FRAME_SKIP (after %d ticks)" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip mode is %d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render start (strip %d)" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render complete (buffer %d)" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render fault (buffer %d)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_MISC, 1), + "TRP state: %d" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_MISC, 1), + "TRP failure: %d" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MISC, 1), + "SW TRP State: %d" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_MISC, 1), + "SW TRP failure: %d" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_MISC, 1), + "HW kick event (%u)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_MISC, 4), + "GPU core (%u/%u): checksum 0x%08x vs. 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_MISC, 6), + "GPU core (%u/%u), unit (%u,%u): checksum 0x%08x vs. 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_MISC, 6), + "HWR: Core%u, Register=0x%08x, OldValue=0x%08x%08x, CurrValue=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_MISC, 4), + "HWR: USC Core%u, ui32TotalSlotsUsedByDM=0x%08x, psDMHWCtl->ui32USCSlotsUsedByDM=0x%08x, bHWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_MISC, 6), + "HWR: USC Core%u, Register=0x%08x, OldValue=0x%08x%08x, CurrValue=0x%08x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_PM, 10), + "ALIST%d SP = %u, MLIST%d SP = %u (VCE 0x%08x%08x, TE 0x%08x%08x, ALIST 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_PM, 8), + "Is TA: %d, finished: %d on HW %u (HWRTData = 0x%08x, MemCtx = 0x%08x). FL different between TA/3D: global:%d, local:%d, mmu:%d" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_PM, 14), + "UFL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), MFL-3D-Base: 0x%08x%08x (SP = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_PM, 14), + "UFL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), MFL-TA-Base: 0x%08x%08x (SP = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_PM, 5), + "Freelist grow completed [0x%08x]: added pages 0x%08x, total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_PM, 1), + "Grow for freelist ID=0x%08x denied by host" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_PM, 5), + "Freelist update completed [0x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_PM, 1), + "Reconstruction of freelist ID=0x%08x failed" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_PM, 2), + "Ignored attempt to pause or unpause the DM while there is no relevant operation in progress (0-TA,1-3D): %d, operation(0-unpause, 1-pause): %d" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_PM, 2), + "Force free 3D Context memory, FWCtx: 0x%08x, status(1:success, 0:fail): %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_PM, 1), + "PM pause TA ALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_PM, 1), + "PM unpause TA ALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_PM, 1), + "PM pause 3D DALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_PM, 1), + "PM unpause 3D DALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_PM, 1), + "PM ALLOC/DALLOC change was not actioned: PM_PAGE_MANAGEOP_STATUS=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_PM, 7), + "Is TA: %d, finished: %d on HW %u (HWRTData = 0x%08x, MemCtx = 0x%08x). FL different between TA/3D: global:%d, local:%d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_PM, 10), + "UFL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_PM, 10), + "UFL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_PM, 7), + "Freelist update completed [0x%08x / FL State 0x%08x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_PM, 7), + "Freelist update failed [0x%08x / FL State 0x%08x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_PM, 10), + "UFL-3D-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_PM, 10), + "UFL-TA-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_PM, 5), + "Freelist 0x%08x base address from HW: 0x%02x%08x (expected value: 0x%02x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_PM, 5), + "Analysis of FL grow: Pause=(%u,%u) Paused+Valid(%u,%u) PMStateBuffer=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_PM, 5), + "Attempt FL grow for FL: 0x%08x, new dev address: 0x%02x%08x, new page count: %u, new ready count: %u" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_PM, 5), + "Deferring FL grow for non-loaded FL: 0x%08x, new dev address: 0x%02x%08x, new page count: %u, new ready count: %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_PM, 4), + "Is GEOM: %d, finished: %d (HWRTData = 0x%08x, MemCtx = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_PM, 1), + "3D Timeout Now for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_PM, 1), + "GEOM PM Recycle for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_PM, 1), + "PM running primary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_PM, 1), + "PM running secondary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_PM, 1), + "PM running tertiary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_PM, 1), + "PM running quaternary config (Core %d)" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_RPM, 3), + "Global link list dynamic page count: vertex 0x%x, varying 0x%x, node 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_RPM, 3), + "Global link list static page count: vertex 0x%x, varying 0x%x, node 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_RPM, 0), + "RPM request failed. Waiting for freelist grow." }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_RPM, 0), + "RPM request failed. Aborting the current frame." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_RPM, 1), + "RPM waiting for pending grow on freelist 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_RPM, 3), + "Request freelist grow [0x%08x] current pages %d, grow size %d" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_RPM, 2), + "Freelist load: SHF = 0x%08x, SHG = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_RPM, 2), + "SHF FPL register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_RPM, 2), + "SHG FPL register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_RPM, 5), + "Kernel requested RPM grow on freelist (type %d) at 0x%08x from current size %d to new size %d, RPM restart: %d (1=Yes)" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_RPM, 0), + "Restarting SHG" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_RPM, 0), + "Grow failed, aborting the current frame." }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_RPM, 1), + "RPM abort complete on HWFrameData [0x%08x]." }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_RPM, 1), + "RPM freelist cleanup [0x%08x] requires abort to proceed." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_RPM, 2), + "RPM page table base register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_RPM, 0), + "Issuing RPM abort." }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_RPM, 0), + "RPM OOM received but toggle bits indicate free pages available" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_RPM, 0), + "RPM hardware timeout. Unable to process OOM event." }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_RPM, 5), + "SHF FL (0x%08x) load, FPL: 0x%08x.0x%08x, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_RPM, 5), + "SHG FL (0x%08x) load, FPL: 0x%08x.0x%08x, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_RPM, 3), + "SHF FL (0x%08x) store, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_RPM, 3), + "SHG FL (0x%08x) store, roff: 0x%08x, woff: 0x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x finished on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x ready on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_RTD, 4), + "CONTEXT_PB_BASE set to 0x%x, FL different between TA/3D: local: %d, global: %d, mmu: %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_RTD, 2), + "Loading VFP table 0x%08x%08x for 3D" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_RTD, 2), + "Loading VFP table 0x%08x%08x for TA" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_RTD, 10), + "Load Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: TotalPMPages = %d, FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_RTD, 0), + "Perform VHEAP table store" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_RTD, 2), + "RTData 0x%08x: found match in Context=%d: Load=No, Store=No" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_RTD, 2), + "RTData 0x%08x: found NULL in Context=%d: Load=Yes, Store=No" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x: found state 3D finished (0x%08x) in Context=%d: Load=Yes, Store=Yes" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x: found state TA finished (0x%08x) in Context=%d: Load=Yes, Store=Yes" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_RTD, 5), + "Loading stack-pointers for %d (0:MidTA,1:3D) on context %d, MLIST = 0x%08x, ALIST = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_RTD, 10), + "Store Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: TotalPMPages = %d, FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_RTD, 2), + "TA RTData 0x%08x finished on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_RTD, 2), + "TA RTData 0x%08x loaded on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_RTD, 12), + "Store Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_RTD, 12), + "Load Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_RTD, 1), + "Freelist 0x%x RESET!!!!!!!!" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_RTD, 5), + "Freelist 0x%x stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_RTD, 3), + "Request reconstruction of Freelist 0x%x type: %d (0:local,1:global,2:mmu) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_RTD, 1), + "Freelist reconstruction ACK from host (HWR state :%u)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_RTD, 0), + "Freelist reconstruction completed" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_RTD, 3), + "TA RTData 0x%08x loaded on HW context %u HWRTDataNeedsLoading=%d" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_RTD, 3), + "TE Region headers base 0x%08x%08x (RGNHDR Init: %d)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_RTD, 8), + "TA Buffers: FWCtx 0x%08x, RT 0x%08x, RTData 0x%08x, VHeap 0x%08x%08x, TPC 0x%08x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x loaded on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_RTD, 4), + "3D Buffers: FWCtx 0x%08x, RT 0x%08x, RTData 0x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_RTD, 2), + "Restarting TA after partial render, HWRTData0State=0x%x, HWRTData1State=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_RTD, 3), + "CONTEXT_PB_BASE set to 0x%x, FL different between TA/3D: local: %d, global: %d" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_RTD, 12), + "Store Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_RTD, 12), + "Load Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_RTD, 5), + "3D Buffers: FWCtx 0x%08x, parent RT 0x%08x, RTData 0x%08x on ctx %d, (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_RTD, 7), + "TA Buffers: FWCtx 0x%08x, RTData 0x%08x, VHeap 0x%08x%08x, TPC 0x%08x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_RTD, 4), + "3D Buffers: FWCtx 0x%08x, RTData 0x%08x on ctx %d, (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_RTD, 6), + "Load Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u)" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_RTD, 1), + "TA RTData 0x%08x marked as killed." }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_RTD, 1), + "3D RTData 0x%08x marked as killed." }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_RTD, 1), + "RTData 0x%08x will be killed after TA restart." }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x Render State Buffer 0x%02x%08x will be reset." }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_RTD, 3), + "GEOM RTData 0x%08x using Render State Buffer 0x%02x%08x." }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_RTD, 3), + "FRAG RTData 0x%08x using Render State Buffer 0x%02x%08x." }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_SPM, 0), + "Force Z-Load for partial render" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_SPM, 0), + "Force Z-Store for partial render" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: Local FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: MMU FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: Global FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_SPM, 6), + "OOM TA/3D PR Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x, HardwareSync Fence [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_SPM, 3), + "OOM TA_cmd=0x%08x, U-FL 0x%08x, N-FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_SPM, 5), + "OOM TA_cmd=0x%08x, OOM MMU:%d, U-FL 0x%08x, N-FL 0x%08x, MMU-FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_SPM, 0), + "Partial render avoided" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_SPM, 0), + "Partial render discarded" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_SPM, 0), + "Partial Render finished" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = 3D-BG" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = 3D-IRQ" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = NONE" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = TA-BG" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = TA-IRQ" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_SPM, 2), + "ZStore address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_SPM, 2), + "SStore address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_SPM, 2), + "ZLoad address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_SPM, 2), + "SLoad address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_SPM, 0), + "No deferred ZS Buffer provided" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer successfully populated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_SPM, 1), + "No need to populate ZS Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer successfully unpopulated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_SPM, 1), + "No need to unpopulate ZS Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_SPM, 1), + "Send ZS-Buffer backing request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_SPM, 1), + "Send ZS-Buffer unbacking request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_SPM, 1), + "Don't send ZS-Buffer backing request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_SPM, 1), + "Don't send ZS-Buffer unbacking request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_SPM, 1), + "Partial Render waiting for ZBuffer to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_SPM, 1), + "Partial Render waiting for SBuffer to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_SPM, 0), + "SPM State = none" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR blocked" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_SPM, 0), + "SPM State = wait for grow" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_SPM, 0), + "SPM State = wait for HW" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR running" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR avoided" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR executed" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_SPM, 2), + "3DMemFree matches freelist 0x%08x (FL type = %u)" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_SPM, 0), + "Raise the 3DMemFreeDedected flag" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_SPM, 1), + "Wait for pending grow on Freelist 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer failed to be populated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_SPM, 5), + "Grow update inconsistency: FL addr: 0x%02x%08x, curr pages: %u, ready: %u, new: %u" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_SPM, 4), + "OOM: Resumed TA with ready pages, FL addr: 0x%02x%08x, current pages: %u, SP : %u" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_SPM, 5), + "Received grow update, FL addr: 0x%02x%08x, current pages: %u, ready pages: %u, threshold: %u" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_SPM, 1), + "No deferred partial render FW (Type=%d) Buffer provided" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_SPM, 1), + "No need to populate PR Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_SPM, 1), + "No need to unpopulate PR Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_SPM, 1), + "Send PR Buffer backing request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_SPM, 1), + "Send PR Buffer unbacking request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_SPM, 1), + "Don't send PR Buffer backing request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_SPM, 1), + "Don't send PR Buffer unbacking request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_SPM, 2), + "Partial Render waiting for Buffer %d type to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_SPM, 4), + "Received grow update, FL addr: 0x%02x%08x, new pages: %u, ready pages: %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_SPM, 3), + "OOM TA/3D PR Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_SPM, 3), + "OOM: Resumed TA with ready pages, FL addr: 0x%02x%08x, current pages: %u" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_SPM, 3), + "OOM TA/3D PR deadlock unblocked reordering DM%d runlist head from Context 0x%08x to 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR force free" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_POW, 4), + "Check Pow state DM%d int: 0x%x, ext: 0x%x, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_POW, 3), + "GPU idle (might be powered down). Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_POW, 3), + "OS requested pow off (forced = %d), DM%d, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_POW, 4), + "Initiate powoff query. Inactive DMs: %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_POW, 2), + "Any RD-DM pending? %d, Any RD-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_POW, 3), + "GPU ready to be powered down. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_POW, 2), + "HW Request On(1)/Off(0): %d, Units: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_POW, 2), + "Request to change num of dusts to %d (Power flags=%d)" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_POW, 2), + "Changing number of dusts from %d to %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_POW, 0), + "Sidekick init" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_POW, 1), + "Rascal+Dusts init (# dusts mask: 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for RD-DMs." }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for TLA-DM." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_POW, 2), + "Any RD-DM pending? %d, Any RD-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_POW, 2), + "TLA-DM pending? %d, TLA-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_POW, 1), + "Request power up due to BRN37270. Pow stat int: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_POW, 3), + "Cancel power off request int: 0x%x, ext: 0x%x, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_POW, 1), + "OS requested forced IDLE, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_POW, 1), + "OS cancelled forced IDLE, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_POW, 3), + "Idle timer start. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_POW, 3), + "Cancel idle timer. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_POW, 2), + "Active PM latency set to %dms. Core clock: %d Hz" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_POW, 2), + "Compute cluster mask change to 0x%x, %d dusts powered." }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_POW, 0), + "Null command executed, repeating initiate powoff query for RD-DMs." }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_POW, 1), + "Power monitor: Estimate of dynamic energy %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_POW, 3), + "Check Pow state: Int: 0x%x, Ext: 0x%x, Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: New deadline, time = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: New workload, cycles = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Proactive frequency calculated = %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Reactive utilisation = %u percent" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Reactive frequency calculated = %u.%u" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: OPP Point Sent = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Deadline removed = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Workload removed = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Throttle to a maximum = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Failed to pass OPP point via GPIO." }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Invalid node passed to function." }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Guest OS attempted to do a privileged action. OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Unprofiled work started. Total unprofiled work present: %u" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Unprofiled work finished. Total unprofiled work present: %u" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Disabled: Not enabled by host." }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_POW, 2), + "HW Request Completed(1)/Aborted(0): %d, Ticks: %d" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_POW, 1), + "Allowed number of dusts is %d due to BRN59042." }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_POW, 3), + "Host timed out while waiting for a forced idle state. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_POW, 5), + "Check Pow state: Int: 0x%x, Ext: 0x%x, Pow flags: 0x%x, Fence Counters: Check: %u - Update: %u" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: OPP Point Sent = 0x%x, Success = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: GPU transitioned to idle" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: GPU transitioned to active" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_POW, 1), + "Power counter dumping: Data truncated writing register %u. Buffer too small." }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_POW, 0), + "Power controller returned ABORT for last request so retrying." }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_POW, 2), + "Discarding invalid power request: type 0x%x, DM %u" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_POW, 2), + "Detected attempt to cancel forced idle while not forced idle (pow state 0x%x, pow flags 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_POW, 2), + "Detected attempt to force power off while not forced idle (pow state 0x%x, pow flags 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_POW, 1), + "Detected attempt to change dust count while not forced idle (pow state 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_POW, 3), + "Power monitor: Type = %d (0 = power, 1 = energy), Estimate result = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_POW, 2), + "Conflicting clock frequency range: OPP min = %u, max = %u" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Set floor to a minimum = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_POW, 2), + "OS requested pow off (forced = %d), pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_POW, 1), + "Discarding invalid power request: type 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_POW, 3), + "Request to change SPU power state mask from 0x%x to 0x%x. Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_POW, 2), + "Changing SPU power state mask from 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_POW, 1), + "Detected attempt to change SPU power state mask while not forced idle (pow state 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_POW, 1), + "Invalid SPU power mask 0x%x! Changing to 1" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Send OPP %u with clock divider value %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_POW, 0), + "PPA block started in perf validation mode." }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_POW, 1), + "Reset PPA block state %u (1=reset, 0=recalculate)." }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_POW, 1), + "Power controller returned ABORT for Core-%d last request so retrying." }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_POW, 3), + "HW Request On(1)/Off(0): %d, Units: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_POW, 5), + "Request to change SPU power state mask from 0x%x to 0x%x and RAC from 0x%x to 0x%x. Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_POW, 4), + "Changing SPU power state mask from 0x%x to 0x%x and RAC from 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_POW, 2), + "RAC pending? %d, RAC Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for RAC." }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_HWR, 2), + "Lockup detected on DM%d, FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_HWR, 3), + "Reset fw state for DM%d, FWCtx: 0x%08.8x, MemCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_HWR, 0), + "Reset HW" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_HWR, 0), + "Lockup recovered." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_HWR, 2), + "Lock-up DM%d FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_HWR, 4), + "Lockup detected: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_HWR, 3), + "Early fault detection: GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_HWR, 3), + "Hold scheduling due lockup: GLB(%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_HWR, 4), + "False lockup detected: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_HWR, 4), + "BRN37729: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_HWR, 3), + "Freelists reconstructed: GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_HWR, 4), + "Reconstructing freelists: %u (0-No, 1-Yes): GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_HWR, 3), + "HW poll %u (0-Unset 1-Set) failed (reg:0x%08x val:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_HWR, 2), + "Discarded cmd on DM%u FWCtx=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_HWR, 6), + "Discarded cmd on DM%u (reason=%u) HWRTData=0x%08x (st: %d), FWCtx 0x%08x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_HWR, 2), + "PM fence WA could not be applied, Valid TA Setup: %d, RD powered off: %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_HWR, 5), + "FL snapshot RTD 0x%08.8x - local (0x%08.8x): %d, global (0x%08.8x): %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_HWR, 8), + "FL check RTD 0x%08.8x, discard: %d - local (0x%08.8x): s%d?=c%d, global (0x%08.8x): s%d?=c%d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_HWR, 2), + "FL reconstruction 0x%08.8x c%d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_HWR, 3), + "3D check: missing TA FWCtx 0x%08.8x @ %d, RTD 0x%08x." }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_HWR, 2), + "Reset HW (mmu:%d, extmem: %d)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_HWR, 4), + "Zero TA caches for FWCtx: 0x%08.8x (TPC addr: 0x%08x%08x, size: %d bytes)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_HWR, 2), + "Recovery DM%u: Freelists reconstructed. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_HWR, 5), + "Recovery DM%u: FWCtx 0x%08x skipped to command @ %u. PR=%u. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_HWR, 1), + "Recovery DM%u: DM fully recovered" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_HWR, 2), + "DM%u: Hold scheduling due to R-Flag = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_HWR, 0), + "Analysis: Need freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup FWCtx: 0x%08.8x. Need to skip to next command" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup while TA is OOM FWCtx: 0x%08.8x. Need to skip to next command" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup while partial render FWCtx: 0x%08.8x. Need PR cleanup" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_HWR, 0), + "GPU has locked up" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_HWR, 1), + "DM%u ready for HWR" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_HWR, 2), + "Recovery DM%u: Updated Recovery counter. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_HWR, 1), + "Analysis: BRN37729 detected, reset TA and re-kicked 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_HWR, 1), + "DM%u timed out" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_HWR, 1), + "RGX_CR_EVENT_STATUS=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_HWR, 2), + "DM%u lockup falsely detected, R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_HWR, 0), + "GPU has overrun its deadline" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_HWR, 0), + "GPU has failed a poll" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_HWR, 2), + "RGX DM%u phase count=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_HWR, 2), + "Reset HW (loop:%d, poll failures: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_HWR, 1), + "MMU fault event: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_HWR, 1), + "BIF1 page fault detected (Bank1 MMU Status: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_HWR, 1), + "Fast CRC Failed. Proceeding to full register checking (DM: %u)." }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_HWR, 2), + "Meta MMU page fault detected (Meta MMU Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_HWR, 2), + "Fast CRC Check result for DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_HWR, 2), + "Full Signature Check result for DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_HWR, 3), + "Final result for DM%u is HWRNeeded=%u with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_HWR, 3), + "USC Slots result for DM%u is HWRNeeded=%u USCSlotsUsedByDM=%d" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_HWR, 2), + "Deadline counter for DM%u is HWRDeadline=%u" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_HWR, 1), + "Holding Scheduling on OSid %u due to pending freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_HWR, 2), + "Requesting reconstruction for freelist 0x%x (ID=%d)" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_HWR, 1), + "Reconstruction of freelist ID=%d complete" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_HWR, 4), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global,2:mmu) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_HWR, 1), + "Reconstruction of freelist ID=%d failed" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_HWR, 4), + "Restricting PDS Tasks to help other stalling DMs (RunningMask=0x%02x, StallingMask=0x%02x, PDS_CTRL=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_HWR, 4), + "Unrestricting PDS Tasks again (RunningMask=0x%02x, StallingMask=0x%02x, PDS_CTRL=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_HWR, 2), + "USC slots: %u used by DM%u" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_HWR, 1), + "USC slots: %u empty" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_HWR, 5), + "HCS DM%d's Context Switch failed to meet deadline. Current time: 0x%08x%08x, deadline: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_HWR, 1), + "Begin hardware reset (HWR Counter=%d)" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_HWR, 1), + "Finished hardware reset (HWR Counter=%d)" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_HWR, 2), + "Holding Scheduling on DM %u for OSid %u due to pending freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_HWR, 5), + "User Mode Queue ROff reset: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u becomes StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_HWR, 4), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_HWR, 3), + "Mips page fault detected (BadVAddr: 0x%08x, EntryLo0: 0x%08x, EntryLo1: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_HWR, 1), + "At least one other DM is running okay so DM%u will get another chance" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_HWR, 2), + "Reconstructing in FW, FL: 0x%x (ID=%d)" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_HWR, 4), + "Zero RTC for FWCtx: 0x%08.8x (RTC addr: 0x%08x%08x, size: %d bytes)" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_HWR, 5), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global) phase: %d (0:TA, 1:3D) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_HWR, 3), + "Start long HW poll %u (0-Unset 1-Set) for (reg:0x%08x val:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_HWR, 1), + "End long HW poll (result=%d)" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_HWR, 3), + "DM%u has taken %d ticks and deadline is %d ticks" }, + { ROGUE_FW_LOG_CREATESFID(74, ROGUE_FW_GROUP_HWR, 5), + "USC Watchdog result for DM%u is HWRNeeded=%u Status=%u USCs={0x%x} with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(75, ROGUE_FW_GROUP_HWR, 6), + "Reconstruction needed for freelist 0x%x (ID=%d) OSid: %d type: %d (0:local,1:global) phase: %d (0:TA, 1:3D) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(76, ROGUE_FW_GROUP_HWR, 1), + "GPU-%u has locked up" }, + { ROGUE_FW_LOG_CREATESFID(77, ROGUE_FW_GROUP_HWR, 1), + "DM%u has locked up" }, + { ROGUE_FW_LOG_CREATESFID(78, ROGUE_FW_GROUP_HWR, 2), + "Core %d RGX_CR_EVENT_STATUS=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(79, ROGUE_FW_GROUP_HWR, 2), + "RGX_CR_MULTICORE_EVENT_STATUS%u=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(80, ROGUE_FW_GROUP_HWR, 5), + "BIF0 page fault detected (Core %d MMU Status: 0x%08x%08x Req Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(81, ROGUE_FW_GROUP_HWR, 3), + "MMU page fault detected (Core %d MMU Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(82, ROGUE_FW_GROUP_HWR, 4), + "MMU page fault detected (Core %d MMU Status: 0x%08x%08x 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(83, ROGUE_FW_GROUP_HWR, 4), + "Reset HW (core:%d of %d, loop:%d, poll failures: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(84, ROGUE_FW_GROUP_HWR, 3), + "Fast CRC Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(85, ROGUE_FW_GROUP_HWR, 3), + "Full Signature Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(86, ROGUE_FW_GROUP_HWR, 4), + "USC Slots result for Core%u, DM%u is HWRNeeded=%u USCSlotsUsedByDM=%d" }, + { ROGUE_FW_LOG_CREATESFID(87, ROGUE_FW_GROUP_HWR, 6), + "USC Watchdog result for Core%u DM%u is HWRNeeded=%u Status=%u USCs={0x%x} with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(88, ROGUE_FW_GROUP_HWR, 3), + "RISC-V MMU page fault detected (FWCORE MMU Status 0x%08x Req Status 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(89, ROGUE_FW_GROUP_HWR, 2), + "TEXAS1_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(90, ROGUE_FW_GROUP_HWR, 2), + "BIF_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(91, ROGUE_FW_GROUP_HWR, 2), + "MMU_ABORT_PM_STATUS set poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(92, ROGUE_FW_GROUP_HWR, 2), + "MMU_ABORT_PM_STATUS unset poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(93, ROGUE_FW_GROUP_HWR, 2), + "MMU_CTRL_INVAL poll (all but fw) failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(94, ROGUE_FW_GROUP_HWR, 2), + "MMU_CTRL_INVAL poll (all) failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(95, ROGUE_FW_GROUP_HWR, 3), + "TEXAS%d_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(96, ROGUE_FW_GROUP_HWR, 3), + "Extra Registers Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(97, ROGUE_FW_GROUP_HWR, 1), + "FW attempted to write to read-only GPU address 0x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_HWP, 2), + "Block 0x%x mapped to Config Idx %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x omitted from event - not enabled in HW" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x included in event - enabled in HW" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_HWP, 2), + "Select register state hi_0x%x lo_0x%x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_HWP, 1), + "Counter stream block header word 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_HWP, 1), + "Counter register offset 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x config unset, skipping" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_HWP, 1), + "Accessing Indirect block 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_HWP, 1), + "Accessing Direct block 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_HWP, 1), + "Programmed counter select register at offset 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_HWP, 2), + "Block register offset 0x%x and value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_HWP, 1), + "Reading config block from driver 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_HWP, 2), + "Reading block range 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_HWP, 1), + "Recording block 0x%x config from driver" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_HWP, 0), + "Finished reading config block from driver" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_HWP, 2), + "Custom Counter offset: 0x%x value: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_HWP, 2), + "Select counter n:%u ID:0x%x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_HWP, 3), + "The counter ID 0x%x is not allowed. The package [b:%u, n:%u] will be discarded" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_HWP, 1), + "Custom Counters filter status %d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_HWP, 2), + "The Custom block %d is not allowed. Use only blocks lower than %d. The package will be discarded" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_HWP, 2), + "The package will be discarded because it contains %d counters IDs while the upper limit is %d" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_HWP, 2), + "Check Filter 0x%x is 0x%x ?" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_HWP, 1), + "The custom block %u is reset" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_HWP, 1), + "Encountered an invalid command (%d)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_HWP, 2), + "HWPerf Queue is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_HWP, 3), + "HWPerf Queue is fencing, we are waiting for Roff = %d (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_HWP, 1), + "Custom Counter block: %d" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x ENABLED" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x DISABLED" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_HWP, 2), + "Accessing Indirect block 0x%x, instance %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_HWP, 2), + "Counter register 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_HWP, 1), + "Counters filter status %d" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_HWP, 2), + "Block 0x%x mapped to Ctl Idx %u" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_HWP, 0), + "Block(s) in use for workload estimation." }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_HWP, 3), + "GPU %u Cycle counter 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_HWP, 3), + "GPU Mask 0x%x Cycle counter 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_HWP, 1), + "Blocks IGNORED for GPU %u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_DMA, 5), + "Transfer 0x%02x request: 0x%02x%08x -> 0x%08x, size %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_DMA, 4), + "Transfer of type 0x%02x expected on channel %u, 0x%02x found, status %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_DMA, 1), + "DMA Interrupt register 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_DMA, 1), + "Waiting for transfer of type 0x%02x completion..." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_DMA, 3), + "Loading of cCCB data from FW common context 0x%08x (offset: %u, size: %u) failed" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_DMA, 3), + "Invalid load of cCCB data from FW common context 0x%08x (offset: %u, size: %u)" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_DMA, 1), + "Transfer 0x%02x request poll failure" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_DMA, 2), + "Boot transfer(s) failed (code? %u, data? %u), used slower memcpy instead" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_DMA, 7), + "Transfer 0x%02x request on ch. %u: system 0x%02x%08x, coremem 0x%08x, flags 0x%x, size %u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_DBG, 2), + "0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_DBG, 1), + "0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_DBG, 2), + "0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_DBG, 3), + "0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_DBG, 4), + "0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_DBG, 5), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_DBG, 6), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_DBG, 7), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_DBG, 8), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_DBG, 1), + "%d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_DBG, 2), + "%d %d" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_DBG, 3), + "%d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_DBG, 4), + "%d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_DBG, 5), + "%d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_DBG, 6), + "%d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_DBG, 7), + "%d %d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_DBG, 8), + "%d %d %d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_DBG, 1), + "%u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_DBG, 2), + "%u %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_DBG, 3), + "%u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_DBG, 4), + "%u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_DBG, 5), + "%u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_DBG, 6), + "%u %u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_DBG, 7), + "%u %u %u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_DBG, 8), + "%u %u %u %u %u %u %u %u" }, + + { ROGUE_FW_LOG_CREATESFID(65535, ROGUE_FW_GROUP_NULL, 15), + "You should not use this string" }, +}; + +#define ROGUE_FW_SF_FIRST ROGUE_FW_LOG_CREATESFID(0, ROGUE_FW_GROUP_NULL, 0) +#define ROGUE_FW_SF_MAIN_ASSERT_FAILED ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MAIN, 1) +#define ROGUE_FW_SF_LAST ROGUE_FW_LOG_CREATESFID(65535, ROGUE_FW_GROUP_NULL, 15) + +#endif /* PVR_ROGUE_FWIF_SF_H */ From cb56cd61086645e46cc54d1837de803b1c471df6 Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:40 +0000 Subject: [PATCH 1191/7721] drm/imagination: Add firmware trace to debugfs Firmware trace is exposed at /sys/debug/dri//pvr_fw/trace_0. Trace is enabled via the group mask at /sys/debug/dri//pvr_params/fw_trace_mask. Changes since v8: - Corrected license identifiers Changes since v3: - Use drm_dev_{enter,exit} Co-developed-by: Matt Coster Signed-off-by: Matt Coster Signed-off-by: Sarah Walker Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/009cf9fee347fa96c8a665dc368fc54a5ffceff0.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/Makefile | 4 + drivers/gpu/drm/imagination/pvr_debugfs.c | 53 +++ drivers/gpu/drm/imagination/pvr_debugfs.h | 29 ++ drivers/gpu/drm/imagination/pvr_device.c | 9 + drivers/gpu/drm/imagination/pvr_device.h | 10 + drivers/gpu/drm/imagination/pvr_drv.c | 4 + drivers/gpu/drm/imagination/pvr_fw_trace.c | 395 +++++++++++++++++++++ drivers/gpu/drm/imagination/pvr_params.c | 147 ++++++++ drivers/gpu/drm/imagination/pvr_params.h | 72 ++++ 9 files changed, 723 insertions(+) create mode 100644 drivers/gpu/drm/imagination/pvr_debugfs.c create mode 100644 drivers/gpu/drm/imagination/pvr_debugfs.h create mode 100644 drivers/gpu/drm/imagination/pvr_params.c create mode 100644 drivers/gpu/drm/imagination/pvr_params.h diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index 7e3515c99caa..ec6db8e9b403 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -20,6 +20,7 @@ powervr-y := \ pvr_hwrt.o \ pvr_job.o \ pvr_mmu.o \ + pvr_params.o \ pvr_power.o \ pvr_queue.o \ pvr_stream.o \ @@ -28,4 +29,7 @@ powervr-y := \ pvr_vm.o \ pvr_vm_mips.o +powervr-$(CONFIG_DEBUG_FS) += \ + pvr_debugfs.o + obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_debugfs.c b/drivers/gpu/drm/imagination/pvr_debugfs.c new file mode 100644 index 000000000000..6b77c9b4bde8 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_debugfs.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_debugfs.h" + +#include "pvr_device.h" +#include "pvr_fw_trace.h" +#include "pvr_params.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +static const struct pvr_debugfs_entry pvr_debugfs_entries[] = { + {"pvr_params", pvr_params_debugfs_init}, + {"pvr_fw", pvr_fw_trace_debugfs_init}, +}; + +void +pvr_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm_dev = minor->dev; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct dentry *root = minor->debugfs_root; + size_t i; + + for (i = 0; i < ARRAY_SIZE(pvr_debugfs_entries); ++i) { + const struct pvr_debugfs_entry *entry = &pvr_debugfs_entries[i]; + struct dentry *dir; + + dir = debugfs_create_dir(entry->name, root); + if (IS_ERR(dir)) { + drm_warn(drm_dev, + "failed to create debugfs dir '%s' (err=%d)", + entry->name, (int)PTR_ERR(dir)); + continue; + } + + entry->init(pvr_dev, dir); + } +} + +/* + * Since all entries are created under &drm_minor->debugfs_root, there's no + * need for a pvr_debugfs_fini() as DRM will clean up everything under its root + * automatically. + */ diff --git a/drivers/gpu/drm/imagination/pvr_debugfs.h b/drivers/gpu/drm/imagination/pvr_debugfs.h new file mode 100644 index 000000000000..ebacbd13b84a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_debugfs.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEBUGFS_H +#define PVR_DEBUGFS_H + +/* Forward declaration from . */ +struct drm_minor; + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; + +/* Forward declaration from . */ +struct dentry; + +struct pvr_debugfs_entry { + const char *name; + void (*init)(struct pvr_device *pvr_dev, struct dentry *dir); +}; + +void pvr_debugfs_init(struct drm_minor *minor); +#else /* defined(CONFIG_DEBUG_FS) */ +#include + +static __always_inline void pvr_debugfs_init(struct drm_minor *minor) {} +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_DEBUGFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 199f812d1ee7..8499becf4fbb 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -5,6 +5,7 @@ #include "pvr_device_info.h" #include "pvr_fw.h" +#include "pvr_params.h" #include "pvr_power.h" #include "pvr_queue.h" #include "pvr_rogue_cr_defs.h" @@ -495,6 +496,14 @@ pvr_device_init(struct pvr_device *pvr_dev) struct device *dev = drm_dev->dev; int err; + /* + * Setup device parameters. We do this first in case other steps + * depend on them. + */ + err = pvr_device_params_init(&pvr_dev->params); + if (err) + return err; + /* Enable and initialize clocks required for the device to operate. */ err = pvr_device_clk_init(pvr_dev); if (err) diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index b6e9a7e8072e..e07655fc65e8 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -7,6 +7,7 @@ #include "pvr_ccb.h" #include "pvr_device_info.h" #include "pvr_fw.h" +#include "pvr_params.h" #include "pvr_rogue_fwif_stream.h" #include "pvr_stream.h" @@ -148,6 +149,15 @@ struct pvr_device { /** @fw_dev: Firmware related data. */ struct pvr_fw_device fw_dev; + /** + * @params: Device-specific parameters. + * + * The values of these parameters are initialized from the + * defaults specified as module parameters. They may be + * modified at runtime via debugfs (if enabled). + */ + struct pvr_device_params params; + /** @stream_musthave_quirks: Bit array of "must-have" quirks for stream commands. */ u32 stream_musthave_quirks[PVR_STREAM_TYPE_MAX][PVR_STREAM_EXTHDR_TYPE_MAX]; diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index a6f1d52aaebb..5c3b2d58d766 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -2,6 +2,7 @@ /* Copyright (c) 2023 Imagination Technologies Ltd. */ #include "pvr_context.h" +#include "pvr_debugfs.h" #include "pvr_device.h" #include "pvr_drv.h" #include "pvr_free_list.h" @@ -1377,6 +1378,9 @@ static struct drm_driver pvr_drm_driver = { .ioctls = pvr_drm_driver_ioctls, .num_ioctls = ARRAY_SIZE(pvr_drm_driver_ioctls), .fops = &pvr_drm_driver_fops, +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = pvr_debugfs_init, +#endif .name = PVR_DRIVER_NAME, .desc = PVR_DRIVER_DESC, diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 0a8340369f1a..87a42fb6ace6 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -4,8 +4,10 @@ #include "pvr_device.h" #include "pvr_gem.h" #include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_sf.h" #include "pvr_fw_trace.h" +#include #include #include @@ -118,3 +120,396 @@ void pvr_fw_trace_fini(struct pvr_device *pvr_dev) } pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj); } + +/** + * update_logtype() - Send KCCB command to trigger FW to update logtype + * @pvr_dev: Target PowerVR device + * @group_mask: New log group mask. + * + * Returns: + * * 0 on success, + * * Any error returned by pvr_kccb_send_cmd(), or + * * -%EIO if the device is lost. + */ +static int +update_logtype(struct pvr_device *pvr_dev, u32 group_mask) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + struct rogue_fwif_kccb_cmd cmd; + int idx; + int err; + + if (group_mask) + fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_TRACE | group_mask; + else + fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; + + fw_trace->group_mask = group_mask; + + down_read(&pvr_dev->reset_sem); + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) { + err = -EIO; + goto err_up_read; + } + + cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE; + cmd.kccb_flags = 0; + + err = pvr_kccb_send_cmd(pvr_dev, &cmd, NULL); + + drm_dev_exit(idx); + +err_up_read: + up_read(&pvr_dev->reset_sem); + + return err; +} + +#if defined(CONFIG_DEBUG_FS) + +static int fw_trace_group_mask_show(struct seq_file *m, void *data) +{ + struct pvr_device *pvr_dev = m->private; + + seq_printf(m, "%08x\n", pvr_dev->fw_dev.fw_trace.group_mask); + + return 0; +} + +static int fw_trace_group_mask_open(struct inode *inode, struct file *file) +{ + return single_open(file, fw_trace_group_mask_show, inode->i_private); +} + +static ssize_t fw_trace_group_mask_write(struct file *file, const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct pvr_device *pvr_dev = m->private; + u32 new_group_mask; + int err; + + err = kstrtouint_from_user(ubuf, len, 0, &new_group_mask); + if (err) + return err; + + err = update_logtype(pvr_dev, new_group_mask); + if (err) + return err; + + pvr_dev->fw_dev.fw_trace.group_mask = new_group_mask; + + return (ssize_t)len; +} + +static const struct file_operations pvr_fw_trace_group_mask_fops = { + .owner = THIS_MODULE, + .open = fw_trace_group_mask_open, + .read = seq_read, + .write = fw_trace_group_mask_write, + .llseek = default_llseek, + .release = single_release, +}; + +struct pvr_fw_trace_seq_data { + /** @buffer: Pointer to copy of trace data. */ + u32 *buffer; + + /** @start_offset: Starting offset in trace data, as reported by FW. */ + u32 start_offset; + + /** @idx: Current index into trace data. */ + u32 idx; + + /** @assert_buf: Trace assert buffer, as reported by FW. */ + struct rogue_fwif_file_info_buf assert_buf; +}; + +static u32 find_sfid(u32 id) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(stid_fmts); i++) { + if (stid_fmts[i].id == id) + return i; + } + + return ROGUE_FW_SF_LAST; +} + +static u32 read_fw_trace(struct pvr_fw_trace_seq_data *trace_seq_data, u32 offset) +{ + u32 idx; + + idx = trace_seq_data->idx + offset; + if (idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) + return 0; + + idx = (idx + trace_seq_data->start_offset) % ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; + return trace_seq_data->buffer[idx]; +} + +/** + * fw_trace_get_next() - Advance trace index to next entry + * @trace_seq_data: Trace sequence data. + * + * Returns: + * * %true if trace index is now pointing to a valid entry, or + * * %false if trace index is pointing to an invalid entry, or has hit the end + * of the trace. + */ +static bool fw_trace_get_next(struct pvr_fw_trace_seq_data *trace_seq_data) +{ + u32 id, sf_id; + + while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { + id = read_fw_trace(trace_seq_data, 0); + trace_seq_data->idx++; + if (!ROGUE_FW_LOG_VALIDID(id)) + continue; + if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { + /* Assertion failure marks the end of the trace. */ + return false; + } + + sf_id = find_sfid(id); + if (sf_id == ROGUE_FW_SF_FIRST) + continue; + if (sf_id == ROGUE_FW_SF_LAST) { + /* + * Could not match with an ID in the SF table, trace is + * most likely corrupt from this point. + */ + return false; + } + + /* Skip over the timestamp, and any parameters. */ + trace_seq_data->idx += 2 + ROGUE_FW_SF_PARAMNUM(id); + + /* Ensure index is now pointing to a valid trace entry. */ + id = read_fw_trace(trace_seq_data, 0); + if (!ROGUE_FW_LOG_VALIDID(id)) + continue; + + return true; + }; + + /* Hit end of trace data. */ + return false; +} + +/** + * fw_trace_get_first() - Find first valid entry in trace + * @trace_seq_data: Trace sequence data. + * + * Skips over invalid (usually zero) and ROGUE_FW_SF_FIRST entries. + * + * If the trace has no valid entries, this function will exit with the trace + * index pointing to the end of the trace. trace_seq_show() will return an error + * in this state. + */ +static void fw_trace_get_first(struct pvr_fw_trace_seq_data *trace_seq_data) +{ + trace_seq_data->idx = 0; + + while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { + u32 id = read_fw_trace(trace_seq_data, 0); + + if (ROGUE_FW_LOG_VALIDID(id)) { + u32 sf_id = find_sfid(id); + + if (sf_id != ROGUE_FW_SF_FIRST) + break; + } + trace_seq_data->idx++; + } +} + +static void *fw_trace_seq_start(struct seq_file *s, loff_t *pos) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + u32 i; + + /* Reset trace index, then advance to *pos. */ + fw_trace_get_first(trace_seq_data); + + for (i = 0; i < *pos; i++) { + if (!fw_trace_get_next(trace_seq_data)) + return NULL; + } + + return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; +} + +static void *fw_trace_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + + (*pos)++; + if (!fw_trace_get_next(trace_seq_data)) + return NULL; + + return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; +} + +static void fw_trace_seq_stop(struct seq_file *s, void *v) +{ +} + +static int fw_trace_seq_show(struct seq_file *s, void *v) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + u64 timestamp; + u32 id; + u32 sf_id; + + if (trace_seq_data->idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) + return -EINVAL; + + id = read_fw_trace(trace_seq_data, 0); + /* Index is not pointing at a valid entry. */ + if (!ROGUE_FW_LOG_VALIDID(id)) + return -EINVAL; + + sf_id = find_sfid(id); + /* Index is not pointing at a valid entry. */ + if (sf_id == ROGUE_FW_SF_LAST) + return -EINVAL; + + timestamp = read_fw_trace(trace_seq_data, 1) | + ((u64)read_fw_trace(trace_seq_data, 2) << 32); + timestamp = (timestamp & ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK) >> + ROGUE_FWT_TIMESTAMP_TIME_SHIFT; + + seq_printf(s, "[%llu] : ", timestamp); + if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { + seq_printf(s, "ASSERTION %s failed at %s:%u", + trace_seq_data->assert_buf.info, + trace_seq_data->assert_buf.path, + trace_seq_data->assert_buf.line_num); + } else { + seq_printf(s, stid_fmts[sf_id].name, + read_fw_trace(trace_seq_data, 3), + read_fw_trace(trace_seq_data, 4), + read_fw_trace(trace_seq_data, 5), + read_fw_trace(trace_seq_data, 6), + read_fw_trace(trace_seq_data, 7), + read_fw_trace(trace_seq_data, 8), + read_fw_trace(trace_seq_data, 9), + read_fw_trace(trace_seq_data, 10), + read_fw_trace(trace_seq_data, 11), + read_fw_trace(trace_seq_data, 12), + read_fw_trace(trace_seq_data, 13), + read_fw_trace(trace_seq_data, 14), + read_fw_trace(trace_seq_data, 15), + read_fw_trace(trace_seq_data, 16), + read_fw_trace(trace_seq_data, 17), + read_fw_trace(trace_seq_data, 18), + read_fw_trace(trace_seq_data, 19), + read_fw_trace(trace_seq_data, 20), + read_fw_trace(trace_seq_data, 21), + read_fw_trace(trace_seq_data, 22)); + } + seq_puts(s, "\n"); + return 0; +} + +static const struct seq_operations pvr_fw_trace_seq_ops = { + .start = fw_trace_seq_start, + .next = fw_trace_seq_next, + .stop = fw_trace_seq_stop, + .show = fw_trace_seq_show +}; + +static int fw_trace_open(struct inode *inode, struct file *file) +{ + struct pvr_fw_trace_buffer *trace_buffer = inode->i_private; + struct rogue_fwif_tracebuf_space *tracebuf_space = + trace_buffer->tracebuf_space; + struct pvr_fw_trace_seq_data *trace_seq_data; + int err; + + trace_seq_data = kzalloc(sizeof(*trace_seq_data), GFP_KERNEL); + if (!trace_seq_data) + return -ENOMEM; + + trace_seq_data->buffer = kcalloc(ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS, + sizeof(*trace_seq_data->buffer), GFP_KERNEL); + if (!trace_seq_data->buffer) { + err = -ENOMEM; + goto err_free_data; + } + + /* + * Take a local copy of the trace buffer, as firmware may still be + * writing to it. This will exist as long as this file is open. + */ + memcpy(trace_seq_data->buffer, trace_buffer->buf, + ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * sizeof(u32)); + trace_seq_data->start_offset = READ_ONCE(tracebuf_space->trace_pointer); + trace_seq_data->assert_buf = tracebuf_space->assert_buf; + fw_trace_get_first(trace_seq_data); + + err = seq_open(file, &pvr_fw_trace_seq_ops); + if (err) + goto err_free_buffer; + + ((struct seq_file *)file->private_data)->private = trace_seq_data; + + return 0; + +err_free_buffer: + kfree(trace_seq_data->buffer); + +err_free_data: + kfree(trace_seq_data); + + return err; +} + +static int fw_trace_release(struct inode *inode, struct file *file) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = + ((struct seq_file *)file->private_data)->private; + + seq_release(inode, file); + kfree(trace_seq_data->buffer); + kfree(trace_seq_data); + + return 0; +} + +static const struct file_operations pvr_fw_trace_fops = { + .owner = THIS_MODULE, + .open = fw_trace_open, + .read = seq_read, + .llseek = seq_lseek, + .release = fw_trace_release, +}; + +void +pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, u32 new_mask) +{ + if (old_mask != new_mask) + update_logtype(pvr_dev, new_mask); +} + +void +pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + u32 thread_nr; + + static_assert(ARRAY_SIZE(fw_trace->buffers) <= 10, + "The filename buffer is only large enough for a single-digit thread count"); + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); ++thread_nr) { + char filename[8]; + + snprintf(filename, ARRAY_SIZE(filename), "trace_%u", thread_nr); + debugfs_create_file(filename, 0400, dir, + &fw_trace->buffers[thread_nr], + &pvr_fw_trace_fops); + } +} +#endif diff --git a/drivers/gpu/drm/imagination/pvr_params.c b/drivers/gpu/drm/imagination/pvr_params.c new file mode 100644 index 000000000000..b91759f362c5 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_params.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_params.h" + +#include +#include + +static struct pvr_device_params pvr_device_param_defaults __read_mostly = { +#define X(type_, name_, value_, desc_, ...) .name_ = (value_), + PVR_DEVICE_PARAMS +#undef X +}; + +#define PVR_DEVICE_PARAM_NAMED(name_, type_, desc_) \ + module_param_named(name_, pvr_device_param_defaults.name_, type_, \ + 0400); \ + MODULE_PARM_DESC(name_, desc_); + +/* + * This list of defines must contain every type specified in "pvr_params.h" as + * ``PVR_PARAM_TYPE_*_C``. + */ +#define PVR_PARAM_TYPE_X32_MODPARAM uint + +#define X(type_, name_, value_, desc_, ...) \ + PVR_DEVICE_PARAM_NAMED(name_, PVR_PARAM_TYPE_##type_##_MODPARAM, desc_); +PVR_DEVICE_PARAMS +#undef X + +int +pvr_device_params_init(struct pvr_device_params *params) +{ + /* + * If heap-allocated parameters are added in the future (e.g. + * modparam's charp type), they must be handled specially here (via + * kstrdup() in the case of charp). Since that's not necessary yet, + * a straight copy will do for now. This change will also require a + * pvr_device_params_fini() function to free any heap-allocated copies. + */ + + *params = pvr_device_param_defaults; + + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +#include "pvr_device.h" + +#include +#include +#include +#include +#include + +/* + * This list of defines must contain every type specified in "pvr_params.h" as + * ``PVR_PARAM_TYPE_*_C``. + */ +#define PVR_PARAM_TYPE_X32_FMT "0x%08llx" + +#define X_SET(name_, mode_) X_SET_##mode_(name_) +#define X_SET_DEF(name_, update_, mode_) X_SET_DEF_##mode_(name_, update_) + +#define X_SET_RO(name_) NULL +#define X_SET_RW(name_) __pvr_device_param_##name_##set + +#define X_SET_DEF_RO(name_, update_) +#define X_SET_DEF_RW(name_, update_) \ + static int \ + X_SET_RW(name_)(void *data, u64 val) \ + { \ + struct pvr_device *pvr_dev = data; \ + /* This is not just (update_) to suppress -Waddress. */ \ + if ((void *)(update_) != NULL) \ + (update_)(pvr_dev, pvr_dev->params.name_, val); \ + pvr_dev->params.name_ = val; \ + return 0; \ + } + +#define X(type_, name_, value_, desc_, mode_, update_) \ + static int \ + __pvr_device_param_##name_##_get(void *data, u64 *val) \ + { \ + struct pvr_device *pvr_dev = data; \ + *val = pvr_dev->params.name_; \ + return 0; \ + } \ + X_SET_DEF(name_, update_, mode_) \ + static int \ + __pvr_device_param_##name_##_open(struct inode *inode, \ + struct file *file) \ + { \ + __simple_attr_check_format(PVR_PARAM_TYPE_##type_##_FMT, \ + 0ull); \ + return simple_attr_open(inode, file, \ + __pvr_device_param_##name_##_get, \ + X_SET(name_, mode_), \ + PVR_PARAM_TYPE_##type_##_FMT); \ + } +PVR_DEVICE_PARAMS +#undef X + +#undef X_SET +#undef X_SET_RO +#undef X_SET_RW +#undef X_SET_DEF +#undef X_SET_DEF_RO +#undef X_SET_DEF_RW + +static struct { +#define X(type_, name_, value_, desc_, mode_, update_) \ + const struct file_operations name_; + PVR_DEVICE_PARAMS +#undef X +} pvr_device_param_debugfs_fops = { +#define X(type_, name_, value_, desc_, mode_, update_) \ + .name_ = { \ + .owner = THIS_MODULE, \ + .open = __pvr_device_param_##name_##_open, \ + .release = simple_attr_release, \ + .read = simple_attr_read, \ + .write = simple_attr_write, \ + .llseek = generic_file_llseek, \ + }, + PVR_DEVICE_PARAMS +#undef X +}; + +void +pvr_params_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) +{ +#define X_MODE(mode_) X_MODE_##mode_ +#define X_MODE_RO 0400 +#define X_MODE_RW 0600 + +#define X(type_, name_, value_, desc_, mode_, update_) \ + debugfs_create_file(#name_, X_MODE(mode_), dir, pvr_dev, \ + &pvr_device_param_debugfs_fops.name_); + PVR_DEVICE_PARAMS +#undef X + +#undef X_MODE +#undef X_MODE_RO +#undef X_MODE_RW +} +#endif diff --git a/drivers/gpu/drm/imagination/pvr_params.h b/drivers/gpu/drm/imagination/pvr_params.h new file mode 100644 index 000000000000..5807915b456b --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_params.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_PARAMS_H +#define PVR_PARAMS_H + +#include "pvr_rogue_fwif.h" + +#include +#include + +/* + * This is the definitive list of types allowed in the definition of + * %PVR_DEVICE_PARAMS. + */ +#define PVR_PARAM_TYPE_X32_C u32 + +/* + * This macro defines all device-specific parameters; that is parameters which + * are set independently per device. + * + * The X-macro accepts the following arguments. Arguments marked with [debugfs] + * are ignored when debugfs is disabled; values used for these arguments may + * safely be gated behind CONFIG_DEBUG_FS. + * + * @type_: The definitive list of allowed values is PVR_PARAM_TYPE_*_C. + * @name_: Name of the parameter. This is used both as the field name in C and + * stringified as the parameter name. + * @value_: Initial/default value. + * @desc_: String literal used as help text to describe the usage of this + * parameter. + * @mode_: [debugfs] One of {RO,RW}. The access mode of the debugfs entry for + * this parameter. + * @update_: [debugfs] When debugfs support is enabled, parameters may be + * updated at runtime. When this happens, this function will be + * called to allow changes to propagate. The signature of this + * function is: + * + * void (*)(struct pvr_device *pvr_dev, T old_val, T new_val) + * + * Where T is the C type associated with @type_. + * + * If @mode_ does not allow write access, this function will never be + * called. In this case, or if no update callback is required, you + * should specify NULL for this argument. + */ +#define PVR_DEVICE_PARAMS \ + X(X32, fw_trace_mask, ROGUE_FWIF_LOG_TYPE_NONE, \ + "Enable FW trace for the specified groups. Specifying 0 disables " \ + "all FW tracing.", \ + RW, pvr_fw_trace_mask_update) + +struct pvr_device_params { +#define X(type_, name_, value_, desc_, ...) \ + PVR_PARAM_TYPE_##type_##_C name_; + PVR_DEVICE_PARAMS +#undef X +}; + +int pvr_device_params_init(struct pvr_device_params *params); + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; + +/* Forward declaration from . */ +struct dentry; + +void pvr_params_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir); +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_PARAMS_H */ From 815d8b0425ad1164e45953ac3d56a9f6f63792cc Mon Sep 17 00:00:00 2001 From: Sarah Walker Date: Wed, 22 Nov 2023 16:34:41 +0000 Subject: [PATCH 1192/7721] drm/imagination: Add driver documentation Add documentation for the UAPI. Changes since v5: - Remove obsolete VM documentation Co-developed-by: Matt Coster Signed-off-by: Matt Coster Co-developed-by: Donald Robson Signed-off-by: Donald Robson Signed-off-by: Sarah Walker Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/76a7b18cfbe93066efcee3311ae795176ce7c65d.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- Documentation/gpu/drivers.rst | 2 + Documentation/gpu/imagination/index.rst | 13 ++ Documentation/gpu/imagination/uapi.rst | 174 ++++++++++++++++++++++++ MAINTAINERS | 1 + 4 files changed, 190 insertions(+) create mode 100644 Documentation/gpu/imagination/index.rst create mode 100644 Documentation/gpu/imagination/uapi.rst diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index 45a12e552091..cc6535f5f28c 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -3,9 +3,11 @@ GPU Driver Documentation ======================== .. toctree:: + :maxdepth: 3 amdgpu/index i915 + imagination/index mcde meson pl111 diff --git a/Documentation/gpu/imagination/index.rst b/Documentation/gpu/imagination/index.rst new file mode 100644 index 000000000000..dc9579e758c3 --- /dev/null +++ b/Documentation/gpu/imagination/index.rst @@ -0,0 +1,13 @@ +======================================= +drm/imagination PowerVR Graphics Driver +======================================= + +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_drv.c + :doc: PowerVR Graphics Driver + +Contents +======== +.. toctree:: + :maxdepth: 2 + + uapi diff --git a/Documentation/gpu/imagination/uapi.rst b/Documentation/gpu/imagination/uapi.rst new file mode 100644 index 000000000000..2227ea7e6222 --- /dev/null +++ b/Documentation/gpu/imagination/uapi.rst @@ -0,0 +1,174 @@ +==== +UAPI +==== +The sources associated with this section can be found in ``pvr_drm.h``. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR UAPI + +OBJECT ARRAYS +============= +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_obj_array + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: DRM_PVR_OBJ_ARRAY + +IOCTLS +====== +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: PVR_IOCTL + +DEV_QUERY +--------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL DEV_QUERY interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_dev_query + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_dev_query_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_dev_query_gpu_info + drm_pvr_dev_query_runtime_info + drm_pvr_dev_query_hwrt_info + drm_pvr_dev_query_quirks + drm_pvr_dev_query_enhancements + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_heap_id + drm_pvr_heap + drm_pvr_dev_query_heap_info + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for DRM_PVR_DEV_QUERY_HEAP_INFO_GET. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_static_data_area_usage + drm_pvr_static_data_area + drm_pvr_dev_query_static_data_areas + +CREATE_BO +--------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_BO interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_bo_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for CREATE_BO + +GET_BO_MMAP_OFFSET +------------------ +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL GET_BO_MMAP_OFFSET interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_get_bo_mmap_offset_args + +CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT +---------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_vm_context_args + drm_pvr_ioctl_destroy_vm_context_args + +VM_MAP and VM_UNMAP +------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL VM_MAP and VM_UNMAP interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_vm_map_args + drm_pvr_ioctl_vm_unmap_args + +CREATE_CONTEXT and DESTROY_CONTEXT +---------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_CONTEXT and DESTROY_CONTEXT interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_context_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ctx_priority + drm_pvr_ctx_type + drm_pvr_static_render_context_state + drm_pvr_static_render_context_state_format + drm_pvr_reset_framework + drm_pvr_reset_framework_format + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_context_args + +CREATE_FREE_LIST and DESTROY_FREE_LIST +-------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_FREE_LIST and DESTROY_FREE_LIST interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_free_list_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_free_list_args + +CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET +-------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_hwrt_dataset_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_create_hwrt_geom_data_args + drm_pvr_create_hwrt_rt_data_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_hwrt_dataset_args + +SUBMIT_JOBS +----------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL SUBMIT_JOBS interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for the drm_pvr_sync_op object. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_submit_jobs_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl geometry command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl fragment command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl compute command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl transfer command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_sync_op + drm_pvr_job_type + drm_pvr_hwrt_data_ref + drm_pvr_job + +Internal notes +============== +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_device.h + :doc: IOCTL validation helpers + +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_device.h + :identifiers: PVR_STATIC_ASSERT_64BIT_ALIGNED PVR_IOCTL_UNION_PADDING_CHECK + pvr_ioctl_union_padding_check diff --git a/MAINTAINERS b/MAINTAINERS index debbc1956b8e..a6d8a15a23dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10398,6 +10398,7 @@ M: Donald Robson M: Matt Coster S: Supported F: Documentation/devicetree/bindings/gpu/img,powervr.yaml +F: Documentation/gpu/imagination/ F: drivers/gpu/drm/imagination/ F: include/uapi/drm/pvr_drm.h From 4bfb53e7d317c01f296b2feb2fae7c421c1d52dc Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Thu, 21 Sep 2023 19:04:22 +0800 Subject: [PATCH 1193/7721] mips: add including With the adding, some default ioremap_xx methods defined in asm-generic/io.h can be used. E.g the default ioremap_uc() returning NULL. We also massaged various headers to avoid nested includes. Signed-off-by: Baoquan He Signed-off-by: Jiaxun Yang [jiaxun.yang@flygoat.com: Massage more headers, fix ioport defines] Reviewed-by: Arnd Bergmann Acked-by: Thomas Bogendoerfer Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: linux-mips@vger.kernel.org Cc: linux-arch@vger.kernel.org Signed-off-by: Arnd Bergmann --- arch/mips/include/asm/io.h | 96 +++++++++++++++++++++++---------- arch/mips/include/asm/mmiowb.h | 4 +- arch/mips/include/asm/smp-ops.h | 2 - arch/mips/include/asm/smp.h | 4 +- arch/mips/kernel/setup.c | 1 + arch/mips/pci/pci-ip27.c | 3 ++ 6 files changed, 75 insertions(+), 35 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 062dd4e6b954..41d8bd5adef8 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -13,7 +13,6 @@ #define _ASM_IO_H #include -#include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include #include @@ -41,6 +39,11 @@ # define __raw_ioswabq(a, x) (x) # define ____raw_ioswabq(a, x) (x) +# define _ioswabb ioswabb +# define _ioswabw ioswabw +# define _ioswabl ioswabl +# define _ioswabq ioswabq + # define __relaxed_ioswabb ioswabb # define __relaxed_ioswabw ioswabw # define __relaxed_ioswabl ioswabl @@ -126,6 +129,7 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) * almost all conceivable cases a device driver should not be using * this function */ +#define phys_to_virt phys_to_virt static inline void * phys_to_virt(unsigned long address) { return __va(address); @@ -296,9 +300,9 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ return pfx##ioswab##bwlq(__mem, __val); \ } -#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, relax, p) \ +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, relax) \ \ -static inline void pfx##out##bwlq##p(type val, unsigned long port) \ +static inline void pfx##out##bwlq(type val, unsigned long port) \ { \ volatile type *__addr; \ type __val; \ @@ -318,7 +322,7 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ *__addr = __val; \ } \ \ -static inline type pfx##in##bwlq##p(unsigned long port) \ +static inline type pfx##in##bwlq(unsigned long port) \ { \ volatile type *__addr; \ type __val; \ @@ -360,11 +364,10 @@ __BUILD_MEMORY_PFX(__mem_, q, u64, 0) #endif #define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0,) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0, _p) + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0) #define BUILDIO_IOPORT(bwlq, type) \ - __BUILD_IOPORT_PFX(, bwlq, type) \ + __BUILD_IOPORT_PFX(_, bwlq, type) \ __BUILD_IOPORT_PFX(__mem_, bwlq, type) BUILDIO_IOPORT(b, u8) @@ -412,14 +415,6 @@ __BUILDIO(q, u64) #define writeq_be(val, addr) \ __raw_writeq(cpu_to_be64((val)), (__force unsigned *)(addr)) -/* - * Some code tests for these symbols - */ -#ifdef CONFIG_64BIT -#define readq readq -#define writeq writeq -#endif - #define __BUILD_MEMORY_STRING(bwlq, type) \ \ static inline void writes##bwlq(volatile void __iomem *mem, \ @@ -480,18 +475,6 @@ BUILDSTRING(l, u32) BUILDSTRING(q, u64) #endif -static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) -{ - memset((void __force *) addr, val, count); -} -static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count) -{ - memcpy(dst, (void __force *) src, count); -} -static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count) -{ - memcpy((void __force *) dst, src, count); -} /* * The caches on some architectures aren't dma-coherent and have need to @@ -548,6 +531,61 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); #define csr_out32(v, a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) #define csr_in32(a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) + +#define __raw_readb __raw_readb +#define __raw_readw __raw_readw +#define __raw_readl __raw_readl +#ifdef CONFIG_64BIT +#define __raw_readq __raw_readq +#endif +#define __raw_writeb __raw_writeb +#define __raw_writew __raw_writew +#define __raw_writel __raw_writel +#ifdef CONFIG_64BIT +#define __raw_writeq __raw_writeq +#endif + +#define readb readb +#define readw readw +#define readl readl +#ifdef CONFIG_64BIT +#define readq readq +#endif +#define writeb writeb +#define writew writew +#define writel writel +#ifdef CONFIG_64BIT +#define writeq writeq +#endif + +#define readsb readsb +#define readsw readsw +#define readsl readsl +#ifdef CONFIG_64BIT +#define readsq readsq +#endif +#define writesb writesb +#define writesw writesw +#define writesl writesl +#ifdef CONFIG_64BIT +#define writesq writesq +#endif + +#define _inb _inb +#define _inw _inw +#define _inl _inl +#define insb insb +#define insw insw +#define insl insl + +#define _outb _outb +#define _outw _outw +#define _outl _outl +#define outsb outsb +#define outsw outsw +#define outsl outsl + + /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem * access @@ -557,4 +595,6 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); void __ioread64_copy(void *to, const void __iomem *from, size_t count); +#include + #endif /* _ASM_IO_H */ diff --git a/arch/mips/include/asm/mmiowb.h b/arch/mips/include/asm/mmiowb.h index a40824e3ef8e..cf27752fd220 100644 --- a/arch/mips/include/asm/mmiowb.h +++ b/arch/mips/include/asm/mmiowb.h @@ -2,9 +2,9 @@ #ifndef _ASM_MMIOWB_H #define _ASM_MMIOWB_H -#include +#include -#define mmiowb() iobarrier_w() +#define mmiowb() wmb() #include diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 5719ff49eff1..a6941b7f0cc0 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h @@ -13,8 +13,6 @@ #include -#include - #ifdef CONFIG_SMP #include diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index a40d8c0e4b87..f3b18b4a5e44 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -11,13 +11,11 @@ #ifndef __ASM_SMP_H #define __ASM_SMP_H -#include +#include #include -#include #include #include -#include #include extern int smp_num_siblings; diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2d2ca024bd47..328426c3ed6f 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index d85cbf84e41c..973faea61cad 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c @@ -7,6 +7,9 @@ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ + +#include + #include #include #include From 026246f114d925b2ab97a60e8b4a5506bd035e9c Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Thu, 21 Sep 2023 19:04:23 +0800 Subject: [PATCH 1194/7721] arch/*/io.h: remove ioremap_uc in some architectures ioremap_uc() is only meaningful on old x86-32 systems with the PAT extension, and on ia64 with its slightly unconventional ioremap() behavior. So remove the ioremap_uc() definition in architecutures other than x86 and ia64. These architectures all have asm-generic/io.h included and will have the default ioremap_uc() definition which returns NULL. This changes the existing behaviour, while no need to worry about any breakage because in the only callsite of ioremap_uc(), code has been adjusted to eliminate the impact. Please see atyfb_setup_generic() of drivers/video/fbdev/aty/atyfb_base.c. If any new invocation of ioremap_uc() need be added, please consider using ioremap() intead or adding a ARCH specific version if necessary. Signed-off-by: Baoquan He Acked-by: Geert Uytterhoeven Acked-by: Michael Ellerman (powerpc) Acked-by: Helge Deller # parisc Acked-by: Arnd Bergmann Acked-by: Thomas Bogendoerfer Acked-by: John Paul Adrian Glaubitz (SuperH) Cc: linux-alpha@vger.kernel.org Cc: linux-hexagon@vger.kernel.org Cc: linux-m68k@lists.linux-m68k.org Cc: linux-mips@vger.kernel.org Cc: linux-parisc@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-sh@vger.kernel.org Cc: sparclinux@vger.kernel.org Signed-off-by: Arnd Bergmann --- Documentation/driver-api/device-io.rst | 9 +++++---- arch/alpha/include/asm/io.h | 1 - arch/hexagon/include/asm/io.h | 3 --- arch/m68k/include/asm/kmap.h | 1 - arch/mips/include/asm/io.h | 1 - arch/parisc/include/asm/io.h | 2 -- arch/powerpc/include/asm/io.h | 1 - arch/sh/include/asm/io.h | 2 -- arch/sparc/include/asm/io_64.h | 1 - 9 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Documentation/driver-api/device-io.rst b/Documentation/driver-api/device-io.rst index 2c7abd234f4e..d55384b106bd 100644 --- a/Documentation/driver-api/device-io.rst +++ b/Documentation/driver-api/device-io.rst @@ -408,11 +408,12 @@ functions for details on the CPU side of things. ioremap_uc() ------------ -ioremap_uc() behaves like ioremap() except that on the x86 architecture without -'PAT' mode, it marks memory as uncached even when the MTRR has designated -it as cacheable, see Documentation/arch/x86/pat.rst. +ioremap_uc() is only meaningful on old x86-32 systems with the PAT extension, +and on ia64 with its slightly unconventional ioremap() behavior, everywhere +elss ioremap_uc() defaults to return NULL. -Portable drivers should avoid the use of ioremap_uc(). + +Portable drivers should avoid the use of ioremap_uc(), use ioremap() instead. ioremap_cache() --------------- diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h index 7aeaf7c30a6f..076f0e4e7f1e 100644 --- a/arch/alpha/include/asm/io.h +++ b/arch/alpha/include/asm/io.h @@ -308,7 +308,6 @@ static inline void __iomem *ioremap(unsigned long port, unsigned long size) } #define ioremap_wc ioremap -#define ioremap_uc ioremap static inline void iounmap(volatile void __iomem *addr) { diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index e2b308e32a37..b7bc246dbcb1 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -174,9 +174,6 @@ static inline void writel(u32 data, volatile void __iomem *addr) #define _PAGE_IOREMAP (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ (__HEXAGON_C_DEV << 6)) -#define ioremap_uc(addr, size) ioremap((addr), (size)) - - #define __raw_writel writel static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, diff --git a/arch/m68k/include/asm/kmap.h b/arch/m68k/include/asm/kmap.h index 4efb3efa593a..b778f015c917 100644 --- a/arch/m68k/include/asm/kmap.h +++ b/arch/m68k/include/asm/kmap.h @@ -25,7 +25,6 @@ static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size) return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); } -#define ioremap_uc ioremap #define ioremap_wt ioremap_wt static inline void __iomem *ioremap_wt(unsigned long physaddr, unsigned long size) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 41d8bd5adef8..1ecf255efb40 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -170,7 +170,6 @@ void iounmap(const volatile void __iomem *addr); */ #define ioremap(offset, size) \ ioremap_prot((offset), (size), _CACHE_UNCACHED) -#define ioremap_uc ioremap /* * ioremap_cache - map bus memory into CPU space diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h index 366537042465..48630c78714a 100644 --- a/arch/parisc/include/asm/io.h +++ b/arch/parisc/include/asm/io.h @@ -132,8 +132,6 @@ static inline void gsc_writeq(unsigned long long val, unsigned long addr) #define ioremap_wc(addr, size) \ ioremap_prot((addr), (size), _PAGE_IOREMAP) -#define ioremap_uc(addr, size) \ - ioremap_prot((addr), (size), _PAGE_IOREMAP) #define pci_iounmap pci_iounmap diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 5220274a6277..bc624a84531d 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -900,7 +900,6 @@ void __iomem *ioremap_wt(phys_addr_t address, unsigned long size); #endif void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size); -#define ioremap_uc(addr, size) ioremap((addr), (size)) #define ioremap_cache(addr, size) \ ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index ac521f287fa5..d0b4e0765654 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -302,8 +302,6 @@ unsigned long long poke_real_address_q(unsigned long long addr, ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) #endif /* CONFIG_MMU */ -#define ioremap_uc ioremap - /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem * access diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 9303270b22f3..d8ee1442f303 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -423,7 +423,6 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) return (void __iomem *)offset; } -#define ioremap_uc(X,Y) ioremap((X),(Y)) #define ioremap_wc(X,Y) ioremap((X),(Y)) #define ioremap_wt(X,Y) ioremap((X),(Y)) static inline void __iomem *ioremap_np(unsigned long offset, unsigned long size) From aea72963608c733c85b8610f493d074d46c4ae68 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Thu, 21 Sep 2023 19:04:24 +0800 Subject: [PATCH 1195/7721] mips: io: remove duplicated codes By adding support, the duplicated phys_to_virt can be removed to use the default version in . Meanwhile move isa_bus_to_virt() down below including to fix the compiling error of missing phys_to_virt definition. Signed-off-by: Baoquan He Acked-by: Arnd Bergmann Acked-by: Thomas Bogendoerfer Cc: Thomas Bogendoerfer Cc: Geert Uytterhoeven Cc: Helge Deller Cc: Serge Semin Cc: Florian Fainelli Cc: Huacai Chen Cc: Jiaxun Yang Cc: linux-mips@vger.kernel.org Signed-off-by: Arnd Bergmann --- arch/mips/include/asm/io.h | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 1ecf255efb40..fe5476c1c689 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -117,24 +117,6 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) return __virt_to_phys(x); } -/* - * phys_to_virt - map physical address to virtual - * @address: address to remap - * - * The returned virtual address is a current CPU mapping for - * the memory address given. It is only valid to use this function on - * addresses that have a kernel mapping - * - * This function does not handle bus mappings for DMA transfers. In - * almost all conceivable cases a device driver should not be using - * this function - */ -#define phys_to_virt phys_to_virt -static inline void * phys_to_virt(unsigned long address) -{ - return __va(address); -} - /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ @@ -143,11 +125,6 @@ static inline unsigned long isa_virt_to_bus(volatile void *address) return virt_to_phys(address); } -static inline void *isa_bus_to_virt(unsigned long address) -{ - return phys_to_virt(address); -} - /* * Change "struct page" to physical address. */ @@ -596,4 +573,9 @@ void __ioread64_copy(void *to, const void __iomem *from, size_t count); #include +static inline void *isa_bus_to_virt(unsigned long address) +{ + return phys_to_virt(address); +} + #endif /* _ASM_IO_H */ From 3cd944590da9b9840c9f14bfc6581bec308c7c71 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Sat, 18 Nov 2023 18:08:27 +0800 Subject: [PATCH 1196/7721] asm/io: remove unnecessary xlate_dev_mem_ptr() and unxlate_dev_mem_ptr() The asm-generic/io.h already has default definition, remove unnecessary arch's defination. Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Brian Cain Cc: "James E.J. Bottomley" Cc: Nicholas Piggin Cc: Christophe Leroy Cc: Yoshinori Sato Cc: Rich Felker Cc: "David S. Miller" Cc: Stanislav Kinsburskii Signed-off-by: Kefeng Wang Signed-off-by: Arnd Bergmann --- arch/alpha/include/asm/io.h | 6 ------ arch/arm/include/asm/io.h | 6 ------ arch/hexagon/include/asm/io.h | 6 ------ arch/m68k/include/asm/io_mm.h | 6 ------ arch/mips/include/asm/io.h | 9 --------- arch/parisc/include/asm/io.h | 6 ------ arch/powerpc/include/asm/io.h | 6 ------ arch/sh/include/asm/io.h | 7 ------- arch/sparc/include/asm/io_64.h | 6 ------ 9 files changed, 58 deletions(-) diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h index 076f0e4e7f1e..4f47a5003fe8 100644 --- a/arch/alpha/include/asm/io.h +++ b/arch/alpha/include/asm/io.h @@ -650,12 +650,6 @@ extern void outsl (unsigned long port, const void *src, unsigned long count); #endif #define RTC_ALWAYS_BCD 0 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * These get provided from since alpha does not * select GENERIC_IOMAP. diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 56b08ed6cc3b..1815748f5d2a 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -407,12 +407,6 @@ struct pci_dev; #define pci_iounmap pci_iounmap extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #include #ifdef CONFIG_MMU diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index b7bc246dbcb1..522d321ea85a 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -58,12 +58,6 @@ static inline void *phys_to_virt(unsigned long address) return __va(address); } -/* - * convert a physical pointer to a virtual kernel pointer for - * /dev/mem access. - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * IO port access primitives. Hexagon doesn't have special IO access * instructions; all I/O is memory mapped. diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h index 47525f2a57e1..090aec54b8fa 100644 --- a/arch/m68k/include/asm/io_mm.h +++ b/arch/m68k/include/asm/io_mm.h @@ -389,12 +389,6 @@ static inline void isa_delay(void) #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) #define readl_relaxed(addr) readl(addr) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index fe5476c1c689..b0866100baf2 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -507,7 +507,6 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); #define csr_out32(v, a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) #define csr_in32(a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) - #define __raw_readb __raw_readb #define __raw_readw __raw_readw #define __raw_readl __raw_readl @@ -561,14 +560,6 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); #define outsw outsw #define outsl outsl - -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) -#define unxlate_dev_mem_ptr(p, v) do { } while (0) - void __ioread64_copy(void *to, const void __iomem *from, size_t count); #include diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h index 48630c78714a..a63190af2f05 100644 --- a/arch/parisc/include/asm/io.h +++ b/arch/parisc/include/asm/io.h @@ -265,12 +265,6 @@ extern void iowrite64be(u64 val, void __iomem *addr); #define iowrite16_rep iowrite16_rep #define iowrite32_rep iowrite32_rep -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - extern int devmem_is_allowed(unsigned long pfn); #include diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index bc624a84531d..08c550ed49be 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -709,12 +709,6 @@ static inline void name at \ #define memcpy_fromio memcpy_fromio #define memcpy_toio memcpy_toio -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * We don't do relaxed operations yet, at least not with this semantic */ diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index d0b4e0765654..cf5eab840d57 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -302,13 +302,6 @@ unsigned long long poke_real_address_q(unsigned long long addr, ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) #endif /* CONFIG_MMU */ -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) -#define unxlate_dev_mem_ptr(p, v) do { } while (0) - #include #define ARCH_HAS_VALID_PHYS_ADDR_RANGE diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index d8ee1442f303..c9528e4719cd 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -469,12 +469,6 @@ static inline int sbus_can_burst64(void) struct device; void sbus_set_sbus64(struct device *, int); -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #endif #endif /* !(__SPARC64_IO_H) */ From 280ac17856ec438757810c9123ddf2294b07c46f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 26 Oct 2023 13:31:14 +0200 Subject: [PATCH 1197/7721] hexagon: Remove CONFIG_HEXAGON_ARCH_VERSION from uapi header uapi headers should not expose CONFIG switches since they are not available in userspace. Fix it in arch/hexagon/include/uapi/asm/user.h by always defining the cs0 and cs1 entries instead of pad values. Suggested-by: Arnd Bergmann Signed-off-by: Thomas Huth Signed-off-by: Arnd Bergmann --- arch/hexagon/include/uapi/asm/user.h | 7 +------ arch/hexagon/kernel/ptrace.c | 7 +++++-- scripts/headers_install.sh | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/hexagon/include/uapi/asm/user.h b/arch/hexagon/include/uapi/asm/user.h index 7327ec59b22f..abae6a4b5813 100644 --- a/arch/hexagon/include/uapi/asm/user.h +++ b/arch/hexagon/include/uapi/asm/user.h @@ -56,15 +56,10 @@ struct user_regs_struct { unsigned long pc; unsigned long cause; unsigned long badva; -#if CONFIG_HEXAGON_ARCH_VERSION < 4 - unsigned long pad1; /* pad out to 48 words total */ - unsigned long pad2; /* pad out to 48 words total */ - unsigned long pad3; /* pad out to 48 words total */ -#else + /* cs0 and cs1 are only available with HEXAGON_ARCH_VERSION >= 4 */ unsigned long cs0; unsigned long cs1; unsigned long pad1; /* pad out to 48 words total */ -#endif }; #endif diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c index 125f19995b76..905b06790ab7 100644 --- a/arch/hexagon/kernel/ptrace.c +++ b/arch/hexagon/kernel/ptrace.c @@ -74,7 +74,7 @@ static int genregs_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - int ret; + int ret, ignore_offset; unsigned long bucket; struct pt_regs *regs = task_pt_regs(target); @@ -111,12 +111,15 @@ static int genregs_set(struct task_struct *target, #if CONFIG_HEXAGON_ARCH_VERSION >=4 INEXT(®s->cs0, cs0); INEXT(®s->cs1, cs1); + ignore_offset = offsetof(struct user_regs_struct, pad1); +#else + ignore_offset = offsetof(struct user_regs_struct, cs0); #endif /* Ignore the rest, if needed */ if (!ret) user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, - offsetof(struct user_regs_struct, pad1), -1); + ignore_offset, -1); else return ret; diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index c3064ac31003..f7d9b114de8f 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -74,7 +74,6 @@ arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8 -arch/hexagon/include/uapi/asm/user.h:CONFIG_HEXAGON_ARCH_VERSION arch/m68k/include/uapi/asm/ptrace.h:CONFIG_COLDFIRE arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT From 57b79ac9f43dc71fc8b55af51d1c9f469cb7a0de Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 5 May 2022 01:25:16 +0900 Subject: [PATCH 1198/7721] soc: apple: rtkit: Get rid of apple_rtkit_send_message_wait It is fundamentally broken and has no users. Just remove it. Acked-by: Eric Curtin Acked-by: Neal Gompa Acked-by: Alyssa Rosenzweig Signed-off-by: Hector Martin --- drivers/soc/apple/rtkit.c | 32 -------------------------------- include/linux/soc/apple/rtkit.h | 18 ------------------ 2 files changed, 50 deletions(-) diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index d9f19dc99da5..7c9b9f25bbc1 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -641,38 +641,6 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, } EXPORT_SYMBOL_GPL(apple_rtkit_send_message); -int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, - unsigned long timeout, bool atomic) -{ - DECLARE_COMPLETION_ONSTACK(completion); - int ret; - long t; - - ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic); - if (ret < 0) - return ret; - - if (atomic) { - ret = mbox_flush(rtk->mbox_chan, timeout); - if (ret < 0) - return ret; - - if (try_wait_for_completion(&completion)) - return 0; - - return -ETIME; - } else { - t = wait_for_completion_interruptible_timeout( - &completion, msecs_to_jiffies(timeout)); - if (t < 0) - return t; - else if (t == 0) - return -ETIME; - return 0; - } -} -EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait); - int apple_rtkit_poll(struct apple_rtkit *rtk) { return mbox_client_peek_data(rtk->mbox_chan); diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h index fc456f75c131..8c9ca857ccf6 100644 --- a/include/linux/soc/apple/rtkit.h +++ b/include/linux/soc/apple/rtkit.h @@ -160,24 +160,6 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint); int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, struct completion *completion, bool atomic); -/* - * Send a message to the given endpoint and wait until it has been submitted - * to the hardware FIFO. - * Will return zero on success and a negative error code on failure - * (e.g. -ETIME when the message couldn't be written within the given - * timeout) - * - * @rtk: RTKit reference - * @ep: target endpoint - * @message: message to be sent - * @timeout: timeout in milliseconds to allow the message transmission - * to be completed - * @atomic: if set to true this function can be called from atomic - * context. - */ -int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, - unsigned long timeout, bool atomic); - /* * Process incoming messages in atomic context. * This only guarantees that messages arrive as far as the recv_message_early From 6e1457fcad3ff6b1885e64f5e393db5ff5ec2a42 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 14 Mar 2023 19:45:45 +0900 Subject: [PATCH 1199/7721] soc: apple: mailbox: Add ASC/M3 mailbox driver This new driver is based on the existing apple-mailbox driver, but replaces the usage of the mailbox subsystem with directly exported symbols. As part of this refactor, this adds support for using the hardware FIFOs (not supported in mailbox) and implicitly fixes a bunch of bugs caused by bad interactions with the mailbox subsystem. It also adds runtime-PM support. The new config symbol is APPLE_MBOX, while the module name remains identical ("apple-mailbox"). The configs are mutually exclusive in Kconfig, to avoid conflicts. Acked-by: Eric Curtin Acked-by: Neal Gompa Acked-by: Alyssa Rosenzweig Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 14 ++ drivers/soc/apple/Makefile | 4 + drivers/soc/apple/mailbox.c | 436 ++++++++++++++++++++++++++++++++++++ drivers/soc/apple/mailbox.h | 48 ++++ 4 files changed, 502 insertions(+) create mode 100644 drivers/soc/apple/mailbox.c create mode 100644 drivers/soc/apple/mailbox.h diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index eff486a77337..e47e10570bd5 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -4,6 +4,20 @@ if ARCH_APPLE || COMPILE_TEST menu "Apple SoC drivers" +config APPLE_MBOX + tristate "Apple SoC mailboxes" + depends on PM + depends on ARCH_APPLE || (64BIT && COMPILE_TEST) + depends on !APPLE_MAILBOX + default ARCH_APPLE + help + Apple SoCs have various co-processors required for certain + peripherals to work (NVMe, display controller, etc.). This + driver adds support for the mailbox controller used to + communicate with those. + + Say Y here if you have an Apple SoC. + config APPLE_RTKIT tristate "Apple RTKit co-processor IPC protocol" depends on MAILBOX diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index b241e6a65e5b..2a7835eda070 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_APPLE_MBOX) += apple-mailbox.o +apple-mailbox-y = mailbox.o + obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o apple-rtkit-y = rtkit.o rtkit-crashlog.o diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c new file mode 100644 index 000000000000..0cbd172f435e --- /dev/null +++ b/drivers/soc/apple/mailbox.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple mailbox driver + * + * Copyright The Asahi Linux Contributors + * + * This driver adds support for two mailbox variants (called ASC and M3 by + * Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to + * exchange 64+32 bit messages between the main CPU and a co-processor. + * Various coprocessors implement different IPC protocols based on these simple + * messages and shared memory buffers. + * + * Both the main CPU and the co-processor see the same set of registers but + * the first FIFO (A2I) is always used to transfer messages from the application + * processor (us) to the I/O processor and the second one (I2A) for the + * other direction. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mailbox.h" + +#define APPLE_ASC_MBOX_CONTROL_FULL BIT(16) +#define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17) + +#define APPLE_ASC_MBOX_A2I_CONTROL 0x110 +#define APPLE_ASC_MBOX_A2I_SEND0 0x800 +#define APPLE_ASC_MBOX_A2I_SEND1 0x808 +#define APPLE_ASC_MBOX_A2I_RECV0 0x810 +#define APPLE_ASC_MBOX_A2I_RECV1 0x818 + +#define APPLE_ASC_MBOX_I2A_CONTROL 0x114 +#define APPLE_ASC_MBOX_I2A_SEND0 0x820 +#define APPLE_ASC_MBOX_I2A_SEND1 0x828 +#define APPLE_ASC_MBOX_I2A_RECV0 0x830 +#define APPLE_ASC_MBOX_I2A_RECV1 0x838 + +#define APPLE_M3_MBOX_CONTROL_FULL BIT(16) +#define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17) + +#define APPLE_M3_MBOX_A2I_CONTROL 0x50 +#define APPLE_M3_MBOX_A2I_SEND0 0x60 +#define APPLE_M3_MBOX_A2I_SEND1 0x68 +#define APPLE_M3_MBOX_A2I_RECV0 0x70 +#define APPLE_M3_MBOX_A2I_RECV1 0x78 + +#define APPLE_M3_MBOX_I2A_CONTROL 0x80 +#define APPLE_M3_MBOX_I2A_SEND0 0x90 +#define APPLE_M3_MBOX_I2A_SEND1 0x98 +#define APPLE_M3_MBOX_I2A_RECV0 0xa0 +#define APPLE_M3_MBOX_I2A_RECV1 0xa8 + +#define APPLE_M3_MBOX_IRQ_ENABLE 0x48 +#define APPLE_M3_MBOX_IRQ_ACK 0x4c +#define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0) +#define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1) +#define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2) +#define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3) + +#define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52) +#define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48) +#define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44) +#define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40) +#define APPLE_MBOX_MSG1_MSG GENMASK(31, 0) + +#define APPLE_MBOX_TX_TIMEOUT 500 + +struct apple_mbox_hw { + unsigned int control_full; + unsigned int control_empty; + + unsigned int a2i_control; + unsigned int a2i_send0; + unsigned int a2i_send1; + + unsigned int i2a_control; + unsigned int i2a_recv0; + unsigned int i2a_recv1; + + bool has_irq_controls; + unsigned int irq_enable; + unsigned int irq_ack; + unsigned int irq_bit_recv_not_empty; + unsigned int irq_bit_send_empty; +}; + +int apple_mbox_send(struct apple_mbox *mbox, const struct apple_mbox_msg msg, + bool atomic) +{ + unsigned long flags; + int ret; + u32 mbox_ctrl; + long t; + + spin_lock_irqsave(&mbox->tx_lock, flags); + mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control); + + while (mbox_ctrl & mbox->hw->control_full) { + if (atomic) { + ret = readl_poll_timeout_atomic( + mbox->regs + mbox->hw->a2i_control, mbox_ctrl, + !(mbox_ctrl & mbox->hw->control_full), 100, + APPLE_MBOX_TX_TIMEOUT * 1000); + + if (ret) { + spin_unlock_irqrestore(&mbox->tx_lock, flags); + return ret; + } + + break; + } + /* + * The interrupt is level triggered and will keep firing as long as the + * FIFO is empty. It will also keep firing if the FIFO was empty + * at any point in the past until it has been acknowledged at the + * mailbox level. By acknowledging it here we can ensure that we will + * only get the interrupt once the FIFO has been cleared again. + * If the FIFO is already empty before the ack it will fire again + * immediately after the ack. + */ + if (mbox->hw->has_irq_controls) { + writel_relaxed(mbox->hw->irq_bit_send_empty, + mbox->regs + mbox->hw->irq_ack); + } + enable_irq(mbox->irq_send_empty); + reinit_completion(&mbox->tx_empty); + spin_unlock_irqrestore(&mbox->tx_lock, flags); + + t = wait_for_completion_interruptible_timeout( + &mbox->tx_empty, + msecs_to_jiffies(APPLE_MBOX_TX_TIMEOUT)); + if (t < 0) + return t; + else if (t == 0) + return -ETIMEDOUT; + + spin_lock_irqsave(&mbox->tx_lock, flags); + mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control); + } + + writeq_relaxed(msg.msg0, mbox->regs + mbox->hw->a2i_send0); + writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg.msg1), + mbox->regs + mbox->hw->a2i_send1); + + spin_unlock_irqrestore(&mbox->tx_lock, flags); + + return 0; +} +EXPORT_SYMBOL(apple_mbox_send); + +static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) +{ + struct apple_mbox *mbox = data; + + /* + * We don't need to acknowledge the interrupt at the mailbox level + * here even if supported by the hardware. It will keep firing but that + * doesn't matter since it's disabled at the main interrupt controller. + * apple_mbox_send will acknowledge it before enabling + * it at the main controller again. + */ + spin_lock(&mbox->tx_lock); + disable_irq_nosync(mbox->irq_send_empty); + complete(&mbox->tx_empty); + spin_unlock(&mbox->tx_lock); + + return IRQ_HANDLED; +} + +static int apple_mbox_poll_locked(struct apple_mbox *mbox) +{ + struct apple_mbox_msg msg; + int ret = 0; + + u32 mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control); + + while (!(mbox_ctrl & mbox->hw->control_empty)) { + msg.msg0 = readq_relaxed(mbox->regs + mbox->hw->i2a_recv0); + msg.msg1 = FIELD_GET( + APPLE_MBOX_MSG1_MSG, + readq_relaxed(mbox->regs + mbox->hw->i2a_recv1)); + + mbox->rx(mbox, msg, mbox->cookie); + ret++; + mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control); + } + + /* + * The interrupt will keep firing even if there are no more messages + * unless we also acknowledge it at the mailbox level here. + * There's no race if a message comes in between the check in the while + * loop above and the ack below: If a new messages arrives inbetween + * those two the interrupt will just fire again immediately after the + * ack since it's level triggered. + */ + if (mbox->hw->has_irq_controls) { + writel_relaxed(mbox->hw->irq_bit_recv_not_empty, + mbox->regs + mbox->hw->irq_ack); + } + + return ret; +} + +static irqreturn_t apple_mbox_recv_irq(int irq, void *data) +{ + struct apple_mbox *mbox = data; + + spin_lock(&mbox->rx_lock); + apple_mbox_poll_locked(mbox); + spin_unlock(&mbox->rx_lock); + + return IRQ_HANDLED; +} + +int apple_mbox_poll(struct apple_mbox *mbox) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&mbox->rx_lock, flags); + ret = apple_mbox_poll_locked(mbox); + spin_unlock_irqrestore(&mbox->rx_lock, flags); + + return ret; +} +EXPORT_SYMBOL(apple_mbox_poll); + +int apple_mbox_start(struct apple_mbox *mbox) +{ + int ret; + + if (mbox->active) + return 0; + + ret = pm_runtime_resume_and_get(mbox->dev); + if (ret) + return ret; + + /* + * Only some variants of this mailbox HW provide interrupt control + * at the mailbox level. We therefore need to handle enabling/disabling + * interrupts at the main interrupt controller anyway for hardware that + * doesn't. Just always keep the interrupts we care about enabled at + * the mailbox level so that both hardware revisions behave almost + * the same. + */ + if (mbox->hw->has_irq_controls) { + writel_relaxed(mbox->hw->irq_bit_recv_not_empty | + mbox->hw->irq_bit_send_empty, + mbox->regs + mbox->hw->irq_enable); + } + + enable_irq(mbox->irq_recv_not_empty); + mbox->active = true; + return 0; +} +EXPORT_SYMBOL(apple_mbox_start); + +void apple_mbox_stop(struct apple_mbox *mbox) +{ + if (!mbox->active) + return; + + mbox->active = false; + disable_irq(mbox->irq_recv_not_empty); + pm_runtime_mark_last_busy(mbox->dev); + pm_runtime_put_autosuspend(mbox->dev); +} +EXPORT_SYMBOL(apple_mbox_stop); + +struct apple_mbox *apple_mbox_get(struct device *dev, int index) +{ + struct of_phandle_args args; + struct platform_device *pdev; + struct apple_mbox *mbox; + int ret; + + ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", + index, &args); + if (ret || !args.np) + return ERR_PTR(ret); + + pdev = of_find_device_by_node(args.np); + of_node_put(args.np); + + if (!pdev) + return ERR_PTR(EPROBE_DEFER); + + mbox = platform_get_drvdata(pdev); + if (!mbox) + return ERR_PTR(EPROBE_DEFER); + + if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) + return ERR_PTR(ENODEV); + + return mbox; +} +EXPORT_SYMBOL(apple_mbox_get); + +struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name) +{ + int index; + + index = of_property_match_string(dev->of_node, "mbox-names", name); + if (index < 0) + return ERR_PTR(index); + + return apple_mbox_get(dev, index); +} +EXPORT_SYMBOL(apple_mbox_get_byname); + +static int apple_mbox_probe(struct platform_device *pdev) +{ + int ret; + char *irqname; + struct apple_mbox *mbox; + struct device *dev = &pdev->dev; + + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + mbox->dev = &pdev->dev; + mbox->hw = of_device_get_match_data(dev); + if (!mbox->hw) + return -EINVAL; + + mbox->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mbox->regs)) + return PTR_ERR(mbox->regs); + + mbox->irq_recv_not_empty = + platform_get_irq_byname(pdev, "recv-not-empty"); + if (mbox->irq_recv_not_empty < 0) + return -ENODEV; + + mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty"); + if (mbox->irq_send_empty < 0) + return -ENODEV; + + spin_lock_init(&mbox->rx_lock); + spin_lock_init(&mbox->tx_lock); + init_completion(&mbox->tx_empty); + + irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev)); + if (!irqname) + return -ENOMEM; + + ret = devm_request_irq(dev, mbox->irq_recv_not_empty, + apple_mbox_recv_irq, + IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox); + if (ret) + return ret; + + irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev)); + if (!irqname) + return -ENOMEM; + + ret = devm_request_irq(dev, mbox->irq_send_empty, + apple_mbox_send_empty_irq, + IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox); + if (ret) + return ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + platform_set_drvdata(pdev, mbox); + return 0; +} + +static const struct apple_mbox_hw apple_mbox_asc_hw = { + .control_full = APPLE_ASC_MBOX_CONTROL_FULL, + .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY, + + .a2i_control = APPLE_ASC_MBOX_A2I_CONTROL, + .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0, + .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1, + + .i2a_control = APPLE_ASC_MBOX_I2A_CONTROL, + .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0, + .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1, + + .has_irq_controls = false, +}; + +static const struct apple_mbox_hw apple_mbox_m3_hw = { + .control_full = APPLE_M3_MBOX_CONTROL_FULL, + .control_empty = APPLE_M3_MBOX_CONTROL_EMPTY, + + .a2i_control = APPLE_M3_MBOX_A2I_CONTROL, + .a2i_send0 = APPLE_M3_MBOX_A2I_SEND0, + .a2i_send1 = APPLE_M3_MBOX_A2I_SEND1, + + .i2a_control = APPLE_M3_MBOX_I2A_CONTROL, + .i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0, + .i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1, + + .has_irq_controls = true, + .irq_enable = APPLE_M3_MBOX_IRQ_ENABLE, + .irq_ack = APPLE_M3_MBOX_IRQ_ACK, + .irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY, + .irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY, +}; + +static const struct of_device_id apple_mbox_of_match[] = { + { .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw }, + { .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_mbox_of_match); + +static struct platform_driver apple_mbox_driver = { + .driver = { + .name = "apple-mailbox", + .of_match_table = apple_mbox_of_match, + }, + .probe = apple_mbox_probe, +}; +module_platform_driver(apple_mbox_driver); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_AUTHOR("Sven Peter "); +MODULE_DESCRIPTION("Apple Mailbox driver"); diff --git a/drivers/soc/apple/mailbox.h b/drivers/soc/apple/mailbox.h new file mode 100644 index 000000000000..f73a8913da95 --- /dev/null +++ b/drivers/soc/apple/mailbox.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* + * Apple mailbox message format + * + * Copyright The Asahi Linux Contributors + */ + +#ifndef _APPLE_MAILBOX_H_ +#define _APPLE_MAILBOX_H_ + +#include +#include + +/* encodes a single 96bit message sent over the single channel */ +struct apple_mbox_msg { + u64 msg0; + u32 msg1; +}; + +struct apple_mbox { + struct device *dev; + void __iomem *regs; + const struct apple_mbox_hw *hw; + bool active; + + int irq_recv_not_empty; + int irq_send_empty; + + spinlock_t rx_lock; + spinlock_t tx_lock; + + struct completion tx_empty; + + /** Receive callback for incoming messages */ + void (*rx)(struct apple_mbox *mbox, struct apple_mbox_msg msg, void *cookie); + void *cookie; +}; + +struct apple_mbox *apple_mbox_get(struct device *dev, int index); +struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name); + +int apple_mbox_start(struct apple_mbox *mbox); +void apple_mbox_stop(struct apple_mbox *mbox); +int apple_mbox_poll(struct apple_mbox *mbox); +int apple_mbox_send(struct apple_mbox *mbox, struct apple_mbox_msg msg, + bool atomic); + +#endif From bb538effdc71397f2d08bb98df6b326d3b5b2333 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 14 Mar 2023 19:46:47 +0900 Subject: [PATCH 1200/7721] soc: apple: rtkit: Port to the internal mailbox driver Now that we have a mailbox driver in drivers/soc/apple, port the RTKit code to it. This mostly just entails replacing calls through the mailbox subsystem with direct calls into the driver. Acked-by: Eric Curtin Acked-by: Neal Gompa Acked-by: Alyssa Rosenzweig Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 2 +- drivers/soc/apple/rtkit-internal.h | 8 +-- drivers/soc/apple/rtkit.c | 101 ++++++++--------------------- 3 files changed, 31 insertions(+), 80 deletions(-) diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index e47e10570bd5..24309e40fbbe 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -20,7 +20,7 @@ config APPLE_MBOX config APPLE_RTKIT tristate "Apple RTKit co-processor IPC protocol" - depends on MAILBOX + depends on APPLE_MBOX depends on ARCH_APPLE || COMPILE_TEST default ARCH_APPLE help diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h index 24bd619ec5e4..27c9fa745fd5 100644 --- a/drivers/soc/apple/rtkit-internal.h +++ b/drivers/soc/apple/rtkit-internal.h @@ -7,18 +7,17 @@ #ifndef _APPLE_RTKIT_INTERAL_H #define _APPLE_RTKIT_INTERAL_H -#include #include #include #include #include #include #include -#include #include #include #include #include +#include "mailbox.h" #define APPLE_RTKIT_APP_ENDPOINT_START 0x20 #define APPLE_RTKIT_MAX_ENDPOINTS 0x100 @@ -28,10 +27,7 @@ struct apple_rtkit { const struct apple_rtkit_ops *ops; struct device *dev; - const char *mbox_name; - int mbox_idx; - struct mbox_client mbox_cl; - struct mbox_chan *mbox_chan; + struct apple_mbox *mbox; struct completion epmap_completion; struct completion iop_pwr_ack_completion; diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index 7c9b9f25bbc1..e6d940292c9f 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -72,11 +72,6 @@ enum { #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 -struct apple_rtkit_msg { - struct completion *completion; - struct apple_mbox_msg mbox_msg; -}; - struct apple_rtkit_rx_work { struct apple_rtkit *rtk; u8 ep; @@ -550,12 +545,12 @@ static void apple_rtkit_rx_work(struct work_struct *work) kfree(rtk_work); } -static void apple_rtkit_rx(struct mbox_client *cl, void *mssg) +static void apple_rtkit_rx(struct apple_mbox *mbox, struct apple_mbox_msg msg, + void *cookie) { - struct apple_rtkit *rtk = container_of(cl, struct apple_rtkit, mbox_cl); - struct apple_mbox_msg *msg = mssg; + struct apple_rtkit *rtk = cookie; struct apple_rtkit_rx_work *work; - u8 ep = msg->msg1; + u8 ep = msg.msg1; /* * The message was read from a MMIO FIFO and we have to make @@ -571,7 +566,7 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg) if (ep >= APPLE_RTKIT_APP_ENDPOINT_START && rtk->ops->recv_message_early && - rtk->ops->recv_message_early(rtk->cookie, ep, msg->msg0)) + rtk->ops->recv_message_early(rtk->cookie, ep, msg.msg0)) return; work = kzalloc(sizeof(*work), GFP_ATOMIC); @@ -580,30 +575,18 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg) work->rtk = rtk; work->ep = ep; - work->msg = msg->msg0; + work->msg = msg.msg0; INIT_WORK(&work->work, apple_rtkit_rx_work); queue_work(rtk->wq, &work->work); } -static void apple_rtkit_tx_done(struct mbox_client *cl, void *mssg, int r) -{ - struct apple_rtkit_msg *msg = - container_of(mssg, struct apple_rtkit_msg, mbox_msg); - - if (r == -ETIME) - return; - - if (msg->completion) - complete(msg->completion); - kfree(msg); -} - int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, struct completion *completion, bool atomic) { - struct apple_rtkit_msg *msg; - int ret; - gfp_t flags; + struct apple_mbox_msg msg = { + .msg0 = message, + .msg1 = ep, + }; if (rtk->crashed) return -EINVAL; @@ -611,19 +594,6 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, !apple_rtkit_is_running(rtk)) return -EINVAL; - if (atomic) - flags = GFP_ATOMIC; - else - flags = GFP_KERNEL; - - msg = kzalloc(sizeof(*msg), flags); - if (!msg) - return -ENOMEM; - - msg->mbox_msg.msg0 = message; - msg->mbox_msg.msg1 = ep; - msg->completion = completion; - /* * The message will be sent with a MMIO write. We need the barrier * here to ensure any previous writes to buffers are visible to the @@ -631,19 +601,13 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, */ dma_wmb(); - ret = mbox_send_message(rtk->mbox_chan, &msg->mbox_msg); - if (ret < 0) { - kfree(msg); - return ret; - } - - return 0; + return apple_mbox_send(rtk->mbox, msg, atomic); } EXPORT_SYMBOL_GPL(apple_rtkit_send_message); int apple_rtkit_poll(struct apple_rtkit *rtk) { - return mbox_client_peek_data(rtk->mbox_chan); + return apple_mbox_poll(rtk->mbox); } EXPORT_SYMBOL_GPL(apple_rtkit_poll); @@ -665,20 +629,6 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint) } EXPORT_SYMBOL_GPL(apple_rtkit_start_ep); -static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk) -{ - if (rtk->mbox_name) - rtk->mbox_chan = mbox_request_channel_byname(&rtk->mbox_cl, - rtk->mbox_name); - else - rtk->mbox_chan = - mbox_request_channel(&rtk->mbox_cl, rtk->mbox_idx); - - if (IS_ERR(rtk->mbox_chan)) - return PTR_ERR(rtk->mbox_chan); - return 0; -} - struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops) @@ -704,13 +654,18 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS); set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints); - rtk->mbox_name = mbox_name; - rtk->mbox_idx = mbox_idx; - rtk->mbox_cl.dev = dev; - rtk->mbox_cl.tx_block = false; - rtk->mbox_cl.knows_txdone = false; - rtk->mbox_cl.rx_callback = &apple_rtkit_rx; - rtk->mbox_cl.tx_done = &apple_rtkit_tx_done; + if (mbox_name) + rtk->mbox = apple_mbox_get_byname(dev, mbox_name); + else + rtk->mbox = apple_mbox_get(dev, mbox_idx); + + if (IS_ERR(rtk->mbox)) { + ret = PTR_ERR(rtk->mbox); + goto free_rtk; + } + + rtk->mbox->rx = apple_rtkit_rx; + rtk->mbox->cookie = rtk; rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM, dev_name(rtk->dev)); @@ -719,7 +674,7 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, goto free_rtk; } - ret = apple_rtkit_request_mbox_chan(rtk); + ret = apple_mbox_start(rtk->mbox); if (ret) goto destroy_wq; @@ -750,7 +705,7 @@ static int apple_rtkit_wait_for_completion(struct completion *c) int apple_rtkit_reinit(struct apple_rtkit *rtk) { /* make sure we don't handle any messages while reinitializing */ - mbox_free_channel(rtk->mbox_chan); + apple_mbox_stop(rtk->mbox); flush_workqueue(rtk->wq); apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); @@ -774,7 +729,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk) rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF; rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF; - return apple_rtkit_request_mbox_chan(rtk); + return apple_mbox_start(rtk->mbox); } EXPORT_SYMBOL_GPL(apple_rtkit_reinit); @@ -930,7 +885,7 @@ EXPORT_SYMBOL_GPL(apple_rtkit_wake); void apple_rtkit_free(struct apple_rtkit *rtk) { - mbox_free_channel(rtk->mbox_chan); + apple_mbox_stop(rtk->mbox); destroy_workqueue(rtk->wq); apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); From 143897c4fa976d02bfafe5ae32b9ffc60dc6145a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 14 Mar 2023 19:47:32 +0900 Subject: [PATCH 1201/7721] mailbox: apple: Delete driver This driver is now orphaned and superseded by drivers/soc/apple/mailbox.c. Acked-by: Eric Curtin Acked-by: Neal Gompa Acked-by: Alyssa Rosenzweig Signed-off-by: Hector Martin --- MAINTAINERS | 2 - drivers/mailbox/Kconfig | 12 - drivers/mailbox/Makefile | 2 - drivers/mailbox/apple-mailbox.c | 441 -------------------------------- include/linux/apple-mailbox.h | 19 -- 5 files changed, 476 deletions(-) delete mode 100644 drivers/mailbox/apple-mailbox.c delete mode 100644 include/linux/apple-mailbox.h diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..c57c011dbd8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1943,7 +1943,6 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c F: drivers/iommu/apple-dart.c F: drivers/iommu/io-pgtable-dart.c F: drivers/irqchip/irq-apple-aic.c -F: drivers/mailbox/apple-mailbox.c F: drivers/nvme/host/apple.c F: drivers/nvmem/apple-efuses.c F: drivers/pinctrl/pinctrl-apple-gpio.c @@ -1952,7 +1951,6 @@ F: drivers/soc/apple/* F: drivers/watchdog/apple_wdt.c F: include/dt-bindings/interrupt-controller/apple-aic.h F: include/dt-bindings/pinctrl/apple.h -F: include/linux/apple-mailbox.h F: include/linux/soc/apple/* ARM/ARTPEC MACHINE SUPPORT diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index bc2e265cb02d..42940108a187 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -8,18 +8,6 @@ menuconfig MAILBOX if MAILBOX -config APPLE_MAILBOX - tristate "Apple Mailbox driver" - depends on ARCH_APPLE || (ARM64 && COMPILE_TEST) - default ARCH_APPLE - help - Apple SoCs have various co-processors required for certain - peripherals to work (NVMe, display controller, etc.). This - driver adds support for the mailbox controller used to - communicate with those. - - Say Y here if you have a Apple SoC. - config ARM_MHU tristate "ARM MHU Mailbox" depends on ARM_AMBA diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fc9376117111..18793e6caa2f 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -60,5 +60,3 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o - -obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o diff --git a/drivers/mailbox/apple-mailbox.c b/drivers/mailbox/apple-mailbox.c deleted file mode 100644 index 2a3e8d8ff8b5..000000000000 --- a/drivers/mailbox/apple-mailbox.c +++ /dev/null @@ -1,441 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* - * Apple mailbox driver - * - * Copyright (C) 2021 The Asahi Linux Contributors - * - * This driver adds support for two mailbox variants (called ASC and M3 by - * Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to - * exchange 64+32 bit messages between the main CPU and a co-processor. - * Various coprocessors implement different IPC protocols based on these simple - * messages and shared memory buffers. - * - * Both the main CPU and the co-processor see the same set of registers but - * the first FIFO (A2I) is always used to transfer messages from the application - * processor (us) to the I/O processor and the second one (I2A) for the - * other direction. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APPLE_ASC_MBOX_CONTROL_FULL BIT(16) -#define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17) - -#define APPLE_ASC_MBOX_A2I_CONTROL 0x110 -#define APPLE_ASC_MBOX_A2I_SEND0 0x800 -#define APPLE_ASC_MBOX_A2I_SEND1 0x808 -#define APPLE_ASC_MBOX_A2I_RECV0 0x810 -#define APPLE_ASC_MBOX_A2I_RECV1 0x818 - -#define APPLE_ASC_MBOX_I2A_CONTROL 0x114 -#define APPLE_ASC_MBOX_I2A_SEND0 0x820 -#define APPLE_ASC_MBOX_I2A_SEND1 0x828 -#define APPLE_ASC_MBOX_I2A_RECV0 0x830 -#define APPLE_ASC_MBOX_I2A_RECV1 0x838 - -#define APPLE_M3_MBOX_CONTROL_FULL BIT(16) -#define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17) - -#define APPLE_M3_MBOX_A2I_CONTROL 0x50 -#define APPLE_M3_MBOX_A2I_SEND0 0x60 -#define APPLE_M3_MBOX_A2I_SEND1 0x68 -#define APPLE_M3_MBOX_A2I_RECV0 0x70 -#define APPLE_M3_MBOX_A2I_RECV1 0x78 - -#define APPLE_M3_MBOX_I2A_CONTROL 0x80 -#define APPLE_M3_MBOX_I2A_SEND0 0x90 -#define APPLE_M3_MBOX_I2A_SEND1 0x98 -#define APPLE_M3_MBOX_I2A_RECV0 0xa0 -#define APPLE_M3_MBOX_I2A_RECV1 0xa8 - -#define APPLE_M3_MBOX_IRQ_ENABLE 0x48 -#define APPLE_M3_MBOX_IRQ_ACK 0x4c -#define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0) -#define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1) -#define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2) -#define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3) - -#define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52) -#define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48) -#define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44) -#define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40) -#define APPLE_MBOX_MSG1_MSG GENMASK(31, 0) - -struct apple_mbox_hw { - unsigned int control_full; - unsigned int control_empty; - - unsigned int a2i_control; - unsigned int a2i_send0; - unsigned int a2i_send1; - - unsigned int i2a_control; - unsigned int i2a_recv0; - unsigned int i2a_recv1; - - bool has_irq_controls; - unsigned int irq_enable; - unsigned int irq_ack; - unsigned int irq_bit_recv_not_empty; - unsigned int irq_bit_send_empty; -}; - -struct apple_mbox { - void __iomem *regs; - const struct apple_mbox_hw *hw; - - int irq_recv_not_empty; - int irq_send_empty; - - struct mbox_chan chan; - - struct device *dev; - struct mbox_controller controller; - spinlock_t rx_lock; -}; - -static const struct of_device_id apple_mbox_of_match[]; - -static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox) -{ - u32 mbox_ctrl = - readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control); - - return !(mbox_ctrl & apple_mbox->hw->control_full); -} - -static bool apple_mbox_hw_send_empty(struct apple_mbox *apple_mbox) -{ - u32 mbox_ctrl = - readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control); - - return mbox_ctrl & apple_mbox->hw->control_empty; -} - -static int apple_mbox_hw_send(struct apple_mbox *apple_mbox, - struct apple_mbox_msg *msg) -{ - if (!apple_mbox_hw_can_send(apple_mbox)) - return -EBUSY; - - dev_dbg(apple_mbox->dev, "> TX %016llx %08x\n", msg->msg0, msg->msg1); - - writeq_relaxed(msg->msg0, apple_mbox->regs + apple_mbox->hw->a2i_send0); - writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg->msg1), - apple_mbox->regs + apple_mbox->hw->a2i_send1); - - return 0; -} - -static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox) -{ - u32 mbox_ctrl = - readl_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_control); - - return !(mbox_ctrl & apple_mbox->hw->control_empty); -} - -static int apple_mbox_hw_recv(struct apple_mbox *apple_mbox, - struct apple_mbox_msg *msg) -{ - if (!apple_mbox_hw_can_recv(apple_mbox)) - return -ENOMSG; - - msg->msg0 = readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv0); - msg->msg1 = FIELD_GET( - APPLE_MBOX_MSG1_MSG, - readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv1)); - - dev_dbg(apple_mbox->dev, "< RX %016llx %08x\n", msg->msg0, msg->msg1); - - return 0; -} - -static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data) -{ - struct apple_mbox *apple_mbox = chan->con_priv; - struct apple_mbox_msg *msg = data; - int ret; - - ret = apple_mbox_hw_send(apple_mbox, msg); - if (ret) - return ret; - - /* - * The interrupt is level triggered and will keep firing as long as the - * FIFO is empty. It will also keep firing if the FIFO was empty - * at any point in the past until it has been acknowledged at the - * mailbox level. By acknowledging it here we can ensure that we will - * only get the interrupt once the FIFO has been cleared again. - * If the FIFO is already empty before the ack it will fire again - * immediately after the ack. - */ - if (apple_mbox->hw->has_irq_controls) { - writel_relaxed(apple_mbox->hw->irq_bit_send_empty, - apple_mbox->regs + apple_mbox->hw->irq_ack); - } - enable_irq(apple_mbox->irq_send_empty); - - return 0; -} - -static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) -{ - struct apple_mbox *apple_mbox = data; - - /* - * We don't need to acknowledge the interrupt at the mailbox level - * here even if supported by the hardware. It will keep firing but that - * doesn't matter since it's disabled at the main interrupt controller. - * apple_mbox_chan_send_data will acknowledge it before enabling - * it at the main controller again. - */ - disable_irq_nosync(apple_mbox->irq_send_empty); - mbox_chan_txdone(&apple_mbox->chan, 0); - return IRQ_HANDLED; -} - -static int apple_mbox_poll(struct apple_mbox *apple_mbox) -{ - struct apple_mbox_msg msg; - int ret = 0; - - while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) { - mbox_chan_received_data(&apple_mbox->chan, (void *)&msg); - ret++; - } - - /* - * The interrupt will keep firing even if there are no more messages - * unless we also acknowledge it at the mailbox level here. - * There's no race if a message comes in between the check in the while - * loop above and the ack below: If a new messages arrives inbetween - * those two the interrupt will just fire again immediately after the - * ack since it's level triggered. - */ - if (apple_mbox->hw->has_irq_controls) { - writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty, - apple_mbox->regs + apple_mbox->hw->irq_ack); - } - - return ret; -} - -static irqreturn_t apple_mbox_recv_irq(int irq, void *data) -{ - struct apple_mbox *apple_mbox = data; - - spin_lock(&apple_mbox->rx_lock); - apple_mbox_poll(apple_mbox); - spin_unlock(&apple_mbox->rx_lock); - - return IRQ_HANDLED; -} - -static bool apple_mbox_chan_peek_data(struct mbox_chan *chan) -{ - struct apple_mbox *apple_mbox = chan->con_priv; - unsigned long flags; - int ret; - - spin_lock_irqsave(&apple_mbox->rx_lock, flags); - ret = apple_mbox_poll(apple_mbox); - spin_unlock_irqrestore(&apple_mbox->rx_lock, flags); - - return ret > 0; -} - -static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout) -{ - struct apple_mbox *apple_mbox = chan->con_priv; - unsigned long deadline = jiffies + msecs_to_jiffies(timeout); - - while (time_before(jiffies, deadline)) { - if (apple_mbox_hw_send_empty(apple_mbox)) { - mbox_chan_txdone(&apple_mbox->chan, 0); - return 0; - } - - udelay(1); - } - - return -ETIME; -} - -static int apple_mbox_chan_startup(struct mbox_chan *chan) -{ - struct apple_mbox *apple_mbox = chan->con_priv; - - /* - * Only some variants of this mailbox HW provide interrupt control - * at the mailbox level. We therefore need to handle enabling/disabling - * interrupts at the main interrupt controller anyway for hardware that - * doesn't. Just always keep the interrupts we care about enabled at - * the mailbox level so that both hardware revisions behave almost - * the same. - */ - if (apple_mbox->hw->has_irq_controls) { - writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty | - apple_mbox->hw->irq_bit_send_empty, - apple_mbox->regs + apple_mbox->hw->irq_enable); - } - - enable_irq(apple_mbox->irq_recv_not_empty); - return 0; -} - -static void apple_mbox_chan_shutdown(struct mbox_chan *chan) -{ - struct apple_mbox *apple_mbox = chan->con_priv; - - disable_irq(apple_mbox->irq_recv_not_empty); -} - -static const struct mbox_chan_ops apple_mbox_ops = { - .send_data = apple_mbox_chan_send_data, - .peek_data = apple_mbox_chan_peek_data, - .flush = apple_mbox_chan_flush, - .startup = apple_mbox_chan_startup, - .shutdown = apple_mbox_chan_shutdown, -}; - -static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox, - const struct of_phandle_args *args) -{ - if (args->args_count != 0) - return ERR_PTR(-EINVAL); - - return &mbox->chans[0]; -} - -static int apple_mbox_probe(struct platform_device *pdev) -{ - int ret; - const struct of_device_id *match; - char *irqname; - struct apple_mbox *mbox; - struct device *dev = &pdev->dev; - - match = of_match_node(apple_mbox_of_match, pdev->dev.of_node); - if (!match) - return -EINVAL; - if (!match->data) - return -EINVAL; - - mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); - if (!mbox) - return -ENOMEM; - platform_set_drvdata(pdev, mbox); - - mbox->dev = dev; - mbox->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mbox->regs)) - return PTR_ERR(mbox->regs); - - mbox->hw = match->data; - mbox->irq_recv_not_empty = - platform_get_irq_byname(pdev, "recv-not-empty"); - if (mbox->irq_recv_not_empty < 0) - return -ENODEV; - - mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty"); - if (mbox->irq_send_empty < 0) - return -ENODEV; - - mbox->controller.dev = mbox->dev; - mbox->controller.num_chans = 1; - mbox->controller.chans = &mbox->chan; - mbox->controller.ops = &apple_mbox_ops; - mbox->controller.txdone_irq = true; - mbox->controller.of_xlate = apple_mbox_of_xlate; - mbox->chan.con_priv = mbox; - spin_lock_init(&mbox->rx_lock); - - irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev)); - if (!irqname) - return -ENOMEM; - - ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL, - apple_mbox_recv_irq, - IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname, - mbox); - if (ret) - return ret; - - irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev)); - if (!irqname) - return -ENOMEM; - - ret = devm_request_irq(dev, mbox->irq_send_empty, - apple_mbox_send_empty_irq, IRQF_NO_AUTOEN, - irqname, mbox); - if (ret) - return ret; - - return devm_mbox_controller_register(dev, &mbox->controller); -} - -static const struct apple_mbox_hw apple_mbox_asc_hw = { - .control_full = APPLE_ASC_MBOX_CONTROL_FULL, - .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY, - - .a2i_control = APPLE_ASC_MBOX_A2I_CONTROL, - .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0, - .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1, - - .i2a_control = APPLE_ASC_MBOX_I2A_CONTROL, - .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0, - .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1, - - .has_irq_controls = false, -}; - -static const struct apple_mbox_hw apple_mbox_m3_hw = { - .control_full = APPLE_M3_MBOX_CONTROL_FULL, - .control_empty = APPLE_M3_MBOX_CONTROL_EMPTY, - - .a2i_control = APPLE_M3_MBOX_A2I_CONTROL, - .a2i_send0 = APPLE_M3_MBOX_A2I_SEND0, - .a2i_send1 = APPLE_M3_MBOX_A2I_SEND1, - - .i2a_control = APPLE_M3_MBOX_I2A_CONTROL, - .i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0, - .i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1, - - .has_irq_controls = true, - .irq_enable = APPLE_M3_MBOX_IRQ_ENABLE, - .irq_ack = APPLE_M3_MBOX_IRQ_ACK, - .irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY, - .irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY, -}; - -static const struct of_device_id apple_mbox_of_match[] = { - { .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw }, - { .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw }, - {} -}; -MODULE_DEVICE_TABLE(of, apple_mbox_of_match); - -static struct platform_driver apple_mbox_driver = { - .driver = { - .name = "apple-mailbox", - .of_match_table = apple_mbox_of_match, - }, - .probe = apple_mbox_probe, -}; -module_platform_driver(apple_mbox_driver); - -MODULE_LICENSE("Dual MIT/GPL"); -MODULE_AUTHOR("Sven Peter "); -MODULE_DESCRIPTION("Apple Mailbox driver"); diff --git a/include/linux/apple-mailbox.h b/include/linux/apple-mailbox.h deleted file mode 100644 index 720fbb70294a..000000000000 --- a/include/linux/apple-mailbox.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ -/* - * Apple mailbox message format - * - * Copyright (C) 2021 The Asahi Linux Contributors - */ - -#ifndef _LINUX_APPLE_MAILBOX_H_ -#define _LINUX_APPLE_MAILBOX_H_ - -#include - -/* encodes a single 96bit message sent over the single channel */ -struct apple_mbox_msg { - u64 msg0; - u32 msg1; -}; - -#endif From c84292d9d253706267889cf2614400712f15d689 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 28 Mar 2023 20:38:26 +0900 Subject: [PATCH 1202/7721] soc: apple: mailbox: Rename config symbol to APPLE_MAILBOX With the original owner of APPLE_MAILBOX removed, let's rename the new APPLE_MBOX to the old name. This avoids .config churn for downstream users, and leaves us with an identical config symbol and module name as before. Acked-by: Eric Curtin Acked-by: Neal Gompa Acked-by: Alyssa Rosenzweig Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 5 ++--- drivers/soc/apple/Makefile | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index 24309e40fbbe..6388cbe1e56b 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -4,11 +4,10 @@ if ARCH_APPLE || COMPILE_TEST menu "Apple SoC drivers" -config APPLE_MBOX +config APPLE_MAILBOX tristate "Apple SoC mailboxes" depends on PM depends on ARCH_APPLE || (64BIT && COMPILE_TEST) - depends on !APPLE_MAILBOX default ARCH_APPLE help Apple SoCs have various co-processors required for certain @@ -20,7 +19,7 @@ config APPLE_MBOX config APPLE_RTKIT tristate "Apple RTKit co-processor IPC protocol" - depends on APPLE_MBOX + depends on APPLE_MAILBOX depends on ARCH_APPLE || COMPILE_TEST default ARCH_APPLE help diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 2a7835eda070..4d9ab8f3037b 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_APPLE_MBOX) += apple-mailbox.o +obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o apple-mailbox-y = mailbox.o obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o From 4dae8c047a70307d83d912afbda2e2c94de155b6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 30 Oct 2023 09:26:21 -0500 Subject: [PATCH 1203/7721] soc: apple: mailbox: Add explicit include of platform_device.h The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other and pull in various other headers. In preparation to fix this, adjust the includes for what is actually needed. platform_device.h is implicitly included by of_platform.h, but that's going to be removed. Signed-off-by: Rob Herring Reviewed-by: Neal Gompa Signed-off-by: Hector Martin --- drivers/soc/apple/mailbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c index 0cbd172f435e..780199bf351e 100644 --- a/drivers/soc/apple/mailbox.c +++ b/drivers/soc/apple/mailbox.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include From 07cb30216d31bee8e4250549ebb4086ba5951887 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:13 +0100 Subject: [PATCH 1204/7721] media: videobuf2: Rename offset parameter Rename 'off' parameter to 'offset' to clarify the code. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 27aee92f3eea..e5fd7ff0dae6 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -356,23 +356,23 @@ static void __setup_offsets(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; unsigned int plane; - unsigned long off = 0; + unsigned long offset = 0; if (vb->index) { struct vb2_buffer *prev = q->bufs[vb->index - 1]; struct vb2_plane *p = &prev->planes[prev->num_planes - 1]; - off = PAGE_ALIGN(p->m.offset + p->length); + offset = PAGE_ALIGN(p->m.offset + p->length); } for (plane = 0; plane < vb->num_planes; ++plane) { - vb->planes[plane].m.offset = off; + vb->planes[plane].m.offset = offset; dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n", - vb->index, plane, off); + vb->index, plane, offset); - off += vb->planes[plane].length; - off = PAGE_ALIGN(off); + offset += vb->planes[plane].length; + offset = PAGE_ALIGN(offset); } } @@ -2185,10 +2185,10 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type) EXPORT_SYMBOL_GPL(vb2_core_streamoff); /* - * __find_plane_by_offset() - find plane associated with the given offset off + * __find_plane_by_offset() - find plane associated with the given offset */ -static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, - unsigned int *_buffer, unsigned int *_plane) +static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset, + unsigned int *_buffer, unsigned int *_plane) { struct vb2_buffer *vb; unsigned int buffer, plane; @@ -2218,7 +2218,7 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, vb = q->bufs[buffer]; for (plane = 0; plane < vb->num_planes; ++plane) { - if (vb->planes[plane].m.offset == off) { + if (vb->planes[plane].m.offset == offset) { *_buffer = buffer; *_plane = plane; return 0; @@ -2304,7 +2304,7 @@ EXPORT_SYMBOL_GPL(vb2_core_expbuf); int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) { - unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct vb2_buffer *vb; unsigned int buffer = 0, plane = 0; int ret; @@ -2335,7 +2335,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) * Find the plane corresponding to the offset passed by userspace. This * will return an error if not MEMORY_MMAP or file I/O is in progress. */ - ret = __find_plane_by_offset(q, off, &buffer, &plane); + ret = __find_plane_by_offset(q, offset, &buffer, &plane); if (ret) goto unlock; @@ -2380,7 +2380,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, unsigned long pgoff, unsigned long flags) { - unsigned long off = pgoff << PAGE_SHIFT; + unsigned long offset = pgoff << PAGE_SHIFT; struct vb2_buffer *vb; unsigned int buffer, plane; void *vaddr; @@ -2392,7 +2392,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, * Find the plane corresponding to the offset passed by userspace. This * will return an error if not MEMORY_MMAP or file I/O is in progress. */ - ret = __find_plane_by_offset(q, off, &buffer, &plane); + ret = __find_plane_by_offset(q, offset, &buffer, &plane); if (ret) goto unlock; From 64bac5ea17d527872121adddfee869c7a0618f8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Nov 2023 13:58:29 +0100 Subject: [PATCH 1205/7721] arch: consolidate arch_irq_work_raise prototypes The prototype was hidden in an #ifdef on x86, which causes a warning: kernel/irq_work.c:72:13: error: no previous prototype for 'arch_irq_work_raise' [-Werror=missing-prototypes] Some architectures have a working prototype, while others don't. Fix this by providing it in only one place that is always visible. Reviewed-by: Alexander Gordeev Acked-by: Catalin Marinas Acked-by: Palmer Dabbelt Acked-by: Guo Ren Signed-off-by: Arnd Bergmann --- arch/arm/include/asm/irq_work.h | 2 -- arch/arm64/include/asm/irq_work.h | 2 -- arch/csky/include/asm/irq_work.h | 2 +- arch/powerpc/include/asm/irq_work.h | 1 - arch/riscv/include/asm/irq_work.h | 2 +- arch/s390/include/asm/irq_work.h | 2 -- arch/x86/include/asm/irq_work.h | 1 - include/linux/irq_work.h | 3 +++ 8 files changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h index 3149e4dc1b54..8895999834cc 100644 --- a/arch/arm/include/asm/irq_work.h +++ b/arch/arm/include/asm/irq_work.h @@ -9,6 +9,4 @@ static inline bool arch_irq_work_has_interrupt(void) return is_smp(); } -extern void arch_irq_work_raise(void); - #endif /* _ASM_ARM_IRQ_WORK_H */ diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index 81bbfa3a035b..a1020285ea75 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h @@ -2,8 +2,6 @@ #ifndef __ASM_IRQ_WORK_H #define __ASM_IRQ_WORK_H -extern void arch_irq_work_raise(void); - static inline bool arch_irq_work_has_interrupt(void) { return true; diff --git a/arch/csky/include/asm/irq_work.h b/arch/csky/include/asm/irq_work.h index 33aaf39d6f94..d39fcc1f5395 100644 --- a/arch/csky/include/asm/irq_work.h +++ b/arch/csky/include/asm/irq_work.h @@ -7,5 +7,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } -extern void arch_irq_work_raise(void); + #endif /* __ASM_CSKY_IRQ_WORK_H */ diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h index b8b0be8f1a07..c6d3078bd8c3 100644 --- a/arch/powerpc/include/asm/irq_work.h +++ b/arch/powerpc/include/asm/irq_work.h @@ -6,6 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } -extern void arch_irq_work_raise(void); #endif /* _ASM_POWERPC_IRQ_WORK_H */ diff --git a/arch/riscv/include/asm/irq_work.h b/arch/riscv/include/asm/irq_work.h index b53891964ae0..b27a4d64fc6a 100644 --- a/arch/riscv/include/asm/irq_work.h +++ b/arch/riscv/include/asm/irq_work.h @@ -6,5 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return IS_ENABLED(CONFIG_SMP); } -extern void arch_irq_work_raise(void); + #endif /* _ASM_RISCV_IRQ_WORK_H */ diff --git a/arch/s390/include/asm/irq_work.h b/arch/s390/include/asm/irq_work.h index 603783766d0a..f00c9f610d5a 100644 --- a/arch/s390/include/asm/irq_work.h +++ b/arch/s390/include/asm/irq_work.h @@ -7,6 +7,4 @@ static inline bool arch_irq_work_has_interrupt(void) return true; } -void arch_irq_work_raise(void); - #endif /* _ASM_S390_IRQ_WORK_H */ diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h index 800ffce0db29..6b4d36c95165 100644 --- a/arch/x86/include/asm/irq_work.h +++ b/arch/x86/include/asm/irq_work.h @@ -9,7 +9,6 @@ static inline bool arch_irq_work_has_interrupt(void) { return boot_cpu_has(X86_FEATURE_APIC); } -extern void arch_irq_work_raise(void); #else static inline bool arch_irq_work_has_interrupt(void) { diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h index 8cd11a223260..136f2980cba3 100644 --- a/include/linux/irq_work.h +++ b/include/linux/irq_work.h @@ -66,6 +66,9 @@ void irq_work_sync(struct irq_work *work); void irq_work_run(void); bool irq_work_needs_cpu(void); void irq_work_single(void *arg); + +void arch_irq_work_raise(void); + #else static inline bool irq_work_needs_cpu(void) { return false; } static inline void irq_work_run(void) { } From 4d86896793dd6eeacdf32b85af1ef130349db4be Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Nov 2023 13:58:30 +0100 Subject: [PATCH 1206/7721] arch: fix asm-offsets.c building with -Wmissing-prototypes When -Wmissing-prototypes is enabled, the some asm-offsets.c files fail to build, even when this warning is disabled in the Makefile for normal files: arch/sparc/kernel/asm-offsets.c:22:5: error: no previous prototype for 'sparc32_foo' [-Werror=missing-prototypes] arch/sparc/kernel/asm-offsets.c:48:5: error: no previous prototype for 'foo' [-Werror=missing-prototypes] Address this by making use of the same trick as x86, marking these functions as 'static __used' to avoid the need for a prototype by not drop them in dead-code elimination. Suggested-by: Masahiro Yamada Reviewed-by: Sam Ravnborg Link: https://lore.kernel.org/lkml/CAK7LNARfEmFk0Du4Hed19eX_G6tUC5wG0zP+L1AyvdpOF4ybXQ@mail.gmail.com/ Signed-off-by: Arnd Bergmann --- arch/alpha/kernel/asm-offsets.c | 2 +- arch/loongarch/kernel/asm-offsets.c | 26 +++++++++++++------------- arch/sparc/kernel/asm-offsets.c | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index b121294bee26..bf1eedd27cf7 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c @@ -12,7 +12,7 @@ #include #include -void foo(void) +static void __used foo(void) { DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c index 173fe514fc9e..bee9f7a3108f 100644 --- a/arch/loongarch/kernel/asm-offsets.c +++ b/arch/loongarch/kernel/asm-offsets.c @@ -15,7 +15,7 @@ #include #include -void output_ptreg_defines(void) +static void __used output_ptreg_defines(void) { COMMENT("LoongArch pt_regs offsets."); OFFSET(PT_R0, pt_regs, regs[0]); @@ -62,7 +62,7 @@ void output_ptreg_defines(void) BLANK(); } -void output_task_defines(void) +static void __used output_task_defines(void) { COMMENT("LoongArch task_struct offsets."); OFFSET(TASK_STATE, task_struct, __state); @@ -77,7 +77,7 @@ void output_task_defines(void) BLANK(); } -void output_thread_info_defines(void) +static void __used output_thread_info_defines(void) { COMMENT("LoongArch thread_info offsets."); OFFSET(TI_TASK, thread_info, task); @@ -93,7 +93,7 @@ void output_thread_info_defines(void) BLANK(); } -void output_thread_defines(void) +static void __used output_thread_defines(void) { COMMENT("LoongArch specific thread_struct offsets."); OFFSET(THREAD_REG01, task_struct, thread.reg01); @@ -129,7 +129,7 @@ void output_thread_defines(void) BLANK(); } -void output_thread_fpu_defines(void) +static void __used output_thread_fpu_defines(void) { OFFSET(THREAD_FPR0, loongarch_fpu, fpr[0]); OFFSET(THREAD_FPR1, loongarch_fpu, fpr[1]); @@ -170,7 +170,7 @@ void output_thread_fpu_defines(void) BLANK(); } -void output_thread_lbt_defines(void) +static void __used output_thread_lbt_defines(void) { OFFSET(THREAD_SCR0, loongarch_lbt, scr0); OFFSET(THREAD_SCR1, loongarch_lbt, scr1); @@ -180,7 +180,7 @@ void output_thread_lbt_defines(void) BLANK(); } -void output_mm_defines(void) +static void __used output_mm_defines(void) { COMMENT("Size of struct page"); DEFINE(STRUCT_PAGE_SIZE, sizeof(struct page)); @@ -212,7 +212,7 @@ void output_mm_defines(void) BLANK(); } -void output_sc_defines(void) +static void __used output_sc_defines(void) { COMMENT("Linux sigcontext offsets."); OFFSET(SC_REGS, sigcontext, sc_regs); @@ -220,7 +220,7 @@ void output_sc_defines(void) BLANK(); } -void output_signal_defines(void) +static void __used output_signal_defines(void) { COMMENT("Linux signal numbers."); DEFINE(_SIGHUP, SIGHUP); @@ -258,7 +258,7 @@ void output_signal_defines(void) } #ifdef CONFIG_SMP -void output_smpboot_defines(void) +static void __used output_smpboot_defines(void) { COMMENT("Linux smp cpu boot offsets."); OFFSET(CPU_BOOT_STACK, secondary_data, stack); @@ -268,7 +268,7 @@ void output_smpboot_defines(void) #endif #ifdef CONFIG_HIBERNATION -void output_pbe_defines(void) +static void __used output_pbe_defines(void) { COMMENT("Linux struct pbe offsets."); OFFSET(PBE_ADDRESS, pbe, address); @@ -280,7 +280,7 @@ void output_pbe_defines(void) #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER -void output_fgraph_ret_regs_defines(void) +static void __used output_fgraph_ret_regs_defines(void) { COMMENT("LoongArch fgraph_ret_regs offsets."); OFFSET(FGRET_REGS_A0, fgraph_ret_regs, regs[0]); @@ -291,7 +291,7 @@ void output_fgraph_ret_regs_defines(void) } #endif -void output_kvm_defines(void) +static void __used output_kvm_defines(void) { COMMENT("KVM/LoongArch Specific offsets."); diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c index 5784f2df489a..3d9b9855dce9 100644 --- a/arch/sparc/kernel/asm-offsets.c +++ b/arch/sparc/kernel/asm-offsets.c @@ -19,14 +19,14 @@ #include #ifdef CONFIG_SPARC32 -int sparc32_foo(void) +static int __used sparc32_foo(void) { DEFINE(AOFF_thread_fork_kpsr, offsetof(struct thread_struct, fork_kpsr)); return 0; } #else -int sparc64_foo(void) +static int __used sparc64_foo(void) { #ifdef CONFIG_HIBERNATION BLANK(); @@ -45,7 +45,7 @@ int sparc64_foo(void) } #endif -int foo(void) +static int __used foo(void) { BLANK(); DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread)); From f717a8d1643d6515c7179cf32408f7d5a0e2e33b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Nov 2023 10:44:55 +0100 Subject: [PATCH 1207/7721] arch: include linux/cpu.h for trap_init() prototype some architectures run into a -Wmissing-prototypes warning for trap_init() arch/microblaze/kernel/traps.c:21:6: warning: no previous prototype for 'trap_init' [-Wmissing-prototypes] Include the right header to avoid this consistently, removing the extra declarations on m68k and x86 that were added as local workarounds already. Signed-off-by: Arnd Bergmann --- arch/alpha/kernel/traps.c | 1 + arch/csky/include/asm/traps.h | 2 -- arch/csky/kernel/traps.c | 1 + arch/m68k/coldfire/vectors.c | 3 +-- arch/m68k/coldfire/vectors.h | 3 --- arch/microblaze/kernel/traps.c | 1 + arch/sparc/kernel/traps_32.c | 1 + arch/sparc/kernel/traps_64.c | 1 + arch/x86/include/asm/traps.h | 1 - arch/x86/kernel/traps.c | 1 + 10 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 arch/m68k/coldfire/vectors.h diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index d9a67b370e04..7fc72aeb7398 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -9,6 +9,7 @@ * This file initializes the trap entry points */ +#include #include #include #include diff --git a/arch/csky/include/asm/traps.h b/arch/csky/include/asm/traps.h index 732c4aaa2e26..495ce318d569 100644 --- a/arch/csky/include/asm/traps.h +++ b/arch/csky/include/asm/traps.h @@ -55,6 +55,4 @@ asmlinkage void trap_c(struct pt_regs *regs); asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); -void trap_init(void); - #endif /* __ASM_CSKY_TRAPS_H */ diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c index 6e426fba0119..c2246b07cc9c 100644 --- a/arch/csky/kernel/traps.c +++ b/arch/csky/kernel/traps.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. +#include #include #include #include diff --git a/arch/m68k/coldfire/vectors.c b/arch/m68k/coldfire/vectors.c index c26c255b530d..4321fd89d83e 100644 --- a/arch/m68k/coldfire/vectors.c +++ b/arch/m68k/coldfire/vectors.c @@ -12,14 +12,13 @@ #include #include #include +#include #include #include #include #include #include -#include "vectors.h" - /***************************************************************************/ #ifdef TRAP_DBG_INTERRUPT diff --git a/arch/m68k/coldfire/vectors.h b/arch/m68k/coldfire/vectors.h deleted file mode 100644 index 0b01450a4353..000000000000 --- a/arch/m68k/coldfire/vectors.h +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -void trap_init(void); diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index 94b6fe93147d..080aa769218d 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index 179aabfa712e..bb149f6cc34b 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -10,6 +10,7 @@ * I hate traps on the sparc, grrr... */ +#include #include #include #include diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 08ffd17d5ec3..3631899f2394 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -9,6 +9,7 @@ * I like traps on v9, :)))) */ +#include #include #include #include diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index b1c9cea6ba88..1f1deaecd364 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -14,7 +14,6 @@ asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs); asmlinkage __visible notrace struct pt_regs *fixup_bad_iret(struct pt_regs *bad_regs); -void __init trap_init(void); asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *eregs); #endif diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index c876f1d36a81..b0737a15c470 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include From 42874e4eb35bdfc54f8514685e50434098ba4f6c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Nov 2023 13:58:36 +0100 Subject: [PATCH 1208/7721] arch: vdso: consolidate gettime prototypes The VDSO functions are defined as globals in the kernel sources but intended to be called from userspace, so there is no need to declare them in a kernel side header. Without a prototype, this now causes warnings such as arch/mips/vdso/vgettimeofday.c:14:5: error: no previous prototype for '__vdso_clock_gettime' [-Werror=missing-prototypes] arch/mips/vdso/vgettimeofday.c:28:5: error: no previous prototype for '__vdso_gettimeofday' [-Werror=missing-prototypes] arch/mips/vdso/vgettimeofday.c:36:5: error: no previous prototype for '__vdso_clock_getres' [-Werror=missing-prototypes] arch/mips/vdso/vgettimeofday.c:42:5: error: no previous prototype for '__vdso_clock_gettime64' [-Werror=missing-prototypes] arch/sparc/vdso/vclock_gettime.c:254:1: error: no previous prototype for '__vdso_clock_gettime' [-Werror=missing-prototypes] arch/sparc/vdso/vclock_gettime.c:282:1: error: no previous prototype for '__vdso_clock_gettime_stick' [-Werror=missing-prototypes] arch/sparc/vdso/vclock_gettime.c:307:1: error: no previous prototype for '__vdso_gettimeofday' [-Werror=missing-prototypes] arch/sparc/vdso/vclock_gettime.c:343:1: error: no previous prototype for '__vdso_gettimeofday_stick' [-Werror=missing-prototypes] Most architectures have already added workarounds for these by adding declarations somewhere, but since these are all compatible, we should really just have one copy, with an #ifdef check for the 32-bit vs 64-bit variant and use that everywhere. Unfortunately, the sparc an um versions are currently incompatible since they never added support for __vdso_clock_gettime64() in 32-bit userland. For the moment, I'm leaving this one out, as I can't easily test it and it requires a larger rework. Reviewed-by: Vincenzo Frascino Signed-off-by: Arnd Bergmann --- arch/arm/include/asm/vdso.h | 5 ----- arch/arm/vdso/vgettimeofday.c | 1 + arch/arm64/kernel/vdso32/vgettimeofday.c | 1 + arch/csky/kernel/vdso/vgettimeofday.c | 11 +---------- arch/loongarch/vdso/vgettimeofday.c | 7 +------ arch/mips/vdso/vgettimeofday.c | 1 + arch/riscv/kernel/vdso/vgettimeofday.c | 7 +------ arch/x86/entry/vdso/vclock_gettime.c | 10 +--------- arch/x86/include/asm/vdso/gettimeofday.h | 2 -- include/vdso/gettime.h | 23 +++++++++++++++++++++++ 10 files changed, 30 insertions(+), 38 deletions(-) create mode 100644 include/vdso/gettime.h diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h index 422c3afa806a..5b85889f82ee 100644 --- a/arch/arm/include/asm/vdso.h +++ b/arch/arm/include/asm/vdso.h @@ -24,11 +24,6 @@ static inline void arm_install_vdso(struct mm_struct *mm, unsigned long addr) #endif /* CONFIG_VDSO */ -int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); -int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); -int __vdso_clock_getres(clockid_t clock_id, struct old_timespec32 *res); - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index a003beacac76..3554aa35f1ba 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -8,6 +8,7 @@ #include #include #include +#include int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index 5acff29c5991..e23c7f4ef26b 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 ARM Limited * */ +#include int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) diff --git a/arch/csky/kernel/vdso/vgettimeofday.c b/arch/csky/kernel/vdso/vgettimeofday.c index c4831145eed5..55af30e83752 100644 --- a/arch/csky/kernel/vdso/vgettimeofday.c +++ b/arch/csky/kernel/vdso/vgettimeofday.c @@ -2,36 +2,27 @@ #include #include +#include extern -int __vdso_clock_gettime(clockid_t clock, - struct old_timespec32 *ts); int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { return __cvdso_clock_gettime32(clock, ts); } -int __vdso_clock_gettime64(clockid_t clock, - struct __kernel_timespec *ts); int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, - struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, - struct old_timespec32 *res); int __vdso_clock_getres(clockid_t clock_id, struct old_timespec32 *res) { diff --git a/arch/loongarch/vdso/vgettimeofday.c b/arch/loongarch/vdso/vgettimeofday.c index 8f22863bd7ea..0885c1f3a89d 100644 --- a/arch/loongarch/vdso/vgettimeofday.c +++ b/arch/loongarch/vdso/vgettimeofday.c @@ -5,23 +5,18 @@ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ #include +#include -extern -int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res); int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res) { return __cvdso_clock_getres(clock_id, res); diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c index 6b83b6376a4b..604afea3f336 100644 --- a/arch/mips/vdso/vgettimeofday.c +++ b/arch/mips/vdso/vgettimeofday.c @@ -9,6 +9,7 @@ */ #include #include +#include #if _MIPS_SIM != _MIPS_SIM_ABI64 int __vdso_clock_gettime(clockid_t clock, diff --git a/arch/riscv/kernel/vdso/vgettimeofday.c b/arch/riscv/kernel/vdso/vgettimeofday.c index cc0d80699c31..b35057802584 100644 --- a/arch/riscv/kernel/vdso/vgettimeofday.c +++ b/arch/riscv/kernel/vdso/vgettimeofday.c @@ -8,23 +8,18 @@ #include #include +#include -extern -int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res); int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res) { return __cvdso_clock_getres(clock_id, res); diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 7d70935b6758..0debc194bd78 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -11,12 +11,10 @@ #include #include #include +#include #include "../../../../lib/vdso/gettimeofday.c" -extern int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); -extern __kernel_old_time_t __vdso_time(__kernel_old_time_t *t); - int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); @@ -35,9 +33,6 @@ __kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__v #if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64) /* both 64-bit and x32 use these */ -extern int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); -extern int __vdso_clock_getres(clockid_t clock, struct __kernel_timespec *res); - int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); @@ -56,9 +51,6 @@ int clock_getres(clockid_t, struct __kernel_timespec *) #else /* i386 only */ -extern int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); -extern int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res); - int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { return __cvdso_clock_gettime32(clock, ts); diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index c81858d903dc..a46edb0e0cf7 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -337,8 +337,6 @@ u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) } #define vdso_calc_delta vdso_calc_delta -int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); - #endif /* !__ASSEMBLY__ */ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/include/vdso/gettime.h b/include/vdso/gettime.h new file mode 100644 index 000000000000..c50d152e7b3e --- /dev/null +++ b/include/vdso/gettime.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _VDSO_GETTIME_H +#define _VDSO_GETTIME_H + +#include + +struct __kernel_timespec; +struct timezone; + +#if !defined(CONFIG_64BIT) || defined(BUILD_VDSO32_64) +struct old_timespec32; +int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res); +int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); +#else +int __vdso_clock_getres(clockid_t clock, struct __kernel_timespec *res); +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); +#endif + +__kernel_old_time_t __vdso_time(__kernel_old_time_t *t); +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); +int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); + +#endif From 1d6571a8794ba276a078a8ca9d84ccc157f8b6c3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Aug 2023 12:07:56 +0200 Subject: [PATCH 1209/7721] arch: add missing prepare_ftrace_return() prototypes The prototype for prepare_ftrace_return() is architecture specific and can't be in a global header. Since it's normally called from assembly, it doesn't really need a prototype, but we get a warning if it's missing: arch/csky/kernel/ftrace.c:147:6: error: no previous prototype for 'prepare_ftrace_return' [-Werror=missing-prototypes] arch/microblaze/kernel/ftrace.c:22:6: error: no previous prototype for 'prepare_ftrace_return' [-Werror=missing-prototypes] arch/mips/kernel/ftrace.c:305:6: error: no previous prototype for 'prepare_ftrace_return' [-Werror=missing-prototypes] Add the prototypes for the three architectures that don't already have one in asm/ftrace.h. Signed-off-by: Arnd Bergmann --- arch/csky/include/asm/ftrace.h | 4 ++++ arch/microblaze/include/asm/ftrace.h | 1 + arch/mips/include/asm/ftrace.h | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h index 9b86341731b6..fd215c38ef27 100644 --- a/arch/csky/include/asm/ftrace.h +++ b/arch/csky/include/asm/ftrace.h @@ -26,5 +26,9 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) struct dyn_arch_ftrace { }; + +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer); + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_CSKY_FTRACE_H */ diff --git a/arch/microblaze/include/asm/ftrace.h b/arch/microblaze/include/asm/ftrace.h index 6a92bed37794..4ca38b92a3a2 100644 --- a/arch/microblaze/include/asm/ftrace.h +++ b/arch/microblaze/include/asm/ftrace.h @@ -10,6 +10,7 @@ #ifndef __ASSEMBLY__ extern void _mcount(void); extern void ftrace_call_graph(void); +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr); #endif #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h index db497a8167da..dc025888f6d2 100644 --- a/arch/mips/include/asm/ftrace.h +++ b/arch/mips/include/asm/ftrace.h @@ -85,6 +85,10 @@ struct dyn_arch_ftrace { }; #endif /* CONFIG_DYNAMIC_FTRACE */ + +void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, + unsigned long fp); + #endif /* __ASSEMBLY__ */ #endif /* CONFIG_FUNCTION_TRACER */ #endif /* _ASM_MIPS_FTRACE_H */ From 23f8c1823bd4041064ab557283dbb37657549c5b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Nov 2023 12:20:13 +0100 Subject: [PATCH 1210/7721] arch: add do_page_fault prototypes do_page_fault() is missing a declaration on a couple of architectures: arch/alpha/mm/fault.c:85:1: error: no previous prototype for 'do_page_fault' [-Werror=missing-prototypes] arch/csky/mm/fault.c:187:17: error: no previous prototype for 'do_page_fault' [-Werror=missing-prototypes] arch/mips/mm/fault.c:323:17: error: no previous prototype for 'do_page_fault' [-Werror=missing-prototypes] arch/nios2/mm/fault.c:43:17: error: no previous prototype for 'do_page_fault' [-Werror=missing-prototypes] arch/sh/mm/fault.c:389:27: error: no previous prototype for 'do_page_fault' [-Werror=missing-prototypes] Since the calling conventions are architecture specific here, add separate prototypes for each one. Signed-off-by: Arnd Bergmann --- arch/alpha/include/asm/mmu_context.h | 2 ++ arch/csky/include/asm/traps.h | 2 ++ arch/mips/include/asm/traps.h | 3 +++ arch/nios2/include/asm/traps.h | 2 ++ arch/sh/include/asm/traps_32.h | 3 +++ 5 files changed, 12 insertions(+) diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h index 4eea7c616992..29a3e3a1f02b 100644 --- a/arch/alpha/include/asm/mmu_context.h +++ b/arch/alpha/include/asm/mmu_context.h @@ -183,6 +183,8 @@ ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, } extern void __load_new_mm_context(struct mm_struct *); +asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, + long cause, struct pt_regs *regs); #ifdef CONFIG_SMP #define check_mmu_context() \ diff --git a/arch/csky/include/asm/traps.h b/arch/csky/include/asm/traps.h index 495ce318d569..6bbbbe43165f 100644 --- a/arch/csky/include/asm/traps.h +++ b/arch/csky/include/asm/traps.h @@ -55,4 +55,6 @@ asmlinkage void trap_c(struct pt_regs *regs); asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); +asmlinkage void do_page_fault(struct pt_regs *regs); + #endif /* __ASM_CSKY_TRAPS_H */ diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h index 15cde638b407..d4d9f8a8fdea 100644 --- a/arch/mips/include/asm/traps.h +++ b/arch/mips/include/asm/traps.h @@ -39,4 +39,7 @@ extern char except_vec_nmi[]; register_nmi_notifier(&fn##_nb); \ }) +asmlinkage void do_page_fault(struct pt_regs *regs, + unsigned long write, unsigned long address); + #endif /* _ASM_TRAPS_H */ diff --git a/arch/nios2/include/asm/traps.h b/arch/nios2/include/asm/traps.h index 82a48473280d..afd77bef01c6 100644 --- a/arch/nios2/include/asm/traps.h +++ b/arch/nios2/include/asm/traps.h @@ -14,6 +14,8 @@ #ifndef __ASSEMBLY__ void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr); +void do_page_fault(struct pt_regs *regs, unsigned long cause, + unsigned long address); #endif #endif /* _ASM_NIOS2_TRAPS_H */ diff --git a/arch/sh/include/asm/traps_32.h b/arch/sh/include/asm/traps_32.h index 8c5bbb7b6053..8f14071bea72 100644 --- a/arch/sh/include/asm/traps_32.h +++ b/arch/sh/include/asm/traps_32.h @@ -43,6 +43,9 @@ static inline void trigger_address_error(void) asmlinkage void do_address_error(struct pt_regs *regs, unsigned long writeaccess, unsigned long address); +asmlinkage void do_page_fault(struct pt_regs *regs, + unsigned long error_code, + unsigned long address); asmlinkage void do_divide_error(unsigned long r4); asmlinkage void do_reserved_inst(void); asmlinkage void do_illegal_slot_inst(void); From ca8e45c8048a2c9503c74751d25414601f730580 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Nov 2023 22:02:59 +0100 Subject: [PATCH 1211/7721] csky: fix arch_jump_label_transform_static override The arch_jump_label_transform_static() function in csky was originally meant to override the generic __weak function, but that got changed to an #ifndef check. This showed up as a missing-prototype warning: arch/csky/kernel/jump_label.c:43:6: error: no previous prototype for 'arch_jump_label_transform_static' [-Werror=missing-prototypes] Change the method to use the new method of having a #define and a prototype for the global function. Fixes: 7e6b9db27de9 ("jump_label: make initial NOP patching the special case") Fixes: 4e8bb4ba5a55 ("csky: Add jump-label implementation") Reviewed-by: Guo Ren Signed-off-by: Arnd Bergmann --- arch/csky/include/asm/jump_label.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h index d488ba6084bc..98a3f4b168bd 100644 --- a/arch/csky/include/asm/jump_label.h +++ b/arch/csky/include/asm/jump_label.h @@ -43,5 +43,10 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, return true; } +enum jump_label_type; +void arch_jump_label_transform_static(struct jump_entry *entry, + enum jump_label_type type); +#define arch_jump_label_transform_static arch_jump_label_transform_static + #endif /* __ASSEMBLY__ */ #endif /* __ASM_CSKY_JUMP_LABEL_H */ From 3431e32cb585f3159ffd4ccceffa0d570bdd5744 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:14 +0100 Subject: [PATCH 1212/7721] media: videobuf2: Rework offset 'cookie' encoding pattern Change how offset 'cookie' field value is computed to make possible to use more buffers. The maximum number of buffers depends of PAGE_SHIFT value and can go up to 0x7fff when PAGE_SHIFT = 12. With this encoding pattern we know the maximum number that a queue could store so we can check it at queue init time. It also make easier and faster to find buffer and plane from using the offset field. Change __find_plane_by_offset() prototype to return the video buffer itself rather than it index. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index e5fd7ff0dae6..0b7c6b297d12 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -31,6 +31,16 @@ #include +#define PLANE_INDEX_BITS 3 +#define PLANE_INDEX_SHIFT (PAGE_SHIFT + PLANE_INDEX_BITS) +#define PLANE_INDEX_MASK (BIT_MASK(PLANE_INDEX_BITS) - 1) +#define MAX_BUFFER_INDEX BIT_MASK(30 - PLANE_INDEX_SHIFT) +#define BUFFER_INDEX_MASK (MAX_BUFFER_INDEX - 1) + +#if BIT(PLANE_INDEX_BITS) != VIDEO_MAX_PLANES +#error PLANE_INDEX_BITS order must be equal to VIDEO_MAX_PLANES +#endif + static int debug; module_param(debug, int, 0644); @@ -358,21 +368,27 @@ static void __setup_offsets(struct vb2_buffer *vb) unsigned int plane; unsigned long offset = 0; - if (vb->index) { - struct vb2_buffer *prev = q->bufs[vb->index - 1]; - struct vb2_plane *p = &prev->planes[prev->num_planes - 1]; - - offset = PAGE_ALIGN(p->m.offset + p->length); - } + /* + * The offset "cookie" value has the following constraints: + * - a buffer can have up to 8 planes. + * - v4l2 mem2mem uses bit 30 to distinguish between + * OUTPUT (aka "source", bit 30 is 0) and + * CAPTURE (aka "destination", bit 30 is 1) buffers. + * - must be page aligned + * That led to this bit mapping when PAGE_SHIFT = 12: + * |30 |29 15|14 12|11 0| + * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0 | + * where there are 15 bits to store the buffer index. + * Depending on PAGE_SHIFT value we can have fewer bits + * to store the buffer index. + */ + offset = vb->index << PLANE_INDEX_SHIFT; for (plane = 0; plane < vb->num_planes; ++plane) { - vb->planes[plane].m.offset = offset; + vb->planes[plane].m.offset = offset + (plane << PAGE_SHIFT); dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n", vb->index, plane, offset); - - offset += vb->planes[plane].length; - offset = PAGE_ALIGN(offset); } } @@ -2188,10 +2204,9 @@ EXPORT_SYMBOL_GPL(vb2_core_streamoff); * __find_plane_by_offset() - find plane associated with the given offset */ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset, - unsigned int *_buffer, unsigned int *_plane) + struct vb2_buffer **vb, unsigned int *plane) { - struct vb2_buffer *vb; - unsigned int buffer, plane; + unsigned int buffer; /* * Sanity checks to ensure the lock is held, MEMORY_MMAP is @@ -2209,24 +2224,15 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset, return -EBUSY; } - /* - * Go over all buffers and their planes, comparing the given offset - * with an offset assigned to each plane. If a match is found, - * return its buffer and plane numbers. - */ - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; + /* Get buffer and plane from the offset */ + buffer = (offset >> PLANE_INDEX_SHIFT) & BUFFER_INDEX_MASK; + *plane = (offset >> PAGE_SHIFT) & PLANE_INDEX_MASK; - for (plane = 0; plane < vb->num_planes; ++plane) { - if (vb->planes[plane].m.offset == offset) { - *_buffer = buffer; - *_plane = plane; - return 0; - } - } - } + if (buffer >= q->num_buffers || *plane >= q->bufs[buffer]->num_planes) + return -EINVAL; - return -EINVAL; + *vb = q->bufs[buffer]; + return 0; } int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, @@ -2306,7 +2312,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct vb2_buffer *vb; - unsigned int buffer = 0, plane = 0; + unsigned int plane = 0; int ret; unsigned long length; @@ -2335,12 +2341,10 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) * Find the plane corresponding to the offset passed by userspace. This * will return an error if not MEMORY_MMAP or file I/O is in progress. */ - ret = __find_plane_by_offset(q, offset, &buffer, &plane); + ret = __find_plane_by_offset(q, offset, &vb, &plane); if (ret) goto unlock; - vb = q->bufs[buffer]; - /* * MMAP requires page_aligned buffers. * The buffer length was page_aligned at __vb2_buf_mem_alloc(), @@ -2368,7 +2372,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) if (ret) return ret; - dprintk(q, 3, "buffer %d, plane %d successfully mapped\n", buffer, plane); + dprintk(q, 3, "buffer %u, plane %d successfully mapped\n", vb->index, plane); return 0; } EXPORT_SYMBOL_GPL(vb2_mmap); @@ -2382,7 +2386,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, { unsigned long offset = pgoff << PAGE_SHIFT; struct vb2_buffer *vb; - unsigned int buffer, plane; + unsigned int plane; void *vaddr; int ret; @@ -2392,12 +2396,10 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, * Find the plane corresponding to the offset passed by userspace. This * will return an error if not MEMORY_MMAP or file I/O is in progress. */ - ret = __find_plane_by_offset(q, offset, &buffer, &plane); + ret = __find_plane_by_offset(q, offset, &vb, &plane); if (ret) goto unlock; - vb = q->bufs[buffer]; - vaddr = vb2_plane_vaddr(vb, plane); mutex_unlock(&q->mmap_lock); return vaddr ? (unsigned long)vaddr : -EINVAL; From 1d33df98b111e358fe21d6282fc98c8d3c66cdce Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:15 +0100 Subject: [PATCH 1213/7721] media: videobuf2: Stop spamming kernel log with all queue counter Only report unbalanced queue counters do avoid spamming kernel log with useless information. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 79 +++++++++++-------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 0b7c6b297d12..009ae53dbe3b 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -538,25 +538,26 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) #ifdef CONFIG_VIDEO_ADV_DEBUG /* - * Check that all the calls were balances during the life-time of this - * queue. If not (or if the debug level is 1 or up), then dump the - * counters to the kernel log. + * Check that all the calls were balanced during the life-time of this + * queue. If not then dump the counters to the kernel log. */ if (q->num_buffers) { bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || q->cnt_prepare_streaming != q->cnt_unprepare_streaming || q->cnt_wait_prepare != q->cnt_wait_finish; - if (unbalanced || debug) { - pr_info("counters for queue %p:%s\n", q, - unbalanced ? " UNBALANCED!" : ""); - pr_info(" setup: %u start_streaming: %u stop_streaming: %u\n", - q->cnt_queue_setup, q->cnt_start_streaming, - q->cnt_stop_streaming); - pr_info(" prepare_streaming: %u unprepare_streaming: %u\n", - q->cnt_prepare_streaming, q->cnt_unprepare_streaming); - pr_info(" wait_prepare: %u wait_finish: %u\n", - q->cnt_wait_prepare, q->cnt_wait_finish); + if (unbalanced) { + pr_info("unbalanced counters for queue %p:\n", q); + if (q->cnt_start_streaming != q->cnt_stop_streaming) + pr_info(" setup: %u start_streaming: %u stop_streaming: %u\n", + q->cnt_queue_setup, q->cnt_start_streaming, + q->cnt_stop_streaming); + if (q->cnt_prepare_streaming != q->cnt_unprepare_streaming) + pr_info(" prepare_streaming: %u unprepare_streaming: %u\n", + q->cnt_prepare_streaming, q->cnt_unprepare_streaming); + if (q->cnt_wait_prepare != q->cnt_wait_finish) + pr_info(" wait_prepare: %u wait_finish: %u\n", + q->cnt_wait_prepare, q->cnt_wait_finish); } q->cnt_queue_setup = 0; q->cnt_wait_prepare = 0; @@ -577,29 +578,37 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) vb->cnt_buf_prepare != vb->cnt_buf_finish || vb->cnt_buf_init != vb->cnt_buf_cleanup; - if (unbalanced || debug) { - pr_info(" counters for queue %p, buffer %d:%s\n", - q, buffer, unbalanced ? " UNBALANCED!" : ""); - pr_info(" buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n", - vb->cnt_buf_init, vb->cnt_buf_cleanup, - vb->cnt_buf_prepare, vb->cnt_buf_finish); - pr_info(" buf_out_validate: %u buf_queue: %u buf_done: %u buf_request_complete: %u\n", - vb->cnt_buf_out_validate, vb->cnt_buf_queue, - vb->cnt_buf_done, vb->cnt_buf_request_complete); - pr_info(" alloc: %u put: %u prepare: %u finish: %u mmap: %u\n", - vb->cnt_mem_alloc, vb->cnt_mem_put, - vb->cnt_mem_prepare, vb->cnt_mem_finish, - vb->cnt_mem_mmap); - pr_info(" get_userptr: %u put_userptr: %u\n", - vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr); - pr_info(" attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n", - vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf, - vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf); - pr_info(" get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n", + if (unbalanced) { + pr_info("unbalanced counters for queue %p, buffer %d:\n", + q, buffer); + if (vb->cnt_buf_init != vb->cnt_buf_cleanup) + pr_info(" buf_init: %u buf_cleanup: %u\n", + vb->cnt_buf_init, vb->cnt_buf_cleanup); + if (vb->cnt_buf_prepare != vb->cnt_buf_finish) + pr_info(" buf_prepare: %u buf_finish: %u\n", + vb->cnt_buf_prepare, vb->cnt_buf_finish); + if (vb->cnt_buf_queue != vb->cnt_buf_done) + pr_info(" buf_out_validate: %u buf_queue: %u buf_done: %u buf_request_complete: %u\n", + vb->cnt_buf_out_validate, vb->cnt_buf_queue, + vb->cnt_buf_done, vb->cnt_buf_request_complete); + if (vb->cnt_mem_alloc != vb->cnt_mem_put) + pr_info(" alloc: %u put: %u\n", + vb->cnt_mem_alloc, vb->cnt_mem_put); + if (vb->cnt_mem_prepare != vb->cnt_mem_finish) + pr_info(" prepare: %u finish: %u\n", + vb->cnt_mem_prepare, vb->cnt_mem_finish); + if (vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr) + pr_info(" get_userptr: %u put_userptr: %u\n", + vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr); + if (vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf) + pr_info(" attach_dmabuf: %u detach_dmabuf: %u\n", + vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf); + if (vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf) + pr_info(" map_dmabuf: %u unmap_dmabuf: %u\n", + vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf); + pr_info(" get_dmabuf: %u num_users: %u\n", vb->cnt_mem_get_dmabuf, - vb->cnt_mem_num_users, - vb->cnt_mem_vaddr, - vb->cnt_mem_cookie); + vb->cnt_mem_num_users); } } #endif From 3c147c29310b838fb79a84f01448e34fbcbf0334 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:16 +0100 Subject: [PATCH 1214/7721] media: videobuf2: Use vb2_buffer instead of index Directly use vb2_buffer pointer instead of index inside queue array. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 40 +++++---------- .../media/common/videobuf2/videobuf2-v4l2.c | 51 +++++++++++-------- drivers/media/dvb-core/dvb_vb2.c | 6 +-- include/media/videobuf2-core.h | 16 +++--- 4 files changed, 53 insertions(+), 60 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 009ae53dbe3b..df515134bb0c 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -659,9 +659,9 @@ static bool __buffers_in_use(struct vb2_queue *q) return false; } -void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) +void vb2_core_querybuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb) { - call_void_bufop(q, fill_user_buffer, q->bufs[index], pb); + call_void_bufop(q, fill_user_buffer, vb, pb); } EXPORT_SYMBOL_GPL(vb2_core_querybuf); @@ -1495,9 +1495,6 @@ static void vb2_req_unprepare(struct media_request_object *obj) WARN_ON(!vb->req_obj.req); } -int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, - struct media_request *req); - static void vb2_req_queue(struct media_request_object *obj) { struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj); @@ -1512,7 +1509,7 @@ static void vb2_req_queue(struct media_request_object *obj) * set. We just ignore that, and expect this will be caught the * next time vb2_req_prepare() is called. */ - err = vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL); + err = vb2_core_qbuf(vb->vb2_queue, vb, NULL, NULL); WARN_ON_ONCE(err && err != -EIO); mutex_unlock(vb->vb2_queue->lock); } @@ -1567,12 +1564,10 @@ unsigned int vb2_request_buffer_cnt(struct media_request *req) } EXPORT_SYMBOL_GPL(vb2_request_buffer_cnt); -int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) +int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb) { - struct vb2_buffer *vb; int ret; - vb = q->bufs[index]; if (vb->state != VB2_BUF_STATE_DEQUEUED) { dprintk(q, 1, "invalid buffer state %s\n", vb2_state_name(vb->state)); @@ -1659,10 +1654,9 @@ static int vb2_start_streaming(struct vb2_queue *q) return ret; } -int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, +int vb2_core_qbuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb, struct media_request *req) { - struct vb2_buffer *vb; enum vb2_buffer_state orig_state; int ret; @@ -1671,8 +1665,6 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, return -EIO; } - vb = q->bufs[index]; - if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && q->requires_requests) { dprintk(q, 1, "qbuf requires a request\n"); @@ -2245,9 +2237,8 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset, } int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, - unsigned int index, unsigned int plane, unsigned int flags) + struct vb2_buffer *vb, unsigned int plane, unsigned int flags) { - struct vb2_buffer *vb = NULL; struct vb2_plane *vb_plane; int ret; struct dma_buf *dbuf; @@ -2272,13 +2263,6 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, return -EINVAL; } - if (index >= q->num_buffers) { - dprintk(q, 1, "buffer index out of range\n"); - return -EINVAL; - } - - vb = q->bufs[index]; - if (plane >= vb->num_planes) { dprintk(q, 1, "buffer plane out of range\n"); return -EINVAL; @@ -2297,20 +2281,20 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { dprintk(q, 1, "failed to export buffer %d, plane %d\n", - index, plane); + vb->index, plane); return -EINVAL; } ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); if (ret < 0) { dprintk(q, 3, "buffer %d, plane %d failed to export (%d)\n", - index, plane, ret); + vb->index, plane, ret); dma_buf_put(dbuf); return ret; } dprintk(q, 3, "buffer %d, plane %d exported as %d descriptor\n", - index, plane, ret); + vb->index, plane, ret); *fd = ret; return 0; @@ -2715,7 +2699,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) * Queue all buffers. */ for (i = 0; i < q->num_buffers; i++) { - ret = vb2_core_qbuf(q, i, NULL, NULL); + ret = vb2_core_qbuf(q, q->bufs[i], NULL, NULL); if (ret) goto err_reqbufs; fileio->bufs[i].queued = 1; @@ -2900,7 +2884,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ if (copy_timestamp) b->timestamp = ktime_get_ns(); - ret = vb2_core_qbuf(q, index, NULL, NULL); + ret = vb2_core_qbuf(q, b, NULL, NULL); dprintk(q, 5, "vb2_qbuf result: %d\n", ret); if (ret) return ret; @@ -3003,7 +2987,7 @@ static int vb2_thread(void *data) if (copy_timestamp) vb->timestamp = ktime_get_ns(); if (!threadio->stop) - ret = vb2_core_qbuf(q, vb->index, NULL, NULL); + ret = vb2_core_qbuf(q, vb, NULL, NULL); call_void_qop(q, wait_prepare, q); if (ret || threadio->stop) break; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index c7a54d82a55e..d19d82a75ac6 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -364,13 +364,12 @@ static void set_buffer_cache_hints(struct vb2_queue *q, } static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev, - struct v4l2_buffer *b, bool is_prepare, - struct media_request **p_req) + struct vb2_buffer *vb, struct v4l2_buffer *b, + bool is_prepare, struct media_request **p_req) { const char *opname = is_prepare ? "prepare_buf" : "qbuf"; struct media_request *req; struct vb2_v4l2_buffer *vbuf; - struct vb2_buffer *vb; int ret; if (b->type != q->type) { @@ -378,23 +377,11 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md return -EINVAL; } - if (b->index >= q->num_buffers) { - dprintk(q, 1, "%s: buffer index out of range\n", opname); - return -EINVAL; - } - - if (q->bufs[b->index] == NULL) { - /* Should never happen */ - dprintk(q, 1, "%s: buffer is NULL\n", opname); - return -EINVAL; - } - if (b->memory != q->memory) { dprintk(q, 1, "%s: invalid memory type\n", opname); return -EINVAL; } - vb = q->bufs[b->index]; vbuf = to_vb2_v4l2_buffer(vb); ret = __verify_planes_array(vb, b); if (ret) @@ -667,7 +654,7 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) vb = q->bufs[b->index]; ret = __verify_planes_array(vb, b); if (!ret) - vb2_core_querybuf(q, b->index, b); + vb2_core_querybuf(q, vb, b); return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -723,6 +710,7 @@ EXPORT_SYMBOL_GPL(vb2_reqbufs); int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, struct v4l2_buffer *b) { + struct vb2_buffer *vb; int ret; if (vb2_fileio_is_active(q)) { @@ -733,9 +721,15 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, if (b->flags & V4L2_BUF_FLAG_REQUEST_FD) return -EINVAL; - ret = vb2_queue_or_prepare_buf(q, mdev, b, true, NULL); + if (b->index >= q->num_buffers) { + dprintk(q, 1, "buffer index out of range\n"); + return -EINVAL; + } + vb = q->bufs[b->index]; - return ret ? ret : vb2_core_prepare_buf(q, b->index, b); + ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, true, NULL); + + return ret ? ret : vb2_core_prepare_buf(q, vb, b); } EXPORT_SYMBOL_GPL(vb2_prepare_buf); @@ -803,6 +797,7 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, struct v4l2_buffer *b) { struct media_request *req = NULL; + struct vb2_buffer *vb; int ret; if (vb2_fileio_is_active(q)) { @@ -810,10 +805,16 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, return -EBUSY; } - ret = vb2_queue_or_prepare_buf(q, mdev, b, false, &req); + if (b->index >= q->num_buffers) { + dprintk(q, 1, "buffer index out of range\n"); + return -EINVAL; + } + vb = q->bufs[b->index]; + + ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, false, &req); if (ret) return ret; - ret = vb2_core_qbuf(q, b->index, b, req); + ret = vb2_core_qbuf(q, vb, b, req); if (req) media_request_put(req); return ret; @@ -873,7 +874,15 @@ EXPORT_SYMBOL_GPL(vb2_streamoff); int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) { - return vb2_core_expbuf(q, &eb->fd, eb->type, eb->index, + struct vb2_buffer *vb; + + if (eb->index >= q->num_buffers) { + dprintk(q, 1, "buffer index out of range\n"); + return -EINVAL; + } + vb = q->bufs[eb->index]; + + return vb2_core_expbuf(q, &eb->fd, eb->type, vb, eb->plane, eb->flags); } EXPORT_SYMBOL_GPL(vb2_expbuf); diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 909df82fed33..b322ef179f05 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -360,7 +360,7 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) dprintk(1, "[%s] buffer index out of range\n", ctx->name); return -EINVAL; } - vb2_core_querybuf(&ctx->vb_q, b->index, b); + vb2_core_querybuf(&ctx->vb_q, q->bufs[b->index], b); dprintk(3, "[%s] index=%d\n", ctx->name, b->index); return 0; } @@ -370,7 +370,7 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp) struct vb2_queue *q = &ctx->vb_q; int ret; - ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, exp->index, + ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index], 0, exp->flags); if (ret) { dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, @@ -391,7 +391,7 @@ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) dprintk(1, "[%s] buffer index out of range\n", ctx->name); return -EINVAL; } - ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL); + ret = vb2_core_qbuf(&ctx->vb_q, q->bufs[b->index], b, NULL); if (ret) { dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, b->index, ret); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 4b6a9d2ea372..cd3ff1cd759d 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -747,7 +747,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q); /** * vb2_core_querybuf() - query video buffer information. * @q: pointer to &struct vb2_queue with videobuf2 queue. - * @index: id number of the buffer. + * @vb: pointer to struct &vb2_buffer. * @pb: buffer struct passed from userspace. * * Videobuf2 core helper to implement VIDIOC_QUERYBUF() operation. It is called @@ -759,7 +759,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q); * * Return: returns zero on success; an error code otherwise. */ -void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb); +void vb2_core_querybuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb); /** * vb2_core_reqbufs() - Initiate streaming. @@ -823,7 +823,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace * to the kernel. * @q: pointer to &struct vb2_queue with videobuf2 queue. - * @index: id number of the buffer. + * @vb: pointer to struct &vb2_buffer. * @pb: buffer structure passed from userspace to * &v4l2_ioctl_ops->vidioc_prepare_buf handler in driver. * @@ -839,13 +839,13 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * * Return: returns zero on success; an error code otherwise. */ -int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb); +int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb); /** * vb2_core_qbuf() - Queue a buffer from userspace * * @q: pointer to &struct vb2_queue with videobuf2 queue. - * @index: id number of the buffer + * @vb: pointer to struct &vb2_buffer. * @pb: buffer structure passed from userspace to * v4l2_ioctl_ops->vidioc_qbuf handler in driver * @req: pointer to &struct media_request, may be NULL. @@ -867,7 +867,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb); * * Return: returns zero on success; an error code otherwise. */ -int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, +int vb2_core_qbuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb, struct media_request *req); /** @@ -931,7 +931,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type); * @fd: pointer to the file descriptor associated with DMABUF * (set by driver). * @type: buffer type. - * @index: id number of the buffer. + * @vb: pointer to struct &vb2_buffer. * @plane: index of the plane to be exported, 0 for single plane queues * @flags: file flags for newly created file, as defined at * include/uapi/asm-generic/fcntl.h. @@ -945,7 +945,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type); * Return: returns zero on success; an error code otherwise. */ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, - unsigned int index, unsigned int plane, unsigned int flags); + struct vb2_buffer *vb, unsigned int plane, unsigned int flags); /** * vb2_core_queue_init() - initialize a videobuf2 queue From 6ea001f94ab571e5e7f8a187dad261710e58563b Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:17 +0100 Subject: [PATCH 1215/7721] media: videobuf2: Access vb2_queue bufs array through helper functions This patch adds 2 helpers functions to add and remove vb2 buffers from a queue. With these 2 and vb2_get_buffer(), bufs field of struct vb2_queue becomes like a private member of the structure. After each call to vb2_get_buffer() we need to be sure that we get a valid pointer in preparation for when buffers can be deleted. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 158 +++++++++++++----- .../media/common/videobuf2/videobuf2-v4l2.c | 44 +++-- 2 files changed, 149 insertions(+), 53 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index df515134bb0c..0024b82663d4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -413,6 +413,31 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) vb->skip_cache_sync_on_finish = 1; } +/** + * vb2_queue_add_buffer() - add a buffer to a queue + * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @vb: pointer to &struct vb2_buffer to be added to the queue. + * @index: index where add vb2_buffer in the queue + */ +static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index) +{ + WARN_ON(index >= VB2_MAX_FRAME || q->bufs[index] || vb->vb2_queue); + + q->bufs[index] = vb; + vb->index = index; + vb->vb2_queue = q; +} + +/** + * vb2_queue_remove_buffer() - remove a buffer from a queue + * @vb: pointer to &struct vb2_buffer to be removed from the queue. + */ +static void vb2_queue_remove_buffer(struct vb2_buffer *vb) +{ + vb->vb2_queue->bufs[vb->index] = NULL; + vb->vb2_queue = NULL; +} + /* * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type) * video buffer memory for all buffers/planes on the queue and initializes the @@ -441,9 +466,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, } vb->state = VB2_BUF_STATE_DEQUEUED; - vb->vb2_queue = q; vb->num_planes = num_planes; - vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; init_buffer_cache_hints(q, vb); @@ -451,9 +474,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->planes[plane].length = plane_sizes[plane]; vb->planes[plane].min_length = plane_sizes[plane]; } - call_void_bufop(q, init_buffer, vb); - q->bufs[vb->index] = vb; + vb2_queue_add_buffer(q, vb, q->num_buffers + buffer); + call_void_bufop(q, init_buffer, vb); /* Allocate video buffer memory for the MMAP type */ if (memory == VB2_MEMORY_MMAP) { @@ -461,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, if (ret) { dprintk(q, 1, "failed allocating memory for buffer %d\n", buffer); - q->bufs[vb->index] = NULL; + vb2_queue_remove_buffer(vb); kfree(vb); break; } @@ -476,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, dprintk(q, 1, "buffer %d %p initialization failed\n", buffer, vb); __vb2_buf_mem_free(vb); - q->bufs[vb->index] = NULL; + vb2_queue_remove_buffer(vb); kfree(vb); break; } @@ -499,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; + vb = vb2_get_buffer(q, buffer); if (!vb) continue; @@ -527,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) /* Call driver-provided cleanup function for each buffer, if provided */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { - struct vb2_buffer *vb = q->bufs[buffer]; + struct vb2_buffer *vb = vb2_get_buffer(q, buffer); if (vb && vb->planes[0].mem_priv) call_void_vb_qop(vb, buf_cleanup, vb); @@ -568,15 +591,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->cnt_unprepare_streaming = 0; } for (buffer = 0; buffer < q->num_buffers; ++buffer) { - struct vb2_buffer *vb = q->bufs[buffer]; - bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put || - vb->cnt_mem_prepare != vb->cnt_mem_finish || - vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr || - vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf || - vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf || - vb->cnt_buf_queue != vb->cnt_buf_done || - vb->cnt_buf_prepare != vb->cnt_buf_finish || - vb->cnt_buf_init != vb->cnt_buf_cleanup; + struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + bool unbalanced; + + if (!vb) + continue; + + unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put || + vb->cnt_mem_prepare != vb->cnt_mem_finish || + vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr || + vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf || + vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf || + vb->cnt_buf_queue != vb->cnt_buf_done || + vb->cnt_buf_prepare != vb->cnt_buf_finish || + vb->cnt_buf_init != vb->cnt_buf_cleanup; if (unbalanced) { pr_info("unbalanced counters for queue %p, buffer %d:\n", @@ -616,8 +644,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) /* Free vb2 buffers */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { - kfree(q->bufs[buffer]); - q->bufs[buffer] = NULL; + struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + + if (!vb) + continue; + + vb2_queue_remove_buffer(vb); + kfree(vb); } q->num_buffers -= buffers; @@ -653,7 +686,12 @@ static bool __buffers_in_use(struct vb2_queue *q) { unsigned int buffer; for (buffer = 0; buffer < q->num_buffers; ++buffer) { - if (vb2_buffer_in_use(q, q->bufs[buffer])) + struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + + if (!vb) + continue; + + if (vb2_buffer_in_use(q, vb)) return true; } return false; @@ -1638,7 +1676,11 @@ static int vb2_start_streaming(struct vb2_queue *q) * correctly return them to vb2. */ for (i = 0; i < q->num_buffers; ++i) { - vb = q->bufs[i]; + vb = vb2_get_buffer(q, i); + + if (!vb) + continue; + if (vb->state == VB2_BUF_STATE_ACTIVE) vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED); } @@ -2039,12 +2081,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * to vb2 in stop_streaming(). */ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { - for (i = 0; i < q->num_buffers; ++i) - if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { - pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n", - q->bufs[i]); - vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR); + for (i = 0; i < q->num_buffers; ++i) { + struct vb2_buffer *vb = vb2_get_buffer(q, i); + + if (!vb) + continue; + + if (vb->state == VB2_BUF_STATE_ACTIVE) { + pr_warn("driver bug: stop_streaming operation is leaving buffer %u in active state\n", + vb->index); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } + } /* Must be zero now */ WARN_ON(atomic_read(&q->owned_by_drv_count)); } @@ -2078,9 +2126,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ for (i = 0; i < q->num_buffers; ++i) { - struct vb2_buffer *vb = q->bufs[i]; - struct media_request *req = vb->req_obj.req; + struct vb2_buffer *vb; + struct media_request *req; + vb = vb2_get_buffer(q, i); + if (!vb) + continue; + + req = vb->req_obj.req; /* * If a request is associated with this buffer, then * call buf_request_cancel() to give the driver to complete() @@ -2229,10 +2282,12 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset, buffer = (offset >> PLANE_INDEX_SHIFT) & BUFFER_INDEX_MASK; *plane = (offset >> PAGE_SHIFT) & PLANE_INDEX_MASK; - if (buffer >= q->num_buffers || *plane >= q->bufs[buffer]->num_planes) + *vb = vb2_get_buffer(q, buffer); + if (!*vb) + return -EINVAL; + if (*plane >= (*vb)->num_planes) return -EINVAL; - *vb = q->bufs[buffer]; return 0; } @@ -2620,6 +2675,7 @@ struct vb2_fileio_data { static int __vb2_init_fileio(struct vb2_queue *q, int read) { struct vb2_fileio_data *fileio; + struct vb2_buffer *vb; int i, ret; unsigned int count = 0; @@ -2670,11 +2726,18 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) if (ret) goto err_kfree; + /* + * Userspace can never add or delete buffers later, so there + * will never be holes. It is safe to assume that vb2_get_buffer(q, 0) + * will always return a valid vb pointer + */ + vb = vb2_get_buffer(q, 0); + /* * Check if plane_count is correct * (multiplane buffers are not supported). */ - if (q->bufs[0]->num_planes != 1) { + if (vb->num_planes != 1) { ret = -EBUSY; goto err_reqbufs; } @@ -2683,12 +2746,15 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) * Get kernel address of each buffer. */ for (i = 0; i < q->num_buffers; i++) { - fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); + /* vb can never be NULL when using fileio. */ + vb = vb2_get_buffer(q, i); + + fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0); if (fileio->bufs[i].vaddr == NULL) { ret = -EINVAL; goto err_reqbufs; } - fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); + fileio->bufs[i].size = vb2_plane_size(vb, 0); } /* @@ -2699,7 +2765,12 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) * Queue all buffers. */ for (i = 0; i < q->num_buffers; i++) { - ret = vb2_core_qbuf(q, q->bufs[i], NULL, NULL); + struct vb2_buffer *vb2 = vb2_get_buffer(q, i); + + if (!vb2) + continue; + + ret = vb2_core_qbuf(q, vb2, NULL, NULL); if (ret) goto err_reqbufs; fileio->bufs[i].queued = 1; @@ -2816,15 +2887,17 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ fileio->cur_index = index; buf = &fileio->bufs[index]; - b = q->bufs[index]; + + /* b can never be NULL when using fileio. */ + b = vb2_get_buffer(q, index); /* * Get number of bytes filled by the driver */ buf->pos = 0; buf->queued = 0; - buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) - : vb2_plane_size(q->bufs[index], 0); + buf->size = read ? vb2_get_plane_payload(b, 0) + : vb2_plane_size(b, 0); /* Compensate for data_offset on read in the multiplanar case. */ if (is_multiplanar && read && b->planes[0].data_offset < buf->size) { @@ -2867,7 +2940,8 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ * Queue next buffer if required. */ if (buf->pos == buf->size || (!read && fileio->write_immediately)) { - struct vb2_buffer *b = q->bufs[index]; + /* b can never be NULL when using fileio. */ + struct vb2_buffer *b = vb2_get_buffer(q, index); /* * Check if this is the last buffer to read. @@ -2894,7 +2968,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ */ buf->pos = 0; buf->queued = 1; - buf->size = vb2_plane_size(q->bufs[index], 0); + buf->size = vb2_plane_size(b, 0); fileio->q_count += 1; /* * If we are queuing up buffers for the first time, then @@ -2965,7 +3039,9 @@ static int vb2_thread(void *data) * Call vb2_dqbuf to get buffer back. */ if (prequeue) { - vb = q->bufs[index++]; + vb = vb2_get_buffer(q, index++); + if (!vb) + continue; prequeue--; } else { call_void_qop(q, wait_finish, q); @@ -2974,7 +3050,7 @@ static int vb2_thread(void *data) call_void_qop(q, wait_prepare, q); dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret); if (!ret) - vb = q->bufs[index]; + vb = vb2_get_buffer(q, index); } if (ret || threadio->stop) break; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index d19d82a75ac6..37f814a89ace 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -615,11 +615,22 @@ static const struct vb2_buf_ops v4l2_buf_ops = { struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) { unsigned int i; + struct vb2_buffer *vb2; - for (i = 0; i < q->num_buffers; i++) - if (q->bufs[i]->copied_timestamp && - q->bufs[i]->timestamp == timestamp) - return vb2_get_buffer(q, i); + /* + * This loop doesn't scale if there is a really large number of buffers. + * Maybe something more efficient will be needed in this case. + */ + for (i = 0; i < q->num_buffers; i++) { + vb2 = vb2_get_buffer(q, i); + + if (!vb2) + continue; + + if (vb2->copied_timestamp && + vb2->timestamp == timestamp) + return vb2; + } return NULL; } EXPORT_SYMBOL_GPL(vb2_find_buffer); @@ -647,11 +658,12 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) return -EINVAL; } - if (b->index >= q->num_buffers) { - dprintk(q, 1, "buffer index out of range\n"); + vb = vb2_get_buffer(q, b->index); + if (!vb) { + dprintk(q, 1, "can't find the requested buffer %u\n", b->index); return -EINVAL; } - vb = q->bufs[b->index]; + ret = __verify_planes_array(vb, b); if (!ret) vb2_core_querybuf(q, vb, b); @@ -721,11 +733,11 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, if (b->flags & V4L2_BUF_FLAG_REQUEST_FD) return -EINVAL; - if (b->index >= q->num_buffers) { - dprintk(q, 1, "buffer index out of range\n"); + vb = vb2_get_buffer(q, b->index); + if (!vb) { + dprintk(q, 1, "can't find the requested buffer %u\n", b->index); return -EINVAL; } - vb = q->bufs[b->index]; ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, true, NULL); @@ -809,7 +821,11 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, dprintk(q, 1, "buffer index out of range\n"); return -EINVAL; } - vb = q->bufs[b->index]; + vb = vb2_get_buffer(q, b->index); + if (!vb) { + dprintk(q, 1, "can't find the requested buffer %u\n", b->index); + return -EINVAL; + } ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, false, &req); if (ret) @@ -880,7 +896,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) dprintk(q, 1, "buffer index out of range\n"); return -EINVAL; } - vb = q->bufs[eb->index]; + vb = vb2_get_buffer(q, eb->index); + if (!vb) { + dprintk(q, 1, "can't find the requested buffer %u\n", eb->index); + return -EINVAL; + } return vb2_core_expbuf(q, &eb->fd, eb->type, vb, eb->plane, eb->flags); From 5287f48952e0e03be919e04d25cb832207d9661a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:18 +0100 Subject: [PATCH 1216/7721] media: videobuf2: Remove duplicated index vs q->num_buffers check vb2_get_buffer() already checks if the requested index is valid. Stop duplicating this kind of check everywhere. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-v4l2.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 37f814a89ace..6ba13a95323c 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -817,10 +817,6 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, return -EBUSY; } - if (b->index >= q->num_buffers) { - dprintk(q, 1, "buffer index out of range\n"); - return -EINVAL; - } vb = vb2_get_buffer(q, b->index); if (!vb) { dprintk(q, 1, "can't find the requested buffer %u\n", b->index); @@ -892,10 +888,6 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) { struct vb2_buffer *vb; - if (eb->index >= q->num_buffers) { - dprintk(q, 1, "buffer index out of range\n"); - return -EINVAL; - } vb = vb2_get_buffer(q, eb->index); if (!vb) { dprintk(q, 1, "can't find the requested buffer %u\n", eb->index); From 741d0f6b51032a35446ac72ee8a04fcfa938ee2e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:19 +0100 Subject: [PATCH 1217/7721] media: videobuf2: Add helper to get queue number of buffers In the future a side effect of introducing DELETE_BUFS ioctl is the create of 'holes' (i.e. unused buffers) in bufs arrays. To know which entries of the bufs arrays are used a bitmap will be added in struct vb2_queue. That will also mean that the number of buffers will be computed given the number of bit set in this bitmap. To smoothly allow this evolution all drives must stop using directly num_buffers field from struct vb2_queue. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index cd3ff1cd759d..8f9d9e4af5b1 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -1139,6 +1139,15 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q) return q->fileio; } +/** + * vb2_get_num_buffers() - get the number of buffer in a queue + * @q: pointer to &struct vb2_queue with videobuf2 queue. + */ +static inline unsigned int vb2_get_num_buffers(struct vb2_queue *q) +{ + return q->num_buffers; +} + /** * vb2_is_busy() - return busy status of the queue. * @q: pointer to &struct vb2_queue with videobuf2 queue. @@ -1147,7 +1156,7 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q) */ static inline bool vb2_is_busy(struct vb2_queue *q) { - return (q->num_buffers > 0); + return vb2_get_num_buffers(q) > 0; } /** From da8fc26b0b7d6c0cf46695ef717458fa248a71fb Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:20 +0100 Subject: [PATCH 1218/7721] media: videobuf2: Use vb2_get_num_buffers() helper Stop using queue num_buffers field directly, instead use vb2_get_num_buffers(). This prepares for the future 'delete buffers' feature where there are holes in the buffer indices. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 94 ++++++++++--------- .../media/common/videobuf2/videobuf2-v4l2.c | 4 +- 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 0024b82663d4..ce5b84b9bcd4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -449,13 +449,14 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, unsigned int num_buffers, unsigned int num_planes, const unsigned plane_sizes[VB2_MAX_PLANES]) { + unsigned int q_num_buffers = vb2_get_num_buffers(q); unsigned int buffer, plane; struct vb2_buffer *vb; int ret; /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */ num_buffers = min_t(unsigned int, num_buffers, - VB2_MAX_FRAME - q->num_buffers); + VB2_MAX_FRAME - q_num_buffers); for (buffer = 0; buffer < num_buffers; ++buffer) { /* Allocate vb2 buffer structures */ @@ -475,7 +476,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->planes[plane].min_length = plane_sizes[plane]; } - vb2_queue_add_buffer(q, vb, q->num_buffers + buffer); + vb2_queue_add_buffer(q, vb, q_num_buffers + buffer); call_void_bufop(q, init_buffer, vb); /* Allocate video buffer memory for the MMAP type */ @@ -519,8 +520,9 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; struct vb2_buffer *vb; + unsigned int q_num_buffers = vb2_get_num_buffers(q); - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; ++buffer) { vb = vb2_get_buffer(q, buffer); if (!vb) @@ -544,11 +546,12 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; + unsigned int q_num_buffers = vb2_get_num_buffers(q); lockdep_assert_held(&q->mmap_lock); /* Call driver-provided cleanup function for each buffer, if provided */ - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; ++buffer) { struct vb2_buffer *vb = vb2_get_buffer(q, buffer); @@ -564,7 +567,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) * Check that all the calls were balanced during the life-time of this * queue. If not then dump the counters to the kernel log. */ - if (q->num_buffers) { + if (q_num_buffers) { bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || q->cnt_prepare_streaming != q->cnt_unprepare_streaming || q->cnt_wait_prepare != q->cnt_wait_finish; @@ -590,7 +593,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->cnt_stop_streaming = 0; q->cnt_unprepare_streaming = 0; } - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = 0; buffer < vb2_get_num_buffers(q); buffer++) { struct vb2_buffer *vb = vb2_get_buffer(q, buffer); bool unbalanced; @@ -642,7 +645,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) #endif /* Free vb2 buffers */ - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; ++buffer) { struct vb2_buffer *vb = vb2_get_buffer(q, buffer); @@ -654,7 +657,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } q->num_buffers -= buffers; - if (!q->num_buffers) { + if (!vb2_get_num_buffers(q)) { q->memory = VB2_MEMORY_UNKNOWN; INIT_LIST_HEAD(&q->queued_list); } @@ -685,7 +688,7 @@ EXPORT_SYMBOL(vb2_buffer_in_use); static bool __buffers_in_use(struct vb2_queue *q) { unsigned int buffer; - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = 0; buffer < vb2_get_num_buffers(q); ++buffer) { struct vb2_buffer *vb = vb2_get_buffer(q, buffer); if (!vb) @@ -811,6 +814,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int flags, unsigned int *count) { unsigned int num_buffers, allocated_buffers, num_planes = 0; + unsigned int q_num_bufs = vb2_get_num_buffers(q); unsigned plane_sizes[VB2_MAX_PLANES] = { }; bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; unsigned int i; @@ -826,7 +830,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, return -EBUSY; } - if (*count == 0 || q->num_buffers != 0 || + if (*count == 0 || q_num_bufs != 0 || (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) || !verify_coherency_flags(q, non_coherent_mem)) { /* @@ -844,7 +848,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * queued without ever calling STREAMON. */ __vb2_queue_cancel(q); - __vb2_queue_free(q, q->num_buffers); + __vb2_queue_free(q, q_num_bufs); mutex_unlock(&q->mmap_lock); /* @@ -939,7 +943,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, if (ret < 0) { /* * Note: __vb2_queue_free() will subtract 'allocated_buffers' - * from q->num_buffers and it will reset q->memory to + * from already queued buffers and it will reset q->memory to * VB2_MEMORY_UNKNOWN. */ __vb2_queue_free(q, allocated_buffers); @@ -973,10 +977,11 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int num_planes = 0, num_buffers, allocated_buffers; unsigned plane_sizes[VB2_MAX_PLANES] = { }; bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; - bool no_previous_buffers = !q->num_buffers; - int ret; + unsigned int q_num_bufs = vb2_get_num_buffers(q); + bool no_previous_buffers = !q_num_bufs; + int ret = 0; - if (q->num_buffers == VB2_MAX_FRAME) { + if (q_num_bufs == VB2_MAX_FRAME) { dprintk(q, 1, "maximum number of buffers already allocated\n"); return -ENOBUFS; } @@ -1005,7 +1010,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, return -EINVAL; } - num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); + num_buffers = min(*count, VB2_MAX_FRAME - q_num_bufs); if (requested_planes && requested_sizes) { num_planes = requested_planes; @@ -1037,7 +1042,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, num_buffers = allocated_buffers; /* - * q->num_buffers contains the total number of buffers, that the + * num_buffers contains the total number of buffers, that the * queue driver has set up */ ret = call_qop(q, queue_setup, q, &num_buffers, @@ -1058,7 +1063,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, if (ret < 0) { /* * Note: __vb2_queue_free() will subtract 'allocated_buffers' - * from q->num_buffers and it will reset q->memory to + * from already queued buffers and it will reset q->memory to * VB2_MEMORY_UNKNOWN. */ __vb2_queue_free(q, allocated_buffers); @@ -1675,7 +1680,7 @@ static int vb2_start_streaming(struct vb2_queue *q) * Forcefully reclaim buffers if the driver did not * correctly return them to vb2. */ - for (i = 0; i < q->num_buffers; ++i) { + for (i = 0; i < vb2_get_num_buffers(q); ++i) { vb = vb2_get_buffer(q, i); if (!vb) @@ -2081,7 +2086,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * to vb2 in stop_streaming(). */ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { - for (i = 0; i < q->num_buffers; ++i) { + for (i = 0; i < vb2_get_num_buffers(q); i++) { struct vb2_buffer *vb = vb2_get_buffer(q, i); if (!vb) @@ -2125,7 +2130,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * call to __fill_user_buffer() after buf_finish(). That order can't * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ - for (i = 0; i < q->num_buffers; ++i) { + for (i = 0; i < vb2_get_num_buffers(q); i++) { struct vb2_buffer *vb; struct media_request *req; @@ -2173,6 +2178,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) int vb2_core_streamon(struct vb2_queue *q, unsigned int type) { + unsigned int q_num_bufs = vb2_get_num_buffers(q); int ret; if (type != q->type) { @@ -2185,12 +2191,12 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) return 0; } - if (!q->num_buffers) { + if (!q_num_bufs) { dprintk(q, 1, "no buffers have been allocated\n"); return -EINVAL; } - if (q->num_buffers < q->min_buffers_needed) { + if (q_num_bufs < q->min_buffers_needed) { dprintk(q, 1, "need at least %u allocated buffers\n", q->min_buffers_needed); return -EINVAL; @@ -2518,7 +2524,7 @@ void vb2_core_queue_release(struct vb2_queue *q) __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); mutex_lock(&q->mmap_lock); - __vb2_queue_free(q, q->num_buffers); + __vb2_queue_free(q, vb2_get_num_buffers(q)); mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_core_queue_release); @@ -2547,7 +2553,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, /* * Start file I/O emulator only if streaming API has not been used yet. */ - if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { + if (vb2_get_num_buffers(q) == 0 && !vb2_fileio_is_active(q)) { if (!q->is_output && (q->io_modes & VB2_READ) && (req_events & (EPOLLIN | EPOLLRDNORM))) { if (__vb2_init_fileio(q, 1)) @@ -2585,7 +2591,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, * For output streams you can call write() as long as there are fewer * buffers queued than there are buffers available. */ - if (q->is_output && q->fileio && q->queued_count < q->num_buffers) + if (q->is_output && q->fileio && q->queued_count < vb2_get_num_buffers(q)) return EPOLLOUT | EPOLLWRNORM; if (list_empty(&q->done_list)) { @@ -2634,8 +2640,8 @@ struct vb2_fileio_buf { * struct vb2_fileio_data - queue context used by file io emulator * * @cur_index: the index of the buffer currently being read from or - * written to. If equal to q->num_buffers then a new buffer - * must be dequeued. + * written to. If equal to number of buffers in the vb2_queue + * then a new buffer must be dequeued. * @initial_index: in the read() case all buffers are queued up immediately * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles * buffers. However, in the write() case no buffers are initially @@ -2645,9 +2651,9 @@ struct vb2_fileio_buf { * buffers. This means that initially __vb2_perform_fileio() * needs to know what buffer index to use when it is queuing up * the buffers for the first time. That initial index is stored - * in this field. Once it is equal to q->num_buffers all - * available buffers have been queued and __vb2_perform_fileio() - * should start the normal dequeue/queue cycle. + * in this field. Once it is equal to number of buffers in the + * vb2_queue all available buffers have been queued and + * __vb2_perform_fileio() should start the normal dequeue/queue cycle. * * vb2 provides a compatibility layer and emulator of file io (read and * write) calls on top of streaming API. For proper operation it required @@ -2695,7 +2701,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) /* * Check if streaming api has not been already activated. */ - if (q->streaming || q->num_buffers > 0) + if (q->streaming || vb2_get_num_buffers(q) > 0) return -EBUSY; /* @@ -2745,7 +2751,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) /* * Get kernel address of each buffer. */ - for (i = 0; i < q->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(q); i++) { /* vb can never be NULL when using fileio. */ vb = vb2_get_buffer(q, i); @@ -2764,7 +2770,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) /* * Queue all buffers. */ - for (i = 0; i < q->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(q); i++) { struct vb2_buffer *vb2 = vb2_get_buffer(q, i); if (!vb2) @@ -2777,10 +2783,10 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) } /* * All buffers have been queued, so mark that by setting - * initial_index to q->num_buffers + * initial_index to the number of buffers in the vb2_queue */ - fileio->initial_index = q->num_buffers; - fileio->cur_index = q->num_buffers; + fileio->initial_index = vb2_get_num_buffers(q); + fileio->cur_index = fileio->initial_index; } /* @@ -2873,7 +2879,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ * Check if we need to dequeue the buffer. */ index = fileio->cur_index; - if (index >= q->num_buffers) { + if (index >= vb2_get_num_buffers(q)) { struct vb2_buffer *b; /* @@ -2974,14 +2980,14 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ * If we are queuing up buffers for the first time, then * increase initial_index by one. */ - if (fileio->initial_index < q->num_buffers) + if (fileio->initial_index < vb2_get_num_buffers(q)) fileio->initial_index++; /* * The next buffer to use is either a buffer that's going to be - * queued for the first time (initial_index < q->num_buffers) - * or it is equal to q->num_buffers, meaning that the next - * time we need to dequeue a buffer since we've now queued up - * all the 'first time' buffers. + * queued for the first time (initial_index < number of buffers in the vb2_queue) + * or it is equal to the number of buffers in the vb2_queue, + * meaning that the next time we need to dequeue a buffer since + * we've now queued up all the 'first time' buffers. */ fileio->cur_index = fileio->initial_index; } @@ -3026,7 +3032,7 @@ static int vb2_thread(void *data) int ret = 0; if (q->is_output) { - prequeue = q->num_buffers; + prequeue = vb2_get_num_buffers(q); copy_timestamp = q->copy_timestamp; } diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 6ba13a95323c..9d3b828cc804 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -621,7 +621,7 @@ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) * This loop doesn't scale if there is a really large number of buffers. * Maybe something more efficient will be needed in this case. */ - for (i = 0; i < q->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(q); i++) { vb2 = vb2_get_buffer(q, i); if (!vb2) @@ -755,7 +755,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) fill_buf_caps(q, &create->capabilities); validate_memory_flags(q, create->memory, &create->flags); - create->index = q->num_buffers; + create->index = vb2_get_num_buffers(q); if (create->count == 0) return ret != -EBUSY ? ret : 0; From e03bcb28989154de1f8998a9bdd62e9aaaed98d7 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:21 +0100 Subject: [PATCH 1219/7721] media: amphion: Use vb2_get_buffer() instead of directly access to buffers array Use vb2_get_buffer() instead of direct access to the vb2_queue bufs array. This allows us to change the type of the bufs in the future. After each call to vb2_get_buffer() we need to be sure that we get a valid pointer so check the return value of all of them. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ming Qian CC: Zhou Peng Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/vpu_dbg.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index 982c2c777484..a462d6fe4ea9 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); for (i = 0; i < vq->num_buffers; i++) { - struct vb2_buffer *vb = vq->bufs[i]; - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vbuf; + + vb = vb2_get_buffer(vq, i); + if (!vb) + continue; if (vb->state == VB2_BUF_STATE_DEQUEUED) continue; + + vbuf = to_vb2_v4l2_buffer(vb); + num = scnprintf(str, sizeof(str), "output [%2d] state = %10s, %8s\n", i, vb2_stat_name[vb->state], @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); for (i = 0; i < vq->num_buffers; i++) { - struct vb2_buffer *vb = vq->bufs[i]; - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vbuf; + + vb = vb2_get_buffer(vq, i); + if (!vb) + continue; if (vb->state == VB2_BUF_STATE_DEQUEUED) continue; + + vbuf = to_vb2_v4l2_buffer(vb); + num = scnprintf(str, sizeof(str), "capture[%2d] state = %10s, %8s\n", i, vb2_stat_name[vb->state], From 1be718477f29b524becd577f71c815b98fc40788 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:22 +0100 Subject: [PATCH 1220/7721] media: amphion: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ming Qian CC: Zhou Peng Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/vpu_dbg.c | 8 ++++---- drivers/media/platform/amphion/vpu_v4l2.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index a462d6fe4ea9..940e5bda5fa3 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -87,7 +87,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) num = scnprintf(str, sizeof(str), "output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;", vb2_is_streaming(vq), - vq->num_buffers, + vb2_get_num_buffers(vq), inst->out_format.pixfmt, inst->out_format.pixfmt >> 8, inst->out_format.pixfmt >> 16, @@ -111,7 +111,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) num = scnprintf(str, sizeof(str), "capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;", vb2_is_streaming(vq), - vq->num_buffers, + vb2_get_num_buffers(vq), inst->cap_format.pixfmt, inst->cap_format.pixfmt >> 8, inst->cap_format.pixfmt >> 16, @@ -139,7 +139,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) return 0; vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); - for (i = 0; i < vq->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(vq); i++) { struct vb2_buffer *vb; struct vb2_v4l2_buffer *vbuf; @@ -161,7 +161,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) } vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - for (i = 0; i < vq->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(vq); i++) { struct vb2_buffer *vb; struct vb2_v4l2_buffer *vbuf; diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 0f6e4c666440..87afb4a18d5d 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -439,7 +439,7 @@ int vpu_get_num_buffers(struct vpu_inst *inst, u32 type) else q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - return q->num_buffers; + return vb2_get_num_buffers(q); } static void vpu_m2m_device_run(void *priv) @@ -587,7 +587,7 @@ static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count) fmt->sizeimage[0], fmt->bytesperline[0], fmt->sizeimage[1], fmt->bytesperline[1], fmt->sizeimage[2], fmt->bytesperline[2], - q->num_buffers); + vb2_get_num_buffers(q)); vb2_clear_last_buffer_dequeued(q); ret = call_vop(inst, start, q->type); if (ret) From a6e86185188c87465402c282fcc612b204602008 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:23 +0100 Subject: [PATCH 1221/7721] media: mediatek: jpeg: Use vb2_get_buffer() instead of directly access to buffers array Use vb2_get_buffer() instead of direct access to the vb2_queue bufs array. This allows us to change the type of the bufs in the future. After each call to vb2_get_buffer() we need to be sure that we get a valid pointer so check the return value of all of them. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Bin Liu CC: Matthias Brugger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 7194f88edc0f..73a063b1569b 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -598,12 +598,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) goto end; vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type); - if (buf->index >= vq->num_buffers) { - dev_err(ctx->jpeg->dev, "buffer index out of range\n"); + vb = vb2_get_buffer(vq, buf->index); + if (!vb) { + dev_err(ctx->jpeg->dev, "buffer not found\n"); return -EINVAL; } - - vb = vq->bufs[buf->index]; jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); jpeg_src_buf->bs_size = buf->m.planes[0].bytesused; From 066f7c4199acbefeed419ca1d3b70405753d0cef Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:29:24 +0100 Subject: [PATCH 1222/7721] media: mediatek: vdec: Remove useless loop Simplify code by removing useless loop by using video buffer index. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Bin Liu CC: Matthias Brugger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index e393e3e668f8..69d37b93bd35 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -1695,13 +1695,8 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst return -EINVAL; /* update internal buffer's width/height */ - for (i = 0; i < vq->num_buffers; i++) { - if (vb == vq->bufs[i]) { - instance->dpb[i].width = w; - instance->dpb[i].height = h; - break; - } - } + instance->dpb[vb->index].width = w; + instance->dpb[vb->index].height = h; /* * get buffer's width/height from instance From a24d5d8553bcf64ef3e3fb592efec1fb476a641e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:29 +0100 Subject: [PATCH 1223/7721] media: mediatek: vcodec: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Bin Liu CC: Matthias Brugger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index eb381fa6e7d1..181884e798fd 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -912,7 +912,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; err_start_stream: - for (i = 0; i < q->num_buffers; ++i) { + for (i = 0; i < vb2_get_num_buffers(q); ++i) { struct vb2_buffer *buf = vb2_get_buffer(q, i); /* From 7bce685bc017295e96aa3ad5edcf3906208685f3 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:30 +0100 Subject: [PATCH 1224/7721] media: sti: hva: Remove useless check Remove index range test since it is done by vb2_get_buffer(). vb2_get_buffer() can return a NULL pointer so we need the return value. Signed-off-by: Benjamin Gaignard CC: Jean-Christophe Trotin Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/st/sti/hva/hva-v4l2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 3a848ca32a0e..cfe83e9dc01b 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -569,14 +569,11 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) struct vb2_buffer *vb2_buf; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type); - - if (buf->index >= vq->num_buffers) { - dev_dbg(dev, "%s buffer index %d out of range (%d)\n", - ctx->name, buf->index, vq->num_buffers); + vb2_buf = vb2_get_buffer(vq, buf->index); + if (!vb2_buf) { + dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index); return -EINVAL; } - - vb2_buf = vb2_get_buffer(vq, buf->index); stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf)); stream->bytesused = buf->bytesused; } From d73dcff9eb0d30956e9caa86d0d94d4c8e402037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 16:53:02 +0100 Subject: [PATCH 1225/7721] net: ethernet: renesas: rcar_gen4_ptp: Remove incorrect comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comments intent was to indicates which function uses the enum. While upstreaming rcar_gen4_ptp the function was renamed but this comment was left with the old function name. Instead of correcting the comment remove it, it adds little value. Signed-off-by: Niklas Söderlund Reviewed-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/rcar_gen4_ptp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h index b1bbea8d3a52..9f148110df66 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h @@ -13,7 +13,6 @@ #define RCAR_GEN4_PTP_CLOCK_S4 PTPTIVC_INIT #define RCAR_GEN4_GPTP_OFFSET_S4 0x00018000 -/* for rcar_gen4_ptp_init */ enum rcar_gen4_ptp_reg_layout { RCAR_GEN4_PTP_REG_LAYOUT_S4 }; From 9f3995707e355a2f9b2da06f6dee685cca974fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 16:53:03 +0100 Subject: [PATCH 1226/7721] net: ethernet: renesas: rcar_gen4_ptp: Fail on unknown register layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of printing a warning and proceeding with an unknown register layout return an error. The only call site is already prepared to propagate the error. Signed-off-by: Niklas Söderlund Reviewed-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/rcar_gen4_ptp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c index c007e33c47e1..443ca5a18703 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c @@ -130,23 +130,30 @@ static struct ptp_clock_info rcar_gen4_ptp_info = { .enable = rcar_gen4_ptp_enable, }; -static void rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv, - enum rcar_gen4_ptp_reg_layout layout) +static int rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv, + enum rcar_gen4_ptp_reg_layout layout) { - WARN_ON(layout != RCAR_GEN4_PTP_REG_LAYOUT_S4); + if (layout != RCAR_GEN4_PTP_REG_LAYOUT_S4) + return -EINVAL; ptp_priv->offs = &s4_offs; + + return 0; } int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, enum rcar_gen4_ptp_reg_layout layout, u32 clock) { + int ret; + if (ptp_priv->initialized) return 0; spin_lock_init(&ptp_priv->lock); - rcar_gen4_ptp_set_offs(ptp_priv, layout); + ret = rcar_gen4_ptp_set_offs(ptp_priv, layout); + if (ret) + return ret; ptp_priv->default_addend = clock; iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment); From 46c361a04635a9f431fec56a75076cbb5262fb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 16:53:04 +0100 Subject: [PATCH 1227/7721] net: ethernet: renesas: rcar_gen4_ptp: Prepare for shared register layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All known R-Car Gen4 SoC share the same register layout, rename the R-Car S4 specific identifiers so they can be shared with the upcoming R-Car V4H support. Signed-off-by: Niklas Söderlund Reviewed-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/rcar_gen4_ptp.c | 6 +++--- drivers/net/ethernet/renesas/rcar_gen4_ptp.h | 4 ++-- drivers/net/ethernet/renesas/rswitch.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c index 443ca5a18703..59f6351e9ae9 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c @@ -14,7 +14,7 @@ #include "rcar_gen4_ptp.h" #define ptp_to_priv(ptp) container_of(ptp, struct rcar_gen4_ptp_private, info) -static const struct rcar_gen4_ptp_reg_offset s4_offs = { +static const struct rcar_gen4_ptp_reg_offset gen4_offs = { .enable = PTPTMEC, .disable = PTPTMDC, .increment = PTPTIVC0, @@ -133,10 +133,10 @@ static struct ptp_clock_info rcar_gen4_ptp_info = { static int rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv, enum rcar_gen4_ptp_reg_layout layout) { - if (layout != RCAR_GEN4_PTP_REG_LAYOUT_S4) + if (layout != RCAR_GEN4_PTP_REG_LAYOUT) return -EINVAL; - ptp_priv->offs = &s4_offs; + ptp_priv->offs = &gen4_offs; return 0; } diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h index 9f148110df66..35664d1dc472 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h @@ -14,7 +14,7 @@ #define RCAR_GEN4_GPTP_OFFSET_S4 0x00018000 enum rcar_gen4_ptp_reg_layout { - RCAR_GEN4_PTP_REG_LAYOUT_S4 + RCAR_GEN4_PTP_REG_LAYOUT }; /* driver's definitions */ @@ -27,7 +27,7 @@ enum rcar_gen4_ptp_reg_layout { #define PTPRO 0 -enum rcar_gen4_ptp_reg_s4 { +enum rcar_gen4_ptp_reg { PTPTMEC = PTPRO + 0x0010, PTPTMDC = PTPRO + 0x0014, PTPTIVC0 = PTPRO + 0x0020, diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 43a7795d6591..e1e29a2caf22 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1828,7 +1828,7 @@ static int rswitch_init(struct rswitch_private *priv) rswitch_fwd_init(priv); - err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT_S4, + err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT, RCAR_GEN4_PTP_CLOCK_S4); if (err < 0) goto err_ptp_register; From be5f81d37f7971abbad8547624453a1d4f033457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 16:53:05 +0100 Subject: [PATCH 1228/7721] net: ethernet: renesas: rcar_gen4_ptp: Get clock increment from clock rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using hard coded clock increment values for each SoC derive the clock increment from the module clock. This is done in preparation to support a second platform, R-Car V4H that uses a 200Mhz clock compared with the 320Mhz clock used on R-Car S4. Tested on both SoCs, S4 reports a clock of 320000000Hz which gives a value of 0x19000000. Documentation says a 320Mhz clock is used and the correct increment for that clock is 0x19000000. V4H reports a clock of 199999992Hz which gives a value of 0x2800001a. Documentation says a 200Mhz clock is used and the correct increment for that clock is 0x28000000. Suggested-by: Geert Uytterhoeven Signed-off-by: Niklas Söderlund Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/rcar_gen4_ptp.c | 14 ++++++++++++-- drivers/net/ethernet/renesas/rcar_gen4_ptp.h | 4 +--- drivers/net/ethernet/renesas/rswitch.c | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c index 59f6351e9ae9..9583894634ae 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c @@ -141,8 +141,18 @@ static int rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv, return 0; } +static s64 rcar_gen4_ptp_rate_to_increment(u32 rate) +{ + /* Timer increment in ns. + * bit[31:27] - integer + * bit[26:0] - decimal + * increment[ns] = perid[ns] * 2^27 => (1ns * 2^27) / rate[hz] + */ + return div_s64(1000000000LL << 27, rate); +} + int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, - enum rcar_gen4_ptp_reg_layout layout, u32 clock) + enum rcar_gen4_ptp_reg_layout layout, u32 rate) { int ret; @@ -155,7 +165,7 @@ int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, if (ret) return ret; - ptp_priv->default_addend = clock; + ptp_priv->default_addend = rcar_gen4_ptp_rate_to_increment(rate); iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment); ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL); if (IS_ERR(ptp_priv->clock)) diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h index 35664d1dc472..e22da5acd53d 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h @@ -9,8 +9,6 @@ #include -#define PTPTIVC_INIT 0x19000000 /* 320MHz */ -#define RCAR_GEN4_PTP_CLOCK_S4 PTPTIVC_INIT #define RCAR_GEN4_GPTP_OFFSET_S4 0x00018000 enum rcar_gen4_ptp_reg_layout { @@ -64,7 +62,7 @@ struct rcar_gen4_ptp_private { }; int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, - enum rcar_gen4_ptp_reg_layout layout, u32 clock); + enum rcar_gen4_ptp_reg_layout layout, u32 rate); int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv); struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev); diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index e1e29a2caf22..d6089429f654 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1829,7 +1829,7 @@ static int rswitch_init(struct rswitch_private *priv) rswitch_fwd_init(priv); err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT, - RCAR_GEN4_PTP_CLOCK_S4); + clk_get_rate(priv->clk)); if (err < 0) goto err_ptp_register; From 8c1c66235e0354fbe8c2159656947fad048d374d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 16:53:06 +0100 Subject: [PATCH 1229/7721] net: ethernet: renesas: rcar_gen4_ptp: Break out to module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Gen4 gPTP support will be shared between the existing Renesas Ethernet Switch driver and the upcoming Renesas Ethernet-TSN driver. In preparation for this break out the gPTP support to its own module. Signed-off-by: Niklas Söderlund Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/Kconfig | 9 +++++++++ drivers/net/ethernet/renesas/Makefile | 5 +++-- drivers/net/ethernet/renesas/rcar_gen4_ptp.c | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig index 8ef5b0241e64..733cbb6eb3ed 100644 --- a/drivers/net/ethernet/renesas/Kconfig +++ b/drivers/net/ethernet/renesas/Kconfig @@ -44,7 +44,16 @@ config RENESAS_ETHER_SWITCH select CRC32 select MII select PHYLINK + select RENESAS_GEN4_PTP help Renesas Ethernet Switch device driver. +config RENESAS_GEN4_PTP + tristate "Renesas R-Car Gen4 gPTP support" if COMPILE_TEST + select CRC32 + select MII + select PHYLIB + help + Renesas R-Car Gen4 gPTP device driver. + endif # NET_VENDOR_RENESAS diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/renesas/Makefile index e8fd85b5fe8f..9070acfd6aaf 100644 --- a/drivers/net/ethernet/renesas/Makefile +++ b/drivers/net/ethernet/renesas/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o ravb-objs := ravb_main.o ravb_ptp.o obj-$(CONFIG_RAVB) += ravb.o -rswitch_drv-objs := rswitch.o rcar_gen4_ptp.o -obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch_drv.o +obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch.o + +obj-$(CONFIG_RENESAS_GEN4_PTP) += rcar_gen4_ptp.o diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c index 9583894634ae..72e7fcc56693 100644 --- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c +++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c @@ -176,6 +176,7 @@ int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, return 0; } +EXPORT_SYMBOL_GPL(rcar_gen4_ptp_register); int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv) { @@ -183,6 +184,7 @@ int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv) return ptp_clock_unregister(ptp_priv->clock); } +EXPORT_SYMBOL_GPL(rcar_gen4_ptp_unregister); struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev) { @@ -196,3 +198,8 @@ struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev) return ptp; } +EXPORT_SYMBOL_GPL(rcar_gen4_ptp_alloc); + +MODULE_AUTHOR("Yoshihiro Shimoda"); +MODULE_DESCRIPTION("Renesas R-Car Gen4 gPTP driver"); +MODULE_LICENSE("GPL"); From 73aea586d6c58f55799f6130e19321ff7b574c3d Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:31 +0100 Subject: [PATCH 1230/7721] media: visl: Use vb2_get_buffer() instead of directly access to buffers array Use vb2_get_buffer() instead of direct access to the vb2_queue bufs array. This allows us to change the type of the bufs in the future. After each call to vb2_get_buffer() we need to be sure that we get a valid pointer so check the return value of all of them. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/visl/visl-dec.c | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c index 318d675e5668..ba20ea998d19 100644 --- a/drivers/media/test-drivers/visl/visl-dec.c +++ b/drivers/media/test-drivers/visl/visl-dec.c @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run) for (i = 0; i < out_q->num_buffers; i++) { char entry[] = "index: %u, state: %s, request_fd: %d, "; u32 old_len = len; - char *q_status = visl_get_vb2_state(out_q->bufs[i]->state); + struct vb2_buffer *vb2; + char *q_status; + + vb2 = vb2_get_buffer(out_q, i); + if (!vb2) + continue; + + q_status = visl_get_vb2_state(vb2->state); len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len, entry, i, q_status, - to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd); + to_vb2_v4l2_buffer(vb2)->request_fd); - len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]), + len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2), &buf[len], TPG_STR_BUF_SZ - len); @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run) len = 0; for (i = 0; i < cap_q->num_buffers; i++) { u32 old_len = len; - char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state); + struct vb2_buffer *vb2; + char *q_status; + + vb2 = vb2_get_buffer(cap_q, i); + if (!vb2) + continue; + + q_status = visl_get_vb2_state(vb2->state); len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len, "index: %u, status: %s, timestamp: %llu, is_held: %d", - cap_q->bufs[i]->index, q_status, - cap_q->bufs[i]->timestamp, - to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held); + vb2->index, q_status, + vb2->timestamp, + to_vb2_v4l2_buffer(vb2)->is_held); tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]); frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]); From 202de2b5d1b6ba12ab95fe3d6ea2a428888e59b4 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:32 +0100 Subject: [PATCH 1231/7721] media: atomisp: Use vb2_get_buffer() instead of directly access to buffers array Use vb2_get_buffer() instead of direct access to the vb2_queue bufs array. This allows us to change the type of the bufs in the future. No need to check the result of vb2_get_buffer, vb2_ioctl_dqbuf() already checked that it is valid. Signed-off-by: Benjamin Gaignard Reviewed-by: Hans de Goede CC: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index a8e4779d007f..a8a964b2f1a8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -1059,7 +1059,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer if (ret) return ret; - vb = pipe->vb_queue.bufs[buf->index]; + vb = vb2_get_buffer(&pipe->vb_queue, buf->index); frame = vb_to_frame(vb); buf->reserved = asd->frame_status[buf->index]; From 53963fb12fd43176dff4b33d937fb7575b0bf4fb Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:33 +0100 Subject: [PATCH 1232/7721] media: atomisp: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Hans de Goede CC: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index a8a964b2f1a8..09c0091b920f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -1028,7 +1028,7 @@ static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - if (buf->index >= vdev->queue->num_buffers) + if (buf->index >= vb2_get_num_buffers(vdev->queue)) return -EINVAL; if (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING) { From 7dc866df40127dceac9ba83ae16c0c11e7d1666f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:34 +0100 Subject: [PATCH 1233/7721] media: dvb-core: Use vb2_get_buffer() instead of directly access to buffers array Use vb2_get_buffer() instead of direct access to the vb2_queue bufs array. This allows us to change the type of the bufs in the future. After each call to vb2_get_buffer() we need to be sure that we get a valid pointer so check the return value of all of them. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_vb2.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index b322ef179f05..3a966fdf814c 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -355,12 +355,13 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req) int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) { struct vb2_queue *q = &ctx->vb_q; + struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index); - if (b->index >= q->num_buffers) { - dprintk(1, "[%s] buffer index out of range\n", ctx->name); + if (!vb2) { + dprintk(1, "[%s] invalid buffer index\n", ctx->name); return -EINVAL; } - vb2_core_querybuf(&ctx->vb_q, q->bufs[b->index], b); + vb2_core_querybuf(&ctx->vb_q, vb2, b); dprintk(3, "[%s] index=%d\n", ctx->name, b->index); return 0; } @@ -385,13 +386,14 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp) int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) { struct vb2_queue *q = &ctx->vb_q; + struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index); int ret; - if (b->index >= q->num_buffers) { - dprintk(1, "[%s] buffer index out of range\n", ctx->name); + if (!vb2) { + dprintk(1, "[%s] invalid buffer index\n", ctx->name); return -EINVAL; } - ret = vb2_core_qbuf(&ctx->vb_q, q->bufs[b->index], b, NULL); + ret = vb2_core_qbuf(&ctx->vb_q, vb2, b, NULL); if (ret) { dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, b->index, ret); From b3b5d2e2297216d5184560583f01f078ce631b75 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:35 +0100 Subject: [PATCH 1234/7721] media: dvb-core: Do not initialize twice queue num_buffer field The above memset already zeroed all the ctx fields, it is useless to do it here again. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_vb2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 3a966fdf814c..167ff82a6fed 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -167,8 +167,6 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking) memset(ctx, 0, sizeof(struct dvb_vb2_ctx)); q->type = DVB_BUF_TYPE_CAPTURE; - /**capture type*/ - q->is_output = 0; /**only mmap is supported currently*/ q->io_modes = VB2_MMAP; q->drv_priv = ctx; @@ -177,7 +175,6 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking) q->ops = &dvb_vb2_qops; q->mem_ops = &vb2_vmalloc_memops; q->buf_ops = &dvb_vb2_buf_ops; - q->num_buffers = 0; ret = vb2_core_queue_init(q); if (ret) { ctx->state = DVB_VB2_STATE_NONE; From 595f445b8f061d1cde2acdef8dfe59c832c20939 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:36 +0100 Subject: [PATCH 1235/7721] media: dvb-frontends: rtl2832: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Antti Palosaari Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 02c619e51641..023db6e793f8 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -439,12 +439,13 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, { struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); struct platform_device *pdev = dev->pdev; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(&pdev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ - if (vq->num_buffers + *nbuffers < 8) - *nbuffers = 8 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 8) + *nbuffers = 8 - q_num_bufs; *nplanes = 1; sizes[0] = PAGE_ALIGN(dev->buffersize); dev_dbg(&pdev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); From cf605a01f03e0aae9ee5df5ab5acaf2877b62e3f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:37 +0100 Subject: [PATCH 1236/7721] media: pci: dt3155: Remove useless check min_buffers_needed is already set to 2 so remove this useless check. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/dt3155/dt3155.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 548156b199cc..d09cde2f6ee4 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -128,8 +128,6 @@ dt3155_queue_setup(struct vb2_queue *vq, struct dt3155_priv *pd = vb2_get_drv_priv(vq); unsigned size = pd->width * pd->height; - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; if (*num_planes) return sizes[0] < size ? -EINVAL : 0; *num_planes = 1; From ba53e3b9bd8d829616523aed13ced6052de517b6 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:38 +0100 Subject: [PATCH 1237/7721] media: pci: tw686x: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw686x/tw686x-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 3ebf7a2c95f0..6bc6d143d18c 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -423,6 +423,7 @@ static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); unsigned int szimage = (vc->width * vc->height * vc->format->depth) >> 3; @@ -430,8 +431,8 @@ static int tw686x_queue_setup(struct vb2_queue *vq, * Let's request at least three buffers: two for the * DMA engine and one for userspace. */ - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) { if (*nplanes != 1 || sizes[0] < szimage) From ad3d85a1359bcc67fd57edffb3bc367b38045592 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:39 +0100 Subject: [PATCH 1238/7721] media: pci: cx18: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Sergey Kozlov CC: Abylay Ospan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-streams.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 597472754c4c..cfbc4a907802 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -104,6 +104,7 @@ static int cx18_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { + unsigned int q_num_bufs = vb2_get_num_buffers(vq); struct cx18_stream *s = vb2_get_drv_priv(vq); struct cx18 *cx = s->cx; unsigned int szimage; @@ -121,8 +122,8 @@ static int cx18_queue_setup(struct vb2_queue *vq, * Let's request at least three buffers: two for the * DMA engine and one for userspace. */ - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) { if (*nplanes != 1 || sizes[0] < szimage) From 58415c7e52a6d6245f0afa679e8ec8b78da1523c Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:40 +0100 Subject: [PATCH 1239/7721] media: pci: netup_unidvb: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Sergey Kozlov CC: Abylay Ospan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index d85bfbb77a25..557985ba25db 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -293,12 +293,13 @@ static int netup_unidvb_queue_setup(struct vb2_queue *vq, struct device *alloc_devs[]) { struct netup_dma *dma = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(&dma->ndev->pci_dev->dev, "%s()\n", __func__); *nplanes = 1; - if (vq->num_buffers + *nbuffers < VIDEO_MAX_FRAME) - *nbuffers = VIDEO_MAX_FRAME - vq->num_buffers; + if (q_num_bufs + *nbuffers < VIDEO_MAX_FRAME) + *nbuffers = VIDEO_MAX_FRAME - q_num_bufs; sizes[0] = PAGE_ALIGN(NETUP_DMA_PACKETS_COUNT * 188); dev_dbg(&dma->ndev->pci_dev->dev, "%s() nbuffers=%d sizes[0]=%d\n", __func__, *nbuffers, sizes[0]); From 70ab9ec9166db90ab8980aff4f7083512ecddd1f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:41 +0100 Subject: [PATCH 1240/7721] media: pci: tw68: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard CC: Fabrizio Castro Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 773a18702d36..79b627ebc92a 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -360,13 +360,14 @@ static int tw68_queue_setup(struct vb2_queue *q, unsigned int sizes[], struct device *alloc_devs[]) { struct tw68_dev *dev = vb2_get_drv_priv(q); - unsigned tot_bufs = q->num_buffers + *num_buffers; + unsigned int q_num_bufs = vb2_get_num_buffers(q); + unsigned int tot_bufs = q_num_bufs + *num_buffers; unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3; if (tot_bufs < 2) tot_bufs = 2; tot_bufs = tw68_buffer_count(size, tot_bufs); - *num_buffers = tot_bufs - q->num_buffers; + *num_buffers = tot_bufs - q_num_bufs; /* * We allow create_bufs, but only if the sizeimage is >= as the * current sizeimage. The tw68_buffer_count calculation becomes quite From da53f4e6fa861bc8d454db3551f807b4a86bbb02 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:42 +0100 Subject: [PATCH 1241/7721] media: i2c: video-i2c: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Fix the number of buffers computation at the same time. Signed-off-by: Benjamin Gaignard CC: Matt Ranostay Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/video-i2c.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 178bd06cc2ed..ebf2ac98a068 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -405,9 +405,10 @@ static int queue_setup(struct vb2_queue *vq, { struct video_i2c_data *data = vb2_get_drv_priv(vq); unsigned int size = data->chip->buffer_size; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2; + if (q_num_bufs + *nbuffers < 2) + *nbuffers = 2 - q_num_bufs; if (*nplanes) return sizes[0] < size ? -EINVAL : 0; From efd7ae5d95caac9ece5b2dfac0d90a574111d3bf Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:43 +0100 Subject: [PATCH 1242/7721] media: coda: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/chips-media/coda/coda-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index cc4892129aaf..f1d85758f6dd 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -794,7 +794,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, if (vb2_is_busy(vq)) { v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n", - __func__, v4l2_type_names[f->type], vq->num_buffers); + __func__, v4l2_type_names[f->type], vb2_get_num_buffers(vq)); return -EBUSY; } From 3f9ea948f1690a6bfa6e8730c74b325d38f8ce26 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:44 +0100 Subject: [PATCH 1243/7721] media: nxp: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Rui Miguel Silva CC: Laurent Pinchart CC: Martin Kepplinger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 15049c6aab37..4c467fb82789 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1245,6 +1245,7 @@ static int imx7_csi_video_queue_setup(struct vb2_queue *vq, struct device *alloc_devs[]) { struct imx7_csi *csi = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); struct v4l2_pix_format *pix = &csi->vdev_fmt; unsigned int count = *nbuffers; @@ -1254,14 +1255,14 @@ static int imx7_csi_video_queue_setup(struct vb2_queue *vq, if (*nplanes) { if (*nplanes != 1 || sizes[0] < pix->sizeimage) return -EINVAL; - count += vq->num_buffers; + count += q_num_bufs; } count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count); if (*nplanes) - *nbuffers = (count < vq->num_buffers) ? 0 : - count - vq->num_buffers; + *nbuffers = (count < q_num_bufs) ? 0 : + count - q_num_bufs; else *nbuffers = count; From 8f661dc7e779bbd51acd20b2cecf9acb430774a0 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:45 +0100 Subject: [PATCH 1244/7721] media: verisilicon: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_postproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c index 64d6fb852ae9..8f8f17e671ce 100644 --- a/drivers/media/platform/verisilicon/hantro_postproc.c +++ b/drivers/media/platform/verisilicon/hantro_postproc.c @@ -195,7 +195,7 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q; - unsigned int num_buffers = cap_queue->num_buffers; + unsigned int num_buffers = vb2_get_num_buffers(cap_queue); struct v4l2_pix_format_mplane pix_mp; const struct hantro_fmt *fmt; unsigned int i, buf_size; From 46cbe0cd4cfbbab4673411230c8de260fe67c064 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:46 +0100 Subject: [PATCH 1245/7721] media: test-drivers: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. If 'min_buffers_needed' is set remove useless checks in queue setup functions. Signed-off-by: Benjamin Gaignard CC: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/visl/visl-dec.c | 4 ++-- drivers/media/test-drivers/vivid/vivid-meta-cap.c | 3 --- drivers/media/test-drivers/vivid/vivid-meta-out.c | 5 +++-- drivers/media/test-drivers/vivid/vivid-touch-cap.c | 5 +++-- drivers/media/test-drivers/vivid/vivid-vbi-cap.c | 3 --- drivers/media/test-drivers/vivid/vivid-vbi-out.c | 3 --- drivers/media/test-drivers/vivid/vivid-vid-cap.c | 3 --- drivers/media/test-drivers/vivid/vivid-vid-out.c | 5 +---- 8 files changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c index ba20ea998d19..4672dc5e52bb 100644 --- a/drivers/media/test-drivers/visl/visl-dec.c +++ b/drivers/media/test-drivers/visl/visl-dec.c @@ -287,7 +287,7 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run) frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf); len = 0; - for (i = 0; i < out_q->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(out_q); i++) { char entry[] = "index: %u, state: %s, request_fd: %d, "; u32 old_len = len; struct vb2_buffer *vb2; @@ -347,7 +347,7 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run) frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf); len = 0; - for (i = 0; i < cap_q->num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(cap_q); i++) { u32 old_len = len; struct vb2_buffer *vb2; char *q_status; diff --git a/drivers/media/test-drivers/vivid/vivid-meta-cap.c b/drivers/media/test-drivers/vivid/vivid-meta-cap.c index 780f96860a6d..0a718d037e59 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-cap.c @@ -30,9 +30,6 @@ static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, sizes[0] = size; } - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - *nplanes = 1; return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 95835b52b58f..4a569a6e58be 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -18,6 +18,7 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); unsigned int size = sizeof(struct vivid_meta_out_buf); if (!vivid_is_webcam(dev)) @@ -30,8 +31,8 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, sizes[0] = size; } - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 2) + *nbuffers = 2 - q_num_bufs; *nplanes = 1; return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c index c7f6e23df51e..4b3c6ea0afde 100644 --- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c @@ -13,6 +13,7 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); struct v4l2_pix_format *f = &dev->tch_format; unsigned int size = f->sizeimage; @@ -23,8 +24,8 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, sizes[0] = size; } - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 2) + *nbuffers = 2 - q_num_bufs; *nplanes = 1; return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c index b65b02eeeb97..3840b3a664ac 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c @@ -134,9 +134,6 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq, sizes[0] = size; - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - *nplanes = 1; return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c index cd56476902a2..434a10676417 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c @@ -30,9 +30,6 @@ static int vbi_out_queue_setup(struct vb2_queue *vq, sizes[0] = size; - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - *nplanes = 1; return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index 3a06df35a2d7..2804975fe278 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -117,9 +117,6 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, dev->fmt_cap->data_offset[p]; } - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - *nplanes = buffers; dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index 184a6df2c29f..1653b2988f7e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -73,12 +73,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, vfmt->data_offset[p] : size; } - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - *nplanes = planes; - dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + dprintk(dev, 1, "%s: count=%u\n", __func__, *nbuffers); for (p = 0; p < planes; p++) dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); return 0; From 9d5ffd498dcb94cdf42cadd4b8e97e86ca7abb12 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:47 +0100 Subject: [PATCH 1246/7721] media: imx: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Steve Longerbeam CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-capture.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index 4846078315ff..ce02199e7b1b 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -605,6 +605,7 @@ static int capture_queue_setup(struct vb2_queue *vq, { struct capture_priv *priv = vb2_get_drv_priv(vq); struct v4l2_pix_format *pix = &priv->vdev.fmt; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); unsigned int count = *nbuffers; if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -613,14 +614,14 @@ static int capture_queue_setup(struct vb2_queue *vq, if (*nplanes) { if (*nplanes != 1 || sizes[0] < pix->sizeimage) return -EINVAL; - count += vq->num_buffers; + count += q_num_bufs; } count = min_t(__u32, VID_MEM_LIMIT / pix->sizeimage, count); if (*nplanes) - *nbuffers = (count < vq->num_buffers) ? 0 : - count - vq->num_buffers; + *nbuffers = (count < q_num_bufs) ? 0 : + count - q_num_bufs; else *nbuffers = count; From 8858adab5004d3e7d2370d822621d23b07aaa371 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:48 +0100 Subject: [PATCH 1247/7721] media: meson: vdec: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/vdec.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 219185aaa588..1e2369f104c8 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -167,22 +167,23 @@ static void process_num_buffers(struct vb2_queue *q, bool is_reqbufs) { const struct amvdec_format *fmt_out = sess->fmt_out; - unsigned int buffers_total = q->num_buffers + *num_buffers; + unsigned int q_num_bufs = vb2_get_num_buffers(q); + unsigned int buffers_total = q_num_bufs + *num_buffers; u32 min_buf_capture = v4l2_ctrl_g_ctrl(sess->ctrl_min_buf_capture); - if (q->num_buffers + *num_buffers < min_buf_capture) - *num_buffers = min_buf_capture - q->num_buffers; + if (q_num_bufs + *num_buffers < min_buf_capture) + *num_buffers = min_buf_capture - q_num_bufs; if (is_reqbufs && buffers_total < fmt_out->min_buffers) - *num_buffers = fmt_out->min_buffers - q->num_buffers; + *num_buffers = fmt_out->min_buffers - q_num_bufs; if (buffers_total > fmt_out->max_buffers) - *num_buffers = fmt_out->max_buffers - q->num_buffers; + *num_buffers = fmt_out->max_buffers - q_num_bufs; /* We need to program the complete CAPTURE buffer list * in registers during start_streaming, and the firmwares * are free to choose any of them to write frames to. As such, * we need all of them to be queued into the driver */ - sess->num_dst_bufs = q->num_buffers + *num_buffers; + sess->num_dst_bufs = q_num_bufs + *num_buffers; q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs); } From 11678528576e5e9ac857e0faa656fa2b00cda0d3 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:49 +0100 Subject: [PATCH 1248/7721] media: touchscreen: sur40: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Acked-by: Dmitry Torokhov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/input/touchscreen/sur40.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 8ddb3f7d307a..e7d2a52169a0 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -847,9 +847,10 @@ static int sur40_queue_setup(struct vb2_queue *q, unsigned int sizes[], struct device *alloc_devs[]) { struct sur40_state *sur40 = vb2_get_drv_priv(q); + unsigned int q_num_bufs = vb2_get_num_buffers(q); - if (q->num_buffers + *nbuffers < 3) - *nbuffers = 3 - q->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) return sizes[0] < sur40->pix_fmt.sizeimage ? -EINVAL : 0; From 88d9ce34a6aa19620911c4e149d99d40307b9f72 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:50 +0100 Subject: [PATCH 1249/7721] media: sample: v4l: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- samples/v4l/v4l2-pci-skeleton.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index a61f94db18d9..a65aa9d1e9da 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -155,6 +155,7 @@ static int queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct skeleton *skel = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); skel->field = skel->format.field; if (skel->field == V4L2_FIELD_ALTERNATE) { @@ -167,8 +168,8 @@ static int queue_setup(struct vb2_queue *vq, skel->field = V4L2_FIELD_TOP; } - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) return sizes[0] < skel->format.sizeimage ? -EINVAL : 0; From e1d2fcf99d7ab03e8928391abc9156d79d60dedd Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:51 +0100 Subject: [PATCH 1250/7721] media: cedrus: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. While at it, check the return value of vb2_get_buffer(). Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Acked-by: Paul Kocialkowski CC: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 9 +++++++-- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index dfb401df138a..3e2843ef6cce 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -653,8 +653,13 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx) vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - for (i = 0; i < vq->num_buffers; i++) { - buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i)); + for (i = 0; i < vb2_get_num_buffers(vq); i++) { + struct vb2_buffer *vb = vb2_get_buffer(vq, i); + + if (!vb) + continue; + + buf = vb2_to_cedrus_buffer(vb); if (buf->codec.h264.mv_col_buf_size > 0) { dma_free_attrs(dev->dev, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index fc9297232456..52e94c8f2f01 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -869,8 +869,13 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx) vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - for (i = 0; i < vq->num_buffers; i++) { - buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i)); + for (i = 0; i < vb2_get_num_buffers(vq); i++) { + struct vb2_buffer *vb = vb2_get_buffer(vq, i); + + if (!vb) + continue; + + buf = vb2_to_cedrus_buffer(vb); if (buf->codec.h265.mv_col_buf_size > 0) { dma_free_attrs(dev->dev, From d6855e4b086538ba513aff280f461971d6c26796 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:52 +0100 Subject: [PATCH 1251/7721] media: nuvoton: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Joseph Liu CC: Marvin Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nuvoton/npcm-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index b9e6782f59b4..f9b4e36a5175 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -393,7 +393,7 @@ static void npcm_video_free_diff_table(struct npcm_video *video) struct rect_list *tmp; unsigned int i; - for (i = 0; i < video->queue.num_buffers; i++) { + for (i = 0; i < vb2_get_num_buffers(&video->queue); i++) { head = &video->list[i]; list_for_each_safe(pos, nx, head) { tmp = list_entry(pos, struct rect_list, list); From 36e3faf99f825fd9d975ae0bf96d93e4da1d732f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:53 +0100 Subject: [PATCH 1252/7721] media: renesas: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Fabrizio Castro Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas/rcar_drif.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 292c5bf9e50c..f21d05054341 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -424,10 +424,11 @@ static int rcar_drif_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); /* Need at least 16 buffers */ - if (vq->num_buffers + *num_buffers < 16) - *num_buffers = 16 - vq->num_buffers; + if (q_num_bufs + *num_buffers < 16) + *num_buffers = 16 - q_num_bufs; *num_planes = 1; sizes[0] = PAGE_ALIGN(sdr->fmt->buffersize); From ff2560f0263ab30e8ed4bec13495dce050e5d8cc Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:54 +0100 Subject: [PATCH 1253/7721] media: ti: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: "Lad, Prabhakar" Reviewed-by: Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/am437x/am437x-vpfe.c | 5 +++-- drivers/media/platform/ti/cal/cal-video.c | 5 +++-- drivers/media/platform/ti/davinci/vpif_capture.c | 5 +++-- drivers/media/platform/ti/davinci/vpif_display.c | 5 +++-- drivers/media/platform/ti/omap/omap_vout.c | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 5fa2ea9025d9..f18acf9286a2 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -1771,9 +1771,10 @@ static int vpfe_queue_setup(struct vb2_queue *vq, { struct vpfe_device *vpfe = vb2_get_drv_priv(vq); unsigned size = vpfe->fmt.fmt.pix.sizeimage; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) { if (sizes[0] < size) diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index a8abcd0fee17..94e67c057a20 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -603,9 +603,10 @@ static int cal_queue_setup(struct vb2_queue *vq, { struct cal_ctx *ctx = vb2_get_drv_priv(vq); unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; if (*nplanes) { if (sizes[0] < size) diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index 99fae8830c41..fc42b4bc37e6 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -113,6 +113,7 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, struct channel_obj *ch = vb2_get_drv_priv(vq); struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; unsigned size = common->fmt.fmt.pix.sizeimage; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); vpif_dbg(2, debug, "vpif_buffer_setup\n"); @@ -122,8 +123,8 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, size = sizes[0]; } - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; *nplanes = 1; sizes[0] = size; diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index f8ec2991c667..9dbab1003c1d 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -115,6 +115,7 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, struct channel_obj *ch = vb2_get_drv_priv(vq); struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; unsigned size = common->fmt.fmt.pix.sizeimage; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); if (*nplanes) { if (sizes[0] < size) @@ -122,8 +123,8 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, size = sizes[0]; } - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 3) + *nbuffers = 3 - q_num_bufs; *nplanes = 1; sizes[0] = size; diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c index 4143274089c3..72ce903717d3 100644 --- a/drivers/media/platform/ti/omap/omap_vout.c +++ b/drivers/media/platform/ti/omap/omap_vout.c @@ -944,10 +944,11 @@ static int omap_vout_vb2_queue_setup(struct vb2_queue *vq, struct device *alloc_devs[]) { struct omap_vout_device *vout = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); int size = vout->pix.sizeimage; - if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) { - *nbufs = VRFB_NUM_BUFS - vq->num_buffers; + if (is_rotation_enabled(vout) && q_num_bufs + *nbufs > VRFB_NUM_BUFS) { + *nbufs = VRFB_NUM_BUFS - q_num_bufs; if (*nbufs == 0) return -EINVAL; } From 912472fd07da4be0de80b49d61b8cb4fb1b0835b Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:55 +0100 Subject: [PATCH 1254/7721] media: usb: airspy: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 462eb8423506..e24e655fb1db 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -482,12 +482,13 @@ static int airspy_queue_setup(struct vb2_queue *vq, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct airspy *s = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ - if (vq->num_buffers + *nbuffers < 8) - *nbuffers = 8 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 8) + *nbuffers = 8 - q_num_bufs; *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); From ca44d57a7020a45086c5a947eb72a33b2c1081ef Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:56 +0100 Subject: [PATCH 1255/7721] media: usb: cx231xx: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 5 +++-- drivers/media/usb/cx231xx/cx231xx-video.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index fe4410a5e128..45973fe690b2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1218,12 +1218,13 @@ static int queue_setup(struct vb2_queue *vq, { struct cx231xx *dev = vb2_get_drv_priv(vq); unsigned int size = mpeglinesize * mpeglines; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev->ts1.ts_packet_size = mpeglinesize; dev->ts1.ts_packet_count = mpeglines; - if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) - *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; + if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - q_num_bufs; if (*nplanes) return sizes[0] < size ? -EINVAL : 0; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index e23b8ccd79d4..c8eb4222319d 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -714,11 +714,12 @@ static int queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct cx231xx *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3; - if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) - *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; + if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - q_num_bufs; if (*nplanes) return sizes[0] < dev->size ? -EINVAL : 0; From 7e17d44d61921cab8e52cb30cc082e3ee96abddd Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:57 +0100 Subject: [PATCH 1256/7721] media: usb: hackrf: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Antti Palosaari Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hackrf/hackrf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 3e535be2c520..9c0ecd5f056c 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -753,12 +753,13 @@ static int hackrf_queue_setup(struct vb2_queue *vq, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct hackrf_dev *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ - if (vq->num_buffers + *nbuffers < 8) - *nbuffers = 8 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 8) + *nbuffers = 8 - q_num_bufs; *nplanes = 1; sizes[0] = PAGE_ALIGN(dev->buffersize); From 4545ca51dd5bd1a652d514a5de9e8ec97579a5b1 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:58 +0100 Subject: [PATCH 1257/7721] media: usb: usbtv: Stop direct calls to queue num_buffers field Use vb2_get_num_buffers() to avoid using queue num_buffers field directly. This allows us to change how the number of buffers is computed in the future. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 1e30e05953dc..62a583040cd4 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -726,9 +726,10 @@ static int usbtv_queue_setup(struct vb2_queue *vq, { struct usbtv *usbtv = vb2_get_drv_priv(vq); unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 2) + *nbuffers = 2 - q_num_bufs; if (*nplanes) return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; From c838530d230bc638d79b78737fc4488ffc28c1ee Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:34:59 +0100 Subject: [PATCH 1258/7721] media: media videobuf2: Be more flexible on the number of queue stored buffers Add 'max_num_buffers' field in vb2_queue struct to let drivers decide how many buffers could be stored in a queue. This require 'bufs' array to be allocated at queue init time and freed when releasing the queue. By default VB2_MAX_FRAME remains the limit. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 46 +++++++++++++++---- .../media/common/videobuf2/videobuf2-v4l2.c | 6 +-- include/media/videobuf2-core.h | 12 ++++- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index ce5b84b9bcd4..8c1df829745b 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -421,7 +421,7 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) */ static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index) { - WARN_ON(index >= VB2_MAX_FRAME || q->bufs[index] || vb->vb2_queue); + WARN_ON(index >= q->max_num_buffers || q->bufs[index] || vb->vb2_queue); q->bufs[index] = vb; vb->index = index; @@ -454,9 +454,12 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, struct vb2_buffer *vb; int ret; - /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */ + /* + * Ensure that the number of already queue + the number of buffers already + * in the queue is below q->max_num_buffers + */ num_buffers = min_t(unsigned int, num_buffers, - VB2_MAX_FRAME - q_num_buffers); + q->max_num_buffers - q_num_buffers); for (buffer = 0; buffer < num_buffers; ++buffer) { /* Allocate vb2 buffer structures */ @@ -818,7 +821,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned plane_sizes[VB2_MAX_PLANES] = { }; bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; unsigned int i; - int ret; + int ret = 0; if (q->streaming) { dprintk(q, 1, "streaming active\n"); @@ -862,17 +865,22 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, /* * Make sure the requested values and current defaults are sane. */ - WARN_ON(q->min_buffers_needed > VB2_MAX_FRAME); num_buffers = max_t(unsigned int, *count, q->min_buffers_needed); - num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME); + num_buffers = min_t(unsigned int, num_buffers, q->max_num_buffers); memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); /* * Set this now to ensure that drivers see the correct q->memory value * in the queue_setup op. */ mutex_lock(&q->mmap_lock); + if (!q->bufs) + q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL); + if (!q->bufs) + ret = -ENOMEM; q->memory = memory; mutex_unlock(&q->mmap_lock); + if (ret) + return ret; set_queue_coherency(q, non_coherent_mem); /* @@ -981,7 +989,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, bool no_previous_buffers = !q_num_bufs; int ret = 0; - if (q_num_bufs == VB2_MAX_FRAME) { + if (q->num_buffers == q->max_num_buffers) { dprintk(q, 1, "maximum number of buffers already allocated\n"); return -ENOBUFS; } @@ -998,7 +1006,13 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, */ mutex_lock(&q->mmap_lock); q->memory = memory; + if (!q->bufs) + q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL); + if (!q->bufs) + ret = -ENOMEM; mutex_unlock(&q->mmap_lock); + if (ret) + return ret; q->waiting_for_buffers = !q->is_output; set_queue_coherency(q, non_coherent_mem); } else { @@ -1010,7 +1024,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, return -EINVAL; } - num_buffers = min(*count, VB2_MAX_FRAME - q_num_bufs); + num_buffers = min(*count, q->max_num_buffers - q_num_bufs); if (requested_planes && requested_sizes) { num_planes = requested_planes; @@ -2470,6 +2484,16 @@ int vb2_core_queue_init(struct vb2_queue *q) /* * Sanity check */ + /* + * For drivers who don't support max_num_buffers ensure + * a backward compatibility. + */ + if (!q->max_num_buffers) + q->max_num_buffers = VB2_MAX_FRAME; + + /* The maximum is limited by offset cookie encoding pattern */ + q->max_num_buffers = min_t(unsigned int, q->max_num_buffers, MAX_BUFFER_INDEX); + if (WARN_ON(!q) || WARN_ON(!q->ops) || WARN_ON(!q->mem_ops) || @@ -2479,6 +2503,10 @@ int vb2_core_queue_init(struct vb2_queue *q) WARN_ON(!q->ops->buf_queue)) return -EINVAL; + if (WARN_ON(q->max_num_buffers > MAX_BUFFER_INDEX) || + WARN_ON(q->min_buffers_needed > q->max_num_buffers)) + return -EINVAL; + if (WARN_ON(q->requires_requests && !q->supports_requests)) return -EINVAL; @@ -2525,6 +2553,8 @@ void vb2_core_queue_release(struct vb2_queue *q) __vb2_queue_cancel(q); mutex_lock(&q->mmap_lock); __vb2_queue_free(q, vb2_get_num_buffers(q)); + kfree(q->bufs); + q->bufs = NULL; mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_core_queue_release); diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 9d3b828cc804..3d71c205406d 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -621,7 +621,7 @@ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) * This loop doesn't scale if there is a really large number of buffers. * Maybe something more efficient will be needed in this case. */ - for (i = 0; i < vb2_get_num_buffers(q); i++) { + for (i = 0; i < q->max_num_buffers; i++) { vb2 = vb2_get_buffer(q, i); if (!vb2) @@ -1136,7 +1136,7 @@ int _vb2_fop_release(struct file *file, struct mutex *lock) if (lock) mutex_lock(lock); - if (file->private_data == vdev->queue->owner) { + if (!vdev->queue->owner || file->private_data == vdev->queue->owner) { vb2_queue_release(vdev->queue); vdev->queue->owner = NULL; } @@ -1264,7 +1264,7 @@ void vb2_video_unregister_device(struct video_device *vdev) */ get_device(&vdev->dev); video_unregister_device(vdev); - if (vdev->queue && vdev->queue->owner) { + if (vdev->queue) { struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 8f9d9e4af5b1..5557d78b6f20 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -558,6 +558,9 @@ struct vb2_buf_ops { * @dma_dir: DMA mapping direction. * @bufs: videobuf2 buffer structures * @num_buffers: number of allocated/used buffers + * @max_num_buffers: upper limit of number of allocated/used buffers. + * If set to 0 v4l2 core will change it VB2_MAX_FRAME + * for backward compatibility. * @queued_list: list of buffers currently queued from userspace * @queued_count: number of buffers queued and ready for streaming. * @owned_by_drv_count: number of buffers owned by the driver @@ -619,8 +622,9 @@ struct vb2_queue { struct mutex mmap_lock; unsigned int memory; enum dma_data_direction dma_dir; - struct vb2_buffer *bufs[VB2_MAX_FRAME]; + struct vb2_buffer **bufs; unsigned int num_buffers; + unsigned int max_num_buffers; struct list_head queued_list; unsigned int queued_count; @@ -1248,6 +1252,12 @@ static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q) static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q, unsigned int index) { + if (!q->bufs) + return NULL; + + if (index >= q->max_num_buffers) + return NULL; + if (index < q->num_buffers) return q->bufs[index]; return NULL; From d055a76c006540defd4eb80dcdea217cee0a141a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:00 +0100 Subject: [PATCH 1259/7721] media: core: Report the maximum possible number of buffers for the queue Use one of the struct v4l2_create_buffers reserved bytes to report the maximum possible number of buffers for the queue. V4l2 framework set V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS flags in queue capabilities so userland can know when the field is valid. Does the same change in v4l2_create_buffers32 structure. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/vidioc-create-bufs.rst | 8 ++++++-- .../userspace-api/media/v4l/vidioc-reqbufs.rst | 1 + drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 ++ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 10 +++++++++- drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++-- include/uapi/linux/videodev2.h | 7 ++++++- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst index a048a9f6b7b6..49232c9006c2 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst @@ -116,9 +116,13 @@ than the number requested. - ``flags`` - Specifies additional buffer management attributes. See :ref:`memory-flags`. - * - __u32 - - ``reserved``\ [6] + - ``max_num_buffers`` + - If the V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set + this field indicates the maximum possible number of buffers + for this queue. + * - __u32 + - ``reserved``\ [5] - A place holder for future extensions. Drivers and applications must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst index 099fa6695167..0b3a41a45d05 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst @@ -120,6 +120,7 @@ aborting or finishing any DMA in progress, an implicit .. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS: .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: .. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS: +.. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS: .. raw:: latex diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 3d71c205406d..440c3b1c18ec 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -756,6 +756,8 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) fill_buf_caps(q, &create->capabilities); validate_memory_flags(q, create->memory, &create->flags); create->index = vb2_get_num_buffers(q); + create->max_num_buffers = q->max_num_buffers; + create->capabilities |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS; if (create->count == 0) return ret != -EBUSY ? ret : 0; diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index f3bed37859a2..8c07400bd280 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -116,6 +116,9 @@ struct v4l2_format32 { * @flags: additional buffer management attributes (ignored unless the * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and * configured for MMAP streaming I/O). + * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set + * this field indicate the maximum possible number of buffers + * for this queue. * @reserved: future extensions */ struct v4l2_create_buffers32 { @@ -125,7 +128,8 @@ struct v4l2_create_buffers32 { struct v4l2_format32 format; __u32 capabilities; __u32 flags; - __u32 reserved[6]; + __u32 max_num_buffers; + __u32 reserved[5]; }; static int get_v4l2_format32(struct v4l2_format *p64, @@ -175,6 +179,9 @@ static int get_v4l2_create32(struct v4l2_create_buffers *p64, return -EFAULT; if (copy_from_user(&p64->flags, &p32->flags, sizeof(p32->flags))) return -EFAULT; + if (copy_from_user(&p64->max_num_buffers, &p32->max_num_buffers, + sizeof(p32->max_num_buffers))) + return -EFAULT; return get_v4l2_format32(&p64->format, &p32->format); } @@ -221,6 +228,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *p64, offsetof(struct v4l2_create_buffers32, format)) || put_user(p64->capabilities, &p32->capabilities) || put_user(p64->flags, &p32->flags) || + put_user(p64->max_num_buffers, &p32->max_num_buffers) || copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) return -EFAULT; return put_v4l2_format32(&p64->format, &p32->format); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 9b1de54ce379..4d90424cbfc4 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -483,9 +483,9 @@ static void v4l_print_create_buffers(const void *arg, bool write_only) { const struct v4l2_create_buffers *p = arg; - pr_cont("index=%d, count=%d, memory=%s, capabilities=0x%08x, ", + pr_cont("index=%d, count=%d, memory=%s, capabilities=0x%08x, max num buffers=%u", p->index, p->count, prt_names(p->memory, v4l2_memory_names), - p->capabilities); + p->capabilities, p->max_num_buffers); v4l_print_format(&p->format, write_only); } diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index c3d4e490ce7c..13ddb5abf584 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1035,6 +1035,7 @@ struct v4l2_requestbuffers { #define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6) +#define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7) /** * struct v4l2_plane - plane info for multi-planar buffers @@ -2605,6 +2606,9 @@ struct v4l2_dbg_chip_info { * @flags: additional buffer management attributes (ignored unless the * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability * and configured for MMAP streaming I/O). + * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set + * this field indicate the maximum possible number of buffers + * for this queue. * @reserved: future extensions */ struct v4l2_create_buffers { @@ -2614,7 +2618,8 @@ struct v4l2_create_buffers { struct v4l2_format format; __u32 capabilities; __u32 flags; - __u32 reserved[6]; + __u32 max_num_buffers; + __u32 reserved[5]; }; /* From cea70ed416b428f8214be196d62cc7ffaa11f1b8 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:01 +0100 Subject: [PATCH 1260/7721] media: test-drivers: vivid: Increase max supported buffers for capture queues Change the maximum number of buffers of some capture queues in order to test max_num_buffers field. Allow to allocate up to: - 64 buffers for video capture queue. - 1024 buffers for sdr capture queue. - 32768 buffers for vbi capture queue. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 394c9f81ea72..353f035fcd19 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -876,6 +876,20 @@ static int vivid_create_queue(struct vivid_dev *dev, q->type = buf_type; q->io_modes = VB2_MMAP | VB2_DMABUF; q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ; + + /* + * The maximum number of buffers is 32768 if PAGE_SHIFT == 12, + * see also MAX_BUFFER_INDEX in videobuf2-core.c. It will be less if + * PAGE_SHIFT > 12, but then max_num_buffers will be clamped by + * videobuf2-core.c to MAX_BUFFER_INDEX. + */ + if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + q->max_num_buffers = 64; + if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE) + q->max_num_buffers = 1024; + if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE) + q->max_num_buffers = 32768; + if (allocators[dev->inst] != 1) q->io_modes |= VB2_USERPTR; q->drv_priv = dev; From 7e8b591d50dc6b63f32fbd591fa80c70679115da Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:02 +0100 Subject: [PATCH 1261/7721] media: test-drivers: vicodec: Increase max supported capture queue buffers Allow to allocated up to 64 buffers on capture queue. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vicodec/vicodec-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 6f0e20df74e9..69cbe2c094e1 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1718,6 +1718,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dst_vq->max_num_buffers = 64; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &vicodec_qops; From 26711491a807ab3b1a04afad839ca48b6d34e63e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:03 +0100 Subject: [PATCH 1262/7721] media: verisilicon: Refactor postprocessor to store more buffers Since vb2 queue can store more than VB2_MAX_FRAME buffers, the postprocessor buffer storage must be capable to store more buffers too. Change static dec_q array to allocated array to be capable to store up to queue 'max_num_buffers'. Keep allocating queue 'num_buffers' at queue setup time but also allows to allocate postprocessors buffers on the fly. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro.h | 7 +- .../media/platform/verisilicon/hantro_drv.c | 4 +- .../media/platform/verisilicon/hantro_hw.h | 4 +- .../platform/verisilicon/hantro_postproc.c | 95 +++++++++++++++---- .../media/platform/verisilicon/hantro_v4l2.c | 2 +- 5 files changed, 86 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 77aee9489516..0948b04a9f8d 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -469,11 +469,14 @@ hantro_get_dst_buf(struct hantro_ctx *ctx) bool hantro_needs_postproc(const struct hantro_ctx *ctx, const struct hantro_fmt *fmt); +dma_addr_t +hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index); + static inline dma_addr_t hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb) { if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) - return ctx->postproc.dec_q[vb->index].dma; + return hantro_postproc_get_dec_buf_addr(ctx, vb->index); return vb2_dma_contig_plane_dma_addr(vb, 0); } @@ -485,8 +488,8 @@ vb2_to_hantro_decoded_buf(struct vb2_buffer *buf) void hantro_postproc_disable(struct hantro_ctx *ctx); void hantro_postproc_enable(struct hantro_ctx *ctx); +int hantro_postproc_init(struct hantro_ctx *ctx); void hantro_postproc_free(struct hantro_ctx *ctx); -int hantro_postproc_alloc(struct hantro_ctx *ctx); int hanto_postproc_enum_framesizes(struct hantro_ctx *ctx, struct v4l2_frmsizeenum *fsize); diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index a9fa05ac56a9..7f5b82eb6649 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -235,8 +235,10 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) * The Kernel needs access to the JPEG destination buffer for the * JPEG encoder to fill in the JPEG headers. */ - if (!ctx->is_encoder) + if (!ctx->is_encoder) { dst_vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + dst_vq->max_num_buffers = MAX_POSTPROC_BUFFERS; + } dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index 7f33f7b07ce4..292a76ef643e 100644 --- a/drivers/media/platform/verisilicon/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h @@ -40,6 +40,8 @@ #define AV1_MAX_FRAME_BUF_COUNT (V4L2_AV1_TOTAL_REFS_PER_FRAME + 1) +#define MAX_POSTPROC_BUFFERS 64 + struct hantro_dev; struct hantro_ctx; struct hantro_buf; @@ -336,7 +338,7 @@ struct hantro_av1_dec_hw_ctx { * @dec_q: References buffers, in decoder format. */ struct hantro_postproc_ctx { - struct hantro_aux_buf dec_q[VB2_MAX_FRAME]; + struct hantro_aux_buf dec_q[MAX_POSTPROC_BUFFERS]; }; /** diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c index 8f8f17e671ce..41e93176300b 100644 --- a/drivers/media/platform/verisilicon/hantro_postproc.c +++ b/drivers/media/platform/verisilicon/hantro_postproc.c @@ -177,9 +177,11 @@ static int hantro_postproc_g2_enum_framesizes(struct hantro_ctx *ctx, void hantro_postproc_free(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + struct vb2_queue *queue = &m2m_ctx->cap_q_ctx.q; unsigned int i; - for (i = 0; i < VB2_MAX_FRAME; ++i) { + for (i = 0; i < queue->max_num_buffers; ++i) { struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i]; if (priv->cpu) { @@ -190,20 +192,17 @@ void hantro_postproc_free(struct hantro_ctx *ctx) } } -int hantro_postproc_alloc(struct hantro_ctx *ctx) +static unsigned int hantro_postproc_buffer_size(struct hantro_ctx *ctx) { - struct hantro_dev *vpu = ctx->dev; - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q; - unsigned int num_buffers = vb2_get_num_buffers(cap_queue); struct v4l2_pix_format_mplane pix_mp; const struct hantro_fmt *fmt; - unsigned int i, buf_size; + unsigned int buf_size; /* this should always pick native format */ fmt = hantro_get_default_fmt(ctx, false, ctx->bit_depth, HANTRO_AUTO_POSTPROC); if (!fmt) - return -EINVAL; + return 0; + v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width, ctx->src_fmt.height); @@ -221,23 +220,77 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx) buf_size += hantro_av1_mv_size(pix_mp.width, pix_mp.height); - for (i = 0; i < num_buffers; ++i) { - struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i]; + return buf_size; +} + +static int hantro_postproc_alloc(struct hantro_ctx *ctx, int index) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index]; + unsigned int buf_size = hantro_postproc_buffer_size(ctx); + + if (!buf_size) + return -EINVAL; + + /* + * The buffers on this queue are meant as intermediate + * buffers for the decoder, so no mapping is needed. + */ + priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING; + priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma, + GFP_KERNEL, priv->attrs); + if (!priv->cpu) + return -ENOMEM; + priv->size = buf_size; - /* - * The buffers on this queue are meant as intermediate - * buffers for the decoder, so no mapping is needed. - */ - priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING; - priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma, - GFP_KERNEL, priv->attrs); - if (!priv->cpu) - return -ENOMEM; - priv->size = buf_size; - } return 0; } +int hantro_postproc_init(struct hantro_ctx *ctx) +{ + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q; + unsigned int num_buffers = vb2_get_num_buffers(cap_queue); + unsigned int i; + int ret; + + for (i = 0; i < num_buffers; i++) { + ret = hantro_postproc_alloc(ctx, i); + if (ret) + return ret; + } + + return 0; +} + +dma_addr_t +hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index) +{ + struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index]; + unsigned int buf_size = hantro_postproc_buffer_size(ctx); + struct hantro_dev *vpu = ctx->dev; + int ret; + + if (priv->size < buf_size && priv->cpu) { + /* buffer is too small, release it */ + dma_free_attrs(vpu->dev, priv->size, priv->cpu, + priv->dma, priv->attrs); + priv->cpu = NULL; + } + + if (!priv->cpu) { + /* buffer not already allocated, try getting a new one */ + ret = hantro_postproc_alloc(ctx, index); + if (ret) + return 0; + } + + if (!priv->cpu) + return 0; + + return priv->dma; +} + static void hantro_postproc_g1_disable(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index b3ae037a50f6..f0d8b165abcd 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -933,7 +933,7 @@ static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) } if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) { - ret = hantro_postproc_alloc(ctx); + ret = hantro_postproc_init(ctx); if (ret) goto err_codec_exit; } From 545bf944f978b7468d3a6bd668d9ff6953bc542e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:04 +0100 Subject: [PATCH 1263/7721] media: verisilicon: Store chroma and motion vectors offset Store computed values of chroma and motion vectors offset because they depends on width and height values which change if the resolution change. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro.h | 2 ++ drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 0948b04a9f8d..6f5eb975d0e3 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -328,6 +328,8 @@ struct hantro_vp9_decoded_buffer_info { /* Info needed when the decoded frame serves as a reference frame. */ unsigned short width; unsigned short height; + size_t chroma_offset; + size_t mv_offset; u32 bit_depth : 4; }; diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c index 6fc4b555517f..6db1c32fce4d 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c @@ -158,9 +158,11 @@ static void config_output(struct hantro_ctx *ctx, chroma_addr = luma_addr + chroma_offset(ctx, dec_params); hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr); + dst->vp9.chroma_offset = chroma_offset(ctx, dec_params); mv_addr = luma_addr + mv_offset(ctx, dec_params); hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr); + dst->vp9.mv_offset = mv_offset(ctx, dec_params); } struct hantro_vp9_ref_reg { @@ -195,7 +197,7 @@ static void config_ref(struct hantro_ctx *ctx, luma_addr = hantro_get_dec_buf_addr(ctx, &buf->base.vb.vb2_buf); hantro_write_addr(ctx->dev, ref_reg->y_base, luma_addr); - chroma_addr = luma_addr + chroma_offset(ctx, dec_params); + chroma_addr = luma_addr + buf->vp9.chroma_offset; hantro_write_addr(ctx->dev, ref_reg->c_base, chroma_addr); } @@ -238,7 +240,7 @@ static void config_ref_registers(struct hantro_ctx *ctx, config_ref(ctx, dst, &ref_regs[2], dec_params, dec_params->alt_frame_ts); mv_addr = hantro_get_dec_buf_addr(ctx, &mv_ref->base.vb.vb2_buf) + - mv_offset(ctx, dec_params); + mv_ref->vp9.mv_offset; hantro_write_addr(ctx->dev, G2_REF_MV_ADDR(0), mv_addr); hantro_reg_write(ctx->dev, &vp9_last_sign_bias, From 3eeaee737dcee3c32e256870dbc2687a2a6fe970 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:05 +0100 Subject: [PATCH 1264/7721] media: verisilicon: g2: Use common helpers to compute chroma and mv offsets HEVC and VP9 are running on the same hardware and share the same chroma and motion vectors offset constraint. Create common helpers functions for these computation. Source and destination buffer height may not be the same because alignment constraint are different so use destination height to compute chroma offset because we target this buffer as hardware output. To be able to use the helpers in both VP9 HEVC code remove dec_params and use context->bit_depth instead. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/verisilicon/hantro_g2.c | 14 ++++++++++ .../platform/verisilicon/hantro_g2_hevc_dec.c | 18 ++----------- .../platform/verisilicon/hantro_g2_vp9_dec.c | 26 +++---------------- .../media/platform/verisilicon/hantro_hw.h | 3 +++ 4 files changed, 23 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_g2.c b/drivers/media/platform/verisilicon/hantro_g2.c index ee5f14c5f8f2..b880a6849d58 100644 --- a/drivers/media/platform/verisilicon/hantro_g2.c +++ b/drivers/media/platform/verisilicon/hantro_g2.c @@ -8,6 +8,8 @@ #include "hantro_hw.h" #include "hantro_g2_regs.h" +#define G2_ALIGN 16 + void hantro_g2_check_idle(struct hantro_dev *vpu) { int i; @@ -42,3 +44,15 @@ irqreturn_t hantro_g2_irq(int irq, void *dev_id) return IRQ_HANDLED; } + +size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx) +{ + return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; +} + +size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx) +{ + size_t cr_offset = hantro_g2_chroma_offset(ctx); + + return ALIGN((cr_offset * 3) / 2, G2_ALIGN); +} diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index a9d4ac84a8d8..d3f8c33eb16c 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -8,20 +8,6 @@ #include "hantro_hw.h" #include "hantro_g2_regs.h" -#define G2_ALIGN 16 - -static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx) -{ - return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; -} - -static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx) -{ - size_t cr_offset = hantro_hevc_chroma_offset(ctx); - - return ALIGN((cr_offset * 3) / 2, G2_ALIGN); -} - static void prepare_tile_info_buffer(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; @@ -384,8 +370,8 @@ static int set_ref(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *vb2_dst; struct hantro_decoded_buffer *dst; - size_t cr_offset = hantro_hevc_chroma_offset(ctx); - size_t mv_offset = hantro_hevc_motion_vectors_offset(ctx); + size_t cr_offset = hantro_g2_chroma_offset(ctx); + size_t mv_offset = hantro_g2_motion_vectors_offset(ctx); u32 max_ref_frames; u16 dpb_longterm_e; static const struct hantro_reg cur_poc[] = { diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c index 6db1c32fce4d..342e543dee4c 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c @@ -16,8 +16,6 @@ #include "hantro_vp9.h" #include "hantro_g2_regs.h" -#define G2_ALIGN 16 - enum hantro_ref_frames { INTRA_FRAME = 0, LAST_FRAME = 1, @@ -90,22 +88,6 @@ static int start_prepare_run(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp9_ return 0; } -static size_t chroma_offset(const struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp9_frame *dec_params) -{ - int bytes_per_pixel = dec_params->bit_depth == 8 ? 1 : 2; - - return ctx->src_fmt.width * ctx->src_fmt.height * bytes_per_pixel; -} - -static size_t mv_offset(const struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp9_frame *dec_params) -{ - size_t cr_offset = chroma_offset(ctx, dec_params); - - return ALIGN((cr_offset * 3) / 2, G2_ALIGN); -} - static struct hantro_decoded_buffer * get_ref_buf(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) { @@ -156,13 +138,13 @@ static void config_output(struct hantro_ctx *ctx, luma_addr = hantro_get_dec_buf_addr(ctx, &dst->base.vb.vb2_buf); hantro_write_addr(ctx->dev, G2_OUT_LUMA_ADDR, luma_addr); - chroma_addr = luma_addr + chroma_offset(ctx, dec_params); + chroma_addr = luma_addr + hantro_g2_chroma_offset(ctx); hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr); - dst->vp9.chroma_offset = chroma_offset(ctx, dec_params); + dst->vp9.chroma_offset = hantro_g2_chroma_offset(ctx); - mv_addr = luma_addr + mv_offset(ctx, dec_params); + mv_addr = luma_addr + hantro_g2_motion_vectors_offset(ctx); hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr); - dst->vp9.mv_offset = mv_offset(ctx, dec_params); + dst->vp9.mv_offset = hantro_g2_motion_vectors_offset(ctx); } struct hantro_vp9_ref_reg { diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index 292a76ef643e..9aec8a79acdc 100644 --- a/drivers/media/platform/verisilicon/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h @@ -521,6 +521,9 @@ hantro_av1_mv_size(unsigned int width, unsigned int height) return ALIGN(num_sbs * 384, 16) * 2 + 512; } +size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx); +size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx); + int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx); void hantro_mpeg2_dec_copy_qtable(u8 *qtable, From bbd267daf4fc831f58bf4a2530a8b64881779e6a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 9 Nov 2023 17:35:06 +0100 Subject: [PATCH 1265/7721] media: verisilicon: vp9: Allow to change resolution while streaming Remove all checks that prohibit to set a new format while streaming. This allow to change dynamically the resolution if the pixel format remains the same. Signed-off-by: Benjamin Gaignard Reviewed-by: Andrzej Pietrasiewicz CC: Ezequiel Garcia CC: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/verisilicon/hantro_v4l2.c | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index f0d8b165abcd..27a1e77cca38 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -514,25 +514,14 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, return ret; if (!ctx->is_encoder) { - struct vb2_queue *peer_vq; - /* * In order to support dynamic resolution change, * the decoder admits a resolution change, as long - * as the pixelformat remains. Can't be done if streaming. + * as the pixelformat remains. */ - if (vb2_is_streaming(vq) || (vb2_is_busy(vq) && - pix_mp->pixelformat != ctx->src_fmt.pixelformat)) - return -EBUSY; - /* - * Since format change on the OUTPUT queue will reset - * the CAPTURE queue, we can't allow doing so - * when the CAPTURE queue has buffers allocated. - */ - peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(peer_vq)) + if (vb2_is_streaming(vq) && pix_mp->pixelformat != ctx->src_fmt.pixelformat) { return -EBUSY; + } } else { /* * The encoder doesn't admit a format change if @@ -577,15 +566,8 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, static int hantro_set_fmt_cap(struct hantro_ctx *ctx, struct v4l2_pix_format_mplane *pix_mp) { - struct vb2_queue *vq; int ret; - /* Change not allowed if queue is busy. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(vq)) - return -EBUSY; - if (ctx->is_encoder) { struct vb2_queue *peer_vq; From 632b8b044a940e415c6d9bd5235778b0db28add1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 11 Oct 2023 10:17:59 +0200 Subject: [PATCH 1266/7721] media: cec: core: count low-drive, error and arb-lost conditions Count how many Low Drive, Error and Arbitration Lost transmit status errors occurred, and expose that in debugfs. Also log the first 8 transmits that result in Low Drive or Error conditions. That really should not happen with well-behaved CEC devices and good HDMI cables. This is useful to detect and debug HDMI cable issues. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/core/cec-adap.c | 54 ++++++++++++++++++++++++++++--- include/media/cec.h | 22 +++++++++++-- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 6bb49bb3f98c..5741adf09a2e 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -511,7 +511,7 @@ int cec_thread_func(void *_adap) pr_warn("cec-%s: transmit timed out\n", adap->name); } adap->transmit_in_progress = false; - adap->tx_timeouts++; + adap->tx_timeout_cnt++; goto unlock; } @@ -625,6 +625,33 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, msg->tx_low_drive_cnt += low_drive_cnt; msg->tx_error_cnt += error_cnt; + adap->tx_arb_lost_cnt += arb_lost_cnt; + adap->tx_low_drive_cnt += low_drive_cnt; + adap->tx_error_cnt += error_cnt; + + /* + * Low Drive transmission errors should really not happen for + * well-behaved CEC devices and proper HDMI cables. + * + * Ditto for the 'Error' status. + * + * For the first few times that this happens, log this. + * Stop logging after that, since that will not add any more + * useful information and instead it will just flood the kernel log. + */ + if (done && adap->tx_low_drive_log_cnt < 8 && msg->tx_low_drive_cnt) { + adap->tx_low_drive_log_cnt++; + dprintk(0, "low drive counter: %u (seq %u: %*ph)\n", + msg->tx_low_drive_cnt, msg->sequence, + msg->len, msg->msg); + } + if (done && adap->tx_error_log_cnt < 8 && msg->tx_error_cnt) { + adap->tx_error_log_cnt++; + dprintk(0, "error counter: %u (seq %u: %*ph)\n", + msg->tx_error_cnt, msg->sequence, + msg->len, msg->msg); + } + /* Mark that we're done with this transmit */ adap->transmitting = NULL; @@ -1607,6 +1634,8 @@ int cec_adap_enable(struct cec_adapter *adap) if (enable) { adap->last_initiator = 0xff; adap->transmit_in_progress = false; + adap->tx_low_drive_log_cnt = 0; + adap->tx_error_log_cnt = 0; ret = adap->ops->adap_enable(adap, true); if (!ret) { /* @@ -2265,10 +2294,25 @@ int cec_adap_status(struct seq_file *file, void *priv) if (adap->monitor_pin_cnt) seq_printf(file, "file handles in Monitor Pin mode: %u\n", adap->monitor_pin_cnt); - if (adap->tx_timeouts) { - seq_printf(file, "transmit timeouts: %u\n", - adap->tx_timeouts); - adap->tx_timeouts = 0; + if (adap->tx_timeout_cnt) { + seq_printf(file, "transmit timeout count: %u\n", + adap->tx_timeout_cnt); + adap->tx_timeout_cnt = 0; + } + if (adap->tx_low_drive_cnt) { + seq_printf(file, "transmit low drive count: %u\n", + adap->tx_low_drive_cnt); + adap->tx_low_drive_cnt = 0; + } + if (adap->tx_arb_lost_cnt) { + seq_printf(file, "transmit arbitration lost count: %u\n", + adap->tx_arb_lost_cnt); + adap->tx_arb_lost_cnt = 0; + } + if (adap->tx_error_cnt) { + seq_printf(file, "transmit error count: %u\n", + adap->tx_error_cnt); + adap->tx_error_cnt = 0; } data = adap->transmitting; if (data) diff --git a/include/media/cec.h b/include/media/cec.h index 53e4b2eb2b26..d77982685116 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -207,7 +207,20 @@ struct cec_adap_ops { * passthrough mode. * @log_addrs: current logical addresses * @conn_info: current connector info - * @tx_timeouts: number of transmit timeouts + * @tx_timeout_cnt: count the number of Timed Out transmits. + * Reset to 0 when this is reported in cec_adap_status(). + * @tx_low_drive_cnt: count the number of Low Drive transmits. + * Reset to 0 when this is reported in cec_adap_status(). + * @tx_error_cnt: count the number of Error transmits. + * Reset to 0 when this is reported in cec_adap_status(). + * @tx_arb_lost_cnt: count the number of Arb Lost transmits. + * Reset to 0 when this is reported in cec_adap_status(). + * @tx_low_drive_log_cnt: number of logged Low Drive transmits since the + * adapter was enabled. Used to avoid flooding the kernel + * log if this happens a lot. + * @tx_error_log_cnt: number of logged Error transmits since the adapter was + * enabled. Used to avoid flooding the kernel log if this + * happens a lot. * @notifier: CEC notifier * @pin: CEC pin status struct * @cec_dir: debugfs cec directory @@ -262,7 +275,12 @@ struct cec_adapter { struct cec_log_addrs log_addrs; struct cec_connector_info conn_info; - u32 tx_timeouts; + u32 tx_timeout_cnt; + u32 tx_low_drive_cnt; + u32 tx_error_cnt; + u32 tx_arb_lost_cnt; + u32 tx_low_drive_log_cnt; + u32 tx_error_log_cnt; #ifdef CONFIG_CEC_NOTIFIER struct cec_notifier *notifier; From 6aa210d27b5feaf81634973f28b896e208166f4c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Oct 2023 13:54:01 +0200 Subject: [PATCH 1267/7721] media: core: v4l2-ioctl: check if ioctl is known to avoid NULL name When ioctl debugging is turned on, the v4l_printk_ioctl() is used to log the ioctl that is called. It uses an array of ioctl information to log the ioctl name and it correctly checks for out-of-bound indexing of that array. However, the array may have holes since not all ioctl numbers are used. In that case the name of the ioctl is NULL. It is harmless (printk handles NULL pointers), but not intended. Instead use the v4l2_is_known_ioctl() function to determine if the ioctl information is available or not. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 4d90424cbfc4..33076af4dfdb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2951,7 +2951,7 @@ void v4l_printk_ioctl(const char *prefix, unsigned int cmd) type = "v4l2_int"; break; case 'V': - if (_IOC_NR(cmd) >= V4L2_IOCTLS) { + if (!v4l2_is_known_ioctl(cmd)) { type = "v4l2"; break; } From 57e3f1cfc23ffdbfd7c8fcee5406930cc7f85eed Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Tue, 7 Nov 2023 18:29:16 +0100 Subject: [PATCH 1268/7721] media: v4l2-common: Add 10bpp RGB formats info Video4Linux2 defines 3 RGB formats with 10 bits per color components plus two optional alpha bits such that a pixel is then stored in a 4 bytes word. Add a format info for the 3 10-bits RGB formats to the v4l2_format_info() table in v4l2-common.c. Signed-off-by: Jacopo Mondi Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 3a4b15a98e02..e9e7e70fa24e 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -254,6 +254,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, /* YUV packed formats */ { .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, From dd4229fa7b6e5b4e12575a0165131874a233f7bc Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 7 Nov 2023 21:05:09 +0100 Subject: [PATCH 1269/7721] media: v4l2-dev: Check that g/s_selection are valid before selecting crop The cropcap and g/s_crop ioctls are automatically marked as valid whenever the g/s_selection ops are filled. The rationale is to auto-enable these legacy cropcap and g/s_crop ioctls that rely on g/s_selection. However it's possible that the ops are filled but explicitly disabled with calls to v4l2_disable_ioctl. In this situation the legacy ioctls should not be enabled. Add a check on the video device's valid ioctls field before auto-selecting them to honor the driver's choice. Note that the meaning of the bitfield stored in the video device is the opposite of what the name suggests as v4l2_disable_ioctl will set the bits. Their meaning will be reversed at the end of the function. Signed-off-by: Paul Kocialkowski Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index f81279492682..d13954bd31fd 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -642,11 +642,13 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd); SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); - if (ops->vidioc_g_selection) { + if (ops->vidioc_g_selection && + !test_bit(_IOC_NR(VIDIOC_G_SELECTION), vdev->valid_ioctls)) { __set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls); __set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls); } - if (ops->vidioc_s_selection) + if (ops->vidioc_s_selection && + !test_bit(_IOC_NR(VIDIOC_S_SELECTION), vdev->valid_ioctls)) __set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); From ed5000fe5ac48980bf0b2a707c64bba184dd83d2 Mon Sep 17 00:00:00 2001 From: Deborah Brouwer Date: Thu, 9 Nov 2023 20:16:43 +0100 Subject: [PATCH 1270/7721] media: v4l2-mem2mem.h: fix typo in comment The comment describing the function v4l2_m2m_last_src_buf() says that this function returns the last destination buffer when it actually returns the last source buffer. Fix the comment so that it is accurate. Signed-off-by: Deborah Brouwer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-mem2mem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 1288fe364fab..7f1af1f7f912 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -668,7 +668,7 @@ v4l2_m2m_next_dst_buf(struct v4l2_m2m_ctx *m2m_ctx) struct vb2_v4l2_buffer *v4l2_m2m_last_buf(struct v4l2_m2m_queue_ctx *q_ctx); /** - * v4l2_m2m_last_src_buf() - return last destination buffer from the list of + * v4l2_m2m_last_src_buf() - return last source buffer from the list of * ready buffers * * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx From 26cb92f7f7c409c2674c019e5f4e44119209dd24 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 10 Nov 2023 09:53:00 +0100 Subject: [PATCH 1271/7721] media: drop CONFIG_MEDIA_CONTROLLER_REQUEST_API This config option was added during the development of the Request API to make it easy to disable it. The Request API is now stable so it is time to drop this option altogether. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 -- drivers/media/mc/Kconfig | 7 ------- drivers/media/mc/mc-device.c | 4 ---- drivers/media/platform/mediatek/vcodec/Kconfig | 1 - drivers/media/platform/nvidia/tegra-vde/Kconfig | 1 - drivers/media/platform/verisilicon/Kconfig | 1 - drivers/media/test-drivers/Kconfig | 1 - drivers/media/test-drivers/vicodec/Kconfig | 1 - drivers/media/test-drivers/visl/Kconfig | 1 - drivers/media/test-drivers/vivid/Kconfig | 1 - drivers/staging/media/rkvdec/Kconfig | 1 - drivers/staging/media/sunxi/cedrus/Kconfig | 1 - 12 files changed, 22 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 440c3b1c18ec..54d572c3b515 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -684,10 +684,8 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) *caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF; if (q->allow_cache_hints && q->io_modes & VB2_MMAP) *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS; -#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API if (q->supports_requests) *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; -#endif } static void validate_memory_flags(struct vb2_queue *q, diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig index 375b09612981..c82b07d2ef36 100644 --- a/drivers/media/mc/Kconfig +++ b/drivers/media/mc/Kconfig @@ -11,10 +11,3 @@ config MEDIA_CONTROLLER_DVB Enable the media controller API support for DVB. This is currently experimental. - -config MEDIA_CONTROLLER_REQUEST_API - bool - depends on MEDIA_CONTROLLER - help - This option enables the Request API for the Media controller and V4L2 - interfaces. It is currently needed by a few stateless codec drivers. diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 8cee956e38d4..c0dd4ae57227 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -372,16 +372,12 @@ static long media_device_get_topology(struct media_device *mdev, void *arg) static long media_device_request_alloc(struct media_device *mdev, void *arg) { -#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API int *alloc_fd = arg; if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) return -ENOTTY; return media_request_alloc(mdev, alloc_fd); -#else - return -ENOTTY; -#endif } static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd) diff --git a/drivers/media/platform/mediatek/vcodec/Kconfig b/drivers/media/platform/mediatek/vcodec/Kconfig index 74b00eb1bc97..bc8292232530 100644 --- a/drivers/media/platform/mediatek/vcodec/Kconfig +++ b/drivers/media/platform/mediatek/vcodec/Kconfig @@ -24,7 +24,6 @@ config VIDEO_MEDIATEK_VCODEC select V4L2_H264 select V4L2_VP9 select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats on MT8173 diff --git a/drivers/media/platform/nvidia/tegra-vde/Kconfig b/drivers/media/platform/nvidia/tegra-vde/Kconfig index f7454823bbbb..2fe13f39c95b 100644 --- a/drivers/media/platform/nvidia/tegra-vde/Kconfig +++ b/drivers/media/platform/nvidia/tegra-vde/Kconfig @@ -6,7 +6,6 @@ config VIDEO_TEGRA_VDE select DMA_SHARED_BUFFER select IOMMU_IOVA select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API select SRAM select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig index e65b836b9d78..24b927d8f182 100644 --- a/drivers/media/platform/verisilicon/Kconfig +++ b/drivers/media/platform/verisilicon/Kconfig @@ -8,7 +8,6 @@ config VIDEO_HANTRO depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV diff --git a/drivers/media/test-drivers/Kconfig b/drivers/media/test-drivers/Kconfig index 459b433e9fae..5a5379524bde 100644 --- a/drivers/media/test-drivers/Kconfig +++ b/drivers/media/test-drivers/Kconfig @@ -12,7 +12,6 @@ config VIDEO_VIM2M select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API help This is a virtual test device for the memory-to-memory driver framework. diff --git a/drivers/media/test-drivers/vicodec/Kconfig b/drivers/media/test-drivers/vicodec/Kconfig index a7a828eec2a4..4ea0689c3abe 100644 --- a/drivers/media/test-drivers/vicodec/Kconfig +++ b/drivers/media/test-drivers/vicodec/Kconfig @@ -5,7 +5,6 @@ config VIDEO_VICODEC select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API help Driver for a Virtual Codec diff --git a/drivers/media/test-drivers/visl/Kconfig b/drivers/media/test-drivers/visl/Kconfig index 7508b904f196..37be9f267224 100644 --- a/drivers/media/test-drivers/visl/Kconfig +++ b/drivers/media/test-drivers/visl/Kconfig @@ -7,7 +7,6 @@ config VIDEO_VISL select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API select VIDEO_V4L2_TPG help diff --git a/drivers/media/test-drivers/vivid/Kconfig b/drivers/media/test-drivers/vivid/Kconfig index 5b08a5ad291e..ec2e71d76965 100644 --- a/drivers/media/test-drivers/vivid/Kconfig +++ b/drivers/media/test-drivers/vivid/Kconfig @@ -10,7 +10,6 @@ config VIDEO_VIVID select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API help Enables a virtual video driver. This driver emulates a webcam, TV, S-Video and HDMI capture hardware, including VBI support for diff --git a/drivers/staging/media/rkvdec/Kconfig b/drivers/staging/media/rkvdec/Kconfig index e963d60cc6ad..5f3bdd848a2c 100644 --- a/drivers/staging/media/rkvdec/Kconfig +++ b/drivers/staging/media/rkvdec/Kconfig @@ -4,7 +4,6 @@ config VIDEO_ROCKCHIP_VDEC depends on ARCH_ROCKCHIP || COMPILE_TEST depends on VIDEO_DEV select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig index 621944f9907a..cb07a343c9c2 100644 --- a/drivers/staging/media/sunxi/cedrus/Kconfig +++ b/drivers/staging/media/sunxi/cedrus/Kconfig @@ -6,7 +6,6 @@ config VIDEO_SUNXI_CEDRUS depends on HAS_DMA depends on OF select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API select SUNXI_SRAM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV From 70be8a84017a4454429abc40dec40a1f845c7827 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Nov 2023 11:39:44 +0100 Subject: [PATCH 1272/7721] media: videodev2.h: add missing __user to p_h264_pps The p_h264_pps pointer in struct v4l2_ext_control was missing the __user annotation. Add this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 13ddb5abf584..c3fc710ef9a7 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1817,7 +1817,7 @@ struct v4l2_ext_control { __s64 __user *p_s64; struct v4l2_area __user *p_area; struct v4l2_ctrl_h264_sps __user *p_h264_sps; - struct v4l2_ctrl_h264_pps *p_h264_pps; + struct v4l2_ctrl_h264_pps __user *p_h264_pps; struct v4l2_ctrl_h264_scaling_matrix __user *p_h264_scaling_matrix; struct v4l2_ctrl_h264_pred_weights __user *p_h264_pred_weights; struct v4l2_ctrl_h264_slice_params __user *p_h264_slice_params; From 26846dda3eca07cbb8dd481421ae52b31ef232d5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Nov 2023 11:50:36 +0100 Subject: [PATCH 1273/7721] media: videodev.h: add missing p_hdr10_* pointers The HDR10 standard compound controls were missing the corresponding pointers in videodev2.h. Add these and document them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 8 ++++++++ include/uapi/linux/videodev2.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index f9f73530a6be..4d56c0528ad7 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -295,6 +295,14 @@ still cause this situation. - ``p_av1_film_grain`` - A pointer to a struct :c:type:`v4l2_ctrl_av1_film_grain`. Valid if this control is of type ``V4L2_CTRL_TYPE_AV1_FILM_GRAIN``. + * - struct :c:type:`v4l2_ctrl_hdr10_cll_info` * + - ``p_hdr10_cll_info`` + - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_cll_info`. Valid if this control is + of type ``V4L2_CTRL_TYPE_HDR10_CLL_INFO``. + * - struct :c:type:`v4l2_ctrl_hdr10_mastering_display` * + - ``p_hdr10_mastering_display`` + - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_mastering_display`. Valid if this control is + of type ``V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY``. * - void * - ``ptr`` - A pointer to a compound type which can be an N-dimensional array diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index c3fc710ef9a7..68e7ac178cc2 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1838,6 +1838,8 @@ struct v4l2_ext_control { struct v4l2_ctrl_av1_tile_group_entry __user *p_av1_tile_group_entry; struct v4l2_ctrl_av1_frame __user *p_av1_frame; struct v4l2_ctrl_av1_film_grain __user *p_av1_film_grain; + struct v4l2_ctrl_hdr10_cll_info __user *p_hdr10_cll_info; + struct v4l2_ctrl_hdr10_mastering_display __user *p_hdr10_mastering_display; void __user *ptr; }; } __attribute__ ((packed)); From c5b9f4792ea6b9abfcfb9486ba256f55e296aaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Tue, 21 Nov 2023 19:37:38 +0100 Subject: [PATCH 1274/7721] dt-bindings: net: renesas,ethertsn: Add Ethernet TSN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add bindings for Renesas R-Car Ethernet TSN End-station IP. The RTSN device provides Ethernet network. Signed-off-by: Niklas Söderlund Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231121183738.656192-1-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Paolo Abeni --- .../bindings/net/renesas,ethertsn.yaml | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/renesas,ethertsn.yaml diff --git a/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml b/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml new file mode 100644 index 000000000000..475aff7714d6 --- /dev/null +++ b/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/renesas,ethertsn.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Ethernet TSN End-station + +maintainers: + - Niklas Söderlund + +description: + The RTSN device provides Ethernet network using a 10 Mbps, 100 Mbps, or 1 + Gbps full-duplex link via MII/GMII/RMII/RGMII. Depending on the connected PHY. + +allOf: + - $ref: ethernet-controller.yaml# + +properties: + compatible: + items: + - enum: + - renesas,r8a779g0-ethertsn # R-Car V4H + - const: renesas,rcar-gen4-ethertsn + + reg: + items: + - description: TSN End Station target + - description: generalized Precision Time Protocol target + + reg-names: + items: + - const: tsnes + - const: gptp + + interrupts: + items: + - description: TX data interrupt + - description: RX data interrupt + + interrupt-names: + items: + - const: tx + - const: rx + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + phy-mode: + contains: + enum: + - mii + - rgmii + + phy-handle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Specifies a reference to a node representing a PHY device. + + rx-internal-delay-ps: + enum: [0, 1800] + + tx-internal-delay-ps: + enum: [0, 2000] + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^ethernet-phy@[0-9a-f]$": + type: object + $ref: ethernet-phy.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + - phy-mode + - phy-handle + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + tsn0: ethernet@e6460000 { + compatible = "renesas,r8a779g0-ethertsn", "renesas,rcar-gen4-ethertsn"; + reg = <0xe6460000 0x7000>, + <0xe6449000 0x500>; + reg-names = "tsnes", "gptp"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + clocks = <&cpg CPG_MOD 2723>; + power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; + resets = <&cpg 2723>; + + phy-mode = "rgmii"; + tx-internal-delay-ps = <2000>; + phy-handle = <&phy3>; + + #address-cells = <1>; + #size-cells = <0>; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + interrupt-parent = <&gpio4>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; + }; + }; From bc53c4d56eb24dbe56cd2c66ef4e9fc9393b1533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:14 +0200 Subject: [PATCH 1275/7721] drm/i915: Check pipe active state in {planes,vrr}_{enabling,disabling}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit {planes,vrr}_{enabling,disabling}() are supposed to indicate whether the specific hardware feature is supposed to be enabling or disabling. That can only makes sense if the pipe is active overall. So check for that before we go poking at the hardware. I think we're semi-safe currently on due to: - intel_pre_plane_update() doesn't get called when the pipe was not-active prior to the commit, but this is actually a bug. This saves vrr_disabling(), and vrr_enabling() is called from deeper down where we have already checked hw.active. - active_planes mirrors the crtc's hw.active Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f8503d917c3d..78d8e9e19cfb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -901,12 +901,18 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) static bool planes_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!new_crtc_state->hw.active) + return false; + return is_enabling(active_planes, old_crtc_state, new_crtc_state); } static bool planes_disabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!old_crtc_state->hw.active) + return false; + return is_disabling(active_planes, old_crtc_state, new_crtc_state); } @@ -923,6 +929,9 @@ static bool vrr_params_changed(const struct intel_crtc_state *old_crtc_state, static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!new_crtc_state->hw.active) + return false; + return is_enabling(vrr.enable, old_crtc_state, new_crtc_state) || (new_crtc_state->vrr.enable && (new_crtc_state->update_m_n || new_crtc_state->update_lrr || @@ -932,6 +941,9 @@ static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state, static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!old_crtc_state->hw.active) + return false; + return is_disabling(vrr.enable, old_crtc_state, new_crtc_state) || (old_crtc_state->vrr.enable && (new_crtc_state->update_m_n || new_crtc_state->update_lrr || From e0d5ce11ed0a21bb2bf328ad82fd261783c7ad88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:15 +0200 Subject: [PATCH 1276/7721] drm/i915: Call intel_pre_plane_updates() also for pipes getting enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to call intel_pre_plane_updates() for any pipe going through a modeset whether the pipe was previously enabled or not. This in fact needed to apply all the necessary clock gating workarounds/etc. Restore the correct behaviour. Fixes: 39919997322f ("drm/i915: Disable all planes before modesetting any pipes") Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 78d8e9e19cfb..6adc32e2f477 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6694,10 +6694,11 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state) if (!intel_crtc_needs_modeset(new_crtc_state)) continue; + intel_pre_plane_update(state, crtc); + if (!old_crtc_state->hw.active) continue; - intel_pre_plane_update(state, crtc); intel_crtc_disable_planes(state, crtc); } From e4fb7f894ed48f6fb5b1ca61ade44a92c425444b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:16 +0200 Subject: [PATCH 1277/7721] drm/i915: Polish some RMWs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing the if-else around RMWs is kinda silly. Just set/clear the apporiate bits with a single RMW. Also unify the coding style a bit icl_wa_cursorclkgating() while at it. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 6adc32e2f477..98ea3591665f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -193,12 +193,9 @@ static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) static void skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - if (enable) - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), - 0, DUPS1_GATING_DIS | DUPS2_GATING_DIS); - else - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), - DUPS1_GATING_DIS | DUPS2_GATING_DIS, 0); + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + DUPS1_GATING_DIS | DUPS2_GATING_DIS, + enable ? DUPS1_GATING_DIS | DUPS2_GATING_DIS : 0); } /* Wa_2006604312:icl,ehl */ @@ -206,10 +203,9 @@ static void icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - if (enable) - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), 0, DPFR_GATING_DIS); - else - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), DPFR_GATING_DIS, 0); + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + DPFR_GATING_DIS, + enable ? DPFR_GATING_DIS : 0); } /* Wa_1604331009:icl,jsl,ehl */ @@ -217,7 +213,8 @@ static void icl_wa_cursorclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), CURSOR_GATING_DIS, + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + CURSOR_GATING_DIS, enable ? CURSOR_GATING_DIS : 0); } From 7966a93a27cfea1d9ceae3be1298be06184f5afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:17 +0200 Subject: [PATCH 1278/7721] drm/i915: Push audio enable/disable further out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Push the audio enable/disable to be the last/first thing respectively that is done in the encoder enable/disable hooks. The goal is to move it further out of these encoder hooks entirely. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_ddi.c | 12 ++++-------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 ++++---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index e8ee0a08947e..79ef2b435beb 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -482,10 +482,10 @@ static void intel_disable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - intel_dp->link_trained = false; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + intel_dp->link_trained = false; + /* * Make sure the panel is off before trying to change the mode. * But also ensure that we have vdd while we switch off the panel. @@ -686,8 +686,8 @@ static void g4x_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { intel_enable_dp(state, encoder, pipe_config, conn_state); - intel_audio_codec_enable(encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void vlv_enable_dp(struct intel_atomic_state *state, @@ -695,8 +695,8 @@ static void vlv_enable_dp(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - intel_audio_codec_enable(encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void g4x_pre_enable_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f70af660dfcf..ca7ca3951de7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3201,8 +3201,6 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, if (!dig_port->lspcon.active || intel_dp_has_hdmi_sink(&dig_port->dp)) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); - intel_audio_codec_enable(encoder, crtc_state, conn_state); - trans_port_sync_stop_link_train(state, encoder, crtc_state); } @@ -3333,8 +3331,6 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, DDI_BUF_CTL(port), buf_ctl); intel_wait_ddi_buf_active(dev_priv, port); - - intel_audio_codec_enable(encoder, crtc_state, conn_state); } static void intel_enable_ddi(struct intel_atomic_state *state, @@ -3362,6 +3358,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_enable_ddi_dp(state, encoder, crtc_state, conn_state); intel_hdcp_enable(state, encoder, crtc_state, conn_state); + + intel_audio_codec_enable(encoder, crtc_state, conn_state); } static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3375,8 +3373,6 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, intel_dp->link_trained = false; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_psr_disable(intel_dp, old_crtc_state); intel_edp_backlight_off(old_conn_state); /* Disable the decompression in DP Sink */ @@ -3395,8 +3391,6 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = old_conn_state->connector; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - if (!intel_hdmi_handle_sink_scrambling(encoder, connector, false, false)) drm_dbg_kms(&i915->drm, @@ -3409,6 +3403,8 @@ static void intel_disable_ddi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + intel_tc_port_link_cancel_reset_work(enc_to_dig_port(encoder)); intel_hdcp_disable(to_intel_connector(old_conn_state->connector)); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index d3d53e1b4489..7f6533c99e2c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -918,10 +918,10 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, drm_dbg_kms(&i915->drm, "active links %d\n", intel_dp->active_mst_links); - intel_hdcp_disable(intel_mst->connector); - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + intel_hdcp_disable(intel_mst->connector); + intel_dp_sink_disable_decompression(state, connector, old_crtc_state); } @@ -1164,9 +1164,9 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_crtc_vblank_on(pipe_config); - intel_audio_codec_enable(encoder, pipe_config, conn_state); - intel_hdcp_enable(state, encoder, pipe_config, conn_state); + + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, From ceb53adad7e3cb4806d5fadcd583eade32a6b915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:18 +0200 Subject: [PATCH 1279/7721] drm/i915: Wrap g4x+ DP/HDMI audio enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put a wrapper around the intel_audio_codec_{enable,disable}() calls in the g4x+ DP/HDMI code. We shall move the presence detect enable/disable into the wrappers later. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 26 ++++++++++++-- drivers/gpu/drm/i915/display/g4x_hdmi.c | 48 +++++++++++++++---------- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 79ef2b435beb..ecc2ec866424 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -475,6 +475,26 @@ intel_dp_link_down(struct intel_encoder *encoder, } } +static void g4x_dp_audio_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + if (!crtc_state->has_audio) + return; + + intel_audio_codec_enable(encoder, crtc_state, conn_state); +} + +static void g4x_dp_audio_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + if (!old_crtc_state->has_audio) + return; + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); +} + static void intel_disable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -482,7 +502,7 @@ static void intel_disable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + g4x_dp_audio_disable(encoder, old_crtc_state, old_conn_state); intel_dp->link_trained = false; @@ -687,7 +707,7 @@ static void g4x_enable_dp(struct intel_atomic_state *state, { intel_enable_dp(state, encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_dp_audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_dp(struct intel_atomic_state *state, @@ -696,7 +716,7 @@ static void vlv_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { intel_edp_backlight_on(pipe_config, conn_state); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_dp_audio_enable(encoder, pipe_config, conn_state); } static void g4x_pre_enable_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 45e044b4a88d..9c70245d8b0a 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -235,18 +235,38 @@ static void g4x_hdmi_enable_port(struct intel_encoder *encoder, intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } +static void g4x_hdmi_audio_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + if (!crtc_state->has_audio) + return; + + drm_WARN_ON(&i915->drm, !crtc_state->has_hdmi_sink); + + intel_audio_codec_enable(encoder, crtc_state, conn_state); +} + +static void g4x_hdmi_audio_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + if (!old_crtc_state->has_audio) + return; + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); +} + static void g4x_enable_hdmi(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - g4x_hdmi_enable_port(encoder, pipe_config); - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); } static void ibx_enable_hdmi(struct intel_atomic_state *state, @@ -297,9 +317,7 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); } static void cpt_enable_hdmi(struct intel_atomic_state *state, @@ -352,9 +370,7 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE, 0); } - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_hdmi(struct intel_atomic_state *state, @@ -362,11 +378,7 @@ static void vlv_enable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); } static void intel_disable_hdmi(struct intel_atomic_state *state, @@ -433,7 +445,7 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + g4x_hdmi_audio_disable(encoder, old_crtc_state, old_conn_state); intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state); } @@ -443,7 +455,7 @@ static void pch_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + g4x_hdmi_audio_disable(encoder, old_crtc_state, old_conn_state); } static void pch_post_disable_hdmi(struct intel_atomic_state *state, From 0195e381b14fc8b16f359cbf45193bcdaaf5cd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:19 +0200 Subject: [PATCH 1280/7721] drm/i915: Split g4x+ DP audio presence detect from port enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the hsw+ approach toggle the audio presence detect when we set up the ELD, instead of doing it when turning the port on/off. This will facilitate audio enable/disable to happen during fastsets instead of requiring a full modeset. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index ecc2ec866424..266cb594d793 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -432,7 +432,7 @@ intel_dp_link_down(struct intel_encoder *encoder, intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); - intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE); + intel_dp->DP &= ~DP_PORT_EN; intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); @@ -479,9 +479,16 @@ static void g4x_dp_audio_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + if (!crtc_state->has_audio) return; + /* Enable audio presence detect */ + intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; + intel_de_write(i915, intel_dp->output_reg, intel_dp->DP); + intel_audio_codec_enable(encoder, crtc_state, conn_state); } @@ -489,10 +496,17 @@ static void g4x_dp_audio_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + if (!old_crtc_state->has_audio) return; intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + + /* Disable audio presence detect */ + intel_dp->DP &= ~DP_AUDIO_OUTPUT_ENABLE; + intel_de_write(i915, intel_dp->output_reg, intel_dp->DP); } static void intel_disable_dp(struct intel_atomic_state *state, @@ -651,8 +665,6 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp, * fail when the power sequencer is freshly used for this port. */ intel_dp->DP |= DP_PORT_EN; - if (crtc_state->has_audio) - intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); From 4645e8980479a0cbfa99bdd07c562cec1597e9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:20 +0200 Subject: [PATCH 1281/7721] drm/i915: Split g4x+ HDMI audio presence detect from port enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the hsw+ approach toggle the audio presence detect when we set up the ELD, instead of doing it when turning the port on/off. This will facilitate audio enable/disable to happen during fastsets instead of requiring a full modeset. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_hdmi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 9c70245d8b0a..beda6b480bf1 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -228,8 +228,6 @@ static void g4x_hdmi_enable_port(struct intel_encoder *encoder, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); @@ -240,12 +238,16 @@ static void g4x_hdmi_audio_enable(struct intel_encoder *encoder, const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); if (!crtc_state->has_audio) return; drm_WARN_ON(&i915->drm, !crtc_state->has_hdmi_sink); + /* Enable audio presence detect */ + intel_de_rmw(i915, hdmi->hdmi_reg, 0, HDMI_AUDIO_ENABLE); + intel_audio_codec_enable(encoder, crtc_state, conn_state); } @@ -253,10 +255,16 @@ static void g4x_hdmi_audio_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); + if (!old_crtc_state->has_audio) return; intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + + /* Disable audio presence detect */ + intel_de_rmw(i915, hdmi->hdmi_reg, HDMI_AUDIO_ENABLE, 0); } static void g4x_enable_hdmi(struct intel_atomic_state *state, @@ -282,8 +290,6 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; /* * HW workaround, need to write this twice for issue @@ -335,8 +341,6 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; /* * WaEnableHDMI8bpcBefore12bpc:snb,ivb @@ -396,7 +400,7 @@ static void intel_disable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); - temp &= ~(SDVO_ENABLE | HDMI_AUDIO_ENABLE); + temp &= ~SDVO_ENABLE; intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); From 3654a48ab16c243519c40849a61b617828a4a61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:21 +0200 Subject: [PATCH 1282/7721] drm/i915: Convert audio enable/disable into encoder vfuncs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add encoder vfuncs for audio enable/disable. This will allow audio to be enabled/disabled during fastsets. An encoder hook is necessary as on pre-hsw platforms different encoder types implement audio in different ways. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 8 ++++--- drivers/gpu/drm/i915/display/g4x_hdmi.c | 14 ++++++----- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +++-- .../drm/i915/display/intel_display_types.h | 6 +++++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 6 +++-- drivers/gpu/drm/i915/display/intel_sdvo.c | 23 ++++++++++++++----- 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 266cb594d793..96232af42db2 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -516,7 +516,7 @@ static void intel_disable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - g4x_dp_audio_disable(encoder, old_crtc_state, old_conn_state); + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); intel_dp->link_trained = false; @@ -719,7 +719,7 @@ static void g4x_enable_dp(struct intel_atomic_state *state, { intel_enable_dp(state, encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); - g4x_dp_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_dp(struct intel_atomic_state *state, @@ -728,7 +728,7 @@ static void vlv_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { intel_edp_backlight_on(pipe_config, conn_state); - g4x_dp_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void g4x_pre_enable_dp(struct intel_atomic_state *state, @@ -1357,6 +1357,8 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv, intel_encoder->disable = g4x_disable_dp; intel_encoder->post_disable = g4x_post_disable_dp; } + intel_encoder->audio_enable = g4x_dp_audio_enable; + intel_encoder->audio_disable = g4x_dp_audio_disable; if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) || (HAS_PCH_CPT(dev_priv) && port != PORT_A)) diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index beda6b480bf1..26a0981102ff 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -274,7 +274,7 @@ static void g4x_enable_hdmi(struct intel_atomic_state *state, { g4x_hdmi_enable_port(encoder, pipe_config); - g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void ibx_enable_hdmi(struct intel_atomic_state *state, @@ -323,7 +323,7 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } - g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void cpt_enable_hdmi(struct intel_atomic_state *state, @@ -374,7 +374,7 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE, 0); } - g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_hdmi(struct intel_atomic_state *state, @@ -382,7 +382,7 @@ static void vlv_enable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - g4x_hdmi_audio_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void intel_disable_hdmi(struct intel_atomic_state *state, @@ -449,7 +449,7 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - g4x_hdmi_audio_disable(encoder, old_crtc_state, old_conn_state); + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state); } @@ -459,7 +459,7 @@ static void pch_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - g4x_hdmi_audio_disable(encoder, old_crtc_state, old_conn_state); + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); } static void pch_post_disable_hdmi(struct intel_atomic_state *state, @@ -766,6 +766,8 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv, else intel_encoder->enable = g4x_enable_hdmi; } + intel_encoder->audio_enable = g4x_hdmi_audio_enable; + intel_encoder->audio_disable = g4x_hdmi_audio_disable; intel_encoder->shutdown = intel_hdmi_encoder_shutdown; intel_encoder->type = INTEL_OUTPUT_HDMI; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ca7ca3951de7..06558fd8d1f1 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3359,7 +3359,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_hdcp_enable(state, encoder, crtc_state, conn_state); - intel_audio_codec_enable(encoder, crtc_state, conn_state); + encoder->audio_enable(encoder, crtc_state, conn_state); } static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3403,7 +3403,7 @@ static void intel_disable_ddi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); intel_tc_port_link_cancel_reset_work(enc_to_dig_port(encoder)); @@ -4936,6 +4936,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, encoder->post_pll_disable = intel_ddi_post_pll_disable; encoder->post_disable = intel_ddi_post_disable; encoder->update_pipe = intel_ddi_update_pipe; + encoder->audio_enable = intel_audio_codec_enable; + encoder->audio_disable = intel_audio_codec_disable; encoder->get_hw_state = intel_ddi_get_hw_state; encoder->sync_state = intel_ddi_sync_state; encoder->initial_fastset_check = intel_ddi_initial_fastset_check; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 9a44350ba05d..b3e942f2eeb0 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -198,6 +198,12 @@ struct intel_encoder { struct intel_encoder *, const struct intel_crtc_state *, const struct drm_connector_state *); + void (*audio_enable)(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); + void (*audio_disable)(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state); /* Read out the current hw state of this connector, returning true if * the encoder is active. If the encoder is enabled it also set the pipe * it is connected to in the pipe parameter. */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 7f6533c99e2c..ebd72c56b124 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -918,7 +918,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, drm_dbg_kms(&i915->drm, "active links %d\n", intel_dp->active_mst_links); - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); intel_hdcp_disable(intel_mst->connector); @@ -1166,7 +1166,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_hdcp_enable(state, encoder, pipe_config, conn_state); - intel_audio_codec_enable(encoder, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, @@ -1626,6 +1626,8 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *dig_port, enum pipe intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp; intel_encoder->pre_enable = intel_mst_pre_enable_dp; intel_encoder->enable = intel_mst_enable_dp; + intel_encoder->audio_enable = intel_audio_codec_enable; + intel_encoder->audio_disable = intel_audio_codec_disable; intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state; intel_encoder->get_config = intel_dp_mst_enc_get_config; intel_encoder->initial_fastset_check = intel_dp_mst_initial_fastset_check; diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index a636f42ceae5..c7af7e046188 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1787,17 +1787,28 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, intel_sdvo_get_eld(intel_sdvo, pipe_config); } -static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo) +static void intel_sdvo_disable_audio(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) { + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + + if (!old_crtc_state->has_audio) + return; + intel_sdvo_set_audio_state(intel_sdvo, 0); } -static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo, +static void intel_sdvo_enable_audio(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); const u8 *eld = crtc_state->eld; + if (!crtc_state->has_audio) + return; + intel_sdvo_set_audio_state(intel_sdvo, 0); intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD, @@ -1818,8 +1829,7 @@ static void intel_disable_sdvo(struct intel_atomic_state *state, struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); u32 temp; - if (old_crtc_state->has_audio) - intel_sdvo_disable_audio(intel_sdvo); + encoder->audio_disable(encoder, old_crtc_state, conn_state); intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) @@ -1913,8 +1923,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, DRM_MODE_DPMS_ON); intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo_connector->output_flag); - if (pipe_config->has_audio) - intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static enum drm_mode_status @@ -3390,6 +3399,8 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, } intel_encoder->pre_enable = intel_sdvo_pre_enable; intel_encoder->enable = intel_enable_sdvo; + intel_encoder->audio_enable = intel_sdvo_enable_audio; + intel_encoder->audio_disable = intel_sdvo_disable_audio; intel_encoder->get_hw_state = intel_sdvo_get_hw_state; intel_encoder->get_config = intel_sdvo_get_config; From cff742cc6851f469ae1192877a308884a6439005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:22 +0200 Subject: [PATCH 1283/7721] drm/i915: Hoist the encoder->audio_{enable,disable}() calls higher up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Push the encoder->audio_{enable,disable}() calls out from the encoder->{enable,disable}() hooks. Moving towards audio fastset. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 2 - drivers/gpu/drm/i915/display/g4x_hdmi.c | 10 ---- drivers/gpu/drm/i915/display/intel_ddi.c | 3 -- drivers/gpu/drm/i915/display/intel_display.c | 49 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 -- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 96232af42db2..dfe0b07a122d 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -516,8 +516,6 @@ static void intel_disable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - encoder->audio_disable(encoder, old_crtc_state, old_conn_state); - intel_dp->link_trained = false; /* diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 26a0981102ff..8096492b3fad 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -273,8 +273,6 @@ static void g4x_enable_hdmi(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { g4x_hdmi_enable_port(encoder, pipe_config); - - encoder->audio_enable(encoder, pipe_config, conn_state); } static void ibx_enable_hdmi(struct intel_atomic_state *state, @@ -322,8 +320,6 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } - - encoder->audio_enable(encoder, pipe_config, conn_state); } static void cpt_enable_hdmi(struct intel_atomic_state *state, @@ -373,8 +369,6 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, intel_de_rmw(dev_priv, TRANS_CHICKEN1(pipe), TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE, 0); } - - encoder->audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_hdmi(struct intel_atomic_state *state, @@ -382,7 +376,6 @@ static void vlv_enable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - encoder->audio_enable(encoder, pipe_config, conn_state); } static void intel_disable_hdmi(struct intel_atomic_state *state, @@ -449,8 +442,6 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - encoder->audio_disable(encoder, old_crtc_state, old_conn_state); - intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state); } @@ -459,7 +450,6 @@ static void pch_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - encoder->audio_disable(encoder, old_crtc_state, old_conn_state); } static void pch_post_disable_hdmi(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 06558fd8d1f1..38f28c480b38 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3359,7 +3359,6 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_hdcp_enable(state, encoder, crtc_state, conn_state); - encoder->audio_enable(encoder, crtc_state, conn_state); } static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3403,8 +3402,6 @@ static void intel_disable_ddi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - encoder->audio_disable(encoder, old_crtc_state, old_conn_state); - intel_tc_port_link_cancel_reset_work(enc_to_dig_port(encoder)); intel_hdcp_disable(to_intel_connector(old_conn_state->connector)); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 98ea3591665f..61594690b1a9 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -888,6 +888,48 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) (DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915)); } +static void intel_encoders_audio_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct drm_connector_state *conn_state; + struct drm_connector *conn; + int i; + + for_each_new_connector_in_state(&state->base, conn, conn_state, i) { + struct intel_encoder *encoder = + to_intel_encoder(conn_state->best_encoder); + + if (conn_state->crtc != &crtc->base) + continue; + + if (encoder->audio_enable) + encoder->audio_enable(encoder, crtc_state, conn_state); + } +} + +static void intel_encoders_audio_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct drm_connector_state *old_conn_state; + struct drm_connector *conn; + int i; + + for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) { + struct intel_encoder *encoder = + to_intel_encoder(old_conn_state->best_encoder); + + if (old_conn_state->crtc != &crtc->base) + continue; + + if (encoder->audio_disable) + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); + } +} + #define is_enabling(feature, old_crtc_state, new_crtc_state) \ ((!(old_crtc_state)->feature || intel_crtc_needs_modeset(new_crtc_state)) && \ (new_crtc_state)->feature) @@ -1460,6 +1502,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); + intel_encoders_audio_enable(state, crtc); if (HAS_PCH_CPT(dev_priv)) intel_wait_for_pipe_scanline_moving(crtc); @@ -1633,6 +1676,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); + intel_encoders_audio_enable(state, crtc); if (psl_clkgate_wa) { intel_crtc_wait_for_next_vblank(crtc); @@ -1684,6 +1728,7 @@ static void ilk_crtc_disable(struct intel_atomic_state *state, intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); + intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_crtc_vblank_off(old_crtc_state); @@ -1718,6 +1763,7 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, * Need care with mst->ddi interactions. */ if (!intel_crtc_is_bigjoiner_slave(old_crtc_state)) { + intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_encoders_post_disable(state, crtc); } @@ -1987,6 +2033,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); + intel_encoders_audio_enable(state, crtc); } static void i9xx_crtc_enable(struct intel_atomic_state *state, @@ -2028,6 +2075,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); + intel_encoders_audio_enable(state, crtc); /* prevents spurious underruns */ if (DISPLAY_VER(dev_priv) == 2) @@ -2064,6 +2112,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) == 2) intel_crtc_wait_for_next_vblank(crtc); + intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_crtc_vblank_off(old_crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index ebd72c56b124..63364c9602ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -918,8 +918,6 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, drm_dbg_kms(&i915->drm, "active links %d\n", intel_dp->active_mst_links); - encoder->audio_disable(encoder, old_crtc_state, old_conn_state); - intel_hdcp_disable(intel_mst->connector); intel_dp_sink_disable_decompression(state, connector, old_crtc_state); @@ -1165,8 +1163,6 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_crtc_vblank_on(pipe_config); intel_hdcp_enable(state, encoder, pipe_config, conn_state); - - encoder->audio_enable(encoder, pipe_config, conn_state); } static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, From 109e1e898abd2c68ceb02058c56db7cf6b9c18d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:23 +0200 Subject: [PATCH 1284/7721] drm/i915: Push audio_{enable,disable}() to the pre/post pane update stage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relocate the audio enable/disable from the full modeset hooks into the common pre/post plane update stage of the commit. Audio fastset is within easy reach now. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-11-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 31 +++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 61594690b1a9..e923ff634d10 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -989,6 +989,24 @@ static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state, vrr_params_changed(old_crtc_state, new_crtc_state))); } +static bool audio_enabling(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + if (!new_crtc_state->hw.active) + return false; + + return is_enabling(has_audio, old_crtc_state, new_crtc_state); +} + +static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + if (!old_crtc_state->hw.active) + return false; + + return is_disabling(has_audio, old_crtc_state, new_crtc_state); +} + #undef is_disabling #undef is_enabling @@ -1029,6 +1047,9 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_post_update(new_crtc_state); + + if (audio_enabling(old_crtc_state, new_crtc_state)) + intel_encoders_audio_enable(state, crtc); } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -1112,6 +1133,9 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, intel_crtc_update_active_timings(old_crtc_state, false); } + if (audio_disabling(old_crtc_state, new_crtc_state)) + intel_encoders_audio_disable(state, crtc); + intel_drrs_deactivate(old_crtc_state); intel_psr_pre_plane_update(state, crtc); @@ -1502,7 +1526,6 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); - intel_encoders_audio_enable(state, crtc); if (HAS_PCH_CPT(dev_priv)) intel_wait_for_pipe_scanline_moving(crtc); @@ -1676,7 +1699,6 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); - intel_encoders_audio_enable(state, crtc); if (psl_clkgate_wa) { intel_crtc_wait_for_next_vblank(crtc); @@ -1728,7 +1750,6 @@ static void ilk_crtc_disable(struct intel_atomic_state *state, intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); - intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_crtc_vblank_off(old_crtc_state); @@ -1763,7 +1784,6 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, * Need care with mst->ddi interactions. */ if (!intel_crtc_is_bigjoiner_slave(old_crtc_state)) { - intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_encoders_post_disable(state, crtc); } @@ -2033,7 +2053,6 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); - intel_encoders_audio_enable(state, crtc); } static void i9xx_crtc_enable(struct intel_atomic_state *state, @@ -2075,7 +2094,6 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, intel_crtc_vblank_on(new_crtc_state); intel_encoders_enable(state, crtc); - intel_encoders_audio_enable(state, crtc); /* prevents spurious underruns */ if (DISPLAY_VER(dev_priv) == 2) @@ -2112,7 +2130,6 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) == 2) intel_crtc_wait_for_next_vblank(crtc); - intel_encoders_audio_disable(state, crtc); intel_encoders_disable(state, crtc); intel_crtc_vblank_off(old_crtc_state); From 07e823c0fd991565106eff6f03892c5d645cd690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Nov 2023 07:43:24 +0200 Subject: [PATCH 1285/7721] drm/i915: Implement audio fastset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no real reason why we'd need a full modeset for audio changes. So let's allow audio to be toggled during fastset. In case the ELD changes while has_audio isn't changing state we force both audio disable and enable so the new ELD gets propagated to the audio driver. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231121054324.9988-12-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 32 ++++++-------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e923ff634d10..cf338ac71229 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -995,7 +995,9 @@ static bool audio_enabling(const struct intel_crtc_state *old_crtc_state, if (!new_crtc_state->hw.active) return false; - return is_enabling(has_audio, old_crtc_state, new_crtc_state); + return is_enabling(has_audio, old_crtc_state, new_crtc_state) || + (new_crtc_state->has_audio && + memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); } static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, @@ -1004,7 +1006,9 @@ static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, if (!old_crtc_state->hw.active) return false; - return is_disabling(has_audio, old_crtc_state, new_crtc_state); + return is_disabling(has_audio, old_crtc_state, new_crtc_state) || + (old_crtc_state->has_audio && + memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); } #undef is_disabling @@ -4956,23 +4960,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } \ } while (0) -/* - * Checks state where we only read out the enabling, but not the entire - * state itself (like full infoframes or ELD for audio). These states - * require a full modeset on bootup to fix up. - */ -#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) do { \ - if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \ - PIPE_CONF_CHECK_BOOL(name); \ - } else { \ - pipe_config_mismatch(fastset, crtc, __stringify(name), \ - "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)", \ - str_yes_no(current_config->name), \ - str_yes_no(pipe_config->name)); \ - ret = false; \ - } \ -} while (0) - #define PIPE_CONF_CHECK_P(name) do { \ if (current_config->name != pipe_config->name) { \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ @@ -5160,8 +5147,10 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_BOOL(enhanced_framing); PIPE_CONF_CHECK_BOOL(fec_enable); - PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); - PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES); + if (!fastset) { + PIPE_CONF_CHECK_BOOL(has_audio); + PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES); + } PIPE_CONF_CHECK_X(gmch_pfit.control); /* pfit ratios are autocomputed by the hw on gen4+ */ @@ -5331,7 +5320,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_BOOL -#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE #undef PIPE_CONF_CHECK_P #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_COLOR_LUT From aebe6f055d9f0e82a61ffb7c5c45f6c3af54b76b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 7 Oct 2023 15:50:02 +0200 Subject: [PATCH 1286/7721] media: vde: Use struct_size() Use struct_size() which is much more common than this offsetof(). Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nvidia/tegra-vde/v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index bd8c207d5b54..0f48ce6f243e 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -813,7 +813,7 @@ static int tegra_open(struct file *file) struct tegra_ctx *ctx; int err; - ctx = kzalloc(offsetof(struct tegra_ctx, ctrls[ARRAY_SIZE(ctrl_cfgs)]), + ctx = kzalloc(struct_size(ctx, ctrls, ARRAY_SIZE(ctrl_cfgs)), GFP_KERNEL); if (!ctx) return -ENOMEM; From ce122258ed8678d0a32b825ba3d7dd3cc16052df Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Wed, 11 Oct 2023 09:30:03 +0200 Subject: [PATCH 1287/7721] media: nuvoton: npcm-video: Fix sleeping in atomic context Change to use mutex instead of spinlock for buffer list lock to fix sleeping in atomic context warnings reported by the Smatch tool. Fixes: 70721089985c ("media: nuvoton: Add driver for NPCM video capture and encoding engine") Reported-by: Dan Carpenter Signed-off-by: Marvin Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nuvoton/npcm-video.c | 30 +++++++++------------ 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index f9b4e36a5175..267e301f2b26 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -120,7 +119,7 @@ struct npcm_video { struct mutex video_lock; /* v4l2 and videobuf2 lock */ struct list_head buffers; - spinlock_t lock; /* buffer list lock */ + struct mutex buffer_lock; /* buffer list lock */ unsigned long flags; unsigned int sequence; @@ -782,7 +781,6 @@ static int npcm_video_start_frame(struct npcm_video *video) { struct npcm_video_buffer *buf; struct regmap *vcd = video->vcd_regmap; - unsigned long flags; unsigned int val; int ret; @@ -798,17 +796,17 @@ static int npcm_video_start_frame(struct npcm_video *video) return -EBUSY; } - spin_lock_irqsave(&video->lock, flags); + mutex_lock(&video->buffer_lock); buf = list_first_entry_or_null(&video->buffers, struct npcm_video_buffer, link); if (!buf) { - spin_unlock_irqrestore(&video->lock, flags); + mutex_unlock(&video->buffer_lock); dev_dbg(video->dev, "No empty buffers; skip capture frame\n"); return 0; } set_bit(VIDEO_CAPTURING, &video->flags); - spin_unlock_irqrestore(&video->lock, flags); + mutex_unlock(&video->buffer_lock); npcm_video_vcd_state_machine_reset(video); @@ -834,14 +832,13 @@ static void npcm_video_bufs_done(struct npcm_video *video, enum vb2_buffer_state state) { struct npcm_video_buffer *buf; - unsigned long flags; - spin_lock_irqsave(&video->lock, flags); + mutex_lock(&video->buffer_lock); list_for_each_entry(buf, &video->buffers, link) vb2_buffer_done(&buf->vb.vb2_buf, state); INIT_LIST_HEAD(&video->buffers); - spin_unlock_irqrestore(&video->lock, flags); + mutex_unlock(&video->buffer_lock); } static void npcm_video_get_diff_rect(struct npcm_video *video, unsigned int index) @@ -1071,12 +1068,12 @@ static irqreturn_t npcm_video_irq(int irq, void *arg) if (status & VCD_STAT_DONE) { regmap_write(vcd, VCD_INTE, 0); - spin_lock(&video->lock); + mutex_lock(&video->buffer_lock); clear_bit(VIDEO_CAPTURING, &video->flags); buf = list_first_entry_or_null(&video->buffers, struct npcm_video_buffer, link); if (!buf) { - spin_unlock(&video->lock); + mutex_unlock(&video->buffer_lock); return IRQ_NONE; } @@ -1093,7 +1090,7 @@ static irqreturn_t npcm_video_irq(int irq, void *arg) size = npcm_video_hextile(video, index, dma_addr, addr); break; default: - spin_unlock(&video->lock); + mutex_unlock(&video->buffer_lock); return IRQ_NONE; } @@ -1104,7 +1101,7 @@ static irqreturn_t npcm_video_irq(int irq, void *arg) vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); list_del(&buf->link); - spin_unlock(&video->lock); + mutex_unlock(&video->buffer_lock); if (npcm_video_start_frame(video)) dev_err(video->dev, "Failed to capture next frame\n"); @@ -1508,13 +1505,12 @@ static void npcm_video_buf_queue(struct vb2_buffer *vb) struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct npcm_video_buffer *nvb = to_npcm_video_buffer(vbuf); - unsigned long flags; bool empty; - spin_lock_irqsave(&video->lock, flags); + mutex_lock(&video->buffer_lock); empty = list_empty(&video->buffers); list_add_tail(&nvb->link, &video->buffers); - spin_unlock_irqrestore(&video->lock, flags); + mutex_unlock(&video->buffer_lock); if (test_bit(VIDEO_STREAMING, &video->flags) && !test_bit(VIDEO_CAPTURING, &video->flags) && empty) { @@ -1744,8 +1740,8 @@ static int npcm_video_probe(struct platform_device *pdev) return -ENOMEM; video->dev = &pdev->dev; - spin_lock_init(&video->lock); mutex_init(&video->video_lock); + mutex_init(&video->buffer_lock); INIT_LIST_HEAD(&video->buffers); regs = devm_platform_ioremap_resource(pdev, 0); From 0cb8c9482501c46854ddb3d43b1bc05d771b9624 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Oct 2023 11:42:33 +0200 Subject: [PATCH 1288/7721] media: qcom: camss: clean up a check Imagine that "->vfe_num" is zero, then the subtraction will underflow to UINT_MAX. Plus it's just cleaner to use >= instead. Signed-off-by: Dan Carpenter Acked-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-ispif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index be9d2f0a10c1..ddfe94377ee5 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -270,7 +270,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) unsigned long time; u32 val; - if (vfe_id > camss->res->vfe_num - 1) { + if (vfe_id >= camss->res->vfe_num) { dev_err(camss->dev, "Error: asked reset for invalid VFE%d\n", vfe_id); return -ENOENT; From ded85b0c0edd8f45fec88783d7555a5b982449c1 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Fri, 13 Oct 2023 01:09:12 +0200 Subject: [PATCH 1289/7721] media: pvrusb2: fix use after free on context disconnection Upon module load, a kthread is created targeting the pvr2_context_thread_func function, which may call pvr2_context_destroy and thus call kfree() on the context object. However, that might happen before the usb hub_event handler is able to notify the driver. This patch adds a sanity check before the invalid read reported by syzbot, within the context disconnection call stack. Reported-and-tested-by: syzbot+621409285c4156a009b3@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/000000000000a02a4205fff8eb92@google.com/ Fixes: e5be15c63804 ("V4L/DVB (7711): pvrusb2: Fix race on module unload") Signed-off-by: Ricardo B. Marliere Acked-by: Mike Isely Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index 14170a5d72b3..1764674de98b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -268,7 +268,8 @@ void pvr2_context_disconnect(struct pvr2_context *mp) { pvr2_hdw_disconnect(mp->hdw); mp->disconnect_flag = !0; - pvr2_context_notify(mp); + if (!pvr2_context_shutok()) + pvr2_context_notify(mp); } From 074728523dd18da4226d43db6756ae9128d6a2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 26 Oct 2023 23:47:40 +0200 Subject: [PATCH 1290/7721] media: staging: media: tegra-video: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert the three tegra-video drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Luca Ceresoli Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-video/csi.c | 6 ++---- drivers/staging/media/tegra-video/vi.c | 6 ++---- drivers/staging/media/tegra-video/vip.c | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c index 9aa72863c213..0d94115b9bbb 100644 --- a/drivers/staging/media/tegra-video/csi.c +++ b/drivers/staging/media/tegra-video/csi.c @@ -818,15 +818,13 @@ static int tegra_csi_probe(struct platform_device *pdev) return ret; } -static int tegra_csi_remove(struct platform_device *pdev) +static void tegra_csi_remove(struct platform_device *pdev) { struct tegra_csi *csi = platform_get_drvdata(pdev); host1x_client_unregister(&csi->client); pm_runtime_disable(&pdev->dev); - - return 0; } #if defined(CONFIG_ARCH_TEGRA_210_SOC) @@ -852,5 +850,5 @@ struct platform_driver tegra_csi_driver = { .pm = &tegra_csi_pm_ops, }, .probe = tegra_csi_probe, - .remove = tegra_csi_remove, + .remove_new = tegra_csi_remove, }; diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 94171e62dee9..61169ff13ec5 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -1944,7 +1944,7 @@ static int tegra_vi_probe(struct platform_device *pdev) return ret; } -static int tegra_vi_remove(struct platform_device *pdev) +static void tegra_vi_remove(struct platform_device *pdev) { struct tegra_vi *vi = platform_get_drvdata(pdev); @@ -1953,8 +1953,6 @@ static int tegra_vi_remove(struct platform_device *pdev) if (vi->ops->vi_enable) vi->ops->vi_enable(vi, false); pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id tegra_vi_of_id_table[] = { @@ -1979,5 +1977,5 @@ struct platform_driver tegra_vi_driver = { .pm = &tegra_vi_pm_ops, }, .probe = tegra_vi_probe, - .remove = tegra_vi_remove, + .remove_new = tegra_vi_remove, }; diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c index e95cc7bb190e..8504b9ea9cea 100644 --- a/drivers/staging/media/tegra-video/vip.c +++ b/drivers/staging/media/tegra-video/vip.c @@ -254,15 +254,13 @@ static int tegra_vip_probe(struct platform_device *pdev) return 0; } -static int tegra_vip_remove(struct platform_device *pdev) +static void tegra_vip_remove(struct platform_device *pdev) { struct tegra_vip *vip = platform_get_drvdata(pdev); host1x_client_unregister(&vip->client); pm_runtime_disable(&pdev->dev); - - return 0; } #if defined(CONFIG_ARCH_TEGRA_2x_SOC) @@ -283,5 +281,5 @@ struct platform_driver tegra_vip_driver = { .of_match_table = tegra_vip_of_id_table, }, .probe = tegra_vip_probe, - .remove = tegra_vip_remove, + .remove_new = tegra_vip_remove, }; From c411b39df8b84945e6d93e8c5ea586eaa5466f2a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 2 Nov 2023 15:04:05 +0100 Subject: [PATCH 1291/7721] media: ivtv: don't call s_stream(0) if not streaming Recently a WARN_ON was added in v4l2-subdev.c to warn if s_stream was called unnecessarily. The ivtv driver hits this once when it is loaded for the first time. Add a bool to avoid this warning. [hverkuil: added a comment for the sd_video_is_streaming field] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-driver.h | 1 + drivers/media/pci/ivtv/ivtv-streams.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index ce3a7ca51736..a6ffa99e16bc 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -619,6 +619,7 @@ struct ivtv { u32 hw_flags; /* hardware description of the board */ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ struct v4l2_subdev *sd_video; /* controlling video decoder subdev */ + bool sd_video_is_streaming; /* is video already streaming? */ struct v4l2_subdev *sd_audio; /* controlling audio subdev */ struct v4l2_subdev *sd_muxer; /* controlling audio muxer subdev */ resource_size_t base_addr; /* PCI resource base address */ diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index 13d7d55e6594..af9e6235c74d 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -623,10 +623,12 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* Avoid tinny audio problem - ensure audio clocks are going */ v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1); /* Avoid unpredictable PCI bus hang - disable video clocks */ - v4l2_subdev_call(itv->sd_video, video, s_stream, 0); + if (itv->sd_video_is_streaming) + v4l2_subdev_call(itv->sd_video, video, s_stream, 0); ivtv_msleep_timeout(300, 0); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); v4l2_subdev_call(itv->sd_video, video, s_stream, 1); + itv->sd_video_is_streaming = true; } /* begin_capture */ From d8212c5c87c143ca01b78f6bf61244af07e0058e Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Mon, 6 Nov 2023 15:48:09 +0100 Subject: [PATCH 1292/7721] media: mtk-jpeg: Remove cancel worker in mtk_jpeg_remove to avoid the crash of multi-core JPEG devices This patch reverts commit c677d7ae8314 ("media: mtk-jpeg: Fix use after free bug due to uncanceled work"). The job_timeout_work is initialized only for the single-core JPEG device so it will cause the crash for multi-core JPEG devices. Fix it by removing the cancel_delayed_work_sync function. Fixes: c677d7ae8314 ("media: mtk-jpeg: Fix use after free bug due to uncanceled work") Signed-off-by: Zheng Wang Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 73a063b1569b..7c2e6a2f6c40 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1402,7 +1402,6 @@ static void mtk_jpeg_remove(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev); - cancel_delayed_work_sync(&jpeg->job_timeout_work); pm_runtime_disable(&pdev->dev); video_unregister_device(jpeg->vdev); v4l2_m2m_release(jpeg->m2m_dev); From 206c857dd17d4d026de85866f1b5f0969f2a109e Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Mon, 6 Nov 2023 15:48:10 +0100 Subject: [PATCH 1293/7721] media: mtk-jpeg: Fix use after free bug due to error path handling in mtk_jpeg_dec_device_run In mtk_jpeg_probe, &jpeg->job_timeout_work is bound with mtk_jpeg_job_timeout_work. In mtk_jpeg_dec_device_run, if error happens in mtk_jpeg_set_dec_dst, it will finally start the worker while mark the job as finished by invoking v4l2_m2m_job_finish. There are two methods to trigger the bug. If we remove the module, it which will call mtk_jpeg_remove to make cleanup. The possible sequence is as follows, which will cause a use-after-free bug. CPU0 CPU1 mtk_jpeg_dec_... | start worker | |mtk_jpeg_job_timeout_work mtk_jpeg_remove | v4l2_m2m_release | kfree(m2m_dev); | | | v4l2_m2m_get_curr_priv | m2m_dev->curr_ctx //use If we close the file descriptor, which will call mtk_jpeg_release, it will have a similar sequence. Fix this bug by starting timeout worker only if started jpegdec worker successfully. Then v4l2_m2m_job_finish will only be called in either mtk_jpeg_job_timeout_work or mtk_jpeg_dec_device_run. Fixes: b2f0d2724ba4 ("[media] vcodec: mediatek: Add Mediatek JPEG Decoder Driver") Signed-off-by: Zheng Wang Signed-off-by: Dmitry Osipenko Cc: stable@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 7c2e6a2f6c40..63165f05e123 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1020,13 +1020,13 @@ static void mtk_jpeg_dec_device_run(void *priv) if (ret < 0) goto dec_end; - schedule_delayed_work(&jpeg->job_timeout_work, - msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); - mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb)) goto dec_end; + schedule_delayed_work(&jpeg->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + spin_lock_irqsave(&jpeg->hw_lock, flags); mtk_jpeg_dec_reset(jpeg->reg_base); mtk_jpeg_dec_set_config(jpeg->reg_base, From 38e1857933def4b3fafc28cc34ff3bbc84cad2c3 Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Mon, 6 Nov 2023 15:48:11 +0100 Subject: [PATCH 1294/7721] media: mtk-jpeg: Fix timeout schedule error in mtk_jpegdec_worker. In mtk_jpegdec_worker, if error occurs in mtk_jpeg_set_dec_dst, it will start the timeout worker and invoke v4l2_m2m_job_finish at the same time. This will break the logic of design for there should be only one function to call v4l2_m2m_job_finish. But now the timeout handler and mtk_jpegdec_worker will both invoke it. Fix it by start the worker only if mtk_jpeg_set_dec_dst successfully finished. Fixes: da4ede4b7fd6 ("media: mtk-jpeg: move data/code inside CONFIG_OF blocks") Signed-off-by: Zheng Wang Signed-off-by: Dmitry Osipenko Cc: stable@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 63165f05e123..ac48658e2de4 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1748,9 +1748,6 @@ static void mtk_jpegdec_worker(struct work_struct *work) v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work, - msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); - mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, @@ -1760,6 +1757,9 @@ static void mtk_jpegdec_worker(struct work_struct *work) goto setdst_end; } + schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags); ctx->total_frame_num++; mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base); From 197f6e6cbf979c05aecceee2ba9b9ed7d7c275b8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 15 Nov 2023 21:59:04 +0100 Subject: [PATCH 1295/7721] media: stm32-dcmi: Drop unnecessary of_match_device() call If probe is reached, we've already matched the device and in the case of DT matching, the struct device_node pointer will be set. Therefore, there is no need to call of_match_device() in probe. Signed-off-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/st/stm32/stm32-dcmi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index 8cb4fdcae137..48140fdf40bb 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -1890,7 +1889,6 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) static int dcmi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match = NULL; struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; struct stm32_dcmi *dcmi; struct vb2_queue *q; @@ -1899,12 +1897,6 @@ static int dcmi_probe(struct platform_device *pdev) struct clk *mclk; int ret = 0; - match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Could not find a match in devicetree\n"); - return -ENODEV; - } - dcmi = devm_kzalloc(&pdev->dev, sizeof(struct stm32_dcmi), GFP_KERNEL); if (!dcmi) return -ENOMEM; From 71025ec7f77674125cb126f88305776151e11d25 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 7 Nov 2023 21:06:28 +0100 Subject: [PATCH 1296/7721] media: cedrus: Update TODO with future rework plans The current TODO list of the cedrus driver is now outdated as most of the points it mentions were already tackled. In addition it is no longer considered relevant to wait for a stateless encoder driver to move it out of staging. The hantro/verisilicon driver was already unstaged without this condition. However the driver suffers from a bad initial design that showed to be very limiting. It was also not a very good fit for a video codec driver either. Since a rework of the driver was already carried out for the purpose of adding encoding support, update the TODO list with a description of the rework. This reworked driver will be published soon and transitional commits from the current driver will be submitted upstreamer after that. It seems best to wait for the rework to land upstream before unstaging the driver, since a major rework is best operated on a staging driver instead of a fully upstream one. Signed-off-by: Paul Kocialkowski Acked-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/TODO | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/TODO b/drivers/staging/media/sunxi/cedrus/TODO index ec277ece47af..00aa304a7e36 100644 --- a/drivers/staging/media/sunxi/cedrus/TODO +++ b/drivers/staging/media/sunxi/cedrus/TODO @@ -1,7 +1,16 @@ -Before this stateless decoder driver can leave the staging area: -* The Request API needs to be stabilized; -* The codec-specific controls need to be thoroughly reviewed to ensure they - cover all intended uses cases; -* Userspace support for the Request API needs to be reviewed; -* Another stateless decoder driver should be submitted; -* At least one stateless encoder driver should be submitted. +This driver suffers from a bad initial design that results in various aspects +being intricated, making it difficult to scale to new codecs and to add encoding +support in the future. + +Before leaving the staging area, it should be reworked to clearly distinguish +between different aspects: +- platform, with resources management, interrupt handler, watchdog, + v4l2 and m2m devices registration; +- proc, with video device registration and related operations; +- context, with m2m context, queue and controls management; +- engine, with each individual codec job execution and codec-specific + operation callbacks; + +This will make it possible to register two different procs (decoder and +encoder) while sharing significant common infrastructure, common v4l2 and m2m +devices but exposing distinct video devices. From ebc733e54a1a79ea2dde2ba5121ae73a188e20d4 Mon Sep 17 00:00:00 2001 From: Ken Lin Date: Wed, 22 Nov 2023 02:24:43 +0100 Subject: [PATCH 1297/7721] media: platform: cros-ec: Add Dexi to the match table The Google Dexi device uses the same approach as the Google Brask which enables the HDMI CEC via the cros-ec-cec driver. Signed-off-by: Ken Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 42dde3f0dbde..52ec0ba4b339 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -324,6 +324,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Boxy", "0000:00:02.0", port_d_conns }, /* Google Taranza */ { "Google", "Taranza", "0000:00:02.0", port_db_conns }, + /* Google Dexi */ + { "Google", "Dexi", "0000:00:02.0", port_db_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, From deaf6b0ad8aede8ca32361a98031585fb5a96758 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 9 Nov 2023 21:16:37 +0100 Subject: [PATCH 1298/7721] media: vicodec: Disable (TRY_)DECODER_CMD for the stateless case The (TRY_)DECODER_CMD ioctls are only useful for stateful decoders and for stateless decoders that support holding capture buffers (which is not the case for this driver). Disable them when registering the stateless decoder. Signed-off-by: Paul Kocialkowski Reviewed-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/test-drivers/vicodec/vicodec-core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 69cbe2c094e1..e13f5452b927 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1240,6 +1240,12 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, struct vicodec_ctx *ctx = file2ctx(file); int ret; + /* + * This ioctl should not be used with a stateless codec that doesn't + * support holding buffers and the associated flush command. + */ + WARN_ON(ctx->is_stateless); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; @@ -2026,7 +2032,7 @@ static const struct v4l2_m2m_ops m2m_ops = { static int register_instance(struct vicodec_dev *dev, struct vicodec_dev_instance *dev_instance, - const char *name, bool is_enc) + const char *name, bool is_enc, bool is_stateless) { struct video_device *vfd; int ret; @@ -2046,10 +2052,11 @@ static int register_instance(struct vicodec_dev *dev, strscpy(vfd->name, name, sizeof(vfd->name)); vfd->device_caps = V4L2_CAP_STREAMING | (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - if (is_enc) { + if (is_enc || is_stateless) { v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - } else { + } + if (!is_enc) { v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); } @@ -2108,17 +2115,17 @@ static int vicodec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder", - true); + true, false); if (ret) goto unreg_dev; ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder", - false); + false, false); if (ret) goto unreg_sf_enc; ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder", - false); + false, true); if (ret) goto unreg_sf_dec; From fa91703dc2e010e48a230dc92967cb5ae23f8680 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Thu, 23 Nov 2023 09:06:58 +0000 Subject: [PATCH 1299/7721] ASoC: cs43130: Allow driver to work without IRQ connection Add a polling mechanism that will keep the driver operational even in absence of physical IRQ connection. If IRQ line is detected, the driver will continue working as usual, in case of missing IRQ line it will fallback to the polling mechanism introduced in this change. This will support users which choose not to connect an IRQ line as it is not critical to part's operation. Signed-off-by: Maciej Strozek Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20231123090658.10418-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 77 ++++++++++++++++++++++++++------------ sound/soc/codecs/cs43130.h | 1 + 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 845611afed85..4f16baf4eafb 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -326,6 +326,34 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int return ret; } +static int cs43130_wait_for_completion(struct cs43130_private *cs43130, struct completion *to_poll, + int time) +{ + int stickies, offset, flag, ret; + + if (cs43130->has_irq_line) { + ret = wait_for_completion_timeout(to_poll, msecs_to_jiffies(time)); + if (ret == 0) + return -ETIMEDOUT; + else + return 0; // Discard number of jiffies left till timeout and return success + } + + if (to_poll == &cs43130->xtal_rdy) { + offset = 0; + flag = CS43130_XTAL_RDY_INT; + } else if (to_poll == &cs43130->pll_rdy) { + offset = 0; + flag = CS43130_PLL_RDY_INT; + } else { + return -EINVAL; + } + + return regmap_read_poll_timeout(cs43130->regmap, CS43130_INT_STATUS_1 + offset, + stickies, (stickies & flag), + 1000, time * 1000); +} + static int cs43130_change_clksrc(struct snd_soc_component *component, enum cs43130_mclk_src_sel src) { @@ -364,14 +392,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_XTAL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->xtal_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret); + return ret; } } @@ -400,14 +427,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_XTAL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->xtal_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret); + return ret; } } @@ -416,14 +442,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_PLL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_PLL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->pll_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->pll_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_PLL_RDY_INT_MASK, 1 << CS43130_PLL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(cs43130->dev, "Timeout waiting for PLL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for PLL_READY interrupt: %d\n", ret); + return ret; } regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, @@ -2015,7 +2040,7 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130, regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk); if (!ret) { dev_err(cs43130->dev, "Timeout waiting for HPLOAD interrupt\n"); - return -1; + return -ETIMEDOUT; } dev_dbg(cs43130->dev, "HP load stat: %x, INT_MASK_4: %x\n", @@ -2510,13 +2535,19 @@ static int cs43130_i2c_probe(struct i2c_client *client) init_completion(&cs43130->pll_rdy); init_completion(&cs43130->hpload_evt); - ret = devm_request_threaded_irq(cs43130->dev, client->irq, - NULL, cs43130_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs43130", cs43130); - if (ret != 0) { - dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret); - goto err; + if (!client->irq) { + dev_dbg(cs43130->dev, "IRQ not found, will poll instead\n"); + cs43130->has_irq_line = 0; + } else { + ret = devm_request_threaded_irq(cs43130->dev, client->irq, + NULL, cs43130_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs43130", cs43130); + if (ret != 0) { + dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret); + goto err; + } + cs43130->has_irq_line = 1; } cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index 2f5ec3888103..694286b78d03 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -507,6 +507,7 @@ struct cs43130_private { struct gpio_desc *reset_gpio; unsigned int dev_id; /* codec device ID */ int xtal_ibias; + bool has_irq_line; /* shared by both DAIs */ struct mutex clk_mutex; From 1aba67132cbc46856dfa8f904cd7021a75b1806d Mon Sep 17 00:00:00 2001 From: Juha-Pekka Heikkila Date: Thu, 16 Nov 2023 17:02:23 +0200 Subject: [PATCH 1300/7721] drm/i915/display: Separate xe and i915 common dpt code into own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here created intel_dpt_common.c to hold intel_dpt_configure which is needed for both xe and i915. Signed-off-by: Juha-Pekka Heikkila Reviewed-by: Jouni Högander Signed-off-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231116150225.204233-1-juhapekka.heikkila@gmail.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_display.c | 1 + drivers/gpu/drm/i915/display/intel_dpt.c | 26 -------------- drivers/gpu/drm/i915/display/intel_dpt.h | 2 -- .../gpu/drm/i915/display/intel_dpt_common.c | 34 +++++++++++++++++++ .../gpu/drm/i915/display/intel_dpt_common.h | 13 +++++++ 6 files changed, 49 insertions(+), 28 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_dpt_common.c create mode 100644 drivers/gpu/drm/i915/display/intel_dpt_common.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7e5d6a39d450..65e984242089 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -275,6 +275,7 @@ i915-y += \ display/intel_dpll.o \ display/intel_dpll_mgr.o \ display/intel_dpt.o \ + display/intel_dpt_common.o \ display/intel_drrs.o \ display/intel_dsb.o \ display/intel_dsb_buffer.o \ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index cf338ac71229..5cf162628b95 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -76,6 +76,7 @@ #include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_dpt.h" +#include "intel_dpt_common.h" #include "intel_drrs.h" #include "intel_dsb.h" #include "intel_dsi.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index 2b067cb952f0..b29bceff73f2 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -9,8 +9,6 @@ #include "gt/gen8_ppgtt.h" #include "i915_drv.h" -#include "i915_reg.h" -#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" @@ -318,27 +316,3 @@ void intel_dpt_destroy(struct i915_address_space *vm) i915_vm_put(&dpt->vm); } -void intel_dpt_configure(struct intel_crtc *crtc) -{ - struct drm_i915_private *i915 = to_i915(crtc->base.dev); - - if (DISPLAY_VER(i915) == 14) { - enum pipe pipe = crtc->pipe; - enum plane_id plane_id; - - for_each_plane_id_on_crtc(crtc, plane_id) { - if (plane_id == PLANE_CURSOR) - continue; - - intel_de_rmw(i915, PLANE_CHICKEN(pipe, plane_id), - PLANE_CHICKEN_DISABLE_DPT, - i915->display.params.enable_dpt ? 0 : - PLANE_CHICKEN_DISABLE_DPT); - } - } else if (DISPLAY_VER(i915) == 13) { - intel_de_rmw(i915, CHICKEN_MISC_2, - CHICKEN_MISC_DISABLE_DPT, - i915->display.params.enable_dpt ? 0 : - CHICKEN_MISC_DISABLE_DPT); - } -} diff --git a/drivers/gpu/drm/i915/display/intel_dpt.h b/drivers/gpu/drm/i915/display/intel_dpt.h index d9a166550185..e18a9f767b11 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.h +++ b/drivers/gpu/drm/i915/display/intel_dpt.h @@ -10,7 +10,6 @@ struct drm_i915_private; struct i915_address_space; struct i915_vma; -struct intel_crtc; struct intel_framebuffer; void intel_dpt_destroy(struct i915_address_space *vm); @@ -20,6 +19,5 @@ void intel_dpt_suspend(struct drm_i915_private *i915); void intel_dpt_resume(struct drm_i915_private *i915); struct i915_address_space * intel_dpt_create(struct intel_framebuffer *fb); -void intel_dpt_configure(struct intel_crtc *crtc); #endif /* __INTEL_DPT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpt_common.c b/drivers/gpu/drm/i915/display/intel_dpt_common.c new file mode 100644 index 000000000000..cdba47165c04 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dpt_common.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_reg.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "intel_dpt_common.h" + +void intel_dpt_configure(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + if (DISPLAY_VER(i915) == 14) { + enum pipe pipe = crtc->pipe; + enum plane_id plane_id; + + for_each_plane_id_on_crtc(crtc, plane_id) { + if (plane_id == PLANE_CURSOR) + continue; + + intel_de_rmw(i915, PLANE_CHICKEN(pipe, plane_id), + PLANE_CHICKEN_DISABLE_DPT, + i915->display.params.enable_dpt ? 0 : + PLANE_CHICKEN_DISABLE_DPT); + } + } else if (DISPLAY_VER(i915) == 13) { + intel_de_rmw(i915, CHICKEN_MISC_2, + CHICKEN_MISC_DISABLE_DPT, + i915->display.params.enable_dpt ? 0 : + CHICKEN_MISC_DISABLE_DPT); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_dpt_common.h b/drivers/gpu/drm/i915/display/intel_dpt_common.h new file mode 100644 index 000000000000..6d7de405126a --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dpt_common.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DPT_COMMON_H__ +#define __INTEL_DPT_COMMON_H__ + +struct intel_crtc; + +void intel_dpt_configure(struct intel_crtc *crtc); + +#endif /* __INTEL_DPT_COMMON_H__ */ From 185b24883e278ba298c073164d1e1abacc986d9f Mon Sep 17 00:00:00 2001 From: Juha-Pekka Heikkila Date: Thu, 16 Nov 2023 17:02:24 +0200 Subject: [PATCH 1301/7721] drm/i915/display: in skl_surf_address check for dpt-vma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit touch dpt_vma->node only if dpt-vma is not NULL Signed-off-by: Juha-Pekka Heikkila Reviewed-by: Jouni Högander Signed-off-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231116150225.204233-2-juhapekka.heikkila@gmail.com --- drivers/gpu/drm/i915/display/skl_universal_plane.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 39499a0ec6c0..f5c77a018e10 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1006,7 +1006,8 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, * The DPT object contains only one vma, so the VMA's offset * within the DPT is always 0. */ - drm_WARN_ON(&i915->drm, plane_state->dpt_vma->node.start); + drm_WARN_ON(&i915->drm, plane_state->dpt_vma && + plane_state->dpt_vma->node.start); drm_WARN_ON(&i915->drm, offset & 0x1fffff); return offset >> 9; } else { From 12b7142e679f8184b42de6750e44a4fc67ebc4e4 Mon Sep 17 00:00:00 2001 From: Juha-Pekka Heikkila Date: Thu, 16 Nov 2023 17:02:25 +0200 Subject: [PATCH 1302/7721] drm/i915/display: In intel_framebuffer_init switch to use intel_bo_to_drm_bo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe driver. I915 and Xe object implementation are differing. Use intel_bo_to_drm_bo instead of &obj->base. Signed-off-by: Juha-Pekka Heikkila Reviewed-by: Jouni Högander Reviewed-by: Uma Shankar Signed-off-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231116150225.204233-3-juhapekka.heikkila@gmail.com --- drivers/gpu/drm/i915/display/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index e1db7a3afd1a..77226ec00cb1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -2093,7 +2093,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, } } - fb->obj[i] = &obj->base; + fb->obj[i] = intel_bo_to_drm_bo(obj); } ret = intel_fill_fb_info(dev_priv, intel_fb); From 3907f6ef8e0d55a88cdb0f7238363d24e26790ca Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 9 Nov 2023 21:16:38 +0100 Subject: [PATCH 1303/7721] media: visl: Hook the (TRY_)DECODER_CMD stateless ioctls The (TRY_)DECODER_CMD ioctls are used to support flushing when holding capture buffers is supported. This is the case of this driver but the ioctls were never hooked to the ioctl ops. Add them to correctly support flushing. Fixes: 0c078e310b6d ("media: visl: add virtual stateless decoder driver") Signed-off-by: Paul Kocialkowski Reviewed-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/visl/visl-video.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index 7cac6a6456eb..9303a3e118d7 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -525,6 +525,9 @@ const struct v4l2_ioctl_ops visl_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; From 6c0d9e12b1d12bbd95484e4b99f63feeb423765f Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 9 Nov 2023 21:16:39 +0100 Subject: [PATCH 1304/7721] media: verisilicon: Hook the (TRY_)DECODER_CMD stateless ioctls The (TRY_)DECODER_CMD ioctls are used to support flushing when holding capture buffers is supported. This is the case of this driver but the ioctls were never hooked to the ioctl ops. Add them to correctly support flushing. Fixes: 340ce50f75a6 ("media: hantro: Enable HOLD_CAPTURE_BUF for H.264") Signed-off-by: Paul Kocialkowski Reviewed-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_drv.c | 2 ++ drivers/media/platform/verisilicon/hantro_v4l2.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 7f5b82eb6649..db3df6cc4513 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -907,6 +907,8 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { vpu->encoder = func; + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); } else { vpu->decoder = func; v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 27a1e77cca38..941fa23c211a 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -767,6 +767,9 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, + .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, .vidioc_encoder_cmd = vidioc_encoder_cmd, }; From 1fb7b5ab62113b29ce331464048d8c39e58fd08a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 9 Nov 2023 21:16:40 +0100 Subject: [PATCH 1305/7721] media: rkvdec: Hook the (TRY_)DECODER_CMD stateless ioctls The (TRY_)DECODER_CMD ioctls are used to support flushing when holding capture buffers is supported. This is the case of this driver but the ioctls were never hooked to the ioctl ops. Add them to correctly support flushing. Fixes: ed7bb87d3d03 ("media: rkvdec: Enable capture buffer holding for H264") Signed-off-by: Paul Kocialkowski Reviewed-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 84a41792cb4b..ac398b5a9736 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -461,6 +461,9 @@ static const struct v4l2_ioctl_ops rkvdec_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, }; static int rkvdec_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, From e3234e547a4db0572e271e490d044bdb4cb7233b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 8 Nov 2023 07:42:37 +0100 Subject: [PATCH 1306/7721] media: exynos4-is: fimc-is-i2c: remove I2C_CLASS_SPD support This I2C bus is used by the firmware only and it seems I2C_CLASS_SPD device auto-detection has never been used. So we can safely remove it. That's one further step towards removing I2C_CLASS_SPD completely. Signed-off-by: Heiner Kallweit Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c index bef6e9b4a25e..44363c4241d5 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c @@ -57,7 +57,6 @@ static int fimc_is_i2c_probe(struct platform_device *pdev) strscpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name)); i2c_adap->owner = THIS_MODULE; i2c_adap->algo = &fimc_is_i2c_algorithm; - i2c_adap->class = I2C_CLASS_SPD; platform_set_drvdata(pdev, isp_i2c); pm_runtime_enable(&pdev->dev); From f033c87fda47e272bb4f75dc7b03677261d91158 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 7 Nov 2023 08:15:21 +0100 Subject: [PATCH 1307/7721] media: amphion: Fix VPU core alias name Starting with commit f6038de293f2 ("arm64: dts: imx8qm: Fix VPU core alias name") the alias for VPU cores uses dashes instead of underscores. Adjust the alias stem accordingly. Fixes the errors: amphion-vpu-core 2d040000.vpu-core: can't get vpu core id amphion-vpu-core 2d050000.vpu-core: can't get vpu core id Fixes: f6038de293f2 ("arm64: dts: imx8qm: Fix VPU core alias name") Signed-off-by: Alexander Stein Reviewed-by: Ming Qian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/vpu_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 1af6fc9460d4..3a2030d02e45 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -642,7 +642,7 @@ static int vpu_core_probe(struct platform_device *pdev) return -ENODEV; core->type = core->res->type; - core->id = of_alias_get_id(dev->of_node, "vpu_core"); + core->id = of_alias_get_id(dev->of_node, "vpu-core"); if (core->id < 0) { dev_err(dev, "can't get vpu core id\n"); return core->id; From c6fbb6bca10838485b820e8a26c23996f77ce580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Oct 2023 16:13:59 +0300 Subject: [PATCH 1308/7721] drm: Fix color LUT rounding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implementation of drm_color_lut_extract() generates weird results. Eg. if we go through all the values for 16->8bpc conversion we see the following pattern: in out (count) 0 - 7f -> 0 (128) 80 - 17f -> 1 (256) 180 - 27f -> 2 (256) 280 - 37f -> 3 (256) ... fb80 - fc7f -> fc (256) fc80 - fd7f -> fd (256) fd80 - fe7f -> fe (256) fe80 - ffff -> ff (384) So less values map to 0 and more values map 0xff, which doesn't seem particularly great. To get just the same number of input values to map to the same output values we'd just need to drop the rounding entrirely. But perhaps a better idea would be to follow the OpenGL int<->float conversion rules, in which case we get the following results: in out (count) 0 - 80 -> 0 (129) 81 - 181 -> 1 (257) 182 - 282 -> 2 (257) 283 - 383 -> 3 (257) ... fc7c - fd7c -> fc (257) fd7d - fe7d -> fd (257) fe7e - ff7e -> fe (257) ff7f - ffff -> ff (129) Note that since the divisor is constant the compiler is able to optimize away the integer division in most cases. The only exception is the _ULL() case on 32bit architectures since that gets emitted as inline asm via do_div() and thus the compiler doesn't get to optimize it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231013131402.24072-2-ville.syrjala@linux.intel.com Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Jani Nikula Acked-by: Maxime Ripard --- include/drm/drm_color_mgmt.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index 81c298488b0c..54b2b2467bfd 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -36,20 +36,17 @@ struct drm_plane; * * Extract a degamma/gamma LUT value provided by user (in the form of * &drm_color_lut entries) and round it to the precision supported by the - * hardware. + * hardware, following OpenGL int<->float conversion rules + * (see eg. OpenGL 4.6 specification - 2.3.5 Fixed-Point Data Conversions). */ static inline u32 drm_color_lut_extract(u32 user_input, int bit_precision) { - u32 val = user_input; - u32 max = 0xffff >> (16 - bit_precision); - - /* Round only if we're not using full precision. */ - if (bit_precision < 16) { - val += 1UL << (16 - bit_precision - 1); - val >>= 16 - bit_precision; - } - - return clamp_val(val, 0, max); + if (bit_precision > 16) + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(user_input, (1 << bit_precision) - 1), + (1 << 16) - 1); + else + return DIV_ROUND_CLOSEST(user_input * ((1 << bit_precision) - 1), + (1 << 16) - 1); } u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n); From edc2b74a535a87110a70757ff535aaa47c34e66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Oct 2023 16:14:00 +0300 Subject: [PATCH 1309/7721] drm/i915: Adjust LUT rounding rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_color_lut_extract() rounding was changed to follow the OpenGL int<->float conversion rules. Adjust intel_color_lut_pack() to match. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231013131402.24072-3-ville.syrjala@linux.intel.com Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 1d26be54ddfc..1e734e932917 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -785,14 +785,12 @@ static void chv_assign_csc(struct intel_crtc_state *crtc_state) /* convert hw value with given bit_precision to lut property val */ static u32 intel_color_lut_pack(u32 val, int bit_precision) { - u32 max = 0xffff >> (16 - bit_precision); - - val = clamp_val(val, 0, max); - - if (bit_precision < 16) - val <<= 16 - bit_precision; - - return val; + if (bit_precision > 16) + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(val, (1 << 16) - 1), + (1 << bit_precision) - 1); + else + return DIV_ROUND_CLOSEST(val * ((1 << 16) - 1), + (1 << bit_precision) - 1); } static u32 i9xx_lut_8(const struct drm_color_lut *color) From 5d76c8163f09cfee7dbc1870a1154c2ca443528b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Oct 2023 16:14:01 +0300 Subject: [PATCH 1310/7721] drm/i915: s/clamp()/min()/ in i965_lut_11p6_max_pack() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use min() instead of clamp() since the color values involved are unsigned. No functional changes. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231013131402.24072-4-ville.syrjala@linux.intel.com Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 1e734e932917..91f92844e213 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -909,7 +909,7 @@ static void i965_lut_10p6_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) static u16 i965_lut_11p6_max_pack(u32 val) { /* PIPEGCMAX is 11.6, clamp to 10.6 */ - return clamp_val(val, 0, 0xffff); + return min(val, 0xffffu); } static u32 ilk_lut_10(const struct drm_color_lut *color) From deac453244d309ad7a94d0501eb5e0f9d8d1f1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Oct 2023 16:14:02 +0300 Subject: [PATCH 1311/7721] drm/i915: Fix glk+ degamma LUT conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implementation of change_lut_val_precision() is just a convoluted way of shifting by 8. Implement the proper rounding by just using drm_color_lut_extract() and intel_color_lut_pack() like everyone else does. And as the uapi can't handle >=1.0 values but the hardware can we need to clamp the results appropriately in the readout path. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231013131402.24072-5-ville.syrjala@linux.intel.com Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 54 +++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 91f92844e213..c5092b7e87d5 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1526,14 +1526,27 @@ static int glk_degamma_lut_size(struct drm_i915_private *i915) return 35; } -/* - * change_lut_val_precision: helper function to upscale or downscale lut values. - * Parameters 'to' and 'from' needs to be less than 32. This should be sufficient - * as currently there are no lut values exceeding 32 bit. - */ -static u32 change_lut_val_precision(u32 lut_val, int to, int from) +static u32 glk_degamma_lut(const struct drm_color_lut *color) { - return mul_u32_u32(lut_val, (1 << to)) / (1 << from); + return color->green; +} + +static void glk_degamma_lut_pack(struct drm_color_lut *entry, u32 val) +{ + /* PRE_CSC_GAMC_DATA is 3.16, clamp to 0.16 */ + entry->red = entry->green = entry->blue = min(val, 0xffffu); +} + +static u32 mtl_degamma_lut(const struct drm_color_lut *color) +{ + return drm_color_lut_extract(color->green, 24); +} + +static void mtl_degamma_lut_pack(struct drm_color_lut *entry, u32 val) +{ + /* PRE_CSC_GAMC_DATA is 3.24, clamp to 0.16 */ + entry->red = entry->green = entry->blue = + intel_color_lut_pack(min(val, 0xffffffu), 24); } static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, @@ -1570,20 +1583,16 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, * ToDo: Extend to max 7.0. Enable 32 bit input value * as compared to just 16 to achieve this. */ - u32 lut_val; - - if (DISPLAY_VER(i915) >= 14) - lut_val = change_lut_val_precision(lut[i].green, 24, 16); - else - lut_val = lut[i].green; - ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), - lut_val); + DISPLAY_VER(i915) >= 14 ? + mtl_degamma_lut(&lut[i]) : glk_degamma_lut(&lut[i])); } /* Clamp values > 1.0. */ while (i++ < glk_degamma_lut_size(i915)) - ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), 1 << 16); + ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), + DISPLAY_VER(i915) >= 14 ? + 1 << 24 : 1 << 16); ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe), 0); } @@ -3570,17 +3579,10 @@ static struct drm_property_blob *glk_read_degamma_lut(struct intel_crtc *crtc) for (i = 0; i < lut_size; i++) { u32 val = intel_de_read_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe)); - /* - * For MTL and beyond, convert back the 24 bit lut values - * read from HW to 16 bit values to maintain parity with - * userspace values - */ if (DISPLAY_VER(dev_priv) >= 14) - val = change_lut_val_precision(val, 16, 24); - - lut[i].red = val; - lut[i].green = val; - lut[i].blue = val; + mtl_degamma_lut_pack(&lut[i], val); + else + glk_degamma_lut_pack(&lut[i], val); } intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), From 0e26cc72c71cb98e951716a6596060cd04b0ba6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Wed, 22 Nov 2023 13:19:38 -0300 Subject: [PATCH 1312/7721] drm: Refuse to async flip with atomic prop changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given that prop changes may lead to modesetting, which would defeat the fast path of the async flip, refuse any atomic prop change for async flips in atomic API. The only exception is the framebuffer ID to flip to. Currently the only plane type supported is the primary one. Signed-off-by: André Almeida Reviewed-by: Simon Ser Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231122161941.320564-2-andrealmeid@igalia.com --- drivers/gpu/drm/drm_atomic_uapi.c | 52 +++++++++++++++++++++++++++-- drivers/gpu/drm/drm_crtc_internal.h | 2 +- drivers/gpu/drm/drm_mode_object.c | 2 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 98d3b10c08ae..52494642b095 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1006,13 +1006,28 @@ int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, return ret; } +static int drm_atomic_check_prop_changes(int ret, uint64_t old_val, uint64_t prop_value, + struct drm_property *prop) +{ + if (ret != 0 || old_val != prop_value) { + drm_dbg_atomic(prop->dev, + "[PROP:%d:%s] No prop can be changed during async flip\n", + prop->base.id, prop->name); + return -EINVAL; + } + + return 0; +} + int drm_atomic_set_property(struct drm_atomic_state *state, struct drm_file *file_priv, struct drm_mode_object *obj, struct drm_property *prop, - uint64_t prop_value) + u64 prop_value, + bool async_flip) { struct drm_mode_object *ref; + u64 old_val; int ret; if (!drm_property_change_valid_get(prop, prop_value, &ref)) @@ -1029,6 +1044,13 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip) { + ret = drm_atomic_connector_get_property(connector, connector_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + ret = drm_atomic_connector_set_property(connector, connector_state, file_priv, prop, prop_value); @@ -1044,6 +1066,13 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip) { + ret = drm_atomic_crtc_get_property(crtc, crtc_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + ret = drm_atomic_crtc_set_property(crtc, crtc_state, prop, prop_value); break; @@ -1051,6 +1080,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state, case DRM_MODE_OBJECT_PLANE: { struct drm_plane *plane = obj_to_plane(obj); struct drm_plane_state *plane_state; + struct drm_mode_config *config = &plane->dev->mode_config; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { @@ -1058,6 +1088,21 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip && prop != config->prop_fb_id) { + ret = drm_atomic_plane_get_property(plane, plane_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + + if (async_flip && plane_state->plane->type != DRM_PLANE_TYPE_PRIMARY) { + drm_dbg_atomic(prop->dev, + "[OBJECT:%d] Only primary planes can be changed during async flip\n", + obj->id); + ret = -EINVAL; + break; + } + ret = drm_atomic_plane_set_property(plane, plane_state, file_priv, prop, prop_value); @@ -1337,6 +1382,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_out_fence_state *fence_state; int ret = 0; unsigned int i, j, num_fences; + bool async_flip = false; /* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -1450,8 +1496,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, goto out; } - ret = drm_atomic_set_property(state, file_priv, - obj, prop, prop_value); + ret = drm_atomic_set_property(state, file_priv, obj, + prop, prop_value, async_flip); if (ret) { drm_mode_object_put(obj); goto out; diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 6b646e0783be..a514d5207e41 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -253,7 +253,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state, struct drm_file *file_priv, struct drm_mode_object *obj, struct drm_property *prop, - uint64_t prop_value); + u64 prop_value, bool async_flip); int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index ac0d2ce3f870..0e8355063eee 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -538,7 +538,7 @@ static int set_property_atomic(struct drm_mode_object *obj, obj_to_connector(obj), prop_value); } else { - ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value); + ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value, false); if (ret) goto out; ret = drm_atomic_commit(state); From 4b4af74ab9719d17538a97f43137e93296ec7437 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Nov 2023 13:19:39 -0300 Subject: [PATCH 1313/7721] drm: allow DRM_MODE_PAGE_FLIP_ASYNC for atomic commits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the driver supports it, allow user-space to supply the DRM_MODE_PAGE_FLIP_ASYNC flag to request an async page-flip. Set drm_crtc_state.async_flip accordingly. Document that drivers will reject atomic commits if an async flip isn't possible. This allows user-space to fall back to something else. For instance, Xorg falls back to a blit. Another option is to wait as close to the next vblank as possible before performing the page-flip to reduce latency. Signed-off-by: Simon Ser Reviewed-by: Alex Deucher Co-developed-by: André Almeida Signed-off-by: André Almeida Link: https://patchwork.freedesktop.org/patch/msgid/20231122161941.320564-3-andrealmeid@igalia.com --- drivers/gpu/drm/drm_atomic_uapi.c | 25 ++++++++++++++++++++++--- include/uapi/drm/drm_mode.h | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 52494642b095..116407002269 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1368,6 +1368,18 @@ static void complete_signaling(struct drm_device *dev, kfree(fence_state); } +static void +set_async_flip(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + crtc_state->async_flip = true; + } +} + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1409,9 +1421,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, } if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) { - drm_dbg_atomic(dev, - "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n"); - return -EINVAL; + if (!dev->mode_config.async_page_flip) { + drm_dbg_atomic(dev, + "commit failed: DRM_MODE_PAGE_FLIP_ASYNC not supported\n"); + return -EINVAL; + } + + async_flip = true; } /* can't test and expect an event at the same time. */ @@ -1514,6 +1530,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, if (ret) goto out; + if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) + set_async_flip(state); + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { ret = drm_atomic_check_only(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 09e7a471ee30..95630f170110 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -957,6 +957,15 @@ struct hdr_output_metadata { * Request that the page-flip is performed as soon as possible, ie. with no * delay due to waiting for vblank. This may cause tearing to be visible on * the screen. + * + * When used with atomic uAPI, the driver will return an error if the hardware + * doesn't support performing an asynchronous page-flip for this update. + * User-space should handle this, e.g. by falling back to a regular page-flip. + * + * Note, some hardware might need to perform one last synchronous page-flip + * before being able to switch to asynchronous page-flips. As an exception, + * the driver will return success even though that first page-flip is not + * asynchronous. */ #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 From e4d983acffff270ccee417445a69b9ed198658b1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Nov 2023 13:19:40 -0300 Subject: [PATCH 1314/7721] drm: introduce DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This new kernel capability indicates whether async page-flips are supported via the atomic uAPI. DRM clients can use it to check for support before feeding DRM_MODE_PAGE_FLIP_ASYNC to the kernel. Make it clear that DRM_CAP_ASYNC_PAGE_FLIP is for legacy uAPI only. Signed-off-by: Simon Ser Reviewed-by: André Almeida Reviewed-by: Alex Deucher Signed-off-by: André Almeida Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231122161941.320564-4-andrealmeid@igalia.com --- drivers/gpu/drm/drm_ioctl.c | 4 ++++ include/uapi/drm/drm.h | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 44fda68c28ae..f461ed862480 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -301,6 +301,10 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ case DRM_CAP_CRTC_IN_VBLANK_EVENT: req->value = 1; break; + case DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP: + req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) && + dev->mode_config.async_page_flip; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 8662b5aeea0c..796de831f4a0 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -713,7 +713,8 @@ struct drm_gem_open { /** * DRM_CAP_ASYNC_PAGE_FLIP * - * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC. + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for legacy + * page-flips. */ #define DRM_CAP_ASYNC_PAGE_FLIP 0x7 /** @@ -773,6 +774,13 @@ struct drm_gem_open { * :ref:`drm_sync_objects`. */ #define DRM_CAP_SYNCOBJ_TIMELINE 0x14 +/** + * DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP + * + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for atomic + * commits. + */ +#define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 /* DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { From 3d123f513af055b4c085b555f9c856bbd7390536 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 23 Nov 2023 15:30:20 +0530 Subject: [PATCH 1315/7721] dt-bindings: power: rpmpd: Update part number to X1E80100 There was a recent part number update from SC8380XP to X1E80100 and as a result of which the SC8380xp rpmpd bindings introduced is no longer correct. Given that it currently has no users, it was agreed that it can be updated to the correct part number (X1E80100) without causing any binding breakage. Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231123100021.10918-2-quic_sibis@quicinc.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index da9c5846f4e1..2ff246cf8b81 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -39,7 +39,6 @@ properties: - qcom,sc7280-rpmhpd - qcom,sc8180x-rpmhpd - qcom,sc8280xp-rpmhpd - - qcom,sc8380xp-rpmhpd - qcom,sdm660-rpmpd - qcom,sdm670-rpmhpd - qcom,sdm845-rpmhpd @@ -57,6 +56,7 @@ properties: - qcom,sm8450-rpmhpd - qcom,sm8550-rpmhpd - qcom,sm8650-rpmhpd + - qcom,x1e80100-rpmhpd - items: - enum: - qcom,msm8937-rpmpd From e60b6c183e1d2925c94987d2754ae1378c0181b7 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 23 Nov 2023 15:30:21 +0530 Subject: [PATCH 1316/7721] pmdomain: qcom: rpmhpd: Update part number to X1E80100 There was a recent part number update from SC8380XP to X1E80100 and as a result of which SC8380xp prefix introduced in the rpmhpd driver is no longer correct. Update it to X1E80100, to reflect the bindings change. Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231123100021.10918-3-quic_sibis@quicinc.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/rpmhpd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index f2e64324deb8..3078896b1300 100644 --- a/drivers/pmdomain/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c @@ -598,8 +598,8 @@ static const struct rpmhpd_desc sc8280xp_desc = { .num_pds = ARRAY_SIZE(sc8280xp_rpmhpds), }; -/* SC8380xp RPMH powerdomains */ -static struct rpmhpd *sc8380xp_rpmhpds[] = { +/* X1E80100 RPMH powerdomains */ +static struct rpmhpd *x1e80100_rpmhpds[] = { [RPMHPD_CX] = &cx, [RPMHPD_CX_AO] = &cx_ao, [RPMHPD_EBI] = &ebi, @@ -615,9 +615,9 @@ static struct rpmhpd *sc8380xp_rpmhpds[] = { [RPMHPD_GMXC] = &gmxc, }; -static const struct rpmhpd_desc sc8380xp_desc = { - .rpmhpds = sc8380xp_rpmhpds, - .num_pds = ARRAY_SIZE(sc8380xp_rpmhpds), +static const struct rpmhpd_desc x1e80100_desc = { + .rpmhpds = x1e80100_rpmhpds, + .num_pds = ARRAY_SIZE(x1e80100_rpmhpds), }; static const struct of_device_id rpmhpd_match_table[] = { @@ -629,7 +629,6 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc }, - { .compatible = "qcom,sc8380xp-rpmhpd", .data = &sc8380xp_desc }, { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc }, { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, @@ -643,6 +642,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc }, { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc }, { .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc }, + { .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc }, { } }; MODULE_DEVICE_TABLE(of, rpmhpd_match_table); From 820cec125970b37cbbd0fa026b314c5e6094fcbf Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 23 Nov 2023 12:08:46 +0000 Subject: [PATCH 1317/7721] pmdomain: arm_scmi: Move Kconfig options to the pmdomain subsystem The Kconfig options belongs closer to the corresponding implementations, hence let's move them from the firmware to the pmdomain subsystem. Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20231123120847.2825444-1-sudeep.holla@arm.com Signed-off-by: Ulf Hansson --- drivers/firmware/arm_scmi/Kconfig | 25 ------------------------- drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/arm/Kconfig | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 drivers/pmdomain/arm/Kconfig diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 706d1264d038..aa5842be19b2 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -168,31 +168,6 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE endif #ARM_SCMI_PROTOCOL -config ARM_SCMI_POWER_DOMAIN - tristate "SCMI power domain driver" - depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCMI power domains which can be - enabled or disabled via the SCP firmware - - This driver can also be built as a module. If so, the module - will be called scmi_pm_domain. Note this may needed early in boot - before rootfs may be available. - -config ARM_SCMI_PERF_DOMAIN - tristate "SCMI performance domain driver" - depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCMI performance domains which can be - enabled or disabled via the SCP firmware. - - This driver can also be built as a module. If so, the module will be - called scmi_perf_domain. - config ARM_SCMI_POWER_CONTROL tristate "SCMI system power control driver" depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig index c98c5bf75a14..23c64851a5b0 100644 --- a/drivers/pmdomain/Kconfig +++ b/drivers/pmdomain/Kconfig @@ -4,6 +4,7 @@ menu "PM Domains" source "drivers/pmdomain/actions/Kconfig" source "drivers/pmdomain/amlogic/Kconfig" source "drivers/pmdomain/apple/Kconfig" +source "drivers/pmdomain/arm/Kconfig" source "drivers/pmdomain/bcm/Kconfig" source "drivers/pmdomain/imx/Kconfig" source "drivers/pmdomain/mediatek/Kconfig" diff --git a/drivers/pmdomain/arm/Kconfig b/drivers/pmdomain/arm/Kconfig new file mode 100644 index 000000000000..acbe4331aaf7 --- /dev/null +++ b/drivers/pmdomain/arm/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-only +config ARM_SCMI_PERF_DOMAIN + tristate "SCMI performance domain driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCMI performance domains which can be + enabled or disabled via the SCP firmware. + + This driver can also be built as a module. If so, the module will be + called scmi_perf_domain. + +config ARM_SCMI_POWER_DOMAIN + tristate "SCMI power domain driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCMI power domains which can be + enabled or disabled via the SCP firmware + + This driver can also be built as a module. If so, the module + will be called scmi_pm_domain. Note this may needed early in boot + before rootfs may be available. From 62b14b9e86a1c94b1a2f41a52adcfda822a9863e Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 23 Nov 2023 12:08:47 +0000 Subject: [PATCH 1318/7721] firmware: arm_scpi: Move power-domain driver to the pmdomain dir To simplify with maintenance let's move the Arm SCPI power-domain driver to the new pmdomain directory. Note this is different from and precedes the new Arm SCMI protocol. Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20231123120847.2825444-2-sudeep.holla@arm.com Signed-off-by: Ulf Hansson --- drivers/firmware/Kconfig | 9 --------- drivers/firmware/Makefile | 1 - drivers/pmdomain/arm/Kconfig | 12 ++++++++++++ drivers/pmdomain/arm/Makefile | 1 + drivers/{firmware => pmdomain/arm}/scpi_pm_domain.c | 0 5 files changed, 13 insertions(+), 10 deletions(-) rename drivers/{firmware => pmdomain/arm}/scpi_pm_domain.c (100%) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 4a98a859d44d..afeb050ae1b4 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -28,15 +28,6 @@ config ARM_SCPI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCP. -config ARM_SCPI_POWER_DOMAIN - tristate "SCPI power domain driver" - depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCPI power domains which can be - enabled or disabled via the SCP firmware - config ARM_SDE_INTERFACE bool "ARM Software Delegated Exception Interface (SDEI)" depends on ARM64 diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5f9dab82e1a0..944833702ebd 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -3,7 +3,6 @@ # Makefile for the linux kernel. # obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o -obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o diff --git a/drivers/pmdomain/arm/Kconfig b/drivers/pmdomain/arm/Kconfig index acbe4331aaf7..efa139c34e08 100644 --- a/drivers/pmdomain/arm/Kconfig +++ b/drivers/pmdomain/arm/Kconfig @@ -23,3 +23,15 @@ config ARM_SCMI_POWER_DOMAIN This driver can also be built as a module. If so, the module will be called scmi_pm_domain. Note this may needed early in boot before rootfs may be available. + +config ARM_SCPI_POWER_DOMAIN + tristate "SCPI power domain driver" + depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCPI power domains which can be + enabled or disabled via the SCP firmware + + This driver can also be built as a module. If so, the module will be + called scpi_pm_domain. diff --git a/drivers/pmdomain/arm/Makefile b/drivers/pmdomain/arm/Makefile index cfcb1f6cdd90..502fe4d0a83e 100644 --- a/drivers/pmdomain/arm/Makefile +++ b/drivers/pmdomain/arm/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o +obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/pmdomain/arm/scpi_pm_domain.c similarity index 100% rename from drivers/firmware/scpi_pm_domain.c rename to drivers/pmdomain/arm/scpi_pm_domain.c From f9c12d6783580f22f283bfc733fdd6c41a0c690d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:05 +0200 Subject: [PATCH 1319/7721] media: atmel-isi: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 4046212d48b4..bb83117bab2e 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -559,11 +559,13 @@ static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi, static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt, struct v4l2_subdev_state *sd_state) { - int ret; + struct v4l2_rect *try_crop = + v4l2_subdev_get_pad_crop(isi->entity.subdev, sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .code = isi_fmt->mbus_code, .which = V4L2_SUBDEV_FORMAT_TRY, }; + int ret; ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size, sd_state, &fse); @@ -572,11 +574,11 @@ static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt, * just use the maximum ISI can receive. */ if (ret) { - sd_state->pads->try_crop.width = MAX_SUPPORT_WIDTH; - sd_state->pads->try_crop.height = MAX_SUPPORT_HEIGHT; + try_crop->width = MAX_SUPPORT_WIDTH; + try_crop->height = MAX_SUPPORT_HEIGHT; } else { - sd_state->pads->try_crop.width = fse.max_width; - sd_state->pads->try_crop.height = fse.max_height; + try_crop->width = fse.max_width; + try_crop->height = fse.max_height; } } From 098a1eed5daeb62e2c974f6c37d3b0d582c5586e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:06 +0200 Subject: [PATCH 1320/7721] media: microchip-isc: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/microchip/microchip-isc-base.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 1f8528844497..a901be02e2f6 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -854,6 +854,8 @@ static int isc_try_configure_pipeline(struct isc_device *isc) static void isc_try_fse(struct isc_device *isc, struct v4l2_subdev_state *sd_state) { + struct v4l2_rect *try_crop = + v4l2_subdev_get_pad_crop(isc->current_subdev->sd, sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -875,11 +877,11 @@ static void isc_try_fse(struct isc_device *isc, * just use the maximum ISC can receive. */ if (ret) { - sd_state->pads->try_crop.width = isc->max_width; - sd_state->pads->try_crop.height = isc->max_height; + try_crop->width = isc->max_width; + try_crop->height = isc->max_height; } else { - sd_state->pads->try_crop.width = fse.max_width; - sd_state->pads->try_crop.height = fse.max_height; + try_crop->width = fse.max_width; + try_crop->height = fse.max_height; } } From f4b7c07dc19f70ba8fb3f290f76f6199e8090795 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:07 +0200 Subject: [PATCH 1321/7721] media: atmel-isc: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/deprecated/atmel/atmel-isc-base.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c index 8e26663cecb6..b63eea8f4fc0 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c +++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c @@ -820,6 +820,8 @@ static int isc_try_configure_pipeline(struct isc_device *isc) static void isc_try_fse(struct isc_device *isc, struct v4l2_subdev_state *sd_state) { + struct v4l2_rect *try_crop = + v4l2_subdev_get_pad_crop(isc->current_subdev->sd, sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -841,11 +843,11 @@ static void isc_try_fse(struct isc_device *isc, * just use the maximum ISC can receive. */ if (ret) { - sd_state->pads->try_crop.width = isc->max_width; - sd_state->pads->try_crop.height = isc->max_height; + try_crop->width = isc->max_width; + try_crop->height = isc->max_height; } else { - sd_state->pads->try_crop.width = fse.max_width; - sd_state->pads->try_crop.height = fse.max_height; + try_crop->width = fse.max_width; + try_crop->height = fse.max_height; } } From 9295e7e0cc38be1e99e330a0ccefa90569ffc91d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:08 +0200 Subject: [PATCH 1322/7721] media: atomisp: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 2 +- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 2 +- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 2 +- drivers/staging/media/atomisp/pci/atomisp_tpg.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 9fa390fbc5f3..5e438c5fd4a9 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -561,7 +561,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; mutex_unlock(&dev->input_lock); return 0; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 1c6643c442ef..db76f52e1dc8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -666,7 +666,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, fmt->height = res->height; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; return 0; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 6a72691ed5b7..ae70e04040dd 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -671,7 +671,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; return 0; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index 074826a5b706..b2376ebf45a1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd, /* only raw8 grbg is supported by TPG */ fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; return 0; } return 0; From 0623979d8352efe18f83c4fad95a2e61df17b3e7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:09 +0200 Subject: [PATCH 1323/7721] media: tegra-video: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Reviewed-by: Luca Ceresoli Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-video/vi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 61169ff13ec5..87e5365defae 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -439,6 +439,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, .which = V4L2_SUBDEV_FORMAT_ACTIVE, .target = V4L2_SEL_TGT_CROP_BOUNDS, }; + struct v4l2_rect *try_crop; int ret; subdev = tegra_channel_get_remote_source_subdev(chan); @@ -473,24 +474,25 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, * Attempt to obtain the format size from subdev. * If not available, try to get crop boundary from subdev. */ + try_crop = v4l2_subdev_get_pad_crop(subdev, sd_state, 0); fse.code = fmtinfo->code; ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse); if (ret) { if (!v4l2_subdev_has_op(subdev, pad, get_selection)) { - sd_state->pads->try_crop.width = 0; - sd_state->pads->try_crop.height = 0; + try_crop->width = 0; + try_crop->height = 0; } else { ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel); if (ret) return -EINVAL; - sd_state->pads->try_crop.width = sdsel.r.width; - sd_state->pads->try_crop.height = sdsel.r.height; + try_crop->width = sdsel.r.width; + try_crop->height = sdsel.r.height; } } else { - sd_state->pads->try_crop.width = fse.max_width; - sd_state->pads->try_crop.height = fse.max_height; + try_crop->width = fse.max_width; + try_crop->height = fse.max_height; } ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt); From fd17e3a9a7886ec949ce269a396b67875b51ff45 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:10 +0200 Subject: [PATCH 1324/7721] media: i2c: Use accessors for pad config 'try_*' fields The 'try_*' fields of the v4l2_subdev_pad_config structure are meant to be accessed through helper functions. Replace direct access with usage of the v4l2_subdev_get_pad_format(), v4l2_subdev_get_pad_crop() and v4l2_subdev_get_pad_compose() helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7183.c | 2 +- drivers/media/i2c/imx274.c | 12 ++++++------ drivers/media/i2c/mt9m001.c | 2 +- drivers/media/i2c/mt9m111.c | 2 +- drivers/media/i2c/mt9t112.c | 2 +- drivers/media/i2c/mt9v011.c | 2 +- drivers/media/i2c/mt9v111.c | 2 +- drivers/media/i2c/ov2640.c | 2 +- drivers/media/i2c/ov2680.c | 4 ++-- drivers/media/i2c/ov6650.c | 34 +++++++++++++++++++++------------- drivers/media/i2c/ov772x.c | 2 +- drivers/media/i2c/ov9640.c | 2 +- drivers/media/i2c/rj54n1cb0c.c | 2 +- drivers/media/i2c/saa6752hs.c | 2 +- drivers/media/i2c/tw9910.c | 2 +- 15 files changed, 41 insertions(+), 33 deletions(-) diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 3659feafac69..0754bfefa073 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -443,7 +443,7 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) decoder->fmt = *fmt; else - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; return 0; } diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index f33b692e6951..1886eaab1c24 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1018,8 +1018,8 @@ static int __imx274_change_compose(struct stimx274 *imx274, int best_goodness = INT_MIN; if (which == V4L2_SUBDEV_FORMAT_TRY) { - cur_crop = &sd_state->pads->try_crop; - tgt_fmt = &sd_state->pads->try_fmt; + cur_crop = v4l2_subdev_get_pad_crop(&imx274->sd, sd_state, 0); + tgt_fmt = v4l2_subdev_get_pad_format(&imx274->sd, sd_state, 0); } else { cur_crop = &imx274->crop; tgt_fmt = &imx274->format; @@ -1112,7 +1112,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd, */ fmt->field = V4L2_FIELD_NONE; if (format->which == V4L2_SUBDEV_FORMAT_TRY) - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; else imx274->format = *fmt; @@ -1143,8 +1143,8 @@ static int imx274_get_selection(struct v4l2_subdev *sd, } if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - src_crop = &sd_state->pads->try_crop; - src_fmt = &sd_state->pads->try_fmt; + src_crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, 0); } else { src_crop = &imx274->crop; src_fmt = &imx274->format; @@ -1215,7 +1215,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274, sel->r = new_crop; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) - tgt_crop = &sd_state->pads->try_crop; + tgt_crop = v4l2_subdev_get_pad_crop(&imx274->sd, sd_state, 0); else tgt_crop = &imx274->crop; diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 79192cf79d28..5c137fc2034e 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -405,7 +405,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9m001_s_fmt(sd, fmt, mf); - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 1f44b72e8a70..e17ff41ebba0 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -671,7 +671,7 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd, mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 93f34b767027..e3b9ff374500 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -982,7 +982,7 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9t112_s_fmt(sd, mf); - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 37a634b92cd5..7f313d731839 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -356,7 +356,7 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd, set_res(sd); } else { - sd_state->pads->try_fmt = *fmt; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; } return 0; diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index f859b49e13bf..2c321e4884be 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -951,7 +951,7 @@ static int mt9v111_set_format(struct v4l2_subdev *subdev, static int mt9v111_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - sd_state->pads->try_fmt = mt9v111_def_fmt; + *v4l2_subdev_get_pad_format(subdev, sd_state, 0) = mt9v111_def_fmt; return 0; } diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 28a01c6eff64..389b6119ddec 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -988,7 +988,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, /* select format */ priv->cfmt_code = mf->code; } else { - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; } out: mutex_unlock(&priv->lock); diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 72bab0ff8a36..f58fa2eb86ee 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -760,9 +760,9 @@ static int ov2680_init_cfg(struct v4l2_subdev *sd, { struct ov2680_dev *sensor = to_ov2680_dev(sd); - sd_state->pads[0].try_crop = ov2680_default_crop; + *v4l2_subdev_get_pad_crop(sd, sd_state, 0) = ov2680_default_crop; - ov2680_fill_format(sensor, &sd_state->pads[0].try_fmt, + ov2680_fill_format(sensor, v4l2_subdev_get_pad_format(sd, sd_state, 0), OV2680_DEFAULT_WIDTH, OV2680_DEFAULT_HEIGHT); return 0; } diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 1ad07935f046..38d21b40f5d8 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -476,7 +476,7 @@ static int ov6650_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { /* pre-select try crop rectangle */ - rect = &sd_state->pads->try_crop; + rect = v4l2_subdev_get_pad_crop(sd, sd_state, 0); } else { /* pre-select active crop rectangle */ @@ -531,8 +531,10 @@ static int ov6650_set_selection(struct v4l2_subdev *sd, ov6650_bind_align_crop_rectangle(&sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_rect *crop = &sd_state->pads->try_crop; - struct v4l2_mbus_framefmt *mf = &sd_state->pads->try_fmt; + struct v4l2_rect *crop = + v4l2_subdev_get_pad_crop(sd, sd_state, 0); + struct v4l2_mbus_framefmt *mf = + v4l2_subdev_get_pad_format(sd, sd_state, 0); /* detect current pad config scaling factor */ bool half_scale = !is_unscaled_ok(mf->width, mf->height, crop); @@ -588,9 +590,12 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, /* update media bus format code and frame size */ if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mf->width = sd_state->pads->try_fmt.width; - mf->height = sd_state->pads->try_fmt.height; - mf->code = sd_state->pads->try_fmt.code; + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_pad_format(sd, sd_state, 0); + + mf->width = try_fmt->width; + mf->height = try_fmt->height; + mf->code = try_fmt->code; } else { mf->width = priv->rect.width >> priv->half_scale; @@ -717,23 +722,26 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, } if (format->which == V4L2_SUBDEV_FORMAT_TRY) - crop = &sd_state->pads->try_crop; + crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); else crop = &priv->rect; half_scale = !is_unscaled_ok(mf->width, mf->height, crop); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_pad_format(sd, sd_state, 0); + /* store new mbus frame format code and size in pad config */ - sd_state->pads->try_fmt.width = crop->width >> half_scale; - sd_state->pads->try_fmt.height = crop->height >> half_scale; - sd_state->pads->try_fmt.code = mf->code; + try_fmt->width = crop->width >> half_scale; + try_fmt->height = crop->height >> half_scale; + try_fmt->code = mf->code; /* return default mbus frame format updated with pad config */ *mf = ov6650_def_fmt; - mf->width = sd_state->pads->try_fmt.width; - mf->height = sd_state->pads->try_fmt.height; - mf->code = sd_state->pads->try_fmt.code; + mf->width = try_fmt->width; + mf->height = try_fmt->height; + mf->code = try_fmt->code; } else { int ret = 0; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 7618b58a7ad0..1fbf72152956 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1220,7 +1220,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd, mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index cbaea049531d..a9adddde1006 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -547,7 +547,7 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return ov9640_s_fmt(sd, mf); - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c index b430046f9e2a..dbddb7a9f211 100644 --- a/drivers/media/i2c/rj54n1cb0c.c +++ b/drivers/media/i2c/rj54n1cb0c.c @@ -1009,7 +1009,7 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd, &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index c106e7a7d1f4..82976aee5e86 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -595,7 +595,7 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd, f->colorspace = V4L2_COLORSPACE_SMPTE170M; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *f; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *f; return 0; } diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 477a64d8f8ab..5233c33b93df 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -829,7 +829,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return tw9910_s_fmt(sd, mf); - sd_state->pads->try_fmt = *mf; + *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; return 0; } From 36f2cd3bd496348a4ff8e1de9b23955bd641ce42 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 23:40:11 +0200 Subject: [PATCH 1325/7721] media: v4l2-subdev: Rename pad config 'try_*' fields The try_fmt, try_crop and try_compose fields of the v4l2_subdev_pad_config structure are misnamed (for historical reason) as they also store data for the subdev active configuration. Rename them to format, crop and compose respectively and update the accessor helpers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index c1f90c1223a7..bb1aad264756 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -688,21 +688,18 @@ struct v4l2_subdev_ir_ops { /** * struct v4l2_subdev_pad_config - Used for storing subdev pad information. * - * @try_fmt: &struct v4l2_mbus_framefmt - * @try_crop: &struct v4l2_rect to be used for crop - * @try_compose: &struct v4l2_rect to be used for compose + * @format: &struct v4l2_mbus_framefmt + * @crop: &struct v4l2_rect to be used for crop + * @compose: &struct v4l2_rect to be used for compose * * This structure only needs to be passed to the pad op if the 'which' field * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL. - * - * Note: This struct is also used in active state, and the 'try' prefix is - * historical and to be removed. */ struct v4l2_subdev_pad_config { - struct v4l2_mbus_framefmt try_fmt; - struct v4l2_rect try_crop; - struct v4l2_rect try_compose; + struct v4l2_mbus_framefmt format; + struct v4l2_rect crop; + struct v4l2_rect compose; }; /** @@ -1145,8 +1142,8 @@ struct v4l2_subdev_fh { #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) /** - * v4l2_subdev_get_pad_format - ancillary routine to call - * &struct v4l2_subdev_pad_config->try_fmt + * v4l2_subdev_get_pad_format - ancillary routine to get + * &struct v4l2_subdev_pad_config->format * * @sd: pointer to &struct v4l2_subdev * @state: pointer to &struct v4l2_subdev_state @@ -1161,12 +1158,12 @@ v4l2_subdev_get_pad_format(struct v4l2_subdev *sd, return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; - return &state->pads[pad].try_fmt; + return &state->pads[pad].format; } /** - * v4l2_subdev_get_pad_crop - ancillary routine to call - * &struct v4l2_subdev_pad_config->try_crop + * v4l2_subdev_get_pad_crop - ancillary routine to get + * &struct v4l2_subdev_pad_config->crop * * @sd: pointer to &struct v4l2_subdev * @state: pointer to &struct v4l2_subdev_state. @@ -1181,12 +1178,12 @@ v4l2_subdev_get_pad_crop(struct v4l2_subdev *sd, return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; - return &state->pads[pad].try_crop; + return &state->pads[pad].crop; } /** - * v4l2_subdev_get_pad_compose - ancillary routine to call - * &struct v4l2_subdev_pad_config->try_compose + * v4l2_subdev_get_pad_compose - ancillary routine to get + * &struct v4l2_subdev_pad_config->compose * * @sd: pointer to &struct v4l2_subdev * @state: pointer to &struct v4l2_subdev_state. @@ -1201,7 +1198,7 @@ v4l2_subdev_get_pad_compose(struct v4l2_subdev *sd, return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; - return &state->pads[pad].try_compose; + return &state->pads[pad].compose; } /* From 6078b2b803dba5f3fa62f652d931120fc1f0137d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Oct 2023 00:17:12 +0200 Subject: [PATCH 1326/7721] media: v4l2-subdev: Drop outdated comment for v4l2_subdev_pad_config The v4l2_subdev_pad_config structure is not passed to subdev operations anymore. Drop an outdated comment to refers to that old mechanism. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index bb1aad264756..bbcee4f3da1e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -691,10 +691,6 @@ struct v4l2_subdev_ir_ops { * @format: &struct v4l2_mbus_framefmt * @crop: &struct v4l2_rect to be used for crop * @compose: &struct v4l2_rect to be used for compose - * - * This structure only needs to be passed to the pad op if the 'which' field - * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For - * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL. */ struct v4l2_subdev_pad_config { struct v4l2_mbus_framefmt format; From 274ee48e4ca9d031a6a957f5f33116049d02a284 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:45 +0200 Subject: [PATCH 1327/7721] media: ipu3-cio2: Drop comment blocks for subdev op handlers The V4L2 subdev .get_fmt() and .set_fmt() pad operation handlers have a short documentation block that merely duplicates information from the V4L2 subdev API documentation. They offer no value, and are prone to bit-rotting as shown by the @cfg parameter documentation being outdated. Drop them. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 5dd69a251b6a..301a0ee6d236 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1215,13 +1215,6 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -/* - * cio2_subdev_get_fmt - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1241,13 +1234,6 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, return 0; } -/* - * cio2_subdev_set_fmt - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) From e5c51f0bb2e4f68218e49167c63b85f3adcbebfa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:46 +0200 Subject: [PATCH 1328/7721] media: xilinx: csi2rxss: Drop comment blocks for subdev op handlers The V4L2 subdev operation handlers have short documentation blocks that merely duplicates information from the V4L2 subdev API documentation. They offer no value, and are prone to bit-rotting as shown by the ixcsi2rxss_set_format() documentation being incorrect. Drop them. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/xilinx/xilinx-csi2rxss.c | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index 5b53745fe44e..d4f66e93eabd 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -386,14 +386,6 @@ static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state) } } -/** - * xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver - * @sd: Pointer to V4L2 subdevice structure - * - * This function prints the current status of Xilinx MIPI CSI-2 - * - * Return: 0 on success - */ static int xcsi2rxss_log_status(struct v4l2_subdev *sd) { struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); @@ -631,16 +623,6 @@ static irqreturn_t xcsi2rxss_irq_handler(int irq, void *data) return IRQ_HANDLED; } -/** - * xcsi2rxss_s_stream - It is used to start/stop the streaming. - * @sd: V4L2 Sub device - * @enable: Flag (True / False) - * - * This function controls the start or stop of streaming for the - * Xilinx MIPI CSI-2 Rx Subsystem. - * - * Return: 0 on success, errors otherwise - */ static int xcsi2rxss_s_stream(struct v4l2_subdev *sd, int enable) { struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); @@ -680,16 +662,6 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss, } } -/** - * xcsi2rxss_init_cfg - Initialise the pad format config to default - * @sd: Pointer to V4L2 Sub device structure - * @sd_state: Pointer to sub device state structure - * - * This function is used to initialize the pad format with the default - * values. - * - * Return: 0 on success - */ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { @@ -707,16 +679,6 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd, return 0; } -/** - * xcsi2rxss_get_format - Get the pad format - * @sd: Pointer to V4L2 Sub device structure - * @sd_state: Pointer to sub device state structure - * @fmt: Pointer to pad level media bus format - * - * This function is used to get the pad format information. - * - * Return: 0 on success - */ static int xcsi2rxss_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -732,19 +694,6 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd, return 0; } -/** - * xcsi2rxss_set_format - This is used to set the pad format - * @sd: Pointer to V4L2 Sub device structure - * @sd_state: Pointer to sub device state structure - * @fmt: Pointer to pad level media bus format - * - * This function is used to set the pad format. Since the pad format is fixed - * in hardware, it can't be modified on run time. So when a format set is - * requested by application, all parameters except the format type is saved - * for the pad and the original pad format is sent back to the application. - * - * Return: 0 on success - */ static int xcsi2rxss_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -789,14 +738,6 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd, return 0; } -/* - * xcsi2rxss_enum_mbus_code - Handle pixel format enumeration - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * - * Return: -EINVAL or zero on success - */ static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) From c1ac5298867b955e8551bc4a93fcd739ea5db85a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:47 +0200 Subject: [PATCH 1329/7721] media: v4l2-subdev: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix the few remaining incorrect references to pad config in the documentation. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/v4l2-subdev.rst | 4 ++-- include/media/v4l2-subdev.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index e56b50b3f203..a62e4aff31be 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -562,8 +562,8 @@ device configuration. This is often implemented as e.g. an array of struct v4l2_mbus_framefmt, one entry for each pad, and similarly for crop and compose rectangles. -In addition to the active configuration, each subdev file handle has an array of -struct v4l2_subdev_pad_config, managed by the V4L2 core, which contains the try +In addition to the active configuration, each subdev file handle has a struct +v4l2_subdev_state, managed by the V4L2 core, which contains the try configuration. To simplify the subdev drivers the V4L2 subdev API now optionally supports a diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index bbcee4f3da1e..8a345b5fa39d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -769,7 +769,7 @@ struct v4l2_subdev_state { /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * - * @init_cfg: initialize the pad config to default values + * @init_cfg: initialize the subdev state to default values * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE() ioctl handler * code. * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE() ioctl handler From c1d9681407be6484055980e1bec068522d9bc36f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:48 +0200 Subject: [PATCH 1330/7721] media: qcom: camss: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix remaining incorrect references to pad config in comments. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/qcom/camss/camss-csid.c | 12 +++++----- .../media/platform/qcom/camss/camss-csiphy.c | 12 +++++----- .../media/platform/qcom/camss/camss-ispif.c | 12 +++++----- drivers/media/platform/qcom/camss/camss-vfe.c | 24 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 95873f988f7e..51952e6b37b3 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -263,7 +263,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) /* * __csid_get_format - Get pointer to format structure * @csid: CSID device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad from which format is requested * @which: TRY or ACTIVE format * @@ -285,7 +285,7 @@ __csid_get_format(struct csid_device *csid, /* * csid_try_format - Handle try format by pad subdev method * @csid: CSID device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad on which format is requested * @fmt: pointer to v4l2 format structure * @which: wanted subdev format @@ -353,7 +353,7 @@ static void csid_try_format(struct csid_device *csid, /* * csid_enum_mbus_code - Handle pixel format enumeration * @sd: CSID V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code: pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -394,7 +394,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, /* * csid_enum_frame_size - Handle frame size enumeration * @sd: CSID V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fse: pointer to v4l2_subdev_frame_size_enum structure * return -EINVAL or zero on success */ @@ -431,7 +431,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd, /* * csid_get_format - Handle get format by pads subdev method * @sd: CSID V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success @@ -455,7 +455,7 @@ static int csid_get_format(struct v4l2_subdev *sd, /* * csid_set_format - Handle set format by pads subdev method * @sd: CSID V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index edd573606a6a..838514b94d66 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -312,7 +312,7 @@ static int csiphy_set_stream(struct v4l2_subdev *sd, int enable) /* * __csiphy_get_format - Get pointer to format structure * @csiphy: CSIPHY device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad from which format is requested * @which: TRY or ACTIVE format * @@ -334,7 +334,7 @@ __csiphy_get_format(struct csiphy_device *csiphy, /* * csiphy_try_format - Handle try format by pad subdev method * @csiphy: CSIPHY device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad on which format is requested * @fmt: pointer to v4l2 format structure * @which: wanted subdev format @@ -381,7 +381,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy, /* * csiphy_enum_mbus_code - Handle pixel format enumeration * @sd: CSIPHY V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code: pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -414,7 +414,7 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd, /* * csiphy_enum_frame_size - Handle frame size enumeration * @sd: CSIPHY V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fse: pointer to v4l2_subdev_frame_size_enum structure * return -EINVAL or zero on success */ @@ -451,7 +451,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd, /* * csiphy_get_format - Handle get format by pads subdev method * @sd: CSIPHY V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success @@ -475,7 +475,7 @@ static int csiphy_get_format(struct v4l2_subdev *sd, /* * csiphy_set_format - Handle set format by pads subdev method * @sd: CSIPHY V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index ddfe94377ee5..c26f270e8e71 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -866,7 +866,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) /* * __ispif_get_format - Get pointer to format structure * @ispif: ISPIF line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad from which format is requested * @which: TRY or ACTIVE format * @@ -888,7 +888,7 @@ __ispif_get_format(struct ispif_line *line, /* * ispif_try_format - Handle try format by pad subdev method * @ispif: ISPIF line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad on which format is requested * @fmt: pointer to v4l2 format structure * @which: wanted subdev format @@ -936,7 +936,7 @@ static void ispif_try_format(struct ispif_line *line, /* * ispif_enum_mbus_code - Handle pixel format enumeration * @sd: ISPIF V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code: pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -969,7 +969,7 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd, /* * ispif_enum_frame_size - Handle frame size enumeration * @sd: ISPIF V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fse: pointer to v4l2_subdev_frame_size_enum structure * return -EINVAL or zero on success */ @@ -1006,7 +1006,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd, /* * ispif_get_format - Handle get format by pads subdev method * @sd: ISPIF V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success @@ -1030,7 +1030,7 @@ static int ispif_get_format(struct v4l2_subdev *sd, /* * ispif_set_format - Handle set format by pads subdev method * @sd: ISPIF V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 4839e2cedfe5..8ebcffc2762d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -815,7 +815,7 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable) /* * __vfe_get_format - Get pointer to format structure * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad from which format is requested * @which: TRY or ACTIVE format * @@ -837,7 +837,7 @@ __vfe_get_format(struct vfe_line *line, /* * __vfe_get_compose - Get pointer to compose selection structure * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @which: TRY or ACTIVE format * * Return pointer to TRY or ACTIVE compose rectangle structure @@ -857,7 +857,7 @@ __vfe_get_compose(struct vfe_line *line, /* * __vfe_get_crop - Get pointer to crop selection structure * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @which: TRY or ACTIVE format * * Return pointer to TRY or ACTIVE crop rectangle structure @@ -877,7 +877,7 @@ __vfe_get_crop(struct vfe_line *line, /* * vfe_try_format - Handle try format by pad subdev method * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad on which format is requested * @fmt: pointer to v4l2 format structure * @which: wanted subdev format @@ -938,7 +938,7 @@ static void vfe_try_format(struct vfe_line *line, /* * vfe_try_compose - Handle try compose selection by pad subdev method * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @rect: pointer to v4l2 rect structure * @which: wanted subdev format */ @@ -977,7 +977,7 @@ static void vfe_try_compose(struct vfe_line *line, /* * vfe_try_crop - Handle try crop selection by pad subdev method * @line: VFE line - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @rect: pointer to v4l2 rect structure * @which: wanted subdev format */ @@ -1020,7 +1020,7 @@ static void vfe_try_crop(struct vfe_line *line, /* * vfe_enum_mbus_code - Handle pixel format enumeration * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code: pointer to v4l2_subdev_mbus_code_enum structure * * return -EINVAL or zero on success @@ -1054,7 +1054,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd, /* * vfe_enum_frame_size - Handle frame size enumeration * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fse: pointer to v4l2_subdev_frame_size_enum structure * * Return -EINVAL or zero on success @@ -1092,7 +1092,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd, /* * vfe_get_format - Handle get format by pads subdev method * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success @@ -1120,7 +1120,7 @@ static int vfe_set_selection(struct v4l2_subdev *sd, /* * vfe_set_format - Handle set format by pads subdev method * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success @@ -1171,7 +1171,7 @@ static int vfe_set_format(struct v4l2_subdev *sd, /* * vfe_get_selection - Handle get selection by pads subdev method * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: pointer to v4l2 subdev selection structure * * Return -EINVAL or zero on success @@ -1241,7 +1241,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd, /* * vfe_set_selection - Handle set selection by pads subdev method * @sd: VFE V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: pointer to v4l2 subdev selection structure * * Return -EINVAL or zero on success From bb118e86dfcc096b8a3889c1a5c88f214e1f65fa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:50 +0200 Subject: [PATCH 1331/7721] media: ti: omap3isp: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix remaining incorrect references to pad config in comments. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/omap3isp/ispccdc.c | 12 ++++++------ drivers/media/platform/ti/omap3isp/ispccp2.c | 10 +++++----- drivers/media/platform/ti/omap3isp/ispcsi2.c | 6 +++--- drivers/media/platform/ti/omap3isp/isppreview.c | 12 ++++++------ drivers/media/platform/ti/omap3isp/ispresizer.c | 16 ++++++++-------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c index 2fe42aa91800..6aace3e592fb 100644 --- a/drivers/media/platform/ti/omap3isp/ispccdc.c +++ b/drivers/media/platform/ti/omap3isp/ispccdc.c @@ -1969,7 +1969,7 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, /* * ccdc_try_format - Try video format on a pad * @ccdc: ISP CCDC device - * @cfg : V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: Pad number * @fmt: Format */ @@ -2127,7 +2127,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, /* * ccdc_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg : V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -2230,7 +2230,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, /* * ccdc_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the output formatter @@ -2274,7 +2274,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, /* * ccdc_set_selection - Set a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the output @@ -2322,7 +2322,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, /* * ccdc_get_format - Retrieve the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond @@ -2346,7 +2346,7 @@ static int ccdc_get_format(struct v4l2_subdev *sd, /* * ccdc_set_format - Set the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c index da5f0176ec78..1bbb618db63d 100644 --- a/drivers/media/platform/ti/omap3isp/ispccp2.c +++ b/drivers/media/platform/ti/omap3isp/ispccp2.c @@ -614,7 +614,7 @@ static const unsigned int ccp2_fmts[] = { /* * __ccp2_get_format - helper function for getting ccp2 format * @ccp2 : Pointer to ISP CCP2 device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad : pad number * @which : wanted subdev format * return format structure or NULL on error @@ -634,7 +634,7 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, /* * ccp2_try_format - Handle try format by pad subdev method * @ccp2 : Pointer to ISP CCP2 device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad : pad num * @fmt : pointer to v4l2 mbus format structure * @which : wanted subdev format @@ -689,7 +689,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, /* * ccp2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -750,7 +750,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, /* * ccp2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ @@ -772,7 +772,7 @@ static int ccp2_get_format(struct v4l2_subdev *sd, /* * ccp2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt : pointer to v4l2 subdev format structure * returns zero */ diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c index 0f9a54b11f98..a415dc405209 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsi2.c +++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c @@ -894,7 +894,7 @@ csi2_try_format(struct isp_csi2_device *csi2, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -968,7 +968,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ @@ -990,7 +990,7 @@ static int csi2_get_format(struct v4l2_subdev *sd, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ diff --git a/drivers/media/platform/ti/omap3isp/isppreview.c b/drivers/media/platform/ti/omap3isp/isppreview.c index 53aedec7990d..740ba6cd3d36 100644 --- a/drivers/media/platform/ti/omap3isp/isppreview.c +++ b/drivers/media/platform/ti/omap3isp/isppreview.c @@ -1724,7 +1724,7 @@ static const unsigned int preview_output_fmts[] = { /* * preview_try_format - Validate a format * @prev: ISP preview engine - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad: pad number * @fmt: format to be validated * @which: try/active format selector @@ -1863,7 +1863,7 @@ static void preview_try_crop(struct isp_prev_device *prev, /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -1924,7 +1924,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, /* * preview_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1967,7 +1967,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, /* * preview_set_selection - Set a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -2015,7 +2015,7 @@ static int preview_set_selection(struct v4l2_subdev *sd, /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ @@ -2037,7 +2037,7 @@ static int preview_get_format(struct v4l2_subdev *sd, /* * preview_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ diff --git a/drivers/media/platform/ti/omap3isp/ispresizer.c b/drivers/media/platform/ti/omap3isp/ispresizer.c index ed2fb0c7a57e..f00a37f29b77 100644 --- a/drivers/media/platform/ti/omap3isp/ispresizer.c +++ b/drivers/media/platform/ti/omap3isp/ispresizer.c @@ -109,7 +109,7 @@ static const struct isprsz_coef filter_coefs = { * __resizer_get_format - helper function for getting resizer format * @res : pointer to resizer private structure * @pad : pad number - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @which : wanted subdev format * return zero */ @@ -127,7 +127,7 @@ __resizer_get_format(struct isp_res_device *res, /* * __resizer_get_crop - helper function for getting resizer crop rectangle * @res : pointer to resizer private structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @which : wanted subdev crop rectangle */ static struct v4l2_rect * @@ -1215,7 +1215,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, /* * resizer_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1265,7 +1265,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, /* * resizer_set_selection - Set a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -1369,7 +1369,7 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res) /* * resizer_try_format - Handle try format by pad subdev method * @res : ISP resizer device - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @pad : pad num * @fmt : pointer to v4l2 format structure * @which : wanted subdev format @@ -1413,7 +1413,7 @@ static void resizer_try_format(struct isp_res_device *res, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -1474,7 +1474,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ @@ -1496,7 +1496,7 @@ static int resizer_get_format(struct v4l2_subdev *sd, /* * resizer_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ From cde7093bd239e2aa9eaafc33ed621bf3525f507c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:51 +0200 Subject: [PATCH 1332/7721] media: ti: omap4iss: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix remaining incorrect references to pad config in comments. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss_csi2.c | 6 +++--- drivers/staging/media/omap4iss/iss_ipipe.c | 8 ++++---- drivers/staging/media/omap4iss/iss_ipipeif.c | 8 ++++---- drivers/staging/media/omap4iss/iss_resizer.c | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index d2844414de4f..bdc44c1290ad 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -891,7 +891,7 @@ csi2_try_format(struct iss_csi2_device *csi2, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg : V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -965,7 +965,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ @@ -987,7 +987,7 @@ static int csi2_get_format(struct v4l2_subdev *sd, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c index 23f707cb336f..7c96fbf7a170 100644 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ b/drivers/staging/media/omap4iss/iss_ipipe.c @@ -189,7 +189,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, /* * ipipe_try_format - Try video format on a pad * @ipipe: ISS IPIPE device - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @pad: Pad number * @fmt: Format */ @@ -240,7 +240,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, /* * ipipe_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg : V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -304,7 +304,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, /* * ipipe_get_format - Retrieve the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond @@ -328,7 +328,7 @@ static int ipipe_get_format(struct v4l2_subdev *sd, /* * ipipe_set_format - Set the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 5e7f25cd53ac..93a4dbec1428 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -369,7 +369,7 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, /* * ipipeif_try_format - Try video format on a pad * @ipipeif: ISS IPIPEIF device - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @pad: Pad number * @fmt: Format */ @@ -440,7 +440,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, /* * ipipeif_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg : V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -512,7 +512,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, /* * ipipeif_get_format - Retrieve the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond @@ -536,7 +536,7 @@ static int ipipeif_get_format(struct v4l2_subdev *sd, /* * ipipeif_set_format - Set the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index a5f8f9f1ab16..6bb906cc17f0 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -428,7 +428,7 @@ __resizer_get_format(struct iss_resizer_device *resizer, /* * resizer_try_format - Try video format on a pad * @resizer: ISS RESIZER device - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @pad: Pad number * @fmt: Format */ @@ -489,7 +489,7 @@ resizer_try_format(struct iss_resizer_device *resizer, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ @@ -572,7 +572,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Retrieve the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond @@ -596,7 +596,7 @@ static int resizer_get_format(struct v4l2_subdev *sd, /* * resizer_set_format - Set the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @cfg: V4L2 subdev pad config + * @sd_state: V4L2 subdev state * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond From aeb18af18828f65eebb3dc475c62faab9cc8e9b6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 11:58:52 +0200 Subject: [PATCH 1333/7721] media: i2c: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix the few remaining incorrect references to pad config in the I2C drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx334.c | 8 ++++---- drivers/media/i2c/imx335.c | 8 ++++---- drivers/media/i2c/imx412.c | 8 ++++---- drivers/media/i2c/ov9282.c | 8 ++++---- drivers/media/i2c/tvp7002.c | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 1196fe93506b..404d0f1dffcd 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -935,14 +935,14 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd, } /** - * imx334_init_pad_cfg() - Initialize sub-device pad configuration + * imx334_init_cfg() - Initialize sub-device state * @sd: pointer to imx334 V4L2 sub-device structure * @sd_state: V4L2 sub-device state * * Return: 0 if successful, error code otherwise. */ -static int imx334_init_pad_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx334_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx334 *imx334 = to_imx334(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -1190,7 +1190,7 @@ static const struct v4l2_subdev_video_ops imx334_video_ops = { }; static const struct v4l2_subdev_pad_ops imx334_pad_ops = { - .init_cfg = imx334_init_pad_cfg, + .init_cfg = imx334_init_cfg, .enum_mbus_code = imx334_enum_mbus_code, .enum_frame_size = imx334_enum_frame_size, .get_fmt = imx334_get_pad_format, diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index ec729126274b..01c871c1ab61 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -618,14 +618,14 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, } /** - * imx335_init_pad_cfg() - Initialize sub-device pad configuration + * imx335_init_cfg() - Initialize sub-device state * @sd: pointer to imx335 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int imx335_init_pad_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx335_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx335 *imx335 = to_imx335(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -835,7 +835,7 @@ static const struct v4l2_subdev_video_ops imx335_video_ops = { }; static const struct v4l2_subdev_pad_ops imx335_pad_ops = { - .init_cfg = imx335_init_pad_cfg, + .init_cfg = imx335_init_cfg, .enum_mbus_code = imx335_enum_mbus_code, .enum_frame_size = imx335_enum_frame_size, .get_fmt = imx335_get_pad_format, diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 962b3136c31e..dd5cf7f20310 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -770,14 +770,14 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, } /** - * imx412_init_pad_cfg() - Initialize sub-device pad configuration + * imx412_init_cfg() - Initialize sub-device state * @sd: pointer to imx412 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int imx412_init_pad_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx412_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx412 *imx412 = to_imx412(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -997,7 +997,7 @@ static const struct v4l2_subdev_video_ops imx412_video_ops = { }; static const struct v4l2_subdev_pad_ops imx412_pad_ops = { - .init_cfg = imx412_init_pad_cfg, + .init_cfg = imx412_init_cfg, .enum_mbus_code = imx412_enum_mbus_code, .enum_frame_size = imx412_enum_frame_size, .get_fmt = imx412_get_pad_format, diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index bf6dfce1b5dd..b50a6196b89c 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -876,14 +876,14 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd, } /** - * ov9282_init_pad_cfg() - Initialize sub-device pad configuration + * ov9282_init_cfg() - Initialize sub-device state * @sd: pointer to ov9282 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int ov9282_init_pad_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov9282_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ov9282 *ov9282 = to_ov9282(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -1192,7 +1192,7 @@ static const struct v4l2_subdev_video_ops ov9282_video_ops = { }; static const struct v4l2_subdev_pad_ops ov9282_pad_ops = { - .init_cfg = ov9282_init_pad_cfg, + .init_cfg = ov9282_init_cfg, .enum_mbus_code = ov9282_enum_mbus_code, .enum_frame_size = ov9282_enum_frame_size, .get_fmt = ov9282_get_pad_format, diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index a2d7bc799849..30831b4b56d6 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -791,7 +791,7 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { /* * tvp7002_enum_mbus_code() - Enum supported digital video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @cfg: pad configuration + * @sd_state: V4L2 subdev state * @code: pointer to subdev enum mbus code struct * * Enumerate supported digital video formats for pad. @@ -813,7 +813,7 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, /* * tvp7002_get_pad_format() - get video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @cfg: pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to subdev format struct * * get video format for pad. @@ -837,7 +837,7 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, /* * tvp7002_set_pad_format() - set video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @cfg: pad configuration + * @sd_state: V4L2 subdev state * @fmt: pointer to subdev format struct * * set video format for pad. From 52c2575db8faa1d93227a92a32deb2cd66b96614 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 09:15:48 +0200 Subject: [PATCH 1334/7721] media: v4l: subdev: Store the sub-device in the sub-device state Store the sub-device in the sub-device state. This will be needed in e.g. validating pad number when retrieving information for non-stream-aware users. There are expected to be more needs for this in the future. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 2 ++ include/media/v4l2-subdev.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index be86b906c985..cd3ff5b19d0c 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1448,6 +1448,8 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, else state->lock = &state->_lock; + state->sd = sd; + /* Drivers that support streams do not need the legacy pad config */ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS) && sd->entity.num_pads) { state->pads = kvcalloc(sd->entity.num_pads, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 8a345b5fa39d..46296852cb5b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -749,6 +749,7 @@ struct v4l2_subdev_krouting { * * @_lock: default for 'lock' * @lock: mutex for the state. May be replaced by the user. + * @sd: the sub-device which the state is related to * @pads: &struct v4l2_subdev_pad_config array * @routing: routing table for the subdev * @stream_configs: stream configurations (only for V4L2_SUBDEV_FL_STREAMS) @@ -761,6 +762,7 @@ struct v4l2_subdev_state { /* lock for the struct v4l2_subdev_state fields */ struct mutex _lock; struct mutex *lock; + struct v4l2_subdev *sd; struct v4l2_subdev_pad_config *pads; struct v4l2_subdev_krouting routing; struct v4l2_subdev_stream_configs stream_configs; From 049fa16b81c276f25a09abaa4e8f743470c3cdc8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 09:31:37 +0200 Subject: [PATCH 1335/7721] media: v4l: subdev: Also return pads array information on stream functions There are two sets of functions that return information from sub-device state, one for stream-unaware users and another for stream-aware users. Add support for stream-aware functions to return format, crop and compose information from pad-based array that are functionally equivalent to the old, stream-unaware ones. Also check state is non-NULL, in order to guard against old drivers potentially calling this with NULL state for active formats or selection rectangles. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 63 +++++++++++++++++++++++++++ include/media/v4l2-subdev.h | 9 ++-- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index cd3ff5b19d0c..554d0c128ee9 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1691,6 +1691,27 @@ v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].format; + } + lockdep_assert_held(state->lock); stream_configs = &state->stream_configs; @@ -1712,6 +1733,27 @@ v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].crop; + } + lockdep_assert_held(state->lock); stream_configs = &state->stream_configs; @@ -1733,6 +1775,27 @@ v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].compose; + } + lockdep_assert_held(state->lock); stream_configs = &state->stream_configs; diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 46296852cb5b..6b242ec58cb7 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1543,7 +1543,8 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad + * stream in the subdev state. * - * If the state does not contain the given pad + stream, NULL is returned. + * For stream-unaware drivers the format for the corresponding pad is returned. + * If the pad does not exist, NULL is returned. */ struct v4l2_mbus_framefmt * v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, @@ -1558,7 +1559,8 @@ v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, * This returns a pointer to crop rectangle for the given pad + stream in the * subdev state. * - * If the state does not contain the given pad + stream, NULL is returned. + * For stream-unaware drivers the crop rectangle for the corresponding pad is + * returned. If the pad does not exist, NULL is returned. */ struct v4l2_rect * v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, @@ -1574,7 +1576,8 @@ v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, * This returns a pointer to compose rectangle for the given pad + stream in the * subdev state. * - * If the state does not contain the given pad + stream, NULL is returned. + * For stream-unaware drivers the compose rectangle for the corresponding pad is + * returned. If the pad does not exist, NULL is returned. */ struct v4l2_rect * v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, From d0fde6aae2bacdc024fff43461ba0f325375fa97 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 10:16:06 +0200 Subject: [PATCH 1336/7721] media: v4l: subdev: Rename sub-device state information access functions Rename the sub-devices state information access functions, removing "_stream" from them and replacing "format" by "ffmt". This makes them shorter and so more convenient to use. No other sets of functions will be needed to access this information. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ds90ub913.c | 3 +-- drivers/media/i2c/ds90ub953.c | 3 +-- drivers/media/i2c/ds90ub960.c | 12 ++++----- .../platform/nxp/imx8-isi/imx8-isi-crossbar.c | 10 +++---- drivers/media/v4l2-core/v4l2-subdev.c | 27 +++++++++---------- include/media/v4l2-subdev.h | 19 +++++++------ 6 files changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 8e9ebed09f64..8bb6be956780 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -424,8 +424,7 @@ static int ub913_set_fmt(struct v4l2_subdev *sd, } /* Set sink format */ - fmt = v4l2_subdev_state_get_stream_format(state, format->pad, - format->stream); + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 644022312833..4eb08e3a31c7 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -558,8 +558,7 @@ static int ub953_set_fmt(struct v4l2_subdev *sd, return v4l2_subdev_get_fmt(sd, state, format); /* Set sink format */ - fmt = v4l2_subdev_state_get_stream_format(state, format->pad, - format->stream); + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index b8f3e5ca03ef..1d1476098c92 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2451,9 +2451,8 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, if (rx_data[nport].num_streams > 2) return -EPIPE; - fmt = v4l2_subdev_state_get_stream_format(state, - route->sink_pad, - route->sink_stream); + fmt = v4l2_subdev_state_get_format(state, route->sink_pad, + route->sink_stream); if (!fmt) return -EPIPE; @@ -2842,8 +2841,8 @@ static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, const struct ub960_format_info *ub960_fmt; struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_state_get_stream_format(state, pad, - route->source_stream); + fmt = v4l2_subdev_state_get_format(state, pad, + route->source_stream); if (!fmt) { ret = -EINVAL; @@ -2891,8 +2890,7 @@ static int ub960_set_fmt(struct v4l2_subdev *sd, if (!ub960_find_format(format->format.code)) format->format.code = ub960_formats[0].code; - fmt = v4l2_subdev_state_get_stream_format(state, format->pad, - format->stream); + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c index 792f031e032a..9401261eb239 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c @@ -58,7 +58,7 @@ static int mxc_isi_crossbar_gasket_enable(struct mxc_isi_crossbar *xbar, return -EINVAL; } - fmt = v4l2_subdev_state_get_stream_format(state, port, 0); + fmt = v4l2_subdev_state_get_format(state, port, 0); if (!fmt) return -EINVAL; @@ -281,8 +281,7 @@ static int mxc_isi_crossbar_set_fmt(struct v4l2_subdev *sd, * Set the format on the sink stream and propagate it to the source * streams. */ - sink_fmt = v4l2_subdev_state_get_stream_format(state, fmt->pad, - fmt->stream); + sink_fmt = v4l2_subdev_state_get_format(state, fmt->pad, fmt->stream); if (!sink_fmt) return -EINVAL; @@ -296,8 +295,9 @@ static int mxc_isi_crossbar_set_fmt(struct v4l2_subdev *sd, route->sink_stream != fmt->stream) continue; - source_fmt = v4l2_subdev_state_get_stream_format(state, route->source_pad, - route->source_stream); + source_fmt = v4l2_subdev_state_get_format(state, + route->source_pad, + route->source_stream); if (!source_fmt) return -EINVAL; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 554d0c128ee9..a6f480ef7881 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -177,7 +177,7 @@ static int check_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, { if (sd->flags & V4L2_SUBDEV_FL_STREAMS) { #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - if (!v4l2_subdev_state_get_stream_format(state, pad, stream)) + if (!v4l2_subdev_state_get_format(state, pad, stream)) return -EINVAL; return 0; #else @@ -1588,8 +1588,8 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_mbus_framefmt *fmt; if (sd->flags & V4L2_SUBDEV_FL_STREAMS) - fmt = v4l2_subdev_state_get_stream_format(state, format->pad, - format->stream); + fmt = v4l2_subdev_state_get_format(state, format->pad, + format->stream); else if (format->pad < sd->entity.num_pads && format->stream == 0) fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); else @@ -1685,8 +1685,8 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt); struct v4l2_mbus_framefmt * -v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream) +v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1724,11 +1724,11 @@ v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_format); +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_format); struct v4l2_rect * -v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream) +v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1766,11 +1766,11 @@ v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_crop); +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_crop); struct v4l2_rect * -v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream) +v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1808,7 +1808,7 @@ v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose); +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_compose); int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, u32 pad, u32 stream, u32 *other_pad, @@ -1854,8 +1854,7 @@ v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, if (ret) return NULL; - return v4l2_subdev_state_get_stream_format(state, other_pad, - other_stream); + return v4l2_subdev_state_get_format(state, other_pad, other_stream); } EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 6b242ec58cb7..f144d49a825c 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1535,7 +1535,7 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, const struct v4l2_mbus_framefmt *fmt); /** - * v4l2_subdev_state_get_stream_format() - Get pointer to a stream format + * v4l2_subdev_state_get_format() - Get pointer to a stream format * @state: subdevice state * @pad: pad id * @stream: stream id @@ -1547,11 +1547,11 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, * If the pad does not exist, NULL is returned. */ struct v4l2_mbus_framefmt * -v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream); +v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream); /** - * v4l2_subdev_state_get_stream_crop() - Get pointer to a stream crop rectangle + * v4l2_subdev_state_get_crop() - Get pointer to a stream crop rectangle * @state: subdevice state * @pad: pad id * @stream: stream id @@ -1563,12 +1563,11 @@ v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, * returned. If the pad does not exist, NULL is returned. */ struct v4l2_rect * -v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream); +v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream); /** - * v4l2_subdev_state_get_stream_compose() - Get pointer to a stream compose - * rectangle + * v4l2_subdev_state_get_compose() - Get pointer to a stream compose rectangle * @state: subdevice state * @pad: pad id * @stream: stream id @@ -1580,8 +1579,8 @@ v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, * returned. If the pad does not exist, NULL is returned. */ struct v4l2_rect * -v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream); +v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream); /** * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream From 8824170e95d72d7583bd8e897246685d3856455a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 10:54:24 +0200 Subject: [PATCH 1337/7721] media: v4l: subdev: v4l2_subdev_state_get_format always returns format now Now that v4l2_subdev_state_get_format() always returns format, don't call alternative v4l2_subdev_get_pad_format() anymore. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index a6f480ef7881..9eef170934c5 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1587,14 +1587,7 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, { struct v4l2_mbus_framefmt *fmt; - if (sd->flags & V4L2_SUBDEV_FL_STREAMS) - fmt = v4l2_subdev_state_get_format(state, format->pad, - format->stream); - else if (format->pad < sd->entity.num_pads && format->stream == 0) - fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); - else - fmt = NULL; - + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; From 791765b426df4d2a1b1be0617c2c0bf2248bfaba Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 23 Oct 2023 12:26:34 +0200 Subject: [PATCH 1338/7721] media: v4l: subdev: Make stream argument optional in state access functions The sub-device state access functions take three arguments: sub-device state, pad and stream. The stream is not relevant for the majority of drivers and having to specify 0 for the stream is considered a nuisance. Provide a two-argument macros for these state access functions to cover the needs of stream-unaware users. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 18 +++++----- include/media/v4l2-subdev.h | 49 ++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 9eef170934c5..06988e3a6f10 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1678,8 +1678,8 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt); struct v4l2_mbus_framefmt * -v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream) +__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1717,11 +1717,11 @@ v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_format); +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_format); struct v4l2_rect * -v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream) +__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1759,11 +1759,11 @@ v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_crop); +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_crop); struct v4l2_rect * -v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream) +__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) { struct v4l2_subdev_stream_configs *stream_configs; unsigned int i; @@ -1801,7 +1801,7 @@ v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, return NULL; } -EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_compose); +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_compose); int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, u32 pad, u32 stream, u32 *other_pad, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index f144d49a825c..c8ac91a2cdb8 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1534,11 +1534,18 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, const struct v4l2_subdev_krouting *routing, const struct v4l2_mbus_framefmt *fmt); +/* + * A macro to generate the macro or function name for sub-devices state access + * wrapper macros below. + */ +#define __v4l2_subdev_state_gen_call(NAME, _1, ARG, ...) \ + __v4l2_subdev_state_get_ ## NAME ## ARG + /** * v4l2_subdev_state_get_format() - Get pointer to a stream format * @state: subdevice state * @pad: pad id - * @stream: stream id + * @...: stream id (optional argument) * * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad + * stream in the subdev state. @@ -1546,15 +1553,29 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, * For stream-unaware drivers the format for the corresponding pad is returned. * If the pad does not exist, NULL is returned. */ +/* + * Wrap v4l2_subdev_state_get_format(), allowing the function to be called with + * two or three arguments. The purpose of the __v4l2_subdev_state_get_format() + * macro below is to come up with the name of the function or macro to call, + * using the last two arguments (_stream and _pad). The selected function or + * macro is then called using the arguments specified by the caller. A similar + * arrangement is used for v4l2_subdev_state_crop() and + * v4l2_subdev_state_compose() below. + */ +#define v4l2_subdev_state_get_format(state, pad, ...) \ + __v4l2_subdev_state_gen_call(format, ##__VA_ARGS__, , _pad) \ + (state, pad, ##__VA_ARGS__) +#define __v4l2_subdev_state_get_format_pad(state, pad) \ + __v4l2_subdev_state_get_format(state, pad, 0) struct v4l2_mbus_framefmt * -v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream); +__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream); /** * v4l2_subdev_state_get_crop() - Get pointer to a stream crop rectangle * @state: subdevice state * @pad: pad id - * @stream: stream id + * @...: stream id (optional argument) * * This returns a pointer to crop rectangle for the given pad + stream in the * subdev state. @@ -1562,15 +1583,20 @@ v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, unsigned int pad, * For stream-unaware drivers the crop rectangle for the corresponding pad is * returned. If the pad does not exist, NULL is returned. */ +#define v4l2_subdev_state_get_crop(state, pad, ...) \ + __v4l2_subdev_state_gen_call(crop, ##__VA_ARGS__, , _pad) \ + (state, pad, ##__VA_ARGS__) +#define __v4l2_subdev_state_get_crop_pad(state, pad) \ + __v4l2_subdev_state_get_crop(state, pad, 0) struct v4l2_rect * -v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream); +__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream); /** * v4l2_subdev_state_get_compose() - Get pointer to a stream compose rectangle * @state: subdevice state * @pad: pad id - * @stream: stream id + * @...: stream id (optional argument) * * This returns a pointer to compose rectangle for the given pad + stream in the * subdev state. @@ -1578,9 +1604,14 @@ v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, * For stream-unaware drivers the compose rectangle for the corresponding pad is * returned. If the pad does not exist, NULL is returned. */ +#define v4l2_subdev_state_get_compose(state, pad, ...) \ + __v4l2_subdev_state_gen_call(compose, ##__VA_ARGS__, , _pad) \ + (state, pad, ##__VA_ARGS__) +#define __v4l2_subdev_state_get_compose_pad(state, pad) \ + __v4l2_subdev_state_get_compose(state, pad, 0) struct v4l2_rect * -v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream); +__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream); /** * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream From 981e0d4c724fae1fbc281b3b25b18b041b793f4d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 10 Nov 2023 08:10:26 +0100 Subject: [PATCH 1339/7721] media: v4l: subdev: Always compile sub-device state access functions Compile sub-device state information access functions v4l2_subdev_state_get_{format,crop,compose} unconditionally as they are now also used by plain V4L2 drivers. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 252 +++++++++++++------------- include/media/v4l2-subdev.h | 128 ++++++------- 2 files changed, 190 insertions(+), 190 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 06988e3a6f10..41fe9fa5c21a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1531,6 +1531,132 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd) } EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup); +struct v4l2_mbus_framefmt * +__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].format; + } + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].fmt; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_format); + +struct v4l2_rect * +__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, + u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].crop; + } + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].crop; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_crop); + +struct v4l2_rect * +__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + if (WARN_ON_ONCE(!state)) + return NULL; + + if (state->pads) { + if (stream) + return NULL; + + /* + * Set the pad to 0 on error as this is aligned with the + * behaviour of the pad state information access functions. The + * purpose of setting pad to 0 here is to avoid accessing memory + * outside the pads array, but still issuing warning of the + * invalid access while making the caller's error handling + * easier. + */ + if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) + pad = 0; + + return &state->pads[pad].compose; + } + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].compose; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_compose); + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) static int @@ -1677,132 +1803,6 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, } EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt); -struct v4l2_mbus_framefmt * -__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream) -{ - struct v4l2_subdev_stream_configs *stream_configs; - unsigned int i; - - if (WARN_ON_ONCE(!state)) - return NULL; - - if (state->pads) { - if (stream) - return NULL; - - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; - - return &state->pads[pad].format; - } - - lockdep_assert_held(state->lock); - - stream_configs = &state->stream_configs; - - for (i = 0; i < stream_configs->num_configs; ++i) { - if (stream_configs->configs[i].pad == pad && - stream_configs->configs[i].stream == stream) - return &stream_configs->configs[i].fmt; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_format); - -struct v4l2_rect * -__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, - u32 stream) -{ - struct v4l2_subdev_stream_configs *stream_configs; - unsigned int i; - - if (WARN_ON_ONCE(!state)) - return NULL; - - if (state->pads) { - if (stream) - return NULL; - - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; - - return &state->pads[pad].crop; - } - - lockdep_assert_held(state->lock); - - stream_configs = &state->stream_configs; - - for (i = 0; i < stream_configs->num_configs; ++i) { - if (stream_configs->configs[i].pad == pad && - stream_configs->configs[i].stream == stream) - return &stream_configs->configs[i].crop; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_crop); - -struct v4l2_rect * -__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, - unsigned int pad, u32 stream) -{ - struct v4l2_subdev_stream_configs *stream_configs; - unsigned int i; - - if (WARN_ON_ONCE(!state)) - return NULL; - - if (state->pads) { - if (stream) - return NULL; - - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; - - return &state->pads[pad].compose; - } - - lockdep_assert_held(state->lock); - - stream_configs = &state->stream_configs; - - for (i = 0; i < stream_configs->num_configs; ++i) { - if (stream_configs->configs[i].pad == pad && - stream_configs->configs[i].stream == stream) - return &stream_configs->configs[i].compose; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_compose); - int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, u32 pad, u32 stream, u32 *other_pad, u32 *other_stream) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index c8ac91a2cdb8..80744d87bae4 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1470,70 +1470,6 @@ v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd) return sd->active_state; } -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - -/** - * v4l2_subdev_get_fmt() - Fill format based on state - * @sd: subdevice - * @state: subdevice state - * @format: pointer to &struct v4l2_subdev_format - * - * Fill @format->format field based on the information in the @format struct. - * - * This function can be used by the subdev drivers which support active state to - * implement v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to - * do anything special in their get_fmt op. - * - * Returns 0 on success, error value otherwise. - */ -int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, - struct v4l2_subdev_format *format); - -/** - * v4l2_subdev_set_routing() - Set given routing to subdev state - * @sd: The subdevice - * @state: The subdevice state - * @routing: Routing that will be copied to subdev state - * - * This will release old routing table (if any) from the state, allocate - * enough space for the given routing, and copy the routing. - * - * This can be used from the subdev driver's set_routing op, after validating - * the routing. - */ -int v4l2_subdev_set_routing(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - const struct v4l2_subdev_krouting *routing); - -struct v4l2_subdev_route * -__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, - struct v4l2_subdev_route *route); - -/** - * for_each_active_route - iterate on all active routes of a routing table - * @routing: The routing table - * @route: The route iterator - */ -#define for_each_active_route(routing, route) \ - for ((route) = NULL; \ - ((route) = __v4l2_subdev_next_active_route((routing), (route)));) - -/** - * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev - * state - * @sd: The subdevice - * @state: The subdevice state - * @routing: Routing that will be copied to subdev state - * @fmt: Format used to initialize all the streams - * - * This is the same as v4l2_subdev_set_routing, but additionally initializes - * all the streams using the given format. - */ -int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - const struct v4l2_subdev_krouting *routing, - const struct v4l2_mbus_framefmt *fmt); - /* * A macro to generate the macro or function name for sub-devices state access * wrapper macros below. @@ -1613,6 +1549,70 @@ struct v4l2_rect * __v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, unsigned int pad, u32 stream); +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + +/** + * v4l2_subdev_get_fmt() - Fill format based on state + * @sd: subdevice + * @state: subdevice state + * @format: pointer to &struct v4l2_subdev_format + * + * Fill @format->format field based on the information in the @format struct. + * + * This function can be used by the subdev drivers which support active state to + * implement v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to + * do anything special in their get_fmt op. + * + * Returns 0 on success, error value otherwise. + */ +int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format); + +/** + * v4l2_subdev_set_routing() - Set given routing to subdev state + * @sd: The subdevice + * @state: The subdevice state + * @routing: Routing that will be copied to subdev state + * + * This will release old routing table (if any) from the state, allocate + * enough space for the given routing, and copy the routing. + * + * This can be used from the subdev driver's set_routing op, after validating + * the routing. + */ +int v4l2_subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + const struct v4l2_subdev_krouting *routing); + +struct v4l2_subdev_route * +__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, + struct v4l2_subdev_route *route); + +/** + * for_each_active_route - iterate on all active routes of a routing table + * @routing: The routing table + * @route: The route iterator + */ +#define for_each_active_route(routing, route) \ + for ((route) = NULL; \ + ((route) = __v4l2_subdev_next_active_route((routing), (route)));) + +/** + * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev + * state + * @sd: The subdevice + * @state: The subdevice state + * @routing: Routing that will be copied to subdev state + * @fmt: Format used to initialize all the streams + * + * This is the same as v4l2_subdev_set_routing, but additionally initializes + * all the streams using the given format. + */ +int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + const struct v4l2_subdev_krouting *routing, + const struct v4l2_mbus_framefmt *fmt); + /** * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream * @routing: routing used to find the opposite side From bc0e8d91feec72b19199298dca470c5816a52105 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 09:37:10 +0200 Subject: [PATCH 1340/7721] media: v4l: subdev: Switch to stream-aware state functions Switch all drivers accessing sub-device state to use the stream-aware functions. We will soon remove the old ones. This patch has been generated using the following Coccinelle script: ---------8<------------ @@ expression E1, E2, E3; @@ - v4l2_subdev_get_pad_format(E1, E2, E3) + v4l2_subdev_state_get_format(E2, E3) @@ expression E1, E2, E3; @@ - v4l2_subdev_get_pad_crop(E1, E2, E3) + v4l2_subdev_state_get_crop(E2, E3) @@ expression E1, E2, E3; @@ - v4l2_subdev_get_pad_compose(E1, E2, E3) + v4l2_subdev_state_get_compose(E2, E3) @@ expression E1, E2, E3; @@ - v4l2_subdev_get_try_format(E1, E2, E3) + v4l2_subdev_state_get_format(E2, E3) @@ expression E1, E2, E3; @@ - v4l2_subdev_get_try_crop(E1, E2, E3) + v4l2_subdev_state_get_crop(E2, E3) @@ expression E1, E2, E3; @@ - v4l2_subdev_get_try_compose(E1, E2, E3) + v4l2_subdev_state_get_compose(E2, E3) ---------8<------------ Additionally drivers/media/i2c/s5k5baf.c and drivers/media/platform/samsung/s3c-camif/camif-capture.c have been manually changed as Coccinelle didn't. Further local variables have been removed as they became unused as a result of the other changes. Also Coccinelle introduced indentation by space in files drivers/media/i2c/st-mipid02.c and drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c. This has been also corrected. The diff from Coccinelle-generated changes are: > diff --git b/drivers/media/i2c/imx319.c a/drivers/media/i2c/imx319.c > index e549692ff478..420984382173 100644 > --- b/drivers/media/i2c/imx319.c > +++ a/drivers/media/i2c/imx319.c > @@ -2001,7 +2001,6 @@ static int imx319_do_get_pad_format(struct imx319 *imx319, > struct v4l2_subdev_format *fmt) > { > struct v4l2_mbus_framefmt *framefmt; > - struct v4l2_subdev *sd = &imx319->sd; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); > diff --git b/drivers/media/i2c/imx355.c a/drivers/media/i2c/imx355.c > index 96bdde685d65..e1b1d2fc79dd 100644 > --- b/drivers/media/i2c/imx355.c > +++ a/drivers/media/i2c/imx355.c > @@ -1299,7 +1299,6 @@ static int imx355_do_get_pad_format(struct imx355 *imx355, > struct v4l2_subdev_format *fmt) > { > struct v4l2_mbus_framefmt *framefmt; > - struct v4l2_subdev *sd = &imx355->sd; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); > diff --git b/drivers/media/i2c/ov08x40.c a/drivers/media/i2c/ov08x40.c > index ca799bbcfdb7..abbb0b774d43 100644 > --- b/drivers/media/i2c/ov08x40.c > +++ a/drivers/media/i2c/ov08x40.c > @@ -2774,7 +2774,6 @@ static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x, > struct v4l2_subdev_format *fmt) > { > struct v4l2_mbus_framefmt *framefmt; > - struct v4l2_subdev *sd = &ov08x->sd; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); > diff --git b/drivers/media/i2c/ov13858.c a/drivers/media/i2c/ov13858.c > index 7816d9787c61..09387e335d80 100644 > --- b/drivers/media/i2c/ov13858.c > +++ a/drivers/media/i2c/ov13858.c > @@ -1316,7 +1316,6 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858, > struct v4l2_subdev_format *fmt) > { > struct v4l2_mbus_framefmt *framefmt; > - struct v4l2_subdev *sd = &ov13858->sd; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); > diff --git b/drivers/media/i2c/ov13b10.c a/drivers/media/i2c/ov13b10.c > index 268cd4b03f9c..c06411d5ee2b 100644 > --- b/drivers/media/i2c/ov13b10.c > +++ a/drivers/media/i2c/ov13b10.c > @@ -1001,7 +1001,6 @@ static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b, > struct v4l2_subdev_format *fmt) > { > struct v4l2_mbus_framefmt *framefmt; > - struct v4l2_subdev *sd = &ov13b->sd; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); > diff --git b/drivers/media/i2c/s5c73m3/s5c73m3-core.c a/drivers/media/i2c/s5c73m3/s5c73m3-core.c > index 47605e36bc60..8f9b5713daf7 100644 > --- b/drivers/media/i2c/s5c73m3/s5c73m3-core.c > +++ a/drivers/media/i2c/s5c73m3/s5c73m3-core.c > @@ -819,7 +819,6 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, > struct v4l2_subdev_format *fmt, > const struct s5c73m3_frame_size **fs) > { > - struct v4l2_subdev *sd = &state->sensor_sd; > u32 code; > > switch (fmt->pad) { > diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c > index 67da2045f543..03ccfb0e1e11 100644 > --- a/drivers/media/i2c/s5k5baf.c > +++ b/drivers/media/i2c/s5k5baf.c > @@ -1472,14 +1472,11 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd, > > if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { > rects = (struct v4l2_rect * []) { > - &s5k5baf_cis_rect, > - v4l2_subdev_get_try_crop(sd, sd_state, > - PAD_CIS), > - v4l2_subdev_get_try_compose(sd, sd_state, > - PAD_CIS), > - v4l2_subdev_get_try_crop(sd, sd_state, > - PAD_OUT) > - }; > + &s5k5baf_cis_rect, > + v4l2_subdev_state_get_crop(sd_state, PAD_CIS), > + v4l2_subdev_state_get_compose(sd_state, PAD_CIS), > + v4l2_subdev_state_get_crop(sd_state, PAD_OUT) > + }; > s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); > return 0; > } > diff --git b/drivers/media/platform/samsung/s3c-camif/camif-capture.c a/drivers/media/platform/samsung/s3c-camif/camif-capture.c > index 295e083f38e8..be58260ea67e 100644 > --- b/drivers/media/platform/samsung/s3c-camif/camif-capture.c > +++ a/drivers/media/platform/samsung/s3c-camif/camif-capture.c > @@ -1216,7 +1216,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, > struct v4l2_mbus_framefmt *mf = &fmt->format; > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); > + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); > fmt->format = *mf; > return 0; > } > @@ -1305,7 +1305,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, > __camif_subdev_try_format(camif, mf, fmt->pad); > > if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); > + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); > *mf = fmt->format; > mutex_unlock(&camif->lock); > return 0; > diff --git b/drivers/media/platform/ti/cal/cal-camerarx.c a/drivers/media/platform/ti/cal/cal-camerarx.c > index cea454ed9c20..61433744c6c4 100644 > --- b/drivers/media/platform/ti/cal/cal-camerarx.c > +++ a/drivers/media/platform/ti/cal/cal-camerarx.c > @@ -621,8 +621,6 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, > struct v4l2_subdev_state *state, > struct v4l2_subdev_mbus_code_enum *code) > { > - struct cal_camerarx *phy = to_cal_camerarx(sd); > - > /* No transcoding, source and sink codes must match. */ > if (cal_rx_pad_is_source(code->pad)) { > struct v4l2_mbus_framefmt *fmt; > diff --git b/drivers/staging/media/imx/imx-ic-prp.c a/drivers/staging/media/imx/imx-ic-prp.c > index dd558fac6477..61d69f19657e 100644 > --- b/drivers/staging/media/imx/imx-ic-prp.c > +++ a/drivers/staging/media/imx/imx-ic-prp.c > @@ -82,8 +82,6 @@ static struct v4l2_mbus_framefmt * > __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, > unsigned int pad, enum v4l2_subdev_format_whence which) > { > - struct imx_ic_priv *ic_priv = priv->ic_priv; > - > if (which == V4L2_SUBDEV_FORMAT_TRY) > return v4l2_subdev_state_get_format(sd_state, pad); > else > diff --git b/drivers/staging/media/imx/imx-ic-prpencvf.c a/drivers/staging/media/imx/imx-ic-prpencvf.c > index 02db7dbb884b..ec73c901079e 100644 > --- b/drivers/staging/media/imx/imx-ic-prpencvf.c > +++ a/drivers/staging/media/imx/imx-ic-prpencvf.c > @@ -790,8 +790,6 @@ static struct v4l2_mbus_framefmt * > __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, > unsigned int pad, enum v4l2_subdev_format_whence which) > { > - struct imx_ic_priv *ic_priv = priv->ic_priv; > - > if (which == V4L2_SUBDEV_FORMAT_TRY) > return v4l2_subdev_state_get_format(sd_state, pad); > else > diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c > index 9c9361354c00..b08a249b5fdd 100644 > --- a/drivers/media/i2c/st-mipid02.c > +++ b/drivers/media/i2c/st-mipid02.c > @@ -751,7 +751,7 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd, > format->format = bridge->fmt; > else > format->format = *v4l2_subdev_state_get_format(sd_state, > - MIPID02_SINK_0); > + MIPID02_SINK_0); > > /* but code may need to be converted */ > format->format.code = serial_to_parallel_code(format->format.code); > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c > index 117912d3bfbd..96353648c032 100644 > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c > @@ -319,7 +319,7 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp, > rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); > > src_fmt = v4l2_subdev_state_get_format(sd_state, > - RKISP1_ISP_PAD_SOURCE_VIDEO); > + RKISP1_ISP_PAD_SOURCE_VIDEO); > src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); > > if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER) > @@ -475,9 +475,9 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, > sink_fmt = v4l2_subdev_state_get_format(sd_state, > RKISP1_ISP_PAD_SINK_VIDEO); > src_fmt = v4l2_subdev_state_get_format(sd_state, > - RKISP1_ISP_PAD_SOURCE_VIDEO); > + RKISP1_ISP_PAD_SOURCE_VIDEO); > src_crop = v4l2_subdev_state_get_crop(sd_state, > - RKISP1_ISP_PAD_SOURCE_VIDEO); > + RKISP1_ISP_PAD_SOURCE_VIDEO); > > /* > * Media bus code. The ISP can operate in pass-through mode (Bayer in, Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 4 +- drivers/media/i2c/adv7183.c | 2 +- drivers/media/i2c/adv748x/adv748x-afe.c | 6 +- drivers/media/i2c/adv748x/adv748x-csi2.c | 2 +- drivers/media/i2c/adv748x/adv748x-hdmi.c | 6 +- drivers/media/i2c/adv7511-v4l2.c | 4 +- drivers/media/i2c/adv7604.c | 4 +- drivers/media/i2c/adv7842.c | 4 +- drivers/media/i2c/ar0521.c | 5 +- drivers/media/i2c/ccs/ccs-core.c | 22 ++-- drivers/media/i2c/et8ek8/et8ek8_driver.c | 3 +- drivers/media/i2c/hi556.c | 13 +-- drivers/media/i2c/hi846.c | 11 +- drivers/media/i2c/hi847.c | 9 +- drivers/media/i2c/imx208.c | 9 +- drivers/media/i2c/imx214.c | 4 +- drivers/media/i2c/imx219.c | 12 +- drivers/media/i2c/imx258.c | 9 +- drivers/media/i2c/imx274.c | 12 +- drivers/media/i2c/imx290.c | 8 +- drivers/media/i2c/imx296.c | 18 +-- drivers/media/i2c/imx319.c | 7 +- drivers/media/i2c/imx334.c | 4 +- drivers/media/i2c/imx335.c | 4 +- drivers/media/i2c/imx355.c | 7 +- drivers/media/i2c/imx412.c | 4 +- drivers/media/i2c/imx415.c | 6 +- drivers/media/i2c/isl7998x.c | 6 +- drivers/media/i2c/max9286.c | 4 +- drivers/media/i2c/mt9m001.c | 6 +- drivers/media/i2c/mt9m111.c | 6 +- drivers/media/i2c/mt9m114.c | 58 +++++----- drivers/media/i2c/mt9p031.c | 6 +- drivers/media/i2c/mt9t112.c | 2 +- drivers/media/i2c/mt9v011.c | 2 +- drivers/media/i2c/mt9v032.c | 10 +- drivers/media/i2c/mt9v111.c | 4 +- drivers/media/i2c/og01a1b.c | 10 +- drivers/media/i2c/ov01a10.c | 2 +- drivers/media/i2c/ov02a10.c | 6 +- drivers/media/i2c/ov08d10.c | 9 +- drivers/media/i2c/ov08x40.c | 7 +- drivers/media/i2c/ov13858.c | 10 +- drivers/media/i2c/ov13b10.c | 10 +- drivers/media/i2c/ov2640.c | 6 +- drivers/media/i2c/ov2659.c | 6 +- drivers/media/i2c/ov2680.c | 10 +- drivers/media/i2c/ov2685.c | 4 +- drivers/media/i2c/ov2740.c | 4 +- drivers/media/i2c/ov4689.c | 2 +- drivers/media/i2c/ov5640.c | 9 +- drivers/media/i2c/ov5645.c | 4 +- drivers/media/i2c/ov5647.c | 12 +- drivers/media/i2c/ov5648.c | 6 +- drivers/media/i2c/ov5670.c | 13 +-- drivers/media/i2c/ov5675.c | 9 +- drivers/media/i2c/ov5693.c | 4 +- drivers/media/i2c/ov5695.c | 8 +- drivers/media/i2c/ov6650.c | 12 +- drivers/media/i2c/ov7251.c | 4 +- drivers/media/i2c/ov7670.c | 7 +- drivers/media/i2c/ov772x.c | 2 +- drivers/media/i2c/ov7740.c | 7 +- drivers/media/i2c/ov8856.c | 9 +- drivers/media/i2c/ov8858.c | 6 +- drivers/media/i2c/ov8865.c | 8 +- drivers/media/i2c/ov9282.c | 6 +- drivers/media/i2c/ov9640.c | 2 +- drivers/media/i2c/ov9650.c | 7 +- drivers/media/i2c/ov9734.c | 9 +- drivers/media/i2c/rj54n1cb0c.c | 2 +- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 37 +++---- drivers/media/i2c/s5k5baf.c | 35 +++--- drivers/media/i2c/s5k6a3.c | 8 +- drivers/media/i2c/saa6752hs.c | 2 +- drivers/media/i2c/st-mipid02.c | 11 +- drivers/media/i2c/st-vgxy61.c | 5 +- drivers/media/i2c/tc358746.c | 12 +- drivers/media/i2c/tda1997x.c | 6 +- drivers/media/i2c/tvp5150.c | 2 +- drivers/media/i2c/tw9910.c | 2 +- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 10 +- drivers/media/pci/intel/ivsc/mei_csi.c | 4 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 4 +- drivers/media/platform/cadence/cdns-csi2tx.c | 3 +- .../platform/microchip/microchip-csi2dc.c | 15 ++- .../platform/microchip/microchip-isc-base.c | 2 +- .../platform/microchip/microchip-isc-scaler.c | 16 +-- drivers/media/platform/nxp/imx-mipi-csis.c | 10 +- drivers/media/platform/nxp/imx7-media-csi.c | 16 +-- .../platform/nxp/imx8-isi/imx8-isi-pipe.c | 18 +-- .../platform/nxp/imx8-isi/imx8-isi-video.c | 2 +- drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 13 ++- .../media/platform/qcom/camss/camss-csid.c | 3 +- .../media/platform/qcom/camss/camss-csiphy.c | 3 +- .../media/platform/qcom/camss/camss-ispif.c | 3 +- drivers/media/platform/qcom/camss/camss-vfe.c | 10 +- drivers/media/platform/renesas/rcar-isp.c | 4 +- .../platform/renesas/rcar-vin/rcar-csi2.c | 4 +- .../platform/renesas/rzg2l-cru/rzg2l-csi2.c | 6 +- .../platform/renesas/rzg2l-cru/rzg2l-ip.c | 6 +- .../media/platform/renesas/vsp1/vsp1_brx.c | 2 +- .../media/platform/renesas/vsp1/vsp1_entity.c | 8 +- .../media/platform/renesas/vsp1/vsp1_rwpf.c | 3 +- .../platform/rockchip/rkisp1/rkisp1-csi.c | 16 ++- .../platform/rockchip/rkisp1/rkisp1-isp.c | 103 +++++++++--------- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 53 ++++----- .../samsung/exynos4-is/fimc-capture.c | 12 +- .../platform/samsung/exynos4-is/fimc-isp.c | 24 ++-- .../platform/samsung/exynos4-is/fimc-lite.c | 16 ++- .../platform/samsung/exynos4-is/mipi-csis.c | 3 +- .../samsung/s3c-camif/camif-capture.c | 8 +- .../platform/sunxi/sun4i-csi/sun4i_v4l2.c | 8 +- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 8 +- .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 8 +- .../sun8i_a83t_mipi_csi2.c | 8 +- drivers/media/platform/ti/cal/cal-camerarx.c | 18 ++- drivers/media/platform/ti/cal/cal-video.c | 2 +- drivers/media/platform/ti/omap3isp/ispccdc.c | 7 +- drivers/media/platform/ti/omap3isp/ispccp2.c | 3 +- drivers/media/platform/ti/omap3isp/ispcsi2.c | 3 +- .../media/platform/ti/omap3isp/isppreview.c | 6 +- .../media/platform/ti/omap3isp/ispresizer.c | 5 +- drivers/media/platform/video-mux.c | 18 +-- .../media/platform/xilinx/xilinx-csi2rxss.c | 5 +- drivers/media/platform/xilinx/xilinx-tpg.c | 9 +- drivers/media/platform/xilinx/xilinx-vip.c | 4 +- .../media/test-drivers/vimc/vimc-debayer.c | 10 +- drivers/media/test-drivers/vimc/vimc-scaler.c | 9 +- drivers/media/test-drivers/vimc/vimc-sensor.c | 6 +- .../media/atomisp/i2c/atomisp-gc0310.c | 2 +- .../media/atomisp/i2c/atomisp-gc2235.c | 2 +- .../media/atomisp/i2c/atomisp-mt9m114.c | 2 +- .../media/atomisp/i2c/atomisp-ov2722.c | 2 +- .../staging/media/atomisp/pci/atomisp_csi2.c | 3 +- .../media/atomisp/pci/atomisp_subdev.c | 6 +- .../staging/media/atomisp/pci/atomisp_tpg.c | 2 +- .../media/deprecated/atmel/atmel-isc-base.c | 2 +- drivers/staging/media/imx/imx-ic-prp.c | 4 +- drivers/staging/media/imx/imx-ic-prpencvf.c | 4 +- drivers/staging/media/imx/imx-media-csi.c | 8 +- drivers/staging/media/imx/imx-media-utils.c | 2 +- drivers/staging/media/imx/imx-media-vdic.c | 2 +- drivers/staging/media/imx/imx6-mipi-csi2.c | 2 +- drivers/staging/media/ipu3/ipu3-v4l2.c | 14 +-- drivers/staging/media/omap4iss/iss_csi2.c | 3 +- drivers/staging/media/omap4iss/iss_ipipe.c | 3 +- drivers/staging/media/omap4iss/iss_ipipeif.c | 3 +- drivers/staging/media/omap4iss/iss_resizer.c | 3 +- .../staging/media/starfive/camss/stf-isp.c | 25 ++--- .../media/sunxi/sun6i-isp/sun6i_isp_proc.c | 8 +- drivers/staging/media/tegra-video/vi.c | 2 +- 153 files changed, 602 insertions(+), 696 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 54134473186b..444c322d756a 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -769,7 +769,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd, struct adv7180_state *state = to_state(sd); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); + format->format = *v4l2_subdev_state_get_format(sd_state, 0); } else { adv7180_mbus_fmt(sd, &format->format); format->format.field = state->field; @@ -806,7 +806,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, adv7180_set_power(state, true); } } else { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + framefmt = v4l2_subdev_state_get_format(sd_state, 0); *framefmt = format->format; } diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 0754bfefa073..bcb99ba9a272 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -443,7 +443,7 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) decoder->fmt = *fmt; else - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; return 0; } diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index 00095c7762c2..50d9fbadbe38 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -354,8 +354,8 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd, return -EINVAL; if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { - mbusformat = v4l2_subdev_get_try_format(sd, sd_state, - sdformat->pad); + mbusformat = v4l2_subdev_state_get_format(sd_state, + sdformat->pad); sdformat->format = *mbusformat; } else { adv748x_afe_fill_format(afe, &sdformat->format); @@ -378,7 +378,7 @@ static int adv748x_afe_set_format(struct v4l2_subdev *sd, if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) return adv748x_afe_get_format(sd, sd_state, sdformat); - mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad); + mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); *mbusformat = sdformat->format; return 0; diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index a5a7cb228896..5b265b722394 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -147,7 +147,7 @@ adv748x_csi2_get_pad_format(struct v4l2_subdev *sd, struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &tx->format; } diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index 400d71c2745c..ec151dc69c23 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -441,8 +441,8 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd, return -EINVAL; if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { - mbusformat = v4l2_subdev_get_try_format(sd, sd_state, - sdformat->pad); + mbusformat = v4l2_subdev_state_get_format(sd_state, + sdformat->pad); sdformat->format = *mbusformat; } else { adv748x_hdmi_fill_format(hdmi, &sdformat->format); @@ -464,7 +464,7 @@ static int adv748x_hdmi_set_format(struct v4l2_subdev *sd, if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) return adv748x_hdmi_get_format(sd, sd_state, sdformat); - mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad); + mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); *mbusformat = sdformat->format; return 0; diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index a9183d9282fd..0f780eb6ef63 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -1238,7 +1238,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); format->format.code = fmt->code; format->format.colorspace = fmt->colorspace; format->format.ycbcr_enc = fmt->ycbcr_enc; @@ -1293,7 +1293,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); fmt->code = format->format.code; fmt->colorspace = format->format.colorspace; fmt->ycbcr_enc = format->format.ycbcr_enc; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index b202a85fbeaa..810fa8826f30 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1929,7 +1929,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); format->format.code = fmt->code; } else { format->format.code = state->format->code; @@ -1978,7 +1978,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); fmt->code = format->format.code; } else { state->format = info; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index c1664a3620c8..2ad0f9f5503d 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2087,7 +2087,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); format->format.code = fmt->code; } else { format->format.code = state->format->code; @@ -2119,7 +2119,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); fmt->code = format->format.code; } else { state->format = info; diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index 701f36345f1e..c7d5fa532ae1 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -446,8 +446,7 @@ static int ar0521_get_fmt(struct v4l2_subdev *sd, mutex_lock(&sensor->lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 0 - /* pad */); + fmt = v4l2_subdev_state_get_format(sd_state, 0); else fmt = &sensor->fmt; @@ -472,7 +471,7 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, 0 /* pad */); + fmt = v4l2_subdev_state_get_format(sd_state, 0); *fmt = format->format; mutex_unlock(&sensor->lock); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 31769ff95d67..fb713b03ad4a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2032,7 +2032,7 @@ static int __ccs_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - fmt->format = *v4l2_subdev_get_pad_format(subdev, sd_state, fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); return 0; @@ -2063,10 +2063,10 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev, if (crops) for (i = 0; i < subdev->entity.num_pads; i++) crops[i] = - v4l2_subdev_get_pad_crop(subdev, sd_state, i); + v4l2_subdev_state_get_crop(sd_state, i); if (comps) - *comps = v4l2_subdev_get_pad_compose(subdev, sd_state, - ssd->sink_pad); + *comps = v4l2_subdev_state_get_compose(sd_state, + ssd->sink_pad); } /* Changes require propagation only on sink pad. */ @@ -2099,7 +2099,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, fallthrough; case V4L2_SEL_TGT_COMPOSE: *crops[CCS_PAD_SRC] = *comp; - fmt = v4l2_subdev_get_pad_format(subdev, sd_state, CCS_PAD_SRC); + fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC); fmt->width = comp->width; fmt->height = comp->height; if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src) @@ -2509,7 +2509,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, if (sel->pad == ssd->sink_pad) { struct v4l2_mbus_framefmt *mfmt = - v4l2_subdev_get_pad_format(subdev, sd_state, sel->pad); + v4l2_subdev_state_get_format(sd_state, sel->pad); src_size.width = mfmt->width; src_size.height = mfmt->height; @@ -2569,8 +2569,8 @@ static int ccs_get_selection(struct v4l2_subdev *subdev, ccs_get_native_size(ssd, &sel->r); } else if (sel->pad == ssd->sink_pad) { struct v4l2_mbus_framefmt *sink_fmt = - v4l2_subdev_get_pad_format(subdev, sd_state, - ssd->sink_pad); + v4l2_subdev_state_get_format(sd_state, + ssd->sink_pad); sel->r.top = sel->r.left = 0; sel->r.width = sink_fmt->width; sel->r.height = sink_fmt->height; @@ -3014,9 +3014,9 @@ static int ccs_init_cfg(struct v4l2_subdev *sd, unsigned int pad = ssd == sensor->pixel_array ? CCS_PA_PAD_SRC : CCS_PAD_SINK; struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_pad_format(sd, sd_state, pad); + v4l2_subdev_state_get_format(sd_state, pad); struct v4l2_rect *crop = - v4l2_subdev_get_pad_crop(sd, sd_state, pad); + v4l2_subdev_state_get_crop(sd_state, pad); bool is_active = !sd->active_state || sd->active_state == sd_state; mutex_lock(&sensor->mutex); @@ -3036,7 +3036,7 @@ static int ccs_init_cfg(struct v4l2_subdev *sd, return 0; } - fmt = v4l2_subdev_get_pad_format(sd, sd_state, CCS_PAD_SRC); + fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC); fmt->code = ssd == sensor->src ? sensor->csi_format->code : sensor->internal_csi_format->code; fmt->field = V4L2_FIELD_NONE; diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index d6fc843f9368..63616dc5a02f 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -995,8 +995,7 @@ __et8ek8_get_pad_format(struct et8ek8_sensor *sensor, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&sensor->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &sensor->format; default: diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index f6ea9b7b9700..38c77d515786 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -935,7 +935,7 @@ __hi556_get_pad_crop(struct hi556 *hi556, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &hi556->cur_mode->crop; } @@ -1075,7 +1075,7 @@ static int hi556_set_format(struct v4l2_subdev *sd, mutex_lock(&hi556->mutex); hi556_assign_pad_format(mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { hi556->cur_mode = mode; __v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index); @@ -1109,9 +1109,8 @@ static int hi556_get_format(struct v4l2_subdev *sd, mutex_lock(&hi556->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&hi556->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else hi556_assign_pad_format(hi556->cur_mode, &fmt->format); @@ -1157,10 +1156,10 @@ static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&hi556->mutex); hi556_assign_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); /* Initialize try_crop rectangle. */ - try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0); + try_crop = v4l2_subdev_state_get_crop(fh->state, 0); try_crop->top = HI556_PIXEL_ARRAY_TOP; try_crop->left = HI556_PIXEL_ARRAY_LEFT; try_crop->width = HI556_PIXEL_ARRAY_WIDTH; diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 825fc8dc48f5..0595080c2211 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1705,7 +1705,7 @@ static int hi846_set_format(struct v4l2_subdev *sd, } if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = *mf; + *v4l2_subdev_state_get_format(sd_state, format->pad) = *mf; return 0; } @@ -1783,9 +1783,8 @@ static int hi846_get_format(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(&hi846->sd, - sd_state, - format->pad); + format->format = *v4l2_subdev_state_get_format(sd_state, + format->pad); return 0; } @@ -1852,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd, mutex_lock(&hi846->mutex); switch (sel->which) { case V4L2_SUBDEV_FORMAT_TRY: - v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + v4l2_subdev_state_get_crop(sd_state, sel->pad); break; case V4L2_SUBDEV_FORMAT_ACTIVE: sel->r = hi846->cur_mode->crop; @@ -1878,7 +1877,7 @@ static int hi846_init_cfg(struct v4l2_subdev *sd, struct hi846 *hi846 = to_hi846(sd); struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); mutex_lock(&hi846->mutex); mf->code = HI846_MEDIA_BUS_FORMAT; diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 4075c389804c..72c60747a839 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -2655,7 +2655,7 @@ static int hi847_set_format(struct v4l2_subdev *sd, mutex_lock(&hi847->mutex); hi847_assign_pad_format(mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { hi847->cur_mode = mode; @@ -2690,9 +2690,8 @@ static int hi847_get_format(struct v4l2_subdev *sd, mutex_lock(&hi847->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&hi847->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else hi847_assign_pad_format(hi847->cur_mode, &fmt->format); @@ -2737,7 +2736,7 @@ static int hi847_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&hi847->mutex); hi847_assign_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&hi847->mutex); return 0; diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index a9b0aea1ae3b..639e05340dbb 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -395,7 +395,7 @@ static int imx208_write_regs(struct imx208 *imx208, static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); /* Initialize try_fmt */ try_fmt->width = supported_modes[0].width; @@ -548,9 +548,8 @@ static int __imx208_get_pad_format(struct imx208 *imx208, struct v4l2_subdev_format *fmt) { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&imx208->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else imx208_mode_to_pad_format(imx208, imx208->cur_mode, fmt); @@ -591,7 +590,7 @@ static int imx208_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx208_mode_to_pad_format(imx208, mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { imx208->cur_mode = mode; __v4l2_ctrl_s_ctrl(imx208->link_freq, mode->link_freq_index); diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 4f77ea02cc27..8bc7b114c57d 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -538,7 +538,7 @@ __imx214_get_pad_format(struct imx214 *imx214, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&imx214->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &imx214->fmt; default: @@ -568,7 +568,7 @@ __imx214_get_pad_crop(struct imx214 *imx214, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&imx214->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &imx214->crop; default: diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 8436880dcf7a..675795ac2e83 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -374,7 +374,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) int ret = 0; state = v4l2_subdev_get_locked_active_state(&imx219->sd); - format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max, exposure_def; @@ -593,8 +593,8 @@ static int imx219_set_framefmt(struct imx219 *imx219, u64 bin_h, bin_v; int ret = 0; - format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); - crop = v4l2_subdev_get_pad_crop(&imx219->sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: @@ -826,7 +826,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); - format = v4l2_subdev_get_pad_format(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); *format = fmt->format; /* @@ -836,7 +836,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); - crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); crop->width = format->width * bin_h; crop->height = format->height * bin_v; crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; @@ -880,7 +880,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd, { switch (sel->target) { case V4L2_SEL_TGT_CROP: { - sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + sel->r = *v4l2_subdev_state_get_crop(state, 0); return 0; } diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index b3827f4bc0eb..a577afb530b7 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -708,7 +708,7 @@ static int imx258_write_regs(struct imx258 *imx258, static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); /* Initialize try_fmt */ try_fmt->width = supported_modes[0].width; @@ -862,9 +862,8 @@ static int __imx258_get_pad_format(struct imx258 *imx258, struct v4l2_subdev_format *fmt) { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&imx258->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else imx258_update_pad_format(imx258->cur_mode, fmt); @@ -908,7 +907,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx258_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { imx258->cur_mode = mode; diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 1886eaab1c24..8dc11c9ec1ee 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1018,8 +1018,8 @@ static int __imx274_change_compose(struct stimx274 *imx274, int best_goodness = INT_MIN; if (which == V4L2_SUBDEV_FORMAT_TRY) { - cur_crop = v4l2_subdev_get_pad_crop(&imx274->sd, sd_state, 0); - tgt_fmt = v4l2_subdev_get_pad_format(&imx274->sd, sd_state, 0); + cur_crop = v4l2_subdev_state_get_crop(sd_state, 0); + tgt_fmt = v4l2_subdev_state_get_format(sd_state, 0); } else { cur_crop = &imx274->crop; tgt_fmt = &imx274->format; @@ -1112,7 +1112,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd, */ fmt->field = V4L2_FIELD_NONE; if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; else imx274->format = *fmt; @@ -1143,8 +1143,8 @@ static int imx274_get_selection(struct v4l2_subdev *sd, } if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - src_crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, 0); + src_crop = v4l2_subdev_state_get_crop(sd_state, 0); + src_fmt = v4l2_subdev_state_get_format(sd_state, 0); } else { src_crop = &imx274->crop; src_fmt = &imx274->format; @@ -1215,7 +1215,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274, sel->r = new_crop; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) - tgt_crop = v4l2_subdev_get_pad_crop(&imx274->sd, sd_state, 0); + tgt_crop = v4l2_subdev_state_get_crop(sd_state, 0); else tgt_crop = &imx274->crop; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 29098612813c..aa8cfbcd40aa 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -758,7 +758,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) return 0; state = v4l2_subdev_get_locked_active_state(&imx290->sd); - format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: @@ -994,7 +994,7 @@ static int imx290_start_streaming(struct imx290 *imx290, } /* Apply the register values related to current frame format */ - format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); ret = imx290_setup_format(imx290, format); if (ret < 0) { dev_err(imx290->dev, "Could not set frame format - %d\n", ret); @@ -1132,7 +1132,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; - format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + format = v4l2_subdev_state_get_format(sd_state, 0); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx290->current_mode = mode; @@ -1155,7 +1155,7 @@ static int imx290_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: { - format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + format = v4l2_subdev_state_get_format(sd_state, 0); /* * The sensor moves the readout by 1 pixel based on flips to diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index 94aac9d2732f..8399cca496a7 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -323,7 +323,7 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); - format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + format = v4l2_subdev_state_get_format(state, 0); switch (ctrl->id) { case V4L2_CID_EXPOSURE: @@ -511,8 +511,8 @@ static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state) unsigned int i; int ret = 0; - format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); - crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0); + format = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i) imx296_write(sensor, imx296_init_table[i].reg, @@ -662,7 +662,7 @@ static int imx296_enum_frame_size(struct v4l2_subdev *sd, { const struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + format = v4l2_subdev_state_get_format(state, fse->pad); if (fse->index >= 2 || fse->code != format->code) return -EINVAL; @@ -683,8 +683,8 @@ static int imx296_set_format(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); - format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + crop = v4l2_subdev_state_get_crop(state, fmt->pad); + format = v4l2_subdev_state_get_format(state, fmt->pad); /* * Binning is only allowed when cropping is disabled according to the @@ -732,7 +732,7 @@ static int imx296_get_selection(struct v4l2_subdev *sd, { switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(state, sel->pad); break; case V4L2_SEL_TGT_CROP_DEFAULT: @@ -780,14 +780,14 @@ static int imx296_set_selection(struct v4l2_subdev *sd, rect.height = min_t(unsigned int, rect.height, IMX296_PIXEL_ARRAY_HEIGHT - rect.top); - crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + crop = v4l2_subdev_state_get_crop(state, sel->pad); if (rect.width != crop->width || rect.height != crop->height) { /* * Reset the output image size if the crop rectangle size has * been modified. */ - format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + format = v4l2_subdev_state_get_format(state, sel->pad); format->width = rect.width; format->height = rect.height; } diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 5378f607f340..420984382173 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -1860,7 +1860,7 @@ static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct imx319 *imx319 = to_imx319(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); mutex_lock(&imx319->mutex); @@ -2001,10 +2001,9 @@ static int imx319_do_get_pad_format(struct imx319 *imx319, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &imx319->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx319_update_pad_format(imx319, imx319->cur_mode, fmt); @@ -2055,7 +2054,7 @@ imx319_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx319_update_pad_format(imx319, mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { imx319->cur_mode = mode; diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 404d0f1dffcd..42cf71c1f6fd 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -879,7 +879,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { fmt->format.code = imx334->cur_code; @@ -920,7 +920,7 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else if (imx334->cur_mode != mode || imx334->cur_code != fmt->format.code) { imx334->cur_code = fmt->format.code; diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 01c871c1ab61..0432f059e913 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -569,7 +569,7 @@ static int imx335_get_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx335_fill_pad_format(imx335, imx335->cur_mode, fmt); @@ -604,7 +604,7 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ret = imx335_update_controls(imx335, mode); diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 9c58c1a80cba..e1b1d2fc79dd 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1158,7 +1158,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct imx355 *imx355 = to_imx355(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); mutex_lock(&imx355->mutex); @@ -1299,10 +1299,9 @@ static int imx355_do_get_pad_format(struct imx355 *imx355, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &imx355->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx355_update_pad_format(imx355, imx355->cur_mode, fmt); @@ -1353,7 +1352,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx355_update_pad_format(imx355, mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { imx355->cur_mode = mode; diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index dd5cf7f20310..41d756a20f3c 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -721,7 +721,7 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx412_fill_pad_format(imx412, imx412->cur_mode, fmt); @@ -756,7 +756,7 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ret = imx412_update_controls(imx412, mode); diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index b3fa71a16839..6436a32c4025 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -546,7 +546,7 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); - format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + format = v4l2_subdev_state_get_format(state, 0); switch (ctrl->id) { case V4L2_CID_EXPOSURE: @@ -828,7 +828,7 @@ static int imx415_enum_frame_size(struct v4l2_subdev *sd, { const struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + format = v4l2_subdev_state_get_format(state, fse->pad); if (fse->index > 0 || fse->code != format->code) return -EINVAL; @@ -846,7 +846,7 @@ static int imx415_set_format(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + format = v4l2_subdev_state_get_format(state, fmt->pad); format->width = fmt->format.width; format->height = fmt->format.height; diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c index 73460688c356..89e13ebbce0c 100644 --- a/drivers/media/i2c/isl7998x.c +++ b/drivers/media/i2c/isl7998x.c @@ -1007,8 +1007,8 @@ static int isl7998x_get_fmt(struct v4l2_subdev *sd, mutex_lock(&isl7998x->lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(sd, sd_state, - format->pad); + format->format = *v4l2_subdev_state_get_format(sd_state, + format->pad); goto out; } @@ -1044,7 +1044,7 @@ static int isl7998x_set_fmt(struct v4l2_subdev *sd, mf->field = mode->field; if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = format->format; + *v4l2_subdev_state_get_format(sd_state, format->pad) = format->format; mutex_unlock(&isl7998x->lock); diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index fc1cf196ef01..ee11ae682d8d 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -913,7 +913,7 @@ max9286_get_pad_format(struct max9286_priv *priv, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &priv->fmt[pad]; default: @@ -1020,7 +1020,7 @@ static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) unsigned int i; for (i = 0; i < MAX9286_N_SINKS; i++) { - format = v4l2_subdev_get_try_format(subdev, fh->state, i); + format = v4l2_subdev_state_get_format(fh->state, i); max9286_init_format(format); } diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 5c137fc2034e..4c897bb07fed 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -325,7 +325,7 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); format->format = *mf; return 0; } @@ -405,7 +405,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9m001_s_fmt(sd, fmt, mf); - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } @@ -656,7 +656,7 @@ static int mt9m001_init_cfg(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); try_fmt->width = MT9M001_MAX_WIDTH; try_fmt->height = MT9M001_MAX_HEIGHT; diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index e17ff41ebba0..17ca92810b58 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -525,7 +525,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + mf = v4l2_subdev_state_get_format(sd_state, format->pad); format->format = *mf; return 0; } @@ -671,7 +671,7 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd, mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } @@ -1115,7 +1115,7 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *format = - v4l2_subdev_get_try_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); format->width = MT9M111_MAX_WIDTH; format->height = MT9M111_MAX_HEIGHT; diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index ac19078ceda3..23cf84f1a746 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -796,13 +796,13 @@ static int mt9m114_configure(struct mt9m114 *sensor, u64 read_mode; int ret = 0; - pa_format = v4l2_subdev_get_pad_format(&sensor->pa.sd, pa_state, 0); - pa_crop = v4l2_subdev_get_pad_crop(&sensor->pa.sd, pa_state, 0); + pa_format = v4l2_subdev_state_get_format(pa_state, 0); + pa_crop = v4l2_subdev_state_get_crop(pa_state, 0); - ifp_format = v4l2_subdev_get_pad_format(&sensor->ifp.sd, ifp_state, 1); + ifp_format = v4l2_subdev_state_get_format(ifp_state, 1); ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code); - ifp_crop = v4l2_subdev_get_pad_crop(&sensor->ifp.sd, ifp_state, 0); - ifp_compose = v4l2_subdev_get_pad_compose(&sensor->ifp.sd, ifp_state, 0); + ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0); + ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0); ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, &read_mode, NULL); @@ -1045,7 +1045,7 @@ static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->pa.sd); - format = v4l2_subdev_get_pad_format(&sensor->pa.sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); switch (ctrl->id) { case V4L2_CID_HBLANK: @@ -1158,14 +1158,14 @@ static int mt9m114_pa_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); crop->left = 0; crop->top = 0; crop->width = MT9M114_PIXEL_ARRAY_WIDTH; crop->height = MT9M114_PIXEL_ARRAY_HEIGHT; - format = v4l2_subdev_get_pad_format(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); format->width = MT9M114_PIXEL_ARRAY_WIDTH; format->height = MT9M114_PIXEL_ARRAY_HEIGHT; @@ -1220,8 +1220,8 @@ static int mt9m114_pa_set_fmt(struct v4l2_subdev *sd, unsigned int hscale; unsigned int vscale; - crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); - format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + crop = v4l2_subdev_state_get_crop(state, fmt->pad); + format = v4l2_subdev_state_get_format(state, fmt->pad); /* The sensor can bin horizontally and vertically. */ hscale = DIV_ROUND_CLOSEST(crop->width, fmt->format.width ? : 1); @@ -1243,7 +1243,7 @@ static int mt9m114_pa_get_selection(struct v4l2_subdev *sd, { switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(state, sel->pad); return 0; case V4L2_SEL_TGT_CROP_DEFAULT: @@ -1271,8 +1271,8 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); - format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + crop = v4l2_subdev_state_get_crop(state, sel->pad); + format = v4l2_subdev_state_get_format(state, sel->pad); /* * Clamp the crop rectangle. The vertical coordinates must be even, and @@ -1402,7 +1402,7 @@ static int mt9m114_pa_init(struct mt9m114 *sensor) /* Update the range of the blanking controls based on the format. */ state = v4l2_subdev_lock_and_get_active_state(sd); - format = v4l2_subdev_get_pad_format(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); mt9m114_pa_ctrl_update_blanking(sensor, format); v4l2_subdev_unlock_state(state); @@ -1632,7 +1632,7 @@ static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd, struct v4l2_rect *crop; struct v4l2_rect *compose; - format = v4l2_subdev_get_pad_format(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); format->width = MT9M114_PIXEL_ARRAY_WIDTH; format->height = MT9M114_PIXEL_ARRAY_HEIGHT; @@ -1643,21 +1643,21 @@ static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd, format->quantization = V4L2_QUANTIZATION_FULL_RANGE; format->xfer_func = V4L2_XFER_FUNC_NONE; - crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); crop->left = 4; crop->top = 4; crop->width = format->width - 8; crop->height = format->height - 8; - compose = v4l2_subdev_get_pad_compose(sd, state, 0); + compose = v4l2_subdev_state_get_compose(state, 0); compose->left = 0; compose->top = 0; compose->width = crop->width; compose->height = crop->height; - format = v4l2_subdev_get_pad_format(sd, state, 1); + format = v4l2_subdev_state_get_format(state, 1); format->width = compose->width; format->height = compose->height; @@ -1738,7 +1738,7 @@ static int mt9m114_ifp_enum_framesizes(struct v4l2_subdev *sd, } else { const struct v4l2_rect *crop; - crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); fse->max_width = crop->width; fse->max_height = crop->height; @@ -1777,7 +1777,7 @@ static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd, struct mt9m114 *sensor = ifp_to_mt9m114(sd); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + format = v4l2_subdev_state_get_format(state, fmt->pad); if (fmt->pad == 0) { /* Only the size can be changed on the sink pad. */ @@ -1797,7 +1797,7 @@ static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd, /* If the output format is RAW10, bypass the scaler. */ if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10) - *format = *v4l2_subdev_get_pad_format(sd, state, 0); + *format = *v4l2_subdev_state_get_format(state, 0); } fmt->format = *format; @@ -1819,7 +1819,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + sel->r = *v4l2_subdev_state_get_crop(state, 0); break; case V4L2_SEL_TGT_CROP_DEFAULT: @@ -1828,7 +1828,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, * The crop default and bounds are equal to the sink * format size minus 4 pixels on each side for demosaicing. */ - format = v4l2_subdev_get_pad_format(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); sel->r.left = 4; sel->r.top = 4; @@ -1837,7 +1837,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, break; case V4L2_SEL_TGT_COMPOSE: - sel->r = *v4l2_subdev_get_pad_compose(sd, state, 0); + sel->r = *v4l2_subdev_state_get_compose(state, 0); break; case V4L2_SEL_TGT_COMPOSE_DEFAULT: @@ -1846,7 +1846,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, * The compose default and bounds sizes are equal to the sink * crop rectangle size. */ - crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); sel->r.left = 0; sel->r.top = 0; sel->r.width = crop->width; @@ -1877,9 +1877,9 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd, if (sel->pad != 0) return -EINVAL; - format = v4l2_subdev_get_pad_format(sd, state, 0); - crop = v4l2_subdev_get_pad_crop(sd, state, 0); - compose = v4l2_subdev_get_pad_compose(sd, state, 0); + format = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); + compose = v4l2_subdev_state_get_compose(state, 0); if (sel->target == V4L2_SEL_TGT_CROP) { /* @@ -1921,7 +1921,7 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd, } /* Propagate the compose rectangle to the source format. */ - format = v4l2_subdev_get_pad_format(sd, state, 1); + format = v4l2_subdev_state_get_format(state, 1); format->width = compose->width; format->height = compose->height; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 348f1e1098fb..89bcd48748b9 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -549,8 +549,7 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&mt9p031->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->format; default: @@ -565,8 +564,7 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&mt9p031->subdev, sd_state, - pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->crop; default: diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index e3b9ff374500..2e2d9853c089 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -982,7 +982,7 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9t112_s_fmt(sd, mf); - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 7f313d731839..d0924b4ac6fb 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -356,7 +356,7 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd, set_res(sd); } else { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; } return 0; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 1c6f6cea1204..3ca76eeae7ff 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -356,8 +356,7 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&mt9v032->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->format; default: @@ -372,8 +371,7 @@ __mt9v032_get_pad_crop(struct mt9v032 *mt9v032, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&mt9v032->subdev, sd_state, - pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->crop; default: @@ -931,13 +929,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0); + crop = v4l2_subdev_state_get_crop(fh->state, 0); crop->left = MT9V032_COLUMN_START_DEF; crop->top = MT9V032_ROW_START_DEF; crop->width = MT9V032_WINDOW_WIDTH_DEF; crop->height = MT9V032_WINDOW_HEIGHT_DEF; - format = v4l2_subdev_get_try_format(subdev, fh->state, 0); + format = v4l2_subdev_state_get_format(fh->state, 0); if (mt9v032->model->color) format->code = MEDIA_BUS_FMT_SGRBG10_1X10; diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 2c321e4884be..6752582cb2c7 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -795,7 +795,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format( { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v111->fmt; default: @@ -951,7 +951,7 @@ static int mt9v111_set_format(struct v4l2_subdev *subdev, static int mt9v111_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - *v4l2_subdev_get_pad_format(subdev, sd_state, 0) = mt9v111_def_fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = mt9v111_def_fmt; return 0; } diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 51378ba16a5d..bac9597faf68 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -769,8 +769,7 @@ static int og01a1b_set_format(struct v4l2_subdev *sd, mutex_lock(&og01a1b->mutex); og01a1b_update_pad_format(mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { og01a1b->cur_mode = mode; __v4l2_ctrl_s_ctrl(og01a1b->link_freq, mode->link_freq_index); @@ -803,9 +802,8 @@ static int og01a1b_get_format(struct v4l2_subdev *sd, mutex_lock(&og01a1b->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&og01a1b->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else og01a1b_update_pad_format(og01a1b->cur_mode, &fmt->format); @@ -850,7 +848,7 @@ static int og01a1b_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&og01a1b->mutex); og01a1b_update_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&og01a1b->mutex); return 0; diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index bbd5740d2280..c72280bb1f5b 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -723,7 +723,7 @@ static int ov01a10_set_format(struct v4l2_subdev *sd, h_blank); } - format = v4l2_subdev_get_pad_format(sd, sd_state, fmt->stream); + format = v4l2_subdev_state_get_format(sd_state, fmt->stream); *format = fmt->format; return 0; diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 848e47a464ac..8454cb39a47b 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -315,7 +315,7 @@ static int ov02a10_set_fmt(struct v4l2_subdev *sd, ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - frame_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + frame_fmt = v4l2_subdev_state_get_format(sd_state, 0); else frame_fmt = &ov02a10->fmt; @@ -336,8 +336,8 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd, mutex_lock(&ov02a10->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); } else { fmt->format = ov02a10->fmt; mbus_fmt->code = ov02a10->fmt.code; diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index 3d49e3fa8e56..1bacbdfa4298 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -1145,7 +1145,7 @@ static int ov08d10_set_format(struct v4l2_subdev *sd, mutex_lock(&ov08d10->mutex); ov08d10_update_pad_format(ov08d10, mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov08d10->cur_mode = mode; @@ -1184,9 +1184,8 @@ static int ov08d10_get_format(struct v4l2_subdev *sd, mutex_lock(&ov08d10->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov08d10->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else ov08d10_update_pad_format(ov08d10, ov08d10->cur_mode, &fmt->format); @@ -1242,7 +1241,7 @@ static int ov08d10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov08d10->mutex); ov08d10_update_pad_format(ov08d10, &ov08d10->priv_lane->sp_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&ov08d10->mutex); return 0; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index b41b6866a0ab..abbb0b774d43 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -2536,7 +2536,7 @@ static int ov08x40_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) const struct ov08x40_mode *default_mode = &supported_modes[0]; struct ov08x40 *ov08x = to_ov08x40(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); mutex_lock(&ov08x->mutex); @@ -2774,10 +2774,9 @@ static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &ov08x->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { ov08x40_update_pad_format(ov08x->cur_mode, fmt); @@ -2826,7 +2825,7 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); ov08x40_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ov08x->cur_mode = mode; diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 4c419014dd7b..09387e335d80 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1147,9 +1147,8 @@ static int ov13858_write_reg_list(struct ov13858 *ov13858, static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov13858 *ov13858 = to_ov13858(sd); - struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, - fh->state, - 0); + struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state, + 0); mutex_lock(&ov13858->mutex); @@ -1317,10 +1316,9 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &ov13858->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { ov13858_update_pad_format(ov13858->cur_mode, fmt); @@ -1369,7 +1367,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); ov13858_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ov13858->cur_mode = mode; diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index 970d2caeb3d6..c06411d5ee2b 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -755,9 +755,8 @@ static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { const struct ov13b10_mode *default_mode = &supported_modes[0]; struct ov13b10 *ov13b = to_ov13b10(sd); - struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, - fh->state, - 0); + struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state, + 0); mutex_lock(&ov13b->mutex); @@ -1002,10 +1001,9 @@ static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &ov13b->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { ov13b10_update_pad_format(ov13b->cur_mode, fmt); @@ -1054,7 +1052,7 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); ov13b10_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ov13b->cur_mode = mode; diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 389b6119ddec..28911d5169f7 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -920,7 +920,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); format->format = *mf; return 0; } @@ -988,7 +988,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, /* select format */ priv->cfmt_code = mf->code; } else { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; } out: mutex_unlock(&priv->lock); @@ -1000,7 +1000,7 @@ static int ov2640_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); const struct ov2640_win_size *win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 2c3dbe164eb6..1d0ef72a6403 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1033,7 +1033,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); mutex_lock(&ov2659->lock); fmt->format = *mf; mutex_unlock(&ov2659->lock); @@ -1109,7 +1109,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mutex_lock(&ov2659->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; } else { s64 val; @@ -1304,7 +1304,7 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); dev_dbg(&client->dev, "%s:\n", __func__); diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index f58fa2eb86ee..9b53ea9af45a 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -309,7 +309,7 @@ __ov2680_get_pad_format(struct ov2680_dev *sensor, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&sensor->sd, state, pad); + return v4l2_subdev_state_get_format(state, pad); return &sensor->mode.fmt; } @@ -321,7 +321,7 @@ __ov2680_get_pad_crop(struct ov2680_dev *sensor, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&sensor->sd, state, pad); + return v4l2_subdev_state_get_crop(state, pad); return &sensor->mode.crop; } @@ -650,7 +650,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, ov2680_fill_format(sensor, &format->format, width, height); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + try_fmt = v4l2_subdev_state_get_format(sd_state, 0); *try_fmt = format->format; return 0; } @@ -760,9 +760,9 @@ static int ov2680_init_cfg(struct v4l2_subdev *sd, { struct ov2680_dev *sensor = to_ov2680_dev(sd); - *v4l2_subdev_get_pad_crop(sd, sd_state, 0) = ov2680_default_crop; + *v4l2_subdev_state_get_crop(sd_state, 0) = ov2680_default_crop; - ov2680_fill_format(sensor, v4l2_subdev_get_pad_format(sd, sd_state, 0), + ov2680_fill_format(sensor, v4l2_subdev_state_get_format(sd_state, 0), OV2680_DEFAULT_WIDTH, OV2680_DEFAULT_HEIGHT); return 0; } diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 396583826ae9..9b8481b8dcd4 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -404,7 +404,7 @@ __ov2685_get_pad_crop(struct ov2685 *ov2685, switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov2685->subdev, state, pad); + return v4l2_subdev_state_get_crop(state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return mode->analog_crop; } @@ -547,7 +547,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov2685->mutex); - try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0); + try_fmt = v4l2_subdev_state_get_format(fh->state, 0); /* Initialize try_fmt */ ov2685_fill_fmt(&supported_modes[0], try_fmt); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 24e468485fbf..23cbd8b7846e 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -826,7 +826,7 @@ static int ov2740_set_format(struct v4l2_subdev *sd, fmt->format.height); ov2740_update_pad_format(mode, &fmt->format); - *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) return 0; @@ -883,7 +883,7 @@ static int ov2740_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { ov2740_update_pad_format(&supported_modes[0], - v4l2_subdev_get_pad_format(sd, sd_state, 0)); + v4l2_subdev_state_get_format(sd_state, 0)); return 0; } diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index 3bd972a822e7..403091651885 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -570,7 +570,7 @@ static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov4689->mutex); - try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0); + try_fmt = v4l2_subdev_state_get_format(fh->state, 0); /* Initialize try_fmt */ ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt); diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 40532f7bcabe..3f79a3b77044 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2797,8 +2797,7 @@ static int ov5640_get_fmt(struct v4l2_subdev *sd, mutex_lock(&sensor->lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, - format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); else fmt = &sensor->fmt; @@ -2971,7 +2970,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, goto out; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *mbus_fmt; goto out; } @@ -3750,8 +3749,8 @@ static int ov5640_init_cfg(struct v4l2_subdev *sd, { struct ov5640_dev *sensor = to_ov5640_dev(sd); struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(sd, state, 0); - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); + v4l2_subdev_state_get_format(state, 0); + struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : ov5640_dvp_default_fmt; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index a70db7e601a4..695f4f673536 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -851,7 +851,7 @@ __ov5645_get_pad_format(struct ov5645 *ov5645, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&ov5645->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov5645->fmt; default: @@ -878,7 +878,7 @@ __ov5645_get_pad_crop(struct ov5645 *ov5645, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov5645->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov5645->crop; default: diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index dcfe3129c63a..96c0fd4ff5ab 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -882,7 +882,7 @@ __ov5647_get_pad_crop(struct ov5647 *ov5647, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov5647->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov5647->mode->crop; } @@ -975,8 +975,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd, mutex_lock(&sensor->lock); switch (format->which) { case V4L2_SUBDEV_FORMAT_TRY: - sensor_format = v4l2_subdev_get_try_format(sd, sd_state, - format->pad); + sensor_format = v4l2_subdev_state_get_format(sd_state, + format->pad); break; default: sensor_format = &sensor->mode->format; @@ -1004,7 +1004,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, /* Update the sensor mode and apply at it at streamon time. */ mutex_lock(&sensor->lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = mode->format; + *v4l2_subdev_state_get_format(sd_state, format->pad) = mode->format; } else { int exposure_max, exposure_def; int hblank, vblank; @@ -1121,8 +1121,8 @@ static int ov5647_detect(struct v4l2_subdev *sd) static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *format = - v4l2_subdev_get_try_format(sd, fh->state, 0); - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); + struct v4l2_rect *crop = v4l2_subdev_state_get_crop(fh->state, 0); crop->left = OV5647_PIXEL_ARRAY_LEFT; crop->top = OV5647_PIXEL_ARRAY_TOP; diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index aa10eb4e3991..13e6060d15d4 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -2232,8 +2232,8 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev, mutex_lock(&sensor->mutex); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(sd_state, + format->pad); else ov5648_mbus_format_fill(mbus_format, sensor->state.mbus_code, sensor->state.mode); @@ -2285,7 +2285,7 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev, ov5648_mbus_format_fill(mbus_format, mbus_code, mode); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) = + *v4l2_subdev_state_get_format(sd_state, format->pad) = *mbus_format; else if (sensor->state.mode != mode || sensor->state.mbus_code != mbus_code) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index e80db3ecd4f8..470d848f40d8 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2200,9 +2200,9 @@ static int ov5670_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(sd, state, 0); + v4l2_subdev_state_get_format(state, 0); const struct ov5670_mode *default_mode = &supported_modes[0]; - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); + struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); fmt->width = default_mode->width; fmt->height = default_mode->height; @@ -2263,9 +2263,8 @@ static int ov5670_do_get_pad_format(struct ov5670 *ov5670, struct v4l2_subdev_format *fmt) { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else ov5670_update_pad_format(ov5670->cur_mode, fmt); @@ -2310,7 +2309,7 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); ov5670_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov5670->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index); @@ -2550,7 +2549,7 @@ __ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state, switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&sensor->sd, state, pad); + return v4l2_subdev_state_get_crop(state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return mode->analog_crop; } diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index e63d9d402d34..3641911bc73f 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -1036,7 +1036,7 @@ static int ov5675_set_format(struct v4l2_subdev *sd, mutex_lock(&ov5675->mutex); ov5675_update_pad_format(mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov5675->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index); @@ -1069,9 +1069,8 @@ static int ov5675_get_format(struct v4l2_subdev *sd, mutex_lock(&ov5675->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else ov5675_update_pad_format(ov5675->cur_mode, &fmt->format); @@ -1141,7 +1140,7 @@ static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov5675->mutex); ov5675_update_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&ov5675->mutex); return 0; diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 819425e21349..205193baa06e 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -775,7 +775,7 @@ __ov5693_get_pad_format(struct ov5693_device *ov5693, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&ov5693->sd, state, pad); + return v4l2_subdev_state_get_format(state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov5693->mode.format; default: @@ -790,7 +790,7 @@ __ov5693_get_pad_crop(struct ov5693_device *ov5693, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov5693->sd, state, pad); + return v4l2_subdev_state_get_crop(state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov5693->mode.crop; } diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index c8f57ce1578d..663eccdfea6a 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -820,7 +820,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd, fmt->format.height = mode->height; fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov5695->cur_mode = mode; h_blank = mode->hts_def - mode->width; @@ -846,8 +846,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd, mutex_lock(&ov5695->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); } else { fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -1039,7 +1039,7 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov5695 *ov5695 = to_ov5695(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); const struct ov5695_mode *def_mode = &supported_modes[0]; mutex_lock(&ov5695->mutex); diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 38d21b40f5d8..bf1e7617ee08 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -476,7 +476,7 @@ static int ov6650_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { /* pre-select try crop rectangle */ - rect = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + rect = v4l2_subdev_state_get_crop(sd_state, 0); } else { /* pre-select active crop rectangle */ @@ -532,9 +532,9 @@ static int ov6650_set_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_rect *crop = - v4l2_subdev_get_pad_crop(sd, sd_state, 0); + v4l2_subdev_state_get_crop(sd_state, 0); struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_pad_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); /* detect current pad config scaling factor */ bool half_scale = !is_unscaled_ok(mf->width, mf->height, crop); @@ -591,7 +591,7 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, /* update media bus format code and frame size */ if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_pad_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); mf->width = try_fmt->width; mf->height = try_fmt->height; @@ -722,7 +722,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, } if (format->which == V4L2_SUBDEV_FORMAT_TRY) - crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + crop = v4l2_subdev_state_get_crop(sd_state, 0); else crop = &priv->rect; @@ -730,7 +730,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_pad_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); /* store new mbus frame format code and size in pad config */ try_fmt->width = crop->width >> half_scale; diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 6582cc0e2384..774f5dfb8186 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1139,7 +1139,7 @@ __ov7251_get_pad_format(struct ov7251 *ov7251, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&ov7251->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov7251->fmt; default: @@ -1169,7 +1169,7 @@ __ov7251_get_pad_crop(struct ov7251 *ov7251, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov7251->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov7251->crop; default: diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 172483597c54..8164c0c433c5 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1112,8 +1112,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) return ret; - mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, - format->pad); + mbus_fmt = v4l2_subdev_state_get_format(sd_state, format->pad); *mbus_fmt = format->format; return 0; } @@ -1141,7 +1140,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mbus_fmt; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + mbus_fmt = v4l2_subdev_state_get_format(sd_state, 0); format->format = *mbus_fmt; return 0; } else { @@ -1707,7 +1706,7 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd, static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *format = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); ov7670_get_default_format(sd, format); diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 1fbf72152956..e397f7531e1d 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1220,7 +1220,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd, mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 356a45e65b81..9c13ff5fe9fa 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -812,8 +812,7 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, if (ret) goto error; - mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, - format->pad); + mbus_fmt = v4l2_subdev_state_get_format(sd_state, format->pad); *mbus_fmt = format->format; mutex_unlock(&ov7740->mutex); return 0; @@ -843,7 +842,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, mutex_lock(&ov7740->mutex); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + mbus_fmt = v4l2_subdev_state_get_format(sd_state, 0); format->format = *mbus_fmt; } else { format->format = ov7740->format; @@ -883,7 +882,7 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); struct v4l2_mbus_framefmt *format = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); mutex_lock(&ov7740->mutex); ov7740_get_default_format(sd, format); diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index a0f673a24e52..6ffe10e57b5b 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2134,7 +2134,7 @@ static int ov8856_set_format(struct v4l2_subdev *sd, mutex_lock(&ov8856->mutex); ov8856_update_pad_format(ov8856, mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov8856->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov8856->link_freq, mode->link_freq_index); @@ -2172,9 +2172,8 @@ static int ov8856_get_format(struct v4l2_subdev *sd, mutex_lock(&ov8856->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else ov8856_update_pad_format(ov8856, ov8856->cur_mode, &fmt->format); @@ -2225,7 +2224,7 @@ static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov8856->mutex); ov8856_update_pad_format(ov8856, &ov8856->priv_lane->supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&ov8856->mutex); return 0; diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 4d9fd76e2f60..0e3776136136 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1333,7 +1333,7 @@ static int ov8858_start_stream(struct ov8858 *ov8858, if (ret) return ret; - format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + format = v4l2_subdev_state_get_format(state, 0); mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes), width, height, format->width, format->height); @@ -1428,7 +1428,7 @@ static int ov8858_set_fmt(struct v4l2_subdev *sd, fmt->format.field = V4L2_FIELD_NONE; /* Store the format in the current subdev state. */ - *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format; + *v4l2_subdev_state_get_format(state, 0) = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) return 0; @@ -1547,7 +1547,7 @@ static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl) * - by the driver when s_ctrl is called in the s_stream(1) call path */ state = v4l2_subdev_get_locked_active_state(&ov8858->subdev); - format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + format = v4l2_subdev_state_get_format(state, 0); /* Propagate change of current control to all related controls */ switch (ctrl->id) { diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index f2213c6158d3..fb19ab0c2a9d 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2710,8 +2710,8 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev, mutex_lock(&sensor->mutex); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(sd_state, + format->pad); else ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code, sensor->state.mode); @@ -2765,7 +2765,7 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev, ov8865_mbus_format_fill(mbus_format, mbus_code, mode); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) = + *v4l2_subdev_state_get_format(sd_state, format->pad) = *mbus_format; else if (sensor->state.mode != mode || sensor->state.mbus_code != mbus_code) @@ -2818,7 +2818,7 @@ __ov8865_get_pad_crop(struct ov8865_sensor *sensor, switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - *r = *v4l2_subdev_get_try_crop(&sensor->subdev, state, pad); + *r = *v4l2_subdev_state_get_crop(state, pad); break; case V4L2_SUBDEV_FORMAT_ACTIVE: r->height = mode->output_size_y; diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index b50a6196b89c..1707bc22ca91 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -814,7 +814,7 @@ static int ov9282_get_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { ov9282_fill_pad_format(ov9282, ov9282->cur_mode, ov9282->code, @@ -860,7 +860,7 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ret = ov9282_update_controls(ov9282, mode, fmt); @@ -902,7 +902,7 @@ __ov9282_get_pad_crop(struct ov9282 *ov9282, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&ov9282->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &ov9282->cur_mode->crop; } diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index a9adddde1006..b0c171fe75bc 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -547,7 +547,7 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return ov9640_s_fmt(sd, mf); - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index da1ab5135eaa..753f6222102a 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1172,7 +1172,7 @@ static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); fmt->format = *mf; return 0; } @@ -1233,8 +1233,7 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { if (sd_state) { - mf = v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; } } else { @@ -1363,7 +1362,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on) static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); ov965x_get_default_format(mf); return 0; diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index ee3315299605..2b766bfc98fc 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -697,7 +697,7 @@ static int ov9734_set_format(struct v4l2_subdev *sd, mutex_lock(&ov9734->mutex); ov9734_update_pad_format(mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; } else { ov9734->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov9734->link_freq, mode->link_freq_index); @@ -730,9 +730,8 @@ static int ov9734_get_format(struct v4l2_subdev *sd, mutex_lock(&ov9734->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd, - sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else ov9734_update_pad_format(ov9734->cur_mode, &fmt->format); @@ -777,7 +776,7 @@ static int ov9734_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&ov9734->mutex); ov9734_update_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); + v4l2_subdev_state_get_format(fh->state, 0)); mutex_unlock(&ov9734->mutex); return 0; diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c index dbddb7a9f211..403185b18f06 100644 --- a/drivers/media/i2c/rj54n1cb0c.c +++ b/drivers/media/i2c/rj54n1cb0c.c @@ -1009,7 +1009,7 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd, &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index ed5b10731a14..8f9b5713daf7 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -819,7 +819,6 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { - struct v4l2_subdev *sd = &state->sensor_sd; u32 code; switch (fmt->pad) { @@ -841,10 +840,8 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) *fs = state->oif_pix_size[RES_ISP]; else - *fs = s5c73m3_find_frame_size( - v4l2_subdev_get_try_format(sd, sd_state, - OIF_ISP_PAD), - RES_ISP); + *fs = s5c73m3_find_frame_size(v4l2_subdev_state_get_format(sd_state, OIF_ISP_PAD), + RES_ISP); break; } @@ -990,8 +987,8 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); return 0; } @@ -1025,8 +1022,8 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); return 0; } @@ -1069,7 +1066,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd, s5c73m3_try_format(state, sd_state, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; } else { switch (fmt->pad) { @@ -1108,11 +1105,11 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, s5c73m3_oif_try_format(state, sd_state, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; if (fmt->pad == OIF_ISP_PAD) { - mf = v4l2_subdev_get_try_format(sd, sd_state, - OIF_SOURCE_PAD); + mf = v4l2_subdev_state_get_format(sd_state, + OIF_SOURCE_PAD); mf->width = fmt->format.width; mf->height = fmt->format.height; } @@ -1260,8 +1257,8 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, if (fse->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, - OIF_ISP_PAD); + mf = v4l2_subdev_state_get_format(sd_state, + OIF_ISP_PAD); w = mf->width; h = mf->height; @@ -1316,11 +1313,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_ISP_PAD); + mf = v4l2_subdev_state_get_format(fh->state, S5C73M3_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_JPEG_PAD); + mf = v4l2_subdev_state_get_format(fh->state, S5C73M3_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); @@ -1331,15 +1328,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_ISP_PAD); + mf = v4l2_subdev_state_get_format(fh->state, OIF_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_JPEG_PAD); + mf = v4l2_subdev_state_get_format(fh->state, OIF_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); - mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_SOURCE_PAD); + mf = v4l2_subdev_state_get_format(fh->state, OIF_SOURCE_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); return 0; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 67da2045f543..03ccfb0e1e11 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1273,7 +1273,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *mf; return 0; } @@ -1307,7 +1307,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = *mf; + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = *mf; return 0; } @@ -1379,11 +1379,11 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { if (rtype == R_COMPOSE) - sel->r = *v4l2_subdev_get_try_compose(sd, sd_state, - sel->pad); + sel->r = *v4l2_subdev_state_get_compose(sd_state, + sel->pad); else - sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, - sel->pad); + sel->r = *v4l2_subdev_state_get_crop(sd_state, + sel->pad); return 0; } @@ -1472,14 +1472,11 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { rects = (struct v4l2_rect * []) { - &s5k5baf_cis_rect, - v4l2_subdev_get_try_crop(sd, sd_state, - PAD_CIS), - v4l2_subdev_get_try_compose(sd, sd_state, - PAD_CIS), - v4l2_subdev_get_try_crop(sd, sd_state, - PAD_OUT) - }; + &s5k5baf_cis_rect, + v4l2_subdev_state_get_crop(sd_state, PAD_CIS), + v4l2_subdev_state_get_compose(sd_state, PAD_CIS), + v4l2_subdev_state_get_crop(sd_state, PAD_OUT) + }; s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); return 0; } @@ -1696,22 +1693,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_CIS); + mf = v4l2_subdev_state_get_format(fh->state, PAD_CIS); s5k5baf_try_cis_format(mf); if (s5k5baf_is_cis_subdev(sd)) return 0; - mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_OUT); + mf = v4l2_subdev_state_get_format(fh->state, PAD_OUT); mf->colorspace = s5k5baf_formats[0].colorspace; mf->code = s5k5baf_formats[0].code; mf->width = s5k5baf_cis_rect.width; mf->height = s5k5baf_cis_rect.height; mf->field = V4L2_FIELD_NONE; - *v4l2_subdev_get_try_crop(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_compose(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_crop(sd, fh->state, PAD_OUT) = s5k5baf_cis_rect; + *v4l2_subdev_state_get_crop(fh->state, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_state_get_compose(fh->state, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_state_get_crop(fh->state, PAD_OUT) = s5k5baf_cis_rect; return 0; } diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index b3560c8f8b41..0c2674115b7b 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -127,8 +127,7 @@ static struct v4l2_mbus_framefmt *__s5k6a3_get_format( u32 pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return sd_state ? v4l2_subdev_get_try_format(&sensor->subdev, - sd_state, pad) : NULL; + return sd_state ? v4l2_subdev_state_get_format(sd_state, pad) : NULL; return &sensor->format; } @@ -174,9 +173,8 @@ static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = { static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, - fh->state, - 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(fh->state, + 0); *format = s5k6a3_formats[0]; format->width = S5K6A3_DEFAULT_WIDTH; diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 82976aee5e86..51b62a97946a 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -595,7 +595,7 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd, f->colorspace = V4L2_COLORSPACE_SMPTE170M; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *f; + *v4l2_subdev_state_get_format(sd_state, 0) = *f; return 0; } diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index fa27638edc07..b08a249b5fdd 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -724,8 +724,7 @@ static int mipid02_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state, - format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); else fmt = &bridge->fmt; @@ -751,8 +750,8 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) format->format = bridge->fmt; else - format->format = *v4l2_subdev_get_try_format(sd, sd_state, - MIPID02_SINK_0); + format->format = *v4l2_subdev_state_get_format(sd_state, + MIPID02_SINK_0); /* but code may need to be converted */ format->format.code = serial_to_parallel_code(format->format.code); @@ -761,7 +760,7 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd, if (format->which != V4L2_SUBDEV_FORMAT_TRY) return; - *v4l2_subdev_get_try_format(sd, sd_state, MIPID02_SOURCE) = + *v4l2_subdev_state_get_format(sd_state, MIPID02_SOURCE) = format->format; } @@ -775,7 +774,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, format->format.code = get_fmt_code(format->format.code); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); else fmt = &bridge->fmt; diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 5dbfb04b3124..507cd9661e9d 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -780,8 +780,7 @@ static int vgxy61_get_fmt(struct v4l2_subdev *sd, mutex_lock(&sensor->lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, - format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); else fmt = &sensor->fmt; @@ -1289,7 +1288,7 @@ static int vgxy61_set_fmt(struct v4l2_subdev *sd, goto out; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + fmt = v4l2_subdev_state_get_format(sd_state, 0); *fmt = format->format; } else if (sensor->current_mode != new_mode || sensor->fmt.code != format->format.code) { diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index ce612a47ba84..8be9c0f293e0 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -427,7 +427,7 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746) sink_state = v4l2_subdev_lock_and_get_active_state(sd); - mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK); + mbusfmt = v4l2_subdev_state_get_format(sink_state, TC358746_SINK); fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code); /* Self defined CSI user data type id's are not supported yet */ @@ -745,10 +745,10 @@ static int tc358746_init_cfg(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SINK); + fmt = v4l2_subdev_state_get_format(state, TC358746_SINK); *fmt = tc358746_def_fmt; - fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SOURCE); + fmt = v4l2_subdev_state_get_format(state, TC358746_SOURCE); *fmt = tc358746_def_fmt; fmt->code = tc358746_src_mbus_code(tc358746_def_fmt.code); @@ -781,7 +781,7 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd, if (format->pad == TC358746_SOURCE) return v4l2_subdev_get_fmt(sd, sd_state, format); - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, TC358746_SINK); fmt = tc358746_get_format_by_code(format->pad, format->format.code); if (IS_ERR(fmt)) { @@ -800,7 +800,7 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd, *sink_fmt = format->format; - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SOURCE); + src_fmt = v4l2_subdev_state_get_format(sd_state, TC358746_SOURCE); *src_fmt = *sink_fmt; src_fmt->code = tc358746_src_mbus_code(sink_fmt->code); @@ -905,7 +905,7 @@ tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link, return err; sink_state = v4l2_subdev_lock_and_get_active_state(sd); - mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK); + mbusfmt = v4l2_subdev_state_get_format(sink_state, TC358746_SINK); /* Check the FIFO settings */ fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code); diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 325e99125941..63c12b77ff1e 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1740,7 +1740,7 @@ static int tda1997x_init_cfg(struct v4l2_subdev *sd, struct tda1997x_state *state = to_state(sd); struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); mf->code = state->mbus_codes[0]; return 0; @@ -1792,7 +1792,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); format->format.code = fmt->code; } else format->format.code = state->mbus_code; @@ -1826,7 +1826,7 @@ static int tda1997x_set_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); *fmt = format->format; } else { int ret = tda1997x_setup_format(state, format->format.code); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index e543b3f7a4d8..76a92bfb6fde 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1035,7 +1035,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder, return &decoder->rect; case V4L2_SUBDEV_FORMAT_TRY: #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - return v4l2_subdev_get_try_crop(&decoder->sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); #else return ERR_PTR(-EINVAL); #endif diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 5233c33b93df..7c331a7f12d4 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -829,7 +829,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return tw9910_s_fmt(sd, mf); - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *mf; + *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 301a0ee6d236..5d3b0ffd3d08 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1205,11 +1205,11 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) }; /* Initialize try_fmt */ - format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SINK); + format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SINK); *format = fmt_default; /* same as sink */ - format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SOURCE); + format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SOURCE); *format = fmt_default; return 0; @@ -1224,8 +1224,8 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, mutex_lock(&q->subdev_lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, - fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); else fmt->format = q->subdev_fmt; @@ -1251,7 +1251,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, return cio2_subdev_get_fmt(sd, sd_state, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - mbus = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mbus = v4l2_subdev_state_get_format(sd_state, fmt->pad); else mbus = &q->subdev_fmt; diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 2ca52390541d..8bf90e2bd856 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -338,7 +338,7 @@ mei_csi_get_pad_format(struct v4l2_subdev *sd, switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &csi->format_mbus[pad]; default: @@ -356,7 +356,7 @@ static int mei_csi_init_cfg(struct v4l2_subdev *sd, mutex_lock(&csi->lock); for (i = 0; i < sd->entity.num_pads; i++) { - mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i); + mbusformat = v4l2_subdev_state_get_format(sd_state, i); *mbusformat = mei_csi_format_mbus_default; } diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index bb83117bab2e..da58f33b6b0a 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -560,7 +560,7 @@ static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt, struct v4l2_subdev_state *sd_state) { struct v4l2_rect *try_crop = - v4l2_subdev_get_pad_crop(isi->entity.subdev, sd_state, 0); + v4l2_subdev_state_get_crop(sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .code = isi_fmt->mbus_code, .which = V4L2_SUBDEV_FORMAT_TRY, diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 889f4fbbafb3..0171ea7b834d 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -406,12 +406,12 @@ static int csi2rx_set_fmt(struct v4l2_subdev *subdev, format->format.field = V4L2_FIELD_NONE; /* Set sink format */ - fmt = v4l2_subdev_get_pad_format(subdev, state, format->pad); + fmt = v4l2_subdev_state_get_format(state, format->pad); *fmt = format->format; /* Propagate to source formats */ for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { - fmt = v4l2_subdev_get_pad_format(subdev, state, i); + fmt = v4l2_subdev_state_get_format(state, i); *fmt = format->format; } diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index c115742f347f..3d98f91f1bee 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -176,8 +176,7 @@ __csi2tx_get_pad_format(struct v4l2_subdev *subdev, struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(subdev, sd_state, - fmt->pad); + return v4l2_subdev_state_get_format(sd_state, fmt->pad); return &csi2tx->pad_fmts[fmt->pad]; } diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c index 988c1cc1d8b6..87a2d092aad2 100644 --- a/drivers/media/platform/microchip/microchip-csi2dc.c +++ b/drivers/media/platform/microchip/microchip-csi2dc.c @@ -232,8 +232,8 @@ static int csi2dc_get_fmt(struct v4l2_subdev *csi2dc_sd, struct v4l2_mbus_framefmt *v4l2_try_fmt; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd, sd_state, - format->pad); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + format->pad); format->format = *v4l2_try_fmt; return 0; @@ -281,13 +281,12 @@ static int csi2dc_set_fmt(struct v4l2_subdev *csi2dc_sd, req_fmt->format.field = V4L2_FIELD_NONE; if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd, sd_state, - req_fmt->pad); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + req_fmt->pad); *v4l2_try_fmt = req_fmt->format; /* Trying on the sink pad makes the source pad change too */ - v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd, - sd_state, - CSI2DC_PAD_SOURCE); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + CSI2DC_PAD_SOURCE); *v4l2_try_fmt = req_fmt->format; /* if we are just trying, we are done */ @@ -440,7 +439,7 @@ static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *v4l2_try_fmt = - v4l2_subdev_get_try_format(csi2dc_sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); v4l2_try_fmt->height = 480; v4l2_try_fmt->width = 640; diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index a901be02e2f6..3fba0e2844b6 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -855,7 +855,7 @@ static void isc_try_fse(struct isc_device *isc, struct v4l2_subdev_state *sd_state) { struct v4l2_rect *try_crop = - v4l2_subdev_get_pad_crop(isc->current_subdev->sd, sd_state, 0); + v4l2_subdev_state_get_crop(sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_TRY, }; diff --git a/drivers/media/platform/microchip/microchip-isc-scaler.c b/drivers/media/platform/microchip/microchip-isc-scaler.c index 0f29a32d15ce..58dffbc9fbcb 100644 --- a/drivers/media/platform/microchip/microchip-isc-scaler.c +++ b/drivers/media/platform/microchip/microchip-isc-scaler.c @@ -33,8 +33,8 @@ static int isc_scaler_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *v4l2_try_fmt; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, - format->pad); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + format->pad); format->format = *v4l2_try_fmt; return 0; @@ -74,12 +74,12 @@ static int isc_scaler_set_fmt(struct v4l2_subdev *sd, req_fmt->format.code = fmt->mbus_code; if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, - req_fmt->pad); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + req_fmt->pad); *v4l2_try_fmt = req_fmt->format; /* Trying on the sink pad makes the source pad change too */ - v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, - ISC_SCALER_PAD_SOURCE); + v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, + ISC_SCALER_PAD_SOURCE); *v4l2_try_fmt = req_fmt->format; v4l_bound_align_image(&v4l2_try_fmt->width, @@ -149,13 +149,13 @@ static int isc_scaler_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *v4l2_try_fmt = - v4l2_subdev_get_try_format(sd, sd_state, 0); + v4l2_subdev_state_get_format(sd_state, 0); struct v4l2_rect *try_crop; struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); *v4l2_try_fmt = isc->scaler_format[ISC_SCALER_PAD_SOURCE]; - try_crop = v4l2_subdev_get_try_crop(sd, sd_state, 0); + try_crop = v4l2_subdev_state_get_crop(sd_state, 0); try_crop->top = 0; try_crop->left = 0; diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 6cb20b45e0a1..a2c748217376 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -954,7 +954,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) state = v4l2_subdev_lock_and_get_active_state(sd); - format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK); + format = v4l2_subdev_state_get_format(state, CSIS_PAD_SINK); csis_fmt = find_csis_format(format->code); ret = mipi_csis_calculate_params(csis, csis_fmt); @@ -1002,7 +1002,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad); + fmt = v4l2_subdev_state_get_format(sd_state, code->pad); code->code = fmt->code; return 0; } @@ -1069,7 +1069,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); + fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; @@ -1083,7 +1083,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE); + fmt = v4l2_subdev_state_get_format(sd_state, CSIS_PAD_SOURCE); *fmt = sdformat->format; /* The format on the source pad might change due to unpacking. */ @@ -1104,7 +1104,7 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, return -EINVAL; state = v4l2_subdev_lock_and_get_active_state(sd); - fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE); + fmt = v4l2_subdev_state_get_format(state, CSIS_PAD_SOURCE); csis_fmt = find_csis_format(fmt->code); v4l2_subdev_unlock_state(state); diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 4c467fb82789..1d2464ca59b8 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -542,8 +542,8 @@ static void imx7_csi_configure(struct imx7_csi *csi, } else { const struct v4l2_mbus_framefmt *sink_fmt; - sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state, - IMX7_CSI_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + IMX7_CSI_PAD_SINK); cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC | BIT_MCLKDIV(1) | BIT_MCLKEN; @@ -1739,7 +1739,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_pad_format(sd, sd_state, i); + v4l2_subdev_state_get_format(sd_state, i); mf->code = IMX7_CSI_DEF_MBUS_CODE; mf->width = IMX7_CSI_DEF_PIX_WIDTH; @@ -1763,7 +1763,7 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *in_fmt; int ret = 0; - in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); + in_fmt = v4l2_subdev_state_get_format(sd_state, IMX7_CSI_PAD_SINK); switch (code->pad) { case IMX7_CSI_PAD_SINK: @@ -1842,7 +1842,7 @@ static void imx7_csi_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *in_fmt; u32 code; - in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); + in_fmt = v4l2_subdev_state_get_format(sd_state, IMX7_CSI_PAD_SINK); switch (sdformat->pad) { case IMX7_CSI_PAD_SRC: @@ -1892,7 +1892,7 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, imx7_csi_try_fmt(sd, sd_state, sdformat, &cc); - fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); + fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); *fmt = sdformat->format; @@ -1903,8 +1903,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, format.format = sdformat->format; imx7_csi_try_fmt(sd, sd_state, &format, &outcc); - outfmt = v4l2_subdev_get_pad_format(sd, sd_state, - IMX7_CSI_PAD_SRC); + outfmt = v4l2_subdev_state_get_format(sd_state, + IMX7_CSI_PAD_SRC); *outfmt = format.format; } diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c index 65d20e9bae69..14c6da392803 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c @@ -263,10 +263,10 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) /* Configure the pipeline. */ state = v4l2_subdev_lock_and_get_active_state(sd); - sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK); - src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE); - compose = v4l2_subdev_get_try_compose(sd, state, MXC_ISI_PIPE_PAD_SINK); - crop = *v4l2_subdev_get_try_crop(sd, state, MXC_ISI_PIPE_PAD_SOURCE); + sink_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE); + compose = v4l2_subdev_state_get_compose(state, MXC_ISI_PIPE_PAD_SINK); + crop = *v4l2_subdev_state_get_crop(state, MXC_ISI_PIPE_PAD_SOURCE); sink_info = mxc_isi_bus_format_by_code(sink_fmt->code, MXC_ISI_PIPE_PAD_SINK); @@ -322,7 +322,7 @@ mxc_isi_pipe_get_pad_format(struct mxc_isi_pipe *pipe, struct v4l2_subdev_state *state, unsigned int pad) { - return v4l2_subdev_get_try_format(&pipe->sd, state, pad); + return v4l2_subdev_state_get_format(state, pad); } static struct v4l2_rect * @@ -330,7 +330,7 @@ mxc_isi_pipe_get_pad_crop(struct mxc_isi_pipe *pipe, struct v4l2_subdev_state *state, unsigned int pad) { - return v4l2_subdev_get_try_crop(&pipe->sd, state, pad); + return v4l2_subdev_state_get_crop(state, pad); } static struct v4l2_rect * @@ -338,7 +338,7 @@ mxc_isi_pipe_get_pad_compose(struct mxc_isi_pipe *pipe, struct v4l2_subdev_state *state, unsigned int pad) { - return v4l2_subdev_get_try_compose(&pipe->sd, state, pad); + return v4l2_subdev_state_get_compose(state, pad); } static int mxc_isi_pipe_init_cfg(struct v4l2_subdev *sd, @@ -832,8 +832,8 @@ int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe, int ret; state = v4l2_subdev_lock_and_get_active_state(sd); - sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK); - src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE); + sink_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE); v4l2_subdev_unlock_state(state); sink_info = mxc_isi_bus_format_by_code(sink_fmt->code, 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 10840c9a0912..49bca2b01cc6 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -713,7 +713,7 @@ static int mxc_isi_video_validate_format(struct mxc_isi_video *video) info = mxc_isi_format_by_fourcc(video->pix.pixelformat, MXC_ISI_VIDEO_CAP); - format = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE); + format = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE); if (format->code != info->mbus_code || format->width != video->pix.width || diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index ed048f73c982..02a4c546a90a 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -296,7 +296,7 @@ static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state, /* Calculate the line rate from the pixel rate. */ - fmt = v4l2_subdev_get_pad_format(&state->sd, sd_state, MIPI_CSI2_PAD_SINK); + fmt = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SINK); csi2_fmt = find_csi2_format(fmt->code); link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, @@ -443,8 +443,9 @@ static int imx8mq_mipi_csi_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; - fmt_sink = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SINK); - fmt_source = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SOURCE); + fmt_sink = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SINK); + fmt_source = v4l2_subdev_state_get_format(sd_state, + MIPI_CSI2_PAD_SOURCE); fmt_sink->code = MEDIA_BUS_FMT_SGBRG10_1X10; fmt_sink->width = MIPI_CSI2_DEF_PIX_WIDTH; @@ -477,7 +478,7 @@ static int imx8mq_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad); + fmt = v4l2_subdev_state_get_format(sd_state, code->pad); code->code = fmt->code; return 0; } @@ -514,7 +515,7 @@ static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd, if (!csi2_fmt) csi2_fmt = &imx8mq_mipi_csi_formats[0]; - fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); + fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); fmt->code = csi2_fmt->code; fmt->width = sdformat->format.width; @@ -523,7 +524,7 @@ static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SOURCE); + fmt = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SOURCE); *fmt = sdformat->format; return 0; diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 51952e6b37b3..bbe253f7571f 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -276,8 +276,7 @@ __csid_get_format(struct csid_device *csid, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csid->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &csid->fmt[pad]; } diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 838514b94d66..264c99efeae8 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -325,8 +325,7 @@ __csiphy_get_format(struct csiphy_device *csiphy, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csiphy->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &csiphy->fmt[pad]; } diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index c26f270e8e71..a12dcc7ff438 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -879,8 +879,7 @@ __ispif_get_format(struct ispif_line *line, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&line->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &line->fmt[pad]; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 8ebcffc2762d..74fe577a84aa 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -828,8 +828,7 @@ __vfe_get_format(struct vfe_line *line, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&line->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &line->fmt[pad]; } @@ -848,8 +847,8 @@ __vfe_get_compose(struct vfe_line *line, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_compose(&line->subdev, sd_state, - MSM_VFE_PAD_SINK); + return v4l2_subdev_state_get_compose(sd_state, + MSM_VFE_PAD_SINK); return &line->compose; } @@ -868,8 +867,7 @@ __vfe_get_crop(struct vfe_line *line, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&line->subdev, sd_state, - MSM_VFE_PAD_SRC); + return v4l2_subdev_state_get_crop(sd_state, MSM_VFE_PAD_SRC); return &line->crop; } diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 19a005d83733..530d65fc546b 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -282,7 +282,7 @@ static int risp_set_pad_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { isp->mf = format->format; } else { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + framefmt = v4l2_subdev_state_get_format(sd_state, 0); *framefmt = format->format; } @@ -302,7 +302,7 @@ static int risp_get_pad_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) format->format = isp->mf; else - format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); + format->format = *v4l2_subdev_state_get_format(sd_state, 0); mutex_unlock(&isp->lock); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c index 66fe553a00e7..582d5e35db0e 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c @@ -1185,7 +1185,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { priv->mf = format->format; } else { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + framefmt = v4l2_subdev_state_get_format(sd_state, 0); *framefmt = format->format; } @@ -1205,7 +1205,7 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) format->format = priv->mf; else - format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); + format->format = *v4l2_subdev_state_get_format(sd_state, 0); mutex_unlock(&priv->lock); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index ad2bd71037ab..04e61e783045 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -250,7 +250,7 @@ static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2) } state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev); - fmt = v4l2_subdev_get_pad_format(&csi2->subdev, state, RZG2L_CSI2_SINK); + fmt = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SINK); format = rzg2l_csi2_code_to_fmt(fmt->code); v4l2_subdev_unlock_state(state); @@ -500,13 +500,13 @@ static int rzg2l_csi2_set_format(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *src_format; struct v4l2_mbus_framefmt *sink_format; - src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SOURCE); + src_format = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SOURCE); if (fmt->pad == RZG2L_CSI2_SOURCE) { fmt->format = *src_format; return 0; } - sink_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SINK); + sink_format = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SINK); if (!rzg2l_csi2_code_to_fmt(fmt->format.code)) sink_format->code = rzg2l_csi2_formats[0].code; diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c index 4dcd2faff5bb..17a59dfc8363 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c @@ -39,7 +39,7 @@ struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) struct v4l2_mbus_framefmt *fmt; state = v4l2_subdev_lock_and_get_active_state(&cru->ip.subdev); - fmt = v4l2_subdev_get_pad_format(&cru->ip.subdev, state, 1); + fmt = v4l2_subdev_state_get_format(state, 1); v4l2_subdev_unlock_state(state); return fmt; @@ -108,13 +108,13 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *src_format; struct v4l2_mbus_framefmt *sink_format; - src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CRU_IP_SOURCE); + src_format = v4l2_subdev_state_get_format(state, RZG2L_CRU_IP_SOURCE); if (fmt->pad == RZG2L_CRU_IP_SOURCE) { fmt->format = *src_format; return 0; } - sink_format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + sink_format = v4l2_subdev_state_get_format(state, fmt->pad); if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code)) sink_format->code = rzg2l_cru_ip_formats[0].code; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c index 89385b4cabe5..95bf7b4ac9b8 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c @@ -100,7 +100,7 @@ static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx, struct v4l2_subdev_state *sd_state, unsigned int pad) { - return v4l2_subdev_get_try_compose(&brx->entity.subdev, sd_state, pad); + return v4l2_subdev_state_get_compose(sd_state, pad); } static void brx_try_format(struct vsp1_brx *brx, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index c31f05a80bb5..d5a49e08a607 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -142,7 +142,7 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, struct v4l2_subdev_state *sd_state, unsigned int pad) { - return v4l2_subdev_get_try_format(&entity->subdev, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); } /** @@ -163,11 +163,9 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity, { switch (target) { case V4L2_SEL_TGT_COMPOSE: - return v4l2_subdev_get_try_compose(&entity->subdev, sd_state, - pad); + return v4l2_subdev_state_get_compose(sd_state, pad); case V4L2_SEL_TGT_CROP: - return v4l2_subdev_get_try_crop(&entity->subdev, sd_state, - pad); + return v4l2_subdev_state_get_crop(sd_state, pad); default: return NULL; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c index 22a82d218152..ae7ff8d5ecf1 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c @@ -19,8 +19,7 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_state *sd_state) { - return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, sd_state, - RWPF_PAD_SINK); + return v4l2_subdev_state_get_crop(sd_state, RWPF_PAD_SINK); } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index 6e17b2817e61..47f4353a1784 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -242,8 +242,8 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, if (code->index) return -EINVAL; - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_CSI_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_CSI_PAD_SINK); code->code = sink_fmt->code; return 0; @@ -275,10 +275,8 @@ static int rkisp1_csi_init_config(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_CSI_PAD_SINK); - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_CSI_PAD_SRC); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; @@ -301,7 +299,7 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, if (fmt->pad == RKISP1_CSI_PAD_SRC) return v4l2_subdev_get_fmt(sd, sd_state, fmt); - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK); sink_fmt->code = fmt->format.code; @@ -321,7 +319,7 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, fmt->format = *sink_fmt; /* Propagate the format to the source pad. */ - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC); *src_fmt = *sink_fmt; return 0; @@ -374,7 +372,7 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) return -EINVAL; sd_state = v4l2_subdev_lock_and_get_active_state(sd); - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK); format = rkisp1_mbus_info_get_by_code(sink_fmt->code); v4l2_subdev_unlock_state(sd_state); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 88ca8b2283b7..96353648c032 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -66,8 +66,8 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state) { const struct v4l2_rect *src_crop = - v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; @@ -102,12 +102,12 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, const struct v4l2_mbus_framefmt *sink_frm; const struct v4l2_rect *sink_crop; - sink_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); - sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); - src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + sink_frm = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_frm = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); sink_fmt = rkisp1_mbus_info_get_by_code(sink_frm->code); src_fmt = rkisp1_mbus_info_get_by_code(src_frm->code); @@ -201,8 +201,8 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, } else { struct v4l2_mbus_framefmt *src_frm; - src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_frm = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat, src_frm->quantization, src_frm->ycbcr_enc); @@ -318,8 +318,8 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp, RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); - src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER) @@ -416,8 +416,8 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, struct v4l2_rect *sink_crop, *src_crop; /* Video. */ - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; @@ -427,15 +427,15 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - sink_crop = v4l2_subdev_get_pad_crop(sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->width = RKISP1_DEFAULT_WIDTH; sink_crop->height = RKISP1_DEFAULT_HEIGHT; sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); *src_fmt = *sink_fmt; src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; src_fmt->colorspace = V4L2_COLORSPACE_SRGB; @@ -443,15 +443,15 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - src_crop = v4l2_subdev_get_pad_crop(sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); *src_crop = *sink_crop; /* Parameters and statistics. */ - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_ISP_PAD_SINK_PARAMS); - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_ISP_PAD_SOURCE_STATS); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_PARAMS); + src_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_STATS); sink_fmt->width = 0; sink_fmt->height = 0; sink_fmt->field = V4L2_FIELD_NONE; @@ -472,12 +472,12 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, const struct v4l2_rect *src_crop; bool set_csc; - sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); - src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); - src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + src_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); /* * Media bus code. The ISP can operate in pass-through mode (Bayer in, @@ -570,10 +570,10 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, const struct v4l2_rect *sink_crop; struct v4l2_rect *src_crop; - src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); - sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + src_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + sink_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); src_crop->left = ALIGN(r->left, 2); src_crop->width = ALIGN(r->width, 2); @@ -584,8 +584,8 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, *r = *src_crop; /* Propagate to out format */ - src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt); } @@ -596,10 +596,10 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, struct v4l2_rect *sink_crop, *src_crop; const struct v4l2_mbus_framefmt *sink_fmt; - sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); - sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->left = ALIGN(r->left, 2); sink_crop->width = ALIGN(r->width, 2); @@ -610,8 +610,8 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, *r = *sink_crop; /* Propagate to out crop */ - src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO); + src_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); rkisp1_isp_set_src_crop(isp, sd_state, src_crop); } @@ -624,8 +624,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->code = format->code; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { @@ -673,8 +673,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, *format = *sink_fmt; /* Propagate to in crop */ - sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop); } @@ -689,7 +689,8 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format); else - fmt->format = *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad); + fmt->format = *v4l2_subdev_state_get_format(sd_state, + fmt->pad); return 0; } @@ -709,19 +710,19 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_pad_format(sd, sd_state, sel->pad); + fmt = v4l2_subdev_state_get_format(sd_state, sel->pad); sel->r.height = fmt->height; sel->r.width = fmt->width; sel->r.left = 0; sel->r.top = 0; } else { - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO); + sel->r = *v4l2_subdev_state_get_crop(sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); } break; case V4L2_SEL_TGT_CROP: - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); break; default: diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 28ecc7347d54..9f94b9f60c35 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -142,10 +142,8 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz, struct v4l2_rect *sink_crop; u32 dc_ctrl; - sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); - sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); if (sink_crop->width == sink_fmt->width && sink_crop->height == sink_fmt->height && @@ -275,10 +273,8 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, struct v4l2_area src_y, src_c; struct v4l2_rect sink_c; - sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); - src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SRC); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC); sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code); src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); @@ -292,8 +288,7 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, return; } - sink_y = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sink_y = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); sink_c.width = sink_y->width / sink_yuv_info->hdiv; sink_c.height = sink_y->height / sink_yuv_info->vdiv; @@ -377,8 +372,7 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; - sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_RSZ_PAD_SRC); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; @@ -388,15 +382,13 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); sink_crop->width = RKISP1_DEFAULT_WIDTH; sink_crop->height = RKISP1_DEFAULT_HEIGHT; sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); *src_fmt = *sink_fmt; /* NOTE: there is no crop in the source pad, only in the sink */ @@ -411,10 +403,8 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, const struct rkisp1_mbus_info *sink_mbus_info; struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); - src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SRC); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC); sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); @@ -441,10 +431,8 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; - sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); - sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); /* Not crop for MP bayer raw data */ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); @@ -478,12 +466,9 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); - src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SRC); - sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC); + sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); if (rsz->id == RKISP1_SELFPATH) sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; @@ -573,8 +558,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - mf_sink = v4l2_subdev_get_pad_format(sd, sd_state, - RKISP1_RSZ_PAD_SINK); + mf_sink = v4l2_subdev_state_get_format(sd_state, + RKISP1_RSZ_PAD_SINK); sel->r.height = mf_sink->height; sel->r.width = mf_sink->width; sel->r.left = 0; @@ -582,8 +567,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, break; case V4L2_SEL_TGT_CROP: - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, - RKISP1_RSZ_PAD_SINK); + sel->r = *v4l2_subdev_state_get_crop(sd_state, + RKISP1_RSZ_PAD_SINK); break; default: diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index a0d43bf892e6..05cafba1c728 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -1479,7 +1479,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *mf; return 0; } @@ -1534,7 +1534,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; return 0; } @@ -1604,10 +1604,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, return 0; case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad); + try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad); f = &ctx->d_frame; break; default: @@ -1651,10 +1651,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad); + try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad); f = &ctx->d_frame; break; default: diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp.c index b85986e50f46..3c5d7bee2655 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp.c @@ -126,7 +126,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *mf = *v4l2_subdev_state_get_format(sd_state, fmt->pad); return 0; } @@ -172,9 +172,8 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; } else { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - format = v4l2_subdev_get_try_format(&isp->subdev, - sd_state, - FIMC_ISP_SD_PAD_SINK); + format = v4l2_subdev_state_get_format(sd_state, + FIMC_ISP_SD_PAD_SINK); else format = &isp->sink_fmt; @@ -207,7 +206,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, __isp_subdev_try_format(isp, sd_state, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; /* Propagate format to the source pads */ @@ -220,8 +219,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, format.pad = pad; __isp_subdev_try_format(isp, sd_state, &format); - mf = v4l2_subdev_get_try_format(sd, sd_state, - pad); + mf = v4l2_subdev_state_get_format(sd_state, + pad); *mf = format.format; } } @@ -374,18 +373,17 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, .field = V4L2_FIELD_NONE, }; - format = v4l2_subdev_get_try_format(sd, fh->state, - FIMC_ISP_SD_PAD_SINK); + format = v4l2_subdev_state_get_format(fh->state, FIMC_ISP_SD_PAD_SINK); *format = fmt; - format = v4l2_subdev_get_try_format(sd, fh->state, - FIMC_ISP_SD_PAD_SRC_FIFO); + format = v4l2_subdev_state_get_format(fh->state, + FIMC_ISP_SD_PAD_SRC_FIFO); fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; *format = fmt; - format = v4l2_subdev_get_try_format(sd, fh->state, - FIMC_ISP_SD_PAD_SRC_DMA); + format = v4l2_subdev_state_get_format(fh->state, + FIMC_ISP_SD_PAD_SRC_DMA); *format = fmt; return 0; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 9396b10b5b1c..7898c9bebb04 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -574,16 +574,14 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, struct v4l2_rect *rect; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, - sd_state, - FLITE_SD_PAD_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, + FLITE_SD_PAD_SINK); mf->code = sink_fmt->code; mf->colorspace = sink_fmt->colorspace; - rect = v4l2_subdev_get_try_crop(&fimc->subdev, - sd_state, - FLITE_SD_PAD_SINK); + rect = v4l2_subdev_state_get_crop(sd_state, + FLITE_SD_PAD_SINK); } else { mf->code = sink->fmt->mbus_code; mf->colorspace = sink->fmt->colorspace; @@ -1021,7 +1019,7 @@ static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt( if (pad != FLITE_SD_PAD_SINK) pad = FLITE_SD_PAD_SOURCE_DMA; - return v4l2_subdev_get_try_format(sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); } static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, @@ -1129,7 +1127,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); return 0; } @@ -1166,7 +1164,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, fimc_lite_try_crop(fimc, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r; + *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r; } else { unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index 686ca8753ba2..aae8a8b2c0f4 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -569,8 +569,7 @@ static struct v4l2_mbus_framefmt *__s5pcsis_get_format( enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return sd_state ? v4l2_subdev_get_try_format(&state->sd, - sd_state, 0) : NULL; + return sd_state ? v4l2_subdev_state_get_format(sd_state, 0) : NULL; return &state->format; } diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 0f5b3845d7b9..be58260ea67e 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -1216,7 +1216,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *mf; return 0; } @@ -1305,7 +1305,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, __camif_subdev_try_format(camif, mf, fmt->pad); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); *mf = fmt->format; mutex_unlock(&camif->lock); return 0; @@ -1357,7 +1357,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); return 0; } @@ -1445,7 +1445,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, __camif_try_crop(camif, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r; + *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r; } else { unsigned long flags; unsigned int i; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c index 48702134ccc5..c37bb1d76ef6 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -271,7 +271,7 @@ static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev, { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(subdev, sd_state, CSI_SUBDEV_SINK); + fmt = v4l2_subdev_state_get_format(sd_state, CSI_SUBDEV_SINK); *fmt = sun4i_csi_pad_fmt_default; return 0; @@ -285,8 +285,7 @@ static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *subdev_fmt; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state, - fmt->pad); + subdev_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); else subdev_fmt = &csi->subdev_fmt; @@ -303,8 +302,7 @@ static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *subdev_fmt; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state, - fmt->pad); + subdev_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); else subdev_fmt = &csi->subdev_fmt; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index e573413123b9..d57481feee05 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -507,7 +507,7 @@ static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev, struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK; struct v4l2_mbus_framefmt *mbus_format = - v4l2_subdev_get_try_format(subdev, state, pad); + v4l2_subdev_state_get_format(state, pad); struct mutex *lock = &csi_dev->bridge.lock; mutex_lock(lock); @@ -547,8 +547,8 @@ static int sun6i_csi_bridge_get_fmt(struct v4l2_subdev *subdev, mutex_lock(lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(state, + format->pad); else *mbus_format = csi_dev->bridge.mbus_format; @@ -570,7 +570,7 @@ static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev, sun6i_csi_bridge_mbus_format_prepare(mbus_format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *v4l2_subdev_state_get_format(state, format->pad) = *mbus_format; else csi_dev->bridge.mbus_format = *mbus_format; diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index 08d86c17b284..d2c9f5d20496 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -311,7 +311,7 @@ static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK; struct v4l2_mbus_framefmt *mbus_format = - v4l2_subdev_get_try_format(subdev, state, pad); + v4l2_subdev_state_get_format(state, pad); struct mutex *lock = &csi2_dev->bridge.lock; mutex_lock(lock); @@ -351,8 +351,8 @@ static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, mutex_lock(lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(state, + format->pad); else *mbus_format = csi2_dev->bridge.mbus_format; @@ -374,7 +374,7 @@ static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, sun6i_mipi_csi2_mbus_format_prepare(mbus_format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *v4l2_subdev_state_get_format(state, format->pad) = *mbus_format; else csi2_dev->bridge.mbus_format = *mbus_format; diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index 14a1844812c0..d6275954af98 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -345,7 +345,7 @@ static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, v4l2_get_subdevdata(subdev); unsigned int pad = SUN8I_A83T_MIPI_CSI2_PAD_SINK; struct v4l2_mbus_framefmt *mbus_format = - v4l2_subdev_get_try_format(subdev, state, pad); + v4l2_subdev_state_get_format(state, pad); struct mutex *lock = &csi2_dev->bridge.lock; mutex_lock(lock); @@ -387,8 +387,8 @@ static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, mutex_lock(lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(state, + format->pad); else *mbus_format = csi2_dev->bridge.mbus_format; @@ -411,7 +411,7 @@ static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *v4l2_subdev_state_get_format(state, format->pad) = *mbus_format; else csi2_dev->bridge.mbus_format = *mbus_format; diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index 1a4273bbe752..61433744c6c4 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -57,7 +57,7 @@ static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) state = v4l2_subdev_get_locked_active_state(&phy->subdev); - fmt = v4l2_subdev_get_pad_format(&phy->subdev, state, CAL_CAMERARX_PAD_SINK); + fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK); fmtinfo = cal_format_by_code(fmt->code); if (!fmtinfo) @@ -621,8 +621,6 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) { - struct cal_camerarx *phy = to_cal_camerarx(sd); - /* No transcoding, source and sink codes must match. */ if (cal_rx_pad_is_source(code->pad)) { struct v4l2_mbus_framefmt *fmt; @@ -630,8 +628,8 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = v4l2_subdev_get_pad_format(&phy->subdev, state, - CAL_CAMERARX_PAD_SINK); + fmt = v4l2_subdev_state_get_format(state, + CAL_CAMERARX_PAD_SINK); code->code = fmt->code; } else { if (code->index >= cal_num_formats) @@ -656,8 +654,8 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, if (cal_rx_pad_is_source(fse->pad)) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_pad_format(sd, state, - CAL_CAMERARX_PAD_SINK); + fmt = v4l2_subdev_state_get_format(state, + CAL_CAMERARX_PAD_SINK); if (fse->code != fmt->code) return -EINVAL; @@ -713,11 +711,11 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, /* Store the format and propagate it to the source pad. */ - fmt = v4l2_subdev_get_pad_format(sd, state, CAL_CAMERARX_PAD_SINK); + fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK); *fmt = format->format; - fmt = v4l2_subdev_get_pad_format(sd, state, - CAL_CAMERARX_PAD_FIRST_SOURCE); + fmt = v4l2_subdev_state_get_format(state, + CAL_CAMERARX_PAD_FIRST_SOURCE); *fmt = format->format; return 0; diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 94e67c057a20..e1c5e68e945b 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -698,7 +698,7 @@ static int cal_video_check_format(struct cal_ctx *ctx) state = v4l2_subdev_lock_and_get_active_state(&ctx->phy->subdev); - format = v4l2_subdev_get_pad_format(&ctx->phy->subdev, state, remote_pad->index); + format = v4l2_subdev_state_get_format(state, remote_pad->index); if (!format) { ret = -EINVAL; goto out; diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c index 6aace3e592fb..dd375c4e180d 100644 --- a/drivers/media/platform/ti/omap3isp/ispccdc.c +++ b/drivers/media/platform/ti/omap3isp/ispccdc.c @@ -1948,8 +1948,7 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ccdc->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &ccdc->formats[pad]; } @@ -1960,8 +1959,8 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&ccdc->subdev, sd_state, - CCDC_PAD_SOURCE_OF); + return v4l2_subdev_state_get_crop(sd_state, + CCDC_PAD_SOURCE_OF); else return &ccdc->crop; } diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c index 1bbb618db63d..1204ee221c9e 100644 --- a/drivers/media/platform/ti/omap3isp/ispccp2.c +++ b/drivers/media/platform/ti/omap3isp/ispccp2.c @@ -625,8 +625,7 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ccp2->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &ccp2->formats[pad]; } diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c index a415dc405209..ae574e1b6528 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsi2.c +++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c @@ -834,8 +834,7 @@ __csi2_get_format(struct isp_csi2_device *csi2, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &csi2->formats[pad]; } diff --git a/drivers/media/platform/ti/omap3isp/isppreview.c b/drivers/media/platform/ti/omap3isp/isppreview.c index 740ba6cd3d36..e383a57654de 100644 --- a/drivers/media/platform/ti/omap3isp/isppreview.c +++ b/drivers/media/platform/ti/omap3isp/isppreview.c @@ -1684,8 +1684,7 @@ __preview_get_format(struct isp_prev_device *prev, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&prev->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &prev->formats[pad]; } @@ -1696,8 +1695,7 @@ __preview_get_crop(struct isp_prev_device *prev, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&prev->subdev, sd_state, - PREV_PAD_SINK); + return v4l2_subdev_state_get_crop(sd_state, PREV_PAD_SINK); else return &prev->crop; } diff --git a/drivers/media/platform/ti/omap3isp/ispresizer.c b/drivers/media/platform/ti/omap3isp/ispresizer.c index f00a37f29b77..87d821b02e5c 100644 --- a/drivers/media/platform/ti/omap3isp/ispresizer.c +++ b/drivers/media/platform/ti/omap3isp/ispresizer.c @@ -119,7 +119,7 @@ __resizer_get_format(struct isp_res_device *res, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&res->subdev, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &res->formats[pad]; } @@ -136,8 +136,7 @@ __resizer_get_crop(struct isp_res_device *res, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&res->subdev, sd_state, - RESZ_PAD_SINK); + return v4l2_subdev_state_get_crop(sd_state, RESZ_PAD_SINK); else return &res->crop.request; } diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 5de6b6694f53..06a28531ed02 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -89,10 +89,10 @@ static int video_mux_link_setup(struct media_entity *entity, /* Propagate the active format to the source */ sd_state = v4l2_subdev_lock_and_get_active_state(sd); - source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, - source_pad); - *source_mbusformat = *v4l2_subdev_get_pad_format(sd, sd_state, - vmux->active); + source_mbusformat = v4l2_subdev_state_get_format(sd_state, + source_pad); + *source_mbusformat = *v4l2_subdev_state_get_format(sd_state, + vmux->active); v4l2_subdev_unlock_state(sd_state); } else { if (vmux->active != local->index) @@ -154,11 +154,11 @@ static int video_mux_set_format(struct v4l2_subdev *sd, struct media_pad *pad = &vmux->pads[sdformat->pad]; u16 source_pad = sd->entity.num_pads - 1; - mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); + mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); if (!mbusformat) return -EINVAL; - source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, source_pad); + source_mbusformat = v4l2_subdev_state_get_format(sd_state, source_pad); if (!source_mbusformat) return -EINVAL; @@ -268,8 +268,8 @@ static int video_mux_set_format(struct v4l2_subdev *sd, /* Source pad mirrors active sink pad, no limitations on sink pads */ if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0) - sdformat->format = *v4l2_subdev_get_pad_format(sd, sd_state, - vmux->active); + sdformat->format = *v4l2_subdev_state_get_format(sd_state, + vmux->active); *mbusformat = sdformat->format; @@ -292,7 +292,7 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd, mutex_lock(&vmux->lock); for (i = 0; i < sd->entity.num_pads; i++) { - mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, i); + mbusformat = v4l2_subdev_state_get_format(sd_state, i); *mbusformat = video_mux_format_mbus_default; } diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index d4f66e93eabd..bca8ec94ee35 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -653,8 +653,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&xcsi2rxss->subdev, - sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &xcsi2rxss->format; default: @@ -671,7 +670,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd, mutex_lock(&xcsi2rxss->lock); for (i = 0; i < XCSI_MEDIA_PADS; i++) { - format = v4l2_subdev_get_try_format(sd, sd_state, i); + format = v4l2_subdev_state_get_format(sd_state, i); *format = xcsi2rxss->default_format; } mutex_unlock(&xcsi2rxss->lock); diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c index 80353ca44402..e05e528ffc6f 100644 --- a/drivers/media/platform/xilinx/xilinx-tpg.c +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -256,8 +256,7 @@ __xtpg_get_pad_format(struct xtpg_device *xtpg, { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, - sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &xtpg->formats[pad]; default: @@ -326,7 +325,7 @@ static int xtpg_enum_frame_size(struct v4l2_subdev *subdev, { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad); + format = v4l2_subdev_state_get_format(sd_state, fse->pad); if (fse->index || fse->code != format->code) return -EINVAL; @@ -354,11 +353,11 @@ static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct xtpg_device *xtpg = to_tpg(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(subdev, fh->state, 0); + format = v4l2_subdev_state_get_format(fh->state, 0); *format = xtpg->default_format; if (xtpg->npads == 2) { - format = v4l2_subdev_get_try_format(subdev, fh->state, 1); + format = v4l2_subdev_state_get_format(fh->state, 1); *format = xtpg->default_format; } diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c index 5b214bf7f93a..f1574edd2b43 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.c +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -260,7 +260,7 @@ int xvip_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(subdev, sd_state, code->pad); + format = v4l2_subdev_state_get_format(sd_state, code->pad); code->code = format->code; @@ -295,7 +295,7 @@ int xvip_enum_frame_size(struct v4l2_subdev *subdev, if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; - format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad); + format = v4l2_subdev_state_get_format(sd_state, fse->pad); if (fse->index || fse->code != format->code) return -EINVAL; diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c index f671251fdf0e..a2fb32c97c84 100644 --- a/drivers/media/test-drivers/vimc/vimc-debayer.c +++ b/drivers/media/test-drivers/vimc/vimc-debayer.c @@ -157,11 +157,11 @@ static int vimc_debayer_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; unsigned int i; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); *mf = sink_fmt_default; for (i = 1; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, sd_state, i); + mf = v4l2_subdev_state_get_format(sd_state, i); *mf = sink_fmt_default; mf->code = vdebayer->src_code; } @@ -221,7 +221,7 @@ static int vimc_debayer_get_fmt(struct v4l2_subdev *sd, /* Get the current sink format */ fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, sd_state, 0) : + *v4l2_subdev_state_get_format(sd_state, 0) : vdebayer->sink_fmt; /* Set the right code for the source pad */ @@ -267,8 +267,8 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, sink_fmt = &vdebayer->sink_fmt; src_code = &vdebayer->src_code; } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code; + sink_fmt = v4l2_subdev_state_get_format(sd_state, 0); + src_code = &v4l2_subdev_state_get_format(sd_state, 1)->code; } /* diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c index b671774e2784..f6592a789f1e 100644 --- a/drivers/media/test-drivers/vimc/vimc-scaler.c +++ b/drivers/media/test-drivers/vimc/vimc-scaler.c @@ -78,11 +78,11 @@ static int vimc_scaler_init_cfg(struct v4l2_subdev *sd, unsigned int i; for (i = 0; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, sd_state, i); + mf = v4l2_subdev_state_get_format(sd_state, i); *mf = fmt_default; } - r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCALER_SINK); + r = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); *r = crop_rect_default; return 0; @@ -138,7 +138,7 @@ vimc_scaler_pad_format(struct vimc_scaler_device *vscaler, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&vscaler->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &vscaler->fmt[pad]; } @@ -149,8 +149,7 @@ vimc_scaler_pad_crop(struct vimc_scaler_device *vscaler, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&vscaler->sd, sd_state, - VIMC_SCALER_SINK); + return v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); else return &vscaler->crop_rect; } diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 41a3dce2d714..676ab503f0ca 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -49,7 +49,7 @@ static int vimc_sensor_init_cfg(struct v4l2_subdev *sd, for (i = 0; i < sd->entity.num_pads; i++) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, i); + mf = v4l2_subdev_state_get_format(sd_state, i); *mf = fmt_default; } @@ -100,7 +100,7 @@ static int vimc_sensor_get_fmt(struct v4l2_subdev *sd, container_of(sd, struct vimc_sensor_device, sd); fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) : + *v4l2_subdev_state_get_format(sd_state, fmt->pad) : vsensor->mbus_format; return 0; @@ -159,7 +159,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, mf = &vsensor->mbus_format; } else { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); } /* Set the new format */ diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 58cddf11c9ab..5d89e4c1b0c2 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -361,7 +361,7 @@ gc0310_get_pad_format(struct gc0310_device *dev, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&dev->sd, state, pad); + return v4l2_subdev_state_get_format(state, pad); return &dev->mode.fmt; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 5e438c5fd4a9..9c20fe915238 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -561,7 +561,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; mutex_unlock(&dev->input_lock); return 0; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index db76f52e1dc8..8105365fbb2a 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -666,7 +666,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, fmt->height = res->height; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; return 0; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index ae70e04040dd..1de63c82cce1 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -671,7 +671,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; return 0; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index abf55a86f795..89118438a3b6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -29,8 +29,7 @@ v4l2_mbus_framefmt *__csi2_get_format(struct atomisp_mipi_csi2_device *csi2, unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &csi2->formats[pad]; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 471912dea5cd..a87fc74159e2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -240,9 +240,9 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, if (which == V4L2_SUBDEV_FORMAT_TRY) { switch (target) { case V4L2_SEL_TGT_CROP: - return v4l2_subdev_get_try_crop(sd, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); case V4L2_SEL_TGT_COMPOSE: - return v4l2_subdev_get_try_compose(sd, sd_state, pad); + return v4l2_subdev_state_get_compose(sd_state, pad); } } @@ -264,7 +264,7 @@ struct v4l2_mbus_framefmt struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &isp_sd->fmt[pad].fmt; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index b2376ebf45a1..92e61ee90993 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd, /* only raw8 grbg is supported by TPG */ fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_pad_format(sd, sd_state, 0) = *fmt; + *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; return 0; } return 0; diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c index b63eea8f4fc0..468568b5bb7a 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c +++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c @@ -821,7 +821,7 @@ static void isc_try_fse(struct isc_device *isc, struct v4l2_subdev_state *sd_state) { struct v4l2_rect *try_crop = - v4l2_subdev_get_pad_crop(isc->current_subdev->sd, sd_state, 0); + v4l2_subdev_state_get_crop(sd_state, 0); struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_TRY, }; diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index ac5fb332088e..61d69f19657e 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -82,10 +82,8 @@ static struct v4l2_mbus_framefmt * __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { - struct imx_ic_priv *ic_priv = priv->ic_priv; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &priv->format_mbus; } diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 9b81cfbcd777..ec73c901079e 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -790,10 +790,8 @@ static struct v4l2_mbus_framefmt * __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { - struct imx_ic_priv *ic_priv = priv->ic_priv; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &priv->format_mbus[pad]; } diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index dda1ebc34692..33902f5daf80 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1148,7 +1148,7 @@ __csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &priv->format_mbus[pad]; } @@ -1158,8 +1158,7 @@ __csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&priv->sd, sd_state, - CSI_SINK_PAD); + return v4l2_subdev_state_get_crop(sd_state, CSI_SINK_PAD); else return &priv->crop; } @@ -1169,8 +1168,7 @@ __csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_compose(&priv->sd, sd_state, - CSI_SINK_PAD); + return v4l2_subdev_state_get_compose(sd_state, CSI_SINK_PAD); else return &priv->compose; } diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 064dc562bc96..ec4349ab48cd 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -445,7 +445,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd, if (ret) continue; - mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad); + mf_try = v4l2_subdev_state_get_format(sd_state, pad); *mf_try = format.format; } diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 3c2093c520ba..792bca1d2d25 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -536,7 +536,7 @@ __vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &priv->format_mbus[pad]; } diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index b2d8476d83a0..6906220ee89e 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -501,7 +501,7 @@ __csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi2->sd, sd_state, pad); + return v4l2_subdev_state_get_format(sd_state, pad); else return &csi2->format_mbus; } diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index e530767e80a5..0fe2b858da83 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -36,7 +36,7 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Initialize try_fmt */ for (i = 0; i < IMGU_NODE_NUM; i++) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, i); + v4l2_subdev_state_get_format(fh->state, i); try_fmt->width = try_crop.width; try_fmt->height = try_crop.height; @@ -44,8 +44,8 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) try_fmt->field = V4L2_FIELD_NONE; } - *v4l2_subdev_get_try_crop(sd, fh->state, IMGU_NODE_IN) = try_crop; - *v4l2_subdev_get_try_compose(sd, fh->state, IMGU_NODE_IN) = try_crop; + *v4l2_subdev_state_get_crop(fh->state, IMGU_NODE_IN) = try_crop; + *v4l2_subdev_state_get_compose(fh->state, IMGU_NODE_IN) = try_crop; return 0; } @@ -136,7 +136,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { fmt->format = imgu_pipe->nodes[pad].pad_fmt; } else { - mf = v4l2_subdev_get_try_format(sd, sd_state, pad); + mf = v4l2_subdev_state_get_format(sd_state, pad); fmt->format = *mf; } @@ -161,7 +161,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd, imgu_pipe = &imgu->imgu_pipe[pipe]; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - mf = v4l2_subdev_get_try_format(sd, sd_state, pad); + mf = v4l2_subdev_state_get_format(sd_state, pad); else mf = &imgu_pipe->nodes[pad].pad_fmt; @@ -194,7 +194,7 @@ imgu_subdev_get_crop(struct imgu_v4l2_subdev *sd, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&sd->subdev, sd_state, pad); + return v4l2_subdev_state_get_crop(sd_state, pad); else return &sd->rect.eff; } @@ -205,7 +205,7 @@ imgu_subdev_get_compose(struct imgu_v4l2_subdev *sd, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_compose(&sd->subdev, sd_state, pad); + return v4l2_subdev_state_get_compose(sd_state, pad); else return &sd->rect.bds; } diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index bdc44c1290ad..0e6c5bd81930 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -830,8 +830,7 @@ __csi2_get_format(struct iss_csi2_device *csi2, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &csi2->formats[pad]; } diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c index 7c96fbf7a170..4a4eae290d65 100644 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ b/drivers/staging/media/omap4iss/iss_ipipe.c @@ -180,8 +180,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &ipipe->formats[pad]; } diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 93a4dbec1428..8fa99532d9d4 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -361,8 +361,7 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &ipipeif->formats[pad]; } diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 6bb906cc17f0..58e698ef9108 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -420,8 +420,7 @@ __resizer_get_format(struct iss_resizer_device *resizer, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&resizer->subdev, sd_state, - pad); + return v4l2_subdev_state_get_format(sd_state, pad); return &resizer->formats[pad]; } diff --git a/drivers/staging/media/starfive/camss/stf-isp.c b/drivers/staging/media/starfive/camss/stf-isp.c index 4205671214b2..893dbd8cddc8 100644 --- a/drivers/staging/media/starfive/camss/stf-isp.c +++ b/drivers/staging/media/starfive/camss/stf-isp.c @@ -66,8 +66,8 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable) struct v4l2_rect *crop; sd_state = v4l2_subdev_lock_and_get_active_state(sd); - fmt = v4l2_subdev_get_pad_format(sd, sd_state, STF_ISP_PAD_SINK); - crop = v4l2_subdev_get_pad_crop(sd, sd_state, STF_ISP_PAD_SRC); + fmt = v4l2_subdev_state_get_format(sd_state, STF_ISP_PAD_SINK); + crop = v4l2_subdev_state_get_crop(sd_state, STF_ISP_PAD_SRC); if (enable) { stf_isp_reset(isp_dev); @@ -131,8 +131,8 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > ARRAY_SIZE(isp_formats_source)) return -EINVAL; - sink_fmt = v4l2_subdev_get_pad_format(sd, state, - STF_ISP_PAD_SRC); + sink_fmt = v4l2_subdev_state_get_format(state, + STF_ISP_PAD_SRC); code->code = sink_fmt->code; if (!code->code) @@ -150,7 +150,7 @@ static int isp_set_format(struct v4l2_subdev *sd, struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + format = v4l2_subdev_state_get_format(state, fmt->pad); if (!format) return -EINVAL; @@ -188,8 +188,7 @@ static void isp_try_crop(struct stf_isp_dev *isp_dev, struct v4l2_rect *crop) { struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_pad_format(&isp_dev->subdev, state, - STF_ISP_PAD_SINK); + v4l2_subdev_state_get_format(state, STF_ISP_PAD_SINK); const struct v4l2_rect bounds = { .width = fmt->width, @@ -212,20 +211,20 @@ static int isp_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: if (sel->pad == STF_ISP_PAD_SINK) { - fmt.format = *v4l2_subdev_get_pad_format(sd, state, - sel->pad); + fmt.format = *v4l2_subdev_state_get_format(state, + sel->pad); sel->r.left = 0; sel->r.top = 0; sel->r.width = fmt.format.width; sel->r.height = fmt.format.height; } else if (sel->pad == STF_ISP_PAD_SRC) { - rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + rect = v4l2_subdev_state_get_crop(state, sel->pad); sel->r = *rect; } break; case V4L2_SEL_TGT_CROP: - rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + rect = v4l2_subdev_state_get_crop(state, sel->pad); if (!rect) return -EINVAL; @@ -253,7 +252,7 @@ static int isp_set_selection(struct v4l2_subdev *sd, sel->pad == STF_ISP_PAD_SINK) { struct v4l2_subdev_selection crop = { 0 }; - rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + rect = v4l2_subdev_state_get_crop(state, sel->pad); if (!rect) return -EINVAL; @@ -270,7 +269,7 @@ static int isp_set_selection(struct v4l2_subdev *sd, sel->pad == STF_ISP_PAD_SRC) { struct v4l2_subdev_format fmt = { 0 }; - rect = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + rect = v4l2_subdev_state_get_crop(state, sel->pad); if (!rect) return -EINVAL; diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c index ccbb530aa2e2..b2ce0d4fae95 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c @@ -262,7 +262,7 @@ static int sun6i_isp_proc_init_cfg(struct v4l2_subdev *subdev, struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_ISP_PROC_PAD_SINK_CSI; struct v4l2_mbus_framefmt *mbus_format = - v4l2_subdev_get_try_format(subdev, state, pad); + v4l2_subdev_state_get_format(state, pad); struct mutex *lock = &isp_dev->proc.lock; mutex_lock(lock); @@ -302,8 +302,8 @@ static int sun6i_isp_proc_get_fmt(struct v4l2_subdev *subdev, mutex_lock(lock); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *mbus_format = *v4l2_subdev_get_try_format(subdev, state, - format->pad); + *mbus_format = *v4l2_subdev_state_get_format(state, + format->pad); else *mbus_format = isp_dev->proc.mbus_format; @@ -325,7 +325,7 @@ static int sun6i_isp_proc_set_fmt(struct v4l2_subdev *subdev, sun6i_isp_proc_mbus_format_prepare(mbus_format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *v4l2_subdev_state_get_format(state, format->pad) = *mbus_format; else isp_dev->proc.mbus_format = *mbus_format; diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 87e5365defae..e0bb59ee3c09 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -474,7 +474,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, * Attempt to obtain the format size from subdev. * If not available, try to get crop boundary from subdev. */ - try_crop = v4l2_subdev_get_pad_crop(subdev, sd_state, 0); + try_crop = v4l2_subdev_state_get_crop(sd_state, 0); fse.code = fmtinfo->code; ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse); if (ret) { From 34dfd1dd52660dc85d43c92c2cb8029efb2bb8f3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Oct 2023 10:09:21 +0200 Subject: [PATCH 1341/7721] media: v4l: subdev: Remove stream-unaware sub-device state access Remove stream-unaware sub-device state access functions and macros. These are no longer used. [Sakari Ailus: Resolve a minor conflict in removed code.] Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 77 ------------------------------------- 1 file changed, 77 deletions(-) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 80744d87bae4..2a438e516095 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1137,83 +1137,6 @@ struct v4l2_subdev_fh { #define to_v4l2_subdev_fh(fh) \ container_of(fh, struct v4l2_subdev_fh, vfh) -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - -/** - * v4l2_subdev_get_pad_format - ancillary routine to get - * &struct v4l2_subdev_pad_config->format - * - * @sd: pointer to &struct v4l2_subdev - * @state: pointer to &struct v4l2_subdev_state - * @pad: index of the pad in the &struct v4l2_subdev_state->pads array - */ -static inline struct v4l2_mbus_framefmt * -v4l2_subdev_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - unsigned int pad) -{ - if (WARN_ON(!state)) - return NULL; - if (WARN_ON(pad >= sd->entity.num_pads)) - pad = 0; - return &state->pads[pad].format; -} - -/** - * v4l2_subdev_get_pad_crop - ancillary routine to get - * &struct v4l2_subdev_pad_config->crop - * - * @sd: pointer to &struct v4l2_subdev - * @state: pointer to &struct v4l2_subdev_state. - * @pad: index of the pad in the &struct v4l2_subdev_state->pads array. - */ -static inline struct v4l2_rect * -v4l2_subdev_get_pad_crop(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - unsigned int pad) -{ - if (WARN_ON(!state)) - return NULL; - if (WARN_ON(pad >= sd->entity.num_pads)) - pad = 0; - return &state->pads[pad].crop; -} - -/** - * v4l2_subdev_get_pad_compose - ancillary routine to get - * &struct v4l2_subdev_pad_config->compose - * - * @sd: pointer to &struct v4l2_subdev - * @state: pointer to &struct v4l2_subdev_state. - * @pad: index of the pad in the &struct v4l2_subdev_state->pads array. - */ -static inline struct v4l2_rect * -v4l2_subdev_get_pad_compose(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - unsigned int pad) -{ - if (WARN_ON(!state)) - return NULL; - if (WARN_ON(pad >= sd->entity.num_pads)) - pad = 0; - return &state->pads[pad].compose; -} - -/* - * Temprary helpers until uses of v4l2_subdev_get_try_* functions have been - * renamed - */ -#define v4l2_subdev_get_try_format(sd, state, pad) \ - v4l2_subdev_get_pad_format(sd, state, pad) - -#define v4l2_subdev_get_try_crop(sd, state, pad) \ - v4l2_subdev_get_pad_crop(sd, state, pad) - -#define v4l2_subdev_get_try_compose(sd, state, pad) \ - v4l2_subdev_get_pad_compose(sd, state, pad) - -#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ - extern const struct v4l2_file_operations v4l2_subdev_fops; /** From 3591c53ae9eccafbeffa9ae2d1899873a5076a87 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 25 Oct 2023 12:22:56 +0200 Subject: [PATCH 1342/7721] media: v4l: subdev: Return NULL from pad access functions on error Return NULL from sub-device pad state access functions (v4l2_subdev_state_get_{format,crop,compose}) for non-existent pads. While this behaviour differs from older set of pad state information access functions, we've had a WARN_ON() there for a long time and callers also do validate the pad index nowadays. Therefore problems are not expected. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 36 +++++---------------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 41fe9fa5c21a..985873b7981e 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1545,16 +1545,8 @@ __v4l2_subdev_state_get_format(struct v4l2_subdev_state *state, if (stream) return NULL; - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; + if (pad >= state->sd->entity.num_pads) + return NULL; return &state->pads[pad].format; } @@ -1587,16 +1579,8 @@ __v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad, if (stream) return NULL; - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; + if (pad >= state->sd->entity.num_pads) + return NULL; return &state->pads[pad].crop; } @@ -1629,16 +1613,8 @@ __v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state, if (stream) return NULL; - /* - * Set the pad to 0 on error as this is aligned with the - * behaviour of the pad state information access functions. The - * purpose of setting pad to 0 here is to avoid accessing memory - * outside the pads array, but still issuing warning of the - * invalid access while making the caller's error handling - * easier. - */ - if (WARN_ON_ONCE(pad >= state->sd->entity.num_pads)) - pad = 0; + if (pad >= state->sd->entity.num_pads) + return NULL; return &state->pads[pad].compose; } From 8830bf13af87f69755df0ffca6d0169ed45ac1ee Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:34 +0800 Subject: [PATCH 1343/7721] media: mediatek: vcodec: Get the chip name for each platform Store the name of the chip in the context of the driver in order to be able to choose the correct configuration values for the different codecs. Use a enum value instead of an integer to store a more descriptive name. Signed-off-by: Yunfei Dong Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Sebastian Fricke Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../mediatek/vcodec/decoder/mtk_vcodec_dec.c | 24 +---------------- .../vcodec/decoder/mtk_vcodec_dec_drv.c | 26 +++++++++++++++++++ .../vcodec/decoder/mtk_vcodec_dec_drv.h | 14 ++++++++++ 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c index 91ed576d6821..ba742f0e391d 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c @@ -208,36 +208,14 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } -static int mtk_vcodec_dec_get_chip_name(void *priv) -{ - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); - struct device *dev = &ctx->dev->plat_dev->dev; - - if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec")) - return 8173; - else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec")) - return 8183; - else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec")) - return 8192; - else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")) - return 8195; - else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec")) - return 8186; - else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec")) - return 8188; - else - return 8173; -} - static int vidioc_vdec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); struct device *dev = &ctx->dev->plat_dev->dev; - int platform_name = mtk_vcodec_dec_get_chip_name(priv); strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); - snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", platform_name); + snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", ctx->dev->chip_name); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 0a89ce452ac3..f47c98faf068 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -326,6 +326,26 @@ static const struct v4l2_file_operations mtk_vcodec_fops = { .mmap = v4l2_m2m_fop_mmap, }; +static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev *vdec_dev) +{ + struct device *dev = &vdec_dev->plat_dev->dev; + + if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8173; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8183; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8192; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8195; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8186; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec")) + vdec_dev->chip_name = MTK_VDEC_MT8188; + else + vdec_dev->chip_name = MTK_VDEC_INVAL; +} + static int mtk_vcodec_probe(struct platform_device *pdev) { struct mtk_vcodec_dec_dev *dev; @@ -341,6 +361,12 @@ static int mtk_vcodec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; + mtk_vcodec_dec_get_chip_name(dev); + if (dev->chip_name == MTK_VDEC_INVAL) { + dev_err(&pdev->dev, "Failed to get decoder chip name"); + return -EINVAL; + } + dev->vdec_pdata = of_device_get_match_data(&pdev->dev); if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", &rproc_phandle)) { diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h index 7e36b2c69b7d..849b89dd205c 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h @@ -18,6 +18,16 @@ #define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE) #define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING) +enum mtk_vcodec_dec_chip_name { + MTK_VDEC_INVAL = 0, + MTK_VDEC_MT8173 = 8173, + MTK_VDEC_MT8183 = 8183, + MTK_VDEC_MT8186 = 8186, + MTK_VDEC_MT8188 = 8188, + MTK_VDEC_MT8192 = 8192, + MTK_VDEC_MT8195 = 8195, +}; + /* * enum mtk_vdec_format_types - Structure used to get supported * format types according to decoder capability @@ -249,6 +259,8 @@ struct mtk_vcodec_dec_ctx { * @vdec_racing_info: record register value * @dec_racing_info_mutex: mutex lock used for inner racing mode * @dbgfs: debug log related information + * + * @chip_name: used to distinguish platforms and select the correct codec configuration values */ struct mtk_vcodec_dec_dev { struct v4l2_device v4l2_dev; @@ -289,6 +301,8 @@ struct mtk_vcodec_dec_dev { /* Protects access to vdec_racing_info data */ struct mutex dec_racing_info_mutex; struct mtk_vcodec_dbgfs dbgfs; + + enum mtk_vcodec_dec_chip_name chip_name; }; static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh) From b1b37f6f23c2691245e71ea38c71a249e01e7b6e Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:35 +0800 Subject: [PATCH 1344/7721] media: mediatek: vcodec: Set the supported h264 level for each platform Set the maximum H264 codec level for each platform. The various mediatek platforms support different levels for decoding, the level of the codec limits among others the maximum resolution, bit rate and frame rate for the decoder. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index e29c9c58f3da..7aaf0db13a76 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -56,6 +56,15 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { }, .codec_type = V4L2_PIX_FMT_H264_SLICE, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .def = V4L2_MPEG_VIDEO_H264_LEVEL_4_1, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, { .cfg = { .id = V4L2_CID_STATELESS_H264_DECODE_MODE, @@ -519,6 +528,40 @@ static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { .s_ctrl = mtk_vdec_s_ctrl, }; +static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8192: + case MTK_VDEC_MT8188: + cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + break; + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0; + break; + case MTK_VDEC_MT8183: + case MTK_VDEC_MT8186: + cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + break; + }; +} + +static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (cfg->id) { + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + mtk_vcodec_dec_fill_h264_level(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "h264 supported level: %lld %lld", cfg->max, cfg->def); + break; + default: + break; + }; +} + static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_dec_ctx *ctx) { unsigned int i; @@ -532,6 +575,8 @@ static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_dec_ctx *ctx) for (i = 0; i < NUM_CTRLS; i++) { struct v4l2_ctrl_config cfg = mtk_stateless_controls[i].cfg; cfg.ops = &mtk_vcodec_dec_ctrl_ops; + + mtk_vcodec_dec_reset_controls(&cfg, ctx); v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL); if (ctx->ctrl_hdl.error) { mtk_v4l2_vdec_err(ctx, "Adding control %d failed %d", i, From 23ad34b8b019dc606f4fb4cfd183d2b2f7858ff4 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:36 +0800 Subject: [PATCH 1345/7721] media: mediatek: vcodec: Set the supported h265 level for each platform Set the maximum H265 codec level for each platform. The various mediatek platforms support different levels for decoding, the level of the codec limits among others the maximum resolution, bit rate and frame rate for the decoder. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index 7aaf0db13a76..f68518ba57c5 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -147,6 +147,16 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { }, .codec_type = V4L2_PIX_FMT_HEVC_SLICE, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .def = V4L2_MPEG_VIDEO_HEVC_LEVEL_4, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1, + }, + .codec_type = V4L2_PIX_FMT_HEVC_SLICE, + }, + { .cfg = { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, @@ -549,6 +559,22 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg, }; } +static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8188: + cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1; + break; + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4; + break; + }; +} + static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, struct mtk_vcodec_dec_ctx *ctx) { @@ -557,6 +583,10 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, mtk_vcodec_dec_fill_h264_level(cfg, ctx); mtk_v4l2_vdec_dbg(3, ctx, "h264 supported level: %lld %lld", cfg->max, cfg->def); break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + mtk_vcodec_dec_fill_h265_level(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "h265 supported level: %lld %lld", cfg->max, cfg->def); + break; default: break; }; From c3caa86b43f5df80d311e1207a8e02300b18d75f Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:37 +0800 Subject: [PATCH 1346/7721] media: mediatek: vcodec: Set the supported h264 profile for each platform Set the maximum H264 codec profile for each platform. The various mediatek platforms support different profiles for decoding, the profile of the codec limits the capabilities for decoding. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index f68518ba57c5..a93098b3a390 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -559,6 +559,20 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg, }; } +static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8188: + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + break; + }; +} + static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg, struct mtk_vcodec_dec_ctx *ctx) { @@ -587,6 +601,11 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, mtk_vcodec_dec_fill_h265_level(cfg, ctx); mtk_v4l2_vdec_dbg(3, ctx, "h265 supported level: %lld %lld", cfg->max, cfg->def); break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + mtk_vcodec_dec_fill_h264_profile(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "h264 supported profile: %lld %lld", cfg->max, + cfg->menu_skip_mask); + break; default: break; }; From 3572c870e91b9a7a5174de27a42996029133787e Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:38 +0800 Subject: [PATCH 1347/7721] media: mediatek: vcodec: Set the supported h265 profile for each platform Set the maximum H265 codec profile for each platform. The various mediatek platforms support different profiles for decoding, the profile of the codec limits the capabilities for decoding. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index a93098b3a390..816709fe0f18 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -589,6 +589,20 @@ static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg, }; } +static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8188: + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + break; + }; +} + static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, struct mtk_vcodec_dec_ctx *ctx) { @@ -606,6 +620,11 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, mtk_v4l2_vdec_dbg(3, ctx, "h264 supported profile: %lld %lld", cfg->max, cfg->menu_skip_mask); break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + mtk_vcodec_dec_fill_h265_profile(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "h265 supported profile: %lld %lld", cfg->max, + cfg->menu_skip_mask); + break; default: break; }; From 6147bdd895df0e209110684c760c9463dadc7822 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:39 +0800 Subject: [PATCH 1348/7721] media: mediatek: vcodec: Set the supported vp9 level for each platform Set the maximum VP9 codec level for each platform. The various mediatek platforms support different levels for decoding, the level of the codec limits among others the maximum resolution, bit rate, frame rate and compression rate for the decoder. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index 816709fe0f18..eb8590edb579 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -113,6 +113,15 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { }, .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .def = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_SPS, @@ -603,6 +612,26 @@ static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg, }; } +static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8192: + case MTK_VDEC_MT8188: + cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1; + break; + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2; + break; + case MTK_VDEC_MT8186: + cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0; + break; + }; +} + static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, struct mtk_vcodec_dec_ctx *ctx) { @@ -615,6 +644,10 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, mtk_vcodec_dec_fill_h265_level(cfg, ctx); mtk_v4l2_vdec_dbg(3, ctx, "h265 supported level: %lld %lld", cfg->max, cfg->def); break; + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: + mtk_vcodec_dec_fill_vp9_level(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "vp9 supported level: %lld %lld", cfg->max, cfg->def); + break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: mtk_vcodec_dec_fill_h264_profile(cfg, ctx); mtk_v4l2_vdec_dbg(3, ctx, "h264 supported profile: %lld %lld", cfg->max, From a00b3f296eac3d43328615c3113e1a74143fc67a Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Mon, 23 Oct 2023 11:06:40 +0800 Subject: [PATCH 1349/7721] media: mediatek: vcodec: Set the supported vp9 profile for each platform Set the maximum VP9 codec profile for each platform. The various mediatek platforms support different profiles for decoding, the profile of the codec limits the capabilities for decoding. Signed-off-by: Yunfei Dong Reviewed-by: Sebastian Fricke Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Fricke Signed-off-by: Hans Verkuil --- .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index eb8590edb579..d54b3833790d 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -109,7 +109,8 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .menu_skip_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_1), }, .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, @@ -632,6 +633,20 @@ static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg, }; } +static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg, + struct mtk_vcodec_dec_ctx *ctx) +{ + switch (ctx->dev->chip_name) { + case MTK_VDEC_MT8188: + case MTK_VDEC_MT8195: + cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2; + break; + default: + cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1; + break; + }; +} + static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, struct mtk_vcodec_dec_ctx *ctx) { @@ -658,6 +673,11 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, mtk_v4l2_vdec_dbg(3, ctx, "h265 supported profile: %lld %lld", cfg->max, cfg->menu_skip_mask); break; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + mtk_vcodec_dec_fill_vp9_profile(cfg, ctx); + mtk_v4l2_vdec_dbg(3, ctx, "vp9 supported profile: %lld %lld", cfg->max, + cfg->menu_skip_mask); + break; default: break; }; From b8d78cb2e24d92352878a9f6525aec002c891528 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Thu, 23 Nov 2023 02:04:39 +0200 Subject: [PATCH 1350/7721] libbpf: Start v1.4 development cycle Bump libbpf.map to v1.4.0 to start a new libbpf version cycle. Signed-off-by: Eduard Zingerman Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231123000439.12025-1-eddyz87@gmail.com --- tools/lib/bpf/libbpf.map | 3 +++ tools/lib/bpf/libbpf_version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index b52dc28dc8af..91c5aef7dae7 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -409,3 +409,6 @@ LIBBPF_1.3.0 { ring__size; ring_buffer__ring; } LIBBPF_1.2.0; + +LIBBPF_1.4.0 { +} LIBBPF_1.3.0; diff --git a/tools/lib/bpf/libbpf_version.h b/tools/lib/bpf/libbpf_version.h index 290411ddb39e..e783a47da815 100644 --- a/tools/lib/bpf/libbpf_version.h +++ b/tools/lib/bpf/libbpf_version.h @@ -4,6 +4,6 @@ #define __LIBBPF_VERSION_H #define LIBBPF_MAJOR_VERSION 1 -#define LIBBPF_MINOR_VERSION 3 +#define LIBBPF_MINOR_VERSION 4 #endif /* __LIBBPF_VERSION_H */ From 80abebd9bf72516a3a6ed50f69908b9dbbf72a93 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 23 Nov 2023 14:32:12 +0100 Subject: [PATCH 1351/7721] dt-bindings: interconnect: document the RPMh Network-On-Chip Interconnect in Qualcomm SM8650 SoC Document the RPMh Network-On-Chip Interconnect of the SM8650 platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231123-topic-sm8650-upstream-interconnect-v2-1-7e050874f59b@linaro.org Signed-off-by: Georgi Djakov --- .../interconnect/qcom,sm8650-rpmh.yaml | 136 ++++++++++++++++ .../interconnect/qcom,sm8650-rpmh.h | 154 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sm8650-rpmh.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml new file mode 100644 index 000000000000..f9322de7cd61 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm8650-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on SM8650 + +maintainers: + - Abel Vesa + - Neil Armstrong + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,sm8650-rpmh.h + +properties: + compatible: + enum: + - qcom,sm8650-aggre1-noc + - qcom,sm8650-aggre2-noc + - qcom,sm8650-clk-virt + - qcom,sm8650-cnoc-main + - qcom,sm8650-config-noc + - qcom,sm8650-gem-noc + - qcom,sm8650-lpass-ag-noc + - qcom,sm8650-lpass-lpiaon-noc + - qcom,sm8650-lpass-lpicx-noc + - qcom,sm8650-mc-virt + - qcom,sm8650-mmss-noc + - qcom,sm8650-nsp-noc + - qcom,sm8650-pcie-anoc + - qcom,sm8650-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-clk-virt + - qcom,sm8650-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-pcie-anoc + then: + properties: + clocks: + items: + - description: aggre-NOC PCIe AXI clock + - description: cfg-NOC PCIe a-NOC AHB clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre1-noc + then: + properties: + clocks: + items: + - description: aggre UFS PHY AXI clock + - description: aggre USB3 PRIM AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre2-noc + then: + properties: + clocks: + items: + - description: RPMH CC IPA clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre1-noc + - qcom,sm8650-aggre2-noc + - qcom,sm8650-pcie-anoc + then: + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,sm8650-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8650-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + clocks = <&gcc_phy_axi_clk>, <&gcc_prim_axi_clk>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h b/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h new file mode 100644 index 000000000000..6c1eaf04e241 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM8650_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM8650_H + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_1 1 +#define MASTER_QUP_3 2 +#define MASTER_SDCC_4 3 +#define MASTER_UFS_MEM 4 +#define MASTER_USB3_0 5 +#define SLAVE_A1NOC_SNOC 6 + +#define MASTER_QDSS_BAM 0 +#define MASTER_QUP_2 1 +#define MASTER_CRYPTO 2 +#define MASTER_IPA 3 +#define MASTER_SP 4 +#define MASTER_QDSS_ETR 5 +#define MASTER_QDSS_ETR_1 6 +#define MASTER_SDCC_2 7 +#define SLAVE_A2NOC_SNOC 8 + +#define MASTER_QUP_CORE_0 0 +#define MASTER_QUP_CORE_1 1 +#define MASTER_QUP_CORE_2 2 +#define SLAVE_QUP_CORE_0 3 +#define SLAVE_QUP_CORE_1 4 +#define SLAVE_QUP_CORE_2 5 + +#define MASTER_CNOC_CFG 0 +#define SLAVE_AHB2PHY_SOUTH 1 +#define SLAVE_AHB2PHY_NORTH 2 +#define SLAVE_CAMERA_CFG 3 +#define SLAVE_CLK_CTL 4 +#define SLAVE_RBCPR_CX_CFG 5 +#define SLAVE_CPR_HMX 6 +#define SLAVE_RBCPR_MMCX_CFG 7 +#define SLAVE_RBCPR_MXA_CFG 8 +#define SLAVE_RBCPR_MXC_CFG 9 +#define SLAVE_CPR_NSPCX 10 +#define SLAVE_CRYPTO_0_CFG 11 +#define SLAVE_CX_RDPM 12 +#define SLAVE_DISPLAY_CFG 13 +#define SLAVE_GFX3D_CFG 14 +#define SLAVE_I2C 15 +#define SLAVE_I3C_IBI0_CFG 16 +#define SLAVE_I3C_IBI1_CFG 17 +#define SLAVE_IMEM_CFG 18 +#define SLAVE_CNOC_MSS 19 +#define SLAVE_MX_2_RDPM 20 +#define SLAVE_MX_RDPM 21 +#define SLAVE_PCIE_0_CFG 22 +#define SLAVE_PCIE_1_CFG 23 +#define SLAVE_PCIE_RSCC 24 +#define SLAVE_PDM 25 +#define SLAVE_PRNG 26 +#define SLAVE_QDSS_CFG 27 +#define SLAVE_QSPI_0 28 +#define SLAVE_QUP_3 29 +#define SLAVE_QUP_1 30 +#define SLAVE_QUP_2 31 +#define SLAVE_SDCC_2 32 +#define SLAVE_SDCC_4 33 +#define SLAVE_SPSS_CFG 34 +#define SLAVE_TCSR 35 +#define SLAVE_TLMM 36 +#define SLAVE_UFS_MEM_CFG 37 +#define SLAVE_USB3_0 38 +#define SLAVE_VENUS_CFG 39 +#define SLAVE_VSENSE_CTRL_CFG 40 +#define SLAVE_CNOC_MNOC_CFG 41 +#define SLAVE_NSP_QTB_CFG 42 +#define SLAVE_PCIE_ANOC_CFG 43 +#define SLAVE_SERVICE_CNOC_CFG 44 +#define SLAVE_QDSS_STM 45 +#define SLAVE_TCU 46 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define SLAVE_AOSS 2 +#define SLAVE_IPA_CFG 3 +#define SLAVE_IPC_ROUTER_CFG 4 +#define SLAVE_TME_CFG 5 +#define SLAVE_APPSS 6 +#define SLAVE_CNOC_CFG 7 +#define SLAVE_DDRSS_CFG 8 +#define SLAVE_IMEM 9 +#define SLAVE_SERVICE_CNOC 10 +#define SLAVE_PCIE_0 11 +#define SLAVE_PCIE_1 12 + +#define MASTER_GPU_TCU 0 +#define MASTER_SYS_TCU 1 +#define MASTER_UBWC_P_TCU 2 +#define MASTER_APPSS_PROC 3 +#define MASTER_GFX3D 4 +#define MASTER_LPASS_GEM_NOC 5 +#define MASTER_MSS_PROC 6 +#define MASTER_MNOC_HF_MEM_NOC 7 +#define MASTER_MNOC_SF_MEM_NOC 8 +#define MASTER_COMPUTE_NOC 9 +#define MASTER_ANOC_PCIE_GEM_NOC 10 +#define MASTER_SNOC_SF_MEM_NOC 11 +#define MASTER_UBWC_P 12 +#define MASTER_GIC 13 +#define SLAVE_GEM_NOC_CNOC 14 +#define SLAVE_LLCC 15 +#define SLAVE_MEM_NOC_PCIE_SNOC 16 + +#define MASTER_LPIAON_NOC 0 +#define SLAVE_LPASS_GEM_NOC 1 + +#define MASTER_LPASS_LPINOC 0 +#define SLAVE_LPIAON_NOC_LPASS_AG_NOC 1 + +#define MASTER_LPASS_PROC 0 +#define SLAVE_LPICX_NOC_LPIAON_NOC 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 + +#define MASTER_CAMNOC_HF 0 +#define MASTER_CAMNOC_ICP 1 +#define MASTER_CAMNOC_SF 2 +#define MASTER_MDP 3 +#define MASTER_CDSP_HCP 4 +#define MASTER_VIDEO 5 +#define MASTER_VIDEO_CV_PROC 6 +#define MASTER_VIDEO_PROC 7 +#define MASTER_VIDEO_V_PROC 8 +#define MASTER_CNOC_MNOC_CFG 9 +#define SLAVE_MNOC_HF_MEM_NOC 10 +#define SLAVE_MNOC_SF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 + +#define MASTER_CDSP_PROC 0 +#define SLAVE_CDSP_MEM_NOC 1 + +#define MASTER_PCIE_ANOC_CFG 0 +#define MASTER_PCIE_0 1 +#define MASTER_PCIE_1 2 +#define SLAVE_ANOC_PCIE_GEM_NOC 3 +#define SLAVE_SERVICE_PCIE_ANOC 4 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define SLAVE_SNOC_GEM_NOC_SF 2 + +#endif From dc84a76f054c01cc1d769a86ffa3a7e13867915a Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 23 Nov 2023 19:20:27 +0530 Subject: [PATCH 1352/7721] dt-bindings: interconnect: Add Qualcomm X1E80100 SoC The Qualcomm X1E80100 SoC has several bus fabrics that could be controlled and tuned dynamically according to the bandwidth demand. Co-developed-by: Abel Vesa Signed-off-by: Abel Vesa Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231123135028.29433-2-quic_sibis@quicinc.com Signed-off-by: Georgi Djakov --- .../interconnect/qcom,x1e80100-rpmh.yaml | 83 +++++++ .../interconnect/qcom,x1e80100-rpmh.h | 207 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml new file mode 100644 index 000000000000..08b0210e0e59 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,x1e80100-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on X1E80100 + +maintainers: + - Rajendra Nayak + - Abel Vesa + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h + +properties: + compatible: + enum: + - qcom,x1e80100-aggre1-noc + - qcom,x1e80100-aggre2-noc + - qcom,x1e80100-clk-virt + - qcom,x1e80100-cnoc-cfg + - qcom,x1e80100-cnoc-main + - qcom,x1e80100-gem-noc + - qcom,x1e80100-lpass-ag-noc + - qcom,x1e80100-lpass-lpiaon-noc + - qcom,x1e80100-lpass-lpicx-noc + - qcom,x1e80100-mc-virt + - qcom,x1e80100-mmss-noc + - qcom,x1e80100-nsp-noc + - qcom,x1e80100-pcie-center-anoc + - qcom,x1e80100-pcie-north-anoc + - qcom,x1e80100-pcie-south-anoc + - qcom,x1e80100-system-noc + - qcom,x1e80100-usb-center-anoc + - qcom,x1e80100-usb-north-anoc + - qcom,x1e80100-usb-south-anoc + + reg: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,x1e80100-clk-virt + - qcom,x1e80100-mc-virt + then: + properties: + reg: false + else: + required: + - reg + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,x1e80100-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,x1e80100-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h b/include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h new file mode 100644 index 000000000000..a38c3472698a --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_X1E80100_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_X1E80100_H + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_1 1 +#define MASTER_SDCC_4 2 +#define MASTER_UFS_MEM 3 +#define SLAVE_A1NOC_SNOC 4 + +#define MASTER_QUP_0 0 +#define MASTER_QUP_2 1 +#define MASTER_CRYPTO 2 +#define MASTER_SP 3 +#define MASTER_QDSS_ETR 4 +#define MASTER_QDSS_ETR_1 5 +#define MASTER_SDCC_2 6 +#define SLAVE_A2NOC_SNOC 7 + +#define MASTER_DDR_PERF_MODE 0 +#define MASTER_QUP_CORE_0 1 +#define MASTER_QUP_CORE_1 2 +#define MASTER_QUP_CORE_2 3 +#define SLAVE_DDR_PERF_MODE 4 +#define SLAVE_QUP_CORE_0 5 +#define SLAVE_QUP_CORE_1 6 +#define SLAVE_QUP_CORE_2 7 + +#define MASTER_CNOC_CFG 0 +#define SLAVE_AHB2PHY_SOUTH 1 +#define SLAVE_AHB2PHY_NORTH 2 +#define SLAVE_AHB2PHY_2 3 +#define SLAVE_AV1_ENC_CFG 4 +#define SLAVE_CAMERA_CFG 5 +#define SLAVE_CLK_CTL 6 +#define SLAVE_CRYPTO_0_CFG 7 +#define SLAVE_DISPLAY_CFG 8 +#define SLAVE_GFX3D_CFG 9 +#define SLAVE_IMEM_CFG 10 +#define SLAVE_IPC_ROUTER_CFG 11 +#define SLAVE_PCIE_0_CFG 12 +#define SLAVE_PCIE_1_CFG 13 +#define SLAVE_PCIE_2_CFG 14 +#define SLAVE_PCIE_3_CFG 15 +#define SLAVE_PCIE_4_CFG 16 +#define SLAVE_PCIE_5_CFG 17 +#define SLAVE_PCIE_6A_CFG 18 +#define SLAVE_PCIE_6B_CFG 19 +#define SLAVE_PCIE_RSC_CFG 20 +#define SLAVE_PDM 21 +#define SLAVE_PRNG 22 +#define SLAVE_QDSS_CFG 23 +#define SLAVE_QSPI_0 24 +#define SLAVE_QUP_0 25 +#define SLAVE_QUP_1 26 +#define SLAVE_QUP_2 27 +#define SLAVE_SDCC_2 28 +#define SLAVE_SDCC_4 29 +#define SLAVE_SMMUV3_CFG 30 +#define SLAVE_TCSR 31 +#define SLAVE_TLMM 32 +#define SLAVE_UFS_MEM_CFG 33 +#define SLAVE_USB2 34 +#define SLAVE_USB3_0 35 +#define SLAVE_USB3_1 36 +#define SLAVE_USB3_2 37 +#define SLAVE_USB3_MP 38 +#define SLAVE_USB4_0 39 +#define SLAVE_USB4_1 40 +#define SLAVE_USB4_2 41 +#define SLAVE_VENUS_CFG 42 +#define SLAVE_LPASS_QTB_CFG 43 +#define SLAVE_CNOC_MNOC_CFG 44 +#define SLAVE_NSP_QTB_CFG 45 +#define SLAVE_QDSS_STM 46 +#define SLAVE_TCU 47 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define SLAVE_AOSS 2 +#define SLAVE_TME_CFG 3 +#define SLAVE_APPSS 4 +#define SLAVE_CNOC_CFG 5 +#define SLAVE_BOOT_IMEM 6 +#define SLAVE_IMEM 7 +#define SLAVE_PCIE_0 8 +#define SLAVE_PCIE_1 9 +#define SLAVE_PCIE_2 10 +#define SLAVE_PCIE_3 11 +#define SLAVE_PCIE_4 12 +#define SLAVE_PCIE_5 13 +#define SLAVE_PCIE_6A 14 +#define SLAVE_PCIE_6B 15 + +#define MASTER_GPU_TCU 0 +#define MASTER_PCIE_TCU 1 +#define MASTER_SYS_TCU 2 +#define MASTER_APPSS_PROC 3 +#define MASTER_GFX3D 4 +#define MASTER_LPASS_GEM_NOC 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_COMPUTE_NOC 8 +#define MASTER_ANOC_PCIE_GEM_NOC 9 +#define MASTER_SNOC_SF_MEM_NOC 10 +#define MASTER_GIC2 11 +#define SLAVE_GEM_NOC_CNOC 12 +#define SLAVE_LLCC 13 +#define SLAVE_MEM_NOC_PCIE_SNOC 14 +#define MASTER_MNOC_HF_MEM_NOC_DISP 15 +#define MASTER_ANOC_PCIE_GEM_NOC_DISP 16 +#define SLAVE_LLCC_DISP 17 +#define MASTER_ANOC_PCIE_GEM_NOC_PCIE 18 +#define SLAVE_LLCC_PCIE 19 + +#define MASTER_LPIAON_NOC 0 +#define SLAVE_LPASS_GEM_NOC 1 + +#define MASTER_LPASS_LPINOC 0 +#define SLAVE_LPIAON_NOC_LPASS_AG_NOC 1 + +#define MASTER_LPASS_PROC 0 +#define SLAVE_LPICX_NOC_LPIAON_NOC 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 +#define MASTER_LLCC_DISP 2 +#define SLAVE_EBI1_DISP 3 +#define MASTER_LLCC_PCIE 4 +#define SLAVE_EBI1_PCIE 5 + +#define MASTER_AV1_ENC 0 +#define MASTER_CAMNOC_HF 1 +#define MASTER_CAMNOC_ICP 2 +#define MASTER_CAMNOC_SF 3 +#define MASTER_EVA 4 +#define MASTER_MDP 5 +#define MASTER_VIDEO 6 +#define MASTER_VIDEO_CV_PROC 7 +#define MASTER_VIDEO_V_PROC 8 +#define MASTER_CNOC_MNOC_CFG 9 +#define SLAVE_MNOC_HF_MEM_NOC 10 +#define SLAVE_MNOC_SF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 +#define MASTER_MDP_DISP 13 +#define SLAVE_MNOC_HF_MEM_NOC_DISP 14 + +#define MASTER_CDSP_PROC 0 +#define SLAVE_CDSP_MEM_NOC 1 + +#define MASTER_PCIE_NORTH 0 +#define MASTER_PCIE_SOUTH 1 +#define SLAVE_ANOC_PCIE_GEM_NOC 2 +#define MASTER_PCIE_NORTH_PCIE 3 +#define MASTER_PCIE_SOUTH_PCIE 4 +#define SLAVE_ANOC_PCIE_GEM_NOC_PCIE 5 + +#define MASTER_PCIE_3 0 +#define MASTER_PCIE_4 1 +#define MASTER_PCIE_5 2 +#define SLAVE_PCIE_NORTH 3 +#define MASTER_PCIE_3_PCIE 4 +#define MASTER_PCIE_4_PCIE 5 +#define MASTER_PCIE_5_PCIE 6 +#define SLAVE_PCIE_NORTH_PCIE 7 + +#define MASTER_PCIE_0 0 +#define MASTER_PCIE_1 1 +#define MASTER_PCIE_2 2 +#define MASTER_PCIE_6A 3 +#define MASTER_PCIE_6B 4 +#define SLAVE_PCIE_SOUTH 5 +#define MASTER_PCIE_0_PCIE 6 +#define MASTER_PCIE_1_PCIE 7 +#define MASTER_PCIE_2_PCIE 8 +#define MASTER_PCIE_6A_PCIE 9 +#define MASTER_PCIE_6B_PCIE 10 +#define SLAVE_PCIE_SOUTH_PCIE 11 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define MASTER_GIC1 2 +#define MASTER_USB_NOC_SNOC 3 +#define SLAVE_SNOC_GEM_NOC_SF 4 + +#define MASTER_AGGRE_USB_NORTH 0 +#define MASTER_AGGRE_USB_SOUTH 1 +#define SLAVE_USB_NOC_SNOC 2 + +#define MASTER_USB2 0 +#define MASTER_USB3_MP 1 +#define SLAVE_AGGRE_USB_NORTH 2 + +#define MASTER_USB3_0 0 +#define MASTER_USB3_1 1 +#define MASTER_USB3_2 2 +#define MASTER_USB4_0 3 +#define MASTER_USB4_1 4 +#define MASTER_USB4_2 5 +#define SLAVE_AGGRE_USB_SOUTH 6 + +#endif From f061c9f7d058ffc32de66f2efb3e1c368e305423 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 21 Nov 2023 03:48:31 -0800 Subject: [PATCH 1353/7721] Documentation: Document each netlink family This is a simple script that parses the Netlink YAML spec files (Documentation/netlink/specs/), and generates RST files to be rendered in the Network -> Netlink Specification documentation page. Create a python script that is invoked during 'make htmldocs', reads the YAML specs input file and generate the correspondent RST file. Create a new Documentation/networking/netlink_spec index page, and reference each Netlink RST file that was processed above in this main index.rst file. In case of any exception during the parsing, dump the error and skip the file. Do not regenerate the RST files if the input files (YAML) were not changed in-between invocations. Suggested-by: Jakub Kicinski Signed-off-by: Breno Leitao ---- Changelog: V3: * Do not regenerate the RST files if the input files were not changed. In order to do it, a few things changed: - Rely on Makefile more to find what changed, and trigger individual file processing - The script parses file by file now (instead of batches) - Create a new option to generate the index file V2: * Moved the logic from a sphinx extension to a external script * Adjust some formatting as suggested by Donald Hunter and Jakub * Auto generating all the rsts instead of having stubs * Handling error gracefully Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/Makefile | 16 +- Documentation/networking/index.rst | 1 + .../networking/netlink_spec/.gitignore | 1 + .../networking/netlink_spec/readme.txt | 4 + tools/net/ynl/ynl-gen-rst.py | 388 ++++++++++++++++++ 5 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 Documentation/networking/netlink_spec/.gitignore create mode 100644 Documentation/networking/netlink_spec/readme.txt create mode 100755 tools/net/ynl/ynl-gen-rst.py diff --git a/Documentation/Makefile b/Documentation/Makefile index 2f35793acd2a..5c156fbb6cdf 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -97,7 +97,21 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) cp $(if $(patsubst /%,,$(DOCS_CSS)),$(abspath $(srctree)/$(DOCS_CSS)),$(DOCS_CSS)) $(BUILDDIR)/$3/_static/; \ fi -htmldocs: +YNL_INDEX:=$(srctree)/Documentation/networking/netlink_spec/index.rst +YNL_RST_DIR:=$(srctree)/Documentation/networking/netlink_spec +YNL_YAML_DIR:=$(srctree)/Documentation/netlink/specs +YNL_TOOL:=$(srctree)/tools/net/ynl/ynl-gen-rst.py + +YNL_RST_FILES_TMP := $(patsubst %.yaml,%.rst,$(wildcard $(YNL_YAML_DIR)/*.yaml)) +YNL_RST_FILES := $(patsubst $(YNL_YAML_DIR)%,$(YNL_RST_DIR)%, $(YNL_RST_FILES_TMP)) + +$(YNL_INDEX): $(YNL_RST_FILES) + @$(YNL_TOOL) -o $@ -x + +$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml + @$(YNL_TOOL) -i $< -o $@ + +htmldocs: $(YNL_INDEX) @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 683eb42309cc..cb435c141794 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -55,6 +55,7 @@ Contents: filter generic-hdlc generic_netlink + netlink_spec/index gen_stats gtp ila diff --git a/Documentation/networking/netlink_spec/.gitignore b/Documentation/networking/netlink_spec/.gitignore new file mode 100644 index 000000000000..30d85567b592 --- /dev/null +++ b/Documentation/networking/netlink_spec/.gitignore @@ -0,0 +1 @@ +*.rst diff --git a/Documentation/networking/netlink_spec/readme.txt b/Documentation/networking/netlink_spec/readme.txt new file mode 100644 index 000000000000..6763f99d216c --- /dev/null +++ b/Documentation/networking/netlink_spec/readme.txt @@ -0,0 +1,4 @@ +SPDX-License-Identifier: GPL-2.0 + +This file is populated during the build of the documentation (htmldocs) by the +tools/net/ynl/ynl-gen-rst.py script. diff --git a/tools/net/ynl/ynl-gen-rst.py b/tools/net/ynl/ynl-gen-rst.py new file mode 100755 index 000000000000..b6292109e236 --- /dev/null +++ b/tools/net/ynl/ynl-gen-rst.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Script to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This script performs extensive parsing to the Linux kernel's netlink YAML + spec files, in an effort to avoid needing to heavily mark up the original + YAML file. + + This code is split in three big parts: + 1) RST formatters: Use to convert a string to a RST output + 2) Parser helpers: Functions to parse the YAML data structure + 3) Main function and small helpers +""" + +from typing import Any, Dict, List +import os.path +import sys +import argparse +import logging +import yaml + + +SPACE_PER_LEVEL = 4 + + +# RST Formatters +# ============== +def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * SPACE_PER_LEVEL) + + +def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" + + +def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" + + +def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple lines + return str(text).replace("\n", "").strip() + + +def rst_fields(key: str, value: str, level: int = 0) -> str: + """Return a RST formatted field""" + return headroom(level) + f":{key}: {value}" + + +def rst_definition(key: str, value: Any, level: int = 0) -> str: + """Format a single rst definition""" + return headroom(level) + key + "\n" + headroom(level + 1) + str(value) + + +def rst_paragraph(paragraph: str, level: int = 0) -> str: + """Return a formatted paragraph""" + return headroom(level) + paragraph + + +def rst_bullet(item: str, level: int = 0) -> str: + """Return a formatted a bullet""" + return headroom(level) + f" - {item}" + + +def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) + + +def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) + + +def rst_section(title: str) -> str: + """Add a section to the document""" + return f"\n{title}\n" + "=" * len(title) + + +def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" + + +def rst_title(title: str) -> str: + """Add a title to the document""" + return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" + + +def rst_list_inline(list_: List[str], level: int = 0) -> str: + """Format a list using inlines""" + return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "]" + + +def rst_header() -> str: + """The headers for all the auto generated RST files""" + lines = [] + + lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) + lines.append(rst_paragraph(".. NOTE: This document was auto-generated.\n\n")) + + return "\n".join(lines) + + +def rst_toctree(maxdepth: int = 2) -> str: + """Generate a toctree RST primitive""" + lines = [] + + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") + + return "\n".join(lines) + + +# Parsers +# ======= + + +def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines = [] + for group in mcast_group: + lines.append(rst_bullet(group["name"])) + + return "\n".join(lines) + + +def parse_do(do_dict: Dict[str, Any], level: int = 0) -> str: + """Parse 'do' section and return a formatted string""" + lines = [] + for key in do_dict.keys(): + lines.append(rst_paragraph(bold(key), level + 1)) + lines.append(parse_do_attributes(do_dict[key], level + 1) + "\n") + + return "\n".join(lines) + + +def parse_do_attributes(attrs: Dict[str, Any], level: int = 0) -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines = [rst_fields("attributes", rst_list_inline(attrs["attributes"]), level + 1)] + + return "\n".join(lines) + + +def parse_operations(operations: List[Dict[str, Any]]) -> str: + """Parse operations block""" + preprocessed = ["name", "doc", "title", "do", "dump"] + lines = [] + + for operation in operations: + lines.append(rst_section(operation["name"])) + lines.append(rst_paragraph(sanitize(operation["doc"])) + "\n") + + for key in operation.keys(): + if key in preprocessed: + # Skip the special fields + continue + lines.append(rst_fields(key, operation[key], 0)) + + if "do" in operation: + lines.append(rst_paragraph(":do:", 0)) + lines.append(parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(rst_paragraph(":dump:", 0)) + lines.append(parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + +def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: + """Parse a list of entries""" + lines = [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + lines.append( + rst_fields(entry.get("name", ""), sanitize(entry.get("doc", "")), level) + ) + elif isinstance(entry, list): + lines.append(rst_list_inline(entry, level)) + else: + lines.append(rst_bullet(inline(sanitize(entry)), level)) + + lines.append("\n") + return "\n".join(lines) + + +def parse_definitions(defs: Dict[str, Any]) -> str: + """Parse definitions section""" + preprocessed = ["name", "entries", "members"] + ignored = ["render-max"] # This is not printed + lines = [] + + for definition in defs: + lines.append(rst_section(definition["name"])) + for k in definition.keys(): + if k in preprocessed + ignored: + continue + lines.append(rst_fields(k, sanitize(definition[k]), 0)) + + # Field list needs to finish with a new line + lines.append("\n") + if "entries" in definition: + lines.append(rst_paragraph(":entries:", 0)) + lines.append(parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(rst_paragraph(":members:", 0)) + lines.append(parse_entries(definition["members"], 1)) + + return "\n".join(lines) + + +def parse_attr_sets(entries: List[Dict[str, Any]]) -> str: + """Parse attribute from attribute-set""" + preprocessed = ["name", "type"] + ignored = ["checks"] + lines = [] + + for entry in entries: + lines.append(rst_section(entry["name"])) + for attr in entry["attributes"]: + type_ = attr.get("type") + attr_line = bold(attr["name"]) + if type_: + # Add the attribute type in the same line + attr_line += f" ({inline(type_)})" + + lines.append(rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k in preprocessed + ignored: + continue + lines.append(rst_fields(k, sanitize(attr[k]), 2)) + lines.append("\n") + + return "\n".join(lines) + + +def parse_yaml(obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines = [] + + # Main header + + lines.append(rst_header()) + + title = f"Family ``{obj['name']}`` netlink specification" + lines.append(rst_title(title)) + lines.append(rst_paragraph(".. contents::\n")) + + if "doc" in obj: + lines.append(rst_subtitle("Summary")) + lines.append(rst_paragraph(obj["doc"], 0)) + + # Operations + if "operations" in obj: + lines.append(rst_subtitle("Operations")) + lines.append(parse_operations(obj["operations"]["list"])) + + # Multicast groups + if "mcast-groups" in obj: + lines.append(rst_subtitle("Multicast groups")) + lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) + + # Definitions + if "definitions" in obj: + lines.append(rst_subtitle("Definitions")) + lines.append(parse_definitions(obj["definitions"])) + + # Attributes set + if "attribute-sets" in obj: + lines.append(rst_subtitle("Attribute sets")) + lines.append(parse_attr_sets(obj["attribute-sets"])) + + return "\n".join(lines) + + +# Main functions +# ============== + + +def parse_arguments() -> argparse.Namespace: + """Parse arguments from user""" + parser = argparse.ArgumentParser(description="Netlink RST generator") + + parser.add_argument("-v", "--verbose", action="store_true") + parser.add_argument("-o", "--output", help="Output file name") + + # Index and input are mutually exclusive + group = parser.add_mutually_exclusive_group() + group.add_argument( + "-x", "--index", action="store_true", help="Generate the index page" + ) + group.add_argument("-i", "--input", help="YAML file name") + + args = parser.parse_args() + + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + if args.input and not os.path.isfile(args.input): + logging.warning("%s is not a valid file.", args.input) + sys.exit(-1) + + if not args.output: + logging.error("No output file specified.") + sys.exit(-1) + + if os.path.isfile(args.output): + logging.debug("%s already exists. Overwriting it.", args.output) + + return args + + +def parse_yaml_file(filename: str) -> str: + """Transform the YAML specified by filename into a rst-formmated string""" + with open(filename, "r", encoding="utf-8") as spec_file: + yaml_data = yaml.safe_load(spec_file) + content = parse_yaml(yaml_data) + + return content + + +def write_to_rstfile(content: str, filename: str) -> None: + """Write the generated content into an RST file""" + logging.debug("Saving RST file to %s", filename) + + with open(filename, "w", encoding="utf-8") as rst_file: + rst_file.write(content) + + +def generate_main_index_rst(output: str) -> None: + """Generate the `networking_spec/index` content and write to the file""" + lines = [] + + lines.append(rst_header()) + lines.append(rst_title("Netlink Specification")) + lines.append(rst_toctree(1)) + + index_dir = os.path.dirname(output) + logging.debug("Looking for .rst files in %s", index_dir) + for filename in os.listdir(index_dir): + if not filename.endswith(".rst") or filename == "index.rst": + continue + lines.append(f" {filename.replace('.rst', '')}\n") + + logging.debug("Writing an index file at %s", output) + write_to_rstfile("".join(lines), output) + + +def main() -> None: + """Main function that reads the YAML files and generates the RST files""" + + args = parse_arguments() + + if args.input: + logging.debug("Parsing %s", args.input) + try: + content = parse_yaml_file(os.path.join(args.input)) + except Exception as exception: + logging.warning("Failed to parse %s.", args.input) + logging.warning(exception) + sys.exit(-1) + + write_to_rstfile(content, args.output) + + if args.index: + # Generate the index RST file + generate_main_index_rst(args.output) + + +if __name__ == "__main__": + main() From aadbd27f9674d7f5457331fe0248b370d5c1f25d Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 21 Nov 2023 14:53:32 +0100 Subject: [PATCH 1354/7721] net: phy: correctly check soft_reset ret ONLY if defined for PHY Introduced by commit 6e2d85ec0559 ("net: phy: Stop with excessive soft reset"). soft_reset call for phy_init_hw had multiple revision across the years and the implementation goes back to 2014. Originally was a simple call to write the generic PHY reset BIT, it was then moved to a dedicated function. It was then added the option for PHY driver to define their own special way to reset the PHY. Till this change, checking for ret was correct as it was always filled by either the generic reset or the custom implementation. This changed tho with commit 6e2d85ec0559 ("net: phy: Stop with excessive soft reset"), as the generic reset call to PHY was dropped but the ret check was never made entirely optional and dependent whether soft_reset was defined for the PHY driver or not. Luckly nothing was ever added before the soft_reset call so the ret check (in the case where a PHY didn't had soft_reset defined) although wrong, never caused problems as ret was init 0 at the start of phy_init_hw. To prevent any kind of problem and to make the function cleaner and more robust, correctly move the ret check if the soft_reset section making it optional and needed only with the function defined. Signed-off-by: Christian Marangi Reviewed-by: Larysa Zaremba Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2ce74593d6e4..478126f6b5bc 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1235,13 +1235,12 @@ int phy_init_hw(struct phy_device *phydev) if (phydev->drv->soft_reset) { ret = phydev->drv->soft_reset(phydev); - /* see comment in genphy_soft_reset for an explanation */ - if (!ret) - phydev->suspended = 0; - } + if (ret < 0) + return ret; - if (ret < 0) - return ret; + /* see comment in genphy_soft_reset for an explanation */ + phydev->suspended = 0; + } ret = phy_scan_fixups(phydev); if (ret < 0) From 58046e6cf811464b8a6f269dc6a40a8cb91a8a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Nov 2023 11:31:36 +0200 Subject: [PATCH 1355/7721] drm/i915: Stop printing pipe name as hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the pipe name in ascii rather than hex. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231122093137.1509-3-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 7958d0bd851e..ef57dad1a9cb 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4537,7 +4537,7 @@ void intel_shared_dpll_state_verify(struct intel_atomic_state *state, "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", pipe_name(crtc->pipe), pll->active_mask); I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask, - "pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n", + "pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n", pipe_name(crtc->pipe), pll->state.pipe_mask); } } From b90fccfb5cde406365c33aa21ee87da83bbfca02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Nov 2023 11:31:37 +0200 Subject: [PATCH 1356/7721] drm/i915: Move the SDP split debug spew to the correct place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding ad-hoc debug prints all over the place is not good. Move the SDP split debug spew into the proper place (state dumper). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231122093137.1509-4-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 3 +++ drivers/gpu/drm/i915/display/intel_dp.c | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 66fe880af8f3..30336453041d 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -261,6 +261,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_dbg_kms(&i915->drm, "fec: %s, enhanced framing: %s\n", str_enabled_disabled(pipe_config->fec_enable), str_enabled_disabled(pipe_config->enhanced_framing)); + + drm_dbg_kms(&i915->drm, "sdp split: %s\n", + str_enabled_disabled(pipe_config->sdp_split_enable)); } drm_dbg_kms(&i915->drm, "framestart delay: %d, MSA timing delay: %d\n", diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6d5a794b6b71..f9b5fc2fdbcb 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2844,19 +2844,12 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct drm_connector *connector = conn_state->connector; - pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state) && intel_audio_compute_config(encoder, pipe_config, conn_state); pipe_config->sdp_split_enable = pipe_config->has_audio && intel_dp_is_uhbr(pipe_config); - - drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] SDP split enable: %s\n", - connector->base.id, connector->name, - str_yes_no(pipe_config->sdp_split_enable)); } int From 2d8f82dd322fbaafc9c1a70d70efb6efe42c973b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 22 Nov 2023 21:04:06 +0100 Subject: [PATCH 1357/7721] arm64: dts: exynos850: use Exynos7 fallbacks for pin wake-up controllers Exynos850 pin controller capable of wake-ups is still compatible with Exynos7, however it does not mux interrupts. Add Exynos7 compatible fallback to annotate that compatibility and match the bindings. Link: https://lore.kernel.org/r/20231122200407.423264-2-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos850.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/exynos850.dtsi b/arch/arm64/boot/dts/exynos/exynos850.dtsi index df5ea43ebcad..da3f4a791e68 100644 --- a/arch/arm64/boot/dts/exynos/exynos850.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos850.dtsi @@ -359,7 +359,8 @@ pinctrl_alive: pinctrl@11850000 { reg = <0x11850000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos850-wakeup-eint"; + compatible = "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; @@ -368,7 +369,8 @@ pinctrl_cmgp: pinctrl@11c30000 { reg = <0x11c30000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos850-wakeup-eint"; + compatible = "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; From 7c1156d8a719d5fca39e0e40e4465e4cbd765e89 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 22 Nov 2023 21:04:07 +0100 Subject: [PATCH 1358/7721] arm64: dts: exynosautov9: use Exynos7 fallbacks for pin wake-up controller ExynosAutov9 pin controller capable of wake-ups is still compatible with Exynos7, however it does not mux interrupts. Add Exynos7 compatible fallback to annotate that compatibility and match the bindings. Link: https://lore.kernel.org/r/20231122200407.423264-3-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynosautov9.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi index 417aa56a81f6..c871a2f49fda 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi +++ b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi @@ -310,7 +310,9 @@ pinctrl_alive: pinctrl@10450000 { reg = <0x10450000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynosautov9-wakeup-eint"; + compatible = "samsung,exynosautov9-wakeup-eint", + "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; From 491dd8edecbc5027ee317f3f1e7e9800fb66d88f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 23 Nov 2023 19:59:35 -0800 Subject: [PATCH 1359/7721] bpf: Emit global subprog name in verifier logs We have the name, instead of emitting just func#N to identify global subprog, augment verifier log messages with actual function name to make it more user-friendly. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231124035937.403208-2-andrii@kernel.org --- kernel/bpf/verifier.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 405da1f9e724..a2939ebf2638 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -339,6 +339,11 @@ struct bpf_kfunc_call_arg_meta { struct btf *btf_vmlinux; +static const char *btf_type_name(const struct btf *btf, u32 id) +{ + return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off); +} + static DEFINE_MUTEX(bpf_verifier_lock); static DEFINE_MUTEX(bpf_percpu_ma_lock); @@ -418,6 +423,17 @@ static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog) return aux && aux[subprog].linkage == BTF_FUNC_GLOBAL; } +static const char *subprog_name(const struct bpf_verifier_env *env, int subprog) +{ + struct bpf_func_info *info; + + if (!env->prog->aux->func_info) + return ""; + + info = &env->prog->aux->func_info[subprog]; + return btf_type_name(env->prog->aux->btf, info->type_id); +} + static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) { return btf_record_has_field(reg_btf_record(reg), BPF_SPIN_LOCK); @@ -587,11 +603,6 @@ static int iter_get_spi(struct bpf_verifier_env *env, struct bpf_reg_state *reg, return stack_slot_obj_get_spi(env, reg, "iter", nr_slots); } -static const char *btf_type_name(const struct btf *btf, u32 id) -{ - return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off); -} - static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) { switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { @@ -9269,13 +9280,16 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, if (err == -EFAULT) return err; if (subprog_is_global(env, subprog)) { + const char *sub_name = subprog_name(env, subprog); + if (err) { - verbose(env, "Caller passes invalid args into func#%d\n", subprog); + verbose(env, "Caller passes invalid args into func#%d ('%s')\n", + subprog, sub_name); return err; } - if (env->log.level & BPF_LOG_LEVEL) - verbose(env, "Func#%d is global and valid. Skipping.\n", subprog); + verbose(env, "Func#%d ('%s') is global and assumed valid.\n", + subprog, sub_name); clear_caller_saved_regs(env, caller->regs); /* All global functions return a 64-bit SCALAR_VALUE */ @@ -19893,9 +19907,8 @@ static int do_check_subprogs(struct bpf_verifier_env *env) if (ret) { return ret; } else if (env->log.level & BPF_LOG_LEVEL) { - verbose(env, - "Func#%d is safe for any args that match its prototype\n", - i); + verbose(env, "Func#%d ('%s') is safe for any args that match its prototype\n", + i, subprog_name(env, i)); } } return 0; From 2afae08c9dcb8ac648414277cec70c2fe6a34d9e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 23 Nov 2023 19:59:36 -0800 Subject: [PATCH 1360/7721] bpf: Validate global subprogs lazily Slightly change BPF verifier logic around eagerness and order of global subprog validation. Instead of going over every global subprog eagerly and validating it before main (entry) BPF program is verified, turn it around. Validate main program first, mark subprogs that were called from main program for later verification, but otherwise assume it is valid. Afterwards, go over marked global subprogs and validate those, potentially marking some more global functions as being called. Continue this process until all (transitively) callable global subprogs are validated. It's a BFS traversal at its heart and will always converge. This is an important change because it allows to feature-gate some subprograms that might not be verifiable on some older kernel, depending on supported set of features. E.g., at some point, global functions were allowed to accept a pointer to memory, which size is identified by user-provided type. Unfortunately, older kernels don't support this feature. With BPF CO-RE approach, the natural way would be to still compile BPF object file once and guard calls to this global subprog with some CO-RE check or using .rodata variables. That's what people do to guard usage of new helpers or kfuncs, and any other new BPF-side feature that might be missing on old kernels. That's currently impossible to do with global subprogs, unfortunately, because they are eagerly and unconditionally validated. This patch set aims to change this, so that in the future when global funcs gain new features, those can be guarded using BPF CO-RE techniques in the same fashion as any other new kernel feature. Two selftests had to be adjusted in sync with these changes. test_global_func12 relied on eager global subprog validation failing before main program failure is detected (unknown return value). Fix by making sure that main program is always valid. verifier_subprog_precision's parent_stack_slot_precise subtest relied on verifier checkpointing heuristic to do a checkpoint at instruction #5, but that's no longer true because we don't have enough jumps validated before reaching insn #5 due to global subprogs being validated later. Other than that, no changes, as one would expect. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231124035937.403208-3-andrii@kernel.org --- include/linux/bpf.h | 2 + kernel/bpf/verifier.c | 48 ++++++++++++++++--- .../selftests/bpf/progs/test_global_func12.c | 4 +- .../bpf/progs/verifier_subprog_precision.c | 4 +- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 258ba232e302..eb447b0a9423 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1347,6 +1347,8 @@ static inline bool bpf_prog_has_trampoline(const struct bpf_prog *prog) struct bpf_func_info_aux { u16 linkage; bool unreliable; + bool called : 1; + bool verified : 1; }; enum bpf_jit_poke_reason { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a2939ebf2638..8e7b6072e3f4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -434,6 +434,11 @@ static const char *subprog_name(const struct bpf_verifier_env *env, int subprog) return btf_type_name(env->prog->aux->btf, info->type_id); } +static struct bpf_func_info_aux *subprog_aux(const struct bpf_verifier_env *env, int subprog) +{ + return &env->prog->aux->func_info_aux[subprog]; +} + static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) { return btf_record_has_field(reg_btf_record(reg), BPF_SPIN_LOCK); @@ -9290,6 +9295,8 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, verbose(env, "Func#%d ('%s') is global and assumed valid.\n", subprog, sub_name); + /* mark global subprog for verifying after main prog */ + subprog_aux(env, subprog)->called = true; clear_caller_saved_regs(env, caller->regs); /* All global functions return a 64-bit SCALAR_VALUE */ @@ -19873,8 +19880,11 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog, bool is_ex return ret; } -/* Verify all global functions in a BPF program one by one based on their BTF. - * All global functions must pass verification. Otherwise the whole program is rejected. +/* Lazily verify all global functions based on their BTF, if they are called + * from main BPF program or any of subprograms transitively. + * BPF global subprogs called from dead code are not validated. + * All callable global functions must pass verification. + * Otherwise the whole program is rejected. * Consider: * int bar(int); * int foo(int f) @@ -19893,14 +19903,26 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog, bool is_ex static int do_check_subprogs(struct bpf_verifier_env *env) { struct bpf_prog_aux *aux = env->prog->aux; - int i, ret; + struct bpf_func_info_aux *sub_aux; + int i, ret, new_cnt; if (!aux->func_info) return 0; + /* exception callback is presumed to be always called */ + if (env->exception_callback_subprog) + subprog_aux(env, env->exception_callback_subprog)->called = true; + +again: + new_cnt = 0; for (i = 1; i < env->subprog_cnt; i++) { - if (aux->func_info_aux[i].linkage != BTF_FUNC_GLOBAL) + if (!subprog_is_global(env, i)) continue; + + sub_aux = subprog_aux(env, i); + if (!sub_aux->called || sub_aux->verified) + continue; + env->insn_idx = env->subprog_info[i].start; WARN_ON_ONCE(env->insn_idx == 0); ret = do_check_common(env, i, env->exception_callback_subprog == i); @@ -19910,7 +19932,21 @@ static int do_check_subprogs(struct bpf_verifier_env *env) verbose(env, "Func#%d ('%s') is safe for any args that match its prototype\n", i, subprog_name(env, i)); } + + /* We verified new global subprog, it might have called some + * more global subprogs that we haven't verified yet, so we + * need to do another pass over subprogs to verify those. + */ + sub_aux->verified = true; + new_cnt++; } + + /* We can't loop forever as we verify at least one global subprog on + * each pass. + */ + if (new_cnt) + goto again; + return 0; } @@ -20556,8 +20592,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (ret < 0) goto skip_full_check; - ret = do_check_subprogs(env); - ret = ret ?: do_check_main(env); + ret = do_check_main(env); + ret = ret ?: do_check_subprogs(env); if (ret == 0 && bpf_prog_is_offloaded(env->prog->aux)) ret = bpf_prog_offload_finalize(env); diff --git a/tools/testing/selftests/bpf/progs/test_global_func12.c b/tools/testing/selftests/bpf/progs/test_global_func12.c index 7f159d83c6f6..6e03d42519a6 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func12.c +++ b/tools/testing/selftests/bpf/progs/test_global_func12.c @@ -19,5 +19,7 @@ int global_func12(struct __sk_buff *skb) { const struct S s = {.x = skb->len }; - return foo(&s); + foo(&s); + + return 1; } diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index f61d623b1ce8..b5efcaeaa1ae 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -370,12 +370,10 @@ __naked int parent_stack_slot_precise(void) SEC("?raw_tp") __success __log_level(2) __msg("9: (0f) r1 += r6") -__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: last_idx 9 first_idx 0") __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") -__msg("mark_precise: frame0: parent state regs= stack=-8:") -__msg("mark_precise: frame0: last_idx 5 first_idx 0") __msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6") __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") From e8a339b5235e294f29153149ea7cf26a9a87dbea Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 23 Nov 2023 19:59:37 -0800 Subject: [PATCH 1361/7721] selftests/bpf: Add lazy global subprog validation tests Add a few test that validate BPF verifier's lazy approach to validating global subprogs. We check that global subprogs that are called transitively through another global subprog is validated. We also check that invalid global subprog is not validated, if it's not called from the main program. And we also check that main program is always validated first, before any of the subprogs. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231124035937.403208-4-andrii@kernel.org --- .../selftests/bpf/prog_tests/verifier.c | 2 + .../bpf/progs/verifier_global_subprogs.c | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_global_subprogs.c diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 5cfa7a6316b6..8d746642cbd7 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -25,6 +25,7 @@ #include "verifier_direct_stack_access_wraparound.skel.h" #include "verifier_div0.skel.h" #include "verifier_div_overflow.skel.h" +#include "verifier_global_subprogs.skel.h" #include "verifier_gotol.skel.h" #include "verifier_helper_access_var_len.skel.h" #include "verifier_helper_packet_access.skel.h" @@ -134,6 +135,7 @@ void test_verifier_direct_packet_access(void) { RUN(verifier_direct_packet_acces void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_stack_access_wraparound); } void test_verifier_div0(void) { RUN(verifier_div0); } void test_verifier_div_overflow(void) { RUN(verifier_div_overflow); } +void test_verifier_global_subprogs(void) { RUN(verifier_global_subprogs); } void test_verifier_gotol(void) { RUN(verifier_gotol); } void test_verifier_helper_access_var_len(void) { RUN(verifier_helper_access_var_len); } void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_access); } diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c new file mode 100644 index 000000000000..a0a5efd1caa1 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include +#include "bpf_misc.h" + +int arr[1]; +int unkn_idx; + +__noinline long global_bad(void) +{ + return arr[unkn_idx]; /* BOOM */ +} + +__noinline long global_good(void) +{ + return arr[0]; +} + +__noinline long global_calls_bad(void) +{ + return global_good() + global_bad() /* does BOOM indirectly */; +} + +__noinline long global_calls_good_only(void) +{ + return global_good(); +} + +SEC("?raw_tp") +__success __log_level(2) +/* main prog is validated completely first */ +__msg("('global_calls_good_only') is global and assumed valid.") +__msg("1: (95) exit") +/* eventually global_good() is transitively validated as well */ +__msg("Validating global_good() func") +__msg("('global_good') is safe for any args that match its prototype") +int chained_global_func_calls_success(void) +{ + return global_calls_good_only(); +} + +SEC("?raw_tp") +__failure __log_level(2) +/* main prog validated successfully first */ +__msg("1: (95) exit") +/* eventually we validate global_bad() and fail */ +__msg("Validating global_bad() func") +__msg("math between map_value pointer and register") /* BOOM */ +int chained_global_func_calls_bad(void) +{ + return global_calls_bad(); +} + +/* do out of bounds access forcing verifier to fail verification if this + * global func is called + */ +__noinline int global_unsupp(const int *mem) +{ + if (!mem) + return 0; + return mem[100]; /* BOOM */ +} + +const volatile bool skip_unsupp_global = true; + +SEC("?raw_tp") +__success +int guarded_unsupp_global_called(void) +{ + if (!skip_unsupp_global) + return global_unsupp(NULL); + return 0; +} + +SEC("?raw_tp") +__failure __log_level(2) +__msg("Func#1 ('global_unsupp') is global and assumed valid.") +__msg("Validating global_unsupp() func#1...") +__msg("value is outside of the allowed memory range") +int unguarded_unsupp_global_called(void) +{ + int x = 0; + + return global_unsupp(&x); +} + +char _license[] SEC("license") = "GPL"; From 29ce1bce3a713a8031a88f80224b72696813447d Mon Sep 17 00:00:00 2001 From: Jia Jie Ho Date: Wed, 15 Nov 2023 01:12:13 +0800 Subject: [PATCH 1362/7721] crypto: starfive - Update driver dependencies Change AMBA_PL08X to required dependency as the hash ops depends on it for data transfer. Signed-off-by: Jia Jie Ho Signed-off-by: Herbert Xu --- drivers/crypto/starfive/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/starfive/Kconfig b/drivers/crypto/starfive/Kconfig index 2cb192502c1b..cb59357b58b2 100644 --- a/drivers/crypto/starfive/Kconfig +++ b/drivers/crypto/starfive/Kconfig @@ -4,7 +4,7 @@ config CRYPTO_DEV_JH7110 tristate "StarFive JH7110 cryptographic engine driver" - depends on SOC_STARFIVE || AMBA_PL08X || COMPILE_TEST + depends on (SOC_STARFIVE && AMBA_PL08X) || COMPILE_TEST depends on HAS_DMA select CRYPTO_ENGINE select CRYPTO_HMAC From ba6e3ee4f5d6c13e984f8cb5fb1706ca39ff4a0e Mon Sep 17 00:00:00 2001 From: Jia Jie Ho Date: Wed, 15 Nov 2023 01:12:14 +0800 Subject: [PATCH 1363/7721] crypto: starfive - RSA poll csr for done status Hardware could not clear irq status without resetting the entire module. Driver receives irq immediately when mask bit is cleared causing intermittent errors in RSA calculations. Switch to use csr polling for done status instead. Signed-off-by: Jia Jie Ho Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-cryp.c | 8 ----- drivers/crypto/starfive/jh7110-cryp.h | 10 +++++- drivers/crypto/starfive/jh7110-rsa.c | 49 +++++++-------------------- 3 files changed, 22 insertions(+), 45 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index 3a67ddc4d936..31803e9cacba 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -109,12 +109,6 @@ static irqreturn_t starfive_cryp_irq(int irq, void *priv) tasklet_schedule(&cryp->hash_done); } - if (status & STARFIVE_IE_FLAG_PKA_DONE) { - mask |= STARFIVE_IE_MASK_PKA_DONE; - writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET); - complete(&cryp->pka_done); - } - return IRQ_HANDLED; } @@ -159,8 +153,6 @@ static int starfive_cryp_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst), "Error getting hardware reset line\n"); - init_completion(&cryp->pka_done); - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; diff --git a/drivers/crypto/starfive/jh7110-cryp.h b/drivers/crypto/starfive/jh7110-cryp.h index fe011d50473d..8510f8c1f307 100644 --- a/drivers/crypto/starfive/jh7110-cryp.h +++ b/drivers/crypto/starfive/jh7110-cryp.h @@ -125,6 +125,15 @@ union starfive_pka_cacr { }; }; +union starfive_pka_casr { + u32 v; + struct { +#define STARFIVE_PKA_DONE BIT(0) + u32 done :1; + u32 rsvd_0 :31; + }; +}; + struct starfive_rsa_key { u8 *n; u8 *e; @@ -183,7 +192,6 @@ struct starfive_cryp_dev { struct crypto_engine *engine; struct tasklet_struct aes_done; struct tasklet_struct hash_done; - struct completion pka_done; size_t assoclen; size_t total_in; size_t total_out; diff --git a/drivers/crypto/starfive/jh7110-rsa.c b/drivers/crypto/starfive/jh7110-rsa.c index f31bbd825f88..c2b1f598873c 100644 --- a/drivers/crypto/starfive/jh7110-rsa.c +++ b/drivers/crypto/starfive/jh7110-rsa.c @@ -6,13 +6,7 @@ */ #include -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -28,13 +22,13 @@ #define STARFIVE_PKA_CAER_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x108) #define STARFIVE_PKA_CANR_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x208) -// R^2 mod N and N0' +/* R ^ 2 mod N and N0' */ #define CRYPTO_CMD_PRE 0x0 -// A * R mod N ==> A +/* A * R mod N ==> A */ #define CRYPTO_CMD_ARN 0x5 -// A * E * R mod N ==> A +/* A * E * R mod N ==> A */ #define CRYPTO_CMD_AERN 0x6 -// A * A * R mod N ==> A +/* A * A * R mod N ==> A */ #define CRYPTO_CMD_AARN 0x7 #define STARFIVE_RSA_MAX_KEYSZ 256 @@ -43,21 +37,10 @@ static inline int starfive_pka_wait_done(struct starfive_cryp_ctx *ctx) { struct starfive_cryp_dev *cryp = ctx->cryp; + u32 status; - return wait_for_completion_timeout(&cryp->pka_done, - usecs_to_jiffies(100000)); -} - -static inline void starfive_pka_irq_mask_clear(struct starfive_cryp_ctx *ctx) -{ - struct starfive_cryp_dev *cryp = ctx->cryp; - u32 stat; - - stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET); - stat &= ~STARFIVE_IE_MASK_PKA_DONE; - writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET); - - reinit_completion(&cryp->pka_done); + return readl_relaxed_poll_timeout(cryp->base + STARFIVE_PKA_CASR_OFFSET, status, + status & STARFIVE_PKA_DONE, 10, 100000); } static void starfive_rsa_free_key(struct starfive_rsa_key *key) @@ -114,10 +97,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.not_r2 = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; for (loop = 0; loop <= opsize; loop++) @@ -136,10 +118,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; } else { rctx->csr.pka.v = 0; @@ -151,10 +132,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.pre_expf = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; for (loop = 0; loop <= count; loop++) @@ -172,10 +152,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; } @@ -226,11 +205,10 @@ static int starfive_rsa_cpu_start(struct starfive_cryp_ctx *ctx, u32 *result, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); ret = -ETIMEDOUT; - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) goto rsa_err; if (mlen) { @@ -242,10 +220,9 @@ static int starfive_rsa_cpu_start(struct starfive_cryp_ctx *ctx, u32 *result, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) goto rsa_err; } } From cc03a934c5da764b369979752cd3ade3bd4f5823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 16 Nov 2023 19:06:41 +0100 Subject: [PATCH 1364/7721] dt-bindings: crypto: convert Inside Secure SafeXcel to the json-schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps validating DTS files. Cc: Antoine Tenart Signed-off-by: Rafał Miłecki Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../crypto/inside-secure,safexcel.yaml | 86 +++++++++++++++++++ .../crypto/inside-secure-safexcel.txt | 40 --------- 2 files changed, 86 insertions(+), 40 deletions(-) create mode 100644 Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml delete mode 100644 Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt diff --git a/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml new file mode 100644 index 000000000000..ef07258d16c1 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/inside-secure,safexcel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Inside Secure SafeXcel cryptographic engine + +maintainers: + - Antoine Tenart + +properties: + compatible: + oneOf: + - const: inside-secure,safexcel-eip197b + - const: inside-secure,safexcel-eip197d + - const: inside-secure,safexcel-eip97ies + - const: inside-secure,safexcel-eip197 + description: Equivalent of inside-secure,safexcel-eip197b + deprecated: true + - const: inside-secure,safexcel-eip97 + description: Equivalent of inside-secure,safexcel-eip97ies + deprecated: true + + reg: + maxItems: 1 + + interrupts: + maxItems: 6 + + interrupt-names: + items: + - const: ring0 + - const: ring1 + - const: ring2 + - const: ring3 + - const: eip + - const: mem + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - const: core + - const: reg + +required: + - reg + - interrupts + - interrupt-names + +allOf: + - if: + properties: + clocks: + minItems: 2 + then: + properties: + clock-names: + minItems: 2 + required: + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + + crypto@800000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0x800000 0x200000>; + interrupts = , + , + , + , + , + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3", "eip", "mem"; + clocks = <&cpm_syscon0 1 26>; + clock-names = "core"; + }; diff --git a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt deleted file mode 100644 index 3bbf144c9988..000000000000 --- a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt +++ /dev/null @@ -1,40 +0,0 @@ -Inside Secure SafeXcel cryptographic engine - -Required properties: -- compatible: Should be "inside-secure,safexcel-eip197b", - "inside-secure,safexcel-eip197d" or - "inside-secure,safexcel-eip97ies". -- reg: Base physical address of the engine and length of memory mapped region. -- interrupts: Interrupt numbers for the rings and engine. -- interrupt-names: Should be "ring0", "ring1", "ring2", "ring3", "eip", "mem". - -Optional properties: -- clocks: Reference to the crypto engine clocks, the second clock is - needed for the Armada 7K/8K SoCs. -- clock-names: mandatory if there is a second clock, in this case the - name must be "core" for the first clock and "reg" for - the second one. - -Backward compatibility: -Two compatibles are kept for backward compatibility, but shouldn't be used for -new submissions: -- "inside-secure,safexcel-eip197" is equivalent to - "inside-secure,safexcel-eip197b". -- "inside-secure,safexcel-eip97" is equivalent to - "inside-secure,safexcel-eip97ies". - -Example: - - crypto: crypto@800000 { - compatible = "inside-secure,safexcel-eip197b"; - reg = <0x800000 0x200000>; - interrupts = , - , - , - , - , - ; - interrupt-names = "mem", "ring0", "ring1", "ring2", "ring3", - "eip"; - clocks = <&cpm_syscon0 1 26>; - }; From 52be2c4926831f7858c25701950afe9c1879f71f Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Fri, 24 Nov 2023 09:50:30 +0000 Subject: [PATCH 1365/7721] ASoC: cs43130: Allow configuration of bit clock and frame inversion Signed-off-by: Maciej Strozek Link: https://lore.kernel.org/r/20231124095030.24539-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 42 ++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/cs43130.h | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 4f16baf4eafb..0f3ead84665f 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -620,6 +620,27 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, return -EINVAL; } + switch (cs43130->dais[dai_id].dai_invert) { + case SND_SOC_DAIFMT_NB_NF: + sclk_edge = 1; + lrck_edge = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + sclk_edge = 0; + lrck_edge = 0; + break; + case SND_SOC_DAIFMT_NB_IF: + sclk_edge = 1; + lrck_edge = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + sclk_edge = 0; + lrck_edge = 1; + break; + default: + return -EINVAL; + } + switch (cs43130->dais[dai_id].dai_mode) { case SND_SOC_DAIFMT_CBS_CFS: dai_mode_val = 0; @@ -632,8 +653,6 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, } frm_size = bitwidth_sclk * params_channels(params); - sclk_edge = 1; - lrck_edge = 0; loc_ch1 = 0; loc_ch2 = bitwidth_sclk * (params_channels(params) - 1); @@ -1516,6 +1535,25 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_NF; + break; + case SND_SOC_DAIFMT_IB_NF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_NF; + break; + case SND_SOC_DAIFMT_NB_IF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_IF; + break; + case SND_SOC_DAIFMT_IB_IF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_IF; + break; + default: + dev_err(cs43130->dev, "Unsupported invert mode 0x%x\n", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S; diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index 694286b78d03..dbdb5b262f1b 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -497,6 +497,7 @@ struct cs43130_dai { unsigned int sclk; unsigned int dai_format; unsigned int dai_mode; + unsigned int dai_invert; }; struct cs43130_private { From 29b0b68f25ae6f9454c3e1c31b054595af0a80fc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 09:38:03 +0100 Subject: [PATCH 1366/7721] ASoC: dt-bindings: correct white-spaces in examples Use only one and exactly one space around '=' in DTS example. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124083803.12773-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8821.yaml | 2 +- Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml | 4 ++-- .../devicetree/bindings/sound/qcom,wcd938x-sdw.yaml | 4 ++-- Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml | 4 ++-- Documentation/devicetree/bindings/sound/renesas,rsnd.yaml | 8 ++++---- .../devicetree/bindings/sound/ti,tlv320aic32x4.yaml | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml index 3380b6aa9542..054b53954ac3 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -135,7 +135,7 @@ examples: nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <0>; nuvoton,dmic-clk-threshold = <3072000>; - nuvoton,dmic-slew-rate= <0>; + nuvoton,dmic-slew-rate = <0>; #sound-dai-cells = <0>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml index 4df59f3b7b01..beb0ff0245b0 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml @@ -201,9 +201,9 @@ examples: - | codec@1,0{ compatible = "slim217,250"; - reg = <1 0>; + reg = <1 0>; reset-gpios = <&tlmm 64 0>; - slim-ifc-dev = <&wcd9340_ifd>; + slim-ifc-dev = <&wcd9340_ifd>; #sound-dai-cells = <1>; interrupt-parent = <&tlmm>; interrupts = <54 4>; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml index b430dd3e1841..7b31bf93f1a1 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml @@ -51,7 +51,7 @@ examples: reg = <0x03210000 0x2000>; wcd938x_rx: codec@0,4 { compatible = "sdw20217010d00"; - reg = <0 4>; + reg = <0 4>; qcom,rx-port-mapping = <1 2 3 4 5>; }; }; @@ -62,7 +62,7 @@ examples: reg = <0x03230000 0x2000>; wcd938x_tx: codec@0,3 { compatible = "sdw20217010d00"; - reg = <0 3>; + reg = <0 3>; qcom,tx-port-mapping = <2 3 4 5>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml index 018565793a3e..adbfa67f88ed 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml @@ -137,7 +137,7 @@ examples: reg = <0x03210000 0x2000>; wcd938x_rx: codec@0,4 { compatible = "sdw20217010d00"; - reg = <0 4>; + reg = <0 4>; qcom,rx-port-mapping = <1 2 3 4 5>; }; }; @@ -148,7 +148,7 @@ examples: reg = <0x03230000 0x2000>; wcd938x_tx: codec@0,3 { compatible = "sdw20217010d00"; - reg = <0 3>; + reg = <0 3>; qcom,tx-port-mapping = <2 3 4 5>; }; }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 1174205286d4..0d7a6b576d88 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -497,19 +497,19 @@ examples: rcar_sound,dai { dai0 { playback = <&ssi5>, <&src5>; - capture = <&ssi6>; + capture = <&ssi6>; }; dai1 { playback = <&ssi3>; }; dai2 { - capture = <&ssi4>; + capture = <&ssi4>; }; dai3 { playback = <&ssi7>; }; dai4 { - capture = <&ssi8>; + capture = <&ssi8>; }; }; @@ -523,7 +523,7 @@ examples: frame-master = <&rsnd_endpoint0>; playback = <&ssi0>, <&src0>, <&dvc0>; - capture = <&ssi1>, <&src1>, <&dvc1>; + capture = <&ssi1>, <&src1>, <&dvc1>; }; }; }; diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml index a7cc9aa34468..4783e6dbb5c4 100644 --- a/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml @@ -90,7 +90,7 @@ examples: ldoin-supply = <®_3v3>; clocks = <&clks 201>; clock-names = "mclk"; - aic32x4-gpio-func= < + aic32x4-gpio-func = < 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ 0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */ From 4e3b70da64a53784683cfcbac2deda5d6e540407 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:05 +0200 Subject: [PATCH 1367/7721] drm: Disable the cursor plane on atomic contexts with virtualized drivers Cursor planes on virtualized drivers have special meaning and require that the clients handle them in specific ways, e.g. the cursor plane should react to the mouse movement the way a mouse cursor would be expected to and the client is required to set hotspot properties on it in order for the mouse events to be routed correctly. This breaks the contract as specified by the "universal planes". Fix it by disabling the cursor planes on virtualized drivers while adding a foundation on top of which it's possible to special case mouse cursor planes for clients that want it. Disabling the cursor planes makes some kms compositors which were broken, e.g. Weston, fallback to software cursor which works fine or at least better than currently while having no effect on others, e.g. gnome-shell or kwin, which put virtualized drivers on a deny-list when running in atomic context to make them fallback to legacy kms and avoid this issue. Signed-off-by: Zack Rusin Fixes: 681e7ec73044 ("drm: Allow userspace to ask for universal plane list (v2)") Cc: # v5.4+ Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Cc: Dave Airlie Cc: Gerd Hoffmann Cc: Hans de Goede Cc: Gurchetan Singh Cc: Chia-I Wu Cc: dri-devel@lists.freedesktop.org Cc: virtualization@lists.linux-foundation.org Cc: spice-devel@lists.freedesktop.org Acked-by: Pekka Paalanen Reviewed-by: Javier Martinez Canillas Acked-by: Simon Ser Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-2-aesteve@redhat.com --- drivers/gpu/drm/drm_plane.c | 13 +++++++++++++ drivers/gpu/drm/qxl/qxl_drv.c | 2 +- drivers/gpu/drm/vboxvideo/vbox_drv.c | 2 +- drivers/gpu/drm/virtio/virtgpu_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- include/drm/drm_drv.h | 9 +++++++++ include/drm/drm_file.h | 12 ++++++++++++ 7 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 24e7998d1731..c6bbb0c209f4 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -678,6 +678,19 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, !file_priv->universal_planes) continue; + /* + * If we're running on a virtualized driver then, + * unless userspace advertizes support for the + * virtualized cursor plane, disable cursor planes + * because they'll be broken due to missing cursor + * hotspot info. + */ + if (plane->type == DRM_PLANE_TYPE_CURSOR && + drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) && + file_priv->atomic && + !file_priv->supports_virtualized_cursor_plane) + continue; + if (drm_lease_held(file_priv, plane->base.id)) { if (count < plane_resp->count_planes && put_user(plane->base.id, plane_ptr + count)) diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 46de4f171970..beee5563031a 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -285,7 +285,7 @@ static const struct drm_ioctl_desc qxl_ioctls[] = { }; static struct drm_driver qxl_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT, .dumb_create = qxl_mode_dumb_create, .dumb_map_offset = drm_gem_ttm_dumb_map_offset, diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c index 047b95812334..cd9e66a06596 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.c +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c @@ -182,7 +182,7 @@ DEFINE_DRM_GEM_FOPS(vbox_fops); static const struct drm_driver driver = { .driver_features = - DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, + DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT, .fops = &vbox_fops, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 4334c7608408..f8e9abe647b9 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -177,7 +177,7 @@ static const struct drm_driver driver = { * out via drm_device::driver_features: */ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC | - DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE, + DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE | DRIVER_CURSOR_HOTSPOT, .open = virtio_gpu_driver_open, .postclose = virtio_gpu_driver_postclose, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8b24ecf60e3e..d3e308fdfd5b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1611,7 +1611,7 @@ static const struct file_operations vmwgfx_driver_fops = { static const struct drm_driver driver = { .driver_features = - DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM, + DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM | DRIVER_CURSOR_HOTSPOT, .ioctls = vmw_ioctls, .num_ioctls = ARRAY_SIZE(vmw_ioctls), .master_set = vmw_master_set, diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index e2640dc64e08..ea36aa79dca2 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -110,6 +110,15 @@ enum drm_driver_feature { * Driver supports user defined GPU VA bindings for GEM objects. */ DRIVER_GEM_GPUVA = BIT(8), + /** + * @DRIVER_CURSOR_HOTSPOT: + * + * Driver supports and requires cursor hotspot information in the + * cursor plane (e.g. cursor plane has to actually track the mouse + * cursor and the clients are required to set hotspot in order for + * the cursor planes to work correctly). + */ + DRIVER_CURSOR_HOTSPOT = BIT(9), /* IMPORTANT: Below are all the legacy flags, add new ones above. */ diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index e1b5b4282f75..8f35dcea82d3 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -226,6 +226,18 @@ struct drm_file { */ bool is_master; + /** + * @supports_virtualized_cursor_plane: + * + * This client is capable of handling the cursor plane with the + * restrictions imposed on it by the virtualized drivers. + * + * This implies that the cursor plane has to behave like a cursor + * i.e. track cursor movement. It also requires setting of the + * hotspot properties by the client on the cursor plane. + */ + bool supports_virtualized_cursor_plane; + /** * @master: * From 8f7179a1027d89bf949b0b80c388a544a5e096f2 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:06 +0200 Subject: [PATCH 1368/7721] drm/atomic: Add support for mouse hotspots Atomic modesetting code lacked support for specifying mouse cursor hotspots. The legacy kms DRM_IOCTL_MODE_CURSOR2 had support for setting the hotspot but the functionality was not implemented in the new atomic paths. Due to the lack of hotspots in the atomic paths userspace compositors completely disable atomic modesetting for drivers that require it (i.e. all paravirtualized drivers). This change adds hotspot properties to the atomic codepaths throughtout the DRM core and will allow enabling atomic modesetting for virtualized drivers in the userspace. Signed-off-by: Zack Rusin Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-3-aesteve@redhat.com --- drivers/gpu/drm/drm_atomic_state_helper.c | 14 +++++++ drivers/gpu/drm/drm_atomic_uapi.c | 20 +++++++++ drivers/gpu/drm/drm_plane.c | 50 +++++++++++++++++++++++ include/drm/drm_plane.h | 14 +++++++ 4 files changed, 98 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 784e63d70a42..54975de44a0e 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -275,6 +275,20 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->normalized_zpos = val; } } + + if (plane->hotspot_x_property) { + if (!drm_object_property_get_default_value(&plane->base, + plane->hotspot_x_property, + &val)) + plane_state->hotspot_x = val; + } + + if (plane->hotspot_y_property) { + if (!drm_object_property_get_default_value(&plane->base, + plane->hotspot_y_property, + &val)) + plane_state->hotspot_y = val; + } } EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 116407002269..aee4a65d4959 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -593,6 +593,22 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (plane->funcs->atomic_set_property) { return plane->funcs->atomic_set_property(plane, state, property, val); + } else if (property == plane->hotspot_x_property) { + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n", + plane->base.id, plane->name, val); + return -EINVAL; + } + state->hotspot_x = val; + } else if (property == plane->hotspot_y_property) { + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n", + plane->base.id, plane->name, val); + return -EINVAL; + } + state->hotspot_y = val; } else { drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", @@ -653,6 +669,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->scaling_filter; } else if (plane->funcs->atomic_get_property) { return plane->funcs->atomic_get_property(plane, state, property, val); + } else if (property == plane->hotspot_x_property) { + *val = state->hotspot_x; + } else if (property == plane->hotspot_y_property) { + *val = state->hotspot_y; } else { drm_dbg_atomic(dev, "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index c6bbb0c209f4..eaca367bdc7e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -230,6 +230,47 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane return 0; } +/** + * drm_plane_create_hotspot_properties - creates the mouse hotspot + * properties and attaches them to the given cursor plane + * + * @plane: drm cursor plane + * + * This function enables the mouse hotspot property on a given + * cursor plane. + * + * RETURNS: + * Zero for success or -errno + */ +static int drm_plane_create_hotspot_properties(struct drm_plane *plane) +{ + struct drm_property *prop_x; + struct drm_property *prop_y; + + drm_WARN_ON(plane->dev, + !drm_core_check_feature(plane->dev, + DRIVER_CURSOR_HOTSPOT)); + + prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", + INT_MIN, INT_MAX); + if (IS_ERR(prop_x)) + return PTR_ERR(prop_x); + + prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", + INT_MIN, INT_MAX); + if (IS_ERR(prop_y)) { + drm_property_destroy(plane->dev, prop_x); + return PTR_ERR(prop_y); + } + + drm_object_attach_property(&plane->base, prop_x, 0); + drm_object_attach_property(&plane->base, prop_y, 0); + plane->hotspot_x_property = prop_x; + plane->hotspot_y_property = prop_y; + + return 0; +} + __printf(9, 0) static int __drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, @@ -348,6 +389,10 @@ static int __drm_universal_plane_init(struct drm_device *dev, drm_object_attach_property(&plane->base, config->prop_src_w, 0); drm_object_attach_property(&plane->base, config->prop_src_h, 0); } + if (drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) && + type == DRM_PLANE_TYPE_CURSOR) { + drm_plane_create_hotspot_properties(plane); + } if (format_modifier_count) create_in_format_blob(dev, plane); @@ -1067,6 +1112,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, fb->hot_x = req->hot_x; fb->hot_y = req->hot_y; + + if (plane->hotspot_x_property && plane->state) + plane->state->hotspot_x = req->hot_x; + if (plane->hotspot_y_property && plane->state) + plane->state->hotspot_y = req->hot_y; } else { fb = NULL; } diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 79d62856defb..e2c671585775 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -116,6 +116,10 @@ struct drm_plane_state { /** @src_h: height of visible portion of plane (in 16.16) */ uint32_t src_h, src_w; + /** @hotspot_x: x offset to mouse cursor hotspot */ + /** @hotspot_y: y offset to mouse cursor hotspot */ + int32_t hotspot_x, hotspot_y; + /** * @alpha: * Opacity of the plane with 0 as completely transparent and 0xffff as @@ -748,6 +752,16 @@ struct drm_plane { * scaling. */ struct drm_property *scaling_filter_property; + + /** + * @hotspot_x_property: property to set mouse hotspot x offset. + */ + struct drm_property *hotspot_x_property; + + /** + * @hotspot_y_property: property to set mouse hotspot y offset. + */ + struct drm_property *hotspot_y_property; }; #define obj_to_plane(x) container_of(x, struct drm_plane, base) From cd5499429237b7ba3f5bfd3efb488688886c82fe Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:07 +0200 Subject: [PATCH 1369/7721] drm/vmwgfx: Use the hotspot properties from cursor planes Atomic modesetting got support for mouse hotspots via the hotspot properties. Port the legacy kms hotspot handling to the new properties on cursor planes. Signed-off-by: Zack Rusin Cc: Maaz Mombasawala Reviewed-by: Javier Martinez Canillas Reviewed-by: Martin Krastev Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-4-aesteve@redhat.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 818b7f109f53..bea0abc3d418 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -768,13 +768,8 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); s32 hotspot_x, hotspot_y; - hotspot_x = du->hotspot_x; - hotspot_y = du->hotspot_y; - - if (new_state->fb) { - hotspot_x += new_state->fb->hot_x; - hotspot_y += new_state->fb->hot_y; - } + hotspot_x = du->hotspot_x + new_state->hotspot_x; + hotspot_y = du->hotspot_y + new_state->hotspot_y; du->cursor_surface = vps->surf; du->cursor_bo = vps->bo; From 305b391d8f84a46119b5554a7a7af775266ce382 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:08 +0200 Subject: [PATCH 1370/7721] drm/qxl: Use the hotspot properties from cursor planes Atomic modesetting got support for mouse hotspots via the hotspot properties. Port the legacy kms hotspot handling to the new properties on cursor planes. Signed-off-by: Zack Rusin Reviewed-by: Gerd Hoffmann Cc: Dave Airlie Cc: Daniel Vetter Cc: virtualization@lists.linux-foundation.org Cc: spice-devel@lists.freedesktop.org Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-5-aesteve@redhat.com --- drivers/gpu/drm/qxl/qxl_display.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 404b0483bb7c..c6d35c33d5d6 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -485,7 +485,6 @@ static int qxl_primary_atomic_check(struct drm_plane *plane, static int qxl_primary_apply_cursor(struct qxl_device *qdev, struct drm_plane_state *plane_state) { - struct drm_framebuffer *fb = plane_state->fb; struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc); struct qxl_cursor_cmd *cmd; struct qxl_release *release; @@ -510,8 +509,8 @@ static int qxl_primary_apply_cursor(struct qxl_device *qdev, cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_CURSOR_SET; - cmd->u.set.position.x = plane_state->crtc_x + fb->hot_x; - cmd->u.set.position.y = plane_state->crtc_y + fb->hot_y; + cmd->u.set.position.x = plane_state->crtc_x + plane_state->hotspot_x; + cmd->u.set.position.y = plane_state->crtc_y + plane_state->hotspot_y; cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0); @@ -531,7 +530,6 @@ static int qxl_primary_apply_cursor(struct qxl_device *qdev, static int qxl_primary_move_cursor(struct qxl_device *qdev, struct drm_plane_state *plane_state) { - struct drm_framebuffer *fb = plane_state->fb; struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc); struct qxl_cursor_cmd *cmd; struct qxl_release *release; @@ -554,8 +552,8 @@ static int qxl_primary_move_cursor(struct qxl_device *qdev, cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_CURSOR_MOVE; - cmd->u.position.x = plane_state->crtc_x + fb->hot_x; - cmd->u.position.y = plane_state->crtc_y + fb->hot_y; + cmd->u.position.x = plane_state->crtc_x + plane_state->hotspot_x; + cmd->u.position.y = plane_state->crtc_y + plane_state->hotspot_y; qxl_release_unmap(qdev, release, &cmd->release_info); qxl_release_fence_buffer_objects(release); @@ -851,8 +849,8 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane, struct qxl_bo *old_cursor_bo = qcrtc->cursor_bo; qcrtc->cursor_bo = qxl_create_cursor(qdev, user_bo, - new_state->fb->hot_x, - new_state->fb->hot_y); + new_state->hotspot_x, + new_state->hotspot_y); qxl_free_cursor(old_cursor_bo); } From 44d877a1de912fa24d1af8f76433a914e6816057 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:09 +0200 Subject: [PATCH 1371/7721] drm/vboxvideo: Use the hotspot properties from cursor planes Atomic modesetting got support for mouse hotspots via the hotspot properties. Port the legacy kms hotspot handling to the new properties on cursor planes. Signed-off-by: Zack Rusin Cc: Hans de Goede Cc: David Airlie Cc: Daniel Vetter Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-6-aesteve@redhat.com --- drivers/gpu/drm/vboxvideo/vbox_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index 341edd982cb3..9ff3bade9795 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -429,8 +429,8 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA; hgsmi_update_pointer_shape(vbox->guest_pool, flags, - min_t(u32, max(fb->hot_x, 0), width), - min_t(u32, max(fb->hot_y, 0), height), + min_t(u32, max(new_state->hotspot_x, 0), width), + min_t(u32, max(new_state->hotspot_y, 0), height), width, height, vbox->cursor_data, data_size); mutex_unlock(&vbox->hw_mutex); From cc6c535967ed07fd75f54a26a70091826daf691e Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:10 +0200 Subject: [PATCH 1372/7721] drm/virtio: Use the hotspot properties from cursor planes Atomic modesetting got support for mouse hotspots via the hotspot properties. Port the legacy kms hotspot handling to the new properties on cursor planes. Signed-off-by: Zack Rusin Reviewed-by: Gerd Hoffmann Cc: David Airlie Cc: Gurchetan Singh Cc: Chia-I Wu Cc: Daniel Vetter Cc: virtualization@lists.linux-foundation.org Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-7-aesteve@redhat.com --- drivers/gpu/drm/virtio/virtgpu_plane.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index a2e045f3a000..20de599658c1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -323,16 +323,16 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle, plane->state->crtc_x, plane->state->crtc_y, - plane->state->fb ? plane->state->fb->hot_x : 0, - plane->state->fb ? plane->state->fb->hot_y : 0); + plane->state->hotspot_x, + plane->state->hotspot_y); output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); output->cursor.resource_id = cpu_to_le32(handle); if (plane->state->fb) { output->cursor.hot_x = - cpu_to_le32(plane->state->fb->hot_x); + cpu_to_le32(plane->state->hotspot_x); output->cursor.hot_y = - cpu_to_le32(plane->state->fb->hot_y); + cpu_to_le32(plane->state->hotspot_y); } else { output->cursor.hot_x = cpu_to_le32(0); output->cursor.hot_y = cpu_to_le32(0); From bce3dab7eb6ee596388699e8a052a7d58954c472 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:11 +0200 Subject: [PATCH 1373/7721] drm: Remove legacy cursor hotspot code Atomic modesetting supports mouse cursor offsets via the hotspot properties that are created on cursor planes. All drivers which support hotspots are atomic and the legacy code has been implemented in terms of the atomic properties as well. Due to the above the lagacy cursor hotspot code is no longer used or needed and can be removed. Signed-off-by: Zack Rusin Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-8-aesteve@redhat.com --- drivers/gpu/drm/drm_plane.c | 3 --- include/drm/drm_framebuffer.h | 12 ------------ 2 files changed, 15 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index eaca367bdc7e..1dc00ad4c33c 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1110,9 +1110,6 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, return PTR_ERR(fb); } - fb->hot_x = req->hot_x; - fb->hot_y = req->hot_y; - if (plane->hotspot_x_property && plane->state) plane->state->hotspot_x = req->hot_x; if (plane->hotspot_y_property && plane->state) diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 80ece7b6dd9b..668077009fce 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -188,18 +188,6 @@ struct drm_framebuffer { * DRM_MODE_FB_MODIFIERS. */ int flags; - /** - * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor - * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR - * universal plane. - */ - int hot_x; - /** - * @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor - * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR - * universal plane. - */ - int hot_y; /** * @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock. */ From 9724ed6c1b1212d138e63f5e80647dc8b6b86696 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 23 Oct 2023 09:46:12 +0200 Subject: [PATCH 1374/7721] drm: Introduce DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT Virtualized drivers place additional restrictions on the cursor plane which breaks the contract of universal planes. To allow atomic modesettings with virtualized drivers the clients need to advertise that they're capable of dealing with those extra restrictions. To do that introduce DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT which lets DRM know that the client is aware of and capable of dealing with the extra restrictions on the virtual cursor plane. Setting this option to true makes DRM expose the cursor plane on virtualized drivers. The userspace is expected to set the hotspots and handle mouse events on that plane. Signed-off-by: Zack Rusin Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Acked-by: Pekka Paalanen Reviewed-by: Javier Martinez Canillas Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-9-aesteve@redhat.com --- drivers/gpu/drm/drm_ioctl.c | 9 +++++++++ include/uapi/drm/drm.h | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f461ed862480..ea303386e688 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -365,6 +365,15 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->writeback_connectors = req->value; break; + case DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT: + if (!drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT)) + return -EOPNOTSUPP; + if (!file_priv->atomic) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->supports_virtualized_cursor_plane = req->value; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 796de831f4a0..91943e5ce010 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -850,6 +850,31 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 +/** + * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT + * + * Drivers for para-virtualized hardware (e.g. vmwgfx, qxl, virtio and + * virtualbox) have additional restrictions for cursor planes (thus + * making cursor planes on those drivers not truly universal,) e.g. + * they need cursor planes to act like one would expect from a mouse + * cursor and have correctly set hotspot properties. + * If this client cap is not set the DRM core will hide cursor plane on + * those virtualized drivers because not setting it implies that the + * client is not capable of dealing with those extra restictions. + * Clients which do set cursor hotspot and treat the cursor plane + * like a mouse cursor should set this property. + * The client must enable &DRM_CLIENT_CAP_ATOMIC first. + * + * Setting this property on drivers which do not special case + * cursor planes (i.e. non-virtualized drivers) will return + * EOPNOTSUPP, which can be used by userspace to gauge + * requirements of the hardware/drivers they're running on. + * + * This capability is always supported for atomic-capable virtualized + * drivers starting from kernel version 6.6. + */ +#define DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT 6 + /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; From 4653f9d014117f78813cae7b022c15b899c77d7b Mon Sep 17 00:00:00 2001 From: Michael Banack Date: Mon, 23 Oct 2023 09:46:13 +0200 Subject: [PATCH 1375/7721] drm: Introduce documentation for hotspot properties To clarify the intent and reasoning behind the hotspot properties introduce userspace documentation that goes over cursor handling in para-virtualized environments. The documentation is generic enough to not special case for any specific hypervisor and should apply equally to all. Signed-off-by: Zack Rusin Acked-by: Pekka Paalanen Reviewed-by: Javier Martinez Canillas Signed-off-by: Michael Banack Signed-off-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231023074613.41327-10-aesteve@redhat.com --- Documentation/gpu/drm-kms.rst | 6 ++++ drivers/gpu/drm/drm_plane.c | 58 ++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 270d320407c7..4a112b8cc7fb 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -579,6 +579,12 @@ Variable Refresh Properties .. kernel-doc:: drivers/gpu/drm/drm_connector.c :doc: Variable refresh properties +Cursor Hotspot Properties +--------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_plane.c + :doc: hotspot properties + Existing KMS Properties ----------------------- diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 1dc00ad4c33c..f3f2eae83cca 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -230,6 +230,61 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane return 0; } +/** + * DOC: hotspot properties + * + * HOTSPOT_X: property to set mouse hotspot x offset. + * HOTSPOT_Y: property to set mouse hotspot y offset. + * + * When the plane is being used as a cursor image to display a mouse pointer, + * the "hotspot" is the offset within the cursor image where mouse events + * are expected to go. + * + * Positive values move the hotspot from the top-left corner of the cursor + * plane towards the right and bottom. + * + * Most display drivers do not need this information because the + * hotspot is not actually connected to anything visible on screen. + * However, this is necessary for display drivers like the para-virtualized + * drivers (eg qxl, vbox, virtio, vmwgfx), that are attached to a user console + * with a mouse pointer. Since these consoles are often being remoted over a + * network, they would otherwise have to wait to display the pointer movement to + * the user until a full network round-trip has occurred. New mouse events have + * to be sent from the user's console, over the network to the virtual input + * devices, forwarded to the desktop for processing, and then the cursor plane's + * position can be updated and sent back to the user's console over the network. + * Instead, with the hotspot information, the console can anticipate the new + * location, and draw the mouse cursor there before the confirmation comes in. + * To do that correctly, the user's console must be able predict how the + * desktop will process mouse events, which normally requires the desktop's + * mouse topology information, ie where each CRTC sits in the mouse coordinate + * space. This is typically sent to the para-virtualized drivers using some + * driver-specific method, and the driver then forwards it to the console by + * way of the virtual display device or hypervisor. + * + * The assumption is generally made that there is only one cursor plane being + * used this way at a time, and that the desktop is feeding all mouse devices + * into the same global pointer. Para-virtualized drivers that require this + * should only be exposing a single cursor plane, or find some other way + * to coordinate with a userspace desktop that supports multiple pointers. + * If the hotspot properties are set, the cursor plane is therefore assumed to be + * used only for displaying a mouse cursor image, and the position of the combined + * cursor plane + offset can therefore be used for coordinating with input from a + * mouse device. + * + * The cursor will then be drawn either at the location of the plane in the CRTC + * console, or as a free-floating cursor plane on the user's console + * corresponding to their desktop mouse position. + * + * DRM clients which would like to work correctly on drivers which expose + * hotspot properties should advertise DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT. + * Setting this property on drivers which do not special case + * cursor planes will return EOPNOTSUPP, which can be used by userspace to + * gauge requirements of the hardware/drivers they're running on. Advertising + * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT implies that the userspace client will be + * correctly setting the hotspot properties. + */ + /** * drm_plane_create_hotspot_properties - creates the mouse hotspot * properties and attaches them to the given cursor plane @@ -237,7 +292,8 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane * @plane: drm cursor plane * * This function enables the mouse hotspot property on a given - * cursor plane. + * cursor plane. Look at the documentation for hotspot properties + * to get a better understanding for what they're used for. * * RETURNS: * Zero for success or -errno From a8d4879d5f1fac060719567d1a8e8f8e68a127fc Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Wed, 22 Nov 2023 17:11:42 +0530 Subject: [PATCH 1376/7721] octeontx2-pf: TC flower offload support for ICMP type and code Adds tc offload support for matching on ICMP type and code. Example usage: To enable adding tc ingress rules tc qdisc add dev eth0 ingress TC rule drop the ICMP echo reply: tc filter add dev eth0 protocol ip parent ffff: \ flower ip_proto icmp type 8 code 0 skip_sw action drop TC rule to drop ICMPv6 echo reply: tc filter add dev eth0 protocol ipv6 parent ffff: flower \ indev eth0 ip_proto icmpv6 type 128 code 0 action drop Signed-off-by: Geetha sowjanya Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 ++ .../net/ethernet/marvell/octeontx2/af/npc.h | 2 ++ .../marvell/octeontx2/af/rvu_debugfs.c | 8 +++++++ .../marvell/octeontx2/af/rvu_npc_fs.c | 23 ++++++++++++++----- .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 14 +++++++++++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 6845556581c3..b4ced739ae44 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1479,6 +1479,8 @@ struct flow_msg { #define OTX2_FLOWER_MASK_MPLS_TTL GENMASK(7, 0) #define OTX2_FLOWER_MASK_MPLS_NON_TTL GENMASK(31, 8) u32 mpls_lse[4]; + u8 icmp_type; + u8 icmp_code; }; struct npc_install_flow_req { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h index ab3e39eef2eb..ffc0aa0a7b47 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -214,6 +214,8 @@ enum key_fields { NPC_MPLS3_TTL, NPC_MPLS4_LBTCBOS, NPC_MPLS4_TTL, + NPC_TYPE_ICMP, + NPC_CODE_ICMP, NPC_HEADER_FIELDS_MAX, NPC_CHAN = NPC_HEADER_FIELDS_MAX, /* Valid when Rx */ NPC_PF_FUNC, /* Valid when Tx */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index bd817ee88735..468b6561ed3f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -2889,6 +2889,14 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s, RVU_DBG_PRINT_MPLS_TTL(rule->packet.mpls_lse[3], rule->mask.mpls_lse[3]); break; + case NPC_TYPE_ICMP: + seq_printf(s, "%d ", rule->packet.icmp_type); + seq_printf(s, "mask 0x%x\n", rule->mask.icmp_type); + break; + case NPC_CODE_ICMP: + seq_printf(s, "%d ", rule->packet.icmp_code); + seq_printf(s, "mask 0x%x\n", rule->mask.icmp_code); + break; default: seq_puts(s, "\n"); break; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 114e4ec21802..db8f151636af 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -51,6 +51,8 @@ static const char * const npc_flow_names[] = { [NPC_MPLS3_TTL] = "lse depth 3 ttl", [NPC_MPLS4_LBTCBOS] = "lse depth 4 label tc bos", [NPC_MPLS4_TTL] = "lse depth 4", + [NPC_TYPE_ICMP] = "icmp type", + [NPC_CODE_ICMP] = "icmp code", [NPC_UNKNOWN] = "unknown", }; @@ -526,6 +528,8 @@ do { \ NPC_SCAN_HDR(NPC_DPORT_TCP, NPC_LID_LD, NPC_LT_LD_TCP, 2, 2); NPC_SCAN_HDR(NPC_SPORT_SCTP, NPC_LID_LD, NPC_LT_LD_SCTP, 0, 2); NPC_SCAN_HDR(NPC_DPORT_SCTP, NPC_LID_LD, NPC_LT_LD_SCTP, 2, 2); + NPC_SCAN_HDR(NPC_TYPE_ICMP, NPC_LID_LD, NPC_LT_LD_ICMP, 0, 1); + NPC_SCAN_HDR(NPC_CODE_ICMP, NPC_LID_LD, NPC_LT_LD_ICMP, 1, 1); NPC_SCAN_HDR(NPC_ETYPE_ETHER, NPC_LID_LA, NPC_LT_LA_ETHER, 12, 2); NPC_SCAN_HDR(NPC_ETYPE_TAG1, NPC_LID_LB, NPC_LT_LB_CTAG, 4, 2); NPC_SCAN_HDR(NPC_ETYPE_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 8, 2); @@ -555,7 +559,7 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf) { struct npc_mcam *mcam = &rvu->hw->mcam; u64 *features = &mcam->rx_features; - u64 tcp_udp_sctp; + u64 proto_flags; int hdr; if (is_npc_intf_tx(intf)) @@ -566,18 +570,21 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf) *features |= BIT_ULL(hdr); } - tcp_udp_sctp = BIT_ULL(NPC_SPORT_TCP) | BIT_ULL(NPC_SPORT_UDP) | + proto_flags = BIT_ULL(NPC_SPORT_TCP) | BIT_ULL(NPC_SPORT_UDP) | BIT_ULL(NPC_DPORT_TCP) | BIT_ULL(NPC_DPORT_UDP) | - BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP); + BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP) | + BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP) | + BIT_ULL(NPC_TYPE_ICMP) | BIT_ULL(NPC_CODE_ICMP); /* for tcp/udp/sctp corresponding layer type should be in the key */ - if (*features & tcp_udp_sctp) { + if (*features & proto_flags) { if (!npc_check_field(rvu, blkaddr, NPC_LD, intf)) - *features &= ~tcp_udp_sctp; + *features &= ~proto_flags; else *features |= BIT_ULL(NPC_IPPROTO_TCP) | BIT_ULL(NPC_IPPROTO_UDP) | - BIT_ULL(NPC_IPPROTO_SCTP); + BIT_ULL(NPC_IPPROTO_SCTP) | + BIT_ULL(NPC_IPPROTO_ICMP); } /* for AH/ICMP/ICMPv6/, check if corresponding layer type is present in the key */ @@ -971,6 +978,10 @@ do { \ ntohs(mask->sport), 0); NPC_WRITE_FLOW(NPC_DPORT_SCTP, dport, ntohs(pkt->dport), 0, ntohs(mask->dport), 0); + NPC_WRITE_FLOW(NPC_TYPE_ICMP, icmp_type, pkt->icmp_type, 0, + mask->icmp_type, 0); + NPC_WRITE_FLOW(NPC_CODE_ICMP, icmp_code, pkt->icmp_code, 0, + mask->icmp_code, 0); NPC_WRITE_FLOW(NPC_IPSEC_SPI, spi, ntohl(pkt->spi), 0, ntohl(mask->spi), 0); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 8a5e3987a482..10657a7559d7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -522,6 +522,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node, BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) | BIT(FLOW_DISSECTOR_KEY_IPSEC) | BIT_ULL(FLOW_DISSECTOR_KEY_MPLS) | + BIT_ULL(FLOW_DISSECTOR_KEY_ICMP) | BIT_ULL(FLOW_DISSECTOR_KEY_IP)))) { netdev_info(nic->netdev, "unsupported flow used key 0x%llx", dissector->used_keys); @@ -796,6 +797,19 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node, } } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP)) { + struct flow_match_icmp match; + + flow_rule_match_icmp(rule, &match); + + flow_spec->icmp_type = match.key->type; + flow_mask->icmp_type = match.mask->type; + req->features |= BIT_ULL(NPC_TYPE_ICMP); + + flow_spec->icmp_code = match.key->code; + flow_mask->icmp_code = match.mask->code; + req->features |= BIT_ULL(NPC_CODE_ICMP); + } return otx2_tc_parse_actions(nic, &rule->action, req, f, node); } From f8e80fc4acebab0447567e77d6abc30fb44250cc Mon Sep 17 00:00:00 2001 From: Guangguan Wang Date: Wed, 22 Nov 2023 21:52:57 +0800 Subject: [PATCH 1377/7721] net/smc: add sysctl for max links per lgr for SMC-R v2.1 Add a new sysctl: net.smc.smcr_max_links_per_lgr, which is used to control the preferred max links per lgr for SMC-R v2.1. The default value of this sysctl is 2, and the acceptable value ranges from 1 to 2. Signed-off-by: Guangguan Wang Reviewed-by: Dust Li Signed-off-by: David S. Miller --- Documentation/networking/smc-sysctl.rst | 8 ++++++++ include/net/netns/smc.h | 1 + net/smc/af_smc.c | 2 +- net/smc/smc_clc.c | 10 +++++++--- net/smc/smc_clc.h | 3 ++- net/smc/smc_sysctl.c | 12 ++++++++++++ net/smc/smc_sysctl.h | 1 + 7 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/smc-sysctl.rst b/Documentation/networking/smc-sysctl.rst index 769149d98773..c6ef86ef4c4f 100644 --- a/Documentation/networking/smc-sysctl.rst +++ b/Documentation/networking/smc-sysctl.rst @@ -57,3 +57,11 @@ rmem - INTEGER only allowed 512KiB for SMC-R and 1MiB for SMC-D. Default: 64KiB + +smcr_max_links_per_lgr - INTEGER + Controls the max number of links can be added to a SMC-R link group. Notice that + the actual number of the links added to a SMC-R link group depends on the number + of RDMA devices exist in the system. The acceptable value ranges from 1 to 2. Only + for SMC-R v2.1 and later. + + Default: 2 diff --git a/include/net/netns/smc.h b/include/net/netns/smc.h index 582212ada3ba..da7023587824 100644 --- a/include/net/netns/smc.h +++ b/include/net/netns/smc.h @@ -22,5 +22,6 @@ struct netns_smc { int sysctl_smcr_testlink_time; int sysctl_wmem; int sysctl_rmem; + int sysctl_max_links_per_lgr; }; #endif diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 2a1388841951..c61666e5beed 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -2461,7 +2461,7 @@ static void smc_listen_work(struct work_struct *work) if (rc) goto out_decl; - rc = smc_clc_srv_v2x_features_validate(pclc, ini); + rc = smc_clc_srv_v2x_features_validate(new_smc, pclc, ini); if (rc) goto out_decl; diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index 8deb46c28f1d..1f87c8895a27 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -824,6 +824,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) struct smc_clc_smcd_gid_chid *gidchids; struct smc_clc_msg_proposal_area *pclc; struct smc_clc_ipv6_prefix *ipv6_prfx; + struct net *net = sock_net(&smc->sk); struct smc_clc_v2_extension *v2_ext; struct smc_clc_msg_smcd *pclc_smcd; struct smc_clc_msg_trail *trl; @@ -944,7 +945,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) if (smcr_indicated(ini->smc_type_v2)) { memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE); v2_ext->max_conns = SMC_CONN_PER_LGR_PREFER; - v2_ext->max_links = SMC_LINKS_PER_LGR_MAX_PREFER; + v2_ext->max_links = net->smc.sysctl_max_links_per_lgr; } pclc_base->hdr.length = htons(plen); @@ -1171,10 +1172,12 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact, return len > 0 ? 0 : len; } -int smc_clc_srv_v2x_features_validate(struct smc_clc_msg_proposal *pclc, +int smc_clc_srv_v2x_features_validate(struct smc_sock *smc, + struct smc_clc_msg_proposal *pclc, struct smc_init_info *ini) { struct smc_clc_v2_extension *pclc_v2_ext; + struct net *net = sock_net(&smc->sk); ini->max_conns = SMC_CONN_PER_LGR_MAX; ini->max_links = SMC_LINKS_ADD_LNK_MAX; @@ -1192,7 +1195,8 @@ int smc_clc_srv_v2x_features_validate(struct smc_clc_msg_proposal *pclc, if (ini->max_conns < SMC_CONN_PER_LGR_MIN) return SMC_CLC_DECL_MAXCONNERR; - ini->max_links = min_t(u8, pclc_v2_ext->max_links, SMC_LINKS_PER_LGR_MAX_PREFER); + ini->max_links = min_t(u8, pclc_v2_ext->max_links, + net->smc.sysctl_max_links_per_lgr); if (ini->max_links < SMC_LINKS_ADD_LNK_MIN) return SMC_CLC_DECL_MAXLINKERR; } diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h index c5c8e7db775a..89b258cedffe 100644 --- a/net/smc/smc_clc.h +++ b/net/smc/smc_clc.h @@ -422,7 +422,8 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, u8 version, u8 *eid, struct smc_init_info *ini); int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact, u8 version, u8 *negotiated_eid, struct smc_init_info *ini); -int smc_clc_srv_v2x_features_validate(struct smc_clc_msg_proposal *pclc, +int smc_clc_srv_v2x_features_validate(struct smc_sock *smc, + struct smc_clc_msg_proposal *pclc, struct smc_init_info *ini); int smc_clc_clnt_v2x_features_validate(struct smc_clc_first_contact_ext *fce, struct smc_init_info *ini); diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c index 5cbc18c6e62b..3e9bb921e40a 100644 --- a/net/smc/smc_sysctl.c +++ b/net/smc/smc_sysctl.c @@ -25,6 +25,8 @@ static int max_sndbuf = INT_MAX / 2; static int max_rcvbuf = INT_MAX / 2; static const int net_smc_wmem_init = (64 * 1024); static const int net_smc_rmem_init = (64 * 1024); +static int links_per_lgr_min = SMC_LINKS_ADD_LNK_MIN; +static int links_per_lgr_max = SMC_LINKS_ADD_LNK_MAX; static struct ctl_table smc_table[] = { { @@ -68,6 +70,15 @@ static struct ctl_table smc_table[] = { .extra1 = &min_rcvbuf, .extra2 = &max_rcvbuf, }, + { + .procname = "smcr_max_links_per_lgr", + .data = &init_net.smc.sysctl_max_links_per_lgr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &links_per_lgr_min, + .extra2 = &links_per_lgr_max, + }, { } }; @@ -97,6 +108,7 @@ int __net_init smc_sysctl_net_init(struct net *net) net->smc.sysctl_smcr_testlink_time = SMC_LLC_TESTLINK_DEFAULT_TIME; WRITE_ONCE(net->smc.sysctl_wmem, net_smc_wmem_init); WRITE_ONCE(net->smc.sysctl_rmem, net_smc_rmem_init); + net->smc.sysctl_max_links_per_lgr = SMC_LINKS_PER_LGR_MAX_PREFER; return 0; diff --git a/net/smc/smc_sysctl.h b/net/smc/smc_sysctl.h index 0becc11bd2f4..5783dd7575dd 100644 --- a/net/smc/smc_sysctl.h +++ b/net/smc/smc_sysctl.h @@ -23,6 +23,7 @@ void __net_exit smc_sysctl_net_exit(struct net *net); static inline int smc_sysctl_net_init(struct net *net) { net->smc.sysctl_autocorking_size = SMC_AUTOCORKING_DEFAULT_SIZE; + net->smc.sysctl_max_links_per_lgr = SMC_LINKS_PER_LGR_MAX_PREFER; return 0; } From 1f2c9dd73f0a279214f9b3c382b3f1df272b3253 Mon Sep 17 00:00:00 2001 From: Guangguan Wang Date: Wed, 22 Nov 2023 21:52:58 +0800 Subject: [PATCH 1378/7721] net/smc: add sysctl for max conns per lgr for SMC-R v2.1 Add a new sysctl: net.smc.smcr_max_conns_per_lgr, which is used to control the preferred max connections per lgr for SMC-R v2.1. The default value of this sysctl is 255, and the acceptable value ranges from 16 to 255. Signed-off-by: Guangguan Wang Reviewed-by: Dust Li Signed-off-by: David S. Miller --- Documentation/networking/smc-sysctl.rst | 6 ++++++ include/net/netns/smc.h | 1 + net/smc/smc_clc.c | 5 +++-- net/smc/smc_sysctl.c | 12 ++++++++++++ net/smc/smc_sysctl.h | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/smc-sysctl.rst b/Documentation/networking/smc-sysctl.rst index c6ef86ef4c4f..a874d007f2db 100644 --- a/Documentation/networking/smc-sysctl.rst +++ b/Documentation/networking/smc-sysctl.rst @@ -65,3 +65,9 @@ smcr_max_links_per_lgr - INTEGER for SMC-R v2.1 and later. Default: 2 + +smcr_max_conns_per_lgr - INTEGER + Controls the max number of connections can be added to a SMC-R link group. The + acceptable value ranges from 16 to 255. Only for SMC-R v2.1 and later. + + Default: 255 diff --git a/include/net/netns/smc.h b/include/net/netns/smc.h index da7023587824..fc752a50f91b 100644 --- a/include/net/netns/smc.h +++ b/include/net/netns/smc.h @@ -23,5 +23,6 @@ struct netns_smc { int sysctl_wmem; int sysctl_rmem; int sysctl_max_links_per_lgr; + int sysctl_max_conns_per_lgr; }; #endif diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index 1f87c8895a27..0fda5156eef0 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -944,7 +944,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) } if (smcr_indicated(ini->smc_type_v2)) { memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE); - v2_ext->max_conns = SMC_CONN_PER_LGR_PREFER; + v2_ext->max_conns = net->smc.sysctl_max_conns_per_lgr; v2_ext->max_links = net->smc.sysctl_max_links_per_lgr; } @@ -1191,7 +1191,8 @@ int smc_clc_srv_v2x_features_validate(struct smc_sock *smc, return SMC_CLC_DECL_NOV2EXT; if (ini->smcr_version & SMC_V2) { - ini->max_conns = min_t(u8, pclc_v2_ext->max_conns, SMC_CONN_PER_LGR_PREFER); + ini->max_conns = min_t(u8, pclc_v2_ext->max_conns, + net->smc.sysctl_max_conns_per_lgr); if (ini->max_conns < SMC_CONN_PER_LGR_MIN) return SMC_CLC_DECL_MAXCONNERR; diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c index 3e9bb921e40a..a5946d1b9d60 100644 --- a/net/smc/smc_sysctl.c +++ b/net/smc/smc_sysctl.c @@ -27,6 +27,8 @@ static const int net_smc_wmem_init = (64 * 1024); static const int net_smc_rmem_init = (64 * 1024); static int links_per_lgr_min = SMC_LINKS_ADD_LNK_MIN; static int links_per_lgr_max = SMC_LINKS_ADD_LNK_MAX; +static int conns_per_lgr_min = SMC_CONN_PER_LGR_MIN; +static int conns_per_lgr_max = SMC_CONN_PER_LGR_MAX; static struct ctl_table smc_table[] = { { @@ -79,6 +81,15 @@ static struct ctl_table smc_table[] = { .extra1 = &links_per_lgr_min, .extra2 = &links_per_lgr_max, }, + { + .procname = "smcr_max_conns_per_lgr", + .data = &init_net.smc.sysctl_max_conns_per_lgr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &conns_per_lgr_min, + .extra2 = &conns_per_lgr_max, + }, { } }; @@ -109,6 +120,7 @@ int __net_init smc_sysctl_net_init(struct net *net) WRITE_ONCE(net->smc.sysctl_wmem, net_smc_wmem_init); WRITE_ONCE(net->smc.sysctl_rmem, net_smc_rmem_init); net->smc.sysctl_max_links_per_lgr = SMC_LINKS_PER_LGR_MAX_PREFER; + net->smc.sysctl_max_conns_per_lgr = SMC_CONN_PER_LGR_PREFER; return 0; diff --git a/net/smc/smc_sysctl.h b/net/smc/smc_sysctl.h index 5783dd7575dd..eb2465ae1e15 100644 --- a/net/smc/smc_sysctl.h +++ b/net/smc/smc_sysctl.h @@ -24,6 +24,7 @@ static inline int smc_sysctl_net_init(struct net *net) { net->smc.sysctl_autocorking_size = SMC_AUTOCORKING_DEFAULT_SIZE; net->smc.sysctl_max_links_per_lgr = SMC_LINKS_PER_LGR_MAX_PREFER; + net->smc.sysctl_max_conns_per_lgr = SMC_CONN_PER_LGR_PREFER; return 0; } From e40f4c4e50fc81ebdeab5dacabd4e14d9fba5a1b Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Wed, 22 Nov 2023 10:34:34 -0800 Subject: [PATCH 1379/7721] octeon_ep: Solve style issues in control net files Solve observed style issues for kernel documentation and structure declarations in control net API definitions. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep/octep_ctrl_net.c | 24 ++-- .../marvell/octeon_ep/octep_ctrl_net.h | 115 ++++++++++-------- 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c index 0594607a2585..2eeeaa7188b1 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c @@ -122,7 +122,7 @@ int octep_ctrl_net_init(struct octep_device *oct) int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; int err; @@ -139,7 +139,7 @@ int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid) int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up, bool wait_for_response) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; init_send_req(&d.msg, req, state_sz, vfid); @@ -154,7 +154,7 @@ int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up, int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up, bool wait_for_response) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; init_send_req(&d.msg, req, state_sz, vfid); @@ -168,7 +168,7 @@ int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up, int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; int err; @@ -187,7 +187,7 @@ int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr) int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr, bool wait_for_response) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; init_send_req(&d.msg, req, mac_sz, vfid); @@ -201,7 +201,7 @@ int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr, int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu, bool wait_for_response) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; init_send_req(&d.msg, req, mtu_sz, vfid); @@ -216,7 +216,7 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid, struct octep_iface_rx_stats *rx_stats, struct octep_iface_tx_stats *tx_stats) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; struct octep_ctrl_net_h2f_resp *resp; int err; @@ -236,7 +236,7 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid, int octep_ctrl_net_get_link_info(struct octep_device *oct, int vfid, struct octep_iface_link_info *link_info) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; struct octep_ctrl_net_h2f_resp *resp; int err; @@ -262,7 +262,7 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct, int vfid, struct octep_iface_link_info *link_info, bool wait_for_response) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req; init_send_req(&d.msg, req, link_info_sz, vfid); @@ -331,8 +331,8 @@ static int process_mbox_notify(struct octep_device *oct, void octep_ctrl_net_recv_fw_messages(struct octep_device *oct) { static u16 msg_sz = sizeof(union octep_ctrl_net_max_data); - union octep_ctrl_net_max_data data = {0}; - struct octep_ctrl_mbox_msg msg = {0}; + union octep_ctrl_net_max_data data = {}; + struct octep_ctrl_mbox_msg msg = {}; int ret; msg.hdr.s.sz = msg_sz; @@ -356,7 +356,7 @@ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct) int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, struct octep_fw_info *info) { - struct octep_ctrl_net_wait_data d = {0}; + struct octep_ctrl_net_wait_data d = {}; struct octep_ctrl_net_h2f_resp *resp; struct octep_ctrl_net_h2f_req *req; int err; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h index b330f370131b..02b8fcf890d0 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h @@ -218,87 +218,95 @@ struct octep_ctrl_net_wait_data { } data; }; -/** Initialize data for ctrl net. +/** + * octep_ctrl_net_init() - Initialize data for ctrl net. * - * @param oct: non-null pointer to struct octep_device. + * @oct: non-null pointer to struct octep_device. * * return value: 0 on success, -errno on error. */ int octep_ctrl_net_init(struct octep_device *oct); -/** Get link status from firmware. +/** + * octep_ctrl_net_get_link_status() - Get link status from firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. * * return value: link status 0=down, 1=up. */ int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid); -/** Set link status in firmware. +/** + * octep_ctrl_net_set_link_status() - Set link status in firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param up: boolean status. - * @param wait_for_response: poll for response. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @up: boolean status. + * @wait_for_response: poll for response. * * return value: 0 on success, -errno on failure */ int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up, bool wait_for_response); -/** Set rx state in firmware. +/** + * octep_ctrl_net_set_rx_state() - Set rx state in firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param up: boolean status. - * @param wait_for_response: poll for response. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @up: boolean status. + * @wait_for_response: poll for response. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up, bool wait_for_response); -/** Get mac address from firmware. +/** + * octep_ctrl_net_get_mac_addr() - Get mac address from firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param addr: non-null pointer to mac address. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @addr: non-null pointer to mac address. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr); -/** Set mac address in firmware. +/** + * octep_ctrl_net_set_mac_addr() - Set mac address in firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param addr: non-null pointer to mac address. - * @param wait_for_response: poll for response. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @addr: non-null pointer to mac address. + * @wait_for_response: poll for response. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr, bool wait_for_response); -/** Set mtu in firmware. +/** + * octep_ctrl_net_set_mtu() - Set mtu in firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param mtu: mtu. - * @param wait_for_response: poll for response. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @mtu: mtu. + * @wait_for_response: poll for response. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu, bool wait_for_response); -/** Get interface statistics from firmware. +/** + * octep_ctrl_net_get_if_stats() - Get interface statistics from firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param rx_stats: non-null pointer struct octep_iface_rx_stats. - * @param tx_stats: non-null pointer struct octep_iface_tx_stats. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @rx_stats: non-null pointer struct octep_iface_rx_stats. + * @tx_stats: non-null pointer struct octep_iface_tx_stats. * * return value: 0 on success, -errno on failure. */ @@ -306,23 +314,25 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid, struct octep_iface_rx_stats *rx_stats, struct octep_iface_tx_stats *tx_stats); -/** Get link info from firmware. +/** + * octep_ctrl_net_get_link_info() - Get link info from firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param link_info: non-null pointer to struct octep_iface_link_info. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @link_info: non-null pointer to struct octep_iface_link_info. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_get_link_info(struct octep_device *oct, int vfid, struct octep_iface_link_info *link_info); -/** Set link info in firmware. +/** + * octep_ctrl_net_set_link_info() - Set link info in firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param link_info: non-null pointer to struct octep_iface_link_info. - * @param wait_for_response: poll for response. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @link_info: non-null pointer to struct octep_iface_link_info. + * @wait_for_response: poll for response. * * return value: 0 on success, -errno on failure. */ @@ -331,26 +341,29 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info, bool wait_for_response); -/** Poll for firmware messages and process them. +/** + * octep_ctrl_net_recv_fw_messages() - Poll for firmware messages and process them. * - * @param oct: non-null pointer to struct octep_device. + * @oct: non-null pointer to struct octep_device. */ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct); -/** Get info from firmware. +/** + * octep_ctrl_net_get_info() - Get info from firmware. * - * @param oct: non-null pointer to struct octep_device. - * @param vfid: Index of virtual function. - * @param info: non-null pointer to struct octep_fw_info. + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @info: non-null pointer to struct octep_fw_info. * * return value: 0 on success, -errno on failure. */ int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, struct octep_fw_info *info); -/** Uninitialize data for ctrl net. +/** + * octep_ctrl_net_uninit() - Uninitialize data for ctrl net. * - * @param oct: non-null pointer to struct octep_device. + * @oct: non-null pointer to struct octep_device. * * return value: 0 on success, -errno on error. */ From 0a5f8534e3986b636570f4d6d32e22af7d868d45 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Wed, 22 Nov 2023 10:34:35 -0800 Subject: [PATCH 1380/7721] octeon_ep: get max rx packet length from firmware Max receive packet length can vary across SoCs, so this needs to be queried from respective firmware and filled by driver. A control net get mtu api should be implemented to do the same. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../ethernet/marvell/octeon_ep/octep_config.h | 2 -- .../marvell/octeon_ep/octep_ctrl_net.c | 18 ++++++++++++++++++ .../marvell/octeon_ep/octep_ctrl_net.h | 10 ++++++++++ .../ethernet/marvell/octeon_ep/octep_main.c | 10 +++++++++- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h index 91cfa19c65b9..4c937ba5589f 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h @@ -45,8 +45,6 @@ /* Minimum MTU supported by Octeon network interface */ #define OCTEP_MIN_MTU ETH_MIN_MTU -/* Maximum MTU supported by Octeon interface*/ -#define OCTEP_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN)) /* Default MTU */ #define OCTEP_DEFAULT_MTU 1500 diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c index 2eeeaa7188b1..5fa596c674da 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c @@ -198,6 +198,24 @@ int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr, return octep_send_mbox_req(oct, &d, wait_for_response); } +int octep_ctrl_net_get_mtu(struct octep_device *oct, int vfid) +{ + struct octep_ctrl_net_wait_data d = {}; + struct octep_ctrl_net_h2f_req *req; + int err; + + req = &d.data.req; + init_send_req(&d.msg, req, mtu_sz, vfid); + req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU; + req->mtu.cmd = OCTEP_CTRL_NET_CMD_GET; + + err = octep_send_mbox_req(oct, &d, true); + if (err < 0) + return err; + + return d.data.resp.mtu.val; +} + int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu, bool wait_for_response) { diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h index 02b8fcf890d0..a2463b460ad9 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h @@ -287,6 +287,16 @@ int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr); int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr, bool wait_for_response); +/** + * octep_ctrl_net_get_mtu() - Get max MTU from firmware. + * + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * + * return value: mtu on success, -errno on failure. + */ +int octep_ctrl_net_get_mtu(struct octep_device *oct, int vfid); + /** * octep_ctrl_net_set_mtu() - Set mtu in firmware. * diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 2da00a701df2..423eec5ff3ad 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -1307,6 +1307,7 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct octep_device *octep_dev = NULL; struct net_device *netdev; + int max_rx_pktlen; int err; err = pci_enable_device(pdev); @@ -1377,8 +1378,15 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->hw_features = NETIF_F_SG; netdev->features |= netdev->hw_features; + + max_rx_pktlen = octep_ctrl_net_get_mtu(octep_dev, OCTEP_CTRL_NET_INVALID_VFID); + if (max_rx_pktlen < 0) { + dev_err(&octep_dev->pdev->dev, + "Failed to get max receive packet size; err = %d\n", max_rx_pktlen); + goto register_dev_err; + } netdev->min_mtu = OCTEP_MIN_MTU; - netdev->max_mtu = OCTEP_MAX_MTU; + netdev->max_mtu = max_rx_pktlen - (ETH_HLEN + ETH_FCS_LEN); netdev->mtu = OCTEP_DEFAULT_MTU; err = octep_ctrl_net_get_mac_addr(octep_dev, OCTEP_CTRL_NET_INVALID_VFID, From dd043b393c8536574a95c567c49d237c4c604699 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Nov 2023 17:09:05 -0600 Subject: [PATCH 1381/7721] dt-bindings: net: qcom,ipa: add SM8550 compatible Add support for SM8550, which uses IPA v5.5. Signed-off-by: Alex Elder Reviewed-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/qcom,ipa.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml index 2d5e4ffb2f9e..702eadccdf99 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml @@ -52,6 +52,7 @@ properties: - qcom,sdx65-ipa - qcom,sm6350-ipa - qcom,sm8350-ipa + - qcom,sm8550-ipa reg: items: From b134b10cf5bbe82f10b9d6e14098e98c2782fcd0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Nov 2023 17:09:06 -0600 Subject: [PATCH 1382/7721] net: ipa: update IPA version comments in "ipa_reg.h" Some definitions in "ipa_reg.h" are only valid for certain versions of IPA. In such cases a comment indicates a version or range of versions where the definition is (or is not) valid. Almost all such cases look like "IPA vX.Y", but a few don't include the "IPA" tag. Update these so they all consistently include "IPA". And replace a few lines that talk about "the next bit" in the definition of the ipa_irq_id enumerated type with a more concise comment using the "IPA vX.Y" convention. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_reg.h | 86 +++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index 3ac48dea865b..aa1cbe76a450 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -240,25 +240,25 @@ enum ipa_reg_local_pkt_proc_cntxt_field_id { /* COUNTER_CFG register */ enum ipa_reg_counter_cfg_field_id { - EOT_COAL_GRANULARITY, /* Not v3.5+ */ + EOT_COAL_GRANULARITY, /* Not IPA v3.5+ */ AGGR_GRANULARITY, }; /* IPA_TX_CFG register */ enum ipa_reg_ipa_tx_cfg_field_id { - TX0_PREFETCH_DISABLE, /* Not v4.0+ */ - TX1_PREFETCH_DISABLE, /* Not v4.0+ */ - PREFETCH_ALMOST_EMPTY_SIZE, /* Not v4.0+ */ - PREFETCH_ALMOST_EMPTY_SIZE_TX0, /* v4.0+ */ - DMAW_SCND_OUTSD_PRED_THRESHOLD, /* v4.0+ */ - DMAW_SCND_OUTSD_PRED_EN, /* v4.0+ */ - DMAW_MAX_BEATS_256_DIS, /* v4.0+ */ - PA_MASK_EN, /* v4.0+ */ - PREFETCH_ALMOST_EMPTY_SIZE_TX1, /* v4.0+ */ - DUAL_TX_ENABLE, /* v4.5+ */ - SSPND_PA_NO_START_STATE, /* v4,2+, not v4.5 */ - SSPND_PA_NO_BQ_STATE, /* v4.2 only */ - HOLB_STICKY_DROP_EN, /* v5.0+ */ + TX0_PREFETCH_DISABLE, /* Not IPA v4.0+ */ + TX1_PREFETCH_DISABLE, /* Not IPA v4.0+ */ + PREFETCH_ALMOST_EMPTY_SIZE, /* Not IPA v4.0+ */ + PREFETCH_ALMOST_EMPTY_SIZE_TX0, /* IPA v4.0+ */ + DMAW_SCND_OUTSD_PRED_THRESHOLD, /* IPA v4.0+ */ + DMAW_SCND_OUTSD_PRED_EN, /* IPA v4.0+ */ + DMAW_MAX_BEATS_256_DIS, /* IPA v4.0+ */ + PA_MASK_EN, /* IPA v4.0+ */ + PREFETCH_ALMOST_EMPTY_SIZE_TX1, /* IPA v4.0+ */ + DUAL_TX_ENABLE, /* IPA v4.5+ */ + SSPND_PA_NO_START_STATE, /* IPA v4,2+, not IPA v4.5 */ + SSPND_PA_NO_BQ_STATE, /* IPA v4.2 only */ + HOLB_STICKY_DROP_EN, /* IPA v5.0+ */ }; /* FLAVOR_0 register */ @@ -319,8 +319,8 @@ enum ipa_reg_rsrc_grp_rsrc_type_field_id { /* ENDP_INIT_CTRL register */ enum ipa_reg_endp_init_ctrl_field_id { - ENDP_SUSPEND, /* Not v4.0+ */ - ENDP_DELAY, /* Not v4.2+ */ + ENDP_SUSPEND, /* Not IPA v4.0+ */ + ENDP_DELAY, /* Not IPA v4.2+ */ }; /* ENDP_INIT_CFG register */ @@ -359,11 +359,11 @@ enum ipa_reg_endp_init_hdr_field_id { HDR_ADDITIONAL_CONST_LEN, HDR_OFST_PKT_SIZE_VALID, HDR_OFST_PKT_SIZE, - HDR_A5_MUX, /* Not v4.9+ */ + HDR_A5_MUX, /* Not IPA v4.9+ */ HDR_LEN_INC_DEAGG_HDR, - HDR_METADATA_REG_VALID, /* Not v4.5+ */ - HDR_LEN_MSB, /* v4.5+ */ - HDR_OFST_METADATA_MSB, /* v4.5+ */ + HDR_METADATA_REG_VALID, /* Not IPA v4.5+ */ + HDR_LEN_MSB, /* IPA v4.5+ */ + HDR_OFST_METADATA_MSB, /* IPA v4.5+ */ }; /* ENDP_INIT_HDR_EXT register */ @@ -374,23 +374,23 @@ enum ipa_reg_endp_init_hdr_ext_field_id { HDR_PAYLOAD_LEN_INC_PADDING, HDR_TOTAL_LEN_OR_PAD_OFFSET, HDR_PAD_TO_ALIGNMENT, - HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB, /* v4.5+ */ - HDR_OFST_PKT_SIZE_MSB, /* v4.5+ */ - HDR_ADDITIONAL_CONST_LEN_MSB, /* v4.5+ */ - HDR_BYTES_TO_REMOVE_VALID, /* v5.0+ */ - HDR_BYTES_TO_REMOVE, /* v5.0+ */ + HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB, /* IPA v4.5+ */ + HDR_OFST_PKT_SIZE_MSB, /* IPA v4.5+ */ + HDR_ADDITIONAL_CONST_LEN_MSB, /* IPA v4.5+ */ + HDR_BYTES_TO_REMOVE_VALID, /* IPA v5.0+ */ + HDR_BYTES_TO_REMOVE, /* IPA v5.0+ */ }; /* ENDP_INIT_MODE register */ enum ipa_reg_endp_init_mode_field_id { ENDP_MODE, - DCPH_ENABLE, /* v4.5+ */ + DCPH_ENABLE, /* IPA v4.5+ */ DEST_PIPE_INDEX, BYTE_THRESHOLD, PIPE_REPLICATION_EN, PAD_EN, - HDR_FTCH_DISABLE, /* v4.5+ */ - DRBIP_ACL_ENABLE, /* v4.9+ */ + HDR_FTCH_DISABLE, /* IPA v4.5+ */ + DRBIP_ACL_ENABLE, /* IPA v4.9+ */ }; /** enum ipa_mode - ENDP_INIT_MODE register MODE field value */ @@ -439,10 +439,10 @@ enum ipa_reg_endp_init_hol_block_en_field_id { /* ENDP_INIT_HOL_BLOCK_TIMER register */ enum ipa_reg_endp_init_hol_block_timer_field_id { - TIMER_BASE_VALUE, /* Not v4.5+ */ - TIMER_SCALE, /* v4.2 only */ - TIMER_LIMIT, /* v4.5+ */ - TIMER_GRAN_SEL, /* v4.5+ */ + TIMER_BASE_VALUE, /* Not IPA v4.5+ */ + TIMER_SCALE, /* IPA v4.2 only */ + TIMER_LIMIT, /* IPA v4.5+ */ + TIMER_GRAN_SEL, /* IPA v4.5+ */ }; /* ENDP_INIT_DEAGGR register */ @@ -463,7 +463,7 @@ enum ipa_reg_endp_init_rsrc_grp_field_id { /* ENDP_INIT_SEQ register */ enum ipa_reg_endp_init_seq_field_id { SEQ_TYPE, - SEQ_REP_TYPE, /* Not v4.5+ */ + SEQ_REP_TYPE, /* Not IPA v4.5+ */ }; /** @@ -512,8 +512,8 @@ enum ipa_seq_rep_type { enum ipa_reg_endp_status_field_id { STATUS_EN, STATUS_ENDP, - STATUS_LOCATION, /* Not v4.5+ */ - STATUS_PKT_SUPPRESS, /* v4.0+ */ + STATUS_LOCATION, /* Not IPA v4.5+ */ + STATUS_PKT_SUPPRESS, /* IPA v4.0+ */ }; /* ENDP_FILTER_ROUTER_HSH_CFG register */ @@ -588,8 +588,7 @@ enum ipa_reg_endp_cache_cfg_field_id { */ enum ipa_irq_id { IPA_IRQ_BAD_SNOC_ACCESS = 0x0, - /* The next bit is not present for IPA v3.5+ */ - IPA_IRQ_EOT_COAL = 0x1, + IPA_IRQ_EOT_COAL = 0x1, /* Not IPA v3.5+ */ IPA_IRQ_UC_0 = 0x2, IPA_IRQ_UC_1 = 0x3, IPA_IRQ_UC_2 = 0x4, @@ -610,17 +609,14 @@ enum ipa_irq_id { IPA_IRQ_PIPE_YELLOW_ABOVE = 0x13, IPA_IRQ_PIPE_RED_ABOVE = 0x14, IPA_IRQ_UCP = 0x15, - /* The next bit is not present for IPA v4.5+ */ - IPA_IRQ_DCMP = 0x16, + IPA_IRQ_DCMP = 0x16, /* Not IPA v4.5+ */ IPA_IRQ_GSI_EE = 0x17, IPA_IRQ_GSI_IPA_IF_TLV_RCVD = 0x18, IPA_IRQ_GSI_UC = 0x19, - /* The next bit is present for IPA v4.5+ */ - IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a, - /* The next three bits are present for IPA v4.9+ */ - IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b, - IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c, - IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d, + IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a, /* IPA v4.5+ */ + IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b, /* IPA v4.9+ */ + IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c, /* IPA v4.9+ */ + IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d, /* IPA v4.9+ */ IPA_IRQ_COUNT, /* Last; not an id */ }; From b00e190cc2000aea4622202d8f081d28ab4bbe41 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Nov 2023 17:09:07 -0600 Subject: [PATCH 1383/7721] net: ipa: prepare for IPA v5.5 For IPA v5.5+, the QTIME_TIMESTAMP_CFG register no longer defines two fields in the DPL timestamp. Make the code referencing those fields in ipa_qtime_config() conditional based on IPA version. IPA v5.0+ supports the IPA_MEM_AP_V4_FILTER and IPA_MEM_AP_V6_FILTER memory regions. Update ipa_mem_id_valid() to reflect that. IPA v5.5 no longer supports a few register fields, adds some others, and removes support for a few IPA interrupt types. Update "ipa_reg.h" to include information about IPA v5.5. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_main.c | 9 ++++++--- drivers/net/ipa/ipa_mem.c | 2 +- drivers/net/ipa/ipa_reg.h | 32 +++++++++++++++++++------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index da853353a5c7..8893290e132b 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -74,6 +74,7 @@ #define IPA_PAS_ID 15 /* Shift of 19.2 MHz timestamp to achieve lower resolution timestamps */ +/* IPA v5.5+ does not specify Qtime timestamp config for DPL */ #define DPL_TIMESTAMP_SHIFT 14 /* ~1.172 kHz, ~853 usec per tick */ #define TAG_TIMESTAMP_SHIFT 14 #define NAT_TIMESTAMP_SHIFT 24 /* ~1.144 Hz, ~874 msec per tick */ @@ -376,9 +377,11 @@ static void ipa_qtime_config(struct ipa *ipa) iowrite32(0, ipa->reg_virt + reg_offset(reg)); reg = ipa_reg(ipa, QTIME_TIMESTAMP_CFG); - /* Set DPL time stamp resolution to use Qtime (instead of 1 msec) */ - val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); - val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + if (ipa->version < IPA_VERSION_5_5) { + /* Set DPL time stamp resolution to use Qtime (not 1 msec) */ + 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); diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c index db6ada2343af..694960537ecd 100644 --- a/drivers/net/ipa/ipa_mem.c +++ b/drivers/net/ipa/ipa_mem.c @@ -165,7 +165,7 @@ static bool ipa_mem_id_valid(struct ipa *ipa, enum ipa_mem_id mem_id) case IPA_MEM_AP_V4_FILTER: case IPA_MEM_AP_V6_FILTER: - if (version != IPA_VERSION_5_0) + if (version < IPA_VERSION_5_0) return false; break; diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index aa1cbe76a450..23231f0df93a 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -277,8 +277,8 @@ enum ipa_reg_idle_indication_cfg_field_id { /* QTIME_TIMESTAMP_CFG register */ enum ipa_reg_qtime_timestamp_cfg_field_id { - DPL_TIMESTAMP_LSB, - DPL_TIMESTAMP_SEL, + DPL_TIMESTAMP_LSB, /* Not IPA v5.5+ */ + DPL_TIMESTAMP_SEL, /* Not IPA v5.5+ */ TAG_TIMESTAMP_LSB, NAT_TIMESTAMP_LSB, }; @@ -329,6 +329,7 @@ enum ipa_reg_endp_init_cfg_field_id { CS_OFFLOAD_EN, CS_METADATA_HDR_OFFSET, CS_GEN_QMB_MASTER_SEL, + PIPE_REPLICATE_EN, /* IPA v5.5+ */ }; /** enum ipa_cs_offload_en - ENDP_INIT_CFG register CS_OFFLOAD_EN field value */ @@ -387,7 +388,7 @@ enum ipa_reg_endp_init_mode_field_id { DCPH_ENABLE, /* IPA v4.5+ */ DEST_PIPE_INDEX, BYTE_THRESHOLD, - PIPE_REPLICATION_EN, + PIPE_REPLICATION_EN, /* Not IPA v5.5+ */ PAD_EN, HDR_FTCH_DISABLE, /* IPA v4.5+ */ DRBIP_ACL_ENABLE, /* IPA v4.9+ */ @@ -412,6 +413,7 @@ enum ipa_reg_endp_init_aggr_field_id { FORCE_CLOSE, HARD_BYTE_LIMIT_EN, AGGR_GRAN_SEL, + AGGR_COAL_L2, /* IPA v5.5+ */ }; /** enum ipa_aggr_en - ENDP_INIT_AGGR register AGGR_EN field value */ @@ -585,9 +587,11 @@ enum ipa_reg_endp_cache_cfg_field_id { * @IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN: (Not currently used) * @IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN: (Not currently used) * @IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN: (Not currently used) + * @IPA_IRQ_ERROR_NON_FATAL: (Not currently used) + * @IPA_IRQ_ERROR_FATAL: (Not currently used) */ enum ipa_irq_id { - IPA_IRQ_BAD_SNOC_ACCESS = 0x0, + IPA_IRQ_BAD_SNOC_ACCESS = 0x0, /* Not IPA v5.5+ */ IPA_IRQ_EOT_COAL = 0x1, /* Not IPA v3.5+ */ IPA_IRQ_UC_0 = 0x2, IPA_IRQ_UC_1 = 0x3, @@ -596,11 +600,11 @@ enum ipa_irq_id { IPA_IRQ_UC_IN_Q_NOT_EMPTY = 0x6, IPA_IRQ_UC_RX_CMD_Q_NOT_FULL = 0x7, IPA_IRQ_PROC_UC_ACK_Q_NOT_EMPTY = 0x8, - IPA_IRQ_RX_ERR = 0x9, - IPA_IRQ_DEAGGR_ERR = 0xa, - IPA_IRQ_TX_ERR = 0xb, - IPA_IRQ_STEP_MODE = 0xc, - IPA_IRQ_PROC_ERR = 0xd, + IPA_IRQ_RX_ERR = 0x9, /* Not IPA v5.5+ */ + IPA_IRQ_DEAGGR_ERR = 0xa, /* Not IPA v5.5+ */ + IPA_IRQ_TX_ERR = 0xb, /* Not IPA v5.5+ */ + IPA_IRQ_STEP_MODE = 0xc, /* Not IPA v5.5+ */ + IPA_IRQ_PROC_ERR = 0xd, /* Not IPA v5.5+ */ IPA_IRQ_TX_SUSPEND = 0xe, IPA_IRQ_TX_HOLB_DROP = 0xf, IPA_IRQ_BAM_GSI_IDLE = 0x10, @@ -613,10 +617,12 @@ enum ipa_irq_id { IPA_IRQ_GSI_EE = 0x17, IPA_IRQ_GSI_IPA_IF_TLV_RCVD = 0x18, IPA_IRQ_GSI_UC = 0x19, - IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a, /* IPA v4.5+ */ - IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b, /* IPA v4.9+ */ - IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c, /* IPA v4.9+ */ - IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d, /* IPA v4.9+ */ + IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a, /* IPA v4.5-v5.2 */ + IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b, /* IPA v4.9-v5.2 */ + IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c, /* IPA v4.9-v5.2 */ + IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d, /* IPA v4.9-v5.2 */ + IPA_IRQ_ERROR_NON_FATAL = 0x1e, /* IPA v5.5+ */ + IPA_IRQ_ERROR_FATAL = 0x1f, /* IPA v5.5+ */ IPA_IRQ_COUNT, /* Last; not an id */ }; From 1bfeafabcd5e95424cf1ce910f04507f26b14702 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Nov 2023 17:09:08 -0600 Subject: [PATCH 1384/7721] net: ipa: add IPA v5.5 register definitions GSI register definitions for IPA v5.5 are the same as those used for IPA v5.0. Update ipa_reg_id_valid() to reflect that IPA v5.0+ supports source and destination resource groups 4 through 7. Add the definitions of IPA register offsets and fields for IPA v5.5. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/Makefile | 2 +- drivers/net/ipa/gsi_reg.c | 1 + drivers/net/ipa/ipa_reg.c | 6 +- drivers/net/ipa/ipa_reg.h | 1 + drivers/net/ipa/reg/ipa_reg-v5.5.c | 565 +++++++++++++++++++++++++++++ 5 files changed, 572 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ipa/reg/ipa_reg-v5.5.c diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile index 7293d5cc2b2b..9d2182068e1c 100644 --- a/drivers/net/ipa/Makefile +++ b/drivers/net/ipa/Makefile @@ -2,7 +2,7 @@ # # Makefile for the Qualcomm IPA driver. -IPA_REG_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 +IPA_REG_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5 # Some IPA versions can reuse another set of GSI register definitions. GSI_REG_VERSIONS := 3.1 3.5.1 4.0 4.5 4.9 4.11 5.0 diff --git a/drivers/net/ipa/gsi_reg.c b/drivers/net/ipa/gsi_reg.c index c5458e28b12f..106c43884aef 100644 --- a/drivers/net/ipa/gsi_reg.c +++ b/drivers/net/ipa/gsi_reg.c @@ -110,6 +110,7 @@ static const struct regs *gsi_regs(struct gsi *gsi) return &gsi_regs_v4_11; case IPA_VERSION_5_0: + case IPA_VERSION_5_5: return &gsi_regs_v5_0; default: diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c index 818a84f7c42d..6a3203ae6f1e 100644 --- a/drivers/net/ipa/ipa_reg.c +++ b/drivers/net/ipa/ipa_reg.c @@ -44,12 +44,12 @@ static bool ipa_reg_id_valid(struct ipa *ipa, enum ipa_reg_id reg_id) case DST_RSRC_GRP_45_RSRC_TYPE: return version <= IPA_VERSION_3_1 || version == IPA_VERSION_4_5 || - version == IPA_VERSION_5_0; + version >= IPA_VERSION_5_0; case SRC_RSRC_GRP_67_RSRC_TYPE: case DST_RSRC_GRP_67_RSRC_TYPE: return version <= IPA_VERSION_3_1 || - version == IPA_VERSION_5_0; + version >= IPA_VERSION_5_0; case ENDP_FILTER_ROUTER_HSH_CFG: return version < IPA_VERSION_5_0 && @@ -125,6 +125,8 @@ static const struct regs *ipa_regs(enum ipa_version version) return &ipa_regs_v4_11; case IPA_VERSION_5_0: return &ipa_regs_v5_0; + case IPA_VERSION_5_5: + return &ipa_regs_v5_5; default: return NULL; } diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index 23231f0df93a..2998f115f12c 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -639,6 +639,7 @@ extern const struct regs ipa_regs_v4_7; extern const struct regs ipa_regs_v4_9; extern const struct regs ipa_regs_v4_11; extern const struct regs ipa_regs_v5_0; +extern const struct regs ipa_regs_v5_5; const struct reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id); diff --git a/drivers/net/ipa/reg/ipa_reg-v5.5.c b/drivers/net/ipa/reg/ipa_reg-v5.5.c new file mode 100644 index 000000000000..26ca9c9bac59 --- /dev/null +++ b/drivers/net/ipa/reg/ipa_reg-v5.5.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Copyright (C) 2023 Linaro Ltd. */ + +#include +#include +#include + +#include "../ipa_reg.h" +#include "../ipa_version.h" + +static const u32 reg_flavor_0_fmask[] = { + [MAX_PIPES] = GENMASK(7, 0), + [MAX_CONS_PIPES] = GENMASK(15, 8), + [MAX_PROD_PIPES] = GENMASK(23, 16), + [PROD_LOWEST] = GENMASK(31, 24), +}; + +REG_FIELDS(FLAVOR_0, flavor_0, 0x00000000); + +static const u32 reg_comp_cfg_fmask[] = { + [RAM_ARB_PRI_CLIENT_SAMP_FIX_DIS] = BIT(0), + [GSI_SNOC_BYPASS_DIS] = BIT(1), + [GEN_QMB_0_SNOC_BYPASS_DIS] = BIT(2), + [GEN_QMB_1_SNOC_BYPASS_DIS] = BIT(3), + /* Bit 4 reserved */ + [IPA_QMB_SELECT_CONS_EN] = BIT(5), + [IPA_QMB_SELECT_PROD_EN] = BIT(6), + [GSI_MULTI_INORDER_RD_DIS] = BIT(7), + [GSI_MULTI_INORDER_WR_DIS] = BIT(8), + [GEN_QMB_0_MULTI_INORDER_RD_DIS] = BIT(9), + [GEN_QMB_1_MULTI_INORDER_RD_DIS] = BIT(10), + [GEN_QMB_0_MULTI_INORDER_WR_DIS] = BIT(11), + [GEN_QMB_1_MULTI_INORDER_WR_DIS] = BIT(12), + [GEN_QMB_0_SNOC_CNOC_LOOP_PROT_DIS] = BIT(13), + [GSI_SNOC_CNOC_LOOP_PROT_DISABLE] = BIT(14), + [GSI_MULTI_AXI_MASTERS_DIS] = BIT(15), + [IPA_QMB_SELECT_GLOBAL_EN] = BIT(16), + /* Bits 17-18 reserved */ + [QMB_RAM_RD_CACHE_DISABLE] = BIT(19), + [GENQMB_AOOOWR] = BIT(20), + [IF_OUT_OF_BUF_STOP_RESET_MASK_EN] = BIT(21), + [ATOMIC_FETCHER_ARB_LOCK_DIS] = GENMASK(27, 22), + /* Bits 28-29 reserved */ + [GEN_QMB_1_DYNAMIC_ASIZE] = BIT(30), + [GEN_QMB_0_DYNAMIC_ASIZE] = BIT(31), +}; + +REG_FIELDS(COMP_CFG, comp_cfg, 0x00000048); + +static const u32 reg_clkon_cfg_fmask[] = { + [CLKON_RX] = BIT(0), + [CLKON_PROC] = BIT(1), + [TX_WRAPPER] = BIT(2), + [CLKON_MISC] = BIT(3), + [RAM_ARB] = BIT(4), + [FTCH_HPS] = BIT(5), + [FTCH_DPS] = BIT(6), + [CLKON_HPS] = BIT(7), + [CLKON_DPS] = BIT(8), + [RX_HPS_CMDQS] = BIT(9), + [HPS_DPS_CMDQS] = BIT(10), + [DPS_TX_CMDQS] = BIT(11), + [RSRC_MNGR] = BIT(12), + [CTX_HANDLER] = BIT(13), + [ACK_MNGR] = BIT(14), + [D_DCPH] = BIT(15), + [H_DCPH] = BIT(16), + /* Bit 17 reserved */ + [NTF_TX_CMDQS] = BIT(18), + [CLKON_TX_0] = BIT(19), + [CLKON_TX_1] = BIT(20), + [CLKON_FNR] = BIT(21), + [QSB2AXI_CMDQ_L] = BIT(22), + [AGGR_WRAPPER] = BIT(23), + [RAM_SLAVEWAY] = BIT(24), + [CLKON_QMB] = BIT(25), + [WEIGHT_ARB] = BIT(26), + [GSI_IF] = BIT(27), + [CLKON_GLOBAL] = BIT(28), + [GLOBAL_2X_CLK] = BIT(29), + [DPL_FIFO] = BIT(30), + [DRBIP] = BIT(31), +}; + +REG_FIELDS(CLKON_CFG, clkon_cfg, 0x00000050); + +static const u32 reg_route_fmask[] = { + [ROUTE_DEF_PIPE] = GENMASK(7, 0), + [ROUTE_FRAG_DEF_PIPE] = GENMASK(15, 8), + [ROUTE_DEF_HDR_OFST] = GENMASK(25, 16), + [ROUTE_DEF_HDR_TABLE] = BIT(26), + [ROUTE_DEF_RETAIN_HDR] = BIT(27), + [ROUTE_DIS] = BIT(28), + /* Bits 29-31 reserved */ +}; + +REG_FIELDS(ROUTE, route, 0x00000054); + +static const u32 reg_shared_mem_size_fmask[] = { + [MEM_SIZE] = GENMASK(15, 0), + [MEM_BADDR] = GENMASK(31, 16), +}; + +REG_FIELDS(SHARED_MEM_SIZE, shared_mem_size, 0x0000005c); + +static const u32 reg_qsb_max_writes_fmask[] = { + [GEN_QMB_0_MAX_WRITES] = GENMASK(3, 0), + [GEN_QMB_1_MAX_WRITES] = GENMASK(7, 4), + /* Bits 8-31 reserved */ +}; + +REG_FIELDS(QSB_MAX_WRITES, qsb_max_writes, 0x00000070); + +static const u32 reg_qsb_max_reads_fmask[] = { + [GEN_QMB_0_MAX_READS] = GENMASK(3, 0), + [GEN_QMB_1_MAX_READS] = GENMASK(7, 4), + /* Bits 8-15 reserved */ + [GEN_QMB_0_MAX_READS_BEATS] = GENMASK(23, 16), + [GEN_QMB_1_MAX_READS_BEATS] = GENMASK(31, 24), +}; + +REG_FIELDS(QSB_MAX_READS, qsb_max_reads, 0x00000074); + +/* Valid bits defined by ipa->available */ + +REG_STRIDE(STATE_AGGR_ACTIVE, state_aggr_active, 0x00000120, 0x0004); + +static const u32 reg_filt_rout_cache_flush_fmask[] = { + [ROUTER_CACHE] = BIT(0), + /* Bits 1-3 reserved */ + [FILTER_CACHE] = BIT(4), + /* Bits 5-31 reserved */ +}; + +REG_FIELDS(FILT_ROUT_CACHE_FLUSH, filt_rout_cache_flush, 0x0000404); + +static const u32 reg_local_pkt_proc_cntxt_fmask[] = { + [IPA_BASE_ADDR] = GENMASK(17, 0), + /* Bits 18-31 reserved */ +}; + +/* Offset must be a multiple of 8 */ +REG_FIELDS(LOCAL_PKT_PROC_CNTXT, local_pkt_proc_cntxt, 0x00000478); + +static const u32 reg_ipa_tx_cfg_fmask[] = { + /* Bits 0-1 reserved */ + [PREFETCH_ALMOST_EMPTY_SIZE_TX0] = GENMASK(5, 2), + [DMAW_SCND_OUTSD_PRED_THRESHOLD] = GENMASK(9, 6), + [DMAW_SCND_OUTSD_PRED_EN] = BIT(10), + [DMAW_MAX_BEATS_256_DIS] = BIT(11), + [PA_MASK_EN] = BIT(12), + [PREFETCH_ALMOST_EMPTY_SIZE_TX1] = GENMASK(16, 13), + [DUAL_TX_ENABLE] = BIT(17), + [SSPND_PA_NO_START_STATE] = BIT(18), + /* Bit 19 reserved */ + [HOLB_STICKY_DROP_EN] = BIT(20), + /* Bits 21-31 reserved */ +}; + +REG_FIELDS(IPA_TX_CFG, ipa_tx_cfg, 0x00000488); + +static const u32 reg_idle_indication_cfg_fmask[] = { + [ENTER_IDLE_DEBOUNCE_THRESH] = GENMASK(15, 0), + [CONST_NON_IDLE_ENABLE] = BIT(16), + /* Bits 17-31 reserved */ +}; + +REG_FIELDS(IDLE_INDICATION_CFG, idle_indication_cfg, 0x000004a8); + +static const u32 reg_qtime_timestamp_cfg_fmask[] = { + /* Bits 0-7 reserved */ + [TAG_TIMESTAMP_LSB] = GENMASK(12, 8), + /* Bits 13-15 reserved */ + [NAT_TIMESTAMP_LSB] = GENMASK(20, 16), + /* Bits 21-31 reserved */ +}; + +REG_FIELDS(QTIME_TIMESTAMP_CFG, qtime_timestamp_cfg, 0x000004ac); + +static const u32 reg_timers_xo_clk_div_cfg_fmask[] = { + [DIV_VALUE] = GENMASK(8, 0), + /* Bits 9-30 reserved */ + [DIV_ENABLE] = BIT(31), +}; + +REG_FIELDS(TIMERS_XO_CLK_DIV_CFG, timers_xo_clk_div_cfg, 0x000004b0); + +static const u32 reg_timers_pulse_gran_cfg_fmask[] = { + [PULSE_GRAN_0] = GENMASK(2, 0), + [PULSE_GRAN_1] = GENMASK(5, 3), + [PULSE_GRAN_2] = GENMASK(8, 6), + [PULSE_GRAN_3] = GENMASK(11, 9), + /* Bits 12-31 reserved */ +}; + +REG_FIELDS(TIMERS_PULSE_GRAN_CFG, timers_pulse_gran_cfg, 0x000004b4); + +static const u32 reg_src_rsrc_grp_01_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(SRC_RSRC_GRP_01_RSRC_TYPE, src_rsrc_grp_01_rsrc_type, + 0x00000500, 0x0020); + +static const u32 reg_src_rsrc_grp_23_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(SRC_RSRC_GRP_23_RSRC_TYPE, src_rsrc_grp_23_rsrc_type, + 0x00000504, 0x0020); + +static const u32 reg_src_rsrc_grp_45_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(SRC_RSRC_GRP_45_RSRC_TYPE, src_rsrc_grp_45_rsrc_type, + 0x00000508, 0x0020); + +static const u32 reg_src_rsrc_grp_67_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(SRC_RSRC_GRP_67_RSRC_TYPE, src_rsrc_grp_67_rsrc_type, + 0x0000050c, 0x0020); + +static const u32 reg_dst_rsrc_grp_01_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(DST_RSRC_GRP_01_RSRC_TYPE, dst_rsrc_grp_01_rsrc_type, + 0x00000600, 0x0020); + +static const u32 reg_dst_rsrc_grp_23_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(DST_RSRC_GRP_23_RSRC_TYPE, dst_rsrc_grp_23_rsrc_type, + 0x00000604, 0x0020); + +static const u32 reg_dst_rsrc_grp_45_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(DST_RSRC_GRP_45_RSRC_TYPE, dst_rsrc_grp_45_rsrc_type, + 0x00000608, 0x0020); + +static const u32 reg_dst_rsrc_grp_67_rsrc_type_fmask[] = { + [X_MIN_LIM] = GENMASK(5, 0), + /* Bits 6-7 reserved */ + [X_MAX_LIM] = GENMASK(13, 8), + /* Bits 14-15 reserved */ + [Y_MIN_LIM] = GENMASK(21, 16), + /* Bits 22-23 reserved */ + [Y_MAX_LIM] = GENMASK(29, 24), + /* Bits 30-31 reserved */ +}; + +REG_STRIDE_FIELDS(DST_RSRC_GRP_67_RSRC_TYPE, dst_rsrc_grp_67_rsrc_type, + 0x0000060c, 0x0020); + +/* Valid bits defined by ipa->available */ + +REG_STRIDE(AGGR_FORCE_CLOSE, aggr_force_close, 0x000006b0, 0x0004); + +static const u32 reg_endp_init_cfg_fmask[] = { + [FRAG_OFFLOAD_EN] = BIT(0), + [CS_OFFLOAD_EN] = GENMASK(2, 1), + [CS_METADATA_HDR_OFFSET] = GENMASK(6, 3), + /* Bit 7 reserved */ + [CS_GEN_QMB_MASTER_SEL] = BIT(8), + [PIPE_REPLICATE_EN] = BIT(9), + /* Bits 10-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_CFG, endp_init_cfg, 0x00001008, 0x0080); + +static const u32 reg_endp_init_nat_fmask[] = { + [NAT_EN] = GENMASK(1, 0), + /* Bits 2-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_NAT, endp_init_nat, 0x0000100c, 0x0080); + +static const u32 reg_endp_init_hdr_fmask[] = { + [HDR_LEN] = GENMASK(5, 0), + [HDR_OFST_METADATA_VALID] = BIT(6), + [HDR_OFST_METADATA] = GENMASK(12, 7), + [HDR_ADDITIONAL_CONST_LEN] = GENMASK(18, 13), + [HDR_OFST_PKT_SIZE_VALID] = BIT(19), + [HDR_OFST_PKT_SIZE] = GENMASK(25, 20), + /* Bit 26 reserved */ + [HDR_LEN_INC_DEAGG_HDR] = BIT(27), + [HDR_LEN_MSB] = GENMASK(29, 28), + [HDR_OFST_METADATA_MSB] = GENMASK(31, 30), +}; + +REG_STRIDE_FIELDS(ENDP_INIT_HDR, endp_init_hdr, 0x00001010, 0x0080); + +static const u32 reg_endp_init_hdr_ext_fmask[] = { + [HDR_ENDIANNESS] = BIT(0), + [HDR_TOTAL_LEN_OR_PAD_VALID] = BIT(1), + [HDR_TOTAL_LEN_OR_PAD] = BIT(2), + [HDR_PAYLOAD_LEN_INC_PADDING] = BIT(3), + [HDR_TOTAL_LEN_OR_PAD_OFFSET] = GENMASK(9, 4), + [HDR_PAD_TO_ALIGNMENT] = GENMASK(13, 10), + /* Bits 14-15 reserved */ + [HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB] = GENMASK(17, 16), + [HDR_OFST_PKT_SIZE_MSB] = GENMASK(19, 18), + [HDR_ADDITIONAL_CONST_LEN_MSB] = GENMASK(21, 20), + [HDR_BYTES_TO_REMOVE_VALID] = BIT(22), + /* Bit 23 reserved */ + [HDR_BYTES_TO_REMOVE] = GENMASK(31, 24), +}; + +REG_STRIDE_FIELDS(ENDP_INIT_HDR_EXT, endp_init_hdr_ext, 0x00001014, 0x0080); + +REG_STRIDE(ENDP_INIT_HDR_METADATA_MASK, endp_init_hdr_metadata_mask, + 0x00001018, 0x0080); + +static const u32 reg_endp_init_mode_fmask[] = { + [ENDP_MODE] = GENMASK(2, 0), + [DCPH_ENABLE] = BIT(3), + [DEST_PIPE_INDEX] = GENMASK(11, 4), + [BYTE_THRESHOLD] = GENMASK(27, 12), + /* Bit 28 reserved */ + [PAD_EN] = BIT(29), + [DRBIP_ACL_ENABLE] = BIT(30), + /* Bit 31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_MODE, endp_init_mode, 0x00001020, 0x0080); + +static const u32 reg_endp_init_aggr_fmask[] = { + [AGGR_EN] = GENMASK(1, 0), + [AGGR_TYPE] = GENMASK(4, 2), + [BYTE_LIMIT] = GENMASK(10, 5), + /* Bit 11 reserved */ + [TIME_LIMIT] = GENMASK(16, 12), + [PKT_LIMIT] = GENMASK(22, 17), + [SW_EOF_ACTIVE] = BIT(23), + [FORCE_CLOSE] = BIT(24), + /* Bit 25 reserved */ + [HARD_BYTE_LIMIT_EN] = BIT(26), + [AGGR_GRAN_SEL] = BIT(27), + [AGGR_COAL_L2] = BIT(28), + /* Bits 27-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_AGGR, endp_init_aggr, 0x00001024, 0x0080); + +static const u32 reg_endp_init_hol_block_en_fmask[] = { + [HOL_BLOCK_EN] = BIT(0), + /* Bits 1-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_HOL_BLOCK_EN, endp_init_hol_block_en, + 0x0000102c, 0x0080); + +static const u32 reg_endp_init_hol_block_timer_fmask[] = { + [TIMER_LIMIT] = GENMASK(4, 0), + /* Bits 5-7 reserved */ + [TIMER_GRAN_SEL] = GENMASK(9, 8), + /* Bits 10-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_HOL_BLOCK_TIMER, endp_init_hol_block_timer, + 0x00001030, 0x0080); + +static const u32 reg_endp_init_deaggr_fmask[] = { + [DEAGGR_HDR_LEN] = GENMASK(5, 0), + [SYSPIPE_ERR_DETECTION] = BIT(6), + [PACKET_OFFSET_VALID] = BIT(7), + [PACKET_OFFSET_LOCATION] = GENMASK(13, 8), + [IGNORE_MIN_PKT_ERR] = BIT(14), + /* Bit 15 reserved */ + [MAX_PACKET_LEN] = GENMASK(31, 16), +}; + +REG_STRIDE_FIELDS(ENDP_INIT_DEAGGR, endp_init_deaggr, 0x00001034, 0x0080); + +static const u32 reg_endp_init_rsrc_grp_fmask[] = { + [ENDP_RSRC_GRP] = GENMASK(2, 0), + /* Bits 3-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_RSRC_GRP, endp_init_rsrc_grp, 0x00001038, 0x0080); + +static const u32 reg_endp_init_seq_fmask[] = { + [SEQ_TYPE] = GENMASK(7, 0), + /* Bits 8-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_INIT_SEQ, endp_init_seq, 0x0000103c, 0x0080); + +static const u32 reg_endp_status_fmask[] = { + [STATUS_EN] = BIT(0), + [STATUS_ENDP] = GENMASK(8, 1), + [STATUS_PKT_SUPPRESS] = BIT(9), + /* Bits 10-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_STATUS, endp_status, 0x00001040, 0x0080); + +static const u32 reg_endp_filter_cache_cfg_fmask[] = { + [CACHE_MSK_SRC_ID] = BIT(0), + [CACHE_MSK_SRC_IP] = BIT(1), + [CACHE_MSK_DST_IP] = BIT(2), + [CACHE_MSK_SRC_PORT] = BIT(3), + [CACHE_MSK_DST_PORT] = BIT(4), + [CACHE_MSK_PROTOCOL] = BIT(5), + [CACHE_MSK_METADATA] = BIT(6), + /* Bits 7-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_FILTER_CACHE_CFG, endp_filter_cache_cfg, + 0x0000105c, 0x0080); + +static const u32 reg_endp_router_cache_cfg_fmask[] = { + [CACHE_MSK_SRC_ID] = BIT(0), + [CACHE_MSK_SRC_IP] = BIT(1), + [CACHE_MSK_DST_IP] = BIT(2), + [CACHE_MSK_SRC_PORT] = BIT(3), + [CACHE_MSK_DST_PORT] = BIT(4), + [CACHE_MSK_PROTOCOL] = BIT(5), + [CACHE_MSK_METADATA] = BIT(6), + /* Bits 7-31 reserved */ +}; + +REG_STRIDE_FIELDS(ENDP_ROUTER_CACHE_CFG, endp_router_cache_cfg, + 0x00001060, 0x0080); + +/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */ +REG(IPA_IRQ_STTS, ipa_irq_stts, 0x0000c008 + 0x1000 * GSI_EE_AP); + +/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */ +REG(IPA_IRQ_EN, ipa_irq_en, 0x0000c00c + 0x1000 * GSI_EE_AP); + +/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */ +REG(IPA_IRQ_CLR, ipa_irq_clr, 0x0000c010 + 0x1000 * GSI_EE_AP); + +static const u32 reg_ipa_irq_uc_fmask[] = { + [UC_INTR] = BIT(0), + /* Bits 1-31 reserved */ +}; + +REG_FIELDS(IPA_IRQ_UC, ipa_irq_uc, 0x0000c01c + 0x1000 * GSI_EE_AP); + +/* Valid bits defined by ipa->available */ + +REG_STRIDE(IRQ_SUSPEND_INFO, irq_suspend_info, + 0x0000c030 + 0x1000 * GSI_EE_AP, 0x0004); + +/* Valid bits defined by ipa->available */ + +REG_STRIDE(IRQ_SUSPEND_EN, irq_suspend_en, + 0x0000c050 + 0x1000 * GSI_EE_AP, 0x0004); + +/* Valid bits defined by ipa->available */ + +REG_STRIDE(IRQ_SUSPEND_CLR, irq_suspend_clr, + 0x0000c070 + 0x1000 * GSI_EE_AP, 0x0004); + +static const struct reg *reg_array[] = { + [COMP_CFG] = ®_comp_cfg, + [CLKON_CFG] = ®_clkon_cfg, + [ROUTE] = ®_route, + [SHARED_MEM_SIZE] = ®_shared_mem_size, + [QSB_MAX_WRITES] = ®_qsb_max_writes, + [QSB_MAX_READS] = ®_qsb_max_reads, + [FILT_ROUT_CACHE_FLUSH] = ®_filt_rout_cache_flush, + [STATE_AGGR_ACTIVE] = ®_state_aggr_active, + [LOCAL_PKT_PROC_CNTXT] = ®_local_pkt_proc_cntxt, + [AGGR_FORCE_CLOSE] = ®_aggr_force_close, + [IPA_TX_CFG] = ®_ipa_tx_cfg, + [FLAVOR_0] = ®_flavor_0, + [IDLE_INDICATION_CFG] = ®_idle_indication_cfg, + [QTIME_TIMESTAMP_CFG] = ®_qtime_timestamp_cfg, + [TIMERS_XO_CLK_DIV_CFG] = ®_timers_xo_clk_div_cfg, + [TIMERS_PULSE_GRAN_CFG] = ®_timers_pulse_gran_cfg, + [SRC_RSRC_GRP_01_RSRC_TYPE] = ®_src_rsrc_grp_01_rsrc_type, + [SRC_RSRC_GRP_23_RSRC_TYPE] = ®_src_rsrc_grp_23_rsrc_type, + [SRC_RSRC_GRP_45_RSRC_TYPE] = ®_src_rsrc_grp_45_rsrc_type, + [SRC_RSRC_GRP_67_RSRC_TYPE] = ®_src_rsrc_grp_67_rsrc_type, + [DST_RSRC_GRP_01_RSRC_TYPE] = ®_dst_rsrc_grp_01_rsrc_type, + [DST_RSRC_GRP_23_RSRC_TYPE] = ®_dst_rsrc_grp_23_rsrc_type, + [DST_RSRC_GRP_45_RSRC_TYPE] = ®_dst_rsrc_grp_45_rsrc_type, + [DST_RSRC_GRP_67_RSRC_TYPE] = ®_dst_rsrc_grp_67_rsrc_type, + [ENDP_INIT_CFG] = ®_endp_init_cfg, + [ENDP_INIT_NAT] = ®_endp_init_nat, + [ENDP_INIT_HDR] = ®_endp_init_hdr, + [ENDP_INIT_HDR_EXT] = ®_endp_init_hdr_ext, + [ENDP_INIT_HDR_METADATA_MASK] = ®_endp_init_hdr_metadata_mask, + [ENDP_INIT_MODE] = ®_endp_init_mode, + [ENDP_INIT_AGGR] = ®_endp_init_aggr, + [ENDP_INIT_HOL_BLOCK_EN] = ®_endp_init_hol_block_en, + [ENDP_INIT_HOL_BLOCK_TIMER] = ®_endp_init_hol_block_timer, + [ENDP_INIT_DEAGGR] = ®_endp_init_deaggr, + [ENDP_INIT_RSRC_GRP] = ®_endp_init_rsrc_grp, + [ENDP_INIT_SEQ] = ®_endp_init_seq, + [ENDP_STATUS] = ®_endp_status, + [ENDP_FILTER_CACHE_CFG] = ®_endp_filter_cache_cfg, + [ENDP_ROUTER_CACHE_CFG] = ®_endp_router_cache_cfg, + [IPA_IRQ_STTS] = ®_ipa_irq_stts, + [IPA_IRQ_EN] = ®_ipa_irq_en, + [IPA_IRQ_CLR] = ®_ipa_irq_clr, + [IPA_IRQ_UC] = ®_ipa_irq_uc, + [IRQ_SUSPEND_INFO] = ®_irq_suspend_info, + [IRQ_SUSPEND_EN] = ®_irq_suspend_en, + [IRQ_SUSPEND_CLR] = ®_irq_suspend_clr, +}; + +const struct regs ipa_regs_v5_5 = { + .reg_count = ARRAY_SIZE(reg_array), + .reg = reg_array, +}; From 7c59294076204cc8f51f794b6c2e7675c8ad12cd Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Nov 2023 17:09:09 -0600 Subject: [PATCH 1385/7721] net: ipa: add IPA v5.5 configuration data Add the configuration data required for IPA v5.5, which is used in the Qualcomm SM8550 SoC. With that, the driver supports IPA v5.5. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/Makefile | 2 +- drivers/net/ipa/data/ipa_data-v5.5.c | 487 +++++++++++++++++++++++++++ drivers/net/ipa/ipa_data.h | 1 + drivers/net/ipa/ipa_main.c | 4 + drivers/net/ipa/ipa_version.h | 1 + 5 files changed, 494 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ipa/data/ipa_data-v5.5.c diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile index 9d2182068e1c..d3abb38633e0 100644 --- a/drivers/net/ipa/Makefile +++ b/drivers/net/ipa/Makefile @@ -7,7 +7,7 @@ IPA_REG_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5 # Some IPA versions can reuse another set of GSI register definitions. GSI_REG_VERSIONS := 3.1 3.5.1 4.0 4.5 4.9 4.11 5.0 -IPA_DATA_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 +IPA_DATA_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5 obj-$(CONFIG_QCOM_IPA) += ipa.o diff --git a/drivers/net/ipa/data/ipa_data-v5.5.c b/drivers/net/ipa/data/ipa_data-v5.5.c new file mode 100644 index 000000000000..2c6390f11354 --- /dev/null +++ b/drivers/net/ipa/data/ipa_data-v5.5.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Copyright (C) 2023 Linaro Ltd. */ + +#include +#include + +#include "../ipa_data.h" +#include "../ipa_endpoint.h" +#include "../ipa_mem.h" + +/** enum ipa_resource_type - IPA resource types for an SoC having IPA v5.5 */ +enum ipa_resource_type { + /* Source resource types; first must have value 0 */ + IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS = 0, + IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS, + IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF, + IPA_RESOURCE_TYPE_SRC_HPS_DMARS, + IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES, + + /* Destination resource types; first must have value 0 */ + IPA_RESOURCE_TYPE_DST_DATA_SECTORS = 0, + IPA_RESOURCE_TYPE_DST_DPS_DMARS, + IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS, +}; + +/* Resource groups used for an SoC having IPA v5.5 */ +enum ipa_rsrc_group_id { + /* Source resource group identifiers */ + IPA_RSRC_GROUP_SRC_UL = 0, + IPA_RSRC_GROUP_SRC_DL, + IPA_RSRC_GROUP_SRC_UNUSED_2, + IPA_RSRC_GROUP_SRC_UNUSED_3, + IPA_RSRC_GROUP_SRC_URLLC, + IPA_RSRC_GROUP_SRC_U_RX_QC, + IPA_RSRC_GROUP_SRC_COUNT, /* Last in set; not a source group */ + + /* Destination resource group identifiers */ + IPA_RSRC_GROUP_DST_UL = 0, + IPA_RSRC_GROUP_DST_DL, + IPA_RSRC_GROUP_DST_UNUSED_2, + IPA_RSRC_GROUP_DST_UNUSED_3, + IPA_RSRC_GROUP_DST_UNUSED_4, + IPA_RSRC_GROUP_DST_UC, + IPA_RSRC_GROUP_DST_DRB_IP, + IPA_RSRC_GROUP_DST_COUNT, /* Last; not a destination group */ +}; + +/* QSB configuration data for an SoC having IPA v5.5 */ +static const struct ipa_qsb_data ipa_qsb_data[] = { + [IPA_QSB_MASTER_DDR] = { + .max_writes = 0, /* Unlimited */ + .max_reads = 12, + .max_reads_beats = 0, + }, + [IPA_QSB_MASTER_PCIE] = { + .max_writes = 0, /* Unlimited */ + .max_reads = 8, + .max_reads_beats = 0, + }, +}; + +/* Endpoint configuration data for an SoC having IPA v5.5 */ +static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = { + [IPA_ENDPOINT_AP_COMMAND_TX] = { + .ee_id = GSI_EE_AP, + .channel_id = 12, + .endpoint_id = 14, + .toward_ipa = true, + .channel = { + .tre_count = 256, + .event_count = 256, + .tlv_count = 20, + }, + .endpoint = { + .config = { + .resource_group = IPA_RSRC_GROUP_SRC_UL, + .dma_mode = true, + .dma_endpoint = IPA_ENDPOINT_AP_LAN_RX, + .tx = { + .seq_type = IPA_SEQ_DMA, + }, + }, + }, + }, + [IPA_ENDPOINT_AP_LAN_RX] = { + .ee_id = GSI_EE_AP, + .channel_id = 13, + .endpoint_id = 16, + .toward_ipa = false, + .channel = { + .tre_count = 256, + .event_count = 256, + .tlv_count = 9, + }, + .endpoint = { + .config = { + .resource_group = IPA_RSRC_GROUP_DST_UL, + .aggregation = true, + .status_enable = true, + .rx = { + .buffer_size = 8192, + .pad_align = ilog2(sizeof(u32)), + .aggr_time_limit = 500, + }, + }, + }, + }, + [IPA_ENDPOINT_AP_MODEM_TX] = { + .ee_id = GSI_EE_AP, + .channel_id = 11, + .endpoint_id = 2, + .toward_ipa = true, + .channel = { + .tre_count = 512, + .event_count = 512, + .tlv_count = 25, + }, + .endpoint = { + .filter_support = true, + .config = { + .resource_group = IPA_RSRC_GROUP_SRC_UL, + .checksum = true, + .qmap = true, + .status_enable = true, + .tx = { + .seq_type = IPA_SEQ_2_PASS_SKIP_LAST_UC, + .status_endpoint = + IPA_ENDPOINT_MODEM_AP_RX, + }, + }, + }, + }, + [IPA_ENDPOINT_AP_MODEM_RX] = { + .ee_id = GSI_EE_AP, + .channel_id = 1, + .endpoint_id = 23, + .toward_ipa = false, + .channel = { + .tre_count = 256, + .event_count = 256, + .tlv_count = 9, + }, + .endpoint = { + .config = { + .resource_group = IPA_RSRC_GROUP_DST_DL, + .checksum = true, + .qmap = true, + .aggregation = true, + .rx = { + .buffer_size = 8192, + .aggr_time_limit = 500, + .aggr_close_eof = true, + }, + }, + }, + }, + [IPA_ENDPOINT_MODEM_AP_TX] = { + .ee_id = GSI_EE_MODEM, + .channel_id = 0, + .endpoint_id = 12, + .toward_ipa = true, + .endpoint = { + .filter_support = true, + }, + }, + [IPA_ENDPOINT_MODEM_AP_RX] = { + .ee_id = GSI_EE_MODEM, + .channel_id = 7, + .endpoint_id = 21, + .toward_ipa = false, + }, + [IPA_ENDPOINT_MODEM_DL_NLO_TX] = { + .ee_id = GSI_EE_MODEM, + .channel_id = 2, + .endpoint_id = 15, + .toward_ipa = true, + .endpoint = { + .filter_support = true, + }, + }, +}; + +/* Source resource configuration data for an SoC having IPA v5.5 */ +static const struct ipa_resource ipa_resource_src[] = { + [IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = { + .limits[IPA_RSRC_GROUP_SRC_UL] = { + .min = 3, .max = 9, + }, + .limits[IPA_RSRC_GROUP_SRC_DL] = { + .min = 4, .max = 10, + }, + .limits[IPA_RSRC_GROUP_SRC_URLLC] = { + .min = 1, .max = 63, + }, + .limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = { + .min = 0, .max = 63, + }, + }, + [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = { + .limits[IPA_RSRC_GROUP_SRC_UL] = { + .min = 9, .max = 9, + }, + .limits[IPA_RSRC_GROUP_SRC_DL] = { + .min = 12, .max = 12, + }, + .limits[IPA_RSRC_GROUP_SRC_URLLC] = { + .min = 10, .max = 10, + }, + }, + [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = { + .limits[IPA_RSRC_GROUP_SRC_UL] = { + .min = 9, .max = 9, + }, + .limits[IPA_RSRC_GROUP_SRC_DL] = { + .min = 24, .max = 24, + }, + .limits[IPA_RSRC_GROUP_SRC_URLLC] = { + .min = 20, .max = 20, + }, + }, + [IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = { + .limits[IPA_RSRC_GROUP_SRC_UL] = { + .min = 0, .max = 63, + }, + .limits[IPA_RSRC_GROUP_SRC_DL] = { + .min = 0, .max = 63, + }, + .limits[IPA_RSRC_GROUP_SRC_URLLC] = { + .min = 1, .max = 63, + }, + .limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = { + .min = 0, .max = 63, + }, + }, + [IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = { + .limits[IPA_RSRC_GROUP_SRC_UL] = { + .min = 22, .max = 22, + }, + .limits[IPA_RSRC_GROUP_SRC_DL] = { + .min = 16, .max = 16, + }, + .limits[IPA_RSRC_GROUP_SRC_URLLC] = { + .min = 16, .max = 16, + }, + }, +}; + +/* Destination resource configuration data for an SoC having IPA v5.5 */ +static const struct ipa_resource ipa_resource_dst[] = { + [IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = { + .limits[IPA_RSRC_GROUP_DST_UL] = { + .min = 6, .max = 6, + }, + .limits[IPA_RSRC_GROUP_DST_DL] = { + .min = 5, .max = 5, + }, + .limits[IPA_RSRC_GROUP_DST_DRB_IP] = { + .min = 39, .max = 39, + }, + }, + [IPA_RESOURCE_TYPE_DST_DPS_DMARS] = { + .limits[IPA_RSRC_GROUP_DST_UL] = { + .min = 0, .max = 3, + }, + .limits[IPA_RSRC_GROUP_DST_DL] = { + .min = 0, .max = 3, + }, + }, + [IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS] = { + .limits[IPA_RSRC_GROUP_DST_UL] = { + .min = 0, .max = 63, + }, + .limits[IPA_RSRC_GROUP_DST_DL] = { + .min = 0, .max = 63, + }, + }, +}; + +/* Resource configuration data for an SoC having IPA v5.5 */ +static const struct ipa_resource_data ipa_resource_data = { + .rsrc_group_dst_count = IPA_RSRC_GROUP_DST_COUNT, + .rsrc_group_src_count = IPA_RSRC_GROUP_SRC_COUNT, + .resource_src_count = ARRAY_SIZE(ipa_resource_src), + .resource_src = ipa_resource_src, + .resource_dst_count = ARRAY_SIZE(ipa_resource_dst), + .resource_dst = ipa_resource_dst, +}; + +/* IPA-resident memory region data for an SoC having IPA v5.5 */ +static const struct ipa_mem ipa_mem_local_data[] = { + { + .id = IPA_MEM_UC_EVENT_RING, + .offset = 0x0000, + .size = 0x1000, + .canary_count = 0, + }, + { + .id = IPA_MEM_UC_SHARED, + .offset = 0x1000, + .size = 0x0080, + .canary_count = 0, + }, + { + .id = IPA_MEM_UC_INFO, + .offset = 0x1080, + .size = 0x0200, + .canary_count = 0, + }, + { + .id = IPA_MEM_V4_FILTER_HASHED, + .offset = 0x1288, + .size = 0x0078, + .canary_count = 2, + }, + { + .id = IPA_MEM_V4_FILTER, + .offset = 0x1308, + .size = 0x0078, + .canary_count = 2, + }, + { + .id = IPA_MEM_V6_FILTER_HASHED, + .offset = 0x1388, + .size = 0x0078, + .canary_count = 2, + }, + { + .id = IPA_MEM_V6_FILTER, + .offset = 0x1408, + .size = 0x0078, + .canary_count = 2, + }, + { + .id = IPA_MEM_V4_ROUTE_HASHED, + .offset = 0x1488, + .size = 0x0098, + .canary_count = 2, + }, + { + .id = IPA_MEM_V4_ROUTE, + .offset = 0x1528, + .size = 0x0098, + .canary_count = 2, + }, + { + .id = IPA_MEM_V6_ROUTE_HASHED, + .offset = 0x15c8, + .size = 0x0098, + .canary_count = 2, + }, + { + .id = IPA_MEM_V6_ROUTE, + .offset = 0x1668, + .size = 0x0098, + .canary_count = 2, + }, + { + .id = IPA_MEM_MODEM_HEADER, + .offset = 0x1708, + .size = 0x0240, + .canary_count = 2, + }, + { + .id = IPA_MEM_AP_HEADER, + .offset = 0x1948, + .size = 0x01e0, + .canary_count = 0, + }, + { + .id = IPA_MEM_MODEM_PROC_CTX, + .offset = 0x1b40, + .size = 0x0b20, + .canary_count = 2, + }, + { + .id = IPA_MEM_AP_PROC_CTX, + .offset = 0x2660, + .size = 0x0200, + .canary_count = 0, + }, + { + .id = IPA_MEM_STATS_QUOTA_MODEM, + .offset = 0x2868, + .size = 0x0060, + .canary_count = 2, + }, + { + .id = IPA_MEM_STATS_QUOTA_AP, + .offset = 0x28c8, + .size = 0x0048, + .canary_count = 0, + }, + { + .id = IPA_MEM_STATS_TETHERING, + .offset = 0x2910, + .size = 0x03c0, + .canary_count = 0, + }, + { + .id = IPA_MEM_AP_V4_FILTER, + .offset = 0x29b8, + .size = 0x0188, + .canary_count = 2, + }, + { + .id = IPA_MEM_AP_V6_FILTER, + .offset = 0x2b40, + .size = 0x0228, + .canary_count = 0, + }, + { + .id = IPA_MEM_STATS_FILTER_ROUTE, + .offset = 0x2cd0, + .size = 0x0ba0, + .canary_count = 2, + }, + { + .id = IPA_MEM_STATS_DROP, + .offset = 0x3870, + .size = 0x0020, + .canary_count = 0, + }, + { + .id = IPA_MEM_MODEM, + .offset = 0x3898, + .size = 0x0d48, + .canary_count = 2, + }, + { + .id = IPA_MEM_NAT_TABLE, + .offset = 0x45e0, + .size = 0x0900, + .canary_count = 0, + }, + { + .id = IPA_MEM_PDN_CONFIG, + .offset = 0x4ee8, + .size = 0x0100, + .canary_count = 2, + }, +}; + +/* Memory configuration data for an SoC having IPA v5.5 */ +static const struct ipa_mem_data ipa_mem_data = { + .local_count = ARRAY_SIZE(ipa_mem_local_data), + .local = ipa_mem_local_data, + .imem_addr = 0x14688000, + .imem_size = 0x00002000, + .smem_id = 497, + .smem_size = 0x0000b000, +}; + +/* Interconnect rates are in 1000 byte/second units */ +static const struct ipa_interconnect_data ipa_interconnect_data[] = { + { + .name = "memory", + .peak_bandwidth = 1900000, /* 1.9 GBps */ + .average_bandwidth = 600000, /* 600 MBps */ + }, + /* Average rate is unused for the next interconnect */ + { + .name = "config", + .peak_bandwidth = 76800, /* 76.8 MBps */ + .average_bandwidth = 0, /* unused */ + }, +}; + +/* Clock and interconnect configuration data for an SoC having IPA v5.5 */ +static const struct ipa_power_data ipa_power_data = { + .core_clock_rate = 120 * 1000 * 1000, /* Hz */ + .interconnect_count = ARRAY_SIZE(ipa_interconnect_data), + .interconnect_data = ipa_interconnect_data, +}; + +/* Configuration data for an SoC having IPA v5.5. */ +const struct ipa_data ipa_data_v5_5 = { + .version = IPA_VERSION_5_5, + .qsb_count = ARRAY_SIZE(ipa_qsb_data), + .qsb_data = ipa_qsb_data, + .modem_route_count = 11, + .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data), + .endpoint_data = ipa_gsi_endpoint_data, + .resource_data = &ipa_resource_data, + .mem_data = &ipa_mem_data, + .power_data = &ipa_power_data, +}; diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h index ce82b00fdc49..2a1605e67b65 100644 --- a/drivers/net/ipa/ipa_data.h +++ b/drivers/net/ipa/ipa_data.h @@ -250,5 +250,6 @@ extern const struct ipa_data ipa_data_v4_7; extern const struct ipa_data ipa_data_v4_9; extern const struct ipa_data ipa_data_v4_11; extern const struct ipa_data ipa_data_v5_0; +extern const struct ipa_data ipa_data_v5_5; #endif /* _IPA_DATA_H_ */ diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 8893290e132b..86884c21e792 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -691,6 +691,10 @@ static const struct of_device_id ipa_match[] = { .compatible = "qcom,sdx65-ipa", .data = &ipa_data_v5_0, }, + { + .compatible = "qcom,sm8550-ipa", + .data = &ipa_data_v5_5, + }, { }, }; MODULE_DEVICE_TABLE(of, ipa_match); diff --git a/drivers/net/ipa/ipa_version.h b/drivers/net/ipa/ipa_version.h index 06e75b8ece7e..38150345b607 100644 --- a/drivers/net/ipa/ipa_version.h +++ b/drivers/net/ipa/ipa_version.h @@ -56,6 +56,7 @@ static inline bool ipa_version_supported(enum ipa_version version) case IPA_VERSION_4_9: case IPA_VERSION_4_11: case IPA_VERSION_5_0: + case IPA_VERSION_5_5: return true; default: return false; From 3b8551e73271fc375b15c887db54ad31686eb2ea Mon Sep 17 00:00:00 2001 From: Deborah Brouwer Date: Thu, 23 Nov 2023 14:08:41 -0800 Subject: [PATCH 1386/7721] media: wave5: add OF and V4L_MEM2MEM_DRIVERS dependencies Fix compile warning when CONFIG_OF=n: drivers/media/platform/chips-media/wave5/wave5-vpu.c:274:34: warning: 'wave5_dt_ids' defined but not used [-Wunused-const-variable=] 274 | static const struct of_device_id wave5_dt_ids[] = { | Signed-off-by: Deborah Brouwer Signed-off-by: Hans Verkuil [hverkuil: added commit log text] --- drivers/media/platform/chips-media/wave5/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig index a3b949356cd5..77e7ae5c8f35 100644 --- a/drivers/media/platform/chips-media/wave5/Kconfig +++ b/drivers/media/platform/chips-media/wave5/Kconfig @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_WAVE_VPU tristate "Chips&Media Wave Codec Driver" - depends on VIDEO_DEV + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && OF select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV From 35ed38d58257336c1df26b14fd5110b026e2adde Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Nov 2023 23:13:00 +0100 Subject: [PATCH 1387/7721] drm: Allow drivers to indicate the damage helpers to ignore damage clips It allows drivers to set a struct drm_plane_state .ignore_damage_clips in their plane's .atomic_check callback, as an indication to damage helpers such as drm_atomic_helper_damage_iter_init() that the damage clips should be ignored. To be used by drivers that do per-buffer (e.g: virtio-gpu) uploads (rather than per-plane uploads), since these type of drivers need to handle buffer damages instead of frame damages. That way, these drivers could force a full plane update if the framebuffer attached to a plane's state has changed since the last update (page-flip). Fixes: 01f05940a9a7 ("drm/virtio: Enable fb damage clips property for the primary plane") Cc: # v6.4+ Reported-by: nerdopolis Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218115 Suggested-by: Thomas Zimmermann Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Reviewed-by: Zack Rusin Acked-by: Sima Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231123221315.3579454-2-javierm@redhat.com --- Documentation/gpu/drm-kms.rst | 2 ++ drivers/gpu/drm/drm_damage_helper.c | 3 ++- include/drm/drm_plane.h | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 4a112b8cc7fb..13d3627d8bc0 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -548,6 +548,8 @@ Plane Composition Properties .. kernel-doc:: drivers/gpu/drm/drm_blend.c :doc: overview +.. _damage_tracking_properties: + Damage Tracking Properties -------------------------- diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index d8b2955e88fd..afb02aae707b 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -241,7 +241,8 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF); iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF); - if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) { + if (!iter->clips || state->ignore_damage_clips || + !drm_rect_equals(&state->src, &old_state->src)) { iter->clips = NULL; iter->num_clips = 0; iter->full_update = true; diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index e2c671585775..c6565a6f9324 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -194,6 +194,16 @@ struct drm_plane_state { */ struct drm_property_blob *fb_damage_clips; + /** + * @ignore_damage_clips: + * + * Set by drivers to indicate the drm_atomic_helper_damage_iter_init() + * helper that the @fb_damage_clips blob property should be ignored. + * + * See :ref:`damage_tracking_properties` for more information. + */ + bool ignore_damage_clips; + /** * @src: * From 0240db231dfe5ee5b7a3a03cba96f0844b7a673d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Nov 2023 23:13:01 +0100 Subject: [PATCH 1388/7721] drm/virtio: Disable damage clipping if FB changed since last page-flip The driver does per-buffer uploads and needs to force a full plane update if the plane's attached framebuffer has change since the last page-flip. Fixes: 01f05940a9a7 ("drm/virtio: Enable fb damage clips property for the primary plane") Cc: # v6.4+ Reported-by: nerdopolis Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218115 Suggested-by: Sima Vetter Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Reviewed-by: Zack Rusin Acked-by: Sima Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231123221315.3579454-3-javierm@redhat.com --- drivers/gpu/drm/virtio/virtgpu_plane.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 20de599658c1..a72a2dbda031 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -79,6 +79,8 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, + plane); bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR; struct drm_crtc_state *crtc_state; int ret; @@ -86,6 +88,14 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) return 0; + /* + * Ignore damage clips if the framebuffer attached to the plane's state + * has changed since the last plane update (page-flip). In this case, a + * full plane update should happen because uploads are done per-buffer. + */ + if (old_plane_state->fb != new_plane_state->fb) + new_plane_state->ignore_damage_clips = true; + crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); if (IS_ERR(crtc_state)) From b83b2a80d662cc8ba9d78db64fb70fbb5a481d9c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Nov 2023 23:13:02 +0100 Subject: [PATCH 1389/7721] drm/vmwgfx: Disable damage clipping if FB changed since last page-flip The driver does per-buffer uploads and needs to force a full plane update if the plane's attached framebuffer has change since the last page-flip. Suggested-by: Sima Vetter Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Reviewed-by: Zack Rusin Acked-by: Sima Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231123221315.3579454-4-javierm@redhat.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bea0abc3d418..5fd0ccaa0b41 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -832,10 +832,21 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, + plane); struct drm_crtc_state *crtc_state = NULL; struct drm_framebuffer *new_fb = new_state->fb; + struct drm_framebuffer *old_fb = old_state->fb; int ret; + /* + * Ignore damage clips if the framebuffer attached to the plane's state + * has changed since the last plane update (page-flip). In this case, a + * full plane update should happen because uploads are done per-buffer. + */ + if (old_fb != new_fb) + new_state->ignore_damage_clips = true; + if (new_state->crtc) crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); From 017bdf8fa20175b9cccbc746122256432a599845 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Nov 2023 23:13:03 +0100 Subject: [PATCH 1390/7721] drm/plane: Extend damage tracking kernel-doc The "Damage Tracking Properties" section in the documentation doesn't have info about the two type of damage handling: frame damage vs buffer damage. Add it to the section and mention that helpers only support frame damage, and how drivers handling buffer damage can indicate that the damage clips should be ignored. Also add references to further documentation about the two damage types. Suggested-by: Simon Ser Signed-off-by: Javier Martinez Canillas Reviewed-by: Simon Ser Reviewed-by: Thomas Zimmermann Reviewed-by: Zack Rusin Acked-by: Sima Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231123221315.3579454-5-javierm@redhat.com --- drivers/gpu/drm/drm_plane.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index f3f2eae83cca..9e8e4c60983d 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1558,6 +1558,36 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and * drm_atomic_helper_damage_iter_next() helper iterator function to get damage * rectangles clipped to &drm_plane_state.src. + * + * Note that there are two types of damage handling: frame damage and buffer + * damage, the type of damage handling implemented depends on a driver's upload + * target. Drivers implementing a per-plane or per-CRTC upload target need to + * handle frame damage, while drivers implementing a per-buffer upload target + * need to handle buffer damage. + * + * The existing damage helpers only support the frame damage type, there is no + * buffer age support or similar damage accumulation algorithm implemented yet. + * + * Only drivers handling frame damage can use the mentioned damage helpers to + * iterate over the damaged regions. Drivers that handle buffer damage, must set + * &drm_plane_state.ignore_damage_clips for drm_atomic_helper_damage_iter_init() + * to know that damage clips should be ignored and return &drm_plane_state.src + * as the damage rectangle, to force a full plane update. + * + * Drivers with a per-buffer upload target could compare the &drm_plane_state.fb + * of the old and new plane states to determine if the framebuffer attached to a + * plane has changed or not since the last plane update. If &drm_plane_state.fb + * has changed, then &drm_plane_state.ignore_damage_clips must be set to true. + * + * That is because drivers with a per-plane upload target, expect the backing + * storage buffer to not change for a given plane. If the upload buffer changes + * between page flips, the new upload buffer has to be updated as a whole. This + * can be improved in the future if support for frame damage is added to the DRM + * damage helpers, similarly to how user-space already handle this case as it is + * explained in the following documents: + * + * https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt + * https://emersion.fr/blog/2019/intro-to-damage-tracking/ */ /** From 6c18005d8fabe8a6835fc0f96102d4269199e05b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Nov 2023 23:13:04 +0100 Subject: [PATCH 1391/7721] drm/todo: Add entry about implementing buffer age for damage tracking Currently, only damage tracking for frame damage is supported. If a driver needs to do buffer damage (e.g: the framebuffer attached to plane's state has changed since the last page-flip), the damage helpers just fallback to a full plane update. Add en entry in the TODO about implementing buffer age or any other damage accumulation algorithm for buffer damage handling. Suggested-by: Simon Ser Signed-off-by: Javier Martinez Canillas Reviewed-by: Simon Ser Reviewed-by: Thomas Zimmermann Reviewed-by: Zack Rusin Acked-by: Sima Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231123221315.3579454-6-javierm@redhat.com --- Documentation/gpu/todo.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index b62c7fa0c2bc..503d57c75215 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -782,6 +782,29 @@ Contact: Hans de Goede Level: Advanced +Buffer age or other damage accumulation algorithm for buffer damage +=================================================================== + +Drivers that do per-buffer uploads, need a buffer damage handling (rather than +frame damage like drivers that do per-plane or per-CRTC uploads), but there is +no support to get the buffer age or any other damage accumulation algorithm. + +For this reason, the damage helpers just fallback to a full plane update if the +framebuffer attached to a plane has changed since the last page-flip. Drivers +set &drm_plane_state.ignore_damage_clips to true as indication to +drm_atomic_helper_damage_iter_init() and drm_atomic_helper_damage_iter_next() +helpers that the damage clips should be ignored. + +This should be improved to get damage tracking properly working on drivers that +do per-buffer uploads. + +More information about damage tracking and references to learning materials can +be found in :ref:`damage_tracking_properties`. + +Contact: Javier Martinez Canillas + +Level: Advanced + Outside DRM =========== From 8e3707975e04e432f132955652fc77e9ff82f31d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 22 Nov 2023 09:33:23 -0800 Subject: [PATCH 1392/7721] tools: ynl-gen: always append ULL/LL to range types 32bit builds generate the following warning when we use a u32-max in range validation: warning: decimal constant 4294967295 is between LONG_MAX and ULONG_MAX. For C99 that means long long, C90 compilers are very likely to produce unsigned long (and a warning) here The range values are u64, slap ULL/LL on all of them just to avoid such noise. There's currently no code using full range validation, but it will matter in the upcoming page-pool introspection. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 3bd6b928c14f..fe5ca7fbe011 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2070,12 +2070,13 @@ def print_kernel_policy_ranges(family, cw): first = False sign = '' if attr.type[0] == 'u' else '_signed' + suffix = 'ULL' if attr.type[0] == 'u' else 'LL' cw.block_start(line=f'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') members = [] if 'min' in attr.checks: - members.append(('min', attr.get_limit('min'))) + members.append(('min', str(attr.get_limit('min')) + suffix)) if 'max' in attr.checks: - members.append(('max', attr.get_limit('max'))) + members.append(('max', str(attr.get_limit('max')) + suffix)) cw.write_struct_init(members) cw.block_end(line=';') cw.nl() From e7bed88e0530c70c1693af886a5905a3c00760fa Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Thu, 23 Nov 2023 09:45:37 +0800 Subject: [PATCH 1393/7721] net/smc: remove unneeded atomic operations in smc_tx_sndbuf_nonempty The commit dcd2cf5f2fc0 ("net/smc: add autocorking support") adds an atomic variable tx_pushing in smc_connection to make sure only one can send to let it cork more and save CDC slot. since smc_tx_pending can be called in the soft IRQ without checking sock_owned_by_user() at that time, which would cause a race condition because bh_lock_sock() did not honor sock_lock() After commit 6b88af839d20 ("net/smc: don't send in the BH context if sock_owned_by_user"), the transmission is deferred to when sock_lock() is held by the user. Therefore, we no longer need tx_pending to hold message. So remove atomic variable tx_pushing and its operation, and smc_tx_sndbuf_nonempty becomes a wrapper of __smc_tx_sndbuf_nonempty, so rename __smc_tx_sndbuf_nonempty back to smc_tx_sndbuf_nonempty Suggested-by: Alexandra Winter Co-developed-by: Dust Li Signed-off-by: Dust Li Signed-off-by: Li RongQing Reviewed-by: Alexandra Winter diff v4: remove atomic variable tx_pushing diff v3: improvements in the commit body and comments diff v2: fix a typo in commit body and add net-next subject-prefix net/smc/smc.h | 1 - net/smc/smc_tx.c | 30 +----------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) Signed-off-by: David S. Miller --- net/smc/smc.h | 1 - net/smc/smc_tx.c | 30 +----------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/net/smc/smc.h b/net/smc/smc.h index e377980b8414..cd51261b7d9e 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h @@ -196,7 +196,6 @@ struct smc_connection { * - dec on polled tx cqe */ wait_queue_head_t cdc_pend_tx_wq; /* wakeup on no cdc_pend_tx_wr*/ - atomic_t tx_pushing; /* nr_threads trying tx push */ struct delayed_work tx_work; /* retry of smc_cdc_msg_send */ u32 tx_off; /* base offset in peer rmb */ diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 3b0ff3b589c7..214ac3cbcf9a 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -621,7 +621,7 @@ static int smcd_tx_sndbuf_nonempty(struct smc_connection *conn) return rc; } -static int __smc_tx_sndbuf_nonempty(struct smc_connection *conn) +int smc_tx_sndbuf_nonempty(struct smc_connection *conn) { struct smc_sock *smc = container_of(conn, struct smc_sock, conn); int rc = 0; @@ -655,34 +655,6 @@ static int __smc_tx_sndbuf_nonempty(struct smc_connection *conn) return rc; } -int smc_tx_sndbuf_nonempty(struct smc_connection *conn) -{ - int rc; - - /* This make sure only one can send simultaneously to prevent wasting - * of CPU and CDC slot. - * Record whether someone has tried to push while we are pushing. - */ - if (atomic_inc_return(&conn->tx_pushing) > 1) - return 0; - -again: - atomic_set(&conn->tx_pushing, 1); - smp_wmb(); /* Make sure tx_pushing is 1 before real send */ - rc = __smc_tx_sndbuf_nonempty(conn); - - /* We need to check whether someone else have added some data into - * the send queue and tried to push but failed after the atomic_set() - * when we are pushing. - * If so, we need to push again to prevent those data hang in the send - * queue. - */ - if (unlikely(!atomic_dec_and_test(&conn->tx_pushing))) - goto again; - - return rc; -} - /* Wakeup sndbuf consumers from process context * since there is more data to transmit. The caller * must hold sock lock. From 486058f42a4728053ae69ebbf78e9731d8ce6f8b Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Thu, 23 Nov 2023 09:55:15 +0800 Subject: [PATCH 1394/7721] bonding: remove print in bond_verify_device_path As suggested by Paolo in link[1], if the memory allocation fails, the mm layer will emit a lot warning comprising the backtrace, so remove the print. [1] https://lore.kernel.org/all/20231118081653.1481260-1-shaozhengchao@huawei.com/ Suggested-by: Paolo Abeni Signed-off-by: Zhengchao Shao Reviewed-by: Hangbin Liu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d987432cee3b..4e0600c7b050 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2973,11 +2973,8 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, if (start_dev == end_dev) { tags = kcalloc(level + 1, sizeof(*tags), GFP_ATOMIC); - if (!tags) { - net_err_ratelimited("%s: %s: Failed to allocate tags\n", - __func__, start_dev->name); + if (!tags) return ERR_PTR(-ENOMEM); - } tags[level].vlan_proto = BOND_VLAN_PROTO_NONE; return tags; } From 19ed9b3d7a77c6ac3927fe05f4eacfa056b43a48 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 22 Nov 2023 19:08:44 -0800 Subject: [PATCH 1395/7721] tools: ynl-get: use family c-name If a new family is ever added with a dash in the name the C codegen will break. Make sure we use the "safe" form of the name consistently. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 46 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index fe5ca7fbe011..b3438e96fde6 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -67,9 +67,9 @@ class Type(SpecAttr): if 'nested-attributes' in attr: self.nested_attrs = attr['nested-attributes'] if self.nested_attrs == family.name: - self.nested_render_name = f"{family.name}" + self.nested_render_name = c_lower(f"{family.name}") else: - self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" + self.nested_render_name = c_lower(f"{family.name}_{self.nested_attrs}") if self.nested_attrs in self.family.consts: self.nested_struct_type = 'struct ' + self.nested_render_name + '_' @@ -335,7 +335,7 @@ class TypeScalar(Type): maybe_enum = not self.is_bitfield and 'enum' in self.attr if maybe_enum and self.family.consts[self.attr['enum']].enum_name: - self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" + self.type_name = c_lower(f"enum {self.family.name}_{self.attr['enum']}") elif self.is_auto_scalar: self.type_name = '__' + self.type[0] + '64' else: @@ -685,9 +685,9 @@ class Struct: self.nested = type_list is None if family.name == c_lower(space_name): - self.render_name = f"{family.name}" + self.render_name = c_lower(family.name) else: - self.render_name = f"{family.name}_{c_lower(space_name)}" + self.render_name = c_lower(family.name + '-' + space_name) self.struct_name = 'struct ' + self.render_name if self.nested and space_name in family.consts: self.struct_name += '_' @@ -841,7 +841,7 @@ class Operation(SpecOperation): def __init__(self, family, yaml, req_value, rsp_value): super().__init__(family, yaml, req_value, rsp_value) - self.render_name = family.name + '_' + c_lower(self.name) + self.render_name = c_lower(family.name + '_' + self.name) self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ ('dump' in yaml and 'request' in yaml['dump']) @@ -1431,7 +1431,7 @@ def op_prefix(ri, direction, deref=False): suffix += '_rsp' suffix += '_dump' if deref else '_list' - return f"{ri.family['name']}{suffix}" + return f"{ri.family.c_name}{suffix}" def type_name(ri, direction, deref=False): @@ -1497,11 +1497,11 @@ def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): def put_op_name_fwd(family, cw): - cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') + cw.write_func_prot('const char *', f'{family.c_name}_op_str', ['int op'], suffix=';') def put_op_name(family, cw): - map_name = f'{family.name}_op_strmap' + map_name = f'{family.c_name}_op_strmap' cw.block_start(line=f"static const char * const {map_name}[] =") for op_name, op in family.msgs.items(): if op.rsp_value: @@ -1518,7 +1518,7 @@ def put_op_name(family, cw): cw.block_end(line=';') cw.nl() - _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op') + _put_enum_to_str_helper(cw, family.c_name + '_op', map_name, 'op') def put_enum_to_str_fwd(family, cw, enum): @@ -1840,7 +1840,7 @@ def _print_type(ri, direction, struct): if ri.op_mode == 'dump': suffix += '_dump' - ri.cw.block_start(line=f"struct {ri.family['name']}{suffix}") + ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}") meta_started = False for _, attr in struct.member_list(): @@ -2106,7 +2106,7 @@ def print_kernel_op_table_fwd(family, cw, terminate): cnt = len(family.ops) qual = 'static const' if not exported else 'const' - line = f"{qual} struct {struct_type} {family.name}_nl_ops[{cnt}]" + line = f"{qual} struct {struct_type} {family.c_name}_nl_ops[{cnt}]" if terminate: cw.p(f"extern {line};") else: @@ -2249,7 +2249,7 @@ def print_kernel_mcgrp_src(family, cw): if not family.mcgrps['list']: return - cw.block_start('static const struct genl_multicast_group ' + family.name + '_nl_mcgrps[] =') + cw.block_start('static const struct genl_multicast_group ' + family.c_name + '_nl_mcgrps[] =') for grp in family.mcgrps['list']: name = grp['name'] grp_id = c_upper(f"{family.name}-nlgrp-{name}") @@ -2262,7 +2262,7 @@ def print_kernel_family_struct_hdr(family, cw): if not kernel_can_gen_family_struct(family): return - cw.p(f"extern struct genl_family {family.name}_nl_family;") + cw.p(f"extern struct genl_family {family.c_name}_nl_family;") cw.nl() @@ -2277,14 +2277,14 @@ def print_kernel_family_struct_src(family, cw): cw.p('.parallel_ops\t= true,') cw.p('.module\t\t= THIS_MODULE,') if family.kernel_policy == 'per-op': - cw.p(f'.ops\t\t= {family.name}_nl_ops,') - cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.ops\t\t= {family.c_name}_nl_ops,') + cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.c_name}_nl_ops),') elif family.kernel_policy == 'split': - cw.p(f'.split_ops\t= {family.name}_nl_ops,') - cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.split_ops\t= {family.c_name}_nl_ops,') + cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.c_name}_nl_ops),') if family.mcgrps['list']: - cw.p(f'.mcgrps\t\t= {family.name}_nl_mcgrps,') - cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.name}_nl_mcgrps),') + cw.p(f'.mcgrps\t\t= {family.c_name}_nl_mcgrps,') + cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.c_name}_nl_mcgrps),') cw.block_end(';') @@ -2294,7 +2294,7 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'): if obj[enum_name]: start_line = 'enum ' + c_lower(obj[enum_name]) elif ckey and ckey in obj: - start_line = 'enum ' + family.name + '_' + c_lower(obj[ckey]) + start_line = 'enum ' + family.c_name + '_' + c_lower(obj[ckey]) cw.block_start(line=start_line) @@ -2478,7 +2478,7 @@ def render_user_family(family, cw, prototype): cw.nl() cw.block_start(f'{symbol} = ') - cw.p(f'.name\t\t= "{family.name}",') + cw.p(f'.name\t\t= "{family.c_name}",') if family.ntfs: cw.p(f".ntf_info\t= {family['name']}_ntf_info,") cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") @@ -2560,7 +2560,7 @@ def main(): render_uapi(parsed, cw) return - hdr_prot = f"_LINUX_{parsed.name.upper()}_GEN_H" + hdr_prot = f"_LINUX_{parsed.c_name.upper()}_GEN_H" if args.header: cw.p('#ifndef ' + hdr_prot) cw.p('#define ' + hdr_prot) From 30c90200153430915a4c4aaaca7437d2592e6ed2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 22 Nov 2023 19:10:50 -0800 Subject: [PATCH 1396/7721] tools: ynl-gen: use enum name from the spec The enum name used for id-to-str table does not handle the enum-name override in the spec correctly. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index b3438e96fde6..cbbda276f6d1 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -755,11 +755,17 @@ class EnumSet(SpecEnumSet): if 'enum-name' in yaml: if yaml['enum-name']: self.enum_name = 'enum ' + c_lower(yaml['enum-name']) + self.user_type = self.enum_name else: self.enum_name = None else: self.enum_name = 'enum ' + self.render_name + if self.enum_name: + self.user_type = self.enum_name + else: + self.user_type = 'int' + self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") super().__init__(family, yaml) @@ -1483,8 +1489,8 @@ def put_typol(cw, struct): def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): args = [f'int {arg_name}'] - if enum and not ('enum-name' in enum and not enum['enum-name']): - args = [f'enum {render_name} {arg_name}'] + if enum: + args = [enum.user_type + ' ' + arg_name] cw.write_func_prot('const char *', f'{render_name}_str', args) cw.block_start() if enum and enum.type == 'flags': @@ -1522,9 +1528,7 @@ def put_op_name(family, cw): def put_enum_to_str_fwd(family, cw, enum): - args = [f'enum {enum.render_name} value'] - if 'enum-name' in enum and not enum['enum-name']: - args = ['int value'] + args = [enum.user_type + ' value'] cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') From 3a767b482cacd9bfeac786837fcac419af315995 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 23 Nov 2023 10:53:26 +0100 Subject: [PATCH 1397/7721] r8169: remove not needed check in rtl_fw_write_firmware This check can never be true for a firmware file with a correct format. Existing checks in rtl_fw_data_ok() are sufficient, no problems with invalid firmware files are known. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_firmware.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index cbc6b846ded5..ed6e721b1555 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -151,9 +151,6 @@ void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw) u32 regno = (action & 0x0fff0000) >> 16; enum rtl_fw_opcode opcode = action >> 28; - if (!action) - break; - switch (opcode) { case PHY_READ: predata = fw_read(tp, regno); From 5980bda0a998a6ee6afd83b97a482a40c1c68076 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Nov 2023 17:08:50 +0200 Subject: [PATCH 1398/7721] ASoC: SOF: ipc4-topology: Helper to find an swidget by module/instance id The sof_ipc4_find_swidget_by_ids() can be used to find the swidget of a module instance. The lookup parameters are the module_id and the instance_id. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231124150853.18648-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-priv.h | 3 +++ sound/soc/sof/ipc4-topology.c | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 9e69b7c29117..fea93b693f4d 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -115,6 +115,9 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid); +struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, + u32 module_id, int instance_id); + struct sof_ipc4_base_module_cfg; void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev, struct sof_ipc4_fw_module *fw_module, diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index b24a64377f68..8ab9c42069ee 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -167,6 +167,26 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; +struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, + u32 module_id, int instance_id) +{ + struct snd_sof_widget *swidget; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + + /* Only active module instances have valid instance_id */ + if (!swidget->use_count) + continue; + + if (fw_module && fw_module->man4_module_entry.id == module_id && + swidget->instance_id == instance_id) + return swidget; + } + + return NULL; +} + static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt, int num_formats) { From 1a307538c9cc274b3191b9a1380bbceece262626 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Nov 2023 17:08:51 +0200 Subject: [PATCH 1399/7721] ASoC: SOF: ipc4: Add data struct for module notification message from firmware With the module notification message the information about the notification is provided via the mailbox with the sof_ipc4_notify_module_data struct. It contains the module and instance id of the sender of the notification, the event_id and optionally additional data which is module and event specific. At the same time add definitions to identify ALSA kcontrol change notification. These notifications use standardized event_id, modules must follow this if they support such notifications: upper 16 bit: 0xA15A as a magic identification value lower 16 bit: param_id of the changed control Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231124150853.18648-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 574a9d581f88..2c81d6dde577 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -532,6 +532,35 @@ struct sof_ipc4_notify_resource_data { #define SOF_IPC4_DEBUG_SLOT_TELEMETRY 0x4c455400 #define SOF_IPC4_DEBUG_SLOT_BROKEN 0x44414544 +/** + * struct sof_ipc4_notify_module_data - payload for module notification + * @instance_id: instance ID of the originator module of the notification + * @module_id: module ID of the originator of the notification + * @event_id: module specific event id + * @event_data_size: Size of the @event_data (if any) in bytes + * @event_data: Optional notification data, module and notification dependent + */ +struct sof_ipc4_notify_module_data { + uint16_t instance_id; + uint16_t module_id; + uint32_t event_id; + uint32_t event_data_size; + uint8_t event_data[]; +} __packed __aligned(4); + +/* + * ALSA kcontrol change notification + * + * The event_id of struct sof_ipc4_notify_module_data is divided into two u16: + * upper u16: magic number for ALSA kcontrol types: 0xA15A + * lower u16: param_id of the control, which is the type of the control + * The event_data contains the struct sof_ipc4_control_msg_payload of the control + * which sent the notification. + */ +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK GENMASK(31, 16) +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL 0xA15A0000 +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK GENMASK(15, 0) + /** @}*/ #endif From f5eb9945cf9c17eb016aa64c7de13875f259ea07 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Nov 2023 17:08:52 +0200 Subject: [PATCH 1400/7721] ASoC: SOF: ipc4-control: Implement control update for switch/enum controls Implement the sof_ipc_tplg_control_ops.update function to support a control change notification from the firmware on switch or enum control types. Based on the module notification message content, look up the swidget, then the scontrol which was the source of the notification then if the message contains the changed values update the cached values. If only a notification without values received, marked the control as dirty and on next read access fetch the new values from the firmware. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231124150853.18648-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-control.c | 179 +++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 938efaceb81c..3d2a35f27a87 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -240,6 +240,50 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev, return ret; } +static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct snd_soc_component *scomp = scontrol->scomp; + struct sof_ipc4_control_msg_payload *data; + struct sof_ipc4_msg *msg = &cdata->msg; + size_t data_size; + unsigned int i; + int ret; + + if (!scontrol->comp_data_dirty) + return; + + if (!pm_runtime_active(scomp->dev)) + return; + + data_size = struct_size(data, chanv, scontrol->num_channels); + data = kmalloc(data_size, GFP_KERNEL); + if (!data) + return; + + data->id = cdata->index; + data->num_elems = scontrol->num_channels; + msg->data_ptr = data; + msg->data_size = data_size; + + scontrol->comp_data_dirty = false; + ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, true); + msg->data_ptr = NULL; + msg->data_size = 0; + if (!ret) { + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = data->chanv[i].channel; + cdata->chanv[i].value = data->chanv[i].value; + } + } else { + dev_err(scomp->dev, "Failed to read control data for %s\n", + scontrol->name); + scontrol->comp_data_dirty = true; + } + + kfree(data); +} + static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, struct snd_ctl_elem_value *ucontrol) { @@ -290,6 +334,8 @@ static int sof_ipc4_switch_get(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; unsigned int i; + sof_ipc4_refresh_generic_control(scontrol); + /* read back each channel */ for (i = 0; i < scontrol->num_channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value; @@ -347,6 +393,8 @@ static int sof_ipc4_enum_get(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; unsigned int i; + sof_ipc4_refresh_generic_control(scontrol); + /* read back each channel */ for (i = 0; i < scontrol->num_channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; @@ -601,6 +649,136 @@ sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false); } +#define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \ + >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT) + +static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) +{ + struct sof_ipc4_msg *ipc4_msg = ipc_message; + struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr; + struct sof_ipc4_control_msg_payload *msg_data; + struct sof_ipc4_control_data *cdata; + struct snd_soc_dapm_widget *widget; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct snd_kcontrol *kc = NULL; + bool scontrol_found = false; + u32 event_param_id; + int i, type; + + if (ndata->event_data_size < sizeof(*msg_data)) { + dev_err(sdev->dev, + "%s: Invalid event data size for module %u.%u: %u\n", + __func__, ndata->module_id, ndata->instance_id, + ndata->event_data_size); + return; + } + + event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK; + switch (event_param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + type = SND_SOC_TPLG_TYPE_MIXER; + break; + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + type = SND_SOC_TPLG_TYPE_ENUM; + break; + default: + dev_err(sdev->dev, + "%s: Invalid control type for module %u.%u: %u\n", + __func__, ndata->module_id, ndata->instance_id, + event_param_id); + return; + } + + /* Find the swidget based on ndata->module_id and ndata->instance_id */ + swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id, + ndata->instance_id); + if (!swidget) { + dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n", + __func__, ndata->module_id, ndata->instance_id); + return; + } + + /* Find the scontrol which is the source of the notification */ + msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data; + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + u32 local_param_id; + + cdata = scontrol->ipc_control_data; + /* + * The scontrol's param_id is stored in the IPC message + * template's extension + */ + local_param_id = PARAM_ID_FROM_EXTENSION(cdata->msg.extension); + if (local_param_id == event_param_id && + msg_data->id == cdata->index) { + scontrol_found = true; + break; + } + } + } + + if (!scontrol_found) { + dev_err(sdev->dev, + "%s: Failed to find control on widget %s: %u:%u\n", + __func__, swidget->widget->name, ndata->event_id & 0xffff, + msg_data->id); + return; + } + + if (msg_data->num_elems) { + /* + * The message includes the updated value/data, update the + * control's local cache using the received notification + */ + for (i = 0; i < msg_data->num_elems; i++) { + u32 channel = msg_data->chanv[i].channel; + + if (channel >= scontrol->num_channels) { + dev_warn(sdev->dev, + "Invalid channel index for %s: %u\n", + scontrol->name, i); + + /* + * Mark the scontrol as dirty to force a refresh + * on next read + */ + scontrol->comp_data_dirty = true; + break; + } + + cdata->chanv[channel].value = msg_data->chanv[i].value; + } + } else { + /* + * Mark the scontrol as dirty because the value/data is changed + * in firmware, forcing a refresh on next read access + */ + scontrol->comp_data_dirty = true; + } + + /* + * Look up the ALSA kcontrol of the scontrol to be able to send a + * notification to user space + */ + widget = swidget->widget; + for (i = 0; i < widget->num_kcontrols; i++) { + /* skip non matching types or non matching indexes within type */ + if (widget->dobj.widget.kcontrol_type[i] == type && + widget->kcontrol_news[i].index == cdata->index) { + kc = widget->kcontrols[i]; + break; + } + } + + if (!kc) + return; + + snd_ctl_notify_one(swidget->scomp->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); +} + /* set up all controls for the widget */ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -674,6 +852,7 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = { .bytes_ext_put = sof_ipc4_bytes_ext_put, .bytes_ext_get = sof_ipc4_bytes_ext_get, .bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get, + .update = sof_ipc4_control_update, .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup, .set_up_volume_table = sof_ipc4_set_up_volume_table, }; From 0ff23d460718641c80c8054425256391dca1ac7d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Nov 2023 17:08:53 +0200 Subject: [PATCH 1401/7721] ASoC: SOF: ipc4: Handle ALSA kcontrol change notification from firmware The control change notification is sent as module notification with a standardized event_id (higher 16 bit is 0xA15A). Add generic code to handle the module notification and invoke the control update callback if the notification is an ALSA kcontrol change message. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231124150853.18648-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 8441f4ae4065..a9d9800d2fcc 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -78,6 +78,9 @@ static const struct sof_ipc4_fw_status { {165, "Reserved (ADSP_IPC_PIPELINE_ALREADY_EXISTS removed)"}, }; +typedef void (*ipc4_notification_handler)(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *msg); + static int sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status) { int i, ret; @@ -610,9 +613,55 @@ static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg return sof_ipc4_init_msg_memory(sdev); } +static void sof_ipc4_module_notification_handler(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *ipc4_msg) +{ + struct sof_ipc4_notify_module_data *data = ipc4_msg->data_ptr; + + /* + * If the notification includes additional, module specific data, then + * we need to re-allocate the buffer and re-read the whole payload, + * including the event_data + */ + if (data->event_data_size) { + void *new; + int ret; + + ipc4_msg->data_size += data->event_data_size; + + new = krealloc(ipc4_msg->data_ptr, ipc4_msg->data_size, GFP_KERNEL); + if (!new) { + ipc4_msg->data_size -= data->event_data_size; + return; + } + + /* re-read the whole payload */ + ipc4_msg->data_ptr = new; + ret = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, + ipc4_msg->data_size); + if (ret < 0) { + dev_err(sdev->dev, + "Failed to read the full module notification: %d\n", + ret); + return; + } + data = ipc4_msg->data_ptr; + } + + /* Handle ALSA kcontrol notification */ + if ((data->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK) == + SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL) { + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + + if (tplg_ops->control->update) + tplg_ops->control->update(sdev, ipc4_msg); + } +} + static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) { struct sof_ipc4_msg *ipc4_msg = sdev->ipc->msg.rx_data; + ipc4_notification_handler handler_func = NULL; size_t data_size = 0; int err; @@ -648,6 +697,10 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) case SOF_IPC4_NOTIFY_EXCEPTION_CAUGHT: snd_sof_dsp_panic(sdev, 0, true); break; + case SOF_IPC4_NOTIFY_MODULE_NOTIFICATION: + data_size = sizeof(struct sof_ipc4_notify_module_data); + handler_func = sof_ipc4_module_notification_handler; + break; default: dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); @@ -663,6 +716,10 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size); } + /* Handle notifications with payload */ + if (handler_func) + handler_func(sdev, ipc4_msg); + sof_ipc4_log_header(sdev->dev, "ipc rx done ", ipc4_msg, true); if (data_size) { From bd5ef3f21d17a80d4e5b9c8e18bad20c8fb53c95 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 24 Nov 2023 09:41:12 +0100 Subject: [PATCH 1402/7721] dt-bindings: clk: g12a-clkc: add CTS_ENCL clock ids Add new CLK ids for the CTS_ENCL and CTS_ENCL_SEL clocks on G12A compatible SoCs. Acked-by: Conor Dooley Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231124-amlogic-v6-4-upstream-dsi-ccf-vim3-v9-1-95256ed139e6@linaro.org Signed-off-by: Jerome Brunet --- include/dt-bindings/clock/g12a-clkc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h index 387767f4e298..636d713f95ff 100644 --- a/include/dt-bindings/clock/g12a-clkc.h +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -279,5 +279,7 @@ #define CLKID_MIPI_DSI_PXCLK_DIV 268 #define CLKID_MIPI_DSI_PXCLK_SEL 269 #define CLKID_MIPI_DSI_PXCLK 270 +#define CLKID_CTS_ENCL 271 +#define CLKID_CTS_ENCL_SEL 272 #endif /* __G12A_CLKC_H */ From 5de4e8353e321c9b91be4233ab99527c4930bfe9 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 24 Nov 2023 09:41:17 +0100 Subject: [PATCH 1403/7721] clk: meson: g12a: add CTS_ENCL & CTS_ENCL_SEL clocks Add new CTS_ENCL & CTS_ENCL_SEL clocks for the G12A compatible SoCs, they are used to feed the VPU LCD Pixel encoder used for DSI display purposes. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231124-amlogic-v6-4-upstream-dsi-ccf-vim3-v9-6-95256ed139e6@linaro.org Signed-off-by: Jerome Brunet --- drivers/clk/meson/g12a.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index f373a8d48b1d..cadd824336ad 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -3549,6 +3549,22 @@ static struct clk_regmap g12a_cts_encp_sel = { }, }; +static struct clk_regmap g12a_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + static struct clk_regmap g12a_cts_vdac_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VIID_CLK_DIV, @@ -3628,6 +3644,22 @@ static struct clk_regmap g12a_cts_encp = { }, }; +static struct clk_regmap g12a_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + static struct clk_regmap g12a_cts_vdac = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL2, @@ -4407,10 +4439,12 @@ static struct clk_hw *g12a_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -4632,10 +4666,12 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -4892,10 +4928,12 @@ static struct clk_hw *sm1_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -5123,10 +5161,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_vclk2_div12_en, &g12a_cts_enci_sel, &g12a_cts_encp_sel, + &g12a_cts_encl_sel, &g12a_cts_vdac_sel, &g12a_hdmi_tx_sel, &g12a_cts_enci, &g12a_cts_encp, + &g12a_cts_encl, &g12a_cts_vdac, &g12a_hdmi_tx, &g12a_hdmi_sel, From 439d3404addf1a1ee8ba6dc6becd555bce7faf98 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 14 Nov 2023 11:14:43 +0100 Subject: [PATCH 1404/7721] dt-bindings: clock: g12a-clkc: add MIPI ISP & CSI PHY clock ids Add MIPI ISP & CSI PHY clock ids to G12A clock bindings header Signed-off-by: Neil Armstrong Acked-by: Conor Dooley Reviewed-by: Daniel Scally Tested-by: Daniel Scally Link: https://lore.kernel.org/r/20231114-topic-amlogic-upstream-isp-clocks-v1-1-223958791501@linaro.org Signed-off-by: Jerome Brunet --- include/dt-bindings/clock/g12a-clkc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h index 636d713f95ff..fd09819da2ec 100644 --- a/include/dt-bindings/clock/g12a-clkc.h +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -281,5 +281,11 @@ #define CLKID_MIPI_DSI_PXCLK 270 #define CLKID_CTS_ENCL 271 #define CLKID_CTS_ENCL_SEL 272 +#define CLKID_MIPI_ISP_DIV 273 +#define CLKID_MIPI_ISP_SEL 274 +#define CLKID_MIPI_ISP 275 +#define CLKID_MIPI_ISP_GATE 276 +#define CLKID_MIPI_ISP_CSI_PHY0 277 +#define CLKID_MIPI_ISP_CSI_PHY1 278 #endif /* __G12A_CLKC_H */ From 773e4e98730845dddab6b4accef03d03b6ff25ce Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 14 Nov 2023 11:14:44 +0100 Subject: [PATCH 1405/7721] clk: meson: g12a: add MIPI ISP clocks Add the MIPI ISP gate, divider and mux used to feed the MIPI CSI ISP (Image Signal Processor) IP on the Amlogic G12B SoC. Signed-off-by: Neil Armstrong Reviewed-by: Daniel Scally Tested-by: Daniel Scally Link: https://lore.kernel.org/r/20231114-topic-amlogic-upstream-isp-clocks-v1-2-223958791501@linaro.org Signed-off-by: Jerome Brunet --- drivers/clk/meson/g12a.c | 66 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/g12a.h | 1 + 2 files changed, 67 insertions(+) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index cadd824336ad..2658a52a28ac 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -3754,6 +3754,66 @@ static struct clk_regmap g12a_mipi_dsi_pxclk = { }, }; +/* MIPI ISP Clocks */ + +static const struct clk_parent_data g12b_mipi_isp_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw }, + { .hw = &g12a_hifi_pll.hw }, + { .hw = &g12a_fclk_div2p5.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12b_mipi_isp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_ISP_CLK_CNTL, + .mask = 7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12b_mipi_isp_parent_data, + .num_parents = ARRAY_SIZE(g12b_mipi_isp_parent_data), + }, +}; + +static struct clk_regmap g12b_mipi_isp_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_ISP_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12b_mipi_isp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_ISP_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_isp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* HDMI Clocks */ static const struct clk_parent_data g12a_hdmi_parent_data[] = { @@ -4765,6 +4825,9 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, + [CLKID_MIPI_ISP_SEL] = &g12b_mipi_isp_sel.hw, + [CLKID_MIPI_ISP_DIV] = &g12b_mipi_isp_div.hw, + [CLKID_MIPI_ISP] = &g12b_mipi_isp.hw, }; static struct clk_hw *sm1_hw_clks[] = { @@ -5261,6 +5324,9 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_mipi_dsi_pxclk_sel, &g12a_mipi_dsi_pxclk_div, &g12a_mipi_dsi_pxclk, + &g12b_mipi_isp_sel, + &g12b_mipi_isp_div, + &g12b_mipi_isp, }; static const struct reg_sequence g12a_init_regs[] = { diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index f11ee3c59849..27df99c4565a 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -70,6 +70,7 @@ #define HHI_MALI_CLK_CNTL 0x1b0 #define HHI_VPU_CLKC_CNTL 0x1b4 #define HHI_VPU_CLK_CNTL 0x1bC +#define HHI_ISP_CLK_CNTL 0x1C0 #define HHI_NNA_CLK_CNTL 0x1C8 #define HHI_HDMI_CLK_CNTL 0x1CC #define HHI_VDEC_CLK_CNTL 0x1E0 From 5205628ab0bfe64952974d476ee001f6c7e0ef7f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 14 Nov 2023 11:14:45 +0100 Subject: [PATCH 1406/7721] clk: meson: g12a: add CSI & ISP gates clocks Add the gates entries for the CSI ISP domain and CSI PHYs. [jbrunet: fixed checkpatch spelling warning] Signed-off-by: Neil Armstrong Reviewed-by: Daniel Scally Tested-by: Daniel Scally Link: https://lore.kernel.org/r/20231114-topic-amlogic-upstream-isp-clocks-v1-3-223958791501@linaro.org Signed-off-by: Jerome Brunet --- drivers/clk/meson/g12a.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 2658a52a28ac..90f4c6103014 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -4306,9 +4306,12 @@ static MESON_GATE(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); static MESON_GATE(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); static MESON_GATE(g12a_bt656, HHI_GCLK_MPEG2, 6); static MESON_GATE(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static MESON_GATE(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17); static MESON_GATE(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); static MESON_GATE(g12a_uart2, HHI_GCLK_MPEG2, 15); static MESON_GATE(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(g12b_csi_phy1, HHI_GCLK_MPEG2, 28); +static MESON_GATE(g12b_csi_phy0, HHI_GCLK_MPEG2, 29); static MESON_GATE(g12a_gic, HHI_GCLK_MPEG2, 30); static MESON_GATE(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); @@ -4828,6 +4831,9 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_MIPI_ISP_SEL] = &g12b_mipi_isp_sel.hw, [CLKID_MIPI_ISP_DIV] = &g12b_mipi_isp_div.hw, [CLKID_MIPI_ISP] = &g12b_mipi_isp.hw, + [CLKID_MIPI_ISP_GATE] = &g12b_mipi_isp_gate.hw, + [CLKID_MIPI_ISP_CSI_PHY0] = &g12b_csi_phy0.hw, + [CLKID_MIPI_ISP_CSI_PHY1] = &g12b_csi_phy1.hw, }; static struct clk_hw *sm1_hw_clks[] = { @@ -5327,6 +5333,9 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12b_mipi_isp_sel, &g12b_mipi_isp_div, &g12b_mipi_isp, + &g12b_mipi_isp_gate, + &g12b_csi_phy1, + &g12b_csi_phy0, }; static const struct reg_sequence g12a_init_regs[] = { From 964946b88887089f447a9b6a28c39ee97dc76360 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 30 Oct 2023 11:12:26 +0100 Subject: [PATCH 1407/7721] firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create() The ending NULL is not taken into account by strncat(), so switch to snprintf() to correctly build 'debug_name'. Using snprintf() also makes the code more readable. Fixes: aa276781a64a ("firmware: Add basic support for TI System Control Interface (TI-SCI) protocol") Signed-off-by: Christophe JAILLET Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/7158db0a4d7b19855ddd542ec61b666973aad8dc.1698660720.git.christophe.jaillet@wanadoo.fr Signed-off-by: Nishanth Menon --- drivers/firmware/ti_sci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 7041befc756a..8b9a2556de16 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -164,7 +164,7 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct resource *res; - char debug_name[50] = "ti_sci_debug@"; + char debug_name[50]; /* Debug region is optional */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -181,10 +181,10 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, /* Setup NULL termination */ info->debug_buffer[info->debug_region_size] = 0; - info->d = debugfs_create_file(strncat(debug_name, dev_name(dev), - sizeof(debug_name) - - sizeof("ti_sci_debug@")), - 0444, NULL, info, &ti_sci_debug_fops); + snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s", + dev_name(dev)); + info->d = debugfs_create_file(debug_name, 0444, NULL, info, + &ti_sci_debug_fops); if (IS_ERR(info->d)) return PTR_ERR(info->d); From c1170c1d04d5bfbd9b38cb968d45b77e6bda2098 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:49:59 +0100 Subject: [PATCH 1408/7721] ARM: dts: ti: keystone: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124095000.58487-1-krzysztof.kozlowski@linaro.org Signed-off-by: Nishanth Menon --- arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi | 6 +++--- arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts | 2 +- arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi | 6 +++--- arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts | 2 +- arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi | 6 +++--- arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi index bff73a0ed10b..5c88a90903b8 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi @@ -36,9 +36,9 @@ queue-pools { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts index 7bfc80f1af26..f0ddbbcdc972 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts @@ -9,7 +9,7 @@ #include "keystone-k2g.dtsi" / { - compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; + compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; model = "Texas Instruments K2G General Purpose EVM"; memory@800000000 { diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi index f6306933ff42..7109ca031617 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi @@ -37,9 +37,9 @@ queue-pools { qpend { qpend-0 { qrange = <77 8>; - interrupts =<0 308 0xf04 0 309 0xf04 0 310 0xf04 - 0 311 0xf04 0 312 0xf04 0 313 0xf04 - 0 314 0xf04 0 315 0xf04>; + interrupts = <0 308 0xf04 0 309 0xf04 0 310 0xf04 + 0 311 0xf04 0 312 0xf04 0 313 0xf04 + 0 314 0xf04 0 315 0xf04>; qalloc-by-id; }; }; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts index 206df8a8d9dd..8dfb54295027 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts @@ -10,7 +10,7 @@ #include "keystone-k2hk.dtsi" / { - compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; + compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; model = "Texas Instruments Keystone 2 Kepler/Hawking EVM"; reserved-memory { diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi index 8a421c65f920..c2ee775eab6a 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi @@ -49,9 +49,9 @@ queue-pools { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <8704 16>; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi index 5ec6680a533d..1afebd7458c1 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi @@ -36,9 +36,9 @@ queue-pools { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; From ea5f49061d1ddbe7c066c3f28ecb106a479154af Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 6 Nov 2023 12:07:59 +0200 Subject: [PATCH 1409/7721] MAINTAINERS: update iwlwifi maintainers Add Miri as a maintainer for iwlwifi driver. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20231106100759.1226662-1-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fca2003efa7b..7e7a54386dc1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10860,6 +10860,7 @@ F: drivers/net/wireless/intel/iwlegacy/ INTEL WIRELESS WIFI LINK (iwlwifi) M: Gregory Greenman +M: Miri Korenblit L: linux-wireless@vger.kernel.org S: Supported W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi From f52c8fba984c7ca1ee687504862a4f8b3c5ef854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Nov 2023 20:41:38 +0100 Subject: [PATCH 1410/7721] rfkill: return ENOTTY on invalid ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For unknown ioctls the correct error is ENOTTY "Inappropriate ioctl for device". ENOSYS as returned before should only be used to indicate that a syscall is not available at all. Signed-off-by: Thomas Weißschuh Reviewed-by: Przemek Kitszel Link: https://lore.kernel.org/r/20231101-rfkill-ioctl-enosys-v1-1-5bf374fabffe@weissschuh.net [in theory this breaks userspace API, but it was discussed and researched, and nothing found relying on the current behaviour] Signed-off-by: Johannes Berg --- net/rfkill/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 14cc8fe8584b..c3feb4f49d09 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1351,11 +1351,11 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct rfkill_data *data = file->private_data; - int ret = -ENOSYS; + int ret = -ENOTTY; u32 size; if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) - return -ENOSYS; + return -ENOTTY; mutex_lock(&data->mtx); switch (_IOC_NR(cmd)) { From d3ca4ab4f16eb81dc3e7721251adcba49b229d54 Mon Sep 17 00:00:00 2001 From: Liam Kearney Date: Wed, 25 Oct 2023 11:27:55 +1100 Subject: [PATCH 1411/7721] wifi: ieee80211: fix PV1 frame control field name Update PV1 frame control field TODS to FROMDS to match 802.11 standard Signed-off-by: Liam Kearney Reviewed-by: Jeff Johnson Link: https://lore.kernel.org/r/20231025002755.1752983-1-liam.kearney@morsemicro.com Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 958771bac9c0..5e5ea216f341 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -172,11 +172,11 @@ #define IEEE80211_SN_MODULO (IEEE80211_MAX_SN + 1) -/* PV1 Layout 11ah 9.8.3.1 */ +/* PV1 Layout IEEE 802.11-2020 9.8.3.1 */ #define IEEE80211_PV1_FCTL_VERS 0x0003 #define IEEE80211_PV1_FCTL_FTYPE 0x001c #define IEEE80211_PV1_FCTL_STYPE 0x00e0 -#define IEEE80211_PV1_FCTL_TODS 0x0100 +#define IEEE80211_PV1_FCTL_FROMDS 0x0100 #define IEEE80211_PV1_FCTL_MOREFRAGS 0x0200 #define IEEE80211_PV1_FCTL_PM 0x0400 #define IEEE80211_PV1_FCTL_MOREDATA 0x0800 From 6285ee30caa1a0fbd9537496578085c143127eee Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 13 Nov 2023 11:35:00 +0200 Subject: [PATCH 1412/7721] wifi: cfg80211: Extend support for scanning while MLO connected To extend the support of TSF accounting in scan results for MLO connections, allow to indicate in the scan request the link ID corresponding to the BSS whose TSF should be used for the TSF accounting. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20231113112844.d4490bcdefb1.I8fcd158b810adddef4963727e9153096416b30ce@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 8 +++++--- net/wireless/nl80211.c | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b137a33a1b68..d36ad4cedf3b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2608,6 +2608,8 @@ struct cfg80211_scan_6ghz_params { * @n_6ghz_params: number of 6 GHz params * @scan_6ghz_params: 6 GHz params * @bssid: BSSID to scan for (most commonly, the wildcard BSSID) + * @tsf_report_link_id: for MLO, indicates the link ID of the BSS that should be + * used for TSF reporting. Can be set to -1 to indicate no preference. */ struct cfg80211_scan_request { struct cfg80211_ssid *ssids; @@ -2636,6 +2638,7 @@ struct cfg80211_scan_request { bool scan_6ghz; u32 n_6ghz_params; struct cfg80211_scan_6ghz_params *scan_6ghz_params; + s8 tsf_report_link_id; /* keep last */ struct ieee80211_channel *channels[] __counted_by(n_channels); diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index dced2c49daec..03e44823355e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -6241,9 +6241,11 @@ enum nl80211_feature_flags { * the BSS that the interface that requested the scan is connected to * (if available). * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the - * time the last beacon/probe was received. The time is the TSF of the - * BSS that the interface that requested the scan is connected to - * (if available). + * time the last beacon/probe was received. For a non MLO connection, the + * time is the TSF of the BSS that the interface that requested the scan is + * connected to (if available). For an MLO connection, the time is the TSF + * of the BSS corresponding with link ID specified in the scan request (if + * specified). * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of * channel dwell time. * @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 569234bc2be6..12b7bd92bb86 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9337,6 +9337,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) else eth_broadcast_addr(request->bssid); + request->tsf_report_link_id = nl80211_link_id_or_invalid(info->attrs); request->wdev = wdev; request->wiphy = &rdev->wiphy; request->scan_start = jiffies; From cbde0b49f276c43efca6b5d5193f2d26f51afbfa Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 13 Nov 2023 11:35:01 +0200 Subject: [PATCH 1413/7721] wifi: mac80211: Extend support for scanning while MLO connected - If the scan request includes a link ID, validate that it is one of the active links. Otherwise, if the scan request doesn't include a valid link ID, select one of the active links. - When reporting the TSF for a BSS entry, use the link ID information from the Rx status or the scan request to set the parent BSSID. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20231113112844.68564692c404.Iae9605cbb7f9d52e00ce98260b3559a34cf18341@changeid Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 48 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 24fa06105378..1d98877647d8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -194,11 +194,32 @@ ieee80211_bss_info_update(struct ieee80211_local *local, if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && scan_sdata->vif.cfg.assoc && ieee80211_have_rx_timestamp(rx_status)) { - bss_meta.parent_tsf = - ieee80211_calculate_rx_timestamp(local, rx_status, - len + FCS_LEN, 24); - ether_addr_copy(bss_meta.parent_bssid, - scan_sdata->vif.bss_conf.bssid); + struct ieee80211_bss_conf *link_conf = NULL; + + /* for an MLO connection, set the TSF data only in case we have + * an indication on which of the links the frame was received + */ + if (ieee80211_vif_is_mld(&scan_sdata->vif)) { + if (rx_status->link_valid) { + s8 link_id = rx_status->link_id; + + link_conf = + rcu_dereference(scan_sdata->vif.link_conf[link_id]); + } + } else { + link_conf = &scan_sdata->vif.bss_conf; + } + + if (link_conf) { + bss_meta.parent_tsf = + ieee80211_calculate_rx_timestamp(local, + rx_status, + len + FCS_LEN, + 24); + + ether_addr_copy(bss_meta.parent_bssid, + link_conf->bssid); + } } rcu_read_unlock(); @@ -666,6 +687,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->scan_req) return -EBUSY; + /* For an MLO connection, if a link ID was specified, validate that it + * is indeed active. If no link ID was specified, select one of the + * active links. + */ + if (ieee80211_vif_is_mld(&sdata->vif)) { + if (req->tsf_report_link_id >= 0) { + if (!(sdata->vif.active_links & + BIT(req->tsf_report_link_id))) + return -EINVAL; + } else { + req->tsf_report_link_id = + __ffs(sdata->vif.active_links); + } + } + if (!__ieee80211_can_leave_ch(sdata)) return -EBUSY; @@ -714,6 +750,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->hw_scan_req->req.duration = req->duration; local->hw_scan_req->req.duration_mandatory = req->duration_mandatory; + local->hw_scan_req->req.tsf_report_link_id = + req->tsf_report_link_id; local->hw_scan_band = 0; local->hw_scan_req->req.n_6ghz_params = req->n_6ghz_params; From d1f7728259ef02ac20b7afb6e7eb5a9eb1696c25 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 15 Nov 2023 17:49:59 +0100 Subject: [PATCH 1414/7721] gpiolib: provide gpio_device_get_label() Provide a getter for the GPIO device label string so that users don't have to dereference struct gpio_chip directly. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 14 ++++++++++++++ include/linux/gpio/driver.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 95d2a7b2ea3e..a5faaea6915d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -254,6 +254,20 @@ int gpio_device_get_base(struct gpio_device *gdev) } EXPORT_SYMBOL_GPL(gpio_device_get_base); +/** + * gpio_device_get_label() - Get the label of this GPIO device + * @gdev: GPIO device + * + * Returns: + * Pointer to the string containing the GPIO device label. The string's + * lifetime is tied to that of the underlying GPIO device. + */ +const char *gpio_device_get_label(struct gpio_device *gdev) +{ + return gdev->label; +} +EXPORT_SYMBOL(gpio_device_get_label); + /** * gpio_device_get_chip() - Get the gpio_chip implementation of this GPIO device * @gdev: GPIO device diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 0aed62f0c633..100c329dc986 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -786,6 +786,7 @@ struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc); /* struct gpio_device getters */ int gpio_device_get_base(struct gpio_device *gdev); +const char *gpio_device_get_label(struct gpio_device *gdev); #else /* CONFIG_GPIOLIB */ From e6d71c7878bc6140d1b0b527116af8fd8376d3d5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 15:44:24 -0700 Subject: [PATCH 1415/7721] dt-bindings: gpio: brcmstb: drop unneeded quotes Drop unneeded quotes over simple string values to fix a soon to be enabled yamllint warning: [error] string value is redundantly quoted with any quotes (quoted-strings) Signed-off-by: Rob Herring Acked-by: Florian Fainelli Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml index 4a896ff7edc5..a1e71c974e79 100644 --- a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml @@ -72,7 +72,7 @@ required: - reg - gpio-controller - "#gpio-cells" - - "brcm,gpio-bank-widths" + - brcm,gpio-bank-widths additionalProperties: false From 0cc3f50f42d262d6175ee2834aeb56e98934cfcc Mon Sep 17 00:00:00 2001 From: Vinayak Yadawad Date: Thu, 9 Nov 2023 12:03:44 +0530 Subject: [PATCH 1416/7721] wifi: nl80211: Documentation update for NL80211_CMD_PORT_AUTHORIZED event Drivers supporting 4-way handshake offload for AP/P2p-GO and STA/P2P-client should use this event to indicate that port has been authorized and open for regular data traffic, sending this event on completion of successful 4-way handshake. Signed-off-by: Vinayak Yadawad Link: https://lore.kernel.org/r/f746b59f41436e9df29c24688035fbc6eb91ab06.1699510229.git.vinayak.yadawad@broadcom.com [rewrite it all to not use the term 'GC' that we don't use in place of P2P-client] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 03e44823355e..0cd1da2c2902 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1135,11 +1135,15 @@ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously * configured PMK for the authenticator address identified by * %NL80211_ATTR_MAC. - * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was - * completed successfully. Drivers that support 4 way handshake offload - * should send this event after indicating 802.1X FT assocation with - * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT - * should be indicated instead. + * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates port is authorized and + * open for regular data traffic. For STA/P2P-client, this event is sent + * with AP MAC address and for AP/P2P-GO, the event carries the STA/P2P- + * client MAC address. + * Drivers that support 4 way handshake offload should send this event for + * STA/P2P-client after successful 4-way HS or after 802.1X FT following + * NL80211_CMD_CONNECT or NL80211_CMD_ROAM. Drivers using AP/P2P-GO 4-way + * handshake offload should send this event on successful completion of + * 4-way handshake with the peer (STA/P2P-client). * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request * and RX notification. This command is used both as a request to transmit * a control port frame and as a notification that a control port frame From 014f831abcb82738e57c0b00db66dfef0798ed67 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 13 Nov 2023 23:12:00 +0100 Subject: [PATCH 1417/7721] drm/nouveau: use GPUVM common infrastructure GPUVM provides common infrastructure to track external and evicted GEM objects as well as locking and validation helpers. Especially external and evicted object tracking is a huge improvement compared to the current brute force approach of iterating all mappings in order to lock and validate the GPUVM's GEM objects. Hence, make us of it. Signed-off-by: Danilo Krummrich Reviewed-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20231113221202.7203-1-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 +- drivers/gpu/drm/nouveau/nouveau_exec.c | 57 +++------- drivers/gpu/drm/nouveau/nouveau_exec.h | 4 - drivers/gpu/drm/nouveau/nouveau_sched.c | 9 +- drivers/gpu/drm/nouveau/nouveau_sched.h | 7 +- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 134 +++++++++++++----------- 6 files changed, 100 insertions(+), 115 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 7afad86da64b..b7dda486a7ea 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1061,17 +1061,18 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); + struct drm_gem_object *obj = &bo->base; struct ttm_resource *old_reg = bo->resource; struct nouveau_drm_tile *new_tile = NULL; int ret = 0; - if (new_reg->mem_type == TTM_PL_TT) { ret = nouveau_ttm_tt_bind(bo->bdev, bo->ttm, new_reg); if (ret) return ret; } + drm_gpuvm_bo_gem_evict(obj, evict); nouveau_bo_move_ntfy(bo, new_reg); ret = ttm_bo_wait_ctx(bo, ctx); if (ret) @@ -1136,6 +1137,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, out_ntfy: if (ret) { nouveau_bo_move_ntfy(bo, bo->resource); + drm_gpuvm_bo_gem_evict(obj, !evict); } return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index 9a5ef574744b..f8ef7004d133 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MIT -#include - #include "nouveau_drv.h" #include "nouveau_gem.h" #include "nouveau_mem.h" @@ -86,14 +84,12 @@ */ static int -nouveau_exec_job_submit(struct nouveau_job *job) +nouveau_exec_job_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); struct nouveau_cli *cli = job->cli; struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; int ret; /* Create a new fence, but do not emit yet. */ @@ -102,52 +98,29 @@ nouveau_exec_job_submit(struct nouveau_job *job) return ret; nouveau_uvmm_lock(uvmm); - drm_exec_init(exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); - drm_exec_until_all_locked(exec) { - struct drm_gpuva *va; - - drm_gpuvm_for_each_va(va, &uvmm->base) { - if (unlikely(va == &uvmm->base.kernel_alloc_node)) - continue; - - ret = drm_exec_prepare_obj(exec, va->gem.obj, 1); - drm_exec_retry_on_contention(exec); - if (ret) - goto err_uvmm_unlock; - } + ret = drm_gpuvm_exec_lock(vme); + if (ret) { + nouveau_uvmm_unlock(uvmm); + return ret; } nouveau_uvmm_unlock(uvmm); - drm_exec_for_each_locked_object(exec, index, obj) { - struct nouveau_bo *nvbo = nouveau_gem_object(obj); - - ret = nouveau_bo_validate(nvbo, true, false); - if (ret) - goto err_exec_fini; + ret = drm_gpuvm_exec_validate(vme); + if (ret) { + drm_gpuvm_exec_unlock(vme); + return ret; } return 0; - -err_uvmm_unlock: - nouveau_uvmm_unlock(uvmm); -err_exec_fini: - drm_exec_fini(exec); - return ret; - } static void -nouveau_exec_job_armed_submit(struct nouveau_job *job) +nouveau_exec_job_armed_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; - - drm_exec_for_each_locked_object(exec, index, obj) - dma_resv_add_fence(obj->resv, job->done_fence, job->resv_usage); - - drm_exec_fini(exec); + drm_gpuvm_exec_resv_add_fence(vme, job->done_fence, + job->resv_usage, job->resv_usage); + drm_gpuvm_exec_unlock(vme); } static struct dma_fence * diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.h b/drivers/gpu/drm/nouveau/nouveau_exec.h index 5488d337bcc0..5a8fe1208a44 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.h +++ b/drivers/gpu/drm/nouveau/nouveau_exec.h @@ -3,16 +3,12 @@ #ifndef __NOUVEAU_EXEC_H__ #define __NOUVEAU_EXEC_H__ -#include - #include "nouveau_drv.h" #include "nouveau_sched.h" struct nouveau_exec_job_args { struct drm_file *file_priv; struct nouveau_sched_entity *sched_entity; - - struct drm_exec exec; struct nouveau_channel *chan; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index e03fd2bc8a11..f69f4cbf251b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -263,6 +263,11 @@ nouveau_job_submit(struct nouveau_job *job) { struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); struct dma_fence *done_fence = NULL; + struct drm_gpuvm_exec vm_exec = { + .vm = &nouveau_cli_uvmm(job->cli)->base, + .flags = DRM_EXEC_IGNORE_DUPLICATES, + .num_fences = 1, + }; int ret; ret = nouveau_job_add_deps(job); @@ -282,7 +287,7 @@ nouveau_job_submit(struct nouveau_job *job) * successfully. */ if (job->ops->submit) { - ret = job->ops->submit(job); + ret = job->ops->submit(job, &vm_exec); if (ret) goto err_cleanup; } @@ -315,7 +320,7 @@ nouveau_job_submit(struct nouveau_job *job) set_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &job->done_fence->flags); if (job->ops->armed_submit) - job->ops->armed_submit(job); + job->ops->armed_submit(job, &vm_exec); nouveau_job_fence_attach(job); diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index 27ac19792597..0f87697dbc9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -5,7 +5,7 @@ #include -#include +#include #include #include "nouveau_drv.h" @@ -54,7 +54,6 @@ struct nouveau_job { struct drm_file *file_priv; struct nouveau_cli *cli; - struct drm_exec exec; enum dma_resv_usage resv_usage; struct dma_fence *done_fence; @@ -76,8 +75,8 @@ struct nouveau_job { /* If .submit() returns without any error, it is guaranteed that * armed_submit() is called. */ - int (*submit)(struct nouveau_job *); - void (*armed_submit)(struct nouveau_job *); + int (*submit)(struct nouveau_job *, struct drm_gpuvm_exec *); + void (*armed_submit)(struct nouveau_job *, struct drm_gpuvm_exec *); struct dma_fence *(*run)(struct nouveau_job *); void (*free)(struct nouveau_job *); enum drm_gpu_sched_stat (*timeout)(struct nouveau_job *); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index eda7bb8624f1..90e6732ee9b5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -438,8 +438,9 @@ nouveau_uvma_region_complete(struct nouveau_uvma_region *reg) static void op_map_prepare_unwind(struct nouveau_uvma *uvma) { + struct drm_gpuva *va = &uvma->va; nouveau_uvma_gem_put(uvma); - drm_gpuva_remove(&uvma->va); + drm_gpuva_remove(va); nouveau_uvma_free(uvma); } @@ -468,6 +469,7 @@ nouveau_uvmm_sm_prepare_unwind(struct nouveau_uvmm *uvmm, break; case DRM_GPUVA_OP_REMAP: { struct drm_gpuva_op_remap *r = &op->remap; + struct drm_gpuva *va = r->unmap->va; if (r->next) op_map_prepare_unwind(new->next); @@ -475,7 +477,7 @@ nouveau_uvmm_sm_prepare_unwind(struct nouveau_uvmm *uvmm, if (r->prev) op_map_prepare_unwind(new->prev); - op_unmap_prepare_unwind(r->unmap->va); + op_unmap_prepare_unwind(va); break; } case DRM_GPUVA_OP_UNMAP: @@ -634,6 +636,7 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, goto unwind; } } + break; } case DRM_GPUVA_OP_REMAP: { @@ -1135,12 +1138,53 @@ bind_link_gpuvas(struct bind_job_op *bop) } static int -nouveau_uvmm_bind_job_submit(struct nouveau_job *job) +bind_lock_validate(struct nouveau_job *job, struct drm_exec *exec, + unsigned int num_fences) +{ + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); + struct bind_job_op *op; + int ret; + + list_for_each_op(op, &bind_job->ops) { + struct drm_gpuva_op *va_op; + + if (!op->ops) + continue; + + drm_gpuva_for_each_op(va_op, op->ops) { + struct drm_gem_object *obj = op_gem_obj(va_op); + + if (unlikely(!obj)) + continue; + + ret = drm_exec_prepare_obj(exec, obj, num_fences); + if (ret) + return ret; + + /* Don't validate GEMs backing mappings we're about to + * unmap, it's not worth the effort. + */ + if (va_op->op == DRM_GPUVA_OP_UNMAP) + continue; + + ret = nouveau_bo_validate(nouveau_gem_object(obj), + true, false); + if (ret) + return ret; + } + } + + return 0; +} + +static int +nouveau_uvmm_bind_job_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); struct nouveau_sched_entity *entity = job->entity; - struct drm_exec *exec = &job->exec; + struct drm_exec *exec = &vme->exec; struct bind_job_op *op; int ret; @@ -1157,6 +1201,8 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) dma_resv_unlock(obj->resv); if (IS_ERR(op->vm_bo)) return PTR_ERR(op->vm_bo); + + drm_gpuvm_bo_extobj_add(op->vm_bo); } ret = bind_validate_op(job, op); @@ -1179,6 +1225,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) * unwind all GPU VA space changes on failure. */ nouveau_uvmm_lock(uvmm); + list_for_each_op(op, &bind_job->ops) { switch (op->op) { case OP_MAP_SPARSE: @@ -1290,55 +1337,13 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) } } - drm_exec_init(exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(exec, vme->flags); drm_exec_until_all_locked(exec) { - list_for_each_op(op, &bind_job->ops) { - struct drm_gpuva_op *va_op; - - if (IS_ERR_OR_NULL(op->ops)) - continue; - - drm_gpuva_for_each_op(va_op, op->ops) { - struct drm_gem_object *obj = op_gem_obj(va_op); - - if (unlikely(!obj)) - continue; - - ret = drm_exec_prepare_obj(exec, obj, 1); - drm_exec_retry_on_contention(exec); - if (ret) { - op = list_last_op(&bind_job->ops); - goto unwind; - } - } - } - } - - list_for_each_op(op, &bind_job->ops) { - struct drm_gpuva_op *va_op; - - if (IS_ERR_OR_NULL(op->ops)) - continue; - - drm_gpuva_for_each_op(va_op, op->ops) { - struct drm_gem_object *obj = op_gem_obj(va_op); - - if (unlikely(!obj)) - continue; - - /* Don't validate GEMs backing mappings we're about to - * unmap, it's not worth the effort. - */ - if (unlikely(va_op->op == DRM_GPUVA_OP_UNMAP)) - continue; - - ret = nouveau_bo_validate(nouveau_gem_object(obj), - true, false); - if (ret) { - op = list_last_op(&bind_job->ops); - goto unwind; - } + ret = bind_lock_validate(job, exec, vme->num_fences); + drm_exec_retry_on_contention(exec); + if (ret) { + op = list_last_op(&bind_job->ops); + goto unwind; } } @@ -1413,21 +1418,17 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) } nouveau_uvmm_unlock(uvmm); - drm_exec_fini(exec); + drm_gpuvm_exec_unlock(vme); return ret; } static void -nouveau_uvmm_bind_job_armed_submit(struct nouveau_job *job) +nouveau_uvmm_bind_job_armed_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; - - drm_exec_for_each_locked_object(exec, index, obj) - dma_resv_add_fence(obj->resv, job->done_fence, job->resv_usage); - - drm_exec_fini(exec); + drm_gpuvm_exec_resv_add_fence(vme, job->done_fence, + job->resv_usage, job->resv_usage); + drm_gpuvm_exec_unlock(vme); } static struct dma_fence * @@ -1815,8 +1816,17 @@ nouveau_uvmm_free(struct drm_gpuvm *gpuvm) kfree(uvmm); } +static int +nouveau_uvmm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec) +{ + struct nouveau_bo *nvbo = nouveau_gem_object(vm_bo->obj); + + return nouveau_bo_validate(nvbo, true, false); +} + static const struct drm_gpuvm_ops gpuvm_ops = { .vm_free = nouveau_uvmm_free, + .vm_bo_validate = nouveau_uvmm_bo_validate, }; int From 5f03a507b29e44a848f315c7240c19894dd8be4f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 14 Nov 2023 01:27:24 +0100 Subject: [PATCH 1418/7721] drm/nouveau: implement 1:1 scheduler - entity relationship Recent patches to the DRM scheduler [1][2] allow for a variable number of run-queues and add support for (shared) workqueues rather than dedicated kthreads per scheduler. This allows us to create a 1:1 relationship between a GPU scheduler and a scheduler entity, in order to properly support firmware schedulers being able to handle an arbitrary amount of dynamically allocated command ring buffers. This perfectly matches Nouveau's needs, hence make use of it. Topology wise we create one scheduler instance per client (handling VM_BIND jobs) and one scheduler instance per channel (handling EXEC jobs). All channel scheduler instances share a workqueue, but every client scheduler instance has a dedicated workqueue. The latter is required to ensure that for VM_BIND job's free_job() work and run_job() work can always run concurrently and hence, free_job() work can never stall run_job() work. For EXEC jobs we don't have this requirement, since EXEC job's free_job() does not require to take any locks which indirectly or directly are held for allocations elsewhere. [1] https://lore.kernel.org/all/8f53f7ef-7621-4f0b-bdef-d8d20bc497ff@redhat.com/T/ [2] https://lore.kernel.org/all/20231031032439.1558703-1-matthew.brost@intel.com/T/ Signed-off-by: Danilo Krummrich Reviewed-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20231114002728.3491-1-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 18 +-- drivers/gpu/drm/nouveau/nouveau_abi16.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 31 ++-- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 +- drivers/gpu/drm/nouveau/nouveau_exec.c | 7 +- drivers/gpu/drm/nouveau/nouveau_exec.h | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.c | 197 +++++++++++++----------- drivers/gpu/drm/nouveau/nouveau_sched.h | 35 ++--- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 69 +++------ drivers/gpu/drm/nouveau/nouveau_uvmm.h | 4 +- 10 files changed, 179 insertions(+), 195 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 2edd7bb13fae..7542e1787183 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -127,21 +127,14 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, { struct nouveau_abi16_ntfy *ntfy, *temp; - /* When a client exits without waiting for it's queued up jobs to - * finish it might happen that we fault the channel. This is due to - * drm_file_free() calling drm_gem_release() before the postclose() - * callback. Hence, we can't tear down this scheduler entity before - * uvmm mappings are unmapped. Currently, we can't detect this case. - * - * However, this should be rare and harmless, since the channel isn't - * needed anymore. - */ - nouveau_sched_entity_fini(&chan->sched_entity); + /* Cancel all jobs from the entity's queue. */ + drm_sched_entity_fini(&chan->sched.entity); - /* wait for all activity to stop before cleaning up */ if (chan->chan) nouveau_channel_idle(chan->chan); + nouveau_sched_fini(&chan->sched); + /* cleanup notifier state */ list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { nouveau_abi16_ntfy_fini(chan, ntfy); @@ -344,8 +337,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; - ret = nouveau_sched_entity_init(&chan->sched_entity, &drm->sched, - drm->sched_wq); + ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 9f538486c10e..1f5e243c0c75 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -26,7 +26,7 @@ struct nouveau_abi16_chan { struct nouveau_bo *ntfy; struct nouveau_vma *ntfy_vma; struct nvkm_mm heap; - struct nouveau_sched_entity sched_entity; + struct nouveau_sched sched; }; struct nouveau_abi16 { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index f603eaef1560..7e5f19153829 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -201,9 +201,9 @@ nouveau_cli_fini(struct nouveau_cli *cli) WARN_ON(!list_empty(&cli->worker)); usif_client_fini(cli); + nouveau_sched_fini(&cli->sched); if (uvmm) nouveau_uvmm_fini(uvmm); - nouveau_sched_entity_fini(&cli->sched_entity); nouveau_vmm_fini(&cli->svm); nouveau_vmm_fini(&cli->vmm); nvif_mmu_dtor(&cli->mmu); @@ -310,8 +310,17 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, cli->mem = &mems[ret]; - ret = nouveau_sched_entity_init(&cli->sched_entity, &drm->sched, - drm->sched_wq); + /* Don't pass in the (shared) sched_wq in order to let + * nouveau_sched_init() create a dedicated one for VM_BIND jobs. + * + * This is required to ensure that for VM_BIND jobs free_job() work and + * run_job() work can always run concurrently and hence, free_job() work + * can never stall run_job() work. For EXEC jobs we don't have this + * requirement, since EXEC job's free_job() does not require to take any + * locks which indirectly or directly are held for allocations + * elsewhere. + */ + ret = nouveau_sched_init(&cli->sched, drm, NULL); if (ret) goto done; @@ -582,13 +591,16 @@ nouveau_drm_device_init(struct drm_device *dev) nvif_parent_ctor(&nouveau_parent, &drm->parent); drm->master.base.object.parent = &drm->parent; - ret = nouveau_sched_init(drm); - if (ret) + drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0, + WQ_MAX_ACTIVE); + if (!drm->sched_wq) { + ret = -ENOMEM; goto fail_alloc; + } ret = nouveau_cli_init(drm, "DRM-master", &drm->master); if (ret) - goto fail_sched; + goto fail_wq; ret = nouveau_cli_init(drm, "DRM", &drm->client); if (ret) @@ -658,8 +670,8 @@ nouveau_drm_device_init(struct drm_device *dev) nouveau_cli_fini(&drm->client); fail_master: nouveau_cli_fini(&drm->master); -fail_sched: - nouveau_sched_fini(drm); +fail_wq: + destroy_workqueue(drm->sched_wq); fail_alloc: nvif_parent_dtor(&drm->parent); kfree(drm); @@ -711,10 +723,9 @@ nouveau_drm_device_fini(struct drm_device *dev) } mutex_unlock(&drm->clients_lock); - nouveau_sched_fini(drm); - nouveau_cli_fini(&drm->client); nouveau_cli_fini(&drm->master); + destroy_workqueue(drm->sched_wq); nvif_parent_dtor(&drm->parent); mutex_destroy(&drm->clients_lock); kfree(drm); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 7f7051df84a6..8a6d94c8b163 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -98,7 +98,7 @@ struct nouveau_cli { bool disabled; } uvmm; - struct nouveau_sched_entity sched_entity; + struct nouveau_sched sched; const struct nvif_mclass *mem; @@ -258,6 +258,9 @@ struct nouveau_drm { u64 context_base; } *runl; + /* Workqueue used for channel schedulers. */ + struct workqueue_struct *sched_wq; + /* context for accelerated drm-internal operations */ struct nouveau_channel *cechan; struct nouveau_channel *channel; @@ -298,10 +301,6 @@ struct nouveau_drm { struct mutex lock; bool component_registered; } audio; - - struct drm_gpu_scheduler sched; - struct workqueue_struct *sched_wq; - }; static inline struct nouveau_drm * diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index f8ef7004d133..a179eeb6df09 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -165,6 +165,7 @@ nouveau_exec_job_free(struct nouveau_job *job) { struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + nouveau_job_done(job); nouveau_job_free(job); kfree(exec_job->fence); @@ -184,8 +185,6 @@ nouveau_exec_job_timeout(struct nouveau_job *job) NV_PRINTK(warn, job->cli, "job timeout, channel %d killed!\n", chan->chid); - nouveau_sched_entity_fini(job->entity); - return DRM_GPU_SCHED_STAT_NOMINAL; } @@ -234,7 +233,7 @@ nouveau_exec_job_init(struct nouveau_exec_job **pjob, job->chan = __args->chan; - args.sched_entity = __args->sched_entity; + args.sched = __args->sched; args.file_priv = __args->file_priv; args.in_sync.count = __args->in_sync.count; @@ -388,7 +387,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev, if (ret) goto out; - args.sched_entity = &chan16->sched_entity; + args.sched = &chan16->sched; args.file_priv = file_priv; args.chan = chan; diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.h b/drivers/gpu/drm/nouveau/nouveau_exec.h index 5a8fe1208a44..9b3b151facfd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.h +++ b/drivers/gpu/drm/nouveau/nouveau_exec.h @@ -8,7 +8,7 @@ struct nouveau_exec_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; + struct nouveau_sched *sched; struct nouveau_channel *chan; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index f69f4cbf251b..0f4583f6fcad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -12,30 +12,29 @@ #include "nouveau_abi16.h" #include "nouveau_sched.h" -/* FIXME - * - * We want to make sure that jobs currently executing can't be deferred by - * other jobs competing for the hardware. Otherwise we might end up with job - * timeouts just because of too many clients submitting too many jobs. We don't - * want jobs to time out because of system load, but because of the job being - * too bulky. - * - * For now allow for up to 16 concurrent jobs in flight until we know how many - * rings the hardware can process in parallel. - */ -#define NOUVEAU_SCHED_HW_SUBMISSIONS 16 +#define NOUVEAU_SCHED_HW_SUBMISSIONS 1 #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 +/* Starts at 0, since the DRM scheduler interprets those parameters as (initial) + * index to the run-queue array. + */ +enum nouveau_sched_priority { + NOUVEAU_SCHED_PRIORITY_SINGLE = DRM_SCHED_PRIORITY_MIN, + NOUVEAU_SCHED_PRIORITY_COUNT, +}; + int nouveau_job_init(struct nouveau_job *job, struct nouveau_job_args *args) { - struct nouveau_sched_entity *entity = args->sched_entity; + struct nouveau_sched *sched = args->sched; int ret; + INIT_LIST_HEAD(&job->entry); + job->file_priv = args->file_priv; job->cli = nouveau_cli(args->file_priv); - job->entity = entity; + job->sched = sched; job->sync = args->sync; job->resv_usage = args->resv_usage; @@ -89,7 +88,7 @@ nouveau_job_init(struct nouveau_job *job, } - ret = drm_sched_job_init(&job->base, &entity->base, 1, NULL); + ret = drm_sched_job_init(&job->base, &sched->entity, 1, NULL); if (ret) goto err_free_chains; @@ -108,6 +107,27 @@ nouveau_job_init(struct nouveau_job *job, return ret; } +void +nouveau_job_fini(struct nouveau_job *job) +{ + dma_fence_put(job->done_fence); + drm_sched_job_cleanup(&job->base); + + job->ops->free(job); +} + +void +nouveau_job_done(struct nouveau_job *job) +{ + struct nouveau_sched *sched = job->sched; + + spin_lock(&sched->job.list.lock); + list_del(&job->entry); + spin_unlock(&sched->job.list.lock); + + wake_up(&sched->job.wq); +} + void nouveau_job_free(struct nouveau_job *job) { @@ -117,13 +137,6 @@ nouveau_job_free(struct nouveau_job *job) kfree(job->out_sync.chains); } -void nouveau_job_fini(struct nouveau_job *job) -{ - dma_fence_put(job->done_fence); - drm_sched_job_cleanup(&job->base); - job->ops->free(job); -} - static int sync_find_fence(struct nouveau_job *job, struct drm_nouveau_sync *sync, @@ -261,7 +274,7 @@ nouveau_job_fence_attach(struct nouveau_job *job) int nouveau_job_submit(struct nouveau_job *job) { - struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); + struct nouveau_sched *sched = job->sched; struct dma_fence *done_fence = NULL; struct drm_gpuvm_exec vm_exec = { .vm = &nouveau_cli_uvmm(job->cli)->base, @@ -281,7 +294,7 @@ nouveau_job_submit(struct nouveau_job *job) /* Make sure the job appears on the sched_entity's queue in the same * order as it was submitted. */ - mutex_lock(&entity->mutex); + mutex_lock(&sched->mutex); /* Guarantee we won't fail after the submit() callback returned * successfully. @@ -292,33 +305,16 @@ nouveau_job_submit(struct nouveau_job *job) goto err_cleanup; } + /* Submit was successful; add the job to the schedulers job list. */ + spin_lock(&sched->job.list.lock); + list_add(&job->entry, &sched->job.list.head); + spin_unlock(&sched->job.list.lock); + drm_sched_job_arm(&job->base); job->done_fence = dma_fence_get(&job->base.s_fence->finished); if (job->sync) done_fence = dma_fence_get(job->done_fence); - /* If a sched job depends on a dma-fence from a job from the same GPU - * scheduler instance, but a different scheduler entity, the GPU - * scheduler does only wait for the particular job to be scheduled, - * rather than for the job to fully complete. This is due to the GPU - * scheduler assuming that there is a scheduler instance per ring. - * However, the current implementation, in order to avoid arbitrary - * amounts of kthreads, has a single scheduler instance while scheduler - * entities represent rings. - * - * As a workaround, set the DRM_SCHED_FENCE_DONT_PIPELINE for all - * out-fences in order to force the scheduler to wait for full job - * completion for dependent jobs from different entities and same - * scheduler instance. - * - * There is some work in progress [1] to address the issues of firmware - * schedulers; once it is in-tree the scheduler topology in Nouveau - * should be re-worked accordingly. - * - * [1] https://lore.kernel.org/dri-devel/20230801205103.627779-1-matthew.brost@intel.com/ - */ - set_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &job->done_fence->flags); - if (job->ops->armed_submit) job->ops->armed_submit(job, &vm_exec); @@ -331,7 +327,7 @@ nouveau_job_submit(struct nouveau_job *job) drm_sched_entity_push_job(&job->base); - mutex_unlock(&entity->mutex); + mutex_unlock(&sched->mutex); if (done_fence) { dma_fence_wait(done_fence, true); @@ -341,20 +337,13 @@ nouveau_job_submit(struct nouveau_job *job) return 0; err_cleanup: - mutex_unlock(&entity->mutex); + mutex_unlock(&sched->mutex); nouveau_job_fence_attach_cleanup(job); err: job->state = NOUVEAU_JOB_SUBMIT_FAILED; return ret; } -bool -nouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, - struct work_struct *work) -{ - return queue_work(entity->sched_wq, work); -} - static struct dma_fence * nouveau_job_run(struct nouveau_job *job) { @@ -404,50 +393,82 @@ nouveau_sched_free_job(struct drm_sched_job *sched_job) nouveau_job_fini(job); } -int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, - struct drm_gpu_scheduler *sched, - struct workqueue_struct *sched_wq) -{ - mutex_init(&entity->mutex); - spin_lock_init(&entity->job.list.lock); - INIT_LIST_HEAD(&entity->job.list.head); - init_waitqueue_head(&entity->job.wq); - - entity->sched_wq = sched_wq; - return drm_sched_entity_init(&entity->base, - DRM_SCHED_PRIORITY_NORMAL, - &sched, 1, NULL); -} - -void -nouveau_sched_entity_fini(struct nouveau_sched_entity *entity) -{ - drm_sched_entity_destroy(&entity->base); -} - static const struct drm_sched_backend_ops nouveau_sched_ops = { .run_job = nouveau_sched_run_job, .timedout_job = nouveau_sched_timedout_job, .free_job = nouveau_sched_free_job, }; -int nouveau_sched_init(struct nouveau_drm *drm) +int +nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, + struct workqueue_struct *wq) { - struct drm_gpu_scheduler *sched = &drm->sched; + struct drm_gpu_scheduler *drm_sched = &sched->base; + struct drm_sched_entity *entity = &sched->entity; long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); + int ret; - drm->sched_wq = create_singlethread_workqueue("nouveau_sched_wq"); - if (!drm->sched_wq) - return -ENOMEM; + if (!wq) { + wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE, + current->pid); + if (!wq) + return -ENOMEM; - return drm_sched_init(sched, &nouveau_sched_ops, NULL, - DRM_SCHED_PRIORITY_COUNT, - NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, - NULL, NULL, "nouveau_sched", drm->dev->dev); + sched->wq = wq; + } + + ret = drm_sched_init(drm_sched, &nouveau_sched_ops, wq, + NOUVEAU_SCHED_PRIORITY_COUNT, + NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, + NULL, NULL, "nouveau_sched", drm->dev->dev); + if (ret) + goto fail_wq; + + /* Using DRM_SCHED_PRIORITY_MIN, since that's what we're required to use + * when we want to have a single run-queue only. + * + * It's not documented, but one will find out when trying to use any + * other priority running into faults, because the scheduler uses the + * priority as array index. + * + * Can't use NOUVEAU_SCHED_PRIORITY_SINGLE either, because it's not + * matching the enum type used in drm_sched_entity_init(). + */ + ret = drm_sched_entity_init(entity, DRM_SCHED_PRIORITY_MIN, + &drm_sched, 1, NULL); + if (ret) + goto fail_sched; + + mutex_init(&sched->mutex); + spin_lock_init(&sched->job.list.lock); + INIT_LIST_HEAD(&sched->job.list.head); + init_waitqueue_head(&sched->job.wq); + + return 0; + +fail_sched: + drm_sched_fini(drm_sched); +fail_wq: + if (sched->wq) + destroy_workqueue(sched->wq); + return ret; } -void nouveau_sched_fini(struct nouveau_drm *drm) +void +nouveau_sched_fini(struct nouveau_sched *sched) { - destroy_workqueue(drm->sched_wq); - drm_sched_fini(&drm->sched); + struct drm_gpu_scheduler *drm_sched = &sched->base; + struct drm_sched_entity *entity = &sched->entity; + + rmb(); /* for list_empty to work without lock */ + wait_event(sched->job.wq, list_empty(&sched->job.list.head)); + + drm_sched_entity_fini(entity); + drm_sched_fini(drm_sched); + + /* Destroy workqueue after scheduler tear down, otherwise it might still + * be in use. + */ + if (sched->wq) + destroy_workqueue(sched->wq); } diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index 0f87697dbc9e..23eff4b0f5b2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -26,7 +26,7 @@ enum nouveau_job_state { struct nouveau_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; + struct nouveau_sched *sched; enum dma_resv_usage resv_usage; bool sync; @@ -49,7 +49,8 @@ struct nouveau_job { enum nouveau_job_state state; - struct nouveau_sched_entity *entity; + struct nouveau_sched *sched; + struct list_head entry; struct drm_file *file_priv; struct nouveau_cli *cli; @@ -89,20 +90,17 @@ int nouveau_job_ucopy_syncs(struct nouveau_job_args *args, int nouveau_job_init(struct nouveau_job *job, struct nouveau_job_args *args); +void nouveau_job_fini(struct nouveau_job *job); +int nouveau_job_submit(struct nouveau_job *job); +void nouveau_job_done(struct nouveau_job *job); void nouveau_job_free(struct nouveau_job *job); -int nouveau_job_submit(struct nouveau_job *job); -void nouveau_job_fini(struct nouveau_job *job); - -#define to_nouveau_sched_entity(entity) \ - container_of((entity), struct nouveau_sched_entity, base) - -struct nouveau_sched_entity { - struct drm_sched_entity base; +struct nouveau_sched { + struct drm_gpu_scheduler base; + struct drm_sched_entity entity; + struct workqueue_struct *wq; struct mutex mutex; - struct workqueue_struct *sched_wq; - struct { struct { struct list_head head; @@ -112,15 +110,8 @@ struct nouveau_sched_entity { } job; }; -int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, - struct drm_gpu_scheduler *sched, - struct workqueue_struct *sched_wq); -void nouveau_sched_entity_fini(struct nouveau_sched_entity *entity); - -bool nouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, - struct work_struct *work); - -int nouveau_sched_init(struct nouveau_drm *drm); -void nouveau_sched_fini(struct nouveau_drm *drm); +int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, + struct workqueue_struct *wq); +void nouveau_sched_fini(struct nouveau_sched *sched); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 90e6732ee9b5..46493fcb82fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -963,6 +963,12 @@ nouveau_uvmm_bind_job_free(struct kref *kref) { struct nouveau_uvmm_bind_job *job = container_of(kref, struct nouveau_uvmm_bind_job, kref); + struct bind_job_op *op, *next; + + list_for_each_op_safe(op, next, &job->ops) { + list_del(&op->entry); + kfree(op); + } nouveau_job_free(&job->base); kfree(job); @@ -1004,14 +1010,16 @@ bind_validate_op(struct nouveau_job *job, static void bind_validate_map_sparse(struct nouveau_job *job, u64 addr, u64 range) { - struct nouveau_uvmm_bind_job *bind_job; - struct nouveau_sched_entity *entity = job->entity; + struct nouveau_sched *sched = job->sched; + struct nouveau_job *__job; struct bind_job_op *op; u64 end = addr + range; again: - spin_lock(&entity->job.list.lock); - list_for_each_entry(bind_job, &entity->job.list.head, entry) { + spin_lock(&sched->job.list.lock); + list_for_each_entry(__job, &sched->job.list.head, entry) { + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(__job); + list_for_each_op(op, &bind_job->ops) { if (op->op == OP_UNMAP) { u64 op_addr = op->va.addr; @@ -1019,7 +1027,7 @@ bind_validate_map_sparse(struct nouveau_job *job, u64 addr, u64 range) if (!(end <= op_addr || addr >= op_end)) { nouveau_uvmm_bind_job_get(bind_job); - spin_unlock(&entity->job.list.lock); + spin_unlock(&sched->job.list.lock); wait_for_completion(&bind_job->complete); nouveau_uvmm_bind_job_put(bind_job); goto again; @@ -1027,7 +1035,7 @@ bind_validate_map_sparse(struct nouveau_job *job, u64 addr, u64 range) } } } - spin_unlock(&entity->job.list.lock); + spin_unlock(&sched->job.list.lock); } static int @@ -1183,7 +1191,6 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job, { struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); - struct nouveau_sched_entity *entity = job->entity; struct drm_exec *exec = &vme->exec; struct bind_job_op *op; int ret; @@ -1380,10 +1387,6 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job, } nouveau_uvmm_unlock(uvmm); - spin_lock(&entity->job.list.lock); - list_add(&bind_job->entry, &entity->job.list.head); - spin_unlock(&entity->job.list.lock); - return 0; unwind_continue: @@ -1466,14 +1469,11 @@ nouveau_uvmm_bind_job_run(struct nouveau_job *job) } static void -nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) +nouveau_uvmm_bind_job_cleanup(struct nouveau_job *job) { - struct nouveau_uvmm_bind_job *bind_job = - container_of(work, struct nouveau_uvmm_bind_job, work); - struct nouveau_job *job = &bind_job->base; + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); - struct nouveau_sched_entity *entity = job->entity; - struct bind_job_op *op, *next; + struct bind_job_op *op; list_for_each_op(op, &bind_job->ops) { struct drm_gem_object *obj = op->gem.obj; @@ -1525,38 +1525,17 @@ nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) drm_gem_object_put(obj); } - spin_lock(&entity->job.list.lock); - list_del(&bind_job->entry); - spin_unlock(&entity->job.list.lock); - + nouveau_job_done(job); complete_all(&bind_job->complete); - wake_up(&entity->job.wq); - - /* Remove and free ops after removing the bind job from the job list to - * avoid races against bind_validate_map_sparse(). - */ - list_for_each_op_safe(op, next, &bind_job->ops) { - list_del(&op->entry); - kfree(op); - } nouveau_uvmm_bind_job_put(bind_job); } -static void -nouveau_uvmm_bind_job_free_qwork(struct nouveau_job *job) -{ - struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); - struct nouveau_sched_entity *entity = job->entity; - - nouveau_sched_entity_qwork(entity, &bind_job->work); -} - static struct nouveau_job_ops nouveau_bind_job_ops = { .submit = nouveau_uvmm_bind_job_submit, .armed_submit = nouveau_uvmm_bind_job_armed_submit, .run = nouveau_uvmm_bind_job_run, - .free = nouveau_uvmm_bind_job_free_qwork, + .free = nouveau_uvmm_bind_job_cleanup, }; static int @@ -1617,7 +1596,6 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, return ret; INIT_LIST_HEAD(&job->ops); - INIT_LIST_HEAD(&job->entry); for (i = 0; i < __args->op.count; i++) { ret = bind_job_op_from_uop(&op, &__args->op.s[i]); @@ -1628,9 +1606,8 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, } init_completion(&job->complete); - INIT_WORK(&job->work, nouveau_uvmm_bind_job_free_work_fn); - args.sched_entity = __args->sched_entity; + args.sched = __args->sched; args.file_priv = __args->file_priv; args.in_sync.count = __args->in_sync.count; @@ -1758,7 +1735,7 @@ nouveau_uvmm_ioctl_vm_bind(struct drm_device *dev, if (ret) return ret; - args.sched_entity = &cli->sched_entity; + args.sched = &cli->sched; args.file_priv = file_priv; ret = nouveau_uvmm_vm_bind(&args); @@ -1910,12 +1887,8 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) MA_STATE(mas, &uvmm->region_mt, 0, 0); struct nouveau_uvma_region *reg; struct nouveau_cli *cli = uvmm->vmm.cli; - struct nouveau_sched_entity *entity = &cli->sched_entity; struct drm_gpuva *va, *next; - rmb(); /* for list_empty to work without lock */ - wait_event(entity->job.wq, list_empty(&entity->job.list.head)); - nouveau_uvmm_lock(uvmm); drm_gpuvm_for_each_va_safe(va, next, &uvmm->base) { struct nouveau_uvma *uvma = uvma_from_va(va); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index f0a6d98ace4f..9d3c348581eb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -44,8 +44,6 @@ struct nouveau_uvmm_bind_job { struct nouveau_job base; struct kref kref; - struct list_head entry; - struct work_struct work; struct completion complete; /* struct bind_job_op */ @@ -54,7 +52,7 @@ struct nouveau_uvmm_bind_job { struct nouveau_uvmm_bind_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; + struct nouveau_sched *sched; unsigned int flags; From 46990918f35c1bf6e367cf8e0423e7344fec9fcb Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 14 Nov 2023 01:27:25 +0100 Subject: [PATCH 1419/7721] drm/nouveau: enable dynamic job-flow control Make use of the scheduler's credit limit and scheduler job's credit count to account for the actual size of a job, such that we fill up the ring efficiently. Signed-off-by: Danilo Krummrich Reviewed-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20231114002728.3491-2-dakr@redhat.com --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_exec.c | 4 +++- drivers/gpu/drm/nouveau/nouveau_sched.c | 9 ++++----- drivers/gpu/drm/nouveau/nouveau_sched.h | 3 ++- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 4 +++- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 7542e1787183..a04156ca8390 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -337,7 +337,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; - ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq); + ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq, + chan->chan->dma.ib_max); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 7e5f19153829..6f6c31a9937b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -320,7 +320,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, * locks which indirectly or directly are held for allocations * elsewhere. */ - ret = nouveau_sched_init(&cli->sched, drm, NULL); + ret = nouveau_sched_init(&cli->sched, drm, NULL, 1); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index a179eeb6df09..bc5d71b79ab2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -231,10 +231,12 @@ nouveau_exec_job_init(struct nouveau_exec_job **pjob, } } + args.file_priv = __args->file_priv; job->chan = __args->chan; args.sched = __args->sched; - args.file_priv = __args->file_priv; + /* Plus one to account for the HW fence. */ + args.credits = job->push.count + 1; args.in_sync.count = __args->in_sync.count; args.in_sync.s = __args->in_sync.s; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 0f4583f6fcad..3393647bd944 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -12,7 +12,6 @@ #include "nouveau_abi16.h" #include "nouveau_sched.h" -#define NOUVEAU_SCHED_HW_SUBMISSIONS 1 #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 /* Starts at 0, since the DRM scheduler interprets those parameters as (initial) @@ -85,10 +84,10 @@ nouveau_job_init(struct nouveau_job *job, ret = -ENOMEM; goto err_free_objs; } - } - ret = drm_sched_job_init(&job->base, &sched->entity, 1, NULL); + ret = drm_sched_job_init(&job->base, &sched->entity, + args->credits, NULL); if (ret) goto err_free_chains; @@ -401,7 +400,7 @@ static const struct drm_sched_backend_ops nouveau_sched_ops = { int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, - struct workqueue_struct *wq) + struct workqueue_struct *wq, u32 credit_limit) { struct drm_gpu_scheduler *drm_sched = &sched->base; struct drm_sched_entity *entity = &sched->entity; @@ -419,7 +418,7 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, ret = drm_sched_init(drm_sched, &nouveau_sched_ops, wq, NOUVEAU_SCHED_PRIORITY_COUNT, - NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, + credit_limit, 0, job_hang_limit, NULL, NULL, "nouveau_sched", drm->dev->dev); if (ret) goto fail_wq; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index 23eff4b0f5b2..a6528f5981e6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -27,6 +27,7 @@ enum nouveau_job_state { struct nouveau_job_args { struct drm_file *file_priv; struct nouveau_sched *sched; + u32 credits; enum dma_resv_usage resv_usage; bool sync; @@ -111,7 +112,7 @@ struct nouveau_sched { }; int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, - struct workqueue_struct *wq); + struct workqueue_struct *wq, u32 credit_limit); void nouveau_sched_fini(struct nouveau_sched *sched); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 46493fcb82fd..4b236da79509 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1607,9 +1607,11 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, init_completion(&job->complete); - args.sched = __args->sched; args.file_priv = __args->file_priv; + args.sched = __args->sched; + args.credits = 1; + args.in_sync.count = __args->in_sync.count; args.in_sync.s = __args->in_sync.s; From edbc78a1b74c3d31dabaf3280bcee0356e744ca9 Mon Sep 17 00:00:00 2001 From: Stanley Jhu Date: Fri, 17 Nov 2023 18:38:10 +0800 Subject: [PATCH 1420/7721] scsi: ufs: mediatek: Change the maintainer for MediaTek UFS hooks Change the maintainer of MediaTek UFS hooks to Peter Wang. The original maintainer, Stanley Chu, who could previously be reached at stanley.chu@mediatek.com, has left MediaTek. Update the email address accordingly and list Stanley as reviewer. Cc: Stanley Chu Reviewed-by: Peter Wang Reviewed-by: Macpaul Lin Signed-off-by: Stanley Jhu Link: https://lore.kernel.org/r/20231117103810.527-1-chu.stanley@gmail.com Signed-off-by: Martin K. Petersen --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..b5ac8c4ae434 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22338,7 +22338,8 @@ S: Maintained F: drivers/ufs/host/ufs-exynos* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER MEDIATEK HOOKS -M: Stanley Chu +M: Peter Wang +R: Stanley Jhu L: linux-scsi@vger.kernel.org L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained From 045da3077bc57e587d0ab4cfc8945b76af03d72d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 18 Nov 2023 21:44:43 +0900 Subject: [PATCH 1421/7721] scsi: ufs: core: Make fault injection dynamically configurable per HBA The UFS driver has two driver-specific fault injection mechanisms (trigger_eh and timeout). Each fault injection configuration can only be specified by a module parameter and cannot be reconfigured without reloading the driver. Also, each configuration is common to all HBAs. This change adds the following subdirectories for each UFS HBA when debugfs is enabled: /sys/kernel/debug/ufshcd//timeout_inject /sys/kernel/debug/ufshcd//trigger_eh_inject Each fault injection attribute can be dynamically set per HBA by a corresponding file in these directories. This is tested with QEMU UFS devices. Signed-off-by: Akinobu Mita Link: https://lore.kernel.org/r/20231118124443.1007116-1-akinobu.mita@gmail.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-fault-injection.c | 19 +++++++++++++++---- drivers/ufs/core/ufs-fault-injection.h | 13 +++++++++---- drivers/ufs/core/ufshcd.c | 5 +++-- include/ufs/ufshcd.h | 5 +++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c index 5b1184aac585..169540417079 100644 --- a/drivers/ufs/core/ufs-fault-injection.c +++ b/drivers/ufs/core/ufs-fault-injection.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "ufs-fault-injection.h" static int ufs_fault_get(char *buffer, const struct kernel_param *kp); @@ -59,12 +60,22 @@ static int ufs_fault_set(const char *val, const struct kernel_param *kp) return 0; } -bool ufs_trigger_eh(void) +void ufs_fault_inject_hba_init(struct ufs_hba *hba) { - return should_fail(&ufs_trigger_eh_attr, 1); + hba->trigger_eh_attr = ufs_trigger_eh_attr; + hba->timeout_attr = ufs_timeout_attr; +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + fault_create_debugfs_attr("trigger_eh_inject", hba->debugfs_root, &hba->trigger_eh_attr); + fault_create_debugfs_attr("timeout_inject", hba->debugfs_root, &hba->timeout_attr); +#endif } -bool ufs_fail_completion(void) +bool ufs_trigger_eh(struct ufs_hba *hba) { - return should_fail(&ufs_timeout_attr, 1); + return should_fail(&hba->trigger_eh_attr, 1); +} + +bool ufs_fail_completion(struct ufs_hba *hba) +{ + return should_fail(&hba->timeout_attr, 1); } diff --git a/drivers/ufs/core/ufs-fault-injection.h b/drivers/ufs/core/ufs-fault-injection.h index 6d0cd8e10c87..996a35769781 100644 --- a/drivers/ufs/core/ufs-fault-injection.h +++ b/drivers/ufs/core/ufs-fault-injection.h @@ -7,15 +7,20 @@ #include #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION -bool ufs_trigger_eh(void); -bool ufs_fail_completion(void); +void ufs_fault_inject_hba_init(struct ufs_hba *hba); +bool ufs_trigger_eh(struct ufs_hba *hba); +bool ufs_fail_completion(struct ufs_hba *hba); #else -static inline bool ufs_trigger_eh(void) +static inline void ufs_fault_inject_hba_init(struct ufs_hba *hba) +{ +} + +static inline bool ufs_trigger_eh(struct ufs_hba *hba) { return false; } -static inline bool ufs_fail_completion(void) +static inline bool ufs_fail_completion(struct ufs_hba *hba) { return false; } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8b1031fb0a44..63f0ee117399 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2992,7 +2992,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_send_command(hba, tag, hwq); out: - if (ufs_trigger_eh()) { + if (ufs_trigger_eh(hba)) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); @@ -5649,7 +5649,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) ufshcd_reset_intr_aggr(hba); - if (ufs_fail_completion()) + if (ufs_fail_completion(hba)) return IRQ_HANDLED; /* @@ -9348,6 +9348,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) goto out_disable_vreg; ufs_debugfs_hba_init(hba); + ufs_fault_inject_hba_init(hba); hba->is_powered = true; goto out; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 7f0b2c5599cd..d862c8ddce03 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1057,6 +1058,10 @@ struct ufs_hba { struct dentry *debugfs_root; struct delayed_work debugfs_ee_work; u32 debugfs_ee_rate_limit_ms; +#endif +#ifdef CONFIG_SCSI_UFS_FAULT_INJECTION + struct fault_attr trigger_eh_attr; + struct fault_attr timeout_attr; #endif u32 luns_avail; unsigned int nr_hw_queues; From 0349be31e4ffc79723e46e2e373569567b06347b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Nov 2023 11:33:38 -0800 Subject: [PATCH 1422/7721] scsi: bfa: Use the proper data type for BLIST flags Fix the following sparse warning: drivers/scsi/bfa/bfad_bsg.c:2553:50: sparse: sparse: incorrect type in initializer (different base types) Fixes: 2e5a6c3baccd ("scsi: bfa: Convert bfad_reset_sdev_bflags() from a macro into a function") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311031255.lmSPisIk-lkp@intel.com/ Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231115193338.2261972-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad_bsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 520f9152f3bf..d4ceca2d435e 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2550,7 +2550,7 @@ bfad_iocmd_vf_clr_stats(struct bfad_s *bfad, void *cmd) static void bfad_reset_sdev_bflags(struct bfad_im_port_s *im_port, int lunmask_cfg) { - const u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; + const blist_flags_t scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; struct bfad_itnim_s *itnim; struct scsi_device *sdev; unsigned long flags; From 10b53db2db8dfda84b25833043f2b63123572af6 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Nov 2023 11:33:43 -0800 Subject: [PATCH 1423/7721] scsi: core: Add a precondition check in scsi_eh_scmd_add() Calling scsi_eh_scmd_add() may cause the error handler never to be woken up because this may result in shost->host_failed to become larger than scsi_host_busy(shost). Hence complain if scsi_eh_scmd_add() is called after SCMD_STATE_INFLIGHT has been cleared. Cc: Hannes Reinecke Cc: Damien Le Moal Cc: Mike Christie Cc: John Garry Cc: Ming Lei Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231115193343.2262013-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index c67cdcdc3ba8..1bac12ef238e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -301,6 +301,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) int ret; WARN_ON_ONCE(!shost->ehandler); + WARN_ON_ONCE(!test_bit(SCMD_STATE_INFLIGHT, &scmd->state)); spin_lock_irqsave(shost->host_lock, flags); if (scsi_host_set_state(shost, SHOST_RECOVERY)) { From db80df77025ee0a5e6e089cc2f2b0c4b97867bea Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Nov 2023 11:33:47 -0800 Subject: [PATCH 1424/7721] scsi: ufs: core: Warn if the request tag is truncated ufshcd_prepare_utp_scsi_cmd_upiu() only uses the lowest eight bits of lrbp->task_tag. Issue a runtime warning if this results in truncation. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231115193359.2262044-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 63f0ee117399..f0b837cb0c2b 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2720,6 +2720,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) .command_set_type = UPIU_COMMAND_SET_TYPE_SCSI, }; + WARN_ON_ONCE(ucd_req_ptr->header.task_tag != lrbp->task_tag); + ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); cdb_len = min_t(unsigned short, cmd->cmd_len, UFS_CDB_SIZE); From 6fa21eab82be57a3ad2470fac27b982793805336 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Thu, 23 Nov 2023 21:31:28 +0530 Subject: [PATCH 1425/7721] scsi: mpi3mr: Add support for SAS5116 PCI IDs Add support for Broadcom's SAS5116 IO/RAID controllers PCI IDs. Signed-off-by: Sumit Saxena Link: https://lore.kernel.org/r/20231123160132.4155-2-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 040031eb0c12..a8d7dbf0159a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5430,6 +5430,14 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = { PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID) }, + { + PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, + MPI3_MFGPAGE_DEVID_SAS5116_MPI, PCI_ANY_ID, PCI_ANY_ID) + }, + { + PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, + MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID) + }, { 0 } }; MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table); From c9260ff28ee561fca5f96425c9328a9698e8427b Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Thu, 23 Nov 2023 21:31:29 +0530 Subject: [PATCH 1426/7721] scsi: mpi3mr: Add PCI checks where SAS5116 diverges from SAS4116 Add PCI IDs checks for the cases where SAS5116 diverges from SAS4116 in behavior. Signed-off-by: Sumit Saxena Link: https://lore.kernel.org/r/20231123160132.4155-3-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 3 ++- drivers/scsi/mpi3mr/mpi3mr_os.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index f039f1d98647..0d148c39ebcc 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1892,7 +1892,8 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) reply_qid = qidx + 1; op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; - if (!mrioc->pdev->revision) + if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && + !mrioc->pdev->revision) op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; op_reply_q->ci = 0; op_reply_q->ephase = 1; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index a8d7dbf0159a..91a22e6e5c3f 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5101,7 +5101,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i], MPI3MR_HOSTTAG_EVTACKCMD_MIN + i); - if (pdev->revision) + if ((pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && + !pdev->revision) + mrioc->enable_segqueue = false; + else mrioc->enable_segqueue = true; init_waitqueue_head(&mrioc->reset_waitq); From cb5b60894602b12a63d3e08be88eaf26b2603c19 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Thu, 23 Nov 2023 21:31:30 +0530 Subject: [PATCH 1427/7721] scsi: mpi3mr: Increase maximum number of PHYs to 64 from 32 SAS5116 controllers supports maximum 48 physical PHYs. Modify driver to accommodate up to 64 PHYs (though current need is to support 48 PHYs). Signed-off-by: Sumit Saxena Link: https://lore.kernel.org/r/20231123160132.4155-4-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 2 +- drivers/scsi/mpi3mr/mpi3mr_transport.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index ae98d15c30b1..7658e8aaadbe 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -506,7 +506,7 @@ struct mpi3mr_sas_port { u8 num_phys; u8 marked_responding; int lowest_phy; - u32 phy_mask; + u64 phy_mask; struct mpi3mr_hba_port *hba_port; struct sas_identify remote_identify; struct sas_rphy *rphy; diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index 82b55e955730..c0c8ab586957 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -1587,7 +1587,7 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, */ struct host_port { u64 sas_address; - u32 phy_mask; + u64 phy_mask; u16 handle; u8 iounit_port_id; u8 used; @@ -1611,7 +1611,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, struct mpi3mr_sas_port *mr_sas_port) { struct mpi3mr_sas_phy *mr_sas_phy; - u32 phy_mask_xor; + u64 phy_mask_xor; u64 phys_to_be_added, phys_to_be_removed; int i; @@ -1619,7 +1619,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, mr_sas_port->marked_responding = 1; dev_info(&mr_sas_port->port->dev, - "sas_address(0x%016llx), old: port_id %d phy_mask 0x%x, new: port_id %d phy_mask:0x%x\n", + "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n", mr_sas_port->remote_identify.sas_address, mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask, h_port->iounit_port_id, h_port->phy_mask); @@ -1637,7 +1637,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, * if these phys are previously registered with another port * then delete these phys from that port first. */ - for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u32)) { + for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) { mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port) mpi3mr_del_phy_from_an_existing_port(mrioc, @@ -1649,7 +1649,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, } /* Delete the phys which are not part of current mr_sas_port's port. */ - for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u32)) { + for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) { mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port) mpi3mr_del_phy_from_an_existing_port(mrioc, @@ -1671,7 +1671,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, void mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) { - struct host_port h_port[32]; + struct host_port h_port[64]; int i, j, found, host_port_count = 0, port_idx; u16 sz, attached_handle, ioc_status; struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; @@ -1742,7 +1742,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list, port_list) { ioc_info(mrioc, - "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n", + "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n", mr_sas_port->hba_port->port_id, mr_sas_port->remote_identify.sas_address, mr_sas_port->phy_mask, mr_sas_port->lowest_phy); @@ -1751,7 +1751,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) ioc_info(mrioc, "Host port details after reset\n"); for (i = 0; i < host_port_count; i++) { ioc_info(mrioc, - "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n", + "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n", h_port[i].iounit_port_id, h_port[i].sas_address, h_port[i].phy_mask, h_port[i].lowest_phy); } From 1193a89d2b6d2673fc2d1f27f8873f02e91e2aab Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Thu, 23 Nov 2023 21:31:31 +0530 Subject: [PATCH 1428/7721] scsi: mpi3mr: Add support for status reply descriptor Inform controller firmware that driver supports status reply descriptor. Signed-off-by: Sumit Saxena Link: https://lore.kernel.org/r/20231123160132.4155-5-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 1 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index 1e4a60fc655f..0cb24fc03620 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -28,6 +28,7 @@ struct mpi3_ioc_init_request { __le64 driver_information_address; }; +#define MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED (0x04) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 0d148c39ebcc..1ad2f88e0528 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3194,6 +3194,9 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) current_time = ktime_get_real(); iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); + iocinit_req.msg_flags |= + MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED; + init_completion(&mrioc->init_cmds.done); retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, sizeof(iocinit_req), 1); From b4d94164ff321f271c9c2d6c07676ce58f0a2c28 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Thu, 23 Nov 2023 21:31:32 +0530 Subject: [PATCH 1429/7721] scsi: mpi3mr: driver version upgrade to 8.5.0.0.50 Update driver version to 8.5.0.0.50. Signed-off-by: Sumit Saxena Link: https://lore.kernel.org/r/20231123160132.4155-6-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 7658e8aaadbe..4f49f8396309 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -55,8 +55,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.5.0.0.0" -#define MPI3MR_DRIVER_RELDATE "24-July-2023" +#define MPI3MR_DRIVER_VERSION "8.5.0.0.50" +#define MPI3MR_DRIVER_RELDATE "22-November-2023" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" From f38d4eda25e29f4690545200f79bee202cc05626 Mon Sep 17 00:00:00 2001 From: Abhinav Singh Date: Fri, 10 Nov 2023 03:20:49 +0530 Subject: [PATCH 1430/7721] scsi: dc395x: Fix warning using plain integer as NULL Sparse static analysis tool generates a warning with this message "Using plain integer as NULL pointer". Fix it. Signed-off-by: Abhinav Singh Link: https://lore.kernel.org/r/20231109215049.1466431-1-singhabhinav9051571833@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index c8e86f8a631e..d108a86e196e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1366,7 +1366,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, "command while another command (0x%p) is active.", srb->cmd, acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd : 0); + acb->active_dcb->active_srb->cmd : NULL); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { From a066f906ba396ab00d4af19fc5fad42b2605582a Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Wed, 22 Nov 2023 14:52:43 +0100 Subject: [PATCH 1431/7721] firmware_loader: Expand Firmware upload error codes with firmware invalid error No error code are available to signal an invalid firmware content. Drivers that can check the firmware content validity can not return this specific failure to the user-space Expand the firmware error code with an additional code: - "firmware invalid" code which can be used when the provided firmware is invalid Sync lib/test_firmware.c file accordingly. Acked-by: Luis Chamberlain Acked-by: Greg Kroah-Hartman Signed-off-by: Kory Maincent Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231122-feature_firmware_error_code-v3-1-04ec753afb71@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/base/firmware_loader/sysfs_upload.c | 1 + include/linux/firmware.h | 2 ++ lib/test_firmware.c | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index a0af8f5f13d8..829270067d16 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -27,6 +27,7 @@ static const char * const fw_upload_err_str[] = { [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", + [FW_UPLOAD_ERR_FW_INVALID] = "firmware-invalid", }; static const char *fw_upload_progress(struct device *dev, diff --git a/include/linux/firmware.h b/include/linux/firmware.h index de7fea3bca51..0311858b46ce 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -27,6 +27,7 @@ struct firmware { * @FW_UPLOAD_ERR_INVALID_SIZE: invalid firmware image size * @FW_UPLOAD_ERR_RW_ERROR: read or write to HW failed, see kernel log * @FW_UPLOAD_ERR_WEAROUT: FLASH device is approaching wear-out, wait & retry + * @FW_UPLOAD_ERR_FW_INVALID: invalid firmware file * @FW_UPLOAD_ERR_MAX: Maximum error code marker */ enum fw_upload_err { @@ -38,6 +39,7 @@ enum fw_upload_err { FW_UPLOAD_ERR_INVALID_SIZE, FW_UPLOAD_ERR_RW_ERROR, FW_UPLOAD_ERR_WEAROUT, + FW_UPLOAD_ERR_FW_INVALID, FW_UPLOAD_ERR_MAX }; diff --git a/lib/test_firmware.c b/lib/test_firmware.c index add4699fc6cd..9cfdcd6d21db 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -1132,6 +1132,7 @@ static const char * const fw_upload_err_str[] = { [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", + [FW_UPLOAD_ERR_FW_INVALID] = "firmware-invalid", }; static void upload_err_inject_error(struct test_firmware_upload *tst, From 14ef4b001ae77bd6bf8c22b3de255701c23591eb Mon Sep 17 00:00:00 2001 From: ching Huang Date: Mon, 2 Oct 2023 17:42:19 +0800 Subject: [PATCH 1432/7721] scsi: arcmsr: Support new RAID controller ARC-1688 Add support for new Areca RAID controller ARC-1688 Signed-off-by: ching Huang Link: https://lore.kernel.org/r/110bdc873497d3d5e090b908fb159b6155bb3a2b.camel@areca.com.tw Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 23 ++++++++ drivers/scsi/arcmsr/arcmsr_hba.c | 90 +++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index ed8d9319862a..8f20d9cc5377 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -818,6 +818,23 @@ typedef struct deliver_completeQ { uint16_t cmdLMID; // reserved (0) uint16_t cmdFlag2; // reserved (0) } DeliverQ, CompletionQ, *pDeliver_Q, *pCompletion_Q; + +#define ARCMSR_XOR_SEG_SIZE (1024 * 1024) +struct HostRamBuf { + uint32_t hrbSignature; // must be "HRBS" + uint32_t hrbSize; // total sg size, be multiples of MB + uint32_t hrbRes[2]; // reserved, must be set to 0 +}; +struct Xor_sg { + dma_addr_t xorPhys; + uint64_t xorBufLen; +}; +struct XorHandle { + dma_addr_t xorPhys; + uint64_t xorBufLen; + void *xorVirt; +}; + /* ******************************************************************************* ** Adapter Control Block @@ -929,6 +946,7 @@ struct AdapterControlBlock char firm_model[12]; char firm_version[20]; char device_map[20]; /*21,84-99*/ + uint32_t firm_PicStatus; struct work_struct arcmsr_do_message_isr_bh; struct timer_list eternal_timer; unsigned short fw_flag; @@ -937,6 +955,7 @@ struct AdapterControlBlock #define FW_DEADLOCK 0x0010 uint32_t maxOutstanding; int vector_count; + int xor_mega; uint32_t maxFreeCCB; struct timer_list refresh_timer; uint32_t doneq_index; @@ -946,6 +965,10 @@ struct AdapterControlBlock uint32_t completionQ_entry; pCompletion_Q pCompletionQ; uint32_t completeQ_size; + void *xorVirt; + dma_addr_t xorPhys; + unsigned int init2cfg_size; + unsigned int xorVirtOffset; };/* HW_DEVICE_EXTENSION */ /* ******************************************************************************* diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index a66221c3b72f..092c704aa735 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -747,6 +747,57 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) return rtn; } +static int arcmsr_alloc_xor_buffer(struct AdapterControlBlock *acb) +{ + int rc = 0; + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle; + int i, xor_ram; + struct Xor_sg *pXorPhys; + void **pXorVirt; + struct HostRamBuf *pRamBuf; + + // allocate 1 MB * N physically continuous memory for XOR engine. + xor_ram = (acb->firm_PicStatus >> 24) & 0x0f; + acb->xor_mega = (xor_ram - 1) * 32 + 128 + 3; + acb->init2cfg_size = sizeof(struct HostRamBuf) + + (sizeof(struct XorHandle) * acb->xor_mega); + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->init2cfg_size, + &dma_coherent_handle, GFP_KERNEL); + acb->xorVirt = dma_coherent; + acb->xorPhys = dma_coherent_handle; + pXorPhys = (struct Xor_sg *)((unsigned long)dma_coherent + + sizeof(struct HostRamBuf)); + acb->xorVirtOffset = sizeof(struct HostRamBuf) + + (sizeof(struct Xor_sg) * acb->xor_mega); + pXorVirt = (void **)((unsigned long)dma_coherent + + (unsigned long)acb->xorVirtOffset); + for (i = 0; i < acb->xor_mega; i++) { + dma_coherent = dma_alloc_coherent(&pdev->dev, + ARCMSR_XOR_SEG_SIZE, + &dma_coherent_handle, GFP_KERNEL); + if (dma_coherent) { + pXorPhys->xorPhys = dma_coherent_handle; + pXorPhys->xorBufLen = ARCMSR_XOR_SEG_SIZE; + *pXorVirt = dma_coherent; + pXorPhys++; + pXorVirt++; + } else { + pr_info("arcmsr%d: alloc max XOR buffer = 0x%x MB\n", + acb->host->host_no, i); + rc = -ENOMEM; + break; + } + } + pRamBuf = (struct HostRamBuf *)acb->xorVirt; + pRamBuf->hrbSignature = 0x53425248; //HRBS + pRamBuf->hrbSize = i * ARCMSR_XOR_SEG_SIZE; + pRamBuf->hrbRes[0] = 0; + pRamBuf->hrbRes[1] = 0; + return rc; +} + static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; @@ -836,7 +887,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ); acb->doneq_index = 0; break; - } + } + if ((acb->firm_PicStatus >> 24) & 0x0f) { + if (arcmsr_alloc_xor_buffer(acb)) + return -ENOMEM; + } return 0; } @@ -2022,6 +2077,29 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) { + if (acb->xor_mega) { + struct Xor_sg *pXorPhys; + void **pXorVirt; + int i; + + pXorPhys = (struct Xor_sg *)(acb->xorVirt + + sizeof(struct HostRamBuf)); + pXorVirt = (void **)((unsigned long)acb->xorVirt + + (unsigned long)acb->xorVirtOffset); + for (i = 0; i < acb->xor_mega; i++) { + if (pXorPhys->xorPhys) { + dma_free_coherent(&acb->pdev->dev, + ARCMSR_XOR_SEG_SIZE, + *pXorVirt, pXorPhys->xorPhys); + pXorPhys->xorPhys = 0; + *pXorVirt = NULL; + } + pXorPhys++; + pXorVirt++; + } + dma_free_coherent(&acb->pdev->dev, acb->init2cfg_size, + acb->xorVirt, acb->xorPhys); + } dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); } @@ -3309,6 +3387,10 @@ static void arcmsr_get_adapter_config(struct AdapterControlBlock *pACB, uint32_t pACB->firm_sdram_size = readl(&rwbuffer[3]); pACB->firm_hd_channels = readl(&rwbuffer[4]); pACB->firm_cfg_version = readl(&rwbuffer[25]); + if (pACB->adapter_type == ACB_ADAPTER_TYPE_F) + pACB->firm_PicStatus = readl(&rwbuffer[30]); + else + pACB->firm_PicStatus = 0; pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", pACB->host->host_no, pACB->firm_model, @@ -4096,6 +4178,12 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) acb->msgcode_rwbuffer[5] = lower_32_bits(acb->dma_coherent_handle2); acb->msgcode_rwbuffer[6] = upper_32_bits(acb->dma_coherent_handle2); acb->msgcode_rwbuffer[7] = acb->completeQ_size; + if (acb->xor_mega) { + acb->msgcode_rwbuffer[8] = 0x455AA; //Linux init 2 + acb->msgcode_rwbuffer[9] = 0; + acb->msgcode_rwbuffer[10] = lower_32_bits(acb->xorPhys); + acb->msgcode_rwbuffer[11] = upper_32_bits(acb->xorPhys); + } writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE; writel(acb->out_doorbell, ®->iobound_doorbell); From 41c8a1a1e90fa4721f856bf3cf71211fd16d6434 Mon Sep 17 00:00:00 2001 From: ching Huang Date: Mon, 2 Oct 2023 17:50:27 +0800 Subject: [PATCH 1433/7721] scsi: arcmsr: Support new PCI device IDs 1883 and 1886 Add support for Areca RAID controllers with PCI device IDs 1883 and 1886. Signed-off-by: ching Huang Link: https://lore.kernel.org/r/7732e743eaad57681b1552eec9c6a86c76dbe459.camel@areca.com.tw Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 4 ++++ drivers/scsi/arcmsr/arcmsr_hba.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 8f20d9cc5377..2f80a6acbb89 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -78,9 +78,13 @@ struct device_attribute; #ifndef PCI_DEVICE_ID_ARECA_1203 #define PCI_DEVICE_ID_ARECA_1203 0x1203 #endif +#ifndef PCI_DEVICE_ID_ARECA_1883 +#define PCI_DEVICE_ID_ARECA_1883 0x1883 +#endif #ifndef PCI_DEVICE_ID_ARECA_1884 #define PCI_DEVICE_ID_ARECA_1884 0x1884 #endif +#define PCI_DEVICE_ID_ARECA_1886_0 0x1886 #define PCI_DEVICE_ID_ARECA_1886 0x188A #define ARCMSR_HOURS (1000 * 60 * 60 * 4) #define ARCMSR_MINUTES (1000 * 60 * 60) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 092c704aa735..ad227e6cb10e 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -214,8 +214,12 @@ static struct pci_device_id arcmsr_device_id_table[] = { .driver_data = ACB_ADAPTER_TYPE_A}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880), .driver_data = ACB_ADAPTER_TYPE_C}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1883), + .driver_data = ACB_ADAPTER_TYPE_C}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1884), .driver_data = ACB_ADAPTER_TYPE_E}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1886_0), + .driver_data = ACB_ADAPTER_TYPE_F}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1886), .driver_data = ACB_ADAPTER_TYPE_F}, {0, 0}, /* Terminating entry */ @@ -4794,9 +4798,11 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1680: case PCI_DEVICE_ID_ARECA_1681: case PCI_DEVICE_ID_ARECA_1880: + case PCI_DEVICE_ID_ARECA_1883: case PCI_DEVICE_ID_ARECA_1884: type = "SAS/SATA"; break; + case PCI_DEVICE_ID_ARECA_1886_0: case PCI_DEVICE_ID_ARECA_1886: type = "NVMe/SAS/SATA"; break; From 56610811cccd04c94c9d347f271cdff63c9dc19d Mon Sep 17 00:00:00 2001 From: ching Huang Date: Mon, 2 Oct 2023 17:54:20 +0800 Subject: [PATCH 1434/7721] scsi: arcmsr: Update driver version to v1.51.00.14-20230915 Signed-off-by: ching Huang Link: https://lore.kernel.org/r/514898a472dfdf0502afe27d127ed5145a1fb915.camel@areca.com.tw Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 2f80a6acbb89..12c4148fe16f 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -50,7 +50,7 @@ struct device_attribute; #define ARCMSR_MAX_OUTSTANDING_CMD 1024 #define ARCMSR_DEFAULT_OUTSTANDING_CMD 128 #define ARCMSR_MIN_OUTSTANDING_CMD 32 -#define ARCMSR_DRIVER_VERSION "v1.50.00.13-20230206" +#define ARCMSR_DRIVER_VERSION "v1.51.00.14-20230915" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 From 2bbe6ab2be53858507f11f99f856846d04765ae3 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 22 Nov 2023 23:58:53 -0500 Subject: [PATCH 1435/7721] drm/sched: Fix bounds limiting when given a malformed entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we're given a malformed entity in drm_sched_entity_init()--shouldn't happen, but we verify--with out-of-bounds priority value, we set it to an allowed value. Fix the expression which sets this limit. Signed-off-by: Luben Tuikov Fixes: 56e449603f0ac5 ("drm/sched: Convert the GPU scheduler to variable number of run-queues") Link: https://patchwork.freedesktop.org/patch/msgid/20231123122422.167832-2-ltuikov89@gmail.com Reviewed-by: Christian König Link: https://lore.kernel.org/r/dbb91dbe-ef77-4d79-aaf9-2adb171c1d7a@amd.com --- drivers/gpu/drm/scheduler/sched_entity.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 4d42b1e4daa6..ee645d38e98d 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -81,12 +81,15 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, */ pr_warn("%s: called with uninitialized scheduler\n", __func__); } else if (num_sched_list) { - /* The "priority" of an entity cannot exceed the number - * of run-queues of a scheduler. + /* The "priority" of an entity cannot exceed the number of run-queues of a + * scheduler. Protect against num_rqs being 0, by converting to signed. */ - if (entity->priority >= sched_list[0]->num_rqs) - entity->priority = max_t(u32, sched_list[0]->num_rqs, - DRM_SCHED_PRIORITY_MIN); + if (entity->priority >= sched_list[0]->num_rqs) { + drm_err(sched_list[0], "entity with out-of-bounds priority:%u num_rqs:%u\n", + entity->priority, sched_list[0]->num_rqs); + entity->priority = max_t(s32, (s32) sched_list[0]->num_rqs - 1, + (s32) DRM_SCHED_PRIORITY_MIN); + } entity->rq = sched_list[0]->sched_rq[entity->priority]; } From fe375c74806dbd30b00ec038a80a5b7bf4653ab7 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Tue, 14 Nov 2023 20:40:58 -0500 Subject: [PATCH 1436/7721] drm/sched: Rename priority MIN to LOW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename DRM_SCHED_PRIORITY_MIN to DRM_SCHED_PRIORITY_LOW. This mirrors DRM_SCHED_PRIORITY_HIGH, for a list of DRM scheduler priorities in ascending order, DRM_SCHED_PRIORITY_LOW, DRM_SCHED_PRIORITY_NORMAL, DRM_SCHED_PRIORITY_HIGH, DRM_SCHED_PRIORITY_KERNEL. Cc: Rob Clark Cc: Abhinav Kumar Cc: Dmitry Baryshkov Cc: Danilo Krummrich Cc: Alex Deucher Cc: Christian König Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Luben Tuikov Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20231124052752.6915-5-ltuikov89@gmail.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- drivers/gpu/drm/msm/msm_gpu.h | 2 +- drivers/gpu/drm/scheduler/sched_entity.c | 2 +- drivers/gpu/drm/scheduler/sched_main.c | 10 +++++----- include/drm/gpu_scheduler.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index e2ae9ba147ba..5cb33ac99f70 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -73,10 +73,10 @@ amdgpu_ctx_to_drm_sched_prio(int32_t ctx_prio) return DRM_SCHED_PRIORITY_NORMAL; case AMDGPU_CTX_PRIORITY_VERY_LOW: - return DRM_SCHED_PRIORITY_MIN; + return DRM_SCHED_PRIORITY_LOW; case AMDGPU_CTX_PRIORITY_LOW: - return DRM_SCHED_PRIORITY_MIN; + return DRM_SCHED_PRIORITY_LOW; case AMDGPU_CTX_PRIORITY_NORMAL: return DRM_SCHED_PRIORITY_NORMAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 62bb7fc7448a..1a25931607c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -325,7 +325,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) int i; /* Signal all jobs not yet scheduled */ - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); list_for_each_entry(s_entity, &rq->entities, list) { diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 4252e3839fbc..eb0c97433e5f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -347,7 +347,7 @@ struct msm_gpu_perfcntr { * DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some * cases, so we don't use it (no need for kernel generated jobs). */ -#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_MIN) +#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_LOW) /** * struct msm_file_private - per-drm_file context diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index ee645d38e98d..dd2b8f777f51 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -88,7 +88,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, drm_err(sched_list[0], "entity with out-of-bounds priority:%u num_rqs:%u\n", entity->priority, sched_list[0]->num_rqs); entity->priority = max_t(s32, (s32) sched_list[0]->num_rqs - 1, - (s32) DRM_SCHED_PRIORITY_MIN); + (s32) DRM_SCHED_PRIORITY_LOW); } entity->rq = sched_list[0]->sched_rq[entity->priority]; } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 044a8c4875ba..b6d7bc49ff6e 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1052,7 +1052,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) int i; /* Kernel run queue has higher priority than normal run queue*/ - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ? drm_sched_rq_select_entity_fifo(sched, sched->sched_rq[i]) : drm_sched_rq_select_entity_rr(sched, sched->sched_rq[i]); @@ -1291,7 +1291,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, if (!sched->sched_rq) goto Out_free; sched->num_rqs = num_rqs; - for (i = DRM_SCHED_PRIORITY_MIN; i < sched->num_rqs; i++) { + for (i = DRM_SCHED_PRIORITY_LOW; i < sched->num_rqs; i++) { sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL); if (!sched->sched_rq[i]) goto Out_unroll; @@ -1312,7 +1312,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->ready = true; return 0; Out_unroll: - for (--i ; i >= DRM_SCHED_PRIORITY_MIN; i--) + for (--i ; i >= DRM_SCHED_PRIORITY_LOW; i--) kfree(sched->sched_rq[i]); Out_free: kfree(sched->sched_rq); @@ -1338,7 +1338,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched) drm_sched_wqueue_stop(sched); - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); @@ -1390,7 +1390,7 @@ void drm_sched_increase_karma(struct drm_sched_job *bad) if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) { atomic_inc(&bad->karma); - for (i = DRM_SCHED_PRIORITY_MIN; + for (i = DRM_SCHED_PRIORITY_LOW; i < min_t(typeof(sched->num_rqs), sched->num_rqs, DRM_SCHED_PRIORITY_KERNEL); i++) { struct drm_sched_rq *rq = sched->sched_rq[i]; diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 9a50348bd5c0..d8e2d84d9223 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -63,7 +63,7 @@ struct drm_file; * to an array, and as such should start at 0. */ enum drm_sched_priority { - DRM_SCHED_PRIORITY_MIN, + DRM_SCHED_PRIORITY_LOW, DRM_SCHED_PRIORITY_NORMAL, DRM_SCHED_PRIORITY_HIGH, DRM_SCHED_PRIORITY_KERNEL, From 38f922a563aac3148ac73e73689805917f034cb5 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 22 Nov 2023 22:08:48 -0500 Subject: [PATCH 1437/7721] drm/sched: Reverse run-queue priority enumeration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverse run-queue priority enumeration such that the higest priority is now 0, and for each consecutive integer the prioirty diminishes. Run-queues correspond to priorities. To an external observer a scheduler created with a single run-queue, and another created with DRM_SCHED_PRIORITY_COUNT number of run-queues, should always schedule sched->sched_rq[0] with the same "priority", as that index run-queue exists in both schedulers, i.e. a scheduler with one run-queue or many. This patch makes it so. In other words, the "priority" of sched->sched_rq[n], n >= 0, is the same for any scheduler created with any allowable number of run-queues (priorities), 0 to DRM_SCHED_PRIORITY_COUNT. Cc: Rob Clark Cc: Abhinav Kumar Cc: Dmitry Baryshkov Cc: Danilo Krummrich Cc: Alex Deucher Cc: Christian König Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Luben Tuikov Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20231124052752.6915-6-ltuikov89@gmail.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- drivers/gpu/drm/msm/msm_gpu.h | 2 +- drivers/gpu/drm/scheduler/sched_entity.c | 5 +++-- drivers/gpu/drm/scheduler/sched_main.c | 15 +++++++-------- include/drm/gpu_scheduler.h | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 1a25931607c5..71a5cf37b472 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -325,7 +325,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) int i; /* Signal all jobs not yet scheduled */ - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { + for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); list_for_each_entry(s_entity, &rq->entities, list) { diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index eb0c97433e5f..2bfcb222e353 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -347,7 +347,7 @@ struct msm_gpu_perfcntr { * DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some * cases, so we don't use it (no need for kernel generated jobs). */ -#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_LOW) +#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_LOW - DRM_SCHED_PRIORITY_HIGH) /** * struct msm_file_private - per-drm_file context diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index dd2b8f777f51..3c4f5a392b06 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -82,13 +82,14 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, pr_warn("%s: called with uninitialized scheduler\n", __func__); } else if (num_sched_list) { /* The "priority" of an entity cannot exceed the number of run-queues of a - * scheduler. Protect against num_rqs being 0, by converting to signed. + * scheduler. Protect against num_rqs being 0, by converting to signed. Choose + * the lowest priority available. */ if (entity->priority >= sched_list[0]->num_rqs) { drm_err(sched_list[0], "entity with out-of-bounds priority:%u num_rqs:%u\n", entity->priority, sched_list[0]->num_rqs); entity->priority = max_t(s32, (s32) sched_list[0]->num_rqs - 1, - (s32) DRM_SCHED_PRIORITY_LOW); + (s32) DRM_SCHED_PRIORITY_KERNEL); } entity->rq = sched_list[0]->sched_rq[entity->priority]; } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index b6d7bc49ff6e..682aebe96db7 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1051,8 +1051,9 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) struct drm_sched_entity *entity; int i; - /* Kernel run queue has higher priority than normal run queue*/ - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { + /* Start with the highest priority. + */ + for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ? drm_sched_rq_select_entity_fifo(sched, sched->sched_rq[i]) : drm_sched_rq_select_entity_rr(sched, sched->sched_rq[i]); @@ -1291,7 +1292,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, if (!sched->sched_rq) goto Out_free; sched->num_rqs = num_rqs; - for (i = DRM_SCHED_PRIORITY_LOW; i < sched->num_rqs; i++) { + for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL); if (!sched->sched_rq[i]) goto Out_unroll; @@ -1312,7 +1313,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->ready = true; return 0; Out_unroll: - for (--i ; i >= DRM_SCHED_PRIORITY_LOW; i--) + for (--i ; i >= DRM_SCHED_PRIORITY_KERNEL; i--) kfree(sched->sched_rq[i]); Out_free: kfree(sched->sched_rq); @@ -1338,7 +1339,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched) drm_sched_wqueue_stop(sched); - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_LOW; i--) { + for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); @@ -1390,9 +1391,7 @@ void drm_sched_increase_karma(struct drm_sched_job *bad) if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) { atomic_inc(&bad->karma); - for (i = DRM_SCHED_PRIORITY_LOW; - i < min_t(typeof(sched->num_rqs), sched->num_rqs, DRM_SCHED_PRIORITY_KERNEL); - i++) { + for (i = DRM_SCHED_PRIORITY_HIGH; i < sched->num_rqs; i++) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index d8e2d84d9223..5acc64954a88 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -63,10 +63,10 @@ struct drm_file; * to an array, and as such should start at 0. */ enum drm_sched_priority { - DRM_SCHED_PRIORITY_LOW, - DRM_SCHED_PRIORITY_NORMAL, - DRM_SCHED_PRIORITY_HIGH, DRM_SCHED_PRIORITY_KERNEL, + DRM_SCHED_PRIORITY_HIGH, + DRM_SCHED_PRIORITY_NORMAL, + DRM_SCHED_PRIORITY_LOW, DRM_SCHED_PRIORITY_COUNT }; From b31559f8e471f402cd71117f35b9cde52d192138 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Nov 2023 12:35:37 -0500 Subject: [PATCH 1438/7721] coda_flag_children(): cope with dentries turning negative ->d_lock on parent does not stabilize ->d_inode of child. We don't do much with that inode in there, but we need at least to avoid struct inode getting freed under us... [rcu_read_lock() is not needed here, since parent's ->d_lock provides an rcu-critical area] Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/coda/cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 3b8c4513118f..d6254cf9f397 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -94,12 +94,12 @@ static void coda_flag_children(struct dentry *parent, int flag) spin_lock(&parent->d_lock); list_for_each_entry(de, &parent->d_subdirs, d_child) { + struct inode *inode = d_inode_rcu(de); /* don't know what to do with negative dentries */ - if (d_inode(de) ) - coda_flag_inode(d_inode(de), flag); + if (inode) + coda_flag_inode(inode, flag); } spin_unlock(&parent->d_lock); - return; } void coda_flag_inode_children(struct inode *inode, int flag) From da549bdd15c295c24b2ee7ffe7ad0f3877fa8a87 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Nov 2023 02:00:39 -0500 Subject: [PATCH 1439/7721] dentry: switch the lists of children to hlist Saves a pointer per struct dentry and actually makes the things less clumsy. Cleaned the d_walk() and dcache_readdir() a bit by use of hlist_for_... iterators. A couple of new helpers - d_first_child() and d_next_sibling(), to make the expressions less awful. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- Documentation/filesystems/porting.rst | 9 +++ arch/powerpc/platforms/cell/spufs/inode.c | 5 +- fs/afs/dynroot.c | 5 +- fs/autofs/expire.c | 7 +-- fs/ceph/dir.c | 2 +- fs/ceph/mds_client.c | 2 +- fs/coda/cache.c | 2 +- fs/dcache.c | 76 +++++++++++------------ fs/libfs.c | 45 +++++++------- fs/notify/fsnotify.c | 2 +- fs/tracefs/inode.c | 34 +++++----- include/linux/dcache.h | 20 ++++-- 12 files changed, 108 insertions(+), 101 deletions(-) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 878e72b2f8b7..331405f4b29f 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1061,3 +1061,12 @@ export_operations ->encode_fh() no longer has a default implementation to encode FILEID_INO32_GEN* file handles. Filesystems that used the default implementation may use the generic helper generic_encode_ino32_fh() explicitly. + +--- + +**mandatory** + +The list of children anchored in parent dentry got turned into hlist now. +Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child +for anchor/entries resp.), so any affected places will be immediately caught +by compiler. diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 10c1320adfd0..030de2b8c145 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode) static void spufs_prune_dir(struct dentry *dir) { - struct dentry *dentry, *tmp; + struct dentry *dentry; + struct hlist_node *n; inode_lock(d_inode(dir)); - list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { + hlist_for_each_entry_safe(dentry, n, &dir->d_children, d_sib) { spin_lock(&dentry->d_lock); if (simple_positive(dentry)) { dget_dlock(dentry); diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c index 4d04ef2d3ae7..fe45462834cc 100644 --- a/fs/afs/dynroot.c +++ b/fs/afs/dynroot.c @@ -370,7 +370,7 @@ int afs_dynroot_populate(struct super_block *sb) void afs_dynroot_depopulate(struct super_block *sb) { struct afs_net *net = afs_sb2net(sb); - struct dentry *root = sb->s_root, *subdir, *tmp; + struct dentry *root = sb->s_root, *subdir; /* Prevent more subdirs from being created */ mutex_lock(&net->proc_cells_lock); @@ -379,10 +379,11 @@ void afs_dynroot_depopulate(struct super_block *sb) mutex_unlock(&net->proc_cells_lock); if (root) { + struct hlist_node *n; inode_lock(root->d_inode); /* Remove all the pins for dirs created for manually added cells */ - list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { + hlist_for_each_entry_safe(subdir, n, &root->d_children, d_sib) { if (subdir->d_fsdata) { subdir->d_fsdata = NULL; dput(subdir); diff --git a/fs/autofs/expire.c b/fs/autofs/expire.c index 038b3d2d9f57..39d8c84c16f4 100644 --- a/fs/autofs/expire.c +++ b/fs/autofs/expire.c @@ -73,12 +73,9 @@ static int autofs_mount_busy(struct vfsmount *mnt, /* p->d_lock held */ static struct dentry *positive_after(struct dentry *p, struct dentry *child) { - if (child) - child = list_next_entry(child, d_child); - else - child = list_first_entry(&p->d_subdirs, struct dentry, d_child); + child = child ? d_next_sibling(child) : d_first_child(p); - list_for_each_entry_from(child, &p->d_subdirs, d_child) { + hlist_for_each_entry_from(child, d_sib) { spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(child)) { dget_dlock(child); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 91709934c8b1..678596684596 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -174,7 +174,7 @@ __dcache_find_get_entry(struct dentry *parent, u64 idx, /* * When possible, we try to satisfy a readdir by peeking at the * dcache. We make this work by carefully ordering dentries on - * d_child when we initially get results back from the MDS, and + * d_children when we initially get results back from the MDS, and * falling back to a "normal" sync readdir if any dentries in the dir * are dropped. * diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d95eb525519a..02ebfabfc8ee 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2128,7 +2128,7 @@ static bool drop_negative_children(struct dentry *dentry) goto out; spin_lock(&dentry->d_lock); - list_for_each_entry(child, &dentry->d_subdirs, d_child) { + hlist_for_each_entry(child, &dentry->d_children, d_sib) { if (d_really_is_positive(child)) { all_negative = false; break; diff --git a/fs/coda/cache.c b/fs/coda/cache.c index d6254cf9f397..970f0022ec52 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -93,7 +93,7 @@ static void coda_flag_children(struct dentry *parent, int flag) struct dentry *de; spin_lock(&parent->d_lock); - list_for_each_entry(de, &parent->d_subdirs, d_child) { + hlist_for_each_entry(de, &parent->d_children, d_sib) { struct inode *inode = d_inode_rcu(de); /* don't know what to do with negative dentries */ if (inode) diff --git a/fs/dcache.c b/fs/dcache.c index c82ae731df9a..59f76c9a15d1 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -51,8 +51,8 @@ * - d_lru * - d_count * - d_unhashed() - * - d_parent and d_subdirs - * - childrens' d_child and d_parent + * - d_parent and d_chilren + * - childrens' d_sib and d_parent * - d_u.d_alias, d_inode * * Ordering: @@ -537,7 +537,7 @@ void d_drop(struct dentry *dentry) } EXPORT_SYMBOL(d_drop); -static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent) +static inline void dentry_unlist(struct dentry *dentry) { struct dentry *next; /* @@ -545,12 +545,12 @@ static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent) * attached to the dentry tree */ dentry->d_flags |= DCACHE_DENTRY_KILLED; - if (unlikely(list_empty(&dentry->d_child))) + if (unlikely(hlist_unhashed(&dentry->d_sib))) return; - __list_del_entry(&dentry->d_child); + __hlist_del(&dentry->d_sib); /* * Cursors can move around the list of children. While we'd been - * a normal list member, it didn't matter - ->d_child.next would've + * a normal list member, it didn't matter - ->d_sib.next would've * been updated. However, from now on it won't be and for the * things like d_walk() it might end up with a nasty surprise. * Normally d_walk() doesn't care about cursors moving around - @@ -558,20 +558,20 @@ static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent) * of its own, we get through it without ever unlocking the parent. * There is one exception, though - if we ascend from a child that * gets killed as soon as we unlock it, the next sibling is found - * using the value left in its ->d_child.next. And if _that_ + * using the value left in its ->d_sib.next. And if _that_ * pointed to a cursor, and cursor got moved (e.g. by lseek()) * before d_walk() regains parent->d_lock, we'll end up skipping * everything the cursor had been moved past. * - * Solution: make sure that the pointer left behind in ->d_child.next + * Solution: make sure that the pointer left behind in ->d_sib.next * points to something that won't be moving around. I.e. skip the * cursors. */ - while (dentry->d_child.next != &parent->d_subdirs) { - next = list_entry(dentry->d_child.next, struct dentry, d_child); + while (dentry->d_sib.next) { + next = hlist_entry(dentry->d_sib.next, struct dentry, d_sib); if (likely(!(next->d_flags & DCACHE_DENTRY_CURSOR))) break; - dentry->d_child.next = next->d_child.next; + dentry->d_sib.next = next->d_sib.next; } } @@ -600,7 +600,7 @@ static void __dentry_kill(struct dentry *dentry) } /* if it was on the hash then remove it */ __d_drop(dentry); - dentry_unlist(dentry, parent); + dentry_unlist(dentry); if (parent) spin_unlock(&parent->d_lock); if (dentry->d_inode) @@ -1348,8 +1348,7 @@ enum d_walk_ret { static void d_walk(struct dentry *parent, void *data, enum d_walk_ret (*enter)(void *, struct dentry *)) { - struct dentry *this_parent; - struct list_head *next; + struct dentry *this_parent, *dentry; unsigned seq = 0; enum d_walk_ret ret; bool retry = true; @@ -1371,13 +1370,9 @@ static void d_walk(struct dentry *parent, void *data, break; } repeat: - next = this_parent->d_subdirs.next; + dentry = d_first_child(this_parent); resume: - while (next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); - next = tmp->next; - + hlist_for_each_entry_from(dentry, d_sib) { if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR)) continue; @@ -1398,7 +1393,7 @@ static void d_walk(struct dentry *parent, void *data, continue; } - if (!list_empty(&dentry->d_subdirs)) { + if (!hlist_empty(&dentry->d_children)) { spin_unlock(&this_parent->d_lock); spin_release(&dentry->d_lock.dep_map, _RET_IP_); this_parent = dentry; @@ -1413,24 +1408,23 @@ static void d_walk(struct dentry *parent, void *data, rcu_read_lock(); ascend: if (this_parent != parent) { - struct dentry *child = this_parent; - this_parent = child->d_parent; + dentry = this_parent; + this_parent = dentry->d_parent; - spin_unlock(&child->d_lock); + spin_unlock(&dentry->d_lock); spin_lock(&this_parent->d_lock); /* might go back up the wrong parent if we have had a rename. */ if (need_seqretry(&rename_lock, seq)) goto rename_retry; /* go into the first sibling still alive */ - do { - next = child->d_child.next; - if (next == &this_parent->d_subdirs) - goto ascend; - child = list_entry(next, struct dentry, d_child); - } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); - rcu_read_unlock(); - goto resume; + hlist_for_each_entry_continue(dentry, d_sib) { + if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) { + rcu_read_unlock(); + goto resume; + } + } + goto ascend; } if (need_seqretry(&rename_lock, seq)) goto rename_retry; @@ -1530,7 +1524,7 @@ int d_set_mounted(struct dentry *dentry) * Search the dentry child list of the specified parent, * and move any unused dentries to the end of the unused * list for prune_dcache(). We descend to the next level - * whenever the d_subdirs list is non-empty and continue + * whenever the d_children list is non-empty and continue * searching. * * It returns zero iff there are no unused children, @@ -1657,7 +1651,7 @@ EXPORT_SYMBOL(shrink_dcache_parent); static enum d_walk_ret umount_check(void *_data, struct dentry *dentry) { /* it has busy descendents; complain about those instead */ - if (!list_empty(&dentry->d_subdirs)) + if (!hlist_empty(&dentry->d_children)) return D_WALK_CONTINUE; /* root with refcount 1 is fine */ @@ -1814,9 +1808,9 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) dentry->d_fsdata = NULL; INIT_HLIST_BL_NODE(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_subdirs); + INIT_HLIST_HEAD(&dentry->d_children); INIT_HLIST_NODE(&dentry->d_u.d_alias); - INIT_LIST_HEAD(&dentry->d_child); + INIT_HLIST_NODE(&dentry->d_sib); d_set_d_op(dentry, dentry->d_sb->s_d_op); if (dentry->d_op && dentry->d_op->d_init) { @@ -1855,7 +1849,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) */ __dget_dlock(parent); dentry->d_parent = parent; - list_add(&dentry->d_child, &parent->d_subdirs); + hlist_add_head(&dentry->d_sib, &parent->d_children); spin_unlock(&parent->d_lock); return dentry; @@ -2993,11 +2987,15 @@ static void __d_move(struct dentry *dentry, struct dentry *target, } else { target->d_parent = old_parent; swap_names(dentry, target); - list_move(&target->d_child, &target->d_parent->d_subdirs); + if (!hlist_unhashed(&target->d_sib)) + __hlist_del(&target->d_sib); + hlist_add_head(&target->d_sib, &target->d_parent->d_children); __d_rehash(target); fsnotify_update_flags(target); } - list_move(&dentry->d_child, &dentry->d_parent->d_subdirs); + if (!hlist_unhashed(&dentry->d_sib)) + __hlist_del(&dentry->d_sib); + hlist_add_head(&dentry->d_sib, &dentry->d_parent->d_children); __d_rehash(dentry); fsnotify_update_flags(dentry); fscrypt_handle_d_move(dentry); diff --git a/fs/libfs.c b/fs/libfs.c index e9440d55073c..46c9177769c1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -104,15 +104,16 @@ EXPORT_SYMBOL(dcache_dir_close); * If no such element exists, NULL is returned. */ static struct dentry *scan_positives(struct dentry *cursor, - struct list_head *p, + struct hlist_node **p, loff_t count, struct dentry *last) { struct dentry *dentry = cursor->d_parent, *found = NULL; spin_lock(&dentry->d_lock); - while ((p = p->next) != &dentry->d_subdirs) { - struct dentry *d = list_entry(p, struct dentry, d_child); + while (*p) { + struct dentry *d = hlist_entry(*p, struct dentry, d_sib); + p = &d->d_sib.next; // we must at least skip cursors, to avoid livelocks if (d->d_flags & DCACHE_DENTRY_CURSOR) continue; @@ -126,8 +127,10 @@ static struct dentry *scan_positives(struct dentry *cursor, count = 1; } if (need_resched()) { - list_move(&cursor->d_child, p); - p = &cursor->d_child; + if (!hlist_unhashed(&cursor->d_sib)) + __hlist_del(&cursor->d_sib); + hlist_add_behind(&cursor->d_sib, &d->d_sib); + p = &cursor->d_sib.next; spin_unlock(&dentry->d_lock); cond_resched(); spin_lock(&dentry->d_lock); @@ -159,13 +162,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) inode_lock_shared(dentry->d_inode); if (offset > 2) - to = scan_positives(cursor, &dentry->d_subdirs, + to = scan_positives(cursor, &dentry->d_children.first, offset - 2, NULL); spin_lock(&dentry->d_lock); + hlist_del_init(&cursor->d_sib); if (to) - list_move(&cursor->d_child, &to->d_child); - else - list_del_init(&cursor->d_child); + hlist_add_behind(&cursor->d_sib, &to->d_sib); spin_unlock(&dentry->d_lock); dput(to); @@ -187,19 +189,16 @@ int dcache_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; struct dentry *cursor = file->private_data; - struct list_head *anchor = &dentry->d_subdirs; struct dentry *next = NULL; - struct list_head *p; + struct hlist_node **p; if (!dir_emit_dots(file, ctx)) return 0; if (ctx->pos == 2) - p = anchor; - else if (!list_empty(&cursor->d_child)) - p = &cursor->d_child; + p = &dentry->d_children.first; else - return 0; + p = &cursor->d_sib.next; while ((next = scan_positives(cursor, p, 1, next)) != NULL) { if (!dir_emit(ctx, next->d_name.name, next->d_name.len, @@ -207,13 +206,12 @@ int dcache_readdir(struct file *file, struct dir_context *ctx) fs_umode_to_dtype(d_inode(next)->i_mode))) break; ctx->pos++; - p = &next->d_child; + p = &next->d_sib.next; } spin_lock(&dentry->d_lock); + hlist_del_init(&cursor->d_sib); if (next) - list_move_tail(&cursor->d_child, &next->d_child); - else - list_del_init(&cursor->d_child); + hlist_add_before(&cursor->d_sib, &next->d_sib); spin_unlock(&dentry->d_lock); dput(next); @@ -492,12 +490,11 @@ const struct file_operations simple_offset_dir_operations = { static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev) { - struct dentry *child = NULL; - struct list_head *p = prev ? &prev->d_child : &parent->d_subdirs; + struct dentry *child = NULL, *d; spin_lock(&parent->d_lock); - while ((p = p->next) != &parent->d_subdirs) { - struct dentry *d = container_of(p, struct dentry, d_child); + d = prev ? d_next_sibling(prev) : d_first_child(parent); + hlist_for_each_entry_from(d, d_sib) { if (simple_positive(d)) { spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(d)) @@ -658,7 +655,7 @@ int simple_empty(struct dentry *dentry) int ret = 0; spin_lock(&dentry->d_lock); - list_for_each_entry(child, &dentry->d_subdirs, d_child) { + hlist_for_each_entry(child, &dentry->d_children, d_sib) { spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(child)) { spin_unlock(&child->d_lock); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 7974e91ffe13..8bfd690e9f10 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -124,7 +124,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) * d_flags to indicate parental interest (their parent is the * original inode) */ spin_lock(&alias->d_lock); - list_for_each_entry(child, &alias->d_subdirs, d_child) { + hlist_for_each_entry(child, &alias->d_children, d_sib) { if (!child->d_inode) continue; diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 5b54948514fe..61ca5fcf10f9 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -199,26 +199,21 @@ static void change_gid(struct dentry *dentry, kgid_t gid) */ static void set_gid(struct dentry *parent, kgid_t gid) { - struct dentry *this_parent; - struct list_head *next; + struct dentry *this_parent, *dentry; this_parent = parent; spin_lock(&this_parent->d_lock); change_gid(this_parent, gid); repeat: - next = this_parent->d_subdirs.next; + dentry = d_first_child(this_parent); resume: - while (next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); - next = tmp->next; - + hlist_for_each_entry_from(dentry, d_sib) { spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); change_gid(dentry, gid); - if (!list_empty(&dentry->d_subdirs)) { + if (!hlist_empty(&dentry->d_children)) { spin_unlock(&this_parent->d_lock); spin_release(&dentry->d_lock.dep_map, _RET_IP_); this_parent = dentry; @@ -233,21 +228,20 @@ static void set_gid(struct dentry *parent, kgid_t gid) rcu_read_lock(); ascend: if (this_parent != parent) { - struct dentry *child = this_parent; - this_parent = child->d_parent; + dentry = this_parent; + this_parent = dentry->d_parent; - spin_unlock(&child->d_lock); + spin_unlock(&dentry->d_lock); spin_lock(&this_parent->d_lock); /* go into the first sibling still alive */ - do { - next = child->d_child.next; - if (next == &this_parent->d_subdirs) - goto ascend; - child = list_entry(next, struct dentry, d_child); - } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); - rcu_read_unlock(); - goto resume; + hlist_for_each_entry_continue(dentry, d_sib) { + if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) { + rcu_read_unlock(); + goto resume; + } + } + goto ascend; } rcu_read_unlock(); spin_unlock(&this_parent->d_lock); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 3da2f0545d5d..0e397a0c519c 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -68,12 +68,12 @@ extern const struct qstr dotdot_name; * large memory footprint increase). */ #ifdef CONFIG_64BIT -# define DNAME_INLINE_LEN 32 /* 192 bytes */ +# define DNAME_INLINE_LEN 40 /* 192 bytes */ #else # ifdef CONFIG_SMP -# define DNAME_INLINE_LEN 36 /* 128 bytes */ -# else # define DNAME_INLINE_LEN 40 /* 128 bytes */ +# else +# define DNAME_INLINE_LEN 44 /* 128 bytes */ # endif #endif @@ -101,8 +101,8 @@ struct dentry { struct list_head d_lru; /* LRU list */ wait_queue_head_t *d_wait; /* in-lookup ones only */ }; - struct list_head d_child; /* child of parent list */ - struct list_head d_subdirs; /* our children */ + struct hlist_node d_sib; /* child of parent list */ + struct hlist_head d_children; /* our children */ /* * d_alias and d_rcu can share memory */ @@ -600,4 +600,14 @@ struct name_snapshot { void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); void release_dentry_name_snapshot(struct name_snapshot *); +static inline struct dentry *d_first_child(const struct dentry *dentry) +{ + return hlist_entry_safe(dentry->d_children.first, struct dentry, d_sib); +} + +static inline struct dentry *d_next_sibling(const struct dentry *dentry) +{ + return hlist_entry_safe(dentry->d_sib.next, struct dentry, d_sib); +} + #endif /* __LINUX_DCACHE_H */ From 3fcf535626a44e107e2d536a2c43da0fb5bde121 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Nov 2023 15:21:33 -0500 Subject: [PATCH 1440/7721] centralize killing dentry from shrink list new helper unifying identical bits of shrink_dentry_list() and shring_dcache_for_umount() Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 59f76c9a15d1..bb862a304e1b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1174,10 +1174,18 @@ static bool shrink_lock_dentry(struct dentry *dentry) return false; } +static inline void shrink_kill(struct dentry *victim, struct list_head *list) +{ + struct dentry *parent = victim->d_parent; + if (parent != victim) + __dput_to_list(parent, list); + __dentry_kill(victim); +} + void shrink_dentry_list(struct list_head *list) { while (!list_empty(list)) { - struct dentry *dentry, *parent; + struct dentry *dentry; dentry = list_entry(list->prev, struct dentry, d_lru); spin_lock(&dentry->d_lock); @@ -1195,10 +1203,7 @@ void shrink_dentry_list(struct list_head *list) } rcu_read_unlock(); d_shrink_del(dentry); - parent = dentry->d_parent; - if (parent != dentry) - __dput_to_list(parent, list); - __dentry_kill(dentry); + shrink_kill(dentry, list); } } @@ -1629,17 +1634,13 @@ void shrink_dcache_parent(struct dentry *parent) data.victim = NULL; d_walk(parent, &data, select_collect2); if (data.victim) { - struct dentry *parent; spin_lock(&data.victim->d_lock); if (!shrink_lock_dentry(data.victim)) { spin_unlock(&data.victim->d_lock); rcu_read_unlock(); } else { rcu_read_unlock(); - parent = data.victim->d_parent; - if (parent != data.victim) - __dput_to_list(parent, &data.dispose); - __dentry_kill(data.victim); + shrink_kill(data.victim, &data.dispose); } } if (!list_empty(&data.dispose)) From cd9f84f35c2eaaf4da7e111021b604662326d8aa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 13:57:12 -0400 Subject: [PATCH 1441/7721] shrink_dentry_list(): no need to check that dentry refcount is marked dead ... we won't see DCACHE_MAY_FREE on anything that is *not* dead and checking d_flags is just as cheap as checking refcount. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index bb862a304e1b..c1025921f8d3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1191,11 +1191,10 @@ void shrink_dentry_list(struct list_head *list) spin_lock(&dentry->d_lock); rcu_read_lock(); if (!shrink_lock_dentry(dentry)) { - bool can_free = false; + bool can_free; rcu_read_unlock(); d_shrink_del(dentry); - if (dentry->d_lockref.count < 0) - can_free = dentry->d_flags & DCACHE_MAY_FREE; + can_free = dentry->d_flags & DCACHE_MAY_FREE; spin_unlock(&dentry->d_lock); if (can_free) dentry_free(dentry); From 15220fbf187100e1cc1ad553b7d21633bdc27e76 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 00:02:14 -0400 Subject: [PATCH 1442/7721] fast_dput(): having ->d_delete() is not reason to delay refcount decrement ->d_delete() is a way for filesystem to tell that dentry is not worth keeping cached. It is not guaranteed to be called every time a dentry has refcount drop down to zero; it is not guaranteed to be called before dentry gets evicted. In other words, it is not suitable for any kind of keeping track of dentry state. None of the in-tree filesystems attempt to use it that way, fortunately. So the contortions done by fast_dput() (as well as dentry_kill()) are not warranted. fast_dput() certainly should treat having ->d_delete() instance as "can't assume we'll be keeping it", but that's not different from the way we treat e.g. DCACHE_DONTCACHE (which is rather similar to making ->d_delete() returns true when called). Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index c1025921f8d3..00c19041adf3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -768,15 +768,7 @@ static inline bool fast_dput(struct dentry *dentry) unsigned int d_flags; /* - * If we have a d_op->d_delete() operation, we sould not - * let the dentry count go to zero, so use "put_or_lock". - */ - if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) - return lockref_put_or_lock(&dentry->d_lockref); - - /* - * .. otherwise, we can try to just decrement the - * lockref optimistically. + * try to decrement the lockref optimistically. */ ret = lockref_put_return(&dentry->d_lockref); @@ -830,7 +822,7 @@ static inline bool fast_dput(struct dentry *dentry) */ smp_rmb(); d_flags = READ_ONCE(dentry->d_flags); - d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | + d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_OP_DELETE | DCACHE_DISCONNECTED | DCACHE_DONTCACHE; /* Nothing to do? Dropping the reference was all we needed? */ From 504e08cebe1d4e1efe25f915234f646e74a364a8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 1 Nov 2023 01:08:54 -0400 Subject: [PATCH 1443/7721] fast_dput(): handle underflows gracefully If refcount is less than 1, we should just warn, unlock dentry and return true, so that the caller doesn't try to do anything else. Taking care of that leaves the rest of "lockref_put_return() has failed" case equivalent to "decrement refcount and rejoin the normal slow path after the point where we grab ->d_lock". NOTE: lockref_put_return() is strictly a fastpath thing - unlike the rest of lockref primitives, it does not contain a fallback. Caller (and it looks like fast_dput() is the only legitimate one in the entire kernel) has to do that itself. Reasons for lockref_put_return() failures: * ->d_lock held by somebody * refcount <= 0 * ... or an architecture not supporting lockref use of cmpxchg - sparc, anything non-SMP, config with spinlock debugging... We could add a fallback, but it would be a clumsy API - we'd have to distinguish between: (1) refcount > 1 - decremented, lock not held on return (2) refcount < 1 - left alone, probably no sense to hold the lock (3) refcount is 1, no cmphxcg - decremented, lock held on return (4) refcount is 1, cmphxcg supported - decremented, lock *NOT* held on return. We want to return with no lock held in case (4); that's the whole point of that thing. We very much do not want to have the fallback in case (3) return without a lock, since the caller might have to retake it in that case. So it wouldn't be more convenient than doing the fallback in the caller and it would be very easy to screw up, especially since the test coverage would suck - no way to test (3) and (4) on the same kernel build. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 00c19041adf3..9edabc7e2e64 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -779,12 +779,12 @@ static inline bool fast_dput(struct dentry *dentry) */ if (unlikely(ret < 0)) { spin_lock(&dentry->d_lock); - if (dentry->d_lockref.count > 1) { - dentry->d_lockref.count--; + if (WARN_ON_ONCE(dentry->d_lockref.count <= 0)) { spin_unlock(&dentry->d_lock); return true; } - return false; + dentry->d_lockref.count--; + goto locked; } /* @@ -842,6 +842,7 @@ static inline bool fast_dput(struct dentry *dentry) * else could have killed it and marked it dead. Either way, we * don't need to do anything else. */ +locked: if (dentry->d_lockref.count) { spin_unlock(&dentry->d_lock); return true; From 15f23734a1def3b22ba790bbf9f0d01949aae231 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 00:11:58 -0400 Subject: [PATCH 1444/7721] fast_dput(): new rules for refcount By now there is only one place in entire fast_dput() where we return false; that happens after refcount had been decremented and found (under ->d_lock) to be zero. In that case, just prior to returning false to caller, fast_dput() forcibly changes the refcount from 0 to 1. Lift that resetting refcount to 1 into the callers; later in the series it will be massaged out of existence. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 9edabc7e2e64..a00e9ba22480 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -847,13 +847,6 @@ static inline bool fast_dput(struct dentry *dentry) spin_unlock(&dentry->d_lock); return true; } - - /* - * Re-get the reference we optimistically dropped. We hold the - * lock, and we just tested that it was zero, so we can just - * set it to 1. - */ - dentry->d_lockref.count = 1; return false; } @@ -896,6 +889,7 @@ void dput(struct dentry *dentry) } /* Slow case: now with the dentry lock held */ + dentry->d_lockref.count = 1; rcu_read_unlock(); if (likely(retain_dentry(dentry))) { @@ -930,6 +924,7 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) return; } rcu_read_unlock(); + dentry->d_lockref.count = 1; if (!retain_dentry(dentry)) __dput_to_list(dentry, list); spin_unlock(&dentry->d_lock); From 6511f6be777f3b06e904c7407fd9f2a39dae8b67 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 00:43:48 -0400 Subject: [PATCH 1445/7721] __dput_to_list(): do decrement of refcount in the callers ... and rename it to to_shrink_list(), seeing that it no longer does dropping any references Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a00e9ba22480..0718b3895c12 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -902,16 +902,13 @@ void dput(struct dentry *dentry) } EXPORT_SYMBOL(dput); -static void __dput_to_list(struct dentry *dentry, struct list_head *list) +static void to_shrink_list(struct dentry *dentry, struct list_head *list) __must_hold(&dentry->d_lock) { - if (dentry->d_flags & DCACHE_SHRINK_LIST) { - /* let the owner of the list it's on deal with it */ - --dentry->d_lockref.count; - } else { + if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { if (dentry->d_flags & DCACHE_LRU_LIST) d_lru_del(dentry); - if (!--dentry->d_lockref.count) + if (!dentry->d_lockref.count) d_shrink_add(dentry, list); } } @@ -925,8 +922,10 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) } rcu_read_unlock(); dentry->d_lockref.count = 1; - if (!retain_dentry(dentry)) - __dput_to_list(dentry, list); + if (!retain_dentry(dentry)) { + --dentry->d_lockref.count; + to_shrink_list(dentry, list); + } spin_unlock(&dentry->d_lock); } @@ -1165,8 +1164,10 @@ static bool shrink_lock_dentry(struct dentry *dentry) static inline void shrink_kill(struct dentry *victim, struct list_head *list) { struct dentry *parent = victim->d_parent; - if (parent != victim) - __dput_to_list(parent, list); + if (parent != victim) { + --parent->d_lockref.count; + to_shrink_list(parent, list); + } __dentry_kill(victim); } From e9d130d05077e71b1224ad96e419f5f5512b8574 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Oct 2023 19:09:11 -0400 Subject: [PATCH 1446/7721] make retain_dentry() neutral with respect to refcounting retain_dentry() used to decrement refcount if and only if it returned true. Lift those decrements into the callers. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index 0718b3895c12..2e74f3f2ce2e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -680,7 +680,6 @@ static inline bool retain_dentry(struct dentry *dentry) return false; /* retain; LRU fodder */ - dentry->d_lockref.count--; if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) d_lru_add(dentry); else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED))) @@ -744,6 +743,8 @@ static struct dentry *dentry_kill(struct dentry *dentry) } else if (likely(!retain_dentry(dentry))) { __dentry_kill(dentry); return parent; + } else { + dentry->d_lockref.count--; } /* we are keeping it, after all */ if (inode) @@ -893,6 +894,7 @@ void dput(struct dentry *dentry) rcu_read_unlock(); if (likely(retain_dentry(dentry))) { + dentry->d_lockref.count--; spin_unlock(&dentry->d_lock); return; } @@ -925,6 +927,8 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) if (!retain_dentry(dentry)) { --dentry->d_lockref.count; to_shrink_list(dentry, list); + } else { + --dentry->d_lockref.count; } spin_unlock(&dentry->d_lock); } From ee0c82503dcd0d14cc1ad53da18d32a04f612c4c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Oct 2023 18:38:27 -0400 Subject: [PATCH 1447/7721] __dentry_kill(): get consistent rules for victim's refcount Currently we call it with refcount equal to 1 when called from dentry_kill(); all other callers have it equal to 0. Make it always be called with zero refcount; on this step we just decrement it before the calls in dentry_kill(). That is safe, since all places that care about the value of refcount either do that under ->d_lock or hold a reference to dentry in question. Either is sufficient to prevent observing a dentry immediately prior to __dentry_kill() getting called from dentry_kill(). Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/dcache.c b/fs/dcache.c index 2e74f3f2ce2e..b527db8e5901 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -729,6 +729,7 @@ static struct dentry *dentry_kill(struct dentry *dentry) goto slow_positive; } } + dentry->d_lockref.count--; __dentry_kill(dentry); return parent; @@ -741,6 +742,7 @@ static struct dentry *dentry_kill(struct dentry *dentry) if (unlikely(dentry->d_lockref.count != 1)) { dentry->d_lockref.count--; } else if (likely(!retain_dentry(dentry))) { + dentry->d_lockref.count--; __dentry_kill(dentry); return parent; } else { From b06c684d3984ef64e792ec3e89889c96cab97b5e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 31 Oct 2023 00:23:35 -0400 Subject: [PATCH 1448/7721] dentry_kill(): don't bother with retain_dentry() on slow path We have already checked it and dentry used to look not worthy of keeping. The only hard obstacle to evicting dentry is non-zero refcount; everything else is advisory - e.g. memory pressure could evict any dentry found with refcount zero. On the slow path in dentry_kill() we had dropped and regained ->d_lock; we must recheck the refcount, but everything else is not worth bothering with. Note that filesystem can not count upon ->d_delete() being called for dentry - not even once. Again, memory pressure (as well as d_prune_aliases(), or attempted rmdir() of ancestor, or...) will not call ->d_delete() at all. So from the correctness point of view we are fine doing the check only once. And it makes things simpler down the road. Signed-off-by: Al Viro --- fs/dcache.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index b527db8e5901..80992e49561c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -739,14 +739,10 @@ static struct dentry *dentry_kill(struct dentry *dentry) spin_lock(&dentry->d_lock); parent = lock_parent(dentry); got_locks: - if (unlikely(dentry->d_lockref.count != 1)) { - dentry->d_lockref.count--; - } else if (likely(!retain_dentry(dentry))) { - dentry->d_lockref.count--; + dentry->d_lockref.count--; + if (likely(dentry->d_lockref.count == 0)) { __dentry_kill(dentry); return parent; - } else { - dentry->d_lockref.count--; } /* we are keeping it, after all */ if (inode) From 2f42f1eb9093834b635991c70d0273fbe249eabf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 01:09:50 -0400 Subject: [PATCH 1449/7721] Call retain_dentry() with refcount 0 Instead of bumping it from 0 to 1, calling retain_dentry(), then decrementing it back to 0 (with ->d_lock held all the way through), just leave refcount at 0 through all of that. It will have a visible effect for ->d_delete() - now it can be called with refcount 0 instead of 1 and it can no longer play silly buggers with dropping/regaining ->d_lock. Not that any in-tree instances tried to (it's pretty hard to get right). Any out-of-tree ones will have to adjust (assuming they need any changes). Note that we do not need to extend rcu-critical area here - we have verified that refcount is non-negative after having grabbed ->d_lock, so nobody will be able to free dentry until they get into __dentry_kill(), which won't happen until they manage to grab ->d_lock. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- Documentation/filesystems/porting.rst | 8 ++++++++ fs/dcache.c | 10 ++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 331405f4b29f..da8073b592ff 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1070,3 +1070,11 @@ The list of children anchored in parent dentry got turned into hlist now. Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child for anchor/entries resp.), so any affected places will be immediately caught by compiler. + +--- + +**mandatory** + +->d_delete() instances are now called for dentries with ->d_lock held +and refcount equal to 0. They are not permitted to drop/regain ->d_lock. +None of in-tree instances did anything of that sort. Make sure yours do not... diff --git a/fs/dcache.c b/fs/dcache.c index 80992e49561c..8ce0fe70f303 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -888,15 +888,14 @@ void dput(struct dentry *dentry) } /* Slow case: now with the dentry lock held */ - dentry->d_lockref.count = 1; rcu_read_unlock(); if (likely(retain_dentry(dentry))) { - dentry->d_lockref.count--; spin_unlock(&dentry->d_lock); return; } + dentry->d_lockref.count = 1; dentry = dentry_kill(dentry); } } @@ -921,13 +920,8 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) return; } rcu_read_unlock(); - dentry->d_lockref.count = 1; - if (!retain_dentry(dentry)) { - --dentry->d_lockref.count; + if (!retain_dentry(dentry)) to_shrink_list(dentry, list); - } else { - --dentry->d_lockref.count; - } spin_unlock(&dentry->d_lock); } From f05441c7e16e6a720cf24e08999661a76ff77478 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 31 Oct 2023 00:45:40 -0400 Subject: [PATCH 1450/7721] fold the call of retain_dentry() into fast_dput() Calls of retain_dentry() happen immediately after getting false from fast_dput() and getting true from retain_dentry() is treated the same way as non-zero refcount would be treated by fast_dput() - unlock dentry and bugger off. Doing that in fast_dput() itself is simpler. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 8ce0fe70f303..b69ff3a0b30f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -757,6 +757,8 @@ static struct dentry *dentry_kill(struct dentry *dentry) * Try to do a lockless dput(), and return whether that was successful. * * If unsuccessful, we return false, having already taken the dentry lock. + * In that case refcount is guaranteed to be zero and we have already + * decided that it's not worth keeping around. * * The caller needs to hold the RCU read lock, so that the dentry is * guaranteed to stay around even if the refcount goes down to zero! @@ -842,7 +844,7 @@ static inline bool fast_dput(struct dentry *dentry) * don't need to do anything else. */ locked: - if (dentry->d_lockref.count) { + if (dentry->d_lockref.count || retain_dentry(dentry)) { spin_unlock(&dentry->d_lock); return true; } @@ -889,12 +891,6 @@ void dput(struct dentry *dentry) /* Slow case: now with the dentry lock held */ rcu_read_unlock(); - - if (likely(retain_dentry(dentry))) { - spin_unlock(&dentry->d_lock); - return; - } - dentry->d_lockref.count = 1; dentry = dentry_kill(dentry); } @@ -920,8 +916,7 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) return; } rcu_read_unlock(); - if (!retain_dentry(dentry)) - to_shrink_list(dentry, list); + to_shrink_list(dentry, list); spin_unlock(&dentry->d_lock); } From 339e9e13530ba750fe0868c5e51bc23be07fd1f1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 31 Oct 2023 01:23:47 -0400 Subject: [PATCH 1451/7721] don't try to cut corners in shrink_lock_dentry() That is to say, do *not* treat the ->d_inode or ->d_parent changes as "it's hard, return false; somebody must have grabbed it, so even if has zero refcount, we don't need to bother killing it - final dput() from whoever grabbed it would've done everything". First of all, that is not guaranteed. It might have been dropped by shrink_kill() handling of victim's parent, which would've found it already on a shrink list (ours) and decided that they don't need to put it on their shrink list. What's more, dentry_kill() is doing pretty much the same thing, cutting its own set of corners (it assumes that dentry can't go from positive to negative, so its inode can change but only once and only in one direction). Doing that right allows to get rid of that not-quite-duplication and removes the only reason for re-incrementing refcount before the call of dentry_kill(). Replacement is called lock_for_kill(); called under rcu_read_lock and with ->d_lock held. If it returns false, dentry has non-zero refcount and the same locks are held. If it returns true, dentry has zero refcount and all locks required by __dentry_kill() are taken. Part of __lock_parent() had been lifted into lock_parent() to allow its reuse. Now it's called with rcu_read_lock already held and dentry already unlocked. Note that this is not the final change - locking requirements for __dentry_kill() are going to change later in the series and the set of locks taken by lock_for_kill() will be adjusted. Both lock_parent() and __lock_parent() will be gone once that happens. Signed-off-by: Al Viro --- fs/dcache.c | 159 ++++++++++++++++++++++------------------------------ 1 file changed, 66 insertions(+), 93 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index b69ff3a0b30f..a7f99d46c41b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -625,8 +625,6 @@ static void __dentry_kill(struct dentry *dentry) static struct dentry *__lock_parent(struct dentry *dentry) { struct dentry *parent; - rcu_read_lock(); - spin_unlock(&dentry->d_lock); again: parent = READ_ONCE(dentry->d_parent); spin_lock(&parent->d_lock); @@ -642,7 +640,6 @@ static struct dentry *__lock_parent(struct dentry *dentry) spin_unlock(&parent->d_lock); goto again; } - rcu_read_unlock(); if (parent != dentry) spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); else @@ -657,7 +654,64 @@ static inline struct dentry *lock_parent(struct dentry *dentry) return NULL; if (likely(spin_trylock(&parent->d_lock))) return parent; - return __lock_parent(dentry); + rcu_read_lock(); + spin_unlock(&dentry->d_lock); + parent = __lock_parent(dentry); + rcu_read_unlock(); + return parent; +} + +/* + * Lock a dentry for feeding it to __dentry_kill(). + * Called under rcu_read_lock() and dentry->d_lock; the former + * guarantees that nothing we access will be freed under us. + * Note that dentry is *not* protected from concurrent dentry_kill(), + * d_delete(), etc. + * + * Return false if dentry is busy. Otherwise, return true and have + * that dentry's inode and parent both locked. + */ + +static bool lock_for_kill(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct dentry *parent = dentry->d_parent; + + if (unlikely(dentry->d_lockref.count)) + return false; + + if (inode && unlikely(!spin_trylock(&inode->i_lock))) + goto slow; + if (dentry == parent) + return true; + if (likely(spin_trylock(&parent->d_lock))) + return true; + + if (inode) + spin_unlock(&inode->i_lock); +slow: + spin_unlock(&dentry->d_lock); + + for (;;) { + if (inode) + spin_lock(&inode->i_lock); + parent = __lock_parent(dentry); + if (likely(inode == dentry->d_inode)) + break; + if (inode) + spin_unlock(&inode->i_lock); + inode = dentry->d_inode; + spin_unlock(&dentry->d_lock); + if (parent) + spin_unlock(&parent->d_lock); + } + if (likely(!dentry->d_lockref.count)) + return true; + if (inode) + spin_unlock(&inode->i_lock); + if (parent) + spin_unlock(&parent->d_lock); + return false; } static inline bool retain_dentry(struct dentry *dentry) @@ -710,45 +764,16 @@ EXPORT_SYMBOL(d_mark_dontcache); static struct dentry *dentry_kill(struct dentry *dentry) __releases(dentry->d_lock) { - struct inode *inode = dentry->d_inode; - struct dentry *parent = NULL; - if (inode && unlikely(!spin_trylock(&inode->i_lock))) - goto slow_positive; - - if (!IS_ROOT(dentry)) { - parent = dentry->d_parent; - if (unlikely(!spin_trylock(&parent->d_lock))) { - parent = __lock_parent(dentry); - if (likely(inode || !dentry->d_inode)) - goto got_locks; - /* negative that became positive */ - if (parent) - spin_unlock(&parent->d_lock); - inode = dentry->d_inode; - goto slow_positive; - } - } dentry->d_lockref.count--; - __dentry_kill(dentry); - return parent; - -slow_positive: - spin_unlock(&dentry->d_lock); - spin_lock(&inode->i_lock); - spin_lock(&dentry->d_lock); - parent = lock_parent(dentry); -got_locks: - dentry->d_lockref.count--; - if (likely(dentry->d_lockref.count == 0)) { + rcu_read_lock(); + if (likely(lock_for_kill(dentry))) { + struct dentry *parent = dentry->d_parent; + rcu_read_unlock(); __dentry_kill(dentry); - return parent; + return parent != dentry ? parent : NULL; } - /* we are keeping it, after all */ - if (inode) - spin_unlock(&inode->i_lock); - if (parent) - spin_unlock(&parent->d_lock); + rcu_read_unlock(); spin_unlock(&dentry->d_lock); return NULL; } @@ -1100,58 +1125,6 @@ void d_prune_aliases(struct inode *inode) } EXPORT_SYMBOL(d_prune_aliases); -/* - * Lock a dentry from shrink list. - * Called under rcu_read_lock() and dentry->d_lock; the former - * guarantees that nothing we access will be freed under us. - * Note that dentry is *not* protected from concurrent dentry_kill(), - * d_delete(), etc. - * - * Return false if dentry has been disrupted or grabbed, leaving - * the caller to kick it off-list. Otherwise, return true and have - * that dentry's inode and parent both locked. - */ -static bool shrink_lock_dentry(struct dentry *dentry) -{ - struct inode *inode; - struct dentry *parent; - - if (dentry->d_lockref.count) - return false; - - inode = dentry->d_inode; - if (inode && unlikely(!spin_trylock(&inode->i_lock))) { - spin_unlock(&dentry->d_lock); - spin_lock(&inode->i_lock); - spin_lock(&dentry->d_lock); - if (unlikely(dentry->d_lockref.count)) - goto out; - /* changed inode means that somebody had grabbed it */ - if (unlikely(inode != dentry->d_inode)) - goto out; - } - - parent = dentry->d_parent; - if (IS_ROOT(dentry) || likely(spin_trylock(&parent->d_lock))) - return true; - - spin_unlock(&dentry->d_lock); - spin_lock(&parent->d_lock); - if (unlikely(parent != dentry->d_parent)) { - spin_unlock(&parent->d_lock); - spin_lock(&dentry->d_lock); - goto out; - } - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - if (likely(!dentry->d_lockref.count)) - return true; - spin_unlock(&parent->d_lock); -out: - if (inode) - spin_unlock(&inode->i_lock); - return false; -} - static inline void shrink_kill(struct dentry *victim, struct list_head *list) { struct dentry *parent = victim->d_parent; @@ -1170,7 +1143,7 @@ void shrink_dentry_list(struct list_head *list) dentry = list_entry(list->prev, struct dentry, d_lru); spin_lock(&dentry->d_lock); rcu_read_lock(); - if (!shrink_lock_dentry(dentry)) { + if (!lock_for_kill(dentry)) { bool can_free; rcu_read_unlock(); d_shrink_del(dentry); @@ -1614,7 +1587,7 @@ void shrink_dcache_parent(struct dentry *parent) d_walk(parent, &data, select_collect2); if (data.victim) { spin_lock(&data.victim->d_lock); - if (!shrink_lock_dentry(data.victim)) { + if (!lock_for_kill(data.victim)) { spin_unlock(&data.victim->d_lock); rcu_read_unlock(); } else { From 5e7a5c8d17d94216aed205cb0f20cd32adfd4487 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 31 Oct 2023 01:41:22 -0400 Subject: [PATCH 1452/7721] fold dentry_kill() into dput() Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a7f99d46c41b..5284b02747cd 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -756,28 +756,6 @@ void d_mark_dontcache(struct inode *inode) } EXPORT_SYMBOL(d_mark_dontcache); -/* - * Finish off a dentry we've decided to kill. - * dentry->d_lock must be held, returns with it unlocked. - * Returns dentry requiring refcount drop, or NULL if we're done. - */ -static struct dentry *dentry_kill(struct dentry *dentry) - __releases(dentry->d_lock) -{ - - dentry->d_lockref.count--; - rcu_read_lock(); - if (likely(lock_for_kill(dentry))) { - struct dentry *parent = dentry->d_parent; - rcu_read_unlock(); - __dentry_kill(dentry); - return parent != dentry ? parent : NULL; - } - rcu_read_unlock(); - spin_unlock(&dentry->d_lock); - return NULL; -} - /* * Try to do a lockless dput(), and return whether that was successful. * @@ -915,9 +893,18 @@ void dput(struct dentry *dentry) } /* Slow case: now with the dentry lock held */ - rcu_read_unlock(); - dentry->d_lockref.count = 1; - dentry = dentry_kill(dentry); + if (likely(lock_for_kill(dentry))) { + struct dentry *parent = dentry->d_parent; + rcu_read_unlock(); + __dentry_kill(dentry); + if (dentry == parent) + return; + dentry = parent; + } else { + rcu_read_unlock(); + spin_unlock(&dentry->d_lock); + return; + } } } EXPORT_SYMBOL(dput); From c2e5e29f3fdaff6f57795be068ce525c60954fd0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 01:06:06 -0400 Subject: [PATCH 1453/7721] to_shrink_list(): call only if refcount is 0 The only thing it does if refcount is not zero is d_lru_del(); no point, IMO, seeing that plain dput() does nothing of that sort... Note that 2 of 3 current callers are guaranteed that refcount is 0. Acked-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 5284b02747cd..704676bf06fd 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -915,8 +915,7 @@ __must_hold(&dentry->d_lock) if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { if (dentry->d_flags & DCACHE_LRU_LIST) d_lru_del(dentry); - if (!dentry->d_lockref.count) - d_shrink_add(dentry, list); + d_shrink_add(dentry, list); } } @@ -1115,10 +1114,8 @@ EXPORT_SYMBOL(d_prune_aliases); static inline void shrink_kill(struct dentry *victim, struct list_head *list) { struct dentry *parent = victim->d_parent; - if (parent != victim) { - --parent->d_lockref.count; + if (parent != victim && !--parent->d_lockref.count) to_shrink_list(parent, list); - } __dentry_kill(victim); } From f5c8a8a4b6c90f2160de6b580fa672b4afc15061 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 30 Oct 2023 21:07:34 -0400 Subject: [PATCH 1454/7721] switch select_collect{,2}() to use of to_shrink_list() Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 704676bf06fd..f68fe7c863e0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1495,13 +1495,9 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) if (dentry->d_flags & DCACHE_SHRINK_LIST) { data->found++; - } else { - if (dentry->d_flags & DCACHE_LRU_LIST) - d_lru_del(dentry); - if (!dentry->d_lockref.count) { - d_shrink_add(dentry, &data->dispose); - data->found++; - } + } else if (!dentry->d_lockref.count) { + to_shrink_list(dentry, &data->dispose); + data->found++; } /* * We can return to the caller if we have found some (this @@ -1522,17 +1518,13 @@ static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry) if (data->start == dentry) goto out; - if (dentry->d_flags & DCACHE_SHRINK_LIST) { - if (!dentry->d_lockref.count) { + if (!dentry->d_lockref.count) { + if (dentry->d_flags & DCACHE_SHRINK_LIST) { rcu_read_lock(); data->victim = dentry; return D_WALK_QUIT; } - } else { - if (dentry->d_flags & DCACHE_LRU_LIST) - d_lru_del(dentry); - if (!dentry->d_lockref.count) - d_shrink_add(dentry, &data->dispose); + to_shrink_list(dentry, &data->dispose); } /* * We can return to the caller if we have found some (this From b4cc0734d25746d402db3baa6082d19109bca951 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Nov 2023 14:46:14 -0400 Subject: [PATCH 1455/7721] d_prune_aliases(): use a shrink list Instead of dropping aliases one by one, restarting, etc., just collect them into a shrink list and kill them off in one pass. We don't really need the restarts - one alias can't pin another (directory has only one alias, and couldn't be its own ancestor anyway), so collecting everything that is not busy and taking it out would take care of everything evictable that had been there as we entered the function. And new aliases added while we'd been dropping old ones could just as easily have appeared right as we return to caller... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/dcache.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index f68fe7c863e0..a3cc612a80d5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -647,20 +647,6 @@ static struct dentry *__lock_parent(struct dentry *dentry) return parent; } -static inline struct dentry *lock_parent(struct dentry *dentry) -{ - struct dentry *parent = dentry->d_parent; - if (IS_ROOT(dentry)) - return NULL; - if (likely(spin_trylock(&parent->d_lock))) - return parent; - rcu_read_lock(); - spin_unlock(&dentry->d_lock); - parent = __lock_parent(dentry); - rcu_read_unlock(); - return parent; -} - /* * Lock a dentry for feeding it to __dentry_kill(). * Called under rcu_read_lock() and dentry->d_lock; the former @@ -1090,24 +1076,18 @@ struct dentry *d_find_alias_rcu(struct inode *inode) */ void d_prune_aliases(struct inode *inode) { + LIST_HEAD(dispose); struct dentry *dentry; -restart: + spin_lock(&inode->i_lock); hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { spin_lock(&dentry->d_lock); - if (!dentry->d_lockref.count) { - struct dentry *parent = lock_parent(dentry); - if (likely(!dentry->d_lockref.count)) { - __dentry_kill(dentry); - dput(parent); - goto restart; - } - if (parent) - spin_unlock(&parent->d_lock); - } + if (!dentry->d_lockref.count) + to_shrink_list(dentry, &dispose); spin_unlock(&dentry->d_lock); } spin_unlock(&inode->i_lock); + shrink_dentry_list(&dispose); } EXPORT_SYMBOL(d_prune_aliases); From 1c18edd1b7a068e07fed7f00e059f22ed67c04c9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Nov 2023 16:14:08 -0500 Subject: [PATCH 1456/7721] __dentry_kill(): new locking scheme Currently we enter __dentry_kill() with parent (along with the victim dentry and victim's inode) held locked. Then we mark dentry refcount as dead call ->d_prune() remove dentry from hash remove it from the parent's list of children unlock the parent, don't need it from that point on detach dentry from inode, unlock dentry and drop the inode (via ->d_iput()) call ->d_release() regain the lock on dentry check if it's on a shrink list (in which case freeing its empty husk has to be left to shrink_dentry_list()) or not (in which case we can free it ourselves). In the former case, mark it as an empty husk, so that shrink_dentry_list() would know it can free the sucker. drop the lock on dentry ... and usually the caller proceeds to drop a reference on the parent, possibly retaking the lock on it. That is painful for a bunch of reasons, starting with the need to take locks out of order, but not limited to that - the parent of positive dentry can change if we drop its ->d_lock, so getting these locks has to be done with care. Moreover, as soon as dentry is out of the parent's list of children, shrink_dcache_for_umount() won't see it anymore, making it appear as if the parent is inexplicably busy. We do work around that by having shrink_dentry_list() decrement the parent's refcount first and put it on shrink list to be evicted once we are done with __dentry_kill() of child, but that may in some cases lead to ->d_iput() on child called after the parent got killed. That doesn't happen in cases where in-tree ->d_iput() instances might want to look at the parent, but that's brittle as hell. Solution: do removal from the parent's list of children in the very end of __dentry_kill(). As the result, the callers do not need to lock the parent and by the time we really need the parent locked, dentry is negative and is guaranteed not to be moved around. It does mean that ->d_prune() will be called with parent not locked. It also means that we might see dentries in process of being torn down while going through the parent's list of children; those dentries will be unhashed, negative and with refcount marked dead. In practice, that's enough for in-tree code that looks through the list of children to do the right thing as-is. Out-of-tree code might need to be adjusted. Calling conventions: __dentry_kill(dentry) is called with dentry->d_lock held, along with ->i_lock of its inode (if any). It either returns the parent (locked, with refcount decremented to 0) or NULL (if there'd been no parent or if refcount decrement for parent hadn't reached 0). lock_for_kill() is adjusted for new requirements - it doesn't touch the parent's ->d_lock at all. Callers adjusted. Note that for dput() we don't need to bother with fast_dput() for the parent - we just need to check retain_dentry() for it, since its ->d_lock is still held since the moment when __dentry_kill() had taken it to remove the victim from the list of children. The kludge with early decrement of parent's refcount in shrink_dentry_list() is no longer needed - shrink_dcache_for_umount() sees the half-killed dentries in the list of children for as long as they are pinning the parent. They are easily recognized and accounted for by select_collect(), so we know we are not done yet. As the result, we always have the expected ordering for ->d_iput()/->d_release() vs. __dentry_kill() of the parent, no exceptions. Moreover, the current rules for shrink lists (one must make sure that shrink_dcache_for_umount() won't happen while any dentries from the superblock in question are on any shrink lists) are gone - shrink_dcache_for_umount() will do the right thing in all cases, taking such dentries out. Their empty husks (memory occupied by struct dentry itself + its external name, if any) will remain on the shrink lists, but they are no obstacles to filesystem shutdown. And such husks will get freed as soon as shrink_dentry_list() of the list they are on gets to them. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- Documentation/filesystems/porting.rst | 17 ++++ fs/dcache.c | 129 ++++++++++---------------- 2 files changed, 65 insertions(+), 81 deletions(-) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index da8073b592ff..d890ef07a9fd 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1078,3 +1078,20 @@ by compiler. ->d_delete() instances are now called for dentries with ->d_lock held and refcount equal to 0. They are not permitted to drop/regain ->d_lock. None of in-tree instances did anything of that sort. Make sure yours do not... + +-- + +**mandatory** + +->d_prune() instances are now called without ->d_lock held on the parent. +->d_lock on dentry itself is still held; if you need per-parent exclusions (none +of the in-tree instances did), use your own spinlock. + +->d_iput() and ->d_release() are called with victim dentry still in the +list of parent's children. It is still unhashed, marked killed, etc., just not +removed from parent's ->d_children yet. + +Anyone iterating through the list of children needs to be aware of the +half-killed dentries that might be seen there; taking ->d_lock on those will +see them negative, unhashed and with negative refcount, which means that most +of the in-kernel users would've done the right thing anyway without any adjustment. diff --git a/fs/dcache.c b/fs/dcache.c index a3cc612a80d5..c795154ffa3a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -575,12 +575,10 @@ static inline void dentry_unlist(struct dentry *dentry) } } -static void __dentry_kill(struct dentry *dentry) +static struct dentry *__dentry_kill(struct dentry *dentry) { struct dentry *parent = NULL; bool can_free = true; - if (!IS_ROOT(dentry)) - parent = dentry->d_parent; /* * The dentry is now unrecoverably dead to the world. @@ -600,9 +598,6 @@ static void __dentry_kill(struct dentry *dentry) } /* if it was on the hash then remove it */ __d_drop(dentry); - dentry_unlist(dentry); - if (parent) - spin_unlock(&parent->d_lock); if (dentry->d_inode) dentry_unlink_inode(dentry); else @@ -611,7 +606,14 @@ static void __dentry_kill(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - spin_lock(&dentry->d_lock); + cond_resched(); + /* now that it's negative, ->d_parent is stable */ + if (!IS_ROOT(dentry)) { + parent = dentry->d_parent; + spin_lock(&parent->d_lock); + } + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); + dentry_unlist(dentry); if (dentry->d_flags & DCACHE_SHRINK_LIST) { dentry->d_flags |= DCACHE_MAY_FREE; can_free = false; @@ -619,31 +621,10 @@ static void __dentry_kill(struct dentry *dentry) spin_unlock(&dentry->d_lock); if (likely(can_free)) dentry_free(dentry); - cond_resched(); -} - -static struct dentry *__lock_parent(struct dentry *dentry) -{ - struct dentry *parent; -again: - parent = READ_ONCE(dentry->d_parent); - spin_lock(&parent->d_lock); - /* - * We can't blindly lock dentry until we are sure - * that we won't violate the locking order. - * Any changes of dentry->d_parent must have - * been done with parent->d_lock held, so - * spin_lock() above is enough of a barrier - * for checking if it's still our child. - */ - if (unlikely(parent != dentry->d_parent)) { + if (parent && --parent->d_lockref.count) { spin_unlock(&parent->d_lock); - goto again; + return NULL; } - if (parent != dentry) - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - else - parent = NULL; return parent; } @@ -655,48 +636,32 @@ static struct dentry *__lock_parent(struct dentry *dentry) * d_delete(), etc. * * Return false if dentry is busy. Otherwise, return true and have - * that dentry's inode and parent both locked. + * that dentry's inode locked. */ static bool lock_for_kill(struct dentry *dentry) { struct inode *inode = dentry->d_inode; - struct dentry *parent = dentry->d_parent; if (unlikely(dentry->d_lockref.count)) return false; - if (inode && unlikely(!spin_trylock(&inode->i_lock))) - goto slow; - if (dentry == parent) - return true; - if (likely(spin_trylock(&parent->d_lock))) + if (!inode || likely(spin_trylock(&inode->i_lock))) return true; - if (inode) - spin_unlock(&inode->i_lock); -slow: - spin_unlock(&dentry->d_lock); - - for (;;) { - if (inode) - spin_lock(&inode->i_lock); - parent = __lock_parent(dentry); + do { + spin_unlock(&dentry->d_lock); + spin_lock(&inode->i_lock); + spin_lock(&dentry->d_lock); if (likely(inode == dentry->d_inode)) break; - if (inode) - spin_unlock(&inode->i_lock); + spin_unlock(&inode->i_lock); inode = dentry->d_inode; - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - } + } while (inode); if (likely(!dentry->d_lockref.count)) return true; if (inode) spin_unlock(&inode->i_lock); - if (parent) - spin_unlock(&parent->d_lock); return false; } @@ -869,29 +834,27 @@ static inline bool fast_dput(struct dentry *dentry) */ void dput(struct dentry *dentry) { - while (dentry) { - might_sleep(); - - rcu_read_lock(); - if (likely(fast_dput(dentry))) { - rcu_read_unlock(); + if (!dentry) + return; + might_sleep(); + rcu_read_lock(); + if (likely(fast_dput(dentry))) { + rcu_read_unlock(); + return; + } + while (lock_for_kill(dentry)) { + rcu_read_unlock(); + dentry = __dentry_kill(dentry); + if (!dentry) return; - } - - /* Slow case: now with the dentry lock held */ - if (likely(lock_for_kill(dentry))) { - struct dentry *parent = dentry->d_parent; - rcu_read_unlock(); - __dentry_kill(dentry); - if (dentry == parent) - return; - dentry = parent; - } else { - rcu_read_unlock(); + if (retain_dentry(dentry)) { spin_unlock(&dentry->d_lock); return; } + rcu_read_lock(); } + rcu_read_unlock(); + spin_unlock(&dentry->d_lock); } EXPORT_SYMBOL(dput); @@ -1091,12 +1054,16 @@ void d_prune_aliases(struct inode *inode) } EXPORT_SYMBOL(d_prune_aliases); -static inline void shrink_kill(struct dentry *victim, struct list_head *list) +static inline void shrink_kill(struct dentry *victim) { - struct dentry *parent = victim->d_parent; - if (parent != victim && !--parent->d_lockref.count) - to_shrink_list(parent, list); - __dentry_kill(victim); + do { + rcu_read_unlock(); + victim = __dentry_kill(victim); + rcu_read_lock(); + } while (victim && lock_for_kill(victim)); + rcu_read_unlock(); + if (victim) + spin_unlock(&victim->d_lock); } void shrink_dentry_list(struct list_head *list) @@ -1117,9 +1084,8 @@ void shrink_dentry_list(struct list_head *list) dentry_free(dentry); continue; } - rcu_read_unlock(); d_shrink_del(dentry); - shrink_kill(dentry, list); + shrink_kill(dentry); } } @@ -1478,6 +1444,8 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) } else if (!dentry->d_lockref.count) { to_shrink_list(dentry, &data->dispose); data->found++; + } else if (dentry->d_lockref.count < 0) { + data->found++; } /* * We can return to the caller if we have found some (this @@ -1547,8 +1515,7 @@ void shrink_dcache_parent(struct dentry *parent) spin_unlock(&data.victim->d_lock); rcu_read_unlock(); } else { - rcu_read_unlock(); - shrink_kill(data.victim, &data.dispose); + shrink_kill(data.victim); } } if (!list_empty(&data.dispose)) From 6367b491c17a34b28aece294bddfda1a36ec0377 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Nov 2023 17:33:21 -0500 Subject: [PATCH 1457/7721] retain_dentry(): introduce a trimmed-down lockless variant fast_dput() contains a small piece of code, preceded by scary comments about 5 times longer than it. What is actually done there is a trimmed-down subset of retain_dentry() - in some situations we can tell that retain_dentry() would have returned true without ever needing ->d_lock and that's what that code checks. If these checks come true fast_dput() can declare that we are done, without bothering with ->d_lock; otherwise it has to take the lock and do full variant of retain_dentry() checks. Trimmed-down variant of the checks is hard to follow and it's asking for trouble - if we ever decide to change the rules in retain_dentry(), we'll have to remember to update that code. It turns out that an equivalent variant of these checks more obviously parallel to retain_dentry() is not just possible, but easy to unify with retain_dentry() itself, passing it a new boolean argument ('locked') to distinguish between the full semantics and trimmed down one. Note that in lockless case true is returned only when locked variant would have returned true without ever needing the lock; false means "punt to the locking path and recheck there". Signed-off-by: Al Viro --- fs/dcache.c | 95 ++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index c795154ffa3a..b212a65ed190 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -665,30 +665,57 @@ static bool lock_for_kill(struct dentry *dentry) return false; } -static inline bool retain_dentry(struct dentry *dentry) +/* + * Decide if dentry is worth retaining. Usually this is called with dentry + * locked; if not locked, we are more limited and might not be able to tell + * without a lock. False in this case means "punt to locked path and recheck". + * + * In case we aren't locked, these predicates are not "stable". However, it is + * sufficient that at some point after we dropped the reference the dentry was + * hashed and the flags had the proper value. Other dentry users may have + * re-gotten a reference to the dentry and change that, but our work is done - + * we can leave the dentry around with a zero refcount. + */ +static inline bool retain_dentry(struct dentry *dentry, bool locked) { - WARN_ON(d_in_lookup(dentry)); + unsigned int d_flags; - /* Unreachable? Get rid of it */ + smp_rmb(); + d_flags = READ_ONCE(dentry->d_flags); + + // Unreachable? Nobody would be able to look it up, no point retaining if (unlikely(d_unhashed(dentry))) return false; - if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) + // Same if it's disconnected + if (unlikely(d_flags & DCACHE_DISCONNECTED)) return false; - if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) { - if (dentry->d_op->d_delete(dentry)) + // ->d_delete() might tell us not to bother, but that requires + // ->d_lock; can't decide without it + if (unlikely(d_flags & DCACHE_OP_DELETE)) { + if (!locked || dentry->d_op->d_delete(dentry)) return false; } - if (unlikely(dentry->d_flags & DCACHE_DONTCACHE)) + // Explicitly told not to bother + if (unlikely(d_flags & DCACHE_DONTCACHE)) return false; - /* retain; LRU fodder */ - if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) + // At this point it looks like we ought to keep it. We also might + // need to do something - put it on LRU if it wasn't there already + // and mark it referenced if it was on LRU, but not marked yet. + // Unfortunately, both actions require ->d_lock, so in lockless + // case we'd have to punt rather than doing those. + if (unlikely(!(d_flags & DCACHE_LRU_LIST))) { + if (!locked) + return false; d_lru_add(dentry); - else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED))) + } else if (unlikely(!(d_flags & DCACHE_REFERENCED))) { + if (!locked) + return false; dentry->d_flags |= DCACHE_REFERENCED; + } return true; } @@ -720,7 +747,6 @@ EXPORT_SYMBOL(d_mark_dontcache); static inline bool fast_dput(struct dentry *dentry) { int ret; - unsigned int d_flags; /* * try to decrement the lockref optimistically. @@ -749,45 +775,18 @@ static inline bool fast_dput(struct dentry *dentry) return true; /* - * Careful, careful. The reference count went down - * to zero, but we don't hold the dentry lock, so - * somebody else could get it again, and do another - * dput(), and we need to not race with that. - * - * However, there is a very special and common case - * where we don't care, because there is nothing to - * do: the dentry is still hashed, it does not have - * a 'delete' op, and it's referenced and already on - * the LRU list. - * - * NOTE! Since we aren't locked, these values are - * not "stable". However, it is sufficient that at - * some point after we dropped the reference the - * dentry was hashed and the flags had the proper - * value. Other dentry users may have re-gotten - * a reference to the dentry and change that, but - * our work is done - we can leave the dentry - * around with a zero refcount. - * - * Nevertheless, there are two cases that we should kill - * the dentry anyway. - * 1. free disconnected dentries as soon as their refcount - * reached zero. - * 2. free dentries if they should not be cached. + * Can we decide that decrement of refcount is all we needed without + * taking the lock? There's a very common case when it's all we need - + * dentry looks like it ought to be retained and there's nothing else + * to do. */ - smp_rmb(); - d_flags = READ_ONCE(dentry->d_flags); - d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_OP_DELETE | - DCACHE_DISCONNECTED | DCACHE_DONTCACHE; - - /* Nothing to do? Dropping the reference was all we needed? */ - if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry)) + if (retain_dentry(dentry, false)) return true; /* - * Not the fast normal case? Get the lock. We've already decremented - * the refcount, but we'll need to re-check the situation after - * getting the lock. + * Either not worth retaining or we can't tell without the lock. + * Get the lock, then. We've already decremented the refcount to 0, + * but we'll need to re-check the situation after getting the lock. */ spin_lock(&dentry->d_lock); @@ -798,7 +797,7 @@ static inline bool fast_dput(struct dentry *dentry) * don't need to do anything else. */ locked: - if (dentry->d_lockref.count || retain_dentry(dentry)) { + if (dentry->d_lockref.count || retain_dentry(dentry, true)) { spin_unlock(&dentry->d_lock); return true; } @@ -847,7 +846,7 @@ void dput(struct dentry *dentry) dentry = __dentry_kill(dentry); if (!dentry) return; - if (retain_dentry(dentry)) { + if (retain_dentry(dentry, true)) { spin_unlock(&dentry->d_lock); return; } From f2824db1b49f947ba6e208ddf02edf4b1391480a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Nov 2023 16:42:43 -0500 Subject: [PATCH 1458/7721] kill d_instantate_anon(), fold __d_instantiate_anon() into remaining caller now that the only user of d_instantiate_anon() is gone... [braino fix folded - kudos to Dan Carpenter] Signed-off-by: Al Viro --- fs/dcache.c | 92 +++++++++++++++++------------------------- include/linux/dcache.h | 1 - 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 9f5b2b5c1e6d..6c520eda131f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2054,75 +2054,55 @@ struct dentry *d_make_root(struct inode *root_inode) } EXPORT_SYMBOL(d_make_root); -static struct dentry *__d_instantiate_anon(struct dentry *dentry, - struct inode *inode, - bool disconnected) -{ - struct dentry *res; - unsigned add_flags; - - security_d_instantiate(dentry, inode); - spin_lock(&inode->i_lock); - res = __d_find_any_alias(inode); - if (res) { - spin_unlock(&inode->i_lock); - dput(dentry); - goto out_iput; - } - - /* attach a disconnected dentry */ - add_flags = d_flags_for_inode(inode); - - if (disconnected) - add_flags |= DCACHE_DISCONNECTED; - - spin_lock(&dentry->d_lock); - __d_set_inode_and_type(dentry, inode, add_flags); - hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); - if (!disconnected) { - hlist_bl_lock(&dentry->d_sb->s_roots); - hlist_bl_add_head(&dentry->d_hash, &dentry->d_sb->s_roots); - hlist_bl_unlock(&dentry->d_sb->s_roots); - } - spin_unlock(&dentry->d_lock); - spin_unlock(&inode->i_lock); - - return dentry; - - out_iput: - iput(inode); - return res; -} - -struct dentry *d_instantiate_anon(struct dentry *dentry, struct inode *inode) -{ - return __d_instantiate_anon(dentry, inode, true); -} -EXPORT_SYMBOL(d_instantiate_anon); - static struct dentry *__d_obtain_alias(struct inode *inode, bool disconnected) { - struct dentry *tmp; - struct dentry *res; + struct super_block *sb; + struct dentry *new, *res; if (!inode) return ERR_PTR(-ESTALE); if (IS_ERR(inode)) return ERR_CAST(inode); - res = d_find_any_alias(inode); - if (res) - goto out_iput; + sb = inode->i_sb; - tmp = d_alloc_anon(inode->i_sb); - if (!tmp) { + res = d_find_any_alias(inode); /* existing alias? */ + if (res) + goto out; + + new = d_alloc_anon(sb); + if (!new) { res = ERR_PTR(-ENOMEM); - goto out_iput; + goto out; } - return __d_instantiate_anon(tmp, inode, disconnected); + security_d_instantiate(new, inode); + spin_lock(&inode->i_lock); + res = __d_find_any_alias(inode); /* recheck under lock */ + if (likely(!res)) { /* still no alias, attach a disconnected dentry */ + unsigned add_flags = d_flags_for_inode(inode); -out_iput: + if (disconnected) + add_flags |= DCACHE_DISCONNECTED; + + spin_lock(&new->d_lock); + __d_set_inode_and_type(new, inode, add_flags); + hlist_add_head(&new->d_u.d_alias, &inode->i_dentry); + if (!disconnected) { + hlist_bl_lock(&sb->s_roots); + hlist_bl_add_head(&new->d_hash, &sb->s_roots); + hlist_bl_unlock(&sb->s_roots); + } + spin_unlock(&new->d_lock); + spin_unlock(&inode->i_lock); + inode = NULL; /* consumed by new->d_inode */ + res = new; + } else { + spin_unlock(&inode->i_lock); + dput(new); + } + + out: iput(inode); return res; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index fa0414cff85c..8c5e3bdf1147 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -218,7 +218,6 @@ extern seqlock_t rename_lock; */ extern void d_instantiate(struct dentry *, struct inode *); extern void d_instantiate_new(struct dentry *, struct inode *); -extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *); extern void __d_drop(struct dentry *dentry); extern void d_drop(struct dentry *dentry); extern void d_delete(struct dentry *); From 9024b4c96576162a13e58003b0d58e93ebe3ac33 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 12 Nov 2023 00:04:46 -0500 Subject: [PATCH 1459/7721] d_alloc_pseudo(): move setting ->d_op there from the (sole) caller Signed-off-by: Al Viro --- fs/dcache.c | 8 +++++++- fs/file_table.c | 5 ----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 6c520eda131f..5947556b6e90 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1890,9 +1890,15 @@ struct dentry *d_alloc_cursor(struct dentry * parent) */ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) { + static const struct dentry_operations anon_ops = { + .d_dname = simple_dname + }; struct dentry *dentry = __d_alloc(sb, name); - if (likely(dentry)) + if (likely(dentry)) { dentry->d_flags |= DCACHE_NORCU; + if (!sb->s_d_op) + d_set_d_op(dentry, &anon_ops); + } return dentry; } diff --git a/fs/file_table.c b/fs/file_table.c index de4a2915bfd4..8889cbee13f8 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -329,9 +329,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt, const char *name, int flags, const struct file_operations *fops) { - static const struct dentry_operations anon_ops = { - .d_dname = simple_dname - }; struct qstr this = QSTR_INIT(name, strlen(name)); struct path path; struct file *file; @@ -339,8 +336,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt, path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this); if (!path.dentry) return ERR_PTR(-ENOMEM); - if (!mnt->mnt_sb->s_d_op) - d_set_d_op(path.dentry, &anon_ops); path.mnt = mntget(mnt); d_instantiate(path.dentry, inode); file = alloc_file(&path, flags, fops); From fb7945b484b8a3c1e204c36eb9e4cf99f32141ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Nov 2023 16:50:29 -0500 Subject: [PATCH 1460/7721] nsfs: use d_make_root() Normally d_make_root() is used to create the root dentry of superblock; here we use it for a different purpose, but... idiomatic or not, we need the same operation. Signed-off-by: Al Viro --- fs/nsfs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/nsfs.c b/fs/nsfs.c index 9a4b228d42fa..34e1e3e36733 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -90,12 +90,9 @@ static int __ns_get_path(struct path *path, struct ns_common *ns) inode->i_fop = &ns_file_operations; inode->i_private = ns; - dentry = d_alloc_anon(mnt->mnt_sb); - if (!dentry) { - iput(inode); + dentry = d_make_root(inode); /* not the normal use, but... */ + if (!dentry) return -ENOMEM; - } - d_instantiate(dentry, inode); dentry->d_fsdata = (void *)ns->ops; d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); if (d) { From 715cd66aabf96b6cf423590954326799312c6dfa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 11 Nov 2023 15:56:55 -0500 Subject: [PATCH 1461/7721] simple_fill_super(): don't bother with d_genocide() on failure Failing ->fill_super() will be followed by ->kill_sb(), which should include kill_litter_super() if the call of simple_fill_super() had been asked to create anything besides the root dentry. So there's no need to empty the partially populated tree - it will be trimmed by inevitable kill_litter_super(). Signed-off-by: Al Viro --- fs/libfs.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index e9440d55073c..6fa8ad36049f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -912,7 +912,6 @@ int simple_fill_super(struct super_block *s, unsigned long magic, const struct tree_descr *files) { struct inode *inode; - struct dentry *root; struct dentry *dentry; int i; @@ -935,8 +934,8 @@ int simple_fill_super(struct super_block *s, unsigned long magic, inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); - root = d_make_root(inode); - if (!root) + s->s_root = d_make_root(inode); + if (!s->s_root) return -ENOMEM; for (i = 0; !files->name || files->name[0]; i++, files++) { if (!files->name) @@ -948,13 +947,13 @@ int simple_fill_super(struct super_block *s, unsigned long magic, "with an index of 1!\n", __func__, s->s_type->name); - dentry = d_alloc_name(root, files->name); + dentry = d_alloc_name(s->s_root, files->name); if (!dentry) - goto out; + return -ENOMEM; inode = new_inode(s); if (!inode) { dput(dentry); - goto out; + return -ENOMEM; } inode->i_mode = S_IFREG | files->mode; simple_inode_init_ts(inode); @@ -962,13 +961,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic, inode->i_ino = i; d_add(dentry, inode); } - s->s_root = root; return 0; -out: - d_genocide(root); - shrink_dcache_parent(root); - dput(root); - return -ENOMEM; } EXPORT_SYMBOL(simple_fill_super); From 8a54b38f3e5ced6cc4b246b8e54bd0f50deceaa8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 11 Nov 2023 16:01:27 -0500 Subject: [PATCH 1462/7721] d_genocide(): move the extern into fs/internal.h Signed-off-by: Al Viro --- fs/internal.h | 1 + include/linux/dcache.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index 9e9fc629f935..d9a920e2636e 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -219,6 +219,7 @@ extern void shrink_dcache_for_umount(struct super_block *); extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); extern struct dentry *__d_lookup_rcu(const struct dentry *parent, const struct qstr *name, unsigned *seq); +extern void d_genocide(struct dentry *); /* * pipe.c diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 8c5e3bdf1147..b4324d47f249 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -243,9 +243,6 @@ extern void d_invalidate(struct dentry *); /* only used at mount-time */ extern struct dentry * d_make_root(struct inode *); -/* - the ramfs-type tree */ -extern void d_genocide(struct dentry *); - extern void d_mark_tmpfile(struct file *, struct inode *); extern void d_tmpfile(struct file *, struct inode *); From 57851607326a2beef21e67f83f4f53a90df8445a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 12 Nov 2023 21:38:48 -0500 Subject: [PATCH 1463/7721] get rid of DCACHE_GENOCIDE ... now that we never call d_genocide() other than from kill_litter_super() Signed-off-by: Al Viro --- fs/dcache.c | 5 +---- include/linux/dcache.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 5947556b6e90..8473c8f0ce22 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3198,10 +3198,7 @@ static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry) if (d_unhashed(dentry) || !dentry->d_inode) return D_WALK_SKIP; - if (!(dentry->d_flags & DCACHE_GENOCIDE)) { - dentry->d_flags |= DCACHE_GENOCIDE; - dentry->d_lockref.count--; - } + dentry->d_lockref.count--; } return D_WALK_CONTINUE; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index b4324d47f249..981f529c6cb5 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -173,7 +173,6 @@ struct dentry_operations { #define DCACHE_DONTCACHE BIT(7) /* Purge from memory on final dput() */ #define DCACHE_CANT_MOUNT BIT(8) -#define DCACHE_GENOCIDE BIT(9) #define DCACHE_SHRINK_LIST BIT(10) #define DCACHE_OP_WEAK_REVALIDATE BIT(11) From f9f677c5f723394170fa838b856602476150948d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 12 Nov 2023 00:38:02 -0500 Subject: [PATCH 1464/7721] d_alloc_parallel(): in-lookup hash insertion doesn't need an RCU variant We only search in the damn thing under hlist_bl_lock(); RCU variant of insertion was, IIRC, pretty much cargo-culted - mea culpa... Signed-off-by: Al Viro --- fs/dcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index 8473c8f0ce22..82d086185703 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2692,7 +2692,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, /* we can't take ->d_lock here; it's OK, though. */ new->d_flags |= DCACHE_PAR_LOOKUP; new->d_wait = wq; - hlist_bl_add_head_rcu(&new->d_u.d_in_lookup_hash, b); + hlist_bl_add_head(&new->d_u.d_in_lookup_hash, b); hlist_bl_unlock(b); return new; mismatch: From ef69f0506d8f3a250ac5baa96746e17ae22c67b5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Nov 2023 18:11:00 -0500 Subject: [PATCH 1465/7721] __d_unalias() doesn't use inode argument ... and hasn't since 2015. Signed-off-by: Al Viro --- fs/dcache.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 82d086185703..74b2d073ebbf 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3045,8 +3045,7 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) * Note: If ever the locking in lock_rename() changes, then please * remember to update this too... */ -static int __d_unalias(struct inode *inode, - struct dentry *dentry, struct dentry *alias) +static int __d_unalias(struct dentry *dentry, struct dentry *alias) { struct mutex *m1 = NULL; struct rw_semaphore *m2 = NULL; @@ -3127,7 +3126,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) inode->i_sb->s_id); } else if (!IS_ROOT(new)) { struct dentry *old_parent = dget(new->d_parent); - int err = __d_unalias(inode, dentry, new); + int err = __d_unalias(dentry, new); write_sequnlock(&rename_lock); if (err) { dput(new); From 1b327b5ac57cf83e3d015de45d0142852f475375 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 10 Nov 2023 14:07:43 -0500 Subject: [PATCH 1466/7721] kill DCACHE_MAY_FREE With the new ordering in __dentry_kill() it has become redundant - it's set if and only if both DCACHE_DENTRY_KILLED and DCACHE_SHRINK_LIST are set. We set it in __dentry_kill(), after having set DCACHE_DENTRY_KILLED with the only condition being that DCACHE_SHRINK_LIST is there; all of that is done without dropping ->d_lock and the only place that checks that flag (shrink_dentry_list()) does so under ->d_lock, after having found the victim on its shrink list. Since DCACHE_SHRINK_LIST is set only when placing dentry into shrink list and removed only by shrink_dentry_list() itself, a check for DCACHE_DENTRY_KILLED in there would be equivalent to check for DCACHE_MAY_FREE. Signed-off-by: Al Viro --- fs/dcache.c | 6 ++---- include/linux/dcache.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 475ef1edba03..523cbf0780f0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -614,10 +614,8 @@ static struct dentry *__dentry_kill(struct dentry *dentry) } spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); dentry_unlist(dentry); - if (dentry->d_flags & DCACHE_SHRINK_LIST) { - dentry->d_flags |= DCACHE_MAY_FREE; + if (dentry->d_flags & DCACHE_SHRINK_LIST) can_free = false; - } spin_unlock(&dentry->d_lock); if (likely(can_free)) dentry_free(dentry); @@ -1072,7 +1070,7 @@ void shrink_dentry_list(struct list_head *list) bool can_free; rcu_read_unlock(); d_shrink_del(dentry); - can_free = dentry->d_flags & DCACHE_MAY_FREE; + can_free = dentry->d_flags & DCACHE_DENTRY_KILLED; spin_unlock(&dentry->d_lock); if (can_free) dentry_free(dentry); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index b4449a1a47ff..48b393545ec2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -202,7 +202,6 @@ struct dentry_operations { #define DCACHE_SPECIAL_TYPE (5 << 20) /* Other file type */ #define DCACHE_SYMLINK_TYPE (6 << 20) /* Symlink */ -#define DCACHE_MAY_FREE BIT(23) #define DCACHE_NOKEY_NAME BIT(25) /* Encrypted name encoded without key */ #define DCACHE_OP_REAL BIT(26) From 1b6ae9f6e6c3e3c35aad0f11b116a81780b8aa03 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Mon, 6 Nov 2023 14:44:17 +0100 Subject: [PATCH 1467/7721] dcache: remove unnecessary NULL check in dget_dlock() dget_dlock() requires dentry->d_lock to be held when called, yet contains a NULL check for dentry. An audit of all calls to dget_dlock() shows that it is never called with a NULL pointer (as spin_lock()/spin_unlock() would crash in these cases): $ git grep -W '\' arch/powerpc/platforms/cell/spufs/inode.c- spin_lock(&dentry->d_lock); arch/powerpc/platforms/cell/spufs/inode.c- if (simple_positive(dentry)) { arch/powerpc/platforms/cell/spufs/inode.c: dget_dlock(dentry); fs/autofs/expire.c- spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); fs/autofs/expire.c- if (simple_positive(child)) { fs/autofs/expire.c: dget_dlock(child); fs/autofs/root.c: dget_dlock(active); fs/autofs/root.c- spin_unlock(&active->d_lock); fs/autofs/root.c: dget_dlock(expiring); fs/autofs/root.c- spin_unlock(&expiring->d_lock); fs/ceph/dir.c- if (!spin_trylock(&dentry->d_lock)) fs/ceph/dir.c- continue; [...] fs/ceph/dir.c: dget_dlock(dentry); fs/ceph/mds_client.c- spin_lock(&alias->d_lock); [...] fs/ceph/mds_client.c: dn = dget_dlock(alias); fs/configfs/inode.c- spin_lock(&dentry->d_lock); fs/configfs/inode.c- if (simple_positive(dentry)) { fs/configfs/inode.c: dget_dlock(dentry); fs/libfs.c: found = dget_dlock(d); fs/libfs.c- spin_unlock(&d->d_lock); fs/libfs.c: found = dget_dlock(child); fs/libfs.c- spin_unlock(&child->d_lock); fs/libfs.c: child = dget_dlock(d); fs/libfs.c- spin_unlock(&d->d_lock); fs/ocfs2/dcache.c: dget_dlock(dentry); fs/ocfs2/dcache.c- spin_unlock(&dentry->d_lock); include/linux/dcache.h:static inline struct dentry *dget_dlock(struct dentry *dentry) After taking out the NULL check, dget_dlock() becomes almost identical to __dget_dlock(); the only difference is that dget_dlock() returns the dentry that was passed in. These are static inline helpers, so we can rely on the compiler to discard unused return values. We can therefore also remove __dget_dlock() and replace calls to it by dget_dlock(). Also fix up and improve the kerneldoc comments while we're at it. Al Viro pointed out that we can also clean up some of the callers to make use of the returned value and provided a bit more info for the kerneldoc. While preparing v2 I also noticed that the tabs used in the kerneldoc comments were causing the kerneldoc to get parsed incorrectly so I also fixed this up (including for d_unhashed, which is otherwise unrelated). Testing: x86 defconfig build + boot; make htmldocs for the kerneldoc warning. objdump shows there are code generation changes. Link: https://lore.kernel.org/all/20231022164520.915013-1-vegard.nossum@oracle.com/ Cc: Alexander Viro Cc: Christian Brauner Cc: linux-fsdevel@vger.kernel.org Cc: Nick Piggin Cc: Waiman Long Cc: linux-doc@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Al Viro --- fs/dcache.c | 16 ++++------------ include/linux/dcache.h | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 523cbf0780f0..bb18ea91d717 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -877,12 +877,6 @@ void dput_to_list(struct dentry *dentry, struct list_head *list) spin_unlock(&dentry->d_lock); } -/* This must be called with d_lock held */ -static inline void __dget_dlock(struct dentry *dentry) -{ - dentry->d_lockref.count++; -} - struct dentry *dget_parent(struct dentry *dentry) { int gotref; @@ -964,7 +958,7 @@ static struct dentry *__d_find_alias(struct inode *inode) hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { spin_lock(&alias->d_lock); if (!d_unhashed(alias)) { - __dget_dlock(alias); + dget_dlock(alias); spin_unlock(&alias->d_lock); return alias; } @@ -1569,8 +1563,7 @@ static enum d_walk_ret find_submount(void *_data, struct dentry *dentry) { struct dentry **victim = _data; if (d_mountpoint(dentry)) { - __dget_dlock(dentry); - *victim = dentry; + *victim = dget_dlock(dentry); return D_WALK_QUIT; } return D_WALK_CONTINUE; @@ -1715,8 +1708,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) * don't need child lock because it is not subject * to concurrency here */ - __dget_dlock(parent); - dentry->d_parent = parent; + dentry->d_parent = dget_dlock(parent); hlist_add_head(&dentry->d_sib, &parent->d_children); spin_unlock(&parent->d_lock); @@ -2683,7 +2675,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) spin_unlock(&alias->d_lock); alias = NULL; } else { - __dget_dlock(alias); + dget_dlock(alias); __d_rehash(alias); spin_unlock(&alias->d_lock); } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 48b393545ec2..1666c387861f 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -287,20 +287,40 @@ extern char *dentry_path(const struct dentry *, char *, int); /* Allocation counts.. */ /** - * dget, dget_dlock - get a reference to a dentry - * @dentry: dentry to get a reference to + * dget_dlock - get a reference to a dentry + * @dentry: dentry to get a reference to * - * Given a dentry or %NULL pointer increment the reference count - * if appropriate and return the dentry. A dentry will not be - * destroyed when it has references. + * Given a live dentry, increment the reference count and return the dentry. + * Caller must hold @dentry->d_lock. Making sure that dentry is alive is + * caller's resonsibility. There are many conditions sufficient to guarantee + * that; e.g. anything with non-negative refcount is alive, so's anything + * hashed, anything positive, anyone's parent, etc. */ static inline struct dentry *dget_dlock(struct dentry *dentry) { - if (dentry) - dentry->d_lockref.count++; + dentry->d_lockref.count++; return dentry; } + +/** + * dget - get a reference to a dentry + * @dentry: dentry to get a reference to + * + * Given a dentry or %NULL pointer increment the reference count + * if appropriate and return the dentry. A dentry will not be + * destroyed when it has references. Conversely, a dentry with + * no references can disappear for any number of reasons, starting + * with memory pressure. In other words, that primitive is + * used to clone an existing reference; using it on something with + * zero refcount is a bug. + * + * NOTE: it will spin if @dentry->d_lock is held. From the deadlock + * avoidance point of view it is equivalent to spin_lock()/increment + * refcount/spin_unlock(), so calling it under @dentry->d_lock is + * always a bug; so's calling it under ->d_lock on any of its descendents. + * + */ static inline struct dentry *dget(struct dentry *dentry) { if (dentry) @@ -311,12 +331,11 @@ static inline struct dentry *dget(struct dentry *dentry) extern struct dentry *dget_parent(struct dentry *dentry); /** - * d_unhashed - is dentry hashed - * @dentry: entry to check + * d_unhashed - is dentry hashed + * @dentry: entry to check * - * Returns true if the dentry passed is not currently hashed. + * Returns true if the dentry passed is not currently hashed. */ - static inline int d_unhashed(const struct dentry *dentry) { return hlist_bl_unhashed(&dentry->d_hash); From 49db9b1b86a82448dfaf3fcfefcf678dee56c8ed Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Oct 2023 23:14:20 +0200 Subject: [PATCH 1468/7721] reiserfs: Avoid touching renamed directory if parent does not change The VFS will not be locking moved directory if its parent does not change. Change reiserfs rename code to avoid touching renamed directory if its parent does not change as without locking that can corrupt the filesystem. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/reiserfs/namei.c | 54 ++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 994d6e6995ab..5996197ba40c 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1324,8 +1324,8 @@ static int reiserfs_rename(struct mnt_idmap *idmap, struct inode *old_inode, *new_dentry_inode; struct reiserfs_transaction_handle th; int jbegin_count; - umode_t old_inode_mode; unsigned long savelink = 1; + bool update_dir_parent = false; if (flags & ~RENAME_NOREPLACE) return -EINVAL; @@ -1375,8 +1375,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap, return -ENOENT; } - old_inode_mode = old_inode->i_mode; - if (S_ISDIR(old_inode_mode)) { + if (S_ISDIR(old_inode->i_mode)) { /* * make sure that directory being renamed has correct ".." * and that its new parent directory has not too many links @@ -1389,24 +1388,28 @@ static int reiserfs_rename(struct mnt_idmap *idmap, } } - /* - * directory is renamed, its parent directory will be changed, - * so find ".." entry - */ - dot_dot_de.de_gen_number_bit_string = NULL; - retval = - reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path, + if (old_dir != new_dir) { + /* + * directory is renamed, its parent directory will be + * changed, so find ".." entry + */ + dot_dot_de.de_gen_number_bit_string = NULL; + retval = + reiserfs_find_entry(old_inode, "..", 2, + &dot_dot_entry_path, &dot_dot_de); - pathrelse(&dot_dot_entry_path); - if (retval != NAME_FOUND) { - reiserfs_write_unlock(old_dir->i_sb); - return -EIO; - } + pathrelse(&dot_dot_entry_path); + if (retval != NAME_FOUND) { + reiserfs_write_unlock(old_dir->i_sb); + return -EIO; + } - /* inode number of .. must equal old_dir->i_ino */ - if (dot_dot_de.de_objectid != old_dir->i_ino) { - reiserfs_write_unlock(old_dir->i_sb); - return -EIO; + /* inode number of .. must equal old_dir->i_ino */ + if (dot_dot_de.de_objectid != old_dir->i_ino) { + reiserfs_write_unlock(old_dir->i_sb); + return -EIO; + } + update_dir_parent = true; } } @@ -1486,7 +1489,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap, reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1); - if (S_ISDIR(old_inode->i_mode)) { + if (update_dir_parent) { if ((retval = search_by_entry_key(new_dir->i_sb, &dot_dot_de.de_entry_key, @@ -1534,14 +1537,14 @@ static int reiserfs_rename(struct mnt_idmap *idmap, new_de.de_bh); reiserfs_restore_prepared_buffer(old_inode->i_sb, old_de.de_bh); - if (S_ISDIR(old_inode_mode)) + if (update_dir_parent) reiserfs_restore_prepared_buffer(old_inode-> i_sb, dot_dot_de. de_bh); continue; } - if (S_ISDIR(old_inode_mode)) { + if (update_dir_parent) { if (item_moved(&dot_dot_ih, &dot_dot_entry_path) || !entry_points_to_object("..", 2, &dot_dot_de, old_dir)) { @@ -1559,7 +1562,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap, } } - RFALSE(S_ISDIR(old_inode_mode) && + RFALSE(update_dir_parent && !buffer_journal_prepared(dot_dot_de.de_bh), ""); break; @@ -1592,11 +1595,12 @@ static int reiserfs_rename(struct mnt_idmap *idmap, savelink = new_dentry_inode->i_nlink; } - if (S_ISDIR(old_inode_mode)) { + if (update_dir_parent) { /* adjust ".." of renamed directory */ set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir)); journal_mark_dirty(&th, dot_dot_de.de_bh); - + } + if (S_ISDIR(old_inode->i_mode)) { /* * there (in new_dir) was no directory, so it got new link * (".." of renamed directory) From 9d618d19b29c2943527e3a43da0a35aea91062fc Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Oct 2023 23:14:21 +0200 Subject: [PATCH 1469/7721] ocfs2: Avoid touching renamed directory if parent does not change The VFS will not be locking moved directory if its parent does not change. Change ocfs2 rename code to avoid touching renamed directory if its parent does not change as without locking that can corrupt the filesystem. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/ocfs2/namei.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 814733ba2f4b..9221a33f917b 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1336,7 +1336,7 @@ static int ocfs2_rename(struct mnt_idmap *idmap, goto bail; } - if (S_ISDIR(old_inode->i_mode)) { + if (S_ISDIR(old_inode->i_mode) && new_dir != old_dir) { u64 old_inode_parent; update_dot_dot = 1; @@ -1353,8 +1353,7 @@ static int ocfs2_rename(struct mnt_idmap *idmap, goto bail; } - if (!new_inode && new_dir != old_dir && - new_dir->i_nlink >= ocfs2_link_max(osb)) { + if (!new_inode && new_dir->i_nlink >= ocfs2_link_max(osb)) { status = -EMLINK; goto bail; } @@ -1601,6 +1600,9 @@ static int ocfs2_rename(struct mnt_idmap *idmap, mlog_errno(status); goto bail; } + } + + if (S_ISDIR(old_inode->i_mode)) { drop_nlink(old_dir); if (new_inode) { drop_nlink(new_inode); From 9d35cebb794bb7be93db76c3383979c7deacfef9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Oct 2023 14:44:23 -0400 Subject: [PATCH 1470/7721] udf_rename(): only access the child content on cross-directory rename We can't really afford locking the source on same-directory rename; currently vfs_rename() tries to do that, but it will have to be changed. The logics in udf_rename() is lazy and goes looking for ".." in source even in same-directory case. It's not hard to get rid of that, leaving that behaviour only for cross-directory case; that VFS can get locks safely (and will keep doing that after the coming changes). Reviewed-by: Jan Kara Signed-off-by: Al Viro --- fs/udf/namei.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 3508ac484da3..fac806a7a8d4 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -766,7 +766,7 @@ static int udf_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); struct udf_fileident_iter oiter, niter, diriter; - bool has_diriter = false; + bool has_diriter = false, is_dir = false; int retval; struct kernel_lb_addr tloc; @@ -789,6 +789,9 @@ static int udf_rename(struct mnt_idmap *idmap, struct inode *old_dir, if (!empty_dir(new_inode)) goto out_oiter; } + is_dir = true; + } + if (is_dir && old_dir != new_dir) { retval = udf_fiiter_find_entry(old_inode, &dotdot_name, &diriter); if (retval == -ENOENT) { @@ -878,7 +881,9 @@ static int udf_rename(struct mnt_idmap *idmap, struct inode *old_dir, udf_dir_entry_len(&diriter.fi)); udf_fiiter_write_fi(&diriter, NULL); udf_fiiter_release(&diriter); + } + if (is_dir) { inode_dec_link_count(old_dir); if (new_inode) inode_dec_link_count(new_inode); From 7307b73fa5a82661808b5541972176c344978789 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Oct 2023 23:14:22 +0200 Subject: [PATCH 1471/7721] ext2: Avoid reading renamed directory if parent does not change The VFS will not be locking moved directory if its parent does not change. Change ext2 rename code to avoid reading renamed directory if its parent does not change. Although it is currently harmless it is a bad practice to read directory contents without inode->i_rwsem. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/ext2/namei.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 65f702b1da5b..8346ab9534c1 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -325,6 +325,7 @@ static int ext2_rename (struct mnt_idmap * idmap, struct ext2_dir_entry_2 * dir_de = NULL; struct folio * old_folio; struct ext2_dir_entry_2 * old_de; + bool old_is_dir = S_ISDIR(old_inode->i_mode); int err; if (flags & ~RENAME_NOREPLACE) @@ -342,7 +343,7 @@ static int ext2_rename (struct mnt_idmap * idmap, if (IS_ERR(old_de)) return PTR_ERR(old_de); - if (S_ISDIR(old_inode->i_mode)) { + if (old_is_dir && old_dir != new_dir) { err = -EIO; dir_de = ext2_dotdot(old_inode, &dir_folio); if (!dir_de) @@ -354,7 +355,7 @@ static int ext2_rename (struct mnt_idmap * idmap, struct ext2_dir_entry_2 *new_de; err = -ENOTEMPTY; - if (dir_de && !ext2_empty_dir (new_inode)) + if (old_is_dir && !ext2_empty_dir(new_inode)) goto out_dir; new_de = ext2_find_entry(new_dir, &new_dentry->d_name, @@ -368,14 +369,14 @@ static int ext2_rename (struct mnt_idmap * idmap, if (err) goto out_dir; inode_set_ctime_current(new_inode); - if (dir_de) + if (old_is_dir) drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { err = ext2_add_link(new_dentry, old_inode); if (err) goto out_dir; - if (dir_de) + if (old_is_dir) inode_inc_link_count(new_dir); } @@ -387,7 +388,7 @@ static int ext2_rename (struct mnt_idmap * idmap, mark_inode_dirty(old_inode); err = ext2_delete_entry(old_de, old_folio); - if (!err && dir_de) { + if (!err && old_is_dir) { if (old_dir != new_dir) err = ext2_set_link(old_inode, dir_de, dir_folio, new_dir, false); From 40dbd071f4b19d9630353c3cd45c2d6adb6799d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Oct 2023 14:55:42 -0400 Subject: [PATCH 1472/7721] ext4: don't access the source subdirectory content on same-directory rename We can't really afford locking the source on same-directory rename; currently vfs_rename() tries to do that, but it will have to be changed. The logics in ext4 is lazy and goes looking for ".." in source even in same-directory case. It's not hard to get rid of that, leaving that behaviour only for cross-directory case; that VFS can get locks safely (and will keep doing that after the coming changes). Reviewed-by: Jan Kara Signed-off-by: Al Viro --- fs/ext4/namei.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d252935f9c8a..467ba47a691c 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3591,10 +3591,14 @@ struct ext4_renament { int dir_inlined; }; -static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent) +static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent, bool is_cross) { int retval; + ent->is_dir = true; + if (!is_cross) + return 0; + ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode, &retval, &ent->parent_de, &ent->dir_inlined); @@ -3612,6 +3616,9 @@ static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent, { int retval; + if (!ent->dir_bh) + return 0; + ent->parent_de->inode = cpu_to_le32(dir_ino); BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata"); if (!ent->dir_inlined) { @@ -3900,7 +3907,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir, if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir)) goto end_rename; } - retval = ext4_rename_dir_prepare(handle, &old); + retval = ext4_rename_dir_prepare(handle, &old, new.dir != old.dir); if (retval) goto end_rename; } @@ -3964,7 +3971,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir, } inode_set_mtime_to_ts(old.dir, inode_set_ctime_current(old.dir)); ext4_update_dx_flag(old.dir); - if (old.dir_bh) { + if (old.is_dir) { retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); if (retval) goto end_rename; @@ -3987,7 +3994,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir, if (unlikely(retval)) goto end_rename; - if (S_ISDIR(old.inode->i_mode)) { + if (old.is_dir) { /* * We disable fast commits here that's because the * replay code is not yet capable of changing dot dot @@ -4114,14 +4121,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ext4_handle_sync(handle); if (S_ISDIR(old.inode->i_mode)) { - old.is_dir = true; - retval = ext4_rename_dir_prepare(handle, &old); + retval = ext4_rename_dir_prepare(handle, &old, new.dir != old.dir); if (retval) goto end_rename; } if (S_ISDIR(new.inode->i_mode)) { - new.is_dir = true; - retval = ext4_rename_dir_prepare(handle, &new); + retval = ext4_rename_dir_prepare(handle, &new, new.dir != old.dir); if (retval) goto end_rename; } From 7deee77b993a2234acb123b8ec477bd56f2e3be3 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Oct 2023 23:14:23 +0200 Subject: [PATCH 1473/7721] f2fs: Avoid reading renamed directory if parent does not change The VFS will not be locking moved directory if its parent does not change. Change f2fs rename code to avoid reading renamed directory if its parent does not change. Having it uninlined while we are reading it would cause trouble and we won't be able to rely upon ->i_rwsem on the directory being renamed in cases that do not alter its parent. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/f2fs/namei.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index d0053b0284d8..fdc97df6bb85 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -963,6 +963,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; + bool old_is_dir = S_ISDIR(old_inode->i_mode); int err; if (unlikely(f2fs_cp_error(sbi))) @@ -1017,7 +1018,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, goto out; } - if (S_ISDIR(old_inode->i_mode)) { + if (old_is_dir && old_dir != new_dir) { old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); if (!old_dir_entry) { if (IS_ERR(old_dir_page)) @@ -1029,7 +1030,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, if (new_inode) { err = -ENOTEMPTY; - if (old_dir_entry && !f2fs_empty_dir(new_inode)) + if (old_is_dir && !f2fs_empty_dir(new_inode)) goto out_dir; err = -ENOENT; @@ -1054,7 +1055,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, inode_set_ctime_current(new_inode); f2fs_down_write(&F2FS_I(new_inode)->i_sem); - if (old_dir_entry) + if (old_is_dir) f2fs_i_links_write(new_inode, false); f2fs_i_links_write(new_inode, false); f2fs_up_write(&F2FS_I(new_inode)->i_sem); @@ -1074,12 +1075,12 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, goto out_dir; } - if (old_dir_entry) + if (old_is_dir) f2fs_i_links_write(new_dir, true); } f2fs_down_write(&F2FS_I(old_inode)->i_sem); - if (!old_dir_entry || whiteout) + if (!old_is_dir || whiteout) file_lost_pino(old_inode); else /* adjust dir's i_pino to pass fsck check */ @@ -1105,8 +1106,8 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, iput(whiteout); } - if (old_dir_entry) { - if (old_dir != new_dir && !whiteout) + if (old_is_dir) { + if (old_dir_entry && !whiteout) f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); else From 22e111ed6c83dcde3037fc81176012721bc34c0b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 19 Nov 2023 20:25:58 -0500 Subject: [PATCH 1474/7721] rename(): fix the locking of subdirectories We should never lock two subdirectories without having taken ->s_vfs_rename_mutex; inode pointer order or not, the "order" proposed in 28eceeda130f "fs: Lock moved directories" is not transitive, with the usual consequences. The rationale for locking renamed subdirectory in all cases was the possibility of race between rename modifying .. in a subdirectory to reflect the new parent and another thread modifying the same subdirectory. For a lot of filesystems that's not a problem, but for some it can lead to trouble (e.g. the case when short directory contents is kept in the inode, but creating a file in it might push it across the size limit and copy its contents into separate data block(s)). However, we need that only in case when the parent does change - otherwise ->rename() doesn't need to do anything with .. entry in the first place. Some instances are lazy and do a tautological update anyway, but it's really not hard to avoid. Amended locking rules for rename(): find the parent(s) of source and target if source and target have the same parent lock the common parent else lock ->s_vfs_rename_mutex lock both parents, in ancestor-first order; if neither is an ancestor of another, lock the parent of source first. find the source and target. if source and target have the same parent if operation is an overwriting rename of a subdirectory lock the target subdirectory else if source is a subdirectory lock the source if target is a subdirectory lock the target lock non-directories involved, in inode pointer order if both source and target are such. That way we are guaranteed that parents are locked (for obvious reasons), that any renamed non-directory is locked (nfsd relies upon that), that any victim is locked (emptiness check needs that, among other things) and subdirectory that changes parent is locked (needed to protect the update of .. entries). We are also guaranteed that any operation locking more than one directory either takes ->s_vfs_rename_mutex or locks a parent followed by its child. Cc: stable@vger.kernel.org Fixes: 28eceeda130f "fs: Lock moved directories" Reviewed-by: Jan Kara Signed-off-by: Al Viro --- .../filesystems/directory-locking.rst | 29 ++++----- Documentation/filesystems/locking.rst | 5 +- Documentation/filesystems/porting.rst | 18 ++++++ fs/namei.c | 60 ++++++++++++------- 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/Documentation/filesystems/directory-locking.rst b/Documentation/filesystems/directory-locking.rst index dccd61c7c5c3..193c22687851 100644 --- a/Documentation/filesystems/directory-locking.rst +++ b/Documentation/filesystems/directory-locking.rst @@ -22,13 +22,16 @@ exclusive. 3) object removal. Locking rules: caller locks parent, finds victim, locks victim and calls the method. Locks are exclusive. -4) rename() that is _not_ cross-directory. Locking rules: caller locks the -parent and finds source and target. We lock both (provided they exist). If we -need to lock two inodes of different type (dir vs non-dir), we lock directory -first. If we need to lock two inodes of the same type, lock them in inode -pointer order. Then call the method. All locks are exclusive. -NB: we might get away with locking the source (and target in exchange -case) shared. +4) rename() that is _not_ cross-directory. Locking rules: caller locks +the parent and finds source and target. Then we decide which of the +source and target need to be locked. Source needs to be locked if it's a +non-directory; target - if it's a non-directory or about to be removed. +Take the locks that need to be taken, in inode pointer order if need +to take both (that can happen only when both source and target are +non-directories - the source because it wouldn't be locked otherwise +and the target because mixing directory and non-directory is allowed +only with RENAME_EXCHANGE, and that won't be removing the target). +After the locks had been taken, call the method. All locks are exclusive. 5) link creation. Locking rules: @@ -44,20 +47,17 @@ rules: * lock the filesystem * lock parents in "ancestors first" order. If one is not ancestor of - the other, lock them in inode pointer order. + the other, lock the parent of source first. * find source and target. * if old parent is equal to or is a descendent of target fail with -ENOTEMPTY * if new parent is equal to or is a descendent of source fail with -ELOOP - * Lock both the source and the target provided they exist. If we - need to lock two inodes of different type (dir vs non-dir), we lock - the directory first. If we need to lock two inodes of the same type, - lock them in inode pointer order. + * Lock subdirectories involved (source before target). + * Lock non-directories involved, in inode pointer order. * call the method. -All ->i_rwsem are taken exclusive. Again, we might get away with locking -the source (and target in exchange case) shared. +All ->i_rwsem are taken exclusive. The rules above obviously guarantee that all directories that are going to be read, modified or removed by method will be locked by caller. @@ -67,6 +67,7 @@ If no directory is its own ancestor, the scheme above is deadlock-free. Proof: +[XXX: will be updated once we are done massaging the lock_rename()] First of all, at any moment we have a linear ordering of the objects - A < B iff (A is an ancestor of B) or (B is not an ancestor of A and ptr(A) < ptr(B)). diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index 7be2900806c8..bd12f2f850ad 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -101,7 +101,7 @@ symlink: exclusive mkdir: exclusive unlink: exclusive (both) rmdir: exclusive (both)(see below) -rename: exclusive (all) (see below) +rename: exclusive (both parents, some children) (see below) readlink: no get_link: no setattr: exclusive @@ -123,6 +123,9 @@ get_offset_ctx no Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem exclusive on victim. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. + ->unlink() and ->rename() have ->i_rwsem exclusive on all non-directories + involved. + ->rename() has ->i_rwsem exclusive on any subdirectory that changes parent. See Documentation/filesystems/directory-locking.rst for more detailed discussion of the locking scheme for directory operations. diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 878e72b2f8b7..9100969e7de6 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1061,3 +1061,21 @@ export_operations ->encode_fh() no longer has a default implementation to encode FILEID_INO32_GEN* file handles. Filesystems that used the default implementation may use the generic helper generic_encode_ino32_fh() explicitly. + +--- + +**mandatory** + +If ->rename() update of .. on cross-directory move needs an exclusion with +directory modifications, do *not* lock the subdirectory in question in your +->rename() - it's done by the caller now [that item should've been added in +28eceeda130f "fs: Lock moved directories"]. + +--- + +**mandatory** + +On same-directory ->rename() the (tautological) update of .. is not protected +by any locks; just don't do it if the old parent is the same as the new one. +We really can't lock two subdirectories in same-directory rename - not without +deadlocks. diff --git a/fs/namei.c b/fs/namei.c index 71c13b2990b4..29bafbdb44ca 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3021,20 +3021,14 @@ static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2) p = d_ancestor(p2, p1); if (p) { inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p1->d_inode, I_MUTEX_CHILD); + inode_lock_nested(p1->d_inode, I_MUTEX_PARENT2); return p; } p = d_ancestor(p1, p2); - if (p) { - inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p2->d_inode, I_MUTEX_CHILD); - return p; - } - - lock_two_inodes(p1->d_inode, p2->d_inode, - I_MUTEX_PARENT, I_MUTEX_PARENT2); - return NULL; + inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); + inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); + return p; } /* @@ -4716,11 +4710,12 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname * * a) we can get into loop creation. * b) race potential - two innocent renames can create a loop together. - * That's where 4.4 screws up. Current fix: serialization on + * That's where 4.4BSD screws up. Current fix: serialization on * sb->s_vfs_rename_mutex. We might be more accurate, but that's another * story. - * c) we have to lock _four_ objects - parents and victim (if it exists), - * and source. + * c) we may have to lock up to _four_ objects - parents and victim (if it exists), + * and source (if it's a non-directory or a subdirectory that moves to + * different parent). * And that - after we got ->i_mutex on parents (until then we don't know * whether the target exists). Solution: try to be smart with locking * order for inodes. We rely on the fact that tree topology may change @@ -4752,6 +4747,7 @@ int vfs_rename(struct renamedata *rd) bool new_is_dir = false; unsigned max_links = new_dir->i_sb->s_max_links; struct name_snapshot old_name; + bool lock_old_subdir, lock_new_subdir; if (source == target) return 0; @@ -4805,15 +4801,32 @@ int vfs_rename(struct renamedata *rd) take_dentry_name_snapshot(&old_name, old_dentry); dget(new_dentry); /* - * Lock all moved children. Moved directories may need to change parent - * pointer so they need the lock to prevent against concurrent - * directory changes moving parent pointer. For regular files we've - * historically always done this. The lockdep locking subclasses are - * somewhat arbitrary but RENAME_EXCHANGE in particular can swap - * regular files and directories so it's difficult to tell which - * subclasses to use. + * Lock children. + * The source subdirectory needs to be locked on cross-directory + * rename or cross-directory exchange since its parent changes. + * The target subdirectory needs to be locked on cross-directory + * exchange due to parent change and on any rename due to becoming + * a victim. + * Non-directories need locking in all cases (for NFS reasons); + * they get locked after any subdirectories (in inode address order). + * + * NOTE: WE ONLY LOCK UNRELATED DIRECTORIES IN CROSS-DIRECTORY CASE. + * NEVER, EVER DO THAT WITHOUT ->s_vfs_rename_mutex. */ - lock_two_inodes(source, target, I_MUTEX_NORMAL, I_MUTEX_NONDIR2); + lock_old_subdir = new_dir != old_dir; + lock_new_subdir = new_dir != old_dir || !(flags & RENAME_EXCHANGE); + if (is_dir) { + if (lock_old_subdir) + inode_lock_nested(source, I_MUTEX_CHILD); + if (target && (!new_is_dir || lock_new_subdir)) + inode_lock(target); + } else if (new_is_dir) { + if (lock_new_subdir) + inode_lock_nested(target, I_MUTEX_CHILD); + inode_lock(source); + } else { + lock_two_nondirectories(source, target); + } error = -EPERM; if (IS_SWAPFILE(source) || (target && IS_SWAPFILE(target))) @@ -4861,8 +4874,9 @@ int vfs_rename(struct renamedata *rd) d_exchange(old_dentry, new_dentry); } out: - inode_unlock(source); - if (target) + if (!is_dir || lock_old_subdir) + inode_unlock(source); + if (target && (!new_is_dir || lock_new_subdir)) inode_unlock(target); dput(new_dentry); if (!error) { From dbd4540df2b2857a91593754275c02f3e415fc30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 19 Nov 2023 22:21:00 -0500 Subject: [PATCH 1475/7721] kill lock_two_inodes() There's only one caller left (lock_two_nondirectories()), and it needs less complexity. Fold lock_two_inodes() in there and simplify. Reviewed-by: Jan Kara Signed-off-by: Al Viro --- fs/inode.c | 49 ++++++------------------------------------------- fs/internal.h | 2 -- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index edcd8a61975f..453d5be1a014 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1087,48 +1087,6 @@ void discard_new_inode(struct inode *inode) } EXPORT_SYMBOL(discard_new_inode); -/** - * lock_two_inodes - lock two inodes (may be regular files but also dirs) - * - * Lock any non-NULL argument. The caller must make sure that if he is passing - * in two directories, one is not ancestor of the other. Zero, one or two - * objects may be locked by this function. - * - * @inode1: first inode to lock - * @inode2: second inode to lock - * @subclass1: inode lock subclass for the first lock obtained - * @subclass2: inode lock subclass for the second lock obtained - */ -void lock_two_inodes(struct inode *inode1, struct inode *inode2, - unsigned subclass1, unsigned subclass2) -{ - if (!inode1 || !inode2) { - /* - * Make sure @subclass1 will be used for the acquired lock. - * This is not strictly necessary (no current caller cares) but - * let's keep things consistent. - */ - if (!inode1) - swap(inode1, inode2); - goto lock; - } - - /* - * If one object is directory and the other is not, we must make sure - * to lock directory first as the other object may be its child. - */ - if (S_ISDIR(inode2->i_mode) == S_ISDIR(inode1->i_mode)) { - if (inode1 > inode2) - swap(inode1, inode2); - } else if (!S_ISDIR(inode1->i_mode)) - swap(inode1, inode2); -lock: - if (inode1) - inode_lock_nested(inode1, subclass1); - if (inode2 && inode2 != inode1) - inode_lock_nested(inode2, subclass2); -} - /** * lock_two_nondirectories - take two i_mutexes on non-directory objects * @@ -1144,7 +1102,12 @@ void lock_two_nondirectories(struct inode *inode1, struct inode *inode2) WARN_ON_ONCE(S_ISDIR(inode1->i_mode)); if (inode2) WARN_ON_ONCE(S_ISDIR(inode2->i_mode)); - lock_two_inodes(inode1, inode2, I_MUTEX_NORMAL, I_MUTEX_NONDIR2); + if (inode1 > inode2) + swap(inode1, inode2); + if (inode1) + inode_lock(inode1); + if (inode2 && inode2 != inode1) + inode_lock_nested(inode2, I_MUTEX_NONDIR2); } EXPORT_SYMBOL(lock_two_nondirectories); diff --git a/fs/internal.h b/fs/internal.h index 58e43341aebf..de67b02226e5 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -196,8 +196,6 @@ extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc); int dentry_needs_remove_privs(struct mnt_idmap *, struct dentry *dentry); bool in_group_or_capable(struct mnt_idmap *idmap, const struct inode *inode, vfsgid_t vfsgid); -void lock_two_inodes(struct inode *inode1, struct inode *inode2, - unsigned subclass1, unsigned subclass2); /* * fs-writeback.c From a8b0026847b8c43445c921ad2c85521c92eb175f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2023 20:02:11 -0500 Subject: [PATCH 1476/7721] rename(): avoid a deadlock in the case of parents having no common ancestor ... and fix the directory locking documentation and proof of correctness. Holding ->s_vfs_rename_mutex *almost* prevents ->d_parent changes; the case where we really don't want it is splicing the root of disconnected tree to somewhere. In other words, ->s_vfs_rename_mutex is sufficient to stabilize "X is an ancestor of Y" only if X and Y are already in the same tree. Otherwise it can go from false to true, and one can construct a deadlock on that. Make lock_two_directories() report an error in such case and update the callers of lock_rename()/lock_rename_child() to handle such errors. And yes, such conditions are not impossible to create ;-/ Reviewed-by: Jan Kara Signed-off-by: Al Viro --- .../filesystems/directory-locking.rst | 322 +++++++++++++----- Documentation/filesystems/porting.rst | 9 + fs/cachefiles/namei.c | 2 + fs/ecryptfs/inode.c | 2 + fs/namei.c | 37 +- fs/nfsd/vfs.c | 4 + fs/overlayfs/copy_up.c | 9 +- fs/overlayfs/dir.c | 4 + fs/overlayfs/super.c | 6 +- fs/overlayfs/util.c | 7 +- fs/smb/server/vfs.c | 5 + 11 files changed, 301 insertions(+), 106 deletions(-) diff --git a/Documentation/filesystems/directory-locking.rst b/Documentation/filesystems/directory-locking.rst index 193c22687851..05ea387bc9fb 100644 --- a/Documentation/filesystems/directory-locking.rst +++ b/Documentation/filesystems/directory-locking.rst @@ -11,130 +11,268 @@ When taking the i_rwsem on multiple non-directory objects, we always acquire the locks in order by increasing address. We'll call that "inode pointer" order in the following. -For our purposes all operations fall in 5 classes: -1) read access. Locking rules: caller locks directory we are accessing. -The lock is taken shared. +Primitives +========== -2) object creation. Locking rules: same as above, but the lock is taken -exclusive. +For our purposes all operations fall in 6 classes: -3) object removal. Locking rules: caller locks parent, finds victim, -locks victim and calls the method. Locks are exclusive. +1. read access. Locking rules: -4) rename() that is _not_ cross-directory. Locking rules: caller locks -the parent and finds source and target. Then we decide which of the -source and target need to be locked. Source needs to be locked if it's a -non-directory; target - if it's a non-directory or about to be removed. -Take the locks that need to be taken, in inode pointer order if need -to take both (that can happen only when both source and target are -non-directories - the source because it wouldn't be locked otherwise -and the target because mixing directory and non-directory is allowed -only with RENAME_EXCHANGE, and that won't be removing the target). -After the locks had been taken, call the method. All locks are exclusive. + * lock the directory we are accessing (shared) -5) link creation. Locking rules: +2. object creation. Locking rules: - * lock parent - * check that source is not a directory - * lock source - * call the method. + * lock the directory we are accessing (exclusive) -All locks are exclusive. +3. object removal. Locking rules: -6) cross-directory rename. The trickiest in the whole bunch. Locking -rules: + * lock the parent (exclusive) + * find the victim + * lock the victim (exclusive) + +4. link creation. Locking rules: + + * lock the parent (exclusive) + * check that the source is not a directory + * lock the source (exclusive; probably could be weakened to shared) + +5. rename that is _not_ cross-directory. Locking rules: + + * lock the parent (exclusive) + * find the source and target + * decide which of the source and target need to be locked. + The source needs to be locked if it's a non-directory, target - if it's + a non-directory or about to be removed. + * take the locks that need to be taken (exlusive), in inode pointer order + if need to take both (that can happen only when both source and target + are non-directories - the source because it wouldn't need to be locked + otherwise and the target because mixing directory and non-directory is + allowed only with RENAME_EXCHANGE, and that won't be removing the target). + +6. cross-directory rename. The trickiest in the whole bunch. Locking rules: * lock the filesystem - * lock parents in "ancestors first" order. If one is not ancestor of - the other, lock the parent of source first. - * find source and target. - * if old parent is equal to or is a descendent of target - fail with -ENOTEMPTY - * if new parent is equal to or is a descendent of source - fail with -ELOOP - * Lock subdirectories involved (source before target). - * Lock non-directories involved, in inode pointer order. - * call the method. + * if the parents don't have a common ancestor, fail the operation. + * lock the parents in "ancestors first" order (exclusive). If neither is an + ancestor of the other, lock the parent of source first. + * find the source and target. + * verify that the source is not a descendent of the target and + target is not a descendent of source; fail the operation otherwise. + * lock the subdirectories involved (exclusive), source before target. + * lock the non-directories involved (exclusive), in inode pointer order. -All ->i_rwsem are taken exclusive. +The rules above obviously guarantee that all directories that are going +to be read, modified or removed by method will be locked by the caller. -The rules above obviously guarantee that all directories that are going to be -read, modified or removed by method will be locked by caller. +Splicing +======== + +There is one more thing to consider - splicing. It's not an operation +in its own right; it may happen as part of lookup. We speak of the +operations on directory trees, but we obviously do not have the full +picture of those - especially for network filesystems. What we have +is a bunch of subtrees visible in dcache and locking happens on those. +Trees grow as we do operations; memory pressure prunes them. Normally +that's not a problem, but there is a nasty twist - what should we do +when one growing tree reaches the root of another? That can happen in +several scenarios, starting from "somebody mounted two nested subtrees +from the same NFS4 server and doing lookups in one of them has reached +the root of another"; there's also open-by-fhandle stuff, and there's a +possibility that directory we see in one place gets moved by the server +to another and we run into it when we do a lookup. + +For a lot of reasons we want to have the same directory present in dcache +only once. Multiple aliases are not allowed. So when lookup runs into +a subdirectory that already has an alias, something needs to be done with +dcache trees. Lookup is already holding the parent locked. If alias is +a root of separate tree, it gets attached to the directory we are doing a +lookup in, under the name we'd been looking for. If the alias is already +a child of the directory we are looking in, it changes name to the one +we'd been looking for. No extra locking is involved in these two cases. +However, if it's a child of some other directory, the things get trickier. +First of all, we verify that it is *not* an ancestor of our directory +and fail the lookup if it is. Then we try to lock the filesystem and the +current parent of the alias. If either trylock fails, we fail the lookup. +If trylocks succeed, we detach the alias from its current parent and +attach to our directory, under the name we are looking for. + +Note that splicing does *not* involve any modification of the filesystem; +all we change is the view in dcache. Moreover, holding a directory locked +exclusive prevents such changes involving its children and holding the +filesystem lock prevents any changes of tree topology, other than having a +root of one tree becoming a child of directory in another. In particular, +if two dentries have been found to have a common ancestor after taking +the filesystem lock, their relationship will remain unchanged until +the lock is dropped. So from the directory operations' point of view +splicing is almost irrelevant - the only place where it matters is one +step in cross-directory renames; we need to be careful when checking if +parents have a common ancestor. + + +Multiple-filesystem stuff +========================= + +For some filesystems a method can involve a directory operation on +another filesystem; it may be ecryptfs doing operation in the underlying +filesystem, overlayfs doing something to the layers, network filesystem +using a local one as a cache, etc. In all such cases the operations +on other filesystems must follow the same locking rules. Moreover, "a +directory operation on this filesystem might involve directory operations +on that filesystem" should be an asymmetric relation (or, if you will, +it should be possible to rank the filesystems so that directory operation +on a filesystem could trigger directory operations only on higher-ranked +ones - in these terms overlayfs ranks lower than its layers, network +filesystem ranks lower than whatever it caches on, etc.) + + +Deadlock avoidance +================== If no directory is its own ancestor, the scheme above is deadlock-free. Proof: -[XXX: will be updated once we are done massaging the lock_rename()] - First of all, at any moment we have a linear ordering of the - objects - A < B iff (A is an ancestor of B) or (B is not an ancestor - of A and ptr(A) < ptr(B)). +There is a ranking on the locks, such that all primitives take +them in order of non-decreasing rank. Namely, - That ordering can change. However, the following is true: + * rank ->i_rwsem of non-directories on given filesystem in inode pointer + order. + * put ->i_rwsem of all directories on a filesystem at the same rank, + lower than ->i_rwsem of any non-directory on the same filesystem. + * put ->s_vfs_rename_mutex at rank lower than that of any ->i_rwsem + on the same filesystem. + * among the locks on different filesystems use the relative + rank of those filesystems. -(1) if object removal or non-cross-directory rename holds lock on A and - attempts to acquire lock on B, A will remain the parent of B until we - acquire the lock on B. (Proof: only cross-directory rename can change - the parent of object and it would have to lock the parent). +For example, if we have NFS filesystem caching on a local one, we have -(2) if cross-directory rename holds the lock on filesystem, order will not - change until rename acquires all locks. (Proof: other cross-directory - renames will be blocked on filesystem lock and we don't start changing - the order until we had acquired all locks). + 1. ->s_vfs_rename_mutex of NFS filesystem + 2. ->i_rwsem of directories on that NFS filesystem, same rank for all + 3. ->i_rwsem of non-directories on that filesystem, in order of + increasing address of inode + 4. ->s_vfs_rename_mutex of local filesystem + 5. ->i_rwsem of directories on the local filesystem, same rank for all + 6. ->i_rwsem of non-directories on local filesystem, in order of + increasing address of inode. -(3) locks on non-directory objects are acquired only after locks on - directory objects, and are acquired in inode pointer order. - (Proof: all operations but renames take lock on at most one - non-directory object, except renames, which take locks on source and - target in inode pointer order in the case they are not directories.) +It's easy to verify that operations never take a lock with rank +lower than that of an already held lock. -Now consider the minimal deadlock. Each process is blocked on -attempt to acquire some lock and already holds at least one lock. Let's -consider the set of contended locks. First of all, filesystem lock is -not contended, since any process blocked on it is not holding any locks. -Thus all processes are blocked on ->i_rwsem. +Suppose deadlocks are possible. Consider the minimal deadlocked +set of threads. It is a cycle of several threads, each blocked on a lock +held by the next thread in the cycle. -By (3), any process holding a non-directory lock can only be -waiting on another non-directory lock with a larger address. Therefore -the process holding the "largest" such lock can always make progress, and -non-directory objects are not included in the set of contended locks. +Since the locking order is consistent with the ranking, all +contended locks in the minimal deadlock will be of the same rank, +i.e. they all will be ->i_rwsem of directories on the same filesystem. +Moreover, without loss of generality we can assume that all operations +are done directly to that filesystem and none of them has actually +reached the method call. -Thus link creation can't be a part of deadlock - it can't be -blocked on source and it means that it doesn't hold any locks. +In other words, we have a cycle of threads, T1,..., Tn, +and the same number of directories (D1,...,Dn) such that -Any contended object is either held by cross-directory rename or -has a child that is also contended. Indeed, suppose that it is held by -operation other than cross-directory rename. Then the lock this operation -is blocked on belongs to child of that object due to (1). + T1 is blocked on D1 which is held by T2 -It means that one of the operations is cross-directory rename. -Otherwise the set of contended objects would be infinite - each of them -would have a contended child and we had assumed that no object is its -own descendent. Moreover, there is exactly one cross-directory rename -(see above). + T2 is blocked on D2 which is held by T3 -Consider the object blocking the cross-directory rename. One -of its descendents is locked by cross-directory rename (otherwise we -would again have an infinite set of contended objects). But that -means that cross-directory rename is taking locks out of order. Due -to (2) the order hadn't changed since we had acquired filesystem lock. -But locking rules for cross-directory rename guarantee that we do not -try to acquire lock on descendent before the lock on ancestor. -Contradiction. I.e. deadlock is impossible. Q.E.D. + ... + Tn is blocked on Dn which is held by T1. + +Each operation in the minimal cycle must have locked at least +one directory and blocked on attempt to lock another. That leaves +only 3 possible operations: directory removal (locks parent, then +child), same-directory rename killing a subdirectory (ditto) and +cross-directory rename of some sort. + +There must be a cross-directory rename in the set; indeed, +if all operations had been of the "lock parent, then child" sort +we would have Dn a parent of D1, which is a parent of D2, which is +a parent of D3, ..., which is a parent of Dn. Relationships couldn't +have changed since the moment directory locks had been acquired, +so they would all hold simultaneously at the deadlock time and +we would have a loop. + +Since all operations are on the same filesystem, there can't be +more than one cross-directory rename among them. Without loss of +generality we can assume that T1 is the one doing a cross-directory +rename and everything else is of the "lock parent, then child" sort. + +In other words, we have a cross-directory rename that locked +Dn and blocked on attempt to lock D1, which is a parent of D2, which is +a parent of D3, ..., which is a parent of Dn. Relationships between +D1,...,Dn all hold simultaneously at the deadlock time. Moreover, +cross-directory rename does not get to locking any directories until it +has acquired filesystem lock and verified that directories involved have +a common ancestor, which guarantees that ancestry relationships between +all of them had been stable. + +Consider the order in which directories are locked by the +cross-directory rename; parents first, then possibly their children. +Dn and D1 would have to be among those, with Dn locked before D1. +Which pair could it be? + +It can't be the parents - indeed, since D1 is an ancestor of Dn, +it would be the first parent to be locked. Therefore at least one of the +children must be involved and thus neither of them could be a descendent +of another - otherwise the operation would not have progressed past +locking the parents. + +It can't be a parent and its child; otherwise we would've had +a loop, since the parents are locked before the children, so the parent +would have to be a descendent of its child. + +It can't be a parent and a child of another parent either. +Otherwise the child of the parent in question would've been a descendent +of another child. + +That leaves only one possibility - namely, both Dn and D1 are +among the children, in some order. But that is also impossible, since +neither of the children is a descendent of another. + +That concludes the proof, since the set of operations with the +properties requiered for a minimal deadlock can not exist. + +Note that the check for having a common ancestor in cross-directory +rename is crucial - without it a deadlock would be possible. Indeed, +suppose the parents are initially in different trees; we would lock the +parent of source, then try to lock the parent of target, only to have +an unrelated lookup splice a distant ancestor of source to some distant +descendent of the parent of target. At that point we have cross-directory +rename holding the lock on parent of source and trying to lock its +distant ancestor. Add a bunch of rmdir() attempts on all directories +in between (all of those would fail with -ENOTEMPTY, had they ever gotten +the locks) and voila - we have a deadlock. + +Loop avoidance +============== These operations are guaranteed to avoid loop creation. Indeed, the only operation that could introduce loops is cross-directory rename. -Since the only new (parent, child) pair added by rename() is (new parent, -source), such loop would have to contain these objects and the rest of it -would have to exist before rename(). I.e. at the moment of loop creation -rename() responsible for that would be holding filesystem lock and new parent -would have to be equal to or a descendent of source. But that means that -new parent had been equal to or a descendent of source since the moment when -we had acquired filesystem lock and rename() would fail with -ELOOP in that -case. +Suppose after the operation there is a loop; since there hadn't been such +loops before the operation, at least on of the nodes in that loop must've +had its parent changed. In other words, the loop must be passing through +the source or, in case of exchange, possibly the target. + +Since the operation has succeeded, neither source nor target could have +been ancestors of each other. Therefore the chain of ancestors starting +in the parent of source could not have passed through the target and +vice versa. On the other hand, the chain of ancestors of any node could +not have passed through the node itself, or we would've had a loop before +the operation. But everything other than source and target has kept +the parent after the operation, so the operation does not change the +chains of ancestors of (ex-)parents of source and target. In particular, +those chains must end after a finite number of steps. + +Now consider the loop created by the operation. It passes through either +source or target; the next node in the loop would be the ex-parent of +target or source resp. After that the loop would follow the chain of +ancestors of that parent. But as we have just shown, that chain must +end after a finite number of steps, which means that it can't be a part +of any loop. Q.E.D. While this locking scheme works for arbitrary DAGs, it relies on ability to check that directory is a descendent of another object. Current diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 9100969e7de6..33cd56e2ca1a 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1079,3 +1079,12 @@ On same-directory ->rename() the (tautological) update of .. is not protected by any locks; just don't do it if the old parent is the same as the new one. We really can't lock two subdirectories in same-directory rename - not without deadlocks. + +--- + +**mandatory** + +lock_rename() and lock_rename_child() may fail in cross-directory case, if +their arguments do not have a common ancestor. In that case ERR_PTR(-EXDEV) +is returned, with no locks taken. In-tree users updated; out-of-tree ones +would need to do so. diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 7bf7a5fcc045..7ade836beb58 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -305,6 +305,8 @@ int cachefiles_bury_object(struct cachefiles_cache *cache, /* do the multiway lock magic */ trap = lock_rename(cache->graveyard, dir); + if (IS_ERR(trap)) + return PTR_ERR(trap); /* do some checks before getting the grave dentry */ if (rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) { diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a25dd3d20008..8efd20dc902b 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -599,6 +599,8 @@ ecryptfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, target_inode = d_inode(new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + if (IS_ERR(trap)) + return PTR_ERR(trap); dget(lower_new_dentry); rc = -EINVAL; if (lower_old_dentry->d_parent != lower_old_dir_dentry) diff --git a/fs/namei.c b/fs/namei.c index 29bafbdb44ca..6b0302ac80d1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3014,21 +3014,37 @@ static inline int may_create(struct mnt_idmap *idmap, return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); } +// p1 != p2, both are on the same filesystem, ->s_vfs_rename_mutex is held static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2) { - struct dentry *p; + struct dentry *p = p1, *q = p2, *r; - p = d_ancestor(p2, p1); - if (p) { + while ((r = p->d_parent) != p2 && r != p) + p = r; + if (r == p2) { + // p is a child of p2 and an ancestor of p1 or p1 itself inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); inode_lock_nested(p1->d_inode, I_MUTEX_PARENT2); return p; } - - p = d_ancestor(p1, p2); - inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); - return p; + // p is the root of connected component that contains p1 + // p2 does not occur on the path from p to p1 + while ((r = q->d_parent) != p1 && r != p && r != q) + q = r; + if (r == p1) { + // q is a child of p1 and an ancestor of p2 or p2 itself + inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); + inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); + return q; + } else if (likely(r == p)) { + // both p2 and p1 are descendents of p + inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); + inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); + return NULL; + } else { // no common ancestor at the time we'd been called + mutex_unlock(&p1->d_sb->s_vfs_rename_mutex); + return ERR_PTR(-EXDEV); + } } /* @@ -4947,6 +4963,10 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, retry_deleg: trap = lock_rename(new_path.dentry, old_path.dentry); + if (IS_ERR(trap)) { + error = PTR_ERR(trap); + goto exit_lock_rename; + } old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry, lookup_flags); @@ -5014,6 +5034,7 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, dput(old_dentry); exit3: unlock_rename(new_path.dentry, old_path.dentry); +exit_lock_rename: if (delegated_inode) { error = break_deleg_wait(&delegated_inode); if (!error) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fbbea7498f02..a99260c3f9bc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1813,6 +1813,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, } trap = lock_rename(tdentry, fdentry); + if (IS_ERR(trap)) { + err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev; + goto out; + } err = fh_fill_pre_attrs(ffhp); if (err != nfs_ok) goto out_unlock; diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 4382881b0709..e44dc5f66161 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -722,7 +722,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) struct inode *inode; struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir); struct path path = { .mnt = ovl_upper_mnt(ofs) }; - struct dentry *temp, *upper; + struct dentry *temp, *upper, *trap; struct ovl_cu_creds cc; int err; struct ovl_cattr cattr = { @@ -760,9 +760,11 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) * If temp was moved, abort without the cleanup. */ ovl_start_write(c->dentry); - if (lock_rename(c->workdir, c->destdir) != NULL || - temp->d_parent != c->workdir) { + trap = lock_rename(c->workdir, c->destdir); + if (trap || temp->d_parent != c->workdir) { err = -EIO; + if (IS_ERR(trap)) + goto out; goto unlock; } else if (err) { goto cleanup; @@ -803,6 +805,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) ovl_set_flag(OVL_WHITEOUTS, inode); unlock: unlock_rename(c->workdir, c->destdir); +out: ovl_end_write(c->dentry); return err; diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index aab3f5d93556..0f8b4a719237 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -1180,6 +1180,10 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir, } trap = lock_rename(new_upperdir, old_upperdir); + if (IS_ERR(trap)) { + err = PTR_ERR(trap); + goto out_revert_creds; + } olddentry = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir, old->d_name.len); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index a0967bb25003..fc3a6ff648bd 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -439,8 +439,10 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) bool ok = false; if (workdir != upperdir) { - ok = (lock_rename(workdir, upperdir) == NULL); - unlock_rename(workdir, upperdir); + struct dentry *trap = lock_rename(workdir, upperdir); + if (!IS_ERR(trap)) + unlock_rename(workdir, upperdir); + ok = (trap == NULL); } return ok; } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 50a201e9cd39..7b667345e673 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1198,12 +1198,17 @@ void ovl_nlink_end(struct dentry *dentry) int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir) { + struct dentry *trap; + /* Workdir should not be the same as upperdir */ if (workdir == upperdir) goto err; /* Workdir should not be subdir of upperdir and vice versa */ - if (lock_rename(workdir, upperdir) != NULL) + trap = lock_rename(workdir, upperdir); + if (IS_ERR(trap)) + goto err; + if (trap) goto err_unlock; return 0; diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index c53dea5598fc..4cf8523ad038 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -708,6 +708,10 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, goto out2; trap = lock_rename_child(old_child, new_path.dentry); + if (IS_ERR(trap)) { + err = PTR_ERR(trap); + goto out_drop_write; + } old_parent = dget(old_child->d_parent); if (d_unhashed(old_child)) { @@ -770,6 +774,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, out3: dput(old_parent); unlock_rename(old_parent, new_path.dentry); +out_drop_write: mnt_drop_write(old_path->mnt); out2: path_put(&new_path); From cf1aaa7d4a719f0bdd9c246c0fac8247cb54ddd7 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Sat, 25 Nov 2023 11:11:50 -0800 Subject: [PATCH 1477/7721] drm/msm/a6xx: Add missing BIT(7) to REG_A6XX_UCHE_CLIENT_PF Downstream always set BIT(7) Signed-off-by: Danylo Piliaiev Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/568930/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 7a0220d29a23..e5558d5e0aa2 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1782,7 +1782,7 @@ static int hw_init(struct msm_gpu *gpu) else gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x1fffff); - gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, 1); + gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, BIT(7) | 0x1); /* Set weights for bicubic filtering */ if (adreno_is_a650_family(adreno_gpu)) { From 07e6de738aa6f0e873463e9ca88bdb7081c4bfd4 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Sat, 25 Nov 2023 11:11:51 -0800 Subject: [PATCH 1478/7721] drm/msm/a690: Fix reg values for a690 KGSL doesn't support a690 so all reg values were the same as on a660. Now we know the values and they are different from the windows driver. This fixes hangs on D3D12 games and some CTS tests. Signed-off-by: Danylo Piliaiev Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/568931/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index e5558d5e0aa2..723f9b97734d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1312,6 +1312,7 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu) if (adreno_is_a650(adreno_gpu) || adreno_is_a660(adreno_gpu) || + adreno_is_a690(adreno_gpu) || adreno_is_a730(adreno_gpu) || adreno_is_a740_family(adreno_gpu)) { /* TODO: get ddr type from bootloader and use 2 for LPDDR4 */ @@ -1321,13 +1322,6 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu) uavflagprd_inv = 2; } - if (adreno_is_a690(adreno_gpu)) { - hbb_lo = 2; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; - } - if (adreno_is_7c3(adreno_gpu)) { hbb_lo = 1; amsbc = 1; @@ -1741,7 +1735,9 @@ static int hw_init(struct msm_gpu *gpu) /* Setting the primFifo thresholds default values, * and vccCacheSkipDis=1 bit (0x200) for A640 and newer */ - if (adreno_is_a650(adreno_gpu) || adreno_is_a660(adreno_gpu) || adreno_is_a690(adreno_gpu)) + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00800200); + else if (adreno_is_a650(adreno_gpu) || adreno_is_a660(adreno_gpu)) gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00300200); else if (adreno_is_a640_family(adreno_gpu) || adreno_is_7c3(adreno_gpu)) gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00200200); @@ -1775,6 +1771,8 @@ static int hw_init(struct msm_gpu *gpu) if (adreno_is_a730(adreno_gpu) || adreno_is_a740_family(adreno_gpu)) gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff); + else if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x4fffff); else if (adreno_is_a619(adreno_gpu)) gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x3fffff); else if (adreno_is_a610(adreno_gpu)) @@ -1808,12 +1806,17 @@ static int hw_init(struct msm_gpu *gpu) a6xx_set_cp_protect(gpu); if (adreno_is_a660_family(adreno_gpu)) { - gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x1); + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x00028801); + else + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x1); gpu_write(gpu, REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x0); } + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x90); /* Set dualQ + disable afull for A660 GPU */ - if (adreno_is_a660(adreno_gpu)) + else if (adreno_is_a660(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x66906); else if (adreno_is_a7xx(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, From 2f3ce7a56c6e02bc0b258507f3a82b7511f62f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 21 Nov 2023 18:20:24 +0100 Subject: [PATCH 1479/7721] net: sfp: rework the RollBall PHY waiting code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RollBall SFP modules allow the access to PHY registers only after a certain time has passed. Until then, the registers read 0xffff. Currently we have quirks for modules where we need to wait either 25 seconds or 4 seconds, but recently I got hands on another module where the wait is even shorter. Instead of hardcoding different wait times, lets rework the code: - increase the PHY retry count to 25 - when RollBall module is detected, increase the PHY retry time from 50ms to 1s Signed-off-by: Marek Behún Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 5468bd209fab..5eb00295b8bf 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -191,7 +191,7 @@ static const enum gpiod_flags gpio_flags[] = { * R_PHY_RETRY is the number of attempts. */ #define T_PHY_RETRY msecs_to_jiffies(50) -#define R_PHY_RETRY 12 +#define R_PHY_RETRY 25 /* SFP module presence detection is poor: the three MOD DEF signals are * the same length on the PCB, which means it's possible for MOD DEF 0 to @@ -274,7 +274,7 @@ struct sfp { struct sfp_eeprom_id id; unsigned int module_power_mW; unsigned int module_t_start_up; - unsigned int module_t_wait; + unsigned int phy_t_retry; unsigned int rate_kbd; unsigned int rs_threshold_kbd; @@ -372,18 +372,22 @@ static void sfp_fixup_10gbaset_30m(struct sfp *sfp) sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR; } -static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs) +static void sfp_fixup_rollball(struct sfp *sfp) { sfp->mdio_protocol = MDIO_I2C_ROLLBALL; - sfp->module_t_wait = msecs_to_jiffies(secs * 1000); + + /* RollBall modules may disallow access to PHY registers for up to 25 + * seconds, and the reads return 0xffff before that. Increase the time + * between PHY probe retries from 50ms to 1s so that we will wait for + * the PHY for a sufficient amount of time. + */ + sfp->phy_t_retry = msecs_to_jiffies(1000); } static void sfp_fixup_fs_10gt(struct sfp *sfp) { sfp_fixup_10gbaset_30m(sfp); - - // These SFPs need 4 seconds before the PHY can be accessed - sfp_fixup_rollball_proto(sfp, 4); + sfp_fixup_rollball(sfp); } static void sfp_fixup_halny_gsfp(struct sfp *sfp) @@ -395,12 +399,6 @@ static void sfp_fixup_halny_gsfp(struct sfp *sfp) sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS); } -static void sfp_fixup_rollball(struct sfp *sfp) -{ - // Rollball SFPs need 25 seconds before the PHY can be accessed - sfp_fixup_rollball_proto(sfp, 25); -} - static void sfp_fixup_rollball_cc(struct sfp *sfp) { sfp_fixup_rollball(sfp); @@ -2331,7 +2329,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) mask |= SFP_F_RS1; sfp->module_t_start_up = T_START_UP; - sfp->module_t_wait = T_WAIT; + sfp->phy_t_retry = T_PHY_RETRY; sfp->state_ignore_mask = 0; @@ -2568,10 +2566,9 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) /* We need to check the TX_FAULT state, which is not defined * while TX_DISABLE is asserted. The earliest we want to do - * anything (such as probe for a PHY) is 50ms (or more on - * specific modules). + * anything (such as probe for a PHY) is 50ms. */ - sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); + sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); break; case SFP_S_WAIT: @@ -2585,8 +2582,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) * deasserting. */ timeout = sfp->module_t_start_up; - if (timeout > sfp->module_t_wait) - timeout -= sfp->module_t_wait; + if (timeout > T_WAIT) + timeout -= T_WAIT; else timeout = 1; @@ -2629,7 +2626,11 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) ret = sfp_sm_probe_for_phy(sfp); if (ret == -ENODEV) { if (--sfp->sm_phy_retries) { - sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY); + sfp_sm_next(sfp, SFP_S_INIT_PHY, + sfp->phy_t_retry); + dev_dbg(sfp->dev, + "no PHY detected, %u tries left\n", + sfp->sm_phy_retries); break; } else { dev_info(sfp->dev, "no PHY detected\n"); From 9f1f6111fd5d553ec175c4e81d7ebf6932aaeca0 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 23 Nov 2023 13:01:35 +0100 Subject: [PATCH 1480/7721] mlxsw: pci: Fix missing error checking I accidentally removed the error checking after issuing the reset. Restore it. Fixes: f257c73e5356 ("mlxsw: pci: Add support for new reset flow") Reported-by: Coverity Scan Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 0d58f13a7c7d..af99bf17eb36 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1561,6 +1561,8 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) pci_dbg(pdev, "Starting software reset flow\n"); err = mlxsw_pci_reset_sw(mlxsw_pci); } + if (err) + return err; err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); if (err) { From 753fff78f430704548f45eda52d6d55371a52c0f Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Tue, 21 Nov 2023 14:03:15 +0100 Subject: [PATCH 1481/7721] RDMA/IPoIB: Fix error code return in ipoib_mcast_join Return the error code in case of ib_sa_join_multicast fail. Signed-off-by: Jack Wang Link: https://lore.kernel.org/r/20231121130316.126364-2-jinpu.wang@ionos.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 5b3154503bf4..9e6967a40042 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -546,6 +546,7 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) spin_unlock_irq(&priv->lock); complete(&mcast->done); spin_lock_irq(&priv->lock); + return ret; } return 0; } From 50af5d12f7e24b85fc10270d7700f4aa1b20b8e4 Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Tue, 21 Nov 2023 14:03:16 +0100 Subject: [PATCH 1482/7721] RDMA/IPoIB: Add tx timeout work to recover queue stop situation As we sometime run into TX timeout from IPoIB, queue seems stopped and can't recover. Diff with Mellanox OFED show Mellanox driver has timeout work to recover in such case. Add TX timeout work/NAPI work to recover such case. Also increase the watchdog_timeo to 10 seconds, so more tolerant to error. Signed-off-by: Jack Wang Link: https://lore.kernel.org/r/20231121130316.126364-3-jinpu.wang@ionos.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/ipoib/ipoib.h | 4 +++ drivers/infiniband/ulp/ipoib/ipoib_ib.c | 26 +++++++++++++++++- drivers/infiniband/ulp/ipoib/ipoib_main.c | 33 +++++++++++++++++++++-- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 35e9c8a330e2..963e936da5e3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -351,10 +351,12 @@ struct ipoib_dev_priv { struct workqueue_struct *wq; struct delayed_work mcast_task; struct work_struct carrier_on_task; + struct work_struct reschedule_napi_work; struct work_struct flush_light; struct work_struct flush_normal; struct work_struct flush_heavy; struct work_struct restart_task; + struct work_struct tx_timeout_work; struct delayed_work ah_reap_task; struct delayed_work neigh_reap_task; struct ib_device *ca; @@ -499,6 +501,7 @@ int ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ib_ah *address, u32 dqpn); void ipoib_reap_ah(struct work_struct *work); +void ipoib_napi_schedule_work(struct work_struct *work); struct ipoib_path *__path_find(struct net_device *dev, void *gid); void ipoib_mark_paths_invalid(struct net_device *dev); void ipoib_flush_paths(struct net_device *dev); @@ -510,6 +513,7 @@ void ipoib_ib_tx_timer_func(struct timer_list *t); void ipoib_ib_dev_flush_light(struct work_struct *work); void ipoib_ib_dev_flush_normal(struct work_struct *work); void ipoib_ib_dev_flush_heavy(struct work_struct *work); +void ipoib_ib_tx_timeout_work(struct work_struct *work); void ipoib_pkey_event(struct work_struct *work); void ipoib_ib_dev_cleanup(struct net_device *dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 7f84d9866cef..5cde275daa94 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -531,11 +531,35 @@ void ipoib_ib_rx_completion(struct ib_cq *cq, void *ctx_ptr) napi_schedule(&priv->recv_napi); } +/* The function will force napi_schedule */ +void ipoib_napi_schedule_work(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, reschedule_napi_work); + bool ret; + + do { + ret = napi_schedule(&priv->send_napi); + if (!ret) + msleep(3); + } while (!ret && netif_queue_stopped(priv->dev) && + test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)); +} + void ipoib_ib_tx_completion(struct ib_cq *cq, void *ctx_ptr) { struct ipoib_dev_priv *priv = ctx_ptr; + bool ret; - napi_schedule(&priv->send_napi); + ret = napi_schedule(&priv->send_napi); + /* + * if the queue is closed the driver must be able to schedule napi, + * otherwise we can end with closed queue forever, because no new + * packets to send and napi callback might not get new event after + * its re-arm of the napi. + */ + if (!ret && netif_queue_stopped(priv->dev)) + schedule_work(&priv->reschedule_napi_work); } static inline int post_send(struct ipoib_dev_priv *priv, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 967004ccad98..7a5be705d718 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1200,7 +1200,34 @@ static void ipoib_timeout(struct net_device *dev, unsigned int txqueue) netif_queue_stopped(dev), priv->tx_head, priv->tx_tail, priv->global_tx_head, priv->global_tx_tail); - /* XXX reset QP, etc. */ + + schedule_work(&priv->tx_timeout_work); +} + +void ipoib_ib_tx_timeout_work(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, + struct ipoib_dev_priv, + tx_timeout_work); + int err; + + rtnl_lock(); + + if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + goto unlock; + + ipoib_stop(priv->dev); + err = ipoib_open(priv->dev); + if (err) { + ipoib_warn(priv, "ipoib_open failed recovering from a tx_timeout, err(%d).\n", + err); + goto unlock; + } + + netif_tx_wake_all_queues(priv->dev); +unlock: + rtnl_unlock(); + } static int ipoib_hard_header(struct sk_buff *skb, @@ -2112,7 +2139,7 @@ void ipoib_setup_common(struct net_device *dev) ipoib_set_ethtool_ops(dev); - dev->watchdog_timeo = HZ; + dev->watchdog_timeo = 10 * HZ; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; @@ -2150,10 +2177,12 @@ static void ipoib_build_priv(struct net_device *dev) INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task); + INIT_WORK(&priv->reschedule_napi_work, ipoib_napi_schedule_work); INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); + INIT_WORK(&priv->tx_timeout_work, ipoib_ib_tx_timeout_work); INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); INIT_DELAYED_WORK(&priv->neigh_reap_task, ipoib_reap_neigh); } From dba1b8a7ab6853a84bf3afdbeac1c2f2370d3444 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 24 Nov 2023 11:16:52 +0100 Subject: [PATCH 1483/7721] mm/page_pool: catch page_pool memory leaks Pages belonging to a page_pool (PP) instance must be freed through the PP APIs in-order to correctly release any DMA mappings and release refcnt on the DMA device when freeing PP instance. When PP release a page (page_pool_release_page) the page->pp_magic value is cleared. This patch detect a leaked PP page in free_page_is_bad() via unexpected state of page->pp_magic value being PP_SIGNATURE. We choose to report and treat it as a bad page. It would be possible to release the page via returning it to the PP instance as the page->pp pointer is likely still valid. Notice this code is only activated when either compiled with CONFIG_DEBUG_VM or boot cmdline debug_pagealloc=on, and CONFIG_PAGE_POOL. Reduced example output of leak with PP_SIGNATURE = dead000000000040: BUG: Bad page state in process swapper/4 pfn:141fa6 page:000000006dbf8062 refcount:0 mapcount:0 mapping:0000000000000000 index:0x141fa6000 pfn:0x141fa6 flags: 0x2fffff80000000(node=0|zone=2|lastcpupid=0x1fffff) page_type: 0xffffffff() raw: 002fffff80000000 dead000000000040 ffff88814888a000 0000000000000000 raw: 0000000141fa6000 0000000000000001 00000000ffffffff 0000000000000000 page dumped because: page_pool leak [...] Call Trace: dump_stack_lvl+0x32/0x50 bad_page+0x70/0xf0 free_unref_page_prepare+0x263/0x430 free_unref_page+0x34/0x130 mlx5e_free_rx_mpwqe+0x190/0x1c0 [mlx5_core] mlx5e_post_rx_mpwqes+0x1ac/0x280 [mlx5_core] mlx5e_napi_poll+0x12b/0x710 [mlx5_core] ? skb_free_head+0x4f/0x90 __napi_poll+0x2b/0x1c0 net_rx_action+0x27b/0x360 The advantage is the Call Trace directly points to the function leaking the PP page, which in this case is an on purpose bug introduced into the mlx5 driver to test this code change. Currently PP will periodically in page_pool_release_retry() printk warning "stalled pool shutdown" which cannot be directly corrolated to leaking and might as well be a false positive due to SKBs being stuck on a socket for an extended period. After this patch we should be able to remove this printk. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- mm/page_alloc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 733732e7e0ba..37ca4f4b62bf 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -915,6 +915,9 @@ static inline bool page_expected_state(struct page *page, page_ref_count(page) | #ifdef CONFIG_MEMCG page->memcg_data | +#endif +#ifdef CONFIG_PAGE_POOL + ((page->pp_magic & ~0x3UL) == PP_SIGNATURE) | #endif (page->flags & check_flags))) return false; @@ -941,6 +944,10 @@ static const char *page_bad_reason(struct page *page, unsigned long flags) #ifdef CONFIG_MEMCG if (unlikely(page->memcg_data)) bad_reason = "page still charged to cgroup"; +#endif +#ifdef CONFIG_PAGE_POOL + if (unlikely((page->pp_magic & ~0x3UL) == PP_SIGNATURE)) + bad_reason = "page_pool leak"; #endif return bad_reason; } From 1c4a4f7362fd3ff691b43cf2997ab68c2344976d Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 22 Nov 2023 18:19:57 +0800 Subject: [PATCH 1484/7721] arm64: dts: imx93: Add audio device nodes Add audio devices nodes including SAI, MICFIL, XCVR and MQS. Signed-off-by: Chancel Liu Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93.dtsi | 87 ++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index ceccf4766440..9a7bff39519c 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -171,6 +171,18 @@ cm33: remoteproc-cm33 { status = "disabled"; }; + mqs1: mqs1 { + compatible = "fsl,imx93-mqs"; + gpr = <&aonmix_ns_gpr>; + status = "disabled"; + }; + + mqs2: mqs2 { + compatible = "fsl,imx93-mqs"; + gpr = <&wakeupmix_gpr>; + status = "disabled"; + }; + soc@0 { compatible = "simple-bus"; #address-cells = <1>; @@ -367,6 +379,19 @@ flexcan1: can@443a0000 { status = "disabled"; }; + sai1: sai@443b0000 { + compatible = "fsl,imx93-sai"; + reg = <0x443b0000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma1 22 0 1>, <&edma1 21 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + iomuxc: pinctrl@443c0000 { compatible = "fsl,imx93-iomuxc"; reg = <0x443c0000 0x10000>; @@ -447,6 +472,23 @@ tmu: tmu@44482000 { #thermal-sensor-cells = <1>; }; + micfil: micfil@44520000 { + compatible = "fsl,imx93-micfil"; + reg = <0x44520000 0x10000>; + interrupts = , + , + , + ; + clocks = <&clk IMX93_CLK_PDM_IPG>, + <&clk IMX93_CLK_PDM_GATE>, + <&clk IMX93_CLK_AUDIO_PLL>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "ipg_clk", "ipg_clk_app", + "pll8k", "clkext3"; + dmas = <&edma1 29 0 5>; + dma-names = "rx"; + status = "disabled"; + }; adc1: adc@44530000 { compatible = "nxp,imx93-adc"; @@ -738,6 +780,51 @@ flexspi1: spi@425e0000 { status = "disabled"; }; + sai2: sai@42650000 { + compatible = "fsl,imx93-sai"; + reg = <0x42650000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI2_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI2_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 59 0 1>, <&edma2 58 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + sai3: sai@42660000 { + compatible = "fsl,imx93-sai"; + reg = <0x42660000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI3_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI3_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 61 0 1>, <&edma2 60 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + xcvr: xcvr@42680000 { + compatible = "fsl,imx93-xcvr"; + reg = <0x42680000 0x800>, + <0x42680800 0x400>, + <0x42680c00 0x080>, + <0x42680e00 0x080>; + reg-names = "ram", "regs", "rxfifo", "txfifo"; + interrupts = , + ; + clocks = <&clk IMX93_CLK_BUS_WAKEUP>, + <&clk IMX93_CLK_SPDIF_GATE>, + <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_AUD_XCVR_GATE>; + clock-names = "ipg", "phy", "spba", "pll_ipg"; + dmas = <&edma2 65 0 1>, <&edma2 66 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + lpuart7: serial@42690000 { compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart"; reg = <0x42690000 0x1000>; From 54303e555df10ea4482fa52784070f216e3c8750 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 22 Nov 2023 18:19:58 +0800 Subject: [PATCH 1485/7721] arm64: dts: imx93: Configure clock rate for audio PLL Configure clock rate for audio PLL. There's one audio PLL on i.MX93. It is used as parent clock for clocks that are multiple of 8kHz. Signed-off-by: Chancel Liu Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index 9a7bff39519c..e6745801308e 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -420,6 +420,8 @@ clk: clock-controller@44450000 { #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>; clock-names = "osc_32k", "osc_24m", "clk_ext1"; + assigned-clocks = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <393216000>; status = "okay"; }; From d9b07915fc3137c46a78b5b092ba3d8f2bd73121 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 09:42:35 +0200 Subject: [PATCH 1486/7721] arm64: dts: freescale: tqma9352-mba93xxla: add 'chassis-type' property Add the chassis-type property to tqma9352-mba93xxla. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts index f06139bdff97..f0d0bf84f6ba 100644 --- a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts +++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts @@ -18,6 +18,7 @@ /{ model = "TQ-Systems i.MX93 TQMa93xxLA on MBa93xxLA SBC"; compatible = "tq,imx93-tqma9352-mba93xxla", "tq,imx93-tqma9352", "fsl,imx93"; + chassis-type = "embedded"; chosen { stdout-path = &lpuart1; From 6a04248799fd87abadbf73ba24139a25d33f4406 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 09:42:36 +0200 Subject: [PATCH 1487/7721] arm64: dts: freescale: add initial device tree for MBa93xxCA starter kit This adds support for TQMa93xx module and MBa93xxCA starterkit mainboard. TQMa93xx is a SOM using i.MX93 SOC. The SOM features PMIC, RAM, e-MMC and some optional peripherals like SPI-NOR, RTC, EEPROM, gyroscope and secure element. TQMa93xxLA is a solder on type SOM and can be used on MBa93XXCA using an adapter. TQMa93xxCA is a feature compatible, socketable type SOM. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 1 + .../freescale/imx93-tqma9352-mba93xxca.dts | 709 ++++++++++++++++++ 2 files changed, 710 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 300049037eb0..a3c5fc814adb 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -164,6 +164,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-iris-v2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxca.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb imx8mm-venice-gw72xx-0x-imx219-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-imx219.dtbo diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts new file mode 100644 index 000000000000..af795ecf678b --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts @@ -0,0 +1,709 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * Copyright (c) 2022-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Markus Niebel + * Author: Alexander Stein + */ +/dts-v1/; + +#include +#include +#include +#include + +#include "imx93-tqma9352.dtsi" + +/{ + model = "TQ-Systems i.MX93 TQMa93xxLA/TQMa93xxCA on MBa93xxCA starter kit"; + compatible = "tq,imx93-tqma9352-mba93xxca", + "tq,imx93-tqma9352", "fsl,imx93"; + chassis-type = "embedded"; + + chosen { + stdout-path = &lpuart1; + }; + + aliases { + eeprom0 = &eeprom0; + rtc0 = &pcf85063; + rtc1 = &bbnsm_rtc; + }; + + backlight_lvds: backlight { + compatible = "pwm-backlight"; + pwms = <&tpm5 0 5000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_12v0>; + enable-gpios = <&expander2 2 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + fan0: pwm-fan { + compatible = "pwm-fan"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwmfan>; + fan-supply = <®_pwm_fan>; + #cooling-cells = <2>; + /* typical 25 kHz -> 40.000 nsec */ + pwms = <&tpm6 0 40000 PWM_POLARITY_INVERTED>; + cooling-levels = <0 32 64 128 196 240>; + pulses-per-revolution = <2>; + interrupt-parent = <&gpio2>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + status = "disabled"; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + switch-a { + label = "switcha"; + linux,code = ; + gpios = <&expander0 6 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + switch-b { + label = "switchb"; + linux,code = ; + gpios = <&expander0 7 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led-1 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&expander2 6 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + led-2 { + color = ; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&expander2 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "V_3V3_MB"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_5v0: regulator-5v0 { + compatible = "regulator-fixed"; + regulator-name = "V_5V0_MB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_12v0: regulator-12v0 { + compatible = "regulator-fixed"; + regulator-name = "V_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&expander1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_mpcie_1v5: regulator-mpcie-1v5 { + compatible = "regulator-fixed"; + regulator-name = "V_1V5_MPCIE"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + gpio = <&expander0 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_mpcie_3v3: regulator-mpcie-3v3 { + compatible = "regulator-fixed"; + regulator-name = "V_3V3_MPCIE"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&expander0 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_pwm_fan: regulator-pwm-fan { + compatible = "regulator-fixed"; + regulator-name = "FAN_PWR"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&expander0 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_12v0>; + }; + + thermal-zones { + cpu-thermal { + trips { + cpu_active0: trip-active0 { + temperature = <40000>; + hysteresis = <5000>; + type = "active"; + }; + + cpu_active1: trip-active1 { + temperature = <48000>; + hysteresis = <3000>; + type = "active"; + }; + + cpu_active2: trip-active2 { + temperature = <60000>; + hysteresis = <10000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&cpu_active0>; + cooling-device = <&fan0 1 1>; + }; + + map2 { + trip = <&cpu_active1>; + cooling-device = <&fan0 2 2>; + }; + + map3 { + trip = <&cpu_active2>; + cooling-device = <&fan0 3 3>; + }; + }; + }; + }; +}; + +&adc1 { + status = "okay"; +}; + +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy_eqos>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy_eqos: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos_phy>; + reset-gpios = <&expander1 0 GPIO_ACTIVE_LOW>; + reset-assert-us = <500000>; + reset-deassert-us = <50000>; + interrupt-parent = <&gpio3>; + interrupts = <26 IRQ_TYPE_EDGE_FALLING>; + enet-phy-lane-no-swap; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,fifo-depth = ; + ti,dp83867-rxctrl-strap-quirk; + ti,clk-output-sel = ; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy_fec>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <5000000>; + + ethphy_fec: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec_phy>; + reset-gpios = <&expander1 1 GPIO_ACTIVE_LOW>; + reset-assert-us = <500000>; + reset-deassert-us = <50000>; + interrupt-parent = <&gpio3>; + interrupts = <27 IRQ_TYPE_EDGE_FALLING>; + enet-phy-lane-no-swap; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,fifo-depth = ; + ti,dp83867-rxctrl-strap-quirk; + ti,clk-output-sel = ; + }; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_3v3>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_3v3>; + status = "okay"; +}; + +&gpio1 { + expander-irq-hog { + gpio-hog; + gpios = <12 GPIO_ACTIVE_LOW>; + input; + line-name = "PEX_INT#"; + }; + + tcpc-irq-hog { + gpio-hog; + gpios = <2 GPIO_ACTIVE_LOW>; + input; + line-name = "USB_C_ALERT#"; + }; +}; + +&lpi2c3 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c3>; + pinctrl-1 = <&pinctrl_lpi2c3>; + status = "okay"; + + temperature-sensor@1c { + compatible = "nxp,se97b", "jedec,jc-42.4-temp"; + reg = <0x1c>; + }; + + eeprom2: eeprom@54 { + compatible = "nxp,se97b", "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + vcc-supply = <®_3v3>; + }; + + expander0: gpio@70 { + compatible = "nxp,pca9538"; + reg = <0x70>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pexp_irq>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio1>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + vcc-supply = <®_3v3>; + gpio-line-names = "FAN_PWR_EN", "MPCIE_WAKE#", + "MPCIE_1V5_EN", "MPCIE_3V3_EN", + "MPCIE_PERST#", "MPCIE_WDISABLE#", + "BUTTON_A#", "BUTTON_B#"; + + mpcie-wake-hog { + gpio-hog; + gpios = <1 GPIO_ACTIVE_LOW>; + input; + line-name = "MPCIE_WAKE#"; + }; + + /* + * Controls the mPCIE slot reset which is low active as + * reset signal. The output-low states, the signal is + * inactive, e.g. not in reset + */ + mpcie_rst_hog: mpcie-rst-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_LOW>; + output-low; + line-name = "MPCIE_PERST#"; + }; + + /* + * Controls the mPCIE slot WDISABLE pin which is low active + * as disable signal. The output-low states, the signal is + * inactive, e.g. not disabled + */ + mpcie_wdisable_hog: mpcie-wdisable-hog { + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-low; + line-name = "MPCIE_WDISABLE#"; + }; + }; + + expander1: gpio@71 { + compatible = "nxp,pca9538"; + reg = <0x71>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3v3>; + gpio-line-names = "ENET1_RESET#", "ENET2_RESET#", + "USB_RESET#", "", + "WLAN_PD#", "WLAN_W_DISABLE#", + "WLAN_PERST#", "12V_EN"; + + /* + * Controls the on board USB Hub reset which is low + * active as reset signal. The output-low states, the + * signal is inactive, e.g. no reset + */ + usb-reset-hog { + gpio-hog; + gpios = <2 GPIO_ACTIVE_LOW>; + output-low; + line-name = "USB_RESET#"; + }; + + /* + * Controls the WiFi card PD pin which is low active + * as power down signal. The output-high states, the signal + * is active, e.g. card is powered down + */ + wlan-pd-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_PD#"; + }; + + /* + * Controls the WiFi card disable pin which is low active + * as disable signal. The output-high states, the signal + * is active, e.g. card is disabled + */ + wlan-wdisable-hog { + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_W_DISABLE#"; + }; + + /* + * Controls the WiFi card reset pin which is low active + * as reset signal. The output-high states, the signal + * is active, e.g. card in reset + */ + wlan-perst-hog { + gpio-hog; + gpios = <6 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_PERST#"; + }; + }; + + expander2: gpio@72 { + compatible = "nxp,pca9538"; + reg = <0x72>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3v3>; + gpio-line-names = "LCD_RESET#", "LCD_PWR_EN", + "LCD_BLT_EN", "DP_EN", + "MIPI_CSI_EN", "MIPI_CSI_RST#", + "USER_LED1", "USER_LED2"; + }; +}; + +&lpi2c5 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c5>; + pinctrl-1 = <&pinctrl_lpi2c5>; + status = "okay"; +}; + +&lpspi6 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpspi6>; + pinctrl-1 = <&pinctrl_lpspi6>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&lpuart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + linux,rs485-enabled-at-boot-time; + status = "okay"; +}; + +/* disabled per default, console for M33 */ +&lpuart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; +}; + +&lpuart6 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart6>; + status = "okay"; +}; + +&lpuart8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart8>; + status = "okay"; +}; + +&tpm5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm5>; +}; + +&tpm6 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm6>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_hs>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_usdhc2_vmmc>; + bus-width = <4>; + no-sdio; + no-mmc; + disable-wp; + status = "okay"; +}; + +&iomuxc { + pinctrl_eqos: eqosgrp { + fsl,pins = < + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET1_MDC__ENET_QOS_MDC 0x51e + MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO 0x4000051e + /* PD | FSEL_2 | DSE X6 */ + MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0 0x57e + MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e + MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e + MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e + /* PD | FSEL_3 | DSE X6 */ + MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x5fe + MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x51e + MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x51e + MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x51e + MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x51e + MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x51e + /* PD | FSEL_3 | DSE X3 */ + MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x58e + >; + }; + + pinctrl_eqos_phy: eqosphygrp { + fsl,pins = < + MX93_PAD_CCM_CLKO1__GPIO3_IO26 0x1306 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET2_MDC__ENET1_MDC 0x51e + MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x4000051e + /* PD | FSEL_2 | DSE X6 */ + MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e + MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e + MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2 0x57e + MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3 0x57e + /* PD | FSEL_3 | DSE X6 */ + MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC 0x5fe + MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x51e + MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x51e + MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2 0x51e + MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3 0x51e + MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x51e + /* PD | FSEL_3 | DSE X3 */ + MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC 0x58e + >; + }; + + pinctrl_fec_phy: fecphygrp { + fsl,pins = < + MX93_PAD_CCM_CLKO2__GPIO3_IO27 0x1306 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX93_PAD_PDM_BIT_STREAM0__CAN1_RX 0x139e + MX93_PAD_PDM_CLK__CAN1_TX 0x139e + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX93_PAD_GPIO_IO25__CAN2_TX 0x139e + MX93_PAD_GPIO_IO27__CAN2_RX 0x139e + >; + }; + + pinctrl_lpi2c3: lpi2c3grp { + fsl,pins = < + MX93_PAD_GPIO_IO28__LPI2C3_SDA 0x40000b9e + MX93_PAD_GPIO_IO29__LPI2C3_SCL 0x40000b9e + >; + }; + + pinctrl_lpi2c5: lpi2c5grp { + fsl,pins = < + MX93_PAD_GPIO_IO22__LPI2C5_SDA 0x40000b9e + MX93_PAD_GPIO_IO23__LPI2C5_SCL 0x40000b9e + >; + }; + + pinctrl_lpspi6: lpspi6grp { + fsl,pins = < + MX93_PAD_GPIO_IO00__LPSPI6_PCS0 0x3fe + MX93_PAD_GPIO_IO01__LPSPI6_SIN 0x3fe + MX93_PAD_GPIO_IO02__LPSPI6_SOUT 0x3fe + MX93_PAD_GPIO_IO03__LPSPI6_SCK 0x3fe + >; + }; + + pinctrl_pexp_irq: pexpirqgrp { + fsl,pins = < + MX93_PAD_SAI1_TXC__GPIO1_IO12 0x1306 + >; + }; + + pinctrl_pwmfan: pwmfangrp { + fsl,pins = < + MX93_PAD_GPIO_IO09__GPIO2_IO09 0x1306 + >; + }; + + pinctrl_tpm5: tpm5grp { + fsl,pins = < + MX93_PAD_GPIO_IO06__TPM5_CH0 0x57e + >; + }; + + pinctrl_tpm6: tpm6grp { + fsl,pins = < + MX93_PAD_GPIO_IO08__TPM6_CH0 0x57e + >; + }; + + pinctrl_typec: typecgrp { + fsl,pins = < + MX93_PAD_I2C2_SCL__GPIO1_IO02 0x1306 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX93_PAD_UART1_RXD__LPUART1_RX 0x31e + MX93_PAD_UART1_TXD__LPUART1_TX 0x31e + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX93_PAD_UART2_TXD__LPUART2_TX 0x31e + MX93_PAD_UART2_RXD__LPUART2_RX 0x31e + MX93_PAD_SAI1_TXD0__LPUART2_RTS_B 0x51e + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX93_PAD_GPIO_IO14__LPUART3_TX 0x31e + MX93_PAD_GPIO_IO15__LPUART3_RX 0x31e + >; + }; + + pinctrl_uart6: uart6grp { + fsl,pins = < + MX93_PAD_GPIO_IO04__LPUART6_TX 0x31e + MX93_PAD_GPIO_IO05__LPUART6_RX 0x31e + >; + }; + + pinctrl_uart8: uart8grp { + fsl,pins = < + MX93_PAD_GPIO_IO12__LPUART8_TX 0x31e + MX93_PAD_GPIO_IO13__LPUART8_RX 0x31e + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e + >; + }; + + pinctrl_usdhc2_hs: usdhc2hsgrp { + fsl,pins = < + /* HYS | PD | PU | FSEL_3 | DSE X5 */ + MX93_PAD_SD2_CLK__USDHC2_CLK 0x17be + /* HYS | PD | PU | FSEL_3 | DSE X4 */ + MX93_PAD_SD2_CMD__USDHC2_CMD 0x139e + /* HYS | PD | PU | FSEL_3 | DSE X3 */ + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x138e + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x138e + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x138e + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x138e + /* PD | PU | FSEL_2 | DSE X3 */ + MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x50e + >; + }; + + pinctrl_usdhc2_uhs: usdhc2uhsgrp { + fsl,pins = < + /* HYS | PD | PU | FSEL_3 | DSE X6 */ + MX93_PAD_SD2_CLK__USDHC2_CLK 0x17fe + /* HYS | PD | PU | FSEL_3 | DSE X4 */ + MX93_PAD_SD2_CMD__USDHC2_CMD 0x139e + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x139e + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x139e + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x139e + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x139e + /* PD | PU | FSEL_2 | DSE X3 */ + MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x50e + >; + }; +}; From 0d4ac04fa7c3f6dc263dba6f575a2ec7a2d4eca8 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:15:53 +0200 Subject: [PATCH 1488/7721] ARM: dts: imx7d: Fix coresight funnel ports imx7d uses two ports for 'in-ports', so the syntax port@ has to be used. imx7d has both port and port@1 nodes present, raising these error: funnel@30041000: in-ports: More than one condition true in oneOf schema funnel@30041000: Unevaluated properties are not allowed ('in-ports' was unexpected) Fix this by also using port@0 for imx7s as well. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7d.dtsi | 3 --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi index 4b94b8afb55d..0484e349e064 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi @@ -217,9 +217,6 @@ fec2: ethernet@30bf0000 { }; &ca_funnel_in_ports { - #address-cells = <1>; - #size-cells = <0>; - port@1 { reg = <1>; ca_funnel_in_port1: endpoint { diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 29b8fd03567a..8e05ab545213 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -190,7 +190,11 @@ funnel@30041000 { clock-names = "apb_pclk"; ca_funnel_in_ports: in-ports { - port { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; ca_funnel_in_port0: endpoint { remote-endpoint = <&etm0_out_port>; }; From 5f55da4cc37051cda600ea870ce8cf29f1297715 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:15:54 +0200 Subject: [PATCH 1489/7721] ARM: dts: imx7s: Fix lcdif compatible imx7d-lcdif is compatible to imx6sx-lcdif. MXSFB_V6 supports overlay by using LCDC_AS_CTRL register. This registers used by overlay plane: * LCDC_AS_CTRL * LCDC_AS_BUF * LCDC_AS_NEXT_BUF are listed in i.MX7D RM as well. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 8e05ab545213..3d221f8cba74 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -815,7 +815,7 @@ csi_from_csi_mux: endpoint { }; lcdif: lcdif@30730000 { - compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif"; + compatible = "fsl,imx7d-lcdif", "fsl,imx6sx-lcdif"; reg = <0x30730000 0x10000>; interrupts = ; clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>, From 4aadb841ed49bada1415c48c44d21f5b69e01299 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:15:55 +0200 Subject: [PATCH 1490/7721] ARM: dts: imx7s: Fix nand-controller #size-cells nand-controller.yaml bindings says #size-cells shall be set to 0. Fixes the dtbs_check warning: arch/arm/boot/dts/nxp/imx/imx7s-mba7.dtb: nand-controller@33002000: #size-cells:0:0: 0 was expected from schema $id: http://devicetree.org/schemas/mtd/gpmi-nand.yaml# Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 3d221f8cba74..608eeac4213b 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -1279,7 +1279,7 @@ dma_apbh: dma-controller@33000000 { gpmi: nand-controller@33002000 { compatible = "fsl,imx7d-gpmi-nand"; #address-cells = <1>; - #size-cells = <1>; + #size-cells = <0>; reg = <0x33002000 0x2000>, <0x33004000 0x4000>; reg-names = "gpmi-nand", "bch"; interrupts = ; From cbad7024a7a9295fdf79b58aa4c2e52f5d014d60 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:15:56 +0200 Subject: [PATCH 1491/7721] ARM: dts: imx7s: Add missing #thermal-sensor-cells imx-thermal.yaml is referencing thermal-sensor.yaml, thus this property is required. Fixes the dtbs_check warning: arch/arm/boot/dts/nxp/imx/imx7d-mba7.dtb: tempmon: '#thermal-sensor-cells' is a required property from schema $id: http://devicetree.org/schemas/thermal/imx-thermal.yaml# Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 608eeac4213b..b563383be695 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -609,6 +609,7 @@ tempmon: tempmon { nvmem-cells = <&tempmon_calib>, <&fuse_grade>; nvmem-cell-names = "calib", "temp_grade"; clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>; + #thermal-sensor-cells = <0>; }; }; From 71f9f77f273644bbc6671927db68ff44018db758 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:31:21 +0200 Subject: [PATCH 1492/7721] arm64: dts: imx8mp: Add CCM interrupts Add both CCM interrupts as mentioned in RM. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index c9a610ba4836..3ad97b7dcb2c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -726,6 +726,8 @@ snvs_lpgpr: snvs-lpgpr { clk: clock-controller@30380000 { compatible = "fsl,imx8mp-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; From ba6f55e3691974d063a5671447f49f58c4d35146 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:31:22 +0200 Subject: [PATCH 1493/7721] arm64: dts: imx8mn: Add CCM interrupts Add both CCM interrupts as mentioned in RM. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mn.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index 1bb1d0c1bae4..136e75c51251 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -637,6 +637,8 @@ snvs_pwrkey: snvs-powerkey { clk: clock-controller@30380000 { compatible = "fsl,imx8mn-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; From 4f776504a9ab719e8ea997e9d0321883c6e29aaf Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Oct 2023 10:31:23 +0200 Subject: [PATCH 1494/7721] arm64: dts: imx8mm: Add CCM interrupts Add both CCM interrupts as mentioned in RM. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 738024baaa57..e76fc9fb1bf4 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -636,6 +636,8 @@ snvs_lpgpr: snvs-lpgpr { clk: clock-controller@30380000 { compatible = "fsl,imx8mm-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; From 5946b71eacf7fae680887c7de6bbc4f470108280 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Thu, 12 Oct 2023 20:41:17 -0500 Subject: [PATCH 1495/7721] arm64: dts: imx8mp-beacon-kit: Enable DSI to HDMI Bridge The baseboard of the Beacon i.MX8M Plus development kit has an ADV7535 DSI to HDMI bridge capable of stereo sound. Signed-off-by: Adam Ford Signed-off-by: Shawn Guo --- .../boot/dts/freescale/imx8mp-beacon-kit.dts | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts index 0bea0798d2db..feae77e03835 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts @@ -94,6 +94,17 @@ button-3 { }; }; + bridge-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&adv7535_out>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -153,6 +164,21 @@ reg_usb1_host_vbus: regulator-usb1-vbus { enable-active-high; }; + sound-adv7535 { + compatible = "simple-audio-card"; + simple-audio-card,name = "sound-adv7535"; + simple-audio-card,format = "i2s"; + + simple-audio-card,cpu { + sound-dai = <&sai5>; + system-clock-direction-out; + }; + + simple-audio-card,codec { + sound-dai = <&adv_bridge>; + }; + }; + sound-dmic { compatible = "simple-audio-card"; simple-audio-card,name = "sound-pdm"; @@ -274,6 +300,35 @@ pca6416_3: gpio@20 { #interrupt-cells = <2>; }; + adv_bridge: hdmi@3d { + compatible = "adi,adv7535"; + reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>; + reg-names = "main", "cec", "edid", "packet"; + adi,dsi-lanes = <4>; + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adv7535_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + adv7535_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + pcieclk: clock-generator@68 { compatible = "renesas,9fgv0241"; reg = <0x68>; @@ -398,6 +453,10 @@ hd3ss3220_out_ep: endpoint { }; }; +&lcdif1 { + status = "okay"; +}; + &micfil { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pdm>; @@ -407,6 +466,21 @@ &micfil { status = "okay"; }; +&mipi_dsi { + samsung,esc-clock-frequency = <10000000>; + status = "okay"; + + ports { + port@1 { + reg = <1>; + + dsi_out: endpoint { + remote-endpoint = <&adv7535_in>; + }; + }; + }; +}; + &pcie { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pcie>; @@ -433,6 +507,16 @@ &sai3 { status = "okay"; }; +&sai5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai5>; + assigned-clocks = <&clk IMX8MP_CLK_SAI5>; + assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; + assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + status = "okay"; +}; + &snvs_pwrkey { status = "okay"; }; @@ -612,6 +696,14 @@ MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK 0xd6 >; }; + pinctrl_sai5: sai5grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI5_TX_DATA00 0xd6 + MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI5_TX_BCLK 0xd6 + MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI5_TX_SYNC 0xd6 + >; + }; + pinctrl_tpm: tpmgrp { fsl,pins = < MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00 0x19 /* Reset */ From beaf2e34dad561cfe465db5348f759b0d65c5441 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Fri, 13 Oct 2023 15:39:59 +0200 Subject: [PATCH 1496/7721] ARM: dts: imx6qdl: mba6: fix typo in comments Replace 'SPPEED' with 'SPEED' Signed-off-by: Markus Niebel Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi index da0f8dae1ea8..4d2abcd44eff 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi @@ -500,21 +500,21 @@ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x001b0f0 /* #PCIE.DIS */ pinctrl_pwm1: pwm1grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_GPIO_9__PWM1_OUT 0x00003050 >; }; pinctrl_pwm3: pwm3grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x00003050 >; }; pinctrl_pwm4: pwm4grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x00003050 >; }; From 43a116148fdd17df511829d9f542483075988bd5 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Fri, 13 Oct 2023 15:40:00 +0200 Subject: [PATCH 1497/7721] ARM: dts: imx6ul: mba6ulx: fix typo in comments Replace 'SPPEED' with 'SPEED' Signed-off-by: Markus Niebel Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi b/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi index 5a8b867d7d79..e78d0a7d8cd2 100644 --- a/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi @@ -467,7 +467,7 @@ MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 pinctrl_pwm2: pwm2grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6UL_PAD_GPIO1_IO09__PWM2_OUT 0x00003050 >; }; From f6862104ff3a56656edefd003bf1be6d89fabda4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Oct 2023 22:01:24 +0200 Subject: [PATCH 1498/7721] arm64: dts: imx8mp: Describe M24C32-D write-lockable page in DH i.MX8MP DHCOM DT The i.MX8MP DHCOM SoM production rev.200 is populated with M24C32-D EEPROMs which have Additional Write lockable page at separate I2C address. Describe the page in DT to make it available. Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi index d8963f32ec84..4ae4fdab461e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi @@ -420,6 +420,18 @@ eeprom1: eeprom@53 { /* EEPROM with FEC MAC address */ reg = <0x53>; }; + eeprom0wl: eeprom@58 { + compatible = "atmel,24c32d-wl"; /* M24C32-D WL page of 0x50 */ + pagesize = <32>; + reg = <0x58>; + }; + + eeprom1wl: eeprom@5b { + compatible = "atmel,24c32d-wl"; /* M24C32-D WL page of 0x53 */ + pagesize = <32>; + reg = <0x5b>; + }; + ioexp: gpio@74 { compatible = "nxp,pca9539"; reg = <0x74>; From bb89601282fc660d2bd312ac6e2baab0fe9e922c Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 17 Oct 2023 14:50:46 +0800 Subject: [PATCH 1499/7721] arm64: dts: imx93-11x11-evk: set SION for cmd and data pad of USDHC imx93 pad integrate has one issue, refer to ERR052021: ERR052021 uSDHC: Sometimes uSDHC does not work under VDD_SOC low drive mode and nominal mode Description: uSDHC PADs have one integration issue. When CMD/DATA lines direction change from output to input, uSDHC controller begin sampling, the integration issue will make input enable signal from uSDHC propagated to the PAD with a long delay, thus the new input value on the pad comes to uSDHC lately. The uSDHC sampled the old input value and the sampling result is wrong. Workaround: Set uSDHC CMD/DATA PADs iomux register SION bit to 1, then PADs will propagate input to uSDHC with no delay, so correct value is sampled. This issue will wrongly trigger the start bit when sample the USDHC command response, cause the USDHC trigger command CRC/index/endbit error, which will finally impact the tuning pass window, espically will impact the standard tuning logic, and can't find a correct delay cell to get the best timing. Signed-off-by: Haibo Chen Signed-off-by: Shawn Guo --- .../boot/dts/freescale/imx93-11x11-evk.dts | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts index 2b9d47716f75..021caf471bf6 100644 --- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts @@ -237,18 +237,19 @@ MX93_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B 0x31e >; }; + /* need to config the SION for data and cmd pad, refer to ERR052021 */ pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX93_PAD_SD1_CLK__USDHC1_CLK 0x15fe - MX93_PAD_SD1_CMD__USDHC1_CMD 0x13fe - MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x13fe - MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x13fe - MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x13fe - MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x13fe - MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x13fe - MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x13fe - MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x13fe - MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x13fe + MX93_PAD_SD1_CMD__USDHC1_CMD 0x400013fe + MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x400013fe + MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x400013fe + MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x400013fe + MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x400013fe + MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x400013fe + MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x400013fe + MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x400013fe + MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x400013fe MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x15fe >; }; @@ -265,14 +266,15 @@ MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e >; }; + /* need to config the SION for data and cmd pad, refer to ERR052021 */ pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe - MX93_PAD_SD2_CMD__USDHC2_CMD 0x13fe - MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x13fe - MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x13fe - MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x13fe - MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x13fe + MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e >; }; From 6783971e88f68470dbce46da856382fb12bf20f1 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 17 Oct 2023 14:50:47 +0800 Subject: [PATCH 1500/7721] arm64: dts: imx93: change tuning start to get a large scan range for standard tuning For original setting, the start point is 20, after the SION setting, ERR052021 can be workaround, but start point from 20 is too large, especially for the LD 133MHz case. Set the tuning start point as 1, tuning step as 2, so that, for the 40 times tuning logic, it can cover 1~81, its large and safe enough for all different devices like eMMC/SD/SDIO. Signed-off-by: Haibo Chen Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index e6745801308e..081859e5c3bd 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -963,7 +963,7 @@ usdhc1: mmc@42850000 { <&clk IMX93_CLK_USDHC1_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <8>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; @@ -977,7 +977,7 @@ usdhc2: mmc@42860000 { <&clk IMX93_CLK_USDHC2_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; @@ -1040,7 +1040,7 @@ usdhc3: mmc@428b0000 { <&clk IMX93_CLK_USDHC3_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; From 47a34668179f6df2832e817db2083f0f02d65256 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 17 Oct 2023 14:50:48 +0800 Subject: [PATCH 1501/7721] arm64: dts: imx93-11x11-evk: add 12 ms delay to make sure the VDD_SD power off To support SD3.0 mode, according to the SD spec, a clean power off for the VDD_SD is keep the VDD_SD lower than 0.5V for at least 1ms. On imx93 board, gate off the VDD_SD, it will cost about 10ms to see the voltage change from 3.3v to 0.5v. So at least need to dealy 11ms to make sure a clean power off and power on. Here add 12ms dealy. Signed-off-by: Haibo Chen Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts index 021caf471bf6..9921ea13ab48 100644 --- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts @@ -76,6 +76,7 @@ reg_usdhc2_vmmc: regulator-usdhc2 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <12000>; enable-active-high; }; }; From d68b9a66ae82a0bbaa6746e4286a7bd777084203 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 25 Oct 2023 15:22:42 +0800 Subject: [PATCH 1502/7721] arm64: dts: imx93: update anatop node The anatop module produces PLL and OSC for Clock Controller Module. Since the binding doc has been updated to clock-controller for this module, Let's also update the device tree node. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index 081859e5c3bd..d3a99d7abba4 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -449,9 +449,10 @@ mediamix: power-domain@44462400 { }; }; - anatop: anatop@44480000 { - compatible = "fsl,imx93-anatop", "syscon"; + clock-controller@44480000 { + compatible = "fsl,imx93-anatop"; reg = <0x44480000 0x2000>; + #clock-cells = <1>; }; tmu: tmu@44482000 { From 2854d8cd032c5588f563d65a3c739a01317a8e3c Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 18 Oct 2023 11:08:38 -0700 Subject: [PATCH 1503/7721] arm64: dts: imx8mm-venice-gw72xx: add TPM device Add the TPM device found on the GW72xx revision F PCB. Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- .../arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index 3a0a10e835a2..02d96f4a2d23 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -84,8 +84,15 @@ reg_usb_otg2_vbus: regulator-usb-otg2 { &ecspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2>; - cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio1 10 GPIO_ACTIVE_LOW>; status = "okay"; + + tpm@1 { + compatible = "tcg,tpm_tis-spi"; + reg = <0x1>; + spi-max-frequency = <36000000>; + }; }; &gpio1 { @@ -312,6 +319,7 @@ MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0xd6 MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0xd6 MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0xd6 MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0xd6 + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0xd6 >; }; From 5016f22028e4ef00f19dedff1115dcd3b96d34a5 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 18 Oct 2023 11:09:22 -0700 Subject: [PATCH 1504/7721] arm64: dts: imx8mp-venice-gw72xx: add TPM device Add the TPM device found on the GW72xx revision F PCB. Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- .../arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi index f942e949084b..28eb7c00a1d9 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi @@ -83,8 +83,15 @@ reg_usdhc2_vmmc: regulator-usdhc2-vmmc { &ecspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2>; - cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio1 10 GPIO_ACTIVE_LOW>; status = "okay"; + + tpm@1 { + compatible = "tcg,tpm_tis-spi"; + reg = <0x1>; + spi-max-frequency = <36000000>; + }; }; &gpio4 { @@ -285,6 +292,7 @@ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x140 MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x140 MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x140 MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x140 + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x140 >; }; From fb72b877a6c95d1c758e878b521406913362bcae Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 23 Oct 2023 11:46:12 +0200 Subject: [PATCH 1505/7721] ARM: dts: imx7s: Add DMA channels for CSPI peripherals This adds the rx/tx DMA channels for CSPI peripherals. Channel numbers are taken from i.MX7D RM Rev1 01/2018. Peripheral types ID (7) is selected according to fsl,imx-sdma.yaml and is similar to i.MX6 and i.MX8M platforms. Same goes for transfer priority ID (last number). Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index b563383be695..38a72f969b4e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -725,6 +725,8 @@ ecspi4: spi@30630000 { clocks = <&clks IMX7D_ECSPI4_ROOT_CLK>, <&clks IMX7D_ECSPI4_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 6 7 1>, <&sdma 7 7 2>; status = "disabled"; }; @@ -880,6 +882,8 @@ ecspi1: spi@30820000 { clocks = <&clks IMX7D_ECSPI1_ROOT_CLK>, <&clks IMX7D_ECSPI1_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 0 7 1>, <&sdma 1 7 2>; status = "disabled"; }; @@ -892,6 +896,8 @@ ecspi2: spi@30830000 { clocks = <&clks IMX7D_ECSPI2_ROOT_CLK>, <&clks IMX7D_ECSPI2_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 2 7 1>, <&sdma 3 7 2>; status = "disabled"; }; @@ -904,6 +910,8 @@ ecspi3: spi@30840000 { clocks = <&clks IMX7D_ECSPI3_ROOT_CLK>, <&clks IMX7D_ECSPI3_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 4 7 1>, <&sdma 5 7 2>; status = "disabled"; }; From fcefbb49ebb7ad9f06ecee33ae87e4d7075728ff Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 25 Oct 2023 11:12:21 -0500 Subject: [PATCH 1506/7721] bus: imx-weim: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Signed-off-by: Shawn Guo --- drivers/bus/imx-weim.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 42c9386a7b42..6b5da73c8541 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -11,7 +11,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -202,9 +205,7 @@ static int weim_timing_setup(struct device *dev, struct device_node *np, static int weim_parse_dt(struct platform_device *pdev) { - const struct of_device_id *of_id = of_match_device(weim_id_table, - &pdev->dev); - const struct imx_weim_devtype *devtype = of_id->data; + const struct imx_weim_devtype *devtype = device_get_match_data(&pdev->dev); int ret = 0, have_child = 0; struct device_node *child; struct weim_priv *priv; From b1f5279b5981f9ed851163ee661692f42397982f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 20 Nov 2023 10:26:05 +0200 Subject: [PATCH 1507/7721] drm/i915/psr: Move plane sel fetch configuration into plane source files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently selective fetch configuration for planes is implemented in psr code. More suitable place for this code is where everything else is configured for planes -> move it into skl_universal_plane.c and intel_cursor.c. This also allows us to drop hooks for cursor handling. v3: Checkpatch warnings fixed v2: Removed setting sel_fetch_area->y1/y2 as -1 Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231120082606.3156488-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 33 +++++++- drivers/gpu/drm/i915/display/intel_psr.c | 75 ------------------- drivers/gpu/drm/i915/display/intel_psr.h | 10 --- .../drm/i915/display/skl_universal_plane.c | 75 ++++++++++++++++++- 4 files changed, 102 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index b342fad180ca..c025cafda7d9 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -21,6 +21,7 @@ #include "intel_fb_pin.h" #include "intel_frontbuffer.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "skl_watermark.h" /* Cursor formats */ @@ -484,6 +485,32 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, return 0; } +static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + plane_state->ctl); +} + +static void i9xx_cursor_disable_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + /* TODO: split into noarm+arm pair */ static void i9xx_cursor_update_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -531,10 +558,10 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, skl_write_cursor_wm(plane, crtc_state); if (plane_state) - intel_psr2_program_plane_sel_fetch_arm(plane, crtc_state, - plane_state); + i9xx_cursor_update_sel_fetch_arm(plane, crtc_state, + plane_state); else - intel_psr2_disable_plane_sel_fetch_arm(plane, crtc_state); + i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); if (plane->cursor.base != base || plane->cursor.size != fbc_ctl || diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 15c1804dcd59..e7d65282fb88 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1917,81 +1917,6 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); } -void intel_psr2_disable_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); -} - -void intel_psr2_program_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - if (plane->id == PLANE_CURSOR) - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - plane_state->ctl); - else - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - PLANE_SEL_FETCH_CTL_ENABLE); -} - -void intel_psr2_program_plane_sel_fetch_noarm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - const struct drm_rect *clip; - u32 val; - int x, y; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - if (plane->id == PLANE_CURSOR) - return; - - clip = &plane_state->psr2_sel_fetch_area; - - val = (clip->y1 + plane_state->uapi.dst.y1) << 16; - val |= plane_state->uapi.dst.x1; - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_POS(pipe, plane->id), val); - - x = plane_state->view.color_plane[color_plane].x; - - /* - * From Bspec: UV surface Start Y Position = half of Y plane Y - * start position. - */ - if (!color_plane) - y = plane_state->view.color_plane[color_plane].y + clip->y1; - else - y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2; - - val = y << 16 | x; - - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id), - val); - - /* Sizes are 0 based */ - val = (drm_rect_height(clip) - 1) << 16; - val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1; - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val); -} - void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 6a1f4573852b..143e0595c097 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -55,16 +55,6 @@ bool intel_psr_enabled(struct intel_dp *intel_dp); int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state); -void intel_psr2_program_plane_sel_fetch_noarm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane); -void intel_psr2_program_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); - -void intel_psr2_disable_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state); void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index f5c77a018e10..0cac8be0c77b 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -18,6 +18,7 @@ #include "intel_fbc.h" #include "intel_frontbuffer.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" @@ -629,6 +630,18 @@ skl_plane_disable_arm(struct intel_plane *plane, intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); } +static void icl_plane_disable_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + static void icl_plane_disable_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state) @@ -642,7 +655,7 @@ icl_plane_disable_arm(struct intel_plane *plane, skl_write_plane_wm(plane, crtc_state); - intel_psr2_disable_plane_sel_fetch_arm(plane, crtc_state); + icl_plane_disable_sel_fetch_arm(plane, crtc_state); intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); } @@ -1197,6 +1210,48 @@ skl_plane_update_arm(struct intel_plane *plane, skl_plane_surf(plane_state, 0)); } +static void icl_plane_update_sel_fetch_noarm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + int color_plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + const struct drm_rect *clip; + u32 val; + int x, y; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + clip = &plane_state->psr2_sel_fetch_area; + + val = (clip->y1 + plane_state->uapi.dst.y1) << 16; + val |= plane_state->uapi.dst.x1; + intel_de_write_fw(i915, PLANE_SEL_FETCH_POS(pipe, plane->id), val); + + x = plane_state->view.color_plane[color_plane].x; + + /* + * From Bspec: UV surface Start Y Position = half of Y plane Y + * start position. + */ + if (!color_plane) + y = plane_state->view.color_plane[color_plane].y + clip->y1; + else + y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2; + + val = y << 16 | x; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_OFFSET(pipe, plane->id), + val); + + /* Sizes are 0 based */ + val = (drm_rect_height(clip) - 1) << 16; + val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1; + intel_de_write_fw(i915, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val); +} + static void icl_plane_update_noarm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -1269,7 +1324,21 @@ icl_plane_update_noarm(struct intel_plane *plane, if (plane_state->force_black) icl_plane_csc_load_black(plane); - intel_psr2_program_plane_sel_fetch_noarm(plane, crtc_state, plane_state, color_plane); + icl_plane_update_sel_fetch_noarm(plane, crtc_state, plane_state, color_plane); +} + +static void icl_plane_update_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + PLANE_SEL_FETCH_CTL_ENABLE); } static void @@ -1296,7 +1365,7 @@ icl_plane_update_arm(struct intel_plane *plane, if (plane_state->scaler_id >= 0) skl_program_plane_scaler(plane, crtc_state, plane_state); - intel_psr2_program_plane_sel_fetch_arm(plane, crtc_state, plane_state); + icl_plane_update_sel_fetch_arm(plane, crtc_state, plane_state); /* * The control register self-arms if the plane was previously From a4f477e6ac171ccdea38556437493c3c5222bbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 20 Nov 2023 10:26:06 +0200 Subject: [PATCH 1508/7721] drm/i915/psr: Add proper handling for disabling sel fetch for planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we are enabling selective fetch for all planes that are visible. This is suboptimal as we might be fetching for memory for planes that are not part of selective update. Fix this by adding proper handling for disabling plane selective fetch: If plane previously part of selective update is now not part of update: Add it into updated planes and let the plane configuration to disable selective fetch for it. v3: Checkpatch warnings fixed v2: - Add setting sel_fetch_area->y1/y2 to -1 - Remove setting again local sel_fetch_area variable Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231120082606.3156488-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 31 ++++++++++--------- drivers/gpu/drm/i915/display/intel_psr.c | 13 +++++++- .../drm/i915/display/skl_universal_plane.c | 7 +++-- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index c025cafda7d9..a515ae2831f8 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -485,6 +485,18 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, return 0; } +static void i9xx_cursor_disable_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) @@ -495,20 +507,11 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, if (!crtc_state->enable_psr2_sel_fetch) return; - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - plane_state->ctl); -} - -static void i9xx_cursor_disable_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + plane_state->ctl); + else + i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); } /* TODO: split into noarm+arm pair */ diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index e7d65282fb88..36e4a1e9b98f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2176,8 +2176,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, continue; inter = pipe_clip; - if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) + sel_fetch_area = &new_plane_state->psr2_sel_fetch_area; + if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) { + sel_fetch_area->y1 = -1; + sel_fetch_area->y2 = -1; + /* + * if plane sel fetch was previously enabled -> + * disable it + */ + if (drm_rect_height(&old_plane_state->psr2_sel_fetch_area) > 0) + crtc_state->update_planes |= BIT(plane->id); + continue; + } if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) { full_update = true; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 0cac8be0c77b..511dc1544854 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1337,8 +1337,11 @@ static void icl_plane_update_sel_fetch_arm(struct intel_plane *plane, if (!crtc_state->enable_psr2_sel_fetch) return; - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - PLANE_SEL_FETCH_CTL_ENABLE); + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + PLANE_SEL_FETCH_CTL_ENABLE); + else + icl_plane_disable_sel_fetch_arm(plane, crtc_state); } static void From beb9c30ba4188e481991d91124c554f61a7ec121 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 24 Nov 2023 09:41:13 +0100 Subject: [PATCH 1509/7721] dt-bindings: soc: amlogic,meson-gx-hhi-sysctrl: add example covering meson-axg-hhi-sysctrl Add a third example covering the meson-axg-hhi-sysctrl variant and more importantly the phy subnode. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231124-amlogic-v6-4-upstream-dsi-ccf-vim3-v9-2-95256ed139e6@linaro.org Signed-off-by: Neil Armstrong --- .../amlogic/amlogic,meson-gx-hhi-sysctrl.yaml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml index 16977e4e4357..c6bce40946d4 100644 --- a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml +++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml @@ -158,3 +158,36 @@ examples: }; }; }; + + - | + system-controller@ff63c000 { + compatible = "amlogic,meson-axg-hhi-sysctrl", "simple-mfd", "syscon"; + reg = <0xff63c000 0x400>; + + clock-controller { + compatible = "amlogic,axg-clkc"; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "xtal"; + }; + + power-controller { + compatible = "amlogic,meson-axg-pwrc"; + #power-domain-cells = <1>; + amlogic,ao-sysctrl = <&sysctrl_AO>; + + resets = <&reset_viu>, + <&reset_venc>, + <&reset_vcbus>, + <&reset_vencl>, + <&reset_vid_lock>; + reset-names = "viu", "venc", "vcbus", "vencl", "vid_lock"; + clocks = <&clk_vpu>, <&clk_vapb>; + clock-names = "vpu", "vapb"; + }; + + phy { + compatible = "amlogic,axg-mipi-pcie-analog-phy"; + #phy-cells = <0>; + }; + }; From a30c7a73b0ad50c40c01811fa23e74764c3ba007 Mon Sep 17 00:00:00 2001 From: Huqiang Qin Date: Fri, 27 Oct 2023 18:43:57 +0800 Subject: [PATCH 1510/7721] arm64: dts: Add watchdog node for Amlogic C3 SoCs Add watchdog device. Signed-off-by: Huqiang Qin Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231027104358.342861-3-huqiang.qin@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi index 998f5050795c..2ad1f8eef199 100644 --- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi @@ -81,6 +81,12 @@ apb4: bus@fe000000 { #size-cells = <2>; ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + watchdog@2100 { + compatible = "amlogic,c3-wdt", "amlogic,t7-wdt"; + reg = <0x0 0x2100 0x0 0x10>; + clocks = <&xtal>; + }; + periphs_pinctrl: pinctrl@4000 { compatible = "amlogic,c3-periphs-pinctrl"; #address-cells = <2>; From 2d66f91208d1174eb8ad29706e8bdfb587a34d5c Mon Sep 17 00:00:00 2001 From: Huqiang Qin Date: Fri, 27 Oct 2023 18:43:58 +0800 Subject: [PATCH 1511/7721] arm64: dts: Add watchdog node for Amlogic S4 SoCs Add watchdog device. Signed-off-by: Huqiang Qin Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231027104358.342861-4-huqiang.qin@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi index e0cfc54ebccb..2344b2d741c3 100644 --- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi @@ -92,6 +92,12 @@ apb4: bus@fe000000 { #size-cells = <2>; ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + watchdog@2100 { + compatible = "amlogic,s4-wdt", "amlogic,t7-wdt"; + reg = <0x0 0x2100 0x0 0x10>; + clocks = <&xtal>; + }; + periphs_pinctrl: pinctrl@4000 { compatible = "amlogic,meson-s4-periphs-pinctrl"; #address-cells = <2>; From 35b47cefe8955f4c34fe45e5a06cb3376d6a8aa6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:47:00 +0100 Subject: [PATCH 1512/7721] arm64: dts: amlogic: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Viacheslav Bocharov Link: https://lore.kernel.org/r/20231124094700.58071-1-krzysztof.kozlowski@linaro.org Signed-off-by: Neil Armstrong --- .../boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts | 2 +- arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi | 2 +- arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts index 0062667c4f65..c9e84db0831a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts @@ -30,7 +30,7 @@ &sd_emmc_b { &uart_B { bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOZ_8 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi index 995ce10d5c81..08c33ec7e9f1 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi @@ -369,7 +369,7 @@ &uart_A { bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi index 0a6a12808568..4b8db872bbf3 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi @@ -487,7 +487,7 @@ &uart_A { bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; }; From be18d53c32b2bbb211f4be599cafdb9d9ecab040 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Thu, 9 Nov 2023 12:45:04 +0300 Subject: [PATCH 1513/7721] arm64: dts: amlogic: meson-axg: pinctrl node for NAND Add pinctrl node for the Meson NAND controller. Signed-off-by: Arseniy Krasnov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231109094504.131265-1-avkrasnov@salutedevices.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi index a49aa62e3f9f..7e5ac9db93f8 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi @@ -432,6 +432,27 @@ mux-1 { }; }; + nand_all_pins: nand-all-pins { + mux { + groups = "emmc_nand_d0", + "emmc_nand_d1", + "emmc_nand_d2", + "emmc_nand_d3", + "emmc_nand_d4", + "emmc_nand_d5", + "emmc_nand_d6", + "emmc_nand_d7", + "nand_ce0", + "nand_ale", + "nand_cle", + "nand_wen_clk", + "nand_ren_wr"; + function = "nand"; + input-enable; + bias-pull-up; + }; + }; + emmc_ds_pins: emmc_ds { mux { groups = "emmc_ds"; @@ -1913,6 +1934,8 @@ nfc: nand-controller@7800 { reg = <0x0 0x7800 0x0 0x100>, <0x0 0x7000 0x0 0x800>; reg-names = "nfc", "emmc"; + pinctrl-0 = <&nand_all_pins>; + pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; interrupts = ; From bee505184fd5543b9e901a37523e39fd1db06860 Mon Sep 17 00:00:00 2001 From: Viacheslav Bocharov Date: Thu, 2 Nov 2023 09:12:33 +0300 Subject: [PATCH 1514/7721] arm64: dts: meson-axg: jethub-jxx add support for EEPROM Add dts node for EEPROM placed on baseboard in JetHub D1+ devices. Signed-off-by: Viacheslav Bocharov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231102061233.3113249-1-adeep@lexina.in Signed-off-by: Neil Armstrong --- .../amlogic/meson-axg-jethome-jethub-j110-rev-2.dts | 12 ++++++++++++ .../amlogic/meson-axg-jethome-jethub-j110-rev-3.dts | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts index c9e84db0831a..8a18ce948450 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts @@ -35,3 +35,15 @@ bluetooth { device-wake-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>; }; }; + +&i2c_AO { + /* EEPROM on base board */ + eeprompd: eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + pagesize = <0x20>; + label = "eeprompd"; + address-width = <0x10>; + vcc-supply = <&vddao_3v3>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts index c2d22b00c1cd..c356bd2cc63a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts @@ -25,3 +25,15 @@ memory@0 { &sd_emmc_b { broken-cd;/* cd-gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;*/ }; + +&i2c_AO { + /* EEPROM on base board */ + eeprompd: eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + pagesize = <0x20>; + label = "eeprompd"; + address-width = <0x10>; + vcc-supply = <&vddao_3v3>; + }; +}; From d397965e584e0f2c6193b927c1e7693d514a6738 Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Wed, 8 Nov 2023 15:56:03 +0300 Subject: [PATCH 1515/7721] firmware: meson_sm: refactor serial sysfs entry via dev_groups attrs Introduce just another way to register sysfs serial entry: the less code, the better in the absence of extra error-paths Signed-off-by: Evgeny Bachinin Acked-by: Neil Armstrong Link: https://lore.kernel.org/r/20231108125604.162383-2-EABachinin@salutedevices.com Signed-off-by: Neil Armstrong --- drivers/firmware/meson/meson_sm.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index ed60f1103053..fb766e40a631 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -274,14 +274,11 @@ static ssize_t serial_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(serial); -static struct attribute *meson_sm_sysfs_attributes[] = { +static struct attribute *meson_sm_sysfs_attrs[] = { &dev_attr_serial.attr, NULL, }; - -static const struct attribute_group meson_sm_sysfs_attr_group = { - .attrs = meson_sm_sysfs_attributes, -}; +ATTRIBUTE_GROUPS(meson_sm_sysfs); static const struct of_device_id meson_sm_ids[] = { { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, @@ -323,9 +320,6 @@ static int __init meson_sm_probe(struct platform_device *pdev) if (devm_of_platform_populate(dev)) goto out_in_base; - if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) - goto out_in_base; - pr_info("secure-monitor enabled\n"); return 0; @@ -340,6 +334,7 @@ static struct platform_driver meson_sm_driver = { .driver = { .name = "meson-sm", .of_match_table = of_match_ptr(meson_sm_ids), + .dev_groups = meson_sm_sysfs_groups, }, }; module_platform_driver_probe(meson_sm_driver, meson_sm_probe); From d8385d7433f9c7d718448465e30d6b8c1207b59f Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Wed, 8 Nov 2023 15:56:04 +0300 Subject: [PATCH 1516/7721] firmware: meson-sm: unmap out_base shmem in error path When SM driver was introduced in [1], the code flow did not require to unmap out_base shmem in case of errors inside probe(). During [2], the additional error path appeared, which requires unmap. Patch adds iounmap() missed. Links: [1] https://lore.kernel.org/linux-amlogic/1466339944-602-2-git-send-email-carlo@caione.org/ [2] https://lore.kernel.org/linux-amlogic/1532613556-5398-1-git-send-email-narmstrong@baylibre.com/ Fixes: 0789724f86a5 ("firmware: meson_sm: Add serial number sysfs entry") Signed-off-by: Evgeny Bachinin Acked-by: Neil Armstrong Link: https://lore.kernel.org/r/20231108125604.162383-3-EABachinin@salutedevices.com Signed-off-by: Neil Armstrong --- drivers/firmware/meson/meson_sm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index fb766e40a631..5d7f62fe1d5f 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -310,7 +310,7 @@ static int __init meson_sm_probe(struct platform_device *pdev) fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, chip->shmem_size); if (WARN_ON(!fw->sm_shmem_out_base)) - goto out_in_base; + goto unmap_in_base; } fw->chip = chip; @@ -318,13 +318,15 @@ static int __init meson_sm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fw); if (devm_of_platform_populate(dev)) - goto out_in_base; + goto unmap_out_base; pr_info("secure-monitor enabled\n"); return 0; -out_in_base: +unmap_out_base: + iounmap(fw->sm_shmem_out_base); +unmap_in_base: iounmap(fw->sm_shmem_in_base); out: return -EINVAL; From b0a7ce53d494c94dfacb5a877fc0668f2a688652 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Sat, 11 Nov 2023 08:08:56 -0500 Subject: [PATCH 1517/7721] drm/ttm: Schedule delayed_delete worker closer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to allocate system memory on the NUMA node the device is closest to and try to run delayed_delete workers on a CPU of this node as well. To optimize the memory clearing operation when a TTM BO gets freed by the delayed_delete worker, scheduling it closer to a NUMA node where the memory was initially allocated helps avoid the cases where the worker gets randomly scheduled on the CPU cores that are across interconnect boundaries such as xGMI, PCIe etc. This change helps USWC GTT allocations on NUMA systems (dGPU) and AMD APU platforms such as GFXIP9.4.3. Signed-off-by: Rajneesh Bhardwaj Acked-by: Felix Kuehling Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20231111130856.1168304-1-rajneesh.bhardwaj@amd.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo.c | 8 +++++++- drivers/gpu/drm/ttm/ttm_device.c | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index e58b7e249816..edf10618fe2b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -370,7 +370,13 @@ static void ttm_bo_release(struct kref *kref) spin_unlock(&bo->bdev->lru_lock); INIT_WORK(&bo->delayed_delete, ttm_bo_delayed_delete); - queue_work(bdev->wq, &bo->delayed_delete); + + /* Schedule the worker on the closest NUMA node. This + * improves performance since system memory might be + * cleared on free and that is best done on a CPU core + * close to it. + */ + queue_work_node(bdev->pool.nid, bdev->wq, &bo->delayed_delete); return; } diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index d48b39132b32..f5187b384ae9 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -204,7 +204,8 @@ int ttm_device_init(struct ttm_device *bdev, const struct ttm_device_funcs *func if (ret) return ret; - bdev->wq = alloc_workqueue("ttm", WQ_MEM_RECLAIM | WQ_HIGHPRI, 16); + bdev->wq = alloc_workqueue("ttm", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 16); if (!bdev->wq) { ttm_global_release(); return -ENOMEM; @@ -213,7 +214,8 @@ int ttm_device_init(struct ttm_device *bdev, const struct ttm_device_funcs *func bdev->funcs = funcs; ttm_sys_man_init(bdev); - ttm_pool_init(&bdev->pool, dev, NUMA_NO_NODE, use_dma_alloc, use_dma32); + + ttm_pool_init(&bdev->pool, dev, dev_to_node(dev), use_dma_alloc, use_dma32); bdev->vma_manager = vma_manager; spin_lock_init(&bdev->lru_lock); From ac2453d06c768b0604e231d6effabc1c405bd802 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Aug 2023 09:30:06 +0100 Subject: [PATCH 1518/7721] arm64: defconfig: Enable Renesas VersaClock 3 clock generator config Enable the config for the Renesas VersaClock 3 programmable clock generator, as it is populated on RZ/{G2L,G2LC} and RZ/V2L SMARC EVKs. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230824083006.88944-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index b60aa1f89343..5ad2b841aafc 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1192,6 +1192,7 @@ CONFIG_COMMON_CLK_FSL_SAI=y CONFIG_COMMON_CLK_S2MPS11=y CONFIG_COMMON_CLK_PWM=y CONFIG_COMMON_CLK_RS9_PCIE=y +CONFIG_COMMON_CLK_VC3=y CONFIG_COMMON_CLK_VC5=y CONFIG_COMMON_CLK_BD718XX=m CONFIG_CLK_RASPBERRYPI=m From 528db5d82783fb25d812f30ec744a364f94d18f3 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 20 Nov 2023 09:00:24 +0200 Subject: [PATCH 1519/7721] ARM: multi_v7_defconfig: Enable CONFIG_RAVB The Renesas Ethernet AVB driver is used by various iWave RZ/G1 development boards. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231120070024.4079344-15-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 10fd74bf85f9..9a04564566a7 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -272,6 +272,7 @@ CONFIG_KS8851=y CONFIG_LAN966X_SWITCH=m CONFIG_R8169=y CONFIG_SH_ETH=y +CONFIG_RAVB=y CONFIG_SMSC911X=y CONFIG_SNI_AVE=y CONFIG_STMMAC_ETH=y From 7c77368b6c42ec87aed9976288a9b50bccb272a6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Nov 2023 17:01:21 +0100 Subject: [PATCH 1520/7721] ARM: shmobile: defconfig: Refresh for v6.7-rc1 Refresh the defconfig for Renesas ARM systems: - Disable CONFIG_SERIAL_8250_EXAR (auto-enabled since commit 5939ff7ffae095ac ("tty: serial: 8250_exar: Does not use anything from 8250_pci")). Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/b9bdb0fe3635a7eb51a7eca9a06e8146d6ad82db.1700667824.git.geert+renesas@glider.be --- arch/arm/configs/shmobile_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index dfdea295c4af..e2ea369548eb 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -75,6 +75,7 @@ CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_16550A_VARIANTS is not set CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_EXAR is not set CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_8250_EM=y # CONFIG_SERIAL_8250_PERICOM is not set From 7ccd37fbecf31d610adf9aa01667632a418e06d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Sun, 22 Oct 2023 20:19:09 +0200 Subject: [PATCH 1521/7721] arm64: dts: renesas: draak: Make HDMI the default video input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most Gen3 R-Car devices have HDMI as the default video input source, align Draak with them and make HDMI the default. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231022181910.898040-2-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/draak.dtsi | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/draak.dtsi b/arch/arm64/boot/dts/renesas/draak.dtsi index ce57c9ad9672..d56cb04d82b5 100644 --- a/arch/arm64/boot/dts/renesas/draak.dtsi +++ b/arch/arm64/boot/dts/renesas/draak.dtsi @@ -356,12 +356,9 @@ port@3 { * CVBS and HDMI inputs through SW[49-53] * switches. * - * CVBS is the default selection, link it to - * VIN4 here. + * HDMI is the default selection, leave CVBS + * not connected here. */ - adv7180_out: endpoint { - remote-endpoint = <&vin4_in>; - }; }; }; @@ -429,13 +426,14 @@ port@2 { * CVBS and HDMI inputs through SW[49-53] * switches. * - * CVBS is the default selection, leave HDMI - * not connected here. + * HDMI is the default selection, link it to + * VIN4 here. */ adv7612_out: endpoint { pclk-sample = <0>; hsync-active = <0>; vsync-active = <0>; + remote-endpoint = <&vin4_in>; }; }; }; @@ -586,8 +584,8 @@ usb0_pins: usb0 { function = "usb0"; }; - vin4_pins_cvbs: vin4 { - groups = "vin4_data8", "vin4_sync", "vin4_clk"; + vin4_pins: vin4 { + groups = "vin4_data24", "vin4_sync", "vin4_clk"; function = "vin4"; }; }; @@ -735,7 +733,7 @@ &usb2_phy0 { }; &vin4 { - pinctrl-0 = <&vin4_pins_cvbs>; + pinctrl-0 = <&vin4_pins>; pinctrl-names = "default"; status = "okay"; @@ -743,7 +741,7 @@ &vin4 { ports { port { vin4_in: endpoint { - remote-endpoint = <&adv7180_out>; + remote-endpoint = <&adv7612_out>; }; }; }; From 25d324331a17e423642ad717e9c21635531f70fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Sun, 22 Oct 2023 20:19:10 +0200 Subject: [PATCH 1522/7721] arm64: dts: renesas: draak: Move HDMI bus properties to correct node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bus properties for HDMI capture are defined on the incorrect node for the VIN driver to be able to consume them. They are described on the HDMI video source but they should be described on the VIN capture node, move them. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231022181910.898040-3-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/draak.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/draak.dtsi b/arch/arm64/boot/dts/renesas/draak.dtsi index d56cb04d82b5..6f133f54ded5 100644 --- a/arch/arm64/boot/dts/renesas/draak.dtsi +++ b/arch/arm64/boot/dts/renesas/draak.dtsi @@ -430,9 +430,6 @@ port@2 { * VIN4 here. */ adv7612_out: endpoint { - pclk-sample = <0>; - hsync-active = <0>; - vsync-active = <0>; remote-endpoint = <&vin4_in>; }; }; @@ -741,6 +738,9 @@ &vin4 { ports { port { vin4_in: endpoint { + pclk-sample = <0>; + hsync-active = <0>; + vsync-active = <0>; remote-endpoint = <&adv7612_out>; }; }; From ea17f751318639c9348f2fc62c865d688f70a53e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Nov 2023 17:12:41 +0100 Subject: [PATCH 1523/7721] ARM: shmobile: defconfig: Switch to DRM_SHMOBILE Now the DRM driver for the SH-Mobile LCD Controller supports DT, replace the legacy frame buffer device driver by the DRM driver. Disable frame buffer device drivers, as this was the last frame buffer device driver for Renesas ARM systems. Enable CONFIG_DRM_FBDEV_EMULATION and CONFIG_FB_DEVICE, as these are no longer auto-enabled since commit bb6c4507fe825f1b ("drm: fix up fbdev Kconfig defaults"). Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/3d17d8418ddabeb84ff5fa1cdd16439ddc84286f.1700669207.git.geert+renesas@glider.be --- arch/arm/configs/shmobile_defconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index dfdea295c4af..dba6222384c0 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -134,8 +134,10 @@ CONFIG_VIDEO_ADV7604=y CONFIG_VIDEO_ADV7604_CEC=y CONFIG_VIDEO_ML86V7667=y CONFIG_DRM=y +CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_RCAR_DU=y # CONFIG_DRM_RCAR_USE_MIPI_DSI is not set +CONFIG_DRM_SHMOBILE=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_EDP=y CONFIG_DRM_DISPLAY_CONNECTOR=y @@ -144,8 +146,7 @@ CONFIG_DRM_SII902X=y CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_I2C_ADV7511=y CONFIG_DRM_I2C_ADV7511_AUDIO=y -CONFIG_FB=y -CONFIG_FB_SH_MOBILE_LCDC=y +CONFIG_FB_DEVICE=y CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_AS3711=y CONFIG_SOUND=y From 138588e9fa237f9742c691369c023b246f5b0b88 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Nov 2023 17:12:42 +0100 Subject: [PATCH 1524/7721] ARM: dts: renesas: r8a7740: Add LCDC nodes Add device nodes for the two LCD Controllers (LCDC) on the R-Mobile A1 SoC, and for the two optional external LCDL clock inputs. Note that the HDMI clock for LCDC1 is not added, as this clock is not yet supported. Based on a patch by Laurent Pinchart adding the first LCDC device node. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/12dcec10e6fb3b55c39f6221349d35d6d6f17a5d.1700669207.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7740.dtsi | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/arch/arm/boot/dts/renesas/r8a7740.dtsi b/arch/arm/boot/dts/renesas/r8a7740.dtsi index 1b2cf5fa322b..55884ec701f8 100644 --- a/arch/arm/boot/dts/renesas/r8a7740.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7740.dtsi @@ -398,6 +398,61 @@ sh_fsi2: sound@fe1f0000 { status = "disabled"; }; + lcdc0: lcd-controller@fe940000 { + compatible = "renesas,r8a7740-lcdc"; + reg = <0xfe940000 0x4000>; + interrupts = ; + clocks = <&mstp1_clks R8A7740_CLK_LCDC0>, + <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk0_clk>, + <&vou_clk>; + clock-names = "fck", "media", "lclk", "video"; + power-domains = <&pd_a4lc>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lcdc0_rgb: endpoint { + }; + }; + }; + }; + + lcdc1: lcd-controller@fe944000 { + compatible = "renesas,r8a7740-lcdc"; + reg = <0xfe944000 0x4000>; + interrupts = ; + clocks = <&mstp1_clks R8A7740_CLK_LCDC1>, + <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk1_clk>, + <&vou_clk>; + clock-names = "fck", "media", "lclk", "video"; + power-domains = <&pd_a4lc>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lcdc1_rgb: endpoint { + }; + }; + + port@1 { + reg = <1>; + + lcdc1_hdmi: endpoint { + }; + }; + }; + }; + tmu0: timer@fff80000 { compatible = "renesas,tmu-r8a7740", "renesas,tmu"; reg = <0xfff80000 0x2c>; @@ -474,6 +529,16 @@ fsibck_clk: fsibck { #clock-cells = <0>; clock-frequency = <0>; }; + lcdlclk0_clk: lcdlclk0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + lcdlclk1_clk: lcdlclk1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { From 5f9e29b9159a41fcf6733c3b59fa46a90ce3ae20 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 20 Nov 2023 09:00:11 +0200 Subject: [PATCH 1525/7721] clk: renesas: rzg2l-cpg: Reuse code in rzg2l_cpg_reset() Code in rzg2l_cpg_reset() is equivalent with the combined code of rzg2l_cpg_assert() and rzg2l_cpg_deassert(). There is no need to have different versions thus re-use rzg2l_cpg_assert() and rzg2l_cpg_deassert(). Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231120070024.4079344-2-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 38 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 764bd72cf059..3189c3167ba8 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1410,29 +1410,6 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, #define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev) -static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); - const struct rzg2l_cpg_info *info = priv->info; - unsigned int reg = info->resets[id].off; - u32 dis = BIT(info->resets[id].bit); - u32 we = dis << 16; - - dev_dbg(rcdev->dev, "reset id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); - - /* Reset module */ - writel(we, priv->base + CLK_RST_R(reg)); - - /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ - udelay(35); - - /* Release module from reset state */ - writel(we | dis, priv->base + CLK_RST_R(reg)); - - return 0; -} - static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, unsigned long id) { @@ -1463,6 +1440,21 @@ static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, return 0; } +static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = rzg2l_cpg_assert(rcdev, id); + if (ret) + return ret; + + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + + return rzg2l_cpg_deassert(rcdev, id); +} + static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, unsigned long id) { From c9a0ed13382660c9f080ca657616b0a83ad25a66 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 22 Nov 2023 17:12:43 +0100 Subject: [PATCH 1526/7721] ARM: dts: renesas: armadillo800eva: Add LCD panel Describe the 5" WVGA TFT LCD panel on the Armadillo-800-EVA development board, and enable the LCD controller that drives it. Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/278339322dcaaedc0d68fc67f1f1272d880084d7.1700669207.git.geert+renesas@glider.be --- .../dts/renesas/r8a7740-armadillo800eva.dts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts index d21e00e1f401..e1ac2c161e73 100644 --- a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts @@ -132,7 +132,7 @@ i2c2: i2c-2 { i2c-gpio,delay-us = <5>; }; - backlight { + backlight: backlight { compatible = "pwm-backlight"; pwms = <&tpu 2 33333 PWM_POLARITY_INVERTED>; brightness-levels = <0 1 2 4 8 16 32 64 128 255>; @@ -143,6 +143,18 @@ backlight { enable-gpios = <&pfc 61 GPIO_ACTIVE_HIGH>; }; + panel { + compatible = "ampire,am-800480l1tmqw-t00h"; + backlight = <&backlight>; + power-supply = <®_5p0v>; + + port { + panel_in: endpoint { + remote-endpoint = <&lcdc0_rgb>; + }; + }; + }; + sound { compatible = "simple-audio-card"; @@ -228,10 +240,22 @@ rtc@30 { }; }; -&pfc { +&lcdc0 { pinctrl-0 = <&lcd0_pins>; pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&pfc { ether_pins: ether { groups = "gether_mii", "gether_int"; function = "gether"; From e1df5202e879bce09845ac62bae30206e1edfb80 Mon Sep 17 00:00:00 2001 From: Shradha Gupta Date: Fri, 24 Nov 2023 05:02:30 -0800 Subject: [PATCH 1527/7721] net :mana :Add remaining GDMA stats for MANA to ethtool Extend performance counter stats in 'ethtool -S ' for MANA VF to include all GDMA stat counter. Tested-on: Ubuntu22 Testcases: 1. LISA testcase: PERF-NETWORK-TCP-THROUGHPUT-MULTICONNECTION-NTTTCP-Synthetic 2. LISA testcase: PERF-NETWORK-TCP-THROUGHPUT-MULTICONNECTION-NTTTCP-SRIOV Signed-off-by: Shradha Gupta Link: https://lore.kernel.org/r/1700830950-803-1-git-send-email-shradhagupta@linux.microsoft.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microsoft/mana/mana_en.c | 49 ++++++++++++++++++- .../ethernet/microsoft/mana/mana_ethtool.c | 40 +++++++++++++++ include/net/mana/mana.h | 46 ++++++++++++----- 3 files changed, 120 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index fc3d2903a80f..6b857188b9da 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -2385,13 +2385,33 @@ void mana_query_gf_stats(struct mana_port_context *apc) mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT, sizeof(req), sizeof(resp)); - req.req_stats = STATISTICS_FLAGS_HC_TX_BYTES | + req.req_stats = STATISTICS_FLAGS_RX_DISCARDS_NO_WQE | + STATISTICS_FLAGS_RX_ERRORS_VPORT_DISABLED | + STATISTICS_FLAGS_HC_RX_BYTES | + STATISTICS_FLAGS_HC_RX_UCAST_PACKETS | + STATISTICS_FLAGS_HC_RX_UCAST_BYTES | + STATISTICS_FLAGS_HC_RX_MCAST_PACKETS | + STATISTICS_FLAGS_HC_RX_MCAST_BYTES | + STATISTICS_FLAGS_HC_RX_BCAST_PACKETS | + STATISTICS_FLAGS_HC_RX_BCAST_BYTES | + STATISTICS_FLAGS_TX_ERRORS_GF_DISABLED | + STATISTICS_FLAGS_TX_ERRORS_VPORT_DISABLED | + STATISTICS_FLAGS_TX_ERRORS_INVAL_VPORT_OFFSET_PACKETS | + STATISTICS_FLAGS_TX_ERRORS_VLAN_ENFORCEMENT | + STATISTICS_FLAGS_TX_ERRORS_ETH_TYPE_ENFORCEMENT | + STATISTICS_FLAGS_TX_ERRORS_SA_ENFORCEMENT | + STATISTICS_FLAGS_TX_ERRORS_SQPDID_ENFORCEMENT | + STATISTICS_FLAGS_TX_ERRORS_CQPDID_ENFORCEMENT | + STATISTICS_FLAGS_TX_ERRORS_MTU_VIOLATION | + STATISTICS_FLAGS_TX_ERRORS_INVALID_OOB | + STATISTICS_FLAGS_HC_TX_BYTES | STATISTICS_FLAGS_HC_TX_UCAST_PACKETS | STATISTICS_FLAGS_HC_TX_UCAST_BYTES | STATISTICS_FLAGS_HC_TX_MCAST_PACKETS | STATISTICS_FLAGS_HC_TX_MCAST_BYTES | STATISTICS_FLAGS_HC_TX_BCAST_PACKETS | - STATISTICS_FLAGS_HC_TX_BCAST_BYTES; + STATISTICS_FLAGS_HC_TX_BCAST_BYTES | + STATISTICS_FLAGS_TX_ERRORS_GDMA_ERROR; err = mana_send_request(apc->ac, &req, sizeof(req), &resp, sizeof(resp)); @@ -2407,6 +2427,30 @@ void mana_query_gf_stats(struct mana_port_context *apc) return; } + apc->eth_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe; + apc->eth_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled; + apc->eth_stats.hc_rx_bytes = resp.hc_rx_bytes; + apc->eth_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts; + apc->eth_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes; + apc->eth_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts; + apc->eth_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes; + apc->eth_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts; + apc->eth_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes; + apc->eth_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled; + apc->eth_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled; + apc->eth_stats.hc_tx_err_inval_vportoffset_pkt = + resp.tx_err_inval_vport_offset_pkt; + apc->eth_stats.hc_tx_err_vlan_enforcement = + resp.tx_err_vlan_enforcement; + apc->eth_stats.hc_tx_err_eth_type_enforcement = + resp.tx_err_ethtype_enforcement; + apc->eth_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement; + apc->eth_stats.hc_tx_err_sqpdid_enforecement = + resp.tx_err_SQPDID_enforcement; + apc->eth_stats.hc_tx_err_cqpdid_enforcement = + resp.tx_err_CQPDID_enforcement; + apc->eth_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation; + apc->eth_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob; apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes; apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts; apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes; @@ -2414,6 +2458,7 @@ void mana_query_gf_stats(struct mana_port_context *apc) apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes; apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; + apc->eth_stats.hc_tx_err_gdma = resp.tx_err_gdma; } static int mana_init_port(struct net_device *ndev) diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index 607150165ab4..7077d647d99a 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -13,6 +13,46 @@ static const struct { } mana_eth_stats[] = { {"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)}, {"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)}, + {"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_stats, + hc_rx_discards_no_wqe)}, + {"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_stats, + hc_rx_err_vport_disabled)}, + {"hc_rx_bytes", offsetof(struct mana_ethtool_stats, hc_rx_bytes)}, + {"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_stats, + hc_rx_ucast_pkts)}, + {"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_stats, + hc_rx_ucast_bytes)}, + {"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_stats, + hc_rx_bcast_pkts)}, + {"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_stats, + hc_rx_bcast_bytes)}, + {"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_stats, + hc_rx_mcast_pkts)}, + {"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_stats, + hc_rx_mcast_bytes)}, + {"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_stats, + hc_tx_err_gf_disabled)}, + {"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_stats, + hc_tx_err_vport_disabled)}, + {"hc_tx_err_inval_vportoffset_pkt", + offsetof(struct mana_ethtool_stats, + hc_tx_err_inval_vportoffset_pkt)}, + {"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_stats, + hc_tx_err_vlan_enforcement)}, + {"hc_tx_err_eth_type_enforcement", + offsetof(struct mana_ethtool_stats, hc_tx_err_eth_type_enforcement)}, + {"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_stats, + hc_tx_err_sa_enforcement)}, + {"hc_tx_err_sqpdid_enforecement", + offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforecement)}, + {"hc_tx_err_cqpdid_enforcement", + offsetof(struct mana_ethtool_stats, hc_tx_err_cqpdid_enforcement)}, + {"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_stats, + hc_tx_err_mtu_violation)}, + {"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_stats, + hc_tx_err_inval_oob)}, + {"hc_tx_err_gdma", offsetof(struct mana_ethtool_stats, + hc_tx_err_gdma)}, {"hc_tx_bytes", offsetof(struct mana_ethtool_stats, hc_tx_bytes)}, {"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_stats, hc_tx_ucast_pkts)}, diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index 6e3e9c1363db..5567f5bc8eb6 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -353,6 +353,25 @@ struct mana_tx_qp { struct mana_ethtool_stats { u64 stop_queue; u64 wake_queue; + u64 hc_rx_discards_no_wqe; + u64 hc_rx_err_vport_disabled; + u64 hc_rx_bytes; + u64 hc_rx_ucast_pkts; + u64 hc_rx_ucast_bytes; + u64 hc_rx_bcast_pkts; + u64 hc_rx_bcast_bytes; + u64 hc_rx_mcast_pkts; + u64 hc_rx_mcast_bytes; + u64 hc_tx_err_gf_disabled; + u64 hc_tx_err_vport_disabled; + u64 hc_tx_err_inval_vportoffset_pkt; + u64 hc_tx_err_vlan_enforcement; + u64 hc_tx_err_eth_type_enforcement; + u64 hc_tx_err_sa_enforcement; + u64 hc_tx_err_sqpdid_enforecement; + u64 hc_tx_err_cqpdid_enforcement; + u64 hc_tx_err_mtu_violation; + u64 hc_tx_err_inval_oob; u64 hc_tx_bytes; u64 hc_tx_ucast_pkts; u64 hc_tx_ucast_bytes; @@ -360,6 +379,7 @@ struct mana_ethtool_stats { u64 hc_tx_bcast_bytes; u64 hc_tx_mcast_pkts; u64 hc_tx_mcast_bytes; + u64 hc_tx_err_gdma; u64 tx_cqe_err; u64 tx_cqe_unknown_type; u64 rx_coalesced_err; @@ -602,8 +622,8 @@ struct mana_query_gf_stat_resp { struct gdma_resp_hdr hdr; u64 reported_stats; /* rx errors/discards */ - u64 discard_rx_nowqe; - u64 err_rx_vport_disabled; + u64 rx_discards_nowqe; + u64 rx_err_vport_disabled; /* rx bytes/packets */ u64 hc_rx_bytes; u64 hc_rx_ucast_pkts; @@ -613,16 +633,16 @@ struct mana_query_gf_stat_resp { u64 hc_rx_mcast_pkts; u64 hc_rx_mcast_bytes; /* tx errors */ - u64 err_tx_gf_disabled; - u64 err_tx_vport_disabled; - u64 err_tx_inval_vport_offset_pkt; - u64 err_tx_vlan_enforcement; - u64 err_tx_ethtype_enforcement; - u64 err_tx_SA_enforecement; - u64 err_tx_SQPDID_enforcement; - u64 err_tx_CQPDID_enforcement; - u64 err_tx_mtu_violation; - u64 err_tx_inval_oob; + u64 tx_err_gf_disabled; + u64 tx_err_vport_disabled; + u64 tx_err_inval_vport_offset_pkt; + u64 tx_err_vlan_enforcement; + u64 tx_err_ethtype_enforcement; + u64 tx_err_SA_enforcement; + u64 tx_err_SQPDID_enforcement; + u64 tx_err_CQPDID_enforcement; + u64 tx_err_mtu_violation; + u64 tx_err_inval_oob; /* tx bytes/packets */ u64 hc_tx_bytes; u64 hc_tx_ucast_pkts; @@ -632,7 +652,7 @@ struct mana_query_gf_stat_resp { u64 hc_tx_mcast_pkts; u64 hc_tx_mcast_bytes; /* tx error */ - u64 err_tx_gdma; + u64 tx_err_gdma; }; /* HW DATA */ /* Configure vPort Rx Steering */ From 45cc50d13433a62f23b7b4af380497aae5e8ddc7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Nov 2023 01:28:27 +0000 Subject: [PATCH 1528/7721] ASoC: makes CPU/Codec channel connection map more generic Current ASoC CPU:Codec = N:M connection is using connection mapping idea, but it is used for N < M case only. We want to use it for any case. By this patch, not only N:M connection, but all existing connection (1:1, 1:N, N:N) will use same connection mapping. Then, because it will use default mapping, no conversion patch is needed to exising drivers. More over, CPU:Codec = N:M (N > M) also supported in the same time. ch_maps array will has CPU/Codec index by this patch. Image CPU0 <---> Codec0 CPU1 <-+-> Codec1 CPU2 <-/ ch_map ch_map[0].cpu = 0 ch_map[0].codec = 0 ch_map[1].cpu = 1 ch_map[1].codec = 1 ch_map[2].cpu = 2 ch_map[2].codec = 1 Link: https://lore.kernel.org/r/87fs6wuszr.wl-kuninori.morimoto.gx@renesas.com Link: https://lore.kernel.org/r/878r7yqeo4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto Reviewed-by: Bard Liao Tested-by: Pierre-Louis Bossart Tested-by: Jerome Brunet Link: https://lore.kernel.org/r/87ttpq4f2c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 56 ++++++++++++++++++- sound/soc/intel/boards/sof_sdw.c | 28 ++++------ sound/soc/soc-core.c | 95 +++++++++++++++++++++++++++++++- sound/soc/soc-dapm.c | 45 ++++----------- sound/soc/soc-pcm.c | 44 +++++---------- 5 files changed, 185 insertions(+), 83 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 7792c393e238..f3803c2dc349 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -655,8 +655,45 @@ struct snd_soc_dai_link_component { struct of_phandle_args *dai_args; }; -struct snd_soc_dai_link_codec_ch_map { - unsigned int connected_cpu_id; +/* + * [dai_link->ch_maps Image sample] + * + *------------------------- + * CPU0 <---> Codec0 + * + * ch-map[0].cpu = 0 ch-map[0].codec = 0 + * + *------------------------- + * CPU0 <---> Codec0 + * CPU1 <---> Codec1 + * CPU2 <---> Codec2 + * + * ch-map[0].cpu = 0 ch-map[0].codec = 0 + * ch-map[1].cpu = 1 ch-map[1].codec = 1 + * ch-map[2].cpu = 2 ch-map[2].codec = 2 + * + *------------------------- + * CPU0 <---> Codec0 + * CPU1 <-+-> Codec1 + * CPU2 <-/ + * + * ch-map[0].cpu = 0 ch-map[0].codec = 0 + * ch-map[1].cpu = 1 ch-map[1].codec = 1 + * ch-map[2].cpu = 2 ch-map[2].codec = 1 + * + *------------------------- + * CPU0 <---> Codec0 + * CPU1 <-+-> Codec1 + * \-> Codec2 + * + * ch-map[0].cpu = 0 ch-map[0].codec = 0 + * ch-map[1].cpu = 1 ch-map[1].codec = 1 + * ch-map[2].cpu = 1 ch-map[2].codec = 2 + * + */ +struct snd_soc_dai_link_ch_map { + unsigned int cpu; + unsigned int codec; unsigned int ch_mask; }; @@ -688,7 +725,9 @@ struct snd_soc_dai_link { struct snd_soc_dai_link_component *codecs; unsigned int num_codecs; - struct snd_soc_dai_link_codec_ch_map *codec_ch_maps; + /* num_ch_maps = max(num_cpu, num_codecs) */ + struct snd_soc_dai_link_ch_map *ch_maps; + /* * You MAY specify the link's platform/PCM/DMA driver, either by * device name, or by DT/OF node, but not both. Some forms of link @@ -775,6 +814,10 @@ struct snd_soc_dai_link { #endif }; +static inline int snd_soc_link_num_ch_map(struct snd_soc_dai_link *link) { + return max(link->num_cpus, link->num_codecs); +} + static inline struct snd_soc_dai_link_component* snd_soc_link_to_cpu(struct snd_soc_dai_link *link, int n) { return &(link)->cpus[n]; @@ -808,6 +851,12 @@ snd_soc_link_to_platform(struct snd_soc_dai_link *link, int n) { ((cpu) = snd_soc_link_to_cpu(link, i)); \ (i)++) +#define for_each_link_ch_maps(link, i, ch_map) \ + for ((i) = 0; \ + ((i) < snd_soc_link_num_ch_map(link) && \ + ((ch_map) = link->ch_maps + i)); \ + (i)++) + /* * Sample 1 : Single CPU/Codec/Platform * @@ -1163,6 +1212,7 @@ struct snd_soc_pcm_runtime { ((i) < (rtd)->dai_link->num_cpus + (rtd)->dai_link->num_codecs) && \ ((dai) = (rtd)->dais[i]); \ (i)++) +#define for_each_rtd_ch_maps(rtd, i, ch_maps) for_each_link_ch_maps(rtd->dai_link, i, ch_maps) void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 3312ad8a563b..2faf7372bad0 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -570,16 +570,14 @@ int sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link_ch_map *ch_maps; int ch = params_channels(params); - struct snd_soc_dai *codec_dai; - struct snd_soc_dai *cpu_dai; unsigned int ch_mask; int num_codecs; int step; int i; - int j; - if (!rtd->dai_link->codec_ch_maps) + if (!rtd->dai_link->ch_maps) return 0; /* Identical data will be sent to all codecs in playback */ @@ -605,13 +603,9 @@ int sdw_hw_params(struct snd_pcm_substream *substream, * link has more than one codec DAIs. Set codec channel mask and * ASoC will set the corresponding channel numbers for each cpu dai. */ - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i) - continue; - rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step); - } - } + for_each_link_ch_maps(rtd->dai_link, i, ch_maps) + ch_maps->ch_mask = ch_mask << (i * step); + return 0; } @@ -1350,15 +1344,17 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, return 0; } -static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps, +static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps, int codec_num, int cpu_num) { int step; int i; step = codec_num / cpu_num; - for (i = 0; i < codec_num; i++) - sdw_codec_ch_maps[i].connected_cpu_id = i / step; + for (i = 0; i < codec_num; i++) { + sdw_codec_ch_maps[i].cpu = i / step; + sdw_codec_ch_maps[i].codec = i; + } } static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; @@ -1453,7 +1449,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, *ignore_pch_dmic = true; for_each_pcm_streams(stream) { - struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps; + struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; char *name, *cpu_name; int playback, capture; static const char * const sdw_stream_name[] = { @@ -1530,7 +1526,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, dai_links[*link_index].nonatomic = true; set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); - dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; + dai_links[*link_index].ch_maps = sdw_codec_ch_maps; ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b2bd45e87bc3..4ca3319a8e19 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1015,6 +1015,94 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, return -EINVAL; } +#define MAX_DEFAULT_CH_MAP_SIZE 7 +static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 1, .codec = 1 }, + { .cpu = 2, .codec = 2 }, + { .cpu = 3, .codec = 3 }, + { .cpu = 4, .codec = 4 }, + { .cpu = 5, .codec = 5 }, + { .cpu = 6, .codec = 6 }, +}; +static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 0, .codec = 1 }, + { .cpu = 0, .codec = 2 }, + { .cpu = 0, .codec = 3 }, + { .cpu = 0, .codec = 4 }, + { .cpu = 0, .codec = 5 }, + { .cpu = 0, .codec = 6 }, +}; +static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 1, .codec = 0 }, + { .cpu = 2, .codec = 0 }, + { .cpu = 3, .codec = 0 }, + { .cpu = 4, .codec = 0 }, + { .cpu = 5, .codec = 0 }, + { .cpu = 6, .codec = 0 }, +}; +static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link_ch_map *ch_maps; + int i; + + /* + * dai_link->ch_maps indicates how CPU/Codec are connected. + * It will be a map seen from a larger number of DAI. + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + + /* it should have ch_maps if connection was N:M */ + if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && + dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) { + dev_err(card->dev, "need to have ch_maps when N:M connction (%s)", + dai_link->name); + return -EINVAL; + } + + /* do nothing if it has own maps */ + if (dai_link->ch_maps) + goto sanity_check; + + /* check default map size */ + if (dai_link->num_cpus > MAX_DEFAULT_CH_MAP_SIZE || + dai_link->num_codecs > MAX_DEFAULT_CH_MAP_SIZE) { + dev_err(card->dev, "soc-core.c needs update default_connection_maps"); + return -EINVAL; + } + + /* Compensate missing map for ... */ + if (dai_link->num_cpus == dai_link->num_codecs) + dai_link->ch_maps = default_ch_map_sync; /* for 1:1 or N:N */ + else if (dai_link->num_cpus < dai_link->num_codecs) + dai_link->ch_maps = default_ch_map_1cpu; /* for 1:N */ + else + dai_link->ch_maps = default_ch_map_1codec; /* for N:1 */ + +sanity_check: + dev_dbg(card->dev, "dai_link %s\n", dai_link->stream_name); + for_each_link_ch_maps(dai_link, i, ch_maps) { + if ((ch_maps->cpu >= dai_link->num_cpus) || + (ch_maps->codec >= dai_link->num_codecs)) { + dev_err(card->dev, + "unexpected dai_link->ch_maps[%d] index (cpu(%d/%d) codec(%d/%d))", + i, + ch_maps->cpu, dai_link->num_cpus, + ch_maps->codec, dai_link->num_codecs); + return -EINVAL; + } + + dev_dbg(card->dev, " [%d] cpu%d <-> codec%d\n", + i, ch_maps->cpu, ch_maps->codec); + } + + return 0; +} + /** * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card * @card: The ASoC card to which the pcm_runtime has @@ -1121,8 +1209,13 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card, int num_dai_link) { for (int i = 0; i < num_dai_link; i++) { - int ret = snd_soc_add_pcm_runtime(card, dai_link + i); + int ret; + ret = snd_soc_compensate_channel_connection_map(card, dai_link + i); + if (ret < 0) + return ret; + + ret = snd_soc_add_pcm_runtime(card, dai_link + i); if (ret < 0) return ret; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 407a26af3eaf..bffeea80277f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4436,11 +4436,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; - int i; /* for each BE DAI link... */ for_each_card_rtds(card, rtd) { + struct snd_soc_dai_link_ch_map *ch_maps; + int i; + /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. @@ -4448,39 +4451,15 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) if (rtd->dai_link->dynamic) continue; - if (rtd->dai_link->num_cpus == 1) { - for_each_rtd_codec_dais(rtd, i, codec_dai) - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, 0)); - } else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) { - for_each_rtd_codec_dais(rtd, i, codec_dai) - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, i)); - } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { - int cpu_id; + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); - if (!rtd->dai_link->codec_ch_maps) { - dev_err(card->dev, "%s: no codec channel mapping table provided\n", - __func__); - continue; - } - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; - if (cpu_id >= rtd->dai_link->num_cpus) { - dev_err(card->dev, - "%s: dai_link %s cpu_id %d too large, num_cpus is %d\n", - __func__, rtd->dai_link->name, cpu_id, - rtd->dai_link->num_cpus); - continue; - } - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, cpu_id)); - } - } else { - dev_err(card->dev, - "%s: codec number %d < cpu number %d is not supported\n", - __func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus); + dapm_connect_dai_pair(card, rtd, codec_dai, cpu_dai); } } } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 323e4d7b6adf..c20573aeb756 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1050,6 +1050,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, } for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + struct snd_soc_dai_link_ch_map *ch_maps; unsigned int ch_mask = 0; int j; @@ -1063,22 +1064,20 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, /* copy params for each cpu */ tmp_params = *params; - if (!rtd->dai_link->codec_ch_maps) - goto hw_params; /* * construct cpu channel mask by combining ch_mask of each * codec which maps to the cpu. + * see + * soc.h :: [dai_link->ch_maps Image sample] */ - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i) - ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask; - } + for_each_rtd_ch_maps(rtd, j, ch_maps) + if (ch_maps->cpu == i) + ch_mask |= ch_maps->ch_mask; /* fixup cpu channel number */ if (ch_mask) soc_pcm_codec_params_fixup(&tmp_params, ch_mask); -hw_params: ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params); if (ret < 0) goto out; @@ -2826,35 +2825,20 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, } } } else { + struct snd_soc_dai_link_ch_map *ch_maps; struct snd_soc_dai *codec_dai; /* Adapt stream for codec2codec links */ int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (dai_link->num_cpus == 1) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - } else if (dai_link->num_cpus == dai_link->num_codecs) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, i); - } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { - int cpu_id; - - if (!rtd->dai_link->codec_ch_maps) { - dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n", - __func__); - return -EINVAL; - } - - cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; - cpu_dai = snd_soc_rtd_to_cpu(rtd, cpu_id); - } else { - dev_err(rtd->card->dev, - "%s codec number %d < cpu number %d is not supported\n", - __func__, rtd->dai_link->num_codecs, - rtd->dai_link->num_cpus); - return -EINVAL; - } + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) From 912eb415631140c93ff5f05378411fec8e6a537f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Nov 2023 01:28:58 +0000 Subject: [PATCH 1529/7721] ASoC: audio-graph-card2: use better image for Multi connection 1st port on Multi ports is for paired CPU/Codec, and the 2nd or later port are for Multi Elements. This patch indicates its image to easy to understand. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sf5a4f1i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 52 +++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 7146611df730..c564f630abf6 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -83,32 +83,32 @@ Multi-CPU/Codec ************************************ -It has connection part (= X) and list part (= y). -links indicates connection part of CPU side (= A). +It has link connection part (= X,x) and list part (= A,B,a,b). +"links" is connection part of CPU side (= @). - +-+ (A) +-+ - CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 - CPU2 --(y) | | | | (y)-- Codec2 - +-+ +-+ + +----+ +---+ + CPU1 --|A X| <-@----> |x a|-- Codec1 + CPU2 --|B | | b|-- Codec2 + +----+ +---+ - sound { - compatible = "audio-graph-card2"; + sound { + compatible = "audio-graph-card2"; -(A) links = <&mcpu>; +(@) links = <&mcpu>; - multi { - ports@0 { -(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; -(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; -(y) port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; - }; - ports@1 { -(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; -(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; -(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; - }; + multi { + ports@0 { +(@) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; // (X) to pair + port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; // (A) Multi Element + port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; // (B) Multi Element + }; + ports@1 { + port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; // (x) to pair + port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; // (a) Multi Element + port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; // (b) Multi Element }; }; + }; CPU { ports { @@ -328,9 +328,9 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port) /* * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ep { ... = rep0 } }; - * port@2 { ep { ... = rep1 } }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ep { ... = rep0 } }; // Multi Element + * port@2 { ep { ... = rep1 } }; // Multi Element * ... * }; * }; @@ -920,9 +920,9 @@ static int graph_counter(struct device_node *lnk) * * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ... }; - * port@2 { ... }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ... }; // Multi Element + * port@2 { ... }; // Multi Element * ... * }; * }; From e2de6808df4ad5faa6106f7a80617921fdf5dff5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Nov 2023 01:29:23 +0000 Subject: [PATCH 1530/7721] ASoC: audio-graph-card2: add CPU:Codec = N:M support Now ASoC is supporting CPU:Codec = N:M support. This patch enables it on Audio Graph Card2. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0ku4f0t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 237 ++++++++++++++++++++++---- 1 file changed, 208 insertions(+), 29 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index c564f630abf6..d9e10308a508 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -504,38 +504,201 @@ static int __graph_parse_node(struct simple_util_priv *priv, return 0; } +static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, + int *nm_idx, int cpu_idx, + struct device_node *mcpu_port) +{ + /* + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu0 <--|A 1|<--------->|4 a|-> codec0 + * cpu1 <--|B 2|<-----+--->|5 b|-> codec1 + * cpu2 <--|C 3|<----/ +---+ + * +---+ + * + * multi { + * ports { + * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair + * port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element + * mcpu0_ep_0 { ... = mcodec0_ep_0; }; }; // (1) connected Codec + * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element + * mcpu1_ep_0 { ... = mcodec1_ep_0; }; }; // (2) connected Codec + * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element + * mcpu2_ep_0 { ... = mcodec1_ep_1; }; }; // (3) connected Codec + * }; + * + * ports { + * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair + * port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element + * mcodec0_ep_0 { ... = mcpu0_ep_0; }; }; // (4) connected CPU + * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element + * mcodec1_ep_0 { ... = mcpu1_ep_0; }; // (5) connected CPU + * mcodec1_ep_1 { ... = mcpu2_ep_0; }; }; // (5) connected CPU + * }; + * }; + */ + struct device_node *mcpu_ep = port_to_endpoint(mcpu_port); + struct device_node *mcpu_ep_n = mcpu_ep; + struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL); + struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top); + struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top); + struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top); + struct device_node *mcodec_ports = of_get_parent(mcodec_port_top); + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + int ret = -EINVAL; + + if (cpu_idx > dai_link->num_cpus) + goto mcpu_err; + + while (1) { + struct device_node *mcodec_ep_n; + struct device_node *mcodec_port_i; + struct device_node *mcodec_port; + int codec_idx; + + if (*nm_idx > nm_max) + break; + + mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n); + if (!mcpu_ep_n) { + ret = 0; + break; + } + + mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n); + mcodec_port = of_get_parent(mcodec_ep_n); + + if (mcodec_ports != of_get_parent(mcodec_port)) + goto mcpu_err; + + codec_idx = 0; + mcodec_port_i = of_get_next_child(mcodec_ports, NULL); + while (1) { + if (codec_idx > dai_link->num_codecs) + goto mcodec_err; + + mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i); + + if (!mcodec_port_i) + goto mcodec_err; + + if (mcodec_port_i == mcodec_port) + break; + + codec_idx++; + } + + dai_link->ch_maps[*nm_idx].cpu = cpu_idx; + dai_link->ch_maps[*nm_idx].codec = codec_idx; + + (*nm_idx)++; + + of_node_put(mcodec_port_i); +mcodec_err: + of_node_put(mcodec_port); + of_node_put(mcpu_ep_n); + of_node_put(mcodec_ep_n); + } +mcpu_err: + of_node_put(mcpu_ep); + of_node_put(mcpu_port_top); + of_node_put(mcpu_ep_top); + of_node_put(mcodec_ep_top); + of_node_put(mcodec_port_top); + of_node_put(mcodec_ports); + + return ret; +} + +static int graph_parse_node_multi(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct device *dev = simple_priv_to_dev(priv); + struct device_node *ep; + int ret = -ENOMEM; + int nm_idx = 0; + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + + /* + * create ch_maps if CPU:Codec = N:M + * DPCM is out of scope + */ + if (gtype != GRAPH_DPCM && !dai_link->ch_maps && + dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && + dai_link->num_cpus != dai_link->num_codecs) { + + dai_link->ch_maps = devm_kcalloc(dev, nm_max, + sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL); + if (!dai_link->ch_maps) + goto multi_err; + } + + for (int idx = 0;; idx++) { + /* + * multi { + * ports { + * port@0 { ... }; // to pair + * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element + * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element + * }; + * }; + * + * cpu { + * ports { + * port@0 { cpu1_ep { ... = mcpu1_ep };}; + * }; + * }; + */ + ep = graph_get_next_multi_ep(&port); + if (!ep) + break; + + ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx); + of_node_put(ep); + if (ret < 0) + goto multi_err; + + /* CPU:Codec = N:M */ + if (is_cpu && dai_link->ch_maps) { + ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port); + if (ret < 0) + goto multi_err; + } + } + + if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max)) + ret = -EINVAL; + +multi_err: + return ret; +} + +static int graph_parse_node_single(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct device_node *ep = port_to_endpoint(port); + int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + + of_node_put(ep); + + return ret; +} + static int graph_parse_node(struct simple_util_priv *priv, enum graph_type gtype, struct device_node *port, struct link_info *li, int is_cpu) { - struct device_node *ep; - int ret = 0; - - if (graph_lnk_is_multi(port)) { - int idx; - - of_node_get(port); - - for (idx = 0;; idx++) { - ep = graph_get_next_multi_ep(&port); - if (!ep) - break; - - ret = __graph_parse_node(priv, gtype, ep, - li, is_cpu, idx); - of_node_put(ep); - if (ret < 0) - break; - } - } else { - /* Single CPU / Codec */ - ep = port_to_endpoint(port); - ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); - of_node_put(ep); - } - - return ret; + if (graph_lnk_is_multi(port)) + return graph_parse_node_multi(priv, gtype, port, li, is_cpu); + else + return graph_parse_node_single(priv, gtype, port, li, is_cpu); } static void graph_parse_daifmt(struct device_node *node, @@ -929,8 +1092,24 @@ static int graph_counter(struct device_node *lnk) * * ignore first lnk part */ - if (graph_lnk_is_multi(lnk)) - return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; + if (graph_lnk_is_multi(lnk)) { + struct device_node *ports = of_get_parent(lnk); + struct device_node *port = NULL; + int cnt = 0; + + /* + * CPU/Codec = N:M case has many endpoints. + * We can't use of_graph_get_endpoint_count() here + */ + while(1) { + port = of_get_next_child(ports, port); + if (!port) + break; + cnt++; + } + + return cnt - 1; + } /* * Single CPU / Codec */ From a706366f93c37c6649acfe15a1ef9a80e25bace4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Nov 2023 01:30:09 +0000 Subject: [PATCH 1531/7721] ASoC: audio-graph-card2-custom-sample: Add connection image Audio Graph Card2 is supporting many type of Sound connections, but thus it is very difficult to understand how these are connected. To support well understanding, adds each connection images and indicates each settings are for where. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm0e4ezi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../audio-graph-card2-custom-sample.dtsi | 181 ++++++++++++++---- 1 file changed, 142 insertions(+), 39 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 8acaa2ddb335..7e2cd9cc3fa8 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -58,7 +58,7 @@ / { * | |-> codec13 * +-+ * - * [Multi-CPU/Codec] + * [Multi-CPU/Codec-0] * +-+ +-+ * cpu1 <--| |<-@--------->| |-> codec1 * cpu2 <--| | | |-> codec2 @@ -144,11 +144,14 @@ audio-graph-card2-custom-sample { */ &cpu0 - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * cpu7/codec12/codec13 + */ &sm0 /* - * [Multi-CPU/Codec]: cpu side only + * [Multi-CPU/Codec-0]: cpu side only * cpu1/cpu2/codec1/codec2 */ &mcpu0 @@ -182,64 +185,115 @@ multi { #address-cells = <1>; #size-cells = <0>; + /* + * [Multi-CPU-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; - /* [Multi-CPU] */ - mcpu0: port@0 { reg = <0>; mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; - port@1 { reg = <1>; mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; - port@2 { reg = <2>; mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; + mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */ }; - /* [Multi-Codec] */ + /* + * [Multi-Codec-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; - port@1 { reg = <1>; mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; - port@2 { reg = <2>; mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; + port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */ }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +---+ + * cpu5 <-@--* *-----@--->|x a|-> codec4 + * cpu6 <-@--* * | b|-> codec5 + * **** +---+ + */ ports@2 { reg = <2>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; }; - port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; }; - port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; }; + port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */ }; - /* [Codec2Codec-Multi]::CPU */ + /* + * [Codec2Codec-Multi]::CPU + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@3 { reg = <3>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; }; - port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; }; - port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; }; + port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */ }; - /* [Codec2Codec-Multi]::Codec */ + /* + * [Codec2Codec-Multi]::Codec + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@4 { reg = <4>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; }; - port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; }; - port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; }; }; + port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */ }; - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * + * +---+ + * cpu7 <-@------->|X A|-> codec12 + * | B|-> codec13 + * +---+ + */ ports@5 { reg = <5>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; }; }; - port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; }; - port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; }; + port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */ }; }; @@ -252,11 +306,27 @@ ports@0 { #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::FE */ + /* + * [DPCM]::FE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; }; fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; }; - /* [DPCM-Multi]::FE */ + /* + * [DPCM-Multi]::FE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; }; fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; }; }; @@ -266,10 +336,26 @@ ports@1 { #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::BE */ + /* + * [DPCM]::BE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; }; }; }; @@ -277,7 +363,13 @@ ports@1 { codec2codec { #address-cells = <1>; #size-cells = <0>; - /* [Codec2Codec] */ + /* + * [Codec2Codec] + * + * +-@(c2c)-> codec6 + * | + * +--------> codec7 + */ ports@0 { reg = <0>; @@ -289,7 +381,18 @@ ports@0 { port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; }; }; - /* [Codec2Codec-Multi] */ + /* + * [Codec2Codec-Multi] + * + * +-+ + * +-@(c2c_m)-->| |-> codec8 + * | | |-> codec9 + * | +-+ + * | +-+ + * +----------->| |-> codec10 + * | |-> codec11 + * +-+ + */ ports@1 { reg = <1>; @@ -323,9 +426,9 @@ ports { /* [Normal] */ cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; - /* [Multi-CPU] */ - port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; - port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; + /* [Multi-CPU-0] */ + port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; }; + port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; }; /* [DPCM]::FE */ port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; }; @@ -363,9 +466,9 @@ ports { /* [Normal] */ port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; }; - /* [Multi-Codec] */ - port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; - port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; + /* [Multi-Codec-0] */ + port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; }; + port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; }; /* [DPCM]::BE */ port@3 { From 792846d9daa876186196b66dc496a2ba8ddd7535 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Nov 2023 01:31:04 +0000 Subject: [PATCH 1532/7721] ASoC: audio-graph-card2-custom-sample: add CPU/Codec = N:M sample Now ASoC is supporting CPU/Codec = N:M connection, add its sample settings. One note here is that it has many type of samples, it reached to maximum of sound minor number. Therefore, new sample is disabled so far. If you want to try it, you need to disable some other one instead. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o7fy4ey0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../audio-graph-card2-custom-sample.dtsi | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 7e2cd9cc3fa8..9efd31206c9b 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -64,6 +64,26 @@ / { * cpu2 <--| | | |-> codec2 * +-+ +-+ * + * [Multi-CPU/Codec-1] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu8 <--| |<----------->| |-> codec14 + * cpu9 <--| |<---+------->| |-> codec15 + * +-+ \------>| |-> codec16 + * +-+ + * + * [Multi-CPU/Codec-2] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu10 <-| |<----------->| |-> codec17 + * cpu11 <-| |<-----+----->| |-> codec18 + * cpu12 <-| |<----/ +-+ + * +-+ + * * [DPCM] * * CPU3/CPU4 are converting rate to 44100 @@ -156,6 +176,26 @@ &sm0 */ &mcpu0 + /* + * [Multi-CPU/Codec-1]: cpu side only + * cpu8/cpu9/codec14/codec15/codec16 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu1 + + /* + * [Multi-CPU/Codec-2]: cpu side only + * cpu10/cpu11/cpu12/codec17/codec18 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu2 + /* * [DPCM]: both FE / BE * cpu3/cpu4/codec3 @@ -295,6 +335,150 @@ ports@5 { port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */ port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */ }; + + /* + * [Multi-CPU-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@6 { + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */ + mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */ + mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */ + mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */ + }; + }; + + /* + * [Multi-Codec-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@7 { + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */ + mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */ + mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */ + mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */ + }; + }; + + /* + * [Multi-CPU-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@8 { + reg = <8>; + #address-cells = <1>; + #size-cells = <0>; + mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */ + mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */ + mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */ + mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */ + }; + }; + + /* + * [Multi-Codec-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@9 { + reg = <9>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */ + mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */ + mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */ + mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */ + }; + }; }; dpcm { @@ -440,6 +624,14 @@ ports { /* [Semi-Multi] */ sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; }; + + /* [Multi-CPU-1] */ + port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; }; + port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; }; + /* [Multi-CPU-2] */ + port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; }; + port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; }; + port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; }; }; }; @@ -498,6 +690,13 @@ port@3 { port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; }; port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; }; + /* [Multi-Codec-1] */ + port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; }; + port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; }; + port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; }; + /* [Multi-Codec-2] */ + port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; }; + port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; }; }; }; }; From 076357cd57c294fb185ac452b9ce5536b2853839 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 19 Nov 2023 19:19:14 +0100 Subject: [PATCH 1533/7721] ASoC: sh: convert not to use dma_request_slave_channel() dma_request_slave_channel() is deprecated. dma_request_chan() should be used directly instead. Switch to the preferred function and update the error handling accordingly. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/1a837f96f056fa3dcb02a77afa5892d40b354cb1.1700417934.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 2ef47aa2c778..84601ba43b7d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1379,7 +1379,9 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev io->chan = dma_request_channel(mask, shdma_chan_filter, (void *)io->dma_id); #else - io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx"); + io->chan = dma_request_chan(dev, is_play ? "tx" : "rx"); + if (IS_ERR(io->chan)) + io->chan = NULL; #endif if (io->chan) { struct dma_slave_config cfg = {}; From d5070d0c10326e09276c34568b9a19fb9a727b6e Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Mon, 27 Nov 2023 12:52:35 +0200 Subject: [PATCH 1534/7721] ASoC: SOF: Intel: mtl: call dsp dump when boot retry fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call snd_sof_dsp_dbg_dump() with the same flags/dump_msg as used in function hda_loader.c/cl_dsp_init(). Reviewed-by: Péter Ujfalusi Signed-off-by: Yong Zhi Signed-off-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127105235.30071-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 254dbbeac1d0..3ef9e5c37028 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -440,7 +440,8 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; - u32 ipc_hdr; + u32 ipc_hdr, flags; + char *dump_msg; int ret; /* step 1: purge FW request */ @@ -493,8 +494,18 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) return 0; err: - snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0); + flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; + + /* after max boot attempts make sure that the dump is printed */ + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + flags &= ~SOF_DBG_DUMP_OPTIONAL; + + dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d", + hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS); + snd_sof_dsp_dbg_dump(sdev, dump_msg, flags); mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + + kfree(dump_msg); return ret; } From 9b3cd8ebb19edd92300932b68fd6941eaf1852d0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 27 Nov 2023 12:43:13 +0200 Subject: [PATCH 1535/7721] ASoC: SOF: Intel: Use existing helpers to change GPROCEN and PIE bits Instead of directly changing the GPROCEN/PIE bits in PPCTL we should use the existing helper hda_dsp_ctrl_ppcap_enable() and hda_dsp_ctrl_ppcap_int_enable() helpers for clarity. Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231127104313.16661-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 5 ++--- sound/soc/sof/intel/hda.c | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 46fb2d1425e9..1805cf754beb 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -510,9 +510,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) return chip_info->init_core_mask; /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); + hda_dsp_ctrl_ppcap_enable(sdev, false); + return ret; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 744c0dd5766d..fe4ae349dad5 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1350,8 +1350,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) if (!sdev->dspless_mode_selected) { /* disable DSP IRQ */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_PIE, 0); + hda_dsp_ctrl_ppcap_int_enable(sdev, false); } /* disable CIE and GIE interrupts */ @@ -1366,8 +1365,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) chip->power_down_dsp(sdev); /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); + hda_dsp_ctrl_ppcap_enable(sdev, false); skip_disable_dsp: free_irq(sdev->ipc_irq, sdev); From b16904fd9f01b580db357ef2b1cc9e86d89576c2 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sun, 26 Nov 2023 21:03:42 -0800 Subject: [PATCH 1536/7721] bpf: Fix a few selftest failures due to llvm18 change With latest upstream llvm18, the following test cases failed: $ ./test_progs -j #13/2 bpf_cookie/multi_kprobe_link_api:FAIL #13/3 bpf_cookie/multi_kprobe_attach_api:FAIL #13 bpf_cookie:FAIL #77 fentry_fexit:FAIL #78/1 fentry_test/fentry:FAIL #78 fentry_test:FAIL #82/1 fexit_test/fexit:FAIL #82 fexit_test:FAIL #112/1 kprobe_multi_test/skel_api:FAIL #112/2 kprobe_multi_test/link_api_addrs:FAIL [...] #112 kprobe_multi_test:FAIL #356/17 test_global_funcs/global_func17:FAIL #356 test_global_funcs:FAIL Further analysis shows llvm upstream patch [1] is responsible for the above failures. For example, for function bpf_fentry_test7() in net/bpf/test_run.c, without [1], the asm code is: 0000000000000400 : 400: f3 0f 1e fa endbr64 404: e8 00 00 00 00 callq 0x409 409: 48 89 f8 movq %rdi, %rax 40c: c3 retq 40d: 0f 1f 00 nopl (%rax) ... and with [1], the asm code is: 0000000000005d20 : 5d20: e8 00 00 00 00 callq 0x5d25 5d25: c3 retq ... and is called instead of and this caused test failures for #13/#77 etc. except #356. For test case #356/17, with [1] (progs/test_global_func17.c)), the main prog looks like: 0000000000000000 : 0: b4 00 00 00 2a 00 00 00 w0 = 0x2a 1: 95 00 00 00 00 00 00 00 exit ... which passed verification while the test itself expects a verification failure. Let us add 'barrier_var' style asm code in both places to prevent function specialization which caused selftests failure. [1] https://github.com/llvm/llvm-project/pull/72903 Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231127050342.1945270-1-yonghong.song@linux.dev --- net/bpf/test_run.c | 2 +- tools/testing/selftests/bpf/progs/test_global_func17.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index c9fdcc5cdce1..711cf5d59816 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -542,7 +542,7 @@ struct bpf_fentry_test_t { int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg) { - asm volatile (""); + asm volatile ("": "+r"(arg)); return (long)arg; } diff --git a/tools/testing/selftests/bpf/progs/test_global_func17.c b/tools/testing/selftests/bpf/progs/test_global_func17.c index a32e11c7d933..5de44b09e8ec 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func17.c +++ b/tools/testing/selftests/bpf/progs/test_global_func17.c @@ -5,6 +5,7 @@ __noinline int foo(int *p) { + barrier_var(p); return p ? (*p = 42) : 0; } From 19b4c60ce8660a0e3a2cebd3e4dc0691928d015d Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Sat, 25 Nov 2023 14:06:08 -0500 Subject: [PATCH 1537/7721] drm/sched: Fix compilation issues with DRM priority rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix compilation issues with DRM scheduler priority rename MIN to LOW. Signed-off-by: Luben Tuikov Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311252109.WgbJsSkG-lkp@intel.com/ Cc: Danilo Krummrich Cc: Frank Binns Cc: Donald Robson Cc: Matt Coster Cc: Direct Rendering Infrastructure - Development Fixes: fe375c74806dbd ("drm/sched: Rename priority MIN to LOW") Fixes: 38f922a563aac3 ("drm/sched: Reverse run-queue priority enumeration") Fixes: 5f03a507b29e44 ("drm/nouveau: implement 1:1 scheduler - entity relationship") Link: https://patchwork.freedesktop.org/patch/msgid/20231125192246.87268-2-ltuikov89@gmail.com Reviewed-by: Christian König Link: https://lore.kernel.org/r/7429262c-6dea-4dcc-bf7e-54d2277dabf1@amd.com --- drivers/gpu/drm/imagination/pvr_queue.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index d65c3fbedf5a..5ed9c98fb599 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -1292,7 +1292,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, goto err_release_ufo; err = drm_sched_entity_init(&queue->entity, - DRM_SCHED_PRIORITY_MIN, + DRM_SCHED_PRIORITY_KERNEL, &sched, 1, &ctx->faulty); if (err) goto err_sched_fini; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 3393647bd944..dd98f6910f9c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -18,7 +18,7 @@ * index to the run-queue array. */ enum nouveau_sched_priority { - NOUVEAU_SCHED_PRIORITY_SINGLE = DRM_SCHED_PRIORITY_MIN, + NOUVEAU_SCHED_PRIORITY_SINGLE = DRM_SCHED_PRIORITY_KERNEL, NOUVEAU_SCHED_PRIORITY_COUNT, }; @@ -423,7 +423,7 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, if (ret) goto fail_wq; - /* Using DRM_SCHED_PRIORITY_MIN, since that's what we're required to use + /* Using DRM_SCHED_PRIORITY_KERNEL, since that's what we're required to use * when we want to have a single run-queue only. * * It's not documented, but one will find out when trying to use any @@ -433,7 +433,7 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, * Can't use NOUVEAU_SCHED_PRIORITY_SINGLE either, because it's not * matching the enum type used in drm_sched_entity_init(). */ - ret = drm_sched_entity_init(entity, DRM_SCHED_PRIORITY_MIN, + ret = drm_sched_entity_init(entity, DRM_SCHED_PRIORITY_KERNEL, &drm_sched, 1, NULL); if (ret) goto fail_sched; From 5c0e047ab629bcb5efa94de63fcdc75c9fe69516 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 27 Nov 2023 15:34:42 +0200 Subject: [PATCH 1538/7721] ASoC: Intel: sof_sdw: Make use of dev_err_probe() The devm_snd_soc_register_card() can return with -EPROBE_DEFER and in that case the driver should not print an error message. Closes: https://github.com/thesofproject/linux/issues/4668 Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Chao Song Link: https://lore.kernel.org/r/20231127133448.18449-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 3312ad8a563b..199490f88653 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1946,7 +1946,7 @@ static int mc_probe(struct platform_device *pdev) /* Register the card */ ret = devm_snd_soc_register_card(card->dev, card); if (ret) { - dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); mc_dailink_exit_loop(card); return ret; } From fd8ff49d35f917c65383642c8f8f20656734f3ad Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 27 Nov 2023 15:34:43 +0200 Subject: [PATCH 1539/7721] ASoC: Intel: sof_sdw: remove unused function declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions sof_sdw_rt712_sdca_init() and sof_sdw_rt712_sdca_exit() declared in header file are never implemented and used, remove them. Signed-off-by: Chao Song Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127133448.18449-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_common.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index e6b98523b4e7..9528f147b719 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -138,12 +138,6 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); /* RT712-SDCA support */ -int sof_sdw_rt712_sdca_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt712_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); int sof_sdw_rt712_spk_init(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, From def127feaa8a9d8684ac41139638b079e6e637e2 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 27 Nov 2023 15:34:44 +0200 Subject: [PATCH 1540/7721] ASoC: Intel: sof_sdw: Add rt722 support RT722 is a multi-function codec which supports headset, amp, and dmic functions. Each function provides a DAI which can be used in different dailinks. The RT711 supports up to 3 SoundWire lanes, but that should not have any impact in the machine driver: the lanes are allocated and controlled by the manager and bandwidth allocation algorithm. Signed-off-by: Chao Song Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127133448.18449-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/Makefile | 3 +- sound/soc/intel/boards/sof_sdw.c | 30 ++++++ sound/soc/intel/boards/sof_sdw_common.h | 12 +++ sound/soc/intel/boards/sof_sdw_rt722_sdca.c | 97 +++++++++++++++++++ .../boards/sof_sdw_rt_sdca_jack_common.c | 8 ++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/boards/sof_sdw_rt722_sdca.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 9e427f00deac..99ebe48216ea 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -686,6 +686,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT712_SDCA_DMIC_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT722_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT1316_SDW diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 943bf8b80e01..bbf796a5f7ba 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -41,9 +41,10 @@ snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_rt5682.o sof_sdw_rt700.o \ sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ sof_sdw_rt712_sdca.o sof_sdw_rt715.o \ - sof_sdw_rt715_sdca.o sof_sdw_dmic.o \ + sof_sdw_rt715_sdca.o sof_sdw_rt722_sdca.o \ sof_sdw_cs42l42.o sof_sdw_cs42l43.o \ sof_sdw_cs_amp.o \ + sof_sdw_dmic.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 199490f88653..77a9ce401103 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -860,6 +860,36 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, .dai_num = 1, }, + { + .part_id = 0x722, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt722-sdca-aif1", + .dai_type = SOF_SDW_DAI_TYPE_JACK, + .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, + .init = sof_sdw_rt_sdca_jack_init, + .exit = sof_sdw_rt_sdca_jack_exit, + }, + { + .direction = {true, false}, + .dai_name = "rt722-sdca-aif2", + .dai_type = SOF_SDW_DAI_TYPE_AMP, + /* No feedback capability is provided by rt722-sdca codec driver*/ + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, + .init = sof_sdw_rt722_spk_init, + }, + { + .direction = {false, true}, + .dai_name = "rt722-sdca-aif3", + .dai_type = SOF_SDW_DAI_TYPE_MIC, + .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, + .init = sof_sdw_rt722_sdca_dmic_init, + }, + }, + .dai_num = 3, + }, { .part_id = 0x8373, .dais = { diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 9528f147b719..f16456945edb 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -183,6 +183,18 @@ int sof_sdw_rt715_sdca_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback); +/* RT722-SDCA support */ +int sof_sdw_rt722_spk_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); +int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + /* MAXIM codec support */ int sof_sdw_maxim_init(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c new file mode 100644 index 000000000000..fe3a2bff95bc --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Intel Corporation + +/* + * sof_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof_sdw_common.h" + +static const struct snd_soc_dapm_widget rt722_spk_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route rt722_spk_map[] = { + { "Speaker", NULL, "rt722 SPK" }, +}; + +static const struct snd_kcontrol_new rt722_spk_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:rt722", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_add_card_controls(card, rt722_spk_controls, + ARRAY_SIZE(rt722_spk_controls)); + if (ret) { + dev_err(card->dev, "failed to add rt722 spk controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt722_spk_widgets, + ARRAY_SIZE(rt722_spk_widgets)); + if (ret) { + dev_err(card->dev, "failed to add rt722 spk widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt722_spk_map, ARRAY_SIZE(rt722_spk_map)); + if (ret) + dev_err(rtd->dev, "failed to add rt722 spk map: %d\n", ret); + + return ret; +} + +int sof_sdw_rt722_spk_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + dai_links->init = rt722_spk_init; + + return 0; +} + +static int rt722_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:%s", + card->components, component->name_prefix); + if (!card->components) + return -ENOMEM; + + return 0; +} + +int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + dai_links->init = rt722_sdca_dmic_rtd_init; + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c index 65bbcee88d6d..e430be7681d2 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c @@ -63,6 +63,11 @@ static const struct snd_soc_dapm_route rt713_sdca_map[] = { { "rt713 MIC2", NULL, "Headset Mic" }, }; +static const struct snd_soc_dapm_route rt722_sdca_map[] = { + { "Headphone", NULL, "rt722 HP" }, + { "rt722 MIC2", NULL, "Headset Mic" }, +}; + static const struct snd_kcontrol_new rt_sdca_jack_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -117,6 +122,9 @@ static int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) } else if (strstr(component->name_prefix, "rt713")) { ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map, ARRAY_SIZE(rt713_sdca_map)); + } else if (strstr(component->name_prefix, "rt722")) { + ret = snd_soc_dapm_add_routes(&card->dapm, rt722_sdca_map, + ARRAY_SIZE(rt722_sdca_map)); } else { dev_err(card->dev, "%s is not supported\n", component->name_prefix); return -EINVAL; From 817178e7674bd8ca35344b2212a3105ed75559e5 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Mon, 27 Nov 2023 15:34:45 +0200 Subject: [PATCH 1541/7721] ASoC: Intel: soc-acpi: rt713+rt1316, no sdw-dmic config This is additional HW board: rt713+rt1316 without rt713-dmic configuration: SDW0: rt713 audio jack SDW1: rt1316 spk_amp_l SDW2: rt1316 spk_amp_r Signed-off-by: Mac Chiang Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127133448.18449-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-mtl-match.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 301b8142d554..61f2b2645496 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -422,6 +422,25 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12_rt1713_l3[] = {} }; +static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt713_0_single_adr), + .adr_d = rt713_0_single_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group2_adr), + .adr_d = rt1316_1_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group2_adr), + .adr_d = rt1316_2_group2_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = { { .adr = 0x000230019F836300ull, @@ -507,6 +526,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg", }, + { + .link_mask = GENMASK(2, 0), + .links = mtl_rt713_l0_rt1316_l12, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg", + }, { .link_mask = BIT(3) | BIT(0), .links = mtl_712_only, From faca26b6ca90b220cba787ff7c6a05e99528731c Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 27 Nov 2023 15:34:46 +0200 Subject: [PATCH 1542/7721] ASoC: Intel: soc-acpi: add Gen4.1 SDCA board support for LNL RVP This patch adds support for LNL RVP with Realtek Gen4.1 SDCA codec board, the codec layout is: SDW0: RT711 Headphone SDW1: RT714 DMIC SDW2: RT1316 Speaker SDW3: RT1316 Speaker Signed-off-by: Chao Song Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127133448.18449-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-lnl-match.c | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 9f35b77deb11..5897bb6b28b8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -22,6 +22,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -31,6 +45,33 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { + { + .adr = 0x000230025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { + { + .adr = 0x000331025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { + { + .adr = 0x000130025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_link_adr lnl_rvp[] = { { .mask = BIT(0), @@ -40,6 +81,30 @@ static const struct snd_soc_acpi_link_adr lnl_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_3_in_1_sdca[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group1_adr), + .adr_d = rt1316_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_group1_adr), + .adr_d = rt1316_3_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt714_1_adr), + .adr_d = rt714_1_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { /* mockup tests need to be first */ @@ -61,6 +126,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg", }, + { + .link_mask = GENMASK(3, 0), + .links = lnl_3_in_1_sdca, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg", + }, { .link_mask = BIT(0), .links = lnl_rvp, From fadf3dffe54fe10e0d86232f0a7576eccc04d537 Mon Sep 17 00:00:00 2001 From: Santosh Pradhan Date: Fri, 24 Nov 2023 22:34:21 +0100 Subject: [PATCH 1543/7721] block/rnbd: add support for REQ_OP_WRITE_ZEROES Remove REQ_OP_WRITE_SAME in favour of REQ_OP_WRITE_ZEROES. Signed-off-by: Santosh Pradhan Reviewed-by: Md Haris Iqbal Signed-off-by: Grzegorz Prajsner Signed-off-by: Md Haris Iqbal Link: https://lore.kernel.org/r/20231124213422.113449-2-haris.iqbal@ionos.com Signed-off-by: Jens Axboe --- drivers/block/rnbd/rnbd-clt.c | 9 ++++++--- drivers/block/rnbd/rnbd-proto.h | 14 ++++++++++---- drivers/block/rnbd/rnbd-srv.c | 3 ++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index b0550b68645d..499d0e655bc3 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1006,10 +1006,10 @@ static int rnbd_client_xfer_request(struct rnbd_clt_dev *dev, msg.prio = cpu_to_le16(req_get_ioprio(rq)); /* - * We only support discards with single segment for now. + * We only support discards/WRITE_ZEROES with single segment for now. * See queue limits. */ - if (req_op(rq) != REQ_OP_DISCARD) + if ((req_op(rq) != REQ_OP_DISCARD) && (req_op(rq) != REQ_OP_WRITE_ZEROES)) sg_cnt = blk_rq_map_sg(dev->queue, rq, iu->sgt.sgl); if (sg_cnt == 0) @@ -1362,6 +1362,8 @@ static void setup_request_queue(struct rnbd_clt_dev *dev, blk_queue_write_cache(dev->queue, !!(rsp->cache_policy & RNBD_WRITEBACK), !!(rsp->cache_policy & RNBD_FUA)); + blk_queue_max_write_zeroes_sectors(dev->queue, + le32_to_cpu(rsp->max_write_zeroes_sectors)); } static int rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev, @@ -1626,10 +1628,11 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, } rnbd_clt_info(dev, - "map_device: Device mapped as %s (nsectors: %llu, logical_block_size: %d, physical_block_size: %d, max_discard_sectors: %d, discard_granularity: %d, discard_alignment: %d, secure_discard: %d, max_segments: %d, max_hw_sectors: %d, wc: %d, fua: %d)\n", + "map_device: Device mapped as %s (nsectors: %llu, logical_block_size: %d, physical_block_size: %d, max_write_zeroes_sectors: %d, max_discard_sectors: %d, discard_granularity: %d, discard_alignment: %d, secure_discard: %d, max_segments: %d, max_hw_sectors: %d, wc: %d, fua: %d)\n", dev->gd->disk_name, le64_to_cpu(rsp->nsectors), le16_to_cpu(rsp->logical_block_size), le16_to_cpu(rsp->physical_block_size), + le32_to_cpu(rsp->max_write_zeroes_sectors), le32_to_cpu(rsp->max_discard_sectors), le32_to_cpu(rsp->discard_granularity), le32_to_cpu(rsp->discard_alignment), diff --git a/drivers/block/rnbd/rnbd-proto.h b/drivers/block/rnbd/rnbd-proto.h index e32f8f2c868a..f35be51d213c 100644 --- a/drivers/block/rnbd/rnbd-proto.h +++ b/drivers/block/rnbd/rnbd-proto.h @@ -128,7 +128,7 @@ enum rnbd_cache_policy { * @device_id: device_id on server side to identify the device * @nsectors: number of sectors in the usual 512b unit * @max_hw_sectors: max hardware sectors in the usual 512b unit - * @max_write_same_sectors: max sectors for WRITE SAME in the 512b unit + * @max_write_zeroes_sectors: max sectors for WRITE ZEROES in the 512b unit * @max_discard_sectors: max. sectors that can be discarded at once in 512b * unit. * @discard_granularity: size of the internal discard allocation unit in bytes @@ -145,7 +145,7 @@ struct rnbd_msg_open_rsp { __le32 device_id; __le64 nsectors; __le32 max_hw_sectors; - __le32 max_write_same_sectors; + __le32 max_write_zeroes_sectors; __le32 max_discard_sectors; __le32 discard_granularity; __le32 discard_alignment; @@ -186,7 +186,7 @@ struct rnbd_msg_io { * @RNBD_OP_FLUSH: flush the volatile write cache * @RNBD_OP_DISCARD: discard sectors * @RNBD_OP_SECURE_ERASE: securely erase sectors - * @RNBD_OP_WRITE_SAME: write the same sectors many times + * @RNBD_OP_WRITE_ZEROES: write zeroes sectors * @RNBD_F_SYNC: request is sync (sync write or read) * @RNBD_F_FUA: forced unit access @@ -199,7 +199,7 @@ enum rnbd_io_flags { RNBD_OP_FLUSH = 2, RNBD_OP_DISCARD = 3, RNBD_OP_SECURE_ERASE = 4, - RNBD_OP_WRITE_SAME = 5, + RNBD_OP_WRITE_ZEROES = 5, /* Flags */ RNBD_F_SYNC = 1<<(RNBD_OP_BITS + 0), @@ -236,6 +236,9 @@ static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf) case RNBD_OP_SECURE_ERASE: bio_opf = REQ_OP_SECURE_ERASE; break; + case RNBD_OP_WRITE_ZEROES: + bio_opf = REQ_OP_WRITE_ZEROES; + break; default: WARN(1, "Unknown RNBD type: %d (flags %d)\n", rnbd_op(rnbd_opf), rnbd_opf); @@ -268,6 +271,9 @@ static inline u32 rq_to_rnbd_flags(struct request *rq) case REQ_OP_SECURE_ERASE: rnbd_opf = RNBD_OP_SECURE_ERASE; break; + case REQ_OP_WRITE_ZEROES: + rnbd_opf = RNBD_OP_WRITE_ZEROES; + break; case REQ_OP_FLUSH: rnbd_opf = RNBD_OP_FLUSH; break; diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c index 65de51f3dfd9..64ad1cd44942 100644 --- a/drivers/block/rnbd/rnbd-srv.c +++ b/drivers/block/rnbd/rnbd-srv.c @@ -544,7 +544,8 @@ static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp, rsp->max_segments = cpu_to_le16(bdev_max_segments(bdev)); rsp->max_hw_sectors = cpu_to_le32(queue_max_hw_sectors(bdev_get_queue(bdev))); - rsp->max_write_same_sectors = 0; + rsp->max_write_zeroes_sectors = + cpu_to_le32(bdev_write_zeroes_sectors(bdev)); rsp->max_discard_sectors = cpu_to_le32(bdev_max_discard_sectors(bdev)); rsp->discard_granularity = cpu_to_le32(bdev_discard_granularity(bdev)); rsp->discard_alignment = cpu_to_le32(bdev_discard_alignment(bdev)); From 70d85bec8f4c0d003db505bf35a3ec87bb1f627f Mon Sep 17 00:00:00 2001 From: Supriti Singh Date: Fri, 24 Nov 2023 22:34:22 +0100 Subject: [PATCH 1544/7721] block/rnbd: use %pe to print errors While printing error, replace %ld by %pe. %pe prints a string whereas %ld would print an error code. Signed-off-by: Supriti Singh Signed-off-by: Jack Wang Signed-off-by: Grzegorz Prajsner Signed-off-by: Md Haris Iqbal Link: https://lore.kernel.org/r/20231124213422.113449-3-haris.iqbal@ionos.com Signed-off-by: Jens Axboe --- drivers/block/rnbd/rnbd-clt.c | 4 ++-- drivers/block/rnbd/rnbd-srv.c | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index 499d0e655bc3..4044c369d22a 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1569,8 +1569,8 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, dev = init_dev(sess, access_mode, pathname, nr_poll_queues); if (IS_ERR(dev)) { - pr_err("map_device: failed to map device '%s' from session %s, can't initialize device, err: %ld\n", - pathname, sess->sessname, PTR_ERR(dev)); + pr_err("map_device: failed to map device '%s' from session %s, can't initialize device, err: %pe\n", + pathname, sess->sessname, dev); ret = PTR_ERR(dev); goto put_sess; } diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c index 64ad1cd44942..29733b615754 100644 --- a/drivers/block/rnbd/rnbd-srv.c +++ b/drivers/block/rnbd/rnbd-srv.c @@ -136,8 +136,8 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, sess_dev = rnbd_get_sess_dev(dev_id, srv_sess); if (IS_ERR(sess_dev)) { - pr_err_ratelimited("Got I/O request on session %s for unknown device id %d\n", - srv_sess->sessname, dev_id); + pr_err_ratelimited("Got I/O request on session %s for unknown device id %d: %pe\n", + srv_sess->sessname, dev_id, sess_dev); err = -ENOTCONN; goto err; } @@ -710,24 +710,24 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess, full_path = rnbd_srv_get_full_path(srv_sess, open_msg->dev_name); if (IS_ERR(full_path)) { ret = PTR_ERR(full_path); - pr_err("Opening device '%s' for client %s failed, failed to get device full path, err: %d\n", - open_msg->dev_name, srv_sess->sessname, ret); + pr_err("Opening device '%s' for client %s failed, failed to get device full path, err: %pe\n", + open_msg->dev_name, srv_sess->sessname, full_path); goto reject; } bdev_handle = bdev_open_by_path(full_path, open_flags, NULL, NULL); if (IS_ERR(bdev_handle)) { ret = PTR_ERR(bdev_handle); - pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %d\n", - full_path, srv_sess->sessname, ret); + pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %pe\n", + full_path, srv_sess->sessname, bdev_handle); goto free_path; } srv_dev = rnbd_srv_get_or_create_srv_dev(bdev_handle->bdev, srv_sess, open_msg->access_mode); if (IS_ERR(srv_dev)) { - pr_err("Opening device '%s' on session %s failed, creating srv_dev failed, err: %ld\n", - full_path, srv_sess->sessname, PTR_ERR(srv_dev)); + pr_err("Opening device '%s' on session %s failed, creating srv_dev failed, err: %pe\n", + full_path, srv_sess->sessname, srv_dev); ret = PTR_ERR(srv_dev); goto blkdev_put; } @@ -737,8 +737,8 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess, open_msg->access_mode == RNBD_ACCESS_RO, srv_dev); if (IS_ERR(srv_sess_dev)) { - pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %ld\n", - full_path, srv_sess->sessname, PTR_ERR(srv_sess_dev)); + pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %pe\n", + full_path, srv_sess->sessname, srv_sess_dev); ret = PTR_ERR(srv_sess_dev); goto srv_dev_put; } @@ -819,7 +819,7 @@ static int __init rnbd_srv_init_module(void) }; rtrs_ctx = rtrs_srv_open(&rtrs_ops, port_nr); if (IS_ERR(rtrs_ctx)) { - pr_err("rtrs_srv_open(), err: %d\n", err); + pr_err("rtrs_srv_open(), err: %pe\n", rtrs_ctx); return PTR_ERR(rtrs_ctx); } From 668bfeeabb5e402e3b36992f7859c284cc6e594d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 27 Nov 2023 08:20:02 +0100 Subject: [PATCH 1545/7721] block: move a few definitions out of CONFIG_BLK_DEV_ZONED Allow using a few symbols with IS_ENABLED instead of #idef by moving the declarations out of #idef CONFIG_BLK_DEV_ZONED, and move bdev_nr_zones into the remaining #idef CONFIG_BLK_DEV_ZONED, #else block below. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20231127072002.1332685-1-hch@lst.de Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 51fa7ffdee83..17c0a7d0d319 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -331,22 +331,13 @@ typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx, void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model); -#ifdef CONFIG_BLK_DEV_ZONED #define BLK_ALL_ZONES ((unsigned int)-1) int blkdev_report_zones(struct block_device *bdev, sector_t sector, - unsigned int nr_zones, report_zones_cb cb, void *data); -unsigned int bdev_nr_zones(struct block_device *bdev); -extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op, - sector_t sectors, sector_t nr_sectors, - gfp_t gfp_mask); + unsigned int nr_zones, report_zones_cb cb, void *data); +int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op, + sector_t sectors, sector_t nr_sectors, gfp_t gfp_mask); int blk_revalidate_disk_zones(struct gendisk *disk, - void (*update_driver_data)(struct gendisk *disk)); -#else /* CONFIG_BLK_DEV_ZONED */ -static inline unsigned int bdev_nr_zones(struct block_device *bdev) -{ - return 0; -} -#endif /* CONFIG_BLK_DEV_ZONED */ + void (*update_driver_data)(struct gendisk *disk)); /* * Independent access ranges: struct blk_independent_access_range describes @@ -643,6 +634,8 @@ static inline bool blk_queue_is_zoned(struct request_queue *q) } #ifdef CONFIG_BLK_DEV_ZONED +unsigned int bdev_nr_zones(struct block_device *bdev); + static inline unsigned int disk_nr_zones(struct gendisk *disk) { return blk_queue_is_zoned(disk->queue) ? disk->nr_zones : 0; @@ -687,6 +680,11 @@ static inline unsigned int bdev_max_active_zones(struct block_device *bdev) } #else /* CONFIG_BLK_DEV_ZONED */ +static inline unsigned int bdev_nr_zones(struct block_device *bdev) +{ + return 0; +} + static inline unsigned int disk_nr_zones(struct gendisk *disk) { return 0; From 2112aa034907c428785e1a5730927181276ee45b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 17 Nov 2023 13:05:55 +0100 Subject: [PATCH 1546/7721] ALSA: pcm: Introduce MSBITS subformat interface Improve granularity of format selection for S32/U32 formats by adding constants representing 20, 24 and MAX most significant bits. The MAX means the maximum number of significant bits which can the physical format hold. For 32-bit formats, MAX is related to 32 bits. For 8-bit formats, MAX is related to 8 bits etc. As there is only one user currently (format S32_LE), subformat is represented by a simple u32 and stores flags only for that one user alone. The approach of subformat being part of struct snd_pcm_hardware is a compromise between ALSA and ASoC allowing for hw_params-intersection code to be alloc/free-less while not adding any new responsibilities to ASoC runtime structures. Acked-by: Mark Brown Signed-off-by: Jaroslav Kysela Co-developed-by: Cezary Rojewski Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20231117120610.1755254-2-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 7 ++++ include/uapi/sound/asound.h | 7 ++-- sound/core/pcm.c | 3 ++ sound/core/pcm_native.c | 55 +++++++++++++++++++++++++++++-- tools/include/uapi/sound/asound.h | 7 ++-- 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2a815373dac1..cc175c623dac 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -32,6 +32,7 @@ struct snd_pcm_hardware { unsigned int info; /* SNDRV_PCM_INFO_* */ u64 formats; /* SNDRV_PCM_FMTBIT_* */ + u32 subformats; /* for S32_LE, SNDRV_PCM_SUBFMTBIT_* */ unsigned int rates; /* SNDRV_PCM_RATE_* */ unsigned int rate_min; /* min rate */ unsigned int rate_max; /* max rate */ @@ -217,6 +218,12 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE #endif +#define _SNDRV_PCM_SUBFMTBIT(fmt) BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt) +#define SNDRV_PCM_SUBFMTBIT_STD _SNDRV_PCM_SUBFMTBIT(STD) +#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX) +#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 _SNDRV_PCM_SUBFMTBIT(MSBITS_20) +#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 _SNDRV_PCM_SUBFMTBIT(MSBITS_24) + struct snd_pcm_file { struct snd_pcm_substream *substream; int no_compat_mmap; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index f9939da41122..d5b9cfbd9cea 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 16) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -267,7 +267,10 @@ typedef int __bitwise snd_pcm_format_t; typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) -#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD +#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) +#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) +#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 #define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 20bb2d7c8d4b..c4bc15f048b6 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -265,6 +265,9 @@ static const char * const snd_pcm_access_names[] = { static const char * const snd_pcm_subformat_names[] = { SUBFORMAT(STD), + SUBFORMAT(MSBITS_MAX), + SUBFORMAT(MSBITS_20), + SUBFORMAT(MSBITS_24), }; static const char * const snd_pcm_tstamp_mode_names[] = { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f610b08f5a2b..f5ff00f99788 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -479,6 +479,7 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, { const struct snd_interval *i; const struct snd_mask *m; + struct snd_mask *m_rw; int err; if (!params->msbits) { @@ -487,6 +488,22 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, params->msbits = snd_interval_value(i); } + if (params->msbits) { + m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + if (snd_mask_single(m)) { + snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m); + + if (snd_pcm_format_linear(format) && + snd_pcm_format_width(format) != params->msbits) { + m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT); + snd_mask_reset(m_rw, + (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); + if (snd_mask_empty(m_rw)) + return -EINVAL; + } + } + } + if (!params->rate_den) { i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); if (snd_interval_single(i)) { @@ -2483,6 +2500,41 @@ static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, return snd_interval_refine(hw_param_interval(params, rule->var), &t); } +static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_mask *sfmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT); + struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + u32 *subformats = rule->private; + snd_pcm_format_t f; + struct snd_mask m; + + snd_mask_none(&m); + /* All PCMs support at least the default STD subformat. */ + snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD); + + pcm_for_each_format(f) { + if (!snd_mask_test(fmask, (__force unsigned)f)) + continue; + + if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats) + m.bits[0] |= *subformats; + else if (snd_pcm_format_linear(f)) + snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); + } + + return snd_mask_refine(sfmask, &m); +} + +static int snd_pcm_hw_constraint_subformats(struct snd_pcm_runtime *runtime, + unsigned int cond, u32 *subformats) +{ + return snd_pcm_hw_rule_add(runtime, cond, -1, + snd_pcm_hw_rule_subformats, (void *)subformats, + SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_HW_PARAM_FORMAT, -1); +} + static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2634,8 +2686,7 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) if (err < 0) return err; - err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, - PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD)); + err = snd_pcm_hw_constraint_subformats(runtime, 0, &hw->subformats); if (err < 0) return err; diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h index f9939da41122..d5b9cfbd9cea 100644 --- a/tools/include/uapi/sound/asound.h +++ b/tools/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 16) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -267,7 +267,10 @@ typedef int __bitwise snd_pcm_format_t; typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) -#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD +#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) +#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) +#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 #define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ From a7fc8b862fd5952be791a870ef8ef56016e83ff4 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:05:56 +0100 Subject: [PATCH 1547/7721] ALSA: hda: Honor subformat when querying PCMs Update mechanism for querying supported PCMs to allow for granular format selection when container size is 32 bits. Currently always the highest bit depth is selected, regardless of how many actual formats codec in question supports. Acked-by: Mark Brown Co-developed-by: Jaroslav Kysela Signed-off-by: Jaroslav Kysela Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20231117120610.1755254-3-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 5 ++-- include/sound/hdaudio.h | 3 ++- sound/hda/hdac_device.c | 47 ++++++++++++++++++++---------------- sound/pci/hda/hda_codec.c | 2 ++ sound/pci/hda/patch_hdmi.c | 1 + sound/soc/codecs/hdac_hdmi.c | 3 ++- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 5497dc9c396a..9c94ba7c183d 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -141,6 +141,7 @@ struct hda_pcm_stream { hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ u32 rates; /* supported rates */ u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ + u32 subformats; /* for S32_LE format, SNDRV_PCM_SUBFMTBIT_* */ unsigned int maxbps; /* supported max. bit per sample */ const struct snd_pcm_chmap_elem *chmap; /* chmap to override */ struct hda_pcm_ops ops; @@ -448,8 +449,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, #define snd_hda_codec_cleanup_stream(codec, nid) \ __snd_hda_codec_cleanup_stream(codec, nid, 0) -#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, bpsp) \ - snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, bpsp) +#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, subfmtp, bpsp) \ + snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, subfmtp, bpsp) #define snd_hda_is_supported_format(codec, nid, fmt) \ snd_hdac_is_supported_format(&(codec)->core, nid, fmt) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index dd7c87bbc613..7cfea9e7f6e4 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -146,7 +146,8 @@ unsigned int snd_hdac_calc_stream_format(unsigned int rate, unsigned int maxbps, unsigned short spdif_ctls); int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); + u32 *ratesp, u64 *formatsp, u32 *subformatsp, + unsigned int *bpsp); bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, unsigned int format); diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index bbf7bcdb449a..cde4d5c33771 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -817,15 +817,17 @@ static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) * @nid: NID to query * @ratesp: the pointer to store the detected rate bitflags * @formatsp: the pointer to store the detected formats + * @subformatsp: the pointer to store the detected subformats for S32_LE format * @bpsp: the pointer to store the detected format widths * - * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp - * or @bsps argument is ignored. + * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp, + * @subformatsp or @bpsp argument is ignored. * * Returns 0 if successful, otherwise a negative error code. */ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp) + u32 *ratesp, u64 *formatsp, u32 *subformatsp, + unsigned int *bpsp) { unsigned int i, val, wcaps; @@ -848,9 +850,10 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, *ratesp = rates; } - if (formatsp || bpsp) { - u64 formats = 0; + if (formatsp || subformatsp || bpsp) { unsigned int streams, bps; + u32 subformats = 0; + u64 formats = 0; streams = query_stream_param(codec, nid); if (!streams) @@ -866,24 +869,24 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, formats |= SNDRV_PCM_FMTBIT_S16_LE; bps = 16; } - if (wcaps & AC_WCAP_DIGITAL) { - if (val & AC_SUPPCM_BITS_32) - formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; - if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; - } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| - AC_SUPPCM_BITS_32)) { + if (val & AC_SUPPCM_BITS_20) { formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_32) + subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_20; + bps = 20; + } + if (val & AC_SUPPCM_BITS_24) { + formats |= SNDRV_PCM_FMTBIT_S32_LE; + subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_24; + bps = 24; + } + if (val & AC_SUPPCM_BITS_32) { + if (wcaps & AC_WCAP_DIGITAL) { + formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; + } else { + formats |= SNDRV_PCM_FMTBIT_S32_LE; + subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_MAX; bps = 32; - else if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; + } } } #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ @@ -911,6 +914,8 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, } if (formatsp) *formatsp = formats; + if (subformatsp) + *subformatsp = subformats; if (bpsp) *bpsp = bps; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 01718b1fc9a7..12f02cdc9659 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3163,6 +3163,7 @@ static int set_pcm_default_values(struct hda_codec *codec, err = snd_hda_query_supported_pcm(codec, info->nid, info->rates ? NULL : &info->rates, info->formats ? NULL : &info->formats, + info->subformats ? NULL : &info->subformats, info->maxbps ? NULL : &info->maxbps); if (err < 0) return err; @@ -3757,6 +3758,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, snd_hda_query_supported_pcm(codec, mout->dig_out_nid, &mout->spdif_rates, &mout->spdif_formats, + NULL, &mout->spdif_maxbps); } mutex_lock(&codec->spdif_mutex); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1cde2a69bdb4..687b8b8fd7ac 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1977,6 +1977,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) err = snd_hda_query_supported_pcm(codec, cvt_nid, &per_cvt->rates, &per_cvt->formats, + NULL, &per_cvt->maxbps); if (err < 0) return err; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b9c5ffbfb5ba..3e4f632d8665 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -670,6 +670,7 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt) err = snd_hdac_query_supported_pcm(hdev, cvt->nid, &cvt->params.rates, &cvt->params.formats, + NULL, &cvt->params.maxbps); if (err < 0) dev_err(&hdev->dev, @@ -1577,7 +1578,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev, list_for_each_entry(cvt, &hdmi->cvt_list, head) { ret = snd_hdac_query_supported_pcm(hdev, cvt->nid, - &rates, &formats, &bps); + &rates, &formats, NULL, &bps); if (ret) return ret; From 4a6ba09e892aab49fda8464e4f9b244a17fd75b2 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:05:57 +0100 Subject: [PATCH 1548/7721] ASoC: pcm: Honor subformat when configuring runtime Subformat options are ignored when setting up hardware parameters and assigning PCM stream capabilities. Account for them to allow for granular format selection. As there is only one user currently (format S32_LE), subformat is represented by a simple u32 and stores flags only for that one user alone. Such approach allows for alloc/free-less code until there are more users on the horizon. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-4-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/soc.h | 1 + sound/soc/soc-pcm.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 7792c393e238..ccc31bc41e92 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -620,6 +620,7 @@ enum snd_soc_trigger_order { struct snd_soc_pcm_stream { const char *stream_name; u64 formats; /* SNDRV_PCM_FMTBIT_* */ + u32 subformats; /* for S32_LE format, SNDRV_PCM_SUBFMTBIT_* */ unsigned int rates; /* SNDRV_PCM_RATE_* */ unsigned int rate_min; /* min rate */ unsigned int rate_max; /* max rate */ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 323e4d7b6adf..9d688917cce2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -554,6 +554,12 @@ static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw, hw->formats &= p->formats; } +static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw, + struct snd_soc_pcm_stream *p) +{ + hw->subformats &= p->subformats; +} + /** * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream * @rtd: ASoC PCM runtime @@ -592,6 +598,7 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, soc_pcm_hw_update_chan(hw, cpu_stream); soc_pcm_hw_update_rate(hw, cpu_stream); soc_pcm_hw_update_format(hw, cpu_stream); + soc_pcm_hw_update_subformat(hw, cpu_stream); } cpu_chan_min = hw->channels_min; cpu_chan_max = hw->channels_max; @@ -613,6 +620,7 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, soc_pcm_hw_update_chan(hw, codec_stream); soc_pcm_hw_update_rate(hw, codec_stream); soc_pcm_hw_update_format(hw, codec_stream); + soc_pcm_hw_update_subformat(hw, codec_stream); } /* Verify both a valid CPU DAI and a valid CODEC DAI were found */ @@ -1713,6 +1721,7 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) soc_pcm_hw_update_rate(hw, cpu_stream); soc_pcm_hw_update_chan(hw, cpu_stream); soc_pcm_hw_update_format(hw, cpu_stream); + soc_pcm_hw_update_subformat(hw, cpu_stream); } } @@ -1750,6 +1759,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream) codec_stream = snd_soc_dai_get_pcm_stream(dai, stream); soc_pcm_hw_update_format(hw, codec_stream); + soc_pcm_hw_update_subformat(hw, codec_stream); } } } From d24f1a090d3f2a5c86a8782afeda71c2d2539966 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:05:58 +0100 Subject: [PATCH 1549/7721] ALSA: hda: Upgrade stream-format infrastructure Introduce a set of functions that ultimately facilite SDxFMT-related calculations in atomic manner: First, introduce snd_pcm_subformat_width() and snd_pcm_hw_params_bits() helpers that separate the base functionality from the HDAudio-specific one. snd_hdac_format_normalize() - format converter. S20_LE, S24_LE and their unsigned and BE friends are invalid from HDAudio perspective but still can be specified as function argument due to compatibility reasons. snd_hdac_stream_format_bits() - obtain just the bits-per-sample value. Does not ignore subformat and msbits parameters. snd_hdac_stream_format() and snd_hdac_spdif_stream_format() - obtain the SDxFMT value given the audio format parameters. The former is stripped away of spdif-related information. Useful for users that do not care about them. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-5-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 5 ++ include/sound/pcm_params.h | 2 + sound/core/pcm_lib.c | 34 ++++++++++ sound/hda/hdac_device.c | 124 +++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 7cfea9e7f6e4..b00c631c4053 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -140,6 +140,11 @@ int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, hda_nid_t *start_id); +unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, + unsigned int maxbits); +unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate); +unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, + unsigned int rate, unsigned short spdif_ctls); unsigned int snd_hdac_calc_stream_format(unsigned int rate, unsigned int channels, snd_pcm_format_t format, diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index ba184f49f7e1..fbf35df6e5cf 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -362,6 +362,8 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) return snd_pcm_format_physical_width(params_format(p)); } +int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p); + static inline void params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) { diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a11cd7d6295f..41103e5c43ce 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1706,6 +1706,40 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, } EXPORT_SYMBOL(snd_pcm_hw_param_last); +/** + * snd_pcm_hw_params_bits - Get the number of bits per the sample. + * @p: hardware parameters + * + * Return: The number of bits per sample based on the format, + * subformat and msbits the specified hw params has. + */ +int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p) +{ + snd_pcm_subformat_t subformat = params_subformat(p); + snd_pcm_format_t format = params_format(p); + + switch (format) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_BE: + switch (subformat) { + case SNDRV_PCM_SUBFORMAT_MSBITS_20: + return 20; + case SNDRV_PCM_SUBFORMAT_MSBITS_24: + return 24; + case SNDRV_PCM_SUBFORMAT_MSBITS_MAX: + case SNDRV_PCM_SUBFORMAT_STD: + default: + break; + } + fallthrough; + default: + return snd_pcm_format_width(format); + } +} +EXPORT_SYMBOL(snd_pcm_hw_params_bits); + static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, void *arg) { diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index cde4d5c33771..556bd24f4014 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "local.h" static void setup_fg_nodes(struct hdac_device *codec); @@ -725,6 +726,129 @@ static const struct hda_rate_tbl rate_bits[] = { { 0 } /* terminator */ }; +static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S20_LE: + case SNDRV_PCM_FORMAT_S24_LE: + return SNDRV_PCM_FORMAT_S32_LE; + + case SNDRV_PCM_FORMAT_U20_LE: + case SNDRV_PCM_FORMAT_U24_LE: + return SNDRV_PCM_FORMAT_U32_LE; + + case SNDRV_PCM_FORMAT_S20_BE: + case SNDRV_PCM_FORMAT_S24_BE: + return SNDRV_PCM_FORMAT_S32_BE; + + case SNDRV_PCM_FORMAT_U20_BE: + case SNDRV_PCM_FORMAT_U24_BE: + return SNDRV_PCM_FORMAT_U32_BE; + + default: + return format; + } +} + +/** + * snd_hdac_stream_format_bits - obtain bits per sample value. + * @format: the PCM format. + * @subformat: the PCM subformat. + * @maxbits: the maximum bits per sample. + * + * Return: The number of bits per sample. + */ +unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, + unsigned int maxbits) +{ + struct snd_pcm_hw_params params; + unsigned int bits; + + memset(¶ms, 0, sizeof(params)); + + params_set_format(¶ms, snd_hdac_format_normalize(format)); + snd_mask_set(hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT), + (__force unsigned int)subformat); + + bits = snd_pcm_hw_params_bits(¶ms); + if (maxbits) + return min(bits, maxbits); + return bits; +} +EXPORT_SYMBOL_GPL(snd_hdac_stream_format_bits); + +/** + * snd_hdac_stream_format - convert format parameters to SDxFMT value. + * @channels: the number of channels. + * @bits: bits per sample. + * @rate: the sample rate. + * + * Return: The format bitset or zero if invalid. + */ +unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate) +{ + unsigned int val = 0; + int i; + + for (i = 0; rate_bits[i].hz; i++) { + if (rate_bits[i].hz == rate) { + val = rate_bits[i].hda_fmt; + break; + } + } + + if (!rate_bits[i].hz) + return 0; + + if (channels == 0 || channels > 8) + return 0; + val |= channels - 1; + + switch (bits) { + case 8: + val |= AC_FMT_BITS_8; + break; + case 16: + val |= AC_FMT_BITS_16; + break; + case 20: + val |= AC_FMT_BITS_20; + break; + case 24: + val |= AC_FMT_BITS_24; + break; + case 32: + val |= AC_FMT_BITS_32; + break; + default: + return 0; + } + + return val; +} +EXPORT_SYMBOL_GPL(snd_hdac_stream_format); + +/** + * snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value. + * @channels: the number of channels. + * @bits: bits per sample. + * @rate: the sample rate. + * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant). + * + * Return: The format bitset or zero if invalid. + */ +unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, + unsigned int rate, unsigned short spdif_ctls) +{ + unsigned int val = snd_hdac_stream_format(channels, bits, rate); + + if (val && spdif_ctls & AC_DIG1_NONAUDIO) + val |= AC_FMT_TYPE_NON_PCM; + + return val; +} +EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format); + /** * snd_hdac_calc_stream_format - calculate the format bitset * @rate: the sample rate From 61b52df4b64fa1c8860cdfbc548cd0bbe7310082 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:05:59 +0100 Subject: [PATCH 1550/7721] ALSA: hda: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-6-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index c42e9ffff9db..3e7bfeee84fd 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -151,7 +151,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int format_val, stream_tag; + unsigned int format_val, stream_tag, bits; int err; struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); @@ -165,11 +165,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) } snd_hdac_stream_reset(azx_stream(azx_dev)); - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hinfo->maxbps, - ctls); + bits = snd_hdac_stream_format_bits(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps); + + format_val = snd_hdac_spdif_stream_format(runtime->channels, bits, runtime->rate, ctls); if (!format_val) { dev_err(chip->card->dev, "invalid format_val, rate=%d, ch=%d, format=%d\n", From 67ea58daab010ea7a622a89392cc9a6190f8b9c1 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:00 +0100 Subject: [PATCH 1551/7721] ALSA: hda/hdmi: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-7-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 687b8b8fd7ac..dff2d7221982 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1655,7 +1655,6 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, #define I915_SILENT_RATE 48000 #define I915_SILENT_CHANNELS 2 -#define I915_SILENT_FORMAT SNDRV_PCM_FORMAT_S16_LE #define I915_SILENT_FORMAT_BITS 16 #define I915_SILENT_FMT_MASK 0xf @@ -1668,8 +1667,8 @@ static void silent_stream_enable_i915(struct hda_codec *codec, per_pin->dev_id, I915_SILENT_RATE); /* trigger silent stream generation in hw */ - format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS, - I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0); + format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS, + I915_SILENT_RATE); snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); usleep_range(100, 200); From 0d41f0c07f19de7fb5790cbe462dddb68af60fa8 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:01 +0100 Subject: [PATCH 1552/7721] ALSA: hda/ca0132: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-8-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 748a3c40966e..aa312441604f 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -3022,8 +3022,7 @@ static int dma_convert_to_hda_format(struct hda_codec *codec, { unsigned int format_val; - format_val = snd_hdac_calc_stream_format(sample_rate, - channels, SNDRV_PCM_FORMAT_S32_LE, 32, 0); + format_val = snd_hdac_stream_format(channels, 32, sample_rate); if (hda_format) *hda_format = (unsigned short)format_val; From d5c00ab2f508176e8d8bd976d8b2207c5f0a932b Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:02 +0100 Subject: [PATCH 1553/7721] ASoC: codecs: hda: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. While at it, complete PCM stream initialization with subformat options. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-9-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/codecs/hda-dai.c | 7 +++++-- sound/soc/codecs/hda.c | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c index 5371ff086261..7bd7ddcd810f 100644 --- a/sound/soc/codecs/hda-dai.c +++ b/sound/soc/codecs/hda-dai.c @@ -76,13 +76,16 @@ static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd struct hdac_stream *stream; struct hda_codec *codec; unsigned int format; + unsigned int bits; int ret; codec = dev_to_hda_codec(dai->dev); stream = substream->runtime->private_data; stream_info = snd_soc_dai_get_dma_data(dai, substream); - format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, - runtime->sample_bits, 0); + + bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, + stream_info->maxbps); + format = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream); if (ret < 0) { diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index d57b043d6bfe..d2117e36ddd1 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -52,6 +52,7 @@ static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count, stream->channels_max = pcm->stream[dir].channels_max; stream->rates = pcm->stream[dir].rates; stream->formats = pcm->stream[dir].formats; + stream->subformats = pcm->stream[dir].subformats; stream->sig_bits = pcm->stream[dir].maxbps; capture_dais: @@ -71,6 +72,7 @@ static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count, stream->channels_max = pcm->stream[dir].channels_max; stream->rates = pcm->stream[dir].rates; stream->formats = pcm->stream[dir].formats; + stream->subformats = pcm->stream[dir].subformats; stream->sig_bits = pcm->stream[dir].maxbps; } From 0bb0af123b0dbae3e3fad2166122777cf40abae4 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:03 +0100 Subject: [PATCH 1554/7721] ASoC: codecs: hdac_hda: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-10-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/codecs/hdac_hda.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 355f30779a34..0c589e46574d 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -215,18 +215,16 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, struct hdac_hda_priv *hda_pvt; unsigned int format_val; unsigned int maxbps; + unsigned int bits; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) maxbps = dai->driver->playback.sig_bits; else maxbps = dai->driver->capture.sig_bits; + bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, maxbps); hda_pvt = snd_soc_component_get_drvdata(component); - format_val = snd_hdac_calc_stream_format(params_rate(params), - params_channels(params), - params_format(params), - maxbps, - 0); + format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); if (!format_val) { dev_err(dai->dev, "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n", From cbc4ebb346162376377ee0a1074fc72d39cfbb51 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:04 +0100 Subject: [PATCH 1555/7721] ASoC: codecs: hdac_hdmi: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-11-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/codecs/hdac_hdmi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3e4f632d8665..b3b11225d483 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -468,13 +468,14 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; + unsigned int bits; int format; dai_map = &hdmi->dai_map[dai->id]; - format = snd_hdac_calc_stream_format(params_rate(hparams), - params_channels(hparams), params_format(hparams), - dai->driver->playback.sig_bits, 0); + bits = snd_hdac_stream_format_bits(params_format(hparams), SNDRV_PCM_SUBFORMAT_STD, + dai->driver->playback.sig_bits); + format = snd_hdac_stream_format(params_channels(hparams), bits, params_rate(hparams)); pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); if (!pcm) From 71fd0fbaf61e6d1a0ae63dc1845a1d7a193cd32b Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:05 +0100 Subject: [PATCH 1556/7721] ASoC: Intel Skylake: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-12-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl-pcm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index d0c02e8a6785..4d52e3b35850 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -127,6 +127,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) unsigned int format_val; struct hdac_stream *hstream; struct hdac_ext_stream *stream; + unsigned int bits; int err; hstream = snd_hdac_get_stream(bus, params->stream, @@ -137,8 +138,9 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) stream = stream_to_hdac_ext_stream(hstream); snd_hdac_ext_stream_decouple(bus, stream, true); - format_val = snd_hdac_calc_stream_format(params->s_freq, - params->ch, params->format, params->host_bps, 0); + bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, + params->host_bps); + format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params->s_freq, params->ch, params->format); @@ -165,6 +167,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) struct hdac_ext_stream *stream; struct hdac_ext_link *link; unsigned char stream_tag; + unsigned int bits; hstream = snd_hdac_get_stream(bus, params->stream, params->link_dma_id + 1); @@ -173,8 +176,10 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) stream = stream_to_hdac_ext_stream(hstream); snd_hdac_ext_stream_decouple(bus, stream, true); - format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, - params->format, params->link_bps, 0); + + bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, + params->link_bps); + format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params->s_freq, params->ch, params->format); From 176d13881137b064dc65e282e2c19821c11e60a2 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:06 +0100 Subject: [PATCH 1557/7721] ASoC: SOF: Intel: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-13-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda-dai-ops.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 87935554b1e4..55ce75db23e5 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -208,14 +208,16 @@ static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev, struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); unsigned int link_bps; unsigned int format_val; + unsigned int bits; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) link_bps = codec_dai->driver->playback.sig_bits; else link_bps = codec_dai->driver->capture.sig_bits; - format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), - params_format(params), link_bps, 0); + bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, + link_bps); + format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, params_rate(params), params_channels(params), params_format(params)); @@ -238,11 +240,11 @@ static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) { unsigned int format_val; + unsigned int bits; - format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), - params_format(params), - params_physical_width(params), - 0); + bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, + params_physical_width(params)); + format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, params_rate(params), params_channels(params), params_format(params)); @@ -258,6 +260,7 @@ static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, snd_pcm_format_t format; unsigned int channels; unsigned int width; + unsigned int bits; channels = params_channels(params); format = params_format(params); @@ -269,10 +272,8 @@ static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, width = 32; } - format_val = snd_hdac_calc_stream_format(params_rate(params), channels, - format, - width, - 0); + bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width); + format_val = snd_hdac_stream_format(channels, bits, params_rate(params)); dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, params_rate(params), channels, format); From 615d13cb4f3e499fb5c270a7db66917286f7d0ec Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:07 +0100 Subject: [PATCH 1558/7721] ASoC: Intel: avs: Switch to new stream-format interface To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-14-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/avs/loader.c | 4 ++-- sound/soc/intel/avs/path.c | 2 +- sound/soc/intel/avs/pcm.c | 19 ++++++++++++++----- sound/soc/intel/avs/probes.c | 3 +-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 65dd8f140fc1..e83ce6a35755 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -371,7 +371,7 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw) hstream = hdac_stream(estream); /* code loading performed with default format */ - sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0); + sdfmt = snd_hdac_stream_format(1, 32, 48000); ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab); if (ret < 0) goto release_stream; @@ -438,7 +438,7 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id) stream = hdac_stream(estream); /* code loading performed with default format */ - sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0); + sdfmt = snd_hdac_stream_format(1, 32, 48000); ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab); if (ret < 0) goto release_stream; diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index aa8b50b931c3..3aa16ee8d34c 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -87,7 +87,7 @@ static bool avs_test_hw_params(struct snd_pcm_hw_params *params, return (params_rate(params) == fmt->sampling_freq && params_channels(params) == fmt->num_channels && params_physical_width(params) == fmt->bit_depth && - params_width(params) == fmt->valid_bit_depth); + snd_pcm_hw_params_bits(params) == fmt->valid_bit_depth); } static struct avs_tplg_path * diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 463dbba18426..f586a804099a 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -335,20 +335,25 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct hdac_ext_stream *link_stream = runtime->private_data; + struct snd_soc_pcm_stream *stream_info; + struct hdac_ext_stream *link_stream; struct hdac_ext_link *link; struct hda_codec *codec; struct hdac_bus *bus; unsigned int format_val; + unsigned int bits; int ret; + link_stream = runtime->private_data; if (link_stream->link_prepared) return 0; codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); bus = &codec->bus->core; - format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, - runtime->sample_bits, 0); + stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); + bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, + stream_info->sig_bits); + format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); snd_hdac_ext_stream_reset(link_stream); snd_hdac_ext_stream_setup(link_stream, format_val); @@ -600,10 +605,12 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_stream *stream_info; struct avs_dma_data *data; struct avs_dev *adev = to_avs_dev(dai->dev); struct hdac_ext_stream *host_stream; unsigned int format_val; + unsigned int bits; int ret; data = snd_soc_dai_get_dma_data(dai, substream); @@ -614,8 +621,10 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so snd_hdac_stream_reset(hdac_stream(host_stream)); - format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, - runtime->sample_bits, 0); + stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); + bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, + stream_info->sig_bits); + format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); if (ret < 0) diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index bdc6b30dc009..817e543036f2 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -140,8 +140,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, bps = snd_pcm_format_physical_width(format); if (bps < 0) return bps; - format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out, - format, bps, 0); + format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate); ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); if (ret < 0) return ret; From dfd6ba6813dd0fdea54de58e7b80ca304ce3fca5 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:08 +0100 Subject: [PATCH 1559/7721] ALSA: hda: Drop snd_hdac_calc_stream_format() There are no users of the function. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-15-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 5 ---- sound/hda/hdac_device.c | 61 ----------------------------------------- 2 files changed, 66 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index b00c631c4053..62a3cd154ff2 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -145,11 +145,6 @@ unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subfor unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate); unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, unsigned int rate, unsigned short spdif_ctls); -unsigned int snd_hdac_calc_stream_format(unsigned int rate, - unsigned int channels, - snd_pcm_format_t format, - unsigned int maxbps, - unsigned short spdif_ctls); int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, u32 *subformatsp, unsigned int *bpsp); diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 556bd24f4014..7f7b67fe1b65 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -849,67 +849,6 @@ unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bi } EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format); -/** - * snd_hdac_calc_stream_format - calculate the format bitset - * @rate: the sample rate - * @channels: the number of channels - * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) - * @maxbps: the max. bps - * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) - * - * Calculate the format bitset from the given rate, channels and th PCM format. - * - * Return zero if invalid. - */ -unsigned int snd_hdac_calc_stream_format(unsigned int rate, - unsigned int channels, - snd_pcm_format_t format, - unsigned int maxbps, - unsigned short spdif_ctls) -{ - int i; - unsigned int val = 0; - - for (i = 0; rate_bits[i].hz; i++) - if (rate_bits[i].hz == rate) { - val = rate_bits[i].hda_fmt; - break; - } - if (!rate_bits[i].hz) - return 0; - - if (channels == 0 || channels > 8) - return 0; - val |= channels - 1; - - switch (snd_pcm_format_width(format)) { - case 8: - val |= AC_FMT_BITS_8; - break; - case 16: - val |= AC_FMT_BITS_16; - break; - case 20: - case 24: - case 32: - if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) - val |= AC_FMT_BITS_32; - else if (maxbps >= 24) - val |= AC_FMT_BITS_24; - else - val |= AC_FMT_BITS_20; - break; - default: - return 0; - } - - if (spdif_ctls & AC_DIG1_NONAUDIO) - val |= AC_FMT_TYPE_NON_PCM; - - return val; -} -EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format); - static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) { unsigned int val = 0; From c93c604e93af7f6085df5b7cad4d96f538ece68d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:09 +0100 Subject: [PATCH 1560/7721] ASoC: Intel: avs: Kill S24_LE format Eliminate all occurrences of S24_LE within PCM code, both HOST and LINK side. Replace those with MSBITS subformats to allow for granular selection when S32_LE is the format of choice. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-16-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/avs/pcm.c | 20 +++++++++++++++----- sound/soc/intel/avs/topology.c | 13 ++++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index f586a804099a..b6c48f88ca85 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -1073,8 +1073,10 @@ static const struct snd_pcm_hardware avs_pcm_hardware = { SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, .buffer_bytes_max = AZX_MAX_BUF_SIZE, .period_bytes_min = 128, .period_bytes_max = AZX_MAX_BUF_SIZE / 2, @@ -1225,8 +1227,10 @@ static const struct snd_soc_dai_driver i2s_dai_template = { .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, .capture = { .channels_min = 1, @@ -1234,8 +1238,10 @@ static const struct snd_soc_dai_driver i2s_dai_template = { .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }; @@ -1310,16 +1316,20 @@ static const struct snd_soc_dai_driver hda_cpu_dai = { .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, .capture = { .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }; diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index c74e9d622e4c..778236d3fd28 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1514,8 +1514,16 @@ static int avs_dai_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { - if (pcm) + u32 fe_subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | + SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX; + + if (pcm) { dai_drv->ops = &avs_dai_fe_ops; + dai_drv->capture.subformats = fe_subformats; + dai_drv->playback.subformats = fe_subformats; + } + return 0; } @@ -1534,6 +1542,9 @@ static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_s /* Open LINK (BE) pipes last and close them first to prevent xruns. */ link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE; link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE; + } else { + /* Do not ignore codec capabilities. */ + link->dpcm_merged_format = 1; } return 0; From f8ccb133c9866b17a44f8e1a2478beb1631a366d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:06:10 +0100 Subject: [PATCH 1561/7721] ASoC: Intel: avs: Unhardcode HDAudio BE DAI drivers description To not expose more than in fact is supported by the codec, update CPU DAI initialization procedure to rely on codec capabilities instead of hardcoding them. This includes subformat which is currently ignored. As capabilities for HDMI streams are initialized on PCM open, leave it as is for now. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-17-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/avs/pcm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index b6c48f88ca85..4dfc5a1ebb7c 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -17,6 +17,7 @@ #include "avs.h" #include "path.h" #include "topology.h" +#include "../../codecs/hda.h" struct avs_dma_data { struct avs_tplg_path_template *template; @@ -1406,6 +1407,15 @@ static int avs_component_hda_probe(struct snd_soc_component *component) ret = -ENOMEM; goto exit; } + + if (!hda_codec_is_display(codec)) { + dais[i].playback.formats = pcm->stream[0].formats; + dais[i].playback.subformats = pcm->stream[0].subformats; + dais[i].playback.rates = pcm->stream[0].rates; + dais[i].playback.channels_min = pcm->stream[0].channels_min; + dais[i].playback.channels_max = pcm->stream[0].channels_max; + dais[i].playback.sig_bits = pcm->stream[0].maxbps; + } } if (pcm->stream[1].substreams) { @@ -1416,6 +1426,15 @@ static int avs_component_hda_probe(struct snd_soc_component *component) ret = -ENOMEM; goto exit; } + + if (!hda_codec_is_display(codec)) { + dais[i].capture.formats = pcm->stream[1].formats; + dais[i].capture.subformats = pcm->stream[1].subformats; + dais[i].capture.rates = pcm->stream[1].rates; + dais[i].capture.channels_min = pcm->stream[1].channels_min; + dais[i].capture.channels_max = pcm->stream[1].channels_max; + dais[i].capture.sig_bits = pcm->stream[1].maxbps; + } } dai = snd_soc_register_dai(component, &dais[i], false); From ed99878462ccc143395987faebda33c50529b116 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 27 Nov 2023 15:34:48 +0200 Subject: [PATCH 1562/7721] ASoC: Intel: soc-acpi-intel-mtl-match: Add rt722 support This patch adds match table for rt722 codec on link 0. RT722 is a multi-function codec, three endpoints are created for its headset, amp and dmic functions. Signed-off-by: Chao Song Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127133448.18449-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-mtl-match.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 61f2b2645496..5a90ebdbf799 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -123,6 +123,31 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { }, }; +/* + * RT722 is a multi-function codec, three endpoints are created for + * its headset, amp and dmic functions. + */ +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_endpoint spk_2_endpoint = { .num = 0, .aggregated = 1, @@ -164,6 +189,15 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + static const struct snd_soc_acpi_adr_device rt713_0_single_adr[] = { { .adr = 0x000031025D071301ull, @@ -355,6 +389,15 @@ static const struct snd_soc_acpi_link_adr mtl_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = { { .mask = BIT(0), @@ -556,6 +599,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg", }, + { + .link_mask = BIT(0), + .links = mtl_rt722_only, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt722-l0.tplg", + }, { .link_mask = BIT(0), .links = mtl_rvp, From 9425039741e84120fc936fbb5a9a7a1410fd9409 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:28 +0200 Subject: [PATCH 1563/7721] ASoC: Intel: sof_ssp_amp: remove dead code This patch fixes a dead code problem when calculating BE ID for each HDMI-In link. Signed-off-by: Brent Lu Reviewed-by: Balamurugan C Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 137ba64254bc..22f37cf3a2ad 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -124,6 +124,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ fixed_be = true; + be_id = HDMI_IN_BE_ID; for (i = 1; i <= num_of_hdmi_ssp; i++) { int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> SOF_HDMI_CAPTURE_1_SSP_SHIFT : @@ -138,7 +139,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); if (!links[id].name) return NULL; - links[id].id = fixed_be ? (HDMI_IN_BE_ID + i - 1) : id; + links[id].id = be_id; links[id].codecs = &snd_soc_dummy_dlc; links[id].num_codecs = 1; links[id].platforms = platform_component; @@ -147,6 +148,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links[id].no_pcm = 1; links[id].num_cpus = 1; id++; + be_id++; } } From 06dea47be6d3d0ad3ef5f7c9dd0947d1c825e0ff Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 Nov 2023 17:26:29 +0200 Subject: [PATCH 1564/7721] ASoC: Intel: sof_maxim_common: add else between 2 if test if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) and if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) can't be true at the same time. Add an else to clarify it. Signed-off-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 3c00afc32805..f64124077ca7 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -67,8 +67,7 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { /* DEV0 tdm slot configuration */ snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { + } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* DEV1 tdm slot configuration */ snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); } From 007d9a638b877f71a0ef28a906525904e44f6aa2 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 Nov 2023 17:26:30 +0200 Subject: [PATCH 1565/7721] ASoC: Intel: sof_maxim_common: check return value snd_soc_dai_set_tdm_slot() could return error. Signed-off-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index f64124077ca7..cf2974718271 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -61,15 +61,21 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; + int ret = 0; int j; for_each_rtd_codec_dais(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { /* DEV0 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* DEV1 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + } + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; } } return 0; From 65b2df10a1e6264dd199c88623a9e4bbf8849c9b Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 27 Nov 2023 17:26:31 +0200 Subject: [PATCH 1566/7721] ASoC: Intel: cht_bsw_rt5672: check return value Set codec sysclk could fail and return error, add error check for it. Signed-off-by: Chao Song Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f6da24f3c466..8cf0b33cc02e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -93,8 +93,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, * when codec is runtime suspended. Codec needs clock for jack * detection and button press. */ - snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, - 48000 * 512, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "failed to set codec sysclk: %d\n", ret); + return ret; + } if (ctx->mclk) clk_disable_unprepare(ctx->mclk); From 93f74ebf3d7623b8b647d2ce5f2e23545f9702df Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:32 +0200 Subject: [PATCH 1567/7721] ASoC: Intel: ssp-common: get codec name function Add a helper function to get codec name string from codec type enum value. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_common.c | 21 +++++++++++++++++++++ sound/soc/intel/boards/sof_ssp_common.h | 1 + 2 files changed, 22 insertions(+) diff --git a/sound/soc/intel/boards/sof_ssp_common.c b/sound/soc/intel/boards/sof_ssp_common.c index 41a258e45a61..96072790e9c0 100644 --- a/sound/soc/intel/boards/sof_ssp_common.c +++ b/sound/soc/intel/boards/sof_ssp_common.c @@ -96,6 +96,27 @@ enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev) } EXPORT_SYMBOL_NS(sof_ssp_detect_amp_type, SND_SOC_INTEL_SOF_SSP_COMMON); +const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codecs); i++) { + if (codecs[i].codec_type != codec_type) + continue; + + return codecs[i].name; + } + for (i = 0; i < ARRAY_SIZE(amps); i++) { + if (amps[i].codec_type != codec_type) + continue; + + return amps[i].name; + } + + return NULL; +} +EXPORT_SYMBOL_NS(sof_ssp_get_codec_name, SND_SOC_INTEL_SOF_SSP_COMMON); + MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_ssp_common.h b/sound/soc/intel/boards/sof_ssp_common.h index e3fd6fb1db1c..6d827103479b 100644 --- a/sound/soc/intel/boards/sof_ssp_common.h +++ b/sound/soc/intel/boards/sof_ssp_common.h @@ -67,5 +67,6 @@ enum sof_ssp_codec { enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev); enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev); +const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type); #endif /* __SOF_SSP_COMMON_H */ From e111dece012f29707da634c341d3f3277bd94528 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:33 +0200 Subject: [PATCH 1568/7721] ASoC: Intel: board_helpers: support codec link initialization Add a helper function for machine drivers to initialize headphone codec DAI links. The function will initialize common fields and let caller to initialize codec-specific fields like codec, init, exit, and ops fields. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.c | 51 ++++++++++++++++++++++ sound/soc/intel/boards/sof_board_helpers.h | 6 +++ 2 files changed, 57 insertions(+) diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index ce2967850c2d..5ee53c781b37 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -3,6 +3,7 @@ // Copyright(c) 2023 Intel Corporation. All rights reserved. #include +#include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" #include "sof_board_helpers.h" @@ -86,6 +87,55 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; +int sof_intel_board_set_codec_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec codec_type, int ssp_codec) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: codec %s, ssp %d\n", be_id, + sof_ssp_get_codec_name(codec_type), ssp_codec); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + if (soc_intel_is_byt() || soc_intel_is_cht()) { + /* backward-compatibility for BYT/CHT boards */ + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", + ssp_codec); + } else { + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", + ssp_codec); + } + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + int sof_intel_board_set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, enum sof_dmic_be_type be_type) @@ -202,3 +252,4 @@ MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index df99f576c1d8..7392d639672d 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -30,6 +30,7 @@ struct sof_rt5682_private { * @amp_type: type of speaker amplifier * @dmic_be_num: number of Intel PCH DMIC BE link * @hdmi_num: number of Intel HDMI BE link + * @ssp_codec: ssp port number of headphone BE link * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { @@ -42,6 +43,8 @@ struct sof_card_private { int dmic_be_num; int hdmi_num; + int ssp_codec; + union { struct sof_rt5682_private rt5682; }; @@ -54,6 +57,9 @@ enum sof_dmic_be_type { int sof_intel_board_card_late_probe(struct snd_soc_card *card); +int sof_intel_board_set_codec_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec codec_type, int ssp_codec); int sof_intel_board_set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, enum sof_dmic_be_type be_type); From f46f07fe264a26daf8d6a5e16535229ee48108a7 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:34 +0200 Subject: [PATCH 1569/7721] ASoC: Intel: sof_cs42l42: use common module for codec link Use intel_board module for headphone codec DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_cs42l42.c | 60 ++++++++-------------------- 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 1f760fc4cab2..30e78c20ce6e 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -245,45 +245,6 @@ static int create_spk_amp_dai_links(struct device *dev, return ret; } -static int create_hp_codec_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, int ssp_codec) -{ - /* codec SSP */ - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", - ssp_codec); - if (!links[*id].name) - goto devm_err; - - links[*id].id = *id; - links[*id].codecs = cs42l42_component; - links[*id].num_codecs = ARRAY_SIZE(cs42l42_component); - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - links[*id].init = sof_cs42l42_init; - links[*id].exit = sof_cs42l42_exit; - links[*id].ops = &sof_cs42l42_ops; - links[*id].dpcm_playback = 1; - links[*id].dpcm_capture = 1; - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[*id].cpus->dai_name) - goto devm_err; - - (*id)++; - - return 0; - -devm_err: - return -ENOMEM; -} - static int create_bt_offload_dai_links(struct device *dev, struct snd_soc_dai_link *links, struct snd_soc_dai_link_component *cpus, @@ -350,12 +311,23 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, switch (link_type) { case LINK_HP: - ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec); - if (ret < 0) { + ret = sof_intel_board_set_codec_link(dev, &links[id], id, + CODEC_CS42L42, + ssp_codec); + if (ret) { dev_err(dev, "fail to create hp codec dai links, ret %d\n", ret); goto devm_err; } + + /* codec-specific fields */ + links[id].codecs = cs42l42_component; + links[id].num_codecs = ARRAY_SIZE(cs42l42_component); + links[id].init = sof_cs42l42_init; + links[id].exit = sof_cs42l42_exit; + links[id].ops = &sof_cs42l42_ops; + + id++; break; case LINK_SPK: ret = create_spk_amp_dai_links(dev, links, cpus, &id, @@ -440,7 +412,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_bt, ssp_amp, ssp_codec; + int ret, ssp_bt, ssp_amp; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -475,7 +447,7 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> SOF_CS42L42_SSP_AMP_SHIFT; - ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; + ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; /* compute number of dai links */ sof_audio_card_cs42l42.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; @@ -486,7 +458,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_cs42l42.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ssp_amp, ssp_bt, + ctx->ssp_codec, ssp_amp, ssp_bt, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) From 99f7422805c96d56a093dbe71beca658b793d0cb Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:35 +0200 Subject: [PATCH 1570/7721] ASoC: Intel: sof_nau8825: use common module for codec link Use intel_board module for headphone codec DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-9-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 29 ++++++++-------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index dc2821a012d4..3aeed23c8d0d 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -226,30 +226,17 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, goto devm_err; /* codec SSP */ - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_codec); - if (!links[id].name) - goto devm_err; + ret = sof_intel_board_set_codec_link(dev, &links[id], id, CODEC_NAU8825, + ssp_codec); + if (ret) + return NULL; - links[id].id = id; + /* codec-specific fields */ links[id].codecs = nau8825_component; links[id].num_codecs = ARRAY_SIZE(nau8825_component); - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_nau8825_codec_init; links[id].exit = sof_nau8825_codec_exit; links[id].ops = &sof_nau8825_ops; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; id++; @@ -368,7 +355,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp, ssp_codec; + int ret, ssp_amp; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -396,7 +383,7 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> SOF_NAU8825_SSP_AMP_SHIFT; - ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; + ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; /* compute number of dai links */ sof_audio_card_nau8825.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; @@ -408,7 +395,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_nau8825.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ssp_amp, + ctx->ssp_codec, ssp_amp, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) From 84c280af16b72fc202fbd9dcecadb6e256956c41 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:36 +0200 Subject: [PATCH 1571/7721] ASoC: Intel: sof_rt5682: use common module for codec link Use intel_board module for headphone codec DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-10-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 38 ++++++++--------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 9723479f43da..8adc82892e2c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -591,13 +591,12 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, goto devm_err; /* codec SSP */ - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_codec); - if (!links[id].name) - goto devm_err; - - links[id].id = id; + ret = sof_intel_board_set_codec_link(dev, &links[id], id, codec_type, + ssp_codec); + if (ret) + return NULL; + /* codec-specific fields */ switch (codec_type) { case CODEC_RT5650: links[id].codecs = &rt5650_components[0]; @@ -616,23 +615,11 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, return NULL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_rt5682_codec_init; links[id].exit = sof_rt5682_codec_exit; links[id].ops = &sof_rt5682_ops; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - } else { + + if (!is_legacy_cpu) { /* * Currently, On SKL+ platforms MCLK will be turned off in sof * runtime suspended, and it will go into runtime suspended @@ -643,11 +630,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, * It can be removed once we can control MCLK by driver. */ links[id].ignore_pmdown_time = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; } id++; @@ -819,7 +801,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp, ssp_codec; + int ret, ssp_amp; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -888,7 +870,7 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> SOF_RT5682_SSP_AMP_SHIFT; - ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; + ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; /* compute number of dai links */ sof_audio_card_rt5682.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; @@ -905,7 +887,7 @@ static int sof_audio_probe(struct platform_device *pdev) SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); dai_links = sof_card_dai_links_create(&pdev->dev, ctx->codec_type, - ctx->amp_type, ssp_codec, ssp_amp, + ctx->amp_type, ctx->ssp_codec, ssp_amp, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec, ctx->rt5682.is_legacy_cpu); From ba0c7c328762d78573d3cac4adad9ea9e695f244 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:37 +0200 Subject: [PATCH 1572/7721] ASoC: Intel: board_helpers: support amp link initialization Add a helper function for machine drivers to initialize speaker amplifier DAI link. The function will initialize common fields and let caller to initialize codec-specific fields like codec, init, exit, and ops fields. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-11-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.c | 42 ++++++++++++++++++++++ sound/soc/intel/boards/sof_board_helpers.h | 5 +++ 2 files changed, 47 insertions(+) diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 5ee53c781b37..515634db0a4d 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -248,6 +248,48 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev, } EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +int sof_intel_board_set_ssp_amp_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec amp_type, int ssp_amp) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id, + sof_ssp_get_codec_name(amp_type), ssp_amp); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index 7392d639672d..17922f3e17a5 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -31,6 +31,7 @@ struct sof_rt5682_private { * @dmic_be_num: number of Intel PCH DMIC BE link * @hdmi_num: number of Intel HDMI BE link * @ssp_codec: ssp port number of headphone BE link + * @ssp_amp: ssp port number of speaker BE link * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { @@ -44,6 +45,7 @@ struct sof_card_private { int hdmi_num; int ssp_codec; + int ssp_amp; union { struct sof_rt5682_private rt5682; @@ -66,5 +68,8 @@ int sof_intel_board_set_dmic_link(struct device *dev, int sof_intel_board_set_intel_hdmi_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, int hdmi_id, bool idisp_codec); +int sof_intel_board_set_ssp_amp_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec amp_type, int ssp_amp); #endif /* __SOF_INTEL_BOARD_HELPERS_H */ From 8739841805744bd1a1d12e2485dc5d0f1d880f64 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:38 +0200 Subject: [PATCH 1573/7721] ASoC: Intel: sof_cs42l42: use common module for amp link Use intel_board module for speaker amplifier DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-12-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_cs42l42.c | 98 +++++++++------------------- 1 file changed, 32 insertions(+), 66 deletions(-) diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 30e78c20ce6e..a8252079d696 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -189,62 +189,6 @@ static struct snd_soc_dai_link_component cs42l42_component[] = { } }; -static int create_spk_amp_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, enum sof_ssp_codec amp_type, - int ssp_amp) -{ - int ret = 0; - - /* speaker amp */ - if (amp_type == CODEC_NONE) - return 0; - - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", - ssp_amp); - if (!links[*id].name) { - ret = -ENOMEM; - goto devm_err; - } - - links[*id].id = *id; - - switch (amp_type) { - case CODEC_MAX98357A: - max_98357a_dai_link(&links[*id]); - break; - case CODEC_MAX98360A: - max_98360a_dai_link(&links[*id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return -EINVAL; - } - - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - links[*id].dpcm_playback = 1; - /* firmware-generated echo reference */ - links[*id].dpcm_capture = 1; - - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", ssp_amp); - if (!links[*id].cpus->dai_name) { - ret = -ENOMEM; - goto devm_err; - } - - (*id)++; - -devm_err: - return ret; -} - static int create_bt_offload_dai_links(struct device *dev, struct snd_soc_dai_link *links, struct snd_soc_dai_link_component *cpus, @@ -330,12 +274,33 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, id++; break; case LINK_SPK: - ret = create_spk_amp_dai_links(dev, links, cpus, &id, - amp_type, ssp_amp); - if (ret < 0) { - dev_err(dev, "fail to create spk amp dai links, ret %d\n", - ret); - goto devm_err; + if (amp_type != CODEC_NONE) { + ret = sof_intel_board_set_ssp_amp_link(dev, + &links[id], + id, + amp_type, + ssp_amp); + if (ret) { + dev_err(dev, "fail to create spk amp dai links, ret %d\n", + ret); + goto devm_err; + } + + /* codec-specific fields */ + switch (amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(&links[id]); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(&links[id]); + break; + default: + dev_err(dev, "invalid amp type %d\n", + amp_type); + goto devm_err; + } + + id++; } break; case LINK_DMIC: @@ -412,7 +377,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_bt, ssp_amp; + int ret, ssp_bt; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -444,7 +409,7 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> SOF_CS42L42_SSP_BT_SHIFT; - ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> + ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> SOF_CS42L42_SSP_AMP_SHIFT; ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; @@ -458,8 +423,9 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_cs42l42.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ctx->ssp_codec, ssp_amp, ssp_bt, - ctx->dmic_be_num, ctx->hdmi_num, + ctx->ssp_codec, ctx->ssp_amp, + ssp_bt, ctx->dmic_be_num, + ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) return -ENOMEM; From adf711655ba21c5d54d52b79aa8df87fbb39df6b Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:39 +0200 Subject: [PATCH 1574/7721] ASoC: Intel: sof_nau8825: use common module for amp link Use intel_board module for speaker amplifier DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-13-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 31 +++++++--------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 3aeed23c8d0d..cc2a11b3de97 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -273,13 +273,12 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, /* speaker amp */ if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_amp); - if (!links[id].name) - goto devm_err; - - links[id].id = id; + ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], id, + amp_type, ssp_amp); + if (ret) + return NULL; + /* codec-specific fields */ switch (amp_type) { case CODEC_MAX98360A: max_98360a_dai_link(&links[id]); @@ -304,20 +303,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, return NULL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback stream or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; id++; } @@ -355,7 +340,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -380,7 +365,7 @@ static int sof_audio_probe(struct platform_device *pdev) if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> + ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> SOF_NAU8825_SSP_AMP_SHIFT; ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; @@ -395,7 +380,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_nau8825.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ctx->ssp_codec, ssp_amp, + ctx->ssp_codec, ctx->ssp_amp, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) From e45cd972a50d2212ad232af33de970fb6923aaf6 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:40 +0200 Subject: [PATCH 1575/7721] ASoC: Intel: sof_rt5682: use common module for amp link Use intel_board module for speaker amplifier DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-14-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 43 +++++++---------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 8adc82892e2c..777d1db5c6ad 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -666,13 +666,12 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, /* speaker amp */ if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_amp); - if (!links[id].name) - goto devm_err; - - links[id].id = id; + ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], id, + amp_type, ssp_amp); + if (ret) + return NULL; + /* codec-specific fields */ switch (amp_type) { case CODEC_MAX98357A: max_98357a_dai_link(&links[id]); @@ -713,29 +712,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, return NULL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback stream or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - - } else { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - } id++; } @@ -801,7 +777,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -867,7 +843,7 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> + ctx->ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> SOF_RT5682_SSP_AMP_SHIFT; ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; @@ -887,8 +863,9 @@ static int sof_audio_probe(struct platform_device *pdev) SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); dai_links = sof_card_dai_links_create(&pdev->dev, ctx->codec_type, - ctx->amp_type, ctx->ssp_codec, ssp_amp, - ctx->dmic_be_num, ctx->hdmi_num, + ctx->amp_type, ctx->ssp_codec, + ctx->ssp_amp, ctx->dmic_be_num, + ctx->hdmi_num, ctx->hdmi.idisp_codec, ctx->rt5682.is_legacy_cpu); if (!dai_links) From 5cdc7a82594eaad27e98dcd6fbd72592edbc0f39 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:41 +0200 Subject: [PATCH 1576/7721] ASoC: Intel: sof_ssp_amp: use common module for amp link Use intel_board module for speaker amplifier DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-15-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 22f37cf3a2ad..8e478d1cc875 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -154,12 +154,13 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, /* codec SSP */ if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); - if (!links[id].name) + be_id = fixed_be ? SPK_BE_ID : id; + ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id, + amp_type, ssp_codec); + if (ret) return NULL; - links[id].id = fixed_be ? SPK_BE_ID : id; - + /* codec-specific fields */ switch (amp_type) { case CODEC_CS35L41: cs35l41_set_dai_link(&links[id]); @@ -172,18 +173,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, return NULL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback from amplifier or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec); - if (!links[id].cpus->dai_name) - return NULL; - id++; } @@ -256,7 +245,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_codec; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -272,7 +261,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) else ctx->dmic_be_num = 0; - ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; + ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; /* set number of dai links */ sof_ssp_amp_card.num_links = ctx->dmic_be_num; @@ -303,7 +292,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) sof_ssp_amp_card.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ctx->dmic_be_num, + ctx->ssp_amp, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) From 823404815fcdf32950b2223ed2c665f077d6b98f Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:42 +0200 Subject: [PATCH 1577/7721] ASoC: Intel: sof_ssp_amp: rename function parameter Rename the parameter 'ssp_codec' of sof_card_dai_links_create() since it's the port number of speaker amplifier. No functional change in this commit. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-16-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 8e478d1cc875..c463bc698c10 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -98,7 +98,7 @@ static struct snd_soc_dai_link_component platform_component[] = { static struct snd_soc_dai_link * sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_codec, int dmic_be_num, int hdmi_num, + int ssp_amp, int dmic_be_num, int hdmi_num, bool idisp_codec) { struct snd_soc_dai_link_component *cpus; @@ -156,7 +156,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, if (amp_type != CODEC_NONE) { be_id = fixed_be ? SPK_BE_ID : id; ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id, - amp_type, ssp_codec); + amp_type, ssp_amp); if (ret) return NULL; From 53d8df6d3f0a1d6fd520865fb12c11868fe6cf81 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:43 +0200 Subject: [PATCH 1578/7721] ASoC: Intel: board_helpers: support BT offload link initialization Add a helper function for machine drivers to initialize BT offload DAI link. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-17-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.c | 43 ++++++++++++++++++++++ sound/soc/intel/boards/sof_board_helpers.h | 8 ++++ 2 files changed, 51 insertions(+) diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 515634db0a4d..335c660561d5 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -290,6 +290,49 @@ int sof_intel_board_set_ssp_amp_link(struct device *dev, } EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +int sof_intel_board_set_bt_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_bt) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index 17922f3e17a5..49a7bfa12a6d 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -32,6 +32,8 @@ struct sof_rt5682_private { * @hdmi_num: number of Intel HDMI BE link * @ssp_codec: ssp port number of headphone BE link * @ssp_amp: ssp port number of speaker BE link + * @ssp_bt: ssp port number of BT offload BE link + * @bt_offload_present: true to create BT offload BE link * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { @@ -46,6 +48,9 @@ struct sof_card_private { int ssp_codec; int ssp_amp; + int ssp_bt; + + bool bt_offload_present; union { struct sof_rt5682_private rt5682; @@ -71,5 +76,8 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev, int sof_intel_board_set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, enum sof_ssp_codec amp_type, int ssp_amp); +int sof_intel_board_set_bt_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_bt); #endif /* __SOF_INTEL_BOARD_HELPERS_H */ From 117445d7655945b0a601a1247842029d0325c7e4 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:44 +0200 Subject: [PATCH 1579/7721] ASoC: Intel: sof_cs42l42: use common module for BT offload link Use intel_board module for BT offload DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-18-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_cs42l42.c | 79 +++++++--------------------- 1 file changed, 19 insertions(+), 60 deletions(-) diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index a8252079d696..c2442bf8ced0 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -138,13 +138,6 @@ static const struct snd_soc_ops sof_cs42l42_ops = { .hw_params = sof_cs42l42_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { return sof_intel_board_card_late_probe(card); @@ -189,52 +182,11 @@ static struct snd_soc_dai_link_component cs42l42_component[] = { } }; -static int create_bt_offload_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, int ssp_bt) -{ - /* bt offload */ - if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)) - return 0; - - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", - ssp_bt); - if (!links[*id].name) - goto devm_err; - - links[*id].id = *id; - links[*id].codecs = &snd_soc_dummy_dlc; - links[*id].num_codecs = 1; - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - - links[*id].dpcm_playback = 1; - links[*id].dpcm_capture = 1; - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_bt); - if (!links[*id].cpus->dai_name) - goto devm_err; - - (*id)++; - - return 0; - -devm_err: - return -ENOMEM; -} - static struct snd_soc_dai_link * sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int ssp_codec, int ssp_amp, int ssp_bt, int dmic_be_num, int hdmi_num, bool idisp_codec) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int ret; int id = 0; @@ -243,9 +195,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) goto devm_err; link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT; @@ -350,11 +300,17 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, } break; case LINK_BT: - ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt); - if (ret < 0) { - dev_err(dev, "fail to create bt offload dai links, ret %d\n", - ret); - goto devm_err; + if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) { + ret = sof_intel_board_set_bt_link(dev, + &links[id], id, + ssp_bt); + if (ret) { + dev_err(dev, "fail to create bt offload dai links, ret %d\n", + ret); + goto devm_err; + } + + id++; } break; case LINK_NONE: @@ -377,7 +333,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_bt; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -406,7 +362,8 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); - ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> SOF_CS42L42_SSP_BT_SHIFT; ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> @@ -419,12 +376,14 @@ static int sof_audio_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_audio_card_cs42l42.num_links++; - if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) + if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_audio_card_cs42l42.num_links++; + } dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, ctx->ssp_codec, ctx->ssp_amp, - ssp_bt, ctx->dmic_be_num, + ctx->ssp_bt, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) From 87ddfdc9dc37032492704b51ab468bda1262d155 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:45 +0200 Subject: [PATCH 1580/7721] ASoC: Intel: sof_nau8825: use common module for BT offload link Use intel_board module for BT offload DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-19-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 42 +++++++++------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index cc2a11b3de97..32a43d1b5846 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -138,13 +138,6 @@ static struct snd_soc_ops sof_nau8825_ops = { .hw_params = sof_nau8825_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); @@ -212,7 +205,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int ssp_codec, int ssp_amp, int dmic_be_num, int hdmi_num, bool idisp_codec) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i; int id = 0; @@ -220,9 +212,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) goto devm_err; /* codec SSP */ @@ -311,23 +301,11 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); + if (ret) + return NULL; + + id++; } return links; @@ -365,6 +343,10 @@ static int sof_audio_probe(struct platform_device *pdev) if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> SOF_NAU8825_SSP_AMP_SHIFT; @@ -376,8 +358,10 @@ static int sof_audio_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_audio_card_nau8825.num_links++; - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_audio_card_nau8825.num_links++; + } dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, ctx->ssp_codec, ctx->ssp_amp, From 3d5b77b9bee016cd1363f3856a3616eaed9026b8 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:46 +0200 Subject: [PATCH 1581/7721] ASoC: Intel: sof_rt5682: use common module for BT offload link Use intel_board module for BT offload DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-20-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 30 ++++++++++++----------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 777d1db5c6ad..22dd85129a51 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -720,23 +720,11 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); + if (ret) + return NULL; + + id++; } /* HDMI-In SSP */ @@ -843,6 +831,10 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + ctx->ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> SOF_RT5682_SSP_AMP_SHIFT; @@ -854,8 +846,10 @@ static int sof_audio_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_audio_card_rt5682.num_links++; - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_audio_card_rt5682.num_links++; + } if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) sof_audio_card_rt5682.num_links += From dc3d7dcb04eae6af5b9c882dc30eede75bbd7fe7 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:47 +0200 Subject: [PATCH 1582/7721] ASoC: Intel: sof_ssp_amp: use common module for BT offload link Use intel_board module for BT offload DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-21-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 31 ++++++++++------------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index c463bc698c10..72505f6a6501 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -215,29 +215,14 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); + if (ret) + return NULL; + id++; } return links; -devm_err: - return NULL; } static int sof_ssp_amp_probe(struct platform_device *pdev) @@ -261,6 +246,10 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) else ctx->dmic_be_num = 0; + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; /* set number of dai links */ @@ -288,8 +277,10 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) ctx->hdmi_num = 0; } - if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_ssp_amp_card.num_links++; + } dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, ctx->ssp_amp, ctx->dmic_be_num, From 9fadbf3f11c378fa307517f20bd793eb9773a15e Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:48 +0200 Subject: [PATCH 1583/7721] ASoC: Intel: sof_ssp_amp: simplify HDMI-In quirks Use bit mask to handle SSP port number of HDMI-In devices to simplify the code. No functional change in this patch. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Balamurugan C Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-22-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 70 +++++++++++----------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 72505f6a6501..eddefa69355d 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -27,21 +27,10 @@ #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) /* HDMI capture*/ -#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4) -#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5 -#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5)) -#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ - (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) - -#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 -#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) -#define SOF_HDMI_CAPTURE_1_SSP(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) - -#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 -#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) -#define SOF_HDMI_CAPTURE_2_SSP(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) +#define SOF_HDMI_CAPTURE_SSP_MASK_SHIFT 4 +#define SOF_HDMI_CAPTURE_SSP_MASK_MASK (GENMASK(9, 4)) +#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_MASK) /* HDMI playback */ #define SOF_HDMI_PLAYBACK_PRESENT BIT(13) @@ -108,6 +97,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int ret; bool fixed_be = false; int be_id; + unsigned long ssp_mask_hdmi_in; links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -117,20 +107,17 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, return NULL; /* HDMI-In SSP */ - if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { - int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> + SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; + + if (ssp_mask_hdmi_in) { + int port = 0; /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ fixed_be = true; be_id = HDMI_IN_BE_ID; - for (i = 1; i <= num_of_hdmi_ssp; i++) { - int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> - SOF_HDMI_CAPTURE_1_SSP_SHIFT : - (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> - SOF_HDMI_CAPTURE_2_SSP_SHIFT); - + for_each_set_bit(port, &ssp_mask_hdmi_in, 32) { links[id].cpus = &cpus[id]; links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); @@ -231,6 +218,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; + unsigned long ssp_mask_hdmi_in; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -246,7 +234,10 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) else ctx->dmic_be_num = 0; - /* port number of peripherals attached to ssp interface */ + /* port number/mask of peripherals attached to ssp interface */ + ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> + SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; + ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; @@ -258,9 +249,8 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_ssp_amp_card.num_links++; - if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) - sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + if (ssp_mask_hdmi_in) + sof_ssp_amp_card.num_links += hweight32(ssp_mask_hdmi_in); if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> @@ -325,10 +315,8 @@ static const struct platform_device_id board_ids[] = { { .name = "tgl_rt1308_hdmi_ssp", .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | - SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(1) | - SOF_HDMI_CAPTURE_2_SSP(5) | - SOF_SSP_HDMI_CAPTURE_PRESENT), + SOF_HDMI_CAPTURE_SSP_MASK(0x22)), + /* SSP 1 and SSP 5 are used for HDMI IN */ }, { .name = "adl_cs35l41", @@ -340,28 +328,22 @@ static const struct platform_device_id board_ids[] = { }, { .name = "adl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "rpl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "mtl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, From f7c015add5b1a6a94fb39420ac0a885c8d7b63ad Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:49 +0200 Subject: [PATCH 1584/7721] ASoC: Intel: board_helpers: support HDMI-In link initialization Add a helper function for machine drivers to initialize HDMI-In DAI link. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Balamurugan C Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-23-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.c | 42 ++++++++++++++++++++++ sound/soc/intel/boards/sof_board_helpers.h | 5 +++ 2 files changed, 47 insertions(+) diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 335c660561d5..a1dba1f45669 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -333,6 +333,48 @@ int sof_intel_board_set_bt_link(struct device *dev, } EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +int sof_intel_board_set_hdmi_in_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_hdmi) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index 49a7bfa12a6d..a4bae62a4ed5 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -33,6 +33,7 @@ struct sof_rt5682_private { * @ssp_codec: ssp port number of headphone BE link * @ssp_amp: ssp port number of speaker BE link * @ssp_bt: ssp port number of BT offload BE link + * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link * @bt_offload_present: true to create BT offload BE link * @rt5682: private data for rt5682 machine driver */ @@ -49,6 +50,7 @@ struct sof_card_private { int ssp_codec; int ssp_amp; int ssp_bt; + unsigned long ssp_mask_hdmi_in; bool bt_offload_present; @@ -79,5 +81,8 @@ int sof_intel_board_set_ssp_amp_link(struct device *dev, int sof_intel_board_set_bt_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, int ssp_bt); +int sof_intel_board_set_hdmi_in_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_hdmi); #endif /* __SOF_INTEL_BOARD_HELPERS_H */ From 426cbd0de2da2553de9c8a2366f956807f94d5b4 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:50 +0200 Subject: [PATCH 1585/7721] ASoC: Intel: sof_rt5682: use common module for HDMI-In link Use intel_board module for HDMI-In DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Balamurugan C Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-24-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 37 +++++++---------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 22dd85129a51..d353ad758c60 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -463,13 +463,6 @@ static struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); @@ -576,18 +569,14 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, int ssp_amp, int dmic_be_num, int hdmi_num, bool idisp_codec, bool is_legacy_cpu) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i; int id = 0; int ret; - int hdmi_id_offset = 0; links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) goto devm_err; /* codec SSP */ @@ -735,22 +724,11 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, int port = 0; for_each_set_bit(port, &hdmi_in_ssp, 32) { - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) + ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], + id, port); + if (ret) return NULL; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); - if (!links[id].name) - return NULL; - links[id].id = id + hdmi_id_offset; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + id++; } } @@ -831,7 +809,10 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - /* port number of peripherals attached to ssp interface */ + /* port number/mask of peripherals attached to ssp interface */ + ctx->ssp_mask_hdmi_in = (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; From ee2486d5219e9f724372084d5926070697e84836 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:51 +0200 Subject: [PATCH 1586/7721] ASoC: Intel: sof_ssp_amp: use common module for HDMI-In link Use intel_board module for HDMI-In DAI link initialization. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Balamurugan C Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-25-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 38 ++++++---------------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index eddefa69355d..ee2e813bf4c0 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -71,13 +71,6 @@ static struct snd_soc_card sof_ssp_amp_card = { .late_probe = sof_card_late_probe, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ #define HDMI_IN_BE_ID 0 #define SPK_BE_ID 2 @@ -90,7 +83,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int ssp_amp, int dmic_be_num, int hdmi_num, bool idisp_codec) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i; int id = 0; @@ -101,9 +93,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) return NULL; /* HDMI-In SSP */ @@ -118,22 +108,11 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, be_id = HDMI_IN_BE_ID; for_each_set_bit(port, &ssp_mask_hdmi_in, 32) { - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) + ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], + be_id, port); + if (ret) return NULL; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); - if (!links[id].name) - return NULL; - links[id].id = be_id; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + id++; be_id++; } @@ -218,7 +197,6 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; - unsigned long ssp_mask_hdmi_in; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -235,7 +213,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) ctx->dmic_be_num = 0; /* port number/mask of peripherals attached to ssp interface */ - ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> + ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> @@ -249,8 +227,8 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_ssp_amp_card.num_links++; - if (ssp_mask_hdmi_in) - sof_ssp_amp_card.num_links += hweight32(ssp_mask_hdmi_in); + if (ctx->ssp_mask_hdmi_in) + sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in); if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> From a6881210f175ae309721b3c76f54eebc8a258339 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:52 +0200 Subject: [PATCH 1587/7721] ASoC: Intel: board_helpers: support DAI link array generation Add a helper function for machine drivers to initialize dai_link and num_links of a snd_soc_card structure. Machine driver needs to initialize sof_card_private structure in driver probe function then board_helpers module will create entire DAI link array for this board. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-26-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_board_helpers.c | 152 +++++++++++++++++++++ sound/soc/intel/boards/sof_board_helpers.h | 7 + 2 files changed, 159 insertions(+) diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index a1dba1f45669..4f2cb8e52971 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -375,6 +375,158 @@ int sof_intel_board_set_hdmi_in_link(struct device *dev, } EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +static int calculate_num_links(struct sof_card_private *ctx) +{ + int num_links = 0; + + /* headphone codec */ + if (ctx->codec_type != CODEC_NONE) + num_links++; + + /* dmic01 and dmic16k */ + if (ctx->dmic_be_num > 0) + num_links++; + + if (ctx->dmic_be_num > 1) + num_links++; + + /* idisp HDMI */ + num_links += ctx->hdmi_num; + + /* speaker amp */ + if (ctx->amp_type != CODEC_NONE) + num_links++; + + /* BT audio offload */ + if (ctx->bt_offload_present) + num_links++; + + /* HDMI-In */ + num_links += hweight32(ctx->ssp_mask_hdmi_in); + + return num_links; +} + +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + struct snd_soc_dai_link *links; + int num_links; + int i; + int idx = 0; + int ret; + int ssp_hdmi_in = 0; + + num_links = calculate_num_links(ctx); + + links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), + GFP_KERNEL); + if (!links) + return -ENOMEM; + + /* headphone codec */ + if (ctx->codec_type != CODEC_NONE) { + ret = sof_intel_board_set_codec_link(dev, &links[idx], idx, + ctx->codec_type, + ctx->ssp_codec); + if (ret) { + dev_err(dev, "fail to set codec link, ret %d\n", ret); + return ret; + } + + ctx->codec_link = &links[idx]; + idx++; + } + + /* dmic01 and dmic16k */ + if (ctx->dmic_be_num > 0) { + /* at least we have dmic01 */ + ret = sof_intel_board_set_dmic_link(dev, &links[idx], idx, + SOF_DMIC_01); + if (ret) { + dev_err(dev, "fail to set dmic01 link, ret %d\n", ret); + return ret; + } + + idx++; + } + + if (ctx->dmic_be_num > 1) { + /* set up 2 BE links at most */ + ret = sof_intel_board_set_dmic_link(dev, &links[idx], idx, + SOF_DMIC_16K); + if (ret) { + dev_err(dev, "fail to set dmic16k link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* idisp HDMI */ + for (i = 1; i <= ctx->hdmi_num; i++) { + ret = sof_intel_board_set_intel_hdmi_link(dev, &links[idx], idx, + i, + ctx->hdmi.idisp_codec); + if (ret) { + dev_err(dev, "fail to set hdmi link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* speaker amp */ + if (ctx->amp_type != CODEC_NONE) { + ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx], idx, + ctx->amp_type, + ctx->ssp_amp); + if (ret) { + dev_err(dev, "fail to set amp link, ret %d\n", ret); + return ret; + } + + ctx->amp_link = &links[idx]; + idx++; + } + + /* BT audio offload */ + if (ctx->bt_offload_present) { + ret = sof_intel_board_set_bt_link(dev, &links[idx], idx, + ctx->ssp_bt); + if (ret) { + dev_err(dev, "fail to set bt link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* HDMI-In */ + for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { + ret = sof_intel_board_set_hdmi_in_link(dev, &links[idx], idx, + ssp_hdmi_in); + if (ret) { + dev_err(dev, "fail to set hdmi-in link, ret %d\n", ret); + return ret; + } + + idx++; + } + + if (idx != num_links) { + dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx, + num_links); + return -EINVAL; + } + + card->dai_link = links; + card->num_links = num_links; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index a4bae62a4ed5..3b36058118ca 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -35,6 +35,8 @@ struct sof_rt5682_private { * @ssp_bt: ssp port number of BT offload BE link * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link * @bt_offload_present: true to create BT offload BE link + * @codec_link: pointer to headset codec dai link + * @amp_link: pointer to speaker amplifier dai link * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { @@ -54,6 +56,9 @@ struct sof_card_private { bool bt_offload_present; + struct snd_soc_dai_link *codec_link; + struct snd_soc_dai_link *amp_link; + union { struct sof_rt5682_private rt5682; }; @@ -65,6 +70,8 @@ enum sof_dmic_be_type { }; int sof_intel_board_card_late_probe(struct snd_soc_card *card); +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx); int sof_intel_board_set_codec_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, From 5da85a3523b5acd3a00347cae32ae2ffe4f4ac8a Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:53 +0200 Subject: [PATCH 1588/7721] ASoC: Intel: sof_nau8825: use common module for DAI link generation Use intel_board module to generate DAI link array and update num_links field in snd_soc_card structure. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-27-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 166 ++++++++------------------- 1 file changed, 49 insertions(+), 117 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 32a43d1b5846..15ea6732ff94 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -200,123 +200,67 @@ static struct snd_soc_dai_link_component nau8825_component[] = { } }; -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_codec, int ssp_amp, int dmic_be_num, - int hdmi_num, bool idisp_codec) +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) { - struct snd_soc_dai_link *links; - int i; - int id = 0; int ret; - links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - if (!links) - goto devm_err; - - /* codec SSP */ - ret = sof_intel_board_set_codec_link(dev, &links[id], id, CODEC_NAU8825, - ssp_codec); + ret = sof_intel_board_set_dai_link(dev, card, ctx); if (ret) - return NULL; + return ret; - /* codec-specific fields */ - links[id].codecs = nau8825_component; - links[id].num_codecs = ARRAY_SIZE(nau8825_component); - links[id].init = sof_nau8825_codec_init; - links[id].exit = sof_nau8825_codec_exit; - links[id].ops = &sof_nau8825_ops; - - id++; - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; } - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_16K); - if (ret) - return NULL; + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = nau8825_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component); + ctx->codec_link->init = sof_nau8825_codec_init; + ctx->codec_link->exit = sof_nau8825_codec_exit; + ctx->codec_link->ops = &sof_nau8825_ops; - id++; + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* HDMI */ - for (i = 1; i <= hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], id, - i, idisp_codec); - if (ret) - return NULL; - - id++; + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + ctx->amp_link->codecs = max_98373_components; + ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); + ctx->amp_link->init = max_98373_spk_codec_init; + ctx->amp_link->ops = &max_98373_ops; + break; + case CODEC_NAU8318: + nau8318_set_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - /* speaker amp */ - if (amp_type != CODEC_NONE) { - ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], id, - amp_type, ssp_amp); - if (ret) - return NULL; - - /* codec-specific fields */ - switch (amp_type) { - case CODEC_MAX98360A: - max_98360a_dai_link(&links[id]); - break; - case CODEC_MAX98373: - links[id].codecs = max_98373_components; - links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max_98373_spk_codec_init; - links[id].ops = &max_98373_ops; - break; - case CODEC_NAU8318: - nau8318_set_dai_link(&links[id]); - break; - case CODEC_RT1015P: - sof_rt1015p_dai_link(&links[id]); - break; - case CODEC_RT1019P: - sof_rt1019p_dai_link(&links[id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - - id++; - } - - /* BT audio offload */ - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); - if (ret) - return NULL; - - id++; - } - - return links; -devm_err: - return NULL; + return 0; } static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; @@ -352,25 +296,13 @@ static int sof_audio_probe(struct platform_device *pdev) ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; - /* compute number of dai links */ - sof_audio_card_nau8825.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; - - if (ctx->amp_type != CODEC_NONE) - sof_audio_card_nau8825.num_links++; - - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) ctx->bt_offload_present = true; - sof_audio_card_nau8825.num_links++; - } - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ctx->ssp_codec, ctx->ssp_amp, - ctx->dmic_be_num, ctx->hdmi_num, - ctx->hdmi.idisp_codec); - if (!dai_links) - return -ENOMEM; - - sof_audio_card_nau8825.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); + if (ret) + return ret; /* update codec_conf */ switch (ctx->amp_type) { From 8fa1116e1cae4858ab69d31da36f1fae9113c29d Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 Nov 2023 17:26:54 +0200 Subject: [PATCH 1589/7721] ASoC: Intel: sof_rt5682: use common module for DAI link generation Use intel_board module to generate DAI link array and update num_links field in snd_soc_card structure. Signed-off-by: Brent Lu Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231127152654.28204-28-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 256 +++++++++------------------- 1 file changed, 82 insertions(+), 174 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index d353ad758c60..cd50f26d1edb 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -563,52 +563,45 @@ static struct snd_soc_dai_link_component rt5650_components[] = { } }; -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, - enum sof_ssp_codec amp_type, int ssp_codec, - int ssp_amp, int dmic_be_num, int hdmi_num, - bool idisp_codec, bool is_legacy_cpu) +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) { - struct snd_soc_dai_link *links; - int i; - int id = 0; int ret; - links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - if (!links) - goto devm_err; - - /* codec SSP */ - ret = sof_intel_board_set_codec_link(dev, &links[id], id, codec_type, - ssp_codec); + ret = sof_intel_board_set_dai_link(dev, card, ctx); if (ret) - return NULL; + return ret; - /* codec-specific fields */ - switch (codec_type) { - case CODEC_RT5650: - links[id].codecs = &rt5650_components[0]; - links[id].num_codecs = 1; - break; - case CODEC_RT5682: - links[id].codecs = rt5682_component; - links[id].num_codecs = ARRAY_SIZE(rt5682_component); - break; - case CODEC_RT5682S: - links[id].codecs = rt5682s_component; - links[id].num_codecs = ARRAY_SIZE(rt5682s_component); - break; - default: - dev_err(dev, "invalid codec type %d\n", codec_type); - return NULL; + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; } - links[id].init = sof_rt5682_codec_init; - links[id].exit = sof_rt5682_codec_exit; - links[id].ops = &sof_rt5682_ops; + /* codec-specific fields for headphone codec */ + switch (ctx->codec_type) { + case CODEC_RT5650: + ctx->codec_link->codecs = &rt5650_components[0]; + ctx->codec_link->num_codecs = 1; + break; + case CODEC_RT5682: + ctx->codec_link->codecs = rt5682_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682_component); + break; + case CODEC_RT5682S: + ctx->codec_link->codecs = rt5682s_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682s_component); + break; + default: + dev_err(dev, "invalid codec type %d\n", ctx->codec_type); + return -EINVAL; + } - if (!is_legacy_cpu) { + ctx->codec_link->init = sof_rt5682_codec_init; + ctx->codec_link->exit = sof_rt5682_codec_exit; + ctx->codec_link->ops = &sof_rt5682_ops; + + if (!ctx->rt5682.is_legacy_cpu) { /* * Currently, On SKL+ platforms MCLK will be turned off in sof * runtime suspended, and it will go into runtime suspended @@ -618,130 +611,64 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, * avoid the noise. * It can be removed once we can control MCLK by driver. */ - links[id].ignore_pmdown_time = 1; - } - id++; - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; + ctx->codec_link->ignore_pmdown_time = 1; } - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_16K); - if (ret) - return NULL; + if (ctx->amp_type == CODEC_NONE) + return 0; - id++; + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* HDMI */ - for (i = 1; i <= hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], id, - i, idisp_codec); - if (ret) - return NULL; - - id++; + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + ctx->amp_link->codecs = max_98373_components; + ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); + ctx->amp_link->init = max_98373_spk_codec_init; + ctx->amp_link->ops = &max_98373_ops; + break; + case CODEC_MAX98390: + max_98390_dai_link(dev, ctx->amp_link); + break; + case CODEC_RT1011: + sof_rt1011_dai_link(ctx->amp_link); + break; + case CODEC_RT1015: + sof_rt1015_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + case CODEC_RT5650: + /* use AIF2 to support speaker pipeline */ + ctx->amp_link->codecs = &rt5650_components[1]; + ctx->amp_link->num_codecs = 1; + ctx->amp_link->init = rt5650_spk_init; + ctx->amp_link->ops = &sof_rt5682_ops; + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - /* speaker amp */ - if (amp_type != CODEC_NONE) { - ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], id, - amp_type, ssp_amp); - if (ret) - return NULL; - - /* codec-specific fields */ - switch (amp_type) { - case CODEC_MAX98357A: - max_98357a_dai_link(&links[id]); - break; - case CODEC_MAX98360A: - max_98360a_dai_link(&links[id]); - break; - case CODEC_MAX98373: - links[id].codecs = max_98373_components; - links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max_98373_spk_codec_init; - links[id].ops = &max_98373_ops; - break; - case CODEC_MAX98390: - max_98390_dai_link(dev, &links[id]); - break; - case CODEC_RT1011: - sof_rt1011_dai_link(&links[id]); - break; - case CODEC_RT1015: - sof_rt1015_dai_link(&links[id]); - break; - case CODEC_RT1015P: - sof_rt1015p_dai_link(&links[id]); - break; - case CODEC_RT1019P: - sof_rt1019p_dai_link(&links[id]); - break; - case CODEC_RT5650: - /* use AIF2 to support speaker pipeline */ - links[id].codecs = &rt5650_components[1]; - links[id].num_codecs = 1; - links[id].init = rt5650_spk_init; - links[id].ops = &sof_rt5682_ops; - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - - id++; - } - - /* BT audio offload */ - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); - if (ret) - return NULL; - - id++; - } - - /* HDMI-In SSP */ - if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) { - unsigned long hdmi_in_ssp = (sof_rt5682_quirk & - SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; - int port = 0; - - for_each_set_bit(port, &hdmi_in_ssp, 32) { - ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], - id, port); - if (ret) - return NULL; - - id++; - } - } - - return links; -devm_err: - return NULL; + return 0; } static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; @@ -821,32 +748,13 @@ static int sof_audio_probe(struct platform_device *pdev) ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; - /* compute number of dai links */ - sof_audio_card_rt5682.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; - - if (ctx->amp_type != CODEC_NONE) - sof_audio_card_rt5682.num_links++; - - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) ctx->bt_offload_present = true; - sof_audio_card_rt5682.num_links++; - } - if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) - sof_audio_card_rt5682.num_links += - hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); - - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->codec_type, - ctx->amp_type, ctx->ssp_codec, - ctx->ssp_amp, ctx->dmic_be_num, - ctx->hdmi_num, - ctx->hdmi.idisp_codec, - ctx->rt5682.is_legacy_cpu); - if (!dai_links) - return -ENOMEM; - - sof_audio_card_rt5682.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); + if (ret) + return ret; /* update codec_conf */ switch (ctx->amp_type) { From e620d2450636a0d90c341a73c64d4ba10b6e4dd1 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 25 Oct 2023 16:59:37 +0200 Subject: [PATCH 1590/7721] i40e: Delete unused and useless i40e_pf fields Removed fields: .fc_autoneg_status Since commit c56999f94876 ("i40e/i40evf: Add set_fc and init of FC settings") write-only and otherwise unused .eeprom_version Write-only and otherwise unused .atr_sample_rate Has only one possible value (I40E_DEFAULT_ATR_SAMPLE_RATE). Remove it and replace its occurrences by I40E_DEFAULT_ATR_SAMPLE_RATE .adminq_work_limit Has only one possible value (I40E_AQ_WORK_LIMIT). Remove it and replace its occurrences by I40E_AQ_WORK_LIMIT .tx_sluggish_count Unused, never written .pf_seid Used to store VSI downlink seid and it is referenced only once in the same codepath. There is no need to save it into i40e_pf. Remove it and use downlink_seid directly in the mentioned log message. .instance Write only. Remove it as well as ugly static local variable 'pfs_found' in i40e_probe. .int_policy .switch_kobj .ptp_pps_work .ptp_extts1_work .ptp_pps_start .pps_delay .ptp_pin .override_q_count All these unused at all Prior the patch: pahole -Ci40e_pf drivers/net/ethernet/intel/i40e/i40e.ko | tail -5 /* size: 5368, cachelines: 84, members: 127 */ /* sum members: 5297, holes: 20, sum holes: 71 */ /* paddings: 6, sum paddings: 19 */ /* last cacheline: 56 bytes */ }; After the patch: pahole -Ci40e_pf drivers/net/ethernet/intel/i40e/i40e.ko | tail -5 /* size: 4976, cachelines: 78, members: 112 */ /* sum members: 4905, holes: 17, sum holes: 71 */ /* paddings: 6, sum paddings: 19 */ /* last cacheline: 48 bytes */ }; Signed-off-by: Ivan Vecera Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e.h | 16 ---------------- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 3 --- drivers/net/ethernet/intel/i40e/i40e_main.c | 18 ++++-------------- 3 files changed, 4 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 6022944d04f8..9b701615c7c6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -468,9 +468,7 @@ struct i40e_pf { struct i40e_hw hw; DECLARE_BITMAP(state, __I40E_STATE_SIZE__); struct msix_entry *msix_entries; - bool fc_autoneg_status; - u16 eeprom_version; u16 num_vmdq_vsis; /* num vmdq vsis this PF has set up */ u16 num_vmdq_qps; /* num queue pairs per vmdq pool */ u16 num_vmdq_msix; /* num queue vectors per vmdq pool */ @@ -486,7 +484,6 @@ struct i40e_pf { u16 rss_size_max; /* HW defined max RSS queues */ u16 fdir_pf_filter_count; /* num of guaranteed filters for this PF */ u16 num_alloc_vsi; /* num VSIs this driver supports */ - u8 atr_sample_rate; bool wol_en; struct hlist_head fdir_filter_list; @@ -524,12 +521,10 @@ struct i40e_pf { struct hlist_head cloud_filter_list; u16 num_cloud_filters; - enum i40e_interrupt_policy int_policy; u16 rx_itr_default; u16 tx_itr_default; u32 msg_enable; char int_name[I40E_INT_NAME_STR_LEN]; - u16 adminq_work_limit; /* num of admin receive queue desc to process */ unsigned long service_timer_period; unsigned long service_timer_previous; struct timer_list service_timer; @@ -543,7 +538,6 @@ struct i40e_pf { u32 tx_timeout_count; u32 tx_timeout_recovery_level; unsigned long tx_timeout_last_recovery; - u32 tx_sluggish_count; u32 hw_csum_rx_error; u32 led_status; u16 corer_count; /* Core reset count */ @@ -565,17 +559,13 @@ struct i40e_pf { struct i40e_lump_tracking *irq_pile; /* switch config info */ - u16 pf_seid; u16 main_vsi_seid; u16 mac_seid; - struct kobject *switch_kobj; #ifdef CONFIG_DEBUG_FS struct dentry *i40e_dbg_pf; #endif /* CONFIG_DEBUG_FS */ bool cur_promisc; - u16 instance; /* A unique number per i40e_pf instance in the system */ - /* sr-iov config info */ struct i40e_vf *vf; int num_alloc_vfs; /* actual number of VFs allocated */ @@ -669,9 +659,7 @@ struct i40e_pf { unsigned long ptp_tx_start; struct hwtstamp_config tstamp_config; struct timespec64 ptp_prev_hw_time; - struct work_struct ptp_pps_work; struct work_struct ptp_extts0_work; - struct work_struct ptp_extts1_work; ktime_t ptp_reset_start; struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */ u32 ptp_adj_mult; @@ -679,10 +667,7 @@ struct i40e_pf { u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; u32 latch_event_flags; - u64 ptp_pps_start; - u32 pps_delay; spinlock_t ptp_rx_lock; /* Used to protect Rx timestamp registers. */ - struct ptp_pin_desc ptp_pin[3]; unsigned long latch_events[4]; bool ptp_tx; bool ptp_rx; @@ -695,7 +680,6 @@ struct i40e_pf { u32 fd_inv; u16 phy_led_val; - u16 override_q_count; u16 last_sw_conf_flags; u16 last_sw_conf_valid_flags; /* List to keep previous DDP profiles to be rolled back in the future */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 88240571721a..ef70ddbe9c2f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1028,9 +1028,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, "emp reset count: %d\n", pf->empr_count); dev_info(&pf->pdev->dev, "pf reset count: %d\n", pf->pfr_count); - dev_info(&pf->pdev->dev, - "pf tx sluggish count: %d\n", - pf->tx_sluggish_count); } else if (strncmp(&cmd_buf[5], "port", 4) == 0) { struct i40e_aqc_query_port_ets_config_resp *bw_data; struct i40e_dcbx_config *cfg = diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7ded598a68e6..d71331a8a972 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3465,7 +3465,7 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) /* some ATR related tx ring init */ if (test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags)) { - ring->atr_sample_rate = vsi->back->atr_sample_rate; + ring->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE; ring->atr_count = 0; } else { ring->atr_sample_rate = 0; @@ -10226,9 +10226,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) opcode); break; } - } while (i++ < pf->adminq_work_limit); + } while (i++ < I40E_AQ_WORK_LIMIT); - if (i < pf->adminq_work_limit) + if (i < I40E_AQ_WORK_LIMIT) clear_bit(__I40E_ADMINQ_EVENT_PENDING, pf->state); /* re-enable Admin queue interrupt cause */ @@ -12769,7 +12769,6 @@ static int i40e_sw_init(struct i40e_pf *pf) if ((pf->hw.func_caps.fd_filters_guaranteed > 0) || (pf->hw.func_caps.fd_filters_best_effort > 0)) { set_bit(I40E_FLAG_FD_ATR_ENA, pf->flags); - pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE; if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && pf->hw.num_partitions > 1) dev_info(&pf->pdev->dev, @@ -12815,7 +12814,6 @@ static int i40e_sw_init(struct i40e_pf *pf) I40E_MAX_VF_COUNT); } #endif /* CONFIG_PCI_IOV */ - pf->eeprom_version = 0xDEAD; pf->lan_veb = I40E_NO_VEB; pf->lan_vsi = I40E_NO_VSI; @@ -14976,12 +14974,11 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, * the PF's VSI */ pf->mac_seid = uplink_seid; - pf->pf_seid = downlink_seid; pf->main_vsi_seid = seid; if (printconfig) dev_info(&pf->pdev->dev, "pf_seid=%d main_vsi_seid=%d\n", - pf->pf_seid, pf->main_vsi_seid); + downlink_seid, pf->main_vsi_seid); break; case I40E_SWITCH_ELEMENT_TYPE_PF: case I40E_SWITCH_ELEMENT_TYPE_VF: @@ -15160,10 +15157,6 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acqui /* fill in link information and enable LSE reporting */ i40e_link_event(pf); - /* Initialize user-specific link properties */ - pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info & - I40E_AQ_AN_COMPLETED) ? true : false); - i40e_ptp_init(pf); if (!lock_acquired) @@ -15637,7 +15630,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #endif /* CONFIG_I40E_DCB */ struct i40e_pf *pf; struct i40e_hw *hw; - static u16 pfs_found; u16 wol_nvm_bits; char nvm_ver[32]; u16 link_status; @@ -15715,7 +15707,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); hw->bus.bus_id = pdev->bus->number; - pf->instance = pfs_found; /* Select something other than the 802.1ad ethertype for the * switch to use internally and drop on ingress. @@ -15777,7 +15768,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } hw->aq.arq_buf_size = I40E_MAX_AQ_BUF_SIZE; hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE; - pf->adminq_work_limit = I40E_AQ_WORK_LIMIT; snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", From 64c0aad13bb8cea0a5a30c8912bb268dce9b317a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 26 Oct 2023 10:38:22 +0200 Subject: [PATCH 1591/7721] i40e: Remove AQ register definitions for VF types The i40e driver does not handle its VF device types so there is no need to keep AdminQ register definitions for such device types. Remove them. Signed-off-by: Ivan Vecera Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_register.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index d561687303ea..2e1eaca44343 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -863,16 +863,6 @@ #define I40E_PFPM_WUFC 0x0006B400 /* Reset: POR */ #define I40E_PFPM_WUFC_MAG_SHIFT 1 #define I40E_PFPM_WUFC_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MAG_SHIFT) -#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ -#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ -#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */ -#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ -#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */ -#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ -#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ -#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */ -#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ -#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */ #define I40E_VFQF_HLUT_MAX_INDEX 15 From 4a95ce2407dadc4343759f96411442fdaa5467e4 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 26 Oct 2023 10:38:52 +0200 Subject: [PATCH 1592/7721] i40e: Remove queue tracking fields from i40e_adminq_ring Fields 'head', 'tail', 'len', 'bah' and 'bal' in i40e_adminq_ring are used to store register offsets. These offsets are initialized and remains constant so there is no need to store them in the i40e_adminq_ring structure. Remove these fields from i40e_adminq_ring and use register offset constants instead. Remove i40e_adminq_init_regs() that originally stores these constants into these fields. Finally improve i40e_check_asq_alive() that assumes that non-zero value of hw->aq.asq.len indicates fully initialized AdminQ send queue. Replace it by check for non-zero value of field hw->aq.asq.count that is non-zero when the sending queue is initialized and is zeroed during shutdown of the queue. Signed-off-by: Ivan Vecera Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 86 +++++++------------ drivers/net/ethernet/intel/i40e/i40e_adminq.h | 7 -- drivers/net/ethernet/intel/i40e/i40e_common.c | 8 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 8 +- 4 files changed, 39 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 896c43905309..f73f5930fc58 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -8,27 +8,6 @@ static void i40e_resume_aq(struct i40e_hw *hw); -/** - * i40e_adminq_init_regs - Initialize AdminQ registers - * @hw: pointer to the hardware structure - * - * This assumes the alloc_asq and alloc_arq functions have already been called - **/ -static void i40e_adminq_init_regs(struct i40e_hw *hw) -{ - /* set head and tail registers in our local struct */ - hw->aq.asq.tail = I40E_PF_ATQT; - hw->aq.asq.head = I40E_PF_ATQH; - hw->aq.asq.len = I40E_PF_ATQLEN; - hw->aq.asq.bal = I40E_PF_ATQBAL; - hw->aq.asq.bah = I40E_PF_ATQBAH; - hw->aq.arq.tail = I40E_PF_ARQT; - hw->aq.arq.head = I40E_PF_ARQH; - hw->aq.arq.len = I40E_PF_ARQLEN; - hw->aq.arq.bal = I40E_PF_ARQBAL; - hw->aq.arq.bah = I40E_PF_ARQBAH; -} - /** * i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings * @hw: pointer to the hardware structure @@ -254,17 +233,17 @@ static int i40e_config_asq_regs(struct i40e_hw *hw) u32 reg = 0; /* Clear Head and Tail */ - wr32(hw, hw->aq.asq.head, 0); - wr32(hw, hw->aq.asq.tail, 0); + wr32(hw, I40E_PF_ATQH, 0); + wr32(hw, I40E_PF_ATQT, 0); /* set starting point */ - wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | + wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries | I40E_PF_ATQLEN_ATQENABLE_MASK)); - wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, I40E_PF_ATQBAL, lower_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, I40E_PF_ATQBAH, upper_32_bits(hw->aq.asq.desc_buf.pa)); /* Check one register to verify that config was applied */ - reg = rd32(hw, hw->aq.asq.bal); + reg = rd32(hw, I40E_PF_ATQBAL); if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) ret_code = -EIO; @@ -283,20 +262,20 @@ static int i40e_config_arq_regs(struct i40e_hw *hw) u32 reg = 0; /* Clear Head and Tail */ - wr32(hw, hw->aq.arq.head, 0); - wr32(hw, hw->aq.arq.tail, 0); + wr32(hw, I40E_PF_ARQH, 0); + wr32(hw, I40E_PF_ARQT, 0); /* set starting point */ - wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | + wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries | I40E_PF_ARQLEN_ARQENABLE_MASK)); - wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, I40E_PF_ARQBAL, lower_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, I40E_PF_ARQBAH, upper_32_bits(hw->aq.arq.desc_buf.pa)); /* Update tail in the HW to post pre-allocated buffers */ - wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); + wr32(hw, I40E_PF_ARQT, hw->aq.num_arq_entries - 1); /* Check one register to verify that config was applied */ - reg = rd32(hw, hw->aq.arq.bal); + reg = rd32(hw, I40E_PF_ARQBAL); if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) ret_code = -EIO; @@ -439,11 +418,11 @@ static int i40e_shutdown_asq(struct i40e_hw *hw) } /* Stop firmware AdminQ processing */ - wr32(hw, hw->aq.asq.head, 0); - wr32(hw, hw->aq.asq.tail, 0); - wr32(hw, hw->aq.asq.len, 0); - wr32(hw, hw->aq.asq.bal, 0); - wr32(hw, hw->aq.asq.bah, 0); + wr32(hw, I40E_PF_ATQH, 0); + wr32(hw, I40E_PF_ATQT, 0); + wr32(hw, I40E_PF_ATQLEN, 0); + wr32(hw, I40E_PF_ATQBAL, 0); + wr32(hw, I40E_PF_ATQBAH, 0); hw->aq.asq.count = 0; /* to indicate uninitialized queue */ @@ -473,11 +452,11 @@ static int i40e_shutdown_arq(struct i40e_hw *hw) } /* Stop firmware AdminQ processing */ - wr32(hw, hw->aq.arq.head, 0); - wr32(hw, hw->aq.arq.tail, 0); - wr32(hw, hw->aq.arq.len, 0); - wr32(hw, hw->aq.arq.bal, 0); - wr32(hw, hw->aq.arq.bah, 0); + wr32(hw, I40E_PF_ARQH, 0); + wr32(hw, I40E_PF_ARQT, 0); + wr32(hw, I40E_PF_ARQLEN, 0); + wr32(hw, I40E_PF_ARQBAL, 0); + wr32(hw, I40E_PF_ARQBAH, 0); hw->aq.arq.count = 0; /* to indicate uninitialized queue */ @@ -608,9 +587,6 @@ int i40e_init_adminq(struct i40e_hw *hw) goto init_adminq_exit; } - /* Set up register offsets */ - i40e_adminq_init_regs(hw); - /* setup ASQ command write back timeout */ hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT; @@ -720,9 +696,9 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) desc = I40E_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); - while (rd32(hw, hw->aq.asq.head) != ntc) { + while (rd32(hw, I40E_PF_ATQH) != ntc) { i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, - "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); + "ntc %d head %d.\n", ntc, rd32(hw, I40E_PF_ATQH)); if (details->callback) { I40E_ADMINQ_CALLBACK cb_func = @@ -756,7 +732,7 @@ static bool i40e_asq_done(struct i40e_hw *hw) /* AQ designers suggest use of head for better * timing reliability than DD bit */ - return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; + return rd32(hw, I40E_PF_ATQH) == hw->aq.asq.next_to_use; } @@ -797,7 +773,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw, hw->aq.asq_last_status = I40E_AQ_RC_OK; - val = rd32(hw, hw->aq.asq.head); + val = rd32(hw, I40E_PF_ATQH); if (val >= hw->aq.num_asq_entries) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: head overrun at %d\n", val); @@ -889,7 +865,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw, if (hw->aq.asq.next_to_use == hw->aq.asq.count) hw->aq.asq.next_to_use = 0; if (!details->postpone) - wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); + wr32(hw, I40E_PF_ATQT, hw->aq.asq.next_to_use); /* if cmd_details are not defined or async flag is not set, * we need to wait for desc write back @@ -949,7 +925,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw, /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { - if (rd32(hw, hw->aq.asq.len) & I40E_GL_ATQLEN_ATQCRIT_MASK) { + if (rd32(hw, I40E_PF_ATQLEN) & I40E_GL_ATQLEN_ATQCRIT_MASK) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: AQ Critical error.\n"); status = -EIO; @@ -1103,7 +1079,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw, } /* set next_to_use to head */ - ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK; + ntu = rd32(hw, I40E_PF_ARQH) & I40E_PF_ARQH_ARQH_MASK; if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = -EALREADY; @@ -1151,7 +1127,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw, desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); /* set tail = the last cleaned desc index. */ - wr32(hw, hw->aq.arq.tail, ntc); + wr32(hw, I40E_PF_ARQT, ntc); /* ntc is updated to tail + 1 */ ntc++; if (ntc == hw->aq.num_arq_entries) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 80125bea80a2..ee86d2c53079 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -29,13 +29,6 @@ struct i40e_adminq_ring { /* used for interrupt processing */ u16 next_to_use; u16 next_to_clean; - - /* used for queue tracking */ - u32 head; - u32 tail; - u32 len; - u32 bah; - u32 bal; }; /* ASQ transaction details */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index e171f4814e21..bd52b73cf61f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -195,11 +195,11 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, **/ bool i40e_check_asq_alive(struct i40e_hw *hw) { - if (hw->aq.asq.len) - return !!(rd32(hw, hw->aq.asq.len) & - I40E_PF_ATQLEN_ATQENABLE_MASK); - else + /* Check if the queue is initialized */ + if (!hw->aq.asq.count) return false; + + return !!(rd32(hw, I40E_PF_ATQLEN) & I40E_PF_ATQLEN_ATQENABLE_MASK); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d71331a8a972..9eeea8d9ab67 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10127,7 +10127,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) return; /* check for error indications */ - val = rd32(&pf->hw, pf->hw.aq.arq.len); + val = rd32(&pf->hw, I40E_PF_ARQLEN); oldval = val; if (val & I40E_PF_ARQLEN_ARQVFE_MASK) { if (hw->debug_mask & I40E_DEBUG_AQ) @@ -10146,9 +10146,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) val &= ~I40E_PF_ARQLEN_ARQCRIT_MASK; } if (oldval != val) - wr32(&pf->hw, pf->hw.aq.arq.len, val); + wr32(&pf->hw, I40E_PF_ARQLEN, val); - val = rd32(&pf->hw, pf->hw.aq.asq.len); + val = rd32(&pf->hw, I40E_PF_ATQLEN); oldval = val; if (val & I40E_PF_ATQLEN_ATQVFE_MASK) { if (pf->hw.debug_mask & I40E_DEBUG_AQ) @@ -10166,7 +10166,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) val &= ~I40E_PF_ATQLEN_ATQCRIT_MASK; } if (oldval != val) - wr32(&pf->hw, pf->hw.aq.asq.len, val); + wr32(&pf->hw, I40E_PF_ATQLEN, val); event.buf_len = I40E_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); From 3d66f21552df25cf56f7f800a8d7687c88771761 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 26 Oct 2023 10:39:32 +0200 Subject: [PATCH 1593/7721] iavf: Remove queue tracking fields from iavf_adminq_ring Fields 'head', 'tail', 'len', 'bah' and 'bal' in iavf_adminq_ring are used to store register offsets. These offsets are initialized and remains constant so there is no need to store them in the iavf_adminq_ring structure. Remove these fields from iavf_adminq_ring and use register offset constants instead. Remove iavf_adminq_init_regs() that originally stores these constants into these fields. Finally improve iavf_check_asq_alive() that assumes that non-zero value of hw->aq.asq.len indicates fully initialized AdminQ send queue. Replace it by check for non-zero value of field hw->aq.asq.count that is non-zero when the sending queue is initialized and is zeroed during shutdown of the queue. Signed-off-by: Ivan Vecera Reviewed-by: Przemek Kitszel Reviewed-by: Wojciech Drewek Reviewed-by: Simon Horman Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_adminq.c | 86 +++++++------------ drivers/net/ethernet/intel/iavf/iavf_adminq.h | 7 -- drivers/net/ethernet/intel/iavf/iavf_common.c | 8 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 8 +- 4 files changed, 39 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.c b/drivers/net/ethernet/intel/iavf/iavf_adminq.c index 9ffbd24d83cb..82fcd18ad660 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_adminq.c +++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.c @@ -7,27 +7,6 @@ #include "iavf_adminq.h" #include "iavf_prototype.h" -/** - * iavf_adminq_init_regs - Initialize AdminQ registers - * @hw: pointer to the hardware structure - * - * This assumes the alloc_asq and alloc_arq functions have already been called - **/ -static void iavf_adminq_init_regs(struct iavf_hw *hw) -{ - /* set head and tail registers in our local struct */ - hw->aq.asq.tail = IAVF_VF_ATQT1; - hw->aq.asq.head = IAVF_VF_ATQH1; - hw->aq.asq.len = IAVF_VF_ATQLEN1; - hw->aq.asq.bal = IAVF_VF_ATQBAL1; - hw->aq.asq.bah = IAVF_VF_ATQBAH1; - hw->aq.arq.tail = IAVF_VF_ARQT1; - hw->aq.arq.head = IAVF_VF_ARQH1; - hw->aq.arq.len = IAVF_VF_ARQLEN1; - hw->aq.arq.bal = IAVF_VF_ARQBAL1; - hw->aq.arq.bah = IAVF_VF_ARQBAH1; -} - /** * iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings * @hw: pointer to the hardware structure @@ -259,17 +238,17 @@ static enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw) u32 reg = 0; /* Clear Head and Tail */ - wr32(hw, hw->aq.asq.head, 0); - wr32(hw, hw->aq.asq.tail, 0); + wr32(hw, IAVF_VF_ATQH1, 0); + wr32(hw, IAVF_VF_ATQT1, 0); /* set starting point */ - wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | + wr32(hw, IAVF_VF_ATQLEN1, (hw->aq.num_asq_entries | IAVF_VF_ATQLEN1_ATQENABLE_MASK)); - wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, IAVF_VF_ATQBAL1, lower_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, IAVF_VF_ATQBAH1, upper_32_bits(hw->aq.asq.desc_buf.pa)); /* Check one register to verify that config was applied */ - reg = rd32(hw, hw->aq.asq.bal); + reg = rd32(hw, IAVF_VF_ATQBAL1); if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; @@ -288,20 +267,20 @@ static enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw) u32 reg = 0; /* Clear Head and Tail */ - wr32(hw, hw->aq.arq.head, 0); - wr32(hw, hw->aq.arq.tail, 0); + wr32(hw, IAVF_VF_ARQH1, 0); + wr32(hw, IAVF_VF_ARQT1, 0); /* set starting point */ - wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | + wr32(hw, IAVF_VF_ARQLEN1, (hw->aq.num_arq_entries | IAVF_VF_ARQLEN1_ARQENABLE_MASK)); - wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, IAVF_VF_ARQBAL1, lower_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, IAVF_VF_ARQBAH1, upper_32_bits(hw->aq.arq.desc_buf.pa)); /* Update tail in the HW to post pre-allocated buffers */ - wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); + wr32(hw, IAVF_VF_ARQT1, hw->aq.num_arq_entries - 1); /* Check one register to verify that config was applied */ - reg = rd32(hw, hw->aq.arq.bal); + reg = rd32(hw, IAVF_VF_ARQBAL1); if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; @@ -455,11 +434,11 @@ static enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw) } /* Stop firmware AdminQ processing */ - wr32(hw, hw->aq.asq.head, 0); - wr32(hw, hw->aq.asq.tail, 0); - wr32(hw, hw->aq.asq.len, 0); - wr32(hw, hw->aq.asq.bal, 0); - wr32(hw, hw->aq.asq.bah, 0); + wr32(hw, IAVF_VF_ATQH1, 0); + wr32(hw, IAVF_VF_ATQT1, 0); + wr32(hw, IAVF_VF_ATQLEN1, 0); + wr32(hw, IAVF_VF_ATQBAL1, 0); + wr32(hw, IAVF_VF_ATQBAH1, 0); hw->aq.asq.count = 0; /* to indicate uninitialized queue */ @@ -489,11 +468,11 @@ static enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw) } /* Stop firmware AdminQ processing */ - wr32(hw, hw->aq.arq.head, 0); - wr32(hw, hw->aq.arq.tail, 0); - wr32(hw, hw->aq.arq.len, 0); - wr32(hw, hw->aq.arq.bal, 0); - wr32(hw, hw->aq.arq.bah, 0); + wr32(hw, IAVF_VF_ARQH1, 0); + wr32(hw, IAVF_VF_ARQT1, 0); + wr32(hw, IAVF_VF_ARQLEN1, 0); + wr32(hw, IAVF_VF_ARQBAL1, 0); + wr32(hw, IAVF_VF_ARQBAH1, 0); hw->aq.arq.count = 0; /* to indicate uninitialized queue */ @@ -529,9 +508,6 @@ enum iavf_status iavf_init_adminq(struct iavf_hw *hw) goto init_adminq_exit; } - /* Set up register offsets */ - iavf_adminq_init_regs(hw); - /* setup ASQ command write back timeout */ hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT; @@ -587,9 +563,9 @@ static u16 iavf_clean_asq(struct iavf_hw *hw) desc = IAVF_ADMINQ_DESC(*asq, ntc); details = IAVF_ADMINQ_DETAILS(*asq, ntc); - while (rd32(hw, hw->aq.asq.head) != ntc) { + while (rd32(hw, IAVF_VF_ATQH1) != ntc) { iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, - "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); + "ntc %d head %d.\n", ntc, rd32(hw, IAVF_VF_ATQH1)); if (details->callback) { IAVF_ADMINQ_CALLBACK cb_func = @@ -624,7 +600,7 @@ bool iavf_asq_done(struct iavf_hw *hw) /* AQ designers suggest use of head for better * timing reliability than DD bit */ - return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; + return rd32(hw, IAVF_VF_ATQH1) == hw->aq.asq.next_to_use; } /** @@ -663,7 +639,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw, hw->aq.asq_last_status = IAVF_AQ_RC_OK; - val = rd32(hw, hw->aq.asq.head); + val = rd32(hw, IAVF_VF_ATQH1); if (val >= hw->aq.num_asq_entries) { iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: head overrun at %d\n", val); @@ -755,7 +731,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw, if (hw->aq.asq.next_to_use == hw->aq.asq.count) hw->aq.asq.next_to_use = 0; if (!details->postpone) - wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); + wr32(hw, IAVF_VF_ATQT1, hw->aq.asq.next_to_use); /* if cmd_details are not defined or async flag is not set, * we need to wait for desc write back @@ -810,7 +786,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw, /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { - if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { + if (rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: AQ Critical error.\n"); status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR; @@ -878,7 +854,7 @@ enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw, } /* set next_to_use to head */ - ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK; + ntu = rd32(hw, IAVF_VF_ARQH1) & IAVF_VF_ARQH1_ARQH_MASK; if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = IAVF_ERR_ADMIN_QUEUE_NO_WORK; @@ -926,7 +902,7 @@ enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw, desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); /* set tail = the last cleaned desc index. */ - wr32(hw, hw->aq.arq.tail, ntc); + wr32(hw, IAVF_VF_ARQT1, ntc); /* ntc is updated to tail + 1 */ ntc++; if (ntc == hw->aq.num_arq_entries) diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.h b/drivers/net/ethernet/intel/iavf/iavf_adminq.h index 1f60518eb0e5..406506f64bdd 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_adminq.h +++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.h @@ -29,13 +29,6 @@ struct iavf_adminq_ring { /* used for interrupt processing */ u16 next_to_use; u16 next_to_clean; - - /* used for queue tracking */ - u32 head; - u32 tail; - u32 len; - u32 bah; - u32 bal; }; /* ASQ transaction details */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c index 8091e6feca01..89d2bce529ae 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_common.c +++ b/drivers/net/ethernet/intel/iavf/iavf_common.c @@ -279,11 +279,11 @@ void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc, **/ bool iavf_check_asq_alive(struct iavf_hw *hw) { - if (hw->aq.asq.len) - return !!(rd32(hw, hw->aq.asq.len) & - IAVF_VF_ATQLEN1_ATQENABLE_MASK); - else + /* Check if the queue is initialized */ + if (!hw->aq.asq.count) return false; + + return !!(rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQENABLE_MASK); } /** diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c862ebcd2e39..27d63b605638 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -3253,7 +3253,7 @@ static void iavf_adminq_task(struct work_struct *work) goto freedom; /* check for error indications */ - val = rd32(hw, hw->aq.arq.len); + val = rd32(hw, IAVF_VF_ARQLEN1); if (val == 0xdeadbeef || val == 0xffffffff) /* device in reset */ goto freedom; oldval = val; @@ -3270,9 +3270,9 @@ static void iavf_adminq_task(struct work_struct *work) val &= ~IAVF_VF_ARQLEN1_ARQCRIT_MASK; } if (oldval != val) - wr32(hw, hw->aq.arq.len, val); + wr32(hw, IAVF_VF_ARQLEN1, val); - val = rd32(hw, hw->aq.asq.len); + val = rd32(hw, IAVF_VF_ATQLEN1); oldval = val; if (val & IAVF_VF_ATQLEN1_ATQVFE_MASK) { dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n"); @@ -3287,7 +3287,7 @@ static void iavf_adminq_task(struct work_struct *work) val &= ~IAVF_VF_ATQLEN1_ATQCRIT_MASK; } if (oldval != val) - wr32(hw, hw->aq.asq.len, val); + wr32(hw, IAVF_VF_ATQLEN1, val); freedom: kfree(event.msg_buf); From 95260816b489509c1f5b0141d0ae7b65be3c1d39 Mon Sep 17 00:00:00 2001 From: Petr Oros Date: Tue, 14 Nov 2023 23:35:22 +0100 Subject: [PATCH 1594/7721] iavf: use iavf_schedule_aq_request() helper Use the iavf_schedule_aq_request() helper when we need to schedule a watchdog task immediately. No functional change. Signed-off-by: Petr Oros Reviewed-by: Wojciech Drewek Tested-by: Rafal Romanowski Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 10 +++------- drivers/net/ethernet/intel/iavf/iavf_main.c | 15 +++++---------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index 6f236d1a6444..6b3d3e54b8b7 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -1445,10 +1445,9 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx iavf_fdir_list_add_fltr(adapter, fltr); adapter->fdir_active_fltr++; fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST; - adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER; spin_unlock_bh(&adapter->fdir_fltr_lock); - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER); ret: if (err && fltr) @@ -1479,7 +1478,6 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx if (fltr) { if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) { fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST; - adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER; } else { err = -EBUSY; } @@ -1489,7 +1487,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx spin_unlock_bh(&adapter->fdir_fltr_lock); if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST) - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER); return err; } @@ -1658,7 +1656,6 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter, rss_old->hash_flds = hash_flds; memcpy(&rss_old->cfg_msg, &rss_new->cfg_msg, sizeof(rss_new->cfg_msg)); - adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG; } else { err = -EEXIST; } @@ -1668,12 +1665,11 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter, rss_new->packet_hdrs = hdrs; rss_new->hash_flds = hash_flds; list_add_tail(&rss_new->list, &adapter->adv_rss_list_head); - adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG; } spin_unlock_bh(&adapter->adv_rss_lock); if (!err) - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_ADV_RSS_CFG); mutex_unlock(&adapter->crit_lock); diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 27d63b605638..06a87030c163 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1059,13 +1059,12 @@ static int iavf_replace_primary_mac(struct iavf_adapter *adapter, */ new_f->is_primary = true; new_f->add = true; - adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; ether_addr_copy(hw->mac.addr, new_mac); spin_unlock_bh(&adapter->mac_vlan_list_lock); /* schedule the watchdog task to immediately process the request */ - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_MAC_FILTER); return 0; } @@ -1284,8 +1283,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter) iavf_napi_enable_all(adapter); - adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES; - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ENABLE_QUEUES); } /** @@ -1439,8 +1437,7 @@ void iavf_down(struct iavf_adapter *adapter) adapter->aq_required |= IAVF_FLAG_AQ_DEL_ADV_RSS_CFG; } - adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES; - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DISABLE_QUEUES); } /** @@ -2337,10 +2334,8 @@ iavf_set_vlan_offload_features(struct iavf_adapter *adapter, } } - if (aq_required) { - adapter->aq_required |= aq_required; - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); - } + if (aq_required) + iavf_schedule_aq_request(adapter, aq_required); } /** From 87ef333c0c046b6d07914c80611cf5cc31790e72 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 20 Nov 2023 18:02:23 +0800 Subject: [PATCH 1595/7721] docs/zh_CN: add process maintainer-pgp-guide tanslation Translate process/maintainer-pgp-guide.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Reviewed-by: Konstantin Ryabitsev Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/7c7f24f653468c9a2c7e3909a7a390ea36eec879.1700474235.git.siyanteng@loongson.cn --- .../translations/zh_CN/process/index.rst | 1 + .../zh_CN/process/maintainer-pgp-guide.rst | 789 ++++++++++++++++++ 2 files changed, 790 insertions(+) create mode 100644 Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst index a1a35f88f4ae..5af0c2735902 100644 --- a/Documentation/translations/zh_CN/process/index.rst +++ b/Documentation/translations/zh_CN/process/index.rst @@ -29,6 +29,7 @@ submitting-patches programming-language coding-style + maintainer-pgp-guide development-process email-clients license-rules diff --git a/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst new file mode 100644 index 000000000000..eb12694a4c59 --- /dev/null +++ b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst @@ -0,0 +1,789 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/process/maintainer-pgp-guide.rst + +:翻译: + + 司延腾 Yanteng Si + +:校译: + + +=================== +内核维护者 PGP 指南 +=================== + +:作者: Konstantin Ryabitsev + +本文档面向 Linux 内核开发者,特别是子系统维护人员。文档中含有Linux 基金 +会发布的更通用的 `保护代码完整性`_ 指南中讨论的内容子集。阅读该文档,以更 +深入地讨论本指南中提到的一些主题。 + +.. _`保护代码完整性`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md + +PGP 在 Linux 内核开发中的作用 +============================= + +PGP 有助于确保 Linux 内核开发社区产出代码的完整性,并在较小程度上,通过 +PGP 签名的电子邮件交换,在开发者之间建立可信的交流渠道。 + +Linux 内核源代码主要有两种(维护)方式: + +- 分布式源仓库 (git) +- 定期发布快照 (tarballs) + +git 仓库和 tarball 都带有创建官方内核版本的内核开发者的 PGP 签名。这 +些签名提供了加密保证,即保证 kernel.org 或任何其他镜像提供的可下载版本 +与这些开发者在其工作站上的版本相同。为此: + +- git 仓库在所有标签上提供 PGP 签名 +- tarball 为所有下载提供独立的 PGP 签名 + +信任开发者,不要信基础设施 +-------------------------- + +自从 2011 年 kernel.org 核心系统遭到入侵以来,内核存档项目的主要运行原 +则就是假定基础设施的任何部分都可能随时受到入侵。因此,管理员特意采取措施, +强调必须始终信任开发者,不能信任代码托管基础设施,无论后者的安全实践有多好。 + +上述指导原则正是需要本指南的原因。希望确保通过对开发者的信任,我们不会简 +单地将未来潜在安全事件的责任归咎于其他人。目的是提供一套指导开发者可以用 +来创建安全的工作环境并保护用于建立 Linux 内核本身完整性的 PGP 密钥。 + +PGP 工具 +======== + +使用 GnuPG 2.2 或更高版本 +------------------------- + +默认情况下,你的发行版应该已经安装了 GnuPG,你只需要验证你使用的是相当新的 +版本即可。要检查,请运行:: + + $ gpg --version | head -n1 + +如果你有 2.2 或更高版本,那么你就可以开始了。如果你的版本早于 2.2,则本指 +南中的某些命令可能不起作用。 + +配置 gpg-agent 选项 +~~~~~~~~~~~~~~~~~~~ + +GnuPG agent是一个辅助工具,每当你使用该命令时,它都会自动启动gpg,并在 +后台运行,目的是缓存私钥密码。你应该知道两个选项,以便调整密码何时从缓存 +过期: + +- ``default-cache-ttl`` (秒): 如果在生命周期结束之前再次使用相同的 + 密钥,倒计时将重置为另一段时间。默认值为 600(10 分钟)。 +- ``max-cache-ttl`` (秒): 无论你自输入初始密码以来多久使用过密钥, + 如果最大生存时间倒计时结束,你都必须再次输入密码。默认值为 30 分钟。 + +如果你发现这些默认值太短(或太长),你可以编辑 ``~/.gnupg/gpg-agent.conf`` +文件以设置你自己的值:: + + # 常规ttl设置为30分钟,最大ttl设置为2小时 + default-cache-ttl 1800 + max-cache-ttl 7200 + +.. note:: + + 不需要在 shell 会话开始时手动启动 gpg-agent。你可能需要检查 + rc 文件来删除旧版本 GnuPG 中的所有内容,因为它可能不再做正确 + 的事情。 + +保护你的 PGP 密钥 +================= + +本指南假定你已经拥有用于 Linux 内核开发目的的 PGP 密钥。如果你还没 +有,请参阅前面提到的 "`保护代码完整性`_" 文档,以获取有关如何创建新 +密钥的指导。 + +如果你当前的密钥低于 2048 位 (RSA),你还应该创建一个新密钥。 + +了解 PGP 子密钥 +--------------- + +PGP 密钥很少由单个密钥对组成 - 通常它是独立子密钥的集合,这些子密钥 +可根据其功能用于不同的目的,并在创建时分配。PGP 定义了密钥可以具有的 +四种功能: + +- **[S]** 密钥可用于签名 +- **[E]** 密钥可用于加密 +- **[A]** 密钥可用于身份验证 +- **[C]** 密钥可用于验证其他密钥 + +具有 **[C]** 功能的密钥通常称为“主”密钥,但该术语具有误导性,因为 +它意味着可以使用Certify密钥来代替同一链上的任何其他子密钥(如物理 +“主密钥”可用于打开为其他钥匙制作的锁)。由于情况并非如此,本指南将 +其称为“认证密钥”以避免任何歧义。 + +充分理解以下内容至关重要: + +1. 所有子项彼此完全独立。如果你丢失了私有子密钥,则无法从链上的任何 + 其他私钥恢复或重新创建它。 +2. 除 Certify 密钥外,可以有多个具有相同功能的子密钥(例如,你可 + 以有 2 个有效的加密子密钥、3 个有效的签名子密钥,但只有 1 个有 + 效的认证子密钥)。所有子密钥都是完全独立的——加密到一个 **[E]** + 子密钥的信息(messages)无法使用你可能拥有的任何其他 **[E]** + 子密钥解密。 +3. 单个子密钥可能具有多种功能(例如,你的 **[C]** 密钥也可以是你 + 的 **[S]** 密钥)。 + +携带 **[C]** (证明)能力的密钥是唯一可以用来指示与其他密钥的关系 +的密钥。仅 **[C]** 密钥可用于: + +- 添加或撤销具有 S/E/A 功能的其他密钥(子密钥) +- 添加、更改或撤销与密钥关联的身份 (uid) +- 添加或更改其本身或任何子密钥的到期日期 +- 出于信任网络的目的签署其他人的密钥 + +默认情况下,GnuPG 在生成新密钥时创建以下内容: + +- 一个子密钥同时具有认证和签名功能 (**[SC]**) +- 具有加密功能的单独子密钥 (**[E]**) + +如果你在生成密钥时使用了默认参数,那么这就是你将得到的。你可以通过 +运行命令来验证,例如: ``gpg --list-secret-keys`` + +:: + + sec ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb cv25519 2022-12-20 [E] [expires: 2024-12-19] + +在 ``sec`` 这行下面长长的一行就是你的密钥指纹-无论在下文任何地方 +看到 ``[fpr]`` 都指的是这40个字符。 + +确保你的密码强度高 +------------------ + +GnuPG 在将私钥存储到磁盘之前使用密码对其进行加密。这样,即使你的 +``.gnupg`` 目录全部泄露或被盗,攻击者在没有事先获取密码来解密的 +情况下也无法使用你的私钥。 + +你的私钥受到强密码保护是绝对必要的。要设置或更改它,请使用:: + + $ gpg --change-passphrase [fpr] + +创建一个单独的签名子密钥 +------------------------ + +我们的目的是通过将你的证书密钥移动到离线媒介来保护它,因此如果你只 +有组合的 **[SC]** 密钥,那么你应该创建一个单独的签名子密钥:: + + $ gpg --quick-addkey [fpr] ed25519 sign + +.. note:: GnuPG 中的 ECC 支持 + + 请注意,如果你打算使用不支持 ED25519 ECC 密钥的硬件密钥,则 + 应选择“nistp256”或“ed25519”。请参阅下面有关推荐硬件设备的 + 部分。 + + +备份你的证书密钥以进行灾难恢复 +------------------------------ + +你的 PGP 密钥上来自其他开发者的签名越多,出于灾难恢复的原因,你就越 +有理由创建一个位于数字媒体之外的备份版本。 + +创建私钥的可打印硬拷贝的最佳方法是使用 ``paperkey`` 为此目的编写 +的软件。有关输出格式及其相对于其他解决方案的优势的更多详细信息,请参 +阅 ``paperkey`` 参考资料。大多数发行版都应该已经打包了 Paperkey。 + +运行以下命令来创建私钥的硬拷贝备份:: + + $ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt + +打印出该文件(或将输出直接传输到 lpr),然后用笔在纸的边缘写下你的密 +码。 **强烈建议这样做**,因为密钥打印输出仍然使用该密码进行加密,并且 +如果你更改了它,你将不记得创建备份时它曾经是什么 - *保证*。 + +将生成的打印输出和手写密码放入信封中,并存放在安全且受到良好保护的地 +方,最好远离你的家,例如银行保险柜。 + +.. note:: + + 你的打印机可能不再是连接到并行端口的简单哑设备,但由于输出仍然使 + 用你的密码进行加密,因此即使“云端打印”的现代打印机也应该保持相 + 对安全的操作 + +备份整个 GnuPG 目录 +------------------- + +.. warning:: + + **!!!不要跳过这个步骤!!!** + +如果你需要恢复 PGP 密钥,拥有一个随时可用的备份非常重要。这与我们 +所做的灾难级准备不同 ``paperkey`` 。每当你需要使用你的证书密钥时, +例如在会议和峰会后更改你自己的密钥或签署其他人的密钥时,你还将依赖 +这些外部副本。 + +首先获取一个小型 USB “拇指” 驱动器(最好是两个!),用于备份目的。 +你需要使用 LUKS 对其进行加密——请参阅你的发行版文档以了解如何完成 +此操作。 + +对于加密密码,你可以使用与 PGP 密钥相同的密码。 + +加密过程完成后,重新插入 USB 驱动器并确保其正确安装。将整个 ``.gnupg`` +目录复制到加密存储:: + + $ cp -a ~/.gnupg /media/disk/foo/gnupg-backup + +你现在应该测试一下,确保一切依然能正常工作:: + + $ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr] + +如果没有出现任何错误,那么就可以开始了。卸下 USB 驱动器,给它贴上 +明显的标签,这样下次需要使用随机 USB 驱动器时就不会把它吹走,然后 +放在安全的地方 - 但不要太远,因为你每次都需要使用它时不时地用于诸 +如编辑身份、添加或撤销子密钥或签署其他人的密钥之类的事情。 + +从你的 homedir 中删除 Certify 密钥 +---------------------------------- + +我们的主目录中的文件并没有我们想象的那么受到保护。它们可以通过多种 +不同的方式泄露或被盗: + +- 在制作快速主目录备份以设置新工作站时意外发生 +- 系统管理员的疏忽或恶意 +- 通过不安全的备份 +- 通过桌面应用程序(浏览器、pdf 查看器等)中的恶意软件 +- 跨越国界时通过胁迫 + +使用良好的密码短语保护你的密钥极大地有助于降低上述任何风险,但密码 +短语可以通过键盘记录器、肩窥或任何其他方式发现。因此,建议的设置是 +从主目录中删除你的证书密钥并将其存储在离线存储中。 + +.. warning:: + + 请参阅上一节并确保你已完整备份 GnuPG 目录。如果你没有可用的 + 备份,我们要做的事情将使你的密钥毫无用处! + +首先,确定你的证书密钥的keygrip:: + + $ gpg --with-keygrip --list-key [fpr] + +输出将是这样的:: + + pub ed25519 2022-12-20 [SC] [expires: 2022-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + Keygrip = 1111000000000000000000000000000000000000 + uid [ultimate] Alice Dev + sub cv25519 2022-12-20 [E] [expires: 2022-12-19] + Keygrip = 2222000000000000000000000000000000000000 + sub ed25519 2022-12-20 [S] + Keygrip = 3333000000000000000000000000000000000000 + +找到该线 ``pub`` 下方的keygrip项 (位于“认证密钥指纹”的正下方)。 +这将直接对应于你``~/.gnupg`` 目录中的一个文件:: + + $ cd ~/.gnupg/private-keys-v1.d + $ ls + 1111000000000000000000000000000000000000.key + 2222000000000000000000000000000000000000.key + 3333000000000000000000000000000000000000.key + +你所要做的只是删除与证书密钥 keygrip 对应的 .key 文件:: + + $ cd ~/.gnupg/private-keys-v1.d + $ rm 1111000000000000000000000000000000000000.key + +现在,如果你发出命令 ``--list-secret-keys`` ,它将显示证书密钥丢 +失( 表示 ``#`` 它不可用):: + + $ gpg --list-secret-keys + sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb cv25519 2022-12-20 [E] [expires: 2024-12-19] + ssb ed25519 2022-12-20 [S] + +你还应该删除 ``~/.gnupg``目录中的所有 ``secring.gpg`` 文件 ,这些 +文件可能是以前版本的 GnuPG 留下的。 + +如果你没有“private-keys-v1.d”目录 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如果你没有 ``~/.gnupg/private-keys-v1.d`` 目录,那么你的密钥仍存 +储在 GnuPG v1 使用的旧文件 ``secring.gpg`` 中。对密钥进行任何更改 +(例如更改密码或添加子密钥)应该会自动转换旧 ``secring.gpg`` 格式以 +供使用 ``private-keys-v1.d`` 。 + +完成此操作后,请确保删除过时的 ``secring.gpg`` 文件,其中仍然包含你 +的私钥。 + + +将子密钥移至专用加密设备 +======================== + +尽管 Certify 密钥现在不会被泄露或被盗,但子密钥仍然位于你的主目录中。 +任何设法获得这些内容的人都将能够解密你的通信或伪造你的签名(如果他们知 +道密码)。此外,每次执行 GnuPG 操作时,密钥都会加载到系统内存中,并 +可能被足够高级的恶意软件(例如 Meltdown 和 Spectre)从那里窃取。 + +完全保护密钥的最佳方法是将它们转移到能够进行智能卡操作的专用硬件设备上。 + +智能卡的好处 +------------ + +智能卡包含一个加密芯片,能够存储私钥并直接在卡本身上执行加密操作。由于 +密钥内容永远不会离开智能卡,因此插入硬件设备的计算机的操作系统无法自行 +检索私钥。这与我们之前用于备份目的的加密 USB 存储设备有很大不同——当 +USB 设备插入并安装时,操作系统能够访问私钥内容。 + +使用外部加密 USB 介质并不能替代具有智能卡功能的设备。 + +可用的智能卡设备 +---------------- + +除非你的所有笔记本电脑和工作站都有智能卡读卡器,否则最简单的方法是获 +取实现智能卡功能的专用 USB 设备。有多种选择:: + +- `Nitrokey Start`_: 开放硬件和免费软件,日本基于FSI的 `Gnuk` 。 + 少数支持 ED25519 ECC 密钥的商用设备之一,但提供的安全功能最少 + (例如防篡改或某些旁路攻击)。 +- `Nitrokey Pro 2`_: 与 Nitrokey Start 类似,但更防篡改并提供 + 更多安全功能。Pro 2 支持 ECC 加密 (NISTP)。 +- `Yubikey 5`_: 专有硬件和软件,但比 Nitrokey Pro 便宜,并且以 + USB-C 形式提供,对于较新的笔记本电脑更有用。提供额外的安全功能, + 例如 FIDO U2F 等,现在终于支持 NISTP 和 ED25519 ECC 密钥。 + +你的选择将取决于成本、你所在地理区域的货运便利性以及开放/专有硬件考虑 +因素。 + +.. note:: + + 如果你位列于 MAINTAINERS 中或在 kernel.org 上拥有帐户,则你有 + 资格获得Linux 基金会提供的_`qualify for a free Nitrokey Start` 。 + +.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6 +.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nkpr2-nitrokey-pro-2-3 +.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/ +.. _Gnuk: https://www.fsij.org/doc-gnuk/ +.. _`qualify for a free Nitrokey Start`: https://www.kernel.org/nitrokey-digital-tokens-for-kernel-developers.html + +配置你的智能卡设备 +------------------ + +当你将智能卡设备插入任何现代 Linux 工作站时,它就应该可以正常工作 +(TM)。你可以通过运行来验证它:: + + $ gpg --card-status + +如果你看到完整的智能卡详细信息,那么你就可以开始了。不幸的是,对所有 +可能无法正常工作的原因进行故障排除超出了本指南的范围。如果你在使该卡 +与 GnuPG 配合使用时遇到问题,请通过常规支持渠道寻求帮助。 + +要配置你的智能卡,你需要使用 GnuPG 菜单系统,因为没有方便的命令行开 +关:: + + $ gpg --card-edit + [...omitted...] + gpg/card> admin + Admin commands are allowed + gpg/card> passwd + +你应该设置用户 PIN (1)、管理员 PIN (3) 和重置代码 (4)。请确保将 +这些信息记录并存储在安全的地方,尤其是管理员 PIN 码和重置代码(它允 +许你完全擦除智能卡)。你很少需要使用管理员 PIN 码,如果你不记录它, +你将不可避免地忘记它是什么。 + +回到主卡菜单,你还可以设置其他值(例如姓名、性别、登录数据等),但这 +不是必需的,并且如果你丢失智能卡,还会泄露有关智能卡的信息。 + +.. note:: + + 尽管名称为“PIN”,但卡上的用户 PIN 和管理员 PIN 都不需要是数字。 + +.. warning:: + + 某些设备可能要求你将子密钥移至设备上,然后才能更改密码。请检查设 + 备制造商提供的文档。 + +将子密钥移至你的智能卡 +---------------------- + +退出卡菜单(使用“q”)并保存所有更改。接下来,让我们将子密钥移至智能卡 +上。对于大多数操作,你将需要 PGP 密钥密码和卡的管理员 PIN:: + + $ gpg --edit-key [fpr] + + Secret subkeys are available. + + pub ed25519/AAAABBBBCCCCDDDD + created: 2022-12-20 expires: 2024-12-19 usage: SC + trust: ultimate validity: ultimate + ssb cv25519/1111222233334444 + created: 2022-12-20 expires: never usage: E + ssb ed25519/5555666677778888 + created: 2017-12-07 expires: never usage: S + [ultimate] (1). Alice Dev + + gpg> + +使用 ``--edit-key`` 使我们再次进入菜单模式,你会注意到按键列表有点 +不同。从现在开始,所有命令都在此菜单模式内完成,如 所示 ``gpg>``。 + +首先,让我们选择要放入卡上的密钥 - 你可以通过键入 ``key 1`` (它是 +列表中的第一个, **[E]** 子密钥)来完成此操作: + + gpg> key 1 + +在输出中,你现在在 **[E]** 子密钥应该看到 ``ssb*`` 。意味着这个子 +密钥当前被选中。它用作切换键,这意味着如果你再次输入 ``key 1`` , +``*`` 将会消失并且该键将不再被选择。 + +现在,让我们将该密钥移至智能卡上:: + + gpg> keytocard + Please select where to store the key: + (2) Encryption key + Your selection? 2 + +由于它是我们的 **[E]** 密钥,因此将其放入加密槽中是有意义的。当你提 +交选择时,系统将首先提示你输入 PGP 密钥密码,然后输入管理员 PIN 码。 +如果命令返回且没有错误,则你的密钥已被移动。 + +**重要提示**:现在再次键入 ``key 1`` 以取消选择第一个键,并 ``key 2`` +选择 **[S]** 密钥:: + + gpg> key 1 + gpg> key 2 + gpg> keytocard + Please select where to store the key: + (1) Signature key + (3) Authentication key + Your selection? 1 + +你可以使用 **[S]** 密钥进行签名和身份验证,但我们希望确保它位于签名槽中, +因此选择 (1)。跟之前一样,如果你的命令返回且没有错误,则操作成功:: + + gpg> q + Save changes? (y/N) y + +保存更改将删除你从主目录移动到卡上的密钥(但这没关系,因为我们还有备份, +让我们需要替换智能卡时再次执行此操作)。 + +验证密钥是否已移动 +~~~~~~~~~~~~~~~~~~ + +如果你现在执行 ``--list-secret-keys`` ,你将看到输出中存在细微的差异:: + + $ gpg --list-secret-keys + sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19] + ssb> ed25519 2022-12-20 [S] + +在 ``ssb>``中的 ``>`` 输出意味着子密钥只能在智能卡上可用,如果你返回 +密钥目录并查看那里的内容,你会注意到 ``.key`` 那里的文件已被存根替换:: + + $ cd ~/.gnupg/private-keys-v1.d + $ strings *.key | grep 'private-key' + +输出应包含 ``shadowed-private-key`` 指示这些文件只是存根,实际内容 +位于智能卡上。 + +验证智能卡是否正常工作 +~~~~~~~~~~~~~~~~~~~~~~ + +要验证智能卡是否按预期工作,你可以创建签名:: + + $ echo "Hello world" | gpg --clearsign > /tmp/test.asc + $ gpg --verify /tmp/test.asc + +在你的第一条命令执行时,应该会询问你智能卡的PIN,然后在你运行 +``gpg --verify`` 后显示"Good signature"。 + +恭喜,你已成功使窃取你的数字开发者身份变得极其困难! + +其他常见的 GnuPG 操作 +--------------------- + +以下是你需要使用 PGP 密钥执行的一些常见操作的快速参考。 + +安装你的安全离线存储 +~~~~~~~~~~~~~~~~~~~~ + +你将需要你的证书密钥来执行以下任何操作,因此你首先需要安装备份离线存储 +并告诉 GnuPG 使用它:: + + $ export GNUPGHOME=/media/disk/foo/gnupg-backup + $ gpg --list-secret-keys + +你需要确保你看到 ``sec`` 而不是 ``sec#`` 在输出中( ``#`` 意味着 +密钥不可用并且你仍在使用常规主目录位置)。 + +延长密钥有效期 +~~~~~~~~~~~~~~ + +证书密钥的默认到期日期为自创建之日起 2 年。这样做既是出于安全原因,也 +是为了使过时的密钥最终从密钥服务器中消失。 + +要将密钥的有效期从当前日期延长一年,只需运行:: + + $ gpg --quick-set-expire [fpr] 1y + +如果更容易记住,你也可以使用特定日期(例如你的生日、1 月 1 日或加拿大 +国庆日):: + + $ gpg --quick-set-expire [fpr] 2025-07-01 + +请记住将更新后的密钥发送回密钥服务器:: + + $ gpg --send-key [fpr] + +进行任何更改后更新你的工作目录 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +使用离线存储对密钥进行任何更改后,你需要将这些更改导入回常规工作目录 +中:: + + $ gpg --export | gpg --homedir ~/.gnupg --import + $ unset GNUPGHOME + +通过 ssh 使用 gpg-agent +~~~~~~~~~~~~~~~~~~~~~~~ + +如果你需要在远程系统上签署标签或提交,你可以通过 ssh 转发你的 +gpg-agent。 + +请参考 GnuPG wiki 上提供的说明: + +- `Agent通过SSH转发`_ + +如果你可以修改远程端的 sshd 服务器设置,则工作会更顺利。 + +.. _`Agent通过SSH转发`: https://wiki.gnupg.org/AgentForwarding + +将 PGP 与 Git 结合使用 +====================== + +Git 的核心功能之一是它的分散性——一旦将仓库克隆到你的系统,你就拥有该 +项目的完整历史记录,包括其所有标签、提交和分支。然而,随着数百个克隆仓 +库的出现,人们如何验证他们的 linux.git 副本没有被恶意第三方篡改? + +或者,如果在代码中发现后门,并且提交中的“Author”行表示它是由你完成的, +而你非常确定 `自己与它无关`_ ,会发生什么? + +为了解决这两个问题,Git 引入了 PGP 集成。签名的标签通过确保其内容与创 +建标签的开发人员的工作站上的内容完全相同来证明仓库的完整性,而签名的提 +交使其他人几乎不可能在无法访问你的 PGP 密钥的情况下冒充你。 + +.. _`自己与它无关`: https://github.com/jayphelps/git-blame-someone-else + +配置 git 使用你的 PGP 密钥 +-------------------------- + +如果你的密钥环中只有一个密钥,那么你实际上不需要执行任何额外操作,因为 +它会成为你的默认密钥。但是,如果你碰巧有多个密钥,你可以告诉 git 应该 +使用哪个密钥(``[fpr]`` 是你密钥的指纹):: + + $ git config --global user.signingKey [fpr] + +如何使用签名标签 +---------------- + +要创建签名标签,只需将 ``-s`` 开关传递给 tag 命令:: + + $ git tag -s [tagname] + +我们的建议是始终签署 git 标签,因为这可以让其他开发人员确保他们从中提 +取的 git 仓库没有被恶意更改。 + +如何验证签名标签 +~~~~~~~~~~~~~~~~ + +要验证签名标签,只需使用以下 ``verify-tag`` 命令:: + + $ git verify-tag [tagname] + +如果你从项目仓库的另一个分支中拉取标签,git 应该自动验证你拉取的顶 +部的签名,并在合并操作期间向你显示结果:: + + $ git pull [url] tags/sometag + +合并消息将包含如下内容:: + + Merge tag 'sometag' of [url] + + [Tag message] + + # gpg: Signature made [...] + # gpg: Good signature from [...] + +如果你正在验证其他人的 git 标签,那么你将需要导入他们的 PGP 密钥。 +请参阅下面的":ref:`身份验证`"部分。 + +配置 git 始终对带注释的标签(annotated tags)进行签名annotated tags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如果你要创建带注释的标签,你很可能会想要对其进行签名。要强制 git 始终签 +署带注释的标签,你可以设置一个全局配置选项:: + + $ git config --global tag.forceSignAnnotated true + +如何使用签名的提交 +------------------ + +创建签名提交很容易,但在 Linux 内核开发中使用它们要困难得多,因为它依赖 +于发送到邮件列表的补丁,并且此工作流程不保留 PGP 提交签名。此外,当重新 +调整仓库以匹配上游时,甚至你自己的 PGP 提交签名最终也会被丢弃。因此,大 +多数内核开发人员不会费心签署他们的提交,并且会忽略他们在工作中依赖的任何 +外部仓库中的签名提交。 + +但是,如果你的工作 git 树在某些 git 托管服务(kernel.org、 +infradead.org、ozlabs.org 或其他)上公开可用,那么建议你签署所有 git +提交,即使上游开发人员不直接受益于这种做法。 + +我们推荐这样做的原因如下: + +1. 如果需要执行代码取证或跟踪代码来源,即使是外部维护的带有 PGP 提交签名 + 的树对于此类问题也很有价值。 +2. 如果你需要重新克隆本地仓库(例如,在磁盘故障后),这可以让你在恢复工 + 作之前轻松验证仓库的完整性。 +3. 如果有人需要挑选你的提交,这可以让他们在应用之前快速验证其完整性。 + +创建签名提交 +~~~~~~~~~~~~ + +要创建签名提交,你只需将 ``-S`` 标志传递给 ``git commit`` 命令(由于 +与另一个标志冲突,所以它是大写的 ``-S`` ):: + + $ git commit -S + +配置 git 始终对提交进行签名 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +你可以告诉 git 总是签署提交:: + + git config --global commit.gpgSign true + +.. note:: + + 确保 ``gpg-agent`` 在打开此功能之前进行配置。 + +.. _身份验证: + + +如何使用签名补丁 +---------------- + +可以使用你的 PGP 密钥来签署发送到内核开发人员邮件列表的补丁。由于现有的 +电子邮件签名机制(PGP-Mime 或 PGP-inline)往往会导致常规代码审查任务 +出现问题,因此你应该使用为此创建的 kernel.org 工具,该工具将加密证明签 +名放入消息标头中(a-la DKIM): + +- `Patatt Patch Attestation`_ + +.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/ + +安装和配置 patatt +~~~~~~~~~~~~~~~~~ + +Patatt 已针对许多发行版进行了打包,因此请先检查那里。你还可以使用 +“ ``pip install patatt`` ”从 pypi 安装它。 + +如果你已经使用 git 配置了 PGP 密钥(通过``user.signingKey`` 配置参数), +则 patatt 不需要进一步配置。你可以通过在所需的仓库中安装 git-send-email +钩子来开始签署补丁:: + + patatt install-hook + +现在,你使用 ``git send-email`` 发送的任何补丁都将自动使用你的加密签 +名进行签名 + +检查 patatt 签名 +~~~~~~~~~~~~~~~~ + +如果你用于 ``b4`` 检索和应用补丁,那么它将自动尝试验证它遇到的所有 +DKIM 和 patatt 签名,例如:: + + $ b4 am 20220720205013.890942-1-broonie@kernel.org + [...] + Checking attestation on all messages, may take a moment... + --- + ✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers + ✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall + ✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls + --- + ✓ Signed: openpgp/broonie@kernel.org + ✓ Signed: DKIM/kernel.org + +.. note:: + + Patatt 和 b4 仍在积极开发中,你应该检查这些项目的最新文档以了解任 + 何新功能或更新功能。 + +如何验证内核开发者身份 +====================== + +签署标签和提交很容易,但是如何验证用于签署某项内容的密钥是否属于实际的内 +核开发人员而不是恶意冒名顶替者? + +使用 WKD 和 DANE 配置auto-key-locate(自动密钥检索) +---------------------------------------------------- + +如果你还没有广泛收集其他开发人员的公钥,那么你可以依靠密钥自动发现和自动 +检索来快速启动你的密钥环。如果从头开始创建自己的信任 Web 的预期太令人畏 +惧, GnuPG 可以借助其他委托信任技术(即 DNSSEC 和 TLS)来帮助你继续前 +进。 + +将以下内容添加到你的 ``~/.gnupg/gpg.conf``:: + + auto-key-locate wkd,dane,local + auto-key-retrieve + +基于 DNS 的命名实体身份验证(“DANE”)是一种在 DNS 中发布公钥并使用 +DNSSEC 签名区域保护它们的方法。Web 密钥目录(“WKD”)是使用 https +查找来达到相同目的的替代方法。当使用 DANE 或 WKD 查找公钥时,GnuPG +将分别验证 DNSSEC 或 TLS 证书,然后将自动检索的公钥添加到本地密钥环。 + +Kernel.org 为所有拥有 kernel.org 帐户的开发人员发布 WKD。一旦你的 +``gpg.conf`` 中进行了上述更改,你就可以自动检索 Linus Torvalds 和 +Greg Kroah-Hartman 的密钥(如果你还没有它们):: + + $ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org + +如果你有 kernel.org 帐户,那么你应该 `添加 kernel.org UID 到你的密钥中`_ +添加到你的密钥中,以使 WKD 对其他内核开发人员更有用。 + +.. _`添加 kernel.org UID 到你的密钥中`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key + +信任网 (WOT) 与首次使用信任 (TOFU) +----------------------------------- + +PGP 结合了称为“信任网”的信任委托机制。从本质上讲,这是一次尝试取代 +HTTPS/TLS 世界对集中式证书颁发机构的需求。PGP 将这一责任留给每个 +用户,而不是由各种软件制造商规定谁应该是你值得信赖的认证实体。 + +不幸的是,很少有人了解信任网是如何运作的。虽然它仍然是 OpenPGP 规 +范的一个重要方面,但最新版本的 GnuPG(2.2 及更高版本)已经实现了 +一种称为“首次使用信任”(TOFU) 的替代机制。你可以将 TOFU 视为“类似 +SSH 的信任方法”。使用 SSH,第一次连接到远程系统时,其密钥指纹会被 +记录并记住。如果将来密钥发生变化,SSH 客户端将向你发出警报并拒绝连 +接,迫使你决定是否选择信任更改后的密钥。同样,第一次导入某人的 PGP +密钥时,它被认为是有效的。如果将来的任何时候 GnuPG 遇到具有相同标 +识的另一个密钥,则先前导入的密钥和新密钥都将被标记为无效,你将需要手 +动确定保留哪一个。 + +我们建议你使用 TOFU+PGP 组合信任模型(这是 GnuPG v2 中新默认的)。 +若要设置它,在 ``~/.gnupg/gpg.conf`` 中添加(或修改) +``trust-model`` 设置:: + + trust-model tofu+pgp + +使用 kernel.org 信任网仓库 +-------------------------- + +Kernel.org 维护着一个包含开发人员公钥的 git 仓库,作为复制密钥服 +务器网络的替代品,而在过去几年中,该网络几乎已经陷入黑暗。有关如何将 +该仓库设置为公钥来源的完整文档可以在此处找到: + +- `内核开发者密钥环`_ + +如果你是内核开发人员,请考虑提交你的密钥以将其包含到该密钥环中。 + +.. _`内核开发者密钥环`: https://korg.docs.kernel.org/pgpkeys.html From a4f6a16370095aae38f47d3ea4977bcfa0c0a9d7 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 20 Nov 2023 18:02:24 +0800 Subject: [PATCH 1596/7721] docs/zh_CN: Adjust the number of characters per line in magic-number.rst to less than 40 The current lines are too long and unfriendly to developers who use vim to read documents, especially on small monitors, so let's adjust to less than 40 characters. In addition, some translations were modified incidentally. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/b3c1b55a442280c583518c45495e5540d6797548.1700474235.git.siyanteng@loongson.cn --- .../zh_CN/process/magic-number.rst | 69 +++++++++++-------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 4a92ebb619ee..4e4aeaca796c 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -1,58 +1,67 @@ -.. _cn_magicnumbers: - .. include:: ../disclaimer-zh_CN.rst -:Original: :ref:`Documentation/process/magic-number.rst ` +:Original: Documentation/process/magic-number.rst -如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可 -以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者:: +:翻译: - 中文版维护者: 贾威威 Jia Wei Wei - 中文版翻译者: 贾威威 Jia Wei Wei - 中文版校译者: 贾威威 Jia Wei Wei + 贾威威 Jia Wei Wei + +:校译: + + 司延腾 Yanteng Si Linux 魔术数 ============ -这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。 +这个文件是有关当前使用的魔术值注册表。当你给一个结构体添加了一个魔术值,你也 +应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构体的魔术值统一起来。 -使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击,或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码,例如,经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。 +使用魔术值来保护内核数据结构是一个 **非常好的主意** 。这就允许你在运行时检 +查一个结构体(a)是否已经被攻击,或者(b)你已经给一个例程传递了一个错误的结构 +体。最后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。例如, +tty源码经常通过特定驱动使用这种方法用来反复地排列特定方面的结构体。 -使用魔术值的方法是在结构的开始处声明的,如下:: +使用魔术值的方法是在结构体的开头声明它们,如下:: struct tty_ldisc { int magic; ... }; -当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,这些情况可以被快速地,安全地避免。 +当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试 +时间,特别是一些古怪的情况,例如,数组超出范围并且覆盖写了超出部分。利用这 +个规则,这些情况可以被快速地,安全地检测到这些案例。 - Theodore Ts'o - 31 Mar 94 +变更日志:: -给当前的Linux 2.1.55添加魔术表。 + Theodore Ts'o + 31 Mar 94 - Michael Chastain - - 22 Sep 1997 + 给当前的Linux 2.1.55添加魔术表。 -现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任何东西。这些条目被数域所排序。 + Michael Chastain + + 22 Sep 1997 - Krzysztof G.Baranowski - - 29 Jul 1998 + 现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任 + 何东西。这些条目被数域所排序。 -更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。 + Krzysztof G.Baranowski + + 29 Jul 1998 - Petr Baudis - - 03 Nov 2002 + 更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔 + 术值在2.6.x之前融入到内核中。 -更新魔术表到Linux 2.5.74。 + Petr Baudis + + 03 Nov 2002 - Fabian Frederick - - 09 Jul 2003 + 更新魔术表到Linux 2.5.74。 + + Fabian Frederick + + 09 Jul 2003 ===================== ================ ======================== ========================================== 魔术数名 数字 结构 文件 From c7dd2c42f1bccf993a80a032e2106b3ecb1ec1ed Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 20 Nov 2023 18:02:25 +0800 Subject: [PATCH 1597/7721] docs/zh_CN: Update process index to 6.7-rc2 Update to commit f1477dbfa562 ("docs: add backporting and conflict resolution document") Signed-off-by: Yanteng Si Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/7f79015d251b3ad88d6ea596508e39832623db9d.1700474235.git.siyanteng@loongson.cn --- .../translations/zh_CN/process/index.rst | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst index 5af0c2735902..3ca02d281be0 100644 --- a/Documentation/translations/zh_CN/process/index.rst +++ b/Documentation/translations/zh_CN/process/index.rst @@ -5,10 +5,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :ref:`Documentation/process/index.rst ` -:Translator: Alex Shi +:Original: Documentation/process/index.rst -.. _cn_process_index: +:翻译: + + Alex Shi ======================== 与Linux 内核社区一起工作 @@ -23,30 +24,55 @@ .. toctree:: :maxdepth: 1 + license-rules howto code-of-conduct code-of-conduct-interpretation + development-process submitting-patches programming-language coding-style maintainer-pgp-guide - development-process email-clients - license-rules kernel-enforcement-statement kernel-driver-statement +TODOLIST: + +* handling-regressions +* maintainer-handbooks + +安全方面, 请阅读: + +.. toctree:: + :maxdepth: 1 + + embargoed-hardware-issues + +TODOLIST: + +* security-bugs + 其它大多数开发人员感兴趣的社区指南: .. toctree:: :maxdepth: 1 - submit-checklist stable-api-nonsense - stable-kernel-rules management-style - embargoed-hardware-issues + stable-kernel-rules + submit-checklist + +TODOLIST: + +* changes +* kernel-docs +* deprecated +* maintainers +* researcher-guidelines +* contribution-maturity-model + 这些是一些总体性技术指南,由于不大好分类而放在这里: @@ -55,6 +81,16 @@ magic-number volatile-considered-harmful + ../arch/riscv/patch-acceptance + ../core-api/unaligned-memory-access + +TODOLIST: + +* applying-patches +* backporting +* adding-syscalls +* botching-up-ioctls +* clang-format .. only:: subproject and html From d254d263f6c89107a5accf5b24bc3d120ead113f Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 15 Nov 2023 18:03:30 +0100 Subject: [PATCH 1598/7721] docs: submitting-patches: improve the base commit explanation After receiving a second patchset this week without knowing which tree it applies on and trying to apply it on the obvious ones and failing, make sure the base tree information which needs to be supplied in the 0th message of the patchset is spelled out more explicitly. Also, make the formulations stronger as this really is a requirement and not only a useful thing anymore. Signed-off-by: "Borislav Petkov (AMD)" change-id: base-commit: Reviewed-by: Kees Cook Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231115170330.16626-1-bp@alien8.de --- Documentation/process/submitting-patches.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index 86d346bcb8ef..66029999b587 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -790,10 +790,14 @@ Providing base tree information ------------------------------- When other developers receive your patches and start the review process, -it is often useful for them to know where in the tree history they -should place your work. This is particularly useful for automated CI -processes that attempt to run a series of tests in order to establish -the quality of your submission before the maintainer starts the review. +it is absolutely necessary for them to know what is the base +commit/branch your work applies on, considering the sheer amount of +maintainer trees present nowadays. Note again the **T:** entry in the +MAINTAINERS file explained above. + +This is even more important for automated CI processes that attempt to +run a series of tests in order to establish the quality of your +submission before the maintainer starts the review. If you are using ``git format-patch`` to generate your patches, you can automatically include the base tree information in your submission by @@ -836,6 +840,9 @@ letter or in the first patch of the series and it should be placed either below the ``---`` line or at the very bottom of all other content, right before your email signature. +Make sure that base commit is in an official maintainer/mainline tree +and not in some internal, accessible only to you tree - otherwise it +would be worthless. References ---------- From e17049148678725248a57ecbf9c21df0fde3b434 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 20 Oct 2023 07:52:13 -0500 Subject: [PATCH 1599/7721] drm: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data in a single step. With this, adjust the includes to explicitly include the correct headers. That also serves as preparation to remove implicit includes within the DT headers (of_device.h in particular). Reviewed-by: Tomi Valkeinen Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20231020125214.2930329-1-robh@kernel.org Signed-off-by: Rob Herring --- drivers/gpu/drm/armada/armada_crtc.c | 24 +++++++----------------- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 10 ++++------ drivers/gpu/drm/exynos/exynos_drm_gsc.c | 9 +++++---- drivers/gpu/drm/imx/ipuv3/imx-ldb.c | 9 ++++----- drivers/gpu/drm/mxsfb/mxsfb_drv.c | 10 +++------- drivers/gpu/drm/omapdrm/dss/dispc.c | 4 ++-- drivers/gpu/drm/omapdrm/dss/dss.c | 5 +++-- 7 files changed, 28 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 52d2c942d3d2..c78687c755a8 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -7,8 +7,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -1012,26 +1013,17 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) int irq = platform_get_irq(pdev, 0); const struct armada_variant *variant; struct device_node *port = NULL; + struct device_node *np, *parent = dev->of_node; if (irq < 0) return irq; - if (!dev->of_node) { - const struct platform_device_id *id; - id = platform_get_device_id(pdev); - if (!id) - return -ENXIO; - - variant = (const struct armada_variant *)id->driver_data; - } else { - const struct of_device_id *match; - struct device_node *np, *parent = dev->of_node; - - match = of_match_device(dev->driver->of_match_table, dev); - if (!match) - return -ENXIO; + variant = device_get_match_data(dev); + if (!variant) + return -ENXIO; + if (parent) { np = of_get_child_by_name(parent, "ports"); if (np) parent = np; @@ -1041,8 +1033,6 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) dev_err(dev, "no port node found in %pOF\n", parent); return -ENXIO; } - - variant = match->data; } return armada_drm_crtc_create(drm, dev, res, irq, variant, port); diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index 78122b35a0cb..a7a6b70220eb 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -6,10 +6,10 @@ #include #include #include -#include -#include +#include #include #include +#include #include #include @@ -143,7 +143,6 @@ static int aspeed_gfx_load(struct drm_device *drm) struct aspeed_gfx *priv = to_aspeed_gfx(drm); struct device_node *np = pdev->dev.of_node; const struct aspeed_gfx_config *config; - const struct of_device_id *match; struct resource *res; int ret; @@ -152,10 +151,9 @@ static int aspeed_gfx_load(struct drm_device *drm) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - match = of_match_device(aspeed_gfx_match, &pdev->dev); - if (!match) + config = device_get_match_data(&pdev->dev); + if (!config) return -EINVAL; - config = match->data; priv->dac_reg = config->dac_reg; priv->int_clr_reg = config->int_clear_reg; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 34cdabc30b4f..35771fb4e85d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -11,9 +11,10 @@ #include #include #include -#include +#include #include #include +#include #include #include @@ -103,7 +104,7 @@ struct gsc_context { unsigned int num_formats; void __iomem *regs; - const char **clk_names; + const char *const *clk_names; struct clk *clocks[GSC_MAX_CLOCKS]; int num_clocks; struct gsc_scaler sc; @@ -1217,7 +1218,7 @@ static const unsigned int gsc_tiled_formats[] = { static int gsc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct gsc_driverdata *driver_data; + const struct gsc_driverdata *driver_data; struct exynos_drm_ipp_formats *formats; struct gsc_context *ctx; int num_formats, ret, i, j; @@ -1226,7 +1227,7 @@ static int gsc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev); + driver_data = device_get_match_data(dev); ctx->dev = dev; ctx->num_clocks = driver_data->num_clocks; ctx->clk_names = driver_data->clk_names; diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index 989eca32d325..53840ab054c7 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -12,8 +12,10 @@ #include #include #include -#include +#include #include +#include +#include #include #include @@ -617,7 +619,6 @@ static int imx_ldb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev); struct device_node *child; struct imx_ldb *imx_ldb; int dual; @@ -638,9 +639,7 @@ static int imx_ldb_probe(struct platform_device *pdev) regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); imx_ldb->dev = dev; - - if (of_id) - imx_ldb->lvds_mux = of_id->data; + imx_ldb->lvds_mux = device_get_match_data(dev); dual = of_property_read_bool(np, "fsl,dual-channel"); if (dual) diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 625c1bfc4173..b483ef48216a 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -11,9 +11,10 @@ #include #include #include +#include #include -#include #include +#include #include #include @@ -346,18 +347,13 @@ MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); static int mxsfb_probe(struct platform_device *pdev) { struct drm_device *drm; - const struct of_device_id *of_id = - of_match_device(mxsfb_dt_ids, &pdev->dev); int ret; - if (!pdev->dev.of_node) - return -ENODEV; - drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); if (IS_ERR(drm)) return PTR_ERR(drm); - ret = mxsfb_load(drm, of_id->data); + ret = mxsfb_load(drm, device_get_match_data(&pdev->dev)); if (ret) goto err_free; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index c26aab4939fa..993691b3cc7e 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -4765,7 +4765,7 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) if (soc) dispc->feat = soc->data; else - dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data; + dispc->feat = device_get_match_data(&pdev->dev); r = dispc_errata_i734_wa_init(dispc); if (r) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 02955f976845..988888e164d7 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -22,12 +22,13 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -1445,7 +1446,7 @@ static int dss_probe(struct platform_device *pdev) if (soc) dss->feat = soc->data; else - dss->feat = of_match_device(dss_of_match, &pdev->dev)->data; + dss->feat = device_get_match_data(&pdev->dev); /* Map I/O registers, get and setup clocks. */ dss->base = devm_platform_ioremap_resource(pdev, 0); From d6e035aad6c09991da1c667fb83419329a3baed8 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 8 Nov 2023 10:22:15 -0800 Subject: [PATCH 1600/7721] md: bypass block throttle for superblock update commit 5e2cf333b7bd ("md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d") introduced a hung bug and will be reverted in next patch, since the issue that commit is fixing is due to md superblock write is throttled by wbt, to fix it, we can have superblock write bypass block layer throttle. Fixes: 5e2cf333b7bd ("md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d") Cc: stable@vger.kernel.org # v5.19+ Suggested-by: Yu Kuai Signed-off-by: Junxiao Bi Reviewed-by: Logan Gunthorpe Reviewed-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231108182216.73611-1-junxiao.bi@oracle.com --- drivers/md/md.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index c94373d64f2c..466bbcb4e230 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1013,9 +1013,10 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, return; bio = bio_alloc_bioset(rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev, - 1, - REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH | REQ_FUA, - GFP_NOIO, &mddev->sync_set); + 1, + REQ_OP_WRITE | REQ_SYNC | REQ_IDLE | REQ_META + | REQ_PREFLUSH | REQ_FUA, + GFP_NOIO, &mddev->sync_set); atomic_inc(&rdev->nr_pending); From bed9e27baf52a09b7ba2a3714f1e24e17ced386d Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 8 Nov 2023 10:22:16 -0800 Subject: [PATCH 1601/7721] Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d" This reverts commit 5e2cf333b7bd5d3e62595a44d598a254c697cd74. That commit introduced the following race and can cause system hung. md_write_start: raid5d: // mddev->in_sync == 1 set "MD_SB_CHANGE_PENDING" // running before md_write_start wakeup it waiting "MD_SB_CHANGE_PENDING" cleared >>>>>>>>> hung wakeup mddev->thread ... waiting "MD_SB_CHANGE_PENDING" cleared >>>> hung, raid5d should clear this flag but get hung by same flag. The issue reverted commit fixing is fixed by last patch in a new way. Fixes: 5e2cf333b7bd ("md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d") Cc: stable@vger.kernel.org # v5.19+ Signed-off-by: Junxiao Bi Reviewed-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231108182216.73611-2-junxiao.bi@oracle.com --- drivers/md/raid5.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dc031d42f53b..fcc8a44dd4fd 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -36,7 +36,6 @@ */ #include -#include #include #include #include @@ -6820,18 +6819,7 @@ static void raid5d(struct md_thread *thread) spin_unlock_irq(&conf->device_lock); md_check_recovery(mddev); spin_lock_irq(&conf->device_lock); - - /* - * Waiting on MD_SB_CHANGE_PENDING below may deadlock - * seeing md_check_recovery() is needed to clear - * the flag when using mdmon. - */ - continue; } - - wait_event_lock_irq(mddev->sb_wait, - !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags), - conf->device_lock); } pr_debug("%d stripes handled\n", handled); From c891f1fd90e66e584bb1353e1859cef7c9eb36f8 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Sat, 25 Nov 2023 16:16:00 +0800 Subject: [PATCH 1602/7721] md: remove flag RemoveSynchronized rcu is not used correctly here, because synchronize_rcu() is called before replacing old value, for example: remove_and_add_spares // other path synchronize_rcu // called before replacing old value set_bit(RemoveSynchronized) rcu_read_lock() rdev = conf->mirros[].rdev pers->hot_remove_disk conf->mirros[].rdev = NULL; if (!test_bit(RemoveSynchronized)) synchronize_rcu /* * won't be called, and won't wait * for concurrent readers to be done. */ // access rdev after remove_and_add_spares() rcu_read_unlock() Fortunately, there is a separate rcu protection to prevent such rdev to be freed: md_kick_rdev_from_array //other path rcu_read_lock() rdev = conf->mirros[].rdev list_del_rcu(&rdev->same_set) rcu_read_unlock() /* * rdev can be removed from conf, but * rdev won't be freed. */ synchronize_rcu() free rdev Hence remove this useless flag and prepare to remove rcu protection to access rdev from 'conf'. Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231125081604.3939938-2-yukuai1@huaweicloud.com --- drivers/md/md-multipath.c | 9 --------- drivers/md/md.c | 37 ++++++------------------------------- drivers/md/md.h | 5 ----- drivers/md/raid1.c | 9 --------- drivers/md/raid10.c | 9 --------- drivers/md/raid5.c | 9 --------- 6 files changed, 6 insertions(+), 72 deletions(-) diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c index d22276870283..aa77133f3188 100644 --- a/drivers/md/md-multipath.c +++ b/drivers/md/md-multipath.c @@ -258,15 +258,6 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev) goto abort; } p->rdev = NULL; - if (!test_bit(RemoveSynchronized, &rdev->flags)) { - synchronize_rcu(); - if (atomic_read(&rdev->nr_pending)) { - /* lost the race, try later */ - err = -EBUSY; - p->rdev = rdev; - goto abort; - } - } err = md_integrity_register(mddev); } abort: diff --git a/drivers/md/md.c b/drivers/md/md.c index 466bbcb4e230..71b3397dea47 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -9244,46 +9244,21 @@ static int remove_and_add_spares(struct mddev *mddev, struct md_rdev *rdev; int spares = 0; int removed = 0; - bool remove_some = false; if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) /* Mustn't remove devices when resync thread is running */ return 0; rdev_for_each(rdev, mddev) { - if ((this == NULL || rdev == this) && - rdev->raid_disk >= 0 && - !test_bit(Blocked, &rdev->flags) && - test_bit(Faulty, &rdev->flags) && - atomic_read(&rdev->nr_pending)==0) { - /* Faulty non-Blocked devices with nr_pending == 0 - * never get nr_pending incremented, - * never get Faulty cleared, and never get Blocked set. - * So we can synchronize_rcu now rather than once per device - */ - remove_some = true; - set_bit(RemoveSynchronized, &rdev->flags); + if ((this == NULL || rdev == this) && rdev_removeable(rdev) && + !mddev->pers->hot_remove_disk(mddev, rdev)) { + sysfs_unlink_rdev(mddev, rdev); + rdev->saved_raid_disk = rdev->raid_disk; + rdev->raid_disk = -1; + removed++; } } - if (remove_some) - synchronize_rcu(); - rdev_for_each(rdev, mddev) { - if ((this == NULL || rdev == this) && - (test_bit(RemoveSynchronized, &rdev->flags) || - rdev_removeable(rdev))) { - if (mddev->pers->hot_remove_disk( - mddev, rdev) == 0) { - sysfs_unlink_rdev(mddev, rdev); - rdev->saved_raid_disk = rdev->raid_disk; - rdev->raid_disk = -1; - removed++; - } - } - if (remove_some && test_bit(RemoveSynchronized, &rdev->flags)) - clear_bit(RemoveSynchronized, &rdev->flags); - } - if (removed && mddev->kobj.sd) sysfs_notify_dirent_safe(mddev->sysfs_degraded); diff --git a/drivers/md/md.h b/drivers/md/md.h index ade83af123a2..8d881cc59799 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -190,11 +190,6 @@ enum flag_bits { * than other devices in the array */ ClusterRemove, - RemoveSynchronized, /* synchronize_rcu() was called after - * this device was known to be faulty, - * so it is safe to remove without - * another synchronize_rcu() call. - */ ExternalBbl, /* External metadata provides bad * block management for a disk */ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 35d12948e0a9..a678e0e6e102 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1863,15 +1863,6 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) goto abort; } p->rdev = NULL; - if (!test_bit(RemoveSynchronized, &rdev->flags)) { - synchronize_rcu(); - if (atomic_read(&rdev->nr_pending)) { - /* lost the race, try later */ - err = -EBUSY; - p->rdev = rdev; - goto abort; - } - } if (conf->mirrors[conf->raid_disks + number].rdev) { /* We just removed a device that is being replaced. * Move down the replacement. We drain all IO before diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a5927e98dc67..132a79523338 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2247,15 +2247,6 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev) goto abort; } *rdevp = NULL; - if (!test_bit(RemoveSynchronized, &rdev->flags)) { - synchronize_rcu(); - if (atomic_read(&rdev->nr_pending)) { - /* lost the race, try later */ - err = -EBUSY; - *rdevp = rdev; - goto abort; - } - } if (p->replacement) { /* We must have just cleared 'rdev' */ p->rdev = p->replacement; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index fcc8a44dd4fd..d431e4625cc5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -8233,15 +8233,6 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) goto abort; } *rdevp = NULL; - if (!test_bit(RemoveSynchronized, &rdev->flags)) { - lockdep_assert_held(&mddev->reconfig_mutex); - synchronize_rcu(); - if (atomic_read(&rdev->nr_pending)) { - /* lost the race, try later */ - err = -EBUSY; - rcu_assign_pointer(*rdevp, rdev); - } - } if (!err) { err = log_modify(conf, rdev, false); if (err) From a448af25becf4b555660b5ba2618c7ed3c4de6da Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Sat, 25 Nov 2023 16:16:01 +0800 Subject: [PATCH 1603/7721] md/raid10: remove rcu protection to access rdev from conf Because it's safe to accees rdev from conf: - If any spinlock is held, because synchronize_rcu() from md_kick_rdev_from_array() will prevent 'rdev' to be freed until spinlock is released; - If 'reconfig_lock' is held, because rdev can't be added or removed from array; - If there is normal IO inflight, because mddev_suspend() will prevent rdev to be added or removed from array; - If there is sync IO inflight, because 'MD_RECOVERY_RUNNING' is checked in remove_and_add_spares(). And these will cover all the scenarios in raid10. This patch also cleanup the code to handle the case that replacement replace rdev while IO is still inflight. Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231125081604.3939938-3-yukuai1@huaweicloud.com --- drivers/md/raid10.c | 213 ++++++++++++-------------------------------- 1 file changed, 58 insertions(+), 155 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 132a79523338..375c11d6159f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -743,7 +743,6 @@ static struct md_rdev *read_balance(struct r10conf *conf, struct geom *geo = &conf->geo; raid10_find_phys(conf, r10_bio); - rcu_read_lock(); best_dist_slot = -1; min_pending = UINT_MAX; best_dist_rdev = NULL; @@ -775,18 +774,11 @@ static struct md_rdev *read_balance(struct r10conf *conf, if (r10_bio->devs[slot].bio == IO_BLOCKED) continue; disk = r10_bio->devs[slot].devnum; - rdev = rcu_dereference(conf->mirrors[disk].replacement); + rdev = conf->mirrors[disk].replacement; if (rdev == NULL || test_bit(Faulty, &rdev->flags) || r10_bio->devs[slot].addr + sectors > - rdev->recovery_offset) { - /* - * Read replacement first to prevent reading both rdev - * and replacement as NULL during replacement replace - * rdev. - */ - smp_mb(); - rdev = rcu_dereference(conf->mirrors[disk].rdev); - } + rdev->recovery_offset) + rdev = conf->mirrors[disk].rdev; if (rdev == NULL || test_bit(Faulty, &rdev->flags)) continue; @@ -876,7 +868,6 @@ static struct md_rdev *read_balance(struct r10conf *conf, r10_bio->read_slot = slot; } else rdev = NULL; - rcu_read_unlock(); *max_sectors = best_good_sectors; return rdev; @@ -1198,9 +1189,8 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, */ gfp = GFP_NOIO | __GFP_HIGH; - rcu_read_lock(); disk = r10_bio->devs[slot].devnum; - err_rdev = rcu_dereference(conf->mirrors[disk].rdev); + err_rdev = conf->mirrors[disk].rdev; if (err_rdev) snprintf(b, sizeof(b), "%pg", err_rdev->bdev); else { @@ -1208,7 +1198,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, /* This never gets dereferenced */ err_rdev = r10_bio->devs[slot].rdev; } - rcu_read_unlock(); } if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) @@ -1279,15 +1268,8 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, int devnum = r10_bio->devs[n_copy].devnum; struct bio *mbio; - if (replacement) { - rdev = conf->mirrors[devnum].replacement; - if (rdev == NULL) { - /* Replacement just got moved to main 'rdev' */ - smp_mb(); - rdev = conf->mirrors[devnum].rdev; - } - } else - rdev = conf->mirrors[devnum].rdev; + rdev = replacement ? conf->mirrors[devnum].replacement : + conf->mirrors[devnum].rdev; mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO, &mddev->bio_set); if (replacement) @@ -1321,25 +1303,6 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, } } -static struct md_rdev *dereference_rdev_and_rrdev(struct raid10_info *mirror, - struct md_rdev **prrdev) -{ - struct md_rdev *rdev, *rrdev; - - rrdev = rcu_dereference(mirror->replacement); - /* - * Read replacement first to prevent reading both rdev and - * replacement as NULL during replacement replace rdev. - */ - smp_mb(); - rdev = rcu_dereference(mirror->rdev); - if (rdev == rrdev) - rrdev = NULL; - - *prrdev = rrdev; - return rdev; -} - static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) { int i; @@ -1348,11 +1311,11 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) retry_wait: blocked_rdev = NULL; - rcu_read_lock(); for (i = 0; i < conf->copies; i++) { struct md_rdev *rdev, *rrdev; - rdev = dereference_rdev_and_rrdev(&conf->mirrors[i], &rrdev); + rdev = conf->mirrors[i].rdev; + rrdev = conf->mirrors[i].replacement; if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { atomic_inc(&rdev->nr_pending); blocked_rdev = rdev; @@ -1391,7 +1354,6 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) } } } - rcu_read_unlock(); if (unlikely(blocked_rdev)) { /* Have to wait for this device to get unblocked, then retry */ @@ -1474,14 +1436,14 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, wait_blocked_dev(mddev, r10_bio); - rcu_read_lock(); max_sectors = r10_bio->sectors; for (i = 0; i < conf->copies; i++) { int d = r10_bio->devs[i].devnum; struct md_rdev *rdev, *rrdev; - rdev = dereference_rdev_and_rrdev(&conf->mirrors[d], &rrdev); + rdev = conf->mirrors[d].rdev; + rrdev = conf->mirrors[d].replacement; if (rdev && (test_bit(Faulty, &rdev->flags))) rdev = NULL; if (rrdev && (test_bit(Faulty, &rrdev->flags))) @@ -1535,7 +1497,6 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, atomic_inc(&rrdev->nr_pending); } } - rcu_read_unlock(); if (max_sectors < r10_bio->sectors) r10_bio->sectors = max_sectors; @@ -1625,17 +1586,8 @@ static void raid10_end_discard_request(struct bio *bio) set_bit(R10BIO_Uptodate, &r10_bio->state); dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl); - if (repl) - rdev = conf->mirrors[dev].replacement; - if (!rdev) { - /* - * raid10_remove_disk uses smp_mb to make sure rdev is set to - * replacement before setting replacement to NULL. It can read - * rdev first without barrier protect even replacement is NULL - */ - smp_rmb(); - rdev = conf->mirrors[dev].rdev; - } + rdev = repl ? conf->mirrors[dev].replacement : + conf->mirrors[dev].rdev; raid_end_discard_bio(r10_bio); rdev_dec_pending(rdev, conf->mddev); @@ -1785,11 +1737,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ - rcu_read_lock(); for (disk = 0; disk < geo->raid_disks; disk++) { struct md_rdev *rdev, *rrdev; - rdev = dereference_rdev_and_rrdev(&conf->mirrors[disk], &rrdev); + rdev = conf->mirrors[disk].rdev; + rrdev = conf->mirrors[disk].replacement; r10_bio->devs[disk].bio = NULL; r10_bio->devs[disk].repl_bio = NULL; @@ -1809,7 +1761,6 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) atomic_inc(&rrdev->nr_pending); } } - rcu_read_unlock(); atomic_set(&r10_bio->remaining, 1); for (disk = 0; disk < geo->raid_disks; disk++) { @@ -1939,6 +1890,8 @@ static void raid10_status(struct seq_file *seq, struct mddev *mddev) struct r10conf *conf = mddev->private; int i; + lockdep_assert_held(&mddev->lock); + if (conf->geo.near_copies < conf->geo.raid_disks) seq_printf(seq, " %dK chunks", mddev->chunk_sectors / 2); if (conf->geo.near_copies > 1) @@ -1953,12 +1906,11 @@ static void raid10_status(struct seq_file *seq, struct mddev *mddev) } seq_printf(seq, " [%d/%d] [", conf->geo.raid_disks, conf->geo.raid_disks - mddev->degraded); - rcu_read_lock(); for (i = 0; i < conf->geo.raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = READ_ONCE(conf->mirrors[i].rdev); + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); } - rcu_read_unlock(); seq_printf(seq, "]"); } @@ -1980,7 +1932,6 @@ static int _enough(struct r10conf *conf, int previous, int ignore) ncopies = conf->geo.near_copies; } - rcu_read_lock(); do { int n = conf->copies; int cnt = 0; @@ -1988,7 +1939,7 @@ static int _enough(struct r10conf *conf, int previous, int ignore) while (n--) { struct md_rdev *rdev; if (this != ignore && - (rdev = rcu_dereference(conf->mirrors[this].rdev)) && + (rdev = conf->mirrors[this].rdev) && test_bit(In_sync, &rdev->flags)) cnt++; this = (this+1) % disks; @@ -1999,7 +1950,6 @@ static int _enough(struct r10conf *conf, int previous, int ignore) } while (first != 0); has_enough = 1; out: - rcu_read_unlock(); return has_enough; } @@ -2072,8 +2022,7 @@ static void print_conf(struct r10conf *conf) pr_debug(" --- wd:%d rd:%d\n", conf->geo.raid_disks - conf->mddev->degraded, conf->geo.raid_disks); - /* This is only called with ->reconfix_mutex held, so - * rcu protection of rdev is not needed */ + lockdep_assert_held(&conf->mddev->reconfig_mutex); for (i = 0; i < conf->geo.raid_disks; i++) { rdev = conf->mirrors[i].rdev; if (rdev) @@ -2190,7 +2139,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) err = 0; if (rdev->saved_raid_disk != mirror) conf->fullsync = 1; - rcu_assign_pointer(p->rdev, rdev); + WRITE_ONCE(p->rdev, rdev); break; } @@ -2204,7 +2153,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); conf->fullsync = 1; - rcu_assign_pointer(p->replacement, rdev); + WRITE_ONCE(p->replacement, rdev); } print_conf(conf); @@ -2246,15 +2195,12 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev) err = -EBUSY; goto abort; } - *rdevp = NULL; + WRITE_ONCE(*rdevp, NULL); if (p->replacement) { /* We must have just cleared 'rdev' */ - p->rdev = p->replacement; + WRITE_ONCE(p->rdev, p->replacement); clear_bit(Replacement, &p->replacement->flags); - smp_mb(); /* Make sure other CPUs may see both as identical - * but will never see neither -- if they are careful. - */ - p->replacement = NULL; + WRITE_ONCE(p->replacement, NULL); } clear_bit(WantReplacement, &rdev->flags); @@ -2754,20 +2700,18 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 if (s > (PAGE_SIZE>>9)) s = PAGE_SIZE >> 9; - rcu_read_lock(); do { sector_t first_bad; int bad_sectors; d = r10_bio->devs[sl].devnum; - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags) && is_badblock(rdev, r10_bio->devs[sl].addr + sect, s, &first_bad, &bad_sectors) == 0) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); success = sync_page_io(rdev, r10_bio->devs[sl].addr + sect, @@ -2775,7 +2719,6 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 conf->tmppage, REQ_OP_READ, false); rdev_dec_pending(rdev, mddev); - rcu_read_lock(); if (success) break; } @@ -2783,7 +2726,6 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 if (sl == conf->copies) sl = 0; } while (sl != slot); - rcu_read_unlock(); if (!success) { /* Cannot read from anywhere, just mark the block @@ -2807,20 +2749,18 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 start = sl; /* write it back and re-read */ - rcu_read_lock(); while (sl != slot) { if (sl==0) sl = conf->copies; sl--; d = r10_bio->devs[sl].devnum; - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (!rdev || test_bit(Faulty, &rdev->flags) || !test_bit(In_sync, &rdev->flags)) continue; atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); if (r10_sync_page_io(rdev, r10_bio->devs[sl].addr + sect, @@ -2839,7 +2779,6 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 rdev->bdev); } rdev_dec_pending(rdev, mddev); - rcu_read_lock(); } sl = start; while (sl != slot) { @@ -2847,14 +2786,13 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 sl = conf->copies; sl--; d = r10_bio->devs[sl].devnum; - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (!rdev || test_bit(Faulty, &rdev->flags) || !test_bit(In_sync, &rdev->flags)) continue; atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); switch (r10_sync_page_io(rdev, r10_bio->devs[sl].addr + sect, @@ -2882,9 +2820,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 } rdev_dec_pending(rdev, mddev); - rcu_read_lock(); } - rcu_read_unlock(); sectors -= s; sect += s; @@ -3358,14 +3294,13 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, /* Completed a full sync so the replacements * are now fully recovered. */ - rcu_read_lock(); for (i = 0; i < conf->geo.raid_disks; i++) { struct md_rdev *rdev = - rcu_dereference(conf->mirrors[i].replacement); + conf->mirrors[i].replacement; + if (rdev) rdev->recovery_offset = MaxSector; } - rcu_read_unlock(); } conf->fullsync = 0; } @@ -3446,9 +3381,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, struct raid10_info *mirror = &conf->mirrors[i]; struct md_rdev *mrdev, *mreplace; - rcu_read_lock(); - mrdev = rcu_dereference(mirror->rdev); - mreplace = rcu_dereference(mirror->replacement); + mrdev = mirror->rdev; + mreplace = mirror->replacement; if (mrdev && (test_bit(Faulty, &mrdev->flags) || test_bit(In_sync, &mrdev->flags))) @@ -3456,22 +3390,18 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, if (mreplace && test_bit(Faulty, &mreplace->flags)) mreplace = NULL; - if (!mrdev && !mreplace) { - rcu_read_unlock(); + if (!mrdev && !mreplace) continue; - } still_degraded = 0; /* want to reconstruct this device */ rb2 = r10_bio; sect = raid10_find_virt(conf, sector_nr, i); - if (sect >= mddev->resync_max_sectors) { + if (sect >= mddev->resync_max_sectors) /* last stripe is not complete - don't * try to recover this sector. */ - rcu_read_unlock(); continue; - } /* Unless we are doing a full sync, or a replacement * we only need to recover the block if it is set in * the bitmap @@ -3487,14 +3417,12 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, * that there will never be anything to do here */ chunks_skipped = -1; - rcu_read_unlock(); continue; } if (mrdev) atomic_inc(&mrdev->nr_pending); if (mreplace) atomic_inc(&mreplace->nr_pending); - rcu_read_unlock(); r10_bio = raid10_alloc_init_r10buf(conf); r10_bio->state = 0; @@ -3513,10 +3441,9 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, /* Need to check if the array will still be * degraded */ - rcu_read_lock(); for (j = 0; j < conf->geo.raid_disks; j++) { - struct md_rdev *rdev = rcu_dereference( - conf->mirrors[j].rdev); + struct md_rdev *rdev = conf->mirrors[j].rdev; + if (rdev == NULL || test_bit(Faulty, &rdev->flags)) { still_degraded = 1; break; @@ -3531,8 +3458,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, int k; int d = r10_bio->devs[j].devnum; sector_t from_addr, to_addr; - struct md_rdev *rdev = - rcu_dereference(conf->mirrors[d].rdev); + struct md_rdev *rdev = conf->mirrors[d].rdev; sector_t sector, first_bad; int bad_sectors; if (!rdev || @@ -3611,7 +3537,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, atomic_inc(&r10_bio->remaining); break; } - rcu_read_unlock(); if (j == conf->copies) { /* Cannot recover, so abort the recovery or * record a bad block */ @@ -3738,12 +3663,10 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, bio = r10_bio->devs[i].bio; bio->bi_status = BLK_STS_IOERR; - rcu_read_lock(); - rdev = rcu_dereference(conf->mirrors[d].rdev); - if (rdev == NULL || test_bit(Faulty, &rdev->flags)) { - rcu_read_unlock(); + rdev = conf->mirrors[d].rdev; + if (rdev == NULL || test_bit(Faulty, &rdev->flags)) continue; - } + sector = r10_bio->devs[i].addr; if (is_badblock(rdev, sector, max_sync, &first_bad, &bad_sectors)) { @@ -3753,7 +3676,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, bad_sectors -= (sector - first_bad); if (max_sync > bad_sectors) max_sync = bad_sectors; - rcu_read_unlock(); continue; } } @@ -3769,11 +3691,10 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, bio_set_dev(bio, rdev->bdev); count++; - rdev = rcu_dereference(conf->mirrors[d].replacement); - if (rdev == NULL || test_bit(Faulty, &rdev->flags)) { - rcu_read_unlock(); + rdev = conf->mirrors[d].replacement; + if (rdev == NULL || test_bit(Faulty, &rdev->flags)) continue; - } + atomic_inc(&rdev->nr_pending); /* Need to set up for writing to the replacement */ @@ -3790,7 +3711,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_iter.bi_sector = sector + rdev->data_offset; bio_set_dev(bio, rdev->bdev); count++; - rcu_read_unlock(); } if (count < 2) { @@ -4500,11 +4420,11 @@ static int calc_degraded(struct r10conf *conf) int degraded, degraded2; int i; - rcu_read_lock(); degraded = 0; /* 'prev' section first */ for (i = 0; i < conf->prev.raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = conf->mirrors[i].rdev; + if (!rdev || test_bit(Faulty, &rdev->flags)) degraded++; else if (!test_bit(In_sync, &rdev->flags)) @@ -4514,13 +4434,12 @@ static int calc_degraded(struct r10conf *conf) */ degraded++; } - rcu_read_unlock(); if (conf->geo.raid_disks == conf->prev.raid_disks) return degraded; - rcu_read_lock(); degraded2 = 0; for (i = 0; i < conf->geo.raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = conf->mirrors[i].rdev; + if (!rdev || test_bit(Faulty, &rdev->flags)) degraded2++; else if (!test_bit(In_sync, &rdev->flags)) { @@ -4533,7 +4452,6 @@ static int calc_degraded(struct r10conf *conf) degraded2++; } } - rcu_read_unlock(); if (degraded2 > degraded) return degraded2; return degraded; @@ -4965,16 +4883,15 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, blist = read_bio; read_bio->bi_next = NULL; - rcu_read_lock(); for (s = 0; s < conf->copies*2; s++) { struct bio *b; int d = r10_bio->devs[s/2].devnum; struct md_rdev *rdev2; if (s&1) { - rdev2 = rcu_dereference(conf->mirrors[d].replacement); + rdev2 = conf->mirrors[d].replacement; b = r10_bio->devs[s/2].repl_bio; } else { - rdev2 = rcu_dereference(conf->mirrors[d].rdev); + rdev2 = conf->mirrors[d].rdev; b = r10_bio->devs[s/2].bio; } if (!rdev2 || test_bit(Faulty, &rdev2->flags)) @@ -5008,7 +4925,6 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, sector_nr += len >> 9; nr_sectors += len >> 9; } - rcu_read_unlock(); r10_bio->sectors = nr_sectors; /* Now submit the read */ @@ -5061,20 +4977,17 @@ static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio) struct bio *b; int d = r10_bio->devs[s/2].devnum; struct md_rdev *rdev; - rcu_read_lock(); if (s&1) { - rdev = rcu_dereference(conf->mirrors[d].replacement); + rdev = conf->mirrors[d].replacement; b = r10_bio->devs[s/2].repl_bio; } else { - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; b = r10_bio->devs[s/2].bio; } - if (!rdev || test_bit(Faulty, &rdev->flags)) { - rcu_read_unlock(); + if (!rdev || test_bit(Faulty, &rdev->flags)) continue; - } + atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); md_sync_acct_bio(b, r10_bio->sectors); atomic_inc(&r10_bio->remaining); b->bi_next = NULL; @@ -5145,10 +5058,9 @@ static int handle_reshape_read_error(struct mddev *mddev, if (s > (PAGE_SIZE >> 9)) s = PAGE_SIZE >> 9; - rcu_read_lock(); while (!success) { int d = r10b->devs[slot].devnum; - struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev); + struct md_rdev *rdev = conf->mirrors[d].rdev; sector_t addr; if (rdev == NULL || test_bit(Faulty, &rdev->flags) || @@ -5157,14 +5069,12 @@ static int handle_reshape_read_error(struct mddev *mddev, addr = r10b->devs[slot].addr + idx * PAGE_SIZE; atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); success = sync_page_io(rdev, addr, s << 9, pages[idx], REQ_OP_READ, false); rdev_dec_pending(rdev, mddev); - rcu_read_lock(); if (success) break; failed: @@ -5174,7 +5084,6 @@ static int handle_reshape_read_error(struct mddev *mddev, if (slot == first_slot) break; } - rcu_read_unlock(); if (!success) { /* couldn't read this block, must give up */ set_bit(MD_RECOVERY_INTR, @@ -5200,12 +5109,8 @@ static void end_reshape_write(struct bio *bio) struct md_rdev *rdev = NULL; d = find_bio_disk(conf, r10_bio, bio, &slot, &repl); - if (repl) - rdev = conf->mirrors[d].replacement; - if (!rdev) { - smp_mb(); - rdev = conf->mirrors[d].rdev; - } + rdev = repl ? conf->mirrors[d].replacement : + conf->mirrors[d].rdev; if (bio->bi_status) { /* FIXME should record badblock */ @@ -5240,18 +5145,16 @@ static void raid10_finish_reshape(struct mddev *mddev) mddev->resync_max_sectors = mddev->array_sectors; } else { int d; - rcu_read_lock(); for (d = conf->geo.raid_disks ; d < conf->geo.raid_disks - mddev->delta_disks; d++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev); + struct md_rdev *rdev = conf->mirrors[d].rdev; if (rdev) clear_bit(In_sync, &rdev->flags); - rdev = rcu_dereference(conf->mirrors[d].replacement); + rdev = conf->mirrors[d].replacement; if (rdev) clear_bit(In_sync, &rdev->flags); } - rcu_read_unlock(); } mddev->layout = mddev->new_layout; mddev->chunk_sectors = 1 << conf->geo.chunk_shift; From 2d32777d60de81aa020a2431567020af26564c71 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Sat, 25 Nov 2023 16:16:02 +0800 Subject: [PATCH 1604/7721] md/raid1: remove rcu protection to access rdev from conf Because it's safe to accees rdev from conf: - If any spinlock is held, because synchronize_rcu() from md_kick_rdev_from_array() will prevent 'rdev' to be freed until spinlock is released; - If 'reconfig_lock' is held, because rdev can't be added or removed from array; - If there is normal IO inflight, because mddev_suspend() will prevent rdev to be added or removed from array; - If there is sync IO inflight, because 'MD_RECOVERY_RUNNING' is checked in remove_and_add_spares(). And these will cover all the scenarios in raid1. Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231125081604.3939938-4-yukuai1@huaweicloud.com --- drivers/md/raid1.c | 62 +++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a678e0e6e102..9348f1709512 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -609,7 +609,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect int choose_first; int choose_next_idle; - rcu_read_lock(); /* * Check if we can balance. We can balance on the whole * device if no resync is going on, or below the resync window. @@ -642,7 +641,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect unsigned int pending; bool nonrot; - rdev = rcu_dereference(conf->mirrors[disk].rdev); + rdev = conf->mirrors[disk].rdev; if (r1_bio->bios[disk] == IO_BLOCKED || rdev == NULL || test_bit(Faulty, &rdev->flags)) @@ -773,7 +772,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect } if (best_disk >= 0) { - rdev = rcu_dereference(conf->mirrors[best_disk].rdev); + rdev = conf->mirrors[best_disk].rdev; if (!rdev) goto retry; atomic_inc(&rdev->nr_pending); @@ -784,7 +783,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect conf->mirrors[best_disk].next_seq_sect = this_sector + sectors; } - rcu_read_unlock(); *max_sectors = sectors; return best_disk; @@ -1235,14 +1233,12 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, if (r1bio_existed) { /* Need to get the block device name carefully */ - struct md_rdev *rdev; - rcu_read_lock(); - rdev = rcu_dereference(conf->mirrors[r1_bio->read_disk].rdev); + struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev; + if (rdev) snprintf(b, sizeof(b), "%pg", rdev->bdev); else strcpy(b, "???"); - rcu_read_unlock(); } /* @@ -1396,10 +1392,9 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, disks = conf->raid_disks * 2; blocked_rdev = NULL; - rcu_read_lock(); max_sectors = r1_bio->sectors; for (i = 0; i < disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = conf->mirrors[i].rdev; /* * The write-behind io is only attempted on drives marked as @@ -1465,7 +1460,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, } r1_bio->bios[i] = bio; } - rcu_read_unlock(); if (unlikely(blocked_rdev)) { /* Wait for this device to become unblocked */ @@ -1617,15 +1611,16 @@ static void raid1_status(struct seq_file *seq, struct mddev *mddev) struct r1conf *conf = mddev->private; int i; + lockdep_assert_held(&mddev->lock); + seq_printf(seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); - rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = READ_ONCE(conf->mirrors[i].rdev); + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); } - rcu_read_unlock(); seq_printf(seq, "]"); } @@ -1691,16 +1686,15 @@ static void print_conf(struct r1conf *conf) pr_debug(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, conf->raid_disks); - rcu_read_lock(); + lockdep_assert_held(&conf->mddev->reconfig_mutex); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = conf->mirrors[i].rdev; if (rdev) pr_debug(" disk %d, wo:%d, o:%d, dev:%pg\n", i, !test_bit(In_sync, &rdev->flags), !test_bit(Faulty, &rdev->flags), rdev->bdev); } - rcu_read_unlock(); } static void close_sync(struct r1conf *conf) @@ -1810,7 +1804,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) */ if (rdev->saved_raid_disk < 0) conf->fullsync = 1; - rcu_assign_pointer(p->rdev, rdev); + WRITE_ONCE(p->rdev, rdev); break; } if (test_bit(WantReplacement, &p->rdev->flags) && @@ -1826,7 +1820,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) rdev->raid_disk = repl_slot; err = 0; conf->fullsync = 1; - rcu_assign_pointer(p[conf->raid_disks].rdev, rdev); + WRITE_ONCE(p[conf->raid_disks].rdev, rdev); } print_conf(conf); @@ -1862,7 +1856,7 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) err = -EBUSY; goto abort; } - p->rdev = NULL; + WRITE_ONCE(p->rdev, NULL); if (conf->mirrors[conf->raid_disks + number].rdev) { /* We just removed a device that is being replaced. * Move down the replacement. We drain all IO before @@ -1883,7 +1877,7 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) goto abort; } clear_bit(Replacement, &repl->flags); - p->rdev = repl; + WRITE_ONCE(p->rdev, repl); conf->mirrors[conf->raid_disks + number].rdev = NULL; unfreeze_array(conf); } @@ -2281,8 +2275,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk, sector_t first_bad; int bad_sectors; - rcu_read_lock(); - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (rdev && (test_bit(In_sync, &rdev->flags) || (!test_bit(Faulty, &rdev->flags) && @@ -2290,15 +2283,14 @@ static void fix_read_error(struct r1conf *conf, int read_disk, is_badblock(rdev, sect, s, &first_bad, &bad_sectors) == 0) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); if (sync_page_io(rdev, sect, s<<9, conf->tmppage, REQ_OP_READ, false)) success = 1; rdev_dec_pending(rdev, mddev); if (success) break; - } else - rcu_read_unlock(); + } + d++; if (d == conf->raid_disks * 2) d = 0; @@ -2317,29 +2309,24 @@ static void fix_read_error(struct r1conf *conf, int read_disk, if (d==0) d = conf->raid_disks * 2; d--; - rcu_read_lock(); - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (rdev && !test_bit(Faulty, &rdev->flags)) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); r1_sync_page_io(rdev, sect, s, conf->tmppage, WRITE); rdev_dec_pending(rdev, mddev); - } else - rcu_read_unlock(); + } } d = start; while (d != read_disk) { if (d==0) d = conf->raid_disks * 2; d--; - rcu_read_lock(); - rdev = rcu_dereference(conf->mirrors[d].rdev); + rdev = conf->mirrors[d].rdev; if (rdev && !test_bit(Faulty, &rdev->flags)) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); if (r1_sync_page_io(rdev, sect, s, conf->tmppage, READ)) { atomic_add(s, &rdev->corrected_errors); @@ -2350,8 +2337,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk, rdev->bdev); } rdev_dec_pending(rdev, mddev); - } else - rcu_read_unlock(); + } } sectors -= s; sect += s; @@ -2732,7 +2718,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, r1_bio = raid1_alloc_init_r1buf(conf); - rcu_read_lock(); /* * If we get a correctably read error during resync or recovery, * we might want to read from a different device. So we @@ -2753,7 +2738,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, struct md_rdev *rdev; bio = r1_bio->bios[i]; - rdev = rcu_dereference(conf->mirrors[i].rdev); + rdev = conf->mirrors[i].rdev; if (rdev == NULL || test_bit(Faulty, &rdev->flags)) { if (i < conf->raid_disks) @@ -2811,7 +2796,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_opf |= MD_FAILFAST; } } - rcu_read_unlock(); if (disk < 0) disk = wonly; r1_bio->read_disk = disk; From ad8606702f268903b26795e6b93605646fd1a6a8 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Sat, 25 Nov 2023 16:16:03 +0800 Subject: [PATCH 1605/7721] md/raid5: remove rcu protection to access rdev from conf Because it's safe to accees rdev from conf: - If any spinlock is held, because synchronize_rcu() from md_kick_rdev_from_array() will prevent 'rdev' to be freed until spinlock is released; - If 'reconfig_lock' is held, because rdev can't be added or removed from array; - If there is normal IO inflight, because mddev_suspend() will prevent rdev to be added or removed from array; - If there is sync IO inflight, because 'MD_RECOVERY_RUNNING' is checked in remove_and_add_spares(). And these will cover all the scenarios in raid456. Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231125081604.3939938-5-yukuai1@huaweicloud.com --- drivers/md/raid5-cache.c | 11 +-- drivers/md/raid5-ppl.c | 16 +--- drivers/md/raid5.c | 182 +++++++++++++-------------------------- drivers/md/raid5.h | 4 +- 4 files changed, 69 insertions(+), 144 deletions(-) diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 6157f5beb9fe..874874fe4fa1 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -1890,28 +1890,22 @@ r5l_recovery_replay_one_stripe(struct r5conf *conf, continue; /* in case device is broken */ - rcu_read_lock(); - rdev = rcu_dereference(conf->disks[disk_index].rdev); + rdev = conf->disks[disk_index].rdev; if (rdev) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); sync_page_io(rdev, sh->sector, PAGE_SIZE, sh->dev[disk_index].page, REQ_OP_WRITE, false); rdev_dec_pending(rdev, rdev->mddev); - rcu_read_lock(); } - rrdev = rcu_dereference(conf->disks[disk_index].replacement); + rrdev = conf->disks[disk_index].replacement; if (rrdev) { atomic_inc(&rrdev->nr_pending); - rcu_read_unlock(); sync_page_io(rrdev, sh->sector, PAGE_SIZE, sh->dev[disk_index].page, REQ_OP_WRITE, false); rdev_dec_pending(rrdev, rrdev->mddev); - rcu_read_lock(); } - rcu_read_unlock(); } ctx->data_parity_stripes++; out: @@ -2948,7 +2942,6 @@ bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect) if (!log) return false; - WARN_ON_ONCE(!rcu_read_lock_held()); tree_index = r5c_tree_index(conf, sect); slot = radix_tree_lookup(&log->big_stripe_tree, tree_index); return slot != NULL; diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index eaea57aee602..da4ba736c4f0 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -620,11 +620,9 @@ static void ppl_do_flush(struct ppl_io_unit *io) struct md_rdev *rdev; struct block_device *bdev = NULL; - rcu_read_lock(); - rdev = rcu_dereference(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; if (rdev && !test_bit(Faulty, &rdev->flags)) bdev = rdev->bdev; - rcu_read_unlock(); if (bdev) { struct bio *bio; @@ -882,9 +880,7 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e, (unsigned long long)r_sector, dd_idx, (unsigned long long)sector); - /* Array has not started so rcu dereference is safe */ - rdev = rcu_dereference_protected( - conf->disks[dd_idx].rdev, 1); + rdev = conf->disks[dd_idx].rdev; if (!rdev || (!test_bit(In_sync, &rdev->flags) && sector >= rdev->recovery_offset)) { pr_debug("%s:%*s data member disk %d missing\n", @@ -936,9 +932,7 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e, 0, &disk, &sh); BUG_ON(sh.pd_idx != le32_to_cpu(e->parity_disk)); - /* Array has not started so rcu dereference is safe */ - parity_rdev = rcu_dereference_protected( - conf->disks[sh.pd_idx].rdev, 1); + parity_rdev = conf->disks[sh.pd_idx].rdev; BUG_ON(parity_rdev->bdev->bd_dev != log->rdev->bdev->bd_dev); pr_debug("%s:%*s write parity at sector %llu, disk %pg\n", @@ -1404,9 +1398,7 @@ int ppl_init_log(struct r5conf *conf) for (i = 0; i < ppl_conf->count; i++) { struct ppl_log *log = &ppl_conf->child_logs[i]; - /* Array has not started so rcu dereference is safe */ - struct md_rdev *rdev = - rcu_dereference_protected(conf->disks[i].rdev, 1); + struct md_rdev *rdev = conf->disks[i].rdev; mutex_init(&log->io_mutex); spin_lock_init(&log->io_list_lock); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index d431e4625cc5..e57deb1c6138 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -693,12 +693,12 @@ int raid5_calc_degraded(struct r5conf *conf) int degraded, degraded2; int i; - rcu_read_lock(); degraded = 0; for (i = 0; i < conf->previous_raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = READ_ONCE(conf->disks[i].rdev); + if (rdev && test_bit(Faulty, &rdev->flags)) - rdev = rcu_dereference(conf->disks[i].replacement); + rdev = READ_ONCE(conf->disks[i].replacement); if (!rdev || test_bit(Faulty, &rdev->flags)) degraded++; else if (test_bit(In_sync, &rdev->flags)) @@ -716,15 +716,14 @@ int raid5_calc_degraded(struct r5conf *conf) if (conf->raid_disks >= conf->previous_raid_disks) degraded++; } - rcu_read_unlock(); if (conf->raid_disks == conf->previous_raid_disks) return degraded; - rcu_read_lock(); degraded2 = 0; for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = READ_ONCE(conf->disks[i].rdev); + if (rdev && test_bit(Faulty, &rdev->flags)) - rdev = rcu_dereference(conf->disks[i].replacement); + rdev = READ_ONCE(conf->disks[i].replacement); if (!rdev || test_bit(Faulty, &rdev->flags)) degraded2++; else if (test_bit(In_sync, &rdev->flags)) @@ -738,7 +737,6 @@ int raid5_calc_degraded(struct r5conf *conf) if (conf->raid_disks <= conf->previous_raid_disks) degraded2++; } - rcu_read_unlock(); if (degraded2 > degraded) return degraded2; return degraded; @@ -1183,14 +1181,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi = &dev->req; rbi = &dev->rreq; /* For writing to replacement */ - rcu_read_lock(); - rrdev = rcu_dereference(conf->disks[i].replacement); - smp_mb(); /* Ensure that if rrdev is NULL, rdev won't be */ - rdev = rcu_dereference(conf->disks[i].rdev); - if (!rdev) { - rdev = rrdev; - rrdev = NULL; - } + rdev = conf->disks[i].rdev; + rrdev = conf->disks[i].replacement; if (op_is_write(op)) { if (replace_only) rdev = NULL; @@ -1211,7 +1203,6 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) rrdev = NULL; if (rrdev) atomic_inc(&rrdev->nr_pending); - rcu_read_unlock(); /* We have already checked bad blocks for reads. Now * need to check for writes. We never accept write errors @@ -2730,28 +2721,6 @@ static void shrink_stripes(struct r5conf *conf) conf->slab_cache = NULL; } -/* - * This helper wraps rcu_dereference_protected() and can be used when - * it is known that the nr_pending of the rdev is elevated. - */ -static struct md_rdev *rdev_pend_deref(struct md_rdev __rcu *rdev) -{ - return rcu_dereference_protected(rdev, - atomic_read(&rcu_access_pointer(rdev)->nr_pending)); -} - -/* - * This helper wraps rcu_dereference_protected() and should be used - * when it is known that the mddev_lock() is held. This is safe - * seeing raid5_remove_disk() has the same lock held. - */ -static struct md_rdev *rdev_mdlock_deref(struct mddev *mddev, - struct md_rdev __rcu *rdev) -{ - return rcu_dereference_protected(rdev, - lockdep_is_held(&mddev->reconfig_mutex)); -} - static void raid5_end_read_request(struct bio * bi) { struct stripe_head *sh = bi->bi_private; @@ -2777,9 +2746,9 @@ static void raid5_end_read_request(struct bio * bi) * In that case it moved down to 'rdev'. * rdev is not removed until all requests are finished. */ - rdev = rdev_pend_deref(conf->disks[i].replacement); + rdev = conf->disks[i].replacement; if (!rdev) - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; if (use_new_offset(conf, sh)) s = sh->sector + rdev->new_data_offset; @@ -2892,11 +2861,11 @@ static void raid5_end_write_request(struct bio *bi) for (i = 0 ; i < disks; i++) { if (bi == &sh->dev[i].req) { - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; break; } if (bi == &sh->dev[i].rreq) { - rdev = rdev_pend_deref(conf->disks[i].replacement); + rdev = conf->disks[i].replacement; if (rdev) replacement = 1; else @@ -2904,7 +2873,7 @@ static void raid5_end_write_request(struct bio *bi) * replaced it. rdev is not removed * until all requests are finished. */ - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; break; } } @@ -3666,15 +3635,13 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, int bitmap_end = 0; if (test_bit(R5_ReadError, &sh->dev[i].flags)) { - struct md_rdev *rdev; - rcu_read_lock(); - rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = conf->disks[i].rdev; + if (rdev && test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) atomic_inc(&rdev->nr_pending); else rdev = NULL; - rcu_read_unlock(); if (rdev) { if (!rdev_set_badblocks( rdev, @@ -3792,16 +3759,17 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh, /* During recovery devices cannot be removed, so * locking and refcounting of rdevs is not needed */ - rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = conf->disks[i].rdev; + if (rdev && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && !rdev_set_badblocks(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0)) abort = 1; - rdev = rcu_dereference(conf->disks[i].replacement); + rdev = conf->disks[i].replacement; + if (rdev && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) @@ -3809,7 +3777,6 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh, RAID5_STRIPE_SECTORS(conf), 0)) abort = 1; } - rcu_read_unlock(); if (abort) conf->recovery_disabled = conf->mddev->recovery_disabled; @@ -3822,15 +3789,13 @@ static int want_replace(struct stripe_head *sh, int disk_idx) struct md_rdev *rdev; int rv = 0; - rcu_read_lock(); - rdev = rcu_dereference(sh->raid_conf->disks[disk_idx].replacement); + rdev = sh->raid_conf->disks[disk_idx].replacement; if (rdev && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && (rdev->recovery_offset <= sh->sector || rdev->mddev->recovery_cp <= sh->sector)) rv = 1; - rcu_read_unlock(); return rv; } @@ -4707,7 +4672,6 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->log_failed = r5l_log_disk_error(conf); /* Now to look around and see what can be done */ - rcu_read_lock(); for (i=disks; i--; ) { struct md_rdev *rdev; sector_t first_bad; @@ -4752,7 +4716,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) /* Prefer to use the replacement for reads, but only * if it is recovered enough and has no bad blocks. */ - rdev = rcu_dereference(conf->disks[i].replacement); + rdev = conf->disks[i].replacement; if (rdev && !test_bit(Faulty, &rdev->flags) && rdev->recovery_offset >= sh->sector + RAID5_STRIPE_SECTORS(conf) && !is_badblock(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), @@ -4763,7 +4727,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) set_bit(R5_NeedReplace, &dev->flags); else clear_bit(R5_NeedReplace, &dev->flags); - rdev = rcu_dereference(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; clear_bit(R5_ReadRepl, &dev->flags); } if (rdev && test_bit(Faulty, &rdev->flags)) @@ -4810,8 +4774,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) if (test_bit(R5_WriteError, &dev->flags)) { /* This flag does not apply to '.replacement' * only to .rdev, so make sure to check that*/ - struct md_rdev *rdev2 = rcu_dereference( - conf->disks[i].rdev); + struct md_rdev *rdev2 = conf->disks[i].rdev; + if (rdev2 == rdev) clear_bit(R5_Insync, &dev->flags); if (rdev2 && !test_bit(Faulty, &rdev2->flags)) { @@ -4823,8 +4787,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) if (test_bit(R5_MadeGood, &dev->flags)) { /* This flag does not apply to '.replacement' * only to .rdev, so make sure to check that*/ - struct md_rdev *rdev2 = rcu_dereference( - conf->disks[i].rdev); + struct md_rdev *rdev2 = conf->disks[i].rdev; + if (rdev2 && !test_bit(Faulty, &rdev2->flags)) { s->handle_bad_blocks = 1; atomic_inc(&rdev2->nr_pending); @@ -4832,8 +4796,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) clear_bit(R5_MadeGood, &dev->flags); } if (test_bit(R5_MadeGoodRepl, &dev->flags)) { - struct md_rdev *rdev2 = rcu_dereference( - conf->disks[i].replacement); + struct md_rdev *rdev2 = conf->disks[i].replacement; + if (rdev2 && !test_bit(Faulty, &rdev2->flags)) { s->handle_bad_blocks = 1; atomic_inc(&rdev2->nr_pending); @@ -4854,8 +4818,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) if (rdev && !test_bit(Faulty, &rdev->flags)) do_recovery = 1; else if (!rdev) { - rdev = rcu_dereference( - conf->disks[i].replacement); + rdev = conf->disks[i].replacement; if (rdev && !test_bit(Faulty, &rdev->flags)) do_recovery = 1; } @@ -4882,7 +4845,6 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) else s->replacing = 1; } - rcu_read_unlock(); } /* @@ -5339,23 +5301,23 @@ static void handle_stripe(struct stripe_head *sh) struct r5dev *dev = &sh->dev[i]; if (test_and_clear_bit(R5_WriteError, &dev->flags)) { /* We own a safe reference to the rdev */ - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; if (!rdev_set_badblocks(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0)) md_error(conf->mddev, rdev); rdev_dec_pending(rdev, conf->mddev); } if (test_and_clear_bit(R5_MadeGood, &dev->flags)) { - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; rdev_clear_badblocks(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0); rdev_dec_pending(rdev, conf->mddev); } if (test_and_clear_bit(R5_MadeGoodRepl, &dev->flags)) { - rdev = rdev_pend_deref(conf->disks[i].replacement); + rdev = conf->disks[i].replacement; if (!rdev) /* rdev have been moved down */ - rdev = rdev_pend_deref(conf->disks[i].rdev); + rdev = conf->disks[i].rdev; rdev_clear_badblocks(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0); rdev_dec_pending(rdev, conf->mddev); @@ -5514,24 +5476,22 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) &dd_idx, NULL); end_sector = sector + bio_sectors(raid_bio); - rcu_read_lock(); if (r5c_big_stripe_cached(conf, sector)) - goto out_rcu_unlock; + return 0; - rdev = rcu_dereference(conf->disks[dd_idx].replacement); + rdev = conf->disks[dd_idx].replacement; if (!rdev || test_bit(Faulty, &rdev->flags) || rdev->recovery_offset < end_sector) { - rdev = rcu_dereference(conf->disks[dd_idx].rdev); + rdev = conf->disks[dd_idx].rdev; if (!rdev) - goto out_rcu_unlock; + return 0; if (test_bit(Faulty, &rdev->flags) || !(test_bit(In_sync, &rdev->flags) || rdev->recovery_offset >= end_sector)) - goto out_rcu_unlock; + return 0; } atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); if (is_badblock(rdev, sector, bio_sectors(raid_bio), &first_bad, &bad_sectors)) { @@ -5575,10 +5535,6 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) raid_bio->bi_iter.bi_sector); submit_bio_noacct(align_bio); return 1; - -out_rcu_unlock: - rcu_read_unlock(); - return 0; } static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio) @@ -6581,14 +6537,12 @@ static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_n * Note in case of > 1 drive failures it's possible we're rebuilding * one drive while leaving another faulty drive in array. */ - rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = conf->disks[i].rdev; if (rdev == NULL || test_bit(Faulty, &rdev->flags)) still_degraded = 1; } - rcu_read_unlock(); md_bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded); @@ -7899,18 +7853,10 @@ static int raid5_run(struct mddev *mddev) for (i = 0; i < conf->raid_disks && conf->previous_raid_disks; i++) { - rdev = rdev_mdlock_deref(mddev, conf->disks[i].rdev); - if (!rdev && conf->disks[i].replacement) { - /* The replacement is all we have yet */ - rdev = rdev_mdlock_deref(mddev, - conf->disks[i].replacement); - conf->disks[i].replacement = NULL; - clear_bit(Replacement, &rdev->flags); - rcu_assign_pointer(conf->disks[i].rdev, rdev); - } + rdev = conf->disks[i].rdev; if (!rdev) continue; - if (rcu_access_pointer(conf->disks[i].replacement) && + if (conf->disks[i].replacement && conf->reshape_progress != MaxSector) { /* replacements and reshape simply do not mix. */ pr_warn("md: cannot handle concurrent replacement and reshape.\n"); @@ -8094,15 +8040,16 @@ static void raid5_status(struct seq_file *seq, struct mddev *mddev) struct r5conf *conf = mddev->private; int i; + lockdep_assert_held(&mddev->lock); + seq_printf(seq, " level %d, %dk chunk, algorithm %d", mddev->level, conf->chunk_sectors / 2, mddev->layout); seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); - rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); + struct md_rdev *rdev = READ_ONCE(conf->disks[i].rdev); + seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); } - rcu_read_unlock(); seq_printf (seq, "]"); } @@ -8140,9 +8087,8 @@ static int raid5_spare_active(struct mddev *mddev) unsigned long flags; for (i = 0; i < conf->raid_disks; i++) { - rdev = rdev_mdlock_deref(mddev, conf->disks[i].rdev); - replacement = rdev_mdlock_deref(mddev, - conf->disks[i].replacement); + rdev = conf->disks[i].rdev; + replacement = conf->disks[i].replacement; if (replacement && replacement->recovery_offset == MaxSector && !test_bit(Faulty, &replacement->flags) @@ -8181,7 +8127,7 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) struct r5conf *conf = mddev->private; int err = 0; int number = rdev->raid_disk; - struct md_rdev __rcu **rdevp; + struct md_rdev **rdevp; struct disk_info *p; struct md_rdev *tmp; @@ -8204,9 +8150,9 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) if (unlikely(number >= conf->pool_size)) return 0; p = conf->disks + number; - if (rdev == rcu_access_pointer(p->rdev)) + if (rdev == p->rdev) rdevp = &p->rdev; - else if (rdev == rcu_access_pointer(p->replacement)) + else if (rdev == p->replacement) rdevp = &p->replacement; else return 0; @@ -8226,28 +8172,24 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) if (!test_bit(Faulty, &rdev->flags) && mddev->recovery_disabled != conf->recovery_disabled && !has_failed(conf) && - (!rcu_access_pointer(p->replacement) || - rcu_access_pointer(p->replacement) == rdev) && + (!p->replacement || p->replacement == rdev) && number < conf->raid_disks) { err = -EBUSY; goto abort; } - *rdevp = NULL; + WRITE_ONCE(*rdevp, NULL); if (!err) { err = log_modify(conf, rdev, false); if (err) goto abort; } - tmp = rcu_access_pointer(p->replacement); + tmp = p->replacement; if (tmp) { /* We must have just cleared 'rdev' */ - rcu_assign_pointer(p->rdev, tmp); + WRITE_ONCE(p->rdev, tmp); clear_bit(Replacement, &tmp->flags); - smp_mb(); /* Make sure other CPUs may see both as identical - * but will never see neither - if they are careful - */ - rcu_assign_pointer(p->replacement, NULL); + WRITE_ONCE(p->replacement, NULL); if (!err) err = log_modify(conf, tmp, true); @@ -8315,7 +8257,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) rdev->raid_disk = disk; if (rdev->saved_raid_disk != disk) conf->fullsync = 1; - rcu_assign_pointer(p->rdev, rdev); + WRITE_ONCE(p->rdev, rdev); err = log_modify(conf, rdev, true); @@ -8324,7 +8266,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) } for (disk = first; disk <= last; disk++) { p = conf->disks + disk; - tmp = rdev_mdlock_deref(mddev, p->rdev); + tmp = p->rdev; if (test_bit(WantReplacement, &tmp->flags) && mddev->reshape_position == MaxSector && p->replacement == NULL) { @@ -8333,7 +8275,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) rdev->raid_disk = disk; err = 0; conf->fullsync = 1; - rcu_assign_pointer(p->replacement, rdev); + WRITE_ONCE(p->replacement, rdev); break; } } @@ -8466,7 +8408,7 @@ static int raid5_start_reshape(struct mddev *mddev) if (mddev->recovery_cp < MaxSector) return -EBUSY; for (i = 0; i < conf->raid_disks; i++) - if (rdev_mdlock_deref(mddev, conf->disks[i].replacement)) + if (conf->disks[i].replacement) return -EBUSY; rdev_for_each(rdev, mddev) { @@ -8637,12 +8579,10 @@ static void raid5_finish_reshape(struct mddev *mddev) for (d = conf->raid_disks ; d < conf->raid_disks - mddev->delta_disks; d++) { - rdev = rdev_mdlock_deref(mddev, - conf->disks[d].rdev); + rdev = conf->disks[d].rdev; if (rdev) clear_bit(In_sync, &rdev->flags); - rdev = rdev_mdlock_deref(mddev, - conf->disks[d].replacement); + rdev = conf->disks[d].replacement; if (rdev) clear_bit(In_sync, &rdev->flags); } diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 22bea20eccbd..9b5a7dc3f2a0 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -473,8 +473,8 @@ enum { */ struct disk_info { - struct md_rdev __rcu *rdev; - struct md_rdev __rcu *replacement; + struct md_rdev *rdev; + struct md_rdev *replacement; struct page *extra_page; /* extra page to use in prexor */ }; From 7ecab28c3b2c26c1a51154d997433e8432eb49ba Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Sat, 25 Nov 2023 16:16:04 +0800 Subject: [PATCH 1606/7721] md/md-multipath: remove rcu protection to access rdev from conf Because it's safe to accees rdev from conf: - If any spinlock is held, because synchronize_rcu() from md_kick_rdev_from_array() will prevent 'rdev' to be freed until spinlock is released; - If there is normal IO inflight, because mddev_suspend() will prevent rdev to be added or removed from array; And these will cover all the scenarios in md-multipath. Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231125081604.3939938-6-yukuai1@huaweicloud.com --- drivers/md/md-multipath.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c index aa77133f3188..19c8625ea642 100644 --- a/drivers/md/md-multipath.c +++ b/drivers/md/md-multipath.c @@ -32,17 +32,15 @@ static int multipath_map (struct mpconf *conf) * now we use the first available disk. */ - rcu_read_lock(); for (i = 0; i < disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); + struct md_rdev *rdev = conf->multipaths[i].rdev; + if (rdev && test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) { atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); return i; } } - rcu_read_unlock(); pr_crit_ratelimited("multipath_map(): no more operational IO paths?\n"); return (-1); @@ -137,14 +135,16 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev) struct mpconf *conf = mddev->private; int i; + lockdep_assert_held(&mddev->lock); + seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); - rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); - seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); + struct md_rdev *rdev = READ_ONCE(conf->multipaths[i].rdev); + + seq_printf(seq, "%s", + rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); } - rcu_read_unlock(); seq_putc(seq, ']'); } @@ -182,7 +182,7 @@ static void multipath_error (struct mddev *mddev, struct md_rdev *rdev) conf->raid_disks - mddev->degraded); } -static void print_multipath_conf (struct mpconf *conf) +static void print_multipath_conf(struct mpconf *conf) { int i; struct multipath_info *tmp; @@ -195,6 +195,7 @@ static void print_multipath_conf (struct mpconf *conf) pr_debug(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, conf->raid_disks); + lockdep_assert_held(&conf->mddev->reconfig_mutex); for (i = 0; i < conf->raid_disks; i++) { tmp = conf->multipaths + i; if (tmp->rdev) @@ -231,7 +232,7 @@ static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev) rdev->raid_disk = path; set_bit(In_sync, &rdev->flags); spin_unlock_irq(&conf->device_lock); - rcu_assign_pointer(p->rdev, rdev); + WRITE_ONCE(p->rdev, rdev); err = 0; break; } @@ -257,7 +258,7 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev) err = -EBUSY; goto abort; } - p->rdev = NULL; + WRITE_ONCE(p->rdev, NULL); err = md_integrity_register(mddev); } abort: From 876843ce1e4897e8ceade50bfa3d9a4ec483abf3 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 10:20:56 -0800 Subject: [PATCH 1607/7721] bpftool: mark orphaned programs during prog show Commit ef01f4e25c17 ("bpf: restore the ebpf program ID for BPF_AUDIT_UNLOAD and PERF_BPF_EVENT_PROG_UNLOAD") stopped removing program's id from idr when the offloaded/bound netdev goes away. I was supposed to take a look and check in [0], but apparently I did not. Martin points out it might be useful to keep it that way for observability sake, but we at least need to mark those programs as unusable. Mark those programs as 'orphaned' and keep printing the list when we encounter ENODEV. 0: unspec tag 0000000000000000 xlated 0B not jited memlock 4096B orphaned [0]: https://lore.kernel.org/all/CAKH8qBtyR20ZWAc11z1-6pGb3Hd47AQUTbE_cfoktG59TqaJ7Q@mail.gmail.com/ v3: * use two spaces for " orphaned" (Quentin) Cc: netdev@vger.kernel.org Fixes: ef01f4e25c17 ("bpf: restore the ebpf program ID for BPF_AUDIT_UNLOAD and PERF_BPF_EVENT_PROG_UNLOAD") Signed-off-by: Stanislav Fomichev Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/r/20231127182057.1081138-1-sdf@google.com Signed-off-by: Martin KaFai Lau --- tools/bpf/bpftool/prog.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 7ec4f5671e7a..feb8e305804f 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -442,7 +442,7 @@ static void print_prog_header_json(struct bpf_prog_info *info, int fd) jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); } -static void print_prog_json(struct bpf_prog_info *info, int fd) +static void print_prog_json(struct bpf_prog_info *info, int fd, bool orphaned) { char *memlock; @@ -461,6 +461,7 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) jsonw_uint_field(json_wtr, "uid", info->created_by_uid); } + jsonw_bool_field(json_wtr, "orphaned", orphaned); jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); if (info->jited_prog_len) { @@ -527,7 +528,7 @@ static void print_prog_header_plain(struct bpf_prog_info *info, int fd) printf("\n"); } -static void print_prog_plain(struct bpf_prog_info *info, int fd) +static void print_prog_plain(struct bpf_prog_info *info, int fd, bool orphaned) { char *memlock; @@ -554,6 +555,9 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) printf(" memlock %sB", memlock); free(memlock); + if (orphaned) + printf(" orphaned"); + if (info->nr_map_ids) show_prog_maps(fd, info->nr_map_ids); @@ -581,15 +585,15 @@ static int show_prog(int fd) int err; err = bpf_prog_get_info_by_fd(fd, &info, &len); - if (err) { + if (err && err != -ENODEV) { p_err("can't get prog info: %s", strerror(errno)); return -1; } if (json_output) - print_prog_json(&info, fd); + print_prog_json(&info, fd, err == -ENODEV); else - print_prog_plain(&info, fd); + print_prog_plain(&info, fd, err == -ENODEV); return 0; } From cf9791631027a476f7cdb0e1b3ac6add16eff264 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 10:20:57 -0800 Subject: [PATCH 1608/7721] selftests/bpf: update test_offload to use new orphaned property - filter orphaned programs by default - when trying to query orphaned program, don't expect bpftool failure Cc: netdev@vger.kernel.org Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127182057.1081138-2-sdf@google.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/test_offload.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index 40cba8d368d9..6157f884d091 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py @@ -169,12 +169,14 @@ def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False): return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail, include_stderr=include_stderr) -def bpftool_prog_list(expected=None, ns=""): +def bpftool_prog_list(expected=None, ns="", exclude_orphaned=True): _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) # Remove the base progs for p in base_progs: if p in progs: progs.remove(p) + if exclude_orphaned: + progs = [ p for p in progs if not p['orphaned'] ] if expected is not None: if len(progs) != expected: fail(True, "%d BPF programs loaded, expected %d" % @@ -612,11 +614,9 @@ def pin_map(file_name, idx=0, expected=1): def check_dev_info_removed(prog_file=None, map_file=None): bpftool_prog_list(expected=0) + bpftool_prog_list(expected=1, exclude_orphaned=False) ret, err = bpftool("prog show pin %s" % (prog_file), fail=False) - fail(ret == 0, "Showing prog with removed device did not fail") - fail(err["error"].find("No such device") == -1, - "Showing prog with removed device expected ENODEV, error is %s" % - (err["error"])) + fail(ret != 0, "failed to show prog with removed device") bpftool_map_list(expected=0) ret, err = bpftool("map show pin %s" % (map_file), fail=False) @@ -1395,10 +1395,7 @@ try: start_test("Test multi-dev ASIC cross-dev destruction - orphaned...") ret, out = bpftool("prog show %s" % (progB), fail=False) - fail(ret == 0, "got information about orphaned program") - fail("error" not in out, "no error reported for get info on orphaned") - fail(out["error"] != "can't get prog info: No such device", - "wrong error for get info on orphaned") + fail(ret != 0, "couldn't get information about orphaned program") print("%s: OK" % (os.path.basename(__file__))) From 243ad8df7a1bd24c2e01bd99d9f0bb88844dae91 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:27:52 +0000 Subject: [PATCH 1609/7721] net: phy: add possible interfaces Add a possible_interfaces member to struct phy_device to indicate which interfaces a clause 45 PHY may switch between depending on the media. This must be populated by the PHY driver by the time the .config_init() method completes according to the PHYs host-side configuration. For example, the Marvell 88x3310 PHY can switch between 10GBASE-R, 5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media side speed, so all these interface modes are set in the possible_interfaces member. This allows phylib users (such as phylink) to know in advance which interface modes to expect, which allows them to appropriately restrict the advertised link modes according to the capabilities of other parts of the link. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VHk-00DDLN-I7@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 2 ++ include/linux/phy.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 478126f6b5bc..400fb09d9cd6 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1246,6 +1246,8 @@ int phy_init_hw(struct phy_device *phydev) if (ret < 0) return ret; + phy_interface_zero(phydev->possible_interfaces); + if (phydev->drv->config_init) { ret = phydev->drv->config_init(phydev); if (ret < 0) diff --git a/include/linux/phy.h b/include/linux/phy.h index e5f1f41e399c..6e7ebcc50b85 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -605,6 +605,8 @@ struct macsec_ops; * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended, * requiring a rerun of the interrupt handler after resume * @interface: enum phy_interface_t value + * @possible_interfaces: bitmap if interface modes that the attached PHY + * will switch between depending on media speed. * @skb: Netlink message for cable diagnostics * @nest: Netlink nest used for cable diagnostics * @ehdr: nNtlink header for cable diagnostics @@ -674,6 +676,7 @@ struct phy_device { u32 dev_flags; phy_interface_t interface; + DECLARE_PHY_INTERFACE_MASK(possible_interfaces); /* * forced speed & duplex (no autoneg) From 2cb6d63b30c6fbc7cf5f671279be4a94049e141f Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:27:58 +0000 Subject: [PATCH 1610/7721] net: phy: marvell10g: table driven mactype decode Replace the code-based mactype decode with a table driven approach. This will allow us to fill in the possible_interfaces cleanly. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1r6VHq-00DDLT-In@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell10g.c | 197 +++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 77 deletions(-) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index d4bb90d76881..a880b3375dee 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -141,13 +141,21 @@ enum { MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */ }; +struct mv3310_mactype { + bool valid; + bool fixed_interface; + phy_interface_t interface_10g; +}; + struct mv3310_chip { bool (*has_downshift)(struct phy_device *phydev); void (*init_supported_interfaces)(unsigned long *mask); int (*get_mactype)(struct phy_device *phydev); int (*set_mactype)(struct phy_device *phydev, int mactype); int (*select_mactype)(unsigned long *interfaces); - int (*init_interface)(struct phy_device *phydev, int mactype); + + const struct mv3310_mactype *mactypes; + size_t n_mactypes; #ifdef CONFIG_HWMON int (*hwmon_read_temp_reg)(struct phy_device *phydev); @@ -156,11 +164,10 @@ struct mv3310_chip { struct mv3310_priv { DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); + const struct mv3310_mactype *mactype; u32 firmware_ver; bool has_downshift; - bool rate_match; - phy_interface_t const_interface; struct device *hwmon_dev; char *hwmon_name; @@ -702,71 +709,99 @@ static int mv3310_select_mactype(unsigned long *interfaces) return -1; } -static int mv2110_init_interface(struct phy_device *phydev, int mactype) -{ - struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +static const struct mv3310_mactype mv2110_mactypes[] = { + [MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_USXGMII, + }, + [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_NA, + }, + [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_NA, + }, + [MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, +}; - priv->rate_match = false; +static const struct mv3310_mactype mv3310_mactypes[] = { + [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_RXAUI, + }, + [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_XAUI, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_RXAUI, + }, + [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_XAUI, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_USXGMII, + }, +}; - if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH) - priv->rate_match = true; - - if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII) - priv->const_interface = PHY_INTERFACE_MODE_USXGMII; - else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH) - priv->const_interface = PHY_INTERFACE_MODE_10GBASER; - else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER || - mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN) - priv->const_interface = PHY_INTERFACE_MODE_NA; - else - return -EINVAL; - - return 0; -} - -static int mv3310_init_interface(struct phy_device *phydev, int mactype) -{ - struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); - - priv->rate_match = false; - - if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH || - mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH || - mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH) - priv->rate_match = true; - - if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII) - priv->const_interface = PHY_INTERFACE_MODE_USXGMII; - else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH || - mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN || - mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER) - priv->const_interface = PHY_INTERFACE_MODE_10GBASER; - else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH || - mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI) - priv->const_interface = PHY_INTERFACE_MODE_RXAUI; - else if (mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH || - mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI) - priv->const_interface = PHY_INTERFACE_MODE_XAUI; - else - return -EINVAL; - - return 0; -} - -static int mv3340_init_interface(struct phy_device *phydev, int mactype) -{ - struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); - int err = 0; - - priv->rate_match = false; - - if (mactype == MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN) - priv->const_interface = PHY_INTERFACE_MODE_RXAUI; - else - err = mv3310_init_interface(phydev, mactype); - - return err; -} +static const struct mv3310_mactype mv3340_mactypes[] = { + [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_RXAUI, + }, + [MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_RXAUI, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_RXAUI, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = { + .valid = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_10GBASER, + }, + [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { + .valid = true, + .fixed_interface = true, + .interface_10g = PHY_INTERFACE_MODE_USXGMII, + }, +}; static int mv3310_config_init(struct phy_device *phydev) { @@ -803,12 +838,13 @@ static int mv3310_config_init(struct phy_device *phydev) if (mactype < 0) return mactype; - err = chip->init_interface(phydev, mactype); - if (err) { + if (mactype >= chip->n_mactypes || !chip->mactypes[mactype].valid) { phydev_err(phydev, "MACTYPE configuration invalid\n"); - return err; + return -EINVAL; } + priv->mactype = &chip->mactypes[mactype]; + /* Enable EDPD mode - saving 600mW */ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); if (err) @@ -935,9 +971,8 @@ static void mv3310_update_interface(struct phy_device *phydev) * * In USXGMII mode the PHY interface mode is also fixed. */ - if (priv->rate_match || - priv->const_interface == PHY_INTERFACE_MODE_USXGMII) { - phydev->interface = priv->const_interface; + if (priv->mactype->fixed_interface) { + phydev->interface = priv->mactype->interface_10g; return; } @@ -949,7 +984,7 @@ static void mv3310_update_interface(struct phy_device *phydev) */ switch (phydev->speed) { case SPEED_10000: - phydev->interface = priv->const_interface; + phydev->interface = priv->mactype->interface_10g; break; case SPEED_5000: phydev->interface = PHY_INTERFACE_MODE_5GBASER; @@ -1163,7 +1198,9 @@ static const struct mv3310_chip mv3310_type = { .get_mactype = mv3310_get_mactype, .set_mactype = mv3310_set_mactype, .select_mactype = mv3310_select_mactype, - .init_interface = mv3310_init_interface, + + .mactypes = mv3310_mactypes, + .n_mactypes = ARRAY_SIZE(mv3310_mactypes), #ifdef CONFIG_HWMON .hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg, @@ -1176,7 +1213,9 @@ static const struct mv3310_chip mv3340_type = { .get_mactype = mv3310_get_mactype, .set_mactype = mv3310_set_mactype, .select_mactype = mv3310_select_mactype, - .init_interface = mv3340_init_interface, + + .mactypes = mv3340_mactypes, + .n_mactypes = ARRAY_SIZE(mv3340_mactypes), #ifdef CONFIG_HWMON .hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg, @@ -1188,7 +1227,9 @@ static const struct mv3310_chip mv2110_type = { .get_mactype = mv2110_get_mactype, .set_mactype = mv2110_set_mactype, .select_mactype = mv2110_select_mactype, - .init_interface = mv2110_init_interface, + + .mactypes = mv2110_mactypes, + .n_mactypes = ARRAY_SIZE(mv2110_mactypes), #ifdef CONFIG_HWMON .hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg, @@ -1200,7 +1241,9 @@ static const struct mv3310_chip mv2111_type = { .get_mactype = mv2110_get_mactype, .set_mactype = mv2110_set_mactype, .select_mactype = mv2110_select_mactype, - .init_interface = mv2110_init_interface, + + .mactypes = mv2110_mactypes, + .n_mactypes = ARRAY_SIZE(mv2110_mactypes), #ifdef CONFIG_HWMON .hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg, From 82f2e76b660a490ae226db80d495b7c785e00d7a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:03 +0000 Subject: [PATCH 1611/7721] net: phy: marvell10g: fill in possible_interfaces Fill in the possible_interfaces member according to the selected mactype mode. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VHv-00DDLZ-OL@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell10g.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index a880b3375dee..ad43e280930c 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -803,6 +803,22 @@ static const struct mv3310_mactype mv3340_mactypes[] = { }, }; +static void mv3310_fill_possible_interfaces(struct phy_device *phydev) +{ + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); + unsigned long *possible = phydev->possible_interfaces; + const struct mv3310_mactype *mactype = priv->mactype; + + if (mactype->interface_10g != PHY_INTERFACE_MODE_NA) + __set_bit(priv->mactype->interface_10g, possible); + + if (!mactype->fixed_interface) { + __set_bit(PHY_INTERFACE_MODE_5GBASER, possible); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); + __set_bit(PHY_INTERFACE_MODE_SGMII, possible); + } +} + static int mv3310_config_init(struct phy_device *phydev) { struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); @@ -845,6 +861,8 @@ static int mv3310_config_init(struct phy_device *phydev) priv->mactype = &chip->mactypes[mactype]; + mv3310_fill_possible_interfaces(phydev); + /* Enable EDPD mode - saving 600mW */ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); if (err) From a22583338e535ba2512283da4aee893163a4b78d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:08 +0000 Subject: [PATCH 1612/7721] net: phy: bcm84881: fill in possible_interfaces Fill in the possible_interfaces member. This PHY driver only supports a single configuration found on SFPs. Reviewed-by: Florian Fainelli Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VI0-00DDLf-Tb@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/bcm84881.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c index 9717a1626f3f..f1d47c264058 100644 --- a/drivers/net/phy/bcm84881.c +++ b/drivers/net/phy/bcm84881.c @@ -29,8 +29,19 @@ static int bcm84881_wait_init(struct phy_device *phydev) 100000, 2000000, false); } +static void bcm84881_fill_possible_interfaces(struct phy_device *phydev) +{ + unsigned long *possible = phydev->possible_interfaces; + + __set_bit(PHY_INTERFACE_MODE_SGMII, possible); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); + __set_bit(PHY_INTERFACE_MODE_10GBASER, possible); +} + static int bcm84881_config_init(struct phy_device *phydev) { + bcm84881_fill_possible_interfaces(phydev); + switch (phydev->interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_2500BASEX: @@ -39,6 +50,7 @@ static int bcm84881_config_init(struct phy_device *phydev) default: return -ENODEV; } + return 0; } From 01972fa9ab7dc1af073dd994380f3e603eb0654e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:14 +0000 Subject: [PATCH 1613/7721] net: phy: aquantia: fill in possible_interfaces for AQR113C Fill in the possible_interfaces bitmap for AQR113C so phylink knows which interface modes will be used by the PHY. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VI6-00DDLl-2D@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/aquantia/aquantia.h | 5 ++ drivers/net/phy/aquantia/aquantia_main.c | 76 +++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index 9ed38972abdb..1c19ae74ad2b 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -47,6 +47,11 @@ #define VEND1_GLOBAL_CFG_5G 0x031e #define VEND1_GLOBAL_CFG_10G 0x031f /* ...and now the fields */ +#define VEND1_GLOBAL_CFG_SERDES_MODE GENMASK(2, 0) +#define VEND1_GLOBAL_CFG_SERDES_MODE_XFI 0 +#define VEND1_GLOBAL_CFG_SERDES_MODE_SGMII 3 +#define VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII 4 +#define VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G 6 #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 diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index cc4a97741c4a..97a2fafa15ca 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -656,6 +656,80 @@ static int aqr107_resume(struct phy_device *phydev) return aqr107_wait_processor_intensive_op(phydev); } +static const u16 aqr_global_cfg_regs[] = { + VEND1_GLOBAL_CFG_10M, + VEND1_GLOBAL_CFG_100M, + VEND1_GLOBAL_CFG_1G, + VEND1_GLOBAL_CFG_2_5G, + VEND1_GLOBAL_CFG_5G, + VEND1_GLOBAL_CFG_10G +}; + +static int aqr107_fill_interface_modes(struct phy_device *phydev) +{ + unsigned long *possible = phydev->possible_interfaces; + unsigned int serdes_mode, rate_adapt; + phy_interface_t interface; + int i, val; + + /* Walk the media-speed configuration registers to determine which + * host-side serdes modes may be used by the PHY depending on the + * negotiated media speed. + */ + for (i = 0; i < ARRAY_SIZE(aqr_global_cfg_regs); i++) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, + aqr_global_cfg_regs[i]); + if (val < 0) + return val; + + serdes_mode = FIELD_GET(VEND1_GLOBAL_CFG_SERDES_MODE, val); + rate_adapt = FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val); + + switch (serdes_mode) { + case VEND1_GLOBAL_CFG_SERDES_MODE_XFI: + if (rate_adapt == VEND1_GLOBAL_CFG_RATE_ADAPT_USX) + interface = PHY_INTERFACE_MODE_USXGMII; + else + interface = PHY_INTERFACE_MODE_10GBASER; + break; + + case VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G: + interface = PHY_INTERFACE_MODE_5GBASER; + break; + + case VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII: + interface = PHY_INTERFACE_MODE_2500BASEX; + break; + + case VEND1_GLOBAL_CFG_SERDES_MODE_SGMII: + interface = PHY_INTERFACE_MODE_SGMII; + break; + + default: + phydev_warn(phydev, "unrecognised serdes mode %u\n", + serdes_mode); + interface = PHY_INTERFACE_MODE_NA; + break; + } + + if (interface != PHY_INTERFACE_MODE_NA) + __set_bit(interface, possible); + } + + return 0; +} + +static int aqr113c_config_init(struct phy_device *phydev) +{ + int ret; + + ret = aqr107_config_init(phydev); + if (ret < 0) + return ret; + + return aqr107_fill_interface_modes(phydev); +} + static int aqr107_probe(struct phy_device *phydev) { int ret; @@ -794,7 +868,7 @@ static struct phy_driver aqr_driver[] = { .name = "Aquantia AQR113C", .probe = aqr107_probe, .get_rate_matching = aqr107_get_rate_matching, - .config_init = aqr107_config_init, + .config_init = aqr113c_config_init, .config_aneg = aqr_config_aneg, .config_intr = aqr_config_intr, .handle_interrupt = aqr_handle_interrupt, From 5f492a04506e5d93d5462238f7f899836ba3d421 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:19 +0000 Subject: [PATCH 1614/7721] net: phylink: split out per-interface validation Split out the internals of phylink_validate_mask() to make the code easier to read. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VIB-00DDLr-7g@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 42 ++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index c276f9482f78..11dd743141d5 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -689,26 +689,44 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; } +static void phylink_validate_one(struct phylink *pl, + const unsigned long *supported, + const struct phylink_link_state *state, + phy_interface_t interface, + unsigned long *accum_supported, + unsigned long *accum_advertising) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_supported); + struct phylink_link_state tmp_state; + + linkmode_copy(tmp_supported, supported); + + tmp_state = *state; + tmp_state.interface = interface; + + if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) { + phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n", + interface, phy_modes(interface), + phy_rate_matching_to_str(tmp_state.rate_matching), + __ETHTOOL_LINK_MODE_MASK_NBITS, tmp_supported); + + linkmode_or(accum_supported, accum_supported, tmp_supported); + linkmode_or(accum_advertising, accum_advertising, + tmp_state.advertising); + } +} + static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, struct phylink_link_state *state, const unsigned long *interfaces) { __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, }; __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; - __ETHTOOL_DECLARE_LINK_MODE_MASK(s); - struct phylink_link_state t; int interface; - for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) { - linkmode_copy(s, supported); - - t = *state; - t.interface = interface; - if (!phylink_validate_mac_and_pcs(pl, s, &t)) { - linkmode_or(all_s, all_s, s); - linkmode_or(all_adv, all_adv, t.advertising); - } - } + for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) + phylink_validate_one(pl, supported, state, interface, + all_s, all_adv); linkmode_copy(supported, all_s); linkmode_copy(state->advertising, all_adv); From 385e72b4003482bfe17c17a9f4005d2850b5e8e0 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:24 +0000 Subject: [PATCH 1615/7721] net: phylink: pass PHY into phylink_validate_one() Pass the phy (if any) into phylink_validate_one() so that we can validate each interface with its rate matching setting. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VIG-00DDLx-Cb@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 11dd743141d5..52414af5c93f 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -689,7 +689,7 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; } -static void phylink_validate_one(struct phylink *pl, +static void phylink_validate_one(struct phylink *pl, struct phy_device *phy, const unsigned long *supported, const struct phylink_link_state *state, phy_interface_t interface, @@ -704,6 +704,9 @@ static void phylink_validate_one(struct phylink *pl, tmp_state = *state; tmp_state.interface = interface; + if (phy) + tmp_state.rate_matching = phy_get_rate_matching(phy, interface); + if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) { phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n", interface, phy_modes(interface), @@ -725,7 +728,7 @@ static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, int interface; for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) - phylink_validate_one(pl, supported, state, interface, + phylink_validate_one(pl, NULL, supported, state, interface, all_s, all_adv); linkmode_copy(supported, all_s); From b7014f9ece5075755105bafbeeb2c17ed0dace11 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:29 +0000 Subject: [PATCH 1616/7721] net: phylink: pass PHY into phylink_validate_mask() Pass the phy (if any) into phylink_validate_mask() so that we can validate each interface with its rate matching setting. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VIL-00DDM3-HJ@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 52414af5c93f..ac48a1db9979 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -719,7 +719,8 @@ static void phylink_validate_one(struct phylink *pl, struct phy_device *phy, } } -static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, +static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy, + unsigned long *supported, struct phylink_link_state *state, const unsigned long *interfaces) { @@ -728,7 +729,7 @@ static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, int interface; for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) - phylink_validate_one(pl, NULL, supported, state, interface, + phylink_validate_one(pl, phy, supported, state, interface, all_s, all_adv); linkmode_copy(supported, all_s); @@ -743,7 +744,8 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported, const unsigned long *interfaces = pl->config->supported_interfaces; if (state->interface == PHY_INTERFACE_MODE_NA) - return phylink_validate_mask(pl, supported, state, interfaces); + return phylink_validate_mask(pl, NULL, supported, state, + interfaces); if (!test_bit(state->interface, interfaces)) return -EINVAL; @@ -3179,7 +3181,8 @@ static int phylink_sfp_config_optical(struct phylink *pl) /* For all the interfaces that are supported, reduce the sfp_support * mask to only those link modes that can be supported. */ - ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces); + ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config, + interfaces); if (ret) { phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support); From 2c62ff83ee14da698bf52e723b704304b59455bb Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:34 +0000 Subject: [PATCH 1617/7721] net: phylink: split out PHY validation from phylink_bringup_phy() When bringing up a PHY, we need to work out which ethtool link modes it should support and advertise. Clause 22 PHYs operate in a single interface mode, which can be easily dealt with. However, clause 45 PHYs tend to switch interface mode depending on the media. We need more flexible validation at this point, so this patch splits out that code in preparation to changing it. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VIQ-00DDM9-LK@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 56 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ac48a1db9979..39d85e47422e 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1760,6 +1760,35 @@ static void phylink_phy_change(struct phy_device *phydev, bool up) phylink_pause_to_str(pl->phy_state.pause)); } +static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, + unsigned long *supported, + struct phylink_link_state *state) +{ + /* Check whether we would use rate matching for the proposed interface + * mode. + */ + state->rate_matching = phy_get_rate_matching(phy, state->interface); + + /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R, + * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching. + * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching + * their Serdes is either unnecessary or not reasonable. + * + * For these which switch interface modes, we really need to know which + * interface modes the PHY supports to properly work out which ethtool + * linkmodes can be supported. For now, as a work-around, we validate + * against all interface modes, which may lead to more ethtool link + * modes being advertised than are actually supported. + */ + if (phy->is_c45 && state->rate_matching == RATE_MATCH_NONE && + state->interface != PHY_INTERFACE_MODE_RXAUI && + state->interface != PHY_INTERFACE_MODE_XAUI && + state->interface != PHY_INTERFACE_MODE_USXGMII) + state->interface = PHY_INTERFACE_MODE_NA; + + return phylink_validate(pl, supported, state); +} + static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, phy_interface_t interface) { @@ -1780,32 +1809,9 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, memset(&config, 0, sizeof(config)); linkmode_copy(supported, phy->supported); linkmode_copy(config.advertising, phy->advertising); + config.interface = interface; - /* Check whether we would use rate matching for the proposed interface - * mode. - */ - config.rate_matching = phy_get_rate_matching(phy, interface); - - /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R, - * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching. - * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching - * their Serdes is either unnecessary or not reasonable. - * - * For these which switch interface modes, we really need to know which - * interface modes the PHY supports to properly work out which ethtool - * linkmodes can be supported. For now, as a work-around, we validate - * against all interface modes, which may lead to more ethtool link - * modes being advertised than are actually supported. - */ - if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE && - interface != PHY_INTERFACE_MODE_RXAUI && - interface != PHY_INTERFACE_MODE_XAUI && - interface != PHY_INTERFACE_MODE_USXGMII) - config.interface = PHY_INTERFACE_MODE_NA; - else - config.interface = interface; - - ret = phylink_validate(pl, supported, &config); + ret = phylink_validate_phy(pl, phy, supported, &config); if (ret) { phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n", phy_modes(config.interface), From 7a1f9a17ee99a3c27577465ce0f6c5f56cf1aacf Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 24 Nov 2023 12:28:39 +0000 Subject: [PATCH 1618/7721] net: phylink: use the PHY's possible_interfaces if populated Some PHYs such as Aquantia, Broadcom 84881, and Marvell 88X33x0 can switch between a set of interface types depending on the negotiated media speed, or can use rate adaption for some or all of these interface types. We currently assume that these are Clause 45 PHYs that are configured not to use a specific set of interface modes, which has worked so far, but is just a work-around. In this workaround, we validate using all interfaces that the MAC supports, which can lead to extra modes being advertised that can not be supported. To properly address this, switch to using the newly introduced PHY possible_interfaces bitmap which indicates which interface modes will be used by the PHY as configured. We calculate the union of the PHY's possible interfaces and MACs supported interfaces, checking that is non-empty. If the PHY is on a SFP, we further reduce the set by those which can be used on a SFP module, again checking that is non-empty. Finally, we validate the subset of interfaces, taking account of whether rate matching will be used for each individual interface mode. This becomes independent of whether the PHY is clause 22 or clause 45. It is encouraged that all PHYs that switch interface modes or use rate matching should populate phydev->possible_interfaces. Tested-by: Luo Jie Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1r6VIV-00DDMF-Pi@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 39d85e47422e..48d3bd3e9fc7 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -121,6 +121,19 @@ do { \ }) #endif +static const phy_interface_t phylink_sfp_interface_preference[] = { + PHY_INTERFACE_MODE_25GBASER, + PHY_INTERFACE_MODE_USXGMII, + PHY_INTERFACE_MODE_10GBASER, + PHY_INTERFACE_MODE_5GBASER, + PHY_INTERFACE_MODE_2500BASEX, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_1000BASEX, + PHY_INTERFACE_MODE_100BASEX, +}; + +static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); + /** * phylink_set_port_modes() - set the port type modes in the ethtool mask * @mask: ethtool link mode mask @@ -1764,6 +1777,47 @@ static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, unsigned long *supported, struct phylink_link_state *state) { + DECLARE_PHY_INTERFACE_MASK(interfaces); + + /* If the PHY provides a bitmap of the interfaces it will be using + * depending on the negotiated media speeds, use this to validate + * which ethtool link modes can be used. + */ + if (!phy_interface_empty(phy->possible_interfaces)) { + /* We only care about the union of the PHY's interfaces and + * those which the host supports. + */ + phy_interface_and(interfaces, phy->possible_interfaces, + pl->config->supported_interfaces); + + if (phy_interface_empty(interfaces)) { + phylink_err(pl, "PHY has no common interfaces\n"); + return -EINVAL; + } + + if (phy_on_sfp(phy)) { + /* If the PHY is on a SFP, limit the interfaces to + * those that can be used with a SFP module. + */ + phy_interface_and(interfaces, interfaces, + phylink_sfp_interfaces); + + if (phy_interface_empty(interfaces)) { + phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n"); + return -EINVAL; + } + } + + phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n", + phydev_name(phy), + (int)PHY_INTERFACE_MODE_MAX, + phy->possible_interfaces, + (int)PHY_INTERFACE_MODE_MAX, interfaces); + + return phylink_validate_mask(pl, phy, supported, state, + interfaces); + } + /* Check whether we would use rate matching for the proposed interface * mode. */ @@ -3032,19 +3086,6 @@ static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus) pl->netdev->sfp_bus = NULL; } -static const phy_interface_t phylink_sfp_interface_preference[] = { - PHY_INTERFACE_MODE_25GBASER, - PHY_INTERFACE_MODE_USXGMII, - PHY_INTERFACE_MODE_10GBASER, - PHY_INTERFACE_MODE_5GBASER, - PHY_INTERFACE_MODE_2500BASEX, - PHY_INTERFACE_MODE_SGMII, - PHY_INTERFACE_MODE_1000BASEX, - PHY_INTERFACE_MODE_100BASEX, -}; - -static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); - static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, const unsigned long *intf) { From a79d8ba734bdbd2574ad16dd1b96506e5f642c4a Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Nov 2023 12:42:44 -0300 Subject: [PATCH 1619/7721] selftests: tc-testing: remove buildebpf plugin As tdc only tests loading/deleting and anything more complicated is better left to the ebpf test suite, provide a pre-compiled version of 'action.c' and don't bother compiling it in kselftests or on the fly at all. Cc: Davide Caratti Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231124154248.315470-2-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/Makefile | 31 +------- tools/testing/selftests/tc-testing/README | 2 - .../testing/selftests/tc-testing/action-ebpf | Bin 0 -> 856 bytes .../tc-testing/plugin-lib/buildebpfPlugin.py | 67 ------------------ .../tc-testing/tc-tests/actions/bpf.json | 14 ++-- .../tc-testing/tc-tests/filters/bpf.json | 10 ++- tools/testing/selftests/tc-testing/tdc.sh | 2 +- 7 files changed, 12 insertions(+), 114 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/action-ebpf delete mode 100644 tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py diff --git a/tools/testing/selftests/tc-testing/Makefile b/tools/testing/selftests/tc-testing/Makefile index b1fa2e177e2f..e8b3dde4fa16 100644 --- a/tools/testing/selftests/tc-testing/Makefile +++ b/tools/testing/selftests/tc-testing/Makefile @@ -1,31 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -include ../../../scripts/Makefile.include - -top_srcdir = $(abspath ../../../..) -APIDIR := $(top_scrdir)/include/uapi -TEST_GEN_FILES = action.o - -include ../lib.mk - -PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) - -ifeq ($(PROBE),) - CPU ?= probe -else - CPU ?= generic -endif - -CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - &1 \ - | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') - -CLANG_FLAGS = -I. -I$(APIDIR) \ - $(CLANG_SYS_INCLUDES) \ - -Wno-compare-distinct-pointer-types - -$(OUTPUT)/%.o: %.c - $(CLANG) $(CLANG_FLAGS) \ - -O2 --target=bpf -emit-llvm -c $< -o - | \ - $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ TEST_PROGS += ./tdc.sh -TEST_FILES := tdc*.py Tdc*.py plugins plugin-lib tc-tests scripts +TEST_FILES := action-ebpf tdc*.py Tdc*.py plugins plugin-lib tc-tests scripts + +include ../lib.mk diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index be7b00799b3e..fc8e858ff119 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -195,8 +195,6 @@ directory: and the other is a test whether the command leaked memory or not. (This one is a preliminary version, it may not work quite right yet, but the overall template is there and it should only need tweaks.) - - buildebpfPlugin.py: - builds all programs in $EBPFDIR. ACKNOWLEDGEMENTS diff --git a/tools/testing/selftests/tc-testing/action-ebpf b/tools/testing/selftests/tc-testing/action-ebpf new file mode 100644 index 0000000000000000000000000000000000000000..4879479b2ee5c046279be0fe8f9ca313dfb7e618 GIT binary patch literal 856 zcmb_ayKcfj5L_FFP=-`UX`o1n`2r$0A&n*IpgTFnLKX%`_!N;U`3b&--wH~R684VW zGukMra)oDhcIIBb_s4kTdmixc;2Y|SRe;%r7+E=j7CQH2*%9vjGf8`~C9?lCIqPKq z0V7lbI2>i;4uxB2IQfRywbcWscZm%V+i>M{cKD3|LY-|jB&p8JwOW?M`i`k`$r`e- zC|*}8na?*>z5rF^X|}F1GK49FmEP#&8S!mp@PEb_r>Rd{&-q1E)skfwzsJ=^YYJZ^ zYA*SHxV}g7SDx>m{VgVh?O*Z}>URklWc~pgW_@`FFBFjbmFFLrY 0: - foutput = serr.decode("utf-8") - else: - foutput = rawout.decode("utf-8") - - proc.stdout.close() - proc.stderr.close() - return proc, foutput diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json index 91832400ddbd..6e00bf32ef9a 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json @@ -54,9 +54,6 @@ "actions", "bpf" ], - "plugins": { - "requires": "buildebpfPlugin" - }, "setup": [ [ "$TC action flush action bpf", @@ -65,10 +62,10 @@ 255 ] ], - "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ok index 667", + "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action-ebpf section action-ok index 667", "expExitCode": "0", "verifyCmd": "$TC action get action bpf index 667", - "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ok\\] id [0-9].* tag [0-9a-f]{16}( jited)? default-action pipe.*index 667 ref", + "matchPattern": "action order [0-9]*: bpf action-ebpf:\\[action-ok\\] id [0-9].* tag [0-9a-f]{16}( jited)? default-action pipe.*index 667 ref", "matchCount": "1", "teardown": [ "$TC action flush action bpf" @@ -81,9 +78,6 @@ "actions", "bpf" ], - "plugins": { - "requires": "buildebpfPlugin" - }, "setup": [ [ "$TC action flush action bpf", @@ -92,10 +86,10 @@ 255 ] ], - "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ko index 667", + "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action-ebpf section action-ko index 667", "expExitCode": "255", "verifyCmd": "$TC action get action bpf index 667", - "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ko\\] id [0-9].*index 667 ref", + "matchPattern": "action order [0-9]*: bpf action-ebpf:\\[action-ko\\] id [0-9].*index 667 ref", "matchCount": "0", "teardown": [ [ diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/filters/bpf.json index 013fb983bc3f..725d406a30ac 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/bpf.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/bpf.json @@ -52,17 +52,16 @@ ], "plugins": { "requires": [ - "buildebpfPlugin", "nsPlugin" ] }, "setup": [ "$TC qdisc add dev $DEV1 ingress" ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf object-file $EBPFDIR/action.o section action-ok", + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf object-file $EBPFDIR/action-ebpf section action-ok", "expExitCode": "0", "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf", - "matchPattern": "filter parent ffff: protocol ip pref 100 bpf chain [0-9]+ handle 0x1 action.o:\\[action-ok\\].*tag [0-9a-f]{16}( jited)?", + "matchPattern": "filter parent ffff: protocol ip pref 100 bpf chain [0-9]+ handle 0x1 action-ebpf:\\[action-ok\\].*tag [0-9a-f]{16}( jited)?", "matchCount": "1", "teardown": [ "$TC qdisc del dev $DEV1 ingress" @@ -77,17 +76,16 @@ ], "plugins": { "requires": [ - "buildebpfPlugin", "nsPlugin" ] }, "setup": [ "$TC qdisc add dev $DEV1 ingress" ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf object-file $EBPFDIR/action.o section action-ko", + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf object-file $EBPFDIR/action-ebpf section action-ko", "expExitCode": "1", "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 protocol ip prio 100 bpf", - "matchPattern": "filter parent ffff: protocol ip pref 100 bpf chain [0-9]+ handle 0x1 action.o:\\[action-ko\\].*tag [0-9a-f]{16}( jited)?", + "matchPattern": "filter parent ffff: protocol ip pref 100 bpf chain [0-9]+ handle 0x1 action-ebpf:\\[action-ko\\].*tag [0-9a-f]{16}( jited)?", "matchCount": "0", "teardown": [ "$TC qdisc del dev $DEV1 ingress" diff --git a/tools/testing/selftests/tc-testing/tdc.sh b/tools/testing/selftests/tc-testing/tdc.sh index 4dbe50bde5a0..407fa53822a0 100755 --- a/tools/testing/selftests/tc-testing/tdc.sh +++ b/tools/testing/selftests/tc-testing/tdc.sh @@ -64,5 +64,5 @@ try_modprobe sch_hfsc try_modprobe sch_hhf try_modprobe sch_htb try_modprobe sch_teql -./tdc.py -J`nproc` -c actions --nobuildebpf +./tdc.py -J`nproc` -c actions ./tdc.py -J`nproc` -c qdisc From 8059e68b99280cc9a224593f3142f9368229c6ee Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Nov 2023 12:42:45 -0300 Subject: [PATCH 1620/7721] selftests: tc-testing: remove unnecessary time.sleep This operation is redundant and it's not stabilizing nor waiting for anything. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231124154248.315470-3-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tdc.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 669ec89ebfe1..c5ec861687b6 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -497,11 +497,6 @@ def prepare_run(pm, args, testlist): pm.call_post_suite(1) return emergency_exit_message - if args.verbose: - print('give test rig 2 seconds to stabilize') - - time.sleep(2) - def purge_run(pm, index): pm.call_post_suite(index) From 56e16bc69bb7d36a931111d8abdcd44b939751c4 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Nov 2023 12:42:46 -0300 Subject: [PATCH 1621/7721] selftests: tc-testing: prefix iproute2 functions with "ipr2" As suggested by Simon, prefix the functions that operate on iproute2 commands in contrast with the "nl" netlink prefix. Cc: Simon Horman Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231124154248.315470-4-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/plugin-lib/nsPlugin.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 65c8f3f983b9..dc7a0597cf44 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -37,7 +37,7 @@ class SubPlugin(TdcPlugin): if netlink == True: self._nl_ns_create() else: - self._ns_create() + self._ipr2_ns_create() # Make sure the netns is visible in the fs ticks = 20 @@ -71,7 +71,7 @@ class SubPlugin(TdcPlugin): if netlink == True: self._nl_ns_destroy() else: - self._ns_destroy() + self._ipr2_ns_destroy() def post_suite(self, index): if self.args.verbose: @@ -161,7 +161,7 @@ class SubPlugin(TdcPlugin): ticks -= 1 continue - def _ns_create_cmds(self): + def _ipr2_ns_create_cmds(self): cmds = [] ns = self.args.NAMES['NS'] @@ -181,26 +181,26 @@ class SubPlugin(TdcPlugin): return cmds - def _ns_create(self): + def _ipr2_ns_create(self): ''' Create the network namespace in which the tests will be run and set up the required network devices for it. ''' - self._exec_cmd_batched('pre', self._ns_create_cmds()) + self._exec_cmd_batched('pre', self._ipr2_ns_create_cmds()) def _nl_ns_destroy(self): ns = self.args.NAMES['NS'] netns.remove(ns) - def _ns_destroy_cmd(self): + def _ipr2_ns_destroy_cmd(self): return self._replace_keywords('netns delete {}'.format(self.args.NAMES['NS'])) - def _ns_destroy(self): + def _ipr2_ns_destroy(self): ''' Destroy the network namespace for testing (and any associated network devices as well) ''' - self._exec_cmd('post', self._ns_destroy_cmd()) + self._exec_cmd('post', self._ipr2_ns_destroy_cmd()) @cached_property def _proc(self): From 501679f5d4a433144ae755dd2e5f757b1ce5a152 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Nov 2023 12:42:47 -0300 Subject: [PATCH 1622/7721] selftests: tc-testing: cleanup on Ctrl-C Cleanup net namespaces and other resources if we get a SIGINT (Ctrl-C). As user visible resources are allocated on a per test basis, it's only required to catch this condition when (possibly) running tests. So far calling post_suite is enough to free up anything that might linger. A missing keyword replacement for nsPlugin is also included. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231124154248.315470-5-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py | 2 +- tools/testing/selftests/tc-testing/tdc.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index dc7a0597cf44..77b1106b8388 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -78,7 +78,7 @@ class SubPlugin(TdcPlugin): print('{}.post_suite'.format(self.sub_class)) # Make sure we don't leak resources - cmd = "$IP -a netns del" + cmd = self._replace_keywords("$IP -a netns del") if self.args.verbose > 3: print('_exec_cmd: command "{}"'.format(cmd)) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index c5ec861687b6..caeacc691587 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -1018,7 +1018,11 @@ def main(): if args.verbose > 2: print('args is {}'.format(args)) - set_operation_mode(pm, parser, args, remaining) + try: + set_operation_mode(pm, parser, args, remaining) + except KeyboardInterrupt: + # Cleanup on Ctrl-C + pm.call_post_suite(None) if __name__ == "__main__": main() From ed346fccfc40364888601a2ec75dd94f4dca23bd Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Nov 2023 12:42:48 -0300 Subject: [PATCH 1623/7721] selftests: tc-testing: remove unused import Remove this leftover from the times we pre-allocated everything Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231124154248.315470-6-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py index 77b1106b8388..bb19b8b76d3b 100644 --- a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -23,8 +23,6 @@ class SubPlugin(TdcPlugin): super().__init__() def pre_suite(self, testcount, testlist): - from itertools import cycle - super().pre_suite(testcount, testlist) def prepare_test(self, test): From d74d8cdefcdcb8acf3be63eca6c5b5cefd534a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Sun, 26 Nov 2023 00:32:42 +0100 Subject: [PATCH 1624/7721] arm64: dts: renesas: r9a09g011: Add missing space in compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing space in compatible property and align style with rest of the file. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231125233242.237660-1-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g011.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi index 33f2ecf42441..50ed66d42a24 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi @@ -163,7 +163,7 @@ usb3peri: usb3peri@85070000 { }; avb: ethernet@a3300000 { - compatible = "renesas,etheravb-r9a09g011","renesas,etheravb-rzv2m"; + compatible = "renesas,etheravb-r9a09g011", "renesas,etheravb-rzv2m"; reg = <0 0xa3300000 0 0x800>; interrupts = , /* ch0: Rx0 BE */ , /* ch1: Rx1 NC */ From 95d516f3eb96bac466a6bfec28a1e55b8ed5160b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Sun, 26 Nov 2023 00:33:27 +0100 Subject: [PATCH 1625/7721] ARM: dts: renesas: r9a06g032: Add missing space in compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing space in compatible property and align style with rest of the file. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231125233327.238575-1-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Geert Uytterhoeven --- arch/arm/boot/dts/renesas/r9a06g032.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/renesas/r9a06g032.dtsi b/arch/arm/boot/dts/renesas/r9a06g032.dtsi index 0fa565a1c3ad..fa63e1afc4ef 100644 --- a/arch/arm/boot/dts/renesas/r9a06g032.dtsi +++ b/arch/arm/boot/dts/renesas/r9a06g032.dtsi @@ -437,7 +437,7 @@ gic: interrupt-controller@44101000 { }; can0: can@52104000 { - compatible = "renesas,r9a06g032-sja1000","renesas,rzn1-sja1000"; + compatible = "renesas,r9a06g032-sja1000", "renesas,rzn1-sja1000"; reg = <0x52104000 0x800>; reg-io-width = <4>; interrupts = ; From 9de586a0a1c58c935bd86b3432f6bf571c3ff24c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 25 Nov 2023 11:24:56 +0200 Subject: [PATCH 1626/7721] dt-bindings: omap: Add Motorola mapphone mz609 and mz617 tablets Let's add compatibles for some xyboard tablets, these are similar to the mapphone devices already listed but with different peripherals. Acked-by: Rob Herring Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/arm/ti/omap.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/ti/omap.yaml b/Documentation/devicetree/bindings/arm/ti/omap.yaml index b18fc046390a..93e04a109a12 100644 --- a/Documentation/devicetree/bindings/arm/ti/omap.yaml +++ b/Documentation/devicetree/bindings/arm/ti/omap.yaml @@ -134,6 +134,8 @@ properties: - amazon,omap4-kc1 # Amazon Kindle Fire (first generation) - motorola,droid4 # Motorola Droid 4 XT894 - motorola,droid-bionic # Motorola Droid Bionic XT875 + - motorola,xyboard-mz609 + - motorola,xyboard-mz617 - ti,omap4-panda - ti,omap4-sdp - const: ti,omap4430 From 662f20c4c450f882c97e9ae3b5801cff243a2c8b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 25 Nov 2023 11:24:56 +0200 Subject: [PATCH 1627/7721] ARM: dts: motorola-mapphone: Move LCD to common file for xt875 and xt894 The LCD regulator and backlight are specific only to droid bionic xt875 and droid4 xt894. On droid razr xt910 and xt912, the LCD regulator and backlight are different. The LCD and backlight are also different on the the mz609 tablets. Let's add a common motorola-mapphone-xt8xx.dtsi to make it easy to add support for xt910 and xt912 and the mz609 to mz617 tablets. While at it, let's also move aliases to the board specific dts files where they belong. And let's move the omap4-droid4-xt894.dts compatible to the top. Signed-off-by: Tony Lindgren --- .../dts/ti/omap/motorola-mapphone-common.dtsi | 79 ------------------- .../dts/ti/omap/motorola-mapphone-xt8xx.dtsi | 75 ++++++++++++++++++ .../dts/ti/omap/omap4-droid-bionic-xt875.dts | 11 ++- .../boot/dts/ti/omap/omap4-droid4-xt894.dts | 19 +++-- 4 files changed, 98 insertions(+), 86 deletions(-) create mode 100644 arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi index a2bb3609c94f..93a3c58feecb 100644 --- a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi @@ -6,15 +6,6 @@ #include "motorola-cpcap-mapphone.dtsi" / { - chosen { - stdout-path = &uart3; - }; - - aliases { - display0 = &lcd0; - display1 = &hdmi0; - }; - /* * We seem to have only 1021 MB accessible, 1021 - 1022 is locked, * then 1023 - 1024 seems to contain mbm. @@ -92,17 +83,6 @@ hsusb2_phy: usb-phy@2 { #phy-cells = <0>; }; - /* LCD regulator from sw5 source */ - lcd_regulator: regulator-lcd { - compatible = "regulator-fixed"; - regulator-name = "lcd"; - regulator-min-microvolt = <5050000>; - regulator-max-microvolt = <5050000>; - gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; /* gpio96 */ - enable-active-high; - vin-supply = <&sw5>; - }; - /* This is probably coming straight from the battery.. */ wl12xx_vmmc: regulator-wl12xx { compatible = "regulator-fixed"; @@ -160,14 +140,6 @@ vibrator { pwm-names = "enable", "direction"; direction-duty-cycle-ns = <10000000>; }; - - backlight: backlight { - compatible = "led-backlight"; - - leds = <&backlight_led>; - brightness-levels = <31 63 95 127 159 191 223 255>; - default-brightness-level = <6>; - }; }; &cpu_thermal { @@ -197,57 +169,6 @@ &dss { status = "okay"; }; -&dsi1 { - status = "okay"; - vdd-supply = <&vcsi>; - - port { - dsi1_out_ep: endpoint { - remote-endpoint = <&lcd0_in>; - lanes = <0 1 2 3 4 5>; - }; - }; - - lcd0: panel@0 { - compatible = "motorola,droid4-panel", "panel-dsi-cm"; - reg = <0>; - label = "lcd0"; - vddi-supply = <&lcd_regulator>; - reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ - - backlight = <&backlight>; - - width-mm = <50>; - height-mm = <89>; - rotation = <90>; - - panel-timing { - clock-frequency = <0>; /* Calculated by dsi */ - - hback-porch = <2>; - hactive = <540>; - hfront-porch = <0>; - hsync-len = <2>; - - vback-porch = <1>; - vactive = <960>; - vfront-porch = <0>; - vsync-len = <1>; - - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - }; - - port { - lcd0_in: endpoint { - remote-endpoint = <&dsi1_out_ep>; - }; - }; - }; -}; - &hdmi { status = "okay"; pinctrl-0 = <&dss_hdmi_pins>; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi new file mode 100644 index 000000000000..aa13bc23bf35 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-common.dtsi" + +/ { + backlight: backlight { + compatible = "led-backlight"; + + leds = <&backlight_led>; + brightness-levels = <31 63 95 127 159 191 223 255>; + default-brightness-level = <6>; + }; + + /* LCD regulator from sw5 source */ + lcd_regulator: regulator-lcd { + compatible = "regulator-fixed"; + regulator-name = "lcd"; + regulator-min-microvolt = <5050000>; + regulator-max-microvolt = <5050000>; + gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; /* gpio96 */ + enable-active-high; + vin-supply = <&sw5>; + }; +}; + +&dsi1 { + status = "okay"; + vdd-supply = <&vcsi>; + + port { + dsi1_out_ep: endpoint { + remote-endpoint = <&lcd0_in>; + lanes = <0 1 2 3 4 5>; + }; + }; + + lcd0: panel@0 { + compatible = "motorola,droid4-panel", "panel-dsi-cm"; + reg = <0>; + label = "lcd0"; + vddi-supply = <&lcd_regulator>; + reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + backlight = <&backlight>; + + width-mm = <50>; + height-mm = <89>; + rotation = <90>; + + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + + hback-porch = <2>; + hactive = <540>; + hfront-porch = <0>; + hsync-len = <2>; + + vback-porch = <1>; + vactive = <960>; + vfront-porch = <0>; + vsync-len = <1>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts b/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts index ccf03a743678..1d9000f84f1b 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts @@ -1,11 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-only /dts-v1/; -#include "motorola-mapphone-common.dtsi" +#include "motorola-mapphone-xt8xx.dtsi" / { model = "Motorola Droid Bionic XT875"; compatible = "motorola,droid-bionic", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display0 = &lcd0; + display1 = &hdmi0; + }; }; &keypad { diff --git a/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts b/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts index e833c21f1c01..cc3f3e1b65ea 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts @@ -1,9 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-only /dts-v1/; -#include "motorola-mapphone-common.dtsi" +#include "motorola-mapphone-xt8xx.dtsi" / { + model = "Motorola Droid 4 XT894"; + compatible = "motorola,droid4", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display0 = &lcd0; + display1 = &hdmi0; + }; + gpio_keys { compatible = "gpio-keys"; @@ -33,11 +45,6 @@ slider { }; }; -/ { - model = "Motorola Droid 4 XT894"; - compatible = "motorola,droid4", "ti,omap4430", "ti,omap4"; -}; - &keypad { keypad,num-rows = <8>; keypad,num-columns = <8>; From 1b5115d655a791a6ae95f789d195c8d211acdaea Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 25 Nov 2023 11:24:56 +0200 Subject: [PATCH 1628/7721] ARM: dts: motorola-mapphone: Move handset devices to a common file The mapphone tablets do not have same peripherals as the mapphone handsets. Let's move the handset specific devices into a common motorola-mapphone-handset.dtsi file. Signed-off-by: Tony Lindgren --- .../dts/ti/omap/motorola-mapphone-common.dtsi | 219 ---------------- .../ti/omap/motorola-mapphone-handset.dtsi | 234 ++++++++++++++++++ .../dts/ti/omap/motorola-mapphone-xt8xx.dtsi | 2 +- 3 files changed, 235 insertions(+), 220 deletions(-) create mode 100644 arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi index 93a3c58feecb..a0c53d9c2625 100644 --- a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi @@ -54,35 +54,6 @@ hdmi_regulator: regulator-hdmi { regulator-always-on; }; - /* FS USB Host PHY on port 1 for mdm6600 */ - fsusb1_phy: usb-phy@1 { - compatible = "motorola,mapphone-mdm6600"; - pinctrl-0 = <&usb_mdm6600_pins>; - pinctrl-1 = <&usb_mdm6600_sleep_pins>; - pinctrl-names = "default", "sleep"; - enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; /* gpio_95 */ - power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; /* gpio_54 */ - reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; /* gpio_49 */ - /* mode: gpio_148 gpio_149 */ - motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>, - <&gpio5 21 GPIO_ACTIVE_HIGH>; - /* cmd: gpio_103 gpio_104 gpio_142 */ - motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>, - <&gpio4 8 GPIO_ACTIVE_HIGH>, - <&gpio5 14 GPIO_ACTIVE_HIGH>; - /* status: gpio_52 gpio_53 gpio_55 */ - motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>, - <&gpio2 21 GPIO_ACTIVE_HIGH>, - <&gpio2 23 GPIO_ACTIVE_HIGH>; - #phy-cells = <0>; - }; - - /* HS USB host TLL nop-phy on port 2 for w3glte */ - hsusb2_phy: usb-phy@2 { - compatible = "usb-nop-xceiv"; - #phy-cells = <0>; - }; - /* This is probably coming straight from the battery.. */ wl12xx_vmmc: regulator-wl12xx { compatible = "regulator-fixed"; @@ -113,33 +84,6 @@ soundcard { dais = <&mcbsp2_port>, <&mcbsp3_port>; }; - - pwm8: pwm-8 { - pinctrl-names = "default"; - pinctrl-0 = <&vibrator_direction_pin>; - - compatible = "ti,omap-dmtimer-pwm"; - #pwm-cells = <3>; - ti,timers = <&timer8>; - ti,clock-source = <0x01>; - }; - - pwm9: pwm-9 { - pinctrl-names = "default"; - pinctrl-0 = <&vibrator_enable_pin>; - - compatible = "ti,omap-dmtimer-pwm"; - #pwm-cells = <3>; - ti,timers = <&timer9>; - ti,clock-source = <0x01>; - }; - - vibrator { - compatible = "pwm-vibrator"; - pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>; - pwm-names = "enable", "direction"; - direction-duty-cycle-ns = <10000000>; - }; }; &cpu_thermal { @@ -183,13 +127,6 @@ hdmi_out: endpoint { }; }; -/* Battery NVRAM on 1-wire handled by w1_ds250x driver */ -&hdqw1w { - pinctrl-0 = <&hdq_pins>; - pinctrl-names = "default"; - ti,mode = "1w"; -}; - &i2c1 { tmp105@48 { compatible = "ti,tmp105"; @@ -243,34 +180,6 @@ wlcore: wlcore@2 { }; }; -&i2c2 { - touchscreen@4a { - compatible = "atmel,maxtouch"; - reg = <0x4a>; - pinctrl-names = "default"; - pinctrl-0 = <&touchscreen_pins>; - - reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */ - - /* gpio_183 with sys_nirq2 pad as wakeup */ - interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>, - <&omap4_pmx_core 0x160>; - interrupt-names = "irq", "wakeup"; - wakeup-source; - }; - - isl29030@44 { - compatible = "isil,isl29030"; - reg = <0x44>; - - pinctrl-names = "default"; - pinctrl-0 = <&als_proximity_pins>; - - interrupt-parent = <&gpio6>; - interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */ - }; -}; - &omap4_pmx_core { /* hdmi_hpd.gpio_63 */ @@ -280,13 +189,6 @@ OMAP4_IOPAD(0x098, PIN_INPUT | MUX_MODE3) >; }; - hdq_pins: hdq-pins { - pinctrl-single,pins = < - /* 0x4a100120 hdq_sio.hdq_sio aa27 */ - OMAP4_IOPAD(0x120, PIN_INPUT | MUX_MODE0) - >; - }; - /* hdmi_cec.hdmi_cec, hdmi_scl.hdmi_scl, hdmi_sda.hdmi_sda */ dss_hdmi_pins: dss-hdmi-pins { pinctrl-single,pins = < @@ -348,73 +250,6 @@ OMAP4_IOPAD(0x088, PIN_OUTPUT | MUX_MODE3) >; }; - touchscreen_pins: touchscreen-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) - >; - }; - - als_proximity_pins: als-proximity-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3) - >; - }; - - usb_mdm6600_pins: usb-mdm6600-pins { - pinctrl-single,pins = < - /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */ - OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) - - /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */ - OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) - - /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */ - OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3) - - /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */ - OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) - - /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */ - OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) - - /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */ - OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) - - /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */ - OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) - - /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */ - OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) - - /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */ - OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) - - /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */ - OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) - - /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */ - OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) - >; - }; - - /* Modem sleep pins to keep gpio_49 high with internal pull */ - usb_mdm6600_sleep_pins: usb-mdm6600-sleep-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x072, PIN_INPUT_PULLUP | MUX_MODE7) /* Keep gpio_49 reset high */ - OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) - >; - }; - usb_ulpi_pins: usb-ulpi-pins { pinctrl-single,pins = < OMAP4_IOPAD(0x196, MUX_MODE7) @@ -522,18 +357,6 @@ OMAP4_IOPAD(0x10a, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_clkx */ OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_fsx */ >; }; - - vibrator_direction_pin: vibrator-direction-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */ - >; - }; - - vibrator_enable_pin: vibrator-enable-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */ - >; - }; }; &omap4_pmx_wkup { @@ -550,17 +373,6 @@ &rng_target { status = "disabled"; }; -/* Configure pwm clock source for timers 8 & 9 */ -&timer8 { - assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>; - assigned-clock-parents = <&sys_32k_ck>; -}; - -&timer9 { - assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>; - assigned-clock-parents = <&sys_32k_ck>; -}; - /* * The uart1 port is wired to mdm6600 with rts and cts. The modem uses gpio_149 * for wake-up events for both the USB PHY and the UART. We can use gpio_149 @@ -593,20 +405,6 @@ bluetooth { }; }; -&usbhsohci { - phys = <&fsusb1_phy>; - phy-names = "usb"; -}; - -&usbhsehci { - phys = <&hsusb2_phy>; -}; - -&usbhshost { - port1-mode = "ohci-phy-4pin-dpdm"; - port2-mode = "ehci-tll"; -}; - /* Internal UTMI+ PHY used for OTG, CPCAP ULPI PHY for detection and charger */ &usb_otg_hs { interface-type = <1>; @@ -619,23 +417,6 @@ &usb_otg_hs { power = <150>; }; -&i2c4 { - ak8975: magnetometer@c { - compatible = "asahi-kasei,ak8975"; - reg = <0x0c>; - - vdd-supply = <&vhvio>; - - interrupt-parent = <&gpio6>; - interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */ - - rotation-matrix = "-1", "0", "0", - "0", "1", "0", - "0", "0", "-1"; - - }; -}; - &mcbsp2 { #sound-dai-cells = <0>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi new file mode 100644 index 000000000000..f3f9ff02b35f --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-common.dtsi" + +/ { + /* FS USB Host PHY on port 1 for mdm6600 */ + fsusb1_phy: usb-phy@1 { + compatible = "motorola,mapphone-mdm6600"; + pinctrl-0 = <&usb_mdm6600_pins>; + pinctrl-1 = <&usb_mdm6600_sleep_pins>; + pinctrl-names = "default", "sleep"; + enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; /* gpio_95 */ + power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; /* gpio_54 */ + reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; /* gpio_49 */ + /* mode: gpio_148 gpio_149 */ + motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>, + <&gpio5 21 GPIO_ACTIVE_HIGH>; + /* cmd: gpio_103 gpio_104 gpio_142 */ + motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>, + <&gpio4 8 GPIO_ACTIVE_HIGH>, + <&gpio5 14 GPIO_ACTIVE_HIGH>; + /* status: gpio_52 gpio_53 gpio_55 */ + motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>, + <&gpio2 21 GPIO_ACTIVE_HIGH>, + <&gpio2 23 GPIO_ACTIVE_HIGH>; + #phy-cells = <0>; + }; + + /* HS USB host TLL nop-phy on port 2 for w3glte */ + hsusb2_phy: usb-phy@2 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + pwm8: pwm-8 { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_direction_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer8>; + ti,clock-source = <0x01>; + }; + + pwm9: pwm-9 { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_enable_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer9>; + ti,clock-source = <0x01>; + }; + + vibrator { + compatible = "pwm-vibrator"; + pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>; + pwm-names = "enable", "direction"; + direction-duty-cycle-ns = <10000000>; + }; +}; + +/* Battery NVRAM on 1-wire handled by w1_ds250x driver */ +&hdqw1w { + pinctrl-0 = <&hdq_pins>; + pinctrl-names = "default"; + ti,mode = "1w"; +}; + +&i2c2 { + touchscreen@4a { + compatible = "atmel,maxtouch"; + reg = <0x4a>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */ + + /* gpio_183 with sys_nirq2 pad as wakeup */ + interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>, + <&omap4_pmx_core 0x160>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; + + isl29030@44 { + compatible = "isil,isl29030"; + reg = <0x44>; + + pinctrl-names = "default"; + pinctrl-0 = <&als_proximity_pins>; + + interrupt-parent = <&gpio6>; + interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */ + }; +}; + +&omap4_pmx_core { + hdq_pins: hdq-pins { + pinctrl-single,pins = < + /* 0x4a100120 hdq_sio.hdq_sio aa27 */ + OMAP4_IOPAD(0x120, PIN_INPUT | MUX_MODE0) + >; + }; + + /* kpd_row0.gpio_178 */ + tmp105_irq: tmp105-irq-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x18e, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + touchscreen_pins: touchscreen-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + usb_mdm6600_pins: usb-mdm6600-pins { + pinctrl-single,pins = < + /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */ + OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) + + /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */ + OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) + + /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */ + OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3) + + /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */ + OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) + + /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */ + OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) + + /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */ + OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) + + /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */ + OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) + + /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */ + OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) + + /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */ + OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) + + /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */ + OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) + + /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */ + OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) + >; + }; + + /* Modem sleep pins to keep gpio_49 high with internal pull */ + usb_mdm6600_sleep_pins: usb-mdm6600-sleep-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x072, PIN_INPUT_PULLUP | MUX_MODE7) /* Keep gpio_49 reset high */ + OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) + >; + }; + + als_proximity_pins: als-proximity-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + vibrator_direction_pin: vibrator-direction-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */ + >; + }; + + vibrator_enable_pin: vibrator-enable-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */ + >; + }; +}; + +/* Configure pwm clock source for timers 8 & 9 */ +&timer8 { + assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>; + assigned-clock-parents = <&sys_32k_ck>; +}; + +&timer9 { + assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>; + assigned-clock-parents = <&sys_32k_ck>; +}; + +&usbhsohci { + phys = <&fsusb1_phy>; + phy-names = "usb"; +}; + +&usbhsehci { + phys = <&hsusb2_phy>; +}; + +&usbhshost { + port1-mode = "ohci-phy-4pin-dpdm"; + port2-mode = "ehci-tll"; +}; + +&i2c4 { + ak8975: magnetometer@c { + compatible = "asahi-kasei,ak8975"; + reg = <0x0c>; + + vdd-supply = <&vhvio>; + + interrupt-parent = <&gpio6>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */ + + rotation-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "-1"; + + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi index aa13bc23bf35..8b8de92b5424 100644 --- a/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /dts-v1/; -#include "motorola-mapphone-common.dtsi" +#include "motorola-mapphone-handset.dtsi" / { backlight: backlight { From 94bd4a6e6e6bd79c7214bab4a739db8c493b792f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 25 Nov 2023 11:24:56 +0200 Subject: [PATCH 1629/7721] ARM: dts: motorola-mapphone: Add basic support for mz609 and mz617 The Motorola mapphone tablets are similar to the mapphone phones, but with different display and without some phone related peripherals. Let's add a new motorola-mapphone-mz607-mz617.dtsi and basic files for xyboard mz609 and mz617. All the tablets from mz607 to mz617 are quite similar so let's use motorola-mapphone-mz607-mz617.dtsi naming for the common file. Note that the tc358765 lcd bridge needs driver changes before it can be added. Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/Makefile | 4 +- .../omap/motorola-mapphone-mz607-mz617.dtsi | 21 +++++++++ .../boot/dts/ti/omap/omap4-xyboard-mz609.dts | 46 +++++++++++++++++++ .../boot/dts/ti/omap/omap4-xyboard-mz617.dts | 17 +++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi create mode 100644 arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts create mode 100644 arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts diff --git a/arch/arm/boot/dts/ti/omap/Makefile b/arch/arm/boot/dts/ti/omap/Makefile index d2b590004fed..a002f6035fde 100644 --- a/arch/arm/boot/dts/ti/omap/Makefile +++ b/arch/arm/boot/dts/ti/omap/Makefile @@ -79,7 +79,9 @@ dtb-$(CONFIG_ARCH_OMAP4) += \ omap4-sdp.dtb \ omap4-sdp-es23plus.dtb \ omap4-var-dvk-om44.dtb \ - omap4-var-stk-om44.dtb + omap4-var-stk-om44.dtb \ + omap4-xyboard-mz609.dtb \ + omap4-xyboard-mz617.dtb dtb-$(CONFIG_SOC_AM33XX) += \ am335x-baltos-ir2110.dtb \ am335x-baltos-ir3220.dtb \ diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi new file mode 100644 index 000000000000..a356b3a2f24e --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-common.dtsi" + +&keypad { + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = , + ; +}; + +/* + * On tablets, mmc1 regulator is vsimcard instead of vwlan2 in the stock kernel + * dtb. The regulator may not be wired even if a MMC cage is added though. + */ +&mmc1 { + vmmc-supply = <&vsimcard>; + bus-width = <4>; + cd-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* gpio_176 */ +}; diff --git a/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts new file mode 100644 index 000000000000..762934e2d075 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-mz607-mz617.dtsi" + +/ { + model = "Motorola Xyboard MZ609"; + compatible = "motorola,xyboard-mz609", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display1 = &hdmi0; + }; + + backlight: backlight { + compatible = "led-backlight"; + + leds = <&backlight_led>; + brightness-levels = <31 63 95 127 159 191 223 255>; + default-brightness-level = <6>; + }; +}; + +&i2c1 { + led-controller@38 { + compatible = "ti,lm3532"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x38>; + + enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; + + ramp-up-us = <1024>; + ramp-down-us = <8193>; + + backlight_led: led@0 { + reg = <0>; + led-sources = <2>; + ti,led-mode = <0>; + label = ":backlight"; + }; + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts new file mode 100644 index 000000000000..b9caea3b7f9d --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-mz607-mz617.dtsi" + +/ { + model = "Motorola Xyboard MZ617"; + compatible = "motorola,xyboard-mz617", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display1 = &hdmi0; + }; +}; From 9ecf44fedc17ff267968b5fff589bf6793fc7ddd Mon Sep 17 00:00:00 2001 From: Jimmy Hon Date: Sun, 26 Nov 2023 14:08:45 -0600 Subject: [PATCH 1630/7721] arm64: dts: rockchip: add USB3 host on rk3588s-orangepi-5 Enable USB3 host controller for the Orange Pi 5. Signed-off-by: Jimmy Hon Link: https://lore.kernel.org/r/20231126200845.1192-1-honyuenkwun@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts index 8f399c4317bd..f7a6132d8205 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts @@ -660,3 +660,7 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&usb_host2_xhci { + status = "okay"; +}; From b685460632d51d7307bbba3d173c0dd6dbf38fa8 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Sat, 25 Nov 2023 19:59:13 +0530 Subject: [PATCH 1631/7721] dt-bindings: arm: rockchip: Update edgeble-neu6 bindings Current binding has following compatible combination for SoM, IO board - NCM6A: edgeble,neural-compute-module-6a, edgeble,neural-compute-module-6a-io - NCM6B: edgeble,neural-compute-module-6b, edgeble,neural-compute-module-6b-io This board topology now changes in final revisions, so a common compatible IO board, NCM6A-IO, is made available for both variants of SoM: NCM6A and NCM6B, produced by Edgeble AI. With this change, 6b-io is not as available and 6a; 6b SoM's have the same compatible IO board as 6a-io. This change is due to the common optimised design of the IO board made available now in final revisions, which was not the case in initial revisions. Update the dt-bindings with this new change. Signed-off-by: Jagan Teki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231125142914.57459-1-jagan@edgeble.ai Signed-off-by: Heiko Stuebner --- .../devicetree/bindings/arm/rockchip.yaml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 5b015c4ed775..e756977acd51 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -101,16 +101,12 @@ properties: - const: edgeble,neural-compute-module-2 # Edgeble Neural Compute Module 2 SoM - const: rockchip,rv1126 - - description: Edgeble Neural Compute Module 6(Neu6) Model A SoM based boards + - description: Edgeble Neural Compute Module 6(Neu6) SoM based boards items: - - const: edgeble,neural-compute-module-6a-io # Edgeble Neural Compute Module 6A IO Board - - const: edgeble,neural-compute-module-6a # Edgeble Neural Compute Module 6A SoM - - const: rockchip,rk3588 - - - description: Edgeble Neural Compute Module 6(Neu6) Model B SoM based boards - items: - - const: edgeble,neural-compute-module-6b-io # Edgeble Neural Compute Module 6B IO Board - - const: edgeble,neural-compute-module-6b # Edgeble Neural Compute Module 6B SoM + - const: edgeble,neural-compute-module-6a-io # Edgeble NCM6A-IO Board + - enum: + - edgeble,neural-compute-module-6a # Edgeble Neural Compute Module 6A SoM + - edgeble,neural-compute-module-6b # Edgeble Neural Compute Module 6B SoM - const: rockchip,rk3588 - description: Elgin RV1108 R1 From 2e9b4e598d287c152261ac614b9517b68241b0d7 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Sat, 25 Nov 2023 19:59:14 +0530 Subject: [PATCH 1632/7721] arm64: dts: rockchip: Use NCM6A-IO board for edgeble-neu6b Edgeble AI 6TOPS board topology is now changed in final revisions as a compatible IO board, NCM6A-IO, is made available for both variants of SoM: NCM6A and NCM6B. With this change, 6b-io is not as available and 6a; 6b SoM's have the same compatible IO board as 6a-io. This change is due to the common optimised design of the IO board made available now in final revisions, which was not the case in initial revisions. So, use the NCM6A-IO compatible for NCM6B SoM based IO dts. Signed-off-by: Jagan Teki Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231125142914.57459-2-jagan@edgeble.ai Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts index 9933765e4097..861067b5d707 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts @@ -9,7 +9,7 @@ / { model = "Edgeble Neu6B IO Board"; - compatible = "edgeble,neural-compute-module-6b-io", + compatible = "edgeble,neural-compute-module-6a-io", "edgeble,neural-compute-module-6b", "rockchip,rk3588"; aliases { From 737077b873e32254959bc6f8c3e63cc67ba1f44c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 24 Nov 2023 16:39:17 +0000 Subject: [PATCH 1633/7721] drm/imagination: Fix a couple of spelling mistakes in literal strings There are a couple of spelling mistakes in literal strings in the stid_fmts array. Fix these. Signed-off-by: Colin Ian King Reviewed-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231124163917.300685-1-colin.i.king@gmail.com --- drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h index 571954182f33..56e11009e123 100644 --- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h @@ -497,7 +497,7 @@ static const struct rogue_km_stid_fmt stid_fmts[] = { { ROGUE_FW_LOG_CREATESFID(213, ROGUE_FW_GROUP_MAIN, 1), "Safety Watchdog threshold period set to 0x%x clock cycles" }, { ROGUE_FW_LOG_CREATESFID(214, ROGUE_FW_GROUP_MAIN, 0), - "MTS Safety Event trigged by the safety watchdog." }, + "MTS Safety Event triggered by the safety watchdog." }, { ROGUE_FW_LOG_CREATESFID(215, ROGUE_FW_GROUP_MAIN, 3), "DM%d USC tasks range limit 0 - %d, stride %d" }, { ROGUE_FW_LOG_CREATESFID(216, ROGUE_FW_GROUP_MAIN, 1), @@ -1114,7 +1114,7 @@ static const struct rogue_km_stid_fmt stid_fmts[] = { { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_SPM, 2), "3DMemFree matches freelist 0x%08x (FL type = %u)" }, { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_SPM, 0), - "Raise the 3DMemFreeDedected flag" }, + "Raise the 3DMemFreeDetected flag" }, { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_SPM, 1), "Wait for pending grow on Freelist 0x%08x" }, { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_SPM, 1), From 3519d77293fb74786a45811fa6b600db26c1b0be Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 27 Nov 2023 09:04:30 +0800 Subject: [PATCH 1634/7721] drm/imagination: Remove unneeded semicolon ./drivers/gpu/drm/imagination/pvr_free_list.c:258:2-3: Unneeded semicolon Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7635 Signed-off-by: Yang Li Reviewed-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231127010430.119666-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/imagination/pvr_free_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_free_list.c b/drivers/gpu/drm/imagination/pvr_free_list.c index c61fd417edcb..5e51bc980751 100644 --- a/drivers/gpu/drm/imagination/pvr_free_list.c +++ b/drivers/gpu/drm/imagination/pvr_free_list.c @@ -255,7 +255,7 @@ pvr_free_list_insert_pages_locked(struct pvr_free_list *free_list, if (!num_pages) break; - }; + } /* clang-format on */ /* Make sure our free_list update is flushed. */ From 4aa89e8644d3b8879191911edea0b6a63ea9d6e2 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 25 Nov 2023 00:36:36 +0100 Subject: [PATCH 1635/7721] drm/imagination: vm: prevent duplicate drm_gpuvm_bo instances Use drm_gpuvm_bo_obtain() instead of drm_gpuvm_bo_create(). The latter should only be used in conjunction with drm_gpuvm_bo_obtain_prealloc(). drm_gpuvm_bo_obtain() re-uses existing instances of a given VM and BO combination, whereas drm_gpuvm_bo_create() would always create a new instance of struct drm_gpuvm_bo and hence leave us with duplicates. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Danilo Krummrich Reviewed-by: Donald Robson Tested-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231124233650.152653-2-dakr@redhat.com --- drivers/gpu/drm/imagination/pvr_vm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 3ad1366294b9..09d481c575b0 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -224,6 +224,7 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, struct pvr_gem_object *pvr_obj, u64 offset, u64 device_addr, u64 size) { + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); const bool is_user = vm_ctx == vm_ctx->pvr_dev->kernel_vm_ctx; const u64 pvr_obj_size = pvr_gem_object_size(pvr_obj); struct sg_table *sgt; @@ -245,10 +246,11 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, bind_op->type = PVR_VM_BIND_TYPE_MAP; - bind_op->gpuvm_bo = drm_gpuvm_bo_create(&vm_ctx->gpuvm_mgr, - gem_from_pvr_gem(pvr_obj)); - if (!bind_op->gpuvm_bo) - return -ENOMEM; + dma_resv_lock(obj->resv, NULL); + bind_op->gpuvm_bo = drm_gpuvm_bo_obtain(&vm_ctx->gpuvm_mgr, obj); + dma_resv_unlock(obj->resv); + if (IS_ERR(bind_op->gpuvm_bo)) + return PTR_ERR(bind_op->gpuvm_bo); bind_op->new_va = kzalloc(sizeof(*bind_op->new_va), GFP_KERNEL); bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL); From 4550d66d08b2257a1b2d3ce339d68ca33177f4b9 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 25 Nov 2023 00:36:37 +0100 Subject: [PATCH 1636/7721] drm/imagination: vm: check for drm_gpuvm_range_valid() Extend pvr_device_addr_and_size_are_valid() by the corresponding GPUVM sanity checks. This includes a, previously missing, overflow check for the base address and size of the requested mapping. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Danilo Krummrich Reviewed-by: Donald Robson Tested-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231124233650.152653-3-dakr@redhat.com --- drivers/gpu/drm/imagination/pvr_vm.c | 9 ++++++--- drivers/gpu/drm/imagination/pvr_vm.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 09d481c575b0..1e89092c3dcc 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -239,7 +239,7 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, return -EINVAL; } - if (!pvr_device_addr_and_size_are_valid(device_addr, size) || + if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size) || offset & ~PAGE_MASK || size & ~PAGE_MASK || offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) return -EINVAL; @@ -295,7 +295,7 @@ pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op, { int err; - if (!pvr_device_addr_and_size_are_valid(device_addr, size)) + if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size)) return -EINVAL; bind_op->type = PVR_VM_BIND_TYPE_UNMAP; @@ -505,6 +505,7 @@ pvr_device_addr_is_valid(u64 device_addr) /** * pvr_device_addr_and_size_are_valid() - Tests whether a device-virtual * address and associated size are both valid. + * @vm_ctx: Target VM context. * @device_addr: Virtual device address to test. * @size: Size of the range based at @device_addr to test. * @@ -523,9 +524,11 @@ pvr_device_addr_is_valid(u64 device_addr) * * %false otherwise. */ bool -pvr_device_addr_and_size_are_valid(u64 device_addr, u64 size) +pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, + u64 device_addr, u64 size) { return pvr_device_addr_is_valid(device_addr) && + drm_gpuvm_range_valid(&vm_ctx->gpuvm_mgr, device_addr, size) && size != 0 && (size & ~PVR_DEVICE_PAGE_MASK) == 0 && (device_addr + size <= PVR_PAGE_TABLE_ADDR_SPACE_SIZE); } diff --git a/drivers/gpu/drm/imagination/pvr_vm.h b/drivers/gpu/drm/imagination/pvr_vm.h index cf8b97553dc8..f2a6463f2b05 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.h +++ b/drivers/gpu/drm/imagination/pvr_vm.h @@ -29,7 +29,8 @@ struct drm_exec; /* Functions defined in pvr_vm.c */ bool pvr_device_addr_is_valid(u64 device_addr); -bool pvr_device_addr_and_size_are_valid(u64 device_addr, u64 size); +bool pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, + u64 device_addr, u64 size); struct pvr_vm_context *pvr_vm_create_context(struct pvr_device *pvr_dev, bool is_userspace_context); From 0d3abd456be45369235dd75793ce26f07900044c Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 25 Nov 2023 00:36:38 +0100 Subject: [PATCH 1637/7721] drm/imagination: vm: fix drm_gpuvm reference count The driver specific reference count indicates whether the VM should be teared down, whereas GPUVM's reference count indicates whether the VM structure can finally be freed. Hence, free the VM structure in pvr_gpuvm_free() and drop the last GPUVM reference after tearing down the VM. Generally, this prevents lifetime issues such as the VM being freed as long as drm_gpuvm_bo structures still hold references to the VM. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Danilo Krummrich Reviewed-by: Donald Robson Tested-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231124233650.152653-4-dakr@redhat.com --- drivers/gpu/drm/imagination/pvr_vm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 1e89092c3dcc..e0d74d9a6190 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -64,6 +64,12 @@ struct pvr_vm_context { struct drm_gem_object dummy_gem; }; +static inline +struct pvr_vm_context *to_pvr_vm_context(struct drm_gpuvm *gpuvm) +{ + return container_of(gpuvm, struct pvr_vm_context, gpuvm_mgr); +} + struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx) { if (vm_ctx) @@ -535,7 +541,7 @@ pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) { - + kfree(to_pvr_vm_context(gpuvm)); } static const struct drm_gpuvm_ops pvr_vm_gpuva_ops = { @@ -655,12 +661,11 @@ pvr_vm_context_release(struct kref *ref_count) WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, vm_ctx->gpuvm_mgr.mm_range)); - drm_gpuvm_put(&vm_ctx->gpuvm_mgr); pvr_mmu_context_destroy(vm_ctx->mmu_ctx); drm_gem_private_object_fini(&vm_ctx->dummy_gem); mutex_destroy(&vm_ctx->lock); - kfree(vm_ctx); + drm_gpuvm_put(&vm_ctx->gpuvm_mgr); } /** From 8c91ca76f44804868d12aed20ebdbc2f89aa7d60 Mon Sep 17 00:00:00 2001 From: Kamil Duljas Date: Thu, 16 Nov 2023 23:01:03 +0100 Subject: [PATCH 1638/7721] ASoC: SOF: icp3-dtrace: Fix wrong kfree() usage trace_filter_parse() allocs memory for *out and when -ENOMEM is returned, caller function, dfsentry_trace_filter_write() trying to freed this memory. After this patch, the memory is freed in trace_filter_parse() before -EINVAL returned. In caller function removed kfree(elms) from error label Signed-off-by: Kamil Duljas Link: https://lore.kernel.org/r/20231116220102.2097-2-kamil.duljas@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-dtrace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index 0dca139322f3..93b189c2d2ee 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -137,6 +137,7 @@ static int trace_filter_parse(struct snd_sof_dev *sdev, char *string, dev_err(sdev->dev, "Parsing filter entry '%s' failed with %d\n", entry, entry_len); + kfree(*out); return -EINVAL; } } @@ -208,13 +209,13 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user ret = ipc3_trace_update_filter(sdev, num_elems, elems); if (ret < 0) { dev_err(sdev->dev, "Filter update failed: %d\n", ret); + kfree(elems); goto error; } } ret = count; error: kfree(string); - kfree(elems); return ret; } From 23cfaf67ba5d2f013d2576b8a9173c45a4a7f895 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:28 -0800 Subject: [PATCH 1639/7721] net: page_pool: factor out uninit We'll soon (next change in the series) need a fuller unwind path in page_pool_create() so create the inverse of page_pool_init(). Reviewed-by: Ilias Apalodimas Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Reviewed-by: Shakeel Butt Signed-off-by: Paolo Abeni --- net/core/page_pool.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index df2a06d7da52..2e4575477e71 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -238,6 +238,18 @@ static int page_pool_init(struct page_pool *pool, return 0; } +static void page_pool_uninit(struct page_pool *pool) +{ + ptr_ring_cleanup(&pool->ring, NULL); + + if (pool->p.flags & PP_FLAG_DMA_MAP) + put_device(pool->p.dev); + +#ifdef CONFIG_PAGE_POOL_STATS + free_percpu(pool->recycle_stats); +#endif +} + /** * page_pool_create() - create a page pool. * @params: parameters, see struct page_pool_params @@ -821,14 +833,7 @@ static void __page_pool_destroy(struct page_pool *pool) if (pool->disconnect) pool->disconnect(pool); - ptr_ring_cleanup(&pool->ring, NULL); - - if (pool->p.flags & PP_FLAG_DMA_MAP) - put_device(pool->p.dev); - -#ifdef CONFIG_PAGE_POOL_STATS - free_percpu(pool->recycle_stats); -#endif + page_pool_uninit(pool); kfree(pool); } From f17c69649c698e4df3cfe0010b7bbf142dec3e40 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:29 -0800 Subject: [PATCH 1640/7721] net: page_pool: id the page pools To give ourselves the flexibility of creating netlink commands and ability to refer to page pool instances in uAPIs create IDs for page pools. Reviewed-by: Ilias Apalodimas Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Reviewed-by: Shakeel Butt Signed-off-by: Paolo Abeni --- include/net/page_pool/types.h | 4 ++++ net/core/Makefile | 2 +- net/core/page_pool.c | 21 +++++++++++++++----- net/core/page_pool_priv.h | 9 +++++++++ net/core/page_pool_user.c | 36 +++++++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 net/core/page_pool_priv.h create mode 100644 net/core/page_pool_user.c diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index e1bb92c192de..c19f0df3bf0b 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -187,6 +187,10 @@ struct page_pool { /* Slow/Control-path information follows */ struct page_pool_params_slow slow; + /* User-facing fields, protected by page_pools_lock */ + struct { + u32 id; + } user; }; struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); diff --git a/net/core/Makefile b/net/core/Makefile index 0cb734cbc24b..821aec06abf1 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -18,7 +18,7 @@ obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o obj-y += net-sysfs.o -obj-$(CONFIG_PAGE_POOL) += page_pool.o +obj-$(CONFIG_PAGE_POOL) += page_pool.o page_pool_user.o obj-$(CONFIG_PROC_FS) += net-procfs.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NETPOLL) += netpoll.o diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 2e4575477e71..a8d96ea38d18 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -23,6 +23,8 @@ #include +#include "page_pool_priv.h" + #define DEFER_TIME (msecs_to_jiffies(1000)) #define DEFER_WARN_INTERVAL (60 * HZ) @@ -264,13 +266,21 @@ struct page_pool *page_pool_create(const struct page_pool_params *params) return ERR_PTR(-ENOMEM); err = page_pool_init(pool, params); - if (err < 0) { - pr_warn("%s() gave up with errno %d\n", __func__, err); - kfree(pool); - return ERR_PTR(err); - } + if (err < 0) + goto err_free; + + err = page_pool_list(pool); + if (err) + goto err_uninit; return pool; + +err_uninit: + page_pool_uninit(pool); +err_free: + pr_warn("%s() gave up with errno %d\n", __func__, err); + kfree(pool); + return ERR_PTR(err); } EXPORT_SYMBOL(page_pool_create); @@ -833,6 +843,7 @@ static void __page_pool_destroy(struct page_pool *pool) if (pool->disconnect) pool->disconnect(pool); + page_pool_unlist(pool); page_pool_uninit(pool); kfree(pool); } diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h new file mode 100644 index 000000000000..c17ea092b4ab --- /dev/null +++ b/net/core/page_pool_priv.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __PAGE_POOL_PRIV_H +#define __PAGE_POOL_PRIV_H + +int page_pool_list(struct page_pool *pool); +void page_pool_unlist(struct page_pool *pool); + +#endif diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c new file mode 100644 index 000000000000..630d1eeecf2a --- /dev/null +++ b/net/core/page_pool_user.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "page_pool_priv.h" + +static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1); +static DEFINE_MUTEX(page_pools_lock); + +int page_pool_list(struct page_pool *pool) +{ + static u32 id_alloc_next; + int err; + + mutex_lock(&page_pools_lock); + err = xa_alloc_cyclic(&page_pools, &pool->user.id, pool, xa_limit_32b, + &id_alloc_next, GFP_KERNEL); + if (err < 0) + goto err_unlock; + + mutex_unlock(&page_pools_lock); + return 0; + +err_unlock: + mutex_unlock(&page_pools_lock); + return err; +} + +void page_pool_unlist(struct page_pool *pool) +{ + mutex_lock(&page_pools_lock); + xa_erase(&page_pools, pool->user.id); + mutex_unlock(&page_pools_lock); +} From 083772c9f972dcc248913b52a0dec1025baa1e16 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:30 -0800 Subject: [PATCH 1641/7721] net: page_pool: record pools per netdev Link the page pools with netdevs. This needs to be netns compatible so we have two options. Either we record the pools per netns and have to worry about moving them as the netdev gets moved. Or we record them directly on the netdev so they move with the netdev without any extra work. Implement the latter option. Since pools may outlast netdev we need a place to store orphans. In time honored tradition use loopback for this purpose. Reviewed-by: Mina Almasry Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- include/linux/list.h | 20 +++++++++ include/linux/netdevice.h | 4 ++ include/linux/poison.h | 2 + include/net/page_pool/types.h | 4 ++ net/core/page_pool_user.c | 84 +++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index 1837caedf723..059aa1fff41e 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -1119,6 +1119,26 @@ static inline void hlist_move_list(struct hlist_head *old, old->first = NULL; } +/** + * hlist_splice_init() - move all entries from one list to another + * @from: hlist_head from which entries will be moved + * @last: last entry on the @from list + * @to: hlist_head to which entries will be moved + * + * @to can be empty, @from must contain at least @last. + */ +static inline void hlist_splice_init(struct hlist_head *from, + struct hlist_node *last, + struct hlist_head *to) +{ + if (to->first) + to->first->pprev = &last->next; + last->next = to->first; + to->first = from->first; + from->first->pprev = &to->first; + from->first = NULL; +} + #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e87caa81f70c..998c7aaa98b8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2447,6 +2447,10 @@ struct net_device { #if IS_ENABLED(CONFIG_DPLL) struct dpll_pin *dpll_pin; #endif +#if IS_ENABLED(CONFIG_PAGE_POOL) + /** @page_pools: page pools created for this netdevice */ + struct hlist_head page_pools; +#endif }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/include/linux/poison.h b/include/linux/poison.h index 851a855d3868..27a7dad17eef 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -83,6 +83,8 @@ /********** net/core/skbuff.c **********/ #define SKB_LIST_POISON_NEXT ((void *)(0x800 + POISON_POINTER_DELTA)) +/********** net/ **********/ +#define NET_PTR_POISON ((void *)(0x801 + POISON_POINTER_DELTA)) /********** kernel/bpf/ **********/ #define BPF_PTR_POISON ((void *)(0xeB9FUL + POISON_POINTER_DELTA)) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index c19f0df3bf0b..b258a571201e 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -5,6 +5,7 @@ #include #include +#include #define PP_FLAG_DMA_MAP BIT(0) /* Should page_pool do the DMA * map/unmap @@ -48,6 +49,7 @@ struct pp_alloc_cache { * @pool_size: size of the ptr_ring * @nid: NUMA node id to allocate from pages from * @dev: device, for DMA pre-mapping purposes + * @netdev: netdev this pool will serve (leave as NULL if none or multiple) * @napi: NAPI which is the sole consumer of pages, otherwise NULL * @dma_dir: DMA mapping direction * @max_len: max DMA sync memory size for PP_FLAG_DMA_SYNC_DEV @@ -66,6 +68,7 @@ struct page_pool_params { unsigned int offset; ); struct_group_tagged(page_pool_params_slow, slow, + struct net_device *netdev; /* private: used by test code only */ void (*init_callback)(struct page *page, void *arg); void *init_arg; @@ -189,6 +192,7 @@ struct page_pool { struct page_pool_params_slow slow; /* User-facing fields, protected by page_pools_lock */ struct { + struct hlist_node list; u32 id; } user; }; diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 630d1eeecf2a..e5c7f078fbd4 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -1,14 +1,31 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include +#include #include #include "page_pool_priv.h" static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1); +/* Protects: page_pools, netdevice->page_pools, pool->slow.netdev, pool->user. + * Ordering: inside rtnl_lock + */ static DEFINE_MUTEX(page_pools_lock); +/* Page pools are only reachable from user space (via netlink) if they are + * linked to a netdev at creation time. Following page pool "visibility" + * states are possible: + * - normal + * - user.list: linked to real netdev, netdev: real netdev + * - orphaned - real netdev has disappeared + * - user.list: linked to lo, netdev: lo + * - invisible - either (a) created without netdev linking, (b) unlisted due + * to error, or (c) the entire namespace which owned this pool disappeared + * - user.list: unhashed, netdev: unknown + */ + int page_pool_list(struct page_pool *pool) { static u32 id_alloc_next; @@ -20,6 +37,10 @@ int page_pool_list(struct page_pool *pool) if (err < 0) goto err_unlock; + if (pool->slow.netdev) + hlist_add_head(&pool->user.list, + &pool->slow.netdev->page_pools); + mutex_unlock(&page_pools_lock); return 0; @@ -32,5 +53,68 @@ void page_pool_unlist(struct page_pool *pool) { mutex_lock(&page_pools_lock); xa_erase(&page_pools, pool->user.id); + hlist_del(&pool->user.list); mutex_unlock(&page_pools_lock); } + +static void page_pool_unreg_netdev_wipe(struct net_device *netdev) +{ + struct page_pool *pool; + struct hlist_node *n; + + mutex_lock(&page_pools_lock); + hlist_for_each_entry_safe(pool, n, &netdev->page_pools, user.list) { + hlist_del_init(&pool->user.list); + pool->slow.netdev = NET_PTR_POISON; + } + mutex_unlock(&page_pools_lock); +} + +static void page_pool_unreg_netdev(struct net_device *netdev) +{ + struct page_pool *pool, *last; + struct net_device *lo; + + lo = dev_net(netdev)->loopback_dev; + + mutex_lock(&page_pools_lock); + last = NULL; + hlist_for_each_entry(pool, &netdev->page_pools, user.list) { + pool->slow.netdev = lo; + last = pool; + } + if (last) + hlist_splice_init(&netdev->page_pools, &last->user.list, + &lo->page_pools); + mutex_unlock(&page_pools_lock); +} + +static int +page_pool_netdevice_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + + if (hlist_empty(&netdev->page_pools)) + return NOTIFY_OK; + + if (netdev->ifindex != LOOPBACK_IFINDEX) + page_pool_unreg_netdev(netdev); + else + page_pool_unreg_netdev_wipe(netdev); + return NOTIFY_OK; +} + +static struct notifier_block page_pool_netdevice_nb = { + .notifier_call = page_pool_netdevice_event, +}; + +static int __init page_pool_user_init(void) +{ + return register_netdevice_notifier(&page_pool_netdevice_nb); +} + +subsys_initcall(page_pool_user_init); From 02b3de80c5f879f92e5f4bb3f535d172e0fc0ea0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:31 -0800 Subject: [PATCH 1642/7721] net: page_pool: stash the NAPI ID for easier access To avoid any issues with race conditions on accessing napi and having to think about the lifetime of NAPI objects in netlink GET - stash the napi_id to which page pool was linked at creation time. Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- include/net/page_pool/types.h | 1 + net/core/page_pool_user.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index b258a571201e..7e47d7bb2c1e 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -193,6 +193,7 @@ struct page_pool { /* User-facing fields, protected by page_pools_lock */ struct { struct hlist_node list; + u32 napi_id; u32 id; } user; }; diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index e5c7f078fbd4..2888aa8dd3e4 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -37,9 +37,11 @@ int page_pool_list(struct page_pool *pool) if (err < 0) goto err_unlock; - if (pool->slow.netdev) + if (pool->slow.netdev) { hlist_add_head(&pool->user.list, &pool->slow.netdev->page_pools); + pool->user.napi_id = pool->p.napi ? pool->p.napi->napi_id : 0; + } mutex_unlock(&page_pools_lock); return 0; From 7cc9e6d77f85fb5faa9ffa26c645c821430c7095 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:32 -0800 Subject: [PATCH 1643/7721] eth: link netdev to page_pools in drivers Link page pool instances to netdev for the drivers which already link to NAPI. Unless the driver is doing something very weird per-NAPI should imply per-netdev. Add netsec as well, Ilias indicates that it fits the mold. Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 + drivers/net/ethernet/microsoft/mana/mana_en.c | 1 + drivers/net/ethernet/socionext/netsec.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d8cf7b30bd03..e35e7e02538c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3331,6 +3331,7 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp, pp.pool_size += bp->rx_ring_size; pp.nid = dev_to_node(&bp->pdev->dev); pp.napi = &rxr->bnapi->napi; + pp.netdev = bp->dev; pp.dev = &bp->pdev->dev; pp.dma_dir = bp->rx_dir; pp.max_len = PAGE_SIZE; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 3aecdf099a2f..af5e0d3c8ee1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -902,6 +902,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params, pp_params.nid = node; pp_params.dev = rq->pdev; pp_params.napi = rq->cq.napi; + pp_params.netdev = rq->netdev; pp_params.dma_dir = rq->buff.map_dir; pp_params.max_len = PAGE_SIZE; diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 6b857188b9da..0eb8321d76c9 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -2137,6 +2137,7 @@ static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc) pprm.pool_size = RX_BUFFERS_PER_QUEUE; pprm.nid = gc->numa_node; pprm.napi = &rxq->rx_cq.napi; + pprm.netdev = rxq->ndev; rxq->page_pool = page_pool_create(&pprm); diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 0891e9e49ecb..5ab8b81b84e6 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -1302,6 +1302,8 @@ static int netsec_setup_rx_dring(struct netsec_priv *priv) .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE, .offset = NETSEC_RXBUF_HEADROOM, .max_len = NETSEC_RX_BUF_SIZE, + .napi = &priv->napi, + .netdev = priv->ndev, }; int i, err; From 839ff60df3ab92b81034ea3b859ab984eaa0c84c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:33 -0800 Subject: [PATCH 1644/7721] net: page_pool: add nlspec for basic access to page pools Add a Netlink spec in YAML for getting very basic information about page pools. Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/netdev.yaml | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 14511b13f305..84ca3c2ab872 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -86,6 +86,34 @@ attribute-sets: See Documentation/networking/xdp-rx-metadata.rst for more details. type: u64 enum: xdp-rx-metadata + - + name: page-pool + attributes: + - + name: id + doc: Unique ID of a Page Pool instance. + type: uint + checks: + min: 1 + max: u32-max + - + name: ifindex + doc: | + ifindex of the netdev to which the pool belongs. + May be reported as 0 if the page pool was allocated for a netdev + which got destroyed already (page pools may outlast their netdevs + because they wait for all memory to be returned). + type: u32 + checks: + min: 1 + max: s32-max + - + name: napi-id + doc: Id of NAPI using this Page Pool instance. + type: uint + checks: + min: 1 + max: u32-max operations: list: @@ -120,6 +148,24 @@ operations: doc: Notification about device configuration being changed. notify: dev-get mcgrp: mgmt + - + name: page-pool-get + doc: | + Get / dump information about Page Pools. + (Only Page Pools associated with a net_device can be listed.) + attribute-set: page-pool + do: + request: + attributes: + - id + reply: &pp-reply + attributes: + - id + - ifindex + - napi-id + dump: + reply: *pp-reply + config-cond: page-pool mcast-groups: list: From 950ab53b77ab829defeb22bc98d40a5e926ae018 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:34 -0800 Subject: [PATCH 1645/7721] net: page_pool: implement GET in the netlink API Expose the very basic page pool information via netlink. Example using ynl-py for a system with 9 queues: $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \ --dump page-pool-get [{'id': 19, 'ifindex': 2, 'napi-id': 147}, {'id': 18, 'ifindex': 2, 'napi-id': 146}, {'id': 17, 'ifindex': 2, 'napi-id': 145}, {'id': 16, 'ifindex': 2, 'napi-id': 144}, {'id': 15, 'ifindex': 2, 'napi-id': 143}, {'id': 14, 'ifindex': 2, 'napi-id': 142}, {'id': 13, 'ifindex': 2, 'napi-id': 141}, {'id': 12, 'ifindex': 2, 'napi-id': 140}, {'id': 11, 'ifindex': 2, 'napi-id': 139}, {'id': 10, 'ifindex': 2, 'napi-id': 138}] Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- include/uapi/linux/netdev.h | 10 +++ net/core/netdev-genl-gen.c | 27 ++++++++ net/core/netdev-genl-gen.h | 3 + net/core/page_pool_user.c | 127 ++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 2943a151d4f1..176665bcf0da 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -64,11 +64,21 @@ enum { NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) }; +enum { + NETDEV_A_PAGE_POOL_ID = 1, + NETDEV_A_PAGE_POOL_IFINDEX, + NETDEV_A_PAGE_POOL_NAPI_ID, + + __NETDEV_A_PAGE_POOL_MAX, + NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, NETDEV_CMD_DEV_DEL_NTF, NETDEV_CMD_DEV_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index ea9231378aa6..bfde13981c77 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -10,11 +10,24 @@ #include +/* Integer value ranges */ +static const struct netlink_range_validation netdev_a_page_pool_id_range = { + .min = 1ULL, + .max = 4294967295ULL, +}; + /* NETDEV_CMD_DEV_GET - do */ static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = { [NETDEV_A_DEV_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), }; +/* NETDEV_CMD_PAGE_POOL_GET - do */ +#ifdef CONFIG_PAGE_POOL +static const struct nla_policy netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL_ID + 1] = { + [NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range), +}; +#endif /* CONFIG_PAGE_POOL */ + /* Ops table for netdev */ static const struct genl_split_ops netdev_nl_ops[] = { { @@ -29,6 +42,20 @@ static const struct genl_split_ops netdev_nl_ops[] = { .dumpit = netdev_nl_dev_get_dumpit, .flags = GENL_CMD_CAP_DUMP, }, +#ifdef CONFIG_PAGE_POOL + { + .cmd = NETDEV_CMD_PAGE_POOL_GET, + .doit = netdev_nl_page_pool_get_doit, + .policy = netdev_page_pool_get_nl_policy, + .maxattr = NETDEV_A_PAGE_POOL_ID, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = NETDEV_CMD_PAGE_POOL_GET, + .dumpit = netdev_nl_page_pool_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, +#endif /* CONFIG_PAGE_POOL */ }; static const struct genl_multicast_group netdev_nl_mcgrps[] = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index 7b370c073e7d..a011d12abff4 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -13,6 +13,9 @@ int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info); +int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); enum { NETDEV_NLGRP_MGMT, diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 2888aa8dd3e4..7eb37c31fce9 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -5,8 +5,10 @@ #include #include #include +#include #include "page_pool_priv.h" +#include "netdev-genl-gen.h" static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1); /* Protects: page_pools, netdevice->page_pools, pool->slow.netdev, pool->user. @@ -26,6 +28,131 @@ static DEFINE_MUTEX(page_pools_lock); * - user.list: unhashed, netdev: unknown */ +typedef int (*pp_nl_fill_cb)(struct sk_buff *rsp, const struct page_pool *pool, + const struct genl_info *info); + +static int +netdev_nl_page_pool_get_do(struct genl_info *info, u32 id, pp_nl_fill_cb fill) +{ + struct page_pool *pool; + struct sk_buff *rsp; + int err; + + mutex_lock(&page_pools_lock); + pool = xa_load(&page_pools, id); + if (!pool || hlist_unhashed(&pool->user.list) || + !net_eq(dev_net(pool->slow.netdev), genl_info_net(info))) { + err = -ENOENT; + goto err_unlock; + } + + rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!rsp) { + err = -ENOMEM; + goto err_unlock; + } + + err = fill(rsp, pool, info); + if (err) + goto err_free_msg; + + mutex_unlock(&page_pools_lock); + + return genlmsg_reply(rsp, info); + +err_free_msg: + nlmsg_free(rsp); +err_unlock: + mutex_unlock(&page_pools_lock); + return err; +} + +struct page_pool_dump_cb { + unsigned long ifindex; + u32 pp_id; +}; + +static int +netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb, + pp_nl_fill_cb fill) +{ + struct page_pool_dump_cb *state = (void *)cb->ctx; + const struct genl_info *info = genl_info_dump(cb); + struct net *net = sock_net(skb->sk); + struct net_device *netdev; + struct page_pool *pool; + int err = 0; + + rtnl_lock(); + mutex_lock(&page_pools_lock); + for_each_netdev_dump(net, netdev, state->ifindex) { + hlist_for_each_entry(pool, &netdev->page_pools, user.list) { + if (state->pp_id && state->pp_id < pool->user.id) + continue; + + state->pp_id = pool->user.id; + err = fill(skb, pool, info); + if (err) + break; + } + + state->pp_id = 0; + } + mutex_unlock(&page_pools_lock); + rtnl_unlock(); + + if (skb->len && err == -EMSGSIZE) + return skb->len; + return err; +} + +static int +page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, + const struct genl_info *info) +{ + void *hdr; + + hdr = genlmsg_iput(rsp, info); + if (!hdr) + return -EMSGSIZE; + + if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id)) + goto err_cancel; + + if (pool->slow.netdev->ifindex != LOOPBACK_IFINDEX && + nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX, + pool->slow.netdev->ifindex)) + goto err_cancel; + if (pool->user.napi_id && + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_NAPI_ID, pool->user.napi_id)) + goto err_cancel; + + genlmsg_end(rsp, hdr); + + return 0; +err_cancel: + genlmsg_cancel(rsp, hdr); + return -EMSGSIZE; +} + +int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + u32 id; + + if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_PAGE_POOL_ID)) + return -EINVAL; + + id = nla_get_uint(info->attrs[NETDEV_A_PAGE_POOL_ID]); + + return netdev_nl_page_pool_get_do(info, id, page_pool_nl_fill); +} + +int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_fill); +} + int page_pool_list(struct page_pool *pool) { static u32 id_alloc_next; From d2ef6aa077bdd0b3495dba5dcae6d3f19579b20b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:35 -0800 Subject: [PATCH 1646/7721] net: page_pool: add netlink notifications for state changes Generate netlink notifications about page pool state changes. Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/netdev.yaml | 20 ++++++++++++++ include/uapi/linux/netdev.h | 4 +++ net/core/netdev-genl-gen.c | 1 + net/core/netdev-genl-gen.h | 1 + net/core/page_pool_user.c | 36 +++++++++++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 84ca3c2ab872..82fbe81f7a49 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -166,8 +166,28 @@ operations: dump: reply: *pp-reply config-cond: page-pool + - + name: page-pool-add-ntf + doc: Notification about page pool appearing. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool + - + name: page-pool-del-ntf + doc: Notification about page pool disappearing. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool + - + name: page-pool-change-ntf + doc: Notification about page pool configuration being changed. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool mcast-groups: list: - name: mgmt + - + name: page-pool diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 176665bcf0da..beb158872226 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -79,11 +79,15 @@ enum { NETDEV_CMD_DEV_DEL_NTF, NETDEV_CMD_DEV_CHANGE_NTF, NETDEV_CMD_PAGE_POOL_GET, + NETDEV_CMD_PAGE_POOL_ADD_NTF, + NETDEV_CMD_PAGE_POOL_DEL_NTF, + NETDEV_CMD_PAGE_POOL_CHANGE_NTF, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) }; #define NETDEV_MCGRP_MGMT "mgmt" +#define NETDEV_MCGRP_PAGE_POOL "page-pool" #endif /* _UAPI_LINUX_NETDEV_H */ diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index bfde13981c77..47fb5e1b6369 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -60,6 +60,7 @@ static const struct genl_split_ops netdev_nl_ops[] = { static const struct genl_multicast_group netdev_nl_mcgrps[] = { [NETDEV_NLGRP_MGMT] = { "mgmt", }, + [NETDEV_NLGRP_PAGE_POOL] = { "page-pool", }, }; struct genl_family netdev_nl_family __ro_after_init = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index a011d12abff4..738097847100 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -19,6 +19,7 @@ int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb, enum { NETDEV_NLGRP_MGMT, + NETDEV_NLGRP_PAGE_POOL, }; extern struct genl_family netdev_nl_family; diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 7eb37c31fce9..1577fef880c9 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -135,6 +135,37 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, return -EMSGSIZE; } +static void netdev_nl_page_pool_event(const struct page_pool *pool, u32 cmd) +{ + struct genl_info info; + struct sk_buff *ntf; + struct net *net; + + lockdep_assert_held(&page_pools_lock); + + /* 'invisible' page pools don't matter */ + if (hlist_unhashed(&pool->user.list)) + return; + net = dev_net(pool->slow.netdev); + + if (!genl_has_listeners(&netdev_nl_family, net, NETDEV_NLGRP_PAGE_POOL)) + return; + + genl_info_init_ntf(&info, &netdev_nl_family, cmd); + + ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!ntf) + return; + + if (page_pool_nl_fill(ntf, pool, &info)) { + nlmsg_free(ntf); + return; + } + + genlmsg_multicast_netns(&netdev_nl_family, net, ntf, + 0, NETDEV_NLGRP_PAGE_POOL, GFP_KERNEL); +} + int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info) { u32 id; @@ -168,6 +199,8 @@ int page_pool_list(struct page_pool *pool) hlist_add_head(&pool->user.list, &pool->slow.netdev->page_pools); pool->user.napi_id = pool->p.napi ? pool->p.napi->napi_id : 0; + + netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_ADD_NTF); } mutex_unlock(&page_pools_lock); @@ -181,6 +214,7 @@ int page_pool_list(struct page_pool *pool) void page_pool_unlist(struct page_pool *pool) { mutex_lock(&page_pools_lock); + netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_DEL_NTF); xa_erase(&page_pools, pool->user.id); hlist_del(&pool->user.list); mutex_unlock(&page_pools_lock); @@ -210,6 +244,8 @@ static void page_pool_unreg_netdev(struct net_device *netdev) last = NULL; hlist_for_each_entry(pool, &netdev->page_pools, user.list) { pool->slow.netdev = lo; + netdev_nl_page_pool_event(pool, + NETDEV_CMD_PAGE_POOL_CHANGE_NTF); last = pool; } if (last) From 7aee8429eedd0970d8add2fb5b856bfc5f5f1fc1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:36 -0800 Subject: [PATCH 1647/7721] net: page_pool: report amount of memory held by page pools Advanced deployments need the ability to check memory use of various system components. It makes it possible to make informed decisions about memory allocation and to find regressions and leaks. Report memory use of page pools. Report both number of references and bytes held. Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/netdev.yaml | 15 +++++++++++++++ include/uapi/linux/netdev.h | 2 ++ net/core/page_pool.c | 13 +++++++++---- net/core/page_pool_priv.h | 2 ++ net/core/page_pool_user.c | 8 ++++++++ 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 82fbe81f7a49..b76623ff2932 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -114,6 +114,19 @@ attribute-sets: checks: min: 1 max: u32-max + - + name: inflight + type: uint + doc: | + Number of outstanding references to this page pool (allocated + but yet to be freed pages). Allocated pages may be held in + socket receive queues, driver receive ring, page pool recycling + ring, the page pool cache, etc. + - + name: inflight-mem + type: uint + doc: | + Amount of memory held by inflight pages. operations: list: @@ -163,6 +176,8 @@ operations: - id - ifindex - napi-id + - inflight + - inflight-mem dump: reply: *pp-reply config-cond: page-pool diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index beb158872226..26ae5bdd3187 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -68,6 +68,8 @@ enum { NETDEV_A_PAGE_POOL_ID = 1, NETDEV_A_PAGE_POOL_IFINDEX, NETDEV_A_PAGE_POOL_NAPI_ID, + NETDEV_A_PAGE_POOL_INFLIGHT, + NETDEV_A_PAGE_POOL_INFLIGHT_MEM, __NETDEV_A_PAGE_POOL_MAX, NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index a8d96ea38d18..566390759294 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -529,7 +529,7 @@ EXPORT_SYMBOL(page_pool_alloc_pages); */ #define _distance(a, b) (s32)((a) - (b)) -static s32 page_pool_inflight(struct page_pool *pool) +s32 page_pool_inflight(const struct page_pool *pool, bool strict) { u32 release_cnt = atomic_read(&pool->pages_state_release_cnt); u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt); @@ -537,8 +537,13 @@ static s32 page_pool_inflight(struct page_pool *pool) inflight = _distance(hold_cnt, release_cnt); - trace_page_pool_release(pool, inflight, hold_cnt, release_cnt); - WARN(inflight < 0, "Negative(%d) inflight packet-pages", inflight); + if (strict) { + trace_page_pool_release(pool, inflight, hold_cnt, release_cnt); + WARN(inflight < 0, "Negative(%d) inflight packet-pages", + inflight); + } else { + inflight = max(0, inflight); + } return inflight; } @@ -881,7 +886,7 @@ static int page_pool_release(struct page_pool *pool) int inflight; page_pool_scrub(pool); - inflight = page_pool_inflight(pool); + inflight = page_pool_inflight(pool, true); if (!inflight) __page_pool_destroy(pool); diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h index c17ea092b4ab..72fb21ea1ddc 100644 --- a/net/core/page_pool_priv.h +++ b/net/core/page_pool_priv.h @@ -3,6 +3,8 @@ #ifndef __PAGE_POOL_PRIV_H #define __PAGE_POOL_PRIV_H +s32 page_pool_inflight(const struct page_pool *pool, bool strict); + int page_pool_list(struct page_pool *pool); void page_pool_unlist(struct page_pool *pool); diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 1577fef880c9..2db71e718485 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -110,6 +110,7 @@ static int page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, const struct genl_info *info) { + size_t inflight, refsz; void *hdr; hdr = genlmsg_iput(rsp, info); @@ -127,6 +128,13 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, nla_put_uint(rsp, NETDEV_A_PAGE_POOL_NAPI_ID, pool->user.napi_id)) goto err_cancel; + inflight = page_pool_inflight(pool, false); + refsz = PAGE_SIZE << pool->p.order; + if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT, inflight) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT_MEM, + inflight * refsz)) + goto err_cancel; + genlmsg_end(rsp, hdr); return 0; From 69cb4952b6f6a226c1c0a7ca400398aaa8f75cf2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:37 -0800 Subject: [PATCH 1648/7721] net: page_pool: report when page pool was destroyed Report when page pool was destroyed. Together with the inflight / memory use reporting this can serve as a replacement for the warning about leaked page pools we currently print to dmesg. Example output for a fake leaked page pool using some hacks in netdevsim (one "live" pool, and one "leaked" on the same dev): $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \ --dump page-pool-get [{'id': 2, 'ifindex': 3}, {'id': 1, 'ifindex': 3, 'destroyed': 133, 'inflight': 1}] Tested-by: Dragos Tatulea Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++ include/net/page_pool/types.h | 1 + include/uapi/linux/netdev.h | 1 + net/core/page_pool.c | 1 + net/core/page_pool_priv.h | 1 + net/core/page_pool_user.c | 12 ++++++++++++ 6 files changed, 29 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index b76623ff2932..b5f715cf9e06 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -127,6 +127,18 @@ attribute-sets: type: uint doc: | Amount of memory held by inflight pages. + - + name: detach-time + type: uint + doc: | + Seconds in CLOCK_BOOTTIME of when Page Pool was detached by + the driver. Once detached Page Pool can no longer be used to + allocate memory. + Page Pools wait for all the memory allocated from them to be freed + before truly disappearing. "Detached" Page Pools cannot be + "re-attached", they are just waiting to disappear. + Attribute is absent if Page Pool has not been detached, and + can still be used to allocate new memory. operations: list: @@ -178,6 +190,7 @@ operations: - napi-id - inflight - inflight-mem + - detach-time dump: reply: *pp-reply config-cond: page-pool diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 7e47d7bb2c1e..ac286ea8ce2d 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -193,6 +193,7 @@ struct page_pool { /* User-facing fields, protected by page_pools_lock */ struct { struct hlist_node list; + u64 detach_time; u32 napi_id; u32 id; } user; diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 26ae5bdd3187..756410274120 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -70,6 +70,7 @@ enum { NETDEV_A_PAGE_POOL_NAPI_ID, NETDEV_A_PAGE_POOL_INFLIGHT, NETDEV_A_PAGE_POOL_INFLIGHT_MEM, + NETDEV_A_PAGE_POOL_DETACH_TIME, __NETDEV_A_PAGE_POOL_MAX, NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 566390759294..a821fb5fe054 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -953,6 +953,7 @@ void page_pool_destroy(struct page_pool *pool) if (!page_pool_release(pool)) return; + page_pool_detached(pool); pool->defer_start = jiffies; pool->defer_warn = jiffies + DEFER_WARN_INTERVAL; diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h index 72fb21ea1ddc..90665d40f1eb 100644 --- a/net/core/page_pool_priv.h +++ b/net/core/page_pool_priv.h @@ -6,6 +6,7 @@ s32 page_pool_inflight(const struct page_pool *pool, bool strict); int page_pool_list(struct page_pool *pool); +void page_pool_detached(struct page_pool *pool); void page_pool_unlist(struct page_pool *pool); #endif diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 2db71e718485..bd5ca94f683f 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -134,6 +134,10 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT_MEM, inflight * refsz)) goto err_cancel; + if (pool->user.detach_time && + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_DETACH_TIME, + pool->user.detach_time)) + goto err_cancel; genlmsg_end(rsp, hdr); @@ -219,6 +223,14 @@ int page_pool_list(struct page_pool *pool) return err; } +void page_pool_detached(struct page_pool *pool) +{ + mutex_lock(&page_pools_lock); + pool->user.detach_time = ktime_get_boottime_seconds(); + netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_CHANGE_NTF); + mutex_unlock(&page_pools_lock); +} + void page_pool_unlist(struct page_pool *pool) { mutex_lock(&page_pools_lock); From d49010adae737638447369a4eff8f1aab736b076 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:38 -0800 Subject: [PATCH 1649/7721] net: page_pool: expose page pool stats via netlink Dump the stats into netlink. More clever approaches like dumping the stats per-CPU for each CPU individually to see where the packets get consumed can be implemented in the future. A trimmed example from a real (but recently booted system): $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \ --dump page-pool-stats-get [{'info': {'id': 19, 'ifindex': 2}, 'alloc-empty': 48, 'alloc-fast': 3024, 'alloc-refill': 0, 'alloc-slow': 48, 'alloc-slow-high-order': 0, 'alloc-waive': 0, 'recycle-cache-full': 0, 'recycle-cached': 0, 'recycle-released-refcnt': 0, 'recycle-ring': 0, 'recycle-ring-full': 0}, {'info': {'id': 18, 'ifindex': 2}, 'alloc-empty': 66, 'alloc-fast': 11811, 'alloc-refill': 35, 'alloc-slow': 66, 'alloc-slow-high-order': 0, 'alloc-waive': 0, 'recycle-cache-full': 1145, 'recycle-cached': 6541, 'recycle-released-refcnt': 0, 'recycle-ring': 1275, 'recycle-ring-full': 0}, {'info': {'id': 17, 'ifindex': 2}, 'alloc-empty': 73, 'alloc-fast': 62099, 'alloc-refill': 413, ... Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/netdev.yaml | 78 ++++++++++++++++++ Documentation/networking/page_pool.rst | 10 ++- include/net/page_pool/helpers.h | 8 +- include/uapi/linux/netdev.h | 19 +++++ net/core/netdev-genl-gen.c | 32 ++++++++ net/core/netdev-genl-gen.h | 7 ++ net/core/page_pool.c | 2 +- net/core/page_pool_user.c | 103 ++++++++++++++++++++++++ 8 files changed, 250 insertions(+), 9 deletions(-) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index b5f715cf9e06..20f75b7d3240 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -139,6 +139,59 @@ attribute-sets: "re-attached", they are just waiting to disappear. Attribute is absent if Page Pool has not been detached, and can still be used to allocate new memory. + - + name: page-pool-info + subset-of: page-pool + attributes: + - + name: id + - + name: ifindex + - + name: page-pool-stats + doc: | + Page pool statistics, see docs for struct page_pool_stats + for information about individual statistics. + attributes: + - + name: info + doc: Page pool identifying information. + type: nest + nested-attributes: page-pool-info + - + name: alloc-fast + type: uint + value: 8 # reserve some attr ids in case we need more metadata later + - + name: alloc-slow + type: uint + - + name: alloc-slow-high-order + type: uint + - + name: alloc-empty + type: uint + - + name: alloc-refill + type: uint + - + name: alloc-waive + type: uint + - + name: recycle-cached + type: uint + - + name: recycle-cache-full + type: uint + - + name: recycle-ring + type: uint + - + name: recycle-ring-full + type: uint + - + name: recycle-released-refcnt + type: uint operations: list: @@ -212,6 +265,31 @@ operations: notify: page-pool-get mcgrp: page-pool config-cond: page-pool + - + name: page-pool-stats-get + doc: Get page pool statistics. + attribute-set: page-pool-stats + do: + request: + attributes: + - info + reply: &pp-stats-reply + attributes: + - info + - alloc-fast + - alloc-slow + - alloc-slow-high-order + - alloc-empty + - alloc-refill + - alloc-waive + - recycle-cached + - recycle-cache-full + - recycle-ring + - recycle-ring-full + - recycle-released-refcnt + dump: + reply: *pp-stats-reply + config-cond: page-pool-stats mcast-groups: list: diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 60993cb56b32..9d958128a57c 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -41,6 +41,11 @@ Architecture overview | Fast cache | | ptr-ring cache | +-----------------+ +------------------+ +Monitoring +========== +Information about page pools on the system can be accessed via the netdev +genetlink family (see Documentation/netlink/specs/netdev.yaml). + API interface ============= The number of pools created **must** match the number of hardware queues @@ -107,8 +112,9 @@ page_pool_get_stats() and structures described below are available. It takes a pointer to a ``struct page_pool`` and a pointer to a struct page_pool_stats allocated by the caller. -The API will fill in the provided struct page_pool_stats with -statistics about the page_pool. +Older drivers expose page pool statistics via ethtool or debugfs. +The same statistics are accessible via the netlink netdev family +in a driver-independent fashion. .. kernel-doc:: include/net/page_pool/types.h :identifiers: struct page_pool_recycle_stats diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h index 4ebd544ae977..7dc65774cde5 100644 --- a/include/net/page_pool/helpers.h +++ b/include/net/page_pool/helpers.h @@ -55,16 +55,12 @@ #include #ifdef CONFIG_PAGE_POOL_STATS +/* Deprecated driver-facing API, use netlink instead */ int page_pool_ethtool_stats_get_count(void); u8 *page_pool_ethtool_stats_get_strings(u8 *data); u64 *page_pool_ethtool_stats_get(u64 *data, void *stats); -/* - * Drivers that wish to harvest page pool stats and report them to users - * (perhaps via ethtool, debugfs, or another mechanism) can allocate a - * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool. - */ -bool page_pool_get_stats(struct page_pool *pool, +bool page_pool_get_stats(const struct page_pool *pool, struct page_pool_stats *stats); #else static inline int page_pool_ethtool_stats_get_count(void) diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 756410274120..2b37233e00c0 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -76,6 +76,24 @@ enum { NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) }; +enum { + NETDEV_A_PAGE_POOL_STATS_INFO = 1, + NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER, + NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY, + NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL, + NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT, + + __NETDEV_A_PAGE_POOL_STATS_MAX, + NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, @@ -85,6 +103,7 @@ enum { NETDEV_CMD_PAGE_POOL_ADD_NTF, NETDEV_CMD_PAGE_POOL_DEL_NTF, NETDEV_CMD_PAGE_POOL_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_STATS_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index 47fb5e1b6369..dccd8c3a141e 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -16,6 +16,17 @@ static const struct netlink_range_validation netdev_a_page_pool_id_range = { .max = 4294967295ULL, }; +static const struct netlink_range_validation netdev_a_page_pool_ifindex_range = { + .min = 1ULL, + .max = 2147483647ULL, +}; + +/* Common nested types */ +const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1] = { + [NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range), + [NETDEV_A_PAGE_POOL_IFINDEX] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_page_pool_ifindex_range), +}; + /* NETDEV_CMD_DEV_GET - do */ static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = { [NETDEV_A_DEV_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), @@ -28,6 +39,13 @@ static const struct nla_policy netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL }; #endif /* CONFIG_PAGE_POOL */ +/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ +#ifdef CONFIG_PAGE_POOL_STATS +static const struct nla_policy netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = { + [NETDEV_A_PAGE_POOL_STATS_INFO] = NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy), +}; +#endif /* CONFIG_PAGE_POOL_STATS */ + /* Ops table for netdev */ static const struct genl_split_ops netdev_nl_ops[] = { { @@ -56,6 +74,20 @@ static const struct genl_split_ops netdev_nl_ops[] = { .flags = GENL_CMD_CAP_DUMP, }, #endif /* CONFIG_PAGE_POOL */ +#ifdef CONFIG_PAGE_POOL_STATS + { + .cmd = NETDEV_CMD_PAGE_POOL_STATS_GET, + .doit = netdev_nl_page_pool_stats_get_doit, + .policy = netdev_page_pool_stats_get_nl_policy, + .maxattr = NETDEV_A_PAGE_POOL_STATS_INFO, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = NETDEV_CMD_PAGE_POOL_STATS_GET, + .dumpit = netdev_nl_page_pool_stats_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, +#endif /* CONFIG_PAGE_POOL_STATS */ }; static const struct genl_multicast_group netdev_nl_mcgrps[] = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index 738097847100..649e4b46eccf 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -11,11 +11,18 @@ #include +/* Common nested types */ +extern const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1]; + int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb, + struct genl_info *info); +int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); enum { NETDEV_NLGRP_MGMT, diff --git a/net/core/page_pool.c b/net/core/page_pool.c index a821fb5fe054..3d0938a60646 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -71,7 +71,7 @@ static const char pp_stats[][ETH_GSTRING_LEN] = { * is passed to this API which is filled in. The caller can then report * those stats to the user (perhaps via ethtool, debugfs, etc.). */ -bool page_pool_get_stats(struct page_pool *pool, +bool page_pool_get_stats(const struct page_pool *pool, struct page_pool_stats *stats) { int cpu = 0; diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index bd5ca94f683f..1426434a7e15 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "page_pool_priv.h" @@ -106,6 +107,108 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb, return err; } +static int +page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool, + const struct genl_info *info) +{ +#ifdef CONFIG_PAGE_POOL_STATS + struct page_pool_stats stats = {}; + struct nlattr *nest; + void *hdr; + + if (!page_pool_get_stats(pool, &stats)) + return 0; + + hdr = genlmsg_iput(rsp, info); + if (!hdr) + return -EMSGSIZE; + + nest = nla_nest_start(rsp, NETDEV_A_PAGE_POOL_STATS_INFO); + + if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id) || + (pool->slow.netdev->ifindex != LOOPBACK_IFINDEX && + nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX, + pool->slow.netdev->ifindex))) + goto err_cancel_nest; + + nla_nest_end(rsp, nest); + + if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST, + stats.alloc_stats.fast) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW, + stats.alloc_stats.slow) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER, + stats.alloc_stats.slow_high_order) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY, + stats.alloc_stats.empty) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL, + stats.alloc_stats.refill) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE, + stats.alloc_stats.waive) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED, + stats.recycle_stats.cached) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL, + stats.recycle_stats.cache_full) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING, + stats.recycle_stats.ring) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL, + stats.recycle_stats.ring_full) || + nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT, + stats.recycle_stats.released_refcnt)) + goto err_cancel_msg; + + genlmsg_end(rsp, hdr); + + return 0; +err_cancel_nest: + nla_nest_cancel(rsp, nest); +err_cancel_msg: + genlmsg_cancel(rsp, hdr); + return -EMSGSIZE; +#else + GENL_SET_ERR_MSG(info, "kernel built without CONFIG_PAGE_POOL_STATS"); + return -EOPNOTSUPP; +#endif +} + +int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *tb[ARRAY_SIZE(netdev_page_pool_info_nl_policy)]; + struct nlattr *nest; + int err; + u32 id; + + if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_PAGE_POOL_STATS_INFO)) + return -EINVAL; + + nest = info->attrs[NETDEV_A_PAGE_POOL_STATS_INFO]; + err = nla_parse_nested(tb, ARRAY_SIZE(tb) - 1, nest, + netdev_page_pool_info_nl_policy, + info->extack); + if (err) + return err; + + if (NL_REQ_ATTR_CHECK(info->extack, nest, tb, NETDEV_A_PAGE_POOL_ID)) + return -EINVAL; + if (tb[NETDEV_A_PAGE_POOL_IFINDEX]) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[NETDEV_A_PAGE_POOL_IFINDEX], + "selecting by ifindex not supported"); + return -EINVAL; + } + + id = nla_get_uint(tb[NETDEV_A_PAGE_POOL_ID]); + + return netdev_nl_page_pool_get_do(info, id, page_pool_nl_stats_fill); +} + +int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_stats_fill); +} + static int page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool, const struct genl_info *info) From be0096676e230b43730b8936ac393d155b4e3262 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:39 -0800 Subject: [PATCH 1650/7721] net: page_pool: mute the periodic warning for visible page pools Mute the periodic "stalled pool shutdown" warning if the page pool is visible to user space. Rolling out a driver using page pools to just a few hundred hosts at Meta surfaces applications which fail to reap their broken sockets. Obviously it's best if the applications are fixed, but we don't generally print warnings for application resource leaks. Admins can now depend on the netlink interface for getting page pool info to detect buggy apps. While at it throw in the ID of the pool into the message, in rare cases (pools from destroyed netns) this will make finding the pool with a debugger easier. Reviewed-by: Eric Dumazet Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- net/core/page_pool.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 3d0938a60646..c2e7c9a6efbe 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -897,18 +897,21 @@ static void page_pool_release_retry(struct work_struct *wq) { struct delayed_work *dwq = to_delayed_work(wq); struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw); + void *netdev; int inflight; inflight = page_pool_release(pool); if (!inflight) return; - /* Periodic warning */ - if (time_after_eq(jiffies, pool->defer_warn)) { + /* Periodic warning for page pools the user can't see */ + netdev = READ_ONCE(pool->slow.netdev); + if (time_after_eq(jiffies, pool->defer_warn) && + (!netdev || netdev == NET_PTR_POISON)) { int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ; - pr_warn("%s() stalled pool shutdown %d inflight %d sec\n", - __func__, inflight, sec); + pr_warn("%s() stalled pool shutdown: id %u, %d inflight %d sec\n", + __func__, pool->user.id, inflight, sec); pool->defer_warn = jiffies + DEFER_WARN_INTERVAL; } From 637567e4a3ef6f6a5ffa48781207d270265f7e68 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 26 Nov 2023 15:07:40 -0800 Subject: [PATCH 1651/7721] tools: ynl: add sample for getting page-pool information Regenerate the tools/ code after netdev spec changes. Add sample to query page-pool info in a concise fashion: $ ./page-pool eth0[2] page pools: 10 (zombies: 0) refs: 41984 bytes: 171966464 (refs: 0 bytes: 0) recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201) Acked-by: Jesper Dangaard Brouer Signed-off-by: Jakub Kicinski Signed-off-by: Paolo Abeni --- tools/include/uapi/linux/netdev.h | 36 +++ tools/net/ynl/generated/netdev-user.c | 419 ++++++++++++++++++++++++++ tools/net/ynl/generated/netdev-user.h | 171 +++++++++++ tools/net/ynl/lib/ynl.h | 2 +- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/Makefile | 2 +- tools/net/ynl/samples/page-pool.c | 147 +++++++++ 7 files changed, 776 insertions(+), 2 deletions(-) create mode 100644 tools/net/ynl/samples/page-pool.c diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 2943a151d4f1..2b37233e00c0 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -64,16 +64,52 @@ enum { NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) }; +enum { + NETDEV_A_PAGE_POOL_ID = 1, + NETDEV_A_PAGE_POOL_IFINDEX, + NETDEV_A_PAGE_POOL_NAPI_ID, + NETDEV_A_PAGE_POOL_INFLIGHT, + NETDEV_A_PAGE_POOL_INFLIGHT_MEM, + NETDEV_A_PAGE_POOL_DETACH_TIME, + + __NETDEV_A_PAGE_POOL_MAX, + NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) +}; + +enum { + NETDEV_A_PAGE_POOL_STATS_INFO = 1, + NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER, + NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY, + NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL, + NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT, + + __NETDEV_A_PAGE_POOL_STATS_MAX, + NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, NETDEV_CMD_DEV_DEL_NTF, NETDEV_CMD_DEV_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_GET, + NETDEV_CMD_PAGE_POOL_ADD_NTF, + NETDEV_CMD_PAGE_POOL_DEL_NTF, + NETDEV_CMD_PAGE_POOL_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_STATS_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) }; #define NETDEV_MCGRP_MGMT "mgmt" +#define NETDEV_MCGRP_PAGE_POOL "page-pool" #endif /* _UAPI_LINUX_NETDEV_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index b5ffe8cd1144..a7b7019d00f1 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -18,6 +18,11 @@ static const char * const netdev_op_strmap[] = { [NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf", [NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf", [NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf", + [NETDEV_CMD_PAGE_POOL_GET] = "page-pool-get", + [NETDEV_CMD_PAGE_POOL_ADD_NTF] = "page-pool-add-ntf", + [NETDEV_CMD_PAGE_POOL_DEL_NTF] = "page-pool-del-ntf", + [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = "page-pool-change-ntf", + [NETDEV_CMD_PAGE_POOL_STATS_GET] = "page-pool-stats-get", }; const char *netdev_op_str(int op) @@ -59,6 +64,16 @@ const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value) } /* Policies */ +struct ynl_policy_attr netdev_page_pool_info_policy[NETDEV_A_PAGE_POOL_MAX + 1] = { + [NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest netdev_page_pool_info_nest = { + .max_attr = NETDEV_A_PAGE_POOL_MAX, + .table = netdev_page_pool_info_policy, +}; + struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, @@ -72,7 +87,85 @@ struct ynl_policy_nest netdev_dev_nest = { .table = netdev_dev_policy, }; +struct ynl_policy_attr netdev_page_pool_policy[NETDEV_A_PAGE_POOL_MAX + 1] = { + [NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, + [NETDEV_A_PAGE_POOL_NAPI_ID] = { .name = "napi-id", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_INFLIGHT] = { .name = "inflight", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_INFLIGHT_MEM] = { .name = "inflight-mem", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_DETACH_TIME] = { .name = "detach-time", .type = YNL_PT_UINT, }, +}; + +struct ynl_policy_nest netdev_page_pool_nest = { + .max_attr = NETDEV_A_PAGE_POOL_MAX, + .table = netdev_page_pool_policy, +}; + +struct ynl_policy_attr netdev_page_pool_stats_policy[NETDEV_A_PAGE_POOL_STATS_MAX + 1] = { + [NETDEV_A_PAGE_POOL_STATS_INFO] = { .name = "info", .type = YNL_PT_NEST, .nest = &netdev_page_pool_info_nest, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST] = { .name = "alloc-fast", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW] = { .name = "alloc-slow", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER] = { .name = "alloc-slow-high-order", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY] = { .name = "alloc-empty", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL] = { .name = "alloc-refill", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE] = { .name = "alloc-waive", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED] = { .name = "recycle-cached", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL] = { .name = "recycle-cache-full", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING] = { .name = "recycle-ring", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL] = { .name = "recycle-ring-full", .type = YNL_PT_UINT, }, + [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT] = { .name = "recycle-released-refcnt", .type = YNL_PT_UINT, }, +}; + +struct ynl_policy_nest netdev_page_pool_stats_nest = { + .max_attr = NETDEV_A_PAGE_POOL_STATS_MAX, + .table = netdev_page_pool_stats_policy, +}; + /* Common nested types */ +void netdev_page_pool_info_free(struct netdev_page_pool_info *obj) +{ +} + +int netdev_page_pool_info_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct netdev_page_pool_info *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.id) + mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, obj->id); + if (obj->_present.ifindex) + mnl_attr_put_u32(nlh, NETDEV_A_PAGE_POOL_IFINDEX, obj->ifindex); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int netdev_page_pool_info_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct netdev_page_pool_info *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_PAGE_POOL_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.id = 1; + dst->id = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } + } + + return 0; +} + /* ============== NETDEV_CMD_DEV_GET ============== */ /* NETDEV_CMD_DEV_GET - do */ void netdev_dev_get_req_free(struct netdev_dev_get_req *req) @@ -197,6 +290,314 @@ void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) free(rsp); } +/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */ +/* NETDEV_CMD_PAGE_POOL_GET - do */ +void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req) +{ + free(req); +} + +void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp) +{ + free(rsp); +} + +int netdev_page_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct netdev_page_pool_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_PAGE_POOL_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.id = 1; + dst->id = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_PAGE_POOL_NAPI_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.napi_id = 1; + dst->napi_id = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_INFLIGHT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.inflight = 1; + dst->inflight = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_INFLIGHT_MEM) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.inflight_mem = 1; + dst->inflight_mem = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_DETACH_TIME) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.detach_time = 1; + dst->detach_time = mnl_attr_get_uint(attr); + } + } + + return MNL_CB_OK; +} + +struct netdev_page_pool_get_rsp * +netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct netdev_page_pool_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1); + ys->req_policy = &netdev_page_pool_nest; + yrs.yarg.rsp_policy = &netdev_page_pool_nest; + + if (req->_present.id) + mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, req->id); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = netdev_page_pool_get_rsp_parse; + yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + netdev_page_pool_get_rsp_free(rsp); + return NULL; +} + +/* NETDEV_CMD_PAGE_POOL_GET - dump */ +void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp) +{ + struct netdev_page_pool_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp); + } +} + +struct netdev_page_pool_get_list * +netdev_page_pool_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct netdev_page_pool_get_list); + yds.cb = netdev_page_pool_get_rsp_parse; + yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET; + yds.rsp_policy = &netdev_page_pool_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + netdev_page_pool_get_list_free(yds.first); + return NULL; +} + +/* NETDEV_CMD_PAGE_POOL_GET - notify */ +void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp) +{ + free(rsp); +} + +/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */ +/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ +void +netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req) +{ + netdev_page_pool_info_free(&req->info); + free(req); +} + +void +netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp) +{ + netdev_page_pool_info_free(&rsp->info); + free(rsp); +} + +int netdev_page_pool_stats_get_rsp_parse(const struct nlmsghdr *nlh, + void *data) +{ + struct netdev_page_pool_stats_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_PAGE_POOL_STATS_INFO) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.info = 1; + + parg.rsp_policy = &netdev_page_pool_info_nest; + parg.data = &dst->info; + if (netdev_page_pool_info_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_fast = 1; + dst->alloc_fast = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_slow = 1; + dst->alloc_slow = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_slow_high_order = 1; + dst->alloc_slow_high_order = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_empty = 1; + dst->alloc_empty = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_refill = 1; + dst->alloc_refill = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.alloc_waive = 1; + dst->alloc_waive = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.recycle_cached = 1; + dst->recycle_cached = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.recycle_cache_full = 1; + dst->recycle_cache_full = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.recycle_ring = 1; + dst->recycle_ring = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.recycle_ring_full = 1; + dst->recycle_ring_full = mnl_attr_get_uint(attr); + } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.recycle_released_refcnt = 1; + dst->recycle_released_refcnt = mnl_attr_get_uint(attr); + } + } + + return MNL_CB_OK; +} + +struct netdev_page_pool_stats_get_rsp * +netdev_page_pool_stats_get(struct ynl_sock *ys, + struct netdev_page_pool_stats_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct netdev_page_pool_stats_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1); + ys->req_policy = &netdev_page_pool_stats_nest; + yrs.yarg.rsp_policy = &netdev_page_pool_stats_nest; + + if (req->_present.info) + netdev_page_pool_info_put(nlh, NETDEV_A_PAGE_POOL_STATS_INFO, &req->info); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = netdev_page_pool_stats_get_rsp_parse; + yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + netdev_page_pool_stats_get_rsp_free(rsp); + return NULL; +} + +/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */ +void +netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp) +{ + struct netdev_page_pool_stats_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + netdev_page_pool_info_free(&rsp->obj.info); + free(rsp); + } +} + +struct netdev_page_pool_stats_get_list * +netdev_page_pool_stats_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct netdev_page_pool_stats_get_list); + yds.cb = netdev_page_pool_stats_get_rsp_parse; + yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET; + yds.rsp_policy = &netdev_page_pool_stats_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + netdev_page_pool_stats_get_list_free(yds.first); + return NULL; +} + static const struct ynl_ntf_info netdev_ntf_info[] = { [NETDEV_CMD_DEV_ADD_NTF] = { .alloc_sz = sizeof(struct netdev_dev_get_ntf), @@ -216,6 +617,24 @@ static const struct ynl_ntf_info netdev_ntf_info[] = { .policy = &netdev_dev_nest, .free = (void *)netdev_dev_get_ntf_free, }, + [NETDEV_CMD_PAGE_POOL_ADD_NTF] = { + .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), + .cb = netdev_page_pool_get_rsp_parse, + .policy = &netdev_page_pool_nest, + .free = (void *)netdev_page_pool_get_ntf_free, + }, + [NETDEV_CMD_PAGE_POOL_DEL_NTF] = { + .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), + .cb = netdev_page_pool_get_rsp_parse, + .policy = &netdev_page_pool_nest, + .free = (void *)netdev_page_pool_get_ntf_free, + }, + [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = { + .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), + .cb = netdev_page_pool_get_rsp_parse, + .policy = &netdev_page_pool_nest, + .free = (void *)netdev_page_pool_get_ntf_free, + }, }; const struct ynl_family ynl_netdev_family = { diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index 4fafac879df3..4093602c9b6c 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -21,6 +21,16 @@ const char *netdev_xdp_act_str(enum netdev_xdp_act value); const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); /* Common nested types */ +struct netdev_page_pool_info { + struct { + __u32 id:1; + __u32 ifindex:1; + } _present; + + __u64 id; + __u32 ifindex; +}; + /* ============== NETDEV_CMD_DEV_GET ============== */ /* NETDEV_CMD_DEV_GET - do */ struct netdev_dev_get_req { @@ -87,4 +97,165 @@ struct netdev_dev_get_ntf { void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); +/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */ +/* NETDEV_CMD_PAGE_POOL_GET - do */ +struct netdev_page_pool_get_req { + struct { + __u32 id:1; + } _present; + + __u64 id; +}; + +static inline struct netdev_page_pool_get_req * +netdev_page_pool_get_req_alloc(void) +{ + return calloc(1, sizeof(struct netdev_page_pool_get_req)); +} +void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req); + +static inline void +netdev_page_pool_get_req_set_id(struct netdev_page_pool_get_req *req, __u64 id) +{ + req->_present.id = 1; + req->id = id; +} + +struct netdev_page_pool_get_rsp { + struct { + __u32 id:1; + __u32 ifindex:1; + __u32 napi_id:1; + __u32 inflight:1; + __u32 inflight_mem:1; + __u32 detach_time:1; + } _present; + + __u64 id; + __u32 ifindex; + __u64 napi_id; + __u64 inflight; + __u64 inflight_mem; + __u64 detach_time; +}; + +void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp); + +/* + * Get / dump information about Page Pools. +(Only Page Pools associated with a net_device can be listed.) + + */ +struct netdev_page_pool_get_rsp * +netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req); + +/* NETDEV_CMD_PAGE_POOL_GET - dump */ +struct netdev_page_pool_get_list { + struct netdev_page_pool_get_list *next; + struct netdev_page_pool_get_rsp obj __attribute__((aligned(8))); +}; + +void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp); + +struct netdev_page_pool_get_list * +netdev_page_pool_get_dump(struct ynl_sock *ys); + +/* NETDEV_CMD_PAGE_POOL_GET - notify */ +struct netdev_page_pool_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct netdev_page_pool_get_ntf *ntf); + struct netdev_page_pool_get_rsp obj __attribute__((aligned(8))); +}; + +void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp); + +/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */ +/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ +struct netdev_page_pool_stats_get_req { + struct { + __u32 info:1; + } _present; + + struct netdev_page_pool_info info; +}; + +static inline struct netdev_page_pool_stats_get_req * +netdev_page_pool_stats_get_req_alloc(void) +{ + return calloc(1, sizeof(struct netdev_page_pool_stats_get_req)); +} +void +netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req); + +static inline void +netdev_page_pool_stats_get_req_set_info_id(struct netdev_page_pool_stats_get_req *req, + __u64 id) +{ + req->_present.info = 1; + req->info._present.id = 1; + req->info.id = id; +} +static inline void +netdev_page_pool_stats_get_req_set_info_ifindex(struct netdev_page_pool_stats_get_req *req, + __u32 ifindex) +{ + req->_present.info = 1; + req->info._present.ifindex = 1; + req->info.ifindex = ifindex; +} + +struct netdev_page_pool_stats_get_rsp { + struct { + __u32 info:1; + __u32 alloc_fast:1; + __u32 alloc_slow:1; + __u32 alloc_slow_high_order:1; + __u32 alloc_empty:1; + __u32 alloc_refill:1; + __u32 alloc_waive:1; + __u32 recycle_cached:1; + __u32 recycle_cache_full:1; + __u32 recycle_ring:1; + __u32 recycle_ring_full:1; + __u32 recycle_released_refcnt:1; + } _present; + + struct netdev_page_pool_info info; + __u64 alloc_fast; + __u64 alloc_slow; + __u64 alloc_slow_high_order; + __u64 alloc_empty; + __u64 alloc_refill; + __u64 alloc_waive; + __u64 recycle_cached; + __u64 recycle_cache_full; + __u64 recycle_ring; + __u64 recycle_ring_full; + __u64 recycle_released_refcnt; +}; + +void +netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp); + +/* + * Get page pool statistics. + */ +struct netdev_page_pool_stats_get_rsp * +netdev_page_pool_stats_get(struct ynl_sock *ys, + struct netdev_page_pool_stats_get_req *req); + +/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */ +struct netdev_page_pool_stats_get_list { + struct netdev_page_pool_stats_get_list *next; + struct netdev_page_pool_stats_get_rsp obj __attribute__((aligned(8))); +}; + +void +netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp); + +struct netdev_page_pool_stats_get_list * +netdev_page_pool_stats_get_dump(struct ynl_sock *ys); + #endif /* _LINUX_NETDEV_GEN_H */ diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index e974378e3b8c..075d868f3b57 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -239,7 +239,7 @@ int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); #ifndef MNL_HAS_AUTO_SCALARS static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) { - if (mnl_attr_get_len(attr) == 4) + if (mnl_attr_get_payload_len(attr) == 4) return mnl_attr_get_u32(attr); return mnl_attr_get_u64(attr); } diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 2aae60c4829f..49637b26c482 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1,3 +1,4 @@ ethtool devlink netdev +page-pool \ No newline at end of file diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 3dbb106e87d9..1afefc266b7a 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -18,7 +18,7 @@ include $(wildcard *.d) all: $(BINS) -$(BINS): ../lib/ynl.a ../generated/protos.a +$(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) @echo -e '\tCC sample $@' @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o @$(LINK.c) $@.o -o $@ $(LDLIBS) diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c new file mode 100644 index 000000000000..18d359713469 --- /dev/null +++ b/tools/net/ynl/samples/page-pool.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include + +#include + +#include + +#include "netdev-user.h" + +struct stat { + unsigned int ifc; + + struct { + unsigned int cnt; + size_t refs, bytes; + } live[2]; + + size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache; +}; + +struct stats_array { + unsigned int i, max; + struct stat *s; +}; + +static struct stat *find_ifc(struct stats_array *a, unsigned int ifindex) +{ + unsigned int i; + + for (i = 0; i < a->i; i++) { + if (a->s[i].ifc == ifindex) + return &a->s[i]; + } + + a->i++; + if (a->i == a->max) { + a->max *= 2; + a->s = reallocarray(a->s, a->max, sizeof(*a->s)); + } + a->s[i].ifc = ifindex; + return &a->s[i]; +} + +static void count(struct stat *s, unsigned int l, + struct netdev_page_pool_get_rsp *pp) +{ + s->live[l].cnt++; + if (pp->_present.inflight) + s->live[l].refs += pp->inflight; + if (pp->_present.inflight_mem) + s->live[l].bytes += pp->inflight_mem; +} + +int main(int argc, char **argv) +{ + struct netdev_page_pool_stats_get_list *pp_stats; + struct netdev_page_pool_get_list *pools; + struct stats_array a = {}; + struct ynl_error yerr; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + a.max = 128; + a.s = calloc(a.max, sizeof(*a.s)); + if (!a.s) + goto err_close; + + pools = netdev_page_pool_get_dump(ys); + if (!pools) + goto err_free; + + ynl_dump_foreach(pools, pp) { + struct stat *s = find_ifc(&a, pp->ifindex); + + count(s, 1, pp); + if (pp->_present.destroyed) + count(s, 0, pp); + } + netdev_page_pool_get_list_free(pools); + + pp_stats = netdev_page_pool_stats_get_dump(ys); + if (!pp_stats) + goto err_free; + + ynl_dump_foreach(pp_stats, pp) { + struct stat *s = find_ifc(&a, pp->info.ifindex); + + if (pp->_present.alloc_fast) + s->alloc_fast += pp->alloc_fast; + if (pp->_present.alloc_slow) + s->alloc_slow += pp->alloc_slow; + if (pp->_present.recycle_ring) + s->recycle_ring += pp->recycle_ring; + if (pp->_present.recycle_cached) + s->recycle_cache += pp->recycle_cached; + } + netdev_page_pool_stats_get_list_free(pp_stats); + + for (unsigned int i = 0; i < a.i; i++) { + char ifname[IF_NAMESIZE]; + struct stat *s = &a.s[i]; + const char *name; + double recycle; + + if (!s->ifc) { + name = "\t"; + } else { + name = if_indextoname(s->ifc, ifname); + if (name) + printf("%8s", name); + printf("[%d]\t", s->ifc); + } + + printf("page pools: %u (zombies: %u)\n", + s->live[1].cnt, s->live[0].cnt); + printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n", + s->live[1].refs, s->live[1].bytes, + s->live[0].refs, s->live[0].bytes); + + /* We don't know how many pages are sitting in cache and ring + * so we will under-count the recycling rate a bit. + */ + recycle = (double)(s->recycle_ring + s->recycle_cache) / + (s->alloc_fast + s->alloc_slow) * 100; + printf("\t\trecycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)\n", + recycle, s->alloc_slow, s->alloc_fast, + s->recycle_ring, s->recycle_cache); + } + + ynl_sock_destroy(ys); + return 0; + +err_free: + free(a.s); +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} From c350a08ac7ec933f1dc8a143ebab60164ed4d90b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:20 +0100 Subject: [PATCH 1652/7721] drm/ast: Turn ioregs_lock to modeset_lock The lock for the I/O registers is only relevant during mode-setting operations. It protects the registers from concurrent access from reading EDID information. Reduce lock coverage to mode setting, rename the lock and move it entirely into the mode-setting code. No functional changes, as the I/O lock was never used for anything else than mode setting. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-2-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 3 ++- drivers/gpu/drm/ast/ast_main.c | 4 ---- drivers/gpu/drm/ast/ast_mode.c | 26 +++++++++++++++----------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 772f3b049c16..2ec29480939d 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -192,7 +192,6 @@ to_ast_bmc_connector(struct drm_connector *connector) struct ast_device { struct drm_device base; - struct mutex ioregs_lock; /* Protects access to I/O registers in ioregs */ void __iomem *regs; void __iomem *ioregs; void __iomem *dp501_fw_buf; @@ -207,6 +206,8 @@ struct ast_device { unsigned long vram_size; unsigned long vram_fb_available; + struct mutex modeset_lock; /* Protects access to modeset I/O registers in ioregs */ + struct ast_plane primary_plane; struct ast_plane cursor_plane; struct drm_crtc crtc; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f4ab40e22cea..445cf47871a4 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -440,10 +440,6 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, pci_set_drvdata(pdev, dev); - ret = drmm_mutex_init(dev, &ast->ioregs_lock); - if (ret) - return ERR_PTR(ret); - ast->regs = pcim_iomap(pdev, 1, 0); if (!ast->regs) return ERR_PTR(-EIO); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index c20534d0ef7c..a718646a66b8 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1358,13 +1358,13 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); edid = drm_get_edid(connector, &ast_vga_connector->i2c->adapter); if (!edid) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1372,7 +1372,7 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1464,13 +1464,13 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); edid = drm_get_edid(connector, &ast_sil164_connector->i2c->adapter); if (!edid) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1478,7 +1478,7 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1670,13 +1670,13 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); succ = ast_astdp_read_edid(connector->dev, edid); if (succ < 0) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); @@ -1685,7 +1685,7 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); kfree(edid); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); @@ -1870,9 +1870,9 @@ static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *s * display modes. Protect access to I/O registers by acquiring * the I/O-register lock. Released in atomic_flush(). */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); drm_atomic_helper_commit_tail_rpm(state); - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); } static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { @@ -1910,6 +1910,10 @@ int ast_mode_config_init(struct ast_device *ast) struct drm_connector *physical_connector = NULL; int ret; + ret = drmm_mutex_init(dev, &ast->modeset_lock); + if (ret) + return ret; + ret = drmm_mode_config_init(dev); if (ret) return ret; From 0ccaa3dde97bd30ae615c66fc20080e920ec9b4e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:21 +0100 Subject: [PATCH 1653/7721] drm/ast: Rework I/O register setup There are three different ways of retrieving the I/O-memory ranges for AST devices: either from PCI BAR 1, from PCI BAR 2 or from PCI BAR 1 by 'guessing'. Make the respective code more readable by making each case self- contained. Also add error checking against the length of the PCI BARs. v2: * fix I/O range length to 128 bytes * fix length test for PCI BAR 2 Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-3-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_main.c | 42 +++++++++++++++++++++++++--------- drivers/gpu/drm/ast/ast_reg.h | 1 + 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 445cf47871a4..70e1871dbaf9 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -444,22 +444,42 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (!ast->regs) return ERR_PTR(-EIO); - /* - * After AST2500, MMIO is enabled by default, and it should be adopted - * to be compatible with Arm. - */ if (pdev->revision >= 0x40) { - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; - } else if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { - drm_info(dev, "platform has no IO space, trying MMIO\n"); - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; - } + /* + * On AST2500 and later models, MMIO is enabled by + * default. Adopt it to be compatible with ARM. + */ + resource_size_t len = pci_resource_len(pdev, 1); - /* "map" IO regs if the above hasn't done so already */ - if (!ast->ioregs) { + if (len < AST_IO_MM_OFFSET) + return ERR_PTR(-EIO); + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return ERR_PTR(-EIO); + ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + } else if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + /* + * Map I/O registers if we have a PCI BAR for I/O. + */ + resource_size_t len = pci_resource_len(pdev, 2); + + if (len < AST_IO_MM_LENGTH) + return -EIO; ast->ioregs = pcim_iomap(pdev, 2, 0); if (!ast->ioregs) return ERR_PTR(-EIO); + } else { + /* + * Anything else is best effort. + */ + resource_size_t len = pci_resource_len(pdev, 1); + + if (len < AST_IO_MM_OFFSET) + return ERR_PTR(-EIO); + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return ERR_PTR(-EIO); + ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + + drm_info(dev, "Platform has no I/O space, using MMIO\n"); } if (!ast_is_vga_enabled(dev)) { diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 555286ecf520..05bab94a9a90 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -10,6 +10,7 @@ */ #define AST_IO_MM_OFFSET (0x380) +#define AST_IO_MM_LENGTH (128) #define AST_IO_VGAARI_W (0x40) #define AST_IO_VGAMR_W (0x42) From b45efcfc94e8043d08344094a305bb4b8030c7df Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:22 +0100 Subject: [PATCH 1654/7721] drm/ast: Retrieve I/O-memory ranges without ast device Read the I/O-memory ranges into local variables before setting them in the ast device instanace. We'll later need this to split detecting the device type from the creation of the ast device instance. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-4-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 70e1871dbaf9..026ef893dd50 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -432,6 +432,8 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, struct ast_device *ast; bool need_post = false; int ret = 0; + void __iomem *regs; + void __iomem *ioregs; ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base); if (IS_ERR(ast)) @@ -440,8 +442,8 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, pci_set_drvdata(pdev, dev); - ast->regs = pcim_iomap(pdev, 1, 0); - if (!ast->regs) + regs = pcim_iomap(pdev, 1, 0); + if (!regs) return ERR_PTR(-EIO); if (pdev->revision >= 0x40) { @@ -455,7 +457,7 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, return ERR_PTR(-EIO); if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) return ERR_PTR(-EIO); - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + ioregs = regs + AST_IO_MM_OFFSET; } else if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { /* * Map I/O registers if we have a PCI BAR for I/O. @@ -464,8 +466,8 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (len < AST_IO_MM_LENGTH) return -EIO; - ast->ioregs = pcim_iomap(pdev, 2, 0); - if (!ast->ioregs) + ioregs = pcim_iomap(pdev, 2, 0); + if (!ioregs) return ERR_PTR(-EIO); } else { /* @@ -477,11 +479,14 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, return ERR_PTR(-EIO); if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) return ERR_PTR(-EIO); - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + ioregs = regs + AST_IO_MM_OFFSET; drm_info(dev, "Platform has no I/O space, using MMIO\n"); } + ast->regs = regs; + ast->ioregs = ioregs; + if (!ast_is_vga_enabled(dev)) { drm_info(dev, "VGA not enabled on entry, requesting chip POST\n"); need_post = true; From cdac0cd459cf282ccdc4f28f838a2375e5cf61f7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:23 +0100 Subject: [PATCH 1655/7721] drm/ast: Add I/O helpers without ast device Implement I/O access in helpers that do not use an ast device instance, but the raw pointer to the I/O memory. We'll later need these helpers to detect the device type before allocating the ast device instance. v3: * fix typo in commit message (Sui) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-5-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 73 +++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 2ec29480939d..71f0e23e08cd 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -273,55 +273,94 @@ static inline bool __ast_gen_is_eq(struct ast_device *ast, unsigned long gen) #define IS_AST_GEN6(__ast) __ast_gen_is_eq(__ast, 6) #define IS_AST_GEN7(__ast) __ast_gen_is_eq(__ast, 7) +static inline u8 __ast_read8(const void __iomem *addr, u32 reg) +{ + return ioread8(addr + reg); +} + +static inline u32 __ast_read32(const void __iomem *addr, u32 reg) +{ + return ioread32(addr + reg); +} + +static inline void __ast_write8(void __iomem *addr, u32 reg, u8 val) +{ + iowrite8(val, addr + reg); +} + +static inline void __ast_write32(void __iomem *addr, u32 reg, u32 val) +{ + iowrite32(val, addr + reg); +} + +static inline u8 __ast_read8_i(void __iomem *addr, u32 reg, u8 index) +{ + __ast_write8(addr, reg, index); + return __ast_read8(addr, reg + 1); +} + +static inline u8 __ast_read8_i_masked(void __iomem *addr, u32 reg, u8 index, u8 read_mask) +{ + u8 val = __ast_read8_i(addr, reg, index); + + return val & read_mask; +} + +static inline void __ast_write8_i(void __iomem *addr, u32 reg, u8 index, u8 val) +{ + __ast_write8(addr, reg, index); + __ast_write8(addr, reg + 1, val); +} + +static inline void __ast_write8_i_masked(void __iomem *addr, u32 reg, u8 index, u8 read_mask, + u8 val) +{ + u8 tmp = __ast_read8_i_masked(addr, reg, index, read_mask); + + tmp |= val; + __ast_write8_i(addr, reg, index, tmp); +} + static inline u32 ast_read32(struct ast_device *ast, u32 reg) { - return ioread32(ast->regs + reg); + return __ast_read32(ast->regs, reg); } static inline void ast_write32(struct ast_device *ast, u32 reg, u32 val) { - iowrite32(val, ast->regs + reg); + __ast_write32(ast->regs, reg, val); } static inline u8 ast_io_read8(struct ast_device *ast, u32 reg) { - return ioread8(ast->ioregs + reg); + return __ast_read8(ast->ioregs, reg); } static inline void ast_io_write8(struct ast_device *ast, u32 reg, u8 val) { - iowrite8(val, ast->ioregs + reg); + __ast_write8(ast->ioregs, reg, val); } static inline u8 ast_get_index_reg(struct ast_device *ast, u32 base, u8 index) { - ast_io_write8(ast, base, index); - ++base; - return ast_io_read8(ast, base); + return __ast_read8_i(ast->ioregs, base, index); } static inline u8 ast_get_index_reg_mask(struct ast_device *ast, u32 base, u8 index, u8 preserve_mask) { - u8 val = ast_get_index_reg(ast, base, index); - - return val & preserve_mask; + return __ast_read8_i_masked(ast->ioregs, base, index, preserve_mask); } static inline void ast_set_index_reg(struct ast_device *ast, u32 base, u8 index, u8 val) { - ast_io_write8(ast, base, index); - ++base; - ast_io_write8(ast, base, val); + __ast_write8_i(ast->ioregs, base, index, val); } static inline void ast_set_index_reg_mask(struct ast_device *ast, u32 base, u8 index, u8 preserve_mask, u8 val) { - u8 tmp = ast_get_index_reg_mask(ast, base, index, preserve_mask); - - tmp |= val; - ast_set_index_reg(ast, base, index, tmp); + __ast_write8_i_masked(ast->ioregs, base, index, preserve_mask, val); } #define AST_VIDMEM_SIZE_8M 0x00800000 From 73b05bb4c0539d89111ed2f9c5a2eac1b577f83d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:24 +0100 Subject: [PATCH 1656/7721] drm/ast: Enable VGA without ast device instance We'll have to enable the VGA functionality for detecting the ast device type. Make this work without an instance of the ast device. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-6-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_main.c | 29 ++++++++++++----------------- drivers/gpu/drm/ast/ast_reg.h | 9 +++++++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 026ef893dd50..82fcee967d98 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -35,22 +35,17 @@ #include "ast_drv.h" -static bool ast_is_vga_enabled(struct drm_device *dev) +static bool ast_is_vga_enabled(void __iomem *ioregs) { - struct ast_device *ast = to_ast_device(dev); - u8 ch; + u8 vgaer = __ast_read8(ioregs, AST_IO_VGAER); - ch = ast_io_read8(ast, AST_IO_VGAER); - - return !!(ch & 0x01); + return vgaer & AST_IO_VGAER_VGA_ENABLE; } -static void ast_enable_vga(struct drm_device *dev) +static void ast_enable_vga(void __iomem *ioregs) { - struct ast_device *ast = to_ast_device(dev); - - ast_io_write8(ast, AST_IO_VGAER, 0x01); - ast_io_write8(ast, AST_IO_VGAMR_W, 0x01); + __ast_write8(ioregs, AST_IO_VGAER, AST_IO_VGAER_VGA_ENABLE); + __ast_write8(ioregs, AST_IO_VGAMR_W, AST_IO_VGAMR_IOSEL); } /* @@ -74,9 +69,9 @@ static int ast_enable_mmio(struct ast_device *ast) return devm_add_action_or_reset(dev->dev, ast_enable_mmio_release, ast); } -static void ast_open_key(struct ast_device *ast) +static void ast_open_key(void __iomem *ioregs) { - ast_set_index_reg(ast, AST_IO_VGACRI, 0x80, 0xA8); + __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); } static int ast_device_config_init(struct ast_device *ast) @@ -487,7 +482,7 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, ast->regs = regs; ast->ioregs = ioregs; - if (!ast_is_vga_enabled(dev)) { + if (!ast_is_vga_enabled(ioregs)) { drm_info(dev, "VGA not enabled on entry, requesting chip POST\n"); need_post = true; } @@ -497,10 +492,10 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, * access to the scratch registers will fail. */ if (need_post) - ast_enable_vga(dev); - + ast_enable_vga(ioregs); /* Enable extended register access */ - ast_open_key(ast); + ast_open_key(ioregs); + ret = ast_enable_mmio(ast); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 05bab94a9a90..5258a84ef3a6 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -13,8 +13,14 @@ #define AST_IO_MM_LENGTH (128) #define AST_IO_VGAARI_W (0x40) + #define AST_IO_VGAMR_W (0x42) +#define AST_IO_VGAMR_R (0x4c) +#define AST_IO_VGAMR_IOSEL BIT(0) + #define AST_IO_VGAER (0x43) +#define AST_IO_VGAER_VGA_ENABLE BIT(0) + #define AST_IO_VGASRI (0x44) #define AST_IO_VGADRR (0x47) #define AST_IO_VGADWR (0x48) @@ -22,14 +28,13 @@ #define AST_IO_VGAGRI (0x4E) #define AST_IO_VGACRI (0x54) +#define AST_IO_VGACR80_PASSWORD (0xa8) #define AST_IO_VGACRCB_HWC_16BPP BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ #define AST_IO_VGACRCB_HWC_ENABLED BIT(1) #define AST_IO_VGAIR1_R (0x5A) #define AST_IO_VGAIR1_VREFRESH BIT(3) -#define AST_IO_VGAMR_R (0x4C) - /* * Display Transmitter Type */ From 66f843d6703513b9ee8d3d10694a21931feb32c7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:25 +0100 Subject: [PATCH 1657/7721] drm/ast: Enable MMIO without ast device instance We'll have to enable the MMIO access for detecting the ast device type. Make this work without an instance of the ast device. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-7-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_main.c | 16 +++++++++------- drivers/gpu/drm/ast/ast_reg.h | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 82fcee967d98..0173cb44f17d 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -54,19 +54,21 @@ static void ast_enable_vga(void __iomem *ioregs) */ static void ast_enable_mmio_release(void *data) { - struct ast_device *ast = data; + void __iomem *ioregs = (void __force __iomem *)data; /* enable standard VGA decode */ - ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x04); + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, AST_IO_VGACRA1_MMIO_ENABLED); } -static int ast_enable_mmio(struct ast_device *ast) +static int ast_enable_mmio(struct device *dev, void __iomem *ioregs) { - struct drm_device *dev = &ast->base; + void *data = (void __force *)ioregs; - ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06); + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, + AST_IO_VGACRA1_MMIO_ENABLED | + AST_IO_VGACRA1_VGAIO_DISABLED); - return devm_add_action_or_reset(dev->dev, ast_enable_mmio_release, ast); + return devm_add_action_or_reset(dev, ast_enable_mmio_release, data); } static void ast_open_key(void __iomem *ioregs) @@ -496,7 +498,7 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, /* Enable extended register access */ ast_open_key(ioregs); - ret = ast_enable_mmio(ast); + ret = ast_enable_mmio(&pdev->dev, ioregs); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 5258a84ef3a6..62dddbf3fe56 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -29,6 +29,8 @@ #define AST_IO_VGACRI (0x54) #define AST_IO_VGACR80_PASSWORD (0xa8) +#define AST_IO_VGACRA1_VGAIO_DISABLED BIT(1) +#define AST_IO_VGACRA1_MMIO_ENABLED BIT(2) #define AST_IO_VGACRCB_HWC_16BPP BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ #define AST_IO_VGACRCB_HWC_ENABLED BIT(1) From 83ab91faf20c1aed982ca5949ce5d83b34b7f546 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:26 +0100 Subject: [PATCH 1658/7721] drm/ast: Partially implement POST without ast device instance We'll have to do some of the GPU POSTing for detecting the ast device type. Make this work without an instance of the ast device. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-8-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 2 +- drivers/gpu/drm/ast/ast_main.c | 2 +- drivers/gpu/drm/ast/ast_post.c | 75 +++++++++++++++++++++------------- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 71f0e23e08cd..390fbec6bc2b 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -482,7 +482,7 @@ int ast_mm_init(struct ast_device *ast); void ast_post_gpu(struct drm_device *dev); u32 ast_mindwm(struct ast_device *ast, u32 r); void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); -void ast_patch_ahb_2500(struct ast_device *ast); +void ast_patch_ahb_2500(void __iomem *regs); /* ast dp501 */ void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 0173cb44f17d..19c8894e391a 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -113,7 +113,7 @@ static int ast_device_config_init(struct ast_device *ast) /* Patch AST2500/AST2510 */ if ((pdev->revision & 0xf0) == 0x40) { if (!(jregd0 & AST_VRAM_INIT_STATUS_MASK)) - ast_patch_ahb_2500(ast); + ast_patch_ahb_2500(ast->regs); } /* Double check that it's actually working */ diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 7a993a384314..22f548805dfb 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -77,28 +77,42 @@ ast_set_def_ext_reg(struct drm_device *dev) ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xff, reg); } -u32 ast_mindwm(struct ast_device *ast, u32 r) +static u32 __ast_mindwm(void __iomem *regs, u32 r) { - uint32_t data; + u32 data; - ast_write32(ast, 0xf004, r & 0xffff0000); - ast_write32(ast, 0xf000, 0x1); + __ast_write32(regs, 0xf004, r & 0xffff0000); + __ast_write32(regs, 0xf000, 0x1); do { - data = ast_read32(ast, 0xf004) & 0xffff0000; + data = __ast_read32(regs, 0xf004) & 0xffff0000; } while (data != (r & 0xffff0000)); - return ast_read32(ast, 0x10000 + (r & 0x0000ffff)); + + return __ast_read32(regs, 0x10000 + (r & 0x0000ffff)); +} + +static void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) +{ + u32 data; + + __ast_write32(regs, 0xf004, r & 0xffff0000); + __ast_write32(regs, 0xf000, 0x1); + + do { + data = __ast_read32(regs, 0xf004) & 0xffff0000; + } while (data != (r & 0xffff0000)); + + __ast_write32(regs, 0x10000 + (r & 0x0000ffff), v); +} + +u32 ast_mindwm(struct ast_device *ast, u32 r) +{ + return __ast_mindwm(ast->regs, r); } void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) { - uint32_t data; - ast_write32(ast, 0xf004, r & 0xffff0000); - ast_write32(ast, 0xf000, 0x1); - do { - data = ast_read32(ast, 0xf004) & 0xffff0000; - } while (data != (r & 0xffff0000)); - ast_write32(ast, 0x10000 + (r & 0x0000ffff), v); + __ast_moutdwm(ast->regs, r, v); } /* @@ -1987,17 +2001,18 @@ static bool ast_dram_init_2500(struct ast_device *ast) return true; } -void ast_patch_ahb_2500(struct ast_device *ast) +void ast_patch_ahb_2500(void __iomem *regs) { - u32 data; + u32 data; /* Clear bus lock condition */ - ast_moutdwm(ast, 0x1e600000, 0xAEED1A03); - ast_moutdwm(ast, 0x1e600084, 0x00010000); - ast_moutdwm(ast, 0x1e600088, 0x00000000); - ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); - data = ast_mindwm(ast, 0x1e6e2070); - if (data & 0x08000000) { /* check fast reset */ + __ast_moutdwm(regs, 0x1e600000, 0xAEED1A03); + __ast_moutdwm(regs, 0x1e600084, 0x00010000); + __ast_moutdwm(regs, 0x1e600088, 0x00000000); + __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); + + data = __ast_mindwm(regs, 0x1e6e2070); + if (data & 0x08000000) { /* check fast reset */ /* * If "Fast restet" is enabled for ARM-ICE debugger, * then WDT needs to enable, that @@ -2009,16 +2024,18 @@ void ast_patch_ahb_2500(struct ast_device *ast) * [1]:= 1:WDT will be cleeared and disabled after timeout occurs * [0]:= 1:WDT enable */ - ast_moutdwm(ast, 0x1E785004, 0x00000010); - ast_moutdwm(ast, 0x1E785008, 0x00004755); - ast_moutdwm(ast, 0x1E78500c, 0x00000033); + __ast_moutdwm(regs, 0x1E785004, 0x00000010); + __ast_moutdwm(regs, 0x1E785008, 0x00004755); + __ast_moutdwm(regs, 0x1E78500c, 0x00000033); udelay(1000); } + do { - ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); - data = ast_mindwm(ast, 0x1e6e2000); - } while (data != 1); - ast_moutdwm(ast, 0x1e6e207c, 0x08000000); /* clear fast reset */ + __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); + data = __ast_mindwm(regs, 0x1e6e2000); + } while (data != 1); + + __ast_moutdwm(regs, 0x1e6e207c, 0x08000000); /* clear fast reset */ } void ast_post_chip_2500(struct drm_device *dev) @@ -2030,7 +2047,7 @@ void ast_post_chip_2500(struct drm_device *dev) reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((reg & AST_VRAM_INIT_STATUS_MASK) == 0) {/* vga only */ /* Clear bus lock condition */ - ast_patch_ahb_2500(ast); + ast_patch_ahb_2500(ast->regs); /* Disable watchdog */ ast_moutdwm(ast, 0x1E78502C, 0x00000000); From 9f3ebec843b0f48ea2c22b7e85c34040aa7c9ee8 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:27 +0100 Subject: [PATCH 1659/7721] drm/ast: Add enum ast_config_mode The config mode used to be a field in struct ast_device. Turn it into a named type. We'll need this for device detection. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-9-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 390fbec6bc2b..4c6ee163c6d9 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -98,6 +98,12 @@ enum ast_tx_chip { #define AST_TX_DP501_BIT BIT(AST_TX_DP501) #define AST_TX_ASTDP_BIT BIT(AST_TX_ASTDP) +enum ast_config_mode { + ast_use_p2a, + ast_use_dt, + ast_use_defaults +}; + #define AST_DRAM_512Mx16 0 #define AST_DRAM_1Gx16 1 #define AST_DRAM_512Mx32 2 @@ -196,7 +202,9 @@ struct ast_device { void __iomem *ioregs; void __iomem *dp501_fw_buf; + enum ast_config_mode config_mode; enum ast_chip chip; + uint32_t dram_bus_width; uint32_t dram_type; uint32_t mclk; @@ -235,11 +243,6 @@ struct ast_device { } output; bool support_wide_screen; - enum { - ast_use_p2a, - ast_use_dt, - ast_use_defaults - } config_mode; unsigned long tx_chip_types; /* bitfield of enum ast_chip_type */ u8 *dp501_fw_addr; From 51412f869337682d0e9e640c5b424ffb8295d353 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:28 +0100 Subject: [PATCH 1660/7721] drm/ast: Detect ast device type and config mode without ast device Return the ast chip and config in the detection function's parameters instead of storing them directly in the ast device instance. v2: * add break statements to switch default branches (Jocelyn) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-10-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_main.c | 106 ++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 19c8894e391a..ad5b758153de 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -76,25 +76,27 @@ static void ast_open_key(void __iomem *ioregs) __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); } -static int ast_device_config_init(struct ast_device *ast) +static int ast_detect_chip(struct pci_dev *pdev, + void __iomem *regs, void __iomem *ioregs, + enum ast_chip *chip_out, + enum ast_config_mode *config_mode_out) { - struct drm_device *dev = &ast->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - struct device_node *np = dev->dev->of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum ast_config_mode config_mode = ast_use_defaults; uint32_t scu_rev = 0xffffffff; + enum ast_chip chip; u32 data; - u8 jregd0, jregd1; + u8 vgacrd0, vgacrd1; /* * Find configuration mode and read SCU revision */ - ast->config_mode = ast_use_defaults; - /* Check if we have device-tree properties */ if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", &data)) { /* We do, disable P2A access */ - ast->config_mode = ast_use_dt; + config_mode = ast_use_dt; scu_rev = data; } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge /* @@ -102,9 +104,9 @@ static int ast_device_config_init(struct ast_device *ast) * is disabled. We force using P2A if VGA only mode bit * is set D[7] */ - jregd0 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); - jregd1 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff); - if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { + vgacrd0 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd0); + vgacrd1 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd1); + if (!(vgacrd0 & 0x80) || !(vgacrd1 & 0x10)) { /* * We have a P2A bridge and it is enabled. @@ -112,32 +114,32 @@ static int ast_device_config_init(struct ast_device *ast) /* Patch AST2500/AST2510 */ if ((pdev->revision & 0xf0) == 0x40) { - if (!(jregd0 & AST_VRAM_INIT_STATUS_MASK)) - ast_patch_ahb_2500(ast->regs); + if (!(vgacrd0 & AST_VRAM_INIT_STATUS_MASK)) + ast_patch_ahb_2500(regs); } /* Double check that it's actually working */ - data = ast_read32(ast, 0xf004); + data = __ast_read32(regs, 0xf004); if ((data != 0xffffffff) && (data != 0x00)) { - ast->config_mode = ast_use_p2a; + config_mode = ast_use_p2a; /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - scu_rev = ast_read32(ast, 0x1207c); + __ast_write32(regs, 0xf004, 0x1e6e0000); + __ast_write32(regs, 0xf000, 0x1); + scu_rev = __ast_read32(regs, 0x1207c); } } } - switch (ast->config_mode) { + switch (config_mode) { case ast_use_defaults: - drm_info(dev, "Using default configuration\n"); + dev_info(dev, "Using default configuration\n"); break; case ast_use_dt: - drm_info(dev, "Using device-tree for configuration\n"); + dev_info(dev, "Using device-tree for configuration\n"); break; case ast_use_p2a: - drm_info(dev, "Using P2A bridge for configuration\n"); + dev_info(dev, "Using P2A bridge for configuration\n"); break; } @@ -146,63 +148,68 @@ static int ast_device_config_init(struct ast_device *ast) */ if (pdev->revision >= 0x50) { - ast->chip = AST2600; - drm_info(dev, "AST 2600 detected\n"); + chip = AST2600; + dev_info(dev, "AST 2600 detected\n"); } else if (pdev->revision >= 0x40) { switch (scu_rev & 0x300) { case 0x0100: - ast->chip = AST2510; - drm_info(dev, "AST 2510 detected\n"); + chip = AST2510; + dev_info(dev, "AST 2510 detected\n"); break; default: - ast->chip = AST2500; - drm_info(dev, "AST 2500 detected\n"); + chip = AST2500; + dev_info(dev, "AST 2500 detected\n"); + break; } } else if (pdev->revision >= 0x30) { switch (scu_rev & 0x300) { case 0x0100: - ast->chip = AST1400; - drm_info(dev, "AST 1400 detected\n"); + chip = AST1400; + dev_info(dev, "AST 1400 detected\n"); break; default: - ast->chip = AST2400; - drm_info(dev, "AST 2400 detected\n"); + chip = AST2400; + dev_info(dev, "AST 2400 detected\n"); + break; } } else if (pdev->revision >= 0x20) { switch (scu_rev & 0x300) { case 0x0000: - ast->chip = AST1300; - drm_info(dev, "AST 1300 detected\n"); + chip = AST1300; + dev_info(dev, "AST 1300 detected\n"); break; default: - ast->chip = AST2300; - drm_info(dev, "AST 2300 detected\n"); + chip = AST2300; + dev_info(dev, "AST 2300 detected\n"); break; } } else if (pdev->revision >= 0x10) { switch (scu_rev & 0x0300) { case 0x0200: - ast->chip = AST1100; - drm_info(dev, "AST 1100 detected\n"); + chip = AST1100; + dev_info(dev, "AST 1100 detected\n"); break; case 0x0100: - ast->chip = AST2200; - drm_info(dev, "AST 2200 detected\n"); + chip = AST2200; + dev_info(dev, "AST 2200 detected\n"); break; case 0x0000: - ast->chip = AST2150; - drm_info(dev, "AST 2150 detected\n"); + chip = AST2150; + dev_info(dev, "AST 2150 detected\n"); break; default: - ast->chip = AST2100; - drm_info(dev, "AST 2100 detected\n"); + chip = AST2100; + dev_info(dev, "AST 2100 detected\n"); break; } } else { - ast->chip = AST2000; - drm_info(dev, "AST 2000 detected\n"); + chip = AST2000; + dev_info(dev, "AST 2000 detected\n"); } + *chip_out = chip; + *config_mode_out = config_mode; + return 0; } @@ -431,6 +438,8 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, int ret = 0; void __iomem *regs; void __iomem *ioregs; + enum ast_config_mode config_mode; + enum ast_chip chip; ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base); if (IS_ERR(ast)) @@ -502,10 +511,13 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (ret) return ERR_PTR(ret); - ret = ast_device_config_init(ast); + ret = ast_detect_chip(pdev, regs, ioregs, &chip, &config_mode); if (ret) return ERR_PTR(ret); + ast->chip = chip; + ast->config_mode = config_mode; + ast_detect_widescreen(ast); ast_detect_tx_chip(ast, need_post); From 83dc1029dcf50b5b849b26679a1b3f860b85d79c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 16 Nov 2023 10:59:29 +0100 Subject: [PATCH 1661/7721] drm/ast: Move detection code into PCI probe helper Detect device type and config mode in the PCI probe helper, but leave DRM device initialization where it is. Structures the driver probe and setup code into a detection and an initialization phase. A later patch can add branching to the device-initialization code. Each chip type can have it own initializer function, if necessary. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231116100240.22975-11-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.c | 263 +++++++++++++++++++++++++++++++- drivers/gpu/drm/ast/ast_drv.h | 10 +- drivers/gpu/drm/ast/ast_main.c | 270 ++------------------------------- 3 files changed, 274 insertions(+), 269 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index cf5b754f044c..90bcb1eb9cd9 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -89,11 +89,194 @@ static const struct pci_device_id ast_pciidlist[] = { MODULE_DEVICE_TABLE(pci, ast_pciidlist); +static bool ast_is_vga_enabled(void __iomem *ioregs) +{ + u8 vgaer = __ast_read8(ioregs, AST_IO_VGAER); + + return vgaer & AST_IO_VGAER_VGA_ENABLE; +} + +static void ast_enable_vga(void __iomem *ioregs) +{ + __ast_write8(ioregs, AST_IO_VGAER, AST_IO_VGAER_VGA_ENABLE); + __ast_write8(ioregs, AST_IO_VGAMR_W, AST_IO_VGAMR_IOSEL); +} + +/* + * Run this function as part of the HW device cleanup; not + * when the DRM device gets released. + */ +static void ast_enable_mmio_release(void *data) +{ + void __iomem *ioregs = (void __force __iomem *)data; + + /* enable standard VGA decode */ + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, AST_IO_VGACRA1_MMIO_ENABLED); +} + +static int ast_enable_mmio(struct device *dev, void __iomem *ioregs) +{ + void *data = (void __force *)ioregs; + + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, + AST_IO_VGACRA1_MMIO_ENABLED | + AST_IO_VGACRA1_VGAIO_DISABLED); + + return devm_add_action_or_reset(dev, ast_enable_mmio_release, data); +} + +static void ast_open_key(void __iomem *ioregs) +{ + __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); +} + +static int ast_detect_chip(struct pci_dev *pdev, + void __iomem *regs, void __iomem *ioregs, + enum ast_chip *chip_out, + enum ast_config_mode *config_mode_out) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum ast_config_mode config_mode = ast_use_defaults; + uint32_t scu_rev = 0xffffffff; + enum ast_chip chip; + u32 data; + u8 vgacrd0, vgacrd1; + + /* + * Find configuration mode and read SCU revision + */ + + /* Check if we have device-tree properties */ + if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", &data)) { + /* We do, disable P2A access */ + config_mode = ast_use_dt; + scu_rev = data; + } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge + /* + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge + * is disabled. We force using P2A if VGA only mode bit + * is set D[7] + */ + vgacrd0 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd0); + vgacrd1 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd1); + if (!(vgacrd0 & 0x80) || !(vgacrd1 & 0x10)) { + + /* + * We have a P2A bridge and it is enabled. + */ + + /* Patch AST2500/AST2510 */ + if ((pdev->revision & 0xf0) == 0x40) { + if (!(vgacrd0 & AST_VRAM_INIT_STATUS_MASK)) + ast_patch_ahb_2500(regs); + } + + /* Double check that it's actually working */ + data = __ast_read32(regs, 0xf004); + if ((data != 0xffffffff) && (data != 0x00)) { + config_mode = ast_use_p2a; + + /* Read SCU7c (silicon revision register) */ + __ast_write32(regs, 0xf004, 0x1e6e0000); + __ast_write32(regs, 0xf000, 0x1); + scu_rev = __ast_read32(regs, 0x1207c); + } + } + } + + switch (config_mode) { + case ast_use_defaults: + dev_info(dev, "Using default configuration\n"); + break; + case ast_use_dt: + dev_info(dev, "Using device-tree for configuration\n"); + break; + case ast_use_p2a: + dev_info(dev, "Using P2A bridge for configuration\n"); + break; + } + + /* + * Identify chipset + */ + + if (pdev->revision >= 0x50) { + chip = AST2600; + dev_info(dev, "AST 2600 detected\n"); + } else if (pdev->revision >= 0x40) { + switch (scu_rev & 0x300) { + case 0x0100: + chip = AST2510; + dev_info(dev, "AST 2510 detected\n"); + break; + default: + chip = AST2500; + dev_info(dev, "AST 2500 detected\n"); + break; + } + } else if (pdev->revision >= 0x30) { + switch (scu_rev & 0x300) { + case 0x0100: + chip = AST1400; + dev_info(dev, "AST 1400 detected\n"); + break; + default: + chip = AST2400; + dev_info(dev, "AST 2400 detected\n"); + break; + } + } else if (pdev->revision >= 0x20) { + switch (scu_rev & 0x300) { + case 0x0000: + chip = AST1300; + dev_info(dev, "AST 1300 detected\n"); + break; + default: + chip = AST2300; + dev_info(dev, "AST 2300 detected\n"); + break; + } + } else if (pdev->revision >= 0x10) { + switch (scu_rev & 0x0300) { + case 0x0200: + chip = AST1100; + dev_info(dev, "AST 1100 detected\n"); + break; + case 0x0100: + chip = AST2200; + dev_info(dev, "AST 2200 detected\n"); + break; + case 0x0000: + chip = AST2150; + dev_info(dev, "AST 2150 detected\n"); + break; + default: + chip = AST2100; + dev_info(dev, "AST 2100 detected\n"); + break; + } + } else { + chip = AST2000; + dev_info(dev, "AST 2000 detected\n"); + } + + *chip_out = chip; + *config_mode_out = config_mode; + + return 0; +} + static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct ast_device *ast; - struct drm_device *dev; + struct device *dev = &pdev->dev; int ret; + void __iomem *regs; + void __iomem *ioregs; + enum ast_config_mode config_mode; + enum ast_chip chip; + struct drm_device *drm; + bool need_post = false; ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &ast_driver); if (ret) @@ -103,16 +286,80 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - ast = ast_device_create(&ast_driver, pdev, ent->driver_data); - if (IS_ERR(ast)) - return PTR_ERR(ast); - dev = &ast->base; + regs = pcim_iomap(pdev, 1, 0); + if (!regs) + return -EIO; - ret = drm_dev_register(dev, ent->driver_data); + if (pdev->revision >= 0x40) { + /* + * On AST2500 and later models, MMIO is enabled by + * default. Adopt it to be compatible with ARM. + */ + resource_size_t len = pci_resource_len(pdev, 1); + + if (len < AST_IO_MM_OFFSET) + return -EIO; + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return -EIO; + ioregs = regs + AST_IO_MM_OFFSET; + } else if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + /* + * Map I/O registers if we have a PCI BAR for I/O. + */ + resource_size_t len = pci_resource_len(pdev, 2); + + if (len < AST_IO_MM_LENGTH) + return -EIO; + ioregs = pcim_iomap(pdev, 2, 0); + if (!ioregs) + return -EIO; + } else { + /* + * Anything else is best effort. + */ + resource_size_t len = pci_resource_len(pdev, 1); + + if (len < AST_IO_MM_OFFSET) + return -EIO; + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return -EIO; + ioregs = regs + AST_IO_MM_OFFSET; + + dev_info(dev, "Platform has no I/O space, using MMIO\n"); + } + + if (!ast_is_vga_enabled(ioregs)) { + dev_info(dev, "VGA not enabled on entry, requesting chip POST\n"); + need_post = true; + } + + /* + * If VGA isn't enabled, we need to enable now or subsequent + * access to the scratch registers will fail. + */ + if (need_post) + ast_enable_vga(ioregs); + /* Enable extended register access */ + ast_open_key(ioregs); + + ret = ast_enable_mmio(dev, ioregs); if (ret) return ret; - drm_fbdev_generic_setup(dev, 32); + ret = ast_detect_chip(pdev, regs, ioregs, &chip, &config_mode); + if (ret) + return ret; + + drm = ast_device_create(pdev, &ast_driver, chip, config_mode, regs, ioregs, need_post); + if (IS_ERR(drm)) + return PTR_ERR(drm); + pci_set_drvdata(pdev, drm); + + ret = drm_dev_register(drm, ent->driver_data); + if (ret) + return ret; + + drm_fbdev_generic_setup(drm, 32); return 0; } diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 4c6ee163c6d9..3be5ccf1f5f4 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -254,9 +254,13 @@ static inline struct ast_device *to_ast_device(struct drm_device *dev) return container_of(dev, struct ast_device, base); } -struct ast_device *ast_device_create(const struct drm_driver *drv, - struct pci_dev *pdev, - unsigned long flags); +struct drm_device *ast_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum ast_chip chip, + enum ast_config_mode config_mode, + void __iomem *regs, + void __iomem *ioregs, + bool need_post); static inline unsigned long __ast_gen(struct ast_device *ast) { diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index ad5b758153de..2f3ad5f949fc 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -35,184 +35,6 @@ #include "ast_drv.h" -static bool ast_is_vga_enabled(void __iomem *ioregs) -{ - u8 vgaer = __ast_read8(ioregs, AST_IO_VGAER); - - return vgaer & AST_IO_VGAER_VGA_ENABLE; -} - -static void ast_enable_vga(void __iomem *ioregs) -{ - __ast_write8(ioregs, AST_IO_VGAER, AST_IO_VGAER_VGA_ENABLE); - __ast_write8(ioregs, AST_IO_VGAMR_W, AST_IO_VGAMR_IOSEL); -} - -/* - * Run this function as part of the HW device cleanup; not - * when the DRM device gets released. - */ -static void ast_enable_mmio_release(void *data) -{ - void __iomem *ioregs = (void __force __iomem *)data; - - /* enable standard VGA decode */ - __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, AST_IO_VGACRA1_MMIO_ENABLED); -} - -static int ast_enable_mmio(struct device *dev, void __iomem *ioregs) -{ - void *data = (void __force *)ioregs; - - __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, - AST_IO_VGACRA1_MMIO_ENABLED | - AST_IO_VGACRA1_VGAIO_DISABLED); - - return devm_add_action_or_reset(dev, ast_enable_mmio_release, data); -} - -static void ast_open_key(void __iomem *ioregs) -{ - __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); -} - -static int ast_detect_chip(struct pci_dev *pdev, - void __iomem *regs, void __iomem *ioregs, - enum ast_chip *chip_out, - enum ast_config_mode *config_mode_out) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - enum ast_config_mode config_mode = ast_use_defaults; - uint32_t scu_rev = 0xffffffff; - enum ast_chip chip; - u32 data; - u8 vgacrd0, vgacrd1; - - /* - * Find configuration mode and read SCU revision - */ - - /* Check if we have device-tree properties */ - if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", &data)) { - /* We do, disable P2A access */ - config_mode = ast_use_dt; - scu_rev = data; - } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge - /* - * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge - * is disabled. We force using P2A if VGA only mode bit - * is set D[7] - */ - vgacrd0 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd0); - vgacrd1 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd1); - if (!(vgacrd0 & 0x80) || !(vgacrd1 & 0x10)) { - - /* - * We have a P2A bridge and it is enabled. - */ - - /* Patch AST2500/AST2510 */ - if ((pdev->revision & 0xf0) == 0x40) { - if (!(vgacrd0 & AST_VRAM_INIT_STATUS_MASK)) - ast_patch_ahb_2500(regs); - } - - /* Double check that it's actually working */ - data = __ast_read32(regs, 0xf004); - if ((data != 0xffffffff) && (data != 0x00)) { - config_mode = ast_use_p2a; - - /* Read SCU7c (silicon revision register) */ - __ast_write32(regs, 0xf004, 0x1e6e0000); - __ast_write32(regs, 0xf000, 0x1); - scu_rev = __ast_read32(regs, 0x1207c); - } - } - } - - switch (config_mode) { - case ast_use_defaults: - dev_info(dev, "Using default configuration\n"); - break; - case ast_use_dt: - dev_info(dev, "Using device-tree for configuration\n"); - break; - case ast_use_p2a: - dev_info(dev, "Using P2A bridge for configuration\n"); - break; - } - - /* - * Identify chipset - */ - - if (pdev->revision >= 0x50) { - chip = AST2600; - dev_info(dev, "AST 2600 detected\n"); - } else if (pdev->revision >= 0x40) { - switch (scu_rev & 0x300) { - case 0x0100: - chip = AST2510; - dev_info(dev, "AST 2510 detected\n"); - break; - default: - chip = AST2500; - dev_info(dev, "AST 2500 detected\n"); - break; - } - } else if (pdev->revision >= 0x30) { - switch (scu_rev & 0x300) { - case 0x0100: - chip = AST1400; - dev_info(dev, "AST 1400 detected\n"); - break; - default: - chip = AST2400; - dev_info(dev, "AST 2400 detected\n"); - break; - } - } else if (pdev->revision >= 0x20) { - switch (scu_rev & 0x300) { - case 0x0000: - chip = AST1300; - dev_info(dev, "AST 1300 detected\n"); - break; - default: - chip = AST2300; - dev_info(dev, "AST 2300 detected\n"); - break; - } - } else if (pdev->revision >= 0x10) { - switch (scu_rev & 0x0300) { - case 0x0200: - chip = AST1100; - dev_info(dev, "AST 1100 detected\n"); - break; - case 0x0100: - chip = AST2200; - dev_info(dev, "AST 2200 detected\n"); - break; - case 0x0000: - chip = AST2150; - dev_info(dev, "AST 2150 detected\n"); - break; - default: - chip = AST2100; - dev_info(dev, "AST 2100 detected\n"); - break; - } - } else { - chip = AST2000; - dev_info(dev, "AST 2000 detected\n"); - } - - *chip_out = chip; - *config_mode_out = config_mode; - - return 0; -} - static void ast_detect_widescreen(struct ast_device *ast) { u8 jreg; @@ -428,95 +250,27 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; } -struct ast_device *ast_device_create(const struct drm_driver *drv, - struct pci_dev *pdev, - unsigned long flags) +struct drm_device *ast_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum ast_chip chip, + enum ast_config_mode config_mode, + void __iomem *regs, + void __iomem *ioregs, + bool need_post) { struct drm_device *dev; struct ast_device *ast; - bool need_post = false; - int ret = 0; - void __iomem *regs; - void __iomem *ioregs; - enum ast_config_mode config_mode; - enum ast_chip chip; + int ret; ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base); if (IS_ERR(ast)) - return ast; + return ERR_CAST(ast); dev = &ast->base; - pci_set_drvdata(pdev, dev); - - regs = pcim_iomap(pdev, 1, 0); - if (!regs) - return ERR_PTR(-EIO); - - if (pdev->revision >= 0x40) { - /* - * On AST2500 and later models, MMIO is enabled by - * default. Adopt it to be compatible with ARM. - */ - resource_size_t len = pci_resource_len(pdev, 1); - - if (len < AST_IO_MM_OFFSET) - return ERR_PTR(-EIO); - if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) - return ERR_PTR(-EIO); - ioregs = regs + AST_IO_MM_OFFSET; - } else if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - /* - * Map I/O registers if we have a PCI BAR for I/O. - */ - resource_size_t len = pci_resource_len(pdev, 2); - - if (len < AST_IO_MM_LENGTH) - return -EIO; - ioregs = pcim_iomap(pdev, 2, 0); - if (!ioregs) - return ERR_PTR(-EIO); - } else { - /* - * Anything else is best effort. - */ - resource_size_t len = pci_resource_len(pdev, 1); - - if (len < AST_IO_MM_OFFSET) - return ERR_PTR(-EIO); - if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) - return ERR_PTR(-EIO); - ioregs = regs + AST_IO_MM_OFFSET; - - drm_info(dev, "Platform has no I/O space, using MMIO\n"); - } - - ast->regs = regs; - ast->ioregs = ioregs; - - if (!ast_is_vga_enabled(ioregs)) { - drm_info(dev, "VGA not enabled on entry, requesting chip POST\n"); - need_post = true; - } - - /* - * If VGA isn't enabled, we need to enable now or subsequent - * access to the scratch registers will fail. - */ - if (need_post) - ast_enable_vga(ioregs); - /* Enable extended register access */ - ast_open_key(ioregs); - - ret = ast_enable_mmio(&pdev->dev, ioregs); - if (ret) - return ERR_PTR(ret); - - ret = ast_detect_chip(pdev, regs, ioregs, &chip, &config_mode); - if (ret) - return ERR_PTR(ret); - ast->chip = chip; ast->config_mode = config_mode; + ast->regs = regs; + ast->ioregs = ioregs; ast_detect_widescreen(ast); ast_detect_tx_chip(ast, need_post); @@ -547,5 +301,5 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (ret) return ERR_PTR(ret); - return ast; + return dev; } From 288b039db225676e0c520c981a1b5a2562d893a3 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Fri, 24 Nov 2023 10:42:30 +0100 Subject: [PATCH 1662/7721] drm/bridge: Fix typo in post_disable() description s/singals/signals/ Fixes: 199e4e967af4 ("drm: Extract drm_bridge.h") Signed-off-by: Dario Binacchi Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231124094253.658064-1-dario.binacchi@amarulasolutions.com --- include/drm/drm_bridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index cfb7dcdb66c4..9ef461aa9b9e 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -194,7 +194,7 @@ struct drm_bridge_funcs { * or &drm_encoder_helper_funcs.dpms hook. * * The bridge must assume that the display pipe (i.e. clocks and timing - * singals) feeding it is no longer running when this callback is + * signals) feeding it is no longer running when this callback is * called. * * The @post_disable callback is optional. From 97137bd3ffc5c5972ef3e27d145250c1750f8dc4 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 27 Nov 2023 11:00:44 -0800 Subject: [PATCH 1663/7721] drm/i915/dg2: Drop Wa_22014600077 This workaround has been dropped from all DG2 variants in the latest workaround database update. Signed-off-by: Matt Roper Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231127190043.4099109-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 9bc0654efdc0..4cbf9e512645 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2357,14 +2357,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) 0, true); } - if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) { - /* Wa_22014600077:dg2 */ - wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), - 0 /* Wa_14012342262 write-only reg, so skip verification */, - true); - } - if (IS_DG2(i915) || IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* From 325b71e820b67569048c621227266783442b75ed Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Thu, 23 Nov 2023 13:18:07 +0800 Subject: [PATCH 1664/7721] drm/bridge: imx93-mipi-dsi: Fix a couple of building warnings Fix a couple of building warnings on used uninitialized 'best_m' and 'best_n' local variables by initializing 'best_m' to zero and 'best_n' to UINT_MAX. This makes compiler happy only. No functional change. Fixes: ce62f8ea7e3f ("drm/bridge: imx: Add i.MX93 MIPI DSI support") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311151746.f7u7dzbZ-lkp@intel.com/ Signed-off-by: Liu Ying Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231123051807.3818342-1-victor.liu@nxp.com --- drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c index 3ff30ce80c5b..2347f8dd632f 100644 --- a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c @@ -226,8 +226,8 @@ dphy_pll_get_configure_from_opts(struct imx93_dsi *dsi, unsigned long fout; unsigned long best_fout = 0; unsigned int fvco_div; - unsigned int min_n, max_n, n, best_n; - unsigned long m, best_m; + unsigned int min_n, max_n, n, best_n = UINT_MAX; + unsigned long m, best_m = 0; unsigned long min_delta = ULONG_MAX; unsigned long delta; u64 tmp; From 1750ec40593399dd0e8b62a4d23e1b9e55068afd Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:05 +0800 Subject: [PATCH 1665/7721] reset: brcmstb: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230704120211.38122-1-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-brcmstb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/reset/reset-brcmstb.c b/drivers/reset/reset-brcmstb.c index 42c9d5241c53..810fe76452d6 100644 --- a/drivers/reset/reset-brcmstb.c +++ b/drivers/reset/reset-brcmstb.c @@ -90,8 +90,7 @@ static int brcmstb_reset_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(kdev, res); + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); From 66a1f3929a522482b735e68a43d243b0545c17b6 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:06 +0800 Subject: [PATCH 1666/7721] reset: meson-audio-arb: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20230704120211.38122-2-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson-audio-arb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/reset-meson-audio-arb.c index 7e46dbc04998..7891d52fa899 100644 --- a/drivers/reset/reset-meson-audio-arb.c +++ b/drivers/reset/reset-meson-audio-arb.c @@ -139,7 +139,6 @@ static int meson_audio_arb_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct meson_audio_arb_match_data *data; struct meson_audio_arb_data *arb; - struct resource *res; int ret; data = of_device_get_match_data(dev); @@ -155,8 +154,7 @@ static int meson_audio_arb_probe(struct platform_device *pdev) if (IS_ERR(arb->clk)) return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - arb->regs = devm_ioremap_resource(dev, res); + arb->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(arb->regs)) return PTR_ERR(arb->regs); From 3d471cfbf26c9865d228c5988daf10f00e3ed770 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:07 +0800 Subject: [PATCH 1667/7721] reset: qcom-aoss: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704120211.38122-3-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-qcom-aoss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c index f52e90e36194..93c84d70ef64 100644 --- a/drivers/reset/reset-qcom-aoss.c +++ b/drivers/reset/reset-qcom-aoss.c @@ -90,7 +90,6 @@ static int qcom_aoss_reset_probe(struct platform_device *pdev) struct qcom_aoss_reset_data *data; struct device *dev = &pdev->dev; const struct qcom_aoss_desc *desc; - struct resource *res; desc = of_device_get_match_data(dev); if (!desc) @@ -101,8 +100,7 @@ static int qcom_aoss_reset_probe(struct platform_device *pdev) return -ENOMEM; data->desc = desc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->base = devm_ioremap_resource(dev, res); + data->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->base)) return PTR_ERR(data->base); From 49994d704d39bca20f15b4af125441c59520e887 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:08 +0800 Subject: [PATCH 1668/7721] reset: qcom: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704120211.38122-4-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-qcom-pdc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c index a3aae3f902e6..dce1fc1a68ad 100644 --- a/drivers/reset/reset-qcom-pdc.c +++ b/drivers/reset/reset-qcom-pdc.c @@ -114,7 +114,6 @@ static int qcom_pdc_reset_probe(struct platform_device *pdev) struct qcom_pdc_reset_data *data; struct device *dev = &pdev->dev; void __iomem *base; - struct resource *res; desc = device_get_match_data(&pdev->dev); if (!desc) @@ -125,8 +124,7 @@ static int qcom_pdc_reset_probe(struct platform_device *pdev) return -ENOMEM; data->desc = desc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From ac53e621d8024848ad8ab16e56aee763eeabe233 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:09 +0800 Subject: [PATCH 1669/7721] reset: simple: Convert to devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704120211.38122-5-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-simple.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index 7ea5adbf2097..818cabcc9fb7 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -169,8 +169,7 @@ static int reset_simple_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - membase = devm_ioremap_resource(dev, res); + membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(membase)) return PTR_ERR(membase); From 5d587019fccaabf84103b9e83a4acc4d6937ec87 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:10 +0800 Subject: [PATCH 1670/7721] reset: sunplus: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704120211.38122-6-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-sunplus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c index 2f23ecaa7b98..df58decab64d 100644 --- a/drivers/reset/reset-sunplus.c +++ b/drivers/reset/reset-sunplus.c @@ -176,8 +176,7 @@ static int sp_reset_probe(struct platform_device *pdev) if (!reset) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reset->base = devm_ioremap_resource(dev, res); + reset->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(reset->base)) return PTR_ERR(reset->base); From c645481229689c62ba6e36f1708dc06d9cfc3f60 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 20:02:11 +0800 Subject: [PATCH 1671/7721] reset: uniphier-glue: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704120211.38122-7-frank.li@vivo.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-uniphier-glue.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c index 97b3ddcdade1..5f9f2f7994c0 100644 --- a/drivers/reset/reset-uniphier-glue.c +++ b/drivers/reset/reset-uniphier-glue.c @@ -58,8 +58,7 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) priv->data->nrsts > MAX_RSTS)) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->rdata.membase = devm_ioremap_resource(dev, res); + priv->rdata.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->rdata.membase)) return PTR_ERR(priv->rdata.membase); From 0c0ea61c9b3a9e4df9cf029971f973cb12ccfef9 Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Thu, 14 Sep 2023 14:40:16 +0800 Subject: [PATCH 1672/7721] dt-bindings: reset: Add compatible and DT bindings for Amlogic C3 Reset Controller Add new compatible and DT bindings for Amlogic C3 Reset Controller Signed-off-by: Zelong Dong Acked-by: Krzysztof Kozlowski Reviewed-by: Dmitry Rokosov Reviewed-by: Rob Herring Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20230914064018.18790-2-zelong.dong@amlogic.com Signed-off-by: Philipp Zabel --- .../bindings/reset/amlogic,meson-reset.yaml | 1 + include/dt-bindings/reset/amlogic,c3-reset.h | 119 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,c3-reset.h diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml index d3fdee89d4f8..f0c6c0df0ce3 100644 --- a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml +++ b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml @@ -18,6 +18,7 @@ properties: - amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs - amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs - amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs + - amlogic,c3-reset # Reset Controller on C3 and compatible SoCs reg: maxItems: 1 diff --git a/include/dt-bindings/reset/amlogic,c3-reset.h b/include/dt-bindings/reset/amlogic,c3-reset.h new file mode 100644 index 000000000000..d9127863f603 --- /dev/null +++ b/include/dt-bindings/reset/amlogic,c3-reset.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2023 Amlogic, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_AMLOGIC_C3_RESET_H +#define _DT_BINDINGS_AMLOGIC_C3_RESET_H + +/* RESET0 */ +/* 0-3 */ +#define RESET_USBCTRL 4 +/* 5-7 */ +#define RESET_USBPHY20 8 +/* 9 */ +#define RESET_USB2DRD 10 +#define RESET_MIPI_DSI_HOST 11 +#define RESET_MIPI_DSI_PHY 12 +/* 13-20 */ +#define RESET_GE2D 21 +#define RESET_DWAP 22 +/* 23-31 */ + +/* RESET1 */ +#define RESET_AUDIO 32 +/* 33-34 */ +#define RESET_DDRAPB 35 +#define RESET_DDR 36 +#define RESET_DOS_CAPB3 37 +#define RESET_DOS 38 +/* 39-46 */ +#define RESET_NNA 47 +#define RESET_ETHERNET 48 +#define RESET_ISP 49 +#define RESET_VC9000E_APB 50 +#define RESET_VC9000E_A 51 +/* 52 */ +#define RESET_VC9000E_CORE 53 +/* 54-63 */ + +/* RESET2 */ +#define RESET_ABUS_ARB 64 +#define RESET_IRCTRL 65 +/* 66 */ +#define RESET_TEMP_PII 67 +/* 68-72 */ +#define RESET_SPICC_0 73 +#define RESET_SPICC_1 74 +#define RESET_RSA 75 + +/* 76-79 */ +#define RESET_MSR_CLK 80 +#define RESET_SPIFC 81 +#define RESET_SAR_ADC 82 +/* 83-87 */ +#define RESET_ACODEC 88 +/* 89-90 */ +#define RESET_WATCHDOG 91 +/* 92-95 */ + +/* RESET3 */ +#define RESET_ISP_NIC_GPV 96 +#define RESET_ISP_NIC_MAIN 97 +#define RESET_ISP_NIC_VCLK 98 +#define RESET_ISP_NIC_VOUT 99 +#define RESET_ISP_NIC_ALL 100 +#define RESET_VOUT 101 +#define RESET_VOUT_VENC 102 +/* 103 */ +#define RESET_CVE_NIC_GPV 104 +#define RESET_CVE_NIC_MAIN 105 +#define RESET_CVE_NIC_GE2D 106 +#define RESET_CVE_NIC_DW 106 +#define RESET_CVE_NIC_CVE 108 +#define RESET_CVE_NIC_ALL 109 +#define RESET_CVE 110 +/* 112-127 */ + +/* RESET4 */ +#define RESET_RTC 128 +#define RESET_PWM_AB 129 +#define RESET_PWM_CD 130 +#define RESET_PWM_EF 131 +#define RESET_PWM_GH 132 +#define RESET_PWM_IJ 133 +#define RESET_PWM_KL 134 +#define RESET_PWM_MN 135 +/* 136-137 */ +#define RESET_UART_A 138 +#define RESET_UART_B 139 +#define RESET_UART_C 140 +#define RESET_UART_D 141 +#define RESET_UART_E 142 +#define RESET_UART_F 143 +#define RESET_I2C_S_A 144 +#define RESET_I2C_M_A 145 +#define RESET_I2C_M_B 146 +#define RESET_I2C_M_C 147 +#define RESET_I2C_M_D 148 +/* 149-151 */ +#define RESET_SD_EMMC_A 152 +#define RESET_SD_EMMC_B 153 +#define RESET_SD_EMMC_C 154 + +/* RESET5 */ +/* 160-172 */ +#define RESET_BRG_NIC_NNA 173 +#define RESET_BRG_MUX_NIC_MAIN 174 +#define RESET_BRG_AO_NIC_ALL 175 +/* 176-183 */ +#define RESET_BRG_NIC_VAPB 184 +#define RESET_BRG_NIC_SDIO_B 185 +#define RESET_BRG_NIC_SDIO_A 186 +#define RESET_BRG_NIC_EMMC 187 +#define RESET_BRG_NIC_DSU 188 +#define RESET_BRG_NIC_SYSCLK 189 +#define RESET_BRG_NIC_MAIN 190 +#define RESET_BRG_NIC_ALL 191 + +#endif From 41df5d7d5e99fa9b15e9f7fec7f9a7f092a1440e Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Thu, 14 Sep 2023 14:40:17 +0800 Subject: [PATCH 1673/7721] reset: reset-meson: add support for Amlogic C3 SoC Reset Controller Add a new compatible string to support for the reset controller on the C3 SoC. The count and offset for C3 Soc RESET registers are same as S4 Soc. Signed-off-by: Zelong Dong Reviewed-by: Dmitry Rokosov Reviewed-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20230914064018.18790-3-zelong.dong@amlogic.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index a7af051b17fb..f78be97898bc 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -108,6 +108,7 @@ static const struct of_device_id meson_reset_dt_ids[] = { { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param}, { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param}, { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param}, + { .compatible = "amlogic,c3-reset", .data = &meson_s4_param}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); From c1d884118f9b1544b39744f2c148fc87050488c1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 15 Nov 2023 14:58:48 -0600 Subject: [PATCH 1674/7721] reset: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Reviewed-by: Patrice Chotard Link: https://lore.kernel.org/r/20231115205848.3732609-1-robh@kernel.org Signed-off-by: Philipp Zabel --- drivers/reset/reset-npcm.c | 5 ++--- drivers/reset/sti/reset-syscfg.c | 11 ++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c index f6c4f854f2be..8935ef95a2d1 100644 --- a/drivers/reset/reset-npcm.c +++ b/drivers/reset/reset-npcm.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -351,8 +351,7 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) } } - rc->info = (const struct npcm_reset_info *) - of_match_device(dev->driver->of_match_table, dev)->data; + rc->info = device_get_match_data(dev); switch (rc->info->bmc_id) { case BMC_NPCM7XX: npcm_usb_reset_npcm7xx(rc); diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c index c1ba04f6f155..2324060b747c 100644 --- a/drivers/reset/sti/reset-syscfg.c +++ b/drivers/reset/sti/reset-syscfg.c @@ -7,10 +7,11 @@ */ #include #include +#include #include #include #include -#include +#include #include #include @@ -183,14 +184,14 @@ static int syscfg_reset_controller_register(struct device *dev, int syscfg_reset_probe(struct platform_device *pdev) { struct device *dev = pdev ? &pdev->dev : NULL; - const struct of_device_id *match; + const void *data; if (!dev || !dev->driver) return -ENODEV; - match = of_match_device(dev->driver->of_match_table, dev); - if (!match || !match->data) + data = device_get_match_data(&pdev->dev); + if (!data) return -EINVAL; - return syscfg_reset_controller_register(dev, match->data); + return syscfg_reset_controller_register(dev, data); } From 1240070d4e045e37823df46314fcaeea3dfe623c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 15 Nov 2023 21:18:29 +0000 Subject: [PATCH 1675/7721] dt-bindings: reset: renesas,rzg2l-usbphy-ctrl: Document RZ/Five SoC The USBPHY Control Device on the RZ/Five SoC is identical to one found on the RZ/G2UL SoC. "renesas,r9a07g043-usbphy-ctrl" compatible string will be used on the RZ/Five SoC so to make this clear and to keep this file consistent, update the comment to include RZ/Five SoC. No driver changes are required as generic compatible string "renesas,rzg2l-usbphy-ctrl" will be used as a fallback on RZ/Five SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231115211829.32542-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml b/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml index 731b8ce01525..03c18611e42d 100644 --- a/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml +++ b/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml @@ -17,7 +17,7 @@ properties: compatible: items: - enum: - - renesas,r9a07g043-usbphy-ctrl # RZ/G2UL + - renesas,r9a07g043-usbphy-ctrl # RZ/G2UL and RZ/Five - renesas,r9a07g044-usbphy-ctrl # RZ/G2{L,LC} - renesas,r9a07g054-usbphy-ctrl # RZ/V2L - const: renesas,rzg2l-usbphy-ctrl From e530fc87259b02d4a12ef0db7cf736e5b54687d2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 15:43:52 -0700 Subject: [PATCH 1676/7721] dt-bindings: reset: qcom: drop unneeded quotes Drop unneeded quotes over simple string values to fix a soon to be enabled yamllint warning: [error] string value is redundantly quoted with any quotes (quoted-strings) Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231122224352.2808435-1-robh@kernel.org Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/qcom,aoss-reset.yaml | 10 +++++----- .../devicetree/bindings/reset/qcom,pdc-global.yaml | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml index d92e2b3cc83f..24beb712b56d 100644 --- a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml +++ b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml @@ -18,17 +18,17 @@ properties: oneOf: - description: on SC7180 SoCs the following compatibles must be specified items: - - const: "qcom,sc7180-aoss-cc" - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sc7180-aoss-cc + - const: qcom,sdm845-aoss-cc - description: on SC7280 SoCs the following compatibles must be specified items: - - const: "qcom,sc7280-aoss-cc" - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sc7280-aoss-cc + - const: qcom,sdm845-aoss-cc - description: on SDM845 SoCs the following compatibles must be specified items: - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sdm845-aoss-cc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml b/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml index ca5d79332189..f514363aa474 100644 --- a/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml +++ b/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml @@ -18,16 +18,16 @@ properties: oneOf: - description: on SC7180 SoCs the following compatibles must be specified items: - - const: "qcom,sc7180-pdc-global" - - const: "qcom,sdm845-pdc-global" + - const: qcom,sc7180-pdc-global + - const: qcom,sdm845-pdc-global - description: on SC7280 SoCs the following compatibles must be specified items: - - const: "qcom,sc7280-pdc-global" + - const: qcom,sc7280-pdc-global - description: on SDM845 SoCs the following compatibles must be specified items: - - const: "qcom,sdm845-pdc-global" + - const: qcom,sdm845-pdc-global reg: maxItems: 1 From e4916e791fb637a87c0ad5a0cd7ee824b817b27f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 15:44:04 -0700 Subject: [PATCH 1677/7721] dt-bindings: reset: imx-src: Simplify compatible schema and drop unneeded quotes The compatible schema can be simplified to a single enum for all the cases with "fsl,imx51-src" fallback compatible. In addition, the compatible strings are redundantly quoted. Drop unneeded quotes over simple string values to fix a soon to be enabled yamllint warning: [error] string value is redundantly quoted with any quotes (quoted-strings) Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231122224404.2808838-1-robh@kernel.org Signed-off-by: Philipp Zabel --- .../bindings/reset/fsl,imx-src.yaml | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml index b11ac533f914..f5ec1d54aa51 100644 --- a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml +++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml @@ -28,28 +28,17 @@ description: | properties: compatible: oneOf: - - const: "fsl,imx51-src" + - const: fsl,imx51-src - items: - - const: "fsl,imx50-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx53-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6q-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sx-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sl-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6ul-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sll-src" - - const: "fsl,imx51-src" + - enum: + - fsl,imx50-src + - fsl,imx53-src + - fsl,imx6q-src + - fsl,imx6sx-src + - fsl,imx6sl-src + - fsl,imx6ul-src + - fsl,imx6sll-src + - const: fsl,imx51-src reg: maxItems: 1 From 58bfaaac03284d82a55a724bfe2d97e19f3a11d0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 27 Nov 2023 20:37:15 +0100 Subject: [PATCH 1678/7721] gpio: sysfs: fix forward declaration of struct gpio_device The forward declaration for struct gpio_device should be provided for both branches of the #ifdef. Fixes: 08a149c40bdb ("gpiolib: Clean up headers") Signed-off-by: Bartosz Golaszewski Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib-sysfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.h b/drivers/gpio/gpiolib-sysfs.h index 0f213bdb4732..b794b396d6a5 100644 --- a/drivers/gpio/gpiolib-sysfs.h +++ b/drivers/gpio/gpiolib-sysfs.h @@ -3,10 +3,10 @@ #ifndef GPIOLIB_SYSFS_H #define GPIOLIB_SYSFS_H -#ifdef CONFIG_GPIO_SYSFS - struct gpio_device; +#ifdef CONFIG_GPIO_SYSFS + int gpiochip_sysfs_register(struct gpio_device *gdev); void gpiochip_sysfs_unregister(struct gpio_device *gdev); From 7192ad2adde8213ad7c7f3b1ff974cccebae4d60 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 28 Nov 2023 09:52:48 -0700 Subject: [PATCH 1679/7721] arm64: vdso32: Define BUILD_VDSO32_64 to correct prototypes After commit 42874e4eb35b ("arch: vdso: consolidate gettime prototypes"), there are a couple of errors when building the 32-bit compat vDSO for arm64: arch/arm64/kernel/vdso32/vgettimeofday.c:10:5: error: conflicting types for '__vdso_clock_gettime'; have 'int(clockid_t, struct old_timespec32 *)' {aka 'int(int, struct old_timespec32 *)'} 10 | int __vdso_clock_gettime(clockid_t clock, | ^~~~~~~~~~~~~~~~~~~~ In file included from arch/arm64/kernel/vdso32/vgettimeofday.c:8: include/vdso/gettime.h:16:5: note: previous declaration of '__vdso_clock_gettime' with type 'int(clockid_t, struct __kernel_timespec *)' {aka 'int(int, struct __kernel_timespec *)'} 16 | int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); | ^~~~~~~~~~~~~~~~~~~~ arch/arm64/kernel/vdso32/vgettimeofday.c:28:5: error: conflicting types for '__vdso_clock_getres'; have 'int(clockid_t, struct old_timespec32 *)' {aka 'int(int, struct old_timespec32 *)'} 28 | int __vdso_clock_getres(clockid_t clock_id, | ^~~~~~~~~~~~~~~~~~~ include/vdso/gettime.h:15:5: note: previous declaration of '__vdso_clock_getres' with type 'int(clockid_t, struct __kernel_timespec *)' {aka 'int(int, struct __kernel_timespec *)'} 15 | int __vdso_clock_getres(clockid_t clock, struct __kernel_timespec *res); | ^~~~~~~~~~~~~~~~~~~ The type of the second parameter in __vdso_clock_getres() and __vdso_clock_gettime() changes based on whether compiling for 32-bit vs. 64-bit, which is controlled by CONFIG_64BIT or the preprocessor macro BUILD_VDSO32_64, which denotes a 32-bit vDSO is being built for a 64-bit architecture. Since this situation is the latter case, define BUILD_VDSO32_64 before the inclusion of include/vdso/gettime.h to clear up the warning Fixes: 42874e4eb35b ("arch: vdso: consolidate gettime prototypes") Reported-by: Naresh Kamboju Closes: https://lore.kernel.org/CA+G9fYtV6X=c3JVTTAX89_=wc+uqLpzggnsbGSx-98m_5yd5yw@mail.gmail.com/ Reported-by: Mark Brown Closes: https://lore.kernel.org/ZWCRWArzbTYUjvon@finisterre.sirena.org.uk/ Signed-off-by: Nathan Chancellor Signed-off-by: Arnd Bergmann --- arch/arm64/kernel/vdso32/vgettimeofday.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index e23c7f4ef26b..29b4d8f61e39 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 ARM Limited * */ +#define BUILD_VDSO32_64 #include int __vdso_clock_gettime(clockid_t clock, From ce0ca865822637a91c03b1791ef02ff57c034a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:31 +0100 Subject: [PATCH 1680/7721] bus: hisi_lpc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/hisi_lpc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index cdc4e38c113e..09340adbacc2 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -657,7 +657,7 @@ static int hisi_lpc_probe(struct platform_device *pdev) return ret; } -static int hisi_lpc_remove(struct platform_device *pdev) +static void hisi_lpc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev); @@ -669,8 +669,6 @@ static int hisi_lpc_remove(struct platform_device *pdev) of_platform_depopulate(dev); logic_pio_unregister_range(range); - - return 0; } static const struct of_device_id hisi_lpc_of_match[] = { @@ -691,6 +689,6 @@ static struct platform_driver hisi_lpc_driver = { .acpi_match_table = hisi_lpc_acpi_match, }, .probe = hisi_lpc_probe, - .remove = hisi_lpc_remove, + .remove_new = hisi_lpc_remove, }; builtin_platform_driver(hisi_lpc_driver); From 854f89a5b56354ba4135e0e1f0e57ab2caee59ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:32 +0100 Subject: [PATCH 1681/7721] bus: omap-ocp2scp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/omap-ocp2scp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index e02d0656242b..7d7479ba0a75 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -84,12 +84,10 @@ static int omap_ocp2scp_probe(struct platform_device *pdev) return ret; } -static int omap_ocp2scp_remove(struct platform_device *pdev) +static void omap_ocp2scp_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); - - return 0; } #ifdef CONFIG_OF @@ -103,7 +101,7 @@ MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); static struct platform_driver omap_ocp2scp_driver = { .probe = omap_ocp2scp_probe, - .remove = omap_ocp2scp_remove, + .remove_new = omap_ocp2scp_remove, .driver = { .name = "omap-ocp2scp", .of_match_table = of_match_ptr(omap_ocp2scp_id_table), From 8c7d255dd2b4b246dceaf830f4f4ffd49f43f67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:33 +0100 Subject: [PATCH 1682/7721] bus: omap_l3_smx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Tony Lindgren Link: https://lore.kernel.org/r/20231109202830.4124591-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/omap_l3_smx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index 31774648be9d..ee6d29925e4d 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -261,7 +261,7 @@ static int omap3_l3_probe(struct platform_device *pdev) return ret; } -static int omap3_l3_remove(struct platform_device *pdev) +static void omap3_l3_remove(struct platform_device *pdev) { struct omap3_l3 *l3 = platform_get_drvdata(pdev); @@ -269,13 +269,11 @@ static int omap3_l3_remove(struct platform_device *pdev) free_irq(l3->debug_irq, l3); iounmap(l3->rt); kfree(l3); - - return 0; } static struct platform_driver omap3_l3_driver = { .probe = omap3_l3_probe, - .remove = omap3_l3_remove, + .remove_new = omap3_l3_remove, .driver = { .name = "omap_l3_smx", .of_match_table = of_match_ptr(omap3_l3_match), From ea7964a660aee352f6dedaea28e1eb05c8b51efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:34 +0100 Subject: [PATCH 1683/7721] bus: qcom-ssc-block-bus: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/qcom-ssc-block-bus.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c index 3fef18a43c01..5931974a21fa 100644 --- a/drivers/bus/qcom-ssc-block-bus.c +++ b/drivers/bus/qcom-ssc-block-bus.c @@ -350,7 +350,7 @@ static int qcom_ssc_block_bus_probe(struct platform_device *pdev) return 0; } -static int qcom_ssc_block_bus_remove(struct platform_device *pdev) +static void qcom_ssc_block_bus_remove(struct platform_device *pdev) { struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev); @@ -363,8 +363,6 @@ static int qcom_ssc_block_bus_remove(struct platform_device *pdev) qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds); pm_runtime_disable(&pdev->dev); pm_clk_destroy(&pdev->dev); - - return 0; } static const struct of_device_id qcom_ssc_block_bus_of_match[] = { @@ -375,7 +373,7 @@ MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match); static struct platform_driver qcom_ssc_block_bus_driver = { .probe = qcom_ssc_block_bus_probe, - .remove = qcom_ssc_block_bus_remove, + .remove_new = qcom_ssc_block_bus_remove, .driver = { .name = "qcom-ssc-block-bus", .of_match_table = qcom_ssc_block_bus_of_match, From f52dfffbb6d40e6d97ef750066b50b75281a24d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:35 +0100 Subject: [PATCH 1684/7721] bus: simple-pm-bus: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231109202830.4124591-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/simple-pm-bus.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index aafcc481de91..50870c827889 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -74,17 +74,16 @@ static int simple_pm_bus_probe(struct platform_device *pdev) return 0; } -static int simple_pm_bus_remove(struct platform_device *pdev) +static void simple_pm_bus_remove(struct platform_device *pdev) { const void *data = of_device_get_match_data(&pdev->dev); if (pdev->driver_override || data) - return 0; + return; dev_dbg(&pdev->dev, "%s\n", __func__); pm_runtime_disable(&pdev->dev); - return 0; } static int simple_pm_bus_runtime_suspend(struct device *dev) @@ -129,7 +128,7 @@ MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match); static struct platform_driver simple_pm_bus_driver = { .probe = simple_pm_bus_probe, - .remove = simple_pm_bus_remove, + .remove_new = simple_pm_bus_remove, .driver = { .name = "simple-pm-bus", .of_match_table = simple_pm_bus_of_match, From 8b763a224970896d6a252dc9bdf8c17dfeb83921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:36 +0100 Subject: [PATCH 1685/7721] bus: sun50i-de2: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Jernej Skrabec Reviewed-by: Andre Przywara Link: https://lore.kernel.org/r/20231109202830.4124591-7-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/sun50i-de2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c index 414f29cdedf0..3339311ce068 100644 --- a/drivers/bus/sun50i-de2.c +++ b/drivers/bus/sun50i-de2.c @@ -24,10 +24,9 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev) return 0; } -static int sun50i_de2_bus_remove(struct platform_device *pdev) +static void sun50i_de2_bus_remove(struct platform_device *pdev) { sunxi_sram_release(&pdev->dev); - return 0; } static const struct of_device_id sun50i_de2_bus_of_match[] = { @@ -37,7 +36,7 @@ static const struct of_device_id sun50i_de2_bus_of_match[] = { static struct platform_driver sun50i_de2_bus_driver = { .probe = sun50i_de2_bus_probe, - .remove = sun50i_de2_bus_remove, + .remove_new = sun50i_de2_bus_remove, .driver = { .name = "sun50i-de2-bus", .of_match_table = sun50i_de2_bus_of_match, From 88807ae1f9b3a1cd7841d75afd59a4845201584b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:37 +0100 Subject: [PATCH 1686/7721] bus: sunxi-rsb: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Jernej Skrabec Reviewed-by: Andre Przywara Link: https://lore.kernel.org/r/20231109202830.4124591-8-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/sunxi-rsb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index db0ed4e5d315..fd3e9d82340a 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -817,15 +817,13 @@ static int sunxi_rsb_probe(struct platform_device *pdev) return 0; } -static int sunxi_rsb_remove(struct platform_device *pdev) +static void sunxi_rsb_remove(struct platform_device *pdev) { struct sunxi_rsb *rsb = platform_get_drvdata(pdev); device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); pm_runtime_disable(&pdev->dev); sunxi_rsb_hw_exit(rsb); - - return 0; } static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = { @@ -842,7 +840,7 @@ MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table); static struct platform_driver sunxi_rsb_driver = { .probe = sunxi_rsb_probe, - .remove = sunxi_rsb_remove, + .remove_new = sunxi_rsb_remove, .driver = { .name = RSB_CTRL_NAME, .of_match_table = sunxi_rsb_of_match_table, From f54ba5ef85eb1af777335170c19e5b5900f52af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:38 +0100 Subject: [PATCH 1687/7721] bus: tegra-aconnect: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-9-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/tegra-aconnect.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index ac58142301f4..de80008bff92 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c @@ -53,11 +53,9 @@ static int tegra_aconnect_probe(struct platform_device *pdev) return 0; } -static int tegra_aconnect_remove(struct platform_device *pdev) +static void tegra_aconnect_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static int tegra_aconnect_runtime_resume(struct device *dev) @@ -106,7 +104,7 @@ MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match); static struct platform_driver tegra_aconnect_driver = { .probe = tegra_aconnect_probe, - .remove = tegra_aconnect_remove, + .remove_new = tegra_aconnect_remove, .driver = { .name = "tegra-aconnect", .of_match_table = tegra_aconnect_of_match, From 812c0c38a85ee66f41a6d9cf7499c08f904fce26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:39 +0100 Subject: [PATCH 1688/7721] bus: tegra-gmi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-10-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/tegra-gmi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index 59919e99f7cc..f5d6414df9f2 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -258,14 +258,12 @@ static int tegra_gmi_probe(struct platform_device *pdev) return 0; } -static int tegra_gmi_remove(struct platform_device *pdev) +static void tegra_gmi_remove(struct platform_device *pdev) { struct tegra_gmi *gmi = platform_get_drvdata(pdev); of_platform_depopulate(gmi->dev); tegra_gmi_disable(gmi); - - return 0; } static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev) @@ -305,7 +303,7 @@ MODULE_DEVICE_TABLE(of, tegra_gmi_id_table); static struct platform_driver tegra_gmi_driver = { .probe = tegra_gmi_probe, - .remove = tegra_gmi_remove, + .remove_new = tegra_gmi_remove, .driver = { .name = "tegra-gmi", .of_match_table = tegra_gmi_id_table, From 2754f6157d65c92185a2c18be103f2ca85f590c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:40 +0100 Subject: [PATCH 1689/7721] bus: ti-pwmss: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-11-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/ti-pwmss.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/bus/ti-pwmss.c b/drivers/bus/ti-pwmss.c index 480a4de76cd4..4969c556e752 100644 --- a/drivers/bus/ti-pwmss.c +++ b/drivers/bus/ti-pwmss.c @@ -33,10 +33,9 @@ static int pwmss_probe(struct platform_device *pdev) return ret; } -static int pwmss_remove(struct platform_device *pdev) +static void pwmss_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static struct platform_driver pwmss_driver = { @@ -45,7 +44,7 @@ static struct platform_driver pwmss_driver = { .of_match_table = pwmss_of_match, }, .probe = pwmss_probe, - .remove = pwmss_remove, + .remove_new = pwmss_remove, }; module_platform_driver(pwmss_driver); From 999f052e9ccc0cbfbaa44545774ee944a8a2a9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:41 +0100 Subject: [PATCH 1690/7721] bus: ti-sysc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Tony Lindgren Link: https://lore.kernel.org/r/20231109202830.4124591-12-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/ti-sysc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index d57bc066dce6..490841dbe0d8 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -3387,7 +3387,7 @@ static int sysc_probe(struct platform_device *pdev) return error; } -static int sysc_remove(struct platform_device *pdev) +static void sysc_remove(struct platform_device *pdev) { struct sysc *ddata = platform_get_drvdata(pdev); int error; @@ -3412,8 +3412,6 @@ static int sysc_remove(struct platform_device *pdev) unprepare: sysc_unprepare(ddata); - - return 0; } static const struct of_device_id sysc_match[] = { @@ -3439,7 +3437,7 @@ MODULE_DEVICE_TABLE(of, sysc_match); static struct platform_driver sysc_driver = { .probe = sysc_probe, - .remove = sysc_remove, + .remove_new = sysc_remove, .driver = { .name = "ti-sysc", .of_match_table = sysc_match, From fc540426f7baa0c7d4b477e80435d075659092a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 9 Nov 2023 21:28:42 +0100 Subject: [PATCH 1691/7721] bus: ts-nbus: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231109202830.4124591-13-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/bus/ts-nbus.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 38c886dc2ed6..4fa932cb0915 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -331,7 +331,7 @@ static int ts_nbus_probe(struct platform_device *pdev) return 0; } -static int ts_nbus_remove(struct platform_device *pdev) +static void ts_nbus_remove(struct platform_device *pdev) { struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev); @@ -339,8 +339,6 @@ static int ts_nbus_remove(struct platform_device *pdev) mutex_lock(&ts_nbus->lock); pwm_disable(ts_nbus->pwm); mutex_unlock(&ts_nbus->lock); - - return 0; } static const struct of_device_id ts_nbus_of_match[] = { @@ -351,7 +349,7 @@ MODULE_DEVICE_TABLE(of, ts_nbus_of_match); static struct platform_driver ts_nbus_driver = { .probe = ts_nbus_probe, - .remove = ts_nbus_remove, + .remove_new = ts_nbus_remove, .driver = { .name = "ts_nbus", .of_match_table = ts_nbus_of_match, From 15da990f8dd7e9d0e1fd0275730f6fed6f6a8a57 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Mon, 27 Nov 2023 19:58:07 -0800 Subject: [PATCH 1692/7721] MAINTAINERS: SOFTWARE RAID: Add Yu Kuai as Reviewer Add Yu Kuai as reviewer for md/raid subsystem. Signed-off-by: Song Liu Acked-by: Yu Kuai Link: https://lore.kernel.org/r/20231128035807.3191738-1-song@kernel.org --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 012df8ccf34e..a800acf46e6a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20106,6 +20106,7 @@ F: include/linux/property.h SOFTWARE RAID (Multiple Disks) SUPPORT M: Song Liu +R: Yu Kuai L: linux-raid@vger.kernel.org S: Supported Q: https://patchwork.kernel.org/project/linux-raid/list/ From 3cc808e3239cf566b3d3b15cf2beee066b60f241 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Tue, 28 Nov 2023 17:35:07 +0000 Subject: [PATCH 1693/7721] drm/imagination: Numerous documentation fixes. Some reported by Stephen Rothwell. The rest were found by running the kernel-doc build script. Some indentation fixes. Reported-by: Stephen Rothwell Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311241526.Y2WZeUau-lkp@intel.com/ Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231128173507.95119-1-donald.robson@imgtec.com --- Documentation/gpu/imagination/index.rst | 2 +- Documentation/gpu/imagination/uapi.rst | 5 +---- drivers/gpu/drm/imagination/pvr_cccb.h | 1 + drivers/gpu/drm/imagination/pvr_device.h | 25 ++++++++++++++++------- drivers/gpu/drm/imagination/pvr_fw.h | 3 ++- drivers/gpu/drm/imagination/pvr_fw_info.h | 8 ++++---- drivers/gpu/drm/imagination/pvr_hwrt.h | 1 + drivers/gpu/drm/imagination/pvr_job.c | 4 +--- drivers/gpu/drm/imagination/pvr_mmu.c | 3 ++- drivers/gpu/drm/imagination/pvr_queue.h | 4 ++-- drivers/gpu/drm/imagination/pvr_vm.c | 2 +- include/uapi/drm/pvr_drm.h | 10 ++++----- 12 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Documentation/gpu/imagination/index.rst b/Documentation/gpu/imagination/index.rst index dc9579e758c3..0c1e247cea41 100644 --- a/Documentation/gpu/imagination/index.rst +++ b/Documentation/gpu/imagination/index.rst @@ -3,7 +3,7 @@ drm/imagination PowerVR Graphics Driver ======================================= .. kernel-doc:: drivers/gpu/drm/imagination/pvr_drv.c - :doc: PowerVR Graphics Driver + :doc: PowerVR (Series 6 and later) and IMG Graphics Driver Contents ======== diff --git a/Documentation/gpu/imagination/uapi.rst b/Documentation/gpu/imagination/uapi.rst index 2227ea7e6222..7502413d0a93 100644 --- a/Documentation/gpu/imagination/uapi.rst +++ b/Documentation/gpu/imagination/uapi.rst @@ -45,9 +45,6 @@ DEV_QUERY drm_pvr_heap drm_pvr_dev_query_heap_info -.. kernel-doc:: include/uapi/drm/pvr_drm.h - :doc: Flags for DRM_PVR_DEV_QUERY_HEAP_INFO_GET. - .. kernel-doc:: include/uapi/drm/pvr_drm.h :identifiers: drm_pvr_static_data_area_usage drm_pvr_static_data_area @@ -121,7 +118,7 @@ CREATE_FREE_LIST and DESTROY_FREE_LIST :identifiers: drm_pvr_ioctl_destroy_free_list_args CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET --------------------------------------- +-------------------------------------------- .. kernel-doc:: include/uapi/drm/pvr_drm.h :doc: PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces diff --git a/drivers/gpu/drm/imagination/pvr_cccb.h b/drivers/gpu/drm/imagination/pvr_cccb.h index f35b3d4c9575..943fe8f2c963 100644 --- a/drivers/gpu/drm/imagination/pvr_cccb.h +++ b/drivers/gpu/drm/imagination/pvr_cccb.h @@ -86,6 +86,7 @@ pvr_cccb_get_size_of_cmd_with_hdr(u32 cmd_size) /** * pvr_cccb_cmdseq_can_fit() - Check if a command sequence can fit in the CCCB. + * @pvr_cccb: Target Client CCB. * @size: Command sequence size. * * Returns: diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h index e07655fc65e8..2ca7e535799f 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -203,17 +203,29 @@ struct pvr_device { struct mutex lock; } queues; + /** + * @watchdog: Watchdog for communications with firmware. + */ struct { /** @work: Work item for watchdog callback. */ struct delayed_work work; - /** @old_kccb_cmds_executed: KCCB command execution count at last watchdog poll. */ + /** + * @old_kccb_cmds_executed: KCCB command execution count at last + * watchdog poll. + */ u32 old_kccb_cmds_executed; - /** @kccb_stall_count: Number of watchdog polls KCCB has been stalled for. */ + /** + * @kccb_stall_count: Number of watchdog polls KCCB has been + * stalled for. + */ u32 kccb_stall_count; } watchdog; + /** + * @kccb: Circular buffer for communications with firmware. + */ struct { /** @ccb: Kernel CCB. */ struct pvr_ccb ccb; @@ -225,8 +237,8 @@ struct pvr_device { struct pvr_fw_object *rtn_obj; /** - * @rtn: Pointer to CPU mapping of KCCB return slots. Must be accessed by - * READ_ONCE()/WRITE_ONCE(). + * @rtn: Pointer to CPU mapping of KCCB return slots. Must be + * accessed by READ_ONCE()/WRITE_ONCE(). */ u32 *rtn; @@ -293,14 +305,13 @@ struct pvr_file { /** * @pvr_dev: A reference to the powervr-specific wrapper for the - * associated device. Saves on repeated calls to - * to_pvr_device(). + * associated device. Saves on repeated calls to to_pvr_device(). */ struct pvr_device *pvr_dev; /** * @ctx_handles: Array of contexts belonging to this file. Array members - * are of type "struct pvr_context *". + * are of type "struct pvr_context *". * * This array is used to allocate handles returned to userspace. */ diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h index 5cd3ef08d82b..b7966bd574a9 100644 --- a/drivers/gpu/drm/imagination/pvr_fw.h +++ b/drivers/gpu/drm/imagination/pvr_fw.h @@ -481,7 +481,8 @@ pvr_fw_object_unmap_and_destroy(struct pvr_fw_object *fw_obj) } /** - * pvr_fw_get_dma_addr() - Get DMA address for given offset in firmware object + * pvr_fw_object_get_dma_addr() - Get DMA address for given offset in firmware + * object. * @fw_obj: Pointer to object to lookup address in. * @offset: Offset within object to lookup address at. * @dma_addr_out: Pointer to location to store DMA address. diff --git a/drivers/gpu/drm/imagination/pvr_fw_info.h b/drivers/gpu/drm/imagination/pvr_fw_info.h index ad5d44a3067a..c3639440610e 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_info.h +++ b/drivers/gpu/drm/imagination/pvr_fw_info.h @@ -122,13 +122,13 @@ struct pvr_fw_layout_entry { * struct pvr_fw_device_info_header - Device information header. */ struct pvr_fw_device_info_header { - /* BRN Mask size (in u64s). */ + /** @brn_mask_size: BRN mask size (in u64s). */ u64 brn_mask_size; - /* ERN Mask size (in u64s). */ + /** @ern_mask_size: ERN mask size (in u64s). */ u64 ern_mask_size; - /* Feature Mask size (in u64s). */ + /** @feature_mask_size: Feature mask size (in u64s). */ u64 feature_mask_size; - /* Feature Parameter size (in u64s). */ + /** @feature_param_size: Feature parameter size (in u64s). */ u64 feature_param_size; }; diff --git a/drivers/gpu/drm/imagination/pvr_hwrt.h b/drivers/gpu/drm/imagination/pvr_hwrt.h index 76992948d047..676070b20c3b 100644 --- a/drivers/gpu/drm/imagination/pvr_hwrt.h +++ b/drivers/gpu/drm/imagination/pvr_hwrt.h @@ -64,6 +64,7 @@ struct pvr_hwrt_dataset { /** @common_fw_obj: FW object representing common FW-side structure. */ struct pvr_fw_object *common_fw_obj; + /** @common: Common HWRT data. */ struct rogue_fwif_hwrtdata_common common; /** @data: HWRT data structures belonging to this set. */ diff --git a/drivers/gpu/drm/imagination/pvr_job.c b/drivers/gpu/drm/imagination/pvr_job.c index 9d0812710295..04139da6c04d 100644 --- a/drivers/gpu/drm/imagination/pvr_job.c +++ b/drivers/gpu/drm/imagination/pvr_job.c @@ -378,7 +378,7 @@ prepare_job_syncs(struct pvr_file *pvr_file, /** * prepare_job_syncs_for_each() - Prepare all sync objects for an array of jobs. - * @file: PowerVR file. + * @pvr_file: PowerVR file. * @job_data: Array of precreated jobs and their sync_ops. * @job_count: Number of jobs. * @signal_array: xarray to receive signal sync objects. @@ -696,8 +696,6 @@ pvr_jobs_link_geom_frag(struct pvr_job_data *job_data, u32 *job_count) * @pvr_dev: Target PowerVR device. * @pvr_file: Pointer to PowerVR file structure. * @args: Ioctl args. - * @job_count: Number of jobs in @jobs_args. On error this will be updated - * with the index into @jobs_args where the error occurred. * * This initial implementation is entirely synchronous; on return the GPU will * be idle. This will not be the case for future implementations. diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c index b71d30e5f380..c8562bfc0dcd 100644 --- a/drivers/gpu/drm/imagination/pvr_mmu.c +++ b/drivers/gpu/drm/imagination/pvr_mmu.c @@ -335,8 +335,9 @@ pvr_mmu_backing_page_fini(struct pvr_mmu_backing_page *page) /** * pvr_mmu_backing_page_sync() - Flush a MMU backing page from the CPU to the - * device. + * device. * @page: Target backing page. + * @flags: MMU flush flags. Must be one of %PVR_MMU_SYNC_LEVEL_*_FLAGS. * * .. caution:: * diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h index b5ce2c742150..e06ced69302f 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.h +++ b/drivers/gpu/drm/imagination/pvr_queue.h @@ -50,7 +50,7 @@ struct pvr_queue_cccb_fence_ctx { */ struct pvr_job *job; - /** @lock: Lock protecting access to the job object. */ + /** @job_lock: Lock protecting access to the job object. */ struct mutex job_lock; }; @@ -114,7 +114,7 @@ struct pvr_queue { } timeline_ufo; /** - * last_queued_job_scheduled_fence: The scheduled fence of the last + * @last_queued_job_scheduled_fence: The scheduled fence of the last * job queued to this queue. * * We use it to insert frag -> geom dependencies when issuing combined diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index e0d74d9a6190..2aab53594a77 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -42,7 +42,7 @@ struct pvr_vm_context { /** @mmu_ctx: The context for binding to physical memory. */ struct pvr_mmu_context *mmu_ctx; - /** @gpuva_mgr: GPUVA manager object associated with this context. */ + /** @gpuvm_mgr: GPUVM object associated with this context. */ struct drm_gpuvm gpuvm_mgr; /** @lock: Global lock on this VM. */ diff --git a/include/uapi/drm/pvr_drm.h b/include/uapi/drm/pvr_drm.h index 1834375390c4..ccf6c2112468 100644 --- a/include/uapi/drm/pvr_drm.h +++ b/include/uapi/drm/pvr_drm.h @@ -741,20 +741,18 @@ enum drm_pvr_ctx_priority { */ enum drm_pvr_ctx_type { /** - * @DRM_PVR_CTX_TYPE_RENDER: Render context. Use &struct - * drm_pvr_ioctl_create_render_context_args for context creation arguments. + * @DRM_PVR_CTX_TYPE_RENDER: Render context. */ DRM_PVR_CTX_TYPE_RENDER = 0, /** - * @DRM_PVR_CTX_TYPE_COMPUTE: Compute context. Use &struct - * drm_pvr_ioctl_create_compute_context_args for context creation arguments. + * @DRM_PVR_CTX_TYPE_COMPUTE: Compute context. */ DRM_PVR_CTX_TYPE_COMPUTE, /** - * @DRM_PVR_CTX_TYPE_TRANSFER_FRAG: Transfer context for fragment data masters. Use - * &struct drm_pvr_ioctl_create_transfer_context_args for context creation arguments. + * @DRM_PVR_CTX_TYPE_TRANSFER_FRAG: Transfer context for fragment data + * master. */ DRM_PVR_CTX_TYPE_TRANSFER_FRAG, }; From 53edb549565f55ccd0bdf43be3d66ce4c2d48b28 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 28 Nov 2023 17:25:16 +0800 Subject: [PATCH 1694/7721] f2fs: fix to avoid dirent corruption As Al reported in link[1]: f2fs_rename() ... if (old_dir != new_dir && !whiteout) f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); else f2fs_put_page(old_dir_page, 0); You want correct inumber in the ".." link. And cross-directory rename does move the source to new parent, even if you'd been asked to leave a whiteout in the old place. [1] https://lore.kernel.org/all/20231017055040.GN800259@ZenIV/ With below testcase, it may cause dirent corruption, due to it missed to call f2fs_set_link() to update ".." link to new directory. - mkdir -p dir/foo - renameat2 -w dir/foo bar [ASSERT] (__chk_dots_dentries:1421) --> Bad inode number[0x4] for '..', parent parent ino is [0x3] [FSCK] other corrupted bugs [Fail] Fixes: 7e01e7ad746b ("f2fs: support RENAME_WHITEOUT") Cc: Jan Kara Reported-by: Al Viro Signed-off-by: Chao Yu Reviewed-by: Jan Kara Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a9360ee02da1..a765db9e26c2 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1105,7 +1105,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, } if (old_dir_entry) { - if (old_dir != new_dir && !whiteout) + if (old_dir != new_dir) f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); else From 5f23ffdf17e805218e56a9796bdc67497ab11bac Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 28 Nov 2023 17:31:29 +0800 Subject: [PATCH 1695/7721] f2fs: introduce tracepoint for f2fs_rename() This patch adds tracepoints for f2fs_rename(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 16 ++++++--- include/trace/events/f2fs.h | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a765db9e26c2..ede6afb81762 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1315,21 +1315,27 @@ static int f2fs_rename2(struct mnt_idmap *idmap, if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) return -EINVAL; + trace_f2fs_rename_start(old_dir, old_dentry, new_dir, new_dentry, + flags); + err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, flags); if (err) return err; - if (flags & RENAME_EXCHANGE) { - return f2fs_cross_rename(old_dir, old_dentry, - new_dir, new_dentry); - } + if (flags & RENAME_EXCHANGE) + err = f2fs_cross_rename(old_dir, old_dentry, + new_dir, new_dentry); + else /* * VFS has already handled the new dentry existence case, * here, we just deal with "RENAME_NOREPLACE" as regular rename. */ - return f2fs_rename(idmap, old_dir, old_dentry, + err = f2fs_rename(idmap, old_dir, old_dentry, new_dir, new_dentry, flags); + + trace_f2fs_rename_end(old_dentry, new_dentry, flags, err); + return err; } static const char *f2fs_encrypted_get_link(struct dentry *dentry, diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 793f82cc1515..36d9e29ca3c5 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -866,6 +866,75 @@ TRACE_EVENT(f2fs_lookup_end, __entry->err) ); +TRACE_EVENT(f2fs_rename_start, + + TP_PROTO(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags), + + TP_ARGS(old_dir, old_dentry, new_dir, new_dentry, flags), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __string(old_name, old_dentry->d_name.name) + __field(ino_t, new_pino) + __string(new_name, new_dentry->d_name.name) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->dev = old_dir->i_sb->s_dev; + __entry->ino = old_dir->i_ino; + __assign_str(old_name, old_dentry->d_name.name); + __entry->new_pino = new_dir->i_ino; + __assign_str(new_name, new_dentry->d_name.name); + __entry->flags = flags; + ), + + TP_printk("dev = (%d,%d), old_dir = %lu, old_name: %s, " + "new_dir = %lu, new_name: %s, flags = %u", + show_dev_ino(__entry), + __get_str(old_name), + __entry->new_pino, + __get_str(new_name), + __entry->flags) +); + +TRACE_EVENT(f2fs_rename_end, + + TP_PROTO(struct dentry *old_dentry, struct dentry *new_dentry, + unsigned int flags, int ret), + + TP_ARGS(old_dentry, new_dentry, flags, ret), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __string(old_name, old_dentry->d_name.name) + __string(new_name, new_dentry->d_name.name) + __field(unsigned int, flags) + __field(int, ret) + ), + + TP_fast_assign( + __entry->dev = old_dentry->d_sb->s_dev; + __entry->ino = old_dentry->d_inode->i_ino; + __assign_str(old_name, old_dentry->d_name.name); + __assign_str(new_name, new_dentry->d_name.name); + __entry->flags = flags; + __entry->ret = ret; + ), + + TP_printk("dev = (%d,%d), ino = %lu, old_name: %s, " + "new_name: %s, flags = %u, ret = %d", + show_dev_ino(__entry), + __get_str(old_name), + __get_str(new_name), + __entry->flags, + __entry->ret) +); + TRACE_EVENT(f2fs_readdir, TP_PROTO(struct inode *dir, loff_t start_pos, loff_t end_pos, int err), From 8e9cf55ef89c775fdaaa7c6212dbb691420a4673 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 28 Nov 2023 17:31:30 +0800 Subject: [PATCH 1696/7721] f2fs: show i_mode in trace_f2fs_new_inode() This patch supports to show i_mode field in trace_f2fs_new_inode(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- include/trace/events/f2fs.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 36d9e29ca3c5..479d26eae22f 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -161,6 +161,19 @@ TRACE_DEFINE_ENUM(EX_BLOCK_AGE); { EX_READ, "Read" }, \ { EX_BLOCK_AGE, "Block Age" }) +#define show_inode_type(x) \ + __print_symbolic(x, \ + { S_IFLNK, "symbolic" }, \ + { S_IFREG, "regular" }, \ + { S_IFDIR, "directory" }, \ + { S_IFCHR, "character" }, \ + { S_IFBLK, "block" }, \ + { S_IFIFO, "fifo" }, \ + { S_IFSOCK, "sock" }) + +#define S_ALL_PERM (S_ISUID | S_ISGID | S_ISVTX | \ + S_IRWXU | S_IRWXG | S_IRWXO) + struct f2fs_sb_info; struct f2fs_io_info; struct extent_info; @@ -215,17 +228,21 @@ DECLARE_EVENT_CLASS(f2fs__inode_exit, TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) + __field(umode_t, mode) __field(int, ret) ), TP_fast_assign( __entry->dev = inode->i_sb->s_dev; __entry->ino = inode->i_ino; + __entry->mode = inode->i_mode; __entry->ret = ret; ), - TP_printk("dev = (%d,%d), ino = %lu, ret = %d", + TP_printk("dev = (%d,%d), ino = %lu, type: %s, mode = 0%o, ret = %d", show_dev_ino(__entry), + show_inode_type(__entry->mode & S_IFMT), + __entry->mode & S_ALL_PERM, __entry->ret) ); From d346fa09abff46988de9267b67b6900d9913d5a2 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 22 Nov 2023 22:47:15 +0800 Subject: [PATCH 1697/7721] f2fs: sysfs: support discard_io_aware It gives a way to enable/disable IO aware feature for background discard, so that we can tune background discard more precisely based on undiscard condition. e.g. force to disable IO aware if there are large number of discard extents, and discard IO may always be interrupted by frequent common IO. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 6 ++++++ fs/f2fs/f2fs.h | 7 +++++++ fs/f2fs/segment.c | 6 +++++- fs/f2fs/sysfs.c | 9 +++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 36c3cb547901..4f1d4e636d67 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -740,3 +740,9 @@ Description: When compress cache is on, it controls cached page If cached page percent exceed threshold, then deny caching compress page. The value should be in range of (0, 100], by default it was initialized as 20(%). + +What: /sys/fs/f2fs//discard_io_aware +Date: November 2023 +Contact: "Chao Yu" +Description: It controls to enable/disable IO aware feature for background discard. + By default, the value is 1 which indicates IO aware is on. diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9043cedfa12b..86a145be4e53 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -374,6 +374,12 @@ enum { MAX_DPOLICY, }; +enum { + DPOLICY_IO_AWARE_DISABLE, /* force to not be aware of IO */ + DPOLICY_IO_AWARE_ENABLE, /* force to be aware of IO */ + DPOLICY_IO_AWARE_MAX, +}; + struct discard_policy { int type; /* type of discard */ unsigned int min_interval; /* used for candidates exist */ @@ -406,6 +412,7 @@ struct discard_cmd_control { unsigned int discard_urgent_util; /* utilization which issue discard proactively */ unsigned int discard_granularity; /* discard granularity */ unsigned int max_ordered_discard; /* maximum discard granularity issued by lba order */ + unsigned int discard_io_aware; /* io_aware policy */ unsigned int undiscard_blks; /* # of undiscard blocks */ unsigned int next_pos; /* next discard position */ atomic_t issued_discard; /* # of issued discard */ diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f4ffd64b44b2..08e2f44a1264 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1172,7 +1172,10 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->min_interval = dcc->min_discard_issue_time; dpolicy->mid_interval = dcc->mid_discard_issue_time; dpolicy->max_interval = dcc->max_discard_issue_time; - dpolicy->io_aware = true; + if (dcc->discard_io_aware == DPOLICY_IO_AWARE_ENABLE) + dpolicy->io_aware = true; + else if (dcc->discard_io_aware == DPOLICY_IO_AWARE_DISABLE) + dpolicy->io_aware = false; dpolicy->sync = false; dpolicy->ordered = true; if (utilization(sbi) > dcc->discard_urgent_util) { @@ -2275,6 +2278,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) dcc->discard_io_aware_gran = MAX_PLIST_NUM; dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY; dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY; + dcc->discard_io_aware = DPOLICY_IO_AWARE_ENABLE; if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) dcc->discard_granularity = sbi->blocks_per_seg; else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION) diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 417fae96890f..7099ffa57299 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -516,6 +516,13 @@ static ssize_t __sbi_store(struct f2fs_attr *a, return count; } + if (!strcmp(a->attr.name, "discard_io_aware")) { + if (t >= DPOLICY_IO_AWARE_MAX) + return -EINVAL; + *ui = t; + return count; + } + if (!strcmp(a->attr.name, "migration_granularity")) { if (t == 0 || t > sbi->segs_per_sec) return -EINVAL; @@ -926,6 +933,7 @@ DCC_INFO_GENERAL_RW_ATTR(discard_io_aware_gran); DCC_INFO_GENERAL_RW_ATTR(discard_urgent_util); DCC_INFO_GENERAL_RW_ATTR(discard_granularity); DCC_INFO_GENERAL_RW_ATTR(max_ordered_discard); +DCC_INFO_GENERAL_RW_ATTR(discard_io_aware); /* NM_INFO ATTR */ NM_INFO_RW_ATTR(max_roll_forward_node_blocks, max_rf_node_blocks); @@ -1074,6 +1082,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(discard_urgent_util), ATTR_LIST(discard_granularity), ATTR_LIST(max_ordered_discard), + ATTR_LIST(discard_io_aware), ATTR_LIST(pending_discard), ATTR_LIST(gc_mode), ATTR_LIST(ipu_policy), From f92a39ae47076ea123c7980fb85e6e33313f372e Mon Sep 17 00:00:00 2001 From: Bert Karwatzki Date: Mon, 27 Nov 2023 17:09:55 +0100 Subject: [PATCH 1698/7721] drm/sched: Partial revert of "Qualify drm_sched_wakeup() by drm_sched_entity_is_ready()" Commit f3123c2590005c, in combination with the use of work queues by the GPU scheduler, leads to random lock-ups of the GUI. This is a partial revert of of commit f3123c2590005c since drm_sched_wakeup() still needs its entity argument to pass it to drm_sched_can_queue(). Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2994 Link: https://lists.freedesktop.org/archives/dri-devel/2023-November/431606.html Signed-off-by: Bert Karwatzki Link: https://patchwork.freedesktop.org/patch/msgid/20231127160955.87879-1-spasswolf@web.de Link: https://lore.kernel.org/r/36bece178ff5dc705065e53d1e5e41f6db6d87e4.camel@web.de Fixes: f3123c2590005c ("drm/sched: Qualify drm_sched_wakeup() by drm_sched_entity_is_ready()") Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 682aebe96db7..550492a7a031 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1029,9 +1029,8 @@ EXPORT_SYMBOL(drm_sched_job_cleanup); void drm_sched_wakeup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - if (drm_sched_entity_is_ready(entity)) - if (drm_sched_can_queue(sched, entity)) - drm_sched_run_job_queue(sched); + if (drm_sched_can_queue(sched, entity)) + drm_sched_run_job_queue(sched); } /** From ca41ae8f445e0bb88fa84584b451bfbf39b2e7f1 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Fri, 17 Nov 2023 13:58:29 +0530 Subject: [PATCH 1699/7721] dt-bindings: interrupt-controller: Add SDX75 PDC compatible Add device tree bindings for PDC on SDX75 SOC. Signed-off-by: Rohit Agarwal Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231117082829.609882-1-quic_rohiagar@quicinc.com Signed-off-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/qcom,pdc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index 8473afffce63..c879f0d2e07f 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -35,6 +35,7 @@ properties: - qcom,sdm845-pdc - qcom,sdx55-pdc - qcom,sdx65-pdc + - qcom,sdx75-pdc - qcom,sm4450-pdc - qcom,sm6350-pdc - qcom,sm8150-pdc From c1c647f604a55e73c6980046cc56df574402e362 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:27:36 +0200 Subject: [PATCH 1700/7721] dt-bindings: qcom,pdc: document the SM8650 Power Domain Controller Document the Power Domain Controller on the SM8650 Platform. Signed-off-by: Neil Armstrong Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231025-topic-sm8650-upstream-bindings-pdc-v1-1-42f62cc9858c@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/qcom,pdc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index c879f0d2e07f..7d8592cef1c0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -43,6 +43,7 @@ properties: - qcom,sm8350-pdc - qcom,sm8450-pdc - qcom,sm8550-pdc + - qcom,sm8650-pdc - const: qcom,pdc reg: From daa9249408fcb4985351d91f166fc0e27d255014 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 24 Nov 2023 15:36:08 +0530 Subject: [PATCH 1701/7721] dt-bindings: interrupt-controller: qcom,pdc: document pdc on X1E80100 The X1E80100 SoC includes a PDC, document it. Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124100608.29964-6-quic_sibis@quicinc.com Signed-off-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/qcom,pdc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index 7d8592cef1c0..4bdc8321904b 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -44,6 +44,7 @@ properties: - qcom,sm8450-pdc - qcom,sm8550-pdc - qcom,sm8650-pdc + - qcom,x1e80100-pdc - const: qcom,pdc reg: From 9e7f72d452477819977f047bddfbec7f66489f3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 15:44:19 -0700 Subject: [PATCH 1702/7721] dt-bindings: fsl,dpaa2-console: drop unneeded quotes Drop unneeded quotes over simple string values to fix a soon to be enabled yamllint warning: [error] string value is redundantly quoted with any quotes (quoted-strings) Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231122224419.2809361-1-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml index 8cc951feb7df..59b83ea5e05e 100644 --- a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml +++ b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml @@ -12,7 +12,7 @@ maintainers: properties: compatible: - const: "fsl,dpaa2-console" + const: fsl,dpaa2-console reg: maxItems: 1 From 67f7a63ecc712dbc307c04a1a7fbf32d1aa864df Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 15:44:32 -0700 Subject: [PATCH 1703/7721] dt-bindings: arm/calxeda: drop unneeded quotes Drop unneeded quotes over simple string values to fix a soon to be enabled yamllint warning: [error] string value is redundantly quoted with any quotes (quoted-strings) Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231122224432.2809781-1-robh@kernel.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml index a9fe01238a88..76b65ea149b6 100644 --- a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml +++ b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml @@ -16,7 +16,7 @@ maintainers: properties: compatible: - const: "calxeda,hb-sregs-l2-ecc" + const: calxeda,hb-sregs-l2-ecc reg: maxItems: 1 From 012e3208ab8d1456379d047d88d69ab7e074a520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 2 Nov 2023 17:56:57 +0100 Subject: [PATCH 1704/7721] drm/tilcdc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. There is one error path in tilcdc_pdev_remove() that potentially could yield a non-zero return code. In this case an error message describing the failure is emitted now instead of remove callback returned a non-zero value. This will be ignored. before. Otherwise there is no difference. Also note that currently tilcdc_get_external_components() doesn't return negative values. Signed-off-by: Uwe Kleine-König Signed-off-by: Jyri Sarha Link: https://patchwork.freedesktop.org/patch/msgid/20231102165640.3307820-34-u.kleine-koenig@pengutronix.de Reviewed-by: Tomi Valkeinen Tested-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 2f6eaac7f659..23bf16f596f6 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -570,19 +570,18 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) match); } -static int tilcdc_pdev_remove(struct platform_device *pdev) +static void tilcdc_pdev_remove(struct platform_device *pdev) { int ret; ret = tilcdc_get_external_components(&pdev->dev, NULL); if (ret < 0) - return ret; + dev_err(&pdev->dev, "tilcdc_get_external_components() failed (%pe)\n", + ERR_PTR(ret)); else if (ret == 0) tilcdc_fini(platform_get_drvdata(pdev)); else component_master_del(&pdev->dev, &tilcdc_comp_ops); - - return 0; } static void tilcdc_pdev_shutdown(struct platform_device *pdev) @@ -599,7 +598,7 @@ MODULE_DEVICE_TABLE(of, tilcdc_of_match); static struct platform_driver tilcdc_platform_driver = { .probe = tilcdc_pdev_probe, - .remove = tilcdc_pdev_remove, + .remove_new = tilcdc_pdev_remove, .shutdown = tilcdc_pdev_shutdown, .driver = { .name = "tilcdc", From 9f7843b515811aea6c56527eb195b622e9c01f12 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Fri, 17 Nov 2023 13:46:32 -0800 Subject: [PATCH 1705/7721] drm/panel-edp: Add override_edid_mode quirk for generic edp Generic edp gets mode from edid. However, some panels report incorrect mode in this way, resulting in glitches on panel. Introduce a new quirk additional_mode to the generic edid to pick a correct hardcoded mode. Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231117215056.1883314-2-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 48 +++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index f22677373171..33535f6de343 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -203,6 +203,9 @@ struct edp_panel_entry { /** @name: Name of this panel (for printing to logs). */ const char *name; + + /** @override_edid_mode: Override the mode obtained by edid. */ + const struct drm_display_mode *override_edid_mode; }; struct panel_edp { @@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct panel_edp *panel, return num; } +static int panel_edp_override_edid_mode(struct panel_edp *panel, + struct drm_connector *connector, + const struct drm_display_mode *override_mode) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, override_mode); + if (!mode) { + dev_err(panel->base.dev, "failed to add additional mode\n"); + return 0; + } + + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + return 1; +} + static int panel_edp_get_non_edid_modes(struct panel_edp *panel, struct drm_connector *connector) { @@ -568,6 +589,9 @@ static int panel_edp_get_modes(struct drm_panel *panel, { struct panel_edp *p = to_panel_edp(panel); int num = 0; + bool has_override_edid_mode = p->detected_panel && + p->detected_panel != ERR_PTR(-EINVAL) && + p->detected_panel->override_edid_mode; /* probe EDID if a DDC bus is available */ if (p->ddc) { @@ -575,9 +599,18 @@ static int panel_edp_get_modes(struct drm_panel *panel, if (!p->edid) p->edid = drm_get_edid(connector, p->ddc); - - if (p->edid) - num += drm_add_edid_modes(connector, p->edid); + if (p->edid) { + if (has_override_edid_mode) { + /* + * override_edid_mode is specified. Use + * override_edid_mode instead of from edid. + */ + num += panel_edp_override_edid_mode(p, connector, + p->detected_panel->override_edid_mode); + } else { + num += drm_add_edid_modes(connector, p->edid); + } + } pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); @@ -1849,6 +1882,15 @@ static const struct panel_delay delay_200_150_e200 = { .delay = _delay \ } +#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name, _mode) \ +{ \ + .name = _name, \ + .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ + product_id), \ + .delay = _delay, \ + .override_edid_mode = _mode \ +} + /* * This table is used to figure out power sequencing delays for panels that * are detected by EDID. Entries here may point to entries in the From 70e0d5550f5cec301ad116703b840a539fe985dc Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Fri, 17 Nov 2023 13:46:33 -0800 Subject: [PATCH 1706/7721] drm/panel-edp: Add auo_b116xa3_mode Add auo_b116xa3_mode to override the original modes parsed from edid of the panels 0x405c B116XAK01.0 and 0x615c B116XAN06.1 which result in glitches on panel. Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231117215056.1883314-3-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 33535f6de343..3e144145a6bd 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -983,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = { }, }; +static const struct drm_display_mode auo_b116xa3_mode = { + .clock = 70589, + .hdisplay = 1366, + .hsync_start = 1366 + 40, + .hsync_end = 1366 + 40 + 40, + .htotal = 1366 + 40 + 40 + 32, + .vdisplay = 768, + .vsync_start = 768 + 10, + .vsync_end = 768 + 10 + 12, + .vtotal = 768 + 10 + 12 + 6, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + static const struct drm_display_mode auo_b116xak01_mode = { .clock = 69300, .hdisplay = 1366, @@ -1908,9 +1921,11 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), + EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", + &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", + &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), From fb3f43d50d9b22946702085d1fa2139c8741283d Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Fri, 17 Nov 2023 13:46:34 -0800 Subject: [PATCH 1707/7721] drm/panel-edp: Avoid adding multiple preferred modes If a non generic edp-panel is under aux-bus, the mode read from edid would still be selected as preferred and results in multiple preferred modes, which is ambiguous. If both hard-coded mode and edid exists, only add mode from hard-coded. Signed-off-by: Hsin-Yi Wang Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231117215056.1883314-4-hsinyi@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 3e144145a6bd..825fa2a0d8a5 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -589,6 +589,7 @@ static int panel_edp_get_modes(struct drm_panel *panel, { struct panel_edp *p = to_panel_edp(panel); int num = 0; + bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes; bool has_override_edid_mode = p->detected_panel && p->detected_panel != ERR_PTR(-EINVAL) && p->detected_panel->override_edid_mode; @@ -599,7 +600,11 @@ static int panel_edp_get_modes(struct drm_panel *panel, if (!p->edid) p->edid = drm_get_edid(connector, p->ddc); - if (p->edid) { + /* + * If both edid and hard-coded modes exists, skip edid modes to + * avoid multiple preferred modes. + */ + if (p->edid && !has_hard_coded_modes) { if (has_override_edid_mode) { /* * override_edid_mode is specified. Use @@ -616,12 +621,7 @@ static int panel_edp_get_modes(struct drm_panel *panel, pm_runtime_put_autosuspend(panel->dev); } - /* - * Add hard-coded panel modes. Don't call this if there are no timings - * and no modes (the generic edp-panel case) because it will clobber - * the display_info that was already set by drm_add_edid_modes(). - */ - if (p->desc->num_timings || p->desc->num_modes) + if (has_hard_coded_modes) num += panel_edp_get_non_edid_modes(p, connector); else if (!num) dev_warn(p->base.dev, "No display modes\n"); From c9d99c73940e47692fa982cf7508581f5c55e363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 23 Nov 2023 18:54:27 +0100 Subject: [PATCH 1708/7721] drm/bridge: ti-sn65dsi86: Simplify using pm_runtime_resume_and_get() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pm_runtime_resume_and_get() already drops the runtime PM usage counter in the error case. So a call to pm_runtime_put_sync() can be dropped. Signed-off-by: Uwe Kleine-König Reviewed-by: Laurent Pinchart Reviewed-by: Neil Armstrong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231123175425.496956-2-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index c45c07840f64..5b8e1dfc458d 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1413,11 +1413,9 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, int ret; if (!pdata->pwm_enabled) { - ret = pm_runtime_get_sync(pdata->dev); - if (ret < 0) { - pm_runtime_put_sync(pdata->dev); + ret = pm_runtime_resume_and_get(pdata->dev); + if (ret < 0) return ret; - } } if (state->enabled) { From 2d2cffdbbc21586b213e5e371680f9d934d3813b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Nov 2023 12:55:08 +0100 Subject: [PATCH 1709/7721] drm/loongson: Add platform dependency Only offer the Loongson DRM driver as an option on platforms where it makes sense. Signed-off-by: Jean Delvare Cc: Sui Jingfeng Cc: David Airlie Cc: Daniel Vetter Reviewed-by: Sui Jingfeng Signed-off-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231113125508.4dc755e8@endymion.delvare --- drivers/gpu/drm/loongson/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/loongson/Kconfig b/drivers/gpu/drm/loongson/Kconfig index df6946d505fa..8e59753e532d 100644 --- a/drivers/gpu/drm/loongson/Kconfig +++ b/drivers/gpu/drm/loongson/Kconfig @@ -3,6 +3,7 @@ config DRM_LOONGSON tristate "DRM support for Loongson Graphics" depends on DRM && PCI && MMU + depends on LOONGARCH || MIPS || COMPILE_TEST select DRM_KMS_HELPER select DRM_TTM select I2C From 4540c29ab9cc06d9c910e98ff9b13a06f7a3fd21 Mon Sep 17 00:00:00 2001 From: Yu Xiao Date: Mon, 27 Nov 2023 07:51:16 +0200 Subject: [PATCH 1710/7721] nfp: ethtool: support TX/RX pause frame on/off Add support for ethtool -A tx on/off and rx on/off. Signed-off-by: Yu Xiao Signed-off-by: Louis Peens Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231127055116.6668-1-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 32 ++++++- .../ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 6 ++ .../netronome/nfp/nfpcore/nfp_nsp_eth.c | 90 ++++++++++++++++++- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index d7896391b8ba..776bee2efd35 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -2235,6 +2235,30 @@ static int nfp_net_set_channels(struct net_device *netdev, return nfp_net_set_num_rings(nn, total_rx, total_tx); } +static int nfp_port_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + int err; + + port = nfp_port_from_netdev(netdev); + eth_port = nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + if (pause->autoneg != AUTONEG_DISABLE) + return -EOPNOTSUPP; + + err = nfp_eth_set_pauseparam(port->app->cpp, eth_port->index, + pause->tx_pause, pause->rx_pause); + if (!err) + /* Only refresh if we did something */ + nfp_net_refresh_port_table(port); + + return err < 0 ? err : 0; +} + static void nfp_port_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { @@ -2246,10 +2270,10 @@ static void nfp_port_get_pauseparam(struct net_device *netdev, if (!eth_port) return; - /* Currently pause frame support is fixed */ + /* Currently pause frame autoneg is fixed */ pause->autoneg = AUTONEG_DISABLE; - pause->rx_pause = 1; - pause->tx_pause = 1; + pause->rx_pause = eth_port->rx_pause; + pause->tx_pause = eth_port->tx_pause; } static int nfp_net_set_phys_id(struct net_device *netdev, @@ -2475,6 +2499,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .set_link_ksettings = nfp_net_set_link_ksettings, .get_fecparam = nfp_port_get_fecparam, .set_fecparam = nfp_port_set_fecparam, + .set_pauseparam = nfp_port_set_pauseparam, .get_pauseparam = nfp_port_get_pauseparam, .set_phys_id = nfp_net_set_phys_id, }; @@ -2499,6 +2524,7 @@ const struct ethtool_ops nfp_port_ethtool_ops = { .set_link_ksettings = nfp_net_set_link_ksettings, .get_fecparam = nfp_port_get_fecparam, .set_fecparam = nfp_port_set_fecparam, + .set_pauseparam = nfp_port_set_pauseparam, .get_pauseparam = nfp_port_get_pauseparam, .set_phys_id = nfp_net_set_phys_id, }; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 00264af13b49..dc0e405c1349 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -189,6 +189,8 @@ enum nfp_ethtool_link_mode_list { * @ports.enabled: is enabled? * @ports.tx_enabled: is TX enabled? * @ports.rx_enabled: is RX enabled? + * @ports.rx_pause: Switch of RX pause frame + * @ports.tx_pause: Switch of Tx pause frame * @ports.override_changed: is media reconfig pending? * * @ports.port_type: one of %PORT_* defines for ethtool @@ -227,6 +229,8 @@ struct nfp_eth_table { bool tx_enabled; bool rx_enabled; bool supp_aneg; + bool rx_pause; + bool tx_pause; bool override_changed; @@ -255,6 +259,8 @@ int nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode); int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state); +int nfp_eth_set_pauseparam(struct nfp_cpp *cpp, unsigned int idx, + unsigned int tx_pause, unsigned int rx_pause); static inline bool nfp_eth_can_support_fec(struct nfp_eth_table_port *eth_port) { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 9d62085d772a..5cfddc9a5d87 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -42,6 +42,8 @@ #define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23) #define NSP_ETH_STATE_FEC GENMASK_ULL(27, 26) #define NSP_ETH_STATE_ACT_FEC GENMASK_ULL(29, 28) +#define NSP_ETH_STATE_TX_PAUSE BIT_ULL(31) +#define NSP_ETH_STATE_RX_PAUSE BIT_ULL(32) #define NSP_ETH_CTRL_CONFIGURED BIT_ULL(0) #define NSP_ETH_CTRL_ENABLED BIT_ULL(1) @@ -52,6 +54,8 @@ #define NSP_ETH_CTRL_SET_ANEG BIT_ULL(6) #define NSP_ETH_CTRL_SET_FEC BIT_ULL(7) #define NSP_ETH_CTRL_SET_IDMODE BIT_ULL(8) +#define NSP_ETH_CTRL_SET_TX_PAUSE BIT_ULL(10) +#define NSP_ETH_CTRL_SET_RX_PAUSE BIT_ULL(11) enum nfp_eth_raw { NSP_ETH_RAW_PORT = 0, @@ -180,6 +184,15 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src, dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state); dst->supp_aneg = FIELD_GET(NSP_ETH_PORT_SUPP_ANEG, port); + + if (nfp_nsp_get_abi_ver_minor(nsp) < 37) { + dst->tx_pause = true; + dst->rx_pause = true; + return; + } + + dst->tx_pause = FIELD_GET(NSP_ETH_STATE_TX_PAUSE, state); + dst->rx_pause = FIELD_GET(NSP_ETH_STATE_RX_PAUSE, state); } static void @@ -497,7 +510,7 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed) static int nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx, const u64 mask, const unsigned int shift, - unsigned int val, const u64 ctrl_bit) + u64 val, const u64 ctrl_bit) { union eth_table_entry *entries = nfp_nsp_config_entries(nsp); unsigned int idx = nfp_nsp_config_idx(nsp); @@ -629,6 +642,81 @@ nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode) return nfp_eth_config_commit_end(nsp); } +/** + * __nfp_eth_set_txpause() - set tx pause control bit + * @nsp: NFP NSP handle returned from nfp_eth_config_start() + * @tx_pause: TX pause switch + * + * Set TX pause switch. + * + * Return: 0 or -ERRNO. + */ +static int __nfp_eth_set_txpause(struct nfp_nsp *nsp, unsigned int tx_pause) +{ + return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_TX_PAUSE, + tx_pause, NSP_ETH_CTRL_SET_TX_PAUSE); +} + +/** + * __nfp_eth_set_rxpause() - set rx pause control bit + * @nsp: NFP NSP handle returned from nfp_eth_config_start() + * @rx_pause: RX pause switch + * + * Set RX pause switch. + * + * Return: 0 or -ERRNO. + */ +static int __nfp_eth_set_rxpause(struct nfp_nsp *nsp, unsigned int rx_pause) +{ + return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_RX_PAUSE, + rx_pause, NSP_ETH_CTRL_SET_RX_PAUSE); +} + +/** + * nfp_eth_set_pauseparam() - Set TX/RX pause switch. + * @cpp: NFP CPP handle + * @idx: NFP chip-wide port index + * @tx_pause: TX pause switch + * @rx_pause: RX pause switch + * + * Return: + * 0 - configuration successful; + * 1 - no changes were needed; + * -ERRNO - configuration failed. + */ +int +nfp_eth_set_pauseparam(struct nfp_cpp *cpp, unsigned int idx, + unsigned int tx_pause, unsigned int rx_pause) +{ + struct nfp_nsp *nsp; + int err; + + nsp = nfp_eth_config_start(cpp, idx); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + if (nfp_nsp_get_abi_ver_minor(nsp) < 37) { + nfp_err(nfp_nsp_cpp(nsp), + "set pause parameter operation not supported, please update flash\n"); + nfp_eth_config_cleanup_end(nsp); + return -EOPNOTSUPP; + } + + err = __nfp_eth_set_txpause(nsp, tx_pause); + if (err) { + nfp_eth_config_cleanup_end(nsp); + return err; + } + + err = __nfp_eth_set_rxpause(nsp, rx_pause); + if (err) { + nfp_eth_config_cleanup_end(nsp); + return err; + } + + return nfp_eth_config_commit_end(nsp); +} + /** * __nfp_eth_set_speed() - set interface speed/rate * @nsp: NFP NSP handle returned from nfp_eth_config_start() From 1bc9d12e1c924b76fb71da97db8818eaae5c30a1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 27 Nov 2023 15:59:17 +0300 Subject: [PATCH 1711/7721] ice: fix error code in ice_eswitch_attach() Set the "err" variable on this error path. Fixes: fff292b47ac1 ("ice: add VF representors one by one") Signed-off-by: Dan Carpenter Reviewed-by: Wojciech Drewek Link: https://lore.kernel.org/r/e0349ee5-76e6-4ff4-812f-4aa0d3f76ae7@moroto.mountain Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 3f80e2081e5d..ca118bc37e44 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -669,8 +669,10 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf) ice_eswitch_stop_reprs(pf); repr = ice_repr_add_vf(vf); - if (IS_ERR(repr)) + if (IS_ERR(repr)) { + err = PTR_ERR(repr); goto err_create_repr; + } err = ice_eswitch_setup_repr(pf, repr); if (err) From cd04b44bf055c4cd6bcee2ebfa6932fb20ef369d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 27 Nov 2023 21:16:10 +0100 Subject: [PATCH 1712/7721] r8169: remove multicast filter limit Once upon a time, when r8169 was new, the multicast filter limit code was copied from RTL8139 driver. There the filter limit is even user-configurable. The filtering is hash-based and we don't have perfect filtering. Actually the mc filtering on RTL8125 still seems to be the same as used on 8390/NE2000. So it's not clear to me which benefit it should bring when switching to all-multi mode once a certain number of filter bits is set. More the opposite: Filtering out at least some unwanted mc traffic is better than no filtering. Also the available chip documentation doesn't mention any restriction. Therefore remove the filter limit. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/57076c05-3730-40d1-ab9a-5334b263e41a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index dbc5c9d354c6..0aed99a20029 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -56,10 +56,6 @@ #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -#define MC_FILTER_LIMIT 32 - #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -2597,8 +2593,7 @@ static void rtl_set_rx_mode(struct net_device *dev) rx_mode |= AcceptAllPhys; } else if (!(dev->flags & IFF_MULTICAST)) { rx_mode &= ~AcceptMulticast; - } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT || - dev->flags & IFF_ALLMULTI || + } else if (dev->flags & IFF_ALLMULTI || tp->mac_version == RTL_GIGA_MAC_VER_35) { /* accept all multicasts */ } else if (netdev_mc_empty(dev)) { From 48f0dfd8d3e212ab27b6db147ed10407ff6aaa88 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:25 +0100 Subject: [PATCH 1713/7721] libbpf: Add st_type argument to elf_resolve_syms_offsets function We need to get offsets for static variables in following changes, so making elf_resolve_syms_offsets to take st_type value as argument and passing it to elf_sym_iter_new. Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20231125193130.834322-2-jolsa@kernel.org --- tools/lib/bpf/elf.c | 5 +++-- tools/lib/bpf/libbpf.c | 2 +- tools/lib/bpf/libbpf_internal.h | 3 ++- tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c index 2a62bf411bb3..b02faec748a5 100644 --- a/tools/lib/bpf/elf.c +++ b/tools/lib/bpf/elf.c @@ -407,7 +407,8 @@ static int symbol_cmp(const void *a, const void *b) * size, that needs to be released by the caller. */ int elf_resolve_syms_offsets(const char *binary_path, int cnt, - const char **syms, unsigned long **poffsets) + const char **syms, unsigned long **poffsets, + int st_type) { int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; int err = 0, i, cnt_done = 0; @@ -438,7 +439,7 @@ int elf_resolve_syms_offsets(const char *binary_path, int cnt, struct elf_sym_iter iter; struct elf_sym *sym; - err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC); + err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], st_type); if (err == -ENOENT) continue; if (err) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e067be95da3c..ea9b8158c20d 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -11447,7 +11447,7 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, return libbpf_err_ptr(err); offsets = resolved_offsets; } else if (syms) { - err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets); + err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets, STT_FUNC); if (err < 0) return libbpf_err_ptr(err); offsets = resolved_offsets; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index f0f08635adb0..b5d334754e5d 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -594,7 +594,8 @@ int elf_open(const char *binary_path, struct elf_fd *elf_fd); void elf_close(struct elf_fd *elf_fd); int elf_resolve_syms_offsets(const char *binary_path, int cnt, - const char **syms, unsigned long **poffsets); + const char **syms, unsigned long **poffsets, + int st_type); int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern, unsigned long **poffsets, size_t *pcnt); diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c index cd051d3901a9..ece260cf2c0b 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c @@ -249,7 +249,7 @@ static void __test_link_api(struct child *child) int link_extra_fd = -1; int err; - err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets); + err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets, STT_FUNC); if (!ASSERT_OK(err, "elf_resolve_syms_offsets")) return; From 4930b7f53a298533bc31d7540b6ea8b79a000331 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:26 +0100 Subject: [PATCH 1714/7721] bpf: Store ref_ctr_offsets values in bpf_uprobe array We will need to return ref_ctr_offsets values through link_info interface in following change, so we need to keep them around. Storing ref_ctr_offsets values directly into bpf_uprobe array. Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20231125193130.834322-3-jolsa@kernel.org --- kernel/trace/bpf_trace.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index f0b8b7c29126..ad0323f27288 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -3033,6 +3033,7 @@ struct bpf_uprobe_multi_link; struct bpf_uprobe { struct bpf_uprobe_multi_link *link; loff_t offset; + unsigned long ref_ctr_offset; u64 cookie; struct uprobe_consumer consumer; }; @@ -3172,7 +3173,6 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr { struct bpf_uprobe_multi_link *link = NULL; unsigned long __user *uref_ctr_offsets; - unsigned long *ref_ctr_offsets = NULL; struct bpf_link_primer link_primer; struct bpf_uprobe *uprobes = NULL; struct task_struct *task = NULL; @@ -3245,18 +3245,12 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr if (!uprobes || !link) goto error_free; - if (uref_ctr_offsets) { - ref_ctr_offsets = kvcalloc(cnt, sizeof(*ref_ctr_offsets), GFP_KERNEL); - if (!ref_ctr_offsets) - goto error_free; - } - for (i = 0; i < cnt; i++) { if (ucookies && __get_user(uprobes[i].cookie, ucookies + i)) { err = -EFAULT; goto error_free; } - if (uref_ctr_offsets && __get_user(ref_ctr_offsets[i], uref_ctr_offsets + i)) { + if (uref_ctr_offsets && __get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) { err = -EFAULT; goto error_free; } @@ -3287,7 +3281,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr for (i = 0; i < cnt; i++) { err = uprobe_register_refctr(d_real_inode(link->path.dentry), uprobes[i].offset, - ref_ctr_offsets ? ref_ctr_offsets[i] : 0, + uprobes[i].ref_ctr_offset, &uprobes[i].consumer); if (err) { bpf_uprobe_unregister(&path, uprobes, i); @@ -3299,11 +3293,9 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr if (err) goto error_free; - kvfree(ref_ctr_offsets); return bpf_link_settle(&link_primer); error_free: - kvfree(ref_ctr_offsets); kvfree(uprobes); kfree(link); if (task) From e56fdbfb06e26a7066b070967badef4148528df2 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:27 +0100 Subject: [PATCH 1715/7721] bpf: Add link_info support for uprobe multi link Adding support to get uprobe_link details through bpf_link_info interface. Adding new struct uprobe_multi to struct bpf_link_info to carry the uprobe_multi link details. The uprobe_multi.count is passed from user space to denote size of array fields (offsets/ref_ctr_offsets/cookies). The actual array size is stored back to uprobe_multi.count (allowing user to find out the actual array size) and array fields are populated up to the user passed size. All the non-array fields (path/count/flags/pid) are always set. Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20231125193130.834322-4-jolsa@kernel.org --- include/uapi/linux/bpf.h | 10 +++++ kernel/trace/bpf_trace.c | 72 ++++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 10 +++++ 3 files changed, 92 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 7a5498242eaa..e88746ba7d21 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6562,6 +6562,16 @@ struct bpf_link_info { __u32 flags; __u64 missed; } kprobe_multi; + struct { + __aligned_u64 path; + __aligned_u64 offsets; + __aligned_u64 ref_ctr_offsets; + __aligned_u64 cookies; + __u32 path_size; /* in/out: real path size on success, including zero byte */ + __u32 count; /* in/out: uprobe_multi offsets/ref_ctr_offsets/cookies count */ + __u32 flags; + __u32 pid; + } uprobe_multi; struct { __u32 type; /* enum bpf_perf_event_type */ __u32 :32; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index ad0323f27288..c284a4ad0315 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -3042,6 +3042,7 @@ struct bpf_uprobe_multi_link { struct path path; struct bpf_link link; u32 cnt; + u32 flags; struct bpf_uprobe *uprobes; struct task_struct *task; }; @@ -3083,9 +3084,79 @@ static void bpf_uprobe_multi_link_dealloc(struct bpf_link *link) kfree(umulti_link); } +static int bpf_uprobe_multi_link_fill_link_info(const struct bpf_link *link, + struct bpf_link_info *info) +{ + u64 __user *uref_ctr_offsets = u64_to_user_ptr(info->uprobe_multi.ref_ctr_offsets); + u64 __user *ucookies = u64_to_user_ptr(info->uprobe_multi.cookies); + u64 __user *uoffsets = u64_to_user_ptr(info->uprobe_multi.offsets); + u64 __user *upath = u64_to_user_ptr(info->uprobe_multi.path); + u32 upath_size = info->uprobe_multi.path_size; + struct bpf_uprobe_multi_link *umulti_link; + u32 ucount = info->uprobe_multi.count; + int err = 0, i; + long left; + + if (!upath ^ !upath_size) + return -EINVAL; + + if ((uoffsets || uref_ctr_offsets || ucookies) && !ucount) + return -EINVAL; + + umulti_link = container_of(link, struct bpf_uprobe_multi_link, link); + info->uprobe_multi.count = umulti_link->cnt; + info->uprobe_multi.flags = umulti_link->flags; + info->uprobe_multi.pid = umulti_link->task ? + task_pid_nr_ns(umulti_link->task, task_active_pid_ns(current)) : 0; + + if (upath) { + char *p, *buf; + + upath_size = min_t(u32, upath_size, PATH_MAX); + + buf = kmalloc(upath_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + p = d_path(&umulti_link->path, buf, upath_size); + if (IS_ERR(p)) { + kfree(buf); + return PTR_ERR(p); + } + upath_size = buf + upath_size - p; + left = copy_to_user(upath, p, upath_size); + kfree(buf); + if (left) + return -EFAULT; + info->uprobe_multi.path_size = upath_size; + } + + if (!uoffsets && !ucookies && !uref_ctr_offsets) + return 0; + + if (ucount < umulti_link->cnt) + err = -ENOSPC; + else + ucount = umulti_link->cnt; + + for (i = 0; i < ucount; i++) { + if (uoffsets && + put_user(umulti_link->uprobes[i].offset, uoffsets + i)) + return -EFAULT; + if (uref_ctr_offsets && + put_user(umulti_link->uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) + return -EFAULT; + if (ucookies && + put_user(umulti_link->uprobes[i].cookie, ucookies + i)) + return -EFAULT; + } + + return err; +} + static const struct bpf_link_ops bpf_uprobe_multi_link_lops = { .release = bpf_uprobe_multi_link_release, .dealloc = bpf_uprobe_multi_link_dealloc, + .fill_link_info = bpf_uprobe_multi_link_fill_link_info, }; static int uprobe_prog_run(struct bpf_uprobe *uprobe, @@ -3274,6 +3345,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr link->uprobes = uprobes; link->path = path; link->task = task; + link->flags = flags; bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI, &bpf_uprobe_multi_link_lops, prog); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 7a5498242eaa..e88746ba7d21 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6562,6 +6562,16 @@ struct bpf_link_info { __u32 flags; __u64 missed; } kprobe_multi; + struct { + __aligned_u64 path; + __aligned_u64 offsets; + __aligned_u64 ref_ctr_offsets; + __aligned_u64 cookies; + __u32 path_size; /* in/out: real path size on success, including zero byte */ + __u32 count; /* in/out: uprobe_multi offsets/ref_ctr_offsets/cookies count */ + __u32 flags; + __u32 pid; + } uprobe_multi; struct { __u32 type; /* enum bpf_perf_event_type */ __u32 :32; From 1703612885723869064f18e8816c6f3f87987748 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:28 +0100 Subject: [PATCH 1716/7721] selftests/bpf: Use bpf_link__destroy in fill_link_info tests The fill_link_info test keeps skeleton open and just creates various links. We are wrongly calling bpf_link__detach after each test to close them, we need to call bpf_link__destroy. Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Yafang Shao Link: https://lore.kernel.org/bpf/20231125193130.834322-5-jolsa@kernel.org --- .../selftests/bpf/prog_tests/fill_link_info.c | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index 97142a4db374..9294cb8d7743 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -140,14 +140,14 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, .retprobe = type == BPF_PERF_EVENT_KRETPROBE, ); ssize_t entry_offset = 0; + struct bpf_link *link; int link_fd, err; - skel->links.kprobe_run = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, - KPROBE_FUNC, &opts); - if (!ASSERT_OK_PTR(skel->links.kprobe_run, "attach_kprobe")) + link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, KPROBE_FUNC, &opts); + if (!ASSERT_OK_PTR(link, "attach_kprobe")) return; - link_fd = bpf_link__fd(skel->links.kprobe_run); + link_fd = bpf_link__fd(link); if (!invalid) { /* See also arch_adjust_kprobe_addr(). */ if (skel->kconfig->CONFIG_X86_KERNEL_IBT) @@ -157,39 +157,41 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, } else { kprobe_fill_invalid_user_buffer(link_fd); } - bpf_link__detach(skel->links.kprobe_run); + bpf_link__destroy(link); } static void test_tp_fill_link_info(struct test_fill_link_info *skel) { + struct bpf_link *link; int link_fd, err; - skel->links.tp_run = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); - if (!ASSERT_OK_PTR(skel->links.tp_run, "attach_tp")) + link = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); + if (!ASSERT_OK_PTR(link, "attach_tp")) return; - link_fd = bpf_link__fd(skel->links.tp_run); + link_fd = bpf_link__fd(link); err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0, 0); ASSERT_OK(err, "verify_perf_link_info"); - bpf_link__detach(skel->links.tp_run); + bpf_link__destroy(link); } static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, enum bpf_perf_event_type type) { + struct bpf_link *link; int link_fd, err; - skel->links.uprobe_run = bpf_program__attach_uprobe(skel->progs.uprobe_run, - type == BPF_PERF_EVENT_URETPROBE, - 0, /* self pid */ - UPROBE_FILE, uprobe_offset); - if (!ASSERT_OK_PTR(skel->links.uprobe_run, "attach_uprobe")) + link = bpf_program__attach_uprobe(skel->progs.uprobe_run, + type == BPF_PERF_EVENT_URETPROBE, + 0, /* self pid */ + UPROBE_FILE, uprobe_offset); + if (!ASSERT_OK_PTR(link, "attach_uprobe")) return; - link_fd = bpf_link__fd(skel->links.uprobe_run); + link_fd = bpf_link__fd(link); err = verify_perf_link_info(link_fd, type, 0, uprobe_offset, 0); ASSERT_OK(err, "verify_perf_link_info"); - bpf_link__detach(skel->links.uprobe_run); + bpf_link__destroy(link); } static int verify_kmulti_link_info(int fd, bool retprobe) @@ -278,24 +280,24 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, bool retprobe, bool invalid) { LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); + struct bpf_link *link; int link_fd, err; opts.syms = kmulti_syms; opts.cnt = KMULTI_CNT; opts.retprobe = retprobe; - skel->links.kmulti_run = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, - NULL, &opts); - if (!ASSERT_OK_PTR(skel->links.kmulti_run, "attach_kprobe_multi")) + link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts); + if (!ASSERT_OK_PTR(link, "attach_kprobe_multi")) return; - link_fd = bpf_link__fd(skel->links.kmulti_run); + link_fd = bpf_link__fd(link); if (!invalid) { err = verify_kmulti_link_info(link_fd, retprobe); ASSERT_OK(err, "verify_kmulti_link_info"); } else { verify_kmulti_invalid_user_buffer(link_fd); } - bpf_link__detach(skel->links.kmulti_run); + bpf_link__destroy(link); } void test_fill_link_info(void) From 147c69307bcf67f1f01246f9acb794da9837f299 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:29 +0100 Subject: [PATCH 1717/7721] selftests/bpf: Add link_info test for uprobe_multi link Adding fill_link_info test for uprobe_multi link. Setting up uprobes with bogus ref_ctr_offsets and cookie values to test all the bpf_link_info::uprobe_multi fields. Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Song Liu Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20231125193130.834322-6-jolsa@kernel.org --- .../selftests/bpf/prog_tests/fill_link_info.c | 198 ++++++++++++++++++ .../selftests/bpf/progs/test_fill_link_info.c | 6 + 2 files changed, 204 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index 9294cb8d7743..d4b1901f7879 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -7,6 +7,7 @@ #include #include "trace_helpers.h" #include "test_fill_link_info.skel.h" +#include "bpf/libbpf_internal.h" #define TP_CAT "sched" #define TP_NAME "sched_switch" @@ -300,6 +301,196 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, bpf_link__destroy(link); } +#define SEC(name) __attribute__((section(name), used)) + +static short uprobe_link_info_sema_1 SEC(".probes"); +static short uprobe_link_info_sema_2 SEC(".probes"); +static short uprobe_link_info_sema_3 SEC(".probes"); + +noinline void uprobe_link_info_func_1(void) +{ + asm volatile (""); + uprobe_link_info_sema_1++; +} + +noinline void uprobe_link_info_func_2(void) +{ + asm volatile (""); + uprobe_link_info_sema_2++; +} + +noinline void uprobe_link_info_func_3(void) +{ + asm volatile (""); + uprobe_link_info_sema_3++; +} + +static int +verify_umulti_link_info(int fd, bool retprobe, __u64 *offsets, + __u64 *cookies, __u64 *ref_ctr_offsets) +{ + char path[PATH_MAX], path_buf[PATH_MAX]; + struct bpf_link_info info; + __u32 len = sizeof(info); + __u64 ref_ctr_offsets_buf[3]; + __u64 offsets_buf[3]; + __u64 cookies_buf[3]; + int i, err, bit; + __u32 count = 0; + + memset(path, 0, sizeof(path)); + err = readlink("/proc/self/exe", path, sizeof(path)); + if (!ASSERT_NEQ(err, -1, "readlink")) + return -1; + + for (bit = 0; bit < 8; bit++) { + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path = ptr_to_u64(path_buf); + info.uprobe_multi.path_size = sizeof(path_buf); + info.uprobe_multi.count = count; + + if (bit & 0x1) + info.uprobe_multi.offsets = ptr_to_u64(offsets_buf); + if (bit & 0x2) + info.uprobe_multi.cookies = ptr_to_u64(cookies_buf); + if (bit & 0x4) + info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets_buf); + + err = bpf_link_get_info_by_fd(fd, &info, &len); + if (!ASSERT_OK(err, "bpf_link_get_info_by_fd")) + return -1; + + if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_UPROBE_MULTI, "info.type")) + return -1; + + ASSERT_EQ(info.uprobe_multi.pid, getpid(), "info.uprobe_multi.pid"); + ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count"); + ASSERT_EQ(info.uprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN, + retprobe, "info.uprobe_multi.flags.retprobe"); + ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1, "info.uprobe_multi.path_size"); + ASSERT_STREQ(path_buf, path, "info.uprobe_multi.path"); + + for (i = 0; i < info.uprobe_multi.count; i++) { + if (info.uprobe_multi.offsets) + ASSERT_EQ(offsets_buf[i], offsets[i], "info.uprobe_multi.offsets"); + if (info.uprobe_multi.cookies) + ASSERT_EQ(cookies_buf[i], cookies[i], "info.uprobe_multi.cookies"); + if (info.uprobe_multi.ref_ctr_offsets) { + ASSERT_EQ(ref_ctr_offsets_buf[i], ref_ctr_offsets[i], + "info.uprobe_multi.ref_ctr_offsets"); + } + } + count = count ?: info.uprobe_multi.count; + } + + return 0; +} + +static void verify_umulti_invalid_user_buffer(int fd) +{ + struct bpf_link_info info; + __u32 len = sizeof(info); + __u64 buf[3]; + int err; + + /* upath_size defined, not path */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path_size = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EINVAL, "failed_upath_size"); + + /* path defined, but small */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path = ptr_to_u64(buf); + info.uprobe_multi.path_size = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_LT(err, 0, "failed_upath_small"); + + /* path has wrong pointer */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path_size = PATH_MAX; + info.uprobe_multi.path = 123; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EFAULT, "failed_bad_path_ptr"); + + /* count zero, with offsets */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = ptr_to_u64(buf); + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EINVAL, "failed_count"); + + /* offsets not big enough */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = ptr_to_u64(buf); + info.uprobe_multi.count = 2; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -ENOSPC, "failed_small_count"); + + /* offsets has wrong pointer */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = 123; + info.uprobe_multi.count = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EFAULT, "failed_wrong_offsets"); +} + +static void test_uprobe_multi_fill_link_info(struct test_fill_link_info *skel, + bool retprobe, bool invalid) +{ + LIBBPF_OPTS(bpf_uprobe_multi_opts, opts, + .retprobe = retprobe, + ); + const char *syms[3] = { + "uprobe_link_info_func_1", + "uprobe_link_info_func_2", + "uprobe_link_info_func_3", + }; + __u64 cookies[3] = { + 0xdead, + 0xbeef, + 0xcafe, + }; + const char *sema[3] = { + "uprobe_link_info_sema_1", + "uprobe_link_info_sema_2", + "uprobe_link_info_sema_3", + }; + __u64 *offsets = NULL, *ref_ctr_offsets; + struct bpf_link *link; + int link_fd, err; + + err = elf_resolve_syms_offsets("/proc/self/exe", 3, sema, + (unsigned long **) &ref_ctr_offsets, STT_OBJECT); + if (!ASSERT_OK(err, "elf_resolve_syms_offsets_object")) + return; + + err = elf_resolve_syms_offsets("/proc/self/exe", 3, syms, + (unsigned long **) &offsets, STT_FUNC); + if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func")) + goto out; + + opts.syms = syms; + opts.cookies = &cookies[0]; + opts.ref_ctr_offsets = (unsigned long *) &ref_ctr_offsets[0]; + opts.cnt = ARRAY_SIZE(syms); + + link = bpf_program__attach_uprobe_multi(skel->progs.umulti_run, 0, + "/proc/self/exe", NULL, &opts); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_uprobe_multi")) + goto out; + + link_fd = bpf_link__fd(link); + if (invalid) + verify_umulti_invalid_user_buffer(link_fd); + else + verify_umulti_link_info(link_fd, retprobe, offsets, cookies, ref_ctr_offsets); + + bpf_link__destroy(link); +out: + free(ref_ctr_offsets); + free(offsets); +} + void test_fill_link_info(void) { struct test_fill_link_info *skel; @@ -339,6 +530,13 @@ void test_fill_link_info(void) if (test__start_subtest("kprobe_multi_invalid_ubuff")) test_kprobe_multi_fill_link_info(skel, true, true); + if (test__start_subtest("uprobe_multi_link_info")) + test_uprobe_multi_fill_link_info(skel, false, false); + if (test__start_subtest("uretprobe_multi_link_info")) + test_uprobe_multi_fill_link_info(skel, true, false); + if (test__start_subtest("uprobe_multi_invalid")) + test_uprobe_multi_fill_link_info(skel, false, true); + cleanup: test_fill_link_info__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_fill_link_info.c b/tools/testing/selftests/bpf/progs/test_fill_link_info.c index 564f402d56fe..69509f8bb680 100644 --- a/tools/testing/selftests/bpf/progs/test_fill_link_info.c +++ b/tools/testing/selftests/bpf/progs/test_fill_link_info.c @@ -39,4 +39,10 @@ int BPF_PROG(kmulti_run) return 0; } +SEC("uprobe.multi") +int BPF_PROG(umulti_run) +{ + return 0; +} + char _license[] SEC("license") = "GPL"; From a7795698f8b6c48283fa4334eb313bc1350b2864 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 25 Nov 2023 20:31:30 +0100 Subject: [PATCH 1718/7721] bpftool: Add support to display uprobe_multi links Adding support to display details for uprobe_multi links, both plain: # bpftool link -p ... 24: uprobe_multi prog 126 uprobe.multi path /home/jolsa/bpf/test_progs func_cnt 3 pid 4143 offset ref_ctr_offset cookies 0xd1f88 0xf5d5a8 0xdead 0xd1f8f 0xf5d5aa 0xbeef 0xd1f96 0xf5d5ac 0xcafe and json: # bpftool link -p [{ ... },{ "id": 24, "type": "uprobe_multi", "prog_id": 126, "retprobe": false, "path": "/home/jolsa/bpf/test_progs", "func_cnt": 3, "pid": 4143, "funcs": [{ "offset": 860040, "ref_ctr_offset": 16111016, "cookie": 57005 },{ "offset": 860047, "ref_ctr_offset": 16111018, "cookie": 48879 },{ "offset": 860054, "ref_ctr_offset": 16111020, "cookie": 51966 } ] } ] Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Reviewed-by: Quentin Monnet Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20231125193130.834322-7-jolsa@kernel.org --- tools/bpf/bpftool/link.c | 105 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index a1528cde81ab..cb46667a6b2e 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -294,6 +294,37 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) jsonw_end_array(json_wtr); } +static __u64 *u64_to_arr(__u64 val) +{ + return (__u64 *) u64_to_ptr(val); +} + +static void +show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) +{ + __u32 i; + + jsonw_bool_field(json_wtr, "retprobe", + info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN); + jsonw_string_field(json_wtr, "path", (char *) u64_to_ptr(info->uprobe_multi.path)); + jsonw_uint_field(json_wtr, "func_cnt", info->uprobe_multi.count); + jsonw_int_field(json_wtr, "pid", (int) info->uprobe_multi.pid); + jsonw_name(json_wtr, "funcs"); + jsonw_start_array(json_wtr); + + for (i = 0; i < info->uprobe_multi.count; i++) { + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "offset", + u64_to_arr(info->uprobe_multi.offsets)[i]); + jsonw_uint_field(json_wtr, "ref_ctr_offset", + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i]); + jsonw_uint_field(json_wtr, "cookie", + u64_to_arr(info->uprobe_multi.cookies)[i]); + jsonw_end_object(json_wtr); + } + jsonw_end_array(json_wtr); +} + static void show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) { @@ -465,6 +496,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) case BPF_LINK_TYPE_KPROBE_MULTI: show_kprobe_multi_json(info, json_wtr); break; + case BPF_LINK_TYPE_UPROBE_MULTI: + show_uprobe_multi_json(info, json_wtr); + break; case BPF_LINK_TYPE_PERF_EVENT: switch (info->perf_event.type) { case BPF_PERF_EVENT_EVENT: @@ -674,6 +708,33 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) } } +static void show_uprobe_multi_plain(struct bpf_link_info *info) +{ + __u32 i; + + if (!info->uprobe_multi.count) + return; + + if (info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN) + printf("\n\turetprobe.multi "); + else + printf("\n\tuprobe.multi "); + + printf("path %s ", (char *) u64_to_ptr(info->uprobe_multi.path)); + printf("func_cnt %u ", info->uprobe_multi.count); + + if (info->uprobe_multi.pid) + printf("pid %d ", info->uprobe_multi.pid); + + printf("\n\t%-16s %-16s %-16s", "offset", "ref_ctr_offset", "cookies"); + for (i = 0; i < info->uprobe_multi.count; i++) { + printf("\n\t0x%-16llx 0x%-16llx 0x%-16llx", + u64_to_arr(info->uprobe_multi.offsets)[i], + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i], + u64_to_arr(info->uprobe_multi.cookies)[i]); + } +} + static void show_perf_event_kprobe_plain(struct bpf_link_info *info) { const char *buf; @@ -807,6 +868,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) case BPF_LINK_TYPE_KPROBE_MULTI: show_kprobe_multi_plain(info); break; + case BPF_LINK_TYPE_UPROBE_MULTI: + show_uprobe_multi_plain(info); + break; case BPF_LINK_TYPE_PERF_EVENT: switch (info->perf_event.type) { case BPF_PERF_EVENT_EVENT: @@ -846,8 +910,10 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) static int do_show_link(int fd) { + __u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL; struct bpf_link_info info; __u32 len = sizeof(info); + char path_buf[PATH_MAX]; __u64 *addrs = NULL; char buf[PATH_MAX]; int count; @@ -889,6 +955,39 @@ static int do_show_link(int fd) goto again; } } + if (info.type == BPF_LINK_TYPE_UPROBE_MULTI && + !info.uprobe_multi.offsets) { + count = info.uprobe_multi.count; + if (count) { + offsets = calloc(count, sizeof(__u64)); + if (!offsets) { + p_err("mem alloc failed"); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.offsets = ptr_to_u64(offsets); + ref_ctr_offsets = calloc(count, sizeof(__u64)); + if (!ref_ctr_offsets) { + p_err("mem alloc failed"); + free(offsets); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets); + cookies = calloc(count, sizeof(__u64)); + if (!cookies) { + p_err("mem alloc failed"); + free(cookies); + free(offsets); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.cookies = ptr_to_u64(cookies); + info.uprobe_multi.path = ptr_to_u64(path_buf); + info.uprobe_multi.path_size = sizeof(path_buf); + goto again; + } + } if (info.type == BPF_LINK_TYPE_PERF_EVENT) { switch (info.perf_event.type) { case BPF_PERF_EVENT_TRACEPOINT: @@ -924,8 +1023,10 @@ static int do_show_link(int fd) else show_link_close_plain(fd, &info); - if (addrs) - free(addrs); + free(ref_ctr_offsets); + free(cookies); + free(offsets); + free(addrs); close(fd); return 0; } From 2ce344b6891618063c0bebe22d9cdf9c086e0aa8 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 25 Nov 2023 17:42:50 +0900 Subject: [PATCH 1719/7721] selftests/bpf: Choose pkg-config for the target pkg-config is used to build sign-file executable. It should use the library for the target instead of the host as it is called during tests. Signed-off-by: Akihiko Odaki Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231125084253.85025-2-akihiko.odaki@daynix.com --- tools/testing/selftests/bpf/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 9c27b67bc7b1..94825ef813d5 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -18,7 +18,7 @@ else GENDIR := $(abspath ../../../../include/generated) endif GENHDR := $(GENDIR)/autoconf.h -HOSTPKG_CONFIG := pkg-config +PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config ifneq ($(wildcard $(GENHDR)),) GENFLAGS := -DHAVE_GENHDR @@ -219,9 +219,9 @@ $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_r $(OUTPUT)/sign-file: ../../../../scripts/sign-file.c $(call msg,SIGN-FILE,,$@) - $(Q)$(CC) $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) \ + $(Q)$(CC) $(shell $(PKG_CONFIG) --cflags libcrypto 2> /dev/null) \ $< -o $@ \ - $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) + $(shell $(PKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) $(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch]) $(call msg,MOD,,$@) From 18f6f9de98d1d0f7040e6e6c39fce8939f55520f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 25 Nov 2023 17:42:51 +0900 Subject: [PATCH 1720/7721] selftests/bpf: Override PKG_CONFIG for static builds A library may need to depend on additional archive files for static builds so pkg-config should be instructed to list them. Signed-off-by: Akihiko Odaki Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231125084253.85025-3-akihiko.odaki@daynix.com --- tools/testing/selftests/bpf/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst index cb9b95702ac6..9af79c7a9b58 100644 --- a/tools/testing/selftests/bpf/README.rst +++ b/tools/testing/selftests/bpf/README.rst @@ -77,7 +77,7 @@ In case of linker errors when running selftests, try using static linking: .. code-block:: console - $ LDLIBS=-static vmtest.sh + $ LDLIBS=-static PKG_CONFIG='pkg-config --static' vmtest.sh .. note:: Some distros may not support static linking. From 8998a479fd96b0b209dcb2feb468eba7eddb4ddb Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 25 Nov 2023 17:42:52 +0900 Subject: [PATCH 1721/7721] selftests/bpf: Use pkg-config for libelf When linking statically, libraries may require other dependencies to be included to ld flags. In particular, libelf may require libzstd. Use pkg-config to determine such dependencies. Signed-off-by: Akihiko Odaki Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231125084253.85025-4-akihiko.odaki@daynix.com --- tools/testing/selftests/bpf/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 94825ef813d5..617ae55c3bb5 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,13 +29,17 @@ SAN_CFLAGS ?= SAN_LDFLAGS ?= $(SAN_CFLAGS) RELEASE ?= OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0) + +LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null) +LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf) + CFLAGS += -g $(OPT_FLAGS) -rdynamic \ -Wall -Werror \ - $(GENFLAGS) $(SAN_CFLAGS) \ + $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) LDFLAGS += $(SAN_LDFLAGS) -LDLIBS += -lelf -lz -lrt -lpthread +LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread ifneq ($(LLVM),) # Silence some warnings when compiled with clang From b844c6bae2b89b4a4e102eb326e35c632308dd85 Mon Sep 17 00:00:00 2001 From: Vinod Govindapillai Date: Fri, 10 Nov 2023 11:32:25 +0200 Subject: [PATCH 1722/7721] drm/i915/xe2lpd: remove the FBC restriction if PSR2 is enabled In earlier versions, FBC was restricted if PSR2 is enabled. From xe2lpd onwards no such restrictions are needed anymore. HSD: 14014305387 Signed-off-by: Vinod Govindapillai Reviewed-by: Mika Kahola Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231110093225.39573-2-vinod.govindapillai@intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 63f389a1707d..f17a1afb4929 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1235,7 +1235,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, * Recommendation is to keep this combination disabled * Bspec: 50422 HSD: 14010260002 */ - if (DISPLAY_VER(i915) >= 12 && crtc_state->has_psr2) { + if (IS_DISPLAY_VER(i915, 12, 14) && crtc_state->has_psr2) { plane_state->no_fbc_reason = "PSR2 enabled"; return 0; } From af3145aa142c92409d3b123ff87ff0b5fd0bf849 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Mon, 20 Nov 2023 17:10:36 +0800 Subject: [PATCH 1723/7721] Revert "drm/bridge: Add 200ms delay to wait FW HPD status stable" This reverts commit 330140d7319fcc4ec68bd924ea212e476bf12275 200ms delay will cause panel display image later than backlight turn on, revert this patch. Fixes: 330140d7319fcc ("drm/bridge: Add 200ms delay to wait FW HPD status stable") Signed-off-by: Xin Ji Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231120091038.284825-1-xji@analogixsemi.com --- drivers/gpu/drm/bridge/analogix/anx7625.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 8f740154707d..51abe42c639e 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1464,9 +1464,6 @@ static int _anx7625_hpd_polling(struct anx7625_data *ctx, if (ctx->pdata.intp_irq) return 0; - /* Delay 200ms for FW HPD de-bounce */ - msleep(200); - ret = readx_poll_timeout(anx7625_read_hpd_status_p0, ctx, val, ((val & HPD_STATUS) || (val < 0)), From e3af7053de3f685c96158373bc234b2feca1f160 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Mon, 20 Nov 2023 17:10:37 +0800 Subject: [PATCH 1724/7721] drm/bridge: anx7625: Fix Set HPD irq detect window to 2ms Polling firmware HPD GPIO status, set HPD irq detect window to 2ms after firmware HPD GPIO initial done Signed-off-by: Xin Ji Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231120091038.284825-2-xji@analogixsemi.com --- drivers/gpu/drm/bridge/analogix/anx7625.c | 51 ++++++++++++++++------- drivers/gpu/drm/bridge/analogix/anx7625.h | 4 ++ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 51abe42c639e..ef31033439bc 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1298,10 +1298,32 @@ static void anx7625_config(struct anx7625_data *ctx) XTAL_FRQ_SEL, XTAL_FRQ_27M); } +static int anx7625_hpd_timer_config(struct anx7625_data *ctx) +{ + int ret; + + /* Set irq detect window to 2ms */ + ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT8_15, + (HPD_TIME >> 8) & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT16_23, + (HPD_TIME >> 16) & 0xFF); + + return ret; +} + +static int anx7625_read_hpd_gpio_config_status(struct anx7625_data *ctx) +{ + return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, GPIO_CTRL_2); +} + static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) { struct device *dev = ctx->dev; - int ret; + int ret, val; /* Reset main ocm */ ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, 0x88, 0x40); @@ -1315,6 +1337,19 @@ static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature fail.\n"); else DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature succeeded.\n"); + + /* + * Make sure the HPD GPIO already be configured after OCM release before + * setting HPD detect window register. Here we poll the status register + * at maximum 40ms, then config HPD irq detect window register + */ + readx_poll_timeout(anx7625_read_hpd_gpio_config_status, + ctx, val, + ((val & HPD_SOURCE) || (val < 0)), + 2000, 2000 * 20); + + /* Set HPD irq detect window to 2ms */ + anx7625_hpd_timer_config(ctx); } static int anx7625_ocm_loading_check(struct anx7625_data *ctx) @@ -1437,20 +1472,6 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx) static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx) { - int ret; - - /* Set irq detect window to 2ms */ - ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); - ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT8_15, - (HPD_TIME >> 8) & 0xFF); - ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT16_23, - (HPD_TIME >> 16) & 0xFF); - if (ret < 0) - return ret; - return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); } diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 5af819611ebc..66ebee7f3d83 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -259,6 +259,10 @@ #define AP_MIPI_RX_EN BIT(5) /* 1: MIPI RX input in 0: no RX in */ #define AP_DISABLE_PD BIT(6) #define AP_DISABLE_DISPLAY BIT(7) + +#define GPIO_CTRL_2 0x49 +#define HPD_SOURCE BIT(6) + /***************************************************************/ /* Register definition of device address 0x84 */ #define MIPI_PHY_CONTROL_3 0x03 From c3c46acd5be9a3351c163d2869045cab4d5342dc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Nov 2023 15:47:58 -0600 Subject: [PATCH 1725/7721] dt-bindings: reset: hisilicon,hi3660-reset: Drop providers and consumers from example Binding examples should generally only cover what the binding covers. A provider binding doesn't need to show consumers and vice-versa. The hisilicon,hi3660-reset binding example has both, so let's drop them. This also fixes an undocumented (by schema) compatible warning for "hisilicon,hi3660-iomcu". Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231128214759.3975428-1-robh@kernel.org Signed-off-by: Philipp Zabel --- .../reset/hisilicon,hi3660-reset.yaml | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml index cdfcf32c53fa..e4de002d6903 100644 --- a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml +++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml @@ -50,32 +50,9 @@ additionalProperties: false examples: - | - #include - #include - #include - - iomcu: iomcu@ffd7e000 { - compatible = "hisilicon,hi3660-iomcu", "syscon"; - reg = <0xffd7e000 0x1000>; - }; - - iomcu_rst: iomcu_rst_controller { + iomcu_rst_controller { compatible = "hisilicon,hi3660-reset"; hisilicon,rst-syscon = <&iomcu>; #reset-cells = <2>; }; - - /* Specifying reset lines connected to IP modules */ - i2c@ffd71000 { - compatible = "snps,designware-i2c"; - reg = <0xffd71000 0x1000>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clock-frequency = <400000>; - clocks = <&crg_ctrl HI3660_CLK_GATE_I2C0>; - resets = <&iomcu_rst 0x20 3>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>; - }; ... From b48807788e7a2bd93044fe84cfe8ff64b85ec15e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:30 +0100 Subject: [PATCH 1726/7721] fbdev/acornfb: Fix name of fb_ops initializer macro Fix build by using the correct name for the initializer macro for struct fb_ops. Signed-off-by: Thomas Zimmermann Fixes: 9037afde8b9d ("fbdev/acornfb: Use fbdev I/O helpers") Cc: Thomas Zimmermann Cc: Sam Ravnborg Cc: Helge Deller Cc: Javier Martinez Canillas Cc: Arnd Bergmann Cc: # v6.6+ Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-2-tzimmermann@suse.de --- drivers/video/fbdev/acornfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/acornfb.c b/drivers/video/fbdev/acornfb.c index 163d2c9f951c..f0600f6ca254 100644 --- a/drivers/video/fbdev/acornfb.c +++ b/drivers/video/fbdev/acornfb.c @@ -605,7 +605,7 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) static const struct fb_ops acornfb_ops = { .owner = THIS_MODULE, - FB_IOMEM_DEFAULT_OPS, + FB_DEFAULT_IOMEM_OPS, .fb_check_var = acornfb_check_var, .fb_set_par = acornfb_set_par, .fb_setcolreg = acornfb_setcolreg, From 12d55c013a09a2d490f004a324c20800e4ff35ec Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:31 +0100 Subject: [PATCH 1727/7721] fbdev/sm712fb: Use correct initializer macros for struct fb_ops Only initialize mmap and draw helpers with macros; leave read/write callbacks to driver implementations. Fixes the following warnings: CC [M] drivers/video/fbdev/sm712fb.o sm712fb.c:1355:25: warning: initialized field overwritten [-Woverride-init] 1355 | .fb_fillrect = cfb_fillrect, | ^~~~~~~~~~~~ sm712fb.c:1355:25: note: (near initialization for 'smtcfb_ops.fb_fillrect') sm712fb.c:1356:25: warning: initialized field overwritten [-Woverride-init] 1356 | .fb_imageblit = cfb_imageblit, | ^~~~~~~~~~~~~ sm712fb.c:1356:25: note: (near initialization for 'smtcfb_ops.fb_imageblit') sm712fb.c:1357:25: warning: initialized field overwritten [-Woverride-init] 1357 | .fb_copyarea = cfb_copyarea, | ^~~~~~~~~~~~ sm712fb.c:1357:25: note: (near initialization for 'smtcfb_ops.fb_copyarea') sm712fb.c:1358:25: warning: initialized field overwritten [-Woverride-init] 1358 | .fb_read = smtcfb_read, | ^~~~~~~~~~~ sm712fb.c:1358:25: note: (near initialization for 'smtcfb_ops.fb_read') sm712fb.c:1359:25: warning: initialized field overwritten [-Woverride-init] 1359 | .fb_write = smtcfb_write, | ^~~~~~~~~~~~ sm712fb.c:1359:25: note: (near initialization for 'smtcfb_ops.fb_write') Signed-off-by: Thomas Zimmermann Fixes: 586132cf1d38 ("fbdev/sm712fb: Initialize fb_ops to fbdev I/O-memory helpers") Cc: Thomas Zimmermann Cc: Javier Martinez Canillas Cc: Sudip Mukherjee Cc: Teddy Wang Cc: Sam Ravnborg Cc: Helge Deller Cc: Arnd Bergmann Cc: linux-fbdev@vger.kernel.org Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-3-tzimmermann@suse.de --- drivers/video/fbdev/sm712fb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 3f8ef50e3209..104f122e0f27 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1347,16 +1347,14 @@ static int smtc_set_par(struct fb_info *info) static const struct fb_ops smtcfb_ops = { .owner = THIS_MODULE, - FB_DEFAULT_IOMEM_OPS, .fb_check_var = smtc_check_var, .fb_set_par = smtc_set_par, .fb_setcolreg = smtc_setcolreg, .fb_blank = smtc_blank, - .fb_fillrect = cfb_fillrect, - .fb_imageblit = cfb_imageblit, - .fb_copyarea = cfb_copyarea, + __FB_DEFAULT_IOMEM_OPS_DRAW, .fb_read = smtcfb_read, .fb_write = smtcfb_write, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; /* From 63994d486c9fb5e780dabb0571c607c25d485421 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:32 +0100 Subject: [PATCH 1728/7721] fbdev/vfb: Set FBINFO_VIRTFB flag The vfb driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-4-tzimmermann@suse.de --- drivers/video/fbdev/vfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index 1b7c338f9956..c748b9311fb1 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -440,6 +440,7 @@ static int vfb_probe(struct platform_device *dev) if (!info) goto err; + info->flags |= FBINFO_VIRTFB; info->screen_buffer = videomemory; info->fbops = &vfb_ops; From 853767b6b94630ac6388aa8e7893d3df26be53be Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:33 +0100 Subject: [PATCH 1729/7721] fbdev/vfb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-5-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 5 +---- drivers/video/fbdev/vfb.c | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 53693c826ebd..63956382ffb6 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1800,10 +1800,7 @@ config FB_DA8XX config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS help This is a `virtual' frame buffer device. It operates on a chunk of unswappable kernel memory instead of on the memory of a graphics diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index c748b9311fb1..f6140f247e4b 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -80,15 +80,12 @@ static int vfb_mmap(struct fb_info *info, static const struct fb_ops vfb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_SYSMEM_OPS_RDWR, .fb_check_var = vfb_check_var, .fb_set_par = vfb_set_par, .fb_setcolreg = vfb_setcolreg, .fb_pan_display = vfb_pan_display, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = vfb_mmap, }; From 30b72c0bde93ae3001736b596cf94bfb47c5e159 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:34 +0100 Subject: [PATCH 1730/7721] fbdev/arcfb: Set FBINFO_VIRTFB flag The arcfb driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Cc: Jaya Kumar Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-6-tzimmermann@suse.de --- drivers/video/fbdev/arcfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c index cff11cb04a55..7344e825543a 100644 --- a/drivers/video/fbdev/arcfb.c +++ b/drivers/video/fbdev/arcfb.c @@ -529,6 +529,7 @@ static int arcfb_probe(struct platform_device *dev) if (!info) goto err_fb_alloc; + info->flags |= FBINFO_VIRTFB; info->screen_buffer = videomemory; info->fbops = &arcfb_ops; From 28f57d03f5a73ad7c5b07fd1414d816f15f7fb1d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:35 +0100 Subject: [PATCH 1731/7721] fbdev/arcfb: Use generator macros for deferred I/O Implement the driver's fops with the generator macros for deferred I/O. Only requires per-driver code for the on-scren scanout buffer. The generated helpers implement reading, writing and drawing on top of that. Also update the selected Kconfig tokens accordingly. Actual support for deferred I/O is missing from the driver. So writing to memory-mapped pages does not automatically update the scanout buffer. Signed-off-by: Thomas Zimmermann Cc: Jaya Kumar Acked-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-7-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 5 +- drivers/video/fbdev/arcfb.c | 113 +++++++++--------------------------- 2 files changed, 27 insertions(+), 91 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 63956382ffb6..44bf622fc8d7 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -272,10 +272,7 @@ config FB_FM2 config FB_ARC tristate "Arc Monochrome LCD board support" depends on FB && (X86 || COMPILE_TEST) - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS_DEFERRED help This enables support for the Arc Monochrome LCD board. The board is based on the KS-108 lcd controller and is typically a matrix diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c index 7344e825543a..b2408543277c 100644 --- a/drivers/video/fbdev/arcfb.c +++ b/drivers/video/fbdev/arcfb.c @@ -363,39 +363,6 @@ static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx, } } -static void arcfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct arcfb_par *par = info->par; - - sys_fillrect(info, rect); - - /* update the physical lcd */ - arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height); -} - -static void arcfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct arcfb_par *par = info->par; - - sys_copyarea(info, area); - - /* update the physical lcd */ - arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height); -} - -static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct arcfb_par *par = info->par; - - sys_imageblit(info, image); - - /* update the physical lcd */ - arcfb_lcd_update(par, image->dx, image->dy, image->width, - image->height); -} - static int arcfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -436,76 +403,48 @@ static int arcfb_ioctl(struct fb_info *info, } } -/* - * this is the access path from userspace. they can seek and write to - * the fb. it's inefficient for them to do anything less than 64*8 - * writes since we update the lcd in each write() anyway. - */ -static ssize_t arcfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) +static void arcfb_damage_range(struct fb_info *info, off_t off, size_t len) { - /* modded from epson 1355 */ + struct arcfb_par *par = info->par; + unsigned int xres = info->var.xres; + unsigned int bitppos, startpos, endpos, bitcount; + unsigned int x, y, width, height; - unsigned long p; - int err; - unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount; - struct arcfb_par *par; - unsigned int xres; - - if (!info->screen_buffer) - return -ENODEV; - - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = (xres * info->var.yres)/8; - - if (p > fbmemlength) - return -ENOSPC; - - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; - } - - if (count) { - char *base_addr; - - base_addr = info->screen_buffer; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; - } - - - bitppos = p*8; + bitppos = off * 8; startpos = floorXres(bitppos, xres); - endpos = ceilXres((bitppos + (count*8)), xres); + endpos = ceilXres((bitppos + (len * 8)), xres); bitcount = endpos - startpos; x = startpos % xres; y = startpos / xres; - w = xres; - h = bitcount / xres; - arcfb_lcd_update(par, x, y, w, h); + width = xres; + height = bitcount / xres; - if (count) - return count; - return err; + arcfb_lcd_update(par, x, y, width, height); } +static void arcfb_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) +{ + struct arcfb_par *par = info->par; + + /* update the physical lcd */ + arcfb_lcd_update(par, x, y, width, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(arcfb, + arcfb_damage_range, + arcfb_damage_area) + static const struct fb_ops arcfb_ops = { .owner = THIS_MODULE, .fb_open = arcfb_open, - .fb_read = fb_sys_read, - .fb_write = arcfb_write, + __FB_DEFAULT_DEFERRED_OPS_RDWR(arcfb), .fb_release = arcfb_release, .fb_pan_display = arcfb_pan_display, - .fb_fillrect = arcfb_fillrect, - .fb_copyarea = arcfb_copyarea, - .fb_imageblit = arcfb_imageblit, + __FB_DEFAULT_DEFERRED_OPS_DRAW(arcfb), .fb_ioctl = arcfb_ioctl, + // .fb_mmap reqires deferred I/O }; static int arcfb_probe(struct platform_device *dev) From eba1418968264cb3f83ff1ce78270ccc9a729c22 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:36 +0100 Subject: [PATCH 1732/7721] auxdisplay/cfag12864bfb: Set FBINFO_VIRTFB flag The cfag12864bfb driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Cc: Miguel Ojeda Reviewed-by: Javier Martinez Canillas Acked-by: Miguel Ojeda Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-8-tzimmermann@suse.de --- drivers/auxdisplay/cfag12864bfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index 729845bcc803..c0ba693845aa 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -72,6 +72,7 @@ static int cfag12864bfb_probe(struct platform_device *device) if (!info) goto none; + info->flags = FBINFO_VIRTFB; info->screen_buffer = cfag12864b_buffer; info->screen_size = CFAG12864B_SIZE; info->fbops = &cfag12864bfb_ops; From 36e6cacdb095e35f2389ba8829db12603133d61d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:37 +0100 Subject: [PATCH 1733/7721] auxdisplay/cfag12864bfb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Cc: Miguel Ojeda Reviewed-by: Javier Martinez Canillas Acked-by: Miguel Ojeda Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-9-tzimmermann@suse.de --- drivers/auxdisplay/Kconfig | 5 +---- drivers/auxdisplay/cfag12864bfb.c | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 64012cda4d12..4377e53f8f57 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -112,10 +112,7 @@ config CFAG12864B depends on X86 depends on FB depends on KS0108 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS default n help If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series, diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index c0ba693845aa..ede0f9a51311 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -56,11 +56,8 @@ static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops cfag12864bfb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_RDWR, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = cfag12864bfb_mmap, }; From 1d6796547a44fb44252c83b36609d0ae6624cd7c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:38 +0100 Subject: [PATCH 1734/7721] auxdisplay/ht16k33: Set FBINFO_VIRTFB flag The ht16k33 driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Cc: Miguel Ojeda Cc: Robin van der Gracht Reviewed-by: Javier Martinez Canillas Acked-by: Miguel Ojeda Acked-by: Robin van der Gracht Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-10-tzimmermann@suse.de --- drivers/auxdisplay/ht16k33.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 3a2d88387224..f1716e3ce6a9 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -640,6 +640,7 @@ static int ht16k33_fbdev_probe(struct device *dev, struct ht16k33_priv *priv, INIT_DELAYED_WORK(&priv->work, ht16k33_fb_update); fbdev->info->fbops = &ht16k33_fb_ops; + fbdev->info->flags |= FBINFO_VIRTFB; fbdev->info->screen_buffer = fbdev->buffer; fbdev->info->screen_size = HT16K33_FB_SIZE; fbdev->info->fix = ht16k33_fb_fix; From df558d53139f8adc7058b3dc17f01ae03c18a440 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:39 +0100 Subject: [PATCH 1735/7721] auxdisplay/ht16k33: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Cc: Miguel Ojeda Cc: Robin van der Gracht Reviewed-by: Javier Martinez Canillas Acked-by: Miguel Ojeda Reviewed-by: Robin van der Gracht Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-11-tzimmermann@suse.de --- drivers/auxdisplay/Kconfig | 5 +---- drivers/auxdisplay/ht16k33.c | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 4377e53f8f57..d944d5298eca 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -167,10 +167,7 @@ config IMG_ASCII_LCD config HT16K33 tristate "Holtek Ht16K33 LED controller with keyscan" depends on FB && I2C && INPUT - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT + select FB_SYSMEM_HELPERS select INPUT_MATRIXKMAP select FB_BACKLIGHT select NEW_LEDS diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index f1716e3ce6a9..2f1dc6b4e276 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -356,12 +356,9 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops ht16k33_fb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_SYSMEM_OPS_RDWR, .fb_blank = ht16k33_blank, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = ht16k33_mmap, }; From bc4e90771c886086572c6bfabd57f7a6b492f52e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:40 +0100 Subject: [PATCH 1736/7721] hid/picolcd_fb: Set FBINFO_VIRTFB flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The picolcd_fb driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Cc: "Bruno Prémont" Cc: Jiri Kosina Cc: Benjamin Tissoires Cc: linux-input@vger.kernel.org Reviewed-by: Javier Martinez Canillas Acked-by: Bruno Prémont Acked-by: Jiri Kosina Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-12-tzimmermann@suse.de --- drivers/hid/hid-picolcd_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index a4dccdcda26f..d7dddd99d325 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -505,6 +505,7 @@ int picolcd_init_framebuffer(struct picolcd_data *data) dev_err(dev, "can't get a free page for framebuffer\n"); goto err_nomem; } + info->flags |= FBINFO_VIRTFB; info->screen_buffer = fbdata->bitmap; info->fix.smem_start = (unsigned long)fbdata->bitmap; memset(fbdata->vbitmap, 0xff, PICOLCDFB_SIZE); From 46b655ceeed09363b810712525dc63b533e5cd0b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:41 +0100 Subject: [PATCH 1737/7721] fbdev/sh_mobile_lcdcfb: Set FBINFO_VIRTFB flag The sh_mobile_lcdcfb driver operates on DMA-able system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-13-tzimmermann@suse.de --- drivers/video/fbdev/sh_mobile_lcdcfb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 1364dafaadb1..5c99fc8a409f 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -1567,6 +1567,7 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl) info->fbops = &sh_mobile_lcdc_overlay_ops; info->device = priv->dev; + info->flags |= FBINFO_VIRTFB; info->screen_buffer = ovl->fb_mem; info->par = ovl; @@ -2053,6 +2054,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, info->fbops = &sh_mobile_lcdc_ops; info->device = priv->dev; + info->flags |= FBINFO_VIRTFB; info->screen_buffer = ch->fb_mem; info->pseudo_palette = &ch->pseudo_palette; info->par = ch; From 01f4fbb3bd265167cdd20ed5ff8250199a0d189e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:42 +0100 Subject: [PATCH 1738/7721] fbdev/sh_mobile_lcdcfb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in DMA-able virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. The driver uses a mixture of DMA helpers and deferred I/O. That probably needs fixing by a driver maintainer. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-14-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 7 ++----- drivers/video/fbdev/sh_mobile_lcdcfb.c | 10 +++------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 44bf622fc8d7..1eab89a07bbc 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1634,12 +1634,9 @@ config FB_SH_MOBILE_LCDC depends on FB && HAVE_CLK && HAS_IOMEM depends on SUPERH || ARCH_RENESAS || COMPILE_TEST depends on FB_DEVICE - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO select FB_BACKLIGHT + select FB_DEFERRED_IO + select FB_DMAMEM_HELPERS help Frame buffer driver for the on-chip SH-Mobile LCD controller. diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 5c99fc8a409f..d84628de5189 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -1488,13 +1488,10 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops sh_mobile_lcdc_overlay_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_blank = sh_mobile_lcdc_overlay_blank, .fb_pan_display = sh_mobile_lcdc_overlay_pan, + __FB_DEFAULT_DMAMEM_OPS_DRAW, .fb_ioctl = sh_mobile_lcdc_overlay_ioctl, .fb_check_var = sh_mobile_lcdc_overlay_check_var, .fb_set_par = sh_mobile_lcdc_overlay_set_par, @@ -1966,8 +1963,7 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_fillrect = sh_mobile_lcdc_fillrect, .fb_copyarea = sh_mobile_lcdc_copyarea, .fb_imageblit = sh_mobile_lcdc_imageblit, From 133a2ca22e11041f891e6fbbf398d0dfd8b07c0c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:43 +0100 Subject: [PATCH 1739/7721] fbdev/smscufx: Select correct helpers The driver uses deferred I/O. Select the correct helpers via FB_SYSMEM_HELPERS_DEFERRED in the Kconfig file. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-15-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 1eab89a07bbc..d110d89b21d4 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1683,11 +1683,7 @@ config FB_SMSCUFX tristate "SMSC UFX6000/7000 USB Framebuffer support" depends on FB && USB select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO + select FB_SYSMEM_HELPERS_DEFERRED help This is a kernel framebuffer driver for SMSC UFX USB devices. Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and From c9496954c138b96964a2fa24bccbe5a4c3ad796f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:44 +0100 Subject: [PATCH 1740/7721] fbdev/udlfb: Select correct helpers The driver uses deferred I/O. Select the correct helpers via FB_SYSMEM_HELPERS_DEFERRED in the Kconfig file. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-16-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index d110d89b21d4..de57bf59e017 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1696,11 +1696,7 @@ config FB_UDL depends on FB && USB depends on FB_DEVICE select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO + select FB_SYSMEM_HELPERS_DEFERRED help This is a kernel framebuffer driver for DisplayLink USB devices. Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and From cb99b486a5bcc9b9a0c869774137fe40c48cf2f4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:45 +0100 Subject: [PATCH 1741/7721] fbdev/au1200fb: Set FBINFO_VIRTFB flag The au1200fb driver operates on DMA-able system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-17-tzimmermann@suse.de --- drivers/video/fbdev/au1200fb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 98afd385c49c..817c1ebb625b 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1568,6 +1568,8 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) fbi->fix.mmio_len = 0; fbi->fix.accel = FB_ACCEL_NONE; + fbi->flags |= FBINFO_VIRTFB; + fbi->screen_buffer = fbdev->fb_mem; au1200fb_update_fbinfo(fbi); From dfc3052256e024057ea8a6fbfa2691bb87fea343 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:46 +0100 Subject: [PATCH 1742/7721] fbdev/au1200fb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in DMA-able virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-18-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 5 +---- drivers/video/fbdev/au1200fb.c | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index de57bf59e017..4c82890887ba 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1457,10 +1457,7 @@ config FB_AU1100 config FB_AU1200 bool "Au1200/Au1300 LCD Driver" depends on (FB = y) && MIPS_ALCHEMY - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_DMAMEM_HELPERS help This is the framebuffer driver for the Au1200/Au1300 SOCs. It can drive various panels and CRTs by passing in kernel cmd line diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 817c1ebb625b..16ebbab50097 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1488,15 +1488,12 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, static const struct fb_ops au1200fb_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_check_var = au1200fb_fb_check_var, .fb_set_par = au1200fb_fb_set_par, .fb_setcolreg = au1200fb_fb_setcolreg, .fb_blank = au1200fb_fb_blank, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_DMAMEM_OPS_DRAW, .fb_sync = NULL, .fb_ioctl = au1200fb_ioctl, .fb_mmap = au1200fb_fb_mmap, From cccc934a74487dcf1407918a0739d0923a3c4cc0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:47 +0100 Subject: [PATCH 1743/7721] fbdev/ps3fb: Set FBINFO_VIRTFB flag The ps3fb driver operates on system memory. Mark the framebuffer accordingly. Helpers operating on the framebuffer memory will test for the presence of this flag. Signed-off-by: Thomas Zimmermann Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Christophe Leroy Cc: linuxppc-dev@lists.ozlabs.org Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-19-tzimmermann@suse.de --- drivers/video/fbdev/ps3fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/ps3fb.c b/drivers/video/fbdev/ps3fb.c index 64d291d6b153..de81ad3a5d1e 100644 --- a/drivers/video/fbdev/ps3fb.c +++ b/drivers/video/fbdev/ps3fb.c @@ -1145,7 +1145,7 @@ static int ps3fb_probe(struct ps3_system_bus_device *dev) info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; info->pseudo_palette = par->pseudo_palette; - info->flags = FBINFO_READS_FAST | + info->flags = FBINFO_VIRTFB | FBINFO_READS_FAST | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; retval = fb_alloc_cmap(&info->cmap, 256, 0); From 741effeab963073c257ad1bcfac6c355d0eca966 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:48 +0100 Subject: [PATCH 1744/7721] fbdev/ps3fb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Christophe Leroy Cc: linuxppc-dev@lists.ozlabs.org Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-20-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 5 +---- drivers/video/fbdev/ps3fb.c | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 4c82890887ba..f9dab4c90033 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1715,10 +1715,7 @@ config FB_IBM_GXT4500 config FB_PS3 tristate "PS3 GPU framebuffer driver" depends on FB && PS3_PS3AV - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS help Include support for the virtual frame buffer in the PS3 platform. diff --git a/drivers/video/fbdev/ps3fb.c b/drivers/video/fbdev/ps3fb.c index de81ad3a5d1e..de8d78bf070a 100644 --- a/drivers/video/fbdev/ps3fb.c +++ b/drivers/video/fbdev/ps3fb.c @@ -939,15 +939,12 @@ static const struct fb_ops ps3fb_ops = { .owner = THIS_MODULE, .fb_open = ps3fb_open, .fb_release = ps3fb_release, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_SYSMEM_OPS_RDWR, .fb_check_var = ps3fb_check_var, .fb_set_par = ps3fb_set_par, .fb_setcolreg = ps3fb_setcolreg, .fb_pan_display = ps3fb_pan_display, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = ps3fb_mmap, .fb_blank = ps3fb_blank, .fb_ioctl = ps3fb_ioctl, From bff13b8f2c5a38f7216ea9ce40aae88694a2b196 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:49 +0100 Subject: [PATCH 1745/7721] media/ivtvfb: Initialize fb_ops to fbdev I/O-memory helpers Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in I/O address space. This explictily sets the read/write, draw and mmap callbacks to the correct default implementation. Fbdev drivers sometimes rely on the callbacks being NULL for a default implementation to be invoked; hence requireing the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Set the callbacks via macros. No functional changes. Signed-off-by: Thomas Zimmermann Cc: Andy Walls Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Reviewed-by: Javier Martinez Canillas Reviewed-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-21-tzimmermann@suse.de --- drivers/media/pci/ivtv/Kconfig | 4 +--- drivers/media/pci/ivtv/ivtvfb.c | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index 9be52101bc4f..2498f9079b75 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -48,9 +48,7 @@ config VIDEO_IVTV_ALSA config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" depends on VIDEO_IVTV && FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_IOMEM_HELPERS help This is a framebuffer driver for the Conexant cx23415 MPEG encoder/decoder. diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 23c8c094e791..410477e3e621 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -927,17 +927,17 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) static const struct fb_ops ivtvfb_ops = { .owner = THIS_MODULE, + .fb_read = fb_io_read, .fb_write = ivtvfb_write, .fb_check_var = ivtvfb_check_var, .fb_set_par = ivtvfb_set_par, .fb_setcolreg = ivtvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + __FB_DEFAULT_IOMEM_OPS_DRAW, .fb_cursor = NULL, .fb_ioctl = ivtvfb_ioctl, .fb_pan_display = ivtvfb_pan_display, .fb_blank = ivtvfb_blank, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; /* Restore hardware after firmware restart */ From dec2d60923dbda7c26a6194a0ed9fff9dc20cd69 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:50 +0100 Subject: [PATCH 1746/7721] fbdev/clps711x-fb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in I/O address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. The driver previously selected drawing ops for system memory although it operates on I/O memory. Fixed now. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-22-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 4 +--- drivers/video/fbdev/clps711x-fb.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index f9dab4c90033..6fc43b40acac 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -146,10 +146,8 @@ config FB_ACORN config FB_CLPS711X tristate "CLPS711X LCD support" depends on FB && (ARCH_CLPS711X || COMPILE_TEST) + select FB_IOMEM_HELPERS select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT select LCD_CLASS_DEVICE select VIDEOMODE_HELPERS help diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c index e956c90efcdc..dcfd1fbbc7e1 100644 --- a/drivers/video/fbdev/clps711x-fb.c +++ b/drivers/video/fbdev/clps711x-fb.c @@ -155,13 +155,11 @@ static int clps711x_fb_blank(int blank, struct fb_info *info) static const struct fb_ops clps711x_fb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_IOMEM_OPS, .fb_setcolreg = clps711x_fb_setcolreg, .fb_check_var = clps711x_fb_check_var, .fb_set_par = clps711x_fb_set_par, .fb_blank = clps711x_fb_blank, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, }; static int clps711x_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi) From 63a11adaceb8b77d70bcce0890197fa9462ce160 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:51 +0100 Subject: [PATCH 1747/7721] fbdev/vt8500lcdfb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in DMA-able virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-23-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 1 + drivers/video/fbdev/vt8500lcdfb.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 6fc43b40acac..4e06e403d021 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1467,6 +1467,7 @@ config FB_VT8500 select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS select FB_MODE_HELPERS select VIDEOMODE_HELPERS help diff --git a/drivers/video/fbdev/vt8500lcdfb.c b/drivers/video/fbdev/vt8500lcdfb.c index 42d39a9d5130..42c25dc85197 100644 --- a/drivers/video/fbdev/vt8500lcdfb.c +++ b/drivers/video/fbdev/vt8500lcdfb.c @@ -241,6 +241,7 @@ static int vt8500lcd_blank(int blank, struct fb_info *info) static const struct fb_ops vt8500lcd_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_set_par = vt8500lcd_set_par, .fb_setcolreg = vt8500lcd_setcolreg, .fb_fillrect = wmt_ge_fillrect, @@ -250,6 +251,7 @@ static const struct fb_ops vt8500lcd_ops = { .fb_ioctl = vt8500lcd_ioctl, .fb_pan_display = vt8500lcd_pan_display, .fb_blank = vt8500lcd_blank, + // .fb_mmap needs DMA mmap }; static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id) @@ -357,7 +359,7 @@ static int vt8500lcd_probe(struct platform_device *pdev) fbi->fb.fix.smem_start = fb_mem_phys; fbi->fb.fix.smem_len = fb_mem_len; - fbi->fb.screen_base = fb_mem_virt; + fbi->fb.screen_buffer = fb_mem_virt; fbi->palette_size = PAGE_ALIGN(512); fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, From 11754a5046080a02ecf8a78bd80644e0dae56362 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:52 +0100 Subject: [PATCH 1748/7721] fbdev/wm8505fb: Initialize fb_ops to fbdev I/O-memory helpers Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in DMA-able address space. This explictily sets the read/write, draw and mmap callbacks to the correct default implementation. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default implementation to be invoked; hence requireing the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Set the callbacks via macros. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-24-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 1 + drivers/video/fbdev/wm8505fb.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 4e06e403d021..004a63cdea5a 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1480,6 +1480,7 @@ config FB_WM8505 select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS select FB_MODE_HELPERS select VIDEOMODE_HELPERS help diff --git a/drivers/video/fbdev/wm8505fb.c b/drivers/video/fbdev/wm8505fb.c index 5833147aa43d..00952e9c8802 100644 --- a/drivers/video/fbdev/wm8505fb.c +++ b/drivers/video/fbdev/wm8505fb.c @@ -248,6 +248,7 @@ static int wm8505fb_blank(int blank, struct fb_info *info) static const struct fb_ops wm8505fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_set_par = wm8505fb_set_par, .fb_setcolreg = wm8505fb_setcolreg, .fb_fillrect = wmt_ge_fillrect, @@ -256,6 +257,7 @@ static const struct fb_ops wm8505fb_ops = { .fb_sync = wmt_ge_sync, .fb_pan_display = wm8505fb_pan_display, .fb_blank = wm8505fb_blank, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; static int wm8505fb_probe(struct platform_device *pdev) From e0f05e643eb1ff9588d38c46ad12ff74efb09959 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:53 +0100 Subject: [PATCH 1749/7721] fbdev/cyber2000fb: Initialize fb_ops with fbdev macros Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in I/O address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-25-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 5 +---- drivers/video/fbdev/cyber2000fb.c | 9 +-------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 004a63cdea5a..37c8188752ba 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -178,10 +178,7 @@ config FB_IMX config FB_CYBER2000 tristate "CyberPro 2000/2010/5000 support" depends on FB && PCI && (BROKEN || !SPARC64) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_IOMEM_FOPS + select FB_IOMEM_HELPERS select VIDEO_NOMODESET help This enables support for the Integraphics CyberPro 20x0 and 5000 diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c index 52105dc1a72f..abb87d3576db 100644 --- a/drivers/video/fbdev/cyber2000fb.c +++ b/drivers/video/fbdev/cyber2000fb.c @@ -227,13 +227,6 @@ cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) CO_REG_CMD_H, cfb); } -static void -cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - cfb_imageblit(info, image); - return; -} - static int cyber2000fb_sync(struct fb_info *info) { struct cfb_info *cfb = container_of(info, struct cfb_info, fb); @@ -1069,7 +1062,7 @@ static const struct fb_ops cyber2000fb_ops = { .fb_pan_display = cyber2000fb_pan_display, .fb_fillrect = cyber2000fb_fillrect, .fb_copyarea = cyber2000fb_copyarea, - .fb_imageblit = cyber2000fb_imageblit, + .fb_imageblit = cfb_imageblit, .fb_sync = cyber2000fb_sync, __FB_DEFAULT_IOMEM_OPS_MMAP, }; From f7c8a046577e09d8f88213c985d102604e73ed4c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:54 +0100 Subject: [PATCH 1750/7721] staging/sm750fb: Declare fb_ops as constant Split up lynxfb_ops and declare each as constant. The fb_ops instance used to be modified while initializing the driver. It is now constant and the driver picks the correct instance, depending on the settings for acceleration and cursor support. Signed-off-by: Thomas Zimmermann Cc: Sudip Mukherjee Cc: Teddy Wang Cc: Greg Kroah-Hartman Cc: linux-staging@lists.linux.dev Acked-by: Javier Martinez Canillas Acked-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-26-tzimmermann@suse.de --- drivers/staging/sm750fb/sm750.c | 59 +++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 79bcd5bd4938..35098516f53c 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -663,16 +663,53 @@ static int sm750fb_set_drv(struct lynxfb_par *par) return ret; } -static struct fb_ops lynxfb_ops = { +static const struct fb_ops lynxfb_ops = { .owner = THIS_MODULE, .fb_check_var = lynxfb_ops_check_var, .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, .fb_blank = lynxfb_ops_blank, + .fb_pan_display = lynxfb_ops_pan_display, .fb_fillrect = cfb_fillrect, .fb_imageblit = cfb_imageblit, .fb_copyarea = cfb_copyarea, - /* cursor */ +}; + +static const struct fb_ops lynxfb_ops_with_cursor = { + .owner = THIS_MODULE, + .fb_check_var = lynxfb_ops_check_var, + .fb_set_par = lynxfb_ops_set_par, + .fb_setcolreg = lynxfb_ops_setcolreg, + .fb_blank = lynxfb_ops_blank, + .fb_pan_display = lynxfb_ops_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = lynxfb_ops_cursor, +}; + +static const struct fb_ops lynxfb_ops_accel = { + .owner = THIS_MODULE, + .fb_check_var = lynxfb_ops_check_var, + .fb_set_par = lynxfb_ops_set_par, + .fb_setcolreg = lynxfb_ops_setcolreg, + .fb_blank = lynxfb_ops_blank, + .fb_pan_display = lynxfb_ops_pan_display, + .fb_fillrect = lynxfb_ops_fillrect, + .fb_copyarea = lynxfb_ops_copyarea, + .fb_imageblit = lynxfb_ops_imageblit, +}; + +static const struct fb_ops lynxfb_ops_accel_with_cursor = { + .owner = THIS_MODULE, + .fb_check_var = lynxfb_ops_check_var, + .fb_set_par = lynxfb_ops_set_par, + .fb_setcolreg = lynxfb_ops_setcolreg, + .fb_blank = lynxfb_ops_blank, + .fb_pan_display = lynxfb_ops_pan_display, + .fb_fillrect = lynxfb_ops_fillrect, + .fb_copyarea = lynxfb_ops_copyarea, + .fb_imageblit = lynxfb_ops_imageblit, .fb_cursor = lynxfb_ops_cursor, }; @@ -714,7 +751,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) par->index = index; output->channel = &crtc->channel; sm750fb_set_drv(par); - lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; /* * set current cursor variable and proc pointer, @@ -731,19 +767,22 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) crtc->cursor.vstart = sm750_dev->pvMem + crtc->cursor.offset; memset_io(crtc->cursor.vstart, 0, crtc->cursor.size); - if (!g_hwcursor) { - lynxfb_ops.fb_cursor = NULL; + if (!g_hwcursor) sm750_hw_cursor_disable(&crtc->cursor); - } /* set info->fbops, must be set before fb_find_mode */ if (!sm750_dev->accel_off) { /* use 2d acceleration */ - lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect; - lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea; - lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit; + if (!g_hwcursor) + info->fbops = &lynxfb_ops_accel; + else + info->fbops = &lynxfb_ops_accel_with_cursor; + } else { + if (!g_hwcursor) + info->fbops = &lynxfb_ops; + else + info->fbops = &lynxfb_ops_with_cursor; } - info->fbops = &lynxfb_ops; if (!g_fbmode[index]) { g_fbmode[index] = g_def_fbmode; From dc0ad215e5d8524bd72180206e042d904fcc1d4f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:55 +0100 Subject: [PATCH 1751/7721] staging/sm750fb: Initialize fb_ops with fbdev macros Initialize all instances of struct fb_ops with fbdev initializer macros for framebuffers in I/O address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig. Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions. Signed-off-by: Thomas Zimmermann Cc: Sudip Mukherjee Cc: Teddy Wang Cc: Greg Kroah-Hartman Cc: linux-staging@lists.linux.dev Reviewed-by: Javier Martinez Canillas Acked-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-27-tzimmermann@suse.de --- drivers/staging/sm750fb/sm750.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 35098516f53c..04c1b32a22c5 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -665,31 +665,28 @@ static int sm750fb_set_drv(struct lynxfb_par *par) static const struct fb_ops lynxfb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_IOMEM_OPS, .fb_check_var = lynxfb_ops_check_var, .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, .fb_blank = lynxfb_ops_blank, .fb_pan_display = lynxfb_ops_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_imageblit = cfb_imageblit, - .fb_copyarea = cfb_copyarea, }; static const struct fb_ops lynxfb_ops_with_cursor = { .owner = THIS_MODULE, + FB_DEFAULT_IOMEM_OPS, .fb_check_var = lynxfb_ops_check_var, .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, .fb_blank = lynxfb_ops_blank, .fb_pan_display = lynxfb_ops_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, .fb_cursor = lynxfb_ops_cursor, }; static const struct fb_ops lynxfb_ops_accel = { .owner = THIS_MODULE, + __FB_DEFAULT_IOMEM_OPS_RDWR, .fb_check_var = lynxfb_ops_check_var, .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, @@ -698,10 +695,12 @@ static const struct fb_ops lynxfb_ops_accel = { .fb_fillrect = lynxfb_ops_fillrect, .fb_copyarea = lynxfb_ops_copyarea, .fb_imageblit = lynxfb_ops_imageblit, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; static const struct fb_ops lynxfb_ops_accel_with_cursor = { .owner = THIS_MODULE, + __FB_DEFAULT_IOMEM_OPS_RDWR, .fb_check_var = lynxfb_ops_check_var, .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, @@ -711,6 +710,7 @@ static const struct fb_ops lynxfb_ops_accel_with_cursor = { .fb_copyarea = lynxfb_ops_copyarea, .fb_imageblit = lynxfb_ops_imageblit, .fb_cursor = lynxfb_ops_cursor, + __FB_DEFAULT_IOMEM_OPS_MMAP, }; static int lynxfb_set_fbinfo(struct fb_info *info, int index) From 27ad64eac10fcb25fcbfb813921f4d30b3458e13 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:56 +0100 Subject: [PATCH 1752/7721] fbdev: Rename FB_SYS_FOPS token to FB_SYSMEM_FOPS Rename the token to harmonize naming among various helpers. For example, I/O-memory helpers use FB_IOMEM_FOPS. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-28-tzimmermann@suse.de --- drivers/video/fbdev/Kconfig | 4 ++-- drivers/video/fbdev/core/Kconfig | 6 +++--- drivers/video/fbdev/core/Makefile | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 37c8188752ba..d5909a9206ff 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1464,7 +1464,7 @@ config FB_VT8500 select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_FOPS select FB_MODE_HELPERS select VIDEOMODE_HELPERS help @@ -1477,7 +1477,7 @@ config FB_WM8505 select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_FOPS select FB_MODE_HELPERS select VIDEOMODE_HELPERS help diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index 7a3ed13bed70..faab5d50cac3 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -129,7 +129,7 @@ config FB_LITTLE_ENDIAN endchoice -config FB_SYS_FOPS +config FB_SYSMEM_FOPS tristate depends on FB_CORE @@ -142,8 +142,8 @@ config FB_DMAMEM_HELPERS depends on FB_CORE select FB_SYS_COPYAREA select FB_SYS_FILLRECT - select FB_SYS_FOPS select FB_SYS_IMAGEBLIT + select FB_SYSMEM_FOPS config FB_IOMEM_FOPS tristate @@ -168,8 +168,8 @@ config FB_SYSMEM_HELPERS depends on FB_CORE select FB_SYS_COPYAREA select FB_SYS_FILLRECT - select FB_SYS_FOPS select FB_SYS_IMAGEBLIT + select FB_SYSMEM_FOPS config FB_SYSMEM_HELPERS_DEFERRED bool diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile index c1d657601b2b..d15974759086 100644 --- a/drivers/video/fbdev/core/Makefile +++ b/drivers/video/fbdev/core/Makefile @@ -32,6 +32,6 @@ obj-$(CONFIG_FB_IOMEM_FOPS) += fb_io_fops.o obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o -obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o +obj-$(CONFIG_FB_SYSMEM_FOPS) += fb_sys_fops.o obj-$(CONFIG_FB_SVGALIB) += svgalib.o obj-$(CONFIG_FB_DDC) += fb_ddc.o From 23dad7b95fea68426311405a0627b90c06c3fc34 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:57 +0100 Subject: [PATCH 1753/7721] fbdev: Remove trailing whitespaces Fix coding style. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-29-tzimmermann@suse.de --- drivers/video/fbdev/sbuslib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c index 21e9fd8e69e2..4d524db5c4f2 100644 --- a/drivers/video/fbdev/sbuslib.c +++ b/drivers/video/fbdev/sbuslib.c @@ -48,7 +48,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, unsigned long map_offset = 0; unsigned long off; int i; - + if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) return -EINVAL; @@ -72,7 +72,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, #define POFF_MASK (PAGE_MASK|0x1UL) #else #define POFF_MASK (PAGE_MASK) -#endif +#endif map_offset = (physbase + map[i].poff) & POFF_MASK; break; } From 76f92201b821dd2f442ebe37ec9b52b525855bac Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:58 +0100 Subject: [PATCH 1754/7721] fbdev: Push pgprot_decrypted() into mmap implementations If a driver sets struct fb_ops.fb_mmap, the fbdev core automatically calls pgprot_decrypted(). But the default fb_mmap code doesn't handle pgprot_decrypted(). Move the call to pgprot_decrypted() into each drivers' fb_mmap function. This only concerns fb_mmap functions for system and DMA memory. For I/O memory, which is the default case, nothing changes. The fb_mmap for I/O-memory can later be moved into a helper as well. DRM's fbdev emulation handles pgprot_decrypted() internally via the Prime helpers. Fbdev doesn't have to do anything in this case. In cases where DRM uses deferred I/O, this patch updates fb_mmap correctly. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-30-tzimmermann@suse.de --- drivers/auxdisplay/cfag12864bfb.c | 2 ++ drivers/auxdisplay/ht16k33.c | 2 ++ drivers/video/fbdev/amba-clcd.c | 2 ++ drivers/video/fbdev/au1100fb.c | 2 ++ drivers/video/fbdev/au1200fb.c | 2 ++ drivers/video/fbdev/core/fb_chrdev.c | 5 ----- drivers/video/fbdev/core/fb_defio.c | 2 ++ drivers/video/fbdev/ep93xx-fb.c | 2 ++ drivers/video/fbdev/gbefb.c | 2 ++ drivers/video/fbdev/omap/omapfb_main.c | 2 ++ drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 ++ drivers/video/fbdev/ps3fb.c | 2 ++ drivers/video/fbdev/sa1100fb.c | 2 ++ drivers/video/fbdev/sbuslib.c | 1 + drivers/video/fbdev/sh_mobile_lcdcfb.c | 4 ++++ drivers/video/fbdev/smscufx.c | 2 ++ drivers/video/fbdev/udlfb.c | 2 ++ drivers/video/fbdev/vermilion/vermilion.c | 2 ++ drivers/video/fbdev/vfb.c | 2 ++ 19 files changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index ede0f9a51311..5ba19c339f08 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -51,6 +51,8 @@ static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct page *pages = virt_to_page(cfag12864b_buffer); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return vm_map_pages_zero(vma, &pages, 1); } diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 2f1dc6b4e276..a90430b7d07b 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -351,6 +351,8 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) struct ht16k33_priv *priv = info->par; struct page *pages = virt_to_page(priv->fbdev.buffer); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return vm_map_pages_zero(vma, &pages, 1); } diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 0399db369e70..47d373f04f3f 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -829,6 +829,8 @@ static int clcdfb_of_dma_setup(struct clcd_fb *fb) static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) { + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base, fb->fb.fix.smem_start, fb->fb.fix.smem_len); } diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c index a9c8d33a6ef7..08109ce535cd 100644 --- a/drivers/video/fbdev/au1100fb.c +++ b/drivers/video/fbdev/au1100fb.c @@ -342,6 +342,8 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) { struct au1100fb_device *fbdev = to_au1100fb_device(fbi); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys, diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 16ebbab50097..6f20efc663d7 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1236,6 +1236,8 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct au1200fb_device *fbdev = info->par; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys, fbdev->fb_len); } diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c index 32a7315b4b6d..b73a122950a9 100644 --- a/drivers/video/fbdev/core/fb_chrdev.c +++ b/drivers/video/fbdev/core/fb_chrdev.c @@ -325,11 +325,6 @@ static int fb_mmap(struct file *file, struct vm_area_struct *vma) if (info->fbops->fb_mmap) { int res; - /* - * The framebuffer needs to be accessed decrypted, be sure - * SME protection is removed ahead of the call - */ - vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); res = info->fbops->fb_mmap(info, vma); mutex_unlock(&info->mm_lock); return res; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 274f5d0fa247..1b0b85e59e5e 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -227,6 +227,8 @@ static const struct address_space_operations fb_deferred_io_aops = { int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) { + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + vma->vm_ops = &fb_deferred_io_vm_ops; vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); if (!(info->flags & FBINFO_VIRTFB)) diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c index cae00deee001..3e378874ccc7 100644 --- a/drivers/video/fbdev/ep93xx-fb.c +++ b/drivers/video/fbdev/ep93xx-fb.c @@ -311,6 +311,8 @@ static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned int offset = vma->vm_pgoff << PAGE_SHIFT; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + if (offset < info->fix.smem_len) { return dma_mmap_wc(info->device, vma, info->screen_base, info->fix.smem_start, info->fix.smem_len); diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c index e89e5579258e..8463de833d1e 100644 --- a/drivers/video/fbdev/gbefb.c +++ b/drivers/video/fbdev/gbefb.c @@ -1000,6 +1000,8 @@ static int gbefb_mmap(struct fb_info *info, unsigned long phys_addr, phys_size; u16 *tile; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + /* check range */ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 694cf6318782..aa31c0d26e92 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -1203,6 +1203,8 @@ static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) struct omapfb_device *fbdev = plane->fbdev; int r; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + omapfb_rqueue_lock(fbdev); r = fbdev->ctrl->mmap(info, vma); omapfb_rqueue_unlock(fbdev); diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index c9fd0ad352d7..0db9c55fce5a 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -1095,6 +1095,8 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) u32 len; int r; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + rg = omapfb_get_mem_region(ofbi->region); start = omapfb_get_region_paddr(ofbi); diff --git a/drivers/video/fbdev/ps3fb.c b/drivers/video/fbdev/ps3fb.c index de8d78bf070a..dbcda307f6a6 100644 --- a/drivers/video/fbdev/ps3fb.c +++ b/drivers/video/fbdev/ps3fb.c @@ -708,6 +708,8 @@ static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { int r; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index befd3fe2f659..0d362d2bf0e3 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -562,6 +562,8 @@ static int sa1100fb_mmap(struct fb_info *info, container_of(info, struct sa1100fb_info, fb); unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + if (off < info->fix.smem_len) { vma->vm_pgoff += 1; /* skip over the palette */ return dma_mmap_wc(fbi->dev, vma, fbi->map_cpu, fbi->map_dma, diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c index 4d524db5c4f2..634e3d159452 100644 --- a/drivers/video/fbdev/sbuslib.c +++ b/drivers/video/fbdev/sbuslib.c @@ -60,6 +60,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Each page, see which map applies */ diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index d84628de5189..eb2297b37504 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -1482,6 +1482,8 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) if (info->fbdefio) return fb_deferred_io_mmap(info, vma); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem, ovl->dma_handle, ovl->fb_size); } @@ -1956,6 +1958,8 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) if (info->fbdefio) return fb_deferred_io_mmap(info, vma); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem, ch->dma_handle, ch->fb_size); } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 90a77d19b236..35d682b110c4 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -783,6 +783,8 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) if (info->fbdefio) return fb_deferred_io_mmap(info, vma); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 2460ff4ac86b..1514ddac4caf 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -331,6 +331,8 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) if (info->fbdefio) return fb_deferred_io_mmap(info, vma); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c index 840ead69654b..a087b42ca652 100644 --- a/drivers/video/fbdev/vermilion/vermilion.c +++ b/drivers/video/fbdev/vermilion/vermilion.c @@ -998,6 +998,8 @@ static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) int ret; unsigned long prot; + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + ret = vmlfb_vram_offset(vinfo, offset); if (ret) return -EINVAL; diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index f6140f247e4b..f86149ba3835 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -382,6 +382,8 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, static int vfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return remap_vmalloc_range(vma, (void *)info->fix.smem_start, vma->vm_pgoff); } From 33253d9e01d40542f07aaf718a655893cd2949e5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:15:59 +0100 Subject: [PATCH 1755/7721] fbdev: Move default fb_mmap code into helper function Move the default fb_mmap code for I/O address spaces into the helper function fb_io_mmap(). The helper can either be called via struct fb_ops.fb_mmap or as the default if no fb_mmap has been set. Also set the new helper in __FB_DEFAULT_IOMEM_OPS_MMAP. In the mid-term, fb_io_mmap() is supposed to become optional. Fbdev drivers will initialize their struct fb_ops.fb_mmap to the helper and select a corresponding Kconfig token. The helper can then be made optional at compile time. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-31-tzimmermann@suse.de --- drivers/video/fbdev/core/fb_chrdev.c | 36 +++++---------------------- drivers/video/fbdev/core/fb_io_fops.c | 27 ++++++++++++++++++++ include/linux/fb.h | 3 ++- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c index b73a122950a9..089441c9d810 100644 --- a/drivers/video/fbdev/core/fb_chrdev.c +++ b/drivers/video/fbdev/core/fb_chrdev.c @@ -314,20 +314,16 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct *vma) { struct fb_info *info = file_fb_info(file); - unsigned long mmio_pgoff; - unsigned long start; - u32 len; + int res; if (!info) return -ENODEV; + mutex_lock(&info->mm_lock); if (info->fbops->fb_mmap) { - int res; res = info->fbops->fb_mmap(info, vma); - mutex_unlock(&info->mm_lock); - return res; #if IS_ENABLED(CONFIG_FB_DEFERRED_IO) } else if (info->fbdefio) { /* @@ -335,35 +331,15 @@ static int fb_mmap(struct file *file, struct vm_area_struct *vma) * minimum, point struct fb_ops.fb_mmap to fb_deferred_io_mmap(). */ dev_warn_once(info->dev, "fbdev mmap not set up for deferred I/O.\n"); - mutex_unlock(&info->mm_lock); - return -ENODEV; + res = -ENODEV; #endif + } else { + res = fb_io_mmap(info, vma); } - /* - * Ugh. This can be either the frame buffer mapping, or - * if pgoff points past it, the mmio mapping. - */ - start = info->fix.smem_start; - len = info->fix.smem_len; - mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; - if (vma->vm_pgoff >= mmio_pgoff) { - if (info->var.accel_flags) { - mutex_unlock(&info->mm_lock); - return -EINVAL; - } - - vma->vm_pgoff -= mmio_pgoff; - start = info->fix.mmio_start; - len = info->fix.mmio_len; - } mutex_unlock(&info->mm_lock); - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start, - vma->vm_end, start); - - return vm_iomap_memory(vma, start, len); + return res; } static int fb_open(struct inode *inode, struct file *file) diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c index 871b829521af..60805e43914e 100644 --- a/drivers/video/fbdev/core/fb_io_fops.c +++ b/drivers/video/fbdev/core/fb_io_fops.c @@ -132,5 +132,32 @@ ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, } EXPORT_SYMBOL(fb_io_write); +int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + unsigned long start = info->fix.smem_start; + u32 len = info->fix.smem_len; + unsigned long mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; + + /* + * This can be either the framebuffer mapping, or if pgoff points + * past it, the mmio mapping. + */ + if (vma->vm_pgoff >= mmio_pgoff) { + if (info->var.accel_flags) + return -EINVAL; + + vma->vm_pgoff -= mmio_pgoff; + start = info->fix.mmio_start; + len = info->fix.mmio_len; + } + + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start, + vma->vm_end, start); + + return vm_iomap_memory(vma, start, len); +} +EXPORT_SYMBOL(fb_io_mmap); + MODULE_DESCRIPTION("Fbdev helpers for framebuffers in I/O memory"); MODULE_LICENSE("GPL"); diff --git a/include/linux/fb.h b/include/linux/fb.h index 94e2c44c6569..a36d05b576b0 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -536,6 +536,7 @@ extern ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); extern ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); +int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma); #define __FB_DEFAULT_IOMEM_OPS_RDWR \ .fb_read = fb_io_read, \ @@ -547,7 +548,7 @@ extern ssize_t fb_io_write(struct fb_info *info, const char __user *buf, .fb_imageblit = cfb_imageblit #define __FB_DEFAULT_IOMEM_OPS_MMAP \ - .fb_mmap = NULL /* default implementation */ + .fb_mmap = fb_io_mmap #define FB_DEFAULT_IOMEM_OPS \ __FB_DEFAULT_IOMEM_OPS_RDWR, \ From b3e8813773c568fd2d65e9752abfda27442e502e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:16:00 +0100 Subject: [PATCH 1756/7721] fbdev: Warn on incorrect framebuffer access Test in framebuffer read, write and drawing helpers if FBINFO_VIRTFB has been set correctly. Framebuffers in I/O memory should only be accessed with the architecture's respective helpers. Framebuffers in system memory should be accessed with the regular load and store operations. Presumably not all drivers get this right, so we now warn about it. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-32-tzimmermann@suse.de --- drivers/video/fbdev/core/cfbcopyarea.c | 3 +++ drivers/video/fbdev/core/cfbfillrect.c | 3 +++ drivers/video/fbdev/core/cfbimgblt.c | 3 +++ drivers/video/fbdev/core/fb_io_fops.c | 9 +++++++++ drivers/video/fbdev/core/fb_sys_fops.c | 6 ++++++ drivers/video/fbdev/core/syscopyarea.c | 3 +++ drivers/video/fbdev/core/sysfillrect.c | 3 +++ drivers/video/fbdev/core/sysimgblt.c | 3 +++ include/linux/fb.h | 8 +++++++- 9 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/cfbcopyarea.c b/drivers/video/fbdev/core/cfbcopyarea.c index 5b80bf3dae50..a271f57d9c6c 100644 --- a/drivers/video/fbdev/core/cfbcopyarea.c +++ b/drivers/video/fbdev/core/cfbcopyarea.c @@ -391,6 +391,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) if (p->state != FBINFO_STATE_RUNNING) return; + if (p->flags & FBINFO_VIRTFB) + fb_warn_once(p, "Framebuffer is not in I/O address space."); + /* if the beginning of the target area might overlap with the end of the source area, be have to copy the area reverse. */ if ((dy == sy && dx > sx) || (dy > sy)) { diff --git a/drivers/video/fbdev/core/cfbfillrect.c b/drivers/video/fbdev/core/cfbfillrect.c index ba9f58b2a5e8..cbaa4c9e2355 100644 --- a/drivers/video/fbdev/core/cfbfillrect.c +++ b/drivers/video/fbdev/core/cfbfillrect.c @@ -287,6 +287,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->state != FBINFO_STATE_RUNNING) return; + if (p->flags & FBINFO_VIRTFB) + fb_warn_once(p, "Framebuffer is not in I/O address space."); + if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR ) fg = ((u32 *) (p->pseudo_palette))[rect->color]; diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c index 9ebda4e0dc7a..7d1d2f1a627d 100644 --- a/drivers/video/fbdev/core/cfbimgblt.c +++ b/drivers/video/fbdev/core/cfbimgblt.c @@ -326,6 +326,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) if (p->state != FBINFO_STATE_RUNNING) return; + if (p->flags & FBINFO_VIRTFB) + fb_warn_once(p, "Framebuffer is not in I/O address space."); + bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); start_index = bitstart & (32 - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c index 60805e43914e..3408ff1b2b7a 100644 --- a/drivers/video/fbdev/core/fb_io_fops.c +++ b/drivers/video/fbdev/core/fb_io_fops.c @@ -12,6 +12,9 @@ ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t int c, cnt = 0, err = 0; unsigned long total_size, trailing; + if (info->flags & FBINFO_VIRTFB) + fb_warn_once(info, "Framebuffer is not in I/O address space."); + if (!info->screen_base) return -ENODEV; @@ -73,6 +76,9 @@ ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, int c, cnt = 0, err = 0; unsigned long total_size, trailing; + if (info->flags & FBINFO_VIRTFB) + fb_warn_once(info, "Framebuffer is not in I/O address space."); + if (!info->screen_base) return -ENODEV; @@ -138,6 +144,9 @@ int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma) u32 len = info->fix.smem_len; unsigned long mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; + if (info->flags & FBINFO_VIRTFB) + fb_warn_once(info, "Framebuffer is not in I/O address space."); + /* * This can be either the framebuffer mapping, or if pgoff points * past it, the mmio mapping. diff --git a/drivers/video/fbdev/core/fb_sys_fops.c b/drivers/video/fbdev/core/fb_sys_fops.c index 0cb0989abda6..a9aa6519a5b3 100644 --- a/drivers/video/fbdev/core/fb_sys_fops.c +++ b/drivers/video/fbdev/core/fb_sys_fops.c @@ -22,6 +22,9 @@ ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, unsigned long total_size, c; ssize_t ret; + if (!(info->flags & FBINFO_VIRTFB)) + fb_warn_once(info, "Framebuffer is not in virtual address space."); + if (!info->screen_buffer) return -ENODEV; @@ -64,6 +67,9 @@ ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, unsigned long total_size, c; size_t ret; + if (!(info->flags & FBINFO_VIRTFB)) + fb_warn_once(info, "Framebuffer is not in virtual address space."); + if (!info->screen_buffer) return -ENODEV; diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c index 7b8bd3a2bedc..75e7001e8450 100644 --- a/drivers/video/fbdev/core/syscopyarea.c +++ b/drivers/video/fbdev/core/syscopyarea.c @@ -324,6 +324,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) if (p->state != FBINFO_STATE_RUNNING) return; + if (!(p->flags & FBINFO_VIRTFB)) + fb_warn_once(p, "Framebuffer is not in virtual address space."); + /* if the beginning of the target area might overlap with the end of the source area, be have to copy the area reverse. */ if ((dy == sy && dx > sx) || (dy > sy)) { diff --git a/drivers/video/fbdev/core/sysfillrect.c b/drivers/video/fbdev/core/sysfillrect.c index bcdcaeae6538..e49221a88ccc 100644 --- a/drivers/video/fbdev/core/sysfillrect.c +++ b/drivers/video/fbdev/core/sysfillrect.c @@ -242,6 +242,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->state != FBINFO_STATE_RUNNING) return; + if (!(p->flags & FBINFO_VIRTFB)) + fb_warn_once(p, "Framebuffer is not in virtual address space."); + if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR ) fg = ((u32 *) (p->pseudo_palette))[rect->color]; diff --git a/drivers/video/fbdev/core/sysimgblt.c b/drivers/video/fbdev/core/sysimgblt.c index 665ef7a0a249..6949bbd51d92 100644 --- a/drivers/video/fbdev/core/sysimgblt.c +++ b/drivers/video/fbdev/core/sysimgblt.c @@ -296,6 +296,9 @@ void sys_imageblit(struct fb_info *p, const struct fb_image *image) if (p->state != FBINFO_STATE_RUNNING) return; + if (!(p->flags & FBINFO_VIRTFB)) + fb_warn_once(p, "Framebuffer is not in virtual address space."); + bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); start_index = bitstart & (32 - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; diff --git a/include/linux/fb.h b/include/linux/fb.h index a36d05b576b0..24f0ec366235 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -849,7 +849,10 @@ static inline bool fb_modesetting_disabled(const char *drvname) } #endif -/* Convenience logging macros */ +/* + * Convenience logging macros + */ + #define fb_err(fb_info, fmt, ...) \ pr_err("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) #define fb_notice(info, fmt, ...) \ @@ -861,4 +864,7 @@ static inline bool fb_modesetting_disabled(const char *drvname) #define fb_dbg(fb_info, fmt, ...) \ pr_debug("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) +#define fb_warn_once(fb_info, fmt, ...) \ + pr_warn_once("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) + #endif /* _LINUX_FB_H */ From 8813e86f6d82a7931446c3cbc5d596f77d0f1ba6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 27 Nov 2023 14:16:01 +0100 Subject: [PATCH 1757/7721] fbdev: Remove default file-I/O implementations Drop the default implementations for file read, write and mmap operations. Each fbdev driver must now provide an implementation and select any necessary helpers. If no implementation has been set, fbdev returns an errno code to user space. The code is the same as if the operation had not been set in the file_operations struct. This change makes the fbdev helpers for I/O memory optional. Most systems only use system-memory framebuffers via DRM's fbdev emulation. v2: * warn once if I/O callbacks are missing (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-33-tzimmermann@suse.de --- drivers/video/fbdev/core/Kconfig | 1 - drivers/video/fbdev/core/fb_chrdev.c | 37 +++++++++------------------- include/linux/fb.h | 5 ++++ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index faab5d50cac3..21053bf00dc5 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -4,7 +4,6 @@ # config FB_CORE - select FB_IOMEM_FOPS select VIDEO_CMDLINE tristate diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c index 089441c9d810..4ebd16b7e3b8 100644 --- a/drivers/video/fbdev/core/fb_chrdev.c +++ b/drivers/video/fbdev/core/fb_chrdev.c @@ -34,13 +34,13 @@ static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t if (!info) return -ENODEV; + if (fb_WARN_ON_ONCE(info, !info->fbops->fb_read)) + return -EINVAL; + if (info->state != FBINFO_STATE_RUNNING) return -EPERM; - if (info->fbops->fb_read) - return info->fbops->fb_read(info, buf, count, ppos); - - return fb_io_read(info, buf, count, ppos); + return info->fbops->fb_read(info, buf, count, ppos); } static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -50,13 +50,13 @@ static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, if (!info) return -ENODEV; + if (fb_WARN_ON_ONCE(info, !info->fbops->fb_write)) + return -EINVAL; + if (info->state != FBINFO_STATE_RUNNING) return -EPERM; - if (info->fbops->fb_write) - return info->fbops->fb_write(info, buf, count, ppos); - - return fb_io_write(info, buf, count, ppos); + return info->fbops->fb_write(info, buf, count, ppos); } static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, @@ -319,24 +319,11 @@ static int fb_mmap(struct file *file, struct vm_area_struct *vma) if (!info) return -ENODEV; + if (fb_WARN_ON_ONCE(info, !info->fbops->fb_mmap)) + return -ENODEV; + mutex_lock(&info->mm_lock); - - if (info->fbops->fb_mmap) { - - res = info->fbops->fb_mmap(info, vma); -#if IS_ENABLED(CONFIG_FB_DEFERRED_IO) - } else if (info->fbdefio) { - /* - * FB deferred I/O wants you to handle mmap in your drivers. At a - * minimum, point struct fb_ops.fb_mmap to fb_deferred_io_mmap(). - */ - dev_warn_once(info->dev, "fbdev mmap not set up for deferred I/O.\n"); - res = -ENODEV; -#endif - } else { - res = fb_io_mmap(info, vma); - } - + res = info->fbops->fb_mmap(info, vma); mutex_unlock(&info->mm_lock); return res; diff --git a/include/linux/fb.h b/include/linux/fb.h index 24f0ec366235..05dc9624897d 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -867,4 +867,9 @@ static inline bool fb_modesetting_disabled(const char *drvname) #define fb_warn_once(fb_info, fmt, ...) \ pr_warn_once("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) +#define fb_WARN_ONCE(fb_info, condition, fmt, ...) \ + WARN_ONCE(condition, "fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) +#define fb_WARN_ON_ONCE(fb_info, x) \ + fb_WARN_ONCE(fb_info, (x), "%s", "fb_WARN_ON_ONCE(" __stringify(x) ")") + #endif /* _LINUX_FB_H */ From a466027abe4af3a39bf1d450e8cacd34a63b7edf Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 13 Nov 2023 07:35:43 -0800 Subject: [PATCH 1758/7721] wifi: ath11k: use select for CRYPTO_MICHAEL_MIC Let ath11k select this option automatically which makes building more intuitive if the user enables this driver (rather than the driver not building unless CRYPTO_MICHAEL_MIC is explicitly enabled). Further investigation shows that ath11k and ath12k are the only who use 'depends on' with CRYPTO_MICHAEL_MIC: ./drivers/net/wireless/intel/ipw2x00/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/intersil/hostap/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/intersil/orinoco/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/ath/ath11k/Kconfig: depends on CRYPTO_MICHAEL_MIC ./drivers/net/wireless/ath/ath12k/Kconfig: depends on CRYPTO_MICHAEL_MIC ./drivers/staging/rtl8192e/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/staging/ks7010/Kconfig: select CRYPTO_MICHAEL_MIC Signed-off-by: James Prestwood Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231113153544.282461-1-prestwoj@gmail.com --- drivers/net/wireless/ath/ath11k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index ad5cc6cac05b..27f0523bf967 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -2,7 +2,7 @@ config ATH11K tristate "Qualcomm Technologies 802.11ax chipset support" depends on MAC80211 && HAS_DMA - depends on CRYPTO_MICHAEL_MIC + select CRYPTO_MICHAEL_MIC select ATH_COMMON select QCOM_QMI_HELPERS help From c7b4f54112e188359844016e982c4d14d95a00ae Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 13 Nov 2023 07:35:44 -0800 Subject: [PATCH 1759/7721] wifi: ath12k: use select for CRYPTO_MICHAEL_MIC Let ath12k select this option automatically which makes building more intuitive if the user enables this driver (rather than the driver not building unless CRYPTO_MICHAEL_MIC is explicitly enabled). Further investigation shows that ath11k and ath12k are the only who use 'depends on' with CRYPTO_MICHAEL_MIC: ./drivers/net/wireless/intel/ipw2x00/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/intersil/hostap/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/intersil/orinoco/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/net/wireless/ath/ath11k/Kconfig: depends on CRYPTO_MICHAEL_MIC ./drivers/net/wireless/ath/ath12k/Kconfig: depends on CRYPTO_MICHAEL_MIC ./drivers/staging/rtl8192e/Kconfig: select CRYPTO_MICHAEL_MIC ./drivers/staging/ks7010/Kconfig: select CRYPTO_MICHAEL_MIC Signed-off-by: James Prestwood Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231113153544.282461-2-prestwoj@gmail.com --- drivers/net/wireless/ath/ath12k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index 4f9c514c13e7..e135d2b1b61d 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -2,7 +2,7 @@ config ATH12K tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)" depends on MAC80211 && HAS_DMA && PCI - depends on CRYPTO_MICHAEL_MIC + select CRYPTO_MICHAEL_MIC select QCOM_QMI_HELPERS select MHI_BUS select QRTR From 898d8b3e1414cd900492ee6a0b582f8095ba4a1a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 22 Nov 2023 20:31:02 +0200 Subject: [PATCH 1760/7721] wifi: ath12k: fix the error handler of rfkill config When the core rfkill config throws error, it should free the allocated resources. Currently it is not freeing the core pdev create resources. Avoid this issue by calling the core pdev destroy in the error handler of core rfkill config. Found this issue in the code review and it is compile tested only. Fixes: 004ccbc0dd49 ("wifi: ath12k: add support for hardware rfkill for WCN7850") Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231111040107.18708-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index b936760b5140..6c01b282fcd3 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -698,13 +698,15 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab) ret = ath12k_core_rfkill_config(ab); if (ret && ret != -EOPNOTSUPP) { ath12k_err(ab, "failed to config rfkill: %d\n", ret); - goto err_core_stop; + goto err_core_pdev_destroy; } mutex_unlock(&ab->core_lock); return 0; +err_core_pdev_destroy: + ath12k_core_pdev_destroy(ab); err_core_stop: ath12k_core_stop(ab); ath12k_mac_destroy(ab); From d281a574f1332ad185faebe433f790abf4eb3b58 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 22 Nov 2023 20:31:02 +0200 Subject: [PATCH 1761/7721] wifi: ath12k: avoid explicit mac id argument in Rxdma replenish Currently all Rxdma replenish callers pass zero for the mac id argument, so make it as zero implicitly. To optimize the rx data path per packet, avoid the explicit unnecessary argument in Rxdma replenish function. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00125-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231111043934.20485-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 4 ++-- drivers/net/wireless/ath/ath12k/dp_rx.c | 16 +++++++--------- drivers/net/wireless/ath/ath12k/dp_rx.h | 4 ++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 6893466f61f0..0eae4e89e07c 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -961,7 +961,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, 0, + ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0, ab->hw_params->hal_params->rx_buf_rbm, true); } diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 9f831e3971f9..c7fc89af05c0 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -256,7 +256,7 @@ static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) } /* Returns number of Rx buffers replenished */ -int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, +int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, int req_entries, enum hal_rx_buf_return_buf_manager mgr, @@ -337,9 +337,7 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, spin_unlock_bh(&rx_ring->idr_lock); if (buf_id < 0) goto fail_dma_unmap; - cookie = u32_encode_bits(mac_id, - DP_RXDMA_BUF_COOKIE_PDEV_ID) | - u32_encode_bits(buf_id, + cookie = u32_encode_bits(buf_id, DP_RXDMA_BUF_COOKIE_BUF_ID); } @@ -437,7 +435,7 @@ static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF)) ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); else - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_entries, + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries, ab->hw_params->hal_params->rx_buf_rbm, ringtype == HAL_RXDMA_BUF); return 0; @@ -2712,7 +2710,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, goto exit; /* TODO: Move to implicit BM? */ - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, ab->hw_params->hal_params->rx_buf_rbm, true); ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, @@ -3491,7 +3489,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, tot_n_bufs_reaped, + ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped, ab->hw_params->hal_params->rx_buf_rbm, true); return tot_n_bufs_reaped; @@ -3805,7 +3803,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, ab->hw_params->hal_params->rx_buf_rbm, true); rcu_read_lock(); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index c955b5c859d1..ef1b172e685c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_RX_H #define ATH12K_DP_RX_H @@ -116,7 +116,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id, struct napi_struct *napi, int budget); -int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, +int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, int req_entries, enum hal_rx_buf_return_buf_manager mgr, From d457f9fe863df2e15ea1815dfe836020d436ea29 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 22 Nov 2023 20:31:02 +0200 Subject: [PATCH 1762/7721] wifi: ath12k: avoid explicit RBM id argument in Rxdma replenish Currently all Rxdma replenish callers pass the same return buffer manager id argument, so make it implicitly. To optimize the rx data path per packet, avoid the explicit unnecessary argument in Rxdma replenish function. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00125-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231111043934.20485-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 1 - drivers/net/wireless/ath/ath12k/dp_rx.c | 13 ++++--------- drivers/net/wireless/ath/ath12k/dp_rx.h | 1 - 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 0eae4e89e07c..6bd16dbef2ef 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -962,7 +962,6 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0, - ab->hw_params->hal_params->rx_buf_rbm, true); } diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index c7fc89af05c0..94e04b65bb64 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -259,7 +259,6 @@ static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, int req_entries, - enum hal_rx_buf_return_buf_manager mgr, bool hw_cc) { struct ath12k_buffer_addr *desc; @@ -272,6 +271,7 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, dma_addr_t paddr; struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info *rx_desc; + enum hal_rx_buf_return_buf_manager mgr = ab->hw_params->hal_params->rx_buf_rbm; req_entries = min(req_entries, rx_ring->bufs_max); @@ -436,7 +436,6 @@ static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); else ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries, - ab->hw_params->hal_params->rx_buf_rbm, ringtype == HAL_RXDMA_BUF); return 0; } @@ -2709,9 +2708,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, if (!total_msdu_reaped) goto exit; - /* TODO: Move to implicit BM? */ - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, true); ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, ring_id); @@ -3489,8 +3486,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped, true); return tot_n_bufs_reaped; } @@ -3803,8 +3799,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, true); rcu_read_lock(); for (i = 0; i < ab->num_radios; i++) { diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index ef1b172e685c..b0fb806a3b14 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -119,7 +119,6 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id, int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, int req_entries, - enum hal_rx_buf_return_buf_manager mgr, bool hw_cc); int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar); int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id); From 4d922ce983cbb9d8f57335acb62d67697ac45202 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 22 Nov 2023 20:31:02 +0200 Subject: [PATCH 1763/7721] wifi: ath12k: avoid explicit HW conversion argument in Rxdma replenish Currently Rxdma replenish require HW conversion argument which is unnecessary argument since ath12k driver configures the Rxdma only in HW conversion. To optimize the rx data path per packet, avoid the explicit unnecessary argument and condition check in the rx replenish. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00125-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231111043934.20485-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 3 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 78 +++++++++---------------- drivers/net/wireless/ath/ath12k/dp_rx.h | 3 +- 3 files changed, 31 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 6bd16dbef2ef..a6f81f2f97ef 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -961,8 +961,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0, - true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0); } /* TODO: Implement handler for other interrupts */ diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 94e04b65bb64..2098a5f8fb70 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -258,15 +258,13 @@ static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) /* Returns number of Rx buffers replenished */ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, - int req_entries, - bool hw_cc) + int req_entries) { struct ath12k_buffer_addr *desc; struct hal_srng *srng; struct sk_buff *skb; int num_free; int num_remain; - int buf_id; u32 cookie; dma_addr_t paddr; struct ath12k_dp *dp = &ab->dp; @@ -307,40 +305,29 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, if (dma_mapping_error(ab->dev, paddr)) goto fail_free_skb; - if (hw_cc) { - spin_lock_bh(&dp->rx_desc_lock); - - /* Get desc from free list and store in used list - * for cleanup purposes - * - * TODO: pass the removed descs rather than - * add/read to optimize - */ - rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, - struct ath12k_rx_desc_info, - list); - if (!rx_desc) { - spin_unlock_bh(&dp->rx_desc_lock); - goto fail_dma_unmap; - } - - rx_desc->skb = skb; - cookie = rx_desc->cookie; - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); + spin_lock_bh(&dp->rx_desc_lock); + /* Get desc from free list and store in used list + * for cleanup purposes + * + * TODO: pass the removed descs rather than + * add/read to optimize + */ + rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, + struct ath12k_rx_desc_info, + list); + if (!rx_desc) { spin_unlock_bh(&dp->rx_desc_lock); - } else { - spin_lock_bh(&rx_ring->idr_lock); - buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, - rx_ring->bufs_max * 3, GFP_ATOMIC); - spin_unlock_bh(&rx_ring->idr_lock); - if (buf_id < 0) - goto fail_dma_unmap; - cookie = u32_encode_bits(buf_id, - DP_RXDMA_BUF_COOKIE_BUF_ID); + goto fail_dma_unmap; } + rx_desc->skb = skb; + cookie = rx_desc->cookie; + list_del(&rx_desc->list); + list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); + + spin_unlock_bh(&dp->rx_desc_lock); + desc = ath12k_hal_srng_src_get_next_entry(ab, srng); if (!desc) goto fail_buf_unassign; @@ -359,17 +346,11 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, return req_entries - num_remain; fail_buf_unassign: - if (hw_cc) { - spin_lock_bh(&dp->rx_desc_lock); - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); - rx_desc->skb = NULL; - spin_unlock_bh(&dp->rx_desc_lock); - } else { - spin_lock_bh(&rx_ring->idr_lock); - idr_remove(&rx_ring->bufs_idr, buf_id); - spin_unlock_bh(&rx_ring->idr_lock); - } + spin_lock_bh(&dp->rx_desc_lock); + list_del(&rx_desc->list); + list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); + rx_desc->skb = NULL; + spin_unlock_bh(&dp->rx_desc_lock); fail_dma_unmap: dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -435,8 +416,7 @@ static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF)) ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); else - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries, - ringtype == HAL_RXDMA_BUF); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries); return 0; } @@ -2708,7 +2688,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, if (!total_msdu_reaped) goto exit; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, ring_id); @@ -3486,7 +3466,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped); return tot_n_bufs_reaped; } @@ -3799,7 +3779,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); rcu_read_lock(); for (i = 0; i < ab->num_radios; i++) { diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index b0fb806a3b14..05b3d5581dbe 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -118,8 +118,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id, int budget); int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, - int req_entries, - bool hw_cc); + int req_entries); int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar); int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id); From 9f1eebf0454dc97512cdd74b9be38330734a0f86 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 22 Nov 2023 20:31:02 +0200 Subject: [PATCH 1764/7721] wifi: ath12k: refactor DP Rxdma ring structure Currently data path Rxdma ring structure store the IDR buffer and lock. These IDR handling is needed only for SW cookie conversion and not needed for HW cookie conversion. REO Rxdma ring use the HW cookie conversion and monitor Rxdma ring use the SW cookie conversion. Since idr not needed for REO Rxdma ring, remove the IDR data entity from the data path Rxdma ring structure. Introduce the new data path ring structure for monitor rxmda rings since it need IDR data entity. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00125-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231111043934.20485-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 13 ++++-- drivers/net/wireless/ath/ath12k/dp_mon.c | 12 ++--- drivers/net/wireless/ath/ath12k/dp_mon.h | 4 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 58 ++++++++++++------------ 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 61f765432516..1df3cdd46140 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_H @@ -31,7 +31,7 @@ struct dp_srng { u32 ring_id; }; -struct dp_rxdma_ring { +struct dp_rxdma_mon_ring { struct dp_srng refill_buf_ring; struct idr bufs_idr; /* Protects bufs_idr */ @@ -39,6 +39,11 @@ struct dp_rxdma_ring { int bufs_max; }; +struct dp_rxdma_ring { + struct dp_srng refill_buf_ring; + int bufs_max; +}; + #define ATH12K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) struct dp_tx_ring { @@ -353,8 +358,8 @@ struct ath12k_dp { struct dp_rxdma_ring rx_refill_buf_ring; struct dp_srng rx_mac_buf_ring[MAX_RXDMA_PER_PDEV]; struct dp_srng rxdma_err_dst_ring[MAX_RXDMA_PER_PDEV]; - struct dp_rxdma_ring rxdma_mon_buf_ring; - struct dp_rxdma_ring tx_mon_buf_ring; + struct dp_rxdma_mon_ring rxdma_mon_buf_ring; + struct dp_rxdma_mon_ring tx_mon_buf_ring; struct ath12k_reo_q_addr_lut reoq_lut; }; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index f44bc5494ce7..98d7c8e2c0eb 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_mon.h" @@ -797,7 +797,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, /* TODO: add msdu start parsing logic */ break; case HAL_MON_BUF_ADDR: { - struct dp_rxdma_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring; + struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring; struct dp_mon_packet_info *packet_info = (struct dp_mon_packet_info *)tlv_data; int buf_id = u32_get_bits(packet_info->cookie, @@ -1259,7 +1259,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, } int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab, - struct dp_rxdma_ring *buf_ring, + struct dp_rxdma_mon_ring *buf_ring, int req_entries) { struct hal_mon_buf_ring *mon_buf; @@ -1902,7 +1902,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_MON_BUF_ADDR: { - struct dp_rxdma_ring *buf_ring = &ab->dp.tx_mon_buf_ring; + struct dp_rxdma_mon_ring *buf_ring = &ab->dp.tx_mon_buf_ring; struct dp_mon_packet_info *packet_info = (struct dp_mon_packet_info *)tlv_data; int buf_id = u32_get_bits(packet_info->cookie, @@ -2067,7 +2067,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, struct ath12k_skb_rxcb *rxcb; struct dp_srng *mon_dst_ring; struct hal_srng *srng; - struct dp_rxdma_ring *buf_ring; + struct dp_rxdma_mon_ring *buf_ring; u64 cookie; u32 ppdu_id; int num_buffs_reaped = 0, srng_id, buf_id; @@ -2480,7 +2480,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, struct ath12k_skb_rxcb *rxcb; struct dp_srng *mon_dst_ring; struct hal_srng *srng; - struct dp_rxdma_ring *buf_ring; + struct dp_rxdma_mon_ring *buf_ring; struct ath12k_sta *arsta = NULL; struct ath12k_peer *peer; u64 cookie; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h index c18c385798a1..fb9e9c176ce5 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.h +++ b/drivers/net/wireless/ath/ath12k/dp_mon.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_MON_H @@ -80,7 +80,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, int mac_id, struct sk_buff *skb, struct napi_struct *napi); int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab, - struct dp_rxdma_ring *buf_ring, + struct dp_rxdma_mon_ring *buf_ring, int req_entries); int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, enum dp_monitor_mode monitor_mode, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 2098a5f8fb70..fb02238798d7 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -364,8 +364,8 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, return req_entries - num_remain; } -static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab, - struct dp_rxdma_ring *rx_ring) +static int ath12k_dp_rxdma_mon_buf_ring_free(struct ath12k_base *ab, + struct dp_rxdma_mon_ring *rx_ring) { struct sk_buff *skb; int buf_id; @@ -390,22 +390,17 @@ static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab, static int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); + ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->rxdma_mon_buf_ring); - rx_ring = &dp->rxdma_mon_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); - - rx_ring = &dp->tx_mon_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); + ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->tx_mon_buf_ring); return 0; } -static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, - struct dp_rxdma_ring *rx_ring, - u32 ringtype) +static int ath12k_dp_rxdma_mon_ring_buf_setup(struct ath12k_base *ab, + struct dp_rxdma_mon_ring *rx_ring, + u32 ringtype) { int num_entries; @@ -413,21 +408,31 @@ static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, ath12k_hal_srng_get_entrysize(ab, ringtype); rx_ring->bufs_max = num_entries; - if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF)) - ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); - else - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries); + ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); + + return 0; +} + +static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, + struct dp_rxdma_ring *rx_ring) +{ + int num_entries; + + num_entries = rx_ring->refill_buf_ring.size / + ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF); + + rx_ring->bufs_max = num_entries; + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries); + return 0; } static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; int ret; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_RXDMA_BUF); + ret = ath12k_dp_rxdma_ring_buf_setup(ab, &dp->rx_refill_buf_ring); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_BUF\n"); @@ -435,18 +440,18 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) } if (ab->hw_params->rxdma1_enable) { - rx_ring = &dp->rxdma_mon_buf_ring; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_RXDMA_MONITOR_BUF); + ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab, + &dp->rxdma_mon_buf_ring, + HAL_RXDMA_MONITOR_BUF); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; } - rx_ring = &dp->tx_mon_buf_ring; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_TX_MONITOR_BUF); + ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab, + &dp->tx_mon_buf_ring, + HAL_TX_MONITOR_BUF); if (ret) { ath12k_warn(ab, "failed to setup HAL_TX_MONITOR_BUF\n"); @@ -4060,9 +4065,6 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; int i, ret; - idr_init(&dp->rx_refill_buf_ring.bufs_idr); - spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); - idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); From d6e71dd1e49e740d4bb0725cd802dab9008cd394 Mon Sep 17 00:00:00 2001 From: Wu Yunchuan Date: Wed, 22 Nov 2023 20:31:03 +0200 Subject: [PATCH 1765/7721] wifi: ath9k: Remove unnecessary (void*) conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need cast (void *) to (struct owl_ctx *), (struct ath_hw *), (struct cmd_buf *) or other types. Signed-off-by: Wu Yunchuan Reviewed-by: Jeff Johnson Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230919045226.524544-1-yunchuan@nfschina.com --- .../wireless/ath/ath9k/ath9k_pci_owl_loader.c | 2 +- drivers/net/wireless/ath/ath9k/common-init.c | 2 +- .../net/wireless/ath/ath9k/common-spectral.c | 2 +- drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/hif_usb.c | 10 +++--- .../net/wireless/ath/ath9k/htc_drv_debug.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 36 +++++++++---------- drivers/net/wireless/ath/ath9k/htc_hst.c | 2 +- drivers/net/wireless/ath/ath9k/init.c | 12 +++---- drivers/net/wireless/ath/ath9k/link.c | 2 +- drivers/net/wireless/ath/ath9k/pci.c | 6 ++-- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 708c8969b503..a5eb43f30320 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -125,7 +125,7 @@ static void owl_rescan(struct pci_dev *pdev) static void owl_fw_cb(const struct firmware *fw, void *context) { - struct owl_ctx *ctx = (struct owl_ctx *)context; + struct owl_ctx *ctx = context; complete(&ctx->eeprom_load); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 82de0fadbc95..7c13a1deb3ac 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -124,7 +124,7 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { int ath9k_cmn_init_channels_rates(struct ath_common *common) { - struct ath_hw *ah = (struct ath_hw *)common->ah; + struct ath_hw *ah = common->ah; void *channels; BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index a5349c72c332..4b27445a5fb8 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -471,7 +471,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; struct ath_hw *ah = spec_priv->ah; struct ath_common *common = ath9k_hw_common(spec_priv->ah); - struct ath_softc *sc = (struct ath_softc *)common->priv; + struct ath_softc *sc = common->priv; u8 num_bins, *vdata = (u8 *)hdr; struct ath_radar_info *radar_info; int len = rs->rs_datalen; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a0376a6787b8..d84e3ee7b5d9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1376,7 +1376,7 @@ void ath9k_deinit_debug(struct ath_softc *sc) int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; sc->debug.debugfs_phy = debugfs_create_dir("ath9k", sc->hw->wiphy->debugfsdir); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 90cfe39aa433..0c7841f95228 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -70,7 +70,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev); static void hif_usb_regout_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; switch (urb->status) { case 0: @@ -134,7 +134,7 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, static void hif_usb_mgmt_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; struct hif_device_usb *hif_dev; unsigned long flags; bool txok = true; @@ -252,7 +252,7 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, static void hif_usb_tx_cb(struct urb *urb) { - struct tx_buf *tx_buf = (struct tx_buf *) urb->context; + struct tx_buf *tx_buf = urb->context; struct hif_device_usb *hif_dev; bool txok = true; @@ -687,7 +687,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, static void ath9k_hif_usb_rx_cb(struct urb *urb) { - struct rx_buf *rx_buf = (struct rx_buf *)urb->context; + struct rx_buf *rx_buf = urb->context; struct hif_device_usb *hif_dev = rx_buf->hif_dev; struct sk_buff *skb = rx_buf->skb; int ret; @@ -734,7 +734,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) static void ath9k_hif_usb_reg_in_cb(struct urb *urb) { - struct rx_buf *rx_buf = (struct rx_buf *)urb->context; + struct rx_buf *rx_buf = urb->context; struct hif_device_usb *hif_dev = rx_buf->hif_dev; struct sk_buff *skb = rx_buf->skb; int ret; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 278ddc713fdc..f7c6d9bc9311 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -482,7 +482,7 @@ void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, priv->hw->wiphy->debugfsdir); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index dae3d9c7b640..0aa5bdeb44a1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -63,12 +63,12 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { static void ath9k_htc_op_ps_wakeup(struct ath_common *common) { - ath9k_htc_ps_wakeup((struct ath9k_htc_priv *) common->priv); + ath9k_htc_ps_wakeup(common->priv); } static void ath9k_htc_op_ps_restore(struct ath_common *common) { - ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv); + ath9k_htc_ps_restore(common->priv); } static const struct ath_ps_ops ath9k_htc_ps_ops = { @@ -235,7 +235,7 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 val, reg = cpu_to_be32(reg_offset); int r; @@ -257,7 +257,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 tmpaddr[8]; __be32 tmpval[8]; int i, ret; @@ -282,7 +282,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, static void ath9k_regwrite_multi(struct ath_common *common) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -303,7 +303,7 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; const __be32 buf[2] = { cpu_to_be32(reg_offset), cpu_to_be32(val), @@ -324,7 +324,7 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; mutex_lock(&priv->wmi->multi_write_mutex); @@ -347,7 +347,7 @@ static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (atomic_read(&priv->wmi->mwrite_cnt)) ath9k_regwrite_buffer(hw_priv, val, reg_offset); @@ -359,7 +359,7 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; atomic_inc(&priv->wmi->mwrite_cnt); } @@ -368,7 +368,7 @@ static void ath9k_regwrite_flush(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; atomic_dec(&priv->wmi->mwrite_cnt); @@ -385,7 +385,7 @@ static void ath9k_reg_rmw_buffer(void *hw_priv, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -423,7 +423,7 @@ static void ath9k_reg_rmw_flush(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -455,7 +455,7 @@ static void ath9k_enable_rmw_buffer(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) return; @@ -468,7 +468,7 @@ static void ath9k_reg_rmw_single(void *hw_priv, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; struct register_rmw buf, buf_ret; int ret; @@ -490,7 +490,7 @@ static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) { u32 val; @@ -518,7 +518,7 @@ static void ath_usb_read_cachesize(struct ath_common *common, int *csz) static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_hw *ah = common->ah; (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); @@ -970,7 +970,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, err_init: ath9k_stop_wmi(priv); - hif_dev = (struct hif_device_usb *)htc_handle->hif_dev; + hif_dev = htc_handle->hif_dev; ath9k_hif_usb_dealloc_urbs(hif_dev); ath9k_destroy_wmi(priv); err_free: @@ -988,7 +988,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) ath9k_deinit_device(htc_handle->drv_priv); ath9k_stop_wmi(htc_handle->drv_priv); - ath9k_hif_usb_dealloc_urbs((struct hif_device_usb *)htc_handle->hif_dev); + ath9k_hif_usb_dealloc_urbs(htc_handle->hif_dev); ath9k_destroy_wmi(htc_handle->drv_priv); ieee80211_free_hw(htc_handle->drv_priv->hw); } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 99667aba289d..eb631fd3336d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -89,7 +89,7 @@ static void htc_process_target_rdy(struct htc_target *target, void *buf) { struct htc_endpoint *endpoint; - struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf; + struct htc_ready_msg *htc_ready_msg = buf; target->credit_size = be16_to_cpu(htc_ready_msg->credit_size); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4f00400c7ffb..7fad7e75af6a 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -151,12 +151,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc); static void ath9k_op_ps_wakeup(struct ath_common *common) { - ath9k_ps_wakeup((struct ath_softc *) common->priv); + ath9k_ps_wakeup(common->priv); } static void ath9k_op_ps_restore(struct ath_common *common) { - ath9k_ps_restore((struct ath_softc *) common->priv); + ath9k_ps_restore(common->priv); } static const struct ath_ps_ops ath9k_ps_ops = { @@ -174,7 +174,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; @@ -189,7 +189,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -229,7 +229,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; unsigned long flags; u32 val; @@ -608,7 +608,7 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) } /* devres manages the calibration values release on shutdown */ - ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); + ah->nvmem_blob = devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); kfree(buf); if (!ah->nvmem_blob) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 9d84003db800..d1e5767aab3c 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -304,7 +304,7 @@ void ath_paprd_calibrate(struct work_struct *work) void ath_ani_calibrate(struct timer_list *t) { struct ath_common *common = from_timer(common, t, ani.timer); - struct ath_softc *sc = (struct ath_softc *)common->priv; + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; bool longcal = false; bool shortcal = false; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 0633589b85c2..e655cd8bbf94 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -781,7 +781,7 @@ static const struct pci_device_id ath_pci_id_table[] = { /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u8 u8tmp; pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); @@ -799,7 +799,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_hw *ah = common->ah; common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); @@ -820,7 +820,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) /* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; struct pci_dev *pdev = to_pci_dev(sc->dev); struct pci_dev *parent; From 2adc886244dff60f948497b59affb6c6ebb3c348 Mon Sep 17 00:00:00 2001 From: Minsuk Kang Date: Wed, 22 Nov 2023 20:31:04 +0200 Subject: [PATCH 1766/7721] wifi: ath9k: Fix potential array-index-out-of-bounds read in ath9k_htc_txstatus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix an array-index-out-of-bounds read in ath9k_htc_txstatus(). The bug occurs when txs->cnt, data from a URB provided by a USB device, is bigger than the size of the array txs->txstatus, which is HTC_MAX_TX_STATUS. WARN_ON() already checks it, but there is no bug handling code after the check. Make the function return if that is the case. Found by a modified version of syzkaller. UBSAN: array-index-out-of-bounds in htc_drv_txrx.c index 13 is out of range for type '__wmi_event_txstatus [12]' Call Trace: ath9k_htc_txstatus ath9k_wmi_event_tasklet tasklet_action_common __do_softirq irq_exit_rxu sysvec_apic_timer_interrupt Signed-off-by: Minsuk Kang Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231113065756.1491991-1-linuxlovemin@yonsei.ac.kr --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 800177021baf..efcaeccb055a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -652,9 +652,10 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) struct ath9k_htc_tx_event *tx_pend; int i; - for (i = 0; i < txs->cnt; i++) { - WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); + if (WARN_ON_ONCE(txs->cnt > HTC_MAX_TX_STATUS)) + return; + for (i = 0; i < txs->cnt; i++) { __txs = &txs->txstatus[i]; skb = ath9k_htc_tx_get_packet(priv, __txs); From 014fdeb0d747304111cfecf93df4407c1a0c80db Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:15 +0200 Subject: [PATCH 1767/7721] ASoC: SOF: Move sof_of_machine_select() to sof-of-dev.c from sof-audio.c Move the sof_of_machine_select() function to sof-of-dev.c file and provide an inline stub in case of non OF builds. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 22 ---------------------- sound/soc/sof/sof-of-dev.c | 23 +++++++++++++++++++++++ sound/soc/sof/sof-of-dev.h | 9 +++++++++ 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 563fe6f7789f..2198bb8e92c3 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -990,28 +990,6 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL(sof_dai_get_bclk); -static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *sof_pdata = sdev->pdata; - const struct sof_dev_desc *desc = sof_pdata->desc; - struct snd_sof_of_mach *mach = desc->of_machines; - - if (!mach) - return NULL; - - for (; mach->compatible; mach++) { - if (of_machine_is_compatible(mach->compatible)) { - sof_pdata->tplg_filename = mach->sof_tplg_filename; - if (mach->fw_filename) - sof_pdata->fw_filename = mach->fw_filename; - - return mach; - } - } - - return NULL; -} - /* * SOF Driver enumeration. */ diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index c6be8a91e74b..432b511bf8c4 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -41,6 +41,29 @@ static void sof_of_probe_complete(struct device *dev) pm_runtime_enable(dev); } +struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_sof_of_mach *mach = desc->of_machines; + + if (!mach) + return NULL; + + for (; mach->compatible; mach++) { + if (of_machine_is_compatible(mach->compatible)) { + sof_pdata->tplg_filename = mach->sof_tplg_filename; + if (mach->fw_filename) + sof_pdata->fw_filename = mach->fw_filename; + + return mach; + } + } + + return NULL; +} +EXPORT_SYMBOL(sof_of_machine_select); + int sof_of_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/sound/soc/sof/sof-of-dev.h b/sound/soc/sof/sof-of-dev.h index b6cc70595f3b..547e358a37e3 100644 --- a/sound/soc/sof/sof-of-dev.h +++ b/sound/soc/sof/sof-of-dev.h @@ -16,6 +16,15 @@ struct snd_sof_of_mach { const char *sof_tplg_filename; }; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_OF_DEV) +struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev); +#else +static inline struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) +{ + return NULL; +} +#endif + extern const struct dev_pm_ops sof_of_pm; int sof_of_probe(struct platform_device *pdev); From 3bc3477915587440035f192c89a1bf9a4360abb3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:16 +0200 Subject: [PATCH 1768/7721] ASoC: SOF: Move sof_machine_* functions from sof-audio.c to core.c Relocate the machine handling functions from sof-audio.c to core.c to maintain code separation. While doing the move, drop the redundant IS_ERR_OR_NULL(plat_data->pdev_mach) check from sof_machine_unregister() Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 95 +++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.c | 98 --------------------------------------- sound/soc/sof/sof-priv.h | 2 - 3 files changed, 95 insertions(+), 100 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index d7b090224f1b..a87522ea4301 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -13,6 +13,7 @@ #include #include #include "sof-priv.h" +#include "sof-of-dev.h" #include "ops.h" #define CREATE_TRACE_POINTS @@ -143,6 +144,66 @@ void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state) } EXPORT_SYMBOL(sof_set_fw_state); +/* SOF Driver enumeration */ +static int sof_machine_check(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { + const struct snd_sof_of_mach *of_mach; + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + goto nocodec; + + /* find machine */ + mach = snd_sof_machine_select(sdev); + if (mach) { + sof_pdata->machine = mach; + + if (sof_pdata->subsystem_id_set) { + mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor; + mach->mach_params.subsystem_device = sof_pdata->subsystem_device; + mach->mach_params.subsystem_id_set = true; + } + + snd_sof_set_mach_params(mach, sdev); + return 0; + } + + of_mach = sof_of_machine_select(sdev); + if (of_mach) { + sof_pdata->of_machine = of_mach; + return 0; + } + + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; + } + } else { + dev_warn(sdev->dev, "Force to use nocodec mode\n"); + } + +nocodec: + /* select nocodec mode */ + dev_warn(sdev->dev, "Using nocodec machine driver\n"); + mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + + mach->drv_name = "sof-nocodec"; + if (!sof_pdata->tplg_filename) + sof_pdata->tplg_filename = desc->nocodec_tplg_filename; + + sof_pdata->machine = mach; + snd_sof_set_mach_params(mach, sdev); + + return 0; +} + /* * FW Boot State Transition Diagram * @@ -527,6 +588,40 @@ int snd_sof_device_shutdown(struct device *dev) } EXPORT_SYMBOL(snd_sof_device_shutdown); +/* Machine driver registering and unregistering */ +int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) +{ + struct snd_sof_pdata *plat_data = pdata; + const char *drv_name; + const void *mach; + int size; + + drv_name = plat_data->machine->drv_name; + mach = plat_data->machine; + size = sizeof(*plat_data->machine); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(sdev->dev, drv_name, + PLATFORM_DEVID_NONE, mach, size); + if (IS_ERR(plat_data->pdev_mach)) + return PTR_ERR(plat_data->pdev_mach); + + dev_dbg(sdev->dev, "created machine %s\n", + dev_name(&plat_data->pdev_mach->dev)); + + return 0; +} +EXPORT_SYMBOL(sof_machine_register); + +void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) +{ + struct snd_sof_pdata *plat_data = pdata; + + platform_device_unregister(plat_data->pdev_mach); +} +EXPORT_SYMBOL(sof_machine_unregister); + MODULE_AUTHOR("Liam Girdwood"); MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 2198bb8e92c3..de40a5e227f4 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -11,7 +11,6 @@ #include #include #include "sof-audio.h" -#include "sof-of-dev.h" #include "ops.h" static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, @@ -989,100 +988,3 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); } EXPORT_SYMBOL(sof_dai_get_bclk); - -/* - * SOF Driver enumeration. - */ -int sof_machine_check(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *sof_pdata = sdev->pdata; - const struct sof_dev_desc *desc = sof_pdata->desc; - struct snd_soc_acpi_mach *mach; - - if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { - const struct snd_sof_of_mach *of_mach; - - if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && - sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) - goto nocodec; - - /* find machine */ - mach = snd_sof_machine_select(sdev); - if (mach) { - sof_pdata->machine = mach; - - if (sof_pdata->subsystem_id_set) { - mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor; - mach->mach_params.subsystem_device = sof_pdata->subsystem_device; - mach->mach_params.subsystem_id_set = true; - } - - snd_sof_set_mach_params(mach, sdev); - return 0; - } - - of_mach = sof_of_machine_select(sdev); - if (of_mach) { - sof_pdata->of_machine = of_mach; - return 0; - } - - if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { - dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; - } - } else { - dev_warn(sdev->dev, "Force to use nocodec mode\n"); - } - -nocodec: - /* select nocodec mode */ - dev_warn(sdev->dev, "Using nocodec machine driver\n"); - mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); - if (!mach) - return -ENOMEM; - - mach->drv_name = "sof-nocodec"; - if (!sof_pdata->tplg_filename) - sof_pdata->tplg_filename = desc->nocodec_tplg_filename; - - sof_pdata->machine = mach; - snd_sof_set_mach_params(mach, sdev); - - return 0; -} -EXPORT_SYMBOL(sof_machine_check); - -int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) -{ - struct snd_sof_pdata *plat_data = pdata; - const char *drv_name; - const void *mach; - int size; - - drv_name = plat_data->machine->drv_name; - mach = plat_data->machine; - size = sizeof(*plat_data->machine); - - /* register machine driver, pass machine info as pdata */ - plat_data->pdev_mach = - platform_device_register_data(sdev->dev, drv_name, - PLATFORM_DEVID_NONE, mach, size); - if (IS_ERR(plat_data->pdev_mach)) - return PTR_ERR(plat_data->pdev_mach); - - dev_dbg(sdev->dev, "created machine %s\n", - dev_name(&plat_data->pdev_mach->dev)); - - return 0; -} -EXPORT_SYMBOL(sof_machine_register); - -void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) -{ - struct snd_sof_pdata *plat_data = pdata; - - if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) - platform_device_unregister(plat_data->pdev_mach); -} -EXPORT_SYMBOL(sof_machine_unregister); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f4185012eb69..faa8a19ed737 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -814,8 +814,6 @@ int sof_stream_pcm_open(struct snd_sof_dev *sdev, int sof_stream_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); -int sof_machine_check(struct snd_sof_dev *sdev); - /* SOF client support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_CLIENT) int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, From 1162d267eabd6392d0d07bc88b75056e88042fc0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:17 +0200 Subject: [PATCH 1769/7721] ASoC: SOF: Add placeholder for platform IPC type and path overrides Add a struct sof_loadable_file_profile which can be filled by platforms (sof-acpi-dev.c, sof-of-dev.c and sof-acpi-dev.c) to be able to use common, generic code to handle path customization. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 268d0ca0f69f..05213bb515a3 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -57,6 +57,18 @@ enum sof_ipc_type { SOF_IPC_TYPE_COUNT }; +struct sof_loadable_file_profile { + enum sof_ipc_type ipc_type; + + const char *fw_path; + const char *fw_path_postfix; + const char *fw_name; + const char *fw_lib_path; + const char *fw_lib_path_postfix; + const char *tplg_path; + const char *tplg_name; +}; + /* * SOF Platform data. */ @@ -86,6 +98,9 @@ struct snd_sof_pdata { /* descriptor */ const struct sof_dev_desc *desc; + /* platform's preferred IPC type and path overrides */ + struct sof_loadable_file_profile ipc_file_profile_base; + /* firmware and topology filenames */ const char *fw_filename_prefix; const char *fw_filename; From a07625dcaf994ab3c5a6a456624719df05ed8ad6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:18 +0200 Subject: [PATCH 1770/7721] ASoC: SOF: sof-acpi-dev: Save the default IPC type and path overrides Store the default IPC type and the firmware and topology path overrides to ipc_file_profile_base Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-acpi-dev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 84a4a0a3318e..87c0c2edc4c9 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -87,6 +87,10 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc else sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3]; + sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; + sof_pdata->ipc_file_profile_base.fw_path = fw_path; + sof_pdata->ipc_file_profile_base.tplg_path = tplg_path; + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_acpi_probe_complete; From 396016d56da4ad30fe9ff736e44d9e1457484805 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:19 +0200 Subject: [PATCH 1771/7721] ASoC: SOF: sof-of-dev: Save the default IPC type and path overrides Store the default IPC type and the firmware and topology path overrides to ipc_file_profile_base Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-of-dev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 432b511bf8c4..7b58f45790f7 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -99,6 +99,10 @@ int sof_of_probe(struct platform_device *pdev) else sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3]; + sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; + sof_pdata->ipc_file_profile_base.fw_path = fw_path; + sof_pdata->ipc_file_profile_base.tplg_path = tplg_path; + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_of_probe_complete; From 59ddeae037b81303063bcf62b70fb33841b3f89e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:20 +0200 Subject: [PATCH 1772/7721] ASoC: SOF: sof-pci-dev: Save the default IPC type and path overrides Store the default IPC type and the overrides to ipc_file_profile_base Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 64b326e3ef85..becc85b27d51 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -190,6 +190,7 @@ static void sof_pci_probe_complete(struct device *dev) int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { + struct sof_loadable_file_profile *path_override; struct device *dev = &pci->dev; const struct sof_dev_desc *desc = (const struct sof_dev_desc *)pci_id->driver_data; @@ -334,6 +335,20 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) sof_pdata->tplg_filename = sof_dmi_override_tplg_name; } + path_override = &sof_pdata->ipc_file_profile_base; + path_override->ipc_type = sof_pdata->ipc_type; + path_override->fw_path = fw_path; + path_override->fw_name = fw_filename; + path_override->fw_lib_path = lib_path; + path_override->tplg_path = tplg_path; + path_override->tplg_name = sof_pdata->tplg_filename; + + if (dmi_check_system(community_key_platforms) && + sof_dmi_use_community_key) { + path_override->fw_path_postfix = "community"; + path_override->fw_lib_path_postfix = "community"; + } + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_pci_probe_complete; From b1a4ee9fd5a2dfb0f23abe58377f816915ec14ba Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:21 +0200 Subject: [PATCH 1773/7721] ASoC: SOF: core: Implement firmware, topology path setup in core Use the information stored in ipc_file_profile_base by platforms to construct the paths, filenames that are going to be used to load the firmware and topology files. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Makefile | 3 +- sound/soc/sof/core.c | 70 +++++++++++++++-- sound/soc/sof/fw-file-profile.c | 130 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 7 ++ 4 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 sound/soc/sof/fw-file-profile.c diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index ef6fd43d0b72..3624124575af 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o + control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\ + fw-file-profile.o # IPC implementations ifneq ($(CONFIG_SND_SOC_SOF_IPC3),) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a87522ea4301..f1a083de9f9e 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -204,6 +204,67 @@ static int sof_machine_check(struct snd_sof_dev *sdev) return 0; } +static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base; + struct sof_loadable_file_profile out_profile; + struct device *dev = sdev->dev; + int ret; + + /* check IPC support */ + if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) { + dev_err(dev, + "ipc_type %d is not supported on this platform, mask is %#x\n", + base_profile->ipc_type, plat_data->desc->ipc_supported_mask); + return -EINVAL; + } + + if (base_profile->ipc_type != plat_data->desc->ipc_default) + dev_info(dev, + "Module parameter used, overriding default IPC %d to %d\n", + plat_data->desc->ipc_default, base_profile->ipc_type); + + if (base_profile->fw_path) + dev_dbg(dev, "Module parameter used, changed fw path to %s\n", + base_profile->fw_path); + else if (base_profile->fw_path_postfix) + dev_dbg(dev, "Path postfix appended to default fw path: %s\n", + base_profile->fw_path_postfix); + + if (base_profile->fw_lib_path) + dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n", + base_profile->fw_lib_path); + else if (base_profile->fw_lib_path_postfix) + dev_dbg(dev, "Path postfix appended to default fw_lib path: %s\n", + base_profile->fw_lib_path_postfix); + + if (base_profile->fw_name) + dev_dbg(dev, "Module parameter used, changed fw filename to %s\n", + base_profile->fw_name); + + if (base_profile->tplg_path) + dev_dbg(dev, "Module parameter used, changed tplg path to %s\n", + base_profile->tplg_path); + + if (base_profile->tplg_name) + dev_dbg(dev, "Module parameter used, changed tplg name to %s\n", + base_profile->tplg_name); + + ret = sof_create_ipc_file_profile(sdev, base_profile, &out_profile); + if (ret) + return ret; + + plat_data->ipc_type = out_profile.ipc_type; + plat_data->fw_filename = out_profile.fw_name; + plat_data->fw_filename_prefix = out_profile.fw_path; + plat_data->fw_lib_prefix = out_profile.fw_lib_path; + plat_data->tplg_filename_prefix = out_profile.tplg_path; + plat_data->tplg_filename = out_profile.tplg_name; + + return 0; +} + /* * FW Boot State Transition Diagram * @@ -442,12 +503,9 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } } - /* check IPC support */ - if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) { - dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n", - plat_data->ipc_type, plat_data->desc->ipc_supported_mask); - return -EINVAL; - } + ret = sof_select_ipc_and_paths(sdev); + if (ret) + return ret; /* init ops, if necessary */ ret = sof_ops_init(sdev); diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c new file mode 100644 index 000000000000..58b55516049e --- /dev/null +++ b/sound/soc/sof/fw-file-profile.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// + +#include +#include "sof-priv.h" + +static int +sof_file_profile_for_ipc_type(struct device *dev, + const struct sof_dev_desc *desc, + struct sof_loadable_file_profile *base_profile, + struct sof_loadable_file_profile *out_profile) +{ + enum sof_ipc_type ipc_type = base_profile->ipc_type; + bool fw_lib_path_allocated = false; + bool fw_path_allocated = false; + int ret = 0; + + /* firmware path */ + if (base_profile->fw_path) { + out_profile->fw_path = base_profile->fw_path; + } else if (base_profile->fw_path_postfix) { + out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s", + desc->default_fw_path[ipc_type], + base_profile->fw_path_postfix); + if (!out_profile->fw_path) + return -ENOMEM; + + fw_path_allocated = true; + } else { + out_profile->fw_path = desc->default_fw_path[ipc_type]; + } + + /* firmware filename */ + if (base_profile->fw_name) + out_profile->fw_name = base_profile->fw_name; + else + out_profile->fw_name = desc->default_fw_filename[ipc_type]; + + + /* firmware library path */ + if (base_profile->fw_lib_path) { + out_profile->fw_lib_path = base_profile->fw_lib_path; + } else if (desc->default_lib_path[ipc_type]) { + if (base_profile->fw_lib_path_postfix) { + out_profile->fw_lib_path = devm_kasprintf(dev, + GFP_KERNEL, "%s/%s", + desc->default_lib_path[ipc_type], + base_profile->fw_lib_path_postfix); + if (!out_profile->fw_lib_path) { + ret = -ENOMEM; + goto out; + } + + fw_lib_path_allocated = true; + } else { + out_profile->fw_lib_path = desc->default_lib_path[ipc_type]; + } + } + + if (base_profile->fw_path_postfix) + out_profile->fw_path_postfix = base_profile->fw_path_postfix; + + if (base_profile->fw_lib_path_postfix) + out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix; + + /* topology path */ + if (base_profile->tplg_path) + out_profile->tplg_path = base_profile->tplg_path; + else + out_profile->tplg_path = desc->default_tplg_path[ipc_type]; + + /* topology name */ + if (base_profile->tplg_name) + out_profile->tplg_name = base_profile->tplg_name; + + out_profile->ipc_type = ipc_type; + +out: + if (ret) { + /* Free up path strings created with devm_kasprintf */ + if (fw_path_allocated) + devm_kfree(dev, out_profile->fw_path); + if (fw_lib_path_allocated) + devm_kfree(dev, out_profile->fw_lib_path); + + memset(out_profile, 0, sizeof(*out_profile)); + } + + return ret; +} + +static void sof_print_profile_info(struct device *dev, + struct sof_loadable_file_profile *profile) +{ + dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); + + dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); + if (profile->fw_lib_path) + dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); + if (profile->tplg_name) + dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, + profile->tplg_name); + else + dev_info(dev, " Topology path: %s\n", profile->tplg_path); +} + +int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, + struct sof_loadable_file_profile *base_profile, + struct sof_loadable_file_profile *out_profile) +{ + const struct sof_dev_desc *desc = sdev->pdata->desc; + struct device *dev = sdev->dev; + int ret; + + memset(out_profile, 0, sizeof(*out_profile)); + + ret = sof_file_profile_for_ipc_type(dev, desc, base_profile, out_profile); + if (ret) + return ret; + + sof_print_profile_info(dev, out_profile); + + return 0; +} +EXPORT_SYMBOL(sof_create_ipc_file_profile); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index faa8a19ed737..6d7897bf9607 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -695,6 +695,13 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); */ extern struct snd_compress_ops sof_compressed_ops; +/* + * Firmware (firmware, libraries, topologies) file location + */ +int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, + struct sof_loadable_file_profile *base_profile, + struct sof_loadable_file_profile *out_profile); + /* * Firmware loading. */ From b2b0bba36f0a81743e7143a8801ca75d2238bdac Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:22 +0200 Subject: [PATCH 1774/7721] ASoC: SOF: sof-acpi-dev: Rely on core to create the file paths The core is now using the information from ipc_file_profile_base to create the paths for the loadable files, no need to set it in here anymore. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-9-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-acpi-dev.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 87c0c2edc4c9..2977f0a63fba 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -74,18 +74,6 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc sof_pdata->desc = desc; sof_pdata->dev = &pdev->dev; - sof_pdata->fw_filename = desc->default_fw_filename[SOF_IPC_TYPE_3]; - - /* alternate fw and tplg filenames ? */ - if (fw_path) - sof_pdata->fw_filename_prefix = fw_path; - else - sof_pdata->fw_filename_prefix = desc->default_fw_path[SOF_IPC_TYPE_3]; - - if (tplg_path) - sof_pdata->tplg_filename_prefix = tplg_path; - else - sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3]; sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; sof_pdata->ipc_file_profile_base.fw_path = fw_path; From 8616168928f278723fdc3f4d7cd3d611dcdae8f8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:23 +0200 Subject: [PATCH 1775/7721] ASoC: SOF: sof-of-dev: Rely on core to create the file paths The core is now using the information from ipc_file_profile_base to create the paths for the loadable files, no need to set it in here anymore. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-10-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-of-dev.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 7b58f45790f7..fa92da5ee9b3 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -87,17 +87,6 @@ int sof_of_probe(struct platform_device *pdev) sof_pdata->desc = desc; sof_pdata->dev = &pdev->dev; - sof_pdata->fw_filename = desc->default_fw_filename[SOF_IPC_TYPE_3]; - - if (fw_path) - sof_pdata->fw_filename_prefix = fw_path; - else - sof_pdata->fw_filename_prefix = desc->default_fw_path[SOF_IPC_TYPE_3]; - - if (tplg_path) - sof_pdata->tplg_filename_prefix = tplg_path; - else - sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3]; sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; sof_pdata->ipc_file_profile_base.fw_path = fw_path; From 8a83f180abb5b95f524fc9b5eb2291f0e39bed30 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:24 +0200 Subject: [PATCH 1776/7721] ASoC: SOF: sof-pci-dev: Rely on core to create the file paths The core is now using the information from ipc_file_profile_base to create the paths for the loadable files, no need to set it in here anymore. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-11-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 115 ++++++------------------------------ 1 file changed, 17 insertions(+), 98 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index becc85b27d51..aab5c900cecf 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -233,120 +233,39 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) sof_pdata->desc = desc; sof_pdata->dev = dev; - sof_pdata->ipc_type = desc->ipc_default; + path_override = &sof_pdata->ipc_file_profile_base; if (sof_pci_ipc_type < 0) { - sof_pdata->ipc_type = desc->ipc_default; + path_override->ipc_type = desc->ipc_default; + } else if (sof_pci_ipc_type < SOF_IPC_TYPE_COUNT) { + path_override->ipc_type = sof_pci_ipc_type; } else { - dev_info(dev, "overriding default IPC %d to requested %d\n", - desc->ipc_default, sof_pci_ipc_type); - if (sof_pci_ipc_type >= SOF_IPC_TYPE_COUNT) { - dev_err(dev, "invalid request value %d\n", sof_pci_ipc_type); - ret = -EINVAL; - goto out; - } - if (!(BIT(sof_pci_ipc_type) & desc->ipc_supported_mask)) { - dev_err(dev, "invalid request value %d, supported mask is %#x\n", - sof_pci_ipc_type, desc->ipc_supported_mask); - ret = -EINVAL; - goto out; - } - sof_pdata->ipc_type = sof_pci_ipc_type; + dev_err(dev, "Invalid IPC type requested: %d\n", sof_pci_ipc_type); + ret = -EINVAL; + goto out; } - if (fw_filename) { - sof_pdata->fw_filename = fw_filename; + path_override->fw_path = fw_path; + path_override->fw_name = fw_filename; + path_override->fw_lib_path = lib_path; + path_override->tplg_path = tplg_path; - dev_dbg(dev, "Module parameter used, changed fw filename to %s\n", - sof_pdata->fw_filename); - } else { - sof_pdata->fw_filename = desc->default_fw_filename[sof_pdata->ipc_type]; + if (dmi_check_system(community_key_platforms) && + sof_dmi_use_community_key) { + path_override->fw_path_postfix = "community"; + path_override->fw_lib_path_postfix = "community"; } - /* - * for platforms using the SOF community key, change the - * default path automatically to pick the right files from the - * linux-firmware tree. This can be overridden with the - * fw_path kernel parameter, e.g. for developers. - */ - - /* alternate fw and tplg filenames ? */ - if (fw_path) { - sof_pdata->fw_filename_prefix = fw_path; - - dev_dbg(dev, - "Module parameter used, changed fw path to %s\n", - sof_pdata->fw_filename_prefix); - - } else if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) { - sof_pdata->fw_filename_prefix = - devm_kasprintf(dev, GFP_KERNEL, "%s/%s", - sof_pdata->desc->default_fw_path[sof_pdata->ipc_type], - "community"); - - dev_dbg(dev, - "Platform uses community key, changed fw path to %s\n", - sof_pdata->fw_filename_prefix); - } else { - sof_pdata->fw_filename_prefix = - sof_pdata->desc->default_fw_path[sof_pdata->ipc_type]; - } - - if (lib_path) { - sof_pdata->fw_lib_prefix = lib_path; - - dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n", - sof_pdata->fw_lib_prefix); - - } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) { - if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) { - sof_pdata->fw_lib_prefix = - devm_kasprintf(dev, GFP_KERNEL, "%s/%s", - sof_pdata->desc->default_lib_path[sof_pdata->ipc_type], - "community"); - - dev_dbg(dev, - "Platform uses community key, changed fw_lib path to %s\n", - sof_pdata->fw_lib_prefix); - } else { - sof_pdata->fw_lib_prefix = - sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]; - } - } - - if (tplg_path) - sof_pdata->tplg_filename_prefix = tplg_path; - else - sof_pdata->tplg_filename_prefix = - sof_pdata->desc->default_tplg_path[sof_pdata->ipc_type]; - /* * the topology filename will be provided in the machine descriptor, unless * it is overridden by a module parameter or DMI quirk. */ if (tplg_filename) { - sof_pdata->tplg_filename = tplg_filename; - - dev_dbg(dev, "Module parameter used, changed tplg filename to %s\n", - sof_pdata->tplg_filename); + path_override->tplg_name = tplg_filename; } else { dmi_check_system(sof_tplg_table); if (sof_dmi_override_tplg_name) - sof_pdata->tplg_filename = sof_dmi_override_tplg_name; - } - - path_override = &sof_pdata->ipc_file_profile_base; - path_override->ipc_type = sof_pdata->ipc_type; - path_override->fw_path = fw_path; - path_override->fw_name = fw_filename; - path_override->fw_lib_path = lib_path; - path_override->tplg_path = tplg_path; - path_override->tplg_name = sof_pdata->tplg_filename; - - if (dmi_check_system(community_key_platforms) && - sof_dmi_use_community_key) { - path_override->fw_path_postfix = "community"; - path_override->fw_lib_path_postfix = "community"; + path_override->tplg_name = sof_dmi_override_tplg_name; } /* set callback to be called on successful device probe to enable runtime_pm */ From a5a65437b02df8b842c4620b0b776bcd91ce200a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:25 +0200 Subject: [PATCH 1777/7721] ASoC: SOF: core: Add helper for initialization of paths, ops Add sof_init_environment() as a helper function to contain path and ops initialization. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-12-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index f1a083de9f9e..a2e9506e0f85 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -265,6 +265,38 @@ static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev) return 0; } +static int sof_init_environment(struct snd_sof_dev *sdev) +{ + int ret; + + ret = sof_select_ipc_and_paths(sdev); + if (ret) + return ret; + + /* init ops, if necessary */ + ret = sof_ops_init(sdev); + if (ret < 0) + return ret; + + /* check all mandatory ops */ + if (!sof_ops(sdev) || !sof_ops(sdev)->probe) { + dev_err(sdev->dev, "missing mandatory ops\n"); + sof_ops_free(sdev); + return -EINVAL; + } + + if (!sdev->dspless_mode_selected && + (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read || + !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || + !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) { + dev_err(sdev->dev, "missing mandatory DSP ops\n"); + sof_ops_free(sdev); + return -EINVAL; + } + + return 0; +} + /* * FW Boot State Transition Diagram * @@ -503,31 +535,11 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } } - ret = sof_select_ipc_and_paths(sdev); + /* Initialize loadable file paths and check the environment validity */ + ret = sof_init_environment(sdev); if (ret) return ret; - /* init ops, if necessary */ - ret = sof_ops_init(sdev); - if (ret < 0) - return ret; - - /* check all mandatory ops */ - if (!sof_ops(sdev) || !sof_ops(sdev)->probe) { - sof_ops_free(sdev); - dev_err(dev, "missing mandatory ops\n"); - return -EINVAL; - } - - if (!sdev->dspless_mode_selected && - (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read || - !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || - !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) { - sof_ops_free(sdev); - dev_err(dev, "missing mandatory DSP ops\n"); - return -EINVAL; - } - INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); From 9b6896538ea71b7c24da1ecb38738a311176f6a8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:26 +0200 Subject: [PATCH 1778/7721] ASoC: SOF: Intel: Do not use resource managed allocation for ipc4_data Manage the ipc4_data allocation in code instead of devm since the ops_init might be called more than once due to IPC type fallback. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-13-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 2 +- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-dai.c | 3 +++ sound/soc/sof/intel/icl.c | 2 +- sound/soc/sof/intel/lnl.c | 2 +- sound/soc/sof/intel/mtl.c | 2 +- sound/soc/sof/intel/skl.c | 2 +- sound/soc/sof/intel/tgl.c | 2 +- 8 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 776b66389c34..dee6c7f73e80 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -55,7 +55,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_fw_data *ipc4_data; - sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 598cf50abadb..85e1e4760d0e 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -402,7 +402,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_fw_data *ipc4_data; - sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a20deaf3b428..f4cbc0ad5de3 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -621,6 +621,9 @@ void hda_ops_free(struct snd_sof_dev *sdev) if (!hda_use_tplg_nhlt) intel_nhlt_free(ipc4_data->nhlt); + + kfree(sdev->private); + sdev->private = NULL; } } EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 8e29d6bb6fe8..040698591992 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -123,7 +123,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_fw_data *ipc4_data; - sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index db94b45e53af..03308721ebd4 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -120,7 +120,7 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; - sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 3ef9e5c37028..f941e2c49d78 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -709,7 +709,7 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; - sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index d24e64e71b58..93824e6ce573 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -62,7 +62,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev) /* probe/remove/shutdown */ sof_skl_ops.shutdown = hda_dsp_shutdown; - sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index f7de1f5ba06d..d890cac6cb01 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -82,7 +82,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_fw_data *ipc4_data; - sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; From 6c393ebbd74ad341bcfb4e2d0091b2655fad45d0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:53:27 +0200 Subject: [PATCH 1779/7721] ASoC: SOF: core: Implement IPC version fallback if firmware files are missing If a firmware file is missing for the selected IPC type then try to switch to other supported IPC type and check if that one can be used instead. If for example a platform is changed to IPC4 as default version but the given machine does not yet have the needed topology file created then we will fall back to IPC3 which should have all the needed files. Relocate the sof_init_environment() to be done at a later phase, in sof_probe_continue(). This will only have changes in behavior if CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE is enabled (Intel HDA platforms) by not failing the module probe, but it is not going to be different case compared to for example failed firmware booting or topology loading error. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20231129125327.23708-14-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 11 ++ sound/soc/sof/core.c | 104 ++++++++++----- sound/soc/sof/fw-file-profile.c | 226 +++++++++++++++++++++++++++++--- 3 files changed, 292 insertions(+), 49 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index a741ed96e789..32ffd345e07f 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -126,6 +126,17 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS If you are not involved in SOF releases and CI development, select "N". +config SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION + bool "SOF allow fallback to newer IPC version" + help + This option will allow the kernel to try to 'fallback' to a newer IPC + version if there are missing firmware files to satisfy the default IPC + version. + IPC version fallback to older versions is not affected by this option, + it is always available. + Say Y if you are involved in SOF development and need this option. + If not, select N. + config SND_SOC_SOF_DEBUG bool "SOF debugging features" help diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a2e9506e0f85..a2afec8f5879 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -212,14 +212,6 @@ static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev) struct device *dev = sdev->dev; int ret; - /* check IPC support */ - if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) { - dev_err(dev, - "ipc_type %d is not supported on this platform, mask is %#x\n", - base_profile->ipc_type, plat_data->desc->ipc_supported_mask); - return -EINVAL; - } - if (base_profile->ipc_type != plat_data->desc->ipc_default) dev_info(dev, "Module parameter used, overriding default IPC %d to %d\n", @@ -260,19 +252,14 @@ static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev) plat_data->fw_filename_prefix = out_profile.fw_path; plat_data->fw_lib_prefix = out_profile.fw_lib_path; plat_data->tplg_filename_prefix = out_profile.tplg_path; - plat_data->tplg_filename = out_profile.tplg_name; return 0; } -static int sof_init_environment(struct snd_sof_dev *sdev) +static int validate_sof_ops(struct snd_sof_dev *sdev) { int ret; - ret = sof_select_ipc_and_paths(sdev); - if (ret) - return ret; - /* init ops, if necessary */ ret = sof_ops_init(sdev); if (ret < 0) @@ -297,6 +284,71 @@ static int sof_init_environment(struct snd_sof_dev *sdev) return 0; } +static int sof_init_sof_ops(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base; + + /* check IPC support */ + if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) { + dev_err(sdev->dev, + "ipc_type %d is not supported on this platform, mask is %#x\n", + base_profile->ipc_type, plat_data->desc->ipc_supported_mask); + return -EINVAL; + } + + /* + * Save the selected IPC type and a topology name override before + * selecting ops since platform code might need this information + */ + plat_data->ipc_type = base_profile->ipc_type; + plat_data->tplg_filename = base_profile->tplg_name; + + return validate_sof_ops(sdev); +} + +static int sof_init_environment(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base; + int ret; + + /* probe the DSP hardware */ + ret = snd_sof_probe(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to probe DSP %d\n", ret); + sof_ops_free(sdev); + return ret; + } + + /* check machine info */ + ret = sof_machine_check(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to get machine info %d\n", ret); + goto err_machine_check; + } + + ret = sof_select_ipc_and_paths(sdev); + if (!ret && plat_data->ipc_type != base_profile->ipc_type) { + /* IPC type changed, re-initialize the ops */ + sof_ops_free(sdev); + + ret = validate_sof_ops(sdev); + if (ret < 0) { + snd_sof_remove(sdev); + return ret; + } + } + +err_machine_check: + if (ret) { + snd_sof_remove(sdev); + sof_ops_free(sdev); + } + + return ret; +} + /* * FW Boot State Transition Diagram * @@ -342,23 +394,13 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) struct snd_sof_pdata *plat_data = sdev->pdata; int ret; - /* probe the DSP hardware */ - ret = snd_sof_probe(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); - goto probe_err; - } + /* Initialize loadable file paths and check the environment validity */ + ret = sof_init_environment(sdev); + if (ret) + return ret; sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); - /* check machine info */ - ret = sof_machine_check(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to get machine info %d\n", - ret); - goto dsp_err; - } - /* set up platform component driver */ snd_sof_new_platform_drv(sdev); @@ -478,9 +520,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ipc_err: dbg_err: snd_sof_free_debug(sdev); -dsp_err: snd_sof_remove(sdev); -probe_err: snd_sof_remove_late(sdev); sof_ops_free(sdev); @@ -535,8 +575,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } } - /* Initialize loadable file paths and check the environment validity */ - ret = sof_init_environment(sdev); + /* Initialize sof_ops based on the initial selected IPC version */ + ret = sof_init_sof_ops(sdev); if (ret) return ret; diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c index 58b55516049e..138a1ca2c4a8 100644 --- a/sound/soc/sof/fw-file-profile.c +++ b/sound/soc/sof/fw-file-profile.c @@ -6,17 +6,99 @@ // Copyright(c) 2023 Intel Corporation. All rights reserved. // +#include #include +#include #include "sof-priv.h" +static int sof_test_firmware_file(struct device *dev, + struct sof_loadable_file_profile *profile, + enum sof_ipc_type *ipc_type_to_adjust) +{ + enum sof_ipc_type fw_ipc_type; + const struct firmware *fw; + const char *fw_filename; + const u32 *magic; + int ret; + + fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path, + profile->fw_name); + if (!fw_filename) + return -ENOMEM; + + ret = firmware_request_nowarn(&fw, fw_filename, dev); + if (ret < 0) { + dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename); + kfree(fw_filename); + return ret; + } + + /* firmware file exists, check the magic number */ + magic = (const u32 *)fw->data; + switch (*magic) { + case SOF_EXT_MAN_MAGIC_NUMBER: + fw_ipc_type = SOF_IPC_TYPE_3; + break; + case SOF_EXT_MAN4_MAGIC_NUMBER: + fw_ipc_type = SOF_IPC_TYPE_4; + break; + default: + dev_err(dev, "Invalid firmware magic: %#x\n", *magic); + ret = -EINVAL; + goto out; + } + + if (ipc_type_to_adjust) { + *ipc_type_to_adjust = fw_ipc_type; + } else if (fw_ipc_type != profile->ipc_type) { + dev_err(dev, + "ipc type mismatch between %s and expected: %d vs %d\n", + fw_filename, fw_ipc_type, profile->ipc_type); + ret = -EINVAL; + } +out: + release_firmware(fw); + kfree(fw_filename); + + return ret; +} + +static int sof_test_topology_file(struct device *dev, + struct sof_loadable_file_profile *profile) +{ + const struct firmware *fw; + const char *tplg_filename; + int ret; + + if (!profile->tplg_path || !profile->tplg_name) + return 0; + + tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path, + profile->tplg_name); + if (!tplg_filename) + return -ENOMEM; + + ret = firmware_request_nowarn(&fw, tplg_filename, dev); + if (!ret) + release_firmware(fw); + else + dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename); + + kfree(tplg_filename); + + return ret; +} + static int -sof_file_profile_for_ipc_type(struct device *dev, +sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, + enum sof_ipc_type ipc_type, const struct sof_dev_desc *desc, struct sof_loadable_file_profile *base_profile, struct sof_loadable_file_profile *out_profile) { - enum sof_ipc_type ipc_type = base_profile->ipc_type; + struct snd_sof_pdata *plat_data = sdev->pdata; bool fw_lib_path_allocated = false; + struct device *dev = sdev->dev; bool fw_path_allocated = false; int ret = 0; @@ -41,6 +123,25 @@ sof_file_profile_for_ipc_type(struct device *dev, else out_profile->fw_name = desc->default_fw_filename[ipc_type]; + /* + * Check the custom firmware path/filename and adjust the ipc_type to + * match with the existing file for the remaining path configuration. + * + * For default path and firmware name do a verification before + * continuing further. + */ + if (base_profile->fw_path || base_profile->fw_name) { + ret = sof_test_firmware_file(dev, out_profile, &ipc_type); + if (ret) + return ret; + + if (!(desc->ipc_supported_mask & BIT(ipc_type))) { + dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n", + ipc_type, out_profile->fw_path, + out_profile->fw_name); + return -EINVAL; + } + } /* firmware library path */ if (base_profile->fw_lib_path) { @@ -75,11 +176,17 @@ sof_file_profile_for_ipc_type(struct device *dev, out_profile->tplg_path = desc->default_tplg_path[ipc_type]; /* topology name */ - if (base_profile->tplg_name) - out_profile->tplg_name = base_profile->tplg_name; + out_profile->tplg_name = plat_data->tplg_filename; out_profile->ipc_type = ipc_type; + /* Test only default firmware file */ + if (!base_profile->fw_path && !base_profile->fw_name) + ret = sof_test_firmware_file(dev, out_profile, NULL); + + if (!ret) + ret = sof_test_topology_file(dev, out_profile); + out: if (ret) { /* Free up path strings created with devm_kasprintf */ @@ -94,19 +201,76 @@ sof_file_profile_for_ipc_type(struct device *dev, return ret; } -static void sof_print_profile_info(struct device *dev, +static void +sof_print_missing_firmware_info(struct snd_sof_dev *sdev, + enum sof_ipc_type ipc_type, + struct sof_loadable_file_profile *base_profile) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + const struct sof_dev_desc *desc = plat_data->desc; + struct device *dev = sdev->dev; + int ipc_type_count, i; + char *marker; + + dev_err(dev, "SOF firmware and/or topology file not found.\n"); + dev_info(dev, "Supported default profiles\n"); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) + ipc_type_count = SOF_IPC_TYPE_COUNT - 1; + else + ipc_type_count = base_profile->ipc_type; + + for (i = 0; i <= ipc_type_count; i++) { + if (!(desc->ipc_supported_mask & BIT(i))) + continue; + + if (i == ipc_type) + marker = "Requested"; + else + marker = "Fallback"; + + dev_info(dev, "- ipc type %d (%s):\n", i, marker); + if (base_profile->fw_path_postfix) + dev_info(dev, " Firmware file: %s/%s/%s\n", + desc->default_fw_path[i], + base_profile->fw_path_postfix, + desc->default_fw_filename[i]); + else + dev_info(dev, " Firmware file: %s/%s\n", + desc->default_fw_path[i], + desc->default_fw_filename[i]); + + dev_info(dev, " Topology file: %s/%s\n", + desc->default_tplg_path[i], + plat_data->tplg_filename); + } + + if (base_profile->fw_path || base_profile->fw_name || + base_profile->tplg_path || base_profile->tplg_name) + dev_info(dev, "Verify the path/name override module parameters.\n"); + + dev_info(dev, "Check if you have 'sof-firmware' package installed.\n"); + dev_info(dev, "Optionally it can be manually downloaded from:\n"); + dev_info(dev, " https://github.com/thesofproject/sof-bin/\n"); +} + +static void sof_print_profile_info(struct snd_sof_dev *sdev, + enum sof_ipc_type ipc_type, struct sof_loadable_file_profile *profile) { + struct device *dev = sdev->dev; + + if (ipc_type != profile->ipc_type) + dev_info(dev, + "Using fallback IPC type %d (requested type was %d)\n", + profile->ipc_type, ipc_type); + dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); if (profile->fw_lib_path) dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); - if (profile->tplg_name) - dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, - profile->tplg_name); - else - dev_info(dev, " Topology path: %s\n", profile->tplg_path); + dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name); } int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, @@ -114,17 +278,45 @@ int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, struct sof_loadable_file_profile *out_profile) { const struct sof_dev_desc *desc = sdev->pdata->desc; - struct device *dev = sdev->dev; - int ret; + int ipc_fallback_start, ret, i; memset(out_profile, 0, sizeof(*out_profile)); - ret = sof_file_profile_for_ipc_type(dev, desc, base_profile, out_profile); + ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc, + base_profile, out_profile); + if (!ret) + goto out; + + /* + * No firmware file was found for the requested IPC type, as fallback + * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check + * all IPC versions in a backwards direction (from newer to older) + * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected, + * check only older IPC versions than the selected/default version + */ + if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) + ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1; + else + ipc_fallback_start = (int)base_profile->ipc_type - 1; + + for (i = ipc_fallback_start; i >= 0 ; i--) { + if (i == base_profile->ipc_type || + !(desc->ipc_supported_mask & BIT(i))) + continue; + + ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile, + out_profile); + if (!ret) + break; + } + +out: if (ret) - return ret; + sof_print_missing_firmware_info(sdev, base_profile->ipc_type, + base_profile); + else + sof_print_profile_info(sdev, base_profile->ipc_type, out_profile); - sof_print_profile_info(dev, out_profile); - - return 0; + return ret; } EXPORT_SYMBOL(sof_create_ipc_file_profile); From 2bd512626f8ea3957c981cadd2ebf75feff737dd Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 29 Nov 2023 14:20:21 +0200 Subject: [PATCH 1780/7721] ASoC: SOF: ipc4: check return value of snd_sof_ipc_msg_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snd_sof_ipc_msg_data could return error. Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231129122021.679-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index a9d9800d2fcc..145d319e041f 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -713,7 +713,14 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) return; ipc4_msg->data_size = data_size; - snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size); + err = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size); + if (err < 0) { + dev_err(sdev->dev, "failed to read IPC notification data: %d\n", err); + kfree(ipc4_msg->data_ptr); + ipc4_msg->data_ptr = NULL; + ipc4_msg->data_size = 0; + return; + } } /* Handle notifications with payload */ From 729bb2cd2e0601ac6d52c53535a543b9db196fad Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Nov 2023 14:28:05 +0200 Subject: [PATCH 1781/7721] ASoC: SOF: ipc4: Move window offset configuration earlier With the added exception handling support if the firmware fails to boot up we are trying to do a panic dump from the telemetry slot. The slot offsets would have been configured only after receiving the FW_READY message which makes this panic dump unusable for early boot failures. With IPC4 the DSP window offsets are at standard places unlike IPC3 where the offsets needs to be queried from the FW_READY message. Move the offset configuration to sof_ipc4_init from the fw_ready handler. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231129122805.10635-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4.c | 55 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 145d319e041f..ac5c6bc66d2a 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -576,40 +576,12 @@ EXPORT_SYMBOL(sof_ipc4_find_debug_slot_offset_by_type); static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg) { - int inbox_offset, inbox_size, outbox_offset, outbox_size; - /* no need to re-check version/ABI for subsequent boots */ if (!sdev->first_boot) return 0; - /* Set up the windows for IPC communication */ - inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev); - if (inbox_offset < 0) { - dev_err(sdev->dev, "%s: No mailbox offset\n", __func__); - return inbox_offset; - } - inbox_size = SOF_IPC4_MSG_MAX_SIZE; - outbox_offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_OUTBOX_WINDOW_IDX); - outbox_size = SOF_IPC4_MSG_MAX_SIZE; - - sdev->fw_info_box.offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_INBOX_WINDOW_IDX); - sdev->fw_info_box.size = sizeof(struct sof_ipc4_fw_registers); - sdev->dsp_box.offset = inbox_offset; - sdev->dsp_box.size = inbox_size; - sdev->host_box.offset = outbox_offset; - sdev->host_box.size = outbox_size; - - sdev->debug_box.offset = snd_sof_dsp_get_window_offset(sdev, - SOF_IPC4_DEBUG_WINDOW_IDX); - sof_ipc4_create_exception_debugfs_node(sdev); - dev_dbg(sdev->dev, "mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, "mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, "debug box 0x%x\n", sdev->debug_box.offset); - return sof_ipc4_init_msg_memory(sdev); } @@ -796,11 +768,38 @@ static const struct sof_ipc_pm_ops ipc4_pm_ops = { static int sof_ipc4_init(struct snd_sof_dev *sdev) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; + int inbox_offset; mutex_init(&ipc4_data->pipeline_state_mutex); xa_init_flags(&ipc4_data->fw_lib_xa, XA_FLAGS_ALLOC); + /* Set up the windows for IPC communication */ + inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev); + if (inbox_offset < 0) { + dev_err(sdev->dev, "%s: No mailbox offset\n", __func__); + return inbox_offset; + } + + sdev->dsp_box.offset = inbox_offset; + sdev->dsp_box.size = SOF_IPC4_MSG_MAX_SIZE; + sdev->host_box.offset = snd_sof_dsp_get_window_offset(sdev, + SOF_IPC4_OUTBOX_WINDOW_IDX); + sdev->host_box.size = SOF_IPC4_MSG_MAX_SIZE; + + sdev->debug_box.offset = snd_sof_dsp_get_window_offset(sdev, + SOF_IPC4_DEBUG_WINDOW_IDX); + + sdev->fw_info_box.offset = snd_sof_dsp_get_window_offset(sdev, + SOF_IPC4_INBOX_WINDOW_IDX); + sdev->fw_info_box.size = sizeof(struct sof_ipc4_fw_registers); + + dev_dbg(sdev->dev, "mailbox upstream %#x - size %#x\n", + sdev->dsp_box.offset, SOF_IPC4_MSG_MAX_SIZE); + dev_dbg(sdev->dev, "mailbox downstream %#x - size %#x\n", + sdev->host_box.offset, SOF_IPC4_MSG_MAX_SIZE); + dev_dbg(sdev->dev, "debug box %#x\n", sdev->debug_box.offset); + return 0; } From e9a92dfc8d4fde6f7adb978fb13d0b0834567cc5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 29 Nov 2023 09:09:58 +0000 Subject: [PATCH 1782/7721] ASoC: core: Fix a handful of spelling mistakes. There is a spelling mistake in a dev_err message and several spelling mistakes in comments. Fix them. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20231129090958.815775-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4ca3319a8e19..132946f82a29 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1059,7 +1059,7 @@ static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card, /* it should have ch_maps if connection was N:M */ if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) { - dev_err(card->dev, "need to have ch_maps when N:M connction (%s)", + dev_err(card->dev, "need to have ch_maps when N:M connection (%s)", dai_link->name); return -EINVAL; } @@ -1299,7 +1299,7 @@ static void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd) * * To avoid such issue, loop from 63 to 0 here. * Small number of SND_SOC_POSSIBLE_xxx will be Hi priority. - * Basic/Default settings of each part and aboves are defined + * Basic/Default settings of each part and above are defined * as Hi priority (= small number) of SND_SOC_POSSIBLE_xxx. */ for (i = 63; i >= 0; i--) { @@ -1845,7 +1845,7 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str) * @flavour: The flavour "differentiator" for the card amongst its peers. * * An Intel machine driver may be used by many different devices but are - * difficult for userspace to differentiate, since machine drivers ususally + * difficult for userspace to differentiate, since machine drivers usually * use their own name as the card short name and leave the card long name * blank. To differentiate such devices and fix bugs due to lack of * device-specific configurations, this function allows DMI info to be used @@ -1866,7 +1866,7 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str) * We only keep number and alphabet characters and a few separator characters * in the card long name since UCM in the user space uses the card long names * as card configuration directory names and AudoConf cannot support special - * charactors like SPACE. + * characters like SPACE. * * Returns 0 on success, otherwise a negative error code. */ @@ -2461,7 +2461,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); /** * snd_soc_add_dai_controls - add an array of controls to a DAI. - * Convienience function to add a list of controls. + * Convenience function to add a list of controls. * * @dai: DAI to add controls to * @controls: array of controls to add From 8f464a410944650adc8d75c7711d7d56c5506da0 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Wed, 29 Nov 2023 14:22:34 +0200 Subject: [PATCH 1783/7721] ASoC: SOF: ipc4-topology: Add module ID print during module set up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This module ID will be used for module performance automatic analysis for different modules, module name, module ID and module instance ID will be combined as a new generated ID for current module, this ID will be further used by analysis tools to identify current module. Take below case as example: 0x030006 gain.11.1 3 is module instance ID, 6 is module ID and gain.11.1 is module name. For pipeline widget print, keep as it is. Signed-off-by: Baofeng Tian Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Reviewed-by: Chao Song Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20231129122234.14515-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8ab9c42069ee..4e7ab4e562e5 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2383,6 +2383,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget } if (swidget->id != snd_soc_dapm_scheduler) { + int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK; + ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); if (ret < 0) { dev_err(sdev->dev, "failed to assign instance id for %s\n", @@ -2398,9 +2400,15 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); + + dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n", + swidget->widget->name, swidget->pipeline_id, module_id, + swidget->instance_id, swidget->core); + } else { + dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", + swidget->widget->name, swidget->pipeline_id, + swidget->instance_id, swidget->core); } - dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", - swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); msg->data_size = ipc_size; msg->data_ptr = ipc_data; From 9cce9c4806a89439ea34aad2e382150d68c7ea95 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Nov 2023 12:31:17 +0100 Subject: [PATCH 1784/7721] ASoC: fsl_rpmsg: update Kconfig dependencies SND_SOC_IMX_RPMSG gained a new dependency and gets selected by SND_SOC_FSL_RPMSG, which as a result needs to have the same dependency, or produce a build failure based on that: WARNING: unmet direct dependencies detected for SND_SOC_IMX_RPMSG Depends on [n]: SOUND [=y] && SND [=y] && SND_SOC [=y] && SND_IMX_SOC [=y] && RPMSG [=y] && OF [=y] && I2C [=n] Selected by [y]: - SND_SOC_FSL_RPMSG [=y] && SOUND [=y] && SND [=y] && SND_SOC [=y] && COMMON_CLK [=y] && RPMSG [=y] && (SND_IMX_SOC [=y] || SND_IMX_SOC [=y]=n) && SND_IMX_SOC [=y]!=n x86_64-linux-ld: sound/soc/fsl/imx-rpmsg.o: in function `imx_rpmsg_late_probe': imx-rpmsg.c:(.text+0x11e): undefined reference to `i2c_find_device_by_fwnode' Fixes: f83d38def6b1 ("ASoC: imx-rpmsg: SND_SOC_IMX_RPMSG should depend on OF and I2C") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231129113204.2869356-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index bec2aa561930..13cb6960aae7 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -121,6 +121,7 @@ config SND_SOC_FSL_UTILS config SND_SOC_FSL_RPMSG tristate "NXP Audio Base On RPMSG support" depends on COMMON_CLK + depends on OF && I2C depends on RPMSG depends on SND_IMX_SOC || SND_IMX_SOC = n select SND_SOC_IMX_RPMSG if SND_IMX_SOC != n From fcebbe2fa3443e400657d71182610219750d1c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 24 Nov 2023 10:27:31 +0200 Subject: [PATCH 1785/7721] drm/i915/psr: Include some basic PSR information in the state dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently no one can figure out what the PSR code is doing since we're including any of it in the basic state dump. Add at least the bare minimum there. v2: Also dump has_panel_replay (Jouni) Cc: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231124082735.25470-1-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- drivers/gpu/drm/i915/display/intel_crtc_state_dump.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 30336453041d..30b8ddeae8ce 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -264,6 +264,12 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_dbg_kms(&i915->drm, "sdp split: %s\n", str_enabled_disabled(pipe_config->sdp_split_enable)); + + drm_dbg_kms(&i915->drm, "psr: %s, psr2: %s, panel replay: %s, selective fetch: %s\n", + str_enabled_disabled(pipe_config->has_psr), + str_enabled_disabled(pipe_config->has_psr2), + str_enabled_disabled(pipe_config->has_panel_replay), + str_enabled_disabled(pipe_config->enable_psr2_sel_fetch)); } drm_dbg_kms(&i915->drm, "framestart delay: %d, MSA timing delay: %d\n", From e0ef2daa8ca8ce4dbc2fd0959e383b753a87fd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Nov 2023 16:50:25 +0200 Subject: [PATCH 1786/7721] drm/i915: Skip some timing checks on BXT/GLK DSI transcoders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently some BXT/GLK systems have DSI panels whose timings don't agree with the normal cpu transcoder hblank>=32 limitation. This is perhaps fine as there are no specific hblank/etc. limits listed for the BXT/GLK DSI transcoders. Move those checks out from the global intel_mode_valid() into into connector specific .mode_valid() hooks, skipping BXT/GLK DSI connectors. We'll leave the basic [hv]display/[hv]total checks in intel_mode_valid() as those seem like sensible upper limits regardless of the transcoder used. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9720 Fixes: 8f4b1068e7fc ("drm/i915: Check some transcoder timing minimum limits") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231127145028.4899-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/icl_dsi.c | 7 +++++++ drivers/gpu/drm/i915/display/intel_crt.c | 5 +++++ drivers/gpu/drm/i915/display/intel_display.c | 10 ++++++++++ drivers/gpu/drm/i915/display/intel_display.h | 3 +++ drivers/gpu/drm/i915/display/intel_dp.c | 4 ++++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 ++++ drivers/gpu/drm/i915/display/intel_dvo.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_hdmi.c | 4 ++++ drivers/gpu/drm/i915/display/intel_lvds.c | 5 +++++ drivers/gpu/drm/i915/display/intel_sdvo.c | 8 +++++++- drivers/gpu/drm/i915/display/intel_tv.c | 8 +++++++- drivers/gpu/drm/i915/display/vlv_dsi.c | 18 +++++++++++++++++- 12 files changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 481fcb650850..ac456a2275db 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1440,6 +1440,13 @@ static void gen11_dsi_post_disable(struct intel_atomic_state *state, static enum drm_mode_status gen11_dsi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_i915_private *i915 = to_i915(connector->dev); + enum drm_mode_status status; + + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; + /* FIXME: DSC? */ return intel_dsi_mode_valid(connector, mode); } diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 0e33a0523a75..abaacea5c2cc 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -348,8 +348,13 @@ intel_crt_mode_valid(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = to_i915(dev); int max_dotclk = dev_priv->max_dotclk_freq; + enum drm_mode_status status; int max_clock; + status = intel_cpu_transcoder_mode_valid(dev_priv, mode); + if (status != MODE_OK) + return status; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5cf162628b95..23b077f43614 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7734,6 +7734,16 @@ enum drm_mode_status intel_mode_valid(struct drm_device *dev, mode->vtotal > vtotal_max) return MODE_V_ILLEGAL; + return MODE_OK; +} + +enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *dev_priv, + const struct drm_display_mode *mode) +{ + /* + * Additional transcoder timing limits, + * excluding BXT/GLK DSI transcoders. + */ if (DISPLAY_VER(dev_priv) >= 5) { if (mode->hdisplay < 64 || mode->htotal - mode->hdisplay < 32) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 8548f49e3972..f4a0773f0fca 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -402,6 +402,9 @@ enum drm_mode_status intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv, const struct drm_display_mode *mode, bool bigjoiner); +enum drm_mode_status +intel_cpu_transcoder_mode_valid(struct drm_i915_private *i915, + const struct drm_display_mode *mode); enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port); bool is_trans_port_sync_mode(const struct intel_crtc_state *state); bool is_trans_port_sync_master(const struct intel_crtc_state *state); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f9b5fc2fdbcb..68b2e69dca39 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1227,6 +1227,10 @@ intel_dp_mode_valid(struct drm_connector *_connector, enum drm_mode_status status; bool dsc = false, bigjoiner = false; + status = intel_cpu_transcoder_mode_valid(dev_priv, mode); + if (status != MODE_OK) + return status; + if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 63364c9602ef..0514f825baf5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1282,6 +1282,10 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, return 0; } + *status = intel_cpu_transcoder_mode_valid(dev_priv, mode); + if (*status != MODE_OK) + return 0; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { *status = MODE_NO_DBLESCAN; return 0; diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 55d6743374bd..9111e9d46486 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -217,11 +217,17 @@ intel_dvo_mode_valid(struct drm_connector *_connector, struct drm_display_mode *mode) { struct intel_connector *connector = to_intel_connector(_connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_dvo *intel_dvo = intel_attached_dvo(connector); const struct drm_display_mode *fixed_mode = intel_panel_fixed_mode(connector, mode); int max_dotclk = to_i915(connector->base.dev)->max_dotclk_freq; int target_clock = mode->clock; + enum drm_mode_status status; + + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index ab18cfc19c0a..39e4f5f7c817 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1983,6 +1983,10 @@ intel_hdmi_mode_valid(struct drm_connector *connector, bool ycbcr_420_only; enum intel_output_format sink_format; + status = intel_cpu_transcoder_mode_valid(dev_priv, mode); + if (status != MODE_OK) + return status; + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) clock *= 2; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 4b114fde57b1..958b6fd0d741 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -389,11 +389,16 @@ intel_lvds_mode_valid(struct drm_connector *_connector, struct drm_display_mode *mode) { struct intel_connector *connector = to_intel_connector(_connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *fixed_mode = intel_panel_fixed_mode(connector, mode); int max_pixclk = to_i915(connector->base.dev)->max_dotclk_freq; enum drm_mode_status status; + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index c7af7e046188..0362d02d70b6 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1930,13 +1930,19 @@ static enum drm_mode_status intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_i915_private *i915 = to_i915(connector->dev); struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; bool has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo_connector, connector->state); + int max_dotclk = i915->max_dotclk_freq; + enum drm_mode_status status; int clock = mode->clock; + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 31a79fdfc812..2ee4f0d95851 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -958,8 +958,14 @@ static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_i915_private *i915 = to_i915(connector->dev); const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); - int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + int max_dotclk = i915->max_dotclk_freq; + enum drm_mode_status status; + + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index bda49734ca33..5bda97c96810 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1544,9 +1544,25 @@ static const struct drm_encoder_funcs intel_dsi_funcs = { .destroy = intel_dsi_encoder_destroy, }; +static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_i915_private *i915 = to_i915(connector->dev); + + if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { + enum drm_mode_status status; + + status = intel_cpu_transcoder_mode_valid(i915, mode); + if (status != MODE_OK) + return status; + } + + return intel_dsi_mode_valid(connector, mode); +} + static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = { .get_modes = intel_dsi_get_modes, - .mode_valid = intel_dsi_mode_valid, + .mode_valid = vlv_dsi_mode_valid, .atomic_check = intel_digital_connector_atomic_check, }; From c1799032d2ef6616113b733428dfaa2199a5604b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Nov 2023 16:50:26 +0200 Subject: [PATCH 1787/7721] drm/i915/mst: Fix .mode_valid_ctx() return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .mode_valid_ctx() returns an errno, not the mode status. Fix the code to do the right thing. Cc: stable@vger.kernel.org Cc: Stanislav Lisovskiy Fixes: d51f25eb479a ("drm/i915: Add DSC support to MST path") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231127145028.4899-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0514f825baf5..0680a42f7d2a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1366,11 +1366,15 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, * Big joiner configuration needs DSC for TGL which is not true for * XE_LPD where uncompressed joiner is supported. */ - if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) - return MODE_CLOCK_HIGH; + if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) { + *status = MODE_CLOCK_HIGH; + return 0; + } - if (mode_rate > max_rate && !dsc) - return MODE_CLOCK_HIGH; + if (mode_rate > max_rate && !dsc) { + *status = MODE_CLOCK_HIGH; + return 0; + } *status = intel_mode_valid_max_plane_size(dev_priv, mode, false); return 0; From 9c058492b16f90bb772cb0dad567e8acc68e155d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Nov 2023 16:50:27 +0200 Subject: [PATCH 1788/7721] drm/i915/mst: Reject modes that require the bigjoiner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have no bigjoiner support in the MST code, so .mode_valid() pretending otherwise is just going to result black screens for users. Reject any mode that needs the joiner. Cc: stable@vger.kernel.org Cc: Stanislav Lisovskiy Fixes: d51f25eb479a ("drm/i915: Add DSC support to MST path") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231127145028.4899-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0680a42f7d2a..b665fe6ef871 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1332,6 +1332,10 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, if (intel_dp_need_bigjoiner(intel_dp, mode->hdisplay, target_clock)) { bigjoiner = true; max_dotclk *= 2; + + /* TODO: add support for bigjoiner */ + *status = MODE_CLOCK_HIGH; + return 0; } if (DISPLAY_VER(dev_priv) >= 10 && From 8dfce5f3095b79236b585bfa0e291b77ba4b6dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Nov 2023 16:50:28 +0200 Subject: [PATCH 1789/7721] drm/i915: Clean up some DISPLAY_VER checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the >= and < operators for the DISPLAY_VER checks everywhere. This is what most of the code does, but especially recently random pieces of code have started doing this differently for no good reason. Conversion done with the following cocci: @find@ expression i915; constant ver; @@ ( DISPLAY_VER(i915) <= ver | DISPLAY_VER(i915) > ver ) @script:python inc@ old_ver << find.ver; new_ver; @@ coccinelle.new_ver = str(int(old_ver) + 1) @@ expression find.i915; constant find.ver; identifier inc.new_ver; @@ ( - DISPLAY_VER(i915) <= ver + DISPLAY_VER(i915) < new_ver | - DISPLAY_VER(i915) > ver + DISPLAY_VER(i915) >= new_ver ) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231127145028.4899-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_wm.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_bw.c | 7 ++++--- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_display_device.h | 2 +- drivers/gpu/drm/i915/display/intel_display_irq.c | 2 +- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/display/intel_lvds.c | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 8 ++++---- 10 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index b37c0d02d500..03e8fb6caa83 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -2477,7 +2477,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_i915_private *dev_priv, * FIFO size is only half of the self * refresh FIFO size on ILK/SNB. */ - if (DISPLAY_VER(dev_priv) <= 6) + if (DISPLAY_VER(dev_priv) < 7) fifo_size /= 2; } @@ -2818,7 +2818,7 @@ static int ilk_compute_pipe_wm(struct intel_atomic_state *state, usable_level = dev_priv->display.wm.num_levels - 1; /* ILK/SNB: LP2+ watermarks only w/o sprites */ - if (DISPLAY_VER(dev_priv) <= 6 && pipe_wm->sprites_enabled) + if (DISPLAY_VER(dev_priv) < 7 && pipe_wm->sprites_enabled) usable_level = 1; /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */ @@ -2961,7 +2961,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv, int last_enabled_level = num_levels - 1; /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ - if ((DISPLAY_VER(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) && + if ((DISPLAY_VER(dev_priv) < 7 || IS_IVYBRIDGE(dev_priv)) && config->num_pipes_active > 1) last_enabled_level = 0; @@ -3060,7 +3060,7 @@ static void ilk_compute_wm_results(struct drm_i915_private *dev_priv, * Always set WM_LP_SPRITE_EN when spr_val != 0, even if the * level is disabled. Doing otherwise could cause underruns. */ - if (DISPLAY_VER(dev_priv) <= 6 && r->spr_val) { + if (DISPLAY_VER(dev_priv) < 7 && r->spr_val) { drm_WARN_ON(&dev_priv->drm, wm_lp != 1); results->wm_lp_spr[wm_lp - 1] |= WM_LP_SPRITE_ENABLE; } diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index bef96db62c80..7f2a50b4f494 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -87,7 +87,8 @@ static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv, return ret; dclk = val & 0xffff; - sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(dev_priv) > 11 ? 500 : 0), 1000); + sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(dev_priv) >= 12 ? 500 : 0), + 1000); sp->t_rp = (val & 0xff0000) >> 16; sp->t_rcd = (val & 0xff000000) >> 24; @@ -480,7 +481,7 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel if (num_channels < qi.max_numchannels && DISPLAY_VER(dev_priv) >= 12) qi.deinterleave = max(DIV_ROUND_UP(qi.deinterleave, 2), 1); - if (DISPLAY_VER(dev_priv) > 11 && num_channels > qi.max_numchannels) + if (DISPLAY_VER(dev_priv) >= 12 && num_channels > qi.max_numchannels) drm_warn(&dev_priv->drm, "Number of channels exceeds max number of channels."); if (qi.max_numchannels != 0) num_channels = min_t(u8, num_channels, qi.max_numchannels); @@ -897,7 +898,7 @@ static int icl_find_qgv_points(struct drm_i915_private *i915, unsigned int idx; unsigned int max_data_rate; - if (DISPLAY_VER(i915) > 11) + if (DISPLAY_VER(i915) >= 12) idx = tgl_max_bw_index(i915, num_active_planes, i); else idx = icl_max_bw_index(i915, num_active_planes, i); diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index b93d1ad7936d..8bb6bab7c8cd 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2597,7 +2597,7 @@ static int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) * Since PPC = 2 with bigjoiner * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits */ - int bigjoiner_interface_bits = DISPLAY_VER(i915) > 13 ? 36 : 24; + int bigjoiner_interface_bits = DISPLAY_VER(i915) >= 14 ? 36 : 24; int min_cdclk_bj = (to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) * pixel_clock) / (2 * bigjoiner_interface_bits); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 23b077f43614..9dc22fc8b3d3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2627,7 +2627,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta crtc_vblank_start = 1; } - if (DISPLAY_VER(dev_priv) > 3) + if (DISPLAY_VER(dev_priv) >= 4) intel_de_write(dev_priv, TRANS_VSYNCSHIFT(cpu_transcoder), vsyncshift); @@ -3167,7 +3167,7 @@ static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state) break; case 36: /* Port output 12BPC defined for ADLP+ */ - if (DISPLAY_VER(dev_priv) > 12) + if (DISPLAY_VER(dev_priv) >= 13) val |= PIPE_MISC_BPC_12_ADLP; break; default: @@ -3224,7 +3224,7 @@ int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc) * MIPI DSI HW readout. */ case PIPE_MISC_BPC_12_ADLP: - if (DISPLAY_VER(dev_priv) > 12) + if (DISPLAY_VER(dev_priv) >= 13) return 36; fallthrough; default: @@ -7763,7 +7763,7 @@ enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *de * Cantiga+ cannot handle modes with a hsync front porch of 0. * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. */ - if ((DISPLAY_VER(dev_priv) > 4 || IS_G4X(dev_priv)) && + if ((DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) && mode->hsync_start == mode->hdisplay) return MODE_H_ILLEGAL; diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 4299cc452e05..79e9f1c3e241 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -49,7 +49,7 @@ struct drm_printer; #define HAS_DSC(__i915) (DISPLAY_RUNTIME_INFO(__i915)->has_dsc) #define HAS_FBC(i915) (DISPLAY_RUNTIME_INFO(i915)->fbc_mask != 0) #define HAS_FPGA_DBG_UNCLAIMED(i915) (DISPLAY_INFO(i915)->has_fpga_dbg) -#define HAS_FW_BLC(i915) (DISPLAY_VER(i915) > 2) +#define HAS_FW_BLC(i915) (DISPLAY_VER(i915) >= 3) #define HAS_GMBUS_IRQ(i915) (DISPLAY_VER(i915) >= 4) #define HAS_GMBUS_BURST_READ(i915) (DISPLAY_VER(i915) >= 10 || IS_KABYLAKE(i915)) #define HAS_GMCH(i915) (DISPLAY_INFO(i915)->has_gmch) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index bff4a76310c0..5a3e10e73e59 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1653,7 +1653,7 @@ void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) else if (HAS_PCH_SPLIT(dev_priv)) ibx_irq_postinstall(dev_priv); - if (DISPLAY_VER(dev_priv) <= 10) + if (DISPLAY_VER(dev_priv) < 11) de_misc_masked |= GEN8_DE_MISC_GSE; if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 68b2e69dca39..0b24c0cba94e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1890,7 +1890,7 @@ static int dsc_src_max_compressed_bpp(struct intel_dp *intel_dp) * Max Compressed bpp for Gen 13+ is 27bpp. * For earlier platform is 23bpp. (Bspec:49259). */ - if (DISPLAY_VER(i915) <= 12) + if (DISPLAY_VER(i915) < 13) return 23; else return 27; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b665fe6ef871..e8940acea8ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -54,7 +54,7 @@ static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp struct intel_crtc_state *crtc_state, bool dsc) { - if (intel_dp_is_uhbr(crtc_state) && DISPLAY_VER(i915) <= 13 && dsc) { + if (intel_dp_is_uhbr(crtc_state) && DISPLAY_VER(i915) < 14 && dsc) { int output_bpp = bpp; /* DisplayPort 2 128b/132b, bits per lane is always 32 */ int symbol_clock = crtc_state->port_clock / 32; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 958b6fd0d741..221f5c6c871b 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -185,7 +185,7 @@ static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv, /* Convert from 100ms to 100us units */ pps->t4 = val * 1000; - if (DISPLAY_VER(dev_priv) <= 4 && + if (DISPLAY_VER(dev_priv) < 5 && pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) { drm_dbg_kms(&dev_priv->drm, "Panel power timings uninitialized, " diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 36e4a1e9b98f..6029bb71276c 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -806,10 +806,10 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_PSR2_IDLE_FRAMES(psr_compute_idle_frames(intel_dp)); - if (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv)) + if (DISPLAY_VER(dev_priv) < 14 && !IS_ALDERLAKE_P(dev_priv)) val |= EDP_SU_TRACK_ENABLE; - if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) + if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) < 13) val |= EDP_Y_COORDINATE_ENABLE; val |= EDP_PSR2_FRAME_BEFORE_SU(frames_before_su_entry(intel_dp)); @@ -1094,7 +1094,7 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d return true; /* Not supported <13 / Wa_22012279113:adl-p */ - if (DISPLAY_VER(dev_priv) <= 13 || intel_dp->edp_dpcd[0] < DP_EDP_14b) + if (DISPLAY_VER(dev_priv) < 14 || intel_dp->edp_dpcd[0] < DP_EDP_14b) return false; crtc_state->req_psr2_sdp_prior_scanline = true; @@ -1221,7 +1221,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * over PSR2. */ if (crtc_state->dsc.compression_enable && - (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv))) { + (DISPLAY_VER(dev_priv) < 14 && !IS_ALDERLAKE_P(dev_priv))) { drm_dbg_kms(&dev_priv->drm, "PSR2 cannot be enabled since DSC is enabled\n"); return false; From fd2a9b29dc9c4c35def91d5d1c5b470843539de6 Mon Sep 17 00:00:00 2001 From: Tatsunosuke Tobita Date: Wed, 15 Nov 2023 08:57:29 +0900 Subject: [PATCH 1790/7721] HID: wacom: Remove AES power_supply after extended inactivity Even if a user does not use their AES pen for an extended period, the battery power supply attributes continue to exist. This results in the desktop showing battery status for a pen that is no longer in use and which may in fact be in a different state (e.g. the user may be charging the pen). To avoid confusion and ensure userspace has an accurate view of the battery state, this patch automatically removes the power_supply after 30 minutes of inactivity. Signed-off-by: Tatsunosuke Tobita Reviewed-by: Jason Gerecke Reviewed-by: Aaron Skomra Reviewed-by: Josh Dickens Link: https://lore.kernel.org/r/20231114235729.6867-1-tatsunosuke.wacom@gmail.com Signed-off-by: Benjamin Tissoires --- drivers/hid/wacom.h | 1 + drivers/hid/wacom_sys.c | 8 ++++++++ drivers/hid/wacom_wac.c | 12 +++++++++++- drivers/hid/wacom_wac.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 166a76c9bcad..77c5fb26cd14 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -164,6 +164,7 @@ struct wacom { struct work_struct battery_work; struct work_struct remote_work; struct delayed_work init_work; + struct delayed_work aes_battery_work; struct wacom_remote *remote; struct work_struct mode_change_work; struct timer_list idleprox_timer; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 3f704b8072e8..b613f11ed949 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1813,6 +1813,13 @@ static void wacom_destroy_battery(struct wacom *wacom) } } +static void wacom_aes_battery_handler(struct work_struct *work) +{ + struct wacom *wacom = container_of(work, struct wacom, aes_battery_work.work); + + wacom_destroy_battery(wacom); +} + static ssize_t wacom_show_speed(struct device *dev, struct device_attribute *attr, char *buf) @@ -2794,6 +2801,7 @@ static int wacom_probe(struct hid_device *hdev, mutex_init(&wacom->lock); INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work); + INIT_DELAYED_WORK(&wacom->aes_battery_work, wacom_aes_battery_handler); INIT_WORK(&wacom->wireless_work, wacom_wireless_work); INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->remote_work, wacom_remote_work); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 471db78dbbf0..c205198ded11 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2528,11 +2528,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev, struct input_dev *input = wacom_wac->pen_input; bool range = wacom_wac->hid_data.inrange_state; bool sense = wacom_wac->hid_data.sense_state; + bool entering_range = !wacom_wac->tool[0] && range; if (wacom_wac->is_invalid_bt_frame) return; - if (!wacom_wac->tool[0] && range) { /* first in range */ + if (entering_range) { /* first in range */ /* Going into range select tool */ if (wacom_wac->hid_data.invert_state) wacom_wac->tool[0] = BTN_TOOL_RUBBER; @@ -2583,6 +2584,15 @@ static void wacom_wac_pen_report(struct hid_device *hdev, input_sync(input); } + /* Handle AES battery timeout behavior */ + if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) { + if (entering_range) + cancel_delayed_work(&wacom->aes_battery_work); + if (!sense) + schedule_delayed_work(&wacom->aes_battery_work, + msecs_to_jiffies(WACOM_AES_BATTERY_TIMEOUT)); + } + if (!sense) { wacom_wac->tool[0] = 0; wacom_wac->id[0] = 0; diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 57e185f18d53..e63b1e806e34 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -14,6 +14,7 @@ #define WACOM_MAX_REMOTES 5 #define WACOM_STATUS_UNKNOWN 255 #define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll +#define WACOM_AES_BATTERY_TIMEOUT 1800000 /* packet length for individual models */ #define WACOM_PKGLEN_BBFUN 9 From 955f4d3bf0a454bc76c6393d74d844556d61b520 Mon Sep 17 00:00:00 2001 From: John Fraker Date: Mon, 27 Nov 2023 16:26:44 -0800 Subject: [PATCH 1791/7721] gve: Perform adminq allocations through a dma_pool. This allows the adminq to be smaller than a page, paving the way for non 4k page support. This is to support platforms where PAGE_SIZE is not 4k, such as some ARM platforms. Signed-off-by: Jordan Kimbrough Signed-off-by: John Fraker Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231128002648.320892-2-jfraker@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve.h | 4 +++ drivers/net/ethernet/google/gve/gve_adminq.c | 28 +++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 0d1e681be250..abc0c708b47a 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -8,6 +8,7 @@ #define _GVE_H_ #include +#include #include #include #include @@ -41,6 +42,8 @@ #define NIC_TX_STATS_REPORT_NUM 0 #define NIC_RX_STATS_REPORT_NUM 4 +#define GVE_ADMINQ_BUFFER_SIZE 4096 + #define GVE_DATA_SLOT_ADDR_PAGE_MASK (~(PAGE_SIZE - 1)) /* PTYPEs are always 10 bits. */ @@ -672,6 +675,7 @@ struct gve_priv { /* Admin queue - see gve_adminq.h*/ union gve_adminq_command *adminq; dma_addr_t adminq_bus_addr; + struct dma_pool *adminq_pool; u32 adminq_mask; /* masks prod_cnt to adminq size */ u32 adminq_prod_cnt; /* free-running count of AQ cmds executed */ u32 adminq_cmd_fail; /* free-running count of AQ cmds failed */ diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index 79db7a6d42bc..d3f3a015238d 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -194,12 +194,19 @@ gve_process_device_options(struct gve_priv *priv, int gve_adminq_alloc(struct device *dev, struct gve_priv *priv) { - priv->adminq = dma_alloc_coherent(dev, PAGE_SIZE, - &priv->adminq_bus_addr, GFP_KERNEL); - if (unlikely(!priv->adminq)) + priv->adminq_pool = dma_pool_create("adminq_pool", dev, + GVE_ADMINQ_BUFFER_SIZE, 0, 0); + if (unlikely(!priv->adminq_pool)) return -ENOMEM; + priv->adminq = dma_pool_alloc(priv->adminq_pool, GFP_KERNEL, + &priv->adminq_bus_addr); + if (unlikely(!priv->adminq)) { + dma_pool_destroy(priv->adminq_pool); + return -ENOMEM; + } - priv->adminq_mask = (PAGE_SIZE / sizeof(union gve_adminq_command)) - 1; + priv->adminq_mask = + (GVE_ADMINQ_BUFFER_SIZE / sizeof(union gve_adminq_command)) - 1; priv->adminq_prod_cnt = 0; priv->adminq_cmd_fail = 0; priv->adminq_timeouts = 0; @@ -251,7 +258,8 @@ void gve_adminq_free(struct device *dev, struct gve_priv *priv) if (!gve_get_admin_queue_ok(priv)) return; gve_adminq_release(priv); - dma_free_coherent(dev, PAGE_SIZE, priv->adminq, priv->adminq_bus_addr); + dma_pool_free(priv->adminq_pool, priv->adminq, priv->adminq_bus_addr); + dma_pool_destroy(priv->adminq_pool); gve_clear_admin_queue_ok(priv); } @@ -778,8 +786,8 @@ int gve_adminq_describe_device(struct gve_priv *priv) u16 mtu; memset(&cmd, 0, sizeof(cmd)); - descriptor = dma_alloc_coherent(&priv->pdev->dev, PAGE_SIZE, - &descriptor_bus, GFP_KERNEL); + descriptor = dma_pool_alloc(priv->adminq_pool, GFP_KERNEL, + &descriptor_bus); if (!descriptor) return -ENOMEM; cmd.opcode = cpu_to_be32(GVE_ADMINQ_DESCRIBE_DEVICE); @@ -787,7 +795,8 @@ int gve_adminq_describe_device(struct gve_priv *priv) cpu_to_be64(descriptor_bus); cmd.describe_device.device_descriptor_version = cpu_to_be32(GVE_ADMINQ_DEVICE_DESCRIPTOR_VERSION); - cmd.describe_device.available_length = cpu_to_be32(PAGE_SIZE); + cmd.describe_device.available_length = + cpu_to_be32(GVE_ADMINQ_BUFFER_SIZE); err = gve_adminq_execute_cmd(priv, &cmd); if (err) @@ -868,8 +877,7 @@ int gve_adminq_describe_device(struct gve_priv *priv) dev_op_jumbo_frames, dev_op_dqo_qpl); free_device_descriptor: - dma_free_coherent(&priv->pdev->dev, PAGE_SIZE, descriptor, - descriptor_bus); + dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus); return err; } From 8ae980d24195f25d639e9f05421fcf80c5c64b3f Mon Sep 17 00:00:00 2001 From: John Fraker Date: Mon, 27 Nov 2023 16:26:45 -0800 Subject: [PATCH 1792/7721] gve: Deprecate adminq_pfn for pci revision 0x1. adminq_pfn assumes a page size of 4k, causing this mechanism to break in kernels compiled with different page sizes. A new PCI device revision was needed for the device to be able to communicate with the driver how to set up the admin queue prior to having access to the admin queue. Signed-off-by: Jordan Kimbrough Signed-off-by: John Fraker Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231128002648.320892-3-jfraker@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_adminq.c | 48 ++++++++++++++----- .../net/ethernet/google/gve/gve_register.h | 9 ++++ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index d3f3a015238d..f81ed6f6296a 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -225,9 +225,20 @@ int gve_adminq_alloc(struct device *dev, struct gve_priv *priv) priv->adminq_get_ptype_map_cnt = 0; /* Setup Admin queue with the device */ - iowrite32be(priv->adminq_bus_addr / PAGE_SIZE, - &priv->reg_bar0->adminq_pfn); - + if (priv->pdev->revision < 0x1) { + iowrite32be(priv->adminq_bus_addr / PAGE_SIZE, + &priv->reg_bar0->adminq_pfn); + } else { + iowrite16be(GVE_ADMINQ_BUFFER_SIZE, + &priv->reg_bar0->adminq_length); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + iowrite32be(priv->adminq_bus_addr >> 32, + &priv->reg_bar0->adminq_base_address_hi); +#endif + iowrite32be(priv->adminq_bus_addr, + &priv->reg_bar0->adminq_base_address_lo); + iowrite32be(GVE_DRIVER_STATUS_RUN_MASK, &priv->reg_bar0->driver_status); + } gve_set_admin_queue_ok(priv); return 0; } @@ -237,16 +248,27 @@ void gve_adminq_release(struct gve_priv *priv) int i = 0; /* Tell the device the adminq is leaving */ - iowrite32be(0x0, &priv->reg_bar0->adminq_pfn); - while (ioread32be(&priv->reg_bar0->adminq_pfn)) { - /* If this is reached the device is unrecoverable and still - * holding memory. Continue looping to avoid memory corruption, - * but WARN so it is visible what is going on. - */ - if (i == GVE_MAX_ADMINQ_RELEASE_CHECK) - WARN(1, "Unrecoverable platform error!"); - i++; - msleep(GVE_ADMINQ_SLEEP_LEN); + if (priv->pdev->revision < 0x1) { + iowrite32be(0x0, &priv->reg_bar0->adminq_pfn); + while (ioread32be(&priv->reg_bar0->adminq_pfn)) { + /* If this is reached the device is unrecoverable and still + * holding memory. Continue looping to avoid memory corruption, + * but WARN so it is visible what is going on. + */ + if (i == GVE_MAX_ADMINQ_RELEASE_CHECK) + WARN(1, "Unrecoverable platform error!"); + i++; + msleep(GVE_ADMINQ_SLEEP_LEN); + } + } else { + iowrite32be(GVE_DRIVER_STATUS_RESET_MASK, &priv->reg_bar0->driver_status); + while (!(ioread32be(&priv->reg_bar0->device_status) + & GVE_DEVICE_STATUS_DEVICE_IS_RESET)) { + if (i == GVE_MAX_ADMINQ_RELEASE_CHECK) + WARN(1, "Unrecoverable platform error!"); + i++; + msleep(GVE_ADMINQ_SLEEP_LEN); + } } gve_clear_device_rings_ok(priv); gve_clear_device_resources_ok(priv); diff --git a/drivers/net/ethernet/google/gve/gve_register.h b/drivers/net/ethernet/google/gve/gve_register.h index fb655463c357..8e72b97008d6 100644 --- a/drivers/net/ethernet/google/gve/gve_register.h +++ b/drivers/net/ethernet/google/gve/gve_register.h @@ -18,11 +18,20 @@ struct gve_registers { __be32 adminq_event_counter; u8 reserved[3]; u8 driver_version; + __be32 adminq_base_address_hi; + __be32 adminq_base_address_lo; + __be16 adminq_length; }; enum gve_device_status_flags { GVE_DEVICE_STATUS_RESET_MASK = BIT(1), GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2), GVE_DEVICE_STATUS_REPORT_STATS_MASK = BIT(3), + GVE_DEVICE_STATUS_DEVICE_IS_RESET = BIT(4), +}; + +enum gve_driver_status_flags { + GVE_DRIVER_STATUS_RUN_MASK = BIT(0), + GVE_DRIVER_STATUS_RESET_MASK = BIT(1), }; #endif /* _GVE_REGISTER_H_ */ From ce260cb114bbf65d53834c712729429b2233f5fd Mon Sep 17 00:00:00 2001 From: John Fraker Date: Mon, 27 Nov 2023 16:26:46 -0800 Subject: [PATCH 1793/7721] gve: Remove obsolete checks that rely on page size. These checks are safe to remove as they are no longer enforced by the backend. Retaining them would require updating them to work differently with page sizes larger than 4k. Signed-off-by: Jordan Kimbrough Signed-off-by: John Fraker Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231128002648.320892-4-jfraker@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_adminq.c | 11 ----------- drivers/net/ethernet/google/gve/gve_rx.c | 8 +------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index f81ed6f6296a..bebb7ed113d3 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -727,18 +727,7 @@ static int gve_set_desc_cnt(struct gve_priv *priv, struct gve_device_descriptor *descriptor) { priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries); - if (priv->tx_desc_cnt * sizeof(priv->tx->desc[0]) < PAGE_SIZE) { - dev_err(&priv->pdev->dev, "Tx desc count %d too low\n", - priv->tx_desc_cnt); - return -EINVAL; - } priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries); - if (priv->rx_desc_cnt * sizeof(priv->rx->desc.desc_ring[0]) - < PAGE_SIZE) { - dev_err(&priv->pdev->dev, "Rx desc count %d too low\n", - priv->rx_desc_cnt); - return -EINVAL; - } return 0; } diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index 73655347902d..82aa18588049 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -211,9 +211,9 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) { struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; - u32 slots, npages; int filled_pages; size_t bytes; + u32 slots; int err; netif_dbg(priv, drv, priv->dev, "allocating rx ring\n"); @@ -270,12 +270,6 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) /* alloc rx desc ring */ bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt; - npages = bytes / PAGE_SIZE; - if (npages * PAGE_SIZE != bytes) { - err = -EIO; - goto abort_with_q_resources; - } - rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus, GFP_KERNEL); if (!rx->desc.desc_ring) { From 513072fb4bf816686473eec897194ce6a28e53db Mon Sep 17 00:00:00 2001 From: John Fraker Date: Mon, 27 Nov 2023 16:26:47 -0800 Subject: [PATCH 1794/7721] gve: Add page size register to the register_page_list command. This register is required on platforms with page sizes greater than 4k. This is because the tx side of the driver vmaps the entire queue page list of pages into a single flat address space, then uses the entire space. Without communicating the guest page size to the backend, the backend will only access the first 4k of each page in the queue page list. Signed-off-by: Jordan Kimbrough Signed-off-by: John Fraker Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231128002648.320892-5-jfraker@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_adminq.c | 1 + drivers/net/ethernet/google/gve/gve_adminq.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index bebb7ed113d3..12fbd723ecc6 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -917,6 +917,7 @@ int gve_adminq_register_page_list(struct gve_priv *priv, .page_list_id = cpu_to_be32(qpl->id), .num_pages = cpu_to_be32(num_entries), .page_address_list_addr = cpu_to_be64(page_list_bus), + .page_size = cpu_to_be64(PAGE_SIZE), }; err = gve_adminq_execute_cmd(priv, &cmd); diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h index 38a22279e863..5865ccdccbd0 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.h +++ b/drivers/net/ethernet/google/gve/gve_adminq.h @@ -219,9 +219,10 @@ struct gve_adminq_register_page_list { __be32 page_list_id; __be32 num_pages; __be64 page_address_list_addr; + __be64 page_size; }; -static_assert(sizeof(struct gve_adminq_register_page_list) == 16); +static_assert(sizeof(struct gve_adminq_register_page_list) == 24); struct gve_adminq_unregister_page_list { __be32 page_list_id; From da7d4b42caf1b4d6ba3447bfd9ed185479fb0fe4 Mon Sep 17 00:00:00 2001 From: John Fraker Date: Mon, 27 Nov 2023 16:26:48 -0800 Subject: [PATCH 1795/7721] gve: Remove dependency on 4k page size. Prior to this change, gve crashes when attempting to run in kernels with page sizes other than 4k. This change removes unnecessary references to PAGE_SIZE and replaces them with more meaningful constants. Signed-off-by: Jordan Kimbrough Signed-off-by: John Fraker Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231128002648.320892-6-jfraker@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve.h | 4 +++- drivers/net/ethernet/google/gve/gve_ethtool.c | 2 +- drivers/net/ethernet/google/gve/gve_main.c | 4 ++-- drivers/net/ethernet/google/gve/gve_rx.c | 9 ++++----- drivers/net/ethernet/google/gve/gve_tx.c | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index abc0c708b47a..b80349154604 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -49,7 +49,9 @@ /* PTYPEs are always 10 bits. */ #define GVE_NUM_PTYPES 1024 -#define GVE_RX_BUFFER_SIZE_DQO 2048 +#define GVE_DEFAULT_RX_BUFFER_SIZE 2048 + +#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048 #define GVE_XDP_ACTIONS 5 diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index 233e5946905e..e5397aa1e48f 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -519,7 +519,7 @@ static int gve_set_tunable(struct net_device *netdev, case ETHTOOL_RX_COPYBREAK: { u32 max_copybreak = gve_is_gqi(priv) ? - (PAGE_SIZE / 2) : priv->data_buffer_size_dqo; + GVE_DEFAULT_RX_BUFFER_SIZE : priv->data_buffer_size_dqo; len = *(u32 *)value; if (len > max_copybreak) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index cc169748ffa2..619bf63ec935 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1328,7 +1328,7 @@ static int gve_open(struct net_device *dev) /* Hard code this for now. This may be tuned in the future for * performance. */ - priv->data_buffer_size_dqo = GVE_RX_BUFFER_SIZE_DQO; + priv->data_buffer_size_dqo = GVE_DEFAULT_RX_BUFFER_SIZE; } err = gve_create_rings(priv); if (err) @@ -1664,7 +1664,7 @@ static int verify_xdp_configuration(struct net_device *dev) return -EOPNOTSUPP; } - if (dev->mtu > (PAGE_SIZE / 2) - sizeof(struct ethhdr) - GVE_RX_PAD) { + if (dev->mtu > GVE_DEFAULT_RX_BUFFER_SIZE - sizeof(struct ethhdr) - GVE_RX_PAD) { netdev_warn(dev, "XDP is not supported for mtu %d.\n", dev->mtu); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index 82aa18588049..7a8dc5386fff 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -283,7 +283,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) /* Allocating half-page buffers allows page-flipping which is faster * than copying or allocating new pages. */ - rx->packet_buffer_size = PAGE_SIZE / 2; + rx->packet_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE; gve_rx_ctx_clear(&rx->ctx); gve_rx_add_to_block(priv, idx); @@ -399,10 +399,10 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi, static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, __be64 *slot_addr) { - const __be64 offset = cpu_to_be64(PAGE_SIZE / 2); + const __be64 offset = cpu_to_be64(GVE_DEFAULT_RX_BUFFER_OFFSET); /* "flip" to other packet buffer on this page */ - page_info->page_offset ^= PAGE_SIZE / 2; + page_info->page_offset ^= GVE_DEFAULT_RX_BUFFER_OFFSET; *(slot_addr) ^= offset; } @@ -507,8 +507,7 @@ static struct sk_buff *gve_rx_copy_to_pool(struct gve_rx_ring *rx, return NULL; gve_dec_pagecnt_bias(copy_page_info); - copy_page_info->page_offset += rx->packet_buffer_size; - copy_page_info->page_offset &= (PAGE_SIZE - 1); + copy_page_info->page_offset ^= GVE_DEFAULT_RX_BUFFER_OFFSET; if (copy_page_info->can_flip) { /* We have used both halves of this copy page, it diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index 9f6ffc4a54f0..07ba124780df 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -819,7 +819,7 @@ int gve_xdp_xmit_one(struct gve_priv *priv, struct gve_tx_ring *tx, return 0; } -#define GVE_TX_START_THRESH PAGE_SIZE +#define GVE_TX_START_THRESH 4096 static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx, u32 to_do, bool try_to_wake) From 87f062ed853ce75f9f71fd2f7aa9887ee7e8ba65 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 27 Nov 2023 15:50:59 +0100 Subject: [PATCH 1796/7721] net: dsa: microchip: ksz8: Make flow control, speed, and duplex on CPU port configurable Allow flow control, speed, and duplex settings on the CPU port to be configurable. Previously, the speed and duplex relied on default switch values, which limited flexibility. Additionally, flow control was hardcoded and only functional in duplex mode. This update enhances the configurability of these parameters. Signed-off-by: Oleksij Rempel Reviewed-by: Simon Horman Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/20231127145101.3039399-2-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8.h | 4 ++ drivers/net/dsa/microchip/ksz8795.c | 53 +++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_common.c | 1 + 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h index 4cea811e73ac..1a5225264e6a 100644 --- a/drivers/net/dsa/microchip/ksz8.h +++ b/drivers/net/dsa/microchip/ksz8.h @@ -56,5 +56,9 @@ int ksz8_reset_switch(struct ksz_device *dev); int ksz8_switch_init(struct ksz_device *dev); void ksz8_switch_exit(struct ksz_device *dev); int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu); +void ksz8_phylink_mac_link_up(struct ksz_device *dev, int port, + unsigned int mode, phy_interface_t interface, + struct phy_device *phydev, int speed, int duplex, + bool tx_pause, bool rx_pause); #endif diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 4bf4d67557dc..88b10aa527d6 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1439,6 +1439,57 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) } } +/** + * ksz8_cpu_port_link_up - Configures the CPU port of the switch. + * @dev: The KSZ device instance. + * @speed: The desired link speed. + * @duplex: The desired duplex mode. + * @tx_pause: If true, enables transmit pause. + * @rx_pause: If true, enables receive pause. + * + * Description: + * The function configures flow control and speed settings for the CPU + * port of the switch based on the desired settings, current duplex mode, and + * speed. + */ +static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + const u16 *regs = dev->info->regs; + u8 ctrl = 0; + + /* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable + * at least on KSZ8873. They can have different values depending on your + * board setup. + */ + if (tx_pause || rx_pause) + ctrl |= SW_FLOW_CTRL; + + if (duplex == DUPLEX_HALF) + ctrl |= SW_HALF_DUPLEX; + + /* This hardware only supports SPEED_10 and SPEED_100. For SPEED_10 + * we need to set the SW_10_MBIT bit. Otherwise, we can leave it 0. + */ + if (speed == SPEED_10) + ctrl |= SW_10_MBIT; + + ksz_rmw8(dev, regs[S_BROADCAST_CTRL], SW_HALF_DUPLEX | SW_FLOW_CTRL | + SW_10_MBIT, ctrl); +} + +void ksz8_phylink_mac_link_up(struct ksz_device *dev, int port, + unsigned int mode, phy_interface_t interface, + struct phy_device *phydev, int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + /* If the port is the CPU port, apply special handling. Only the CPU + * port is configured via global registers. + */ + if (dev->cpu_port == port) + ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause); +} + static int ksz8_handle_global_errata(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -1487,8 +1538,6 @@ int ksz8_setup(struct dsa_switch *ds) */ ds->vlan_filtering_is_global = true; - ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); - /* Enable automatic fast aging when link changed detected. */ ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 3fed406fb46a..0ee7cfb8d4bd 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -277,6 +277,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { .mirror_add = ksz8_port_mirror_add, .mirror_del = ksz8_port_mirror_del, .get_caps = ksz8_get_caps, + .phylink_mac_link_up = ksz8_phylink_mac_link_up, .config_cpu_port = ksz8_config_cpu_port, .enable_stp_addr = ksz8_enable_stp_addr, .reset = ksz8_reset_switch, From 2f58148c41e23e11f16e79308455d82ab9342607 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 27 Nov 2023 15:51:00 +0100 Subject: [PATCH 1797/7721] net: dsa: microchip: ksz8: Add function to configure ports with integrated PHYs This patch introduces the function 'ksz8_phy_port_link_up' to the Microchip KSZ8xxx driver. This function is responsible for setting up flow control and duplex settings for the ports that are integrated with PHYs. The KSZ8795 switch supports asymmetric pause control, which can't be fully utilized since a single bit controls both RX and TX pause. Despite this, the flow control can be adjusted based on the auto-negotiation process, taking into account the capabilities of both link partners. On the other hand, the KSZ8873's PORT_FORCE_FLOW_CTRL bit can be set by the hardware bootstrap, which ignores the auto-negotiation result. Therefore, even in auto-negotiation mode, we need to ensure that this bit is correctly set. When auto-negotiation isn't in use, we enforce symmetric pause control for the KSZ8795 switch. Please note, forcing flow control disable on a port while still advertising pause support isn't possible. While this scenario might not be practical or desired, it's important to be aware of this limitation when working with the KSZ8873 and similar devices. Signed-off-by: Oleksij Rempel Reviewed-by: Simon Horman Reviewed-by: Florian Fainelli Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/20231127145101.3039399-3-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8795.c | 70 ++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_common.c | 4 +- drivers/net/dsa/microchip/ksz_common.h | 1 + 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 88b10aa527d6..ec1ddfcf7473 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1439,6 +1439,74 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) } } +/** + * ksz8_phy_port_link_up - Configures ports with integrated PHYs + * @dev: The KSZ device instance. + * @port: The port number to configure. + * @duplex: The desired duplex mode. + * @tx_pause: If true, enables transmit pause. + * @rx_pause: If true, enables receive pause. + * + * Description: + * The function configures flow control settings for a given port based on the + * desired settings and current duplex mode. + * + * According to the KSZ8873 datasheet, the PORT_FORCE_FLOW_CTRL bit in the + * Port Control 2 register (0x1A for Port 1, 0x22 for Port 2, 0x32 for Port 3) + * determines how flow control is handled on the port: + * "1 = will always enable full-duplex flow control on the port, regardless + * of AN result. + * 0 = full-duplex flow control is enabled based on AN result." + * + * This means that the flow control behavior depends on the state of this bit: + * - If PORT_FORCE_FLOW_CTRL is set to 1, the switch will ignore AN results and + * force flow control on the port. + * - If PORT_FORCE_FLOW_CTRL is set to 0, the switch will enable or disable + * flow control based on the AN results. + * + * However, there is a potential limitation in this configuration. It is + * currently not possible to force disable flow control on a port if we still + * advertise pause support. While such a configuration is not currently + * supported by Linux, and may not make practical sense, it's important to be + * aware of this limitation when working with the KSZ8873 and similar devices. + */ +static void ksz8_phy_port_link_up(struct ksz_device *dev, int port, int duplex, + bool tx_pause, bool rx_pause) +{ + const u16 *regs = dev->info->regs; + u8 sctrl = 0; + + /* The KSZ8795 switch differs from the KSZ8873 by supporting + * asymmetric pause control. However, since a single bit is used to + * control both RX and TX pause, we can't enforce asymmetric pause + * control - both TX and RX pause will be either enabled or disabled + * together. + * + * If auto-negotiation is enabled, we usually allow the flow control to + * be determined by the auto-negotiation process based on the + * capabilities of both link partners. However, for KSZ8873, the + * PORT_FORCE_FLOW_CTRL bit may be set by the hardware bootstrap, + * ignoring the auto-negotiation result. Thus, even in auto-negotiation + * mode, we need to ensure that the PORT_FORCE_FLOW_CTRL bit is + * properly cleared. + * + * In the absence of pause auto-negotiation, we will enforce symmetric + * pause control for both variants of switches - KSZ8873 and KSZ8795. + * + * Autoneg Pause Autoneg rx,tx PORT_FORCE_FLOW_CTRL + * 1 1 x 0 + * 0 1 x 0 (flow control probably disabled) + * x 0 1 1 (flow control force enabled) + * 1 0 0 0 (flow control still depends on + * aneg result due to hardware) + * 0 0 0 0 (flow control probably disabled) + */ + if (dev->ports[port].manual_flow && tx_pause) + sctrl |= PORT_FORCE_FLOW_CTRL; + + ksz_prmw8(dev, port, regs[P_STP_CTRL], PORT_FORCE_FLOW_CTRL, sctrl); +} + /** * ksz8_cpu_port_link_up - Configures the CPU port of the switch. * @dev: The KSZ device instance. @@ -1488,6 +1556,8 @@ void ksz8_phylink_mac_link_up(struct ksz_device *dev, int port, */ if (dev->cpu_port == port) ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause); + else if (dev->info->internal_phy[port]) + ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause); } static int ksz8_handle_global_errata(struct dsa_switch *ds) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 0ee7cfb8d4bd..3b1fe9aff6a8 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2967,8 +2967,10 @@ static void ksz_phylink_mac_config(struct dsa_switch *ds, int port, { struct ksz_device *dev = ds->priv; - if (ksz_is_ksz88x3(dev)) + if (ksz_is_ksz88x3(dev)) { + dev->ports[port].manual_flow = !(state->pause & MLO_PAUSE_AN); return; + } /* Internal PHYs */ if (dev->info->internal_phy[port]) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index b7e8a403a132..d1a1c876ba0d 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -134,6 +134,7 @@ struct ksz_port { ktime_t tstamp_msg; struct completion tstamp_msg_comp; #endif + bool manual_flow; }; struct ksz_device { From 71cd5ce7e2f390de105b118a330ffe40a3417bdc Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 27 Nov 2023 15:51:01 +0100 Subject: [PATCH 1798/7721] net: dsa: microchip: make phylink_mac_link_up() not optional Last part of the driver do now support phylink_mac_link_up(). So, make it not optional. Signed-off-by: Oleksij Rempel Reviewed-by: Florian Fainelli Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/20231127145101.3039399-4-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 3b1fe9aff6a8..9545aed905f5 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -3113,10 +3113,8 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, { struct ksz_device *dev = ds->priv; - if (dev->dev_ops->phylink_mac_link_up) - dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface, - phydev, speed, duplex, - tx_pause, rx_pause); + dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface, phydev, + speed, duplex, tx_pause, rx_pause); } static int ksz_switch_detect(struct ksz_device *dev) From fd2096500acb8b57a66a75ec7985049a5650cff1 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 26 Nov 2023 21:42:01 +0000 Subject: [PATCH 1799/7721] drm/i915/irq: Improve error logging for unexpected DE Misc interrupts Dump the iir value in hex when the interrupt is unexpected. Link: https://gitlab.freedesktop.org/drm/intel/-/issues/9652#note_2178501 Cc: Jani Nikula Signed-off-by: Rahul Rameshbabu Reviewed-by: Chaitanya Kumar Borah Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231126214142.102106-1-sergeantsagara@protonmail.com --- drivers/gpu/drm/i915/display/intel_display_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 5a3e10e73e59..f8ed53f30b2e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -896,7 +896,7 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) } if (!found) - drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); + drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt: 0x%08x\n", iir); } static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, From ef32c3cc9c62252986f09e06b4e525742cd91529 Mon Sep 17 00:00:00 2001 From: heminhong Date: Tue, 14 Nov 2023 10:43:41 +0800 Subject: [PATCH 1800/7721] drm/i915: correct the input parameter on _intel_dsb_commit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current, the dewake_scanline variable is defined as unsigned int, an unsigned int variable that is always greater than or equal to 0. when _intel_dsb_commit function is called by intel_dsb_commit function, the dewake_scanline variable may have an int value. So the dewake_scanline variable is necessary to defined as an int. Fixes: f83b94d23770 ("drm/i915/dsb: Use DEwake to combat PkgC latency") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310052201.AnVbpgPr-lkp@intel.com/ Cc: Ville Syrjälä Cc: Uma Shankar Signed-off-by: heminhong Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231114024341.14524-1-heminhong@kylinos.cn --- drivers/gpu/drm/i915/display/intel_dsb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 9598d50f68f2..482c28b5c2de 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -341,7 +341,7 @@ static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state) } static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, - unsigned int dewake_scanline) + int dewake_scanline) { struct intel_crtc *crtc = dsb->crtc; struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); From d32bac9cb09cce4dc3131ec5d0b6ba3c277502ac Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 28 Nov 2023 17:56:37 +0100 Subject: [PATCH 1801/7721] ASoC: qcom: Add helper for allocating Soundwire stream runtime Newer Qualcomm SoC soundcards will need to allocate Soundwire stream runtime in their startup op. The code will be exactly the same for all soundcards, so add a helper for that. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231128165638.757665-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sdw.c | 45 +++++++++++++++++++++++++++++++++++++++++++- sound/soc/qcom/sdw.h | 1 + 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index dd275123d31d..77dbe0c28b29 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018, Linaro Limited. +// Copyright (c) 2018-2023, Linaro Limited. // Copyright (c) 2018, The Linux Foundation. All rights reserved. #include @@ -7,6 +7,49 @@ #include #include "sdw.h" +/** + * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card + * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup() + * + * Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set + * Soundwire stream runtime to each codec DAI. + * + * The shutdown() callback should call sdw_release_stream() on the same + * sdw_stream_runtime. + * + * Return: 0 or errno + */ +int qcom_snd_sdw_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime; + struct snd_soc_dai *codec_dai; + int ret, i; + + sruntime = sdw_alloc_stream(cpu_dai->name); + if (!sruntime) + return -ENOMEM; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_stream(codec_dai, sruntime, + substream->stream); + if (ret < 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "Failed to set sdw stream on %s\n", + codec_dai->name); + goto err_set_stream; + } + } + + return 0; + +err_set_stream: + sdw_release_stream(sruntime); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup); + int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime, bool *stream_prepared) diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h index d74cbb84da13..392e3455f1b1 100644 --- a/sound/soc/qcom/sdw.h +++ b/sound/soc/qcom/sdw.h @@ -6,6 +6,7 @@ #include +int qcom_snd_sdw_startup(struct snd_pcm_substream *substream); int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *runtime, bool *stream_prepared); From 15c7fab0e0477d7d7185eac574ca43c15b59b015 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 28 Nov 2023 17:56:38 +0100 Subject: [PATCH 1802/7721] ASoC: qcom: Move Soundwire runtime stream alloc to soundcards Currently the Qualcomm Soundwire controller in its DAI startup op allocates the Soundwire stream runtime. This works fine for existing designs, but has limitations for stream runtimes with multiple controllers, like upcoming Qualcomm X1E80100 SoC with four WSA8840 speakers on two Soundwire controllers. When two Soundwire controllers are added to sound card codecs, Soundwire startup() is called twice, one for each Soundwire controller, and second execution overwrites what was set before. During shutdown() this causes double free. It is expected to have only one Soundwire stream runtime, thus it should be allocated from SoC soundcard context startup(), not from each Soundwire startup(). Such way will properly handle both cases: one and two Soundwire controllers in the stream runtime. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231128165638.757665-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/soundwire/qcom.c | 33 +-------------------------------- sound/soc/qcom/sc8280xp.c | 13 +++++++++++++ sound/soc/qcom/sm8250.c | 15 ++++++++++++++- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index a1e2d6c98186..8076d40407d4 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -1265,10 +1265,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct sdw_stream_runtime *sruntime; - struct snd_soc_dai *codec_dai; - int ret, i; + int ret; ret = pm_runtime_get_sync(ctrl->dev); if (ret < 0 && ret != -EACCES) { @@ -1279,33 +1276,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, return ret; } - sruntime = sdw_alloc_stream(dai->name); - if (!sruntime) { - ret = -ENOMEM; - goto err_alloc; - } - - ctrl->sruntime[dai->id] = sruntime; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_stream(codec_dai, sruntime, - substream->stream); - if (ret < 0 && ret != -ENOTSUPP) { - dev_err(dai->dev, "Failed to set sdw stream on %s\n", - codec_dai->name); - goto err_set_stream; - } - } - return 0; - -err_set_stream: - sdw_release_stream(sruntime); -err_alloc: - pm_runtime_mark_last_busy(ctrl->dev); - pm_runtime_put_autosuspend(ctrl->dev); - - return ret; } static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, @@ -1314,8 +1285,6 @@ static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); swrm_wait_for_wr_fifo_done(ctrl); - sdw_release_stream(ctrl->sruntime[dai->id]); - ctrl->sruntime[dai->id] = NULL; pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index d93b18f07be5..7c20b25ba3de 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -31,6 +31,17 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } +static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; + + pdata->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +} + static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -91,6 +102,8 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) } static const struct snd_soc_ops sc8280xp_be_ops = { + .startup = qcom_snd_sdw_startup, + .shutdown = sc8280xp_snd_shutdown, .hw_params = sc8280xp_snd_hw_params, .hw_free = sc8280xp_snd_hw_free, .prepare = sc8280xp_snd_prepare, diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 9cc869fd70ac..f298167c2a23 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -66,7 +66,19 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) default: break; } - return 0; + + return qcom_snd_sdw_startup(substream); +} + +static void sm2450_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); } static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, @@ -103,6 +115,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sm8250_be_ops = { .startup = sm8250_snd_startup, + .shutdown = sm2450_snd_shutdown, .hw_params = sm8250_snd_hw_params, .hw_free = sm8250_snd_hw_free, .prepare = sm8250_snd_prepare, From 0f82a1b94862da255ac791e11f2c3610f5ad5f26 Mon Sep 17 00:00:00 2001 From: Balasubramani Vivekanandan Date: Tue, 28 Nov 2023 15:54:51 +0530 Subject: [PATCH 1803/7721] drm/i915/display: Fix IP version of the WAs WAs 14011508470, 14011503030 were applied on IP versions beyond which they are applicable. Fixed the IP version checks for these workarounds. Signed-off-by: Balasubramani Vivekanandan Reviewed-by: Gustavo Sousa Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20231128102451.825242-1-balasubramani.vivekanandan@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e390595d7341..f23080a4368d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1697,14 +1697,14 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, if (resume) intel_dmc_load_program(dev_priv); - /* Wa_14011508470:tgl,dg1,rkl,adl-s,adl-p */ - if (DISPLAY_VER(dev_priv) >= 12) + /* Wa_14011508470:tgl,dg1,rkl,adl-s,adl-p,dg2 */ + if (IS_DISPLAY_IP_RANGE(dev_priv, IP_VER(12, 0), IP_VER(13, 0))) intel_de_rmw(dev_priv, GEN11_CHICKEN_DCPR_2, 0, DCPR_CLEAR_MEMSTAT_DIS | DCPR_SEND_RESP_IMM | DCPR_MASK_LPMODE | DCPR_MASK_MAXLATENCY_MEMUP_CLR); /* Wa_14011503030:xelpd */ - if (DISPLAY_VER(dev_priv) >= 13) + if (DISPLAY_VER(dev_priv) == 13) intel_de_write(dev_priv, XELPD_DISPLAY_ERR_FATAL_MASK, ~0); } From dad19630c476f4c3d88f222c60f254f13e6245ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 29 Nov 2023 10:06:37 +0100 Subject: [PATCH 1804/7721] Documentation/gpu: VM_BIND locking document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the first version of the VM_BIND locking document which is intended to be part of the xe driver upstreaming agreement. The document describes and discuss the locking used during exec- functions, evicton and for userptr gpu-vmas. Intention is to be using the same nomenclature as the drm-vm-bind-async.rst. v2: - s/gvm/gpu_vm/g (Rodrigo Vivi) - Clarify the userptr seqlock with a pointer to mm/mmu_notifier.c (Rodrigo Vivi) - Adjust commit message accordingly. - Add SPDX license header. v3: - Large update to align with the drm_gpuvm manager locking - Add "Efficient userptr gpu_vma exec function iteration" section - Add "Locking at bind- and unbind time" section. v4: - Fix tabs vs space errors by untabifying (Rodrigo Vivi) - Minor style fixes and typos (Rodrigo Vivi) - Clarify situations where stale GPU mappings are occurring and how access through these mappings are blocked. (Rodrigo Vivi) - Insert into the toctree in implementation_guidelines.rst v5: - Add a section about recoverable page-faults. - Use local references to other documentation where possible (Bagas Sanjaya) - General documentation fixes and typos (Danilo Krummrich and Boris Brezillon) - Improve the documentation around locks that need to be grabbed from the dm-fence critical section (Boris Brezillon) - Add more references to the DRM GPUVM helpers (Danilo Krummrich and Boriz Brezillon) - Update the rfc/xe.rst document. v6: - Rework wording to improve readability (Boris Brezillon, Rodrigo Vivi, Bagas Sanjaya) - Various minor fixes across the document (Boris Brezillon) Cc: Rodrigo Vivi Signed-off-by: Thomas Hellström Reviewed-by: Boris Brezillon Reviewed-by: Rodrigo Vivi Reviewed-by: Danilo Krummrich Acked-by: John Hubbard # Documentation/core-api/pin_user_pages.rst changes Link: https://patchwork.freedesktop.org/patch/msgid/20231129090637.2629-1-thomas.hellstrom@linux.intel.com --- Documentation/core-api/pin_user_pages.rst | 2 + Documentation/gpu/drm-mm.rst | 4 + Documentation/gpu/drm-vm-bind-locking.rst | 582 ++++++++++++++++++ .../gpu/implementation_guidelines.rst | 1 + Documentation/gpu/rfc/xe.rst | 5 + 5 files changed, 594 insertions(+) create mode 100644 Documentation/gpu/drm-vm-bind-locking.rst diff --git a/Documentation/core-api/pin_user_pages.rst b/Documentation/core-api/pin_user_pages.rst index d3c1f6d8c0e0..6b5f7e6e7155 100644 --- a/Documentation/core-api/pin_user_pages.rst +++ b/Documentation/core-api/pin_user_pages.rst @@ -153,6 +153,8 @@ NOTE: Some pages, such as DAX pages, cannot be pinned with longterm pins. That's because DAX pages do not have a separate page cache, and so "pinning" implies locking down file system blocks, which is not (yet) supported in that way. +.. _mmu-notifier-registration-case: + CASE 3: MMU notifier registration, with or without page faulting hardware ------------------------------------------------------------------------- Device drivers can pin pages via get_user_pages*(), and register for mmu diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index acc5901ac840..d55751cad67c 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -466,6 +466,8 @@ DRM MM Range Allocator Function References .. kernel-doc:: drivers/gpu/drm/drm_mm.c :export: +.. _drm_gpuvm: + DRM GPUVM ========= @@ -481,6 +483,8 @@ Split and Merge .. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Split and Merge +.. _drm_gpuvm_locking: + Locking ------- diff --git a/Documentation/gpu/drm-vm-bind-locking.rst b/Documentation/gpu/drm-vm-bind-locking.rst new file mode 100644 index 000000000000..a345aa513d12 --- /dev/null +++ b/Documentation/gpu/drm-vm-bind-locking.rst @@ -0,0 +1,582 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=============== +VM_BIND locking +=============== + +This document attempts to describe what's needed to get VM_BIND locking right, +including the userptr mmu_notifier locking. It also discusses some +optimizations to get rid of the looping through of all userptr mappings and +external / shared object mappings that is needed in the simplest +implementation. In addition, there is a section describing the VM_BIND locking +required for implementing recoverable pagefaults. + +The DRM GPUVM set of helpers +============================ + +There is a set of helpers for drivers implementing VM_BIND, and this +set of helpers implements much, but not all of the locking described +in this document. In particular, it is currently lacking a userptr +implementation. This document does not intend to describe the DRM GPUVM +implementation in detail, but it is covered in :ref:`its own +documentation `. It is highly recommended for any driver +implementing VM_BIND to use the DRM GPUVM helpers and to extend it if +common functionality is missing. + +Nomenclature +============ + +* ``gpu_vm``: Abstraction of a virtual GPU address space with + meta-data. Typically one per client (DRM file-private), or one per + execution context. +* ``gpu_vma``: Abstraction of a GPU address range within a gpu_vm with + associated meta-data. The backing storage of a gpu_vma can either be + a GEM object or anonymous or page-cache pages mapped also into the CPU + address space for the process. +* ``gpu_vm_bo``: Abstracts the association of a GEM object and + a VM. The GEM object maintains a list of gpu_vm_bos, where each gpu_vm_bo + maintains a list of gpu_vmas. +* ``userptr gpu_vma or just userptr``: A gpu_vma, whose backing store + is anonymous or page-cache pages as described above. +* ``revalidating``: Revalidating a gpu_vma means making the latest version + of the backing store resident and making sure the gpu_vma's + page-table entries point to that backing store. +* ``dma_fence``: A struct dma_fence that is similar to a struct completion + and which tracks GPU activity. When the GPU activity is finished, + the dma_fence signals. Please refer to the ``DMA Fences`` section of + the :doc:`dma-buf doc `. +* ``dma_resv``: A struct dma_resv (a.k.a reservation object) that is used + to track GPU activity in the form of multiple dma_fences on a + gpu_vm or a GEM object. The dma_resv contains an array / list + of dma_fences and a lock that needs to be held when adding + additional dma_fences to the dma_resv. The lock is of a type that + allows deadlock-safe locking of multiple dma_resvs in arbitrary + order. Please refer to the ``Reservation Objects`` section of the + :doc:`dma-buf doc `. +* ``exec function``: An exec function is a function that revalidates all + affected gpu_vmas, submits a GPU command batch and registers the + dma_fence representing the GPU command's activity with all affected + dma_resvs. For completeness, although not covered by this document, + it's worth mentioning that an exec function may also be the + revalidation worker that is used by some drivers in compute / + long-running mode. +* ``local object``: A GEM object which is only mapped within a + single VM. Local GEM objects share the gpu_vm's dma_resv. +* ``external object``: a.k.a shared object: A GEM object which may be shared + by multiple gpu_vms and whose backing storage may be shared with + other drivers. + +Locks and locking order +======================= + +One of the benefits of VM_BIND is that local GEM objects share the gpu_vm's +dma_resv object and hence the dma_resv lock. So, even with a huge +number of local GEM objects, only one lock is needed to make the exec +sequence atomic. + +The following locks and locking orders are used: + +* The ``gpu_vm->lock`` (optionally an rwsem). Protects the gpu_vm's + data structure keeping track of gpu_vmas. It can also protect the + gpu_vm's list of userptr gpu_vmas. With a CPU mm analogy this would + correspond to the mmap_lock. An rwsem allows several readers to walk + the VM tree concurrently, but the benefit of that concurrency most + likely varies from driver to driver. +* The ``userptr_seqlock``. This lock is taken in read mode for each + userptr gpu_vma on the gpu_vm's userptr list, and in write mode during mmu + notifier invalidation. This is not a real seqlock but described in + ``mm/mmu_notifier.c`` as a "Collision-retry read-side/write-side + 'lock' a lot like a seqcount. However this allows multiple + write-sides to hold it at once...". The read side critical section + is enclosed by ``mmu_interval_read_begin() / + mmu_interval_read_retry()`` with ``mmu_interval_read_begin()`` + sleeping if the write side is held. + The write side is held by the core mm while calling mmu interval + invalidation notifiers. +* The ``gpu_vm->resv`` lock. Protects the gpu_vm's list of gpu_vmas needing + rebinding, as well as the residency state of all the gpu_vm's local + GEM objects. + Furthermore, it typically protects the gpu_vm's list of evicted and + external GEM objects. +* The ``gpu_vm->userptr_notifier_lock``. This is an rwsem that is + taken in read mode during exec and write mode during a mmu notifier + invalidation. The userptr notifier lock is per gpu_vm. +* The ``gem_object->gpuva_lock`` This lock protects the GEM object's + list of gpu_vm_bos. This is usually the same lock as the GEM + object's dma_resv, but some drivers protects this list differently, + see below. +* The ``gpu_vm list spinlocks``. With some implementations they are needed + to be able to update the gpu_vm evicted- and external object + list. For those implementations, the spinlocks are grabbed when the + lists are manipulated. However, to avoid locking order violations + with the dma_resv locks, a special scheme is needed when iterating + over the lists. + +.. _gpu_vma lifetime: + +Protection and lifetime of gpu_vm_bos and gpu_vmas +================================================== + +The GEM object's list of gpu_vm_bos, and the gpu_vm_bo's list of gpu_vmas +is protected by the ``gem_object->gpuva_lock``, which is typically the +same as the GEM object's dma_resv, but if the driver +needs to access these lists from within a dma_fence signalling +critical section, it can instead choose to protect it with a +separate lock, which can be locked from within the dma_fence signalling +critical section. Such drivers then need to pay additional attention +to what locks need to be taken from within the loop when iterating +over the gpu_vm_bo and gpu_vma lists to avoid locking-order violations. + +The DRM GPUVM set of helpers provide lockdep asserts that this lock is +held in relevant situations and also provides a means of making itself +aware of which lock is actually used: :c:func:`drm_gem_gpuva_set_lock`. + +Each gpu_vm_bo holds a reference counted pointer to the underlying GEM +object, and each gpu_vma holds a reference counted pointer to the +gpu_vm_bo. When iterating over the GEM object's list of gpu_vm_bos and +over the gpu_vm_bo's list of gpu_vmas, the ``gem_object->gpuva_lock`` must +not be dropped, otherwise, gpu_vmas attached to a gpu_vm_bo may +disappear without notice since those are not reference-counted. A +driver may implement its own scheme to allow this at the expense of +additional complexity, but this is outside the scope of this document. + +In the DRM GPUVM implementation, each gpu_vm_bo and each gpu_vma +holds a reference count on the gpu_vm itself. Due to this, and to avoid circular +reference counting, cleanup of the gpu_vm's gpu_vmas must not be done from the +gpu_vm's destructor. Drivers typically implements a gpu_vm close +function for this cleanup. The gpu_vm close function will abort gpu +execution using this VM, unmap all gpu_vmas and release page-table memory. + +Revalidation and eviction of local objects +========================================== + +Note that in all the code examples given below we use simplified +pseudo-code. In particular, the dma_resv deadlock avoidance algorithm +as well as reserving memory for dma_resv fences is left out. + +Revalidation +____________ +With VM_BIND, all local objects need to be resident when the gpu is +executing using the gpu_vm, and the objects need to have valid +gpu_vmas set up pointing to them. Typically, each gpu command buffer +submission is therefore preceded with a re-validation section: + +.. code-block:: C + + dma_resv_lock(gpu_vm->resv); + + // Validation section starts here. + for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) { + validate_gem_bo(&gpu_vm_bo->gem_bo); + + // The following list iteration needs the Gem object's + // dma_resv to be held (it protects the gpu_vm_bo's list of + // gpu_vmas, but since local gem objects share the gpu_vm's + // dma_resv, it is already held at this point. + for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma) + move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list); + } + + for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) { + rebind_gpu_vma(&gpu_vma); + remove_gpu_vma_from_rebind_list(&gpu_vma); + } + // Validation section ends here, and job submission starts. + + add_dependencies(&gpu_job, &gpu_vm->resv); + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + dma_resv_unlock(gpu_vm->resv); + +The reason for having a separate gpu_vm rebind list is that there +might be userptr gpu_vmas that are not mapping a buffer object that +also need rebinding. + +Eviction +________ + +Eviction of one of these local objects will then look similar to the +following: + +.. code-block:: C + + obj = get_object_from_lru(); + + dma_resv_lock(obj->resv); + for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo); + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + + add_dependencies(&eviction_job, &obj->resv); + job_dma_fence = gpu_submit(&eviction_job); + add_dma_fence(&obj->resv, job_dma_fence); + + dma_resv_unlock(&obj->resv); + put_object(obj); + +Note that since the object is local to the gpu_vm, it will share the gpu_vm's +dma_resv lock such that ``obj->resv == gpu_vm->resv``. +The gpu_vm_bos marked for eviction are put on the gpu_vm's evict list, +which is protected by ``gpu_vm->resv``. During eviction all local +objects have their dma_resv locked and, due to the above equality, also +the gpu_vm's dma_resv protecting the gpu_vm's evict list is locked. + +With VM_BIND, gpu_vmas don't need to be unbound before eviction, +since the driver must ensure that the eviction blit or copy will wait +for GPU idle or depend on all previous GPU activity. Furthermore, any +subsequent attempt by the GPU to access freed memory through the +gpu_vma will be preceded by a new exec function, with a revalidation +section which will make sure all gpu_vmas are rebound. The eviction +code holding the object's dma_resv while revalidating will ensure a +new exec function may not race with the eviction. + +A driver can be implemented in such a way that, on each exec function, +only a subset of vmas are selected for rebind. In this case, all vmas that are +*not* selected for rebind must be unbound before the exec +function workload is submitted. + +Locking with external buffer objects +==================================== + +Since external buffer objects may be shared by multiple gpu_vm's they +can't share their reservation object with a single gpu_vm. Instead +they need to have a reservation object of their own. The external +objects bound to a gpu_vm using one or many gpu_vmas are therefore put on a +per-gpu_vm list which is protected by the gpu_vm's dma_resv lock or +one of the :ref:`gpu_vm list spinlocks `. Once +the gpu_vm's reservation object is locked, it is safe to traverse the +external object list and lock the dma_resvs of all external +objects. However, if instead a list spinlock is used, a more elaborate +iteration scheme needs to be used. + +At eviction time, the gpu_vm_bos of *all* the gpu_vms an external +object is bound to need to be put on their gpu_vm's evict list. +However, when evicting an external object, the dma_resvs of the +gpu_vms the object is bound to are typically not held. Only +the object's private dma_resv can be guaranteed to be held. If there +is a ww_acquire context at hand at eviction time we could grab those +dma_resvs but that could cause expensive ww_mutex rollbacks. A simple +option is to just mark the gpu_vm_bos of the evicted gem object with +an ``evicted`` bool that is inspected before the next time the +corresponding gpu_vm evicted list needs to be traversed. For example, when +traversing the list of external objects and locking them. At that time, +both the gpu_vm's dma_resv and the object's dma_resv is held, and the +gpu_vm_bo marked evicted, can then be added to the gpu_vm's list of +evicted gpu_vm_bos. The ``evicted`` bool is formally protected by the +object's dma_resv. + +The exec function becomes + +.. code-block:: C + + dma_resv_lock(gpu_vm->resv); + + // External object list is protected by the gpu_vm->resv lock. + for_each_gpu_vm_bo_on_extobj_list(gpu_vm, &gpu_vm_bo) { + dma_resv_lock(gpu_vm_bo.gem_obj->resv); + if (gpu_vm_bo_marked_evicted(&gpu_vm_bo)) + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + } + + for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) { + validate_gem_bo(&gpu_vm_bo->gem_bo); + + for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma) + move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list); + } + + for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) { + rebind_gpu_vma(&gpu_vma); + remove_gpu_vma_from_rebind_list(&gpu_vma); + } + + add_dependencies(&gpu_job, &gpu_vm->resv); + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + for_each_external_obj(gpu_vm, &obj) + add_dma_fence(job_dma_fence, &obj->resv); + dma_resv_unlock_all_resv_locks(); + +And the corresponding shared-object aware eviction would look like: + +.. code-block:: C + + obj = get_object_from_lru(); + + dma_resv_lock(obj->resv); + for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo) + if (object_is_vm_local(obj)) + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + else + mark_gpu_vm_bo_evicted(&gpu_vm_bo); + + add_dependencies(&eviction_job, &obj->resv); + job_dma_fence = gpu_submit(&eviction_job); + add_dma_fence(&obj->resv, job_dma_fence); + + dma_resv_unlock(&obj->resv); + put_object(obj); + +.. _Spinlock iteration: + +Accessing the gpu_vm's lists without the dma_resv lock held +=========================================================== + +Some drivers will hold the gpu_vm's dma_resv lock when accessing the +gpu_vm's evict list and external objects lists. However, there are +drivers that need to access these lists without the dma_resv lock +held, for example due to asynchronous state updates from within the +dma_fence signalling critical path. In such cases, a spinlock can be +used to protect manipulation of the lists. However, since higher level +sleeping locks need to be taken for each list item while iterating +over the lists, the items already iterated over need to be +temporarily moved to a private list and the spinlock released +while processing each item: + +.. code block:: C + + struct list_head still_in_list; + + INIT_LIST_HEAD(&still_in_list); + + spin_lock(&gpu_vm->list_lock); + do { + struct list_head *entry = list_first_entry_or_null(&gpu_vm->list, head); + + if (!entry) + break; + + list_move_tail(&entry->head, &still_in_list); + list_entry_get_unless_zero(entry); + spin_unlock(&gpu_vm->list_lock); + + process(entry); + + spin_lock(&gpu_vm->list_lock); + list_entry_put(entry); + } while (true); + + list_splice_tail(&still_in_list, &gpu_vm->list); + spin_unlock(&gpu_vm->list_lock); + +Due to the additional locking and atomic operations, drivers that *can* +avoid accessing the gpu_vm's list outside of the dma_resv lock +might want to avoid also this iteration scheme. Particularly, if the +driver anticipates a large number of list items. For lists where the +anticipated number of list items is small, where list iteration doesn't +happen very often or if there is a significant additional cost +associated with each iteration, the atomic operation overhead +associated with this type of iteration is, most likely, negligible. Note that +if this scheme is used, it is necessary to make sure this list +iteration is protected by an outer level lock or semaphore, since list +items are temporarily pulled off the list while iterating, and it is +also worth mentioning that the local list ``still_in_list`` should +also be considered protected by the ``gpu_vm->list_lock``, and it is +thus possible that items can be removed also from the local list +concurrently with list iteration. + +Please refer to the :ref:`DRM GPUVM locking section +` and its internal +:c:func:`get_next_vm_bo_from_list` function. + + +userptr gpu_vmas +================ + +A userptr gpu_vma is a gpu_vma that, instead of mapping a buffer object to a +GPU virtual address range, directly maps a CPU mm range of anonymous- +or file page-cache pages. +A very simple approach would be to just pin the pages using +pin_user_pages() at bind time and unpin them at unbind time, but this +creates a Denial-Of-Service vector since a single user-space process +would be able to pin down all of system memory, which is not +desirable. (For special use-cases and assuming proper accounting pinning might +still be a desirable feature, though). What we need to do in the +general case is to obtain a reference to the desired pages, make sure +we are notified using a MMU notifier just before the CPU mm unmaps the +pages, dirty them if they are not mapped read-only to the GPU, and +then drop the reference. +When we are notified by the MMU notifier that CPU mm is about to drop the +pages, we need to stop GPU access to the pages by waiting for VM idle +in the MMU notifier and make sure that before the next time the GPU +tries to access whatever is now present in the CPU mm range, we unmap +the old pages from the GPU page tables and repeat the process of +obtaining new page references. (See the :ref:`notifier example +` below). Note that when the core mm decides to +laundry pages, we get such an unmap MMU notification and can mark the +pages dirty again before the next GPU access. We also get similar MMU +notifications for NUMA accounting which the GPU driver doesn't really +need to care about, but so far it has proven difficult to exclude +certain notifications. + +Using a MMU notifier for device DMA (and other methods) is described in +:ref:`the pin_user_pages() documentation `. + +Now, the method of obtaining struct page references using +get_user_pages() unfortunately can't be used under a dma_resv lock +since that would violate the locking order of the dma_resv lock vs the +mmap_lock that is grabbed when resolving a CPU pagefault. This means +the gpu_vm's list of userptr gpu_vmas needs to be protected by an +outer lock, which in our example below is the ``gpu_vm->lock``. + +The MMU interval seqlock for a userptr gpu_vma is used in the following +way: + +.. code-block:: C + + // Exclusive locking mode here is strictly needed only if there are + // invalidated userptr gpu_vmas present, to avoid concurrent userptr + // revalidations of the same userptr gpu_vma. + down_write(&gpu_vm->lock); + retry: + + // Note: mmu_interval_read_begin() blocks until there is no + // invalidation notifier running anymore. + seq = mmu_interval_read_begin(&gpu_vma->userptr_interval); + if (seq != gpu_vma->saved_seq) { + obtain_new_page_pointers(&gpu_vma); + dma_resv_lock(&gpu_vm->resv); + add_gpu_vma_to_revalidate_list(&gpu_vma, &gpu_vm); + dma_resv_unlock(&gpu_vm->resv); + gpu_vma->saved_seq = seq; + } + + // The usual revalidation goes here. + + // Final userptr sequence validation may not happen before the + // submission dma_fence is added to the gpu_vm's resv, from the POW + // of the MMU invalidation notifier. Hence the + // userptr_notifier_lock that will make them appear atomic. + + add_dependencies(&gpu_job, &gpu_vm->resv); + down_read(&gpu_vm->userptr_notifier_lock); + if (mmu_interval_read_retry(&gpu_vma->userptr_interval, gpu_vma->saved_seq)) { + up_read(&gpu_vm->userptr_notifier_lock); + goto retry; + } + + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + + for_each_external_obj(gpu_vm, &obj) + add_dma_fence(job_dma_fence, &obj->resv); + + dma_resv_unlock_all_resv_locks(); + up_read(&gpu_vm->userptr_notifier_lock); + up_write(&gpu_vm->lock); + +The code between ``mmu_interval_read_begin()`` and the +``mmu_interval_read_retry()`` marks the read side critical section of +what we call the ``userptr_seqlock``. In reality, the gpu_vm's userptr +gpu_vma list is looped through, and the check is done for *all* of its +userptr gpu_vmas, although we only show a single one here. + +The userptr gpu_vma MMU invalidation notifier might be called from +reclaim context and, again, to avoid locking order violations, we can't +take any dma_resv lock nor the gpu_vm->lock from within it. + +.. _Invalidation example: +.. code-block:: C + + bool gpu_vma_userptr_invalidate(userptr_interval, cur_seq) + { + // Make sure the exec function either sees the new sequence + // and backs off or we wait for the dma-fence: + + down_write(&gpu_vm->userptr_notifier_lock); + mmu_interval_set_seq(userptr_interval, cur_seq); + up_write(&gpu_vm->userptr_notifier_lock); + + // At this point, the exec function can't succeed in + // submitting a new job, because cur_seq is an invalid + // sequence number and will always cause a retry. When all + // invalidation callbacks, the mmu notifier core will flip + // the sequence number to a valid one. However we need to + // stop gpu access to the old pages here. + + dma_resv_wait_timeout(&gpu_vm->resv, DMA_RESV_USAGE_BOOKKEEP, + false, MAX_SCHEDULE_TIMEOUT); + return true; + } + +When this invalidation notifier returns, the GPU can no longer be +accessing the old pages of the userptr gpu_vma and needs to redo the +page-binding before a new GPU submission can succeed. + +Efficient userptr gpu_vma exec_function iteration +_________________________________________________ + +If the gpu_vm's list of userptr gpu_vmas becomes large, it's +inefficient to iterate through the complete lists of userptrs on each +exec function to check whether each userptr gpu_vma's saved +sequence number is stale. A solution to this is to put all +*invalidated* userptr gpu_vmas on a separate gpu_vm list and +only check the gpu_vmas present on this list on each exec +function. This list will then lend itself very-well to the spinlock +locking scheme that is +:ref:`described in the spinlock iteration section `, since +in the mmu notifier, where we add the invalidated gpu_vmas to the +list, it's not possible to take any outer locks like the +``gpu_vm->lock`` or the ``gpu_vm->resv`` lock. Note that the +``gpu_vm->lock`` still needs to be taken while iterating to ensure the list is +complete, as also mentioned in that section. + +If using an invalidated userptr list like this, the retry check in the +exec function trivially becomes a check for invalidated list empty. + +Locking at bind and unbind time +=============================== + +At bind time, assuming a GEM object backed gpu_vma, each +gpu_vma needs to be associated with a gpu_vm_bo and that +gpu_vm_bo in turn needs to be added to the GEM object's +gpu_vm_bo list, and possibly to the gpu_vm's external object +list. This is referred to as *linking* the gpu_vma, and typically +requires that the ``gpu_vm->lock`` and the ``gem_object->gpuva_lock`` +are held. When unlinking a gpu_vma the same locks should be held, +and that ensures that when iterating over ``gpu_vmas`, either under +the ``gpu_vm->resv`` or the GEM object's dma_resv, that the gpu_vmas +stay alive as long as the lock under which we iterate is not released. For +userptr gpu_vmas it's similarly required that during vma destroy, the +outer ``gpu_vm->lock`` is held, since otherwise when iterating over +the invalidated userptr list as described in the previous section, +there is nothing keeping those userptr gpu_vmas alive. + +Locking for recoverable page-fault page-table updates +===================================================== + +There are two important things we need to ensure with locking for +recoverable page-faults: + +* At the time we return pages back to the system / allocator for + reuse, there should be no remaining GPU mappings and any GPU TLB + must have been flushed. +* The unmapping and mapping of a gpu_vma must not race. + +Since the unmapping (or zapping) of GPU ptes is typically taking place +where it is hard or even impossible to take any outer level locks we +must either introduce a new lock that is held at both mapping and +unmapping time, or look at the locks we do hold at unmapping time and +make sure that they are held also at mapping time. For userptr +gpu_vmas, the ``userptr_seqlock`` is held in write mode in the mmu +invalidation notifier where zapping happens. Hence, if the +``userptr_seqlock`` as well as the ``gpu_vm->userptr_notifier_lock`` +is held in read mode during mapping, it will not race with the +zapping. For GEM object backed gpu_vmas, zapping will take place under +the GEM object's dma_resv and ensuring that the dma_resv is held also +when populating the page-tables for any gpu_vma pointing to the GEM +object, will similarly ensure we are race-free. + +If any part of the mapping is performed asynchronously +under a dma-fence with these locks released, the zapping will need to +wait for that dma-fence to signal under the relevant lock before +starting to modify the page-table. + +Since modifying the +page-table structure in a way that frees up page-table memory +might also require outer level locks, the zapping of GPU ptes +typically focuses only on zeroing page-table or page-directory entries +and flushing TLB, whereas freeing of page-table memory is deferred to +unbind or rebind time. diff --git a/Documentation/gpu/implementation_guidelines.rst b/Documentation/gpu/implementation_guidelines.rst index 138e637dcc6b..dbccfa72f1c9 100644 --- a/Documentation/gpu/implementation_guidelines.rst +++ b/Documentation/gpu/implementation_guidelines.rst @@ -7,3 +7,4 @@ Misc DRM driver uAPI- and feature implementation guidelines .. toctree:: drm-vm-bind-async + drm-vm-bind-locking diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index c29113a0ac30..ceb21219d52e 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -123,10 +123,15 @@ Documentation should include: * O(1) complexity under VM_BIND. +The document is now included in the drm documentation :doc:`here `. + Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when the second driver supporting VM_BIND+userptr appears. Details to be defined when the time comes. +The DRM GPUVM helpers do not yet include the userptr parts, but discussions +about implementing them are ongoing. + Long running compute: minimal data structure/scaffolding -------------------------------------------------------- The generic scheduler code needs to include the handling of endless compute From e185a24eeab3efd667176aef60f88d27ce641cd7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:21:21 +0100 Subject: [PATCH 1805/7721] dt-bindings: correct white-spaces in examples Use only one and exactly one space around '=' in DTS example. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Mathieu Poirier Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Acked-by: Serge Semin Acked-by: Ulf Hansson # For MMC Acked-by: Jonathan Cameron #for-iio Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20231124092121.16866-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/auxdisplay/hit,hd44780.yaml | 2 +- .../devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml | 2 +- Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml | 6 +++--- .../devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml | 2 +- .../devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml | 2 +- .../interrupt-controller/st,stih407-irq-syscfg.yaml | 4 ++-- Documentation/devicetree/bindings/mmc/arm,pl18x.yaml | 2 +- Documentation/devicetree/bindings/net/sff,sfp.yaml | 2 +- .../devicetree/bindings/pci/toshiba,visconti-pcie.yaml | 2 +- .../bindings/pinctrl/renesas,rzg2l-pinctrl.yaml | 6 +++--- .../devicetree/bindings/power/supply/richtek,rt9455.yaml | 8 ++++---- .../devicetree/bindings/regulator/mps,mp5416.yaml | 4 ++-- .../devicetree/bindings/regulator/mps,mpq7920.yaml | 4 ++-- .../devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 8 ++++---- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml index fde07e4b119d..406a922a714e 100644 --- a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml +++ b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml @@ -113,7 +113,7 @@ examples: hd44780 { compatible = "hit,hd44780"; display-height-chars = <2>; - display-width-chars = <16>; + display-width-chars = <16>; data-gpios = <&pcf8574 4 0>, <&pcf8574 5 0>, <&pcf8574 6 0>, diff --git a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml index 624984d51c10..7f8d98226437 100644 --- a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml +++ b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml @@ -125,7 +125,7 @@ examples: clk25m: clock-oscillator-25m { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <25000000>; + clock-frequency = <25000000>; clock-output-names = "clk25m"; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml index 5fcc8dd012f1..be2616ff9af6 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml @@ -80,9 +80,9 @@ examples: compatible = "adi,ad7780"; reg = <0>; - avdd-supply = <&vdd_supply>; - powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; - adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + avdd-supply = <&vdd_supply>; + powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; adi,filter-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml index 73def67fbe01..b6a233cd5f6b 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml @@ -58,7 +58,7 @@ examples: reg = <0x3600>; interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; qcom,external-resistor-micro-ohms = <10000>; - #io-channel-cells = <1>; + #io-channel-cells = <1>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml index b3a626389870..64abe9a4cd9e 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml @@ -46,6 +46,6 @@ examples: pmic_rradc: adc@4500 { compatible = "qcom,pmi8998-rradc"; reg = <0x4500>; - #io-channel-cells = <1>; + #io-channel-cells = <1>; }; }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml index 2b153d7c5421..e44e4e5708a7 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml @@ -55,8 +55,8 @@ examples: - | #include irq-syscfg { - compatible = "st,stih407-irq-syscfg"; - st,syscfg = <&syscfg_cpu>; + compatible = "st,stih407-irq-syscfg"; + st,syscfg = <&syscfg_cpu>; st,irq-device = , ; st,fiq-device = , diff --git a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml index 2459a55ed540..940b12688167 100644 --- a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml +++ b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml @@ -203,7 +203,7 @@ examples: bus-width = <4>; cap-sd-highspeed; cap-mmc-highspeed; - cd-gpios = <&gpio2 31 0x4>; + cd-gpios = <&gpio2 31 0x4>; st,sig-dir-dat0; st,sig-dir-dat2; st,sig-dir-cmd; diff --git a/Documentation/devicetree/bindings/net/sff,sfp.yaml b/Documentation/devicetree/bindings/net/sff,sfp.yaml index 973e478a399d..bf6cbc7c2ba3 100644 --- a/Documentation/devicetree/bindings/net/sff,sfp.yaml +++ b/Documentation/devicetree/bindings/net/sff,sfp.yaml @@ -120,7 +120,7 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&cps_sfpp0_pins>; tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>; - tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>; }; mdio { diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml index 53da2edd7c9a..120e3bb1e545 100644 --- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml @@ -83,7 +83,7 @@ examples: <0x0 0x28050000 0x0 0x00010000>, <0x0 0x24200000 0x0 0x00002000>, <0x0 0x24162000 0x0 0x00001000>; - reg-names = "dbi", "config", "ulreg", "smu", "mpu"; + reg-names = "dbi", "config", "ulreg", "smu", "mpu"; device_type = "pci"; bus-range = <0x00 0xff>; num-lanes = <2>; diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml index b5ca40d0e251..d476de82e5c3 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml @@ -185,17 +185,17 @@ examples: sd1_mux { pinmux = , /* CD */ ; /* WP */ - power-source = <3300>; + power-source = <3300>; }; sd1_data { pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; - power-source = <3300>; + power-source = <3300>; }; sd1_ctrl { pins = "SD1_CLK", "SD1_CMD"; - power-source = <3300>; + power-source = <3300>; }; }; }; diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml index 07e38be39f1b..89f9603499b4 100644 --- a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml +++ b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml @@ -79,10 +79,10 @@ examples: interrupt-parent = <&gpio1>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - richtek,output-charge-current = <500000>; - richtek,end-of-charge-percentage = <10>; - richtek,battery-regulation-voltage = <4200000>; - richtek,boost-output-voltage = <5050000>; + richtek,output-charge-current = <500000>; + richtek,end-of-charge-percentage = <10>; + richtek,battery-regulation-voltage = <4200000>; + richtek,boost-output-voltage = <5050000>; richtek,min-input-voltage-regulation = <4500000>; richtek,avg-input-current-regulation = <500000>; diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml index 0221397eb51e..f825ee9efd81 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml @@ -62,8 +62,8 @@ examples: regulator-name = "buck1"; regulator-min-microvolt = <600000>; regulator-max-microvolt = <2187500>; - regulator-min-microamp = <3800000>; - regulator-max-microamp = <6800000>; + regulator-min-microamp = <3800000>; + regulator-max-microamp = <6800000>; regulator-boot-on; }; diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml index 6de5b027f990..0d34af98403f 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml @@ -98,8 +98,8 @@ examples: regulator-name = "buck1"; regulator-min-microvolt = <400000>; regulator-max-microvolt = <3587500>; - regulator-min-microamp = <460000>; - regulator-max-microamp = <7600000>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <7600000>; regulator-boot-on; mps,buck-ovp-disable; mps,buck-phase-delay = /bits/ 8 <2>; diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index 30632efdad8b..df36e29d974c 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -113,10 +113,10 @@ examples: }; imx7d-cm4 { - compatible = "fsl,imx7d-cm4"; - memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>; - syscon = <&src>; - clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>; + compatible = "fsl,imx7d-cm4"; + memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>; + syscon = <&src>; + clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>; }; - | From 613ecd6563d2716192e69624105fe1939d104663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 10 Nov 2023 12:23:28 -0500 Subject: [PATCH 1806/7721] drm/amd: Document device reset methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document what each amdgpu driver reset method does. Signed-off-by: André Almeida Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 4d100f8d75bf..ea2656bd714f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -508,6 +508,31 @@ struct amdgpu_allowed_register_entry { bool grbm_indexed; }; +/** + * enum amd_reset_method - Methods for resetting AMD GPU devices + * + * @AMD_RESET_METHOD_NONE: The device will not be reset. + * @AMD_RESET_LEGACY: Method reserved for SI, CIK and VI ASICs. + * @AMD_RESET_MODE0: Reset the entire ASIC. Not currently available for the + * any device. + * @AMD_RESET_MODE1: Resets all IP blocks on the ASIC (SDMA, GFX, VCN, etc.) + * individually. Suitable only for some discrete GPU, not + * available for all ASICs. + * @AMD_RESET_MODE2: Resets a lesser level of IPs compared to MODE1. Which IPs + * are reset depends on the ASIC. Notably doesn't reset IPs + * shared with the CPU on APUs or the memory controllers (so + * VRAM is not lost). Not available on all ASICs. + * @AMD_RESET_BACO: BACO (Bus Alive, Chip Off) method powers off and on the card + * but without powering off the PCI bus. Suitable only for + * discrete GPUs. + * @AMD_RESET_PCI: Does a full bus reset using core Linux subsystem PCI reset + * and does a secondary bus reset or FLR, depending on what the + * underlying hardware supports. + * + * Methods available for AMD GPU driver for resetting the device. Not all + * methods are suitable for every device. User can override the method using + * module parameter `reset_method`. + */ enum amd_reset_method { AMD_RESET_METHOD_NONE = -1, AMD_RESET_METHOD_LEGACY = 0, From 534eee82356c220649dc9c2ea90099f39fb1cb62 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Sun, 12 Nov 2023 09:30:51 +0530 Subject: [PATCH 1807/7721] drm/amd/display: Remove redundant DRM device struct in amdgpu_dm_, mst_types.c Declaration of 'struct drm_device *dev' is redundant, as 'connector->dev' & 'dev_get_drvdata(kdev)' can be directly passed to 'drm_to_adev', without any intermediate DRM device 'dev' variable Cc: Roman Li Cc: Hamza Mahfooz Cc: Harry Wentland Cc: Rodrigo Siqueira Cc: Aurabindo Pillai Cc: Alex Deucher Signed-off-by: Srinivasan Shanmugam Reviewed-by: Roman Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++------ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ee97814ebd99..ba3f7b232a16 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -894,8 +894,7 @@ static int dm_early_init(void *handle); /* Allocate memory for FBC compressed data */ static void amdgpu_dm_fbc_init(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct dm_compressor_info *compressor = &adev->dm.compressor; struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); struct drm_display_mode *mode; @@ -989,8 +988,7 @@ static int amdgpu_dm_audio_component_bind(struct device *kdev, static void amdgpu_dm_audio_component_unbind(struct device *kdev, struct device *hda_kdev, void *data) { - struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev)); struct drm_audio_component *acomp = data; acomp->ops = NULL; @@ -10788,8 +10786,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, struct dm_connector_state *dm_con_state = NULL; struct dc_sink *sink; - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; bool freesync_capable = false; enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 8d7d4024f285..a6995688d7ad 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -424,8 +424,7 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector, { struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, connector); - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc); return &adev->dm.mst_encoders[acrtc->crtc_id].base; From 12c2d3b5f5bc4ecb470a4bc06424914c145e8c03 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 29 Sep 2023 10:51:02 +0530 Subject: [PATCH 1808/7721] drm/amd/pm: Add support to fetch pm metrics sample Add API support to fetch a snapshot of power management metrics from PMFW. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 17 +++++++++++++++++ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 12 ++++++++++++ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 15 +++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 10 ++++++++++ drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 ++- 6 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index f9c438d16c56..6a1d31e8fdd1 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -431,6 +431,7 @@ struct amd_pm_funcs { int (*set_df_cstate)(void *handle, enum pp_df_cstate state); int (*set_xgmi_pstate)(void *handle, uint32_t pstate); ssize_t (*get_gpu_metrics)(void *handle, void **table); + ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size); int (*set_watermarks_for_clock_ranges)(void *handle, struct pp_smu_wm_range_sets *ranges); int (*display_disable_memory_clock_switch)(void *handle, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 1ae3b81548fa..4717884a2bc4 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -1299,6 +1299,23 @@ int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table) return ret; } +ssize_t amdgpu_dpm_get_pm_metrics(struct amdgpu_device *adev, void *pm_metrics, + size_t size) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret = 0; + + if (!pp_funcs->get_pm_metrics) + return -EOPNOTSUPP; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_pm_metrics(adev->powerplay.pp_handle, pm_metrics, + size); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + int amdgpu_dpm_get_fan_control_mode(struct amdgpu_device *adev, uint32_t *fan_mode) { diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index feccd2a7120d..9b3fef5474b1 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -511,6 +511,18 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev, int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev, long *input, uint32_t size); int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table); + +/** + * @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The + * sample is copied to pm_metrics buffer. It's expected to be allocated by the + * caller and size of the allocated buffer is passed. Max size expected for a + * metrics sample is 4096 bytes. + * + * Return: Actual size of the metrics sample + */ +ssize_t amdgpu_dpm_get_pm_metrics(struct amdgpu_device *adev, void *pm_metrics, + size_t size); + int amdgpu_dpm_get_fan_control_mode(struct amdgpu_device *adev, uint32_t *fan_mode); int amdgpu_dpm_set_fan_speed_pwm(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 37c2605f9b35..930e7e3532ad 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -3189,6 +3189,20 @@ static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) return smu->ppt_funcs->get_gpu_metrics(smu, table); } +static ssize_t smu_sys_get_pm_metrics(void *handle, void *pm_metrics, + size_t size) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->ppt_funcs->get_pm_metrics) + return -EOPNOTSUPP; + + return smu->ppt_funcs->get_pm_metrics(smu, pm_metrics, size); +} + static int smu_enable_mgpu_fan_boost(void *handle) { struct smu_context *smu = handle; @@ -3330,6 +3344,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_df_cstate = smu_set_df_cstate, .set_xgmi_pstate = smu_set_xgmi_pstate, .get_gpu_metrics = smu_sys_get_gpu_metrics, + .get_pm_metrics = smu_sys_get_pm_metrics, .set_watermarks_for_clock_ranges = smu_set_watermarks_for_clock_ranges, .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 8def291b18bc..32600ba74bf1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -253,6 +253,7 @@ struct smu_table { uint64_t mc_address; void *cpu_addr; struct amdgpu_bo *bo; + uint32_t version; }; enum smu_perf_level_designation { @@ -1252,6 +1253,15 @@ struct pptable_funcs { */ ssize_t (*get_gpu_metrics)(struct smu_context *smu, void **table); + /** + * @get_pm_metrics: Get one snapshot of power management metrics from + * PMFW. + * + * Return: Size of the metrics sample + */ + ssize_t (*get_pm_metrics)(struct smu_context *smu, void *pm_metrics, + size_t size); + /** * @enable_mgpu_fan_boost: Enable multi-GPU fan boost. */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index 9dd47d91093e..ea8ea99b7436 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -259,7 +259,8 @@ __SMU_DUMMY_MAP(PowerUpUmsch), \ __SMU_DUMMY_MAP(PowerDownUmsch), \ __SMU_DUMMY_MAP(SetSoftMaxVpe), \ - __SMU_DUMMY_MAP(SetSoftMinVpe), + __SMU_DUMMY_MAP(SetSoftMinVpe), \ + __SMU_DUMMY_MAP(GetMetricsVersion), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type From f9a45b76a1883b081fbe15466b11d0264e85d372 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 29 Sep 2023 11:35:19 +0530 Subject: [PATCH 1809/7721] drm/amd/pm: Add pm metrics support to SMU v13.0.6 Add support to fetch PM metrics sample from SMU v13.0.6 Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index f723a4190ee5..8ccb8354bb49 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -120,6 +120,7 @@ struct mca_ras_info { #define P2S_TABLE_ID_A 0x50325341 #define P2S_TABLE_ID_X 0x50325358 +// clang-format off static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -128,6 +129,7 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), MSG_MAP(RequestI2cTransaction, PPSMC_MSG_RequestI2cTransaction, 0), MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1), + MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1), MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1), MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1), MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), @@ -171,6 +173,7 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), }; +// clang-format on static const struct cmn2asic_mapping smu_v13_0_6_clk_map[SMU_CLK_COUNT] = { CLK_MAP(SOCCLK, PPCLK_SOCCLK), CLK_MAP(FCLK, PPCLK_FCLK), @@ -428,6 +431,41 @@ static int smu_v13_0_6_get_metrics_table(struct smu_context *smu, return 0; } +static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu, + void *metrics, size_t max_size) +{ + struct smu_table_context *smu_tbl_ctxt = &smu->smu_table; + uint32_t table_version = smu_tbl_ctxt->tables[SMU_TABLE_SMU_METRICS].version; + uint32_t table_size = smu_tbl_ctxt->tables[SMU_TABLE_SMU_METRICS].size; + struct amdgpu_pm_metrics *pm_metrics = metrics; + uint32_t pmfw_version; + int ret; + + if (!pm_metrics || !max_size) + return -EINVAL; + + if (max_size < (table_size + sizeof(pm_metrics->common_header))) + return -EOVERFLOW; + + /* Don't use cached metrics data */ + ret = smu_v13_0_6_get_metrics_table(smu, pm_metrics->data, true); + if (ret) + return ret; + + smu_cmn_get_smc_version(smu, NULL, &pmfw_version); + + memset(&pm_metrics->common_header, 0, + sizeof(pm_metrics->common_header)); + pm_metrics->common_header.mp1_ip_discovery_version = + IP_VERSION(13, 0, 6); + pm_metrics->common_header.pmfw_version = pmfw_version; + pm_metrics->common_header.pmmetrics_version = table_version; + pm_metrics->common_header.structure_size = + sizeof(pm_metrics->common_header) + table_size; + + return pm_metrics->common_header.structure_size; +} + static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; @@ -435,6 +473,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; int ret, i, retry = 100; + uint32_t table_version; /* Store one-time values in driver PPTable */ if (!pptable->Init) { @@ -453,6 +492,13 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) if (!retry) return -ETIME; + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion, + &table_version); + if (ret) + return ret; + smu_table->tables[SMU_TABLE_SMU_METRICS].version = + table_version; + pptable->MaxSocketPowerLimit = SMUQ10_ROUND(metrics->MaxSocketPowerLimit); pptable->MaxGfxclkFrequency = @@ -2864,6 +2910,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .log_thermal_throttling_event = smu_v13_0_6_log_thermal_throttling_event, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, + .get_pm_metrics = smu_v13_0_6_get_pm_metrics, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, .mode2_reset_is_support = smu_v13_0_6_is_mode2_reset_supported, From 223aad1be34e1169ee7210bce05726cc5ef1fd66 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 29 Sep 2023 11:56:49 +0530 Subject: [PATCH 1810/7721] drm/amd/pm: Add sysfs attribute to get pm metrics Add sysfs attribute to read power management metrics. A snapshot is captured to the buffer when the attribute is read. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index ca2ece24e1e0..e1497296afee 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -1799,6 +1799,44 @@ static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev, return count; } +static int amdgpu_pm_metrics_attr_update(struct amdgpu_device *adev, + struct amdgpu_device_attr *attr, + uint32_t mask, + enum amdgpu_device_attr_states *states) +{ + if (amdgpu_dpm_get_pm_metrics(adev, NULL, 0) == -EOPNOTSUPP) + *states = ATTR_STATE_UNSUPPORTED; + + return 0; +} + +static ssize_t amdgpu_get_pm_metrics(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t size = 0; + int ret; + + if (amdgpu_in_reset(adev)) + return -EPERM; + if (adev->in_suspend && !adev->in_runpm) + return -EPERM; + + ret = pm_runtime_get_sync(ddev->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(ddev->dev); + return ret; + } + + size = amdgpu_dpm_get_pm_metrics(adev, buf, PAGE_SIZE); + + pm_runtime_mark_last_busy(ddev->dev); + pm_runtime_put_autosuspend(ddev->dev); + + return size; +} + /** * DOC: gpu_metrics * @@ -2096,6 +2134,8 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RW(smartshift_bias, ATTR_FLAG_BASIC, .attr_update = ss_bias_attr_update), AMDGPU_DEVICE_ATTR_RW(xgmi_plpd_policy, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RO(pm_metrics, ATTR_FLAG_BASIC, + .attr_update = amdgpu_pm_metrics_attr_update), }; static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, From cee6de122461de699aaa7932b33466c6d259eabb Mon Sep 17 00:00:00 2001 From: Dennis Chan Date: Fri, 27 Oct 2023 11:00:36 +0800 Subject: [PATCH 1811/7721] drm/amd/display: Add new Replay command and Disabled Replay Timing Resync [why] To support dynamic switching for Replay timing sync mechanism. Reviewed-by: ChunTao Tso Acked-by: Hamza Mahfooz Signed-off-by: Dennis Chan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 10 ++++++++ .../gpu/drm/amd/display/dc/dce/dmub_replay.h | 3 +++ drivers/gpu/drm/amd/display/dc/inc/link.h | 3 +++ .../drm/amd/display/dc/link/link_factory.c | 1 + .../link/protocols/link_edp_panel_control.c | 24 +++++++++++++++++++ .../link/protocols/link_edp_panel_control.h | 3 +++ 6 files changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index fcb825e4f1bb..edf60c4f318c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1022,6 +1022,16 @@ enum replay_coasting_vtotal_type { PR_COASTING_TYPE_NUM, }; +/* + * This is general Interface for Replay to + * set an 32 bit variable to dmub + * The Message_type indicates which variable + * passed to DMUB. + */ +enum replay_FW_Message_type { + Replay_Set_Timing_Sync_Supported, +}; + union replay_error_status { struct { unsigned char STATE_TRANSITION_ERROR :1; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index e8385bbf51fc..427bc47a676e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -45,6 +45,9 @@ struct dmub_replay_funcs { struct replay_context *replay_context, uint8_t panel_inst); void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst); + void (*replay_send_cmd)(struct dmub_replay *dmub, + enum replay_FW_Message_type msg, unsigned int panel_inst, + uint32_t cmd_data); void (*replay_set_coasting_vtotal)(struct dmub_replay *dmub, uint16_t coasting_vtotal, uint8_t panel_inst); void (*replay_residency)(struct dmub_replay *dmub, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h index d7685368140a..dd3f53151d8b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -281,6 +281,9 @@ struct link_service { const unsigned int *power_opts); bool (*edp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); + bool (*edp_send_replay_cmd)(struct dc_link *link, + enum replay_FW_Message_type msg, + uint32_t params); bool (*edp_set_coasting_vtotal)( struct dc_link *link, uint16_t coasting_vtotal); bool (*edp_replay_residency)(const struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 7abfc67d10a6..6b306ea58b9b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -213,6 +213,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_get_replay_state = edp_get_replay_state; link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active; link_srv->edp_setup_replay = edp_setup_replay; + link_srv->edp_send_replay_cmd = edp_send_replay_cmd; link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal; link_srv->edp_replay_residency = edp_replay_residency; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index e32a7974a4bc..c52b51b2b4b3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -1007,6 +1007,30 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream return true; } +/* + * This is general Interface for Replay to set an 32 bit variable to dmub + * replay_FW_Message_type: Indicates which instruction or variable pass to DMUB + * cmd_data: Value of the config. + */ +bool edp_send_replay_cmd(struct dc_link *link, + enum replay_FW_Message_type msg, + uint32_t cmd_data) +{ + struct dc *dc = link->ctx->dc; + struct dmub_replay *replay = dc->res_pool->replay; + unsigned int panel_inst; + + if (!replay) + return false; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + replay->funcs->replay_send_cmd(replay, msg, cmd_data, panel_inst); + + return true; +} + bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal) { struct dc *dc = link->ctx->dc; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index ebf7deb63d13..6b223580ac8a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -57,6 +57,9 @@ bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream); +bool edp_send_replay_cmd(struct dc_link *link, + enum replay_FW_Message_type msg, + uint32_t params); bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal); bool edp_replay_residency(const struct dc_link *link, unsigned int *residency, const bool is_start, const bool is_alpm); From 1c22d6ce53280763bcb4cb24d4f71111fff4a526 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Mon, 6 Nov 2023 11:20:15 -0500 Subject: [PATCH 1812/7721] drm/amd/display: Include udelay when waiting for INBOX0 ACK When waiting for the ACK for INBOX0 message, we have to ensure to include the udelay for proper wait time Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Samson Tam Acked-by: Hamza Mahfooz Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 22fc4ba96def..38360adc53d9 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -1077,6 +1077,7 @@ enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t ti ack = dmub->hw_funcs.read_inbox0_ack_register(dmub); if (ack) return DMUB_STATUS_OK; + udelay(1); } return DMUB_STATUS_TIMEOUT; } From 3f3b08be58834339b00f28d19c20d684cdec704f Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 3 Nov 2023 10:01:01 -0400 Subject: [PATCH 1813/7721] drm/amd/display: Add z-state support policy for dcn35 [Why] DML2 means that the dcn3x policy for calculating z-state support no longer runs from validate_bandwidth. This means we are unconditionally allowing Z8, the hardware default. [How] Port the policy over to DCN35, but with a few modifications: - Don't use min_dst_y_next_start as a check for Z8/Z10 allow - Add support for overriding the Z10 stutter period per ASIC - Cleanup the code to make the policy assignment more clear Reviewed-by: Charlene Liu Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 34 +++++++++++++++++++ .../drm/amd/display/dc/dml/dcn35/dcn35_fpu.h | 2 ++ .../dc/resource/dcn35/dcn35_resource.c | 7 ++++ 4 files changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 541e781267b9..349629858205 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -874,6 +874,7 @@ struct dc_debug_options { unsigned int seamless_boot_odm_combine; unsigned int force_odm_combine_4to1; //bit vector based on otg inst int minimum_z8_residency_time; + int minimum_z10_residency_time; bool disable_z9_mpc; unsigned int force_fclk_khz; bool enable_tri_buf; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index a5fe523668e9..dee80429fc4c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -507,3 +507,37 @@ int dcn35_populate_dml_pipes_from_context_fpu(struct dc *dc, return pipe_cnt; } + +void dcn35_decide_zstate_support(struct dc *dc, struct dc_state *context) +{ + enum dcn_zstate_support_state support = DCN_ZSTATE_SUPPORT_DISALLOW; + unsigned int i, plane_count = 0; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].plane_state) + plane_count++; + } + + if (plane_count == 0) { + support = DCN_ZSTATE_SUPPORT_ALLOW; + } else if (plane_count == 1 && context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { + struct dc_link *link = context->streams[0]->sink->link; + bool is_pwrseq0 = link && link->link_index == 0; + bool is_psr1 = link && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr; + int minmum_z8_residency = + dc->debug.minimum_z8_residency_time > 0 ? dc->debug.minimum_z8_residency_time : 1000; + bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z8_residency; + int minmum_z10_residency = + dc->debug.minimum_z10_residency_time > 0 ? dc->debug.minimum_z10_residency_time : 5000; + bool allow_z10 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z10_residency; + + if (is_pwrseq0 && allow_z10) + support = DCN_ZSTATE_SUPPORT_ALLOW; + else if (is_pwrseq0 && is_psr1) + support = allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY; + else if (allow_z8) + support = DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY; + } + + context->bw_ctx.bw.dcn.clk.zstate_support = support; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.h index e8d5a170893e..067480fc3691 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.h @@ -39,4 +39,6 @@ int dcn35_populate_dml_pipes_from_context_fpu(struct dc *dc, display_e2e_pipe_params_st *pipes, bool fast_validate); +void dcn35_decide_zstate_support(struct dc *dc, struct dc_state *context); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 5c935d94a95c..0d5a03c6d812 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -1724,6 +1724,13 @@ static bool dcn35_validate_bandwidth(struct dc *dc, out = dml2_validate(dc, context, fast_validate); + if (fast_validate) + return out; + + DC_FP_START(); + dcn35_decide_zstate_support(dc, context); + DC_FP_END(); + return out; } From a2d3c69261178df7d4c1350d5ef67375d399acd3 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 17 Nov 2023 05:16:59 +0000 Subject: [PATCH 1814/7721] drm/amdkfd: Copy HW exception data to user event Fixes issue where user events of type KFD_EVENT_TYPE_HW_EXCEPTION do not have valid data Signed-off-by: David Yat Sin Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 0f58be65132f..739721254a5d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -880,6 +880,10 @@ static int copy_signaled_event_data(uint32_t num_events, dst = &data[i].memory_exception_data; src = &event->memory_exception_data; size = sizeof(struct kfd_hsa_memory_exception_data); + } else if (event->type == KFD_EVENT_TYPE_HW_EXCEPTION) { + dst = &data[i].memory_exception_data; + src = &event->hw_exception_data; + size = sizeof(struct kfd_hsa_hw_exception_data); } else if (event->type == KFD_EVENT_TYPE_SIGNAL && waiter->event_age_enabled) { dst = &data[i].signal_event_data.last_event_age; From 35c425f5cc251417ad681475dc9901ab6d3244ea Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 16 Nov 2023 13:57:07 -0500 Subject: [PATCH 1815/7721] drm/amdgpu: update xgmi num links info post gc9.4.2 GC IP 9.4.2 and up support TA reporting of the number of xGMI links between peers. Tested-by: Vignesh Chander Signed-off-by: Jonathan Kim Reviewed-by: Mukul Joshi Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 6ab17330a6ed..2d22f7d45512 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -547,7 +547,7 @@ int amdgpu_amdkfd_get_xgmi_bandwidth_mbytes(struct amdgpu_device *dst, struct amdgpu_device *adev = dst, *peer_adev; int num_links; - if (adev->asic_type != CHIP_ALDEBARAN) + if (amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(9, 4, 2)) return 0; if (src) From 76c5d6900908439386b0045a6130150150079300 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Mon, 6 Nov 2023 17:29:33 -0500 Subject: [PATCH 1816/7721] drm/amd/display: Update DCN35 watermarks [Why & How] Update to the new values per HW team request. Affects both stutter and z8. Reviewed-by: Charlene Liu Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 32 +++++++++---------- .../drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 8 ++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 507a7cf56711..3469f692d6ea 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -443,32 +443,32 @@ static struct wm_table ddr5_wm_table = { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 9, - .sr_enter_plus_exit_time_us = 11, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 9, - .sr_enter_plus_exit_time_us = 11, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 9, - .sr_enter_plus_exit_time_us = 11, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 9, - .sr_enter_plus_exit_time_us = 11, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, } @@ -480,32 +480,32 @@ static struct wm_table lpddr5_wm_table = { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 11.5, - .sr_enter_plus_exit_time_us = 14.5, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 11.5, - .sr_enter_plus_exit_time_us = 14.5, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 11.5, - .sr_enter_plus_exit_time_us = 14.5, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 11.5, - .sr_enter_plus_exit_time_us = 14.5, + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, .valid = true, }, } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index dee80429fc4c..30d78ad91b9c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -164,10 +164,10 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = { }, }, .num_states = 5, - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .sr_exit_z8_time_us = 50.0, /*changed from 442.0*/ - .sr_enter_plus_exit_z8_time_us = 50.0,/*changed from 560.0*/ + .sr_exit_time_us = 14.0, + .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_z8_time_us = 525.0, + .sr_enter_plus_exit_z8_time_us = 715.0, .fclk_change_latency_us = 20.0, .usr_retraining_latency_us = 2, .writeback_latency_us = 12.0, From c4290449f8fbecc55013c6125b50908b5359a8fd Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Mon, 6 Nov 2023 15:46:19 +0800 Subject: [PATCH 1817/7721] drm/amd/display: add skip_implict_edp_power_control flag for dce110 If the link requests to skip implicit eDP power control, we should honor that request. Reviewed-by: Robin Chen Acked-by: Hamza Mahfooz Signed-off-by: Ian Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 960a55e06375..0a331d17ee92 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -3115,7 +3115,8 @@ void dce110_disable_link_output(struct dc_link *link, struct dmcu *dmcu = dc->res_pool->dmcu; if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) link->dc->hwss.edp_backlight_control(link, false); else if (dmcu != NULL && dmcu->funcs->lock_phy) dmcu->funcs->lock_phy(dmcu); From 613a81995575889753ca44d70d33e84a1d21bae5 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Mon, 6 Nov 2023 16:47:19 -0500 Subject: [PATCH 1818/7721] drm/amd/display: fix a pipe mapping error in dcn32_fpu [why] In dcn32 DML pipes are ordered the same as dc pipes but only for used pipes. For example, if dc pipe 1 and 2 are used, their dml pipe indices would be 0 and 1 respectively. However update_pipe_slice_table_with_split_flags doesn't skip indices for free pipes. This causes us to not reference correct dml pipe output when building pipe topology. [how] Use two variables to iterate dc and dml pipes respectively and only increment dml pipe index when current dc pipe is not free. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Chaitanya Dhere Acked-by: Hamza Mahfooz Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 9ec4172d1c2d..44b0666e53b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1192,13 +1192,16 @@ static bool update_pipe_slice_table_with_split_flags( */ struct pipe_ctx *pipe; bool odm; - int i; + int dc_pipe_idx, dml_pipe_idx = 0; bool updated = false; - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &context->res_ctx.pipe_ctx[i]; + for (dc_pipe_idx = 0; + dc_pipe_idx < dc->res_pool->pipe_count; dc_pipe_idx++) { + pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx]; + if (resource_is_pipe_type(pipe, FREE_PIPE)) + continue; - if (merge[i]) { + if (merge[dc_pipe_idx]) { if (resource_is_pipe_type(pipe, OPP_HEAD)) /* merging OPP head means reducing ODM slice * count by 1 @@ -1213,17 +1216,18 @@ static bool update_pipe_slice_table_with_split_flags( updated = true; } - if (split[i]) { - odm = vba->ODMCombineEnabled[vba->pipe_plane[i]] != + if (split[dc_pipe_idx]) { + odm = vba->ODMCombineEnabled[vba->pipe_plane[dml_pipe_idx]] != dm_odm_combine_mode_disabled; if (odm && resource_is_pipe_type(pipe, OPP_HEAD)) update_slice_table_for_stream( - table, pipe->stream, split[i] - 1); + table, pipe->stream, split[dc_pipe_idx] - 1); else if (!odm && resource_is_pipe_type(pipe, DPP_PIPE)) update_slice_table_for_plane(table, pipe, - pipe->plane_state, split[i] - 1); + pipe->plane_state, split[dc_pipe_idx] - 1); updated = true; } + dml_pipe_idx++; } return updated; } From 702e2fb579e000382c219c58dacef4f733511a36 Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Mon, 20 Nov 2023 11:04:45 +0800 Subject: [PATCH 1819/7721] drm/amdgpu: Retire query/reset_ras_err_status from gfx_v9_4_3 Not needed anymore. Signed-off-by: Hawking Zhang Reviewed-by: Stanley Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 156 ------------------------ 1 file changed, 156 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 40d06d32bb74..21865668b787 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -3882,150 +3882,6 @@ static void gfx_v9_4_3_inst_reset_ras_err_count(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } -static void gfx_v9_4_3_inst_query_utc_err_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t data; - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX UTCL2 Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS, 0x3); - } - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX VML2 Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS, 0x3); - } - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), - regVML2_WALKER_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX VML2 Walker Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_WALKER_MEM_ECC_STATUS, - 0x3); - } -} - -static void gfx_v9_4_3_log_cu_timeout_status(struct amdgpu_device *adev, - uint32_t status, int xcc_id) -{ - struct amdgpu_cu_info *cu_info = &adev->gfx.cu_info; - uint32_t i, simd, wave; - uint32_t wave_status; - uint32_t wave_pc_lo, wave_pc_hi; - uint32_t wave_exec_lo, wave_exec_hi; - uint32_t wave_inst_dw0, wave_inst_dw1; - uint32_t wave_ib_sts; - - for (i = 0; i < 32; i++) { - if (!((i << 1) & status)) - continue; - - simd = i / cu_info->max_waves_per_simd; - wave = i % cu_info->max_waves_per_simd; - - wave_status = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_STATUS); - wave_pc_lo = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_PC_LO); - wave_pc_hi = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_PC_HI); - wave_exec_lo = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_EXEC_LO); - wave_exec_hi = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_EXEC_HI); - wave_inst_dw0 = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_INST_DW0); - wave_inst_dw1 = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_INST_DW1); - wave_ib_sts = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_IB_STS); - - dev_info( - adev->dev, - "\t SIMD %d, Wave %d: status 0x%x, pc 0x%llx, exec 0x%llx, inst 0x%llx, ib_sts 0x%x\n", - simd, wave, wave_status, - ((uint64_t)wave_pc_hi << 32 | wave_pc_lo), - ((uint64_t)wave_exec_hi << 32 | wave_exec_lo), - ((uint64_t)wave_inst_dw1 << 32 | wave_inst_dw0), - wave_ib_sts); - } -} - -static void gfx_v9_4_3_inst_query_sq_timeout_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t se_idx, sh_idx, cu_idx; - uint32_t status; - - mutex_lock(&adev->grbm_idx_mutex); - for (se_idx = 0; se_idx < adev->gfx.config.max_shader_engines; se_idx++) { - for (sh_idx = 0; sh_idx < adev->gfx.config.max_sh_per_se; sh_idx++) { - for (cu_idx = 0; cu_idx < adev->gfx.config.max_cu_per_sh; cu_idx++) { - gfx_v9_4_3_xcc_select_se_sh(adev, se_idx, sh_idx, - cu_idx, xcc_id); - status = RREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS); - if (status != 0) { - dev_info( - adev->dev, - "GFX Watchdog Timeout: SE %d, SH %d, CU %d\n", - se_idx, sh_idx, cu_idx); - gfx_v9_4_3_log_cu_timeout_status( - adev, status, xcc_id); - } - /* clear old status */ - WREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS, 0); - } - } - } - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); -} - -static void gfx_v9_4_3_inst_query_ras_err_status(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - gfx_v9_4_3_inst_query_utc_err_status(adev, xcc_id); - gfx_v9_4_3_inst_query_sq_timeout_status(adev, xcc_id); -} - -static void gfx_v9_4_3_inst_reset_utc_err_status(struct amdgpu_device *adev, - int xcc_id) -{ - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS, 0x3); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS, 0x3); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_WALKER_MEM_ECC_STATUS, 0x3); -} - -static void gfx_v9_4_3_inst_reset_sq_timeout_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t se_idx, sh_idx, cu_idx; - - mutex_lock(&adev->grbm_idx_mutex); - for (se_idx = 0; se_idx < adev->gfx.config.max_shader_engines; se_idx++) { - for (sh_idx = 0; sh_idx < adev->gfx.config.max_sh_per_se; sh_idx++) { - for (cu_idx = 0; cu_idx < adev->gfx.config.max_cu_per_sh; cu_idx++) { - gfx_v9_4_3_xcc_select_se_sh(adev, se_idx, sh_idx, - cu_idx, xcc_id); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS, 0); - } - } - } - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); -} - -static void gfx_v9_4_3_inst_reset_ras_err_status(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - gfx_v9_4_3_inst_reset_utc_err_status(adev, xcc_id); - gfx_v9_4_3_inst_reset_sq_timeout_status(adev, xcc_id); -} - static void gfx_v9_4_3_inst_enable_watchdog_timer(struct amdgpu_device *adev, void *ras_error_status, int xcc_id) { @@ -4067,16 +3923,6 @@ static void gfx_v9_4_3_reset_ras_error_count(struct amdgpu_device *adev) amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_reset_ras_err_count); } -static void gfx_v9_4_3_query_ras_error_status(struct amdgpu_device *adev) -{ - amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_query_ras_err_status); -} - -static void gfx_v9_4_3_reset_ras_error_status(struct amdgpu_device *adev) -{ - amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_reset_ras_err_status); -} - static void gfx_v9_4_3_enable_watchdog_timer(struct amdgpu_device *adev) { amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_enable_watchdog_timer); @@ -4394,8 +4240,6 @@ struct amdgpu_xcp_ip_funcs gfx_v9_4_3_xcp_funcs = { struct amdgpu_ras_block_hw_ops gfx_v9_4_3_ras_ops = { .query_ras_error_count = &gfx_v9_4_3_query_ras_error_count, .reset_ras_error_count = &gfx_v9_4_3_reset_ras_error_count, - .query_ras_error_status = &gfx_v9_4_3_query_ras_error_status, - .reset_ras_error_status = &gfx_v9_4_3_reset_ras_error_status, }; struct amdgpu_gfx_ras gfx_v9_4_3_ras = { From 2e9b152325f649923b9324fa8ea5f1a5289145bb Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 1 Aug 2023 10:37:41 -0400 Subject: [PATCH 1820/7721] drm/amdgpu: optimize RLC powerdown notification on Vangogh The smu needs to get the rlc power down message to sync the rlc state with smu, the rlc state updating message need to be sent at while smu begin suspend sequence , otherwise SMU will crash while RLC state is not notified by driver, and rlc state probally changed after that notification, so it needs to notify rlc state to smu at the end of the suspend sequence in amdgpu_device_suspend() that can make sure the rlc state is correctly set to SMU. [ 101.000590] amdgpu 0000:03:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001E SMN_C2PMSG_82:0x00000000 [ 101.000598] amdgpu 0000:03:00.0: amdgpu: Failed to disable gfxoff! [ 110.838026] amdgpu 0000:03:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001E SMN_C2PMSG_82:0x00000000 [ 110.838035] amdgpu 0000:03:00.0: amdgpu: Failed to disable smu features. [ 110.838039] amdgpu 0000:03:00.0: amdgpu: Fail to disable dpm features! [ 110.838040] [drm:amdgpu_device_ip_suspend_phase2 [amdgpu]] *ERROR* suspend of IP block failed -62 [ 110.884394] PM: suspend of devices aborted after 21213.620 msecs [ 110.884402] PM: start suspend of devices aborted after 21213.882 msecs [ 110.884405] PM: Some devices failed to suspend, or early wake event detected Reviewed-by: Yifan Zhang Signed-off-by: Perry Yuan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++++ drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 18 ++++++++++++++++++ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 2 ++ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 10 ++++++++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 5 +++++ .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 5 ++--- drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 1 + 8 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index b5edf40b5d03..5d3a83193115 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4549,6 +4549,10 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) if (amdgpu_sriov_vf(adev)) amdgpu_virt_release_full_gpu(adev, false); + r = amdgpu_dpm_notify_rlc_state(adev, false); + if (r) + return r; + return 0; } diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 6a1d31e8fdd1..8ebba87f4289 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -445,6 +445,7 @@ struct amd_pm_funcs { struct dpm_clocks *clock_table); int (*get_smu_prv_buf_details)(void *handle, void **addr, size_t *size); void (*pm_compute_clocks)(void *handle); + int (*notify_rlc_state)(void *handle, bool en); }; struct metrics_table_header { diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 4717884a2bc4..97b40c5fa1ff 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -181,6 +181,24 @@ int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, return ret; } +int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en) +{ + int ret = 0; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (pp_funcs && pp_funcs->notify_rlc_state) { + mutex_lock(&adev->pm.mutex); + + ret = pp_funcs->notify_rlc_state( + adev->powerplay.pp_handle, + en); + + mutex_unlock(&adev->pm.mutex); + } + + return ret; +} + bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 9b3fef5474b1..d76b0a60db44 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -415,6 +415,8 @@ int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev); int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, enum pp_mp1_state mp1_state); +int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en); + int amdgpu_dpm_set_gfx_power_up_by_imu(struct amdgpu_device *adev); int amdgpu_dpm_baco_exit(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 930e7e3532ad..f464610a959f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1710,6 +1710,16 @@ static int smu_disable_dpms(struct smu_context *smu) } } + /* Notify SMU RLC is going to be off, stop RLC and SMU interaction. + * otherwise SMU will hang while interacting with RLC if RLC is halted + * this is a WA for Vangogh asic which fix the SMU hang issue. + */ + ret = smu_notify_rlc_state(smu, false); + if (ret) { + dev_err(adev->dev, "Fail to notify rlc status!\n"); + return ret; + } + if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(9, 4, 2) && !((adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs) && !amdgpu_sriov_vf(adev) && adev->gfx.rlc.funcs->stop) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 32600ba74bf1..c125253df20b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1370,6 +1370,11 @@ struct pptable_funcs { * management. */ int (*dpm_set_umsch_mm_enable)(struct smu_context *smu, bool enable); + + /** + * @notify_rlc_state: Notify RLC power state to SMU. + */ + int (*notify_rlc_state)(struct smu_context *smu, bool en); }; typedef enum { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 762b31455a0b..2ff6deedef95 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2193,8 +2193,7 @@ static int vangogh_get_dpm_clock_table(struct smu_context *smu, struct dpm_clock return 0; } - -static int vangogh_system_features_control(struct smu_context *smu, bool en) +static int vangogh_notify_rlc_state(struct smu_context *smu, bool en) { struct amdgpu_device *adev = smu->adev; int ret = 0; @@ -2523,7 +2522,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .print_clk_levels = vangogh_common_print_clk_levels, .set_default_dpm_table = vangogh_set_default_dpm_tables, .set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters, - .system_features_control = vangogh_system_features_control, + .notify_rlc_state = vangogh_notify_rlc_state, .feature_is_enabled = smu_cmn_feature_is_enabled, .set_power_profile_mode = vangogh_set_power_profile_mode, .get_power_profile_mode = vangogh_get_power_profile_mode, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 80b3c3efc006..64766ac69c53 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -97,6 +97,7 @@ #define smu_get_default_config_table_settings(smu, config_table) smu_ppt_funcs(get_default_config_table_settings, -EOPNOTSUPP, smu, config_table) #define smu_set_config_table(smu, config_table) smu_ppt_funcs(set_config_table, -EOPNOTSUPP, smu, config_table) #define smu_init_pptable_microcode(smu) smu_ppt_funcs(init_pptable_microcode, 0, smu) +#define smu_notify_rlc_state(smu, en) smu_ppt_funcs(notify_rlc_state, 0, smu, en) #endif #endif From cfab803884f426b36b58dbe1f86f99742767c208 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 2 Nov 2023 14:59:13 -0400 Subject: [PATCH 1821/7721] drm/amd/display: update pixel clock params after stream slice count change in context [why] When ODM slice count is changed, otg master pipe's pixel clock params is no longer valid as the value is dependent on ODM slice count. Reviewed-by: Chaitanya Dhere Acked-by: Hamza Mahfooz Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 9 ++++++--- .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 6 +----- drivers/gpu/drm/amd/display/dc/inc/core_types.h | 1 + .../display/dc/resource/dcn20/dcn20_resource.c | 16 ++++++++++------ .../display/dc/resource/dcn20/dcn20_resource.h | 1 + .../display/dc/resource/dcn32/dcn32_resource.c | 1 + .../display/dc/resource/dcn321/dcn321_resource.c | 1 + 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 42a927710743..84d632700949 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2256,7 +2256,7 @@ static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine( } static bool update_pipe_params_after_odm_slice_count_change( - const struct dc_stream_state *stream, + struct pipe_ctx *otg_master, struct dc_state *context, const struct resource_pool *pool) { @@ -2266,9 +2266,12 @@ static bool update_pipe_params_after_odm_slice_count_change( for (i = 0; i < pool->pipe_count && result; i++) { pipe = &context->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && pipe->plane_state) + if (pipe->stream == otg_master->stream && pipe->plane_state) result = resource_build_scaling_params(pipe); } + + if (pool->funcs->build_pipe_pix_clk_params) + pool->funcs->build_pipe_pix_clk_params(otg_master); return result; } @@ -2951,7 +2954,7 @@ bool resource_update_pipes_for_stream_with_slice_count( otg_master, new_ctx, pool); if (result) result = update_pipe_params_after_odm_slice_count_change( - otg_master->stream, new_ctx, pool); + otg_master, new_ctx, pool); return result; } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 44b0666e53b0..e7f13e28caa3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1237,15 +1237,11 @@ static void update_pipes_with_slice_table(struct dc *dc, struct dc_state *contex { int i; - for (i = 0; i < table->odm_combine_count; i++) { + for (i = 0; i < table->odm_combine_count; i++) resource_update_pipes_for_stream_with_slice_count(context, dc->current_state, dc->res_pool, table->odm_combines[i].stream, table->odm_combines[i].slice_count); - /* TODO: move this into the function above */ - dcn20_build_mapped_resource(dc, context, - table->odm_combines[i].stream); - } for (i = 0; i < table->mpc_combine_count; i++) resource_update_pipes_for_plane_with_slice_count(context, diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index bac1420b1de8..10397d4dfb07 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -205,6 +205,7 @@ struct resource_funcs { void (*get_panel_config_defaults)(struct dc_panel_config *panel_config); void (*save_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); void (*restore_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); + void (*build_pipe_pix_clk_params)(struct pipe_ctx *pipe_ctx); }; struct audio_support{ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index f04bb5b1471d..f9c5bc624be3 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -1273,15 +1273,19 @@ static void build_clamping_params(struct dc_stream_state *stream) stream->clamping.pixel_encoding = stream->timing.pixel_encoding; } +void dcn20_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx) +{ + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); +} + static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) { - get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); - - pipe_ctx->clock_source->funcs->get_pix_clk_dividers( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - &pipe_ctx->pll_settings); + dcn20_build_pipe_pix_clk_params(pipe_ctx); pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h index 37ecaccc5d12..4cee3fa11a7f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h @@ -165,6 +165,7 @@ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream); enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state); +void dcn20_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx); #endif /* __DC_RESOURCE_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index 36e4c7bef403..f6cbcc9b4006 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -2041,6 +2041,7 @@ static struct resource_funcs dcn32_res_pool_funcs = { .retain_phantom_pipes = dcn32_retain_phantom_pipes, .save_mall_state = dcn32_save_mall_state, .restore_mall_state = dcn32_restore_mall_state, + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, }; static uint32_t read_pipe_fuses(struct dc_context *ctx) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index bedb70b98162..12986fe0b289 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -1609,6 +1609,7 @@ static struct resource_funcs dcn321_res_pool_funcs = { .retain_phantom_pipes = dcn32_retain_phantom_pipes, .save_mall_state = dcn32_save_mall_state, .restore_mall_state = dcn32_restore_mall_state, + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, }; static uint32_t read_pipe_fuses(struct dc_context *ctx) From 1290183db494641772c18d063c34e9c8f720c61c Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 2 Nov 2023 15:02:42 -0400 Subject: [PATCH 1822/7721] drm/amd/display: always use mpc factor of 2 for stereo timings [why] In the new pipe resource management logic, the special handling for stereo timings is missing. This commit implements the same stereo timings handling as old pipe resource management code. Reviewed-by: Chaitanya Dhere Acked-by: Hamza Mahfooz Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../display/dc/dml2/dml2_dc_resource_mgmt.c | 26 +++++++++++++------ .../gpu/drm/amd/display/dc/dml2/dml2_utils.c | 2 +- .../gpu/drm/amd/display/dc/dml2/dml2_utils.h | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c index 1a2b24cc6b61..0baf39d64a2d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c @@ -772,18 +772,29 @@ static unsigned int get_mpc_factor(struct dml2_context *ctx, const struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, struct dml2_dml_to_dc_pipe_mapping *mapping, - const struct dc_stream_status *status, unsigned int stream_id, + const struct dc_stream_status *status, + const struct dc_stream_state *stream, int plane_idx) { unsigned int plane_id; unsigned int cfg_idx; + unsigned int mpc_factor; - get_plane_id(ctx, state, status->plane_states[plane_idx], stream_id, plane_idx, &plane_id); + get_plane_id(ctx, state, status->plane_states[plane_idx], + stream->stream_id, plane_idx, &plane_id); cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id); - if (ctx->architecture == dml2_architecture_20) - return (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx]; - ASSERT(false); - return 1; + if (ctx->architecture == dml2_architecture_20) { + mpc_factor = (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx]; + } else { + mpc_factor = 1; + ASSERT(false); + } + + /* For stereo timings, we need to pipe split */ + if (dml2_is_stereo_timing(stream)) + mpc_factor = 2; + + return mpc_factor; } static unsigned int get_odm_factor( @@ -820,14 +831,13 @@ static void populate_mpc_factors_for_stream( unsigned int mpc_factors[MAX_PIPES]) { const struct dc_stream_status *status = &state->stream_status[stream_idx]; - unsigned int stream_id = state->streams[stream_idx]->stream_id; int i; for (i = 0; i < status->plane_count; i++) if (odm_factor == 1) mpc_factors[i] = get_mpc_factor( ctx, state, disp_cfg, mapping, status, - stream_id, i); + state->streams[stream_idx], i); else mpc_factors[i] = 1; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c index 2498b8341199..33eab80e89a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c @@ -468,7 +468,7 @@ bool dml2_verify_det_buffer_configuration(struct dml2_context *in_ctx, struct dc return need_recalculation; } -bool dml2_is_stereo_timing(struct dc_stream_state *stream) +bool dml2_is_stereo_timing(const struct dc_stream_state *stream) { bool is_stereo = false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h index 23b9028337d4..5842d6d3c4b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h @@ -42,7 +42,7 @@ void dml2_copy_clocks_to_dc_state(struct dml2_dcn_clocks *out_clks, struct dc_st void dml2_extract_watermark_set(struct dcn_watermarks *watermark, struct display_mode_lib_st *dml_core_ctx); int dml2_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context *ctx, unsigned int stream_id); bool is_dtbclk_required(const struct dc *dc, struct dc_state *context); -bool dml2_is_stereo_timing(struct dc_stream_state *stream); +bool dml2_is_stereo_timing(const struct dc_stream_state *stream); /* * dml2_dc_construct_pipes - This function will determine if we need additional pipes based From 80061d6b58a99f1fffb97a7f3592234a5fe0a3fe Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 7 Nov 2023 11:12:45 -0500 Subject: [PATCH 1823/7721] drm/amd/display: Add Z8 watermarks for DML2 bbox overrides [Why] We can override SR watermarks but not Z8 ones. [How] Add new parameters for Z8 matching the SR ones and feed them into the states. These also weren't being applied to every state, so make sure that we loop over and update all SOC states if given an override. Reviewed-by: Jun Lei Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../display/dc/dml2/dml2_translation_helper.c | 47 +++++++++++++------ .../drm/amd/display/dc/dml2/dml2_wrapper.h | 2 + 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index 75171bee6f71..2b9638c6d9b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -341,25 +341,42 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, break; } - /* Override from passed values, mainly for debugging purposes, if available */ - if (dml2->config.bbox_overrides.sr_exit_latency_us) { - p->in_states->state_array[0].sr_exit_time_us = dml2->config.bbox_overrides.sr_exit_latency_us; - } + /* Override from passed values, if available */ + for (i = 0; i < p->in_states->num_states; i++) { + if (dml2->config.bbox_overrides.sr_exit_latency_us) { + p->in_states->state_array[i].sr_exit_time_us = + dml2->config.bbox_overrides.sr_exit_latency_us; + } - if (dml2->config.bbox_overrides.sr_enter_plus_exit_latency_us) { - p->in_states->state_array[0].sr_enter_plus_exit_time_us = dml2->config.bbox_overrides.sr_enter_plus_exit_latency_us; - } + if (dml2->config.bbox_overrides.sr_enter_plus_exit_latency_us) { + p->in_states->state_array[i].sr_enter_plus_exit_time_us = + dml2->config.bbox_overrides.sr_enter_plus_exit_latency_us; + } - if (dml2->config.bbox_overrides.urgent_latency_us) { - p->in_states->state_array[0].urgent_latency_pixel_data_only_us = dml2->config.bbox_overrides.urgent_latency_us; - } + if (dml2->config.bbox_overrides.sr_exit_z8_time_us) { + p->in_states->state_array[i].sr_exit_z8_time_us = + dml2->config.bbox_overrides.sr_exit_z8_time_us; + } - if (dml2->config.bbox_overrides.dram_clock_change_latency_us) { - p->in_states->state_array[0].dram_clock_change_latency_us = dml2->config.bbox_overrides.dram_clock_change_latency_us; - } + if (dml2->config.bbox_overrides.sr_enter_plus_exit_z8_time_us) { + p->in_states->state_array[i].sr_enter_plus_exit_z8_time_us = + dml2->config.bbox_overrides.sr_enter_plus_exit_z8_time_us; + } - if (dml2->config.bbox_overrides.fclk_change_latency_us) { - p->in_states->state_array[0].fclk_change_latency_us = dml2->config.bbox_overrides.fclk_change_latency_us; + if (dml2->config.bbox_overrides.urgent_latency_us) { + p->in_states->state_array[i].urgent_latency_pixel_data_only_us = + dml2->config.bbox_overrides.urgent_latency_us; + } + + if (dml2->config.bbox_overrides.dram_clock_change_latency_us) { + p->in_states->state_array[i].dram_clock_change_latency_us = + dml2->config.bbox_overrides.dram_clock_change_latency_us; + } + + if (dml2->config.bbox_overrides.fclk_change_latency_us) { + p->in_states->state_array[i].fclk_change_latency_us = + dml2->config.bbox_overrides.fclk_change_latency_us; + } } /* DCFCLK stas values are project specific */ diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h index 317f90776d97..fe15baa4bf09 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h @@ -139,6 +139,8 @@ struct dml2_soc_bbox_overrides { double urgent_latency_us; double sr_exit_latency_us; double sr_enter_plus_exit_latency_us; + double sr_exit_z8_time_us; + double sr_enter_plus_exit_z8_time_us; double dram_clock_change_latency_us; double fclk_change_latency_us; unsigned int dram_num_chan; From 4b8251e019ea17037667e6d61aa5e66d5b4f51d2 Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Mon, 20 Nov 2023 10:14:21 +0800 Subject: [PATCH 1824/7721] drm/amdgpu: Do not issue gpu reset from nbio v7_9 bif interrupt In nbio v7_9, host driver should not issu gpu reset Signed-off-by: Hawking Zhang Reviewed-by: Stanley Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index 23f26f8caad4..25a3da83e0fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -611,11 +611,6 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device dev_info(adev->dev, "RAS controller interrupt triggered " "by NBIF error\n"); - - /* ras_controller_int is dedicated for nbif ras error, - * not the global interrupt for sync flood - */ - amdgpu_ras_reset_gpu(adev); } amdgpu_ras_error_data_fini(&err_data); From 20b07b0cb3a0a2fb3a6daf00f645925be77ec80c Mon Sep 17 00:00:00 2001 From: Alex Sierra Date: Mon, 20 Nov 2023 11:31:32 -0600 Subject: [PATCH 1825/7721] drm/amdgpu: Force order between a read and write to the same address Setting register to force ordering to prevent read/write or write/read hazards for un-cached modes. Signed-off-by: Alex Sierra Acked-by: Alex Deucher Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 8 ++++++++ .../gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 0c6133cc5e57..40ce12323164 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -89,6 +89,10 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_0_me.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_0_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_0_rlc.bin"); +static const struct soc15_reg_golden golden_settings_gc_11_0[] = { + SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL, 0x20000000, 0x20000000) +}; + static const struct soc15_reg_golden golden_settings_gc_11_0_1[] = { SOC15_REG_GOLDEN_VALUE(GC, 0, regCGTT_GS_NGG_CLK_CTRL, 0x9fff8fff, 0x00000010), @@ -304,6 +308,10 @@ static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev) default: break; } + soc15_program_register_sequence(adev, + golden_settings_gc_11_0, + (const u32)ARRAY_SIZE(golden_settings_gc_11_0)); + } static void gfx_v11_0_write_data_to_reg(struct amdgpu_ring *ring, int eng_sel, diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h index c92c4b83253f..4bff1ef8a9a6 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h @@ -6369,6 +6369,8 @@ #define regTCP_INVALIDATE_BASE_IDX 1 #define regTCP_STATUS 0x19a1 #define regTCP_STATUS_BASE_IDX 1 +#define regTCP_CNTL 0x19a2 +#define regTCP_CNTL_BASE_IDX 1 #define regTCP_CNTL2 0x19a3 #define regTCP_CNTL2_BASE_IDX 1 #define regTCP_DEBUG_INDEX 0x19a5 From 251027968a7230f18c353e25634cc7e25d9ab953 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 7 Nov 2023 11:15:16 -0500 Subject: [PATCH 1826/7721] drm/amd/display: Feed SR and Z8 watermarks into DML2 for DCN35 [Why] We've updated the table but the values aren't being reflected in DML2 calculation. [How] Pass them into the bbox overrides. Reviewed-by: Jun Lei Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index 30d78ad91b9c..21c17d3296a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -329,6 +329,15 @@ void dcn35_update_bw_bounding_box_fpu(struct dc *dc, /*temp till dml2 fully work without dml1*/ dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); + + /* Update latency values */ + dc->dml2_options.bbox_overrides.dram_clock_change_latency_us = dcn3_5_soc.dram_clock_change_latency_us; + + dc->dml2_options.bbox_overrides.sr_exit_latency_us = dcn3_5_soc.sr_exit_time_us; + dc->dml2_options.bbox_overrides.sr_enter_plus_exit_latency_us = dcn3_5_soc.sr_enter_plus_exit_time_us; + + dc->dml2_options.bbox_overrides.sr_exit_z8_time_us = dcn3_5_soc.sr_exit_z8_time_us; + dc->dml2_options.bbox_overrides.sr_enter_plus_exit_z8_time_us = dcn3_5_soc.sr_enter_plus_exit_z8_time_us; } static bool is_dual_plane(enum surface_pixel_format format) From a953cd8cac6be69fba0b66e6fb46d1324d797af4 Mon Sep 17 00:00:00 2001 From: Ilya Bakoulin Date: Tue, 7 Nov 2023 15:07:56 -0500 Subject: [PATCH 1827/7721] drm/amd/display: Fix MPCC 1DLUT programming [Why] Wrong function is used to translate LUT values to HW format, leading to visible artifacting in some cases. [How] Use the correct cm3_helper function. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Krunoslav Kovac Acked-by: Hamza Mahfooz Signed-off-by: Ilya Bakoulin Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 6a65af8c36b9..5f7f474ef51c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -487,8 +487,7 @@ bool dcn32_set_mcm_luts( if (plane_state->blend_tf->type == TF_TYPE_HWPWL) lut_params = &plane_state->blend_tf->pwl; else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->blend_tf, + cm3_helper_translate_curve_to_hw_format(plane_state->blend_tf, &dpp_base->regamma_params, false); lut_params = &dpp_base->regamma_params; } @@ -503,8 +502,7 @@ bool dcn32_set_mcm_luts( else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace ASSERT(false); - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->in_shaper_func, + cm3_helper_translate_curve_to_hw_format(plane_state->in_shaper_func, &dpp_base->shaper_params, true); lut_params = &dpp_base->shaper_params; } From 40436ce7ccfec5c616e2e48d0ec2c905637c7397 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Tue, 7 Nov 2023 17:01:49 -0500 Subject: [PATCH 1828/7721] drm/amd/display: Use DRAM speed from validation for dummy p-state [Description] When choosing which dummy p-state latency to use, we need to use the DRAM speed from validation. The DRAMSpeed DML variable can change because we use different input params to DML when populating watermarks set B. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Samson Tam Acked-by: Hamza Mahfooz Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index e7f13e28caa3..92e2ddc9ab7e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -2231,6 +2231,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, int i, pipe_idx, vlevel_temp = 0; double dcfclk = dcn3_2_soc.clock_limits[0].dcfclk_mhz; double dcfclk_from_validation = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; + double dram_speed_from_validation = context->bw_ctx.dml.vba.DRAMSpeed; double dcfclk_from_fw_based_mclk_switching = dcfclk_from_validation; bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != dm_dram_clock_change_unsupported; @@ -2418,7 +2419,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, } if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) { - min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed; + min_dram_speed_mts = dram_speed_from_validation; min_dram_speed_mts_margin = 160; context->bw_ctx.dml.soc.dram_clock_change_latency_us = From 6c22fb07e0c2935d97a86509f16f755ab895f2c8 Mon Sep 17 00:00:00 2001 From: Bhuvana Chandra Pinninti Date: Wed, 18 Oct 2023 19:16:17 +0530 Subject: [PATCH 1829/7721] drm/amd/display: Refactor DSC into component folder [why] To refactor DSC and make DSC files unit testable. [how] moved the dcnxx_dsc.c and .h files into corresponding dcn folders inside the dsc and cleared the linkage errors. Reviewed-by: Wenjing Liu Acked-by: Hamza Mahfooz Signed-off-by: Bhuvana Chandra Pinninti Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Makefile | 1 + drivers/gpu/drm/amd/display/dc/dcn20/Makefile | 2 -- drivers/gpu/drm/amd/display/dc/dcn35/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dsc/Makefile | 26 +++++++++++++++++++ .../display/dc/{ => dsc}/dcn20/dcn20_dsc.c | 0 .../display/dc/{ => dsc}/dcn20/dcn20_dsc.h | 0 .../display/dc/{ => dsc}/dcn35/dcn35_dsc.c | 0 .../display/dc/{ => dsc}/dcn35/dcn35_dsc.h | 0 .../drm/amd/display/dc/{inc/hw => dsc}/dsc.h | 0 9 files changed, 28 insertions(+), 3 deletions(-) rename drivers/gpu/drm/amd/display/dc/{ => dsc}/dcn20/dcn20_dsc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => dsc}/dcn20/dcn20_dsc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => dsc}/dcn35/dcn35_dsc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => dsc}/dcn35/dcn35_dsc.h (100%) rename drivers/gpu/drm/amd/display/dc/{inc/hw => dsc}/dsc.h (100%) diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 71192fc81a20..7b0959da2cac 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -31,6 +31,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/clk_mgr subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hwss subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/resource +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dsc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index 1cac1eca8111..93ac45802e44 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -7,8 +7,6 @@ DCN20 = dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o -DCN20 += dcn20_dsc.o - AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20)) AMD_DISPLAY_FILES += $(AMD_DAL_DCN20) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile index 719afb5a3b12..85a307babab9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile @@ -12,7 +12,7 @@ DCN35 = dcn35_init.o dcn35_dio_stream_encoder.o \ dcn35_dio_link_encoder.o dcn35_dccg.o dcn35_optc.o \ - dcn35_dsc.o dcn35_hubp.o dcn35_hubbub.o \ + dcn35_hubp.o dcn35_hubbub.o \ dcn35_mmhubbub.o dcn35_opp.o dcn35_dpp.o dcn35_pg_cntl.o dcn35_dwb.o AMD_DAL_DCN35 = $(addprefix $(AMDDALPATH)/dc/dcn35/,$(DCN35)) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index a2537229ee88..b183ba5a692e 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -1,8 +1,34 @@ # SPDX-License-Identifier: MIT # # Makefile for the 'dsc' sub-component of DAL. + +ifdef CONFIG_DRM_AMD_DC_FP + +############################################################################### +# DCN20 +############################################################################### +DSC_DCN20 = dcn20_dsc.o + +AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/dsc/dcn20/,$(DSC_DCN20)) + + + + +############################################################################### +# DCN35 +############################################################################### + +DSC_DCN35 = dcn35_dsc.o + +AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/dsc/dcn35/,$(DSC_DCN35)) + + + +endif + DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC)) AMD_DISPLAY_FILES += $(AMD_DAL_DSC) + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c rename to drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h rename to drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.c rename to drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.h rename to drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.h diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h rename to drivers/gpu/drm/amd/display/dc/dsc/dsc.h From c77b0008591094d454c1f340d1e82b5ebe2d918d Mon Sep 17 00:00:00 2001 From: Max Tseng Date: Tue, 7 Nov 2023 15:00:03 +0800 Subject: [PATCH 1830/7721] drm/amd/display: replay: generalize the send command function usage Augment the function to allow send different format data in different use case. Reviewed-by: Dennis Chan Acked-by: Hamza Mahfooz Signed-off-by: Max Tseng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h | 3 +-- drivers/gpu/drm/amd/display/dc/inc/link.h | 2 +- .../display/dc/link/protocols/link_edp_panel_control.c | 4 ++-- .../display/dc/link/protocols/link_edp_panel_control.h | 2 +- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 10 ++++++++++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index edf60c4f318c..6f5da510e8de 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1029,6 +1029,7 @@ enum replay_coasting_vtotal_type { * passed to DMUB. */ enum replay_FW_Message_type { + Replay_Msg_Not_Support = -1, Replay_Set_Timing_Sync_Supported, }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index 427bc47a676e..368711f76335 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -46,8 +46,7 @@ struct dmub_replay_funcs { void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst); void (*replay_send_cmd)(struct dmub_replay *dmub, - enum replay_FW_Message_type msg, unsigned int panel_inst, - uint32_t cmd_data); + enum replay_FW_Message_type msg, unsigned int panel_inst, union dmub_replay_cmd_set *cmd_element); void (*replay_set_coasting_vtotal)(struct dmub_replay *dmub, uint16_t coasting_vtotal, uint8_t panel_inst); void (*replay_residency)(struct dmub_replay *dmub, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h index dd3f53151d8b..7439865d1b50 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -283,7 +283,7 @@ struct link_service { const struct dc_stream_state *stream); bool (*edp_send_replay_cmd)(struct dc_link *link, enum replay_FW_Message_type msg, - uint32_t params); + union dmub_replay_cmd_set *cmd_data); bool (*edp_set_coasting_vtotal)( struct dc_link *link, uint16_t coasting_vtotal); bool (*edp_replay_residency)(const struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index c52b51b2b4b3..6bc8ec47e267 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -1014,7 +1014,7 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream */ bool edp_send_replay_cmd(struct dc_link *link, enum replay_FW_Message_type msg, - uint32_t cmd_data) + union dmub_replay_cmd_set *cmd_data) { struct dc *dc = link->ctx->dc; struct dmub_replay *replay = dc->res_pool->replay; @@ -1026,7 +1026,7 @@ bool edp_send_replay_cmd(struct dc_link *link, if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) return false; - replay->funcs->replay_send_cmd(replay, msg, cmd_data, panel_inst); + replay->funcs->replay_send_cmd(replay, msg, panel_inst, cmd_data); return true; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index 6b223580ac8a..39526bd40178 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -59,7 +59,7 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream); bool edp_send_replay_cmd(struct dc_link *link, enum replay_FW_Message_type msg, - uint32_t params); + union dmub_replay_cmd_set *cmd_data); bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal); bool edp_replay_residency(const struct dc_link *link, unsigned int *residency, const bool is_start, const bool is_alpm); diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 55573083bc31..5f06cf4c663f 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -3143,6 +3143,16 @@ struct dmub_rb_cmd_replay_set_timing_sync { struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; }; +/** + * Definition union of replay command set + */ +union dmub_replay_cmd_set { + /** + * Definition of DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command data. + */ + struct dmub_cmd_replay_set_timing_sync_data sync_data; +}; + /** * Set of HW components that can be locked. * From 220db802cb505e6ec3b3e0018ac0233205632a72 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Fri, 27 Oct 2023 14:12:51 -0400 Subject: [PATCH 1831/7721] drm/amd/display: Do not read DPREFCLK spread info from LUT on DCN35 [WHY] Currently DCN35 does not spread DPREFCLK [HOW] Remove hardcoded table with nonzero caps Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Michael Strauss Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 3469f692d6ea..0f3f6a9d5144 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -515,11 +515,6 @@ static DpmClocks_t_dcn35 dummy_clocks; static struct dcn35_watermarks dummy_wms = { 0 }; -static struct dcn35_ss_info_table ss_info_table = { - .ss_divider = 1000, - .ss_percentage = {0, 0, 375, 375, 375} -}; - static void dcn35_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn35_watermarks *table) { int i, num_valid_sets; @@ -965,21 +960,6 @@ struct clk_mgr_funcs dcn35_fpga_funcs = { .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, }; -static void dcn35_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr) -{ - uint32_t clock_source; - struct dc_context *ctx = clk_mgr->base.ctx; - - REG_GET(CLK1_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL, &clock_source); - - clk_mgr->dprefclk_ss_percentage = ss_info_table.ss_percentage[clock_source]; - - if (clk_mgr->dprefclk_ss_percentage != 0) { - clk_mgr->ss_on_dprefclk = true; - clk_mgr->dprefclk_ss_divider = ss_info_table.ss_divider; - } -} - void dcn35_clk_mgr_construct( struct dc_context *ctx, struct clk_mgr_dcn35 *clk_mgr, @@ -1052,8 +1032,6 @@ void dcn35_clk_mgr_construct( dce_clock_read_ss_info(&clk_mgr->base); /*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/ - dcn35_read_ss_info_from_lut(&clk_mgr->base); - clk_mgr->base.base.bw_params = &dcn35_bw_params; if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { From 75a3371e8ffdab2e504f4326daab60f8fb15fdf1 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Wed, 8 Nov 2023 17:16:28 -0500 Subject: [PATCH 1832/7721] drm/amd/display: Increase num voltage states to 40 [Description] If during driver init stage there are greater than 20 intermediary voltage states while constructing the SOC BB we could hit issues because we will index outside of the clock_limits array and start overwriting data. Increase the total number of states to 40 to avoid this issue. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Samson Tam Acked-by: Hamza Mahfooz Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dc_features.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h index 2cbdd75429ff..6e669a2c5b2d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h @@ -36,7 +36,7 @@ * Define the maximum amount of states supported by the ASIC. Every ASIC has a * specific number of states; this macro defines the maximum number of states. */ -#define DC__VOLTAGE_STATES 20 +#define DC__VOLTAGE_STATES 40 #define DC__NUM_DPP__4 1 #define DC__NUM_DPP__0_PRESENT 1 #define DC__NUM_DPP__1_PRESENT 1 From 37f4382b64a2b01109a0ed5c05f58d3f86385e10 Mon Sep 17 00:00:00 2001 From: Max Tseng Date: Wed, 8 Nov 2023 11:31:50 +0800 Subject: [PATCH 1833/7721] drm/amd/display: replay: Augment Frameupdate Command [Why] Sending certain Frameupdate number for Replay Power Evaluation Reviewed-by: Dennis Chan Acked-by: Hamza Mahfooz Signed-off-by: Max Tseng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + .../gpu/drm/amd/display/dc/dce/dmub_replay.h | 2 +- .../link/protocols/link_edp_panel_control.c | 12 +++-- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 51 +++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 6f5da510e8de..4a60d2c47686 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1031,6 +1031,7 @@ enum replay_coasting_vtotal_type { enum replay_FW_Message_type { Replay_Msg_Not_Support = -1, Replay_Set_Timing_Sync_Supported, + Replay_Set_Residency_Frameupdate_Timer, }; union replay_error_status { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index 368711f76335..b3ee90a0b8b3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -46,7 +46,7 @@ struct dmub_replay_funcs { void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst); void (*replay_send_cmd)(struct dmub_replay *dmub, - enum replay_FW_Message_type msg, unsigned int panel_inst, union dmub_replay_cmd_set *cmd_element); + enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element); void (*replay_set_coasting_vtotal)(struct dmub_replay *dmub, uint16_t coasting_vtotal, uint8_t panel_inst); void (*replay_residency)(struct dmub_replay *dmub, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index 6bc8ec47e267..fdeb8dff5485 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -1023,10 +1023,16 @@ bool edp_send_replay_cmd(struct dc_link *link, if (!replay) return false; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; + DC_LOGGER_INIT(link->ctx->logger); - replay->funcs->replay_send_cmd(replay, msg, panel_inst, cmd_data); + if (dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + cmd_data->panel_inst = panel_inst; + else { + DC_LOG_DC("%s(): get edp panel inst fail ", __func__); + return false; + } + + replay->funcs->replay_send_cmd(replay, msg, cmd_data); return true; } diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 5f06cf4c663f..d1becbb5aa29 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -2880,6 +2880,10 @@ enum dmub_cmd_replay_type { * Set disabled iiming sync. */ DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED = 5, + /** + * Set Residency Frameupdate Timer. + */ + DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6, }; /** @@ -3143,14 +3147,57 @@ struct dmub_rb_cmd_replay_set_timing_sync { struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; }; +/** + * Data passed from driver to FW in DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. + */ +struct dmub_cmd_replay_frameupdate_timer_data { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Replay Frameupdate Timer Enable or not + */ + uint8_t enable; + /** + * REPLAY force reflash frame update number + */ + uint16_t frameupdate_count; +}; +/** + * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER + */ +struct dmub_rb_cmd_replay_set_frameupdate_timer { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. + */ + struct dmub_cmd_replay_frameupdate_timer_data data; +}; + /** * Definition union of replay command set */ union dmub_replay_cmd_set { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; /** * Definition of DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command data. */ struct dmub_cmd_replay_set_timing_sync_data sync_data; + /** + * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data. + */ + struct dmub_cmd_replay_frameupdate_timer_data timer_data; }; /** @@ -4288,6 +4335,10 @@ union dmub_rb_cmd { struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal replay_set_power_opt_and_coasting_vtotal; struct dmub_rb_cmd_replay_set_timing_sync replay_set_timing_sync; + /** + * Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. + */ + struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer; }; /** From 43b8ac4b34ec239bccf4a692c1227ef51a95a4d2 Mon Sep 17 00:00:00 2001 From: Camille Cho Date: Fri, 3 Nov 2023 12:08:42 +0800 Subject: [PATCH 1834/7721] drm/amd/display: Simplify brightness initialization [Why] Remove the brightness cache in DC. It uses a single value to represent the brightness for both SDR and HDR mode. This leads to flash in HDR on/off. It also unconditionally programs brightness as in HDR mode. This may introduce garbage on SDR mode in miniLED panel. [How] Simplify the initialization flow by removing the DC cache and taking what panel has as default. Expand the mechanism for PWM to DPCD Aux to restore cached brightness value generally. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Krunoslav Kovac Acked-by: Hamza Mahfooz Signed-off-by: Camille Cho Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 - drivers/gpu/drm/amd/display/dc/dc_types.h | 4 ---- .../gpu/drm/amd/display/dc/link/link_detection.c | 2 +- drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 3 +-- .../dc/link/protocols/link_edp_panel_control.c | 16 +++------------- .../dc/link/protocols/link_edp_panel_control.h | 1 - 6 files changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 349629858205..18b8d7f3f738 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1610,7 +1610,6 @@ struct dc_link { enum edp_revision edp_revision; union dpcd_sink_ext_caps dpcd_sink_ext_caps; - struct backlight_settings backlight_settings; struct psr_settings psr_settings; struct replay_settings replay_settings; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 4a60d2c47686..a2f6c994a2a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -991,10 +991,6 @@ struct link_mst_stream_allocation_table { struct link_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM]; }; -struct backlight_settings { - uint32_t backlight_millinits; -}; - /* PSR feature flags */ struct psr_settings { bool psr_feature_enabled; // PSR is supported by sink diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f2fe523f914f..24153b0df503 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -879,7 +879,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, (link->dpcd_sink_ext_caps.bits.oled == 1)) { dpcd_set_source_specific_data(link); msleep(post_oui_delay); - set_cached_brightness_aux(link); + set_default_brightness_aux(link); } return true; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 34a4a8c0e18c..f8e01ca09d96 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -2142,8 +2142,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (link->dpcd_sink_ext_caps.bits.oled == 1 || link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 || link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) { - set_cached_brightness_aux(link); - + set_default_brightness_aux(link); if (link->dpcd_sink_ext_caps.bits.oled == 1) msleep(bl_oled_enable_delay); edp_backlight_enable_aux(link, true); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index fdeb8dff5485..ac0fa88b52a0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -170,7 +170,6 @@ bool edp_set_backlight_level_nits(struct dc_link *link, *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits; *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms; - link->backlight_settings.backlight_millinits = backlight_millinits; if (!link->dpcd_caps.panel_luminance_control) { if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, @@ -288,9 +287,9 @@ bool set_default_brightness_aux(struct dc_link *link) if (link && link->dpcd_sink_ext_caps.bits.oled == 1) { if (!read_default_bl_aux(link, &default_backlight)) default_backlight = 150000; - // if < 1 nits or > 5000, it might be wrong readback - if (default_backlight < 1000 || default_backlight > 5000000) - default_backlight = 150000; // + // if > 5000, it might be wrong readback + if (default_backlight > 5000000) + default_backlight = 150000; return edp_set_backlight_level_nits(link, true, default_backlight, 0); @@ -298,15 +297,6 @@ bool set_default_brightness_aux(struct dc_link *link) return false; } -bool set_cached_brightness_aux(struct dc_link *link) -{ - if (link->backlight_settings.backlight_millinits) - return edp_set_backlight_level_nits(link, true, - link->backlight_settings.backlight_millinits, 0); - else - return set_default_brightness_aux(link); - return false; -} bool edp_is_ilr_optimization_enabled(struct dc_link *link) { if (link->dpcd_caps.edp_supported_link_rates_count == 0 || !link->panel_config.ilr.optimize_edp_link_rate) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index 39526bd40178..b7493ff4fcee 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -30,7 +30,6 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); bool set_default_brightness_aux(struct dc_link *link); -bool set_cached_brightness_aux(struct dc_link *link); void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); int edp_get_backlight_level(const struct dc_link *link); bool edp_get_backlight_level_nits(struct dc_link *link, From 83a79dd6f4fb54c8cfe3ecbd378817047687a9b2 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Mon, 7 Aug 2023 15:34:39 +0800 Subject: [PATCH 1835/7721] drm/amd/display: adjust flow for deallocation mst payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why] MST relevant variables are maintained at drm side. As the result, we still have to call drm_dp_remove_payload_part2() to update the relevant values regardless the link is under mst mode or not. We used to have a workaround patch to tackle this: commit 3d8fcc6740c9 ("drm/amd/display: Extract temp drm mst deallocation wa into its own function") Now it's time to remove the workaround and adjust the flow. [How] During deallocate_mst_payload(), source actually doesn't send out ALLOCATE_PAYLOAD at the end as like the flow in allocate_mst_payload(). Call function dm_helpers_dp_mst_send_payload_allocation() at the end of deallocate_mst_payload() is a bit confusing. Separate dm_helpers_dp_mst_send_payload_allocation() into 2 functions. Have a new function dm_helpers_dp_mst_update_mst_mgr_for_deallocation() to replace dm_helpers_dp_mst_send_payload_allocation() for payload deallocation. Cc: Ville Syrjälä Reviewed-by: Wenjing Liu Acked-by: Hamza Mahfooz Signed-off-by: Wayne Lin Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 53 +++++---- drivers/gpu/drm/amd/display/dc/dc.h | 1 - drivers/gpu/drm/amd/display/dc/dm_helpers.h | 12 +- .../gpu/drm/amd/display/dc/link/link_dpms.c | 105 ++---------------- 5 files changed, 50 insertions(+), 138 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ba3f7b232a16..2be64c593c87 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1715,23 +1715,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) /* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */ adev->dm.dc->debug.ignore_cable_id = true; - /* TODO: There is a new drm mst change where the freedom of - * vc_next_start_slot update is revoked/moved into drm, instead of in - * driver. This forces us to make sure to get vc_next_start_slot updated - * in drm function each time without considering if mst_state is active - * or not. Otherwise, next time hotplug will give wrong start_slot - * number. We are implementing a temporary solution to even notify drm - * mst deallocation when link is no longer of MST type when uncommitting - * the stream so we will have more time to work on a proper solution. - * Ideally when dm_helpers_dp_mst_stop_top_mgr message is triggered, we - * should notify drm to do a complete "reset" of its states and stop - * calling further drm mst functions when link is no longer of an MST - * type. This could happen when we unplug an MST hubs/displays. When - * uncommit stream comes later after unplug, we should just reset - * hardware states only. - */ - adev->dm.dc->debug.temp_mst_deallocation_sequence = true; - if (adev->dm.dc->caps.dp_hdmi21_pcon_support) DRM_INFO("DP-HDMI FRL PCON supported\n"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index c7a29bb737e2..e44ba5c1c48e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -333,15 +333,14 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger( return ACT_SUCCESS; } -bool dm_helpers_dp_mst_send_payload_allocation( +void dm_helpers_dp_mst_send_payload_allocation( struct dc_context *ctx, - const struct dc_stream_state *stream, - bool enable) + const struct dc_stream_state *stream) { struct amdgpu_dm_connector *aconnector; struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_mgr *mst_mgr; - struct drm_dp_mst_atomic_payload *new_payload, old_payload; + struct drm_dp_mst_atomic_payload *new_payload; enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD; enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD; int ret = 0; @@ -349,25 +348,13 @@ bool dm_helpers_dp_mst_send_payload_allocation( aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; if (!aconnector || !aconnector->mst_root) - return false; + return; mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); - if (!enable) { - set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; - clr_flag = MST_ALLOCATE_NEW_PAYLOAD; - } - - if (enable) { - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); - } else { - dm_helpers_construct_old_payload(mst_mgr, mst_state, - new_payload, &old_payload); - drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); - } + ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); if (ret) { amdgpu_dm_set_mst_status(&aconnector->mst_status, @@ -378,10 +365,36 @@ bool dm_helpers_dp_mst_send_payload_allocation( amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); } - - return true; } +void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + struct dc_context *ctx, + const struct dc_stream_state *stream) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_atomic_payload *new_payload, old_payload; + enum mst_progress_status set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; + enum mst_progress_status clr_flag = MST_ALLOCATE_NEW_PAYLOAD; + + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + + if (!aconnector || !aconnector->mst_root) + return; + + mst_mgr = &aconnector->mst_root->mst_mgr; + mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); + new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); + dm_helpers_construct_old_payload(mst_mgr, mst_state, + new_payload, &old_payload); + + drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); + + amdgpu_dm_set_mst_status(&aconnector->mst_status, set_flag, true); + amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); + } + void dm_dtn_log_begin(struct dc_context *ctx, struct dc_log_buffer_ctx *log_ctx) { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 18b8d7f3f738..85771ef98cd7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -956,7 +956,6 @@ struct dc_debug_options { unsigned int min_prefetch_in_strobe_ns; bool disable_unbounded_requesting; bool dig_fifo_off_in_blank; - bool temp_mst_deallocation_sequence; bool override_dispclk_programming; bool otg_crc_db; bool disallow_dispclk_dppclk_ds; diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 7ce9a5b6c33b..6d7a15dcf8a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -103,10 +103,16 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger( /* * Sends ALLOCATE_PAYLOAD message. */ -bool dm_helpers_dp_mst_send_payload_allocation( +void dm_helpers_dp_mst_send_payload_allocation( struct dc_context *ctx, - const struct dc_stream_state *stream, - bool enable); + const struct dc_stream_state *stream); + +/* + * Update mst manager relevant variables + */ +void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + struct dc_context *ctx, + const struct dc_stream_state *stream); bool dm_helpers_dp_mst_start_top_mgr( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index f8e01ca09d96..aa0a086aa7fc 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -1247,86 +1247,6 @@ static void remove_stream_from_alloc_table( } } -static enum dc_status deallocate_mst_payload_with_temp_drm_wa( - struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dc_dp_mst_stream_allocation_table proposed_table = {0}; - struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0); - int i; - bool mst_mode = (link->type == dc_connection_mst_branch); - /* adjust for drm changes*/ - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - const struct dc_link_settings empty_link_settings = {0}; - DC_LOGGER_INIT(link->ctx->logger); - - if (link_hwss->ext.set_throttled_vcp_size) - link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp); - if (link_hwss->ext.set_hblank_min_symbol_width) - link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx, - &empty_link_settings, - avg_time_slots_per_mtp); - - if (dm_helpers_dp_mst_write_payload_allocation_table( - stream->ctx, - stream, - &proposed_table, - false)) - update_mst_stream_alloc_table( - link, - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.hpo_dp_stream_enc, - &proposed_table); - else - DC_LOG_WARNING("Failed to update" - "MST allocation table for" - "pipe idx:%d\n", - pipe_ctx->pipe_idx); - - DC_LOG_MST("%s" - "stream_count: %d: ", - __func__, - link->mst_stream_alloc_table.stream_count); - - for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - DC_LOG_MST("stream_enc[%d]: %p " - "stream[%d].hpo_dp_stream_enc: %p " - "stream[%d].vcp_id: %d " - "stream[%d].slot_count: %d\n", - i, - (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc, - i, - (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc, - i, - link->mst_stream_alloc_table.stream_allocations[i].vcp_id, - i, - link->mst_stream_alloc_table.stream_allocations[i].slot_count); - } - - if (link_hwss->ext.update_stream_allocation_table == NULL || - link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { - DC_LOG_DEBUG("Unknown encoding format\n"); - return DC_ERROR_UNEXPECTED; - } - - link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res, - &link->mst_stream_alloc_table); - - if (mst_mode) { - dm_helpers_dp_mst_poll_for_allocation_change_trigger( - stream->ctx, - stream); - } - - dm_helpers_dp_mst_send_payload_allocation( - stream->ctx, - stream, - false); - - return DC_OK; -} - static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; @@ -1339,9 +1259,6 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) const struct dc_link_settings empty_link_settings = {0}; DC_LOGGER_INIT(link->ctx->logger); - if (link->dc->debug.temp_mst_deallocation_sequence) - return deallocate_mst_payload_with_temp_drm_wa(pipe_ctx); - /* deallocate_mst_payload is called before disable link. When mode or * disable/enable monitor, new stream is created which is not in link * stream[] yet. For this, payload is not allocated yet, so de-alloc @@ -1414,16 +1331,14 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res, &link->mst_stream_alloc_table); - if (mst_mode) { + if (mst_mode) dm_helpers_dp_mst_poll_for_allocation_change_trigger( stream->ctx, stream); - dm_helpers_dp_mst_send_payload_allocation( - stream->ctx, - stream, - false); - } + dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + stream->ctx, + stream); return DC_OK; } @@ -1504,12 +1419,10 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) stream->ctx, stream); - if (ret != ACT_LINK_LOST) { + if (ret != ACT_LINK_LOST) dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); - } + stream); /* slot X.Y for only current stream */ pbn_per_slot = get_pbn_per_slot(stream); @@ -1769,8 +1682,7 @@ enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); + stream); /* notify immediate branch device table update */ if (dm_helpers_dp_mst_write_payload_allocation_table( @@ -1899,8 +1811,7 @@ enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_ /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); + stream); } /* increase throttled vcp size */ From 5f2a404cbccec0c8d6635f0997cea2ac226d25d4 Mon Sep 17 00:00:00 2001 From: Dennis Chan Date: Tue, 31 Oct 2023 10:09:02 +0800 Subject: [PATCH 1836/7721] drm/amd/display: Disable Timing sync check in Full-Screen Video Case [why] If Panel max link off frame count is low, it will cause low residency for Replay, then Disabled timing sync check in Full screen Video Case. Reviewed-by: Robin Chen Acked-by: Hamza Mahfooz Signed-off-by: Dennis Chan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 62 ++++++++++++++----- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 11 ++-- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index a2f6c994a2a9..7313cfe69498 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1018,6 +1018,12 @@ enum replay_coasting_vtotal_type { PR_COASTING_TYPE_NUM, }; +enum replay_link_off_frame_count_level { + PR_LINK_OFF_FRAME_COUNT_FAIL = 0x0, + PR_LINK_OFF_FRAME_COUNT_GOOD = 0x2, + PR_LINK_OFF_FRAME_COUNT_BEST = 0x6, +}; + /* * This is general Interface for Replay to * set an 32 bit variable to dmub @@ -1041,26 +1047,48 @@ union replay_error_status { }; struct replay_config { - bool replay_supported; // Replay feature is supported - unsigned int replay_power_opt_supported; // Power opt flags that are supported - bool replay_smu_opt_supported; // SMU optimization is supported - unsigned int replay_enable_option; // Replay enablement option - uint32_t debug_flags; // Replay debug flags - bool replay_timing_sync_supported; // Replay desync is supported - bool force_disable_desync_error_check; // Replay desync is supported - bool received_desync_error_hpd; //Replay Received Desync Error HPD. - union replay_error_status replay_error_status; // Replay error status + /* Replay feature is supported */ + bool replay_supported; + /* Power opt flags that are supported */ + unsigned int replay_power_opt_supported; + /* SMU optimization is supported */ + bool replay_smu_opt_supported; + /* Replay enablement option */ + unsigned int replay_enable_option; + /* Replay debug flags */ + uint32_t debug_flags; + /* Replay sync is supported */ + bool replay_timing_sync_supported; + /* Replay Disable desync error check. */ + bool force_disable_desync_error_check; + /* Replay Received Desync Error HPD. */ + bool received_desync_error_hpd; + /* Replay feature is supported long vblank */ + bool replay_support_fast_resync_in_ultra_sleep_mode; + /* Replay error status */ + union replay_error_status replay_error_status; }; -/* Replay feature flags */ +/* Replay feature flags*/ struct replay_settings { - struct replay_config config; // Replay configuration - bool replay_feature_enabled; // Replay feature is ready for activating - bool replay_allow_active; // Replay is currently active - unsigned int replay_power_opt_active; // Power opt flags that are activated currently - bool replay_smu_opt_enable; // SMU optimization is enabled - uint16_t coasting_vtotal; // Current Coasting vtotal - uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; // Coasting vtotal table + /* Replay configuration */ + struct replay_config config; + /* Replay feature is ready for activating */ + bool replay_feature_enabled; + /* Replay is currently active */ + bool replay_allow_active; + /* Replay is currently active */ + bool replay_allow_long_vblank; + /* Power opt flags that are activated currently */ + unsigned int replay_power_opt_active; + /* SMU optimization is enabled */ + bool replay_smu_opt_enable; + /* Current Coasting vtotal */ + uint16_t coasting_vtotal; + /* Coasting vtotal table */ + uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; + /* Maximum link off frame count */ + enum replay_link_off_frame_count_level link_off_frame_count_level; }; /* To split out "global" and "per-panel" config settings. diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index d1becbb5aa29..a08073fc92ae 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -3056,15 +3056,14 @@ struct dmub_cmd_replay_set_timing_sync_data { * Currently the support is only for 0 or 1 */ uint8_t panel_inst; - - /** - * Explicit padding to 4 byte boundary. - */ - uint8_t pad[3]; /** * REPLAY set_timing_sync */ - bool timing_sync_supported; + uint8_t timing_sync_supported; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; }; /** From 8f3656ce65d6d550247a85fdb5c54a5b65cc2252 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 9 Nov 2023 10:50:30 -0500 Subject: [PATCH 1837/7721] drm/amd/display: Enable SubVP on 1080p60 displays [Description] - Previously SubVP would never be selected on 1080p60 displays because it has too much vactive margin. However, implement a change to allow it like how 1440p60 is allowed. - Add a new struct such that we have a list of allowed modes for enabling subvp with vactive margin (currently 1080p60 and 1440p60) - Also ensure to block drr + vblank cases to prevent unexpected enablement of new display configs - Update SW cursor fallback for these new potential cases as well Reviewed-by: Samson Tam Acked-by: Hamza Mahfooz Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- .../display/dc/dcn32/dcn32_resource_helpers.c | 32 ++++++++++++++- .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 41 +++++++++++-------- .../dc/resource/dcn32/dcn32_resource.h | 10 +++++ 4 files changed, 65 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 84d632700949..f3a9fdd2340d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -5316,7 +5316,7 @@ bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_st if (dc->current_state->stream_count == 1 && stream->timing.v_addressable >= 2880 && ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120) return true; - else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 2160 && + else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 1080 && ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120) return true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index ef0a2b01734d..389ac7ae1154 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -665,6 +665,30 @@ bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int widt return is_native_scaling; } +/** + * disallow_subvp_in_active_plus_blank() - Function to determine disallowed subvp + drr/vblank configs + * + * @pipe: subvp pipe to be used for the subvp + drr/vblank config + * + * Since subvp is being enabled on more configs (such as 1080p60), we want + * to explicitly block any configs that we don't want to enable. We do not + * want to enable any 1080p60 (SubVP) + drr / vblank configs since these + * are already convered by FPO. + * + * Return: True if disallowed, false otherwise + */ +static bool disallow_subvp_in_active_plus_blank(struct pipe_ctx *pipe) +{ + bool disallow = false; + + if (resource_is_pipe_type(pipe, OPP_HEAD) && + resource_is_pipe_type(pipe, DPP_PIPE)) { + if (pipe->stream->timing.v_addressable == 1080 && pipe->stream->timing.h_addressable == 1920) + disallow = true; + } + return disallow; +} + /** * dcn32_subvp_drr_admissable() - Determine if SubVP + DRR config is admissible * @@ -688,6 +712,7 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) bool drr_pipe_found = false; bool drr_psr_capable = false; uint64_t refresh_rate = 0; + bool subvp_disallow = false; for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -697,6 +722,7 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { subvp_count++; + subvp_disallow |= disallow_subvp_in_active_plus_blank(pipe); refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); @@ -713,7 +739,7 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) } } - if (subvp_count == 1 && non_subvp_pipes == 1 && drr_pipe_found && !drr_psr_capable && + if (subvp_count == 1 && !subvp_disallow && non_subvp_pipes == 1 && drr_pipe_found && !drr_psr_capable && ((uint32_t)refresh_rate < 120)) result = true; @@ -746,6 +772,7 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int struct vba_vars_st *vba = &context->bw_ctx.dml.vba; bool vblank_psr_capable = false; uint64_t refresh_rate = 0; + bool subvp_disallow = false; for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -755,6 +782,7 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { subvp_count++; + subvp_disallow |= disallow_subvp_in_active_plus_blank(pipe); refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); @@ -772,7 +800,7 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int } if (subvp_count == 1 && non_subvp_pipes == 1 && !drr_pipe_found && !vblank_psr_capable && - ((uint32_t)refresh_rate < 120) && + ((uint32_t)refresh_rate < 120) && !subvp_disallow && vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp) result = true; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 92e2ddc9ab7e..c4ffb4b92b56 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -45,6 +45,14 @@ static const struct subvp_high_refresh_list subvp_high_refresh_list = { {.width = 1920, .height = 1080, }}, }; +static const struct subvp_active_margin_list subvp_active_margin_list = { + .min_refresh = 55, + .max_refresh = 65, + .res = { + {.width = 2560, .height = 1440, }, + {.width = 1920, .height = 1080, }}, +}; + struct _vcs_dpi_ip_params_st dcn3_2_ip = { .gpuvm_enable = 0, .gpuvm_max_page_table_levels = 4, @@ -3295,25 +3303,24 @@ bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe) { bool allow = false; uint32_t refresh_rate = 0; + uint32_t min_refresh = subvp_active_margin_list.min_refresh; + uint32_t max_refresh = subvp_active_margin_list.max_refresh; + uint32_t i; - /* Allow subvp on displays that have active margin for 2560x1440@60hz displays - * only for now. There must be no scaling as well. - * - * For now we only enable on 2560x1440@60hz displays to enable 4K60 + 1440p60 configs - * for p-state switching. - */ - if (pipe->stream && pipe->plane_state) { - refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 + - pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1) - / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total); - if (pipe->stream->timing.v_addressable == 1440 && - pipe->stream->timing.h_addressable == 2560 && - refresh_rate >= 55 && refresh_rate <= 65 && - pipe->plane_state->src_rect.height == 1440 && - pipe->plane_state->src_rect.width == 2560 && - pipe->plane_state->dst_rect.height == 1440 && - pipe->plane_state->dst_rect.width == 2560) + for (i = 0; i < SUBVP_ACTIVE_MARGIN_LIST_LEN; i++) { + uint32_t width = subvp_active_margin_list.res[i].width; + uint32_t height = subvp_active_margin_list.res[i].height; + + refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); + refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); + refresh_rate = div_u64(refresh_rate, pipe->stream->timing.h_total); + + if (refresh_rate >= min_refresh && refresh_rate <= max_refresh && + dcn32_check_native_scaling_for_res(pipe, width, height)) { allow = true; + break; + } } return allow; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h index b931008114c9..b2f20e6cfb38 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h @@ -39,6 +39,7 @@ #define DCN3_2_MBLK_HEIGHT_8BPE 64 #define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq #define SUBVP_HIGH_REFRESH_LIST_LEN 4 +#define SUBVP_ACTIVE_MARGIN_LIST_LEN 2 #define DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ 1800 #define DCN3_2_VMIN_DISPCLK_HZ 717000000 @@ -57,6 +58,15 @@ struct subvp_high_refresh_list { } res[SUBVP_HIGH_REFRESH_LIST_LEN]; }; +struct subvp_active_margin_list { + int min_refresh; + int max_refresh; + struct { + int width; + int height; + } res[SUBVP_ACTIVE_MARGIN_LIST_LEN]; +}; + struct dcn32_resource_pool { struct resource_pool base; }; From ee95135bfeecf67b313b5573054b03aa6dbc76f8 Mon Sep 17 00:00:00 2001 From: Li Ma Date: Tue, 21 Nov 2023 16:54:59 +0800 Subject: [PATCH 1838/7721] drm/amdgpu: add init_registers for nbio v7.11 enable init_registers callback func for nbio v7.11. Signed-off-by: Li Ma Reviewed-by: Yifan Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c | 18 ++++++------ .../asic_reg/nbio/nbio_7_11_0_offset.h | 2 ++ .../asic_reg/nbio/nbio_7_11_0_sh_mask.h | 29 +++++++++++++++++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c index 676ab1d20d2f..1f52b4b1db03 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c @@ -259,17 +259,17 @@ const struct nbio_hdp_flush_reg nbio_v7_11_hdp_flush_reg = { static void nbio_v7_11_init_registers(struct amdgpu_device *adev) { -/* uint32_t def, data; + uint32_t def, data; - def = data = RREG32_SOC15(NBIO, 0, regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3); - data = REG_SET_FIELD(data, BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, - CI_SWUS_MAX_READ_REQUEST_SIZE_MODE, 1); - data = REG_SET_FIELD(data, BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, - CI_SWUS_MAX_READ_REQUEST_SIZE_PRIV, 1); + def = data = RREG32_SOC15(NBIO, 0, regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3); + data = REG_SET_FIELD(data, BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, + CI_SWUS_MAX_READ_REQUEST_SIZE_MODE, 1); + data = REG_SET_FIELD(data, BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, + CI_SWUS_MAX_READ_REQUEST_SIZE_PRIV, 1); + + if (def != data) + WREG32_SOC15(NBIO, 0, regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, data); - if (def != data) - WREG32_SOC15(NBIO, 0, regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, data); -*/ } static void nbio_v7_11_update_medium_grain_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h index ff30f04be591..7ee3d291120d 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h @@ -781,6 +781,8 @@ #define regBIF_BIF256_CI256_RC3X4_USB4_PCIE_CNTL2_BASE_IDX 5 #define regBIF_BIF256_CI256_RC3X4_USB4_PCIE_TX_POWER_CTRL_1 0x420187 #define regBIF_BIF256_CI256_RC3X4_USB4_PCIE_TX_POWER_CTRL_1_BASE_IDX 5 +#define regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3 0x4201c6 +#define regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3_BASE_IDX 5 // addressBlock: nbio_nbif0_bif_cfg_dev0_rc_bifcfgdecp diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h index 7f131999a263..eb8c556d9c93 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h @@ -24646,6 +24646,35 @@ //BIF_BIF256_CI256_RC3X4_USB4_PCIE_TX_POWER_CTRL_1 #define BIF_BIF256_CI256_RC3X4_USB4_PCIE_TX_POWER_CTRL_1__MST_MEM_LS_EN_MASK 0x00000001L #define BIF_BIF256_CI256_RC3X4_USB4_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_LS_EN_MASK 0x00000008L +//BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_PAYLOAD_SIZE_MODE__SHIFT 0x8 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_PRIV_MAX_PAYLOAD_SIZE__SHIFT 0x9 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_10BIT_TAG_EN_OVERRIDE__SHIFT 0xb +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_10BIT_TAG_EN_OVERRIDE__SHIFT 0xd +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__MST_DROP_SYNC_FLOOD_EN__SHIFT 0xf +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_PAYLOAD_SIZE_MODE__SHIFT 0x10 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_PRIV_MAX_PAYLOAD_SIZE__SHIFT 0x11 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_READ_REQUEST_SIZE_MODE__SHIFT 0x14 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_PRIV_MAX_READ_REQUEST_SIZE__SHIFT 0x15 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_READ_SAFE_MODE__SHIFT 0x18 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_EXTENDED_TAG_EN_OVERRIDE__SHIFT 0x19 +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_READ_REQUEST_SIZE_MODE__SHIFT 0x1b +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_READ_REQUEST_SIZE_PRIV__SHIFT 0x1c +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_EXTENDED_TAG_EN_OVERRIDE__SHIFT 0x1e +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_PAYLOAD_SIZE_MODE_MASK 0x00000100L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_PRIV_MAX_PAYLOAD_SIZE_MASK 0x00000600L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_10BIT_TAG_EN_OVERRIDE_MASK 0x00001800L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_10BIT_TAG_EN_OVERRIDE_MASK 0x00006000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__MST_DROP_SYNC_FLOOD_EN_MASK 0x00008000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_PAYLOAD_SIZE_MODE_MASK 0x00010000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_PRIV_MAX_PAYLOAD_SIZE_MASK 0x000E0000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_READ_REQUEST_SIZE_MODE_MASK 0x00100000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_PRIV_MAX_READ_REQUEST_SIZE_MASK 0x00E00000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_MAX_READ_SAFE_MODE_MASK 0x01000000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_EXTENDED_TAG_EN_OVERRIDE_MASK 0x06000000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_READ_REQUEST_SIZE_MODE_MASK 0x08000000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_MAX_READ_REQUEST_SIZE_PRIV_MASK 0x30000000L +#define BIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3__CI_SWUS_EXTENDED_TAG_EN_OVERRIDE_MASK 0xC0000000L // addressBlock: nbio_nbif0_bif_cfg_dev0_rc_bifcfgdecp //BIF_CFG_DEV0_RC0_VENDOR_ID From 88f4b10a793262c4d6cf2566b1d210ec76f87867 Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Tue, 21 Nov 2023 11:06:51 +0800 Subject: [PATCH 1839/7721] drm/amdgpu: fix memory overflow in the IB test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a memory overflow issue in the gfx IB test for some ASICs. At least 20 bytes are needed for the IB test packet. v2: correct code indentation errors. (Christian) Signed-off-by: Tim Huang Reviewed-by: Yifan Zhang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 40ce12323164..8ed4a6fb147a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -427,7 +427,7 @@ static int gfx_v11_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); cpu_ptr = &adev->wb.wb[index]; - r = amdgpu_ib_get(adev, NULL, 16, AMDGPU_IB_POOL_DIRECT, &ib); + r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); if (r) { DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); goto err1; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 885ebd703260..1943beb135c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -883,8 +883,8 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) gpu_addr = adev->wb.gpu_addr + (index * 4); adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); memset(&ib, 0, sizeof(ib)); - r = amdgpu_ib_get(adev, NULL, 16, - AMDGPU_IB_POOL_DIRECT, &ib); + + r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); if (r) goto err1; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index e3ff6e46f3f7..69c500910746 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1039,8 +1039,8 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) gpu_addr = adev->wb.gpu_addr + (index * 4); adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); memset(&ib, 0, sizeof(ib)); - r = amdgpu_ib_get(adev, NULL, 16, - AMDGPU_IB_POOL_DIRECT, &ib); + + r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); if (r) goto err1; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 21865668b787..00b21ece081f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -297,8 +297,8 @@ static int gfx_v9_4_3_ring_test_ib(struct amdgpu_ring *ring, long timeout) gpu_addr = adev->wb.gpu_addr + (index * 4); adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); memset(&ib, 0, sizeof(ib)); - r = amdgpu_ib_get(adev, NULL, 16, - AMDGPU_IB_POOL_DIRECT, &ib); + + r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); if (r) goto err1; From c4b8394e76adba4f50a3c2696c75b214a291e24a Mon Sep 17 00:00:00 2001 From: Meenakshikumar Somasundaram Date: Thu, 9 Nov 2023 00:04:36 -0500 Subject: [PATCH 1840/7721] drm/amd/display: Fix tiled display misalignment [Why] When otg workaround is applied during clock update, otgs of tiled display went out of sync. [How] To call dc_trigger_sync() after clock update to sync otgs again. Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Meenakshikumar Somasundaram Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 76b47f178127..eab713c0da0d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1964,6 +1964,10 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c wait_for_no_pipes_pending(dc, context); /* pplib is notified if disp_num changed */ dc->hwss.optimize_bandwidth(dc, context); + /* Need to do otg sync again as otg could be out of sync due to otg + * workaround applied during clock update + */ + dc_trigger_sync(dc, context); } if (dc->hwss.update_dsc_pg) From fcd94ef1b3e78f7dc76309c9611915018d2d62a3 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 8 Nov 2023 10:55:53 -0500 Subject: [PATCH 1841/7721] drm/amd/display: Remove min_dst_y_next_start check for Z8 [Why] Flickering occurs on DRR supported panels when engaged in DRR due to min_dst_y_next becoming larger than the frame size itself. [How] In general, we should be able to enter Z8 when this is engaged but it might be a net power loss even if the calculation wasn't bugged. Don't support enabling Z8 during the DRR region. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Syed Hassan Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 7fc8b18096ba..ec77b2b41ba3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -950,10 +950,8 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc { int plane_count; int i; - unsigned int min_dst_y_next_start_us; plane_count = 0; - min_dst_y_next_start_us = 0; for (i = 0; i < dc->res_pool->pipe_count; i++) { if (context->res_ctx.pipe_ctx[i].plane_state) plane_count++; @@ -975,26 +973,15 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { struct dc_link *link = context->streams[0]->sink->link; struct dc_stream_status *stream_status = &context->stream_status[0]; - struct dc_stream_state *current_stream = context->streams[0]; int minmum_z8_residency = dc->debug.minimum_z8_residency_time > 0 ? dc->debug.minimum_z8_residency_time : 1000; bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z8_residency; bool is_pwrseq0 = link->link_index == 0; - bool isFreesyncVideo; - - isFreesyncVideo = current_stream->adjust.v_total_min == current_stream->adjust.v_total_max; - isFreesyncVideo = isFreesyncVideo && current_stream->timing.v_total < current_stream->adjust.v_total_min; - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (context->res_ctx.pipe_ctx[i].stream == current_stream && isFreesyncVideo) { - min_dst_y_next_start_us = context->res_ctx.pipe_ctx[i].dlg_regs.min_dst_y_next_start_us; - break; - } - } /* Don't support multi-plane configurations */ if (stream_status->plane_count > 1) return DCN_ZSTATE_SUPPORT_DISALLOW; - if (is_pwrseq0 && (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || min_dst_y_next_start_us > 5000)) + if (is_pwrseq0 && context->bw_ctx.dml.vba.StutterPeriod > 5000.0) return DCN_ZSTATE_SUPPORT_ALLOW; else if (is_pwrseq0 && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr) return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY; From d642b0100bf8c95e88e8396b7191b35807dabb4c Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 8 Nov 2023 10:59:00 -0500 Subject: [PATCH 1842/7721] drm/amd/display: Update min Z8 residency time to 2100 for DCN314 [Why] Some panels with residency period of 2054 exhibit flickering with Z8 at the end of the frame. [How] As a workaround, increase the limit to block these panels. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Syed Hassan Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index 677361d74a4e..c97391edb5ff 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -871,7 +871,7 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .enable_z9_disable_interface = true, - .minimum_z8_residency_time = 2000, + .minimum_z8_residency_time = 2100, .psr_skip_crtc_disable = true, .replay_skip_crtc_disabled = true, .disable_dmcu = true, From a5e90392fdda05ce842810bb749f3d210c3ffc65 Mon Sep 17 00:00:00 2001 From: Gabe Teeger Date: Thu, 9 Nov 2023 17:53:49 -0500 Subject: [PATCH 1843/7721] Revert "drm/amd/display: Enable CM low mem power optimization" This reverts commit fcfc6ceec3ebb725a0d6381a1120e7cd546e1df4. [why] Flickering observed. Regression search pointed to this being the offending commit. Reviewed-by: Charlene Liu Reviewed-by: Yihan Zhu Acked-by: Hamza Mahfooz Signed-off-by: Gabe Teeger Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c | 13 +++++-------- .../amd/display/dc/resource/dcn35/dcn35_resource.c | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 1a2adb354718..994b21ed272f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -71,24 +71,21 @@ void mpc32_power_on_blnd_lut( { struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); -/* if (mpc->ctx->dc->debug.enable_mem_low_power.bits.cm) { if (power_on) { REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0); REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5); } else if (!mpc->ctx->dc->debug.disable_mem_low_power) { - //TODO: change to mpc - dpp_base->ctx->dc->optimized_required = true; - dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; + ASSERT(false); + /* TODO: change to mpc + * dpp_base->ctx->dc->optimized_required = true; + * dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; + */ } } else { REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, MPCC_MCM_1DLUT_MEM_PWR_FORCE, power_on == true ? 0 : 1); } -*/ - - REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, - MPCC_MCM_1DLUT_MEM_PWR_FORCE, power_on == true ? 0 : 1); } static enum dc_lut_mode mpc32_get_post1dlut_current(struct mpc *mpc, uint32_t mpcc_id) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 0d5a03c6d812..53eefba0b9dc 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -736,7 +736,7 @@ static const struct dc_debug_options debug_defaults_drv = { .i2c = true, .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled .dscl = true, - .cm = true, + .cm = false, .mpc = true, .optc = true, .vpg = true, From 0e6a12884ca72520b195d95f1fa1bf790678cd6c Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Wed, 8 Nov 2023 14:38:29 +0800 Subject: [PATCH 1844/7721] drm/amdgpu: correct the amdgpu runtime dereference usage count Fix the amdgpu runpm dereference usage count. Signed-off-by: Prike Liang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 0cacd0b9f8be..b8fbe97efe1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -340,14 +340,11 @@ int amdgpu_display_crtc_set_config(struct drm_mode_set *set, adev->have_disp_power_ref = true; return ret; } - /* if we have no active crtcs, then drop the power ref - * we got before + /* if we have no active crtcs, then go to + * drop the power ref we got before */ - if (!active && adev->have_disp_power_ref) { - pm_runtime_put_autosuspend(dev->dev); + if (!active && adev->have_disp_power_ref) adev->have_disp_power_ref = false; - } - out: /* drop the power reference we got coming in here */ pm_runtime_put_autosuspend(dev->dev); From f4233efedf75572e49efd08202b1a07196949b4a Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 9 Nov 2023 18:08:17 -0500 Subject: [PATCH 1845/7721] drm/amd/display: If P-State is supported try SubVP for smaller vlevel [Description] - To reduce vlevel further, we can try to apply subvp on configs that already support p-state since the natural p-state support may not allow for DPM0. - Add code to try subvp to reduce UCLK DPM level further if already supported, but don't use subvp if it does not optimize the DPM level even lower Reviewed-by: Samson Tam Acked-by: Hamza Mahfooz Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index c4ffb4b92b56..26411d4e9730 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1416,6 +1416,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, unsigned int dc_pipe_idx = 0; int i = 0; bool found_supported_config = false; + int vlevel_temp = 0; dc_assert_fp_enabled(); @@ -1448,13 +1449,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, */ if (!dc->debug.force_disable_subvp && !dc->caps.dmub_caps.gecc_enable && dcn32_all_pipes_have_stream_and_plane(dc, context) && !dcn32_mpo_in_use(context) && !dcn32_any_surfaces_rotated(dc, context) && !is_test_pattern_enabled(context) && - (*vlevel == context->bw_ctx.dml.soc.num_states || + (*vlevel == context->bw_ctx.dml.soc.num_states || (vba->DRAMSpeedPerState[*vlevel] != vba->DRAMSpeedPerState[0] && + vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported) || vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported || dc->debug.force_subvp_mclk_switch)) { dcn32_merge_pipes_for_subvp(dc, context); memset(merge, 0, MAX_PIPES * sizeof(bool)); + vlevel_temp = *vlevel; /* to re-initialize viewport after the pipe merge */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1523,6 +1526,9 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, } } + if (vba->DRAMSpeedPerState[*vlevel] >= vba->DRAMSpeedPerState[vlevel_temp]) + found_supported_config = false; + // If SubVP pipe config is unsupported (or cannot be used for UCLK switching) // remove phantom pipes and repopulate dml pipes if (!found_supported_config) { From 5a9a2cc8ae1889c4002850b00fd4fd9691dfac4e Mon Sep 17 00:00:00 2001 From: Zhongwei Date: Wed, 8 Nov 2023 16:34:36 +0800 Subject: [PATCH 1846/7721] drm/amd/display: force toggle rate wa for first link training for a retimer [WHY] Handover from DMUB to driver does not perform link rate toggle. It might cause link training failure for boot up. [HOW] Force toggle rate wa for first link train. link->vendor_specific_lttpr_link_rate_wa should be zero then. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Michael Strauss Acked-by: Hamza Mahfooz Signed-off-by: Zhongwei Signed-off-by: Alex Deucher --- .../link/protocols/link_dp_training_fixed_vs_pe_retimer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index fd8f6f198146..68096d12f52f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -115,7 +115,7 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq lt_settings->cr_pattern_time = 16000; /* Fixed VS/PE specific: Toggle link rate */ - apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); + apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0)); target_rate = get_dpcd_link_rate(<_settings->link_settings); toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; @@ -271,7 +271,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( /* Vendor specific: Toggle link rate */ toggle_rate = (rate == 0x6) ? 0xA : 0x6; - if (link->vendor_specific_lttpr_link_rate_wa == rate) { + if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { core_link_write_dpcd( link, DP_LINK_BW_SET, @@ -617,7 +617,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( /* Vendor specific: Toggle link rate */ toggle_rate = (rate == 0x6) ? 0xA : 0x6; - if (link->vendor_specific_lttpr_link_rate_wa == rate) { + if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { core_link_write_dpcd( link, DP_LINK_BW_SET, From 3d0fe49454652117522f60bfbefb978ba0e5300b Mon Sep 17 00:00:00 2001 From: Parandhaman K Date: Thu, 9 Nov 2023 15:52:17 +0530 Subject: [PATCH 1847/7721] drm/amd/display: Refactor OPTC into component folder [why] Move all optc files to unique folder optc. [how] creating optc repo in dc, and moved the dcnxx_optc.c and .h files into corresponding new folders inside the optc and cleared the linkage errors by adding relative paths in the Makefile.template. Reviewed-by: Martin Leung Acked-by: Hamza Mahfooz Signed-off-by: Parandhaman K Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Makefile | 1 + drivers/gpu/drm/amd/display/dc/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/Makefile | 2 +- .../dc/dcn10/dcn10_hw_sequencer_debug.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn20/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn201/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn30/Makefile | 1 - .../gpu/drm/amd/display/dc/dcn301/Makefile | 3 +- drivers/gpu/drm/amd/display/dc/dcn31/Makefile | 2 +- .../gpu/drm/amd/display/dc/dcn314/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dcn32/Makefile | 6 +- drivers/gpu/drm/amd/display/dc/dcn35/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/optc/Makefile | 108 ++++++++++++++++++ .../display/dc/{ => optc}/dcn10/dcn10_optc.c | 0 .../display/dc/{ => optc}/dcn10/dcn10_optc.h | 0 .../display/dc/{ => optc}/dcn20/dcn20_optc.c | 0 .../display/dc/{ => optc}/dcn20/dcn20_optc.h | 2 +- .../dc/{ => optc}/dcn201/dcn201_optc.c | 0 .../dc/{ => optc}/dcn201/dcn201_optc.h | 0 .../display/dc/{ => optc}/dcn30/dcn30_optc.c | 0 .../display/dc/{ => optc}/dcn30/dcn30_optc.h | 0 .../dc/{ => optc}/dcn301/dcn301_optc.c | 0 .../dc/{ => optc}/dcn301/dcn301_optc.h | 0 .../display/dc/{ => optc}/dcn31/dcn31_optc.c | 0 .../display/dc/{ => optc}/dcn31/dcn31_optc.h | 0 .../dc/{ => optc}/dcn314/dcn314_optc.c | 0 .../dc/{ => optc}/dcn314/dcn314_optc.h | 0 .../display/dc/{ => optc}/dcn32/dcn32_optc.c | 0 .../display/dc/{ => optc}/dcn32/dcn32_optc.h | 0 .../display/dc/{ => optc}/dcn35/dcn35_optc.c | 0 .../display/dc/{ => optc}/dcn35/dcn35_optc.h | 0 31 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/optc/Makefile rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn10/dcn10_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn10/dcn10_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn20/dcn20_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn20/dcn20_optc.h (99%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn201/dcn201_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn201/dcn201_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn30/dcn30_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn30/dcn30_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn301/dcn301_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn301/dcn301_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn31/dcn31_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn31/dcn31_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn314/dcn314_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn314/dcn314_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn32/dcn32_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn32/dcn32_optc.h (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn35/dcn35_optc.c (100%) rename drivers/gpu/drm/amd/display/dc/{ => optc}/dcn35/dcn35_optc.h (100%) diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 7b0959da2cac..92a5c5efcf92 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -32,6 +32,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/clk_mgr subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hwss subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/resource subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dsc +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/optc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index ab51a065cf0e..390e7a99be54 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -22,7 +22,7 @@ # # Makefile for Display Core (dc) component. -DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc resource +DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc resource optc ifdef CONFIG_DRM_AMD_DC_FP diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 1eb7418ced3a..0dd62934a18c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -24,7 +24,7 @@ DCN10 = dcn10_init.o dcn10_ipp.o \ dcn10_hw_sequencer_debug.o \ - dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ + dcn10_dpp.o dcn10_opp.o \ dcn10_hubp.o dcn10_mpc.o \ dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \ dcn10_hubbub.o dcn10_stream_encoder.o dcn10_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 92fdab731f4a..9033b39e0e0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -32,7 +32,7 @@ #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" -#include "dcn10_optc.h" +#include "dcn10/dcn10_optc.h" #include "dcn10/dcn10_dpp.h" #include "dcn10/dcn10_mpc.h" #include "timing_generator.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index 93ac45802e44..bd760442ff89 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -3,7 +3,7 @@ # Makefile for DCN. DCN20 = dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ - dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ + dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_mmhubbub.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile index c069a894db92..a101e6511555 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile @@ -3,7 +3,7 @@ # Makefile for DCN. DCN201 = dcn201_init.o \ dcn201_hubbub.o\ - dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_optc.o dcn201_dpp.o \ + dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_dpp.o \ dcn201_dccg.o dcn201_link_encoder.o AMD_DAL_DCN201 = $(addprefix $(AMDDALPATH)/dc/dcn201/,$(DCN201)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile index 9dcf06c0954d..cd95f322235e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile @@ -28,7 +28,6 @@ DCN30 := \ dcn30_hubbub.o \ dcn30_hubp.o \ dcn30_dpp.o \ - dcn30_optc.o \ dcn30_dccg.o \ dcn30_mpc.o dcn30_vpg.o \ dcn30_afmt.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile index cbf59d7e78c4..090011300dcd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile @@ -11,8 +11,7 @@ # Makefile for dcn30. DCN301 = dcn301_init.o dcn301_dccg.o \ - dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o \ - dcn301_optc.o + dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o AMD_DAL_DCN301 = $(addprefix $(AMDDALPATH)/dc/dcn301/,$(DCN301)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile index 212287008c0a..11a2662e58ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -11,7 +11,7 @@ # Makefile for dcn31. DCN31 = dcn31_hubbub.o dcn31_init.o dcn31_hubp.o \ - dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ + dcn31_dccg.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o \ dcn31_afmt.o dcn31_vpg.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile index 6ea47e00d62d..d5c177346a3b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile @@ -11,7 +11,7 @@ # Makefile for dcn314. DCN314 = dcn314_init.o \ - dcn314_dio_stream_encoder.o dcn314_dccg.o dcn314_optc.o + dcn314_dio_stream_encoder.o dcn314_dccg.o AMD_DAL_DCN314 = $(addprefix $(AMDDALPATH)/dc/dcn314/,$(DCN314)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile index 3bb17dd01e4c..905b74b53092 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile @@ -11,9 +11,9 @@ # Makefile for dcn32. DCN32 = dcn32_hubbub.o dcn32_init.o dcn32_dccg.o \ - dcn32_dccg.o dcn32_optc.o dcn32_mmhubbub.o dcn32_hubp.o dcn32_dpp.o \ - dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_hpo_dp_link_encoder.o \ - dcn32_resource_helpers.o dcn32_mpc.o + dcn32_mmhubbub.o dcn32_dpp.o dcn32_hubp.o dcn32_mpc.o \ + dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_resource_helpers.o \ + dcn32_hpo_dp_link_encoder.o AMD_DAL_DCN32 = $(addprefix $(AMDDALPATH)/dc/dcn32/,$(DCN32)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile index 85a307babab9..fa7ec82ae5f5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile @@ -11,7 +11,7 @@ # Makefile for DCN35. DCN35 = dcn35_init.o dcn35_dio_stream_encoder.o \ - dcn35_dio_link_encoder.o dcn35_dccg.o dcn35_optc.o \ + dcn35_dio_link_encoder.o dcn35_dccg.o \ dcn35_hubp.o dcn35_hubbub.o \ dcn35_mmhubbub.o dcn35_opp.o dcn35_dpp.o dcn35_pg_cntl.o dcn35_dwb.o diff --git a/drivers/gpu/drm/amd/display/dc/optc/Makefile b/drivers/gpu/drm/amd/display/dc/optc/Makefile new file mode 100644 index 000000000000..bb213335fb9f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/Makefile @@ -0,0 +1,108 @@ + +# Copyright 2022 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Makefile for the 'optc' sub-component of DAL. +# + + +ifdef CONFIG_DRM_AMD_DC_FP +############################################################################### +# DCN +############################################################################### + +OPTC_DCN10 = dcn10_optc.o + +AMD_DAL_OPTC_DCN10 = $(addprefix $(AMDDALPATH)/dc/optc/dcn10/,$(OPTC_DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN10) + +############################################################################### + +OPTC_DCN20 = dcn20_optc.o + +AMD_DAL_OPTC_DCN20 = $(addprefix $(AMDDALPATH)/dc/optc/dcn20/,$(OPTC_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN20) + +############################################################################### + +OPTC_DCN201 = dcn201_optc.o + +AMD_DAL_OPTC_DCN201 = $(addprefix $(AMDDALPATH)/dc/optc/dcn201/,$(OPTC_DCN201)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN201) + +############################################################################### + +############################################################################### + +############################################################################### + +OPTC_DCN30 = dcn30_optc.o + +AMD_DAL_OPTC_DCN30 = $(addprefix $(AMDDALPATH)/dc/optc/dcn30/,$(OPTC_DCN30)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN30) + +############################################################################### + +OPTC_DCN301 = dcn301_optc.o + +AMD_DAL_OPTC_DCN301 = $(addprefix $(AMDDALPATH)/dc/optc/dcn301/,$(OPTC_DCN301)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN301) + +############################################################################### + +OPTC_DCN31 = dcn31_optc.o + +AMD_DAL_OPTC_DCN31 = $(addprefix $(AMDDALPATH)/dc/optc/dcn31/,$(OPTC_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN31) + +############################################################################### + +OPTC_DCN314 = dcn314_optc.o + +AMD_DAL_OPTC_DCN314 = $(addprefix $(AMDDALPATH)/dc/optc/dcn314/,$(OPTC_DCN314)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN314) + +############################################################################### + +OPTC_DCN32 = dcn32_optc.o + +AMD_DAL_OPTC_DCN32 = $(addprefix $(AMDDALPATH)/dc/optc/dcn32/,$(OPTC_DCN32)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN32) + +############################################################################### + +OPTC_DCN35 = dcn35_optc.o + +AMD_DAL_OPTC_DCN35 = $(addprefix $(AMDDALPATH)/dc/optc/dcn35/,$(OPTC_DCN35)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN35) + +############################################################################### + +############################################################################### +endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h similarity index 99% rename from drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h index f7968b9ca16e..c2e03ced392e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h @@ -26,7 +26,7 @@ #ifndef __DC_OPTC_DCN20_H__ #define __DC_OPTC_DCN20_H__ -#include "../dcn10/dcn10_optc.h" +#include "dcn10/dcn10_optc.h" #define TG_COMMON_REG_LIST_DCN2_0(inst) \ TG_COMMON_REG_LIST_DCN(inst),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.c rename to drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.h rename to drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h From 5fcf74e002f152db0c39a7cdafa082c952cc5640 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 3 Nov 2023 18:07:11 -0400 Subject: [PATCH 1848/7721] drm/amd/display: Update DCN35 clock table policy [Why] The new table doesn't have an implicit mapping between Fclk SOC voltage and MemClk and it currently builds the table off of number of Fclk states rather than DcfClock states. The DML table in use is not correct for functionality or power and does not align with our existing policies for DCN3x. [How] Build the table based on DcfClock with the following assumptions: 1. Raising Soc voltage is the most expensive operation, so assume that running at max DispClock or DppClock is preferable. 2. Assume that we can run at max Fclk / MemClk at any state, but restrict the maximum state to the very last entry in the table as the worst case scenario. 3. Assume that Fclk always has a 2x multiplier on DcfClock unless the table specifies something lower. Reviewed-by: Taimur Hassan Acked-by: Hamza Mahfooz Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 77 ++++++++++++------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 0f3f6a9d5144..19f8d83698be 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -648,27 +648,47 @@ static unsigned int convert_wck_ratio(uint8_t wck_ratio) return 1; } +static inline uint32_t calc_dram_speed_mts(const MemPstateTable_t *entry) +{ + return entry->UClk * convert_wck_ratio(entry->WckRatio) * 2; +} + static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr, struct integrated_info *bios_info, DpmClocks_t_dcn35 *clock_table) { struct clk_bw_params *bw_params = clk_mgr->base.bw_params; struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; - uint32_t max_pstate = 0, max_uclk = 0, max_fclk = 0; - uint32_t min_pstate = 0, max_dispclk = 0, max_dppclk = 0; + uint32_t max_fclk = 0, min_pstate = 0, max_dispclk = 0, max_dppclk = 0; + uint32_t max_pstate = 0, max_dram_speed_mts = 0, min_dram_speed_mts = 0; int i; + /* Determine min/max p-state values. */ for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { - if (is_valid_clock_value(clock_table->MemPstateTable[i].UClk) && - clock_table->MemPstateTable[i].UClk > max_uclk) { - max_uclk = clock_table->MemPstateTable[i].UClk; + uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); + + if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts > max_dram_speed_mts) { + max_dram_speed_mts = dram_speed_mts; max_pstate = i; } } - /* We expect the table to contain at least one valid Uclk entry. */ - ASSERT(is_valid_clock_value(max_uclk)); + min_dram_speed_mts = max_dram_speed_mts; + min_pstate = max_pstate; + for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { + uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); + + if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts < min_dram_speed_mts) { + min_dram_speed_mts = dram_speed_mts; + min_pstate = i; + } + } + + /* We expect the table to contain at least one valid P-state entry. */ + ASSERT(clock_table->NumMemPstatesEnabled && + is_valid_clock_value(max_dram_speed_mts) && + is_valid_clock_value(min_dram_speed_mts)); /* dispclk and dppclk can be max at any voltage, same number of levels for both */ if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS && @@ -678,47 +698,46 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled); } else { + /* Invalid number of entries in the table from PMFW. */ ASSERT(0); } - if (clock_table->NumFclkLevelsEnabled <= NUM_FCLK_DPM_LEVELS) - max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, - clock_table->NumFclkLevelsEnabled); - for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { - uint32_t min_uclk = clock_table->MemPstateTable[0].UClk; + /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */ + ASSERT(clock_table->NumDcfClkLevelsEnabled > 0); + + max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, clock_table->NumFclkLevelsEnabled); + + for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { int j; - for (j = 1; j < clock_table->NumMemPstatesEnabled; j++) { - if (is_valid_clock_value(clock_table->MemPstateTable[j].UClk) && - clock_table->MemPstateTable[j].UClk < min_uclk && - clock_table->MemPstateTable[j].Voltage <= clock_table->SocVoltage[i]) { - min_uclk = clock_table->MemPstateTable[j].UClk; - min_pstate = j; - } - } - + /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i]) - break; + break; bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz; bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz; bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; - bw_params->clk_table.entries[i].fclk_mhz = max_fclk; + + /* Now update clocks we do read */ bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[min_pstate].MemClk; bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[min_pstate].Voltage; bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; - bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio( - clock_table->MemPstateTable[min_pstate].WckRatio); - } + bw_params->clk_table.entries[i].wck_ratio = + convert_wck_ratio(clock_table->MemPstateTable[min_pstate].WckRatio); + + /* Dcfclk and Fclk are tied, but at a different ratio */ + bw_params->clk_table.entries[i].fclk_mhz = min(max_fclk, 2 * clock_table->DcfClocks[i]); + } /* Make sure to include at least one entry at highest pstate */ if (max_pstate != min_pstate || i == 0) { if (i > MAX_NUM_DPM_LVL - 1) i = MAX_NUM_DPM_LVL - 1; + bw_params->clk_table.entries[i].fclk_mhz = max_fclk; bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[max_pstate].MemClk; bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[max_pstate].Voltage; @@ -734,6 +753,7 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk } bw_params->clk_table.num_entries = i--; + /* Make sure all highest clocks are included*/ bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); bw_params->clk_table.entries[i].dispclk_mhz = @@ -752,6 +772,11 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk bw_params->clk_table.num_entries_per_clk.num_fclk_levels = clock_table->NumFclkLevelsEnabled; bw_params->clk_table.num_entries_per_clk.num_memclk_levels = clock_table->NumMemPstatesEnabled; bw_params->clk_table.num_entries_per_clk.num_socclk_levels = clock_table->NumSocClkLevelsEnabled; + + /* + * Set any 0 clocks to max default setting. Not an issue for + * power since we aren't doing switching in such case anyway + */ for (i = 0; i < bw_params->clk_table.num_entries; i++) { if (!bw_params->clk_table.entries[i].fclk_mhz) { bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; From f19c115d9c3c4f386c4662cc7b02ae1ffc2374af Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 10 Nov 2023 10:06:09 -0500 Subject: [PATCH 1849/7721] drm/amd/display: Remove config update [Why] Prevent overwrite of dc->config.use_default_clock_table, as it should be pre-configured. Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Taimur Hassan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 53eefba0b9dc..1a0ed1c7e2d4 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -1876,7 +1876,7 @@ static bool dcn35_resource_construct( /* Use pipe context based otg sync logic */ dc->config.use_pipe_ctx_sync_logic = true; - dc->config.use_default_clock_table = false; + /* read VBIOS LTTPR caps */ { if (ctx->dc_bios->funcs->get_lttpr_caps) { From fbd2076c31e3281dea7b475d80211b7a6f1500da Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Wed, 22 Nov 2023 15:17:22 -0500 Subject: [PATCH 1850/7721] drm/amdkfd: Use common function for IP version check KFD_GC_VERSION was recently updated to use a new function for IP version checks. As a result, use KFD_GC_VERSION as the common function for all IP version checks in KFD. Signed-off-by: Mukul Joshi Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index a40f8cfc6aa5..45366b4ca976 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1127,7 +1127,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev, struct kfd_dev *dev = adev->kfd.dev; uint32_t i; - if (adev->ip_versions[GC_HWIP][0] != IP_VERSION(9, 4, 3)) + if (KFD_GC_VERSION(dev) != IP_VERSION(9, 4, 3)) return dev->nodes[0]; for (i = 0; i < dev->num_nodes; i++) From 22136ff27c4e01fae81f6588033363a46c72ed8c Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 10 Nov 2023 10:15:28 -0500 Subject: [PATCH 1851/7721] drm/amd/display: Fix conversions between bytes and KB [Why] There are a number of instances where we convert HostVMMinPageSize or GPUVMMinPageSize from bytes to KB by dividing (rather than multiplying) and vice versa. Additionally, in some cases, a parameter is passed through DML in KB but later checked as if it were in bytes. Cc: stable@vger.kernel.org Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Taimur Hassan Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2/display_mode_core.c | 16 ++++++++-------- .../display/dc/dml2/dml2_translation_helper.c | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c index 510be909cd75..59718ee33e51 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c @@ -6329,7 +6329,7 @@ static void dml_prefetch_check(struct display_mode_lib_st *mode_lib) mode_lib->ms.NoOfDPPThisState, mode_lib->ms.dpte_group_bytes, s->HostVMInefficiencyFactor, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels); s->NextMaxVStartup = s->MaxVStartupAllPlanes[j]; @@ -6542,7 +6542,7 @@ static void dml_prefetch_check(struct display_mode_lib_st *mode_lib) mode_lib->ms.cache_display_cfg.plane.HostVMEnable, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels, mode_lib->ms.cache_display_cfg.plane.GPUVMEnable, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.PDEAndMetaPTEBytesPerFrame[j][k], mode_lib->ms.MetaRowBytes[j][k], mode_lib->ms.DPTEBytesPerRow[j][k], @@ -7687,7 +7687,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; @@ -7957,7 +7957,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) UseMinimumDCFCLK_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; UseMinimumDCFCLK_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; UseMinimumDCFCLK_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; - UseMinimumDCFCLK_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + UseMinimumDCFCLK_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; UseMinimumDCFCLK_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; UseMinimumDCFCLK_params->DynamicMetadataVMEnabled = mode_lib->ms.ip.dynamic_metadata_vm_enabled; UseMinimumDCFCLK_params->ImmediateFlipRequirement = s->ImmediateFlipRequiredFinal; @@ -8699,7 +8699,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = s->dummy_boolean_array[0]; @@ -8805,7 +8805,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc mode_lib->ms.cache_display_cfg.hw.DPPPerSurface, locals->dpte_group_bytes, s->HostVMInefficiencyFactor, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels); locals->TCalc = 24.0 / locals->DCFCLKDeepSleep; @@ -8995,7 +8995,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc CalculatePrefetchSchedule_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; CalculatePrefetchSchedule_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; CalculatePrefetchSchedule_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; - CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculatePrefetchSchedule_params->DynamicMetadataEnable = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataEnable[k]; CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ms.ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataLinesBeforeActiveRequired[k]; @@ -9240,7 +9240,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc mode_lib->ms.cache_display_cfg.plane.HostVMEnable, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels, mode_lib->ms.cache_display_cfg.plane.GPUVMEnable, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, locals->PDEAndMetaPTEBytesFrame[k], locals->MetaRowByte[k], locals->PixelPTEBytesPerRow[k], diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index 2b9638c6d9b0..48caa34a5ce7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -515,8 +515,8 @@ void dml2_translate_socbb_params(const struct dc *in, struct soc_bounding_box_st out->do_urgent_latency_adjustment = in_soc_params->do_urgent_latency_adjustment; out->dram_channel_width_bytes = (dml_uint_t)in_soc_params->dram_channel_width_bytes; out->fabric_datapath_to_dcn_data_return_bytes = (dml_uint_t)in_soc_params->fabric_datapath_to_dcn_data_return_bytes; - out->gpuvm_min_page_size_kbytes = in_soc_params->gpuvm_min_page_size_bytes * 1024; - out->hostvm_min_page_size_kbytes = in_soc_params->hostvm_min_page_size_bytes * 1024; + out->gpuvm_min_page_size_kbytes = in_soc_params->gpuvm_min_page_size_bytes / 1024; + out->hostvm_min_page_size_kbytes = in_soc_params->hostvm_min_page_size_bytes / 1024; out->mall_allocated_for_dcn_mbytes = (dml_uint_t)in_soc_params->mall_allocated_for_dcn_mbytes; out->max_avg_dram_bw_use_normal_percent = in_soc_params->max_avg_dram_bw_use_normal_percent; out->max_avg_fabric_bw_use_normal_percent = in_soc_params->max_avg_fabric_bw_use_normal_percent; From 2d1c884a535fcca74814553132d41c15dc9831ef Mon Sep 17 00:00:00 2001 From: Sung Joon Kim Date: Fri, 10 Nov 2023 11:33:45 -0500 Subject: [PATCH 1852/7721] drm/amd/display: Fix black screen on video playback with embedded panel [why] We have dynamic power control in driver but should be ignored when power is forced on. [how] Bypass any power control when it's forced on. Cc: stable@vger.kernel.org Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Sung Joon Kim Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 1 - drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 19f8d83698be..63a0b885b6f0 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -1132,7 +1132,6 @@ void dcn35_clk_mgr_construct( ctx->dc->debug.disable_dpp_power_gate = false; ctx->dc->debug.disable_hubp_power_gate = false; ctx->dc->debug.disable_dsc_power_gate = false; - ctx->dc->debug.disable_hpo_power_gate = false; } else { /*let's reset the config control flag*/ ctx->dc->config.disable_ips = DMUB_IPS_DISABLE_ALL; /*pmfw not support it, disable it all*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c index 0f60c40e1fc5..53bd0ae4bab5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c @@ -261,6 +261,7 @@ void pg_cntl35_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; + uint32_t power_forceon; bool block_enabled; if (pg_cntl->ctx->dc->debug.ignore_pg || @@ -277,6 +278,10 @@ void pg_cntl35_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) return; } + REG_GET(DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); + if (power_forceon) + return; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -304,6 +309,7 @@ void pg_cntl35_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; + uint32_t power_forceon; bool block_enabled; if (pg_cntl->ctx->dc->debug.ignore_pg || @@ -319,6 +325,10 @@ void pg_cntl35_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) return; } + REG_GET(DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); + if (power_forceon) + return; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); From 641220b2a53c64efb8327ffbbc3bfcf96b5a613f Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 11 Nov 2023 22:47:50 -0500 Subject: [PATCH 1853/7721] drm/amd/display: [FW Promotion] Release 0.0.193.0 - Add a tracing framework, to measure duration, execution count and longest duration of main loop/vsync interrupt work GPINT command is used to start/stop the measurements. Acked-by: Hamza Mahfooz Signed-off-by: Anthony Koo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index a08073fc92ae..b7d9360bfdc8 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -185,8 +185,7 @@ union abm_flags { unsigned int disable_abm_requested : 1; /** - * @disable_abm_immediately: Indicates if driver has requested ABM to be disabled - * immediately. + * @disable_abm_immediately: Indicates if driver has requested ABM to be disabled immediately. */ unsigned int disable_abm_immediately : 1; @@ -866,6 +865,13 @@ enum dmub_gpint_command { * DESC: Updates the trace buffer mask bit32~bit63. */ DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD3 = 119, + + /** + * DESC: Enable measurements for various task duration + * ARGS: 0 - Disable measurement + * 1 - Enable measurement + */ + DMUB_GPINT__TRACE_DMUB_WAKE_ACTIVITY = 123, }; /** From db4616f7667c9d1f733ec360a754a4d7fd32c28e Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Mon, 13 Nov 2023 09:07:22 -0500 Subject: [PATCH 1854/7721] drm/amd/display: 3.2.261 This version brings along the following: - DCN314 fixes - DCN32 fixes - DCN35 fixes - DML2 fixes - eDP fixes - HDR fixes - MST fixes - Replay fixes - SubVP support for more configs Acked-by: Hamza Mahfooz Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 85771ef98cd7..6074ac1b180a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -49,7 +49,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.260" +#define DC_VER "3.2.261" #define MAX_SURFACES 3 #define MAX_PLANES 6 From 201761b5eb57c3fad810cde555795c3b5721a031 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 9 Nov 2023 10:50:38 +0530 Subject: [PATCH 1855/7721] drm/amdgpu: Move mca debug mode decision to ras Refactor code such that ras block decides the default mca debug mode, and not swsmu block. By default mca debug mode is set to false. v2: squash in uninitialized value fix (Alex) Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 14 +++++++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 2 +- .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 12 ------------ 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index cf33eb219e25..54f2f346579e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -377,7 +377,7 @@ static int amdgpu_mca_smu_debug_mode_set(void *data, u64 val) struct amdgpu_device *adev = (struct amdgpu_device *)data; int ret; - ret = amdgpu_mca_smu_set_debug_mode(adev, val ? true : false); + ret = amdgpu_ras_set_mca_debug_mode(adev, val ? true : false); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index a3dc68e98910..f6b47ebce9d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -3132,6 +3132,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return 0; + amdgpu_ras_set_mca_debug_mode(adev, false); + list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { if (!node->ras_obj) { dev_warn(adev->dev, "Warning: abnormal ras list node.\n"); @@ -3405,12 +3407,18 @@ int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) return 0; } -void amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) +int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + int ret = 0; - if (con) - con->is_mca_debug_mode = enable; + if (con) { + ret = amdgpu_mca_smu_set_debug_mode(adev, enable); + if (!ret) + con->is_mca_debug_mode = enable; + } + + return ret; } bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 19161916ac46..6a941eb8fb8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -773,7 +773,7 @@ struct amdgpu_ras* amdgpu_ras_get_context(struct amdgpu_device *adev); int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_con); -void amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); +int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev); bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, unsigned int *mode); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 8ccb8354bb49..dda2249c4994 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1516,7 +1516,6 @@ static int smu_v13_0_6_mca_set_debug_mode(struct smu_context *smu, bool enable) if (smu->smc_fw_version < 0x554800) return 0; - amdgpu_ras_set_mca_debug_mode(smu->adev, enable); return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ClearMcaOnRead, enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | ClearMcaOnRead_CE_POLL_MASK, NULL); @@ -2346,16 +2345,6 @@ static int smu_v13_0_6_smu_send_hbm_bad_page_num(struct smu_context *smu, return ret; } -static int smu_v13_0_6_post_init(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - if (!amdgpu_sriov_vf(adev) && adev->ras_enabled) - return smu_v13_0_6_mca_set_debug_mode(smu, false); - - return 0; -} - static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) { struct smu_context *smu = adev->powerplay.pp_handle; @@ -2920,7 +2909,6 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .i2c_init = smu_v13_0_6_i2c_control_init, .i2c_fini = smu_v13_0_6_i2c_control_fini, .send_hbm_bad_pages_num = smu_v13_0_6_smu_send_hbm_bad_page_num, - .post_init = smu_v13_0_6_post_init, }; void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) From 7a6931a476d30f0d6bf70b01a925f76f92d23940 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Wed, 22 Nov 2023 14:50:34 -0500 Subject: [PATCH 1856/7721] drm/amd/display: fix ABM disablement On recent versions of DMUB firmware, if we want to completely disable ABM we have to pass ABM_LEVEL_IMMEDIATE_DISABLE as the requested ABM level to DMUB. Otherwise, LCD eDP displays are unable to reach their maximum brightness levels. So, to fix this whenever the user requests an ABM level of 0 pass ABM_LEVEL_IMMEDIATE_DISABLE to DMUB instead. Also, to keep the user's experience consistent map ABM_LEVEL_IMMEDIATE_DISABLE to 0 when a user tries to read the requested ABM level. Cc: stable@vger.kernel.org # 6.1+ Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 2be64c593c87..39a4b47b6804 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6248,7 +6248,7 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, dm_new_state->underscan_enable = val; ret = 0; } else if (property == adev->mode_info.abm_level_property) { - dm_new_state->abm_level = val; + dm_new_state->abm_level = val ?: ABM_LEVEL_IMMEDIATE_DISABLE; ret = 0; } @@ -6293,7 +6293,8 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, *val = dm_state->underscan_enable; ret = 0; } else if (property == adev->mode_info.abm_level_property) { - *val = dm_state->abm_level; + *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ? + dm_state->abm_level : 0; ret = 0; } @@ -6366,7 +6367,8 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->pbn = 0; if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) - state->abm_level = amdgpu_dm_abm_level; + state->abm_level = amdgpu_dm_abm_level ?: + ABM_LEVEL_IMMEDIATE_DISABLE; __drm_atomic_helper_connector_reset(connector, &state->base); } From 01a1526ac4c8d9342d3d8b703751f3fc5ce487ba Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Fri, 3 Nov 2023 14:55:37 -0400 Subject: [PATCH 1857/7721] drm/amd/display: update dcn315 lpddr pstate latency [WHY/HOW] Increase the pstate latency to improve ac/dc transition Reviewed-by: Charlene Liu Acked-by: Tom Chung Signed-off-by: Dmytro Laktyushkin Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c index b2c4f97afc8b..8776055bbeaa 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c @@ -334,7 +334,7 @@ static struct wm_table lpddr5_wm_table = { { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -342,7 +342,7 @@ static struct wm_table lpddr5_wm_table = { { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -350,7 +350,7 @@ static struct wm_table lpddr5_wm_table = { { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -358,7 +358,7 @@ static struct wm_table lpddr5_wm_table = { { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, From bcdbd6f607bacb51743ac73f13f40d015cb9de53 Mon Sep 17 00:00:00 2001 From: RutingZhang Date: Tue, 21 Nov 2023 12:36:20 +0800 Subject: [PATCH 1858/7721] drm/amd/display: remove unnecessary braces to fix coding style checkpatch complains that: WARNING: braces {} are not necessary for single statement blocks + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } Fixed it by removing unnecessary braces to fix the coding style issue. Signed-off-by: RutingZhang Reviewed-by: Dongliang Mu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index c07da45e1e2c..65d337731f56 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -713,9 +713,8 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) pool->base.hubps[i] = NULL; } - if (pool->base.irqs != NULL) { + if (pool->base.irqs != NULL) dal_irq_service_destroy(&pool->base.irqs); - } } for (i = 0; i < pool->base.res_cap->num_ddc; i++) { From ca0b006939f9701ab2e14a08ed9ef77a8014d2c5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 10 Nov 2023 09:39:18 -0500 Subject: [PATCH 1859/7721] drm/amdgpu: fix AGP addressing when GART is not at 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This worked by luck if the GART aperture ended up at 0. When we ended up moving GART on some chips, the GART aperture ended up offsetting the AGP address since the resource->start is a GART offset, not an MC address. Fix this by moving the AGP address setup into amdgpu_bo_gpu_offset_no_check(). v2: check mem_type before checking agp v3: check if the ttm bo has a ttm_tt allocated yet Fixes: 67318cb84341 ("drm/amdgpu/gmc11: set gart placement GC11") Tested-by: Mario Limonciello Reported-by: Jesse Zhang Reported-by: Yifan Zhang Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: christian.koenig@amd.com Cc: mario.limonciello@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 10 +++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 4 +--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 5f71414190e9..d2f273d77e59 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -181,6 +181,9 @@ uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); + if (!bo->ttm) + return AMDGPU_BO_INVALID_OFFSET; + if (bo->ttm->num_pages != 1 || bo->ttm->caching == ttm_cached) return AMDGPU_BO_INVALID_OFFSET; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index cef920a93924..d79b4ca1ecfc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -1527,10 +1527,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - uint64_t offset; + uint64_t offset = AMDGPU_BO_INVALID_OFFSET; - offset = (bo->tbo.resource->start << PAGE_SHIFT) + - amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type); + if (bo->tbo.resource->mem_type == TTM_PL_TT) + offset = amdgpu_gmc_agp_addr(&bo->tbo); + + if (offset == AMDGPU_BO_INVALID_OFFSET) + offset = (bo->tbo.resource->start << PAGE_SHIFT) + + amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type); return amdgpu_gmc_sign_extend(offset); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 05991c5c8ddb..ab4a762aed5b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -959,10 +959,8 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) return 0; addr = amdgpu_gmc_agp_addr(bo); - if (addr != AMDGPU_BO_INVALID_OFFSET) { - bo->resource->start = addr >> PAGE_SHIFT; + if (addr != AMDGPU_BO_INVALID_OFFSET) return 0; - } /* allocate GART space */ placement.num_placement = 1; From b0e5c88d8a88bdcc9834409387e10a5ae1b2753e Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Thu, 23 Nov 2023 15:33:22 +0800 Subject: [PATCH 1860/7721] drm/amd/pm: fix a memleak in aldebaran_tables_init When kzalloc() for smu_table->ecc_table fails, we should free the previously allocated resources to prevent memleak. Fixes: edd794208555 ("drm/amd/pm: add message smu to get ecc_table v2") Signed-off-by: Dinghao Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 1a6675d70a4b..f1440869d1ce 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -257,8 +257,11 @@ static int aldebaran_tables_init(struct smu_context *smu) } smu_table->ecc_table = kzalloc(tables[SMU_TABLE_ECCINFO].size, GFP_KERNEL); - if (!smu_table->ecc_table) + if (!smu_table->ecc_table) { + kfree(smu_table->metrics_table); + kfree(smu_table->gpu_metrics_table); return -ENOMEM; + } return 0; } From 7b194fdccb8458779687063e582cf218a0920c29 Mon Sep 17 00:00:00 2001 From: Lu Yao Date: Thu, 23 Nov 2023 09:22:34 +0800 Subject: [PATCH 1861/7721] drm/amdgpu: Fix cat debugfs amdgpu_regs_didt causes kernel null pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For 'AMDGPU_FAMILY_SI' family cards, in 'si_common_early_init' func, init 'didt_rreg' and 'didt_wreg' to 'NULL'. But in func 'amdgpu_debugfs_regs_didt_read/write', using 'RREG32_DIDT' 'WREG32_DIDT' lacks of relevant judgment. And other 'amdgpu_ip_block_version' that use these two definitions won't be added for 'AMDGPU_FAMILY_SI'. So, add null pointer judgment before calling. Reviewed-by: Christian König Signed-off-by: Lu Yao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index a53f436fa9f1..0e61ebdb3f3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -638,6 +638,9 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; + if (!adev->didt_rreg) + return -EOPNOTSUPP; + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); @@ -694,6 +697,9 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user if (size & 0x3 || *pos & 0x3) return -EINVAL; + if (!adev->didt_wreg) + return -EOPNOTSUPP; + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); From bd1f6a31e7762ebc99b97f3eda5e5ea3708fa792 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 24 Nov 2023 09:56:32 -0600 Subject: [PATCH 1862/7721] drm/amd: Enable PCIe PME from D3 When dGPU is put into BOCO it may be in D3cold but still able send PME on display hotplug event. For this to work it must be enabled as wake source from D3. When runpm is enabled use pci_wake_from_d3() to mark wakeup as enabled by default. Cc: stable@vger.kernel.org # 6.1+ Signed-off-by: Mario Limonciello Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8f24cabe2155..8b33b130ea36 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2263,6 +2263,8 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); + pci_wake_from_d3(pdev, TRUE); + /* * For runpm implemented via BACO, PMFW will handle the * timing for BACO in and out: From 2e583200907cc43f062321bf751fe4b0960dbecf Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Mon, 13 Nov 2023 13:12:44 -0500 Subject: [PATCH 1863/7721] drm/amd/display: block dcn315 dynamic crb allocation when unintended [WHY/HOW] Limit the dynamic crb to dual stream configs that include eDP Reviewed-by: Charlene Liu Acked-by: Tom Chung Signed-off-by: Dmytro Laktyushkin Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/resource/dcn315/dcn315_resource.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index cb8024eee8e4..515ba435f759 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -1631,8 +1631,10 @@ static bool allow_pixel_rate_crb(struct dc *dc, struct dc_state *context) int i; struct resource_context *res_ctx = &context->res_ctx; - /*Don't apply for single stream*/ - if (context->stream_count < 2) + /* Only apply for dual stream scenarios with edp*/ + if (context->stream_count != 2) + return false; + if (context->streams[0]->signal != SIGNAL_TYPE_EDP && context->streams[1]->signal != SIGNAL_TYPE_EDP) return false; for (i = 0; i < dc->res_pool->pipe_count; i++) { From 4fc26c2f912b5d9232dc4432fb1b7bfd6f016be6 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Fri, 13 Oct 2023 12:13:28 -0400 Subject: [PATCH 1864/7721] drm/amd/display: Update Fixed VS/PE Retimer Sequence [WHY/HOW] Add a new AUX sequence provided by vendor to improve interop with specific display configurations. Reviewed-by: Wenjing Liu Acked-by: Tom Chung Signed-off-by: Michael Strauss Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../protocols/link_dp_training_fixed_vs_pe_retimer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index 68096d12f52f..7087cdc9e977 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -205,6 +205,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; + const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87}; enum link_training_result status = LINK_TRAINING_SUCCESS; uint8_t lane = 0; union down_spread_ctrl downspread = {0}; @@ -293,6 +294,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); + link_configure_fixed_vs_pe_retimer(link->ddc, + &vendor_lttpr_write_data_dpmf[0], + sizeof(vendor_lttpr_write_data_dpmf)); + if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { link_configure_fixed_vs_pe_retimer(link->ddc, &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); @@ -552,6 +557,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; + const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87}; enum link_training_result status = LINK_TRAINING_SUCCESS; uint8_t lane = 0; union down_spread_ctrl downspread = {0}; @@ -639,6 +645,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); + link_configure_fixed_vs_pe_retimer(link->ddc, + &vendor_lttpr_write_data_dpmf[0], + sizeof(vendor_lttpr_write_data_dpmf)); + if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { link_configure_fixed_vs_pe_retimer(link->ddc, &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); From 9a1c1339abf972477aeef4ea037e650f49c5892d Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Fri, 27 Oct 2023 18:21:55 -0400 Subject: [PATCH 1865/7721] drm/amdkfd: Run restore_workers on freezable WQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make restore workers freezable so we don't have to explicitly flush them in suspend and GPU reset code paths, and we don't accidentally try to restore BOs while the GPU is suspended. Not having to flush restore_work also helps avoid lock/fence dependencies in the GPU reset case where we're not allowed to wait for fences. A side effect of this is, that we can now have multiple concurrent threads trying to signal the same eviction fence. Rework eviction fence signaling and replacement to account for that. The GPU reset path can no longer rely on restore_process_worker to resume queues because evict/restore workers can run independently of it. Instead call a new restore_process_helper directly. This is an RFC and request for testing. v2: - Reworked eviction fence signaling - Introduced restore_process_helper v3: - Handle unsignaled eviction fences in restore_process_bos Signed-off-by: Felix Kuehling Acked-by: Christian König Tested-by: Emily Deng Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 68 +++++++++++---- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 87 +++++++++++-------- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 4 +- 3 files changed, 104 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index b98c0969d3be..73288f9ccaf8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1384,7 +1384,6 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, amdgpu_amdkfd_restore_userptr_worker); *process_info = info; - *ef = dma_fence_get(&info->eviction_fence->base); } vm->process_info = *process_info; @@ -1415,6 +1414,8 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, list_add_tail(&vm->vm_list_node, &(vm->process_info->vm_list_head)); vm->process_info->n_vms++; + + *ef = dma_fence_get(&vm->process_info->eviction_fence->base); mutex_unlock(&vm->process_info->lock); return 0; @@ -1426,10 +1427,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, reserve_pd_fail: vm->process_info = NULL; if (info) { - /* Two fence references: one in info and one in *ef */ dma_fence_put(&info->eviction_fence->base); - dma_fence_put(*ef); - *ef = NULL; *process_info = NULL; put_pid(info->pid); create_evict_fence_fail: @@ -1623,7 +1621,8 @@ int amdgpu_amdkfd_criu_resume(void *p) goto out_unlock; } WRITE_ONCE(pinfo->block_mmu_notifications, false); - schedule_delayed_work(&pinfo->restore_userptr_work, 0); + queue_delayed_work(system_freezable_wq, + &pinfo->restore_userptr_work, 0); out_unlock: mutex_unlock(&pinfo->lock); @@ -2426,7 +2425,8 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, KFD_QUEUE_EVICTION_TRIGGER_USERPTR); if (r) pr_err("Failed to quiesce KFD\n"); - schedule_delayed_work(&process_info->restore_userptr_work, + queue_delayed_work(system_freezable_wq, + &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); } mutex_unlock(&process_info->notifier_lock); @@ -2749,7 +2749,8 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) /* If validation failed, reschedule another attempt */ if (evicted_bos) { - schedule_delayed_work(&process_info->restore_userptr_work, + queue_delayed_work(system_freezable_wq, + &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); kfd_smi_event_queue_restore_rescheduled(mm); @@ -2758,6 +2759,23 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) put_task_struct(usertask); } +static void replace_eviction_fence(struct dma_fence **ef, + struct dma_fence *new_ef) +{ + struct dma_fence *old_ef = rcu_replace_pointer(*ef, new_ef, true + /* protected by process_info->lock */); + + /* If we're replacing an unsignaled eviction fence, that fence will + * never be signaled, and if anyone is still waiting on that fence, + * they will hang forever. This should never happen. We should only + * replace the fence in restore_work that only gets scheduled after + * eviction work signaled the fence. + */ + WARN_ONCE(!dma_fence_is_signaled(old_ef), + "Replacing unsignaled eviction fence"); + dma_fence_put(old_ef); +} + /** amdgpu_amdkfd_gpuvm_restore_process_bos - Restore all BOs for the given * KFD process identified by process_info * @@ -2781,7 +2799,6 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) struct amdkfd_process_info *process_info = info; struct amdgpu_vm *peer_vm; struct kgd_mem *mem; - struct amdgpu_amdkfd_fence *new_fence; struct list_head duplicate_save; struct amdgpu_sync sync_obj; unsigned long failed_size = 0; @@ -2907,22 +2924,35 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) /* Wait for validate and PT updates to finish */ amdgpu_sync_wait(&sync_obj, false); - /* Release old eviction fence and create new one, because fence only - * goes from unsignaled to signaled, fence cannot be reused. - * Use context and mm from the old fence. + /* The old eviction fence may be unsignaled if restore happens + * after a GPU reset or suspend/resume. Keep the old fence in that + * case. Otherwise release the old eviction fence and create new + * one, because fence only goes from unsignaled to signaled once + * and cannot be reused. Use context and mm from the old fence. + * + * If an old eviction fence signals after this check, that's OK. + * Anyone signaling an eviction fence must stop the queues first + * and schedule another restore worker. */ - new_fence = amdgpu_amdkfd_fence_create( + if (dma_fence_is_signaled(&process_info->eviction_fence->base)) { + struct amdgpu_amdkfd_fence *new_fence = + amdgpu_amdkfd_fence_create( process_info->eviction_fence->base.context, process_info->eviction_fence->mm, NULL); - if (!new_fence) { - pr_err("Failed to create eviction fence\n"); - ret = -ENOMEM; - goto validate_map_fail; + + if (!new_fence) { + pr_err("Failed to create eviction fence\n"); + ret = -ENOMEM; + goto validate_map_fail; + } + dma_fence_put(&process_info->eviction_fence->base); + process_info->eviction_fence = new_fence; + replace_eviction_fence(ef, dma_fence_get(&new_fence->base)); + } else { + WARN_ONCE(*ef != &process_info->eviction_fence->base, + "KFD eviction fence doesn't match KGD process_info"); } - dma_fence_put(&process_info->eviction_fence->base); - process_info->eviction_fence = new_fence; - *ef = dma_fence_get(&new_fence->base); /* Attach new eviction fence to all BOs except pinned ones */ list_for_each_entry(mem, &process_info->kfd_bo_list, validate_list) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index c10d050e1a61..71df51fcc1b0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -664,7 +664,8 @@ int kfd_process_create_wq(void) if (!kfd_process_wq) kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0); if (!kfd_restore_wq) - kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", 0); + kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", + WQ_FREEZABLE); if (!kfd_process_wq || !kfd_restore_wq) { kfd_process_destroy_wq(); @@ -1642,6 +1643,7 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, struct amdgpu_fpriv *drv_priv; struct amdgpu_vm *avm; struct kfd_process *p; + struct dma_fence *ef; struct kfd_node *dev; int ret; @@ -1661,11 +1663,12 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, avm, &p->kgd_process_info, - &p->ef); + &ef); if (ret) { pr_err("Failed to create process VM object\n"); return ret; } + RCU_INIT_POINTER(p->ef, ef); pdd->drm_priv = drm_file->private_data; ret = kfd_process_device_reserve_ib_mem(pdd); @@ -1908,6 +1911,21 @@ kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node, return -EINVAL; } +static int signal_eviction_fence(struct kfd_process *p) +{ + struct dma_fence *ef; + int ret; + + rcu_read_lock(); + ef = dma_fence_get_rcu_safe(&p->ef); + rcu_read_unlock(); + + ret = dma_fence_signal(ef); + dma_fence_put(ef); + + return ret; +} + static void evict_process_worker(struct work_struct *work) { int ret; @@ -1920,31 +1938,46 @@ static void evict_process_worker(struct work_struct *work) * lifetime of this thread, kfd_process p will be valid */ p = container_of(dwork, struct kfd_process, eviction_work); - WARN_ONCE(p->last_eviction_seqno != p->ef->seqno, - "Eviction fence mismatch\n"); - - /* Narrow window of overlap between restore and evict work - * item is possible. Once amdgpu_amdkfd_gpuvm_restore_process_bos - * unreserves KFD BOs, it is possible to evicted again. But - * restore has few more steps of finish. So lets wait for any - * previous restore work to complete - */ - flush_delayed_work(&p->restore_work); pr_debug("Started evicting pasid 0x%x\n", p->pasid); ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_TTM); if (!ret) { - dma_fence_signal(p->ef); - dma_fence_put(p->ef); - p->ef = NULL; - queue_delayed_work(kfd_restore_wq, &p->restore_work, + /* If another thread already signaled the eviction fence, + * they are responsible stopping the queues and scheduling + * the restore work. + */ + if (!signal_eviction_fence(p)) + queue_delayed_work(kfd_restore_wq, &p->restore_work, msecs_to_jiffies(PROCESS_RESTORE_TIME_MS)); + else + kfd_process_restore_queues(p); pr_debug("Finished evicting pasid 0x%x\n", p->pasid); } else pr_err("Failed to evict queues of pasid 0x%x\n", p->pasid); } +static int restore_process_helper(struct kfd_process *p) +{ + int ret = 0; + + /* VMs may not have been acquired yet during debugging. */ + if (p->kgd_process_info) { + ret = amdgpu_amdkfd_gpuvm_restore_process_bos( + p->kgd_process_info, &p->ef); + if (ret) + return ret; + } + + ret = kfd_process_restore_queues(p); + if (!ret) + pr_debug("Finished restoring pasid 0x%x\n", p->pasid); + else + pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid); + + return ret; +} + static void restore_process_worker(struct work_struct *work) { struct delayed_work *dwork; @@ -1970,24 +2003,15 @@ static void restore_process_worker(struct work_struct *work) */ p->last_restore_timestamp = get_jiffies_64(); - /* VMs may not have been acquired yet during debugging. */ - if (p->kgd_process_info) - ret = amdgpu_amdkfd_gpuvm_restore_process_bos(p->kgd_process_info, - &p->ef); + + ret = restore_process_helper(p); if (ret) { pr_debug("Failed to restore BOs of pasid 0x%x, retry after %d ms\n", p->pasid, PROCESS_BACK_OFF_TIME_MS); ret = queue_delayed_work(kfd_restore_wq, &p->restore_work, msecs_to_jiffies(PROCESS_BACK_OFF_TIME_MS)); WARN(!ret, "reschedule restore work failed\n"); - return; } - - ret = kfd_process_restore_queues(p); - if (!ret) - pr_debug("Finished restoring pasid 0x%x\n", p->pasid); - else - pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid); } void kfd_suspend_all_processes(void) @@ -1998,14 +2022,9 @@ void kfd_suspend_all_processes(void) WARN(debug_evictions, "Evicting all processes"); hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - cancel_delayed_work_sync(&p->eviction_work); - flush_delayed_work(&p->restore_work); - if (kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_SUSPEND)) pr_err("Failed to suspend process 0x%x\n", p->pasid); - dma_fence_signal(p->ef); - dma_fence_put(p->ef); - p->ef = NULL; + signal_eviction_fence(p); } srcu_read_unlock(&kfd_processes_srcu, idx); } @@ -2017,7 +2036,7 @@ int kfd_resume_all_processes(void) int ret = 0, idx = srcu_read_lock(&kfd_processes_srcu); hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - if (!queue_delayed_work(kfd_restore_wq, &p->restore_work, 0)) { + if (restore_process_helper(p)) { pr_err("Restore process %d failed during resume\n", p->pasid); ret = -EFAULT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index f2f3c338fd94..613f19510287 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1870,7 +1870,7 @@ static void svm_range_restore_work(struct work_struct *work) /* If validation failed, reschedule another attempt */ if (evicted_ranges) { pr_debug("reschedule to restore svm range\n"); - schedule_delayed_work(&svms->restore_work, + queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); kfd_smi_event_queue_restore_rescheduled(mm); @@ -1946,7 +1946,7 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm, pr_debug("failed to quiesce KFD\n"); pr_debug("schedule to restore svm %p ranges\n", svms); - schedule_delayed_work(&svms->restore_work, + queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); } else { unsigned long s, l; From 1919fd6bb09f61015549b9e5a5af1541b41f45d9 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 18 Nov 2023 14:39:40 -0500 Subject: [PATCH 1866/7721] drm/amd/display: [FW Promotion] Release 0.0.194.0 - Add a new dmub command in enum dmub_cmd_cab_type Reviewed-by: Tom Chung Acked-by: Tom Chung Signed-off-by: Anthony Koo Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index b7d9360bfdc8..a365f6c096de 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -1345,6 +1345,10 @@ enum dmub_cmd_cab_type { * Fit surfaces in CAB (i.e. CAB enable) */ DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB = 2, + /** + * Do not fit surfaces in CAB (i.e. no CAB) + */ + DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB = 3, }; /** From 061a5bf210cd7b941627092309ff6035a017cda3 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 14 Nov 2023 11:22:09 -0500 Subject: [PATCH 1867/7721] drm/amd/display: Allow DTBCLK disable for DCN35 [Why] DTBCLK is enabled on idle and it will burn power. [How] There's a few issues here: - Always enabling DTBCLK on clock manager init - Setting refclk when DTBCLK is supposed to be disabled - Not applying the correct calculated version refclk, but instead the base value which might be zero On dtbclk_en change we'll message PMFW to enable or disable the clock accordingly. The DTBDTO will be then based on refclk, but it will be set to the default fixed value if there was nothing calculated in DML despite the clock being considered enabled. Reviewed-by: Charlene Liu Acked-by: Tom Chung Signed-off-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 63a0b885b6f0..d5fde7d23fbf 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -232,6 +232,10 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, if (dc->work_arounds.skip_clock_update) return; + /* DTBCLK is fixed, so set a default if unspecified. */ + if (new_clocks->dtbclk_en && !new_clocks->ref_dtbclk_khz) + new_clocks->ref_dtbclk_khz = 600000; + /* * if it is safe to lower, but we are already in the lower state, we don't have to do anything * also if safe to lower is false, we just go in the higher state @@ -265,8 +269,10 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { dcn35_smu_set_dtbclk(clk_mgr, true); - dcn35_update_clocks_update_dtb_dto(clk_mgr, context, clk_mgr_base->clks.ref_dtbclk_khz); clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; + + dcn35_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); + clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; } /* check that we're not already in D0 */ @@ -314,17 +320,12 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, update_dispclk = true; } - if (!new_clocks->dtbclk_en) { - new_clocks->ref_dtbclk_khz = 600000; - } - /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ if (!dc->debug.disable_dtb_ref_clk_switch && - should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000)) { - /* DCCG requires KHz precision for DTBCLK */ - dcn35_smu_set_dtbclk(clk_mgr, true); - - dcn35_update_clocks_update_dtb_dto(clk_mgr, context, clk_mgr_base->clks.ref_dtbclk_khz); + should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, + clk_mgr_base->clks.ref_dtbclk_khz / 1000)) { + dcn35_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); + clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; } if (dpp_clock_lowered) { @@ -1048,12 +1049,8 @@ void dcn35_clk_mgr_construct( dcn35_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info); clk_mgr->base.base.dprefclk_khz = dcn35_smu_get_dprefclk(&clk_mgr->base); - clk_mgr->base.base.clks.ref_dtbclk_khz = dcn35_smu_get_dtbclk(&clk_mgr->base); + clk_mgr->base.base.clks.ref_dtbclk_khz = 600000; - if (!clk_mgr->base.base.clks.ref_dtbclk_khz) - dcn35_smu_set_dtbclk(&clk_mgr->base, true); - - clk_mgr->base.base.clks.dtbclk_en = true; dce_clock_read_ss_info(&clk_mgr->base); /*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/ From ca0ad76089a8171d7a075e50b7beecf092f8fd0c Mon Sep 17 00:00:00 2001 From: Candice Li Date: Fri, 24 Nov 2023 09:33:47 +0800 Subject: [PATCH 1868/7721] drm/amdgpu: Update EEPROM I2C address for smu v13_0_0 Check smu v13_0_0 SKU type to select EEPROM I2C address. Signed-off-by: Candice Li Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 65aa218380be..2fde93b00cab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -214,6 +214,12 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, control->i2c_address = EEPROM_I2C_MADDR_0; return true; case IP_VERSION(13, 0, 0): + if (strnstr(atom_ctx->vbios_pn, "D707", + sizeof(atom_ctx->vbios_pn))) + control->i2c_address = EEPROM_I2C_MADDR_0; + else + control->i2c_address = EEPROM_I2C_MADDR_4; + return true; case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 10): control->i2c_address = EEPROM_I2C_MADDR_4; From d581ceab26a1be9fe94befe2604cbe99eadf1acc Mon Sep 17 00:00:00 2001 From: ZhenGuo Yin Date: Mon, 6 Nov 2023 18:07:51 +0800 Subject: [PATCH 1869/7721] drm/amdkfd: Free gang_ctx_bo and wptr_bo in pqm_uninit [Why] Memory leaks of gang_ctx_bo and wptr_bo. [How] Free gang_ctx_bo and wptr_bo in pqm_uninit. v2: add a common function pqm_clean_queue_resource to free queue's resources. v3: reset pdd->pqd.num_gws when destorying GWS queue. Reviewed-by: Felix Kuehling Signed-off-by: ZhenGuo Yin Signed-off-by: Alex Deucher --- .../amd/amdkfd/kfd_process_queue_manager.c | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 77649392e233..77f493262e05 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -169,16 +169,43 @@ int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p) return 0; } +static void pqm_clean_queue_resource(struct process_queue_manager *pqm, + struct process_queue_node *pqn) +{ + struct kfd_node *dev; + struct kfd_process_device *pdd; + + dev = pqn->q->device; + + pdd = kfd_get_process_device_data(dev, pqm->process); + if (!pdd) { + pr_err("Process device data doesn't exist\n"); + return; + } + + if (pqn->q->gws) { + if (KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && + !dev->kfd->shared_resources.enable_mes) + amdgpu_amdkfd_remove_gws_from_process( + pqm->process->kgd_process_info, pqn->q->gws); + pdd->qpd.num_gws = 0; + } + + if (dev->kfd->shared_resources.enable_mes) { + amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->gang_ctx_bo); + if (pqn->q->wptr_bo) + amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo); + } +} + void pqm_uninit(struct process_queue_manager *pqm) { struct process_queue_node *pqn, *next; list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) { - if (pqn->q && pqn->q->gws && - KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && - !pqn->q->device->kfd->shared_resources.enable_mes) - amdgpu_amdkfd_remove_gws_from_process(pqm->process->kgd_process_info, - pqn->q->gws); + if (pqn->q) + pqm_clean_queue_resource(pqm, pqn); + kfd_procfs_del_queue(pqn->q); uninit_queue(pqn->q); list_del(&pqn->process_queue_list); @@ -461,22 +488,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) goto err_destroy_queue; } - if (pqn->q->gws) { - if (KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && - !dev->kfd->shared_resources.enable_mes) - amdgpu_amdkfd_remove_gws_from_process( - pqm->process->kgd_process_info, - pqn->q->gws); - pdd->qpd.num_gws = 0; - } - - if (dev->kfd->shared_resources.enable_mes) { - amdgpu_amdkfd_free_gtt_mem(dev->adev, - pqn->q->gang_ctx_bo); - if (pqn->q->wptr_bo) - amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo); - - } + pqm_clean_queue_resource(pqm, pqn); uninit_queue(pqn->q); } From 5290ed0a8b261115fe4965a6d95a642b0742d159 Mon Sep 17 00:00:00 2001 From: Ilya Bakoulin Date: Thu, 16 Nov 2023 15:28:53 -0500 Subject: [PATCH 1870/7721] drm/amd/display: Add DSC granular throughput adjustment [Why/How] Update DSC DPCD parsing to take granular throughput adjustment into consideration. Reviewed-by: Wenjing Liu Acked-by: Tom Chung Signed-off-by: Ilya Bakoulin Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index e8b5f17beb96..0df6c55eb326 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -331,8 +331,9 @@ bool dc_dsc_parse_dsc_dpcd(const struct dc *dc, int buff_block_size; int buff_size; - if (!dsc_buff_block_size_from_dpcd(dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT], - &buff_block_size)) + if (!dsc_buff_block_size_from_dpcd( + dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT] & 0x03, + &buff_block_size)) return false; buff_size = dpcd_dsc_basic_data[DP_DSC_RC_BUF_SIZE - DP_DSC_SUPPORT] + 1; @@ -357,10 +358,15 @@ bool dc_dsc_parse_dsc_dpcd(const struct dc *dc, { int dpcd_throughput = dpcd_dsc_basic_data[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT]; + int dsc_throughput_granular_delta; + + dsc_throughput_granular_delta = dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT] >> 3; + dsc_throughput_granular_delta *= 2; if (!dsc_throughput_from_dpcd(dpcd_throughput & DP_DSC_THROUGHPUT_MODE_0_MASK, &dsc_sink_caps->throughput_mode_0_mps)) return false; + dsc_sink_caps->throughput_mode_0_mps += dsc_throughput_granular_delta; dpcd_throughput = (dpcd_throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> DP_DSC_THROUGHPUT_MODE_1_SHIFT; if (!dsc_throughput_from_dpcd(dpcd_throughput, &dsc_sink_caps->throughput_mode_1_mps)) From 33a6e409165cd23d1dc580031cb749550ca18517 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 10 Nov 2023 10:24:20 -0500 Subject: [PATCH 1871/7721] drm/amd/display: Fix some HostVM parameters in DML [Why] A number of DML parameters related to HostVM were either missing or being set incorrectly, which may cause inaccuracies in calculating margins and determining BW limitations. [How] Correct these values where needed and populate the missing values. Cc: stable@vger.kernel.org Reviewed-by: Nicholas Kazlauskas Acked-by: Hamza Mahfooz Signed-off-by: Taimur Hassan Signed-off-by: Roman Li Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 33 +++++++++++++++++++ .../display/dc/dml2/dml2_translation_helper.c | 9 +++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index 21c17d3296a3..39cf1ae3a3e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -330,6 +330,39 @@ void dcn35_update_bw_bounding_box_fpu(struct dc *dc, dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); + /*copy to dml2, before dml2_create*/ + if (clk_table->num_entries > 2) { + + for (i = 0; i < clk_table->num_entries; i++) { + dc->dml2_options.bbox_overrides.clks_table.num_states = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz = + clock_limits[i].dcfclk_mhz; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].fclk_mhz = + clock_limits[i].fabricclk_mhz; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dispclk_mhz = + clock_limits[i].dispclk_mhz; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dppclk_mhz = + clock_limits[i].dppclk_mhz; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].socclk_mhz = + clock_limits[i].socclk_mhz; + dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].memclk_mhz = + clk_table->entries[i].memclk_mhz * clk_table->entries[i].wck_ratio; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_fclk_levels = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_dispclk_levels = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_dppclk_levels = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_socclk_levels = + clk_table->num_entries; + dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_memclk_levels = + clk_table->num_entries; + } + } + /* Update latency values */ dc->dml2_options.bbox_overrides.dram_clock_change_latency_us = dcn3_5_soc.dram_clock_change_latency_us; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index 48caa34a5ce7..fa8fe5bf7e57 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -1057,9 +1057,12 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat } //Generally these are set by referencing our latest BB/IP params in dcn32_resource.c file - dml_dispcfg->plane.GPUVMEnable = true; - dml_dispcfg->plane.GPUVMMaxPageTableLevels = 4; - dml_dispcfg->plane.HostVMEnable = false; + dml_dispcfg->plane.GPUVMEnable = dml2->v20.dml_core_ctx.ip.gpuvm_enable; + dml_dispcfg->plane.GPUVMMaxPageTableLevels = dml2->v20.dml_core_ctx.ip.gpuvm_max_page_table_levels; + dml_dispcfg->plane.HostVMEnable = dml2->v20.dml_core_ctx.ip.hostvm_enable; + dml_dispcfg->plane.HostVMMaxPageTableLevels = dml2->v20.dml_core_ctx.ip.hostvm_max_page_table_levels; + if (dml2->v20.dml_core_ctx.ip.hostvm_enable) + dml2->v20.dml_core_ctx.policy.AllowForPStateChangeOrStutterInVBlankFinal = dml_prefetch_support_uclk_fclk_and_stutter; dml2_populate_pipe_to_plane_index_mapping(dml2, context); From 70378005378a23fbfe0d4c44dac4187cad07da94 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Sun, 19 Nov 2023 23:02:26 -0500 Subject: [PATCH 1872/7721] drm/amd/display: Promote DAL to 3.2.262 This version brings along following fixes: - Add DSC granular throughput adjustment - Allow DTBCLK disable for DCN35 - Update Fixed VS/PE Retimer Sequence - Block dcn315 dynamic crb allocation when unintended - Update dcn315 lpddr pstate latency - Fix some HostVM parameters in DML Reviewed-by: Tom Chung Acked-by: Tom Chung Signed-off-by: Aric Cyr Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6074ac1b180a..e8c1599ab18a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -49,7 +49,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.261" +#define DC_VER "3.2.262" #define MAX_SURFACES 3 #define MAX_PLANES 6 From 9a5095e785c38ab8d9f3d91f4ee76f4f73ec4adc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 13 Sep 2023 12:00:44 -0400 Subject: [PATCH 1873/7721] drm/amdgpu: add amdgpu_reg_state.h This header defines the reg state structures exposed via sysfs for umr debugging. v2: add content type Signed-off-by: Alex Deucher Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 + .../gpu/drm/amd/include/amdgpu_reg_state.h | 140 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 drivers/gpu/drm/amd/include/amdgpu_reg_state.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index ea2656bd714f..0af8ac81facd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -110,6 +110,7 @@ #include "amdgpu_ras.h" #include "amdgpu_xcp.h" #include "amdgpu_seq64.h" +#include "amdgpu_reg_state.h" #define MAX_GPU_INSTANCE 64 @@ -612,6 +613,10 @@ struct amdgpu_asic_funcs { const struct amdgpu_video_codecs **codecs); /* encode "> 32bits" smn addressing */ u64 (*encode_ext_smn_addressing)(int ext_id); + + ssize_t (*get_reg_state)(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size); }; /* diff --git a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h new file mode 100644 index 000000000000..3dbdb118db59 --- /dev/null +++ b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __AMDGPU_REG_STATE_H__ +#define __AMDGPU_REG_STATE_H__ + +enum amdgpu_reg_state { + AMDGPU_REG_STATE_TYPE_INVALID = 0, + AMDGPU_REG_STATE_TYPE_XGMI = 1, + AMDGPU_REG_STATE_TYPE_WAFL = 2, + AMDGPU_REG_STATE_TYPE_PCIE = 3, + AMDGPU_REG_STATE_TYPE_USR = 4, + AMDGPU_REG_STATE_TYPE_USR_1 = 5 +}; + +struct amdgpu_reg_state_header { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; + uint8_t state_type; + uint8_t num_instances; + uint16_t pad; +}; + +enum amdgpu_reg_inst_state { + AMDGPU_INST_S_OK, + AMDGPU_INST_S_EDISABLED, + AMDGPU_INST_S_EACCESS, +}; + +struct amdgpu_smn_reg_data { + uint64_t addr; + uint32_t value; + uint32_t pad; +}; + +struct amdgpu_reg_inst_header { + uint16_t instance; + uint16_t state; + uint16_t num_smn_regs; + uint16_t pad; +}; + + +struct amdgpu_regs_xgmi_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_xgmi_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_XGMI */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_xgmi_v1_0 xgmi_state_regs[]; +}; + +struct amdgpu_regs_wafl_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_wafl_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_WAFL */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_wafl_v1_0 wafl_state_regs[]; +}; + +struct amdgpu_regs_pcie_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + uint16_t device_status; + uint16_t link_status; + uint32_t sub_bus_number_latency; + uint32_t pcie_corr_err_status; + uint32_t pcie_uncorr_err_status; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_pcie_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_PCIE */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_pcie_v1_0 pci_state_regs[]; +}; + +struct amdgpu_regs_usr_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_usr_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_USR */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_usr_v1_0 usr_state_regs[]; +}; + +static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size, + uint16_t num_regs) +{ + return num_inst * + (inst_size + num_regs * sizeof(struct amdgpu_smn_reg_data)); +} + +#define amdgpu_asic_get_reg_state_supported(adev) \ + ((adev)->asic_funcs->get_reg_state ? 1 : 0) + +#define amdgpu_asic_get_reg_state(adev, state, buf, size) \ + ((adev)->asic_funcs->get_reg_state ? \ + (adev)->asic_funcs->get_reg_state((adev), (state), (buf), \ + (size)) : \ + 0) + +#endif From af39e6f4d8032b101907cc2ac12a21a778da568d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 6 Oct 2023 13:49:03 +0530 Subject: [PATCH 1874/7721] drm/amdgpu: Add reg_state sysfs attribute Add reg_state attribute to fetch the register snapshot of different IPs like XGMI, WAFL,PCIE and USR. To get a snapshot for a particular IP 1) Open the sysfs file 2) Seek to the offset as defined in amdgpu_sysfs_reg_offset 3) Read Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 62 +++++++++++++++++++ .../gpu/drm/amd/include/amdgpu_reg_state.h | 13 ++++ 2 files changed, 75 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 5d3a83193115..f29d0faf956e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -162,6 +162,65 @@ static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev, static DEVICE_ATTR(pcie_replay_count, 0444, amdgpu_device_get_pcie_replay_count, NULL); +static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t ppos, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t bytes_read; + + switch (ppos) { + case AMDGPU_SYS_REG_STATE_XGMI: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_XGMI, buf, count); + break; + case AMDGPU_SYS_REG_STATE_WAFL: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_WAFL, buf, count); + break; + case AMDGPU_SYS_REG_STATE_PCIE: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_PCIE, buf, count); + break; + case AMDGPU_SYS_REG_STATE_USR: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_USR, buf, count); + break; + case AMDGPU_SYS_REG_STATE_USR_1: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_USR_1, buf, count); + break; + default: + return -EINVAL; + } + + return bytes_read; +} + +BIN_ATTR(reg_state, 0444, amdgpu_sysfs_reg_state_get, NULL, + AMDGPU_SYS_REG_STATE_END); + +int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev) +{ + int ret; + + if (!amdgpu_asic_get_reg_state_supported(adev)) + return 0; + + ret = sysfs_create_bin_file(&adev->dev->kobj, &bin_attr_reg_state); + + return ret; +} + +void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev) +{ + if (!amdgpu_asic_get_reg_state_supported(adev)) + return; + sysfs_remove_bin_file(&adev->dev->kobj, &bin_attr_reg_state); +} + /** * DOC: board_info * @@ -4233,6 +4292,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, "Could not create amdgpu board attributes\n"); amdgpu_fru_sysfs_init(adev); + amdgpu_reg_state_sysfs_init(adev); if (IS_ENABLED(CONFIG_PERF_EVENTS)) r = amdgpu_pmu_init(adev); @@ -4355,6 +4415,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); amdgpu_fru_sysfs_fini(adev); + amdgpu_reg_state_sysfs_fini(adev); + /* disable ras feature must before hw fini */ amdgpu_ras_pre_fini(adev); diff --git a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h index 3dbdb118db59..be519c8edf49 100644 --- a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h +++ b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h @@ -34,6 +34,15 @@ enum amdgpu_reg_state { AMDGPU_REG_STATE_TYPE_USR_1 = 5 }; +enum amdgpu_sysfs_reg_offset { + AMDGPU_SYS_REG_STATE_XGMI = 0x0000, + AMDGPU_SYS_REG_STATE_WAFL = 0x1000, + AMDGPU_SYS_REG_STATE_PCIE = 0x2000, + AMDGPU_SYS_REG_STATE_USR = 0x3000, + AMDGPU_SYS_REG_STATE_USR_1 = 0x4000, + AMDGPU_SYS_REG_STATE_END = 0x5000, +}; + struct amdgpu_reg_state_header { uint16_t structure_size; uint8_t format_revision; @@ -137,4 +146,8 @@ static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size, (size)) : \ 0) + +int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev); +void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev); + #endif From 081a6eda2b25092e1466f09eb46d829488b75730 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 6 Oct 2023 14:20:45 +0530 Subject: [PATCH 1875/7721] drm/amdgpu: Read aquavanjaram PCIE register state Add support to read aqua vanjaram PCIE register state Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 115 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/soc15.c | 1 + drivers/gpu/drm/amd/amdgpu/soc15.h | 4 + 3 files changed, 120 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index 3f715e7fe1a9..0a4598480dd5 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -24,6 +24,7 @@ #include "soc15.h" #include "soc15_common.h" +#include "amdgpu_reg_state.h" #include "amdgpu_xcp.h" #include "gfx_v9_4_3.h" #include "gfxhub_v1_2.h" @@ -656,3 +657,117 @@ int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev) return 0; } + +static void aqua_read_smn(struct amdgpu_device *adev, + struct amdgpu_smn_reg_data *regdata, + uint64_t smn_addr) +{ + regdata->addr = smn_addr; + regdata->value = RREG32_PCIE(smn_addr); +} + +struct aqua_reg_list { + uint64_t start_addr; + uint32_t num_regs; + uint32_t incrx; +}; + +#define DW_ADDR_INCR 4 + +#define smnreg_0x1A340218 0x1A340218 +#define smnreg_0x1A3402E4 0x1A3402E4 +#define smnreg_0x1A340294 0x1A340294 +#define smreg_0x1A380088 0x1A380088 + +#define NUM_PCIE_SMN_REGS 14 + +static struct aqua_reg_list pcie_reg_addrs[] = { + { smnreg_0x1A340218, 1, 0 }, + { smnreg_0x1A3402E4, 1, 0 }, + { smnreg_0x1A340294, 6, DW_ADDR_INCR }, + { smreg_0x1A380088, 6, DW_ADDR_INCR }, +}; + +static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_pcie_v1_0 *pcie_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_pcie_v1_0 *pcie_regs; + struct amdgpu_smn_reg_data *reg_data; + struct pci_dev *us_pdev, *ds_pdev; + int aer_cap, r, n; + + if (!buf || !max_size) + return -EINVAL; + + pcie_reg_state = (struct amdgpu_reg_state_pcie_v1_0 *)buf; + + szbuf = sizeof(*pcie_reg_state) + + amdgpu_reginst_size(1, sizeof(*pcie_regs), NUM_PCIE_SMN_REGS); + /* Only one instance of pcie regs */ + if (max_size < szbuf) + return -EOVERFLOW; + + pcie_regs = (struct amdgpu_regs_pcie_v1_0 *)((uint8_t *)buf + + sizeof(*pcie_reg_state)); + pcie_regs->inst_header.instance = 0; + pcie_regs->inst_header.state = AMDGPU_INST_S_OK; + pcie_regs->inst_header.num_smn_regs = NUM_PCIE_SMN_REGS; + + reg_data = pcie_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(pcie_reg_addrs); r++) { + start_addr = pcie_reg_addrs[r].start_addr; + incrx = pcie_reg_addrs[r].incrx; + num_regs = pcie_reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn(adev, reg_data, start_addr + n * incrx); + ++reg_data; + } + } + + ds_pdev = pci_upstream_bridge(adev->pdev); + us_pdev = pci_upstream_bridge(ds_pdev); + + pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA, + &pcie_regs->device_status); + pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA, + &pcie_regs->link_status); + + aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR); + if (aer_cap) { + pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_COR_STATUS, + &pcie_regs->pcie_corr_err_status); + pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_UNCOR_STATUS, + &pcie_regs->pcie_uncorr_err_status); + } + + pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS, + &pcie_regs->sub_bus_number_latency); + + pcie_reg_state->common_header.structure_size = szbuf; + pcie_reg_state->common_header.format_revision = 1; + pcie_reg_state->common_header.content_revision = 0; + pcie_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_PCIE; + pcie_reg_state->common_header.num_instances = 1; + + return pcie_reg_state->common_header.structure_size; +} + +ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size) +{ + ssize_t size; + + switch (reg_state) { + case AMDGPU_REG_STATE_TYPE_PCIE: + size = aqua_vanjaram_read_pcie_state(adev, buf, max_size); + break; + default: + return -EINVAL; + } + + return size; +} diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index d4b8d62f4294..e3d41e8aac9d 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -902,6 +902,7 @@ static const struct amdgpu_asic_funcs aqua_vanjaram_asic_funcs = .pre_asic_init = &soc15_pre_asic_init, .query_video_codecs = &soc15_query_video_codecs, .encode_ext_smn_addressing = &aqua_vanjaram_encode_ext_smn_addressing, + .get_reg_state = &aqua_vanjaram_get_reg_state, }; static int soc15_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.h b/drivers/gpu/drm/amd/amdgpu/soc15.h index eac54042c6c0..1444b7765e4b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15.h @@ -27,6 +27,7 @@ #include "nbio_v6_1.h" #include "nbio_v7_0.h" #include "nbio_v7_4.h" +#include "amdgpu_reg_state.h" extern const struct amdgpu_ip_block_version vega10_common_ip_block; @@ -114,6 +115,9 @@ int aldebaran_reg_base_init(struct amdgpu_device *adev); void aqua_vanjaram_ip_map_init(struct amdgpu_device *adev); u64 aqua_vanjaram_encode_ext_smn_addressing(int ext_id); int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev); +ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size); void vega10_doorbell_index_init(struct amdgpu_device *adev); void vega20_doorbell_index_init(struct amdgpu_device *adev); From 92e508eaf337d465f0574dda18d805bb4df138bc Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 7 Oct 2023 15:41:27 +0530 Subject: [PATCH 1876/7721] drm/amdgpu: Read aquavanjaram XGMI register state Add support to read state of XGMI links in aquavanjaram SOC. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index 0a4598480dd5..a00b8c6f0a94 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -674,6 +674,15 @@ struct aqua_reg_list { #define DW_ADDR_INCR 4 +static void aqua_read_smn_ext(struct amdgpu_device *adev, + struct amdgpu_smn_reg_data *regdata, + uint64_t smn_addr, int i) +{ + regdata->addr = + smn_addr + adev->asic_funcs->encode_ext_smn_addressing(i); + regdata->value = RREG32_PCIE_EXT(regdata->addr); +} + #define smnreg_0x1A340218 0x1A340218 #define smnreg_0x1A3402E4 0x1A3402E4 #define smnreg_0x1A340294 0x1A340294 @@ -755,6 +764,90 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, return pcie_reg_state->common_header.structure_size; } +#define smnreg_0x11A00050 0x11A00050 +#define smnreg_0x11A00180 0x11A00180 +#define smnreg_0x11A00070 0x11A00070 +#define smnreg_0x11A00200 0x11A00200 +#define smnreg_0x11A0020C 0x11A0020C +#define smnreg_0x11A00210 0x11A00210 +#define smnreg_0x11A00108 0x11A00108 + +#define XGMI_LINK_REG(smnreg, l) ((smnreg) | (l << 20)) + +#define NUM_XGMI_SMN_REGS 25 + +static struct aqua_reg_list xgmi_reg_addrs[] = { + { smnreg_0x11A00050, 1, 0 }, + { smnreg_0x11A00180, 16, DW_ADDR_INCR }, + { smnreg_0x11A00070, 4, DW_ADDR_INCR }, + { smnreg_0x11A00200, 1, 0 }, + { smnreg_0x11A0020C, 1, 0 }, + { smnreg_0x11A00210, 1, 0 }, + { smnreg_0x11A00108, 1, 0 }, +}; + +static ssize_t aqua_vanjaram_read_xgmi_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_xgmi_v1_0 *xgmi_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_xgmi_v1_0 *xgmi_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_xgmi_instances = 8; + int inst = 0, i, j, r, n; + const int xgmi_inst = 2; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + xgmi_reg_state = (struct amdgpu_reg_state_xgmi_v1_0 *)buf; + + szbuf = sizeof(*xgmi_reg_state) + + amdgpu_reginst_size(max_xgmi_instances, sizeof(*xgmi_regs), + NUM_XGMI_SMN_REGS); + /* Only one instance of pcie regs */ + if (max_size < szbuf) + return -EOVERFLOW; + + p = &xgmi_reg_state->xgmi_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + for (j = 0; j < xgmi_inst; ++j) { + xgmi_regs = (struct amdgpu_regs_xgmi_v1_0 *)p; + xgmi_regs->inst_header.instance = inst++; + + xgmi_regs->inst_header.state = AMDGPU_INST_S_OK; + xgmi_regs->inst_header.num_smn_regs = NUM_XGMI_SMN_REGS; + + reg_data = xgmi_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(xgmi_reg_addrs); r++) { + start_addr = xgmi_reg_addrs[r].start_addr; + incrx = xgmi_reg_addrs[r].incrx; + num_regs = xgmi_reg_addrs[r].num_regs; + + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext( + adev, reg_data, + XGMI_LINK_REG(start_addr, j) + + n * incrx, + i); + ++reg_data; + } + } + p = reg_data; + } + } + + xgmi_reg_state->common_header.structure_size = szbuf; + xgmi_reg_state->common_header.format_revision = 1; + xgmi_reg_state->common_header.content_revision = 0; + xgmi_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_XGMI; + xgmi_reg_state->common_header.num_instances = max_xgmi_instances; + + return xgmi_reg_state->common_header.structure_size; +} + ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, enum amdgpu_reg_state reg_state, void *buf, size_t max_size) @@ -765,6 +858,9 @@ ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, case AMDGPU_REG_STATE_TYPE_PCIE: size = aqua_vanjaram_read_pcie_state(adev, buf, max_size); break; + case AMDGPU_REG_STATE_TYPE_XGMI: + size = aqua_vanjaram_read_xgmi_state(adev, buf, max_size); + break; default: return -EINVAL; } From 36fd9969fa53c40e8a58192714d9a3624cbe04e3 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 28 Nov 2023 16:47:14 +0530 Subject: [PATCH 1877/7721] drm/amdgpu: Use another offset for GC 9.4.3 remap The legacy region at 0x7F000 maps to valid registers in GC 9.4.3 SOCs. Use 0x1A000 offset instead as MMIO register remap region. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc15.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index e3d41e8aac9d..9ad4d6d3122b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1162,6 +1162,11 @@ static int soc15_common_early_init(void *handle) AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_JPEG; adev->external_rev_id = adev->rev_id + 0x46; + /* GC 9.4.3 uses MMIO register region hole at a different offset */ + if (!amdgpu_sriov_vf(adev)) { + adev->rmmio_remap.reg_offset = 0x1A000; + adev->rmmio_remap.bus_addr = adev->rmmio_base + 0x1A000; + } break; default: /* FIXME: not supported yet */ From 562f33836f519a235e5c5e71bcc723ab1faccd2f Mon Sep 17 00:00:00 2001 From: Clint Taylor Date: Tue, 28 Nov 2023 11:03:29 -0800 Subject: [PATCH 1878/7721] drm/i915/dgfx: DGFX uses direct VBT pin mapping DDC pin mapping for DGFX cards uses direct VBT pin mapping Cc: Lucas De Marchi Cc: Matt Roper Signed-off-by: Clint Taylor Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20231128190329.1335562-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/i915/display/intel_bios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 2fd72b2fd109..3e7e96acb24a 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2201,6 +2201,9 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int i, n_entries; + if (IS_DGFX(i915)) + return vbt_pin; + if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; @@ -2208,8 +2211,6 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) } else if (IS_ALDERLAKE_S(i915)) { ddc_pin_map = adls_ddc_pin_map; n_entries = ARRAY_SIZE(adls_ddc_pin_map); - } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { - return vbt_pin; } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) { ddc_pin_map = rkl_pch_tgp_ddc_pin_map; n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map); From 341ac980eab90ac1f6c22ee9f9da83ed9604d899 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:07 -0800 Subject: [PATCH 1879/7721] xsk: Support tx_metadata_len For zerocopy mode, tx_desc->addr can point to an arbitrary offset and carry some TX metadata in the headroom. For copy mode, there is no way currently to populate skb metadata. Introduce new tx_metadata_len umem config option that indicates how many bytes to treat as metadata. Metadata bytes come prior to tx_desc address (same as in RX case). The size of the metadata has mostly the same constraints as XDP: - less than 256 bytes - 8-byte aligned (compared to 4-byte alignment on xdp, due to 8-byte timestamp in the completion) - non-zero This data is not interpreted in any way right now. Reviewed-by: Song Yoong Siang Signed-off-by: Stanislav Fomichev Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20231127190319.1190813-2-sdf@google.com Signed-off-by: Alexei Starovoitov --- include/net/xdp_sock.h | 1 + include/net/xsk_buff_pool.h | 1 + include/uapi/linux/if_xdp.h | 1 + net/xdp/xdp_umem.c | 4 ++++ net/xdp/xsk.c | 12 +++++++++++- net/xdp/xsk_buff_pool.c | 1 + net/xdp/xsk_queue.h | 17 ++++++++++------- tools/include/uapi/linux/if_xdp.h | 1 + 8 files changed, 30 insertions(+), 8 deletions(-) diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index f83128007fb0..bcf765124f72 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -30,6 +30,7 @@ struct xdp_umem { struct user_struct *user; refcount_t users; u8 flags; + u8 tx_metadata_len; bool zc; struct page **pgs; int id; diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h index b0bdff26fc88..1985ffaf9b0c 100644 --- a/include/net/xsk_buff_pool.h +++ b/include/net/xsk_buff_pool.h @@ -77,6 +77,7 @@ struct xsk_buff_pool { u32 chunk_size; u32 chunk_shift; u32 frame_len; + u8 tx_metadata_len; /* inherited from umem */ u8 cached_need_wakeup; bool uses_need_wakeup; bool dma_need_sync; diff --git a/include/uapi/linux/if_xdp.h b/include/uapi/linux/if_xdp.h index 8d48863472b9..2ecf79282c26 100644 --- a/include/uapi/linux/if_xdp.h +++ b/include/uapi/linux/if_xdp.h @@ -76,6 +76,7 @@ struct xdp_umem_reg { __u32 chunk_size; __u32 headroom; __u32 flags; + __u32 tx_metadata_len; }; struct xdp_statistics { diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index 06cead2b8e34..946a687fb8e8 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -199,6 +199,9 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr) if (headroom >= chunk_size - XDP_PACKET_HEADROOM) return -EINVAL; + if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8) + return -EINVAL; + umem->size = size; umem->headroom = headroom; umem->chunk_size = chunk_size; @@ -207,6 +210,7 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr) umem->pgs = NULL; umem->user = NULL; umem->flags = mr->flags; + umem->tx_metadata_len = mr->tx_metadata_len; INIT_LIST_HEAD(&umem->xsk_dma_list); refcount_set(&umem->users, 1); diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index ae9f8cb611f6..c904356e2800 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -1283,6 +1283,14 @@ struct xdp_umem_reg_v1 { __u32 headroom; }; +struct xdp_umem_reg_v2 { + __u64 addr; /* Start of packet data area */ + __u64 len; /* Length of packet data area */ + __u32 chunk_size; + __u32 headroom; + __u32 flags; +}; + static int xsk_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen) { @@ -1326,8 +1334,10 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname, if (optlen < sizeof(struct xdp_umem_reg_v1)) return -EINVAL; - else if (optlen < sizeof(mr)) + else if (optlen < sizeof(struct xdp_umem_reg_v2)) mr_size = sizeof(struct xdp_umem_reg_v1); + else if (optlen < sizeof(mr)) + mr_size = sizeof(struct xdp_umem_reg_v2); if (copy_from_sockptr(&mr, optval, mr_size)) return -EFAULT; diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index 49cb9f9a09be..386eddcdf837 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -85,6 +85,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs, XDP_PACKET_HEADROOM; pool->umem = umem; pool->addrs = umem->addrs; + pool->tx_metadata_len = umem->tx_metadata_len; INIT_LIST_HEAD(&pool->free_list); INIT_LIST_HEAD(&pool->xskb_list); INIT_LIST_HEAD(&pool->xsk_tx_list); diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h index 13354a1e4280..c74a1372bcb9 100644 --- a/net/xdp/xsk_queue.h +++ b/net/xdp/xsk_queue.h @@ -143,15 +143,17 @@ static inline bool xp_unused_options_set(u32 options) static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc) { - u64 offset = desc->addr & (pool->chunk_size - 1); + u64 addr = desc->addr - pool->tx_metadata_len; + u64 len = desc->len + pool->tx_metadata_len; + u64 offset = addr & (pool->chunk_size - 1); if (!desc->len) return false; - if (offset + desc->len > pool->chunk_size) + if (offset + len > pool->chunk_size) return false; - if (desc->addr >= pool->addrs_cnt) + if (addr >= pool->addrs_cnt) return false; if (xp_unused_options_set(desc->options)) @@ -162,16 +164,17 @@ static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool, static inline bool xp_unaligned_validate_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc) { - u64 addr = xp_unaligned_add_offset_to_addr(desc->addr); + u64 addr = xp_unaligned_add_offset_to_addr(desc->addr) - pool->tx_metadata_len; + u64 len = desc->len + pool->tx_metadata_len; if (!desc->len) return false; - if (desc->len > pool->chunk_size) + if (len > pool->chunk_size) return false; - if (addr >= pool->addrs_cnt || addr + desc->len > pool->addrs_cnt || - xp_desc_crosses_non_contig_pg(pool, addr, desc->len)) + if (addr >= pool->addrs_cnt || addr + len > pool->addrs_cnt || + xp_desc_crosses_non_contig_pg(pool, addr, len)) return false; if (xp_unused_options_set(desc->options)) diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index 73a47da885dc..34411a2e5b6c 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -76,6 +76,7 @@ struct xdp_umem_reg { __u32 chunk_size; __u32 headroom; __u32 flags; + __u32 tx_metadata_len; }; struct xdp_statistics { From 48eb03dd26304c24f03bdbb9382e89c8564e71df Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:08 -0800 Subject: [PATCH 1880/7721] xsk: Add TX timestamp and TX checksum offload support This change actually defines the (initial) metadata layout that should be used by AF_XDP userspace (xsk_tx_metadata). The first field is flags which requests appropriate offloads, followed by the offload-specific fields. The supported per-device offloads are exported via netlink (new xsk-flags). The offloads themselves are still implemented in a bit of a framework-y fashion that's left from my initial kfunc attempt. I'm introducing new xsk_tx_metadata_ops which drivers are supposed to implement. The drivers are also supposed to call xsk_tx_metadata_request/xsk_tx_metadata_complete in the right places. Since xsk_tx_metadata_{request,_complete} are static inline, we don't incur any extra overhead doing indirect calls. The benefit of this scheme is as follows: - keeps all metadata layout parsing away from driver code - makes it easy to grep and see which drivers implement what - don't need any extra flags to maintain to keep track of what offloads are implemented; if the callback is implemented - the offload is supported (used by netlink reporting code) Two offloads are defined right now: 1. XDP_TXMD_FLAGS_CHECKSUM: skb-style csum_start+csum_offset 2. XDP_TXMD_FLAGS_TIMESTAMP: writes TX timestamp back into metadata area upon completion (tx_timestamp field) XDP_TXMD_FLAGS_TIMESTAMP is also implemented for XDP_COPY mode: it writes SW timestamp from the skb destructor (note I'm reusing hwtstamps to pass metadata pointer). The struct is forward-compatible and can be extended in the future by appending more fields. Reviewed-by: Song Yoong Siang Signed-off-by: Stanislav Fomichev Acked-by: Jakub Kicinski Link: https://lore.kernel.org/r/20231127190319.1190813-3-sdf@google.com Signed-off-by: Alexei Starovoitov --- Documentation/netlink/specs/netdev.yaml | 19 +++- include/linux/netdevice.h | 2 + include/linux/skbuff.h | 14 ++- include/net/xdp_sock.h | 110 ++++++++++++++++++++++++ include/net/xdp_sock_drv.h | 13 +++ include/net/xsk_buff_pool.h | 6 ++ include/uapi/linux/if_xdp.h | 38 ++++++++ include/uapi/linux/netdev.h | 16 ++++ net/core/netdev-genl.c | 13 ++- net/xdp/xsk.c | 34 ++++++++ net/xdp/xsk_queue.h | 2 +- tools/include/uapi/linux/if_xdp.h | 54 ++++++++++-- tools/include/uapi/linux/netdev.h | 16 ++++ tools/net/ynl/generated/netdev-user.c | 19 ++++ tools/net/ynl/generated/netdev-user.h | 3 + 15 files changed, 349 insertions(+), 10 deletions(-) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 14511b13f305..00439bcbd2e3 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -45,7 +45,6 @@ definitions: - type: flags name: xdp-rx-metadata - render-max: true entries: - name: timestamp @@ -55,6 +54,18 @@ definitions: name: hash doc: Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash(). + - + type: flags + name: xsk-flags + entries: + - + name: tx-timestamp + doc: + HW timestamping egress packets is supported by the driver. + - + name: tx-checksum + doc: + L3 checksum HW offload is supported by the driver. attribute-sets: - @@ -86,6 +97,11 @@ attribute-sets: See Documentation/networking/xdp-rx-metadata.rst for more details. type: u64 enum: xdp-rx-metadata + - + name: xsk-features + doc: Bitmask of enabled AF_XDP features. + type: u64 + enum: xsk-flags operations: list: @@ -103,6 +119,7 @@ operations: - xdp-features - xdp-zc-max-segs - xdp-rx-metadata-features + - xsk-features dump: reply: *dev-all - diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e87caa81f70c..08da8b28c816 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1865,6 +1865,7 @@ enum netdev_stat_type { * @netdev_ops: Includes several pointers to callbacks, * if one wants to override the ndo_*() functions * @xdp_metadata_ops: Includes pointers to XDP metadata callbacks. + * @xsk_tx_metadata_ops: Includes pointers to AF_XDP TX metadata callbacks. * @ethtool_ops: Management operations * @l3mdev_ops: Layer 3 master device operations * @ndisc_ops: Includes callbacks for different IPv6 neighbour @@ -2128,6 +2129,7 @@ struct net_device { unsigned long long priv_flags; const struct net_device_ops *netdev_ops; const struct xdp_metadata_ops *xdp_metadata_ops; + const struct xsk_tx_metadata_ops *xsk_tx_metadata_ops; int ifindex; unsigned short gflags; unsigned short hard_header_len; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 27998f73183e..b370eb8d70f7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -566,6 +566,15 @@ struct ubuf_info_msgzc { int mm_account_pinned_pages(struct mmpin *mmp, size_t size); void mm_unaccount_pinned_pages(struct mmpin *mmp); +/* Preserve some data across TX submission and completion. + * + * Note, this state is stored in the driver. Extending the layout + * might need some special care. + */ +struct xsk_tx_metadata_compl { + __u64 *tx_timestamp; +}; + /* This data is invariant across clones and lives at * the end of the header data, ie. at skb->end. */ @@ -578,7 +587,10 @@ struct skb_shared_info { /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; struct sk_buff *frag_list; - struct skb_shared_hwtstamps hwtstamps; + union { + struct skb_shared_hwtstamps hwtstamps; + struct xsk_tx_metadata_compl xsk_meta; + }; unsigned int gso_type; u32 tskey; diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index bcf765124f72..3cb4dc9bd70e 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -93,12 +93,105 @@ struct xdp_sock { struct xsk_queue *cq_tmp; /* Only as tmp storage before bind */ }; +/* + * AF_XDP TX metadata hooks for network devices. + * The following hooks can be defined; unless noted otherwise, they are + * optional and can be filled with a null pointer. + * + * void (*tmo_request_timestamp)(void *priv) + * Called when AF_XDP frame requested egress timestamp. + * + * u64 (*tmo_fill_timestamp)(void *priv) + * Called when AF_XDP frame, that had requested egress timestamp, + * received a completion. The hook needs to return the actual HW timestamp. + * + * void (*tmo_request_checksum)(u16 csum_start, u16 csum_offset, void *priv) + * Called when AF_XDP frame requested HW checksum offload. csum_start + * indicates position where checksumming should start. + * csum_offset indicates position where checksum should be stored. + * + */ +struct xsk_tx_metadata_ops { + void (*tmo_request_timestamp)(void *priv); + u64 (*tmo_fill_timestamp)(void *priv); + void (*tmo_request_checksum)(u16 csum_start, u16 csum_offset, void *priv); +}; + #ifdef CONFIG_XDP_SOCKETS int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp); int __xsk_map_redirect(struct xdp_sock *xs, struct xdp_buff *xdp); void __xsk_map_flush(void); +/** + * xsk_tx_metadata_to_compl - Save enough relevant metadata information + * to perform tx completion in the future. + * @meta: pointer to AF_XDP metadata area + * @compl: pointer to output struct xsk_tx_metadata_to_compl + * + * This function should be called by the networking device when + * it prepares AF_XDP egress packet. The value of @compl should be stored + * and passed to xsk_tx_metadata_complete upon TX completion. + */ +static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta, + struct xsk_tx_metadata_compl *compl) +{ + if (!meta) + return; + + if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP) + compl->tx_timestamp = &meta->completion.tx_timestamp; + else + compl->tx_timestamp = NULL; +} + +/** + * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission + * and call appropriate xsk_tx_metadata_ops operation. + * @meta: pointer to AF_XDP metadata area + * @ops: pointer to struct xsk_tx_metadata_ops + * @priv: pointer to driver-private aread + * + * This function should be called by the networking device when + * it prepares AF_XDP egress packet. + */ +static inline void xsk_tx_metadata_request(const struct xsk_tx_metadata *meta, + const struct xsk_tx_metadata_ops *ops, + void *priv) +{ + if (!meta) + return; + + if (ops->tmo_request_timestamp) + if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP) + ops->tmo_request_timestamp(priv); + + if (ops->tmo_request_checksum) + if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) + ops->tmo_request_checksum(meta->request.csum_start, + meta->request.csum_offset, priv); +} + +/** + * xsk_tx_metadata_complete - Evaluate AF_XDP TX metadata at completion + * and call appropriate xsk_tx_metadata_ops operation. + * @compl: pointer to completion metadata produced from xsk_tx_metadata_to_compl + * @ops: pointer to struct xsk_tx_metadata_ops + * @priv: pointer to driver-private aread + * + * This function should be called by the networking device upon + * AF_XDP egress completion. + */ +static inline void xsk_tx_metadata_complete(struct xsk_tx_metadata_compl *compl, + const struct xsk_tx_metadata_ops *ops, + void *priv) +{ + if (!compl) + return; + + *compl->tx_timestamp = ops->tmo_fill_timestamp(priv); +} + #else static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) @@ -115,6 +208,23 @@ static inline void __xsk_map_flush(void) { } +static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta, + struct xsk_tx_metadata_compl *compl) +{ +} + +static inline void xsk_tx_metadata_request(struct xsk_tx_metadata *meta, + const struct xsk_tx_metadata_ops *ops, + void *priv) +{ +} + +static inline void xsk_tx_metadata_complete(struct xsk_tx_metadata_compl *compl, + const struct xsk_tx_metadata_ops *ops, + void *priv) +{ +} + #endif /* CONFIG_XDP_SOCKETS */ #if defined(CONFIG_XDP_SOCKETS) && defined(CONFIG_DEBUG_NET) diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h index 1f6fc8c7a84c..e2558ac3e195 100644 --- a/include/net/xdp_sock_drv.h +++ b/include/net/xdp_sock_drv.h @@ -165,6 +165,14 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) return xp_raw_get_data(pool, addr); } +static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr) +{ + if (!pool->tx_metadata_len) + return NULL; + + return xp_raw_get_data(pool, addr) - pool->tx_metadata_len; +} + static inline void xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp, struct xsk_buff_pool *pool) { struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); @@ -324,6 +332,11 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) return NULL; } +static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr) +{ + return NULL; +} + static inline void xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp, struct xsk_buff_pool *pool) { } diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h index 1985ffaf9b0c..97f5cc10d79e 100644 --- a/include/net/xsk_buff_pool.h +++ b/include/net/xsk_buff_pool.h @@ -33,6 +33,7 @@ struct xdp_buff_xsk { }; #define XSK_CHECK_PRIV_TYPE(t) BUILD_BUG_ON(sizeof(t) > offsetofend(struct xdp_buff_xsk, cb)) +#define XSK_TX_COMPL_FITS(t) BUILD_BUG_ON(sizeof(struct xsk_tx_metadata_compl) > sizeof(t)) struct xsk_dma_map { dma_addr_t *dma_pages; @@ -234,4 +235,9 @@ static inline u64 xp_get_handle(struct xdp_buff_xsk *xskb) return xskb->orig_addr + (offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT); } +static inline bool xp_tx_metadata_enabled(const struct xsk_buff_pool *pool) +{ + return pool->tx_metadata_len > 0; +} + #endif /* XSK_BUFF_POOL_H_ */ diff --git a/include/uapi/linux/if_xdp.h b/include/uapi/linux/if_xdp.h index 2ecf79282c26..95de66d5a26c 100644 --- a/include/uapi/linux/if_xdp.h +++ b/include/uapi/linux/if_xdp.h @@ -106,6 +106,41 @@ struct xdp_options { #define XSK_UNALIGNED_BUF_ADDR_MASK \ ((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1) +/* Request transmit timestamp. Upon completion, put it into tx_timestamp + * field of struct xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0) + +/* Request transmit checksum offload. Checksum start position and offset + * are communicated via csum_start and csum_offset fields of struct + * xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_CHECKSUM (1 << 1) + +/* AF_XDP offloads request. 'request' union member is consumed by the driver + * when the packet is being transmitted. 'completion' union member is + * filled by the driver when the transmit completion arrives. + */ +struct xsk_tx_metadata { + __u64 flags; + + union { + struct { + /* XDP_TXMD_FLAGS_CHECKSUM */ + + /* Offset from desc->addr where checksumming should start. */ + __u16 csum_start; + /* Offset from csum_start where checksum should be stored. */ + __u16 csum_offset; + } request; + + struct { + /* XDP_TXMD_FLAGS_TIMESTAMP */ + __u64 tx_timestamp; + } completion; + }; +}; + /* Rx/Tx descriptor */ struct xdp_desc { __u64 addr; @@ -122,4 +157,7 @@ struct xdp_desc { */ #define XDP_PKT_CONTD (1 << 0) +/* TX packet carries valid metadata. */ +#define XDP_TX_METADATA (1 << 1) + #endif /* _LINUX_IF_XDP_H */ diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 2943a151d4f1..48d5477a668c 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -53,12 +53,28 @@ enum netdev_xdp_rx_metadata { NETDEV_XDP_RX_METADATA_MASK = 3, }; +/** + * enum netdev_xsk_flags + * @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported + * by the driver. + * @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the + * driver. + */ +enum netdev_xsk_flags { + NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1, + NETDEV_XSK_FLAGS_TX_CHECKSUM = 2, + + /* private: */ + NETDEV_XSK_FLAGS_MASK = 3, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, + NETDEV_A_DEV_XSK_FEATURES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index fe61f85bcf33..10f2124e9e23 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "netdev-genl-gen.h" @@ -13,6 +14,7 @@ static int netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, const struct genl_info *info) { + u64 xsk_features = 0; u64 xdp_rx_meta = 0; void *hdr; @@ -26,11 +28,20 @@ netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC + if (netdev->xsk_tx_metadata_ops) { + if (netdev->xsk_tx_metadata_ops->tmo_fill_timestamp) + xsk_features |= NETDEV_XSK_FLAGS_TX_TIMESTAMP; + if (netdev->xsk_tx_metadata_ops->tmo_request_checksum) + xsk_features |= NETDEV_XSK_FLAGS_TX_CHECKSUM; + } + if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) || nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES, netdev->xdp_features, NETDEV_A_DEV_PAD) || nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, - xdp_rx_meta, NETDEV_A_DEV_PAD)) { + xdp_rx_meta, NETDEV_A_DEV_PAD) || + nla_put_u64_64bit(rsp, NETDEV_A_DEV_XSK_FEATURES, + xsk_features, NETDEV_A_DEV_PAD)) { genlmsg_cancel(rsp, hdr); return -EINVAL; } diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index c904356e2800..e83ade32f1fd 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -571,6 +571,13 @@ static u32 xsk_get_num_desc(struct sk_buff *skb) static void xsk_destruct_skb(struct sk_buff *skb) { + struct xsk_tx_metadata_compl *compl = &skb_shinfo(skb)->xsk_meta; + + if (compl->tx_timestamp) { + /* sw completion timestamp, not a real one */ + *compl->tx_timestamp = ktime_get_tai_fast_ns(); + } + xsk_cq_submit_locked(xdp_sk(skb->sk), xsk_get_num_desc(skb)); sock_wfree(skb); } @@ -655,8 +662,10 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs, static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, struct xdp_desc *desc) { + struct xsk_tx_metadata *meta = NULL; struct net_device *dev = xs->dev; struct sk_buff *skb = xs->skb; + bool first_frag = false; int err; if (dev->priv_flags & IFF_TX_SKB_NO_LINEAR) { @@ -687,6 +696,8 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, kfree_skb(skb); goto free_err; } + + first_frag = true; } else { int nr_frags = skb_shinfo(skb)->nr_frags; struct page *page; @@ -709,12 +720,35 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, skb_add_rx_frag(skb, nr_frags, page, 0, len, 0); } + + if (first_frag && desc->options & XDP_TX_METADATA) { + if (unlikely(xs->pool->tx_metadata_len == 0)) { + err = -EINVAL; + goto free_err; + } + + meta = buffer - xs->pool->tx_metadata_len; + + if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) { + if (unlikely(meta->request.csum_start + + meta->request.csum_offset + + sizeof(__sum16) > len)) { + err = -EINVAL; + goto free_err; + } + + skb->csum_start = hr + meta->request.csum_start; + skb->csum_offset = meta->request.csum_offset; + skb->ip_summed = CHECKSUM_PARTIAL; + } + } } skb->dev = dev; skb->priority = READ_ONCE(xs->sk.sk_priority); skb->mark = READ_ONCE(xs->sk.sk_mark); skb->destructor = xsk_destruct_skb; + xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta); xsk_set_destructor_arg(skb); return skb; diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h index c74a1372bcb9..6f2d1621c992 100644 --- a/net/xdp/xsk_queue.h +++ b/net/xdp/xsk_queue.h @@ -137,7 +137,7 @@ static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr) static inline bool xp_unused_options_set(u32 options) { - return options & ~XDP_PKT_CONTD; + return options & ~(XDP_PKT_CONTD | XDP_TX_METADATA); } static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool, diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index 34411a2e5b6c..d0882edc1642 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -26,11 +26,11 @@ */ #define XDP_USE_NEED_WAKEUP (1 << 3) /* By setting this option, userspace application indicates that it can - * handle multiple descriptors per packet thus enabling xsk core to split + * handle multiple descriptors per packet thus enabling AF_XDP to split * multi-buffer XDP frames into multiple Rx descriptors. Without this set - * such frames will be dropped by xsk. + * such frames will be dropped. */ -#define XDP_USE_SG (1 << 4) +#define XDP_USE_SG (1 << 4) /* Flags for xsk_umem_config flags */ #define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) @@ -106,6 +106,41 @@ struct xdp_options { #define XSK_UNALIGNED_BUF_ADDR_MASK \ ((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1) +/* Request transmit timestamp. Upon completion, put it into tx_timestamp + * field of union xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0) + +/* Request transmit checksum offload. Checksum start position and offset + * are communicated via csum_start and csum_offset fields of union + * xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_CHECKSUM (1 << 1) + +/* AF_XDP offloads request. 'request' union member is consumed by the driver + * when the packet is being transmitted. 'completion' union member is + * filled by the driver when the transmit completion arrives. + */ +struct xsk_tx_metadata { + __u64 flags; + + union { + struct { + /* XDP_TXMD_FLAGS_CHECKSUM */ + + /* Offset from desc->addr where checksumming should start. */ + __u16 csum_start; + /* Offset from csum_start where checksum should be stored. */ + __u16 csum_offset; + } request; + + struct { + /* XDP_TXMD_FLAGS_TIMESTAMP */ + __u64 tx_timestamp; + } completion; + }; +}; + /* Rx/Tx descriptor */ struct xdp_desc { __u64 addr; @@ -113,9 +148,16 @@ struct xdp_desc { __u32 options; }; -/* Flag indicating packet constitutes of multiple buffers*/ -#define XDP_PKT_CONTD (1 << 0) - /* UMEM descriptor is __u64 */ +/* Flag indicating that the packet continues with the buffer pointed out by the + * next frame in the ring. The end of the packet is signalled by setting this + * bit to zero. For single buffer packets, every descriptor has 'options' set + * to 0 and this maintains backward compatibility. + */ +#define XDP_PKT_CONTD (1 << 0) + +/* TX packet carries valid metadata. */ +#define XDP_TX_METADATA (1 << 1) + #endif /* _LINUX_IF_XDP_H */ diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 2943a151d4f1..48d5477a668c 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -53,12 +53,28 @@ enum netdev_xdp_rx_metadata { NETDEV_XDP_RX_METADATA_MASK = 3, }; +/** + * enum netdev_xsk_flags + * @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported + * by the driver. + * @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the + * driver. + */ +enum netdev_xsk_flags { + NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1, + NETDEV_XSK_FLAGS_TX_CHECKSUM = 2, + + /* private: */ + NETDEV_XSK_FLAGS_MASK = 3, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, + NETDEV_A_DEV_XSK_FEATURES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index b5ffe8cd1144..6283d87dad37 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -58,6 +58,19 @@ const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value) return netdev_xdp_rx_metadata_strmap[value]; } +static const char * const netdev_xsk_flags_strmap[] = { + [0] = "tx-timestamp", + [1] = "tx-checksum", +}; + +const char *netdev_xsk_flags_str(enum netdev_xsk_flags value) +{ + value = ffs(value) - 1; + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xsk_flags_strmap)) + return NULL; + return netdev_xsk_flags_strmap[value]; +} + /* Policies */ struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, @@ -65,6 +78,7 @@ struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { [NETDEV_A_DEV_XDP_FEATURES] = { .name = "xdp-features", .type = YNL_PT_U64, }, [NETDEV_A_DEV_XDP_ZC_MAX_SEGS] = { .name = "xdp-zc-max-segs", .type = YNL_PT_U32, }, [NETDEV_A_DEV_XDP_RX_METADATA_FEATURES] = { .name = "xdp-rx-metadata-features", .type = YNL_PT_U64, }, + [NETDEV_A_DEV_XSK_FEATURES] = { .name = "xsk-features", .type = YNL_PT_U64, }, }; struct ynl_policy_nest netdev_dev_nest = { @@ -116,6 +130,11 @@ int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return MNL_CB_ERROR; dst->_present.xdp_rx_metadata_features = 1; dst->xdp_rx_metadata_features = mnl_attr_get_u64(attr); + } else if (type == NETDEV_A_DEV_XSK_FEATURES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.xsk_features = 1; + dst->xsk_features = mnl_attr_get_u64(attr); } } diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index 4fafac879df3..39af1908444b 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -19,6 +19,7 @@ extern const struct ynl_family ynl_netdev_family; const char *netdev_op_str(int op); const char *netdev_xdp_act_str(enum netdev_xdp_act value); const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); +const char *netdev_xsk_flags_str(enum netdev_xsk_flags value); /* Common nested types */ /* ============== NETDEV_CMD_DEV_GET ============== */ @@ -50,12 +51,14 @@ struct netdev_dev_get_rsp { __u32 xdp_features:1; __u32 xdp_zc_max_segs:1; __u32 xdp_rx_metadata_features:1; + __u32 xsk_features:1; } _present; __u32 ifindex; __u64 xdp_features; __u32 xdp_zc_max_segs; __u64 xdp_rx_metadata_features; + __u64 xsk_features; }; void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp); From 9276009d35d3f65e083b95d30a4f967baaae0fc6 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:09 -0800 Subject: [PATCH 1881/7721] tools: ynl: Print xsk-features from the sample In a similar fashion we do for the other bit masks. Fix mask parsing (>= vs >) while we are it. Signed-off-by: Stanislav Fomichev Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20231127190319.1190813-4-sdf@google.com Signed-off-by: Alexei Starovoitov --- tools/net/ynl/samples/netdev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/samples/netdev.c b/tools/net/ynl/samples/netdev.c index b828225daad0..591b90e21890 100644 --- a/tools/net/ynl/samples/netdev.c +++ b/tools/net/ynl/samples/netdev.c @@ -33,17 +33,23 @@ static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op) return; printf("xdp-features (%llx):", d->xdp_features); - for (int i = 0; d->xdp_features > 1U << i; i++) { + for (int i = 0; d->xdp_features >= 1U << i; i++) { if (d->xdp_features & (1U << i)) printf(" %s", netdev_xdp_act_str(1 << i)); } printf(" xdp-rx-metadata-features (%llx):", d->xdp_rx_metadata_features); - for (int i = 0; d->xdp_rx_metadata_features > 1U << i; i++) { + for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { if (d->xdp_rx_metadata_features & (1U << i)) printf(" %s", netdev_xdp_rx_metadata_str(1 << i)); } + printf(" xsk-features (%llx):", d->xsk_features); + for (int i = 0; d->xsk_features >= 1U << i; i++) { + if (d->xsk_features & (1U << i)) + printf(" %s", netdev_xsk_flags_str(1 << i)); + } + printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); name = netdev_op_str(op); From ec706a860eba99bf934d59f74b5db90af44e882e Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:10 -0800 Subject: [PATCH 1882/7721] net/mlx5e: Implement AF_XDP TX timestamp and checksum offload TX timestamp: - requires passing clock, not sure I'm passing the correct one (from cq->mdev), but the timestamp value looks convincing TX checksum: - looks like device does packet parsing (and doesn't accept custom start/offset), so I'm ignoring user offsets Cc: Saeed Mahameed Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-5-sdf@google.com Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 +- .../net/ethernet/mellanox/mlx5/core/en/xdp.c | 72 ++++++++++++++++--- .../net/ethernet/mellanox/mlx5/core/en/xdp.h | 11 ++- .../ethernet/mellanox/mlx5/core/en/xsk/tx.c | 17 ++++- .../net/ethernet/mellanox/mlx5/core/en_main.c | 1 + 5 files changed, 89 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b2a5da9739d2..43f027bf2da3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -484,10 +484,12 @@ struct mlx5e_xdp_info_fifo { struct mlx5e_xdpsq; struct mlx5e_xmit_data; +struct xsk_tx_metadata; typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *); typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *, struct mlx5e_xmit_data *, - int); + int, + struct xsk_tx_metadata *); struct mlx5e_xdpsq { /* data path */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c index 7decc81ed33a..e2e7d82cfca4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c @@ -103,7 +103,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, xdptxd->dma_addr = dma_addr; if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, - mlx5e_xmit_xdp_frame, sq, xdptxd, 0))) + mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL))) return false; /* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */ @@ -145,7 +145,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, xdptxd->dma_addr = dma_addr; if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, - mlx5e_xmit_xdp_frame, sq, xdptxd, 0))) + mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL))) return false; /* xmit_mode == MLX5E_XDP_XMIT_MODE_PAGE */ @@ -261,6 +261,37 @@ const struct xdp_metadata_ops mlx5e_xdp_metadata_ops = { .xmo_rx_hash = mlx5e_xdp_rx_hash, }; +struct mlx5e_xsk_tx_complete { + struct mlx5_cqe64 *cqe; + struct mlx5e_cq *cq; +}; + +static u64 mlx5e_xsk_fill_timestamp(void *_priv) +{ + struct mlx5e_xsk_tx_complete *priv = _priv; + u64 ts; + + ts = get_cqe_ts(priv->cqe); + + if (mlx5_is_real_time_rq(priv->cq->mdev) || mlx5_is_real_time_sq(priv->cq->mdev)) + return mlx5_real_time_cyc2time(&priv->cq->mdev->clock, ts); + + return mlx5_timecounter_cyc2time(&priv->cq->mdev->clock, ts); +} + +static void mlx5e_xsk_request_checksum(u16 csum_start, u16 csum_offset, void *priv) +{ + struct mlx5_wqe_eth_seg *eseg = priv; + + /* HW/FW is doing parsing, so offsets are largely ignored. */ + eseg->cs_flags |= MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; +} + +const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops = { + .tmo_fill_timestamp = mlx5e_xsk_fill_timestamp, + .tmo_request_checksum = mlx5e_xsk_request_checksum, +}; + /* returns true if packet was consumed by xdp */ bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct bpf_prog *prog, struct mlx5e_xdp_buff *mxbuf) @@ -398,11 +429,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result); + int check_result, struct xsk_tx_metadata *meta); INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result) + int check_result, struct xsk_tx_metadata *meta) { struct mlx5e_tx_mpwqe *session = &sq->mpwqe; struct mlx5e_xdpsq_stats *stats = sq->stats; @@ -420,7 +451,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx */ if (unlikely(sq->mpwqe.wqe)) mlx5e_xdp_mpwqe_complete(sq); - return mlx5e_xmit_xdp_frame(sq, xdptxd, 0); + return mlx5e_xmit_xdp_frame(sq, xdptxd, 0, meta); } if (!xdptxd->len) { skb_frag_t *frag = &xdptxdf->sinfo->frags[0]; @@ -450,6 +481,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx * and it's safe to complete it at any time. */ mlx5e_xdp_mpwqe_session_start(sq); + xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth); } mlx5e_xdp_mpwqe_add_dseg(sq, p, stats); @@ -480,7 +512,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq) INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result) + int check_result, struct xsk_tx_metadata *meta) { struct mlx5e_xmit_data_frags *xdptxdf = container_of(xdptxd, struct mlx5e_xmit_data_frags, xd); @@ -599,6 +631,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, sq->pc++; } + xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg); + sq->doorbell_cseg = cseg; stats->xmit++; @@ -608,7 +642,9 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_wqe_info *wi, u32 *xsk_frames, - struct xdp_frame_bulk *bq) + struct xdp_frame_bulk *bq, + struct mlx5e_cq *cq, + struct mlx5_cqe64 *cqe) { struct mlx5e_xdp_info_fifo *xdpi_fifo = &sq->db.xdpi_fifo; u16 i; @@ -668,10 +704,24 @@ static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq, break; } - case MLX5E_XDP_XMIT_MODE_XSK: + case MLX5E_XDP_XMIT_MODE_XSK: { /* AF_XDP send */ + struct xsk_tx_metadata_compl *compl = NULL; + struct mlx5e_xsk_tx_complete priv = { + .cqe = cqe, + .cq = cq, + }; + + if (xp_tx_metadata_enabled(sq->xsk_pool)) { + xdpi = mlx5e_xdpi_fifo_pop(xdpi_fifo); + compl = &xdpi.xsk_meta; + + xsk_tx_metadata_complete(compl, &mlx5e_xsk_tx_metadata_ops, &priv); + } + (*xsk_frames)++; break; + } default: WARN_ON_ONCE(true); } @@ -720,7 +770,7 @@ bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq) sqcc += wi->num_wqebbs; - mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq); + mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq, cq, cqe); } while (!last_wqe); if (unlikely(get_cqe_opcode(cqe) != MLX5_CQE_REQ)) { @@ -767,7 +817,7 @@ void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq) sq->cc += wi->num_wqebbs; - mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq); + mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq, NULL, NULL); } xdp_flush_frame_bulk(&bq); @@ -840,7 +890,7 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, } ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, - mlx5e_xmit_xdp_frame, sq, xdptxd, 0); + mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL); if (unlikely(!ret)) { int j; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h index ecfe93a479da..e054db1e10f8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h @@ -33,6 +33,7 @@ #define __MLX5_EN_XDP_H__ #include +#include #include "en.h" #include "en/txrx.h" @@ -82,7 +83,7 @@ enum mlx5e_xdp_xmit_mode { * num, page_1, page_2, ... , page_num. * * MLX5E_XDP_XMIT_MODE_XSK: - * none. + * frame.xsk_meta. */ #define MLX5E_XDP_FIFO_ENTRIES2DS_MAX_RATIO 4 @@ -97,6 +98,7 @@ union mlx5e_xdp_info { u8 num; struct page *page; } page; + struct xsk_tx_metadata_compl xsk_meta; }; struct mlx5e_xsk_param; @@ -112,13 +114,16 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, u32 flags); extern const struct xdp_metadata_ops mlx5e_xdp_metadata_ops; +extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops; INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result)); + int check_result, + struct xsk_tx_metadata *meta)); INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result)); + int check_result, + struct xsk_tx_metadata *meta)); INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq)); INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c index 597f319d4770..a59199ed590d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c @@ -55,12 +55,16 @@ static void mlx5e_xsk_tx_post_err(struct mlx5e_xdpsq *sq, nopwqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc); mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, *xdpi); + if (xp_tx_metadata_enabled(sq->xsk_pool)) + mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, + (union mlx5e_xdp_info) { .xsk_meta = {} }); sq->doorbell_cseg = &nopwqe->ctrl; } bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget) { struct xsk_buff_pool *pool = sq->xsk_pool; + struct xsk_tx_metadata *meta = NULL; union mlx5e_xdp_info xdpi; bool work_done = true; bool flush = false; @@ -93,12 +97,13 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget) xdptxd.dma_addr = xsk_buff_raw_get_dma(pool, desc.addr); xdptxd.data = xsk_buff_raw_get_data(pool, desc.addr); xdptxd.len = desc.len; + meta = xsk_buff_get_metadata(pool, desc.addr); xsk_buff_raw_dma_sync_for_device(pool, xdptxd.dma_addr, xdptxd.len); ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, mlx5e_xmit_xdp_frame, sq, &xdptxd, - check_result); + check_result, meta); if (unlikely(!ret)) { if (sq->mpwqe.wqe) mlx5e_xdp_mpwqe_complete(sq); @@ -106,6 +111,16 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget) mlx5e_xsk_tx_post_err(sq, &xdpi); } else { mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, xdpi); + if (xp_tx_metadata_enabled(sq->xsk_pool)) { + struct xsk_tx_metadata_compl compl; + + xsk_tx_metadata_to_compl(meta, &compl); + XSK_TX_COMPL_FITS(void *); + + mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, + (union mlx5e_xdp_info) + { .xsk_meta = compl }); + } } flush = true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 3aecdf099a2f..0197eefb2108 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -5164,6 +5164,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) netdev->netdev_ops = &mlx5e_netdev_ops; netdev->xdp_metadata_ops = &mlx5e_xdp_metadata_ops; + netdev->xsk_tx_metadata_ops = &mlx5e_xsk_tx_metadata_ops; mlx5e_dcbnl_build_netdev(netdev); From 1347b419318d6afa1c86d7865d82ca0a6cdf30ce Mon Sep 17 00:00:00 2001 From: Song Yoong Siang Date: Mon, 27 Nov 2023 11:03:11 -0800 Subject: [PATCH 1883/7721] net: stmmac: Add Tx HWTS support to XDP ZC This patch enables transmit hardware timestamp support to XDP zero copy via XDP Tx metadata framework. This patchset is tested with tools/testing/selftests/bpf/xdp_hw_metadata on Intel Tiger Lake platform. Below are the test steps and results. Command on DUT: sudo ./xdp_hw_metadata sudo hwstamp_ctl -i -t 1 -r 1 Command on Link Partner: echo -n xdp | nc -u -q1 9091 Result: xsk_ring_cons__peek: 1 0x55bbbf08b6d0: rx_desc[2]->addr=8c100 addr=8c100 comp_addr=8c100 EoP No rx_hash err=-95 rx_timestamp: 1677762688429141540 (sec:1677762688.4291) HW RX-time: 1677762688429141540 (sec:1677762688.4291) delta to User RX-time sec:0.0003 (250.665 usec) XDP RX-time: 1677762688429375597 (sec:1677762688.4294) delta to User RX-time sec:0.0000 (16.608 usec) 0x55bbbf08b6d0: ping-pong with csum=561c (want f488) csum_start=34 csum_offset=6 0x55bbbf08b6d0: complete tx idx=2 addr=2008 tx_timestamp: 1677762688431127273 (sec:1677762688.4311) HW TX-complete-time: 1677762688431127273 (sec:1677762688.4311) delta to User TX-complete-time sec:0.0083 (8331.655 usec) XDP RX-time: 1677762688429375597 (sec:1677762688.4294) delta to User TX-complete-time sec:0.0101 (10083.331 usec) HW RX-time: 1677762688429141540 (sec:1677762688.4291) delta to HW TX-complete-time sec:0.0020 (1985.733 usec) 0x55bbbf08b6d0: complete rx idx=130 addr=8c100 Signed-off-by: Song Yoong Siang Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-6-sdf@google.com Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 12 ++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 64 ++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index cd7a9768de5f..686c94c2e8a7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -51,6 +51,7 @@ struct stmmac_tx_info { bool last_segment; bool is_jumbo; enum stmmac_txbuf_type buf_type; + struct xsk_tx_metadata_compl xsk_meta; }; #define STMMAC_TBS_AVAIL BIT(0) @@ -100,6 +101,17 @@ struct stmmac_xdp_buff { struct dma_desc *ndesc; }; +struct stmmac_metadata_request { + struct stmmac_priv *priv; + struct dma_desc *tx_desc; + bool *set_ic; +}; + +struct stmmac_xsk_tx_complete { + struct stmmac_priv *priv; + struct dma_desc *desc; +}; + struct stmmac_rx_queue { u32 rx_count_frames; u32 queue_index; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8964fc8a955f..c2ac88aaffed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2430,6 +2430,46 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) } } +static void stmmac_xsk_request_timestamp(void *_priv) +{ + struct stmmac_metadata_request *meta_req = _priv; + + stmmac_enable_tx_timestamp(meta_req->priv, meta_req->tx_desc); + *meta_req->set_ic = true; +} + +static u64 stmmac_xsk_fill_timestamp(void *_priv) +{ + struct stmmac_xsk_tx_complete *tx_compl = _priv; + struct stmmac_priv *priv = tx_compl->priv; + struct dma_desc *desc = tx_compl->desc; + bool found = false; + u64 ns = 0; + + if (!priv->hwts_tx_en) + return 0; + + /* check tx tstamp status */ + if (stmmac_get_tx_timestamp_status(priv, desc)) { + stmmac_get_timestamp(priv, desc, priv->adv_ts, &ns); + found = true; + } else if (!stmmac_get_mac_tx_timestamp(priv, priv->hw, &ns)) { + found = true; + } + + if (found) { + ns -= priv->plat->cdc_error_adj; + return ns_to_ktime(ns); + } + + return 0; +} + +static const struct xsk_tx_metadata_ops stmmac_xsk_tx_metadata_ops = { + .tmo_request_timestamp = stmmac_xsk_request_timestamp, + .tmo_fill_timestamp = stmmac_xsk_fill_timestamp, +}; + static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) { struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); @@ -2449,6 +2489,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) budget = min(budget, stmmac_tx_avail(priv, queue)); while (budget-- > 0) { + struct stmmac_metadata_request meta_req; + struct xsk_tx_metadata *meta = NULL; dma_addr_t dma_addr; bool set_ic; @@ -2472,6 +2514,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) tx_desc = tx_q->dma_tx + entry; dma_addr = xsk_buff_raw_get_dma(pool, xdp_desc.addr); + meta = xsk_buff_get_metadata(pool, xdp_desc.addr); xsk_buff_raw_dma_sync_for_device(pool, dma_addr, xdp_desc.len); tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_XSK_TX; @@ -2499,6 +2542,11 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) else set_ic = false; + meta_req.priv = priv; + meta_req.tx_desc = tx_desc; + meta_req.set_ic = &set_ic; + xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops, + &meta_req); if (set_ic) { tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, tx_desc); @@ -2511,6 +2559,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) stmmac_enable_dma_transmission(priv, priv->ioaddr); + xsk_tx_metadata_to_compl(meta, + &tx_q->tx_skbuff_dma[entry].xsk_meta); + tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); entry = tx_q->cur_tx; } @@ -2620,8 +2671,18 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue, } else { tx_packets++; } - if (skb) + if (skb) { stmmac_get_tx_hwtstamp(priv, p, skb); + } else { + struct stmmac_xsk_tx_complete tx_compl = { + .priv = priv, + .desc = p, + }; + + xsk_tx_metadata_complete(&tx_q->tx_skbuff_dma[entry].xsk_meta, + &stmmac_xsk_tx_metadata_ops, + &tx_compl); + } } if (likely(tx_q->tx_skbuff_dma[entry].buf && @@ -7464,6 +7525,7 @@ int stmmac_dvr_probe(struct device *device, ndev->netdev_ops = &stmmac_netdev_ops; ndev->xdp_metadata_ops = &stmmac_xdp_metadata_ops; + ndev->xsk_tx_metadata_ops = &stmmac_xsk_tx_metadata_ops; ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; From 9620e956d5b592d305728144931e89d780a598aa Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:12 -0800 Subject: [PATCH 1884/7721] xsk: Document tx_metadata_len layout - how to use - how to query features - pointers to the examples Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-7-sdf@google.com Signed-off-by: Alexei Starovoitov --- Documentation/networking/index.rst | 1 + Documentation/networking/xdp-rx-metadata.rst | 2 + Documentation/networking/xsk-tx-metadata.rst | 70 ++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 Documentation/networking/xsk-tx-metadata.rst diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 683eb42309cc..a297a894b366 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -123,6 +123,7 @@ Contents: xfrm_sync xfrm_sysctl xdp-rx-metadata + xsk-tx-metadata .. only:: subproject and html diff --git a/Documentation/networking/xdp-rx-metadata.rst b/Documentation/networking/xdp-rx-metadata.rst index 205696780b78..e3e9420fd817 100644 --- a/Documentation/networking/xdp-rx-metadata.rst +++ b/Documentation/networking/xdp-rx-metadata.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + =============== XDP RX Metadata =============== diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst new file mode 100644 index 000000000000..4f376560b23f --- /dev/null +++ b/Documentation/networking/xsk-tx-metadata.rst @@ -0,0 +1,70 @@ +================== +AF_XDP TX Metadata +================== + +This document describes how to enable offloads when transmitting packets +via :doc:`af_xdp`. Refer to :doc:`xdp-rx-metadata` on how to access similar +metadata on the receive side. + +General Design +============== + +The headroom for the metadata is reserved via ``tx_metadata_len`` in +``struct xdp_umem_reg``. The metadata length is therefore the same for +every socket that shares the same umem. The metadata layout is a fixed UAPI, +refer to ``union xsk_tx_metadata`` in ``include/uapi/linux/if_xdp.h``. +Thus, generally, the ``tx_metadata_len`` field above should contain +``sizeof(union xsk_tx_metadata)``. + +The headroom and the metadata itself should be located right before +``xdp_desc->addr`` in the umem frame. Within a frame, the metadata +layout is as follows:: + + tx_metadata_len + / \ + +-----------------+---------+----------------------------+ + | xsk_tx_metadata | padding | payload | + +-----------------+---------+----------------------------+ + ^ + | + xdp_desc->addr + +An AF_XDP application can request headrooms larger than ``sizeof(struct +xsk_tx_metadata)``. The kernel will ignore the padding (and will still +use ``xdp_desc->addr - tx_metadata_len`` to locate +the ``xsk_tx_metadata``). For the frames that shouldn't carry +any metadata (i.e., the ones that don't have ``XDP_TX_METADATA`` option), +the metadata area is ignored by the kernel as well. + +The flags field enables the particular offload: + +- ``XDP_TXMD_FLAGS_TIMESTAMP``: requests the device to put transmission + timestamp into ``tx_timestamp`` field of ``union xsk_tx_metadata``. +- ``XDP_TXMD_FLAGS_CHECKSUM``: requests the device to calculate L4 + checksum. ``csum_start`` specifies byte offset of where the checksumming + should start and ``csum_offset`` specifies byte offset where the + device should store the computed checksum. + +Besides the flags above, in order to trigger the offloads, the first +packet's ``struct xdp_desc`` descriptor should set ``XDP_TX_METADATA`` +bit in the ``options`` field. Also note that in a multi-buffer packet +only the first chunk should carry the metadata. + +Querying Device Capabilities +============================ + +Every devices exports its offloads capabilities via netlink netdev family. +Refer to ``xsk-flags`` features bitmask in +``Documentation/netlink/specs/netdev.yaml``. + +- ``tx-timestamp``: device supports ``XDP_TXMD_FLAGS_TIMESTAMP`` +- ``tx-checksum``: device supports ``XDP_TXMD_FLAGS_CHECKSUM`` + +See ``tools/net/ynl/samples/netdev.c`` on how to query this information. + +Example +======= + +See ``tools/testing/selftests/bpf/xdp_hw_metadata.c`` for an example +program that handles TX metadata. Also see https://github.com/fomichev/xskgen +for a more bare-bones example. From ce59f9686e0eca19431571c7403394a6c36371e2 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:13 -0800 Subject: [PATCH 1885/7721] xsk: Validate xsk_tx_metadata flags Accept only the flags that the kernel knows about to make sure we can extend this field in the future. Note that only in XDP_COPY mode we propagate the error signal back to the user (via sendmsg). For zerocopy mode we silently skip the metadata for the descriptors that have wrong flags (since we process the descriptors deep in the driver). Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-8-sdf@google.com Signed-off-by: Alexei Starovoitov --- include/net/xdp_sock_drv.h | 23 ++++++++++++++++++++++- net/xdp/xsk.c | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h index e2558ac3e195..81e02de3f453 100644 --- a/include/net/xdp_sock_drv.h +++ b/include/net/xdp_sock_drv.h @@ -165,12 +165,28 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) return xp_raw_get_data(pool, addr); } +#define XDP_TXMD_FLAGS_VALID ( \ + XDP_TXMD_FLAGS_TIMESTAMP | \ + XDP_TXMD_FLAGS_CHECKSUM | \ + 0) + +static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta) +{ + return !(meta->flags & ~XDP_TXMD_FLAGS_VALID); +} + static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr) { + struct xsk_tx_metadata *meta; + if (!pool->tx_metadata_len) return NULL; - return xp_raw_get_data(pool, addr) - pool->tx_metadata_len; + meta = xp_raw_get_data(pool, addr) - pool->tx_metadata_len; + if (unlikely(!xsk_buff_valid_tx_metadata(meta))) + return NULL; /* no way to signal the error to the user */ + + return meta; } static inline void xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp, struct xsk_buff_pool *pool) @@ -332,6 +348,11 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) return NULL; } +static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta) +{ + return false; +} + static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr) { return NULL; diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index e83ade32f1fd..d66ba9d6154f 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -728,6 +728,10 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, } meta = buffer - xs->pool->tx_metadata_len; + if (unlikely(!xsk_buff_valid_tx_metadata(meta))) { + err = -EINVAL; + goto free_err; + } if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) { if (unlikely(meta->request.csum_start + From 11614723af26e7c32fcb704d8f30fdf60c1122dc Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:14 -0800 Subject: [PATCH 1886/7721] xsk: Add option to calculate TX checksum in SW For XDP_COPY mode, add a UMEM option XDP_UMEM_TX_SW_CSUM to call skb_checksum_help in transmit path. Might be useful to debugging issues with real hardware. I also use this mode in the selftests. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-9-sdf@google.com Signed-off-by: Alexei Starovoitov --- Documentation/networking/xsk-tx-metadata.rst | 9 +++++++++ include/net/xsk_buff_pool.h | 1 + include/uapi/linux/if_xdp.h | 8 +++++++- net/xdp/xdp_umem.c | 7 ++++++- net/xdp/xsk.c | 6 ++++++ net/xdp/xsk_buff_pool.c | 1 + tools/include/uapi/linux/if_xdp.h | 8 +++++++- 7 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst index 4f376560b23f..97ecfa480d00 100644 --- a/Documentation/networking/xsk-tx-metadata.rst +++ b/Documentation/networking/xsk-tx-metadata.rst @@ -50,6 +50,15 @@ packet's ``struct xdp_desc`` descriptor should set ``XDP_TX_METADATA`` bit in the ``options`` field. Also note that in a multi-buffer packet only the first chunk should carry the metadata. +Software TX Checksum +==================== + +For development and testing purposes its possible to pass +``XDP_UMEM_TX_SW_CSUM`` flag to ``XDP_UMEM_REG`` UMEM registration call. +In this case, when running in ``XDK_COPY`` mode, the TX checksum +is calculated on the CPU. Do not enable this option in production because +it will negatively affect performance. + Querying Device Capabilities ============================ diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h index 97f5cc10d79e..8d48d37ab7c0 100644 --- a/include/net/xsk_buff_pool.h +++ b/include/net/xsk_buff_pool.h @@ -83,6 +83,7 @@ struct xsk_buff_pool { bool uses_need_wakeup; bool dma_need_sync; bool unaligned; + bool tx_sw_csum; void *addrs; /* Mutual exclusion of the completion ring in the SKB mode. Two cases to protect: * NAPI TX thread and sendmsg error paths in the SKB destructor callback and when diff --git a/include/uapi/linux/if_xdp.h b/include/uapi/linux/if_xdp.h index 95de66d5a26c..d31698410410 100644 --- a/include/uapi/linux/if_xdp.h +++ b/include/uapi/linux/if_xdp.h @@ -33,7 +33,13 @@ #define XDP_USE_SG (1 << 4) /* Flags for xsk_umem_config flags */ -#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) +#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) + +/* Force checksum calculation in software. Can be used for testing or + * working around potential HW issues. This option causes performance + * degradation and only works in XDP_COPY mode. + */ +#define XDP_UMEM_TX_SW_CSUM (1 << 1) struct sockaddr_xdp { __u16 sxdp_family; diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index 946a687fb8e8..caa340134b0e 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -148,6 +148,11 @@ static int xdp_umem_account_pages(struct xdp_umem *umem) return 0; } +#define XDP_UMEM_FLAGS_VALID ( \ + XDP_UMEM_UNALIGNED_CHUNK_FLAG | \ + XDP_UMEM_TX_SW_CSUM | \ + 0) + static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr) { bool unaligned_chunks = mr->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG; @@ -167,7 +172,7 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr) return -EINVAL; } - if (mr->flags & ~XDP_UMEM_UNALIGNED_CHUNK_FLAG) + if (mr->flags & ~XDP_UMEM_FLAGS_VALID) return -EINVAL; if (!unaligned_chunks && !is_power_of_2(chunk_size)) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index d66ba9d6154f..281d49b4fca4 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -744,6 +744,12 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, skb->csum_start = hr + meta->request.csum_start; skb->csum_offset = meta->request.csum_offset; skb->ip_summed = CHECKSUM_PARTIAL; + + if (unlikely(xs->pool->tx_sw_csum)) { + err = skb_checksum_help(skb); + if (err) + goto free_err; + } } } } diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index 386eddcdf837..4f6f538a5462 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -86,6 +86,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs, pool->umem = umem; pool->addrs = umem->addrs; pool->tx_metadata_len = umem->tx_metadata_len; + pool->tx_sw_csum = umem->flags & XDP_UMEM_TX_SW_CSUM; INIT_LIST_HEAD(&pool->free_list); INIT_LIST_HEAD(&pool->xskb_list); INIT_LIST_HEAD(&pool->xsk_tx_list); diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index d0882edc1642..638c606dfa74 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -33,7 +33,13 @@ #define XDP_USE_SG (1 << 4) /* Flags for xsk_umem_config flags */ -#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) +#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) + +/* Force checksum calculation in software. Can be used for testing or + * working around potential HW issues. This option causes performance + * degradation and only works in XDP_COPY mode. + */ +#define XDP_UMEM_TX_SW_CSUM (1 << 1) struct sockaddr_xdp { __u16 sxdp_family; From df3ed0003ec4994ce8ed4818c435c481281df89e Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:15 -0800 Subject: [PATCH 1887/7721] selftests/xsk: Support tx_metadata_len Add new config field and propagate to UMEM registration setsockopt. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-10-sdf@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xsk.c | 3 +++ tools/testing/selftests/bpf/xsk.h | 1 + 2 files changed, 4 insertions(+) diff --git a/tools/testing/selftests/bpf/xsk.c b/tools/testing/selftests/bpf/xsk.c index e574711eeb84..25d568abf0f2 100644 --- a/tools/testing/selftests/bpf/xsk.c +++ b/tools/testing/selftests/bpf/xsk.c @@ -115,6 +115,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg, cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM; cfg->flags = XSK_UMEM__DEFAULT_FLAGS; + cfg->tx_metadata_len = 0; return; } @@ -123,6 +124,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg, cfg->frame_size = usr_cfg->frame_size; cfg->frame_headroom = usr_cfg->frame_headroom; cfg->flags = usr_cfg->flags; + cfg->tx_metadata_len = usr_cfg->tx_metadata_len; } static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg, @@ -252,6 +254,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, mr.chunk_size = umem->config.frame_size; mr.headroom = umem->config.frame_headroom; mr.flags = umem->config.flags; + mr.tx_metadata_len = umem->config.tx_metadata_len; err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr)); if (err) { diff --git a/tools/testing/selftests/bpf/xsk.h b/tools/testing/selftests/bpf/xsk.h index 771570bc3731..93c2cc413cfc 100644 --- a/tools/testing/selftests/bpf/xsk.h +++ b/tools/testing/selftests/bpf/xsk.h @@ -200,6 +200,7 @@ struct xsk_umem_config { __u32 frame_size; __u32 frame_headroom; __u32 flags; + __u32 tx_metadata_len; }; int xsk_attach_xdp_program(struct bpf_program *prog, int ifindex, u32 xdp_flags); From f6642de0c3e94d3ef6f44e127d11fcf4138873f7 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:16 -0800 Subject: [PATCH 1888/7721] selftests/bpf: Add csum helpers Checksum helpers will be used to calculate pseudo-header checksum in AF_XDP metadata selftests. The helpers are mirroring existing kernel ones: - csum_tcpudp_magic : IPv4 pseudo header csum - csum_ipv6_magic : IPv6 pseudo header csum - csum_fold : fold csum and do one's complement Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-11-sdf@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/network_helpers.h | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 34f1200a781b..94b9be24e39b 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -71,4 +71,47 @@ struct nstoken; */ struct nstoken *open_netns(const char *name); void close_netns(struct nstoken *token); + +static __u16 csum_fold(__u32 csum) +{ + csum = (csum & 0xffff) + (csum >> 16); + csum = (csum & 0xffff) + (csum >> 16); + + return (__u16)~csum; +} + +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + + s += (__u32)saddr; + s += (__u32)daddr; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + +static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + int i; + + for (i = 0; i < 4; i++) + s += (__u32)saddr->s6_addr32[i]; + for (i = 0; i < 4; i++) + s += (__u32)daddr->s6_addr32[i]; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + #endif From 40808a237d9c8fcaa3eaeefe2ac59e4733907478 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:17 -0800 Subject: [PATCH 1889/7721] selftests/bpf: Add TX side to xdp_metadata Request TX timestamp and make sure it's not empty. Request TX checksum offload (SW-only) and make sure it's resolved to the correct one. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-12-sdf@google.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/xdp_metadata.c | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c index 4439ba9392f8..33cdf88efa6b 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c @@ -56,7 +56,8 @@ static int open_xsk(int ifindex, struct xsk *xsk) .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, - .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG, + .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG | XDP_UMEM_TX_SW_CSUM, + .tx_metadata_len = sizeof(struct xsk_tx_metadata), }; __u32 idx; u64 addr; @@ -138,6 +139,7 @@ static void ip_csum(struct iphdr *iph) static int generate_packet(struct xsk *xsk, __u16 dst_port) { + struct xsk_tx_metadata *meta; struct xdp_desc *tx_desc; struct udphdr *udph; struct ethhdr *eth; @@ -151,10 +153,14 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) return -1; tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx); - tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE; + tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata); printf("%p: tx_desc[%u]->addr=%llx\n", xsk, idx, tx_desc->addr); data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr); + meta = data - sizeof(struct xsk_tx_metadata); + memset(meta, 0, sizeof(*meta)); + meta->flags = XDP_TXMD_FLAGS_TIMESTAMP; + eth = data; iph = (void *)(eth + 1); udph = (void *)(iph + 1); @@ -178,11 +184,17 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) udph->source = htons(AF_XDP_SOURCE_PORT); udph->dest = htons(dst_port); udph->len = htons(sizeof(*udph) + UDP_PAYLOAD_BYTES); - udph->check = 0; + udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); memset(udph + 1, 0xAA, UDP_PAYLOAD_BYTES); + meta->flags |= XDP_TXMD_FLAGS_CHECKSUM; + meta->request.csum_start = sizeof(*eth) + sizeof(*iph); + meta->request.csum_offset = offsetof(struct udphdr, check); + tx_desc->len = sizeof(*eth) + sizeof(*iph) + sizeof(*udph) + UDP_PAYLOAD_BYTES; + tx_desc->options |= XDP_TX_METADATA; xsk_ring_prod__submit(&xsk->tx, 1); ret = sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0); @@ -194,13 +206,21 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) static void complete_tx(struct xsk *xsk) { - __u32 idx; + struct xsk_tx_metadata *meta; __u64 addr; + void *data; + __u32 idx; if (ASSERT_EQ(xsk_ring_cons__peek(&xsk->comp, 1, &idx), 1, "xsk_ring_cons__peek")) { addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx); printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr); + + data = xsk_umem__get_data(xsk->umem_area, addr); + meta = data - sizeof(struct xsk_tx_metadata); + + ASSERT_NEQ(meta->completion.tx_timestamp, 0, "tx_timestamp"); + xsk_ring_cons__release(&xsk->comp, 1); } } @@ -221,6 +241,7 @@ static int verify_xsk_metadata(struct xsk *xsk) const struct xdp_desc *rx_desc; struct pollfd fds = {}; struct xdp_meta *meta; + struct udphdr *udph; struct ethhdr *eth; struct iphdr *iph; __u64 comp_addr; @@ -257,6 +278,7 @@ static int verify_xsk_metadata(struct xsk *xsk) ASSERT_EQ(eth->h_proto, htons(ETH_P_IP), "eth->h_proto"); iph = (void *)(eth + 1); ASSERT_EQ((int)iph->version, 4, "iph->version"); + udph = (void *)(iph + 1); /* custom metadata */ @@ -270,6 +292,9 @@ static int verify_xsk_metadata(struct xsk *xsk) ASSERT_EQ(meta->rx_hash_type, 0, "rx_hash_type"); + /* checksum offload */ + ASSERT_EQ(udph->check, htons(0x721c), "csum"); + xsk_ring_cons__release(&xsk->rx, 1); refill_rx(xsk, comp_addr); From 12b4b7963d3cca253db3c31aa7611b988699e30f Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:18 -0800 Subject: [PATCH 1890/7721] selftests/bpf: Convert xdp_hw_metadata to XDP_USE_NEED_WAKEUP This is the recommended way to run AF_XDP, so let's use it in the test. Also, some unrelated changes to now blow up the log too much: - change default mode to zerocopy and add -c to use copy mode - small fixes for the flags/sizes/prints - add print_tstamp_delta to print timestamp + reference Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-13-sdf@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xdp_hw_metadata.c | 71 +++++++++++++------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index c3ba40d0b9de..4484b17c7a56 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -32,7 +32,7 @@ #include "xdp_metadata.h" -#define UMEM_NUM 16 +#define UMEM_NUM 256 #define UMEM_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE #define UMEM_SIZE (UMEM_FRAME_SIZE * UMEM_NUM) #define XDP_FLAGS (XDP_FLAGS_DRV_MODE | XDP_FLAGS_REPLACE) @@ -48,7 +48,7 @@ struct xsk { }; struct xdp_hw_metadata *bpf_obj; -__u16 bind_flags = XDP_COPY; +__u16 bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY; struct xsk *rx_xsk; const char *ifname; int ifindex; @@ -68,7 +68,7 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id) .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, - .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG, + .flags = XSK_UMEM__DEFAULT_FLAGS, }; __u32 idx; u64 addr; @@ -110,7 +110,7 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id) for (i = 0; i < UMEM_NUM / 2; i++) { addr = (UMEM_NUM / 2 + i) * UMEM_FRAME_SIZE; printf("%p: rx_desc[%d] -> %lx\n", xsk, i, addr); - *xsk_ring_prod__fill_addr(&xsk->fill, i) = addr; + *xsk_ring_prod__fill_addr(&xsk->fill, idx + i) = addr; } xsk_ring_prod__submit(&xsk->fill, ret); @@ -131,12 +131,22 @@ static void refill_rx(struct xsk *xsk, __u64 addr) __u32 idx; if (xsk_ring_prod__reserve(&xsk->fill, 1, &idx) == 1) { - printf("%p: complete idx=%u addr=%llx\n", xsk, idx, addr); + printf("%p: complete rx idx=%u addr=%llx\n", xsk, idx, addr); *xsk_ring_prod__fill_addr(&xsk->fill, idx) = addr; xsk_ring_prod__submit(&xsk->fill, 1); } } +static int kick_tx(struct xsk *xsk) +{ + return sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0); +} + +static int kick_rx(struct xsk *xsk) +{ + return recvfrom(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, NULL); +} + #define NANOSEC_PER_SEC 1000000000 /* 10^9 */ static __u64 gettime(clockid_t clock_id) { @@ -152,6 +162,17 @@ static __u64 gettime(clockid_t clock_id) return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec; } +static void print_tstamp_delta(const char *name, const char *refname, + __u64 tstamp, __u64 reference) +{ + __s64 delta = (__s64)reference - (__s64)tstamp; + + printf("%s: %llu (sec:%0.4f) delta to %s sec:%0.4f (%0.3f usec)\n", + name, tstamp, (double)tstamp / NANOSEC_PER_SEC, refname, + (double)delta / NANOSEC_PER_SEC, + (double)delta / 1000); +} + static void verify_xdp_metadata(void *data, clockid_t clock_id) { struct xdp_meta *meta; @@ -167,22 +188,13 @@ static void verify_xdp_metadata(void *data, clockid_t clock_id) printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp, (double)meta->rx_timestamp / NANOSEC_PER_SEC); if (meta->rx_timestamp) { - __u64 usr_clock = gettime(clock_id); - __u64 xdp_clock = meta->xdp_timestamp; - __s64 delta_X = xdp_clock - meta->rx_timestamp; - __s64 delta_X2U = usr_clock - xdp_clock; + __u64 ref_tstamp = gettime(clock_id); - printf("XDP RX-time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", - xdp_clock, (double)xdp_clock / NANOSEC_PER_SEC, - (double)delta_X / NANOSEC_PER_SEC, - (double)delta_X / 1000); - - printf("AF_XDP time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", - usr_clock, (double)usr_clock / NANOSEC_PER_SEC, - (double)delta_X2U / NANOSEC_PER_SEC, - (double)delta_X2U / 1000); + print_tstamp_delta("HW RX-time", "User RX-time", + meta->rx_timestamp, ref_tstamp); + print_tstamp_delta("XDP RX-time", "User RX-time", + meta->xdp_timestamp, ref_tstamp); } - } static void verify_skb_metadata(int fd) @@ -252,6 +264,13 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t while (true) { errno = 0; + + for (i = 0; i < rxq; i++) { + ret = kick_rx(&rx_xsk[i]); + if (ret) + printf("kick_rx ret=%d\n", ret); + } + ret = poll(fds, rxq + 1, 1000); printf("poll: %d (%d) skip=%llu fail=%llu redir=%llu\n", ret, errno, bpf_obj->bss->pkts_skip, @@ -420,8 +439,9 @@ static void print_usage(void) { const char *usage = "Usage: xdp_hw_metadata [OPTIONS] [IFNAME]\n" - " -m Enable multi-buffer XDP for larger MTU\n" + " -c Run in copy mode (zerocopy is default)\n" " -h Display this help and exit\n\n" + " -m Enable multi-buffer XDP for larger MTU\n" "Generate test packets on the other machine with:\n" " echo -n xdp | nc -u -q1 9091\n"; @@ -432,14 +452,19 @@ static void read_args(int argc, char *argv[]) { int opt; - while ((opt = getopt(argc, argv, "mh")) != -1) { + while ((opt = getopt(argc, argv, "chm")) != -1) { switch (opt) { - case 'm': - bind_flags |= XDP_USE_SG; + case 'c': + bind_flags &= ~XDP_USE_NEED_WAKEUP; + bind_flags &= ~XDP_ZEROCOPY; + bind_flags |= XDP_COPY; break; case 'h': print_usage(); exit(0); + case 'm': + bind_flags |= XDP_USE_SG; + break; case '?': if (isprint(optopt)) fprintf(stderr, "Unknown option: -%c\n", optopt); From 60523115c1b10c8855492d84c1ba88af452e221c Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:19 -0800 Subject: [PATCH 1891/7721] selftests/bpf: Add TX side to xdp_hw_metadata When we get a packet on port 9091, we swap src/dst and send it out. At this point we also request the timestamp and checksum offloads. Checksum offload is verified by looking at the tcpdump on the other side. The tool prints pseudo-header csum and the final one it expects. The final checksum actually matches the incoming packets checksum because we only flip the src/dst and don't change the payload. Some other related changes: - switched to zerocopy mode by default; new flag can be used to force old behavior - request fixed tx_metadata_len headroom - some other small fixes (umem size, fill idx+i, etc) mvbz3:~# ./xdp_hw_metadata eth3 ... xsk_ring_cons__peek: 1 0x19546f8: rx_desc[0]->addr=80100 addr=80100 comp_addr=80100 rx_hash: 0x80B7EA8B with RSS type:0x2A rx_timestamp: 1697580171852147395 (sec:1697580171.8521) HW RX-time: 1697580171852147395 (sec:1697580171.8521), delta to User RX-time sec:0.2797 (279673.082 usec) XDP RX-time: 1697580172131699047 (sec:1697580172.1317), delta to User RX-time sec:0.0001 (121.430 usec) 0x19546f8: ping-pong with csum=3b8e (want d862) csum_start=54 csum_offset=6 0x19546f8: complete tx idx=0 addr=8 tx_timestamp: 1697580172056756493 (sec:1697580172.0568) HW TX-complete-time: 1697580172056756493 (sec:1697580172.0568), delta to User TX-complete-time sec:0.0852 (85175.537 usec) XDP RX-time: 1697580172131699047 (sec:1697580172.1317), delta to User TX-complete-time sec:0.0102 (10232.983 usec) HW RX-time: 1697580171852147395 (sec:1697580171.8521), delta to HW TX-complete-time sec:0.2046 (204609.098 usec) 0x19546f8: complete rx idx=128 addr=80100 mvbz4:~# nc -Nu -q1 ${MVBZ3_LINK_LOCAL_IP}%eth3 9091 mvbz4:~# tcpdump -vvx -i eth3 udp tcpdump: listening on eth3, link-type EN10MB (Ethernet), snapshot length 262144 bytes 12:26:09.301074 IP6 (flowlabel 0x35fa5, hlim 127, next-header UDP (17) payload length: 11) fe80::1270:fdff:fe48:1087.55807 > fe80::1270:fdff:fe48:1077.9091: [bad udp cksum 0x3b8e -> 0xde7e!] UDP, length 3 0x0000: 6003 5fa5 000b 117f fe80 0000 0000 0000 0x0010: 1270 fdff fe48 1087 fe80 0000 0000 0000 0x0020: 1270 fdff fe48 1077 d9ff 2383 000b 3b8e 0x0030: 7864 70 12:26:09.301976 IP6 (flowlabel 0x35fa5, hlim 127, next-header UDP (17) payload length: 11) fe80::1270:fdff:fe48:1077.9091 > fe80::1270:fdff:fe48:1087.55807: [udp sum ok] UDP, length 3 0x0000: 6003 5fa5 000b 117f fe80 0000 0000 0000 0x0010: 1270 fdff fe48 1077 fe80 0000 0000 0000 0x0020: 1270 fdff fe48 1087 2383 d9ff 000b de7e 0x0030: 7864 70 Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-14-sdf@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xdp_hw_metadata.c | 164 +++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index 4484b17c7a56..3291625ba4fb 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -10,7 +10,9 @@ * - rx_hash * * TX: - * - TBD + * - UDP 9091 packets trigger TX reply + * - TX HW timestamp is requested and reported back upon completion + * - TX checksum is requested */ #include @@ -24,11 +26,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include "xdp_metadata.h" @@ -53,6 +58,9 @@ struct xsk *rx_xsk; const char *ifname; int ifindex; int rxq; +bool skip_tx; +__u64 last_hw_rx_timestamp; +__u64 last_xdp_rx_timestamp; void test__fail(void) { /* for network_helpers.c */ } @@ -69,6 +77,7 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id) .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, .flags = XSK_UMEM__DEFAULT_FLAGS, + .tx_metadata_len = sizeof(struct xsk_tx_metadata), }; __u32 idx; u64 addr; @@ -185,15 +194,19 @@ static void verify_xdp_metadata(void *data, clockid_t clock_id) printf("rx_hash: 0x%X with RSS type:0x%X\n", meta->rx_hash, meta->rx_hash_type); - printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp, - (double)meta->rx_timestamp / NANOSEC_PER_SEC); if (meta->rx_timestamp) { __u64 ref_tstamp = gettime(clock_id); + /* store received timestamps to calculate a delta at tx */ + last_hw_rx_timestamp = meta->rx_timestamp; + last_xdp_rx_timestamp = meta->xdp_timestamp; + print_tstamp_delta("HW RX-time", "User RX-time", meta->rx_timestamp, ref_tstamp); print_tstamp_delta("XDP RX-time", "User RX-time", meta->xdp_timestamp, ref_tstamp); + } else { + printf("No rx_timestamp\n"); } } @@ -242,6 +255,129 @@ static void verify_skb_metadata(int fd) printf("skb hwtstamp is not found!\n"); } +static bool complete_tx(struct xsk *xsk, clockid_t clock_id) +{ + struct xsk_tx_metadata *meta; + __u64 addr; + void *data; + __u32 idx; + + if (!xsk_ring_cons__peek(&xsk->comp, 1, &idx)) + return false; + + addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx); + data = xsk_umem__get_data(xsk->umem_area, addr); + meta = data - sizeof(struct xsk_tx_metadata); + + printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr); + + if (meta->completion.tx_timestamp) { + __u64 ref_tstamp = gettime(clock_id); + + print_tstamp_delta("HW TX-complete-time", "User TX-complete-time", + meta->completion.tx_timestamp, ref_tstamp); + print_tstamp_delta("XDP RX-time", "User TX-complete-time", + last_xdp_rx_timestamp, ref_tstamp); + print_tstamp_delta("HW RX-time", "HW TX-complete-time", + last_hw_rx_timestamp, meta->completion.tx_timestamp); + } else { + printf("No tx_timestamp\n"); + } + + xsk_ring_cons__release(&xsk->comp, 1); + + return true; +} + +#define swap(a, b, len) do { \ + for (int i = 0; i < len; i++) { \ + __u8 tmp = ((__u8 *)a)[i]; \ + ((__u8 *)a)[i] = ((__u8 *)b)[i]; \ + ((__u8 *)b)[i] = tmp; \ + } \ +} while (0) + +static void ping_pong(struct xsk *xsk, void *rx_packet, clockid_t clock_id) +{ + struct xsk_tx_metadata *meta; + struct ipv6hdr *ip6h = NULL; + struct iphdr *iph = NULL; + struct xdp_desc *tx_desc; + struct udphdr *udph; + struct ethhdr *eth; + __sum16 want_csum; + void *data; + __u32 idx; + int ret; + int len; + + ret = xsk_ring_prod__reserve(&xsk->tx, 1, &idx); + if (ret != 1) { + printf("%p: failed to reserve tx slot\n", xsk); + return; + } + + tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx); + tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata); + data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr); + + meta = data - sizeof(struct xsk_tx_metadata); + memset(meta, 0, sizeof(*meta)); + meta->flags = XDP_TXMD_FLAGS_TIMESTAMP; + + eth = rx_packet; + + if (eth->h_proto == htons(ETH_P_IP)) { + iph = (void *)(eth + 1); + udph = (void *)(iph + 1); + } else if (eth->h_proto == htons(ETH_P_IPV6)) { + ip6h = (void *)(eth + 1); + udph = (void *)(ip6h + 1); + } else { + printf("%p: failed to detect IP version for ping pong %04x\n", xsk, eth->h_proto); + xsk_ring_prod__cancel(&xsk->tx, 1); + return; + } + + len = ETH_HLEN; + if (ip6h) + len += sizeof(*ip6h) + ntohs(ip6h->payload_len); + if (iph) + len += ntohs(iph->tot_len); + + swap(eth->h_dest, eth->h_source, ETH_ALEN); + if (iph) + swap(&iph->saddr, &iph->daddr, 4); + else + swap(&ip6h->saddr, &ip6h->daddr, 16); + swap(&udph->source, &udph->dest, 2); + + want_csum = udph->check; + if (ip6h) + udph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); + else + udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); + + meta->flags |= XDP_TXMD_FLAGS_CHECKSUM; + if (iph) + meta->request.csum_start = sizeof(*eth) + sizeof(*iph); + else + meta->request.csum_start = sizeof(*eth) + sizeof(*ip6h); + meta->request.csum_offset = offsetof(struct udphdr, check); + + printf("%p: ping-pong with csum=%04x (want %04x) csum_start=%d csum_offset=%d\n", + xsk, ntohs(udph->check), ntohs(want_csum), + meta->request.csum_start, meta->request.csum_offset); + + memcpy(data, rx_packet, len); /* don't share umem chunk for simplicity */ + tx_desc->options |= XDP_TX_METADATA; + tx_desc->len = len; + + xsk_ring_prod__submit(&xsk->tx, 1); +} + static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id) { const struct xdp_desc *rx_desc; @@ -307,6 +443,22 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr), clock_id); first_seg = false; + + if (!skip_tx) { + /* mirror first chunk back */ + ping_pong(xsk, xsk_umem__get_data(xsk->umem_area, addr), + clock_id); + + ret = kick_tx(xsk); + if (ret) + printf("kick_tx ret=%d\n", ret); + + for (int j = 0; j < 500; j++) { + if (complete_tx(xsk, clock_id)) + break; + usleep(10*1000); + } + } } xsk_ring_cons__release(&xsk->rx, 1); @@ -442,6 +594,7 @@ static void print_usage(void) " -c Run in copy mode (zerocopy is default)\n" " -h Display this help and exit\n\n" " -m Enable multi-buffer XDP for larger MTU\n" + " -r Don't generate AF_XDP reply (rx metadata only)\n" "Generate test packets on the other machine with:\n" " echo -n xdp | nc -u -q1 9091\n"; @@ -452,7 +605,7 @@ static void read_args(int argc, char *argv[]) { int opt; - while ((opt = getopt(argc, argv, "chm")) != -1) { + while ((opt = getopt(argc, argv, "chmr")) != -1) { switch (opt) { case 'c': bind_flags &= ~XDP_USE_NEED_WAKEUP; @@ -465,6 +618,9 @@ static void read_args(int argc, char *argv[]) case 'm': bind_flags |= XDP_USE_SG; break; + case 'r': + skip_tx = true; + break; case '?': if (isprint(optopt)) fprintf(stderr, "Unknown option: -%c\n", optopt); From 0eec708ec3c2cb4076cd239605eb6d51e7c23e77 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 22 Nov 2023 11:15:23 -0800 Subject: [PATCH 1892/7721] drm/i915/pxp: Add drm_dbgs for critical PXP events. Debugging PXP issues can't even begin without understanding precedding sequence of important events. Add drm_dbg into the most important PXP events. v5 : - rebase. v4 : - rebase. v3 : - move gt_dbg to after mutex block in function i915_gsc_proxy_component_bind. (Vivaik) v2 : - remove __func__ since drm_dbg covers that (Jani). - add timeout dbg of the restart from front-end (Alan). Signed-off-by: Alan Previn Reviewed-by: Vivaik Balasubrawmanian Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20231122191523.58379-1-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c | 2 ++ drivers/gpu/drm/i915/pxp/intel_pxp.c | 15 ++++++++++++--- drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 5 +++-- drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 6 +++++- drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 1 + 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c index 5f138de3c14f..40817ebcca71 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c @@ -322,6 +322,7 @@ static int i915_gsc_proxy_component_bind(struct device *i915_kdev, gsc->proxy.component = data; gsc->proxy.component->mei_dev = mei_kdev; mutex_unlock(&gsc->proxy.mutex); + gt_dbg(gt, "GSC proxy mei component bound\n"); return 0; } @@ -342,6 +343,7 @@ static void i915_gsc_proxy_component_unbind(struct device *i915_kdev, with_intel_runtime_pm(&i915->runtime_pm, wakeref) intel_uncore_rmw(gt->uncore, HECI_H_CSR(MTL_GSC_HECI2_BASE), HECI_H_CSR_IE | HECI_H_CSR_RST, 0); + gt_dbg(gt, "GSC proxy mei component unbound\n"); } static const struct component_ops i915_gsc_proxy_component_ops = { diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index dc327cf40b5a..e11f562b1876 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -303,6 +303,8 @@ static int __pxp_global_teardown_final(struct intel_pxp *pxp) if (!pxp->arb_is_valid) return 0; + + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: teardown for suspend/fini"); /* * To ensure synchronous and coherent session teardown completion * in response to suspend or shutdown triggers, don't use a worker. @@ -324,6 +326,8 @@ static int __pxp_global_teardown_restart(struct intel_pxp *pxp) if (pxp->arb_is_valid) return 0; + + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: teardown for restart"); /* * The arb-session is currently inactive and we are doing a reset and restart * due to a runtime event. Use the worker that was designed for this. @@ -332,8 +336,11 @@ static int __pxp_global_teardown_restart(struct intel_pxp *pxp) timeout = intel_pxp_get_backend_timeout_ms(pxp); - if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) + if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: restart backend timed out (%d ms)", + timeout); return -ETIMEDOUT; + } return 0; } @@ -414,10 +421,12 @@ int intel_pxp_start(struct intel_pxp *pxp) int ret = 0; ret = intel_pxp_get_readiness_status(pxp, PXP_READINESS_TIMEOUT); - if (ret < 0) + if (ret < 0) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: tried but not-avail (%d)", ret); return ret; - else if (ret > 1) + } else if (ret > 1) { return -EIO; /* per UAPI spec, user may retry later */ + } mutex_lock(&pxp->arb_mutex); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c index 91e9622c07d0..d81750b9bdda 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c @@ -40,11 +40,12 @@ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { /* immediately mark PXP as inactive on termination */ intel_pxp_mark_termination_in_progress(pxp); - pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED; + pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED | + PXP_EVENT_TYPE_IRQ; } if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) - pxp->session_events |= PXP_TERMINATION_COMPLETE; + pxp->session_events |= PXP_TERMINATION_COMPLETE | PXP_EVENT_TYPE_IRQ; if (pxp->session_events) queue_work(system_unbound_wq, &pxp->session_work); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 0a3e66b0265e..091c86e03d1a 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -137,8 +137,10 @@ void intel_pxp_terminate(struct intel_pxp *pxp, bool post_invalidation_needs_res static void pxp_terminate_complete(struct intel_pxp *pxp) { /* Re-create the arb session after teardown handle complete */ - if (fetch_and_zero(&pxp->hw_state_invalidated)) + if (fetch_and_zero(&pxp->hw_state_invalidated)) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: creating arb_session after invalidation"); pxp_create_arb_session(pxp); + } complete_all(&pxp->termination); } @@ -157,6 +159,8 @@ static void pxp_session_work(struct work_struct *work) if (!events) return; + drm_dbg(>->i915->drm, "PXP: processing event-flags 0x%08x", events); + if (events & PXP_INVAL_REQUIRED) intel_pxp_invalidate(pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 7e11fa8034b2..07864b584cf4 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -124,6 +124,7 @@ struct intel_pxp { #define PXP_TERMINATION_REQUEST BIT(0) #define PXP_TERMINATION_COMPLETE BIT(1) #define PXP_INVAL_REQUIRED BIT(2) +#define PXP_EVENT_TYPE_IRQ BIT(3) }; #endif /* __INTEL_PXP_TYPES_H__ */ From b101d08451de6eaebd1a840e4885ce7ce73656ad Mon Sep 17 00:00:00 2001 From: Yuran Pereira Date: Fri, 17 Nov 2023 02:22:00 +0530 Subject: [PATCH 1893/7721] drm/nouveau: Removes unnecessary args check in nouveau_uvmm_sm_prepare Checking `args` after calling `op_map_prepare` is unnecessary since if `op_map_prepare` was to be called with NULL args, it would lead to a NULL pointer dereference, thus never hitting that check. Hence remove the check and add a note to remind users of this function to ensure that args != NULL when calling this function for a map operation as it was suggested by Danilo [1]. [1] https://lore.kernel.org/lkml/6a1ebcef-bade-45a0-9bd9-c05f0226eb88@redhat.com Suggested-by: Danilo Krummrich Signed-off-by: Yuran Pereira Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/GV1PR10MB65637F4BAABFE2D8E261E1DCE8B0A@GV1PR10MB6563.EURPRD10.PROD.OUTLOOK.COM --- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 4b236da79509..dae3baf707a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -608,6 +608,9 @@ op_unmap_prepare(struct drm_gpuva_op_unmap *u) drm_gpuva_unmap(u); } +/* + * Note: @args should not be NULL when calling for a map operation. + */ static int nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, struct nouveau_uvma_prealloc *new, @@ -628,7 +631,7 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, if (ret) goto unwind; - if (args && vmm_get_range) { + if (vmm_get_range) { ret = nouveau_uvmm_vmm_get(uvmm, vmm_get_start, vmm_get_range); if (ret) { From 698e19da2914a0021a088b2b5d101d1854862315 Mon Sep 17 00:00:00 2001 From: Zhanjun Dong Date: Mon, 13 Nov 2023 14:49:53 -0800 Subject: [PATCH 1894/7721] drm/i915: Skip pxp init if gt is wedged The gt wedged could be triggered by missing guc firmware file, HW not working, etc. Once triggered, it means all gt usage is dead, therefore we can't enable pxp under this fatal error condition. v2: Updated commit message. v3: Updated return code check. Signed-off-by: Zhanjun Dong Reviewed-by: Alan Previn Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20231113224953.378534-1-zhanjun.dong@intel.com --- drivers/gpu/drm/i915/i915_driver.c | 4 +++- drivers/gpu/drm/i915/pxp/intel_pxp.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index db6f7c30adde..8a17eb7f9321 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -804,7 +804,9 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_cleanup_modeset2; - intel_pxp_init(i915); + ret = intel_pxp_init(i915); + if (ret != -ENODEV) + drm_dbg(&i915->drm, "pxp init failed with %d\n", ret); ret = intel_display_driver_probe(i915); if (ret) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index e11f562b1876..75278e78ca90 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -199,6 +199,9 @@ int intel_pxp_init(struct drm_i915_private *i915) struct intel_gt *gt; bool is_full_feature = false; + if (intel_gt_is_wedged(to_gt(i915))) + return -ENOTCONN; + /* * NOTE: Get the ctrl_gt before checking intel_pxp_is_supported since * we still need it if PXP's backend tee transport is needed. From ee1eb9de81dbdbf078df659062e4df256a009627 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 29 Nov 2023 11:36:19 -0800 Subject: [PATCH 1895/7721] tools: ynl: fix build of the page-pool sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the "destroyed" field in the reply was not changed in the sample after we started calling it "detach_time". page-pool.c: In function ‘main’: page-pool.c:84:33: error: ‘struct ’ has no member named ‘destroyed’ 84 | if (pp->_present.destroyed) | ^ Fixes: 637567e4a3ef ("tools: ynl: add sample for getting page-pool information") Link: https://lore.kernel.org/r/20231129193622.2912353-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/samples/page-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c index 18d359713469..098b5190d0e5 100644 --- a/tools/net/ynl/samples/page-pool.c +++ b/tools/net/ynl/samples/page-pool.c @@ -81,7 +81,7 @@ int main(int argc, char **argv) struct stat *s = find_ifc(&a, pp->ifindex); count(s, 1, pp); - if (pp->_present.destroyed) + if (pp->_present.detach_time) count(s, 0, pp); } netdev_page_pool_get_list_free(pools); From 929003723f6d1998155bf0472f97d6c75c3db93f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 29 Nov 2023 11:36:20 -0800 Subject: [PATCH 1896/7721] tools: ynl: make sure we use local headers for page-pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building samples generates the following warning: In file included from page-pool.c:11: generated/netdev-user.h:21:45: warning: ‘enum netdev_xdp_rx_metadata’ declared inside parameter list will not be visible outside of this definition or declaration 21 | const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); | ^~~~~~~~~~~~~~~~~~~~~~ Our magic way of including uAPI headers assumes the sample name matches the family name. We need to copy the flags over. Fixes: 637567e4a3ef ("tools: ynl: add sample for getting page-pool information") Link: https://lore.kernel.org/r/20231129193622.2912353-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/samples/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 1afefc266b7a..28bdb1557a54 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -18,6 +18,8 @@ include $(wildcard *.d) all: $(BINS) +CFLAGS_page-pool=$(CFLAGS_netdev) + $(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) @echo -e '\tCC sample $@' @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o From 9cf9b57082411ad42d6d12c7b857e60add673877 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 29 Nov 2023 11:36:21 -0800 Subject: [PATCH 1897/7721] tools: ynl: order building samples after generated code Parallel builds of ynl: make -C tools/net/ynl/ -j 4 don't work correctly right now. samples get handled before generated, so build of samples does not notice that protos.a has changed. Order samples to be last. Link: https://lore.kernel.org/r/20231129193622.2912353-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index d664b36deb5b..da1aa10bbcc3 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -4,6 +4,8 @@ SUBDIRS = lib generated samples all: $(SUBDIRS) +samples: | lib generated + $(SUBDIRS): @if [ -f "$@/Makefile" ] ; then \ $(MAKE) -C $@ ; \ From a115b9279f4897b8afdfbc30035b1382c047fc26 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 29 Nov 2023 11:36:22 -0800 Subject: [PATCH 1898/7721] tools: ynl: don't skip regeneration from make targets Commit 2b7ac0c87d98 ("tools: ynl-gen: don't touch the output file if content is the same") is working too well. It was added so that ynl-regen -f doesn't make us rebuild half of the kernel, if there are no actual changes in any generated code. When ynl-gen-c is called by make, however, we're better off trusting make's tracking and overwrite the file. Otherwise if output is identical we won't update file timestamps and make will retry code gen on every invocation. Link: https://lore.kernel.org/r/20231129193622.2912353-5-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 12 ++++++++---- tools/net/ynl/ynl-regen.sh | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index cbbda276f6d1..ba1c3611c6fa 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1164,8 +1164,9 @@ class RenderInfo: class CodeWriter: - def __init__(self, nlib, out_file=None): + def __init__(self, nlib, out_file=None, overwrite=True): self.nlib = nlib + self._overwrite = overwrite self._nl = False self._block_end = False @@ -1186,8 +1187,9 @@ class CodeWriter: return # Avoid modifying the file if contents didn't change self._out.flush() - if os.path.isfile(self._out_file) and filecmp.cmp(self._out.name, self._out_file, shallow=False): - return + if not self._overwrite and os.path.isfile(self._out_file): + if filecmp.cmp(self._out.name, self._out_file, shallow=False): + return with open(self._out_file, 'w+') as out_file: self._out.seek(0) shutil.copyfileobj(self._out, out_file) @@ -2516,6 +2518,8 @@ def main(): parser.add_argument('--header', dest='header', action='store_true', default=None) parser.add_argument('--source', dest='header', action='store_false') parser.add_argument('--user-header', nargs='+', default=[]) + parser.add_argument('--cmp-out', action='store_true', default=None, + help='Do not overwrite the output file if the new output is identical to the old') parser.add_argument('--exclude-op', action='append', default=[]) parser.add_argument('-o', dest='out_file', type=str, default=None) args = parser.parse_args() @@ -2543,7 +2547,7 @@ def main(): print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation') os.sys.exit(1) - cw = CodeWriter(BaseNlLib(), args.out_file) + cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out)) _, spec_kernel = find_kernel_root(args.spec) if args.mode == 'uapi' or args.header: diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index bdba24066cf1..a37304dcc88e 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -30,8 +30,8 @@ for f in $files; do fi echo -e "\tGEN ${params[2]}\t$f" - $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} \ - $args -o $f + $TOOL --cmp-out --mode ${params[2]} --${params[3]} \ + --spec $KDIR/${params[0]} $args -o $f done popd >>/dev/null From fbb7033b76eb0639a6f24d48e59f28407a4dee64 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:43:04 +0100 Subject: [PATCH 1899/7721] dt-bindings: net: dsa: Require ports or ethernet-ports Bindings using dsa.yaml#/$defs/ethernet-ports specify that a DSA switch node need to have a ports or ethernet-ports subnode, and that is actually required, so add requirements using oneOf. Suggested-by: Rob Herring Acked-by: Florian Fainelli Reviewed-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231127-marvell-88e6152-wan-led-v9-1-272934e04681@linaro.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/dsa/dsa.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index 6107189d276a..2abd036578d1 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -46,4 +46,10 @@ $defs: $ref: dsa-port.yaml# unevaluatedProperties: false +oneOf: + - required: + - ports + - required: + - ethernet-ports + ... From a6e44f3028e7d582da625a611ef17908844d0e82 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:43:05 +0100 Subject: [PATCH 1900/7721] dt-bindings: net: mvusb: Fix up DSA example When adding a proper schema for the Marvell mx88e6xxx switch, the scripts start complaining about this embedded example: dtschema/dtc warnings/errors: net/marvell,mvusb.example.dtb: switch@0: ports: '#address-cells' is a required property from schema $id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# net/marvell,mvusb.example.dtb: switch@0: ports: '#size-cells' is a required property from schema $id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# Fix this up by extending the example with those properties in the ports node. While we are at it, rename "ports" to "ethernet-ports" and rename "switch" to "ethernet-switch" as this is recommended practice. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Reviewed-by: Rob Herring Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231127-marvell-88e6152-wan-led-v9-2-272934e04681@linaro.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/marvell,mvusb.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml index 3a3325168048..ab838c1ffeed 100644 --- a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml +++ b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml @@ -50,11 +50,14 @@ examples: #address-cells = <1>; #size-cells = <0>; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0x0>; - ports { + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + /* Port definitions */ }; From f45c197465ed92c72c1af7ac773ca5050bd9535a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:43:06 +0100 Subject: [PATCH 1901/7721] dt-bindings: net: ethernet-switch: Accept special variants Accept special node naming variants for Marvell switches with special node names as ABI. This is maybe not the prettiest but it avoids special-casing the Marvell MV88E6xxx bindings by copying a lot of generic binding code down into that one binding just to special-case these unfixable nodes. Reviewed-by: Rob Herring Reviewed-by: Andrew Lunn Signed-off-by: Linus Walleij Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20231127-marvell-88e6152-wan-led-v9-3-272934e04681@linaro.org Signed-off-by: Jakub Kicinski --- .../bindings/net/ethernet-switch.yaml | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/net/ethernet-switch.yaml b/Documentation/devicetree/bindings/net/ethernet-switch.yaml index 72ac67ca3415..b3b7e1a1b127 100644 --- a/Documentation/devicetree/bindings/net/ethernet-switch.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-switch.yaml @@ -20,9 +20,26 @@ description: select: false -properties: - $nodename: - pattern: "^(ethernet-)?switch(@.*)?$" +allOf: + # This condition is here to satisfy the case where certain device + # nodes have to preserve non-standard names because of + # backward-compatibility with boot loaders inspecting certain + # node names. + - if: + properties: + compatible: + contains: + enum: + - marvell,turris-mox-mv88e6085 + - marvell,turris-mox-mv88e6190 + then: + properties: + $nodename: + pattern: "switch[0-3]@[0-3]+$" + else: + properties: + $nodename: + pattern: "^(ethernet-)?switch(@.*)?$" patternProperties: "^(ethernet-)?ports$": From 43915b2f4bb9fc0e098fa703d508027b58f442fa Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:43:07 +0100 Subject: [PATCH 1902/7721] dt-bindings: marvell: Rewrite MV88E6xxx in schema This is an attempt to rewrite the Marvell MV88E6xxx switch bindings in YAML schema. The current text binding says: WARNING: This binding is currently unstable. Do not program it into a FLASH never to be changed again. Once this binding is stable, this warning will be removed. Well that never happened before we switched to YAML markup, we can't have it like this, what about fixing the mess? Reviewed-by: Andrew Lunn Reviewed-by: Rob Herring Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20231127-marvell-88e6152-wan-led-v9-4-272934e04681@linaro.org Signed-off-by: Jakub Kicinski --- .../bindings/net/dsa/marvell,mv88e6xxx.yaml | 337 ++++++++++++++++++ .../devicetree/bindings/net/dsa/marvell.txt | 109 ------ MAINTAINERS | 2 +- 3 files changed, 338 insertions(+), 110 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml delete mode 100644 Documentation/devicetree/bindings/net/dsa/marvell.txt diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml new file mode 100644 index 000000000000..19f15bdd1c97 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml @@ -0,0 +1,337 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6xxx DSA switch family + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6xxx switch series has been produced and sold + by Marvell since at least 2008. The switch has a few compatibles which + just indicate the base address of the switch, then operating systems + can investigate switch ID registers to find out which actual version + of the switch it is dealing with. + +properties: + compatible: + oneOf: + - enum: + - marvell,mv88e6085 + - marvell,mv88e6190 + - marvell,mv88e6250 + description: | + marvell,mv88e6085: This switch uses base address 0x10. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6085" should be + specified. This includes the following list of MV88Exxxx switches: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, 6171, 6172, 6175, 6176, + 6185, 6240, 6320, 6321, 6341, 6350, 6351, 6352 + marvell,mv88e6190: This switch uses base address 0x00. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6190" should be + specified. This includes the following list of MV88Exxxx switches: + 6190, 6190X, 6191, 6290, 6361, 6390, 6390X + marvell,mv88e6250: This switch uses base address 0x08 or 0x18. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6250" should be + specified. This includes the following list of MV88Exxxx switches: + 6220, 6250 + - items: + - const: marvell,turris-mox-mv88e6085 + - const: marvell,mv88e6085 + - items: + - const: marvell,turris-mox-mv88e6190 + - const: marvell,mv88e6190 + + reg: + maxItems: 1 + + eeprom-length: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Set to the length of an EEPROM connected to the switch. Must be + set if the switch can not detect the presence and/or size of a connected + EEPROM, otherwise optional. + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + + interrupts: + description: The switch provides an external interrupt line, but it is + not always used by target systems. + maxItems: 1 + + interrupt-controller: + description: The switch has an internal interrupt controller used by + the different sub-blocks. + + '#interrupt-cells': + description: The internal interrupt controller only supports triggering + on active high level interrupts so the second cell must alway be set to + IRQ_TYPE_LEVEL_HIGH. + const: 2 + + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches have an varying combination of + internal and external MDIO buses, in some cases a combined bus that + can be used both internally and externally. This node is for the + primary bus, used internally and sometimes also externally. + + mdio-external: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches that have a separate external + MDIO bus use this port to access external components on the MDIO bus. + + properties: + compatible: + const: marvell,mv88e6xxx-mdio-external + + required: + - compatible + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + sw_phy0: ethernet-phy@0 { + reg = <0x0>; + }; + + sw_phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + sw_phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + sw_phy3: ethernet-phy@3 { + reg = <0x3>; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan4"; + phy-handle = <&sw_phy0>; + phy-mode = "internal"; + }; + + ethernet-port@1 { + reg = <1>; + label = "lan3"; + phy-handle = <&sw_phy1>; + phy-mode = "internal"; + }; + + ethernet-port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&sw_phy2>; + phy-mode = "internal"; + }; + + ethernet-port@3 { + reg = <3>; + label = "lan1"; + phy-handle = <&sw_phy3>; + phy-mode = "internal"; + }; + + ethernet-port@5 { + reg = <5>; + ethernet = <&fec>; + phy-mode = "rgmii-id"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6190"; + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&switch_interrupt_pins>; + pinctrl-names = "default"; + reg = <0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch0phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + switch0phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + switch0phy3: ethernet-phy@3 { + reg = <0x3>; + }; + + switch0phy4: ethernet-phy@4 { + reg = <0x4>; + }; + + switch0phy5: ethernet-phy@5 { + reg = <0x5>; + }; + + switch0phy6: ethernet-phy@6 { + reg = <0x6>; + }; + + switch0phy7: ethernet-phy@7 { + reg = <0x7>; + }; + + switch0phy8: ethernet-phy@8 { + reg = <0x8>; + }; + }; + + mdio-external { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@b { + reg = <0xb>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + + phy2: ethernet-phy@c { + reg = <0xc>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + ethernet = <ð0>; + phy-mode = "rgmii"; + reg = <0>; + + fixed-link { + full-duplex; + pause; + speed = <1000>; + }; + }; + + ethernet-port@1 { + label = "lan1"; + phy-handle = <&switch0phy1>; + reg = <1>; + }; + + ethernet-port@2 { + label = "lan2"; + phy-handle = <&switch0phy2>; + reg = <2>; + }; + + ethernet-port@3 { + label = "lan3"; + phy-handle = <&switch0phy3>; + reg = <3>; + }; + + ethernet-port@4 { + label = "lan4"; + phy-handle = <&switch0phy4>; + reg = <4>; + }; + + ethernet-port@5 { + label = "lan5"; + phy-handle = <&switch0phy5>; + reg = <5>; + }; + + ethernet-port@6 { + label = "lan6"; + phy-handle = <&switch0phy6>; + reg = <6>; + }; + + ethernet-port@7 { + label = "lan7"; + phy-handle = <&switch0phy7>; + reg = <7>; + }; + + ethernet-port@8 { + label = "lan8"; + phy-handle = <&switch0phy8>; + reg = <8>; + }; + + ethernet-port@9 { + /* 88X3310P external phy */ + label = "lan9"; + phy-handle = <&phy1>; + phy-mode = "xaui"; + reg = <9>; + }; + + ethernet-port@a { + /* 88X3310P external phy */ + label = "lan10"; + phy-handle = <&phy2>; + phy-mode = "xaui"; + reg = <0xa>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt deleted file mode 100644 index 6ec0c181b6db..000000000000 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ /dev/null @@ -1,109 +0,0 @@ -Marvell DSA Switch Device Tree Bindings ---------------------------------------- - -WARNING: This binding is currently unstable. Do not program it into a -FLASH never to be changed again. Once this binding is stable, this -warning will be removed. - -If you need a stable binding, use the old dsa.txt binding. - -Marvell Switches are MDIO devices. The following properties should be -placed as a child node of an mdio device. - -The properties described here are those specific to Marvell devices. -Additional required and optional properties can be found in dsa.txt. - -The compatibility string is used only to find an identification register, -which is at a different MDIO base address in different switch families. -- "marvell,mv88e6085" : Switch has base address 0x10. Use with models: - 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, - 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, - 6341, 6350, 6351, 6352 -- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: - 6190, 6190X, 6191, 6290, 6361, 6390, 6390X -- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: - 6220, 6250 - -Required properties: -- compatible : Should be one of "marvell,mv88e6085", - "marvell,mv88e6190" or "marvell,mv88e6250" as - indicated above -- reg : Address on the MII bus for the switch. - -Optional properties: - -- reset-gpios : Should be a gpio specifier for a reset line -- interrupts : Interrupt from the switch -- interrupt-controller : Indicates the switch is itself an interrupt - controller. This is used for the PHY interrupts. -#interrupt-cells = <2> : Controller uses two cells, number and flag -- eeprom-length : Set to the length of an EEPROM connected to the - switch. Must be set if the switch can not detect - the presence and/or size of a connected EEPROM, - otherwise optional. -- mdio : Container of PHY and devices on the switches MDIO - bus. -- mdio? : Container of PHYs and devices on the external MDIO - bus. The node must contains a compatible string of - "marvell,mv88e6xxx-mdio-external" - -Example: - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6085"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - }; - }; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6190"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - - mdio1 { - compatible = "marvell,mv88e6xxx-mdio-external"; - #address-cells = <1>; - #size-cells = <0>; - switch1phy9: switch1phy0@9 { - reg = <9>; - }; - }; - }; - }; diff --git a/MAINTAINERS b/MAINTAINERS index 4b1c2077e959..f3bb6688d1f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12773,7 +12773,7 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/net/dsa/marvell.txt +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ F: include/linux/dsa/mv88e6xxx.h From 017ca9c9f31051bf6118e8557c78fe6471cca6fc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:43:08 +0100 Subject: [PATCH 1903/7721] dt-bindings: marvell: Add Marvell MV88E6060 DSA schema The Marvell MV88E6060 is one of the oldest DSA switches from Marvell, and it has DT bindings used in the wild. Let's define them properly. It is different enough from the rest of the MV88E6xxx switches that it deserves its own binding. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Reviewed-by: Rob Herring Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231127-marvell-88e6152-wan-led-v9-5-272934e04681@linaro.org Signed-off-by: Jakub Kicinski --- .../bindings/net/dsa/marvell,mv88e6060.yaml | 88 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml new file mode 100644 index 000000000000..4f1adf00431a --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6060.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6060 DSA switch + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6060 switch has been produced and sold by Marvell + since at least 2008. The switch has one pin ADDR4 that controls the + MDIO address of the switch to be 0x10 or 0x00, and on the MDIO bus + connected to the switch, the PHYs inside the switch appear as + independent devices on address 0x00-0x04 or 0x10-0x14, so in difference + from many other DSA switches this switch does not have an internal + MDIO bus for the PHY devices. + +properties: + compatible: + const: marvell,mv88e6060 + description: + The MV88E6060 is the oldest Marvell DSA switch product, and + as such a bit limited in features compared to later hardware. + + reg: + maxItems: 1 + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@16 { + compatible = "marvell,mv88e6060"; + reg = <16>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan1"; + }; + ethernet-port@1 { + reg = <1>; + label = "lan2"; + }; + ethernet-port@2 { + reg = <2>; + label = "lan3"; + }; + ethernet-port@3 { + reg = <3>; + label = "lan4"; + }; + ethernet-port@5 { + reg = <5>; + phy-mode = "rev-mii"; + ethernet = <ðc>; + fixed-link { + speed = <100>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f3bb6688d1f5..dcdc7e86ca9c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12773,6 +12773,7 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ From 127532cd0f060ebc3c4cbca81b6438728ad5896e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 27 Nov 2023 18:20:11 +0100 Subject: [PATCH 1904/7721] r8169: improve handling task scheduling If we know that the task is going to be a no-op, don't even schedule it. And remove the check for netif_running() in the worker function, the check for flag RTL_FLAG_TASK_ENABLED is sufficient. Note that we can't remove the check for flag RTL_FLAG_TASK_ENABLED in the worker function because we have no guarantee when it will be executed. Signed-off-by: Heiner Kallweit Reviewed-by: Przemek Kitszel Link: https://lore.kernel.org/r/c65873a3-7394-4107-99a7-83f20030779c@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 0aed99a20029..5d7b8f03fe6c 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2227,6 +2227,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) { + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) + return; + set_bit(flag, tp->wk.flags); schedule_work(&tp->wk.work); } @@ -4467,8 +4470,7 @@ static void rtl_task(struct work_struct *work) rtnl_lock(); - if (!netif_running(tp->dev) || - !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) goto out_unlock; if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { From cb2f01b856eaef26ba2263f8c3b87ab5e1ea587d Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Mon, 27 Nov 2023 16:31:39 +0100 Subject: [PATCH 1905/7721] net: phy: adin: allow control of Fast Link Down Add support to allow Fast Link Down (aka "Enhanced link detection") to be controlled via the ETHTOOL_PHY_FAST_LINK_DOWN tunable. These PHYs have this feature enabled by default. Signed-off-by: Vincent Whitchurch Acked-by: Nuno Sa Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20231127-adin-fld-v1-1-797f6423fd48@axis.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/adin.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index 134637584a83..2e1a46e121d9 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -68,6 +68,24 @@ #define ADIN1300_EEE_CAP_REG 0x8000 #define ADIN1300_EEE_ADV_REG 0x8001 #define ADIN1300_EEE_LPABLE_REG 0x8002 + +#define ADIN1300_FLD_EN_REG 0x8E27 +#define ADIN1300_FLD_PCS_ERR_100_EN BIT(7) +#define ADIN1300_FLD_PCS_ERR_1000_EN BIT(6) +#define ADIN1300_FLD_SLCR_OUT_STUCK_100_EN BIT(5) +#define ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN BIT(4) +#define ADIN1300_FLD_SLCR_IN_ZDET_100_EN BIT(3) +#define ADIN1300_FLD_SLCR_IN_ZDET_1000_EN BIT(2) +#define ADIN1300_FLD_SLCR_IN_INVLD_100_EN BIT(1) +#define ADIN1300_FLD_SLCR_IN_INVLD_1000_EN BIT(0) +/* These bits are the ones which are enabled by default. */ +#define ADIN1300_FLD_EN_ON \ + (ADIN1300_FLD_SLCR_OUT_STUCK_100_EN | \ + ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN | \ + ADIN1300_FLD_SLCR_IN_ZDET_100_EN | \ + ADIN1300_FLD_SLCR_IN_ZDET_1000_EN | \ + ADIN1300_FLD_SLCR_IN_INVLD_1000_EN) + #define ADIN1300_CLOCK_STOP_REG 0x9400 #define ADIN1300_LPI_WAKE_ERR_CNT_REG 0xa000 @@ -416,6 +434,37 @@ static int adin_set_edpd(struct phy_device *phydev, u16 tx_interval) val); } +static int adin_get_fast_down(struct phy_device *phydev, u8 *msecs) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_FLD_EN_REG); + if (reg < 0) + return reg; + + if (reg & ADIN1300_FLD_EN_ON) + *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON; + else + *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; + + return 0; +} + +static int adin_set_fast_down(struct phy_device *phydev, const u8 *msecs) +{ + if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON) + return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + ADIN1300_FLD_EN_REG, + ADIN1300_FLD_EN_ON); + + if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) + return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + ADIN1300_FLD_EN_REG, + ADIN1300_FLD_EN_ON); + + return -EINVAL; +} + static int adin_get_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, void *data) { @@ -424,6 +473,8 @@ static int adin_get_tunable(struct phy_device *phydev, return adin_get_downshift(phydev, data); case ETHTOOL_PHY_EDPD: return adin_get_edpd(phydev, data); + case ETHTOOL_PHY_FAST_LINK_DOWN: + return adin_get_fast_down(phydev, data); default: return -EOPNOTSUPP; } @@ -437,6 +488,8 @@ static int adin_set_tunable(struct phy_device *phydev, return adin_set_downshift(phydev, *(const u8 *)data); case ETHTOOL_PHY_EDPD: return adin_set_edpd(phydev, *(const u16 *)data); + case ETHTOOL_PHY_FAST_LINK_DOWN: + return adin_set_fast_down(phydev, data); default: return -EOPNOTSUPP; } From 7edce370d87a23e8ed46af5b76a9fef1e341b67b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 28 Nov 2023 14:59:28 +0100 Subject: [PATCH 1906/7721] net: phy: aquantia: drop wrong endianness conversion for addr and CRC On further testing on BE target with kernel test robot, it was notice that the endianness conversion for addr and CRC in fw_load_memory was wrong. Drop the cpu_to_le32 conversion for addr load as it's not needed. Use get_unaligned_le32 instead of get_unaligned for FW data word load to correctly convert data in the correct order to follow system endian. Also drop the cpu_to_be32 for CRC calculation as it's wrong and would cause different CRC on BE system. The loaded word is swapped internally and MAILBOX calculates the CRC on the swapped word. To correctly calculate the CRC to be later matched with the one from MAILBOX, use an u8 struct and swap the word there to keep the same order on both LE and BE for crc_ccitt_false function. Also add additional comments on how the CRC verification for the loaded section works. CRC is calculated as we load the section and verified with the MAILBOX only after the entire section is loaded to skip additional slowdown by loop the section data again. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311210414.sEJZjlcD-lkp@intel.com/ Fixes: e93984ebc1c8 ("net: phy: aquantia: add firmware load support") Tested-by: Robert Marko # ipq8072 LE device Signed-off-by: Christian Marangi Link: https://lore.kernel.org/r/20231128135928.9841-1-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/aquantia/aquantia_firmware.c | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/aquantia/aquantia_firmware.c b/drivers/net/phy/aquantia/aquantia_firmware.c index c5f292b1c4c8..ff34d00d5a0e 100644 --- a/drivers/net/phy/aquantia/aquantia_firmware.c +++ b/drivers/net/phy/aquantia/aquantia_firmware.c @@ -93,9 +93,6 @@ static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr, u16 crc = 0, up_crc; size_t pos; - /* PHY expect addr in LE */ - addr = (__force u32)cpu_to_le32(addr); - phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE1, VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET); @@ -110,10 +107,11 @@ static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr, * If a firmware that is not word aligned is found, please report upstream. */ for (pos = 0; pos < len; pos += sizeof(u32)) { + u8 crc_data[4]; u32 word; /* FW data is always stored in little-endian */ - word = get_unaligned((const u32 *)(data + pos)); + word = get_unaligned_le32((const u32 *)(data + pos)); phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5, VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word)); @@ -124,15 +122,21 @@ static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr, VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE | VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE); - /* calculate CRC as we load data to the mailbox. - * We convert word to big-endian as PHY is BE and mailbox will - * return a BE CRC. + /* Word is swapped internally and MAILBOX CRC is calculated + * using big-endian order. Mimic what the PHY does to have a + * matching CRC... */ - word = (__force u32)cpu_to_be32(word); - crc = crc_ccitt_false(crc, (u8 *)&word, sizeof(word)); - } + crc_data[0] = word >> 24; + crc_data[1] = word >> 16; + crc_data[2] = word >> 8; + crc_data[3] = word; + /* ...calculate CRC as we load data... */ + crc = crc_ccitt_false(crc, crc_data, sizeof(crc_data)); + } + /* ...gets CRC from MAILBOX after we have loaded the entire section... */ up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2); + /* ...and make sure it does match our calculated CRC */ if (crc != up_crc) { phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n", crc, up_crc); From 01de00f439ab4989feec68c193c87479d7f1202a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:34 +0100 Subject: [PATCH 1907/7721] mlxsw: spectrum_fid: Privatize FID families Currently, mlxsw always uses a "controlled" flood mode on all Nvidia Spectrum generations. The following patches will however introduce a possibility to run a "CFF" (for Compressed FID Flooding) mode on newer machines, if the FW supports it. Several operations will differ between how they need to be done in controlled mode vs. CFF mode. Thus the per-FID-family ops will differ between controlled and CFF, thus the FID family array as such will differ depending on whether the mode negotiated with FW is controlled or CFF. The simple approach of having several globally visible arrays for spectrum.c to statically choose from no longer works. Instead privatize all FID initialization and finalization logic, and expose it as ops instead. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/d3fa390d97cf3dbd2f7a28741be69b311e2059e4.1701183891.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 18 +++++----- .../net/ethernet/mellanox/mlxsw/spectrum.h | 13 +++++--- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 33 +++++++++++++++---- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index cec72d99d9c9..6726447ce100 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3190,10 +3190,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_lag_init; } - err = mlxsw_sp_fids_init(mlxsw_sp); + err = mlxsw_sp->fid_core_ops->init(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); - goto err_fids_init; + goto err_fid_core_init; } err = mlxsw_sp_policers_init(mlxsw_sp); @@ -3379,8 +3379,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, err_traps_init: mlxsw_sp_policers_fini(mlxsw_sp); err_policers_init: - mlxsw_sp_fids_fini(mlxsw_sp); -err_fids_init: + mlxsw_sp->fid_core_ops->fini(mlxsw_sp); +err_fid_core_init: mlxsw_sp_lag_fini(mlxsw_sp); err_lag_init: mlxsw_sp_pgt_fini(mlxsw_sp); @@ -3416,7 +3416,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp1_router_ops; mlxsw_sp->listeners = mlxsw_sp1_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp1_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; mlxsw_sp->pgt_smpe_index_valid = true; @@ -3450,7 +3450,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3484,7 +3484,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3518,7 +3518,7 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3552,7 +3552,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_devlink_traps_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); mlxsw_sp_policers_fini(mlxsw_sp); - mlxsw_sp_fids_fini(mlxsw_sp); + mlxsw_sp->fid_core_ops->fini(mlxsw_sp); mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_pgt_fini(mlxsw_sp); mlxsw_sp_kvdl_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 800c461deefa..e50f22870602 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -205,7 +205,7 @@ struct mlxsw_sp { const struct mlxsw_sp_mall_ops *mall_ops; const struct mlxsw_sp_router_ops *router_ops; const struct mlxsw_listener *listeners; - const struct mlxsw_sp_fid_family **fid_family_arr; + const struct mlxsw_sp_fid_core_ops *fid_core_ops; size_t listeners_count; u32 lowest_shaper_bs; struct rhashtable ipv6_addr_ht; @@ -252,6 +252,11 @@ struct mlxsw_sp_ptp_ops { const struct mlxsw_tx_info *tx_info); }; +struct mlxsw_sp_fid_core_ops { + int (*init)(struct mlxsw_sp *mlxsw_sp); + void (*fini)(struct mlxsw_sp *mlxsw_sp); +}; + static inline struct mlxsw_sp_upper * mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) { @@ -1321,11 +1326,9 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp); -void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp); -extern const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[]; -extern const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[]; +extern const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops; +extern const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops; /* spectrum_mr.c */ enum mlxsw_sp_mr_route_prio { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index aad4bb17dfb1..fc55ba781bca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -1486,7 +1486,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { .smpe_index_valid = false, }; -const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { +static const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family, [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family, @@ -1529,7 +1529,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = { .smpe_index_valid = false, }; -const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = { +static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = { [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family, [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, @@ -1799,7 +1799,9 @@ void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; } -int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) +static int +mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_family *fid_family_arr[]) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); struct mlxsw_sp_fid_core *fid_core; @@ -1826,8 +1828,7 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) } for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { - err = mlxsw_sp_fid_family_register(mlxsw_sp, - mlxsw_sp->fid_family_arr[i]); + err = mlxsw_sp_fid_family_register(mlxsw_sp, fid_family_arr[i]); if (err) goto err_fid_ops_register; @@ -1852,7 +1853,7 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) return err; } -void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) +static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; int i; @@ -1865,3 +1866,23 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) rhashtable_destroy(&fid_core->fid_ht); kfree(fid_core); } + +static int mlxsw_sp1_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp1_fid_family_arr); +} + +const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = { + .init = mlxsw_sp1_fids_init, + .fini = mlxsw_sp_fids_fini, +}; + +static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr); +} + +const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = { + .init = mlxsw_sp2_fids_init, + .fini = mlxsw_sp_fids_fini, +}; From ab68bd743af8d4e9efd21c570acb7bee65bb47ce Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:35 +0100 Subject: [PATCH 1908/7721] mlxsw: spectrum_fid: Rename FID ops, families, arrays Currently, mlxsw always uses a "controlled" flood mode on all Nvidia Spectrum generations. The following patches will however introduce a possibility to run a "CFF" (for Compressed FID Flooding) mode on newer machines, if the FW supports it. To reflect that, label all FID ops, FID families and FID family arrays with a _ctl suffix. This will make it clearer what is what when the CFF families are introduced in later patches. Keep the dummy family intact. Since the dummy family has no flood tables in either CTL or CFF mode, there are no flood-mode-specific callbacks. Additionally, add a remark at two fields that they are only relevant when flood mode is not CFF. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/96b6da5439bb662fa86e795bbcec9dc3ccfa59fd.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index fc55ba781bca..d92c44c6ffbf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -71,7 +71,7 @@ static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { struct mlxsw_sp_flood_table { enum mlxsw_sp_flood_type packet_type; - enum mlxsw_flood_table_type table_type; + enum mlxsw_flood_table_type table_type; /* For flood_mode!=CFF. */ int table_index; }; @@ -109,7 +109,7 @@ struct mlxsw_sp_fid_family { enum mlxsw_sp_rif_type rif_type; const struct mlxsw_sp_fid_ops *ops; struct mlxsw_sp *mlxsw_sp; - bool flood_rsp; + bool flood_rsp; /* For flood_mode!=CFF. */ enum mlxsw_reg_bridge_type bridge_type; u16 pgt_base; bool smpe_index_valid; @@ -1068,7 +1068,7 @@ mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, return 0; } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .setup = mlxsw_sp_fid_8021d_setup, .configure = mlxsw_sp_fid_8021d_configure, .deconfigure = mlxsw_sp_fid_8021d_deconfigure, @@ -1120,8 +1120,10 @@ mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); } -static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg) +static void mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid, + const void *arg) { + /* In controlled mode, the FW takes care of FID placement. */ fid->fid_offset = 0; } @@ -1248,8 +1250,8 @@ mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, return 0; } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { - .setup = mlxsw_sp_fid_rfid_setup, +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = { + .setup = mlxsw_sp_fid_rfid_setup_ctl, .configure = mlxsw_sp_fid_rfid_configure, .deconfigure = mlxsw_sp_fid_rfid_deconfigure, .index_alloc = mlxsw_sp_fid_rfid_index_alloc, @@ -1405,7 +1407,7 @@ mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false); } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .setup = mlxsw_sp_fid_8021q_setup, .configure = mlxsw_sp_fid_8021q_configure, .deconfigure = mlxsw_sp_fid_8021q_deconfigure, @@ -1447,7 +1449,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = { .flood_tables = mlxsw_sp_fid_8021d_flood_tables, .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_VLAN, - .ops = &mlxsw_sp_fid_8021q_ops, + .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, .smpe_index_valid = false, @@ -1461,7 +1463,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = { .flood_tables = mlxsw_sp_fid_8021d_flood_tables, .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_FID, - .ops = &mlxsw_sp_fid_8021d_ops, + .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .smpe_index_valid = false, }; @@ -1475,13 +1477,13 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = { .smpe_index_valid = false, }; -static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_ctl = { .type = MLXSW_SP_FID_TYPE_RFID, .fid_size = sizeof(struct mlxsw_sp_fid), .start_index = MLXSW_SP_RFID_START, .end_index = MLXSW_SP_RFID_END, .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, - .ops = &mlxsw_sp_fid_rfid_ops, + .ops = &mlxsw_sp_fid_rfid_ops_ctl, .flood_rsp = true, .smpe_index_valid = false, }; @@ -1490,10 +1492,10 @@ static const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family, [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family, - [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, }; -static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = { .type = MLXSW_SP_FID_TYPE_8021Q, .fid_size = sizeof(struct mlxsw_sp_fid_8021q), .start_index = MLXSW_SP_FID_8021Q_START, @@ -1501,13 +1503,13 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = { .flood_tables = mlxsw_sp_fid_8021d_flood_tables, .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_VLAN, - .ops = &mlxsw_sp_fid_8021q_ops, + .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, .smpe_index_valid = true, }; -static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = { .type = MLXSW_SP_FID_TYPE_8021D, .fid_size = sizeof(struct mlxsw_sp_fid_8021d), .start_index = MLXSW_SP_FID_8021D_START, @@ -1515,7 +1517,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = { .flood_tables = mlxsw_sp_fid_8021d_flood_tables, .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_FID, - .ops = &mlxsw_sp_fid_8021d_ops, + .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .smpe_index_valid = true, }; @@ -1529,11 +1531,11 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = { .smpe_index_valid = false, }; -static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = { - [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family, - [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family, +static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_ctl, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_ctl, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, - [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, }; static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, @@ -1877,12 +1879,12 @@ const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = { .fini = mlxsw_sp_fids_fini, }; -static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp) +static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp) { - return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr); + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl); } const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = { - .init = mlxsw_sp2_fids_init, + .init = mlxsw_sp2_fids_init_ctl, .fini = mlxsw_sp_fids_fini, }; From 82ff7a196d76a04cf437ac0469ac9e9b84110b13 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:36 +0100 Subject: [PATCH 1909/7721] mlxsw: spectrum_fid: Split a helper out of mlxsw_sp_fid_flood_table_mid() In future patches, for CFF flood mode support, we will need a way to determine a PGT base dynamically, as an op. Therefore, for symmetry, split out a helper, mlxsw_sp_fid_pgt_base_ctl(), that determines a PGT base in the controlled mode as well. Now that the helper is available, use it in mlxsw_sp_fid_flood_table_init() which currently invokes the FID->MID helper to that end. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/fd41c66a1df4df6499d3da34f40e7b9efa15bc3e.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_fid.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index d92c44c6ffbf..96cedc241bf2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -329,14 +329,21 @@ mlxsw_sp_fid_family_pgt_size(const struct mlxsw_sp_fid_family *fid_family) } static u16 -mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table, - u16 fid_offset) +mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) { u16 num_fids; num_fids = mlxsw_sp_fid_family_num_fids(fid_family); - return fid_family->pgt_base + num_fids * flood_table->table_index + + return fid_family->pgt_base + num_fids * flood_table->table_index; +} + +static u16 +mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table, + u16 fid_offset) +{ + return mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table) + fid_offset; } @@ -1671,7 +1678,7 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, u16 mid_base; int err, i; - mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); + mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table); sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { From 17eda112b0d8e282e310f720aed2acda4fbd3317 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:37 +0100 Subject: [PATCH 1910/7721] mlxsw: spectrum_fid: Make mlxsw_sp_fid_ops.setup return an int This operation will be fallible for rFIDs in CFF mode, which will be introduced in follow-up patches. Have it return an int, and handle the failures in the caller. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/75f1b85c0cb86bea5501fcc8657042f221a78b32.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 96cedc241bf2..ab0632bd5cd4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -76,7 +76,7 @@ struct mlxsw_sp_flood_table { }; struct mlxsw_sp_fid_ops { - void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); + int (*setup)(struct mlxsw_sp_fid *fid, const void *arg); int (*configure)(struct mlxsw_sp_fid *fid); void (*deconfigure)(struct mlxsw_sp_fid *fid); int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, @@ -417,12 +417,13 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) return mlxsw_sp_fid_8021q_fid(fid)->vid; } -static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) { u16 vid = *(u16 *) arg; mlxsw_sp_fid_8021q_fid(fid)->vid = vid; fid->fid_offset = fid->fid_index - fid->fid_family->start_index; + return 0; } static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) @@ -785,12 +786,13 @@ mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) return container_of(fid, struct mlxsw_sp_fid_8021d, common); } -static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) { int br_ifindex = *(int *) arg; mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; fid->fid_offset = fid->fid_index - fid->fid_family->start_index; + return 0; } static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) @@ -1127,11 +1129,12 @@ mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); } -static void mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid, - const void *arg) +static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid, + const void *arg) { /* In controlled mode, the FW takes care of FID placement. */ fid->fid_offset = 0; + return 0; } static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) @@ -1272,9 +1275,10 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = { .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, }; -static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) { fid->fid_offset = 0; + return 0; } static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) @@ -1590,7 +1594,9 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, fid->fid_index = fid_index; __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); - fid->fid_family->ops->setup(fid, arg); + err = fid->fid_family->ops->setup(fid, arg); + if (err) + goto err_setup; err = fid->fid_family->ops->configure(fid); if (err) @@ -1608,6 +1614,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, err_rhashtable_insert: fid->fid_family->ops->deconfigure(fid); err_configure: +err_setup: __clear_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); err_index_alloc: From 1d0791168ef7a31780c5f9dc65cbdb044b7e859c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:38 +0100 Subject: [PATCH 1911/7721] mlxsw: spectrum_fid: Move mlxsw_sp_fid_flood_table_init() up Move the function to the point where it will need to be to be visible for the 802.1d ops. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/aef09e26b0c2dd077531e665d7135b300bdaf0a8.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index ab0632bd5cd4..0c7295d7e693 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -1077,6 +1077,36 @@ mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, return 0; } +static int +mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + const int *sfgc_packet_types; + u16 mid_base; + int err, i; + + mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table); + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + + if (!sfgc_packet_types[i]) + continue; + + mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, + flood_table->table_type, 0, mid_base); + + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + } + + return 0; +} + static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .setup = mlxsw_sp_fid_8021d_setup, .configure = mlxsw_sp_fid_8021d_configure, @@ -1675,36 +1705,6 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); } -static int -mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table) -{ - enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; - struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; - const int *sfgc_packet_types; - u16 mid_base; - int err, i; - - mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table); - - sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; - for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { - char sfgc_pl[MLXSW_REG_SFGC_LEN]; - - if (!sfgc_packet_types[i]) - continue; - - mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, - flood_table->table_type, 0, mid_base); - - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); - if (err) - return err; - } - - return 0; -} - static int mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) { From 80638da22e11164e6833f8697ad94136e0a6cdd5 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:39 +0100 Subject: [PATCH 1912/7721] mlxsw: spectrum_fid: Add an op for flood table initialization In controlled flood mode, for each bridge FID family (i.e., 802.1Q and 802.1D) and packet type (i.e., UUC/MC/BC), the hardware needs to be told which PGT address to use as the base address for the flood table and how to determine the offset from the base for each FID. The above is not needed in CFF mode where each FID has its own flood table instead of the FID family itself. Therefore, create a new FID family operation for the above configuration and only implement it for the 802.1Q and 802.1D families in controlled flood mode. No functional changes intended. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/06f71415eec75811585ec597e1dd101b6dff77e7.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_fid.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 0c7295d7e693..9ba4748e8d23 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -95,6 +95,8 @@ struct mlxsw_sp_fid_ops { const struct net_device *nve_dev); int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid, const struct mlxsw_sp_rif *rif); + int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table); }; struct mlxsw_sp_fid_family { @@ -1078,8 +1080,8 @@ mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, } static int -mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table) +mlxsw_sp_fid_flood_table_init_ctl(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) { enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; @@ -1121,6 +1123,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, + .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, }; #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) @@ -1462,6 +1465,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, + .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, }; /* There are 4K-2 802.1Q FIDs */ @@ -1723,9 +1727,12 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) const struct mlxsw_sp_flood_table *flood_table; flood_table = &fid_family->flood_tables[i]; - err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); - if (err) - goto err_flood_table_init; + if (fid_family->ops->flood_table_init) { + err = fid_family->ops->flood_table_init(fid_family, + flood_table); + if (err) + goto err_flood_table_init; + } } return 0; From 1686b8d902fd4f1486b21304a62d469fd3713019 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:40 +0100 Subject: [PATCH 1913/7721] mlxsw: spectrum_fid: Add an op to get PGT allocation size In the CFF flood mode, the PGT allocation size of RFID family will not depend on number of FIDs, but rather number of ports and LAGs. Therefore introduce a FID family operation to calculate the PGT allocation size. The way that size is calculated in the CFF mode depends on calling fallible functions. Thus express the op as returning an int, with the size returned via a pointer argument. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/1174651b7160fcedbef50010ae4b68201112fe6f.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 9ba4748e8d23..e8327c5b0b82 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -97,6 +97,8 @@ struct mlxsw_sp_fid_ops { const struct mlxsw_sp_rif *rif); int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family, const struct mlxsw_sp_flood_table *flood_table); + int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size); }; struct mlxsw_sp_fid_family { @@ -322,12 +324,14 @@ mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family) return fid_family->end_index - fid_family->start_index + 1; } -static u16 -mlxsw_sp_fid_family_pgt_size(const struct mlxsw_sp_fid_family *fid_family) +static int +mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size) { u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family); - return num_fids * fid_family->nr_flood_tables; + *p_pgt_size = num_fids * fid_family->nr_flood_tables; + return 0; } static u16 @@ -1124,6 +1128,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, }; #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) @@ -1466,6 +1471,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, }; /* There are 4K-2 802.1Q FIDs */ @@ -1717,7 +1723,10 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) int err; int i; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); + err = fid_family->ops->pgt_size(fid_family, &pgt_size); + if (err) + return err; + err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base, pgt_size); if (err) @@ -1747,8 +1756,12 @@ mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family) { struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; u16 pgt_size; + int err; + + err = fid_family->ops->pgt_size(fid_family, &pgt_size); + if (WARN_ON_ONCE(err)) + return; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size); } From e917a789594cab0621b19ab33cae298f2bce2ea3 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:41 +0100 Subject: [PATCH 1914/7721] mlxsw: spectrum_fid: Add an op to get PGT address of a FID In the CFF flood mode, the way to determine a PGT address where a given FID / flood table resides is different from the controlled flood mode, which mlxsw currently uses. Furthermore, this will differ between rFID family and bridge families. The operation therefore needs to be dynamically dispatched. To that end, add an op to FID-family ops. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Reviewed-by: Amit Cohen Link: https://lore.kernel.org/r/00e8f6ad79009a9a77a5c95d596ea9574776dc95.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_fid.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index e8327c5b0b82..c3f4ce3cf4e7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -99,6 +99,8 @@ struct mlxsw_sp_fid_ops { const struct mlxsw_sp_flood_table *flood_table); int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family, u16 *p_pgt_size); + u16 (*fid_mid)(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table); }; struct mlxsw_sp_fid_family { @@ -345,12 +347,11 @@ mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family, } static u16 -mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table, - u16 fid_offset) +mlxsw_sp_fid_fid_mid_ctl(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table) { - return mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table) + - fid_offset; + return mlxsw_sp_fid_pgt_base_ctl(fid->fid_family, flood_table) + + fid->fid_offset; } int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, @@ -368,8 +369,7 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, if (!flood_table) return -ESRCH; - mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, - fid->fid_offset); + mid_index = fid_family->ops->fid_mid(fid, flood_table); return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index, fid->fid_index, local_port, member); } @@ -1129,6 +1129,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_ctl, }; #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) @@ -1472,6 +1473,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_ctl, }; /* There are 4K-2 802.1Q FIDs */ From f6454316c8b9b247403b7dadc1c5b6e6f5163f0c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:42 +0100 Subject: [PATCH 1915/7721] mlxsw: spectrum_fid: Add an op for packing SFMR The way SFMR is packed differs between the controlled and CFF flood modes. Add an op to dispatch it dynamically. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/f12fe7879a7086ee86343ee4db02c859f78f0534.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index c3f4ce3cf4e7..223716c51401 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -101,6 +101,8 @@ struct mlxsw_sp_fid_ops { u16 *p_pgt_size); u16 (*fid_mid)(const struct mlxsw_sp_fid *fid, const struct mlxsw_sp_flood_table *flood_table); + void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op); }; struct mlxsw_sp_fid_family { @@ -466,7 +468,8 @@ static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, mlxsw_sp_sfmr_op(valid)); + fid->fid_family->ops->fid_pack(sfmr_pl, fid, + mlxsw_sp_sfmr_op(valid)); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } @@ -476,7 +479,9 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid, struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, MLXSW_REG_SFMR_OP_CREATE_FID); + fid->fid_family->ops->fid_pack(sfmr_pl, fid, + MLXSW_REG_SFMR_OP_CREATE_FID); + mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid); mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni)); mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid); @@ -1130,6 +1135,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, .pgt_size = mlxsw_sp_fid_8021d_pgt_size, .fid_mid = mlxsw_sp_fid_fid_mid_ctl, + .fid_pack = mlxsw_sp_fid_pack_ctl, }; #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) @@ -1312,6 +1318,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = { .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set, .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear, .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, + .fid_pack = mlxsw_sp_fid_pack_ctl, }; static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) @@ -1374,6 +1381,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { .vni_clear = mlxsw_sp_fid_dummy_vni_clear, .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set, .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear, + .fid_pack = mlxsw_sp_fid_pack, }; static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) @@ -1474,6 +1482,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, .pgt_size = mlxsw_sp_fid_8021d_pgt_size, .fid_mid = mlxsw_sp_fid_fid_mid_ctl, + .fid_pack = mlxsw_sp_fid_pack_ctl, }; /* There are 4K-2 802.1Q FIDs */ From a59316ffd92e62f0660a066aa4011378f0c857bd Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:43 +0100 Subject: [PATCH 1916/7721] mlxsw: spectrum_fid: Add a not-UC packet type In CFF flood mode, the rFID family will allocate two tables. One for unknown UC traffic, one for everything else. Add a traffic type for the everything else traffic. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/8fb968b2d1cc37137cd0110c98cdeb625b03ca99.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index e50f22870602..8bd1083cfd9e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -513,6 +513,8 @@ enum mlxsw_sp_flood_type { MLXSW_SP_FLOOD_TYPE_UC, MLXSW_SP_FLOOD_TYPE_BC, MLXSW_SP_FLOOD_TYPE_MC, + /* For RSP FIDs in CFF mode. */ + MLXSW_SP_FLOOD_TYPE_NOT_UC, }; int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 223716c51401..a718bdfa4c3b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -139,10 +139,20 @@ static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, }; +static const int mlxsw_sp_sfgc_not_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +}; + static const int *mlxsw_sp_packet_type_sfgc_types[] = { [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, + [MLXSW_SP_FLOOD_TYPE_NOT_UC] = mlxsw_sp_sfgc_not_uc_packet_types, }; struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, From 315702e09bed79f0c9f8d198f3268a2a1fc4d5ca Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:44 +0100 Subject: [PATCH 1917/7721] mlxsw: spectrum_fid: Add hooks for RSP table maintenance In the CFF flood mode, the driver has to allocate a table within PGT, which holds flood vectors for router subport FIDs. For LAGs, these flood vectors have to obviously be maintained dynamically as port membership in a LAG changes. But even for physical ports, the flood vectors have to be kept valid, and may not contain enabled bits corresponding to non-existent ports. It is therefore not possible to precompute the port part of the RSP table, it has to be maintained as ports come and go due to splits. To support the RSP table maintenance, add to FID ops two new ops: fid_port_init and fid_port_fini, for when a port comes to existence, or joins a lag, and vice versa. Invoke these ops from mlxsw_sp_port_fids_init() and mlxsw_sp_port_fids_fini(), which are called when port is added and removed, respectively. Also add two new hooks for LAG maintenance, mlxsw_sp_fid_port_join_lag() / _leave_lag() which transitively call into the same ops. Later patches will actually add the op implementations themselves, this just adds the scaffolding. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/234398a23540317abb25f74f920a5c8121faecf0.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 8 +++ .../net/ethernet/mellanox/mlxsw/spectrum.h | 2 + .../ethernet/mellanox/mlxsw/spectrum_fid.c | 58 ++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 6726447ce100..e3ef63e265d2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4515,6 +4515,10 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 1; lag->ref_count++; + err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port); + if (err) + goto err_fid_port_join_lag; + /* Port is no longer usable as a router interface */ if (mlxsw_sp_port->default_vlan->fid) mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan); @@ -4534,6 +4538,8 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, err_replay: mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev); err_router_join: + mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); +err_fid_port_join_lag: lag->ref_count--; mlxsw_sp_port->lagged = 0; mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, @@ -4569,6 +4575,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, */ mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev); + mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); + if (lag->ref_count == 1) mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8bd1083cfd9e..61612c413310 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -1328,6 +1328,8 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port); extern const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops; extern const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index a718bdfa4c3b..76b0df7370b3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -103,6 +103,14 @@ struct mlxsw_sp_fid_ops { const struct mlxsw_sp_flood_table *flood_table); void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid, enum mlxsw_reg_sfmr_op op); + + /* These are specific to RFID families and we assume are only + * implemented by RFID families, if at all. + */ + int (*fid_port_init)(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port); + void (*fid_port_fini)(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port); }; struct mlxsw_sp_fid_family { @@ -1836,9 +1844,34 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, kfree(fid_family); } +static int mlxsw_sp_fid_port_init(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_fid_family *rfid_family; + + rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid]; + if (rfid_family->ops->fid_port_init) + return rfid_family->ops->fid_port_init(rfid_family, + mlxsw_sp_port); + return 0; +} + +static void mlxsw_sp_fid_port_fini(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_fid_family *rfid_family; + + rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid]; + if (rfid_family->ops->fid_port_fini) + rfid_family->ops->fid_port_fini(rfid_family, mlxsw_sp_port); +} + int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; /* Track number of FIDs configured on the port with mapping type * PORT_VID_TO_FID, so that we know when to transition the port @@ -1846,16 +1879,39 @@ int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) */ mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; - return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + err = mlxsw_sp_fid_port_init(mlxsw_sp_port); + if (err) + return err; + + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + if (err) + goto err_vp_mode_set; + + return 0; + +err_vp_mode_set: + mlxsw_sp_fid_port_fini(mlxsw_sp_port); + return err; } void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + mlxsw_sp_fid_port_fini(mlxsw_sp_port); mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; } +int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + return mlxsw_sp_fid_port_init(mlxsw_sp_port); +} + +void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_fid_port_fini(mlxsw_sp_port); +} + static int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_fid_family *fid_family_arr[]) From 5e6146e34b9c3b198f1681dc0da40df8bf05bfe4 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:45 +0100 Subject: [PATCH 1918/7721] mlxsw: spectrum_fid: Add an object to keep flood profiles A flood profile is a mapping from traffic type to an offset at which a flood vector should be looked up. In mlxsw so far, a flood profile was somewhat implicitly represented by flood table array. When the CFF flood mode will be introduced, the flood profile will become more explicit: each will get a number and the profile ID / traffic-type / offset mapping will actually need to be initialized in the hardware. Therefore it is going to be handy to have a structure that keeps all the components that compose a flood profile. Add this structure, currently with just the flood table array bits. In the FID families that flood at all, reference the flood profile instead of just the table array. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/15e113de114d3f41ce3fd2a14a2fa6a1b1d7e8f2.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 76b0df7370b3..af460a0d030b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -113,6 +113,11 @@ struct mlxsw_sp_fid_ops { const struct mlxsw_sp_port *mlxsw_sp_port); }; +struct mlxsw_sp_fid_flood_profile { + const struct mlxsw_sp_flood_table *flood_tables; + int nr_flood_tables; +}; + struct mlxsw_sp_fid_family { enum mlxsw_sp_fid_type type; size_t fid_size; @@ -120,8 +125,7 @@ struct mlxsw_sp_fid_family { u16 end_index; struct list_head fids_list; unsigned long *fids_bitmap; - const struct mlxsw_sp_flood_table *flood_tables; - int nr_flood_tables; + const struct mlxsw_sp_fid_flood_profile *flood_profile; enum mlxsw_sp_rif_type rif_type; const struct mlxsw_sp_fid_ops *ops; struct mlxsw_sp *mlxsw_sp; @@ -331,10 +335,13 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, struct mlxsw_sp_fid_family *fid_family = fid->fid_family; int i; - for (i = 0; i < fid_family->nr_flood_tables; i++) { - if (fid_family->flood_tables[i].packet_type != packet_type) + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + + flood_table = &fid_family->flood_profile->flood_tables[i]; + if (flood_table->packet_type != packet_type) continue; - return &fid_family->flood_tables[i]; + return flood_table; } return NULL; @@ -352,7 +359,7 @@ mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family, { u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family); - *p_pgt_size = num_fids * fid_family->nr_flood_tables; + *p_pgt_size = num_fids * fid_family->flood_profile->nr_flood_tables; return 0; } @@ -382,7 +389,7 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, const struct mlxsw_sp_flood_table *flood_table; u16 mid_index; - if (WARN_ON(!fid_family->flood_tables)) + if (WARN_ON(!fid_family->flood_profile)) return -EINVAL; flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); @@ -1177,6 +1184,12 @@ static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { }, }; +static const +struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = { + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), +}; + static bool mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) { @@ -1526,8 +1539,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = { .fid_size = sizeof(struct mlxsw_sp_fid_8021q), .start_index = MLXSW_SP_FID_8021Q_START, .end_index = MLXSW_SP_FID_8021Q_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_VLAN, .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, @@ -1540,8 +1552,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = { .fid_size = sizeof(struct mlxsw_sp_fid_8021d), .start_index = MLXSW_SP_FID_8021D_START, .end_index = MLXSW_SP_FID_8021D_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_FID, .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, @@ -1580,8 +1591,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = { .fid_size = sizeof(struct mlxsw_sp_fid_8021q), .start_index = MLXSW_SP_FID_8021Q_START, .end_index = MLXSW_SP_FID_8021Q_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_VLAN, .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, @@ -1594,8 +1604,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = { .fid_size = sizeof(struct mlxsw_sp_fid_8021d), .start_index = MLXSW_SP_FID_8021D_START, .end_index = MLXSW_SP_FID_8021D_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_FID, .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, @@ -1761,10 +1770,13 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) if (err) return err; - for (i = 0; i < fid_family->nr_flood_tables; i++) { + if (!fid_family->flood_profile) + return 0; + + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { const struct mlxsw_sp_flood_table *flood_table; - flood_table = &fid_family->flood_tables[i]; + flood_table = &fid_family->flood_profile->flood_tables[i]; if (fid_family->ops->flood_table_init) { err = fid_family->ops->flood_table_init(fid_family, flood_table); @@ -1813,7 +1825,7 @@ static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, goto err_alloc_fids_bitmap; } - if (fid_family->flood_tables) { + if (fid_family->flood_profile) { err = mlxsw_sp_fid_flood_tables_init(fid_family); if (err) goto err_fid_flood_tables_init; @@ -1836,7 +1848,7 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, { mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; - if (fid_family->flood_tables) + if (fid_family->flood_profile) mlxsw_sp_fid_flood_tables_fini(fid_family); bitmap_free(fid_family->fids_bitmap); From af1e696fdf1e588ac0153cc8dff70b5a10a2e220 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:46 +0100 Subject: [PATCH 1919/7721] mlxsw: spectrum_fid: Add profile_id to flood profile In the CFF mode, flood profiles are identified by a unique numerical identifier. This is used for configuration of FIDs and for configuration of traffic-type to PGT offset rules. In both cases, the numerical identifier serves as a handle for the flood profile. Add the identifier to the flood profile structure. There is currently only one flood profile in use explicitly, the one used for all bridging. Eventually three will be necessary in total: one for bridges, one for rFIDs, one for NVE underlay. A total of four profiles are supported by the HW. Start allocating at 1, because 0 is currently used for underlay NVE flood. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/19ea9c35ba8b522fa5f7eb6fd7bc1b68f0f66b41.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index af460a0d030b..2d61fb8bff57 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -113,9 +113,14 @@ struct mlxsw_sp_fid_ops { const struct mlxsw_sp_port *mlxsw_sp_port); }; +enum mlxsw_sp_fid_flood_profile_id { + MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1, +}; + struct mlxsw_sp_fid_flood_profile { const struct mlxsw_sp_flood_table *flood_tables; int nr_flood_tables; + const enum mlxsw_sp_fid_flood_profile_id profile_id; /* For CFF mode. */ }; struct mlxsw_sp_fid_family { @@ -1188,6 +1193,7 @@ static const struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = { .flood_tables = mlxsw_sp_fid_8021d_flood_tables, .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE, }; static bool From d79b70dbb76001e51a287d0f7430009068e1e55e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:47 +0100 Subject: [PATCH 1920/7721] mlxsw: spectrum_fid: Initialize flood profiles in CFF mode In CFF flood mode, the way flood vectors are looked up changes: there's a per-FID PGT base, to which a small offset is added depending on type of traffic. Thus each FID occupies a small contiguous block of PGT memory, whereas in the controlled flood mode, flood vectors for a given FID were spread across the PGT. Each FID is associated with one of a handful of profiles. The profile and the traffic type are then used as keys to look up the PGT offset. This offset is then added to the per-FID PGT base. The profile / type / offset mapping needs to be configured by the driver, and is only relevant in CFF flood mode. In this patch, add the SFFP initialization code. Only initialize the one profile currently explicitly used. As follow-up patch add more profiles, this code will pick them up and initialize as well. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/2c4733ed72d439444218969c032acad22cd4ed88.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 123 +++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 2d61fb8bff57..8c4377081872 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -1633,6 +1633,9 @@ static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = { [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, }; +static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = { +}; + static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, enum mlxsw_sp_fid_type type, const void *arg) @@ -2008,12 +2011,130 @@ const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = { .fini = mlxsw_sp_fids_fini, }; +static int mlxsw_sp_fid_check_flood_profile_id(struct mlxsw_sp *mlxsw_sp, + int profile_id) +{ + u32 max_profiles; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_FLOOD_PRF)) + return -EIO; + + max_profiles = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_FLOOD_PRF); + if (WARN_ON_ONCE(!profile_id) || + WARN_ON_ONCE(profile_id >= max_profiles)) + return -EINVAL; + + return 0; +} + +static int +mlxsw_sp2_fids_init_flood_table(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_flood_profile_id profile_id, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + const int *sfgc_packet_types; + int err; + int i; + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + char sffp_pl[MLXSW_REG_SFFP_LEN]; + + if (!sfgc_packet_types[i]) + continue; + + mlxsw_reg_sffp_pack(sffp_pl, profile_id, i, + flood_table->table_index); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sffp), sffp_pl); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_flood_profile * + flood_profile) +{ + int err; + int i; + + err = mlxsw_sp_fid_check_flood_profile_id(mlxsw_sp, + flood_profile->profile_id); + if (err) + return err; + + for (i = 0; i < flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + + flood_table = &flood_profile->flood_tables[i]; + err = mlxsw_sp2_fids_init_flood_table(mlxsw_sp, + flood_profile->profile_id, + flood_table); + if (err) + return err; + } + + return 0; +} + +static const +struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = { + &mlxsw_sp_fid_8021d_flood_profile, +}; + +static int +mlxsw_sp2_fids_init_flood_profiles(struct mlxsw_sp *mlxsw_sp) +{ + int err; + int i; + + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_fid_flood_profiles); i++) { + const struct mlxsw_sp_fid_flood_profile *flood_profile; + + flood_profile = mlxsw_sp_fid_flood_profiles[i]; + err = mlxsw_sp2_fids_init_flood_profile(mlxsw_sp, + flood_profile); + if (err) + return err; + } + + return 0; +} + static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp) { return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl); } +static int mlxsw_sp2_fids_init_cff(struct mlxsw_sp *mlxsw_sp) +{ + int err; + + err = mlxsw_sp2_fids_init_flood_profiles(mlxsw_sp); + if (err) + return err; + + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_cff); +} + +static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + switch (mlxsw_core_flood_mode(mlxsw_sp->core)) { + case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED: + return mlxsw_sp2_fids_init_ctl(mlxsw_sp); + case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF: + return mlxsw_sp2_fids_init_cff(mlxsw_sp); + default: + WARN_ON_ONCE(1); + return -EINVAL; + } +} + const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = { - .init = mlxsw_sp2_fids_init_ctl, + .init = mlxsw_sp2_fids_init, .fini = mlxsw_sp_fids_fini, }; From db3e541b59e2a9d7e57b23451a6e59f395aa1258 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:48 +0100 Subject: [PATCH 1921/7721] mlxsw: spectrum_fid: Add a family for bridge FIDs in CFF flood mode In this patch, add the artifacts for 802.1d and 802.1q FID families that work in CFF flood mode. In CFF flood mode, the way flood vectors are looked up changes: there's a per-FID PGT base, to which a small offset is added depending on type of traffic. Thus each FID occupies a small contiguous block of PGT memory, whereas in the controlled flood mode, flood vectors for a given FID were spread across the PGT. The term "flood table" as used by the spectrum_fid module, borrows from controlled flood mode way of organizing the PGT table. There flood tables were actual tables, contiguous in the PGT. In the CFF flood mode, they are more abstract: a flood table becomes a collection of e.g. all first rows of the per-FID PGT blocks. Nonetheless we retain the nomenclature. FIDs are still configured through the SFMR register, but there are different fields to set under CFF mode: PGT base and profile. Thus register packing gets a dedicated op overload as well. The new organization of PGT makes it possible to treat the PGT as a block of an ordinary memory, allocate and deallocate on demand, and achieve better flexibility. Here instead, we aim to keep the code as close as possible to the previous controlled flood mode, support for which we need to retain for Spectrum-1 and older FW versions anyway. Thus the PGT footprint of the individual families is the same as before, just the internal organization of the per-family PGT region differs. Hence the pgt_size callback is reused between the controlled and CFF flood modes. Since the dummy family has no flood tables in either the CTL mode or in CFF mode, the existing one can be reused for the CFF family array. Users should not notice any changes between the controlled and CFF flood modes. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/ca40b8163e6d6a21f63ef299619acee953cf9519.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 8c4377081872..696a7ed30709 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -493,6 +493,32 @@ static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl, fid->fid_family->bridge_type); } +static u16 +mlxsw_sp_fid_off_pgt_base_cff(const struct mlxsw_sp_fid_family *fid_family, + u16 fid_offset) +{ + return fid_family->pgt_base + + fid_offset * fid_family->flood_profile->nr_flood_tables; +} + +static u16 mlxsw_sp_fid_pgt_base_cff(const struct mlxsw_sp_fid *fid) +{ + return mlxsw_sp_fid_off_pgt_base_cff(fid->fid_family, fid->fid_offset); +} + +static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl, + const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 pgt_base = mlxsw_sp_fid_pgt_base_cff(fid); + + mlxsw_sp_fid_pack(sfmr_pl, fid, op); + mlxsw_reg_sfmr_cff_mid_base_set(sfmr_pl, pgt_base); + mlxsw_reg_sfmr_cff_prf_id_set(sfmr_pl, + fid_family->flood_profile->profile_id); +} + static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; @@ -1168,6 +1194,32 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .fid_pack = mlxsw_sp_fid_pack_ctl, }; +static u16 +mlxsw_sp_fid_fid_mid_cff(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table) +{ + return mlxsw_sp_fid_pgt_base_cff(fid) + flood_table->table_index; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_cff = { + .setup = mlxsw_sp_fid_8021d_setup, + .configure = mlxsw_sp_fid_8021d_configure, + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021d_compare, + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, + .vni_set = mlxsw_sp_fid_8021d_vni_set, + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, + .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, + .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, +}; + #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) #define MLXSW_SP_FID_RFID_MAX (11 * 1024) @@ -1522,6 +1574,25 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .fid_pack = mlxsw_sp_fid_pack_ctl, }; +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_cff = { + .setup = mlxsw_sp_fid_8021q_setup, + .configure = mlxsw_sp_fid_8021q_configure, + .deconfigure = mlxsw_sp_fid_8021q_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021q_compare, + .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, + .vni_set = mlxsw_sp_fid_8021d_vni_set, + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, + .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, + .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, +}; + /* There are 4K-2 802.1Q FIDs */ #define MLXSW_SP_FID_8021Q_START 1 /* FID 0 is reserved. */ #define MLXSW_SP_FID_8021Q_END (MLXSW_SP_FID_8021Q_START + \ @@ -1633,7 +1704,32 @@ static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = { [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, }; +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_cff = { + .type = MLXSW_SP_FID_TYPE_8021Q, + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), + .start_index = MLXSW_SP_FID_8021Q_START, + .end_index = MLXSW_SP_FID_8021Q_END, + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, + .ops = &mlxsw_sp_fid_8021q_ops_cff, + .smpe_index_valid = true, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = { + .type = MLXSW_SP_FID_TYPE_8021D, + .fid_size = sizeof(struct mlxsw_sp_fid_8021d), + .start_index = MLXSW_SP_FID_8021D_START, + .end_index = MLXSW_SP_FID_8021D_END, + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, + .rif_type = MLXSW_SP_RIF_TYPE_FID, + .ops = &mlxsw_sp_fid_8021d_ops_cff, + .smpe_index_valid = true, +}; + static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_cff, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_cff, + [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, }; static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, From 72a4cedb3760ff66446a1a4d006315aad79d573f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:49 +0100 Subject: [PATCH 1922/7721] mlxsw: spectrum_fid: Add support for rFID family in CFF flood mode In this patch, add the artifacts for the rFID family that works in CFF flood mode. The same that was said about PGT organization and lookup in bridge FID families applies for the rFID family as well. The main difference lies in the fact that in the controlled flood mode, the FW was taking care of maintaining the PGT tables for rFIDs. In CFF mode, the responsibility shifts to the driver. All rFIDs are based off either a front panel port, or a LAG port. For those based off ports, we need to maintain at worst one PGT block for each port, for those based off LAGs, one PGT block per LAG. This reflects in the pgt_size callback, which determines the PGT footprint based on number of ports and the LAG capacity. A number of FIDs may end up using the same PGT base. Unlike with bridges, where membership of a port in a given FID is highly dynamic, an rFID based of a port will just always need to flood to that port. Both the port and the LAG subtables need to be actively maintained. To that end, the CFF rFID family implements fid_port_init and fid_port_fini callbacks, which toggle the necessary bits. Both FID-MID translation and SFMR packing then point into either the port or the LAG subtable, to the block that corresponds to a given port or a given LAG, depending on what port the RIF bound to the rFID uses. As in the previous patch, the way CFF flood mode organizes PGT accesses allows for much more smarts and dynamism. As in the previous patch, we rather aim to keep things simple and static. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/962deb4367585d38250e80c685a34735c0c7f3ad.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_fid.c | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 696a7ed30709..401117086235 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -11,6 +11,7 @@ #include #include "spectrum.h" +#include "spectrum_router.h" #include "reg.h" struct mlxsw_sp_fid_family; @@ -115,6 +116,7 @@ struct mlxsw_sp_fid_ops { enum mlxsw_sp_fid_flood_profile_id { MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1, + MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP, }; struct mlxsw_sp_fid_flood_profile { @@ -368,6 +370,36 @@ mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family, return 0; } +static unsigned int mlxsw_sp_fid_rfid_port_offset_cff(unsigned int local_port) +{ + /* Port 0 is the CPU port. Since we never create RIFs based off that + * port, we don't need to count it. + */ + return WARN_ON_ONCE(!local_port) ? 0 : local_port - 1; +} + +static int +mlxsw_sp_fid_rfid_pgt_size_cff(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size) +{ + struct mlxsw_core *core = fid_family->mlxsw_sp->core; + unsigned int max_ports; + u16 pgt_size; + u16 max_lags; + int err; + + max_ports = mlxsw_core_max_ports(core); + + err = mlxsw_core_max_lag(core, &max_lags); + if (err) + return err; + + pgt_size = (mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + max_lags) * + fid_family->flood_profile->nr_flood_tables; + *p_pgt_size = pgt_size; + return 0; +} + static u16 mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family, const struct mlxsw_sp_flood_table *flood_table) @@ -519,6 +551,18 @@ static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl, fid_family->flood_profile->profile_id); } +static u16 mlxsw_sp_fid_rfid_fid_offset_cff(struct mlxsw_sp *mlxsw_sp, + u16 port_lag_id, bool is_lag) +{ + u16 max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + + if (is_lag) + return mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + + port_lag_id; + else + return mlxsw_sp_fid_rfid_port_offset_cff(port_lag_id); +} + static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; @@ -1248,6 +1292,24 @@ struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = { .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE, }; +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_rsp_flood_tables_cff[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_NOT_UC, + .table_index = 1, + }, +}; + +static const +struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_rsp_flood_profile_cff = { + .flood_tables = mlxsw_sp_fid_rsp_flood_tables_cff, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_rsp_flood_tables_cff), + .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP, +}; + static bool mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) { @@ -1271,6 +1333,29 @@ static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid, return 0; } +static int mlxsw_sp_fid_rfid_setup_cff(struct mlxsw_sp_fid *fid, + const void *arg) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + u16 rif_index = *(const u16 *)arg; + struct mlxsw_sp_rif *rif; + bool is_lag; + u16 port; + int err; + + rif = mlxsw_sp_rif_by_index(mlxsw_sp, rif_index); + if (!rif) + return -ENOENT; + + err = mlxsw_sp_rif_subport_port(rif, &port, &is_lag); + if (err) + return err; + + fid->fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port, + is_lag); + return 0; +} + static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) { return mlxsw_sp_fid_op(fid, true); @@ -1410,6 +1495,139 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = { .fid_pack = mlxsw_sp_fid_pack_ctl, }; +static int +mlxsw_sp_fid_rfid_port_add_cff(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_flood_table *flood_table, + u16 pgt_addr, u16 smpe, unsigned int local_port) +{ + int err; + + err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + local_port, true); + if (err) + return err; + + if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) { + u16 router_port = mlxsw_sp_router_port(mlxsw_sp); + + err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + router_port, true); + if (err) + goto err_entry_port_set; + } + + return 0; + +err_entry_port_set: + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port, + false); + return err; +} + +static void +mlxsw_sp_fid_rfid_port_del_cff(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_flood_table *flood_table, + u16 pgt_addr, u16 smpe, u16 local_port) +{ + if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) { + u16 router_port = mlxsw_sp_router_port(mlxsw_sp); + + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + router_port, false); + } + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port, + false); +} + +static int +mlxsw_sp_fid_rfid_port_memb_ft_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table, + const struct mlxsw_sp_port *mlxsw_sp_port, + bool member) +{ + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + u16 local_port = mlxsw_sp_port->local_port; + u16 fid_pgt_base; + u16 fid_offset; + u16 pgt_addr; + u16 smpe; + u16 port; + + /* In-PGT SMPE is only valid on Spectrum-1, CFF only on Spectrum>1. */ + smpe = 0; + + port = mlxsw_sp_port->lagged ? mlxsw_sp_port->lag_id : local_port; + fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port, + mlxsw_sp_port->lagged); + fid_pgt_base = mlxsw_sp_fid_off_pgt_base_cff(fid_family, fid_offset); + pgt_addr = fid_pgt_base + flood_table->table_index; + + if (member) + return mlxsw_sp_fid_rfid_port_add_cff(mlxsw_sp, flood_table, + pgt_addr, smpe, + local_port); + + mlxsw_sp_fid_rfid_port_del_cff(mlxsw_sp, flood_table, pgt_addr, smpe, + local_port); + return 0; +} + +static int +mlxsw_sp_fid_rfid_port_memb_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port, + bool member) +{ + int i; + + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table = + &fid_family->flood_profile->flood_tables[i]; + int err; + + err = mlxsw_sp_fid_rfid_port_memb_ft_cff(fid_family, + flood_table, + mlxsw_sp_port, member); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp_fid_rfid_port_init_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port) +{ + return mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, true); +} + +static void +mlxsw_sp_fid_rfid_port_fini_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_cff = { + .setup = mlxsw_sp_fid_rfid_setup_cff, + .configure = mlxsw_sp_fid_rfid_configure, + .deconfigure = mlxsw_sp_fid_rfid_deconfigure, + .index_alloc = mlxsw_sp_fid_rfid_index_alloc, + .compare = mlxsw_sp_fid_rfid_compare, + .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, + .vni_set = mlxsw_sp_fid_rfid_vni_set, + .vni_clear = mlxsw_sp_fid_rfid_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear, + .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_rfid_pgt_size_cff, + .fid_port_init = mlxsw_sp_fid_rfid_port_init_cff, + .fid_port_fini = mlxsw_sp_fid_rfid_port_fini_cff, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, +}; + static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) { fid->fid_offset = 0; @@ -1726,10 +1944,22 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = { .smpe_index_valid = true, }; +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_cff = { + .type = MLXSW_SP_FID_TYPE_RFID, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_START, + .end_index = MLXSW_SP_RFID_END, + .flood_profile = &mlxsw_sp_fid_rsp_flood_profile_cff, + .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, + .ops = &mlxsw_sp_fid_rfid_ops_cff, + .smpe_index_valid = false, +}; + static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = { [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_cff, [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_cff, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_cff, }; static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, @@ -2180,6 +2410,7 @@ mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp, static const struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = { &mlxsw_sp_fid_8021d_flood_profile, + &mlxsw_sp_fid_rsp_flood_profile_cff, }; static int From 69f289e9c72afc8439b5ad83dd8c46803a097657 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 28 Nov 2023 16:50:50 +0100 Subject: [PATCH 1923/7721] mlxsw: spectrum: Use CFF mode where available Mark all Spectrum>2 systems as preferring CFF flood mode if supported by the firmware. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/8a3d2ad96b943f7e3f53f998bd333a14e19cd641.1701183892.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index e3ef63e265d2..5d3413636a62 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3598,6 +3598,7 @@ static const struct mlxsw_config_profile mlxsw_sp2_config_profile = { .used_cqe_time_stamp_type = 1, .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, .lag_mode_prefer_sw = true, + .flood_mode_prefer_cff = true, }; /* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs @@ -3626,6 +3627,7 @@ static const struct mlxsw_config_profile mlxsw_sp4_config_profile = { .used_cqe_time_stamp_type = 1, .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, .lag_mode_prefer_sw = true, + .flood_mode_prefer_cff = true, }; static void From 6ebf6f90ab4ac09a76172a6d387e8819d3259595 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:45 -0800 Subject: [PATCH 1924/7721] mptcp: add mptcpi_subflows_total counter If the initial subflow has been removed, we cannot know without checking other counters, e.g. ss -ti | grep -c tcp-ulp-mptcp or getsockopt(SOL_MPTCP, MPTCP_FULL_INFO, ...) (or others except MPTCP_INFO of course) and then check mptcp_subflow_data->num_subflows to get the total amount of subflows. This patch adds a new counter mptcpi_subflows_total in mptcpi_flags to store the total amount of subflows, including the initial one. A new helper __mptcp_has_initial_subflow() is added to check whether the initial subflow has been removed or not. With this helper, we can then compute the total amount of subflows from mptcp_info by doing something like: mptcpi_subflows_total = mptcpi_subflows + __mptcp_has_initial_subflow(msk). Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/428 Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-1-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- include/uapi/linux/mptcp.h | 1 + net/mptcp/protocol.h | 9 +++++++++ net/mptcp/sockopt.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index a6451561f3f8..74cfe496891e 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -57,6 +57,7 @@ struct mptcp_info { __u64 mptcpi_bytes_sent; __u64 mptcpi_bytes_received; __u64 mptcpi_bytes_acked; + __u8 mptcpi_subflows_total; }; /* MPTCP Reset reason codes, rfc8684 */ diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index fe6f2d399ee8..458a2d7bb0dd 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1072,6 +1072,15 @@ static inline void __mptcp_do_fallback(struct mptcp_sock *msk) set_bit(MPTCP_FALLBACK_DONE, &msk->flags); } +static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk) +{ + struct sock *ssk = READ_ONCE(msk->first); + + return ssk && ((1 << inet_sk_state_load(ssk)) & + (TCPF_ESTABLISHED | TCPF_SYN_SENT | + TCPF_SYN_RECV | TCPF_LISTEN)); +} + static inline void mptcp_do_fallback(struct sock *ssk) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index 353680733700..cabe856b2a45 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -938,6 +938,8 @@ void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info) info->mptcpi_bytes_sent = msk->bytes_sent; info->mptcpi_bytes_received = msk->bytes_received; info->mptcpi_bytes_retrans = msk->bytes_retrans; + info->mptcpi_subflows_total = info->mptcpi_subflows + + __mptcp_has_initial_subflow(msk); unlock_sock_fast(sk, slow); } EXPORT_SYMBOL_GPL(mptcp_diag_fill_info); From 06848c0f341ee3f9226ed01e519c72e4d2b6f001 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:46 -0800 Subject: [PATCH 1925/7721] selftests: mptcp: add evts_get_info helper This patch adds a new helper get_info_value(), using 'sed' command to parse the value of the given item name in the line with the given keyword, to make chk_mptcp_info() and pedit_action_pkts() more readable. Also add another helper evts_get_info() to use get_info_value() to parse the output of 'pm_nl_ctl events' command, to make all the userspace pm selftests more readable, both in mptcp_join.sh and userspace_pm.sh. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-2-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 19 ++-- .../testing/selftests/net/mptcp/mptcp_lib.sh | 10 +++ .../selftests/net/mptcp/userspace_pm.sh | 86 +++++++++---------- 3 files changed, 57 insertions(+), 58 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 3c94f2f194d6..d24b0e5e73ef 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1869,10 +1869,8 @@ chk_mptcp_info() print_check "mptcp_info ${info1:0:8}=$exp1:$exp2" - cnt1=$(ss -N $ns1 -inmHM | grep "$info1:" | - sed -n 's/.*\('"$info1"':\)\([[:digit:]]*\).*$/\2/p;q') - cnt2=$(ss -N $ns2 -inmHM | grep "$info2:" | - sed -n 's/.*\('"$info2"':\)\([[:digit:]]*\).*$/\2/p;q') + cnt1=$(ss -N $ns1 -inmHM | mptcp_lib_get_info_value "$info1" "$info1") + cnt2=$(ss -N $ns2 -inmHM | mptcp_lib_get_info_value "$info2" "$info2") # 'ss' only display active connections and counters that are not 0. [ -z "$cnt1" ] && cnt1=0 [ -z "$cnt2" ] && cnt2=0 @@ -2848,13 +2846,13 @@ verify_listener_events() return fi - type=$(grep "type:$e_type," $evt | sed -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q') - family=$(grep "type:$e_type," $evt | sed -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q') - sport=$(grep "type:$e_type," $evt | sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + type=$(mptcp_lib_evts_get_info type "$evt" "$e_type") + family=$(mptcp_lib_evts_get_info family "$evt" "$e_type") + sport=$(mptcp_lib_evts_get_info sport "$evt" "$e_type") if [ $family ] && [ $family = $AF_INET6 ]; then - saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') + saddr=$(mptcp_lib_evts_get_info saddr6 "$evt" "$e_type") else - saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q') + saddr=$(mptcp_lib_evts_get_info saddr4 "$evt" "$e_type") fi if [ $type ] && [ $type = $e_type ] && @@ -3249,8 +3247,7 @@ fastclose_tests() pedit_action_pkts() { tc -n $ns2 -j -s action show action pedit index 100 | \ - grep "packets" | \ - sed 's/.*"packets":\([0-9]\+\),.*/\1/' + mptcp_lib_get_info_value \"packets\" packets } fail_tests() diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 92a5befe8039..56cbd57abbae 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -207,3 +207,13 @@ mptcp_lib_result_print_all_tap() { printf "%s\n" "${subtest}" done } + +# get the value of keyword $1 in the line marked by keyword $2 +mptcp_lib_get_info_value() { + grep "${2}" | sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q' +} + +# $1: info name ; $2: evts_ns ; $3: event type +mptcp_lib_evts_get_info() { + mptcp_lib_get_info_value "${1}" "^type:${3:-1}," < "${2}" +} diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh index b25a3e33eb25..2413059a42e5 100755 --- a/tools/testing/selftests/net/mptcp/userspace_pm.sh +++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh @@ -247,14 +247,11 @@ make_connection() local server_token local server_serverside - client_token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") - client_port=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") - client_serverside=$(sed --unbuffered -n 's/.*\(server_side:\)\([[:digit:]]*\).*$/\2/p;q'\ - "$client_evts") - server_token=$(grep "type:1," "$server_evts" | - sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') - server_serverside=$(grep "type:1," "$server_evts" | - sed --unbuffered -n 's/.*\(server_side:\)\([[:digit:]]*\).*$/\2/p;q') + client_token=$(mptcp_lib_evts_get_info token "$client_evts") + client_port=$(mptcp_lib_evts_get_info sport "$client_evts") + client_serverside=$(mptcp_lib_evts_get_info server_side "$client_evts") + server_token=$(mptcp_lib_evts_get_info token "$server_evts") + server_serverside=$(mptcp_lib_evts_get_info server_side "$server_evts") print_test "Established IP${is_v6} MPTCP Connection ns2 => ns1" if [ "$client_token" != "" ] && [ "$server_token" != "" ] && [ "$client_serverside" = 0 ] && @@ -340,16 +337,16 @@ verify_announce_event() local dport local id - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") + type=$(mptcp_lib_evts_get_info type "$evt" $e_type) + token=$(mptcp_lib_evts_get_info token "$evt" $e_type) if [ "$e_af" = "v6" ] then - addr=$(sed --unbuffered -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt") + addr=$(mptcp_lib_evts_get_info daddr6 "$evt" $e_type) else - addr=$(sed --unbuffered -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt") + addr=$(mptcp_lib_evts_get_info daddr4 "$evt" $e_type) fi - dport=$(sed --unbuffered -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - id=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") + dport=$(mptcp_lib_evts_get_info dport "$evt" $e_type) + id=$(mptcp_lib_evts_get_info rem_id "$evt" $e_type) check_expected "type" "token" "addr" "dport" "id" } @@ -367,7 +364,7 @@ test_announce() $client_addr_id dev ns2eth1 > /dev/null 2>&1 local type - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + type=$(mptcp_lib_evts_get_info type "$server_evts") print_test "ADD_ADDR 10.0.2.2 (ns2) => ns1, invalid token" if [ "$type" = "" ] then @@ -446,9 +443,9 @@ verify_remove_event() local token local id - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - id=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") + type=$(mptcp_lib_evts_get_info type "$evt" $e_type) + token=$(mptcp_lib_evts_get_info token "$evt" $e_type) + id=$(mptcp_lib_evts_get_info rem_id "$evt" $e_type) check_expected "type" "token" "id" } @@ -466,7 +463,7 @@ test_remove() $client_addr_id > /dev/null 2>&1 print_test "RM_ADDR id:${client_addr_id} ns2 => ns1, invalid token" local type - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + type=$(mptcp_lib_evts_get_info type "$server_evts") if [ "$type" = "" ] then test_pass @@ -479,7 +476,7 @@ test_remove() ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\ $invalid_id > /dev/null 2>&1 print_test "RM_ADDR id:${invalid_id} ns2 => ns1, invalid id" - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + type=$(mptcp_lib_evts_get_info type "$server_evts") if [ "$type" = "" ] then test_pass @@ -583,19 +580,19 @@ verify_subflow_events() fi fi - type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - family=$(sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - dport=$(sed --unbuffered -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - locid=$(sed --unbuffered -n 's/.*\(loc_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") - remid=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt") + type=$(mptcp_lib_evts_get_info type "$evt" $e_type) + token=$(mptcp_lib_evts_get_info token "$evt" $e_type) + family=$(mptcp_lib_evts_get_info family "$evt" $e_type) + dport=$(mptcp_lib_evts_get_info dport "$evt" $e_type) + locid=$(mptcp_lib_evts_get_info loc_id "$evt" $e_type) + remid=$(mptcp_lib_evts_get_info rem_id "$evt" $e_type) if [ "$family" = "$AF_INET6" ] then - saddr=$(sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt") - daddr=$(sed --unbuffered -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt") + saddr=$(mptcp_lib_evts_get_info saddr6 "$evt" $e_type) + daddr=$(mptcp_lib_evts_get_info daddr6 "$evt" $e_type) else - saddr=$(sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt") - daddr=$(sed --unbuffered -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt") + saddr=$(mptcp_lib_evts_get_info saddr4 "$evt" $e_type) + daddr=$(mptcp_lib_evts_get_info daddr4 "$evt" $e_type) fi check_expected "type" "token" "daddr" "dport" "family" "saddr" "locid" "remid" @@ -630,7 +627,7 @@ test_subflows() kill_wait $listener_pid local sport - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW from server to client machine :>"$server_evts" @@ -668,7 +665,7 @@ test_subflows() # Delete the listener from the client ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW6 from server to client machine :>"$server_evts" @@ -707,7 +704,7 @@ test_subflows() # Delete the listener from the client ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW from server to client machine :>"$server_evts" @@ -745,7 +742,7 @@ test_subflows() # Delete the listener from the server ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW from client to server machine :>"$client_evts" @@ -784,7 +781,7 @@ test_subflows() # Delete the listener from the server ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW6 from client to server machine :>"$client_evts" @@ -821,7 +818,7 @@ test_subflows() # Delete the listener from the server ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW from client to server machine :>"$client_evts" @@ -867,7 +864,7 @@ test_subflows_v4_v6_mix() # Delete the listener from the server ns, if one was created kill_wait $listener_pid - sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) # DESTROY_SUBFLOW from client to server machine :>"$client_evts" @@ -933,18 +930,13 @@ verify_listener_events() print_test "CLOSE_LISTENER $e_saddr:$e_sport" fi - type=$(grep "type:$e_type," $evt | - sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q') - family=$(grep "type:$e_type," $evt | - sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q') - sport=$(grep "type:$e_type," $evt | - sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + type=$(mptcp_lib_evts_get_info type $evt $e_type) + family=$(mptcp_lib_evts_get_info family $evt $e_type) + sport=$(mptcp_lib_evts_get_info sport $evt $e_type) if [ $family ] && [ $family = $AF_INET6 ]; then - saddr=$(grep "type:$e_type," $evt | - sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') + saddr=$(mptcp_lib_evts_get_info saddr6 $evt $e_type) else - saddr=$(grep "type:$e_type," $evt | - sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q') + saddr=$(mptcp_lib_evts_get_info saddr4 $evt $e_type) fi check_expected "type" "family" "saddr" "sport" From 80775412882e273b8ef62124fae861cde8e6fb3d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:47 -0800 Subject: [PATCH 1926/7721] selftests: mptcp: add chk_subflows_total helper This patch adds a new helper chk_subflows_total(), in it use the newly added counter mptcpi_subflows_total to get the "correct" amount of subflows, including the initial one. To be compatible with old 'ss' or kernel versions not supporting this counter, get the total subflows by listing TCP connections that are MPTCP subflows: ss -ti state state established state syn-sent state syn-recv | grep -c tcp-ulp-mptcp. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-3-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index d24b0e5e73ef..566fa0f6506f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1867,7 +1867,7 @@ chk_mptcp_info() local cnt2 local dump_stats - print_check "mptcp_info ${info1:0:8}=$exp1:$exp2" + print_check "mptcp_info ${info1:0:15}=$exp1:$exp2" cnt1=$(ss -N $ns1 -inmHM | mptcp_lib_get_info_value "$info1" "$info1") cnt2=$(ss -N $ns2 -inmHM | mptcp_lib_get_info_value "$info2" "$info2") @@ -1888,6 +1888,42 @@ chk_mptcp_info() fi } +# $1: subflows in ns1 ; $2: subflows in ns2 +# number of all subflows, including the initial subflow. +chk_subflows_total() +{ + local cnt1 + local cnt2 + local info="subflows_total" + local dump_stats + + # if subflows_total counter is supported, use it: + if [ -n "$(ss -N $ns1 -inmHM | mptcp_lib_get_info_value $info $info)" ]; then + chk_mptcp_info $info $1 $info $2 + return + fi + + print_check "$info $1:$2" + + # if not, count the TCP connections that are in fact MPTCP subflows + cnt1=$(ss -N $ns1 -ti state established state syn-sent state syn-recv | + grep -c tcp-ulp-mptcp) + cnt2=$(ss -N $ns2 -ti state established state syn-sent state syn-recv | + grep -c tcp-ulp-mptcp) + + if [ "$1" != "$cnt1" ] || [ "$2" != "$cnt2" ]; then + fail_test "got subflows $cnt1:$cnt2 expected $1:$2" + dump_stats=1 + else + print_ok + fi + + if [ "$dump_stats" = 1 ]; then + ss -N $ns1 -ti + ss -N $ns2 -ti + fi +} + chk_link_usage() { local ns=$1 @@ -3431,10 +3467,12 @@ userspace_tests() chk_join_nr 1 1 1 chk_add_nr 1 1 chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 2 2 chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 chk_rm_nr 1 1 invert chk_mptcp_info subflows 0 subflows 0 + chk_subflows_total 1 1 kill_events_pids wait $tests_pid fi @@ -3451,9 +3489,11 @@ userspace_tests() userspace_pm_add_sf 10.0.3.2 20 chk_join_nr 1 1 1 chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 2 2 userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 chk_rm_nr 1 1 chk_mptcp_info subflows 0 subflows 0 + chk_subflows_total 1 1 kill_events_pids wait $tests_pid fi From 757c828ce94905a2975873d5e90a376c701b2b90 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:48 -0800 Subject: [PATCH 1927/7721] selftests: mptcp: update userspace pm test helpers This patch adds a new argument namespace to userspace_pm_add_addr() and userspace_pm_add_sf() to make these two helper more versatile. Add two more versatile helpers for userspace pm remove subflow or address: userspace_pm_rm_addr() and userspace_pm_rm_sf(). The original test helpers userspace_pm_rm_sf_addr_ns1() and userspace_pm_rm_sf_addr_ns2() can be replaced by these new helpers. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-4-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 98 +++++++++---------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 566fa0f6506f..6d84c7f5296a 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -2848,6 +2848,7 @@ backup_tests() fi } +SUB_ESTABLISHED=10 # MPTCP_EVENT_SUB_ESTABLISHED LISTENER_CREATED=15 #MPTCP_EVENT_LISTENER_CREATED LISTENER_CLOSED=16 #MPTCP_EVENT_LISTENER_CLOSED @@ -3308,75 +3309,70 @@ fail_tests() fi } +# $1: ns ; $2: addr ; $3: id userspace_pm_add_addr() { - local addr=$1 - local id=$2 + local evts=$evts_ns1 local tk - tk=$(grep "type:1," "$evts_ns1" | - sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec $ns1 ./pm_nl_ctl ann $addr token $tk id $id + [ "$1" == "$ns2" ] && evts=$evts_ns2 + tk=$(mptcp_lib_evts_get_info token "$evts") + + ip netns exec $1 ./pm_nl_ctl ann $2 token $tk id $3 sleep 1 } -userspace_pm_rm_sf_addr_ns1() +# $1: ns ; $2: id +userspace_pm_rm_addr() { - local addr=$1 - local id=$2 - local tk sp da dp - local cnt_addr cnt_sf + local evts=$evts_ns1 + local tk + local cnt - tk=$(grep "type:1," "$evts_ns1" | - sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') - sp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - da=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') - dp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') - cnt_addr=$(rm_addr_count ${ns1}) - cnt_sf=$(rm_sf_count ${ns1}) - ip netns exec $ns1 ./pm_nl_ctl rem token $tk id $id - ip netns exec $ns1 ./pm_nl_ctl dsf lip "::ffff:$addr" \ - lport $sp rip $da rport $dp token $tk - wait_rm_addr $ns1 "${cnt_addr}" - wait_rm_sf $ns1 "${cnt_sf}" + [ "$1" == "$ns2" ] && evts=$evts_ns2 + tk=$(mptcp_lib_evts_get_info token "$evts") + + cnt=$(rm_addr_count ${1}) + ip netns exec $1 ./pm_nl_ctl rem token $tk id $2 + wait_rm_addr $1 "${cnt}" } +# $1: ns ; $2: addr ; $3: id userspace_pm_add_sf() { - local addr=$1 - local id=$2 + local evts=$evts_ns1 local tk da dp - tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") - dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - ip netns exec $ns2 ./pm_nl_ctl csf lip $addr lid $id \ + [ "$1" == "$ns2" ] && evts=$evts_ns2 + tk=$(mptcp_lib_evts_get_info token "$evts") + da=$(mptcp_lib_evts_get_info daddr4 "$evts") + dp=$(mptcp_lib_evts_get_info dport "$evts") + + ip netns exec $1 ./pm_nl_ctl csf lip $2 lid $3 \ rip $da rport $dp token $tk sleep 1 } -userspace_pm_rm_sf_addr_ns2() +# $1: ns ; $2: addr $3: event type +userspace_pm_rm_sf() { - local addr=$1 - local id=$2 + local evts=$evts_ns1 + local t=${3:-1} + local ip=4 local tk da dp sp - local cnt_addr cnt_sf + local cnt - tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") - dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - sp=$(grep "type:10" "$evts_ns2" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - cnt_addr=$(rm_addr_count ${ns2}) - cnt_sf=$(rm_sf_count ${ns2}) - ip netns exec $ns2 ./pm_nl_ctl rem token $tk id $id - ip netns exec $ns2 ./pm_nl_ctl dsf lip $addr lport $sp \ + [ "$1" == "$ns2" ] && evts=$evts_ns2 + if is_v6 $2; then ip=6; fi + tk=$(mptcp_lib_evts_get_info token "$evts") + da=$(mptcp_lib_evts_get_info "daddr$ip" "$evts" $t) + dp=$(mptcp_lib_evts_get_info dport "$evts" $t) + sp=$(mptcp_lib_evts_get_info sport "$evts" $t) + + cnt=$(rm_sf_count ${1}) + ip netns exec $1 ./pm_nl_ctl dsf lip $2 lport $sp \ rip $da rport $dp token $tk - wait_rm_addr $ns2 "${cnt_addr}" - wait_rm_sf $ns2 "${cnt_sf}" + wait_rm_sf $1 "${cnt}" } userspace_tests() @@ -3463,13 +3459,14 @@ userspace_tests() run_tests $ns1 $ns2 10.0.1.1 & local tests_pid=$! wait_mpj $ns1 - userspace_pm_add_addr 10.0.2.1 10 + userspace_pm_add_addr $ns1 10.0.2.1 10 chk_join_nr 1 1 1 chk_add_nr 1 1 chk_mptcp_info subflows 1 subflows 1 chk_subflows_total 2 2 chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 - userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 + userspace_pm_rm_addr $ns1 10 + userspace_pm_rm_sf $ns1 "::ffff:10.0.2.1" $SUB_ESTABLISHED chk_rm_nr 1 1 invert chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 @@ -3486,11 +3483,12 @@ userspace_tests() run_tests $ns1 $ns2 10.0.1.1 & local tests_pid=$! wait_mpj $ns2 - userspace_pm_add_sf 10.0.3.2 20 + userspace_pm_add_sf $ns2 10.0.3.2 20 chk_join_nr 1 1 1 chk_mptcp_info subflows 1 subflows 1 chk_subflows_total 2 2 - userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 + userspace_pm_rm_addr $ns2 20 + userspace_pm_rm_sf $ns2 10.0.3.2 $SUB_ESTABLISHED chk_rm_nr 1 1 chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 From b2e2248f365a7ef0687fe048c335fe1a32f98b36 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:49 -0800 Subject: [PATCH 1928/7721] selftests: mptcp: userspace pm create id 0 subflow This patch adds a selftest to create id 0 subflow. Pass id 0 to the helper userspace_pm_add_sf() to create id 0 subflow. chk_mptcp_info shows one subflow but chk_subflows_total shows two subflows in each namespace. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-5-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 6d84c7f5296a..4357a46ca3f3 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -3495,6 +3495,25 @@ userspace_tests() kill_events_pids wait $tests_pid fi + + # userspace pm create id 0 subflow + if reset_with_events "userspace pm create id 0 subflow" && + continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then + set_userspace_pm $ns2 + pm_nl_set_limits $ns1 0 1 + speed=5 \ + run_tests $ns1 $ns2 10.0.1.1 & + local tests_pid=$! + wait_mpj $ns2 + chk_mptcp_info subflows 0 subflows 0 + chk_subflows_total 1 1 + userspace_pm_add_sf $ns2 10.0.3.2 0 + chk_join_nr 1 1 1 + chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 2 2 + kill_events_pids + wait $tests_pid + fi } endpoint_tests() From b3ac570aae6b73eb810207583af0693adca30543 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:50 -0800 Subject: [PATCH 1929/7721] mptcp: userspace pm rename remove_err to out The value of 'err' will not be only '-EINVAL', but can be '0' in some cases. So it's better to rename the label 'remove_err' to 'out' to avoid confusions. Suggested-by: Matthieu Baerts Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-6-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/pm_userspace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index 5c01b9bc619a..efecbe3cf415 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -276,12 +276,12 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) if (!mptcp_pm_is_userspace(msk)) { GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected"); - goto remove_err; + goto out; } if (id_val == 0) { err = mptcp_userspace_pm_remove_id_zero_address(msk, info); - goto remove_err; + goto out; } lock_sock(sk); @@ -296,7 +296,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) if (!match) { GENL_SET_ERR_MSG(info, "address with specified id not found"); release_sock(sk); - goto remove_err; + goto out; } list_move(&match->list, &free_list); @@ -310,7 +310,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) } err = 0; - remove_err: +out: sock_put(sk); return err; } From e3b47e460b4bd0c61d0082f1ac02650dcb79e5d1 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:51 -0800 Subject: [PATCH 1930/7721] selftests: mptcp: userspace pm remove initial subflow This patch adds a selftest for userspace PM to remove the initial subflow. Use userspace_pm_add_sf() to add a subflow, and pass initial IP address to userspace_pm_rm_sf() to remove the initial subflow. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-7-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 4357a46ca3f3..812a5ee54158 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -3514,6 +3514,30 @@ userspace_tests() kill_events_pids wait $tests_pid fi + + # userspace pm remove initial subflow + if reset_with_events "userspace pm remove initial subflow" && + continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then + set_userspace_pm $ns2 + pm_nl_set_limits $ns1 0 1 + speed=5 \ + run_tests $ns1 $ns2 10.0.1.1 & + local tests_pid=$! + wait_mpj $ns2 + userspace_pm_add_sf $ns2 10.0.3.2 20 + chk_join_nr 1 1 1 + chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 2 2 + userspace_pm_rm_sf $ns2 10.0.1.2 + # we don't look at the counter linked to the RM_ADDR but + # to the one linked to the subflows that have been removed + chk_rm_nr 0 1 + chk_rst_nr 0 0 invert + chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 1 1 + kill_events_pids + wait $tests_pid + fi } endpoint_tests() From b9fb176081fb216c43d923888f0d53d9e3a5965b Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:52 -0800 Subject: [PATCH 1931/7721] selftests: mptcp: userspace pm send RM_ADDR for ID 0 This patch adds a selftest for userspace PM to remove id 0 address. Use userspace_pm_add_addr() helper to add an id 10 address, then use userspace_pm_rm_addr() helper to remove id 0 address. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-8-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 812a5ee54158..a98a72e55d2c 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -3538,6 +3538,32 @@ userspace_tests() kill_events_pids wait $tests_pid fi + + # userspace pm send RM_ADDR for ID 0 + if reset_with_events "userspace pm send RM_ADDR for ID 0" && + continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then + set_userspace_pm $ns1 + pm_nl_set_limits $ns2 1 1 + speed=5 \ + run_tests $ns1 $ns2 10.0.1.1 & + local tests_pid=$! + wait_mpj $ns1 + userspace_pm_add_addr $ns1 10.0.2.1 10 + chk_join_nr 1 1 1 + chk_add_nr 1 1 + chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 2 2 + chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 + userspace_pm_rm_addr $ns1 0 + # we don't look at the counter linked to the subflows that + # have been removed but to the one linked to the RM_ADDR + chk_rm_nr 1 0 invert + chk_rst_nr 0 0 invert + chk_mptcp_info subflows 1 subflows 1 + chk_subflows_total 1 1 + kill_events_pids + wait $tests_pid + fi } endpoint_tests() From bdbef0a6ff10603895b0ba39f56bf874cb2b551a Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:53 -0800 Subject: [PATCH 1932/7721] selftests: mptcp: add mptcp_lib_kill_wait To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. Export kill_wait() helper in userspace_pm.sh into mptcp_lib.sh and rename it as mptcp_lib_kill_wait(). It can be used to instead of kill_wait() in mptcp_join.sh. Use the new helper in both scripts. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-9-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 10 ++---- .../testing/selftests/net/mptcp/mptcp_lib.sh | 9 ++++++ .../selftests/net/mptcp/userspace_pm.sh | 31 +++++++------------ 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index a98a72e55d2c..e7557f6a0dc1 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -682,16 +682,10 @@ wait_mpj() done } -kill_wait() -{ - kill $1 > /dev/null 2>&1 - wait $1 2>/dev/null -} - kill_events_pids() { - kill_wait $evts_ns1_pid - kill_wait $evts_ns2_pid + mptcp_lib_kill_wait $evts_ns1_pid + mptcp_lib_kill_wait $evts_ns2_pid } kill_tests_wait() diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 56cbd57abbae..e421b658d748 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -217,3 +217,12 @@ mptcp_lib_get_info_value() { mptcp_lib_evts_get_info() { mptcp_lib_get_info_value "${1}" "^type:${3:-1}," < "${2}" } + +# $1: PID +mptcp_lib_kill_wait() { + [ "${1}" -eq 0 ] && return 0 + + kill -SIGUSR1 "${1}" > /dev/null 2>&1 + kill "${1}" > /dev/null 2>&1 + wait "${1}" 2>/dev/null +} diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh index 2413059a42e5..f4e352494f05 100755 --- a/tools/testing/selftests/net/mptcp/userspace_pm.sh +++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh @@ -108,15 +108,6 @@ test_fail() mptcp_lib_result_fail "${test_name}" } -kill_wait() -{ - [ $1 -eq 0 ] && return 0 - - kill -SIGUSR1 $1 > /dev/null 2>&1 - kill $1 > /dev/null 2>&1 - wait $1 2>/dev/null -} - # This function is used in the cleanup trap #shellcheck disable=SC2317 cleanup() @@ -128,7 +119,7 @@ cleanup() for pid in $client4_pid $server4_pid $client6_pid $server6_pid\ $server_evts_pid $client_evts_pid do - kill_wait $pid + mptcp_lib_kill_wait $pid done local netns @@ -210,7 +201,7 @@ make_connection() fi :>"$client_evts" if [ $client_evts_pid -ne 0 ]; then - kill_wait $client_evts_pid + mptcp_lib_kill_wait $client_evts_pid fi ip netns exec "$ns2" ./pm_nl_ctl events >> "$client_evts" 2>&1 & client_evts_pid=$! @@ -219,7 +210,7 @@ make_connection() fi :>"$server_evts" if [ $server_evts_pid -ne 0 ]; then - kill_wait $server_evts_pid + mptcp_lib_kill_wait $server_evts_pid fi ip netns exec "$ns1" ./pm_nl_ctl events >> "$server_evts" 2>&1 & server_evts_pid=$! @@ -624,7 +615,7 @@ test_subflows() "10.0.2.2" "$client4_port" "23" "$client_addr_id" "ns1" "ns2" # Delete the listener from the client ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid local sport sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) @@ -663,7 +654,7 @@ test_subflows() "$client_addr_id" "ns1" "ns2" # Delete the listener from the client ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) @@ -702,7 +693,7 @@ test_subflows() "$client_addr_id" "ns1" "ns2" # Delete the listener from the client ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$server_evts" $SUB_ESTABLISHED) @@ -740,7 +731,7 @@ test_subflows() "10.0.2.1" "$app4_port" "23" "$server_addr_id" "ns2" "ns1" # Delete the listener from the server ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) @@ -779,7 +770,7 @@ test_subflows() "$server_addr_id" "ns2" "ns1" # Delete the listener from the server ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) @@ -816,7 +807,7 @@ test_subflows() "10.0.2.2" "10.0.2.1" "$new4_port" "23" "$server_addr_id" "ns2" "ns1" # Delete the listener from the server ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) @@ -862,7 +853,7 @@ test_subflows_v4_v6_mix() "$server_addr_id" "ns2" "ns1" # Delete the listener from the server ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sport=$(mptcp_lib_evts_get_info sport "$client_evts" $SUB_ESTABLISHED) @@ -974,7 +965,7 @@ test_listener() sleep 0.5 # Delete the listener from the client ns, if one was created - kill_wait $listener_pid + mptcp_lib_kill_wait $listener_pid sleep 0.5 verify_listener_events $client_evts $LISTENER_CLOSED $AF_INET 10.0.2.2 $client4_port From b850f2c7dd85ecd14a333685c4ffd23f12665e94 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:54 -0800 Subject: [PATCH 1933/7721] selftests: mptcp: add mptcp_lib_is_v6 To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. is_v6() helper is defined in mptcp_connect.sh, mptcp_join.sh and mptcp_sockopt.sh, so export it into mptcp_lib.sh and rename it as mptcp_lib_is_v6(). Use this new helper in all scripts. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-10-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_connect.sh | 16 +++++----------- tools/testing/selftests/net/mptcp/mptcp_join.sh | 14 ++++---------- tools/testing/selftests/net/mptcp/mptcp_lib.sh | 5 +++++ .../testing/selftests/net/mptcp/mptcp_sockopt.sh | 8 +------- 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index b1fc8afd072d..4cf62b2b0480 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -310,12 +310,6 @@ check_mptcp_disabled() return 0 } -# $1: IP address -is_v6() -{ - [ -z "${1##*:*}" ] -} - do_ping() { local listener_ns="$1" @@ -324,7 +318,7 @@ do_ping() local ping_args="-q -c 1" local rc=0 - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then $ipv6 || return 0 ping_args="${ping_args} -6" fi @@ -635,12 +629,12 @@ run_tests_lo() fi # skip if we don't want v6 - if ! $ipv6 && is_v6 "${connect_addr}"; then + if ! $ipv6 && mptcp_lib_is_v6 "${connect_addr}"; then return 0 fi local local_addr - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then local_addr="::" else local_addr="0.0.0.0" @@ -708,7 +702,7 @@ run_test_transparent() TEST_GROUP="${msg}" # skip if we don't want v6 - if ! $ipv6 && is_v6 "${connect_addr}"; then + if ! $ipv6 && mptcp_lib_is_v6 "${connect_addr}"; then return 0 fi @@ -741,7 +735,7 @@ EOF fi local local_addr - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then local_addr="::" r6flag="-6" else diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index e7557f6a0dc1..2ec5c5006d38 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -587,12 +587,6 @@ link_failure() done } -# $1: IP address -is_v6() -{ - [ -z "${1##*:*}" ] -} - # $1: ns, $2: port wait_local_port_listen() { @@ -895,7 +889,7 @@ pm_nl_set_endpoint() local id=10 while [ $add_nr_ns1 -gt 0 ]; do local addr - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then addr="dead:beef:$counter::1" else addr="10.0.$counter.1" @@ -947,7 +941,7 @@ pm_nl_set_endpoint() local id=20 while [ $add_nr_ns2 -gt 0 ]; do local addr - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then addr="dead:beef:$counter::2" else addr="10.0.$counter.2" @@ -989,7 +983,7 @@ pm_nl_set_endpoint() pm_nl_flush_endpoint ${connector_ns} elif [ $rm_nr_ns2 -eq 9 ]; then local addr - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then addr="dead:beef:1::2" else addr="10.0.1.2" @@ -3357,7 +3351,7 @@ userspace_pm_rm_sf() local cnt [ "$1" == "$ns2" ] && evts=$evts_ns2 - if is_v6 $2; then ip=6; fi + if mptcp_lib_is_v6 $2; then ip=6; fi tk=$(mptcp_lib_evts_get_info token "$evts") da=$(mptcp_lib_evts_get_info "daddr$ip" "$evts" $t) dp=$(mptcp_lib_evts_get_info dport "$evts" $t) diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index e421b658d748..447292cad33c 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -226,3 +226,8 @@ mptcp_lib_kill_wait() { kill "${1}" > /dev/null 2>&1 wait "${1}" 2>/dev/null } + +# $1: IP address +mptcp_lib_is_v6() { + [ -z "${1##*:*}" ] +} diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh index a817af6616ec..bfa744e350ef 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -161,12 +161,6 @@ check_transfer() return 0 } -# $1: IP address -is_v6() -{ - [ -z "${1##*:*}" ] -} - do_transfer() { local listener_ns="$1" @@ -183,7 +177,7 @@ do_transfer() local mptcp_connect="./mptcp_connect -r 20" local local_addr ip - if is_v6 "${connect_addr}"; then + if mptcp_lib_is_v6 "${connect_addr}"; then local_addr="::" ip=ipv6 else From 61c131f5d4d2b79904af2fdcb2839a9db8e7c55c Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:55 -0800 Subject: [PATCH 1934/7721] selftests: mptcp: add mptcp_lib_get_counter To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. The helper get_counter() in mptcp_join.sh and get_mib_counter() in mptcp_connect.sh have the same functionality, export get_counter() into mptcp_lib.sh and rename it as mptcp_lib_get_counter(). Use this new helper instead of get_counter() and get_mib_counter(). Use this helper in test_prio() in userspace_pm.sh too instead of open-coding. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-11-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../selftests/net/mptcp/mptcp_connect.sh | 41 +++------ .../testing/selftests/net/mptcp/mptcp_join.sh | 88 ++++++++----------- .../testing/selftests/net/mptcp/mptcp_lib.sh | 16 ++++ .../selftests/net/mptcp/userspace_pm.sh | 14 +-- 4 files changed, 73 insertions(+), 86 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index 4cf62b2b0480..3b971d1617d8 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -335,21 +335,6 @@ do_ping() return 0 } -# $1: ns, $2: MIB counter -get_mib_counter() -{ - local listener_ns="${1}" - local mib="${2}" - - # strip the header - ip netns exec "${listener_ns}" \ - nstat -z -a "${mib}" | \ - tail -n+2 | \ - while read a count c rest; do - echo $count - done -} - # $1: ns, $2: port wait_local_port_listen() { @@ -435,12 +420,12 @@ do_transfer() nstat -n fi - local stat_synrx_last_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") - local stat_ackrx_last_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") - local stat_cookietx_last=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesSent") - local stat_cookierx_last=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesRecv") - local stat_csum_err_s=$(get_mib_counter "${listener_ns}" "MPTcpExtDataCsumErr") - local stat_csum_err_c=$(get_mib_counter "${connector_ns}" "MPTcpExtDataCsumErr") + local stat_synrx_last_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") + local stat_ackrx_last_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") + local stat_cookietx_last=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent") + local stat_cookierx_last=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv") + local stat_csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr") + local stat_csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr") timeout ${timeout_test} \ ip netns exec ${listener_ns} \ @@ -503,11 +488,11 @@ do_transfer() check_transfer $cin $sout "file received by server" rets=$? - local stat_synrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") - local stat_ackrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") - local stat_cookietx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesSent") - local stat_cookierx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesRecv") - local stat_ooo_now=$(get_mib_counter "${listener_ns}" "TcpExtTCPOFOQueue") + local stat_synrx_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") + local stat_ackrx_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") + local stat_cookietx_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent") + local stat_cookierx_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv") + local stat_ooo_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtTCPOFOQueue") expect_synrx=$((stat_synrx_last_l)) expect_ackrx=$((stat_ackrx_last_l)) @@ -536,8 +521,8 @@ do_transfer() fi if $checksum; then - local csum_err_s=$(get_mib_counter "${listener_ns}" "MPTcpExtDataCsumErr") - local csum_err_c=$(get_mib_counter "${connector_ns}" "MPTcpExtDataCsumErr") + local csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr") + local csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr") local csum_err_s_nr=$((csum_err_s - stat_csum_err_s)) if [ $csum_err_s_nr -gt 0 ]; then diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 2ec5c5006d38..a5d66d1bfeb4 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -605,25 +605,9 @@ wait_local_port_listen() done } -# $1: ns ; $2: counter -get_counter() -{ - local ns="${1}" - local counter="${2}" - local count - - count=$(ip netns exec ${ns} nstat -asz "${counter}" | awk 'NR==1 {next} {print $2}') - if [ -z "${count}" ]; then - mptcp_lib_fail_if_expected_feature "${counter} counter" - return 1 - fi - - echo "${count}" -} - rm_addr_count() { - get_counter "${1}" "MPTcpExtRmAddr" + mptcp_lib_get_counter "${1}" "MPTcpExtRmAddr" } # $1: ns, $2: old rm_addr counter in $ns @@ -643,7 +627,7 @@ wait_rm_addr() rm_sf_count() { - get_counter "${1}" "MPTcpExtRmSubflow" + mptcp_lib_get_counter "${1}" "MPTcpExtRmSubflow" } # $1: ns, $2: old rm_sf counter in $ns @@ -666,11 +650,11 @@ wait_mpj() local ns="${1}" local cnt old_cnt - old_cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx") + old_cnt=$(mptcp_lib_get_counter ${ns} "MPTcpExtMPJoinAckRx") local i for i in $(seq 10); do - cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx") + cnt=$(mptcp_lib_get_counter ${ns} "MPTcpExtMPJoinAckRx") [ "$cnt" = "${old_cnt}" ] || break sleep 0.1 done @@ -1272,7 +1256,7 @@ chk_csum_nr() fi print_check "sum" - count=$(get_counter ${ns1} "MPTcpExtDataCsumErr") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtDataCsumErr") if [ "$count" != "$csum_ns1" ]; then extra_msg="$extra_msg ns1=$count" fi @@ -1285,7 +1269,7 @@ chk_csum_nr() print_ok fi print_check "csum" - count=$(get_counter ${ns2} "MPTcpExtDataCsumErr") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtDataCsumErr") if [ "$count" != "$csum_ns2" ]; then extra_msg="$extra_msg ns2=$count" fi @@ -1329,7 +1313,7 @@ chk_fail_nr() fi print_check "ftx" - count=$(get_counter ${ns_tx} "MPTcpExtMPFailTx") + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtMPFailTx") if [ "$count" != "$fail_tx" ]; then extra_msg="$extra_msg,tx=$count" fi @@ -1343,7 +1327,7 @@ chk_fail_nr() fi print_check "failrx" - count=$(get_counter ${ns_rx} "MPTcpExtMPFailRx") + count=$(mptcp_lib_get_counter ${ns_rx} "MPTcpExtMPFailRx") if [ "$count" != "$fail_rx" ]; then extra_msg="$extra_msg,rx=$count" fi @@ -1376,7 +1360,7 @@ chk_fclose_nr() fi print_check "ctx" - count=$(get_counter ${ns_tx} "MPTcpExtMPFastcloseTx") + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtMPFastcloseTx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$fclose_tx" ]; then @@ -1387,7 +1371,7 @@ chk_fclose_nr() fi print_check "fclzrx" - count=$(get_counter ${ns_rx} "MPTcpExtMPFastcloseRx") + count=$(mptcp_lib_get_counter ${ns_rx} "MPTcpExtMPFastcloseRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$fclose_rx" ]; then @@ -1417,7 +1401,7 @@ chk_rst_nr() fi print_check "rtx" - count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx") + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtMPRstTx") if [ -z "$count" ]; then print_skip # accept more rst than expected except if we don't expect any @@ -1429,7 +1413,7 @@ chk_rst_nr() fi print_check "rstrx" - count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx") + count=$(mptcp_lib_get_counter ${ns_rx} "MPTcpExtMPRstRx") if [ -z "$count" ]; then print_skip # accept more rst than expected except if we don't expect any @@ -1450,7 +1434,7 @@ chk_infi_nr() local count print_check "itx" - count=$(get_counter ${ns2} "MPTcpExtInfiniteMapTx") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtInfiniteMapTx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$infi_tx" ]; then @@ -1460,7 +1444,7 @@ chk_infi_nr() fi print_check "infirx" - count=$(get_counter ${ns1} "MPTcpExtInfiniteMapRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtInfiniteMapRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$infi_rx" ]; then @@ -1489,7 +1473,7 @@ chk_join_nr() fi print_check "syn" - count=$(get_counter ${ns1} "MPTcpExtMPJoinSynRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinSynRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$syn_nr" ]; then @@ -1500,7 +1484,7 @@ chk_join_nr() print_check "synack" with_cookie=$(ip netns exec $ns2 sysctl -n net.ipv4.tcp_syncookies) - count=$(get_counter ${ns2} "MPTcpExtMPJoinSynAckRx") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtMPJoinSynAckRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$syn_ack_nr" ]; then @@ -1517,7 +1501,7 @@ chk_join_nr() fi print_check "ack" - count=$(get_counter ${ns1} "MPTcpExtMPJoinAckRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinAckRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$ack_nr" ]; then @@ -1550,8 +1534,8 @@ chk_stale_nr() print_check "stale" - stale_nr=$(get_counter ${ns} "MPTcpExtSubflowStale") - recover_nr=$(get_counter ${ns} "MPTcpExtSubflowRecover") + stale_nr=$(mptcp_lib_get_counter ${ns} "MPTcpExtSubflowStale") + recover_nr=$(mptcp_lib_get_counter ${ns} "MPTcpExtSubflowRecover") if [ -z "$stale_nr" ] || [ -z "$recover_nr" ]; then print_skip elif [ $stale_nr -lt $stale_min ] || @@ -1588,7 +1572,7 @@ chk_add_nr() timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) print_check "add" - count=$(get_counter ${ns2} "MPTcpExtAddAddr") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtAddAddr") if [ -z "$count" ]; then print_skip # if the test configured a short timeout tolerate greater then expected @@ -1600,7 +1584,7 @@ chk_add_nr() fi print_check "echo" - count=$(get_counter ${ns1} "MPTcpExtEchoAdd") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtEchoAdd") if [ -z "$count" ]; then print_skip elif [ "$count" != "$echo_nr" ]; then @@ -1611,7 +1595,7 @@ chk_add_nr() if [ $port_nr -gt 0 ]; then print_check "pt" - count=$(get_counter ${ns2} "MPTcpExtPortAdd") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtPortAdd") if [ -z "$count" ]; then print_skip elif [ "$count" != "$port_nr" ]; then @@ -1621,7 +1605,7 @@ chk_add_nr() fi print_check "syn" - count=$(get_counter ${ns1} "MPTcpExtMPJoinPortSynRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinPortSynRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$syn_nr" ]; then @@ -1632,7 +1616,7 @@ chk_add_nr() fi print_check "synack" - count=$(get_counter ${ns2} "MPTcpExtMPJoinPortSynAckRx") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtMPJoinPortSynAckRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$syn_ack_nr" ]; then @@ -1643,7 +1627,7 @@ chk_add_nr() fi print_check "ack" - count=$(get_counter ${ns1} "MPTcpExtMPJoinPortAckRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinPortAckRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$ack_nr" ]; then @@ -1654,7 +1638,7 @@ chk_add_nr() fi print_check "syn" - count=$(get_counter ${ns1} "MPTcpExtMismatchPortSynRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMismatchPortSynRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$mis_syn_nr" ]; then @@ -1665,7 +1649,7 @@ chk_add_nr() fi print_check "ack" - count=$(get_counter ${ns1} "MPTcpExtMismatchPortAckRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMismatchPortAckRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$mis_ack_nr" ]; then @@ -1687,7 +1671,7 @@ chk_add_tx_nr() timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) print_check "add TX" - count=$(get_counter ${ns1} "MPTcpExtAddAddrTx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtAddAddrTx") if [ -z "$count" ]; then print_skip # if the test configured a short timeout tolerate greater then expected @@ -1699,7 +1683,7 @@ chk_add_tx_nr() fi print_check "echo TX" - count=$(get_counter ${ns2} "MPTcpExtEchoAddTx") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtEchoAddTx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$echo_tx_nr" ]; then @@ -1737,7 +1721,7 @@ chk_rm_nr() fi print_check "rm" - count=$(get_counter ${addr_ns} "MPTcpExtRmAddr") + count=$(mptcp_lib_get_counter ${addr_ns} "MPTcpExtRmAddr") if [ -z "$count" ]; then print_skip elif [ "$count" != "$rm_addr_nr" ]; then @@ -1747,13 +1731,13 @@ chk_rm_nr() fi print_check "rmsf" - count=$(get_counter ${subflow_ns} "MPTcpExtRmSubflow") + count=$(mptcp_lib_get_counter ${subflow_ns} "MPTcpExtRmSubflow") if [ -z "$count" ]; then print_skip elif [ -n "$simult" ]; then local cnt suffix - cnt=$(get_counter ${addr_ns} "MPTcpExtRmSubflow") + cnt=$(mptcp_lib_get_counter ${addr_ns} "MPTcpExtRmSubflow") # in case of simult flush, the subflow removal count on each side is # unreliable @@ -1782,7 +1766,7 @@ chk_rm_tx_nr() local rm_addr_tx_nr=$1 print_check "rm TX" - count=$(get_counter ${ns2} "MPTcpExtRmAddrTx") + count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtRmAddrTx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$rm_addr_tx_nr" ]; then @@ -1799,7 +1783,7 @@ chk_prio_nr() local count print_check "ptx" - count=$(get_counter ${ns1} "MPTcpExtMPPrioTx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPPrioTx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$mp_prio_nr_tx" ]; then @@ -1809,7 +1793,7 @@ chk_prio_nr() fi print_check "prx" - count=$(get_counter ${ns1} "MPTcpExtMPPrioRx") + count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPPrioRx") if [ -z "$count" ]; then print_skip elif [ "$count" != "$mp_prio_nr_rx" ]; then @@ -1943,7 +1927,7 @@ wait_attempt_fail() while [ $time -lt $timeout_ms ]; do local cnt - cnt=$(get_counter ${ns} "TcpAttemptFails") + cnt=$(mptcp_lib_get_counter ${ns} "TcpAttemptFails") [ "$cnt" = 1 ] && return 1 time=$((time + 100)) diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 447292cad33c..718c79dda2b3 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -231,3 +231,19 @@ mptcp_lib_kill_wait() { mptcp_lib_is_v6() { [ -z "${1##*:*}" ] } + +# $1: ns, $2: MIB counter +mptcp_lib_get_counter() { + local ns="${1}" + local counter="${2}" + local count + + count=$(ip netns exec "${ns}" nstat -asz "${counter}" | + awk 'NR==1 {next} {print $2}') + if [ -z "${count}" ]; then + mptcp_lib_fail_if_expected_feature "${counter} counter" + return 1 + fi + + echo "${count}" +} diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh index f4e352494f05..f136956f6c95 100755 --- a/tools/testing/selftests/net/mptcp/userspace_pm.sh +++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh @@ -884,9 +884,10 @@ test_prio() # Check TX print_test "MP_PRIO TX" - count=$(ip netns exec "$ns2" nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ $count != 1 ]; then + count=$(mptcp_lib_get_counter "$ns2" "MPTcpExtMPPrioTx") + if [ -z "$count" ]; then + test_skip + elif [ $count != 1 ]; then test_fail "Count != 1: ${count}" else test_pass @@ -894,9 +895,10 @@ test_prio() # Check RX print_test "MP_PRIO RX" - count=$(ip netns exec "$ns1" nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ $count != 1 ]; then + count=$(mptcp_lib_get_counter "$ns1" "MPTcpExtMPPrioRx") + if [ -z "$count" ]; then + test_skip + elif [ $count != 1 ]; then test_fail "Count != 1: ${count}" else test_pass From 119931cc88ce7073b9a289c13abaf2348d55fdfa Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:56 -0800 Subject: [PATCH 1935/7721] selftests: mptcp: add missing oflag=append In mptcp_connect.sh we are missing something like "oflag=append" because this will write "${rem}" bytes at the beginning of the file where there is already some random bytes. It should write that at the end. This patch adds this missing 'oflag=append' flag for 'dd' command in make_file(). Suggested-by: Matthieu Baerts Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-12-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_connect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index 3b971d1617d8..c4f08976c418 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -593,7 +593,7 @@ make_file() rem=$((SIZE - (ksize * 1024))) dd if=/dev/urandom of="$name" bs=1024 count=$ksize 2> /dev/null - dd if=/dev/urandom conv=notrunc of="$name" bs=1 count=$rem 2> /dev/null + dd if=/dev/urandom conv=notrunc of="$name" oflag=append bs=1 count=$rem 2> /dev/null echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" echo "Created $name (size $(du -b "$name")) containing data sent by $who" From 3a96dea9f88763cfa29e15f681f95fca8952ec77 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:57 -0800 Subject: [PATCH 1936/7721] selftests: mptcp: add mptcp_lib_make_file To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. make_file() helper in mptcp_sockopt.sh and userspace_pm.sh are the same. Export it into mptcp_lib.sh and rename it as mptcp_lib_kill_wait(). Use it in both mptcp_connect.sh and mptcp_join.sh. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-13-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_connect.sh | 3 +-- tools/testing/selftests/net/mptcp/mptcp_join.sh | 3 +-- tools/testing/selftests/net/mptcp/mptcp_lib.sh | 9 +++++++++ tools/testing/selftests/net/mptcp/mptcp_sockopt.sh | 3 +-- tools/testing/selftests/net/mptcp/userspace_pm.sh | 12 +----------- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index c4f08976c418..d20e278480fb 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -592,9 +592,8 @@ make_file() ksize=$((SIZE / 1024)) rem=$((SIZE - (ksize * 1024))) - dd if=/dev/urandom of="$name" bs=1024 count=$ksize 2> /dev/null + mptcp_lib_make_file $name 1024 $ksize dd if=/dev/urandom conv=notrunc of="$name" oflag=append bs=1 count=$rem 2> /dev/null - echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" echo "Created $name (size $(du -b "$name")) containing data sent by $who" } diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index a5d66d1bfeb4..37f434cbfa44 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1171,8 +1171,7 @@ make_file() local who=$2 local size=$3 - dd if=/dev/urandom of="$name" bs=1024 count=$size 2> /dev/null - echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" + mptcp_lib_make_file $name 1024 $size print_info "Test file (size $size KB) for $who" } diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 718c79dda2b3..61be4f29a69a 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -247,3 +247,12 @@ mptcp_lib_get_counter() { echo "${count}" } + +mptcp_lib_make_file() { + local name="${1}" + local bs="${2}" + local size="${3}" + + dd if=/dev/urandom of="${name}" bs="${bs}" count="${size}" 2> /dev/null + echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}" +} diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh index bfa744e350ef..96dc46eda133 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -251,8 +251,7 @@ make_file() local who=$2 local size=$3 - dd if=/dev/urandom of="$name" bs=1024 count=$size 2> /dev/null - echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" + mptcp_lib_make_file $name 1024 $size echo "Created $name (size $size KB) containing data sent by $who" } diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh index f136956f6c95..6167837f48e1 100755 --- a/tools/testing/selftests/net/mptcp/userspace_pm.sh +++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh @@ -164,22 +164,12 @@ print_title "Init" print_test "Created network namespaces ns1, ns2" test_pass -make_file() -{ - # Store a chunk of data in a file to transmit over an MPTCP connection - local name=$1 - local ksize=1 - - dd if=/dev/urandom of="$name" bs=2 count=$ksize 2> /dev/null - echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" -} - make_connection() { if [ -z "$file" ]; then file=$(mktemp) fi - make_file "$file" "client" + mptcp_lib_make_file "$file" 2 1 local is_v6=$1 local app_port=$app4_port From 9d9095bbc24df4432b38fb33a3cf59ea1e9213d0 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:58 -0800 Subject: [PATCH 1937/7721] selftests: mptcp: add mptcp_lib_check_transfer To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. check_transfer() and print_file_err() helpers are defined both in mptcp_connect.sh and mptcp_sockopt.sh, export them into mptcp_lib.sh and rename them with mptcp_lib_ prefix. And use them in all scripts. Note: In mptcp_sockopt.sh it is OK to drop 'ret=1' in check_transfer() because it will be set in run_tests() anyway. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-14-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- .../selftests/net/mptcp/mptcp_connect.sh | 29 ++----------------- .../testing/selftests/net/mptcp/mptcp_join.sh | 11 ++----- .../testing/selftests/net/mptcp/mptcp_lib.sh | 24 +++++++++++++++ .../selftests/net/mptcp/mptcp_sockopt.sh | 28 +----------------- 4 files changed, 29 insertions(+), 63 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index d20e278480fb..537f180aa51e 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -254,31 +254,6 @@ else set_ethtool_flags "$ns4" ns4eth3 "$ethtool_args" fi -print_file_err() -{ - ls -l "$1" 1>&2 - echo "Trailing bytes are: " - tail -c 27 "$1" -} - -check_transfer() -{ - local in=$1 - local out=$2 - local what=$3 - - cmp "$in" "$out" > /dev/null 2>&1 - if [ $? -ne 0 ] ;then - echo "[ FAIL ] $what does not match (in, out):" - print_file_err "$in" - print_file_err "$out" - - return 1 - fi - - return 0 -} - check_mptcp_disabled() { local disabled_ns="ns_disabled-$rndh" @@ -483,9 +458,9 @@ do_transfer() return 1 fi - check_transfer $sin $cout "file received by client" + mptcp_lib_check_transfer $sin $cout "file received by client" retc=$? - check_transfer $cin $sout "file received by server" + mptcp_lib_check_transfer $cin $sout "file received by server" rets=$? local stat_synrx_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 37f434cbfa44..420e4b3f9ad0 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -511,13 +511,6 @@ get_failed_tests_ids() done | sort -n } -print_file_err() -{ - ls -l "$1" 1>&2 - echo -n "Trailing bytes are: " - tail -c 27 "$1" -} - check_transfer() { local in=$1 @@ -548,8 +541,8 @@ check_transfer() local sum=$((0${a} + 0${b})) if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then fail_test "$what does not match (in, out):" - print_file_err "$in" - print_file_err "$out" + mptcp_lib_print_file_err "$in" + mptcp_lib_print_file_err "$out" return 1 else diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 61be4f29a69a..86f4003ab6f6 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -256,3 +256,27 @@ mptcp_lib_make_file() { dd if=/dev/urandom of="${name}" bs="${bs}" count="${size}" 2> /dev/null echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}" } + +# $1: file +mptcp_lib_print_file_err() { + ls -l "${1}" 1>&2 + echo "Trailing bytes are: " + tail -c 27 "${1}" +} + +# $1: input file ; $2: output file ; $3: what kind of file +mptcp_lib_check_transfer() { + local in="${1}" + local out="${2}" + local what="${3}" + + if ! cmp "$in" "$out" > /dev/null 2>&1; then + echo "[ FAIL ] $what does not match (in, out):" + mptcp_lib_print_file_err "$in" + mptcp_lib_print_file_err "$out" + + return 1 + fi + + return 0 +} diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh index 96dc46eda133..c643872ddf47 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -135,32 +135,6 @@ check_mark() return 0 } -print_file_err() -{ - ls -l "$1" 1>&2 - echo "Trailing bytes are: " - tail -c 27 "$1" -} - -check_transfer() -{ - local in=$1 - local out=$2 - local what=$3 - - cmp "$in" "$out" > /dev/null 2>&1 - if [ $? -ne 0 ] ;then - echo "[ FAIL ] $what does not match (in, out):" - print_file_err "$in" - print_file_err "$out" - ret=1 - - return 1 - fi - - return 0 -} - do_transfer() { local listener_ns="$1" @@ -232,7 +206,7 @@ do_transfer() check_mark $connector_ns 4 || retc=1 fi - check_transfer $cin $sout "file received by server" + mptcp_lib_check_transfer $cin $sout "file received by server" rets=$? mptcp_lib_result_code "${retc}" "mark ${ip}" From 9369777c29395730cec967e7d0f48aed872b7110 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 28 Nov 2023 15:18:59 -0800 Subject: [PATCH 1938/7721] selftests: mptcp: add mptcp_lib_wait_local_port_listen To avoid duplicated code in different MPTCP selftests, we can add and use helpers defined in mptcp_lib.sh. wait_local_port_listen() helper is defined in diag.sh, mptcp_connect.sh, mptcp_join.sh and simult_flows.sh, export it into mptcp_lib.sh and rename it with mptcp_lib_ prefix. Use this new helper in all these scripts. Note: We only have IPv4 connections in this helper, not looking at IPv6 (tcp6) but that's OK because we only have IPv4 connections here in diag.sh. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231128-send-net-next-2023107-v4-15-8d6b94150f6b@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/diag.sh | 23 +++---------------- .../selftests/net/mptcp/mptcp_connect.sh | 19 +-------------- .../testing/selftests/net/mptcp/mptcp_join.sh | 20 +--------------- .../testing/selftests/net/mptcp/mptcp_lib.sh | 18 +++++++++++++++ .../selftests/net/mptcp/simult_flows.sh | 19 +-------------- 5 files changed, 24 insertions(+), 75 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/diag.sh b/tools/testing/selftests/net/mptcp/diag.sh index 85a8ee9395b3..95b498efacd1 100755 --- a/tools/testing/selftests/net/mptcp/diag.sh +++ b/tools/testing/selftests/net/mptcp/diag.sh @@ -182,23 +182,6 @@ chk_msk_inuse() __chk_nr get_msk_inuse $expected "$msg" 0 } -# $1: ns, $2: port -wait_local_port_listen() -{ - local listener_ns="${1}" - local port="${2}" - - local port_hex i - - port_hex="$(printf "%04X" "${port}")" - for i in $(seq 10); do - ip netns exec "${listener_ns}" cat /proc/net/tcp | \ - awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && - break - sleep 0.1 - done -} - wait_connected() { local listener_ns="${1}" @@ -222,7 +205,7 @@ echo "a" | \ ip netns exec $ns \ ./mptcp_connect -p 10000 -l -t ${timeout_poll} -w 20 \ 0.0.0.0 >/dev/null & -wait_local_port_listen $ns 10000 +mptcp_lib_wait_local_port_listen $ns 10000 chk_msk_nr 0 "no msk on netns creation" chk_msk_listen 10000 @@ -245,7 +228,7 @@ echo "a" | \ ip netns exec $ns \ ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} -w 20 \ 0.0.0.0 >/dev/null & -wait_local_port_listen $ns 10001 +mptcp_lib_wait_local_port_listen $ns 10001 echo "b" | \ timeout ${timeout_test} \ ip netns exec $ns \ @@ -266,7 +249,7 @@ for I in `seq 1 $NR_CLIENTS`; do ./mptcp_connect -p $((I+10001)) -l -w 20 \ -t ${timeout_poll} 0.0.0.0 >/dev/null & done -wait_local_port_listen $ns $((NR_CLIENTS + 10001)) +mptcp_lib_wait_local_port_listen $ns $((NR_CLIENTS + 10001)) for I in `seq 1 $NR_CLIENTS`; do echo "b" | \ diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index 537f180aa51e..7898d62fce0b 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -310,23 +310,6 @@ do_ping() return 0 } -# $1: ns, $2: port -wait_local_port_listen() -{ - local listener_ns="${1}" - local port="${2}" - - local port_hex i - - port_hex="$(printf "%04X" "${port}")" - for i in $(seq 10); do - ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ - awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && - break - sleep 0.1 - done -} - do_transfer() { local listener_ns="$1" @@ -408,7 +391,7 @@ do_transfer() $extra_args $local_addr < "$sin" > "$sout" & local spid=$! - wait_local_port_listen "${listener_ns}" "${port}" + mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}" local start start=$(date +%s%3N) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 420e4b3f9ad0..8362ea454af3 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -580,24 +580,6 @@ link_failure() done } -# $1: ns, $2: port -wait_local_port_listen() -{ - local listener_ns="${1}" - local port="${2}" - - local port_hex - port_hex="$(printf "%04X" "${port}")" - - local i - for i in $(seq 10); do - ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ - awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && - break - sleep 0.1 - done -} - rm_addr_count() { mptcp_lib_get_counter "${1}" "MPTcpExtRmAddr" @@ -1082,7 +1064,7 @@ do_transfer() fi local spid=$! - wait_local_port_listen "${listener_ns}" "${port}" + mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}" extra_cl_args="$extra_args $extra_cl_args" if [ "$test_linkfail" -eq 0 ];then diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 86f4003ab6f6..022262a2cfe0 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -280,3 +280,21 @@ mptcp_lib_check_transfer() { return 0 } + +# $1: ns, $2: port +mptcp_lib_wait_local_port_listen() { + local listener_ns="${1}" + local port="${2}" + + local port_hex + port_hex="$(printf "%04X" "${port}")" + + local _ + for _ in $(seq 10); do + ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ + awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) \ + {rc=0; exit}} END {exit rc}" && + break + sleep 0.1 + done +} diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh index ce9203b817f8..ae8ad5d6fb9d 100755 --- a/tools/testing/selftests/net/mptcp/simult_flows.sh +++ b/tools/testing/selftests/net/mptcp/simult_flows.sh @@ -123,23 +123,6 @@ setup() grep -q ' kmemleak_init$\| lockdep_init$\| kasan_init$\| prove_locking$' /proc/kallsyms && slack=$((slack+550)) } -# $1: ns, $2: port -wait_local_port_listen() -{ - local listener_ns="${1}" - local port="${2}" - - local port_hex i - - port_hex="$(printf "%04X" "${port}")" - for i in $(seq 10); do - ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ - awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && - break - sleep 0.1 - done -} - do_transfer() { local cin=$1 @@ -179,7 +162,7 @@ do_transfer() 0.0.0.0 < "$sin" > "$sout" & local spid=$! - wait_local_port_listen "${ns3}" "${port}" + mptcp_lib_wait_local_port_listen "${ns3}" "${port}" timeout ${timeout_test} \ ip netns exec ${ns1} \ From 4b86d7c64e8f69824b9b2cc0e9b72842ac2d0e62 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Nov 2023 19:50:27 +0200 Subject: [PATCH 1939/7721] net: dsa: sja1105: Use units.h instead of the copy of a definition BYTES_PER_KBIT is defined in units.h, use that definition. Signed-off-by: Andy Shevchenko Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20231128175027.394754-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/sja1105/sja1105_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 74cee39d73df..6646f7fb0f90 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -21,6 +21,8 @@ #include #include #include +#include + #include "sja1105.h" #include "sja1105_tas.h" @@ -2138,7 +2140,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, sja1105_bridge_member(ds, port, bridge, false); } -#define BYTES_PER_KBIT (1000LL / 8) /* Port 0 (the uC port) does not have CBS shapers */ #define SJA1110_FIXED_CBS(port, prio) ((((port) - 1) * SJA1105_NUM_TC) + (prio)) From f422544118cbdfc3bba7b7c5189e18147acb9047 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Nov 2023 09:53:04 +0000 Subject: [PATCH 1940/7721] net: mana: Fix spelling mistake "enforecement" -> "enforcement" There is a spelling mistake in struct field hc_tx_err_sqpdid_enforecement. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Shradha Gupta Link: https://lore.kernel.org/r/20231128095304.515492-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microsoft/mana/mana_en.c | 2 +- drivers/net/ethernet/microsoft/mana/mana_ethtool.c | 4 ++-- include/net/mana/mana.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 0eb8321d76c9..cb7b9d8ef618 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -2446,7 +2446,7 @@ void mana_query_gf_stats(struct mana_port_context *apc) apc->eth_stats.hc_tx_err_eth_type_enforcement = resp.tx_err_ethtype_enforcement; apc->eth_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement; - apc->eth_stats.hc_tx_err_sqpdid_enforecement = + apc->eth_stats.hc_tx_err_sqpdid_enforcement = resp.tx_err_SQPDID_enforcement; apc->eth_stats.hc_tx_err_cqpdid_enforcement = resp.tx_err_CQPDID_enforcement; diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index 7077d647d99a..777e65b8223d 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -43,8 +43,8 @@ static const struct { offsetof(struct mana_ethtool_stats, hc_tx_err_eth_type_enforcement)}, {"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_stats, hc_tx_err_sa_enforcement)}, - {"hc_tx_err_sqpdid_enforecement", - offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforecement)}, + {"hc_tx_err_sqpdid_enforcement", + offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforcement)}, {"hc_tx_err_cqpdid_enforcement", offsetof(struct mana_ethtool_stats, hc_tx_err_cqpdid_enforcement)}, {"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_stats, diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index 5567f5bc8eb6..76147feb0d10 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -368,7 +368,7 @@ struct mana_ethtool_stats { u64 hc_tx_err_vlan_enforcement; u64 hc_tx_err_eth_type_enforcement; u64 hc_tx_err_sa_enforcement; - u64 hc_tx_err_sqpdid_enforecement; + u64 hc_tx_err_sqpdid_enforcement; u64 hc_tx_err_cqpdid_enforcement; u64 hc_tx_err_mtu_violation; u64 hc_tx_err_inval_oob; From 34efc9cfe7c6d11ccc438ca03b59a1bf43cc60ec Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:17 -0800 Subject: [PATCH 1941/7721] tcp: Clean up reverse xmas tree in cookie_v[46]_check(). We will grow and cut the xmas tree in cookie_v[46]_check(). This patch cleans it up to make later patches tidy. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-2-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/ipv4/syncookies.c | 12 ++++++------ net/ipv6/syncookies.c | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index d37282c06e3d..a0118ea76734 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -331,18 +331,18 @@ EXPORT_SYMBOL_GPL(cookie_tcp_reqsk_alloc); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) { struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; - struct tcp_options_received tcp_opt; - struct inet_request_sock *ireq; - struct tcp_request_sock *treq; - struct tcp_sock *tp = tcp_sk(sk); const struct tcphdr *th = tcp_hdr(skb); __u32 cookie = ntohl(th->ack_seq) - 1; - struct sock *ret = sk; + struct tcp_options_received tcp_opt; + struct tcp_sock *tp = tcp_sk(sk); + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; struct request_sock *req; + struct sock *ret = sk; int full_space, mss; + struct flowi4 fl4; struct rtable *rt; __u8 rcv_wscale; - struct flowi4 fl4; u32 tsoff = 0; int l3index; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 12eedc6ca2cc..aa5fb5486cde 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -127,17 +127,17 @@ EXPORT_SYMBOL_GPL(__cookie_v6_check); struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) { - struct tcp_options_received tcp_opt; - struct inet_request_sock *ireq; - struct tcp_request_sock *treq; - struct ipv6_pinfo *np = inet6_sk(sk); - struct tcp_sock *tp = tcp_sk(sk); const struct tcphdr *th = tcp_hdr(skb); __u32 cookie = ntohl(th->ack_seq) - 1; - struct sock *ret = sk; + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_options_received tcp_opt; + struct tcp_sock *tp = tcp_sk(sk); + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; struct request_sock *req; - int full_space, mss; struct dst_entry *dst; + struct sock *ret = sk; + int full_space, mss; __u8 rcv_wscale; u32 tsoff = 0; int l3index; From 45c28509fee6b4c867374b83c5b9e10dac245988 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:18 -0800 Subject: [PATCH 1942/7721] tcp: Cache sock_net(sk) in cookie_v[46]_check(). sock_net(sk) is used repeatedly in cookie_v[46]_check(). Let's cache it in a variable. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/ipv4/syncookies.c | 21 +++++++++++---------- net/ipv6/syncookies.c | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index a0118ea76734..fb41bb18fe6b 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -336,6 +336,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) struct tcp_options_received tcp_opt; struct tcp_sock *tp = tcp_sk(sk); struct inet_request_sock *ireq; + struct net *net = sock_net(sk); struct tcp_request_sock *treq; struct request_sock *req; struct sock *ret = sk; @@ -346,7 +347,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) u32 tsoff = 0; int l3index; - if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) || + if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) goto out; @@ -355,24 +356,24 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) mss = __cookie_v4_check(ip_hdr(skb), th, cookie); if (mss == 0) { - __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); + __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; } - __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); + __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESRECV); /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); + tcp_parse_options(net, skb, &tcp_opt, 0, NULL); if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { - tsoff = secure_tcp_ts_off(sock_net(sk), + tsoff = secure_tcp_ts_off(net, ip_hdr(skb)->daddr, ip_hdr(skb)->saddr); tcp_opt.rcv_tsecr -= tsoff; } - if (!cookie_timestamp_decode(sock_net(sk), &tcp_opt)) + if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; ret = NULL; @@ -406,13 +407,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->ir_iif = inet_request_bound_dev_if(sk, skb); - l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif); + l3index = l3mdev_master_ifindex_by_index(net, ireq->ir_iif); tcp_ao_syncookie(sk, skb, treq, AF_INET, l3index); /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) */ - RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(sock_net(sk), skb)); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); if (security_inet_conn_request(sk, skb, req)) { reqsk_free(req); @@ -433,7 +434,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) opt->srr ? opt->faddr : ireq->ir_rmt_addr, ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi_common(&fl4)); - rt = ip_route_output_key(sock_net(sk), &fl4); + rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) { reqsk_free(req); goto out; @@ -453,7 +454,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) dst_metric(&rt->dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; - ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, &rt->dst); ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst, tsoff); /* ip_queue_xmit() depends on our flow being setup diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index aa5fb5486cde..ba394fa73f41 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -133,6 +133,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) struct tcp_options_received tcp_opt; struct tcp_sock *tp = tcp_sk(sk); struct inet_request_sock *ireq; + struct net *net = sock_net(sk); struct tcp_request_sock *treq; struct request_sock *req; struct dst_entry *dst; @@ -142,7 +143,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) u32 tsoff = 0; int l3index; - if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) || + if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) goto out; @@ -151,24 +152,24 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) mss = __cookie_v6_check(ipv6_hdr(skb), th, cookie); if (mss == 0) { - __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); + __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; } - __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); + __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESRECV); /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); + tcp_parse_options(net, skb, &tcp_opt, 0, NULL); if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { - tsoff = secure_tcpv6_ts_off(sock_net(sk), + tsoff = secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32, ipv6_hdr(skb)->saddr.s6_addr32); tcp_opt.rcv_tsecr -= tsoff; } - if (!cookie_timestamp_decode(sock_net(sk), &tcp_opt)) + if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; ret = NULL; @@ -217,7 +218,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) treq->ts_off = 0; treq->txhash = net_tx_rndhash(); - l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif); + l3index = l3mdev_master_ifindex_by_index(net, ireq->ir_iif); tcp_ao_syncookie(sk, skb, treq, AF_INET6, l3index); if (IS_ENABLED(CONFIG_SMC)) @@ -243,7 +244,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.flowi6_uid = sk->sk_uid; security_req_classify_flow(req, flowi6_to_flowi_common(&fl6)); - dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p); + dst = ip6_dst_lookup_flow(net, sk, &fl6, final_p); if (IS_ERR(dst)) goto out_free; } @@ -261,7 +262,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) dst_metric(dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; - ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, dst); ret = tcp_get_cookie_sock(sk, skb, req, dst, tsoff); out: From 50468cddd6bc27e75e7377e376674d40fd1b1d73 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:19 -0800 Subject: [PATCH 1943/7721] tcp: Clean up goto labels in cookie_v[46]_check(). We will support arbitrary SYN Cookie with BPF, and then reqsk will be preallocated before cookie_v[46]_check(). Depending on how validation fails, we send RST or just drop skb. To make the error handling easier, let's clean up goto labels. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-4-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/ipv4/syncookies.c | 22 +++++++++++----------- net/ipv6/syncookies.c | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index fb41bb18fe6b..8b7d7d7788af 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -376,11 +376,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - ret = NULL; req = cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, &tcp_request_sock_ipv4_ops, sk, skb); if (!req) - goto out; + goto out_drop; ireq = inet_rsk(req); treq = tcp_rsk(req); @@ -415,10 +414,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) */ RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); - if (security_inet_conn_request(sk, skb, req)) { - reqsk_free(req); - goto out; - } + if (security_inet_conn_request(sk, skb, req)) + goto out_free; req->num_retrans = 0; @@ -435,10 +432,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi_common(&fl4)); rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) { - reqsk_free(req); - goto out; - } + if (IS_ERR(rt)) + goto out_free; /* Try to redo what tcp_v4_send_synack did. */ req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); @@ -462,5 +457,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) */ if (ret) inet_sk(ret)->cork.fl.u.ip4 = fl4; -out: return ret; +out: + return ret; +out_free: + reqsk_free(req); +out_drop: + return NULL; } diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index ba394fa73f41..106376cbc9de 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -172,11 +172,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - ret = NULL; req = cookie_tcp_reqsk_alloc(&tcp6_request_sock_ops, &tcp_request_sock_ipv6_ops, sk, skb); if (!req) - goto out; + goto out_drop; ireq = inet_rsk(req); treq = tcp_rsk(req); @@ -269,5 +268,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) return ret; out_free: reqsk_free(req); +out_drop: return NULL; } From 7577bc8249c3fc86096ef1b1c9a8f4b6232231e7 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:20 -0800 Subject: [PATCH 1944/7721] tcp: Don't pass cookie to __cookie_v[46]_check(). tcp_hdr(skb) and SYN Cookie are passed to __cookie_v[46]_check(), but none of the callers passes cookie other than ntohl(th->ack_seq) - 1. Let's fetch it in __cookie_v[46]_check() instead of passing the cookie over and over. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-5-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/linux/netfilter_ipv6.h | 8 ++++---- include/net/tcp.h | 6 ++---- net/core/filter.c | 15 ++++----------- net/ipv4/syncookies.c | 15 ++++++++------- net/ipv6/syncookies.c | 15 ++++++++------- net/netfilter/nf_synproxy_core.c | 4 ++-- 6 files changed, 28 insertions(+), 35 deletions(-) diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 7834c0be2831..61aa48f46dd7 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -51,7 +51,7 @@ struct nf_ipv6_ops { u32 (*cookie_init_sequence)(const struct ipv6hdr *iph, const struct tcphdr *th, u16 *mssp); int (*cookie_v6_check)(const struct ipv6hdr *iph, - const struct tcphdr *th, __u32 cookie); + const struct tcphdr *th); #endif void (*route_input)(struct sk_buff *skb); int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb, @@ -179,16 +179,16 @@ static inline u32 nf_ipv6_cookie_init_sequence(const struct ipv6hdr *iph, } static inline int nf_cookie_v6_check(const struct ipv6hdr *iph, - const struct tcphdr *th, __u32 cookie) + const struct tcphdr *th) { #if IS_ENABLED(CONFIG_SYN_COOKIES) #if IS_MODULE(CONFIG_IPV6) const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops(); if (v6_ops) - return v6_ops->cookie_v6_check(iph, th, cookie); + return v6_ops->cookie_v6_check(iph, th); #elif IS_BUILTIN(CONFIG_IPV6) - return __cookie_v6_check(iph, th, cookie); + return __cookie_v6_check(iph, th); #endif #endif return 0; diff --git a/include/net/tcp.h b/include/net/tcp.h index d2f0736b76b8..2b2c79c7bbcd 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -491,8 +491,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct dst_entry *dst, u32 tsoff); -int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, - u32 cookie); +int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, const struct tcp_request_sock_ops *af_ops, @@ -586,8 +585,7 @@ bool cookie_ecn_ok(const struct tcp_options_received *opt, const struct net *net, const struct dst_entry *dst); /* From net/ipv6/syncookies.c */ -int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th, - u32 cookie); +int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th); struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, diff --git a/net/core/filter.c b/net/core/filter.c index 7e4d7c3bcc84..0adaa4afa35f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7238,7 +7238,6 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len struct tcphdr *, th, u32, th_len) { #ifdef CONFIG_SYN_COOKIES - u32 cookie; int ret; if (unlikely(!sk || th_len < sizeof(*th))) @@ -7260,8 +7259,6 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len if (tcp_synq_no_recent_overflow(sk)) return -ENOENT; - cookie = ntohl(th->ack_seq) - 1; - /* Both struct iphdr and struct ipv6hdr have the version field at the * same offset so we can cast to the shorter header (struct iphdr). */ @@ -7270,7 +7267,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len if (sk->sk_family == AF_INET6 && ipv6_only_sock(sk)) return -EINVAL; - ret = __cookie_v4_check((struct iphdr *)iph, th, cookie); + ret = __cookie_v4_check((struct iphdr *)iph, th); break; #if IS_BUILTIN(CONFIG_IPV6) @@ -7281,7 +7278,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len if (sk->sk_family != AF_INET6) return -EINVAL; - ret = __cookie_v6_check((struct ipv6hdr *)iph, th, cookie); + ret = __cookie_v6_check((struct ipv6hdr *)iph, th); break; #endif /* CONFIG_IPV6 */ @@ -7734,9 +7731,7 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = { BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph, struct tcphdr *, th) { - u32 cookie = ntohl(th->ack_seq) - 1; - - if (__cookie_v4_check(iph, th, cookie) > 0) + if (__cookie_v4_check(iph, th) > 0) return 0; return -EACCES; @@ -7757,9 +7752,7 @@ BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv6, struct ipv6hdr *, iph, struct tcphdr *, th) { #if IS_BUILTIN(CONFIG_IPV6) - u32 cookie = ntohl(th->ack_seq) - 1; - - if (__cookie_v6_check(iph, th, cookie) > 0) + if (__cookie_v6_check(iph, th) > 0) return 0; return -EACCES; diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 8b7d7d7788af..c08428d63d11 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -189,12 +189,14 @@ __u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mssp) * Check if a ack sequence number is a valid syncookie. * Return the decoded mss if it is, or 0 if not. */ -int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, - u32 cookie) +int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th) { + __u32 cookie = ntohl(th->ack_seq) - 1; __u32 seq = ntohl(th->seq) - 1; - __u32 mssind = check_tcp_syn_cookie(cookie, iph->saddr, iph->daddr, - th->source, th->dest, seq); + __u32 mssind; + + mssind = check_tcp_syn_cookie(cookie, iph->saddr, iph->daddr, + th->source, th->dest, seq); return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; } @@ -332,7 +334,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) { struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; const struct tcphdr *th = tcp_hdr(skb); - __u32 cookie = ntohl(th->ack_seq) - 1; struct tcp_options_received tcp_opt; struct tcp_sock *tp = tcp_sk(sk); struct inet_request_sock *ireq; @@ -354,7 +355,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (tcp_synq_no_recent_overflow(sk)) goto out; - mss = __cookie_v4_check(ip_hdr(skb), th, cookie); + mss = __cookie_v4_check(ip_hdr(skb), th); if (mss == 0) { __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; @@ -384,7 +385,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); treq = tcp_rsk(req); treq->rcv_isn = ntohl(th->seq) - 1; - treq->snt_isn = cookie; + treq->snt_isn = ntohl(th->ack_seq) - 1; treq->ts_off = 0; treq->txhash = net_tx_rndhash(); req->mss = mss; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 106376cbc9de..4cd26c481168 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -114,12 +114,14 @@ __u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mssp) return __cookie_v6_init_sequence(iph, th, mssp); } -int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th, - __u32 cookie) +int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th) { + __u32 cookie = ntohl(th->ack_seq) - 1; __u32 seq = ntohl(th->seq) - 1; - __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, - th->source, th->dest, seq); + __u32 mssind; + + mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, + th->source, th->dest, seq); return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; } @@ -128,7 +130,6 @@ EXPORT_SYMBOL_GPL(__cookie_v6_check); struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) { const struct tcphdr *th = tcp_hdr(skb); - __u32 cookie = ntohl(th->ack_seq) - 1; struct ipv6_pinfo *np = inet6_sk(sk); struct tcp_options_received tcp_opt; struct tcp_sock *tp = tcp_sk(sk); @@ -150,7 +151,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (tcp_synq_no_recent_overflow(sk)) goto out; - mss = __cookie_v6_check(ipv6_hdr(skb), th, cookie); + mss = __cookie_v6_check(ipv6_hdr(skb), th); if (mss == 0) { __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; @@ -213,7 +214,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; treq->snt_synack = 0; treq->rcv_isn = ntohl(th->seq) - 1; - treq->snt_isn = cookie; + treq->snt_isn = ntohl(th->ack_seq) - 1; treq->ts_off = 0; treq->txhash = net_tx_rndhash(); diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index 467671f2d42f..fbbc4fd37349 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -617,7 +617,7 @@ synproxy_recv_client_ack(struct net *net, struct synproxy_net *snet = synproxy_pernet(net); int mss; - mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1); + mss = __cookie_v4_check(ip_hdr(skb), th); if (mss == 0) { this_cpu_inc(snet->stats->cookie_invalid); return false; @@ -1034,7 +1034,7 @@ synproxy_recv_client_ack_ipv6(struct net *net, struct synproxy_net *snet = synproxy_pernet(net); int mss; - mss = nf_cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1); + mss = nf_cookie_v6_check(ipv6_hdr(skb), th); if (mss == 0) { this_cpu_inc(snet->stats->cookie_invalid); return false; From efce3d1fdff53ef45b11ff407f16bc2f6f292b93 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:21 -0800 Subject: [PATCH 1945/7721] tcp: Don't initialise tp->tsoffset in tcp_get_cookie_sock(). When we create a full socket from SYN Cookie, we initialise tcp_sk(sk)->tsoffset redundantly in tcp_get_cookie_sock() as the field is inherited from tcp_rsk(req)->ts_off. cookie_v[46]_check |- treq->ts_off = 0 `- tcp_get_cookie_sock |- tcp_v[46]_syn_recv_sock | `- tcp_create_openreq_child | `- newtp->tsoffset = treq->ts_off `- tcp_sk(child)->tsoffset = tsoff Let's initialise tcp_rsk(req)->ts_off with the correct offset and remove the second initialisation of tcp_sk(sk)->tsoffset. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-6-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/tcp.h | 2 +- net/ipv4/syncookies.c | 7 +++---- net/ipv6/syncookies.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 2b2c79c7bbcd..cc7143a781da 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -490,7 +490,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); /* From syncookies.c */ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, - struct dst_entry *dst, u32 tsoff); + struct dst_entry *dst); int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index c08428d63d11..de051eb08db8 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -204,7 +204,7 @@ EXPORT_SYMBOL_GPL(__cookie_v4_check); struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, - struct dst_entry *dst, u32 tsoff) + struct dst_entry *dst) { struct inet_connection_sock *icsk = inet_csk(sk); struct sock *child; @@ -214,7 +214,6 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, NULL, &own_req); if (child) { refcount_set(&req->rsk_refcnt, 1); - tcp_sk(child)->tsoffset = tsoff; sock_rps_save_rxhash(child, skb); if (rsk_drop_req(req)) { @@ -386,7 +385,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) treq = tcp_rsk(req); treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = ntohl(th->ack_seq) - 1; - treq->ts_off = 0; + treq->ts_off = tsoff; treq->txhash = net_tx_rndhash(); req->mss = mss; ireq->ir_num = ntohs(th->dest); @@ -452,7 +451,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, &rt->dst); - ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst, tsoff); + ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst); /* ip_queue_xmit() depends on our flow being setup * Normal sockets get it right from inet_csk_route_child_sock() */ diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 4cd26c481168..18c2e3c1677b 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -215,7 +215,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) treq->snt_synack = 0; treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = ntohl(th->ack_seq) - 1; - treq->ts_off = 0; + treq->ts_off = tsoff; treq->txhash = net_tx_rndhash(); l3index = l3mdev_master_ifindex_by_index(net, ireq->ir_iif); @@ -264,7 +264,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, dst); - ret = tcp_get_cookie_sock(sk, skb, req, dst, tsoff); + ret = tcp_get_cookie_sock(sk, skb, req, dst); out: return ret; out_free: From 7b0f570f879adecf12329ecd60485e7e6b4783c1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:22 -0800 Subject: [PATCH 1946/7721] tcp: Move TCP-AO bits from cookie_v[46]_check() to tcp_ao_syncookie(). We initialise treq->af_specific in cookie_tcp_reqsk_alloc() so that we can look up a key later in tcp_create_openreq_child(). Initially, that change was added for MD5 by commit ba5a4fdd63ae ("tcp: make sure treq->af_specific is initialized"), but it has not been used since commit d0f2b7a9ca0a ("tcp: Disable header prediction for MD5 flow."). Now, treq->af_specific is used only by TCP-AO, so, we can move that initialisation into tcp_ao_syncookie(). In addition to that, l3index in cookie_v[46]_check() is only used for tcp_ao_syncookie(), so let's move it as well. While at it, we move down tcp_ao_syncookie() in cookie_v4_check() so that it will be called after security_inet_conn_request() to make functions order consistent with cookie_v6_check(). Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-7-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/tcp.h | 1 - include/net/tcp_ao.h | 6 ++---- net/ipv4/syncookies.c | 16 ++++------------ net/ipv4/tcp_ao.c | 16 ++++++++++++++-- net/ipv6/syncookies.c | 7 ++----- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index cc7143a781da..d4d0e9763175 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -494,7 +494,6 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, - const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct sk_buff *skb); #ifdef CONFIG_SYN_COOKIES diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h index b56be10838f0..4d900ef8dfc3 100644 --- a/include/net/tcp_ao.h +++ b/include/net/tcp_ao.h @@ -265,8 +265,7 @@ void tcp_ao_established(struct sock *sk); void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb); void tcp_ao_connect_init(struct sock *sk); void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb, - struct tcp_request_sock *treq, - unsigned short int family, int l3index); + struct request_sock *req, unsigned short int family); #else /* CONFIG_TCP_AO */ static inline int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, @@ -277,8 +276,7 @@ static inline int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, } static inline void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb, - struct tcp_request_sock *treq, - unsigned short int family, int l3index) + struct request_sock *req, unsigned short int family) { } diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index de051eb08db8..1e3783c97e28 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -286,9 +286,7 @@ bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt, EXPORT_SYMBOL(cookie_ecn_ok); struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, - const struct tcp_request_sock_ops *af_ops, - struct sock *sk, - struct sk_buff *skb) + struct sock *sk, struct sk_buff *skb) { struct tcp_request_sock *treq; struct request_sock *req; @@ -303,9 +301,6 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, treq = tcp_rsk(req); - /* treq->af_specific might be used to perform TCP_MD5 lookup */ - treq->af_specific = af_ops; - treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; treq->req_usec_ts = false; @@ -345,7 +340,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) struct rtable *rt; __u8 rcv_wscale; u32 tsoff = 0; - int l3index; if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) @@ -376,8 +370,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - req = cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, - &tcp_request_sock_ipv4_ops, sk, skb); + req = cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, sk, skb); if (!req) goto out_drop; @@ -406,9 +399,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->ir_iif = inet_request_bound_dev_if(sk, skb); - l3index = l3mdev_master_ifindex_by_index(net, ireq->ir_iif); - tcp_ao_syncookie(sk, skb, treq, AF_INET, l3index); - /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) */ @@ -417,6 +407,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (security_inet_conn_request(sk, skb, req)) goto out_free; + tcp_ao_syncookie(sk, skb, req, AF_INET); + req->num_retrans = 0; /* diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c index 7696417d0640..c4cd1e09eb6b 100644 --- a/net/ipv4/tcp_ao.c +++ b/net/ipv4/tcp_ao.c @@ -844,18 +844,30 @@ static struct tcp_ao_key *tcp_ao_inbound_lookup(unsigned short int family, } void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb, - struct tcp_request_sock *treq, - unsigned short int family, int l3index) + struct request_sock *req, unsigned short int family) { + struct tcp_request_sock *treq = tcp_rsk(req); const struct tcphdr *th = tcp_hdr(skb); const struct tcp_ao_hdr *aoh; struct tcp_ao_key *key; + int l3index; + + /* treq->af_specific is used to perform TCP_AO lookup + * in tcp_create_openreq_child(). + */ +#if IS_ENABLED(CONFIG_IPV6) + if (family == AF_INET6) + treq->af_specific = &tcp_request_sock_ipv6_ops; + else +#endif + treq->af_specific = &tcp_request_sock_ipv4_ops; treq->maclen = 0; if (tcp_parse_auth_options(th, NULL, &aoh) || !aoh) return; + l3index = l3mdev_master_ifindex_by_index(sock_net(sk), inet_rsk(req)->ir_iif); key = tcp_ao_inbound_lookup(family, sk, skb, -1, aoh->keyid, l3index); if (!key) /* Key not found, continue without TCP-AO */ diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 18c2e3c1677b..12b1809245f9 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -142,7 +142,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) int full_space, mss; __u8 rcv_wscale; u32 tsoff = 0; - int l3index; if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) @@ -173,8 +172,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - req = cookie_tcp_reqsk_alloc(&tcp6_request_sock_ops, - &tcp_request_sock_ipv6_ops, sk, skb); + req = cookie_tcp_reqsk_alloc(&tcp6_request_sock_ops, sk, skb); if (!req) goto out_drop; @@ -218,8 +216,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) treq->ts_off = tsoff; treq->txhash = net_tx_rndhash(); - l3index = l3mdev_master_ifindex_by_index(net, ireq->ir_iif); - tcp_ao_syncookie(sk, skb, treq, AF_INET6, l3index); + tcp_ao_syncookie(sk, skb, req, AF_INET6); if (IS_ENABLED(CONFIG_SMC)) ireq->smc_ok = 0; From de5626b95e13a054aa80f890f2a774d2fc18d855 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:23 -0800 Subject: [PATCH 1947/7721] tcp: Factorise cookie-independent fields initialisation in cookie_v[46]_check(). We will support arbitrary SYN Cookie with BPF, and then some reqsk fields are initialised in kfunc, and others are done in cookie_v[46]_check(). This patch factorises the common part as cookie_tcp_reqsk_init() and calls it in cookie_tcp_reqsk_alloc() to minimise the discrepancy between cookie_v[46]_check(). Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-8-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/ipv4/syncookies.c | 68 +++++++++++++++++++++++-------------------- net/ipv6/syncookies.c | 14 --------- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 1e3783c97e28..f4bcd4822fe0 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -285,10 +285,43 @@ bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt, } EXPORT_SYMBOL(cookie_ecn_ok); +static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, + struct request_sock *req) +{ + struct inet_request_sock *ireq = inet_rsk(req); + struct tcp_request_sock *treq = tcp_rsk(req); + const struct tcphdr *th = tcp_hdr(skb); + + req->num_retrans = 0; + + ireq->ir_num = ntohs(th->dest); + ireq->ir_rmt_port = th->source; + ireq->ir_iif = inet_request_bound_dev_if(sk, skb); + ireq->ir_mark = inet_request_mark(sk, skb); + + if (IS_ENABLED(CONFIG_SMC)) + ireq->smc_ok = 0; + + treq->snt_synack = 0; + treq->tfo_listener = false; + treq->txhash = net_tx_rndhash(); + treq->rcv_isn = ntohl(th->seq) - 1; + treq->snt_isn = ntohl(th->ack_seq) - 1; + treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; + treq->req_usec_ts = false; + +#if IS_ENABLED(CONFIG_MPTCP) + treq->is_mptcp = sk_is_mptcp(sk); + if (treq->is_mptcp) + return mptcp_subflow_init_cookie_req(req, sk, skb); +#endif + + return 0; +} + struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk, struct sk_buff *skb) { - struct tcp_request_sock *treq; struct request_sock *req; if (sk_is_mptcp(sk)) @@ -299,22 +332,10 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, if (!req) return NULL; - treq = tcp_rsk(req); - - treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; - treq->req_usec_ts = false; - -#if IS_ENABLED(CONFIG_MPTCP) - treq->is_mptcp = sk_is_mptcp(sk); - if (treq->is_mptcp) { - int err = mptcp_subflow_init_cookie_req(req, sk, skb); - - if (err) { - reqsk_free(req); - return NULL; - } + if (cookie_tcp_reqsk_init(sk, skb, req)) { + reqsk_free(req); + return NULL; } -#endif return req; } @@ -376,28 +397,15 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); treq = tcp_rsk(req); - treq->rcv_isn = ntohl(th->seq) - 1; - treq->snt_isn = ntohl(th->ack_seq) - 1; treq->ts_off = tsoff; - treq->txhash = net_tx_rndhash(); req->mss = mss; - ireq->ir_num = ntohs(th->dest); - ireq->ir_rmt_port = th->source; sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); - ireq->ir_mark = inet_request_mark(sk, skb); ireq->snd_wscale = tcp_opt.snd_wscale; ireq->sack_ok = tcp_opt.sack_ok; ireq->wscale_ok = tcp_opt.wscale_ok; ireq->tstamp_ok = tcp_opt.saw_tstamp; req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; - treq->snt_synack = 0; - treq->tfo_listener = false; - - if (IS_ENABLED(CONFIG_SMC)) - ireq->smc_ok = 0; - - ireq->ir_iif = inet_request_bound_dev_if(sk, skb); /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) @@ -409,8 +417,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) tcp_ao_syncookie(sk, skb, req, AF_INET); - req->num_retrans = 0; - /* * We need to lookup the route here to get at the correct * window size. We should better make sure that the window size diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 12b1809245f9..e0a9220d1536 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -178,11 +178,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); treq = tcp_rsk(req); - treq->tfo_listener = false; req->mss = mss; - ireq->ir_rmt_port = th->source; - ireq->ir_num = ntohs(th->dest); ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; @@ -196,31 +193,20 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->pktopts = skb; } - ireq->ir_iif = inet_request_bound_dev_if(sk, skb); /* So that link locals have meaning */ if (!sk->sk_bound_dev_if && ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) ireq->ir_iif = tcp_v6_iif(skb); - ireq->ir_mark = inet_request_mark(sk, skb); - - req->num_retrans = 0; ireq->snd_wscale = tcp_opt.snd_wscale; ireq->sack_ok = tcp_opt.sack_ok; ireq->wscale_ok = tcp_opt.wscale_ok; ireq->tstamp_ok = tcp_opt.saw_tstamp; req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; - treq->snt_synack = 0; - treq->rcv_isn = ntohl(th->seq) - 1; - treq->snt_isn = ntohl(th->ack_seq) - 1; treq->ts_off = tsoff; - treq->txhash = net_tx_rndhash(); tcp_ao_syncookie(sk, skb, req, AF_INET6); - if (IS_ENABLED(CONFIG_SMC)) - ireq->smc_ok = 0; - /* * We need to lookup the dst_entry to get the correct window size. * This is taken from tcp_v6_syn_recv_sock. Somebody please enlighten From 8e7bab6b9652cd07a05ee0380b623c0e00e3eb00 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 28 Nov 2023 18:29:24 -0800 Subject: [PATCH 1948/7721] tcp: Factorise cookie-dependent fields initialisation in cookie_v[46]_check() We will support arbitrary SYN Cookie with BPF, and then kfunc at TC will preallocate reqsk and initialise some fields that should not be overwritten later by cookie_v[46]_check(). To simplify the flow in cookie_v[46]_check(), we move such fields' initialisation to cookie_tcp_reqsk_alloc() and factorise non-BPF SYN Cookie handling into cookie_tcp_check(), where we validate the cookie and allocate reqsk, as done by kfunc later. Note that we set ireq->ecn_ok in two steps, the latter of which will be shared by the BPF case. As cookie_ecn_ok() is one-liner, now it's inlined. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20231129022924.96156-9-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/tcp.h | 13 ++++-- net/ipv4/syncookies.c | 106 +++++++++++++++++++++++------------------- net/ipv6/syncookies.c | 61 ++++++++++++------------ 3 files changed, 99 insertions(+), 81 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index d4d0e9763175..973555cb1d3f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -494,7 +494,10 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, - struct sock *sk, struct sk_buff *skb); + struct sock *sk, struct sk_buff *skb, + struct tcp_options_received *tcp_opt, + int mss, u32 tsoff); + #ifdef CONFIG_SYN_COOKIES /* Syncookies use a monotonic timer which increments every 60 seconds. @@ -580,8 +583,12 @@ __u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); u64 cookie_init_timestamp(struct request_sock *req, u64 now); bool cookie_timestamp_decode(const struct net *net, struct tcp_options_received *opt); -bool cookie_ecn_ok(const struct tcp_options_received *opt, - const struct net *net, const struct dst_entry *dst); + +static inline bool cookie_ecn_ok(const struct net *net, const struct dst_entry *dst) +{ + return READ_ONCE(net->ipv4.sysctl_tcp_ecn) || + dst_feature(dst, RTAX_FEATURE_ECN); +} /* From net/ipv6/syncookies.c */ int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index f4bcd4822fe0..61f1c96cfe63 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -270,21 +270,6 @@ bool cookie_timestamp_decode(const struct net *net, } EXPORT_SYMBOL(cookie_timestamp_decode); -bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt, - const struct net *net, const struct dst_entry *dst) -{ - bool ecn_ok = tcp_opt->rcv_tsecr & TS_OPT_ECN; - - if (!ecn_ok) - return false; - - if (READ_ONCE(net->ipv4.sysctl_tcp_ecn)) - return true; - - return dst_feature(dst, RTAX_FEATURE_ECN); -} -EXPORT_SYMBOL(cookie_ecn_ok); - static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, struct request_sock *req) { @@ -320,8 +305,12 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, } struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, - struct sock *sk, struct sk_buff *skb) + struct sock *sk, struct sk_buff *skb, + struct tcp_options_received *tcp_opt, + int mss, u32 tsoff) { + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; struct request_sock *req; if (sk_is_mptcp(sk)) @@ -337,40 +326,36 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, return NULL; } + ireq = inet_rsk(req); + treq = tcp_rsk(req); + + req->mss = mss; + req->ts_recent = tcp_opt->saw_tstamp ? tcp_opt->rcv_tsval : 0; + + ireq->snd_wscale = tcp_opt->snd_wscale; + ireq->tstamp_ok = tcp_opt->saw_tstamp; + ireq->sack_ok = tcp_opt->sack_ok; + ireq->wscale_ok = tcp_opt->wscale_ok; + ireq->ecn_ok = !!(tcp_opt->rcv_tsecr & TS_OPT_ECN); + + treq->ts_off = tsoff; + return req; } EXPORT_SYMBOL_GPL(cookie_tcp_reqsk_alloc); -/* On input, sk is a listener. - * Output is listener if incoming packet would not create a child - * NULL if memory could not be allocated. - */ -struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) +static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk, + struct sk_buff *skb) { - struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; - const struct tcphdr *th = tcp_hdr(skb); struct tcp_options_received tcp_opt; - struct tcp_sock *tp = tcp_sk(sk); - struct inet_request_sock *ireq; - struct net *net = sock_net(sk); - struct tcp_request_sock *treq; - struct request_sock *req; - struct sock *ret = sk; - int full_space, mss; - struct flowi4 fl4; - struct rtable *rt; - __u8 rcv_wscale; u32 tsoff = 0; - - if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || - !th->ack || th->rst) - goto out; + int mss; if (tcp_synq_no_recent_overflow(sk)) goto out; - mss = __cookie_v4_check(ip_hdr(skb), th); - if (mss == 0) { + mss = __cookie_v4_check(ip_hdr(skb), tcp_hdr(skb)); + if (!mss) { __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; } @@ -391,21 +376,44 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - req = cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, sk, skb); + return cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, sk, skb, + &tcp_opt, mss, tsoff); +out: + return ERR_PTR(-EINVAL); +} + +/* On input, sk is a listener. + * Output is listener if incoming packet would not create a child + * NULL if memory could not be allocated. + */ +struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) +{ + struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; + const struct tcphdr *th = tcp_hdr(skb); + struct tcp_sock *tp = tcp_sk(sk); + struct inet_request_sock *ireq; + struct net *net = sock_net(sk); + struct request_sock *req; + struct sock *ret = sk; + struct flowi4 fl4; + struct rtable *rt; + __u8 rcv_wscale; + int full_space; + + if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || + !th->ack || th->rst) + goto out; + + req = cookie_tcp_check(net, sk, skb); + if (IS_ERR(req)) + goto out; if (!req) goto out_drop; ireq = inet_rsk(req); - treq = tcp_rsk(req); - treq->ts_off = tsoff; - req->mss = mss; + sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); - ireq->snd_wscale = tcp_opt.snd_wscale; - ireq->sack_ok = tcp_opt.sack_ok; - ireq->wscale_ok = tcp_opt.wscale_ok; - ireq->tstamp_ok = tcp_opt.saw_tstamp; - req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) @@ -447,7 +455,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) dst_metric(&rt->dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; - ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, &rt->dst); + ireq->ecn_ok &= cookie_ecn_ok(net, &rt->dst); ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst); /* ip_queue_xmit() depends on our flow being setup diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index e0a9220d1536..c8d2ca27220c 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -127,31 +127,18 @@ int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th) } EXPORT_SYMBOL_GPL(__cookie_v6_check); -struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) +static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk, + struct sk_buff *skb) { - const struct tcphdr *th = tcp_hdr(skb); - struct ipv6_pinfo *np = inet6_sk(sk); struct tcp_options_received tcp_opt; - struct tcp_sock *tp = tcp_sk(sk); - struct inet_request_sock *ireq; - struct net *net = sock_net(sk); - struct tcp_request_sock *treq; - struct request_sock *req; - struct dst_entry *dst; - struct sock *ret = sk; - int full_space, mss; - __u8 rcv_wscale; u32 tsoff = 0; - - if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || - !th->ack || th->rst) - goto out; + int mss; if (tcp_synq_no_recent_overflow(sk)) goto out; - mss = __cookie_v6_check(ipv6_hdr(skb), th); - if (mss == 0) { + mss = __cookie_v6_check(ipv6_hdr(skb), tcp_hdr(skb)); + if (!mss) { __NET_INC_STATS(net, LINUX_MIB_SYNCOOKIESFAILED); goto out; } @@ -172,14 +159,37 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (!cookie_timestamp_decode(net, &tcp_opt)) goto out; - req = cookie_tcp_reqsk_alloc(&tcp6_request_sock_ops, sk, skb); + return cookie_tcp_reqsk_alloc(&tcp6_request_sock_ops, sk, skb, + &tcp_opt, mss, tsoff); +out: + return ERR_PTR(-EINVAL); +} + +struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) +{ + const struct tcphdr *th = tcp_hdr(skb); + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp = tcp_sk(sk); + struct inet_request_sock *ireq; + struct net *net = sock_net(sk); + struct request_sock *req; + struct dst_entry *dst; + struct sock *ret = sk; + __u8 rcv_wscale; + int full_space; + + if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || + !th->ack || th->rst) + goto out; + + req = cookie_tcp_check(net, sk, skb); + if (IS_ERR(req)) + goto out; if (!req) goto out_drop; ireq = inet_rsk(req); - treq = tcp_rsk(req); - req->mss = mss; ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; @@ -198,13 +208,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) ireq->ir_iif = tcp_v6_iif(skb); - ireq->snd_wscale = tcp_opt.snd_wscale; - ireq->sack_ok = tcp_opt.sack_ok; - ireq->wscale_ok = tcp_opt.wscale_ok; - ireq->tstamp_ok = tcp_opt.saw_tstamp; - req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; - treq->ts_off = tsoff; - tcp_ao_syncookie(sk, skb, req, AF_INET6); /* @@ -245,7 +248,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) dst_metric(dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; - ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, net, dst); + ireq->ecn_ok &= cookie_ecn_ok(net, dst); ret = tcp_get_cookie_sock(sk, skb, req, dst); out: From 03219a3aa6c89f1cbb6624907f32d6939a1ffeb0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Nov 2023 10:26:29 +0300 Subject: [PATCH 1949/7721] drm/imagination: Fix error codes in pvr_device_clk_init() There is a cut and paste error so this code returns the wrong variable. Fixes: 1f88f017e649 ("drm/imagination: Get GPU resources") Signed-off-by: Dan Carpenter Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/1649c66b-3eea-40d2-9687-592124f968cf@moroto.mountain --- drivers/gpu/drm/imagination/pvr_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 8499becf4fbb..e1dcc4e42087 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -105,12 +105,12 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev) sys_clk = devm_clk_get_optional(drm_dev->dev, "sys"); if (IS_ERR(sys_clk)) - return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + return dev_err_probe(drm_dev->dev, PTR_ERR(sys_clk), "failed to get sys clock\n"); mem_clk = devm_clk_get_optional(drm_dev->dev, "mem"); if (IS_ERR(mem_clk)) - return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + return dev_err_probe(drm_dev->dev, PTR_ERR(mem_clk), "failed to get mem clock\n"); pvr_dev->core_clk = core_clk; From 9ee33dc47772724ff583b060bb37c62b92b2d9c4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Nov 2023 10:27:01 +0300 Subject: [PATCH 1950/7721] drm/imagination: Fix IS_ERR() vs NULL bug in pvr_request_firmware() The pvr_build_firmware_filename() function returns NULL on error. It doesn't return error pointers. Fixes: f99f5f3ea7ef ("drm/imagination: Add GPU ID parsing and firmware loading") Signed-off-by: Dan Carpenter Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/384288de-a779-46c7-869d-b3c63462e12b@moroto.mountain --- drivers/gpu/drm/imagination/pvr_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index e1dcc4e42087..5389aea7ff21 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -286,8 +286,8 @@ pvr_request_firmware(struct pvr_device *pvr_dev) filename = pvr_build_firmware_filename(pvr_dev, "powervr/rogue", PVR_FW_VERSION_MAJOR); - if (IS_ERR(filename)) - return PTR_ERR(filename); + if (!filename) + return -ENOMEM; /* * This function takes a copy of &filename, meaning we can free our From 55b0f4a7c37680428d640aeada96d62888366c56 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Nov 2023 10:27:15 +0300 Subject: [PATCH 1951/7721] drm/imagination: fix off by one in pvr_vm_mips_init() error handling If the call to vmap() fails the "page_nr" is one element beyond the end of the mips_data->pt_dma_addr[] and mips_data->pt_pages[] arrays. The way that this is traditionally written is that we clean up the partial loop iteration before the goto and then we can say while (--i >= 0). At that point we know that all the elements thus far are initialized so we don't need to have NULL checks. Fixes: 927f3e0253c1 ("drm/imagination: Implement MIPS firmware processor and MMU support") Signed-off-by: Dan Carpenter Reviewed-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/a2d3210b-290f-4397-9c3e-efdcca94d8ac@moroto.mountain --- drivers/gpu/drm/imagination/pvr_vm_mips.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm_mips.c b/drivers/gpu/drm/imagination/pvr_vm_mips.c index 7268cf6e630b..2bc7181a4c3e 100644 --- a/drivers/gpu/drm/imagination/pvr_vm_mips.c +++ b/drivers/gpu/drm/imagination/pvr_vm_mips.c @@ -57,6 +57,7 @@ pvr_vm_mips_init(struct pvr_device *pvr_dev) PAGE_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, mips_data->pt_dma_addr[page_nr])) { err = -ENOMEM; + __free_page(mips_data->pt_pages[page_nr]); goto err_free_pages; } } @@ -79,13 +80,11 @@ pvr_vm_mips_init(struct pvr_device *pvr_dev) return 0; err_free_pages: - for (; page_nr >= 0; page_nr--) { - if (mips_data->pt_dma_addr[page_nr]) - dma_unmap_page(from_pvr_device(pvr_dev)->dev, - mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); + while (--page_nr >= 0) { + dma_unmap_page(from_pvr_device(pvr_dev)->dev, + mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); - if (mips_data->pt_pages[page_nr]) - __free_page(mips_data->pt_pages[page_nr]); + __free_page(mips_data->pt_pages[page_nr]); } return err; From 3cc12bb83e6794de7f50799ce43d85c7a3d55828 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 29 Nov 2023 12:27:46 +0530 Subject: [PATCH 1952/7721] firmware: arm_scmi: Fix NULL pointer dereference during fastchannel init The scmi_perf_domain_lookup requires the protocol handle to have the private data set, which is yet to happen during the fastchannel init scenario. This results in a NULL pointer dereference. Fix this by using the pre-populated perf_dom_info to pass on the required information instead. | scmi_perf_protocol_init+0x434/0x678 | scmi_get_protocol_instance+0x168/0x29c | scmi_devres_protocol_instance_get+0x50/0xa0 | scmi_devm_protocol_get+0x20/0x50 | scmi_cpufreq_probe+0x34/0xd4 | scmi_dev_probe+0x28/0x3c | really_probe+0x148/0x2ac | __driver_probe_device+0x78/0x12c | driver_probe_device+0x40/0x160 | __device_attach_driver+0xb8/0x134 | bus_for_each_drv+0x80/0xdc | __device_attach+0xa8/0x1b0 | device_initial_probe+0x14/0x20 | bus_probe_device+0xa8/0xac | device_add+0x5cc/0x778 | device_register+0x20/0x30 | __scmi_device_create.part.0+0xec/0x1cc | scmi_device_create+0x180/0x1c4 | scmi_create_protocol_devices+0x4c/0xb0 | scmi_probe+0x660/0x738 | platform_probe+0x68/0xdc | really_probe+0x148/0x2ac | __driver_probe_device+0x78/0x12c | driver_probe_device+0x40/0x160 | __device_attach_driver+0xb8/0x134 | bus_for_each_drv+0x80/0xdc | __device_attach+0xa8/0x1b0 | device_initial_probe+0x14/0x20 | bus_probe_device+0xa8/0xac | deferred_probe_work_func+0x88/0xc0 | process_one_work+0x13c/0x264 | worker_thread+0x32c/0x438 | kthread+0x118/0x11c | ret_from_fork+0x10/0x20 Fixes: 619bc6e034f3 ("firmware: arm_scmi: Populate fastchannel info only if set operations are allowed") Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20231129065748.19871-2-quic_sibis@quicinc.com Reviewed-by: Cristian Marussi Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/perf.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index d1323c5d9c27..a648521e04a3 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -759,40 +759,35 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph, } static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, - u32 domain, struct scmi_fc_info **p_fc) + struct perf_dom_info *dom) { struct scmi_fc_info *fc; - struct perf_dom_info *dom; - - dom = scmi_perf_domain_lookup(ph, domain); - if (IS_ERR(dom)) - return; fc = devm_kcalloc(ph->dev, PERF_FC_MAX, sizeof(*fc), GFP_KERNEL); if (!fc) return; ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LEVEL_GET, 4, domain, + PERF_LEVEL_GET, 4, dom->id, &fc[PERF_FC_LEVEL].get_addr, NULL); ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LIMITS_GET, 8, domain, + PERF_LIMITS_GET, 8, dom->id, &fc[PERF_FC_LIMIT].get_addr, NULL); if (dom->info.set_perf) ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LEVEL_SET, 4, domain, + PERF_LEVEL_SET, 4, dom->id, &fc[PERF_FC_LEVEL].set_addr, &fc[PERF_FC_LEVEL].set_db); if (dom->set_limits) ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LIMITS_SET, 8, domain, + PERF_LIMITS_SET, 8, dom->id, &fc[PERF_FC_LIMIT].set_addr, &fc[PERF_FC_LIMIT].set_db); - *p_fc = fc; + dom->fc_info = fc; } static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, @@ -1102,7 +1097,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) scmi_perf_describe_levels_get(ph, dom, version); if (dom->perf_fastchannels) - scmi_perf_domain_init_fc(ph, dom->id, &dom->fc_info); + scmi_perf_domain_init_fc(ph, dom); } ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo); From f32f977fa8ab1d2fde0cd7136e0d0393fce31d84 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 23 Nov 2023 17:17:41 +0100 Subject: [PATCH 1953/7721] dt-bindings: power: meson-g12a-power: document ISP power domain Add MIPI ISP power domain ID to the G12A Power domains bindings header Signed-off-by: Neil Armstrong Reviewed-by: Daniel Scally Tested-by: Daniel Scally Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231123-topic-amlogic-upstream-isp-pmdomain-v2-1-61f2fcf709e5@linaro.org Signed-off-by: Ulf Hansson --- include/dt-bindings/power/meson-g12a-power.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/power/meson-g12a-power.h b/include/dt-bindings/power/meson-g12a-power.h index 44ec0c50e340..01fd0ac4dd08 100644 --- a/include/dt-bindings/power/meson-g12a-power.h +++ b/include/dt-bindings/power/meson-g12a-power.h @@ -10,5 +10,6 @@ #define PWRC_G12A_VPU_ID 0 #define PWRC_G12A_ETH_ID 1 #define PWRC_G12A_NNA_ID 2 +#define PWRC_G12A_ISP_ID 3 #endif From 6341e97b52b6238ed06dddc7ec22d025a9346a1e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 23 Nov 2023 17:17:42 +0100 Subject: [PATCH 1954/7721] pmdomain: amlogic: meson-ee-pwrc: add support for G12A ISP power domain Add entries for the ISP power domain found in the Amlogic G12B SoC Signed-off-by: Neil Armstrong Reviewed-by: Daniel Scally Tested-by: Daniel Scally Link: https://lore.kernel.org/r/20231123-topic-amlogic-upstream-isp-pmdomain-v2-2-61f2fcf709e5@linaro.org Signed-off-by: Ulf Hansson --- drivers/pmdomain/amlogic/meson-ee-pwrc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pmdomain/amlogic/meson-ee-pwrc.c b/drivers/pmdomain/amlogic/meson-ee-pwrc.c index 0dd71cd814c5..fcec6eb610e4 100644 --- a/drivers/pmdomain/amlogic/meson-ee-pwrc.c +++ b/drivers/pmdomain/amlogic/meson-ee-pwrc.c @@ -47,6 +47,8 @@ #define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2) #define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2) +#define G12A_HHI_ISP_MEM_PD_REG0 (0x45 << 2) +#define G12A_HHI_ISP_MEM_PD_REG1 (0x46 << 2) struct meson_ee_pwrc; struct meson_ee_pwrc_domain; @@ -115,6 +117,13 @@ static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = { .iso_mask = BIT(16) | BIT(17), }; +static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = { + .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0, + .sleep_mask = BIT(18) | BIT(19), + .iso_reg = GX_AO_RTI_GEN_PWR_ISO0, + .iso_mask = BIT(18) | BIT(19), +}; + /* Memory PD Domains */ #define VPU_MEMPD(__reg) \ @@ -231,6 +240,11 @@ static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = { { G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(31, 0) }, }; +static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = { + { G12A_HHI_ISP_MEM_PD_REG0, GENMASK(31, 0) }, + { G12A_HHI_ISP_MEM_PD_REG1, GENMASK(31, 0) }, +}; + #define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \ { \ .name = __name, \ @@ -269,6 +283,8 @@ static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = { [PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), [PWRC_G12A_NNA_ID] = TOP_PD("NNA", &g12a_pwrc_nna, g12a_pwrc_mem_nna, pwrc_ee_is_powered_off), + [PWRC_G12A_ISP_ID] = TOP_PD("ISP", &g12a_pwrc_isp, g12a_pwrc_mem_isp, + pwrc_ee_is_powered_off), }; static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = { From b3dff2e97c614c1b60083898ffb42010ca16992e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:25 +0100 Subject: [PATCH 1955/7721] pmdomain: imx-pgc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-2-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/gpc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index 7d81e3171d39..d6cf3759570b 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -212,7 +212,7 @@ static int imx_pgc_power_domain_probe(struct platform_device *pdev) return ret; } -static int imx_pgc_power_domain_remove(struct platform_device *pdev) +static void imx_pgc_power_domain_remove(struct platform_device *pdev) { struct imx_pm_domain *domain = pdev->dev.platform_data; @@ -221,8 +221,6 @@ static int imx_pgc_power_domain_remove(struct platform_device *pdev) pm_genpd_remove(&domain->base); imx_pgc_put_clocks(domain); } - - return 0; } static const struct platform_device_id imx_pgc_power_domain_id[] = { @@ -235,7 +233,7 @@ static struct platform_driver imx_pgc_power_domain_driver = { .name = "imx-pgc-pd", }, .probe = imx_pgc_power_domain_probe, - .remove = imx_pgc_power_domain_remove, + .remove_new = imx_pgc_power_domain_remove, .id_table = imx_pgc_power_domain_id, }; builtin_platform_driver(imx_pgc_power_domain_driver) From da07c5871d18157608a0d0702cb093168d79080a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:26 +0100 Subject: [PATCH 1956/7721] pmdomain: imx-gpc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-3-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/gpc.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index d6cf3759570b..9517cce93d8a 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -509,7 +509,7 @@ static int imx_gpc_probe(struct platform_device *pdev) return 0; } -static int imx_gpc_remove(struct platform_device *pdev) +static void imx_gpc_remove(struct platform_device *pdev) { struct device_node *pgc_node; int ret; @@ -519,7 +519,7 @@ static int imx_gpc_remove(struct platform_device *pdev) /* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) - return 0; + return; /* * If the old DT binding is used the toplevel driver needs to @@ -529,16 +529,20 @@ static int imx_gpc_remove(struct platform_device *pdev) of_genpd_del_provider(pdev->dev.of_node); ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); - if (ret) - return ret; + if (ret) { + dev_err(&pdev->dev, "Failed to remove PU power domain (%pe)\n", + ERR_PTR(ret)); + return; + } imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]); ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base); - if (ret) - return ret; + if (ret) { + dev_err(&pdev->dev, "Failed to remove ARM power domain (%pe)\n", + ERR_PTR(ret)); + return; + } } - - return 0; } static struct platform_driver imx_gpc_driver = { @@ -547,6 +551,6 @@ static struct platform_driver imx_gpc_driver = { .of_match_table = imx_gpc_dt_ids, }, .probe = imx_gpc_probe, - .remove = imx_gpc_remove, + .remove_new = imx_gpc_remove, }; builtin_platform_driver(imx_gpc_driver) From 697bc6c8ab0af49b6ff0244f8ae8380a42898521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:27 +0100 Subject: [PATCH 1957/7721] pmdomain: imx-gpcv2: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-4-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/gpcv2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c index fbd3d92f8cd8..4b828d74a606 100644 --- a/drivers/pmdomain/imx/gpcv2.c +++ b/drivers/pmdomain/imx/gpcv2.c @@ -1373,7 +1373,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) return ret; } -static int imx_pgc_domain_remove(struct platform_device *pdev) +static void imx_pgc_domain_remove(struct platform_device *pdev) { struct imx_pgc_domain *domain = pdev->dev.platform_data; @@ -1385,8 +1385,6 @@ static int imx_pgc_domain_remove(struct platform_device *pdev) domain->bits.map, 0); pm_runtime_disable(domain->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1430,7 +1428,7 @@ static struct platform_driver imx_pgc_domain_driver = { .pm = &imx_pgc_domain_pm_ops, }, .probe = imx_pgc_domain_probe, - .remove = imx_pgc_domain_remove, + .remove_new = imx_pgc_domain_remove, .id_table = imx_pgc_domain_id, }; builtin_platform_driver(imx_pgc_domain_driver) From eeba351945b72da4bc58d842ff9d4a90a39aaf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:28 +0100 Subject: [PATCH 1958/7721] pmdomain: imx8m-blk-ctrl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-5-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx8m-blk-ctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index cc5ef6e2f0a8..1341a707f61b 100644 --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c @@ -330,7 +330,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) return ret; } -static int imx8m_blk_ctrl_remove(struct platform_device *pdev) +static void imx8m_blk_ctrl_remove(struct platform_device *pdev) { struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); int i; @@ -347,8 +347,6 @@ static int imx8m_blk_ctrl_remove(struct platform_device *pdev) dev_pm_genpd_remove_notifier(bc->bus_power_dev); dev_pm_domain_detach(bc->bus_power_dev, true); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -888,7 +886,7 @@ MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match); static struct platform_driver imx8m_blk_ctrl_driver = { .probe = imx8m_blk_ctrl_probe, - .remove = imx8m_blk_ctrl_remove, + .remove_new = imx8m_blk_ctrl_remove, .driver = { .name = "imx8m-blk-ctrl", .pm = &imx8m_blk_ctrl_pm_ops, From 7476ddfd36ac65d2944b40373467c1c8eb0bc467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:29 +0100 Subject: [PATCH 1959/7721] pmdomain: imx8mp-blk-ctrl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-6-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx8mp-blk-ctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c index c6ac32c1a8c1..e3203eb6a022 100644 --- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c @@ -760,7 +760,7 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) return ret; } -static int imx8mp_blk_ctrl_remove(struct platform_device *pdev) +static void imx8mp_blk_ctrl_remove(struct platform_device *pdev) { struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); int i; @@ -777,8 +777,6 @@ static int imx8mp_blk_ctrl_remove(struct platform_device *pdev) dev_pm_genpd_remove_notifier(bc->bus_power_dev); dev_pm_domain_detach(bc->bus_power_dev, true); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -856,7 +854,7 @@ MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match); static struct platform_driver imx8mp_blk_ctrl_driver = { .probe = imx8mp_blk_ctrl_probe, - .remove = imx8mp_blk_ctrl_remove, + .remove_new = imx8mp_blk_ctrl_remove, .driver = { .name = "imx8mp-blk-ctrl", .pm = &imx8mp_blk_ctrl_pm_ops, From 77647eb5546c01cee08c4716a3a5717f6016b086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:30 +0100 Subject: [PATCH 1960/7721] pmdomain: imx93-blk-ctrl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-7-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index 40bd90f8b977..904ffa55b8f4 100644 --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c @@ -306,7 +306,7 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) return ret; } -static int imx93_blk_ctrl_remove(struct platform_device *pdev) +static void imx93_blk_ctrl_remove(struct platform_device *pdev) { struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); int i; @@ -318,8 +318,6 @@ static int imx93_blk_ctrl_remove(struct platform_device *pdev) pm_genpd_remove(&domain->genpd); } - - return 0; } static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = { @@ -438,7 +436,7 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); static struct platform_driver imx93_blk_ctrl_driver = { .probe = imx93_blk_ctrl_probe, - .remove = imx93_blk_ctrl_remove, + .remove_new = imx93_blk_ctrl_remove, .driver = { .name = "imx93-blk-ctrl", .of_match_table = imx93_blk_ctrl_of_match, From 673c09bc6e134e6277b58e24caf29ed0746ea08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:31 +0100 Subject: [PATCH 1961/7721] pmdomain: imx93-pd: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-8-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx93-pd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/imx/imx93-pd.c b/drivers/pmdomain/imx/imx93-pd.c index b9e60d136875..1e94b499c19b 100644 --- a/drivers/pmdomain/imx/imx93-pd.c +++ b/drivers/pmdomain/imx/imx93-pd.c @@ -83,7 +83,7 @@ static int imx93_pd_off(struct generic_pm_domain *genpd) return 0; }; -static int imx93_pd_remove(struct platform_device *pdev) +static void imx93_pd_remove(struct platform_device *pdev) { struct imx93_power_domain *domain = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -94,8 +94,6 @@ static int imx93_pd_remove(struct platform_device *pdev) of_genpd_del_provider(np); pm_genpd_remove(&domain->genpd); - - return 0; } static int imx93_pd_probe(struct platform_device *pdev) @@ -167,7 +165,7 @@ static struct platform_driver imx93_power_domain_driver = { .of_match_table = imx93_pd_ids, }, .probe = imx93_pd_probe, - .remove = imx93_pd_remove, + .remove_new = imx93_pd_remove, }; module_platform_driver(imx93_power_domain_driver); From 4b7599a5e847d4263e25f7e5d7d381792fcb5726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:32 +0100 Subject: [PATCH 1962/7721] pmdomain: qcom-cpr: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231124080623.564924-9-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/cpr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/qcom/cpr.c b/drivers/pmdomain/qcom/cpr.c index e9dd42bded6f..c64e84a27cc7 100644 --- a/drivers/pmdomain/qcom/cpr.c +++ b/drivers/pmdomain/qcom/cpr.c @@ -1712,7 +1712,7 @@ static int cpr_probe(struct platform_device *pdev) return ret; } -static int cpr_remove(struct platform_device *pdev) +static void cpr_remove(struct platform_device *pdev) { struct cpr_drv *drv = platform_get_drvdata(pdev); @@ -1725,8 +1725,6 @@ static int cpr_remove(struct platform_device *pdev) pm_genpd_remove(&drv->pd); debugfs_remove_recursive(drv->debugfs); - - return 0; } static const struct of_device_id cpr_match_table[] = { @@ -1737,7 +1735,7 @@ MODULE_DEVICE_TABLE(of, cpr_match_table); static struct platform_driver cpr_driver = { .probe = cpr_probe, - .remove = cpr_remove, + .remove_new = cpr_remove, .driver = { .name = "qcom-cpr", .of_match_table = cpr_match_table, From 833811353f701421c389f5c4d4bdf06e052fd649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 24 Nov 2023 09:06:33 +0100 Subject: [PATCH 1963/7721] pmdomain: xilinx/zynqmp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Michal Simek Link: https://lore.kernel.org/r/20231124080623.564924-10-u.kleine-koenig@pengutronix.de Signed-off-by: Ulf Hansson --- drivers/pmdomain/xilinx/zynqmp-pm-domains.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c index 69d03ad4cf1e..6fd514286d82 100644 --- a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c +++ b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c @@ -293,11 +293,9 @@ static int zynqmp_gpd_probe(struct platform_device *pdev) return 0; } -static int zynqmp_gpd_remove(struct platform_device *pdev) +static void zynqmp_gpd_remove(struct platform_device *pdev) { of_genpd_del_provider(pdev->dev.parent->of_node); - - return 0; } static void zynqmp_gpd_sync_state(struct device *dev) @@ -315,7 +313,7 @@ static struct platform_driver zynqmp_power_domain_driver = { .sync_state = zynqmp_gpd_sync_state, }, .probe = zynqmp_gpd_probe, - .remove = zynqmp_gpd_remove, + .remove_new = zynqmp_gpd_remove, }; module_platform_driver(zynqmp_power_domain_driver); From f690ff9122d2ca8e38769f3bcf217bd3df681a36 Mon Sep 17 00:00:00 2001 From: Yujie Liu Date: Thu, 30 Nov 2023 11:40:18 +0800 Subject: [PATCH 1964/7721] bpf/tests: Remove duplicate JSGT tests It seems unnecessary that JSGT is tested twice (one before JSGE and one after JSGE) since others are tested only once. Remove the duplicate JSGT tests. Fixes: 0bbaa02b4816 ("bpf/tests: Add tests to check source register zero-extension") Signed-off-by: Yujie Liu Signed-off-by: Daniel Borkmann Acked-by: Johan Almbladh Link: https://lore.kernel.org/bpf/20231130034018.2144963-1-yujie.liu@intel.com --- lib/test_bpf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index c148f8d1e564..e380fdf756db 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -12199,7 +12199,6 @@ static struct bpf_test tests[] = { BPF_JMP32_IMM_ZEXT(JLE), BPF_JMP32_IMM_ZEXT(JSGT), BPF_JMP32_IMM_ZEXT(JSGE), - BPF_JMP32_IMM_ZEXT(JSGT), BPF_JMP32_IMM_ZEXT(JSLT), BPF_JMP32_IMM_ZEXT(JSLE), #undef BPF_JMP2_IMM_ZEXT @@ -12235,7 +12234,6 @@ static struct bpf_test tests[] = { BPF_JMP32_REG_ZEXT(JLE), BPF_JMP32_REG_ZEXT(JSGT), BPF_JMP32_REG_ZEXT(JSGE), - BPF_JMP32_REG_ZEXT(JSGT), BPF_JMP32_REG_ZEXT(JSLT), BPF_JMP32_REG_ZEXT(JSLE), #undef BPF_JMP2_REG_ZEXT From 15d74e6588a158e481f38858de34011034957152 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 28 Nov 2023 12:52:54 +0100 Subject: [PATCH 1965/7721] Documentation: devlink: extend reload-reinit description Be more explicit about devlink entities that may stay and that have to be removed during reload reinit action. Signed-off-by: Jiri Pirko Reviewed-by: Przemek Kitszel Signed-off-by: Paolo Abeni --- Documentation/networking/devlink/devlink-reload.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/devlink/devlink-reload.rst b/Documentation/networking/devlink/devlink-reload.rst index 505d22da027d..2fb0269b2054 100644 --- a/Documentation/networking/devlink/devlink-reload.rst +++ b/Documentation/networking/devlink/devlink-reload.rst @@ -22,8 +22,17 @@ By default ``driver_reinit`` action is selected. * - ``driver-reinit`` - Devlink driver entities re-initialization, including applying new values to devlink entities which are used during driver - load such as ``devlink-params`` in configuration mode - ``driverinit`` or ``devlink-resources`` + load which are: + + * ``devlink-params`` in configuration mode ``driverinit`` + * ``devlink-resources`` + + Other devlink entities may stay over the re-initialization: + + * ``devlink-health-reporter`` + * ``devlink-region`` + + The rest of the devlink entities have to be removed and readded. * - ``fw_activate`` - Firmware activate. Activates new firmware if such image is stored and pending activation. If no limitation specified this action may involve From 9b2348e2d6c94146f50b68d7d2067146e7339ac5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 28 Nov 2023 12:52:55 +0100 Subject: [PATCH 1966/7721] devlink: warn about existing entities during reload-reinit During reload-reinit, all entities except for params, resources, regions and health reporter should be removed and re-added. Add a warning to be triggered in case the driver behaves differently. Signed-off-by: Jiri Pirko Reviewed-by: Przemek Kitszel Signed-off-by: Paolo Abeni --- net/devlink/dev.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/devlink/dev.c b/net/devlink/dev.c index ea6a92f2e6a2..918a0395b03e 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -425,6 +425,18 @@ static void devlink_reload_netns_change(struct devlink *devlink, devlink_rel_nested_in_notify(devlink); } +static void devlink_reload_reinit_sanity_check(struct devlink *devlink) +{ + WARN_ON(!list_empty(&devlink->trap_policer_list)); + WARN_ON(!list_empty(&devlink->trap_group_list)); + WARN_ON(!list_empty(&devlink->trap_list)); + WARN_ON(!list_empty(&devlink->dpipe_table_list)); + WARN_ON(!list_empty(&devlink->sb_list)); + WARN_ON(!list_empty(&devlink->rate_list)); + WARN_ON(!list_empty(&devlink->linecard_list)); + WARN_ON(!xa_empty(&devlink->ports)); +} + int devlink_reload(struct devlink *devlink, struct net *dest_net, enum devlink_reload_action action, enum devlink_reload_limit limit, @@ -452,8 +464,10 @@ int devlink_reload(struct devlink *devlink, struct net *dest_net, if (dest_net && !net_eq(dest_net, curr_net)) devlink_reload_netns_change(devlink, curr_net, dest_net); - if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT) + if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT) { devlink_params_driverinit_load_new(devlink); + devlink_reload_reinit_sanity_check(devlink); + } err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack); devlink_reload_failed_set(devlink, !!err); From 7234dc5ccba6e57b6b6ad19f7078e57afc40c9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 28 Nov 2023 18:38:25 +0100 Subject: [PATCH 1967/7721] net: ethernet: ti: am65-cpsw: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Replace the error path returning a non-zero value by an error message and a comment that there is more to do. With that this patch results in no change of behaviour in this driver apart from improving the error message. Signed-off-by: Uwe Kleine-König Reviewed-by: Roger Quadros Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 7992a76ed4d8..7651f90f51f2 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -3028,7 +3028,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) return ret; } -static int am65_cpsw_nuss_remove(struct platform_device *pdev) +static void am65_cpsw_nuss_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct am65_cpsw_common *common; @@ -3037,8 +3037,14 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev) common = dev_get_drvdata(dev); ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } am65_cpsw_unregister_devlink(common); am65_cpsw_unregister_notifiers(common); @@ -3056,7 +3062,6 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int am65_cpsw_nuss_suspend(struct device *dev) @@ -3156,7 +3161,7 @@ static struct platform_driver am65_cpsw_nuss_driver = { .pm = &am65_cpsw_nuss_dev_pm_ops, }, .probe = am65_cpsw_nuss_probe, - .remove = am65_cpsw_nuss_remove, + .remove_new = am65_cpsw_nuss_remove, }; module_platform_driver(am65_cpsw_nuss_driver); From 7ac3f867a35833a228b1bd9645a1581c808a5900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 28 Nov 2023 18:38:26 +0100 Subject: [PATCH 1968/7721] net: ethernet: ti: cpsw: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Replace the error path returning a non-zero value by an error message and a comment that there is more to do. With that this patch results in no change of behaviour in this driver apart from improving the error message. Signed-off-by: Uwe Kleine-König Reviewed-by: Roger Quadros Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ti/cpsw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index ca4d4548f85e..ea85c6dd5484 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1722,14 +1722,20 @@ static int cpsw_probe(struct platform_device *pdev) return ret; } -static int cpsw_remove(struct platform_device *pdev) +static void cpsw_remove(struct platform_device *pdev) { struct cpsw_common *cpsw = platform_get_drvdata(pdev); int i, ret; ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } for (i = 0; i < cpsw->data.slaves; i++) if (cpsw->slaves[i].ndev) @@ -1740,7 +1746,6 @@ static int cpsw_remove(struct platform_device *pdev) cpsw_remove_dt(pdev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1795,7 +1800,7 @@ static struct platform_driver cpsw_driver = { .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove = cpsw_remove, + .remove_new = cpsw_remove, }; module_platform_driver(cpsw_driver); From a76772e2fd83e97a8d1bd363e986fc842ad31446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 28 Nov 2023 18:38:27 +0100 Subject: [PATCH 1969/7721] net: ethernet: ti: cpsw-new: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Replace the error path returning a non-zero value by an error message and a comment that there is more to do. With that this patch results in no change of behaviour in this driver apart from improving the error message. Signed-off-by: Uwe Kleine-König Reviewed-by: Roger Quadros Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ti/cpsw_new.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 0e4f526b1753..498c50c6d1a7 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -2037,14 +2037,20 @@ static int cpsw_probe(struct platform_device *pdev) return ret; } -static int cpsw_remove(struct platform_device *pdev) +static void cpsw_remove(struct platform_device *pdev) { struct cpsw_common *cpsw = platform_get_drvdata(pdev); int ret; ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } cpsw_unregister_notifiers(cpsw); cpsw_unregister_devlink(cpsw); @@ -2055,7 +2061,6 @@ static int cpsw_remove(struct platform_device *pdev) cpsw_remove_dt(cpsw); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int __maybe_unused cpsw_suspend(struct device *dev) @@ -2116,7 +2121,7 @@ static struct platform_driver cpsw_driver = { .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove = cpsw_remove, + .remove_new = cpsw_remove, }; module_platform_driver(cpsw_driver); From 7ec1bb2ce64ba9528b1f67bf489dd5f6147d1f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 28 Nov 2023 18:38:28 +0100 Subject: [PATCH 1970/7721] net: ethernet: ezchip: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ezchip/nps_enet.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 4d7184d46824..07c2b701b5fa 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -633,7 +633,7 @@ static s32 nps_enet_probe(struct platform_device *pdev) return err; } -static s32 nps_enet_remove(struct platform_device *pdev) +static void nps_enet_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct nps_enet_priv *priv = netdev_priv(ndev); @@ -641,8 +641,6 @@ static s32 nps_enet_remove(struct platform_device *pdev) unregister_netdev(ndev); netif_napi_del(&priv->napi); free_netdev(ndev); - - return 0; } static const struct of_device_id nps_enet_dt_ids[] = { @@ -653,7 +651,7 @@ MODULE_DEVICE_TABLE(of, nps_enet_dt_ids); static struct platform_driver nps_enet_driver = { .probe = nps_enet_probe, - .remove = nps_enet_remove, + .remove_new = nps_enet_remove, .driver = { .name = DRV_NAME, .of_match_table = nps_enet_dt_ids, From d6296525f128efdd8c82bd3cbd3a83d306031d15 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 10 Oct 2023 16:19:25 -0500 Subject: [PATCH 1971/7721] arm: dts: omap: Apply am57xx-idk overlays to base dtbs DT overlays in tree need to be applied to a base DTB to validate they apply, to run schema checks on them, and to catch any errors at compile time. Signed-off-by: Rob Herring Message-ID: <20231010211925.1629653-1-robh@kernel.org> Acked-by: Andrew Davis Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/ti/omap/Makefile b/arch/arm/boot/dts/ti/omap/Makefile index a002f6035fde..95c68135dd0c 100644 --- a/arch/arm/boot/dts/ti/omap/Makefile +++ b/arch/arm/boot/dts/ti/omap/Makefile @@ -131,6 +131,16 @@ dtb-$(CONFIG_SOC_AM43XX) += \ am57xx-evm-dtbs := am57xx-beagle-x15.dtb am57xx-evm.dtbo am57xx-evm-reva3-dtbs := am57xx-beagle-x15-revc.dtb am57xx-evm.dtbo +am571x-idk-overlays-dtbs := am571x-idk.dtb \ + am571x-idk-touchscreen.dtbo am57xx-idk-lcd-osd101t2587.dtbo +am572x-idk-overlays-dtbs := am572x-idk.dtb \ + am572x-idk-touchscreen.dtbo am57xx-idk-lcd-osd101t2045.dtbo + +# Build time test only, enabled by CONFIG_OF_ALL_DTBS +dtb- += \ + am571x-idk-overlays.dtb \ + am572x-idk-overlays.dtb + dtb-$(CONFIG_SOC_DRA7XX) += \ am57xx-beagle-x15.dtb \ am57xx-beagle-x15-revb1.dtb \ From 3a40640ded577bd1e05c78508270f6e825463799 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 24 Jul 2023 12:39:09 +0200 Subject: [PATCH 1972/7721] ARM: dts: ti/omap: Replace deprecated extcon-usb-gpio id-gpio/vbus-gpio properties Use id-gpios and vbus-gpios instead. Signed-off-by: Alexander Stein Message-ID: <20230724103914.1779027-3-alexander.stein@ew.tq-group.com> Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/am571x-idk.dts | 4 ++-- arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts | 2 +- arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi | 4 ++-- arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi | 4 ++-- arch/arm/boot/dts/ti/omap/dra71-evm.dts | 4 ++-- arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi | 4 ++-- arch/arm/boot/dts/ti/omap/dra76-evm.dts | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/ti/omap/am571x-idk.dts b/arch/arm/boot/dts/ti/omap/am571x-idk.dts index 48425020281a..322cf79d22e9 100644 --- a/arch/arm/boot/dts/ti/omap/am571x-idk.dts +++ b/arch/arm/boot/dts/ti/omap/am571x-idk.dts @@ -168,8 +168,8 @@ blue3-led { }; &extcon_usb2 { - id-gpio = <&gpio5 7 GPIO_ACTIVE_HIGH>; - vbus-gpio = <&gpio7 22 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio5 7 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&gpio7 22 GPIO_ACTIVE_HIGH>; }; &sn65hvs882 { diff --git a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts index 9a234dc1431d..c8e55642f9c6 100644 --- a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts +++ b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts @@ -197,7 +197,7 @@ brcmf_pwrseq: brcmf_pwrseq { extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; ti,enable-id-detection; - id-gpio = <&gpio3 13 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi b/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi index 1d66278c3a72..3fca84819dc0 100644 --- a/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi @@ -169,8 +169,8 @@ blue3-led { }; &extcon_usb2 { - id-gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>; - vbus-gpio = <&gpio3 26 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; }; &sn65hvs882 { diff --git a/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi b/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi index 4cdffd6db740..ed5199d7acd8 100644 --- a/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi @@ -15,12 +15,12 @@ chosen { extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; }; extcon_usb2: extcon_usb2 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; }; sound0: sound0 { diff --git a/arch/arm/boot/dts/ti/omap/dra71-evm.dts b/arch/arm/boot/dts/ti/omap/dra71-evm.dts index a64364443031..f747ac56eb92 100644 --- a/arch/arm/boot/dts/ti/omap/dra71-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dra71-evm.dts @@ -293,11 +293,11 @@ &hdmi { }; &extcon_usb1 { - vbus-gpio = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; }; &extcon_usb2 { - vbus-gpio = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; }; &ipu2 { diff --git a/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi b/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi index 31ab0c60ca75..f8151c61488e 100644 --- a/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi @@ -96,12 +96,12 @@ evm_3v3_sd: fixedregulator-sd { extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; }; extcon_usb2: extcon_usb2 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; }; hdmi0: connector { diff --git a/arch/arm/boot/dts/ti/omap/dra76-evm.dts b/arch/arm/boot/dts/ti/omap/dra76-evm.dts index 57868ac60d29..cf9c3d35b049 100644 --- a/arch/arm/boot/dts/ti/omap/dra76-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dra76-evm.dts @@ -533,11 +533,11 @@ &pcie1_ep { }; &extcon_usb1 { - vbus-gpio = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; }; &extcon_usb2 { - vbus-gpio = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; }; &m_can0 { From b1a041afb41083d9741db11061c49c6572c383ca Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 16 Sep 2023 12:05:15 +0200 Subject: [PATCH 1973/7721] ARM: dts: omap4-embt2ws: enable 32K clock on WLAN WLAN did only work if clock was left enabled by the original system, so make it fully enable the needed resources itself. Signed-off-by: Andreas Kemnade Message-ID: <20230916100515.1650336-6-andreas@kemnade.info> Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts index 01d783826d5f..0411adbe0dcb 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts @@ -51,6 +51,12 @@ unknown_supply: unknown-supply { regulator-name = "unknown"; }; + wl12xx_pwrseq: wl12xx-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&twl 1>; + clock-names = "ext_clock"; + }; + /* regulator for wl12xx on sdio2 */ wl12xx_vmmc: wl12xx-vmmc { pinctrl-names = "default"; @@ -74,6 +80,7 @@ &i2c1 { twl: pmic@48 { compatible = "ti,twl6032"; reg = <0x48>; + #clock-cells = <1>; /* IRQ# = 7 */ interrupts = ; /* IRQ_SYS_1N cascaded to gic */ interrupt-controller; @@ -294,6 +301,7 @@ &mmc3 { pinctrl-names = "default"; pinctrl-0 = <&wl12xx_pins>; vmmc-supply = <&wl12xx_vmmc>; + mmc-pwrseq = <&wl12xx_pwrseq>; interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH &omap4_pmx_core 0x12e>; non-removable; From 288fde659ec6992552c4467534e15247b7445530 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 27 Nov 2023 21:04:30 +0100 Subject: [PATCH 1974/7721] ARM: dts: omap: logicpd-torpedo: do not disguise GNSS device https://support.logicpd.com/DesktopModules/Bring2mind/DMX/Download.aspx?portalid=0&EntryId=649 clearly specifies the availability of GPS, so let's not disguise it and name the node accordingly. Signed-off-by: Andreas Kemnade Message-ID: <20231127200430.143231-1-andreas@kemnade.info> Acked-by: Adam Ford Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts index 533ce7ce387a..fbff15a0a0fe 100644 --- a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts +++ b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts @@ -52,7 +52,7 @@ wlcore: wlcore@2 { &uart2 { /delete-property/dma-names; - bluetooth { + bluetooth-gnss { compatible = "ti,wl1283-st"; enable-gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>; /* gpio 162 */ max-speed = <3000000>; From 21a34e63afcc4328bd3f62289dafd796ae95550b Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:48 +0800 Subject: [PATCH 1975/7721] dt-bindings: interrupt-controller: Add SOPHGO CV1812H plic Add compatible string for SOPHGO CV1812H plic. Signed-off-by: Inochi Amaoto Acked-by: Krzysztof Kozlowski Reviewed-by: Jisheng Zhang Signed-off-by: Conor Dooley --- .../bindings/interrupt-controller/sifive,plic-1.0.0.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index 0c07e8dda445..709b2211276b 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -66,6 +66,7 @@ properties: - enum: - allwinner,sun20i-d1-plic - sophgo,cv1800b-plic + - sophgo,cv1812h-plic - sophgo,sg2042-plic - thead,th1520-plic - const: thead,c900-plic From 06ea2a1968a92a2a8a03c91b4989bda2b0a8a578 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:49 +0800 Subject: [PATCH 1976/7721] dt-bindings: timer: Add SOPHGO CV1812H clint Add compatible string for the SOPHGO CV1812H clint. Signed-off-by: Inochi Amaoto Acked-by: Krzysztof Kozlowski Reviewed-by: Jisheng Zhang Signed-off-by: Conor Dooley --- Documentation/devicetree/bindings/timer/sifive,clint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/timer/sifive,clint.yaml b/Documentation/devicetree/bindings/timer/sifive,clint.yaml index e8be6c470364..4b6c20fc8194 100644 --- a/Documentation/devicetree/bindings/timer/sifive,clint.yaml +++ b/Documentation/devicetree/bindings/timer/sifive,clint.yaml @@ -38,6 +38,7 @@ properties: - enum: - allwinner,sun20i-d1-clint - sophgo,cv1800b-clint + - sophgo,cv1812h-clint - thead,th1520-clint - const: thead,c900-clint - items: From d7b92027834e92a47f254d846483968d29ce2360 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:50 +0800 Subject: [PATCH 1977/7721] dt-bindings: riscv: Add SOPHGO Huashan Pi board compatibles Document the compatible strings for the SOPHGO Huashan Pi board which uses the SOPHGO CV1812H SoC. Signed-off-by: Inochi Amaoto Link: https://en.sophgo.com/product/introduce/huashan.html Link: https://en.sophgo.com/product/introduce/cv181xH.html Acked-by: Chen Wang Acked-by: Krzysztof Kozlowski Reviewed-by: Jisheng Zhang Signed-off-by: Conor Dooley --- Documentation/devicetree/bindings/riscv/sophgo.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/riscv/sophgo.yaml b/Documentation/devicetree/bindings/riscv/sophgo.yaml index 86748c5390be..9bc813dad098 100644 --- a/Documentation/devicetree/bindings/riscv/sophgo.yaml +++ b/Documentation/devicetree/bindings/riscv/sophgo.yaml @@ -22,6 +22,10 @@ properties: - enum: - milkv,duo - const: sophgo,cv1800b + - items: + - enum: + - sophgo,huashan-pi + - const: sophgo,cv1812h - items: - enum: - milkv,pioneer From 5b5dce3951b23e265e053970828ce7a8471d268d Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:51 +0800 Subject: [PATCH 1978/7721] riscv: dts: sophgo: Separate compatible specific for CV1800B soc As CV180x and CV181x have the identical layouts, it is OK to use the cv1800b basic device tree for the whole series. For CV1800B soc specific compatible, just move them out of the common file. Signed-off-by: Inochi Amaoto Acked-by: Chen Wang Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/sophgo/cv1800b.dtsi | 123 ++---------------------- arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 120 +++++++++++++++++++++++ 2 files changed, 129 insertions(+), 114 deletions(-) create mode 100644 arch/riscv/boot/dts/sophgo/cv18xx.dtsi diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi index df40e87ee063..165e9e320a8c 100644 --- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi @@ -3,121 +3,16 @@ * Copyright (C) 2023 Jisheng Zhang */ -#include +#include "cv18xx.dtsi" / { compatible = "sophgo,cv1800b"; - #address-cells = <1>; - #size-cells = <1>; - - cpus: cpus { - #address-cells = <1>; - #size-cells = <0>; - timebase-frequency = <25000000>; - - cpu0: cpu@0 { - compatible = "thead,c906", "riscv"; - device_type = "cpu"; - reg = <0>; - d-cache-block-size = <64>; - d-cache-sets = <512>; - d-cache-size = <65536>; - i-cache-block-size = <64>; - i-cache-sets = <128>; - i-cache-size = <32768>; - mmu-type = "riscv,sv39"; - riscv,isa = "rv64imafdc"; - riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; - - cpu0_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <1>; - }; - }; - }; - - osc: oscillator { - compatible = "fixed-clock"; - clock-output-names = "osc_25m"; - #clock-cells = <0>; - }; - - soc { - compatible = "simple-bus"; - interrupt-parent = <&plic>; - #address-cells = <1>; - #size-cells = <1>; - dma-noncoherent; - ranges; - - uart0: serial@4140000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04140000 0x100>; - interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart1: serial@4150000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04150000 0x100>; - interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart2: serial@4160000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04160000 0x100>; - interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart3: serial@4170000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04170000 0x100>; - interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart4: serial@41c0000 { - compatible = "snps,dw-apb-uart"; - reg = <0x041c0000 0x100>; - interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - plic: interrupt-controller@70000000 { - compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; - reg = <0x70000000 0x4000000>; - interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - riscv,ndev = <101>; - }; - - clint: timer@74000000 { - compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; - reg = <0x74000000 0x10000>; - interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; - }; - }; +}; + +&plic { + compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; +}; + +&clint { + compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; }; diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi new file mode 100644 index 000000000000..55d4bc84faa0 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Jisheng Zhang + */ + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <25000000>; + + cpu0: cpu@0 { + compatible = "thead,c906", "riscv"; + device_type = "cpu"; + reg = <0>; + d-cache-block-size = <64>; + d-cache-sets = <512>; + d-cache-size = <65536>; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <32768>; + mmu-type = "riscv,sv39"; + riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + osc: oscillator { + compatible = "fixed-clock"; + clock-output-names = "osc_25m"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; + #address-cells = <1>; + #size-cells = <1>; + dma-noncoherent; + ranges; + + uart0: serial@4140000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04140000 0x100>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart1: serial@4150000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04150000 0x100>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart2: serial@4160000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04160000 0x100>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart3: serial@4170000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04170000 0x100>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart4: serial@41c0000 { + compatible = "snps,dw-apb-uart"; + reg = <0x041c0000 0x100>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + plic: interrupt-controller@70000000 { + reg = <0x70000000 0x4000000>; + interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <101>; + }; + + clint: timer@74000000 { + reg = <0x74000000 0x10000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; + }; + }; +}; From dd791b45c866b735601605b8dbceed4ab147db38 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:52 +0800 Subject: [PATCH 1979/7721] riscv: dts: sophgo: cv18xx: Add gpio devices Add common GPIO devices for the CV180x and CV181x soc. Signed-off-by: Inochi Amaoto Reviewed-by: Jisheng Zhang Acked-by: Chen Wang Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 73 ++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi index 55d4bc84faa0..d415cc758def 100644 --- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0 OR MIT) /* * Copyright (C) 2023 Jisheng Zhang + * Copyright (C) 2023 Inochi Amaoto */ #include @@ -53,6 +54,78 @@ soc { dma-noncoherent; ranges; + gpio0: gpio@3020000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3020000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <60 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio1: gpio@3021000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3021000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <61 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio2: gpio@3022000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3022000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio3: gpio@3023000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3023000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <63 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + uart0: serial@4140000 { compatible = "snps,dw-apb-uart"; reg = <0x04140000 0x100>; From 681ec684a741ed3ac2c6b283b56245effa7a2c9d Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:53 +0800 Subject: [PATCH 1980/7721] riscv: dts: sophgo: add initial CV1812H SoC device tree Add initial device tree for the CV1812H RISC-V SoC by SOPHGO. Signed-off-by: Inochi Amaoto Acked-by: Chen Wang Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/sophgo/cv1812h.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 arch/riscv/boot/dts/sophgo/cv1812h.dtsi diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi new file mode 100644 index 000000000000..3e7a942f5c1a --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Inochi Amaoto + */ + +#include +#include "cv18xx.dtsi" + +/ { + compatible = "sophgo,cv1812h"; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; +}; + +&plic { + compatible = "sophgo,cv1812h-plic", "thead,c900-plic"; +}; + +&clint { + compatible = "sophgo,cv1812h-clint", "thead,c900-clint"; +}; From 2c36b0cfb408e47402792439e3ebfb862ea5b6dc Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 19 Oct 2023 07:18:54 +0800 Subject: [PATCH 1981/7721] riscv: dts: sophgo: add Huashan Pi board device tree Add initial device tree files for the Huashan Pi board. Note: The boot of CV1812H chip needs a rtos firmware for coprocessor to function properly. To make the soc happy, reserved the last 2M memory for the rtos firmware. Signed-off-by: Inochi Amaoto Link: https://en.sophgo.com/product/introduce/huashan.html Link: https://en.sophgo.com/product/introduce/cv181xH.html Link: https://github.com/milkv-duo/duo-buildroot-sdk/blob/develop/build/boards/cv181x/cv1812h_wevb_0007a_emmc_huashan/memmap.py#L15 Reviewed-by: Jisheng Zhang Acked-by: Chen Wang Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/sophgo/Makefile | 1 + .../boot/dts/sophgo/cv1812h-huashan-pi.dts | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile index 3fb65512c631..57ad82a61ea6 100644 --- a/arch/riscv/boot/dts/sophgo/Makefile +++ b/arch/riscv/boot/dts/sophgo/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb diff --git a/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts new file mode 100644 index 000000000000..aa361f3a86bb --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Inochi Amaoto + */ + +/dts-v1/; + +#include "cv1812h.dtsi" + +/ { + model = "Huashan Pi"; + compatible = "sophgo,huashan-pi", "sophgo,cv1812h"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + coprocessor_rtos: region@8fe00000 { + reg = <0x8fe00000 0x200000>; + no-map; + }; + }; +}; + +&osc { + clock-frequency = <25000000>; +}; + +&uart0 { + status = "okay"; +}; From 3d1ff9dfdc168722f570144aba0ce29d28d7f483 Mon Sep 17 00:00:00 2001 From: Ramesh Errabolu Date: Wed, 22 Nov 2023 10:05:56 -0600 Subject: [PATCH 1982/7721] dma-buf: Correct the documentation of name and exp_name symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the documentation of struct dma_buf members name and exp_name as to how these members are to be used and accessed. Signed-off-by: Ramesh Errabolu Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20231122160556.24948-1-Ramesh.Errabolu@amd.com Signed-off-by: Christian König --- include/linux/dma-buf.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 3f31baa3293f..8ff4add71f88 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -343,16 +343,19 @@ struct dma_buf { /** * @exp_name: * - * Name of the exporter; useful for debugging. See the - * DMA_BUF_SET_NAME IOCTL. + * Name of the exporter; useful for debugging. Must not be NULL */ const char *exp_name; /** * @name: * - * Userspace-provided name; useful for accounting and debugging, - * protected by dma_resv_lock() on @resv and @name_lock for read access. + * Userspace-provided name. Default value is NULL. If not NULL, + * length cannot be longer than DMA_BUF_NAME_LEN, including NIL + * char. Useful for accounting and debugging. Read/Write accesses + * are protected by @name_lock + * + * See the IOCTLs DMA_BUF_SET_NAME or DMA_BUF_SET_NAME_A/B */ const char *name; From 7b2d039da622daa9ba259ac6f38701d542b237c3 Mon Sep 17 00:00:00 2001 From: Anthony Krowiak Date: Thu, 9 Nov 2023 11:44:20 -0500 Subject: [PATCH 1983/7721] s390/vfio-ap: unpin pages on gisc registration failure In the vfio_ap_irq_enable function, after the page containing the notification indicator byte (NIB) is pinned, the function attempts to register the guest ISC. If registration fails, the function sets the status response code and returns without unpinning the page containing the NIB. In order to avoid a memory leak, the NIB should be unpinned before returning from the vfio_ap_irq_enable function. Co-developed-by: Janosch Frank Signed-off-by: Janosch Frank Signed-off-by: Anthony Krowiak Reviewed-by: Matthew Rosato Fixes: 783f0a3ccd79 ("s390/vfio-ap: add s390dbf logging to the vfio_ap_irq_enable function") Cc: Link: https://lore.kernel.org/r/20231109164427.460493-2-akrowiak@linux.ibm.com Signed-off-by: Alexander Gordeev --- drivers/s390/crypto/vfio_ap_ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 4db538a55192..9cb28978c186 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -457,6 +457,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, VFIO_AP_DBF_WARN("%s: gisc registration failed: nisc=%d, isc=%d, apqn=%#04x\n", __func__, nisc, isc, q->apqn); + vfio_unpin_pages(&q->matrix_mdev->vdev, nib, 1); status.response_code = AP_RESPONSE_INVALID_GISA; return status; } From 3746d48c55aced92c8fc1cbb432600da3e47344c Mon Sep 17 00:00:00 2001 From: Anthony Krowiak Date: Thu, 9 Nov 2023 11:44:21 -0500 Subject: [PATCH 1984/7721] s390/vfio-ap: set status response code to 06 on gisc registration failure The interception handler for the PQAP(AQIC) command calls the kvm_s390_gisc_register function to register the guest ISC with the channel subsystem. If that call fails, the status response code 08 - indicating Invalid ZONE/GISA designation - is returned to the guest. This response code is not valid because setting the ZONE/GISA values is the responsibility of the hypervisor controlling the guest and there is nothing that can be done from the guest perspective to correct that problem. The likelihood of GISC registration failure is nil and there is no status response code to indicate an invalid ISC value, so let's set the response code to 06 indicating 'Invalid address of AP-queue notification byte'. While this is not entirely accurate, it is better than setting a response code which makes no sense for the guest. Signed-off-by: Anthony Krowiak Suggested-by: Halil Pasic Reviewed-by: Halil Pasic Reviewed-by: Harald Freudenberger Link: https://lore.kernel.org/r/20231109164427.460493-3-akrowiak@linux.ibm.com Signed-off-by: Alexander Gordeev --- drivers/s390/crypto/vfio_ap_ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 9cb28978c186..25d7ce2094f8 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -393,8 +393,8 @@ static int ensure_nib_shared(unsigned long addr, struct gmap *gmap) * Register the guest ISC to GIB interface and retrieve the * host ISC to issue the host side PQAP/AQIC * - * Response.status may be set to AP_RESPONSE_INVALID_ADDRESS in case the - * vfio_pin_pages failed. + * status.response_code may be set to AP_RESPONSE_INVALID_ADDRESS in case the + * vfio_pin_pages or kvm_s390_gisc_register failed. * * Otherwise return the ap_queue_status returned by the ap_aqic(), * all retry handling will be done by the guest. @@ -458,7 +458,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, __func__, nisc, isc, q->apqn); vfio_unpin_pages(&q->matrix_mdev->vdev, nib, 1); - status.response_code = AP_RESPONSE_INVALID_GISA; + status.response_code = AP_RESPONSE_INVALID_ADDRESS; return status; } From c44ce579240d8025da74c6328295aa0a75a581a3 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Thu, 9 Nov 2023 11:44:22 -0500 Subject: [PATCH 1985/7721] s390/vfio-ap: improve reaction to response code 07 from PQAP(AQIC) command Let's improve the vfio_ap driver's reaction to reception of response code 07 from the PQAP(AQIC) command when enabling interrupts on behalf of a guest: * Unregister the guest's ISC before the pages containing the notification indicator bytes are unpinned. * Capture the return code from the kvm_s390_gisc_unregister function and log a DBF warning if it fails. Suggested-by: Matthew Rosato Signed-off-by: Tony Krowiak Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/r/20231109164427.460493-4-akrowiak@linux.ibm.com Signed-off-by: Alexander Gordeev --- drivers/s390/crypto/vfio_ap_ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 25d7ce2094f8..4e80c211ba47 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -476,8 +476,11 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, break; case AP_RESPONSE_OTHERWISE_CHANGED: /* We could not modify IRQ settings: clear new configuration */ + ret = kvm_s390_gisc_unregister(kvm, isc); + if (ret) + VFIO_AP_DBF_WARN("%s: kvm_s390_gisc_unregister: rc=%d isc=%d, apqn=%#04x\n", + __func__, ret, isc, q->apqn); vfio_unpin_pages(&q->matrix_mdev->vdev, nib, 1); - kvm_s390_gisc_unregister(kvm, isc); break; default: pr_warn("%s: apqn %04x: response: %02x\n", __func__, q->apqn, From a0d8f4eeb7c4ffaee21702bcc91a09b3988c5b7a Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Wed, 8 Nov 2023 15:11:30 -0500 Subject: [PATCH 1986/7721] s390/vfio-ap: fix sysfs status attribute for AP queue devices The 'status' attribute for AP queue devices bound to the vfio_ap device driver displays incorrect status when the mediated device is attached to a guest, but the queue device is not passed through. In the current implementation, the status displayed is 'in_use' which is not correct; it should be 'assigned'. This can happen if one of the queue devices associated with a given adapter is not bound to the vfio_ap device driver. For example: Queues listed in /sys/bus/ap/drivers/vfio_ap: 14.0005 14.0006 14.000d 16.0006 16.000d Queues listed in /sys/devices/vfio_ap/matrix/$UUID/matrix 14.0005 14.0006 14.000d 16.0005 16.0006 16.000d Queues listed in /sys/devices/vfio_ap/matrix/$UUID/guest_matrix 14.0005 14.0006 14.000d The reason no queues for adapter 0x16 are listed in the guest_matrix is because queue 16.0005 is not bound to the vfio_ap device driver, so no queue associated with the adapter is passed through to the guest; therefore, each queue device for adapter 0x16 should display 'assigned' instead of 'in_use', because those queues are not in use by a guest, but only assigned to the mediated device. Let's check the AP configuration for the guest to determine whether a queue device is passed through before displaying a status of 'in_use'. Signed-off-by: Tony Krowiak Acked-by: Halil Pasic Acked-by: Harald Freudenberger Link: https://lore.kernel.org/r/20231108201135.351419-1-akrowiak@linux.ibm.com Signed-off-by: Alexander Gordeev --- drivers/s390/crypto/vfio_ap_ops.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 4e80c211ba47..0d1adc7d730d 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -1980,6 +1980,7 @@ static ssize_t status_show(struct device *dev, { ssize_t nchars = 0; struct vfio_ap_queue *q; + unsigned long apid, apqi; struct ap_matrix_mdev *matrix_mdev; struct ap_device *apdev = to_ap_dev(dev); @@ -1987,8 +1988,21 @@ static ssize_t status_show(struct device *dev, q = dev_get_drvdata(&apdev->device); matrix_mdev = vfio_ap_mdev_for_queue(q); + /* If the queue is assigned to the matrix mediated device, then + * determine whether it is passed through to a guest; otherwise, + * indicate that it is unassigned. + */ if (matrix_mdev) { - if (matrix_mdev->kvm) + apid = AP_QID_CARD(q->apqn); + apqi = AP_QID_QUEUE(q->apqn); + /* + * If the queue is passed through to the guest, then indicate + * that it is in use; otherwise, indicate that it is + * merely assigned to a matrix mediated device. + */ + if (matrix_mdev->kvm && + test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) && + test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) nchars = scnprintf(buf, PAGE_SIZE, "%s\n", AP_QUEUE_IN_USE); else From d4c53ae8e4948f7f733f24cd863da31c8e9379a7 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Sat, 4 Nov 2023 10:04:31 +0100 Subject: [PATCH 1987/7721] s390/ap: store TAPQ hwinfo in struct ap_card As of now the AP card struct held only part of the queue's hwinfo (that is the GR2 register content returned with an TAPQ invocation). This patch reworks struct ap_card to hold the whole hwinfo now. As there is a nice bit field union on top of this ap_tapq_hwinfo struct, all the ugly bit checkings can now get replaced by simple evaluations of the required bit field. Suggested-by: Ingo Franzki Signed-off-by: Harald Freudenberger Reviewed-by: Holger Dengler Signed-off-by: Alexander Gordeev --- arch/s390/include/asm/ap.h | 21 ++++++---- drivers/s390/crypto/ap_bus.c | 69 ++++++++++++++----------------- drivers/s390/crypto/ap_bus.h | 20 ++------- drivers/s390/crypto/ap_card.c | 18 ++++---- drivers/s390/crypto/ap_queue.c | 33 +++++++-------- drivers/s390/crypto/vfio_ap_ops.c | 2 +- drivers/s390/crypto/zcrypt_api.c | 16 +++---- drivers/s390/crypto/zcrypt_cex4.c | 31 +++++++------- 8 files changed, 95 insertions(+), 115 deletions(-) diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 40c2b82f083a..43ac4a64f49b 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -88,7 +88,7 @@ static inline bool ap_instructions_available(void) } /* TAPQ register GR2 response struct */ -struct ap_tapq_gr2 { +struct ap_tapq_hwinfo { union { unsigned long value; struct { @@ -96,11 +96,13 @@ struct ap_tapq_gr2 { unsigned int apinfo : 32; /* ap type, ... */ }; struct { - unsigned int s : 1; /* APSC */ - unsigned int m : 1; /* AP4KM */ - unsigned int c : 1; /* AP4KC */ - unsigned int mode : 3; - unsigned int n : 1; /* APXA */ + unsigned int apsc : 1; /* APSC */ + unsigned int mex4k : 1; /* AP4KM */ + unsigned int crt4k : 1; /* AP4KC */ + unsigned int cca : 1; /* D */ + unsigned int accel : 1; /* A */ + unsigned int ep11 : 1; /* X */ + unsigned int apxa : 1; /* APXA */ unsigned int : 1; unsigned int class : 8; unsigned int bs : 2; /* SE bind/assoc */ @@ -126,11 +128,12 @@ struct ap_tapq_gr2 { /** * ap_tapq(): Test adjunct processor queue. * @qid: The AP queue number - * @info: Pointer to queue descriptor + * @info: Pointer to tapq hwinfo struct * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *info) +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, + struct ap_tapq_hwinfo *info) { union ap_queue_status_reg reg1; unsigned long reg2; @@ -158,7 +161,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *i * Returns AP queue status structure. */ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit, - struct ap_tapq_gr2 *info) + struct ap_tapq_hwinfo *info) { if (tbit) qid |= 1UL << 23; /* set T bit*/ diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5dd33155d5d5..20396eccb33b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -357,13 +357,12 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); * -1 invalid APQN, TAPQ error or AP queue status which * indicates there is no APQN. */ -static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, - int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) +static int ap_queue_info(ap_qid_t qid, struct ap_tapq_hwinfo *hwinfo, + bool *decfg, bool *cstop) { struct ap_queue_status status; - struct ap_tapq_gr2 tapq_info; - tapq_info.value = 0; + hwinfo->value = 0; /* make sure we don't run into a specifiation exception */ if (AP_QID_CARD(qid) > ap_max_adapter_id || @@ -371,7 +370,7 @@ static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, return -1; /* call TAPQ on this APQN */ - status = ap_test_queue(qid, ap_apft_available(), &tapq_info); + status = ap_test_queue(qid, ap_apft_available(), hwinfo); switch (status.response_code) { case AP_RESPONSE_NORMAL: @@ -389,15 +388,11 @@ static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, } /* There should be at least one of the mode bits set */ - if (WARN_ON_ONCE(!tapq_info.value)) + if (WARN_ON_ONCE(!hwinfo->value)) return 0; - *q_type = tapq_info.at; - *q_fac = tapq_info.fac; - *q_depth = tapq_info.qd; - *q_ml = tapq_info.ml; - *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; - *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; + *decfg = status.response_code == AP_RESPONSE_DECONFIGURED; + *cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; return 1; } @@ -642,11 +637,11 @@ static int ap_uevent(const struct device *dev, struct kobj_uevent_env *env) return rc; /* Add MODE= */ - if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) + if (ac->hwinfo.accel) rc = add_uevent_var(env, "MODE=accel"); - else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) + else if (ac->hwinfo.cca) rc = add_uevent_var(env, "MODE=cca"); - else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) + else if (ac->hwinfo.ep11) rc = add_uevent_var(env, "MODE=ep11"); if (rc) return rc; @@ -654,11 +649,11 @@ static int ap_uevent(const struct device *dev, struct kobj_uevent_env *env) struct ap_queue *aq = to_ap_queue(&ap_dev->device); /* Add MODE= */ - if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) + if (aq->card->hwinfo.accel) rc = add_uevent_var(env, "MODE=accel"); - else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) + else if (aq->card->hwinfo.cca) rc = add_uevent_var(env, "MODE=cca"); - else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) + else if (aq->card->hwinfo.ep11) rc = add_uevent_var(env, "MODE=ep11"); if (rc) return rc; @@ -1799,12 +1794,12 @@ static inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) */ static inline void ap_scan_domains(struct ap_card *ac) { - int rc, dom, depth, type, ml; + struct ap_tapq_hwinfo hwinfo; bool decfg, chkstop; struct ap_queue *aq; struct device *dev; - unsigned int func; ap_qid_t qid; + int rc, dom; /* * Go through the configuration for the domains and compare them @@ -1827,8 +1822,7 @@ static inline void ap_scan_domains(struct ap_card *ac) goto put_dev_and_continue; } /* domain is valid, get info from this APQN */ - rc = ap_queue_info(qid, &type, &func, &depth, - &ml, &decfg, &chkstop); + rc = ap_queue_info(qid, &hwinfo, &decfg, &chkstop); switch (rc) { case -1: if (dev) { @@ -1955,11 +1949,11 @@ static inline void ap_scan_domains(struct ap_card *ac) */ static inline void ap_scan_adapter(int ap) { - int rc, dom, depth, type, comp_type, ml; + struct ap_tapq_hwinfo hwinfo; + int rc, dom, comp_type; bool decfg, chkstop; struct ap_card *ac; struct device *dev; - unsigned int func; ap_qid_t qid; /* Is there currently a card device for this adapter ? */ @@ -1989,8 +1983,7 @@ static inline void ap_scan_adapter(int ap) for (dom = 0; dom <= ap_max_domain_id; dom++) if (ap_test_config_usage_domain(dom)) { qid = AP_MKQID(ap, dom); - if (ap_queue_info(qid, &type, &func, &depth, - &ml, &decfg, &chkstop) > 0) + if (ap_queue_info(qid, &hwinfo, &decfg, &chkstop) > 0) break; } if (dom > ap_max_domain_id) { @@ -2006,7 +1999,7 @@ static inline void ap_scan_adapter(int ap) } return; } - if (!type) { + if (!hwinfo.at) { /* No apdater type info available, an unusable adapter */ if (ac) { AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devs\n", @@ -2019,18 +2012,18 @@ static inline void ap_scan_adapter(int ap) } return; } + hwinfo.value &= TAPQ_CARD_HWINFO_MASK; /* filter card specific hwinfo */ if (ac) { /* Check APQN against existing card device for changes */ - if (ac->raw_hwtype != type) { + if (ac->hwinfo.at != hwinfo.at) { AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devs\n", - __func__, ap, type); + __func__, ap, hwinfo.at); ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); ac = NULL; - } else if ((ac->functions & TAPQ_CARD_FUNC_CMP_MASK) != - (func & TAPQ_CARD_FUNC_CMP_MASK)) { + } else if (ac->hwinfo.fac != hwinfo.fac) { AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n", - __func__, ap, func); + __func__, ap, hwinfo.fac); ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); ac = NULL; @@ -2064,13 +2057,13 @@ static inline void ap_scan_adapter(int ap) if (!ac) { /* Build a new card device */ - comp_type = ap_get_compatible_type(qid, type, func); + comp_type = ap_get_compatible_type(qid, hwinfo.at, hwinfo.fac); if (!comp_type) { AP_DBF_WARN("%s(%d) type %d, can't get compatibility type\n", - __func__, ap, type); + __func__, ap, hwinfo.at); return; } - ac = ap_card_create(ap, depth, type, comp_type, func, ml); + ac = ap_card_create(ap, hwinfo, comp_type); if (!ac) { AP_DBF_WARN("%s(%d) ap_card_create() failed\n", __func__, ap); @@ -2101,13 +2094,13 @@ static inline void ap_scan_adapter(int ap) get_device(dev); if (decfg) AP_DBF_INFO("%s(%d) new (decfg) card dev type=%d func=0x%08x created\n", - __func__, ap, type, func); + __func__, ap, hwinfo.at, hwinfo.fac); else if (chkstop) AP_DBF_INFO("%s(%d) new (chkstop) card dev type=%d func=0x%08x created\n", - __func__, ap, type, func); + __func__, ap, hwinfo.at, hwinfo.fac); else AP_DBF_INFO("%s(%d) new card dev type=%d func=0x%08x created\n", - __func__, ap, type, func); + __func__, ap, hwinfo.at, hwinfo.fac); } /* Verify the domains and the queue devices for this card */ diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index b0771ca0849b..cc256424f70b 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -75,16 +75,6 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) #define AP_DEVICE_TYPE_CEX7 13 #define AP_DEVICE_TYPE_CEX8 14 -/* - * Known function facilities - */ -#define AP_FUNC_MEX4K 1 -#define AP_FUNC_CRT4K 2 -#define AP_FUNC_COPRO 3 -#define AP_FUNC_ACCEL 4 -#define AP_FUNC_EP11 5 -#define AP_FUNC_APXA 6 - /* * AP queue state machine states */ @@ -182,9 +172,7 @@ struct ap_device { struct ap_card { struct ap_device ap_dev; - int raw_hwtype; /* AP raw hardware type. */ - unsigned int functions; /* TAPQ GR2 upper 32 facility bits */ - int queue_depth; /* AP queue depth.*/ + struct ap_tapq_hwinfo hwinfo; /* TAPQ GR2 content */ int id; /* AP card number. */ unsigned int maxmsgsize; /* AP msg limit for this card */ bool config; /* configured state */ @@ -192,7 +180,7 @@ struct ap_card { atomic64_t total_request_count; /* # requests ever for this AP device.*/ }; -#define TAPQ_CARD_FUNC_CMP_MASK 0xFFFF0000 +#define TAPQ_CARD_HWINFO_MASK 0xFEFF0000FFFF0F0FUL #define ASSOC_IDX_INVALID 0x10000 #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) @@ -290,8 +278,8 @@ void ap_queue_remove(struct ap_queue *aq); void ap_queue_init_state(struct ap_queue *aq); void _ap_queue_init_state(struct ap_queue *aq); -struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, - int comp_type, unsigned int functions, int ml); +struct ap_card *ap_card_create(int id, struct ap_tapq_hwinfo info, + int comp_type); #define APMASKSIZE (BITS_TO_LONGS(AP_DEVICES) * sizeof(unsigned long)) #define AQMASKSIZE (BITS_TO_LONGS(AP_DOMAINS) * sizeof(unsigned long)) diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index b2bd477659a7..ce953cbbd564 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -34,7 +34,7 @@ static ssize_t raw_hwtype_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return sysfs_emit(buf, "%d\n", ac->raw_hwtype); + return sysfs_emit(buf, "%d\n", ac->hwinfo.at); } static DEVICE_ATTR_RO(raw_hwtype); @@ -44,7 +44,7 @@ static ssize_t depth_show(struct device *dev, struct device_attribute *attr, { struct ap_card *ac = to_ap_card(dev); - return sysfs_emit(buf, "%d\n", ac->queue_depth); + return sysfs_emit(buf, "%d\n", ac->hwinfo.qd); } static DEVICE_ATTR_RO(depth); @@ -54,7 +54,7 @@ static ssize_t ap_functions_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return sysfs_emit(buf, "0x%08X\n", ac->functions); + return sysfs_emit(buf, "0x%08X\n", ac->hwinfo.fac); } static DEVICE_ATTR_RO(ap_functions); @@ -229,8 +229,8 @@ static void ap_card_device_release(struct device *dev) kfree(ac); } -struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, - int comp_type, unsigned int functions, int ml) +struct ap_card *ap_card_create(int id, struct ap_tapq_hwinfo hwinfo, + int comp_type) { struct ap_card *ac; @@ -240,12 +240,10 @@ struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, ac->ap_dev.device.release = ap_card_device_release; ac->ap_dev.device.type = &ap_card_type; ac->ap_dev.device_type = comp_type; - ac->raw_hwtype = raw_type; - ac->queue_depth = queue_depth; - ac->functions = functions; + ac->hwinfo = hwinfo; ac->id = id; - ac->maxmsgsize = ml > 0 ? - ml * AP_TAPQ_ML_FIELD_CHUNK_SIZE : AP_DEFAULT_MAX_MSG_SIZE; + ac->maxmsgsize = hwinfo.ml > 0 ? + hwinfo.ml * AP_TAPQ_ML_FIELD_CHUNK_SIZE : AP_DEFAULT_MAX_MSG_SIZE; return ac; } diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 3934a0cc13e7..39f250f1f1c3 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -24,13 +24,12 @@ static void __ap_flush_queue(struct ap_queue *aq); static inline bool ap_q_supports_bind(struct ap_queue *aq) { - return ap_test_bit(&aq->card->functions, AP_FUNC_EP11) || - ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL); + return aq->card->hwinfo.ep11 || aq->card->hwinfo.accel; } static inline bool ap_q_supports_assoc(struct ap_queue *aq) { - return ap_test_bit(&aq->card->functions, AP_FUNC_EP11); + return aq->card->hwinfo.ep11; } static inline bool ap_q_needs_bind(struct ap_queue *aq) @@ -257,7 +256,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) list_move_tail(&ap_msg->list, &aq->pendingq); aq->requestq_count--; aq->pendingq_count++; - if (aq->queue_count < aq->card->queue_depth) { + if (aq->queue_count < aq->card->hwinfo.qd) { aq->sm_state = AP_SM_STATE_WORKING; return AP_SM_WAIT_AGAIN; } @@ -421,9 +420,9 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) { struct ap_queue_status status; - struct ap_tapq_gr2 info; + struct ap_tapq_hwinfo hwinfo; - status = ap_test_queue(aq->qid, 1, &info); + status = ap_test_queue(aq->qid, 1, &hwinfo); /* handle asynchronous error on this queue */ if (status.async && status.response_code) { aq->dev_state = AP_DEV_STATE_ERROR; @@ -443,7 +442,7 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) } /* check bs bits */ - switch (info.bs) { + switch (hwinfo.bs) { case AP_BS_Q_USABLE: /* association is through */ aq->sm_state = AP_SM_STATE_IDLE; @@ -460,7 +459,7 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) aq->dev_state = AP_DEV_STATE_ERROR; aq->last_err_rc = status.response_code; AP_DBF_WARN("%s bs 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", - __func__, info.bs, + __func__, hwinfo.bs, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); return AP_SM_WAIT_NONE; } @@ -687,9 +686,9 @@ static ssize_t ap_functions_show(struct device *dev, { struct ap_queue *aq = to_ap_queue(dev); struct ap_queue_status status; - struct ap_tapq_gr2 info; + struct ap_tapq_hwinfo hwinfo; - status = ap_test_queue(aq->qid, 1, &info); + status = ap_test_queue(aq->qid, 1, &hwinfo); if (status.response_code > AP_RESPONSE_BUSY) { AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", __func__, status.response_code, @@ -697,7 +696,7 @@ static ssize_t ap_functions_show(struct device *dev, return -EIO; } - return sysfs_emit(buf, "0x%08X\n", info.fac); + return sysfs_emit(buf, "0x%08X\n", hwinfo.fac); } static DEVICE_ATTR_RO(ap_functions); @@ -840,19 +839,19 @@ static ssize_t se_bind_show(struct device *dev, { struct ap_queue *aq = to_ap_queue(dev); struct ap_queue_status status; - struct ap_tapq_gr2 info; + struct ap_tapq_hwinfo hwinfo; if (!ap_q_supports_bind(aq)) return sysfs_emit(buf, "-\n"); - status = ap_test_queue(aq->qid, 1, &info); + status = ap_test_queue(aq->qid, 1, &hwinfo); if (status.response_code > AP_RESPONSE_BUSY) { AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", __func__, status.response_code, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); return -EIO; } - switch (info.bs) { + switch (hwinfo.bs) { case AP_BS_Q_USABLE: case AP_BS_Q_USABLE_NO_SECURE_KEY: return sysfs_emit(buf, "bound\n"); @@ -920,12 +919,12 @@ static ssize_t se_associate_show(struct device *dev, { struct ap_queue *aq = to_ap_queue(dev); struct ap_queue_status status; - struct ap_tapq_gr2 info; + struct ap_tapq_hwinfo hwinfo; if (!ap_q_supports_assoc(aq)) return sysfs_emit(buf, "-\n"); - status = ap_test_queue(aq->qid, 1, &info); + status = ap_test_queue(aq->qid, 1, &hwinfo); if (status.response_code > AP_RESPONSE_BUSY) { AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", __func__, status.response_code, @@ -933,7 +932,7 @@ static ssize_t se_associate_show(struct device *dev, return -EIO; } - switch (info.bs) { + switch (hwinfo.bs) { case AP_BS_Q_USABLE: if (aq->assoc_idx == ASSOC_IDX_INVALID) { AP_DBF_WARN("%s AP_BS_Q_USABLE but invalid assoc_idx\n", __func__); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 0d1adc7d730d..243d252bc631 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -2315,7 +2315,7 @@ static void vfio_ap_filter_apid_by_qtype(unsigned long *apm, unsigned long *aqm) bool apid_cleared; struct ap_queue_status status; unsigned long apid, apqi; - struct ap_tapq_gr2 info; + struct ap_tapq_hwinfo info; for_each_set_bit_inv(apid, apm, AP_DEVICES) { apid_cleared = false; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index dcd6c7299fa9..74200f54dfff 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -673,7 +673,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, for_each_zcrypt_card(zc) { /* Check for usable accelerator or CCA card */ if (!zc->online || !zc->card->config || zc->card->chkstop || - !(zc->card->functions & 0x18000000)) + !(zc->card->hwinfo.accel || zc->card->hwinfo.cca)) continue; /* Check for size limits */ if (zc->min_mod_size > mex->inputdatalength || @@ -778,7 +778,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, for_each_zcrypt_card(zc) { /* Check for usable accelerator or CCA card */ if (!zc->online || !zc->card->config || zc->card->chkstop || - !(zc->card->functions & 0x18000000)) + !(zc->card->hwinfo.accel || zc->card->hwinfo.cca)) continue; /* Check for size limits */ if (zc->min_mod_size > crt->inputdatalength || @@ -893,7 +893,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, for_each_zcrypt_card(zc) { /* Check for usable CCA card */ if (!zc->online || !zc->card->config || zc->card->chkstop || - !(zc->card->functions & 0x10000000)) + !zc->card->hwinfo.cca) continue; /* Check for user selected CCA card */ if (xcrb->user_defined != AUTOSELECT && @@ -1064,7 +1064,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, for_each_zcrypt_card(zc) { /* Check for usable EP11 card */ if (!zc->online || !zc->card->config || zc->card->chkstop || - !(zc->card->functions & 0x04000000)) + !zc->card->hwinfo.ep11) continue; /* Check for user selected EP11 card */ if (targets && @@ -1177,7 +1177,7 @@ static long zcrypt_rng(char *buffer) for_each_zcrypt_card(zc) { /* Check for usable CCA card */ if (!zc->online || !zc->card->config || zc->card->chkstop || - !(zc->card->functions & 0x10000000)) + !zc->card->hwinfo.cca) continue; /* get weight index of the card device */ wgt = zc->speed_rating[func_code]; @@ -1238,7 +1238,7 @@ static void zcrypt_device_status_mask(struct zcrypt_device_status *devstatus) queue = AP_QID_QUEUE(zq->queue->qid); stat = &devstatus[card * AP_DOMAINS + queue]; stat->hwtype = zc->card->ap_dev.device_type; - stat->functions = zc->card->functions >> 26; + stat->functions = zc->card->hwinfo.fac >> 26; stat->qid = zq->queue->qid; stat->online = zq->online ? 0x01 : 0x00; } @@ -1263,7 +1263,7 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus) queue = AP_QID_QUEUE(zq->queue->qid); stat = &devstatus[card * AP_DOMAINS + queue]; stat->hwtype = zc->card->ap_dev.device_type; - stat->functions = zc->card->functions >> 26; + stat->functions = zc->card->hwinfo.fac >> 26; stat->qid = zq->queue->qid; stat->online = zq->online ? 0x01 : 0x00; } @@ -1286,7 +1286,7 @@ int zcrypt_device_status_ext(int card, int queue, if (card == AP_QID_CARD(zq->queue->qid) && queue == AP_QID_QUEUE(zq->queue->qid)) { devstat->hwtype = zc->card->ap_dev.device_type; - devstat->functions = zc->card->functions >> 26; + devstat->functions = zc->card->hwinfo.fac >> 26; devstat->qid = zq->queue->qid; devstat->online = zq->online ? 0x01 : 0x00; spin_unlock(&zcrypt_list_lock); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 5c4532ab0040..64df7d2f6266 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -477,7 +477,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) return -ENOMEM; zc->card = ac; dev_set_drvdata(&ap_dev->device, zc); - if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) { + if (ac->hwinfo.accel) { if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4A"; zc->user_space_type = ZCRYPT_CEX4; @@ -506,8 +506,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->user_space_type = ZCRYPT_CEX6; } zc->min_mod_size = CEX4A_MIN_MOD_SIZE; - if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && - ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) { + if (ac->hwinfo.mex4k && ac->hwinfo.crt4k) { zc->max_mod_size = CEX4A_MAX_MOD_SIZE_4K; zc->max_exp_bit_length = CEX4A_MAX_MOD_SIZE_4K; @@ -516,7 +515,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->max_exp_bit_length = CEX4A_MAX_MOD_SIZE_2K; } - } else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + } else if (ac->hwinfo.cca) { if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4C"; zc->speed_rating = CEX4C_SPEED_IDX; @@ -556,7 +555,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->min_mod_size = CEX4C_MIN_MOD_SIZE; zc->max_mod_size = CEX4C_MAX_MOD_SIZE; zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; - } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) { + } else if (ac->hwinfo.ep11) { if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4P"; zc->user_space_type = ZCRYPT_CEX4; @@ -599,14 +598,14 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) return rc; } - if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + if (ac->hwinfo.cca) { rc = sysfs_create_group(&ap_dev->device.kobj, &cca_card_attr_grp); if (rc) { zcrypt_card_unregister(zc); zcrypt_card_free(zc); } - } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) { + } else if (ac->hwinfo.ep11) { rc = sysfs_create_group(&ap_dev->device.kobj, &ep11_card_attr_grp); if (rc) { @@ -627,9 +626,9 @@ static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device); struct ap_card *ac = to_ap_card(&ap_dev->device); - if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) + if (ac->hwinfo.cca) sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_grp); - else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) + else if (ac->hwinfo.ep11) sysfs_remove_group(&ap_dev->device.kobj, &ep11_card_attr_grp); zcrypt_card_unregister(zc); @@ -654,19 +653,19 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) struct zcrypt_queue *zq; int rc; - if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) { + if (aq->card->hwinfo.accel) { zq = zcrypt_queue_alloc(aq->card->maxmsgsize); if (!zq) return -ENOMEM; zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); - } else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + } else if (aq->card->hwinfo.cca) { zq = zcrypt_queue_alloc(aq->card->maxmsgsize); if (!zq) return -ENOMEM; zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, MSGTYPE06_VARIANT_DEFAULT); - } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) { + } else if (aq->card->hwinfo.ep11) { zq = zcrypt_queue_alloc(aq->card->maxmsgsize); if (!zq) return -ENOMEM; @@ -689,14 +688,14 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) return rc; } - if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + if (aq->card->hwinfo.cca) { rc = sysfs_create_group(&ap_dev->device.kobj, &cca_queue_attr_grp); if (rc) { zcrypt_queue_unregister(zq); zcrypt_queue_free(zq); } - } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) { + } else if (aq->card->hwinfo.ep11) { rc = sysfs_create_group(&ap_dev->device.kobj, &ep11_queue_attr_grp); if (rc) { @@ -717,9 +716,9 @@ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device); struct ap_queue *aq = to_ap_queue(&ap_dev->device); - if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) + if (aq->card->hwinfo.cca) sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_grp); - else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) + else if (aq->card->hwinfo.ep11) sysfs_remove_group(&ap_dev->device.kobj, &ep11_queue_attr_grp); zcrypt_queue_unregister(zq); From 207022d39d3b158ca3581e321212f799fa5e7e24 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 9 Nov 2023 11:24:20 +0100 Subject: [PATCH 1988/7721] s390/ap: handle outband SE bind state change This patch addresses some weird scenarios where an outband manipulation of the SE bind state of a queue assigned and maybe in use by an SE guest with AP pass-through support took place. So for example when the guest has bound and associated a queue and then this domain has been zeroed on the service element. Signed-off-by: Harald Freudenberger Reviewed-by: Holger Dengler Signed-off-by: Alexander Gordeev --- drivers/s390/crypto/ap_bus.c | 3 + drivers/s390/crypto/ap_bus.h | 2 +- drivers/s390/crypto/ap_queue.c | 167 +++++++++++++++++++++++---------- 3 files changed, 122 insertions(+), 50 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 20396eccb33b..f46dd6abacd7 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1847,6 +1847,7 @@ static inline void ap_scan_domains(struct ap_card *ac) aq->card = ac; aq->config = !decfg; aq->chkstop = chkstop; + aq->se_bstate = hwinfo.bs; dev = &aq->ap_dev.device; dev->bus = &ap_bus_type; dev->parent = &ac->ap_dev.device; @@ -1876,6 +1877,8 @@ static inline void ap_scan_domains(struct ap_card *ac) } /* handle state changes on already existing queue device */ spin_lock_bh(&aq->lock); + /* SE bind state */ + aq->se_bstate = hwinfo.bs; /* checkstop state */ if (chkstop && !aq->chkstop) { /* checkstop on */ diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index cc256424f70b..98814839ef30 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -194,7 +194,7 @@ struct ap_queue { bool config; /* configured state */ bool chkstop; /* checkstop state */ ap_qid_t qid; /* AP queue id. */ - bool se_bound; /* SE bound state */ + unsigned int se_bstate; /* SE bind state (BS) */ unsigned int assoc_idx; /* SE association index */ int queue_count; /* # messages currently on AP queue. */ int pendingq_count; /* # requests on pendingq list. */ diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 39f250f1f1c3..682595443145 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -317,7 +317,6 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) case AP_RESPONSE_RESET_IN_PROGRESS: aq->sm_state = AP_SM_STATE_RESET_WAIT; aq->rapq_fbit = 0; - aq->se_bound = false; return AP_SM_WAIT_LOW_TIMEOUT; default: aq->dev_state = AP_DEV_STATE_ERROR; @@ -338,17 +337,15 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq) { struct ap_queue_status status; + struct ap_tapq_hwinfo hwinfo; void *lsi_ptr; - if (aq->queue_count > 0 && aq->reply) - /* Try to read a completed message and get the status */ - status = ap_sm_recv(aq); - else - /* Get the status with TAPQ */ - status = ap_tapq(aq->qid, NULL); + /* Get the status with TAPQ */ + status = ap_test_queue(aq->qid, 1, &hwinfo); switch (status.response_code) { case AP_RESPONSE_NORMAL: + aq->se_bstate = hwinfo.bs; lsi_ptr = ap_airq_ptr(); if (lsi_ptr && ap_queue_enable_irq(aq, lsi_ptr) == 0) aq->sm_state = AP_SM_STATE_SETIRQ_WAIT; @@ -441,6 +438,9 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) return AP_SM_WAIT_NONE; } + /* update queue's SE bind state */ + aq->se_bstate = hwinfo.bs; + /* check bs bits */ switch (hwinfo.bs) { case AP_BS_Q_USABLE: @@ -851,6 +851,12 @@ static ssize_t se_bind_show(struct device *dev, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); return -EIO; } + + /* update queue's SE bind state */ + spin_lock_bh(&aq->lock); + aq->se_bstate = hwinfo.bs; + spin_unlock_bh(&aq->lock); + switch (hwinfo.bs) { case AP_BS_Q_USABLE: case AP_BS_Q_USABLE_NO_SECURE_KEY: @@ -866,6 +872,7 @@ static ssize_t se_bind_store(struct device *dev, { struct ap_queue *aq = to_ap_queue(dev); struct ap_queue_status status; + struct ap_tapq_hwinfo hwinfo; bool value; int rc; @@ -877,39 +884,80 @@ static ssize_t se_bind_store(struct device *dev, if (rc) return rc; - if (value) { - /* bind, do BAPQ */ - spin_lock_bh(&aq->lock); - if (aq->sm_state < AP_SM_STATE_IDLE) { - spin_unlock_bh(&aq->lock); - return -EBUSY; - } - status = ap_bapq(aq->qid); - spin_unlock_bh(&aq->lock); - if (!status.response_code) { - aq->se_bound = true; - AP_DBF_INFO("%s bapq(0x%02x.%04x) success\n", __func__, - AP_QID_CARD(aq->qid), - AP_QID_QUEUE(aq->qid)); - } else { - AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n", - __func__, status.response_code, - AP_QID_CARD(aq->qid), - AP_QID_QUEUE(aq->qid)); - return -EIO; - } - } else { - /* unbind, set F bit arg and trigger RAPQ */ + if (!value) { + /* Unbind. Set F bit arg and trigger RAPQ */ spin_lock_bh(&aq->lock); __ap_flush_queue(aq); aq->rapq_fbit = 1; - aq->assoc_idx = ASSOC_IDX_INVALID; - aq->sm_state = AP_SM_STATE_RESET_START; - ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); - spin_unlock_bh(&aq->lock); + _ap_queue_init_state(aq); + rc = count; + goto out; } - return count; + /* Bind. Check current SE bind state */ + status = ap_test_queue(aq->qid, 1, &hwinfo); + if (status.response_code) { + AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } + + /* Update BS state */ + spin_lock_bh(&aq->lock); + aq->se_bstate = hwinfo.bs; + if (hwinfo.bs != AP_BS_Q_AVAIL_FOR_BINDING) { + AP_DBF_WARN("%s bind attempt with bs %d on queue 0x%02x.%04x\n", + __func__, hwinfo.bs, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = -EINVAL; + goto out; + } + + /* Check SM state */ + if (aq->sm_state < AP_SM_STATE_IDLE) { + rc = -EBUSY; + goto out; + } + + /* invoke BAPQ */ + status = ap_bapq(aq->qid); + if (status.response_code) { + AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = -EIO; + goto out; + } + aq->assoc_idx = ASSOC_IDX_INVALID; + + /* verify SE bind state */ + status = ap_test_queue(aq->qid, 1, &hwinfo); + if (status.response_code) { + AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = -EIO; + goto out; + } + aq->se_bstate = hwinfo.bs; + if (!(hwinfo.bs == AP_BS_Q_USABLE || + hwinfo.bs == AP_BS_Q_USABLE_NO_SECURE_KEY)) { + AP_DBF_WARN("%s BAPQ success, but bs shows %d on queue 0x%02x.%04x\n", + __func__, hwinfo.bs, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = -EIO; + goto out; + } + + /* SE bind was successful */ + AP_DBF_INFO("%s bapq(0x%02x.%04x) success\n", __func__, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = count; + +out: + spin_unlock_bh(&aq->lock); + return rc; } static DEVICE_ATTR_RW(se_bind); @@ -932,6 +980,11 @@ static ssize_t se_associate_show(struct device *dev, return -EIO; } + /* update queue's SE bind state */ + spin_lock_bh(&aq->lock); + aq->se_bstate = hwinfo.bs; + spin_unlock_bh(&aq->lock); + switch (hwinfo.bs) { case AP_BS_Q_USABLE: if (aq->assoc_idx == ASSOC_IDX_INVALID) { @@ -954,6 +1007,7 @@ static ssize_t se_associate_store(struct device *dev, { struct ap_queue *aq = to_ap_queue(dev); struct ap_queue_status status; + struct ap_tapq_hwinfo hwinfo; unsigned int value; int rc; @@ -967,18 +1021,28 @@ static ssize_t se_associate_store(struct device *dev, if (value >= ASSOC_IDX_INVALID) return -EINVAL; + /* check current SE bind state */ + status = ap_test_queue(aq->qid, 1, &hwinfo); + if (status.response_code) { + AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } spin_lock_bh(&aq->lock); - - /* sm should be in idle state */ - if (aq->sm_state != AP_SM_STATE_IDLE) { - spin_unlock_bh(&aq->lock); - return -EBUSY; + aq->se_bstate = hwinfo.bs; + if (hwinfo.bs != AP_BS_Q_USABLE_NO_SECURE_KEY) { + AP_DBF_WARN("%s association attempt with bs %d on queue 0x%02x.%04x\n", + __func__, hwinfo.bs, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + rc = -EINVAL; + goto out; } - /* already associated or association pending ? */ - if (aq->assoc_idx != ASSOC_IDX_INVALID) { - spin_unlock_bh(&aq->lock); - return -EINVAL; + /* check SM state */ + if (aq->sm_state != AP_SM_STATE_IDLE) { + rc = -EBUSY; + goto out; } /* trigger the asynchronous association request */ @@ -989,17 +1053,20 @@ static ssize_t se_associate_store(struct device *dev, aq->sm_state = AP_SM_STATE_ASSOC_WAIT; aq->assoc_idx = value; ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); - spin_unlock_bh(&aq->lock); break; default: - spin_unlock_bh(&aq->lock); AP_DBF_WARN("%s RC 0x%02x on aapq(0x%02x.%04x)\n", __func__, status.response_code, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); - return -EIO; + rc = -EIO; + goto out; } - return count; + rc = count; + +out: + spin_unlock_bh(&aq->lock); + return rc; } static DEVICE_ATTR_RW(se_associate); @@ -1122,7 +1189,9 @@ bool ap_queue_usable(struct ap_queue *aq) } /* SE guest's queues additionally need to be bound */ - if (ap_q_needs_bind(aq) && !aq->se_bound) + if (ap_q_needs_bind(aq) && + !(aq->se_bstate == AP_BS_Q_USABLE || + aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY)) rc = false; unlock_and_out: From 05205b9576615fca5da91cdae5a3f89f2ad32703 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 28 Nov 2023 07:19:25 -0800 Subject: [PATCH 1989/7721] wifi: ath12k: Update Qualcomm Innovation Center, Inc. copyrights Update the copyright for all ath12k files modified on behalf of Qualcomm Innovation Center, Inc. in 2023. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231128-ath12kcopyrights-v1-1-be0b7408cbac@quicinc.com --- drivers/net/wireless/ath/ath12k/dbring.c | 2 +- drivers/net/wireless/ath/ath12k/debug.c | 2 +- drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +- drivers/net/wireless/ath/ath12k/hal.c | 2 +- drivers/net/wireless/ath/ath12k/hal.h | 2 +- drivers/net/wireless/ath/ath12k/hal_rx.c | 2 +- drivers/net/wireless/ath/ath12k/hif.h | 2 +- drivers/net/wireless/ath/ath12k/hw.c | 2 +- drivers/net/wireless/ath/ath12k/hw.h | 2 +- drivers/net/wireless/ath/ath12k/mac.c | 2 +- drivers/net/wireless/ath/ath12k/mac.h | 2 +- drivers/net/wireless/ath/ath12k/mhi.c | 2 +- drivers/net/wireless/ath/ath12k/pci.c | 2 +- drivers/net/wireless/ath/ath12k/pci.h | 2 +- drivers/net/wireless/ath/ath12k/peer.h | 2 +- drivers/net/wireless/ath/ath12k/qmi.c | 2 +- drivers/net/wireless/ath/ath12k/qmi.h | 2 +- drivers/net/wireless/ath/ath12k/reg.c | 2 +- drivers/net/wireless/ath/ath12k/reg.h | 2 +- drivers/net/wireless/ath/ath12k/rx_desc.h | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dbring.c b/drivers/net/wireless/ath/ath12k/dbring.c index 8fbf868e6f7e..788160c84c68 100644 --- a/drivers/net/wireless/ath/ath12k/dbring.c +++ b/drivers/net/wireless/ath/ath12k/dbring.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath12k/debug.c b/drivers/net/wireless/ath/ath12k/debug.c index 45d33279e665..fe5a732ba9ec 100644 --- a/drivers/net/wireless/ath/ath12k/debug.c +++ b/drivers/net/wireless/ath/ath12k/debug.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 492ca6ce6714..62f9cdbb811c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index eca86fc25a60..ca6f1d0db31e 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "hal_tx.h" diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 66035a787c72..fc47e7e6b498 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_H diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index f6afbd8196bf..4f25eb9f7745 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index 4095fd82b1b3..c653ca1f59b2 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HIF_H diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 2245fb510ba2..ea3eda1f1948 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 2d6427cf41a4..d2622bfef942 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HW_H diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fc0d14ea328e..a13506c177f6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 59b4e8f5eee0..7d71ae1aba45 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_MAC_H diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 39e640293cdc..27eb38b2b1bd 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 3006cd3fbe11..a6a5f9bcffbd 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 0f24fd9395cd..9a17a7dcdd6a 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PCI_H #define ATH12K_PCI_H diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index c6edb24cbedd..7b3500b5c8c2 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PEER_H diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index f6e949c618d0..77a132f6bbd1 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index e20d6511d1ca..e25bbaa125e8 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_QMI_H diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 5c006256c82a..8321715779cb 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "core.h" diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h index 35569f03042d..d4a0776e1034 100644 --- a/drivers/net/wireless/ath/ath12k/reg.h +++ b/drivers/net/wireless/ath/ath12k/reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_REG_H diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index c4058abc516e..55f20c446ca9 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_RX_DESC_H #define ATH12K_RX_DESC_H diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 0e5bf5ce8d4c..11cc3005c0f9 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include From ea77e9398b326d65b052096840b883271f8a7a48 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 29 Nov 2023 13:39:23 +0200 Subject: [PATCH 1990/7721] wifi: ath11k: Update Qualcomm Innovation Center, Inc. copyrights Update the copyright for all ath11k files modified on behalf of Qualcomm Innovation Center, Inc. in 2021 through 2023. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231128-ath12kcopyrights-v1-2-be0b7408cbac@quicinc.com --- drivers/net/wireless/ath/ath11k/ce.c | 2 +- drivers/net/wireless/ath/ath11k/ce.h | 1 + drivers/net/wireless/ath/ath11k/dbring.c | 1 + drivers/net/wireless/ath/ath11k/dbring.h | 1 + drivers/net/wireless/ath/ath11k/debug.c | 1 + drivers/net/wireless/ath/ath11k/debug.h | 2 +- drivers/net/wireless/ath/ath11k/debugfs.c | 1 + drivers/net/wireless/ath/ath11k/debugfs.h | 1 + drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c | 2 +- drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h | 2 +- drivers/net/wireless/ath/ath11k/debugfs_sta.c | 1 + drivers/net/wireless/ath/ath11k/debugfs_sta.h | 1 + drivers/net/wireless/ath/ath11k/dp.c | 2 +- drivers/net/wireless/ath/ath11k/dp.h | 2 +- drivers/net/wireless/ath/ath11k/dp_rx.c | 1 + drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +- drivers/net/wireless/ath/ath11k/dp_tx.h | 1 + drivers/net/wireless/ath/ath11k/hal.c | 2 +- drivers/net/wireless/ath/ath11k/hal.h | 2 +- drivers/net/wireless/ath/ath11k/hal_desc.h | 1 + drivers/net/wireless/ath/ath11k/hal_rx.c | 1 + drivers/net/wireless/ath/ath11k/hal_rx.h | 1 + drivers/net/wireless/ath/ath11k/hif.h | 1 + drivers/net/wireless/ath/ath11k/htc.c | 1 + drivers/net/wireless/ath/ath11k/htc.h | 1 + drivers/net/wireless/ath/ath11k/hw.c | 2 +- drivers/net/wireless/ath/ath11k/hw.h | 2 +- drivers/net/wireless/ath/ath11k/mac.h | 1 + drivers/net/wireless/ath/ath11k/mhi.c | 2 +- drivers/net/wireless/ath/ath11k/mhi.h | 1 + drivers/net/wireless/ath/ath11k/pcic.c | 2 +- drivers/net/wireless/ath/ath11k/peer.c | 2 +- drivers/net/wireless/ath/ath11k/peer.h | 2 +- drivers/net/wireless/ath/ath11k/qmi.c | 2 +- drivers/net/wireless/ath/ath11k/qmi.h | 2 +- drivers/net/wireless/ath/ath11k/reg.c | 1 + drivers/net/wireless/ath/ath11k/reg.h | 1 + drivers/net/wireless/ath/ath11k/rx_desc.h | 1 + drivers/net/wireless/ath/ath11k/spectral.c | 1 + drivers/net/wireless/ath/ath11k/spectral.h | 1 + drivers/net/wireless/ath/ath11k/thermal.c | 1 + drivers/net/wireless/ath/ath11k/thermal.h | 1 + drivers/net/wireless/ath/ath11k/trace.h | 1 + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.h | 2 +- drivers/net/wireless/ath/ath11k/wow.h | 1 + 46 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 289d47ae92af..e66e86bdec20 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_rx.h" diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index c0f6a0ba86df..69946fc70077 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CE_H diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index 5536e8642331..fbb6e8d8a476 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index ef906c687b8c..2f93b78a50df 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DBRING_H diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index f5c8a34c8802..2b8544355fc1 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 9c52804ef8ac..cc8934d15697 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUG_H_ diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index be76e7d1c436..a847bc0d50c0 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h index 3af0169f6cf2..44d15845f39a 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.h +++ b/drivers/net/wireless/ath/ath11k/debugfs.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUGFS_H_ diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index 0207fc4910f3..870e86a31bf8 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 96219301f05b..476689bbd4da 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef DEBUG_HTT_STATS_H diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index 8c177fba6f14..f56a24b6c8da 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.h b/drivers/net/wireless/ath/ath11k/debugfs_sta.h index e6c11b3a40aa..ace877e19275 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUGFS_STA_H_ diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index a7252b52555c..8975dc57ad77 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 15815af453b2..2f6dd69d3be2 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_H diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 7eac93ce7a1d..afd481f5858f 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index a5fa08bc623b..c1072e66e3e8 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h index 68a21ea9b934..61be2265e09f 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_TX_H diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 23f3af8e372d..c060c4b5c0cc 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "hal_tx.h" diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 1942d41d6de5..80447f488954 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_H diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h index d895ea878d9f..b2fd180bd28e 100644 --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index 41946795d620..e758ee8e17c9 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h index 472a52cf5889..0fa9aef9d533 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.h +++ b/drivers/net/wireless/ath/ath11k/hal_rx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_RX_H diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index d68ed4214dec..877a4073fed6 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HIF_H_ diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 2c2e425c8665..23054ab29a5e 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h index d31e501c807c..cf6b9aa0784d 100644 --- a/drivers/net/wireless/ath/ath11k/htc.h +++ b/drivers/net/wireless/ath/ath11k/htc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HTC_H diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index d7b5ec6e6904..77d8f9237680 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index d51a99669dd6..1b070747a5db 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HW_H diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 0231783ad754..0dfdeed5177b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_MAC_H diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index afeabd6ecc67..6835c14b82cc 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index 8d9f852da695..f81fba2644a4 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_MHI_H #define _ATH11K_MHI_H diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 16d1e332193f..90d8936a3e2e 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 1c79a932d17f..6d0126c39301 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index 9bd385d0a38c..3ad2f3355b14 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_PEER_H diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c270dc46d506..2c7cab62b9bb 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index d477e2be814b..7e06d100af57 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_QMI_H diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 3c7debae800a..b4fd4d2107c7 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 84daa6543b6a..f28902f85e41 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h index 786d5f36f5e5..2da6da727278 100644 --- a/drivers/net/wireless/ath/ath11k/rx_desc.h +++ b/drivers/net/wireless/ath/ath11k/rx_desc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_RX_DESC_H #define ATH11K_RX_DESC_H diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 0b7b7122cc05..79e091134515 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/spectral.h b/drivers/net/wireless/ath/ath11k/spectral.h index 96bfa16e18e9..789cff7c64a7 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.h +++ b/drivers/net/wireless/ath/ath11k/spectral.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_SPECTRAL_H diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index c9b012f97ba5..c29b11ab5bfa 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath11k/thermal.h b/drivers/net/wireless/ath/ath11k/thermal.h index 83cb67686733..cdaf4e01d92e 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.h +++ b/drivers/net/wireless/ath/ath11k/thermal.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_THERMAL_ diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 9535745fe026..235ab8ea715f 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 2845b4313d3a..8a65fa04b48d 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 3ad29d5d0999..ff0a9a92beeb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_WMI_H diff --git a/drivers/net/wireless/ath/ath11k/wow.h b/drivers/net/wireless/ath/ath11k/wow.h index 553ba850d910..c85811e3f42b 100644 --- a/drivers/net/wireless/ath/ath11k/wow.h +++ b/drivers/net/wireless/ath/ath11k/wow.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WOW_H_ From b1dc0ba41431147e55407140962c76f3e7a06753 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 29 Nov 2023 13:39:28 +0200 Subject: [PATCH 1991/7721] wifi: ath10k: Update Qualcomm Innovation Center, Inc. copyrights Update the copyright for all ath10k files modified on behalf of Qualcomm Innovation Center, Inc. in 2021 through 2023. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231128-ath12kcopyrights-v1-3-be0b7408cbac@quicinc.com --- drivers/net/wireless/ath/ath10k/bmi.c | 1 + drivers/net/wireless/ath/ath10k/ce.c | 1 + drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/coredump.c | 1 + drivers/net/wireless/ath/ath10k/coredump.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 1 + drivers/net/wireless/ath/ath10k/debugfs_sta.c | 1 + drivers/net/wireless/ath/ath10k/htc.c | 1 + drivers/net/wireless/ath/ath10k/htt.h | 1 + drivers/net/wireless/ath/ath10k/htt_rx.c | 1 + drivers/net/wireless/ath/ath10k/htt_tx.c | 1 + drivers/net/wireless/ath/ath10k/hw.c | 1 + drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 1 + drivers/net/wireless/ath/ath10k/pci.c | 1 + drivers/net/wireless/ath/ath10k/pci.h | 1 + drivers/net/wireless/ath/ath10k/qmi.c | 1 + drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c | 1 + drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h | 1 + drivers/net/wireless/ath/ath10k/rx_desc.h | 1 + drivers/net/wireless/ath/ath10k/sdio.c | 1 + drivers/net/wireless/ath/ath10k/thermal.c | 1 + drivers/net/wireless/ath/ath10k/usb.h | 1 + drivers/net/wireless/ath/ath10k/wmi-tlv.h | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 1 + drivers/net/wireless/ath/ath10k/wmi.h | 1 + drivers/net/wireless/ath/ath10k/wow.c | 1 + 28 files changed, 28 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index af6546572df2..9a4f8e815412 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "bmi.h" diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index c27b8204718a..afae4a8027f8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "hif.h" diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6cdb225b7eac..e9a434f1eb42 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ba9795a8378a..c110d15528bd 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CORE_H_ diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 2d1634a890dd..bb3a276b7ed5 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "coredump.h" diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 437b9759f05d..e5ef0352e319 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _COREDUMP_H_ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index ad9cf953a2fc..b93a64bf8190 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 87a3365330ff..394bf3c32abf 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 5bfeecb95fca..a6e21ce90bad 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index c80470e8886a..4a9270e2a4c8 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HTT_H_ diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b261d6371c0f..fa0f598ed6bf 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 5d814162e02b..9725feecefd6 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 6d32b43a4da6..8fafe096adff 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 9643031a4427..2e65902f8b21 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HW_H_ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e18427f72492..ed2db79b7b18 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2f8c785277af..3de2de6d44bc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 480cd97ab739..27bb4cf2dfea 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _PCI_H_ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 52c1a3de8da6..38e939f572a9 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 1c81e454f943..0e85c75d2278 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h index f0db991408dc..9f311f3bc9e7 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef WCN3990_QMI_SVC_V01_H diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 777e53aa69dc..564293df1e9a 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _RX_DESC_H_ diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 56fbcfb80bf8..0ab5433f6cf6 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -3,6 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index cefd97323dfe..31c8d7fbb095 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/usb.h b/drivers/net/wireless/ath/ath10k/usb.h index 48e066ba8162..7e4cfbb673c9 100644 --- a/drivers/net/wireless/ath/ath10k/usb.h +++ b/drivers/net/wireless/ath/ath10k/usb.h @@ -3,6 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _USB_H_ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index dbb48d70f2e9..83a8f07a687f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_TLV_H #define _WMI_TLV_H diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 05fa7d4c0e1a..88befe92f95d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b112e8826093..9146df98fcee 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_H_ diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 20b9aa8ddf7d..aa7b2e703f3d 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" From c7876faa91ab01b314b81ea8e5a0ccdeb186f483 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 27 Nov 2023 08:14:47 -0800 Subject: [PATCH 1992/7721] wifi: ath10k: remove ath10k_htc_record::pauload[] The misspelled pauload member of struct ath10k_htc_record is unused, so remove it. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231127-flexarray-htc_record-v1-1-6be1f36126fd@quicinc.com --- drivers/net/wireless/ath/ath10k/htc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 0eaa21ad86ac..feb7af8f373a 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -249,7 +249,6 @@ struct ath10k_htc_record { struct ath10k_htc_credit_report credit_report[0]; struct ath10k_htc_lookahead_report lookahead_report[0]; struct ath10k_htc_lookahead_bundle lookahead_bundle[0]; - u8 pauload[0]; }; } __packed __aligned(4); From 7b4df59fced034c88c012231361f94662d2487dc Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 27 Nov 2023 08:14:48 -0800 Subject: [PATCH 1993/7721] wifi: ath10k: Use DECLARE_FLEX_ARRAY() for ath10k_htc_record Transform the zero-length arrays in ath10k_htc_record into proper flexible arrays via the DECLARE_FLEX_ARRAY() macro. This helps with ongoing efforts to globally enable -Warray-bounds. Signed-off-by: Jeff Johnson Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231127-flexarray-htc_record-v1-2-6be1f36126fd@quicinc.com --- drivers/net/wireless/ath/ath10k/htc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index feb7af8f373a..7ff665020015 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -246,9 +246,9 @@ struct ath10k_htc_lookahead_bundle { struct ath10k_htc_record { struct ath10k_ath10k_htc_record_hdr hdr; union { - struct ath10k_htc_credit_report credit_report[0]; - struct ath10k_htc_lookahead_report lookahead_report[0]; - struct ath10k_htc_lookahead_bundle lookahead_bundle[0]; + DECLARE_FLEX_ARRAY(struct ath10k_htc_credit_report, credit_report); + DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_report, lookahead_report); + DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_bundle, lookahead_bundle); }; } __packed __aligned(4); From f20eb4cb93240c4da4c7a3563b4063047bef3a7b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 27 Nov 2023 08:14:49 -0800 Subject: [PATCH 1994/7721] wifi: ath11k: remove ath11k_htc_record::pauload[] The misspelled pauload member of struct ath11k_htc_record is unused, so remove it. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231127-flexarray-htc_record-v1-3-6be1f36126fd@quicinc.com --- drivers/net/wireless/ath/ath11k/htc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h index cf6b9aa0784d..d5864a35e75b 100644 --- a/drivers/net/wireless/ath/ath11k/htc.h +++ b/drivers/net/wireless/ath/ath11k/htc.h @@ -153,7 +153,6 @@ struct ath11k_htc_record { struct ath11k_htc_record_hdr hdr; union { struct ath11k_htc_credit_report credit_report[0]; - u8 pauload[0]; }; } __packed __aligned(4); From 5082b3e3027eae393a4e86874bffb4ce3f83c26e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 17 Nov 2023 08:39:19 +0800 Subject: [PATCH 1995/7721] wifi: ath11k: fix race due to setting ATH11K_FLAG_EXT_IRQ_ENABLED too early We are seeing below error randomly in the case where only one MSI vector is configured: kernel: ath11k_pci 0000:03:00.0: wmi command 16387 timeout The reason is, currently, in ath11k_pcic_ext_irq_enable(), ATH11K_FLAG_EXT_IRQ_ENABLED is set before NAPI is enabled. This results in a race condition: after ATH11K_FLAG_EXT_IRQ_ENABLED is set but before NAPI enabled, CE interrupt breaks in. Since IRQ is shared by CE and data path, ath11k_pcic_ext_interrupt_handler() is also called where we call disable_irq_nosync() to disable IRQ. Then napi_schedule() is called but it does nothing because NAPI is not enabled at that time, meaning ath11k_pcic_ext_grp_napi_poll() will never run, so we have no chance to call enable_irq() to enable IRQ back. Finally we get above error. Fix it by setting ATH11K_FLAG_EXT_IRQ_ENABLED after all NAPI and IRQ work are done. With the fix, we are sure that by the time ATH11K_FLAG_EXT_IRQ_ENABLED is set, NAPI is enabled. Note that the fix above also introduce some side effects: if ath11k_pcic_ext_interrupt_handler() breaks in after NAPI enabled but before ATH11K_FLAG_EXT_IRQ_ENABLED set, nothing will be done by the handler this time, the work will be postponed till the next time the IRQ fires. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117003919.26218-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/pcic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 90d8936a3e2e..15e2ceb22a44 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -460,8 +460,6 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab) { int i; - set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); - for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -471,6 +469,8 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab) } ath11k_pcic_ext_grp_enable(irq_grp); } + + set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); } EXPORT_SYMBOL(ath11k_pcic_ext_irq_enable); From 62e31362033e900a231a119a02ddcef553f11b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:30:58 +0100 Subject: [PATCH 1996/7721] wifi: ath11k: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117093056.873834-9-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath11k/ahb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index f8f5e653cd03..7c0a23517949 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1251,7 +1251,7 @@ static void ath11k_ahb_free_resources(struct ath11k_base *ab) platform_set_drvdata(pdev, NULL); } -static int ath11k_ahb_remove(struct platform_device *pdev) +static void ath11k_ahb_remove(struct platform_device *pdev) { struct ath11k_base *ab = platform_get_drvdata(pdev); @@ -1267,8 +1267,6 @@ static int ath11k_ahb_remove(struct platform_device *pdev) qmi_fail: ath11k_ahb_free_resources(ab); - - return 0; } static void ath11k_ahb_shutdown(struct platform_device *pdev) @@ -1296,7 +1294,7 @@ static struct platform_driver ath11k_ahb_driver = { .of_match_table = ath11k_ahb_of_match, }, .probe = ath11k_ahb_probe, - .remove = ath11k_ahb_remove, + .remove_new = ath11k_ahb_remove, .shutdown = ath11k_ahb_shutdown, }; From f9893fdac319bb2817e5e7818870264d7fb2eb02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 30 Nov 2023 09:22:59 +0000 Subject: [PATCH 1997/7721] net: page_pool: fix general protection fault in page_pool_unlist syzbot was able to trigger a crash [1] in page_pool_unlist() page_pool_list() only inserts a page pool into a netdev page pool list if a netdev was set in params. Even if the kzalloc() call in page_pool_create happens to initialize pool->user.list, I chose to be more explicit in page_pool_list() adding one INIT_HLIST_NODE(). We could test in page_pool_unlist() if netdev was set, but since netdev can be changed to lo, it seems more robust to check if pool->user.list is hashed before calling hlist_del(). [1] Illegal XDP return value 4294946546 on prog (id 2) dev N/A, expect packet loss! general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] CPU: 0 PID: 5064 Comm: syz-executor391 Not tainted 6.7.0-rc2-syzkaller-00533-ga379972973a8 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/10/2023 RIP: 0010:__hlist_del include/linux/list.h:988 [inline] RIP: 0010:hlist_del include/linux/list.h:1002 [inline] RIP: 0010:page_pool_unlist+0xd1/0x170 net/core/page_pool_user.c:342 Code: df 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 90 00 00 00 4c 8b a3 f0 06 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 e2 48 c1 ea 03 <80> 3c 02 00 75 68 48 85 ed 49 89 2c 24 74 24 e8 1b ca 07 f9 48 8d RSP: 0018:ffffc900039ff768 EFLAGS: 00010246 RAX: dffffc0000000000 RBX: ffff88814ae02000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff88814ae026f0 RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff1d57fdc R10: ffffffff8eabfee3 R11: ffffffff8aa0008b R12: 0000000000000000 R13: ffff88814ae02000 R14: dffffc0000000000 R15: 0000000000000001 FS: 000055555717a380(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000002555398 CR3: 0000000025044000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __page_pool_destroy net/core/page_pool.c:851 [inline] page_pool_release+0x507/0x6b0 net/core/page_pool.c:891 page_pool_destroy+0x1ac/0x4c0 net/core/page_pool.c:956 xdp_test_run_teardown net/bpf/test_run.c:216 [inline] bpf_test_run_xdp_live+0x1578/0x1af0 net/bpf/test_run.c:388 bpf_prog_test_run_xdp+0x827/0x1530 net/bpf/test_run.c:1254 bpf_prog_test_run kernel/bpf/syscall.c:4041 [inline] __sys_bpf+0x11bf/0x4920 kernel/bpf/syscall.c:5402 __do_sys_bpf kernel/bpf/syscall.c:5488 [inline] __se_sys_bpf kernel/bpf/syscall.c:5486 [inline] __x64_sys_bpf+0x78/0xc0 kernel/bpf/syscall.c:5486 Fixes: 083772c9f972 ("net: page_pool: record pools per netdev") Reported-and-tested-by: syzbot+f9f8efb58a4db2ca98d0@syzkaller.appspotmail.com Signed-off-by: Eric Dumazet Tested-by: Andrew Lunn Link: https://lore.kernel.org/r/20231130092259.3797753-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/page_pool_user.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 1426434a7e15..ffe5244e5597 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -310,6 +310,7 @@ int page_pool_list(struct page_pool *pool) if (err < 0) goto err_unlock; + INIT_HLIST_NODE(&pool->user.list); if (pool->slow.netdev) { hlist_add_head(&pool->user.list, &pool->slow.netdev->page_pools); @@ -339,7 +340,8 @@ void page_pool_unlist(struct page_pool *pool) mutex_lock(&page_pools_lock); netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_DEL_NTF); xa_erase(&page_pools, pool->user.id); - hlist_del(&pool->user.list); + if (!hlist_unhashed(&pool->user.list)) + hlist_del(&pool->user.list); mutex_unlock(&page_pools_lock); } From cda398fcb488a89628033df90680c8d5f2fc6d0c Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 15 Nov 2023 09:00:17 +0800 Subject: [PATCH 1998/7721] wifi: rt2x00: Simplify bool conversion ./drivers/net/wireless/ralink/rt2x00/rt2800lib.c:1331:47-52: WARNING: conversion to bool not needed here ./drivers/net/wireless/ralink/rt2x00/rt2800lib.c:1332:47-52: WARNING: conversion to bool not needed here Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7531 Signed-off-by: Yang Li Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231115010017.112081-1-yang.lee@linux.alibaba.com --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 84b218adbaaf..485096e3be94 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1328,8 +1328,8 @@ static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev) else rt2x00dev->txdma_busy = 0; - busy_rx = rt2x00dev->rxdma_busy > 30 ? true : false; - busy_tx = rt2x00dev->txdma_busy > 30 ? true : false; + busy_rx = rt2x00dev->rxdma_busy > 30; + busy_tx = rt2x00dev->txdma_busy > 30; if (!busy_rx && !busy_tx) return false; From afb154426bf13a9d5cdc71f5d89d7416a6c2da10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:31:02 +0100 Subject: [PATCH 1999/7721] wifi: brcmfmac: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117093056.873834-13-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index a194b0e68eb5..b6d458e022fa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -578,18 +578,16 @@ static int __init brcmf_common_pd_probe(struct platform_device *pdev) return 0; } -static int brcmf_common_pd_remove(struct platform_device *pdev) +static void brcmf_common_pd_remove(struct platform_device *pdev) { brcmf_dbg(INFO, "Enter\n"); if (brcmfmac_pdata->power_off) brcmfmac_pdata->power_off(); - - return 0; } static struct platform_driver brcmf_pd = { - .remove = brcmf_common_pd_remove, + .remove_new = brcmf_common_pd_remove, .driver = { .name = BRCMFMAC_PDATA_NAME, } From 1da42060128469e0ff13ff2ff69d8db916b16c6a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 22 Nov 2023 14:14:29 +0800 Subject: [PATCH 2000/7721] wifi: rtw88: debug: remove wrapper of rtw_dbg() Remove unnecessary wrapper of rtw_dbg(), and just call it directly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122061429.34487-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/debug.c | 6 +++--- drivers/net/wireless/realtek/rtw88/debug.h | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 35bc37a3c469..1b2ad81838be 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -1314,8 +1314,8 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) #ifdef CONFIG_RTW88_DEBUG -void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, - const char *fmt, ...) +void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, + const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -1330,6 +1330,6 @@ void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, va_end(args); } -EXPORT_SYMBOL(__rtw_dbg); +EXPORT_SYMBOL(rtw_dbg); #endif /* CONFIG_RTW88_DEBUG */ diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index a03ced11bbe0..f20c0471c82a 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -43,10 +43,8 @@ static inline void rtw_debugfs_init(struct rtw_dev *rtwdev) {} #ifdef CONFIG_RTW88_DEBUG __printf(3, 4) -void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, - const char *fmt, ...); - -#define rtw_dbg(rtwdev, a...) __rtw_dbg(rtwdev, ##a) +void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, + const char *fmt, ...); static inline bool rtw_dbg_is_enabled(struct rtw_dev *rtwdev, enum rtw_debug_mask mask) From 18814f723f92826d83fef40e19fc8cb130367868 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 22 Nov 2023 09:30:47 +0100 Subject: [PATCH 2001/7721] wifi: libertas: fix config name in dependency for SDIO support Commit 4b478bf6bdd8 ("wifi: libertas: drop 16-bit PCMCIA support") reworks the dependencies for config LIBERTAS, and adds alternative dependencies for USB, SDIO and SPI. The config option SDIO however does not exist in the kernel tree. It was probably intended to refer to the config option MMC, which represents "MMC/SD/SDIO card support" and is used as dependency by various other drivers that use SDIO. Fix the dependency to the config option MMC for declaring the requirement on provision of SDIO support. Fixes: 4b478bf6bdd8 ("wifi: libertas: drop 16-bit PCMCIA support") Signed-off-by: Lukas Bulwahn Reviewed-by: Arnd Bergmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122083047.12774-1-lukas.bulwahn@gmail.com --- drivers/net/wireless/marvell/libertas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 56156a021be3..36b234bc5be8 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" - depends on USB || SDIO || SPI + depends on USB || MMC || SPI depends on CFG80211 select LIB80211 select FW_LOADER From ac586b8401c911df24019532a28b69a4257e53d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 11:09:18 +0200 Subject: [PATCH 2002/7721] bcma: Use PCI_HEADER_TYPE_MASK instead of literal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace literal 0x7f with PCI_HEADER_TYPE_MASK. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124090919.23687-6-ilpo.jarvinen@linux.intel.com --- drivers/bcma/driver_pci_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index aa0581cda718..ed3be52ab63d 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -280,7 +280,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev, /* check for Header type 0 */ bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val, sizeof(u8)); - if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL) + if ((byte_val & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) return cap_ptr; /* check if the capability pointer field exists */ From cda37445718d917c22fe1f2cf7ab1f501e6f84b2 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Mon, 27 Nov 2023 09:35:11 +0800 Subject: [PATCH 2003/7721] wifi: rtlwifi: rtl8821ae: phy: remove some useless code Clang static checker warns: Value stored to 'v1' is never read [deadcode.DeadStores] Value stored to 'channel' is never read [deadcode.DeadStores] Remove them to save some place. Signed-off-by: Su Hui Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231127013511.26694-1-suhui@nfschina.com --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 5323ead30db0..6df270e29e66 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -2038,15 +2038,9 @@ static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, /*don't need the hw_body*/ if (!_rtl8821ae_check_condition(hw, v1)) { i += 2; /* skip the pair of expression*/ - v1 = array[i]; v2 = array[i+1]; - v3 = array[i+2]; - while (v2 != 0xDEAD) { + while (v2 != 0xDEAD) i += 3; - v1 = array[i]; - v2 = array[i+1]; - v3 = array[i+2]; - } } } } @@ -3543,7 +3537,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &rtlpriv->phy; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u32 timeout = 1000, timecount = 0; - u8 channel = rtlphy->current_channel; if (rtlphy->sw_chnl_inprogress) return 0; @@ -3566,8 +3559,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw) rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G); rtlphy->sw_chnl_inprogress = true; - if (channel == 0) - channel = 1; rtl_dbg(rtlpriv, COMP_SCAN, DBG_TRACE, "switch to channel%d, band type is %d\n", From bc8263083af60e7e57c6120edbc1f75d6c909a35 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Mon, 27 Nov 2023 09:35:13 +0800 Subject: [PATCH 2004/7721] wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior Clang static checker warns: drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c:184:49: The result of the left shift is undefined due to shifting by '32', which is greater or equal to the width of type 'u32'. [core.UndefinedBinaryOperatorResult] If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.[1][2] For example, when using different gcc's compilation optimization options (-O0 or -O2), the result of '(u32)data << 32' is different. One is 0, the other is old value of data. Let _rtl8821ae_phy_calculate_bit_shift()'s return value less than 32 to fix this problem. Warn if bitmask is zero. [1] https://stackoverflow.com/questions/11270492/what-does-the-c-standard-say-about-bitshifting-more-bits-than-the-width-of-type [2] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf Fixes: 21e4b0726dc6 ("rtlwifi: rtl8821ae: Move driver from staging to regular tree") Signed-off-by: Su Hui Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231127013511.26694-2-suhui@nfschina.com --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 6df270e29e66..68c3fb0395ce 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -29,9 +29,10 @@ static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw, u32 data); static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask) { - u32 i = ffs(bitmask); + if (WARN_ON_ONCE(!bitmask)) + return 0; - return i ? i - 1 : 32; + return __ffs(bitmask); } static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw); /*static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);*/ From 77abbabaafe5d14ed033adb6969c54d42faf67f0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 22 Nov 2023 14:04:55 +0800 Subject: [PATCH 2005/7721] wifi: rtw89: debug: add to check if debug mask is enabled The coming dynamic mechanism of EDCCA adjustment will add a function to dump registers to reflect status. However, if we are not debugging the mechanism, we don't print anything, so avoid reading registers by checking debug mask to reduce IO. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122060458.30878-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index b663ee24555a..f18021f9046d 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -74,6 +74,12 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, print_hex_dump_bytes(prefix_str, DUMP_PREFIX_OFFSET, buf, len); } + +static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev, + enum rtw89_debug_mask mask) +{ + return !!(rtw89_debug_mask & mask); +} #else static inline void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, @@ -82,6 +88,11 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, const char *prefix_str, const void *buf, size_t len) {} +static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev, + enum rtw89_debug_mask mask) +{ + return false; +} #endif #endif From 0bb185257de6043857498d29fd5c7aae3acb1d45 Mon Sep 17 00:00:00 2001 From: Yi-Chen Chen Date: Wed, 22 Nov 2023 14:04:56 +0800 Subject: [PATCH 2006/7721] wifi: rtw89: phy: dynamically adjust EDCCA threshold Add dynamic mechanism EDCCA (Energy Detection Clear Channel Assessment) in track work. Using a fixed-value threshold will make EDCCA particularly sensitive and cause failure to transmit under certain circumstances. Therefore, the threshold is dynamically adjusted to make EDCCA suitable for any situation. However, in some cases, we will adjust the EDCCA threshold to the highest level so that urgent transmissions can be performed successfully, such as scanning. Finally, in order to observe the EDCCA report in time, add the EDCCA perIC register macro and EDCCA HW report analysis. EDCCA logs can be displayed by using the EDCCA debug mask. Signed-off-by: Yi-Chen Chen Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122060458.30878-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/core.h | 27 ++- drivers/net/wireless/realtek/rtw89/debug.h | 1 + drivers/net/wireless/realtek/rtw89/phy.c | 206 +++++++++++++++++- drivers/net/wireless/realtek/rtw89/phy.h | 9 + drivers/net/wireless/realtek/rtw89/reg.h | 39 +++- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 16 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 16 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 16 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 16 +- 10 files changed, 327 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 74bf29643823..7eb827ddc53a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3129,6 +3129,7 @@ static void rtw89_track_work(struct work_struct *work) rtw89_phy_tx_path_div_track(rtwdev); rtw89_phy_antdiv_track(rtwdev); rtw89_phy_ul_tb_ctrl_track(rtwdev); + rtw89_phy_edcca_track(rtwdev); rtw89_tas_track(rtwdev); rtw89_chanctx_track(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6948ffe0f206..00aa9e96541c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3590,6 +3590,22 @@ struct rtw89_dig_regs { struct rtw89_reg_def p1_s20_pagcugc_en; }; +struct rtw89_edcca_regs { + u32 edcca_level; + u32 edcca_mask; + u32 edcca_p_mask; + u32 ppdu_level; + u32 ppdu_mask; + u32 rpt_a; + u32 rpt_b; + u32 rpt_sel; + u32 rpt_sel_mask; + u32 rpt_sel_be; + u32 rpt_sel_be_mask; + u32 tx_collision_t2r_st; + u32 tx_collision_t2r_st_mask; +}; + struct rtw89_phy_ul_tb_info { bool dyn_tb_tri_en; u8 def_if_bandedge; @@ -3741,7 +3757,7 @@ struct rtw89_chip_info { struct rtw89_reg_def bss_clr_vld; u32 bss_clr_map_reg; u32 dma_ch_mask; - u32 edcca_lvl_reg; + const struct rtw89_edcca_regs *edcca_regs; const struct wiphy_wowlan_support *wowlan_stub; const struct rtw89_xtal_info *xtal_info; }; @@ -4010,6 +4026,13 @@ struct rtw89_sub_entity { struct rtw89_chanctx_cfg *cfg; }; +struct rtw89_edcca_bak { + u8 a; + u8 p; + u8 ppdu; + u8 th_old; +}; + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -4034,7 +4057,7 @@ struct rtw89_hal { bool entity_pause; enum rtw89_entity_mode entity_mode; - u32 edcca_bak; + struct rtw89_edcca_bak edcca_bak; }; #define RTW89_MAX_MAC_ID_NUM 128 diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index f18021f9046d..a4cdc3c8c622 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -30,6 +30,7 @@ enum rtw89_debug_mask { RTW89_DBG_UL_TB = BIT(19), RTW89_DBG_CHAN = BIT(20), RTW89_DBG_ACPI = BIT(21), + RTW89_DBG_EDCCA = BIT(22), RTW89_DBG_UNEXP = BIT(31), }; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 17ccc9efed28..3d5bd888218e 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -4620,6 +4620,29 @@ static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev) rtw89_phy_ifs_clm_setting_init(rtwdev); } +static void rtw89_phy_edcca_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; + + memset(edcca_bak, 0, sizeof(*edcca_bak)); + + if (rtwdev->chip->chip_id == RTL8922A && rtwdev->hal.cv == CHIP_CAV) { + rtw89_phy_set_phy_regs(rtwdev, R_TXGATING, B_TXGATING_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_VAL, 2); + rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_ON, 1); + rtw89_phy_set_phy_regs(rtwdev, R_SPOOF_CG, B_SPOOF_CG_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_CG_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 1); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 1); + } + + rtw89_phy_write32_mask(rtwdev, edcca_regs->tx_collision_t2r_st, + edcca_regs->tx_collision_t2r_st_mask, 0x29); +} + void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) { rtw89_phy_stat_init(rtwdev); @@ -4630,6 +4653,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); + rtw89_phy_edcca_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); rtw89_chip_rfe_gpio(rtwdev); @@ -4892,25 +4916,185 @@ void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, } EXPORT_SYMBOL(rtw89_decode_chan_idx); -#define EDCCA_DEFAULT 249 void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan) { - u32 reg = rtwdev->chip->edcca_lvl_reg; - struct rtw89_hal *hal = &rtwdev->hal; - u32 val; + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; if (scan) { - hal->edcca_bak = rtw89_phy_read32(rtwdev, reg); - val = hal->edcca_bak; - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK); - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK); - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK); - rtw89_phy_write32(rtwdev, reg, val); + edcca_bak->a = + rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask); + edcca_bak->p = + rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask); + edcca_bak->ppdu = + rtw89_phy_read32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, EDCCA_MAX); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, EDCCA_MAX); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, EDCCA_MAX); } else { - rtw89_phy_write32(rtwdev, reg, hal->edcca_bak); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, + edcca_bak->a); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, + edcca_bak->p); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, + edcca_bak->ppdu); } } +static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80; + s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80; + u8 path, per20_bitmap; + u8 pwdb[8]; + u32 tmp; + + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_EDCCA)) + return; + + if (rtwdev->chip->chip_id == RTL8922A) + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 0); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 0); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + path = u32_get_bits(tmp, B_EDCCA_RPT_B_PATH_MASK); + flag_s80 = u32_get_bits(tmp, B_EDCCA_RPT_B_S80); + flag_s40 = u32_get_bits(tmp, B_EDCCA_RPT_B_S40); + flag_s20 = u32_get_bits(tmp, B_EDCCA_RPT_B_S20); + flag_p20 = u32_get_bits(tmp, B_EDCCA_RPT_B_P20); + flag_fb = u32_get_bits(tmp, B_EDCCA_RPT_B_FB); + pwdb_s20 = u32_get_bits(tmp, MASKBYTE1); + pwdb_p20 = u32_get_bits(tmp, MASKBYTE2); + pwdb_fb = u32_get_bits(tmp, MASKBYTE3); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 4); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb_s80 = u32_get_bits(tmp, MASKBYTE1); + pwdb_s40 = u32_get_bits(tmp, MASKBYTE2); + + per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_regs->rpt_a, + MASKBYTE0); + + if (rtwdev->chip->chip_id == RTL8922A) { + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 4); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb[0] = u32_get_bits(tmp, MASKBYTE3); + pwdb[1] = u32_get_bits(tmp, MASKBYTE2); + pwdb[2] = u32_get_bits(tmp, MASKBYTE1); + pwdb[3] = u32_get_bits(tmp, MASKBYTE0); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 5); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb[4] = u32_get_bits(tmp, MASKBYTE3); + pwdb[5] = u32_get_bits(tmp, MASKBYTE2); + pwdb[6] = u32_get_bits(tmp, MASKBYTE1); + pwdb[7] = u32_get_bits(tmp, MASKBYTE0); + } else { + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 0); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[0] = u32_get_bits(tmp, MASKBYTE3); + pwdb[1] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 1); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[2] = u32_get_bits(tmp, MASKBYTE3); + pwdb[3] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 2); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[4] = u32_get_bits(tmp, MASKBYTE3); + pwdb[5] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 3); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[6] = u32_get_bits(tmp, MASKBYTE3); + pwdb[7] = u32_get_bits(tmp, MASKBYTE2); + } + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: edcca_bitmap = %04x\n", per20_bitmap); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: pwdb per20{0,1,2,3,4,5,6,7} = {%d,%d,%d,%d,%d,%d,%d,%d}(dBm)\n", + pwdb[0], pwdb[1], pwdb[2], pwdb[3], pwdb[4], pwdb[5], + pwdb[6], pwdb[7]); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: path=%d, flag {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}\n", + path, flag_fb, flag_p20, flag_s20, flag_s40, flag_s80); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: pwdb {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}(dBm)\n", + pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80); +} + +static u8 rtw89_phy_edcca_get_thre_by_rssi(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info; + bool is_linked = rtwdev->total_sta_assoc > 0; + u8 rssi_min = ch_info->rssi_min >> 1; + u8 edcca_thre; + + if (!is_linked) { + edcca_thre = EDCCA_MAX; + } else { + edcca_thre = rssi_min - RSSI_UNIT_CONVER + EDCCA_UNIT_CONVER - + EDCCA_TH_REF; + edcca_thre = max_t(u8, edcca_thre, EDCCA_TH_L2H_LB); + } + + return edcca_thre; +} + +void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; + u8 th; + + th = rtw89_phy_edcca_get_thre_by_rssi(rtwdev); + if (th == edcca_bak->th_old) + return; + + edcca_bak->th_old = th; + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: Normal Mode, EDCCA_th = %d\n", th); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, th); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, th); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, th); +} + +void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev) +{ + rtw89_phy_edcca_thre_calc(rtwdev); + rtw89_phy_edcca_log(rtwdev); +} + static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = { .setting_addr = R_CCX, .edcca_opt_mask = B_CCX_EDCCA_OPT_MSK, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 2d9cf5c02b92..d6363defcde6 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -122,6 +122,13 @@ #define PHYSTS_RSVD BIT(RTW89_RX_TYPE_RSVD) #define PPDU_FILTER_BITMAP (PHYSTS_MGNT | PHYSTS_DATA) +#define EDCCA_MAX 249 +#define EDCCA_TH_L2H_LB 66 +#define EDCCA_TH_REF 3 +#define EDCCA_HL_DIFF_NORMAL 8 +#define RSSI_UNIT_CONVER 110 +#define EDCCA_UNIT_CONVER 128 + enum rtw89_phy_c2h_ra_func { RTW89_PHY_C2H_FUNC_STS_RPT, RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT, @@ -807,5 +814,7 @@ u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band); void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, u8 *ch, enum nl80211_band *band); void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan); +void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev); +void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 7a9ae6cd86e5..197fbb40922c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4727,6 +4727,11 @@ #define B_P0_RSTB_WATCH_DOG BIT(0) #define B_P1_RSTB_WATCH_DOG BIT(1) #define B_UPD_P0_EN BIT(31) +#define R_SPOOF_CG 0x00B4 +#define B_SPOOF_CG_EN BIT(17) +#define R_DFS_FFT_CG 0x00B8 +#define B_DFS_CG_EN BIT(1) +#define B_DFS_FFT_EN BIT(0) #define R_ANAPAR_PW15 0x030C #define B_ANAPAR_PW15 GENMASK(31, 24) #define B_ANAPAR_PW15_H GENMASK(27, 24) @@ -4789,6 +4794,8 @@ #define R_PHY_STS_BITMAP_HT 0x076C #define R_PHY_STS_BITMAP_VHT 0x0770 #define R_PHY_STS_BITMAP_HE 0x0774 +#define R_EDCCA_RPTREG_SEL_BE 0x078C +#define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20) #define R_PMAC_GNT 0x0980 #define B_PMAC_GNT_TXEN BIT(0) #define B_PMAC_GNT_RXEN BIT(16) @@ -4848,12 +4855,18 @@ #define B_IOQ_IQK_DPK_EN BIT(1) #define R_GNT_BT_WGT_EN 0x0C6C #define B_GNT_BT_WGT_EN BIT(21) +#define R_TX_COLLISION_T2R_ST 0x0C70 +#define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20) +#define R_TXGATING 0x0C74 +#define B_TXGATING_EN BIT(4) #define R_PD_ARBITER_OFF 0x0C80 #define B_PD_ARBITER_OFF BIT(31) #define R_SNDCCA_A1 0x0C9C #define B_SNDCCA_A1_EN GENMASK(19, 12) #define R_SNDCCA_A2 0x0CA0 #define B_SNDCCA_A2_VAL GENMASK(19, 12) +#define R_TX_COLLISION_T2R_ST_BE 0x0CC8 +#define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8) #define R_RXHT_MCS_LIMIT 0x0D18 #define B_RXHT_MCS_LIMIT GENMASK(9, 8) #define R_RXVHT_MCS_LIMIT 0x0D18 @@ -4872,6 +4885,10 @@ #define R_BRK_ASYNC_RST_EN_1 0x0DC0 #define R_BRK_ASYNC_RST_EN_2 0x0DC4 #define R_BRK_ASYNC_RST_EN_3 0x0DC8 +#define R_CTLTOP 0x1008 +#define B_CTLTOP_ON BIT(23) +#define B_CTLTOP_VAL GENMASK(15, 12) +#define R_EDCCA_RPT_SEL_BE 0x10CC #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P0_RXCK 0x12A0 @@ -4903,6 +4920,14 @@ #define R_CFO_COMP_SEG0_H 0x1388 #define R_CFO_COMP_SEG0_CTRL 0x138C #define R_DBG32_D 0x1730 +#define R_EDCCA_RPT_A 0x1738 +#define R_EDCCA_RPT_B 0x173c +#define B_EDCCA_RPT_B_FB BIT(7) +#define B_EDCCA_RPT_B_P20 BIT(6) +#define B_EDCCA_RPT_B_S20 BIT(5) +#define B_EDCCA_RPT_B_S40 BIT(4) +#define B_EDCCA_RPT_B_S80 BIT(3) +#define B_EDCCA_RPT_B_PATH_MASK GENMASK(2, 1) #define R_SWSI_V1 0x174C #define B_SWSI_W_BUSY_V1 BIT(24) #define B_SWSI_R_BUSY_V1 BIT(25) @@ -4964,6 +4989,8 @@ #define R_S0_ADDCK 0x1E00 #define B_S0_ADDCK_I GENMASK(9, 0) #define B_S0_ADDCK_Q GENMASK(19, 10) +#define R_EDCCA_RPT_SEL 0x20CC +#define B_EDCCA_RPT_SEL_MSK GENMASK(2, 0) #define R_ADC_FIFO 0x20fc #define B_ADC_FIFO_RST GENMASK(31, 24) #define B_ADC_FIFO_RXK GENMASK(31, 16) @@ -5010,6 +5037,8 @@ #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0) #define R_P1_EN_SOUND_WO_NDP 0x2D7C #define B_P1_EN_SOUND_WO_NDP BIT(1) +#define R_EDCCA_RPT_A_BE 0x2E38 +#define R_EDCCA_RPT_B_BE 0x2E3C #define R_S1_HW_SI_DIS 0x3200 #define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P1_RXCK 0x32A0 @@ -5218,9 +5247,9 @@ #define R_SEG0R_PD_V2 0x6A74 #define R_SEG0R_EDCCA_LVL 0x4840 #define R_SEG0R_EDCCA_LVL_V1 0x4884 -#define B_SEG0R_PPDU_LVL_MSK GENMASK(31, 24) -#define B_SEG0R_EDCCA_LVL_P_MSK GENMASK(15, 8) -#define B_SEG0R_EDCCA_LVL_A_MSK GENMASK(7, 0) +#define B_EDCCA_LVL_MSK3 GENMASK(31, 24) +#define B_EDCCA_LVL_MSK1 GENMASK(15, 8) +#define B_EDCCA_LVL_MSK0 GENMASK(7, 0) #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30) #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK BIT(29) #define B_SEG0R_PD_LOWER_BOUND_MSK GENMASK(10, 6) @@ -5476,6 +5505,10 @@ #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28) #define R_DCFO_OPT_V1 0x6260 #define B_DCFO_OPT_EN_V1 BIT(17) +#define R_SEG0R_EDCCA_LVL_BE 0x69EC +#define R_SEG0R_PPDU_LVL_BE 0x69F0 +#define R_SEGSND 0x6A14 +#define B_SEGSND_EN BIT(31) #define R_RPL_BIAS_COMP1 0x6DF0 #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0) #define R_P1_TSSI_ALIM1 0x7630 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index dd15b904cd2f..ed1f0560a514 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -205,6 +205,20 @@ static const struct rtw89_dig_regs rtw8851b_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8851b_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_V1, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL_V1, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = { {255, 0, 0, 7}, /* 0 -> original */ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ @@ -2446,7 +2460,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, + .edcca_regs = &rtw8851b_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8851b, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 2bddd0acb195..561049d17854 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -498,6 +498,20 @@ static const struct rtw89_dig_regs rtw8852a_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852a_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static void rtw8852ae_efuse_parsing(struct rtw89_efuse *efuse, struct rtw8852a_efuse *map) { @@ -2181,7 +2195,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL, + .edcca_regs = &rtw8852a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index a576e4f47880..9c62844cf06b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -330,6 +330,20 @@ static const struct rtw89_dig_regs rtw8852b_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852b_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_V1, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL_V1, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_ul[] = { {255, 0, 0, 7}, /* 0 -> original */ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ @@ -2617,7 +2631,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, + .edcca_regs = &rtw8852b_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852b, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index ea152a4613f2..976d34b33377 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -167,6 +167,20 @@ static const struct rtw89_dig_regs rtw8852c_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852c_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static void rtw8852c_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, enum rtw89_phy_idx phy_idx); @@ -2954,7 +2968,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL, + .edcca_regs = &rtw8852c_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, #endif From d371c3aa35fd2dc8d77d4be6db2e3d573f4a9704 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 22 Nov 2023 14:04:57 +0800 Subject: [PATCH 2007/7721] wifi: rtw89: debug: add debugfs entry to disable dynamic mechanism A dynamic mechanism is usually an algorithm to adjust registers to adapt to different environment every two seconds. In field, it could get unexpected result, so we need to stop it and adjust registers manually, and then fine tune the algorithm. To stop mechanisms to assist debugging, add a debugfs entry shown as Disabled DM: 0x1 [0] DYNAMIC_EDCCA: X Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122060458.30878-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 5 ++ drivers/net/wireless/realtek/rtw89/debug.c | 58 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.c | 5 ++ 3 files changed, 68 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 00aa9e96541c..c9f054c0f6fb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4033,6 +4033,10 @@ struct rtw89_edcca_bak { u8 th_old; }; +enum rtw89_dm_type { + RTW89_DM_DYNAMIC_EDCCA, +}; + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -4058,6 +4062,7 @@ struct rtw89_hal { enum rtw89_entity_mode entity_mode; struct rtw89_edcca_bak edcca_bak; + u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ }; #define RTW89_MAX_MAC_ID_NUM 128 diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index a3f795d240ea..f914c0750576 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3770,6 +3770,58 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) return 0; } +#define DM_INFO(type) {RTW89_DM_ ## type, #type} + +static const struct rtw89_disabled_dm_info { + enum rtw89_dm_type type; + const char *name; +} rtw89_disabled_dm_infos[] = { + DM_INFO(DYNAMIC_EDCCA), +}; + +static int +rtw89_debug_priv_disable_dm_get(struct seq_file *m, void *v) +{ + struct rtw89_debugfs_priv *debugfs_priv = m->private; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + const struct rtw89_disabled_dm_info *info; + struct rtw89_hal *hal = &rtwdev->hal; + u32 disabled; + int i; + + seq_printf(m, "Disabled DM: 0x%x\n", hal->disabled_dm_bitmap); + + for (i = 0; i < ARRAY_SIZE(rtw89_disabled_dm_infos); i++) { + info = &rtw89_disabled_dm_infos[i]; + disabled = BIT(info->type) & hal->disabled_dm_bitmap; + + seq_printf(m, "[%d] %s: %c\n", info->type, info->name, + disabled ? 'X' : 'O'); + } + + return 0; +} + +static ssize_t +rtw89_debug_priv_disable_dm_set(struct file *filp, const char __user *user_buf, + size_t count, loff_t *loff) +{ + struct seq_file *m = (struct seq_file *)filp->private_data; + struct rtw89_debugfs_priv *debugfs_priv = m->private; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw89_hal *hal = &rtwdev->hal; + u32 conf; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, &conf); + if (ret) + return -EINVAL; + + hal->disabled_dm_bitmap = conf; + + return count; +} + static struct rtw89_debugfs_priv rtw89_debug_priv_read_reg = { .cb_read = rtw89_debug_priv_read_reg_get, .cb_write = rtw89_debug_priv_read_reg_select, @@ -3845,6 +3897,11 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_stations = { .cb_read = rtw89_debug_priv_stations_get, }; +static struct rtw89_debugfs_priv rtw89_debug_priv_disable_dm = { + .cb_read = rtw89_debug_priv_disable_dm_get, + .cb_write = rtw89_debug_priv_disable_dm_set, +}; + #define rtw89_debugfs_add(name, mode, fopname, parent) \ do { \ rtw89_debug_priv_ ##name.rtwdev = rtwdev; \ @@ -3885,6 +3942,7 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev) rtw89_debugfs_add_w(fw_log_manual); rtw89_debugfs_add_r(phy_info); rtw89_debugfs_add_r(stations); + rtw89_debugfs_add_rw(disable_dm); } #endif diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 3d5bd888218e..bfb1d8cfc531 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -5091,6 +5091,11 @@ void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev) void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev) { + struct rtw89_hal *hal = &rtwdev->hal; + + if (hal->disabled_dm_bitmap & BIT(RTW89_DM_DYNAMIC_EDCCA)) + return; + rtw89_phy_edcca_thre_calc(rtwdev); rtw89_phy_edcca_log(rtwdev); } From 9f4dee32b783955f35b74609241db76f625f2ec3 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 22 Nov 2023 14:04:58 +0800 Subject: [PATCH 2008/7721] wifi: rtw89: debug: remove wrapper of rtw89_debug() The wrapper of rtw89_debug() is unnecessary, so just remove it. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231122060458.30878-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 7 +++---- drivers/net/wireless/realtek/rtw89/debug.h | 6 ++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index f914c0750576..9780af8e296d 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3947,9 +3947,8 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev) #endif #ifdef CONFIG_RTW89_DEBUGMSG -void __rtw89_debug(struct rtw89_dev *rtwdev, - enum rtw89_debug_mask mask, - const char *fmt, ...) +void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, + const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -3965,5 +3964,5 @@ void __rtw89_debug(struct rtw89_dev *rtwdev, va_end(args); } -EXPORT_SYMBOL(__rtw89_debug); +EXPORT_SYMBOL(rtw89_debug); #endif diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index a4cdc3c8c622..800ea59873a1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -59,12 +59,10 @@ static inline void rtw89_debugfs_init(struct rtw89_dev *rtwdev) {} #ifdef CONFIG_RTW89_DEBUGMSG extern unsigned int rtw89_debug_mask; -#define rtw89_debug(rtwdev, a...) __rtw89_debug(rtwdev, ##a) __printf(3, 4) -void __rtw89_debug(struct rtw89_dev *rtwdev, - enum rtw89_debug_mask mask, - const char *fmt, ...); +void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, + const char *fmt, ...); static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, const char *prefix_str, From cb6d2fd30dddd00499333e9475f8b11bbd84f37c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 14 Nov 2023 09:54:18 -0800 Subject: [PATCH 2009/7721] SUNRPC: Replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated[1]. Additionally, it returns the size of the source string, not the resulting size of the destination string. In an effort to remove strlcpy() completely[2], replace strlcpy() here with strscpy(). Explicitly handle the truncation case by returning the size of the resulting string. If "nodename" was ever longer than sizeof(clnt->cl_nodename) - 1, this change will fix a bug where clnt->cl_nodelen would end up thinking there were more characters in clnt->cl_nodename than there actually were, which might have lead to kernel memory content exposures. Cc: Trond Myklebust Cc: Anna Schumaker Cc: Chuck Lever Cc: Jeff Layton Cc: Neil Brown Cc: Olga Kornievskaia Cc: Dai Ngo Cc: Tom Talpey Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: linux-nfs@vger.kernel.org Cc: netdev@vger.kernel.org Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1] Link: https://github.com/KSPP/linux/issues/89 [2] Co-developed-by: Azeem Shaikh Signed-off-by: Azeem Shaikh Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20231114175407.work.410-kees@kernel.org Signed-off-by: Kees Cook --- net/sunrpc/clnt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index daa9582ec861..7afe02bdea4a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -287,8 +287,14 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) { - clnt->cl_nodelen = strlcpy(clnt->cl_nodename, - nodename, sizeof(clnt->cl_nodename)); + ssize_t copied; + + copied = strscpy(clnt->cl_nodename, + nodename, sizeof(clnt->cl_nodename)); + + clnt->cl_nodelen = copied < 0 + ? sizeof(clnt->cl_nodename) - 1 + : copied; } static int rpc_client_register(struct rpc_clnt *clnt, From 40b2519d7566266d7eafd3c5232c73a497640bca Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 16 Nov 2023 11:15:10 -0800 Subject: [PATCH 2010/7721] samples: Replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated[1]. Additionally, it returns the size of the source string, not the resulting size of the destination string. In an effort to remove strlcpy() completely[2], replace strlcpy() here with strscpy(). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1] Link: https://github.com/KSPP/linux/issues/89 [2] Cc: Masami Hiramatsu Cc: Valentin Schneider Cc: "Steven Rostedt (Google)" Cc: Chuck Lever Cc: Geliang Tang Cc: Greg Kroah-Hartman Cc: Christophe JAILLET Cc: Thomas Gleixner Cc: Arnd Bergmann Acked-by: "Steven Rostedt (Google)" Link: https://lore.kernel.org/r/20231116191510.work.550-kees@kernel.org Signed-off-by: Kees Cook --- samples/trace_events/trace-events-sample.h | 2 +- samples/v4l/v4l2-pci-skeleton.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h index 1c6b843b8c4e..23f923ccd529 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h @@ -305,7 +305,7 @@ TRACE_EVENT(foo_bar, ), TP_fast_assign( - strlcpy(__entry->foo, foo, 10); + strscpy(__entry->foo, foo, 10); __entry->bar = bar; memcpy(__get_dynamic_array(list), lst, __length_of(lst) * sizeof(int)); diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index a61f94db18d9..69ef788d9e3b 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -291,8 +291,8 @@ static int skeleton_querycap(struct file *file, void *priv, { struct skeleton *skel = video_drvdata(file); - strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); - strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(skel->pdev)); return 0; @@ -597,11 +597,11 @@ static int skeleton_enum_input(struct file *file, void *priv, i->type = V4L2_INPUT_TYPE_CAMERA; if (i->index == 0) { i->std = SKEL_TVNORMS; - strlcpy(i->name, "S-Video", sizeof(i->name)); + strscpy(i->name, "S-Video", sizeof(i->name)); i->capabilities = V4L2_IN_CAP_STD; } else { i->std = 0; - strlcpy(i->name, "HDMI", sizeof(i->name)); + strscpy(i->name, "HDMI", sizeof(i->name)); i->capabilities = V4L2_IN_CAP_DV_TIMINGS; } return 0; @@ -845,7 +845,7 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Initialize the video_device structure */ vdev = &skel->vdev; - strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); + strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); /* * There is nothing to clean up, so release is set to an empty release * function. The release callback must be non-NULL. From c3f17d5f89fc72d7b170beaf393a8687ae938b19 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 29 Nov 2023 12:27:48 +0530 Subject: [PATCH 2011/7721] firmware: arm_scmi: Increase the maximum opp count in the perf protocol The number of opps on certain variants of the X1E80100 SoC are greater than current maximum of 16, so increase the MAX_OPP count to 32 (next power of 2) to accommodate that. Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20231129065748.19871-4-quic_sibis@quicinc.com Reviewed-by: Cristian Marussi Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index a648521e04a3..81dd5c5e5533 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -24,7 +24,7 @@ #include "protocols.h" #include "notify.h" -#define MAX_OPPS 16 +#define MAX_OPPS 32 enum scmi_performance_protocol_cmd { PERF_DOMAIN_ATTRIBUTES = 0x3, From d4011f6817ae85e42874af705fec866fec7c4ecf Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 3 Oct 2023 21:01:58 +0000 Subject: [PATCH 2012/7721] HID: uhid: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Furthermore, let's make sure `hid->xyz` and `ev->u.create2.xyz` are the same size at compile time to prevent silent truncation. With these changes, it is abundantly clear what the intent and behavior of the code is -- We are getting a string to string copy with NUL-termination and no truncation. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Cc: Kees Cook Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231003-strncpy-drivers-hid-uhid-c-v2-1-6a501402581e@google.com Signed-off-by: Kees Cook --- drivers/hid/uhid.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 4588d2cd4ea4..a54c7995b9be 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -490,7 +490,7 @@ static int uhid_dev_create2(struct uhid_device *uhid, const struct uhid_event *ev) { struct hid_device *hid; - size_t rd_size, len; + size_t rd_size; void *rd_data; int ret; @@ -514,13 +514,12 @@ static int uhid_dev_create2(struct uhid_device *uhid, goto err_free; } - /* @hid is zero-initialized, strncpy() is correct, strlcpy() not */ - len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1; - strncpy(hid->name, ev->u.create2.name, len); - len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1; - strncpy(hid->phys, ev->u.create2.phys, len); - len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1; - strncpy(hid->uniq, ev->u.create2.uniq, len); + BUILD_BUG_ON(sizeof(hid->name) != sizeof(ev->u.create2.name)); + strscpy(hid->name, ev->u.create2.name, sizeof(hid->name)); + BUILD_BUG_ON(sizeof(hid->phys) != sizeof(ev->u.create2.phys)); + strscpy(hid->phys, ev->u.create2.phys, sizeof(hid->phys)); + BUILD_BUG_ON(sizeof(hid->uniq) != sizeof(ev->u.create2.uniq)); + strscpy(hid->uniq, ev->u.create2.uniq, sizeof(hid->uniq)); hid->ll_driver = &uhid_hid_driver; hid->bus = ev->u.create2.bus; From da2e08d4630ab04ee5b61515fe423c582b5c3be2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Oct 2023 16:18:38 -0700 Subject: [PATCH 2013/7721] i40e: Annotate struct i40e_qvlist_info with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct i40e_qvlist_info. Cc: Tony Nguyen Cc: Shiraz Saleem Cc: Jakub Kicinski Cc: Jesse Brandeburg Cc: Gurucharan G Cc: "Gustavo A. R. Silva" Link: https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci [1] Reviewed-by: "Gustavo A. R. Silva" Link: https://lore.kernel.org/r/20231003231838.work.510-kees@kernel.org Signed-off-by: Kees Cook --- include/linux/net/intel/i40e_client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/net/intel/i40e_client.h b/include/linux/net/intel/i40e_client.h index ed42bd5f639f..0aa4411528fc 100644 --- a/include/linux/net/intel/i40e_client.h +++ b/include/linux/net/intel/i40e_client.h @@ -45,7 +45,7 @@ struct i40e_qv_info { struct i40e_qvlist_info { u32 num_vectors; - struct i40e_qv_info qv_info[]; + struct i40e_qv_info qv_info[] __counted_by(num_vectors); }; From b7d2a4da38fb558832b70c6f45929649a9d114a3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 13 Nov 2023 17:00:15 -0800 Subject: [PATCH 2014/7721] drm/i915/guc: Fix for potential false positives in GuC hang selftest Noticed that the hangcheck selftest is submitting a non-preemptoble spinner. That means that even if the GuC does not die, the heartbeat will still kick in and trigger a reset. Which is rather defeating the purpose of the test - to verify that the heartbeat will kick in if the GuC itself has died. The test is deliberately killing the GuC, so it should never hit the case of a non-dead GuC. But it is not impossible that the kill might fail at some future point due to other driver re-work. So, make the spinner pre-emptible. That way the heartbeat can get through if the GuC is alive and context switching. Thus a reset only happens if the GuC dies. Thus, if the kill should stop working the test will now fail rather than claim to pass. Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20231114010016.234570-2-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c index 34b5d952e2bc..26fdc392fce6 100644 --- a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c @@ -74,7 +74,7 @@ static int intel_hang_guc(void *arg) goto err; } - rq = igt_spinner_create_request(&spin, ce, MI_NOOP); + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); intel_context_put(ce); if (IS_ERR(rq)) { ret = PTR_ERR(rq); From 706785c19fe92186815bdb9ae0148c4ba7262669 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 13 Nov 2023 17:00:16 -0800 Subject: [PATCH 2015/7721] drm/i915/guc: Add a selftest for FAST_REQUEST errors There is a mechanism for reporting errors from fire and forget H2G messages. This is the only way to find out about almost any error in the GuC backend submission path. So it would be useful to know that it is working. v2: Fix some dumb over-complications and a couple of typos - review feedback from Daniele. Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20231114010016.234570-3-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 4 + drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 9 ++ drivers/gpu/drm/i915/gt/uc/selftest_guc.c | 115 ++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 2b6dfe62c8f2..e22c12ce245a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -297,6 +297,10 @@ struct intel_guc { * @number_guc_id_stolen: The number of guc_ids that have been stolen */ int number_guc_id_stolen; + /** + * @fast_response_selftest: Backdoor to CT handler for fast response selftest + */ + u32 fast_response_selftest; #endif }; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 89e314b3756b..ed6ce73ef3b0 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -1076,6 +1076,15 @@ static int ct_handle_response(struct intel_guc_ct *ct, struct ct_incoming_msg *r found = true; break; } + +#ifdef CONFIG_DRM_I915_SELFTEST + if (!found && ct_to_guc(ct)->fast_response_selftest) { + CT_DEBUG(ct, "Assuming unsolicited response due to FAST_REQUEST selftest\n"); + ct_to_guc(ct)->fast_response_selftest++; + found = true; + } +#endif + if (!found) { CT_ERROR(ct, "Unsolicited response message: len %u, data %#x (fence %u, last %u)\n", len, hxg[0], fence, ct->requests.last_fence); diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c index bfb72143566f..c900aac85adb 100644 --- a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c @@ -286,11 +286,126 @@ static int intel_guc_steal_guc_ids(void *arg) return ret; } +/* + * Send a context schedule H2G message with an invalid context id. + * This should generate a GUC_RESULT_INVALID_CONTEXT response. + */ +static int bad_h2g(struct intel_guc *guc) +{ + u32 action[] = { + INTEL_GUC_ACTION_SCHED_CONTEXT, + 0x12345678, + }; + + return intel_guc_send_nb(guc, action, ARRAY_SIZE(action), 0); +} + +/* + * Set a spinner running to make sure the system is alive and active, + * then send a bad but asynchronous H2G command and wait to see if an + * error response is returned. If no response is received or if the + * spinner dies then the test will fail. + */ +#define FAST_RESPONSE_TIMEOUT_MS 1000 +static int intel_guc_fast_request(void *arg) +{ + struct intel_gt *gt = arg; + struct intel_context *ce; + struct igt_spinner spin; + struct i915_request *rq; + intel_wakeref_t wakeref; + struct intel_engine_cs *engine = intel_selftest_find_any_engine(gt); + bool spinning = false; + int ret = 0; + + if (!engine) + return 0; + + wakeref = intel_runtime_pm_get(gt->uncore->rpm); + + ce = intel_context_create(engine); + if (IS_ERR(ce)) { + ret = PTR_ERR(ce); + gt_err(gt, "Failed to create spinner request: %pe\n", ce); + goto err_pm; + } + + ret = igt_spinner_init(&spin, engine->gt); + if (ret) { + gt_err(gt, "Failed to create spinner: %pe\n", ERR_PTR(ret)); + goto err_pm; + } + spinning = true; + + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); + intel_context_put(ce); + if (IS_ERR(rq)) { + ret = PTR_ERR(rq); + gt_err(gt, "Failed to create spinner request: %pe\n", rq); + goto err_spin; + } + + ret = request_add_spin(rq, &spin); + if (ret) { + gt_err(gt, "Failed to add Spinner request: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + gt->uc.guc.fast_response_selftest = 1; + + ret = bad_h2g(>->uc.guc); + if (ret) { + gt_err(gt, "Failed to send H2G: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + ret = wait_for(gt->uc.guc.fast_response_selftest != 1 || i915_request_completed(rq), + FAST_RESPONSE_TIMEOUT_MS); + if (ret) { + gt_err(gt, "Request wait failed: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + if (i915_request_completed(rq)) { + gt_err(gt, "Spinner died waiting for fast request error!\n"); + ret = -EIO; + goto err_rq; + } + + if (gt->uc.guc.fast_response_selftest != 2) { + gt_err(gt, "Unexpected fast response count: %d\n", + gt->uc.guc.fast_response_selftest); + goto err_rq; + } + + igt_spinner_end(&spin); + spinning = false; + + ret = intel_selftest_wait_for_rq(rq); + if (ret) { + gt_err(gt, "Request failed to complete: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + +err_rq: + i915_request_put(rq); + +err_spin: + if (spinning) + igt_spinner_end(&spin); + igt_spinner_fini(&spin); + +err_pm: + intel_runtime_pm_put(gt->uncore->rpm, wakeref); + return ret; +} + int intel_guc_live_selftests(struct drm_i915_private *i915) { static const struct i915_subtest tests[] = { SUBTEST(intel_guc_scrub_ctbs), SUBTEST(intel_guc_steal_guc_ids), + SUBTEST(intel_guc_fast_request), }; struct intel_gt *gt = to_gt(i915); From 04fcc3fec5dbd316b0b1fb2b9f8a39bfbe07af50 Mon Sep 17 00:00:00 2001 From: ZhenGuo Yin Date: Thu, 23 Nov 2023 16:47:33 +0800 Subject: [PATCH 2016/7721] drm/amdgpu: Skip access gfx11 golden registers under SRIOV [Why] Golden registers are PF-only registers on gfx11. RLCG interface will return "out-of-range" under SRIOV VF. [How] Skip access gfx11 golden registers under SRIOV. Reviewed-by: Horace Chen Signed-off-by: ZhenGuo Yin Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 8ed4a6fb147a..288e926e5cd4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -293,6 +293,9 @@ static void gfx_v11_0_set_kiq_pm4_funcs(struct amdgpu_device *adev) static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev) { + if (amdgpu_sriov_vf(adev)) + return; + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 4): From 00f9d49bce844e8196e0c2ea298f9a41a11129d9 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 30 Nov 2023 12:58:14 +0800 Subject: [PATCH 2017/7721] drm/amdgpu: Fix missing mca debugfs node Use amdgpu_ip_version() helper function to check ip version. The ip version contains other information, use the helper function to avoid reading wrong value. Reviewed-by: Lijo Lazar Signed-off-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index 54f2f346579e..210aea590a52 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -485,7 +485,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(mca_debug_mode_fops, NULL, amdgpu_mca_smu_debug_mode_se void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root) { #if defined(CONFIG_DEBUG_FS) - if (!root || adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 6)) + if (!root || amdgpu_ip_version(adev, MP1_HWIP, 0) != IP_VERSION(13, 0, 6)) return; debugfs_create_file("mca_debug_mode", 0200, root, adev, &mca_debug_mode_fops); From 9596ffe1cc99dd699e595ea971a2c8ccd2735e21 Mon Sep 17 00:00:00 2001 From: Likun Gao Date: Wed, 29 Nov 2023 10:59:53 +0800 Subject: [PATCH 2018/7721] drm/amdgpu: distinguish rlc fw for different SKU For some SKU, rlc firmware should use different one compared with the normal rlc firmware. Signed-off-by: Likun Gao Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 288e926e5cd4..c659ef0f47ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -67,6 +67,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_0_pfp.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_me.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_rlc.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_0_rlc_1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_toc.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_pfp.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_me.bin"); @@ -567,7 +568,11 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) } if (!amdgpu_sriov_vf(adev)) { - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 0) && + adev->pdev->revision == 0xCE) + snprintf(fw_name, sizeof(fw_name), "amdgpu/gc_11_0_0_rlc_1.bin"); + else + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; From f875f61b1fd626a4223a5bdf0339b5372c689e13 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 30 Nov 2023 18:39:03 +0800 Subject: [PATCH 2019/7721] drm/amdgpu: enable mca debug mode on APU by default enable MCA debug mode on APU device by default. Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index f6b47ebce9d6..72634d675e27 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -3132,7 +3132,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return 0; - amdgpu_ras_set_mca_debug_mode(adev, false); + /* enable MCA debug on APU device */ + amdgpu_ras_set_mca_debug_mode(adev, !!(adev->flags & AMD_IS_APU)); list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { if (!node->ras_obj) { From 39c960bbf9d9ea862398759e75736cfb68c3446f Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Wed, 29 Nov 2023 07:22:30 -0800 Subject: [PATCH 2020/7721] drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg() While improbable, there may be a chance of hitting integer overflow when the result of radeon_get_ib_value() gets shifted left. Avoid it by casting one of the operands to larger data type (u64). Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: 1729dd33d20b ("drm/radeon/kms: r600 CS parser fixes") Signed-off-by: Nikita Zhandarovich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 638f861af80f..6cf54a747749 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -1275,7 +1275,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) return -EINVAL; } tmp = (reg - CB_COLOR0_BASE) / 4; - track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; + track->cb_color_bo_offset[tmp] = (u64)radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); track->cb_color_base_last[tmp] = ib[idx]; track->cb_color_bo[tmp] = reloc->robj; @@ -1302,7 +1302,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) "0x%04X\n", reg); return -EINVAL; } - track->htile_offset = radeon_get_ib_value(p, idx) << 8; + track->htile_offset = (u64)radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); track->htile_bo = reloc->robj; track->db_dirty = true; From b5c5baa458faa5430c445acd9a17481274d77ccf Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Wed, 29 Nov 2023 07:22:12 -0800 Subject: [PATCH 2021/7721] drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check() It may be possible, albeit unlikely, to encounter integer overflow during the multiplication of several unsigned int variables, the result being assigned to a variable 'size' of wider type. Prevent this potential behaviour by converting one of the multiples to unsigned long. Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: 0242f74d29df ("drm/radeon: clean up CS functions in r100.c") Signed-off-by: Nikita Zhandarovich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index affa9e0309b2..cfeca2694d5f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2321,7 +2321,7 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) switch (prim_walk) { case 1: for (i = 0; i < track->num_arrays; i++) { - size = track->arrays[i].esize * track->max_indx * 4; + size = track->arrays[i].esize * track->max_indx * 4UL; if (track->arrays[i].robj == NULL) { DRM_ERROR("(PW %u) Vertex array %u no buffer " "bound\n", prim_walk, i); @@ -2340,7 +2340,7 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) break; case 2: for (i = 0; i < track->num_arrays; i++) { - size = track->arrays[i].esize * (nverts - 1) * 4; + size = track->arrays[i].esize * (nverts - 1) * 4UL; if (track->arrays[i].robj == NULL) { DRM_ERROR("(PW %u) Vertex array %u no buffer " "bound\n", prim_walk, i); From 71225e1c930942cb1e042fc08c5cc0c4ef30e95e Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Tue, 8 Aug 2023 11:04:16 -0700 Subject: [PATCH 2022/7721] drm/radeon: check return value of radeon_ring_lock() In the unlikely event of radeon_ring_lock() failing, its errno return value should be processed. This patch checks said return value and prints a debug message in case of an error. Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: 48c0c902e2e6 ("drm/radeon/kms: add support for CP setup on SI") Signed-off-by: Nikita Zhandarovich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/si.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index a91012447b56..85e9cba49cec 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -3611,6 +3611,10 @@ static int si_cp_start(struct radeon_device *rdev) for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) { ring = &rdev->ring[i]; r = radeon_ring_lock(rdev, ring, 2); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + return r; + } /* clear the compute context state */ radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0)); From b719a9c15d52d4f56bdea8241a5d90fd9197ce99 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 28 Nov 2023 18:35:09 -0600 Subject: [PATCH 2023/7721] drm/amd/display: Fix NULL pointer dereference at hibernate During hibernate sequence the source context might not have a clk_mgr. So don't use it to look for DML2 support. Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2980 Fixes: 7966f319c66d ("drm/amd/display: Introduce DML2") Reviewed-by: Harry Wentland Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index f3a9fdd2340d..e1c02527d04a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -4554,7 +4554,7 @@ void dc_resource_state_copy_construct( struct dml2_context *dml2 = NULL; // Need to preserve allocated dml2 context - if (src_ctx->clk_mgr->ctx->dc->debug.using_dml2) + if (src_ctx->clk_mgr && src_ctx->clk_mgr->ctx->dc->debug.using_dml2) dml2 = dst_ctx->bw_ctx.dml2; #endif @@ -4562,7 +4562,7 @@ void dc_resource_state_copy_construct( #ifdef CONFIG_DRM_AMD_DC_FP // Preserve allocated dml2 context - if (src_ctx->clk_mgr->ctx->dc->debug.using_dml2) + if (src_ctx->clk_mgr && src_ctx->clk_mgr->ctx->dc->debug.using_dml2) dst_ctx->bw_ctx.dml2 = dml2; #endif From 10dfde4bec529aa1d78e4b3acce7882a312880b7 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 4 Oct 2023 09:03:09 +0200 Subject: [PATCH 2024/7721] ARM: dts: omap4-embt2ws: Add Bluetooth Since the required clock is now available, add bluetooth. Note: Firmware (bts file) from device vendor reroutes tx for some time during initialisation and later put it back, producing timeouts in bluetooth initialisation but ignoring that command leads to proper initialisation. Signed-off-by: Andreas Kemnade Message-ID: <20231004070309.2408745-1-andreas@kemnade.info> Reviewed-by: Krzysztof Kozlowski Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts index 0411adbe0dcb..24f7d0285f79 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts @@ -462,10 +462,12 @@ &uart2 { interrupts-extended = <&wakeupgen GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH &omap4_pmx_core OMAP4_UART2_RX>; - /* - * BT + GPS in WL1283 in WG7500 requiring CLK32KAUDIO of pmic - * which does not have a driver - */ + bluetooth-gnss { + compatible = "ti,wl1283-st"; + enable-gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>; /* GPIO_25 */ + clocks = <&twl 1>; + clock-names = "ext_clock"; + }; }; &uart3 { From ac10d6c3c5f9b85e780ec5cfaf0608ae048c5205 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 20 Nov 2023 22:56:35 +0100 Subject: [PATCH 2025/7721] ARM: omap2plus_defconfig: enable I2C devcies of bt200 Enable all available I2C drivers needed for the Epson Moverio BT200, that are: - LED - Subdevs of the TWL6032 PMIC - IMU sensors Signed-off-by: Andreas Kemnade Message-ID: <20231120215635.4187399-1-andreas@kemnade.info> Signed-off-by: Tony Lindgren --- arch/arm/configs/omap2plus_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 7b1b41b4b160..3a166c2f02bd 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -607,6 +607,7 @@ CONFIG_LEDS_LP55XX_COMMON=m CONFIG_LEDS_LP5523=m CONFIG_LEDS_PCA963X=m CONFIG_LEDS_PWM=m +CONFIG_LEDS_BD2606MVV=m CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_ONESHOT=m @@ -624,6 +625,7 @@ CONFIG_RTC_DRV_PALMAS=m CONFIG_RTC_DRV_OMAP=m CONFIG_RTC_DRV_CPCAP=m CONFIG_DMADEVICES=y +CONFIG_CLK_TWL=m CONFIG_CLK_TWL6040=m CONFIG_COMMON_CLK_PALMAS=m CONFIG_OMAP_IOMMU=y @@ -646,6 +648,9 @@ CONFIG_CPCAP_ADC=m CONFIG_INA2XX_ADC=m CONFIG_TI_AM335X_ADC=m CONFIG_TWL4030_MADC=m +CONFIG_TWL6030_GPADC=m +CONFIG_MPU3050_I2C=m +CONFIG_INV_MPU6050_I2C=m CONFIG_SENSORS_ISL29028=m CONFIG_AK8975=m CONFIG_BMP280=m From 6353ed6f311b9daab93df4d968d72ddf2070fe7f Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 15 Nov 2023 11:44:34 +0100 Subject: [PATCH 2026/7721] MAINTAINERS: add omap bus drivers to OMAP2+ SUPPORT While doing some code cleanup in drivers/bus/, I noticed that the files drivers/bus/omap*.[ch] have no maintainer. As far as I see from the git history, important changes to those files went through Tony Lindgren. Further, the inclusion of those drivers depend on the config ARCH_OMAP2PLUS being enabled. This suggests these drivers are part of the section OMAP2+ SUPPORT. Add the omap bus drivers to OMAP2+ SUPPORT. Signed-off-by: Lukas Bulwahn Message-ID: <20231115104434.25796-1-lukas.bulwahn@gmail.com> Signed-off-by: Tony Lindgren --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..cf877dc7ff6c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15860,6 +15860,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git F: Documentation/devicetree/bindings/arm/ti/omap.yaml F: arch/arm/configs/omap2plus_defconfig F: arch/arm/mach-omap2/ +F: drivers/bus/omap*.[ch] F: drivers/bus/ti-sysc.c F: drivers/gpio/gpio-tps65219.c F: drivers/i2c/busses/i2c-omap.c From df16c1c51d8166958f533c0c886766f7ee9dd50f Mon Sep 17 00:00:00 2001 From: Andrew Halaney Date: Mon, 27 Nov 2023 15:41:10 -0600 Subject: [PATCH 2027/7721] net: phy: mdio_device: Reset device only when necessary Currently the phy reset sequence is as shown below for a devicetree described mdio phy on boot: 1. Assert the phy_device's reset as part of registering 2. Deassert the phy_device's reset as part of registering 3. Deassert the phy_device's reset as part of phy_probe 4. Deassert the phy_device's reset as part of phy_hw_init The extra two deasserts include waiting the deassert delay afterwards, which is adding unnecessary delay. This applies to both possible types of resets (reset controller reference and a reset gpio) that can be used. Here's some snipped tracing output using the following command line params "trace_event=gpio:* trace_options=stacktrace" illustrating the reset handling and where its coming from: /* Assert */ systemd-udevd-283 [002] ..... 6.780434: gpio_value: 544 set 0 systemd-udevd-283 [002] ..... 6.783849: => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => mdiobus_register_device => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ systemd-udevd-283 [002] ..... 6.802480: gpio_value: 544 set 1 systemd-udevd-283 [002] ..... 6.805886: => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ systemd-udevd-283 [002] ..... 6.882601: gpio_value: 544 set 1 systemd-udevd-283 [002] ..... 6.886014: => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_probe => really_probe => __driver_probe_device => driver_probe_device => __device_attach_driver => bus_for_each_drv => __device_attach => device_initial_probe => bus_probe_device => device_add => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ NetworkManager-477 [000] ..... 7.023144: gpio_value: 544 set 1 NetworkManager-477 [000] ..... 7.026596: => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_init_hw => phy_attach_direct => phylink_fwnode_phy_connect => __stmmac_open => stmmac_open There's a lot of paths where the device is getting its reset asserted and deasserted. Let's track the state and only actually do the assert/deassert when it changes. Reported-by: Sagar Cheluvegowda Signed-off-by: Andrew Halaney Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20231127-net-phy-reset-once-v2-1-448e8658779e@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mdio_device.c | 6 ++++++ drivers/net/phy/phy_device.c | 1 + include/linux/mdio.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c index 044828d081d2..73f6539b9e50 100644 --- a/drivers/net/phy/mdio_device.c +++ b/drivers/net/phy/mdio_device.c @@ -62,6 +62,7 @@ struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr) mdiodev->device_remove = mdio_device_remove; mdiodev->bus = bus; mdiodev->addr = addr; + mdiodev->reset_state = -1; dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr); @@ -122,6 +123,9 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value) if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl) return; + if (mdiodev->reset_state == value) + return; + if (mdiodev->reset_gpio) gpiod_set_value_cansleep(mdiodev->reset_gpio, value); @@ -135,6 +139,8 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value) d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay; if (d) fsleep(d); + + mdiodev->reset_state = value; } EXPORT_SYMBOL(mdio_device_reset); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 400fb09d9cd6..d8e9335d415c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -654,6 +654,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, mdiodev->flags = MDIO_DEVICE_FLAG_PHY; mdiodev->device_free = phy_mdio_device_free; mdiodev->device_remove = phy_mdio_device_remove; + mdiodev->reset_state = -1; dev->speed = SPEED_UNKNOWN; dev->duplex = DUPLEX_UNKNOWN; diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 007fd9c3e4b6..79ceee3c8673 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -38,6 +38,7 @@ struct mdio_device { /* Bus address of the MDIO device (0-31) */ int addr; int flags; + int reset_state; struct gpio_desc *reset_gpio; struct reset_control *reset_ctrl; unsigned int reset_assert_delay; From 000db9e9ad42e135c7d92a56a66116542ae2b6c3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Nov 2023 19:48:13 +0200 Subject: [PATCH 2028/7721] net/sched: cbs: Use units.h instead of the copy of a definition BYTES_PER_KBIT is defined in units.h, use that definition. Signed-off-by: Andy Shevchenko Acked-by: Vinicius Costa Gomes Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20231128174813.394462-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jakub Kicinski --- net/sched/sch_cbs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index 9a0b85190a2c..beece8e82c23 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include #include @@ -65,8 +67,6 @@ static LIST_HEAD(cbs_list); static DEFINE_SPINLOCK(cbs_list_lock); -#define BYTES_PER_KBIT (1000LL / 8) - struct cbs_sched_data { bool offload; int queue; From b77e23f1b03e4e9a5940bb52d0480a5098a44c1d Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 28 Nov 2023 20:53:47 -0800 Subject: [PATCH 2029/7721] octeon_ep: implement device unload control net API Device unload control net function should inform firmware of driver unload to let it take necessary actions to cleanup. Signed-off-by: Shinas Rasheed Link: https://lore.kernel.org/r/20231129045348.2538843-2-srasheed@marvell.com Signed-off-by: Jakub Kicinski --- .../ethernet/marvell/octeon_ep/octep_ctrl_net.c | 16 +++++++++++++++- .../ethernet/marvell/octeon_ep/octep_ctrl_net.h | 11 +++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c index 5fa596c674da..4c39e2fabe0a 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c @@ -26,7 +26,7 @@ static atomic_t ctrl_net_msg_id; /* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */ static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = { - [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_GET_INFO] = + [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE] = OCTEP_CP_VERSION(1, 0, 0) }; @@ -393,10 +393,24 @@ int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, return 0; } +int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid) +{ + struct octep_ctrl_net_wait_data d = {}; + struct octep_ctrl_net_h2f_req *req; + + req = &d.data.req; + dev_dbg(&oct->pdev->dev, "Sending dev_unload msg to fw\n"); + init_send_req(&d.msg, req, sizeof(int), vfid); + req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE; + + return octep_send_mbox_req(oct, &d, false); +} int octep_ctrl_net_uninit(struct octep_device *oct) { struct octep_ctrl_net_wait_data *pos, *n; + octep_ctrl_net_dev_remove(oct, OCTEP_CTRL_NET_INVALID_VFID); + list_for_each_entry_safe(pos, n, &oct->ctrl_req_wait_list, list) pos->done = 1; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h index a2463b460ad9..0de4de2ceb8f 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h @@ -42,6 +42,7 @@ enum octep_ctrl_net_h2f_cmd { OCTEP_CTRL_NET_H2F_CMD_RX_STATE, OCTEP_CTRL_NET_H2F_CMD_LINK_INFO, OCTEP_CTRL_NET_H2F_CMD_GET_INFO, + OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE, OCTEP_CTRL_NET_H2F_CMD_MAX }; @@ -370,6 +371,16 @@ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct); int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, struct octep_fw_info *info); +/** + * octep_ctrl_net_dev_remove() - Indicate to firmware that a device unload has happened. + * + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * + * return value: 0 on success, -errno on failure. + */ +int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid); + /** * octep_ctrl_net_uninit() - Uninitialize data for ctrl net. * From 068b2b649fc1fa340b53114350457d40b31aeedb Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 28 Nov 2023 20:53:48 -0800 Subject: [PATCH 2030/7721] octeon_ep: support OCTEON CN98 devices Add PCI Endpoint NIC support for Octeon CN98 devices. CN98 devices are part of Octeon 9 family products with similar PCI NIC characteristics to CN93, already supported driver. Add CN98 card to the device id table, as well as support differences in the register fields and certain usage scenarios such as unload. Signed-off-by: Shinas Rasheed Link: https://lore.kernel.org/r/20231129045348.2538843-3-srasheed@marvell.com Signed-off-by: Jakub Kicinski --- .../ethernet/marvell/octeon_ep.rst | 1 + .../marvell/octeon_ep/octep_cn9k_pf.c | 24 +++++++++++++++---- .../ethernet/marvell/octeon_ep/octep_main.c | 4 ++++ .../ethernet/marvell/octeon_ep/octep_main.h | 1 + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 4 ++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst index 613a818d5db6..c96d262b30be 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst @@ -22,6 +22,7 @@ EndPoint NIC. Supported Devices ================= Currently, this driver support following devices: + * Network controller: Cavium, Inc. Device b100 * Network controller: Cavium, Inc. Device b200 * Network controller: Cavium, Inc. Device b400 * Network controller: Cavium, Inc. Device b900 diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c index d4ee2454675b..8baabd07e91f 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c @@ -216,9 +216,15 @@ static void octep_init_config_cn93_pf(struct octep_device *oct) conf->sriov_cfg.vf_srn = CN93_SDP_EPF_RINFO_SRN(val); val = octep_read_csr64(oct, CN93_SDP_MAC_PF_RING_CTL(oct->pcie_port)); - conf->pf_ring_cfg.srn = CN93_SDP_MAC_PF_RING_CTL_SRN(val); - conf->pf_ring_cfg.max_io_rings = CN93_SDP_MAC_PF_RING_CTL_RPPF(val); - conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings; + if (oct->chip_id == OCTEP_PCI_DEVICE_ID_CN98_PF) { + conf->pf_ring_cfg.srn = CN98_SDP_MAC_PF_RING_CTL_SRN(val); + conf->pf_ring_cfg.max_io_rings = CN98_SDP_MAC_PF_RING_CTL_RPPF(val); + conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings; + } else { + conf->pf_ring_cfg.srn = CN93_SDP_MAC_PF_RING_CTL_SRN(val); + conf->pf_ring_cfg.max_io_rings = CN93_SDP_MAC_PF_RING_CTL_RPPF(val); + conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings; + } dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n", conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf, conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings); @@ -578,6 +584,13 @@ static irqreturn_t octep_ioq_intr_handler_cn93_pf(void *data) return IRQ_HANDLED; } +/* soft reset of 98xx */ +static int octep_soft_reset_cn98_pf(struct octep_device *oct) +{ + dev_info(&oct->pdev->dev, "CN98XX: skip soft reset\n"); + return 0; +} + /* soft reset of 93xx */ static int octep_soft_reset_cn93_pf(struct octep_device *oct) { @@ -806,7 +819,10 @@ void octep_device_setup_cn93_pf(struct octep_device *oct) oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cn93_pf; oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cn93_pf; oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cn93_pf; - oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf; + if (oct->chip_id == OCTEP_PCI_DEVICE_ID_CN98_PF) + oct->hw_ops.soft_reset = octep_soft_reset_cn98_pf; + else + oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf; oct->hw_ops.reinit_regs = octep_reinit_regs_cn93_pf; oct->hw_ops.enable_interrupts = octep_enable_interrupts_cn93_pf; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 423eec5ff3ad..1a24b3d3cce6 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -22,6 +22,7 @@ struct workqueue_struct *octep_wq; /* Supported Devices */ static const struct pci_device_id octep_pci_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN98_PF)}, {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_PF)}, {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_PF)}, {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_PF)}, @@ -1147,6 +1148,8 @@ static void octep_ctrl_mbox_task(struct work_struct *work) static const char *octep_devid_to_str(struct octep_device *oct) { switch (oct->chip_id) { + case OCTEP_PCI_DEVICE_ID_CN98_PF: + return "CN98XX"; case OCTEP_PCI_DEVICE_ID_CN93_PF: return "CN93XX"; case OCTEP_PCI_DEVICE_ID_CNF95N_PF: @@ -1197,6 +1200,7 @@ int octep_device_setup(struct octep_device *oct) dev_info(&pdev->dev, "chip_id = 0x%x\n", pdev->device); switch (oct->chip_id) { + case OCTEP_PCI_DEVICE_ID_CN98_PF: case OCTEP_PCI_DEVICE_ID_CN93_PF: case OCTEP_PCI_DEVICE_ID_CNF95N_PF: dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n", diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h index e2fe8b28eb0e..e1b4b2af618e 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h @@ -18,6 +18,7 @@ #define OCTEP_PCIID_CN93_PF 0xB200177d #define OCTEP_PCIID_CN93_VF 0xB203177d +#define OCTEP_PCI_DEVICE_ID_CN98_PF 0xB100 #define OCTEP_PCI_DEVICE_ID_CN93_PF 0xB200 #define OCTEP_PCI_DEVICE_ID_CN93_VF 0xB203 diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h index 0a43983e9101..2e20a39d89af 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h @@ -362,6 +362,10 @@ #define CN93_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0xFF) #define CN93_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F) +#define CN98_SDP_MAC_PF_RING_CTL_NPFS(val) (((val) >> 48) & 0xF) +#define CN98_SDP_MAC_PF_RING_CTL_SRN(val) ((val) & 0xFF) +#define CN98_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 32) & 0x3F) + /* Number of non-queue interrupts in CN93xx */ #define CN93_NUM_NON_IOQ_INTR 16 From e8c780a5706066eba210e4c514968d95ba29e052 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Nov 2023 20:14:27 -0800 Subject: [PATCH 2031/7721] docs: netlink: link to family documentations from spec info To increase the chances of people finding the rendered docs add a link to specs.rst and index.rst. Add a label in the generated index.rst and while at it adjust the title a little bit. Reviewed-by: Breno Leitao Reviewed-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20231129041427.2763074-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/userspace-api/netlink/index.rst | 4 +++- Documentation/userspace-api/netlink/specs.rst | 2 +- tools/net/ynl/ynl-gen-rst.py | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/userspace-api/netlink/index.rst b/Documentation/userspace-api/netlink/index.rst index 62725dafbbdb..c1b6765cc963 100644 --- a/Documentation/userspace-api/netlink/index.rst +++ b/Documentation/userspace-api/netlink/index.rst @@ -16,4 +16,6 @@ Netlink documentation for users. genetlink-legacy netlink-raw -See also :ref:`Documentation/core-api/netlink.rst `. +See also: + - :ref:`Documentation/core-api/netlink.rst ` + - :ref:`Documentation/networking/netlink_spec/index.rst ` diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index c1b951649113..1b50d97d8d7c 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -15,7 +15,7 @@ kernel headers directly. Internally kernel uses the YAML specs to generate: - the C uAPI header - - documentation of the protocol as a ReST file + - documentation of the protocol as a ReST file - see :ref:`Documentation/networking/netlink_spec/index.rst ` - policy tables for input attribute validation - operation tables diff --git a/tools/net/ynl/ynl-gen-rst.py b/tools/net/ynl/ynl-gen-rst.py index b6292109e236..8c62e040df5d 100755 --- a/tools/net/ynl/ynl-gen-rst.py +++ b/tools/net/ynl/ynl-gen-rst.py @@ -122,6 +122,11 @@ def rst_toctree(maxdepth: int = 2) -> str: return "\n".join(lines) +def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" + + # Parsers # ======= @@ -349,7 +354,8 @@ def generate_main_index_rst(output: str) -> None: lines = [] lines.append(rst_header()) - lines.append(rst_title("Netlink Specification")) + lines.append(rst_label("specs")) + lines.append(rst_title("Netlink Family Specifications")) lines.append(rst_toctree(1)) index_dir = os.path.dirname(output) From f7580f00cc6e5bf57256d61c223d3ac6b4001ae7 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 29 Nov 2023 19:24:21 -0300 Subject: [PATCH 2032/7721] selftests: tc-testing: remove spurious nsPlugin usage Tests using DEV2 should not be run in a dedicated net namespace, and in parallel, as this device cannot be shared. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231129222424.910148-2-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/tc-tests/filters/tests.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json index 361235ad574b..4598f1d330fe 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json @@ -48,9 +48,6 @@ "filter", "flower" ], - "plugins": { - "requires": "nsPlugin" - }, "setup": [ "$TC qdisc add dev $DEV2 ingress", "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000" @@ -72,9 +69,6 @@ "filter", "flower" ], - "plugins": { - "requires": "nsPlugin" - }, "setup": [ "$TC qdisc add dev $DEV2 ingress", "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop" From 74f7e7eeb1d2c1b00f1a8fa1a6666a509f274da8 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 29 Nov 2023 19:24:22 -0300 Subject: [PATCH 2033/7721] selftests: tc-testing: remove spurious './' from Makefile Patchwork CI didn't like the extra './', so remove it. Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231129222424.910148-3-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/Makefile b/tools/testing/selftests/tc-testing/Makefile index e8b3dde4fa16..9153e3428a77 100644 --- a/tools/testing/selftests/tc-testing/Makefile +++ b/tools/testing/selftests/tc-testing/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS += ./tdc.sh +TEST_PROGS += tdc.sh TEST_FILES := action-ebpf tdc*.py Tdc*.py plugins plugin-lib tc-tests scripts include ../lib.mk From 7de8b2efafeb770e3f2113d506c31be7f4c9618e Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 29 Nov 2023 19:24:23 -0300 Subject: [PATCH 2034/7721] selftests: tc-testing: rename concurrency.json to flower.json All tests in this file pertain to flower, so name it appropriately Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231129222424.910148-4-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/filters/{concurrency.json => flower.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/testing/selftests/tc-testing/tc-tests/filters/{concurrency.json => flower.json} (100%) diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json b/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json similarity index 100% rename from tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json rename to tools/testing/selftests/tc-testing/tc-tests/filters/flower.json From 0fbb5a54f9416953fa8a3857425a62ea6b1efd5c Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 29 Nov 2023 19:24:24 -0300 Subject: [PATCH 2035/7721] selftests: tc-testing: remove filters/tests.json Remove this generic file and move the tests to their appropriate files Signed-off-by: Pedro Tammela Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20231129222424.910148-5-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/filters/flower.json | 98 ++++++++++++++ .../tc-testing/tc-tests/filters/matchall.json | 23 ++++ .../tc-testing/tc-tests/filters/tests.json | 123 ------------------ 3 files changed, 121 insertions(+), 123 deletions(-) delete mode 100644 tools/testing/selftests/tc-testing/tc-tests/filters/tests.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json b/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json index c2a433a4737e..6b08c0642069 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json @@ -173,5 +173,103 @@ "$TC qdisc del dev $DEV2 ingress", "/bin/rm -rf $BATCH_DIR" ] + }, + { + "id": "2ff3", + "name": "Add flower with max handle and then dump it", + "category": [ + "filter", + "flower" + ], + "setup": [ + "$TC qdisc add dev $DEV2 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress handle 0xffffffff flower action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV2 ingress", + "matchPattern": "filter protocol ip pref 1 flower.*handle 0xffffffff", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV2 ingress" + ] + }, + { + "id": "d052", + "name": "Add 1M filters with the same action", + "category": [ + "filter", + "flower" + ], + "setup": [ + "$TC qdisc add dev $DEV2 ingress", + "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000" + ], + "cmdUnderTest": "$TC -b $BATCH_FILE", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "action order 0: gact action drop.*index 1 ref 1000000 bind 1000000", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV2 ingress", + "/bin/rm $BATCH_FILE" + ] + }, + { + "id": "4cbd", + "name": "Try to add filter with duplicate key", + "category": [ + "filter", + "flower" + ], + "setup": [ + "$TC qdisc add dev $DEV2 ingress", + "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop" + ], + "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop", + "expExitCode": "2", + "verifyCmd": "$TC -s filter show dev $DEV2 ingress", + "matchPattern": "filter protocol ip pref 1 flower chain 0 handle", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV2 ingress" + ] + }, + { + "id": "7c65", + "name": "Add flower filter and then terse dump it", + "category": [ + "filter", + "flower" + ], + "setup": [ + "$TC qdisc add dev $DEV2 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop", + "expExitCode": "0", + "verifyCmd": "$TC -br filter show dev $DEV2 ingress", + "matchPattern": "filter protocol ip pref 1 flower.*handle", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV2 ingress" + ] + }, + { + "id": "d45e", + "name": "Add flower filter and verify that terse dump doesn't output filter key", + "category": [ + "filter", + "flower" + ], + "setup": [ + "$TC qdisc add dev $DEV2 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop", + "expExitCode": "0", + "verifyCmd": "$TC -br filter show dev $DEV2 ingress", + "matchPattern": " dst_mac e4:11:22:11:4a:51", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV2 ingress" + ] } ] diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json index afa1b9b0c856..f8d28c415bc3 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json @@ -480,5 +480,28 @@ "$TC qdisc del dev $DUMMY ingress", "$TC actions del action police index 199" ] + }, + { + "id": "2638", + "name": "Add matchall and try to get it", + "category": [ + "filter", + "matchall" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "$TC qdisc add dev $DEV1 clsact", + "$TC filter add dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall action ok" + ], + "cmdUnderTest": "$TC filter get dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 ingress", + "matchPattern": "filter protocol all pref 1 matchall chain 0 handle 0x1234", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 clsact" + ] } ] diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json deleted file mode 100644 index 4598f1d330fe..000000000000 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json +++ /dev/null @@ -1,123 +0,0 @@ -[ - { - "id": "2638", - "name": "Add matchall and try to get it", - "category": [ - "filter", - "matchall" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 clsact", - "$TC filter add dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall action ok" - ], - "cmdUnderTest": "$TC filter get dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall", - "expExitCode": "0", - "verifyCmd": "$TC filter show dev $DEV1 ingress", - "matchPattern": "filter protocol all pref 1 matchall chain 0 handle 0x1234", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 clsact" - ] - }, - { - "id": "2ff3", - "name": "Add flower with max handle and then dump it", - "category": [ - "filter", - "flower" - ], - "setup": [ - "$TC qdisc add dev $DEV2 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress handle 0xffffffff flower action ok", - "expExitCode": "0", - "verifyCmd": "$TC filter show dev $DEV2 ingress", - "matchPattern": "filter protocol ip pref 1 flower.*handle 0xffffffff", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV2 ingress" - ] - }, - { - "id": "d052", - "name": "Add 1M filters with the same action", - "category": [ - "filter", - "flower" - ], - "setup": [ - "$TC qdisc add dev $DEV2 ingress", - "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000" - ], - "cmdUnderTest": "$TC -b $BATCH_FILE", - "expExitCode": "0", - "verifyCmd": "$TC actions list action gact", - "matchPattern": "action order 0: gact action drop.*index 1 ref 1000000 bind 1000000", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV2 ingress", - "/bin/rm $BATCH_FILE" - ] - }, - { - "id": "4cbd", - "name": "Try to add filter with duplicate key", - "category": [ - "filter", - "flower" - ], - "setup": [ - "$TC qdisc add dev $DEV2 ingress", - "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop" - ], - "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop", - "expExitCode": "2", - "verifyCmd": "$TC -s filter show dev $DEV2 ingress", - "matchPattern": "filter protocol ip pref 1 flower chain 0 handle", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV2 ingress" - ] - }, - { - "id": "7c65", - "name": "Add flower filter and then terse dump it", - "category": [ - "filter", - "flower" - ], - "setup": [ - "$TC qdisc add dev $DEV2 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop", - "expExitCode": "0", - "verifyCmd": "$TC -br filter show dev $DEV2 ingress", - "matchPattern": "filter protocol ip pref 1 flower.*handle", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV2 ingress" - ] - }, - { - "id": "d45e", - "name": "Add flower filter and verify that terse dump doesn't output filter key", - "category": [ - "filter", - "flower" - ], - "setup": [ - "$TC qdisc add dev $DEV2 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop", - "expExitCode": "0", - "verifyCmd": "$TC -br filter show dev $DEV2 ingress", - "matchPattern": " dst_mac e4:11:22:11:4a:51", - "matchCount": "0", - "teardown": [ - "$TC qdisc del dev $DEV2 ingress" - ] - } -] From 31937546bef19d1d5be1157ceb68fb5c23b47f0c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:50:00 +0100 Subject: [PATCH 2036/7721] arm64: dts: ti: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124095000.58487-2-krzysztof.kozlowski@linaro.org Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am69-sk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts index 9868c7049bfb..d6a7ae086244 100644 --- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts @@ -671,7 +671,7 @@ exp1: gpio@21 { reg = <0x21>; gpio-controller; #gpio-cells = <2>; - gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", + gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", "IO_EXP_MCU_RGMII_RST#", "IO_EXP_PCIe0_4L_PERST#", "IO_EXP_PCIe1_M.2_RTSz", "IO_EXP_PCIe3_M.2_RTSz", "PM_INA_BUS_EN", "ENET1_EXP_PWRDN", "EXP1_ENET_RSTz", From 7dc4af358cc382c5d20bd5b726e53ef0f526eb6d Mon Sep 17 00:00:00 2001 From: Nitin Yadav Date: Fri, 27 Oct 2023 12:29:30 +0530 Subject: [PATCH 2037/7721] arm64: dts: ti: k3-am62a-main: Fix GPIO pin count in DT nodes Fix number of gpio pins in main_gpio0 & main_gpio1 DT nodes according to AM62A7 datasheet[0]. [0] https://www.ti.com/lit/gpn/am62a3 Section: 6.3.10 GPIO (Page No. 52-55) Fixes: 5fc6b1b62639 ("arm64: dts: ti: Introduce AM62A7 family of SoCs") Signed-off-by: Nitin Yadav Link: https://lore.kernel.org/r/20231027065930.1187405-1-n-yadav@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a-main.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi index 4ae7fdc5221b..ccd708b09acd 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi @@ -462,7 +462,7 @@ main_gpio0: gpio@600000 { <193>, <194>, <195>; interrupt-controller; #interrupt-cells = <2>; - ti,ngpio = <87>; + ti,ngpio = <92>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 77 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 77 0>; @@ -480,7 +480,7 @@ main_gpio1: gpio@601000 { <183>, <184>, <185>; interrupt-controller; #interrupt-cells = <2>; - ti,ngpio = <88>; + ti,ngpio = <52>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 78 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 78 0>; From b57160859263c083c49482b0d083a586b1517f78 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 6 Nov 2023 11:57:48 +0200 Subject: [PATCH 2038/7721] arm64: dts: ti: k3-am65-main: Fix DSS irq trigger type DSS irq trigger type is set to IRQ_TYPE_EDGE_RISING in the DT file, but the TRM says it is level triggered. For some reason triggering on rising edge results in double the amount of expected interrupts, e.g. for normal page flipping test the number of interrupts per second is 2 * fps. It is as if the IRQ triggers on both edges. There are no other side effects to this issue than slightly increased CPU & power consumption due to the extra interrupt. Switching to IRQ_TYPE_LEVEL_HIGH is correct and fixes the issue, so let's do that. Fixes: fc539b90eda2 ("arm64: dts: ti: am654: Add DSS node") Signed-off-by: Tomi Valkeinen Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231106-am65-dss-clk-edge-v1-1-4a959fec0e1e@ideasonboard.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 5ebb87f467de..29048d6577cf 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -1034,7 +1034,7 @@ dss: dss@4a00000 { assigned-clocks = <&k3_clks 67 2>; assigned-clock-parents = <&k3_clks 67 5>; - interrupts = ; + interrupts = ; dma-coherent; From 2897596e3793ce4d58654c56dcc531e853c3ca5a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 10:20:59 -0600 Subject: [PATCH 2039/7721] arm64: dts: ti: k3-am64-main: Fix typo in epwm_tbclk node name The node name has @4140 but the reg is at 4130, fix this here. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117162059.88633-1-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am64-main.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index 0be642bc1b86..745143410146 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -63,7 +63,7 @@ phy_gmii_sel: phy@4044 { #phy-cells = <1>; }; - epwm_tbclk: clock-controller@4140 { + epwm_tbclk: clock-controller@4130 { compatible = "ti,am64-epwm-tbclk"; reg = <0x4130 0x4>; #clock-cells = <1>; From 26abae3d840b8b83413c6222725db1104fe4811d Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Fri, 10 Nov 2023 18:55:06 +0530 Subject: [PATCH 2040/7721] arm64: dts: ti: k3-am642-evm/sk: Mark mcu_gpio_intr as reserved Similar to MCU GPIO, mark the MCU GPIO router also as reserved for MCU domain firmware usage. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20231110132508.3137454-1-vigneshr@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am642-evm.dts | 6 +++++- arch/arm64/boot/dts/ti/k3-am642-sk.dts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts index 4dba18941015..45f64b6f8281 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -468,11 +468,15 @@ &main_gpio0 { bootph-all; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &main_spi0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts index f29c8a9b59ba..d2d3b5017ac4 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -433,11 +433,15 @@ exp2: gpio@60 { }; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &sdhci0 { vmmc-supply = <&wlan_en>; bus-width = <4>; From 1b3014a65adb491ec5a777c988f0dd85094d78bd Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Fri, 10 Nov 2023 18:55:07 +0530 Subject: [PATCH 2041/7721] arm64: dts: ti: k3-am62p5-sk: Mark mcu gpio and mcu_gpio_intr as reserved These are typically under MCU Firmware usage. Hence mark them reserved. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20231110132508.3137454-2-vigneshr@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts index f377eadef0c1..1773c05f752c 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts @@ -598,3 +598,12 @@ &wkup_uart0 { status = "reserved"; bootph-all; }; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; From 5582b1c623a6d62d3aff62c070173c9f1eb8fabd Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Fri, 10 Nov 2023 18:55:08 +0530 Subject: [PATCH 2042/7721] arm64: dts: ti: k3-am62x-sk-common: Mark mcu gpio and mcu_gpio_intr as reserved These are typically under MCU Firmware usage. Hence mark them reserved. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20231110132508.3137454-3-vigneshr@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi index 19f57ead4ebd..3b9729316739 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi @@ -517,3 +517,12 @@ dpi1_out: endpoint { }; }; }; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; From ad8edf4ff37ab157f6547da173aedc9f4e5c4015 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 4 Nov 2023 09:52:15 +0100 Subject: [PATCH 2043/7721] arm64: dts: ti: iot2050: Re-add aliases Lost while dropping them from the common dtsi. Fixes: ffc449e016e2 ("arm64: dts: ti: k3-am65: Drop aliases") Signed-off-by: Jan Kiszka Link: https://lore.kernel.org/r/1edbc1b56ed4ff2256d7afb7db3cab4b3a423692.1699087938.git.jan.kiszka@siemens.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index ba1c14a54acf..b849648d51f9 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -14,6 +14,16 @@ / { aliases { + serial0 = &wkup_uart0; + serial1 = &mcu_uart0; + serial2 = &main_uart0; + serial3 = &main_uart1; + i2c0 = &wkup_i2c0; + i2c1 = &mcu_i2c0; + i2c2 = &main_i2c0; + i2c3 = &main_i2c1; + i2c4 = &main_i2c2; + i2c5 = &main_i2c3; spi0 = &mcu_spi0; mmc0 = &sdhci1; mmc1 = &sdhci0; From 95fd0767ef961d906f0722b5848276e566a46a4c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 4 Nov 2023 09:52:16 +0100 Subject: [PATCH 2044/7721] arm64: dts: ti: iot2050: Drop unused ecap0 PWM In fact, this was never used by the final device, only dates back to first prototypes. Signed-off-by: Jan Kiszka Link: https://lore.kernel.org/r/6131d44e0505ca3efbb9039e5f2b637a3e139312.1699087938.git.jan.kiszka@siemens.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index b849648d51f9..fc39ae0f9587 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -355,12 +355,6 @@ AM65X_IOPAD(0x0008, PIN_INPUT, 0) /* (B21) I2C1_SCL */ AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */ >; }; - - ecap0_pins_default: ecap0-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */ - >; - }; }; &wkup_uart0 { @@ -557,12 +551,6 @@ &mcu_cpsw { status = "disabled"; }; -&ecap0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&ecap0_pins_default>; -}; - &sdhci1 { pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; From e6a53facc8ade138089a64adb4980a1622e7f75f Mon Sep 17 00:00:00 2001 From: Benedikt Niedermayr Date: Sat, 4 Nov 2023 09:52:17 +0100 Subject: [PATCH 2045/7721] arm64: dts: ti: iot2050: Definitions for runtime pinmuxing Add multiple device tree nodes in order to support runtime pinmuxing via debugfs. All nodes are added to the pinctrl device node, since they are now belonging to multiple interfaces now. Note: Pinconf is also handled by debugfs-pinmux. This is possible since pinconf and pinmux accessing the same 32-Bit register and setting the function mask to 32-Bit allows writes to the whole register. Signed-off-by: Benedikt Niedermayr [Jan: fix node name style] Signed-off-by: Jan Kiszka Link: https://lore.kernel.org/r/3f90f3e521758622aa9b10f030cf0de1e68e77a4.1699087938.git.jan.kiszka@siemens.com Signed-off-by: Nishanth Menon --- .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 663 +++++++++++++++++- .../dts/ti/k3-am6548-iot2050-advanced-m2.dts | 4 +- 2 files changed, 628 insertions(+), 39 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index fc39ae0f9587..41c980d2a242 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -114,6 +114,425 @@ dp_refclk: clock { }; &wkup_pmx0 { + pinctrl-names = + "default", + "d0-uart0-rxd", "d0-gpio", "d0-gpio-pullup", "d0-gpio-pulldown", + "d1-uart0-txd", "d1-gpio", "d1-gpio-pullup", "d1-gpio-pulldown", + "d2-uart0-ctsn", "d2-gpio", "d2-gpio-pullup", "d2-gpio-pulldown", + "d3-uart0-rtsn", "d3-gpio", "d3-gpio-pullup", "d3-gpio-pulldown", + "d10-spi0-cs0", "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown", + "d11-spi0-d0", "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown", + "d12-spi0-d1", "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown", + "d13-spi0-clk", "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown", + "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown", + "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown", + "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown", + "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown", + "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown", + "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown"; + + pinctrl-0 = <&d0_uart0_rxd>; + pinctrl-1 = <&d0_uart0_rxd>; + pinctrl-2 = <&d0_gpio>; + pinctrl-3 = <&d0_gpio_pullup>; + pinctrl-4 = <&d0_gpio_pulldown>; + pinctrl-5 = <&d1_uart0_txd>; + pinctrl-6 = <&d1_gpio>; + pinctrl-7 = <&d1_gpio_pullup>; + pinctrl-8 = <&d1_gpio_pulldown>; + pinctrl-9 = <&d2_uart0_ctsn>; + pinctrl-10 = <&d2_gpio>; + pinctrl-11 = <&d2_gpio_pullup>; + pinctrl-12 = <&d2_gpio_pulldown>; + pinctrl-13 = <&d3_uart0_rtsn>; + pinctrl-14 = <&d3_gpio>; + pinctrl-15 = <&d3_gpio_pullup>; + pinctrl-16 = <&d3_gpio_pulldown>; + pinctrl-17 = <&d10_spi0_cs0>; + pinctrl-18 = <&d10_gpio>; + pinctrl-19 = <&d10_gpio_pullup>; + pinctrl-20 = <&d10_gpio_pulldown>; + pinctrl-21 = <&d11_spi0_d0>; + pinctrl-22 = <&d11_gpio>; + pinctrl-23 = <&d11_gpio_pullup>; + pinctrl-24 = <&d11_gpio_pulldown>; + pinctrl-25 = <&d12_spi0_d1>; + pinctrl-26 = <&d12_gpio>; + pinctrl-27 = <&d12_gpio_pullup>; + pinctrl-28 = <&d12_gpio_pulldown>; + pinctrl-29 = <&d13_spi0_clk>; + pinctrl-30 = <&d13_gpio>; + pinctrl-31 = <&d13_gpio_pullup>; + pinctrl-32 = <&d13_gpio_pulldown>; + pinctrl-33 = <&a0_gpio>; + pinctrl-34 = <&a0_gpio_pullup>; + pinctrl-35 = <&a0_gpio_pulldown>; + pinctrl-36 = <&a1_gpio>; + pinctrl-37 = <&a1_gpio_pullup>; + pinctrl-38 = <&a1_gpio_pulldown>; + pinctrl-39 = <&a2_gpio>; + pinctrl-40 = <&a2_gpio_pullup>; + pinctrl-41 = <&a2_gpio_pulldown>; + pinctrl-42 = <&a3_gpio>; + pinctrl-43 = <&a3_gpio_pullup>; + pinctrl-44 = <&a3_gpio_pulldown>; + pinctrl-45 = <&a4_gpio>; + pinctrl-46 = <&a4_gpio_pullup>; + pinctrl-47 = <&a4_gpio_pulldown>; + pinctrl-48 = <&a5_gpio>; + pinctrl-49 = <&a5_gpio_pullup>; + pinctrl-50 = <&a5_gpio_pulldown>; + + d0_uart0_rxd: d0-uart0-rxd-pins { + pinctrl-single,pins = < + /* (P4) MCU_UART0_RXD */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) + >; + }; + + d0_gpio: d0-gpio-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7) + >; + }; + + d0_gpio_pullup: d0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7) + >; + }; + + d0_gpio_pulldown: d0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d1_uart0_txd: d1-uart0-txd-pins { + pinctrl-single,pins = < + /* (P5) MCU_UART0_TXD */ + AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) + >; + }; + + d1_gpio: d1-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pullup: d1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pulldown: d1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d2_uart0_ctsn: d2-uart0-ctsn-pins { + pinctrl-single,pins = < + /* (P1) MCU_UART0_CTSn */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4) + >; + }; + + d2_gpio: d2-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pullup: d2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pulldown: d2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d3_uart0_rtsn: d3-uart0-rtsn-pins { + pinctrl-single,pins = < + /* (N3) MCU_UART0_RTSn */ + AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4) + >; + }; + + d3_gpio: d3-gpio-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pullup: d3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pulldown: d3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d10_spi0_cs0: d10-spi0-cs0-pins { + pinctrl-single,pins = < + /* (Y4) MCU_SPI0_CS0 */ + AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0) + >; + }; + + d10_gpio: d10-gpio-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pullup: d10-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pulldown: d10-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d11_spi0_d0: d11-spi0-d0-pins { + pinctrl-single,pins = < + /* (Y3) MCU_SPI0_D0 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0) + >; + }; + + d11_gpio: d11-gpio-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pullup: d11-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pulldown: d11-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d12_spi0_d1: d12-spi0-d1-pins { + pinctrl-single,pins = < + /* (Y2) MCU_SPI0_D1 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0) + >; + }; + + d12_gpio: d12-gpio-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pullup: d12-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pulldown: d12-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d13_spi0_clk: d13-spi0-clk-pins { + pinctrl-single,pins = < + /* (Y1) MCU_SPI0_CLK */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0) + >; + }; + + d13_gpio: d13-gpio-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pullup: d13-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pulldown: d13-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a0_gpio: a0-gpio-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pullup: a0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pulldown: a0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a1_gpio: a1-gpio-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pullup: a1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pulldown: a1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a2_gpio: a2-gpio-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pullup: a2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pulldown: a2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a3_gpio: a3-gpio-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pullup: a3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pulldown: a3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a4_gpio: a4-gpio-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pullup: a4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pulldown: a4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a5_gpio: a5-gpio-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7) + >; + }; + + a5_gpio_pullup: a5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7) + >; + }; + + a5_gpio_pulldown: a5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7) + >; + }; + wkup_i2c0_pins_default: wkup-i2c0-default-pins { pinctrl-single,pins = < /* (AC7) WKUP_I2C0_SCL */ @@ -146,23 +565,6 @@ AM65X_WKUP_IOPAD(0x0034, PIN_INPUT, 7) >; }; - arduino_uart_pins_default: arduino-uart-default-pins { - pinctrl-single,pins = < - /* (P4) MCU_UART0_RXD */ - AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) - /* (P5) MCU_UART0_TXD */ - AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) - >; - }; - - arduino_io_d2_to_d3_pins_default: arduino-io-d2-to-d3-default-pins { - pinctrl-single,pins = < - /* (P1) WKUP_GPIO0_31 */ - AM65X_WKUP_IOPAD(0x004C, PIN_OUTPUT, 7) - /* (N3) WKUP_GPIO0_33 */ - AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 7) - >; - }; arduino_io_oe_pins_default: arduino-io-oe-default-pins { pinctrl-single,pins = < @@ -242,6 +644,214 @@ AM65X_WKUP_IOPAD(0x003C, PIN_OUTPUT, 7) }; &main_pmx0 { + pinctrl-names = + "default", + "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown", + "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown", + "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown", + "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown", + "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown", + "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown"; + + pinctrl-0 = <&d4_ehrpwm0_a>; + pinctrl-1 = <&d4_ehrpwm0_a>; + pinctrl-2 = <&d4_gpio>; + pinctrl-3 = <&d4_gpio_pullup>; + pinctrl-4 = <&d4_gpio_pulldown>; + + pinctrl-5 = <&d5_ehrpwm1_a>; + pinctrl-6 = <&d5_gpio>; + pinctrl-7 = <&d5_gpio_pullup>; + pinctrl-8 = <&d5_gpio_pulldown>; + + pinctrl-9 = <&d6_ehrpwm2_a>; + pinctrl-10 = <&d6_gpio>; + pinctrl-11 = <&d6_gpio_pullup>; + pinctrl-12 = <&d6_gpio_pulldown>; + + pinctrl-13 = <&d7_ehrpwm3_a>; + pinctrl-14 = <&d7_gpio>; + pinctrl-15 = <&d7_gpio_pullup>; + pinctrl-16 = <&d7_gpio_pulldown>; + + pinctrl-17 = <&d8_ehrpwm4_a>; + pinctrl-18 = <&d8_gpio>; + pinctrl-19 = <&d8_gpio_pullup>; + pinctrl-20 = <&d8_gpio_pulldown>; + + pinctrl-21 = <&d9_ehrpwm5_a>; + pinctrl-22 = <&d9_gpio>; + pinctrl-23 = <&d9_gpio_pullup>; + pinctrl-24 = <&d9_gpio_pulldown>; + + d4_ehrpwm0_a: d4-ehrpwm0-a-pins { + pinctrl-single,pins = < + /* (AG18) EHRPWM0_A */ + AM65X_IOPAD(0x0084, PIN_OUTPUT, 5) + >; + }; + + d4_gpio: d4-gpio-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + d4_gpio_pullup: d4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7) + >; + }; + + d4_gpio_pulldown: d4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d5_ehrpwm1_a: d5-ehrpwm1-a-pins { + pinctrl-single,pins = < + /* (AF17) EHRPWM1_A */ + AM65X_IOPAD(0x008C, PIN_OUTPUT, 5) + >; + }; + + d5_gpio: d5-gpio-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT, 7) + >; + }; + + d5_gpio_pullup: d5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7) + >; + }; + + d5_gpio_pulldown: d5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d6_ehrpwm2_a: d6-ehrpwm2-a-pins { + pinctrl-single,pins = < + /* (AH16) EHRPWM2_A */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 5) + >; + }; + + d6_gpio: d6-gpio-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d6_gpio_pullup: d6-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7) + >; + }; + + d6_gpio_pulldown: d6-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d7_ehrpwm3_a: d7-ehrpwm3-a-pins { + pinctrl-single,pins = < + /* (AH15) EHRPWM3_A */ + AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5) + >; + }; + + d7_gpio: d7-gpio-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT, 7) + >; + }; + + d7_gpio_pullup: d7-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7) + >; + }; + + d7_gpio_pulldown: d7-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d8_ehrpwm4_a: d8-ehrpwm4-a-pins { + pinctrl-single,pins = < + /* (AG15) EHRPWM4_A */ + AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5) + >; + }; + + d8_gpio: d8-gpio-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT, 7) + >; + }; + + d8_gpio_pullup: d8-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7) + >; + }; + + d8_gpio_pulldown: d8-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d9_ehrpwm5_a: d9-ehrpwm5-a-pins { + pinctrl-single,pins = < + /* (AD15) EHRPWM5_A */ + AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5) + >; + }; + + d9_gpio: d9-gpio-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT, 7) + >; + }; + + d9_gpio_pullup: d9-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7) + >; + }; + + d9_gpio_pulldown: d9-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) + >; + }; + main_uart1_pins_default: main-uart1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ @@ -283,17 +893,6 @@ AM65X_IOPAD(0x02c0, PIN_OUTPUT, 0) /* (AC8) USB1_DRVVBUS */ >; }; - arduino_io_d4_to_d9_pins_default: arduino-io-d4-to-d9-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0084, PIN_OUTPUT, 7) /* (AG18) GPIO0_33 */ - AM65X_IOPAD(0x008C, PIN_OUTPUT, 7) /* (AF17) GPIO0_35 */ - AM65X_IOPAD(0x0098, PIN_OUTPUT, 7) /* (AH16) GPIO0_38 */ - AM65X_IOPAD(0x00AC, PIN_OUTPUT, 7) /* (AH15) GPIO0_43 */ - AM65X_IOPAD(0x00C0, PIN_OUTPUT, 7) /* (AG15) GPIO0_48 */ - AM65X_IOPAD(0x00CC, PIN_OUTPUT, 7) /* (AD15) GPIO0_51 */ - >; - }; - dss_vout1_pins_default: dss-vout1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ @@ -370,13 +969,9 @@ &main_uart1 { &mcu_uart0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&arduino_uart_pins_default>; }; &main_gpio0 { - pinctrl-names = "default"; - pinctrl-0 = <&arduino_io_d4_to_d9_pins_default>; gpio-line-names = "main_gpio0-base", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -389,7 +984,6 @@ &main_gpio0 { &wkup_gpio0 { pinctrl-names = "default"; pinctrl-0 = - <&arduino_io_d2_to_d3_pins_default>, <&arduino_i2c_aio_switch_pins_default>, <&arduino_io_oe_pins_default>, <&push_button_pins_default>, @@ -572,9 +1166,6 @@ &usb1 { &mcu_spi0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_spi0_pins_default>; - #address-cells = <1>; #size-cells = <0>; ti,pindir-d0-out-d1-in; diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts index 774eb14ac907..8301c35c31b3 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts @@ -66,9 +66,7 @@ AM65X_IOPAD(0x001c, PIN_INPUT_PULLUP, 7) /* (C23) GPIO1_89 */ &main_gpio0 { pinctrl-names = "default"; - pinctrl-0 = - <&main_m2_pcie_mux_control>, - <&arduino_io_d4_to_d9_pins_default>; + pinctrl-0 = <&main_m2_pcie_mux_control>; }; &main_gpio1 { From 6c183a881100144e990f23fbd0f3262e93e8191d Mon Sep 17 00:00:00 2001 From: Su Bao Cheng Date: Sat, 4 Nov 2023 09:52:18 +0100 Subject: [PATCH 2046/7721] arm64: dts: ti: iot2050: Refactor the m.2 and minipcie power pin Make the m.2 power control pin also available on miniPCIE variants. This can fix some miniPCIE card hang issue, by forcing a power on reset during boot. Signed-off-by: Baocheng Su Signed-off-by: Jan Kiszka Link: https://lore.kernel.org/r/8b2f8c1698421b8d0694eb337ad7ea2320d76aa6.1699087938.git.jan.kiszka@siemens.com Signed-off-by: Nishanth Menon --- .../arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi | 4 +++- arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 11 +++++++++++ .../boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts | 8 +------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi index e9419c4fe605..e9b57b87e42e 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi @@ -20,7 +20,9 @@ AM65X_IOPAD(0x01e0, PIN_OUTPUT, 7) &main_gpio1 { pinctrl-names = "default"; - pinctrl-0 = <&cp2102n_reset_pin_default>; + pinctrl-0 = + <&main_pcie_enable_pins_default>, + <&cp2102n_reset_pin_default>; gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index 41c980d2a242..d2b6439cf496 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -852,6 +852,12 @@ AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) >; }; + main_pcie_enable_pins_default: main-pcie-enable-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ + >; + }; + main_uart1_pins_default: main-uart1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ @@ -981,6 +987,11 @@ &main_gpio0 { "", "IO9"; }; +&main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_pcie_enable_pins_default>; +}; + &wkup_gpio0 { pinctrl-names = "default"; pinctrl-0 = diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts index 8301c35c31b3..bd6f2e696e94 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts @@ -27,12 +27,6 @@ &mcu_r5fss0 { }; &main_pmx0 { - main_m2_enable_pins_default: main-m2-enable-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ - >; - }; - main_bkey_pcie_reset: main-bkey-pcie-reset-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ @@ -72,7 +66,7 @@ &main_gpio0 { &main_gpio1 { pinctrl-names = "default"; pinctrl-0 = - <&main_m2_enable_pins_default>, + <&main_pcie_enable_pins_default>, <&main_pmx0_m2_config_pins_default>, <&main_pmx1_m2_config_pins_default>, <&cp2102n_reset_pin_default>; From 73b4e471cd573e7597cfbd59b882a6cf6408791a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 4 Nov 2023 09:52:19 +0100 Subject: [PATCH 2047/7721] arm64: dts: ti: iot2050: Add icssg-prueth nodes for PG2 devices Add the required nodes to enable ICSSG SR2.0 based prueth networking. As the driver still needs to be extended for SR1.0 support, keep related nodes disabled on PG1 devices. Signed-off-by: Jan Kiszka Link: https://lore.kernel.org/r/565d31a5fd29c4dd0cf28e347049a1247a6e446c.1699087938.git.jan.kiszka@siemens.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-am65-iot2050-common-pg1.dtsi | 10 +- .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 128 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi index 51f902fa35a7..1d1979859583 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) Siemens AG, 2021 + * Copyright (c) Siemens AG, 2021-2023 * * Authors: * Jan Kiszka @@ -44,3 +44,11 @@ &tx_pru2_0 { &tx_pru2_1 { status = "disabled"; }; + +&icssg0_eth { + status = "disabled"; +}; + +&icssg0_mdio { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index d2b6439cf496..ab1dffa5c1c6 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -11,6 +11,7 @@ #include "k3-am654.dtsi" #include +#include / { aliases { @@ -27,6 +28,8 @@ aliases { spi0 = &mcu_spi0; mmc0 = &sdhci1; mmc1 = &sdhci0; + ethernet1 = &icssg0_emac0; + ethernet2 = &icssg0_emac1; }; chosen { @@ -111,6 +114,76 @@ dp_refclk: clock { #clock-cells = <0>; clock-frequency = <19200000>; }; + + /* Dual Ethernet application node on PRU-ICSSG0 */ + icssg0_eth: icssg0-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_rgmii_pins_default>; + sram = <&msmc_ram>; + + ti,prus = <&pru0_0>, <&rtu0_0>, <&tx_pru0_0>, + <&pru0_1>, <&rtu0_1>, <&tx_pru0_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg0_mii_g_rt>; + ti,mii-rt = <&icssg0_mii_rt>; + ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; + + interrupt-parent = <&icssg0_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc100>, /* egress slice 0 */ + <&main_udmap 0xc101>, /* egress slice 0 */ + <&main_udmap 0xc102>, /* egress slice 0 */ + <&main_udmap 0xc103>, /* egress slice 0 */ + <&main_udmap 0xc104>, /* egress slice 1 */ + <&main_udmap 0xc105>, /* egress slice 1 */ + <&main_udmap 0xc106>, /* egress slice 1 */ + <&main_udmap 0xc107>, /* egress slice 1 */ + <&main_udmap 0x4100>, /* ingress slice 0 */ + <&main_udmap 0x4101>; /* ingress slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg0_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg0_eth0_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4100>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + icssg0_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg0_eth1_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4104>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; }; &wkup_pmx0 { @@ -944,6 +1017,43 @@ AM65X_IOPAD(0x0074, PIN_INPUT, 5) /* (T27) I2C2_SCL */ AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) I2C2_SDA */ >; }; + + icssg0_mdio_pins_default: icssg0-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0294, PIN_INPUT, 0) /* (AE26) PRG0_MDIO0_MDIO */ + AM65X_IOPAD(0x0298, PIN_OUTPUT, 0) /* (AE28) PRG0_MDIO0_MDC */ + >; + }; + + icssg0_rgmii_pins_default: icssg0-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0244, PIN_INPUT, 2) /* (AB28) PRG0_PRU1_GPO0.PRG0_RGMII2_RD0 */ + AM65X_IOPAD(0x0248, PIN_INPUT, 2) /* (AC28) PRG0_PRU1_GPO1.PRG0_RGMII2_RD1 */ + AM65X_IOPAD(0x024c, PIN_INPUT, 2) /* (AC27) PRG0_PRU1_GPO2.PRG0_RGMII2_RD2 */ + AM65X_IOPAD(0x0250, PIN_INPUT, 2) /* (AB26) PRG0_PRU1_GPO3.PRG0_RGMII2_RD3 */ + AM65X_IOPAD(0x0274, PIN_OUTPUT, 2) /* (AC25) PRG0_PRU1_GPO12.PRG0_RGMII2_TD0 */ + AM65X_IOPAD(0x0278, PIN_OUTPUT, 2) /* (AD25) PRG0_PRU1_GPO13.PRG0_RGMII2_TD1 */ + AM65X_IOPAD(0x027c, PIN_OUTPUT, 2) /* (AD24) PRG0_PRU1_GPO14.PRG0_RGMII2_TD2 */ + AM65X_IOPAD(0x0280, PIN_OUTPUT, 2) /* (AE27) PRG0_PRU1_GPO15.PRG0_RGMII2_TD3 */ + AM65X_IOPAD(0x0284, PIN_INPUT, 2) /* (AC24) PRG0_PRU1_GPO16.PRG0_RGMII2_TXC */ + AM65X_IOPAD(0x0270, PIN_OUTPUT, 2) /* (AB24) PRG0_PRU1_GPO11.PRG0_RGMII2_TX_CTL */ + AM65X_IOPAD(0x025c, PIN_INPUT, 2) /* (AB27) PRG0_PRU1_GPO6.PRG0_RGMII2_RXC */ + AM65X_IOPAD(0x0254, PIN_INPUT, 2) /* (AA25) PRG0_PRU1_GPO4.PRG0_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x01f4, PIN_INPUT, 2) /* (V24) PRG0_PRU0_GPO0.PRG0_RGMII1_RD0 */ + AM65X_IOPAD(0x01f8, PIN_INPUT, 2) /* (W25) PRG0_PRU0_GPO1.PRG0_RGMII1_RD1 */ + AM65X_IOPAD(0x01fc, PIN_INPUT, 2) /* (W24) PRG0_PRU0_GPO2.PRG0_RGMII1_RD2 */ + AM65X_IOPAD(0x0200, PIN_INPUT, 2) /* (AA27) PRG0_PRU0_GPO3.PRG0_RGMII1_RD3 */ + AM65X_IOPAD(0x0224, PIN_OUTPUT, 2) /* (AD27) PRG0_PRU0_GPO12.PRG0_RGMII1_TD0 */ + AM65X_IOPAD(0x0228, PIN_OUTPUT, 2) /* (AC26) PRG0_PRU0_GPO13.PRG0_RGMII1_TD1 */ + AM65X_IOPAD(0x022c, PIN_OUTPUT, 2) /* (AD26) PRG0_PRU0_GPO14.PRG0_RGMII1_TD2 */ + AM65X_IOPAD(0x0230, PIN_OUTPUT, 2) /* (AA24) PRG0_PRU0_GPO15.PRG0_RGMII1_TD3 */ + AM65X_IOPAD(0x0234, PIN_INPUT, 2) /* (AD28) PRG0_PRU0_GPO16.PRG0_RGMII1_TXC */ + AM65X_IOPAD(0x0220, PIN_OUTPUT, 2) /* (AB25) PRG0_PRU0_GPO11.PRG0_RGMII1_TX_CTL */ + AM65X_IOPAD(0x020c, PIN_INPUT, 2) /* (Y25) PRG0_PRU0_GPO6.PRG0_RGMII1_RXC */ + AM65X_IOPAD(0x0204, PIN_INPUT, 2) /* (Y24) PRG0_PRU0_GPO4.PRG0_RGMII1_RX_CTL */ + >; + }; }; &main_pmx1 { @@ -1316,3 +1426,21 @@ &mcu_r5fss0_core1 { <&mcu_r5fss0_core1_memory_region>; mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>; }; + +&icssg0_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_mdio_pins_default>; + + icssg0_eth0_phy: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg0_eth1_phy: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; From 00cb022753e29a1c5993fa7d291378750377bd70 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 29 Nov 2023 19:33:16 +0200 Subject: [PATCH 2048/7721] drm/i915: use PIPE_CONF_CHECK_BOOL() for bool members Don't treat bools as integers. v2: Rebase Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231129173317.1192269-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9dc22fc8b3d3..d62cdae7ab6b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5091,8 +5091,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_QUIRK(quirk) \ ((current_config->quirks | pipe_config->quirks) & (quirk)) - PIPE_CONF_CHECK_I(hw.enable); - PIPE_CONF_CHECK_I(hw.active); + PIPE_CONF_CHECK_BOOL(hw.enable); + PIPE_CONF_CHECK_BOOL(hw.active); PIPE_CONF_CHECK_I(cpu_transcoder); PIPE_CONF_CHECK_I(mst_master_transcoder); @@ -5301,8 +5301,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(dsc.config.second_line_bpg_offset); PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); - PIPE_CONF_CHECK_I(dsc.compression_enable); - PIPE_CONF_CHECK_I(dsc.dsc_split); + PIPE_CONF_CHECK_BOOL(dsc.compression_enable); + PIPE_CONF_CHECK_BOOL(dsc.dsc_split); PIPE_CONF_CHECK_I(dsc.compressed_bpp_x16); PIPE_CONF_CHECK_BOOL(splitter.enable); From 9f82f1655fdbaf598a0106f7268ff99a606be434 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 29 Nov 2023 19:33:17 +0200 Subject: [PATCH 2049/7721] drm/i915: add bool type checks in PIPE_CONF_CHECK_* Avoid bool/int mismatches in state checker macros. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231129173317.1192269-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d62cdae7ab6b..7d48bcdd5797 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4923,6 +4923,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_X(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected 0x%08x, found 0x%08x)", \ current_config->name, \ @@ -4933,6 +4935,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_X_WITH_MASK(name, mask) do { \ if ((current_config->name & (mask)) != (pipe_config->name & (mask))) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected 0x%08x, found 0x%08x)", \ current_config->name & (mask), \ @@ -4943,6 +4947,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_I(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected %i, found %i)", \ current_config->name, \ @@ -4953,6 +4959,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_BOOL(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(!__same_type(current_config->name, bool), \ + __stringify(name) " is not bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected %s, found %s)", \ str_yes_no(current_config->name), \ From c46172c905f8b64ba490a8a30bf678be82c56eb6 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Wed, 15 Nov 2023 14:29:13 +0530 Subject: [PATCH 2050/7721] arm64: dts: ti: k3-am68-sk-base-board: Add alias for MCU CPSW2G Add alias for the MCU CPSW2G port to enable Linux to fetch MAC Address for the port directly from U-Boot. Signed-off-by: Siddharth Vadapalli Reviewed-by: Ravi Gunasekaran Link: https://lore.kernel.org/r/20231115085913.3585740-1-s-vadapalli@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts index 1e1a82f9d2b8..d0cfdeac21fb 100644 --- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts @@ -31,6 +31,7 @@ aliases { can1 = &mcu_mcan1; can2 = &main_mcan6; can3 = &main_mcan7; + ethernet0 = &cpsw_port1; }; vusb_main: regulator-vusb-main5v0 { From 9a9429b9ce975bcc97b45824bdd153bee5bad46c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Nov 2023 23:37:41 +0100 Subject: [PATCH 2051/7721] gpio: ixp4xx: Handle clock output on pin 14 and 15 This makes it possible to provide basic clock output on pins 14 and 15. The clocks are typically used by random electronics, not modeled in the device tree, so they just need to be provided on request. In order to not disturb old systems that require that the hardware defaults are kept in the clock setting bits, we only manipulate these if either device tree property is present. Once we know a device needs one of the clocks we can set it in the device tree. Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ixp4xx.c | 51 +++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index dde6cf3a5779..c5a9fa640566 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -38,6 +38,18 @@ #define IXP4XX_GPIO_STYLE_MASK GENMASK(2, 0) #define IXP4XX_GPIO_STYLE_SIZE 3 +/* + * Clock output control register defines. + */ +#define IXP4XX_GPCLK_CLK0DC_SHIFT 0 +#define IXP4XX_GPCLK_CLK0TC_SHIFT 4 +#define IXP4XX_GPCLK_CLK0_MASK GENMASK(7, 0) +#define IXP4XX_GPCLK_MUX14 BIT(8) +#define IXP4XX_GPCLK_CLK1DC_SHIFT 16 +#define IXP4XX_GPCLK_CLK1TC_SHIFT 20 +#define IXP4XX_GPCLK_CLK1_MASK GENMASK(23, 16) +#define IXP4XX_GPCLK_MUX15 BIT(24) + /** * struct ixp4xx_gpio - IXP4 GPIO state container * @dev: containing device for this instance @@ -202,6 +214,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) struct ixp4xx_gpio *g; struct gpio_irq_chip *girq; struct device_node *irq_parent; + bool clk_14, clk_15; + u32 val; int ret; g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); @@ -225,13 +239,48 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) } g->fwnode = of_node_to_fwnode(np); + /* + * If either clock output is enabled explicitly in the device tree + * we take full control of the clock by masking off all bits for + * the clock control and selectively enabling them. Otherwise + * we leave the hardware default settings. + * + * Enable clock outputs with default timings of requested clock. + * If you need control over TC and DC, add these to the device + * tree bindings and use them here. + */ + clk_14 = of_property_read_bool(np, "intel,ixp4xx-gpio14-clkout"); + clk_15 = of_property_read_bool(np, "intel,ixp4xx-gpio15-clkout"); + /* * Make sure GPIO 14 and 15 are NOT used as clocks but GPIO on * specific machines. */ if (of_machine_is_compatible("dlink,dsm-g600-a") || of_machine_is_compatible("iom,nas-100d")) - __raw_writel(0x0, g->base + IXP4XX_REG_GPCLK); + val = 0; + else { + val = __raw_readl(g->base + IXP4XX_REG_GPCLK); + + if (clk_14 || clk_15) { + val &= ~(IXP4XX_GPCLK_MUX14 | IXP4XX_GPCLK_MUX15); + val &= ~IXP4XX_GPCLK_CLK0_MASK; + val &= ~IXP4XX_GPCLK_CLK1_MASK; + if (clk_14) { + /* IXP4XX_GPCLK_CLK0DC implicit low */ + val |= (1 << IXP4XX_GPCLK_CLK0TC_SHIFT); + val |= IXP4XX_GPCLK_MUX14; + } + + if (clk_15) { + /* IXP4XX_GPCLK_CLK1DC implicit low */ + val |= (1 << IXP4XX_GPCLK_CLK1TC_SHIFT); + val |= IXP4XX_GPCLK_MUX15; + } + } + } + + __raw_writel(val, g->base + IXP4XX_REG_GPCLK); /* * This is a very special big-endian ARM issue: when the IXP4xx is From 7232522e6cafdf466ed7649c14546fd07ccc1978 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 30 Nov 2023 18:56:18 +0200 Subject: [PATCH 2052/7721] fanotify: store fsid in mark instead of in connector Some filesystems like fuse and nfs have zero or non-unique fsid. We would like to avoid reporting ambiguous fsid in events, so we need to avoid marking objects with same fsid and different sb. To make this easier to enforce, store the fsid in the marks of the group instead of in the shared conenctor. Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Message-Id: <20231130165619.3386452-2-amir73il@gmail.com> --- fs/notify/fanotify/fanotify.c | 19 +++-------- fs/notify/fanotify/fanotify.h | 10 ++++++ fs/notify/fanotify/fanotify_user.c | 18 ++++++++--- fs/notify/mark.c | 52 +++++------------------------- include/linux/fsnotify_backend.h | 13 +++----- 5 files changed, 42 insertions(+), 70 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 9dac7f6e72d2..aff1ab3c32aa 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -838,9 +838,8 @@ static struct fanotify_event *fanotify_alloc_event( } /* - * Get cached fsid of the filesystem containing the object from any connector. - * All connectors are supposed to have the same fsid, but we do not verify that - * here. + * Get cached fsid of the filesystem containing the object from any mark. + * All marks are supposed to have the same fsid, but we do not verify that here. */ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) { @@ -849,17 +848,9 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) __kernel_fsid_t fsid = {}; fsnotify_foreach_iter_mark_type(iter_info, mark, type) { - struct fsnotify_mark_connector *conn; - - conn = READ_ONCE(mark->connector); - /* Mark is just getting destroyed or created? */ - if (!conn) + if (!(mark->flags & FSNOTIFY_MARK_FLAG_HAS_FSID)) continue; - if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) - continue; - /* Pairs with smp_wmb() in fsnotify_add_mark_list() */ - smp_rmb(); - fsid = conn->fsid; + fsid = FANOTIFY_MARK(mark)->fsid; if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) continue; return fsid; @@ -1068,7 +1059,7 @@ static void fanotify_freeing_mark(struct fsnotify_mark *mark, static void fanotify_free_mark(struct fsnotify_mark *fsn_mark) { - kmem_cache_free(fanotify_mark_cache, fsn_mark); + kmem_cache_free(fanotify_mark_cache, FANOTIFY_MARK(fsn_mark)); } const struct fsnotify_ops fanotify_fsnotify_ops = { diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 6936671e148d..f3b9ef60f0c0 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -489,6 +489,16 @@ static inline unsigned int fanotify_event_hash_bucket( return event->hash & FANOTIFY_HTABLE_MASK; } +struct fanotify_mark { + struct fsnotify_mark fsn_mark; + __kernel_fsid_t fsid; +}; + +static inline struct fanotify_mark *FANOTIFY_MARK(struct fsnotify_mark *mark) +{ + return container_of(mark, struct fanotify_mark, fsn_mark); +} + static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) { unsigned int mflags = 0; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 4d765c72496f..e3d836d4d156 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -1199,6 +1199,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, __kernel_fsid_t *fsid) { struct ucounts *ucounts = group->fanotify_data.ucounts; + struct fanotify_mark *fan_mark; struct fsnotify_mark *mark; int ret; @@ -1211,17 +1212,26 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, !inc_ucount(ucounts->ns, ucounts->uid, UCOUNT_FANOTIFY_MARKS)) return ERR_PTR(-ENOSPC); - mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); - if (!mark) { + fan_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); + if (!fan_mark) { ret = -ENOMEM; goto out_dec_ucounts; } + mark = &fan_mark->fsn_mark; fsnotify_init_mark(mark, group); if (fan_flags & FAN_MARK_EVICTABLE) mark->flags |= FSNOTIFY_MARK_FLAG_NO_IREF; - ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid); + /* Cache fsid of filesystem containing the marked object */ + if (fsid) { + fan_mark->fsid = *fsid; + mark->flags |= FSNOTIFY_MARK_FLAG_HAS_FSID; + } else { + fan_mark->fsid.val[0] = fan_mark->fsid.val[1] = 0; + } + + ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0); if (ret) { fsnotify_put_mark(mark); goto out_dec_ucounts; @@ -1935,7 +1945,7 @@ static int __init fanotify_user_setup(void) BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11); - fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, + fanotify_mark_cache = KMEM_CACHE(fanotify_mark, SLAB_PANIC|SLAB_ACCOUNT); fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event, SLAB_PANIC); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index c74ef947447d..d6944ff86ffa 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -537,8 +537,7 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) } static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, - unsigned int obj_type, - __kernel_fsid_t *fsid) + unsigned int obj_type) { struct fsnotify_mark_connector *conn; @@ -550,14 +549,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, conn->flags = 0; conn->type = obj_type; conn->obj = connp; - /* Cache fsid of filesystem containing the object */ - if (fsid) { - conn->fsid = *fsid; - conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID; - } else { - conn->fsid.val[0] = conn->fsid.val[1] = 0; - conn->flags = 0; - } + conn->flags = 0; fsnotify_get_sb_connectors(conn); /* @@ -608,8 +600,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector( */ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, fsnotify_connp_t *connp, - unsigned int obj_type, - int add_flags, __kernel_fsid_t *fsid) + unsigned int obj_type, int add_flags) { struct fsnotify_mark *lmark, *last = NULL; struct fsnotify_mark_connector *conn; @@ -619,41 +610,15 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, if (WARN_ON(!fsnotify_valid_obj_type(obj_type))) return -EINVAL; - /* Backend is expected to check for zero fsid (e.g. tmpfs) */ - if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1])) - return -ENODEV; - restart: spin_lock(&mark->lock); conn = fsnotify_grab_connector(connp); if (!conn) { spin_unlock(&mark->lock); - err = fsnotify_attach_connector_to_object(connp, obj_type, - fsid); + err = fsnotify_attach_connector_to_object(connp, obj_type); if (err) return err; goto restart; - } else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) { - conn->fsid = *fsid; - /* Pairs with smp_rmb() in fanotify_get_fsid() */ - smp_wmb(); - conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID; - } else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) && - (fsid->val[0] != conn->fsid.val[0] || - fsid->val[1] != conn->fsid.val[1])) { - /* - * Backend is expected to check for non uniform fsid - * (e.g. btrfs), but maybe we missed something? - * Only allow setting conn->fsid once to non zero fsid. - * inotify and non-fid fanotify groups do not set nor test - * conn->fsid. - */ - pr_warn_ratelimited("%s: fsid mismatch on object of type %u: " - "%x.%x != %x.%x\n", __func__, conn->type, - fsid->val[0], fsid->val[1], - conn->fsid.val[0], conn->fsid.val[1]); - err = -EXDEV; - goto out_err; } /* is mark the first mark? */ @@ -703,7 +668,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, */ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, fsnotify_connp_t *connp, unsigned int obj_type, - int add_flags, __kernel_fsid_t *fsid) + int add_flags) { struct fsnotify_group *group = mark->group; int ret = 0; @@ -723,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, fsnotify_get_mark(mark); /* for g_list */ spin_unlock(&mark->lock); - ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags, fsid); + ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags); if (ret) goto err; @@ -742,14 +707,13 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, } int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, - unsigned int obj_type, int add_flags, - __kernel_fsid_t *fsid) + unsigned int obj_type, int add_flags) { int ret; struct fsnotify_group *group = mark->group; fsnotify_group_lock(group); - ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags, fsid); + ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags); fsnotify_group_unlock(group); return ret; } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index c0892d75ce33..a80b525ca653 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -472,10 +472,8 @@ typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t; struct fsnotify_mark_connector { spinlock_t lock; unsigned short type; /* Type of object [lock] */ -#define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01 #define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02 unsigned short flags; /* flags [lock] */ - __kernel_fsid_t fsid; /* fsid of filesystem containing object */ union { /* Object pointer [lock] */ fsnotify_connp_t *obj; @@ -530,6 +528,7 @@ struct fsnotify_mark { #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 #define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400 +#define FSNOTIFY_MARK_FLAG_HAS_FSID 0x0800 unsigned int flags; /* flags [mark->lock] */ }; @@ -763,11 +762,10 @@ extern struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp, /* attach the mark to the object */ extern int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, unsigned int obj_type, - int add_flags, __kernel_fsid_t *fsid); + int add_flags); extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, fsnotify_connp_t *connp, - unsigned int obj_type, int add_flags, - __kernel_fsid_t *fsid); + unsigned int obj_type, int add_flags); /* attach the mark to the inode */ static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark, @@ -775,15 +773,14 @@ static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark, int add_flags) { return fsnotify_add_mark(mark, &inode->i_fsnotify_marks, - FSNOTIFY_OBJ_TYPE_INODE, add_flags, NULL); + FSNOTIFY_OBJ_TYPE_INODE, add_flags); } static inline int fsnotify_add_inode_mark_locked(struct fsnotify_mark *mark, struct inode *inode, int add_flags) { return fsnotify_add_mark_locked(mark, &inode->i_fsnotify_marks, - FSNOTIFY_OBJ_TYPE_INODE, add_flags, - NULL); + FSNOTIFY_OBJ_TYPE_INODE, add_flags); } /* given a group and a mark, flag mark to be freed when all references are dropped */ From 30ad1938326bf9303ca38090339d948975a626f5 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Thu, 30 Nov 2023 18:56:19 +0200 Subject: [PATCH 2053/7721] fanotify: allow "weak" fsid when watching a single filesystem So far, fanotify returns -ENODEV or -EXDEV when trying to set a mark on a filesystem with a "weak" fsid, namely, zero fsid (e.g. fuse), or non-uniform fsid (e.g. btrfs non-root subvol). When group is watching inodes all from the same filesystem (or subvol), allow adding inode marks with "weak" fsid, because there is no ambiguity regarding which filesystem reports the event. The first mark added to a group determines if this group is single or multi filesystem, depending on the fsid at the path of the added mark. If the first mark added has a "strong" fsid, marks with "weak" fsid cannot be added and vice versa. If the first mark added has a "weak" fsid, following marks must have the same "weak" fsid and the same sb as the first mark. Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Message-Id: <20231130165619.3386452-3-amir73il@gmail.com> --- fs/notify/fanotify/fanotify.c | 15 +--- fs/notify/fanotify/fanotify.h | 6 ++ fs/notify/fanotify/fanotify_user.c | 112 +++++++++++++++++++++++------ include/linux/fsnotify_backend.h | 1 + 4 files changed, 101 insertions(+), 33 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index aff1ab3c32aa..1e4def21811e 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -29,12 +29,6 @@ static unsigned int fanotify_hash_path(const struct path *path) hash_ptr(path->mnt, FANOTIFY_EVENT_HASH_BITS); } -static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, - __kernel_fsid_t *fsid2) -{ - return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1]; -} - static unsigned int fanotify_hash_fsid(__kernel_fsid_t *fsid) { return hash_32(fsid->val[0], FANOTIFY_EVENT_HASH_BITS) ^ @@ -851,7 +845,8 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) if (!(mark->flags & FSNOTIFY_MARK_FLAG_HAS_FSID)) continue; fsid = FANOTIFY_MARK(mark)->fsid; - if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) + if (!(mark->flags & FSNOTIFY_MARK_FLAG_WEAK_FSID) && + WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) continue; return fsid; } @@ -933,12 +928,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, return 0; } - if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) { + if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) fsid = fanotify_get_fsid(iter_info); - /* Racing with mark destruction or creation? */ - if (!fsid.val[0] && !fsid.val[1]) - return 0; - } event = fanotify_alloc_event(group, mask, data, data_type, dir, file_name, &fsid, match_mask); diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index f3b9ef60f0c0..e5ab33cae6a7 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -499,6 +499,12 @@ static inline struct fanotify_mark *FANOTIFY_MARK(struct fsnotify_mark *mark) return container_of(mark, struct fanotify_mark, fsn_mark); } +static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, + __kernel_fsid_t *fsid2) +{ + return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1]; +} + static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) { unsigned int mflags = 0; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index e3d836d4d156..f83e7cc5ccf2 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -23,7 +23,7 @@ #include -#include "../../mount.h" +#include "../fsnotify.h" #include "../fdinfo.h" #include "fanotify.h" @@ -1192,11 +1192,68 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, return recalc; } +struct fan_fsid { + struct super_block *sb; + __kernel_fsid_t id; + bool weak; +}; + +static int fanotify_set_mark_fsid(struct fsnotify_group *group, + struct fsnotify_mark *mark, + struct fan_fsid *fsid) +{ + struct fsnotify_mark_connector *conn; + struct fsnotify_mark *old; + struct super_block *old_sb = NULL; + + FANOTIFY_MARK(mark)->fsid = fsid->id; + mark->flags |= FSNOTIFY_MARK_FLAG_HAS_FSID; + if (fsid->weak) + mark->flags |= FSNOTIFY_MARK_FLAG_WEAK_FSID; + + /* First mark added will determine if group is single or multi fsid */ + if (list_empty(&group->marks_list)) + return 0; + + /* Find sb of an existing mark */ + list_for_each_entry(old, &group->marks_list, g_list) { + conn = READ_ONCE(old->connector); + if (!conn) + continue; + old_sb = fsnotify_connector_sb(conn); + if (old_sb) + break; + } + + /* Only detached marks left? */ + if (!old_sb) + return 0; + + /* Do not allow mixing of marks with weak and strong fsid */ + if ((mark->flags ^ old->flags) & FSNOTIFY_MARK_FLAG_WEAK_FSID) + return -EXDEV; + + /* Allow mixing of marks with strong fsid from different fs */ + if (!fsid->weak) + return 0; + + /* Do not allow mixing marks with weak fsid from different fs */ + if (old_sb != fsid->sb) + return -EXDEV; + + /* Do not allow mixing marks from different btrfs sub-volumes */ + if (!fanotify_fsid_equal(&FANOTIFY_MARK(old)->fsid, + &FANOTIFY_MARK(mark)->fsid)) + return -EXDEV; + + return 0; +} + static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, fsnotify_connp_t *connp, unsigned int obj_type, unsigned int fan_flags, - __kernel_fsid_t *fsid) + struct fan_fsid *fsid) { struct ucounts *ucounts = group->fanotify_data.ucounts; struct fanotify_mark *fan_mark; @@ -1225,20 +1282,21 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, /* Cache fsid of filesystem containing the marked object */ if (fsid) { - fan_mark->fsid = *fsid; - mark->flags |= FSNOTIFY_MARK_FLAG_HAS_FSID; + ret = fanotify_set_mark_fsid(group, mark, fsid); + if (ret) + goto out_put_mark; } else { fan_mark->fsid.val[0] = fan_mark->fsid.val[1] = 0; } ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0); - if (ret) { - fsnotify_put_mark(mark); - goto out_dec_ucounts; - } + if (ret) + goto out_put_mark; return mark; +out_put_mark: + fsnotify_put_mark(mark); out_dec_ucounts: if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS)) dec_ucount(ucounts, UCOUNT_FANOTIFY_MARKS); @@ -1289,7 +1347,7 @@ static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark, static int fanotify_add_mark(struct fsnotify_group *group, fsnotify_connp_t *connp, unsigned int obj_type, __u32 mask, unsigned int fan_flags, - __kernel_fsid_t *fsid) + struct fan_fsid *fsid) { struct fsnotify_mark *fsn_mark; bool recalc; @@ -1337,7 +1395,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt, __u32 mask, - unsigned int flags, __kernel_fsid_t *fsid) + unsigned int flags, struct fan_fsid *fsid) { return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid); @@ -1345,7 +1403,7 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, static int fanotify_add_sb_mark(struct fsnotify_group *group, struct super_block *sb, __u32 mask, - unsigned int flags, __kernel_fsid_t *fsid) + unsigned int flags, struct fan_fsid *fsid) { return fanotify_add_mark(group, &sb->s_fsnotify_marks, FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid); @@ -1353,7 +1411,7 @@ static int fanotify_add_sb_mark(struct fsnotify_group *group, static int fanotify_add_inode_mark(struct fsnotify_group *group, struct inode *inode, __u32 mask, - unsigned int flags, __kernel_fsid_t *fsid) + unsigned int flags, struct fan_fsid *fsid) { pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); @@ -1564,20 +1622,25 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) return fd; } -static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid) +static int fanotify_test_fsid(struct dentry *dentry, unsigned int flags, + struct fan_fsid *fsid) { + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; __kernel_fsid_t root_fsid; int err; /* * Make sure dentry is not of a filesystem with zero fsid (e.g. fuse). */ - err = vfs_get_fsid(dentry, fsid); + err = vfs_get_fsid(dentry, &fsid->id); if (err) return err; - if (!fsid->val[0] && !fsid->val[1]) - return -ENODEV; + fsid->sb = dentry->d_sb; + if (!fsid->id.val[0] && !fsid->id.val[1]) { + err = -ENODEV; + goto weak; + } /* * Make sure dentry is not of a filesystem subvolume (e.g. btrfs) @@ -1587,11 +1650,18 @@ static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid) if (err) return err; - if (root_fsid.val[0] != fsid->val[0] || - root_fsid.val[1] != fsid->val[1]) - return -EXDEV; + if (!fanotify_fsid_equal(&root_fsid, &fsid->id)) { + err = -EXDEV; + goto weak; + } + fsid->weak = false; return 0; + +weak: + /* Allow weak fsid when marking inodes */ + fsid->weak = true; + return (mark_type == FAN_MARK_INODE) ? 0 : err; } /* Check if filesystem can encode a unique fid */ @@ -1675,7 +1745,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, struct fsnotify_group *group; struct fd f; struct path path; - __kernel_fsid_t __fsid, *fsid = NULL; + struct fan_fsid __fsid, *fsid = NULL; u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS; @@ -1827,7 +1897,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, } if (fid_mode) { - ret = fanotify_test_fsid(path.dentry, &__fsid); + ret = fanotify_test_fsid(path.dentry, flags, &__fsid); if (ret) goto path_put_and_out; diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index a80b525ca653..7f63be5ca0f1 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -529,6 +529,7 @@ struct fsnotify_mark { #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 #define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400 #define FSNOTIFY_MARK_FLAG_HAS_FSID 0x0800 +#define FSNOTIFY_MARK_FLAG_WEAK_FSID 0x1000 unsigned int flags; /* flags [mark->lock] */ }; From 8a0d929b53c383ba678ed65742e4a8982f71d5c0 Mon Sep 17 00:00:00 2001 From: Jia Jie Ho Date: Mon, 20 Nov 2023 11:12:42 +0800 Subject: [PATCH 2054/7721] crypto: starfive - Pad adata with zeroes Aad requires padding with zeroes up to 15 bytes in some cases. This patch increases the allocated buffer size for aad and prevents the driver accessing uninitialized memory region. v1->v2: Specify reason for alloc size change in descriptions. Signed-off-by: Jia Jie Ho Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-aes.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c index 9378e6682f0e..e0fe599f8192 100644 --- a/drivers/crypto/starfive/jh7110-aes.c +++ b/drivers/crypto/starfive/jh7110-aes.c @@ -500,7 +500,7 @@ static int starfive_aes_prepare_req(struct skcipher_request *req, scatterwalk_start(&cryp->out_walk, rctx->out_sg); if (cryp->assoclen) { - rctx->adata = kzalloc(ALIGN(cryp->assoclen, AES_BLOCK_SIZE), GFP_KERNEL); + rctx->adata = kzalloc(cryp->assoclen + AES_BLOCK_SIZE, GFP_KERNEL); if (!rctx->adata) return dev_err_probe(cryp->dev, -ENOMEM, "Failed to alloc memory for adata"); @@ -569,7 +569,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq struct starfive_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); struct starfive_cryp_dev *cryp = ctx->cryp; - struct starfive_cryp_request_ctx *rctx = ctx->rctx; + struct starfive_cryp_request_ctx *rctx; u32 block[AES_BLOCK_32]; u32 stat; int err; @@ -579,6 +579,8 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq if (err) return err; + rctx = ctx->rctx; + if (!cryp->assoclen) goto write_text; From fed93fb62e05c38152b0fc1dc9609639e63eed76 Mon Sep 17 00:00:00 2001 From: "Gonglei (Arei)" Date: Mon, 20 Nov 2023 11:49:45 +0000 Subject: [PATCH 2055/7721] crypto: virtio - Handle dataq logic with tasklet Doing ipsec produces a spinlock recursion warning. This is due to crypto_finalize_request() being called in the upper half. Move virtual data queue processing of virtio-crypto driver to tasklet. Fixes: dbaf0624ffa57 ("crypto: add virtio-crypto driver") Reported-by: Halil Pasic Signed-off-by: wangyangxin Signed-off-by: Gonglei Signed-off-by: Herbert Xu --- drivers/crypto/virtio/virtio_crypto_common.h | 2 ++ drivers/crypto/virtio/virtio_crypto_core.c | 23 +++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h index 154590e1f764..7059bbe5a2eb 100644 --- a/drivers/crypto/virtio/virtio_crypto_common.h +++ b/drivers/crypto/virtio/virtio_crypto_common.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ struct data_queue { char name[32]; struct crypto_engine *engine; + struct tasklet_struct done_task; }; struct virtio_crypto { diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index 43a0838d31ff..428d76562447 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -72,27 +72,28 @@ int virtio_crypto_ctrl_vq_request(struct virtio_crypto *vcrypto, struct scatterl return 0; } -static void virtcrypto_dataq_callback(struct virtqueue *vq) +static void virtcrypto_done_task(unsigned long data) { - struct virtio_crypto *vcrypto = vq->vdev->priv; + struct data_queue *data_vq = (struct data_queue *)data; + struct virtqueue *vq = data_vq->vq; struct virtio_crypto_request *vc_req; - unsigned long flags; unsigned int len; - unsigned int qid = vq->index; - spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags); do { virtqueue_disable_cb(vq); while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) { - spin_unlock_irqrestore( - &vcrypto->data_vq[qid].lock, flags); if (vc_req->alg_cb) vc_req->alg_cb(vc_req, len); - spin_lock_irqsave( - &vcrypto->data_vq[qid].lock, flags); } } while (!virtqueue_enable_cb(vq)); - spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags); +} + +static void virtcrypto_dataq_callback(struct virtqueue *vq) +{ + struct virtio_crypto *vcrypto = vq->vdev->priv; + struct data_queue *dq = &vcrypto->data_vq[vq->index]; + + tasklet_schedule(&dq->done_task); } static int virtcrypto_find_vqs(struct virtio_crypto *vi) @@ -150,6 +151,8 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) ret = -ENOMEM; goto err_engine; } + tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task, + (unsigned long)&vi->data_vq[i]); } kfree(names); From 2d37b3649c412b3bcecfea932cb677f7a5775b15 Mon Sep 17 00:00:00 2001 From: Jia Jie Ho Date: Mon, 20 Nov 2023 23:11:21 +0800 Subject: [PATCH 2056/7721] hwrng: starfive - Fix dev_err_probe return error Current dev_err_probe will return 0 instead of proper error code if driver failed to get irq number. Fix the return err code. Signed-off-by: Jia Jie Ho Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202311160649.3GhKCfhd-lkp@intel.com/ Signed-off-by: Herbert Xu --- drivers/char/hw_random/jh7110-trng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/jh7110-trng.c b/drivers/char/hw_random/jh7110-trng.c index 38474d48a25e..b1f94e3c0c6a 100644 --- a/drivers/char/hw_random/jh7110-trng.c +++ b/drivers/char/hw_random/jh7110-trng.c @@ -300,7 +300,7 @@ static int starfive_trng_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, starfive_trng_irq, 0, pdev->name, (void *)trng); if (ret) - return dev_err_probe(&pdev->dev, irq, + return dev_err_probe(&pdev->dev, ret, "Failed to register interrupt handler\n"); trng->hclk = devm_clk_get(&pdev->dev, "hclk"); From 65089000ba8c2ae713ccac6603319143f3e1c08b Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Tue, 21 Nov 2023 17:59:45 +0100 Subject: [PATCH 2057/7721] crypto: qat - add sysfs_added flag for ras The qat_ras sysfs attribute group is registered within the adf_dev_start() function, alongside other driver components. If any of the functions preceding the group registration fails, the adf_dev_start() function returns, and the caller, to undo the operation, invokes adf_dev_stop() followed by adf_dev_shutdown(). However, the current flow lacks information about whether the registration of the qat_ras attribute group was successful or not. In cases where this condition is encountered, an error similar to the following might be reported: 4xxx 0000:6b:00.0: Starting device qat_dev0 4xxx 0000:6b:00.0: qat_dev0 started 9 acceleration engines 4xxx 0000:6b:00.0: Failed to send init message 4xxx 0000:6b:00.0: Failed to start device qat_dev0 sysfs group 'qat_ras' not found for kobject '0000:6b:00.0' ... sysfs_remove_groups+0x29/0x50 adf_sysfs_stop_ras+0x4b/0x80 [intel_qat] adf_dev_stop+0x43/0x1d0 [intel_qat] adf_dev_down+0x4b/0x150 [intel_qat] ... 4xxx 0000:6b:00.0: qat_dev0 stopped 9 acceleration engines 4xxx 0000:6b:00.0: Resetting device qat_dev0 To prevent attempting to remove attributes from a group that has not been added yet, a flag named 'sysfs_added' is introduced. This flag is set to true upon the successful registration of the attribute group. Fixes: 532d7f6bc458 ("crypto: qat - add error counters") Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_accel_devices.h | 1 + .../crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index 4ff5729a3496..9d5fdd529a2e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -92,6 +92,7 @@ enum ras_errors { struct adf_error_counters { atomic_t counter[ADF_RAS_ERRORS]; + bool sysfs_added; bool enabled; }; diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c index cffe2d722995..e97c67c87b3c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c @@ -99,6 +99,8 @@ void adf_sysfs_start_ras(struct adf_accel_dev *accel_dev) if (device_add_group(&GET_DEV(accel_dev), &qat_ras_group)) dev_err(&GET_DEV(accel_dev), "Failed to create qat_ras attribute group.\n"); + + accel_dev->ras_errors.sysfs_added = true; } void adf_sysfs_stop_ras(struct adf_accel_dev *accel_dev) @@ -106,7 +108,10 @@ void adf_sysfs_stop_ras(struct adf_accel_dev *accel_dev) if (!accel_dev->ras_errors.enabled) return; - device_remove_group(&GET_DEV(accel_dev), &qat_ras_group); + if (accel_dev->ras_errors.sysfs_added) { + device_remove_group(&GET_DEV(accel_dev), &qat_ras_group); + accel_dev->ras_errors.sysfs_added = false; + } ADF_RAS_ERR_CTR_CLEAR(accel_dev->ras_errors); } From d71fdd0f3c278c7f132c3a522645ebf9157edd6d Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Tue, 21 Nov 2023 18:02:23 +0100 Subject: [PATCH 2058/7721] crypto: qat - add sysfs_added flag for rate limiting The qat_rl sysfs attribute group is registered within the adf_dev_start() function, alongside other driver components. If any of the functions preceding the group registration fails, the adf_dev_start() function returns, and the caller, to undo the operation, invokes adf_dev_stop() followed by adf_dev_shutdown(). However, the current flow lacks information about whether the registration of the qat_rl attribute group was successful or not. In cases where this condition is encountered, an error similar to the following might be reported: 4xxx 0000:6b:00.0: Starting device qat_dev0 4xxx 0000:6b:00.0: qat_dev0 started 9 acceleration engines 4xxx 0000:6b:00.0: Failed to send init message 4xxx 0000:6b:00.0: Failed to start device qat_dev0 sysfs group 'qat_rl' not found for kobject '0000:6b:00.0' ... sysfs_remove_groups+0x2d/0x50 adf_sysfs_rl_rm+0x44/0x70 [intel_qat] adf_rl_stop+0x2d/0xb0 [intel_qat] adf_dev_stop+0x33/0x1d0 [intel_qat] adf_dev_down+0xf1/0x150 [intel_qat] ... 4xxx 0000:6b:00.0: qat_dev0 stopped 9 acceleration engines 4xxx 0000:6b:00.0: Resetting device qat_dev0 To prevent attempting to remove attributes from a group that has not been added yet, a flag named 'sysfs_added' is introduced. This flag is set to true upon the successful registration of the attribute group. Fixes: d9fb8408376e ("crypto: qat - add rate limiting feature to qat_4xxx") Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_rl.h | 1 + drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.h b/drivers/crypto/intel/qat/qat_common/adf_rl.h index eb5a330f8543..269c6656fb90 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.h +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.h @@ -79,6 +79,7 @@ struct adf_rl_interface_data { struct adf_rl_sla_input_data input; enum adf_base_services cap_rem_srv; struct rw_semaphore lock; + bool sysfs_added; }; struct adf_rl_hw_data { diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c index abf9c52474ec..bedb514d4e30 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c @@ -441,11 +441,19 @@ int adf_sysfs_rl_add(struct adf_accel_dev *accel_dev) data->cap_rem_srv = ADF_SVC_NONE; data->input.srv = ADF_SVC_NONE; + data->sysfs_added = true; return ret; } void adf_sysfs_rl_rm(struct adf_accel_dev *accel_dev) { + struct adf_rl_interface_data *data; + + data = &GET_RL_STRUCT(accel_dev); + if (!data->sysfs_added) + return; + device_remove_group(&GET_DEV(accel_dev), &qat_rl_group); + data->sysfs_added = false; } From aaa03fdb56c781db4a4831dd5d6ec8817918c726 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 21 Nov 2023 12:52:44 -0600 Subject: [PATCH 2059/7721] crypto: p10-aes-gcm - Avoid -Wstringop-overflow warnings The compiler doesn't know that `32` is an offset into the Hash table: 56 struct Hash_ctx { 57 u8 H[16]; /* subkey */ 58 u8 Htable[256]; /* Xi, Hash table(offset 32) */ 59 }; So, it legitimately complains about a potential out-of-bounds issue if `256 bytes` are accessed in `htable` (this implies going `32 bytes` beyond the boundaries of `Htable`): arch/powerpc/crypto/aes-gcm-p10-glue.c: In function 'gcmp10_init': arch/powerpc/crypto/aes-gcm-p10-glue.c:120:9: error: 'gcm_init_htable' accessing 256 bytes in a region of size 224 [-Werror=stringop-overflow=] 120 | gcm_init_htable(hash->Htable+32, hash->H); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arch/powerpc/crypto/aes-gcm-p10-glue.c:120:9: note: referencing argument 1 of type 'unsigned char[256]' arch/powerpc/crypto/aes-gcm-p10-glue.c:120:9: note: referencing argument 2 of type 'unsigned char[16]' arch/powerpc/crypto/aes-gcm-p10-glue.c:40:17: note: in a call to function 'gcm_init_htable' 40 | asmlinkage void gcm_init_htable(unsigned char htable[256], unsigned char Xi[16]); | ^~~~~~~~~~~~~~~ Address this by avoiding specifying the size of `htable` in the function prototype; and just for consistency, do the same for parameter `Xi`. Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-next/20231121131903.68a37932@canb.auug.org.au/ Signed-off-by: Gustavo A. R. Silva Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-gcm-p10-glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/crypto/aes-gcm-p10-glue.c b/arch/powerpc/crypto/aes-gcm-p10-glue.c index 4b6e899895e7..f62ee54076c0 100644 --- a/arch/powerpc/crypto/aes-gcm-p10-glue.c +++ b/arch/powerpc/crypto/aes-gcm-p10-glue.c @@ -37,7 +37,7 @@ asmlinkage void aes_p10_gcm_encrypt(u8 *in, u8 *out, size_t len, void *rkey, u8 *iv, void *Xi); asmlinkage void aes_p10_gcm_decrypt(u8 *in, u8 *out, size_t len, void *rkey, u8 *iv, void *Xi); -asmlinkage void gcm_init_htable(unsigned char htable[256], unsigned char Xi[16]); +asmlinkage void gcm_init_htable(unsigned char htable[], unsigned char Xi[]); asmlinkage void gcm_ghash_p10(unsigned char *Xi, unsigned char *Htable, unsigned char *aad, unsigned int alen); From a9864bae1806499ebf3757a9e71dddde5b9c48c6 Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Fri, 24 Nov 2023 13:49:24 +0800 Subject: [PATCH 2060/7721] crypto: hisilicon/zip - add zip comp high perf mode configuration To meet specific application scenarios, the function of switching between the high performance mode and the high compression mode is added. Use the perf_mode=0/1 configuration to set the compression high perf mode, 0(default, high compression mode), 1(high performance mode). These two modes only apply to the compression direction and are compatible with software algorithm in both directions. Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_main.c | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index d6672b777efc..07ab61c113ab 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -107,6 +107,14 @@ #define HZIP_CLOCK_GATED_EN (HZIP_CORE_GATED_EN | \ HZIP_CORE_GATED_OOO_EN) +/* zip comp high performance */ +#define HZIP_HIGH_PERF_OFFSET 0x301208 + +enum { + HZIP_HIGH_COMP_RATE, + HZIP_HIGH_COMP_PERF, +}; + static const char hisi_zip_name[] = "hisi_zip"; static struct dentry *hzip_debugfs_root; @@ -352,6 +360,37 @@ static int hzip_diff_regs_show(struct seq_file *s, void *unused) return 0; } DEFINE_SHOW_ATTRIBUTE(hzip_diff_regs); + +static int perf_mode_set(const char *val, const struct kernel_param *kp) +{ + int ret; + u32 n; + + if (!val) + return -EINVAL; + + ret = kstrtou32(val, 10, &n); + if (ret != 0 || (n != HZIP_HIGH_COMP_PERF && + n != HZIP_HIGH_COMP_RATE)) + return -EINVAL; + + return param_set_int(val, kp); +} + +static const struct kernel_param_ops zip_com_perf_ops = { + .set = perf_mode_set, + .get = param_get_int, +}; + +/* + * perf_mode = 0 means enable high compression rate mode, + * perf_mode = 1 means enable high compression performance mode. + * These two modes only apply to the compression direction. + */ +static u32 perf_mode = HZIP_HIGH_COMP_RATE; +module_param_cb(perf_mode, &zip_com_perf_ops, &perf_mode, 0444); +MODULE_PARM_DESC(perf_mode, "ZIP high perf mode 0(default), 1(enable)"); + static const struct kernel_param_ops zip_uacce_mode_ops = { .set = uacce_mode_set, .get = param_get_int, @@ -417,6 +456,28 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) return false; } +static int hisi_zip_set_high_perf(struct hisi_qm *qm) +{ + u32 val; + int ret; + + val = readl_relaxed(qm->io_base + HZIP_HIGH_PERF_OFFSET); + if (perf_mode == HZIP_HIGH_COMP_PERF) + val |= HZIP_HIGH_COMP_PERF; + else + val &= ~HZIP_HIGH_COMP_PERF; + + /* Set perf mode */ + writel(val, qm->io_base + HZIP_HIGH_PERF_OFFSET); + ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_HIGH_PERF_OFFSET, + val, val == perf_mode, HZIP_DELAY_1_US, + HZIP_POLL_TIMEOUT_US); + if (ret) + pci_err(qm->pdev, "failed to set perf mode\n"); + + return ret; +} + static int hisi_zip_set_qm_algs(struct hisi_qm *qm) { struct device *dev = &qm->pdev->dev; @@ -1115,6 +1176,10 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) if (ret) return ret; + ret = hisi_zip_set_high_perf(qm); + if (ret) + return ret; + hisi_zip_open_sva_prefetch(qm); hisi_qm_dev_err_init(qm); hisi_zip_debug_regs_clear(qm); From fb4ac519c6caf5fdfcc30ef838cae55dbc919e2e Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 25 Nov 2023 19:50:09 +0800 Subject: [PATCH 2061/7721] crypto: hisilicon/sgl - small cleanups for sgl.c 1. Remove unnecessary brackets in function hisi_acc_create_sgl_pool(). 2. Modify local variable type, ensure that the variable type is consistent with the variable type to be compared. 3. Because the function clear_hw_sgl_sge() is in the task process, obtain the value of le16_to_cpu(hw_sgl->entry_sum_in_sgl) before loop execting to shorten the loop execution time. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sgl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c index 3df7a256e919..4b2cd6736df7 100644 --- a/drivers/crypto/hisilicon/sgl.c +++ b/drivers/crypto/hisilicon/sgl.c @@ -121,10 +121,10 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, return pool; err_free_mem: - for (j = 0; j < i; j++) { + for (j = 0; j < i; j++) dma_free_coherent(dev, block_size, block[j].sgl, block[j].sgl_dma); - } + kfree_sensitive(pool); return ERR_PTR(-ENOMEM); } @@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool); void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool) { struct mem_block *block; - int i; + u32 i; if (!dev || !pool) return; @@ -196,9 +196,10 @@ static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum) static void clear_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl) { struct acc_hw_sge *hw_sge = hw_sgl->sge_entries; + u16 entry_sum = le16_to_cpu(hw_sgl->entry_sum_in_sgl); int i; - for (i = 0; i < le16_to_cpu(hw_sgl->entry_sum_in_sgl); i++) { + for (i = 0; i < entry_sum; i++) { hw_sge[i].page_ctrl = NULL; hw_sge[i].buf = 0; hw_sge[i].len = 0; @@ -223,10 +224,11 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, u32 index, dma_addr_t *hw_sgl_dma) { struct hisi_acc_hw_sgl *curr_hw_sgl; + unsigned int i, sg_n_mapped; dma_addr_t curr_sgl_dma = 0; struct acc_hw_sge *curr_hw_sge; struct scatterlist *sg; - int i, sg_n, sg_n_mapped; + int sg_n; if (!dev || !sgl || !pool || !hw_sgl_dma) return ERR_PTR(-EINVAL); From c66272a4c9932d6c585eef99039747617d48d662 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 25 Nov 2023 19:50:10 +0800 Subject: [PATCH 2062/7721] crypto: hisilicon/qm - simplify the status of qm The 'QM_INIT' and 'QM_CLOSE' status of qm and 'QP_INIT' and 'QP_CLOSE' status of queue are not actually used. Currently, driver only needs to switch status when the device or queue is enabled or stopped, Therefore, remove unneeded status to simplify driver. In addition, rename'QM_START to'QM_WORK' for ease to understand. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- Documentation/ABI/testing/debugfs-hisi-hpre | 2 +- Documentation/ABI/testing/debugfs-hisi-sec | 2 +- Documentation/ABI/testing/debugfs-hisi-zip | 2 +- drivers/crypto/hisilicon/debugfs.c | 4 + drivers/crypto/hisilicon/qm.c | 130 +++----------------- drivers/crypto/hisilicon/qm_common.h | 4 - include/linux/hisi_acc_qm.h | 8 +- 7 files changed, 25 insertions(+), 127 deletions(-) diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre index 82abf92df429..8e8de49c5cc6 100644 --- a/Documentation/ABI/testing/debugfs-hisi-hpre +++ b/Documentation/ABI/testing/debugfs-hisi-hpre @@ -101,7 +101,7 @@ What: /sys/kernel/debug/hisi_hpre//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on HPRE. What: /sys/kernel/debug/hisi_hpre//qm/diff_regs diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec index 93c530d1bf0f..deeefe2c735e 100644 --- a/Documentation/ABI/testing/debugfs-hisi-sec +++ b/Documentation/ABI/testing/debugfs-hisi-sec @@ -81,7 +81,7 @@ What: /sys/kernel/debug/hisi_sec2//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on SEC. What: /sys/kernel/debug/hisi_sec2//qm/diff_regs diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip index fd3f314cf8d1..593714afaed2 100644 --- a/Documentation/ABI/testing/debugfs-hisi-zip +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -94,7 +94,7 @@ What: /sys/kernel/debug/hisi_zip//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on ZIP. What: /sys/kernel/debug/hisi_zip//qm/diff_regs diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 415139b4abc1..80ed4b2d209c 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -31,6 +31,10 @@ static const char * const qm_debug_file_name[] = { [CLEAR_ENABLE] = "clear_enable", }; +static const char * const qm_s[] = { + "work", "stop", +}; + struct qm_dfx_item { const char *name; u32 offset; diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 4d91a249be74..7d22412774ba 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -402,10 +402,6 @@ static const char * const qm_fifo_overflow[] = { "cq", "eq", "aeq", }; -static const char * const qp_s[] = { - "none", "init", "start", "stop", "close", -}; - struct qm_typical_qos_table { u32 start; u32 end; @@ -433,85 +429,6 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { static void qm_irqs_unregister(struct hisi_qm *qm); -static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new) -{ - enum qm_state curr = atomic_read(&qm->status.flags); - bool avail = false; - - switch (curr) { - case QM_INIT: - if (new == QM_START || new == QM_CLOSE) - avail = true; - break; - case QM_START: - if (new == QM_STOP) - avail = true; - break; - case QM_STOP: - if (new == QM_CLOSE || new == QM_START) - avail = true; - break; - default: - break; - } - - dev_dbg(&qm->pdev->dev, "change qm state from %s to %s\n", - qm_s[curr], qm_s[new]); - - if (!avail) - dev_warn(&qm->pdev->dev, "Can not change qm state from %s to %s\n", - qm_s[curr], qm_s[new]); - - return avail; -} - -static bool qm_qp_avail_state(struct hisi_qm *qm, struct hisi_qp *qp, - enum qp_state new) -{ - enum qm_state qm_curr = atomic_read(&qm->status.flags); - enum qp_state qp_curr = 0; - bool avail = false; - - if (qp) - qp_curr = atomic_read(&qp->qp_status.flags); - - switch (new) { - case QP_INIT: - if (qm_curr == QM_START || qm_curr == QM_INIT) - avail = true; - break; - case QP_START: - if ((qm_curr == QM_START && qp_curr == QP_INIT) || - (qm_curr == QM_START && qp_curr == QP_STOP)) - avail = true; - break; - case QP_STOP: - if ((qm_curr == QM_START && qp_curr == QP_START) || - (qp_curr == QP_INIT)) - avail = true; - break; - case QP_CLOSE: - if ((qm_curr == QM_START && qp_curr == QP_INIT) || - (qm_curr == QM_START && qp_curr == QP_STOP) || - (qm_curr == QM_STOP && qp_curr == QP_STOP) || - (qm_curr == QM_STOP && qp_curr == QP_INIT)) - avail = true; - break; - default: - break; - } - - dev_dbg(&qm->pdev->dev, "change qp state from %s to %s in QM %s\n", - qp_s[qp_curr], qp_s[new], qm_s[qm_curr]); - - if (!avail) - dev_warn(&qm->pdev->dev, - "Can not change qp state from %s to %s in QM %s\n", - qp_s[qp_curr], qp_s[new], qm_s[qm_curr]); - - return avail; -} - static u32 qm_get_hw_error_status(struct hisi_qm *qm) { return readl(qm->io_base + QM_ABNORMAL_INT_STATUS); @@ -1853,8 +1770,10 @@ static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) struct hisi_qp *qp; int qp_id; - if (!qm_qp_avail_state(qm, NULL, QP_INIT)) + if (atomic_read(&qm->status.flags) == QM_STOP) { + dev_info_ratelimited(dev, "failed to create qp as qm is stop!\n"); return ERR_PTR(-EPERM); + } if (qm->qp_in_used == qm->qp_num) { dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", @@ -1881,7 +1800,6 @@ static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) qp->alg_type = alg_type; qp->is_in_kernel = true; qm->qp_in_used++; - atomic_set(&qp->qp_status.flags, QP_INIT); return qp; } @@ -1924,11 +1842,6 @@ static void hisi_qm_release_qp(struct hisi_qp *qp) down_write(&qm->qps_lock); - if (!qm_qp_avail_state(qm, qp, QP_CLOSE)) { - up_write(&qm->qps_lock); - return; - } - qm->qp_in_used--; idr_remove(&qm->qp_idr, qp->qp_id); @@ -2008,8 +1921,10 @@ static int qm_start_qp_nolock(struct hisi_qp *qp, unsigned long arg) u32 pasid = arg; int ret; - if (!qm_qp_avail_state(qm, qp, QP_START)) + if (atomic_read(&qm->status.flags) == QM_STOP) { + dev_info_ratelimited(dev, "failed to start qp as qm is stop!\n"); return -EPERM; + } ret = qm_qp_ctx_cfg(qp, qp_id, pasid); if (ret) @@ -2131,21 +2046,17 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp) * is_resetting flag should be set negative so that this qp will not * be restarted after reset. */ - if (atomic_read(&qp->qp_status.flags) == QP_STOP) { + if (atomic_read(&qp->qp_status.flags) != QP_START) { qp->is_resetting = false; return 0; } - if (!qm_qp_avail_state(qp->qm, qp, QP_STOP)) - return -EPERM; - atomic_set(&qp->qp_status.flags, QP_STOP); ret = qm_drain_qp(qp); if (ret) dev_err(dev, "Failed to drain out data for stopping!\n"); - flush_workqueue(qp->qm->wq); if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used))) qp_stop_fail_cb(qp); @@ -2865,13 +2776,8 @@ void hisi_qm_uninit(struct hisi_qm *qm) { qm_cmd_uninit(qm); hisi_qm_unint_work(qm); + down_write(&qm->qps_lock); - - if (!qm_avail_state(qm, QM_CLOSE)) { - up_write(&qm->qps_lock); - return; - } - hisi_qm_memory_uninit(qm); hisi_qm_set_state(qm, QM_NOT_READY); up_write(&qm->qps_lock); @@ -3045,11 +2951,6 @@ int hisi_qm_start(struct hisi_qm *qm) down_write(&qm->qps_lock); - if (!qm_avail_state(qm, QM_START)) { - up_write(&qm->qps_lock); - return -EPERM; - } - dev_dbg(dev, "qm start with %u queue pairs\n", qm->qp_num); if (!qm->qp_num) { @@ -3059,10 +2960,12 @@ int hisi_qm_start(struct hisi_qm *qm) } ret = __hisi_qm_start(qm); - if (!ret) - atomic_set(&qm->status.flags, QM_START); + if (ret) + goto err_unlock; + atomic_set(&qm->status.flags, QM_WORK); hisi_qm_set_state(qm, QM_READY); + err_unlock: up_write(&qm->qps_lock); return ret; @@ -3159,10 +3062,11 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) down_write(&qm->qps_lock); qm->status.stop_reason = r; - if (!qm_avail_state(qm, QM_STOP)) { - ret = -EPERM; + if (atomic_read(&qm->status.flags) == QM_STOP) goto err_unlock; - } + + /* Stop all the request sending at first. */ + atomic_set(&qm->status.flags, QM_STOP); if (qm->status.stop_reason == QM_SOFT_RESET || qm->status.stop_reason == QM_DOWN) { @@ -3186,7 +3090,6 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) } qm_clear_queues(qm); - atomic_set(&qm->status.flags, QM_STOP); err_unlock: up_write(&qm->qps_lock); @@ -5350,7 +5253,6 @@ int hisi_qm_init(struct hisi_qm *qm) goto err_free_qm_memory; qm_cmd_init(qm); - atomic_set(&qm->status.flags, QM_INIT); return 0; diff --git a/drivers/crypto/hisilicon/qm_common.h b/drivers/crypto/hisilicon/qm_common.h index 7b0b15c83ec1..0760bf55f13e 100644 --- a/drivers/crypto/hisilicon/qm_common.h +++ b/drivers/crypto/hisilicon/qm_common.h @@ -72,10 +72,6 @@ struct qm_aeqc { __le32 dw6; }; -static const char * const qm_s[] = { - "init", "start", "close", "stop", -}; - int qm_set_and_get_xqc(struct hisi_qm *qm, u8 cmd, void *xqc, u32 qp_id, bool op); void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm); void hisi_qm_set_algqos_init(struct hisi_qm *qm); diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index ddc7ebb70523..e3c0a1297b2c 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -108,17 +108,13 @@ enum qm_stop_reason { }; enum qm_state { - QM_INIT = 0, - QM_START, - QM_CLOSE, + QM_WORK = 0, QM_STOP, }; enum qp_state { - QP_INIT = 1, - QP_START, + QP_START = 1, QP_STOP, - QP_CLOSE, }; enum qm_hw_ver { From a10d17a4a6190c442d4b1448a23c5674f94eb46b Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 25 Nov 2023 19:50:11 +0800 Subject: [PATCH 2063/7721] crypto: hisilicon/qm - add comments and remove redundant array element 1. Remove redundant array element, prevent the size obtained by ARRAY_SIZE() from qm_log_hw_error is greater than actual size. 2. Add comments in function qm_set_vf_mse() and qm_cq_ctx_cfg() to make it easier to understand. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 7d22412774ba..7ed079a9c929 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -391,7 +391,6 @@ static const struct hisi_qm_hw_error qm_hw_error[] = { { .int_msk = BIT(12), .msg = "qm_db_random_invalid" }, { .int_msk = BIT(13), .msg = "qm_mailbox_timeout" }, { .int_msk = BIT(14), .msg = "qm_flr_timeout" }, - { /* sentinel */ } }; static const char * const qm_db_timeout[] = { @@ -1889,6 +1888,11 @@ static int qm_cq_ctx_cfg(struct hisi_qp *qp, int qp_id, u32 pasid) cqc.dw3 = cpu_to_le32(QM_MK_CQC_DW3_V2(QM_QC_CQE_SIZE, qp->cq_depth)); cqc.w8 = 0; /* rand_qc */ } + /* + * Enable request finishing interrupts defaultly. + * So, there will be some interrupts until disabling + * this. + */ cqc.dw6 = cpu_to_le32(1 << QM_CQ_PHASE_SHIFT | 1 << QM_CQ_FLAG_SHIFT); cqc.base_l = cpu_to_le32(lower_32_bits(qp->cqe_dma)); cqc.base_h = cpu_to_le32(upper_32_bits(qp->cqe_dma)); @@ -3879,6 +3883,11 @@ static int qm_set_vf_mse(struct hisi_qm *qm, bool set) int pos; int i; + /* + * Since function qm_set_vf_mse is called only after SRIOV is enabled, + * pci_find_ext_capability cannot return 0, pos does not need to be + * checked. + */ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); pci_read_config_word(pdev, pos + PCI_SRIOV_CTRL, &sriov_ctrl); if (set) From ce852f1308ac738e61c5b2502517deea593a1554 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Mon, 27 Nov 2023 02:03:01 +0000 Subject: [PATCH 2064/7721] crypto: sa2ul - Return crypto_aead_setkey to transfer the error Return crypto_aead_setkey() in order to transfer the error if it fails. Fixes: d2c8ac187fc9 ("crypto: sa2ul - Add AEAD algorithm support") Signed-off-by: Chen Ni Signed-off-by: Herbert Xu --- drivers/crypto/sa2ul.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index 6846a8429574..78a4930c6480 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -1869,9 +1869,8 @@ static int sa_aead_setkey(struct crypto_aead *authenc, crypto_aead_set_flags(ctx->fallback.aead, crypto_aead_get_flags(authenc) & CRYPTO_TFM_REQ_MASK); - crypto_aead_setkey(ctx->fallback.aead, key, keylen); - return 0; + return crypto_aead_setkey(ctx->fallback.aead, key, keylen); } static int sa_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) From f8cc37c59731c88c8c2c62222482dddf071a0600 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 13 Nov 2023 14:55:01 -0600 Subject: [PATCH 2065/7721] drm/omapdrm: Improve check for contiguous buffers While a scatter-gather table having only 1 entry does imply it is contiguous, it is a logic error to assume the inverse. Tables can have more than 1 entry and still be contiguous. Use a proper check here. Signed-off-by: Andrew Davis Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231113205501.616927-1-afd@ti.com --- drivers/gpu/drm/omapdrm/omap_gem.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index c48fa531ca32..3421e8389222 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -48,7 +48,7 @@ struct omap_gem_object { * OMAP_BO_MEM_DMA_API flag set) * * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set) - * if they are physically contiguous (when sgt->orig_nents == 1) + * if they are physically contiguous * * - buffers mapped through the TILER when pin_cnt is not zero, in which * case the DMA address points to the TILER aperture @@ -148,12 +148,18 @@ u64 omap_gem_mmap_offset(struct drm_gem_object *obj) return drm_vma_node_offset_addr(&obj->vma_node); } +static bool omap_gem_sgt_is_contiguous(struct sg_table *sgt, size_t size) +{ + return !(drm_prime_get_contiguous_size(sgt) < size); +} + static bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj) { if (omap_obj->flags & OMAP_BO_MEM_DMA_API) return true; - if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1) + if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && + omap_gem_sgt_is_contiguous(omap_obj->sgt, omap_obj->base.size)) return true; return false; @@ -1385,7 +1391,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, union omap_gem_size gsize; /* Without a DMM only physically contiguous buffers can be supported. */ - if (sgt->orig_nents != 1 && !priv->has_dmm) + if (!omap_gem_sgt_is_contiguous(sgt, size) && !priv->has_dmm) return ERR_PTR(-EINVAL); gsize.bytes = PAGE_ALIGN(size); @@ -1399,7 +1405,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, omap_obj->sgt = sgt; - if (sgt->orig_nents == 1) { + if (omap_gem_sgt_is_contiguous(sgt, size)) { omap_obj->dma_addr = sg_dma_address(sgt->sgl); } else { /* Create pages list from sgt */ From 7959ceb767e4b6c8ced7cb8aaa1c6439cfca890c Mon Sep 17 00:00:00 2001 From: Aradhya Bhatia Date: Wed, 8 Nov 2023 22:46:18 +0530 Subject: [PATCH 2066/7721] dt-bindings: display: ti: Add support for am62a7 dss The DSS controller on TI's AM62A7 SoC is an update from that on TI's AM625 SoC. Like the DSS in AM625, the DSS in this SoC has 2 video pipelines, but unlike the former, the latter only has one output port on VP2 to service DPI display sinks. Add the new controller's compatible. Signed-off-by: Aradhya Bhatia Reviewed-by: Krzysztof Kozlowski Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20231108171619.978438-2-a-bhatia1@ti.com Signed-off-by: Tomi Valkeinen --- .../bindings/display/ti/ti,am65x-dss.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml index ae09cd3cbce1..b6767ef0d24d 100644 --- a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml +++ b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml @@ -23,6 +23,7 @@ properties: compatible: enum: - ti,am625-dss + - ti,am62a7,dss - ti,am65x-dss reg: @@ -87,6 +88,7 @@ properties: For AM65x DSS, the OLDI output port node from video port 1. For AM625 DSS, the internal DPI output port node from video port 1. + For AM62A7 DSS, the port is tied off inside the SoC. port@1: $ref: /schemas/graph.yaml#/properties/port @@ -108,6 +110,18 @@ properties: Input memory (from main memory to dispc) bandwidth limit in bytes per second +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62a7-dss + then: + properties: + ports: + properties: + port@0: false + required: - compatible - reg From 5cc5ea7b6d7b0649b74df1e0f2d1875e683704d9 Mon Sep 17 00:00:00 2001 From: Aradhya Bhatia Date: Wed, 8 Nov 2023 22:46:19 +0530 Subject: [PATCH 2067/7721] drm/tidss: Add support for AM62A7 DSS Add support for the DSS controller on TI's AM62A7 SoC in the tidss driver. This controller has 2 video pipelines that can render 2 video planes on over a screen, using the overlay managers. The output of the DSS comes from video port 2 (VP2) in the form of RGB88 DPI signals, while the VP1 is tied off inside the SoC. Also add and use a new type of VP, DISPC_VP_TIED_OFF, for the tied-off VP1 of AM62A DSS. Signed-off-by: Aradhya Bhatia Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20231108171619.978438-3-a-bhatia1@ti.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 59 +++++++++++++++++++++++++++++ drivers/gpu/drm/tidss/tidss_dispc.h | 3 ++ drivers/gpu/drm/tidss/tidss_drv.c | 1 + 3 files changed, 63 insertions(+) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index 9d9dee7abaef..7af416457c57 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -322,6 +322,60 @@ const struct dispc_features dispc_am625_feats = { .vid_order = { 1, 0 }, }; +const struct dispc_features dispc_am62a7_feats = { + /* + * if the code reaches dispc_mode_valid with VP1, + * it should return MODE_BAD. + */ + .max_pclk_khz = { + [DISPC_VP_TIED_OFF] = 0, + [DISPC_VP_DPI] = 165000, + }, + + .scaling = { + .in_width_max_5tap_rgb = 1280, + .in_width_max_3tap_rgb = 2560, + .in_width_max_5tap_yuv = 2560, + .in_width_max_3tap_yuv = 4096, + .upscale_limit = 16, + .downscale_limit_5tap = 4, + .downscale_limit_3tap = 2, + /* + * The max supported pixel inc value is 255. The value + * of pixel inc is calculated like this: 1+(xinc-1)*bpp. + * The maximum bpp of all formats supported by the HW + * is 8. So the maximum supported xinc value is 32, + * because 1+(32-1)*8 < 255 < 1+(33-1)*4. + */ + .xinc_max = 32, + }, + + .subrev = DISPC_AM62A7, + + .common = "common", + .common_regs = tidss_am65x_common_regs, + + .num_vps = 2, + .vp_name = { "vp1", "vp2" }, + .ovr_name = { "ovr1", "ovr2" }, + .vpclk_name = { "vp1", "vp2" }, + /* VP1 of the DSS in AM62A7 SoC is tied off internally */ + .vp_bus_type = { DISPC_VP_TIED_OFF, DISPC_VP_DPI }, + + .vp_feat = { .color = { + .has_ctm = true, + .gamma_size = 256, + .gamma_type = TIDSS_GAMMA_8BIT, + }, + }, + + .num_planes = 2, + /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ + .vid_name = { "vid", "vidl1" }, + .vid_lite = { false, true, }, + .vid_order = { 1, 0 }, +}; + static const u16 *dispc_common_regmap; struct dss_vp_data { @@ -824,6 +878,7 @@ dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc) case DISPC_K2G: return dispc_k2g_read_and_clear_irqstatus(dispc); case DISPC_AM625: + case DISPC_AM62A7: case DISPC_AM65X: case DISPC_J721E: return dispc_k3_read_and_clear_irqstatus(dispc); @@ -840,6 +895,7 @@ void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask) dispc_k2g_set_irqenable(dispc, mask); break; case DISPC_AM625: + case DISPC_AM62A7: case DISPC_AM65X: case DISPC_J721E: dispc_k3_set_irqenable(dispc, mask); @@ -1331,6 +1387,7 @@ void dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane, x, y, layer); break; case DISPC_AM625: + case DISPC_AM62A7: case DISPC_AM65X: dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport, x, y, layer); @@ -2250,6 +2307,7 @@ static void dispc_plane_init(struct dispc_device *dispc) dispc_k2g_plane_init(dispc); break; case DISPC_AM625: + case DISPC_AM62A7: case DISPC_AM65X: case DISPC_J721E: dispc_k3_plane_init(dispc); @@ -2357,6 +2415,7 @@ static void dispc_vp_write_gamma_table(struct dispc_device *dispc, dispc_k2g_vp_write_gamma_table(dispc, hw_videoport); break; case DISPC_AM625: + case DISPC_AM62A7: case DISPC_AM65X: dispc_am65x_vp_write_gamma_table(dispc, hw_videoport); break; diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h index 33ac5ad7a423..086327d51a90 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.h +++ b/drivers/gpu/drm/tidss/tidss_dispc.h @@ -54,12 +54,14 @@ enum dispc_vp_bus_type { DISPC_VP_DPI, /* DPI output */ DISPC_VP_OLDI, /* OLDI (LVDS) output */ DISPC_VP_INTERNAL, /* SoC internal routing */ + DISPC_VP_TIED_OFF, /* Tied off / Unavailable */ DISPC_VP_MAX_BUS_TYPE, }; enum dispc_dss_subrevision { DISPC_K2G, DISPC_AM625, + DISPC_AM62A7, DISPC_AM65X, DISPC_J721E, }; @@ -88,6 +90,7 @@ struct dispc_features { extern const struct dispc_features dispc_k2g_feats; extern const struct dispc_features dispc_am625_feats; +extern const struct dispc_features dispc_am62a7_feats; extern const struct dispc_features dispc_am65x_feats; extern const struct dispc_features dispc_j721e_feats; diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c index 4d063eb9cd0b..edf69d020544 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.c +++ b/drivers/gpu/drm/tidss/tidss_drv.c @@ -231,6 +231,7 @@ static void tidss_shutdown(struct platform_device *pdev) static const struct of_device_id tidss_of_table[] = { { .compatible = "ti,k2g-dss", .data = &dispc_k2g_feats, }, { .compatible = "ti,am625-dss", .data = &dispc_am625_feats, }, + { .compatible = "ti,am62a7-dss", .data = &dispc_am62a7_feats, }, { .compatible = "ti,am65x-dss", .data = &dispc_am65x_feats, }, { .compatible = "ti,j721e-dss", .data = &dispc_j721e_feats, }, { } From a0a9e7b4690b1d78f146fbc8c78a630856ed3015 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:54 +0200 Subject: [PATCH 2068/7721] drm/tidss: Use pm_runtime_resume_and_get() Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync(), which will handle error situations better. Also fix the return, as there should be no reason for the current complex return. Reviewed-by: Laurent Pinchart Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-1-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c index edf69d020544..bb1297820856 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.c +++ b/drivers/gpu/drm/tidss/tidss_drv.c @@ -32,9 +32,9 @@ int tidss_runtime_get(struct tidss_device *tidss) dev_dbg(tidss->dev, "%s\n", __func__); - r = pm_runtime_get_sync(tidss->dev); + r = pm_runtime_resume_and_get(tidss->dev); WARN_ON(r < 0); - return r < 0 ? r : 0; + return r; } void tidss_runtime_put(struct tidss_device *tidss) From 4b0bdf9383a999498b88df4c1a1e3f0910b86d53 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:55 +0200 Subject: [PATCH 2069/7721] drm/tidss: Use PM autosuspend Use runtime PM autosuspend feature, with 1s timeout, to avoid unnecessary suspend-resume cycles when, e.g. the userspace temporarily turns off the crtcs when configuring the outputs. Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-2-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_drv.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c index bb1297820856..09e30de2dd48 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.c +++ b/drivers/gpu/drm/tidss/tidss_drv.c @@ -43,7 +43,9 @@ void tidss_runtime_put(struct tidss_device *tidss) dev_dbg(tidss->dev, "%s\n", __func__); - r = pm_runtime_put_sync(tidss->dev); + pm_runtime_mark_last_busy(tidss->dev); + + r = pm_runtime_put_autosuspend(tidss->dev); WARN_ON(r < 0); } @@ -144,6 +146,9 @@ static int tidss_probe(struct platform_device *pdev) pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + #ifndef CONFIG_PM /* If we don't have PM, we need to call resume manually */ dispc_runtime_resume(tidss->dispc); @@ -192,6 +197,7 @@ static int tidss_probe(struct platform_device *pdev) #ifndef CONFIG_PM dispc_runtime_suspend(tidss->dispc); #endif + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); return ret; @@ -215,6 +221,7 @@ static void tidss_remove(struct platform_device *pdev) /* If we don't have PM, we need to call suspend manually */ dispc_runtime_suspend(tidss->dispc); #endif + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); /* devm allocated dispc goes away with the dev so mark it NULL */ From c2746e4d278be8f71ef0dbcd00fcc8ba46c678ef Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:56 +0200 Subject: [PATCH 2070/7721] drm/tidss: Drop useless variable init No need to initialize the ret to 0 in dispc_softreset(). Reviewed-by: Laurent Pinchart Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-3-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index 7af416457c57..1dfd95a54e64 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2764,7 +2764,7 @@ static void dispc_init_errata(struct dispc_device *dispc) static void dispc_softreset(struct dispc_device *dispc) { u32 val; - int ret = 0; + int ret; /* Soft reset */ REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1); From 36d1e0852680aa038e2428d450673390111b165c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:57 +0200 Subject: [PATCH 2071/7721] drm/tidss: Move reset to the end of dispc_init() We do a DSS reset in the middle of the dispc_init(). While that happens to work now, we should really make sure that e..g the fclk, which is acquired only later in the function, is enabled when doing a reset. This will be handled in a later patch, but for now, let's move the dispc_softreset() call to the end of dispc_init(), which is a sensible place for it anyway. Reviewed-by: Laurent Pinchart Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-4-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index 1dfd95a54e64..bce5432d26f3 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2836,10 +2836,6 @@ int dispc_init(struct tidss_device *tidss) return r; } - /* K2G display controller does not support soft reset */ - if (feat->subrev != DISPC_K2G) - dispc_softreset(dispc); - for (i = 0; i < dispc->feat->num_vps; i++) { u32 gamma_size = dispc->feat->vp_feat.color.gamma_size; u32 *gamma_table; @@ -2888,6 +2884,10 @@ int dispc_init(struct tidss_device *tidss) of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", &dispc->memory_bandwidth_limit); + /* K2G display controller does not support soft reset */ + if (feat->subrev != DISPC_K2G) + dispc_softreset(dispc); + tidss->dispc = dispc; return 0; From aceafbb5035c4bfc75a321863ed1e393d644d2d2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:58 +0200 Subject: [PATCH 2072/7721] drm/tidss: Return error value from from softreset Return an error value from dispc_softreset() so that the caller can handle the errors. Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-5-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index bce5432d26f3..b72f1e7d4b72 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2761,7 +2761,7 @@ static void dispc_init_errata(struct dispc_device *dispc) } } -static void dispc_softreset(struct dispc_device *dispc) +static int dispc_softreset(struct dispc_device *dispc) { u32 val; int ret; @@ -2771,8 +2771,12 @@ static void dispc_softreset(struct dispc_device *dispc) /* Wait for reset to complete */ ret = readl_poll_timeout(dispc->base_common + DSS_SYSSTATUS, val, val & 1, 100, 5000); - if (ret) - dev_warn(dispc->dev, "failed to reset dispc\n"); + if (ret) { + dev_err(dispc->dev, "failed to reset dispc\n"); + return ret; + } + + return 0; } int dispc_init(struct tidss_device *tidss) @@ -2885,8 +2889,11 @@ int dispc_init(struct tidss_device *tidss) &dispc->memory_bandwidth_limit); /* K2G display controller does not support soft reset */ - if (feat->subrev != DISPC_K2G) - dispc_softreset(dispc); + if (feat->subrev != DISPC_K2G) { + r = dispc_softreset(dispc); + if (r) + return r; + } tidss->dispc = dispc; From 151825150cf9c2e9fb90763d35b9dff3783628ac Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:37:59 +0200 Subject: [PATCH 2073/7721] drm/tidss: Check for K2G in in dispc_softreset() K2G doesn't have softreset feature. Instead of having every caller of dispc_softreset() check for K2G, move the check into dispc_softreset(), and make dispc_softreset() return 0 in case of K2G. Reviewed-by: Laurent Pinchart Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-6-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index b72f1e7d4b72..f9de26cd241a 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2766,6 +2766,10 @@ static int dispc_softreset(struct dispc_device *dispc) u32 val; int ret; + /* K2G display controller does not support soft reset */ + if (dispc->feat->subrev == DISPC_K2G) + return 0; + /* Soft reset */ REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1); /* Wait for reset to complete */ @@ -2888,12 +2892,9 @@ int dispc_init(struct tidss_device *tidss) of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", &dispc->memory_bandwidth_limit); - /* K2G display controller does not support soft reset */ - if (feat->subrev != DISPC_K2G) { - r = dispc_softreset(dispc); - if (r) - return r; - } + r = dispc_softreset(dispc); + if (r) + return r; tidss->dispc = dispc; From 576d96c5c896221b5bc8feae473739469a92e144 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:38:00 +0200 Subject: [PATCH 2074/7721] drm/tidss: Add simple K2G manual reset K2G display controller does not support soft reset, but we can do the most important steps manually: mask the IRQs and disable the VPs. Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-7-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index f9de26cd241a..c3741feaafff 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2761,14 +2761,28 @@ static void dispc_init_errata(struct dispc_device *dispc) } } +/* + * K2G display controller does not support soft reset, so we do a basic manual + * reset here: make sure the IRQs are masked and VPs are disabled. + */ +static void dispc_softreset_k2g(struct dispc_device *dispc) +{ + dispc_set_irqenable(dispc, 0); + dispc_read_and_clear_irqstatus(dispc); + + for (unsigned int vp_idx = 0; vp_idx < dispc->feat->num_vps; ++vp_idx) + VP_REG_FLD_MOD(dispc, vp_idx, DISPC_VP_CONTROL, 0, 0, 0); +} + static int dispc_softreset(struct dispc_device *dispc) { u32 val; int ret; - /* K2G display controller does not support soft reset */ - if (dispc->feat->subrev == DISPC_K2G) + if (dispc->feat->subrev == DISPC_K2G) { + dispc_softreset_k2g(dispc); return 0; + } /* Soft reset */ REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1); From bc288a927815efcf9d7f4a54d4d89c5df478c635 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:38:01 +0200 Subject: [PATCH 2075/7721] drm/tidss: Fix dss reset The probe function calls dispc_softreset() before runtime PM is enabled and without enabling any of the DSS clocks. This happens to work by luck, and we need to make sure the DSS HW is active and the fclk is enabled. To fix the above, add a new function, dispc_init_hw(), which does: - pm_runtime_set_active() - clk_prepare_enable(fclk) - dispc_softreset(). This ensures that the reset can be successfully accomplished. Note that we use pm_runtime_set_active(), not the normal pm_runtime_get(). The reason for this is that at this point we haven't enabled the runtime PM yet and also we don't want the normal resume callback to be called: the dispc resume callback does some initial HW setup, and it expects that the HW was off (no video ports are streaming). If the bootloader has enabled the DSS and has set up a boot time splash-screen, the DSS would be enabled and streaming which might lead to issues with the normal resume callback. Fixes: c9b2d923befd ("drm/tidss: Soft Reset DISPC on startup") Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-8-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_dispc.c | 45 ++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index c3741feaafff..1ad711f8d2a8 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -2797,6 +2797,49 @@ static int dispc_softreset(struct dispc_device *dispc) return 0; } +static int dispc_init_hw(struct dispc_device *dispc) +{ + struct device *dev = dispc->dev; + int ret; + + ret = pm_runtime_set_active(dev); + if (ret) { + dev_err(dev, "Failed to set DSS PM to active\n"); + return ret; + } + + ret = clk_prepare_enable(dispc->fclk); + if (ret) { + dev_err(dev, "Failed to enable DSS fclk\n"); + goto err_runtime_suspend; + } + + ret = dispc_softreset(dispc); + if (ret) + goto err_clk_disable; + + clk_disable_unprepare(dispc->fclk); + ret = pm_runtime_set_suspended(dev); + if (ret) { + dev_err(dev, "Failed to set DSS PM to suspended\n"); + return ret; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(dispc->fclk); + +err_runtime_suspend: + ret = pm_runtime_set_suspended(dev); + if (ret) { + dev_err(dev, "Failed to set DSS PM to suspended\n"); + return ret; + } + + return ret; +} + int dispc_init(struct tidss_device *tidss) { struct device *dev = tidss->dev; @@ -2906,7 +2949,7 @@ int dispc_init(struct tidss_device *tidss) of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", &dispc->memory_bandwidth_limit); - r = dispc_softreset(dispc); + r = dispc_init_hw(dispc); if (r) return r; From d4652187367bc55983139401d0ee41d6e565b13d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:38:02 +0200 Subject: [PATCH 2076/7721] drm/tidss: IRQ code cleanup The IRQ setup code is overly complex. All we really need to do is initialize the related fields in struct tidss_device, and request the IRQ. We can drop all the HW accesses, as they are pointless: the driver will set the IRQs correctly when it needs any of the IRQs, and at probe time we have done a reset, so we know that all the IRQs are masked by default in the hardware. Thus we can combine the tidss_irq_preinstall() and tidss_irq_postinstall() into the tidss_irq_install() function, drop the HW accesses, and drop the use of spinlock, as this is done at init time and there can be no races. We can also drop the HW access from the tidss_irq_uninstall(), as the driver will anyway disable and suspend the hardware at remove time. Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-9-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_drv.c | 2 ++ drivers/gpu/drm/tidss/tidss_irq.c | 54 +++++-------------------------- 2 files changed, 10 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c index 09e30de2dd48..d15f836dca95 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.c +++ b/drivers/gpu/drm/tidss/tidss_drv.c @@ -138,6 +138,8 @@ static int tidss_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tidss); + spin_lock_init(&tidss->wait_lock); + ret = dispc_init(tidss); if (ret) { dev_err(dev, "failed to initialize dispc: %d\n", ret); diff --git a/drivers/gpu/drm/tidss/tidss_irq.c b/drivers/gpu/drm/tidss/tidss_irq.c index 0c681c7600bc..604334ef526a 100644 --- a/drivers/gpu/drm/tidss/tidss_irq.c +++ b/drivers/gpu/drm/tidss/tidss_irq.c @@ -93,33 +93,21 @@ void tidss_irq_resume(struct tidss_device *tidss) spin_unlock_irqrestore(&tidss->wait_lock, flags); } -static void tidss_irq_preinstall(struct drm_device *ddev) +int tidss_irq_install(struct drm_device *ddev, unsigned int irq) { struct tidss_device *tidss = to_tidss(ddev); + int ret; - spin_lock_init(&tidss->wait_lock); + if (irq == IRQ_NOTCONNECTED) + return -ENOTCONN; - tidss_runtime_get(tidss); - - dispc_set_irqenable(tidss->dispc, 0); - dispc_read_and_clear_irqstatus(tidss->dispc); - - tidss_runtime_put(tidss); -} - -static void tidss_irq_postinstall(struct drm_device *ddev) -{ - struct tidss_device *tidss = to_tidss(ddev); - unsigned long flags; - unsigned int i; - - tidss_runtime_get(tidss); - - spin_lock_irqsave(&tidss->wait_lock, flags); + ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev); + if (ret) + return ret; tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR; - for (i = 0; i < tidss->num_crtcs; ++i) { + for (unsigned int i = 0; i < tidss->num_crtcs; ++i) { struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]); tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport); @@ -127,28 +115,6 @@ static void tidss_irq_postinstall(struct drm_device *ddev) tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport); } - tidss_irq_update(tidss); - - spin_unlock_irqrestore(&tidss->wait_lock, flags); - - tidss_runtime_put(tidss); -} - -int tidss_irq_install(struct drm_device *ddev, unsigned int irq) -{ - int ret; - - if (irq == IRQ_NOTCONNECTED) - return -ENOTCONN; - - tidss_irq_preinstall(ddev); - - ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev); - if (ret) - return ret; - - tidss_irq_postinstall(ddev); - return 0; } @@ -156,9 +122,5 @@ void tidss_irq_uninstall(struct drm_device *ddev) { struct tidss_device *tidss = to_tidss(ddev); - tidss_runtime_get(tidss); - dispc_set_irqenable(tidss->dispc, 0); - tidss_runtime_put(tidss); - free_irq(tidss->irq, ddev); } From 95d4b471953411854f9c80b568da7fcf753f3801 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:38:03 +0200 Subject: [PATCH 2077/7721] drm/tidss: Fix atomic_flush check tidss_crtc_atomic_flush() checks if the crtc is enabled, and if not, returns immediately as there's no reason to do any register changes. However, the code checks for 'crtc->state->enable', which does not reflect the actual HW state. We should instead look at the 'crtc->state->active' flag. This causes the tidss_crtc_atomic_flush() to proceed with the flush even if the active state is false, which then causes us to hit the WARN_ON(!crtc->state->event) check. Fix this by checking the active flag, and while at it, fix the related debug print which had "active" and "needs modeset" wrong way. Cc: Fixes: 32a1795f57ee ("drm/tidss: New driver for TI Keystone platform Display SubSystem") Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-10-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_crtc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c index 5e5e466f35d1..7c78c074e3a2 100644 --- a/drivers/gpu/drm/tidss/tidss_crtc.c +++ b/drivers/gpu/drm/tidss/tidss_crtc.c @@ -169,13 +169,13 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc, struct tidss_device *tidss = to_tidss(ddev); unsigned long flags; - dev_dbg(ddev->dev, - "%s: %s enabled %d, needs modeset %d, event %p\n", __func__, - crtc->name, drm_atomic_crtc_needs_modeset(crtc->state), - crtc->state->enable, crtc->state->event); + dev_dbg(ddev->dev, "%s: %s is %sactive, %s modeset, event %p\n", + __func__, crtc->name, crtc->state->active ? "" : "not ", + drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need", + crtc->state->event); /* There is nothing to do if CRTC is not going to be enabled. */ - if (!crtc->state->enable) + if (!crtc->state->active) return; /* From ca89b69734f92021e25899dff3e433b1904f5832 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Nov 2023 09:38:04 +0200 Subject: [PATCH 2078/7721] drm/tidss: Use DRM_PLANE_COMMIT_ACTIVE_ONLY At the moment the driver does not use DRM_PLANE_COMMIT_ACTIVE_ONLY, but still checks for crtc->state->active in tidss_crtc_atomic_flush(), and skips the flush if the crtc is not active. The exact reason why DRM_PLANE_COMMIT_ACTIVE_ONLY is not used has been lost in history. DRM_PLANE_COMMIT_ACTIVE_ONLY does also affect the plane updates, and I think the issue was related to multi-display systems and moving planes between the displays. However, it is possible the issue was only present on the older DSS hardware, handled by the omapdrm driver (on which the tidss driver is loosely based). Reviewing the code related to DRM_PLANE_COMMIT_ACTIVE_ONLY does not show any issues, and testing on J7 EVM with two displays works fine. Change the driver to use DRM_PLANE_COMMIT_ACTIVE_ONLY. Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-11-ac91b5ea35c0@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/tidss/tidss_crtc.c | 4 ---- drivers/gpu/drm/tidss/tidss_kms.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c index 7c78c074e3a2..5f838980c7a1 100644 --- a/drivers/gpu/drm/tidss/tidss_crtc.c +++ b/drivers/gpu/drm/tidss/tidss_crtc.c @@ -174,10 +174,6 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc, drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need", crtc->state->event); - /* There is nothing to do if CRTC is not going to be enabled. */ - if (!crtc->state->active) - return; - /* * Flush CRTC changes with go bit only if new modeset is not * coming, so CRTC is enabled trough out the commit. diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index d096d8d2bc8f..a0e494c806a9 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -29,7 +29,7 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) tidss_runtime_get(tidss); drm_atomic_helper_commit_modeset_disables(ddev, old_state); - drm_atomic_helper_commit_planes(ddev, old_state, 0); + drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_commit_modeset_enables(ddev, old_state); drm_atomic_helper_commit_hw_done(old_state); From 561322c3bc14bb59f26120a9135eabc140284f86 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Wed, 29 Nov 2023 14:22:21 +0200 Subject: [PATCH 2079/7721] drm/i915/display: Skip state verification with TBT-ALT mode With TBT-ALT mode we are not programming C20 chip PLL's and hence we don't need to check state verification. We don't need to program DP link signal levels i.e.pre-emphasis and voltage swing either. This patch fixes dmesg errors like this one "[drm] ERROR PHY F Write 0c06 failed after 3 retries." Signed-off-by: Mika Kahola Reviewed-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20231129122221.1109084-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index a8fa76580802..5fbec5784b83 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -415,9 +415,15 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(i915, encoder->port); - u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); + u8 owned_lane_mask; intel_wakeref_t wakeref; int n_entries, ln; + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (intel_tc_port_in_tbt_alt_mode(dig_port)) + return; + + owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); wakeref = intel_cx0_phy_transaction_begin(encoder); @@ -3136,6 +3142,9 @@ void intel_cx0pll_state_verify(struct intel_atomic_state *state, encoder = intel_get_crtc_new_encoder(state, new_crtc_state); phy = intel_port_to_phy(i915, encoder->port); + if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) + return; + intel_cx0pll_readout_hw_state(encoder, &mpll_hw_state); if (intel_is_c10phy(i915, phy)) From 3fde49c5dd8b1a65c44e2d6861899ccfa9c11197 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 30 Nov 2023 10:15:38 +0100 Subject: [PATCH 2080/7721] dt-bindings: gpio: modepin: Describe label property Describe optional label property which can be used for better gpio identification. Signed-off-by: Michal Simek Acked-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml index 56143f1fe84a..b1fd632718d4 100644 --- a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml +++ b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml @@ -23,6 +23,8 @@ properties: "#gpio-cells": const: 2 + label: true + required: - compatible - gpio-controller @@ -37,6 +39,7 @@ examples: compatible = "xlnx,zynqmp-gpio-modepin"; gpio-controller; #gpio-cells = <2>; + label = "modepin"; }; }; From 0cd523ee864243c9bdb9d52776613e62b992f6bf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Nov 2023 16:13:19 +0300 Subject: [PATCH 2081/7721] octeon_ep: Fix error code in probe() Set the error code if octep_ctrl_net_get_mtu() fails. Currently the code returns success. Fixes: 0a5f8534e398 ("octeon_ep: get max rx packet length from firmware") Signed-off-by: Dan Carpenter Reviewed-by: Simon Horman Signed-off-by: Dan Carpenter Reviewed-by: Sathesh B Edara Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeon_ep/octep_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 1a24b3d3cce6..f22fd309a78f 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -1387,6 +1387,7 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (max_rx_pktlen < 0) { dev_err(&octep_dev->pdev->dev, "Failed to get max receive packet size; err = %d\n", max_rx_pktlen); + err = max_rx_pktlen; goto register_dev_err; } netdev->min_mtu = OCTEP_MIN_MTU; From 15bc81212f593fbd7bda787598418b931842dc14 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Tue, 28 Nov 2023 21:31:31 -0800 Subject: [PATCH 2082/7721] octeon_ep: set backpressure watermark for RX queues Set backpressure watermark for hardware RX queues. Backpressure gets triggered when the available buffers of a hardware RX queue falls below the set watermark. This backpressure will propagate to packet processing pipeline in the OCTEON card, so that the host receives fewer packets and prevents packet dropping at host. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 7 +++++++ drivers/net/ethernet/marvell/octeon_ep/octep_config.h | 10 ++++++++++ .../ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h | 3 +++ 3 files changed, 20 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c index abb03e9119e7..098a0c5c4d1c 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c @@ -258,6 +258,7 @@ static void octep_init_config_cnxk_pf(struct octep_device *oct) conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD; conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD; conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD; + conf->oq.wmark = OCTEP_OQ_WMARK_MIN; conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR; conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings; @@ -378,6 +379,12 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); + + /* set watermark for backpressure */ + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no)); + reg_val &= ~0xFFFFFFFFULL; + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); } /* Setup registers for a PF mailbox */ diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h index 4c937ba5589f..c528344a7d0c 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h @@ -20,6 +20,9 @@ /* Packet threshold for Tx queue interrupt */ #define OCTEP_IQ_INTR_THRESHOLD 0x0 +/* Minimum watermark for backpressure */ +#define OCTEP_OQ_WMARK_MIN 256 + /* Rx Queue: maximum descriptors per ring */ #define OCTEP_OQ_MAX_DESCRIPTORS 1024 @@ -67,6 +70,7 @@ #define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold) #define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt) #define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time) +#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark) #define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.max_io_rings) #define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings) @@ -136,6 +140,12 @@ struct octep_oq_config { * default. The time is specified in microseconds. */ u32 oq_intr_time; + + /* Water mark for backpressure. + * Output queue sends backpressure signal to source when + * free buffer count falls below wmark. + */ + u32 wmark; }; /* Tx/Rx configuration */ diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h index abe02df8af11..ea677f760ef0 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h @@ -143,6 +143,9 @@ #define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \ (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET)) +#define CNXK_SDP_R_OUT_WMARK(ring) \ + (CNXK_SDP_R_OUT_WMARK_START + ((ring) * CNXK_RING_OFFSET)) + #define CNXK_SDP_R_OUT_CNTS(ring) \ (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET)) From 780b9463ce66a9efb18e3b5d35cd011fb918d741 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:24 -0300 Subject: [PATCH 2083/7721] drm/v3d: Remove unused function header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v3d_mmu_get_offset header was added but the function was never defined. Just remove it. Signed-off-by: Melissa Wen Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-3-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 4c59fefaa0b4..d8b392494eba 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -420,8 +420,6 @@ void v3d_irq_disable(struct v3d_dev *v3d); void v3d_irq_reset(struct v3d_dev *v3d); /* v3d_mmu.c */ -int v3d_mmu_get_offset(struct drm_file *file_priv, struct v3d_bo *bo, - u32 *offset); int v3d_mmu_set_page_table(struct v3d_dev *v3d); void v3d_mmu_insert_ptes(struct v3d_bo *bo); void v3d_mmu_remove_ptes(struct v3d_bo *bo); From a8ad9d63a160f6b93f6958a5a0ded1a6abb15815 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:25 -0300 Subject: [PATCH 2084/7721] drm/v3d: Move wait BO ioctl to the v3d_bo file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IOCTLs related to BO operations reside on the file v3d_bo.c. The wait BO ioctl is the only IOCTL regarding BOs that is placed in a different file. So, move it to the v3d_bo.c file. Signed-off-by: Melissa Wen Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-4-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_bo.c | 33 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_drv.h | 4 ++-- drivers/gpu/drm/v3d/v3d_gem.c | 33 --------------------------------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index 8b3229a37c6d..357a0da7e16a 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -233,3 +233,36 @@ int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data, drm_gem_object_put(gem_obj); return 0; } + +int +v3d_wait_bo_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + int ret; + struct drm_v3d_wait_bo *args = data; + ktime_t start = ktime_get(); + u64 delta_ns; + unsigned long timeout_jiffies = + nsecs_to_jiffies_timeout(args->timeout_ns); + + if (args->pad != 0) + return -EINVAL; + + ret = drm_gem_dma_resv_wait(file_priv, args->handle, + true, timeout_jiffies); + + /* Decrement the user's timeout, in case we got interrupted + * such that the ioctl will be restarted. + */ + delta_ns = ktime_to_ns(ktime_sub(ktime_get(), start)); + if (delta_ns < args->timeout_ns) + args->timeout_ns -= delta_ns; + else + args->timeout_ns = 0; + + /* Asked to wait beyond the jiffie/scheduler precision? */ + if (ret == -ETIME && args->timeout_ns) + ret = -EAGAIN; + + return ret; +} diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index d8b392494eba..fc04372d5cbd 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -385,6 +385,8 @@ int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); struct drm_gem_object *v3d_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); @@ -405,8 +407,6 @@ int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); void v3d_job_cleanup(struct v3d_job *job); void v3d_job_put(struct v3d_job *job); void v3d_reset(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 9d2ac23c29e3..26f62a48d226 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -363,39 +363,6 @@ void v3d_job_put(struct v3d_job *job) kref_put(&job->refcount, job->free); } -int -v3d_wait_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - int ret; - struct drm_v3d_wait_bo *args = data; - ktime_t start = ktime_get(); - u64 delta_ns; - unsigned long timeout_jiffies = - nsecs_to_jiffies_timeout(args->timeout_ns); - - if (args->pad != 0) - return -EINVAL; - - ret = drm_gem_dma_resv_wait(file_priv, args->handle, - true, timeout_jiffies); - - /* Decrement the user's timeout, in case we got interrupted - * such that the ioctl will be restarted. - */ - delta_ns = ktime_to_ns(ktime_sub(ktime_get(), start)); - if (delta_ns < args->timeout_ns) - args->timeout_ns -= delta_ns; - else - args->timeout_ns = 0; - - /* Asked to wait beyond the jiffie/scheduler precision? */ - if (ret == -ETIME && args->timeout_ns) - ret = -EAGAIN; - - return ret; -} - static int v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, void **container, size_t size, void (*free)(struct kref *ref), From 9032d5f633ed7b5c726971dc7e2372045bf27f40 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:26 -0300 Subject: [PATCH 2085/7721] drm/v3d: Detach job submissions IOCTLs to a new specific file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will include a new job submission type, the CPU job submission. For readability and maintability, separate the job submission IOCTLs and related operations from v3d_gem.c. Minor fix in the CSD submission kernel doc: CSD (texture formatting) -> CSD (compute shader). Signed-off-by: Melissa Wen Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-5-mcanal@igalia.com --- drivers/gpu/drm/v3d/Makefile | 3 +- drivers/gpu/drm/v3d/v3d_drv.h | 12 +- drivers/gpu/drm/v3d/v3d_gem.c | 735 ------------------------------ drivers/gpu/drm/v3d/v3d_submit.c | 744 +++++++++++++++++++++++++++++++ 4 files changed, 753 insertions(+), 741 deletions(-) create mode 100644 drivers/gpu/drm/v3d/v3d_submit.c diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile index 4b21b20e4998..b7d673f1153b 100644 --- a/drivers/gpu/drm/v3d/Makefile +++ b/drivers/gpu/drm/v3d/Makefile @@ -12,7 +12,8 @@ v3d-y := \ v3d_perfmon.o \ v3d_trace_points.o \ v3d_sched.o \ - v3d_sysfs.o + v3d_sysfs.o \ + v3d_submit.o v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index fc04372d5cbd..4db9ace66024 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -401,17 +401,19 @@ struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue queue); /* v3d_gem.c */ int v3d_gem_init(struct drm_device *dev); void v3d_gem_destroy(struct drm_device *dev); +void v3d_reset(struct v3d_dev *v3d); +void v3d_invalidate_caches(struct v3d_dev *v3d); +void v3d_clean_caches(struct v3d_dev *v3d); + +/* v3d_submit.c */ +void v3d_job_cleanup(struct v3d_job *job); +void v3d_job_put(struct v3d_job *job); int v3d_submit_cl_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -void v3d_job_cleanup(struct v3d_job *job); -void v3d_job_put(struct v3d_job *job); -void v3d_reset(struct v3d_dev *v3d); -void v3d_invalidate_caches(struct v3d_dev *v3d); -void v3d_clean_caches(struct v3d_dev *v3d); /* v3d_irq.c */ int v3d_irq_init(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 26f62a48d226..afc565078c78 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -11,8 +11,6 @@ #include #include -#include -#include #include "v3d_drv.h" #include "v3d_regs.h" @@ -241,739 +239,6 @@ v3d_invalidate_caches(struct v3d_dev *v3d) v3d_invalidate_slices(v3d, 0); } -/* Takes the reservation lock on all the BOs being referenced, so that - * at queue submit time we can update the reservations. - * - * We don't lock the RCL the tile alloc/state BOs, or overflow memory - * (all of which are on exec->unref_list). They're entirely private - * to v3d, so we don't attach dma-buf fences to them. - */ -static int -v3d_lock_bo_reservations(struct v3d_job *job, - struct ww_acquire_ctx *acquire_ctx) -{ - int i, ret; - - ret = drm_gem_lock_reservations(job->bo, job->bo_count, acquire_ctx); - if (ret) - return ret; - - for (i = 0; i < job->bo_count; i++) { - ret = dma_resv_reserve_fences(job->bo[i]->resv, 1); - if (ret) - goto fail; - - ret = drm_sched_job_add_implicit_dependencies(&job->base, - job->bo[i], true); - if (ret) - goto fail; - } - - return 0; - -fail: - drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); - return ret; -} - -/** - * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects - * referenced by the job. - * @dev: DRM device - * @file_priv: DRM file for this fd - * @job: V3D job being set up - * @bo_handles: GEM handles - * @bo_count: Number of GEM handles passed in - * - * The command validator needs to reference BOs by their index within - * the submitted job's BO list. This does the validation of the job's - * BO list and reference counting for the lifetime of the job. - * - * Note that this function doesn't need to unreference the BOs on - * failure, because that will happen at v3d_exec_cleanup() time. - */ -static int -v3d_lookup_bos(struct drm_device *dev, - struct drm_file *file_priv, - struct v3d_job *job, - u64 bo_handles, - u32 bo_count) -{ - job->bo_count = bo_count; - - if (!job->bo_count) { - /* See comment on bo_index for why we have to check - * this. - */ - DRM_DEBUG("Rendering requires BOs\n"); - return -EINVAL; - } - - return drm_gem_objects_lookup(file_priv, - (void __user *)(uintptr_t)bo_handles, - job->bo_count, &job->bo); -} - -static void -v3d_job_free(struct kref *ref) -{ - struct v3d_job *job = container_of(ref, struct v3d_job, refcount); - int i; - - if (job->bo) { - for (i = 0; i < job->bo_count; i++) - drm_gem_object_put(job->bo[i]); - kvfree(job->bo); - } - - dma_fence_put(job->irq_fence); - dma_fence_put(job->done_fence); - - if (job->perfmon) - v3d_perfmon_put(job->perfmon); - - kfree(job); -} - -static void -v3d_render_job_free(struct kref *ref) -{ - struct v3d_render_job *job = container_of(ref, struct v3d_render_job, - base.refcount); - struct v3d_bo *bo, *save; - - list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) { - drm_gem_object_put(&bo->base.base); - } - - v3d_job_free(ref); -} - -void v3d_job_cleanup(struct v3d_job *job) -{ - if (!job) - return; - - drm_sched_job_cleanup(&job->base); - v3d_job_put(job); -} - -void v3d_job_put(struct v3d_job *job) -{ - kref_put(&job->refcount, job->free); -} - -static int -v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, - void **container, size_t size, void (*free)(struct kref *ref), - u32 in_sync, struct v3d_submit_ext *se, enum v3d_queue queue) -{ - struct v3d_file_priv *v3d_priv = file_priv->driver_priv; - struct v3d_job *job; - bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); - int ret, i; - - *container = kcalloc(1, size, GFP_KERNEL); - if (!*container) { - DRM_ERROR("Cannot allocate memory for v3d job."); - return -ENOMEM; - } - - job = *container; - job->v3d = v3d; - job->free = free; - job->file = file_priv; - - ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], - 1, v3d_priv); - if (ret) - goto fail; - - if (has_multisync) { - if (se->in_sync_count && se->wait_stage == queue) { - struct drm_v3d_sem __user *handle = u64_to_user_ptr(se->in_syncs); - - for (i = 0; i < se->in_sync_count; i++) { - struct drm_v3d_sem in; - - if (copy_from_user(&in, handle++, sizeof(in))) { - ret = -EFAULT; - DRM_DEBUG("Failed to copy wait dep handle.\n"); - goto fail_deps; - } - ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv, in.handle, 0); - - // TODO: Investigate why this was filtered out for the IOCTL. - if (ret && ret != -ENOENT) - goto fail_deps; - } - } - } else { - ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv, in_sync, 0); - - // TODO: Investigate why this was filtered out for the IOCTL. - if (ret && ret != -ENOENT) - goto fail_deps; - } - - kref_init(&job->refcount); - - return 0; - -fail_deps: - drm_sched_job_cleanup(&job->base); -fail: - kfree(*container); - *container = NULL; - - return ret; -} - -static void -v3d_push_job(struct v3d_job *job) -{ - drm_sched_job_arm(&job->base); - - job->done_fence = dma_fence_get(&job->base.s_fence->finished); - - /* put by scheduler job completion */ - kref_get(&job->refcount); - - drm_sched_entity_push_job(&job->base); -} - -static void -v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, - struct v3d_job *job, - struct ww_acquire_ctx *acquire_ctx, - u32 out_sync, - struct v3d_submit_ext *se, - struct dma_fence *done_fence) -{ - struct drm_syncobj *sync_out; - bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); - int i; - - for (i = 0; i < job->bo_count; i++) { - /* XXX: Use shared fences for read-only objects. */ - dma_resv_add_fence(job->bo[i]->resv, job->done_fence, - DMA_RESV_USAGE_WRITE); - } - - drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); - - /* Update the return sync object for the job */ - /* If it only supports a single signal semaphore*/ - if (!has_multisync) { - sync_out = drm_syncobj_find(file_priv, out_sync); - if (sync_out) { - drm_syncobj_replace_fence(sync_out, done_fence); - drm_syncobj_put(sync_out); - } - return; - } - - /* If multiple semaphores extension is supported */ - if (se->out_sync_count) { - for (i = 0; i < se->out_sync_count; i++) { - drm_syncobj_replace_fence(se->out_syncs[i].syncobj, - done_fence); - drm_syncobj_put(se->out_syncs[i].syncobj); - } - kvfree(se->out_syncs); - } -} - -static void -v3d_put_multisync_post_deps(struct v3d_submit_ext *se) -{ - unsigned int i; - - if (!(se && se->out_sync_count)) - return; - - for (i = 0; i < se->out_sync_count; i++) - drm_syncobj_put(se->out_syncs[i].syncobj); - kvfree(se->out_syncs); -} - -static int -v3d_get_multisync_post_deps(struct drm_file *file_priv, - struct v3d_submit_ext *se, - u32 count, u64 handles) -{ - struct drm_v3d_sem __user *post_deps; - int i, ret; - - if (!count) - return 0; - - se->out_syncs = (struct v3d_submit_outsync *) - kvmalloc_array(count, - sizeof(struct v3d_submit_outsync), - GFP_KERNEL); - if (!se->out_syncs) - return -ENOMEM; - - post_deps = u64_to_user_ptr(handles); - - for (i = 0; i < count; i++) { - struct drm_v3d_sem out; - - if (copy_from_user(&out, post_deps++, sizeof(out))) { - ret = -EFAULT; - DRM_DEBUG("Failed to copy post dep handles\n"); - goto fail; - } - - se->out_syncs[i].syncobj = drm_syncobj_find(file_priv, - out.handle); - if (!se->out_syncs[i].syncobj) { - ret = -EINVAL; - goto fail; - } - } - se->out_sync_count = count; - - return 0; - -fail: - for (i--; i >= 0; i--) - drm_syncobj_put(se->out_syncs[i].syncobj); - kvfree(se->out_syncs); - - return ret; -} - -/* Get data for multiple binary semaphores synchronization. Parse syncobj - * to be signaled when job completes (out_sync). - */ -static int -v3d_get_multisync_submit_deps(struct drm_file *file_priv, - struct drm_v3d_extension __user *ext, - void *data) -{ - struct drm_v3d_multi_sync multisync; - struct v3d_submit_ext *se = data; - int ret; - - if (copy_from_user(&multisync, ext, sizeof(multisync))) - return -EFAULT; - - if (multisync.pad) - return -EINVAL; - - ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, - multisync.out_syncs); - if (ret) - return ret; - - se->in_sync_count = multisync.in_sync_count; - se->in_syncs = multisync.in_syncs; - se->flags |= DRM_V3D_EXT_ID_MULTI_SYNC; - se->wait_stage = multisync.wait_stage; - - return 0; -} - -/* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data - * according to the extension id (name). - */ -static int -v3d_get_extensions(struct drm_file *file_priv, - u64 ext_handles, - void *data) -{ - struct drm_v3d_extension __user *user_ext; - int ret; - - user_ext = u64_to_user_ptr(ext_handles); - while (user_ext) { - struct drm_v3d_extension ext; - - if (copy_from_user(&ext, user_ext, sizeof(ext))) { - DRM_DEBUG("Failed to copy submit extension\n"); - return -EFAULT; - } - - switch (ext.id) { - case DRM_V3D_EXT_ID_MULTI_SYNC: - ret = v3d_get_multisync_submit_deps(file_priv, user_ext, data); - if (ret) - return ret; - break; - default: - DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); - return -EINVAL; - } - - user_ext = u64_to_user_ptr(ext.next); - } - - return 0; -} - -/** - * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D. - * @dev: DRM device - * @data: ioctl argument - * @file_priv: DRM file for this fd - * - * This is the main entrypoint for userspace to submit a 3D frame to - * the GPU. Userspace provides the binner command list (if - * applicable), and the kernel sets up the render command list to draw - * to the framebuffer described in the ioctl, using the command lists - * that the 3D engine's binner will produce. - */ -int -v3d_submit_cl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct v3d_dev *v3d = to_v3d_dev(dev); - struct v3d_file_priv *v3d_priv = file_priv->driver_priv; - struct drm_v3d_submit_cl *args = data; - struct v3d_submit_ext se = {0}; - struct v3d_bin_job *bin = NULL; - struct v3d_render_job *render = NULL; - struct v3d_job *clean_job = NULL; - struct v3d_job *last_job; - struct ww_acquire_ctx acquire_ctx; - int ret = 0; - - trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); - - if (args->pad) - return -EINVAL; - - if (args->flags && - args->flags & ~(DRM_V3D_SUBMIT_CL_FLUSH_CACHE | - DRM_V3D_SUBMIT_EXTENSION)) { - DRM_INFO("invalid flags: %d\n", args->flags); - return -EINVAL; - } - - if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); - if (ret) { - DRM_DEBUG("Failed to get extensions.\n"); - return ret; - } - } - - ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), - v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER); - if (ret) - goto fail; - - render->start = args->rcl_start; - render->end = args->rcl_end; - INIT_LIST_HEAD(&render->unref_list); - - if (args->bcl_start != args->bcl_end) { - ret = v3d_job_init(v3d, file_priv, (void *)&bin, sizeof(*bin), - v3d_job_free, args->in_sync_bcl, &se, V3D_BIN); - if (ret) - goto fail; - - bin->start = args->bcl_start; - bin->end = args->bcl_end; - bin->qma = args->qma; - bin->qms = args->qms; - bin->qts = args->qts; - bin->render = render; - } - - if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { - ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), - v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); - if (ret) - goto fail; - - last_job = clean_job; - } else { - last_job = &render->base; - } - - ret = v3d_lookup_bos(dev, file_priv, last_job, - args->bo_handles, args->bo_handle_count); - if (ret) - goto fail; - - ret = v3d_lock_bo_reservations(last_job, &acquire_ctx); - if (ret) - goto fail; - - if (args->perfmon_id) { - render->base.perfmon = v3d_perfmon_find(v3d_priv, - args->perfmon_id); - - if (!render->base.perfmon) { - ret = -ENOENT; - goto fail_perfmon; - } - } - - mutex_lock(&v3d->sched_lock); - if (bin) { - bin->base.perfmon = render->base.perfmon; - v3d_perfmon_get(bin->base.perfmon); - v3d_push_job(&bin->base); - - ret = drm_sched_job_add_dependency(&render->base.base, - dma_fence_get(bin->base.done_fence)); - if (ret) - goto fail_unreserve; - } - - v3d_push_job(&render->base); - - if (clean_job) { - struct dma_fence *render_fence = - dma_fence_get(render->base.done_fence); - ret = drm_sched_job_add_dependency(&clean_job->base, - render_fence); - if (ret) - goto fail_unreserve; - clean_job->perfmon = render->base.perfmon; - v3d_perfmon_get(clean_job->perfmon); - v3d_push_job(clean_job); - } - - mutex_unlock(&v3d->sched_lock); - - v3d_attach_fences_and_unlock_reservation(file_priv, - last_job, - &acquire_ctx, - args->out_sync, - &se, - last_job->done_fence); - - if (bin) - v3d_job_put(&bin->base); - v3d_job_put(&render->base); - if (clean_job) - v3d_job_put(clean_job); - - return 0; - -fail_unreserve: - mutex_unlock(&v3d->sched_lock); -fail_perfmon: - drm_gem_unlock_reservations(last_job->bo, - last_job->bo_count, &acquire_ctx); -fail: - v3d_job_cleanup((void *)bin); - v3d_job_cleanup((void *)render); - v3d_job_cleanup(clean_job); - v3d_put_multisync_post_deps(&se); - - return ret; -} - -/** - * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D. - * @dev: DRM device - * @data: ioctl argument - * @file_priv: DRM file for this fd - * - * Userspace provides the register setup for the TFU, which we don't - * need to validate since the TFU is behind the MMU. - */ -int -v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct v3d_dev *v3d = to_v3d_dev(dev); - struct drm_v3d_submit_tfu *args = data; - struct v3d_submit_ext se = {0}; - struct v3d_tfu_job *job = NULL; - struct ww_acquire_ctx acquire_ctx; - int ret = 0; - - trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); - - if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { - DRM_DEBUG("invalid flags: %d\n", args->flags); - return -EINVAL; - } - - if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); - if (ret) { - DRM_DEBUG("Failed to get extensions.\n"); - return ret; - } - } - - ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), - v3d_job_free, args->in_sync, &se, V3D_TFU); - if (ret) - goto fail; - - job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), - sizeof(*job->base.bo), GFP_KERNEL); - if (!job->base.bo) { - ret = -ENOMEM; - goto fail; - } - - job->args = *args; - - for (job->base.bo_count = 0; - job->base.bo_count < ARRAY_SIZE(args->bo_handles); - job->base.bo_count++) { - struct drm_gem_object *bo; - - if (!args->bo_handles[job->base.bo_count]) - break; - - bo = drm_gem_object_lookup(file_priv, args->bo_handles[job->base.bo_count]); - if (!bo) { - DRM_DEBUG("Failed to look up GEM BO %d: %d\n", - job->base.bo_count, - args->bo_handles[job->base.bo_count]); - ret = -ENOENT; - goto fail; - } - job->base.bo[job->base.bo_count] = bo; - } - - ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx); - if (ret) - goto fail; - - mutex_lock(&v3d->sched_lock); - v3d_push_job(&job->base); - mutex_unlock(&v3d->sched_lock); - - v3d_attach_fences_and_unlock_reservation(file_priv, - &job->base, &acquire_ctx, - args->out_sync, - &se, - job->base.done_fence); - - v3d_job_put(&job->base); - - return 0; - -fail: - v3d_job_cleanup((void *)job); - v3d_put_multisync_post_deps(&se); - - return ret; -} - -/** - * v3d_submit_csd_ioctl() - Submits a CSD (texture formatting) job to the V3D. - * @dev: DRM device - * @data: ioctl argument - * @file_priv: DRM file for this fd - * - * Userspace provides the register setup for the CSD, which we don't - * need to validate since the CSD is behind the MMU. - */ -int -v3d_submit_csd_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct v3d_dev *v3d = to_v3d_dev(dev); - struct v3d_file_priv *v3d_priv = file_priv->driver_priv; - struct drm_v3d_submit_csd *args = data; - struct v3d_submit_ext se = {0}; - struct v3d_csd_job *job = NULL; - struct v3d_job *clean_job = NULL; - struct ww_acquire_ctx acquire_ctx; - int ret; - - trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]); - - if (args->pad) - return -EINVAL; - - if (!v3d_has_csd(v3d)) { - DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n"); - return -EINVAL; - } - - if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { - DRM_INFO("invalid flags: %d\n", args->flags); - return -EINVAL; - } - - if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); - if (ret) { - DRM_DEBUG("Failed to get extensions.\n"); - return ret; - } - } - - ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), - v3d_job_free, args->in_sync, &se, V3D_CSD); - if (ret) - goto fail; - - ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), - v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); - if (ret) - goto fail; - - job->args = *args; - - ret = v3d_lookup_bos(dev, file_priv, clean_job, - args->bo_handles, args->bo_handle_count); - if (ret) - goto fail; - - ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx); - if (ret) - goto fail; - - if (args->perfmon_id) { - job->base.perfmon = v3d_perfmon_find(v3d_priv, - args->perfmon_id); - if (!job->base.perfmon) { - ret = -ENOENT; - goto fail_perfmon; - } - } - - mutex_lock(&v3d->sched_lock); - v3d_push_job(&job->base); - - ret = drm_sched_job_add_dependency(&clean_job->base, - dma_fence_get(job->base.done_fence)); - if (ret) - goto fail_unreserve; - - v3d_push_job(clean_job); - mutex_unlock(&v3d->sched_lock); - - v3d_attach_fences_and_unlock_reservation(file_priv, - clean_job, - &acquire_ctx, - args->out_sync, - &se, - clean_job->done_fence); - - v3d_job_put(&job->base); - v3d_job_put(clean_job); - - return 0; - -fail_unreserve: - mutex_unlock(&v3d->sched_lock); -fail_perfmon: - drm_gem_unlock_reservations(clean_job->bo, clean_job->bo_count, - &acquire_ctx); -fail: - v3d_job_cleanup((void *)job); - v3d_job_cleanup(clean_job); - v3d_put_multisync_post_deps(&se); - - return ret; -} - int v3d_gem_init(struct drm_device *dev) { diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c new file mode 100644 index 000000000000..f36214002f37 --- /dev/null +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -0,0 +1,744 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014-2018 Broadcom + * Copyright (C) 2023 Raspberry Pi + */ + +#include + +#include "v3d_drv.h" +#include "v3d_regs.h" +#include "v3d_trace.h" + +/* Takes the reservation lock on all the BOs being referenced, so that + * at queue submit time we can update the reservations. + * + * We don't lock the RCL the tile alloc/state BOs, or overflow memory + * (all of which are on exec->unref_list). They're entirely private + * to v3d, so we don't attach dma-buf fences to them. + */ +static int +v3d_lock_bo_reservations(struct v3d_job *job, + struct ww_acquire_ctx *acquire_ctx) +{ + int i, ret; + + ret = drm_gem_lock_reservations(job->bo, job->bo_count, acquire_ctx); + if (ret) + return ret; + + for (i = 0; i < job->bo_count; i++) { + ret = dma_resv_reserve_fences(job->bo[i]->resv, 1); + if (ret) + goto fail; + + ret = drm_sched_job_add_implicit_dependencies(&job->base, + job->bo[i], true); + if (ret) + goto fail; + } + + return 0; + +fail: + drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); + return ret; +} + +/** + * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects + * referenced by the job. + * @dev: DRM device + * @file_priv: DRM file for this fd + * @job: V3D job being set up + * @bo_handles: GEM handles + * @bo_count: Number of GEM handles passed in + * + * The command validator needs to reference BOs by their index within + * the submitted job's BO list. This does the validation of the job's + * BO list and reference counting for the lifetime of the job. + * + * Note that this function doesn't need to unreference the BOs on + * failure, because that will happen at v3d_exec_cleanup() time. + */ +static int +v3d_lookup_bos(struct drm_device *dev, + struct drm_file *file_priv, + struct v3d_job *job, + u64 bo_handles, + u32 bo_count) +{ + job->bo_count = bo_count; + + if (!job->bo_count) { + /* See comment on bo_index for why we have to check + * this. + */ + DRM_DEBUG("Rendering requires BOs\n"); + return -EINVAL; + } + + return drm_gem_objects_lookup(file_priv, + (void __user *)(uintptr_t)bo_handles, + job->bo_count, &job->bo); +} + +static void +v3d_job_free(struct kref *ref) +{ + struct v3d_job *job = container_of(ref, struct v3d_job, refcount); + int i; + + if (job->bo) { + for (i = 0; i < job->bo_count; i++) + drm_gem_object_put(job->bo[i]); + kvfree(job->bo); + } + + dma_fence_put(job->irq_fence); + dma_fence_put(job->done_fence); + + if (job->perfmon) + v3d_perfmon_put(job->perfmon); + + kfree(job); +} + +static void +v3d_render_job_free(struct kref *ref) +{ + struct v3d_render_job *job = container_of(ref, struct v3d_render_job, + base.refcount); + struct v3d_bo *bo, *save; + + list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) { + drm_gem_object_put(&bo->base.base); + } + + v3d_job_free(ref); +} + +void v3d_job_cleanup(struct v3d_job *job) +{ + if (!job) + return; + + drm_sched_job_cleanup(&job->base); + v3d_job_put(job); +} + +void v3d_job_put(struct v3d_job *job) +{ + kref_put(&job->refcount, job->free); +} + +static int +v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, + void **container, size_t size, void (*free)(struct kref *ref), + u32 in_sync, struct v3d_submit_ext *se, enum v3d_queue queue) +{ + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct v3d_job *job; + bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); + int ret, i; + + *container = kcalloc(1, size, GFP_KERNEL); + if (!*container) { + DRM_ERROR("Cannot allocate memory for v3d job."); + return -ENOMEM; + } + + job = *container; + job->v3d = v3d; + job->free = free; + job->file = file_priv; + + ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], + 1, v3d_priv); + if (ret) + goto fail; + + if (has_multisync) { + if (se->in_sync_count && se->wait_stage == queue) { + struct drm_v3d_sem __user *handle = u64_to_user_ptr(se->in_syncs); + + for (i = 0; i < se->in_sync_count; i++) { + struct drm_v3d_sem in; + + if (copy_from_user(&in, handle++, sizeof(in))) { + ret = -EFAULT; + DRM_DEBUG("Failed to copy wait dep handle.\n"); + goto fail_deps; + } + ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv, in.handle, 0); + + // TODO: Investigate why this was filtered out for the IOCTL. + if (ret && ret != -ENOENT) + goto fail_deps; + } + } + } else { + ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv, in_sync, 0); + + // TODO: Investigate why this was filtered out for the IOCTL. + if (ret && ret != -ENOENT) + goto fail_deps; + } + + kref_init(&job->refcount); + + return 0; + +fail_deps: + drm_sched_job_cleanup(&job->base); +fail: + kfree(*container); + *container = NULL; + + return ret; +} + +static void +v3d_push_job(struct v3d_job *job) +{ + drm_sched_job_arm(&job->base); + + job->done_fence = dma_fence_get(&job->base.s_fence->finished); + + /* put by scheduler job completion */ + kref_get(&job->refcount); + + drm_sched_entity_push_job(&job->base); +} + +static void +v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, + struct v3d_job *job, + struct ww_acquire_ctx *acquire_ctx, + u32 out_sync, + struct v3d_submit_ext *se, + struct dma_fence *done_fence) +{ + struct drm_syncobj *sync_out; + bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); + int i; + + for (i = 0; i < job->bo_count; i++) { + /* XXX: Use shared fences for read-only objects. */ + dma_resv_add_fence(job->bo[i]->resv, job->done_fence, + DMA_RESV_USAGE_WRITE); + } + + drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); + + /* Update the return sync object for the job */ + /* If it only supports a single signal semaphore*/ + if (!has_multisync) { + sync_out = drm_syncobj_find(file_priv, out_sync); + if (sync_out) { + drm_syncobj_replace_fence(sync_out, done_fence); + drm_syncobj_put(sync_out); + } + return; + } + + /* If multiple semaphores extension is supported */ + if (se->out_sync_count) { + for (i = 0; i < se->out_sync_count; i++) { + drm_syncobj_replace_fence(se->out_syncs[i].syncobj, + done_fence); + drm_syncobj_put(se->out_syncs[i].syncobj); + } + kvfree(se->out_syncs); + } +} + +static void +v3d_put_multisync_post_deps(struct v3d_submit_ext *se) +{ + unsigned int i; + + if (!(se && se->out_sync_count)) + return; + + for (i = 0; i < se->out_sync_count; i++) + drm_syncobj_put(se->out_syncs[i].syncobj); + kvfree(se->out_syncs); +} + +static int +v3d_get_multisync_post_deps(struct drm_file *file_priv, + struct v3d_submit_ext *se, + u32 count, u64 handles) +{ + struct drm_v3d_sem __user *post_deps; + int i, ret; + + if (!count) + return 0; + + se->out_syncs = (struct v3d_submit_outsync *) + kvmalloc_array(count, + sizeof(struct v3d_submit_outsync), + GFP_KERNEL); + if (!se->out_syncs) + return -ENOMEM; + + post_deps = u64_to_user_ptr(handles); + + for (i = 0; i < count; i++) { + struct drm_v3d_sem out; + + if (copy_from_user(&out, post_deps++, sizeof(out))) { + ret = -EFAULT; + DRM_DEBUG("Failed to copy post dep handles\n"); + goto fail; + } + + se->out_syncs[i].syncobj = drm_syncobj_find(file_priv, + out.handle); + if (!se->out_syncs[i].syncobj) { + ret = -EINVAL; + goto fail; + } + } + se->out_sync_count = count; + + return 0; + +fail: + for (i--; i >= 0; i--) + drm_syncobj_put(se->out_syncs[i].syncobj); + kvfree(se->out_syncs); + + return ret; +} + +/* Get data for multiple binary semaphores synchronization. Parse syncobj + * to be signaled when job completes (out_sync). + */ +static int +v3d_get_multisync_submit_deps(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + void *data) +{ + struct drm_v3d_multi_sync multisync; + struct v3d_submit_ext *se = data; + int ret; + + if (copy_from_user(&multisync, ext, sizeof(multisync))) + return -EFAULT; + + if (multisync.pad) + return -EINVAL; + + ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, + multisync.out_syncs); + if (ret) + return ret; + + se->in_sync_count = multisync.in_sync_count; + se->in_syncs = multisync.in_syncs; + se->flags |= DRM_V3D_EXT_ID_MULTI_SYNC; + se->wait_stage = multisync.wait_stage; + + return 0; +} + +/* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data + * according to the extension id (name). + */ +static int +v3d_get_extensions(struct drm_file *file_priv, + u64 ext_handles, + void *data) +{ + struct drm_v3d_extension __user *user_ext; + int ret; + + user_ext = u64_to_user_ptr(ext_handles); + while (user_ext) { + struct drm_v3d_extension ext; + + if (copy_from_user(&ext, user_ext, sizeof(ext))) { + DRM_DEBUG("Failed to copy submit extension\n"); + return -EFAULT; + } + + switch (ext.id) { + case DRM_V3D_EXT_ID_MULTI_SYNC: + ret = v3d_get_multisync_submit_deps(file_priv, user_ext, data); + if (ret) + return ret; + break; + default: + DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); + return -EINVAL; + } + + user_ext = u64_to_user_ptr(ext.next); + } + + return 0; +} + +/** + * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * This is the main entrypoint for userspace to submit a 3D frame to + * the GPU. Userspace provides the binner command list (if + * applicable), and the kernel sets up the render command list to draw + * to the framebuffer described in the ioctl, using the command lists + * that the 3D engine's binner will produce. + */ +int +v3d_submit_cl_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct drm_v3d_submit_cl *args = data; + struct v3d_submit_ext se = {0}; + struct v3d_bin_job *bin = NULL; + struct v3d_render_job *render = NULL; + struct v3d_job *clean_job = NULL; + struct v3d_job *last_job; + struct ww_acquire_ctx acquire_ctx; + int ret = 0; + + trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); + + if (args->pad) + return -EINVAL; + + if (args->flags && + args->flags & ~(DRM_V3D_SUBMIT_CL_FLUSH_CACHE | + DRM_V3D_SUBMIT_EXTENSION)) { + DRM_INFO("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions, &se); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + + ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), + v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER); + if (ret) + goto fail; + + render->start = args->rcl_start; + render->end = args->rcl_end; + INIT_LIST_HEAD(&render->unref_list); + + if (args->bcl_start != args->bcl_end) { + ret = v3d_job_init(v3d, file_priv, (void *)&bin, sizeof(*bin), + v3d_job_free, args->in_sync_bcl, &se, V3D_BIN); + if (ret) + goto fail; + + bin->start = args->bcl_start; + bin->end = args->bcl_end; + bin->qma = args->qma; + bin->qms = args->qms; + bin->qts = args->qts; + bin->render = render; + } + + if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { + ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); + if (ret) + goto fail; + + last_job = clean_job; + } else { + last_job = &render->base; + } + + ret = v3d_lookup_bos(dev, file_priv, last_job, + args->bo_handles, args->bo_handle_count); + if (ret) + goto fail; + + ret = v3d_lock_bo_reservations(last_job, &acquire_ctx); + if (ret) + goto fail; + + if (args->perfmon_id) { + render->base.perfmon = v3d_perfmon_find(v3d_priv, + args->perfmon_id); + + if (!render->base.perfmon) { + ret = -ENOENT; + goto fail_perfmon; + } + } + + mutex_lock(&v3d->sched_lock); + if (bin) { + bin->base.perfmon = render->base.perfmon; + v3d_perfmon_get(bin->base.perfmon); + v3d_push_job(&bin->base); + + ret = drm_sched_job_add_dependency(&render->base.base, + dma_fence_get(bin->base.done_fence)); + if (ret) + goto fail_unreserve; + } + + v3d_push_job(&render->base); + + if (clean_job) { + struct dma_fence *render_fence = + dma_fence_get(render->base.done_fence); + ret = drm_sched_job_add_dependency(&clean_job->base, + render_fence); + if (ret) + goto fail_unreserve; + clean_job->perfmon = render->base.perfmon; + v3d_perfmon_get(clean_job->perfmon); + v3d_push_job(clean_job); + } + + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, + last_job, + &acquire_ctx, + args->out_sync, + &se, + last_job->done_fence); + + if (bin) + v3d_job_put(&bin->base); + v3d_job_put(&render->base); + if (clean_job) + v3d_job_put(clean_job); + + return 0; + +fail_unreserve: + mutex_unlock(&v3d->sched_lock); +fail_perfmon: + drm_gem_unlock_reservations(last_job->bo, + last_job->bo_count, &acquire_ctx); +fail: + v3d_job_cleanup((void *)bin); + v3d_job_cleanup((void *)render); + v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); + + return ret; +} + +/** + * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Userspace provides the register setup for the TFU, which we don't + * need to validate since the TFU is behind the MMU. + */ +int +v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct drm_v3d_submit_tfu *args = data; + struct v3d_submit_ext se = {0}; + struct v3d_tfu_job *job = NULL; + struct ww_acquire_ctx acquire_ctx; + int ret = 0; + + trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); + + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_DEBUG("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions, &se); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), + v3d_job_free, args->in_sync, &se, V3D_TFU); + if (ret) + goto fail; + + job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), + sizeof(*job->base.bo), GFP_KERNEL); + if (!job->base.bo) { + ret = -ENOMEM; + goto fail; + } + + job->args = *args; + + for (job->base.bo_count = 0; + job->base.bo_count < ARRAY_SIZE(args->bo_handles); + job->base.bo_count++) { + struct drm_gem_object *bo; + + if (!args->bo_handles[job->base.bo_count]) + break; + + bo = drm_gem_object_lookup(file_priv, args->bo_handles[job->base.bo_count]); + if (!bo) { + DRM_DEBUG("Failed to look up GEM BO %d: %d\n", + job->base.bo_count, + args->bo_handles[job->base.bo_count]); + ret = -ENOENT; + goto fail; + } + job->base.bo[job->base.bo_count] = bo; + } + + ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx); + if (ret) + goto fail; + + mutex_lock(&v3d->sched_lock); + v3d_push_job(&job->base); + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, + &job->base, &acquire_ctx, + args->out_sync, + &se, + job->base.done_fence); + + v3d_job_put(&job->base); + + return 0; + +fail: + v3d_job_cleanup((void *)job); + v3d_put_multisync_post_deps(&se); + + return ret; +} + +/** + * v3d_submit_csd_ioctl() - Submits a CSD (compute shader) job to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Userspace provides the register setup for the CSD, which we don't + * need to validate since the CSD is behind the MMU. + */ +int +v3d_submit_csd_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct drm_v3d_submit_csd *args = data; + struct v3d_submit_ext se = {0}; + struct v3d_csd_job *job = NULL; + struct v3d_job *clean_job = NULL; + struct ww_acquire_ctx acquire_ctx; + int ret; + + trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]); + + if (args->pad) + return -EINVAL; + + if (!v3d_has_csd(v3d)) { + DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n"); + return -EINVAL; + } + + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_INFO("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions, &se); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), + v3d_job_free, args->in_sync, &se, V3D_CSD); + if (ret) + goto fail; + + ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); + if (ret) + goto fail; + + job->args = *args; + + ret = v3d_lookup_bos(dev, file_priv, clean_job, + args->bo_handles, args->bo_handle_count); + if (ret) + goto fail; + + ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx); + if (ret) + goto fail; + + if (args->perfmon_id) { + job->base.perfmon = v3d_perfmon_find(v3d_priv, + args->perfmon_id); + if (!job->base.perfmon) { + ret = -ENOENT; + goto fail_perfmon; + } + } + + mutex_lock(&v3d->sched_lock); + v3d_push_job(&job->base); + + ret = drm_sched_job_add_dependency(&clean_job->base, + dma_fence_get(job->base.done_fence)); + if (ret) + goto fail_unreserve; + + v3d_push_job(clean_job); + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, + clean_job, + &acquire_ctx, + args->out_sync, + &se, + clean_job->done_fence); + + v3d_job_put(&job->base); + v3d_job_put(clean_job); + + return 0; + +fail_unreserve: + mutex_unlock(&v3d->sched_lock); +fail_perfmon: + drm_gem_unlock_reservations(clean_job->bo, clean_job->bo_count, + &acquire_ctx); +fail: + v3d_job_cleanup((void *)job); + v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); + + return ret; +} From 8288faaa8b3817c2fcdbacc720527bb8df2b57b1 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:27 -0300 Subject: [PATCH 2086/7721] drm/v3d: Simplify job refcount handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of checking if the job is NULL every time we call the function, check it inside the function. Signed-off-by: Melissa Wen Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-6-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_submit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index f36214002f37..a0caf9c499bb 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -129,6 +129,9 @@ void v3d_job_cleanup(struct v3d_job *job) void v3d_job_put(struct v3d_job *job) { + if (!job) + return; + kref_put(&job->refcount, job->free); } @@ -517,11 +520,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, &se, last_job->done_fence); - if (bin) - v3d_job_put(&bin->base); + v3d_job_put(&bin->base); v3d_job_put(&render->base); - if (clean_job) - v3d_job_put(clean_job); + v3d_job_put(clean_job); return 0; From 6893deb881ab7da1691bd05045ffcc0c806319b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:28 -0300 Subject: [PATCH 2087/7721] drm/v3d: Don't allow two multisync extensions in the same job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, two multisync extensions can be added to the same job and only the last multisync extension will be used. To avoid this vulnerability, don't allow two multisync extensions in the same job. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-7-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_submit.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index a0caf9c499bb..10141dc2820a 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -329,6 +329,11 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, struct v3d_submit_ext *se = data; int ret; + if (se->in_sync_count || se->out_sync_count) { + DRM_DEBUG("Two multisync extensions were added to the same job."); + return -EINVAL; + } + if (copy_from_user(&multisync, ext, sizeof(multisync))) return -EFAULT; From 464c61e76de851a216e667c91332172c68ffed54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:29 -0300 Subject: [PATCH 2088/7721] drm/v3d: Decouple job allocation from job initiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to allow the IOCTLs to allocate the job without initiating it. This will be useful for the CPU job submission IOCTL, as the CPU job has the need to use information from the user extensions. Currently, the user extensions are parsed before the job allocation, making it impossible to fill the CPU job when parsing the user extensions. Therefore, decouple the job allocation from the job initiation. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-8-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_submit.c | 66 ++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 10141dc2820a..148900283c2a 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -136,22 +136,26 @@ void v3d_job_put(struct v3d_job *job) } static int -v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, - void **container, size_t size, void (*free)(struct kref *ref), - u32 in_sync, struct v3d_submit_ext *se, enum v3d_queue queue) +v3d_job_allocate(void **container, size_t size) { - struct v3d_file_priv *v3d_priv = file_priv->driver_priv; - struct v3d_job *job; - bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); - int ret, i; - *container = kcalloc(1, size, GFP_KERNEL); if (!*container) { - DRM_ERROR("Cannot allocate memory for v3d job."); + DRM_ERROR("Cannot allocate memory for V3D job.\n"); return -ENOMEM; } - job = *container; + return 0; +} + +static int +v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, + struct v3d_job *job, void (*free)(struct kref *ref), + u32 in_sync, struct v3d_submit_ext *se, enum v3d_queue queue) +{ + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); + int ret, i; + job->v3d = v3d; job->free = free; job->file = file_priv; @@ -159,7 +163,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], 1, v3d_priv); if (ret) - goto fail; + return ret; if (has_multisync) { if (se->in_sync_count && se->wait_stage == queue) { @@ -194,10 +198,6 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, fail_deps: drm_sched_job_cleanup(&job->base); -fail: - kfree(*container); - *container = NULL; - return ret; } @@ -437,7 +437,11 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } } - ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), + ret = v3d_job_allocate((void *)&render, sizeof(*render)); + if (ret) + return ret; + + ret = v3d_job_init(v3d, file_priv, &render->base, v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER); if (ret) goto fail; @@ -447,7 +451,11 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, INIT_LIST_HEAD(&render->unref_list); if (args->bcl_start != args->bcl_end) { - ret = v3d_job_init(v3d, file_priv, (void *)&bin, sizeof(*bin), + ret = v3d_job_allocate((void *)&bin, sizeof(*bin)); + if (ret) + goto fail; + + ret = v3d_job_init(v3d, file_priv, &bin->base, v3d_job_free, args->in_sync_bcl, &se, V3D_BIN); if (ret) goto fail; @@ -461,7 +469,11 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { - ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + ret = v3d_job_allocate((void *)&clean_job, sizeof(*clean_job)); + if (ret) + goto fail; + + ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); if (ret) goto fail; @@ -580,7 +592,11 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, } } - ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), + ret = v3d_job_allocate((void *)&job, sizeof(*job)); + if (ret) + return ret; + + ret = v3d_job_init(v3d, file_priv, &job->base, v3d_job_free, args->in_sync, &se, V3D_TFU); if (ret) goto fail; @@ -683,12 +699,20 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, } } - ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), + ret = v3d_job_allocate((void *)&job, sizeof(*job)); + if (ret) + return ret; + + ret = v3d_job_init(v3d, file_priv, &job->base, v3d_job_free, args->in_sync, &se, V3D_CSD); if (ret) goto fail; - ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + ret = v3d_job_allocate((void *)&clean_job, sizeof(*clean_job)); + if (ret) + goto fail; + + ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); if (ret) goto fail; From aafc1a2bea67460c41a289e8bb1e4dc6d016fe11 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:30 -0300 Subject: [PATCH 2089/7721] drm/v3d: Add a CPU job submission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new type of job, a CPU job. A CPU job is a type of job that performs operations that requires CPU intervention. The overall idea is to use user extensions to enable different types of CPU job, allowing the CPU job to perform different operations according to the type of user extension. The user extension ID identify the type of CPU job that must be dealt. Having a CPU job is interesting for synchronization purposes as a CPU job has a queue like any other V3D job and can be synchoronized by the multisync extension. Signed-off-by: Melissa Wen Co-developed-by: Maíra Canal Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-9-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.c | 4 ++ drivers/gpu/drm/v3d/v3d_drv.h | 16 +++++- drivers/gpu/drm/v3d/v3d_sched.c | 57 +++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 86 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 17 +++++++ 5 files changed, 179 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 44a1ca57d6a4..3debf37e7d9b 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -91,6 +91,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: args->value = 1; return 0; + case DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE: + args->value = 1; + return 0; default: DRM_DEBUG("Unknown parameter %d\n", args->param); return -EINVAL; @@ -189,6 +192,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(V3D_PERFMON_CREATE, v3d_perfmon_create_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_PERFMON_DESTROY, v3d_perfmon_destroy_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), }; static const struct drm_driver v3d_drm_driver = { diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 4db9ace66024..2246a0e29955 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -19,7 +19,7 @@ struct reset_control; #define GMP_GRANULARITY (128 * 1024) -#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) +#define V3D_MAX_QUEUES (V3D_CPU + 1) static inline char *v3d_queue_to_string(enum v3d_queue queue) { @@ -29,6 +29,7 @@ static inline char *v3d_queue_to_string(enum v3d_queue queue) case V3D_TFU: return "tfu"; case V3D_CSD: return "csd"; case V3D_CACHE_CLEAN: return "cache_clean"; + case V3D_CPU: return "cpu"; } return "UNKNOWN"; } @@ -122,6 +123,7 @@ struct v3d_dev { struct v3d_render_job *render_job; struct v3d_tfu_job *tfu_job; struct v3d_csd_job *csd_job; + struct v3d_cpu_job *cpu_job; struct v3d_queue_state queue[V3D_MAX_QUEUES]; @@ -312,6 +314,16 @@ struct v3d_csd_job { struct drm_v3d_submit_csd args; }; +enum v3d_cpu_job_type {}; + +struct v3d_cpu_job { + struct v3d_job base; + + enum v3d_cpu_job_type job_type; +}; + +typedef void (*v3d_cpu_job_fn)(struct v3d_cpu_job *); + struct v3d_submit_outsync { struct drm_syncobj *syncobj; }; @@ -414,6 +426,8 @@ int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* v3d_irq.c */ int v3d_irq_init(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index fccbea2a5f2e..c89e92fc614c 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -55,6 +55,12 @@ to_csd_job(struct drm_sched_job *sched_job) return container_of(sched_job, struct v3d_csd_job, base.base); } +static struct v3d_cpu_job * +to_cpu_job(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct v3d_cpu_job, base.base); +} + static void v3d_sched_job_free(struct drm_sched_job *sched_job) { @@ -262,6 +268,42 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) return fence; } +static const v3d_cpu_job_fn cpu_job_function[] = { }; + +static struct dma_fence * +v3d_cpu_job_run(struct drm_sched_job *sched_job) +{ + struct v3d_cpu_job *job = to_cpu_job(sched_job); + struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; + u64 runtime; + + v3d->cpu_job = job; + + if (job->job_type >= ARRAY_SIZE(cpu_job_function)) { + DRM_DEBUG_DRIVER("Unknown CPU job: %d\n", job->job_type); + return NULL; + } + + file->start_ns[V3D_CPU] = local_clock(); + v3d->queue[V3D_CPU].start_ns = file->start_ns[V3D_CPU]; + + cpu_job_function[job->job_type](job); + + runtime = local_clock() - file->start_ns[V3D_CPU]; + + file->enabled_ns[V3D_CPU] += runtime; + v3d->queue[V3D_CPU].enabled_ns += runtime; + + file->jobs_sent[V3D_CPU]++; + v3d->queue[V3D_CPU].jobs_sent++; + + file->start_ns[V3D_CPU] = 0; + v3d->queue[V3D_CPU].start_ns = 0; + + return NULL; +} + static struct dma_fence * v3d_cache_clean_job_run(struct drm_sched_job *sched_job) { @@ -416,6 +458,12 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { .free_job = v3d_sched_job_free }; +static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { + .run_job = v3d_cpu_job_run, + .timedout_job = v3d_generic_job_timedout, + .free_job = v3d_sched_job_free +}; + int v3d_sched_init(struct v3d_dev *v3d) { @@ -471,6 +519,15 @@ v3d_sched_init(struct v3d_dev *v3d) goto fail; } + ret = drm_sched_init(&v3d->queue[V3D_CPU].sched, + &v3d_cpu_sched_ops, NULL, + DRM_SCHED_PRIORITY_COUNT, + 1, job_hang_limit, + msecs_to_jiffies(hang_limit_ms), NULL, + NULL, "v3d_cpu", v3d->drm.dev); + if (ret) + goto fail; + return 0; fail: diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 148900283c2a..918e28b1d00a 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -772,3 +772,89 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, return ret; } + +static const unsigned int cpu_job_bo_handle_count[] = { }; + +/** + * v3d_submit_cpu_ioctl() - Submits a CPU job to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Userspace specifies the CPU job type and data required to perform its + * operations through the drm_v3d_extension struct. + */ +int +v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct drm_v3d_submit_cpu *args = data; + struct v3d_submit_ext se = {0}; + struct v3d_cpu_job *cpu_job = NULL; + struct ww_acquire_ctx acquire_ctx; + int ret; + + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_INFO("Invalid flags: %d\n", args->flags); + return -EINVAL; + } + + ret = v3d_job_allocate((void *)&cpu_job, sizeof(*cpu_job)); + if (ret) + return ret; + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions, &se); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + goto fail; + } + } + + /* Every CPU job must have a CPU job user extension */ + if (!cpu_job->job_type) { + DRM_DEBUG("CPU job must have a CPU job user extension.\n"); + goto fail; + } + + if (args->bo_handle_count != cpu_job_bo_handle_count[cpu_job->job_type]) { + DRM_DEBUG("This CPU job was not submitted with the proper number of BOs.\n"); + goto fail; + } + + ret = v3d_job_init(v3d, file_priv, &cpu_job->base, + v3d_job_free, 0, &se, V3D_CPU); + if (ret) + goto fail; + + if (args->bo_handle_count) { + ret = v3d_lookup_bos(dev, file_priv, &cpu_job->base, + args->bo_handles, args->bo_handle_count); + if (ret) + goto fail; + + ret = v3d_lock_bo_reservations(&cpu_job->base, &acquire_ctx); + if (ret) + goto fail; + } + + mutex_lock(&v3d->sched_lock); + v3d_push_job(&cpu_job->base); + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, + &cpu_job->base, + &acquire_ctx, 0, + NULL, cpu_job->base.done_fence); + + v3d_job_put(&cpu_job->base); + + return 0; + +fail: + v3d_job_cleanup((void *)cpu_job); + v3d_put_multisync_post_deps(&se); + + return ret; +} diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 1a7d7a689de3..00abef9d0db7 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -41,6 +41,7 @@ extern "C" { #define DRM_V3D_PERFMON_CREATE 0x08 #define DRM_V3D_PERFMON_DESTROY 0x09 #define DRM_V3D_PERFMON_GET_VALUES 0x0a +#define DRM_V3D_SUBMIT_CPU 0x0b #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) @@ -56,6 +57,7 @@ extern "C" { struct drm_v3d_perfmon_destroy) #define DRM_IOCTL_V3D_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_PERFMON_GET_VALUES, \ struct drm_v3d_perfmon_get_values) +#define DRM_IOCTL_V3D_SUBMIT_CPU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CPU, struct drm_v3d_submit_cpu) #define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 #define DRM_V3D_SUBMIT_EXTENSION 0x02 @@ -93,6 +95,7 @@ enum v3d_queue { V3D_TFU, V3D_CSD, V3D_CACHE_CLEAN, + V3D_CPU, }; /** @@ -276,6 +279,7 @@ enum drm_v3d_param { DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, DRM_V3D_PARAM_SUPPORTS_PERFMON, DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT, + DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE, }; struct drm_v3d_get_param { @@ -361,6 +365,19 @@ struct drm_v3d_submit_csd { __u32 pad; }; +struct drm_v3d_submit_cpu { + /* Pointer to a u32 array of the BOs that are referenced by the job. */ + __u64 bo_handles; + + /* Number of BO handles passed in (size is that times 4). */ + __u32 bo_handle_count; + + __u32 flags; + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; +}; + enum { V3D_PERFCNT_FEP_VALID_PRIMTS_NO_PIXELS, V3D_PERFCNT_FEP_VALID_PRIMS, From c5195d001f4c122032a9ce90c6b88d772673fa35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:31 -0300 Subject: [PATCH 2090/7721] drm/v3d: Use v3d_get_extensions() to parse CPU job data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, v3d_get_extensions() only parses multisync data and assigns it to the `struct v3d_submit_ext`. But, to implement the CPU job with user extensions, we want v3d_get_extensions() to be able to parse CPU job data and assign it to the `struct v3d_cpu_job`. Therefore, allow the function v3d_get_extensions() to use `struct v3d_cpu_job *` as a parameter. If the `struct v3d_cpu_job *` is assigned to NULL, it means that the job is a GPU job and CPU job extensions should be rejected. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-10-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_submit.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 918e28b1d00a..124935547f17 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -323,10 +323,9 @@ v3d_get_multisync_post_deps(struct drm_file *file_priv, static int v3d_get_multisync_submit_deps(struct drm_file *file_priv, struct drm_v3d_extension __user *ext, - void *data) + struct v3d_submit_ext *se) { struct drm_v3d_multi_sync multisync; - struct v3d_submit_ext *se = data; int ret; if (se->in_sync_count || se->out_sync_count) { @@ -340,7 +339,7 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, if (multisync.pad) return -EINVAL; - ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, + ret = v3d_get_multisync_post_deps(file_priv, se, multisync.out_sync_count, multisync.out_syncs); if (ret) return ret; @@ -359,7 +358,8 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, static int v3d_get_extensions(struct drm_file *file_priv, u64 ext_handles, - void *data) + struct v3d_submit_ext *se, + struct v3d_cpu_job *job) { struct drm_v3d_extension __user *user_ext; int ret; @@ -375,15 +375,16 @@ v3d_get_extensions(struct drm_file *file_priv, switch (ext.id) { case DRM_V3D_EXT_ID_MULTI_SYNC: - ret = v3d_get_multisync_submit_deps(file_priv, user_ext, data); - if (ret) - return ret; + ret = v3d_get_multisync_submit_deps(file_priv, user_ext, se); break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; } + if (ret) + return ret; + user_ext = u64_to_user_ptr(ext.next); } @@ -430,7 +431,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); + ret = v3d_get_extensions(file_priv, args->extensions, &se, NULL); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -585,7 +586,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); + ret = v3d_get_extensions(file_priv, args->extensions, &se, NULL); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -692,7 +693,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); + ret = v3d_get_extensions(file_priv, args->extensions, &se, NULL); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -805,7 +806,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, return ret; if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions, &se); + ret = v3d_get_extensions(file_priv, args->extensions, &se, cpu_job); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); goto fail; From 1fe0879efc8f623816c7a825d853d2140c88cb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:32 -0300 Subject: [PATCH 2091/7721] drm/v3d: Create tracepoints to track the CPU job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create tracepoints to track the three major events of a CPU job lifetime: 1. Submission of a `v3d_submit_cpu` IOCTL 2. Beginning of the execution of a CPU job 3. Ending of the execution of a CPU job Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-11-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_sched.c | 4 +++ drivers/gpu/drm/v3d/v3d_submit.c | 2 ++ drivers/gpu/drm/v3d/v3d_trace.h | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index c89e92fc614c..ebbd00840a73 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -288,8 +288,12 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job) file->start_ns[V3D_CPU] = local_clock(); v3d->queue[V3D_CPU].start_ns = file->start_ns[V3D_CPU]; + trace_v3d_cpu_job_begin(&v3d->drm, job->job_type); + cpu_job_function[job->job_type](job); + trace_v3d_cpu_job_end(&v3d->drm, job->job_type); + runtime = local_clock() - file->start_ns[V3D_CPU]; file->enabled_ns[V3D_CPU] += runtime; diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 124935547f17..c134b113b181 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -824,6 +824,8 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, goto fail; } + trace_v3d_submit_cpu_ioctl(&v3d->drm, cpu_job->job_type); + ret = v3d_job_init(v3d, file_priv, &cpu_job->base, v3d_job_free, 0, &se, V3D_CPU); if (ret) diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h index 7aa8dc356e54..5917b94148f5 100644 --- a/drivers/gpu/drm/v3d/v3d_trace.h +++ b/drivers/gpu/drm/v3d/v3d_trace.h @@ -225,6 +225,63 @@ TRACE_EVENT(v3d_submit_csd, __entry->seqno) ); +TRACE_EVENT(v3d_submit_cpu_ioctl, + TP_PROTO(struct drm_device *dev, enum v3d_cpu_job_type job_type), + TP_ARGS(dev, job_type), + + TP_STRUCT__entry( + __field(u32, dev) + __field(enum v3d_cpu_job_type, job_type) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->job_type = job_type; + ), + + TP_printk("dev=%u, job_type=%d", + __entry->dev, + __entry->job_type) +); + +TRACE_EVENT(v3d_cpu_job_begin, + TP_PROTO(struct drm_device *dev, enum v3d_cpu_job_type job_type), + TP_ARGS(dev, job_type), + + TP_STRUCT__entry( + __field(u32, dev) + __field(enum v3d_cpu_job_type, job_type) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->job_type = job_type; + ), + + TP_printk("dev=%u, job_type=%d", + __entry->dev, + __entry->job_type) +); + +TRACE_EVENT(v3d_cpu_job_end, + TP_PROTO(struct drm_device *dev, enum v3d_cpu_job_type job_type), + TP_ARGS(dev, job_type), + + TP_STRUCT__entry( + __field(u32, dev) + __field(enum v3d_cpu_job_type, job_type) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->job_type = job_type; + ), + + TP_printk("dev=%u, job_type=%d", + __entry->dev, + __entry->job_type) +); + TRACE_EVENT(v3d_cache_clean_begin, TP_PROTO(struct drm_device *dev), TP_ARGS(dev), From 369b05961731925e4a43608ea1e7884df200f0bd Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Nov 2023 13:40:33 -0300 Subject: [PATCH 2092/7721] drm/v3d: Detach the CSD job BO setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detach CSD job setup from CSD submission ioctl to reuse it in CPU submission ioctl for indirect CSD job. Signed-off-by: Melissa Wen Co-developed-by: Maíra Canal Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-12-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_submit.c | 68 ++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index c134b113b181..eb26fe1e27e3 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -256,6 +256,45 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, } } +static int +v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv, + struct v3d_dev *v3d, + struct drm_v3d_submit_csd *args, + struct v3d_csd_job **job, + struct v3d_job **clean_job, + struct v3d_submit_ext *se, + struct ww_acquire_ctx *acquire_ctx) +{ + int ret; + + ret = v3d_job_allocate((void *)job, sizeof(**job)); + if (ret) + return ret; + + ret = v3d_job_init(v3d, file_priv, &(*job)->base, + v3d_job_free, args->in_sync, se, V3D_CSD); + if (ret) + return ret; + + ret = v3d_job_allocate((void *)clean_job, sizeof(**clean_job)); + if (ret) + return ret; + + ret = v3d_job_init(v3d, file_priv, *clean_job, + v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); + if (ret) + return ret; + + (*job)->args = *args; + + ret = v3d_lookup_bos(&v3d->drm, file_priv, *clean_job, + args->bo_handles, args->bo_handle_count); + if (ret) + return ret; + + return v3d_lock_bo_reservations(*clean_job, acquire_ctx); +} + static void v3d_put_multisync_post_deps(struct v3d_submit_ext *se) { @@ -700,32 +739,9 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, } } - ret = v3d_job_allocate((void *)&job, sizeof(*job)); - if (ret) - return ret; - - ret = v3d_job_init(v3d, file_priv, &job->base, - v3d_job_free, args->in_sync, &se, V3D_CSD); - if (ret) - goto fail; - - ret = v3d_job_allocate((void *)&clean_job, sizeof(*clean_job)); - if (ret) - goto fail; - - ret = v3d_job_init(v3d, file_priv, clean_job, - v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); - if (ret) - goto fail; - - job->args = *args; - - ret = v3d_lookup_bos(dev, file_priv, clean_job, - args->bo_handles, args->bo_handle_count); - if (ret) - goto fail; - - ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx); + ret = v3d_setup_csd_jobs_and_bos(file_priv, v3d, args, + &job, &clean_job, &se, + &acquire_ctx); if (ret) goto fail; From 7c13132c4073628b5fe23b5188ac583a2882a6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:34 -0300 Subject: [PATCH 2093/7721] drm/v3d: Enable BO mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the indirect CSD CPU job, we will need to access the internal contents of the BO with the dispatch parameters. Therefore, create methods to allow the mapping and unmapping of the BO. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-13-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_bo.c | 18 ++++++++++++++++++ drivers/gpu/drm/v3d/v3d_drv.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index 357a0da7e16a..1bdfac8beafd 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -33,6 +33,9 @@ void v3d_free_object(struct drm_gem_object *obj) struct v3d_dev *v3d = to_v3d_dev(obj->dev); struct v3d_bo *bo = to_v3d_bo(obj); + if (bo->vaddr) + v3d_put_bo_vaddr(bo); + v3d_mmu_remove_ptes(bo); mutex_lock(&v3d->bo_lock); @@ -134,6 +137,7 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv, if (IS_ERR(shmem_obj)) return ERR_CAST(shmem_obj); bo = to_v3d_bo(&shmem_obj->base); + bo->vaddr = NULL; ret = v3d_bo_create_finish(&shmem_obj->base); if (ret) @@ -167,6 +171,20 @@ v3d_prime_import_sg_table(struct drm_device *dev, return obj; } +void v3d_get_bo_vaddr(struct v3d_bo *bo) +{ + struct drm_gem_shmem_object *obj = &bo->base; + + bo->vaddr = vmap(obj->pages, obj->base.size >> PAGE_SHIFT, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); +} + +void v3d_put_bo_vaddr(struct v3d_bo *bo) +{ + vunmap(bo->vaddr); + bo->vaddr = NULL; +} + int v3d_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 2246a0e29955..39d62915cdd6 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -202,6 +202,8 @@ struct v3d_bo { * v3d_render_job->unref_list */ struct list_head unref_head; + + void *vaddr; }; static inline struct v3d_bo * @@ -391,6 +393,8 @@ struct drm_gem_object *v3d_create_object(struct drm_device *dev, size_t size); void v3d_free_object(struct drm_gem_object *gem_obj); struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv, size_t size); +void v3d_get_bo_vaddr(struct v3d_bo *bo); +void v3d_put_bo_vaddr(struct v3d_bo *bo); int v3d_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data, From 70582e26f5d9a94b373f925186c03455849fd3db Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 19 Oct 2023 17:44:59 +0000 Subject: [PATCH 2094/7721] wifi: iwlwifi: fw: replace deprecated strncpy with strscpy_pad strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. Based on the deliberate `sizeof(dest) ... - 1` pattern we can see that both dump_info->dev_human_readable and dump_info->bus_human_readable are intended to be NUL-terminated. Moreover, since this seems to cross the file boundary let's NUL-pad to ensure no behavior change. strscpy_pad() covers both the NUL-termination and NUL-padding, let's use it. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231019-strncpy-drivers-net-wireless-intel-iwlwifi-fw-dbg-c-v2-1-179b211a374b@google.com --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 3975a53a9f20..7ee9b7c8a3ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -880,10 +880,10 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, cpu_to_le32(fwrt->trans->hw_rev_step); memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); - strncpy(dump_info->dev_human_readable, fwrt->trans->name, - sizeof(dump_info->dev_human_readable) - 1); - strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name, - sizeof(dump_info->bus_human_readable) - 1); + strscpy_pad(dump_info->dev_human_readable, fwrt->trans->name, + sizeof(dump_info->dev_human_readable)); + strscpy_pad(dump_info->bus_human_readable, fwrt->dev->bus->name, + sizeof(dump_info->bus_human_readable)); dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs; dump_info->lmac_err_id[0] = cpu_to_le32(fwrt->dump.lmac_err_id[0]); From fdb3bb0af2599f780ea7dd04a13b610b70d65a3f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:16:56 +0800 Subject: [PATCH 2095/7721] wifi: rtw89: 8922a: extend and add quota number Define 8922A buffer quota that are used by HCI control flow, payload engine, descriptor engine and etc for operation modes, such as SCC (single channel concurrence) and download firmware. Since WiFi 7 chips has more buffer classifications, add fields and struct according to design. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 26 ++++++++++ drivers/net/wireless/realtek/rtw89/mac.c | 14 ++++++ drivers/net/wireless/realtek/rtw89/mac.h | 14 ++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 50 +++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c9f054c0f6fb..7010cf818fb4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3292,6 +3292,8 @@ struct rtw89_dle_size { u16 pge_size; u16 lnk_pge_num; u16 unlnk_pge_num; + /* for WiFi 7 chips below */ + u32 srt_ofst; }; struct rtw89_wde_quota { @@ -3314,6 +3316,26 @@ struct rtw89_ple_quota { u16 wd_rel; u16 cpu_io; u16 tx_rpt; + /* for WiFi 7 chips below */ + u16 h2d; +}; + +struct rtw89_rsvd_quota { + u16 mpdu_info_tbl; + u16 b0_csi; + u16 b1_csi; + u16 b0_lmr; + u16 b1_lmr; + u16 b0_ftm; + u16 b1_ftm; + u16 b0_smr; + u16 b1_smr; + u16 others; +}; + +struct rtw89_dle_rsvd_size { + u32 srt_ofst; + u32 size; }; struct rtw89_dle_mem { @@ -3324,6 +3346,10 @@ struct rtw89_dle_mem { const struct rtw89_wde_quota *wde_max_qt; const struct rtw89_ple_quota *ple_min_qt; const struct rtw89_ple_quota *ple_max_qt; + /* for WiFi 7 chips below */ + const struct rtw89_rsvd_quota *rsvd_qt; + const struct rtw89_dle_rsvd_size *rsvd0_size; + const struct rtw89_dle_rsvd_size *rsvd1_size; }; struct rtw89_reg_def { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 9ec307051611..b93a00f56cb9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1461,10 +1461,14 @@ static int rtw89_mac_sys_init(struct rtw89_dev *rtwdev) const struct rtw89_mac_size_set rtw89_mac_size = { .hfc_preccfg_pcie = {2, 40, 0, 0, 1, 0, 0, 0}, + .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0}, + .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0}, /* PCIE 64 */ .wde_size0 = {RTW89_WDE_PG_64, 4095, 1,}, + .wde_size0_v1 = {RTW89_WDE_PG_64, 3328, 0, 0,}, /* DLFW */ .wde_size4 = {RTW89_WDE_PG_64, 0, 4096,}, + .wde_size4_v1 = {RTW89_WDE_PG_64, 0, 3328, 0,}, /* PCIE 64 */ .wde_size6 = {RTW89_WDE_PG_64, 512, 0,}, /* 8852B PCIE SCC */ @@ -1477,6 +1481,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, + .ple_size0_v1 = {RTW89_PLE_PG_128, 2672, 256, 212992,}, + .ple_size3_v1 = {RTW89_PLE_PG_128, 2928, 0, 212992,}, /* DLFW */ .ple_size4 = {RTW89_PLE_PG_128, 64, 1472,}, /* PCIE 64 */ @@ -1489,6 +1495,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, /* PCIE 64 */ .wde_qt0 = {3792, 196, 0, 107,}, + .wde_qt0_v1 = {3302, 6, 0, 20,}, /* DLFW */ .wde_qt4 = {0, 0, 0, 0,}, /* PCIE 64 */ @@ -1499,10 +1506,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, + .ple_qt0 = {320, 0, 32, 16, 13, 13, 292, 0, 32, 18, 1, 4, 0,}, + .ple_qt1 = {320, 0, 32, 16, 1944, 1944, 2223, 0, 1963, 1949, 1, 1935, 0,}, /* PCIE SCC */ .ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,}, /* PCIE SCC */ .ple_qt5 = {264, 0, 32, 20, 64, 13, 1101, 0, 64, 128, 120,}, + .ple_qt9 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0,}, /* DLFW */ .ple_qt13 = {0, 0, 16, 48, 0, 0, 0, 0, 0, 0, 0,}, /* PCIE 64 */ @@ -1523,6 +1533,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_52b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, /* 8851B PCIE WOW */ .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, + .ple_rsvd_qt0 = {2, 112, 56, 6, 6, 6, 6, 0, 0, 62,}, + .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .rsvd0_size0 = {212992, 0,}, + .rsvd1_size0 = {587776, 2048,}, }; EXPORT_SYMBOL(rtw89_mac_size); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index f47a42387a6a..511ee5dc4240 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -818,27 +818,37 @@ enum mac_ax_err_info { struct rtw89_mac_size_set { const struct rtw89_hfc_prec_cfg hfc_preccfg_pcie; + const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c0; + const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c2; const struct rtw89_dle_size wde_size0; + const struct rtw89_dle_size wde_size0_v1; const struct rtw89_dle_size wde_size4; + const struct rtw89_dle_size wde_size4_v1; const struct rtw89_dle_size wde_size6; const struct rtw89_dle_size wde_size7; const struct rtw89_dle_size wde_size9; const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size ple_size0; + const struct rtw89_dle_size ple_size0_v1; + const struct rtw89_dle_size ple_size3_v1; const struct rtw89_dle_size ple_size4; const struct rtw89_dle_size ple_size6; const struct rtw89_dle_size ple_size8; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; const struct rtw89_wde_quota wde_qt0; + const struct rtw89_wde_quota wde_qt0_v1; const struct rtw89_wde_quota wde_qt4; const struct rtw89_wde_quota wde_qt6; const struct rtw89_wde_quota wde_qt7; const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; + const struct rtw89_ple_quota ple_qt0; + const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; const struct rtw89_ple_quota ple_qt5; + const struct rtw89_ple_quota ple_qt9; const struct rtw89_ple_quota ple_qt13; const struct rtw89_ple_quota ple_qt18; const struct rtw89_ple_quota ple_qt44; @@ -849,6 +859,10 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; const struct rtw89_ple_quota ple_qt_51b_wow; + const struct rtw89_rsvd_quota ple_rsvd_qt0; + const struct rtw89_rsvd_quota ple_rsvd_qt1; + const struct rtw89_dle_rsvd_size rsvd0_size0; + const struct rtw89_dle_rsvd_size rsvd1_size0; }; extern const struct rtw89_mac_size_set rtw89_mac_size; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index d190f095a5a8..b75d555d0cc3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -15,6 +15,54 @@ #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME ".bin" +static const struct rtw89_hfc_ch_cfg rtw8922a_hfc_chcfg_pcie[] = { + {2, 1641, grp_0}, /* ACH 0 */ + {2, 1641, grp_0}, /* ACH 1 */ + {2, 1641, grp_0}, /* ACH 2 */ + {2, 1641, grp_0}, /* ACH 3 */ + {2, 1641, grp_1}, /* ACH 4 */ + {2, 1641, grp_1}, /* ACH 5 */ + {2, 1641, grp_1}, /* ACH 6 */ + {2, 1641, grp_1}, /* ACH 7 */ + {2, 1641, grp_0}, /* B0MGQ */ + {2, 1641, grp_0}, /* B0HIQ */ + {2, 1641, grp_1}, /* B1MGQ */ + {2, 1641, grp_1}, /* B1HIQ */ + {0, 0, 0}, /* FWCMDQ */ + {0, 0, 0}, /* BMC */ + {0, 0, 0}, /* H2D */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8922a_hfc_pubcfg_pcie = { + 1651, /* Group 0 */ + 1651, /* Group 1 */ + 3302, /* Public Max */ + 0, /* WP threshold */ +}; + +static const struct rtw89_hfc_param_ini rtw8922a_hfc_param_ini_pcie[] = { + [RTW89_QTA_SCC] = {rtw8922a_hfc_chcfg_pcie, &rtw8922a_hfc_pubcfg_pcie, + &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH}, + [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_prec_cfg_c2, + RTW89_HCIFC_POH}, + [RTW89_QTA_INVALID] = {NULL}, +}; + +static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size0_v1, + &rtw89_mac_size.ple_size0_v1, &rtw89_mac_size.wde_qt0_v1, + &rtw89_mac_size.wde_qt0_v1, &rtw89_mac_size.ple_qt0, + &rtw89_mac_size.ple_qt1, &rtw89_mac_size.ple_rsvd_qt0, + &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4_v1, + &rtw89_mac_size.ple_size3_v1, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt9, + &rtw89_mac_size.ple_qt9, &rtw89_mac_size.ple_rsvd_qt1, + &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, @@ -292,6 +340,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, + .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, + .dle_mem = rtw8922a_dle_mem_pcie, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, From cecf1643145a3a5980aff221e7b5ca8f90efa1cf Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:16:57 +0800 Subject: [PATCH 2096/7721] wifi: rtw89: mac: add to get DLE reserved quota The reserved quota of DLE (data link engine) is used for processing next packet. Add this to get quota number, and then WiFi 7 chips can use them. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/mac.c | 55 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 19 ++++++++ 3 files changed, 76 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7010cf818fb4..5124f9842596 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3807,8 +3807,10 @@ enum rtw89_hcifc_mode { }; struct rtw89_dle_info { + const struct rtw89_rsvd_quota *rsvd_qt; enum rtw89_qta_mode qta_mode; u16 ple_pg_size; + u16 ple_free_pg; u16 c0_rx_qta; u16 c1_rx_qta; }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b93a00f56cb9..ac14865a114a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1555,7 +1555,9 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return NULL; } + mac->dle_info.rsvd_qt = cfg->rsvd_qt; mac->dle_info.ple_pg_size = cfg->ple_size->pge_size; + mac->dle_info.ple_free_pg = cfg->ple_size->lnk_pge_num; mac->dle_info.qta_mode = mode; mac->dle_info.c0_rx_qta = cfg->ple_min_qt->cma0_dma; mac->dle_info.c1_rx_qta = cfg->ple_min_qt->cma1_dma; @@ -1563,6 +1565,59 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return cfg; } +int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, + enum rtw89_mac_dle_rsvd_qt_type type, + struct rtw89_mac_dle_rsvd_qt_cfg *cfg) +{ + struct rtw89_dle_info *dle_info = &rtwdev->mac.dle_info; + const struct rtw89_rsvd_quota *rsvd_qt = dle_info->rsvd_qt; + + switch (type) { + case DLE_RSVD_QT_MPDU_INFO: + cfg->pktid = dle_info->ple_free_pg; + cfg->pg_num = rsvd_qt->mpdu_info_tbl; + break; + case DLE_RSVD_QT_B0_CSI: + cfg->pktid = dle_info->ple_free_pg + rsvd_qt->mpdu_info_tbl; + cfg->pg_num = rsvd_qt->b0_csi; + break; + case DLE_RSVD_QT_B1_CSI: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi; + cfg->pg_num = rsvd_qt->b1_csi; + break; + case DLE_RSVD_QT_B0_LMR: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi; + cfg->pg_num = rsvd_qt->b0_lmr; + break; + case DLE_RSVD_QT_B1_LMR: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr; + cfg->pg_num = rsvd_qt->b1_lmr; + break; + case DLE_RSVD_QT_B0_FTM: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr + rsvd_qt->b1_lmr; + cfg->pg_num = rsvd_qt->b0_ftm; + break; + case DLE_RSVD_QT_B1_FTM: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr + rsvd_qt->b1_lmr + rsvd_qt->b0_ftm; + cfg->pg_num = rsvd_qt->b1_ftm; + break; + default: + return -EINVAL; + } + + cfg->size = (u32)cfg->pg_num * dle_info->ple_pg_size; + + return 0; +} + static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 511ee5dc4240..b16fa9bbd412 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -650,6 +650,22 @@ struct rtw89_mac_dle_dfi_qempty { u32 qempty; }; +enum rtw89_mac_dle_rsvd_qt_type { + DLE_RSVD_QT_MPDU_INFO, + DLE_RSVD_QT_B0_CSI, + DLE_RSVD_QT_B1_CSI, + DLE_RSVD_QT_B0_LMR, + DLE_RSVD_QT_B1_LMR, + DLE_RSVD_QT_B0_FTM, + DLE_RSVD_QT_B1_FTM, +}; + +struct rtw89_mac_dle_rsvd_qt_cfg { + u16 pktid; + u16 pg_num; + u32 size; +}; + enum rtw89_mac_error_scenario { RTW89_RXI300_ERROR = 1, RTW89_WCPU_CPU_EXCEPTION = 2, @@ -1254,5 +1270,8 @@ int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, enum rtw89_mac_idx band); void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); +int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, + enum rtw89_mac_dle_rsvd_qt_type type, + struct rtw89_mac_dle_rsvd_qt_cfg *cfg); #endif From aabe741e2d18a3a28b0f08c53b7a81374c0690b0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:16:58 +0800 Subject: [PATCH 2097/7721] wifi: rtw89: add reserved size as factor of DLE used size DLE stands for Double Link Engine that is used to maintain buffer page. To avoid linking to wrong pages, we check the used page size during initialization and stop driver probe if the used size is unexpected. Currently, we check the page size used by PLE (payload engine) and WDE (WiFi descriptor engine). For coming WiFi 7 chips, additional reserved size is added for BB as buffer to run LA mode, so add and check the reserved size as well. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index ac14865a114a..bdd9c152951f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1672,11 +1672,21 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) return (val32 & msk32) == msk32; } -static inline u32 dle_used_size(const struct rtw89_dle_size *wde, - const struct rtw89_dle_size *ple) +static inline u32 dle_used_size(const struct rtw89_dle_mem *cfg) { - return wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) + + const struct rtw89_dle_size *wde = cfg->wde_size; + const struct rtw89_dle_size *ple = cfg->ple_size; + u32 used; + + used = wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) + ple->pge_size * (ple->lnk_pge_num + ple->unlnk_pge_num); + + if (cfg->rsvd0_size && cfg->rsvd1_size) { + used += cfg->rsvd0_size->size; + used += cfg->rsvd1_size->size; + } + + return used; } static u32 dle_expected_used_size(struct rtw89_dev *rtwdev, @@ -1898,8 +1908,7 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, ext_wde_min_qt_wcpu = ext_cfg->wde_min_qt->wcpu; } - if (dle_used_size(cfg->wde_size, cfg->ple_size) != - dle_expected_used_size(rtwdev, mode)) { + if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) { rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n"); ret = -EINVAL; goto error; @@ -3037,8 +3046,7 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) return -EINVAL; } - if (dle_used_size(cfg->wde_size, cfg->ple_size) != - dle_expected_used_size(rtwdev, mode)) { + if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) { rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n"); return -EINVAL; } From 2706cb25028dd27471e25047bcc3e5df73644a4a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 24 Nov 2023 15:16:59 +0800 Subject: [PATCH 2098/7721] wifi: rtw89: refine element naming used by queue empty check In queue empty check, one group contains 32 queues. And, the two elements, wde_qempty_acq_num and wde_qempty_mgq_sel, are number of group and select of group. To avoid confusing them with queue number and queue selection, we refine their naming. (don't change logic at all) Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 4 ++-- drivers/net/wireless/realtek/rtw89/mac.c | 8 ++++---- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 ++ 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 5124f9842596..c315ef96e91e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3692,8 +3692,8 @@ struct rtw89_chip_info { u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini; const struct rtw89_dle_mem *dle_mem; - u8 wde_qempty_acq_num; - u8 wde_qempty_mgq_sel; + u8 wde_qempty_acq_grpnum; + u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; u8 support_chanctx_num; u8 support_bands; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index bdd9c152951f..b5e32b830a17 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1621,13 +1621,13 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; - u32 qnum, qtmp, val32, msk32; + u32 grpnum, qtmp, val32, msk32; int i, j, ret; - qnum = rtwdev->chip->wde_qempty_acq_num; + grpnum = rtwdev->chip->wde_qempty_acq_grpnum; qempty.dle_type = DLE_CTRL_TYPE_WDE; - for (i = 0; i < qnum; i++) { + for (i = 0; i < grpnum; i++) { qempty.grpsel = i; ret = dle_dfi_qempty(rtwdev, &qempty); if (ret) { @@ -1643,7 +1643,7 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) } } - qempty.grpsel = rtwdev->chip->wde_qempty_mgq_sel; + qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel; ret = dle_dfi_qempty(rtwdev, &qempty); if (ret) { rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index ed1f0560a514..e850e34be51f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2374,8 +2374,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, .dle_mem = rtw8851b_dle_mem_pcie, - .wde_qempty_acq_num = 4, - .wde_qempty_mgq_sel = 4, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 561049d17854..90f39a8791ea 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2109,8 +2109,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, .dle_mem = rtw8852a_dle_mem_pcie, - .wde_qempty_acq_num = 16, - .wde_qempty_mgq_sel = 16, + .wde_qempty_acq_grpnum = 16, + .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, .pwr_on_seq = pwr_on_seq_8852a, .pwr_off_seq = pwr_off_seq_8852a, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 9c62844cf06b..7b2062cc8499 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2543,8 +2543,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, .dle_mem = rtw8852b_dle_mem_pcie, - .wde_qempty_acq_num = 4, - .wde_qempty_mgq_sel = 4, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 976d34b33377..d618faf1885b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2879,8 +2879,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, .dle_mem = rtw8852c_dle_mem_pcie, - .wde_qempty_acq_num = 16, - .wde_qempty_mgq_sel = 16, + .wde_qempty_acq_grpnum = 16, + .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index b75d555d0cc3..a82c17fb1281 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -342,6 +342,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .rsvd_ple_ofst = 0x8f800, .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, .dle_mem = rtw8922a_dle_mem_pcie, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, From 27ea6be913f42ebeecac43916be3ed43025b2dca Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 24 Nov 2023 15:17:00 +0800 Subject: [PATCH 2099/7721] wifi: rtw89: mac: check queue empty according to chip gen This function, currently called by WoWLAN flow, polls until specific HW queues are empty. The polling bit definitions are not totally the same between WiFi 6 and 7 chips. In addition, the check conditions are also a little different. So, we differentiate the implementations according to chip gen. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 17 +++++--- drivers/net/wireless/realtek/rtw89/mac.h | 7 +++ drivers/net/wireless/realtek/rtw89/mac_be.c | 47 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 30 +++++++++++++ 4 files changed, 94 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b5e32b830a17..074c1edb0d25 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -174,8 +174,8 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev, return 0; } -static int dle_dfi_qempty(struct rtw89_dev *rtwdev, - struct rtw89_mac_dle_dfi_qempty *qempty) +int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_qempty *qempty) { struct rtw89_mac_dle_dfi_ctrl ctrl; u32 ret; @@ -220,7 +220,7 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) qempty.dle_type = DLE_CTRL_TYPE_PLE; qempty.grpsel = 0; qempty.qempty = ~(u32)0; - ret = dle_dfi_qempty(rtwdev, &qempty); + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else @@ -1618,7 +1618,7 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, return 0; } -static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) +static bool mac_is_txq_empty_ax(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; u32 grpnum, qtmp, val32, msk32; @@ -1629,7 +1629,7 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) for (i = 0; i < grpnum; i++) { qempty.grpsel = i; - ret = dle_dfi_qempty(rtwdev, &qempty); + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) { rtw89_warn(rtwdev, "dle dfi acq empty %d\n", ret); return false; @@ -1644,7 +1644,7 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) } qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel; - ret = dle_dfi_qempty(rtwdev, &qempty); + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) { rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret); return false; @@ -5797,6 +5797,7 @@ void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, enum rtw89_mac_idx band) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_pkt_drop_params params = {0}; bool empty; int i, ret = 0, try_cnt = 3; @@ -5805,7 +5806,7 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, params.sel = RTW89_PKT_DROP_SEL_BAND_ONCE; for (i = 0; i < try_cnt; i++) { - ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50, + ret = read_poll_timeout(mac->is_txq_empty, empty, empty, 50, 50000, false, rtwdev); if (ret && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw)) rtw89_fw_h2c_pkt_drop(rtwdev, ¶ms); @@ -5864,5 +5865,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .cnv_efuse_state = rtw89_cnv_efuse_state_ax, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, + + .is_txq_empty = mac_is_txq_empty_ax, }; EXPORT_SYMBOL(rtw89_mac_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b16fa9bbd412..8beb278934bf 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -537,6 +537,9 @@ enum rtw89_mac_bf_rrsc_rate { #define B_CMAC1_MGQ_NO_PWRSAV BIT(11) #define B_CMAC1_CPUMGQ BIT(12) +#define B_CMAC0_MGQ_NORMAL_BE BIT(2) +#define B_CMAC1_MGQ_NORMAL_BE BIT(30) + #define QEMP_ACQ_GRP_MACID_NUM 8 #define QEMP_ACQ_GRP_QSEL_SH 4 #define QEMP_ACQ_GRP_QSEL_MASK 0xF @@ -910,6 +913,8 @@ struct rtw89_mac_gen_def { bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr); + + bool (*is_txq_empty)(struct rtw89_dev *rtwdev); }; extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax; @@ -1015,6 +1020,8 @@ int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 band, enum rtw89_mac_hwmod_sel sel); int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val); int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val); +int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_qempty *qempty); int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 1c607316f652..612baa8b83d9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -405,6 +405,51 @@ static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev, } } +static bool mac_is_txq_empty_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + u32 val32, msk32; + u32 grpnum; + int ret; + int i; + + grpnum = rtwdev->chip->wde_qempty_acq_grpnum; + qempty.dle_type = DLE_CTRL_TYPE_WDE; + + for (i = 0; i < grpnum; i++) { + qempty.grpsel = i; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, + "%s: failed to dle dfi acq empty: %d\n", + __func__, ret); + return false; + } + + /* Each acq group contains 32 queues (8 macid * 4 acq), + * but here, we can simply check if all bits are set. + */ + if (qempty.qempty != MASKDWORD) + return false; + } + + qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, "%s: failed to dle dfi mgq empty: %d\n", + __func__, ret); + return false; + } + + msk32 = B_CMAC0_MGQ_NORMAL_BE | B_CMAC1_MGQ_NORMAL_BE; + if ((qempty.qempty & msk32) != msk32) + return false; + + msk32 = B_BE_WDE_EMPTY_QUE_OTHERS; + val32 = rtw89_read32(rtwdev, R_BE_DLE_EMPTY0); + return (val32 & msk32) == msk32; +} + const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .band1_offset = RTW89_MAC_BE_BAND_REG_OFFSET, .filter_model_addr = R_BE_FILTER_MODEL_ADDR, @@ -435,5 +480,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .cnv_efuse_state = rtw89_cnv_efuse_state_be, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, + + .is_txq_empty = mac_is_txq_empty_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 197fbb40922c..455038967af4 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4144,6 +4144,36 @@ #define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) #define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) +#define R_BE_DLE_EMPTY0 0x8430 +#define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) +#define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) +#define B_BE_PLE_EMPTY_QTA_DMAC_MPDU_TX BIT(25) +#define B_BE_PLE_EMPTY_QTA_DMAC_WLAN_CPU BIT(24) +#define B_BE_PLE_EMPTY_QTA_DMAC_H2C BIT(23) +#define B_BE_PLE_EMPTY_QTA_DMAC_B1_TXPL BIT(22) +#define B_BE_PLE_EMPTY_QTA_DMAC_B0_TXPL BIT(21) +#define B_BE_WDE_EMPTY_QTA_DMAC_CPUIO BIT(20) +#define B_BE_WDE_EMPTY_QTA_DMAC_PKTIN BIT(19) +#define B_BE_WDE_EMPTY_QTA_DMAC_DATA_CPU BIT(18) +#define B_BE_WDE_EMPTY_QTA_DMAC_WLAN_CPU BIT(17) +#define B_BE_WDE_EMPTY_QTA_DMAC_HIF BIT(16) +#define B_BE_WDE_EMPTY_QUE_CMAC_B1_HIQ BIT(15) +#define B_BE_WDE_EMPTY_QUE_CMAC_B1_MBH BIT(14) +#define B_BE_WDE_EMPTY_QUE_CMAC_B0_OTHERS BIT(13) +#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_ACQ BIT(12) +#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_MISC BIT(11) +#define B_BE_WDE_EMPTY_QUE_DMAC_PKTIN BIT(10) +#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_TX BIT(9) +#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_TX BIT(8) +#define B_BE_WDE_EMPTY_QUE_OTHERS BIT(7) +#define B_BE_WDE_EMPTY_QUE_CMAC_WMM3 BIT(6) +#define B_BE_WDE_EMPTY_QUE_CMAC_WMM2 BIT(5) +#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM1 BIT(4) +#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM0 BIT(3) +#define B_BE_WDE_EMPTY_QUE_CMAC1_MBH BIT(2) +#define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) +#define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) From 0d16d8fbffb3fec128ec563b6f8cd512ebcec315 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:17:01 +0800 Subject: [PATCH 2100/7721] wifi: rtw89: mac: move code related to hardware engine to individual functions WiFi 7 chips will use the same functionalities but different registers to control hardware components, so move these stuff into functions, and then we can implement these for WiFi 7 chips later. This patch doesn't change logic. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 65 +++++++++++++++++------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 074c1edb0d25..be063f73573b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -901,7 +901,7 @@ static int hfc_pub_ctrl(struct rtw89_dev *rtwdev) return 0; } -static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) +static void hfc_get_mix_info(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -910,11 +910,6 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; struct rtw89_hfc_pub_info *info = ¶m->pub_info; u32 val; - int ret; - - ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); - if (ret) - return ret; val = rtw89_read32(rtwdev, regs->pub_page_info1); info->g0_used = u32_get_bits(val, B_AX_G0_USE_PG_MASK); @@ -959,6 +954,18 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) val = rtw89_read32(rtwdev, regs->pub_page_ctrl1); pub_cfg->grp0 = u32_get_bits(val, B_AX_PUBPG_G0_MASK); pub_cfg->grp1 = u32_get_bits(val, B_AX_PUBPG_G1_MASK); +} + +static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) + return ret; + + hfc_get_mix_info(rtwdev); ret = hfc_pub_info_chk(rtwdev); if (param->en && ret) @@ -1780,6 +1787,23 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg return 0; } +static int chk_dle_rdy(struct rtw89_dev *rtwdev, bool wde_or_ple) +{ + u32 reg, mask; + u32 ini; + + if (wde_or_ple) { + reg = R_AX_WDE_INI_STATUS; + mask = WDE_MGN_INI_RDY; + } else { + reg = R_AX_PLE_INI_STATUS; + mask = PLE_MGN_INI_RDY; + } + + return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1, + 2000, false, rtwdev, reg); +} + #define INVALID_QT_WCPU U16_MAX #define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \ do { \ @@ -1884,7 +1908,6 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, const struct rtw89_dle_mem *cfg, *ext_cfg; u16 ext_wde_min_qt_wcpu = INVALID_QT_WCPU; int ret = 0; - u32 ini; ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) @@ -1926,17 +1949,13 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, dle_func_en(rtwdev, true); - ret = read_poll_timeout(rtw89_read32, ini, - (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1, - 2000, false, rtwdev, R_AX_WDE_INI_STATUS); + ret = chk_dle_rdy(rtwdev, true); if (ret) { rtw89_err(rtwdev, "[ERR]WDE cfg ready\n"); return ret; } - ret = read_poll_timeout(rtw89_read32, ini, - (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1, - 2000, false, rtwdev, R_AX_PLE_INI_STATUS); + ret = chk_dle_rdy(rtwdev, false); if (ret) { rtw89_err(rtwdev, "[ERR]PLE cfg ready\n"); return ret; @@ -3598,11 +3617,10 @@ static int rtw89_mac_enable_cpu_ax(struct rtw89_dev *rtwdev, u8 boot_reason, return 0; } -static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) +static void rtw89_mac_hci_func_en(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val; - int ret; if (chip_id == RTL8852C) val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN | @@ -3611,6 +3629,12 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN | B_AX_PKT_BUF_EN; rtw89_write32(rtwdev, R_AX_DMAC_FUNC_EN, val); +} + +static void rtw89_mac_dmac_func_pre_en(struct rtw89_dev *rtwdev) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 val; if (chip_id == RTL8851B) val = B_AX_DISPATCHER_CLK_EN | B_AX_AXIDMA_CLK_EN; @@ -3619,7 +3643,7 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_AX_DMAC_CLK_EN, val); if (chip_id != RTL8852C) - goto dle; + return; val = rtw89_read32(rtwdev, R_AX_HAXI_INIT_CFG1); val &= ~(B_AX_DMA_MODE_MASK | B_AX_STOP_AXI_MST); @@ -3634,8 +3658,15 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) B_AX_STOP_CH12 | B_AX_STOP_ACH2); rtw89_write32_clr(rtwdev, R_AX_HAXI_DMA_STOP2, B_AX_STOP_CH10 | B_AX_STOP_CH11); rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_AXIDMA_EN); +} + +static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_mac_hci_func_en(rtwdev); + rtw89_mac_dmac_func_pre_en(rtwdev); -dle: ret = dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]DLE pre init %d\n", ret); From 39e9b5691921a886e19c80be47f492efef14d00f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:17:02 +0800 Subject: [PATCH 2101/7721] wifi: rtw89: mac: use pointer to access functions of hardware engine and quota To share flow with WiFi 7 chips, abstract functions related hardware engines and their quota, so use pointer to access them. This doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 5 +- drivers/net/wireless/realtek/rtw89/mac.c | 104 +++++++++++++-------- drivers/net/wireless/realtek/rtw89/mac.h | 24 ++++- 3 files changed, 87 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 9780af8e296d..44829a148185 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3330,13 +3330,14 @@ rtw89_debug_priv_early_h2c_set(struct file *filp, const char __user *user_buf, static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_cpuio_ctrl ctrl_para = {0}; u16 pkt_id; int ret; rtw89_leave_ps_mode(rtwdev); - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); if (ret) return ret; @@ -3348,7 +3349,7 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS; ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT; - if (rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true)) + if (mac->set_cpuio(rtwdev, &ctrl_para, true)) return -EFAULT; return 0; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index be063f73573b..c3dac7a6c377 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -901,7 +901,7 @@ static int hfc_pub_ctrl(struct rtw89_dev *rtwdev) return 0; } -static void hfc_get_mix_info(struct rtw89_dev *rtwdev) +static void hfc_get_mix_info_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -958,6 +958,7 @@ static void hfc_get_mix_info(struct rtw89_dev *rtwdev) static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; int ret; @@ -965,7 +966,7 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) if (ret) return ret; - hfc_get_mix_info(rtwdev); + mac->hfc_get_mix_info(rtwdev); ret = hfc_pub_info_chk(rtwdev); if (param->en && ret) @@ -974,7 +975,7 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) return 0; } -static void hfc_h2c_cfg(struct rtw89_dev *rtwdev) +static void hfc_h2c_cfg_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -990,7 +991,7 @@ static void hfc_h2c_cfg(struct rtw89_dev *rtwdev) prec_cfg->h2c_full_cond); } -static void hfc_mix_cfg(struct rtw89_dev *rtwdev) +static void hfc_mix_cfg_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -1025,7 +1026,7 @@ static void hfc_mix_cfg(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, regs->hci_fc_ctrl, val); } -static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en) +static void hfc_func_en_ax(struct rtw89_dev *rtwdev, bool en, bool h2c_en) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -1043,6 +1044,7 @@ static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en) static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; u32 dma_ch_mask = chip->dma_ch_mask; u8 ch; @@ -1057,11 +1059,11 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) if (ret) return ret; - hfc_func_en(rtwdev, false, false); + mac->hfc_func_en(rtwdev, false, false); if (!en && h2c_en) { - hfc_h2c_cfg(rtwdev); - hfc_func_en(rtwdev, en, h2c_en); + mac->hfc_h2c_cfg(rtwdev); + mac->hfc_func_en(rtwdev, en, h2c_en); return ret; } @@ -1077,9 +1079,9 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) if (ret) return ret; - hfc_mix_cfg(rtwdev); + mac->hfc_mix_cfg(rtwdev); if (en || h2c_en) { - hfc_func_en(rtwdev, en, h2c_en); + mac->hfc_func_en(rtwdev, en, h2c_en); udelay(10); } for (ch = RTW89_DMA_ACH0; ch < RTW89_DMA_H2C; ch++) { @@ -1707,7 +1709,7 @@ static u32 dle_expected_used_size(struct rtw89_dev *rtwdev, return size; } -static void dle_func_en(struct rtw89_dev *rtwdev, bool enable) +static void dle_func_en_ax(struct rtw89_dev *rtwdev, bool enable) { if (enable) rtw89_write32_set(rtwdev, R_AX_DMAC_FUNC_EN, @@ -1717,7 +1719,7 @@ static void dle_func_en(struct rtw89_dev *rtwdev, bool enable) B_AX_DLE_WDE_EN | B_AX_DLE_PLE_EN); } -static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable) +static void dle_clk_en_ax(struct rtw89_dev *rtwdev, bool enable) { u32 val = B_AX_DLE_WDE_CLK_EN | B_AX_DLE_PLE_CLK_EN; @@ -1730,7 +1732,7 @@ static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable) } } -static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) +static int dle_mix_cfg_ax(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) { const struct rtw89_dle_size *size_cfg; u32 val; @@ -1787,7 +1789,7 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg return 0; } -static int chk_dle_rdy(struct rtw89_dev *rtwdev, bool wde_or_ple) +static int chk_dle_rdy_ax(struct rtw89_dev *rtwdev, bool wde_or_ple) { u32 reg, mask; u32 ini; @@ -1816,10 +1818,10 @@ static int chk_dle_rdy(struct rtw89_dev *rtwdev, bool wde_or_ple) #define SET_QUOTA(_x, _module, _idx) \ SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx) -static void wde_quota_cfg(struct rtw89_dev *rtwdev, - const struct rtw89_wde_quota *min_cfg, - const struct rtw89_wde_quota *max_cfg, - u16 ext_wde_min_qt_wcpu) +static void wde_quota_cfg_ax(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu) { u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ? ext_wde_min_qt_wcpu : min_cfg->wcpu; @@ -1831,9 +1833,9 @@ static void wde_quota_cfg(struct rtw89_dev *rtwdev, SET_QUOTA(cpu_io, WDE, 4); } -static void ple_quota_cfg(struct rtw89_dev *rtwdev, - const struct rtw89_ple_quota *min_cfg, - const struct rtw89_ple_quota *max_cfg) +static void ple_quota_cfg_ax(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg) { u32 val; @@ -1898,16 +1900,19 @@ static void dle_quota_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg, u16 ext_wde_min_qt_wcpu) { - wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu); - ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt); + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + mac->wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu); + mac->ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt); } static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, enum rtw89_qta_mode ext_mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_dle_mem *cfg, *ext_cfg; u16 ext_wde_min_qt_wcpu = INVALID_QT_WCPU; - int ret = 0; + int ret; ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) @@ -1937,25 +1942,25 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, goto error; } - dle_func_en(rtwdev, false); - dle_clk_en(rtwdev, true); + mac->dle_func_en(rtwdev, false); + mac->dle_clk_en(rtwdev, true); - ret = dle_mix_cfg(rtwdev, cfg); + ret = mac->dle_mix_cfg(rtwdev, cfg); if (ret) { rtw89_err(rtwdev, "[ERR] dle mix cfg\n"); goto error; } dle_quota_cfg(rtwdev, cfg, ext_wde_min_qt_wcpu); - dle_func_en(rtwdev, true); + mac->dle_func_en(rtwdev, true); - ret = chk_dle_rdy(rtwdev, true); + ret = mac->chk_dle_rdy(rtwdev, true); if (ret) { rtw89_err(rtwdev, "[ERR]WDE cfg ready\n"); return ret; } - ret = chk_dle_rdy(rtwdev, false); + ret = mac->chk_dle_rdy(rtwdev, false); if (ret) { rtw89_err(rtwdev, "[ERR]PLE cfg ready\n"); return ret; @@ -1963,7 +1968,7 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, return 0; error: - dle_func_en(rtwdev, false); + mac->dle_func_en(rtwdev, false); rtw89_err(rtwdev, "[ERR]trxcfg wde 0x8900 = %x\n", rtw89_read32(rtwdev, R_AX_WDE_INI_STATUS)); rtw89_err(rtwdev, "[ERR]trxcfg ple 0x8D00 = %x\n", @@ -2975,7 +2980,7 @@ int rtw89_mac_resume_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en) } EXPORT_SYMBOL(rtw89_mac_resume_sch_tx_v1); -int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) +static int dle_buf_req_ax(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) { u32 val, reg; int ret; @@ -2999,7 +3004,7 @@ int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *p return 0; } -int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, +static int set_cpuio_ax(struct rtw89_dev *rtwdev, struct rtw89_cpuio_ctrl *ctrl_para, bool wd) { u32 val, cmd_type, reg; @@ -3054,6 +3059,7 @@ int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_dle_mem *cfg; struct rtw89_cpuio_ctrl ctrl_para = {0}; u16 pkt_id; @@ -3072,7 +3078,7 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) dle_quota_cfg(rtwdev, cfg, INVALID_QT_WCPU); - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); if (ret) { rtw89_err(rtwdev, "[ERR]WDE DLE buf req\n"); return ret; @@ -3084,13 +3090,13 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) ctrl_para.pkt_num = 0; ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS; ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT; - ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true); + ret = mac->set_cpuio(rtwdev, &ctrl_para, true); if (ret) { rtw89_err(rtwdev, "[ERR]WDE DLE enqueue to head\n"); return -EFAULT; } - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, false, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, false, &pkt_id); if (ret) { rtw89_err(rtwdev, "[ERR]PLE DLE buf req\n"); return ret; @@ -3102,7 +3108,7 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) ctrl_para.pkt_num = 0; ctrl_para.dst_pid = PLE_DLE_PORT_ID_PLRLS; ctrl_para.dst_qid = PLE_DLE_QUEID_NO_REPORT; - ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, false); + ret = mac->set_cpuio(rtwdev, &ctrl_para, false); if (ret) { rtw89_err(rtwdev, "[ERR]PLE DLE enqueue to head\n"); return -EFAULT; @@ -3617,7 +3623,7 @@ static int rtw89_mac_enable_cpu_ax(struct rtw89_dev *rtwdev, u8 boot_reason, return 0; } -static void rtw89_mac_hci_func_en(struct rtw89_dev *rtwdev) +static void rtw89_mac_hci_func_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val; @@ -3631,7 +3637,7 @@ static void rtw89_mac_hci_func_en(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_AX_DMAC_FUNC_EN, val); } -static void rtw89_mac_dmac_func_pre_en(struct rtw89_dev *rtwdev) +static void rtw89_mac_dmac_func_pre_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val; @@ -3662,10 +3668,11 @@ static void rtw89_mac_dmac_func_pre_en(struct rtw89_dev *rtwdev) static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; - rtw89_mac_hci_func_en(rtwdev); - rtw89_mac_dmac_func_pre_en(rtwdev); + mac->hci_func_en(rtwdev); + mac->dmac_func_pre_en(rtwdev); ret = dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode); if (ret) { @@ -5885,8 +5892,23 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { B_AX_BFMEE_HE_NDPA_EN, }, + .hci_func_en = rtw89_mac_hci_func_en_ax, + .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, + .dle_func_en = dle_func_en_ax, + .dle_clk_en = dle_clk_en_ax, .bf_assoc = rtw89_mac_bf_assoc_ax, + .dle_mix_cfg = dle_mix_cfg_ax, + .chk_dle_rdy = chk_dle_rdy_ax, + .dle_buf_req = dle_buf_req_ax, + .hfc_func_en = hfc_func_en_ax, + .hfc_h2c_cfg = hfc_h2c_cfg_ax, + .hfc_mix_cfg = hfc_mix_cfg_ax, + .hfc_get_mix_info = hfc_get_mix_info_ax, + .wde_quota_cfg = wde_quota_cfg_ax, + .ple_quota_cfg = ple_quota_cfg_ax, + .set_cpuio = set_cpuio_ax, + .disable_cpu = rtw89_mac_disable_cpu_ax, .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 8beb278934bf..c6b2072f94c3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -898,9 +898,30 @@ struct rtw89_mac_gen_def { struct rtw89_reg_def muedca_ctrl; struct rtw89_reg_def bfee_ctrl; + void (*hci_func_en)(struct rtw89_dev *rtwdev); + void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); + void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); + void (*dle_clk_en)(struct rtw89_dev *rtwdev, bool enable); void (*bf_assoc)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg); + int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple); + int (*dle_buf_req)(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id); + void (*hfc_func_en)(struct rtw89_dev *rtwdev, bool en, bool h2c_en); + void (*hfc_h2c_cfg)(struct rtw89_dev *rtwdev); + void (*hfc_mix_cfg)(struct rtw89_dev *rtwdev); + void (*hfc_get_mix_info)(struct rtw89_dev *rtwdev); + void (*wde_quota_cfg)(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu); + void (*ple_quota_cfg)(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg); + int (*set_cpuio)(struct rtw89_dev *rtwdev, + struct rtw89_cpuio_ctrl *ctrl_para, bool wd); + void (*disable_cpu)(struct rtw89_dev *rtwdev); int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw, bool include_bb); @@ -1267,9 +1288,6 @@ enum rtw89_mac_xtal_si_offset { int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask); int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val); void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id); -int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, - struct rtw89_cpuio_ctrl *ctrl_para, bool wd); int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, enum rtw89_machdr_frame_type type, enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); From 1dd1dc262afacb99e66ebdc174e7b11f51a816ab Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 24 Nov 2023 15:17:03 +0800 Subject: [PATCH 2102/7721] wifi: rtw89: mac: functions to configure hardware engine and quota for WiFi 7 chips Add functions to configure HCI, DMAC (data MAC), DLE (data link engine), HFC (HCI flow control), PLE (payload engine) and etc for WiFi 7 chips. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124071703.132549-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 390 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 264 +++++++++++++ 2 files changed, 654 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 612baa8b83d9..ec394f02a8ca 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -57,6 +57,297 @@ static const struct rtw89_port_reg rtw89_port_base_be = { R_BE_PORT_HGQ_WINDOW_CFG + 3}, }; +static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + struct rtw89_hfc_pub_info *info = ¶m->pub_info; + u32 val; + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO1); + info->g0_used = u32_get_bits(val, B_BE_G0_USE_PG_MASK); + info->g1_used = u32_get_bits(val, B_BE_G1_USE_PG_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO3); + info->g0_aval = u32_get_bits(val, B_BE_G0_AVAL_PG_MASK); + info->g1_aval = u32_get_bits(val, B_BE_G1_AVAL_PG_MASK); + info->pub_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO2), + B_BE_PUB_AVAL_PG_MASK); + info->wp_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_WP_PAGE_INFO1), + B_BE_WP_AVAL_PG_MASK); + + val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL); + param->en = !!(val & B_BE_HCI_FC_EN); + param->h2c_en = !!(val & B_BE_HCI_FC_CH12_EN); + param->mode = u32_get_bits(val, B_BE_HCI_FC_MODE_MASK); + prec_cfg->ch011_full_cond = u32_get_bits(val, B_BE_HCI_FC_WD_FULL_COND_MASK); + prec_cfg->h2c_full_cond = u32_get_bits(val, B_BE_HCI_FC_CH12_FULL_COND_MASK); + prec_cfg->wp_ch07_full_cond = + u32_get_bits(val, B_BE_HCI_FC_WP_CH07_FULL_COND_MASK); + prec_cfg->wp_ch811_full_cond = + u32_get_bits(val, B_BE_HCI_FC_WP_CH811_FULL_COND_MASK); + + val = rtw89_read32(rtwdev, R_BE_CH_PAGE_CTRL); + prec_cfg->ch011_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH011_V1_MASK); + prec_cfg->h2c_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH12_V1_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL2); + pub_cfg->pub_max = u32_get_bits(val, B_BE_PUBPG_ALL_MASK); + + val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL1); + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + + val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL2); + pub_cfg->wp_thrd = u32_get_bits(val, B_BE_WP_THRD_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL1); + pub_cfg->grp0 = u32_get_bits(val, B_BE_PUBPG_G0_MASK); + pub_cfg->grp1 = u32_get_bits(val, B_BE_PUBPG_G1_MASK); +} + +static void hfc_h2c_cfg_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + u32 val; + + val = u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); +} + +static void hfc_mix_cfg_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + const struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + u32 val; + + val = u32_encode_bits(prec_cfg->ch011_prec, B_BE_PREC_PAGE_CH011_V1_MASK) | + u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); + + val = u32_encode_bits(pub_cfg->pub_max, B_BE_PUBPG_ALL_MASK); + rtw89_write32(rtwdev, R_BE_PUB_PAGE_CTRL2, val); + + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); + rtw89_write32(rtwdev, R_BE_WP_PAGE_CTRL1, val); + + val = u32_replace_bits(rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL), + param->mode, B_BE_HCI_FC_MODE_MASK); + val = u32_replace_bits(val, prec_cfg->ch011_full_cond, + B_BE_HCI_FC_WD_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->h2c_full_cond, + B_BE_HCI_FC_CH12_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->wp_ch07_full_cond, + B_BE_HCI_FC_WP_CH07_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->wp_ch811_full_cond, + B_BE_HCI_FC_WP_CH811_FULL_COND_MASK); + rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val); +} + +static void hfc_func_en_be(struct rtw89_dev *rtwdev, bool en, bool h2c_en) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL); + param->en = en; + param->h2c_en = h2c_en; + val = en ? (val | B_BE_HCI_FC_EN) : (val & ~B_BE_HCI_FC_EN); + val = h2c_en ? (val | B_BE_HCI_FC_CH12_EN) : + (val & ~B_BE_HCI_FC_CH12_EN); + rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val); +} + +static void dle_func_en_be(struct rtw89_dev *rtwdev, bool enable) +{ + if (enable) + rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN); + else + rtw89_write32_clr(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN); +} + +static void dle_clk_en_be(struct rtw89_dev *rtwdev, bool enable) +{ + if (enable) + rtw89_write32_set(rtwdev, R_BE_DMAC_CLK_EN, + B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); + else + rtw89_write32_clr(rtwdev, R_BE_DMAC_CLK_EN, + B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); +} + +static int dle_mix_cfg_be(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) +{ + const struct rtw89_dle_size *wde_size_cfg, *ple_size_cfg; + u32 bound; + u32 val; + + wde_size_cfg = cfg->wde_size; + ple_size_cfg = cfg->ple_size; + + val = rtw89_read32(rtwdev, R_BE_WDE_PKTBUF_CFG); + + switch (wde_size_cfg->pge_size) { + default: + case RTW89_WDE_PG_64: + val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_64, + B_BE_WDE_PAGE_SEL_MASK); + break; + case RTW89_WDE_PG_128: + val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_128, + B_BE_WDE_PAGE_SEL_MASK); + break; + case RTW89_WDE_PG_256: + rtw89_err(rtwdev, "[ERR]WDE DLE doesn't support 256 byte!\n"); + return -EINVAL; + } + + bound = wde_size_cfg->srt_ofst / DLE_BOUND_UNIT; + val = u32_replace_bits(val, bound, B_BE_WDE_START_BOUND_MASK); + val = u32_replace_bits(val, wde_size_cfg->lnk_pge_num, + B_BE_WDE_FREE_PAGE_NUM_MASK); + rtw89_write32(rtwdev, R_BE_WDE_PKTBUF_CFG, val); + + val = rtw89_read32(rtwdev, R_BE_PLE_PKTBUF_CFG); + + switch (ple_size_cfg->pge_size) { + default: + case RTW89_PLE_PG_64: + rtw89_err(rtwdev, "[ERR]PLE DLE doesn't support 64 byte!\n"); + return -EINVAL; + case RTW89_PLE_PG_128: + val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_128, + B_BE_PLE_PAGE_SEL_MASK); + break; + case RTW89_PLE_PG_256: + val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_256, + B_BE_PLE_PAGE_SEL_MASK); + break; + } + + bound = ple_size_cfg->srt_ofst / DLE_BOUND_UNIT; + val = u32_replace_bits(val, bound, B_BE_PLE_START_BOUND_MASK); + val = u32_replace_bits(val, ple_size_cfg->lnk_pge_num, + B_BE_PLE_FREE_PAGE_NUM_MASK); + rtw89_write32(rtwdev, R_BE_PLE_PKTBUF_CFG, val); + + return 0; +} + +static int chk_dle_rdy_be(struct rtw89_dev *rtwdev, bool wde_or_ple) +{ + u32 reg, mask; + u32 ini; + + if (wde_or_ple) { + reg = R_AX_WDE_INI_STATUS; + mask = WDE_MGN_INI_RDY; + } else { + reg = R_AX_PLE_INI_STATUS; + mask = PLE_MGN_INI_RDY; + } + + return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1, + 2000, false, rtwdev, reg); +} + +#define INVALID_QT_WCPU U16_MAX +#define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \ + do { \ + val = u32_encode_bits(_min_x, B_BE_ ## _module ## _Q ## _idx ## _MIN_SIZE_MASK) | \ + u32_encode_bits(_max_x, B_BE_ ## _module ## _Q ## _idx ## _MAX_SIZE_MASK); \ + rtw89_write32(rtwdev, \ + R_BE_ ## _module ## _QTA ## _idx ## _CFG, \ + val); \ + } while (0) +#define SET_QUOTA(_x, _module, _idx) \ + SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx) + +static void wde_quota_cfg_be(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu) +{ + u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ? + ext_wde_min_qt_wcpu : min_cfg->wcpu; + u16 max_qt_wcpu = max(max_cfg->wcpu, min_qt_wcpu); + u32 val; + + SET_QUOTA(hif, WDE, 0); + SET_QUOTA_VAL(min_qt_wcpu, max_qt_wcpu, WDE, 1); + SET_QUOTA_VAL(0, 0, WDE, 2); + SET_QUOTA(pkt_in, WDE, 3); + SET_QUOTA(cpu_io, WDE, 4); +} + +static void ple_quota_cfg_be(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg) +{ + u32 val; + + SET_QUOTA(cma0_tx, PLE, 0); + SET_QUOTA(cma1_tx, PLE, 1); + SET_QUOTA(c2h, PLE, 2); + SET_QUOTA(h2c, PLE, 3); + SET_QUOTA(wcpu, PLE, 4); + SET_QUOTA(mpdu_proc, PLE, 5); + SET_QUOTA(cma0_dma, PLE, 6); + SET_QUOTA(cma1_dma, PLE, 7); + SET_QUOTA(bb_rpt, PLE, 8); + SET_QUOTA(wd_rel, PLE, 9); + SET_QUOTA(cpu_io, PLE, 10); + SET_QUOTA(tx_rpt, PLE, 11); + SET_QUOTA(h2d, PLE, 12); +} + +static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_BE_HCI_FUNC_EN, B_BE_HCI_TXDMA_EN | + B_BE_HCI_RXDMA_EN); +} + +static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + + switch (rtwdev->hci.type) { + case RTW89_HCI_TYPE_PCIE: + val = u32_replace_bits(val, S_BE_DMA_MOD_PCIE_NO_DATA_CPU, + B_BE_DMA_MODE_MASK); + break; + case RTW89_HCI_TYPE_USB: + val = u32_replace_bits(val, S_BE_DMA_MOD_USB, B_BE_DMA_MODE_MASK); + val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN; + break; + case RTW89_HCI_TYPE_SDIO: + val = u32_replace_bits(val, S_BE_DMA_MOD_SDIO, B_BE_DMA_MODE_MASK); + val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN; + break; + default: + return; + } + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); + + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, + B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | + B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | + B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | + B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11 | + B_BE_STOP_CH12 | B_BE_STOP_CH13 | B_BE_STOP_CH14); + + rtw89_write32_set(rtwdev, R_BE_DMAC_TABLE_CTRL, B_BE_DMAC_ADDR_MODE); +} + static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev) { u32 val32; @@ -206,6 +497,90 @@ static int rtw89_fwdl_check_path_ready_be(struct rtw89_dev *rtwdev, rtwdev, R_BE_WCPU_FW_CTRL); } +static int dle_buf_req_be(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) +{ + u32 val, reg; + int ret; + + reg = wd ? R_BE_WD_BUF_REQ : R_BE_PL_BUF_REQ; + val = buf_len; + val |= B_BE_WD_BUF_REQ_EXEC; + rtw89_write32(rtwdev, reg, val); + + reg = wd ? R_BE_WD_BUF_STATUS : R_BE_PL_BUF_STATUS; + + ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_BUF_STAT_DONE, + 1, 2000, false, rtwdev, reg); + if (ret) + return ret; + + *pkt_id = u32_get_bits(val, B_BE_WD_BUF_STAT_PKTID_MASK); + if (*pkt_id == S_WD_BUF_STAT_PKTID_INVALID) + return -ENOENT; + + return 0; +} + +static int set_cpuio_be(struct rtw89_dev *rtwdev, + struct rtw89_cpuio_ctrl *ctrl_para, bool wd) +{ + u32 val_op0, val_op1, val_op2, val_op3; + u32 val, cmd_type, reg; + int ret; + + cmd_type = ctrl_para->cmd_type; + + reg = wd ? R_BE_WD_CPUQ_OP_3 : R_BE_PL_CPUQ_OP_3; + val_op3 = u32_replace_bits(0, ctrl_para->start_pktid, + B_BE_WD_CPUQ_OP_STRT_PKTID_MASK); + val_op3 = u32_replace_bits(val_op3, ctrl_para->end_pktid, + B_BE_WD_CPUQ_OP_END_PKTID_MASK); + rtw89_write32(rtwdev, reg, val_op3); + + reg = wd ? R_BE_WD_CPUQ_OP_1 : R_BE_PL_CPUQ_OP_1; + val_op1 = u32_replace_bits(0, ctrl_para->src_pid, + B_BE_WD_CPUQ_OP_SRC_PID_MASK); + val_op1 = u32_replace_bits(val_op1, ctrl_para->src_qid, + B_BE_WD_CPUQ_OP_SRC_QID_MASK); + val_op1 = u32_replace_bits(val_op1, ctrl_para->macid, + B_BE_WD_CPUQ_OP_SRC_MACID_MASK); + rtw89_write32(rtwdev, reg, val_op1); + + reg = wd ? R_BE_WD_CPUQ_OP_2 : R_BE_PL_CPUQ_OP_2; + val_op2 = u32_replace_bits(0, ctrl_para->dst_pid, + B_BE_WD_CPUQ_OP_DST_PID_MASK); + val_op2 = u32_replace_bits(val_op2, ctrl_para->dst_qid, + B_BE_WD_CPUQ_OP_DST_QID_MASK); + val_op2 = u32_replace_bits(val_op2, ctrl_para->macid, + B_BE_WD_CPUQ_OP_DST_MACID_MASK); + rtw89_write32(rtwdev, reg, val_op2); + + reg = wd ? R_BE_WD_CPUQ_OP_0 : R_BE_PL_CPUQ_OP_0; + val_op0 = u32_replace_bits(0, cmd_type, + B_BE_WD_CPUQ_OP_CMD_TYPE_MASK); + val_op0 = u32_replace_bits(val_op0, ctrl_para->pkt_num, + B_BE_WD_CPUQ_OP_PKTNUM_MASK); + val_op0 |= B_BE_WD_CPUQ_OP_EXEC; + rtw89_write32(rtwdev, reg, val_op0); + + reg = wd ? R_BE_WD_CPUQ_OP_STATUS : R_BE_PL_CPUQ_OP_STATUS; + + ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_CPUQ_OP_STAT_DONE, + 1, 2000, false, rtwdev, reg); + if (ret) { + rtw89_err(rtwdev, "[ERR]set cpuio wd timeout\n"); + rtw89_err(rtwdev, "[ERR]op_0=0x%X, op_1=0x%X, op_2=0x%X\n", + val_op0, val_op1, val_op2); + return ret; + } + + if (cmd_type == CPUIO_OP_CMD_GET_NEXT_PID || + cmd_type == CPUIO_OP_CMD_GET_1ST_PID) + ctrl_para->pktid = u32_get_bits(val, B_BE_WD_CPUQ_OP_PKTID_MASK); + + return 0; +} + static bool rtw89_mac_get_txpwr_cr_be(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr) @@ -469,8 +844,23 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { B_BE_BFMEE_HE_NDPA_EN | B_BE_BFMEE_EHT_NDPA_EN, }, + .hci_func_en = rtw89_mac_hci_func_en_be, + .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, + .dle_func_en = dle_func_en_be, + .dle_clk_en = dle_clk_en_be, .bf_assoc = rtw89_mac_bf_assoc_be, + .dle_mix_cfg = dle_mix_cfg_be, + .chk_dle_rdy = chk_dle_rdy_be, + .dle_buf_req = dle_buf_req_be, + .hfc_func_en = hfc_func_en_be, + .hfc_h2c_cfg = hfc_h2c_cfg_be, + .hfc_mix_cfg = hfc_mix_cfg_be, + .hfc_get_mix_info = hfc_get_mix_info_be, + .wde_quota_cfg = wde_quota_cfg_be, + .ple_quota_cfg = ple_quota_cfg_be, + .set_cpuio = set_cpuio_be, + .disable_cpu = rtw89_mac_disable_cpu_be, .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 455038967af4..268c537394d4 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4123,6 +4123,53 @@ #define B_BE_HCI_RXDMA_EN BIT(1) #define B_BE_HCI_TXDMA_EN BIT(0) +#define R_BE_DMAC_FUNC_EN 0x8400 +#define B_BE_DMAC_CRPRT BIT(31) +#define B_BE_MAC_FUNC_EN BIT(30) +#define B_BE_DMAC_FUNC_EN BIT(29) +#define B_BE_MPDU_PROC_EN BIT(28) +#define B_BE_WD_RLS_EN BIT(27) +#define B_BE_DLE_WDE_EN BIT(26) +#define B_BE_TXPKT_CTRL_EN BIT(25) +#define B_BE_STA_SCH_EN BIT(24) +#define B_BE_DLE_PLE_EN BIT(23) +#define B_BE_PKT_BUF_EN BIT(22) +#define B_BE_DMAC_TBL_EN BIT(21) +#define B_BE_PKT_IN_EN BIT(20) +#define B_BE_DLE_CPUIO_EN BIT(19) +#define B_BE_DISPATCHER_EN BIT(18) +#define B_BE_BBRPT_EN BIT(17) +#define B_BE_MAC_SEC_EN BIT(16) +#define B_BE_DMACREG_GCKEN BIT(15) +#define B_BE_H_AXIDMA_EN BIT(14) +#define B_BE_DMAC_MLO_EN BIT(11) +#define B_BE_PLRLS_EN BIT(10) +#define B_BE_P_AXIDMA_EN BIT(9) +#define B_BE_DLE_DATACPUIO_EN BIT(8) +#define B_BE_LTR_CTL_EN BIT(7) + +#define R_BE_DMAC_CLK_EN 0x8404 +#define B_BE_MAC_CKEN BIT(30) +#define B_BE_DMAC_CKEN BIT(29) +#define B_BE_MPDU_CKEN BIT(28) +#define B_BE_WD_RLS_CLK_EN BIT(27) +#define B_BE_DLE_WDE_CLK_EN BIT(26) +#define B_BE_TXPKT_CTRL_CLK_EN BIT(25) +#define B_BE_STA_SCH_CLK_EN BIT(24) +#define B_BE_DLE_PLE_CLK_EN BIT(23) +#define B_BE_PKTBUF_CKEN BIT(22) +#define B_BE_DMAC_TABLE_CLK_EN BIT(21) +#define B_BE_PKT_IN_CLK_EN BIT(20) +#define B_BE_DLE_CPUIO_CLK_EN BIT(19) +#define B_BE_DISPATCHER_CLK_EN BIT(18) +#define B_BE_BBRPT_CLK_EN BIT(17) +#define B_BE_MAC_SEC_CLK_EN BIT(16) +#define B_BE_H_AXIDMA_CKEN BIT(14) +#define B_BE_DMAC_MLO_CKEN BIT(11) +#define B_BE_PLRLS_CKEN BIT(10) +#define B_BE_P_AXIDMA_CKEN BIT(9) +#define B_BE_DLE_DATACPUIO_CKEN BIT(8) + #define R_BE_LTR_CTRL_0 0x8410 #define B_BE_LTR_REQ_FW BIT(18) #define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16) @@ -4144,6 +4191,13 @@ #define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) #define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) +#define R_BE_DMAC_TABLE_CTRL 0x8420 +#define B_BE_HWAMSDU_PADDING_MODE BIT(31) +#define B_BE_MACID_MPDU_PROCESSOR_OFFSET_MASK GENMASK(26, 16) +#define B_BE_DMAC_ADDR_MODE BIT(12) +#define B_BE_DMAC_CTRL_INFO_SER_IO BIT(11) +#define B_BE_DMAC_CTRL_INFO_OFFSET_MASK GENMASK(10, 0) + #define R_BE_DLE_EMPTY0 0x8430 #define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) #define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) @@ -4174,6 +4228,88 @@ #define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) #define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) +#define R_BE_WDE_PKTBUF_CFG 0x8C08 +#define B_BE_WDE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define B_BE_WDE_START_BOUND_MASK GENMASK(14, 8) +#define B_BE_WDE_PAGE_SEL_MASK GENMASK(1, 0) + +#define R_BE_WDE_QTA0_CFG 0x8C40 +#define B_BE_WDE_Q0_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q0_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA1_CFG 0x8C44 +#define B_BE_WDE_Q1_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q1_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA2_CFG 0x8C48 +#define B_BE_WDE_Q2_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q2_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA3_CFG 0x8C4C +#define B_BE_WDE_Q3_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q3_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA4_CFG 0x8C50 +#define B_BE_WDE_Q4_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q4_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_PKTBUF_CFG 0x9008 +#define B_BE_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define B_BE_PLE_START_BOUND_MASK GENMASK(14, 8) +#define B_BE_PLE_PAGE_SEL_MASK GENMASK(1, 0) + +#define R_BE_PLE_QTA0_CFG 0x9040 +#define B_BE_PLE_Q0_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q0_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA1_CFG 0x9044 +#define B_BE_PLE_Q1_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q1_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA2_CFG 0x9048 +#define B_BE_PLE_Q2_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q2_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA3_CFG 0x904C +#define B_BE_PLE_Q3_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q3_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA4_CFG 0x9050 +#define B_BE_PLE_Q4_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q4_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA5_CFG 0x9054 +#define B_BE_PLE_Q5_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q5_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA6_CFG 0x9058 +#define B_BE_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA7_CFG 0x905C +#define B_BE_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA8_CFG 0x9060 +#define B_BE_PLE_Q8_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q8_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA9_CFG 0x9064 +#define B_BE_PLE_Q9_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q9_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA10_CFG 0x9068 +#define B_BE_PLE_Q10_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q10_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA11_CFG 0x906C +#define B_BE_PLE_Q11_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q11_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA12_CFG 0x9070 +#define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) @@ -4182,6 +4318,72 @@ #define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114 #define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0) +#define R_BE_WD_BUF_REQ 0x9800 +#define B_BE_WD_BUF_REQ_EXEC BIT(31) +#define B_BE_WD_BUF_REQ_QUOTA_ID_MASK GENMASK(23, 16) +#define B_BE_WD_BUF_REQ_LEN_MASK GENMASK(15, 0) + +#define R_BE_WD_BUF_STATUS 0x9804 +#define B_BE_WD_BUF_STAT_DONE BIT(31) +#define B_BE_WD_BUF_STAT_PKTID_MASK GENMASK(11, 0) + +#define R_BE_WD_CPUQ_OP_0 0x9810 +#define B_BE_WD_CPUQ_OP_EXEC BIT(31) +#define B_BE_WD_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24) +#define B_BE_WD_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0) + +#define R_BE_WD_CPUQ_OP_1 0x9814 +#define B_BE_WD_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12) +#define B_BE_WD_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4) +#define B_BE_WD_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0) + +#define R_BE_WD_CPUQ_OP_2 0x9818 +#define B_BE_WD_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12) +#define B_BE_WD_CPUQ_OP_DST_QID_MASK GENMASK(9, 4) +#define B_BE_WD_CPUQ_OP_DST_PID_MASK GENMASK(2, 0) + +#define R_BE_WD_CPUQ_OP_3 0x981C +#define B_BE_WD_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16) +#define B_BE_WD_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0) + +#define R_BE_WD_CPUQ_OP_STATUS 0x9820 +#define B_BE_WD_CPUQ_OP_STAT_DONE BIT(31) +#define B_BE_WD_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16) +#define B_BE_WD_CPUQ_OP_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_BUF_REQ 0x9840 +#define B_BE_PL_BUF_REQ_EXEC BIT(31) +#define B_BE_PL_BUF_REQ_QUOTA_ID_MASK GENMASK(19, 16) +#define B_BE_PL_BUF_REQ_LEN_MASK GENMASK(15, 0) + +#define R_BE_PL_BUF_STATUS 0x9844 +#define B_BE_PL_BUF_STAT_DONE BIT(31) +#define B_BE_PL_BUF_STAT_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_CPUQ_OP_0 0x9850 +#define B_BE_PL_CPUQ_OP_EXEC BIT(31) +#define B_BE_PL_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24) +#define B_BE_PL_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0) + +#define R_BE_PL_CPUQ_OP_1 0x9854 +#define B_BE_PL_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12) +#define B_BE_PL_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4) +#define B_BE_PL_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0) + +#define R_BE_PL_CPUQ_OP_2 0x9858 +#define B_BE_PL_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12) +#define B_BE_PL_CPUQ_OP_DST_QID_MASK GENMASK(9, 4) +#define B_BE_PL_CPUQ_OP_DST_PID_MASK GENMASK(2, 0) + +#define R_BE_PL_CPUQ_OP_3 0x985C +#define B_BE_PL_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16) +#define B_BE_PL_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_CPUQ_OP_STATUS 0x9860 +#define B_BE_PL_CPUQ_OP_STAT_DONE BIT(31) +#define B_BE_PL_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16) +#define B_BE_PL_CPUQ_OP_PKTID_MASK GENMASK(11, 0) + #define R_BE_HAXI_INIT_CFG1 0xB000 #define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) #define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) @@ -4204,6 +4406,68 @@ #define B_BE_MAX_RXDMA_MASK GENMASK(3, 2) #define B_BE_MAX_TXDMA_MASK GENMASK(1, 0) +#define R_BE_HAXI_DMA_STOP1 0xB010 +#define B_BE_STOP_WPDMA BIT(31) +#define B_BE_STOP_CH14 BIT(14) +#define B_BE_STOP_CH13 BIT(13) +#define B_BE_STOP_CH12 BIT(12) +#define B_BE_STOP_CH11 BIT(11) +#define B_BE_STOP_CH10 BIT(10) +#define B_BE_STOP_CH9 BIT(9) +#define B_BE_STOP_CH8 BIT(8) +#define B_BE_STOP_CH7 BIT(7) +#define B_BE_STOP_CH6 BIT(6) +#define B_BE_STOP_CH5 BIT(5) +#define B_BE_STOP_CH4 BIT(4) +#define B_BE_STOP_CH3 BIT(3) +#define B_BE_STOP_CH2 BIT(2) +#define B_BE_STOP_CH1 BIT(1) +#define B_BE_STOP_CH0 BIT(0) + +#define R_BE_HCI_FC_CTRL 0xB700 +#define B_BE_WD_PAGE_MODE_MASK GENMASK(17, 16) +#define B_BE_HCI_FC_CH14_FULL_COND_MASK GENMASK(15, 14) +#define B_BE_HCI_FC_TWD_FULL_COND_MASK GENMASK(13, 12) +#define B_BE_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) +#define B_BE_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) +#define B_BE_HCI_FC_WP_CH07_FULL_COND_MASK GENMASK(7, 6) +#define B_BE_HCI_FC_WD_FULL_COND_MASK GENMASK(5, 4) +#define B_BE_HCI_FC_CH12_EN BIT(3) +#define B_BE_HCI_FC_MODE_MASK GENMASK(2, 1) +#define B_BE_HCI_FC_EN BIT(0) + +#define R_BE_CH_PAGE_CTRL 0xB704 +#define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) +#define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) + +#define R_BE_PUB_PAGE_INFO3 0xB78C +#define B_BE_G1_AVAL_PG_MASK GENMASK(28, 16) +#define B_BE_G0_AVAL_PG_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_CTRL1 0xB790 +#define B_BE_PUBPG_G1_MASK GENMASK(28, 16) +#define B_BE_PUBPG_G0_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_CTRL2 0xB794 +#define B_BE_PUBPG_ALL_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_INFO1 0xB79C +#define B_BE_G1_USE_PG_MASK GENMASK(28, 16) +#define B_BE_G0_USE_PG_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_INFO2 0xB7A0 +#define B_BE_PUB_AVAL_PG_MASK GENMASK(12, 0) + +#define R_BE_WP_PAGE_CTRL1 0xB7A4 +#define B_BE_PREC_PAGE_WP_CH811_MASK GENMASK(24, 16) +#define B_BE_PREC_PAGE_WP_CH07_MASK GENMASK(8, 0) + +#define R_BE_WP_PAGE_CTRL2 0xB7A8 +#define B_BE_WP_THRD_MASK GENMASK(12, 0) + +#define R_BE_WP_PAGE_INFO1 0xB7AC +#define B_BE_WP_AVAL_PG_MASK GENMASK(28, 16) + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) From 18b8413b25b7070fa2e55858a2c808e6909581d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:35 -0300 Subject: [PATCH 2103/7721] drm/v3d: Create a CPU job extension for a indirect CSD job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. An indirect CSD job is a job that, when executed in the queue, will map the indirect buffer, read the dispatch parameters, and submit a regular dispatch. Therefore, it is a job that needs CPU intervention. So, create a user extension for the CPU job that enables the creation of an indirect CSD. This user extension will allow the creation of a CSD job linked to a CPU job. The CPU job will wait for the indirect CSD job dependencies and, once they are signaled, it will update the CSD job parameters. Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-14-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 31 ++++++++- drivers/gpu/drm/v3d/v3d_sched.c | 41 +++++++++++- drivers/gpu/drm/v3d/v3d_submit.c | 104 ++++++++++++++++++++++++++++++- include/uapi/drm/v3d_drm.h | 43 ++++++++++++- 4 files changed, 213 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 39d62915cdd6..202c0d4b04a5 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -316,12 +316,41 @@ struct v3d_csd_job { struct drm_v3d_submit_csd args; }; -enum v3d_cpu_job_type {}; +enum v3d_cpu_job_type { + V3D_CPU_JOB_TYPE_INDIRECT_CSD = 1, +}; + +struct v3d_indirect_csd_info { + /* Indirect CSD */ + struct v3d_csd_job *job; + + /* Clean cache job associated to the Indirect CSD job */ + struct v3d_job *clean_job; + + /* Offset within the BO where the workgroup counts are stored */ + u32 offset; + + /* Workgroups size */ + u32 wg_size; + + /* Indices of the uniforms with the workgroup dispatch counts + * in the uniform stream. + */ + u32 wg_uniform_offsets[3]; + + /* Indirect BO */ + struct drm_gem_object *indirect; + + /* Context of the Indirect CSD job */ + struct ww_acquire_ctx acquire_ctx; +}; struct v3d_cpu_job { struct v3d_job base; enum v3d_cpu_job_type job_type; + + struct v3d_indirect_csd_info indirect_csd; }; typedef void (*v3d_cpu_job_fn)(struct v3d_cpu_job *); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index ebbd00840a73..307257ab0e4a 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -25,6 +25,8 @@ #include "v3d_regs.h" #include "v3d_trace.h" +#define V3D_CSD_CFG012_WG_COUNT_SHIFT 16 + static struct v3d_job * to_v3d_job(struct drm_sched_job *sched_job) { @@ -268,7 +270,44 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) return fence; } -static const v3d_cpu_job_fn cpu_job_function[] = { }; +static void +v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job) +{ + struct v3d_indirect_csd_info *indirect_csd = &job->indirect_csd; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + struct v3d_bo *indirect = to_v3d_bo(indirect_csd->indirect); + struct drm_v3d_submit_csd *args = &indirect_csd->job->args; + u32 *wg_counts; + + v3d_get_bo_vaddr(bo); + v3d_get_bo_vaddr(indirect); + + wg_counts = (uint32_t *)(bo->vaddr + indirect_csd->offset); + + if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0) + return; + + args->cfg[0] = wg_counts[0] << V3D_CSD_CFG012_WG_COUNT_SHIFT; + args->cfg[1] = wg_counts[1] << V3D_CSD_CFG012_WG_COUNT_SHIFT; + args->cfg[2] = wg_counts[2] << V3D_CSD_CFG012_WG_COUNT_SHIFT; + args->cfg[4] = DIV_ROUND_UP(indirect_csd->wg_size, 16) * + (wg_counts[0] * wg_counts[1] * wg_counts[2]) - 1; + + for (int i = 0; i < 3; i++) { + /* 0xffffffff indicates that the uniform rewrite is not needed */ + if (indirect_csd->wg_uniform_offsets[i] != 0xffffffff) { + u32 uniform_idx = indirect_csd->wg_uniform_offsets[i]; + ((uint32_t *)indirect->vaddr)[uniform_idx] = wg_counts[i]; + } + } + + v3d_put_bo_vaddr(indirect); + v3d_put_bo_vaddr(bo); +} + +static const v3d_cpu_job_fn cpu_job_function[] = { + [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, +}; static struct dma_fence * v3d_cpu_job_run(struct drm_sched_job *sched_job) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index eb26fe1e27e3..0320695b941b 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -391,6 +391,48 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, return 0; } +/* Get data for the indirect CSD job submission. */ +static int +v3d_get_cpu_indirect_csd_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct v3d_dev *v3d = v3d_priv->v3d; + struct drm_v3d_indirect_csd indirect_csd; + struct v3d_indirect_csd_info *info = &job->indirect_csd; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(&indirect_csd, ext, sizeof(indirect_csd))) + return -EFAULT; + + if (!v3d_has_csd(v3d)) { + DRM_DEBUG("Attempting CSD submit on non-CSD hardware.\n"); + return -EINVAL; + } + + job->job_type = V3D_CPU_JOB_TYPE_INDIRECT_CSD; + info->offset = indirect_csd.offset; + info->wg_size = indirect_csd.wg_size; + memcpy(&info->wg_uniform_offsets, &indirect_csd.wg_uniform_offsets, + sizeof(indirect_csd.wg_uniform_offsets)); + + info->indirect = drm_gem_object_lookup(file_priv, indirect_csd.indirect); + + return v3d_setup_csd_jobs_and_bos(file_priv, v3d, &indirect_csd.submit, + &info->job, &info->clean_job, + NULL, &info->acquire_ctx); +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -416,6 +458,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_MULTI_SYNC: ret = v3d_get_multisync_submit_deps(file_priv, user_ext, se); break; + case DRM_V3D_EXT_ID_CPU_INDIRECT_CSD: + ret = v3d_get_cpu_indirect_csd_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -790,7 +835,9 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, return ret; } -static const unsigned int cpu_job_bo_handle_count[] = { }; +static const unsigned int cpu_job_bo_handle_count[] = { + [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = 1, +}; /** * v3d_submit_cpu_ioctl() - Submits a CPU job to the V3D. @@ -808,7 +855,10 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, struct v3d_dev *v3d = to_v3d_dev(dev); struct drm_v3d_submit_cpu *args = data; struct v3d_submit_ext se = {0}; + struct v3d_submit_ext *out_se = NULL; struct v3d_cpu_job *cpu_job = NULL; + struct v3d_csd_job *csd_job = NULL; + struct v3d_job *clean_job = NULL; struct ww_acquire_ctx acquire_ctx; int ret; @@ -847,6 +897,9 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, if (ret) goto fail; + clean_job = cpu_job->indirect_csd.clean_job; + csd_job = cpu_job->indirect_csd.job; + if (args->bo_handle_count) { ret = v3d_lookup_bos(dev, file_priv, &cpu_job->base, args->bo_handles, args->bo_handle_count); @@ -860,19 +913,66 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, mutex_lock(&v3d->sched_lock); v3d_push_job(&cpu_job->base); + + switch (cpu_job->job_type) { + case V3D_CPU_JOB_TYPE_INDIRECT_CSD: + ret = drm_sched_job_add_dependency(&csd_job->base.base, + dma_fence_get(cpu_job->base.done_fence)); + if (ret) + goto fail_unreserve; + + v3d_push_job(&csd_job->base); + + ret = drm_sched_job_add_dependency(&clean_job->base, + dma_fence_get(csd_job->base.done_fence)); + if (ret) + goto fail_unreserve; + + v3d_push_job(clean_job); + + break; + default: + break; + } mutex_unlock(&v3d->sched_lock); + out_se = (cpu_job->job_type == V3D_CPU_JOB_TYPE_INDIRECT_CSD) ? NULL : &se; + v3d_attach_fences_and_unlock_reservation(file_priv, &cpu_job->base, &acquire_ctx, 0, - NULL, cpu_job->base.done_fence); + out_se, cpu_job->base.done_fence); + + switch (cpu_job->job_type) { + case V3D_CPU_JOB_TYPE_INDIRECT_CSD: + v3d_attach_fences_and_unlock_reservation(file_priv, + clean_job, + &cpu_job->indirect_csd.acquire_ctx, + 0, &se, clean_job->done_fence); + break; + default: + break; + } v3d_job_put(&cpu_job->base); + v3d_job_put(&csd_job->base); + v3d_job_put(clean_job); return 0; +fail_unreserve: + mutex_unlock(&v3d->sched_lock); + + drm_gem_unlock_reservations(cpu_job->base.bo, cpu_job->base.bo_count, + &acquire_ctx); + + drm_gem_unlock_reservations(clean_job->bo, clean_job->bo_count, + &cpu_job->indirect_csd.acquire_ctx); + fail: v3d_job_cleanup((void *)cpu_job); + v3d_job_cleanup((void *)csd_job); + v3d_job_cleanup(clean_job); v3d_put_multisync_post_deps(&se); return ret; diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 00abef9d0db7..0c0f47782528 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -71,7 +71,8 @@ extern "C" { struct drm_v3d_extension { __u64 next; __u32 id; -#define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 +#define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 +#define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 __u32 flags; /* mbz */ }; @@ -365,8 +366,46 @@ struct drm_v3d_submit_csd { __u32 pad; }; +/** + * struct drm_v3d_indirect_csd - ioctl extension for the CPU job to create an + * indirect CSD + * + * When an extension of DRM_V3D_EXT_ID_CPU_INDIRECT_CSD id is defined, it + * points to this extension to define a indirect CSD submission. It creates a + * CPU job linked to a CSD job. The CPU job waits for the indirect CSD + * dependencies and, once they are signaled, it updates the CSD job config + * before allowing the CSD job execution. + */ +struct drm_v3d_indirect_csd { + struct drm_v3d_extension base; + + /* Indirect CSD */ + struct drm_v3d_submit_csd submit; + + /* Handle of the indirect BO, that should be also attached to the + * indirect CSD. + */ + __u32 indirect; + + /* Offset within the BO where the workgroup counts are stored */ + __u32 offset; + + /* Workgroups size */ + __u32 wg_size; + + /* Indices of the uniforms with the workgroup dispatch counts + * in the uniform stream. If the uniform rewrite is not needed, + * the offset must be 0xffffffff. + */ + __u32 wg_uniform_offsets[3]; +}; + struct drm_v3d_submit_cpu { - /* Pointer to a u32 array of the BOs that are referenced by the job. */ + /* Pointer to a u32 array of the BOs that are referenced by the job. + * + * For DRM_V3D_EXT_ID_CPU_INDIRECT_CSD, it must contain only one BO, + * that contains the workgroup counts. + */ __u64 bo_handles; /* Number of BO handles passed in (size is that times 4). */ From 00384f565a91c08c4bedae167f749b093d10e3fe Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 20 Nov 2023 12:57:26 +0100 Subject: [PATCH 2104/7721] wifi: rtw88: sdio: Honor the host max_req_size in the RX path Lukas reports skb_over_panic errors on his Banana Pi BPI-CM4 which comes with an Amlogic A311D (G12B) SoC and a RTL8822CS SDIO wifi/Bluetooth combo card. The error he observed is identical to what has been fixed in commit e967229ead0e ("wifi: rtw88: sdio: Check the HISR RX_REQUEST bit in rtw_sdio_rx_isr()") but that commit didn't fix Lukas' problem. Lukas found that disabling or limiting RX aggregation works around the problem for some time (but does not fully fix it). In the following discussion a few key topics have been discussed which have an impact on this problem: - The Amlogic A311D (G12B) SoC has a hardware bug in the SDIO controller which prevents DMA transfers. Instead all transfers need to go through the controller SRAM which limits transfers to 1536 bytes - rtw88 chips don't split incoming (RX) packets, so if a big packet is received this is forwarded to the host in it's original form - rtw88 chips can do RX aggregation, meaning more multiple incoming packets can be pulled by the host from the card with one MMC/SDIO transfer. This Depends on settings in the REG_RXDMA_AGG_PG_TH register (BIT_RXDMA_AGG_PG_TH limits the number of packets that will be aggregated, BIT_DMA_AGG_TO_V1 configures a timeout for aggregation and BIT_EN_PRE_CALC makes the chip honor the limits more effectively) Use multiple consecutive reads in rtw_sdio_read_port() and limit the number of bytes which are copied by the host from the card in one MMC/SDIO transfer. This allows receiving a buffer that's larger than the hosts max_req_size (number of bytes which can be transferred in one MMC/SDIO transfer). As a result of this the skb_over_panic error is gone as the rtw88 driver is now able to receive more than 1536 bytes from the card (either because the incoming packet is larger than that or because multiple packets have been aggregated). In case of an receive errors (-EILSEQ has been observed by Lukas) we need to drain the remaining data from the card's buffer, otherwise the card will return corrupt data for the next rtw_sdio_read_port() call. Fixes: 65371a3f14e7 ("wifi: rtw88: sdio: Add HCI implementation for SDIO based chipsets") Reported-by: Lukas F. Hartmann Closes: https://lore.kernel.org/linux-wireless/CAFBinCBaXtebixKbjkWKW_WXc5k=NdGNaGUjVE8NCPNxOhsb2g@mail.gmail.com/ Suggested-by: Ping-Ke Shih Signed-off-by: Martin Blumenstingl Reviewed-by: Ulf Hansson Acked-by: Ping-Ke Shih Tested-by: Lukas F. Hartmann Reported-by: Lukas F. Hartmann Signed-off-by: Martin Blumenstingl Reviewed-by: Ulf Hansson Acked-by: Ping-Ke Shih Tested-by: Lukas F. Hartmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231120115726.1569323-1-martin.blumenstingl@googlemail.com --- drivers/net/wireless/realtek/rtw88/sdio.c | 35 ++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 2c1fb2dabd40..0cae5746f540 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -500,19 +500,40 @@ static u32 rtw_sdio_get_tx_addr(struct rtw_dev *rtwdev, size_t size, static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) { struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; + struct mmc_host *host = rtwsdio->sdio_func->card->host; bool bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); u32 rxaddr = rtwsdio->rx_addr++; - int ret; + int ret = 0, err; + size_t bytes; if (bus_claim) sdio_claim_host(rtwsdio->sdio_func); - ret = sdio_memcpy_fromio(rtwsdio->sdio_func, buf, - RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr), count); - if (ret) - rtw_warn(rtwdev, - "Failed to read %zu byte(s) from SDIO port 0x%08x", - count, rxaddr); + while (count > 0) { + bytes = min_t(size_t, host->max_req_size, count); + + err = sdio_memcpy_fromio(rtwsdio->sdio_func, buf, + RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr), + bytes); + if (err) { + rtw_warn(rtwdev, + "Failed to read %zu byte(s) from SDIO port 0x%08x: %d", + bytes, rxaddr, err); + + /* Signal to the caller that reading did not work and + * that the data in the buffer is short/corrupted. + */ + ret = err; + + /* Don't stop here - instead drain the remaining data + * from the card's buffer, else the card will return + * corrupt data for the next rtw_sdio_read_port() call. + */ + } + + count -= bytes; + buf += bytes; + } if (bus_claim) sdio_release_host(rtwsdio->sdio_func); From b3943b3c2971444364e03224cfc828c5789deada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:16 +0200 Subject: [PATCH 2105/7721] wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since introduction in the commit 0c8173385e54 ("rtl8192ce: Add new driver") the rtlwifi code has, according to comments, attempted to disable/enable ASPM of the upstream bridge by writing into its LNKCTL register. However, the code has never been correct because it performs the writes to the device instead of the upstream bridge. Worse yet, the offset where the PCIe capabilities reside is derived from the offset of the upstream bridge. As a result, the write will use an offset on the device that does not relate to the LNKCTL register making the ASPM disable/enable code outright dangerous. Because of those problems, there is no indication that the driver needs disable/enable ASPM on the upstream bridge. As the Capabilities offset is not correctly calculated for the write to target device's LNKCTL register, the code is not disabling/enabling device's ASPM either. Therefore, just remove the upstream bridge related ASPM disable/enable code entirely. The upstream bridge related ASPM code was the only user of the struct mp_adapter members num4bytes, pcibridge_pciehdr_offset, and pcibridge_linkctrlreg so those are removed as well. Note: This change does not remove the code related to changing the device's ASPM on purpose (which is independent of this flawed code related to upstream bridge's ASPM). Suggested-by: Bjorn Helgaas Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") Fixes: 886e14b65a8f ("rtlwifi: Eliminate raw reads and writes from PCIe portion") Cc: stable@vger.kernel.org Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-2-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 58 +--------------------- drivers/net/wireless/realtek/rtlwifi/pci.h | 5 -- 2 files changed, 1 insertion(+), 62 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index b163a069660b..cb8f1470cf59 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -191,11 +191,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u8 num4bytes = pcipriv->ndis_adapter.num4bytes; /*Retrieve original configuration settings. */ u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; - u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. - pcibridge_linkctrlreg; u16 aspmlevel = 0; u8 tmp_u1b = 0; @@ -220,16 +217,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) /*Set corresponding value. */ aspmlevel |= BIT(0) | BIT(1); linkctrl_reg &= ~aspmlevel; - pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1)); _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); - udelay(50); - - /*4 Disable Pci Bridge ASPM */ - pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), - pcibridge_linkctrlreg); - - udelay(50); } /*Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for @@ -244,9 +233,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u8 num4bytes = pcipriv->ndis_adapter.num4bytes; u16 aspmlevel; - u8 u_pcibridge_aspmsetting; u8 u_device_aspmsetting; if (!ppsc->support_aspm) @@ -258,25 +245,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) return; } - /*4 Enable Pci Bridge ASPM */ - - u_pcibridge_aspmsetting = - pcipriv->ndis_adapter.pcibridge_linkctrlreg | - rtlpci->const_hostpci_aspm_setting; - - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) - u_pcibridge_aspmsetting &= ~BIT(0); - - pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), - u_pcibridge_aspmsetting); - - rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "PlatformEnableASPM(): Write reg[%x] = %x\n", - (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), - u_pcibridge_aspmsetting); - - udelay(50); - /*Get ASPM level (with/without Clock Req) */ aspmlevel = rtlpci->const_devicepci_aspm_setting; u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg; @@ -357,22 +325,6 @@ static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw, return tpriv != NULL; } -static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) -{ - struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); - u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; - u8 linkctrl_reg; - u8 num4bbytes; - - num4bbytes = (capabilityoffset + 0x10) / 4; - - /*Read Link Control Register */ - pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg); - - pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; -} - static void rtl_pci_parse_configuration(struct pci_dev *pdev, struct ieee80211_hw *hw) { @@ -2027,12 +1979,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, PCI_SLOT(bridge_pdev->devfn); pcipriv->ndis_adapter.pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); - pcipriv->ndis_adapter.pcibridge_pciehdr_offset = - pci_pcie_cap(bridge_pdev); - pcipriv->ndis_adapter.num4bytes = - (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; - - rtl_pci_get_linkcontrol_field(hw); if (pcipriv->ndis_adapter.pcibridge_vendor == PCI_BRIDGE_VENDOR_AMD) { @@ -2049,13 +1995,11 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg); rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n", + "pci_bridge busnumber:devnumber:funcnumber:vendor:amd %d:%d:%d:%x:%x\n", pcipriv->ndis_adapter.pcibridge_busnum, pcipriv->ndis_adapter.pcibridge_devnum, pcipriv->ndis_adapter.pcibridge_funcnum, pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor], - pcipriv->ndis_adapter.pcibridge_pciehdr_offset, - pcipriv->ndis_adapter.pcibridge_linkctrlreg, pcipriv->ndis_adapter.amd_l1_patch); rtl_pci_parse_configuration(pdev, hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index 4725d43609fd..ba25bc6d3acb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -235,11 +235,6 @@ struct mp_adapter { u16 pcibridge_vendorid; u16 pcibridge_deviceid; - u8 num4bytes; - - u8 pcibridge_pciehdr_offset; - u8 pcibridge_linkctrlreg; - bool amd_l1_patch; }; From 5894d0089cbc146063dcc0239a78ede0a8142efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:17 +0200 Subject: [PATCH 2106/7721] wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtlwifi driver comes with custom code to write into PCIe Link Control register. RMW access for the Link Control register requires locking that is already provided by the standard PCIe capability accessors. Convert the custom RMW code writing into LNKCTL register to standard RMW capability accessors. The accesses are changed to cover the full LNKCTL register instead of touching just a single byte of the register. Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") Cc: stable@vger.kernel.org Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-3-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index cb8f1470cf59..3a7eed1d4c5e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -163,21 +163,29 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) - value |= 0x40; + value &= PCI_EXP_LNKCTL_ASPMC; - pci_write_config_byte(rtlpci->pdev, 0x80, value); + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= PCI_EXP_LNKCTL_CCC; + + pcie_capability_clear_and_set_word(rtlpci->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_ASPMC | value, + value); return false; } -/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ -static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) +/* @value is PCI_EXP_LNKCTL_CLKREQ_EN or 0 to enable/disable clk request. */ +static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u16 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - pci_write_config_byte(rtlpci->pdev, 0x81, value); + value &= PCI_EXP_LNKCTL_CLKREQ_EN; + + pcie_capability_clear_and_set_word(rtlpci->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CLKREQ_EN, + value); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) udelay(100); @@ -258,7 +266,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { _rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level & - RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); + RT_RF_OFF_LEVL_CLK_REQ) ? + PCI_EXP_LNKCTL_CLKREQ_EN : 0); RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); } udelay(100); From a4fcac11a25ac3f3336a4324b497a16ae1ae5e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:18 +0200 Subject: [PATCH 2107/7721] wifi: rtlwifi: Convert to use PCIe capability accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtlwifi driver accesses PCIe capabilities through custom config offsets. Convert the accesses to use the normal PCIe capability accessors. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-4-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 3a7eed1d4c5e..bc41e865bac1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -64,7 +64,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u8 init_aspm; + u16 init_aspm; ppsc->reg_rfps_level = 0; ppsc->support_aspm = false; @@ -150,9 +150,10 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /* toshiba aspm issue, toshiba will set aspm selfly * so we should not set aspm in driver */ - pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &init_aspm); if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && - init_aspm == 0x43) + ((u8)init_aspm) == (PCI_EXP_LNKCTL_ASPM_L0S | + PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_CCC)) ppsc->support_aspm = false; } @@ -202,7 +203,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) /*Retrieve original configuration settings. */ u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; u16 aspmlevel = 0; - u8 tmp_u1b = 0; + u16 tmp_u1b = 0; if (!ppsc->support_aspm) return; @@ -220,10 +221,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) } /*for promising device will in L0 state after an I/O. */ - pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); + pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &tmp_u1b); /*Set corresponding value. */ - aspmlevel |= BIT(0) | BIT(1); + aspmlevel |= PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1; linkctrl_reg &= ~aspmlevel; _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); @@ -350,9 +351,8 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n", pcipriv->ndis_adapter.linkctrl_reg); - pci_read_config_byte(pdev, 0x98, &tmp); - tmp |= BIT(4); - pci_write_config_byte(pdev, 0x98, tmp); + pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_COMP_TMOUT_DIS); tmp = 0x17; pci_write_config_byte(pdev, 0x70f, tmp); From 6e071ae899f10d1b8a75639349c226b8e777de26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:19 +0200 Subject: [PATCH 2108/7721] wifi: rtlwifi: rtl8821ae: Remove unnecessary PME_Status bit set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BIT(7) (PME_Status) is first checked and then set unnecessarily. Remove the unnecessary setting for the bit that is already on and adjust the comment related to it. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-5-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 1633328bc3d1..6ae37d61a2a2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2312,9 +2312,7 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg); if (pmcs_reg & BIT(7)) { - /* PME event occured, clear the PM_Status by write 1 */ - pmcs_reg = pmcs_reg | BIT(7); - + /* Clear PME_Status with write */ pci_write_config_byte(rtlpci->pdev, cap_pointer + 5, pmcs_reg); /* Read it back to check */ From 760bfed91201299a135049f9219fd3ec8845f525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:20 +0200 Subject: [PATCH 2109/7721] wifi: rtlwifi: rtl8821ae: Reverse PM Capability exists check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check if PM Capability does not exists and return early which follows the usual error handling pattern. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-6-ilpo.jarvinen@linux.intel.com --- .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 6ae37d61a2a2..53cfeed0b030 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2305,30 +2305,31 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) } } while (cnt++ < 200); - if (cap_id == 0x01) { - /* Get the PM CSR (Control/Status Register), - * The PME_Status is located at PM Capatibility offset 5, bit 7 - */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg); - - if (pmcs_reg & BIT(7)) { - /* Clear PME_Status with write */ - pci_write_config_byte(rtlpci->pdev, cap_pointer + 5, - pmcs_reg); - /* Read it back to check */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, - &pmcs_reg); - rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "Clear PME status 0x%2x to 0x%2x\n", - cap_pointer + 5, pmcs_reg); - } else { - rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "PME status(0x%2x) = 0x%2x\n", - cap_pointer + 5, pmcs_reg); - } - } else { + if (cap_id != 0x01) { rtl_dbg(rtlpriv, COMP_INIT, DBG_WARNING, "Cannot find PME Capability\n"); + return; + } + + /* Get the PM CSR (Control/Status Register), + * The PME_Status is located at PM Capatibility offset 5, bit 7 + */ + pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg); + + if (pmcs_reg & BIT(7)) { + /* Clear PME_Status with write */ + pci_write_config_byte(rtlpci->pdev, cap_pointer + 5, + pmcs_reg); + /* Read it back to check */ + pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, + &pmcs_reg); + rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, + "Clear PME status 0x%2x to 0x%2x\n", + cap_pointer + 5, pmcs_reg); + } else { + rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, + "PME status(0x%2x) = 0x%2x\n", + cap_pointer + 5, pmcs_reg); } } From 9dcc75e0b7d05069d257108d21080d6c5abb43d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:21 +0200 Subject: [PATCH 2110/7721] wifi: rtlwifi: rtl8821ae: Use pci_find_capability() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of open coding the capability structure search, find the PM Capability using pci_find_capability(). While at it, rename the generic 'cap_pointer' to 'pm_cap' which makes the intent of the code more obvious. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-7-ilpo.jarvinen@linux.intel.com --- .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 49 +++---------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 53cfeed0b030..7877509c34c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2270,42 +2270,11 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u16 cap_hdr; - u8 cap_pointer; - u8 cap_id = 0xff; u8 pmcs_reg; - u8 cnt = 0; + u8 pm_cap; - /* Get the Capability pointer first, - * the Capability Pointer is located at - * offset 0x34 from the Function Header */ - - pci_read_config_byte(rtlpci->pdev, 0x34, &cap_pointer); - rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "PCI configuration 0x34 = 0x%2x\n", cap_pointer); - - do { - pci_read_config_word(rtlpci->pdev, cap_pointer, &cap_hdr); - cap_id = cap_hdr & 0xFF; - - rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "in pci configuration, cap_pointer%x = %x\n", - cap_pointer, cap_id); - - if (cap_id == 0x01) { - break; - } else { - /* point to next Capability */ - cap_pointer = (cap_hdr >> 8) & 0xFF; - /* 0: end of pci capability, 0xff: invalid value */ - if (cap_pointer == 0x00 || cap_pointer == 0xff) { - cap_id = 0xff; - break; - } - } - } while (cnt++ < 200); - - if (cap_id != 0x01) { + pm_cap = pci_find_capability(rtlpci->pdev, PCI_CAP_ID_PM); + if (!pm_cap) { rtl_dbg(rtlpriv, COMP_INIT, DBG_WARNING, "Cannot find PME Capability\n"); return; @@ -2314,22 +2283,20 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) /* Get the PM CSR (Control/Status Register), * The PME_Status is located at PM Capatibility offset 5, bit 7 */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg); + pci_read_config_byte(rtlpci->pdev, pm_cap + 5, &pmcs_reg); if (pmcs_reg & BIT(7)) { /* Clear PME_Status with write */ - pci_write_config_byte(rtlpci->pdev, cap_pointer + 5, - pmcs_reg); + pci_write_config_byte(rtlpci->pdev, pm_cap + 5, pmcs_reg); /* Read it back to check */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, - &pmcs_reg); + pci_read_config_byte(rtlpci->pdev, pm_cap + 5, &pmcs_reg); rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "Clear PME status 0x%2x to 0x%2x\n", - cap_pointer + 5, pmcs_reg); + pm_cap + 5, pmcs_reg); } else { rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "PME status(0x%2x) = 0x%2x\n", - cap_pointer + 5, pmcs_reg); + pm_cap + 5, pmcs_reg); } } From 7bd350d2ac915e66d9a23c60fd2fdf41c4233980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:22 +0200 Subject: [PATCH 2111/7721] wifi: rtlwifi: rtl8821ae: Add pdev into _rtl8821ae_clear_pci_pme_status() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add local variable pdev to shorten rtlpci->pdev. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-8-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 7877509c34c7..7cc648d49f2d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2270,10 +2270,11 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct pci_dev *pdev = rtlpci->pdev; u8 pmcs_reg; u8 pm_cap; - pm_cap = pci_find_capability(rtlpci->pdev, PCI_CAP_ID_PM); + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (!pm_cap) { rtl_dbg(rtlpriv, COMP_INIT, DBG_WARNING, "Cannot find PME Capability\n"); @@ -2283,13 +2284,13 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) /* Get the PM CSR (Control/Status Register), * The PME_Status is located at PM Capatibility offset 5, bit 7 */ - pci_read_config_byte(rtlpci->pdev, pm_cap + 5, &pmcs_reg); + pci_read_config_byte(pdev, pm_cap + 5, &pmcs_reg); if (pmcs_reg & BIT(7)) { /* Clear PME_Status with write */ - pci_write_config_byte(rtlpci->pdev, pm_cap + 5, pmcs_reg); + pci_write_config_byte(pdev, pm_cap + 5, pmcs_reg); /* Read it back to check */ - pci_read_config_byte(rtlpci->pdev, pm_cap + 5, &pmcs_reg); + pci_read_config_byte(pdev, pm_cap + 5, &pmcs_reg); rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "Clear PME status 0x%2x to 0x%2x\n", pm_cap + 5, pmcs_reg); From 05b311a3f9153226b5603e33831aec34fd38e228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:23 +0200 Subject: [PATCH 2112/7721] wifi: rtlwifi: rtl8821ae: Access full PMCS reg and use pci_regs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _rtl8821ae_clear_pci_pme_status() accesses the upper byte of the Power Management Control/Status register (PMCS) with literal 5 offset. Access the entire PMCS register using defines from pci_regs.h to improve code readability. While at it, remove the obvious comment and tweak debug prints slightly to not sound misleading. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-9-ilpo.jarvinen@linux.intel.com --- .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 7cc648d49f2d..f4b232f038a9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2271,7 +2271,7 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct pci_dev *pdev = rtlpci->pdev; - u8 pmcs_reg; + u16 pmcs_reg; u8 pm_cap; pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); @@ -2281,23 +2281,16 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) return; } - /* Get the PM CSR (Control/Status Register), - * The PME_Status is located at PM Capatibility offset 5, bit 7 - */ - pci_read_config_byte(pdev, pm_cap + 5, &pmcs_reg); - - if (pmcs_reg & BIT(7)) { + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg); + if (pmcs_reg & PCI_PM_CTRL_PME_STATUS) { /* Clear PME_Status with write */ - pci_write_config_byte(pdev, pm_cap + 5, pmcs_reg); - /* Read it back to check */ - pci_read_config_byte(pdev, pm_cap + 5, &pmcs_reg); + pci_write_config_word(pdev, pm_cap + PCI_PM_CTRL, pmcs_reg); + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg); rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "Clear PME status 0x%2x to 0x%2x\n", - pm_cap + 5, pmcs_reg); + "Cleared PME status, PMCS reg = 0x%4x\n", pmcs_reg); } else { rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "PME status(0x%2x) = 0x%2x\n", - pm_cap + 5, pmcs_reg); + "PMCS reg = 0x%4x\n", pmcs_reg); } } From 217fbc032eaaaa7bdfcaae0f1680cc0fbb0f3b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:24 +0200 Subject: [PATCH 2113/7721] wifi: rtlwifi: Remove unused PCI related defines and struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtlwifi driver comes with a number of PCI related defines that are unused and many would be provided by PCI core anyway if they'd be needed again. Similarly, the struct rtl_pci_capabilities_header is unused and no driver should come up their own way to access PCI Capabilities anyway. Remove the unused/duplicated PCI related defines and struct. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-10-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/pci.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index ba25bc6d3acb..7556f3975fe6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -44,18 +44,6 @@ #define ATI_DEVICE_ID 0x7914 #define AMD_VENDOR_ID 0x1022 -#define PCI_MAX_BRIDGE_NUMBER 255 -#define PCI_MAX_DEVICES 32 -#define PCI_MAX_FUNCTION 8 - -#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */ -#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */ - -#define PCI_CLASS_BRIDGE_DEV 0x06 -#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 -#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 -#define PCI_CAP_ID_EXP 0x10 - #define U1DONTCARE 0xFF #define U2DONTCARE 0xFFFF #define U4DONTCARE 0xFFFFFFFF @@ -113,11 +101,6 @@ enum pci_bridge_vendor { PCI_BRIDGE_VENDOR_MAX, }; -struct rtl_pci_capabilities_header { - u8 capability_id; - u8 next; -}; - /* In new TRX flow, Buffer_desc is new concept * But TX wifi info == TX descriptor in old flow * RX wifi info == RX descriptor in old flow From 874a0eda000dbdf2f6c6aa52c0f617333aaf3e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Nov 2023 10:47:25 +0200 Subject: [PATCH 2114/7721] wifi: rtlwifi: Remove bridge vendor/device ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither vendorid nor deviceid in the struct mp_adapter is used so remove them. Signed-off-by: Ilpo Järvinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231124084725.12738-11-ilpo.jarvinen@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 1 - drivers/net/wireless/realtek/rtlwifi/pci.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index bc41e865bac1..96ce05bcf0b3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1968,7 +1968,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, */ if (bridge_pdev) { /*find bridge info if available */ - pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { pcipriv->ndis_adapter.pcibridge_vendor = tmp; diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index 7556f3975fe6..e8fa022df8b4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -215,8 +215,6 @@ struct mp_adapter { u8 pcibridge_funcnum; u8 pcibridge_vendor; - u16 pcibridge_vendorid; - u16 pcibridge_deviceid; bool amd_l1_patch; }; From 9ba0ff3e083f6a4a0b6698f06bfff74805fefa5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:36 -0300 Subject: [PATCH 2115/7721] drm/v3d: Create a CPU job extension for the timestamp query job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. A timestamp query job is a job that calculates the query timestamp and updates the query availability by signaling a syncobj. As V3D doesn't provide any mechanism to obtain a timestamp from the GPU, it is a job that needs CPU intervention. So, create a user extension for the CPU job that enables the creation of a timestamp query job. This user extension will allow the creation of a CPU job that performs the timestamp query calculation and updates the timestamp BO with the proper value. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-15-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 17 +++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 40 +++++++++++++++++++- drivers/gpu/drm/v3d/v3d_submit.c | 63 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 30 +++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 202c0d4b04a5..dd86e745c260 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -318,6 +318,15 @@ struct v3d_csd_job { enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_INDIRECT_CSD = 1, + V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY, +}; + +struct v3d_timestamp_query { + /* Offset of this query in the timestamp BO for its value. */ + u32 offset; + + /* Syncobj that indicates the timestamp availability */ + struct drm_syncobj *syncobj; }; struct v3d_indirect_csd_info { @@ -345,12 +354,20 @@ struct v3d_indirect_csd_info { struct ww_acquire_ctx acquire_ctx; }; +struct v3d_timestamp_query_info { + struct v3d_timestamp_query *queries; + + u32 count; +}; + struct v3d_cpu_job { struct v3d_job base; enum v3d_cpu_job_type job_type; struct v3d_indirect_csd_info indirect_csd; + + struct v3d_timestamp_query_info timestamp_query; }; typedef void (*v3d_cpu_job_fn)(struct v3d_cpu_job *); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 307257ab0e4a..5e692f087105 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -21,6 +21,8 @@ #include #include +#include + #include "v3d_drv.h" #include "v3d_regs.h" #include "v3d_trace.h" @@ -71,6 +73,21 @@ v3d_sched_job_free(struct drm_sched_job *sched_job) v3d_job_cleanup(job); } +static void +v3d_cpu_job_free(struct drm_sched_job *sched_job) +{ + struct v3d_cpu_job *job = to_cpu_job(sched_job); + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + + if (timestamp_query->queries) { + for (int i = 0; i < timestamp_query->count; i++) + drm_syncobj_put(timestamp_query->queries[i].syncobj); + kvfree(timestamp_query->queries); + } + + v3d_job_cleanup(&job->base); +} + static void v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) { @@ -305,8 +322,29 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job) v3d_put_bo_vaddr(bo); } +static void +v3d_timestamp_query(struct v3d_cpu_job *job) +{ + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + u8 *value_addr; + + v3d_get_bo_vaddr(bo); + + for (int i = 0; i < timestamp_query->count; i++) { + value_addr = ((u8 *)bo->vaddr) + timestamp_query->queries[i].offset; + *((u64 *)value_addr) = i == 0 ? ktime_get_ns() : 0ull; + + drm_syncobj_replace_fence(timestamp_query->queries[i].syncobj, + job->base.done_fence); + } + + v3d_put_bo_vaddr(bo); +} + static const v3d_cpu_job_fn cpu_job_function[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, + [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, }; static struct dma_fence * @@ -504,7 +542,7 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { .run_job = v3d_cpu_job_run, .timedout_job = v3d_generic_job_timedout, - .free_job = v3d_sched_job_free + .free_job = v3d_cpu_job_free }; int diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 0320695b941b..83e029e786ea 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -433,6 +433,64 @@ v3d_get_cpu_indirect_csd_params(struct drm_file *file_priv, NULL, &info->acquire_ctx); } +/* Get data for the query timestamp job submission. */ +static int +v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *offsets, *syncs; + struct drm_v3d_timestamp_query timestamp; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(×tamp, ext, sizeof(timestamp))) + return -EFAULT; + + if (timestamp.pad) + return -EINVAL; + + job->job_type = V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY; + + job->timestamp_query.queries = kvmalloc_array(timestamp.count, + sizeof(struct v3d_timestamp_query), + GFP_KERNEL); + if (!job->timestamp_query.queries) + return -ENOMEM; + + offsets = u64_to_user_ptr(timestamp.offsets); + syncs = u64_to_user_ptr(timestamp.syncs); + + for (int i = 0; i < timestamp.count; i++) { + u32 offset, sync; + + if (copy_from_user(&offset, offsets++, sizeof(offset))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].offset = offset; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + } + job->timestamp_query.count = timestamp.count; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -461,6 +519,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_INDIRECT_CSD: ret = v3d_get_cpu_indirect_csd_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY: + ret = v3d_get_cpu_timestamp_query_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -837,6 +898,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, static const unsigned int cpu_job_bo_handle_count[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = 1, + [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = 1, }; /** @@ -974,6 +1036,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, v3d_job_cleanup((void *)csd_job); v3d_job_cleanup(clean_job); v3d_put_multisync_post_deps(&se); + kvfree(cpu_job->timestamp_query.queries); return ret; } diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 0c0f47782528..239801b5e117 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -73,6 +73,7 @@ struct drm_v3d_extension { __u32 id; #define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 +#define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 __u32 flags; /* mbz */ }; @@ -400,11 +401,40 @@ struct drm_v3d_indirect_csd { __u32 wg_uniform_offsets[3]; }; +/** + * struct drm_v3d_timestamp_query - ioctl extension for the CPU job to calculate + * a timestamp query + * + * When an extension DRM_V3D_EXT_ID_TIMESTAMP_QUERY is defined, it points to + * this extension to define a timestamp query submission. This CPU job will + * calculate the timestamp query and update the query value within the + * timestamp BO. Moreover, it will signal the timestamp syncobj to indicate + * query availability. + */ +struct drm_v3d_timestamp_query { + struct drm_v3d_extension base; + + /* Array of queries' offsets within the timestamp BO for their value */ + __u64 offsets; + + /* Array of timestamp's syncobjs to indicate its availability */ + __u64 syncs; + + /* Number of queries */ + __u32 count; + + /* mbz */ + __u32 pad; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. * * For DRM_V3D_EXT_ID_CPU_INDIRECT_CSD, it must contain only one BO, * that contains the workgroup counts. + * + * For DRM_V3D_EXT_ID_TIMESTAMP_QUERY, it must contain only one BO, + * that will contain the timestamp. */ __u64 bo_handles; From 62ad3b976cd7f1cc75458c7df34afb4349ae2429 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 26 Nov 2023 20:53:58 +0100 Subject: [PATCH 2116/7721] wifi: rt2x00: make watchdog param per device We can run PCI/MMIO devices together with USB devices in the system. Make watchdog parameter per device to avoid situation when plugin USB device change modparam_watchdog for PCI/MMIO device. Signed-off-by: Stanislaw Gruszka Tested-by: Shiji Yang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231126195358.500259-1-stf_xl@wp.pl --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 11 +++++------ drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 485096e3be94..aaf31857ae1e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1353,10 +1353,10 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) return; - if (modparam_watchdog & RT2800_WATCHDOG_DMA_BUSY) + if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_DMA_BUSY) reset = rt2800_watchdog_dma_busy(rt2x00dev); - if (modparam_watchdog & RT2800_WATCHDOG_HANG) + if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_HANG) reset = rt2800_watchdog_hung(rt2x00dev) || reset; if (reset) @@ -12065,14 +12065,13 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); } + rt2x00dev->link.watchdog = modparam_watchdog; /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */ if (rt2x00_is_usb(rt2x00dev)) - modparam_watchdog &= ~RT2800_WATCHDOG_DMA_BUSY; - if (modparam_watchdog) { + rt2x00dev->link.watchdog &= ~RT2800_WATCHDOG_DMA_BUSY; + if (rt2x00dev->link.watchdog) { __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags); rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100); - } else { - rt2x00dev->link.watchdog_disabled = true; } /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 62fed38f41c0..82af01448a0a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -334,7 +334,7 @@ struct link { */ struct delayed_work watchdog_work; unsigned int watchdog_interval; - bool watchdog_disabled; + unsigned int watchdog; /* * Work structure for scheduling periodic AGC adjustments. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c index 6cf7e7c997c2..fb23d409fba8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c @@ -384,7 +384,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) struct link *link = &rt2x00dev->link; if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled) + rt2x00dev->ops->lib->watchdog && link->watchdog) ieee80211_queue_delayed_work(rt2x00dev->hw, &link->watchdog_work, link->watchdog_interval); From 34a101e64296c736b14ce27e647fcebd70cb7bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:37 -0300 Subject: [PATCH 2117/7721] drm/v3d: Create a CPU job extension for the reset timestamp job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. A reset timestamp job is a job that resets the timestamp queries based on the value offset of the first query. As V3D doesn't provide any mechanism to obtain a timestamp from the GPU, it is a job that needs CPU intervention. So, create a user extension for the CPU job that enables the creation of a reset timestamp job. This user extension will allow the creation of a CPU job that resets the timestamp value in the timestamp BO and resets the availability syncobj. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-16-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 1 + drivers/gpu/drm/v3d/v3d_sched.c | 21 +++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 52 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 27 +++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index dd86e745c260..3988407635ed 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -319,6 +319,7 @@ struct v3d_csd_job { enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_INDIRECT_CSD = 1, V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY, + V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY, }; struct v3d_timestamp_query { diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 5e692f087105..e287f42d3621 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -342,9 +342,30 @@ v3d_timestamp_query(struct v3d_cpu_job *job) v3d_put_bo_vaddr(bo); } +static void +v3d_reset_timestamp_queries(struct v3d_cpu_job *job) +{ + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + struct v3d_timestamp_query *queries = timestamp_query->queries; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + u8 *value_addr; + + v3d_get_bo_vaddr(bo); + + for (int i = 0; i < timestamp_query->count; i++) { + value_addr = ((u8 *)bo->vaddr) + queries[i].offset; + *((u64 *)value_addr) = 0; + + drm_syncobj_replace_fence(queries[i].syncobj, NULL); + } + + v3d_put_bo_vaddr(bo); +} + static const v3d_cpu_job_fn cpu_job_function[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, + [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = v3d_reset_timestamp_queries, }; static struct dma_fence * diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 83e029e786ea..1c719416e26a 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -491,6 +491,54 @@ v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv, return 0; } +static int +v3d_get_cpu_reset_timestamp_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *syncs; + struct drm_v3d_reset_timestamp_query reset; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(&reset, ext, sizeof(reset))) + return -EFAULT; + + job->job_type = V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY; + + job->timestamp_query.queries = kvmalloc_array(reset.count, + sizeof(struct v3d_timestamp_query), + GFP_KERNEL); + if (!job->timestamp_query.queries) + return -ENOMEM; + + syncs = u64_to_user_ptr(reset.syncs); + + for (int i = 0; i < reset.count; i++) { + u32 sync; + + job->timestamp_query.queries[i].offset = reset.offset + 8 * i; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + } + job->timestamp_query.count = reset.count; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -522,6 +570,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY: ret = v3d_get_cpu_timestamp_query_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY: + ret = v3d_get_cpu_reset_timestamp_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -899,6 +950,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, static const unsigned int cpu_job_bo_handle_count[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = 1, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = 1, + [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = 1, }; /** diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 239801b5e117..930f8d07f088 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -74,6 +74,7 @@ struct drm_v3d_extension { #define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 #define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 +#define DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY 0x04 __u32 flags; /* mbz */ }; @@ -427,6 +428,29 @@ struct drm_v3d_timestamp_query { __u32 pad; }; +/** + * struct drm_v3d_reset_timestamp_query - ioctl extension for the CPU job to + * reset timestamp queries + * + * When an extension DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY is defined, it + * points to this extension to define a reset timestamp submission. This CPU + * job will reset the timestamp queries based on value offset of the first + * query. Moreover, it will reset the timestamp syncobj to reset query + * availability. + */ +struct drm_v3d_reset_timestamp_query { + struct drm_v3d_extension base; + + /* Array of timestamp's syncobjs to indicate its availability */ + __u64 syncs; + + /* Offset of the first query within the timestamp BO for its value */ + __u32 offset; + + /* Number of queries */ + __u32 count; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. * @@ -435,6 +459,9 @@ struct drm_v3d_submit_cpu { * * For DRM_V3D_EXT_ID_TIMESTAMP_QUERY, it must contain only one BO, * that will contain the timestamp. + * + * For DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY, it must contain only + * one BO, that contains the timestamp. */ __u64 bo_handles; From 0052b3c401cdf39d3c3d12a0c3852175bc9a39c7 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Wed, 29 Nov 2023 15:00:43 +0800 Subject: [PATCH 2118/7721] wifi: rtw89: fix not entering PS mode after AP stops The attempt to enter power save mode might fail if there are still beacons pending in the queue. This sometimes happens after stopping P2P GO or AP mode. Extend stop AP function and flush all beacons to resolve this. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231129070046.18443-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 71 ++++++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/reg.h | 17 ++++++ 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index c3dac7a6c377..587113f6fc94 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -3869,6 +3869,50 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { R_AX_PORT_HGQ_WINDOW_CFG + 3}, }; +static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, u8 type) +{ + u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port); + u32 reg_info, reg_ctrl; + u32 val; + int ret; + + reg_info = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG_INFO, rtwvif->mac_idx); + reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG, rtwvif->mac_idx); + + rtw89_write32_mask(rtwdev, reg_ctrl, B_AX_PTCL_DBG_SEL_MASK, type); + rtw89_write32_set(rtwdev, reg_ctrl, B_AX_PTCL_DBG_EN); + fsleep(100); + + ret = read_poll_timeout(rtw89_read32_mask, val, val == 0, 1000, 100000, + true, rtwdev, reg_info, mask); + if (ret) + rtw89_warn(rtwdev, "Polling beacon packet empty fail\n"); +} + +static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; + + rtw89_write32_set(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); + rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, 1); + rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, 0); + rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 0); + rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, 2); + rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK, 1); + rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, 1); + rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); + + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM0); + if (rtwvif->port == RTW89_PORT_0) + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM1); + + rtw89_write32_clr(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); + rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); + fsleep(2); +} + #define BCN_INTERVAL 100 #define BCN_ERLY_DEF 160 #define BCN_SETUP_DEF 2 @@ -3884,21 +3928,36 @@ static void rtw89_mac_port_cfg_func_sw(struct rtw89_dev *rtwdev, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + const struct rtw89_chip_info *chip = rtwdev->chip; + bool need_backup = false; + u32 backup_val; if (!rtw89_read32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN)) return; - rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1); - rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK); - rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK); + if (chip->chip_id == RTL8852A && rtwvif->port != RTW89_PORT_0) { + need_backup = true; + backup_val = rtw89_read32_port(rtwdev, rtwvif, p->tbtt_prohib); + } + + if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_bcn_drop(rtwdev, rtwvif); + + if (chip->chip_id == RTL8852A) { + rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK); + rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1); + rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK); + rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK); + } msleep(vif->bss_conf.beacon_int + 1); - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN | B_AX_BRK_SETUP); rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSFTR_RST); rtw89_write32_port(rtwdev, rtwvif, p->bcn_cnt_tmr, 0); + + if (need_backup) + rtw89_write32_port(rtwdev, rtwvif, p->tbtt_prohib, backup_val); } static void rtw89_mac_port_cfg_tx_rpt(struct rtw89_dev *rtwdev, @@ -4383,7 +4442,7 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, false); + rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif); } int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 268c537394d4..1bd91c62678d 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -2376,6 +2376,14 @@ #define R_AX_TSFTR_HIGH_P4 0xC53C #define B_AX_TSFTR_HIGH_MASK GENMASK(31, 0) +#define R_AX_BCN_DROP_ALL0 0xC560 +#define R_AX_BCN_DROP_ALL0_C1 0xE560 +#define B_AX_BCN_DROP_ALL_P4 BIT(4) +#define B_AX_BCN_DROP_ALL_P3 BIT(3) +#define B_AX_BCN_DROP_ALL_P2 BIT(2) +#define B_AX_BCN_DROP_ALL_P1 BIT(1) +#define B_AX_BCN_DROP_ALL_P0 BIT(0) + #define R_AX_MBSSID_CTRL 0xC568 #define R_AX_MBSSID_CTRL_C1 0xE568 #define B_AX_P0MB_ALL_MASK GENMASK(23, 1) @@ -2555,11 +2563,20 @@ #define R_AX_PTCL_DBG_INFO 0xC6F0 #define R_AX_PTCL_DBG_INFO_C1 0xE6F0 +#define B_AX_PTCL_DBG_INFO_MASK_BY_PORT(port) \ +({\ + typeof(port) _port = (port); \ + GENMASK((_port) * 2 + 1, (_port) * 2); \ +}) + #define B_AX_PTCL_DBG_INFO_MASK GENMASK(31, 0) #define R_AX_PTCL_DBG 0xC6F4 #define R_AX_PTCL_DBG_C1 0xE6F4 #define B_AX_PTCL_DBG_EN BIT(8) #define B_AX_PTCL_DBG_SEL_MASK GENMASK(7, 0) +#define AX_PTCL_DBG_BCNQ_NUM0 8 +#define AX_PTCL_DBG_BCNQ_NUM1 9 + #define R_AX_DLE_CTRL 0xC800 #define R_AX_DLE_CTRL_C1 0xE800 From 2f3eaccc662122704f70bfef1d02a78239033b85 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Wed, 29 Nov 2023 15:00:44 +0800 Subject: [PATCH 2119/7721] wifi: rtw89: Refine active scan behavior in 6 GHz The interval between sending each probe request is regulated. Before this patch, some packets are not sent out properly because of our HW limit. Extend the 6 GHz channel dwell time to cope with this. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231129070046.18443-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index a732c22a2d54..898b3f432d1c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3867,6 +3867,8 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, if (info->channel_6ghz && ch_info->pri_ch != info->channel_6ghz) continue; + else if (info->channel_6ghz && probe_count != 0) + ch_info->period += RTW89_CHANNEL_TIME_6G; ch_info->pkt_id[probe_count++] = info->id; if (probe_count >= RTW89_SCANOFLD_MAX_SSID) break; From e46987ce819d9c531b3389d487ae135fc54da494 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Wed, 29 Nov 2023 15:00:45 +0800 Subject: [PATCH 2120/7721] wifi: rtw89: refine remain on channel flow to improve P2P connection We add a scanning check to avoid entering IPS after ROC (remain on channel) during scanning. Additionally, When P2P scanning, the flow is `1. p2p_listen step` and `2. configure filter` and `3. p2p_scan starts` in wpas, but in kernel, cfg80211 uses another workqueue to notify driver the filter change, so sometimes we see (1 > 3 > 2), that will cause Rx filter related to scan to be cleared. Therefore, we add a scanning check when configure filter to avoid scan results to be filtered. Finally, we cancel the ROC delayed workqueue before entering ROC to avoid entering twice, which might cause leaving ROC too early. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231129070046.18443-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 +++--- drivers/net/wireless/realtek/rtw89/mac80211.c | 18 ++++++++++++++++-- drivers/net/wireless/realtek/rtw89/ps.h | 4 ++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 7eb827ddc53a..d5ee2aa053d4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2883,9 +2883,6 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) lockdep_assert_held(&rtwdev->mutex); - ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work, - msecs_to_jiffies(rtwvif->roc.duration)); - rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC); @@ -2907,6 +2904,9 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); ieee80211_ready_on_channel(hw); + cancel_delayed_work(&rtwvif->roc.roc_work); + ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work, + msecs_to_jiffies(rtwvif->roc.duration)); } void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 31d1f7891675..5c3a3d9c272a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -226,6 +226,7 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + u32 rx_fltr; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); @@ -272,16 +273,29 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, } } + rx_fltr = rtwdev->hal.rx_fltr; + + /* mac80211 doesn't configure filter when HW scan, driver need to + * set by itself. However, during P2P scan might have configure + * filter to overwrite filter that HW scan needed, so we need to + * check scan and append related filter + */ + if (rtwdev->scanning) { + rx_fltr &= ~B_AX_A_BCN_CHK_EN; + rx_fltr &= ~B_AX_A_BC; + rx_fltr &= ~B_AX_A_A1_MATCH; + } + rtw89_write32_mask(rtwdev, rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rx_fltr); if (!rtwdev->dbcc_en) goto out; rtw89_write32_mask(rtwdev, rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1), B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rx_fltr); out: mutex_unlock(&rtwdev->mutex); diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index aff0fba71cb0..54486e4550b6 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -33,6 +33,10 @@ static inline void rtw89_enter_ips_by_hwflags(struct rtw89_dev *rtwdev) { struct ieee80211_hw *hw = rtwdev->hw; + /* prevent entering IPS after ROC, but it is scanning */ + if (rtwdev->scanning) + return; + if (hw->conf.flags & IEEE80211_CONF_IDLE) rtw89_enter_ips(rtwdev); } From 756b31203d482d2dd1aa6c208978b0410dc7530f Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Wed, 29 Nov 2023 15:00:46 +0800 Subject: [PATCH 2121/7721] wifi: rtw89: fix misbehavior of TX beacon in concurrent mode In concurrent mode, when STA interface is scanning, it causes AP interface TX beacon on wrong channel. We modified it to scan with the operating channel when one of the interfaces is already connected. Additionally, STA interface need to stop scan when AP interface is starting to avoid TX beacon on wrong channel. Finally, AP interface need to stop TX beacon when STA interface is scanning and switching to non-OP channel,This prevent other device to get beacons on wrong channel. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231129070046.18443-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 17 +++++++++-- drivers/net/wireless/realtek/rtw89/mac.c | 29 +++++++++++++++---- drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac80211.c | 3 ++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 898b3f432d1c..b11ed35e265d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4045,6 +4045,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_core_scan_complete(rtwdev, vif, true); ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_wake_queues(rtwdev->hw); + rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); rtw89_release_pkt_list(rtwdev); rtwvif = (struct rtw89_vif *)vif->drv_priv; @@ -4062,6 +4063,19 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) rtw89_hw_scan_complete(rtwdev, vif, true); } +static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) +{ + struct rtw89_vif *rtwvif; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + /* This variable implies connected or during attempt to connect */ + if (!is_zero_ether_addr(rtwvif->bssid)) + return true; + } + + return false; +} + int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, bool enable) { @@ -4074,8 +4088,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, if (!rtwvif) return -EINVAL; - /* This variable implies connected or during attempt to connect */ - connected = !is_zero_ether_addr(rtwvif->bssid); + connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); opt.enable = enable; opt.target_ch_mode = connected; if (enable) { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 587113f6fc94..d4812b25c86c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4038,12 +4038,10 @@ static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, } static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif *rtwvif, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; if (en) rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); @@ -4051,6 +4049,24 @@ static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); } +static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || + rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); +} + +void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) +{ + struct rtw89_vif *rtwvif; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); +} + static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { @@ -4357,7 +4373,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif); rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif); rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif); - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif); + rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif); rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif); rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif); rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif); @@ -4519,8 +4535,10 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, switch (reason) { case RTW89_SCAN_LEAVE_CH_NOTIFY: - if (rtw89_is_op_chan(rtwdev, band, chan)) + if (rtw89_is_op_chan(rtwdev, band, chan)) { + rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, false); ieee80211_stop_queues(rtwdev->hw); + } return; case RTW89_SCAN_END_SCAN_NOTIFY: if (rtwvif && rtwvif->scan_req && @@ -4538,6 +4556,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, if (rtw89_is_op_chan(rtwdev, band, chan)) { rtw89_assign_entity_chan(rtwdev, rtwvif->sub_entity_idx, &rtwdev->scan_info.op_chan); + rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); ieee80211_wake_queues(rtwdev->hw); } else { rtw89_chan_create(&new, chan, chan, band, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index c6b2072f94c3..b63c506e8de1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1054,6 +1054,7 @@ int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en); int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev); int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 5c3a3d9c272a..93889d2fface 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -491,6 +491,9 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, return -EOPNOTSUPP; } + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); rtw89_mac_port_update(rtwdev, rtwvif); From 6745f3e44a20ac18e7e5a40a3c7f62225983d544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:38 -0300 Subject: [PATCH 2122/7721] drm/v3d: Create a CPU job extension to copy timestamp query to a buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. A copy timestamp query job is a job that copy the complete or partial result of a query to a buffer. As V3D doesn't provide any mechanism to obtain a timestamp from the GPU, it is a job that needs CPU intervention. So, create a user extension for the CPU job that enables the creation of a copy timestamp query job. This user extension will allow the creation of a CPU job that copy the results of a timestamp query to a BO with the possibility to indicate the timestamp availability with a availability bit. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-17-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 20 +++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 56 ++++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 69 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 45 +++++++++++++++++++++ 4 files changed, 190 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 3988407635ed..5058a354fffd 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -320,6 +320,7 @@ enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_INDIRECT_CSD = 1, V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY, V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY, + V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY, }; struct v3d_timestamp_query { @@ -361,6 +362,23 @@ struct v3d_timestamp_query_info { u32 count; }; +struct v3d_copy_query_results_info { + /* Define if should write to buffer using 64 or 32 bits */ + bool do_64bit; + + /* Define if it can write to buffer even if the query is not available */ + bool do_partial; + + /* Define if it should write availability bit to buffer */ + bool availability_bit; + + /* Offset of the copy buffer in the BO */ + u32 offset; + + /* Stride of the copy buffer in the BO */ + u32 stride; +}; + struct v3d_cpu_job { struct v3d_job base; @@ -369,6 +387,8 @@ struct v3d_cpu_job { struct v3d_indirect_csd_info indirect_csd; struct v3d_timestamp_query_info timestamp_query; + + struct v3d_copy_query_results_info copy; }; typedef void (*v3d_cpu_job_fn)(struct v3d_cpu_job *); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index e287f42d3621..b1662d32a929 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -362,10 +362,66 @@ v3d_reset_timestamp_queries(struct v3d_cpu_job *job) v3d_put_bo_vaddr(bo); } +static void +write_to_buffer(void *dst, u32 idx, bool do_64bit, u64 value) +{ + if (do_64bit) { + u64 *dst64 = (u64 *)dst; + + dst64[idx] = value; + } else { + u32 *dst32 = (u32 *)dst; + + dst32[idx] = (u32)value; + } +} + +static void +v3d_copy_query_results(struct v3d_cpu_job *job) +{ + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + struct v3d_timestamp_query *queries = timestamp_query->queries; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + struct v3d_bo *timestamp = to_v3d_bo(job->base.bo[1]); + struct v3d_copy_query_results_info *copy = &job->copy; + struct dma_fence *fence; + u8 *query_addr; + bool available, write_result; + u8 *data; + int i; + + v3d_get_bo_vaddr(bo); + v3d_get_bo_vaddr(timestamp); + + data = ((u8 *)bo->vaddr) + copy->offset; + + for (i = 0; i < timestamp_query->count; i++) { + fence = drm_syncobj_fence_get(queries[i].syncobj); + available = fence ? dma_fence_is_signaled(fence) : false; + + write_result = available || copy->do_partial; + if (write_result) { + query_addr = ((u8 *)timestamp->vaddr) + queries[i].offset; + write_to_buffer(data, 0, copy->do_64bit, *((u64 *)query_addr)); + } + + if (copy->availability_bit) + write_to_buffer(data, 1, copy->do_64bit, available ? 1u : 0u); + + data += copy->stride; + + dma_fence_put(fence); + } + + v3d_put_bo_vaddr(timestamp); + v3d_put_bo_vaddr(bo); +} + static const v3d_cpu_job_fn cpu_job_function[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = v3d_reset_timestamp_queries, + [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = v3d_copy_query_results, }; static struct dma_fence * diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 1c719416e26a..bafd49c6440c 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -539,6 +539,71 @@ v3d_get_cpu_reset_timestamp_params(struct drm_file *file_priv, return 0; } +/* Get data for the copy timestamp query results job submission. */ +static int +v3d_get_cpu_copy_query_results_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *offsets, *syncs; + struct drm_v3d_copy_timestamp_query copy; + int i; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(©, ext, sizeof(copy))) + return -EFAULT; + + if (copy.pad) + return -EINVAL; + + job->job_type = V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY; + + job->timestamp_query.queries = kvmalloc_array(copy.count, + sizeof(struct v3d_timestamp_query), + GFP_KERNEL); + if (!job->timestamp_query.queries) + return -ENOMEM; + + offsets = u64_to_user_ptr(copy.offsets); + syncs = u64_to_user_ptr(copy.syncs); + + for (i = 0; i < copy.count; i++) { + u32 offset, sync; + + if (copy_from_user(&offset, offsets++, sizeof(offset))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].offset = offset; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + } + job->timestamp_query.count = copy.count; + + job->copy.do_64bit = copy.do_64bit; + job->copy.do_partial = copy.do_partial; + job->copy.availability_bit = copy.availability_bit; + job->copy.offset = copy.offset; + job->copy.stride = copy.stride; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -573,6 +638,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY: ret = v3d_get_cpu_reset_timestamp_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY: + ret = v3d_get_cpu_copy_query_results_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -951,6 +1019,7 @@ static const unsigned int cpu_job_bo_handle_count[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = 1, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = 1, [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = 1, + [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = 2, }; /** diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 930f8d07f088..f7defbf3d043 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -75,6 +75,7 @@ struct drm_v3d_extension { #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 #define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 #define DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY 0x04 +#define DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY 0x05 __u32 flags; /* mbz */ }; @@ -451,6 +452,46 @@ struct drm_v3d_reset_timestamp_query { __u32 count; }; +/** + * struct drm_v3d_copy_timestamp_query - ioctl extension for the CPU job to copy + * query results to a buffer + * + * When an extension DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY is defined, it + * points to this extension to define a copy timestamp query submission. This + * CPU job will copy the timestamp queries results to a BO with the offset + * and stride defined in the extension. + */ +struct drm_v3d_copy_timestamp_query { + struct drm_v3d_extension base; + + /* Define if should write to buffer using 64 or 32 bits */ + __u8 do_64bit; + + /* Define if it can write to buffer even if the query is not available */ + __u8 do_partial; + + /* Define if it should write availability bit to buffer */ + __u8 availability_bit; + + /* mbz */ + __u8 pad; + + /* Offset of the buffer in the BO */ + __u32 offset; + + /* Stride of the buffer in the BO */ + __u32 stride; + + /* Number of queries */ + __u32 count; + + /* Array of queries' offsets within the timestamp BO for their value */ + __u64 offsets; + + /* Array of timestamp's syncobjs to indicate its availability */ + __u64 syncs; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. * @@ -462,6 +503,10 @@ struct drm_v3d_submit_cpu { * * For DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY, it must contain only * one BO, that contains the timestamp. + * + * For DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY, it must contain two + * BOs. The first is the BO where the timestamp queries will be written + * to. The second is the BO that contains the timestamp. */ __u64 bo_handles; From bae7cb5d68001a8d4ceec5964dda74bb9aab7220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:39 -0300 Subject: [PATCH 2123/7721] drm/v3d: Create a CPU job extension for the reset performance query job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. A reset performance query job is a job that resets the performance queries by resetting the values of the perfmons. Moreover, we also reset the syncobjs related to the availability of the query. So, create a user extension for the CPU job that enables the creation of a reset performance job. This user extension will allow the creation of a CPU job that resets the perfmons values and resets the availability syncobj. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-18-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 28 ++++++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 36 ++++++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 73 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 30 +++++++++++++ 4 files changed, 167 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 5058a354fffd..0f7f80ad8d88 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -321,6 +321,7 @@ enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY, V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY, V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY, + V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY, }; struct v3d_timestamp_query { @@ -331,6 +332,18 @@ struct v3d_timestamp_query { struct drm_syncobj *syncobj; }; +/* Number of perfmons required to handle all supported performance counters */ +#define V3D_MAX_PERFMONS DIV_ROUND_UP(V3D_PERFCNT_NUM, \ + DRM_V3D_MAX_PERF_COUNTERS) + +struct v3d_performance_query { + /* Performance monitor IDs for this query */ + u32 kperfmon_ids[V3D_MAX_PERFMONS]; + + /* Syncobj that indicates the query availability */ + struct drm_syncobj *syncobj; +}; + struct v3d_indirect_csd_info { /* Indirect CSD */ struct v3d_csd_job *job; @@ -362,6 +375,19 @@ struct v3d_timestamp_query_info { u32 count; }; +struct v3d_performance_query_info { + struct v3d_performance_query *queries; + + /* Number of performance queries */ + u32 count; + + /* Number of performance monitors related to that query pool */ + u32 nperfmons; + + /* Number of performance counters related to that query pool */ + u32 ncounters; +}; + struct v3d_copy_query_results_info { /* Define if should write to buffer using 64 or 32 bits */ bool do_64bit; @@ -389,6 +415,8 @@ struct v3d_cpu_job { struct v3d_timestamp_query_info timestamp_query; struct v3d_copy_query_results_info copy; + + struct v3d_performance_query_info performance_query; }; typedef void (*v3d_cpu_job_fn)(struct v3d_cpu_job *); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index b1662d32a929..e83d2907bc83 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -78,6 +78,7 @@ v3d_cpu_job_free(struct drm_sched_job *sched_job) { struct v3d_cpu_job *job = to_cpu_job(sched_job); struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + struct v3d_performance_query_info *performance_query = &job->performance_query; if (timestamp_query->queries) { for (int i = 0; i < timestamp_query->count; i++) @@ -85,6 +86,12 @@ v3d_cpu_job_free(struct drm_sched_job *sched_job) kvfree(timestamp_query->queries); } + if (performance_query->queries) { + for (int i = 0; i < performance_query->count; i++) + drm_syncobj_put(performance_query->queries[i].syncobj); + kvfree(performance_query->queries); + } + v3d_job_cleanup(&job->base); } @@ -417,11 +424,40 @@ v3d_copy_query_results(struct v3d_cpu_job *job) v3d_put_bo_vaddr(bo); } +static void +v3d_reset_performance_queries(struct v3d_cpu_job *job) +{ + struct v3d_performance_query_info *performance_query = &job->performance_query; + struct v3d_file_priv *v3d_priv = job->base.file->driver_priv; + struct v3d_dev *v3d = job->base.v3d; + struct v3d_perfmon *perfmon; + + for (int i = 0; i < performance_query->count; i++) { + for (int j = 0; j < performance_query->nperfmons; j++) { + perfmon = v3d_perfmon_find(v3d_priv, + performance_query->queries[i].kperfmon_ids[j]); + if (!perfmon) { + DRM_DEBUG("Failed to find perfmon."); + continue; + } + + v3d_perfmon_stop(v3d, perfmon, false); + + memset(perfmon->values, 0, perfmon->ncounters * sizeof(u64)); + + v3d_perfmon_put(perfmon); + } + + drm_syncobj_replace_fence(performance_query->queries[i].syncobj, NULL); + } +} + static const v3d_cpu_job_fn cpu_job_function[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = v3d_reset_timestamp_queries, [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = v3d_copy_query_results, + [V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY] = v3d_reset_performance_queries, }; static struct dma_fence * diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index bafd49c6440c..20af8ae14831 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -604,6 +604,74 @@ v3d_get_cpu_copy_query_results_params(struct drm_file *file_priv, return 0; } +static int +v3d_get_cpu_reset_performance_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *syncs; + u64 __user *kperfmon_ids; + struct drm_v3d_reset_performance_query reset; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(&reset, ext, sizeof(reset))) + return -EFAULT; + + job->job_type = V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY; + + job->performance_query.queries = kvmalloc_array(reset.count, + sizeof(struct v3d_performance_query), + GFP_KERNEL); + if (!job->performance_query.queries) + return -ENOMEM; + + syncs = u64_to_user_ptr(reset.syncs); + kperfmon_ids = u64_to_user_ptr(reset.kperfmon_ids); + + for (int i = 0; i < reset.count; i++) { + u32 sync; + u64 ids; + u32 __user *ids_pointer; + u32 id; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + + if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + ids_pointer = u64_to_user_ptr(ids); + + for (int j = 0; j < reset.nperfmons; j++) { + if (copy_from_user(&id, ids_pointer++, sizeof(id))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + job->performance_query.queries[i].kperfmon_ids[j] = id; + } + } + job->performance_query.count = reset.count; + job->performance_query.nperfmons = reset.nperfmons; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -641,6 +709,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY: ret = v3d_get_cpu_copy_query_results_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY: + ret = v3d_get_cpu_reset_performance_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -1020,6 +1091,7 @@ static const unsigned int cpu_job_bo_handle_count[] = { [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = 1, [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = 1, [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = 2, + [V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY] = 0, }; /** @@ -1158,6 +1230,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, v3d_job_cleanup(clean_job); v3d_put_multisync_post_deps(&se); kvfree(cpu_job->timestamp_query.queries); + kvfree(cpu_job->performance_query.queries); return ret; } diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index f7defbf3d043..d609bdf29fd6 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -76,6 +76,7 @@ struct drm_v3d_extension { #define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 #define DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY 0x04 #define DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY 0x05 +#define DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY 0x06 __u32 flags; /* mbz */ }; @@ -492,6 +493,32 @@ struct drm_v3d_copy_timestamp_query { __u64 syncs; }; +/** + * struct drm_v3d_reset_performance_query - ioctl extension for the CPU job to + * reset performance queries + * + * When an extension DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY is defined, it + * points to this extension to define a reset performance submission. This CPU + * job will reset the performance queries by resetting the values of the + * performance monitors. Moreover, it will reset the syncobj to reset query + * availability. + */ +struct drm_v3d_reset_performance_query { + struct drm_v3d_extension base; + + /* Array of performance queries's syncobjs to indicate its availability */ + __u64 syncs; + + /* Number of queries */ + __u32 count; + + /* Number of performance monitors */ + __u32 nperfmons; + + /* Array of u64 user-pointers that point to an array of kperfmon_ids */ + __u64 kperfmon_ids; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. * @@ -507,6 +534,9 @@ struct drm_v3d_submit_cpu { * For DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY, it must contain two * BOs. The first is the BO where the timestamp queries will be written * to. The second is the BO that contains the timestamp. + * + * For DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY, it must contain no + * BOs. */ __u64 bo_handles; From 209e8d2695ee7a67a5b0487bbd1aa75e290d0f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 30 Nov 2023 13:40:40 -0300 Subject: [PATCH 2124/7721] drm/v3d: Create a CPU job extension for the copy performance query job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CPU job is a type of job that performs operations that requires CPU intervention. A copy performance query job is a job that copy the complete or partial result of a query to a buffer. In order to copy the result of a performance query to a buffer, we need to get the values from the performance monitors. So, create a user extension for the CPU job that enables the creation of a copy performance query job. This user extension will allow the creation of a CPU job that copy the results of a performance query to a BO with the possibility to indicate the availability with a availability bit. Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20231130164420.932823-19-mcanal@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 1 + drivers/gpu/drm/v3d/v3d_sched.c | 65 +++++++++++++++++++++++++ drivers/gpu/drm/v3d/v3d_submit.c | 82 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 50 +++++++++++++++++++ 4 files changed, 198 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 0f7f80ad8d88..3c7d58866570 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -322,6 +322,7 @@ enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY, V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY, V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY, + V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY, }; struct v3d_timestamp_query { diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index e83d2907bc83..54015ad765c7 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -452,12 +452,77 @@ v3d_reset_performance_queries(struct v3d_cpu_job *job) } } +static void +v3d_write_performance_query_result(struct v3d_cpu_job *job, void *data, u32 query) +{ + struct v3d_performance_query_info *performance_query = &job->performance_query; + struct v3d_copy_query_results_info *copy = &job->copy; + struct v3d_file_priv *v3d_priv = job->base.file->driver_priv; + struct v3d_dev *v3d = job->base.v3d; + struct v3d_perfmon *perfmon; + u64 counter_values[V3D_PERFCNT_NUM]; + + for (int i = 0; i < performance_query->nperfmons; i++) { + perfmon = v3d_perfmon_find(v3d_priv, + performance_query->queries[query].kperfmon_ids[i]); + if (!perfmon) { + DRM_DEBUG("Failed to find perfmon."); + continue; + } + + v3d_perfmon_stop(v3d, perfmon, true); + + memcpy(&counter_values[i * DRM_V3D_MAX_PERF_COUNTERS], perfmon->values, + perfmon->ncounters * sizeof(u64)); + + v3d_perfmon_put(perfmon); + } + + for (int i = 0; i < performance_query->ncounters; i++) + write_to_buffer(data, i, copy->do_64bit, counter_values[i]); +} + +static void +v3d_copy_performance_query(struct v3d_cpu_job *job) +{ + struct v3d_performance_query_info *performance_query = &job->performance_query; + struct v3d_copy_query_results_info *copy = &job->copy; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + struct dma_fence *fence; + bool available, write_result; + u8 *data; + + v3d_get_bo_vaddr(bo); + + data = ((u8 *)bo->vaddr) + copy->offset; + + for (int i = 0; i < performance_query->count; i++) { + fence = drm_syncobj_fence_get(performance_query->queries[i].syncobj); + available = fence ? dma_fence_is_signaled(fence) : false; + + write_result = available || copy->do_partial; + if (write_result) + v3d_write_performance_query_result(job, data, i); + + if (copy->availability_bit) + write_to_buffer(data, performance_query->ncounters, + copy->do_64bit, available ? 1u : 0u); + + data += copy->stride; + + dma_fence_put(fence); + } + + v3d_put_bo_vaddr(bo); +} + static const v3d_cpu_job_fn cpu_job_function[] = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = v3d_reset_timestamp_queries, [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = v3d_copy_query_results, [V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY] = v3d_reset_performance_queries, + [V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY] = v3d_copy_performance_query, }; static struct dma_fence * diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 20af8ae14831..d7a9da2484fd 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -672,6 +672,84 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv, return 0; } +static int +v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *syncs; + u64 __user *kperfmon_ids; + struct drm_v3d_copy_performance_query copy; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(©, ext, sizeof(copy))) + return -EFAULT; + + if (copy.pad) + return -EINVAL; + + job->job_type = V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY; + + job->performance_query.queries = kvmalloc_array(copy.count, + sizeof(struct v3d_performance_query), + GFP_KERNEL); + if (!job->performance_query.queries) + return -ENOMEM; + + syncs = u64_to_user_ptr(copy.syncs); + kperfmon_ids = u64_to_user_ptr(copy.kperfmon_ids); + + for (int i = 0; i < copy.count; i++) { + u32 sync; + u64 ids; + u32 __user *ids_pointer; + u32 id; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + + if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + ids_pointer = u64_to_user_ptr(ids); + + for (int j = 0; j < copy.nperfmons; j++) { + if (copy_from_user(&id, ids_pointer++, sizeof(id))) { + kvfree(job->performance_query.queries); + return -EFAULT; + } + + job->performance_query.queries[i].kperfmon_ids[j] = id; + } + } + job->performance_query.count = copy.count; + job->performance_query.nperfmons = copy.nperfmons; + job->performance_query.ncounters = copy.ncounters; + + job->copy.do_64bit = copy.do_64bit; + job->copy.do_partial = copy.do_partial; + job->copy.availability_bit = copy.availability_bit; + job->copy.offset = copy.offset; + job->copy.stride = copy.stride; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -712,6 +790,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY: ret = v3d_get_cpu_reset_performance_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_COPY_PERFORMANCE_QUERY: + ret = v3d_get_cpu_copy_performance_query_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -1092,6 +1173,7 @@ static const unsigned int cpu_job_bo_handle_count[] = { [V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY] = 1, [V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY] = 2, [V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY] = 0, + [V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY] = 1, }; /** diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index d609bdf29fd6..dce1835eced4 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -77,6 +77,7 @@ struct drm_v3d_extension { #define DRM_V3D_EXT_ID_CPU_RESET_TIMESTAMP_QUERY 0x04 #define DRM_V3D_EXT_ID_CPU_COPY_TIMESTAMP_QUERY 0x05 #define DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY 0x06 +#define DRM_V3D_EXT_ID_CPU_COPY_PERFORMANCE_QUERY 0x07 __u32 flags; /* mbz */ }; @@ -519,6 +520,52 @@ struct drm_v3d_reset_performance_query { __u64 kperfmon_ids; }; +/** + * struct drm_v3d_copy_performance_query - ioctl extension for the CPU job to copy + * performance query results to a buffer + * + * When an extension DRM_V3D_EXT_ID_CPU_COPY_PERFORMANCE_QUERY is defined, it + * points to this extension to define a copy performance query submission. This + * CPU job will copy the performance queries results to a BO with the offset + * and stride defined in the extension. + */ +struct drm_v3d_copy_performance_query { + struct drm_v3d_extension base; + + /* Define if should write to buffer using 64 or 32 bits */ + __u8 do_64bit; + + /* Define if it can write to buffer even if the query is not available */ + __u8 do_partial; + + /* Define if it should write availability bit to buffer */ + __u8 availability_bit; + + /* mbz */ + __u8 pad; + + /* Offset of the buffer in the BO */ + __u32 offset; + + /* Stride of the buffer in the BO */ + __u32 stride; + + /* Number of performance monitors */ + __u32 nperfmons; + + /* Number of performance counters related to this query pool */ + __u32 ncounters; + + /* Number of queries */ + __u32 count; + + /* Array of performance queries's syncobjs to indicate its availability */ + __u64 syncs; + + /* Array of u64 user-pointers that point to an array of kperfmon_ids */ + __u64 kperfmon_ids; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. * @@ -537,6 +584,9 @@ struct drm_v3d_submit_cpu { * * For DRM_V3D_EXT_ID_CPU_RESET_PERFORMANCE_QUERY, it must contain no * BOs. + * + * For DRM_V3D_EXT_ID_CPU_COPY_PERFORMANCE_QUERY, it must contain one + * BO, where the performance queries will be written. */ __u64 bo_handles; From ff3670877e7c73d06c2a835d9abb62efcae0145c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 6 Jul 2023 11:27:31 +0200 Subject: [PATCH 2125/7721] drm/imx/lcdc: Fix double-free of driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct imx_lcdc driver data is allocated using devm_drm_dev_alloc() so it must not be explicitly kfree()d. Also drm_kms_helper_poll_fini() should not be called as there is no matching drm_kms_helper_poll_init(). So drop the release function completely. Fixes: c87e859cdeb5 ("drm/imx/lcdc: Implement DRM driver for imx25") Signed-off-by: Uwe Kleine-König Reviewed-by: Philipp Zabel Signed-off-by: Philipp Zabel Link: https://patchwork.freedesktop.org/patch/msgid/20230706092731.2630232-1-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index 0902983374d0..43ddf3a9810b 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -342,21 +342,12 @@ static const struct drm_mode_config_helper_funcs imx_lcdc_mode_config_helpers = .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; -static void imx_lcdc_release(struct drm_device *drm) -{ - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(drm); - - drm_kms_helper_poll_fini(drm); - kfree(lcdc); -} - DEFINE_DRM_GEM_DMA_FOPS(imx_lcdc_drm_fops); static struct drm_driver imx_lcdc_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &imx_lcdc_drm_fops, DRM_GEM_DMA_DRIVER_OPS_VMAP, - .release = imx_lcdc_release, .name = "imx-lcdc", .desc = "i.MX LCDC driver", .date = "20200716", From b6a3451e0847d5d70fb5fa2b2a80ab9f80bf2c7b Mon Sep 17 00:00:00 2001 From: Jeroen van Ingen Schenau Date: Thu, 30 Nov 2023 13:03:53 +0100 Subject: [PATCH 2126/7721] selftests/bpf: Fix erroneous bitmask operation xdp_synproxy_kern.c is a BPF program that generates SYN cookies on allowed TCP ports and sends SYNACKs to clients, accelerating synproxy iptables module. Fix the bitmask operation when checking the status of an existing conntrack entry within tcp_lookup() function. Do not AND with the bit position number, but with the bitmask value to check whether the entry found has the IPS_CONFIRMED flag set. Fixes: fb5cd0ce70d4 ("selftests/bpf: Add selftests for raw syncookie helpers") Signed-off-by: Jeroen van Ingen Schenau Signed-off-by: Daniel Borkmann Tested-by: Minh Le Hoang Link: https://lore.kernel.org/xdp-newbies/CAAi1gX7owA+Tcxq-titC-h-KPM7Ri-6ZhTNMhrnPq5gmYYwKow@mail.gmail.com/T/#u Link: https://lore.kernel.org/bpf/20231130120353.3084-1-jeroen.vaningenschenau@novoserve.com --- tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c index 80f620602d50..518329c666e9 100644 --- a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c +++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c @@ -467,13 +467,13 @@ static __always_inline int tcp_lookup(void *ctx, struct header_pointers *hdr, bo unsigned long status = ct->status; bpf_ct_release(ct); - if (status & IPS_CONFIRMED_BIT) + if (status & IPS_CONFIRMED) return XDP_PASS; } else if (ct_lookup_opts.error != -ENOENT) { return XDP_ABORTED; } - /* error == -ENOENT || !(status & IPS_CONFIRMED_BIT) */ + /* error == -ENOENT || !(status & IPS_CONFIRMED) */ return XDP_TX; } From 80d20fd99124800749d605c733911a8d9da78e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 15 Nov 2023 11:07:18 +0200 Subject: [PATCH 2127/7721] drm/i915/display: split i915 specific code from intel_fbdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out code from intel_fbdev that can not be share between i915 and xe. Create new i915 specific source/header file intel_fbdev_fb.[ch] which contains this code. Signed-off-by: Jouni Högander Reviewed-by: Vinod Govindapillai Link: https://patchwork.freedesktop.org/patch/msgid/20231115090719.3210079-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/intel_fbdev.c | 108 ++-------------- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 115 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 21 ++++ 4 files changed, 146 insertions(+), 101 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_fbdev_fb.c create mode 100644 drivers/gpu/drm/i915/display/intel_fbdev_fb.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 65e984242089..eadc9e612962 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -318,7 +318,8 @@ i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o i915-$(CONFIG_DRM_FBDEV_EMULATION) += \ - display/intel_fbdev.o + display/intel_fbdev.o \ + display/intel_fbdev_fb.o i915-$(CONFIG_DEBUG_FS) += \ display/intel_display_debugfs.o \ display/intel_display_debugfs_params.o \ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 31d0d695d567..b7e4b7830e45 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -43,7 +43,6 @@ #include #include -#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_mman.h" #include "i915_drv.h" @@ -51,6 +50,7 @@ #include "intel_fb.h" #include "intel_fb_pin.h" #include "intel_fbdev.h" +#include "intel_fbdev_fb.h" #include "intel_frontbuffer.h" struct intel_fbdev { @@ -146,65 +146,6 @@ static const struct fb_ops intelfb_ops = { .fb_mmap = intel_fbdev_mmap, }; -static int intelfb_alloc(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct intel_fbdev *ifbdev = to_intel_fbdev(helper); - struct drm_framebuffer *fb; - struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_mode_fb_cmd2 mode_cmd = {}; - struct drm_i915_gem_object *obj; - int size; - - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = PAGE_ALIGN(size); - - obj = ERR_PTR(-ENODEV); - if (HAS_LMEM(dev_priv)) { - obj = i915_gem_object_create_lmem(dev_priv, size, - I915_BO_ALLOC_CONTIGUOUS | - I915_BO_ALLOC_USER); - } else { - /* - * If the FB is too big, just don't use it since fbdev is not very - * important and we should probably use that space with FBC or other - * features. - * - * Also skip stolen on MTL as Wa_22018444074 mitigation. - */ - if (!(IS_METEORLAKE(dev_priv)) && size * 2 < dev_priv->dsm.usable_size) - obj = i915_gem_object_create_stolen(dev_priv, size); - if (IS_ERR(obj)) - obj = i915_gem_object_create_shmem(dev_priv, size); - } - - if (IS_ERR(obj)) { - drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj); - return PTR_ERR(obj); - } - - fb = intel_framebuffer_create(obj, &mode_cmd); - i915_gem_object_put(obj); - if (IS_ERR(fb)) - return PTR_ERR(fb); - - ifbdev->fb = to_intel_framebuffer(fb); - return 0; -} - static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { @@ -213,7 +154,6 @@ static int intelfb_create(struct drm_fb_helper *helper, struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - struct i915_ggtt *ggtt = to_gt(dev_priv)->ggtt; const struct i915_gtt_view view = { .type = I915_GTT_VIEW_NORMAL, }; @@ -222,9 +162,7 @@ static int intelfb_create(struct drm_fb_helper *helper, struct i915_vma *vma; unsigned long flags = 0; bool prealloc = false; - void __iomem *vaddr; struct drm_i915_gem_object *obj; - struct i915_gem_ww_ctx ww; int ret; mutex_lock(&ifbdev->hpd_lock); @@ -245,12 +183,13 @@ static int intelfb_create(struct drm_fb_helper *helper, intel_fb = ifbdev->fb = NULL; } if (!intel_fb || drm_WARN_ON(dev, !intel_fb_obj(&intel_fb->base))) { + struct drm_framebuffer *fb; drm_dbg_kms(&dev_priv->drm, "no BIOS fb, allocating a new one\n"); - ret = intelfb_alloc(helper, sizes); - if (ret) - return ret; - intel_fb = ifbdev->fb; + fb = intel_fbdev_fb_alloc(helper, sizes); + if (IS_ERR(fb)) + return PTR_ERR(fb); + intel_fb = ifbdev->fb = to_intel_framebuffer(fb); } else { drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n"); prealloc = true; @@ -283,49 +222,18 @@ static int intelfb_create(struct drm_fb_helper *helper, info->fbops = &intelfb_ops; obj = intel_fb_obj(&intel_fb->base); - if (i915_gem_object_is_lmem(obj)) { - struct intel_memory_region *mem = obj->mm.region; - - /* Use fbdev's framebuffer from lmem for discrete */ - info->fix.smem_start = - (unsigned long)(mem->io_start + - i915_gem_object_get_dma_address(obj, 0)); - info->fix.smem_len = obj->base.size; - } else { - /* Our framebuffer is the entirety of fbdev's system memory */ - info->fix.smem_start = - (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); - info->fix.smem_len = vma->size; - } - - for_i915_gem_ww(&ww, ret, false) { - ret = i915_gem_object_lock(vma->obj, &ww); - - if (ret) - continue; - - vaddr = i915_vma_pin_iomap(vma); - if (IS_ERR(vaddr)) { - drm_err(&dev_priv->drm, - "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); - ret = PTR_ERR(vaddr); - continue; - } - } + ret = intel_fbdev_fb_fill_info(dev_priv, info, obj, vma); if (ret) goto out_unpin; - info->screen_base = vaddr; - info->screen_size = vma->size; - drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); /* If the object is shmemfs backed, it will have given us zeroed pages. * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (!i915_gem_object_is_shmem(vma->obj) && !prealloc) + if (!i915_gem_object_is_shmem(obj) && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c new file mode 100644 index 000000000000..717c3a3237c4 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include "gem/i915_gem_lmem.h" + +#include "i915_drv.h" +#include "intel_display_types.h" +#include "intel_fbdev_fb.h" + +struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_framebuffer *fb; + struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_i915_gem_object *obj; + int size; + + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * + DIV_ROUND_UP(sizes->surface_bpp, 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = PAGE_ALIGN(size); + + obj = ERR_PTR(-ENODEV); + if (HAS_LMEM(dev_priv)) { + obj = i915_gem_object_create_lmem(dev_priv, size, + I915_BO_ALLOC_CONTIGUOUS | + I915_BO_ALLOC_USER); + } else { + /* + * If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. + * + * Also skip stolen on MTL as Wa_22018444074 mitigation. + */ + if (!(IS_METEORLAKE(dev_priv)) && size * 2 < dev_priv->dsm.usable_size) + obj = i915_gem_object_create_stolen(dev_priv, size); + if (IS_ERR(obj)) + obj = i915_gem_object_create_shmem(dev_priv, size); + } + + if (IS_ERR(obj)) { + drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj); + return ERR_PTR(-ENOMEM); + } + + fb = intel_framebuffer_create(obj, &mode_cmd); + i915_gem_object_put(obj); + + return fb; +} + +int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info, + struct drm_i915_gem_object *obj, struct i915_vma *vma) +{ + struct i915_gem_ww_ctx ww; + void __iomem *vaddr; + int ret; + + if (i915_gem_object_is_lmem(obj)) { + struct intel_memory_region *mem = obj->mm.region; + + /* Use fbdev's framebuffer from lmem for discrete */ + info->fix.smem_start = + (unsigned long)(mem->io_start + + i915_gem_object_get_dma_address(obj, 0)); + info->fix.smem_len = obj->base.size; + } else { + struct i915_ggtt *ggtt = to_gt(i915)->ggtt; + + /* Our framebuffer is the entirety of fbdev's system memory */ + info->fix.smem_start = + (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); + info->fix.smem_len = vma->size; + } + + for_i915_gem_ww(&ww, ret, false) { + ret = i915_gem_object_lock(vma->obj, &ww); + + if (ret) + continue; + + vaddr = i915_vma_pin_iomap(vma); + if (IS_ERR(vaddr)) { + drm_err(&i915->drm, + "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); + ret = PTR_ERR(vaddr); + continue; + } + } + + if (ret) + return ret; + + info->screen_base = vaddr; + info->screen_size = intel_bo_to_drm_bo(obj)->size; + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h new file mode 100644 index 000000000000..a395b2c65d33 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_FBDEV_FB_H__ +#define __INTEL_FBDEV_FB_H__ + +struct drm_fb_helper; +struct drm_fb_helper_surface_size; +struct drm_i915_gem_object; +struct drm_i915_private; +struct fb_info; +struct i915_vma; + +struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); +int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info, + struct drm_i915_gem_object *obj, struct i915_vma *vma); + +#endif From c952bf11ace50b03fce14dbc15a092fdc9a6d2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Wed, 15 Nov 2023 11:07:19 +0200 Subject: [PATCH 2128/7721] drm/i915/display: use intel_bo_to_drm_bo in intel_fbdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe driver. I915 and Xe object implementation are differing. Do not use i915_gem_object->base directly. Instead use intel_bo_to_drm_bo. Signed-off-by: Jouni Högander Signed-off-by: Maarten Lankhorst Reviewed-by: Vinod Govindapillai Link: https://patchwork.freedesktop.org/patch/msgid/20231115090719.3210079-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fbdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index b7e4b7830e45..99894a855ef0 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -332,12 +332,12 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, continue; } - if (obj->base.size > max_size) { + if (intel_bo_to_drm_bo(obj)->size > max_size) { drm_dbg_kms(&i915->drm, "found possible fb from [PLANE:%d:%s]\n", plane->base.base.id, plane->base.name); fb = to_intel_framebuffer(plane_state->uapi.fb); - max_size = obj->base.size; + max_size = intel_bo_to_drm_bo(obj)->size; } } From c52391fafcefe4c562bdac62088a2735c185b942 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 15 Nov 2023 15:02:44 -0600 Subject: [PATCH 2129/7721] auxdisplay: img-ascii-lcd: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Cc: Paul Burton Link: https://lore.kernel.org/r/20231115210245.3744589-1-robh@kernel.org [ As discussed, used `dev` and moved call to `cfg`'s initialization. ] Signed-off-by: Miguel Ojeda --- drivers/auxdisplay/img-ascii-lcd.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c index fa23e415f260..56efda0740fb 100644 --- a/drivers/auxdisplay/img-ascii-lcd.c +++ b/drivers/auxdisplay/img-ascii-lcd.c @@ -8,9 +8,9 @@ #include #include #include -#include -#include +#include #include +#include #include #include @@ -225,17 +225,11 @@ MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches); */ static int img_ascii_lcd_probe(struct platform_device *pdev) { - const struct of_device_id *match; - const struct img_ascii_lcd_config *cfg; struct device *dev = &pdev->dev; + const struct img_ascii_lcd_config *cfg = device_get_match_data(dev); struct img_ascii_lcd_ctx *ctx; int err; - match = of_match_device(img_ascii_lcd_matches, dev); - if (!match) - return -ENODEV; - - cfg = match->data; ctx = devm_kzalloc(dev, sizeof(*ctx) + cfg->num_chars, GFP_KERNEL); if (!ctx) return -ENOMEM; From 37a0dd6137ecfbd25d6ce84b65ad23de4f06b779 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Thu, 30 Nov 2023 19:09:51 +0200 Subject: [PATCH 2130/7721] wifi: ath12k: add 320 MHz bandwidth enums Add 320 MHz bandwidth as a new bandwidth enum for ATH12k driver. This is extending existing bandwidth related enums to include 320 MHz. This is a precursor to supporting 320 MHz in the future. Sanity test performed to confirm that there was no impact in existing bandwidths. Additionally update QuIC copyright to include 2023 in hal_rx.h. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00125-QCAHKSWPL_SILICONZ-1 Signed-off-by: Muna Sinada Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231116221839.1303170-1-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_mon.c | 3 ++- drivers/net/wireless/ath/ath12k/dp_rx.c | 3 ++- drivers/net/wireless/ath/ath12k/hal_rx.h | 3 ++- drivers/net/wireless/ath/ath12k/mac.c | 8 ++++++++ drivers/net/wireless/ath/ath12k/mac.h | 1 + drivers/net/wireless/ath/ath12k/wmi.h | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 98d7c8e2c0eb..be4b39f5fa80 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1091,7 +1091,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct spin_unlock_bh(&ar->ab->base_lock); ath12k_dbg(ar->ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -1104,6 +1104,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct (status->bw == RATE_INFO_BW_40) ? "40" : "", (status->bw == RATE_INFO_BW_80) ? "80" : "", (status->bw == RATE_INFO_BW_160) ? "160" : "", + (status->bw == RATE_INFO_BW_320) ? "320" : "", status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->nss, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index fb02238798d7..1ee83f765929 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2417,7 +2417,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap spin_unlock_bh(&ab->base_lock); ath12k_dbg(ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -2431,6 +2431,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap (status->bw == RATE_INFO_BW_40) ? "40" : "", (status->bw == RATE_INFO_BW_80) ? "80" : "", (status->bw == RATE_INFO_BW_160) ? "160" : "", + (status->bw == RATE_INFO_BW_320) ? "320" : "", status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->nss, diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index fcfb6c819047..095216eabc01 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_RX_H @@ -61,6 +61,7 @@ enum hal_rx_bw { HAL_RX_BW_40MHZ, HAL_RX_BW_80MHZ, HAL_RX_BW_160MHZ, + HAL_RX_BW_320MHZ, HAL_RX_BW_MAX, }; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a13506c177f6..b0d594d2fc90 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -343,6 +343,9 @@ ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw) case ATH12K_BW_160: ret = RATE_INFO_BW_160; break; + case ATH12K_BW_320: + ret = RATE_INFO_BW_320; + break; } return ret; @@ -359,6 +362,8 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b return ATH12K_BW_80; case RATE_INFO_BW_160: return ATH12K_BW_160; + case RATE_INFO_BW_320: + return ATH12K_BW_320; default: return ATH12K_BW_20; } @@ -3726,6 +3731,9 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, case IEEE80211_STA_RX_BW_160: bw = WMI_PEER_CHWIDTH_160MHZ; break; + case IEEE80211_STA_RX_BW_320: + bw = WMI_PEER_CHWIDTH_320MHZ; + break; default: ath12k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n", sta->deflink.bandwidth, sta->addr); diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7d71ae1aba45..7c63bb628adc 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -43,6 +43,7 @@ enum ath12k_supported_bw { ATH12K_BW_40 = 1, ATH12K_BW_80 = 2, ATH12K_BW_160 = 3, + ATH12K_BW_320 = 4, }; extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 811aeea34e34..06e5b9b4049b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2222,6 +2222,7 @@ enum wmi_peer_chwidth { WMI_PEER_CHWIDTH_40MHZ = 1, WMI_PEER_CHWIDTH_80MHZ = 2, WMI_PEER_CHWIDTH_160MHZ = 3, + WMI_PEER_CHWIDTH_320MHZ = 4, }; enum wmi_beacon_gen_mode { From 842addae02089fce4731be1c8d7d539449d4d009 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 21 Nov 2023 05:28:11 +0530 Subject: [PATCH 2131/7721] wifi: ath12k: Optimize the mac80211 hw data access Currently mac80211 hw data is accessed by convert the hw to radio (ar) structure and then radio to hw structure which is not necessary in some places where mac80211 hw data is already present. So in that kind of places avoid the conversion and directly access the mac80211 hw data. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231120235812.2602198-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 14 +++++++------- drivers/net/wireless/ath/ath12k/reg.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b0d594d2fc90..d6728103c58e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4995,7 +4995,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", ret); - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(hw, skb); } return; } @@ -5003,7 +5003,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, ret = ath12k_dp_tx(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(hw, skb); } } @@ -5604,7 +5604,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, goto err_peer_del; param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; - param_value = ar->hw->wiphy->rts_threshold; + param_value = hw->wiphy->rts_threshold; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -6844,7 +6844,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); return ret; } - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, arvif); } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, @@ -6890,14 +6890,14 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; } - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, arvif); mutex_lock(&ar->conf_mutex); arvif->bitrate_mask = *mask; - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_set_bitrate_mask_iter, arvif); @@ -6935,7 +6935,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ath12k_warn(ar->ab, "pdev %d successfully recovered\n", ar->pdev->pdev_id); ar->state = ATH12K_STATE_ON; - ieee80211_wake_queues(ar->hw); + ieee80211_wake_queues(hw); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 8321715779cb..6e98277b5ec8 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -28,11 +28,11 @@ static const struct ieee80211_regdomain ath12k_world_regd = { } }; -static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2) +static bool ath12k_regdom_changes(struct ieee80211_hw *hw, char *alpha2) { const struct ieee80211_regdomain *regd; - regd = rcu_dereference_rtnl(ar->hw->wiphy->regd); + regd = rcu_dereference_rtnl(hw->wiphy->regd); /* This can happen during wiphy registration where the previous * user request is received before we update the regd received * from firmware. @@ -71,7 +71,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) return; } - if (!ath12k_regdom_changes(ar, request->alpha2)) { + if (!ath12k_regdom_changes(hw, request->alpha2)) { ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Country is already set\n"); return; } From 940b57fd0e77109874a99de8b304d672599d1acb Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 21 Nov 2023 05:28:12 +0530 Subject: [PATCH 2132/7721] wifi: ath12k: avoid repeated hw access from ar Currently, the helper functions are accessing mac80211 hw data from the radio (ar) structure repeatedly. So optimize these helper functions by storing mac80211 hw data locally and accessing it directly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231120235812.2602198-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 158 +++++++++++++------------- drivers/net/wireless/ath/ath12k/reg.c | 13 ++- drivers/net/wireless/ath/ath12k/reg.h | 2 +- 3 files changed, 90 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d6728103c58e..556013f8c609 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6266,10 +6266,11 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; + struct ieee80211_hw *hw = ar->hw; lockdep_assert_held(&ar->conf_mutex); - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, ath12k_mac_change_chanctx_cnt_iter, &arg); @@ -6280,7 +6281,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, if (!arg.vifs) return; - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, ath12k_mac_change_chanctx_fill_iter, &arg); @@ -7159,6 +7160,7 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) static int ath12k_mac_setup_channels_rates(struct ath12k *ar, u32 supported_bands) { + struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; void *channels; @@ -7184,7 +7186,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_g_rates_size; band->bitrates = ath12k_g_rates; - ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + hw->wiphy->bands[NL80211_BAND_2GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); @@ -7211,7 +7213,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + hw->wiphy->bands[NL80211_BAND_6GHZ] = band; ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); @@ -7233,7 +7235,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + hw->wiphy->bands[NL80211_BAND_5GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); @@ -7252,6 +7254,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->hw; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; @@ -7302,8 +7305,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80); - ar->hw->wiphy->iface_combinations = combinations; - ar->hw->wiphy->n_iface_combinations = 1; + hw->wiphy->iface_combinations = combinations; + hw->wiphy->n_iface_combinations = 1; return 0; } @@ -7347,9 +7350,11 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { static void __ath12k_mac_unregister(struct ath12k *ar) { + struct ieee80211_hw *hw = ar->hw; + cancel_work_sync(&ar->regd_update_work); - ieee80211_unregister_hw(ar->hw); + ieee80211_unregister_hw(hw); idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); @@ -7358,10 +7363,10 @@ static void __ath12k_mac_unregister(struct ath12k *ar) kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); - kfree(ar->hw->wiphy->iface_combinations[0].limits); - kfree(ar->hw->wiphy->iface_combinations); + kfree(hw->wiphy->iface_combinations[0].limits); + kfree(hw->wiphy->iface_combinations); - SET_IEEE80211_DEV(ar->hw, NULL); + SET_IEEE80211_DEV(hw, NULL); } void ath12k_mac_unregister(struct ath12k_base *ab) @@ -7383,6 +7388,7 @@ void ath12k_mac_unregister(struct ath12k_base *ab) static int __ath12k_mac_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->hw; struct ath12k_pdev_cap *cap = &ar->pdev->cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, @@ -7400,9 +7406,9 @@ static int __ath12k_mac_register(struct ath12k *ar) ath12k_pdev_caps_update(ar); - SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(ar->hw, ab->dev); + SET_IEEE80211_DEV(hw, ab->dev); ret = ath12k_mac_setup_channels_rates(ar, cap->supported_bands); @@ -7418,103 +7424,103 @@ static int __ath12k_mac_register(struct ath12k *ar) goto err_free_channels; } - ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask; - ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask; + hw->wiphy->available_antennas_rx = cap->rx_chain_mask; + hw->wiphy->available_antennas_tx = cap->tx_chain_mask; - ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes; + hw->wiphy->interface_modes = ab->hw_params->interface_modes; - if (ar->hw->wiphy->bands[NL80211_BAND_2GHZ] && - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] && - ar->hw->wiphy->bands[NL80211_BAND_6GHZ]) - ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS); + if (hw->wiphy->bands[NL80211_BAND_2GHZ] && + hw->wiphy->bands[NL80211_BAND_5GHZ] && + hw->wiphy->bands[NL80211_BAND_6GHZ]) + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); - ieee80211_hw_set(ar->hw, SIGNAL_DBM); - ieee80211_hw_set(ar->hw, SUPPORTS_PS); - ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); - ieee80211_hw_set(ar->hw, MFP_CAPABLE); - ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); - ieee80211_hw_set(ar->hw, AP_LINK_PS); - ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); - ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); - ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); - ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); - ieee80211_hw_set(ar->hw, QUEUE_CONTROL); - ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); - ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, MFP_CAPABLE); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, AP_LINK_PS); + ieee80211_hw_set(hw, SPECTRUM_MGMT); + ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); + ieee80211_hw_set(hw, QUEUE_CONTROL); + ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(hw, REPORTS_LOW_ACK); if (ht_cap & WMI_HT_CAP_ENABLED) { - ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); - ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); - ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU); - ieee80211_hw_set(ar->hw, USES_RSS); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, USES_RSS); } - ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; - ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; /* TODO: Check if HT capability advertised from firmware is different * for each band for a dual band capable radio. It will be tricky to * handle it when the ht capability different for each band. */ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) - ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; - ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; - ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; + hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; + hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; - ar->hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; + hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; - ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - ar->hw->wiphy->max_remain_on_channel_duration = 5000; + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->max_remain_on_channel_duration = 5000; - ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; ar->max_num_stations = TARGET_NUM_STATIONS; ar->max_num_peers = TARGET_NUM_PEERS_PDEV; - ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; - ar->hw->queues = ATH12K_HW_MAX_QUEUES; - ar->hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN; - ar->hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; - ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->queues = ATH12K_HW_MAX_QUEUES; + hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN; + hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; - ar->hw->vif_data_size = sizeof(struct ath12k_vif); - ar->hw->sta_data_size = sizeof(struct ath12k_sta); + hw->vif_data_size = sizeof(struct ath12k_vif); + hw->sta_data_size = sizeof(struct ath12k_sta); - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); - ar->hw->wiphy->cipher_suites = cipher_suites; - ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + hw->wiphy->cipher_suites = cipher_suites; + hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - ar->hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; - ar->hw->wiphy->num_iftype_ext_capab = + hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; + hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); if (ar->supports_6ghz) { - wiphy_ext_feature_set(ar->hw->wiphy, + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); - wiphy_ext_feature_set(ar->hw->wiphy, + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); } - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT); - ath12k_reg_init(ar); + ath12k_reg_init(hw); if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { - ar->hw->netdev_features = NETIF_F_HW_CSUM; - ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); - ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); + hw->netdev_features = NETIF_F_HW_CSUM; + ieee80211_hw_set(hw, SW_CRYPTO_CONTROL); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); } - ret = ieee80211_register_hw(ar->hw); + ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); goto err_free_if_combs; @@ -7526,7 +7532,7 @@ static int __ath12k_mac_register(struct ath12k *ar) * while. But that time is so short and in practise it make * a difference in real life. */ - ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); /* Apply the regd received during initialization */ ret = ath12k_regd_update(ar, true); @@ -7538,11 +7544,11 @@ static int __ath12k_mac_register(struct ath12k *ar) return 0; err_unregister_hw: - ieee80211_unregister_hw(ar->hw); + ieee80211_unregister_hw(hw); err_free_if_combs: - kfree(ar->hw->wiphy->iface_combinations[0].limits); - kfree(ar->hw->wiphy->iface_combinations); + kfree(hw->wiphy->iface_combinations[0].limits); + kfree(hw->wiphy->iface_combinations); err_free_channels: kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); @@ -7550,7 +7556,7 @@ static int __ath12k_mac_register(struct ath12k *ar) kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); err: - SET_IEEE80211_DEV(ar->hw, NULL); + SET_IEEE80211_DEV(hw, NULL); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 6e98277b5ec8..f924bc13ccff 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -199,6 +199,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig, int ath12k_regd_update(struct ath12k *ar, bool init) { + struct ieee80211_hw *hw = ar->hw; struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath12k_base *ab; @@ -246,9 +247,9 @@ int ath12k_regd_update(struct ath12k *ar, bool init) } rtnl_lock(); - wiphy_lock(ar->hw->wiphy); - ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); - wiphy_unlock(ar->hw->wiphy); + wiphy_lock(hw->wiphy); + ret = regulatory_set_wiphy_regd_sync(hw->wiphy, regd_copy); + wiphy_unlock(hw->wiphy); rtnl_unlock(); kfree(regd_copy); @@ -729,10 +730,10 @@ void ath12k_regd_update_work(struct work_struct *work) } } -void ath12k_reg_init(struct ath12k *ar) +void ath12k_reg_init(struct ieee80211_hw *hw) { - ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; - ar->hw->wiphy->reg_notifier = ath12k_reg_notifier; + hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; + hw->wiphy->reg_notifier = ath12k_reg_notifier; } void ath12k_reg_free(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h index d4a0776e1034..29c7ec3260da 100644 --- a/drivers/net/wireless/ath/ath12k/reg.h +++ b/drivers/net/wireless/ath/ath12k/reg.h @@ -89,7 +89,7 @@ enum ath12k_reg_phy_bitmap { ATH12K_REG_PHY_BITMAP_NO11BE = BIT(6), }; -void ath12k_reg_init(struct ath12k *ar); +void ath12k_reg_init(struct ieee80211_hw *hw); void ath12k_reg_free(struct ath12k_base *ab); void ath12k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab, From b5418d170b7cf9af89245319935cfe7bf45a151c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:30:59 +0100 Subject: [PATCH 2133/7721] wifi: ath5k: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117093056.873834-10-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath5k/ahb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 08bd5d3b00f1..f27308ccb2f1 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -185,7 +185,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return ret; } -static int ath_ahb_remove(struct platform_device *pdev) +static void ath_ahb_remove(struct platform_device *pdev) { struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); struct ieee80211_hw *hw = platform_get_drvdata(pdev); @@ -193,7 +193,7 @@ static int ath_ahb_remove(struct platform_device *pdev) u32 reg; if (!hw) - return 0; + return; ah = hw->priv; @@ -215,13 +215,11 @@ static int ath_ahb_remove(struct platform_device *pdev) ath5k_deinit_ah(ah); iounmap(ah->iobase); ieee80211_free_hw(hw); - - return 0; } static struct platform_driver ath_ahb_driver = { .probe = ath_ahb_probe, - .remove = ath_ahb_remove, + .remove_new = ath_ahb_remove, .driver = { .name = "ar231x-wmac", }, From 8cc18a70913fcdc8ac06796ca91304df0a51b6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:31:01 +0100 Subject: [PATCH 2134/7721] wifi: wcn36xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231117093056.873834-12-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/wcn36xx/main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 2bd1163177f0..41119fb177e3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1644,7 +1644,7 @@ static int wcn36xx_probe(struct platform_device *pdev) return ret; } -static int wcn36xx_remove(struct platform_device *pdev) +static void wcn36xx_remove(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct wcn36xx *wcn = hw->priv; @@ -1666,8 +1666,6 @@ static int wcn36xx_remove(struct platform_device *pdev) mutex_destroy(&wcn->hal_mutex); ieee80211_free_hw(hw); - - return 0; } static const struct of_device_id wcn36xx_of_match[] = { @@ -1678,7 +1676,7 @@ MODULE_DEVICE_TABLE(of, wcn36xx_of_match); static struct platform_driver wcn36xx_driver = { .probe = wcn36xx_probe, - .remove = wcn36xx_remove, + .remove_new = wcn36xx_remove, .driver = { .name = "wcn36xx", .of_match_table = wcn36xx_of_match, From b5efc28a754d2e90b9d52ba5aaa051cc24a5c85d Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Fri, 1 Dec 2023 13:58:58 +0000 Subject: [PATCH 2135/7721] firmware: arm_scmi: Add protocol versioning checks Platform and agent supported protocols versions do not necessarily match. When talking to an older SCMI platform, supporting only older protocol versions, the kernel SCMI agent will downgrade the version of the used protocol to match the platform and avoid compatibility issues. In the case where the kernel/OSPM agent happens to communicate with a newer platform which can support newer protocol versions unknown to the agent, and potentially backward incompatible, the agent currently carries on, silently, in a best-effort approach. Note that the SCMI specification doesn't provide means to explicitly detect the protocol versions used by the agents, neither it is required to support multiple, older, protocol versions. Add an explicit protocol version check to let the agent detect when this version mismatch happens and warn the user about this condition. Signed-off-by: Cristian Marussi Link: https://lore.kernel.org/r/20231201135858.2367651-1-cristian.marussi@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/base.c | 6 +++++- drivers/firmware/arm_scmi/clock.c | 6 +++++- drivers/firmware/arm_scmi/driver.c | 12 +++++++++++- drivers/firmware/arm_scmi/perf.c | 6 +++++- drivers/firmware/arm_scmi/power.c | 6 +++++- drivers/firmware/arm_scmi/powercap.c | 6 +++++- drivers/firmware/arm_scmi/protocols.h | 8 +++++++- drivers/firmware/arm_scmi/reset.c | 6 +++++- drivers/firmware/arm_scmi/sensors.c | 6 +++++- drivers/firmware/arm_scmi/system.c | 6 +++++- drivers/firmware/arm_scmi/voltage.c | 6 +++++- 11 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index a52f084a6a87..97254de35ab0 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -13,6 +13,9 @@ #include "common.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define SCMI_BASE_NUM_SOURCES 1 #define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 @@ -385,7 +388,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) rev->major_ver = PROTOCOL_REV_MAJOR(version), rev->minor_ver = PROTOCOL_REV_MINOR(version); - ph->set_priv(ph, rev); + ph->set_priv(ph, rev, version); ret = scmi_base_attributes_get(ph); if (ret) @@ -423,6 +426,7 @@ static const struct scmi_protocol scmi_base = { .instance_init = &scmi_base_protocol_init, .ops = NULL, .events = &base_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 98511a3aa367..c0644558042a 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -12,6 +12,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 + enum scmi_clock_protocol_cmd { CLOCK_ATTRIBUTES = 0x3, CLOCK_DESCRIBE_RATES = 0x4, @@ -961,7 +964,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) } cinfo->version = version; - return ph->set_priv(ph, cinfo); + return ph->set_priv(ph, cinfo, version); } static const struct scmi_protocol scmi_clock = { @@ -970,6 +973,7 @@ static const struct scmi_protocol scmi_clock = { .instance_init = &scmi_clock_protocol_init, .ops = &clk_proto_ops, .events = &clk_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 3eb19ed6f148..a9f70e6e58ac 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -85,6 +85,7 @@ struct scmi_xfers_info { * @gid: A reference for per-protocol devres management. * @users: A refcount to track effective users of this protocol. * @priv: Reference for optional protocol private data. + * @version: Protocol version supported by the platform as detected at runtime. * @ph: An embedded protocol handle that will be passed down to protocol * initialization code to identify this instance. * @@ -97,6 +98,7 @@ struct scmi_protocol_instance { void *gid; refcount_t users; void *priv; + unsigned int version; struct scmi_protocol_handle ph; }; @@ -1392,15 +1394,17 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version) * * @ph: A reference to the protocol handle. * @priv: The private data to set. + * @version: The detected protocol version for the core to register. * * Return: 0 on Success */ static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph, - void *priv) + void *priv, u32 version) { struct scmi_protocol_instance *pi = ph_to_pi(ph); pi->priv = priv; + pi->version = version; return 0; } @@ -1849,6 +1853,12 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, devres_close_group(handle->dev, pi->gid); dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id); + if (pi->version > proto->supported_version) + dev_warn(handle->dev, + "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X." + "Backward compatibility is NOT assured.\n", + pi->version, pi->proto->id); + return pi; clean: diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 81dd5c5e5533..ebdfa8d6af72 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -24,6 +24,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x40000 + #define MAX_OPPS 32 enum scmi_performance_protocol_cmd { @@ -1104,7 +1107,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) if (ret) return ret; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_perf = { @@ -1113,6 +1116,7 @@ static const struct scmi_protocol scmi_perf = { .instance_init = &scmi_perf_protocol_init, .ops = &perf_proto_ops, .events = &perf_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf) diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 077767d6e902..c2e6b9b4d941 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + enum scmi_power_protocol_cmd { POWER_DOMAIN_ATTRIBUTES = 0x3, POWER_STATE_SET = 0x4, @@ -328,7 +331,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph) pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_power = { @@ -337,6 +340,7 @@ static const struct scmi_protocol scmi_power = { .instance_init = &scmi_power_protocol_init, .ops = &power_proto_ops, .events = &power_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power) diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c index 62a7780fedbb..a4c6cd4716fe 100644 --- a/drivers/firmware/arm_scmi/powercap.c +++ b/drivers/firmware/arm_scmi/powercap.c @@ -17,6 +17,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + enum scmi_powercap_protocol_cmd { POWERCAP_DOMAIN_ATTRIBUTES = 0x3, POWERCAP_CAP_GET = 0x4, @@ -975,7 +978,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph) } pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_powercap = { @@ -984,6 +987,7 @@ static const struct scmi_protocol scmi_powercap = { .instance_init = &scmi_powercap_protocol_init, .ops = &powercap_proto_ops, .events = &powercap_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap) diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h index b3c6314bb4b8..e683c26f24eb 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -174,7 +174,8 @@ struct scmi_protocol_handle { struct device *dev; const struct scmi_xfer_ops *xops; const struct scmi_proto_helpers_ops *hops; - int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv); + int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv, + u32 version); void *(*get_priv)(const struct scmi_protocol_handle *ph); }; @@ -311,6 +312,10 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *); * @ops: Optional reference to the operations provided by the protocol and * exposed in scmi_protocol.h. * @events: An optional reference to the events supported by this protocol. + * @supported_version: The highest version currently supported for this + * protocol by the agent. Each protocol implementation + * in the agent is supposed to downgrade to match the + * protocol version supported by the platform. */ struct scmi_protocol { const u8 id; @@ -319,6 +324,7 @@ struct scmi_protocol { const scmi_prot_init_ph_fn_t instance_deinit; const void *ops; const struct scmi_protocol_events *events; + unsigned int supported_version; }; #define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \ diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index 7217fd7c6afa..19970d9f9e36 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + enum scmi_reset_protocol_cmd { RESET_DOMAIN_ATTRIBUTES = 0x3, RESET = 0x4, @@ -343,7 +346,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) } pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_reset = { @@ -352,6 +355,7 @@ static const struct scmi_protocol scmi_reset = { .instance_init = &scmi_reset_protocol_init, .ops = &reset_proto_ops, .events = &reset_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 9952a7bc6682..311149965370 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -14,6 +14,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + #define SCMI_MAX_NUM_SENSOR_AXIS 63 #define SCMIv2_SENSOR_PROTOCOL 0x10000 @@ -1138,7 +1141,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph) if (ret) return ret; - return ph->set_priv(ph, sinfo); + return ph->set_priv(ph, sinfo, version); } static const struct scmi_protocol scmi_sensors = { @@ -1147,6 +1150,7 @@ static const struct scmi_protocol scmi_sensors = { .instance_init = &scmi_sensors_protocol_init, .ops = &sensor_proto_ops, .events = &sensor_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors) diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index 9383d7584539..1621da97bcbb 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define SCMI_SYSTEM_NUM_SOURCES 1 enum scmi_system_protocol_cmd { @@ -144,7 +147,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2) pinfo->graceful_timeout_supported = true; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_system = { @@ -153,6 +156,7 @@ static const struct scmi_protocol scmi_system = { .instance_init = &scmi_system_protocol_init, .ops = NULL, .events = &system_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index 36e2df77738c..2175ffd6cef5 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -10,6 +10,9 @@ #include "protocols.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) #define REMAINING_LEVELS_MASK GENMASK(31, 16) #define RETURNED_LEVELS_MASK GENMASK(11, 0) @@ -432,7 +435,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph) dev_warn(ph->dev, "No Voltage domains found.\n"); } - return ph->set_priv(ph, vinfo); + return ph->set_priv(ph, vinfo, version); } static const struct scmi_protocol scmi_voltage = { @@ -440,6 +443,7 @@ static const struct scmi_protocol scmi_voltage = { .owner = THIS_MODULE, .instance_init = &scmi_voltage_protocol_init, .ops = &voltage_proto_ops, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage) From f8dd1f89bd5ecbfcc547ee5b222a4b9ddb0a0160 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:30 +0100 Subject: [PATCH 2136/7721] ASoC: cs35l32: Drop legacy include This driver includes the legacy GPIO API but does not use any symbols from it. Drop the include. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-1-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 138040618438..d1350ffbf3bd 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include From 50678d339d670a92658e5538ebee30447c88ccb3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:31 +0100 Subject: [PATCH 2137/7721] ASoC: cs35l33: Fix GPIO name and drop legacy include This driver includes the legacy GPIO APIs and but does not use any symbols from any of them. Drop the includes. Further the driver is requesting "reset-gpios" rather than just "reset" from the GPIO framework. This is wrong because the gpiolib core will add "-gpios" before processing the request from e.g. device tree. Drop the suffix. The last problem means that the optional RESET GPIO has never been properly retrieved and used even if it existed, but nobody noticed. Fixes: 3333cb7187b9 ("ASoC: cs35l33: Initial commit of the cs35l33 CODEC driver.") Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-2-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l33.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 4010a2d33a33..a19a2bafb37c 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -22,13 +22,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include "cs35l33.h" @@ -1165,7 +1163,7 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client) /* We could issue !RST or skip it based on AMP topology */ cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, - "reset-gpios", GPIOD_OUT_HIGH); + "reset", GPIOD_OUT_HIGH); if (IS_ERR(cs35l33->reset_gpio)) { dev_err(&i2c_client->dev, "%s ERROR: Can't get reset GPIO\n", __func__); From a6122b0b4211d132934ef99e7b737910e6d54d2f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:32 +0100 Subject: [PATCH 2138/7721] ASoC: cs35l34: Fix GPIO name and drop legacy include This driver includes the legacy GPIO APIs and but does not use any symbols from any of them. Drop the includes. Further the driver is requesting "reset-gpios" rather than just "reset" from the GPIO framework. This is wrong because the gpiolib core will add "-gpios" before processing the request from e.g. device tree. Drop the suffix. The last problem means that the optional RESET GPIO has never been properly retrieved and used even if it existed, but nobody noticed. Fixes: c1124c09e103 ("ASoC: cs35l34: Initial commit of the cs35l34 CODEC driver.") Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-3-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index e5871736fa29..cca59de66b73 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -20,14 +20,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -1061,7 +1059,7 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client) dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, - "reset-gpios", GPIOD_OUT_LOW); + "reset", GPIOD_OUT_LOW); if (IS_ERR(cs35l34->reset_gpio)) { ret = PTR_ERR(cs35l34->reset_gpio); goto err_regulator; From 490d2d9f190a9a6125495ac4d833fa0af41763d0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:33 +0100 Subject: [PATCH 2139/7721] ASoC: cs35l35: Drop legacy includes This driver includes the legacy GPIO APIs and but does not use any symbols from any of them. Drop the includes. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-4-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 63a538f747d3..ddb7d63213a3 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -18,14 +18,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include From 194ef700d4e255686173a03b65e15cac637cc15a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:34 +0100 Subject: [PATCH 2140/7721] ASoC: cs35l36: Drop legacy includes This driver includes the legacy GPIO APIs and but does not use any symbols from any of them. Drop the includes. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-5-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index f2fde6e652b9..f5bd32e434a0 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -17,15 +17,14 @@ #include #include #include +#include #include -#include #include #include #include #include #include #include -#include #include #include #include From 42d1178d223ba9498c1ed40a5fc243a43d35ec97 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:35 +0100 Subject: [PATCH 2141/7721] ASoC: cs4271: Convert to GPIO descriptors This converts the Cirrus CS4271 ASoC codec driver to use GPIO descriptors. It turns out that there are two in-kernel users of the platform data passing mechanism so these are switched over as well. One locally defined GPIO "gpio_disabled" is declared in the state struct but completely unused in the driver, so we delete it. Reviewed-by: Alexander Sverdlin Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-6-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-ep93xx/edb93xx.c | 32 ++++++++++++++++++++--- arch/arm/mach-ep93xx/vision_ep9307.c | 12 ++++++++- include/sound/cs4271.h | 1 - sound/soc/codecs/cs4271.c | 39 ++++++++++------------------ 4 files changed, 52 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 4b90899a66e9..dbdb822a0100 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -88,7 +88,7 @@ static void __init edb93xx_register_i2c(void) * EDB93xx SPI peripheral handling *************************************************************************/ static struct cs4271_platform_data edb93xx_cs4271_data = { - .gpio_nreset = -EINVAL, /* filled in later */ + /* Intentionally left blank */ }; static struct spi_board_info edb93xx_spi_board_info[] __initdata = { @@ -114,14 +114,38 @@ static struct ep93xx_spi_info edb93xx_spi_info __initdata = { /* Intentionally left blank */ }; +static struct gpiod_lookup_table edb93xx_cs4272_edb9301_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("A", 1, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table edb93xx_cs4272_edb9302_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("H", 2, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table edb93xx_cs4272_edb9315_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("B", 6, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init edb93xx_register_spi(void) { if (machine_is_edb9301() || machine_is_edb9302()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO1; + gpiod_add_lookup_table(&edb93xx_cs4272_edb9301_gpio_table); else if (machine_is_edb9302a() || machine_is_edb9307a()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_H(2); + gpiod_add_lookup_table(&edb93xx_cs4272_edb9302_gpio_table); else if (machine_is_edb9315a()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO14; + gpiod_add_lookup_table(&edb93xx_cs4272_edb9315_gpio_table); gpiod_add_lookup_table(&edb93xx_spi_cs_gpio_table); ep93xx_register_spi(&edb93xx_spi_info, edb93xx_spi_board_info, diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 30d9cf3791eb..9471938df64c 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -164,7 +164,7 @@ static struct i2c_board_info vision_i2c_info[] __initdata = { * SPI CS4271 Audio Codec *************************************************************************/ static struct cs4271_platform_data vision_cs4271_data = { - .gpio_nreset = EP93XX_GPIO_LINE_H(2), + /* Intentionally left blank */ }; /************************************************************************* @@ -241,6 +241,15 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }, }; +static struct gpiod_lookup_table vision_spi_cs4271_gpio_table = { + .dev_id = "spi0.0", /* cs4271 @ CS0 */ + .table = { + /* RESET */ + GPIO_LOOKUP_IDX("H", 2, NULL, 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct gpiod_lookup_table vision_spi_cs_gpio_table = { .dev_id = "spi0", .table = { @@ -292,6 +301,7 @@ static void __init vision_init_machine(void) ep93xx_register_i2c(vision_i2c_info, ARRAY_SIZE(vision_i2c_info)); + gpiod_add_lookup_table(&vision_spi_cs4271_gpio_table); gpiod_add_lookup_table(&vision_spi_mmc_gpio_table); gpiod_add_lookup_table(&vision_spi_cs_gpio_table); ep93xx_register_spi(&vision_spi_master, vision_spi_board_info, diff --git a/include/sound/cs4271.h b/include/sound/cs4271.h index 6ff23ab48894..5a55d135bdea 100644 --- a/include/sound/cs4271.h +++ b/include/sound/cs4271.h @@ -9,7 +9,6 @@ #define __CS4271_H struct cs4271_platform_data { - int gpio_nreset; /* GPIO driving Reset pin, if any */ bool amutec_eq_bmutec; /* flag to enable AMUTEC=BMUTEC */ /* diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 9e6f8a048dd5..74a84832d958 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -13,9 +13,8 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -160,9 +159,7 @@ struct cs4271_private { /* Current sample rate for de-emphasis control */ int rate; /* GPIO driving Reset pin, if any */ - int gpio_nreset; - /* GPIO that disable serial bus, if any */ - int gpio_disable; + struct gpio_desc *reset; /* enable soft reset workaround */ bool enable_soft_reset; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; @@ -487,12 +484,10 @@ static int cs4271_reset(struct snd_soc_component *component) { struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(cs4271->gpio_nreset)) { - gpio_direction_output(cs4271->gpio_nreset, 0); - mdelay(1); - gpio_set_value(cs4271->gpio_nreset, 1); - mdelay(1); - } + gpiod_direction_output(cs4271->reset, 1); + mdelay(1); + gpiod_set_value(cs4271->reset, 0); + mdelay(1); return 0; } @@ -612,9 +607,8 @@ static void cs4271_component_remove(struct snd_soc_component *component) { struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(cs4271->gpio_nreset)) - /* Set codec to the reset state */ - gpio_set_value(cs4271->gpio_nreset, 0); + /* Set codec to the reset state */ + gpiod_set_value(cs4271->reset, 1); regcache_mark_dirty(cs4271->regmap); regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); @@ -639,7 +633,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4271 = { static int cs4271_common_probe(struct device *dev, struct cs4271_private **c) { - struct cs4271_platform_data *cs4271plat = dev->platform_data; struct cs4271_private *cs4271; int i, ret; @@ -647,17 +640,11 @@ static int cs4271_common_probe(struct device *dev, if (!cs4271) return -ENOMEM; - cs4271->gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); - - if (cs4271plat) - cs4271->gpio_nreset = cs4271plat->gpio_nreset; - - if (gpio_is_valid(cs4271->gpio_nreset)) { - ret = devm_gpio_request(dev, cs4271->gpio_nreset, - "CS4271 Reset"); - if (ret < 0) - return ret; - } + cs4271->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(cs4271->reset)) + return dev_err_probe(dev, PTR_ERR(cs4271->reset), + "error retrieveing RESET GPIO\n"); + gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset"); for (i = 0; i < ARRAY_SIZE(supply_names); i++) cs4271->supplies[i].supply = supply_names[i]; From b191a524b225a3acd7528c3fa8ebeb15302c979b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:36 +0100 Subject: [PATCH 2142/7721] ASoC: cirrus: edb93xx: Drop legacy include This driver includes the legacy GPIO API but does not use any symbols from it. Drop the include. Reviewed-by: Alexander Sverdlin Link: https://patchwork.kernel.org/project/alsa-devel/patch/20231122-ep93xx-v5-38-d59a76d5df29@maquefel.me/ Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-7-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/cirrus/edb93xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 6b6817256331..8bb67d7d2b4b 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include From 0ec65e8e2219a91987cbb041387d94d40cab38b2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:37 +0100 Subject: [PATCH 2143/7721] ASoC: cs42l42: Drop legacy include This driver includes the legacy GPIO API but does not use any symbols from it. Drop the include. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-8-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 1 - sound/soc/codecs/cs42l42.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 94bcab812629..2d11c5125f73 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 7785125b73ab..3d85ebc59489 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include From c6324cafd8370c2254f90a33b7327c45e7a58bbd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:38 +0100 Subject: [PATCH 2144/7721] ASoC: cs43130: Drop legacy includes This driver includes the legacy GPIO APIs and but does not use any symbols from any of them. Drop the includes. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-9-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 0f3ead84665f..b6d829bbe3cc 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include #include From 9c16cfe42d9fbfd258a3928b4a054d6b3ef932b0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Dec 2023 14:20:39 +0100 Subject: [PATCH 2145/7721] ASoC: cs4349: Drop legacy include This driver includes the legacy GPIO API but does not use any symbols from it. Drop the include. Acked-by: Charles Keepax Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231201-descriptors-sound-cirrus-v2-10-ee9f9d4655eb@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 9083228495d4..ca8f21aa4837 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include From 44df9a2a13211955ae98f8650e4dc04065e8ec0b Mon Sep 17 00:00:00 2001 From: Carl Vanderlip Date: Fri, 17 Nov 2023 10:43:36 -0700 Subject: [PATCH 2146/7721] accel/qaic: Increase number of in_reset states 'in_reset' holds the state of the device. As part of bringup, the device needs to be queried to check if it's in a valid state. Add a new state that indicates that the device is coming up, but not ready for users yet. Rename to 'dev_state' to better describe the variable. Signed-off-by: Carl Vanderlip Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231117174337.20174-2-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 13 +++++++++++-- drivers/accel/qaic/qaic_control.c | 5 +++-- drivers/accel/qaic/qaic_data.c | 16 ++++++++-------- drivers/accel/qaic/qaic_drv.c | 12 ++++++------ 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index bc40d52dc010..cb04f7f9cdb3 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -31,6 +31,15 @@ #define to_drm(qddev) (&(qddev)->drm) #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ +enum __packed dev_states { + /* Device is offline or will be very soon */ + QAIC_OFFLINE, + /* Device is booting, not clear if it's in a usable state */ + QAIC_BOOT, + /* Device is fully operational */ + QAIC_ONLINE, +}; + extern bool datapath_polling; struct qaic_user { @@ -121,8 +130,8 @@ struct qaic_device { struct workqueue_struct *cntl_wq; /* Synchronizes all the users of device during cleanup */ struct srcu_struct dev_lock; - /* true: Device under reset; false: Device not under reset */ - bool in_reset; + /* Track the state of the device during resets */ + enum dev_states dev_state; /* true: single MSI is used to operate device */ bool single_msi; /* diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index 84915824be54..9e8a8cbadf6b 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -1022,7 +1022,8 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u int xfer_count = 0; int retry_count; - if (qdev->in_reset) { + /* Allow QAIC_BOOT state since we need to check control protocol version */ + if (qdev->dev_state == QAIC_OFFLINE) { mutex_unlock(&qdev->cntl_mutex); return ERR_PTR(-ENODEV); } @@ -1306,7 +1307,7 @@ int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); srcu_read_unlock(&usr->qddev_lock, usr_rcu_id); return -ENODEV; diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 8998c28e566e..cf2898eda7ae 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -690,7 +690,7 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -749,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -970,7 +970,7 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1341,7 +1341,7 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1497,7 +1497,7 @@ void irq_polling_work(struct work_struct *work) rcu_id = srcu_read_lock(&dbc->ch_lock); while (1) { - if (dbc->qdev->in_reset) { + if (dbc->qdev->dev_state != QAIC_ONLINE) { srcu_read_unlock(&dbc->ch_lock, rcu_id); return; } @@ -1687,7 +1687,7 @@ int qaic_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1756,7 +1756,7 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1847,7 +1847,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index b12226385003..24b8680b2dbd 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -64,7 +64,7 @@ static int qaic_open(struct drm_device *dev, struct drm_file *file) int ret; rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto dev_unlock; } @@ -121,7 +121,7 @@ static void qaic_postclose(struct drm_device *dev, struct drm_file *file) if (qddev) { qdev = qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (!qdev->in_reset) { + if (qdev->dev_state == QAIC_ONLINE) { qaic_release_usr(qdev, usr); for (i = 0; i < qdev->num_dbc; ++i) if (qdev->dbc[i].usr && qdev->dbc[i].usr->handle == usr->handle) @@ -254,7 +254,7 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); - qdev->in_reset = false; + qdev->dev_state = QAIC_ONLINE; dev_set_drvdata(&mhi_dev->dev, qdev); qdev->cntl_ch = mhi_dev; @@ -291,7 +291,7 @@ static void qaic_notify_reset(struct qaic_device *qdev) { int i; - qdev->in_reset = true; + qdev->dev_state = QAIC_OFFLINE; /* wake up any waiters to avoid waiting for timeouts at sync */ wake_all_cntl(qdev); for (i = 0; i < qdev->num_dbc; ++i) @@ -313,7 +313,7 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset) release_dbc(qdev, i); if (exit_reset) - qdev->in_reset = false; + qdev->dev_state = QAIC_ONLINE; } static void cleanup_qdev(struct qaic_device *qdev) @@ -550,7 +550,7 @@ static void qaic_pci_reset_done(struct pci_dev *pdev) { struct qaic_device *qdev = pci_get_drvdata(pdev); - qdev->in_reset = false; + qdev->dev_state = QAIC_ONLINE; qaic_mhi_reset_done(qdev->mhi_cntrl); } From 5f0a0ebca2b98eeda10715433c7d9418ef2e6d01 Mon Sep 17 00:00:00 2001 From: Carl Vanderlip Date: Fri, 17 Nov 2023 10:43:37 -0700 Subject: [PATCH 2147/7721] accel/qaic: Expand DRM device lifecycle Currently the QAIC DRM device registers itself when the MHI QAIC_CONTROL channel becomes available. This is when the device is able to process workloads. However, the DRM driver also provides the debugfs interface bootlog for the device. If the device fails to boot to the QSM (which brings up the MHI QAIC_CONTROL channel), the bootlog won't be available for debugging why it failed to boot. Change when the DRM device registers itself from when QAIC_CONTROL is available to when the card is first probed on the PCI bus. Additionally, make the DRM driver persist through reset/error cases so the driver doesn't have to be reloaded to access the card again. Send KOBJ_ONLINE/OFFLINE uevents so userspace can know when DRM device is ready to handle requests. Signed-off-by: Carl Vanderlip Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231117174337.20174-3-quic_jhugo@quicinc.com --- Documentation/accel/qaic/qaic.rst | 9 +++++- drivers/accel/qaic/mhi_controller.c | 2 +- drivers/accel/qaic/qaic.h | 2 +- drivers/accel/qaic/qaic_drv.c | 44 +++++++++++------------------ 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/Documentation/accel/qaic/qaic.rst b/Documentation/accel/qaic/qaic.rst index f81020736ebf..efb7771273bb 100644 --- a/Documentation/accel/qaic/qaic.rst +++ b/Documentation/accel/qaic/qaic.rst @@ -93,8 +93,15 @@ commands (does not impact QAIC). uAPI ==== +QAIC creates an accel device per phsyical PCIe device. This accel device exists +for as long as the PCIe device is known to Linux. + +The PCIe device may not be in the state to accept requests from userspace at +all times. QAIC will trigger KOBJ_ONLINE/OFFLINE uevents to advertise when the +device can accept requests (ONLINE) and when the device is no longer accepting +requests (OFFLINE) because of a reset or other state transition. + QAIC defines a number of driver specific IOCTLs as part of the userspace API. -This section describes those APIs. DRM_IOCTL_QAIC_MANAGE This IOCTL allows userspace to send a NNC request to the QSM. The call will diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 5d3cc30009cc..832464f2833a 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -469,7 +469,7 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback re pci_err(qdev->pdev, "Fatal error received from device. Attempting to recover\n"); /* this event occurs in non-atomic context */ if (reason == MHI_CB_SYS_ERROR) - qaic_dev_reset_clean_local_state(qdev, true); + qaic_dev_reset_clean_local_state(qdev); } static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index cb04f7f9cdb3..582836f9538f 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -283,7 +283,7 @@ void wakeup_dbc(struct qaic_device *qdev, u32 dbc_id); void release_dbc(struct qaic_device *qdev, u32 dbc_id); void wake_all_cntl(struct qaic_device *qdev); -void qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset); +void qaic_dev_reset_clean_local_state(struct qaic_device *qdev); struct drm_gem_object *qaic_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 24b8680b2dbd..2a313eb69b12 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -43,9 +44,6 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); static bool link_up; static DEFINE_IDA(qaic_usrs); -static int qaic_create_drm_device(struct qaic_device *qdev, s32 partition_id); -static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id); - static void free_usr(struct kref *kref) { struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count); @@ -183,13 +181,6 @@ static int qaic_create_drm_device(struct qaic_device *qdev, s32 partition_id) qddev->partition_id = partition_id; - /* - * drm_dev_unregister() sets the driver data to NULL and - * drm_dev_register() does not update the driver data. During a SOC - * reset drm dev is unregistered and registered again leaving the - * driver data to NULL. - */ - dev_set_drvdata(to_accel_kdev(qddev), drm->accel); ret = drm_dev_register(drm, 0); if (ret) pci_dbg(qdev->pdev, "drm_dev_register failed %d\n", ret); @@ -203,7 +194,6 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id) struct drm_device *drm = to_drm(qddev); struct qaic_user *usr; - drm_dev_get(drm); drm_dev_unregister(drm); qddev->partition_id = 0; /* @@ -232,7 +222,6 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id) mutex_lock(&qddev->users_mutex); } mutex_unlock(&qddev->users_mutex); - drm_dev_put(drm); } static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) @@ -254,8 +243,6 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); - qdev->dev_state = QAIC_ONLINE; - dev_set_drvdata(&mhi_dev->dev, qdev); qdev->cntl_ch = mhi_dev; @@ -265,6 +252,7 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id return ret; } + qdev->dev_state = QAIC_BOOT; ret = get_cntl_version(qdev, NULL, &major, &minor); if (ret || major != CNTL_MAJOR || minor > CNTL_MINOR) { pci_err(qdev->pdev, "%s: Control protocol version (%d.%d) not supported. Supported version is (%d.%d). Ret: %d\n", @@ -272,8 +260,8 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id ret = -EINVAL; goto close_control; } - - ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); + qdev->dev_state = QAIC_ONLINE; + kobject_uevent(&(to_accel_kdev(qdev->qddev))->kobj, KOBJ_ONLINE); return ret; @@ -291,6 +279,7 @@ static void qaic_notify_reset(struct qaic_device *qdev) { int i; + kobject_uevent(&(to_accel_kdev(qdev->qddev))->kobj, KOBJ_OFFLINE); qdev->dev_state = QAIC_OFFLINE; /* wake up any waiters to avoid waiting for timeouts at sync */ wake_all_cntl(qdev); @@ -299,21 +288,15 @@ static void qaic_notify_reset(struct qaic_device *qdev) synchronize_srcu(&qdev->dev_lock); } -void qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset) +void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) { int i; qaic_notify_reset(qdev); - /* remove drmdevs to prevent new users from coming in */ - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); - /* start tearing things down */ for (i = 0; i < qdev->num_dbc; ++i) release_dbc(qdev, i); - - if (exit_reset) - qdev->dev_state = QAIC_ONLINE; } static void cleanup_qdev(struct qaic_device *qdev) @@ -338,6 +321,7 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de if (!qdev) return NULL; + qdev->dev_state = QAIC_OFFLINE; if (id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); @@ -499,15 +483,21 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto cleanup_qdev; } + ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); + if (ret) + goto cleanup_qdev; + qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); - goto cleanup_qdev; + goto cleanup_drm_dev; } return 0; +cleanup_drm_dev: + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); cleanup_qdev: cleanup_qdev(qdev); return ret; @@ -520,7 +510,8 @@ static void qaic_pci_remove(struct pci_dev *pdev) if (!qdev) return; - qaic_dev_reset_clean_local_state(qdev, false); + qaic_dev_reset_clean_local_state(qdev); + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); cleanup_qdev(qdev); } @@ -543,14 +534,13 @@ static void qaic_pci_reset_prepare(struct pci_dev *pdev) qaic_notify_reset(qdev); qaic_mhi_start_reset(qdev->mhi_cntrl); - qaic_dev_reset_clean_local_state(qdev, false); + qaic_dev_reset_clean_local_state(qdev); } static void qaic_pci_reset_done(struct pci_dev *pdev) { struct qaic_device *qdev = pci_get_drvdata(pdev); - qdev->dev_state = QAIC_ONLINE; qaic_mhi_reset_done(qdev->mhi_cntrl); } From 97f3880a33cd4a0c916242fd296aed975ad512d3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 7 Oct 2023 16:32:34 +0200 Subject: [PATCH 2148/7721] VMCI: Annotate struct vmci_handle_arr with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). Signed-off-by: Christophe JAILLET Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/56bef519d982218176b59bbba64a3a308d8733d5.1696689091.git.christophe.jaillet@wanadoo.fr Signed-off-by: Kees Cook --- drivers/misc/vmw_vmci/vmci_handle_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.h b/drivers/misc/vmw_vmci/vmci_handle_array.h index 96193f85be5b..b0e6b1956014 100644 --- a/drivers/misc/vmw_vmci/vmci_handle_array.h +++ b/drivers/misc/vmw_vmci/vmci_handle_array.h @@ -17,7 +17,7 @@ struct vmci_handle_arr { u32 max_capacity; u32 size; u32 pad; - struct vmci_handle entries[]; + struct vmci_handle entries[] __counted_by(capacity); }; #define VMCI_HANDLE_ARRAY_HEADER_SIZE \ From 446425648c5d19ff7564923863538e9fae93e916 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 10 Oct 2023 06:59:44 -0600 Subject: [PATCH 2149/7721] afs: Add __counted_by for struct afs_acl and use struct_size() Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). While there, use struct_size() helper, instead of the open-coded version, to calculate the size for the allocation of the whole flexible structure, including of course, the flexible-array member. This code was found with the help of Coccinelle, and audited and fixed manually. Signed-off-by: "Gustavo A. R. Silva" Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/ZSVKwBmxQ1amv47E@work Signed-off-by: Kees Cook --- fs/afs/internal.h | 2 +- fs/afs/xattr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index c9cef3782b4a..9d6f1aa65776 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1116,7 +1116,7 @@ extern void afs_fs_inline_bulk_status(struct afs_operation *); struct afs_acl { u32 size; - u8 data[]; + u8 data[] __counted_by(size); }; extern void afs_fs_fetch_acl(struct afs_operation *); diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index 64b2c0224f62..e19f396aa370 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -75,7 +75,7 @@ static bool afs_make_acl(struct afs_operation *op, { struct afs_acl *acl; - acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); + acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); if (!acl) { afs_op_nomem(op); return false; From 3b2894c967377a49be084b9b39b21b2315bd9b2c Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 16 Oct 2023 22:38:20 +0000 Subject: [PATCH 2150/7721] drm/modes: replace deprecated strncpy with strscpy_pad `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We should NUL-pad as there are full struct copies happening in places: | struct drm_mode_modeinfo umode; | | ... | struct drm_property_blob *blob; | | drm_mode_convert_to_umode(&umode, mode); | blob = drm_property_create_blob(crtc->dev, | sizeof(umode), &umode); A suitable replacement is `strscpy_pad` due to the fact that it guarantees both NUL-termination and NUL-padding on the destination buffer. Additionally, replace size macro `DRM_DISPLAY_MODE_LEN` with sizeof() to more directly tie the maximum buffer size to the destination buffer: | struct drm_display_mode { | ... | char name[DRM_DISPLAY_MODE_LEN]; Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Cc: Xu Panda Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231016-strncpy-drivers-gpu-drm-drm_modes-c-v2-1-d0b60686e1c6@google.com Signed-off-by: Kees Cook --- drivers/gpu/drm/drm_modes.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac9a406250c5..893f52ee4926 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2617,8 +2617,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, break; } - strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); - out->name[DRM_DISPLAY_MODE_LEN-1] = 0; + strscpy_pad(out->name, in->name, sizeof(out->name)); } /** @@ -2659,8 +2658,7 @@ int drm_mode_convert_umode(struct drm_device *dev, * useful for the kernel->userspace direction anyway. */ out->type = in->type & DRM_MODE_TYPE_ALL; - strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); - out->name[DRM_DISPLAY_MODE_LEN-1] = 0; + strscpy_pad(out->name, in->name, sizeof(out->name)); /* Clearing picture aspect ratio bits from out flags, * as the aspect-ratio information is not stored in From 576b75f93b3d3c408235808f689453f1ed891486 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 18 Oct 2023 22:48:49 +0000 Subject: [PATCH 2151/7721] nvme-fabrics: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect both data->subsysnqn and data->hostnqn to be NUL-terminated based on their usage with format specifier ("%s"): fabrics.c: 322: dev_err(ctrl->device, 323: "%s, subsysnqn \"%s\"\n", 324: inv_data, data->subsysnqn); ... 349: dev_err(ctrl->device, 350: "Connect for subsystem %s is not allowed, hostnqn: %s\n", 351: data->subsysnqn, data->hostnqn); Moreover, there's no need to NUL-pad since `data` is zero-allocated already in fabrics.c: 383: data = kzalloc(sizeof(*data), GFP_KERNEL); ... therefore any further NUL-padding is rendered useless. Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. I opted not to switch NVMF_NQN_SIZE to sizeof(data->xyz) because the size is defined as: | /* NQN names in commands fields specified one size */ | #define NVMF_NQN_FIELD_LEN 256 ... while NVMF_NQN_SIZE is defined as: | /* However the max length of a qualified name is another size */ | #define NVMF_NQN_SIZE 223 Since 223 seems pretty magic, I'm not going to touch it. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231018-strncpy-drivers-nvme-host-fabrics-c-v1-1-b6677df40a35@google.com Signed-off-by: Kees Cook --- drivers/nvme/host/fabrics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 4673ead69c5f..830bf01df4b8 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -387,8 +387,8 @@ static struct nvmf_connect_data *nvmf_connect_data_prep(struct nvme_ctrl *ctrl, uuid_copy(&data->hostid, &ctrl->opts->host->id); data->cntlid = cpu_to_le16(cntlid); - strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE); - strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE); + strscpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE); + strscpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE); return data; } From ab7e8bb6e077a55ae5ac1a4bb4ebba85470d47e5 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 19 Oct 2023 17:54:15 +0000 Subject: [PATCH 2152/7721] nvdimm/btt: replace deprecated strncpy with strscpy Found with grep. strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect super->signature to be NUL-terminated based on its usage with memcmp against a NUL-term'd buffer: btt_devs.c: 253 | if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) btt.h: 13 | #define BTT_SIG "BTT_ARENA_INFO\0" NUL-padding is not required as `super` is already zero-allocated: btt.c: 985 | super = kzalloc(sizeof(struct btt_sb), GFP_NOIO); ... rendering any additional NUL-padding superfluous. Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also use the more idiomatic strscpy usage of (dest, src, sizeof(dest)) instead of (dest, src, XYZ_LEN) for buffers that the compiler can determine the size of. This more tightly correlates the destination buffer to the amount of bytes copied. Side note, this pattern of memcmp() on two NUL-terminated strings should really be changed to just a strncmp(), if i'm not mistaken? I see multiple instances of this pattern in this system: | if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) | return false; where BIT_SIG is defined (weirdly) as a double NUL-terminated string: | #define BTT_SIG "BTT_ARENA_INFO\0" Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231019-strncpy-drivers-nvdimm-btt-c-v2-1-366993878cf0@google.com Signed-off-by: Kees Cook --- drivers/nvdimm/btt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index d5593b0dc700..9372c36e8f76 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -986,7 +986,7 @@ static int btt_arena_write_layout(struct arena_info *arena) if (!super) return -ENOMEM; - strncpy(super->signature, BTT_SIG, BTT_SIG_LEN); + strscpy(super->signature, BTT_SIG, sizeof(super->signature)); export_uuid(super->uuid, nd_btt->uuid); export_uuid(super->parent_uuid, parent_uuid); super->flags = cpu_to_le32(arena->flags); From e5a4975ca463e91c2009f5950e0156f0b857eb10 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 19 Oct 2023 21:34:35 +0000 Subject: [PATCH 2153/7721] nvme-fc: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. Let's instead use strscpy() [2] as it guarantees NUL-termination on the destination buffer. Moreover, there is no need to use: | min(FCNVME_ASSOC_HOSTNQN_LEN, NVMF_NQN_SIZE)); I imagine this was originally done to make sure the destination buffer is NUL-terminated by ensuring we copy a number of bytes less than the size of our destination, thus leaving some NUL-bytes at the end. However, with strscpy(), we no longer need to do this and we can instead opt for the more idiomatic strscpy() usage of: | strscpy(dest, src, sizeof(dest)) Also, no NUL-padding is required as lsop is zero-allocated: | lsop = kzalloc((sizeof(*lsop) + | sizeof(*assoc_rqst) + sizeof(*assoc_acc) + | ctrl->lport->ops->lsrqst_priv_sz), GFP_KERNEL); ... and assoc_rqst points to a field in lsop: | assoc_rqst = (struct fcnvme_ls_cr_assoc_rqst *)&lsop[1]; Therefore, any additional NUL-byte assignments (like the ones that strncpy() makes) are redundant. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Similar-to: https://lore.kernel.org/all/20231018-strncpy-drivers-nvme-host-fabrics-c-v1-1-b6677df40a35@google.com/ Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231019-strncpy-drivers-nvme-host-fc-c-v1-1-5805c15e4b49@google.com Signed-off-by: Kees Cook --- drivers/nvme/host/fc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 49c3e46eaa1e..a719ca2cd406 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1218,10 +1218,10 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, /* Linux supports only Dynamic controllers */ assoc_rqst->assoc_cmd.cntlid = cpu_to_be16(0xffff); uuid_copy(&assoc_rqst->assoc_cmd.hostid, &ctrl->ctrl.opts->host->id); - strncpy(assoc_rqst->assoc_cmd.hostnqn, ctrl->ctrl.opts->host->nqn, - min(FCNVME_ASSOC_HOSTNQN_LEN, NVMF_NQN_SIZE)); - strncpy(assoc_rqst->assoc_cmd.subnqn, ctrl->ctrl.opts->subsysnqn, - min(FCNVME_ASSOC_SUBNQN_LEN, NVMF_NQN_SIZE)); + strscpy(assoc_rqst->assoc_cmd.hostnqn, ctrl->ctrl.opts->host->nqn, + sizeof(assoc_rqst->assoc_cmd.hostnqn)); + strscpy(assoc_rqst->assoc_cmd.subnqn, ctrl->ctrl.opts->subsysnqn, + sizeof(assoc_rqst->assoc_cmd.subnqn)); lsop->queue = queue; lsreq->rqstaddr = assoc_rqst; From aabf7c37dfbce3e5fe24f0c86a34bc8f2f63cee8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 29 Nov 2023 13:44:04 -0800 Subject: [PATCH 2154/7721] lkdtm: Add kfence read after free crash type Add the ability to allocate memory from kfence and trigger a read after free on that memory to validate that kfence is working properly. This is used by ChromeOS integration tests to validate that kfence errors can be collected on user devices and parsed properly. Cc: Alexander Potapenko Acked-by: Marco Elver Cc: Dmitry Vyukov Cc: Andrew Morton Cc: kasan-dev@googlegroups.com Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20231129214413.3156334-1-swboyd@chromium.org Signed-off-by: Kees Cook --- drivers/misc/lkdtm/heap.c | 60 +++++++++++++++++++++++++++++++++++++++ include/linux/kfence.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 0ce4cbf6abda..4f467d3972a6 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -4,6 +4,7 @@ * page allocation and slab allocations. */ #include "lkdtm.h" +#include #include #include #include @@ -132,6 +133,64 @@ static void lkdtm_READ_AFTER_FREE(void) kfree(val); } +static void lkdtm_KFENCE_READ_AFTER_FREE(void) +{ + int *base, val, saw; + unsigned long timeout, resched_after; + size_t len = 1024; + /* + * The slub allocator will use the either the first word or + * the middle of the allocation to store the free pointer, + * depending on configurations. Store in the second word to + * avoid running into the freelist. + */ + size_t offset = sizeof(*base); + + /* + * 100x the sample interval should be more than enough to ensure we get + * a KFENCE allocation eventually. + */ + timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval); + /* + * Especially for non-preemption kernels, ensure the allocation-gate + * timer can catch up: after @resched_after, every failed allocation + * attempt yields, to ensure the allocation-gate timer is scheduled. + */ + resched_after = jiffies + msecs_to_jiffies(kfence_sample_interval); + do { + base = kmalloc(len, GFP_KERNEL); + if (!base) { + pr_err("FAIL: Unable to allocate kfence memory!\n"); + return; + } + + if (is_kfence_address(base)) { + val = 0x12345678; + base[offset] = val; + pr_info("Value in memory before free: %x\n", base[offset]); + + kfree(base); + + pr_info("Attempting bad read from freed memory\n"); + saw = base[offset]; + if (saw != val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + } else { + pr_err("FAIL: Memory was not poisoned!\n"); + pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free"); + } + return; + } + + kfree(base); + if (time_after(jiffies, resched_after)) + cond_resched(); + } while (time_before(jiffies, timeout)); + + pr_err("FAIL: kfence memory never allocated!\n"); +} + static void lkdtm_WRITE_BUDDY_AFTER_FREE(void) { unsigned long p = __get_free_page(GFP_KERNEL); @@ -327,6 +386,7 @@ static struct crashtype crashtypes[] = { CRASHTYPE(VMALLOC_LINEAR_OVERFLOW), CRASHTYPE(WRITE_AFTER_FREE), CRASHTYPE(READ_AFTER_FREE), + CRASHTYPE(KFENCE_READ_AFTER_FREE), CRASHTYPE(WRITE_BUDDY_AFTER_FREE), CRASHTYPE(READ_BUDDY_AFTER_FREE), CRASHTYPE(SLAB_INIT_ON_ALLOC), diff --git a/include/linux/kfence.h b/include/linux/kfence.h index 401af4757514..88100cc9caba 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -223,6 +223,8 @@ bool __kfence_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *sla #else /* CONFIG_KFENCE */ +#define kfence_sample_interval (0) + static inline bool is_kfence_address(const void *addr) { return false; } static inline void kfence_alloc_pool_and_metadata(void) { } static inline void kfence_init(void) { } From 12cd3cd8c797e07afcc47bc4afa760e4ec75e9d7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Nov 2023 17:11:42 +0200 Subject: [PATCH 2155/7721] params: Introduce the param_unknown_fn type Introduce a new type for the callback to parse an unknown argument. This unifies function prototypes which takes that as a parameter. Reviewed-by: Luis Chamberlain Reviewed-by: Kees Cook Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231120151419.1661807-2-andriy.shevchenko@linux.intel.com Signed-off-by: Kees Cook --- include/linux/moduleparam.h | 6 +++--- kernel/params.c | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 4fa9726bc328..bfb85fd13e1f 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -385,6 +385,8 @@ extern bool parameq(const char *name1, const char *name2); */ extern bool parameqn(const char *name1, const char *name2, size_t n); +typedef int (*parse_unknown_fn)(char *param, char *val, const char *doing, void *arg); + /* Called on module insert or kernel boot */ extern char *parse_args(const char *name, char *args, @@ -392,9 +394,7 @@ extern char *parse_args(const char *name, unsigned num, s16 level_min, s16 level_max, - void *arg, - int (*unknown)(char *param, char *val, - const char *doing, void *arg)); + void *arg, parse_unknown_fn unknown); /* Called by module remove. */ #ifdef CONFIG_SYSFS diff --git a/kernel/params.c b/kernel/params.c index 2d4a0564697e..626fa8265932 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -120,9 +120,7 @@ static int parse_one(char *param, unsigned num_params, s16 min_level, s16 max_level, - void *arg, - int (*handle_unknown)(char *param, char *val, - const char *doing, void *arg)) + void *arg, parse_unknown_fn handle_unknown) { unsigned int i; int err; @@ -165,9 +163,7 @@ char *parse_args(const char *doing, unsigned num, s16 min_level, s16 max_level, - void *arg, - int (*unknown)(char *param, char *val, - const char *doing, void *arg)) + void *arg, parse_unknown_fn unknown) { char *param, *val, *err = NULL; From fd0cd057a1b7351604daa6ffc91dfe28adf7225d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Nov 2023 17:11:43 +0200 Subject: [PATCH 2156/7721] params: Do not go over the limit when getting the string length We can use strnlen() even on early stages and it prevents from going over the string boundaries in case it's already too long. Reviewed-by: Luis Chamberlain Reviewed-by: Kees Cook Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231120151419.1661807-3-andriy.shevchenko@linux.intel.com Signed-off-by: Kees Cook --- kernel/params.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/params.c b/kernel/params.c index 626fa8265932..f8e3c4139854 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -260,7 +260,10 @@ EXPORT_SYMBOL_GPL(param_set_uint_minmax); int param_set_charp(const char *val, const struct kernel_param *kp) { - if (strlen(val) > 1024) { + size_t len, maxlen = 1024; + + len = strnlen(val, maxlen + 1); + if (len == maxlen + 1) { pr_err("%s: string parameter too long\n", kp->name); return -ENOSPC; } @@ -270,7 +273,7 @@ int param_set_charp(const char *val, const struct kernel_param *kp) /* This is a hack. We can't kmalloc in early boot, and we * don't need to; this mangled commandline is preserved. */ if (slab_is_available()) { - *(char **)kp->arg = kmalloc_parameter(strlen(val)+1); + *(char **)kp->arg = kmalloc_parameter(len + 1); if (!*(char **)kp->arg) return -ENOMEM; strcpy(*(char **)kp->arg, val); @@ -508,7 +511,7 @@ int param_set_copystring(const char *val, const struct kernel_param *kp) { const struct kparam_string *kps = kp->str; - if (strlen(val)+1 > kps->maxlen) { + if (strnlen(val, kps->maxlen) == kps->maxlen) { pr_err("%s: string doesn't fit in %u chars.\n", kp->name, kps->maxlen-1); return -ENOSPC; From 0fc79cbc937f2a754a302a710a94b68c61d0a89a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Nov 2023 17:11:44 +0200 Subject: [PATCH 2157/7721] params: Use size_add() for kmalloc() Prevent allocations from integer overflow by using size_add(). Reviewed-by: Luis Chamberlain Reviewed-by: Kees Cook Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231120151419.1661807-4-andriy.shevchenko@linux.intel.com Signed-off-by: Kees Cook --- kernel/params.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/params.c b/kernel/params.c index f8e3c4139854..c3a029fe183d 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,7 @@ static void *kmalloc_parameter(unsigned int size) { struct kmalloced_param *p; - p = kmalloc(sizeof(*p) + size, GFP_KERNEL); + p = kmalloc(size_add(sizeof(*p), size), GFP_KERNEL); if (!p) return NULL; From a05f096c2c0ca52e8fd34740c7d4b53ab3e7123e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Nov 2023 17:11:45 +0200 Subject: [PATCH 2158/7721] params: Sort headers Sort the headers in alphabetic order in order to ease the maintenance for this part. Reviewed-by: Luis Chamberlain Reviewed-by: Kees Cook Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231120151419.1661807-5-andriy.shevchenko@linux.intel.com Signed-off-by: Kees Cook --- kernel/params.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/params.c b/kernel/params.c index c3a029fe183d..eb55b32399b4 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -3,18 +3,18 @@ Copyright (C) 2001 Rusty Russell. */ -#include -#include -#include -#include -#include -#include +#include #include #include +#include +#include +#include +#include +#include #include -#include -#include #include +#include +#include #ifdef CONFIG_SYSFS /* Protects all built-in parameters, modules use their own param_lock */ From b5e3f86a47d34f7b8af899f8cc70520f6daf8b53 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Nov 2023 17:11:46 +0200 Subject: [PATCH 2159/7721] params: Fix multi-line comment style The multi-line comment style in the file is rather arbitrary. Make it follow the standard one. Reviewed-by: Luis Chamberlain Reviewed-by: Kees Cook Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231120151419.1661807-6-andriy.shevchenko@linux.intel.com Signed-off-by: Kees Cook --- kernel/params.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/kernel/params.c b/kernel/params.c index eb55b32399b4..2e447f8ae183 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Helpers for initial module or kernel cmdline parsing - Copyright (C) 2001 Rusty Russell. - -*/ +/* + * Helpers for initial module or kernel cmdline parsing + * Copyright (C) 2001 Rusty Russell. + */ #include #include #include @@ -271,8 +271,10 @@ int param_set_charp(const char *val, const struct kernel_param *kp) maybe_kfree_parameter(*(char **)kp->arg); - /* This is a hack. We can't kmalloc in early boot, and we - * don't need to; this mangled commandline is preserved. */ + /* + * This is a hack. We can't kmalloc() in early boot, and we + * don't need to; this mangled commandline is preserved. + */ if (slab_is_available()) { *(char **)kp->arg = kmalloc_parameter(len + 1); if (!*(char **)kp->arg) @@ -743,8 +745,10 @@ void module_param_sysfs_remove(struct module *mod) { if (mod->mkobj.mp) { sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); - /* We are positive that no one is using any param - * attrs at this point. Deallocate immediately. */ + /* + * We are positive that no one is using any param + * attrs at this point. Deallocate immediately. + */ free_module_param_attrs(&mod->mkobj); } } From 8a3750ecf8104de55c569ffbe844a85aa9d5deaa Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 30 Nov 2023 12:56:08 -0800 Subject: [PATCH 2160/7721] tracing/uprobe: Replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated[1]. Additionally, it returns the size of the source string, not the resulting size of the destination string. In an effort to remove strlcpy() completely[2], replace strlcpy() here with strscpy(). The negative return value is already handled by this code so no new handling is needed here. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1] Link: https://github.com/KSPP/linux/issues/89 [2] Cc: Steven Rostedt Cc: Masami Hiramatsu Cc: linux-trace-kernel@vger.kernel.org Acked-by: "Masami Hiramatsu (Google)" Link: https://lore.kernel.org/r/20231130205607.work.463-kees@kernel.org Signed-off-by: Kees Cook --- kernel/trace/trace_uprobe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 99c051de412a..a84b85d8aac1 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -151,7 +151,7 @@ fetch_store_string(unsigned long addr, void *dest, void *base) return -ENOMEM; if (addr == FETCH_TOKEN_COMM) - ret = strlcpy(dst, current->comm, maxlen); + ret = strscpy(dst, current->comm, maxlen); else ret = strncpy_from_user(dst, src, maxlen); if (ret >= 0) { From 29215a7d43c77466f2d7e6c264942e6bc8e06cd8 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 1 Dec 2023 10:38:35 -0800 Subject: [PATCH 2161/7721] f2fs: allow checkpoint=disable for zoned block device Let's allow checkpoint=disable back for zoned block device. It's very risky as the feature relies on fsck or runtime recovery which matches the write pointers again if the device rebooted while disabling the checkpoint. Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 033af907c3b1..617340e9ea7f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1422,11 +1422,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) } } - if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) { - f2fs_err(sbi, "LFS is not compatible with checkpoint=disable"); - return -EINVAL; - } - if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) { f2fs_err(sbi, "LFS is not compatible with ATGC"); return -EINVAL; From 625ed9457de50d7726ccb3f2bc4e01e543ceb126 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 1 Dec 2023 14:53:31 +0100 Subject: [PATCH 2162/7721] ASoC: qcom: sc8280xp: set card driver name from match data Sound machine drivers for all newer Qualcomm SoC platforms are the exactly same, therefore it makes sense to use same machine driver for newer platforms as well. Choice of sound topology and user-space Alsa UCM files depends however on card driver name, which must be customized per each board. Allow such customization by using driver match data as sound card driver name. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231201135332.154017-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 7c20b25ba3de..77722d6416b8 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -14,8 +14,6 @@ #include "common.h" #include "sdw.h" -#define DRIVER_NAME "sc8280xp" - struct sc8280xp_snd_data { bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; @@ -146,13 +144,13 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) if (ret) return ret; - card->driver_name = DRIVER_NAME; + card->driver_name = of_device_get_match_data(dev); sc8280xp_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } static const struct of_device_id snd_sc8280xp_dt_match[] = { - {.compatible = "qcom,sc8280xp-sndcard",}, + {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, {} }; From fdcaecfc71e2f4ab70ce9469f14dd64c23bf401a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 1 Dec 2023 14:53:32 +0100 Subject: [PATCH 2163/7721] ASoC: qcom: sc8280xp: Add support for SM8450 and SM8550 Add compatibles for sound card on Qualcomm SM8450 and SM8550 boards. The compatibles were already documented. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231201135332.154017-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 77722d6416b8..249a43e1dee3 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -151,6 +151,8 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) static const struct of_device_id snd_sc8280xp_dt_match[] = { {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, + {.compatible = "qcom,sm8450-sndcard", "sm8450"}, + {.compatible = "qcom,sm8550-sndcard", "sm8550"}, {} }; From 8570c27932e132d2663e8120311891deb2a853de Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Aug 2023 14:54:54 -0700 Subject: [PATCH 2164/7721] drm/syncobj: Add deadline support for syncobj waits Add a new flag to let userspace provide a deadline as a hint for syncobj and timeline waits. This gives a hint to the driver signaling the backing fences about how soon userspace needs it to compete work, so it can adjust GPU frequency accordingly. An immediate deadline can be given to provide something equivalent to i915 "wait boost". v2: Use absolute u64 ns value for deadline hint, drop cap and driver feature flag in favor of allowing count_handles==0 as a way for userspace to probe kernel for support of new flag v3: More verbose comments about UAPI v4: Fix negative zero, s/deadline_ns/deadline_nsec/ for consistency with existing ioctl struct fields v5: Comment/description typo fixes Signed-off-by: Rob Clark Reviewed-by: Tvrtko Ursulin [DB: fixed checkpatch warnings] Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20230823215458.203366-2-robdclark@gmail.com --- drivers/gpu/drm/drm_syncobj.c | 64 ++++++++++++++++++++++++++++------- include/uapi/drm/drm.h | 17 ++++++++++ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 01da6789d044..cbb65b7ba425 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -126,6 +126,11 @@ * synchronize between the two. * This requirement is inherited from the Vulkan fence API. * + * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE is set, the ioctl will also set + * a fence deadline hint on the backing fences before waiting, to provide the + * fence signaler with an appropriate sense of urgency. The deadline is + * specified as an absolute &CLOCK_MONOTONIC value in units of ns. + * * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj * handles as well as an array of u64 points and does a host-side wait on all * of syncobj fences at the given points simultaneously. @@ -1027,7 +1032,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, uint32_t count, uint32_t flags, signed long timeout, - uint32_t *idx) + uint32_t *idx, + ktime_t *deadline) { struct syncobj_wait_entry *entries; struct dma_fence *fence; @@ -1108,6 +1114,15 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]); } + if (deadline) { + for (i = 0; i < count; ++i) { + fence = entries[i].fence; + if (!fence) + continue; + dma_fence_set_deadline(fence, *deadline); + } + } + do { set_current_state(TASK_INTERRUPTIBLE); @@ -1206,7 +1221,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, struct drm_file *file_private, struct drm_syncobj_wait *wait, struct drm_syncobj_timeline_wait *timeline_wait, - struct drm_syncobj **syncobjs, bool timeline) + struct drm_syncobj **syncobjs, bool timeline, + ktime_t *deadline) { signed long timeout = 0; uint32_t first = ~0; @@ -1217,7 +1233,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, NULL, wait->count_handles, wait->flags, - timeout, &first); + timeout, &first, + deadline); if (timeout < 0) return timeout; wait->first_signaled = first; @@ -1227,7 +1244,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, u64_to_user_ptr(timeline_wait->points), timeline_wait->count_handles, timeline_wait->flags, - timeout, &first); + timeout, &first, + deadline); if (timeout < 0) return timeout; timeline_wait->first_signaled = first; @@ -1298,17 +1316,22 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_wait *args = data; struct drm_syncobj **syncobjs; + unsigned int possible_flags; + ktime_t t, *tp = NULL; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) return -EOPNOTSUPP; - if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)) + possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + + if (args->flags & ~possible_flags) return -EINVAL; if (args->count_handles == 0) - return -EINVAL; + return 0; ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), @@ -1317,8 +1340,13 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; + if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { + t = ns_to_ktime(args->deadline_nsec); + tp = &t; + } + ret = drm_syncobj_array_wait(dev, file_private, - args, NULL, syncobjs, false); + args, NULL, syncobjs, false, tp); drm_syncobj_array_free(syncobjs, args->count_handles); @@ -1331,18 +1359,23 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_timeline_wait *args = data; struct drm_syncobj **syncobjs; + unsigned int possible_flags; + ktime_t t, *tp = NULL; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) + possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + + if (args->flags & ~possible_flags) return -EINVAL; if (args->count_handles == 0) - return -EINVAL; + return 0; ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), @@ -1351,8 +1384,13 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; + if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { + t = ns_to_ktime(args->deadline_nsec); + tp = &t; + } + ret = drm_syncobj_array_wait(dev, file_private, - NULL, args, syncobjs, true); + NULL, args, syncobjs, true, tp); drm_syncobj_array_free(syncobjs, args->count_handles); diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 91943e5ce010..16122819edfe 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -926,6 +926,7 @@ struct drm_syncobj_transfer { #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE (1 << 3) /* set fence deadline to deadline_nsec */ struct drm_syncobj_wait { __u64 handles; /* absolute timeout */ @@ -934,6 +935,14 @@ struct drm_syncobj_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; }; struct drm_syncobj_timeline_wait { @@ -946,6 +955,14 @@ struct drm_syncobj_timeline_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; }; /** From 63ee44540205d993854f143a5ab1d7d9e63ffcf1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Aug 2023 14:54:55 -0700 Subject: [PATCH 2165/7721] dma-buf/sync_file: Add SET_DEADLINE ioctl The initial purpose is for igt tests, but this would also be useful for compositors that wait until close to vblank deadline to make decisions about which frame to show. The igt tests can be found at: https://gitlab.freedesktop.org/robclark/igt-gpu-tools/-/commits/fence-deadline v2: Clarify the timebase, add link to igt tests v3: Use u64 value in ns to express deadline. v4: More doc Signed-off-by: Rob Clark Acked-by: Pekka Paalanen Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20230823215458.203366-3-robdclark@gmail.com --- drivers/dma-buf/dma-fence.c | 3 ++- drivers/dma-buf/sync_file.c | 19 +++++++++++++++++++ include/uapi/linux/sync_file.h | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 8aa8f8cb7071..e0fd99e61a2d 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -934,7 +934,8 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout); * the GPU's devfreq to reduce frequency, when in fact the opposite is what is * needed. * - * To this end, deadline hint(s) can be set on a &dma_fence via &dma_fence_set_deadline. + * To this end, deadline hint(s) can be set on a &dma_fence via &dma_fence_set_deadline + * (or indirectly via userspace facing ioctls like &sync_set_deadline). * The deadline hint provides a way for the waiting driver, or userspace, to * convey an appropriate sense of urgency to the signaling driver. * diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 2e9a316c596a..d9b1c1b2a72b 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -347,6 +347,22 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, return ret; } +static int sync_file_ioctl_set_deadline(struct sync_file *sync_file, + unsigned long arg) +{ + struct sync_set_deadline ts; + + if (copy_from_user(&ts, (void __user *)arg, sizeof(ts))) + return -EFAULT; + + if (ts.pad) + return -EINVAL; + + dma_fence_set_deadline(sync_file->fence, ns_to_ktime(ts.deadline_ns)); + + return 0; +} + static long sync_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -359,6 +375,9 @@ static long sync_file_ioctl(struct file *file, unsigned int cmd, case SYNC_IOC_FILE_INFO: return sync_file_ioctl_fence_info(sync_file, arg); + case SYNC_IOC_SET_DEADLINE: + return sync_file_ioctl_set_deadline(sync_file, arg); + default: return -ENOTTY; } diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h index ff0a931833e2..ff1f38889dcf 100644 --- a/include/uapi/linux/sync_file.h +++ b/include/uapi/linux/sync_file.h @@ -76,6 +76,27 @@ struct sync_file_info { __u64 sync_fence_info; }; +/** + * struct sync_set_deadline - SYNC_IOC_SET_DEADLINE - set a deadline hint on a fence + * @deadline_ns: absolute time of the deadline + * @pad: must be zero + * + * Allows userspace to set a deadline on a fence, see &dma_fence_set_deadline + * + * The timebase for the deadline is CLOCK_MONOTONIC (same as vblank). For + * example + * + * clock_gettime(CLOCK_MONOTONIC, &t); + * deadline_ns = (t.tv_sec * 1000000000L) + t.tv_nsec + ns_until_deadline + */ +struct sync_set_deadline { + __u64 deadline_ns; + /* Not strictly needed for alignment but gives some possibility + * for future extension: + */ + __u64 pad; +}; + #define SYNC_IOC_MAGIC '>' /* @@ -87,5 +108,6 @@ struct sync_file_info { #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info) +#define SYNC_IOC_SET_DEADLINE _IOW(SYNC_IOC_MAGIC, 5, struct sync_set_deadline) #endif /* _UAPI_LINUX_SYNC_H */ From 70e67aaec2f4706df0006423eebca813b00f5840 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Aug 2023 14:54:56 -0700 Subject: [PATCH 2166/7721] dma-buf/sw_sync: Add fence deadline support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This consists of simply storing the most recent deadline, and adding an ioctl to retrieve the deadline. This can be used in conjunction with the SET_DEADLINE ioctl on a fence fd for testing. Ie. create various sw_sync fences, merge them into a fence-array, set deadline on the fence-array and confirm that it is propagated properly to each fence. v2: Switch UABI to express deadline as u64 v3: More verbose UAPI docs, show how to convert from timespec v4: Better comments, track the soonest deadline, as a normal fence implementation would, return an error if no deadline set. Signed-off-by: Rob Clark Reviewed-by: Christian König Acked-by: Pekka Paalanen Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20230823215458.203366-4-robdclark@gmail.com --- drivers/dma-buf/sw_sync.c | 82 ++++++++++++++++++++++++++++++++++++ drivers/dma-buf/sync_debug.h | 2 + 2 files changed, 84 insertions(+) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index f0a35277fd84..c353029789cf 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -52,12 +52,33 @@ struct sw_sync_create_fence_data { __s32 fence; /* fd of new fence */ }; +/** + * struct sw_sync_get_deadline - get the deadline hint of a sw_sync fence + * @deadline_ns: absolute time of the deadline + * @pad: must be zero + * @fence_fd: the sw_sync fence fd (in) + * + * Return the earliest deadline set on the fence. The timebase for the + * deadline is CLOCK_MONOTONIC (same as vblank). If there is no deadline + * set on the fence, this ioctl will return -ENOENT. + */ +struct sw_sync_get_deadline { + __u64 deadline_ns; + __u32 pad; + __s32 fence_fd; +}; + #define SW_SYNC_IOC_MAGIC 'W' #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ struct sw_sync_create_fence_data) #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) +#define SW_SYNC_GET_DEADLINE _IOWR(SW_SYNC_IOC_MAGIC, 2, \ + struct sw_sync_get_deadline) + + +#define SW_SYNC_HAS_DEADLINE_BIT DMA_FENCE_FLAG_USER_BITS static const struct dma_fence_ops timeline_fence_ops; @@ -171,6 +192,22 @@ static void timeline_fence_timeline_value_str(struct dma_fence *fence, snprintf(str, size, "%d", parent->value); } +static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadline) +{ + struct sync_pt *pt = dma_fence_to_sync_pt(fence); + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) { + if (ktime_before(deadline, pt->deadline)) + pt->deadline = deadline; + } else { + pt->deadline = deadline; + __set_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags); + } + spin_unlock_irqrestore(fence->lock, flags); +} + static const struct dma_fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, @@ -179,6 +216,7 @@ static const struct dma_fence_ops timeline_fence_ops = { .release = timeline_fence_release, .fence_value_str = timeline_fence_value_str, .timeline_value_str = timeline_fence_timeline_value_str, + .set_deadline = timeline_fence_set_deadline, }; /** @@ -387,6 +425,47 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) return 0; } +static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long arg) +{ + struct sw_sync_get_deadline data; + struct dma_fence *fence; + unsigned long flags; + struct sync_pt *pt; + int ret = 0; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) + return -EFAULT; + + if (data.deadline_ns || data.pad) + return -EINVAL; + + fence = sync_file_get_fence(data.fence_fd); + if (!fence) + return -EINVAL; + + pt = dma_fence_to_sync_pt(fence); + if (!pt) + return -EINVAL; + + spin_lock_irqsave(fence->lock, flags); + if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) { + data.deadline_ns = ktime_to_ns(pt->deadline); + } else { + ret = -ENOENT; + } + spin_unlock_irqrestore(fence->lock, flags); + + dma_fence_put(fence); + + if (ret) + return ret; + + if (copy_to_user((void __user *)arg, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + static long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -399,6 +478,9 @@ static long sw_sync_ioctl(struct file *file, unsigned int cmd, case SW_SYNC_IOC_INC: return sw_sync_ioctl_inc(obj, arg); + case SW_SYNC_GET_DEADLINE: + return sw_sync_ioctl_get_deadline(obj, arg); + default: return -ENOTTY; } diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index 6176e52ba2d7..a1bdd62efccd 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -55,11 +55,13 @@ static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) * @base: base fence object * @link: link on the sync timeline's list * @node: node in the sync timeline's tree + * @deadline: the earliest fence deadline hint */ struct sync_pt { struct dma_fence base; struct list_head link; struct rb_node node; + ktime_t deadline; }; extern const struct file_operations sw_sync_debugfs_fops; From e6c0de5f445091d250b75dabc4c60dd2643b8c98 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Mon, 11 Sep 2023 15:16:27 -0700 Subject: [PATCH 2167/7721] drm/msm/dpu: try multirect based on mdp clock limits It's certainly possible that for large resolutions a single DPU SSPP cannot process the image without exceeding the MDP clock limits but it can still process it in multirect mode because the source rectangles will get divided and can fall within the MDP clock limits. If the SSPP cannot process the image even in multirect mode, then it will be rejected in dpu_plane_atomic_check_pipe(). Hence try using multirect for resolutions which cannot be processed by a single SSPP without exceeding the MDP clock limits. changes in v2: - use crtc_state's adjusted_mode instead of mode - fix the UBWC condition to check maxlinewidth Signed-off-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/556817/ Link: https://lore.kernel.org/r/20230911221627.9569-2-quic_abhinavk@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 3eef5e025e12..1e0da38c6f2a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -824,6 +824,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, plane); int ret = 0, min_scale; struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); + u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_sw_pipe *pipe = &pstate->pipe; struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; @@ -892,14 +894,16 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { /* * In parallel multirect case only the half of the usual width * is supported for tiled formats. If we are here, we know that * full width is more than max_linewidth, thus each rect is * wider than allowed. */ - if (DPU_FORMAT_IS_UBWC(fmt)) { + if (DPU_FORMAT_IS_UBWC(fmt) && + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n", DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); return -E2BIG; From a9bd555de5e9042fdf8ab8d6080b86f45c68ddf6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 9 Oct 2023 19:56:27 +0300 Subject: [PATCH 2168/7721] drm/msm/dpu: enable SmartDMA on SM8450 Enable the SmartDMA / multirect support on the SM8450 platform to support higher resoltion modes. Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/561590/ Link: https://lore.kernel.org/r/20231009165627.2691015-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 7742f52be859..d18145c226da 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x32c, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_0, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x32c, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_1, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x32c, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_2, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x32c, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_3, .xin_id = 12, .type = SSPP_TYPE_VIG, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x32c, - .features = DMA_SDM845_MASK, + .features = DMA_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_0, .xin_id = 1, .type = SSPP_TYPE_DMA, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x32c, - .features = DMA_SDM845_MASK, + .features = DMA_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_1, .xin_id = 5, .type = SSPP_TYPE_DMA, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x32c, - .features = DMA_CURSOR_SDM845_MASK, + .features = DMA_CURSOR_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_2, .xin_id = 9, .type = SSPP_TYPE_DMA, @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x32c, - .features = DMA_CURSOR_SDM845_MASK, + .features = DMA_CURSOR_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_3, .xin_id = 13, .type = SSPP_TYPE_DMA, From 921e32bf6c0c86f774226577cb743d654f9bcfd9 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Fri, 8 Sep 2023 12:33:13 -0700 Subject: [PATCH 2169/7721] drm/msm/dpu: enable smartdma on sm8350 To support high resolutions on sm8350, enable smartdma in its catalog. Signed-off-by: Abhinav Kumar Tested-by: Dmitry Baryshkov Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/556561/ Link: https://lore.kernel.org/r/20230908193314.27008-1-quic_abhinavk@quicinc.com [DB: rebased on top of msm-next] Signed-off-by: Dmitry Baryshkov --- .../drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 1709ba57f384..5aaa24281906 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -74,7 +74,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_0, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -82,7 +82,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_1, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -90,7 +90,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_2, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -98,7 +98,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SC7180_MASK_SDMA, .sblk = &sm8250_vig_sblk_3, .xin_id = 12, .type = SSPP_TYPE_VIG, @@ -106,7 +106,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, - .features = DMA_SDM845_MASK, + .features = DMA_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_0, .xin_id = 1, .type = SSPP_TYPE_DMA, @@ -114,7 +114,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, - .features = DMA_SDM845_MASK, + .features = DMA_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_1, .xin_id = 5, .type = SSPP_TYPE_DMA, @@ -122,7 +122,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, - .features = DMA_CURSOR_SDM845_MASK, + .features = DMA_CURSOR_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_2, .xin_id = 9, .type = SSPP_TYPE_DMA, @@ -130,7 +130,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f8, - .features = DMA_CURSOR_SDM845_MASK, + .features = DMA_CURSOR_SDM845_MASK_SDMA, .sblk = &sdm845_dma_sblk_3, .xin_id = 13, .type = SSPP_TYPE_DMA, From 96ab215b2d5edc39310c00f50b33d8ab72ac3fe3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Oct 2023 22:04:03 +0200 Subject: [PATCH 2170/7721] drm/msm/a6xx: add QMP dependency When QMP is in a loadable module, the A6xx GPU driver fails to link as built-in: x86_64-linux-ld: drivers/gpu/drm/msm/adreno/a6xx_gmu.o: in function `a6xx_gmu_resume': a6xx_gmu.c:(.text+0xd62): undefined reference to `qmp_send' Add the usual dependency that still allows compiling without QMP but otherwise avoids the broken combination of options. Fixes: 88a0997f2f949 ("drm/msm/a6xx: Send ACD state to QMP at GMU resume") Signed-off-by: Arnd Bergmann Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/562945/ Link: https://lore.kernel.org/r/20231016200415.791090-1-arnd@kernel.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 6309a857ca31..ad70b611b44f 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -6,6 +6,7 @@ config DRM_MSM depends on ARCH_QCOM || SOC_IMX5 || COMPILE_TEST depends on COMMON_CLK depends on IOMMU_SUPPORT + depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n depends on QCOM_OCMEM || QCOM_OCMEM=n depends on QCOM_LLCC || QCOM_LLCC=n depends on QCOM_COMMAND_DB || QCOM_COMMAND_DB=n From fa2bbff7b0b4e211fec5e5686ef96350690597b5 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Wed, 29 Nov 2023 10:02:34 +0800 Subject: [PATCH 2171/7721] md: synchronize flush io with array reconfiguration Currently rcu is used to protect iterating rdev from submit_flushes(): submit_flushes remove_and_add_spares synchronize_rcu pers->hot_remove_disk() rcu_read_lock() rdev_for_each_rcu if (rdev->raid_disk >= 0) rdev->radi_disk = -1; atomic_inc(&rdev->nr_pending) rcu_read_unlock() bi = bio_alloc_bioset() bi->bi_end_io = md_end_flush bi->private = rdev submit_bio // issue io for removed rdev Fix this problem by grabbing 'acive_io' before iterating rdev, make sure that remove_and_add_spares() won't concurrent with submit_flushes(). Fixes: a2826aa92e2e ("md: support barrier requests on all personalities.") Signed-off-by: Yu Kuai Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231129020234.1586910-1-yukuai1@huaweicloud.com --- drivers/md/md.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 71b3397dea47..4e9fe5cbeedc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -529,6 +529,9 @@ static void md_end_flush(struct bio *bio) rdev_dec_pending(rdev, mddev); if (atomic_dec_and_test(&mddev->flush_pending)) { + /* The pair is percpu_ref_get() from md_flush_request() */ + percpu_ref_put(&mddev->active_io); + /* The pre-request flush has finished */ queue_work(md_wq, &mddev->flush_work); } @@ -548,12 +551,8 @@ static void submit_flushes(struct work_struct *ws) rdev_for_each_rcu(rdev, mddev) if (rdev->raid_disk >= 0 && !test_bit(Faulty, &rdev->flags)) { - /* Take two references, one is dropped - * when request finishes, one after - * we reclaim rcu_read_lock - */ struct bio *bi; - atomic_inc(&rdev->nr_pending); + atomic_inc(&rdev->nr_pending); rcu_read_unlock(); bi = bio_alloc_bioset(rdev->bdev, 0, @@ -564,7 +563,6 @@ static void submit_flushes(struct work_struct *ws) atomic_inc(&mddev->flush_pending); submit_bio(bi); rcu_read_lock(); - rdev_dec_pending(rdev, mddev); } rcu_read_unlock(); if (atomic_dec_and_test(&mddev->flush_pending)) @@ -617,6 +615,18 @@ bool md_flush_request(struct mddev *mddev, struct bio *bio) /* new request after previous flush is completed */ if (ktime_after(req_start, mddev->prev_flush_start)) { WARN_ON(mddev->flush_bio); + /* + * Grab a reference to make sure mddev_suspend() will wait for + * this flush to be done. + * + * md_flush_reqeust() is called under md_handle_request() and + * 'active_io' is already grabbed, hence percpu_ref_is_zero() + * won't pass, percpu_ref_tryget_live() can't be used because + * percpu_ref_kill() can be called by mddev_suspend() + * concurrently. + */ + WARN_ON(percpu_ref_is_zero(&mddev->active_io)); + percpu_ref_get(&mddev->active_io); mddev->flush_bio = bio; bio = NULL; } From e50e5fed41c7eed2db4119645bf3480ec43fec11 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:51 -0700 Subject: [PATCH 2172/7721] drm: Introduce pixel_source DRM plane property Add support for pixel_source property to drm_plane and related documentation. In addition, force pixel_source to DRM_PLANE_PIXEL_SOURCE_FB in DRM_IOCTL_MODE_SETPLANE as to not break legacy userspace. This enum property will allow user to specify a pixel source for the plane. Possible pixel sources will be defined in the drm_plane_pixel_source enum. Currently, the only pixel sources are DRM_PLANE_PIXEL_SOURCE_FB (the default value) and DRM_PLANE_PIXEL_SOURCE_NONE. Acked-by: Dmitry Baryshkov Acked-by: Pekka Paalanen Acked-by: Harry Wentland Acked-by: Sebastian Wick Acked-by: Simon Ser Signed-off-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-1-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic_state_helper.c | 1 + drivers/gpu/drm/drm_atomic_uapi.c | 4 + drivers/gpu/drm/drm_blend.c | 94 +++++++++++++++++++++++ drivers/gpu/drm/drm_plane.c | 19 ++++- include/drm/drm_blend.h | 2 + include/drm/drm_plane.h | 21 +++++ 6 files changed, 137 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 54975de44a0e..311b04edf742 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -252,6 +252,7 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE; plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; + plane_state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; if (plane->color_encoding_property) { if (!drm_object_property_get_default_value(&plane->base, diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index aee4a65d4959..bd7140531948 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -562,6 +562,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->src_w = val; } else if (property == config->prop_src_h) { state->src_h = val; + } else if (property == plane->pixel_source_property) { + state->pixel_source = val; } else if (property == plane->alpha_property) { state->alpha = val; } else if (property == plane->blend_mode_property) { @@ -650,6 +652,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->src_w; } else if (property == config->prop_src_h) { *val = state->src_h; + } else if (property == plane->pixel_source_property) { + *val = state->pixel_source; } else if (property == plane->alpha_property) { *val = state->alpha; } else if (property == plane->blend_mode_property) { diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 6e74de833466..fce734cdb85b 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -185,6 +185,25 @@ * plane does not expose the "alpha" property, then this is * assumed to be 1.0 * + * pixel_source: + * pixel_source is set up with drm_plane_create_pixel_source_property(). + * It is used to toggle the active source of pixel data for the plane. + * The plane will only display data from the set pixel_source -- any + * data from other sources will be ignored. + * + * For non-framebuffer sources, if pixel_source is set to a non-framebuffer + * and non-NONE source, and the corresponding source property is NULL, then + * the atomic commit should return an error. + * + * Possible values: + * + * "NONE": + * No active pixel source. + * Committing with a NONE pixel source will disable the plane. + * + * "FB": + * Framebuffer source set by the "FB_ID" property. + * * Note that all the property extensions described here apply either to the * plane or the CRTC (e.g. for the background color, which currently is not * exposed and assumed to be black). @@ -615,3 +634,78 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_blend_mode_property); + +static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { + { DRM_PLANE_PIXEL_SOURCE_NONE, "NONE" }, + { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, +}; + +/** + * drm_plane_create_pixel_source_property - create a new pixel source property + * @plane: DRM plane + * @extra_sources: Bitmask of additional supported pixel_sources for the driver. + * DRM_PLANE_PIXEL_SOURCE_FB and DRM_PLANE_PIXEL_SOURCE_NONE will + * always be enabled as supported sources. + * + * This creates a new property describing the current source of pixel data for the + * plane. The pixel_source will be initialized as DRM_PLANE_PIXEL_SOURCE_FB by default. + * + * Drivers can set a custom default source by overriding the pixel_source value in + * drm_plane_funcs.reset() + * + * The property is exposed to userspace as an enumeration property called + * "pixel_source" and has the following enumeration values: + * + * "NONE": + * No active pixel source + * + * "FB": + * Framebuffer pixel source + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_plane_create_pixel_source_property(struct drm_plane *plane, + unsigned long extra_sources) +{ + struct drm_device *dev = plane->dev; + struct drm_property *prop; + static const unsigned int valid_source_mask = BIT(DRM_PLANE_PIXEL_SOURCE_FB) | + BIT(DRM_PLANE_PIXEL_SOURCE_NONE); + int i; + + /* FB is supported by default */ + unsigned long supported_sources = extra_sources | + BIT(DRM_PLANE_PIXEL_SOURCE_FB) | + BIT(DRM_PLANE_PIXEL_SOURCE_NONE); + + if (WARN_ON(supported_sources & ~valid_source_mask)) + return -EINVAL; + + prop = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_ATOMIC, "pixel_source", + hweight32(supported_sources)); + + if (!prop) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(drm_pixel_source_enum_list); i++) { + int ret; + + if (!test_bit(drm_pixel_source_enum_list[i].type, &supported_sources)) + continue; + + ret = drm_property_add_enum(prop, drm_pixel_source_enum_list[i].type, + drm_pixel_source_enum_list[i].name); + if (ret) { + drm_property_destroy(dev, prop); + + return ret; + } + } + + drm_object_attach_property(&plane->base, prop, DRM_PLANE_PIXEL_SOURCE_FB); + plane->pixel_source_property = prop; + + return 0; +} +EXPORT_SYMBOL(drm_plane_create_pixel_source_property); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 9e8e4c60983d..c8dbe5ae60cc 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -953,6 +953,14 @@ bool drm_any_plane_has_format(struct drm_device *dev, } EXPORT_SYMBOL(drm_any_plane_has_format); +static bool drm_plane_needs_disable(struct drm_plane_state *state, struct drm_framebuffer *fb) +{ + if (state->pixel_source == DRM_PLANE_PIXEL_SOURCE_NONE) + return true; + + return state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && fb == NULL; +} + /* * __setplane_internal - setplane handler for internal callers * @@ -975,8 +983,8 @@ static int __setplane_internal(struct drm_plane *plane, WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); - /* No fb means shut it down */ - if (!fb) { + /* No visible data means shut it down */ + if (drm_plane_needs_disable(plane->state, fb)) { plane->old_fb = plane->fb; ret = plane->funcs->disable_plane(plane, ctx); if (!ret) { @@ -1027,8 +1035,8 @@ static int __setplane_atomic(struct drm_plane *plane, WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev)); - /* No fb means shut it down */ - if (!fb) + /* No visible data means shut it down */ + if (drm_plane_needs_disable(plane->state, fb)) return plane->funcs->disable_plane(plane, ctx); /* @@ -1101,6 +1109,9 @@ int drm_mode_setplane(struct drm_device *dev, void *data, return -ENOENT; } + if (plane->state) + plane->state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; + if (plane_req->fb_id) { fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id); if (!fb) { diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 88bdfec3bd88..122bbfbaae33 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -58,4 +58,6 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); +int drm_plane_create_pixel_source_property(struct drm_plane *plane, + unsigned long extra_sources); #endif diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index c6565a6f9324..bc0176ba25be 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -40,6 +40,12 @@ enum drm_scaling_filter { DRM_SCALING_FILTER_NEAREST_NEIGHBOR, }; +enum drm_plane_pixel_source { + DRM_PLANE_PIXEL_SOURCE_NONE, + DRM_PLANE_PIXEL_SOURCE_FB, + DRM_PLANE_PIXEL_SOURCE_MAX +}; + /** * struct drm_plane_state - mutable plane state * @@ -120,6 +126,14 @@ struct drm_plane_state { /** @hotspot_y: y offset to mouse cursor hotspot */ int32_t hotspot_x, hotspot_y; + /** + * @pixel_source: + * + * Source of pixel information for the plane. See + * drm_plane_create_pixel_source_property() for more details. + */ + enum drm_plane_pixel_source pixel_source; + /** * @alpha: * Opacity of the plane with 0 as completely transparent and 0xffff as @@ -713,6 +727,13 @@ struct drm_plane { */ struct drm_plane_state *state; + /* + * @pixel_source_property: + * Optional pixel_source property for this plane. See + * drm_plane_create_pixel_source_property(). + */ + struct drm_property *pixel_source_property; + /** * @alpha_property: * Optional alpha property for this plane. See From 85863a4e16e77079ee14865905ddc3ef9483a640 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:52 -0700 Subject: [PATCH 2173/7721] drm: Introduce solid fill DRM plane property Document and add support for solid_fill property to drm_plane. In addition, add support for setting and getting the values for solid_fill. To enable solid fill planes, userspace must assign a property blob to the "solid_fill" plane property containing the following information: struct drm_mode_solid_fill { u32 r, g, b, pad; }; Acked-by: Harry Wentland Acked-by: Sebastian Wick Signed-off-by: Jessica Zhang Reviewed-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-2-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic_state_helper.c | 9 ++++++ drivers/gpu/drm/drm_atomic_uapi.c | 26 ++++++++++++++++ drivers/gpu/drm/drm_blend.c | 30 +++++++++++++++++++ include/drm/drm_blend.h | 1 + include/drm/drm_plane.h | 36 +++++++++++++++++++++++ include/uapi/drm/drm_mode.h | 24 +++++++++++++++ 6 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 311b04edf742..f6c76cea8be4 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -254,6 +254,11 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; plane_state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; + if (plane_state->solid_fill_blob) { + drm_property_blob_put(plane_state->solid_fill_blob); + plane_state->solid_fill_blob = NULL; + } + if (plane->color_encoding_property) { if (!drm_object_property_get_default_value(&plane->base, plane->color_encoding_property, @@ -350,6 +355,9 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, if (state->fb) drm_framebuffer_get(state->fb); + if (state->solid_fill_blob) + drm_property_blob_get(state->solid_fill_blob); + state->fence = NULL; state->commit = NULL; state->fb_damage_clips = NULL; @@ -399,6 +407,7 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) drm_crtc_commit_put(state->commit); drm_property_blob_put(state->fb_damage_clips); + drm_property_blob_put(state->solid_fill_blob); } EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index bd7140531948..d7ae8e2c0265 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -316,6 +316,20 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, } EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); +static void drm_atomic_set_solid_fill_prop(struct drm_plane_state *state) +{ + struct drm_mode_solid_fill *user_info; + + if (!state->solid_fill_blob) + return; + + user_info = (struct drm_mode_solid_fill *)state->solid_fill_blob->data; + + state->solid_fill.r = user_info->r; + state->solid_fill.g = user_info->g; + state->solid_fill.b = user_info->b; +} + static void set_out_fence_for_crtc(struct drm_atomic_state *state, struct drm_crtc *crtc, s32 __user *fence_ptr) { @@ -564,6 +578,15 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->src_h = val; } else if (property == plane->pixel_source_property) { state->pixel_source = val; + } else if (property == plane->solid_fill_property) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->solid_fill_blob, + val, sizeof(struct drm_mode_solid_fill), + -1, &replaced); + if (ret) + return ret; + + drm_atomic_set_solid_fill_prop(state); } else if (property == plane->alpha_property) { state->alpha = val; } else if (property == plane->blend_mode_property) { @@ -654,6 +677,9 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->src_h; } else if (property == plane->pixel_source_property) { *val = state->pixel_source; + } else if (property == plane->solid_fill_property) { + *val = state->solid_fill_blob ? + state->solid_fill_blob->base.id : 0; } else if (property == plane->alpha_property) { *val = state->alpha; } else if (property == plane->blend_mode_property) { diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index fce734cdb85b..665c5d9b056f 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -204,6 +204,10 @@ * "FB": * Framebuffer source set by the "FB_ID" property. * + * solid_fill: + * solid_fill is set up with drm_plane_create_solid_fill_property(). It + * contains pixel data that drivers can use to fill a plane. + * * Note that all the property extensions described here apply either to the * plane or the CRTC (e.g. for the background color, which currently is not * exposed and assumed to be black). @@ -709,3 +713,29 @@ int drm_plane_create_pixel_source_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_pixel_source_property); + +/** + * drm_plane_create_solid_fill_property - create a new solid_fill property + * @plane: drm plane + * + * This creates a new property blob that holds pixel data for solid fill planes. + * The property is exposed to userspace as a property blob called "solid_fill". + * + * For information on what the blob contains, see `drm_mode_solid_fill`. + */ +int drm_plane_create_solid_fill_property(struct drm_plane *plane) +{ + struct drm_property *prop; + + prop = drm_property_create(plane->dev, + DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, + "solid_fill", 0); + if (!prop) + return -ENOMEM; + + drm_object_attach_property(&plane->base, prop, 0); + plane->solid_fill_property = prop; + + return 0; +} +EXPORT_SYMBOL(drm_plane_create_solid_fill_property); diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 122bbfbaae33..e7158fbee389 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -60,4 +60,5 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); int drm_plane_create_pixel_source_property(struct drm_plane *plane, unsigned long extra_sources); +int drm_plane_create_solid_fill_property(struct drm_plane *plane); #endif diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index bc0176ba25be..5bac644d4cc3 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -46,6 +46,18 @@ enum drm_plane_pixel_source { DRM_PLANE_PIXEL_SOURCE_MAX }; +/** + * struct solid_fill_property - RGB values for solid fill plane + * + * TODO: Add solid fill source and corresponding pixel source + * that supports RGBA color + */ +struct drm_solid_fill { + uint32_t r; + uint32_t g; + uint32_t b; +}; + /** * struct drm_plane_state - mutable plane state * @@ -134,6 +146,23 @@ struct drm_plane_state { */ enum drm_plane_pixel_source pixel_source; + /** + * @solid_fill_blob: + * + * Blob containing relevant information for a solid fill plane + * including RGB color values. See + * drm_plane_create_solid_fill_property() for more details. + */ + struct drm_property_blob *solid_fill_blob; + + /** + * @solid_fill: + * + * Pixel data for solid fill planes. See + * drm_plane_create_solid_fill_property() for more details. + */ + struct drm_solid_fill solid_fill; + /** * @alpha: * Opacity of the plane with 0 as completely transparent and 0xffff as @@ -734,6 +763,13 @@ struct drm_plane { */ struct drm_property *pixel_source_property; + /** + * @solid_fill_property: + * Optional solid_fill property for this plane. See + * drm_plane_create_solid_fill_property(). + */ + struct drm_property *solid_fill_property; + /** * @alpha_property: * Optional alpha property for this plane. See diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 95630f170110..cbd943a8c88b 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -259,6 +259,30 @@ struct drm_mode_modeinfo { char name[DRM_DISPLAY_MODE_LEN]; }; +/** + * struct drm_mode_solid_fill - User info for solid fill planes + * + * This is the userspace API solid fill information structure. + * + * Userspace can enable solid fill planes by assigning the plane "solid_fill" + * property to a blob containing a single drm_mode_solid_fill struct populated with an RGB323232 + * color and setting the pixel source to "SOLID_FILL". + * + * For information on the plane property, see drm_plane_create_solid_fill_property() + * + * @r: Red color value of single pixel + * @g: Green color value of single pixel + * @b: Blue color value of single pixel + * @pad: padding, must be zero + */ +struct drm_mode_solid_fill { + __u32 r; + __u32 g; + __u32 b; + __u32 pad; +}; + + struct drm_mode_card_res { __u64 fb_id_ptr; __u64 crtc_id_ptr; From 4b64167042927531f4cfaf035b8f88c2f7a05f06 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:53 -0700 Subject: [PATCH 2174/7721] drm: Add solid fill pixel source Add "SOLID_FILL" as a valid pixel source. If the pixel_source property is set to "SOLID_FILL", it will display data from the drm_plane "solid_fill" blob property. Reviewed-by: Dmitry Baryshkov Acked-by: Pekka Paalanen Acked-by: Harry Wentland Acked-by: Sebastian Wick Signed-off-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-3-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_blend.c | 10 +++++++++- include/drm/drm_plane.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 665c5d9b056f..37b31b7e5ce5 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -204,6 +204,9 @@ * "FB": * Framebuffer source set by the "FB_ID" property. * + * "SOLID_FILL": + * Solid fill color source set by the "solid_fill" property. + * * solid_fill: * solid_fill is set up with drm_plane_create_solid_fill_property(). It * contains pixel data that drivers can use to fill a plane. @@ -642,6 +645,7 @@ EXPORT_SYMBOL(drm_plane_create_blend_mode_property); static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { { DRM_PLANE_PIXEL_SOURCE_NONE, "NONE" }, { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, + { DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, "SOLID_FILL" }, }; /** @@ -666,6 +670,9 @@ static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { * "FB": * Framebuffer pixel source * + * "SOLID_FILL": + * Solid fill color pixel source + * * Returns: * Zero on success, negative errno on failure. */ @@ -675,7 +682,8 @@ int drm_plane_create_pixel_source_property(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct drm_property *prop; static const unsigned int valid_source_mask = BIT(DRM_PLANE_PIXEL_SOURCE_FB) | - BIT(DRM_PLANE_PIXEL_SOURCE_NONE); + BIT(DRM_PLANE_PIXEL_SOURCE_NONE) | + BIT(DRM_PLANE_PIXEL_SOURCE_SOLID_FILL); int i; /* FB is supported by default */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 5bac644d4cc3..4b7af4381bbe 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -43,6 +43,7 @@ enum drm_scaling_filter { enum drm_plane_pixel_source { DRM_PLANE_PIXEL_SOURCE_NONE, DRM_PLANE_PIXEL_SOURCE_FB, + DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, DRM_PLANE_PIXEL_SOURCE_MAX }; From 8283ac7871a959848e09fc6593b8c12b8febfee6 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:54 -0700 Subject: [PATCH 2175/7721] drm/atomic: Add pixel source to plane state dump Add pixel source to the atomic plane state dump Reviewed-by: Dmitry Baryshkov Acked-by: Harry Wentland Acked-by: Sebastian Wick Signed-off-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-4-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_blend.c | 1 + drivers/gpu/drm/drm_crtc_internal.h | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f1a503aafe5a..02aa7df832cc 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -722,6 +722,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf(p, "\tpixel-source=%s\n", drm_get_pixel_source_name(state->pixel_source)); drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 37b31b7e5ce5..9c1608f7c1df 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -647,6 +647,7 @@ static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, { DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, "SOLID_FILL" }, }; +DRM_ENUM_NAME_FN(drm_get_pixel_source_name, drm_pixel_source_enum_list); /** * drm_plane_create_pixel_source_property - create a new pixel source property diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index a514d5207e41..4114675c0728 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -269,6 +269,7 @@ int drm_plane_check_pixel_format(struct drm_plane *plane, u32 format, u64 modifier); struct drm_mode_rect * __drm_plane_get_damage_clips(const struct drm_plane_state *state); +const char *drm_get_pixel_source_name(int val); /* drm_bridge.c */ void drm_bridge_detach(struct drm_bridge *bridge); From e86413f5442ee094e66b3e75f2d3419ed0df9520 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:55 -0700 Subject: [PATCH 2176/7721] drm/atomic: Add solid fill data to plane state dump Add solid_fill property data to the atomic plane state dump. Reviewed-by: Dmitry Baryshkov Acked-by: Harry Wentland Acked-by: Sebastian Wick Signed-off-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-5-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic.c | 4 ++++ drivers/gpu/drm/drm_plane.c | 8 ++++++++ include/drm/drm_plane.h | 3 +++ 3 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 02aa7df832cc..1339785fbe80 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -726,6 +726,10 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); + drm_printf(p, "\tsolid_fill=%u\n", + state->solid_fill_blob ? state->solid_fill_blob->base.id : 0); + if (state->solid_fill_blob) + drm_plane_solid_fill_print_info(p, 2, state); drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); drm_printf(p, "\trotation=%x\n", state->rotation); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index c8dbe5ae60cc..c65c72701dd2 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1641,6 +1641,14 @@ __drm_plane_get_damage_clips(const struct drm_plane_state *state) state->fb_damage_clips->data : NULL); } +void drm_plane_solid_fill_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_plane_state *state) +{ + drm_printf_indent(p, indent, "r=0x%08x\n", state->solid_fill.r); + drm_printf_indent(p, indent, "g=0x%08x\n", state->solid_fill.g); + drm_printf_indent(p, indent, "b=0x%08x\n", state->solid_fill.b); +} + /** * drm_plane_get_damage_clips - Returns damage clips. * @state: Plane state. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 4b7af4381bbe..d14e2f1db234 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -1025,6 +1025,9 @@ drm_plane_get_damage_clips_count(const struct drm_plane_state *state); struct drm_mode_rect * drm_plane_get_damage_clips(const struct drm_plane_state *state); +void drm_plane_solid_fill_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_plane_state *state); + int drm_plane_create_scaling_filter_property(struct drm_plane *plane, unsigned int supported_filters); From 4ba6b7a646321e740c7f2d80c90505019c4e8fce Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:56 -0700 Subject: [PATCH 2177/7721] drm/atomic: Move framebuffer checks to helper Currently framebuffer checks happen directly in drm_atomic_plane_check(). Move these checks into their own helper method. Reviewed-by: Dmitry Baryshkov Acked-by: Harry Wentland Acked-by: Sebastian Wick Signed-off-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-6-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic.c | 130 ++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1339785fbe80..c6f2b86c48ae 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -589,6 +589,76 @@ plane_switching_crtc(const struct drm_plane_state *old_plane_state, return true; } +static int drm_atomic_plane_check_fb(const struct drm_plane_state *state) +{ + struct drm_plane *plane = state->plane; + const struct drm_framebuffer *fb = state->fb; + struct drm_mode_rect *clips; + + uint32_t num_clips; + unsigned int fb_width, fb_height; + int ret; + + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); + + if (ret) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n", + plane->base.id, plane->name, + &fb->format->format, fb->modifier); + return ret; + } + + fb_width = fb->width << 16; + fb_height = fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (state->src_w > fb_width || + state->src_x > fb_width - state->src_w || + state->src_h > fb_height || + state->src_y > fb_height - state->src_h) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", + plane->base.id, plane->name, + state->src_w >> 16, + ((state->src_w & 0xffff) * 15625) >> 10, + state->src_h >> 16, + ((state->src_h & 0xffff) * 15625) >> 10, + state->src_x >> 16, + ((state->src_x & 0xffff) * 15625) >> 10, + state->src_y >> 16, + ((state->src_y & 0xffff) * 15625) >> 10, + fb->width, fb->height); + return -ENOSPC; + } + + clips = __drm_plane_get_damage_clips(state); + num_clips = drm_plane_get_damage_clips_count(state); + + /* Make sure damage clips are valid and inside the fb. */ + while (num_clips > 0) { + if (clips->x1 >= clips->x2 || + clips->y1 >= clips->y2 || + clips->x1 < 0 || + clips->y1 < 0 || + clips->x2 > fb_width || + clips->y2 > fb_height) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", + plane->base.id, plane->name, clips->x1, + clips->y1, clips->x2, clips->y2); + return -EINVAL; + } + clips++; + num_clips--; + } + + return 0; +} + /** * drm_atomic_plane_check - check plane state * @old_plane_state: old plane state to check @@ -605,9 +675,6 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, struct drm_plane *plane = new_plane_state->plane; struct drm_crtc *crtc = new_plane_state->crtc; const struct drm_framebuffer *fb = new_plane_state->fb; - unsigned int fb_width, fb_height; - struct drm_mode_rect *clips; - uint32_t num_clips; int ret; /* either *both* CRTC and FB must be set, or neither */ @@ -634,17 +701,6 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, return -EINVAL; } - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->format->format, - fb->modifier); - if (ret) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n", - plane->base.id, plane->name, - &fb->format->format, fb->modifier); - return ret; - } - /* Give drivers some help against integer overflows */ if (new_plane_state->crtc_w > INT_MAX || new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || @@ -658,50 +714,10 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, return -ERANGE; } - fb_width = fb->width << 16; - fb_height = fb->height << 16; - /* Make sure source coordinates are inside the fb. */ - if (new_plane_state->src_w > fb_width || - new_plane_state->src_x > fb_width - new_plane_state->src_w || - new_plane_state->src_h > fb_height || - new_plane_state->src_y > fb_height - new_plane_state->src_h) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", - plane->base.id, plane->name, - new_plane_state->src_w >> 16, - ((new_plane_state->src_w & 0xffff) * 15625) >> 10, - new_plane_state->src_h >> 16, - ((new_plane_state->src_h & 0xffff) * 15625) >> 10, - new_plane_state->src_x >> 16, - ((new_plane_state->src_x & 0xffff) * 15625) >> 10, - new_plane_state->src_y >> 16, - ((new_plane_state->src_y & 0xffff) * 15625) >> 10, - fb->width, fb->height); - return -ENOSPC; - } - - clips = __drm_plane_get_damage_clips(new_plane_state); - num_clips = drm_plane_get_damage_clips_count(new_plane_state); - - /* Make sure damage clips are valid and inside the fb. */ - while (num_clips > 0) { - if (clips->x1 >= clips->x2 || - clips->y1 >= clips->y2 || - clips->x1 < 0 || - clips->y1 < 0 || - clips->x2 > fb_width || - clips->y2 > fb_height) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", - plane->base.id, plane->name, clips->x1, - clips->y1, clips->x2, clips->y2); - return -EINVAL; - } - clips++; - num_clips--; - } + ret = drm_atomic_plane_check_fb(new_plane_state); + if (ret) + return ret; if (plane_switching_crtc(old_plane_state, new_plane_state)) { drm_dbg_atomic(plane->dev, From f1e75da5364e780905d9cd6043f9c74cdcf84073 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Fri, 27 Oct 2023 15:32:57 -0700 Subject: [PATCH 2178/7721] drm/atomic: Loosen FB atomic checks Loosen the requirements for atomic and legacy commit so that, in cases where pixel_source != FB, the commit can still go through. This includes adding framebuffer NULL checks in other areas to account for FB being NULL when non-FB pixel sources are enabled. To disable a plane, the pixel_source must be NONE or the FB must be NULL if pixel_source == FB. Signed-off-by: Jessica Zhang Reviewed-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-7-780188bfa7b2@quicinc.com --- drivers/gpu/drm/drm_atomic.c | 21 +++++++------- drivers/gpu/drm/drm_atomic_helper.c | 43 ++++++++++++++++------------- include/drm/drm_atomic_helper.h | 4 +-- include/drm/drm_plane.h | 29 +++++++++++++++++++ 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c6f2b86c48ae..aed0a694c74c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -674,17 +674,16 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, { struct drm_plane *plane = new_plane_state->plane; struct drm_crtc *crtc = new_plane_state->crtc; - const struct drm_framebuffer *fb = new_plane_state->fb; int ret; - /* either *both* CRTC and FB must be set, or neither */ - if (crtc && !fb) { - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no FB\n", + /* either *both* CRTC and pixel source must be set, or neither */ + if (crtc && !drm_plane_has_visible_data(new_plane_state)) { + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no visible data\n", plane->base.id, plane->name); return -EINVAL; - } else if (fb && !crtc) { - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] FB set but no CRTC\n", - plane->base.id, plane->name); + } else if (drm_plane_has_visible_data(new_plane_state) && !crtc) { + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] Source %d has visible data but no CRTC\n", + plane->base.id, plane->name, new_plane_state->pixel_source); return -EINVAL; } @@ -715,9 +714,11 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, } - ret = drm_atomic_plane_check_fb(new_plane_state); - if (ret) - return ret; + if (new_plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && new_plane_state->fb) { + ret = drm_atomic_plane_check_fb(new_plane_state); + if (ret) + return ret; + } if (plane_switching_crtc(old_plane_state, new_plane_state)) { drm_dbg_atomic(plane->dev, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3f677130def..dc048988e3f3 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -861,7 +861,6 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, bool can_position, bool can_update_disabled) { - struct drm_framebuffer *fb = plane_state->fb; struct drm_rect *src = &plane_state->src; struct drm_rect *dst = &plane_state->dst; unsigned int rotation = plane_state->rotation; @@ -873,7 +872,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, *src = drm_plane_state_src(plane_state); *dst = drm_plane_state_dest(plane_state); - if (!fb) { + if (!drm_plane_has_visible_data(plane_state)) { plane_state->visible = false; return 0; } @@ -890,26 +889,32 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, return -EINVAL; } - drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); + /* Check that selected pixel source is valid */ + if (plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && plane_state->fb) { + struct drm_framebuffer *fb = plane_state->fb; + drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); - /* Check scaling */ - hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); - vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); - if (hscale < 0 || vscale < 0) { - drm_dbg_kms(plane_state->plane->dev, - "Invalid scaling of plane\n"); - drm_rect_debug_print("src: ", &plane_state->src, true); - drm_rect_debug_print("dst: ", &plane_state->dst, false); - return -ERANGE; + /* Check scaling */ + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); + + if (hscale < 0 || vscale < 0) { + drm_dbg_kms(plane_state->plane->dev, + "Invalid scaling of plane\n"); + drm_rect_debug_print("src: ", &plane_state->src, true); + drm_rect_debug_print("dst: ", &plane_state->dst, false); + return -ERANGE; + } + + if (crtc_state->enable) + drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); + + plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); + } else if (drm_plane_solid_fill_enabled(plane_state)) { + plane_state->visible = true; } - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); - - plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); - - drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); - if (!plane_state->visible) /* * Plane isn't visible; some drivers can handle this diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 536a0b0091c3..6d97f38ac1f6 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -256,8 +256,8 @@ drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state, * Anything else should be considered a bug in the atomic core, so we * gently warn about it. */ - WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) || - (new_plane_state->crtc != NULL && new_plane_state->fb == NULL)); + WARN_ON((new_plane_state->crtc == NULL && drm_plane_has_visible_data(new_plane_state)) || + (new_plane_state->crtc != NULL && !drm_plane_has_visible_data(new_plane_state))); return old_plane_state->crtc && !new_plane_state->crtc; } diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index d14e2f1db234..3b187f3f5466 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -1016,6 +1016,35 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) +/** + * drm_plane_solid_fill_enabled - Check if solid fill is enabled on plane + * @state: plane state + * + * Returns: + * Whether the plane has been assigned a solid_fill_blob + */ +static inline bool drm_plane_solid_fill_enabled(struct drm_plane_state *state) +{ + if (!state) + return false; + return state->pixel_source == DRM_PLANE_PIXEL_SOURCE_SOLID_FILL && state->solid_fill_blob; +} + +static inline bool drm_plane_has_visible_data(const struct drm_plane_state *state) +{ + switch (state->pixel_source) { + case DRM_PLANE_PIXEL_SOURCE_NONE: + return false; + case DRM_PLANE_PIXEL_SOURCE_SOLID_FILL: + return state->solid_fill_blob != NULL; + case DRM_PLANE_PIXEL_SOURCE_FB: + default: + WARN_ON(state->pixel_source != DRM_PLANE_PIXEL_SOURCE_FB); + } + + return state->fb != NULL; +} + bool drm_any_plane_has_format(struct drm_device *dev, u32 format, u64 modifier); From ac9c05e0e453cfcab2866f6d28f257590e4f66e5 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:12 -0800 Subject: [PATCH 2179/7721] bpf: Add kfunc bpf_get_file_xattr It is common practice for security solutions to store tags/labels in xattrs. To implement similar functionalities in BPF LSM, add new kfunc bpf_get_file_xattr(). The first use case of bpf_get_file_xattr() is to implement file verifications with asymmetric keys. Specificially, security applications could use fsverity for file hashes and use xattr to store file signatures. (kfunc for fsverity hash will be added in a separate commit.) Currently, only xattrs with "user." prefix can be read with kfunc bpf_get_file_xattr(). As use cases evolve, we may add a dedicated prefix for bpf_get_file_xattr(). To avoid recursion, bpf_get_file_xattr can be only called from LSM hooks. Signed-off-by: Song Liu Acked-by: Christian Brauner Acked-by: KP Singh Link: https://lore.kernel.org/r/20231129234417.856536-2-song@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/trace/bpf_trace.c | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index c284a4ad0315..1648bde28f01 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -1431,6 +1432,72 @@ static int __init bpf_key_sig_kfuncs_init(void) late_initcall(bpf_key_sig_kfuncs_init); #endif /* CONFIG_KEYS */ +/* filesystem kfuncs */ +__bpf_kfunc_start_defs(); + +/** + * bpf_get_file_xattr - get xattr of a file + * @file: file to get xattr from + * @name__str: name of the xattr + * @value_ptr: output buffer of the xattr value + * + * Get xattr *name__str* of *file* and store the output in *value_ptr*. + * + * For security reasons, only *name__str* with prefix "user." is allowed. + * + * Return: 0 on success, a negative value on error. + */ +__bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str, + struct bpf_dynptr_kern *value_ptr) +{ + struct dentry *dentry; + u32 value_len; + void *value; + int ret; + + if (strncmp(name__str, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) + return -EPERM; + + value_len = __bpf_dynptr_size(value_ptr); + value = __bpf_dynptr_data_rw(value_ptr, value_len); + if (!value) + return -EINVAL; + + dentry = file_dentry(file); + ret = inode_permission(&nop_mnt_idmap, dentry->d_inode, MAY_READ); + if (ret) + return ret; + return __vfs_getxattr(dentry, dentry->d_inode, name__str, value, value_len); +} + +__bpf_kfunc_end_defs(); + +BTF_SET8_START(fs_kfunc_set_ids) +BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) +BTF_SET8_END(fs_kfunc_set_ids) + +static int bpf_get_file_xattr_filter(const struct bpf_prog *prog, u32 kfunc_id) +{ + if (!btf_id_set8_contains(&fs_kfunc_set_ids, kfunc_id)) + return 0; + + /* Only allow to attach from LSM hooks, to avoid recursion */ + return prog->type != BPF_PROG_TYPE_LSM ? -EACCES : 0; +} + +static const struct btf_kfunc_id_set bpf_fs_kfunc_set = { + .owner = THIS_MODULE, + .set = &fs_kfunc_set_ids, + .filter = bpf_get_file_xattr_filter, +}; + +static int __init bpf_fs_kfuncs_init(void) +{ + return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set); +} + +late_initcall(bpf_fs_kfuncs_init); + static const struct bpf_func_proto * bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { From 67814c00de3161181cddd06c77aeaf86ac4cc584 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:13 -0800 Subject: [PATCH 2180/7721] bpf, fsverity: Add kfunc bpf_get_fsverity_digest fsverity provides fast and reliable hash of files, namely fsverity_digest. The digest can be used by security solutions to verify file contents. Add new kfunc bpf_get_fsverity_digest() so that we can access fsverity from BPF LSM programs. This kfunc is added to fs/verity/measure.c because some data structure used in the function is private to fsverity (fs/verity/fsverity_private.h). To avoid recursion, bpf_get_fsverity_digest is only allowed in BPF LSM programs. Signed-off-by: Song Liu Acked-by: Eric Biggers Link: https://lore.kernel.org/r/20231129234417.856536-3-song@kernel.org Signed-off-by: Alexei Starovoitov --- fs/verity/fsverity_private.h | 10 +++++ fs/verity/init.c | 1 + fs/verity/measure.c | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index d071a6e32581..a6a6b2749241 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -100,6 +100,16 @@ fsverity_msg(const struct inode *inode, const char *level, #define fsverity_err(inode, fmt, ...) \ fsverity_msg((inode), KERN_ERR, fmt, ##__VA_ARGS__) +/* measure.c */ + +#ifdef CONFIG_BPF_SYSCALL +void __init fsverity_init_bpf(void); +#else +static inline void fsverity_init_bpf(void) +{ +} +#endif + /* open.c */ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, diff --git a/fs/verity/init.c b/fs/verity/init.c index a29f062f6047..1e207c0f71de 100644 --- a/fs/verity/init.c +++ b/fs/verity/init.c @@ -69,6 +69,7 @@ static int __init fsverity_init(void) fsverity_init_workqueue(); fsverity_init_sysctl(); fsverity_init_signature(); + fsverity_init_bpf(); return 0; } late_initcall(fsverity_init) diff --git a/fs/verity/measure.c b/fs/verity/measure.c index eec5956141da..bf7a5f4cccaf 100644 --- a/fs/verity/measure.c +++ b/fs/verity/measure.c @@ -7,6 +7,8 @@ #include "fsverity_private.h" +#include +#include #include /** @@ -100,3 +102,85 @@ int fsverity_get_digest(struct inode *inode, return hash_alg->digest_size; } EXPORT_SYMBOL_GPL(fsverity_get_digest); + +#ifdef CONFIG_BPF_SYSCALL + +/* bpf kfuncs */ +__bpf_kfunc_start_defs(); + +/** + * bpf_get_fsverity_digest: read fsverity digest of file + * @file: file to get digest from + * @digest_ptr: (out) dynptr for struct fsverity_digest + * + * Read fsverity_digest of *file* into *digest_ptr*. + * + * Return: 0 on success, a negative value on error. + */ +__bpf_kfunc int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr_kern *digest_ptr) +{ + const struct inode *inode = file_inode(file); + u32 dynptr_sz = __bpf_dynptr_size(digest_ptr); + struct fsverity_digest *arg; + const struct fsverity_info *vi; + const struct fsverity_hash_alg *hash_alg; + int out_digest_sz; + + if (dynptr_sz < sizeof(struct fsverity_digest)) + return -EINVAL; + + arg = __bpf_dynptr_data_rw(digest_ptr, dynptr_sz); + if (!arg) + return -EINVAL; + + if (!IS_ALIGNED((uintptr_t)arg, __alignof__(*arg))) + return -EINVAL; + + vi = fsverity_get_info(inode); + if (!vi) + return -ENODATA; /* not a verity file */ + + hash_alg = vi->tree_params.hash_alg; + + arg->digest_algorithm = hash_alg - fsverity_hash_algs; + arg->digest_size = hash_alg->digest_size; + + out_digest_sz = dynptr_sz - sizeof(struct fsverity_digest); + + /* copy digest */ + memcpy(arg->digest, vi->file_digest, min_t(int, hash_alg->digest_size, out_digest_sz)); + + /* fill the extra buffer with zeros */ + if (out_digest_sz > hash_alg->digest_size) + memset(arg->digest + arg->digest_size, 0, out_digest_sz - hash_alg->digest_size); + + return 0; +} + +__bpf_kfunc_end_defs(); + +BTF_SET8_START(fsverity_set_ids) +BTF_ID_FLAGS(func, bpf_get_fsverity_digest, KF_TRUSTED_ARGS) +BTF_SET8_END(fsverity_set_ids) + +static int bpf_get_fsverity_digest_filter(const struct bpf_prog *prog, u32 kfunc_id) +{ + if (!btf_id_set8_contains(&fsverity_set_ids, kfunc_id)) + return 0; + + /* Only allow to attach from LSM hooks, to avoid recursion */ + return prog->type != BPF_PROG_TYPE_LSM ? -EACCES : 0; +} + +static const struct btf_kfunc_id_set bpf_fsverity_set = { + .owner = THIS_MODULE, + .set = &fsverity_set_ids, + .filter = bpf_get_fsverity_digest_filter, +}; + +void __init fsverity_init_bpf(void) +{ + register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fsverity_set); +} + +#endif /* CONFIG_BPF_SYSCALL */ From 0de267d9ec6574536ec5ea2f2242df5c92bcdd4b Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:14 -0800 Subject: [PATCH 2181/7721] Documentation/bpf: Add documentation for filesystem kfuncs Add a brief introduction for file system kfuncs: bpf_get_file_xattr() bpf_get_fsverity_digest() The documentation highlights the strategy to avoid recursions of these kfuncs. Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231129234417.856536-4-song@kernel.org Signed-off-by: Alexei Starovoitov --- Documentation/bpf/fs_kfuncs.rst | 21 +++++++++++++++++++++ Documentation/bpf/index.rst | 1 + 2 files changed, 22 insertions(+) create mode 100644 Documentation/bpf/fs_kfuncs.rst diff --git a/Documentation/bpf/fs_kfuncs.rst b/Documentation/bpf/fs_kfuncs.rst new file mode 100644 index 000000000000..8762c3233a3d --- /dev/null +++ b/Documentation/bpf/fs_kfuncs.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _fs_kfuncs-header-label: + +===================== +BPF filesystem kfuncs +===================== + +BPF LSM programs need to access filesystem data from LSM hooks. The following +BPF kfuncs can be used to get these data. + + * ``bpf_get_file_xattr()`` + + * ``bpf_get_fsverity_digest()`` + +To avoid recursions, these kfuncs follow the following rules: + +1. These kfuncs are only permitted from BPF LSM function. +2. These kfuncs should not call into other LSM hooks, i.e. security_*(). For + example, ``bpf_get_file_xattr()`` does not use ``vfs_getxattr()``, because + the latter calls LSM hook ``security_inode_getxattr``. diff --git a/Documentation/bpf/index.rst b/Documentation/bpf/index.rst index aeaeb35e6d4a..0bb5cb8157f1 100644 --- a/Documentation/bpf/index.rst +++ b/Documentation/bpf/index.rst @@ -21,6 +21,7 @@ that goes into great technical depth about the BPF Architecture. helpers kfuncs cpumasks + fs_kfuncs programs maps bpf_prog_run From 6b0ae4566aba566a2ab4a2de9c59ab3d7f4b43c2 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:15 -0800 Subject: [PATCH 2182/7721] selftests/bpf: Sort config in alphabetic order Move CONFIG_VSOCKETS up, so the CONFIGs are in alphabetic order. Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231129234417.856536-5-song@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 3ec5927ec3e5..782876452acf 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -82,7 +82,7 @@ CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_TEST_BPF=m CONFIG_USERFAULTFD=y +CONFIG_VSOCKETS=y CONFIG_VXLAN=y CONFIG_XDP_SOCKETS=y CONFIG_XFRM_INTERFACE=y -CONFIG_VSOCKETS=y From 341f06fdddf72cd60a10945152f69f0f1d614519 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:16 -0800 Subject: [PATCH 2183/7721] selftests/bpf: Add tests for filesystem kfuncs Add selftests for two new filesystem kfuncs: 1. bpf_get_file_xattr 2. bpf_get_fsverity_digest These tests simply make sure the two kfuncs work. Another selftest will be added to demonstrate how to use these kfuncs to verify file signature. CONFIG_FS_VERITY is added to selftests config. However, this is not sufficient to guarantee bpf_get_fsverity_digest works. This is because fsverity need to be enabled at file system level (for example, with tune2fs on ext4). If local file system doesn't have this feature enabled, just skip the test. Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231129234417.856536-6-song@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_kfuncs.h | 3 + tools/testing/selftests/bpf/config | 1 + .../selftests/bpf/prog_tests/fs_kfuncs.c | 134 ++++++++++++++++++ .../selftests/bpf/progs/test_fsverity.c | 48 +++++++ .../selftests/bpf/progs/test_get_xattr.c | 37 +++++ 5 files changed, 223 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c create mode 100644 tools/testing/selftests/bpf/progs/test_fsverity.c create mode 100644 tools/testing/selftests/bpf/progs/test_get_xattr.c diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 5ca68ff0b59f..c2c084a44eae 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -55,4 +55,7 @@ void *bpf_cast_to_kern_ctx(void *) __ksym; void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; +extern int bpf_get_file_xattr(struct file *file, const char *name, + struct bpf_dynptr *value_ptr) __ksym; +extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym; #endif diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 782876452acf..c125c441abc7 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -23,6 +23,7 @@ CONFIG_FPROBE=y CONFIG_FTRACE_SYSCALLS=y CONFIG_FUNCTION_ERROR_INJECTION=y CONFIG_FUNCTION_TRACER=y +CONFIG_FS_VERITY=y CONFIG_GENEVE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c new file mode 100644 index 000000000000..d3196a4b089f --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include +#include +#include "test_get_xattr.skel.h" +#include "test_fsverity.skel.h" + +static const char testfile[] = "/tmp/test_progs_fs_kfuncs"; + +static void test_xattr(void) +{ + struct test_get_xattr *skel = NULL; + int fd = -1, err; + + fd = open(testfile, O_CREAT | O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + close(fd); + fd = -1; + + err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0); + if (!ASSERT_OK(err, "setxattr")) + goto out; + + skel = test_get_xattr__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_get_xattr__attach(skel); + + if (!ASSERT_OK(err, "test_get_xattr__attach")) + goto out; + + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file")) + goto out; + + ASSERT_EQ(skel->bss->found_xattr, 1, "found_xattr"); + +out: + close(fd); + test_get_xattr__destroy(skel); + remove(testfile); +} + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +static void test_fsverity(void) +{ + struct fsverity_enable_arg arg = {0}; + struct test_fsverity *skel = NULL; + struct fsverity_digest *d; + int fd, err; + char buffer[4096]; + + fd = open(testfile, O_CREAT | O_RDWR, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + /* Write random buffer, so the file is not empty */ + err = write(fd, buffer, 4096); + if (!ASSERT_EQ(err, 4096, "write_file")) + goto out; + close(fd); + + /* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */ + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file1")) + return; + + /* Enable fsverity for the file. + * If the file system doesn't support verity, this will fail. Skip + * the test in such case. + */ + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg); + if (err) { + printf("%s:SKIP:local fs doesn't support fsverity (%d)\n" + "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n", + __func__, errno); + test__skip(); + goto out; + } + + skel = test_fsverity__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load")) + goto out; + + /* Get fsverity_digest from ioctl */ + d = (struct fsverity_digest *)skel->bss->expected_digest; + d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256; + d->digest_size = SHA256_DIGEST_SIZE; + err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest); + if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_fsverity__attach(skel); + if (!ASSERT_OK(err, "test_fsverity__attach")) + goto out; + + /* Reopen the file to trigger the program */ + close(fd); + fd = open(testfile, O_RDONLY); + if (!ASSERT_GE(fd, 0, "open_file2")) + goto out; + + ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity"); + ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches"); +out: + close(fd); + test_fsverity__destroy(skel); + remove(testfile); +} + +void test_fs_kfuncs(void) +{ + if (test__start_subtest("xattr")) + test_xattr(); + + if (test__start_subtest("fsverity")) + test_fsverity(); +} diff --git a/tools/testing/selftests/bpf/progs/test_fsverity.c b/tools/testing/selftests/bpf/progs/test_fsverity.c new file mode 100644 index 000000000000..3975495b75c8 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_fsverity.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#define SIZEOF_STRUCT_FSVERITY_DIGEST 4 /* sizeof(struct fsverity_digest) */ + +char expected_digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; +char digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; +__u32 monitored_pid; +__u32 got_fsverity; +__u32 digest_matches; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr; + __u32 pid; + int ret; + int i; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + ret = bpf_get_fsverity_digest(f, &digest_ptr); + if (ret < 0) + return 0; + got_fsverity = 1; + + for (i = 0; i < sizeof(digest); i++) { + if (digest[i] != expected_digest[i]) + return 0; + } + + digest_matches = 1; + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_get_xattr.c b/tools/testing/selftests/bpf/progs/test_get_xattr.c new file mode 100644 index 000000000000..7eb2a4e5a3e5 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_get_xattr.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +__u32 monitored_pid; +__u32 found_xattr; + +static const char expected_value[] = "hello"; +char value[32]; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr value_ptr; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr); + + ret = bpf_get_file_xattr(f, "user.kfuncs", &value_ptr); + if (ret != sizeof(expected_value)) + return 0; + if (bpf_strncmp(value, ret, expected_value)) + return 0; + found_xattr = 1; + return 0; +} From 1030e9154258b54e3c7dc07c39e7b6dcf24bc3d2 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 29 Nov 2023 15:44:17 -0800 Subject: [PATCH 2184/7721] selftests/bpf: Add test that uses fsverity and xattr to sign a file This selftests shows a proof of concept method to use BPF LSM to enforce file signature. This test is added to verify_pkcs7_sig, so that some existing logic can be reused. This file signature method uses fsverity, which provides reliable and efficient hash (known as digest) of the file. The file digest is signed with asymmetic key, and the signature is stored in xattr. At the run time, BPF LSM reads file digest and the signature, and then checks them against the public key. Note that this solution does NOT require FS_VERITY_BUILTIN_SIGNATURES. fsverity is only used to provide file digest. The signature verification and access control is all implemented in BPF LSM. Signed-off-by: Song Liu Link: https://lore.kernel.org/r/20231129234417.856536-7-song@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_kfuncs.h | 7 + .../bpf/prog_tests/verify_pkcs7_sig.c | 165 +++++++++++++++++- .../selftests/bpf/progs/test_sig_in_xattr.c | 83 +++++++++ .../bpf/progs/test_verify_pkcs7_sig.c | 8 +- .../testing/selftests/bpf/verify_sig_setup.sh | 25 +++ 5 files changed, 280 insertions(+), 8 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/test_sig_in_xattr.c diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index c2c084a44eae..b4e78c1eb37b 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -58,4 +58,11 @@ void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; extern int bpf_get_file_xattr(struct file *file, const char *name, struct bpf_dynptr *value_ptr) __ksym; extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym; + +extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; +extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; +extern void bpf_key_put(struct bpf_key *key) __ksym; +extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, + struct bpf_dynptr *sig_ptr, + struct bpf_key *trusted_keyring) __ksym; #endif diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c index dd7f2bc70048..6c90372b772d 100644 --- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -16,9 +16,12 @@ #include #include #include +#include +#include #include #include "test_verify_pkcs7_sig.skel.h" +#include "test_sig_in_xattr.skel.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 @@ -26,6 +29,10 @@ #define VERIFY_USE_SECONDARY_KEYRING (1UL) #define VERIFY_USE_PLATFORM_KEYRING (2UL) +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ #define MODULE_SIG_STRING "~Module signature appended~\n" @@ -254,7 +261,7 @@ static int populate_data_item_mod(struct data *data_item) return ret; } -void test_verify_pkcs7_sig(void) +static void test_verify_pkcs7_sig_from_map(void) { libbpf_print_fn_t old_print_cb; char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; @@ -400,3 +407,159 @@ void test_verify_pkcs7_sig(void) skel->bss->monitored_pid = 0; test_verify_pkcs7_sig__destroy(skel); } + +static int get_signature_size(const char *sig_path) +{ + struct stat st; + + if (stat(sig_path, &st) == -1) + return -1; + + return st.st_size; +} + +static int add_signature_to_xattr(const char *data_path, const char *sig_path) +{ + char sig[MAX_SIG_SIZE] = {0}; + int fd, size, ret; + + if (sig_path) { + fd = open(sig_path, O_RDONLY); + if (fd < 0) + return -1; + + size = read(fd, sig, MAX_SIG_SIZE); + close(fd); + if (size <= 0) + return -1; + } else { + /* no sig_path, just write 32 bytes of zeros */ + size = 32; + } + ret = setxattr(data_path, "user.sig", sig, size, 0); + if (!ASSERT_OK(ret, "setxattr")) + return -1; + + return 0; +} + +static int test_open_file(struct test_sig_in_xattr *skel, char *data_path, + pid_t pid, bool should_success, char *name) +{ + int ret; + + skel->bss->monitored_pid = pid; + ret = open(data_path, O_RDONLY); + close(ret); + skel->bss->monitored_pid = 0; + + if (should_success) { + if (!ASSERT_GE(ret, 0, name)) + return -1; + } else { + if (!ASSERT_LT(ret, 0, name)) + return -1; + } + return 0; +} + +static void test_pkcs7_sig_fsverity(void) +{ + char data_path[PATH_MAX]; + char sig_path[PATH_MAX]; + char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; + char *tmp_dir; + struct test_sig_in_xattr *skel = NULL; + pid_t pid; + int ret; + + tmp_dir = mkdtemp(tmp_dir_template); + if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp")) + return; + + snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir); + snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir); + + ret = _run_setup_process(tmp_dir, "setup"); + if (!ASSERT_OK(ret, "_run_setup_process")) + goto out; + + ret = _run_setup_process(tmp_dir, "fsverity-create-sign"); + + if (ret) { + printf("%s: SKIP: fsverity [sign|enable] doesn't work.\n" + "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n", + __func__); + test__skip(); + goto out; + } + + skel = test_sig_in_xattr__open(); + if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open")) + goto out; + ret = get_signature_size(sig_path); + if (!ASSERT_GT(ret, 0, "get_signaure_size")) + goto out; + skel->bss->sig_size = ret; + skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring", + "ebpf_testing_keyring", NULL, + KEY_SPEC_SESSION_KEYRING); + memcpy(skel->bss->digest, "FSVerity", 8); + + ret = test_sig_in_xattr__load(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__load")) + goto out; + + ret = test_sig_in_xattr__attach(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__attach")) + goto out; + + pid = getpid(); + + /* Case 1: fsverity is not enabled, open should succeed */ + if (test_open_file(skel, data_path, pid, true, "open_1")) + goto out; + + /* Case 2: fsverity is enabled, xattr is missing, open should + * fail + */ + ret = _run_setup_process(tmp_dir, "fsverity-enable"); + if (!ASSERT_OK(ret, "fsverity-enable")) + goto out; + if (test_open_file(skel, data_path, pid, false, "open_2")) + goto out; + + /* Case 3: fsverity is enabled, xattr has valid signature, open + * should succeed + */ + ret = add_signature_to_xattr(data_path, sig_path); + if (!ASSERT_OK(ret, "add_signature_to_xattr_1")) + goto out; + + if (test_open_file(skel, data_path, pid, true, "open_3")) + goto out; + + /* Case 4: fsverity is enabled, xattr has invalid signature, open + * should fail + */ + ret = add_signature_to_xattr(data_path, NULL); + if (!ASSERT_OK(ret, "add_signature_to_xattr_2")) + goto out; + test_open_file(skel, data_path, pid, false, "open_4"); + +out: + _run_setup_process(tmp_dir, "cleanup"); + if (!skel) + return; + + skel->bss->monitored_pid = 0; + test_sig_in_xattr__destroy(skel); +} + +void test_verify_pkcs7_sig(void) +{ + if (test__start_subtest("pkcs7_sig_from_map")) + test_verify_pkcs7_sig_from_map(); + if (test__start_subtest("pkcs7_sig_fsverity")) + test_pkcs7_sig_fsverity(); +} diff --git a/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c new file mode 100644 index 000000000000..2f0eb1334d65 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#define MAX_SIG_SIZE 1024 + +/* By default, "fsverity sign" signs a file with fsverity_formatted_digest + * of the file. fsverity_formatted_digest on the kernel side is only used + * with CONFIG_FS_VERITY_BUILTIN_SIGNATURES. However, BPF LSM doesn't not + * require CONFIG_FS_VERITY_BUILTIN_SIGNATURES, so vmlinux.h may not have + * fsverity_formatted_digest. In this test, we intentionally avoid using + * fsverity_formatted_digest. + * + * Luckily, fsverity_formatted_digest is simply 8-byte magic followed by + * fsverity_digest. We use a char array of size fsverity_formatted_digest + * plus SHA256_DIGEST_SIZE. The magic part of it is filled by user space, + * and the rest of it is filled by bpf_get_fsverity_digest. + * + * Note that, generating signatures based on fsverity_formatted_digest is + * the design choice of this selftest (and "fsverity sign"). With BPF + * LSM, we have the flexibility to generate signature based on other data + * sets, for example, fsverity_digest or only the digest[] part of it. + */ +#define MAGIC_SIZE 8 +#define SIZEOF_STRUCT_FSVERITY_DIGEST 4 /* sizeof(struct fsverity_digest) */ +char digest[MAGIC_SIZE + SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; + +__u32 monitored_pid; +char sig[MAX_SIG_SIZE]; +__u32 sig_size; +__u32 user_keyring_serial; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr, sig_ptr; + struct bpf_key *trusted_keyring; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + /* digest_ptr points to fsverity_digest */ + bpf_dynptr_from_mem(digest + MAGIC_SIZE, sizeof(digest) - MAGIC_SIZE, 0, &digest_ptr); + + ret = bpf_get_fsverity_digest(f, &digest_ptr); + /* No verity, allow access */ + if (ret < 0) + return 0; + + /* Move digest_ptr to fsverity_formatted_digest */ + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + + /* Read signature from xattr */ + bpf_dynptr_from_mem(sig, sizeof(sig), 0, &sig_ptr); + ret = bpf_get_file_xattr(f, "user.sig", &sig_ptr); + /* No signature, reject access */ + if (ret < 0) + return -EPERM; + + trusted_keyring = bpf_lookup_user_key(user_keyring_serial, 0); + if (!trusted_keyring) + return -ENOENT; + + /* Verify signature */ + ret = bpf_verify_pkcs7_signature(&digest_ptr, &sig_ptr, trusted_keyring); + + bpf_key_put(trusted_keyring); + return ret; +} diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c index 7748cc23de8a..f42e9f3831a1 100644 --- a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c @@ -10,17 +10,11 @@ #include #include #include +#include "bpf_kfuncs.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 -extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; -extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; -extern void bpf_key_put(struct bpf_key *key) __ksym; -extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, - struct bpf_dynptr *sig_ptr, - struct bpf_key *trusted_keyring) __ksym; - __u32 monitored_pid; __u32 user_keyring_serial; __u64 system_keyring_id; diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh index ba08922b4a27..f2cac42298ba 100755 --- a/tools/testing/selftests/bpf/verify_sig_setup.sh +++ b/tools/testing/selftests/bpf/verify_sig_setup.sh @@ -60,6 +60,27 @@ cleanup() { rm -rf ${tmp_dir} } +fsverity_create_sign_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + sig_file=${tmp_dir}/sig-file + dd if=/dev/urandom of=$data_file bs=1 count=12345 2> /dev/null + fsverity sign --key ${tmp_dir}/signing_key.pem $data_file $sig_file + + # We do not want to enable fsverity on $data_file yet. Try whether + # the file system support fsverity on a different file. + touch ${tmp_dir}/tmp-file + fsverity enable ${tmp_dir}/tmp-file +} + +fsverity_enable_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + fsverity enable $data_file +} + catch() { local exit_code="$1" @@ -86,6 +107,10 @@ main() setup "${tmp_dir}" elif [[ "${action}" == "cleanup" ]]; then cleanup "${tmp_dir}" + elif [[ "${action}" == "fsverity-create-sign" ]]; then + fsverity_create_sign_file "${tmp_dir}" + elif [[ "${action}" == "fsverity-enable" ]]; then + fsverity_enable_file "${tmp_dir}" else echo "Unknown action: ${action}" exit 1 From 492c5d455969fc2e829f26ed4c83487b068f0dd7 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 30 Nov 2023 13:53:06 -0800 Subject: [PATCH 2185/7721] block: bio-integrity: directly map user buffers Passthrough commands that utilize metadata currently need to bounce the user space buffer through the kernel. Add support for mapping user space directly so that we can avoid this costly overhead. This is similar to how the normal bio data payload utilizes user addresses with bio_map_user_iov(). If the user address can't directly be used for reason, like too many segments or address unalignement, fallback to a copy of the user vec while keeping the user address pinned for the IO duration so that it can safely be copied on completion in any process context. Signed-off-by: Keith Busch Link: https://lore.kernel.org/r/20231130215309.2923568-2-kbusch@meta.com [axboe: fold in fix from Kanchan Joshi] Signed-off-by: Jens Axboe --- block/bio-integrity.c | 218 +++++++++++++++++++++++++++++++++++++++++- include/linux/bio.h | 9 ++ 2 files changed, 225 insertions(+), 2 deletions(-) diff --git a/block/bio-integrity.c b/block/bio-integrity.c index ec8ac8cf6e1b..feef615e2c9c 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -69,15 +69,15 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, memset(bip, 0, sizeof(*bip)); + /* always report as many vecs as asked explicitly, not inline vecs */ + bip->bip_max_vcnt = nr_vecs; if (nr_vecs > inline_vecs) { - bip->bip_max_vcnt = nr_vecs; bip->bip_vec = bvec_alloc(&bs->bvec_integrity_pool, &bip->bip_max_vcnt, gfp_mask); if (!bip->bip_vec) goto err; } else { bip->bip_vec = bip->bip_inline_vecs; - bip->bip_max_vcnt = inline_vecs; } bip->bip_bio = bio; @@ -91,6 +91,47 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, } EXPORT_SYMBOL(bio_integrity_alloc); +static void bio_integrity_unpin_bvec(struct bio_vec *bv, int nr_vecs, + bool dirty) +{ + int i; + + for (i = 0; i < nr_vecs; i++) { + if (dirty && !PageCompound(bv[i].bv_page)) + set_page_dirty_lock(bv[i].bv_page); + unpin_user_page(bv[i].bv_page); + } +} + +static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip) +{ + unsigned short nr_vecs = bip->bip_max_vcnt - 1; + struct bio_vec *copy = &bip->bip_vec[1]; + size_t bytes = bip->bip_iter.bi_size; + struct iov_iter iter; + int ret; + + iov_iter_bvec(&iter, ITER_DEST, copy, nr_vecs, bytes); + ret = copy_to_iter(bvec_virt(bip->bip_vec), bytes, &iter); + WARN_ON_ONCE(ret != bytes); + + bio_integrity_unpin_bvec(copy, nr_vecs, true); +} + +static void bio_integrity_unmap_user(struct bio_integrity_payload *bip) +{ + bool dirty = bio_data_dir(bip->bip_bio) == READ; + + if (bip->bip_flags & BIP_COPY_USER) { + if (dirty) + bio_integrity_uncopy_user(bip); + kfree(bvec_virt(bip->bip_vec)); + return; + } + + bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt, dirty); +} + /** * bio_integrity_free - Free bio integrity payload * @bio: bio containing bip to be freed @@ -105,6 +146,8 @@ void bio_integrity_free(struct bio *bio) if (bip->bip_flags & BIP_BLOCK_INTEGRITY) kfree(bvec_virt(bip->bip_vec)); + else if (bip->bip_flags & BIP_INTEGRITY_USER) + bio_integrity_unmap_user(bip); __bio_integrity_free(bs, bip); bio->bi_integrity = NULL; @@ -160,6 +203,177 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, } EXPORT_SYMBOL(bio_integrity_add_page); +static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + int nr_vecs, unsigned int len, + unsigned int direction, u32 seed) +{ + bool write = direction == ITER_SOURCE; + struct bio_integrity_payload *bip; + struct iov_iter iter; + void *buf; + int ret; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (write) { + iov_iter_bvec(&iter, direction, bvec, nr_vecs, len); + if (!copy_from_iter_full(buf, len, &iter)) { + ret = -EFAULT; + goto free_buf; + } + + bip = bio_integrity_alloc(bio, GFP_KERNEL, 1); + } else { + memset(buf, 0, len); + + /* + * We need to preserve the original bvec and the number of vecs + * in it for completion handling + */ + bip = bio_integrity_alloc(bio, GFP_KERNEL, nr_vecs + 1); + } + + if (IS_ERR(bip)) { + ret = PTR_ERR(bip); + goto free_buf; + } + + if (write) + bio_integrity_unpin_bvec(bvec, nr_vecs, false); + else + memcpy(&bip->bip_vec[1], bvec, nr_vecs * sizeof(*bvec)); + + ret = bio_integrity_add_page(bio, virt_to_page(buf), len, + offset_in_page(buf)); + if (ret != len) { + ret = -ENOMEM; + goto free_bip; + } + + bip->bip_flags |= BIP_INTEGRITY_USER | BIP_COPY_USER; + bip->bip_iter.bi_sector = seed; + return 0; +free_bip: + bio_integrity_free(bio); +free_buf: + kfree(buf); + return ret; +} + +static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, + int nr_vecs, unsigned int len, u32 seed) +{ + struct bio_integrity_payload *bip; + + bip = bio_integrity_alloc(bio, GFP_KERNEL, nr_vecs); + if (IS_ERR(bip)) + return PTR_ERR(bip); + + memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec)); + bip->bip_flags |= BIP_INTEGRITY_USER; + bip->bip_iter.bi_sector = seed; + bip->bip_iter.bi_size = len; + return 0; +} + +static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + int nr_vecs, ssize_t bytes, ssize_t offset) +{ + unsigned int nr_bvecs = 0; + int i, j; + + for (i = 0; i < nr_vecs; i = j) { + size_t size = min_t(size_t, bytes, PAGE_SIZE - offset); + struct folio *folio = page_folio(pages[i]); + + bytes -= size; + for (j = i + 1; j < nr_vecs; j++) { + size_t next = min_t(size_t, PAGE_SIZE, bytes); + + if (page_folio(pages[j]) != folio || + pages[j] != pages[j - 1] + 1) + break; + unpin_user_page(pages[j]); + size += next; + bytes -= next; + } + + bvec_set_page(&bvec[nr_bvecs], pages[i], size, offset); + offset = 0; + nr_bvecs++; + } + + return nr_bvecs; +} + +int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, + u32 seed) +{ + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + unsigned int align = q->dma_pad_mask | queue_dma_alignment(q); + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; + unsigned int direction, nr_bvecs; + struct iov_iter iter; + int ret, nr_vecs; + size_t offset; + bool copy; + + if (bio_integrity(bio)) + return -EINVAL; + if (bytes >> SECTOR_SHIFT > queue_max_hw_sectors(q)) + return -E2BIG; + + if (bio_data_dir(bio) == READ) + direction = ITER_DEST; + else + direction = ITER_SOURCE; + + iov_iter_ubuf(&iter, direction, ubuf, bytes); + nr_vecs = iov_iter_npages(&iter, BIO_MAX_VECS + 1); + if (nr_vecs > BIO_MAX_VECS) + return -E2BIG; + if (nr_vecs > UIO_FASTIOV) { + bvec = kcalloc(sizeof(*bvec), nr_vecs, GFP_KERNEL); + if (!bvec) + return -ENOMEM; + pages = NULL; + } + + copy = !iov_iter_is_aligned(&iter, align, align); + ret = iov_iter_extract_pages(&iter, &pages, bytes, nr_vecs, 0, &offset); + if (unlikely(ret < 0)) + goto free_bvec; + + nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset); + if (pages != stack_pages) + kvfree(pages); + if (nr_bvecs > queue_max_integrity_segments(q)) + copy = true; + + if (copy) + ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, + direction, seed); + else + ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes, seed); + if (ret) + goto release_pages; + if (bvec != stack_vec) + kfree(bvec); + + return 0; + +release_pages: + bio_integrity_unpin_bvec(bvec, nr_bvecs, false); +free_bvec: + if (bvec != stack_vec) + kfree(bvec); + return ret; +} +EXPORT_SYMBOL_GPL(bio_integrity_map_user); + /** * bio_integrity_process - Process integrity metadata for a bio * @bio: bio to generate/verify integrity metadata for diff --git a/include/linux/bio.h b/include/linux/bio.h index 41d417ee1349..ec4db73e5f4e 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -324,6 +324,8 @@ enum bip_flags { BIP_CTRL_NOCHECK = 1 << 2, /* disable HBA integrity checking */ BIP_DISK_NOCHECK = 1 << 3, /* disable disk integrity checking */ BIP_IP_CHECKSUM = 1 << 4, /* IP checksum */ + BIP_INTEGRITY_USER = 1 << 5, /* Integrity payload is user address */ + BIP_COPY_USER = 1 << 6, /* Kernel bounce buffer in use */ }; /* @@ -718,6 +720,7 @@ static inline bool bioset_initialized(struct bio_set *bs) for_each_bio(_bio) \ bip_for_each_vec(_bvl, _bio->bi_integrity, _iter) +int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len, u32 seed); extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int); extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); extern bool bio_integrity_prep(struct bio *); @@ -789,6 +792,12 @@ static inline int bio_integrity_add_page(struct bio *bio, struct page *page, return 0; } +static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf, + ssize_t len, u32 seed) +{ + return -EINVAL; +} + #endif /* CONFIG_BLK_DEV_INTEGRITY */ /* From d6aacee9255e7fc10654d867f077d7b0e381eeec Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 30 Nov 2023 13:53:07 -0800 Subject: [PATCH 2186/7721] nvme: use bio_integrity_map_user Map user metadata buffers directly. Now that the bio tracks the metadata, nvme doesn't need special metadata handling and tracking with callbacks and additional fields in the pdu. Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Keith Busch Link: https://lore.kernel.org/r/20231130215309.2923568-3-kbusch@meta.com Signed-off-by: Jens Axboe --- drivers/nvme/host/ioctl.c | 199 ++++++-------------------------------- 1 file changed, 30 insertions(+), 169 deletions(-) diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index 529b9954d2b8..32c9bcf491a3 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -96,58 +96,6 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval) return (void __user *)ptrval; } -static void *nvme_add_user_metadata(struct request *req, void __user *ubuf, - unsigned len, u32 seed) -{ - struct bio_integrity_payload *bip; - int ret = -ENOMEM; - void *buf; - struct bio *bio = req->bio; - - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - goto out; - - if (req_op(req) == REQ_OP_DRV_OUT) { - ret = -EFAULT; - if (copy_from_user(buf, ubuf, len)) - goto out_free_meta; - } else { - memset(buf, 0, len); - } - - bip = bio_integrity_alloc(bio, GFP_KERNEL, 1); - if (IS_ERR(bip)) { - ret = PTR_ERR(bip); - goto out_free_meta; - } - - bip->bip_iter.bi_sector = seed; - ret = bio_integrity_add_page(bio, virt_to_page(buf), len, - offset_in_page(buf)); - if (ret != len) { - ret = -ENOMEM; - goto out_free_meta; - } - - req->cmd_flags |= REQ_INTEGRITY; - return buf; -out_free_meta: - kfree(buf); -out: - return ERR_PTR(ret); -} - -static int nvme_finish_user_metadata(struct request *req, void __user *ubuf, - void *meta, unsigned len, int ret) -{ - if (!ret && req_op(req) == REQ_OP_DRV_IN && - copy_to_user(ubuf, meta, len)) - ret = -EFAULT; - kfree(meta); - return ret; -} - static struct request *nvme_alloc_user_request(struct request_queue *q, struct nvme_command *cmd, blk_opf_t rq_flags, blk_mq_req_flags_t blk_flags) @@ -164,14 +112,12 @@ static struct request *nvme_alloc_user_request(struct request_queue *q, static int nvme_map_user_request(struct request *req, u64 ubuffer, unsigned bufflen, void __user *meta_buffer, unsigned meta_len, - u32 meta_seed, void **metap, struct io_uring_cmd *ioucmd, - unsigned int flags) + u32 meta_seed, struct io_uring_cmd *ioucmd, unsigned int flags) { struct request_queue *q = req->q; struct nvme_ns *ns = q->queuedata; struct block_device *bdev = ns ? ns->disk->part0 : NULL; struct bio *bio = NULL; - void *meta = NULL; int ret; if (ioucmd && (ioucmd->flags & IORING_URING_CMD_FIXED)) { @@ -193,18 +139,17 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, if (ret) goto out; - bio = req->bio; - if (bdev) - bio_set_dev(bio, bdev); - if (bdev && meta_buffer && meta_len) { - meta = nvme_add_user_metadata(req, meta_buffer, meta_len, - meta_seed); - if (IS_ERR(meta)) { - ret = PTR_ERR(meta); - goto out_unmap; + bio = req->bio; + if (bdev) { + bio_set_dev(bio, bdev); + if (meta_buffer && meta_len) { + ret = bio_integrity_map_user(bio, meta_buffer, meta_len, + meta_seed); + if (ret) + goto out_unmap; + req->cmd_flags |= REQ_INTEGRITY; } - *metap = meta; } return ret; @@ -225,7 +170,6 @@ static int nvme_submit_user_cmd(struct request_queue *q, struct nvme_ns *ns = q->queuedata; struct nvme_ctrl *ctrl; struct request *req; - void *meta = NULL; struct bio *bio; u32 effects; int ret; @@ -237,7 +181,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, req->timeout = timeout; if (ubuffer && bufflen) { ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer, - meta_len, meta_seed, &meta, NULL, flags); + meta_len, meta_seed, NULL, flags); if (ret) return ret; } @@ -249,9 +193,6 @@ static int nvme_submit_user_cmd(struct request_queue *q, ret = nvme_execute_rq(req, false); if (result) *result = le64_to_cpu(nvme_req(req)->result.u64); - if (meta) - ret = nvme_finish_user_metadata(req, meta_buffer, meta, - meta_len, ret); if (bio) blk_rq_unmap_user(bio); blk_mq_free_request(req); @@ -446,19 +387,10 @@ struct nvme_uring_data { * Expect build errors if this grows larger than that. */ struct nvme_uring_cmd_pdu { - union { - struct bio *bio; - struct request *req; - }; - u32 meta_len; - u32 nvme_status; - union { - struct { - void *meta; /* kernel-resident buffer */ - void __user *meta_buffer; - }; - u64 result; - } u; + struct request *req; + struct bio *bio; + u64 result; + int status; }; static inline struct nvme_uring_cmd_pdu *nvme_uring_cmd_pdu( @@ -467,31 +399,6 @@ static inline struct nvme_uring_cmd_pdu *nvme_uring_cmd_pdu( return (struct nvme_uring_cmd_pdu *)&ioucmd->pdu; } -static void nvme_uring_task_meta_cb(struct io_uring_cmd *ioucmd, - unsigned issue_flags) -{ - struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd); - struct request *req = pdu->req; - int status; - u64 result; - - if (nvme_req(req)->flags & NVME_REQ_CANCELLED) - status = -EINTR; - else - status = nvme_req(req)->status; - - result = le64_to_cpu(nvme_req(req)->result.u64); - - if (pdu->meta_len) - status = nvme_finish_user_metadata(req, pdu->u.meta_buffer, - pdu->u.meta, pdu->meta_len, status); - if (req->bio) - blk_rq_unmap_user(req->bio); - blk_mq_free_request(req); - - io_uring_cmd_done(ioucmd, status, result, issue_flags); -} - static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd, unsigned issue_flags) { @@ -499,8 +406,7 @@ static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd, if (pdu->bio) blk_rq_unmap_user(pdu->bio); - - io_uring_cmd_done(ioucmd, pdu->nvme_status, pdu->u.result, issue_flags); + io_uring_cmd_done(ioucmd, pdu->status, pdu->result, issue_flags); } static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req, @@ -509,53 +415,24 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req, struct io_uring_cmd *ioucmd = req->end_io_data; struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd); - req->bio = pdu->bio; - if (nvme_req(req)->flags & NVME_REQ_CANCELLED) { - pdu->nvme_status = -EINTR; - } else { - pdu->nvme_status = nvme_req(req)->status; - if (!pdu->nvme_status) - pdu->nvme_status = blk_status_to_errno(err); - } - pdu->u.result = le64_to_cpu(nvme_req(req)->result.u64); + if (nvme_req(req)->flags & NVME_REQ_CANCELLED) + pdu->status = -EINTR; + else + pdu->status = nvme_req(req)->status; + pdu->result = le64_to_cpu(nvme_req(req)->result.u64); /* * For iopoll, complete it directly. * Otherwise, move the completion to task work. */ - if (blk_rq_is_poll(req)) { - WRITE_ONCE(ioucmd->cookie, NULL); + if (blk_rq_is_poll(req)) nvme_uring_task_cb(ioucmd, IO_URING_F_UNLOCKED); - } else { + else io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb); - } return RQ_END_IO_FREE; } -static enum rq_end_io_ret nvme_uring_cmd_end_io_meta(struct request *req, - blk_status_t err) -{ - struct io_uring_cmd *ioucmd = req->end_io_data; - struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd); - - req->bio = pdu->bio; - pdu->req = req; - - /* - * For iopoll, complete it directly. - * Otherwise, move the completion to task work. - */ - if (blk_rq_is_poll(req)) { - WRITE_ONCE(ioucmd->cookie, NULL); - nvme_uring_task_meta_cb(ioucmd, IO_URING_F_UNLOCKED); - } else { - io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_meta_cb); - } - - return RQ_END_IO_NONE; -} - static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, struct io_uring_cmd *ioucmd, unsigned int issue_flags, bool vec) { @@ -567,7 +444,6 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, struct request *req; blk_opf_t rq_flags = REQ_ALLOC_CACHE; blk_mq_req_flags_t blk_flags = 0; - void *meta = NULL; int ret; c.common.opcode = READ_ONCE(cmd->opcode); @@ -615,27 +491,16 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, if (d.addr && d.data_len) { ret = nvme_map_user_request(req, d.addr, d.data_len, nvme_to_user_ptr(d.metadata), - d.metadata_len, 0, &meta, ioucmd, vec); + d.metadata_len, 0, ioucmd, vec); if (ret) return ret; } - if (blk_rq_is_poll(req)) { - ioucmd->flags |= IORING_URING_CMD_POLLED; - WRITE_ONCE(ioucmd->cookie, req); - } - /* to free bio on completion, as req->bio will be null at that time */ pdu->bio = req->bio; - pdu->meta_len = d.metadata_len; + pdu->req = req; req->end_io_data = ioucmd; - if (pdu->meta_len) { - pdu->u.meta = meta; - pdu->u.meta_buffer = nvme_to_user_ptr(d.metadata); - req->end_io = nvme_uring_cmd_end_io_meta; - } else { - req->end_io = nvme_uring_cmd_end_io; - } + req->end_io = nvme_uring_cmd_end_io; blk_execute_rq_nowait(req, false); return -EIOCBQUEUED; } @@ -786,16 +651,12 @@ int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd, struct io_comp_batch *iob, unsigned int poll_flags) { - struct request *req; - int ret = 0; + struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd); + struct request *req = pdu->req; - if (!(ioucmd->flags & IORING_URING_CMD_POLLED)) - return 0; - - req = READ_ONCE(ioucmd->cookie); if (req && blk_rq_is_poll(req)) - ret = blk_rq_poll(req, iob, poll_flags); - return ret; + return blk_rq_poll(req, iob, poll_flags); + return 0; } #ifdef CONFIG_NVME_MULTIPATH static int nvme_ns_head_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd, From e5da71f1e373f36c7506ffa9a60ef7ec6e84674d Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 30 Nov 2023 13:53:08 -0800 Subject: [PATCH 2187/7721] iouring: remove IORING_URING_CMD_POLLED No more users of this flag. Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Keith Busch Link: https://lore.kernel.org/r/20231130215309.2923568-4-kbusch@meta.com Signed-off-by: Jens Axboe --- include/linux/io_uring.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h index aefb73eeeebf..fe23bf88f86f 100644 --- a/include/linux/io_uring.h +++ b/include/linux/io_uring.h @@ -28,7 +28,6 @@ enum io_uring_cmd_flags { /* only top 8 bits of sqe->uring_cmd_flags for kernel internal use */ #define IORING_URING_CMD_CANCELABLE (1U << 30) -#define IORING_URING_CMD_POLLED (1U << 31) struct io_uring_cmd { struct file *file; From 8fadb86d4ced8b8349a3b227d6d66736ff150819 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 30 Nov 2023 13:53:09 -0800 Subject: [PATCH 2188/7721] io_uring: remove uring_cmd cookie No more users of this field. Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Keith Busch Link: https://lore.kernel.org/r/20231130215309.2923568-5-kbusch@meta.com Signed-off-by: Jens Axboe --- include/linux/io_uring.h | 8 ++------ io_uring/uring_cmd.c | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h index fe23bf88f86f..9e6ce6d4ab51 100644 --- a/include/linux/io_uring.h +++ b/include/linux/io_uring.h @@ -32,12 +32,8 @@ enum io_uring_cmd_flags { struct io_uring_cmd { struct file *file; const struct io_uring_sqe *sqe; - union { - /* callback to defer completions to task context */ - void (*task_work_cb)(struct io_uring_cmd *cmd, unsigned); - /* used for polled completion */ - void *cookie; - }; + /* callback to defer completions to task context */ + void (*task_work_cb)(struct io_uring_cmd *cmd, unsigned); u32 cmd_op; u32 flags; u8 pdu[32]; /* available inline for free use */ diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c index acbc2924ecd2..b39ec25c36bc 100644 --- a/io_uring/uring_cmd.c +++ b/io_uring/uring_cmd.c @@ -182,7 +182,6 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags) return -EOPNOTSUPP; issue_flags |= IO_URING_F_IOPOLL; req->iopoll_completed = 0; - WRITE_ONCE(ioucmd->cookie, NULL); } ret = file->f_op->uring_cmd(ioucmd, issue_flags); From 847c5bcdfb41704e52930783b028302f415a3209 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Fri, 24 Nov 2023 00:33:31 +0530 Subject: [PATCH 2189/7721] block: skip QUEUE_FLAG_STATS and rq-qos for passthrough io Write-back throttling (WBT) enables QUEUE_FLAG_STATS on the request queue. But WBT does not make sense for passthrough io, so skip QUEUE_FLAG_STATS processing. Also skip rq_qos_issue/done for passthrough io. Overall, the change gives ~11% hike in peak performance. Signed-off-by: Kundan Kumar Signed-off-by: Kanchan Joshi Link: https://lore.kernel.org/r/20231123190331.7934-1-kundan.kumar@samsung.com Signed-off-by: Jens Axboe --- block/blk-mq.c | 3 ++- block/blk-rq-qos.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 900c1be1fee1..fb29ff5cc281 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1248,7 +1248,8 @@ void blk_mq_start_request(struct request *rq) trace_block_rq_issue(rq); - if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { + if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags) && + !blk_rq_is_passthrough(rq)) { rq->io_start_time_ns = ktime_get_ns(); rq->stats_sectors = blk_rq_sectors(rq); rq->rq_flags |= RQF_STATS; diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index f48ee150d667..37245c97ee61 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -118,7 +118,7 @@ static inline void rq_qos_cleanup(struct request_queue *q, struct bio *bio) static inline void rq_qos_done(struct request_queue *q, struct request *rq) { - if (q->rq_qos) + if (q->rq_qos && !blk_rq_is_passthrough(rq)) __rq_qos_done(q->rq_qos, rq); } From 527d2cd8b852e06c25c129fe400832bf88d2b5b0 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Thu, 30 Nov 2023 21:49:53 +0000 Subject: [PATCH 2190/7721] doc/netlink: Add bitfield32, s8, s16 to the netlink-raw schema The netlink-raw schema was not updated when bitfield32 was added to the genetlink-legacy schema. It is needed for rtnetlink families. s8 and s16 were also missing. Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20231130214959.27377-2-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/netlink-raw.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 775cce8c548a..ad5395040765 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -200,7 +200,8 @@ properties: type: string type: &attr-type description: The netlink attribute type - enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, + enum: [ unused, pad, flag, binary, bitfield32, + u8, u16, u32, u64, s8, s16, s32, s64, string, nest, array-nest, nest-type-value ] doc: description: Documentation of the attribute. From b32e8fbeace6117b00b072eef3f1726149fe0298 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 30 Nov 2023 18:41:35 +0000 Subject: [PATCH 2191/7721] tcp: tcp_gro_dev_warn() cleanup Use DO_ONCE_LITE_IF() and __cold attribute to put tcp_gro_dev_warn() out of line. This also allows the message to be printed again after a "echo 1 > /sys/kernel/debug/clear_warn_once" Also add a READ_ONCE() when reading device mtu, as it could be changed concurrently. Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20231130184135.4130860-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_input.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bcb55d98004c..0548f0c12155 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -202,23 +202,17 @@ static void bpf_skops_established(struct sock *sk, int bpf_op, } #endif -static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb, - unsigned int len) +static __cold void tcp_gro_dev_warn(const struct sock *sk, const struct sk_buff *skb, + unsigned int len) { - static bool __once __read_mostly; + struct net_device *dev; - if (!__once) { - struct net_device *dev; - - __once = true; - - rcu_read_lock(); - dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); - if (!dev || len >= dev->mtu) - pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", - dev ? dev->name : "Unknown driver"); - rcu_read_unlock(); - } + rcu_read_lock(); + dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); + if (!dev || len >= READ_ONCE(dev->mtu)) + pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", + dev ? dev->name : "Unknown driver"); + rcu_read_unlock(); } /* Adapt the MSS value used to make delayed ack decision to the @@ -250,9 +244,8 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, tcp_sk(sk)->advmss); /* Account for possibly-removed options */ - if (unlikely(len > icsk->icsk_ack.rcv_mss + - MAX_TCP_OPTION_SPACE)) - tcp_gro_dev_warn(sk, skb, len); + DO_ONCE_LITE_IF(len > icsk->icsk_ack.rcv_mss + MAX_TCP_OPTION_SPACE, + tcp_gro_dev_warn, sk, skb, len); /* If the skb has a len of exactly 1*MSS and has the PSH bit * set then it is likely the end of an application write. So * more data may not be arriving soon, and yet the data sender From cc124ad39288ef8366d1f731567115d077e612a1 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Thu, 30 Nov 2023 20:13:59 +0100 Subject: [PATCH 2192/7721] Documentation: networking: add missing PLCA messages from the message list Physical Layer Collision Avoidance messages are correctly documented but were left-out of the global list of ethnl messages, add them to the list. Signed-off-by: Maxime Chevallier Link: https://lore.kernel.org/r/20231130191400.817948-1-maxime.chevallier@bootlin.com Signed-off-by: Jakub Kicinski --- Documentation/networking/ethtool-netlink.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 2540c70952ff..6a49624a9cbf 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -223,6 +223,9 @@ Userspace to kernel: ``ETHTOOL_MSG_PSE_SET`` set PSE parameters ``ETHTOOL_MSG_PSE_GET`` get PSE parameters ``ETHTOOL_MSG_RSS_GET`` get RSS settings + ``ETHTOOL_MSG_PLCA_GET_CFG`` get PLCA RS parameters + ``ETHTOOL_MSG_PLCA_SET_CFG`` set PLCA RS parameters + ``ETHTOOL_MSG_PLCA_GET_STATUS`` get PLCA RS status ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters ===================================== ================================= @@ -267,6 +270,9 @@ Kernel to userspace: ``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings + ``ETHTOOL_MSG_PLCA_GET_CFG_REPLY`` PLCA RS parameters + ``ETHTOOL_MSG_PLCA_GET_STATUS_REPLY`` PLCA RS status + ``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status ======================================== ================================= From 4f09947abf248c9aa3479c1335ea69851af4b5d6 Mon Sep 17 00:00:00 2001 From: Nithin Dabilpuram Date: Thu, 30 Nov 2023 11:37:03 +0530 Subject: [PATCH 2193/7721] octeontx2-af: debugfs: update CQ context fields This patch update the CQ structure fields to support the feature added in new silicons and also dump these fields in debugfs. Signed-off-by: Nithin Dabilpuram Signed-off-by: Geetha sowjanya Link: https://lore.kernel.org/r/20231130060703.16769-1-gakula@marvell.com Signed-off-by: Jakub Kicinski --- .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 17 +++++++++++++++++ .../ethernet/marvell/octeontx2/af/rvu_struct.h | 17 +++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 468b6561ed3f..e6d7914ce61c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -1825,6 +1825,8 @@ static void print_nix_rq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) { struct nix_cq_ctx_s *cq_ctx = &rsp->cq; + struct nix_hw *nix_hw = m->private; + struct rvu *rvu = nix_hw->rvu; seq_printf(m, "W0: base \t\t\t%llx\n\n", cq_ctx->base); @@ -1836,6 +1838,16 @@ static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) seq_printf(m, "W1: bpid \t\t\t%d\nW1: bp_ena \t\t\t%d\n\n", cq_ctx->bpid, cq_ctx->bp_ena); + if (!is_rvu_otx2(rvu)) { + seq_printf(m, "W1: lbpid_high \t\t\t0x%03x\n", cq_ctx->lbpid_high); + seq_printf(m, "W1: lbpid_med \t\t\t0x%03x\n", cq_ctx->lbpid_med); + seq_printf(m, "W1: lbpid_low \t\t\t0x%03x\n", cq_ctx->lbpid_low); + seq_printf(m, "(W1: lbpid) \t\t\t0x%03x\n", + cq_ctx->lbpid_high << 6 | cq_ctx->lbpid_med << 3 | + cq_ctx->lbpid_low); + seq_printf(m, "W1: lbp_ena \t\t\t\t%d\n\n", cq_ctx->lbp_ena); + } + seq_printf(m, "W2: update_time \t\t%d\nW2:avg_level \t\t\t%d\n", cq_ctx->update_time, cq_ctx->avg_level); seq_printf(m, "W2: head \t\t\t%d\nW2:tail \t\t\t%d\n\n", @@ -1847,6 +1859,11 @@ static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) cq_ctx->qsize, cq_ctx->caching); seq_printf(m, "W3: substream \t\t\t0x%03x\nW3: ena \t\t\t%d\n", cq_ctx->substream, cq_ctx->ena); + if (!is_rvu_otx2(rvu)) { + seq_printf(m, "W3: lbp_frac \t\t\t%d\n", cq_ctx->lbp_frac); + seq_printf(m, "W3: cpt_drop_err_en \t\t\t%d\n", + cq_ctx->cpt_drop_err_en); + } seq_printf(m, "W3: drop_ena \t\t\t%d\nW3: drop \t\t\t%d\n", cq_ctx->drop_ena, cq_ctx->drop); seq_printf(m, "W3: bp \t\t\t\t%d\n\n", cq_ctx->bp); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index edc9367b1b95..5ef406c7e8a4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -340,11 +340,12 @@ struct nix_aq_res_s { /* NIX Completion queue context structure */ struct nix_cq_ctx_s { u64 base; - u64 rsvd_64_67 : 4; + u64 lbp_ena : 1; + u64 lbpid_low : 3; u64 bp_ena : 1; - u64 rsvd_69_71 : 3; + u64 lbpid_med : 3; u64 bpid : 9; - u64 rsvd_81_83 : 3; + u64 lbpid_high : 3; u64 qint_idx : 7; u64 cq_err : 1; u64 cint_idx : 7; @@ -358,10 +359,14 @@ struct nix_cq_ctx_s { u64 drop : 8; u64 drop_ena : 1; u64 ena : 1; - u64 rsvd_210_211 : 2; - u64 substream : 20; + u64 cpt_drop_err_en : 1; + u64 rsvd_211 : 1; + u64 substream : 12; + u64 stash_thresh : 4; + u64 lbp_frac : 4; u64 caching : 1; - u64 rsvd_233_235 : 3; + u64 stashing : 1; + u64 rsvd_234_235 : 2; u64 qsize : 4; u64 cq_err_int : 8; u64 cq_err_int_ena : 8; From a10859384256cdfab37601239ec1640a982a67e2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 29 Nov 2023 18:22:58 +0100 Subject: [PATCH 2194/7721] dt-bindings: net: qcom,ipa: document SM8650 compatible Document the IPA on the SM8650 Platform which uses version 5.5.1, which is a minor revision of v5.5 found on SM8550, thus we can use the SM8550 bindings as fallback since it shares the same register mappings. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231129-topic-sm8650-upstream-bindings-ipa-v1-1-ca21eb2dfb14@linaro.org Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/qcom,ipa.yaml | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml index 702eadccdf99..c30218684cfe 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml @@ -43,16 +43,21 @@ description: properties: compatible: - enum: - - qcom,msm8998-ipa - - qcom,sc7180-ipa - - qcom,sc7280-ipa - - qcom,sdm845-ipa - - qcom,sdx55-ipa - - qcom,sdx65-ipa - - qcom,sm6350-ipa - - qcom,sm8350-ipa - - qcom,sm8550-ipa + oneOf: + - enum: + - qcom,msm8998-ipa + - qcom,sc7180-ipa + - qcom,sc7280-ipa + - qcom,sdm845-ipa + - qcom,sdx55-ipa + - qcom,sdx65-ipa + - qcom,sm6350-ipa + - qcom,sm8350-ipa + - qcom,sm8550-ipa + - items: + - enum: + - qcom,sm8650-ipa + - const: qcom,sm8550-ipa reg: items: From 078e07570359b77655d7e54a05153873f1d20648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 29 Nov 2023 12:11:42 +0100 Subject: [PATCH 2195/7721] net: ethernet: renesas: rcar_gen4_ptp: Depend on PTP_1588_CLOCK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When breaking out the Gen4 gPTP support to its own module the dependency on the PTP_1588_CLOCK framework was left as optional and only stated for the driver using the module. This leads to issues when doing COMPILE_TEST of RENESAS_GEN4_PTP separately and PTP_1588_CLOCK is built as a module and the other as a built-in. Add an explicit depend on PTP_1588_CLOCK. While at it remove the optional support for PTP_1588_CLOCK from RENESAS_ETHER_SWITCH as the driver unconditionally calls the Gen4 gPTP module and thus also requires the PTP_1588_CLOCK framework. Reported-by: Arnd Bergmann Fixes: 8c1c66235e03 ("net: ethernet: renesas: rcar_gen4_ptp: Break out to module") Signed-off-by: Niklas Söderlund Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231129111142.3322667-1-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig index 733cbb6eb3ed..d6136fe5c206 100644 --- a/drivers/net/ethernet/renesas/Kconfig +++ b/drivers/net/ethernet/renesas/Kconfig @@ -40,7 +40,7 @@ config RAVB config RENESAS_ETHER_SWITCH tristate "Renesas Ethernet Switch support" depends on ARCH_RENESAS || COMPILE_TEST - depends on PTP_1588_CLOCK_OPTIONAL + depends on PTP_1588_CLOCK select CRC32 select MII select PHYLINK @@ -50,6 +50,7 @@ config RENESAS_ETHER_SWITCH config RENESAS_GEN4_PTP tristate "Renesas R-Car Gen4 gPTP support" if COMPILE_TEST + depends on PTP_1588_CLOCK select CRC32 select MII select PHYLIB From 7453d7a633d020d2481cfedbcfcab6dab89ee194 Mon Sep 17 00:00:00 2001 From: Yinjun Zhang Date: Wed, 29 Nov 2023 10:04:13 +0200 Subject: [PATCH 2196/7721] nfp: ethtool: expose transmit SO_TIMESTAMPING capability NFP always supports software time stamping of tx, now expose the capability through ethtool ops. Signed-off-by: Yinjun Zhang Signed-off-by: Louis Peens Link: https://lore.kernel.org/r/20231129080413.83789-1-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 776bee2efd35..200b3588363c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -2502,6 +2502,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .set_pauseparam = nfp_port_set_pauseparam, .get_pauseparam = nfp_port_get_pauseparam, .set_phys_id = nfp_net_set_phys_id, + .get_ts_info = ethtool_op_get_ts_info, }; const struct ethtool_ops nfp_port_ethtool_ops = { From 5d86c15c3171c3ecebd84d53e30d9812b5591c84 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 13:51:42 +0100 Subject: [PATCH 2197/7721] dt-bindings: gpu: mali-utgard: Add Rockchip RK3128 compatible Rockchip RK312x SoC family has a Mali400 MP2. Add a compatible for it. Signed-off-by: Alex Bee Acked-by: Krzysztof Kozlowski Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231202125144.66052-4-knaerzche@gmail.com --- Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml index 0fae1ef013be..abd4aa335fbc 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml @@ -29,6 +29,7 @@ properties: - allwinner,sun50i-a64-mali - rockchip,rk3036-mali - rockchip,rk3066-mali + - rockchip,rk3128-mali - rockchip,rk3188-mali - rockchip,rk3228-mali - samsung,exynos4210-mali From 3d880c31d40d30328cb550523adadf1466e7c686 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 13:41:58 +0100 Subject: [PATCH 2198/7721] ARM: dts: rockchip: Add gmac node for RK3128 RK3128's gmac is based on Synopsys Ethernet GMAC IP core. Add it to the devicetree. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231202124158.65615-3-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 4e8b38604ecd..c0c9f0eaffa3 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -525,6 +525,34 @@ pdma: dma-controller@20078000 { #dma-cells = <1>; }; + gmac: ethernet@2008c000 { + compatible = "rockchip,rk3128-gmac"; + reg = <0x2008c000 0x4000>; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + clocks = <&cru SCLK_MAC>, + <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>, + <&cru SCLK_MAC_REF>, <&cru SCLK_MAC_REFOUT>, + <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; + clock-names = "stmmaceth", + "mac_clk_rx", "mac_clk_tx", + "clk_mac_ref", "clk_mac_refout", + "aclk_mac", "pclk_mac"; + resets = <&cru SRST_GMAC>; + reset-names = "stmmaceth"; + rockchip,grf = <&grf>; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; + status = "disabled"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + }; + pinctrl: pinctrl { compatible = "rockchip,rk3128-pinctrl"; rockchip,grf = <&grf>; From b47c0b9ed3eb31c8efb8f8be3bca32d6ced5fd52 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 13:41:59 +0100 Subject: [PATCH 2199/7721] ARM: dts: rockchip: Enable gmac for XPI-3128 Add the required properties and enable the gmac node for XPI-3128 board. The minimum reset timing requirements for the phy have been taken from DP83848J's datasheet [0] [0] https://www.ti.com/lit/ds/symlink/dp83848j.pdf Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231202124158.65615-4-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- .../arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index 61b9f069c8a2..e979425f11a0 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -11,6 +11,7 @@ / { compatible = "geniatech,xpi-3128", "rockchip,rk3128"; aliases { + ethernet0 = &gmac; gpio0 = &gpio0; gpio1 = &gpio1; gpio2 = &gpio2; @@ -255,6 +256,18 @@ &emmc { status = "okay"; }; +&gmac { + clock_in_out = "output"; + phy-supply = <&vcc_lan>; + phy-mode = "rmii"; + phy-handle = <&phy0>; + assigned-clocks = <&cru SCLK_MAC_SRC>; + assigned-clock-rates= <50000000>; + pinctrl-names = "default"; + pinctrl-0 = <&rmii_pins>; + status = "okay"; +}; + &gpio0 { gpio-line-names = /* GPIO0 A0-A7 */ "", "", "HEADER_5", "HEADER_3", @@ -315,6 +328,21 @@ &gpio3 { "", "", "", ""; }; +&mdio { + phy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + max-speed = <100>; + /* T2.2.4 min. 1 us */ + reset-assert-us = <10>; + /* T2.2.1 + T2.2.2 + T2.2.3 min. 6.05 us */ + reset-deassert-us = <20>; + reset-gpios = <&gpio2 RK_PD0 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&dp83848c_rst>; + }; +}; + &pinctrl { dp83848c { dp83848c_rst: dp83848c-rst { From 45b5623f2d721c25d1a2fdc8c4600fb4b7b61c75 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:56:55 -0800 Subject: [PATCH 2200/7721] bpf: rearrange bpf_func_state fields to save a bit of memory It's a trivial rearrangement saving 8 bytes. We have 4 bytes of padding at the end which can be filled with another field without increasing struct bpf_func_state. copy_func_state() logic remains correct without any further changes. BEFORE ====== struct bpf_func_state { struct bpf_reg_state regs[11]; /* 0 1320 */ /* --- cacheline 20 boundary (1280 bytes) was 40 bytes ago --- */ int callsite; /* 1320 4 */ u32 frameno; /* 1324 4 */ u32 subprogno; /* 1328 4 */ u32 async_entry_cnt; /* 1332 4 */ bool in_callback_fn; /* 1336 1 */ /* XXX 7 bytes hole, try to pack */ /* --- cacheline 21 boundary (1344 bytes) --- */ struct tnum callback_ret_range; /* 1344 16 */ bool in_async_callback_fn; /* 1360 1 */ bool in_exception_callback_fn; /* 1361 1 */ /* XXX 2 bytes hole, try to pack */ int acquired_refs; /* 1364 4 */ struct bpf_reference_state * refs; /* 1368 8 */ int allocated_stack; /* 1376 4 */ /* XXX 4 bytes hole, try to pack */ struct bpf_stack_state * stack; /* 1384 8 */ /* size: 1392, cachelines: 22, members: 13 */ /* sum members: 1379, holes: 3, sum holes: 13 */ /* last cacheline: 48 bytes */ }; AFTER ===== struct bpf_func_state { struct bpf_reg_state regs[11]; /* 0 1320 */ /* --- cacheline 20 boundary (1280 bytes) was 40 bytes ago --- */ int callsite; /* 1320 4 */ u32 frameno; /* 1324 4 */ u32 subprogno; /* 1328 4 */ u32 async_entry_cnt; /* 1332 4 */ struct tnum callback_ret_range; /* 1336 16 */ /* --- cacheline 21 boundary (1344 bytes) was 8 bytes ago --- */ bool in_callback_fn; /* 1352 1 */ bool in_async_callback_fn; /* 1353 1 */ bool in_exception_callback_fn; /* 1354 1 */ /* XXX 1 byte hole, try to pack */ int acquired_refs; /* 1356 4 */ struct bpf_reference_state * refs; /* 1360 8 */ struct bpf_stack_state * stack; /* 1368 8 */ int allocated_stack; /* 1376 4 */ /* size: 1384, cachelines: 22, members: 13 */ /* sum members: 1379, holes: 1, sum holes: 1 */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index d99a636d36a7..0c0e1bccad45 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -297,8 +297,8 @@ struct bpf_func_state { * void foo(void) { bpf_timer_set_callback(,foo); } */ u32 async_entry_cnt; - bool in_callback_fn; struct tnum callback_ret_range; + bool in_callback_fn; bool in_async_callback_fn; bool in_exception_callback_fn; /* For callback calling functions that limit number of possible @@ -316,8 +316,8 @@ struct bpf_func_state { /* The following fields should be last. See copy_func_state() */ int acquired_refs; struct bpf_reference_state *refs; - int allocated_stack; struct bpf_stack_state *stack; + int allocated_stack; }; struct bpf_idx_pair { From 5fad52bee30414270104525e3a0266327a6e9d11 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:56:56 -0800 Subject: [PATCH 2201/7721] bpf: provide correct register name for exception callback retval check bpf_throw() is checking R1, so let's report R1 in the log. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 12 ++++++------ .../testing/selftests/bpf/progs/exceptions_assert.c | 2 +- tools/testing/selftests/bpf/progs/exceptions_fail.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8e7b6072e3f4..25b9d470957e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -11805,7 +11805,7 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env, return 0; } -static int check_return_code(struct bpf_verifier_env *env, int regno); +static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name); static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx_p) @@ -11942,7 +11942,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, * to bpf_throw becomes the return value of the program. */ if (!env->exception_callback_subprog) { - err = check_return_code(env, BPF_REG_1); + err = check_return_code(env, BPF_REG_1, "R1"); if (err < 0) return err; } @@ -14972,7 +14972,7 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) return 0; } -static int check_return_code(struct bpf_verifier_env *env, int regno) +static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name) { struct tnum enforce_attach_type_range = tnum_unknown; const struct bpf_prog *prog = env->prog; @@ -15026,7 +15026,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno) } if (!tnum_in(const_0, reg->var_off)) { - verbose_invalid_scalar(env, reg, &const_0, "async callback", "R0"); + verbose_invalid_scalar(env, reg, &const_0, "async callback", reg_name); return -EINVAL; } return 0; @@ -15126,7 +15126,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno) } if (!tnum_in(range, reg->var_off)) { - verbose_invalid_scalar(env, reg, &range, "program exit", "R0"); + verbose_invalid_scalar(env, reg, &range, "program exit", reg_name); if (prog->expected_attach_type == BPF_LSM_CGROUP && prog_type == BPF_PROG_TYPE_LSM && !prog->aux->attach_func_proto->type) @@ -17410,7 +17410,7 @@ static int do_check(struct bpf_verifier_env *env) continue; } - err = check_return_code(env, BPF_REG_0); + err = check_return_code(env, BPF_REG_0, "R0"); if (err) return err; process_bpf_exit: diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c index 49efaed143fc..575e7dd719c4 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_assert.c +++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c @@ -125,7 +125,7 @@ int check_assert_generic(struct __sk_buff *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R0 has value (0x40; 0x0)") +__failure __msg("At program exit the register R1 has value (0x40; 0x0)") int check_assert_with_return(void *ctx) { bpf_assert_with(!ctx, 64); diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c index 8c0ef2742208..81ead7512ba2 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_fail.c +++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c @@ -308,7 +308,7 @@ int reject_set_exception_cb_bad_ret1(void *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R0 has value (0x40; 0x0) should") +__failure __msg("At program exit the register R1 has value (0x40; 0x0) should") int reject_set_exception_cb_bad_ret2(void *ctx) { bpf_throw(64); From 0acd03a5bd188b0c501d285d938439618bd855c4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:56:57 -0800 Subject: [PATCH 2202/7721] bpf: enforce precision of R0 on callback return Given verifier checks actual value, r0 has to be precise, so we need to propagate precision properly. r0 also has to be marked as read, otherwise subsequent state comparisons will ignore such register as unimportant and precision won't really help here. Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper") Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 25b9d470957e..849fbf47b5f3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9590,6 +9590,13 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) verbose(env, "R0 not a scalar value\n"); return -EACCES; } + + /* we are going to rely on register's precise value */ + err = mark_reg_read(env, r0, r0->parent, REG_LIVE_READ64); + err = err ?: mark_chain_precision(env, BPF_REG_0); + if (err) + return err; + if (!tnum_in(range, r0->var_off)) { verbose_invalid_scalar(env, r0, &range, "callback return", "R0"); return -EINVAL; From 8fa4ecd49b81ccd9d1d87f1c8b2260e218644878 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:56:58 -0800 Subject: [PATCH 2203/7721] bpf: enforce exact retval range on subprog/callback exit Instead of relying on potentially imprecise tnum representation of expected return value range for callbacks and subprogs, validate that smin/smax range satisfy exact expected range of return values. E.g., if callback would need to return [0, 2] range, tnum can't represent this precisely and instead will allow [0, 3] range. By checking smin/smax range, we can make sure that subprog/callback indeed returns only valid [0, 2] range. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 7 ++++++- kernel/bpf/verifier.c | 33 ++++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 0c0e1bccad45..3378cc753061 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -275,6 +275,11 @@ struct bpf_reference_state { int callback_ref; }; +struct bpf_retval_range { + s32 minval; + s32 maxval; +}; + /* state of the program: * type of all registers and stack info */ @@ -297,7 +302,7 @@ struct bpf_func_state { * void foo(void) { bpf_timer_set_callback(,foo); } */ u32 async_entry_cnt; - struct tnum callback_ret_range; + struct bpf_retval_range callback_ret_range; bool in_callback_fn; bool in_async_callback_fn; bool in_exception_callback_fn; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 849fbf47b5f3..f3d9d7de68da 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2305,6 +2305,11 @@ static void init_reg_state(struct bpf_verifier_env *env, regs[BPF_REG_FP].frameno = state->frameno; } +static struct bpf_retval_range retval_range(s32 minval, s32 maxval) +{ + return (struct bpf_retval_range){ minval, maxval }; +} + #define BPF_MAIN_FUNC (-1) static void init_func_state(struct bpf_verifier_env *env, struct bpf_func_state *state, @@ -2313,7 +2318,7 @@ static void init_func_state(struct bpf_verifier_env *env, state->callsite = callsite; state->frameno = frameno; state->subprogno = subprogno; - state->callback_ret_range = tnum_range(0, 0); + state->callback_ret_range = retval_range(0, 0); init_reg_state(env, state); mark_verifier_state_scratched(env); } @@ -9396,7 +9401,7 @@ static int set_map_elem_callback_state(struct bpf_verifier_env *env, return err; callee->in_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9418,7 +9423,7 @@ static int set_loop_callback_state(struct bpf_verifier_env *env, __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); callee->in_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9448,7 +9453,7 @@ static int set_timer_callback_state(struct bpf_verifier_env *env, __mark_reg_not_init(env, &callee->regs[BPF_REG_4]); __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); callee->in_async_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9476,7 +9481,7 @@ static int set_find_vma_callback_state(struct bpf_verifier_env *env, __mark_reg_not_init(env, &callee->regs[BPF_REG_4]); __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); callee->in_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9499,7 +9504,7 @@ static int set_user_ringbuf_callback_state(struct bpf_verifier_env *env, __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); callee->in_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9531,7 +9536,7 @@ static int set_rbtree_add_callback_state(struct bpf_verifier_env *env, __mark_reg_not_init(env, &callee->regs[BPF_REG_4]); __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); callee->in_callback_fn = true; - callee->callback_ret_range = tnum_range(0, 1); + callee->callback_ret_range = retval_range(0, 1); return 0; } @@ -9560,6 +9565,11 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env) return is_rbtree_lock_required_kfunc(kfunc_btf_id); } +static bool retval_range_within(struct bpf_retval_range range, const struct bpf_reg_state *reg) +{ + return range.minval <= reg->smin_value && reg->smax_value <= range.maxval; +} + static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) { struct bpf_verifier_state *state = env->cur_state, *prev_st; @@ -9583,9 +9593,6 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) caller = state->frame[state->curframe - 1]; if (callee->in_callback_fn) { - /* enforce R0 return value range [0, 1]. */ - struct tnum range = callee->callback_ret_range; - if (r0->type != SCALAR_VALUE) { verbose(env, "R0 not a scalar value\n"); return -EACCES; @@ -9597,7 +9604,11 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) if (err) return err; - if (!tnum_in(range, r0->var_off)) { + /* enforce R0 return value range */ + if (!retval_range_within(callee->callback_ret_range, r0)) { + struct tnum range = tnum_range(callee->callback_ret_range.minval, + callee->callback_ret_range.maxval); + verbose_invalid_scalar(env, r0, &range, "callback return", "R0"); return -EINVAL; } From 60a6b2c78c62d0a99ccb7ad5edc950f79e56306a Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:56:59 -0800 Subject: [PATCH 2204/7721] selftests/bpf: add selftest validating callback result is enforced BPF verifier expects callback subprogs to return values from specified range (typically [0, 1]). This requires that r0 at exit is both precise (because we rely on specific value range) and is marked as read (otherwise state comparison will ignore such register as unimportant). Add a simple test that validates that all these conditions are enforced. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/progs/verifier_subprog_precision.c | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index b5efcaeaa1ae..d41d2a8bb97e 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -117,6 +117,56 @@ __naked int global_subprog_result_precise(void) ); } +__naked __noinline __used +static unsigned long loop_callback_bad() +{ + /* bpf_loop() callback that can return values outside of [0, 1] range */ + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 0;" + "1:" + "goto +0;" /* checkpoint */ + /* bpf_loop() expects [0, 1] values, so branch above skipping + * r0 = 0; should lead to a failure, but if exit instruction + * doesn't enforce r0's precision, this callback will be + * successfully verified + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); +} + +SEC("?raw_tp") +__failure __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame1: regs=r0 stack= before 11: (b7) r0 = 0") +/* check that we have branch code path doing its own validation */ +__msg("from 10 to 12: frame1: R0=scalar(smin=umin=1001") +/* check that branch code path marks r0 as precise, before failing */ +__msg("mark_precise: frame1: regs=r0 stack= before 9: (85) call bpf_get_prandom_u32#7") +__msg("At callback return the register R0 has value (0x0; 0x7fffffffffffffff) should have been in (0x0; 0x1)") +__naked int callback_precise_return_fail(void) +{ + asm volatile ( + "r1 = 1;" /* nr_loops */ + "r2 = %[loop_callback_bad];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r0 = 0;" + "exit;" + : + : __imm_ptr(loop_callback_bad), + __imm(bpf_loop) + : __clobber_common + ); +} + SEC("?raw_tp") __success __log_level(2) /* First simulated path does not include callback body, From c871d0e00f0e8c207ce8ff89025e35cc49a8a3c3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:00 -0800 Subject: [PATCH 2205/7721] bpf: enforce precise retval range on program exit Similarly to subprog/callback logic, enforce return value of BPF program using more precise smin/smax range. We need to adjust a bunch of tests due to a changed format of an error message. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 56 ++++++++++--------- .../selftests/bpf/progs/exceptions_assert.c | 2 +- .../selftests/bpf/progs/exceptions_fail.c | 2 +- .../selftests/bpf/progs/test_global_func15.c | 2 +- .../selftests/bpf/progs/timer_failure.c | 2 +- .../selftests/bpf/progs/user_ringbuf_fail.c | 2 +- .../bpf/progs/verifier_cgroup_inv_retcode.c | 8 +-- .../bpf/progs/verifier_netfilter_retcode.c | 2 +- .../bpf/progs/verifier_subprog_precision.c | 2 +- 9 files changed, 40 insertions(+), 38 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f3d9d7de68da..9411c1046268 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -362,20 +362,23 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) static void verbose_invalid_scalar(struct bpf_verifier_env *env, struct bpf_reg_state *reg, - struct tnum *range, const char *ctx, + struct bpf_retval_range range, const char *ctx, const char *reg_name) { - char tn_buf[48]; + bool unknown = true; - verbose(env, "At %s the register %s ", ctx, reg_name); - if (!tnum_is_unknown(reg->var_off)) { - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose(env, "has value %s", tn_buf); - } else { - verbose(env, "has unknown scalar value"); + verbose(env, "At %s the register %s has", ctx, reg_name); + if (reg->smin_value > S64_MIN) { + verbose(env, " smin=%lld", reg->smin_value); + unknown = false; } - tnum_strn(tn_buf, sizeof(tn_buf), *range); - verbose(env, " should have been in %s\n", tn_buf); + if (reg->smax_value < S64_MAX) { + verbose(env, " smax=%lld", reg->smax_value); + unknown = false; + } + if (unknown) + verbose(env, " unknown scalar value"); + verbose(env, " should have been in [%d, %d]\n", range.minval, range.maxval); } static bool type_may_be_null(u32 type) @@ -9606,10 +9609,8 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) /* enforce R0 return value range */ if (!retval_range_within(callee->callback_ret_range, r0)) { - struct tnum range = tnum_range(callee->callback_ret_range.minval, - callee->callback_ret_range.maxval); - - verbose_invalid_scalar(env, r0, &range, "callback return", "R0"); + verbose_invalid_scalar(env, r0, callee->callback_ret_range, + "callback return", "R0"); return -EINVAL; } if (!calls_callback(env, callee->callsite)) { @@ -14995,7 +14996,8 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char struct tnum enforce_attach_type_range = tnum_unknown; const struct bpf_prog *prog = env->prog; struct bpf_reg_state *reg; - struct tnum range = tnum_range(0, 1), const_0 = tnum_const(0); + struct bpf_retval_range range = retval_range(0, 1); + struct bpf_retval_range const_0 = retval_range(0, 0); enum bpf_prog_type prog_type = resolve_prog_type(env->prog); int err; struct bpf_func_state *frame = env->cur_state->frame[0]; @@ -15043,8 +15045,8 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char return -EINVAL; } - if (!tnum_in(const_0, reg->var_off)) { - verbose_invalid_scalar(env, reg, &const_0, "async callback", reg_name); + if (!retval_range_within(const_0, reg)) { + verbose_invalid_scalar(env, reg, const_0, "async callback", reg_name); return -EINVAL; } return 0; @@ -15070,14 +15072,14 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char env->prog->expected_attach_type == BPF_CGROUP_INET4_GETSOCKNAME || env->prog->expected_attach_type == BPF_CGROUP_INET6_GETSOCKNAME || env->prog->expected_attach_type == BPF_CGROUP_UNIX_GETSOCKNAME) - range = tnum_range(1, 1); + range = retval_range(1, 1); if (env->prog->expected_attach_type == BPF_CGROUP_INET4_BIND || env->prog->expected_attach_type == BPF_CGROUP_INET6_BIND) - range = tnum_range(0, 3); + range = retval_range(0, 3); break; case BPF_PROG_TYPE_CGROUP_SKB: if (env->prog->expected_attach_type == BPF_CGROUP_INET_EGRESS) { - range = tnum_range(0, 3); + range = retval_range(0, 3); enforce_attach_type_range = tnum_range(2, 3); } break; @@ -15090,13 +15092,13 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char case BPF_PROG_TYPE_RAW_TRACEPOINT: if (!env->prog->aux->attach_btf_id) return 0; - range = tnum_const(0); + range = retval_range(0, 0); break; case BPF_PROG_TYPE_TRACING: switch (env->prog->expected_attach_type) { case BPF_TRACE_FENTRY: case BPF_TRACE_FEXIT: - range = tnum_const(0); + range = retval_range(0, 0); break; case BPF_TRACE_RAW_TP: case BPF_MODIFY_RETURN: @@ -15108,7 +15110,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char } break; case BPF_PROG_TYPE_SK_LOOKUP: - range = tnum_range(SK_DROP, SK_PASS); + range = retval_range(SK_DROP, SK_PASS); break; case BPF_PROG_TYPE_LSM: @@ -15122,12 +15124,12 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char /* Make sure programs that attach to void * hooks don't try to modify return value. */ - range = tnum_range(1, 1); + range = retval_range(1, 1); } break; case BPF_PROG_TYPE_NETFILTER: - range = tnum_range(NF_DROP, NF_ACCEPT); + range = retval_range(NF_DROP, NF_ACCEPT); break; case BPF_PROG_TYPE_EXT: /* freplace program can return anything as its return value @@ -15143,8 +15145,8 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char return -EINVAL; } - if (!tnum_in(range, reg->var_off)) { - verbose_invalid_scalar(env, reg, &range, "program exit", reg_name); + if (!retval_range_within(range, reg)) { + verbose_invalid_scalar(env, reg, range, "program exit", reg_name); if (prog->expected_attach_type == BPF_LSM_CGROUP && prog_type == BPF_PROG_TYPE_LSM && !prog->aux->attach_func_proto->type) diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c index 575e7dd719c4..0ef81040da59 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_assert.c +++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c @@ -125,7 +125,7 @@ int check_assert_generic(struct __sk_buff *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R1 has value (0x40; 0x0)") +__failure __msg("At program exit the register R1 has smin=64 smax=64") int check_assert_with_return(void *ctx) { bpf_assert_with(!ctx, 64); diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c index 81ead7512ba2..9cceb6521143 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_fail.c +++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c @@ -308,7 +308,7 @@ int reject_set_exception_cb_bad_ret1(void *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R1 has value (0x40; 0x0) should") +__failure __msg("At program exit the register R1 has smin=64 smax=64 should") int reject_set_exception_cb_bad_ret2(void *ctx) { bpf_throw(64); diff --git a/tools/testing/selftests/bpf/progs/test_global_func15.c b/tools/testing/selftests/bpf/progs/test_global_func15.c index b512d6a6c75e..f80207480e8a 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func15.c +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c @@ -13,7 +13,7 @@ __noinline int foo(unsigned int *v) } SEC("cgroup_skb/ingress") -__failure __msg("At program exit the register R0 has value") +__failure __msg("At program exit the register R0 has ") int global_func15(struct __sk_buff *skb) { unsigned int v = 1; diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c index 226d33b5a05c..9000da1e2120 100644 --- a/tools/testing/selftests/bpf/progs/timer_failure.c +++ b/tools/testing/selftests/bpf/progs/timer_failure.c @@ -30,7 +30,7 @@ static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer) } SEC("fentry/bpf_fentry_test1") -__failure __msg("should have been in (0x0; 0x0)") +__failure __msg("should have been in [0, 0]") int BPF_PROG2(test_ret_1, int, a) { int key = 0; diff --git a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c index 03ee946c6bf7..11ab25c42c36 100644 --- a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c +++ b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c @@ -184,7 +184,7 @@ invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context) * not be able to write to that pointer. */ SEC("?raw_tp") -__failure __msg("At callback return the register R0 has value") +__failure __msg("At callback return the register R0 has ") int user_ringbuf_callback_invalid_return(void *ctx) { bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0); diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c index d6c4a7f3f790..6e0f349f8f15 100644 --- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c +++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c @@ -7,7 +7,7 @@ SEC("cgroup/sock") __description("bpf_exit with invalid return code. test1") -__failure __msg("R0 has value (0x0; 0xffffffff)") +__failure __msg("smin=0 smax=4294967295 should have been in [0, 1]") __naked void with_invalid_return_code_test1(void) { asm volatile (" \ @@ -30,7 +30,7 @@ __naked void with_invalid_return_code_test2(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test3") -__failure __msg("R0 has value (0x0; 0x3)") +__failure __msg("smin=0 smax=3 should have been in [0, 1]") __naked void with_invalid_return_code_test3(void) { asm volatile (" \ @@ -53,7 +53,7 @@ __naked void with_invalid_return_code_test4(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test5") -__failure __msg("R0 has value (0x2; 0x0)") +__failure __msg("smin=2 smax=2 should have been in [0, 1]") __naked void with_invalid_return_code_test5(void) { asm volatile (" \ @@ -75,7 +75,7 @@ __naked void with_invalid_return_code_test6(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test7") -__failure __msg("R0 has unknown scalar value") +__failure __msg("R0 has unknown scalar value should have been in [0, 1]") __naked void with_invalid_return_code_test7(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c index 353ae6da00e1..e1ffa5d32ff0 100644 --- a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c +++ b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c @@ -39,7 +39,7 @@ __naked void with_valid_return_code_test3(void) SEC("netfilter") __description("bpf_exit with invalid return code. test4") -__failure __msg("R0 has value (0x2; 0x0)") +__failure __msg("R0 has smin=2 smax=2 should have been in [0, 1]") __naked void with_invalid_return_code_test4(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index d41d2a8bb97e..0dfe3f8b69ac 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -148,7 +148,7 @@ __msg("mark_precise: frame1: regs=r0 stack= before 11: (b7) r0 = 0") __msg("from 10 to 12: frame1: R0=scalar(smin=umin=1001") /* check that branch code path marks r0 as precise, before failing */ __msg("mark_precise: frame1: regs=r0 stack= before 9: (85) call bpf_get_prandom_u32#7") -__msg("At callback return the register R0 has value (0x0; 0x7fffffffffffffff) should have been in (0x0; 0x1)") +__msg("At callback return the register R0 has smin=1001 should have been in [0, 1]") __naked int callback_precise_return_fail(void) { asm volatile ( From 0ef24c8dfae24a4b8aa2e92eac20faecdc5502e5 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:01 -0800 Subject: [PATCH 2206/7721] bpf: unify async callback and program retval checks Use common logic to verify program return values and async callback return values. This allows to avoid duplication of any extra steps necessary, like precision marking, which will be added in the next patch. Acked-by: Eduard Zingerman Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9411c1046268..c54944af1bcc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -367,7 +367,7 @@ static void verbose_invalid_scalar(struct bpf_verifier_env *env, { bool unknown = true; - verbose(env, "At %s the register %s has", ctx, reg_name); + verbose(env, "%s the register %s has", ctx, reg_name); if (reg->smin_value > S64_MIN) { verbose(env, " smin=%lld", reg->smin_value); unknown = false; @@ -9610,7 +9610,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) /* enforce R0 return value range */ if (!retval_range_within(callee->callback_ret_range, r0)) { verbose_invalid_scalar(env, r0, callee->callback_ret_range, - "callback return", "R0"); + "At callback return", "R0"); return -EINVAL; } if (!calls_callback(env, callee->callsite)) { @@ -14993,11 +14993,11 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name) { + const char *exit_ctx = "At program exit"; struct tnum enforce_attach_type_range = tnum_unknown; const struct bpf_prog *prog = env->prog; struct bpf_reg_state *reg; struct bpf_retval_range range = retval_range(0, 1); - struct bpf_retval_range const_0 = retval_range(0, 0); enum bpf_prog_type prog_type = resolve_prog_type(env->prog); int err; struct bpf_func_state *frame = env->cur_state->frame[0]; @@ -15039,17 +15039,9 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char if (frame->in_async_callback_fn) { /* enforce return zero from async callbacks like timer */ - if (reg->type != SCALAR_VALUE) { - verbose(env, "In async callback the register R%d is not a known value (%s)\n", - regno, reg_type_str(env, reg->type)); - return -EINVAL; - } - - if (!retval_range_within(const_0, reg)) { - verbose_invalid_scalar(env, reg, const_0, "async callback", reg_name); - return -EINVAL; - } - return 0; + exit_ctx = "At async callback return"; + range = retval_range(0, 0); + goto enforce_retval; } if (is_subprog && !frame->in_exception_callback_fn) { @@ -15139,15 +15131,17 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char return 0; } +enforce_retval: if (reg->type != SCALAR_VALUE) { - verbose(env, "At program exit the register R%d is not a known value (%s)\n", - regno, reg_type_str(env, reg->type)); + verbose(env, "%s the register R%d is not a known value (%s)\n", + exit_ctx, regno, reg_type_str(env, reg->type)); return -EINVAL; } if (!retval_range_within(range, reg)) { - verbose_invalid_scalar(env, reg, range, "program exit", reg_name); - if (prog->expected_attach_type == BPF_LSM_CGROUP && + verbose_invalid_scalar(env, reg, range, exit_ctx, reg_name); + if (!is_subprog && + prog->expected_attach_type == BPF_LSM_CGROUP && prog_type == BPF_PROG_TYPE_LSM && !prog->aux->attach_func_proto->type) verbose(env, "Note, BPF_LSM_CGROUP that attach to void LSM hooks can't modify return value!\n"); From eabe518de533a4291996020977054a7a7b78c7d3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:02 -0800 Subject: [PATCH 2207/7721] bpf: enforce precision of R0 on program/async callback return Given we enforce a valid range for program and async callback return value, we must mark R0 as precise to avoid incorrect state pruning. Fixes: b5dc0163d8fd ("bpf: precise scalar_value tracking") Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c54944af1bcc..2cd150d6d141 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -15138,6 +15138,10 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char return -EINVAL; } + err = mark_chain_precision(env, regno); + if (err) + return err; + if (!retval_range_within(range, reg)) { verbose_invalid_scalar(env, reg, range, exit_ctx, reg_name); if (!is_subprog && From e02dea158ddaebe6e725be715e0009923b96ec8e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:03 -0800 Subject: [PATCH 2208/7721] selftests/bpf: validate async callback return value check correctness Adjust timer/timer_ret_1 test to validate more carefully verifier logic of enforcing async callback return value. This test will pass only if return result is marked precise and read. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/timer_failure.c | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c index 9000da1e2120..9fbc69c77bbb 100644 --- a/tools/testing/selftests/bpf/progs/timer_failure.c +++ b/tools/testing/selftests/bpf/progs/timer_failure.c @@ -21,17 +21,37 @@ struct { __type(value, struct elem); } timer_map SEC(".maps"); -static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer) +__naked __noinline __used +static unsigned long timer_cb_ret_bad() { - if (bpf_get_smp_processor_id() % 2) - return 1; - else - return 0; + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 0;" + "1:" + "goto +0;" /* checkpoint */ + /* async callback is expected to return 0, so branch above + * skipping r0 = 0; should lead to a failure, but if exit + * instruction doesn't enforce r0's precision, this callback + * will be successfully verified + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); } SEC("fentry/bpf_fentry_test1") -__failure __msg("should have been in [0, 0]") -int BPF_PROG2(test_ret_1, int, a) +__log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__failure +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 22: (b7) r0 = 0") +/* check that branch code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 24: (85) call bpf_get_prandom_u32#7") +__msg("should have been in [0, 0]") +long BPF_PROG2(test_bad_ret, int, a) { int key = 0; struct bpf_timer *timer; @@ -39,7 +59,7 @@ int BPF_PROG2(test_ret_1, int, a) timer = bpf_map_lookup_elem(&timer_map, &key); if (timer) { bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME); - bpf_timer_set_callback(timer, timer_cb_ret1); + bpf_timer_set_callback(timer, timer_cb_ret_bad); bpf_timer_start(timer, 1000, 0); } From 5c19e1d05e9e71b42d8e779f41959254239709da Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:04 -0800 Subject: [PATCH 2209/7721] selftests/bpf: adjust global_func15 test to validate prog exit precision Add one more subtest to global_func15 selftest to validate that verifier properly marks r0 as precise and avoids erroneous state pruning of the branch that has return value outside of expected [0, 1] value. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-11-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/test_global_func15.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/test_global_func15.c b/tools/testing/selftests/bpf/progs/test_global_func15.c index f80207480e8a..b4e089d6981d 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func15.c +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c @@ -22,3 +22,35 @@ int global_func15(struct __sk_buff *skb) return v; } + +SEC("cgroup_skb/ingress") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__failure +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 2: (b7) r0 = 1") +/* check that branch code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 0: (85) call bpf_get_prandom_u32#7") +__msg("At program exit the register R0 has ") +__naked int global_func15_tricky_pruning(void) +{ + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 1;" + "1:" + "goto +0;" /* checkpoint */ + /* cgroup_skb/ingress program is expected to return [0, 1] + * values, so branch above makes sure that in a fallthrough + * case we have a valid 1 stored in R0 register, but in + * a branch case we assign some random value to R0. So if + * there is something wrong with precision tracking for R0 at + * program exit, we might erronenously prune branch case, + * because R0 in fallthrough case is imprecise (and thus any + * value is valid from POV of verifier is_state_equal() logic) + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); +} From 81eff2e36481c5cf4a2ac906ae56c3fbd3e6f305 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sat, 2 Dec 2023 09:57:05 -0800 Subject: [PATCH 2210/7721] bpf: simplify tnum output if a fully known constant Emit tnum representation as just a constant if all bits are known. Use decimal-vs-hex logic to determine exact format of emitted constant value, just like it's done for register range values. For that move tnum_strn() to kernel/bpf/log.c to reuse decimal-vs-hex determination logic and constants. Acked-by: Shung-Hsi Yu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231202175705.885270-12-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 13 +++++++++++++ kernel/bpf/tnum.c | 6 ------ .../bpf/progs/verifier_direct_packet_access.c | 2 +- .../testing/selftests/bpf/progs/verifier_int_ptr.c | 2 +- .../selftests/bpf/progs/verifier_stack_ptr.c | 4 ++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 3505f3e5ae96..55d019f30e91 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -539,6 +539,19 @@ static void verbose_snum(struct bpf_verifier_env *env, s64 num) verbose(env, "%#llx", num); } +int tnum_strn(char *str, size_t size, struct tnum a) +{ + /* print as a constant, if tnum is fully known */ + if (a.mask == 0) { + if (is_unum_decimal(a.value)) + return snprintf(str, size, "%llu", a.value); + else + return snprintf(str, size, "%#llx", a.value); + } + return snprintf(str, size, "(%#llx; %#llx)", a.value, a.mask); +} +EXPORT_SYMBOL_GPL(tnum_strn); + static void print_scalar_ranges(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, const char **sep) diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c index f4c91c9b27d7..9dbc31b25e3d 100644 --- a/kernel/bpf/tnum.c +++ b/kernel/bpf/tnum.c @@ -172,12 +172,6 @@ bool tnum_in(struct tnum a, struct tnum b) return a.value == b.value; } -int tnum_strn(char *str, size_t size, struct tnum a) -{ - return snprintf(str, size, "(%#llx; %#llx)", a.value, a.mask); -} -EXPORT_SYMBOL_GPL(tnum_strn); - int tnum_sbin(char *str, size_t size, struct tnum a) { size_t n; diff --git a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c index 99a23dea8233..be95570ab382 100644 --- a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c +++ b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c @@ -411,7 +411,7 @@ l0_%=: r0 = 0; \ SEC("tc") __description("direct packet access: test17 (pruning, alignment)") -__failure __msg("misaligned packet access off 2+(0x0; 0x0)+15+-4 size 4") +__failure __msg("misaligned packet access off 2+0+15+-4 size 4") __flag(BPF_F_STRICT_ALIGNMENT) __naked void packet_access_test17_pruning_alignment(void) { diff --git a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c index b054f9c48143..74d9cad469d9 100644 --- a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c +++ b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c @@ -67,7 +67,7 @@ __naked void ptr_to_long_half_uninitialized(void) SEC("cgroup/sysctl") __description("ARG_PTR_TO_LONG misaligned") -__failure __msg("misaligned stack access off (0x0; 0x0)+-20+0 size 8") +__failure __msg("misaligned stack access off 0+-20+0 size 8") __naked void arg_ptr_to_long_misaligned(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c b/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c index e0f77e3e7869..417c61cd4b19 100644 --- a/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c +++ b/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c @@ -37,7 +37,7 @@ __naked void ptr_to_stack_store_load(void) SEC("socket") __description("PTR_TO_STACK store/load - bad alignment on off") -__failure __msg("misaligned stack access off (0x0; 0x0)+-8+2 size 8") +__failure __msg("misaligned stack access off 0+-8+2 size 8") __failure_unpriv __naked void load_bad_alignment_on_off(void) { @@ -53,7 +53,7 @@ __naked void load_bad_alignment_on_off(void) SEC("socket") __description("PTR_TO_STACK store/load - bad alignment on reg") -__failure __msg("misaligned stack access off (0x0; 0x0)+-10+8 size 8") +__failure __msg("misaligned stack access off 0+-10+8 size 8") __failure_unpriv __naked void load_bad_alignment_on_reg(void) { From ac7110d883ff2a25d2b0ae45c909c02d598c33af Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 10 Oct 2023 06:46:50 -0600 Subject: [PATCH 2211/7721] atags_proc: Add __counted_by for struct buffer and use struct_size() Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). While there, use struct_size() helper, instead of the open-coded version, to calculate the size for the allocation of the whole flexible structure, including of course, the flexible-array member. This code was found with the help of Coccinelle, and audited and fixed manually. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Reviewed-by: Justin Stitt Link: https://lore.kernel.org/r/ZSVHurzo/4aFQcT3@work Signed-off-by: Kees Cook --- arch/arm/kernel/atags_proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/atags_proc.c b/arch/arm/kernel/atags_proc.c index 3ec2afe78423..cd09f8ab93e3 100644 --- a/arch/arm/kernel/atags_proc.c +++ b/arch/arm/kernel/atags_proc.c @@ -7,7 +7,7 @@ struct buffer { size_t size; - char data[]; + char data[] __counted_by(size); }; static ssize_t atags_read(struct file *file, char __user *buf, @@ -54,7 +54,7 @@ static int __init init_atags_procfs(void) WARN_ON(tag->hdr.tag != ATAG_NONE); - b = kmalloc(sizeof(*b) + size, GFP_KERNEL); + b = kmalloc(struct_size(b, data, size), GFP_KERNEL); if (!b) goto nomem; From 14006f1d8fa24a2320781ad503ca1cba92e940d2 Mon Sep 17 00:00:00 2001 From: Coco Li Date: Wed, 29 Nov 2023 07:27:52 +0000 Subject: [PATCH 2212/7721] Documentations: Analyze heavily used Networking related structs Analyzed a few structs in the networking stack by looking at variables within them that are used in the TCP/IP fast path. Fast path is defined as TCP path where data is transferred from sender to receiver unidirectionally. It doesn't include phases other than TCP_ESTABLISHED, nor does it look at error paths. We hope to re-organizing variables that span many cachelines whose fast path variables are also spread out, and this document can help future developers keep networking fast path cachelines small. Optimized_cacheline field is computed as (Fastpath_Bytes/L3_cacheline_size_x86), and not the actual organized results (see patches to come for these). Investigation is done on 6.5 Name Struct_Cachelines Cur_fastpath_cache Fastpath_Bytes Optimized_cacheline tcp_sock 42 (2664 Bytes) 12 396 8 net_device 39 (2240 bytes) 12 234 4 inet_sock 15 (960 bytes) 14 922 14 Inet_connection_sock 22 (1368 bytes) 18 1166 18 Netns_ipv4 (sysctls) 12 (768 bytes) 4 77 2 linux_mib 16 (1060) 6 104 2 Note how there isn't much improvement space for inet_sock and Inet_connection_sock because sk and icsk_inet respectively takes up so much of the struct that rest of the variables become a small portion of the struct size. So, we decided to reorganize tcp_sock, net_device, netns_ipv4 Suggested-by: Eric Dumazet Signed-off-by: Coco Li Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller --- Documentation/networking/index.rst | 1 + .../networking/net_cachelines/index.rst | 15 ++ .../net_cachelines/inet_connection_sock.rst | 49 +++++ .../networking/net_cachelines/inet_sock.rst | 43 +++++ .../networking/net_cachelines/net_device.rst | 177 ++++++++++++++++++ .../net_cachelines/netns_ipv4_sysctl.rst | 157 ++++++++++++++++ .../networking/net_cachelines/snmp.rst | 134 +++++++++++++ .../networking/net_cachelines/tcp_sock.rst | 156 +++++++++++++++ MAINTAINERS | 3 + 9 files changed, 735 insertions(+) create mode 100644 Documentation/networking/net_cachelines/index.rst create mode 100644 Documentation/networking/net_cachelines/inet_connection_sock.rst create mode 100644 Documentation/networking/net_cachelines/inet_sock.rst create mode 100644 Documentation/networking/net_cachelines/net_device.rst create mode 100644 Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst create mode 100644 Documentation/networking/net_cachelines/snmp.rst create mode 100644 Documentation/networking/net_cachelines/tcp_sock.rst diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index d9424dcb19bf..69f3d6dcd9fd 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -75,6 +75,7 @@ Contents: mptcp-sysctl multiqueue napi + net_cachelines/index netconsole netdev-features netdevices diff --git a/Documentation/networking/net_cachelines/index.rst b/Documentation/networking/net_cachelines/index.rst new file mode 100644 index 000000000000..6f1a99989bbd --- /dev/null +++ b/Documentation/networking/net_cachelines/index.rst @@ -0,0 +1,15 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +=================================== +Common Networking Struct Cachelines +=================================== + +.. toctree:: + :maxdepth: 1 + + inet_connection_sock + inet_sock + net_device + netns_ipv4_sysctl + snmp + tcp_sock diff --git a/Documentation/networking/net_cachelines/inet_connection_sock.rst b/Documentation/networking/net_cachelines/inet_connection_sock.rst new file mode 100644 index 000000000000..ad2b200147a6 --- /dev/null +++ b/Documentation/networking/net_cachelines/inet_connection_sock.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +===================================================== +inet_connection_sock struct fast path usage breakdown +===================================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..inet_connection_sock +struct_inet_sock icsk_inet read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct_request_sock_queue icsk_accept_queue - - +struct_inet_bind_bucket icsk_bind_hash read_mostly - tcp_set_state +struct_inet_bind2_bucket icsk_bind2_hash read_mostly - tcp_set_state,inet_put_port +unsigned_long icsk_timeout read_mostly - inet_csk_reset_xmit_timer,tcp_connect +struct_timer_list icsk_retransmit_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect +struct_timer_list icsk_delack_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect +u32 icsk_rto read_write - tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one +u32 icsk_rto_min - - +u32 icsk_delack_max - - +u32 icsk_pmtu_cookie read_write - tcp_sync_mss,tcp_current_mss,tcp_send_syn_data,tcp_connect_init,tcp_connect +struct_tcp_congestion_ops icsk_ca_ops read_write - tcp_cwnd_validate,tcp_tso_segs,tcp_ca_dst_init,tcp_connect_init,tcp_connect,tcp_write_xmit +struct_inet_connection_sock_af_ops icsk_af_ops read_mostly - tcp_finish_connect,tcp_send_syn_data,tcp_mtup_init,tcp_mtu_check_reprobe,tcp_mtu_probe,tcp_connect_init,tcp_connect,__tcp_transmit_skb +struct_tcp_ulp_ops* icsk_ulp_ops - - +void* icsk_ulp_data - - +u8:5 icsk_ca_state read_write - tcp_cwnd_application_limited,tcp_set_ca_state,tcp_enter_cwr,tcp_tso_should_defer,tcp_mtu_probe,tcp_schedule_loss_probe,tcp_write_xmit,__tcp_transmit_skb +u8:1 icsk_ca_initialized read_write - tcp_init_transfer,tcp_init_congestion_control,tcp_init_transfer,tcp_finish_connect,tcp_connect +u8:1 icsk_ca_setsockopt - - +u8:1 icsk_ca_dst_locked write_mostly - tcp_ca_dst_init,tcp_connect_init,tcp_connect +u8 icsk_retransmits write_mostly - tcp_connect_init,tcp_connect +u8 icsk_pending read_write - inet_csk_reset_xmit_timer,tcp_connect,tcp_check_probe_timer,__tcp_push_pending_frames,tcp_rearm_rto,tcp_event_new_data_sent,tcp_event_new_data_sent +u8 icsk_backoff write_mostly - tcp_write_queue_purge,tcp_connect_init +u8 icsk_syn_retries - - +u8 icsk_probes_out - - +u16 icsk_ext_hdr_len read_mostly - __tcp_mtu_to_mss,tcp_mtu_to_rss,tcp_mtu_probe,tcp_write_xmit,tcp_mtu_to_mss, +struct_icsk_ack_u8 pending read_write read_write inet_csk_ack_scheduled,__tcp_cleanup_rbuf,tcp_cleanup_rbuf,inet_csk_clear_xmit_timer,tcp_event_ack-sent,inet_csk_reset_xmit_timer +struct_icsk_ack_u8 quick read_write write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_select_window,__tcp_cleanup_rbuf +struct_icsk_ack_u8 pingpong - - +struct_icsk_ack_u8 retry write_mostly read_write inet_csk_clear_xmit_timer,tcp_rearm_rto,tcp_event_new_data_sent,tcp_write_xmit,__tcp_send_ack,tcp_send_ack, +struct_icsk_ack_u8 ato read_mostly write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_send_ack,tcp_send_ack +struct_icsk_ack_unsigned_long timeout read_write read_write inet_csk_reset_xmit_timer,tcp_connect +struct_icsk_ack_u32 lrcvtime read_write - tcp_finish_connect,tcp_connect,tcp_event_data_sent,__tcp_transmit_skb +struct_icsk_ack_u16 rcv_mss write_mostly read_mostly __tcp_select_window,__tcp_cleanup_rbuf,tcp_initialize_rcv_mss,tcp_connect_init +struct_icsk_mtup_int search_high read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_check_reprobe,tcp_write_xmit +struct_icsk_mtup_int search_low read_write - tcp_mtu_probe,tcp_mtu_check_reprobe,tcp_write_xmit,tcp_sync_mss,tcp_connect_init,tcp_mtup_init +struct_icsk_mtup_u32:31 probe_size read_write - tcp_mtup_init,tcp_connect_init,__tcp_transmit_skb +struct_icsk_mtup_u32:1 enabled read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_probe,tcp_write_xmit +struct_icsk_mtup_u32 probe_timestamp read_write - tcp_mtup_init,tcp_connect_init,tcp_mtu_check_reprobe,tcp_mtu_probe +u32 icsk_probes_tstamp - - +u32 icsk_user_timeout - - +u64[104/sizeof(u64)] icsk_ca_priv - - diff --git a/Documentation/networking/net_cachelines/inet_sock.rst b/Documentation/networking/net_cachelines/inet_sock.rst new file mode 100644 index 000000000000..4077febdb995 --- /dev/null +++ b/Documentation/networking/net_cachelines/inet_sock.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +===================================================== +inet_connection_sock struct fast path usage breakdown +===================================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..inet_sock +struct_sock sk read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct_ipv6_pinfo* pinet6 - - +be16 inet_sport read_mostly - __tcp_transmit_skb +be32 inet_daddr read_mostly - ip_select_ident_segs +be32 inet_rcv_saddr - - +be16 inet_dport read_mostly - __tcp_transmit_skb +u16 inet_num - - +be32 inet_saddr - - +s16 uc_ttl read_mostly - __ip_queue_xmit/ip_select_ttl +u16 cmsg_flags - - +struct_ip_options_rcu* inet_opt read_mostly - __ip_queue_xmit +u16 inet_id read_mostly - ip_select_ident_segs +u8 tos read_mostly - ip_queue_xmit +u8 min_ttl - - +u8 mc_ttl - - +u8 pmtudisc - - +u8:1 recverr - - +u8:1 is_icsk - - +u8:1 freebind - - +u8:1 hdrincl - - +u8:1 mc_loop - - +u8:1 transparent - - +u8:1 mc_all - - +u8:1 nodefrag - - +u8:1 bind_address_no_port - - +u8:1 recverr_rfc4884 - - +u8:1 defer_connect read_mostly - tcp_sendmsg_fastopen +u8 rcv_tos - - +u8 convert_csum - - +int uc_index - - +int mc_index - - +be32 mc_addr - - +struct_ip_mc_socklist* mc_list - - +struct_inet_cork_full cork read_mostly - __tcp_transmit_skb +struct local_port_range - - diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst new file mode 100644 index 000000000000..98508aa4f800 --- /dev/null +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -0,0 +1,177 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +=========================================== +net_device struct fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access Comments +..struct ..net_device +char name[16] - - +struct_netdev_name_node* name_node +struct_dev_ifalias* ifalias +unsigned_long mem_end +unsigned_long mem_start +unsigned_long base_addr +unsigned_long state +struct_list_head dev_list +struct_list_head napi_list +struct_list_head unreg_list +struct_list_head close_list +struct_list_head ptype_all read_mostly - dev_nit_active(tx) +struct_list_head ptype_specific read_mostly deliver_ptype_list_skb/__netif_receive_skb_core(rx) +struct adj_list +unsigned_int flags read_mostly read_mostly __dev_queue_xmit,__dev_xmit_skb,ip6_output,__ip6_finish_output(tx);ip6_rcv_core(rx) +xdp_features_t xdp_features +unsigned_long_long priv_flags read_mostly - __dev_queue_xmit(tx) +struct_net_device_ops* netdev_ops read_mostly - netdev_core_pick_tx,netdev_start_xmit(tx) +struct_xdp_metadata_ops* xdp_metadata_ops +int ifindex - read_mostly ip6_rcv_core +unsigned_short gflags +unsigned_short hard_header_len read_mostly read_mostly ip6_xmit(tx);gro_list_prepare(rx) +unsigned_int mtu read_mostly - ip_finish_output2 +unsigned_short needed_headroom read_mostly - LL_RESERVED_SPACE/ip_finish_output2 +unsigned_short needed_tailroom +netdev_features_t features read_mostly read_mostly HARD_TX_LOCK,netif_skb_features,sk_setup_caps(tx);netif_elide_gro(rx) +netdev_features_t hw_features +netdev_features_t wanted_features +netdev_features_t vlan_features +netdev_features_t hw_enc_features - - netif_skb_features +netdev_features_t mpls_features +netdev_features_t gso_partial_features +unsigned_int min_mtu +unsigned_int max_mtu +unsigned_short type +unsigned_char min_header_len +unsigned_char name_assign_type +int group +struct_net_device_stats stats +struct_net_device_core_stats* core_stats +atomic_t carrier_up_count +atomic_t carrier_down_count +struct_iw_handler_def* wireless_handlers +struct_iw_public_data* wireless_data +struct_ethtool_ops* ethtool_ops +struct_l3mdev_ops* l3mdev_ops +struct_ndisc_ops* ndisc_ops +struct_xfrmdev_ops* xfrmdev_ops +struct_tlsdev_ops* tlsdev_ops +struct_header_ops* header_ops read_mostly - ip_finish_output2,ip6_finish_output2(tx) +unsigned_char operstate +unsigned_char link_mode +unsigned_char if_port +unsigned_char dma +unsigned_char perm_addr[32] +unsigned_char addr_assign_type +unsigned_char addr_len +unsigned_char upper_level +unsigned_char lower_level +unsigned_short neigh_priv_len +unsigned_short padded +unsigned_short dev_id +unsigned_short dev_port +spinlock_t addr_list_lock +int irq +struct_netdev_hw_addr_list uc +struct_netdev_hw_addr_list mc +struct_netdev_hw_addr_list dev_addrs +struct_kset* queues_kset +struct_list_head unlink_list +unsigned_int promiscuity +unsigned_int allmulti +bool uc_promisc +unsigned_char nested_level +struct_in_device* ip_ptr read_mostly read_mostly __in_dev_get +struct_inet6_dev* ip6_ptr read_mostly read_mostly __in6_dev_get +struct_vlan_info* vlan_info +struct_dsa_port* dsa_ptr +struct_tipc_bearer* tipc_ptr +void* atalk_ptr +void* ax25_ptr +struct_wireless_dev* ieee80211_ptr +struct_wpan_dev* ieee802154_ptr +struct_mpls_dev* mpls_ptr +struct_mctp_dev* mctp_ptr +unsigned_char* dev_addr +struct_netdev_queue* _rx read_mostly - netdev_get_rx_queue(rx) +unsigned_int num_rx_queues +unsigned_int real_num_rx_queues - read_mostly get_rps_cpu +struct_bpf_prog* xdp_prog +unsigned_long gro_flush_timeout - read_mostly napi_complete_done +int napi_defer_hard_irqs - read_mostly napi_complete_done +unsigned_int gro_max_size - read_mostly skb_gro_receive +unsigned_int gro_ipv4_max_size - read_mostly skb_gro_receive +rx_handler_func_t* rx_handler read_mostly - __netif_receive_skb_core +void* rx_handler_data read_mostly - +struct_netdev_queue* ingress_queue read_mostly - +struct_bpf_mprog_entry tcx_ingress - read_mostly sch_handle_ingress +struct_nf_hook_entries* nf_hooks_ingress +unsigned_char broadcast[32] +struct_cpu_rmap* rx_cpu_rmap +struct_hlist_node index_hlist +struct_netdev_queue* _tx read_mostly - netdev_get_tx_queue(tx) +unsigned_int num_tx_queues - - +unsigned_int real_num_tx_queues read_mostly - skb_tx_hash,netdev_core_pick_tx(tx) +unsigned_int tx_queue_len +spinlock_t tx_global_lock +struct_xdp_dev_bulk_queue__percpu* xdp_bulkq +struct_xps_dev_maps* xps_maps[2] read_mostly - __netif_set_xps_queue +struct_bpf_mprog_entry tcx_egress read_mostly - sch_handle_egress +struct_nf_hook_entries* nf_hooks_egress read_mostly - +struct_hlist_head qdisc_hash[16] +struct_timer_list watchdog_timer +int watchdog_timeo +u32 proto_down_reason +struct_list_head todo_list +int__percpu* pcpu_refcnt +refcount_t dev_refcnt +struct_ref_tracker_dir refcnt_tracker +struct_list_head link_watch_list +enum:8 reg_state +bool dismantle +enum:16 rtnl_link_state +bool needs_free_netdev +void*priv_destructor struct_net_device +struct_netpoll_info* npinfo - read_mostly napi_poll/napi_poll_lock +possible_net_t nd_net - read_mostly (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish +void* ml_priv +enum_netdev_ml_priv_type ml_priv_type +struct_pcpu_lstats__percpu* lstats +struct_pcpu_sw_netstats__percpu* tstats +struct_pcpu_dstats__percpu* dstats +struct_garp_port* garp_port +struct_mrp_port* mrp_port +struct_dm_hw_stat_delta* dm_private +struct_device dev - - +struct_attribute_group* sysfs_groups[4] +struct_attribute_group* sysfs_rx_queue_group +struct_rtnl_link_ops* rtnl_link_ops +unsigned_int gso_max_size read_mostly - sk_dst_gso_max_size +unsigned_int tso_max_size +u16 gso_max_segs read_mostly - gso_max_segs +u16 tso_max_segs +unsigned_int gso_ipv4_max_size read_mostly - sk_dst_gso_max_size +struct_dcbnl_rtnl_ops* dcbnl_ops +s16 num_tc read_mostly - skb_tx_hash +struct_netdev_tc_txq tc_to_txq[16] read_mostly - skb_tx_hash +u8 prio_tc_map[16] +unsigned_int fcoe_ddp_xid +struct_netprio_map* priomap +struct_phy_device* phydev +struct_sfp_bus* sfp_bus +struct_lock_class_key* qdisc_tx_busylock +bool proto_down +unsigned:1 wol_enabled +unsigned:1 threaded - - napi_poll(napi_enable,dev_set_threaded) +struct_list_head net_notifier_list +struct_macsec_ops* macsec_ops +struct_udp_tunnel_nic_info* udp_tunnel_nic_info +struct_udp_tunnel_nic* udp_tunnel_nic +unsigned_int xdp_zc_max_segs +struct_bpf_xdp_entity xdp_state[3] +u8 dev_addr_shadow[32] +netdevice_tracker linkwatch_dev_tracker +netdevice_tracker watchdog_dev_tracker +netdevice_tracker dev_registered_tracker +struct_rtnl_hw_stats64* offload_xstats_l3 +struct_devlink_port* devlink_port +struct_dpll_pin* dpll_pin diff --git a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst new file mode 100644 index 000000000000..47e1a0105384 --- /dev/null +++ b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst @@ -0,0 +1,157 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +=========================================== +netns_ipv4 struct fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..netns_ipv4 +struct_inet_timewait_death_row tcp_death_row +struct_udp_table* udp_table +struct_ctl_table_header* forw_hdr +struct_ctl_table_header* frags_hdr +struct_ctl_table_header* ipv4_hdr +struct_ctl_table_header* route_hdr +struct_ctl_table_header* xfrm4_hdr +struct_ipv4_devconf* devconf_all +struct_ipv4_devconf* devconf_dflt +struct_ip_ra_chain ra_chain +struct_mutex ra_mutex +struct_fib_rules_ops* rules_ops +struct_fib_table fib_main +struct_fib_table fib_default +unsigned_int fib_rules_require_fldissect +bool fib_has_custom_rules +bool fib_has_custom_local_routes +bool fib_offload_disabled +atomic_t fib_num_tclassid_users +struct_hlist_head* fib_table_hash +struct_sock* fibnl +struct_sock* mc_autojoin_sk +struct_inet_peer_base* peers +struct_fqdir* fqdir +u8 sysctl_icmp_echo_ignore_all +u8 sysctl_icmp_echo_enable_probe +u8 sysctl_icmp_echo_ignore_broadcasts +u8 sysctl_icmp_ignore_bogus_error_responses +u8 sysctl_icmp_errors_use_inbound_ifaddr +int sysctl_icmp_ratelimit +int sysctl_icmp_ratemask +u32 ip_rt_min_pmtu - - +int ip_rt_mtu_expires - - +int ip_rt_min_advmss - - +struct_local_ports ip_local_ports - - +u8 sysctl_tcp_ecn - - +u8 sysctl_tcp_ecn_fallback - - +u8 sysctl_ip_default_ttl - - ip4_dst_hoplimit/ip_select_ttl +u8 sysctl_ip_no_pmtu_disc - - +u8 sysctl_ip_fwd_use_pmtu read_mostly - ip_dst_mtu_maybe_forward/ip_skb_dst_mtu +u8 sysctl_ip_fwd_update_priority - - ip_forward +u8 sysctl_ip_nonlocal_bind - - +u8 sysctl_ip_autobind_reuse - - +u8 sysctl_ip_dynaddr - - +u8 sysctl_ip_early_demux - read_mostly ip(6)_rcv_finish_core +u8 sysctl_raw_l3mdev_accept - - +u8 sysctl_tcp_early_demux - read_mostly ip(6)_rcv_finish_core +u8 sysctl_udp_early_demux +u8 sysctl_nexthop_compat_mode - - +u8 sysctl_fwmark_reflect - - +u8 sysctl_tcp_fwmark_accept - - +u8 sysctl_tcp_l3mdev_accept - - +u8 sysctl_tcp_mtu_probing - - +int sysctl_tcp_mtu_probe_floor - - +int sysctl_tcp_base_mss - - +int sysctl_tcp_min_snd_mss read_mostly - __tcp_mtu_to_mss(tcp_write_xmit) +int sysctl_tcp_probe_threshold - - tcp_mtu_probe(tcp_write_xmit) +u32 sysctl_tcp_probe_interval - - tcp_mtu_check_reprobe(tcp_write_xmit) +int sysctl_tcp_keepalive_time - - +int sysctl_tcp_keepalive_intvl - - +u8 sysctl_tcp_keepalive_probes - - +u8 sysctl_tcp_syn_retries - - +u8 sysctl_tcp_synack_retries - - +u8 sysctl_tcp_syncookies - - generated_on_syn +u8 sysctl_tcp_migrate_req - - reuseport +u8 sysctl_tcp_comp_sack_nr - - __tcp_ack_snd_check +int sysctl_tcp_reordering - read_mostly tcp_may_raise_cwnd/tcp_cong_control +u8 sysctl_tcp_retries1 - - +u8 sysctl_tcp_retries2 - - +u8 sysctl_tcp_orphan_retries - - +u8 sysctl_tcp_tw_reuse - - timewait_sock_ops +int sysctl_tcp_fin_timeout - - TCP_LAST_ACK/tcp_rcv_state_process +unsigned_int sysctl_tcp_notsent_lowat read_mostly - tcp_notsent_lowat/tcp_stream_memory_free +u8 sysctl_tcp_sack - - tcp_syn_options +u8 sysctl_tcp_window_scaling - - tcp_syn_options,tcp_parse_options +u8 sysctl_tcp_timestamps +u8 sysctl_tcp_early_retrans read_mostly - tcp_schedule_loss_probe(tcp_write_xmit) +u8 sysctl_tcp_recovery - - tcp_fastretrans_alert +u8 sysctl_tcp_thin_linear_timeouts - - tcp_retrans_timer(on_thin_streams) +u8 sysctl_tcp_slow_start_after_idle - - unlikely(tcp_cwnd_validate-network-not-starved) +u8 sysctl_tcp_retrans_collapse - - +u8 sysctl_tcp_stdurg - - unlikely(tcp_check_urg) +u8 sysctl_tcp_rfc1337 - - +u8 sysctl_tcp_abort_on_overflow - - +u8 sysctl_tcp_fack - - +int sysctl_tcp_max_reordering - - tcp_check_sack_reordering +int sysctl_tcp_adv_win_scale - - tcp_init_buffer_space +u8 sysctl_tcp_dsack - - partial_packet_or_retrans_in_tcp_data_queue +u8 sysctl_tcp_app_win - - tcp_win_from_space +u8 sysctl_tcp_frto - - tcp_enter_loss +u8 sysctl_tcp_nometrics_save - - TCP_LAST_ACK/tcp_update_metrics +u8 sysctl_tcp_no_ssthresh_metrics_save - - TCP_LAST_ACK/tcp_(update/init)_metrics +u8 sysctl_tcp_moderate_rcvbuf read_mostly read_mostly tcp_tso_should_defer(tx);tcp_rcv_space_adjust(rx) +u8 sysctl_tcp_tso_win_divisor read_mostly - tcp_tso_should_defer(tcp_write_xmit) +u8 sysctl_tcp_workaround_signed_windows - - tcp_select_window +int sysctl_tcp_limit_output_bytes read_mostly - tcp_small_queue_check(tcp_write_xmit) +int sysctl_tcp_challenge_ack_limit - - +int sysctl_tcp_min_rtt_wlen read_mostly - tcp_ack_update_rtt +u8 sysctl_tcp_min_tso_segs - - unlikely(icsk_ca_ops-written) +u8 sysctl_tcp_tso_rtt_log read_mostly - tcp_tso_autosize +u8 sysctl_tcp_autocorking read_mostly - tcp_push/tcp_should_autocork +u8 sysctl_tcp_reflect_tos - - tcp_v(4/6)_send_synack +int sysctl_tcp_invalid_ratelimit - - +int sysctl_tcp_pacing_ss_ratio - - default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_pacing_ca_ratio - - default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_wmem[3] read_mostly - tcp_wmem_schedule(sendmsg/sendpage) +int sysctl_tcp_rmem[3] - read_mostly __tcp_grow_window(tx),tcp_rcv_space_adjust(rx) +unsigned_int sysctl_tcp_child_ehash_entries +unsigned_long sysctl_tcp_comp_sack_delay_ns - - __tcp_ack_snd_check +unsigned_long sysctl_tcp_comp_sack_slack_ns - - __tcp_ack_snd_check +int sysctl_max_syn_backlog - - +int sysctl_tcp_fastopen - - +struct_tcp_congestion_ops tcp_congestion_control - - init_cc +struct_tcp_fastopen_context tcp_fastopen_ctx - - +unsigned_int sysctl_tcp_fastopen_blackhole_timeout - - +atomic_t tfo_active_disable_times - - +unsigned_long tfo_active_disable_stamp - - +u32 tcp_challenge_timestamp - - +u32 tcp_challenge_count - - +u8 sysctl_tcp_plb_enabled - - +u8 sysctl_tcp_plb_idle_rehash_rounds - - +u8 sysctl_tcp_plb_rehash_rounds - - +u8 sysctl_tcp_plb_suspend_rto_sec - - +int sysctl_tcp_plb_cong_thresh - - +int sysctl_udp_wmem_min +int sysctl_udp_rmem_min +u8 sysctl_fib_notify_on_flag_change +u8 sysctl_udp_l3mdev_accept +u8 sysctl_igmp_llm_reports +int sysctl_igmp_max_memberships +int sysctl_igmp_max_msf +int sysctl_igmp_qrv +struct_ping_group_range ping_group_range +atomic_t dev_addr_genid +unsigned_int sysctl_udp_child_hash_entries +unsigned_long* sysctl_local_reserved_ports +int sysctl_ip_prot_sock +struct_mr_table* mrt +struct_list_head mr_tables +struct_fib_rules_ops* mr_rules_ops +u32 sysctl_fib_multipath_hash_fields +u8 sysctl_fib_multipath_use_neigh +u8 sysctl_fib_multipath_hash_policy +struct_fib_notifier_ops* notifier_ops +unsigned_int fib_seq +struct_fib_notifier_ops* ipmr_notifier_ops +unsigned_int ipmr_seq +atomic_t rt_genid +siphash_key_t ip_id_key diff --git a/Documentation/networking/net_cachelines/snmp.rst b/Documentation/networking/net_cachelines/snmp.rst new file mode 100644 index 000000000000..1eaeb8bc252c --- /dev/null +++ b/Documentation/networking/net_cachelines/snmp.rst @@ -0,0 +1,134 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +=========================================== +netns_ipv4 enum fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..enum +unsigned_long LINUX_MIB_TCPKEEPALIVE write_mostly - tcp_keepalive_timer +unsigned_long LINUX_MIB_DELAYEDACKS write_mostly - tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_DELAYEDACKLOCKED write_mostly - tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_TCPAUTOCORKING write_mostly - tcp_push,tcp_sendmsg_locked +unsigned_long LINUX_MIB_TCPFROMZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPTOZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPWANTZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPORIGDATASENT write_mostly - tcp_write_xmit +unsigned_long LINUX_MIB_TCPHPHITS - write_mostly tcp_rcv_established,tcp_v4_do_rcv,tcp_v6_do_rcv +unsigned_long LINUX_MIB_TCPRCVCOALESCE - write_mostly tcp_try_coalesce,tcp_queue_rcv,tcp_rcv_established +unsigned_long LINUX_MIB_TCPPUREACKS - write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPHPACKS - write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPDELIVERED - write_mostly tcp_newly_delivered,tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_SYNCOOKIESSENT +unsigned_long LINUX_MIB_SYNCOOKIESRECV +unsigned_long LINUX_MIB_SYNCOOKIESFAILED +unsigned_long LINUX_MIB_EMBRYONICRSTS +unsigned_long LINUX_MIB_PRUNECALLED +unsigned_long LINUX_MIB_RCVPRUNED +unsigned_long LINUX_MIB_OFOPRUNED +unsigned_long LINUX_MIB_OUTOFWINDOWICMPS +unsigned_long LINUX_MIB_LOCKDROPPEDICMPS +unsigned_long LINUX_MIB_ARPFILTER +unsigned_long LINUX_MIB_TIMEWAITED +unsigned_long LINUX_MIB_TIMEWAITRECYCLED +unsigned_long LINUX_MIB_TIMEWAITKILLED +unsigned_long LINUX_MIB_PAWSACTIVEREJECTED +unsigned_long LINUX_MIB_PAWSESTABREJECTED +unsigned_long LINUX_MIB_DELAYEDACKLOST +unsigned_long LINUX_MIB_LISTENOVERFLOWS +unsigned_long LINUX_MIB_LISTENDROPS +unsigned_long LINUX_MIB_TCPRENORECOVERY +unsigned_long LINUX_MIB_TCPSACKRECOVERY +unsigned_long LINUX_MIB_TCPSACKRENEGING +unsigned_long LINUX_MIB_TCPSACKREORDER +unsigned_long LINUX_MIB_TCPRENOREORDER +unsigned_long LINUX_MIB_TCPTSREORDER +unsigned_long LINUX_MIB_TCPFULLUNDO +unsigned_long LINUX_MIB_TCPPARTIALUNDO +unsigned_long LINUX_MIB_TCPDSACKUNDO +unsigned_long LINUX_MIB_TCPLOSSUNDO +unsigned_long LINUX_MIB_TCPLOSTRETRANSMIT +unsigned_long LINUX_MIB_TCPRENOFAILURES +unsigned_long LINUX_MIB_TCPSACKFAILURES +unsigned_long LINUX_MIB_TCPLOSSFAILURES +unsigned_long LINUX_MIB_TCPFASTRETRANS +unsigned_long LINUX_MIB_TCPSLOWSTARTRETRANS +unsigned_long LINUX_MIB_TCPTIMEOUTS +unsigned_long LINUX_MIB_TCPLOSSPROBES +unsigned_long LINUX_MIB_TCPLOSSPROBERECOVERY +unsigned_long LINUX_MIB_TCPRENORECOVERYFAIL +unsigned_long LINUX_MIB_TCPSACKRECOVERYFAIL +unsigned_long LINUX_MIB_TCPRCVCOLLAPSED +unsigned_long LINUX_MIB_TCPDSACKOLDSENT +unsigned_long LINUX_MIB_TCPDSACKOFOSENT +unsigned_long LINUX_MIB_TCPDSACKRECV +unsigned_long LINUX_MIB_TCPDSACKOFORECV +unsigned_long LINUX_MIB_TCPABORTONDATA +unsigned_long LINUX_MIB_TCPABORTONCLOSE +unsigned_long LINUX_MIB_TCPABORTONMEMORY +unsigned_long LINUX_MIB_TCPABORTONTIMEOUT +unsigned_long LINUX_MIB_TCPABORTONLINGER +unsigned_long LINUX_MIB_TCPABORTFAILED +unsigned_long LINUX_MIB_TCPMEMORYPRESSURES +unsigned_long LINUX_MIB_TCPMEMORYPRESSURESCHRONO +unsigned_long LINUX_MIB_TCPSACKDISCARD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDOLD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDNOUNDO +unsigned_long LINUX_MIB_TCPSPURIOUSRTOS +unsigned_long LINUX_MIB_TCPMD5NOTFOUND +unsigned_long LINUX_MIB_TCPMD5UNEXPECTED +unsigned_long LINUX_MIB_TCPMD5FAILURE +unsigned_long LINUX_MIB_SACKSHIFTED +unsigned_long LINUX_MIB_SACKMERGED +unsigned_long LINUX_MIB_SACKSHIFTFALLBACK +unsigned_long LINUX_MIB_TCPBACKLOGDROP +unsigned_long LINUX_MIB_PFMEMALLOCDROP +unsigned_long LINUX_MIB_TCPMINTTLDROP +unsigned_long LINUX_MIB_TCPDEFERACCEPTDROP +unsigned_long LINUX_MIB_IPRPFILTER +unsigned_long LINUX_MIB_TCPTIMEWAITOVERFLOW +unsigned_long LINUX_MIB_TCPREQQFULLDOCOOKIES +unsigned_long LINUX_MIB_TCPREQQFULLDROP +unsigned_long LINUX_MIB_TCPRETRANSFAIL +unsigned_long LINUX_MIB_TCPBACKLOGCOALESCE +unsigned_long LINUX_MIB_TCPOFOQUEUE +unsigned_long LINUX_MIB_TCPOFODROP +unsigned_long LINUX_MIB_TCPOFOMERGE +unsigned_long LINUX_MIB_TCPCHALLENGEACK +unsigned_long LINUX_MIB_TCPSYNCHALLENGE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVE +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENLISTENOVERFLOW +unsigned_long LINUX_MIB_TCPFASTOPENCOOKIEREQD +unsigned_long LINUX_MIB_TCPFASTOPENBLACKHOLE +unsigned_long LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES +unsigned_long LINUX_MIB_BUSYPOLLRXPACKETS +unsigned_long LINUX_MIB_TCPSYNRETRANS +unsigned_long LINUX_MIB_TCPHYSTARTTRAINDETECT +unsigned_long LINUX_MIB_TCPHYSTARTTRAINCWND +unsigned_long LINUX_MIB_TCPHYSTARTDELAYDETECT +unsigned_long LINUX_MIB_TCPHYSTARTDELAYCWND +unsigned_long LINUX_MIB_TCPACKSKIPPEDSYNRECV +unsigned_long LINUX_MIB_TCPACKSKIPPEDPAWS +unsigned_long LINUX_MIB_TCPACKSKIPPEDSEQ +unsigned_long LINUX_MIB_TCPACKSKIPPEDFINWAIT2 +unsigned_long LINUX_MIB_TCPACKSKIPPEDTIMEWAIT +unsigned_long LINUX_MIB_TCPACKSKIPPEDCHALLENGE +unsigned_long LINUX_MIB_TCPWINPROBE +unsigned_long LINUX_MIB_TCPMTUPFAIL +unsigned_long LINUX_MIB_TCPMTUPSUCCESS +unsigned_long LINUX_MIB_TCPDELIVEREDCE +unsigned_long LINUX_MIB_TCPACKCOMPRESSED +unsigned_long LINUX_MIB_TCPZEROWINDOWDROP +unsigned_long LINUX_MIB_TCPRCVQDROP +unsigned_long LINUX_MIB_TCPWQUEUETOOBIG +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEALTKEY +unsigned_long LINUX_MIB_TCPTIMEOUTREHASH +unsigned_long LINUX_MIB_TCPDUPLICATEDATAREHASH +unsigned_long LINUX_MIB_TCPDSACKRECVSEGS +unsigned_long LINUX_MIB_TCPDSACKIGNOREDDUBIOUS +unsigned_long LINUX_MIB_TCPMIGRATEREQSUCCESS +unsigned_long LINUX_MIB_TCPMIGRATEREQFAILURE +unsigned_long __LINUX_MIB_MAX diff --git a/Documentation/networking/net_cachelines/tcp_sock.rst b/Documentation/networking/net_cachelines/tcp_sock.rst new file mode 100644 index 000000000000..802ad22015d7 --- /dev/null +++ b/Documentation/networking/net_cachelines/tcp_sock.rst @@ -0,0 +1,156 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC +========================================= +tcp_sock struct fast path usage breakdown +========================================= + +Type Name fastpath_tx_access fastpath_rx_access Comments +..struct ..tcp_sock +struct_inet_connection_sock inet_conn +u16 tcp_header_len read_mostly read_mostly tcp_bound_to_half_wnd,tcp_current_mss(tx);tcp_rcv_established(rx) +u16 gso_segs read_mostly - tcp_xmit_size_goal +__be32 pred_flags read_write read_mostly tcp_select_window(tx);tcp_rcv_established(rx) +u64 bytes_received - read_write tcp_rcv_nxt_update(rx) +u32 segs_in - read_write tcp_v6_rcv(rx) +u32 data_segs_in - read_write tcp_v6_rcv(rx) +u32 rcv_nxt read_mostly read_write tcp_cleanup_rbuf,tcp_send_ack,tcp_inq_hint,tcp_transmit_skb,tcp_receive_window(tx);tcp_v6_do_rcv,tcp_rcv_established,tcp_data_queue,tcp_receive_window,tcp_rcv_nxt_update(write)(rx) +u32 copied_seq - read_mostly tcp_cleanup_rbuf,tcp_rcv_space_adjust,tcp_inq_hint +u32 rcv_wup - read_write __tcp_cleanup_rbuf,tcp_receive_window,tcp_receive_established +u32 snd_nxt read_write read_mostly tcp_rate_check_app_limited,__tcp_transmit_skb,tcp_event_new_data_sent(write)(tx);tcp_rcv_established,tcp_ack,tcp_clean_rtx_queue(rx) +u32 segs_out read_write - __tcp_transmit_skb +u32 data_segs_out read_write - __tcp_transmit_skb,tcp_update_skb_after_send +u64 bytes_sent read_write - __tcp_transmit_skb +u64 bytes_acked - read_write tcp_snd_una_update/tcp_ack +u32 dsack_dups +u32 snd_una read_mostly read_write tcp_wnd_end,tcp_urg_mode,tcp_minshall_check,tcp_cwnd_validate(tx);tcp_ack,tcp_may_update_window,tcp_clean_rtx_queue(write),tcp_ack_tstamp(rx) +u32 snd_sml read_write - tcp_minshall_check,tcp_minshall_update +u32 rcv_tstamp - read_mostly tcp_ack +u32 lsndtime read_write - tcp_slow_start_after_idle_check,tcp_event_data_sent +u32 last_oow_ack_time +u32 compressed_ack_rcv_nxt +u32 tsoffset read_mostly read_mostly tcp_established_options(tx);tcp_fast_parse_options(rx) +struct_list_head tsq_node - - +struct_list_head tsorted_sent_queue read_write - tcp_update_skb_after_send +u32 snd_wl1 - read_mostly tcp_may_update_window +u32 snd_wnd read_mostly read_mostly tcp_wnd_end,tcp_tso_should_defer(tx);tcp_fast_path_on(rx) +u32 max_window read_mostly - tcp_bound_to_half_wnd,forced_push +u32 mss_cache read_mostly read_mostly tcp_rate_check_app_limited,tcp_current_mss,tcp_sync_mss,tcp_sndbuf_expand,tcp_tso_should_defer(tx);tcp_update_pacing_rate,tcp_clean_rtx_queue(rx) +u32 window_clamp read_mostly read_write tcp_rcv_space_adjust,__tcp_select_window +u32 rcv_ssthresh read_mostly - __tcp_select_window +u82 scaling_ratio +struct tcp_rack +u16 advmss - read_mostly tcp_rcv_space_adjust +u8 compressed_ack +u8:2 dup_ack_counter +u8:1 tlp_retrans +u8:1 tcp_usec_ts +u32 chrono_start read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u32[3] chrono_stat read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:2 chrono_type read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:1 rate_app_limited - read_write tcp_rate_gen +u8:1 fastopen_connect +u8:1 fastopen_no_cookie +u8:1 is_sack_reneg - read_mostly tcp_skb_entail,tcp_ack +u8:2 fastopen_client_fail +u8:4 nonagle read_write - tcp_skb_entail,tcp_push_pending_frames +u8:1 thin_lto +u8:1 recvmsg_inq +u8:1 repair read_mostly - tcp_write_xmit +u8:1 frto +u8 repair_queue - - +u8:2 save_syn +u8:1 syn_data +u8:1 syn_fastopen +u8:1 syn_fastopen_exp +u8:1 syn_fastopen_ch +u8:1 syn_data_acked +u8:1 is_cwnd_limited read_mostly - tcp_cwnd_validate,tcp_is_cwnd_limited +u32 tlp_high_seq - read_mostly tcp_ack +u32 tcp_tx_delay +u64 tcp_wstamp_ns read_write - tcp_pacing_check,tcp_tso_should_defer,tcp_update_skb_after_send +u64 tcp_clock_cache read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust),__tcp_transmit_skb,tcp_tso_should_defer;timer +u64 tcp_mstamp read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust)(tx);tcp_rcv_space_adjust,tcp_rate_gen,tcp_clean_rtx_queue,tcp_ack_update_rtt/tcp_time_stamp(rx);timer +u32 srtt_us read_mostly read_write tcp_tso_should_defer(tx);tcp_update_pacing_rate,__tcp_set_rto,tcp_rtt_estimator(rx) +u32 mdev_us read_write - tcp_rtt_estimator +u32 mdev_max_us +u32 rttvar_us - read_mostly __tcp_set_rto +u32 rtt_seq read_write tcp_rtt_estimator +struct_minmax rtt_min - read_mostly tcp_min_rtt/tcp_rate_gen,tcp_min_rtttcp_update_rtt_min +u32 packets_out read_write read_write tcp_packets_in_flight(tx/rx);tcp_slow_start_after_idle_check,tcp_nagle_check,tcp_rate_skb_sent,tcp_event_new_data_sent,tcp_cwnd_validate,tcp_write_xmit(tx);tcp_ack,tcp_clean_rtx_queue,tcp_update_pacing_rate(rx) +u32 retrans_out - read_mostly tcp_packets_in_flight,tcp_rate_check_app_limited +u32 max_packets_out - read_write tcp_cwnd_validate +u32 cwnd_usage_seq - read_write tcp_cwnd_validate +u16 urg_data - read_mostly tcp_fast_path_check +u8 ecn_flags read_write - tcp_ecn_send +u8 keepalive_probes +u32 reordering read_mostly - tcp_sndbuf_expand +u32 reord_seen +u32 snd_up read_write read_mostly tcp_mark_urg,tcp_urg_mode,__tcp_transmit_skb(tx);tcp_clean_rtx_queue(rx) +struct_tcp_options_received rx_opt read_mostly read_write tcp_established_options(tx);tcp_fast_path_on,tcp_ack_update_window,tcp_is_sack,tcp_data_queue,tcp_rcv_established,tcp_ack_update_rtt(rx) +u32 snd_ssthresh - read_mostly tcp_update_pacing_rate +u32 snd_cwnd read_mostly read_mostly tcp_snd_cwnd,tcp_rate_check_app_limited,tcp_tso_should_defer(tx);tcp_update_pacing_rate +u32 snd_cwnd_cnt +u32 snd_cwnd_clamp +u32 snd_cwnd_used +u32 snd_cwnd_stamp +u32 prior_cwnd +u32 prr_delivered +u32 prr_out read_mostly read_mostly tcp_rate_skb_sent,tcp_newly_delivered(tx);tcp_ack,tcp_rate_gen,tcp_clean_rtx_queue(rx) +u32 delivered read_mostly read_write tcp_rate_skb_sent, tcp_newly_delivered(tx);tcp_ack, tcp_rate_gen, tcp_clean_rtx_queue (rx) +u32 delivered_ce read_mostly read_write tcp_rate_skb_sent(tx);tcp_rate_gen(rx) +u32 lost - read_mostly tcp_ack +u32 app_limited read_write read_mostly tcp_rate_check_app_limited,tcp_rate_skb_sent(tx);tcp_rate_gen(rx) +u64 first_tx_mstamp read_write - tcp_rate_skb_sent +u64 delivered_mstamp read_write - tcp_rate_skb_sent +u32 rate_delivered - read_mostly tcp_rate_gen +u32 rate_interval_us - read_mostly rate_delivered,rate_app_limited +u32 rcv_wnd read_write read_mostly tcp_select_window,tcp_receive_window,tcp_fast_path_check +u32 write_seq read_write - tcp_rate_check_app_limited,tcp_write_queue_empty,tcp_skb_entail,forced_push,tcp_mark_push +u32 notsent_lowat read_mostly - tcp_stream_memory_free +u32 pushed_seq read_write - tcp_mark_push,forced_push +u32 lost_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_rate_check_app_limited(rx) +u32 sacked_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_clean_rtx_queue(rx) +struct_hrtimer pacing_timer +struct_hrtimer compressed_ack_timer +struct_sk_buff* lost_skb_hint read_mostly tcp_clean_rtx_queue +struct_sk_buff* retransmit_skb_hint read_mostly - tcp_clean_rtx_queue +struct_rb_root out_of_order_queue - read_mostly tcp_data_queue,tcp_fast_path_check +struct_sk_buff* ooo_last_skb +struct_tcp_sack_block[1] duplicate_sack +struct_tcp_sack_block[4] selective_acks +struct_tcp_sack_block[4] recv_sack_cache +struct_sk_buff* highest_sack read_write - tcp_event_new_data_sent +int lost_cnt_hint +u32 prior_ssthresh +u32 high_seq +u32 retrans_stamp +u32 undo_marker +int undo_retrans +u64 bytes_retrans +u32 total_retrans +u32 rto_stamp +u16 total_rto +u16 total_rto_recoveries +u32 total_rto_time +u32 urg_seq - - +unsigned_int keepalive_time +unsigned_int keepalive_intvl +int linger2 +u8 bpf_sock_ops_cb_flags +u8:1 bpf_chg_cc_inprogress +u16 timeout_rehash +u32 rcv_ooopack +u32 rcv_rtt_last_tsecr +struct rcv_rtt_est - read_write tcp_rcv_space_adjust,tcp_rcv_established +struct rcvq_space - read_write tcp_rcv_space_adjust +struct mtu_probe +u32 plb_rehash +u32 mtu_info +bool is_mptcp +bool smc_hs_congested +bool syn_smc +struct_tcp_sock_af_ops* af_specific +struct_tcp_md5sig_info* md5sig_info +struct_tcp_fastopen_request* fastopen_req +struct_request_sock* fastopen_rsk +struct_saved_syn* saved_syn \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index e3fd148d462e..2d2865c1e479 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14986,6 +14986,7 @@ Q: https://patchwork.kernel.org/project/netdevbpf/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/devicetree/bindings/net/ +F: Documentation/networking/net_cachelines/net_device.rst F: drivers/connector/ F: drivers/net/ F: include/dt-bindings/net/ @@ -15041,6 +15042,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/core-api/netlink.rst F: Documentation/netlink/ F: Documentation/networking/ +F: Documentation/networking/net_cachelines/ F: Documentation/process/maintainer-netdev.rst F: Documentation/userspace-api/netlink/ F: include/linux/in.h @@ -15149,6 +15151,7 @@ NETWORKING [TCP] M: Eric Dumazet L: netdev@vger.kernel.org S: Maintained +F: Documentation/networking/net_cachelines/tcp_sock.rst F: include/linux/tcp.h F: include/net/tcp.h F: include/trace/events/tcp.h From aeb9ce058d7c6193dc41e06b3a5b29d22c446b14 Mon Sep 17 00:00:00 2001 From: Coco Li Date: Wed, 29 Nov 2023 07:27:53 +0000 Subject: [PATCH 2213/7721] cache: enforce cache groups Set up build time warnings to safeguard against future header changes of organized structs. Warning includes: 1) whether all variables are still in the same cache group 2) whether all the cache groups have the sum of the members size (in the maximum condition, including all members defined in configs) The __cache_group* variables are ignored in kernel-doc check in the various header files they appear in to enforce the cache groups. Suggested-by: Daniel Borkmann Acked-by: Daniel Borkmann Signed-off-by: Coco Li Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller --- include/linux/cache.h | 25 +++++++++++++++++++++++++ scripts/kernel-doc | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/include/linux/cache.h b/include/linux/cache.h index 9900d20b76c2..0ecb17bb6883 100644 --- a/include/linux/cache.h +++ b/include/linux/cache.h @@ -85,6 +85,31 @@ #define cache_line_size() L1_CACHE_BYTES #endif +#ifndef __cacheline_group_begin +#define __cacheline_group_begin(GROUP) \ + __u8 __cacheline_group_begin__##GROUP[0] +#endif + +#ifndef __cacheline_group_end +#define __cacheline_group_end(GROUP) \ + __u8 __cacheline_group_end__##GROUP[0] +#endif + +#ifndef CACHELINE_ASSERT_GROUP_MEMBER +#define CACHELINE_ASSERT_GROUP_MEMBER(TYPE, GROUP, MEMBER) \ + BUILD_BUG_ON(!(offsetof(TYPE, MEMBER) >= \ + offsetofend(TYPE, __cacheline_group_begin__##GROUP) && \ + offsetofend(TYPE, MEMBER) <= \ + offsetof(TYPE, __cacheline_group_end__##GROUP))) +#endif + +#ifndef CACHELINE_ASSERT_GROUP_SIZE +#define CACHELINE_ASSERT_GROUP_SIZE(TYPE, GROUP, SIZE) \ + BUILD_BUG_ON(offsetof(TYPE, __cacheline_group_end__##GROUP) - \ + offsetofend(TYPE, __cacheline_group_begin__##GROUP) > \ + SIZE) +#endif + /* * Helper to add padding within a struct to ensure data fall into separate * cachelines. diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 08a3e603db19..0a890fe4d22b 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1592,6 +1592,11 @@ sub push_parameter($$$$$) { $parameterdescs{$param} = "anonymous\n"; $anon_struct_union = 1; } + elsif ($param =~ "__cacheline_group" ) + # handle cache group enforcing variables: they do not need be described in header files + { + return; # ignore __cacheline_group_begin and __cacheline_group_end + } # warn if parameter has no description # (but ignore ones starting with # as these are not parameters From 18fd64d2542292713b0322e6815be059bdee440c Mon Sep 17 00:00:00 2001 From: Coco Li Date: Wed, 29 Nov 2023 07:27:54 +0000 Subject: [PATCH 2214/7721] netns-ipv4: reorganize netns_ipv4 fast path variables Reorganize fast path variables on tx-txrx-rx order. Fastpath cacheline ends after sysctl_tcp_rmem. There are only read-only variables here. (write is on the control path and not considered in this case) Below data generated with pahole on x86 architecture. Fast path variables span cache lines before change: 4 Fast path variables span cache lines after change: 2 Suggested-by: Eric Dumazet Reviewed-by: Wei Wang Reviewed-by: David Ahern Signed-off-by: Coco Li Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller --- include/net/netns/ipv4.h | 47 +++++++++++++++++++++++++++------------- net/core/net_namespace.c | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 73f43f699199..ea882964c71e 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -42,6 +42,38 @@ struct inet_timewait_death_row { struct tcp_fastopen_context; struct netns_ipv4 { + /* Cacheline organization can be found documented in + * Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst. + * Please update the document when adding new fields. + */ + + /* TX readonly hotpath cache lines */ + __cacheline_group_begin(netns_ipv4_read_tx); + u8 sysctl_tcp_early_retrans; + u8 sysctl_tcp_tso_win_divisor; + u8 sysctl_tcp_tso_rtt_log; + u8 sysctl_tcp_autocorking; + int sysctl_tcp_min_snd_mss; + unsigned int sysctl_tcp_notsent_lowat; + int sysctl_tcp_limit_output_bytes; + int sysctl_tcp_min_rtt_wlen; + int sysctl_tcp_wmem[3]; + u8 sysctl_ip_fwd_use_pmtu; + __cacheline_group_end(netns_ipv4_read_tx); + + /* TXRX readonly hotpath cache lines */ + __cacheline_group_begin(netns_ipv4_read_txrx); + u8 sysctl_tcp_moderate_rcvbuf; + __cacheline_group_end(netns_ipv4_read_txrx); + + /* RX readonly hotpath cache line */ + __cacheline_group_begin(netns_ipv4_read_rx); + u8 sysctl_ip_early_demux; + u8 sysctl_tcp_early_demux; + int sysctl_tcp_reordering; + int sysctl_tcp_rmem[3]; + __cacheline_group_end(netns_ipv4_read_rx); + struct inet_timewait_death_row tcp_death_row; struct udp_table *udp_table; @@ -96,17 +128,14 @@ struct netns_ipv4 { u8 sysctl_ip_default_ttl; u8 sysctl_ip_no_pmtu_disc; - u8 sysctl_ip_fwd_use_pmtu; u8 sysctl_ip_fwd_update_priority; u8 sysctl_ip_nonlocal_bind; u8 sysctl_ip_autobind_reuse; /* Shall we try to damage output packets if routing dev changes? */ u8 sysctl_ip_dynaddr; - u8 sysctl_ip_early_demux; #ifdef CONFIG_NET_L3_MASTER_DEV u8 sysctl_raw_l3mdev_accept; #endif - u8 sysctl_tcp_early_demux; u8 sysctl_udp_early_demux; u8 sysctl_nexthop_compat_mode; @@ -119,7 +148,6 @@ struct netns_ipv4 { u8 sysctl_tcp_mtu_probing; int sysctl_tcp_mtu_probe_floor; int sysctl_tcp_base_mss; - int sysctl_tcp_min_snd_mss; int sysctl_tcp_probe_threshold; u32 sysctl_tcp_probe_interval; @@ -135,17 +163,14 @@ struct netns_ipv4 { u8 sysctl_tcp_backlog_ack_defer; u8 sysctl_tcp_pingpong_thresh; - int sysctl_tcp_reordering; u8 sysctl_tcp_retries1; u8 sysctl_tcp_retries2; u8 sysctl_tcp_orphan_retries; u8 sysctl_tcp_tw_reuse; int sysctl_tcp_fin_timeout; - unsigned int sysctl_tcp_notsent_lowat; u8 sysctl_tcp_sack; u8 sysctl_tcp_window_scaling; u8 sysctl_tcp_timestamps; - u8 sysctl_tcp_early_retrans; u8 sysctl_tcp_recovery; u8 sysctl_tcp_thin_linear_timeouts; u8 sysctl_tcp_slow_start_after_idle; @@ -161,21 +186,13 @@ struct netns_ipv4 { u8 sysctl_tcp_frto; u8 sysctl_tcp_nometrics_save; u8 sysctl_tcp_no_ssthresh_metrics_save; - u8 sysctl_tcp_moderate_rcvbuf; - u8 sysctl_tcp_tso_win_divisor; u8 sysctl_tcp_workaround_signed_windows; - int sysctl_tcp_limit_output_bytes; int sysctl_tcp_challenge_ack_limit; - int sysctl_tcp_min_rtt_wlen; u8 sysctl_tcp_min_tso_segs; - u8 sysctl_tcp_tso_rtt_log; - u8 sysctl_tcp_autocorking; u8 sysctl_tcp_reflect_tos; int sysctl_tcp_invalid_ratelimit; int sysctl_tcp_pacing_ss_ratio; int sysctl_tcp_pacing_ca_ratio; - int sysctl_tcp_wmem[3]; - int sysctl_tcp_rmem[3]; unsigned int sysctl_tcp_child_ehash_entries; unsigned long sysctl_tcp_comp_sack_delay_ns; unsigned long sysctl_tcp_comp_sack_slack_ns; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index f4183c4c1ec8..cb8bcbff9e83 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -1099,11 +1099,56 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, rtnl_set_sk_err(net, RTNLGRP_NSID, err); } +#ifdef CONFIG_NET_NS +static void __init netns_ipv4_struct_check(void) +{ + /* TX readonly hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_early_retrans); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_tso_win_divisor); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_tso_rtt_log); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_autocorking); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_min_snd_mss); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_notsent_lowat); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_limit_output_bytes); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_min_rtt_wlen); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_tcp_wmem); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, + sysctl_ip_fwd_use_pmtu); + CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_tx, 33); + + /* TXRX readonly hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_txrx, + sysctl_tcp_moderate_rcvbuf); + CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_txrx, 1); + + /* RX readonly hotpath cache line */ + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, + sysctl_ip_early_demux); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, + sysctl_tcp_early_demux); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, + sysctl_tcp_reordering); + CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, + sysctl_tcp_rmem); + CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_rx, 18); +} +#endif + void __init net_ns_init(void) { struct net_generic *ng; #ifdef CONFIG_NET_NS + netns_ipv4_struct_check(); net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, SLAB_PANIC|SLAB_ACCOUNT, NULL); From ab8420418c2e67c81549ce483ff6a472c6dc2833 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 19 Oct 2023 13:44:19 +0300 Subject: [PATCH 2215/7721] drm/msm/dp: cleanup debugfs handling Currently there are two subdirs for DP debugfs files, e.g. DP-1, created by the drm core for the connector, and the msm_dp-DP-1, created by the DP driver itself. Merge those two, so that there are no extraneous connector-related subdirs. Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/563523/ Link: https://lore.kernel.org/r/20231019104419.1032329-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 11 ---- drivers/gpu/drm/msm/dp/dp_debug.c | 69 ++++++------------------- drivers/gpu/drm/msm/dp/dp_debug.h | 23 +++------ drivers/gpu/drm/msm/dp/dp_display.c | 5 +- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_drm.c | 16 ++++++ drivers/gpu/drm/msm/msm_drv.h | 6 --- 7 files changed, 42 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index fe7267b3bff5..babec724c76a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -274,9 +274,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) struct dpu_kms *dpu_kms = to_dpu_kms(kms); void *p = dpu_hw_util_get_log_mask_ptr(); struct dentry *entry; - struct drm_device *dev; - struct msm_drm_private *priv; - int i; if (!p) return -EINVAL; @@ -285,9 +282,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) if (minor->type != DRM_MINOR_PRIMARY) return 0; - dev = dpu_kms->dev; - priv = dev->dev_private; - entry = debugfs_create_dir("debug", minor->debugfs_root); debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p); @@ -297,11 +291,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) dpu_debugfs_core_irq_init(dpu_kms, entry); dpu_debugfs_sspp_init(dpu_kms, entry); - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { - if (priv->dp[i]) - msm_dp_debugfs_init(priv->dp[i], minor); - } - return dpu_core_perf_debugfs_init(dpu_kms, entry); } #endif diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 3bba901afe33..6c281dc095b9 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -19,13 +19,9 @@ #define DEBUG_NAME "msm_dp" struct dp_debug_private { - struct dentry *root; - struct dp_link *link; struct dp_panel *panel; struct drm_connector *connector; - struct device *dev; - struct drm_device *drm_dev; struct dp_debug dp_debug; }; @@ -204,35 +200,33 @@ static const struct file_operations test_active_fops = { .write = dp_test_active_write }; -static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor) +static void dp_debug_init(struct dp_debug *dp_debug, struct dentry *root, bool is_edp) { - char path[64]; struct dp_debug_private *debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - snprintf(path, sizeof(path), "msm_dp-%s", debug->connector->name); - - debug->root = debugfs_create_dir(path, minor->debugfs_root); - - debugfs_create_file("dp_debug", 0444, debug->root, + debugfs_create_file("dp_debug", 0444, root, debug, &dp_debug_fops); - debugfs_create_file("msm_dp_test_active", 0444, - debug->root, - debug, &test_active_fops); + if (!is_edp) { + debugfs_create_file("msm_dp_test_active", 0444, + root, + debug, &test_active_fops); - debugfs_create_file("msm_dp_test_data", 0444, - debug->root, - debug, &dp_test_data_fops); + debugfs_create_file("msm_dp_test_data", 0444, + root, + debug, &dp_test_data_fops); - debugfs_create_file("msm_dp_test_type", 0444, - debug->root, - debug, &dp_test_type_fops); + debugfs_create_file("msm_dp_test_type", 0444, + root, + debug, &dp_test_type_fops); + } } struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, - struct drm_connector *connector, struct drm_minor *minor) + struct drm_connector *connector, + struct dentry *root, bool is_edp) { struct dp_debug_private *debug; struct dp_debug *dp_debug; @@ -253,46 +247,15 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, debug->dp_debug.debug_en = false; debug->link = link; debug->panel = panel; - debug->dev = dev; - debug->drm_dev = minor->dev; - debug->connector = connector; dp_debug = &debug->dp_debug; dp_debug->vdisplay = 0; dp_debug->hdisplay = 0; dp_debug->vrefresh = 0; - dp_debug_init(dp_debug, minor); + dp_debug_init(dp_debug, root, is_edp); return dp_debug; error: return ERR_PTR(rc); } - -static int dp_debug_deinit(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return -EINVAL; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - debugfs_remove_recursive(debug->root); - - return 0; -} - -void dp_debug_put(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - dp_debug_deinit(dp_debug); - - devm_kfree(debug->dev, debug); -} diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 124227873d58..9b3b2e702f65 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -34,7 +34,8 @@ struct dp_debug { * @panel: instance of panel module * @link: instance of link module * @connector: double pointer to display connector - * @minor: pointer to drm minor number after device registration + * @root: connector's debugfs root + * @is_edp: set for eDP connectors / panels * return: pointer to allocated debug module data * * This function sets up the debug module and provides a way @@ -43,31 +44,21 @@ struct dp_debug { struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, struct drm_connector *connector, - struct drm_minor *minor); - -/** - * dp_debug_put() - * - * Cleans up dp_debug instance - * - * @dp_debug: instance of dp_debug - */ -void dp_debug_put(struct dp_debug *dp_debug); + struct dentry *root, + bool is_edp); #else static inline struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, - struct drm_connector *connector, struct drm_minor *minor) + struct drm_connector *connector, + struct dentry *root, + bool is_edp) { return ERR_PTR(-EINVAL); } -static inline void dp_debug_put(struct dp_debug *dp_debug) -{ -} - #endif /* defined(CONFIG_DEBUG_FS) */ #endif /* _DP_DEBUG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index e329e03e068d..2ac9d61501c7 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -715,7 +715,6 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) static void dp_display_deinit_sub_modules(struct dp_display_private *dp) { - dp_debug_put(dp->debug); dp_audio_put(dp->audio); dp_panel_put(dp->panel); dp_aux_put(dp->aux); @@ -1451,7 +1450,7 @@ bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) return dp->wide_bus_en; } -void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) +void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, bool is_edp) { struct dp_display_private *dp; struct device *dev; @@ -1462,7 +1461,7 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) dp->debug = dp_debug_get(dev, dp->panel, dp->link, dp->dp_display.connector, - minor); + root, is_edp); if (IS_ERR(dp->debug)) { rc = PTR_ERR(dp->debug); DRM_ERROR("failed to initialize debug, rc = %d\n", rc); diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index f66cdbc35785..5e2fbd8318e9 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -42,5 +42,6 @@ int dp_display_get_test_bpp(struct msm_dp *dp_display); void dp_display_signal_audio_start(struct msm_dp *dp_display); void dp_display_signal_audio_complete(struct msm_dp *dp_display); void dp_display_set_psr(struct msm_dp *dp, bool enter); +void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *dentry, bool is_edp); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 40e7344180e3..21850a384b10 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -90,6 +90,13 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * return rc; } +static void dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +{ + struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + + dp_display_debugfs_init(dp, root, false); +} + static const struct drm_bridge_funcs dp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -105,6 +112,7 @@ static const struct drm_bridge_funcs dp_bridge_ops = { .hpd_enable = dp_bridge_hpd_enable, .hpd_disable = dp_bridge_hpd_disable, .hpd_notify = dp_bridge_hpd_notify, + .debugfs_init = dp_bridge_debugfs_init, }; static int edp_bridge_atomic_check(struct drm_bridge *drm_bridge, @@ -260,6 +268,13 @@ static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } +static void edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +{ + struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + + dp_display_debugfs_init(dp, root, true); +} + static const struct drm_bridge_funcs edp_bridge_ops = { .atomic_enable = edp_bridge_atomic_enable, .atomic_disable = edp_bridge_atomic_disable, @@ -270,6 +285,7 @@ static const struct drm_bridge_funcs edp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_check = edp_bridge_atomic_check, + .debugfs_init = edp_bridge_debugfs_init, }; int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index cd5bf658df66..628ef3e663ea 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -389,7 +389,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, void msm_dp_irq_postinstall(struct msm_dp *dp_display); void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display); -void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor); bool msm_dp_wide_bus_available(const struct msm_dp *dp_display); #else @@ -415,11 +414,6 @@ static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm { } -static inline void msm_dp_debugfs_init(struct msm_dp *dp_display, - struct drm_minor *minor) -{ -} - static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) { return false; From 062aeadeba1d3822b1704235de9a0a0024a78683 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:52 +0300 Subject: [PATCH 2216/7721] drm/msm/mdp5: use devres-managed allocation for configuration data Use devm_kzalloc to create configuration data structure. This allows us to remove corresponding kfree and drop mdp5_cfg_destroy() function. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546156/ Link: https://lore.kernel.org/r/20230708010407.3871346-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c | 24 +++++------------------- drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h | 1 - drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 2 -- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index 694d54341337..c5179e4c393c 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c @@ -1350,23 +1350,17 @@ int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler) return cfg_handler->revision; } -void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler) -{ - kfree(cfg_handler); -} - struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor) { struct drm_device *dev = mdp5_kms->dev; struct mdp5_cfg_handler *cfg_handler; const struct mdp5_cfg_handler *cfg_handlers; - int i, ret = 0, num_handlers; + int i, num_handlers; - cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); + cfg_handler = devm_kzalloc(dev->dev, sizeof(*cfg_handler), GFP_KERNEL); if (unlikely(!cfg_handler)) { - ret = -ENOMEM; - goto fail; + return ERR_PTR(-ENOMEM); } switch (major) { @@ -1381,8 +1375,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, default: DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n", major, minor); - ret = -ENXIO; - goto fail; + return ERR_PTR(-ENXIO); } /* only after mdp5_cfg global pointer's init can we access the hw */ @@ -1396,8 +1389,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, if (unlikely(!mdp5_cfg)) { DRM_DEV_ERROR(dev->dev, "unexpected MDP minor revision: v%d.%d\n", major, minor); - ret = -ENXIO; - goto fail; + return ERR_PTR(-ENXIO); } cfg_handler->revision = minor; @@ -1406,10 +1398,4 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, DBG("MDP5: %s hw config selected", mdp5_cfg->name); return cfg_handler; - -fail: - if (cfg_handler) - mdp5_cfg_destroy(cfg_handler); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h index c2502cc33864..26c5d8b4ab46 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h @@ -121,6 +121,5 @@ int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd); struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor); -void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd); #endif /* __MDP5_CFG_H__ */ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 11d9fc2c6bf5..9f0467c8f172 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -629,8 +629,6 @@ static void mdp5_destroy(struct mdp5_kms *mdp5_kms) mdp5_ctlm_destroy(mdp5_kms->ctlm); if (mdp5_kms->smp) mdp5_smp_destroy(mdp5_kms->smp); - if (mdp5_kms->cfg) - mdp5_cfg_destroy(mdp5_kms->cfg); for (i = 0; i < mdp5_kms->num_intfs; i++) kfree(mdp5_kms->intfs[i]); From 4c1f4c1f1b43dbe399b93cf712ce31cc0b5181e6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:53 +0300 Subject: [PATCH 2217/7721] drm/msm/mdp5: use devres-managed allocation for CTL manager data Use devm_kzalloc to create CTL manager data structure. This allows us to remove corresponding kfree and drop mdp5_ctlm_destroy() function. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546159/ Link: https://lore.kernel.org/r/20230708010407.3871346-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c | 21 ++++----------------- drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h | 1 - drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 2 -- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index 1220f2b20e05..666de99a46a5 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -681,11 +681,6 @@ void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr) } } -void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr) -{ - kfree(ctl_mgr); -} - struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd) { @@ -697,18 +692,16 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, unsigned long flags; int c, ret; - ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL); + ctl_mgr = devm_kzalloc(dev->dev, sizeof(*ctl_mgr), GFP_KERNEL); if (!ctl_mgr) { DRM_DEV_ERROR(dev->dev, "failed to allocate CTL manager\n"); - ret = -ENOMEM; - goto fail; + return ERR_PTR(-ENOMEM); } if (WARN_ON(ctl_cfg->count > MAX_CTL)) { DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n", ctl_cfg->count); - ret = -ENOSPC; - goto fail; + return ERR_PTR(-ENOSPC); } /* initialize the CTL manager: */ @@ -727,7 +720,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, DRM_DEV_ERROR(dev->dev, "CTL_%d: base is null!\n", c); ret = -EINVAL; spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags); - goto fail; + return ERR_PTR(ret); } ctl->ctlm = ctl_mgr; ctl->id = c; @@ -755,10 +748,4 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, DBG("Pool of %d CTLs created.", ctl_mgr->nctl); return ctl_mgr; - -fail: - if (ctl_mgr) - mdp5_ctlm_destroy(ctl_mgr); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h index c2af68aa77ae..9020e8efc4e4 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h @@ -17,7 +17,6 @@ struct mdp5_ctl_manager; struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd); void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm); -void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm); /* * CTL prototypes: diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 9f0467c8f172..d2bd14e8dadf 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -625,8 +625,6 @@ static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { int i; - if (mdp5_kms->ctlm) - mdp5_ctlm_destroy(mdp5_kms->ctlm); if (mdp5_kms->smp) mdp5_smp_destroy(mdp5_kms->smp); From 1ad175c2c884a8ee56fb669648ef655a5d3f22fe Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:54 +0300 Subject: [PATCH 2218/7721] drm/msm/mdp5: use devres-managed allocation for mixer data Use devm_kzalloc to create mixer data structure. This allows us to remove corresponding kfree and drop mdp5_mixer_destroy() function. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546166/ Link: https://lore.kernel.org/r/20230708010407.3871346-5-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 5 +---- drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c | 10 +++------- drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h | 4 ++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index d2bd14e8dadf..3189b3b0a743 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -211,9 +211,6 @@ static void mdp5_kms_destroy(struct msm_kms *kms) struct msm_gem_address_space *aspace = kms->aspace; int i; - for (i = 0; i < mdp5_kms->num_hwmixers; i++) - mdp5_mixer_destroy(mdp5_kms->hwmixers[i]); - for (i = 0; i < mdp5_kms->num_hwpipes; i++) mdp5_pipe_destroy(mdp5_kms->hwpipes[i]); @@ -720,7 +717,7 @@ static int hwmixer_init(struct mdp5_kms *mdp5_kms) for (i = 0; i < hw_cfg->lm.count; i++) { struct mdp5_hw_mixer *mixer; - mixer = mdp5_mixer_init(&hw_cfg->lm.instances[i]); + mixer = mdp5_mixer_init(dev, &hw_cfg->lm.instances[i]); if (IS_ERR(mixer)) { ret = PTR_ERR(mixer); DRM_DEV_ERROR(dev->dev, "failed to construct LM%d (%d)\n", diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c index 2536def2a000..2822b533f807 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c @@ -140,20 +140,16 @@ int mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) return 0; } -void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer) -{ - kfree(mixer); -} - static const char * const mixer_names[] = { "LM0", "LM1", "LM2", "LM3", "LM4", "LM5", }; -struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm) +struct mdp5_hw_mixer *mdp5_mixer_init(struct drm_device *dev, + const struct mdp5_lm_instance *lm) { struct mdp5_hw_mixer *mixer; - mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + mixer = devm_kzalloc(dev->dev, sizeof(*mixer), GFP_KERNEL); if (!mixer) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h index 545ee223b9d7..2bedd75835bc 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h @@ -25,8 +25,8 @@ struct mdp5_hw_mixer_state { struct drm_crtc *hwmixer_to_crtc[8]; }; -struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm); -void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm); +struct mdp5_hw_mixer *mdp5_mixer_init(struct drm_device *dev, + const struct mdp5_lm_instance *lm); int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, uint32_t caps, struct mdp5_hw_mixer **mixer, struct mdp5_hw_mixer **r_mixer); From 323e9a18d6e195f44eaaa3d3fe92fce9073fe298 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:55 +0300 Subject: [PATCH 2219/7721] drm/msm/mdp5: use devres-managed allocation for pipe data Use devm_kzalloc to create pipe data structure. This allows us to remove corresponding kfree and drop mdp5_pipe_destroy() function. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546171/ Link: https://lore.kernel.org/r/20230708010407.3871346-6-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 6 +----- drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c | 10 +++------- drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h | 4 ++-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 3189b3b0a743..b918c9dc0afb 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -209,10 +209,6 @@ static void mdp5_kms_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct msm_gem_address_space *aspace = kms->aspace; - int i; - - for (i = 0; i < mdp5_kms->num_hwpipes; i++) - mdp5_pipe_destroy(mdp5_kms->hwpipes[i]); if (aspace) { aspace->mmu->funcs->detach(aspace->mmu); @@ -645,7 +641,7 @@ static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt, for (i = 0; i < cnt; i++) { struct mdp5_hw_pipe *hwpipe; - hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps); + hwpipe = mdp5_pipe_init(dev, pipes[i], offsets[i], caps); if (IS_ERR(hwpipe)) { ret = PTR_ERR(hwpipe); DRM_DEV_ERROR(dev->dev, "failed to construct pipe for %s (%d)\n", diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c index e4b8a789835a..99b2c30b1d48 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c @@ -151,17 +151,13 @@ int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe) return 0; } -void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe) -{ - kfree(hwpipe); -} - -struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe, +struct mdp5_hw_pipe *mdp5_pipe_init(struct drm_device *dev, + enum mdp5_pipe pipe, uint32_t reg_offset, uint32_t caps) { struct mdp5_hw_pipe *hwpipe; - hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL); + hwpipe = devm_kzalloc(dev->dev, sizeof(*hwpipe), GFP_KERNEL); if (!hwpipe) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h index cca67938cab2..452138821f60 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h @@ -39,8 +39,8 @@ int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane, struct mdp5_hw_pipe **r_hwpipe); int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe); -struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe, +struct mdp5_hw_pipe *mdp5_pipe_init(struct drm_device *dev, + enum mdp5_pipe pipe, uint32_t reg_offset, uint32_t caps); -void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe); #endif /* __MDP5_PIPE_H__ */ From 531d5313d934325c10721e1d22e352dc4c4a236e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:56 +0300 Subject: [PATCH 2220/7721] drm/msm/mdp5: use devres-managed allocation for SMP data Use devm_kzalloc to create SMP data structure. This allows us to remove corresponding kfree and drop mdp5_smp_destroy() function. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546172/ Link: https://lore.kernel.org/r/20230708010407.3871346-7-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 3 --- drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c | 19 ++++--------------- drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h | 1 - 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index b918c9dc0afb..4cfb1a8e903e 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -618,9 +618,6 @@ static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { int i; - if (mdp5_kms->smp) - mdp5_smp_destroy(mdp5_kms->smp); - for (i = 0; i < mdp5_kms->num_intfs; i++) kfree(mdp5_kms->intfs[i]); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index b68682c1b5bc..8b59562e29e2 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -370,23 +370,17 @@ void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) drm_modeset_unlock(&mdp5_kms->glob_state_lock); } -void mdp5_smp_destroy(struct mdp5_smp *smp) -{ - kfree(smp); -} struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg) { + struct drm_device *dev = mdp5_kms->dev; struct mdp5_smp_state *state; struct mdp5_global_state *global_state; struct mdp5_smp *smp; - int ret; - smp = kzalloc(sizeof(*smp), GFP_KERNEL); - if (unlikely(!smp)) { - ret = -ENOMEM; - goto fail; - } + smp = devm_kzalloc(dev->dev, sizeof(*smp), GFP_KERNEL); + if (unlikely(!smp)) + return ERR_PTR(-ENOMEM); smp->dev = mdp5_kms->dev; smp->blk_cnt = cfg->mmb_count; @@ -400,9 +394,4 @@ struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_ memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); return smp; -fail: - if (smp) - mdp5_smp_destroy(smp); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h index ba5618e136c3..d8b6a11413d9 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h @@ -68,7 +68,6 @@ struct mdp5_smp; struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg); -void mdp5_smp_destroy(struct mdp5_smp *smp); void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p); From 6de8288bf668ef4eba1258a523faf32a8d406d9e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:57 +0300 Subject: [PATCH 2221/7721] drm/msm/mdp5: use devres-managed allocation for INTF data Use devm_kzalloc to create INTF data structure. This allows us to remove corresponding kfree() call. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546163/ Link: https://lore.kernel.org/r/20230708010407.3871346-8-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 4cfb1a8e903e..48f447f4e183 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -616,11 +616,6 @@ static int mdp5_kms_init(struct drm_device *dev) static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { - int i; - - for (i = 0; i < mdp5_kms->num_intfs; i++) - kfree(mdp5_kms->intfs[i]); - if (mdp5_kms->rpm_enabled) pm_runtime_disable(&mdp5_kms->pdev->dev); @@ -741,7 +736,7 @@ static int interface_init(struct mdp5_kms *mdp5_kms) if (intf_types[i] == INTF_DISABLED) continue; - intf = kzalloc(sizeof(*intf), GFP_KERNEL); + intf = devm_kzalloc(dev->dev, sizeof(*intf), GFP_KERNEL); if (!intf) { DRM_DEV_ERROR(dev->dev, "failed to construct INTF%d\n", i); return -ENOMEM; From 6f235e3d6b1894a808cefdf32e45998a6459794f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:58 +0300 Subject: [PATCH 2222/7721] drm/msm/mdp5: use drmm-managed allocation for mdp5_crtc Change struct mdp5_crtc allocation to use drmm_crtc_alloc(). This removes the need to perform any actions on CRTC destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546169/ Link: https://lore.kernel.org/r/20230708010407.3871346-9-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 86036dd4e1e8..4a3db2ea1689 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -172,14 +173,11 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) drm_gem_object_put(val); } -static void mdp5_crtc_destroy(struct drm_crtc *crtc) +static void mdp5_crtc_flip_cleanup(struct drm_device *dev, void *ptr) { - struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_crtc *mdp5_crtc = ptr; - drm_crtc_cleanup(crtc); drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work); - - kfree(mdp5_crtc); } static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage) @@ -1147,7 +1145,6 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc) static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp5_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = mdp5_crtc_reset, .atomic_duplicate_state = mdp5_crtc_duplicate_state, @@ -1161,7 +1158,6 @@ static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { static const struct drm_crtc_funcs mdp5_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp5_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = mdp5_crtc_reset, .atomic_duplicate_state = mdp5_crtc_duplicate_state, @@ -1327,10 +1323,16 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, { struct drm_crtc *crtc = NULL; struct mdp5_crtc *mdp5_crtc; + int ret; - mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL); - if (!mdp5_crtc) - return ERR_PTR(-ENOMEM); + mdp5_crtc = drmm_crtc_alloc_with_planes(dev, struct mdp5_crtc, base, + plane, cursor_plane, + cursor_plane ? + &mdp5_crtc_no_lm_cursor_funcs : + &mdp5_crtc_funcs, + NULL); + if (IS_ERR(mdp5_crtc)) + return ERR_CAST(mdp5_crtc); crtc = &mdp5_crtc->base; @@ -1346,13 +1348,11 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true; - drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane, - cursor_plane ? - &mdp5_crtc_no_lm_cursor_funcs : - &mdp5_crtc_funcs, NULL); - drm_flip_work_init(&mdp5_crtc->unref_cursor_work, "unref cursor", unref_cursor_worker); + ret = drmm_add_action_or_reset(dev, mdp5_crtc_flip_cleanup, mdp5_crtc); + if (ret) + return ERR_PTR(ret); drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); From 669afee4a17ebb758889b1470b993efe9c66d5eb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:03:59 +0300 Subject: [PATCH 2223/7721] drm/msm/mdp5: use drmm-managed allocation for mdp5_encoder Change struct mdp5_encoder allocation to use drmm_encoder_alloc(). This removes the need to perform any actions on encoder destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546164/ Link: https://lore.kernel.org/r/20230708010407.3871346-10-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c | 29 +++----------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index 79d67c495780..8db97083e14d 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -16,17 +16,6 @@ static struct mdp5_kms *get_kms(struct drm_encoder *encoder) return to_mdp5_kms(to_mdp_kms(priv->kms)); } -static void mdp5_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp5_encoder); -} - -static const struct drm_encoder_funcs mdp5_encoder_funcs = { - .destroy = mdp5_encoder_destroy, -}; - static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -342,13 +331,11 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, struct mdp5_encoder *mdp5_encoder; int enc_type = (intf->type == INTF_DSI) ? DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS; - int ret; - mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL); - if (!mdp5_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp5_encoder = drmm_encoder_alloc(dev, struct mdp5_encoder, base, + NULL, enc_type, NULL); + if (IS_ERR(mdp5_encoder)) + return ERR_CAST(mdp5_encoder); encoder = &mdp5_encoder->base; mdp5_encoder->ctl = ctl; @@ -356,15 +343,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, spin_lock_init(&mdp5_encoder->intf_lock); - drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL); - drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs); return encoder; - -fail: - if (encoder) - mdp5_encoder_destroy(encoder); - - return ERR_PTR(ret); } From 54f1fbcb47d45bbd9737cd0115e44fd80acf4073 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:04:01 +0300 Subject: [PATCH 2224/7721] drm/msm/mdp4: use bulk regulators API for LCDC encoder Switch mdp4_lcdc_encoder to using regulator_bulk_* API instead of enumerating regulators by hand. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546173/ Link: https://lore.kernel.org/r/20230708010407.3871346-12-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 10eb3e5b218e..67c118bb30ca 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -18,7 +18,7 @@ struct mdp4_lcdc_encoder { struct drm_panel *panel; struct clk *lcdc_clk; unsigned long int pixclock; - struct regulator *regs[3]; + struct regulator_bulk_data regs[3]; bool enabled; uint32_t bsc; }; @@ -271,12 +271,10 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) { - struct drm_device *dev = encoder->dev; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = to_mdp4_lcdc_encoder(encoder); struct mdp4_kms *mdp4_kms = get_kms(encoder); struct drm_panel *panel; - int i, ret; if (WARN_ON(!mdp4_lcdc_encoder->enabled)) return; @@ -301,11 +299,8 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk); - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_disable(mdp4_lcdc_encoder->regs[i]); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to disable regulator: %d\n", ret); - } + regulator_bulk_disable(ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); mdp4_lcdc_encoder->enabled = false; } @@ -319,7 +314,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) struct mdp4_kms *mdp4_kms = get_kms(encoder); struct drm_panel *panel; uint32_t config; - int i, ret; + int ret; if (WARN_ON(mdp4_lcdc_encoder->enabled)) return; @@ -339,11 +334,10 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) mdp4_crtc_set_config(encoder->crtc, config); mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0); - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_enable(mdp4_lcdc_encoder->regs[i]); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to enable regulator: %d\n", ret); - } + ret = regulator_bulk_enable(ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); + if (ret) + DRM_DEV_ERROR(dev->dev, "failed to enable regulators: %d\n", ret); DBG("setting lcdc_clk=%lu", pc); ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc); @@ -385,7 +379,6 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, { struct drm_encoder *encoder = NULL; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder; - struct regulator *reg; int ret; mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL); @@ -411,29 +404,15 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, } /* TODO: different regulators in other cases? */ - reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret); - goto fail; - } - mdp4_lcdc_encoder->regs[0] = reg; + mdp4_lcdc_encoder->regs[0].supply = "lvds-vccs-3p3v"; + mdp4_lcdc_encoder->regs[1].supply = "lvds-vccs-3p3v"; + mdp4_lcdc_encoder->regs[2].supply = "lvds-vdda"; - reg = devm_regulator_get(dev->dev, "lvds-pll-vdda"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret); + ret = devm_regulator_bulk_get(dev->dev, + ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); + if (ret) goto fail; - } - mdp4_lcdc_encoder->regs[1] = reg; - - reg = devm_regulator_get(dev->dev, "lvds-vdda"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-vdda: %d\n", ret); - goto fail; - } - mdp4_lcdc_encoder->regs[2] = reg; return encoder; From 783ad6e6312fe28a005a3378128cdbbaab211527 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:04:02 +0300 Subject: [PATCH 2225/7721] drm/msm/mdp4: use drmm-managed allocation for mdp4_crtc Change struct mdp4_crtc allocation to use drmm_crtc_alloc(). This removes the need to perform any actions on CRTC destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546184/ Link: https://lore.kernel.org/r/20230708010407.3871346-13-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 169f9de4a12a..5e5c31b44a8a 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -123,16 +124,6 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) drm_gem_object_put(val); } -static void mdp4_crtc_destroy(struct drm_crtc *crtc) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - - drm_crtc_cleanup(crtc); - drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); - - kfree(mdp4_crtc); -} - /* statically (for now) map planes to mixer stage (z-order): */ static const int idxs[] = { [VG1] = 1, @@ -475,7 +466,6 @@ static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) static const struct drm_crtc_funcs mdp4_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp4_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .cursor_set = mdp4_crtc_cursor_set, .cursor_move = mdp4_crtc_cursor_move, @@ -616,6 +606,13 @@ static const char *dma_names[] = { "DMA_P", "DMA_S", "DMA_E", }; +static void mdp4_crtc_flip_cleanup(struct drm_device *dev, void *ptr) +{ + struct mdp4_crtc *mdp4_crtc = ptr; + + drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); +} + /* initialize crtc */ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id, int ovlp_id, @@ -623,10 +620,13 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, { struct drm_crtc *crtc = NULL; struct mdp4_crtc *mdp4_crtc; + int ret; - mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL); - if (!mdp4_crtc) - return ERR_PTR(-ENOMEM); + mdp4_crtc = drmm_crtc_alloc_with_planes(dev, struct mdp4_crtc, base, + plane, NULL, + &mdp4_crtc_funcs, NULL); + if (IS_ERR(mdp4_crtc)) + return ERR_CAST(mdp4_crtc); crtc = &mdp4_crtc->base; @@ -648,9 +648,10 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, drm_flip_work_init(&mdp4_crtc->unref_cursor_work, "unref cursor", unref_cursor_worker); + ret = drmm_add_action_or_reset(dev, mdp4_crtc_flip_cleanup, mdp4_crtc); + if (ret) + return ERR_PTR(ret); - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs, - NULL); drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); return crtc; From e79571e8708bdcbd12c85ec0fdef3c6b99e34e0f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:04:03 +0300 Subject: [PATCH 2226/7721] drm/msm/mdp4: use drmm-managed allocation for mdp4_dsi_encoder Change struct mdp4_dsi_encoder allocation to use drmm_encoder_alloc(). This removes the need to perform any actions on this encoder destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546180/ Link: https://lore.kernel.org/r/20230708010407.3871346-14-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 39b8fe53c29d..74dafe7106be 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c @@ -26,18 +26,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(mdp4_dsi_encoder); -} - -static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = { - .destroy = mdp4_dsi_encoder_destroy, -}; - static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -148,28 +136,18 @@ static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = { /* initialize encoder */ struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_dsi_encoder *mdp4_dsi_encoder; - int ret; - mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL); - if (!mdp4_dsi_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_dsi_encoder = drmm_encoder_alloc(dev, struct mdp4_dsi_encoder, base, + NULL, DRM_MODE_ENCODER_DSI, NULL); + if (IS_ERR(mdp4_dsi_encoder)) + return ERR_CAST(mdp4_dsi_encoder); encoder = &mdp4_dsi_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs, - DRM_MODE_ENCODER_DSI, NULL); drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs); return encoder; - -fail: - if (encoder) - mdp4_dsi_encoder_destroy(encoder); - - return ERR_PTR(ret); } #endif /* CONFIG_DRM_MSM_DSI */ From 93d6e1b82b93df1a7e58cd511663197f1208a8b0 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:04:04 +0300 Subject: [PATCH 2227/7721] drm/msm/mdp4: use drmm-managed allocation for mdp4_dtv_encoder Change struct mdp4_dtv_encoder allocation to use drmm_encoder_alloc(). This removes the need to perform any actions on this encoder destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546178/ Link: https://lore.kernel.org/r/20230708010407.3871346-15-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c | 37 ++++--------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index 88645dbc3785..3b70764b48c4 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c @@ -25,17 +25,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_dtv_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp4_dtv_encoder); -} - -static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = { - .destroy = mdp4_dtv_encoder_destroy, -}; - static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -173,41 +162,29 @@ long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate) /* initialize encoder */ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_dtv_encoder *mdp4_dtv_encoder; - int ret; - mdp4_dtv_encoder = kzalloc(sizeof(*mdp4_dtv_encoder), GFP_KERNEL); - if (!mdp4_dtv_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_dtv_encoder = drmm_encoder_alloc(dev, struct mdp4_dtv_encoder, base, + NULL, DRM_MODE_ENCODER_TMDS, NULL); + if (IS_ERR(mdp4_dtv_encoder)) + return ERR_CAST(mdp4_dtv_encoder); encoder = &mdp4_dtv_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs); mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk"); if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get hdmi_clk\n"); - ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk); - goto fail; + return ERR_CAST(mdp4_dtv_encoder->hdmi_clk); } mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk"); if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get tv_clk\n"); - ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk); - goto fail; + return ERR_CAST(mdp4_dtv_encoder->mdp_clk); } return encoder; - -fail: - if (encoder) - mdp4_dtv_encoder_destroy(encoder); - - return ERR_PTR(ret); } From 2c24668cc068fc69bf3ffb32234c7e6e91184a82 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 04:04:05 +0300 Subject: [PATCH 2228/7721] drm/msm/mdp4: use drmm-managed allocation for mdp4_lcdc_encoder Change struct mdp4_lcdc_encoder allocation to use drmm_encoder_alloc(). This removes the need to perform any actions on this encoder destruction. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/546176/ Link: https://lore.kernel.org/r/20230708010407.3871346-16-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c | 36 ++++--------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 67c118bb30ca..576995ddce37 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -30,18 +30,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = - to_mdp4_lcdc_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp4_lcdc_encoder); -} - -static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = { - .destroy = mdp4_lcdc_encoder_destroy, -}; - /* this should probably be a helper: */ static struct drm_connector *get_connector(struct drm_encoder *encoder) { @@ -377,30 +365,26 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate) struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, struct device_node *panel_node) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder; int ret; - mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL); - if (!mdp4_lcdc_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_lcdc_encoder = drmm_encoder_alloc(dev, struct mdp4_lcdc_encoder, base, + NULL, DRM_MODE_ENCODER_LVDS, NULL); + if (IS_ERR(mdp4_lcdc_encoder)) + return ERR_CAST(mdp4_lcdc_encoder); mdp4_lcdc_encoder->panel_node = panel_node; encoder = &mdp4_lcdc_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs, - DRM_MODE_ENCODER_LVDS, NULL); drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs); /* TODO: do we need different pll in other cases? */ mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev); if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get lvds_clk\n"); - ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk); - goto fail; + return ERR_CAST(mdp4_lcdc_encoder->lcdc_clk); } /* TODO: different regulators in other cases? */ @@ -412,13 +396,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, ARRAY_SIZE(mdp4_lcdc_encoder->regs), mdp4_lcdc_encoder->regs); if (ret) - goto fail; + return ERR_PTR(ret); return encoder; - -fail: - if (encoder) - mdp4_lcdc_encoder_destroy(encoder); - - return ERR_PTR(ret); } From 52e36770b174948126416ecddbcb0da817bc3cfc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:36:00 +0100 Subject: [PATCH 2229/7721] dt-bindings: display/msm: qcom, sm8250-mdss: add DisplayPort controller node Document the DisplayPort controller node in MDSS binding, already used in DTS: sm8250-xiaomi-elish-boe.dtb: display-subsystem@ae00000: Unevaluated properties are not allowed ('displayport-controller@ae90000' was unexpected) Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Patchwork: https://patchwork.freedesktop.org/patch/566297/ Link: https://lore.kernel.org/r/20231107103600.27424-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/qcom,sm8250-mdss.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml index 994975909fea..51368cda7b2f 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml @@ -52,6 +52,16 @@ patternProperties: compatible: const: qcom,sm8250-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + items: + - const: qcom,sm8250-dp + - const: qcom,sm8350-dp + "^dsi@[0-9a-f]+$": type: object additionalProperties: true From 1cd83dfe9a584a0db2f9a7dc617d710123169feb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 15:20:17 +0100 Subject: [PATCH 2230/7721] dt-bindings: display/msm: qcom, sm8150-mdss: correct DSI PHY compatible Qualcomm SM8150 MDSS comes with a bit different 7nm DSI PHY with its own compatible. DTS already use it: sa8155p-adp.dtb: display-subsystem@ae00000: phy@ae94400:compatible:0: 'qcom,dsi-phy-7nm' was expected Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Patchwork: https://patchwork.freedesktop.org/patch/567178/ Link: https://lore.kernel.org/r/20231111142017.51922-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml index a2a8be7f64a9..c0d6a4fdff97 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml @@ -69,7 +69,7 @@ patternProperties: properties: compatible: - const: qcom,dsi-phy-7nm + const: qcom,dsi-phy-7nm-8150 unevaluatedProperties: false @@ -247,7 +247,7 @@ examples: }; dsi0_phy: phy@ae94400 { - compatible = "qcom,dsi-phy-7nm"; + compatible = "qcom,dsi-phy-7nm-8150"; reg = <0x0ae94400 0x200>, <0x0ae94600 0x280>, <0x0ae94900 0x260>; @@ -318,7 +318,7 @@ examples: }; dsi1_phy: phy@ae96400 { - compatible = "qcom,dsi-phy-7nm"; + compatible = "qcom,dsi-phy-7nm-8150"; reg = <0x0ae96400 0x200>, <0x0ae96600 0x280>, <0x0ae96900 0x260>; From c6721b3c6423d8a348ae885a0f4c85e14f9bf85c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Nov 2023 00:54:01 +0300 Subject: [PATCH 2231/7721] drm/msm/mdp4: flush vblank event on disable Flush queued events when disabling the crtc. This avoids timeouts when we come back and wait for dependencies (like the previous frame's flip_done). Fixes: c8afe684c95c ("drm/msm: basic KMS driver for snapdragon") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/569127/ Link: https://lore.kernel.org/r/20231127215401.4064128-1-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 5e5c31b44a8a..75f93e346282 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -260,6 +260,7 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); + unsigned long flags; DBG("%s", mdp4_crtc->name); @@ -272,6 +273,14 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); mdp4_disable(mdp4_kms); + if (crtc->state->event && !crtc->state->active) { + WARN_ON(mdp4_crtc->event); + spin_lock_irqsave(&mdp4_kms->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irqrestore(&mdp4_kms->dev->event_lock, flags); + } + mdp4_crtc->enabled = false; } From 25daacc60394d1c82b14b13ebfb87544e14a5f36 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:43:58 +0100 Subject: [PATCH 2232/7721] dt-bindings: display: msm: qcm2290-mdss: Use the non-deprecated DSI compat The "qcom,dsi-ctrl-6g-qcm2290" has been deprecated in commit 0c0f65c6dd44 ("dt-bindings: msm: dsi-controller-main: Add compatible strings for every current SoC"), but the example hasn't been updated to reflect that. Fix that. Fixes: 0c0f65c6dd44 ("dt-bindings: msm: dsi-controller-main: Add compatible strings for every current SoC") Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/569478/ Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-1-4cbb567743bb@linaro.org Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml index 5ad155612b6c..d71a8e09a798 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml @@ -56,7 +56,9 @@ patternProperties: properties: compatible: - const: qcom,dsi-ctrl-6g-qcm2290 + items: + - const: qcom,qcm2290-dsi-ctrl + - const: qcom,mdss-dsi-ctrl "^phy@[0-9a-f]+$": type: object @@ -136,7 +138,8 @@ examples: }; dsi@5e94000 { - compatible = "qcom,dsi-ctrl-6g-qcm2290"; + compatible = "qcom,qcm2290-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; reg = <0x05e94000 0x400>; reg-names = "dsi_ctrl"; From a1ed5860efd39cb6c7766a94badff0c7616df6f5 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:43:59 +0100 Subject: [PATCH 2233/7721] dt-bindings: display: msm: Add reg bus and rotator interconnects Apart from the already handled data bus (MAS_MDP_Pn<->DDR), there are other connection paths: - a path that connects rotator block to the DDR. - a path that needs to be handled to ensure MDSS register access functions properly, namely the "reg bus", a.k.a the CPU-MDSS CFG interconnect. Describe these paths to allow using them in device trees and in the driver. [Konrad: rework for one vs two MDP paths, update examples] Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/569480/ Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-2-4cbb567743bb@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/mdss-common.yaml | 18 ++++++++++++++---- .../display/msm/qcom,qcm2290-mdss.yaml | 14 ++++++++++---- .../bindings/display/msm/qcom,sc7180-mdss.yaml | 14 ++++++++++---- .../bindings/display/msm/qcom,sc7280-mdss.yaml | 14 ++++++++++---- .../bindings/display/msm/qcom,sm6115-mdss.yaml | 10 ++++++++++ .../bindings/display/msm/qcom,sm6125-mdss.yaml | 8 ++++++-- .../bindings/display/msm/qcom,sm6350-mdss.yaml | 8 ++++++-- .../bindings/display/msm/qcom,sm6375-mdss.yaml | 8 ++++++-- .../bindings/display/msm/qcom,sm8450-mdss.yaml | 13 ++++++++----- 9 files changed, 80 insertions(+), 27 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml index f69196e4cc76..c6305a6e0334 100644 --- a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml +++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml @@ -61,17 +61,27 @@ properties: ranges: true + # This is not a perfect description, but it's impossible to discern and match + # the entries like we do with interconnect-names interconnects: minItems: 1 items: - description: Interconnect path from mdp0 (or a single mdp) port to the data bus - description: Interconnect path from mdp1 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - minItems: 1 - items: - - const: mdp0-mem - - const: mdp1-mem + oneOf: + - minItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg + + - minItems: 2 + items: + - const: mdp0-mem + - const: mdp1-mem + - const: cpu-cfg resets: items: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml index d71a8e09a798..f0cdb5422688 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 2 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -98,8 +102,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>, + <&bimc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x420 0x2>, <&apps_smmu 0x421 0x0>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml index 3432a2407caa..7a0555b15ddf 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 1 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -106,8 +110,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x800 0x2>; ranges; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml index bbb727831fca..2947f27e0585 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 1 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -118,8 +122,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &cnoc2 SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x900 0x402>; ranges; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml index dde5c2acead5..309de1953c88 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml @@ -29,6 +29,16 @@ properties: iommus: maxItems: 2 + interconnects: + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus + + interconnect-names: + items: + - const: mdp0-mem + - const: cpu-cfg + patternProperties: "^display-controller@[0-9a-f]+$": type: object diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml index 671c2c2aa896..3deb9dc81c9c 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml index e1dcb453762e..c9ba1fae8042 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml index b15c3950f09d..8e8a288d318c 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml index 001b26e65301..747a2e9665f4 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml @@ -30,10 +30,10 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + maxItems: 3 interconnect-names: - maxItems: 2 + maxItems: 3 patternProperties: "^display-controller@[0-9a-f]+$": @@ -91,9 +91,12 @@ examples: reg = <0x0ae00000 0x1000>; reg-names = "mdss"; - interconnects = <&mmss_noc MASTER_MDP_DISP 0 &mc_virt SLAVE_EBI1_DISP 0>, - <&mmss_noc MASTER_MDP_DISP 0 &mc_virt SLAVE_EBI1_DISP 0>; - interconnect-names = "mdp0-mem", "mdp1-mem"; + interconnects = <&mmss_noc MASTER_MDP_DISP &mc_virt SLAVE_EBI1_DISP>, + <&mmss_noc MASTER_MDP_DISP &mc_virt SLAVE_EBI1_DISP>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; From 82c2a5751227056a643455d080a389a4b0bfe184 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:43 -0800 Subject: [PATCH 2234/7721] drm/msm/dp: tie dp_display_irq_handler() with dp driver Currently the dp_display_request_irq() is executed at msm_dp_modeset_init() which ties irq registering to the DPU device's life cycle, while depending on resources that are released as the DP device is torn down. Move register DP driver irq handler to dp_display_probe() to have dp_display_irq_handler() IRQ tied with DP device. In addition, use platform_get_irq() to retrieve irq number from platform device directly. Changes in v5: -- reworded commit text as review comments at change #4 -- tear down component if failed at dp_display_request_irq() Changes in v4: -- delete dp->irq check at dp_display_request_irq() Changes in v3: -- move calling dp_display_irq_handler() to probe Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570069/ Link: https://lore.kernel.org/r/1701472789-25951-2-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 32 ++++++++++++----------------- drivers/gpu/drm/msm/dp/dp_display.h | 1 - 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 2ac9d61501c7..36bdba19467a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1183,26 +1183,18 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) return ret; } -int dp_display_request_irq(struct msm_dp *dp_display) +static int dp_display_request_irq(struct dp_display_private *dp) { int rc = 0; - struct dp_display_private *dp; + struct platform_device *pdev = dp->dp_display.pdev; - if (!dp_display) { - DRM_ERROR("invalid input\n"); - return -EINVAL; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - dp->irq = irq_of_parse_and_map(dp->dp_display.pdev->dev.of_node, 0); + dp->irq = platform_get_irq(pdev, 0); if (!dp->irq) { DRM_ERROR("failed to get irq\n"); return -EINVAL; } - rc = devm_request_irq(dp_display->drm_dev->dev, dp->irq, - dp_display_irq_handler, + rc = devm_request_irq(&pdev->dev, dp->irq, dp_display_irq_handler, IRQF_TRIGGER_HIGH, "dp_display_isr", dp); if (rc < 0) { DRM_ERROR("failed to request IRQ%u: %d\n", @@ -1277,13 +1269,21 @@ static int dp_display_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &dp->dp_display); + rc = dp_display_request_irq(dp); + if (rc) + goto err; + rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { DRM_ERROR("component add failed, rc=%d\n", rc); - dp_display_deinit_sub_modules(dp); + goto err; } return rc; + +err: + dp_display_deinit_sub_modules(dp); + return rc; } static void dp_display_remove(struct platform_device *pdev) @@ -1536,12 +1536,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, dp_priv = container_of(dp_display, struct dp_display_private, dp_display); - ret = dp_display_request_irq(dp_display); - if (ret) { - DRM_ERROR("request_irq failed, ret=%d\n", ret); - return ret; - } - ret = dp_display_get_next_bridge(dp_display); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 5e2fbd8318e9..b4a8be0abd9a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -36,7 +36,6 @@ struct msm_dp { int dp_display_set_plugged_cb(struct msm_dp *dp_display, hdmi_codec_plugged_cb fn, struct device *codec_dev); int dp_display_get_modes(struct msm_dp *dp_display); -int dp_display_request_irq(struct msm_dp *dp_display); bool dp_display_check_video_test(struct msm_dp *dp_display); int dp_display_get_test_bpp(struct msm_dp *dp_display); void dp_display_signal_audio_start(struct msm_dp *dp_display); From aa1131204e587535b9b48ed6d1b9187942bc939e Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:44 -0800 Subject: [PATCH 2235/7721] drm/msm/dp: rename is_connected with link_ready The is_connected flag is set to true after DP mainlink successfully finishes link training to enter into ST_MAINLINK_READY state rather than being set after the DP dongle is connected. Rename the is_connected flag with link_ready flag to match the state of DP driver's state machine. Changes in v5: -- reworded commit text according to review comments from change #4 Changes in v4: -- reworded commit text Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570063/ Link: https://lore.kernel.org/r/1701472789-25951-3-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 19 +++++++++---------- drivers/gpu/drm/msm/dp/dp_display.h | 2 +- drivers/gpu/drm/msm/dp/dp_drm.c | 14 +++++++------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 36bdba19467a..a3d7cb1943e2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -351,12 +351,11 @@ static void dp_display_send_hpd_event(struct msm_dp *dp_display) drm_helper_hpd_irq_event(connector->dev); } - static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool hpd) { - if ((hpd && dp->dp_display.is_connected) || - (!hpd && !dp->dp_display.is_connected)) { + if ((hpd && dp->dp_display.link_ready) || + (!hpd && !dp->dp_display.link_ready)) { drm_dbg_dp(dp->drm_dev, "HPD already %s\n", (hpd ? "on" : "off")); return 0; @@ -370,7 +369,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, dp->panel->dpcd, dp->panel->downstream_ports); } - dp->dp_display.is_connected = hpd; + dp->dp_display.link_ready = hpd; drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n", dp->dp_display.connector_type, hpd); @@ -912,7 +911,7 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display, dp_display->plugged_cb = fn; dp_display->codec_dev = codec_dev; - plugged = dp_display->is_connected; + plugged = dp_display->link_ready; dp_display_handle_plugged_change(dp_display, plugged); return 0; @@ -1343,16 +1342,16 @@ static int dp_pm_resume(struct device *dev) * also only signal audio when disconnected */ if (dp->link->sink_count) { - dp->dp_display.is_connected = true; + dp->dp_display.link_ready = true; } else { - dp->dp_display.is_connected = false; + dp->dp_display.link_ready = false; dp_display_handle_plugged_change(dp_display, false); } drm_dbg_dp(dp->drm_dev, "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", dp->dp_display.connector_type, dp->link->sink_count, - dp->dp_display.is_connected, dp->core_initialized, + dp->dp_display.link_ready, dp->core_initialized, dp->phy_initialized, dp_display->power_on); mutex_unlock(&dp->event_mutex); @@ -1740,8 +1739,8 @@ void dp_bridge_hpd_notify(struct drm_bridge *bridge, return; } - if (!dp_display->is_connected && status == connector_status_connected) + if (!dp_display->link_ready && status == connector_status_connected) dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); - else if (dp_display->is_connected && status == connector_status_disconnected) + else if (dp_display->link_ready && status == connector_status_disconnected) dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); } diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index b4a8be0abd9a..102f3507d824 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -17,7 +17,7 @@ struct msm_dp { struct drm_bridge *bridge; struct drm_connector *connector; struct drm_bridge *next_bridge; - bool is_connected; + bool link_ready; bool audio_enabled; bool power_on; unsigned int connector_type; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 21850a384b10..0efb501490cc 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -24,10 +24,10 @@ static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge) dp = to_dp_bridge(bridge)->dp_display; - drm_dbg_dp(dp->drm_dev, "is_connected = %s\n", - (dp->is_connected) ? "true" : "false"); + drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", + (dp->link_ready) ? "true" : "false"); - return (dp->is_connected) ? connector_status_connected : + return (dp->link_ready) ? connector_status_connected : connector_status_disconnected; } @@ -40,8 +40,8 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge, dp = to_dp_bridge(bridge)->dp_display; - drm_dbg_dp(dp->drm_dev, "is_connected = %s\n", - (dp->is_connected) ? "true" : "false"); + drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", + (dp->link_ready) ? "true" : "false"); /* * There is no protection in the DRM framework to check if the display @@ -55,7 +55,7 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge, * After that this piece of code can be removed. */ if (bridge->ops & DRM_BRIDGE_OP_HPD) - return (dp->is_connected) ? 0 : -ENOTCONN; + return (dp->link_ready) ? 0 : -ENOTCONN; return 0; } @@ -78,7 +78,7 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * dp = to_dp_bridge(bridge)->dp_display; /* pluggable case assumes EDID is read when HPD */ - if (dp->is_connected) { + if (dp->link_ready) { rc = dp_display_get_modes(dp); if (rc <= 0) { DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc); From e467e0bde881a667ccde9c7963f1042c01818059 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:45 -0800 Subject: [PATCH 2236/7721] drm/msm/dp: use drm_bridge_hpd_notify() to report HPD status changes Currently DP driver use drm_helper_hpd_irq_event(), bypassing drm bridge framework, to report HPD status changes to user space frame work. Replace it with drm_bridge_hpd_notify() since DP driver is part of drm bridge. Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570067/ Link: https://lore.kernel.org/r/1701472789-25951-4-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a3d7cb1943e2..148ac1629ef2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -340,26 +340,10 @@ static const struct component_ops dp_display_comp_ops = { .unbind = dp_display_unbind, }; -static void dp_display_send_hpd_event(struct msm_dp *dp_display) -{ - struct dp_display_private *dp; - struct drm_connector *connector; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - connector = dp->dp_display.connector; - drm_helper_hpd_irq_event(connector->dev); -} - static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool hpd) { - if ((hpd && dp->dp_display.link_ready) || - (!hpd && !dp->dp_display.link_ready)) { - drm_dbg_dp(dp->drm_dev, "HPD already %s\n", - (hpd ? "on" : "off")); - return 0; - } + struct drm_bridge *bridge = dp->dp_display.bridge; /* reset video pattern flag on disconnect */ if (!hpd) { @@ -373,7 +357,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n", dp->dp_display.connector_type, hpd); - dp_display_send_hpd_event(&dp->dp_display); + drm_bridge_hpd_notify(bridge, dp->dp_display.link_ready); return 0; } From 9179fd9596a47de3ff2947101751315ea00bd7ef Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:46 -0800 Subject: [PATCH 2237/7721] drm/msm/dp: move parser->parse() and dp_power_client_init() to probe Original both parser->parse() and dp_power_client_init() are done at dp_display_bind() since eDP population is done at binding time. In the preparation of having eDP population done at probe() time, move both function from dp_display_bind() to dp_display_probe(). Changes in v6: -- move dp_power_client_deinit() to remove() Changes in v5: -- explain why parser->parse() and dp_power_client_init() are moved to probe time -- tear down sub modules if failed Changes in v4: -- split this patch out of "incorporate pm_runtime framework into DP driver" patch Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570065/ Link: https://lore.kernel.org/r/1701472789-25951-5-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 148ac1629ef2..bae37e459d34 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -275,11 +275,6 @@ static int dp_display_bind(struct device *dev, struct device *master, dp->dp_display.drm_dev = drm; priv->dp[dp->id] = &dp->dp_display; - rc = dp->parser->parse(dp->parser); - if (rc) { - DRM_ERROR("device tree parsing failed\n"); - goto end; - } dp->drm_dev = drm; @@ -290,11 +285,6 @@ static int dp_display_bind(struct device *dev, struct device *master, goto end; } - rc = dp_power_client_init(dp->power); - if (rc) { - DRM_ERROR("Power client create failed\n"); - goto end; - } rc = dp_register_audio_driver(dev, dp->audio); if (rc) { @@ -327,7 +317,6 @@ static void dp_display_unbind(struct device *dev, struct device *master, of_dp_aux_depopulate_bus(dp->aux); - dp_power_client_deinit(dp->power); dp_unregister_audio_driver(dev, dp->audio); dp_aux_unregister(dp->aux); dp->drm_dev = NULL; @@ -1240,6 +1229,18 @@ static int dp_display_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + rc = dp->parser->parse(dp->parser); + if (rc) { + DRM_ERROR("device tree parsing failed\n"); + goto err; + } + + rc = dp_power_client_init(dp->power); + if (rc) { + DRM_ERROR("Power client create failed\n"); + goto err; + } + /* setup event q */ mutex_init(&dp->event_mutex); init_waitqueue_head(&dp->event_q); @@ -1274,6 +1275,7 @@ static void dp_display_remove(struct platform_device *pdev) struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); component_del(&pdev->dev, &dp_display_comp_ops); + dp_power_client_deinit(dp->power); dp_display_deinit_sub_modules(dp); platform_set_drvdata(pdev, NULL); From 5814b8bf086a1402a7fab4021aa58d4b84246db5 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:47 -0800 Subject: [PATCH 2238/7721] drm/msm/dp: incorporate pm_runtime framework into DP driver Currently DP driver is executed independent of PM runtime framework. This leads msm eDP panel can not being detected by edp_panel driver during generic_edp_panel_probe() due to AUX DPCD read failed at edp panel driver. Incorporate PM runtime framework into DP driver so that host controller's power and clocks are enable/disable through PM runtime mechanism. Once PM runtime framework is incorporated into DP driver, waking up device from power up path is not necessary. Hence remove it. After incorporating pm_runtime framework into eDP/DP driver, dp_pm_suspend() to handle power off both DP phy and controller during suspend and dp_pm_resume() to handle power on both DP phy and controller during resume are not necessary. Therefore both dp_pm_suspend() and dp_pm_resume() are dropped and replace with dp_pm_runtime_suspend() and dp_pm_runtime_resume() respectively. Changes in v9: -- silent compiler warning message at dp_power_init() and dp_power_deinit() with W1 flag Changes in v7: -- add comments to dp_pm_runtime_resume() -- add comments to dp_bridge_hpd_enable() -- delete dp->hpd_state = ST_DISCONNECTED from dp_bridge_hpd_notify() Changes in v6: -- delete dp_power_client_deinit(dp->power); -- remove if (!dp->dp_display.is_edp) condition checkout at plug_handle() -- remove if (!dp->dp_display.is_edp) condition checkout at unplug_handle() -- add IRQF_NO_AUTOEN to devm_request_irq() -- add enable_irq() and disable_irq() to pm_runtime_resume()/suspend() -- del dp->hpd_state = ST_DISCONNECTED from dp_bridge_hpd_disable() Changes in v5: -- remove pm_runtime_put_autosuspend feature, use pm_runtime_put_sync() -- squash add pm_runtime_force_suspend()/resume() patch into this patch Changes in v4: -- reworded commit text to explain why pm_framework is required for edp panel -- reworded commit text to explain autosuspend is choiced -- delete EV_POWER_PM_GET and PM_EV_POWER_PUT from changes #3 -- delete dp_display_pm_get() and dp_display_pm_Put() from changes #3 -- return value from pm_runtime_resume_and_get() directly -- check return value of devm_pm_runtime_enable() -- delete pm_runtime_xxx from dp_display_remove() -- drop dp_display_host_init() from EV_HPD_INIT_SETUP -- drop both dp_pm_prepare() and dp_pm_compete() from this change -- delete ST_SUSPENDED state -- rewording commit text to add more details regrading the purpose of this change Changes in v3: -- incorporate removing pm_runtime_xx() from dp_pwer.c to this patch -- use pm_runtime_resume_and_get() instead of pm_runtime_get() -- error checking pm_runtime_resume_and_get() return value -- add EV_POWER_PM_GET and PM_EV_POWER_PUT to handle HPD_GPIO case -- replace dp_pm_suspend() with pm_runtime_force_suspend() -- replace dp_pm_resume() with pm_runtime_force_resume() Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570073/ Link: https://lore.kernel.org/r/1701472789-25951-6-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_aux.c | 5 + drivers/gpu/drm/msm/dp/dp_display.c | 181 +++++++++++----------------- drivers/gpu/drm/msm/dp/dp_power.c | 32 +---- drivers/gpu/drm/msm/dp/dp_power.h | 11 -- 4 files changed, 77 insertions(+), 152 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 8e3b677f35e6..10b6eeb7bebf 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -291,6 +291,10 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, return -EINVAL; } + ret = pm_runtime_resume_and_get(dp_aux->dev); + if (ret) + return ret; + mutex_lock(&aux->mutex); if (!aux->initted) { ret = -EIO; @@ -364,6 +368,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, exit: mutex_unlock(&aux->mutex); + pm_runtime_put_sync(dp_aux->dev); return ret; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index bae37e459d34..05143ab9c6a4 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -49,7 +49,6 @@ enum { ST_CONNECTED, ST_DISCONNECT_PENDING, ST_DISPLAY_OFF, - ST_SUSPENDED, }; enum { @@ -309,10 +308,6 @@ static void dp_display_unbind(struct device *dev, struct device *master, struct dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv = dev_get_drvdata(master); - /* disable all HPD interrupts */ - if (dp->core_initialized) - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); - kthread_stop(dp->ev_tsk); of_dp_aux_depopulate_bus(dp->aux); @@ -542,6 +537,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) { u32 state; int ret; + struct platform_device *pdev = dp->dp_display.pdev; mutex_lock(&dp->event_mutex); @@ -549,7 +545,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -566,7 +562,13 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return 0; } - ret = dp_display_usbpd_configure_cb(&dp->dp_display.pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) { + DRM_ERROR("failed to pm_runtime_resume\n"); + return ret; + } + + ret = dp_display_usbpd_configure_cb(&pdev->dev); if (ret) { /* link train failed */ dp->hpd_state = ST_DISCONNECTED; } else { @@ -598,6 +600,7 @@ static void dp_display_handle_plugged_change(struct msm_dp *dp_display, static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) { u32 state; + struct platform_device *pdev = dp->dp_display.pdev; mutex_lock(&dp->event_mutex); @@ -648,6 +651,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp->dp_display.connector_type, state); /* uevent will complete disconnection part */ + pm_runtime_put_sync(&pdev->dev); mutex_unlock(&dp->event_mutex); return 0; } @@ -663,7 +667,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -1075,7 +1079,6 @@ static int hpd_event_thread(void *data) switch (todo->event_id) { case EV_HPD_INIT_SETUP: - dp_display_host_init(dp_priv); break; case EV_HPD_PLUG_INT: dp_hpd_plug_handle(dp_priv, todo->data); @@ -1167,7 +1170,9 @@ static int dp_display_request_irq(struct dp_display_private *dp) } rc = devm_request_irq(&pdev->dev, dp->irq, dp_display_irq_handler, - IRQF_TRIGGER_HIGH, "dp_display_isr", dp); + IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN, + "dp_display_isr", dp); + if (rc < 0) { DRM_ERROR("failed to request IRQ%u: %d\n", dp->irq, rc); @@ -1253,6 +1258,10 @@ static int dp_display_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &dp->dp_display); + rc = devm_pm_runtime_enable(&pdev->dev); + if (rc) + goto err; + rc = dp_display_request_irq(dp); if (rc) goto err; @@ -1275,115 +1284,52 @@ static void dp_display_remove(struct platform_device *pdev) struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); component_del(&pdev->dev, &dp_display_comp_ops); - dp_power_client_deinit(dp->power); dp_display_deinit_sub_modules(dp); platform_set_drvdata(pdev, NULL); } -static int dp_pm_resume(struct device *dev) +static int dp_pm_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; - int sink_count = 0; + struct dp_display_private *dp = dev_get_dp_display_private(dev); - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* start from disconnected state */ - dp->hpd_state = ST_DISCONNECTED; - - /* turn on dp ctrl/phy */ - dp_display_host_init(dp); - - if (dp_display->is_edp) - dp_catalog_ctrl_hpd_enable(dp->catalog); - - if (dp_catalog_link_is_connected(dp->catalog)) { - /* - * set sink to normal operation mode -- D0 - * before dpcd read - */ - dp_display_host_phy_init(dp); - dp_link_psm_config(dp->link, &dp->panel->link_info, false); - sink_count = drm_dp_read_sink_count(dp->aux); - if (sink_count < 0) - sink_count = 0; + disable_irq(dp->irq); + if (dp->dp_display.is_edp) { dp_display_host_phy_exit(dp); + dp_catalog_ctrl_hpd_disable(dp->catalog); } - - dp->link->sink_count = sink_count; - /* - * can not declared display is connected unless - * HDMI cable is plugged in and sink_count of - * dongle become 1 - * also only signal audio when disconnected - */ - if (dp->link->sink_count) { - dp->dp_display.link_ready = true; - } else { - dp->dp_display.link_ready = false; - dp_display_handle_plugged_change(dp_display, false); - } - - drm_dbg_dp(dp->drm_dev, - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", - dp->dp_display.connector_type, dp->link->sink_count, - dp->dp_display.link_ready, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - mutex_unlock(&dp->event_mutex); + dp_display_host_deinit(dp); return 0; } -static int dp_pm_suspend(struct device *dev) +static int dp_pm_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; + struct dp_display_private *dp = dev_get_dp_display_private(dev); - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* mainlink enabled */ - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) - dp_ctrl_off_link_stream(dp->ctrl); - - dp_display_host_phy_exit(dp); - - /* host_init will be called at pm_resume */ - dp_display_host_deinit(dp); - - dp->hpd_state = ST_SUSPENDED; - - drm_dbg_dp(dp->drm_dev, - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - mutex_unlock(&dp->event_mutex); + /* + * for eDP, host cotroller, HPD block and PHY are enabled here + * but with HPD irq disabled + * + * for DP, only host controller is enabled here. + * HPD block is enabled at dp_bridge_hpd_enable() + * PHY will be enabled at plugin handler later + */ + dp_display_host_init(dp); + if (dp->dp_display.is_edp) { + dp_catalog_ctrl_hpd_enable(dp->catalog); + dp_display_host_phy_init(dp); + } + enable_irq(dp->irq); return 0; } static const struct dev_pm_ops dp_pm_ops = { - .suspend = dp_pm_suspend, - .resume = dp_pm_resume, + SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver dp_display_driver = { @@ -1466,10 +1412,6 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) aux_bus = of_get_child_by_name(dev->of_node, "aux-bus"); if (aux_bus && dp->is_edp) { - dp_display_host_init(dp_priv); - dp_catalog_ctrl_hpd_enable(dp_priv->catalog); - dp_display_host_phy_init(dp_priv); - /* * The code below assumes that the panel will finish probing * by the time devm_of_dp_aux_populate_ep_devices() returns. @@ -1566,6 +1508,11 @@ void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, dp_hpd_plug_handle(dp_display, 0); mutex_lock(&dp_display->event_mutex); + if (pm_runtime_resume_and_get(&dp->pdev->dev)) { + DRM_ERROR("failed to pm_runtime_resume\n"); + mutex_unlock(&dp_display->event_mutex); + return; + } state = dp_display->hpd_state; if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) { @@ -1630,10 +1577,9 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, mutex_lock(&dp_display->event_mutex); state = dp_display->hpd_state; - if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) { - mutex_unlock(&dp_display->event_mutex); - return; - } + if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) + drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n", + dp->connector_type, state); dp_display_disable(dp_display); @@ -1646,6 +1592,8 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, } drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); + + pm_runtime_put_sync(&dp->pdev->dev); mutex_unlock(&dp_display->event_mutex); } @@ -1684,7 +1632,21 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge) struct msm_dp *dp_display = dp_bridge->dp_display; struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display); + /* + * this is for external DP with hpd irq enabled case, + * step-1: dp_pm_runtime_resume() enable dp host only + * step-2: enable hdp block and have hpd irq enabled here + * step-3: waiting for plugin irq while phy is not initialized + * step-4: DP PHY is initialized at plugin handler before link training + * + */ mutex_lock(&dp->event_mutex); + if (pm_runtime_resume_and_get(&dp_display->pdev->dev)) { + DRM_ERROR("failed to resume power\n"); + mutex_unlock(&dp->event_mutex); + return; + } + dp_catalog_ctrl_hpd_enable(dp->catalog); /* enable HDP interrupts */ @@ -1706,6 +1668,8 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) dp_catalog_ctrl_hpd_disable(dp->catalog); dp_display->internal_hpd = false; + + pm_runtime_put_sync(&dp_display->pdev->dev); mutex_unlock(&dp->event_mutex); } @@ -1720,11 +1684,6 @@ void dp_bridge_hpd_notify(struct drm_bridge *bridge, if (dp_display->internal_hpd) return; - if (!dp->core_initialized) { - drm_dbg_dp(dp->drm_dev, "not initialized\n"); - return; - } - if (!dp_display->link_ready && status == connector_status_connected) dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); else if (dp_display->link_ready && status == connector_status_disconnected) diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c index 5cb84ca40e9e..c4843dd69f47 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.c +++ b/drivers/gpu/drm/msm/dp/dp_power.c @@ -152,45 +152,17 @@ int dp_power_client_init(struct dp_power *dp_power) power = container_of(dp_power, struct dp_power_private, dp_power); - pm_runtime_enable(power->dev); - return dp_power_clk_init(power); } -void dp_power_client_deinit(struct dp_power *dp_power) -{ - struct dp_power_private *power; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - pm_runtime_disable(power->dev); -} - int dp_power_init(struct dp_power *dp_power) { - int rc = 0; - struct dp_power_private *power = NULL; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - pm_runtime_get_sync(power->dev); - - rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); - if (rc) - pm_runtime_put_sync(power->dev); - - return rc; + return dp_power_clk_enable(dp_power, DP_CORE_PM, true); } int dp_power_deinit(struct dp_power *dp_power) { - struct dp_power_private *power; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - dp_power_clk_enable(dp_power, DP_CORE_PM, false); - pm_runtime_put_sync(power->dev); - return 0; + return dp_power_clk_enable(dp_power, DP_CORE_PM, false); } struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser) diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h index a3dec200785e..55ada51edb57 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.h +++ b/drivers/gpu/drm/msm/dp/dp_power.h @@ -80,17 +80,6 @@ int dp_power_clk_enable(struct dp_power *power, enum dp_pm_type pm_type, */ int dp_power_client_init(struct dp_power *power); -/** - * dp_power_clinet_deinit() - de-initialize clock and regulator modules - * - * @power: instance of power module - * return: 0 for success, error for failure. - * - * This API will de-initialize the DisplayPort's clocks and regulator - * modules. - */ -void dp_power_client_deinit(struct dp_power *power); - /** * dp_power_get() - configure and get the DisplayPort power module data * From 2b3aabc9caa2452653ef22bdfd15af65f0dff164 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:48 -0800 Subject: [PATCH 2239/7721] drm/msm/dp: delete EV_HPD_INIT_SETUP EV_HPD_INIT_SETUP flag is used to trigger the initialization of external DP host controller. Since external DP host controller initialization had been incorporated into pm_runtime_resume(), this flag became obsolete. msm_dp_irq_postinstall() which triggers EV_HPD_INIT_SETUP event is obsoleted accordingly. Changes in v4: -- reworded commit text -- drop EV_HPD_INIT_SETUP -- drop msm_dp_irq_postinstall() Changes in v3: -- drop EV_HPD_INIT_SETUP and msm_dp_irq_postinstall() Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570075/ Link: https://lore.kernel.org/r/1701472789-25951-7-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 ---- drivers/gpu/drm/msm/dp/dp_display.c | 16 ---------------- drivers/gpu/drm/msm/msm_drv.h | 5 ----- 3 files changed, 25 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index babec724c76a..9b2efd7acc87 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -845,7 +845,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) { struct msm_drm_private *priv; struct dpu_kms *dpu_kms = to_dpu_kms(kms); - int i; if (!dpu_kms || !dpu_kms->dev) return -EINVAL; @@ -854,9 +853,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) if (!priv) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) - msm_dp_irq_postinstall(priv->dp[i]); - return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 05143ab9c6a4..50054f28e5b2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -54,7 +54,6 @@ enum { enum { EV_NO_EVENT, /* hpd events */ - EV_HPD_INIT_SETUP, EV_HPD_PLUG_INT, EV_IRQ_HPD_INT, EV_HPD_UNPLUG_INT, @@ -1078,8 +1077,6 @@ static int hpd_event_thread(void *data) spin_unlock_irqrestore(&dp_priv->event_lock, flag); switch (todo->event_id) { - case EV_HPD_INIT_SETUP: - break; case EV_HPD_PLUG_INT: dp_hpd_plug_handle(dp_priv, todo->data); break; @@ -1359,19 +1356,6 @@ void __exit msm_dp_unregister(void) platform_driver_unregister(&dp_display_driver); } -void msm_dp_irq_postinstall(struct msm_dp *dp_display) -{ - struct dp_display_private *dp; - - if (!dp_display) - return; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - if (!dp_display->is_edp) - dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0); -} - bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) { struct dp_display_private *dp; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 628ef3e663ea..a205127ccc93 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -386,7 +386,6 @@ int __init msm_dp_register(void); void __exit msm_dp_unregister(void); int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder); -void msm_dp_irq_postinstall(struct msm_dp *dp_display); void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display); bool msm_dp_wide_bus_available(const struct msm_dp *dp_display); @@ -406,10 +405,6 @@ static inline int msm_dp_modeset_init(struct msm_dp *dp_display, return -EINVAL; } -static inline void msm_dp_irq_postinstall(struct msm_dp *dp_display) -{ -} - static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display) { } From e2969ee302522b0b29506a9d17cebb5b02b5ce5c Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 1 Dec 2023 15:19:49 -0800 Subject: [PATCH 2240/7721] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe() Currently eDP population is done at msm_dp_modeset_init() which happen at binding time. Move eDP population to be done at display probe time so that probe deferral cases can be handled effectively. wait_for_hpd_asserted callback is added during drm_dp_aux_init() to ensure eDP's HPD is up before proceeding eDP population. Changes in v5: -- inline dp_display_auxbus_population() and delete it Changes in v4: -- delete duplicate initialize code to dp_aux before drm_dp_aux_register() -- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline the function -- not initialize rc = 0 Changes in v3: -- add done_probing callback into devm_of_dp_aux_populate_bus() Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570074/ Link: https://lore.kernel.org/r/1701472789-25951-8-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_aux.c | 34 +++++++++++++---- drivers/gpu/drm/msm/dp/dp_display.c | 59 ++++++++++++----------------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 10b6eeb7bebf..03f4951c49f4 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -479,7 +479,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux) int dp_aux_register(struct drm_dp_aux *dp_aux) { - struct dp_aux_private *aux; int ret; if (!dp_aux) { @@ -487,12 +486,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux) return -EINVAL; } - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - aux->dp_aux.name = "dpu_dp_aux"; - aux->dp_aux.dev = aux->dev; - aux->dp_aux.transfer = dp_aux_transfer; - ret = drm_dp_aux_register(&aux->dp_aux); + ret = drm_dp_aux_register(dp_aux); if (ret) { DRM_ERROR("%s: failed to register drm aux: %d\n", __func__, ret); @@ -507,6 +501,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux) drm_dp_aux_unregister(dp_aux); } +static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux, + unsigned long wait_us) +{ + int ret; + struct dp_aux_private *aux; + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + pm_runtime_get_sync(aux->dev); + ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog); + pm_runtime_put_sync(aux->dev); + + return ret; +} + struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, bool is_edp) { @@ -530,6 +539,17 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, aux->catalog = catalog; aux->retry_cnt = 0; + /* + * Use the drm_dp_aux_init() to use the aux adapter + * before registering AUX with the DRM device so that + * msm eDP panel can be detected by generic_dep_panel_probe(). + */ + aux->dp_aux.name = "dpu_dp_aux"; + aux->dp_aux.dev = dev; + aux->dp_aux.transfer = dp_aux_transfer; + aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted; + drm_dp_aux_init(&aux->dp_aux); + return &aux->dp_aux; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 50054f28e5b2..3a360c87e2dc 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1198,6 +1198,17 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde return NULL; } +static int dp_auxbus_done_probe(struct drm_dp_aux *aux) +{ + int rc; + + rc = component_add(aux->dev, &dp_display_comp_ops); + if (rc) + DRM_ERROR("eDP component add failed, rc=%d\n", rc); + + return rc; +} + static int dp_display_probe(struct platform_device *pdev) { int rc = 0; @@ -1263,10 +1274,18 @@ static int dp_display_probe(struct platform_device *pdev) if (rc) goto err; - rc = component_add(&pdev->dev, &dp_display_comp_ops); - if (rc) { - DRM_ERROR("component add failed, rc=%d\n", rc); - goto err; + if (dp->dp_display.is_edp) { + rc = devm_of_dp_aux_populate_bus(dp->aux, dp_auxbus_done_probe); + if (rc) { + DRM_ERROR("eDP auxbus population failed, rc=%d\n", rc); + goto err; + } + } else { + rc = component_add(&pdev->dev, &dp_display_comp_ops); + if (rc) { + DRM_ERROR("component add failed, rc=%d\n", rc); + goto err; + } } return rc; @@ -1282,7 +1301,6 @@ static void dp_display_remove(struct platform_device *pdev) component_del(&pdev->dev, &dp_display_comp_ops); dp_display_deinit_sub_modules(dp); - platform_set_drvdata(pdev, NULL); } @@ -1388,29 +1406,8 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) { int rc; struct dp_display_private *dp_priv; - struct device_node *aux_bus; - struct device *dev; dp_priv = container_of(dp, struct dp_display_private, dp_display); - dev = &dp_priv->dp_display.pdev->dev; - aux_bus = of_get_child_by_name(dev->of_node, "aux-bus"); - - if (aux_bus && dp->is_edp) { - /* - * The code below assumes that the panel will finish probing - * by the time devm_of_dp_aux_populate_ep_devices() returns. - * This isn't a great assumption since it will fail if the - * panel driver is probed asynchronously but is the best we - * can do without a bigger driver reorganization. - */ - rc = of_dp_aux_populate_bus(dp_priv->aux, NULL); - of_node_put(aux_bus); - if (rc) - goto error; - } else if (dp->is_edp) { - DRM_ERROR("eDP aux_bus not found\n"); - return -ENODEV; - } /* * External bridges are mandatory for eDP interfaces: one has to @@ -1423,17 +1420,9 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) if (!dp->is_edp && rc == -ENODEV) return 0; - if (!rc) { + if (!rc) dp->next_bridge = dp_priv->parser->next_bridge; - return 0; - } -error: - if (dp->is_edp) { - of_dp_aux_depopulate_bus(dp_priv->aux); - dp_display_host_phy_exit(dp_priv); - dp_display_host_deinit(dp_priv); - } return rc; } From 0b414c731432917c83353c446e60ee838c9a9cfd Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 30 Nov 2023 11:21:18 -0800 Subject: [PATCH 2241/7721] drm/msm/dpu: Correct UBWC settings for sc8280xp The UBWC settings need to match between the display and GPU. When we updated the GPU settings, we forgot to make the corresponding update on the display side. Reported-by: Steev Klimaszewski Fixes: 07e6de738aa6 ("drm/msm/a690: Fix reg values for a690") Signed-off-by: Rob Clark Tested-by: Steev Klimaszewski Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/569817/ Link: https://lore.kernel.org/r/20231130192119.32538-1-robdclark@gmail.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_mdss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 6865db1e3ce8..29bb38f0bb2c 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -545,7 +545,7 @@ static const struct msm_mdss_data sc8280xp_data = { .ubwc_dec_version = UBWC_4_0, .ubwc_swizzle = 6, .ubwc_static = 1, - .highest_bank_bit = 2, + .highest_bank_bit = 3, .macrotile_mode = 1, }; From 9cad81143ef000695b32e92048d8ec0481e5ea3d Mon Sep 17 00:00:00 2001 From: Paloma Arellano Date: Thu, 30 Nov 2023 14:47:37 -0800 Subject: [PATCH 2242/7721] drm/msm/dpu: Capture dpu snapshot when frame_done_timer timeouts Trigger a devcoredump to dump dpu registers and capture the drm atomic state when the frame_done_timer timeouts. v2: Optimize the format in which frame_done_timeout_cnt is incremented v3: Describe parameter frame_done_timeout_cnt in dpu_encoder_virt Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312010225.2OJWLKmA-lkp@intel.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Paloma Arellano Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/569834/ Link: https://lore.kernel.org/r/20231130224740.24383-1-quic_parellan@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 1cf7ff6caff4..1c3560e1c625 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -151,6 +151,8 @@ enum dpu_enc_rc_states { * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data * @frame_done_timeout_ms: frame done timeout in ms + * @frame_done_timeout_cnt: atomic counter tracking the number of frame + * done timeouts * @frame_done_timer: watchdog timer for frame done event * @disp_info: local copy of msm_display_info struct * @idle_pc_supported: indicate if idle power collaps is supported @@ -191,6 +193,7 @@ struct dpu_encoder_virt { void *crtc_frame_event_cb_data; atomic_t frame_done_timeout_ms; + atomic_t frame_done_timeout_cnt; struct timer_list frame_done_timer; struct msm_display_info disp_info; @@ -1204,6 +1207,8 @@ static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc, dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc); + atomic_set(&dpu_enc->frame_done_timeout_cnt, 0); + if (disp_info->intf_type == INTF_DP) dpu_enc->wide_bus_en = msm_dp_wide_bus_available(priv->dp[index]); else if (disp_info->intf_type == INTF_DSI) @@ -2115,11 +2120,12 @@ static int _dpu_encoder_status_show(struct seq_file *s, void *data) for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - seq_printf(s, "intf:%d wb:%d vsync:%8d underrun:%8d ", + seq_printf(s, "intf:%d wb:%d vsync:%8d underrun:%8d frame_done_cnt:%d", phys->hw_intf ? phys->hw_intf->idx - INTF_0 : -1, phys->hw_wb ? phys->hw_wb->idx - WB_0 : -1, atomic_read(&phys->vsync_cnt), - atomic_read(&phys->underrun_cnt)); + atomic_read(&phys->underrun_cnt), + atomic_read(&dpu_enc->frame_done_timeout_cnt)); seq_printf(s, "mode: %s\n", dpu_encoder_helper_get_intf_type(phys->intf_mode)); } @@ -2341,6 +2347,9 @@ static void dpu_encoder_frame_done_timeout(struct timer_list *t) DPU_ERROR_ENC(dpu_enc, "frame done timeout\n"); + if (atomic_inc_return(&dpu_enc->frame_done_timeout_cnt) == 1) + msm_disp_snapshot_state(drm_enc->dev); + event = DPU_ENCODER_FRAME_EVENT_ERROR; trace_dpu_enc_frame_done_timeout(DRMID(drm_enc), event); dpu_enc->crtc_frame_event_cb(dpu_enc->crtc_frame_event_cb_data, event); @@ -2392,6 +2401,7 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, goto fail; atomic_set(&dpu_enc->frame_done_timeout_ms, 0); + atomic_set(&dpu_enc->frame_done_timeout_cnt, 0); timer_setup(&dpu_enc->frame_done_timer, dpu_encoder_frame_done_timeout, 0); From 7cc2621f16b644bb7af37987cb471311641a9e56 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Nov 2023 16:35:01 -0800 Subject: [PATCH 2243/7721] drm/msm/dpu: Add missing safe_lut_tbl in sc8180x catalog Similar to SC8280XP, the misconfigured SAFE logic causes rather significant delays in __arm_smmu_tlb_sync(), resulting in poor performance for things such as USB. Introduce appropriate SAFE values for SC8180X to correct this. Fixes: f3af2d6ee9ab ("drm/msm/dpu: Add SC8180x to hw catalog") Signed-off-by: Bjorn Andersson Reported-by: Anton Bambura Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/569840/ Link: https://lore.kernel.org/r/20231130-sc8180x-dpu-safe-lut-v1-1-a8a6bbac36b8@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index e07f4c8c25b9..9ffc8804a6fc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -367,6 +367,7 @@ static const struct dpu_perf_cfg sc8180x_perf_data = { .min_llcc_ib = 800000, .min_dram_ib = 800000, .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfff0, 0xf000, 0xffff}, .qos_lut_tbl = { {.nentry = ARRAY_SIZE(sc7180_qos_linear), .entries = sc7180_qos_linear From 3d07a411b4faaf2b498760ccf12888f8de529de0 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 20 Jun 2023 13:43:20 +0200 Subject: [PATCH 2244/7721] drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks This helper has been introduced to avoid programmer errors (missing _put calls leading to dangling refcnt) when using pm_runtime_get, use it. While at it, start checking the return value. Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Fixes: 5c8290284402 ("drm/msm/dsi: Split PHY drivers to separate files") Patchwork: https://patchwork.freedesktop.org/patch/543350/ Link: https://lore.kernel.org/r/20230620-topic-dsiphy_rpm-v2-1-a11a751f34f0@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 05621e5e7d63..b6314bb66d2f 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -516,7 +516,9 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) struct device *dev = &phy->pdev->dev; int ret; - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; ret = clk_prepare_enable(phy->ahb_clk); if (ret) { From 6ab502bc1cf3147ea1d8540d04b83a7a4cb6d1f1 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 20 Jun 2023 13:43:21 +0200 Subject: [PATCH 2245/7721] drm/msm/dsi: Enable runtime PM Some devices power the DSI PHY/PLL through a power rail that we model as a GENPD. Enable runtime PM to make it suspendable. Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/543352/ Link: https://lore.kernel.org/r/20230620-topic-dsiphy_rpm-v2-2-a11a751f34f0@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index b6314bb66d2f..e49ebd9f6326 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -691,6 +691,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(phy->ahb_clk), "Unable to get ahb clk\n"); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + /* PLL init will call into clk_register which requires * register access, so we need to enable power and ahb clock. */ From 94da379dba88c4cdd562bad21c9ba5656e5ed5df Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 24 Sep 2023 20:31:01 +0200 Subject: [PATCH 2246/7721] ARM: dts: qcom: sdx65: correct PCIe EP phy-names Qualcomm PCIe endpoint bindings expect phy-names to be "pciephy": arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dtb: pcie-ep@1c00000: phy-names:0: 'pciephy' was expected Fixes: 9c0bb38414a4 ("ARM: dts: qcom: sdx65: Add support for PCIe EP") Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Reviewed-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230924183103.49487-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx65.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index 726755c4f8a3..ab492c47baaa 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -333,7 +333,7 @@ pcie_ep: pcie-ep@1c00000 { power-domains = <&gcc PCIE_GDSC>; phys = <&pcie_phy>; - phy-names = "pcie-phy"; + phy-names = "pciephy"; max-link-speed = <3>; num-lanes = <2>; From f64f653df2ef713359178c731bc8f89ff54014b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 24 Sep 2023 20:31:02 +0200 Subject: [PATCH 2247/7721] ARM: dts: qcom: sdx65: add missing GCC clocks The SDX65 GCC clock controller expects two required clocks: pcie_pipe_clk and usb3_phy_wrapper_gcc_usb30_pipe_clk. The first one is provided by existing phy node, but second is not yet implemented. qcom-sdx65-mtp.dtb: clock-controller@100000: clocks: [[11, 0], [11, 1], [12]] is too short qcom-sdx65-mtp.dtb: clock-controller@100000: clock-names: ['bi_tcxo', 'bi_tcxo_ao', 'sleep_clk'] is too short Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230924183103.49487-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx65.dtsi | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index ab492c47baaa..0380caa5db6b 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -204,8 +204,16 @@ soc: soc { gcc: clock-controller@100000 { compatible = "qcom,gcc-sdx65"; reg = <0x00100000 0x001f7400>; - clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>; - clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk"; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&pcie_phy>, + <0>; + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "sleep_clk", + "pcie_pipe_clk", + "usb3_phy_wrapper_gcc_usb30_pipe_clk"; #power-domain-cells = <1>; #clock-cells = <1>; #reset-cells = <1>; From a900ad783f507cb396e402827052e70c0c565ae9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 24 Sep 2023 20:31:03 +0200 Subject: [PATCH 2248/7721] ARM: dts: qcom: sdx65: correct SPMI node name Node names should not have vendor prefixes: qcom-sdx65-mtp.dtb: qcom,spmi@c440000: $nodename:0: 'qcom,spmi@c440000' does not match '^spmi@.* Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230924183103.49487-3-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx65.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index 0380caa5db6b..40591a4da6a4 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -533,7 +533,7 @@ restart@c264000 { reg = <0x0c264000 0x1000>; }; - spmi_bus: qcom,spmi@c440000 { + spmi_bus: spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0xc440000 0xd00>, <0xc600000 0x2000000>, From 4d45d56e17348c6b6bb2bce126a4a5ea97b19900 Mon Sep 17 00:00:00 2001 From: Gokul Sriram Palanisamy Date: Mon, 25 Sep 2023 15:58:24 +0530 Subject: [PATCH 2249/7721] dt-bindings: clock: qcom,a53pll: add IPQ5018 compatible Add IPQ5018 compatible to A53 PLL bindings. Signed-off-by: Gokul Sriram Palanisamy Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230925102826.405446-2-quic_gokulsri@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,a53pll.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml index 9436266828af..5ca927a8b1d5 100644 --- a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,ipq5018-a53pll - qcom,ipq5332-a53pll - qcom,ipq6018-a53pll - qcom,ipq8074-a53pll From 50492f929486c044b43cb3e2c0e040aa9b61ea2b Mon Sep 17 00:00:00 2001 From: Gokul Sriram Palanisamy Date: Mon, 25 Sep 2023 15:58:25 +0530 Subject: [PATCH 2250/7721] clk: qcom: apss-ipq-pll: add support for IPQ5018 IPQ5018 APSS PLL is of type Stromer. Reuse Stromer Plus PLL offsets, add configuration values and the compatible. Co-developed-by: Sricharan Ramabadhran Signed-off-by: Sricharan Ramabadhran Signed-off-by: Gokul Sriram Palanisamy Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230925102826.405446-3-quic_gokulsri@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/apss-ipq-pll.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index 41279e5437a6..678b805f13d4 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -73,6 +73,20 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = { }, }; +static const struct alpha_pll_config ipq5018_pll_config = { + .l = 0x32, + .config_ctl_val = 0x4001075b, + .config_ctl_hi_val = 0x304, + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), + .early_output_mask = BIT(3), + .alpha_en_mask = BIT(24), + .status_val = 0x3, + .status_mask = GENMASK(10, 8), + .lock_det = BIT(2), + .test_ctl_hi_val = 0x00400003, +}; + static const struct alpha_pll_config ipq5332_pll_config = { .l = 0x2d, .config_ctl_val = 0x4001075b, @@ -129,6 +143,12 @@ struct apss_pll_data { const struct alpha_pll_config *pll_config; }; +static const struct apss_pll_data ipq5018_pll_data = { + .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, + .pll = &ipq_pll_stromer_plus, + .pll_config = &ipq5018_pll_config, +}; + static struct apss_pll_data ipq5332_pll_data = { .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, .pll = &ipq_pll_stromer_plus, @@ -195,6 +215,7 @@ static int apss_ipq_pll_probe(struct platform_device *pdev) } static const struct of_device_id apss_ipq_pll_match_table[] = { + { .compatible = "qcom,ipq5018-a53pll", .data = &ipq5018_pll_data }, { .compatible = "qcom,ipq5332-a53pll", .data = &ipq5332_pll_data }, { .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_data }, { .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_data }, From 3e4b53e04281ed3d9c7a4329c027097265c04d54 Mon Sep 17 00:00:00 2001 From: Gokul Sriram Palanisamy Date: Mon, 25 Sep 2023 15:58:26 +0530 Subject: [PATCH 2251/7721] arm64: dts: qcom: ipq5018: enable the CPUFreq support Add the APCS, A53 PLL, cpu-opp-table nodes to set the CPU frequency at 800MHz (idle) or 1.008GHz. Co-developed-by: Sricharan Ramabadhran Signed-off-by: Sricharan Ramabadhran Signed-off-by: Gokul Sriram Palanisamy Reviewed-by: Dmitry Baryshkov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230925102826.405446-4-quic_gokulsri@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 0b739077ed70..ae31bd72f0b7 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -5,6 +5,7 @@ * Copyright (c) 2023 The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -36,6 +37,8 @@ CPU0: cpu@0 { reg = <0x0>; enable-method = "psci"; next-level-cache = <&L2_0>; + clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; + operating-points-v2 = <&cpu_opp_table>; }; CPU1: cpu@1 { @@ -44,6 +47,8 @@ CPU1: cpu@1 { reg = <0x1>; enable-method = "psci"; next-level-cache = <&L2_0>; + clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; + operating-points-v2 = <&cpu_opp_table>; }; L2_0: l2-cache { @@ -54,6 +59,23 @@ L2_0: l2-cache { }; }; + cpu_opp_table: opp-table-cpu { + compatible = "operating-points-v2"; + opp-shared; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1100000>; + clock-latency-ns = <200000>; + }; + + opp-1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <1100000>; + clock-latency-ns = <200000>; + }; + }; + firmware { scm { compatible = "qcom,scm-ipq5018", "qcom,scm"; @@ -267,6 +289,24 @@ watchdog: watchdog@b017000 { clocks = <&sleep_clk>; }; + apcs_glb: mailbox@b111000 { + compatible = "qcom,ipq5018-apcs-apps-global", + "qcom,ipq6018-apcs-apps-global"; + reg = <0x0b111000 0x1000>; + #clock-cells = <1>; + clocks = <&a53pll>, <&xo_board_clk>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; + #mbox-cells = <1>; + }; + + a53pll: clock@b116000 { + compatible = "qcom,ipq5018-a53pll"; + reg = <0x0b116000 0x40>; + #clock-cells = <0>; + clocks = <&xo_board_clk>; + clock-names = "xo"; + }; + timer@b120000 { compatible = "arm,armv7-timer-mem"; reg = <0x0b120000 0x1000>; From 14259fcdaf72d3ce93ad9c2b12cc0e96ed5a0c4e Mon Sep 17 00:00:00 2001 From: Sridharan S N Date: Wed, 27 Sep 2023 15:01:30 +0530 Subject: [PATCH 2252/7721] dt-bindings: arm: qcom: drop the IPQ board types IPQ bootloaders do not need these information to select the the DTB blob. So dropping the board names from board section. Signed-off-by: Sridharan S N Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230927093130.4098385-1-quic_sridsn@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 88b84035e7b1..c0c7b282cb6d 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -91,24 +91,10 @@ description: | The 'board' element must be one of the following strings: adp - ap-al02-c2 - ap-al02-c6 - ap-al02-c7 - ap-al02-c8 - ap-al02-c9 - ap-mi01.2 - ap-mi01.3 - ap-mi01.6 - ap-mi01.9 cdp - cp01-c1 dragonboard - hk01 - hk10-c1 - hk10-c2 idp liquid - rdp432-c2 mtp qrd rb2 From 95053f6bc8ffca438a261400d7c06bd74e3f106e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Wed, 11 Oct 2023 18:33:15 +0200 Subject: [PATCH 2253/7721] ARM: dts: qcom: msm8974: Add watchdog node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add watchdog for MSM8974 platform. Signed-off-by: Matti Lehtimäki Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231011-msm8226-msm8974-watchdog-v1-3-2c472818fbce@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index b3a0a71c6369..f7d7e5d70f30 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -346,6 +346,14 @@ apcs: syscon@f9011000 { reg = <0xf9011000 0x1000>; }; + watchdog@f9017000 { + compatible = "qcom,apss-wdt-msm8974", "qcom,kpss-wdt"; + reg = <0xf9017000 0x1000>; + interrupts = , + ; + clocks = <&sleep_clk>; + }; + timer@f9020000 { #address-cells = <1>; #size-cells = <1>; From ec987b5efd59fdea4178d824d8ec4bbdf3019bdf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 12 Oct 2023 22:51:28 +0530 Subject: [PATCH 2254/7721] arm64: dts: qcom: sdm845: Add OPP table support to UFSHC UFS host controller, when scaling gears, should choose appropriate performance state of RPMh power domain controller along with clock frequency. So let's add the OPP table support to specify both clock frequency and RPMh performance states replacing the old "freq-table-hz" property. Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski [mani: Splitted pd change and used rpmhpd_opp_low_svs] Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231012172129.65172-5-manivannan.sadhasivam@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 42 +++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 22cf162dd816..9b62ca0229bd 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2595,22 +2595,44 @@ ufs_mem_hc: ufshc@1d84000 { <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>, <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; - freq-table-hz = - <50000000 200000000>, - <0 0>, - <0 0>, - <37500000 150000000>, - <0 0>, - <0 0>, - <0 0>, - <0 0>, - <75000000 300000000>; + + operating-points-v2 = <&ufs_opp_table>; interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mem_noc SLAVE_EBI1 0>, <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>; interconnect-names = "ufs-ddr", "cpu-ufs"; status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <75000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <150000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; }; ufs_mem_phy: phy@1d87000 { From 725be1d6318e4ea7e3947fd4242a14cf589cfebf Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 12 Oct 2023 22:51:29 +0530 Subject: [PATCH 2255/7721] arm64: dts: qcom: sm8250: Add OPP table support to UFSHC UFS host controller, when scaling gears, should choose appropriate performance state of RPMh power domain controller along with clock frequency. So let's add the OPP table support to specify both clock frequency and RPMh performance states replacing the old "freq-table-hz" property. Reviewed-by: Dmitry Baryshkov Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231012172129.65172-6-manivannan.sadhasivam@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 39 +++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 125f5fb0e4e5..f8abf9566024 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -2463,21 +2463,42 @@ ufs_mem_hc: ufshc@1d84000 { <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; - freq-table-hz = - <37500000 300000000>, - <0 0>, - <0 0>, - <37500000 300000000>, - <0 0>, - <0 0>, - <0 0>, - <0 0>; + + operating-points-v2 = <&ufs_opp_table>; interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI_CH0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_UFS_MEM_CFG 0>; interconnect-names = "ufs-ddr", "cpu-ufs"; status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; }; ufs_mem_phy: phy@1d87000 { From 18c74d56fe6070c7c38058d7b43ccf2102abebcd Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 13 Oct 2023 10:09:53 +0200 Subject: [PATCH 2256/7721] iio: adc: Add PM7325 PMIC7 ADC bindings Add the defines for the ADC channels found on the PM7325. The list is taken from downstream msm-5.4 and adjusted for mainline. Signed-off-by: Luca Weiss Acked-by: Jonathan Cameron Link: https://lore.kernel.org/r/20231013-fp5-thermals-v1-1-f14df01922e6@fairphone.com Signed-off-by: Bjorn Andersson --- .../dt-bindings/iio/qcom,spmi-adc7-pm7325.h | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 include/dt-bindings/iio/qcom,spmi-adc7-pm7325.h diff --git a/include/dt-bindings/iio/qcom,spmi-adc7-pm7325.h b/include/dt-bindings/iio/qcom,spmi-adc7-pm7325.h new file mode 100644 index 000000000000..96908014e09e --- /dev/null +++ b/include/dt-bindings/iio/qcom,spmi-adc7-pm7325.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_PM7325_H +#define _DT_BINDINGS_QCOM_SPMI_VADC_PM7325_H + +#ifndef PM7325_SID +#define PM7325_SID 1 +#endif + +#include + +/* ADC channels for PM7325_ADC for PMIC7 */ +#define PM7325_ADC7_REF_GND (PM7325_SID << 8 | ADC7_REF_GND) +#define PM7325_ADC7_1P25VREF (PM7325_SID << 8 | ADC7_1P25VREF) +#define PM7325_ADC7_VREF_VADC (PM7325_SID << 8 | ADC7_VREF_VADC) +#define PM7325_ADC7_DIE_TEMP (PM7325_SID << 8 | ADC7_DIE_TEMP) + +#define PM7325_ADC7_AMUX_THM1 (PM7325_SID << 8 | ADC7_AMUX_THM1) +#define PM7325_ADC7_AMUX_THM2 (PM7325_SID << 8 | ADC7_AMUX_THM2) +#define PM7325_ADC7_AMUX_THM3 (PM7325_SID << 8 | ADC7_AMUX_THM3) +#define PM7325_ADC7_AMUX_THM4 (PM7325_SID << 8 | ADC7_AMUX_THM4) +#define PM7325_ADC7_AMUX_THM5 (PM7325_SID << 8 | ADC7_AMUX_THM5) +#define PM7325_ADC7_GPIO1 (PM7325_SID << 8 | ADC7_GPIO1) +#define PM7325_ADC7_GPIO2 (PM7325_SID << 8 | ADC7_GPIO2) +#define PM7325_ADC7_GPIO3 (PM7325_SID << 8 | ADC7_GPIO3) +#define PM7325_ADC7_GPIO4 (PM7325_SID << 8 | ADC7_GPIO4) + +/* 30k pull-up1 */ +#define PM7325_ADC7_AMUX_THM1_30K_PU (PM7325_SID << 8 | ADC7_AMUX_THM1_30K_PU) +#define PM7325_ADC7_AMUX_THM2_30K_PU (PM7325_SID << 8 | ADC7_AMUX_THM2_30K_PU) +#define PM7325_ADC7_AMUX_THM3_30K_PU (PM7325_SID << 8 | ADC7_AMUX_THM3_30K_PU) +#define PM7325_ADC7_AMUX_THM4_30K_PU (PM7325_SID << 8 | ADC7_AMUX_THM4_30K_PU) +#define PM7325_ADC7_AMUX_THM5_30K_PU (PM7325_SID << 8 | ADC7_AMUX_THM5_30K_PU) +#define PM7325_ADC7_GPIO1_30K_PU (PM7325_SID << 8 | ADC7_GPIO1_30K_PU) +#define PM7325_ADC7_GPIO2_30K_PU (PM7325_SID << 8 | ADC7_GPIO2_30K_PU) +#define PM7325_ADC7_GPIO3_30K_PU (PM7325_SID << 8 | ADC7_GPIO3_30K_PU) +#define PM7325_ADC7_GPIO4_30K_PU (PM7325_SID << 8 | ADC7_GPIO4_30K_PU) + +/* 100k pull-up2 */ +#define PM7325_ADC7_AMUX_THM1_100K_PU (PM7325_SID << 8 | ADC7_AMUX_THM1_100K_PU) +#define PM7325_ADC7_AMUX_THM2_100K_PU (PM7325_SID << 8 | ADC7_AMUX_THM2_100K_PU) +#define PM7325_ADC7_AMUX_THM3_100K_PU (PM7325_SID << 8 | ADC7_AMUX_THM3_100K_PU) +#define PM7325_ADC7_AMUX_THM4_100K_PU (PM7325_SID << 8 | ADC7_AMUX_THM4_100K_PU) +#define PM7325_ADC7_AMUX_THM5_100K_PU (PM7325_SID << 8 | ADC7_AMUX_THM5_100K_PU) +#define PM7325_ADC7_GPIO1_100K_PU (PM7325_SID << 8 | ADC7_GPIO1_100K_PU) +#define PM7325_ADC7_GPIO2_100K_PU (PM7325_SID << 8 | ADC7_GPIO2_100K_PU) +#define PM7325_ADC7_GPIO3_100K_PU (PM7325_SID << 8 | ADC7_GPIO3_100K_PU) +#define PM7325_ADC7_GPIO4_100K_PU (PM7325_SID << 8 | ADC7_GPIO4_100K_PU) + +/* 400k pull-up3 */ +#define PM7325_ADC7_AMUX_THM1_400K_PU (PM7325_SID << 8 | ADC7_AMUX_THM1_400K_PU) +#define PM7325_ADC7_AMUX_THM2_400K_PU (PM7325_SID << 8 | ADC7_AMUX_THM2_400K_PU) +#define PM7325_ADC7_AMUX_THM3_400K_PU (PM7325_SID << 8 | ADC7_AMUX_THM3_400K_PU) +#define PM7325_ADC7_AMUX_THM4_400K_PU (PM7325_SID << 8 | ADC7_AMUX_THM4_400K_PU) +#define PM7325_ADC7_AMUX_THM5_400K_PU (PM7325_SID << 8 | ADC7_AMUX_THM5_400K_PU) +#define PM7325_ADC7_GPIO1_400K_PU (PM7325_SID << 8 | ADC7_GPIO1_400K_PU) +#define PM7325_ADC7_GPIO2_400K_PU (PM7325_SID << 8 | ADC7_GPIO2_400K_PU) +#define PM7325_ADC7_GPIO3_400K_PU (PM7325_SID << 8 | ADC7_GPIO3_400K_PU) +#define PM7325_ADC7_GPIO4_400K_PU (PM7325_SID << 8 | ADC7_GPIO4_400K_PU) + +/* 1/3 Divider */ +#define PM7325_ADC7_GPIO4_DIV3 (PM7325_SID << 8 | ADC7_GPIO4_DIV3) + +#define PM7325_ADC7_VPH_PWR (PM7325_SID << 8 | ADC7_VPH_PWR) + +#endif /* _DT_BINDINGS_QCOM_SPMI_VADC_PM7325_H */ From 4c343fe9b68adeca1aa3a851bd06e62ecdaed180 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 13 Oct 2023 10:09:54 +0200 Subject: [PATCH 2257/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Add PM7250B thermals Configure the thermals for the CHARGER_SKIN_THERM and USB_CONN_THERM thermistors connected to PM7250B. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231013-fp5-thermals-v1-2-f14df01922e6@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 2de0b8c26c35..7fe19b556e6a 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -134,6 +134,36 @@ afvdd_2p8: regulator-afvdd-2p8 { enable-active-high; vin-supply = <&vreg_bob>; }; + + thermal-zones { + chg-skin-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm7250b_adc_tm 0>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + conn-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm7250b_adc_tm 1>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; }; &apps_rsc { @@ -425,6 +455,42 @@ &ipa { status = "okay"; }; +&pm7250b_adc { + channel@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "charger_skin_therm"; + }; + + channel@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "conn_therm"; + }; +}; + +&pm7250b_adc_tm { + status = "okay"; + + charger-skin-therm@0 { + reg = <0>; + io-channels = <&pm7250b_adc ADC5_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + conn-therm@1 { + reg = <1>; + io-channels = <&pm7250b_adc ADC5_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + &pm7325_gpios { volume_down_default: volume-down-default-state { pins = "gpio6"; From 46a2f77e1eb81990d303a94ab62f1bf79d0c9926 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 13 Oct 2023 10:09:55 +0200 Subject: [PATCH 2258/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Add PMK7325 thermals Configure the thermals for the XO_THERM line connected to PMK7325 (named in software PMK8350). Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231013-fp5-thermals-v1-3-f14df01922e6@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 7fe19b556e6a..2c01f799a6b2 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -9,6 +9,7 @@ #define PM7250B_SID 8 #define PM7250B_SID1 9 +#include #include #include #include @@ -163,6 +164,20 @@ active-config0 { }; }; }; + + xo-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 0>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; }; }; @@ -514,10 +529,33 @@ led-0 { }; }; +&pmk8350_adc_tm { + status = "okay"; + + xo-therm@0 { + reg = <0>; + io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + &pmk8350_rtc { status = "okay"; }; +&pmk8350_vadc { + status = "okay"; + + channel@44 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pmk8350_xo_therm"; + }; +}; + &pon_pwrkey { status = "okay"; }; From ae1122c375707a36c8fecebba745421a1e0ff93f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 13 Oct 2023 10:09:56 +0200 Subject: [PATCH 2259/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Add PM7325 thermals Configure the thermals for the QUIET_THERM, CAM_FLASH_THERM, MSM_THERM and RFC_CAM_THERM thermistors connected to PM7325. With this PMIC the software communication to the ADC is going through PMK7325 (= PMK8350). Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231013-fp5-thermals-v1-4-f14df01922e6@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 2c01f799a6b2..d0b1e4e507ff 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -9,6 +9,7 @@ #define PM7250B_SID 8 #define PM7250B_SID1 9 +#include #include #include #include @@ -137,6 +138,20 @@ afvdd_2p8: regulator-afvdd-2p8 { }; thermal-zones { + camera-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 2>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + chg-skin-thermal { polling-delay-passive = <0>; polling-delay = <0>; @@ -165,6 +180,48 @@ active-config0 { }; }; + quiet-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 1>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + rear-cam-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 4>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + sdm-skin-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 3>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + xo-thermal { polling-delay-passive = <0>; polling-delay = <0>; @@ -538,6 +595,34 @@ xo-therm@0 { qcom,ratiometric; qcom,hw-settle-time-us = <200>; }; + + quiet-therm@1 { + reg = <1>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + cam-flash-therm@2 { + reg = <2>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + sdm-skin-therm@3 { + reg = <3>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + wide-rfc-therm@4 { + reg = <4>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM4_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; }; &pmk8350_rtc { @@ -554,6 +639,38 @@ channel@44 { qcom,pre-scaling = <1 1>; label = "pmk8350_xo_therm"; }; + + channel@144 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_quiet_therm"; + }; + + channel@145 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_cam_flash_therm"; + }; + + channel@146 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_sdm_skin_therm"; + }; + + channel@147 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_wide_rfc_therm"; + }; }; &pon_pwrkey { From be69109e93c78cb3b9c191a21fc2b54291a711da Mon Sep 17 00:00:00 2001 From: Gianluca Boiano Date: Fri, 13 Oct 2023 13:05:31 +0200 Subject: [PATCH 2260/7721] arm64: dts: qcom: msm8953: add SPI interfaces This change add spi_3, spi_5 and spi_6 interfaces to MSM8953 devices. Signed-off-by: Gianluca Boiano Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231013110531.84140-1-morf3089@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 102 ++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index e7de7632669a..cdfc38e562b6 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -726,6 +726,48 @@ i2c_8_sleep: i2c-8-sleep-state { bias-disable; }; + spi_3_default: spi-3-default-state { + pins = "gpio10", "gpio11"; + function = "blsp_spi3"; + drive-strength = <2>; + bias-disable; + }; + + spi_3_sleep: spi-3-sleep-state { + pins = "gpio10", "gpio11"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + spi_5_default: spi-5-default-state { + pins = "gpio18", "gpio19"; + function = "blsp_spi5"; + drive-strength = <2>; + bias-disable; + }; + + spi_5_sleep: spi-5-sleep-state { + pins = "gpio18", "gpio19"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + spi_6_default: spi-6-default-state { + pins = "gpio22", "gpio23"; + function = "blsp_spi6"; + drive-strength = <2>; + bias-disable; + }; + + spi_6_sleep: spi-6-sleep-state { + pins = "gpio22", "gpio23"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + wcnss_pin_a: wcnss-active-state { wcss-wlan2-pins { @@ -1360,6 +1402,26 @@ i2c_3: i2c@78b7000 { status = "disabled"; }; + spi_3: spi@78b7000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x078b7000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + dmas = <&blsp1_dma 8>, <&blsp1_dma 9>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_3_default>; + pinctrl-1 = <&spi_3_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_4: i2c@78b8000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x078b8000 0x600>; @@ -1413,6 +1475,26 @@ i2c_5: i2c@7af5000 { status = "disabled"; }; + spi_5: spi@7af5000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x07af5000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP2_QUP1_I2C_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + dmas = <&blsp2_dma 4>, <&blsp2_dma 5>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_5_default>; + pinctrl-1 = <&spi_5_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_6: i2c@7af6000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x07af6000 0x600>; @@ -1433,6 +1515,26 @@ i2c_6: i2c@7af6000 { status = "disabled"; }; + spi_6: spi@7af6000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x07af6000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + dmas = <&blsp2_dma 6>, <&blsp2_dma 7>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_6_default>; + pinctrl-1 = <&spi_6_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_7: i2c@7af7000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x07af7000 0x600>; From afc4f14be33c50f066392f1e9671473419ba7ded Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Fri, 13 Oct 2023 18:39:33 +0200 Subject: [PATCH 2261/7721] dt-bindings: clocks: qcom,gcc-ipq8074: allow QMP PCI PHY PIPE clocks QMP PCI PHY PIPE clocks are inputs for the GCC clock controller. In order to describe this in DTS, allow passing them as the inputs to GCC. This has a benefit that it avoids doing a global matching by name. Signed-off-by: Robert Marko Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231013164025.3541606-1-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml index 52e7831a8d6d..2d44ddc45aab 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml @@ -27,11 +27,15 @@ properties: items: - description: board XO clock - description: sleep clock + - description: Gen3 QMP PCIe PHY PIPE clock + - description: Gen2 QMP PCIe PHY PIPE clock clock-names: items: - const: xo - const: sleep_clk + - const: pcie0_pipe + - const: pcie1_pipe required: - compatible From 591da388c344f934601548cb44f54eab012c6c94 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Fri, 13 Oct 2023 18:39:34 +0200 Subject: [PATCH 2262/7721] arm64: dts: qcom: ipq8074: pass QMP PCI PHY PIPE clocks to GCC Pass QMP PCI PHY PIPE clocks to the GCC controller so it does not have to find them by matching globaly by name. If not passed directly, driver maintains backwards compatibility by then falling back to global lookup. Signed-off-by: Robert Marko Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231013164025.3541606-2-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 3d4ff7476320..a4f7ae35be27 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -357,8 +357,14 @@ qpic_pins: qpic-state { gcc: gcc@1800000 { compatible = "qcom,gcc-ipq8074"; reg = <0x01800000 0x80000>; - clocks = <&xo>, <&sleep_clk>; - clock-names = "xo", "sleep_clk"; + clocks = <&xo>, + <&sleep_clk>, + <&pcie_qmp0>, + <&pcie_qmp1>; + clock-names = "xo", + "sleep_clk", + "pcie0_pipe", + "pcie1_pipe"; #clock-cells = <1>; #power-domain-cells = <1>; #reset-cells = <1>; From 924645058d31bde9788d6b493adefc6f113b3272 Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Wed, 29 Nov 2023 18:33:20 +0800 Subject: [PATCH 2263/7721] arm64: dts: qcom: sm4450: Add apps_rsc and cmd_db node Add apps_rsc node and cmd_db memory region for sm4450. Reviewed-by: Konrad Dybcio Signed-off-by: Ajit Pandey Signed-off-by: Tengfei Fan Link: https://lore.kernel.org/r/20231129103325.24854-2-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm4450.dtsi | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi index c4e5b33f5169..5e09880f4218 100644 --- a/arch/arm64/boot/dts/qcom/sm4450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi @@ -5,6 +5,7 @@ #include #include +#include / { interrupt-parent = <&intc>; @@ -328,6 +329,18 @@ CLUSTER_PD: power-domain-cpu-cluster0 { }; }; + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + aop_cmd_db_mem: cmd-db@80860000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x80860000 0x0 0x20000>; + no-map; + }; + }; + soc: soc@0 { #address-cells = <2>; #size-cells = <2>; @@ -419,6 +432,28 @@ frame@1742d000 { status = "disabled"; }; }; + + apps_rsc: rsc@17a00000 { + compatible = "qcom,rpmh-rsc"; + reg = <0x0 0x17a00000 0x0 0x10000>, + <0x0 0x17a10000 0x0 0x10000>, + <0x0 0x17a20000 0x0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + label = "apps_rsc"; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + power-domains = <&CLUSTER_PD>; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + }; + }; timer { From 483fa5552d352f3bfe835a3156e6cf037c4cf77f Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 29 Nov 2023 18:33:21 +0800 Subject: [PATCH 2264/7721] arm64: dts: qcom: sm4450: Add RPMH and Global clock Add device node for RPMH and Global clock controller on Qualcomm SM4450 platform. Reviewed-by: Konrad Dybcio Signed-off-by: Ajit Pandey Signed-off-by: Tengfei Fan Link: https://lore.kernel.org/r/20231129103325.24854-3-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm4450.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi index 5e09880f4218..5a8a54b0f6c1 100644 --- a/arch/arm64/boot/dts/qcom/sm4450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi @@ -3,6 +3,8 @@ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include #include #include #include @@ -348,6 +350,20 @@ soc: soc@0 { dma-ranges = <0 0 0 0 0x10 0>; compatible = "simple-bus"; + gcc: clock-controller@100000 { + compatible = "qcom,sm4450-gcc"; + reg = <0x0 0x00100000 0x0 0x1f4200>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; @@ -452,6 +468,13 @@ apps_rsc: rsc@17a00000 { apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; }; + + rpmhcc: clock-controller { + compatible = "qcom,sm4450-rpmh-clk"; + #clock-cells = <1>; + clocks = <&xo_board>; + clock-names = "xo"; + }; }; }; From 980679261b061da92fc441fa4e2fdb7ef8baadb2 Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 29 Nov 2023 18:33:22 +0800 Subject: [PATCH 2265/7721] arm64: dts: qcom: sm4450: add uart console support Add base description of UART and TLMM nodes which helps SM4450 boot to shell with console on boards with this SoC. Reviewed-by: Konrad Dybcio Signed-off-by: Tengfei Fan Link: https://lore.kernel.org/r/20231129103325.24854-4-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm4450.dtsi | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi index 5a8a54b0f6c1..3e7ae3bebbe0 100644 --- a/arch/arm64/boot/dts/qcom/sm4450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi @@ -364,6 +364,29 @@ gcc: clock-controller@100000 { <0>; }; + qupv3_id_0: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x00ac0000 0x0 0x2000>; + ranges; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + clock-names = "m-ahb", "s-ahb"; + #address-cells = <2>; + #size-cells = <2>; + status = "disabled"; + + uart7: serial@a88000 { + compatible = "qcom,geni-debug-uart"; + reg = <0x0 0x00a88000 0x0 0x4000>; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + interrupts = ; + pinctrl-0 = <&qup_uart7_tx>, <&qup_uart7_rx>; + pinctrl-names = "default"; + status = "disabled"; + }; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; @@ -380,6 +403,32 @@ pdc: interrupt-controller@b220000 { interrupt-controller; }; + tlmm: pinctrl@f100000 { + compatible = "qcom,sm4450-tlmm"; + reg = <0x0 0x0f100000 0x0 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 137>; + wakeup-parent = <&pdc>; + + qup_uart7_rx: qup-uart7-rx-state { + pins = "gpio23"; + function = "qup1_se2_l2"; + drive-strength = <2>; + bias-disable; + }; + + qup_uart7_tx: qup-uart7-tx-state { + pins = "gpio22"; + function = "qup1_se2_l2"; + drive-strength = <2>; + bias-disable; + }; + }; + intc: interrupt-controller@17200000 { compatible = "arm,gic-v3"; reg = <0x0 0x17200000 0x0 0x10000>, /* GICD */ From b6fbe1112e40109b8a0013d19b2d97f01438482d Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 29 Nov 2023 18:33:23 +0800 Subject: [PATCH 2266/7721] arm64: dts: qcom: sm4450-qrd: add QRD4450 uart support Add uart support for QRD4450 for enable uart console. Reviewed-by: Konrad Dybcio Signed-off-by: Tengfei Fan Link: https://lore.kernel.org/r/20231129103325.24854-5-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm4450-qrd.dts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts index 00a1c81ca397..bb8c58fb4267 100644 --- a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts @@ -10,9 +10,19 @@ / { model = "Qualcomm Technologies, Inc. SM4450 QRD"; compatible = "qcom,sm4450-qrd", "qcom,sm4450"; - aliases { }; + aliases { + serial0 = &uart7; + }; chosen { - bootargs = "console=hvc0"; + stdout-path = "serial0:115200n8"; }; }; + +&qupv3_id_0 { + status = "okay"; +}; + +&uart7 { + status = "okay"; +}; From 6e28e70f00756275151ffb02534c6d2318229416 Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 29 Nov 2023 18:33:24 +0800 Subject: [PATCH 2267/7721] arm64: dts: qcom: sm4450-qrd: mark QRD4450 reserved gpios Some gpios are reserved for other subsystems, so mark these reserved gpios. Suggested-by: Can Guo Signed-off-by: Tengfei Fan Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231129103325.24854-6-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm4450-qrd.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts index bb8c58fb4267..866e93783590 100644 --- a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts @@ -23,6 +23,10 @@ &qupv3_id_0 { status = "okay"; }; +&tlmm { + gpio-reserved-ranges = <0 4>; /* NFC eSE SPI */ +}; + &uart7 { status = "okay"; }; From 06fd1dd1efde4a0bcc874de03558f6e0ba3817eb Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Wed, 29 Nov 2023 12:28:14 +0530 Subject: [PATCH 2268/7721] dt-bindings: arm: qcom: Add QCM6490 IDP and QCS6490 RB3Gen2 board Document the qcom,qcm6490-idp and qcs6490-rb3gen2 boards. qcm6490-idp based off qcm6490 SoC derived from sc7280 meant for various form factor including IoT and qcs6490-rb3gen2 based off qcs6490 SoC derivative of qcm6490 without internal modem. Co-developed by: Naina Mehta Signed-off by: Naina Mehta Signed-off-by: Komal Bajaj Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231129065816.26409-2-quic_kbajaj@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index c0c7b282cb6d..10ff45b2c287 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -393,6 +393,8 @@ properties: - items: - enum: - fairphone,fp5 + - qcom,qcm6490-idp + - qcom,qcs6490-rb3gen2 - const: qcom,qcm6490 - description: Qualcomm Technologies, Inc. Distributed Unit 1000 platform From 9af6a9f32ad0023b1d682af213a0c8c2aa1dce29 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Wed, 29 Nov 2023 12:28:15 +0530 Subject: [PATCH 2269/7721] arm64: dts: qcom: Add base qcm6490 idp board dts Add DTS for Qualcomm IDP platform using QCM6490 SoC. This adds debug uart, eMMC and usb support along with regulators found on this board. Signed-off-by: Komal Bajaj Reviewed-by: Konrad Dybcio Reviewed-by: Caleb Connolly Link: https://lore.kernel.org/r/20231129065816.26409-3-quic_kbajaj@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 465 +++++++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcm6490-idp.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index d6cb840b7050..77babebe4904 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -87,6 +87,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-maple.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-poplar.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-xiaomi-sagit.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-fairphone-fp5.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcm6490-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts new file mode 100644 index 000000000000..2a5631b0fa40 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include "sc7280.dtsi" +#include "pm7325.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" + +/delete-node/ &ipa_fw_mem; +/delete-node/ &rmtfs_mem; +/delete-node/ &video_mem; +/delete-node/ &wlan_ce_mem; +/delete-node/ &xbl_mem; + +/ { + model = "Qualcomm Technologies, Inc. QCM6490 IDP"; + compatible = "qcom,qcm6490-idp", "qcom,qcm6490"; + chassis-type = "embedded"; + + aliases { + serial0 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + xbl_mem: xbl@80700000 { + reg = <0x0 0x80700000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap_mem: cdsp-secure-heap@81800000 { + reg = <0x0 0x81800000 0x0 0x1e00000>; + no-map; + }; + + camera_mem: camera@84300000 { + reg = <0x0 0x84300000 0x0 0x500000>; + no-map; + }; + + wpss_mem: wpss@84800000 { + reg = <0x0 0x84800000 0x0 0x1900000>; + no-map; + }; + + adsp_mem: adsp@86100000 { + reg = <0x0 0x86100000 0x0 0x2800000>; + no-map; + }; + + cdsp_mem: cdsp@88900000 { + reg = <0x0 0x88900000 0x0 0x1e00000>; + no-map; + }; + + video_mem: video@8a700000 { + reg = <0x0 0x8a700000 0x0 0x700000>; + no-map; + }; + + cvp_mem: cvp@8ae00000 { + reg = <0x0 0x8ae00000 0x0 0x500000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@8b300000 { + reg = <0x0 0x8b300000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@8b310000 { + reg = <0x0 0x8b310000 0x0 0xa000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8b31a000 { + reg = <0x0 0x8b31a000 0x0 0x2000>; + no-map; + }; + + mpss_mem: mpss@8b800000 { + reg = <0x0 0x8b800000 0x0 0xf600000>; + no-map; + }; + + tz_stat_mem: tz-stat@c0000000 { + reg = <0x0 0xc0000000 0x0 0x100000>; + no-map; + }; + + tags_mem: tags@c0100000 { + reg = <0x0 0xc0100000 0x0 0x1200000>; + no-map; + }; + + qtee_mem: qtee@c1300000 { + reg = <0x0 0xc1300000 0x0 0x500000>; + no-map; + }; + + trusted_apps_mem: trusted_apps@c1800000 { + reg = <0x0 0xc1800000 0x0 0x1c00000>; + no-map; + }; + + debug_vm_mem: debug-vm@d0600000 { + reg = <0x0 0xd0600000 0x0 0x100000>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <4350000>; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p972>; + vdd-l2-l7-supply = <&vreg_bob_3p296>; + vdd-l3-supply = <&vreg_s2b_0p876>; + vdd-l5-supply = <&vreg_s2b_0p876>; + vdd-l6-l9-l10-supply = <&vreg_s8b_1p272>; + vdd-l8-supply = <&vreg_s7b_0p972>; + vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p872>; + vdd-l13-supply = <&vreg_s7b_0p972>; + vdd-l14-l16-supply = <&vreg_s8b_1p272>; + + vreg_s1b_1p872: smps1 { + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s2b_0p876: smps2 { + regulator-min-microvolt = <570070>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7b_0p972: smps7 { + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b_1p272: smps8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b_0p912: ldo1 { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p072: ldo2 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l3b_0p504: ldo3 { + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vreg_l4b_0p752: ldo4 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <820000>; + regulator-initial-mode = ; + }; + + reg_l5b_0p752: ldo5 { + regulator-min-microvolt = <552000>; + regulator-max-microvolt = <832000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p2: ldo6 { + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p952: ldo7 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8b_0p904: ldo8 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vreg_l9b_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l11b_1p504: ldo11 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12b_0p751: ldo12 { + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l13b_0p53: ldo13 { + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l14b_1p08: ldo14 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l15b_0p765: ldo15 { + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b_1p1: ldo16 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l17b_1p7: ldo17 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l18b_1p8: ldo18 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l19b_1p8: ldo19 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l12-supply = <&vreg_s1b_1p872>; + vdd-l2-l8-supply = <&vreg_s1b_1p872>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob_3p296>; + vdd-l6-l9-l11-supply = <&vreg_bob_3p296>; + vdd-l10-supply = <&vreg_s7b_0p972>; + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_2p19: smps1 { + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vreg_s2c_0p752: smps2 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s5c_0p752: smps5 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7c_0p752: smps7 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s9c_1p084: smps9 { + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p62: ldo2 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3c_2p8: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vreg_l4c_1p62: ldo4 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p62: ldo5 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p96: ldo6 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p62: ldo8 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p96: ldo9 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <35440000>; + regulator-initial-mode = ; + }; + + vreg_l10c_0p88: ldo10 { + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + }; + + vreg_l11c_2p8: ldo11 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l12c_1p65: ldo12 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l13c_2p7: ldo13 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_bob_3p296: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + }; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&sdhc_1 { + non-removable; + no-sd; + no-sdio; + + vmmc-supply = <&vreg_l7b_2p952>; + vqmmc-supply = <&vreg_l19b_1p8>; + + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <32 2>, /* ADSP */ + <48 4>; /* NFC */ +}; + +&uart5 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l10c_0p88>; + vdda33-supply = <&vreg_l2b_3p072>; + vdda18-supply = <&vreg_l1c_1p8>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p912>; + + status = "okay"; +}; + +&wifi { + memory-region = <&wlan_fw_mem>; +}; From 04cf333afc757d8fd3c674c6c3f5f86c7755b4d4 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Wed, 29 Nov 2023 12:28:16 +0530 Subject: [PATCH 2270/7721] arm64: dts: qcom: Add base qcs6490-rb3gen2 board dts Add DTS for Qualcomm qcs6490-rb3gen2 board which uses QCS6490 SoC. This adds debug uart and usb support along with regulators found on this board. Co-developed-by: Naina Mehta Signed-off-by: Naina Mehta Signed-off-by: Komal Bajaj Reviewed-by: Konrad Dybcio Reviewed-by: Caleb Connolly Link: https://lore.kernel.org/r/20231129065816.26409-4-quic_kbajaj@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 452 +++++++++++++++++++ 2 files changed, 453 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 77babebe4904..4c0f9e4a2e5b 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -90,6 +90,7 @@ dtb-$(CONFIG_ARCH_QCOM) += qcm6490-fairphone-fp5.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb2210-rb1.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb4210-rb2.dtb diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts new file mode 100644 index 000000000000..0beab54c051e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +/* PM7250B is configured to use SID8/9 */ +#define PM7250B_SID 8 +#define PM7250B_SID1 9 + +#include +#include "sc7280.dtsi" +#include "pm7250b.dtsi" +#include "pm7325.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" + +/delete-node/ &ipa_fw_mem; +/delete-node/ &remoteproc_mpss; +/delete-node/ &rmtfs_mem; +/delete-node/ &video_mem; +/delete-node/ &wlan_ce_mem; +/delete-node/ &xbl_mem; + +/ { + model = "Qualcomm Technologies, Inc. Robotics RB3gen2"; + compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490"; + chassis-type = "embedded"; + + aliases { + serial0 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + xbl_mem: xbl@80700000 { + reg = <0x0 0x80700000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap_mem: cdsp-secure-heap@81800000 { + reg = <0x0 0x81800000 0x0 0x1e00000>; + no-map; + }; + + camera_mem: camera@84300000 { + reg = <0x0 0x84300000 0x0 0x500000>; + no-map; + }; + + wpss_mem: wpss@84800000 { + reg = <0x0 0x84800000 0x0 0x1900000>; + no-map; + }; + + adsp_mem: adsp@86100000 { + reg = <0x0 0x86100000 0x0 0x2800000>; + no-map; + }; + + cdsp_mem: cdsp@88900000 { + reg = <0x0 0x88900000 0x0 0x1e00000>; + no-map; + }; + + video_mem: video@8a700000 { + reg = <0x0 0x8a700000 0x0 0x700000>; + no-map; + }; + + cvp_mem: cvp@8ae00000 { + reg = <0x0 0x8ae00000 0x0 0x500000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@8b300000 { + reg = <0x0 0x8b300000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@8b310000 { + reg = <0x0 0x8b310000 0x0 0xa000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8b31a000 { + reg = <0x0 0x8b31a000 0x0 0x2000>; + no-map; + }; + + tz_stat_mem: tz-stat@c0000000 { + reg = <0x0 0xc0000000 0x0 0x100000>; + no-map; + }; + + tags_mem: tags@c0100000 { + reg = <0x0 0xc0100000 0x0 0x1200000>; + no-map; + }; + + qtee_mem: qtee@c1300000 { + reg = <0x0 0xc1300000 0x0 0x500000>; + no-map; + }; + + trusted_apps_mem: trusted_apps@c1800000 { + reg = <0x0 0xc1800000 0x0 0x1c00000>; + no-map; + }; + + debug_vm_mem: debug-vm@d0600000 { + reg = <0x0 0xd0600000 0x0 0x100000>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <4350000>; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p972>; + vdd-l2-l7-supply = <&vreg_bob_3p296>; + vdd-l3-supply = <&vreg_s2b_0p876>; + vdd-l5-supply = <&vreg_s2b_0p876>; + vdd-l6-l9-l10-supply = <&vreg_s8b_1p272>; + vdd-l8-supply = <&vreg_s7b_0p972>; + vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p872>; + vdd-l13-supply = <&vreg_s7b_0p972>; + vdd-l14-l16-supply = <&vreg_s8b_1p272>; + + vreg_s1b_1p872: smps1 { + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s2b_0p876: smps2 { + regulator-min-microvolt = <570070>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7b_0p972: smps7 { + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b_1p272: smps8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b_0p912: ldo1 { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p072: ldo2 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l3b_0p504: ldo3 { + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vreg_l4b_0p752: ldo4 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <820000>; + regulator-initial-mode = ; + }; + + reg_l5b_0p752: ldo5 { + regulator-min-microvolt = <552000>; + regulator-max-microvolt = <832000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p2: ldo6 { + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p952: ldo7 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8b_0p904: ldo8 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vreg_l9b_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l11b_1p504: ldo11 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12b_0p751: ldo12 { + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l13b_0p53: ldo13 { + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l14b_1p08: ldo14 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l15b_0p765: ldo15 { + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b_1p1: ldo16 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l17b_1p7: ldo17 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l18b_1p8: ldo18 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l19b_1p8: ldo19 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l12-supply = <&vreg_s1b_1p872>; + vdd-l2-l8-supply = <&vreg_s1b_1p872>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob_3p296>; + vdd-l6-l9-l11-supply = <&vreg_bob_3p296>; + vdd-l10-supply = <&vreg_s7b_0p972>; + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_2p19: smps1 { + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vreg_s2c_0p752: smps2 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s5c_0p752: smps5 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7c_0p752: smps7 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s9c_1p084: smps9 { + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p62: ldo2 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3c_2p8: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vreg_l4c_1p62: ldo4 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p62: ldo5 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p96: ldo6 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p62: ldo8 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p96: ldo9 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <35440000>; + regulator-initial-mode = ; + }; + + vreg_l10c_0p88: ldo10 { + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + }; + + vreg_l11c_2p8: ldo11 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l12c_1p65: ldo12 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l13c_2p7: ldo13 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_bob_3p296: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + }; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <32 2>, /* ADSP */ + <48 4>; /* NFC */ +}; + +&uart5 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l10c_0p88>; + vdda33-supply = <&vreg_l2b_3p072>; + vdda18-supply = <&vreg_l1c_1p8>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p912>; + + status = "okay"; +}; + +&wifi { + memory-region = <&wlan_fw_mem>; +}; From 3c3fcac8d3b1b0f242845c3b3c3263bd38b3b92f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 28 Nov 2023 19:04:41 -0800 Subject: [PATCH 2271/7721] dt-bindings: arm: qcom: Fix html link This link got broken by commit e790a4ce5290 ("arm: docs: Move Arm documentation to Documentation/arch/") when the doc moved from arm/ to arch/arm/. Fix the link so that it can continue to be followed. Fixes: e790a4ce5290 ("arm: docs: Move Arm documentation to Documentation/arch/") Cc: Alexandre TORGUE Cc: Yanteng Si Cc: Jonathan Corbet Reviewed-by: Douglas Anderson Acked-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20231129030443.2753833-1-swboyd@chromium.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 10ff45b2c287..ace3a2a18a8a 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -124,7 +124,7 @@ description: | There are many devices in the list below that run the standard ChromeOS bootloader setup and use the open source depthcharge bootloader to boot the OS. These devices do not use the scheme described above. For details, see: - https://docs.kernel.org/arm/google/chromebook-boot-flow.html + https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html properties: $nodename: From 5b006a82a2bbc0ce18bc6b084fc8d8d9cc110001 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 27 Nov 2023 22:55:38 +0100 Subject: [PATCH 2272/7721] arm64: dts: qcom: sdm632-fairphone-fp3: Enable WiFi/Bluetooth Configure and enable the WCNSS which provides WiFi and Bluetooth on this device using the WCN3680B chip. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231127-fp3-wcnss-v2-1-a5154fae4768@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts index 301eca9a4f31..476d0d40aaf9 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts @@ -239,3 +239,18 @@ &usb3 { &usb3_dwc3 { dr_mode = "peripheral"; }; + +&wcnss { + status = "okay"; + + vddpx-supply = <&pm8953_l5>; +}; + +&wcnss_iris { + compatible = "qcom,wcn3680"; + + vddxo-supply = <&pm8953_l7>; + vddrfa-supply = <&pm8953_l19>; + vddpa-supply = <&pm8953_l9>; + vdddig-supply = <&pm8953_l5>; +}; From ba5f5610841fad3b15c69c6949ed6e19bd5b466e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 27 Nov 2023 12:23:27 +0100 Subject: [PATCH 2273/7721] arm64: dts: qcom: sm6115: Add UART3 Hook up UART3, usually used for communicating with a Bluetooth module. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231120-topic-rb2_bt-v2-1-4bbf266258ef@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6115.dtsi | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi index 839c60351240..0d13d7bf6bd1 100644 --- a/arch/arm64/boot/dts/qcom/sm6115.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi @@ -273,6 +273,25 @@ memory@80000000 { reg = <0 0x80000000 0 0>; }; + qup_opp_table: opp-table-qup { + compatible = "operating-points-v2"; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmpd_opp_svs>; + }; + + opp-128000000 { + opp-hz = /bits/ 64 <128000000>; + required-opps = <&rpmpd_opp_nom>; + }; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = ; @@ -1208,6 +1227,17 @@ spi3: spi@4a8c000 { status = "disabled"; }; + uart3: serial@4a8c000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x04a8c000 0x0 0x4000>; + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + power-domains = <&rpmpd SM6115_VDDCX>; + operating-points-v2 = <&qup_opp_table>; + status = "disabled"; + }; + i2c4: i2c@4a90000 { compatible = "qcom,geni-i2c"; reg = <0x0 0x04a90000 0x0 0x4000>; From cab60b166575dd6db4c85487e87a9b677e04c153 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 27 Nov 2023 12:23:28 +0100 Subject: [PATCH 2274/7721] arm64: dts: qcom: qrb4210-rb2: Enable bluetooth Enable the QCA bluetooth on RB2. It identifies like the following: Bluetooth: hci0: QCA Product ID :0x0000000a Bluetooth: hci0: QCA SOC Version :0x40020150 Bluetooth: hci0: QCA ROM Version :0x00000201 Bluetooth: hci0: QCA Patch Version:0x00000001 Bluetooth: hci0: QCA controller version 0x01500201 Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231120-topic-rb2_bt-v2-2-4bbf266258ef@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 87 +++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts index 9738c0dacd58..33c312ae842e 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -15,6 +15,7 @@ / { aliases { serial0 = &uart4; + serial1 = &uart3; }; chosen { @@ -352,7 +353,8 @@ vreg_l8a_0p664: l8 { vreg_l9a_1p8: l9 { regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2000000>; + regulator-max-microvolt = <1800000>; + regulator-allow-set-load; }; vreg_l10a_1p8: l10 { @@ -389,11 +391,13 @@ vreg_l15a_3p128: l15 { vreg_l16a_1p3: l16 { regulator-min-microvolt = <1704000>; regulator-max-microvolt = <1904000>; + regulator-allow-set-load; }; vreg_l17a_1p3: l17 { regulator-min-microvolt = <1152000>; regulator-max-microvolt = <1384000>; + regulator-allow-set-load; }; vreg_l18a_1p232: l18 { @@ -426,6 +430,7 @@ vreg_l22a_2p96: l22 { vreg_l23a_3p3: l23 { regulator-min-microvolt = <3200000>; regulator-max-microvolt = <3400000>; + regulator-allow-set-load; }; vreg_l24a_2p96: l24 { @@ -487,6 +492,66 @@ &tlmm { <56 3>, <61 2>, <64 1>, <68 1>, <72 8>, <96 1>; + uart3_default: uart3-default-state { + cts-pins { + pins = "gpio8"; + function = "qup3"; + drive-strength = <2>; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio9"; + function = "qup3"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio10"; + function = "qup3"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio11"; + function = "qup3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart3_sleep: uart3-sleep-state { + cts-pins { + pins = "gpio8"; + function = "gpio"; + drive-strength = <2>; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio9"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + tx-pins { + pins = "gpio10"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + rx-pins { + pins = "gpio11"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + lt9611_rst_pin: lt9611-rst-state { pins = "gpio41"; function = "gpio"; @@ -508,6 +573,26 @@ sdc2_card_det_n: sd-card-det-n-state { }; }; +&uart3 { + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-0 = <&uart3_default>; + pinctrl-1 = <&uart3_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3988-bt"; + + vddio-supply = <&vreg_l9a_1p8>; + vddxo-supply = <&vreg_l16a_1p3>; + vddrf-supply = <&vreg_l17a_1p3>; + vddch0-supply = <&vreg_l23a_3p3>; + enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>; + max-speed = <3200000>; + }; +}; + &uart4 { status = "okay"; }; From fbe0870c48ac84f117860096048055a4f078a976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Sun, 26 Nov 2023 22:46:20 +0100 Subject: [PATCH 2275/7721] arm64: dts: qcom: msm8939-longcheer-l9100: Add proximity-near-level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consider an object near to the sensor when their distance is about 4 cm or below. Reviewed-by: Konrad Dybcio Signed-off-by: André Apitzsch Link: https://lore.kernel.org/r/20231126-bqm5_prox-v2-1-b7defc3979ac@apitzsch.eu Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts index ff532fdc1826..e3404c4455cf 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts @@ -180,6 +180,7 @@ magnetometer@d { light-sensor@23 { compatible = "liteon,ltr559"; reg = <0x23>; + proximity-near-level = <75>; vdd-supply = <&pm8916_l17>; vddio-supply = <&pm8916_l5>; From 608168b4d6079f2c43944bdfd64fd6c405d9a767 Mon Sep 17 00:00:00 2001 From: Jianhua Lu Date: Sun, 26 Nov 2023 10:28:48 +0800 Subject: [PATCH 2276/7721] arm64: dts: qcom: sm8250-xiaomi-elish: Fix typos There are two typos in this dtsi, so fix it. classis -> chassis. 80700000 -> 80600000 Reviewed-by: Konrad Dybcio Signed-off-by: Jianhua Lu Link: https://lore.kernel.org/r/20231126022849.14273-1-lujianhua000@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi index 85e5cf3dc91e..3d4ea428e4cb 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi @@ -23,7 +23,7 @@ /delete-node/ &xbl_aop_mem; / { - classis-type = "tablet"; + chassis-type = "tablet"; /* required for bootloader to select correct board */ qcom,msm-id = ; /* SM8250 v2.1 */ @@ -114,7 +114,7 @@ vreg_s6c_0p88: smpc6-regulator { }; reserved-memory { - xbl_aop_mem: xbl-aop@80700000 { + xbl_aop_mem: xbl-aop@80600000 { reg = <0x0 0x80600000 0x0 0x260000>; no-map; }; From 69652787279d64b0b0cc350fdfb34c503e40653c Mon Sep 17 00:00:00 2001 From: Jianhua Lu Date: Sun, 26 Nov 2023 10:28:49 +0800 Subject: [PATCH 2277/7721] arm64: dts: qcom: sm8250-xiaomi-elish: Add pm8150b type-c node and enable usb otg Add type-c node to feature otg function and set usb-role-switch property for usb_1_dwc3 to enable usb otg. Reviewed-by: Konrad Dybcio Signed-off-by: Jianhua Lu Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20231126022849.14273-2-lujianhua000@gmail.com Signed-off-by: Bjorn Andersson --- .../dts/qcom/sm8250-xiaomi-elish-common.dtsi | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi index 3d4ea428e4cb..946365f15a59 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include #include "sm8250.dtsi" #include "pm8150.dtsi" #include "pm8150b.dtsi" @@ -627,6 +628,41 @@ vol_up_n: vol-up-n-state { }; }; +&pm8150b_typec { + vdd-pdphy-supply = <&vreg_l2a_3p1>; + status = "okay"; + + connector { + compatible = "usb-c-connector"; + + power-role = "source"; + data-role = "dual"; + self-powered; + + source-pdos = ; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pm8150b_role_switch_in: endpoint { + remote-endpoint = <&usb_1_role_switch_out>; + }; + }; + }; + }; +}; + +&pm8150b_vbus { + status = "okay"; +}; + &pon_pwrkey { status = "okay"; }; @@ -664,11 +700,12 @@ &usb_1 { }; &usb_1_dwc3 { - dr_mode = "peripheral"; + dr_mode = "otg"; maximum-speed = "high-speed"; /* Remove USB3 phy */ phys = <&usb_1_hsphy>; phy-names = "usb2-phy"; + usb-role-switch; }; &usb_1_hsphy { @@ -678,6 +715,10 @@ &usb_1_hsphy { status = "okay"; }; +&usb_1_role_switch_out { + remote-endpoint = <&pm8150b_role_switch_in>; +}; + &ufs_mem_hc { vcc-supply = <&vreg_l17a_3p0>; vcc-max-microamp = <800000>; From fa78d0280fdc984d3dc1209b8c7c7a22ec9735de Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 30 Nov 2023 15:58:21 +0100 Subject: [PATCH 2278/7721] dt-bindings: soc: qcom: stats: Add QMP handle The stats can be expanded by poking the Always-On Subsystem through QMP. Allow passing a QMP handle for configurations that support it. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231130-topic-ddr_sleep_stats-v1-1-5981c2e764b6@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/soc/qcom/qcom-stats.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml index 96a7f1822022..686a7ef2f48a 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml @@ -31,10 +31,24 @@ properties: reg: maxItems: 1 + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM + required: - compatible - reg +allOf: + - if: + not: + properties: + compatible: + const: qcom,rpmh-stats + then: + properties: + qcom,qmp: false + additionalProperties: false examples: From bcaa71f13cc7160f2d5f9a401e9c58215612f79e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 30 Nov 2023 15:58:23 +0100 Subject: [PATCH 2279/7721] arm64: dts: qcom: sc8280xp: Add QMP handle to RPMh stats When a handle to QMP is accessible, we can query even more internal power management stats. Add it. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231130-topic-ddr_sleep_stats-v1-3-5981c2e764b6@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index cad59af7ccef..38cc823c9c87 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -4030,6 +4030,7 @@ aoss_qmp: power-management@c300000 { sram@c3f0000 { compatible = "qcom,rpmh-stats"; reg = <0 0x0c3f0000 0 0x400>; + qcom,qmp = <&aoss_qmp>; }; spmi_bus: spmi@c440000 { From 8786398f8686d1a4267ab52f830b25f17e6d62fc Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:03 +0100 Subject: [PATCH 2280/7721] arm64: dts: qcom: sc7180: Add the missing MDSS icc path MDSS, aside from the MDP-MEM path, also requires the CPU-DISP_CFG one. Failing to provide it may result in register accesses failing and that's never good. Add the missing path. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-6-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 11f353d416b4..9664e42faeb1 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -3100,8 +3100,12 @@ mdss: display-subsystem@ae00000 { interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 0 &mc_virt SLAVE_EBI1 0>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x800 0x2>; From c657056d99878c8a8ea84d5d4a9101bcb90b47f2 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:04 +0100 Subject: [PATCH 2281/7721] arm64: dts: qcom: sc7280: Add the missing MDSS icc path MDSS, aside from the MDP-MEM path, also requires the CPU-DISP_CFG one. Failing to provide it may result in register accesses failing and that's never good. Add the missing path. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-7-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 04bf85b0399a..41d327b1f1b6 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -3958,8 +3959,12 @@ mdss: display-subsystem@ae00000 { interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 0 &mc_virt SLAVE_EBI1 0>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc2 SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x900 0x402>; From a2b32096709dbf4af02675d98356a9d3ad86ff05 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:05 +0100 Subject: [PATCH 2282/7721] arm64: dts: qcom: qcm2290: Add display nodes Add the required nodes to support display on QCM2290. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-8-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 214 ++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index d46e591e72b5..a3edc4667cc5 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -5,6 +5,7 @@ * Based on sm6115.dtsi and previous efforts by Shawn Guo & Loic Poulain. */ +#include #include #include #include @@ -1105,6 +1106,219 @@ usb_dwc3: usb@4e00000 { }; }; + mdss: display-subsystem@5e00000 { + compatible = "qcom,qcm2290-mdss"; + reg = <0x0 0x05e00000 0x0 0x1000>; + reg-names = "mdss"; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", + "bus", + "core"; + + resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; + + power-domains = <&dispcc MDSS_GDSC>; + + iommus = <&apps_smmu 0x420 0x2>, + <&apps_smmu 0x421 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdp: display-controller@5e01000 { + compatible = "qcom,qcm2290-dpu"; + reg = <0x0 0x05e01000 0x0 0x8f000>, + <0x0 0x05eb0000 0x0 0x2008>; + reg-names = "mdp", + "vbif"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", + "iface", + "core", + "lut", + "vsync"; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmpd_opp_min_svs>; + }; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + required-opps = <&rpmpd_opp_svs>; + }; + + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + required-opps = <&rpmpd_opp_svs_plus>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@5e94000 { + compatible = "qcom,qcm2290-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0 0x05e94000 0x0 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + phys = <&mdss_dsi0_phy>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmpd_opp_min_svs>; + }; + + opp-164000000 { + opp-hz = /bits/ 64 <164000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmpd_opp_svs>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@5e94400 { + compatible = "qcom,dsi-phy-14nm-2290"; + reg = <0x0 0x05e94400 0x0 0x100>, + <0x0 0x05e94500 0x0 0x300>, + <0x0 0x05e94800 0x0 0x188>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", + "ref"; + + power-domains = <&rpmpd QCM2290_VDDMX>; + required-opps = <&rpmpd_opp_nom>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + }; + + dispcc: clock-controller@5f00000 { + compatible = "qcom,qcm2290-dispcc"; + reg = <0x0 0x05f00000 0x0 0x20000>; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, + <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "dsi0_phy_pll_out_byteclk", + "dsi0_phy_pll_out_dsiclk"; + #power-domain-cells = <1>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + remoteproc_mpss: remoteproc@6080000 { compatible = "qcom,qcm2290-mpss-pas", "qcom,sm6115-mpss-pas"; reg = <0x0 0x06080000 0x0 0x100>; From 5b970ff0193d67da4a8d2d5fda50dd8ddb50a71e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:06 +0100 Subject: [PATCH 2283/7721] arm64: dts: qcom: qcm2290: Hook up interconnects Add interconnect provider nodes and hook up interconnects to consumer devices, including bwmon. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-9-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 248 ++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index a3edc4667cc5..ce04d0acdede 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include / { @@ -151,6 +153,8 @@ scm: scm { clocks = <&rpmcc RPM_SMD_CE1_CLK>; clock-names = "core"; #reset-cells = <1>; + interconnects = <&system_noc MASTER_CRYPTO_CORE0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; }; }; @@ -669,6 +673,33 @@ usb_qmpphy: phy@1615000 { status = "disabled"; }; + system_noc: interconnect@1880000 { + compatible = "qcom,qcm2290-snoc"; + reg = <0x0 0x01880000 0x0 0x60200>; + #interconnect-cells = <2>; + + qup_virt: interconnect-qup { + compatible = "qcom,qcm2290-qup-virt"; + #interconnect-cells = <2>; + }; + + mmnrt_virt: interconnect-mmnrt { + compatible = "qcom,qcm2290-mmnrt-virt"; + #interconnect-cells = <2>; + }; + + mmrt_virt: interconnect-mmrt { + compatible = "qcom,qcm2290-mmrt-virt"; + #interconnect-cells = <2>; + }; + }; + + config_noc: interconnect@1900000 { + compatible = "qcom,qcm2290-cnoc"; + reg = <0x0 0x01900000 0x0 0x8200>; + #interconnect-cells = <2>; + }; + qfprom@1b44000 { compatible = "qcom,qcm2290-qfprom", "qcom,qfprom"; reg = <0x0 0x01b44000 0x0 0x3000>; @@ -681,6 +712,60 @@ qusb2_hstx_trim: hstx-trim@25b { }; }; + pmu@1b8e300 { + compatible = "qcom,qcm2290-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x01b8e300 0x0 0x600>; + interrupts = ; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + interconnects = <&bimc MASTER_APPSS_PROC RPM_ACTIVE_TAG + &bimc SLAVE_EBI1 RPM_ACTIVE_TAG>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <(200 * 4 * 1000)>; + }; + + opp-1 { + opp-peak-kBps = <(300 * 4 * 1000)>; + }; + + opp-2 { + opp-peak-kBps = <(451 * 4 * 1000)>; + }; + + opp-3 { + opp-peak-kBps = <(547 * 4 * 1000)>; + }; + + opp-4 { + opp-peak-kBps = <(681 * 4 * 1000)>; + }; + + opp-5 { + opp-peak-kBps = <(768 * 4 * 1000)>; + }; + + opp-6 { + opp-peak-kBps = <(1017 * 4 * 1000)>; + }; + + opp-7 { + opp-peak-kBps = <(1353 * 4 * 1000)>; + }; + + opp-8 { + opp-peak-kBps = <(1555 * 4 * 1000)>; + }; + + opp-9 { + opp-peak-kBps = <(1804 * 4 * 1000)>; + }; + }; + }; + spmi_bus: spmi@1c40000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x01c40000 0x0 0x1100>, @@ -721,6 +806,12 @@ rng: rng@4453000 { clock-names = "core"; }; + bimc: interconnect@4480000 { + compatible = "qcom,qcm2290-bimc"; + reg = <0x0 0x04480000 0x0 0x80000>; + #interconnect-cells = <2>; + }; + rpm_msg_ram: sram@45f0000 { compatible = "qcom,rpm-msg-ram"; reg = <0x0 0x045f0000 0x0 0x7000>; @@ -756,13 +847,45 @@ sdhc_1: mmc@4744000 { resets = <&gcc GCC_SDCC1_BCR>; power-domains = <&rpmpd QCM2290_VDDCX>; + operating-points-v2 = <&sdhc1_opp_table>; iommus = <&apps_smmu 0xc0 0x0>; + interconnects = <&system_noc MASTER_SDCC_1 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_1 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; qcom,dll-config = <0x000f642c>; qcom,ddr-config = <0x80040868>; bus-width = <8>; status = "disabled"; + + sdhc1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <102400 65000>; + }; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmpd_opp_svs_plus>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + }; }; sdhc_2: mmc@4784000 { @@ -786,6 +909,12 @@ sdhc_2: mmc@4784000 { power-domains = <&rpmpd QCM2290_VDDCX>; operating-points-v2 = <&sdhc2_opp_table>; iommus = <&apps_smmu 0xa0 0x0>; + interconnects = <&system_noc MASTER_SDCC_2 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_2 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; qcom,dll-config = <0x0007642c>; qcom,ddr-config = <0x80040868>; @@ -799,11 +928,15 @@ sdhc2_opp_table: opp-table { opp-100000000 { opp-hz = /bits/ 64 <100000000>; required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <261438 150000>; }; opp-202000000 { opp-hz = /bits/ 64 <202000000>; required-opps = <&rpmpd_opp_svs_plus>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <261438 300000>; }; }; }; @@ -851,6 +984,15 @@ i2c0: i2c@4a80000 { dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, <&gpi_dma0 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -867,6 +1009,12 @@ spi0: spi@4a80000 { dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, <&gpi_dma0 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -880,6 +1028,12 @@ uart0: serial@4a80000 { clock-names = "se"; pinctrl-0 = <&qup_uart0_default>; pinctrl-names = "default"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; status = "disabled"; }; @@ -894,6 +1048,15 @@ i2c1: i2c@4a84000 { dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -910,6 +1073,12 @@ spi1: spi@4a84000 { dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, <&gpi_dma0 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -926,6 +1095,15 @@ i2c2: i2c@4a88000 { dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -942,6 +1120,12 @@ spi2: spi@4a88000 { dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, <&gpi_dma0 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -958,6 +1142,15 @@ i2c3: i2c@4a8c000 { dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -974,6 +1167,12 @@ spi3: spi@4a8c000 { dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, <&gpi_dma0 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -990,6 +1189,15 @@ i2c4: i2c@4a90000 { dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, <&gpi_dma0 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1006,6 +1214,12 @@ spi4: spi@4a90000 { dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, <&gpi_dma0 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1019,6 +1233,12 @@ uart4: serial@4a90000 { clock-names = "se"; pinctrl-0 = <&qup_uart4_default>; pinctrl-names = "default"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; status = "disabled"; }; @@ -1033,6 +1253,15 @@ i2c5: i2c@4a94000 { dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, <&gpi_dma0 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1049,6 +1278,12 @@ spi5: spi@4a94000 { dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, <&gpi_dma0 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1081,6 +1316,13 @@ usb: usb@4ef8800 { resets = <&gcc GCC_USB30_PRIM_BCR>; power-domains = <&gcc GCC_USB30_PRIM_GDSC>; + /* TODO: USB<->IPA path */ + interconnects = <&system_noc MASTER_USB3_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_USB3 RPM_ALWAYS_TAG>; + interconnect-names = "usb-ddr", + "apps-usb"; wakeup-source; #address-cells = <2>; @@ -1127,6 +1369,12 @@ mdss: display-subsystem@5e00000 { iommus = <&apps_smmu 0x420 0x2>, <&apps_smmu 0x421 0x0>; + interconnects = <&mmrt_virt MASTER_MDP0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_DISPLAY_CFG RPM_ALWAYS_TAG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; #address-cells = <2>; #size-cells = <2>; From 616eda24edd48b8b56516886c51d211fbfd2679b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:07 +0100 Subject: [PATCH 2284/7721] arm64: dts: qcom: qrb2210-rb1: Set up HDMI Add the required nodes to support display output via the HDMI port. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-10-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 86 ++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index 94885b9c21c8..ac6584164058 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -40,6 +40,17 @@ key-volume-up { }; }; + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <<9611_out>; + }; + }; + }; + leds { compatible = "gpio-leds"; @@ -158,6 +169,68 @@ vph_pwr: regulator-vph-pwr { }; }; +&gpi_dma0 { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <400000>; + status = "okay"; + + lt9611_codec: hdmi-bridge@2b { + compatible = "lontium,lt9611uxc"; + reg = <0x2b>; + interrupts-extended = <&tlmm 46 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 41 GPIO_ACTIVE_HIGH>; + + vdd-supply = <&vreg_hdmi_out_1p2>; + vcc-supply = <<9611_3v3>; + + pinctrl-0 = <<9611_irq_pin <9611_rst_pin>; + pinctrl-names = "default"; + #sound-dai-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lt9611_a: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@2 { + reg = <2>; + + lt9611_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&pm2250_l5>; + status = "okay"; +}; + +&mdss_dsi0_out { + remote-endpoint = <<9611_a>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + status = "okay"; +}; + &pm2250_resin { linux,code = ; status = "okay"; @@ -377,6 +450,19 @@ &sdhc_2 { }; &tlmm { + lt9611_rst_pin: lt9611-rst-state { + pins = "gpio41"; + function = "gpio"; + input-disable; + output-high; + }; + + lt9611_irq_pin: lt9611-irq-state { + pins = "gpio46"; + function = "gpio"; + bias-disable; + }; + sd_det_in_on: sd-det-in-on-state { pins = "gpio88"; function = "gpio"; From 252bc7ad359478dba8d77bce9502f2cc7bb547a3 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:08 +0100 Subject: [PATCH 2285/7721] arm64: dts: qcom: qrb2210-rb1: Enable CAN bus controller Enable the Microchip mcp2518fd hosted on the SPI5 bus. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-11-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index ac6584164058..ac597eb3fe9d 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -23,6 +23,14 @@ chosen { stdout-path = "serial0:115200n8"; }; + clocks { + clk40M: can-clk { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + #clock-cells = <0>; + }; + }; + gpio-keys { compatible = "gpio-keys"; label = "gpio-keys"; @@ -449,6 +457,20 @@ &sdhc_2 { status = "okay"; }; +&spi5 { + status = "okay"; + + can@0 { + compatible = "microchip,mcp2518fd"; + reg = <0>; + interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>; + clocks = <&clk40M>; + spi-max-frequency = <10000000>; + vdd-supply = <&vdc_5v>; + xceiver-supply = <&vdc_5v>; + }; +}; + &tlmm { lt9611_rst_pin: lt9611-rst-state { pins = "gpio41"; From b6a56a5a25d6273729b2b5139d58e3d390318ed2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 29 Nov 2023 15:44:09 +0100 Subject: [PATCH 2286/7721] arm64: dts: qcom: qrb2210-rb1: add wifi variant property The RB1 platform doesn't have board-specific board-id programmed, it uses generic 0xff. Thus add the property with the 'variant' of the calibration data. Note: the driver will check for the calibration data for the following IDs, so existing board-2.bin files will continue to work. - 'bus=snoc,qmi-board-id=ff,qmi-chip-id=120,variant=Thundercomm_RB1' - 'bus=snoc,qmi-board-id=ff,qmi-chip-id=120' - 'bus=snoc,qmi-board-id=ff' For the reference, the board is identified by the driver in the following way: ath10k_snoc c800000.wifi: qmi chip_id 0x120 chip_family 0x4007 board_id 0xff soc_id 0x40670000 ath10k_snoc c800000.wifi: qmi fw_version 0x337302d3 fw_build_timestamp 2023-01-06 01:50 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HL.3.3.7.c2-00723-QCAHLSWMTPLZ-1 ath10k_snoc c800000.wifi: wcn3990 hw1.0 target 0x00000008 chip_id 0x00000000 sub 0000:0000 ath10k_snoc c800000.wifi: kconfig debug 0 debugfs 0 tracing 0 dfs 0 testmode 0 ath10k_snoc c800000.wifi: firmware ver api 5 features wowlan,mgmt-tx-by-reference,non-bmi crc32 b3d4b790 ath10k_snoc c800000.wifi: htt-ver 3.114 wmi-op 4 htt-op 3 cal file max-sta 32 raw 0 hwcrypto 1 Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-12-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index ac597eb3fe9d..bd7bcf803654 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -535,6 +535,7 @@ &wifi { vdd-1.8-xo-supply = <&pm2250_l13>; vdd-1.3-rfa-supply = <&pm2250_l10>; vdd-3.3-ch0-supply = <&pm2250_l22>; + qcom,ath10k-calibration-variant = "Thundercomm_RB1"; status = "okay"; }; From 2e0dcbf164fb02d2558bd08b9609a30ef5935912 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 25 Nov 2023 13:19:28 +0100 Subject: [PATCH 2287/7721] arm64: dts: qcom: msm8953: Use non-deprecated qcom,domain in LPASS Use the qcom,domain property instead of the deprecated qcom,apr-domain, which in turn also fixes a bunch of dtbs_checks warnings. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231125-msm8953-misc-fixes-v2-2-df86655841d9@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index cdfc38e562b6..fbfd3a441173 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -1747,7 +1747,7 @@ smd-edge { apr { compatible = "qcom,apr-v2"; qcom,smd-channels = "apr_audio_svc"; - qcom,apr-domain = ; + qcom,domain = ; #address-cells = <1>; #size-cells = <0>; From 01a3c3739183003640f8468ecf75d7eeb15f808a Mon Sep 17 00:00:00 2001 From: Lukas Walter Date: Sat, 21 Oct 2023 16:30:24 +0200 Subject: [PATCH 2288/7721] dt-bindings: arm: qcom: Add Huawei Honor 5X / GR5 (2016) Add a compatible for Huawei Honor 5X / GR5 (2016). Acked-by: Krzysztof Kozlowski Signed-off-by: Lukas Walter Link: https://lore.kernel.org/r/20231021143025.77088-1-lukas.walter@aceart.de Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index ace3a2a18a8a..ba0616445cdd 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -187,6 +187,7 @@ properties: - items: - enum: + - huawei,kiwi - longcheer,l9100 - samsung,a7 - sony,kanuti-tulip From cff9a76f306bfb6262153c0da2029071036b9a04 Mon Sep 17 00:00:00 2001 From: Lukas Walter Date: Sat, 21 Oct 2023 16:30:25 +0200 Subject: [PATCH 2289/7721] arm64: dts: qcom: msm8939-huawei-kiwi: Add initial device tree This dts adds support for Huawei Honor 5X / GR5 (2016) smartphone released in 2015. Add device tree with initial support for: - GPIO keys - Hall sensor - SDHCI (internal and external storage) - WCNSS (BT/WIFI) - Sensors (accelerometer and proximity) - Vibrator - Touchscreen Signed-off-by: Raymond Hackley Signed-off-by: Lukas Walter Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231021143025.77088-2-lukas.walter@aceart.de Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/msm8939-huawei-kiwi.dts | 242 ++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 4c0f9e4a2e5b..51335f08a742 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -45,6 +45,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-thwc-uf896.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-thwc-ufi001c.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-wingtech-wt88047.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-yiming-uz801v3.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8939-huawei-kiwi.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-longcheer-l9100.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-samsung-a7.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-sony-xperia-kanuti-tulip.dtb diff --git a/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts b/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts new file mode 100644 index 000000000000..3cec51891aed --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/dts-v1/; + +#include "msm8939-pm8916.dtsi" +#include + +/ { + model = "Huawei Honor 5X / GR5 (2016)"; + compatible = "huawei,kiwi", "qcom,msm8939"; + chassis-type = "handset"; + + aliases { + mmc0 = &sdhc_1; /* SDC1 eMMC slot */ + mmc1 = &sdhc_2; /* SDC2 SD card slot */ + serial0 = &blsp_uart2; + }; + + chosen { + stdout-path = "serial0"; + }; + + reserved-memory { + qseecom_mem: qseecom@84a00000 { + reg = <0x0 0x84a00000 0x0 0x1600000>; + no-map; + }; + }; + + gpio-hall-sensor { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_hall_sensor_default>; + pinctrl-names = "default"; + + label = "GPIO Hall Effect Sensor"; + + event-hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + linux,can-disable; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + label = "GPIO Buttons"; + + button-volume-up { + label = "Volume Up"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; + id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb_id_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_i2c2 { + status = "okay"; + + accelerometer@1e { + compatible = "kionix,kx023-1025"; + reg = <0x1e>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + pinctrl-0 = <&accel_int_default>; + pinctrl-names = "default"; + mount-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "1"; + }; + + proximity@39 { + compatible = "avago,apds9930"; + reg = <0x39>; + + interrupt-parent = <&tlmm>; + interrupts = <113 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + + led-max-microamp = <25000>; + amstaos,proximity-diodes = <0>; + + pinctrl-0 = <&prox_irq_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_i2c5 { + status = "okay"; + + touchscreen@1c { + compatible = "cypress,tt21000"; + + reg = <0x1c>; + interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + /* + * NOTE: vdd is not directly supplied by pm8916_l16, it seems to be a + * fixed regulator that is automatically enabled by pm8916_l16. + */ + vdd-supply = <&pm8916_l16>; + vddio-supply = <&pm8916_l16>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_uart2 { + status = "okay"; +}; + +&pm8916_l8 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; +}; + +&pm8916_resin { + linux,code = ; + status = "okay"; +}; + +&pm8916_rpm_regulators { + pm8916_l16: l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8916_l17: l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; +}; + +&pm8916_vib { + status = "okay"; +}; + +&sdhc_1 { + status = "okay"; +}; + +&sdhc_2 { + pinctrl-0 = <&sdc2_default &sdc2_cd_default>; + pinctrl-1 = <&sdc2_sleep &sdc2_cd_default>; + pinctrl-names = "default", "sleep"; + + cd-gpios = <&tlmm 38 GPIO_ACTIVE_HIGH>; + + status = "okay"; +}; + +&usb { + extcon = <&usb_id>, <&usb_id>; + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&usb_id>; +}; + +&wcnss { + status = "okay"; +}; + +&wcnss_iris { + compatible = "qcom,wcn3620"; +}; + +&wcnss_mem { + status = "okay"; +}; + +&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio115"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + gpio_hall_sensor_default: gpio-hall-sensor-default-state { + pins = "gpio69"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + gpio_keys_default: gpio-keys-default-state { + pins = "gpio107"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + prox_irq_default: prox-irq-default-state { + pins = "gpio113"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + sdc2_cd_default: sdc2-cd-default-state { + pins = "gpio38"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + touchscreen_default: touchscreen-default-state { + pins = "gpio12", "gpio13"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + usb_id_default: usb-id-default-state { + pins = "gpio110"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; From 83afcf14edb9217e58837eb119da96d734a4b3b1 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sat, 21 Oct 2023 14:00:07 +0200 Subject: [PATCH 2290/7721] arm64: dts: qcom: ipq6018: use CPUFreq NVMEM IPQ6018 comes in multiple SKU-s and some of them dont support all of the OPP-s that are current set, so lets utilize CPUFreq NVMEM to allow only supported OPP-s based on the SoC dynamically. As an example, IPQ6018 is generaly rated at 1.8GHz but some silicon only goes up to 1.5GHz and is marked as such via an eFuse. Signed-off-by: Robert Marko Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231021120048.231239-1-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index a89b6f54d3a7..39cd6b76b4c1 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -96,42 +96,49 @@ scm { }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&cpu_speed_bin>; opp-shared; opp-864000000 { opp-hz = /bits/ 64 <864000000>; opp-microvolt = <725000>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1056000000 { opp-hz = /bits/ 64 <1056000000>; opp-microvolt = <787500>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1320000000 { opp-hz = /bits/ 64 <1320000000>; opp-microvolt = <862500>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; opp-1440000000 { opp-hz = /bits/ 64 <1440000000>; opp-microvolt = <925000>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; opp-microvolt = <987500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1062500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; }; @@ -309,6 +316,11 @@ qfprom: efuse@a4000 { reg = <0x0 0x000a4000 0x0 0x2000>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@135 { + reg = <0x135 0x1>; + bits = <7 1>; + }; }; prng: qrng@e3000 { From 50891bc7f1e9e65fa260c442efa7fa24b3523c96 Mon Sep 17 00:00:00 2001 From: Raymond Hackley Date: Tue, 17 Oct 2023 13:00:11 +0000 Subject: [PATCH 2291/7721] arm64: dts: qcom: msm8916-acer-a1-724: Add notification LED Acer Iconia Talk S A1-724 uses KTD2026 LED driver. However, there is no blue LED on it. Add it to the device tree. Signed-off-by: Raymond Hackley Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231017125848.84311-1-raymondhackley@protonmail.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-acer-a1-724.dts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts index 57a74eea1005..b32c7a97394d 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts @@ -7,6 +7,7 @@ #include #include #include +#include /* * NOTE: The original firmware from Acer can only boot 32-bit kernels. @@ -83,6 +84,29 @@ magnetometer@12 { }; }; +&blsp_i2c4 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + function = LED_FUNCTION_STATUS; + color = ; + }; + + led@1 { + reg = <1>; + function = LED_FUNCTION_STATUS; + color = ; + }; + }; +}; + &blsp_i2c5 { status = "okay"; From 2dee68e77cb5322d7cfe44f3c84ff8ae2eaf4aee Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sun, 15 Oct 2023 22:06:56 +0200 Subject: [PATCH 2292/7721] arm64: dts: qcom: sdm632-fairphone-fp3: Enable LPASS Enable the LPASS/ADSP found on the phone. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231015-fp3-lpass-v1-1-4d46a399a035@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts index 476d0d40aaf9..057579ae3013 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts @@ -80,6 +80,10 @@ nfc@28 { }; }; +&lpass { + status = "okay"; +}; + &pm8953_resin { status = "okay"; linux,code = ; From 663affdb12b3e26c77d103327cf27de720c8117e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Oct 2023 10:06:58 +0200 Subject: [PATCH 2293/7721] arm64: dts: qcom: sc8280xp-crd: fix eDP phy compatible The sc8280xp Display Port PHYs can be used in either DP or eDP mode and this is configured using the devicetree compatible string which defaults to DP mode in the SoC dtsi. Override the default compatible string for the CRD eDP PHY node so that the eDP settings are used. Fixes: 4a883a8d80b5 ("arm64: dts: qcom: sc8280xp-crd: Enable EDP") Cc: stable@vger.kernel.org # 6.3 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231016080658.6667-1-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts index e4861c61a65b..ffc4406422ae 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts @@ -458,6 +458,8 @@ mdss0_dp3_out: endpoint { }; &mdss0_dp3_phy { + compatible = "qcom,sc8280xp-edp-phy"; + vdda-phy-supply = <&vreg_l6b>; vdda-pll-supply = <&vreg_l3b>; From 1aaa08e8de365cce59203541cafadb5053b1ec1a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Nov 2023 16:11:10 -0800 Subject: [PATCH 2294/7721] arm64: dts: qcom: sc8180x-primus: Fix HALL_INT polarity The hall sensor interrupt on the Primus is active low, which means that with the current configuration the device attempts to suspend when the LID is open. Fix the polarity of the HALL_INT GPIO to avoid this. Fixes: 2ce38cc1e8fe ("arm64: dts: qcom: sc8180x: Introduce Primus") Signed-off-by: Bjorn Andersson Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231130-sc8180x-primus-lid-polarity-v1-1-da917b59604b@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts index fd2fab4895b3..a40ef23a2a4f 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts @@ -43,7 +43,7 @@ gpio-keys { pinctrl-0 = <&hall_int_active_state>; lid-switch { - gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>; + gpios = <&tlmm 121 GPIO_ACTIVE_LOW>; linux,input-type = ; linux,code = ; wakeup-source; From 20e886590a310665244a354e3b693b881544edec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 29 Nov 2023 15:05:36 +0100 Subject: [PATCH 2295/7721] arm64: dts: qcom: sm8450: correct TX Soundwire clock The TX Soundwire controller should take clock from TX macro codec, not VA macro codec clock, otherwise the clock stays disabled. This looks like a copy-paste issue, because the SC8280xp code uses here correctly clock from TX macro. The VA macro clock is already consumed by TX macro codec, thus it won't be disabled by this change. Fixes: 14341e76dbc7 ("arm64: dts: qcom: sm8450: add Soundwire and LPASS") Reported-by: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231129140537.161720-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index bde9c1093384..12e55a0c7417 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -2314,7 +2314,7 @@ swr2: soundwire-controller@33b0000 { ; interrupt-names = "core", "wakeup"; - clocks = <&vamacro>; + clocks = <&txmacro>; clock-names = "iface"; label = "TX"; From ead0f132fc494b46fcd94788456f9b264fd631bb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 29 Nov 2023 15:05:37 +0100 Subject: [PATCH 2296/7721] arm64: dts: qcom: sm8550: correct TX Soundwire clock The TX Soundwire controller should take clock from TX macro codec, not VA macro codec clock, otherwise the clock stays disabled. This looks like a copy-paste issue, because the SC8280xp code uses here correctly clock from TX macro. The VA macro clock is already consumed by TX macro codec, thus it won't be disabled by this change. Fixes: 61b006389bb7 ("arm64: dts: qcom: sm8550: add Soundwire controllers") Reported-by: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231129140537.161720-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 7bafb3d88d69..17c4f0a7638a 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -2199,7 +2199,7 @@ swr2: soundwire-controller@6d30000 { interrupts = , ; interrupt-names = "core", "wakeup"; - clocks = <&lpass_vamacro>; + clocks = <&lpass_txmacro>; clock-names = "iface"; label = "TX"; From d69e34675a8be0affe8c55dbf50f795dac521933 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 25 Nov 2023 13:05:33 +0100 Subject: [PATCH 2297/7721] dt-bindings: vendor-prefixes: document HTC Corporation Add the vendor prefix for HTC (https://www.htc.com/). Acked-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231125-htc-memul-v3-1-e8f4c5839e23@z3ntu.xyz Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 309b94c328c8..b752f8902367 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -597,6 +597,8 @@ patternProperties: description: Hewlett Packard Enterprise "^hsg,.*": description: HannStar Display Co. + "^htc,.*": + description: HTC Corporation "^huawei,.*": description: Huawei Technologies Co., Ltd. "^hugsun,.*": From bfccc195192ea6ae72a4a49a85c94f1ad8ee7a13 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 25 Nov 2023 13:05:34 +0100 Subject: [PATCH 2298/7721] dt-bindings: arm: qcom: Add HTC One Mini 2 Document the compatible for the MSM8926-based HTC One Mini 2 smartphone. Acked-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231125-htc-memul-v3-2-e8f4c5839e23@z3ntu.xyz Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index ba0616445cdd..e09745a802fd 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -256,6 +256,11 @@ properties: - const: qcom,msm8916-v1-qrd/9-v1 - const: qcom,msm8916 + - items: + - enum: + - htc,memul + - const: qcom,msm8926 + - items: - enum: - motorola,potter From 2c21e5a84524381977b4744e906fb31862ac5809 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:44:30 +0100 Subject: [PATCH 2299/7721] arm64: dts: qcom: sc8180x: drop duplicated PCI iommus property The IOMMUs for PCI controller on SC8180x are defined in iommu-map, so drop duplicared iommus: sc8180x-lenovo-flex-5g.dtb: pci@1c08000: Unevaluated properties are not allowed ('iommus' was unexpected) Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231112184430.3495-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index a34f438ef2d9..00967811a808 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -1736,7 +1736,6 @@ pcie0: pci@1c00000 { assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1d80 0x7f>; iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, <0x100 &apps_smmu 0x1d81 0x1>; @@ -1833,7 +1832,6 @@ pcie3: pci@1c08000 { assigned-clocks = <&gcc GCC_PCIE_3_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1e00 0x7f>; iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, <0x100 &apps_smmu 0x1e01 0x1>; @@ -1931,7 +1929,6 @@ pcie1: pci@1c10000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1c80 0x7f>; iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, <0x100 &apps_smmu 0x1c81 0x1>; @@ -2029,7 +2026,6 @@ pcie2: pci@1c18000 { assigned-clocks = <&gcc GCC_PCIE_2_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1d00 0x7f>; iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, <0x100 &apps_smmu 0x1d01 0x1>; From 7ac90b4cf107a3999b30844d7899e0331686b33b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:28 -0800 Subject: [PATCH 2300/7721] arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered On sc7180 when the watchdog timer fires your logs get filled with: watchdog0: pretimeout event watchdog0: pretimeout event watchdog0: pretimeout event ... watchdog0: pretimeout event If you're using console-ramoops to debug crashes the above gets quite annoying since it blows away any other log messages that might have been there. The issue is that the "bark" interrupt (AKA the "pretimeout" interrupt) remains high until the watchdog is pet. Since we've got things configured as "level" triggered we'll keep getting interrupted over and over. Let's switch to edge triggered. Now we'll get one interrupt when the "bark" interrupt goes off and won't get another one until the "bark" interrupt is cleared and asserts again. This matches how many older Qualcomm SoCs have things configured. Fixes: 28cc13e4060c ("arm64: dts: qcom: sc7180: Add watchdog bark interrupt") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.1.Ic7577567baff921347d423b722de8b857602efb1@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 9664e42faeb1..f0f0709718ac 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -3580,7 +3580,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sc7180", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { From 6897fac411db7b43243f67d4fd4d3f95abf7f656 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:29 -0800 Subject: [PATCH 2301/7721] arm64: dts: qcom: sc7280: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 0e51f883daa9 ("arm64: dts: qcom: sc7280: Add APSS watchdog node") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.2.I11f77956d2492c88aca0ef5462123f225caf4fb4@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 41d327b1f1b6..a150131d4a8d 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -5394,7 +5394,7 @@ watchdog: watchdog@17c10000 { compatible = "qcom,apss-wdt-sc7280", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; status = "reserved"; /* Owned by Gunyah hyp */ }; From 263b348499454f38d36b9442c3cf9279c571bb54 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:30 -0800 Subject: [PATCH 2302/7721] arm64: dts: qcom: sdm845: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 36c436b03c58 ("arm64: dts: qcom: sdm845: Add watchdog bark interrupt") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.3.I16675ebe5517c68453a1bd7f4334ff885f806c03@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 9b62ca0229bd..b8d0fa283085 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -5105,7 +5105,7 @@ watchdog@17980000 { compatible = "qcom,apss-wdt-sdm845", "qcom,kpss-wdt"; reg = <0 0x17980000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; apss_shared: mailbox@17990000 { From 9204e9a4099212c850e1703c374ef4538080825b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:31 -0800 Subject: [PATCH 2303/7721] arm64: dts: qcom: sm8150: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: b094c8f8dd2a ("arm64: dts: qcom: sm8150: Add watchdog bark interrupt") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.4.I23d0aa6c8f1fec5c26ad9b3c610df6f4c5392850@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 7eee72415ebb..3cba87e00123 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -4163,7 +4163,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { From 735d80e2e8e5d073ae8b1fff8b1589ea284aa5af Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:32 -0800 Subject: [PATCH 2304/7721] arm64: dts: qcom: sm8250: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 46a4359f9156 ("arm64: dts: qcom: sm8250: Add watchdog bark interrupt") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.5.I2910e7c10493d896841e9785c1817df9b9a58701@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index f8abf9566024..9a64e8ab2046 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -6033,7 +6033,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sm8250", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { From 48d5cf4772ec6268853158d9ffc54612e988ebe6 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:33 -0800 Subject: [PATCH 2305/7721] arm64: dts: qcom: sa8775p: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 09b701b89a76 ("arm64: dts: qcom: sa8775p: add the watchdog node") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20231106144335.v2.6.I909b7c4453d7b7fb0db4b6e49aa21666279d827d@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index 13dd44dd9ed1..6b92f9083104 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -2235,7 +2235,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sa8775p", "qcom,kpss-wdt"; reg = <0x0 0x17c10000 0x0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; memtimer: timer@17c20000 { From 6c4a9c7ea486da490400c84ba2768c90d228c283 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:34 -0800 Subject: [PATCH 2306/7721] arm64: dts: qcom: sc8280xp: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 152d1faf1e2f ("arm64: dts: qcom: add SC8280XP platform") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.7.I1c8ab71570f6906fd020decb80675f05fbe1fe74@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 38cc823c9c87..2ef3c1c9eadf 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -4226,7 +4226,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sc8280xp", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { From 5b84bb2b8d86595544fc8272364b0f1a34b68a4f Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Nov 2023 14:43:35 -0800 Subject: [PATCH 2307/7721] arm64: dts: qcom: sm6350: Make watchdog bark interrupt edge triggered As described in the patch ("arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered"), the Qualcomm watchdog timer's bark interrupt should be configured as edge triggered. Make the change. Fixes: 5f82b9cda61e ("arm64: dts: qcom: Add SM6350 device tree") Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20231106144335.v2.8.Ic1d4402e99c70354d501ccd98105e908a902f671@changeid Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6350.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index 8fd6f4d03490..6464e144c228 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -2524,7 +2524,7 @@ watchdog@17c10000 { compatible = "qcom,apss-wdt-sm6350", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { From a5b2dcb96d6acb286459612a142371b0d74543bf Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 20 Sep 2023 13:13:58 -0700 Subject: [PATCH 2308/7721] drm: improve the documentation of connector hpd ops While making the changes in [1], it was noted that the documentation of the enable_hpd() and disable_hpd() does not make it clear that these ops should not try to do hpd state maintenance and should only enable/disable hpd related hardware for the connector. The state management of these calls to make sure these calls are balanced is handled by the DRM core and we should keep it that way to minimize the overhead in the drivers which implement these ops. [1]: https://patchwork.freedesktop.org/patch/558387/ Signed-off-by: Abhinav Kumar Suggested-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20230920201358.27597-1-quic_abhinavk@quicinc.com --- include/drm/drm_modeset_helper_vtables.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index e3c3ac615909..a33cf7488737 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -1154,6 +1154,11 @@ struct drm_connector_helper_funcs { * This operation is optional. * * This callback is used by the drm_kms_helper_poll_enable() helpers. + * + * This operation does not need to perform any hpd state tracking as + * the DRM core handles that maintenance and ensures the calls to enable + * and disable hpd are balanced. + * */ void (*enable_hpd)(struct drm_connector *connector); @@ -1165,6 +1170,11 @@ struct drm_connector_helper_funcs { * This operation is optional. * * This callback is used by the drm_kms_helper_poll_disable() helpers. + * + * This operation does not need to perform any hpd state tracking as + * the DRM core handles that maintenance and ensures the calls to enable + * and disable hpd are balanced. + * */ void (*disable_hpd)(struct drm_connector *connector); }; From f730e7adfd69d7ac859d8fe4d67e980cbad1e445 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 19 Sep 2023 10:48:12 -0700 Subject: [PATCH 2309/7721] drm: remove drm_bridge_hpd_disable() from drm_bridge_connector_destroy() drm_bridge_hpd_enable()/drm_bridge_hpd_disable() callbacks call into the respective driver's hpd_enable()/hpd_disable() ops. These ops control the HPD enable/disable logic which in some cases like MSM can be a dedicate hardware block to control the HPD. During probe_defer cases, a connector can be initialized and then later destroyed till the probe is retried. During connector destroy in these cases, the hpd_disable() callback gets called without a corresponding hpd_enable() leading to an unbalanced state potentially causing even a crash. This can be avoided by the respective drivers maintaining their own state logic to ensure that a hpd_disable() without a corresponding hpd_enable() just returns without doing anything. However, to have a generic fix it would be better to avoid the hpd_disable() callback from the connector destroy path and let the hpd_enable() / hpd_disable() balance be maintained by the corresponding drm_bridge_connector_enable_hpd() / drm_bridge_connector_disable_hpd() APIs which should get called by drm_kms_helper_disable_hpd(). changes in v2: - minor change in commit text (Dmitry) Signed-off-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Reviewed-by: Laurent Pinchart Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20230919174813.26958-1-quic_abhinavk@quicinc.com --- drivers/gpu/drm/drm_bridge_connector.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 8239ad43aed5..3acd67021ec6 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -198,12 +198,6 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector) struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector); - if (bridge_connector->bridge_hpd) { - struct drm_bridge *hpd = bridge_connector->bridge_hpd; - - drm_bridge_hpd_disable(hpd); - } - drm_connector_unregister(connector); drm_connector_cleanup(connector); From 97817a8275a1ec06773016c13c6f009535b53a6f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 25 Nov 2023 13:05:35 +0100 Subject: [PATCH 2310/7721] ARM: dts: qcom: Add support for HTC One Mini 2 Add support for this smartphone based on the MSM8926 SoC, codenamed "memul". Supported functionality: * Power & volume buttons * ADSP * Magnetometer * Accelerometer * Touchscreen * Vibrator * SD card * Charger * USB Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231125-htc-memul-v3-3-e8f4c5839e23@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/qcom-msm8926-htc-memul.dts | 370 ++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 3dfb1c8cefb8..c13dddd3c683 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -29,6 +29,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8916-samsung-e7.dtb \ qcom-msm8916-samsung-grandmax.dtb \ qcom-msm8916-samsung-serranove.dtb \ + qcom-msm8926-htc-memul.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8960-samsung-expressatt.dtb \ qcom-msm8974-lge-nexus5-hammerhead.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts new file mode 100644 index 000000000000..9e90330a6231 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Luca Weiss + */ + +/dts-v1/; + +#include "qcom-msm8226.dtsi" +#include "pm8226.dtsi" + +/delete-node/ &adsp_region; +/delete-node/ &smem_region; + +/ { + model = "HTC One Mini 2"; + compatible = "htc,memul", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; + + aliases { + mmc1 = &sdhc_2; /* SDC2 SD card slot */ + }; + + gpio-keys { + compatible = "gpio-keys"; + + key-power { + label = "Power"; + gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + + key-volume-down { + label = "Volume Down"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + + key-volume-up { + label = "Volume Up"; + gpios = <&tlmm 108 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + }; + + reserved-memory { + unknown@5b00000 { + reg = <0x05b00000 0x200000>; + no-map; + }; + + unknown@7500000 { + reg = <0x07500000 0xb00000>; + no-map; + }; + + mpss_region: mpss@8000000 { + reg = <0x08000000 0x4f00000>; + no-map; + }; + + unknown@cf00000 { + reg = <0x0cf00000 0x200000>; + no-map; + }; + + mba_region: mba@d100000 { + reg = <0x0d100000 0x3a000>; + no-map; + }; + + unknown@d13a000 { + reg = <0x0d13a000 0xc6000>; + no-map; + }; + + wcnss_region: wcnss@d200000 { + reg = <0x0d200000 0x650000>; + no-map; + }; + + unknown@d850000 { + reg = <0x0d850000 0x3b0000>; + no-map; + }; + + adsp_region: adsp@dc00000 { + reg = <0x0dc00000 0x1400000>; + no-map; + }; + + unknown@f000000 { + reg = <0x0f000000 0x500000>; + no-map; + }; + + venus_region: venus@f500000 { + reg = <0x0f500000 0x500000>; + no-map; + }; + + smem_region: smem@fa00000 { + reg = <0x0fa00000 0x100000>; + no-map; + }; + + unknown@fb00000 { + reg = <0x0fb00000 0x1b00000>; + no-map; + }; + }; +}; + +&adsp { + firmware-name = "qcom/msm8926/memul/adsp.mbn"; + status = "okay"; +}; + +&blsp1_i2c2 { + status = "okay"; + + magnetometer@d { + compatible = "asahi-kasei,ak8963"; + reg = <0x0d>; + interrupts-extended = <&tlmm 66 IRQ_TYPE_EDGE_RISING>; + vdd-supply = <&pm8226_l19>; + vid-supply = <&pm8226_l28>; + }; + + accelerometer@18 { + compatible = "bosch,bma250e"; + reg = <0x18>; + interrupts-extended = <&tlmm 63 IRQ_TYPE_EDGE_RISING>; + vdd-supply = <&pm8226_l19>; + vddio-supply = <&pm8226_l28>; + }; +}; + +&blsp1_i2c4 { + status = "okay"; + + /* TFA9887 @ 34 */ + /* TFA9887 @ 35 */ +}; + +&blsp1_i2c5 { + status = "okay"; + + touchscreen@20 { + compatible = "syna,rmi4-i2c"; + reg = <0x20>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l19>; + + syna,startup-delay-ms = <160>; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + + rmi4-f12@12 { + reg = <0x12>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c6 { + status = "okay"; + + /* NCP6924 Camera Regulators @ 10 */ + /* PN544 NFC @ 28 */ + /* TPS61310 Flash/Torch @ 33 */ +}; + +&pm8226_vib { + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-pm8226-regulators"; + + pm8226_s3: s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + }; + + pm8226_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2200000>; + }; + + pm8226_s5: s5 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l1: l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l3: l3 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1337500>; + }; + + pm8226_l4: l4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l5: l5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + pm8226_l8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l9: l9 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l10: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l12: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l14: l14 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + }; + + pm8226_l15: l15 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l16: l16 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3350000>; + }; + + pm8226_l17: l17 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l18: l18 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l19: l19 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l20: l20 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + pm8226_l21: l21 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + }; + + pm8226_l22: l22 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l23: l23 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l24: l24 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1350000>; + }; + + pm8226_l25: l25 { + regulator-min-microvolt = <1775000>; + regulator-max-microvolt = <2125000>; + }; + + pm8226_l26: l26 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l27: l27 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l28: l28 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_lvs1: lvs1 {}; + }; +}; + +&sdhc_2 { + vmmc-supply = <&pm8226_l18>; + vqmmc-supply = <&pm8226_l21>; + + bus-width = <4>; + cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + + status = "okay"; +}; + +&smbb { + qcom,fast-charge-safe-current = <1750000>; + qcom,fast-charge-current-limit = <1750000>; + qcom,fast-charge-safe-voltage = <4360000>; + qcom,fast-charge-high-threshold-voltage = <4350000>; + qcom,auto-recharge-threshold-voltage = <4300000>; + qcom,minimum-input-voltage = <4300000>; +}; + +&usb { + extcon = <&smbb>; + dr_mode = "peripheral"; + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&smbb>; + v1p8-supply = <&pm8226_l10>; + v3p3-supply = <&pm8226_l20>; +}; From e84e61bdb97c14cf989094394c6e6a6dcb1a3381 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 30 Nov 2023 15:58:22 +0100 Subject: [PATCH 2311/7721] soc: qcom: stats: Add DDR sleep stats Add DDR sleep stats that include: - the available RAM low power states - per-state residency information - per-frequency residency information (for some freqs only, it seems) - DDR vote information (AB/IB) and some magic thing that we're yet to decode. Based on the msm-5.4 downstream implementation, debugged with some help from Qualcomm's Maulik Shah. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231130-topic-ddr_sleep_stats-v1-2-5981c2e764b6@linaro.org [bjorn: Add missing bitfield.h include] Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_stats.c | 187 +++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 0216fc24f2ca..4763d62a8cb0 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -3,6 +3,7 @@ * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -11,6 +12,7 @@ #include #include +#include #include #include @@ -22,8 +24,20 @@ #define LAST_ENTERED_AT_OFFSET 0x8 #define LAST_EXITED_AT_OFFSET 0x10 #define ACCUMULATED_OFFSET 0x18 +#define DDR_DYNAMIC_OFFSET 0x1c + #define DDR_OFFSET_MASK GENMASK(9, 0) #define CLIENT_VOTES_OFFSET 0x20 +#define ARCH_TIMER_FREQ 19200000 +#define DDR_MAGIC_KEY1 0xA1157A75 /* leetspeak "ALLSTATS" */ +#define DDR_MAX_NUM_ENTRIES 20 + +#define DDR_VOTE_DRV_MAX 18 +#define DDR_VOTE_DRV_ABSENT 0xdeaddead +#define DDR_VOTE_DRV_INVALID 0xffffdead +#define DDR_VOTE_X GENMASK(27, 14) +#define DDR_VOTE_Y GENMASK(13, 0) + struct subsystem_data { const char *name; u32 smem_item; @@ -48,6 +62,7 @@ struct stats_config { bool appended_stats_avail; bool dynamic_offset; bool subsystem_stats_in_smem; + bool ddr_stats; }; struct stats_data { @@ -68,6 +83,25 @@ struct appended_stats { u32 reserved[3]; }; +struct ddr_stats_entry { + u32 name; + u32 count; + u64 dur; +} __packed; + +struct ddr_stats { + u32 key; + u32 entry_count; +#define MAX_DDR_STAT_ENTRIES 20 + struct ddr_stats_entry entry[MAX_DDR_STAT_ENTRIES]; +} __packed; + +struct ddr_stats_data { + struct device *dev; + void __iomem *base; + struct qmp *qmp; +}; + static void qcom_print_stats(struct seq_file *s, const struct sleep_stats *stat) { u64 accumulated = stat->accumulated; @@ -118,6 +152,108 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused) return 0; } +#define DDR_NAME_TYPE GENMASK(15, 8) + #define DDR_NAME_TYPE_LPM 0 + #define DDR_NAME_TYPE_FREQ 1 + +#define DDR_NAME_LPM_NAME GENMASK(7, 0) + +#define DDR_NAME_FREQ_MHZ GENMASK(31, 16) +#define DDR_NAME_FREQ_CP_IDX GENMASK(4, 0) +static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *entry) +{ + u32 cp_idx, name; + u8 type; + + type = FIELD_GET(DDR_NAME_TYPE, entry->name); + + switch (type) { + case DDR_NAME_TYPE_LPM: + name = FIELD_GET(DDR_NAME_LPM_NAME, entry->name); + + seq_printf(s, "LPM | Type 0x%2x\tcount: %u\ttime: %llums\n", + name, entry->count, entry->dur); + break; + case DDR_NAME_TYPE_FREQ: + cp_idx = FIELD_GET(DDR_NAME_FREQ_CP_IDX, entry->name); + name = FIELD_GET(DDR_NAME_FREQ_MHZ, entry->name); + + /* Neither 0Mhz nor 0 votes is very interesting */ + if (!name || !entry->count) + return; + + seq_printf(s, "Freq | %dMHz (idx %u)\tcount: %u\ttime: %llums\n", + name, cp_idx, entry->count, entry->dur); + break; + default: + seq_printf(s, "Unknown data chunk (type = 0x%x count = 0x%x dur = 0x%llx)\n", + type, entry->count, entry->dur); + } +} + +static int qcom_ddr_stats_show(struct seq_file *s, void *unused) +{ + struct ddr_stats_data *ddrd = s->private; + struct ddr_stats ddr; + struct ddr_stats_entry *entry = ddr.entry; + u32 entry_count, stats_size; + u32 votes[DDR_VOTE_DRV_MAX]; + int i, ret; + + /* Request a stats sync, it may take some time to update though.. */ + ret = qmp_send(ddrd->qmp, "{class: ddr, action: freqsync}"); + if (ret) { + dev_err(ddrd->dev, "failed to send QMP message\n"); + return ret; + } + + entry_count = readl(ddrd->base + offsetof(struct ddr_stats, entry_count)); + if (entry_count > DDR_MAX_NUM_ENTRIES) + return -EINVAL; + + /* We're not guaranteed to have DDR_MAX_NUM_ENTRIES */ + stats_size = sizeof(ddr); + stats_size -= DDR_MAX_NUM_ENTRIES * sizeof(*entry); + stats_size += entry_count * sizeof(*entry); + + /* Copy and process the stats */ + memcpy_fromio(&ddr, ddrd->base, stats_size); + + for (i = 0; i < ddr.entry_count; i++) { + /* Convert the period to ms */ + entry[i].dur = mult_frac(MSEC_PER_SEC, entry[i].dur, ARCH_TIMER_FREQ); + } + + for (i = 0; i < ddr.entry_count; i++) + qcom_ddr_stats_print(s, &entry[i]); + + /* Ask AOSS to dump DDR votes */ + ret = qmp_send(ddrd->qmp, "{class: ddr, res: drvs_ddr_votes}"); + if (ret) { + dev_err(ddrd->dev, "failed to send QMP message\n"); + return ret; + } + + /* Subsystem votes */ + memcpy_fromio(votes, ddrd->base + stats_size, sizeof(u32) * DDR_VOTE_DRV_MAX); + + for (i = 0; i < DDR_VOTE_DRV_MAX; i++) { + u32 ab, ib; + + if (votes[i] == DDR_VOTE_DRV_ABSENT || votes[i] == DDR_VOTE_DRV_INVALID) + ab = ib = votes[i]; + else { + ab = FIELD_GET(DDR_VOTE_X, votes[i]); + ib = FIELD_GET(DDR_VOTE_Y, votes[i]); + } + + seq_printf(s, "Vote | AB = %5u\tIB = %5u\n", ab, ib); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats); DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats); DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats); @@ -180,13 +316,56 @@ static void qcom_create_subsystem_stat_files(struct dentry *root, &qcom_subsystem_sleep_stats_fops); } +static int qcom_create_ddr_stats_files(struct device *dev, + struct dentry *root, + void __iomem *reg, + const struct stats_config *config) +{ + struct ddr_stats_data *ddrd; + u32 key, stats_offset; + struct dentry *dent; + + /* Nothing to do */ + if (!config->ddr_stats) + return 0; + + ddrd = devm_kzalloc(dev, sizeof(*ddrd), GFP_KERNEL); + if (!ddrd) + return dev_err_probe(dev, -ENOMEM, "Couldn't allocate DDR stats data\n"); + + ddrd->dev = dev; + + /* Get the offset of DDR stats */ + stats_offset = readl(reg + DDR_DYNAMIC_OFFSET) & DDR_OFFSET_MASK; + ddrd->base = reg + stats_offset; + + /* Check if DDR stats are present */ + key = readl(ddrd->base); + if (key != DDR_MAGIC_KEY1) + return 0; + + dent = debugfs_create_file("ddr_sleep_stats", 0400, root, ddrd, &qcom_ddr_stats_fops); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + /* QMP is only necessary for DDR votes */ + ddrd->qmp = qmp_get(dev); + if (IS_ERR(ddrd->qmp)) { + dev_err(dev, "Couldn't get QMP mailbox: %ld. DDR votes won't be available.\n", + PTR_ERR(ddrd->qmp)); + debugfs_remove(dent); + } + + return 0; +} + static int qcom_stats_probe(struct platform_device *pdev) { void __iomem *reg; struct dentry *root; const struct stats_config *config; struct stats_data *d; - int i; + int i, ret; config = device_get_match_data(&pdev->dev); if (!config) @@ -208,6 +387,11 @@ static int qcom_stats_probe(struct platform_device *pdev) qcom_create_subsystem_stat_files(root, config); qcom_create_soc_sleep_stat_files(root, reg, d, config); + ret = qcom_create_ddr_stats_files(&pdev->dev, root, reg, config); + if (ret) { + debugfs_remove_recursive(root); + return ret; + }; platform_set_drvdata(pdev, root); @@ -254,6 +438,7 @@ static const struct stats_config rpmh_data = { .appended_stats_avail = false, .dynamic_offset = false, .subsystem_stats_in_smem = true, + .ddr_stats = true, }; static const struct of_device_id qcom_stats_table[] = { From 72207699ff76d4392244c8d9850aaef0160dc6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Sun, 3 Dec 2023 13:48:37 +0200 Subject: [PATCH 2312/7721] drm/i915/display: use intel_bo_to_drm_bo in intel_fb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe driver. I915 and Xe object implementation are differing. Do not use i915_gem_object->base directly. Instead use intel_bo_to_drm_bo. Also use drm_gem_object_put instead of i915_gem_object_put. This should be ok as i915_gem_object_put is really just doing __drm_gem_object_put. Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231203114840.841311-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 77226ec00cb1..b17600aba577 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1657,10 +1657,10 @@ int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer * max_size = max(max_size, offset + size); } - if (mul_u32_u32(max_size, tile_size) > obj->base.size) { + if (mul_u32_u32(max_size, tile_size) > intel_bo_to_drm_bo(obj)->size) { drm_dbg_kms(&i915->drm, "fb too big for bo (need %llu bytes, have %zu bytes)\n", - mul_u32_u32(max_size, tile_size), obj->base.size); + mul_u32_u32(max_size, tile_size), intel_bo_to_drm_bo(obj)->size); return -EINVAL; } @@ -1889,7 +1889,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, unsigned int *handle) { struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct drm_i915_private *i915 = to_i915(intel_bo_to_drm_bo(obj)->dev); if (i915_gem_object_is_userptr(obj)) { drm_dbg(&i915->drm, @@ -1897,7 +1897,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return -EINVAL; } - return drm_gem_handle_create(file, &obj->base, handle); + return drm_gem_handle_create(file, intel_bo_to_drm_bo(obj), handle); } struct frontbuffer_fence_cb { @@ -1975,7 +1975,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd) { - struct drm_i915_private *dev_priv = to_i915(obj->base.dev); + struct drm_i915_private *dev_priv = to_i915(intel_bo_to_drm_bo(obj)->dev); struct drm_framebuffer *fb = &intel_fb->base; u32 max_stride; unsigned int tiling, stride; @@ -2153,7 +2153,7 @@ intel_user_framebuffer_create(struct drm_device *dev, } fb = intel_framebuffer_create(obj, &mode_cmd); - i915_gem_object_put(obj); + drm_gem_object_put(intel_bo_to_drm_bo(obj)); return fb; } From 6383f69bd2ccd4765b22d60f12576891daa36c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Sun, 3 Dec 2023 13:48:38 +0200 Subject: [PATCH 2313/7721] drm/i915/display: Convert intel_fb_modifier_to_tiling as non-static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are about to split i915 specific code from intel_fb.c. Convert intel_fb_modifier_to_tiling as non-static to allow calling it from split code. Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231203114840.841311-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 40 ++++++++++++------------- drivers/gpu/drm/i915/display/intel_fb.h | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index b17600aba577..f42a693f96c1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -301,6 +301,26 @@ lookup_format_info(const struct drm_format_info formats[], return NULL; } +unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) +{ + u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps & + INTEL_PLANE_CAP_TILING_MASK; + + switch (tiling_caps) { + case INTEL_PLANE_CAP_TILING_Y: + return I915_TILING_Y; + case INTEL_PLANE_CAP_TILING_X: + return I915_TILING_X; + case INTEL_PLANE_CAP_TILING_4: + case INTEL_PLANE_CAP_TILING_Yf: + case INTEL_PLANE_CAP_TILING_NONE: + return I915_TILING_NONE; + default: + MISSING_CASE(tiling_caps); + return I915_TILING_NONE; + } +} + /** * intel_fb_get_format_info: Get a modifier specific format information * @cmd: FB add command structure @@ -737,26 +757,6 @@ intel_fb_align_height(const struct drm_framebuffer *fb, return ALIGN(height, tile_height); } -static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) -{ - u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps & - INTEL_PLANE_CAP_TILING_MASK; - - switch (tiling_caps) { - case INTEL_PLANE_CAP_TILING_Y: - return I915_TILING_Y; - case INTEL_PLANE_CAP_TILING_X: - return I915_TILING_X; - case INTEL_PLANE_CAP_TILING_4: - case INTEL_PLANE_CAP_TILING_Yf: - case INTEL_PLANE_CAP_TILING_NONE: - return I915_TILING_NONE; - default: - MISSING_CASE(tiling_caps); - return I915_TILING_NONE; - } -} - bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) { return HAS_DPT(i915) && modifier != DRM_FORMAT_MOD_LINEAR; diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index e85167d6bc34..23db6628f53e 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -95,4 +95,6 @@ intel_user_framebuffer_create(struct drm_device *dev, bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier); bool intel_fb_uses_dpt(const struct drm_framebuffer *fb); +unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier); + #endif /* __INTEL_FB_H__ */ From ae424921a5ca763fef4be46f900065db0b0870ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Sun, 3 Dec 2023 13:48:39 +0200 Subject: [PATCH 2314/7721] drm/i915/display: Handle invalid fb_modifier in intel_fb_modifier_to_tiling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lookup_modifier is returning INTEL_PLANE_CAP_TILING_4 on invalid fb_modifier value. Use lookup_modifier_or_null in intel_fb_modifier_to_tiling and return I915_TILING_NONE in case lookup_modifier_or_null returns null. Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231203114840.841311-4-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index f42a693f96c1..20d58a021a42 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -303,7 +303,14 @@ lookup_format_info(const struct drm_format_info formats[], unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) { - u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps & + const struct intel_modifier_desc *md; + u8 tiling_caps; + + md = lookup_modifier_or_null(fb_modifier); + if (!md) + return I915_TILING_NONE; + + tiling_caps = lookup_modifier_or_null(fb_modifier)->plane_caps & INTEL_PLANE_CAP_TILING_MASK; switch (tiling_caps) { From 5f449ed05da8bb2a470b17962978f0347ba399d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Sun, 3 Dec 2023 13:48:40 +0200 Subject: [PATCH 2315/7721] drm/i915/display: Split i915 specific code away from intel_fb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are preparing for Xe driver. Backing object implementation is differing between i915 and Xe. Split i915 specific code into separate source file built only for i915. v9: - Use ERR_CAST v8: - return original error code from intel_fb_bo_lookup_valid_bo on failure v7: - drop #include - s/user_mode_cmd/mode_cmd/ - Use passed i915 pointer instead of to_i915(obj->base.dev) v6: Add missing intel_fb_bo.[ch] v5: - Keep drm_any_plane_has_format check in intel_fb.c - Use mode_cmd instead of user_mode_cmd for intel_fb_bo_lookup_valid_bo v4: Move drm_any_plane_has_format check into intel_fb_bo.c v3: Fix failure handling in intel_framebuffer_init v2: Couple of fixes to error value handling Signed-off-by: Jouni Högander Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231203114840.841311-5-jouni.hogander@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_fb.c | 71 +++-------------- drivers/gpu/drm/i915/display/intel_fb_bo.c | 92 ++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fb_bo.h | 24 ++++++ 4 files changed, 126 insertions(+), 62 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_fb_bo.c create mode 100644 drivers/gpu/drm/i915/display/intel_fb_bo.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index eadc9e612962..e777686190ca 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -280,6 +280,7 @@ i915-y += \ display/intel_dsb.o \ display/intel_dsb_buffer.o \ display/intel_fb.o \ + display/intel_fb_bo.o \ display/intel_fb_pin.o \ display/intel_fbc.o \ display/intel_fdi.o \ diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 20d58a021a42..96663f9ac431 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -15,6 +14,7 @@ #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" +#include "intel_fb_bo.h" #include "intel_frontbuffer.h" #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) @@ -1985,7 +1985,6 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_i915_private *dev_priv = to_i915(intel_bo_to_drm_bo(obj)->dev); struct drm_framebuffer *fb = &intel_fb->base; u32 max_stride; - unsigned int tiling, stride; int ret = -EINVAL; int i; @@ -1993,32 +1992,11 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (!intel_fb->frontbuffer) return -ENOMEM; - i915_gem_object_lock(obj, NULL); - tiling = i915_gem_object_get_tiling(obj); - stride = i915_gem_object_get_stride(obj); - i915_gem_object_unlock(obj); - - if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { - /* - * If there's a fence, enforce that - * the fb modifier and tiling mode match. - */ - if (tiling != I915_TILING_NONE && - tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { - drm_dbg_kms(&dev_priv->drm, - "tiling_mode doesn't match fb modifier\n"); - goto err; - } - } else { - if (tiling == I915_TILING_X) { - mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED; - } else if (tiling == I915_TILING_Y) { - drm_dbg_kms(&dev_priv->drm, - "No Y tiling for legacy addfb\n"); - goto err; - } - } + ret = intel_fb_bo_framebuffer_init(intel_fb, obj, mode_cmd); + if (ret) + goto err; + ret = -EINVAL; if (!drm_any_plane_has_format(&dev_priv->drm, mode_cmd->pixel_format, mode_cmd->modifier[0])) { @@ -2028,17 +2006,6 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, goto err; } - /* - * gen2/3 display engine uses the fence if present, - * so the tiling mode must match the fb modifier exactly. - */ - if (DISPLAY_VER(dev_priv) < 4 && - tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { - drm_dbg_kms(&dev_priv->drm, - "tiling_mode must match fb modifier exactly on gen2/3\n"); - goto err; - } - max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format, mode_cmd->modifier[0]); if (mode_cmd->pitches[0] > max_stride) { @@ -2050,17 +2017,6 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, goto err; } - /* - * If there's a fence, enforce that - * the fb pitch and fence stride match. - */ - if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) { - drm_dbg_kms(&dev_priv->drm, - "pitch (%d) must match tiling stride (%d)\n", - mode_cmd->pitches[0], stride); - goto err; - } - /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ if (mode_cmd->offsets[0] != 0) { drm_dbg_kms(&dev_priv->drm, @@ -2144,20 +2100,11 @@ intel_user_framebuffer_create(struct drm_device *dev, struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; - struct drm_i915_private *i915; + struct drm_i915_private *i915 = to_i915(dev); - obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - /* object is backed with LMEM for discrete */ - i915 = to_i915(obj->base.dev); - if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) { - /* object is "remote", not in local memory */ - i915_gem_object_put(obj); - drm_dbg_kms(&i915->drm, "framebuffer must reside in local memory\n"); - return ERR_PTR(-EREMOTE); - } + obj = intel_fb_bo_lookup_valid_bo(i915, filp, &mode_cmd); + if (IS_ERR(obj)) + return ERR_CAST(obj); fb = intel_framebuffer_create(obj, &mode_cmd); drm_gem_object_put(intel_bo_to_drm_bo(obj)); diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.c b/drivers/gpu/drm/i915/display/intel_fb_bo.c new file mode 100644 index 000000000000..ce86eff7b226 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#include + +#include "gem/i915_gem_object.h" + +#include "i915_drv.h" +#include "intel_fb.h" +#include "intel_fb_bo.h" + +int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, + struct drm_i915_gem_object *obj, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + unsigned int tiling, stride; + + i915_gem_object_lock(obj, NULL); + tiling = i915_gem_object_get_tiling(obj); + stride = i915_gem_object_get_stride(obj); + i915_gem_object_unlock(obj); + + if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { + /* + * If there's a fence, enforce that + * the fb modifier and tiling mode match. + */ + if (tiling != I915_TILING_NONE && + tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { + drm_dbg_kms(&i915->drm, + "tiling_mode doesn't match fb modifier\n"); + return -EINVAL; + } + } else { + if (tiling == I915_TILING_X) { + mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED; + } else if (tiling == I915_TILING_Y) { + drm_dbg_kms(&i915->drm, + "No Y tiling for legacy addfb\n"); + return -EINVAL; + } + } + + /* + * gen2/3 display engine uses the fence if present, + * so the tiling mode must match the fb modifier exactly. + */ + if (DISPLAY_VER(i915) < 4 && + tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { + drm_dbg_kms(&i915->drm, + "tiling_mode must match fb modifier exactly on gen2/3\n"); + return -EINVAL; + } + + /* + * If there's a fence, enforce that + * the fb pitch and fence stride match. + */ + if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) { + drm_dbg_kms(&i915->drm, + "pitch (%d) must match tiling stride (%d)\n", + mode_cmd->pitches[0], stride); + return -EINVAL; + } + + return 0; +} + +struct drm_i915_gem_object * +intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915, + struct drm_file *filp, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_lookup(filp, mode_cmd->handles[0]); + if (!obj) + return ERR_PTR(-ENOENT); + + /* object is backed with LMEM for discrete */ + if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) { + /* object is "remote", not in local memory */ + i915_gem_object_put(obj); + drm_dbg_kms(&i915->drm, "framebuffer must reside in local memory\n"); + return ERR_PTR(-EREMOTE); + } + + return obj; +} diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.h b/drivers/gpu/drm/i915/display/intel_fb_bo.h new file mode 100644 index 000000000000..dd06ceec8601 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_FB_BO_H__ +#define __INTEL_FB_BO_H__ + +struct drm_file; +struct drm_mode_fb_cmd2; +struct drm_i915_gem_object; +struct drm_i915_private; +struct intel_framebuffer; + +int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, + struct drm_i915_gem_object *obj, + struct drm_mode_fb_cmd2 *mode_cmd); + +struct drm_i915_gem_object * +intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915, + struct drm_file *filp, + const struct drm_mode_fb_cmd2 *user_mode_cmd); + +#endif From 52816298bd2a1e8c6fb3d9311730c00ef03c1f03 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 1 Dec 2023 15:08:40 +0100 Subject: [PATCH 2316/7721] dt-bindings: gpio: rockchip: add a pattern for gpio hogs Allow validating gpio-hogs defined inside the gpio controller node. Signed-off-by: Heiko Stuebner Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/rockchip,gpio-bank.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml index affd823c881d..d76987ce8e50 100644 --- a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml +++ b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml @@ -41,6 +41,13 @@ properties: "#interrupt-cells": const: 2 +patternProperties: + "^.+-hog(-[0-9]+)?$": + type: object + + required: + - gpio-hog + required: - compatible - reg From 93032ae634d409e621c68a2fb7d6930e7eebb1d9 Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Thu, 30 Nov 2023 18:14:16 +0100 Subject: [PATCH 2317/7721] drm/test: add a test suite for GEM objects backed by shmem This patch introduces an initial KUnit test suite for GEM objects backed by shmem buffers. Suggested-by: Javier Martinez Canillas Signed-off-by: Marco Pagani v5: - using __drm_kunit_helper_alloc_drm_device() to avoid local struct v4: - Add missing MMU dependency for DRM_GEM_SHMEM_HELPER (kernel test robot) v3: - Explicitly cast pointers in the helpers - Removed unused pointer to parent dev in struct fake_dev - Test entries reordering in Kconfig and Makefile sent as a separate patch v2: - Improved description of test cases - Cleaner error handling using KUnit actions - Alphabetical order in Kconfig and Makefile Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231130171417.74162-1-marpagan@redhat.com --- drivers/gpu/drm/Kconfig | 3 +- drivers/gpu/drm/tests/Makefile | 1 + drivers/gpu/drm/tests/drm_gem_shmem_test.c | 383 +++++++++++++++++++++ 3 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/tests/drm_gem_shmem_test.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 740c1c0bd068..b7abd436455f 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -74,12 +74,13 @@ config DRM_KUNIT_TEST_HELPERS config DRM_KUNIT_TEST tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS - depends on DRM && KUNIT + depends on DRM && KUNIT && MMU select DRM_BUDDY select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER select DRM_EXEC select DRM_EXPORT_FOR_TESTS if m + select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER select DRM_KUNIT_TEST_HELPERS select DRM_LIB_RANDOM diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index 2645af241ff0..d6183b3d7688 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_format_helper_test.o \ drm_format_test.o \ drm_framebuffer_test.o \ + drm_gem_shmem_test.o \ drm_managed_test.o \ drm_mm_test.o \ drm_modes_test.o \ diff --git a/drivers/gpu/drm/tests/drm_gem_shmem_test.c b/drivers/gpu/drm/tests/drm_gem_shmem_test.c new file mode 100644 index 000000000000..91202e40cde9 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_gem_shmem_test.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test suite for GEM objects backed by shmem buffers + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define TEST_SIZE SZ_1M +#define TEST_BYTE 0xae + +/* + * Wrappers to avoid an explicit type casting when passing action + * functions to kunit_add_action(). + */ +static void kfree_wrapper(void *ptr) +{ + const void *obj = ptr; + + kfree(obj); +} + +static void sg_free_table_wrapper(void *ptr) +{ + struct sg_table *sgt = ptr; + + sg_free_table(sgt); +} + +static void drm_gem_shmem_free_wrapper(void *ptr) +{ + struct drm_gem_shmem_object *shmem = ptr; + + drm_gem_shmem_free(shmem); +} + +/* + * Test creating a shmem GEM object backed by shmem buffer. The test + * case succeeds if the GEM object is successfully allocated with the + * shmem file node and object functions attributes set, and the size + * attribute is equal to the correct size. + */ +static void drm_gem_shmem_test_obj_create(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + KUNIT_EXPECT_EQ(test, shmem->base.size, TEST_SIZE); + KUNIT_EXPECT_NOT_NULL(test, shmem->base.filp); + KUNIT_EXPECT_NOT_NULL(test, shmem->base.funcs); + + drm_gem_shmem_free(shmem); +} + +/* + * Test creating a shmem GEM object from a scatter/gather table exported + * via a DMA-BUF. The test case succeed if the GEM object is successfully + * created with the shmem file node attribute equal to NULL and the sgt + * attribute pointing to the scatter/gather table that has been imported. + */ +static void drm_gem_shmem_test_obj_create_private(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + struct drm_gem_object *gem_obj; + struct dma_buf buf_mock; + struct dma_buf_attachment attach_mock; + struct sg_table *sgt; + char *buf; + int ret; + + /* Create a mock scatter/gather table */ + buf = kunit_kzalloc(test, TEST_SIZE, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, buf); + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, sgt); + + ret = kunit_add_action_or_reset(test, kfree_wrapper, sgt); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = kunit_add_action_or_reset(test, sg_free_table_wrapper, sgt); + KUNIT_ASSERT_EQ(test, ret, 0); + + sg_init_one(sgt->sgl, buf, TEST_SIZE); + + /* Init a mock DMA-BUF */ + buf_mock.size = TEST_SIZE; + attach_mock.dmabuf = &buf_mock; + + gem_obj = drm_gem_shmem_prime_import_sg_table(drm_dev, &attach_mock, sgt); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gem_obj); + KUNIT_EXPECT_EQ(test, gem_obj->size, TEST_SIZE); + KUNIT_EXPECT_NULL(test, gem_obj->filp); + KUNIT_EXPECT_NOT_NULL(test, gem_obj->funcs); + + /* The scatter/gather table will be freed by drm_gem_shmem_free */ + kunit_remove_action(test, sg_free_table_wrapper, sgt); + kunit_remove_action(test, kfree_wrapper, sgt); + + shmem = to_drm_gem_shmem_obj(gem_obj); + KUNIT_EXPECT_PTR_EQ(test, shmem->sgt, sgt); + + drm_gem_shmem_free(shmem); +} + +/* + * Test pinning backing pages for a shmem GEM object. The test case + * succeeds if a suitable number of backing pages are allocated, and + * the pages table counter attribute is increased by one. + */ +static void drm_gem_shmem_test_pin_pages(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + int i, ret; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + KUNIT_EXPECT_NULL(test, shmem->pages); + KUNIT_EXPECT_EQ(test, shmem->pages_use_count, 0); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_gem_shmem_pin(shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_NOT_NULL(test, shmem->pages); + KUNIT_EXPECT_EQ(test, shmem->pages_use_count, 1); + + for (i = 0; i < (shmem->base.size >> PAGE_SHIFT); i++) + KUNIT_ASSERT_NOT_NULL(test, shmem->pages[i]); + + drm_gem_shmem_unpin(shmem); + KUNIT_EXPECT_NULL(test, shmem->pages); + KUNIT_EXPECT_EQ(test, shmem->pages_use_count, 0); +} + +/* + * Test creating a virtual mapping for a shmem GEM object. The test + * case succeeds if the backing memory is mapped and the reference + * counter for virtual mapping is increased by one. Moreover, the test + * case writes and then reads a test pattern over the mapped memory. + */ +static void drm_gem_shmem_test_vmap(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + struct iosys_map map; + int ret, i; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + KUNIT_EXPECT_NULL(test, shmem->vaddr); + KUNIT_EXPECT_EQ(test, shmem->vmap_use_count, 0); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_gem_shmem_vmap(shmem, &map); + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_NOT_NULL(test, shmem->vaddr); + KUNIT_ASSERT_FALSE(test, iosys_map_is_null(&map)); + KUNIT_EXPECT_EQ(test, shmem->vmap_use_count, 1); + + iosys_map_memset(&map, 0, TEST_BYTE, TEST_SIZE); + for (i = 0; i < TEST_SIZE; i++) + KUNIT_EXPECT_EQ(test, iosys_map_rd(&map, i, u8), TEST_BYTE); + + drm_gem_shmem_vunmap(shmem, &map); + KUNIT_EXPECT_NULL(test, shmem->vaddr); + KUNIT_EXPECT_EQ(test, shmem->vmap_use_count, 0); +} + +/* + * Test exporting a scatter/gather table of pinned pages suitable for + * PRIME usage from a shmem GEM object. The test case succeeds if a + * scatter/gather table large enough to accommodate the backing memory + * is successfully exported. + */ +static void drm_gem_shmem_test_get_pages_sgt(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + struct sg_table *sgt; + struct scatterlist *sg; + unsigned int si, len = 0; + int ret; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_gem_shmem_pin(shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + sgt = drm_gem_shmem_get_sg_table(shmem); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt); + KUNIT_EXPECT_NULL(test, shmem->sgt); + + ret = kunit_add_action_or_reset(test, sg_free_table_wrapper, sgt); + KUNIT_ASSERT_EQ(test, ret, 0); + + for_each_sgtable_sg(sgt, sg, si) { + KUNIT_EXPECT_NOT_NULL(test, sg); + len += sg->length; + } + + KUNIT_EXPECT_GE(test, len, TEST_SIZE); +} + +/* + * Test pinning pages and exporting a scatter/gather table suitable for + * driver usage from a shmem GEM object. The test case succeeds if the + * backing pages are pinned and a scatter/gather table large enough to + * accommodate the backing memory is successfully exported. + */ +static void drm_gem_shmem_test_get_sg_table(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + struct sg_table *sgt; + struct scatterlist *sg; + unsigned int si, ret, len = 0; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* The scatter/gather table will be freed by drm_gem_shmem_free */ + sgt = drm_gem_shmem_get_pages_sgt(shmem); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt); + KUNIT_ASSERT_NOT_NULL(test, shmem->pages); + KUNIT_EXPECT_EQ(test, shmem->pages_use_count, 1); + KUNIT_EXPECT_PTR_EQ(test, sgt, shmem->sgt); + + for_each_sgtable_sg(sgt, sg, si) { + KUNIT_EXPECT_NOT_NULL(test, sg); + len += sg->length; + } + + KUNIT_EXPECT_GE(test, len, TEST_SIZE); +} + +/* + * Test updating the madvise state of a shmem GEM object. The test + * case checks that the function for setting madv updates it only if + * its current value is greater or equal than zero and returns false + * if it has a negative value. + */ +static void drm_gem_shmem_test_madvise(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + int ret; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + KUNIT_ASSERT_EQ(test, shmem->madv, 0); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_gem_shmem_madvise(shmem, 1); + KUNIT_EXPECT_TRUE(test, ret); + KUNIT_ASSERT_EQ(test, shmem->madv, 1); + + /* Set madv to a negative value */ + ret = drm_gem_shmem_madvise(shmem, -1); + KUNIT_EXPECT_FALSE(test, ret); + KUNIT_ASSERT_EQ(test, shmem->madv, -1); + + /* Check that madv cannot be set back to a positive value */ + ret = drm_gem_shmem_madvise(shmem, 0); + KUNIT_EXPECT_FALSE(test, ret); + KUNIT_ASSERT_EQ(test, shmem->madv, -1); +} + +/* + * Test purging a shmem GEM object. First, assert that a newly created + * shmem GEM object is not purgeable. Then, set madvise to a positive + * value and call drm_gem_shmem_get_pages_sgt() to pin and dma-map the + * backing pages. Finally, assert that the shmem GEM object is now + * purgeable and purge it. + */ +static void drm_gem_shmem_test_purge(struct kunit *test) +{ + struct drm_device *drm_dev = test->priv; + struct drm_gem_shmem_object *shmem; + struct sg_table *sgt; + int ret; + + shmem = drm_gem_shmem_create(drm_dev, TEST_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shmem); + + ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_gem_shmem_is_purgeable(shmem); + KUNIT_EXPECT_FALSE(test, ret); + + ret = drm_gem_shmem_madvise(shmem, 1); + KUNIT_EXPECT_TRUE(test, ret); + + /* The scatter/gather table will be freed by drm_gem_shmem_free */ + sgt = drm_gem_shmem_get_pages_sgt(shmem); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt); + + ret = drm_gem_shmem_is_purgeable(shmem); + KUNIT_EXPECT_TRUE(test, ret); + + drm_gem_shmem_purge(shmem); + KUNIT_EXPECT_NULL(test, shmem->pages); + KUNIT_EXPECT_NULL(test, shmem->sgt); + KUNIT_EXPECT_EQ(test, shmem->madv, -1); +} + +static int drm_gem_shmem_test_init(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm_dev; + + /* Allocate a parent device */ + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + /* + * The DRM core will automatically initialize the GEM core and create + * a DRM Memory Manager object which provides an address space pool + * for GEM objects allocation. + */ + drm_dev = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm_dev), + 0, DRIVER_GEM); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm_dev); + + test->priv = drm_dev; + + return 0; +} + +static struct kunit_case drm_gem_shmem_test_cases[] = { + KUNIT_CASE(drm_gem_shmem_test_obj_create), + KUNIT_CASE(drm_gem_shmem_test_obj_create_private), + KUNIT_CASE(drm_gem_shmem_test_pin_pages), + KUNIT_CASE(drm_gem_shmem_test_vmap), + KUNIT_CASE(drm_gem_shmem_test_get_pages_sgt), + KUNIT_CASE(drm_gem_shmem_test_get_sg_table), + KUNIT_CASE(drm_gem_shmem_test_madvise), + KUNIT_CASE(drm_gem_shmem_test_purge), + {} +}; + +static struct kunit_suite drm_gem_shmem_suite = { + .name = "drm_gem_shmem", + .init = drm_gem_shmem_test_init, + .test_cases = drm_gem_shmem_test_cases +}; + +kunit_test_suite(drm_gem_shmem_suite); + +MODULE_LICENSE("GPL"); From 51097ef14d4e555c532ae535d24f97cc19c8c5a6 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 30 Nov 2023 16:00:13 +0000 Subject: [PATCH 2318/7721] drm/imagination: Fixed warning due to implicit cast to bool This line appears to confuse the compiler and had been noticed previously in clang-tidy output. There isn't anything fundamentally wrong that I can see. I suspect that it just looks like a mistake - hence the first note. By making the second operand an actual bool result, const correctness can be preserved while silencing the warning. >> drivers/gpu/drm/imagination/pvr_device_info.c:230:47: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] 230 | } else if (features_size == mapping_max_size && (mapping_max & 63)) { | ^ ~~~~~~~~~~~~~~~~~~ drivers/gpu/drm/imagination/pvr_device_info.c:230:47: note: use '&' for a bitwise operation 230 | } else if (features_size == mapping_max_size && (mapping_max & 63)) { | ^~ | & drivers/gpu/drm/imagination/pvr_device_info.c:230:47: note: remove constant to silence this warning 230 | } else if (features_size == mapping_max_size && (mapping_max & 63)) { | ~^~~~~~~~~~~~~~~~~~~~~ 1 warning generated. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311241752.3iLyyFcA-lkp@intel.com/ Fixes: f99f5f3ea7ef ("drm/imagination: Add GPU ID parsing and firmware loading") Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231130160017.259902-1-donald.robson@imgtec.com --- drivers/gpu/drm/imagination/pvr_device_info.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_device_info.c b/drivers/gpu/drm/imagination/pvr_device_info.c index 11e6bef52ecd..d3301cde7d11 100644 --- a/drivers/gpu/drm/imagination/pvr_device_info.c +++ b/drivers/gpu/drm/imagination/pvr_device_info.c @@ -227,7 +227,8 @@ int pvr_device_info_set_features(struct pvr_device *pvr_dev, const u64 *features /* Verify no unsupported values in the bitmask. */ if (features_size > mapping_max_size) { drm_warn(from_pvr_device(pvr_dev), "Unsupported features in firmware image"); - } else if (features_size == mapping_max_size && (mapping_max & 63)) { + } else if (features_size == mapping_max_size && + ((mapping_max & 63) != 0)) { u64 invalid_mask = ~0ull << (mapping_max & 63); if (features[features_size - 1] & invalid_mask) From 0ffe9eb826f1391d52089ba8056a3778688da57d Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 30 Nov 2023 16:00:14 +0000 Subject: [PATCH 2319/7721] drm/imagination: Fixed missing header in pvr_fw_meta A missing header causes the compiler to warn that the function below is not forward declared. >> drivers/gpu/drm/imagination/pvr_fw_meta.c:33:1: warning: no previous prototype for function 'pvr_meta_cr_read32' [-Wmissing-prototypes] 33 | pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out) | ^ drivers/gpu/drm/imagination/pvr_fw_meta.c:32:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 32 | int | ^ | static 1 warning generated. Include the correct header. Reported-by: Arnd Bergmann Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311250226.Da2yiSKp-lkp@intel.com/ Fixes: cc1aeedb98ad ("drm/imagination: Implement firmware infrastructure and META FW support") Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231130160017.259902-2-donald.robson@imgtec.com --- drivers/gpu/drm/imagination/pvr_fw_meta.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.c b/drivers/gpu/drm/imagination/pvr_fw_meta.c index 119934c36184..c39beb70c317 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_meta.c +++ b/drivers/gpu/drm/imagination/pvr_fw_meta.c @@ -4,6 +4,7 @@ #include "pvr_device.h" #include "pvr_fw.h" #include "pvr_fw_info.h" +#include "pvr_fw_meta.h" #include "pvr_gem.h" #include "pvr_rogue_cr_defs.h" #include "pvr_rogue_meta.h" From 7620c6bd76b1076b104926b78da8d6ff17cfef5d Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 30 Nov 2023 16:00:15 +0000 Subject: [PATCH 2320/7721] drm/imagination: pvr_device_process_active_queues now static The function below is used only within this source file, but is not static. >> drivers/gpu/drm/imagination/pvr_device.c:129:6: warning: no previous prototype for function 'pvr_device_process_active_queues' [-Wmissing-prototypes] 129 | void pvr_device_process_active_queues(struct pvr_device *pvr_dev) | ^ drivers/gpu/drm/imagination/pvr_device.c:129:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 129 | void pvr_device_process_active_queues(struct pvr_device *pvr_dev) | ^ | static 1 warning generated. Make it static. Reported-by: Arnd Bergmann Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311250632.giVEx7MU-lkp@intel.com/ Fixes: eaf01ee5ba28 ("drm/imagination: Implement job submission and scheduling") Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231130160017.259902-3-donald.robson@imgtec.com --- drivers/gpu/drm/imagination/pvr_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 5389aea7ff21..1704c0268589 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -127,7 +127,7 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev) * This is called any time we receive a FW event. It iterates over all * active queues and calls pvr_queue_process() on them. */ -void pvr_device_process_active_queues(struct pvr_device *pvr_dev) +static void pvr_device_process_active_queues(struct pvr_device *pvr_dev) { struct pvr_queue *queue, *tmp_queue; LIST_HEAD(active_queues); From e8878b8043a25a19d0b405a29652a0cb94f56cdb Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 30 Nov 2023 16:00:16 +0000 Subject: [PATCH 2321/7721] drm/imagination: pvr_gpuvm_free() now static The function below is used only within this source file, but is not static. drivers/gpu/drm/imagination/pvr_vm.c:542:6: error: no previous prototype for 'pvr_gpuvm_free' [-Werror=missing-prototypes] 542 | void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) Make it static. Reported-by: Arnd Bergmann Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311242159.hh8MWiAm-lkp@intel.com/ Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Donald Robson Link: https://lore.kernel.org/r/20231130160017.259902-4-donald.robson@imgtec.com Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/pvr_vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 2aab53594a77..30ecd7d7052e 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -539,7 +539,7 @@ pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, (device_addr + size <= PVR_PAGE_TABLE_ADDR_SPACE_SIZE); } -void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) +static void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) { kfree(to_pvr_vm_context(gpuvm)); } From 72ef65ab246e55847097d68e0964fbcdfff4366c Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 30 Nov 2023 16:00:17 +0000 Subject: [PATCH 2322/7721] drm/imagination: Removed unused function to_pvr_vm_gpuva() This function is now unused, hence it causes a compiler warning. drivers/gpu/drm/imagination/pvr_vm.c:112:22: warning: unused function 'to_pvr_vm_gpuva' [-Wunused-function] 112 | struct pvr_vm_gpuva *to_pvr_vm_gpuva(struct drm_gpuva *gpuva) | ^ Remove the function for now. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311242159.hh8MWiAm-lkp@intel.com/ Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231130160017.259902-5-donald.robson@imgtec.com --- drivers/gpu/drm/imagination/pvr_vm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 30ecd7d7052e..6f4e07effad2 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -114,12 +114,6 @@ struct pvr_vm_gpuva { struct drm_gpuva base; }; -static __always_inline -struct pvr_vm_gpuva *to_pvr_vm_gpuva(struct drm_gpuva *gpuva) -{ - return container_of(gpuva, struct pvr_vm_gpuva, base); -} - enum pvr_vm_bind_type { PVR_VM_BIND_TYPE_MAP, PVR_VM_BIND_TYPE_UNMAP, From 5f8dec200923a76dc57187965fd59c1136f5d085 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 01:55:52 +0300 Subject: [PATCH 2323/7721] drm/drv: propagate errors from drm_modeset_register_all() In case the drm_modeset_register_all() function fails, its error code will be ignored. Instead make the drm_dev_register() bail out in case of such an error. Fixes: 79190ea2658a ("drm: Add callbacks for late registering") Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231202225552.1283638-1-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_drv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 535f16e7882e..3c835c99daad 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -949,8 +949,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto err_minors; } - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_modeset_register_all(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_modeset_register_all(dev); + if (ret) + goto err_unload; + } DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", driver->name, driver->major, driver->minor, @@ -960,6 +963,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto out_unlock; +err_unload: + if (dev->driver->unload) + dev->driver->unload(dev); err_minors: remove_compat_control_link(dev); drm_minor_unregister(dev, DRM_MINOR_ACCEL); From b1dba0b13c0aa93d22f8ef8cb082a4f32e5ab1f6 Mon Sep 17 00:00:00 2001 From: heminhong Date: Fri, 10 Nov 2023 13:50:31 +0800 Subject: [PATCH 2324/7721] drm/qxl: remove unused declaration Some functions are never used by the driver, removing the functions declaration, it can be reducing program size, and improving code readability and maintainability. Signed-off-by: heminhong Link: https://lore.kernel.org/r/20231110055031.57360-1-heminhong@kylinos.cn Signed-off-by: Maxime Ripard --- drivers/gpu/drm/qxl/qxl_drv.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 307a890fde13..32069acd93f8 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -119,7 +119,6 @@ struct qxl_output { #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base) #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base) -#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc) struct qxl_mman { struct ttm_device bdev; @@ -256,8 +255,6 @@ struct qxl_device { #define to_qxl(dev) container_of(dev, struct qxl_device, ddev) -int qxl_debugfs_fence_init(struct qxl_device *rdev); - int qxl_device_init(struct qxl_device *qdev, struct pci_dev *pdev); void qxl_device_fini(struct qxl_device *qdev); @@ -344,8 +341,6 @@ qxl_image_alloc_objects(struct qxl_device *qdev, int height, int stride); void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage); -void qxl_update_screen(struct qxl_device *qxl); - /* qxl io operations (qxl_cmd.c) */ void qxl_io_create_primary(struct qxl_device *qdev, @@ -445,8 +440,6 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev, int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo); -struct qxl_drv_surface * -qxl_surface_lookup(struct drm_device *dev, int surface_id); void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freeing); /* qxl_ioctl.c */ From 30d187cd74874aaf24e1b4a2dd2a64dc850c6b14 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 26 Nov 2023 03:37:15 +0200 Subject: [PATCH 2325/7721] media: renesas: vsp1: Fix references to pad config V4L2 subdev operations have moved from operating on a v4l2_subdev_pad_config to a v4l2_subdev_state a long time ago. Fix remaining incorrect references to pad config in function and variable names. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../media/platform/renesas/vsp1/vsp1_brx.c | 40 +++++---- .../media/platform/renesas/vsp1/vsp1_clu.c | 3 +- .../media/platform/renesas/vsp1/vsp1_entity.c | 85 +++++++++---------- .../media/platform/renesas/vsp1/vsp1_entity.h | 10 +-- .../media/platform/renesas/vsp1/vsp1_hgo.c | 4 +- .../media/platform/renesas/vsp1/vsp1_hgt.c | 4 +- .../media/platform/renesas/vsp1/vsp1_histo.c | 24 +++--- .../media/platform/renesas/vsp1/vsp1_hsit.c | 11 ++- .../media/platform/renesas/vsp1/vsp1_lif.c | 2 +- .../media/platform/renesas/vsp1/vsp1_rpf.c | 8 +- .../media/platform/renesas/vsp1/vsp1_rwpf.c | 37 ++++---- .../media/platform/renesas/vsp1/vsp1_sru.c | 36 ++++---- .../media/platform/renesas/vsp1/vsp1_uds.c | 39 ++++----- .../media/platform/renesas/vsp1/vsp1_uif.c | 24 +++--- .../media/platform/renesas/vsp1/vsp1_video.c | 4 +- .../media/platform/renesas/vsp1/vsp1_wpf.c | 10 +-- 16 files changed, 162 insertions(+), 179 deletions(-) diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c index 95bf7b4ac9b8..758525a03289 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c @@ -136,29 +136,28 @@ static int brx_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_brx *brx = to_brx(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; mutex_lock(&brx->entity.lock); - config = vsp1_entity_get_pad_config(&brx->entity, sd_state, - fmt->which); - if (!config) { + state = vsp1_entity_get_state(&brx->entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } - brx_try_format(brx, config, fmt->pad, &fmt->format); + brx_try_format(brx, state, fmt->pad, &fmt->format); - format = vsp1_entity_get_pad_format(&brx->entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(&brx->entity, state, fmt->pad); *format = fmt->format; /* Reset the compose rectangle. */ if (fmt->pad != brx->entity.source_pad) { struct v4l2_rect *compose; - compose = brx_get_compose(brx, config, fmt->pad); + compose = brx_get_compose(brx, state, fmt->pad); compose->left = 0; compose->top = 0; compose->width = format->width; @@ -171,7 +170,7 @@ static int brx_set_format(struct v4l2_subdev *subdev, for (i = 0; i <= brx->entity.source_pad; ++i) { format = vsp1_entity_get_pad_format(&brx->entity, - config, i); + state, i); format->code = fmt->format.code; } } @@ -186,7 +185,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_brx *brx = to_brx(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; if (sel->pad == brx->entity.source_pad) return -EINVAL; @@ -200,13 +199,13 @@ static int brx_get_selection(struct v4l2_subdev *subdev, return 0; case V4L2_SEL_TGT_COMPOSE: - config = vsp1_entity_get_pad_config(&brx->entity, sd_state, - sel->which); - if (!config) + state = vsp1_entity_get_state(&brx->entity, sd_state, + sel->which); + if (!state) return -EINVAL; mutex_lock(&brx->entity.lock); - sel->r = *brx_get_compose(brx, config, sel->pad); + sel->r = *brx_get_compose(brx, state, sel->pad); mutex_unlock(&brx->entity.lock); return 0; @@ -220,7 +219,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_brx *brx = to_brx(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; struct v4l2_rect *compose; int ret = 0; @@ -233,9 +232,8 @@ static int brx_set_selection(struct v4l2_subdev *subdev, mutex_lock(&brx->entity.lock); - config = vsp1_entity_get_pad_config(&brx->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&brx->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } @@ -244,7 +242,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev, * The compose rectangle top left corner must be inside the output * frame. */ - format = vsp1_entity_get_pad_format(&brx->entity, config, + format = vsp1_entity_get_pad_format(&brx->entity, state, brx->entity.source_pad); sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); @@ -253,11 +251,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev, * Scaling isn't supported, the compose rectangle size must be identical * to the sink format size. */ - format = vsp1_entity_get_pad_format(&brx->entity, config, sel->pad); + format = vsp1_entity_get_pad_format(&brx->entity, state, sel->pad); sel->r.width = format->width; sel->r.height = format->height; - compose = brx_get_compose(brx, config, sel->pad); + compose = brx_get_compose(brx, state, sel->pad); *compose = sel->r; done: @@ -293,7 +291,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, unsigned int flags; unsigned int i; - format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.config, + format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.state, brx->entity.source_pad); /* diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c index c5217fee24f1..50a5c0dc0e86 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c @@ -182,8 +182,7 @@ static void clu_configure_stream(struct vsp1_entity *entity, * The yuv_mode can't be changed during streaming. Cache it internally * for future runtime configuration calls. */ - format = vsp1_entity_get_pad_format(&clu->entity, - clu->entity.config, + format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.state, CLU_PAD_SINK); clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index d5a49e08a607..0280b8ff7ba9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -101,27 +101,26 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity, */ /** - * vsp1_entity_get_pad_config - Get the pad configuration for an entity + * vsp1_entity_get_state - Get the subdev state for an entity * @entity: the entity * @sd_state: the TRY state - * @which: configuration selector (ACTIVE or TRY) + * @which: state selector (ACTIVE or TRY) * * When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold * the entity lock to access the returned configuration. * - * Return the pad configuration requested by the which argument. The TRY - * configuration is passed explicitly to the function through the cfg argument - * and simply returned when requested. The ACTIVE configuration comes from the - * entity structure. + * Return the subdev state requested by the which argument. The TRY state is + * passed explicitly to the function through the sd_state argument and simply + * returned when requested. The ACTIVE state comes from the entity structure. */ struct v4l2_subdev_state * -vsp1_entity_get_pad_config(struct vsp1_entity *entity, - struct v4l2_subdev_state *sd_state, - enum v4l2_subdev_format_whence which) +vsp1_entity_get_state(struct vsp1_entity *entity, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_ACTIVE: - return entity->config; + return entity->state; case V4L2_SUBDEV_FORMAT_TRY: default: return sd_state; @@ -174,10 +173,11 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity, /* * vsp1_entity_init_cfg - Initialize formats on all pads * @subdev: V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * - * Initialize all pad formats with default values in the given pad config. This - * function can be used as a handler for the subdev pad::init_cfg operation. + * Initialize all pad formats with default values in the given subdev state. + * This function can be used as a handler for the subdev pad::init_cfg + * operation. */ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) @@ -200,7 +200,7 @@ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, /* * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler * @subdev: V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: V4L2 subdev format * * This function implements the subdev get_fmt pad operation. It can be used as @@ -211,14 +211,14 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_entity *entity = to_vsp1_entity(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; - config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which); - if (!config) + state = vsp1_entity_get_state(entity, sd_state, fmt->which); + if (!state) return -EINVAL; mutex_lock(&entity->lock); - fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad); + fmt->format = *vsp1_entity_get_pad_format(entity, state, fmt->pad); mutex_unlock(&entity->lock); return 0; @@ -227,7 +227,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, /* * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler * @subdev: V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @code: Media bus code enumeration * @codes: Array of supported media bus codes * @ncodes: Number of supported media bus codes @@ -250,7 +250,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, code->code = codes[code->index]; } else { - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; /* @@ -260,13 +260,12 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - config = vsp1_entity_get_pad_config(entity, sd_state, - code->which); - if (!config) + state = vsp1_entity_get_state(entity, sd_state, code->which); + if (!state) return -EINVAL; mutex_lock(&entity->lock); - format = vsp1_entity_get_pad_format(entity, config, 0); + format = vsp1_entity_get_pad_format(entity, state, 0); code->code = format->code; mutex_unlock(&entity->lock); } @@ -277,7 +276,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, /* * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler * @subdev: V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fse: Frame size enumeration * @min_width: Minimum image width * @min_height: Minimum image height @@ -296,15 +295,15 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, unsigned int max_width, unsigned int max_height) { struct vsp1_entity *entity = to_vsp1_entity(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; - config = vsp1_entity_get_pad_config(entity, sd_state, fse->which); - if (!config) + state = vsp1_entity_get_state(entity, sd_state, fse->which); + if (!state) return -EINVAL; - format = vsp1_entity_get_pad_format(entity, config, fse->pad); + format = vsp1_entity_get_pad_format(entity, state, fse->pad); mutex_lock(&entity->lock); @@ -337,7 +336,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, /* * vsp1_subdev_set_pad_format - Subdev pad set_fmt handler * @subdev: V4L2 subdevice - * @cfg: V4L2 subdev pad configuration + * @sd_state: V4L2 subdev state * @fmt: V4L2 subdev format * @codes: Array of supported media bus codes * @ncodes: Number of supported media bus codes @@ -360,7 +359,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, unsigned int max_width, unsigned int max_height) { struct vsp1_entity *entity = to_vsp1_entity(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; struct v4l2_rect *selection; unsigned int i; @@ -368,13 +367,13 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, mutex_lock(&entity->lock); - config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which); - if (!config) { + state = vsp1_entity_get_state(entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } - format = vsp1_entity_get_pad_format(entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(entity, state, fmt->pad); if (fmt->pad == entity->source_pad) { /* The output format can't be modified. */ @@ -402,18 +401,18 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(entity, config, entity->source_pad); + format = vsp1_entity_get_pad_format(entity, state, entity->source_pad); *format = fmt->format; /* Reset the crop and compose rectangles. */ - selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad, + selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad, V4L2_SEL_TGT_CROP); selection->left = 0; selection->top = 0; selection->width = format->width; selection->height = format->height; - selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad, + selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad, V4L2_SEL_TGT_COMPOSE); selection->left = 0; selection->top = 0; @@ -670,18 +669,18 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, vsp1_entity_init_cfg(subdev, NULL); /* - * Allocate the pad configuration to store formats and selection + * Allocate the subdev state to store formats and selection * rectangles. */ /* * FIXME: Drop this call, drivers are not supposed to use * __v4l2_subdev_state_alloc(). */ - entity->config = __v4l2_subdev_state_alloc(&entity->subdev, - "vsp1:config->lock", &key); - if (IS_ERR(entity->config)) { + entity->state = __v4l2_subdev_state_alloc(&entity->subdev, + "vsp1:state->lock", &key); + if (IS_ERR(entity->state)) { media_entity_cleanup(&entity->subdev.entity); - return PTR_ERR(entity->config); + return PTR_ERR(entity->state); } return 0; @@ -693,6 +692,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity) entity->ops->destroy(entity); if (entity->subdev.ctrl_handler) v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); - __v4l2_subdev_state_free(entity->config); + __v4l2_subdev_state_free(entity->state); media_entity_cleanup(&entity->subdev.entity); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h index 17f98a6a972e..8c737cadee81 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h @@ -115,9 +115,9 @@ struct vsp1_entity { unsigned int sink_pad; struct v4l2_subdev subdev; - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; - struct mutex lock; /* Protects the pad config */ + struct mutex lock; /* Protects the state */ }; static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) @@ -135,9 +135,9 @@ int vsp1_entity_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags); struct v4l2_subdev_state * -vsp1_entity_get_pad_config(struct vsp1_entity *entity, - struct v4l2_subdev_state *sd_state, - enum v4l2_subdev_format_whence which); +vsp1_entity_get_state(struct vsp1_entity *entity, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which); struct v4l2_mbus_framefmt * vsp1_entity_get_pad_format(struct vsp1_entity *entity, struct v4l2_subdev_state *sd_state, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c index e6492deb0a64..40c571a987ef 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c @@ -140,9 +140,9 @@ static void hgo_configure_stream(struct vsp1_entity *entity, unsigned int hratio; unsigned int vratio; - crop = vsp1_entity_get_pad_selection(entity, entity->config, + crop = vsp1_entity_get_pad_selection(entity, entity->state, HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); - compose = vsp1_entity_get_pad_selection(entity, entity->config, + compose = vsp1_entity_get_pad_selection(entity, entity->state, HISTO_PAD_SINK, V4L2_SEL_TGT_COMPOSE); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c index aa1c718e0453..8281b86874ab 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c @@ -139,9 +139,9 @@ static void hgt_configure_stream(struct vsp1_entity *entity, u8 upper; unsigned int i; - crop = vsp1_entity_get_pad_selection(entity, entity->config, + crop = vsp1_entity_get_pad_selection(entity, entity->state, HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); - compose = vsp1_entity_get_pad_selection(entity, entity->config, + compose = vsp1_entity_get_pad_selection(entity, entity->state, HISTO_PAD_SINK, V4L2_SEL_TGT_COMPOSE); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index f22449dd654c..71155282ca11 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -203,7 +203,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_histogram *histo = subdev_to_histo(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; int ret = 0; @@ -213,9 +213,8 @@ static int histo_get_selection(struct v4l2_subdev *subdev, mutex_lock(&histo->entity.lock); - config = vsp1_entity_get_pad_config(&histo->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&histo->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } @@ -223,7 +222,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_COMPOSE_DEFAULT: - crop = vsp1_entity_get_pad_selection(&histo->entity, config, + crop = vsp1_entity_get_pad_selection(&histo->entity, state, HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); sel->r.left = 0; @@ -234,7 +233,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: - format = vsp1_entity_get_pad_format(&histo->entity, config, + format = vsp1_entity_get_pad_format(&histo->entity, state, HISTO_PAD_SINK); sel->r.left = 0; sel->r.top = 0; @@ -244,7 +243,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_CROP: - sel->r = *vsp1_entity_get_pad_selection(&histo->entity, config, + sel->r = *vsp1_entity_get_pad_selection(&histo->entity, state, sel->pad, sel->target); break; @@ -346,7 +345,7 @@ static int histo_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_histogram *histo = subdev_to_histo(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; int ret; if (sel->pad != HISTO_PAD_SINK) @@ -354,17 +353,16 @@ static int histo_set_selection(struct v4l2_subdev *subdev, mutex_lock(&histo->entity.lock); - config = vsp1_entity_get_pad_config(&histo->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&histo->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } if (sel->target == V4L2_SEL_TGT_CROP) - ret = histo_set_crop(subdev, config, sel); + ret = histo_set_crop(subdev, state, sel); else if (sel->target == V4L2_SEL_TGT_COMPOSE) - ret = histo_set_compose(subdev, config, sel); + ret = histo_set_compose(subdev, state, sel); else ret = -EINVAL; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c index 361a870380c2..6342ac7bdf54 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c @@ -66,20 +66,19 @@ static int hsit_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_hsit *hsit = to_hsit(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; mutex_lock(&hsit->entity.lock); - config = vsp1_entity_get_pad_config(&hsit->entity, sd_state, - fmt->which); - if (!config) { + state = vsp1_entity_get_state(&hsit->entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } - format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(&hsit->entity, state, fmt->pad); if (fmt->pad == HSIT_PAD_SOURCE) { /* @@ -102,7 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&hsit->entity, config, + format = vsp1_entity_get_pad_format(&hsit->entity, state, HSIT_PAD_SOURCE); *format = fmt->format; format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c index 0ab2e0c70474..75c24df41a7a 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c @@ -94,7 +94,7 @@ static void lif_configure_stream(struct vsp1_entity *entity, unsigned int obth; unsigned int lbth; - format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, + format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.state, LIF_PAD_SOURCE); switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) { diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c index ea12c3f12c92..c47579efc65f 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c @@ -81,10 +81,10 @@ static void rpf_configure_stream(struct vsp1_entity *entity, /* Format */ sink_format = vsp1_entity_get_pad_format(&rpf->entity, - rpf->entity.config, + rpf->entity.state, RWPF_PAD_SINK); source_format = vsp1_entity_get_pad_format(&rpf->entity, - rpf->entity.config, + rpf->entity.state, RWPF_PAD_SOURCE); infmt = VI6_RPF_INFMT_CIPM @@ -158,7 +158,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity, const struct v4l2_rect *compose; compose = vsp1_entity_get_pad_selection(pipe->brx, - pipe->brx->config, + pipe->brx->state, rpf->brx_input, V4L2_SEL_TGT_COMPOSE); left = compose->left; @@ -302,7 +302,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity, * offsets are needed, as planes 2 and 3 always have identical * strides. */ - crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config); + crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.state); /* * Partition Algorithm Control diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c index 6391a503ec97..cb3ab351b7de 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c @@ -61,15 +61,14 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; mutex_lock(&rwpf->entity.lock); - config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state, - fmt->which); - if (!config) { + state = vsp1_entity_get_state(&rwpf->entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } @@ -80,7 +79,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(&rwpf->entity, state, fmt->pad); if (fmt->pad == RWPF_PAD_SOURCE) { /* @@ -106,7 +105,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_rect *crop; /* Update the sink crop rectangle. */ - crop = vsp1_rwpf_get_crop(rwpf, config); + crop = vsp1_rwpf_get_crop(rwpf, state); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; @@ -114,7 +113,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, } /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, config, + format = vsp1_entity_get_pad_format(&rwpf->entity, state, RWPF_PAD_SOURCE); *format = fmt->format; @@ -133,7 +132,7 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; @@ -146,20 +145,19 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, mutex_lock(&rwpf->entity.lock); - config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *vsp1_rwpf_get_crop(rwpf, config); + sel->r = *vsp1_rwpf_get_crop(rwpf, state); break; case V4L2_SEL_TGT_CROP_BOUNDS: - format = vsp1_entity_get_pad_format(&rwpf->entity, config, + format = vsp1_entity_get_pad_format(&rwpf->entity, state, RWPF_PAD_SINK); sel->r.left = 0; sel->r.top = 0; @@ -182,7 +180,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; int ret = 0; @@ -199,15 +197,14 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, mutex_lock(&rwpf->entity.lock); - config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } /* Make sure the crop rectangle is entirely contained in the image. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, config, + format = vsp1_entity_get_pad_format(&rwpf->entity, state, RWPF_PAD_SINK); /* @@ -228,11 +225,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, sel->r.height = min_t(unsigned int, sel->r.height, format->height - sel->r.top); - crop = vsp1_rwpf_get_crop(rwpf, config); + crop = vsp1_rwpf_get_crop(rwpf, state); *crop = sel->r; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, config, + format = vsp1_entity_get_pad_format(&rwpf->entity, state, RWPF_PAD_SOURCE); format->width = crop->width; format->height = crop->height; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c index b614a2aea461..2dd6f8575614 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c @@ -123,16 +123,15 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, struct v4l2_subdev_frame_size_enum *fse) { struct vsp1_sru *sru = to_sru(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; - config = vsp1_entity_get_pad_config(&sru->entity, sd_state, - fse->which); - if (!config) + state = vsp1_entity_get_state(&sru->entity, sd_state, fse->which); + if (!state) return -EINVAL; - format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK); + format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SINK); mutex_lock(&sru->entity.lock); @@ -221,31 +220,30 @@ static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_sru *sru = to_sru(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; mutex_lock(&sru->entity.lock); - config = vsp1_entity_get_pad_config(&sru->entity, sd_state, - fmt->which); - if (!config) { + state = vsp1_entity_get_state(&sru->entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } - sru_try_format(sru, config, fmt->pad, &fmt->format); + sru_try_format(sru, state, fmt->pad, &fmt->format); - format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(&sru->entity, state, fmt->pad); *format = fmt->format; if (fmt->pad == SRU_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&sru->entity, config, + format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SOURCE); *format = fmt->format; - sru_try_format(sru, config, SRU_PAD_SOURCE, format); + sru_try_format(sru, state, SRU_PAD_SOURCE, format); } done: @@ -280,9 +278,9 @@ static void sru_configure_stream(struct vsp1_entity *entity, struct v4l2_mbus_framefmt *output; u32 ctrl0; - input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SINK); - output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SOURCE); if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) @@ -310,9 +308,9 @@ static unsigned int sru_max_width(struct vsp1_entity *entity, struct v4l2_mbus_framefmt *input; struct v4l2_mbus_framefmt *output; - input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SINK); - output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SOURCE); /* @@ -336,9 +334,9 @@ static void sru_partition(struct vsp1_entity *entity, struct v4l2_mbus_framefmt *input; struct v4l2_mbus_framefmt *output; - input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SINK); - output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, SRU_PAD_SOURCE); /* Adapt if SRUx2 is enabled. */ diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c index 1c290cda005a..59ff4ae46cea 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c @@ -128,17 +128,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, struct v4l2_subdev_frame_size_enum *fse) { struct vsp1_uds *uds = to_uds(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; - config = vsp1_entity_get_pad_config(&uds->entity, sd_state, - fse->which); - if (!config) + state = vsp1_entity_get_state(&uds->entity, sd_state, fse->which); + if (!state) return -EINVAL; - format = vsp1_entity_get_pad_format(&uds->entity, config, - UDS_PAD_SINK); + format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SINK); mutex_lock(&uds->entity.lock); @@ -205,31 +203,30 @@ static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_format *fmt) { struct vsp1_uds *uds = to_uds(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; mutex_lock(&uds->entity.lock); - config = vsp1_entity_get_pad_config(&uds->entity, sd_state, - fmt->which); - if (!config) { + state = vsp1_entity_get_state(&uds->entity, sd_state, fmt->which); + if (!state) { ret = -EINVAL; goto done; } - uds_try_format(uds, config, fmt->pad, &fmt->format); + uds_try_format(uds, state, fmt->pad, &fmt->format); - format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad); + format = vsp1_entity_get_pad_format(&uds->entity, state, fmt->pad); *format = fmt->format; if (fmt->pad == UDS_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&uds->entity, config, + format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SOURCE); *format = fmt->format; - uds_try_format(uds, config, UDS_PAD_SOURCE, format); + uds_try_format(uds, state, UDS_PAD_SOURCE, format); } done: @@ -269,9 +266,9 @@ static void uds_configure_stream(struct vsp1_entity *entity, unsigned int vscale; bool multitap; - input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SINK); - output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SOURCE); hscale = uds_compute_ratio(input->width, output->width); @@ -314,7 +311,7 @@ static void uds_configure_partition(struct vsp1_entity *entity, struct vsp1_partition *partition = pipe->partition; const struct v4l2_mbus_framefmt *output; - output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SOURCE); /* Input size clipping. */ @@ -339,9 +336,9 @@ static unsigned int uds_max_width(struct vsp1_entity *entity, const struct v4l2_mbus_framefmt *input; unsigned int hscale; - input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SINK); - output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SOURCE); hscale = output->width / input->width; @@ -381,9 +378,9 @@ static void uds_partition(struct vsp1_entity *entity, partition->uds_sink = *window; partition->uds_source = *window; - input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SINK); - output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, UDS_PAD_SOURCE); partition->uds_sink.width = window->width * input->width diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uif.c b/drivers/media/platform/renesas/vsp1/vsp1_uif.c index 83d7f17df80e..d84d10f35090 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_uif.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_uif.c @@ -86,7 +86,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_uif *uif = to_uif(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; int ret = 0; @@ -95,9 +95,8 @@ static int uif_get_selection(struct v4l2_subdev *subdev, mutex_lock(&uif->entity.lock); - config = vsp1_entity_get_pad_config(&uif->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&uif->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } @@ -105,7 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: - format = vsp1_entity_get_pad_format(&uif->entity, config, + format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK); sel->r.left = 0; sel->r.top = 0; @@ -114,7 +113,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev, break; case V4L2_SEL_TGT_CROP: - sel->r = *vsp1_entity_get_pad_selection(&uif->entity, config, + sel->r = *vsp1_entity_get_pad_selection(&uif->entity, state, sel->pad, sel->target); break; @@ -133,7 +132,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_selection *sel) { struct vsp1_uif *uif = to_uif(subdev); - struct v4l2_subdev_state *config; + struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; struct v4l2_rect *selection; int ret = 0; @@ -144,15 +143,14 @@ static int uif_set_selection(struct v4l2_subdev *subdev, mutex_lock(&uif->entity.lock); - config = vsp1_entity_get_pad_config(&uif->entity, sd_state, - sel->which); - if (!config) { + state = vsp1_entity_get_state(&uif->entity, sd_state, sel->which); + if (!state) { ret = -EINVAL; goto done; } /* The crop rectangle must be inside the input frame. */ - format = vsp1_entity_get_pad_format(&uif->entity, config, UIF_PAD_SINK); + format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK); sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); @@ -162,7 +160,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev, format->height - sel->r.top); /* Store the crop rectangle. */ - selection = vsp1_entity_get_pad_selection(&uif->entity, config, + selection = vsp1_entity_get_pad_selection(&uif->entity, state, sel->pad, V4L2_SEL_TGT_CROP); *selection = sel->r; @@ -206,7 +204,7 @@ static void uif_configure_stream(struct vsp1_entity *entity, vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR, VI6_UIF_DISCOM_DOCMPMR_SEL(9)); - crop = vsp1_entity_get_pad_selection(entity, entity->config, + crop = vsp1_entity_get_pad_selection(entity, entity->state, UIF_PAD_SINK, V4L2_SEL_TGT_CROP); left = crop->left; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index e9d5027761bb..5a9cb0e5640e 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -198,7 +198,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe, * at the WPF sink. */ format = vsp1_entity_get_pad_format(&pipe->output->entity, - pipe->output->entity.config, + pipe->output->entity.state, RWPF_PAD_SINK); /* A single partition simply processes the output size in full. */ @@ -263,7 +263,7 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) * at the WPF sink. */ format = vsp1_entity_get_pad_format(&pipe->output->entity, - pipe->output->entity.config, + pipe->output->entity.state, RWPF_PAD_SINK); div_size = format->width; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c index cab4445eca69..9693aeab1cac 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c @@ -66,10 +66,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation) } sink_format = vsp1_entity_get_pad_format(&wpf->entity, - wpf->entity.config, + wpf->entity.state, RWPF_PAD_SINK); source_format = vsp1_entity_get_pad_format(&wpf->entity, - wpf->entity.config, + wpf->entity.state, RWPF_PAD_SOURCE); mutex_lock(&wpf->entity.lock); @@ -246,10 +246,10 @@ static void wpf_configure_stream(struct vsp1_entity *entity, int ret; sink_format = vsp1_entity_get_pad_format(&wpf->entity, - wpf->entity.config, + wpf->entity.state, RWPF_PAD_SINK); source_format = vsp1_entity_get_pad_format(&wpf->entity, - wpf->entity.config, + wpf->entity.state, RWPF_PAD_SOURCE); /* Format */ @@ -384,7 +384,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, unsigned int i; sink_format = vsp1_entity_get_pad_format(&wpf->entity, - wpf->entity.config, + wpf->entity.state, RWPF_PAD_SINK); width = sink_format->width; height = sink_format->height; From c12251898fbd4e0455ce22108aeada6a98d128aa Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 22 Nov 2023 08:51:47 +0100 Subject: [PATCH 2326/7721] dt-bindings: vendor-prefixes: Add prefix for GalaxyCore Inc. Add a vendor prefix entry for galaxycore (https://www.gcoreinc.com) Signed-off-by: Alain Volmat Acked-by: Krzysztof Kozlowski Reviewed-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 309b94c328c8..b3d751b42927 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -502,6 +502,8 @@ patternProperties: description: Fujitsu Ltd. "^fxtec,.*": description: FX Technology Ltd. + "^galaxycore,.*": + description: GalaxyCore Inc. "^gardena,.*": description: GARDENA GmbH "^gateway,.*": From 0d32f666bedc2685b7006ec01002069b08e376d1 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 22 Nov 2023 08:51:48 +0100 Subject: [PATCH 2327/7721] dt-bindings: media: i2c: add galaxycore,gc2145 dt-bindings Introduction of the Galaxy Core GC2145 XVGA CMOS camera sensor. Signed-off-by: Alain Volmat Reviewed-by: Conor Dooley Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/i2c/galaxycore,gc2145.yaml | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml new file mode 100644 index 000000000000..1726ecca4c77 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc2145.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Galaxy Core 1/5'' UXGA CMOS Image Sensor + +maintainers: + - Alain Volmat + +description: + The Galaxy Core GC2145 is a 2 Megapixel CMOS image sensor, for mobile + phone camera applications and digital camera products. GC2145 incorporates a + 1616V x 1232H active pixel array, on-chip 10-bit ADC, and image signal + processor allowing AE/AWB/interpolation/de-noise/color-conversion and + gamma correction. Bayer RGB, RGB565 and YCbCr 4:2:2 can be provided by the + sensor. It is programmable through an I2C interface. Image data is sent + either through a parallel interface or through MIPI CSI-2. + +allOf: + - $ref: ../video-interface-devices.yaml# + +properties: + compatible: + const: galaxycore,gc2145 + + reg: + const: 0x3c + + clocks: + maxItems: 1 + + powerdown-gpios: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + iovdd-supply: + description: Power Supply for I/O circuits (1.7 - 3V). + + avdd-supply: + description: Power for analog circuit/sensor array (2.7 - 3V). + + dvdd-supply: + description: Power for digital core (1.7 - 1.9V). + + orientation: true + + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + link-frequencies: true + + required: + - link-frequencies + + required: + - endpoint + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - powerdown-gpios + - reset-gpios + - iovdd-supply + - avdd-supply + - dvdd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@3c { + compatible = "galaxycore,gc2145"; + reg = <0x3c>; + clocks = <&clk_ext_camera>; + iovdd-supply = <&scmi_v3v3_sw>; + avdd-supply = <&scmi_v3v3_sw>; + dvdd-supply = <&scmi_v3v3_sw>; + powerdown-gpios = <&mcp23017 3 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; + reset-gpios = <&mcp23017 4 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; + + port { + endpoint { + remote-endpoint = <&mipid02_0>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <120000000 192000000 240000000>; + }; + }; + }; + }; + +... From 03cc7fefbb09dd70f3b21d127784879fac0bbf00 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 22 Nov 2023 08:51:49 +0100 Subject: [PATCH 2328/7721] media: i2c: gc2145: Galaxy Core GC2145 sensor support Addition of support for the Galaxy Core GC2145 XVGA sensor. The sensor supports both DVP and CSI-2 interfaces however for the time being only CSI-2 is implemented. Configurations are currently based on initialization scripts coming from Galaxy Core and so for that purpose only 3 static resolutions are supported: - 640x480 - 1280x720 - 1600x1200 Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 8 + drivers/media/i2c/Kconfig | 10 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/gc2145.c | 1446 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1465 insertions(+) create mode 100644 drivers/media/i2c/gc2145.c diff --git a/MAINTAINERS b/MAINTAINERS index 47565a6e0f4e..b9fc8fdaa320 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8760,6 +8760,14 @@ F: kernel/futex/* F: tools/perf/bench/futex* F: tools/testing/selftests/futex/ +GALAXYCORE GC2145 SENSOR DRIVER +M: Alain Volmat +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml +F: drivers/media/i2c/gc2145.c + GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER M: Tim Harvey S: Maintained diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 59ee0ca2c978..fc053c834782 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -50,6 +50,16 @@ config VIDEO_AR0521 To compile this driver as a module, choose M here: the module will be called ar0521. +config VIDEO_GC2145 + select V4L2_CCI_I2C + tristate "GalaxyCore GC2145 sensor support" + help + This is a V4L2 sensor-level driver for GalaxyCore GC2145 + 2 Mpixel camera. + + To compile this driver as a module, choose M here: the + module will be called gc2145. + config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" help diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index f5010f80a21f..08e7e638dedc 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_VIDEO_DW9719) += dw9719.o obj-$(CONFIG_VIDEO_DW9768) += dw9768.o obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ +obj-$(CONFIG_VIDEO_GC2145) += gc2145.o obj-$(CONFIG_VIDEO_HI556) += hi556.o obj-$(CONFIG_VIDEO_HI846) += hi846.o obj-$(CONFIG_VIDEO_HI847) += hi847.o diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c new file mode 100644 index 000000000000..12d3780b5548 --- /dev/null +++ b/drivers/media/i2c/gc2145.c @@ -0,0 +1,1446 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A V4L2 driver for Galaxycore GC2145 camera. + * Copyright (C) 2023, STMicroelectronics SA + * + * Inspired by the imx219.c driver + * + * Datasheet v1.0 available at http://files.pine64.org/doc/datasheet/PinebookPro/GC2145%20CSP%20DataSheet%20release%20V1.0_20131201.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Chip ID */ +#define GC2145_CHIP_ID 0x2145 + +/* Page 0 */ +#define GC2145_REG_EXPOSURE CCI_REG16(0x03) +#define GC2145_REG_HBLANK CCI_REG16(0x05) +#define GC2145_REG_VBLANK CCI_REG16(0x07) +#define GC2145_REG_ROW_START CCI_REG16(0x09) +#define GC2145_REG_COL_START CCI_REG16(0x0b) +#define GC2145_REG_WIN_HEIGHT CCI_REG16(0x0d) +#define GC2145_REG_WIN_WIDTH CCI_REG16(0x0f) +#define GC2145_REG_ANALOG_MODE1 CCI_REG8(0x17) +#define GC2145_REG_OUTPUT_FMT CCI_REG8(0x84) +#define GC2145_REG_SYNC_MODE CCI_REG8(0x86) +#define GC2145_SYNC_MODE_COL_SWITCH BIT(4) +#define GC2145_SYNC_MODE_ROW_SWITCH BIT(5) +#define GC2145_REG_BYPASS_MODE CCI_REG8(0x89) +#define GC2145_BYPASS_MODE_SWITCH BIT(5) +#define GC2145_REG_DEBUG_MODE2 CCI_REG8(0x8c) +#define GC2145_REG_DEBUG_MODE3 CCI_REG8(0x8d) +#define GC2145_REG_CROP_ENABLE CCI_REG8(0x90) +#define GC2145_REG_CROP_Y CCI_REG16(0x91) +#define GC2145_REG_CROP_X CCI_REG16(0x93) +#define GC2145_REG_CROP_HEIGHT CCI_REG16(0x95) +#define GC2145_REG_CROP_WIDTH CCI_REG16(0x97) +#define GC2145_REG_GLOBAL_GAIN CCI_REG8(0xb0) +#define GC2145_REG_CHIP_ID CCI_REG16(0xf0) +#define GC2145_REG_PAD_IO CCI_REG8(0xf2) +#define GC2145_REG_PAGE_SELECT CCI_REG8(0xfe) +/* Page 3 */ +#define GC2145_REG_DPHY_ANALOG_MODE1 CCI_REG8(0x01) +#define GC2145_DPHY_MODE_PHY_CLK_EN BIT(0) +#define GC2145_DPHY_MODE_PHY_LANE0_EN BIT(1) +#define GC2145_DPHY_MODE_PHY_LANE1_EN BIT(2) +#define GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL BIT(7) +#define GC2145_REG_DPHY_ANALOG_MODE2 CCI_REG8(0x02) +#define GC2145_DPHY_CLK_DIFF(a) ((a) & 0x07) +#define GC2145_DPHY_LANE0_DIFF(a) (((a) & 0x07) << 4) +#define GC2145_REG_DPHY_ANALOG_MODE3 CCI_REG8(0x03) +#define GC2145_DPHY_LANE1_DIFF(a) ((a) & 0x07) +#define GC2145_DPHY_CLK_DELAY BIT(4) +#define GC2145_DPHY_LANE0_DELAY BIT(5) +#define GC2145_DPHY_LANE1_DELAY BIT(6) +#define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04) +#define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05) +#define GC2145_REG_FIFO_MODE CCI_REG8(0x06) +#define GC2145_FIFO_MODE_READ_GATE BIT(3) +#define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7) +#define GC2145_REG_BUF_CSI2_MODE CCI_REG8(0x10) +#define GC2145_CSI2_MODE_DOUBLE BIT(0) +#define GC2145_CSI2_MODE_RAW8 BIT(2) +#define GC2145_CSI2_MODE_MIPI_EN BIT(4) +#define GC2145_CSI2_MODE_EN BIT(7) +#define GC2145_REG_MIPI_DT CCI_REG8(0x11) +#define GC2145_REG_LWC_LOW CCI_REG8(0x12) +#define GC2145_REG_LWC_HIGH CCI_REG8(0x13) +#define GC2145_REG_DPHY_MODE CCI_REG8(0x15) +#define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4) +#define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17) +#define GC2145_REG_T_LPX CCI_REG8(0x21) +#define GC2145_REG_T_CLK_HS_PREPARE CCI_REG8(0x22) +#define GC2145_REG_T_CLK_ZERO CCI_REG8(0x23) +#define GC2145_REG_T_CLK_PRE CCI_REG8(0x24) +#define GC2145_REG_T_CLK_POST CCI_REG8(0x25) +#define GC2145_REG_T_CLK_TRAIL CCI_REG8(0x26) +#define GC2145_REG_T_HS_EXIT CCI_REG8(0x27) +#define GC2145_REG_T_WAKEUP CCI_REG8(0x28) +#define GC2145_REG_T_HS_PREPARE CCI_REG8(0x29) +#define GC2145_REG_T_HS_ZERO CCI_REG8(0x2a) +#define GC2145_REG_T_HS_TRAIL CCI_REG8(0x2b) + +/* External clock frequency is 24.0MHz */ +#define GC2145_XCLK_FREQ (24 * HZ_PER_MHZ) + +#define GC2145_NATIVE_WIDTH 1616U +#define GC2145_NATIVE_HEIGHT 1232U + +/** + * struct gc2145_mode - GC2145 mode description + * @width: frame width (in pixels) + * @height: frame height (in pixels) + * @reg_seq: registers config sequence to enter into the mode + * @reg_seq_size: size of the sequence + * @pixel_rate: pixel rate associated with the mode + * @crop: window area captured + * @hblank: default horizontal blanking + * @vblank: default vertical blanking + * @link_freq_index: index within the link frequency menu + */ +struct gc2145_mode { + unsigned int width; + unsigned int height; + const struct cci_reg_sequence *reg_seq; + size_t reg_seq_size; + unsigned long pixel_rate; + struct v4l2_rect crop; + unsigned int hblank; + unsigned int vblank; + unsigned int link_freq_index; +}; + +#define GC2145_DEFAULT_EXPOSURE 0x04e2 +#define GC2145_DEFAULT_GLOBAL_GAIN 0x55 +static const struct cci_reg_sequence gc2145_common_regs[] = { + {GC2145_REG_PAGE_SELECT, 0x00}, + /* SH Delay */ + {CCI_REG8(0x12), 0x2e}, + /* Flip */ + {GC2145_REG_ANALOG_MODE1, 0x14}, + /* Analog Conf */ + {CCI_REG8(0x18), 0x22}, {CCI_REG8(0x19), 0x0e}, {CCI_REG8(0x1a), 0x01}, + {CCI_REG8(0x1b), 0x4b}, {CCI_REG8(0x1c), 0x07}, {CCI_REG8(0x1d), 0x10}, + {CCI_REG8(0x1e), 0x88}, {CCI_REG8(0x1f), 0x78}, {CCI_REG8(0x20), 0x03}, + {CCI_REG8(0x21), 0x40}, {CCI_REG8(0x22), 0xa0}, {CCI_REG8(0x24), 0x16}, + {CCI_REG8(0x25), 0x01}, {CCI_REG8(0x26), 0x10}, {CCI_REG8(0x2d), 0x60}, + {CCI_REG8(0x30), 0x01}, {CCI_REG8(0x31), 0x90}, {CCI_REG8(0x33), 0x06}, + {CCI_REG8(0x34), 0x01}, + /* ISP related */ + {CCI_REG8(0x80), 0x7f}, {CCI_REG8(0x81), 0x26}, {CCI_REG8(0x82), 0xfa}, + {CCI_REG8(0x83), 0x00}, {CCI_REG8(0x84), 0x02}, {CCI_REG8(0x86), 0x02}, + {CCI_REG8(0x88), 0x03}, + {GC2145_REG_BYPASS_MODE, 0x03}, + {CCI_REG8(0x85), 0x08}, {CCI_REG8(0x8a), 0x00}, {CCI_REG8(0x8b), 0x00}, + {GC2145_REG_GLOBAL_GAIN, GC2145_DEFAULT_GLOBAL_GAIN}, + {CCI_REG8(0xc3), 0x00}, {CCI_REG8(0xc4), 0x80}, {CCI_REG8(0xc5), 0x90}, + {CCI_REG8(0xc6), 0x3b}, {CCI_REG8(0xc7), 0x46}, + /* BLK */ + {GC2145_REG_PAGE_SELECT, 0x00}, + {CCI_REG8(0x40), 0x42}, {CCI_REG8(0x41), 0x00}, {CCI_REG8(0x43), 0x5b}, + {CCI_REG8(0x5e), 0x00}, {CCI_REG8(0x5f), 0x00}, {CCI_REG8(0x60), 0x00}, + {CCI_REG8(0x61), 0x00}, {CCI_REG8(0x62), 0x00}, {CCI_REG8(0x63), 0x00}, + {CCI_REG8(0x64), 0x00}, {CCI_REG8(0x65), 0x00}, {CCI_REG8(0x66), 0x20}, + {CCI_REG8(0x67), 0x20}, {CCI_REG8(0x68), 0x20}, {CCI_REG8(0x69), 0x20}, + {CCI_REG8(0x76), 0x00}, {CCI_REG8(0x6a), 0x08}, {CCI_REG8(0x6b), 0x08}, + {CCI_REG8(0x6c), 0x08}, {CCI_REG8(0x6d), 0x08}, {CCI_REG8(0x6e), 0x08}, + {CCI_REG8(0x6f), 0x08}, {CCI_REG8(0x70), 0x08}, {CCI_REG8(0x71), 0x08}, + {CCI_REG8(0x76), 0x00}, {CCI_REG8(0x72), 0xf0}, {CCI_REG8(0x7e), 0x3c}, + {CCI_REG8(0x7f), 0x00}, + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x48), 0x15}, {CCI_REG8(0x49), 0x00}, {CCI_REG8(0x4b), 0x0b}, + /* AEC */ + {GC2145_REG_PAGE_SELECT, 0x00}, + {GC2145_REG_EXPOSURE, GC2145_DEFAULT_EXPOSURE}, + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x01), 0x04}, {CCI_REG8(0x02), 0xc0}, {CCI_REG8(0x03), 0x04}, + {CCI_REG8(0x04), 0x90}, {CCI_REG8(0x05), 0x30}, {CCI_REG8(0x06), 0x90}, + {CCI_REG8(0x07), 0x30}, {CCI_REG8(0x08), 0x80}, {CCI_REG8(0x09), 0x00}, + {CCI_REG8(0x0a), 0x82}, {CCI_REG8(0x0b), 0x11}, {CCI_REG8(0x0c), 0x10}, + {CCI_REG8(0x11), 0x10}, {CCI_REG8(0x13), 0x7b}, {CCI_REG8(0x17), 0x00}, + {CCI_REG8(0x1c), 0x11}, {CCI_REG8(0x1e), 0x61}, {CCI_REG8(0x1f), 0x35}, + {CCI_REG8(0x20), 0x40}, {CCI_REG8(0x22), 0x40}, {CCI_REG8(0x23), 0x20}, + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x0f), 0x04}, + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x12), 0x35}, {CCI_REG8(0x15), 0xb0}, {CCI_REG8(0x10), 0x31}, + {CCI_REG8(0x3e), 0x28}, {CCI_REG8(0x3f), 0xb0}, {CCI_REG8(0x40), 0x90}, + {CCI_REG8(0x41), 0x0f}, + /* INTPEE */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x90), 0x6c}, {CCI_REG8(0x91), 0x03}, {CCI_REG8(0x92), 0xcb}, + {CCI_REG8(0x94), 0x33}, {CCI_REG8(0x95), 0x84}, {CCI_REG8(0x97), 0x65}, + {CCI_REG8(0xa2), 0x11}, + /* DNDD */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x80), 0xc1}, {CCI_REG8(0x81), 0x08}, {CCI_REG8(0x82), 0x05}, + {CCI_REG8(0x83), 0x08}, {CCI_REG8(0x84), 0x0a}, {CCI_REG8(0x86), 0xf0}, + {CCI_REG8(0x87), 0x50}, {CCI_REG8(0x88), 0x15}, {CCI_REG8(0x89), 0xb0}, + {CCI_REG8(0x8a), 0x30}, {CCI_REG8(0x8b), 0x10}, + /* ASDE */ + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x21), 0x04}, + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0xa3), 0x50}, {CCI_REG8(0xa4), 0x20}, {CCI_REG8(0xa5), 0x40}, + {CCI_REG8(0xa6), 0x80}, {CCI_REG8(0xab), 0x40}, {CCI_REG8(0xae), 0x0c}, + {CCI_REG8(0xb3), 0x46}, {CCI_REG8(0xb4), 0x64}, {CCI_REG8(0xb6), 0x38}, + {CCI_REG8(0xb7), 0x01}, {CCI_REG8(0xb9), 0x2b}, {CCI_REG8(0x3c), 0x04}, + {CCI_REG8(0x3d), 0x15}, {CCI_REG8(0x4b), 0x06}, {CCI_REG8(0x4c), 0x20}, + /* Gamma */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x10), 0x09}, {CCI_REG8(0x11), 0x0d}, {CCI_REG8(0x12), 0x13}, + {CCI_REG8(0x13), 0x19}, {CCI_REG8(0x14), 0x27}, {CCI_REG8(0x15), 0x37}, + {CCI_REG8(0x16), 0x45}, {CCI_REG8(0x17), 0x53}, {CCI_REG8(0x18), 0x69}, + {CCI_REG8(0x19), 0x7d}, {CCI_REG8(0x1a), 0x8f}, {CCI_REG8(0x1b), 0x9d}, + {CCI_REG8(0x1c), 0xa9}, {CCI_REG8(0x1d), 0xbd}, {CCI_REG8(0x1e), 0xcd}, + {CCI_REG8(0x1f), 0xd9}, {CCI_REG8(0x20), 0xe3}, {CCI_REG8(0x21), 0xea}, + {CCI_REG8(0x22), 0xef}, {CCI_REG8(0x23), 0xf5}, {CCI_REG8(0x24), 0xf9}, + {CCI_REG8(0x25), 0xff}, + {GC2145_REG_PAGE_SELECT, 0x00}, + {CCI_REG8(0xc6), 0x20}, {CCI_REG8(0xc7), 0x2b}, + /* Gamma 2 */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x26), 0x0f}, {CCI_REG8(0x27), 0x14}, {CCI_REG8(0x28), 0x19}, + {CCI_REG8(0x29), 0x1e}, {CCI_REG8(0x2a), 0x27}, {CCI_REG8(0x2b), 0x33}, + {CCI_REG8(0x2c), 0x3b}, {CCI_REG8(0x2d), 0x45}, {CCI_REG8(0x2e), 0x59}, + {CCI_REG8(0x2f), 0x69}, {CCI_REG8(0x30), 0x7c}, {CCI_REG8(0x31), 0x89}, + {CCI_REG8(0x32), 0x98}, {CCI_REG8(0x33), 0xae}, {CCI_REG8(0x34), 0xc0}, + {CCI_REG8(0x35), 0xcf}, {CCI_REG8(0x36), 0xda}, {CCI_REG8(0x37), 0xe2}, + {CCI_REG8(0x38), 0xe9}, {CCI_REG8(0x39), 0xf3}, {CCI_REG8(0x3a), 0xf9}, + {CCI_REG8(0x3b), 0xff}, + /* YCP */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0xd1), 0x32}, {CCI_REG8(0xd2), 0x32}, {CCI_REG8(0xd3), 0x40}, + {CCI_REG8(0xd6), 0xf0}, {CCI_REG8(0xd7), 0x10}, {CCI_REG8(0xd8), 0xda}, + {CCI_REG8(0xdd), 0x14}, {CCI_REG8(0xde), 0x86}, {CCI_REG8(0xed), 0x80}, + {CCI_REG8(0xee), 0x00}, {CCI_REG8(0xef), 0x3f}, {CCI_REG8(0xd8), 0xd8}, + /* ABS */ + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x9f), 0x40}, + /* LSC */ + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0xc2), 0x14}, {CCI_REG8(0xc3), 0x0d}, {CCI_REG8(0xc4), 0x0c}, + {CCI_REG8(0xc8), 0x15}, {CCI_REG8(0xc9), 0x0d}, {CCI_REG8(0xca), 0x0a}, + {CCI_REG8(0xbc), 0x24}, {CCI_REG8(0xbd), 0x10}, {CCI_REG8(0xbe), 0x0b}, + {CCI_REG8(0xb6), 0x25}, {CCI_REG8(0xb7), 0x16}, {CCI_REG8(0xb8), 0x15}, + {CCI_REG8(0xc5), 0x00}, {CCI_REG8(0xc6), 0x00}, {CCI_REG8(0xc7), 0x00}, + {CCI_REG8(0xcb), 0x00}, {CCI_REG8(0xcc), 0x00}, {CCI_REG8(0xcd), 0x00}, + {CCI_REG8(0xbf), 0x07}, {CCI_REG8(0xc0), 0x00}, {CCI_REG8(0xc1), 0x00}, + {CCI_REG8(0xb9), 0x00}, {CCI_REG8(0xba), 0x00}, {CCI_REG8(0xbb), 0x00}, + {CCI_REG8(0xaa), 0x01}, {CCI_REG8(0xab), 0x01}, {CCI_REG8(0xac), 0x00}, + {CCI_REG8(0xad), 0x05}, {CCI_REG8(0xae), 0x06}, {CCI_REG8(0xaf), 0x0e}, + {CCI_REG8(0xb0), 0x0b}, {CCI_REG8(0xb1), 0x07}, {CCI_REG8(0xb2), 0x06}, + {CCI_REG8(0xb3), 0x17}, {CCI_REG8(0xb4), 0x0e}, {CCI_REG8(0xb5), 0x0e}, + {CCI_REG8(0xd0), 0x09}, {CCI_REG8(0xd1), 0x00}, {CCI_REG8(0xd2), 0x00}, + {CCI_REG8(0xd6), 0x08}, {CCI_REG8(0xd7), 0x00}, {CCI_REG8(0xd8), 0x00}, + {CCI_REG8(0xd9), 0x00}, {CCI_REG8(0xda), 0x00}, {CCI_REG8(0xdb), 0x00}, + {CCI_REG8(0xd3), 0x0a}, {CCI_REG8(0xd4), 0x00}, {CCI_REG8(0xd5), 0x00}, + {CCI_REG8(0xa4), 0x00}, {CCI_REG8(0xa5), 0x00}, {CCI_REG8(0xa6), 0x77}, + {CCI_REG8(0xa7), 0x77}, {CCI_REG8(0xa8), 0x77}, {CCI_REG8(0xa9), 0x77}, + {CCI_REG8(0xa1), 0x80}, {CCI_REG8(0xa2), 0x80}, + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0xdf), 0x0d}, {CCI_REG8(0xdc), 0x25}, {CCI_REG8(0xdd), 0x30}, + {CCI_REG8(0xe0), 0x77}, {CCI_REG8(0xe1), 0x80}, {CCI_REG8(0xe2), 0x77}, + {CCI_REG8(0xe3), 0x90}, {CCI_REG8(0xe6), 0x90}, {CCI_REG8(0xe7), 0xa0}, + {CCI_REG8(0xe8), 0x90}, {CCI_REG8(0xe9), 0xa0}, + /* AWB */ + /* measure window */ + {GC2145_REG_PAGE_SELECT, 0x00}, + {CCI_REG8(0xec), 0x06}, {CCI_REG8(0xed), 0x04}, {CCI_REG8(0xee), 0x60}, + {CCI_REG8(0xef), 0x90}, {CCI_REG8(0xb6), 0x01}, + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4b), 0x01}, + {CCI_REG8(0x4f), 0x00}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x71}, {CCI_REG8(0x4e), 0x01}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x91}, {CCI_REG8(0x4e), 0x01}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x70}, {CCI_REG8(0x4e), 0x01}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x90}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xb0}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8f}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6f}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaf}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xd0}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xf0}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcf}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xef}, {CCI_REG8(0x4e), 0x02}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6e}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8e}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xae}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xce}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4d}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6d}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8d}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xad}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcd}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4c}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6c}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8c}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xac}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcc}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcb}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4b}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6b}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8b}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xab}, {CCI_REG8(0x4e), 0x03}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaa}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x04}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0b}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0a}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xeb}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xea}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x29}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x2a}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x4a}, {CCI_REG8(0x4e), 0x05}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x49}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x48}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x68}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe9}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc8}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe8}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa7}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc7}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe7}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x07}, {CCI_REG8(0x4e), 0x07}, + {CCI_REG8(0x4f), 0x01}, + {CCI_REG8(0x50), 0x80}, {CCI_REG8(0x51), 0xa8}, {CCI_REG8(0x52), 0x47}, + {CCI_REG8(0x53), 0x38}, {CCI_REG8(0x54), 0xc7}, {CCI_REG8(0x56), 0x0e}, + {CCI_REG8(0x58), 0x08}, {CCI_REG8(0x5b), 0x00}, {CCI_REG8(0x5c), 0x74}, + {CCI_REG8(0x5d), 0x8b}, {CCI_REG8(0x61), 0xdb}, {CCI_REG8(0x62), 0xb8}, + {CCI_REG8(0x63), 0x86}, {CCI_REG8(0x64), 0xc0}, {CCI_REG8(0x65), 0x04}, + {CCI_REG8(0x67), 0xa8}, {CCI_REG8(0x68), 0xb0}, {CCI_REG8(0x69), 0x00}, + {CCI_REG8(0x6a), 0xa8}, {CCI_REG8(0x6b), 0xb0}, {CCI_REG8(0x6c), 0xaf}, + {CCI_REG8(0x6d), 0x8b}, {CCI_REG8(0x6e), 0x50}, {CCI_REG8(0x6f), 0x18}, + {CCI_REG8(0x73), 0xf0}, {CCI_REG8(0x70), 0x0d}, {CCI_REG8(0x71), 0x60}, + {CCI_REG8(0x72), 0x80}, {CCI_REG8(0x74), 0x01}, {CCI_REG8(0x75), 0x01}, + {CCI_REG8(0x7f), 0x0c}, {CCI_REG8(0x76), 0x70}, {CCI_REG8(0x77), 0x58}, + {CCI_REG8(0x78), 0xa0}, {CCI_REG8(0x79), 0x5e}, {CCI_REG8(0x7a), 0x54}, + {CCI_REG8(0x7b), 0x58}, + /* CC */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0xc0), 0x01}, {CCI_REG8(0xc1), 0x44}, {CCI_REG8(0xc2), 0xfd}, + {CCI_REG8(0xc3), 0x04}, {CCI_REG8(0xc4), 0xf0}, {CCI_REG8(0xc5), 0x48}, + {CCI_REG8(0xc6), 0xfd}, {CCI_REG8(0xc7), 0x46}, {CCI_REG8(0xc8), 0xfd}, + {CCI_REG8(0xc9), 0x02}, {CCI_REG8(0xca), 0xe0}, {CCI_REG8(0xcb), 0x45}, + {CCI_REG8(0xcc), 0xec}, {CCI_REG8(0xcd), 0x48}, {CCI_REG8(0xce), 0xf0}, + {CCI_REG8(0xcf), 0xf0}, {CCI_REG8(0xe3), 0x0c}, {CCI_REG8(0xe4), 0x4b}, + {CCI_REG8(0xe5), 0xe0}, + /* ABS */ + {GC2145_REG_PAGE_SELECT, 0x01}, + {CCI_REG8(0x9f), 0x40}, + /* Dark sun */ + {GC2145_REG_PAGE_SELECT, 0x02}, + {CCI_REG8(0x40), 0xbf}, {CCI_REG8(0x46), 0xcf}, +}; + +#define GC2145_640_480_PIXELRATE 30000000 +#define GC2145_640_480_LINKFREQ 120000000 +#define GC2145_640_480_HBLANK 0x0130 +#define GC2145_640_480_VBLANK 0x000c +static const struct cci_reg_sequence gc2145_mode_640_480_regs[] = { + {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0}, + {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06}, + {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x86}, + {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e}, + /* Disable PAD IO */ + {GC2145_REG_PAD_IO, 0x00}, + {GC2145_REG_PAGE_SELECT, 0x00}, + /* Row/Col start - 0/0 */ + {GC2145_REG_ROW_START, 0x0000}, + {GC2145_REG_COL_START, 0x0000}, + /* Window size 1216/1618 */ + {GC2145_REG_WIN_HEIGHT, 0x04c0}, + {GC2145_REG_WIN_WIDTH, 0x0652}, + /* Scalar more */ + {CCI_REG8(0xfd), 0x01}, {CCI_REG8(0xfa), 0x00}, + /* Crop 640-480@0-0 */ + {GC2145_REG_CROP_ENABLE, 0x01}, + {GC2145_REG_CROP_Y, 0x0000}, + {GC2145_REG_CROP_X, 0x0000}, + {GC2145_REG_CROP_HEIGHT, 0x01e0}, + {GC2145_REG_CROP_WIDTH, 0x0280}, + /* Subsampling configuration */ + {CCI_REG8(0x99), 0x55}, {CCI_REG8(0x9a), 0x06}, {CCI_REG8(0x9b), 0x01}, + {CCI_REG8(0x9c), 0x23}, {CCI_REG8(0x9d), 0x00}, {CCI_REG8(0x9e), 0x00}, + {CCI_REG8(0x9f), 0x01}, {CCI_REG8(0xa0), 0x23}, {CCI_REG8(0xa1), 0x00}, + {CCI_REG8(0xa2), 0x00}, + {GC2145_REG_PAGE_SELECT, 0x01}, + /* AEC anti-flicker */ + {CCI_REG16(0x25), 0x0175}, + /* AEC exposure level 1-5 */ + {CCI_REG16(0x27), 0x045f}, {CCI_REG16(0x29), 0x045f}, + {CCI_REG16(0x2b), 0x045f}, {CCI_REG16(0x2d), 0x045f}, +}; + +#define GC2145_1280_720_PIXELRATE 48000000 +#define GC2145_1280_720_LINKFREQ 192000000 +#define GC2145_1280_720_HBLANK 0x0156 +#define GC2145_1280_720_VBLANK 0x0011 +static const struct cci_reg_sequence gc2145_mode_1280_720_regs[] = { + {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0}, + {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06}, + {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x83}, + {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e}, + /* Disable PAD IO */ + {GC2145_REG_PAD_IO, 0x00}, + {GC2145_REG_PAGE_SELECT, 0x00}, + /* Row/Col start - 240/160 */ + {GC2145_REG_ROW_START, 0x00f0}, + {GC2145_REG_COL_START, 0x00a0}, + /* Window size 736/1296 */ + {GC2145_REG_WIN_HEIGHT, 0x02e0}, + {GC2145_REG_WIN_WIDTH, 0x0510}, + /* Crop 1280-720@0-0 */ + {GC2145_REG_CROP_ENABLE, 0x01}, + {GC2145_REG_CROP_Y, 0x0000}, + {GC2145_REG_CROP_X, 0x0000}, + {GC2145_REG_CROP_HEIGHT, 0x02d0}, + {GC2145_REG_CROP_WIDTH, 0x0500}, + {GC2145_REG_PAGE_SELECT, 0x01}, + /* AEC anti-flicker */ + {CCI_REG16(0x25), 0x00e6}, + /* AEC exposure level 1-5 */ + {CCI_REG16(0x27), 0x02b2}, {CCI_REG16(0x29), 0x02b2}, + {CCI_REG16(0x2b), 0x02b2}, {CCI_REG16(0x2d), 0x02b2}, +}; + +#define GC2145_1600_1200_PIXELRATE 60000000 +#define GC2145_1600_1200_LINKFREQ 240000000 +#define GC2145_1600_1200_HBLANK 0x0156 +#define GC2145_1600_1200_VBLANK 0x0010 +static const struct cci_reg_sequence gc2145_mode_1600_1200_regs[] = { + {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0}, + {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06}, + {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x84}, + {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e}, + /* Disable PAD IO */ + {GC2145_REG_PAD_IO, 0x00}, + {GC2145_REG_PAGE_SELECT, 0x00}, + /* Row/Col start - 0/0 */ + {GC2145_REG_ROW_START, 0x0000}, + {GC2145_REG_COL_START, 0x0000}, + /* Window size: 1216/1618 */ + {GC2145_REG_WIN_HEIGHT, 0x04c0}, + {GC2145_REG_WIN_WIDTH, 0x0652}, + /* Crop 1600-1200@0-0 */ + {GC2145_REG_CROP_ENABLE, 0x01}, + {GC2145_REG_CROP_Y, 0x0000}, + {GC2145_REG_CROP_X, 0x0000}, + {GC2145_REG_CROP_HEIGHT, 0x04b0}, + {GC2145_REG_CROP_WIDTH, 0x0640}, + {GC2145_REG_PAGE_SELECT, 0x01}, + /* AEC anti-flicker */ + {CCI_REG16(0x25), 0x00fa}, + /* AEC exposure level 1-5 */ + {CCI_REG16(0x27), 0x04e2}, {CCI_REG16(0x29), 0x04e2}, + {CCI_REG16(0x2b), 0x04e2}, {CCI_REG16(0x2d), 0x04e2}, +}; + +static const s64 gc2145_link_freq_menu[] = { + GC2145_640_480_LINKFREQ, + GC2145_1280_720_LINKFREQ, + GC2145_1600_1200_LINKFREQ, +}; + +/* Regulators supplies */ +static const char * const gc2145_supply_name[] = { + "iovdd", /* Digital I/O (1.7-3V) suppply */ + "avdd", /* Analog (2.7-3V) supply */ + "dvdd", /* Digital Core (1.7-1.9V) supply */ +}; + +#define GC2145_NUM_SUPPLIES ARRAY_SIZE(gc2145_supply_name) + +/* Mode configs */ +#define GC2145_MODE_640X480 0 +#define GC2145_MODE_1280X720 1 +#define GC2145_MODE_1600X1200 2 +static const struct gc2145_mode supported_modes[] = { + { + /* 640x480 30fps mode */ + .width = 640, + .height = 480, + .reg_seq = gc2145_mode_640_480_regs, + .reg_seq_size = ARRAY_SIZE(gc2145_mode_640_480_regs), + .pixel_rate = GC2145_640_480_PIXELRATE, + .crop = { + .top = 0, + .left = 0, + .width = 640, + .height = 480, + }, + .hblank = GC2145_640_480_HBLANK, + .vblank = GC2145_640_480_VBLANK, + .link_freq_index = GC2145_MODE_640X480, + }, + { + /* 1280x720 30fps mode */ + .width = 1280, + .height = 720, + .reg_seq = gc2145_mode_1280_720_regs, + .reg_seq_size = ARRAY_SIZE(gc2145_mode_1280_720_regs), + .pixel_rate = GC2145_1280_720_PIXELRATE, + .crop = { + .top = 160, + .left = 240, + .width = 1280, + .height = 720, + }, + .hblank = GC2145_1280_720_HBLANK, + .vblank = GC2145_1280_720_VBLANK, + .link_freq_index = GC2145_MODE_1280X720, + }, + { + /* 1600x1200 20fps mode */ + .width = 1600, + .height = 1200, + .reg_seq = gc2145_mode_1600_1200_regs, + .reg_seq_size = ARRAY_SIZE(gc2145_mode_1600_1200_regs), + .pixel_rate = GC2145_1600_1200_PIXELRATE, + .crop = { + .top = 0, + .left = 0, + .width = 1600, + .height = 1200, + }, + .hblank = GC2145_1600_1200_HBLANK, + .vblank = GC2145_1600_1200_VBLANK, + .link_freq_index = GC2145_MODE_1600X1200, + }, +}; + +/** + * struct gc2145_format - GC2145 pixel format description + * @code: media bus (MBUS) associated code + * @datatype: MIPI CSI2 data type + * @output_fmt: GC2145 output format + * @switch_bit: GC2145 first/second switch + */ +struct gc2145_format { + unsigned int code; + unsigned char datatype; + unsigned char output_fmt; + bool switch_bit; +}; + +/* All supported formats */ +static const struct gc2145_format supported_formats[] = { + { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .output_fmt = 0x00, + }, + { + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .output_fmt = 0x01, + }, + { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .output_fmt = 0x02, + }, + { + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .output_fmt = 0x03, + }, + { + .code = MEDIA_BUS_FMT_RGB565_1X16, + .datatype = MIPI_CSI2_DT_RGB565, + .output_fmt = 0x06, + .switch_bit = true, + }, +}; + +struct gc2145_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; +}; + +struct gc2145 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct regmap *regmap; + struct clk *xclk; + + struct gpio_desc *reset_gpio; + struct gpio_desc *powerdown_gpio; + struct regulator_bulk_data supplies[GC2145_NUM_SUPPLIES]; + + /* V4L2 controls */ + struct gc2145_ctrls ctrls; + + /* Current mode */ + const struct gc2145_mode *mode; +}; + +static inline struct gc2145 *to_gc2145(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct gc2145, sd); +} + +static inline struct v4l2_subdev *gc2145_ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct gc2145, + ctrls.handler)->sd; +} + +static const struct gc2145_format * +gc2145_get_format_code(struct gc2145 *gc2145, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { + if (supported_formats[i].code == code) + break; + } + + if (i >= ARRAY_SIZE(supported_formats)) + i = 0; + + return &supported_formats[i]; +} + +static void gc2145_update_pad_format(struct gc2145 *gc2145, + const struct gc2145_mode *mode, + struct v4l2_mbus_framefmt *fmt, u32 code) +{ + fmt->code = code; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int gc2145_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct gc2145 *gc2145 = to_gc2145(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + /* Initialize pad format */ + format = v4l2_subdev_state_get_format(state, 0); + gc2145_update_pad_format(gc2145, &supported_modes[0], format, + MEDIA_BUS_FMT_RGB565_1X16); + + /* Initialize crop rectangle. */ + crop = v4l2_subdev_state_get_crop(state, 0); + *crop = supported_modes[0].crop; + + return 0; +} + +static int gc2145_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); + return 0; + + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = GC2145_NATIVE_WIDTH; + sel->r.height = GC2145_NATIVE_HEIGHT; + + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = 1600; + sel->r.height = 1200; + + return 0; + } + + return -EINVAL; +} + +static int gc2145_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(supported_formats)) + return -EINVAL; + + code->code = supported_formats[code->index].code; + return 0; +} + +static int gc2145_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct gc2145 *gc2145 = to_gc2145(sd); + const struct gc2145_format *gc2145_format; + u32 code; + + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + gc2145_format = gc2145_get_format_code(gc2145, fse->code); + code = gc2145_format->code; + if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int gc2145_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct gc2145 *gc2145 = to_gc2145(sd); + const struct gc2145_mode *mode; + const struct gc2145_format *gc2145_fmt; + struct v4l2_mbus_framefmt *framefmt; + struct gc2145_ctrls *ctrls = &gc2145->ctrls; + struct v4l2_rect *crop; + + gc2145_fmt = gc2145_get_format_code(gc2145, fmt->format.code); + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + + gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + gc2145->mode = mode; + /* Update pixel_rate based on the mode */ + __v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mode->pixel_rate); + /* Update link_freq based on the mode */ + __v4l2_ctrl_s_ctrl(ctrls->link_freq, mode->link_freq_index); + /* Update hblank/vblank based on the mode */ + __v4l2_ctrl_s_ctrl(ctrls->hblank, mode->hblank); + __v4l2_ctrl_s_ctrl(ctrls->vblank, mode->vblank); + } + *framefmt = fmt->format; + crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad); + *crop = mode->crop; + + return 0; +} + +static const struct cci_reg_sequence gc2145_common_mipi_regs[] = { + {GC2145_REG_PAGE_SELECT, 0x03}, + {GC2145_REG_DPHY_ANALOG_MODE1, GC2145_DPHY_MODE_PHY_CLK_EN | + GC2145_DPHY_MODE_PHY_LANE0_EN | + GC2145_DPHY_MODE_PHY_LANE1_EN | + GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL}, + {GC2145_REG_DPHY_ANALOG_MODE2, GC2145_DPHY_CLK_DIFF(2) | + GC2145_DPHY_LANE0_DIFF(2)}, + {GC2145_REG_DPHY_ANALOG_MODE3, GC2145_DPHY_LANE1_DIFF(0) | + GC2145_DPHY_CLK_DELAY}, + {GC2145_REG_FIFO_MODE, GC2145_FIFO_MODE_READ_GATE | + GC2145_FIFO_MODE_MIPI_CLK_MODULE}, + {GC2145_REG_DPHY_MODE, GC2145_DPHY_MODE_TRIGGER_PROG}, + /* Clock & Data lanes timing */ + {GC2145_REG_T_LPX, 0x10}, + {GC2145_REG_T_CLK_HS_PREPARE, 0x04}, {GC2145_REG_T_CLK_ZERO, 0x10}, + {GC2145_REG_T_CLK_PRE, 0x10}, {GC2145_REG_T_CLK_POST, 0x10}, + {GC2145_REG_T_CLK_TRAIL, 0x05}, + {GC2145_REG_T_HS_PREPARE, 0x03}, {GC2145_REG_T_HS_ZERO, 0x0a}, + {GC2145_REG_T_HS_TRAIL, 0x06}, +}; + +static int gc2145_config_mipi_mode(struct gc2145 *gc2145, + const struct gc2145_format *gc2145_format) +{ + u16 lwc, fifo_full_lvl; + int ret = 0; + + /* Common MIPI settings */ + cci_multi_reg_write(gc2145->regmap, gc2145_common_mipi_regs, + ARRAY_SIZE(gc2145_common_mipi_regs), &ret); + + /* + * Adjust the MIPI buffer settings. + * For YUV/RGB, LWC = image width * 2 + * For RAW8, LWC = image width + * For RAW10, LWC = image width * 1.25 + */ + lwc = gc2145->mode->width * 2; + cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret); + cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret); + + /* + * Adjust the MIPI FIFO Full Level + * 640x480 RGB: 0x0190 + * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001 + * 1600x1200 RAW: 0x0190 + */ + if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600) + fifo_full_lvl = 0x0001; + else + fifo_full_lvl = 0x0190; + + cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH, + fifo_full_lvl >> 8, &ret); + cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW, + fifo_full_lvl & 0xff, &ret); + + /* + * Set the FIFO gate mode / MIPI wdiv set: + * 0xf1 in case of RAW mode and 0xf0 otherwise + */ + cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret); + + /* Set the MIPI data type */ + cci_write(gc2145->regmap, GC2145_REG_MIPI_DT, + gc2145_format->datatype, &ret); + + /* Configure mode and enable CSI */ + cci_write(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE, + GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE | + GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, &ret); + + return ret; +} + +static int gc2145_start_streaming(struct gc2145 *gc2145, + struct v4l2_subdev_state *state) +{ + struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); + const struct gc2145_format *gc2145_format; + struct v4l2_mbus_framefmt *fmt; + int ret; + + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + return ret; + + /* Apply default values of current mode */ + cci_multi_reg_write(gc2145->regmap, gc2145->mode->reg_seq, + gc2145->mode->reg_seq_size, &ret); + cci_multi_reg_write(gc2145->regmap, gc2145_common_regs, + ARRAY_SIZE(gc2145_common_regs), &ret); + if (ret) { + dev_err(&client->dev, "%s failed to write regs\n", __func__); + goto err_rpm_put; + } + + fmt = v4l2_subdev_state_get_format(state, 0); + gc2145_format = gc2145_get_format_code(gc2145, fmt->code); + + /* Set the output format */ + cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret); + + cci_write(gc2145->regmap, GC2145_REG_OUTPUT_FMT, + gc2145_format->output_fmt, &ret); + cci_update_bits(gc2145->regmap, GC2145_REG_BYPASS_MODE, + GC2145_BYPASS_MODE_SWITCH, + gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH + : 0, &ret); + if (ret) { + dev_err(&client->dev, "%s failed to write regs\n", __func__); + goto err_rpm_put; + } + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(&gc2145->ctrls.handler); + if (ret) { + dev_err(&client->dev, "%s failed to apply ctrls\n", __func__); + goto err_rpm_put; + } + + /* Perform MIPI specific configuration */ + ret = gc2145_config_mipi_mode(gc2145, gc2145_format); + if (ret) { + dev_err(&client->dev, "%s failed to write mipi conf\n", + __func__); + goto err_rpm_put; + } + + cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret); + + return 0; + +err_rpm_put: + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + return ret; +} + +static void gc2145_stop_streaming(struct gc2145 *gc2145) +{ + struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); + int ret = 0; + + /* Disable lanes & mipi streaming */ + cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x03, &ret); + cci_update_bits(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE, + GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, 0, + &ret); + cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret); + if (ret) + dev_err(&client->dev, "%s failed to write regs\n", __func__); + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); +} + +static int gc2145_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct gc2145 *gc2145 = to_gc2145(sd); + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (enable) + ret = gc2145_start_streaming(gc2145, state); + else + gc2145_stop_streaming(gc2145); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +/* Power/clock management functions */ +static int gc2145_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc2145 *gc2145 = to_gc2145(sd); + int ret; + + ret = regulator_bulk_enable(GC2145_NUM_SUPPLIES, gc2145->supplies); + if (ret) { + dev_err(dev, "failed to enable regulators\n"); + return ret; + } + + ret = clk_prepare_enable(gc2145->xclk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + goto reg_off; + } + + gpiod_set_value_cansleep(gc2145->powerdown_gpio, 0); + gpiod_set_value_cansleep(gc2145->reset_gpio, 0); + + /* + * Datasheet doesn't mention timing between PWDN/RESETB control and + * i2c access however, experimentation shows that a rather big delay is + * needed. + */ + msleep(41); + + return 0; + +reg_off: + regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies); + + return ret; +} + +static int gc2145_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc2145 *gc2145 = to_gc2145(sd); + + gpiod_set_value_cansleep(gc2145->powerdown_gpio, 1); + gpiod_set_value_cansleep(gc2145->reset_gpio, 1); + clk_disable_unprepare(gc2145->xclk); + regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies); + + return 0; +} + +static int gc2145_get_regulators(struct gc2145 *gc2145) +{ + struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); + unsigned int i; + + for (i = 0; i < GC2145_NUM_SUPPLIES; i++) + gc2145->supplies[i].supply = gc2145_supply_name[i]; + + return devm_regulator_bulk_get(&client->dev, GC2145_NUM_SUPPLIES, + gc2145->supplies); +} + +/* Verify chip ID */ +static int gc2145_identify_module(struct gc2145 *gc2145) +{ + struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); + int ret; + u64 chip_id; + + ret = cci_read(gc2145->regmap, GC2145_REG_CHIP_ID, &chip_id, NULL); + if (ret) { + dev_err(&client->dev, "failed to read chip id (%d)\n", ret); + return ret; + } + + if (chip_id != GC2145_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", + GC2145_CHIP_ID, chip_id); + return -EIO; + } + + return 0; +} + +static const char * const test_pattern_menu[] = { + "Disabled", + "Colored patterns", + "Uniform white", + "Uniform yellow", + "Uniform cyan", + "Uniform green", + "Uniform magenta", + "Uniform red", + "Uniform black", +}; + +#define GC2145_TEST_PATTERN_ENABLE BIT(0) +#define GC2145_TEST_PATTERN_UXGA BIT(3) + +#define GC2145_TEST_UNIFORM BIT(3) +#define GC2145_TEST_WHITE (4 << 4) +#define GC2145_TEST_YELLOW (8 << 4) +#define GC2145_TEST_CYAN (9 << 4) +#define GC2145_TEST_GREEN (6 << 4) +#define GC2145_TEST_MAGENTA (10 << 4) +#define GC2145_TEST_RED (5 << 4) +#define GC2145_TEST_BLACK (0) + +static const u8 test_pattern_val[] = { + 0, + GC2145_TEST_PATTERN_ENABLE, + GC2145_TEST_UNIFORM | GC2145_TEST_WHITE, + GC2145_TEST_UNIFORM | GC2145_TEST_YELLOW, + GC2145_TEST_UNIFORM | GC2145_TEST_CYAN, + GC2145_TEST_UNIFORM | GC2145_TEST_GREEN, + GC2145_TEST_UNIFORM | GC2145_TEST_MAGENTA, + GC2145_TEST_UNIFORM | GC2145_TEST_RED, + GC2145_TEST_UNIFORM | GC2145_TEST_BLACK, +}; + +static const struct v4l2_subdev_core_ops gc2145_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops gc2145_video_ops = { + .s_stream = gc2145_set_stream, +}; + +static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { + .init_cfg = gc2145_init_cfg, + .enum_mbus_code = gc2145_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = gc2145_set_pad_format, + .get_selection = gc2145_get_selection, + .enum_frame_size = gc2145_enum_frame_size, +}; + +static const struct v4l2_subdev_ops gc2145_subdev_ops = { + .core = &gc2145_core_ops, + .video = &gc2145_video_ops, + .pad = &gc2145_pad_ops, +}; + +static int gc2145_set_ctrl_test_pattern(struct gc2145 *gc2145, int value) +{ + int ret = 0; + + if (!value) { + /* Disable test pattern */ + cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2, 0, &ret); + return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0, + &ret); + } + + /* Enable test pattern, colored or uniform */ + cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2, + GC2145_TEST_PATTERN_ENABLE | GC2145_TEST_PATTERN_UXGA, &ret); + + if (!(test_pattern_val[value] & GC2145_TEST_UNIFORM)) + return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0, + &ret); + + /* Uniform */ + return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, + test_pattern_val[value], &ret); +} + +static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = gc2145_ctrl_to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct gc2145 *gc2145 = to_gc2145(sd); + int ret; + + if (pm_runtime_get_if_in_use(&client->dev) == 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HBLANK: + ret = cci_write(gc2145->regmap, GC2145_REG_HBLANK, ctrl->val, + NULL); + break; + case V4L2_CID_VBLANK: + ret = cci_write(gc2145->regmap, GC2145_REG_VBLANK, ctrl->val, + NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = gc2145_set_ctrl_test_pattern(gc2145, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1, + BIT(0), (ctrl->val ? BIT(0) : 0), NULL); + break; + case V4L2_CID_VFLIP: + ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1, + BIT(1), (ctrl->val ? BIT(1) : 0), NULL); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops gc2145_ctrl_ops = { + .s_ctrl = gc2145_s_ctrl, +}; + +/* Initialize control handlers */ +static int gc2145_init_controls(struct gc2145 *gc2145) +{ + struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); + const struct v4l2_ctrl_ops *ops = &gc2145_ctrl_ops; + struct gc2145_ctrls *ctrls = &gc2145->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + struct v4l2_fwnode_device_properties props; + int ret; + + ret = v4l2_ctrl_handler_init(hdl, 12); + if (ret) + return ret; + + ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, + GC2145_640_480_PIXELRATE, + GC2145_1600_1200_PIXELRATE, 1, + supported_modes[0].pixel_rate); + + ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, + ARRAY_SIZE(gc2145_link_freq_menu) - 1, + 0, gc2145_link_freq_menu); + if (ctrls->link_freq) + ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, + 0, 0xfff, 1, GC2145_640_480_HBLANK); + + ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + 0, 0x1fff, 1, GC2145_640_480_VBLANK); + + ctrls->test_pattern = + v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + ret = hdl->error; + dev_err(&client->dev, "control init failed (%d)\n", ret); + goto error; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(hdl, &gc2145_ctrl_ops, + &props); + if (ret) + goto error; + + gc2145->sd.ctrl_handler = hdl; + + return 0; + +error: + v4l2_ctrl_handler_free(hdl); + + return ret; +} + +static int gc2145_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *endpoint; + struct v4l2_fwnode_endpoint ep_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { + dev_err(dev, "endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg); + fwnode_handle_put(endpoint); + if (ret) + return ret; + + /* Check the number of MIPI CSI2 data lanes */ + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { + dev_err(dev, "only 2 data lanes are currently supported\n"); + ret = -EINVAL; + goto out; + } + + /* Check the link frequency set in device tree */ + if (!ep_cfg.nr_of_link_frequencies) { + dev_err(dev, "link-frequency property not found in DT\n"); + ret = -EINVAL; + goto out; + } + + if (ep_cfg.nr_of_link_frequencies != 3 || + ep_cfg.link_frequencies[0] != GC2145_640_480_LINKFREQ || + ep_cfg.link_frequencies[1] != GC2145_1280_720_LINKFREQ || + ep_cfg.link_frequencies[2] != GC2145_1600_1200_LINKFREQ) { + dev_err(dev, "Invalid link-frequencies provided\n"); + ret = -EINVAL; + } + +out: + v4l2_fwnode_endpoint_free(&ep_cfg); + + return ret; +} + +static int gc2145_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + unsigned int xclk_freq; + struct gc2145 *gc2145; + int ret; + + gc2145 = devm_kzalloc(&client->dev, sizeof(*gc2145), GFP_KERNEL); + if (!gc2145) + return -ENOMEM; + + v4l2_i2c_subdev_init(&gc2145->sd, client, &gc2145_subdev_ops); + + /* Check the hardware configuration in device tree */ + if (gc2145_check_hwcfg(dev)) + return -EINVAL; + + /* Get system clock (xclk) */ + gc2145->xclk = devm_clk_get(dev, NULL); + if (IS_ERR(gc2145->xclk)) + return dev_err_probe(dev, PTR_ERR(gc2145->xclk), + "failed to get xclk\n"); + + xclk_freq = clk_get_rate(gc2145->xclk); + if (xclk_freq != GC2145_XCLK_FREQ) { + dev_err(dev, "xclk frequency not supported: %d Hz\n", + xclk_freq); + return -EINVAL; + } + + ret = gc2145_get_regulators(gc2145); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulators\n"); + + /* Request optional reset pin */ + gc2145->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(gc2145->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(gc2145->reset_gpio), + "failed to get reset_gpio\n"); + + /* Request optional powerdown pin */ + gc2145->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(gc2145->powerdown_gpio)) + return dev_err_probe(dev, PTR_ERR(gc2145->powerdown_gpio), + "failed to get powerdown_gpio\n"); + + /* Initialise the regmap for further cci access */ + gc2145->regmap = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(gc2145->regmap)) + return dev_err_probe(dev, PTR_ERR(gc2145->regmap), + "failed to get cci regmap\n"); + + /* + * The sensor must be powered for gc2145_identify_module() + * to be able to read the CHIP_ID register + */ + ret = gc2145_power_on(dev); + if (ret) + return ret; + + ret = gc2145_identify_module(gc2145); + if (ret) + goto error_power_off; + + /* Set default mode */ + gc2145->mode = &supported_modes[0]; + + ret = gc2145_init_controls(gc2145); + if (ret) + goto error_power_off; + + /* Initialize subdev */ + gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + gc2145->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&gc2145->sd.entity, 1, &gc2145->pad); + if (ret) { + dev_err(dev, "failed to init entity pads: %d\n", ret); + goto error_handler_free; + } + + gc2145->sd.state_lock = gc2145->ctrls.handler.lock; + ret = v4l2_subdev_init_finalize(&gc2145->sd); + if (ret < 0) { + dev_err(dev, "subdev init error: %d\n", ret); + goto error_media_entity; + } + + /* Enable runtime PM and turn off the device */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(dev); + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + ret = v4l2_async_register_subdev_sensor(&gc2145->sd); + if (ret < 0) { + dev_err(dev, "failed to register sensor sub-device: %d\n", ret); + goto error_subdev_cleanup; + } + + return 0; + +error_subdev_cleanup: + v4l2_subdev_cleanup(&gc2145->sd); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + +error_media_entity: + media_entity_cleanup(&gc2145->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(&gc2145->ctrls.handler); + +error_power_off: + gc2145_power_off(dev); + + return ret; +} + +static void gc2145_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc2145 *gc2145 = to_gc2145(sd); + + v4l2_subdev_cleanup(sd); + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&gc2145->ctrls.handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + gc2145_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); +} + +static const struct of_device_id gc2145_dt_ids[] = { + { .compatible = "galaxycore,gc2145" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, gc2145_dt_ids); + +static const struct dev_pm_ops gc2145_pm_ops = { + RUNTIME_PM_OPS(gc2145_power_off, gc2145_power_on, NULL) +}; + +static struct i2c_driver gc2145_i2c_driver = { + .driver = { + .name = "gc2145", + .of_match_table = gc2145_dt_ids, + .pm = pm_ptr(&gc2145_pm_ops), + }, + .probe = gc2145_probe, + .remove = gc2145_remove, +}; + +module_i2c_driver(gc2145_i2c_driver); + +MODULE_AUTHOR("Alain Volmat "); +MODULE_DESCRIPTION("GalaxyCore GC2145 sensor driver"); +MODULE_LICENSE("GPL"); From a9c8c738066b7ba9e208cfc3200a6f60593982b4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 6 Nov 2023 09:31:41 +0200 Subject: [PATCH 2329/7721] device property: Add fwnode_name_eq() Add fwnode_name_eq() to implement the functionality of of_node_name_eq() on fwnode property API. The same convention of ending the comparison at '@' (besides NUL) is applied on also both ACPI and swnode. The function is intended for comparing unit address-less node names on DT and firmware or swnodes compliant with DT bindings. Reviewed-by: Laurent Pinchart Tested-by: Laurent Pinchart Acked-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/base/property.c | 28 ++++++++++++++++++++++++++++ include/linux/property.h | 1 + 2 files changed, 29 insertions(+) diff --git a/drivers/base/property.c b/drivers/base/property.c index 8c40abed7852..b79608ee0b46 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -594,6 +594,34 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) return fwnode_call_ptr_op(fwnode, get_name_prefix); } +/** + * fwnode_name_eq - Return true if node name is equal + * @fwnode: The firmware node + * @name: The name to which to compare the node name + * + * Compare the name provided as an argument to the name of the node, stopping + * the comparison at either NUL or '@' character, whichever comes first. This + * function is generally used for comparing node names while ignoring the + * possible unit address of the node. + * + * Return: true if the node name matches with the name provided in the @name + * argument, false otherwise. + */ +bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name) +{ + const char *node_name; + ptrdiff_t len; + + node_name = fwnode_get_name(fwnode); + if (!node_name) + return false; + + len = strchrnul(node_name, '@') - node_name; + + return str_has_prefix(node_name, name) == len; +} +EXPORT_SYMBOL_GPL(fwnode_name_eq); + /** * fwnode_get_parent - Return parent firwmare node * @fwnode: Firmware whose parent is retrieved diff --git a/include/linux/property.h b/include/linux/property.h index 9f2585d705a8..4ebbb169df20 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -109,6 +109,7 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, const char *fwnode_get_name(const struct fwnode_handle *fwnode); const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode); +bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name); struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode); struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode); From cba1ec57b33127ed810d3ab14645086a07e050a6 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Fri, 24 Nov 2023 16:26:23 +0200 Subject: [PATCH 2330/7721] dt-bindings: media: Add bindings for THine THP7312 ISP The THP7312 is an external ISP from THine. Add DT bindings for it. Signed-off-by: Paul Elder Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/i2c/thine,thp7312.yaml | 224 ++++++++++++++++++ MAINTAINERS | 8 + 2 files changed, 232 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml new file mode 100644 index 000000000000..1978fbb77a6c --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml @@ -0,0 +1,224 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Ideas on Board +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/thine,thp7312.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: THine THP7312 + +maintainers: + - Paul Elder + +description: + The THP7312 is a standalone ISP controlled over i2c, and is capable of + various image processing and correction functions, including 3A control. It + can be connected to CMOS image sensors from various vendors, supporting both + MIPI CSI-2 and parallel interfaces. It can also output on either MIPI CSI-2 + or parallel. The hardware is capable of transmitting and receiving MIPI + interlaved data strams with data types or multiple virtual channel + identifiers. + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: thine,thp7312 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: CLKI clock input + + thine,boot-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 1 + default: 1 + description: + Boot mode of the THP7312, reflecting the value of the BOOT[0] pin strap. + 0 is for the SPI/2-wire slave boot, 1 is for the SPI master boot (from + external flash ROM). + + reset-gpios: + maxItems: 1 + description: + Reference to the GPIO connected to the RESET_N pin, if any. + Must be released (set high) after all supplies are applied. + + vddcore-supply: + description: + 1.2V supply for core, PLL, MIPI rx and MIPI tx. + + vhtermrx-supply: + description: + Supply for input (RX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel. + + vddtx-supply: + description: + Supply for output (TX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel. + + vddhost-supply: + description: + Supply for host interface. 1.8V, 2.8V, or 3.3V. + + vddcmos-supply: + description: + Supply for sensor interface. 1.8V, 2.8V, or 3.3V. + + vddgpio-0-supply: + description: + Supply for GPIO_0. 1.8V, 2.8V, or 3.3V. + + vddgpio-1-supply: + description: + Supply for GPIO_1. 1.8V, 2.8V, or 3.3V. + + orientation: true + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + const: 4 # CSI-2 D-PHY + + data-lanes: + description: + This property is for lane reordering between the THP7312 and the + SoC. The sensor supports either two-lane, or four-lane operation. + If this property is omitted four-lane operation is assumed. For + two-lane operation the property must be set to <1 2>. + minItems: 2 + maxItems: 4 + items: + maximum: 4 + + sensors: + type: object + description: List of connected sensors + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^sensor@[01]$": + type: object + description: + Sensors connected to the first and second input, with one node per + sensor. + + properties: + thine,model: + $ref: /schemas/types.yaml#/definitions/string + description: + Model of the connected sensors. Must be a valid compatible string. + + reg: + description: THP7312 input port number + items: + - maximum: 1 + + data-lanes: + $ref: /schemas/media/video-interfaces.yaml#/properties/data-lanes + items: + maxItems: 4 + description: + This property is for lane reordering between the THP7312 and the imaging + sensor that it is connected to. + + required: + - reg + - data-lanes + + additionalProperties: false + + required: + - "#address-cells" + - "#size-cells" + + additionalProperties: false + +required: + - compatible + - reg + - reset-gpios + - clocks + - vddcore-supply + - vhtermrx-supply + - vddtx-supply + - vddhost-supply + - vddcmos-supply + - vddgpio-0-supply + - vddgpio-1-supply + - sensors + - port + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@61 { + compatible = "thine,thp7312"; + reg = <0x61>; + + pinctrl-names = "default"; + pinctrl-0 = <&cam1_pins_default>; + + reset-gpios = <&pio 119 GPIO_ACTIVE_LOW>; + clocks = <&camera61_clk>; + + vddcore-supply = <&vsys_v4p2>; + vhtermrx-supply = <&vsys_v4p2>; + vddtx-supply = <&vsys_v4p2>; + vddhost-supply = <&vsys_v4p2>; + vddcmos-supply = <&vsys_v4p2>; + vddgpio-0-supply = <&vsys_v4p2>; + vddgpio-1-supply = <&vsys_v4p2>; + + orientation = <0>; + rotation = <0>; + + sensors { + #address-cells = <1>; + #size-cells = <0>; + + sensor@0 { + thine,model = "sony,imx258"; + reg = <0>; + + data-lanes = <4 1 3 2>; + }; + }; + + port { + thp7312_2_endpoint: endpoint { + remote-endpoint = <&mipi_thp7312_2>; + bus-type = ; + data-lanes = <4 2 1 3>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index b9fc8fdaa320..6d20dc6f617c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21663,6 +21663,14 @@ S: Maintained F: Documentation/ABI/testing/sysfs-class-firmware-attributes F: drivers/platform/x86/think-lmi.? +THP7312 ISP DRIVER +M: Laurent Pinchart +M: Paul Elder +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml + THUNDERBOLT DMA TRAFFIC TEST DRIVER M: Isaac Hazan L: linux-usb@vger.kernel.org From 0d9e32a8075a6cccbab294f98ccf7d33821d9b1c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 24 Nov 2023 16:26:24 +0200 Subject: [PATCH 2331/7721] media: uapi: Add controls for the THP7312 ISP The THP7312 is an external ISP from THine. As such, it implements a large number of parameters to control all aspects of the image processing. Many of those controls are already standard in V4L2, but some are fairly device-specific. Reserve a range of 32 controls for the device. The driver will implement 4 device-specific controls to start with, define and document them. 28 additional device-specific controls should be enough for future development. Co-developed-by: Paul Elder Signed-off-by: Paul Elder Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../userspace-api/media/drivers/index.rst | 1 + .../userspace-api/media/drivers/thp7312.rst | 39 +++++++++++++++++++ MAINTAINERS | 2 + include/uapi/linux/thp7312.h | 19 +++++++++ include/uapi/linux/v4l2-controls.h | 6 +++ 5 files changed, 67 insertions(+) create mode 100644 Documentation/userspace-api/media/drivers/thp7312.rst create mode 100644 include/uapi/linux/thp7312.h diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 1726f8ec86fa..6b62c818899f 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -41,4 +41,5 @@ For more details see the file COPYING in the source distribution of Linux. npcm-video omap3isp-uapi st-vgxy61 + thp7312 uvcvideo diff --git a/Documentation/userspace-api/media/drivers/thp7312.rst b/Documentation/userspace-api/media/drivers/thp7312.rst new file mode 100644 index 000000000000..7c777e6fb7d2 --- /dev/null +++ b/Documentation/userspace-api/media/drivers/thp7312.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +THine THP7312 ISP driver +======================== + +The THP7312 driver implements the following driver-specific controls: + +``V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION`` + Enable/Disable auto-adjustment, based on lighting conditions, of the frame + rate when auto-exposure is enabled. + +``V4L2_CID_THP7312_AUTO_FOCUS_METHOD`` + Set method of auto-focus. Only takes effect when auto-focus is enabled. + + .. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 4 + + * - ``0`` + - Contrast-based auto-focus + * - ``1`` + - PDAF + * - ``2`` + - Hybrid of contrast-based and PDAF + + Supported values for the control depend on the camera sensor module + connected to the THP7312. If the module doesn't have a focus lens actuator, + this control will not be exposed by the THP7312 driver. If the module has a + controllable focus lens but the sensor doesn't support PDAF, only the + contrast-based auto-focus value will be valid. Otherwise all values for the + controls will be supported. + +``V4L2_CID_THP7312_NOISE_REDUCTION_AUTO`` + Enable/Disable auto noise reduction. + +``V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE`` + Set the noise reduction strength, where 0 is the weakest and 10 is the + strongest. diff --git a/MAINTAINERS b/MAINTAINERS index 6d20dc6f617c..c4468f6a4cb2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21670,6 +21670,8 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml +F: Documentation/userspace-api/media/drivers/thp7312.rst +F: include/uapi/linux/thp7312.h THUNDERBOLT DMA TRAFFIC TEST DRIVER M: Isaac Hazan diff --git a/include/uapi/linux/thp7312.h b/include/uapi/linux/thp7312.h new file mode 100644 index 000000000000..2b629e05daf9 --- /dev/null +++ b/include/uapi/linux/thp7312.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * THine THP7312 user space header file. + * + * Copyright (C) 2021 THine Electronics, Inc. + * Copyright (C) 2023 Ideas on Board Oy + */ + +#ifndef __UAPI_THP7312_H_ +#define __UAPI_THP7312_H_ + +#include + +#define V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION (V4L2_CID_USER_THP7312_BASE + 0x01) +#define V4L2_CID_THP7312_AUTO_FOCUS_METHOD (V4L2_CID_USER_THP7312_BASE + 0x02) +#define V4L2_CID_THP7312_NOISE_REDUCTION_AUTO (V4L2_CID_USER_THP7312_BASE + 0x03) +#define V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE (V4L2_CID_USER_THP7312_BASE + 0x04) + +#endif /* __UAPI_THP7312_H_ */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 68db66d4aae8..99c3f5e99da7 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -209,6 +209,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_NPCM_BASE (V4L2_CID_USER_BASE + 0x11b0) +/* + * The base for THine THP7312 driver controls. + * We reserve 32 controls for this driver. + */ +#define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ From 7a52ab415b43f3b4680b69f6652ba2ec6716e55f Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Fri, 24 Nov 2023 16:26:25 +0200 Subject: [PATCH 2332/7721] media: i2c: Add driver for THine THP7312 The THP7312 is an external camera ISP from THine. Add a V4L2 subdev driver for it. Signed-off-by: Paul Elder Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart [Sakari Ailus: squash a patch to fix missing mutex_unlock by Laurent.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 16 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/thp7312.c | 2240 +++++++++++++++++++++++++++++++++++ 4 files changed, 2258 insertions(+) create mode 100644 drivers/media/i2c/thp7312.c diff --git a/MAINTAINERS b/MAINTAINERS index c4468f6a4cb2..b8f0bb78700d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21671,6 +21671,7 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml F: Documentation/userspace-api/media/drivers/thp7312.rst +F: drivers/media/i2c/thp7312.c F: include/uapi/linux/thp7312.h THUNDERBOLT DMA TRAFFIC TEST DRIVER diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index fc053c834782..e77444f64257 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -638,6 +638,22 @@ source "drivers/media/i2c/et8ek8/Kconfig" endif +menu "Camera ISPs" + visible if MEDIA_CAMERA_SUPPORT + +config VIDEO_THP7312 + tristate "THine THP7312 support" + depends on I2C + select MEDIA_CONTROLLER + select V4L2_CCI_I2C + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor-level driver for the THine + THP7312 ISP. + +endmenu + menu "Lens drivers" visible if MEDIA_CAMERA_SUPPORT diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 08e7e638dedc..a7ee96174397 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o +obj-$(CONFIG_VIDEO_THP7312) += thp7312.o obj-$(CONFIG_VIDEO_THS7303) += ths7303.o obj-$(CONFIG_VIDEO_THS8200) += ths8200.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c new file mode 100644 index 000000000000..9b387e568603 --- /dev/null +++ b/drivers/media/i2c/thp7312.c @@ -0,0 +1,2240 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 THine Electronics, Inc. + * Copyright (C) 2023 Ideas on Board Oy + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ISP registers */ + +#define THP7312_REG_FIRMWARE_VERSION_1 CCI_REG8(0xf000) +#define THP7312_REG_CAMERA_STATUS CCI_REG8(0xf001) +#define THP7312_REG_FIRMWARE_VERSION_2 CCI_REG8(0xf005) +#define THP7312_REG_SET_OUTPUT_ENABLE CCI_REG8(0xf008) +#define THP7312_OUTPUT_ENABLE 0x01 +#define THP7312_OUTPUT_DISABLE 0x00 +#define THP7312_REG_SET_OUTPUT_COLOR_COMPRESSION CCI_REG8(0xf009) +#define THP7312_REG_SET_OUTPUT_COLOR_UYVY 0x00 +#define THP7312_REG_SET_OUTPUT_COLOR_YUY2 0x04 +#define THP7312_REG_FLIP_MIRROR CCI_REG8(0xf00c) +#define THP7312_REG_FLIP_MIRROR_FLIP BIT(0) +#define THP7312_REG_FLIP_MIRROR_MIRROR BIT(1) +#define THP7312_REG_VIDEO_IMAGE_SIZE CCI_REG8(0xf00d) +#define THP7312_VIDEO_IMAGE_SIZE_640x360 0x52 +#define THP7312_VIDEO_IMAGE_SIZE_640x460 0x03 +#define THP7312_VIDEO_IMAGE_SIZE_1280x720 0x0a +#define THP7312_VIDEO_IMAGE_SIZE_1920x1080 0x0b +#define THP7312_VIDEO_IMAGE_SIZE_3840x2160 0x0d +#define THP7312_VIDEO_IMAGE_SIZE_4160x3120 0x14 +#define THP7312_VIDEO_IMAGE_SIZE_2016x1512 0x20 +#define THP7312_VIDEO_IMAGE_SIZE_2048x1536 0x21 +#define THP7312_REG_VIDEO_FRAME_RATE_MODE CCI_REG8(0xf00f) +#define THP7312_VIDEO_FRAME_RATE_MODE1 0x80 +#define THP7312_VIDEO_FRAME_RATE_MODE2 0x81 +#define THP7312_VIDEO_FRAME_RATE_MODE3 0x82 +#define THP7312_REG_SET_DRIVING_MODE CCI_REG8(0xf010) +#define THP7312_REG_DRIVING_MODE_STATUS CCI_REG8(0xf011) +#define THP7312_REG_JPEG_COMPRESSION_FACTOR CCI_REG8(0xf01b) +#define THP7312_REG_AE_EXPOSURE_COMPENSATION CCI_REG8(0xf022) +#define THP7312_REG_AE_FLICKER_MODE CCI_REG8(0xf023) +#define THP7312_AE_FLICKER_MODE_50 0x00 +#define THP7312_AE_FLICKER_MODE_60 0x01 +#define THP7312_AE_FLICKER_MODE_DISABLE 0x80 +#define THP7312_REG_AE_FIX_FRAME_RATE CCI_REG8(0xf02e) +#define THP7312_REG_MANUAL_WB_RED_GAIN CCI_REG8(0xf036) +#define THP7312_REG_MANUAL_WB_BLUE_GAIN CCI_REG8(0xf037) +#define THP7312_REG_WB_MODE CCI_REG8(0xf039) +#define THP7312_WB_MODE_AUTO 0x00 +#define THP7312_WB_MODE_MANUAL 0x11 +#define THP7312_REG_MANUAL_FOCUS_POSITION CCI_REG16(0xf03c) +#define THP7312_REG_AF_CONTROL CCI_REG8(0xf040) +#define THP7312_REG_AF_CONTROL_AF 0x01 +#define THP7312_REG_AF_CONTROL_MANUAL 0x10 +#define THP7312_REG_AF_CONTROL_LOCK 0x80 +#define THP7312_REG_AF_SETTING CCI_REG8(0xf041) +#define THP7312_REG_AF_SETTING_ONESHOT_CONTRAST 0x00 +#define THP7312_REG_AF_SETTING_ONESHOT_PDAF 0x40 +#define THP7312_REG_AF_SETTING_ONESHOT_HYBRID 0x80 +#define THP7312_REG_AF_SETTING_CONTINUOUS_CONTRAST 0x30 +#define THP7312_REG_AF_SETTING_CONTINUOUS_PDAF 0x70 +#define THP7312_REG_AF_SETTING_CONTINUOUS_HYBRID 0xf0 +#define THP7312_REG_AF_SUPPORT CCI_REG8(0xf043) +#define THP7312_AF_SUPPORT_PDAF BIT(1) +#define THP7312_AF_SUPPORT_CONTRAST BIT(0) +#define THP7312_REG_SATURATION CCI_REG8(0xf052) +#define THP7312_REG_SHARPNESS CCI_REG8(0xf053) +#define THP7312_REG_BRIGHTNESS CCI_REG8(0xf056) +#define THP7312_REG_CONTRAST CCI_REG8(0xf057) +#define THP7312_REG_NOISE_REDUCTION CCI_REG8(0xf059) +#define THP7312_REG_NOISE_REDUCTION_FIXED BIT(7) + +#define TH7312_REG_CUSTOM_MIPI_SET CCI_REG8(0xf0f6) +#define TH7312_REG_CUSTOM_MIPI_STATUS CCI_REG8(0xf0f7) +#define TH7312_REG_CUSTOM_MIPI_RD CCI_REG8(0xf0f8) +#define TH7312_REG_CUSTOM_MIPI_TD CCI_REG8(0xf0f9) + +/* + * Firmware update registers. Those use a different address space than the + * normal operation ISP registers. + */ + +#define THP7312_REG_FW_DRIVABILITY CCI_REG32(0xd65c) +#define THP7312_REG_FW_DEST_BANK_ADDR CCI_REG32(0xff08) +#define THP7312_REG_FW_VERIFY_RESULT CCI_REG8(0xff60) +#define THP7312_REG_FW_RESET_FLASH CCI_REG8(0xff61) +#define THP7312_REG_FW_MEMORY_IO_SETTING CCI_REG8(0xff62) +#define THP7312_FW_MEMORY_IO_GPIO0 1 +#define THP7312_FW_MEMORY_IO_GPIO1 0 +#define THP7312_REG_FW_CRC_RESULT CCI_REG32(0xff64) +#define THP7312_REG_FW_STATUS CCI_REG8(0xfffc) + +#define THP7312_FW_VERSION(major, minor) (((major) << 8) | (minor)) +#define THP7312_FW_VERSION_MAJOR(v) ((v) >> 8) +#define THP7312_FW_VERSION_MINOR(v) ((v) & 0xff) + +enum thp7312_focus_method { + THP7312_FOCUS_METHOD_CONTRAST, + THP7312_FOCUS_METHOD_PDAF, + THP7312_FOCUS_METHOD_HYBRID, +}; + +/* + * enum thp7312_focus_state - State of the focus handler + * + * @THP7312_FOCUS_STATE_MANUAL: Manual focus, controlled through the + * V4L2_CID_FOCUS_ABSOLUTE control + * @THP7312_FOCUS_STATE_AUTO: Continuous auto-focus + * @THP7312_FOCUS_STATE_LOCKED: Lock the focus to a fixed position. This state + * is entered when switching from auto to manual mode. + * @THP7312_FOCUS_STATE_ONESHOT: One-shot auto-focus + * + * Valid transitions are as follow: + * + * digraph fsm { + * node [shape=circle]; + * + * manual [label="MANUAL"]; + * auto [label="AUTO"]; + * locked [label="LOCKED"]; + * oneshot [label="ONESHOT"]; + * + * manual -> auto [label="FOCUS_AUTO <- true"] + * locked -> auto [label="FOCUS_AUTO <- true"] + * oneshot -> auto [label="FOCUS_AUTO <- true"] + * auto -> locked [label="FOCUS_AUTO <- false"] + * + * locked -> manual [label="FOCUS_ABSOLUTE <- *"] + * oneshot -> manual [label="FOCUS_ABSOLUTE <- *"] + * + * manual -> oneshot [label="FOCUS_START <- *"] + * locked -> oneshot [label="FOCUS_START <- *"] + * } + */ +enum thp7312_focus_state { + THP7312_FOCUS_STATE_MANUAL, + THP7312_FOCUS_STATE_AUTO, + THP7312_FOCUS_STATE_LOCKED, + THP7312_FOCUS_STATE_ONESHOT, +}; + +enum thp7312_boot_mode { + THP7312_BOOT_MODE_2WIRE_SLAVE = 0, + THP7312_BOOT_MODE_SPI_MASTER = 1, +}; + +struct thp7312_frame_rate { + u32 fps; + u32 link_freq; + u8 reg_frame_rate_mode; +}; + +struct thp7312_mode_info { + u32 width; + u32 height; + u8 reg_image_size; + const struct thp7312_frame_rate *rates; +}; + +static const u32 thp7312_colour_fmts[] = { + MEDIA_BUS_FMT_YUYV8_1X16, +}; + +/* regulator supplies */ +static const char * const thp7312_supply_name[] = { + "vddcore", + "vhtermrx", + "vddtx", + "vddhost", + "vddcmos", + "vddgpio-0", + "vddgpio-1", +}; + +static const struct thp7312_mode_info thp7312_mode_info_data[] = { + { + .width = 1920, + .height = 1080, + .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_1920x1080, + .rates = (const struct thp7312_frame_rate[]) { + { 30, 300000000, 0x81 }, + { 60, 387500000, 0x82 }, + { 0 } + }, + }, { + .width = 2048, + .height = 1536, + .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_2048x1536, + .rates = (const struct thp7312_frame_rate[]) { + { 30, 300000000, 0x81 }, + { 0 } + } + }, { + .width = 3840, + .height = 2160, + .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_3840x2160, + .rates = (const struct thp7312_frame_rate[]) { + { 30, 600000000, 0x81 }, + { 0 } + }, + }, { + .width = 4160, + .height = 3120, + .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_4160x3120, + .rates = (const struct thp7312_frame_rate[]) { + { 20, 600000000, 0x81 }, + { 0 } + }, + }, +}; + +struct thp7312_device; + +struct thp7312_sensor_info { + const char *model; +}; + +struct thp7312_sensor { + const struct thp7312_sensor_info *info; + u8 lane_remap; +}; + +struct thp7312_device { + struct device *dev; + struct regmap *regmap; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(thp7312_supply_name)]; + struct clk *iclk; + + u8 lane_remap; + + struct thp7312_sensor sensors[1]; + + enum thp7312_boot_mode boot_mode; + + struct v4l2_ctrl_handler ctrl_handler; + bool ctrls_applied; + + /* These are protected by v4l2 active state */ + const struct thp7312_mode_info *current_mode; + const struct thp7312_frame_rate *current_rate; + s64 link_freq; + + struct { + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; + + struct { + struct v4l2_ctrl *focus_auto; + struct v4l2_ctrl *focus_absolute; + struct v4l2_ctrl *focus_start; + struct v4l2_ctrl *focus_method; + }; + + enum thp7312_focus_state focus_state; + + struct { + struct v4l2_ctrl *noise_reduction_auto; + struct v4l2_ctrl *noise_reduction_absolute; + }; + + /* Lock to protect fw_cancel */ + struct mutex fw_lock; + struct fw_upload *fwl; + u8 *fw_write_buf; + bool fw_cancel; + + u16 fw_version; +}; + +static const struct thp7312_sensor_info thp7312_sensor_info[] = { + { + .model = "sony,imx258", + }, +}; + +static inline struct thp7312_device *to_thp7312_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct thp7312_device, sd); +} + +/* ----------------------------------------------------------------------------- + * Device Access & Configuration + */ + +#define thp7312_read_poll_timeout(dev, addr, val, cond, sleep_us, timeout_us) \ +({ \ + int __ret, __err; \ + __ret = read_poll_timeout(cci_read, __err, __err || (cond), sleep_us, \ + timeout_us, false, (dev)->regmap, addr, \ + &(val), NULL); \ + __ret ? : __err; \ +}) + +static int thp7312_map_data_lanes(u8 *lane_remap, const u8 *lanes, u8 num_lanes) +{ + u8 used_lanes = 0; + u8 val = 0; + unsigned int i; + + /* + * The value that we write to the register is the index in the + * data-lanes array, so we need to do a conversion. Do this in the same + * pass as validating data-lanes. + */ + for (i = 0; i < num_lanes; i++) { + if (lanes[i] < 1 || lanes[i] > 4) + return -EINVAL; + + if (used_lanes & (BIT(lanes[i]))) + return -EINVAL; + + used_lanes |= BIT(lanes[i]); + + /* + * data-lanes is 1-indexed while the field position in the + * register is 0-indexed. + */ + val |= i << ((lanes[i] - 1) * 2); + } + + *lane_remap = val; + + return 0; +} + +static int thp7312_set_mipi_lanes(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + int ret = 0; + u64 val; + + cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_RD, + thp7312->sensors[0].lane_remap, &ret); + cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_TD, + thp7312->lane_remap, &ret); + cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_SET, 1, &ret); + + if (ret) + return ret; + + ret = thp7312_read_poll_timeout(thp7312, TH7312_REG_CUSTOM_MIPI_STATUS, + val, val == 0x00, 100000, 2000000); + if (ret) { + dev_err(dev, "Failed to poll MIPI lane status: %d\n", ret); + return ret; + } + + return 0; +} + +static int thp7312_change_mode(struct thp7312_device *thp7312, + const struct thp7312_mode_info *mode, + const struct thp7312_frame_rate *rate) +{ + struct device *dev = thp7312->dev; + u64 val = 0; + int ret; + + ret = thp7312_read_poll_timeout(thp7312, THP7312_REG_CAMERA_STATUS, val, + val == 0x80, 20000, 200000); + if (ret < 0) { + dev_err(dev, "%s(): failed to poll ISP: %d\n", __func__, ret); + return ret; + } + + cci_write(thp7312->regmap, THP7312_REG_VIDEO_IMAGE_SIZE, + mode->reg_image_size, &ret); + cci_write(thp7312->regmap, THP7312_REG_VIDEO_FRAME_RATE_MODE, + rate->reg_frame_rate_mode, &ret); + cci_write(thp7312->regmap, THP7312_REG_JPEG_COMPRESSION_FACTOR, 0x5e, + &ret); + cci_write(thp7312->regmap, THP7312_REG_SET_DRIVING_MODE, 0x01, &ret); + + if (ret) + return ret; + + ret = thp7312_read_poll_timeout(thp7312, THP7312_REG_DRIVING_MODE_STATUS, + val, val == 0x01, 20000, 100000); + if (ret < 0) { + dev_err(dev, "%s(): failed\n", __func__); + return ret; + } + + return 0; +} + +static int thp7312_set_framefmt(struct thp7312_device *thp7312, + struct v4l2_mbus_framefmt *format) +{ + u8 val; + + switch (format->code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + /* YUV422, UYVY */ + val = THP7312_REG_SET_OUTPUT_COLOR_UYVY; + break; + case MEDIA_BUS_FMT_YUYV8_1X16: + /* YUV422, YUYV */ + val = THP7312_REG_SET_OUTPUT_COLOR_YUY2; + break; + default: + /* Should never happen */ + return -EINVAL; + } + + return cci_write(thp7312->regmap, + THP7312_REG_SET_OUTPUT_COLOR_COMPRESSION, val, NULL); +} + +static int thp7312_init_mode(struct thp7312_device *thp7312, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_mbus_framefmt *fmt; + int ret; + + fmt = v4l2_subdev_state_get_format(sd_state, 0); + + ret = thp7312_set_framefmt(thp7312, fmt); + if (ret) + return ret; + + return thp7312_change_mode(thp7312, thp7312->current_mode, + thp7312->current_rate); +} + +static int thp7312_stream_enable(struct thp7312_device *thp7312, bool enable) +{ + return cci_write(thp7312->regmap, THP7312_REG_SET_OUTPUT_ENABLE, + enable ? THP7312_OUTPUT_ENABLE : THP7312_OUTPUT_DISABLE, + NULL); +} + +static int thp7312_check_status_stream_mode(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + u64 status = 0; + int ret; + + while (status != 0x80) { + ret = cci_read(thp7312->regmap, THP7312_REG_CAMERA_STATUS, + &status, NULL); + if (ret) + return ret; + + if (status == 0x80) { + dev_dbg(dev, "Camera initialization done\n"); + return 0; + } + + if (status != 0x00) { + dev_err(dev, "Invalid camera status %llx\n", status); + return -EINVAL; + } + + dev_dbg(dev, "Camera initializing...\n"); + usleep_range(70000, 80000); + } + + return 0; +} + +static void thp7312_reset(struct thp7312_device *thp7312) +{ + unsigned long rate; + + gpiod_set_value_cansleep(thp7312->reset_gpio, 1); + + /* + * The minimum reset duration is 8 clock cycles, make it 10 to provide + * a safety margin. + */ + rate = clk_get_rate(thp7312->iclk); + fsleep(DIV_ROUND_UP(10 * USEC_PER_SEC, rate)); + + gpiod_set_value_cansleep(thp7312->reset_gpio, 0); + + /* + * TODO: The documentation states that the device needs 2ms to + * initialize after reset is deasserted. It then proceeds to load the + * firmware from the flash memory, which takes an unspecified amount of + * time. Check if this delay could be reduced. + */ + fsleep(300000); +} + +/* ----------------------------------------------------------------------------- + * Power Management + */ + +static void __thp7312_power_off(struct thp7312_device *thp7312) +{ + regulator_bulk_disable(ARRAY_SIZE(thp7312->supplies), thp7312->supplies); + clk_disable_unprepare(thp7312->iclk); +} + +static void thp7312_power_off(struct thp7312_device *thp7312) +{ + __thp7312_power_off(thp7312); +} + +static int __thp7312_power_on(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(thp7312->supplies), + thp7312->supplies); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(thp7312->iclk); + if (ret < 0) { + dev_err(dev, "clk prepare enable failed\n"); + regulator_bulk_disable(ARRAY_SIZE(thp7312->supplies), + thp7312->supplies); + return ret; + } + + /* + * We cannot assume that turning off and on again will reset, so do a + * software reset on power up. + */ + thp7312_reset(thp7312); + + return 0; +} + +static int thp7312_power_on(struct thp7312_device *thp7312) +{ + int ret; + + ret = __thp7312_power_on(thp7312); + if (ret < 0) + return ret; + + ret = thp7312_check_status_stream_mode(thp7312); + if (ret < 0) + goto error; + + ret = thp7312_set_mipi_lanes(thp7312); + if (ret) + goto error; + + return 0; + +error: + thp7312_power_off(thp7312); + return ret; +} + +static int __maybe_unused thp7312_pm_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + + thp7312_power_off(thp7312); + + thp7312->ctrls_applied = false; + + return 0; +} + +static int __maybe_unused thp7312_pm_runtime_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + + return thp7312_power_on(thp7312); +} + +static const struct dev_pm_ops thp7312_pm_ops = { + SET_RUNTIME_PM_OPS(thp7312_pm_runtime_suspend, + thp7312_pm_runtime_resume, NULL) +}; + +/* ----------------------------------------------------------------------------- + * V4L2 Subdev Operations + */ + +static bool thp7312_find_bus_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(thp7312_colour_fmts); ++i) { + if (thp7312_colour_fmts[i] == code) + return true; + } + + return false; +} + +static const struct thp7312_mode_info * +thp7312_find_mode(unsigned int width, unsigned int height, bool nearest) +{ + const struct thp7312_mode_info *mode; + + mode = v4l2_find_nearest_size(thp7312_mode_info_data, + ARRAY_SIZE(thp7312_mode_info_data), + width, height, width, height); + + if (!nearest && (mode->width != width || mode->height != height)) + return NULL; + + return mode; +} + +static void thp7312_set_frame_rate(struct thp7312_device *thp7312, + const struct thp7312_frame_rate *rate) +{ + thp7312->link_freq = rate->link_freq; + thp7312->current_rate = rate; +} + +static int thp7312_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(thp7312_colour_fmts)) + return -EINVAL; + + code->code = thp7312_colour_fmts[code->index]; + + return 0; +} + +static int thp7312_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (!thp7312_find_bus_code(fse->code)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(thp7312_mode_info_data)) + return -EINVAL; + + fse->min_width = thp7312_mode_info_data[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = thp7312_mode_info_data[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int thp7312_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_interval_enum *fie) +{ + const struct thp7312_frame_rate *rate; + const struct thp7312_mode_info *mode; + unsigned int index = fie->index; + + if (!thp7312_find_bus_code(fie->code)) + return -EINVAL; + + mode = thp7312_find_mode(fie->width, fie->height, false); + if (!mode) + return -EINVAL; + + for (rate = mode->rates; rate->fps; ++rate, --index) { + if (!index) { + fie->interval.numerator = 1; + fie->interval.denominator = rate->fps; + + return 0; + } + } + + return -EINVAL; +} + +static int thp7312_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &format->format; + struct v4l2_mbus_framefmt *fmt; + const struct thp7312_mode_info *mode; + + if (!thp7312_find_bus_code(mbus_fmt->code)) + mbus_fmt->code = thp7312_colour_fmts[0]; + + mode = thp7312_find_mode(mbus_fmt->width, mbus_fmt->height, true); + + fmt = v4l2_subdev_state_get_format(sd_state, 0); + + fmt->code = mbus_fmt->code; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + + *mbus_fmt = *fmt; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + thp7312->current_mode = mode; + thp7312_set_frame_rate(thp7312, &mode->rates[0]); + } + + return 0; +} + +static int thp7312_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + struct v4l2_subdev_state *sd_state; + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + fi->interval.numerator = 1; + fi->interval.denominator = thp7312->current_rate->fps; + v4l2_subdev_unlock_state(sd_state); + + return 0; +} + +static int thp7312_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + const struct thp7312_mode_info *mode; + const struct thp7312_frame_rate *best_rate = NULL; + const struct thp7312_frame_rate *rate; + struct v4l2_subdev_state *sd_state; + unsigned int best_delta = UINT_MAX; + unsigned int fps; + + /* Avoid divisions by 0, pick the highest frame if the interval is 0. */ + fps = fi->interval.numerator + ? DIV_ROUND_CLOSEST(fi->interval.denominator, fi->interval.numerator) + : UINT_MAX; + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + mode = thp7312->current_mode; + + for (rate = mode->rates; rate->fps && best_delta; ++rate) { + unsigned int delta = abs(rate->fps - fps); + + if (delta <= best_delta) { + best_delta = delta; + best_rate = rate; + } + } + + thp7312_set_frame_rate(thp7312, best_rate); + + v4l2_subdev_unlock_state(sd_state); + + fi->interval.numerator = 1; + fi->interval.denominator = best_rate->fps; + + return 0; +} + +static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + struct v4l2_subdev_state *sd_state; + int ret; + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + if (!enable) { + thp7312_stream_enable(thp7312, false); + + pm_runtime_mark_last_busy(thp7312->dev); + pm_runtime_put_autosuspend(thp7312->dev); + + v4l2_subdev_unlock_state(sd_state); + + return 0; + } + + ret = pm_runtime_resume_and_get(thp7312->dev); + if (ret) + goto finish_unlock; + + ret = thp7312_init_mode(thp7312, sd_state); + if (ret) + goto finish_pm; + + if (!thp7312->ctrls_applied) { + ret = __v4l2_ctrl_handler_setup(&thp7312->ctrl_handler); + if (ret) + goto finish_pm; + + thp7312->ctrls_applied = true; + } + + ret = thp7312_stream_enable(thp7312, true); + if (ret) + goto finish_pm; + + goto finish_unlock; + +finish_pm: + pm_runtime_mark_last_busy(thp7312->dev); + pm_runtime_put_autosuspend(thp7312->dev); +finish_unlock: + v4l2_subdev_unlock_state(sd_state); + + return ret; +} + +static int thp7312_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + const struct thp7312_mode_info *default_mode = &thp7312_mode_info_data[0]; + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(sd_state, 0); + + /* + * default init sequence initialize thp7312 to + * YUV422 YUYV VGA@30fps + */ + fmt->code = MEDIA_BUS_FMT_YUYV8_1X16; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + fmt->width = default_mode->width; + fmt->height = default_mode->height; + fmt->field = V4L2_FIELD_NONE; + + return 0; +} + +static const struct v4l2_subdev_core_ops thp7312_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops thp7312_video_ops = { + .g_frame_interval = thp7312_g_frame_interval, + .s_frame_interval = thp7312_s_frame_interval, + .s_stream = thp7312_s_stream, +}; + +static const struct v4l2_subdev_pad_ops thp7312_pad_ops = { + .enum_mbus_code = thp7312_enum_mbus_code, + .init_cfg = thp7312_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = thp7312_set_fmt, + .enum_frame_size = thp7312_enum_frame_size, + .enum_frame_interval = thp7312_enum_frame_interval, +}; + +static const struct v4l2_subdev_ops thp7312_subdev_ops = { + .core = &thp7312_core_ops, + .video = &thp7312_video_ops, + .pad = &thp7312_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 Control Operations + */ + +static inline struct thp7312_device *to_thp7312_from_ctrl(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct thp7312_device, ctrl_handler); +} + +/* 0: 3000cm, 18: 8cm */ +static const u16 thp7312_focus_values[] = { + 3000, 1000, 600, 450, 350, + 290, 240, 200, 170, 150, + 140, 130, 120, 110, 100, + 93, 87, 83, 80, +}; + +static int thp7312_set_focus(struct thp7312_device *thp7312) +{ + enum thp7312_focus_state new_state = thp7312->focus_state; + bool continuous; + u8 af_control; + u8 af_setting; + int ret = 0; + + /* Start by programming the manual focus position if it has changed. */ + if (thp7312->focus_absolute->is_new) { + unsigned int value; + + value = thp7312_focus_values[thp7312->focus_absolute->val]; + + ret = cci_write(thp7312->regmap, + THP7312_REG_MANUAL_FOCUS_POSITION, value, NULL); + if (ret) + return ret; + } + + /* Calculate the new focus state. */ + switch (thp7312->focus_state) { + case THP7312_FOCUS_STATE_MANUAL: + default: + if (thp7312->focus_auto->val) + new_state = THP7312_FOCUS_STATE_AUTO; + else if (thp7312->focus_start->is_new) + new_state = THP7312_FOCUS_STATE_ONESHOT; + break; + + case THP7312_FOCUS_STATE_AUTO: + if (!thp7312->focus_auto->val) + new_state = THP7312_FOCUS_STATE_LOCKED; + break; + + case THP7312_FOCUS_STATE_LOCKED: + if (thp7312->focus_auto->val) + new_state = THP7312_FOCUS_STATE_AUTO; + else if (thp7312->focus_start->is_new) + new_state = THP7312_FOCUS_STATE_ONESHOT; + else if (thp7312->focus_absolute->is_new) + new_state = THP7312_FOCUS_STATE_MANUAL; + break; + + case THP7312_FOCUS_STATE_ONESHOT: + if (thp7312->focus_auto->val) + new_state = THP7312_FOCUS_STATE_AUTO; + else if (thp7312->focus_start->is_new) + new_state = THP7312_FOCUS_STATE_ONESHOT; + else if (thp7312->focus_absolute->is_new) + new_state = THP7312_FOCUS_STATE_MANUAL; + break; + } + + /* + * If neither the state nor the focus method has changed, and no new + * one-shot focus is requested, there's nothing new to program to the + * hardware. + */ + if (thp7312->focus_state == new_state && + !thp7312->focus_method->is_new && !thp7312->focus_start->is_new) + return 0; + + continuous = new_state == THP7312_FOCUS_STATE_MANUAL || + new_state == THP7312_FOCUS_STATE_ONESHOT; + + switch (thp7312->focus_method->val) { + case THP7312_FOCUS_METHOD_CONTRAST: + default: + af_setting = continuous + ? THP7312_REG_AF_SETTING_CONTINUOUS_CONTRAST + : THP7312_REG_AF_SETTING_ONESHOT_CONTRAST; + break; + case THP7312_FOCUS_METHOD_PDAF: + af_setting = continuous + ? THP7312_REG_AF_SETTING_CONTINUOUS_PDAF + : THP7312_REG_AF_SETTING_ONESHOT_PDAF; + break; + case THP7312_FOCUS_METHOD_HYBRID: + af_setting = continuous + ? THP7312_REG_AF_SETTING_CONTINUOUS_HYBRID + : THP7312_REG_AF_SETTING_ONESHOT_HYBRID; + break; + } + + switch (new_state) { + case THP7312_FOCUS_STATE_MANUAL: + default: + af_control = THP7312_REG_AF_CONTROL_MANUAL; + break; + case THP7312_FOCUS_STATE_AUTO: + case THP7312_FOCUS_STATE_ONESHOT: + af_control = THP7312_REG_AF_CONTROL_AF; + break; + case THP7312_FOCUS_STATE_LOCKED: + af_control = THP7312_REG_AF_CONTROL_LOCK; + break; + } + + cci_write(thp7312->regmap, THP7312_REG_AF_SETTING, af_setting, &ret); + + if (new_state == THP7312_FOCUS_STATE_MANUAL && + (thp7312->focus_state == THP7312_FOCUS_STATE_AUTO || + thp7312->focus_state == THP7312_FOCUS_STATE_ONESHOT)) { + /* When switching to manual state, lock AF first. */ + cci_write(thp7312->regmap, THP7312_REG_AF_CONTROL, + THP7312_REG_AF_CONTROL_LOCK, &ret); + } + + cci_write(thp7312->regmap, THP7312_REG_AF_CONTROL, af_control, &ret); + + if (ret) + return ret; + + thp7312->focus_state = new_state; + + return 0; +} + +static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct thp7312_device *thp7312 = to_thp7312_from_ctrl(ctrl); + int ret = 0; + u8 value; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return -EINVAL; + + if (!pm_runtime_get_if_active(thp7312->dev, true)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + cci_write(thp7312->regmap, THP7312_REG_BRIGHTNESS, + ctrl->val + 10, &ret); + break; + + case V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION: + /* 0 = Auto adjust frame rate, 1 = Fix frame rate */ + cci_write(thp7312->regmap, THP7312_REG_AE_FIX_FRAME_RATE, + ctrl->val ? 0 : 1, &ret); + break; + + case V4L2_CID_FOCUS_AUTO: + case V4L2_CID_FOCUS_ABSOLUTE: + case V4L2_CID_AUTO_FOCUS_START: + case V4L2_CID_THP7312_AUTO_FOCUS_METHOD: + ret = thp7312_set_focus(thp7312); + break; + + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + value = (thp7312->hflip->val ? THP7312_REG_FLIP_MIRROR_MIRROR : 0) + | (thp7312->vflip->val ? THP7312_REG_FLIP_MIRROR_FLIP : 0); + + cci_write(thp7312->regmap, THP7312_REG_FLIP_MIRROR, value, &ret); + break; + + case V4L2_CID_THP7312_NOISE_REDUCTION_AUTO: + case V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE: + value = thp7312->noise_reduction_auto->val ? 0 + : THP7312_REG_NOISE_REDUCTION_FIXED | + thp7312->noise_reduction_absolute->val; + + cci_write(thp7312->regmap, THP7312_REG_NOISE_REDUCTION, value, + &ret); + break; + + case V4L2_CID_AUTO_WHITE_BALANCE: + value = ctrl->val ? THP7312_WB_MODE_AUTO : THP7312_WB_MODE_MANUAL; + + cci_write(thp7312->regmap, THP7312_REG_WB_MODE, value, &ret); + break; + + case V4L2_CID_RED_BALANCE: + cci_write(thp7312->regmap, THP7312_REG_MANUAL_WB_RED_GAIN, + ctrl->val, &ret); + break; + + case V4L2_CID_BLUE_BALANCE: + cci_write(thp7312->regmap, THP7312_REG_MANUAL_WB_BLUE_GAIN, + ctrl->val, &ret); + break; + + case V4L2_CID_AUTO_EXPOSURE_BIAS: + cci_write(thp7312->regmap, THP7312_REG_AE_EXPOSURE_COMPENSATION, + ctrl->val, &ret); + break; + + case V4L2_CID_POWER_LINE_FREQUENCY: + if (ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) { + value = THP7312_AE_FLICKER_MODE_60; + } else if (ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) { + value = THP7312_AE_FLICKER_MODE_50; + } else { + if (thp7312->fw_version == THP7312_FW_VERSION(40, 3)) { + /* THP7312_AE_FLICKER_MODE_DISABLE is not supported */ + value = THP7312_AE_FLICKER_MODE_50; + } else { + value = THP7312_AE_FLICKER_MODE_DISABLE; + } + } + + cci_write(thp7312->regmap, THP7312_REG_AE_FLICKER_MODE, + value, &ret); + break; + + case V4L2_CID_SATURATION: + cci_write(thp7312->regmap, THP7312_REG_SATURATION, + ctrl->val, &ret); + break; + + case V4L2_CID_CONTRAST: + cci_write(thp7312->regmap, THP7312_REG_CONTRAST, + ctrl->val, &ret); + break; + + case V4L2_CID_SHARPNESS: + cci_write(thp7312->regmap, THP7312_REG_SHARPNESS, + ctrl->val, &ret); + break; + + default: + break; + } + + pm_runtime_mark_last_busy(thp7312->dev); + pm_runtime_put_autosuspend(thp7312->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops thp7312_ctrl_ops = { + .s_ctrl = thp7312_s_ctrl, +}; + +/* + * Refer to Documentation/userspace-api/media/drivers/thp7312.rst for details. + */ +static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_cdaf = { + .ops = &thp7312_ctrl_ops, + .id = V4L2_CID_THP7312_AUTO_FOCUS_METHOD, + .name = "Auto-Focus Method", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = THP7312_FOCUS_METHOD_CONTRAST, + .def = THP7312_FOCUS_METHOD_CONTRAST, + .max = THP7312_FOCUS_METHOD_CONTRAST, + .step = 1, +}; + +static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_pdaf = { + .ops = &thp7312_ctrl_ops, + .id = V4L2_CID_THP7312_AUTO_FOCUS_METHOD, + .name = "Auto-Focus Method", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = THP7312_FOCUS_METHOD_CONTRAST, + .def = THP7312_FOCUS_METHOD_HYBRID, + .max = THP7312_FOCUS_METHOD_HYBRID, + .step = 1, +}; + +static const struct v4l2_ctrl_config thp7312_v4l2_ctrls_custom[] = { + { + .ops = &thp7312_ctrl_ops, + .id = V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION, + .name = "Low Light Compensation", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .def = 1, + .max = 1, + .step = 1, + }, { + .ops = &thp7312_ctrl_ops, + .id = V4L2_CID_THP7312_NOISE_REDUCTION_AUTO, + .name = "Noise Reduction Auto", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .def = 1, + .max = 1, + .step = 1, + }, { + .ops = &thp7312_ctrl_ops, + .id = V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE, + .name = "Noise Reduction Level", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 0, + .max = 10, + .step = 1, + }, +}; + +static const s64 exp_bias_qmenu[] = { + -2000, -1667, -1333, -1000, -667, -333, 0, 333, 667, 1000, 1333, 1667, 2000 +}; + +static int thp7312_init_controls(struct thp7312_device *thp7312) +{ + struct v4l2_ctrl_handler *hdl = &thp7312->ctrl_handler; + struct device *dev = thp7312->dev; + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *link_freq; + unsigned int num_controls; + unsigned int i; + u8 af_support; + int ret; + + /* + * Check what auto-focus methods the connected sensor supports, if any. + * Firmwares before v90.03 didn't expose the AF_SUPPORT register, + * consider both CDAF and PDAF as supported in that case. + */ + if (thp7312->fw_version >= THP7312_FW_VERSION(90, 3)) { + u64 val; + + ret = cci_read(thp7312->regmap, THP7312_REG_AF_SUPPORT, &val, + NULL); + if (ret) + return ret; + + af_support = val & (THP7312_AF_SUPPORT_PDAF | + THP7312_AF_SUPPORT_CONTRAST); + } else { + af_support = THP7312_AF_SUPPORT_PDAF + | THP7312_AF_SUPPORT_CONTRAST; + } + + num_controls = 14 + ARRAY_SIZE(thp7312_v4l2_ctrls_custom) + + (af_support ? 4 : 0); + + v4l2_ctrl_handler_init(hdl, num_controls); + + if (af_support) { + const struct v4l2_ctrl_config *af_method; + + af_method = af_support & THP7312_AF_SUPPORT_PDAF + ? &thp7312_ctrl_focus_method_pdaf + : &thp7312_ctrl_focus_method_cdaf; + + thp7312->focus_state = THP7312_FOCUS_STATE_MANUAL; + + thp7312->focus_auto = + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, + V4L2_CID_FOCUS_AUTO, + 0, 1, 1, 1); + thp7312->focus_absolute = + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, + V4L2_CID_FOCUS_ABSOLUTE, + 0, ARRAY_SIZE(thp7312_focus_values), + 1, 0); + thp7312->focus_method = + v4l2_ctrl_new_custom(hdl, af_method, NULL); + thp7312->focus_start = + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, + V4L2_CID_AUTO_FOCUS_START, + 1, 1, 1, 1); + + v4l2_ctrl_cluster(4, &thp7312->focus_auto); + } + + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + /* 32: 1x, 255: 7.95x */ + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_RED_BALANCE, + 32, 255, 1, 64); + /* 32: 1x, 255: 7.95x */ + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_BLUE_BALANCE, + 32, 255, 1, 50); + + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_BRIGHTNESS, + -10, 10, 1, 0); + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_SATURATION, + 0, 31, 1, 10); + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_CONTRAST, + 0, 20, 1, 10); + v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_SHARPNESS, + 0, 31, 1, 8); + + thp7312->hflip = v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + thp7312->vflip = v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_cluster(2, &thp7312->hflip); + + v4l2_ctrl_new_int_menu(hdl, &thp7312_ctrl_ops, + V4L2_CID_AUTO_EXPOSURE_BIAS, + ARRAY_SIZE(exp_bias_qmenu) - 1, + ARRAY_SIZE(exp_bias_qmenu) / 2, exp_bias_qmenu); + + v4l2_ctrl_new_std_menu(hdl, &thp7312_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + + link_freq = v4l2_ctrl_new_int_menu(hdl, &thp7312_ctrl_ops, + V4L2_CID_LINK_FREQ, 0, 0, + &thp7312->link_freq); + + /* Set properties from fwnode (e.g. rotation, orientation). */ + ret = v4l2_fwnode_device_parse(dev, &props); + if (ret) { + dev_err(dev, "Failed to parse fwnode: %d\n", ret); + goto error; + } + + ret = v4l2_ctrl_new_fwnode_properties(hdl, &thp7312_ctrl_ops, &props); + if (ret) { + dev_err(dev, "Failed to create new v4l2 ctrl for fwnode properties: %d\n", ret); + goto error; + } + + for (i = 0; i < ARRAY_SIZE(thp7312_v4l2_ctrls_custom); i++) { + const struct v4l2_ctrl_config *ctrl_cfg = + &thp7312_v4l2_ctrls_custom[i]; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_custom(hdl, ctrl_cfg, NULL); + + if (ctrl_cfg->id == V4L2_CID_THP7312_NOISE_REDUCTION_AUTO) + thp7312->noise_reduction_auto = ctrl; + else if (ctrl_cfg->id == V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE) + thp7312->noise_reduction_absolute = ctrl; + } + + v4l2_ctrl_cluster(2, &thp7312->noise_reduction_auto); + + if (hdl->error) { + dev_err(dev, "v4l2_ctrl_handler error\n"); + ret = hdl->error; + goto error; + } + + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + return ret; + +error: + v4l2_ctrl_handler_free(hdl); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Firmware Update + */ + +/* + * The firmware data is made of 128kB of RAM firmware, followed by a + * variable-size "header". Both are stored in flash memory. + */ +#define THP7312_FW_RAM_SIZE (128 * 1024) +#define THP7312_FW_MIN_SIZE (THP7312_FW_RAM_SIZE + 4) +#define THP7312_FW_MAX_SIZE (THP7312_FW_RAM_SIZE + 64 * 1024) + +/* + * Data is first uploaded to the THP7312 128kB SRAM, and then written to flash. + * The SRAM is exposed over I2C as 32kB banks, and up to 4kB of data can be + * transferred in a single I2C write. + */ +#define THP7312_RAM_BANK_SIZE (32 * 1024) +#define THP7312_FW_DOWNLOAD_UNIT (4 * 1024) + +#define THP7312_FLASH_MEMORY_ERASE_TIMEOUT 40 + +#define THP7312_FLASH_MAX_REG_READ_SIZE 10 +#define THP7312_FLASH_MAX_REG_DATA_SIZE 10 + +static const u8 thp7312_cmd_config_flash_mem_if[] = { + 0xd5, 0x18, 0x00, 0x00, 0x00, 0x80 +}; + +static const u8 thp7312_cmd_write_to_reg[] = { + 0xd5, 0x0c, 0x80, 0x00, 0x00, 0x00 +}; + +static const u8 thp7312_cmd_read_reg[] = { + 0xd5, 0x04 +}; + +/* + * THP7312 Write data from RAM to Flash Memory + * Command ID FF700F + * Format: FF700F AA AA AA BB BB BB + * AA AA AA: destination start address + * BB BB BB: (write size - 1) + * Source address always starts from 0 + */ +static const u8 thp7312_cmd_write_ram_to_flash[] = { 0xff, 0x70, 0x0f }; + +/* + * THP7312 Calculate CRC command + * Command ID: FF70 09 + * Format: FF70 09 AA AA AA BB BB BB + * AA AA AA: Start address of calculation + * BB BB BB: (calculate size - 1) + */ +static const u8 thp7312_cmd_calc_crc[] = { 0xff, 0x70, 0x09 }; + +static const u8 thp7312_jedec_rdid[] = { SPINOR_OP_RDID, 0x00, 0x00, 0x00 }; +static const u8 thp7312_jedec_rdsr[] = { SPINOR_OP_RDSR, 0x00, 0x00, 0x00 }; +static const u8 thp7312_jedec_wen[] = { SPINOR_OP_WREN }; + +static int thp7312_read_firmware_version(struct thp7312_device *thp7312) +{ + u64 val = 0; + int ret = 0; + u8 major; + u8 minor; + + cci_read(thp7312->regmap, THP7312_REG_FIRMWARE_VERSION_1, &val, &ret); + major = val; + + cci_read(thp7312->regmap, THP7312_REG_FIRMWARE_VERSION_2, &val, &ret); + minor = val; + + thp7312->fw_version = THP7312_FW_VERSION(major, minor); + return ret; +} + +static int thp7312_write_buf(struct thp7312_device *thp7312, + const u8 *write_buf, u16 write_size) +{ + struct i2c_client *client = to_i2c_client(thp7312->dev); + int ret; + + ret = i2c_master_send(client, write_buf, write_size); + return ret >= 0 ? 0 : ret; +} + +static int __thp7312_flash_reg_write(struct thp7312_device *thp7312, + const u8 *write_buf, u16 write_size) +{ + struct device *dev = thp7312->dev; + u8 temp_write_buf[THP7312_FLASH_MAX_REG_DATA_SIZE + 2]; + int ret; + + if (write_size > THP7312_FLASH_MAX_REG_DATA_SIZE) { + dev_err(dev, "%s: Write size error size = %d\n", + __func__, write_size); + return -EINVAL; + } + + ret = thp7312_write_buf(thp7312, thp7312_cmd_config_flash_mem_if, + sizeof(thp7312_cmd_config_flash_mem_if)); + if (ret < 0) { + dev_err(dev, "%s: Failed to config flash memory IF: %d\n", + __func__, ret); + return ret; + } + + temp_write_buf[0] = 0xd5; + temp_write_buf[1] = 0x00; + memcpy((temp_write_buf + 2), write_buf, write_size); + ret = thp7312_write_buf(thp7312, temp_write_buf, write_size + 2); + if (ret < 0) + return ret; + + thp7312_write_buf(thp7312, thp7312_cmd_write_to_reg, + sizeof(thp7312_cmd_write_to_reg)); + + return 0; +} + +static int __thp7312_flash_reg_read(struct thp7312_device *thp7312, + const u8 *write_buf, u16 write_size, + u8 *read_buf, u16 read_size) +{ + struct i2c_client *client = to_i2c_client(thp7312->dev); + struct i2c_msg msgs[2]; + int ret; + + ret = __thp7312_flash_reg_write(thp7312, write_buf, write_size); + if (ret) + return ret; + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(thp7312_cmd_read_reg), + msgs[0].buf = (u8 *)thp7312_cmd_read_reg; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = read_size; + msgs[1].buf = read_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + return ret >= 0 ? 0 : ret; +} + +#define thp7312_flash_reg_write(thp7312, wrbuf) \ + __thp7312_flash_reg_write(thp7312, wrbuf, sizeof(wrbuf)) + +#define thp7312_flash_reg_read(thp7312, wrbuf, rdbuf) \ + __thp7312_flash_reg_read(thp7312, wrbuf, sizeof(wrbuf), \ + rdbuf, sizeof(rdbuf)) + +static enum fw_upload_err thp7312_fw_prepare_config(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + int ret; + + ret = cci_write(thp7312->regmap, THP7312_REG_FW_MEMORY_IO_SETTING, + THP7312_FW_MEMORY_IO_GPIO0, NULL); + if (ret) { + dev_err(dev, "Failed to set flash memory I/O\n"); + return FW_UPLOAD_ERR_HW_ERROR; + } + + /* Set max drivability. */ + ret = cci_write(thp7312->regmap, THP7312_REG_FW_DRIVABILITY, 0x00777777, + NULL); + if (ret) { + dev_err(dev, "Failed to set drivability: %d\n", ret); + return FW_UPLOAD_ERR_HW_ERROR; + } + + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_prepare_check(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + u8 read_buf[3] = { 0 }; + int ret; + + /* Get JEDEC ID */ + ret = thp7312_flash_reg_read(thp7312, thp7312_jedec_rdid, read_buf); + if (ret) { + dev_err(dev, "Failed to get JEDEC ID: %d\n", ret); + return FW_UPLOAD_ERR_HW_ERROR; + } + + dev_dbg(dev, "Flash Memory: JEDEC ID = 0x%x 0x%x 0x%x\n", + read_buf[0], read_buf[1], read_buf[2]); + + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_prepare_reset(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + int ret; + + ret = cci_write(thp7312->regmap, THP7312_REG_FW_RESET_FLASH, 0x81, NULL); + if (ret) { + dev_err(dev, "Failed to reset flash memory: %d\n", ret); + return FW_UPLOAD_ERR_HW_ERROR; + } + + return FW_UPLOAD_ERR_NONE; +} + +/* TODO: Erase only the amount of blocks necessary */ +static enum fw_upload_err thp7312_flash_erase(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + u8 read_buf[1] = { 0 }; + unsigned int i; + u8 block; + int ret; + + for (block = 0; block < 3; block++) { + const u8 jedec_se[] = { SPINOR_OP_SE, block, 0x00, 0x00 }; + + ret = thp7312_flash_reg_write(thp7312, thp7312_jedec_wen); + if (ret < 0) { + dev_err(dev, "Failed to enable flash for writing\n"); + return FW_UPLOAD_ERR_RW_ERROR; + } + + ret = thp7312_flash_reg_write(thp7312, jedec_se); + if (ret < 0) { + dev_err(dev, "Failed to erase flash sector\n"); + return FW_UPLOAD_ERR_RW_ERROR; + } + + for (i = 0; i < THP7312_FLASH_MEMORY_ERASE_TIMEOUT; i++) { + usleep_range(100000, 101000); + thp7312_flash_reg_read(thp7312, thp7312_jedec_rdsr, + read_buf); + + /* Check Busy bit. Busy == 0x0 means erase complete. */ + if (!(read_buf[0] & SR_WIP)) + break; + } + + if (i == THP7312_FLASH_MEMORY_ERASE_TIMEOUT) + return FW_UPLOAD_ERR_TIMEOUT; + } + + thp7312_flash_reg_read(thp7312, thp7312_jedec_rdsr, read_buf); + + /* Check WEL bit. */ + if (read_buf[0] & SR_WEL) + return FW_UPLOAD_ERR_HW_ERROR; + + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err +thp7312_write_download_data_by_unit(struct thp7312_device *thp7312, + unsigned int addr, const u8 *data, + unsigned int size) +{ + struct device *dev = thp7312->dev; + u8 *write_buf = thp7312->fw_write_buf; + int ret; + + dev_dbg(dev, "%s: addr = 0x%04x, data = 0x%p, size = %u\n", + __func__, addr, data, size); + + write_buf[0] = (addr >> 8) & 0xff; + write_buf[1] = (addr >> 0) & 0xff; + memcpy(&write_buf[2], data, size); + + /* + * THP7312 Firmware download to RAM + * Command ID (address to download): 0x0000 - 0x7fff + * Format:: 0000 XX XX XX ........ XX + */ + ret = thp7312_write_buf(thp7312, write_buf, size + 2); + if (ret < 0) + dev_err(dev, "Unit transfer ERROR %s(): ret = %d\n", __func__, ret); + + return ret >= 0 ? FW_UPLOAD_ERR_NONE : FW_UPLOAD_ERR_RW_ERROR; +} + +static enum fw_upload_err thp7312_fw_load_to_ram(struct thp7312_device *thp7312, + const u8 *data, u32 size) +{ + struct device *dev = thp7312->dev; + enum fw_upload_err ret; + unsigned int num_banks; + unsigned int i, j; + + num_banks = DIV_ROUND_UP(size, THP7312_RAM_BANK_SIZE); + + dev_dbg(dev, "%s: loading %u bytes in SRAM (%u banks)\n", __func__, + size, num_banks); + + for (i = 0; i < num_banks; i++) { + const u32 bank_addr = 0x10000000 | (i * THP7312_RAM_BANK_SIZE); + unsigned int bank_size; + unsigned int num_chunks; + + ret = cci_write(thp7312->regmap, THP7312_REG_FW_DEST_BANK_ADDR, + bank_addr, NULL); + if (ret) + return FW_UPLOAD_ERR_HW_ERROR; + + bank_size = min_t(u32, size, THP7312_RAM_BANK_SIZE); + num_chunks = DIV_ROUND_UP(bank_size, THP7312_FW_DOWNLOAD_UNIT); + + dev_dbg(dev, "%s: loading %u bytes in SRAM bank %u (%u chunks)\n", + __func__, bank_size, i, num_chunks); + + for (j = 0 ; j < num_chunks; j++) { + unsigned int chunk_addr; + unsigned int chunk_size; + + chunk_addr = j * THP7312_FW_DOWNLOAD_UNIT; + chunk_size = min_t(u32, size, THP7312_FW_DOWNLOAD_UNIT); + + ret = thp7312_write_download_data_by_unit(thp7312, chunk_addr, + data, chunk_size); + if (ret != FW_UPLOAD_ERR_NONE) { + dev_err(dev, "Unit transfer ERROR at bank transfer %s(): %d\n", + __func__, j); + return ret; + } + + data += chunk_size; + size -= chunk_size; + } + } + + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_write_to_flash(struct thp7312_device *thp7312, + u32 dest, u32 write_size) +{ + u8 command[sizeof(thp7312_cmd_write_ram_to_flash) + 6]; + static const u32 cmd_size = sizeof(thp7312_cmd_write_ram_to_flash); + u64 val; + int ret; + + memcpy(command, thp7312_cmd_write_ram_to_flash, cmd_size); + + command[cmd_size] = (dest & 0xff0000) >> 16; + command[cmd_size + 1] = (dest & 0x00ff00) >> 8; + command[cmd_size + 2] = (dest & 0x0000ff); + command[cmd_size + 3] = ((write_size - 1) & 0xff0000) >> 16; + command[cmd_size + 4] = ((write_size - 1) & 0x00ff00) >> 8; + command[cmd_size + 5] = ((write_size - 1) & 0x0000ff); + + ret = thp7312_write_buf(thp7312, command, sizeof(command)); + if (ret < 0) + return FW_UPLOAD_ERR_RW_ERROR; + + usleep_range(8000000, 8100000); + + ret = cci_read(thp7312->regmap, THP7312_REG_FW_VERIFY_RESULT, &val, + NULL); + if (ret < 0) + return FW_UPLOAD_ERR_RW_ERROR; + + return val ? FW_UPLOAD_ERR_HW_ERROR : FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_check_crc(struct thp7312_device *thp7312, + const u8 *fw_data, u32 fw_size) +{ + struct device *dev = thp7312->dev; + u16 header_size = fw_size - THP7312_FW_RAM_SIZE; + u8 command[sizeof(thp7312_cmd_calc_crc) + 6]; + static const u32 cmd_size = sizeof(thp7312_cmd_calc_crc); + u32 size = THP7312_FW_RAM_SIZE - 4; + u32 fw_crc; + u64 crc; + int ret; + + memcpy(command, thp7312_cmd_calc_crc, cmd_size); + + command[cmd_size] = 0; + command[cmd_size + 1] = (header_size >> 8) & 0xff; + command[cmd_size + 2] = header_size & 0xff; + + command[cmd_size + 3] = (size >> 16) & 0xff; + command[cmd_size + 4] = (size >> 8) & 0xff; + command[cmd_size + 5] = size & 0xff; + + ret = thp7312_write_buf(thp7312, command, sizeof(command)); + if (ret < 0) + return FW_UPLOAD_ERR_RW_ERROR; + + usleep_range(2000000, 2100000); + + fw_crc = get_unaligned_be32(&fw_data[fw_size - 4]); + + ret = cci_read(thp7312->regmap, THP7312_REG_FW_CRC_RESULT, &crc, NULL); + if (ret < 0) + return FW_UPLOAD_ERR_RW_ERROR; + + if (fw_crc != crc) { + dev_err(dev, "CRC mismatch: firmware 0x%08x, flash 0x%08llx\n", + fw_crc, crc); + return FW_UPLOAD_ERR_HW_ERROR; + } + + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_prepare(struct fw_upload *fw_upload, + const u8 *data, u32 size) +{ + struct thp7312_device *thp7312 = fw_upload->dd_handle; + struct device *dev = thp7312->dev; + enum fw_upload_err ret; + + mutex_lock(&thp7312->fw_lock); + thp7312->fw_cancel = false; + mutex_unlock(&thp7312->fw_lock); + + if (size < THP7312_FW_MIN_SIZE || size > THP7312_FW_MAX_SIZE) { + dev_err(dev, "%s: Invalid firmware size %d; must be between %d and %d\n", + __func__, size, THP7312_FW_MIN_SIZE, THP7312_FW_MAX_SIZE); + return FW_UPLOAD_ERR_INVALID_SIZE; + } + + ret = thp7312_fw_prepare_config(thp7312); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_prepare_check(thp7312); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_prepare_reset(thp7312); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + mutex_lock(&thp7312->fw_lock); + ret = thp7312->fw_cancel ? FW_UPLOAD_ERR_CANCELED : FW_UPLOAD_ERR_NONE; + mutex_unlock(&thp7312->fw_lock); + + return ret; +} + +static enum fw_upload_err thp7312_fw_write(struct fw_upload *fw_upload, + const u8 *data, u32 offset, + u32 size, u32 *written) +{ + struct thp7312_device *thp7312 = fw_upload->dd_handle; + struct device *dev = thp7312->dev; + u16 header_size = size - THP7312_FW_RAM_SIZE; + enum fw_upload_err ret; + bool cancel; + + mutex_lock(&thp7312->fw_lock); + cancel = thp7312->fw_cancel; + mutex_unlock(&thp7312->fw_lock); + + if (cancel) + return FW_UPLOAD_ERR_CANCELED; + + ret = thp7312_flash_erase(thp7312); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_load_to_ram(thp7312, data, THP7312_FW_RAM_SIZE); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_write_to_flash(thp7312, 0, 0x1ffff); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_load_to_ram(thp7312, data + THP7312_FW_RAM_SIZE, header_size); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_write_to_flash(thp7312, 0x20000, header_size - 1); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + ret = thp7312_fw_check_crc(thp7312, data, size); + if (ret != FW_UPLOAD_ERR_NONE) + return ret; + + dev_info(dev, "Successfully wrote firmware\n"); + + *written = size; + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err thp7312_fw_poll_complete(struct fw_upload *fw_upload) +{ + return FW_UPLOAD_ERR_NONE; +} + +/* + * This may be called asynchronously with an on-going update. All other + * functions are called sequentially in a single thread. To avoid contention on + * register accesses, only update the cancel_request flag. Other functions will + * check this flag and handle the cancel request synchronously. + */ +static void thp7312_fw_cancel(struct fw_upload *fw_upload) +{ + struct thp7312_device *thp7312 = fw_upload->dd_handle; + + mutex_lock(&thp7312->fw_lock); + thp7312->fw_cancel = true; + mutex_unlock(&thp7312->fw_lock); +} + +static const struct fw_upload_ops thp7312_fw_upload_ops = { + .prepare = thp7312_fw_prepare, + .write = thp7312_fw_write, + .poll_complete = thp7312_fw_poll_complete, + .cancel = thp7312_fw_cancel, +}; + +static int thp7312_register_flash_mode(struct thp7312_device *thp7312) +{ + struct device *dev = thp7312->dev; + struct fw_upload *fwl; + u64 val; + int ret; + + dev_info(dev, "booted in flash mode\n"); + + mutex_init(&thp7312->fw_lock); + + thp7312->fw_write_buf = devm_kzalloc(dev, THP7312_FW_DOWNLOAD_UNIT + 2, + GFP_KERNEL); + if (!thp7312->fw_write_buf) + return -ENOMEM; + + ret = __thp7312_power_on(thp7312); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to power on\n"); + + ret = cci_read(thp7312->regmap, THP7312_REG_FW_STATUS, &val, NULL); + if (ret) { + dev_err_probe(dev, ret, "Camera status read failed\n"); + goto error; + } + + fwl = firmware_upload_register(THIS_MODULE, dev, "thp7312-firmware", + &thp7312_fw_upload_ops, thp7312); + if (IS_ERR(fwl)) { + ret = PTR_ERR(fwl); + dev_err_probe(dev, ret, "Failed to register firmware upload\n"); + goto error; + } + + thp7312->fwl = fwl; + return 0; + +error: + __thp7312_power_off(thp7312); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Probe & Remove + */ + +static int thp7312_get_regulators(struct thp7312_device *thp7312) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(thp7312->supplies); i++) + thp7312->supplies[i].supply = thp7312_supply_name[i]; + + return devm_regulator_bulk_get(thp7312->dev, + ARRAY_SIZE(thp7312->supplies), + thp7312->supplies); +} + +static int thp7312_sensor_parse_dt(struct thp7312_device *thp7312, + struct fwnode_handle *node) +{ + struct device *dev = thp7312->dev; + struct thp7312_sensor *sensor; + const char *model; + u8 data_lanes[4]; + u32 values[4]; + unsigned int i; + u32 reg; + int ret; + + /* Retrieve the sensor index from the reg property. */ + ret = fwnode_property_read_u32(node, "reg", ®); + if (ret < 0) { + dev_err(dev, "'reg' property missing in sensor node\n"); + return -EINVAL; + } + + if (reg >= ARRAY_SIZE(thp7312->sensors)) { + dev_err(dev, "Out-of-bounds 'reg' value %u\n", reg); + return -EINVAL; + } + + sensor = &thp7312->sensors[reg]; + if (sensor->info) { + dev_err(dev, "Duplicate entry for sensor %u\n", reg); + return -EINVAL; + } + + ret = fwnode_property_read_string(node, "thine,model", &model); + if (ret < 0) { + dev_err(dev, "'thine,model' property missing in sensor node\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(thp7312_sensor_info); i++) { + const struct thp7312_sensor_info *info = + &thp7312_sensor_info[i]; + + if (!strcmp(info->model, model)) { + sensor->info = info; + break; + } + } + + if (!sensor->info) { + dev_err(dev, "Unsupported sensor model %s\n", model); + return -EINVAL; + } + + ret = fwnode_property_read_u32_array(node, "data-lanes", values, + ARRAY_SIZE(values)); + if (ret < 0) { + dev_err(dev, "Failed to read property data-lanes: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(data_lanes); ++i) + data_lanes[i] = values[i]; + + ret = thp7312_map_data_lanes(&sensor->lane_remap, data_lanes, + ARRAY_SIZE(data_lanes)); + if (ret) { + dev_err(dev, "Invalid sensor@%u data-lanes value\n", reg); + return ret; + } + + return 0; +} + +static int thp7312_parse_dt(struct thp7312_device *thp7312) +{ + struct v4l2_fwnode_endpoint ep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct device *dev = thp7312->dev; + struct fwnode_handle *endpoint; + struct fwnode_handle *sensors; + unsigned int num_sensors = 0; + struct fwnode_handle *node; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) + return dev_err_probe(dev, -EINVAL, "Endpoint node not found\n"); + + ret = v4l2_fwnode_endpoint_parse(endpoint, &ep); + fwnode_handle_put(endpoint); + if (ret) + return dev_err_probe(dev, ret, "Could not parse endpoint\n"); + + ret = thp7312_map_data_lanes(&thp7312->lane_remap, + ep.bus.mipi_csi2.data_lanes, + ep.bus.mipi_csi2.num_data_lanes); + if (ret) { + dev_err(dev, "Invalid data-lanes value\n"); + return ret; + } + + /* + * The thine,boot-mode property is optional and default to + * THP7312_BOOT_MODE_SPI_MASTER (1). + */ + thp7312->boot_mode = THP7312_BOOT_MODE_SPI_MASTER; + ret = device_property_read_u32(dev, "thine,boot-mode", + &thp7312->boot_mode); + if (ret && ret != -EINVAL) + return dev_err_probe(dev, ret, "Property '%s' is invalid\n", + "thine,boot-mode"); + + if (thp7312->boot_mode != THP7312_BOOT_MODE_2WIRE_SLAVE && + thp7312->boot_mode != THP7312_BOOT_MODE_SPI_MASTER) + return dev_err_probe(dev, -EINVAL, "Invalid '%s' value %u\n", + "thine,boot-mode", thp7312->boot_mode); + + /* Sensors */ + sensors = device_get_named_child_node(dev, "sensors"); + if (!sensors) { + dev_err(dev, "'sensors' child node not found\n"); + return -EINVAL; + } + + fwnode_for_each_available_child_node(sensors, node) { + if (fwnode_name_eq(node, "sensor")) { + if (!thp7312_sensor_parse_dt(thp7312, node)) + num_sensors++; + } + } + + fwnode_handle_put(sensors); + + if (!num_sensors) { + dev_err(dev, "No sensor found\n"); + return -EINVAL; + } + + return 0; +} + +static int thp7312_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct v4l2_subdev_state *sd_state; + struct thp7312_device *thp7312; + int ret; + + thp7312 = devm_kzalloc(dev, sizeof(*thp7312), GFP_KERNEL); + if (!thp7312) + return -ENOMEM; + + thp7312->dev = dev; + + thp7312->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(thp7312->regmap)) + return dev_err_probe(dev, PTR_ERR(thp7312->regmap), + "Unable to initialize I2C\n"); + + ret = thp7312_parse_dt(thp7312); + if (ret < 0) + return ret; + + ret = thp7312_get_regulators(thp7312); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + thp7312->iclk = devm_clk_get(dev, NULL); + if (IS_ERR(thp7312->iclk)) + return dev_err_probe(dev, PTR_ERR(thp7312->iclk), + "Failed to get iclk\n"); + + thp7312->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(thp7312->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(thp7312->reset_gpio), + "Failed to get reset gpio\n"); + + if (thp7312->boot_mode == THP7312_BOOT_MODE_2WIRE_SLAVE) + return thp7312_register_flash_mode(thp7312); + + v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops); + thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + thp7312->pad.flags = MEDIA_PAD_FL_SOURCE; + thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = media_entity_pads_init(&thp7312->sd.entity, 1, &thp7312->pad); + if (ret) + return ret; + + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the device manually here. + */ + ret = thp7312_power_on(thp7312); + if (ret) + goto err_entity_cleanup; + + ret = thp7312_read_firmware_version(thp7312); + if (ret < 0) { + dev_err(dev, "Camera is not found\n"); + goto err_power_off; + } + + ret = thp7312_init_controls(thp7312); + if (ret) { + dev_err(dev, "Failed to initialize controls\n"); + goto err_power_off; + } + + thp7312->sd.ctrl_handler = &thp7312->ctrl_handler; + thp7312->sd.state_lock = thp7312->ctrl_handler.lock; + + ret = v4l2_subdev_init_finalize(&thp7312->sd); + if (ret < 0) { + dev_err(dev, "Subdev active state initialization failed\n"); + goto err_free_ctrls; + } + + sd_state = v4l2_subdev_lock_and_get_active_state(&thp7312->sd); + thp7312->current_mode = &thp7312_mode_info_data[0]; + thp7312_set_frame_rate(thp7312, &thp7312->current_mode->rates[0]); + v4l2_subdev_unlock_state(sd_state); + + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = v4l2_async_register_subdev(&thp7312->sd); + if (ret < 0) { + dev_err(dev, "Subdev registration failed\n"); + goto err_pm; + } + + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + dev_info(dev, "THP7312 firmware version %02u.%02u\n", + THP7312_FW_VERSION_MAJOR(thp7312->fw_version), + THP7312_FW_VERSION_MINOR(thp7312->fw_version)); + + return 0; + +err_pm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + v4l2_subdev_cleanup(&thp7312->sd); +err_free_ctrls: + v4l2_ctrl_handler_free(&thp7312->ctrl_handler); +err_power_off: + thp7312_power_off(thp7312); +err_entity_cleanup: + media_entity_cleanup(&thp7312->sd.entity); + return ret; +} + +static void thp7312_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct thp7312_device *thp7312 = to_thp7312_dev(sd); + + if (thp7312->boot_mode == THP7312_BOOT_MODE_2WIRE_SLAVE) { + firmware_upload_unregister(thp7312->fwl); + __thp7312_power_off(thp7312); + return; + } + + v4l2_async_unregister_subdev(&thp7312->sd); + v4l2_subdev_cleanup(&thp7312->sd); + media_entity_cleanup(&thp7312->sd.entity); + v4l2_ctrl_handler_free(&thp7312->ctrl_handler); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(thp7312->dev); + if (!pm_runtime_status_suspended(thp7312->dev)) + thp7312_power_off(thp7312); + pm_runtime_set_suspended(thp7312->dev); +} + +static const struct of_device_id thp7312_dt_ids[] = { + { .compatible = "thine,thp7312" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, thp7312_dt_ids); + +static struct i2c_driver thp7312_i2c_driver = { + .driver = { + .name = "thp7312", + .pm = &thp7312_pm_ops, + .of_match_table = thp7312_dt_ids, + }, + .probe = thp7312_probe, + .remove = thp7312_remove, +}; + +module_i2c_driver(thp7312_i2c_driver); + +MODULE_DESCRIPTION("THP7312 MIPI Camera Subdev Driver"); +MODULE_LICENSE("GPL"); From 5755be5f15d9e651ed433e5dbf7b7b968efb3064 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 27 Nov 2023 11:07:44 +0200 Subject: [PATCH 2333/7721] media: v4l2-subdev: Rename .init_cfg() operation to .init_state() The subdev .init_cfg() operation is affected by two issues: - It has long been extended to initialize a whole v4l2_subdev_state instead of just a v4l2_subdev_pad_config, but its name has stuck around. - Despite operating on a whole subdev state and not being directly exposed to the subdev users (either in-kernel or through the userspace API), .init_cfg() is categorized as a subdev pad operation. This participates in making the subdev API confusing for new developers. Fix it by renaming the operation to .init_state(), and make it a subdev internal operation. Signed-off-by: Laurent Pinchart Acked-by: Michael Riesch # for imx415 Acked-by: Shuah Khan # for vimc Reviewed-by: Philipp Zabel Reviewed-by: Tomi Valkeinen [Sakari Ailus: Resolved a conflict in Renesas vsp1 driver.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/adv7180.c | 10 ++-- drivers/media/i2c/ccs/ccs-core.c | 6 +-- drivers/media/i2c/ds90ub913.c | 10 ++-- drivers/media/i2c/ds90ub953.c | 10 ++-- drivers/media/i2c/ds90ub960.c | 11 ++-- drivers/media/i2c/gc2145.c | 10 ++-- drivers/media/i2c/hi846.c | 10 ++-- drivers/media/i2c/imx214.c | 12 +++-- drivers/media/i2c/imx219.c | 9 ++-- drivers/media/i2c/imx290.c | 10 ++-- drivers/media/i2c/imx296.c | 10 ++-- drivers/media/i2c/imx334.c | 12 +++-- drivers/media/i2c/imx335.c | 12 +++-- drivers/media/i2c/imx412.c | 12 +++-- drivers/media/i2c/imx415.c | 10 ++-- drivers/media/i2c/mt9m001.c | 10 ++-- drivers/media/i2c/mt9m111.c | 10 ++-- drivers/media/i2c/mt9m114.c | 16 +++--- drivers/media/i2c/mt9p031.c | 8 +-- drivers/media/i2c/mt9v111.c | 10 ++-- drivers/media/i2c/ov01a10.c | 10 ++-- drivers/media/i2c/ov02a10.c | 10 ++-- drivers/media/i2c/ov2640.c | 10 ++-- drivers/media/i2c/ov2680.c | 10 ++-- drivers/media/i2c/ov2740.c | 10 ++-- drivers/media/i2c/ov5640.c | 10 ++-- drivers/media/i2c/ov5645.c | 12 +++-- drivers/media/i2c/ov5670.c | 10 ++-- drivers/media/i2c/ov7251.c | 12 +++-- drivers/media/i2c/ov8858.c | 10 ++-- drivers/media/i2c/ov9282.c | 12 +++-- drivers/media/i2c/st-vgxy61.c | 10 ++-- drivers/media/i2c/tc358746.c | 10 ++-- drivers/media/i2c/tda1997x.c | 10 ++-- drivers/media/i2c/thp7312.c | 10 ++-- drivers/media/i2c/tvp5150.c | 6 +-- drivers/media/pci/intel/ivsc/mei_csi.c | 10 ++-- drivers/media/platform/cadence/cdns-csi2rx.c | 10 ++-- .../platform/microchip/microchip-csi2dc.c | 10 ++-- .../platform/microchip/microchip-isc-scaler.c | 10 ++-- drivers/media/platform/nxp/imx-mipi-csis.c | 10 ++-- drivers/media/platform/nxp/imx7-media-csi.c | 6 +-- .../platform/nxp/imx8-isi/imx8-isi-crossbar.c | 10 ++-- .../platform/nxp/imx8-isi/imx8-isi-pipe.c | 10 ++-- drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 10 ++-- .../platform/renesas/rzg2l-cru/rzg2l-csi2.c | 10 ++-- .../platform/renesas/rzg2l-cru/rzg2l-ip.c | 10 ++-- .../media/platform/renesas/vsp1/vsp1_brx.c | 1 - .../media/platform/renesas/vsp1/vsp1_clu.c | 1 - .../media/platform/renesas/vsp1/vsp1_entity.c | 53 +++++++++---------- .../media/platform/renesas/vsp1/vsp1_entity.h | 2 - .../media/platform/renesas/vsp1/vsp1_hsit.c | 1 - .../media/platform/renesas/vsp1/vsp1_lif.c | 1 - .../media/platform/renesas/vsp1/vsp1_lut.c | 1 - .../media/platform/renesas/vsp1/vsp1_rwpf.c | 1 - .../media/platform/renesas/vsp1/vsp1_sru.c | 1 - .../media/platform/renesas/vsp1/vsp1_uds.c | 1 - .../media/platform/renesas/vsp1/vsp1_uif.c | 1 - .../platform/rockchip/rkisp1/rkisp1-csi.c | 10 ++-- .../platform/rockchip/rkisp1/rkisp1-isp.c | 10 ++-- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 10 ++-- .../platform/sunxi/sun4i-csi/sun4i_csi.c | 1 + .../platform/sunxi/sun4i-csi/sun4i_csi.h | 1 + .../platform/sunxi/sun4i-csi/sun4i_v4l2.c | 9 ++-- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 10 ++-- .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 10 ++-- .../sun8i_a83t_mipi_csi2.c | 10 ++-- drivers/media/platform/ti/cal/cal-camerarx.c | 10 ++-- drivers/media/platform/video-mux.c | 10 ++-- .../media/platform/xilinx/xilinx-csi2rxss.c | 10 ++-- .../media/test-drivers/vimc/vimc-debayer.c | 11 ++-- drivers/media/test-drivers/vimc/vimc-scaler.c | 11 ++-- drivers/media/test-drivers/vimc/vimc-sensor.c | 11 ++-- drivers/media/v4l2-core/v4l2-subdev.c | 20 +++---- drivers/staging/media/imx/imx-ic-prp.c | 2 +- drivers/staging/media/imx/imx-ic-prpencvf.c | 2 +- drivers/staging/media/imx/imx-media-csi.c | 2 +- drivers/staging/media/imx/imx-media-utils.c | 8 +-- drivers/staging/media/imx/imx-media-vdic.c | 2 +- drivers/staging/media/imx/imx-media.h | 4 +- drivers/staging/media/imx/imx6-mipi-csi2.c | 2 +- .../staging/media/starfive/camss/stf-isp.c | 6 ++- .../media/sunxi/sun6i-isp/sun6i_isp_proc.c | 10 ++-- include/media/v4l2-subdev.h | 7 +-- 84 files changed, 481 insertions(+), 258 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 444c322d756a..e10811cce801 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -813,8 +813,8 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, return ret; } -static int adv7180_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int adv7180_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY @@ -929,7 +929,6 @@ static const struct v4l2_subdev_core_ops adv7180_core_ops = { }; static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { - .init_cfg = adv7180_init_cfg, .enum_mbus_code = adv7180_enum_mbus_code, .set_fmt = adv7180_set_pad_format, .get_fmt = adv7180_get_pad_format, @@ -947,6 +946,10 @@ static const struct v4l2_subdev_ops adv7180_ops = { .sensor = &adv7180_sensor_ops, }; +static const struct v4l2_subdev_internal_ops adv7180_internal_ops = { + .init_state = adv7180_init_state, +}; + static irqreturn_t adv7180_irq(int irq, void *devid) { struct adv7180_state *state = devid; @@ -1458,6 +1461,7 @@ static int adv7180_probe(struct i2c_client *client) state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); + sd->internal_ops = &adv7180_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ret = adv7180_init_controls(state); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index fb713b03ad4a..92ef98a2b951 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3006,8 +3006,8 @@ static int ccs_init_subdev(struct ccs_sensor *sensor, return 0; } -static int ccs_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ccs_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ccs_subdev *ssd = to_ccs_subdev(sd); struct ccs_sensor *sensor = ssd->sensor; @@ -3055,7 +3055,6 @@ static const struct v4l2_subdev_video_ops ccs_video_ops = { }; static const struct v4l2_subdev_pad_ops ccs_pad_ops = { - .init_cfg = ccs_init_cfg, .enum_mbus_code = ccs_enum_mbus_code, .get_fmt = ccs_get_format, .set_fmt = ccs_set_format, @@ -3079,6 +3078,7 @@ static const struct media_entity_operations ccs_entity_ops = { }; static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { + .init_state = ccs_init_state, .registered = ccs_registered, .unregistered = ccs_unregistered, }; diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 8bb6be956780..ca9bb29dab89 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -443,8 +443,8 @@ static int ub913_set_fmt(struct v4l2_subdev *sd, return 0; } -static int ub913_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ub913_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_route routes[] = { { @@ -503,7 +503,6 @@ static const struct v4l2_subdev_pad_ops ub913_pad_ops = { .get_frame_desc = ub913_get_frame_desc, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ub913_set_fmt, - .init_cfg = ub913_init_cfg, }; static const struct v4l2_subdev_ops ub913_subdev_ops = { @@ -511,6 +510,10 @@ static const struct v4l2_subdev_ops ub913_subdev_ops = { .pad = &ub913_pad_ops, }; +static const struct v4l2_subdev_internal_ops ub913_internal_ops = { + .init_state = ub913_init_state, +}; + static const struct media_entity_operations ub913_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -744,6 +747,7 @@ static int ub913_subdev_init(struct ub913_data *priv) int ret; v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub913_subdev_ops); + priv->sd.internal_ops = &ub913_internal_ops; priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub913_entity_ops; diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 4eb08e3a31c7..16f88db14981 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -575,8 +575,8 @@ static int ub953_set_fmt(struct v4l2_subdev *sd, return 0; } -static int ub953_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ub953_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_route routes[] = { { @@ -713,7 +713,6 @@ static const struct v4l2_subdev_pad_ops ub953_pad_ops = { .get_frame_desc = ub953_get_frame_desc, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ub953_set_fmt, - .init_cfg = ub953_init_cfg, }; static const struct v4l2_subdev_core_ops ub953_subdev_core_ops = { @@ -727,6 +726,10 @@ static const struct v4l2_subdev_ops ub953_subdev_ops = { .pad = &ub953_pad_ops, }; +static const struct v4l2_subdev_internal_ops ub953_internal_ops = { + .init_state = ub953_init_state, +}; + static const struct media_entity_operations ub953_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -1240,6 +1243,7 @@ static int ub953_subdev_init(struct ub953_data *priv) int ret; v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub953_subdev_ops); + priv->sd.internal_ops = &ub953_internal_ops; priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 1d1476098c92..ffe5f25f8647 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2906,8 +2906,8 @@ static int ub960_set_fmt(struct v4l2_subdev *sd, return 0; } -static int ub960_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ub960_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct ub960_data *priv = sd_to_ub960(sd); @@ -2938,8 +2938,6 @@ static const struct v4l2_subdev_pad_ops ub960_pad_ops = { .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ub960_set_fmt, - - .init_cfg = ub960_init_cfg, }; static int ub960_log_status(struct v4l2_subdev *sd) @@ -3091,6 +3089,10 @@ static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = { .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; +static const struct v4l2_subdev_internal_ops ub960_internal_ops = { + .init_state = ub960_init_state, +}; + static const struct v4l2_subdev_ops ub960_subdev_ops = { .core = &ub960_subdev_core_ops, .pad = &ub960_pad_ops, @@ -3650,6 +3652,7 @@ static int ub960_create_subdev(struct ub960_data *priv) int ret; v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub960_subdev_ops); + priv->sd.internal_ops = &ub960_internal_ops; v4l2_ctrl_handler_init(&priv->ctrl_handler, 1); priv->sd.ctrl_handler = &priv->ctrl_handler; diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index 12d3780b5548..bef7b0e056a8 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -653,8 +653,8 @@ static void gc2145_update_pad_format(struct gc2145 *gc2145, fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int gc2145_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int gc2145_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct gc2145 *gc2145 = to_gc2145(sd); struct v4l2_mbus_framefmt *format; @@ -1079,7 +1079,6 @@ static const struct v4l2_subdev_video_ops gc2145_video_ops = { }; static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { - .init_cfg = gc2145_init_cfg, .enum_mbus_code = gc2145_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = gc2145_set_pad_format, @@ -1093,6 +1092,10 @@ static const struct v4l2_subdev_ops gc2145_subdev_ops = { .pad = &gc2145_pad_ops, }; +static const struct v4l2_subdev_internal_ops gc2145_subdev_internal_ops = { + .init_state = gc2145_init_state, +}; + static int gc2145_set_ctrl_test_pattern(struct gc2145 *gc2145, int value) { int ret = 0; @@ -1286,6 +1289,7 @@ static int gc2145_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&gc2145->sd, client, &gc2145_subdev_ops); + gc2145->sd.internal_ops = &gc2145_subdev_internal_ops; /* Check the hardware configuration in device tree */ if (gc2145_check_hwcfg(dev)) diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 0595080c2211..9c565ec033d4 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1871,8 +1871,8 @@ static int hi846_get_selection(struct v4l2_subdev *sd, } } -static int hi846_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int hi846_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct hi846 *hi846 = to_hi846(sd); struct v4l2_mbus_framefmt *mf; @@ -1895,7 +1895,6 @@ static const struct v4l2_subdev_video_ops hi846_video_ops = { }; static const struct v4l2_subdev_pad_ops hi846_pad_ops = { - .init_cfg = hi846_init_cfg, .enum_frame_size = hi846_enum_frame_size, .enum_mbus_code = hi846_enum_mbus_code, .set_fmt = hi846_set_format, @@ -1908,6 +1907,10 @@ static const struct v4l2_subdev_ops hi846_subdev_ops = { .pad = &hi846_pad_ops, }; +static const struct v4l2_subdev_internal_ops hi846_internal_ops = { + .init_state = hi846_init_state, +}; + static const struct media_entity_operations hi846_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -2071,6 +2074,7 @@ static int hi846_probe(struct i2c_client *client) return ret; v4l2_i2c_subdev_init(&hi846->sd, client, &hi846_subdev_ops); + hi846->sd.internal_ops = &hi846_internal_ops; mutex_init(&hi846->mutex); diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 8bc7b114c57d..474c95572bf6 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -633,8 +633,8 @@ static int imx214_get_selection(struct v4l2_subdev *sd, return 0; } -static int imx214_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int imx214_entity_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { }; @@ -839,7 +839,6 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = { .get_fmt = imx214_get_format, .set_fmt = imx214_set_format, .get_selection = imx214_get_selection, - .init_cfg = imx214_entity_init_cfg, }; static const struct v4l2_subdev_ops imx214_subdev_ops = { @@ -848,6 +847,10 @@ static const struct v4l2_subdev_ops imx214_subdev_ops = { .pad = &imx214_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx214_internal_ops = { + .init_state = imx214_entity_init_state, +}; + static const struct regmap_config sensor_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -957,6 +960,7 @@ static int imx214_probe(struct i2c_client *client) } v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); + imx214->sd.internal_ops = &imx214_internal_ops; /* * Enable power initially, to avoid warnings @@ -1021,7 +1025,7 @@ static int imx214_probe(struct i2c_client *client) goto free_ctrl; } - imx214_entity_init_cfg(&imx214->sd, NULL); + imx214_entity_init_state(&imx214->sd, NULL); ret = v4l2_async_register_subdev_sensor(&imx214->sd); if (ret < 0) { diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 675795ac2e83..e17ef2e9d9d0 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -905,8 +905,8 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return -EINVAL; } -static int imx219_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int imx219_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, @@ -933,7 +933,6 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = { }; static const struct v4l2_subdev_pad_ops imx219_pad_ops = { - .init_cfg = imx219_init_cfg, .enum_mbus_code = imx219_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx219_set_pad_format, @@ -947,6 +946,9 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = { .pad = &imx219_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx219_internal_ops = { + .init_state = imx219_init_state, +}; /* ----------------------------------------------------------------------------- * Power management @@ -1098,6 +1100,7 @@ static int imx219_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); + imx219->sd.internal_ops = &imx219_internal_ops; /* Check the hardware configuration in device tree */ if (imx219_check_hwcfg(dev, imx219)) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index aa8cfbcd40aa..52ba6188911b 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1195,8 +1195,8 @@ static int imx290_get_selection(struct v4l2_subdev *sd, } } -static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int imx290_entity_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, @@ -1221,7 +1221,6 @@ static const struct v4l2_subdev_video_ops imx290_video_ops = { }; static const struct v4l2_subdev_pad_ops imx290_pad_ops = { - .init_cfg = imx290_entity_init_cfg, .enum_mbus_code = imx290_enum_mbus_code, .enum_frame_size = imx290_enum_frame_size, .get_fmt = v4l2_subdev_get_fmt, @@ -1235,6 +1234,10 @@ static const struct v4l2_subdev_ops imx290_subdev_ops = { .pad = &imx290_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx290_internal_ops = { + .init_state = imx290_entity_init_state, +}; + static const struct media_entity_operations imx290_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -1248,6 +1251,7 @@ static int imx290_subdev_init(struct imx290 *imx290) imx290->current_mode = &imx290_modes_ptr(imx290)[0]; v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); + imx290->sd.internal_ops = &imx290_internal_ops; imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; imx290->sd.dev = imx290->dev; diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index 8399cca496a7..83149fa729c4 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -798,8 +798,8 @@ static int imx296_set_selection(struct v4l2_subdev *sd, return 0; } -static int imx296_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int imx296_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_selection sel = { .target = V4L2_SEL_TGT_CROP, @@ -830,7 +830,6 @@ static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = { .set_fmt = imx296_set_format, .get_selection = imx296_get_selection, .set_selection = imx296_set_selection, - .init_cfg = imx296_init_cfg, }; static const struct v4l2_subdev_ops imx296_subdev_ops = { @@ -838,12 +837,17 @@ static const struct v4l2_subdev_ops imx296_subdev_ops = { .pad = &imx296_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx296_internal_ops = { + .init_state = imx296_init_state, +}; + static int imx296_subdev_init(struct imx296 *sensor) { struct i2c_client *client = to_i2c_client(sensor->dev); int ret; v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops); + sensor->subdev.internal_ops = &imx296_internal_ops; ret = imx296_ctrls_init(sensor); if (ret < 0) diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 42cf71c1f6fd..6725b3e2a73e 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -935,14 +935,14 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd, } /** - * imx334_init_cfg() - Initialize sub-device state + * imx334_init_state() - Initialize sub-device state * @sd: pointer to imx334 V4L2 sub-device structure * @sd_state: V4L2 sub-device state * * Return: 0 if successful, error code otherwise. */ -static int imx334_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx334_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx334 *imx334 = to_imx334(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -1190,7 +1190,6 @@ static const struct v4l2_subdev_video_ops imx334_video_ops = { }; static const struct v4l2_subdev_pad_ops imx334_pad_ops = { - .init_cfg = imx334_init_cfg, .enum_mbus_code = imx334_enum_mbus_code, .enum_frame_size = imx334_enum_frame_size, .get_fmt = imx334_get_pad_format, @@ -1202,6 +1201,10 @@ static const struct v4l2_subdev_ops imx334_subdev_ops = { .pad = &imx334_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx334_internal_ops = { + .init_state = imx334_init_state, +}; + /** * imx334_power_on() - Sensor power on sequence * @dev: pointer to i2c device @@ -1359,6 +1362,7 @@ static int imx334_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&imx334->sd, client, &imx334_subdev_ops); + imx334->sd.internal_ops = &imx334_internal_ops; ret = imx334_parse_hw_config(imx334); if (ret) { diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 0432f059e913..205a150971b7 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -618,14 +618,14 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, } /** - * imx335_init_cfg() - Initialize sub-device state + * imx335_init_state() - Initialize sub-device state * @sd: pointer to imx335 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int imx335_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx335_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx335 *imx335 = to_imx335(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -835,7 +835,6 @@ static const struct v4l2_subdev_video_ops imx335_video_ops = { }; static const struct v4l2_subdev_pad_ops imx335_pad_ops = { - .init_cfg = imx335_init_cfg, .enum_mbus_code = imx335_enum_mbus_code, .enum_frame_size = imx335_enum_frame_size, .get_fmt = imx335_get_pad_format, @@ -847,6 +846,10 @@ static const struct v4l2_subdev_ops imx335_subdev_ops = { .pad = &imx335_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx335_internal_ops = { + .init_state = imx335_init_state, +}; + /** * imx335_power_on() - Sensor power on sequence * @dev: pointer to i2c device @@ -999,6 +1002,7 @@ static int imx335_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops); + imx335->sd.internal_ops = &imx335_internal_ops; ret = imx335_parse_hw_config(imx335); if (ret) { diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 41d756a20f3c..0efce329525e 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -770,14 +770,14 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, } /** - * imx412_init_cfg() - Initialize sub-device state + * imx412_init_state() - Initialize sub-device state * @sd: pointer to imx412 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int imx412_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx412_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx412 *imx412 = to_imx412(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -997,7 +997,6 @@ static const struct v4l2_subdev_video_ops imx412_video_ops = { }; static const struct v4l2_subdev_pad_ops imx412_pad_ops = { - .init_cfg = imx412_init_cfg, .enum_mbus_code = imx412_enum_mbus_code, .enum_frame_size = imx412_enum_frame_size, .get_fmt = imx412_get_pad_format, @@ -1009,6 +1008,10 @@ static const struct v4l2_subdev_ops imx412_subdev_ops = { .pad = &imx412_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx412_internal_ops = { + .init_state = imx412_init_state, +}; + /** * imx412_power_on() - Sensor power on sequence * @dev: pointer to i2c device @@ -1177,6 +1180,7 @@ static int imx412_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops); + imx412->sd.internal_ops = &imx412_internal_ops; ret = imx412_parse_hw_config(imx412); if (ret) { diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 6436a32c4025..1e5f20c3ed82 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -880,8 +880,8 @@ static int imx415_get_selection(struct v4l2_subdev *sd, return -EINVAL; } -static int imx415_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int imx415_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_format format = { .format = { @@ -905,7 +905,6 @@ static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = { .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx415_set_format, .get_selection = imx415_get_selection, - .init_cfg = imx415_init_cfg, }; static const struct v4l2_subdev_ops imx415_subdev_ops = { @@ -913,12 +912,17 @@ static const struct v4l2_subdev_ops imx415_subdev_ops = { .pad = &imx415_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx415_internal_ops = { + .init_state = imx415_init_state, +}; + static int imx415_subdev_init(struct imx415 *sensor) { struct i2c_client *client = to_i2c_client(sensor->dev); int ret; v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops); + sensor->subdev.internal_ops = &imx415_internal_ops; ret = imx415_ctrls_init(sensor); if (ret) diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 4c897bb07fed..ad1a3ab77411 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -650,8 +650,8 @@ static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { #endif }; -static int mt9m001_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int mt9m001_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); @@ -708,7 +708,6 @@ static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { }; static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { - .init_cfg = mt9m001_init_cfg, .enum_mbus_code = mt9m001_enum_mbus_code, .get_selection = mt9m001_get_selection, .set_selection = mt9m001_set_selection, @@ -724,6 +723,10 @@ static const struct v4l2_subdev_ops mt9m001_subdev_ops = { .pad = &mt9m001_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops mt9m001_internal_ops = { + .init_state = mt9m001_init_state, +}; + static int mt9m001_probe(struct i2c_client *client) { struct mt9m001 *mt9m001; @@ -755,6 +758,7 @@ static int mt9m001_probe(struct i2c_client *client) return PTR_ERR(mt9m001->reset_gpio); v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); + mt9m001->subdev.internal_ops = &mt9m001_internal_ops; mt9m001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; v4l2_ctrl_handler_init(&mt9m001->hdl, 4); diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 17ca92810b58..54a7a4c623ea 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1111,8 +1111,8 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9m111_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int mt9m111_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(sd_state, 0); @@ -1156,7 +1156,6 @@ static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { - .init_cfg = mt9m111_init_cfg, .enum_mbus_code = mt9m111_enum_mbus_code, .get_selection = mt9m111_get_selection, .set_selection = mt9m111_set_selection, @@ -1171,6 +1170,10 @@ static const struct v4l2_subdev_ops mt9m111_subdev_ops = { .pad = &mt9m111_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops mt9m111_internal_ops = { + .init_state = mt9m111_init_state, +}; + /* * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one @@ -1275,6 +1278,7 @@ static int mt9m111_probe(struct i2c_client *client) mt9m111->ctx = &context_b; v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); + mt9m111->subdev.internal_ops = &mt9m111_internal_ops; mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index 23cf84f1a746..0a22f328981d 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -1152,8 +1152,8 @@ static inline struct mt9m114 *pa_to_mt9m114(struct v4l2_subdev *sd) return container_of(sd, struct mt9m114, pa.sd); } -static int mt9m114_pa_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int mt9m114_pa_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; @@ -1304,7 +1304,6 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { - .init_cfg = mt9m114_pa_init_cfg, .enum_mbus_code = mt9m114_pa_enum_mbus_code, .enum_frame_size = mt9m114_pa_enum_framesizes, .get_fmt = v4l2_subdev_get_fmt, @@ -1317,6 +1316,10 @@ static const struct v4l2_subdev_ops mt9m114_pa_ops = { .pad = &mt9m114_pa_pad_ops, }; +static const struct v4l2_subdev_internal_ops mt9m114_pa_internal_ops = { + .init_state = mt9m114_pa_init_state, +}; + static int mt9m114_pa_init(struct mt9m114 *sensor) { struct v4l2_ctrl_handler *hdl = &sensor->pa.hdl; @@ -1329,6 +1332,7 @@ static int mt9m114_pa_init(struct mt9m114 *sensor) /* Initialize the subdev. */ v4l2_subdev_init(sd, &mt9m114_pa_ops); + sd->internal_ops = &mt9m114_pa_internal_ops; v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " pixel array"); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -1624,8 +1628,8 @@ static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd, return ret; } -static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int mt9m114_ifp_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct mt9m114 *sensor = ifp_to_mt9m114(sd); struct v4l2_mbus_framefmt *format; @@ -1968,7 +1972,6 @@ static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = { - .init_cfg = mt9m114_ifp_init_cfg, .enum_mbus_code = mt9m114_ifp_enum_mbus_code, .enum_frame_size = mt9m114_ifp_enum_framesizes, .enum_frame_interval = mt9m114_ifp_enum_frameintervals, @@ -1984,6 +1987,7 @@ static const struct v4l2_subdev_ops mt9m114_ifp_ops = { }; static const struct v4l2_subdev_internal_ops mt9m114_ifp_internal_ops = { + .init_state = mt9m114_ifp_init_state, .registered = mt9m114_ifp_registered, .unregistered = mt9m114_ifp_unregistered, }; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 89bcd48748b9..596200d0248c 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -696,8 +696,8 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev, return 0; } -static int mt9p031_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int mt9p031_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); struct v4l2_mbus_framefmt *format; @@ -1041,7 +1041,6 @@ static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { - .init_cfg = mt9p031_init_cfg, .enum_mbus_code = mt9p031_enum_mbus_code, .enum_frame_size = mt9p031_enum_frame_size, .get_fmt = mt9p031_get_format, @@ -1057,6 +1056,7 @@ static const struct v4l2_subdev_ops mt9p031_subdev_ops = { }; static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { + .init_state = mt9p031_init_state, .registered = mt9p031_registered, .open = mt9p031_open, .close = mt9p031_close, @@ -1189,7 +1189,7 @@ static int mt9p031_probe(struct i2c_client *client) mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ret = mt9p031_init_cfg(&mt9p031->subdev, NULL); + ret = mt9p031_init_state(&mt9p031->subdev, NULL); if (ret) goto done; diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 6752582cb2c7..b186e9160d94 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -948,8 +948,8 @@ static int mt9v111_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9v111_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int mt9v111_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { *v4l2_subdev_state_get_format(sd_state, 0) = mt9v111_def_fmt; @@ -967,7 +967,6 @@ static const struct v4l2_subdev_video_ops mt9v111_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = { - .init_cfg = mt9v111_init_cfg, .enum_mbus_code = mt9v111_enum_mbus_code, .enum_frame_size = mt9v111_enum_frame_size, .enum_frame_interval = mt9v111_enum_frame_interval, @@ -981,6 +980,10 @@ static const struct v4l2_subdev_ops mt9v111_ops = { .pad = &mt9v111_pad_ops, }; +static const struct v4l2_subdev_internal_ops mt9v111_internal_ops = { + .init_state = mt9v111_init_state, +}; + static const struct media_entity_operations mt9v111_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -1194,6 +1197,7 @@ static int mt9v111_probe(struct i2c_client *client) mt9v111->pending = true; v4l2_i2c_subdev_init(&mt9v111->sd, client, &mt9v111_ops); + mt9v111->sd.internal_ops = &mt9v111_internal_ops; mt9v111->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; mt9v111->sd.entity.ops = &mt9v111_subdev_entity_ops; diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index c72280bb1f5b..7cca9294ea31 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -729,8 +729,8 @@ static int ov01a10_set_format(struct v4l2_subdev *sd, return 0; } -static int ov01a10_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ov01a10_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, @@ -813,7 +813,6 @@ static const struct v4l2_subdev_video_ops ov01a10_video_ops = { }; static const struct v4l2_subdev_pad_ops ov01a10_pad_ops = { - .init_cfg = ov01a10_init_cfg, .set_fmt = ov01a10_set_format, .get_fmt = v4l2_subdev_get_fmt, .get_selection = ov01a10_get_selection, @@ -827,6 +826,10 @@ static const struct v4l2_subdev_ops ov01a10_subdev_ops = { .pad = &ov01a10_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov01a10_internal_ops = { + .init_state = ov01a10_init_state, +}; + static const struct media_entity_operations ov01a10_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -872,6 +875,7 @@ static int ov01a10_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&ov01a10->sd, client, &ov01a10_subdev_ops); + ov01a10->sd.internal_ops = &ov01a10_internal_ops; ret = ov01a10_identify_module(ov01a10); if (ret) diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 8454cb39a47b..6c30e1a0d814 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -511,8 +511,8 @@ static int __ov02a10_stop_stream(struct ov02a10 *ov02a10) SC_CTRL_MODE_STANDBY); } -static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov02a10_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, @@ -709,7 +709,6 @@ static const struct v4l2_subdev_video_ops ov02a10_video_ops = { }; static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = { - .init_cfg = ov02a10_entity_init_cfg, .enum_mbus_code = ov02a10_enum_mbus_code, .enum_frame_size = ov02a10_enum_frame_sizes, .get_fmt = ov02a10_get_fmt, @@ -721,6 +720,10 @@ static const struct v4l2_subdev_ops ov02a10_subdev_ops = { .pad = &ov02a10_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov02a10_internal_ops = { + .init_state = ov02a10_init_state, +}; + static const struct media_entity_operations ov02a10_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -869,6 +872,7 @@ static int ov02a10_probe(struct i2c_client *client) "failed to check HW configuration\n"); v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops); + ov02a10->subdev.internal_ops = &ov02a10_internal_ops; ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT; ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 28911d5169f7..67c4bd2916e8 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -996,8 +996,8 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, return ret; } -static int ov2640_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov2640_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(sd_state, 0); @@ -1125,7 +1125,6 @@ static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { }; static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { - .init_cfg = ov2640_init_cfg, .enum_mbus_code = ov2640_enum_mbus_code, .get_selection = ov2640_get_selection, .get_fmt = ov2640_get_fmt, @@ -1142,6 +1141,10 @@ static const struct v4l2_subdev_ops ov2640_subdev_ops = { .video = &ov2640_subdev_video_ops, }; +static const struct v4l2_subdev_internal_ops ov2640_internal_ops = { + .init_state = ov2640_init_state, +}; + static int ov2640_probe_dt(struct i2c_client *client, struct ov2640_priv *priv) { @@ -1211,6 +1214,7 @@ static int ov2640_probe(struct i2c_client *client) priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); + priv->subdev.internal_ops = &ov2640_internal_ops; priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; mutex_init(&priv->lock); diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 9b53ea9af45a..d34d1972dcd9 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -755,8 +755,8 @@ static int ov2680_set_selection(struct v4l2_subdev *sd, return 0; } -static int ov2680_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov2680_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ov2680_dev *sensor = to_ov2680_dev(sd); @@ -876,7 +876,6 @@ static const struct v4l2_subdev_video_ops ov2680_video_ops = { }; static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { - .init_cfg = ov2680_init_cfg, .enum_mbus_code = ov2680_enum_mbus_code, .enum_frame_size = ov2680_enum_frame_size, .enum_frame_interval = ov2680_enum_frame_interval, @@ -891,6 +890,10 @@ static const struct v4l2_subdev_ops ov2680_subdev_ops = { .pad = &ov2680_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov2680_internal_ops = { + .init_state = ov2680_init_state, +}; + static int ov2680_mode_init(struct ov2680_dev *sensor) { /* set initial mode */ @@ -915,6 +918,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) int ret = 0; v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops); + sensor->sd.internal_ops = &ov2680_internal_ops; sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 23cbd8b7846e..f0be51b343a7 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -879,8 +879,8 @@ static int ov2740_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int ov2740_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov2740_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { ov2740_update_pad_format(&supported_modes[0], v4l2_subdev_state_get_format(sd_state, 0)); @@ -897,7 +897,6 @@ static const struct v4l2_subdev_pad_ops ov2740_pad_ops = { .set_fmt = ov2740_set_format, .enum_mbus_code = ov2740_enum_mbus_code, .enum_frame_size = ov2740_enum_frame_size, - .init_cfg = ov2740_init_cfg, }; static const struct v4l2_subdev_ops ov2740_subdev_ops = { @@ -905,6 +904,10 @@ static const struct v4l2_subdev_ops ov2740_subdev_ops = { .pad = &ov2740_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov2740_internal_ops = { + .init_state = ov2740_init_state, +}; + static const struct media_entity_operations ov2740_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -1074,6 +1077,7 @@ static int ov2740_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&ov2740->sd, client, &ov2740_subdev_ops); + ov2740->sd.internal_ops = &ov2740_internal_ops; full_power = acpi_dev_state_d0(&client->dev); if (full_power) { ret = ov2740_identify_module(ov2740); diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 3f79a3b77044..6fd98b8cb181 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3744,8 +3744,8 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int ov5640_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ov5640_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct ov5640_dev *sensor = to_ov5640_dev(sd); struct v4l2_mbus_framefmt *fmt = @@ -3776,7 +3776,6 @@ static const struct v4l2_subdev_video_ops ov5640_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { - .init_cfg = ov5640_init_cfg, .enum_mbus_code = ov5640_enum_mbus_code, .get_fmt = ov5640_get_fmt, .set_fmt = ov5640_set_fmt, @@ -3791,6 +3790,10 @@ static const struct v4l2_subdev_ops ov5640_subdev_ops = { .pad = &ov5640_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov5640_internal_ops = { + .init_state = ov5640_init_state, +}; + static int ov5640_get_regulators(struct ov5640_dev *sensor) { int i; @@ -3905,6 +3908,7 @@ static int ov5640_probe(struct i2c_client *client) return PTR_ERR(sensor->reset_gpio); v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); + sensor->sd.internal_ops = &ov5640_internal_ops; sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 695f4f673536..a26ac11c989d 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -934,8 +934,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd, return 0; } -static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int ov5645_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { 0 }; @@ -1023,7 +1023,6 @@ static const struct v4l2_subdev_video_ops ov5645_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { - .init_cfg = ov5645_entity_init_cfg, .enum_mbus_code = ov5645_enum_mbus_code, .enum_frame_size = ov5645_enum_frame_size, .get_fmt = ov5645_get_format, @@ -1036,6 +1035,10 @@ static const struct v4l2_subdev_ops ov5645_subdev_ops = { .pad = &ov5645_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov5645_internal_ops = { + .init_state = ov5645_init_state, +}; + static int ov5645_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -1162,6 +1165,7 @@ static int ov5645_probe(struct i2c_client *client) } v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops); + ov5645->sd.internal_ops = &ov5645_internal_ops; ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov5645->pad.flags = MEDIA_PAD_FL_SOURCE; ov5645->sd.dev = &client->dev; @@ -1220,7 +1224,7 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - ov5645_entity_init_cfg(&ov5645->sd, NULL); + ov5645_init_state(&ov5645->sd, NULL); ret = v4l2_async_register_subdev(&ov5645->sd); if (ret < 0) { diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 470d848f40d8..2aee85965cf7 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2196,8 +2196,8 @@ static int ov5670_init_controls(struct ov5670 *ov5670) return ret; } -static int ov5670_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int ov5670_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_mbus_framefmt *fmt = v4l2_subdev_state_get_format(state, 0); @@ -2592,7 +2592,6 @@ static const struct v4l2_subdev_video_ops ov5670_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5670_pad_ops = { - .init_cfg = ov5670_init_cfg, .enum_mbus_code = ov5670_enum_mbus_code, .get_fmt = ov5670_get_pad_format, .set_fmt = ov5670_set_pad_format, @@ -2612,6 +2611,10 @@ static const struct v4l2_subdev_ops ov5670_subdev_ops = { .sensor = &ov5670_sensor_ops, }; +static const struct v4l2_subdev_internal_ops ov5670_internal_ops = { + .init_state = ov5670_init_state, +}; + static const struct media_entity_operations ov5670_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -2675,6 +2678,7 @@ static int ov5670_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); + ov5670->sd.internal_ops = &ov5670_internal_ops; ret = ov5670_regulators_probe(ov5670); if (ret) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 774f5dfb8186..897a0763df4a 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1282,8 +1282,8 @@ static int ov7251_set_format(struct v4l2_subdev *sd, return ret; } -static int ov7251_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int ov7251_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY @@ -1441,7 +1441,6 @@ static const struct v4l2_subdev_video_ops ov7251_video_ops = { }; static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = { - .init_cfg = ov7251_entity_init_cfg, .enum_mbus_code = ov7251_enum_mbus_code, .enum_frame_size = ov7251_enum_frame_size, .enum_frame_interval = ov7251_enum_frame_ival, @@ -1455,6 +1454,10 @@ static const struct v4l2_subdev_ops ov7251_subdev_ops = { .pad = &ov7251_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov7251_internal_ops = { + .init_state = ov7251_init_state, +}; + static int ov7251_check_hwcfg(struct ov7251 *ov7251) { struct fwnode_handle *fwnode = dev_fwnode(ov7251->dev); @@ -1693,6 +1696,7 @@ static int ov7251_probe(struct i2c_client *client) } v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops); + ov7251->sd.internal_ops = &ov7251_internal_ops; ov7251->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov7251->pad.flags = MEDIA_PAD_FL_SOURCE; ov7251->sd.dev = &client->dev; @@ -1750,7 +1754,7 @@ static int ov7251_probe(struct i2c_client *client) goto free_entity; } - ov7251_entity_init_cfg(&ov7251->sd, NULL); + ov7251_init_state(&ov7251->sd, NULL); return 0; diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 0e3776136136..174c65f76886 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1476,8 +1476,8 @@ static int ov8858_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int ov8858_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov8858_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { const struct ov8858_mode *def_mode = &ov8858_modes[0]; struct v4l2_subdev_format fmt = { @@ -1494,7 +1494,6 @@ static int ov8858_init_cfg(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { - .init_cfg = ov8858_init_cfg, .enum_mbus_code = ov8858_enum_mbus_code, .enum_frame_size = ov8858_enum_frame_sizes, .get_fmt = v4l2_subdev_get_fmt, @@ -1512,6 +1511,10 @@ static const struct v4l2_subdev_ops ov8858_subdev_ops = { .pad = &ov8858_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov8858_internal_ops = { + .init_state = ov8858_init_state, +}; + /* ---------------------------------------------------------------------------- * Controls handling */ @@ -1899,6 +1902,7 @@ static int ov8858_probe(struct i2c_client *client) "Failed to get powerdown gpio\n"); v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops); + ov8858->subdev.internal_ops = &ov8858_internal_ops; ret = ov8858_configure_regulators(ov8858); if (ret) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 1707bc22ca91..251a4b534914 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -876,14 +876,14 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd, } /** - * ov9282_init_cfg() - Initialize sub-device state + * ov9282_init_state() - Initialize sub-device state * @sd: pointer to ov9282 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int ov9282_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int ov9282_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ov9282 *ov9282 = to_ov9282(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -1192,7 +1192,6 @@ static const struct v4l2_subdev_video_ops ov9282_video_ops = { }; static const struct v4l2_subdev_pad_ops ov9282_pad_ops = { - .init_cfg = ov9282_init_cfg, .enum_mbus_code = ov9282_enum_mbus_code, .enum_frame_size = ov9282_enum_frame_size, .get_fmt = ov9282_get_pad_format, @@ -1206,6 +1205,10 @@ static const struct v4l2_subdev_ops ov9282_subdev_ops = { .pad = &ov9282_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov9282_internal_ops = { + .init_state = ov9282_init_state, +}; + /** * ov9282_power_on() - Sensor power on sequence * @dev: pointer to i2c device @@ -1394,6 +1397,7 @@ static int ov9282_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops); + ov9282->sd.internal_ops = &ov9282_internal_ops; v4l2_i2c_subdev_set_name(&ov9282->sd, client, device_get_match_data(ov9282->dev), NULL); diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 507cd9661e9d..98d8975dcd67 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -1322,8 +1322,8 @@ static int vgxy61_set_fmt(struct v4l2_subdev *sd, return ret; } -static int vgxy61_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vgxy61_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct vgxy61_dev *sensor = to_vgxy61_dev(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -1469,7 +1469,6 @@ static const struct v4l2_subdev_video_ops vgxy61_video_ops = { }; static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = { - .init_cfg = vgxy61_init_cfg, .enum_mbus_code = vgxy61_enum_mbus_code, .get_fmt = vgxy61_get_fmt, .set_fmt = vgxy61_set_fmt, @@ -1482,6 +1481,10 @@ static const struct v4l2_subdev_ops vgxy61_subdev_ops = { .pad = &vgxy61_pad_ops, }; +static const struct v4l2_subdev_internal_ops vgxy61_internal_ops = { + .init_state = vgxy61_init_state, +}; + static const struct media_entity_operations vgxy61_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -1842,6 +1845,7 @@ static int vgxy61_probe(struct i2c_client *client) device_property_read_bool(dev, "st,strobe-gpios-polarity"); v4l2_i2c_subdev_init(&sensor->sd, client, &vgxy61_subdev_ops); + sensor->sd.internal_ops = &vgxy61_internal_ops; sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->sd.entity.ops = &vgxy61_subdev_entity_ops; diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 8be9c0f293e0..106de4271d2e 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -740,8 +740,8 @@ static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) return v4l2_subdev_call(src, video, s_stream, 0); } -static int tc358746_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int tc358746_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_mbus_framefmt *fmt; @@ -1038,7 +1038,6 @@ static const struct v4l2_subdev_video_ops tc358746_video_ops = { }; static const struct v4l2_subdev_pad_ops tc358746_pad_ops = { - .init_cfg = tc358746_init_cfg, .enum_mbus_code = tc358746_enum_mbus_code, .set_fmt = tc358746_set_fmt, .get_fmt = v4l2_subdev_get_fmt, @@ -1052,6 +1051,10 @@ static const struct v4l2_subdev_ops tc358746_ops = { .pad = &tc358746_pad_ops, }; +static const struct v4l2_subdev_internal_ops tc358746_internal_ops = { + .init_state = tc358746_init_state, +}; + static const struct media_entity_operations tc358746_entity_ops = { .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, .link_validate = v4l2_subdev_link_validate, @@ -1282,6 +1285,7 @@ tc358746_init_subdev(struct tc358746 *tc358746, struct i2c_client *client) int err; v4l2_i2c_subdev_init(sd, client, &tc358746_ops); + sd->internal_ops = &tc358746_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; sd->entity.ops = &tc358746_entity_ops; diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 63c12b77ff1e..1ea703a9909f 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1734,8 +1734,8 @@ static const struct v4l2_subdev_video_ops tda1997x_video_ops = { * v4l2_subdev_pad_ops */ -static int tda1997x_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int tda1997x_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct tda1997x_state *state = to_state(sd); struct v4l2_mbus_framefmt *mf; @@ -1925,7 +1925,6 @@ static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = { - .init_cfg = tda1997x_init_cfg, .enum_mbus_code = tda1997x_enum_mbus_code, .get_fmt = tda1997x_get_format, .set_fmt = tda1997x_set_format, @@ -2047,6 +2046,10 @@ static const struct v4l2_subdev_ops tda1997x_subdev_ops = { .pad = &tda1997x_pad_ops, }; +static const struct v4l2_subdev_internal_ops tda1997x_internal_ops = { + .init_state = tda1997x_init_state, +}; + /* ----------------------------------------------------------------------------- * v4l2_controls */ @@ -2588,6 +2591,7 @@ static int tda1997x_probe(struct i2c_client *client) /* initialize subdev */ sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_ops); + sd->internal_ops = &tda1997x_internal_ops; snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", id->name, i2c_adapter_id(client->adapter), client->addr); diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index 9b387e568603..3d46e428e0ac 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -837,8 +837,8 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int thp7312_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int thp7312_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { const struct thp7312_mode_info *default_mode = &thp7312_mode_info_data[0]; struct v4l2_mbus_framefmt *fmt; @@ -875,7 +875,6 @@ static const struct v4l2_subdev_video_ops thp7312_video_ops = { static const struct v4l2_subdev_pad_ops thp7312_pad_ops = { .enum_mbus_code = thp7312_enum_mbus_code, - .init_cfg = thp7312_init_cfg, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = thp7312_set_fmt, .enum_frame_size = thp7312_enum_frame_size, @@ -888,6 +887,10 @@ static const struct v4l2_subdev_ops thp7312_subdev_ops = { .pad = &thp7312_pad_ops, }; +static const struct v4l2_subdev_internal_ops thp7312_internal_ops = { + .init_state = thp7312_init_state, +}; + /* ----------------------------------------------------------------------------- * V4L2 Control Operations */ @@ -2106,6 +2109,7 @@ static int thp7312_probe(struct i2c_client *client) return thp7312_register_flash_mode(thp7312); v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops); + thp7312->sd.internal_ops = &thp7312_internal_ops; thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; thp7312->pad.flags = MEDIA_PAD_FL_SOURCE; thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 76a92bfb6fde..9fc586cfdcd8 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1209,8 +1209,8 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd, /**************************************************************************** V4L2 subdev pad ops ****************************************************************************/ -static int tvp5150_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int tvp5150_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct tvp5150 *decoder = to_tvp5150(sd); v4l2_std_id std; @@ -1722,7 +1722,6 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { }; static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { - .init_cfg = tvp5150_init_cfg, .enum_mbus_code = tvp5150_enum_mbus_code, .enum_frame_size = tvp5150_enum_frame_size, .set_fmt = tvp5150_fill_fmt, @@ -1741,6 +1740,7 @@ static const struct v4l2_subdev_ops tvp5150_ops = { }; static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { + .init_state = tvp5150_init_state, .registered = tvp5150_registered, .open = tvp5150_open, .close = tvp5150_close, diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 8bf90e2bd856..15b905f66ab7 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -346,8 +346,8 @@ mei_csi_get_pad_format(struct v4l2_subdev *sd, } } -static int mei_csi_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int mei_csi_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mbusformat; struct mei_csi *csi = sd_to_csi(sd); @@ -554,7 +554,6 @@ static const struct v4l2_subdev_video_ops mei_csi_video_ops = { }; static const struct v4l2_subdev_pad_ops mei_csi_pad_ops = { - .init_cfg = mei_csi_init_cfg, .get_fmt = mei_csi_get_fmt, .set_fmt = mei_csi_set_fmt, }; @@ -564,6 +563,10 @@ static const struct v4l2_subdev_ops mei_csi_subdev_ops = { .pad = &mei_csi_pad_ops, }; +static const struct v4l2_subdev_internal_ops mei_csi_internal_ops = { + .init_state = mei_csi_init_state, +}; + static const struct media_entity_operations mei_csi_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -747,6 +750,7 @@ static int mei_csi_probe(struct mei_cl_device *cldev, csi->subdev.dev = &cldev->dev; v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops); + csi->subdev.internal_ops = &mei_csi_internal_ops; v4l2_set_subdevdata(&csi->subdev, csi); csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 0171ea7b834d..fead5426830e 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -418,8 +418,8 @@ static int csi2rx_set_fmt(struct v4l2_subdev *subdev, return 0; } -static int csi2rx_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *state) +static int csi2rx_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) { struct v4l2_subdev_format format = { .pad = CSI2RX_PAD_SINK, @@ -441,7 +441,6 @@ static int csi2rx_init_cfg(struct v4l2_subdev *subdev, static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { .get_fmt = v4l2_subdev_get_fmt, .set_fmt = csi2rx_set_fmt, - .init_cfg = csi2rx_init_cfg, }; static const struct v4l2_subdev_video_ops csi2rx_video_ops = { @@ -453,6 +452,10 @@ static const struct v4l2_subdev_ops csi2rx_subdev_ops = { .pad = &csi2rx_pad_ops, }; +static const struct v4l2_subdev_internal_ops csi2rx_internal_ops = { + .init_state = csi2rx_init_state, +}; + static const struct media_entity_operations csi2rx_media_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -663,6 +666,7 @@ static int csi2rx_probe(struct platform_device *pdev) csi2rx->subdev.owner = THIS_MODULE; csi2rx->subdev.dev = &pdev->dev; v4l2_subdev_init(&csi2rx->subdev, &csi2rx_subdev_ops); + csi2rx->subdev.internal_ops = &csi2rx_internal_ops; v4l2_set_subdevdata(&csi2rx->subdev, &pdev->dev); snprintf(csi2rx->subdev.name, sizeof(csi2rx->subdev.name), "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c index 87a2d092aad2..fee73260bb1e 100644 --- a/drivers/media/platform/microchip/microchip-csi2dc.c +++ b/drivers/media/platform/microchip/microchip-csi2dc.c @@ -435,8 +435,8 @@ static int csi2dc_s_stream(struct v4l2_subdev *csi2dc_sd, int enable) return ret; } -static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd, - struct v4l2_subdev_state *sd_state) +static int csi2dc_init_state(struct v4l2_subdev *csi2dc_sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, 0); @@ -461,7 +461,6 @@ static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = { .enum_mbus_code = csi2dc_enum_mbus_code, .set_fmt = csi2dc_set_fmt, .get_fmt = csi2dc_get_fmt, - .init_cfg = csi2dc_init_cfg, }; static const struct v4l2_subdev_video_ops csi2dc_video_ops = { @@ -473,6 +472,10 @@ static const struct v4l2_subdev_ops csi2dc_subdev_ops = { .video = &csi2dc_video_ops, }; +static const struct v4l2_subdev_internal_ops csi2dc_internal_ops = { + .init_state = csi2dc_init_state, +}; + static int csi2dc_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_connection *asd) @@ -677,6 +680,7 @@ static int csi2dc_probe(struct platform_device *pdev) } v4l2_subdev_init(&csi2dc->csi2dc_sd, &csi2dc_subdev_ops); + csi2dc->csi2dc_sd.internal_ops = &csi2dc_internal_ops; csi2dc->csi2dc_sd.owner = THIS_MODULE; csi2dc->csi2dc_sd.dev = dev; diff --git a/drivers/media/platform/microchip/microchip-isc-scaler.c b/drivers/media/platform/microchip/microchip-isc-scaler.c index 58dffbc9fbcb..e83463543e21 100644 --- a/drivers/media/platform/microchip/microchip-isc-scaler.c +++ b/drivers/media/platform/microchip/microchip-isc-scaler.c @@ -145,8 +145,8 @@ static int isc_scaler_g_sel(struct v4l2_subdev *sd, return 0; } -static int isc_scaler_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int isc_scaler_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state, 0); @@ -170,7 +170,6 @@ static const struct v4l2_subdev_pad_ops isc_scaler_pad_ops = { .set_fmt = isc_scaler_set_fmt, .get_fmt = isc_scaler_get_fmt, .get_selection = isc_scaler_g_sel, - .init_cfg = isc_scaler_init_cfg, }; static const struct media_entity_operations isc_scaler_entity_ops = { @@ -181,11 +180,16 @@ static const struct v4l2_subdev_ops xisc_scaler_subdev_ops = { .pad = &isc_scaler_pad_ops, }; +static const struct v4l2_subdev_internal_ops isc_scaler_internal_ops = { + .init_state = isc_scaler_init_state, +}; + int isc_scaler_init(struct isc_device *isc) { int ret; v4l2_subdev_init(&isc->scaler_sd, &xisc_scaler_subdev_ops); + isc->scaler_sd.internal_ops = &isc_scaler_internal_ops; isc->scaler_sd.owner = THIS_MODULE; isc->scaler_sd.dev = isc->dev; diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index a2c748217376..b12e2435ef60 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1122,8 +1122,8 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, return 0; } -static int mipi_csis_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int mipi_csis_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .pad = CSIS_PAD_SINK, @@ -1163,7 +1163,6 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { }; static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { - .init_cfg = mipi_csis_init_cfg, .enum_mbus_code = mipi_csis_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipi_csis_set_fmt, @@ -1176,6 +1175,10 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { .pad = &mipi_csis_pad_ops, }; +static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = { + .init_state = mipi_csis_init_state, +}; + /* ----------------------------------------------------------------------------- * Media entity operations */ @@ -1350,6 +1353,7 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis) int ret; v4l2_subdev_init(sd, &mipi_csis_subdev_ops); + sd->internal_ops = &mipi_csis_internal_ops; sd->owner = THIS_MODULE; snprintf(sd->name, sizeof(sd->name), "csis-%s", dev_name(csis->dev)); diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 1d2464ca59b8..651151da3ab4 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1729,8 +1729,8 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int imx7_csi_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx7_csi_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { const struct imx7_csi_pixfmt *cc; int i; @@ -2006,7 +2006,6 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = { }; static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = { - .init_cfg = imx7_csi_init_cfg, .enum_mbus_code = imx7_csi_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx7_csi_set_fmt, @@ -2019,6 +2018,7 @@ static const struct v4l2_subdev_ops imx7_csi_subdev_ops = { }; static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops = { + .init_state = imx7_csi_init_state, .registered = imx7_csi_registered, .unregistered = imx7_csi_unregistered, }; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c index 9401261eb239..575f17337388 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c @@ -176,8 +176,8 @@ mxc_isi_crossbar_xlate_streams(struct mxc_isi_crossbar *xbar, return sd; } -static int mxc_isi_crossbar_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd); struct v4l2_subdev_krouting routing = { }; @@ -404,7 +404,6 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops mxc_isi_crossbar_subdev_pad_ops = { - .init_cfg = mxc_isi_crossbar_init_cfg, .enum_mbus_code = mxc_isi_crossbar_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mxc_isi_crossbar_set_fmt, @@ -417,6 +416,10 @@ static const struct v4l2_subdev_ops mxc_isi_crossbar_subdev_ops = { .pad = &mxc_isi_crossbar_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops mxc_isi_crossbar_internal_ops = { + .init_state = mxc_isi_crossbar_init_state, +}; + static const struct media_entity_operations mxc_isi_cross_entity_ops = { .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, .link_validate = v4l2_subdev_link_validate, @@ -438,6 +441,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi) xbar->isi = isi; v4l2_subdev_init(sd, &mxc_isi_crossbar_subdev_ops); + sd->internal_ops = &mxc_isi_crossbar_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; strscpy(sd->name, "crossbar", sizeof(sd->name)); sd->dev = isi->dev; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c index 14c6da392803..d76eb58deb09 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c @@ -341,8 +341,8 @@ mxc_isi_pipe_get_pad_compose(struct mxc_isi_pipe *pipe, return v4l2_subdev_state_get_compose(state, pad); } -static int mxc_isi_pipe_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int mxc_isi_pipe_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct mxc_isi_pipe *pipe = to_isi_pipe(sd); struct v4l2_mbus_framefmt *fmt_source; @@ -682,7 +682,6 @@ static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops mxc_isi_pipe_subdev_pad_ops = { - .init_cfg = mxc_isi_pipe_init_cfg, .enum_mbus_code = mxc_isi_pipe_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mxc_isi_pipe_set_fmt, @@ -694,6 +693,10 @@ static const struct v4l2_subdev_ops mxc_isi_pipe_subdev_ops = { .pad = &mxc_isi_pipe_subdev_pad_ops, }; +static const struct v4l2_subdev_internal_ops mxc_isi_pipe_internal_ops = { + .init_state = mxc_isi_pipe_init_state, +}; + /* ----------------------------------------------------------------------------- * IRQ handling */ @@ -767,6 +770,7 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id) sd = &pipe->sd; v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops); + sd->internal_ops = &mxc_isi_pipe_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "mxc_isi.%d", pipe->id); sd->dev = isi->dev; diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index 02a4c546a90a..ba2e81f24965 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -437,8 +437,8 @@ static int imx8mq_mipi_csi_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int imx8mq_mipi_csi_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx8mq_mipi_csi_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; @@ -535,7 +535,6 @@ static const struct v4l2_subdev_video_ops imx8mq_mipi_csi_video_ops = { }; static const struct v4l2_subdev_pad_ops imx8mq_mipi_csi_pad_ops = { - .init_cfg = imx8mq_mipi_csi_init_cfg, .enum_mbus_code = imx8mq_mipi_csi_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx8mq_mipi_csi_set_fmt, @@ -546,6 +545,10 @@ static const struct v4l2_subdev_ops imx8mq_mipi_csi_subdev_ops = { .pad = &imx8mq_mipi_csi_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx8mq_mipi_csi_internal_ops = { + .init_state = imx8mq_mipi_csi_init_state, +}; + /* ----------------------------------------------------------------------------- * Media entity operations */ @@ -760,6 +763,7 @@ static int imx8mq_mipi_csi_subdev_init(struct csi_state *state) int ret; v4l2_subdev_init(sd, &imx8mq_mipi_csi_subdev_ops); + sd->internal_ops = &imx8mq_mipi_csi_internal_ops; sd->owner = THIS_MODULE; snprintf(sd->name, sizeof(sd->name), "%s %s", MIPI_CSI2_SUBDEV_NAME, dev_name(state->dev)); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index 04e61e783045..d20f4eff93a4 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -530,8 +530,8 @@ static int rzg2l_csi2_set_format(struct v4l2_subdev *sd, return 0; } -static int rzg2l_csi2_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int rzg2l_csi2_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .pad = RZG2L_CSI2_SINK, }; @@ -582,7 +582,6 @@ static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = { static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = { .enum_mbus_code = rzg2l_csi2_enum_mbus_code, - .init_cfg = rzg2l_csi2_init_config, .enum_frame_size = rzg2l_csi2_enum_frame_size, .set_fmt = rzg2l_csi2_set_format, .get_fmt = v4l2_subdev_get_fmt, @@ -593,6 +592,10 @@ static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = { .pad = &rzg2l_csi2_pad_ops, }; +static const struct v4l2_subdev_internal_ops rzg2l_csi2_internal_ops = { + .init_state = rzg2l_csi2_init_state, +}; + /* ----------------------------------------------------------------------------- * Async handling and registration of subdevices and links. */ @@ -777,6 +780,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev) csi2->subdev.dev = &pdev->dev; v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops); + csi2->subdev.internal_ops = &rzg2l_csi2_internal_ops; v4l2_set_subdevdata(&csi2->subdev, &pdev->dev); snprintf(csi2->subdev.name, sizeof(csi2->subdev.name), "csi-%s", dev_name(&pdev->dev)); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c index 17a59dfc8363..9f351a05893e 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c @@ -168,8 +168,8 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int rzg2l_cru_ip_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int rzg2l_cru_ip_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_subdev_format fmt = { .pad = RZG2L_CRU_IP_SINK, }; @@ -192,7 +192,6 @@ static const struct v4l2_subdev_video_ops rzg2l_cru_ip_video_ops = { static const struct v4l2_subdev_pad_ops rzg2l_cru_ip_pad_ops = { .enum_mbus_code = rzg2l_cru_ip_enum_mbus_code, .enum_frame_size = rzg2l_cru_ip_enum_frame_size, - .init_cfg = rzg2l_cru_ip_init_config, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rzg2l_cru_ip_set_format, }; @@ -202,6 +201,10 @@ static const struct v4l2_subdev_ops rzg2l_cru_ip_subdev_ops = { .pad = &rzg2l_cru_ip_pad_ops, }; +static const struct v4l2_subdev_internal_ops rzg2l_cru_ip_internal_ops = { + .init_state = rzg2l_cru_ip_init_state, +}; + static const struct media_entity_operations rzg2l_cru_ip_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -213,6 +216,7 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru) ip->subdev.dev = cru->dev; v4l2_subdev_init(&ip->subdev, &rzg2l_cru_ip_subdev_ops); + ip->subdev.internal_ops = &rzg2l_cru_ip_internal_ops; v4l2_set_subdevdata(&ip->subdev, cru); snprintf(ip->subdev.name, sizeof(ip->subdev.name), "cru-ip-%s", dev_name(cru->dev)); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c index 758525a03289..a8535c6e2c46 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c @@ -264,7 +264,6 @@ static int brx_set_selection(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops brx_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = brx_enum_mbus_code, .enum_frame_size = brx_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c index 50a5c0dc0e86..625776a9bda4 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c @@ -155,7 +155,6 @@ static int clu_set_format(struct v4l2_subdev *subdev, */ static const struct v4l2_subdev_pad_ops clu_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = clu_enum_mbus_code, .enum_frame_size = clu_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 0280b8ff7ba9..0a5a7f9cc870 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -170,33 +170,6 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity, } } -/* - * vsp1_entity_init_cfg - Initialize formats on all pads - * @subdev: V4L2 subdevice - * @sd_state: V4L2 subdev state - * - * Initialize all pad formats with default values in the given subdev state. - * This function can be used as a handler for the subdev pad::init_cfg - * operation. - */ -int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) -{ - unsigned int pad; - - for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { - struct v4l2_subdev_format format = { - .pad = pad, - .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY - : V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format); - } - - return 0; -} - /* * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler * @subdev: V4L2 subdevice @@ -424,6 +397,29 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, return ret; } +static int vsp1_entity_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) +{ + unsigned int pad; + + /* Initialize all pad formats with default values. */ + for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { + struct v4l2_subdev_format format = { + .pad = pad, + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY + : V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format); + } + + return 0; +} + +static const struct v4l2_subdev_internal_ops vsp1_entity_internal_ops = { + .init_state = vsp1_entity_init_state, +}; + /* ----------------------------------------------------------------------------- * Media Operations */ @@ -658,6 +654,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, /* Initialize the V4L2 subdev. */ subdev = &entity->subdev; v4l2_subdev_init(subdev, ops); + subdev->internal_ops = &vsp1_entity_internal_ops; subdev->entity.function = function; subdev->entity.ops = &vsp1->media_ops; @@ -666,7 +663,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, snprintf(subdev->name, sizeof(subdev->name), "%s %s", dev_name(vsp1->dev), name); - vsp1_entity_init_cfg(subdev, NULL); + vsp1_entity_init_state(subdev, NULL); /* * Allocate the subdev state to store formats and selection diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h index 8c737cadee81..735f32dde4b5 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h @@ -146,8 +146,6 @@ struct v4l2_rect * vsp1_entity_get_pad_selection(struct vsp1_entity *entity, struct v4l2_subdev_state *sd_state, unsigned int pad, unsigned int target); -int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state); void vsp1_entity_route_setup(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c index 6342ac7bdf54..bc1299c29ac9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c @@ -113,7 +113,6 @@ static int hsit_set_format(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops hsit_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = hsit_enum_mbus_code, .enum_frame_size = hsit_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c index 75c24df41a7a..b1d21a54837b 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c @@ -68,7 +68,6 @@ static int lif_set_format(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops lif_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lif_enum_mbus_code, .enum_frame_size = lif_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c index ac6802a325f5..451d24ab0b56 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c @@ -131,7 +131,6 @@ static int lut_set_format(struct v4l2_subdev *subdev, */ static const struct v4l2_subdev_pad_ops lut_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lut_enum_mbus_code, .enum_frame_size = lut_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c index cb3ab351b7de..09fb6ffa14e2 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c @@ -240,7 +240,6 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = vsp1_rwpf_enum_mbus_code, .enum_frame_size = vsp1_rwpf_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c index 2dd6f8575614..11e008aa9f20 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c @@ -252,7 +252,6 @@ static int sru_set_format(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops sru_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = sru_enum_mbus_code, .enum_frame_size = sru_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c index 59ff4ae46cea..d89f1197b86c 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c @@ -239,7 +239,6 @@ static int uds_set_format(struct v4l2_subdev *subdev, */ static const struct v4l2_subdev_pad_ops uds_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = uds_enum_mbus_code, .enum_frame_size = uds_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uif.c b/drivers/media/platform/renesas/vsp1/vsp1_uif.c index d84d10f35090..f66936a28a2a 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_uif.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_uif.c @@ -174,7 +174,6 @@ static int uif_set_selection(struct v4l2_subdev *subdev, */ static const struct v4l2_subdev_pad_ops uif_pad_ops = { - .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = uif_enum_mbus_code, .enum_frame_size = uif_enum_frame_size, .get_fmt = vsp1_subdev_get_pad_format, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index 47f4353a1784..e6642a2167ef 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -270,8 +270,8 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; } -static int rkisp1_csi_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int rkisp1_csi_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; @@ -405,7 +405,6 @@ static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = { static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = { .enum_mbus_code = rkisp1_csi_enum_mbus_code, - .init_cfg = rkisp1_csi_init_config, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_csi_set_fmt, }; @@ -415,6 +414,10 @@ static const struct v4l2_subdev_ops rkisp1_csi_ops = { .pad = &rkisp1_csi_pad_ops, }; +static const struct v4l2_subdev_internal_ops rkisp1_csi_internal_ops = { + .init_state = rkisp1_csi_init_state, +}; + int rkisp1_csi_register(struct rkisp1_device *rkisp1) { struct rkisp1_csi *csi = &rkisp1->csi; @@ -426,6 +429,7 @@ int rkisp1_csi_register(struct rkisp1_device *rkisp1) sd = &csi->sd; v4l2_subdev_init(sd, &rkisp1_csi_ops); + sd->internal_ops = &rkisp1_csi_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->entity.ops = &rkisp1_csi_media_ops; sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 96353648c032..ca6703bfd27b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -409,8 +409,8 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int rkisp1_isp_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int rkisp1_isp_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop, *src_crop; @@ -769,7 +769,6 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { .enum_frame_size = rkisp1_isp_enum_frame_size, .get_selection = rkisp1_isp_get_selection, .set_selection = rkisp1_isp_set_selection, - .init_cfg = rkisp1_isp_init_config, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_isp_set_fmt, .link_validate = v4l2_subdev_link_validate_default, @@ -880,6 +879,10 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = { .pad = &rkisp1_isp_pad_ops, }; +static const struct v4l2_subdev_internal_ops rkisp1_isp_internal_ops = { + .init_state = rkisp1_isp_init_state, +}; + int rkisp1_isp_register(struct rkisp1_device *rkisp1) { struct rkisp1_isp *isp = &rkisp1->isp; @@ -890,6 +893,7 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) isp->rkisp1 = rkisp1; v4l2_subdev_init(sd, &rkisp1_isp_ops); + sd->internal_ops = &rkisp1_isp_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; sd->entity.ops = &rkisp1_isp_media_ops; sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 9f94b9f60c35..f7af360dcb28 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -366,8 +366,8 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, return ret; } -static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int rkisp1_rsz_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; @@ -605,7 +605,6 @@ static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { .enum_mbus_code = rkisp1_rsz_enum_mbus_code, .get_selection = rkisp1_rsz_get_selection, .set_selection = rkisp1_rsz_set_selection, - .init_cfg = rkisp1_rsz_init_config, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_rsz_set_fmt, .link_validate = v4l2_subdev_link_validate_default, @@ -652,6 +651,10 @@ static const struct v4l2_subdev_ops rkisp1_rsz_ops = { .pad = &rkisp1_rsz_pad_ops, }; +static const struct v4l2_subdev_internal_ops rkisp1_rsz_internal_ops = { + .init_state = rkisp1_rsz_init_state, +}; + static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) { if (!rsz->rkisp1) @@ -681,6 +684,7 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) } v4l2_subdev_init(sd, &rkisp1_rsz_ops); + sd->internal_ops = &rkisp1_rsz_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->entity.ops = &rkisp1_rsz_media_ops; sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index ad13d447d483..097a3a08ef7d 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -211,6 +211,7 @@ static int sun4i_csi_probe(struct platform_device *pdev) /* Initialize subdev */ v4l2_subdev_init(subdev, &sun4i_csi_subdev_ops); + subdev->internal_ops = &sun4i_csi_subdev_internal_ops; subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; subdev->owner = THIS_MODULE; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h index 8eeed87bfb13..4e0c2df45d4d 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h @@ -89,6 +89,7 @@ enum csi_subdev_pads { }; extern const struct v4l2_subdev_ops sun4i_csi_subdev_ops; +extern const struct v4l2_subdev_internal_ops sun4i_csi_subdev_internal_ops; struct sun4i_csi_format { u32 mbus; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c index c37bb1d76ef6..744197b0fccb 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -266,8 +266,8 @@ static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = { .xfer_func = V4L2_XFER_FUNC_DEFAULT, }; -static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state) +static int sun4i_csi_subdev_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *fmt; @@ -334,7 +334,6 @@ sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev, static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = { .link_validate = v4l2_subdev_link_validate_default, - .init_cfg = sun4i_csi_subdev_init_cfg, .get_fmt = sun4i_csi_subdev_get_fmt, .set_fmt = sun4i_csi_subdev_set_fmt, .enum_mbus_code = sun4i_csi_subdev_enum_mbus_code, @@ -344,6 +343,10 @@ const struct v4l2_subdev_ops sun4i_csi_subdev_ops = { .pad = &sun4i_csi_subdev_pad_ops, }; +const struct v4l2_subdev_internal_ops sun4i_csi_subdev_internal_ops = { + .init_state = sun4i_csi_subdev_init_state, +}; + int sun4i_csi_v4l2_register(struct sun4i_csi *csi) { struct video_device *vdev = &csi->vdev; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index d57481feee05..d006d9dd0170 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -501,8 +501,8 @@ sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *state) +static int sun6i_csi_bridge_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) { struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK; @@ -581,7 +581,6 @@ static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops sun6i_csi_bridge_pad_ops = { - .init_cfg = sun6i_csi_bridge_init_cfg, .enum_mbus_code = sun6i_csi_bridge_enum_mbus_code, .get_fmt = sun6i_csi_bridge_get_fmt, .set_fmt = sun6i_csi_bridge_set_fmt, @@ -592,6 +591,10 @@ static const struct v4l2_subdev_ops sun6i_csi_bridge_subdev_ops = { .pad = &sun6i_csi_bridge_pad_ops, }; +static const struct v4l2_subdev_internal_ops sun6i_csi_bridge_internal_ops = { + .init_state = sun6i_csi_bridge_init_state, +}; + /* Media Entity */ static const struct media_entity_operations sun6i_csi_bridge_entity_ops = { @@ -782,6 +785,7 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) /* V4L2 Subdev */ v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops); + subdev->internal_ops = &sun6i_csi_bridge_internal_ops; strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name)); subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; subdev->owner = THIS_MODULE; diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index d2c9f5d20496..f9d4dc45b490 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -305,8 +305,8 @@ sun6i_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *state) +static int sun6i_mipi_csi2_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) { struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK; @@ -385,7 +385,6 @@ static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_pad_ops = { - .init_cfg = sun6i_mipi_csi2_init_cfg, .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, .get_fmt = sun6i_mipi_csi2_get_fmt, .set_fmt = sun6i_mipi_csi2_set_fmt, @@ -396,6 +395,10 @@ static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { .pad = &sun6i_mipi_csi2_pad_ops, }; +static const struct v4l2_subdev_internal_ops sun6i_mipi_csi2_internal_ops = { + .init_state = sun6i_mipi_csi2_init_state, +}; + /* Media Entity */ static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { @@ -504,6 +507,7 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev) /* V4L2 Subdev */ v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); + subdev->internal_ops = &sun6i_mipi_csi2_internal_ops; strscpy(subdev->name, SUN6I_MIPI_CSI2_NAME, sizeof(subdev->name)); subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; subdev->owner = THIS_MODULE; diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index d6275954af98..4a5698eb12b7 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -338,8 +338,8 @@ sun8i_a83t_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *state) +static int sun8i_a83t_mipi_csi2_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) { struct sun8i_a83t_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); @@ -422,7 +422,6 @@ static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_pad_ops = { - .init_cfg = sun8i_a83t_mipi_csi2_init_cfg, .enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code, .get_fmt = sun8i_a83t_mipi_csi2_get_fmt, .set_fmt = sun8i_a83t_mipi_csi2_set_fmt, @@ -433,6 +432,10 @@ static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = { .pad = &sun8i_a83t_mipi_csi2_pad_ops, }; +static const struct v4l2_subdev_internal_ops sun8i_a83t_mipi_csi2_internal_ops = { + .init_state = sun8i_a83t_mipi_csi2_init_state, +}; + /* Media Entity */ static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = { @@ -542,6 +545,7 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) /* V4L2 Subdev */ v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops); + subdev->internal_ops = &sun8i_a83t_mipi_csi2_internal_ops; strscpy(subdev->name, SUN8I_A83T_MIPI_CSI2_NAME, sizeof(subdev->name)); subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; subdev->owner = THIS_MODULE; diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index 61433744c6c4..4afc2ad00330 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -721,8 +721,8 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, return 0; } -static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int cal_camerarx_sd_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { struct v4l2_subdev_format format = { .which = state ? V4L2_SUBDEV_FORMAT_TRY @@ -782,7 +782,6 @@ static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = { }; static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = { - .init_cfg = cal_camerarx_sd_init_cfg, .enum_mbus_code = cal_camerarx_sd_enum_mbus_code, .enum_frame_size = cal_camerarx_sd_enum_frame_size, .get_fmt = v4l2_subdev_get_fmt, @@ -795,6 +794,10 @@ static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = { .pad = &cal_camerarx_pad_ops, }; +static const struct v4l2_subdev_internal_ops cal_camerarx_internal_ops = { + .init_state = cal_camerarx_sd_init_state, +}; + static struct media_entity_operations cal_camerarx_media_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -846,6 +849,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, /* Initialize the V4L2 subdev and media entity. */ sd = &phy->subdev; v4l2_subdev_init(sd, &cal_camerarx_subdev_ops); + sd->internal_ops = &cal_camerarx_internal_ops; sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance); diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 06a28531ed02..31e9e92e723e 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -282,8 +282,8 @@ static int video_mux_set_format(struct v4l2_subdev *sd, return 0; } -static int video_mux_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int video_mux_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); struct v4l2_mbus_framefmt *mbusformat; @@ -302,7 +302,6 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops video_mux_pad_ops = { - .init_cfg = video_mux_init_cfg, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = video_mux_set_format, }; @@ -312,6 +311,10 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = { .video = &video_mux_subdev_video_ops, }; +static const struct v4l2_subdev_internal_ops video_mux_internal_ops = { + .init_state = video_mux_init_state, +}; + static int video_mux_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_connection *asd) @@ -400,6 +403,7 @@ static int video_mux_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vmux); v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops); + vmux->subdev.internal_ops = &video_mux_internal_ops; snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np); vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; vmux->subdev.dev = dev; diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index bca8ec94ee35..f953d5474ae0 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -661,8 +661,8 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss, } } -static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int xcsi2rxss_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); struct v4l2_mbus_framefmt *format; @@ -780,7 +780,6 @@ static const struct v4l2_subdev_video_ops xcsi2rxss_video_ops = { }; static const struct v4l2_subdev_pad_ops xcsi2rxss_pad_ops = { - .init_cfg = xcsi2rxss_init_cfg, .get_fmt = xcsi2rxss_get_format, .set_fmt = xcsi2rxss_set_format, .enum_mbus_code = xcsi2rxss_enum_mbus_code, @@ -793,6 +792,10 @@ static const struct v4l2_subdev_ops xcsi2rxss_ops = { .pad = &xcsi2rxss_pad_ops }; +static const struct v4l2_subdev_internal_ops xcsi2rxss_internal_ops = { + .init_state = xcsi2rxss_init_state, +}; + static int xcsi2rxss_parse_of(struct xcsi2rxss_state *xcsi2rxss) { struct device *dev = xcsi2rxss->dev; @@ -970,6 +973,7 @@ static int xcsi2rxss_probe(struct platform_device *pdev) /* Initialize V4L2 subdevice and media entity */ subdev = &xcsi2rxss->subdev; v4l2_subdev_init(subdev, &xcsi2rxss_ops); + subdev->internal_ops = &xcsi2rxss_internal_ops; subdev->dev = dev; strscpy(subdev->name, dev_name(dev), sizeof(subdev->name)); subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c index a2fb32c97c84..d72ed086e00b 100644 --- a/drivers/media/test-drivers/vimc/vimc-debayer.c +++ b/drivers/media/test-drivers/vimc/vimc-debayer.c @@ -150,8 +150,8 @@ static bool vimc_debayer_src_code_is_valid(u32 code) return false; } -static int vimc_debayer_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_debayer_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; @@ -307,7 +307,6 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = { - .init_cfg = vimc_debayer_init_cfg, .enum_mbus_code = vimc_debayer_enum_mbus_code, .enum_frame_size = vimc_debayer_enum_frame_size, .get_fmt = vimc_debayer_get_fmt, @@ -395,6 +394,10 @@ static const struct v4l2_subdev_ops vimc_debayer_ops = { .video = &vimc_debayer_video_ops, }; +static const struct v4l2_subdev_internal_ops vimc_debayer_internal_ops = { + .init_state = vimc_debayer_init_state, +}; + static unsigned int vimc_debayer_get_val(const u8 *bytes, const unsigned int n_bytes) { @@ -595,6 +598,8 @@ static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc, if (ret) goto err_free_hdl; + vdebayer->sd.internal_ops = &vimc_debayer_internal_ops; + vdebayer->ved.process_frame = vimc_debayer_process_frame; vdebayer->ved.dev = vimc->mdev.dev; vdebayer->mean_win_size = vimc_debayer_ctrl_mean_win_size.def; diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c index f6592a789f1e..afe13d6af321 100644 --- a/drivers/media/test-drivers/vimc/vimc-scaler.c +++ b/drivers/media/test-drivers/vimc/vimc-scaler.c @@ -70,8 +70,8 @@ vimc_scaler_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) return r; } -static int vimc_scaler_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_scaler_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf; struct v4l2_rect *r; @@ -292,7 +292,6 @@ static int vimc_scaler_set_selection(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = { - .init_cfg = vimc_scaler_init_cfg, .enum_mbus_code = vimc_scaler_enum_mbus_code, .enum_frame_size = vimc_scaler_enum_frame_size, .get_fmt = vimc_scaler_get_fmt, @@ -347,6 +346,10 @@ static const struct v4l2_subdev_ops vimc_scaler_ops = { .video = &vimc_scaler_video_ops, }; +static const struct v4l2_subdev_internal_ops vimc_scaler_internal_ops = { + .init_state = vimc_scaler_init_state, +}; + static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vscaler, const u8 *const sink_frame) { @@ -424,6 +427,8 @@ static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc, return ERR_PTR(ret); } + vscaler->sd.internal_ops = &vimc_scaler_internal_ops; + vscaler->ved.process_frame = vimc_scaler_process_frame; vscaler->ved.dev = vimc->mdev.dev; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 676ab503f0ca..5e34b1aed95e 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -41,8 +41,8 @@ static const struct v4l2_mbus_framefmt fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -static int vimc_sensor_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_sensor_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { unsigned int i; @@ -183,7 +183,6 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, } static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = { - .init_cfg = vimc_sensor_init_cfg, .enum_mbus_code = vimc_sensor_enum_mbus_code, .enum_frame_size = vimc_sensor_enum_frame_size, .get_fmt = vimc_sensor_get_fmt, @@ -294,6 +293,10 @@ static const struct v4l2_subdev_ops vimc_sensor_ops = { .video = &vimc_sensor_video_ops, }; +static const struct v4l2_subdev_internal_ops vimc_sensor_internal_ops = { + .init_state = vimc_sensor_init_state, +}; + static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl) { struct vimc_sensor_device *vsensor = @@ -429,6 +432,8 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, if (ret) goto err_free_tpg; + vsensor->sd.internal_ops = &vimc_sensor_internal_ops; + vsensor->ved.process_frame = vimc_sensor_process_frame; vsensor->ved.dev = vimc->mdev.dev; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 985873b7981e..4fbefe4cd714 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -1460,16 +1460,18 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, } } - /* - * There can be no race at this point, but we lock the state anyway to - * satisfy lockdep checks. - */ - v4l2_subdev_lock_state(state); - ret = v4l2_subdev_call(sd, pad, init_cfg, state); - v4l2_subdev_unlock_state(state); + if (sd->internal_ops && sd->internal_ops->init_state) { + /* + * There can be no race at this point, but we lock the state + * anyway to satisfy lockdep checks. + */ + v4l2_subdev_lock_state(state); + ret = sd->internal_ops->init_state(sd, state); + v4l2_subdev_unlock_state(state); - if (ret < 0 && ret != -ENOIOCTLCMD) - goto err; + if (ret) + goto err; + } return state; diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index 61d69f19657e..8bd9be49cc08 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -448,7 +448,6 @@ static int prp_registered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops prp_pad_ops = { - .init_cfg = imx_media_init_cfg, .enum_mbus_code = prp_enum_mbus_code, .get_fmt = prp_get_fmt, .set_fmt = prp_set_fmt, @@ -472,6 +471,7 @@ static const struct v4l2_subdev_ops prp_subdev_ops = { }; static const struct v4l2_subdev_internal_ops prp_internal_ops = { + .init_state = imx_media_init_state, .registered = prp_registered, }; diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index ec73c901079e..04878f07eeba 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -1296,7 +1296,6 @@ static void prp_unregistered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops prp_pad_ops = { - .init_cfg = imx_media_init_cfg, .enum_mbus_code = prp_enum_mbus_code, .enum_frame_size = prp_enum_frame_size, .get_fmt = prp_get_fmt, @@ -1320,6 +1319,7 @@ static const struct v4l2_subdev_ops prp_subdev_ops = { }; static const struct v4l2_subdev_internal_ops prp_internal_ops = { + .init_state = imx_media_init_state, .registered = prp_registered, .unregistered = prp_unregistered, }; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 33902f5daf80..2fc94011fe4d 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1866,7 +1866,6 @@ static const struct v4l2_subdev_video_ops csi_video_ops = { }; static const struct v4l2_subdev_pad_ops csi_pad_ops = { - .init_cfg = imx_media_init_cfg, .enum_mbus_code = csi_enum_mbus_code, .enum_frame_size = csi_enum_frame_size, .enum_frame_interval = csi_enum_frame_interval, @@ -1884,6 +1883,7 @@ static const struct v4l2_subdev_ops csi_subdev_ops = { }; static const struct v4l2_subdev_internal_ops csi_internal_ops = { + .init_state = imx_media_init_state, .registered = csi_registered, .unregistered = csi_unregistered, }; diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index ec4349ab48cd..1b5af8945e6b 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -426,10 +426,10 @@ EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt); /* * Initializes the TRY format to the ACTIVE format on all pads - * of a subdev. Can be used as the .init_cfg pad operation. + * of a subdev. Can be used as the .init_state internal operation. */ -int imx_media_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +int imx_media_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf_try; unsigned int pad; @@ -451,7 +451,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd, return 0; } -EXPORT_SYMBOL_GPL(imx_media_init_cfg); +EXPORT_SYMBOL_GPL(imx_media_init_state); /* * Default the colorspace in tryfmt to SRGB if set to an unsupported diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 792bca1d2d25..810b38ea3ab9 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -882,7 +882,6 @@ static void vdic_unregistered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops vdic_pad_ops = { - .init_cfg = imx_media_init_cfg, .enum_mbus_code = vdic_enum_mbus_code, .get_fmt = vdic_get_fmt, .set_fmt = vdic_set_fmt, @@ -906,6 +905,7 @@ static const struct v4l2_subdev_ops vdic_subdev_ops = { }; static const struct v4l2_subdev_internal_ops vdic_internal_ops = { + .init_state = imx_media_init_state, .registered = vdic_registered, .unregistered = vdic_unregistered, }; diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 2640cd34dce2..f095d9134fee 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -192,8 +192,8 @@ static inline int imx_media_enum_ipu_formats(u32 *code, u32 index, int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, u32 width, u32 height, u32 code, u32 field, const struct imx_media_pixfmt **cc); -int imx_media_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state); +int imx_media_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state); void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt, bool ic_route); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index 6906220ee89e..0d8b42061623 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -619,7 +619,6 @@ static const struct v4l2_subdev_video_ops csi2_video_ops = { }; static const struct v4l2_subdev_pad_ops csi2_pad_ops = { - .init_cfg = imx_media_init_cfg, .get_fmt = csi2_get_fmt, .set_fmt = csi2_set_fmt, }; @@ -631,6 +630,7 @@ static const struct v4l2_subdev_ops csi2_subdev_ops = { }; static const struct v4l2_subdev_internal_ops csi2_internal_ops = { + .init_state = imx_media_init_state, .registered = csi2_registered, }; diff --git a/drivers/staging/media/starfive/camss/stf-isp.c b/drivers/staging/media/starfive/camss/stf-isp.c index 893dbd8cddc8..6bffffb2b20c 100644 --- a/drivers/staging/media/starfive/camss/stf-isp.c +++ b/drivers/staging/media/starfive/camss/stf-isp.c @@ -311,7 +311,6 @@ static const struct v4l2_subdev_video_ops isp_video_ops = { }; static const struct v4l2_subdev_pad_ops isp_pad_ops = { - .init_cfg = isp_init_formats, .enum_mbus_code = isp_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = isp_set_format, @@ -324,6 +323,10 @@ static const struct v4l2_subdev_ops isp_v4l2_ops = { .pad = &isp_pad_ops, }; +static const struct v4l2_subdev_internal_ops isp_internal_ops = { + .init_state = isp_init_formats, +}; + static const struct media_entity_operations isp_media_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -335,6 +338,7 @@ int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev) int ret; v4l2_subdev_init(sd, &isp_v4l2_ops); + sd->internal_ops = &isp_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, ARRAY_SIZE(sd->name), "stf_isp"); v4l2_set_subdevdata(sd, isp_dev); diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c index b2ce0d4fae95..46a334b602f1 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c @@ -256,8 +256,8 @@ sun6i_isp_proc_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_isp_proc_init_cfg(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *state) +static int sun6i_isp_proc_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) { struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev); unsigned int pad = SUN6I_ISP_PROC_PAD_SINK_CSI; @@ -336,7 +336,6 @@ static int sun6i_isp_proc_set_fmt(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops sun6i_isp_proc_pad_ops = { - .init_cfg = sun6i_isp_proc_init_cfg, .enum_mbus_code = sun6i_isp_proc_enum_mbus_code, .get_fmt = sun6i_isp_proc_get_fmt, .set_fmt = sun6i_isp_proc_set_fmt, @@ -347,6 +346,10 @@ static const struct v4l2_subdev_ops sun6i_isp_proc_subdev_ops = { .pad = &sun6i_isp_proc_pad_ops, }; +static const struct v4l2_subdev_internal_ops sun6i_isp_proc_internal_ops = { + .init_state = sun6i_isp_proc_init_state, +}; + /* Media Entity */ static const struct media_entity_operations sun6i_isp_proc_entity_ops = { @@ -501,6 +504,7 @@ int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev) /* V4L2 Subdev */ v4l2_subdev_init(subdev, &sun6i_isp_proc_subdev_ops); + subdev->internal_ops = &sun6i_isp_proc_internal_ops; strscpy(subdev->name, SUN6I_ISP_PROC_NAME, sizeof(subdev->name)); subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; subdev->owner = THIS_MODULE; diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2a438e516095..8b08f6640dee 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -771,7 +771,6 @@ struct v4l2_subdev_state { /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * - * @init_cfg: initialize the subdev state to default values * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE() ioctl handler * code. * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE() ioctl handler @@ -836,8 +835,6 @@ struct v4l2_subdev_state { * directly, use v4l2_subdev_disable_streams() instead. */ struct v4l2_subdev_pad_ops { - int (*init_cfg)(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state); int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code); @@ -914,6 +911,8 @@ struct v4l2_subdev_ops { /** * struct v4l2_subdev_internal_ops - V4L2 subdev internal ops * + * @init_state: initialize the subdev state to default values + * * @registered: called when this subdev is registered. When called the v4l2_dev * field is set to the correct v4l2_device. * @@ -939,6 +938,8 @@ struct v4l2_subdev_ops { * these ops. */ struct v4l2_subdev_internal_ops { + int (*init_state)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state); int (*registered)(struct v4l2_subdev *sd); void (*unregistered)(struct v4l2_subdev *sd); int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); From c9e3e84963a79bc50791ad99bcd06920ee2f28c7 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 31 Oct 2023 20:22:37 +0200 Subject: [PATCH 2334/7721] media: v4l: fwnode: Parse MIPI DisCo for Imaging properties Parse MIPI DisCo for Imaging properties "mipi-img-lens-focus" and "mipi-img-flash-leds" for VCMs and flash LEDs. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-fwnode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 7f181fbbb140..89c7192148df 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1179,7 +1179,9 @@ v4l2_async_nf_parse_fwnode_sensor(struct device *dev, static const char * const led_props[] = { "led" }; static const struct v4l2_fwnode_int_props props[] = { { "flash-leds", led_props, ARRAY_SIZE(led_props) }, - { "lens-focus", NULL, 0 }, + { "mipi-img-flash-leds", }, + { "lens-focus", }, + { "mipi-img-lens-focus", }, }; unsigned int i; From b33cb0cbe2893b96ecbfa16254407153f4b55d16 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 13 Nov 2023 15:57:30 +0100 Subject: [PATCH 2335/7721] media: i2c: st-mipid02: correct format propagation Use a copy of the struct v4l2_subdev_format when propagating format from the sink to source pad in order to avoid impacting the sink format returned to the application. Thanks to Jacopo Mondi for pointing the issue. Fixes: 6c01e6f3f27b ("media: st-mipid02: Propagate format from sink to source pad") Signed-off-by: Alain Volmat Cc: stable@vger.kernel.org Reviewed-by: Jacopo Mondi Reviewed-by: Daniel Scally Reviewed-by: Benjamin Mugnier Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index b08a249b5fdd..914f915749a8 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -769,6 +769,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct v4l2_subdev_format source_fmt; struct v4l2_mbus_framefmt *fmt; format->format.code = get_fmt_code(format->format.code); @@ -780,8 +781,12 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, *fmt = format->format; - /* Propagate the format change to the source pad */ - mipid02_set_fmt_source(sd, sd_state, format); + /* + * Propagate the format change to the source pad, taking + * care not to update the format pointer given back to user + */ + source_fmt = *format; + mipid02_set_fmt_source(sd, sd_state, &source_fmt); } static int mipid02_set_fmt(struct v4l2_subdev *sd, From 046ee0e2a4d602268a49be0d77df8c85559015e3 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:49 +0100 Subject: [PATCH 2336/7721] media: i2c: st-mipid02: add usage of v4l2_get_link_freq Use the helper v4l2_get_link_freq instead of performing manually check of the LINK_FREQ or PIXELRATE ctrls. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 64 +++++++++------------------------- 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 914f915749a8..b699f0b4efe7 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -367,64 +367,34 @@ static int mipid02_detect(struct mipid02_dev *bridge) return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); } -static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, - struct v4l2_subdev *subdev) -{ - struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; - struct v4l2_ctrl *ctrl; - int ret; - - ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); - if (!ctrl) - return 0; - qm.index = v4l2_ctrl_g_ctrl(ctrl); - - ret = v4l2_querymenu(subdev->ctrl_handler, &qm); - if (ret) - return 0; - - return qm.value; -} - -static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, - struct v4l2_subdev *subdev) -{ - struct v4l2_fwnode_endpoint *ep = &bridge->rx; - struct v4l2_ctrl *ctrl; - u32 pixel_clock; - u32 bpp = bpp_from_code(bridge->fmt.code); - - ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); - if (!ctrl) - return 0; - pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); - - return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); -} - /* * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency - * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel + * will be retrieve from connected device via v4l2_get_link_freq, bit per pixel * and number of lanes. */ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) { struct i2c_client *client = bridge->i2c_client; struct v4l2_subdev *subdev = bridge->s_subdev; - u32 link_freq; + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + u32 bpp = bpp_from_code(bridge->fmt.code); + /* + * clk_lane_reg1 requires 4 times the unit interval time, and bitrate + * is twice the link frequency, hence ui_4 = 1000000000 * 4 / 2 + */ + u64 ui_4 = 2000000000; + s64 link_freq; - link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); - if (!link_freq) { - link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, - subdev); - if (!link_freq) { - dev_err(&client->dev, "Failed to get link frequency"); - return -EINVAL; - } + link_freq = v4l2_get_link_freq(subdev->ctrl_handler, bpp, + 2 * ep->bus.mipi_csi2.num_data_lanes); + if (link_freq < 0) { + dev_err(&client->dev, "Failed to get link frequency"); + return -EINVAL; } - dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); - bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; + dev_dbg(&client->dev, "detect link_freq = %lld Hz", link_freq); + do_div(ui_4, link_freq); + bridge->r.clk_lane_reg1 |= ui_4 << 2; return 0; } From c26eb0f323419abc9ca94d2c56546511e23692bb Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:50 +0100 Subject: [PATCH 2337/7721] media: i2c: st-mipid02: don't keep track of streaming status As explained in the following series, subdev do not have to keep track of their streaming status: https://lore.kernel.org/linux-media/20230914181704.4811-1-laurent.pinchart@ideasonboard.com/ Signed-off-by: Alain Volmat [Sakari Ailus: Remove redundant local variable in mipid02_set_fmt.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index b699f0b4efe7..0c5c5b848b0b 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -112,7 +112,6 @@ struct mipid02_dev { } r; /* lock to protect all members below */ struct mutex lock; - bool streaming; struct v4l2_mbus_framefmt fmt; }; @@ -629,22 +628,13 @@ static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = bridge->i2c_client; int ret = 0; - dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, - enable, bridge->streaming); - mutex_lock(&bridge->lock); - - if (bridge->streaming == enable) - goto out; + dev_dbg(&client->dev, "%s : requested %d\n", __func__, enable); ret = enable ? mipid02_stream_enable(bridge) : mipid02_stream_disable(bridge); - if (!ret) - bridge->streaming = enable; - -out: - dev_dbg(&client->dev, "%s current now = %d / %d", __func__, - bridge->streaming, ret); - mutex_unlock(&bridge->lock); + if (ret) + dev_err(&client->dev, "failed to stream %s (%d)\n", + enable ? "enable" : "disable", ret); return ret; } @@ -765,7 +755,6 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd, { struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; - int ret = 0; dev_dbg(&client->dev, "%s for %d", __func__, format->pad); @@ -777,20 +766,14 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd, mutex_lock(&bridge->lock); - if (bridge->streaming) { - ret = -EBUSY; - goto error; - } - if (format->pad == MIPID02_SOURCE) mipid02_set_fmt_source(sd, sd_state, format); else mipid02_set_fmt_sink(sd, sd_state, format); -error: mutex_unlock(&bridge->lock); - return ret; + return 0; } static const struct v4l2_subdev_video_ops mipid02_video_ops = { From 6223dafa3c9111d17c546b4ca5bbe26057f913ce Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:51 +0100 Subject: [PATCH 2338/7721] media: i2c: st-mipid02: use cci_* helpers for register access. Use cci_read & cci_write functions for accessing registers. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/st-mipid02.c | 169 +++++++++------------------------ 2 files changed, 47 insertions(+), 123 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index e77444f64257..aae05142e191 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1458,6 +1458,7 @@ config VIDEO_ST_MIPID02 depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API + select V4L2_CCI_I2C select V4L2_FWNODE help Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 0c5c5b848b0b..bad98aa8d269 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -17,24 +17,25 @@ #include #include #include +#include #include #include #include #include -#define MIPID02_CLK_LANE_WR_REG1 0x01 -#define MIPID02_CLK_LANE_REG1 0x02 -#define MIPID02_CLK_LANE_REG3 0x04 -#define MIPID02_DATA_LANE0_REG1 0x05 -#define MIPID02_DATA_LANE0_REG2 0x06 -#define MIPID02_DATA_LANE1_REG1 0x09 -#define MIPID02_DATA_LANE1_REG2 0x0a -#define MIPID02_MODE_REG1 0x14 -#define MIPID02_MODE_REG2 0x15 -#define MIPID02_DATA_ID_RREG 0x17 -#define MIPID02_DATA_SELECTION_CTRL 0x19 -#define MIPID02_PIX_WIDTH_CTRL 0x1e -#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f +#define MIPID02_CLK_LANE_WR_REG1 CCI_REG8(0x01) +#define MIPID02_CLK_LANE_REG1 CCI_REG8(0x02) +#define MIPID02_CLK_LANE_REG3 CCI_REG8(0x04) +#define MIPID02_DATA_LANE0_REG1 CCI_REG8(0x05) +#define MIPID02_DATA_LANE0_REG2 CCI_REG8(0x06) +#define MIPID02_DATA_LANE1_REG1 CCI_REG8(0x09) +#define MIPID02_DATA_LANE1_REG2 CCI_REG8(0x0a) +#define MIPID02_MODE_REG1 CCI_REG8(0x14) +#define MIPID02_MODE_REG2 CCI_REG8(0x15) +#define MIPID02_DATA_ID_RREG CCI_REG8(0x17) +#define MIPID02_DATA_SELECTION_CTRL CCI_REG8(0x19) +#define MIPID02_PIX_WIDTH_CTRL CCI_REG8(0x1e) +#define MIPID02_PIX_WIDTH_CTRL_EMB CCI_REG8(0x1f) /* Bits definition for MIPID02_CLK_LANE_REG1 */ #define CLK_ENABLE BIT(0) @@ -88,6 +89,7 @@ struct mipid02_dev { struct i2c_client *i2c_client; struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; struct v4l2_subdev sd; + struct regmap *regmap; struct media_pad pad[MIPID02_PAD_NB]; struct clk *xclk; struct gpio_desc *reset_gpio; @@ -237,62 +239,6 @@ static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) return container_of(sd, struct mipid02_dev, sd); } -static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) -{ - struct i2c_client *client = bridge->i2c_client; - struct i2c_msg msg[2]; - u8 buf[2]; - int ret; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - - msg[0].addr = client->addr; - msg[0].flags = client->flags; - msg[0].buf = buf; - msg[0].len = sizeof(buf); - - msg[1].addr = client->addr; - msg[1].flags = client->flags | I2C_M_RD; - msg[1].buf = val; - msg[1].len = 1; - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", - __func__, client->addr, reg, ret); - return ret; - } - - return 0; -} - -static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) -{ - struct i2c_client *client = bridge->i2c_client; - struct i2c_msg msg; - u8 buf[3]; - int ret; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - buf[2] = val; - - msg.addr = client->addr; - msg.flags = client->flags; - msg.buf = buf; - msg.len = sizeof(buf); - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", - __func__, reg, ret); - return ret; - } - - return 0; -} - static int mipid02_get_regulators(struct mipid02_dev *bridge) { unsigned int i; @@ -357,13 +303,13 @@ static void mipid02_set_power_off(struct mipid02_dev *bridge) static int mipid02_detect(struct mipid02_dev *bridge) { - u8 reg; + u64 reg; /* * There is no version registers. Just try to read register * MIPID02_CLK_LANE_WR_REG1. */ - return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); + return cci_read(bridge->regmap, MIPID02_CLK_LANE_WR_REG1, ®, NULL); } /* @@ -524,13 +470,9 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge) goto error; /* Disable all lanes */ - ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); + cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); if (ret) goto error; error: @@ -561,51 +503,26 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge) goto error; /* write mipi registers */ - ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, - bridge->r.clk_lane_reg1); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, - bridge->r.data_lane0_reg1); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, - DATA_MIPI_CSI); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, - bridge->r.data_lane1_reg1); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, - DATA_MIPI_CSI); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, - MODE_NO_BYPASS | bridge->r.mode_reg1); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, - bridge->r.mode_reg2); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, - bridge->r.data_id_rreg); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, - bridge->r.data_selection_ctrl); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, - bridge->r.pix_width_ctrl); - if (ret) - goto error; - ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, - bridge->r.pix_width_ctrl_emb); + cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, + bridge->r.clk_lane_reg1, &ret); + cci_write(bridge->regmap, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, + bridge->r.data_lane0_reg1, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG2, DATA_MIPI_CSI, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, + bridge->r.data_lane1_reg1, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG2, DATA_MIPI_CSI, &ret); + cci_write(bridge->regmap, MIPID02_MODE_REG1, + MODE_NO_BYPASS | bridge->r.mode_reg1, &ret); + cci_write(bridge->regmap, MIPID02_MODE_REG2, bridge->r.mode_reg2, &ret); + cci_write(bridge->regmap, MIPID02_DATA_ID_RREG, bridge->r.data_id_rreg, + &ret); + cci_write(bridge->regmap, MIPID02_DATA_SELECTION_CTRL, + bridge->r.data_selection_ctrl, &ret); + cci_write(bridge->regmap, MIPID02_PIX_WIDTH_CTRL, + bridge->r.pix_width_ctrl, &ret); + cci_write(bridge->regmap, MIPID02_PIX_WIDTH_CTRL_EMB, + bridge->r.pix_width_ctrl_emb, &ret); if (ret) goto error; @@ -983,6 +900,12 @@ static int mipid02_probe(struct i2c_client *client) return ret; } + /* Initialise the regmap for further cci access */ + bridge->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(bridge->regmap)) + return dev_err_probe(dev, PTR_ERR(bridge->regmap), + "failed to get cci regmap\n"); + mutex_init(&bridge->lock); bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; From 04d170b288b3404924282086b065a01f3b8d0795 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:52 +0100 Subject: [PATCH 2339/7721] media: i2c: st-mipid02: use active state to store pad formats Store formats information within pad allowing to simplify further more the driver (mutex / format store within the driver structure no more necessary). Signed-off-by: Alain Volmat [Sakari Ailus: Address init_cfg -> init_state API change.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 209 +++++++++++++-------------------- 1 file changed, 79 insertions(+), 130 deletions(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index bad98aa8d269..2cc07b3ed0da 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -112,9 +112,6 @@ struct mipid02_dev { u8 pix_width_ctrl; u8 pix_width_ctrl_emb; } r; - /* lock to protect all members below */ - struct mutex lock; - struct v4l2_mbus_framefmt fmt; }; static int bpp_from_code(__u32 code) @@ -192,18 +189,6 @@ static u8 data_type_from_code(__u32 code) } } -static void init_format(struct v4l2_mbus_framefmt *fmt) -{ - fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); - fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); - fmt->width = 640; - fmt->height = 480; -} - static __u32 get_fmt_code(__u32 code) { unsigned int i; @@ -317,12 +302,13 @@ static int mipid02_detect(struct mipid02_dev *bridge) * will be retrieve from connected device via v4l2_get_link_freq, bit per pixel * and number of lanes. */ -static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) +static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge, + struct v4l2_mbus_framefmt *fmt) { struct i2c_client *client = bridge->i2c_client; struct v4l2_subdev *subdev = bridge->s_subdev; struct v4l2_fwnode_endpoint *ep = &bridge->rx; - u32 bpp = bpp_from_code(bridge->fmt.code); + u32 bpp = bpp_from_code(fmt->code); /* * clk_lane_reg1 requires 4 times the unit interval time, and bitrate * is twice the link frequency, hence ui_4 = 1000000000 * 4 / 2 @@ -394,7 +380,8 @@ static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, return 0; } -static int mipid02_configure_from_rx(struct mipid02_dev *bridge) +static int mipid02_configure_from_rx(struct mipid02_dev *bridge, + struct v4l2_mbus_framefmt *fmt) { struct v4l2_fwnode_endpoint *ep = &bridge->rx; bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; @@ -419,7 +406,7 @@ static int mipid02_configure_from_rx(struct mipid02_dev *bridge) bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; bridge->r.mode_reg1 |= (nb - 1) << 1; - return mipid02_configure_from_rx_speed(bridge); + return mipid02_configure_from_rx_speed(bridge, fmt); } static int mipid02_configure_from_tx(struct mipid02_dev *bridge) @@ -439,16 +426,17 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge) return 0; } -static int mipid02_configure_from_code(struct mipid02_dev *bridge) +static int mipid02_configure_from_code(struct mipid02_dev *bridge, + struct v4l2_mbus_framefmt *fmt) { u8 data_type; bridge->r.data_id_rreg = 0; - if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { + if (fmt->code != MEDIA_BUS_FMT_JPEG_1X8) { bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; - data_type = data_type_from_code(bridge->fmt.code); + data_type = data_type_from_code(fmt->code); if (!data_type) return -EINVAL; bridge->r.data_id_rreg = data_type; @@ -485,23 +473,31 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge) static int mipid02_stream_enable(struct mipid02_dev *bridge) { struct i2c_client *client = bridge->i2c_client; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; int ret = -EINVAL; if (!bridge->s_subdev) goto error; memset(&bridge->r, 0, sizeof(bridge->r)); + + state = v4l2_subdev_lock_and_get_active_state(&bridge->sd); + fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0); + /* build registers content */ - ret = mipid02_configure_from_rx(bridge); + ret = mipid02_configure_from_rx(bridge, fmt); if (ret) goto error; ret = mipid02_configure_from_tx(bridge); if (ret) goto error; - ret = mipid02_configure_from_code(bridge); + ret = mipid02_configure_from_code(bridge, fmt); if (ret) goto error; + v4l2_subdev_unlock_state(state); + /* write mipi registers */ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, bridge->r.clk_lane_reg1, &ret); @@ -556,11 +552,32 @@ static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) return ret; } +static const struct v4l2_mbus_framefmt default_fmt = { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, + .width = 640, + .height = 480, +}; + +static int mipid02_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + *v4l2_subdev_state_get_format(state, MIPID02_SINK_0) = default_fmt; + /* MIPID02_SINK_1 isn't supported yet */ + *v4l2_subdev_state_get_format(state, MIPID02_SOURCE) = default_fmt; + + return 0; +} + static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct v4l2_mbus_framefmt *sink_fmt; int ret = 0; switch (code->pad) { @@ -571,10 +588,13 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, code->code = mipid02_supported_fmt_codes[code->index]; break; case MIPID02_SOURCE: - if (code->index == 0) - code->code = serial_to_parallel_code(bridge->fmt.code); - else + if (code->index == 0) { + sink_fmt = v4l2_subdev_state_get_format(sd_state, + MIPID02_SINK_0); + code->code = serial_to_parallel_code(sink_fmt->code); + } else { ret = -EINVAL; + } break; default: ret = -EINVAL; @@ -583,112 +603,36 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, return ret; } -static int mipid02_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mbus_fmt = &format->format; - struct mipid02_dev *bridge = to_mipid02_dev(sd); - struct i2c_client *client = bridge->i2c_client; - struct v4l2_mbus_framefmt *fmt; - - dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); - - if (format->pad >= MIPID02_PAD_NB) - return -EINVAL; - /* second CSI-2 pad not yet supported */ - if (format->pad == MIPID02_SINK_1) - return -EINVAL; - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_state_get_format(sd_state, format->pad); - else - fmt = &bridge->fmt; - - mutex_lock(&bridge->lock); - - *mbus_fmt = *fmt; - /* code may need to be converted for source */ - if (format->pad == MIPID02_SOURCE) - mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); - - mutex_unlock(&bridge->lock); - - return 0; -} - -static void mipid02_set_fmt_source(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct mipid02_dev *bridge = to_mipid02_dev(sd); - - /* source pad mirror sink pad */ - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - format->format = bridge->fmt; - else - format->format = *v4l2_subdev_state_get_format(sd_state, - MIPID02_SINK_0); - - /* but code may need to be converted */ - format->format.code = serial_to_parallel_code(format->format.code); - - /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ - if (format->which != V4L2_SUBDEV_FORMAT_TRY) - return; - - *v4l2_subdev_state_get_format(sd_state, MIPID02_SOURCE) = - format->format; -} - -static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct mipid02_dev *bridge = to_mipid02_dev(sd); - struct v4l2_subdev_format source_fmt; - struct v4l2_mbus_framefmt *fmt; - - format->format.code = get_fmt_code(format->format.code); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_state_get_format(sd_state, format->pad); - else - fmt = &bridge->fmt; - - *fmt = format->format; - - /* - * Propagate the format change to the source pad, taking - * care not to update the format pointer given back to user - */ - source_fmt = *format; - mipid02_set_fmt_source(sd, sd_state, &source_fmt); -} - static int mipid02_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) + struct v4l2_subdev_format *fmt) { struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; + struct v4l2_mbus_framefmt *pad_fmt; - dev_dbg(&client->dev, "%s for %d", __func__, format->pad); + dev_dbg(&client->dev, "%s for %d", __func__, fmt->pad); - if (format->pad >= MIPID02_PAD_NB) - return -EINVAL; /* second CSI-2 pad not yet supported */ - if (format->pad == MIPID02_SINK_1) + if (fmt->pad == MIPID02_SINK_1) return -EINVAL; - mutex_lock(&bridge->lock); + pad_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); + fmt->format.code = get_fmt_code(fmt->format.code); - if (format->pad == MIPID02_SOURCE) - mipid02_set_fmt_source(sd, sd_state, format); - else - mipid02_set_fmt_sink(sd, sd_state, format); + /* code may need to be converted */ + if (fmt->pad == MIPID02_SOURCE) + fmt->format.code = serial_to_parallel_code(fmt->format.code); - mutex_unlock(&bridge->lock); + *pad_fmt = fmt->format; + + /* Propagate the format to the source pad in case of sink pad update */ + if (fmt->pad == MIPID02_SINK_0) { + pad_fmt = v4l2_subdev_state_get_format(sd_state, + MIPID02_SOURCE); + *pad_fmt = fmt->format; + pad_fmt->code = serial_to_parallel_code(fmt->format.code); + } return 0; } @@ -699,7 +643,7 @@ static const struct v4l2_subdev_video_ops mipid02_video_ops = { static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { .enum_mbus_code = mipid02_enum_mbus_code, - .get_fmt = mipid02_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipid02_set_fmt, }; @@ -708,6 +652,10 @@ static const struct v4l2_subdev_ops mipid02_subdev_ops = { .pad = &mipid02_pad_ops, }; +static const struct v4l2_subdev_internal_ops mipid02_subdev_internal_ops = { + .init_state = mipid02_init_state, +}; + static const struct media_entity_operations mipid02_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; @@ -867,8 +815,6 @@ static int mipid02_probe(struct i2c_client *client) if (!bridge) return -ENOMEM; - init_format(&bridge->fmt); - bridge->i2c_client = client; v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); @@ -906,9 +852,9 @@ static int mipid02_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(bridge->regmap), "failed to get cci regmap\n"); - mutex_init(&bridge->lock); bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + bridge->sd.internal_ops = &mipid02_subdev_internal_ops; bridge->sd.entity.ops = &mipid02_subdev_entity_ops; bridge->pad[0].flags = MEDIA_PAD_FL_SINK; bridge->pad[1].flags = MEDIA_PAD_FL_SINK; @@ -917,7 +863,13 @@ static int mipid02_probe(struct i2c_client *client) bridge->pad); if (ret) { dev_err(&client->dev, "pads init failed %d", ret); - goto mutex_cleanup; + return ret; + } + + ret = v4l2_subdev_init_finalize(&bridge->sd); + if (ret < 0) { + dev_err(dev, "subdev init error: %d\n", ret); + goto entity_cleanup; } /* enable clock, power and reset device if available */ @@ -961,8 +913,6 @@ static int mipid02_probe(struct i2c_client *client) mipid02_set_power_off(bridge); entity_cleanup: media_entity_cleanup(&bridge->sd.entity); -mutex_cleanup: - mutex_destroy(&bridge->lock); return ret; } @@ -977,7 +927,6 @@ static void mipid02_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&bridge->sd); mipid02_set_power_off(bridge); media_entity_cleanup(&bridge->sd.entity); - mutex_destroy(&bridge->lock); } static const struct of_device_id mipid02_dt_ids[] = { From 290f9b3406d748eda5a20562df4a2c45a9c1b0dd Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:53 +0100 Subject: [PATCH 2340/7721] media: i2c: st-mipid02: use mipi-csi macro for data-type Use MIPI data-type macros. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 2cc07b3ed0da..2811997e9161 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -158,17 +159,17 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: - return 0x2a; + return MIPI_CSI2_DT_RAW8; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: - return 0x2b; + return MIPI_CSI2_DT_RAW10; case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: - return 0x2c; + return MIPI_CSI2_DT_RAW12; case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: @@ -177,13 +178,13 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: - return 0x1e; + return MIPI_CSI2_DT_YUV422_8B; case MEDIA_BUS_FMT_BGR888_1X24: - return 0x24; + return MIPI_CSI2_DT_RGB888; case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_RGB565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: - return 0x22; + return MIPI_CSI2_DT_RGB565; default: return 0; } From 248b6248eaea4ee62f9c54feafff204ee2b98d66 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:54 +0100 Subject: [PATCH 2341/7721] media: i2c: st-mipid02: removal of unused link_frequency variable link_frequency variable within struct mipid02_dev seems to have never been used hence remove it. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 2811997e9161..0015cd32457c 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -96,7 +96,6 @@ struct mipid02_dev { struct gpio_desc *reset_gpio; /* endpoints info */ struct v4l2_fwnode_endpoint rx; - u64 link_frequency; struct v4l2_fwnode_endpoint tx; /* remote source */ struct v4l2_async_notifier notifier; From 2cc0f07718f244d128bd8f38ad4e41f5c67222c1 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sat, 25 Nov 2023 19:20:55 +0100 Subject: [PATCH 2342/7721] media: i2c: st-mipid02: add Y8 format support Add support of MEDIA_BUS_FMT_Y8_1X8. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-mipid02.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 0015cd32457c..f250640729ca 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -70,7 +70,7 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_JPEG_1X8 + MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8 }; /* regulator supplies */ @@ -121,6 +121,7 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: return 8; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: @@ -158,6 +159,7 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: return MIPI_CSI2_DT_RAW8; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: From b4c4f8b81694f16b602e5e7b6d308d5ec69e6207 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 27 Nov 2023 14:51:11 +0100 Subject: [PATCH 2343/7721] media: i2c: st-vgxy61: Add V4L2_SUBDEV_FL_HAS_EVENTS and subscribe hooks Any V4L2 subdevice that implements controls and declares V4L2_SUBDEV_FL_HAS_DEVNODE should also declare V4L2_SUBDEV_FL_HAS_EVENTS and implement subscribe_event and unsubscribe_event hooks. With that done, v4l2-compliance testing is now ok. Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-vgxy61.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 98d8975dcd67..c85fd580dcf4 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1464,6 +1465,11 @@ static int vgxy61_init_controls(struct vgxy61_dev *sensor) return ret; } +static const struct v4l2_subdev_core_ops vgxy61_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops vgxy61_video_ops = { .s_stream = vgxy61_s_stream, }; @@ -1477,6 +1483,7 @@ static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = { }; static const struct v4l2_subdev_ops vgxy61_subdev_ops = { + .core = &vgxy61_core_ops, .video = &vgxy61_video_ops, .pad = &vgxy61_pad_ops, }; @@ -1846,7 +1853,8 @@ static int vgxy61_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&sensor->sd, client, &vgxy61_subdev_ops); sensor->sd.internal_ops = &vgxy61_internal_ops; - sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->sd.entity.ops = &vgxy61_subdev_entity_ops; sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; From 998ba665e16e651715d80d1795044c02fa4eb35d Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 27 Nov 2023 14:51:12 +0100 Subject: [PATCH 2344/7721] media: i2c: st-vgxy61: add v4l2_fwnode ctrls parse and addition Allow parsing of the v4l2_fwnode properties from the DT and addition of those properties (such as orientation, rotation). Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/st-vgxy61.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index c85fd580dcf4..e4d37a197724 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -1403,6 +1403,7 @@ static int vgxy61_init_controls(struct vgxy61_dev *sensor) const struct v4l2_ctrl_ops *ops = &vgxy61_ctrl_ops; struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler; const struct vgxy61_mode_info *cur_mode = sensor->current_mode; + struct v4l2_fwnode_device_properties props; struct v4l2_ctrl *ctrl; int ret; @@ -1457,6 +1458,14 @@ static int vgxy61_init_controls(struct vgxy61_dev *sensor) goto free_ctrls; } + ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props); + if (ret) + goto free_ctrls; + + ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); + if (ret) + goto free_ctrls; + sensor->sd.ctrl_handler = hdl; return 0; From c7387b069e602b710471bddc627c15473b32f8d1 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 27 Nov 2023 18:08:15 +0100 Subject: [PATCH 2345/7721] dt-bindings: media: add bindings for stm32 dcmipp Add the yaml binding for the ST Microelectronics STM32 DCMIPP (Digital Camera Memory Interface Pixel Processor) Signed-off-by: Alain Volmat Reviewed-by: Conor Dooley Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/st,stm32-dcmipp.yaml | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml new file mode 100644 index 000000000000..87731f3ce7bd --- /dev/null +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/st,stm32-dcmipp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 DCMIPP Digital Camera Memory Interface Pixel Processor + +maintainers: + - Hugues Fruchet + - Alain Volmat + +properties: + compatible: + const: st,stm32mp13-dcmipp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + DCMIPP supports a single port node with parallel bus. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + default: 5 + + bus-width: + enum: [8, 10, 12, 14] + default: 8 + + pclk-sample: true + hsync-active: true + vsync-active: true + + required: + - pclk-sample + +required: + - compatible + - reg + - interrupts + - clocks + - resets + - port + +additionalProperties: false + +examples: + - | + #include + #include + #include + dcmipp@5a000000 { + compatible = "st,stm32mp13-dcmipp"; + reg = <0x5a000000 0x400>; + interrupts = ; + resets = <&rcc DCMIPP_R>; + clocks = <&rcc DCMIPP_K>; + + port { + endpoint { + remote-endpoint = <&mipid02_2>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <0>; + }; + }; + }; + +... From fa0f34188a916bf1c0e1299405d394431bf5a3b2 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 27 Nov 2023 18:08:16 +0100 Subject: [PATCH 2346/7721] media: MAINTAINERS: add entry for STM32 DCMIPP driver Add the entry related to the STM32 MEDIA DCMIPP driver within the MAINTAINERS file. Add myself as maintainer of the DCMI driver as well. Signed-off-by: Alain Volmat Reviewed-by: Laurent Pinchart [Sakari Ailus: Arrange files alphabetically.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b8f0bb78700d..0d96db7e1a9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13440,13 +13440,16 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/dvb-frontends/stv6111* -MEDIA DRIVERS FOR STM32 - DCMI +MEDIA DRIVERS FOR STM32 - DCMI / DCMIPP M: Hugues Fruchet +M: Alain Volmat L: linux-media@vger.kernel.org S: Supported T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +F: Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml F: drivers/media/platform/st/stm32/stm32-dcmi.c +F: drivers/media/platform/st/stm32/stm32-dcmipp/* MEDIA INPUT INFRASTRUCTURE (V4L/DVB) M: Mauro Carvalho Chehab From 28e0f37722965fa150af31d82101c95fd21aef60 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 27 Nov 2023 18:08:17 +0100 Subject: [PATCH 2347/7721] media: stm32-dcmipp: STM32 DCMIPP camera interface driver This V4L2 subdev driver enables Digital Camera Memory Interface Pixel Processor(DCMIPP) of STMicroelectronics STM32 SoC series. Signed-off-by: Hugues Fruchet Signed-off-by: Alain Volmat Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil [hverkuil: remove empty line at end of source] --- drivers/media/platform/st/stm32/Kconfig | 16 + drivers/media/platform/st/stm32/Makefile | 1 + .../platform/st/stm32/stm32-dcmipp/Makefile | 4 + .../st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 956 ++++++++++++++++++ .../st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 565 +++++++++++ .../st/stm32/stm32-dcmipp/dcmipp-common.c | 111 ++ .../st/stm32/stm32-dcmipp/dcmipp-common.h | 217 ++++ .../st/stm32/stm32-dcmipp/dcmipp-core.c | 604 +++++++++++ .../st/stm32/stm32-dcmipp/dcmipp-parallel.c | 440 ++++++++ 9 files changed, 2914 insertions(+) create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/Makefile create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c create mode 100644 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c diff --git a/drivers/media/platform/st/stm32/Kconfig b/drivers/media/platform/st/stm32/Kconfig index b22dd4753496..9df9a2a17728 100644 --- a/drivers/media/platform/st/stm32/Kconfig +++ b/drivers/media/platform/st/stm32/Kconfig @@ -16,6 +16,22 @@ config VIDEO_STM32_DCMI To compile this driver as a module, choose M here: the module will be called stm32-dcmi. +config VIDEO_STM32_DCMIPP + tristate "STM32 Digital Camera Memory Interface Pixel Processor (DCMIPP) support" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_STM32 || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This module makes the STM32 Digital Camera Memory Interface + Pixel Processor (DCMIPP) available as a v4l2 device. + + To compile this driver as a module, choose M here: the module + will be called stm32-dcmipp. + # Mem2mem drivers config VIDEO_STM32_DMA2D tristate "STM32 Chrom-Art Accelerator (DMA2D)" diff --git a/drivers/media/platform/st/stm32/Makefile b/drivers/media/platform/st/stm32/Makefile index 896ef98a73ab..7ed8297b9b19 100644 --- a/drivers/media/platform/st/stm32/Makefile +++ b/drivers/media/platform/st/stm32/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32-dcmi.o +obj-$(CONFIG_VIDEO_STM32_DCMIPP) += stm32-dcmipp/ stm32-dma2d-objs := dma2d/dma2d.o dma2d/dma2d-hw.o obj-$(CONFIG_VIDEO_STM32_DMA2D) += stm32-dma2d.o diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile b/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile new file mode 100644 index 000000000000..8920d9388a21 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +stm32-dcmipp-y := dcmipp-core.o dcmipp-common.o dcmipp-parallel.o dcmipp-byteproc.o dcmipp-bytecap.o + +obj-$(CONFIG_VIDEO_STM32_DCMIPP) += stm32-dcmipp.o diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c new file mode 100644 index 000000000000..0cd9b088bd97 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c @@ -0,0 +1,956 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include + +#include "dcmipp-common.h" + +#define DCMIPP_PRSR 0x1f8 +#define DCMIPP_CMIER 0x3f0 +#define DCMIPP_CMIER_P0FRAMEIE BIT(9) +#define DCMIPP_CMIER_P0VSYNCIE BIT(10) +#define DCMIPP_CMIER_P0OVRIE BIT(15) +#define DCMIPP_CMIER_P0ALL (DCMIPP_CMIER_P0VSYNCIE |\ + DCMIPP_CMIER_P0FRAMEIE |\ + DCMIPP_CMIER_P0OVRIE) +#define DCMIPP_CMSR1 0x3f4 +#define DCMIPP_CMSR2 0x3f8 +#define DCMIPP_CMSR2_P0FRAMEF BIT(9) +#define DCMIPP_CMSR2_P0VSYNCF BIT(10) +#define DCMIPP_CMSR2_P0OVRF BIT(15) +#define DCMIPP_CMFCR 0x3fc +#define DCMIPP_P0FSCR 0x404 +#define DCMIPP_P0FSCR_PIPEN BIT(31) +#define DCMIPP_P0FCTCR 0x500 +#define DCMIPP_P0FCTCR_CPTREQ BIT(3) +#define DCMIPP_P0DCCNTR 0x5b0 +#define DCMIPP_P0DCLMTR 0x5b4 +#define DCMIPP_P0DCLMTR_ENABLE BIT(31) +#define DCMIPP_P0DCLMTR_LIMIT_MASK GENMASK(23, 0) +#define DCMIPP_P0PPM0AR1 0x5c4 +#define DCMIPP_P0SR 0x5f8 +#define DCMIPP_P0SR_CPTACT BIT(23) + +struct dcmipp_bytecap_pix_map { + unsigned int code; + u32 pixelformat; +}; + +#define PIXMAP_MBUS_PFMT(mbus, fmt) \ + { \ + .code = MEDIA_BUS_FMT_##mbus, \ + .pixelformat = V4L2_PIX_FMT_##fmt \ + } + +static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pix_map_list[] = { + PIXMAP_MBUS_PFMT(RGB565_2X8_LE, RGB565), + PIXMAP_MBUS_PFMT(YUYV8_2X8, YUYV), + PIXMAP_MBUS_PFMT(YVYU8_2X8, YVYU), + PIXMAP_MBUS_PFMT(UYVY8_2X8, UYVY), + PIXMAP_MBUS_PFMT(VYUY8_2X8, VYUY), + PIXMAP_MBUS_PFMT(Y8_1X8, GREY), + PIXMAP_MBUS_PFMT(SBGGR8_1X8, SBGGR8), + PIXMAP_MBUS_PFMT(SGBRG8_1X8, SGBRG8), + PIXMAP_MBUS_PFMT(SGRBG8_1X8, SGRBG8), + PIXMAP_MBUS_PFMT(SRGGB8_1X8, SRGGB8), + PIXMAP_MBUS_PFMT(JPEG_1X8, JPEG), +}; + +static const struct dcmipp_bytecap_pix_map * +dcmipp_bytecap_pix_map_by_pixelformat(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) { + if (dcmipp_bytecap_pix_map_list[i].pixelformat == pixelformat) + return &dcmipp_bytecap_pix_map_list[i]; + } + + return NULL; +} + +struct dcmipp_buf { + struct vb2_v4l2_buffer vb; + bool prepared; + dma_addr_t addr; + size_t size; + struct list_head list; +}; + +enum dcmipp_state { + DCMIPP_STOPPED = 0, + DCMIPP_WAIT_FOR_BUFFER, + DCMIPP_RUNNING, +}; + +struct dcmipp_bytecap_device { + struct dcmipp_ent_device ved; + struct video_device vdev; + struct device *dev; + struct v4l2_pix_format format; + struct vb2_queue queue; + struct list_head buffers; + /* + * Protects concurrent calls of buf queue / irq handler + * and buffer handling related variables / lists + */ + spinlock_t irqlock; + /* mutex used as vdev and queue lock */ + struct mutex lock; + u32 sequence; + struct media_pipeline pipe; + struct v4l2_subdev *s_subdev; + + enum dcmipp_state state; + + /* + * DCMIPP driver is handling 2 buffers + * active: buffer into which DCMIPP is currently writing into + * next: buffer given to the DCMIPP and which will become + * automatically active on next VSYNC + */ + struct dcmipp_buf *active, *next; + + void __iomem *regs; + + u32 cmier; + u32 cmsr2; + + struct { + u32 errors; + u32 limit; + u32 overrun; + u32 buffers; + u32 vsync; + u32 frame; + u32 it; + u32 underrun; + u32 nactive; + } count; +}; + +static const struct v4l2_pix_format fmt_default = { + .width = DCMIPP_FMT_WIDTH_DEFAULT, + .height = DCMIPP_FMT_HEIGHT_DEFAULT, + .pixelformat = V4L2_PIX_FMT_RGB565, + .field = V4L2_FIELD_NONE, + .bytesperline = DCMIPP_FMT_WIDTH_DEFAULT * 2, + .sizeimage = DCMIPP_FMT_WIDTH_DEFAULT * DCMIPP_FMT_HEIGHT_DEFAULT * 2, + .colorspace = DCMIPP_COLORSPACE_DEFAULT, + .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, + .quantization = DCMIPP_QUANTIZATION_DEFAULT, + .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, +}; + +static int dcmipp_bytecap_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DCMIPP_PDEV_NAME, sizeof(cap->driver)); + strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); + + return 0; +} + +static int dcmipp_bytecap_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct dcmipp_bytecap_device *vcap = video_drvdata(file); + + f->fmt.pix = vcap->format; + + return 0; +} + +static int dcmipp_bytecap_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct dcmipp_bytecap_device *vcap = video_drvdata(file); + struct v4l2_pix_format *format = &f->fmt.pix; + const struct dcmipp_bytecap_pix_map *vpix; + u32 in_w, in_h; + + /* Don't accept a pixelformat that is not on the table */ + vpix = dcmipp_bytecap_pix_map_by_pixelformat(format->pixelformat); + if (!vpix) + format->pixelformat = fmt_default.pixelformat; + + /* Adjust width & height */ + in_w = format->width; + in_h = format->height; + v4l_bound_align_image(&format->width, DCMIPP_FRAME_MIN_WIDTH, + DCMIPP_FRAME_MAX_WIDTH, 0, &format->height, + DCMIPP_FRAME_MIN_HEIGHT, DCMIPP_FRAME_MAX_HEIGHT, + 0, 0); + if (format->width != in_w || format->height != in_h) + dev_dbg(vcap->dev, "resolution updated: %dx%d -> %dx%d\n", + in_w, in_h, format->width, format->height); + + if (format->pixelformat == V4L2_PIX_FMT_JPEG) { + format->bytesperline = format->width; + format->sizeimage = format->bytesperline * format->height; + } else { + v4l2_fill_pixfmt(format, format->pixelformat, + format->width, format->height); + } + + if (format->field == V4L2_FIELD_ANY) + format->field = fmt_default.field; + + dcmipp_colorimetry_clamp(format); + + return 0; +} + +static int dcmipp_bytecap_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct dcmipp_bytecap_device *vcap = video_drvdata(file); + int ret; + + /* Do not change the format while stream is on */ + if (vb2_is_busy(&vcap->queue)) + return -EBUSY; + + ret = dcmipp_bytecap_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + dev_dbg(vcap->dev, "%s: format update: old:%ux%u (0x%p4cc, %u, %u, %u, %u) new:%ux%d (0x%p4cc, %u, %u, %u, %u)\n", + vcap->vdev.name, + /* old */ + vcap->format.width, vcap->format.height, + &vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, + /* new */ + f->fmt.pix.width, f->fmt.pix.height, + &f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + + return 0; +} + +static int dcmipp_bytecap_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct dcmipp_bytecap_pix_map *vpix; + unsigned int index = f->index; + unsigned int i; + + if (f->mbus_code) { + /* + * If a media bus code is specified, only enumerate formats + * compatible with it. + */ + for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) { + vpix = &dcmipp_bytecap_pix_map_list[i]; + if (vpix->code != f->mbus_code) + continue; + + if (index == 0) + break; + + index--; + } + + if (i == ARRAY_SIZE(dcmipp_bytecap_pix_map_list)) + return -EINVAL; + } else { + /* Otherwise, enumerate all formats. */ + if (f->index >= ARRAY_SIZE(dcmipp_bytecap_pix_map_list)) + return -EINVAL; + + vpix = &dcmipp_bytecap_pix_map_list[f->index]; + } + + f->pixelformat = vpix->pixelformat; + + return 0; +} + +static int dcmipp_bytecap_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct dcmipp_bytecap_pix_map *vpix; + + if (fsize->index) + return -EINVAL; + + /* Only accept code in the pix map table */ + vpix = dcmipp_bytecap_pix_map_by_pixelformat(fsize->pixel_format); + if (!vpix) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = DCMIPP_FRAME_MIN_WIDTH; + fsize->stepwise.max_width = DCMIPP_FRAME_MAX_WIDTH; + fsize->stepwise.min_height = DCMIPP_FRAME_MIN_HEIGHT; + fsize->stepwise.max_height = DCMIPP_FRAME_MAX_HEIGHT; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_file_operations dcmipp_bytecap_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_ioctl_ops dcmipp_bytecap_ioctl_ops = { + .vidioc_querycap = dcmipp_bytecap_querycap, + + .vidioc_g_fmt_vid_cap = dcmipp_bytecap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = dcmipp_bytecap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = dcmipp_bytecap_try_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = dcmipp_bytecap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = dcmipp_bytecap_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static int dcmipp_pipeline_s_stream(struct dcmipp_bytecap_device *vcap, + int state) +{ + struct media_pad *pad; + int ret; + + /* + * Get source subdev - since link is IMMUTABLE, pointer is cached + * within the dcmipp_bytecap_device structure + */ + if (!vcap->s_subdev) { + pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + return -EINVAL; + vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity); + } + + ret = v4l2_subdev_call(vcap->s_subdev, video, s_stream, state); + if (ret < 0) { + dev_err(vcap->dev, "failed to %s streaming (%d)\n", + state ? "start" : "stop", ret); + return ret; + } + + return 0; +} + +static void dcmipp_start_capture(struct dcmipp_bytecap_device *vcap, + struct dcmipp_buf *buf) +{ + /* Set buffer address */ + reg_write(vcap, DCMIPP_P0PPM0AR1, buf->addr); + + /* Set buffer size */ + reg_write(vcap, DCMIPP_P0DCLMTR, DCMIPP_P0DCLMTR_ENABLE | + ((buf->size / 4) & DCMIPP_P0DCLMTR_LIMIT_MASK)); + + /* Capture request */ + reg_set(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ); +} + +static void dcmipp_bytecap_all_buffers_done(struct dcmipp_bytecap_device *vcap, + enum vb2_buffer_state state) +{ + struct dcmipp_buf *buf, *node; + + list_for_each_entry_safe(buf, node, &vcap->buffers, list) { + list_del_init(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } +} + +static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq, + unsigned int count) +{ + struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq); + struct media_entity *entity = &vcap->vdev.entity; + struct dcmipp_buf *buf; + int ret; + + vcap->sequence = 0; + memset(&vcap->count, 0, sizeof(vcap->count)); + + ret = pm_runtime_resume_and_get(vcap->dev); + if (ret < 0) { + dev_err(vcap->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", + __func__, ret); + goto err_buffer_done; + } + + ret = media_pipeline_start(entity->pads, &vcap->pipe); + if (ret) { + dev_dbg(vcap->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", + __func__, ret); + goto err_pm_put; + } + + ret = dcmipp_pipeline_s_stream(vcap, 1); + if (ret) + goto err_media_pipeline_stop; + + spin_lock_irq(&vcap->irqlock); + + /* Enable pipe at the end of programming */ + reg_set(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN); + + /* + * vb2 framework guarantee that we have at least 'min_buffers_needed' + * buffers in the list at this moment + */ + vcap->next = list_first_entry(&vcap->buffers, typeof(*buf), list); + dev_dbg(vcap->dev, "Start with next [%d] %p phy=%pad\n", + vcap->next->vb.vb2_buf.index, vcap->next, &vcap->next->addr); + + dcmipp_start_capture(vcap, vcap->next); + + /* Enable interruptions */ + vcap->cmier |= DCMIPP_CMIER_P0ALL; + reg_set(vcap, DCMIPP_CMIER, vcap->cmier); + + vcap->state = DCMIPP_RUNNING; + + spin_unlock_irq(&vcap->irqlock); + + return 0; + +err_media_pipeline_stop: + media_pipeline_stop(entity->pads); +err_pm_put: + pm_runtime_put(vcap->dev); +err_buffer_done: + spin_lock_irq(&vcap->irqlock); + /* + * Return all buffers to vb2 in QUEUED state. + * This will give ownership back to userspace + */ + dcmipp_bytecap_all_buffers_done(vcap, VB2_BUF_STATE_QUEUED); + vcap->active = NULL; + spin_unlock_irq(&vcap->irqlock); + + return ret; +} + +static void dcmipp_dump_status(struct dcmipp_bytecap_device *vcap) +{ + struct device *dev = vcap->dev; + + dev_dbg(dev, "[DCMIPP_PRSR] =%#10.8x\n", reg_read(vcap, DCMIPP_PRSR)); + dev_dbg(dev, "[DCMIPP_P0SR] =%#10.8x\n", reg_read(vcap, DCMIPP_P0SR)); + dev_dbg(dev, "[DCMIPP_P0DCCNTR]=%#10.8x\n", + reg_read(vcap, DCMIPP_P0DCCNTR)); + dev_dbg(dev, "[DCMIPP_CMSR1] =%#10.8x\n", reg_read(vcap, DCMIPP_CMSR1)); + dev_dbg(dev, "[DCMIPP_CMSR2] =%#10.8x\n", reg_read(vcap, DCMIPP_CMSR2)); +} + +/* + * Stop the stream engine. Any remaining buffers in the stream queue are + * dequeued and passed on to the vb2 framework marked as STATE_ERROR. + */ +static void dcmipp_bytecap_stop_streaming(struct vb2_queue *vq) +{ + struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq); + int ret; + u32 status; + + dcmipp_pipeline_s_stream(vcap, 0); + + /* Stop the media pipeline */ + media_pipeline_stop(vcap->vdev.entity.pads); + + /* Disable interruptions */ + reg_clear(vcap, DCMIPP_CMIER, vcap->cmier); + + /* Stop capture */ + reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ); + + /* Wait until CPTACT become 0 */ + ret = readl_relaxed_poll_timeout(vcap->regs + DCMIPP_P0SR, status, + !(status & DCMIPP_P0SR_CPTACT), + 20 * USEC_PER_MSEC, + 1000 * USEC_PER_MSEC); + if (ret) + dev_warn(vcap->dev, "Timeout when stopping\n"); + + /* Disable pipe */ + reg_clear(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN); + + spin_lock_irq(&vcap->irqlock); + + /* Return all queued buffers to vb2 in ERROR state */ + dcmipp_bytecap_all_buffers_done(vcap, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&vcap->buffers); + + vcap->active = NULL; + vcap->state = DCMIPP_STOPPED; + + spin_unlock_irq(&vcap->irqlock); + + dcmipp_dump_status(vcap); + + pm_runtime_put(vcap->dev); + + if (vcap->count.errors) + dev_warn(vcap->dev, "Some errors found while streaming: errors=%d (overrun=%d, limit=%d, nactive=%d), underrun=%d, buffers=%d\n", + vcap->count.errors, vcap->count.overrun, + vcap->count.limit, vcap->count.nactive, + vcap->count.underrun, vcap->count.buffers); +} + +static int dcmipp_bytecap_buf_prepare(struct vb2_buffer *vb) +{ + struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb); + unsigned long size; + + size = vcap->format.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(vcap->dev, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + if (!buf->prepared) { + /* Get memory addresses */ + buf->addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0); + buf->prepared = true; + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); + + dev_dbg(vcap->dev, "Setup [%d] phy=%pad size=%zu\n", + vb->index, &buf->addr, buf->size); + } + + return 0; +} + +static void dcmipp_bytecap_buf_queue(struct vb2_buffer *vb2_buf) +{ + struct dcmipp_bytecap_device *vcap = + vb2_get_drv_priv(vb2_buf->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2_buf); + struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb); + + dev_dbg(vcap->dev, "Queue [%d] %p phy=%pad\n", buf->vb.vb2_buf.index, + buf, &buf->addr); + + spin_lock_irq(&vcap->irqlock); + list_add_tail(&buf->list, &vcap->buffers); + + if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) { + vcap->next = buf; + dev_dbg(vcap->dev, "Restart with next [%d] %p phy=%pad\n", + buf->vb.vb2_buf.index, buf, &buf->addr); + + dcmipp_start_capture(vcap, buf); + + vcap->state = DCMIPP_RUNNING; + } + + spin_unlock_irq(&vcap->irqlock); +} + +static int dcmipp_bytecap_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq); + unsigned int size; + + size = vcap->format.sizeimage; + + /* Make sure the image size is large enough */ + if (*nplanes) + return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = vcap->format.sizeimage; + + dev_dbg(vcap->dev, "Setup queue, count=%d, size=%d\n", + *nbuffers, size); + + return 0; +} + +static int dcmipp_bytecap_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static const struct vb2_ops dcmipp_bytecap_qops = { + .start_streaming = dcmipp_bytecap_start_streaming, + .stop_streaming = dcmipp_bytecap_stop_streaming, + .buf_init = dcmipp_bytecap_buf_init, + .buf_prepare = dcmipp_bytecap_buf_prepare, + .buf_queue = dcmipp_bytecap_buf_queue, + .queue_setup = dcmipp_bytecap_queue_setup, + /* + * Since q->lock is set we can use the standard + * vb2_ops_wait_prepare/finish helper functions. + */ + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static void dcmipp_bytecap_release(struct video_device *vdev) +{ + struct dcmipp_bytecap_device *vcap = + container_of(vdev, struct dcmipp_bytecap_device, vdev); + + dcmipp_pads_cleanup(vcap->ved.pads); + mutex_destroy(&vcap->lock); + + kfree(vcap); +} + +void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved) +{ + struct dcmipp_bytecap_device *vcap = + container_of(ved, struct dcmipp_bytecap_device, ved); + + media_entity_cleanup(ved->ent); + vb2_video_unregister_device(&vcap->vdev); +} + +static void dcmipp_buffer_done(struct dcmipp_bytecap_device *vcap, + struct dcmipp_buf *buf, + size_t bytesused, + int err) +{ + struct vb2_v4l2_buffer *vbuf; + + list_del_init(&buf->list); + + vbuf = &buf->vb; + + vbuf->sequence = vcap->sequence++; + vbuf->field = V4L2_FIELD_NONE; + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused); + vb2_buffer_done(&vbuf->vb2_buf, + err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev_dbg(vcap->dev, "Done [%d] %p phy=%pad\n", buf->vb.vb2_buf.index, + buf, &buf->addr); + vcap->count.buffers++; +} + +/* irqlock must be held */ +static void +dcmipp_bytecap_set_next_frame_or_stop(struct dcmipp_bytecap_device *vcap) +{ + if (!vcap->next && list_is_singular(&vcap->buffers)) { + /* + * If there is no available buffer (none or a single one in the + * list while two are expected), stop the capture (effective + * for next frame). On-going frame capture will continue until + * FRAME END but no further capture will be done. + */ + reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ); + + dev_dbg(vcap->dev, "Capture restart is deferred to next buffer queueing\n"); + vcap->next = NULL; + vcap->state = DCMIPP_WAIT_FOR_BUFFER; + return; + } + + /* If we don't have buffer yet, pick the one after active */ + if (!vcap->next) + vcap->next = list_next_entry(vcap->active, list); + + /* + * Set buffer address + * This register is shadowed and will be taken into + * account on next VSYNC (start of next frame) + */ + reg_write(vcap, DCMIPP_P0PPM0AR1, vcap->next->addr); + dev_dbg(vcap->dev, "Write [%d] %p phy=%pad\n", + vcap->next->vb.vb2_buf.index, vcap->next, &vcap->next->addr); +} + +/* irqlock must be held */ +static void dcmipp_bytecap_process_frame(struct dcmipp_bytecap_device *vcap, + size_t bytesused) +{ + int err = 0; + struct dcmipp_buf *buf = vcap->active; + + if (!buf) { + vcap->count.nactive++; + vcap->count.errors++; + return; + } + + if (bytesused > buf->size) { + dev_dbg(vcap->dev, "frame larger than expected (%zu > %zu)\n", + bytesused, buf->size); + /* Clip to buffer size and return buffer to V4L2 in error */ + bytesused = buf->size; + vcap->count.limit++; + vcap->count.errors++; + err = -EOVERFLOW; + } + + dcmipp_buffer_done(vcap, buf, bytesused, err); + vcap->active = NULL; +} + +static irqreturn_t dcmipp_bytecap_irq_thread(int irq, void *arg) +{ + struct dcmipp_bytecap_device *vcap = + container_of(arg, struct dcmipp_bytecap_device, ved); + size_t bytesused = 0; + u32 cmsr2; + + spin_lock_irq(&vcap->irqlock); + + cmsr2 = vcap->cmsr2 & vcap->cmier; + + /* + * If we have an overrun, a frame-end will probably not be generated, + * in that case the active buffer will be recycled as next buffer by + * the VSYNC handler + */ + if (cmsr2 & DCMIPP_CMSR2_P0OVRF) { + vcap->count.errors++; + vcap->count.overrun++; + } + + if (cmsr2 & DCMIPP_CMSR2_P0FRAMEF) { + vcap->count.frame++; + + /* Read captured buffer size */ + bytesused = reg_read(vcap, DCMIPP_P0DCCNTR); + dcmipp_bytecap_process_frame(vcap, bytesused); + } + + if (cmsr2 & DCMIPP_CMSR2_P0VSYNCF) { + vcap->count.vsync++; + if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) { + vcap->count.underrun++; + goto out; + } + + /* + * On VSYNC, the previously set next buffer is going to become + * active thanks to the shadowing mechanism of the DCMIPP. In + * most of the cases, since a FRAMEEND has already come, + * pointer next is NULL since active is reset during the + * FRAMEEND handling. However, in case of framerate adjustment, + * there are more VSYNC than FRAMEEND. Thus we recycle the + * active (but not used) buffer and put it back into next. + */ + swap(vcap->active, vcap->next); + dcmipp_bytecap_set_next_frame_or_stop(vcap); + } + +out: + spin_unlock_irq(&vcap->irqlock); + return IRQ_HANDLED; +} + +static irqreturn_t dcmipp_bytecap_irq_callback(int irq, void *arg) +{ + struct dcmipp_bytecap_device *vcap = + container_of(arg, struct dcmipp_bytecap_device, ved); + + /* Store interrupt status register */ + vcap->cmsr2 = reg_read(vcap, DCMIPP_CMSR2) & vcap->cmier; + vcap->count.it++; + + /* Clear interrupt */ + reg_write(vcap, DCMIPP_CMFCR, vcap->cmsr2); + + return IRQ_WAKE_THREAD; +} + +static int dcmipp_bytecap_link_validate(struct media_link *link) +{ + struct media_entity *entity = link->sink->entity; + struct video_device *vd = media_entity_to_video_device(entity); + struct dcmipp_bytecap_device *vcap = container_of(vd, + struct dcmipp_bytecap_device, vdev); + struct v4l2_subdev *source_sd = + media_entity_to_v4l2_subdev(link->source->entity); + struct v4l2_subdev_format source_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; + const struct dcmipp_bytecap_pix_map *vpix; + int ret; + + ret = v4l2_subdev_call(source_sd, pad, get_fmt, NULL, &source_fmt); + if (ret < 0) + return 0; + + if (source_fmt.format.width != vcap->format.width || + source_fmt.format.height != vcap->format.height) { + dev_err(vcap->dev, "Wrong width or height %ux%u (%ux%u expected)\n", + vcap->format.width, vcap->format.height, + source_fmt.format.width, source_fmt.format.height); + return -EINVAL; + } + + vpix = dcmipp_bytecap_pix_map_by_pixelformat(vcap->format.pixelformat); + if (source_fmt.format.code != vpix->code) { + dev_err(vcap->dev, "Wrong mbus_code 0x%x, (0x%x expected)\n", + vpix->code, source_fmt.format.code); + return -EINVAL; + } + + return 0; +} + +static const struct media_entity_operations dcmipp_bytecap_entity_ops = { + .link_validate = dcmipp_bytecap_link_validate, +}; + +struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev, + const char *entity_name, + struct v4l2_device *v4l2_dev, + void __iomem *regs) +{ + struct dcmipp_bytecap_device *vcap; + struct video_device *vdev; + struct vb2_queue *q; + const unsigned long pad_flag = MEDIA_PAD_FL_SINK; + int ret = 0; + + /* Allocate the dcmipp_bytecap_device struct */ + vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); + if (!vcap) + return ERR_PTR(-ENOMEM); + + /* Allocate the pads */ + vcap->ved.pads = dcmipp_pads_init(1, &pad_flag); + if (IS_ERR(vcap->ved.pads)) { + ret = PTR_ERR(vcap->ved.pads); + goto err_free_vcap; + } + + /* Initialize the media entity */ + vcap->vdev.entity.name = entity_name; + vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; + vcap->vdev.entity.ops = &dcmipp_bytecap_entity_ops; + ret = media_entity_pads_init(&vcap->vdev.entity, 1, vcap->ved.pads); + if (ret) + goto err_clean_pads; + + /* Initialize the lock */ + mutex_init(&vcap->lock); + + /* Initialize the vb2 queue */ + q = &vcap->queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->lock = &vcap->lock; + q->drv_priv = vcap; + q->buf_struct_size = sizeof(struct dcmipp_buf); + q->ops = &dcmipp_bytecap_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; + q->dev = dev; + + /* DCMIPP requires 16 bytes aligned buffers */ + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32) & ~0x0f); + if (ret) { + dev_err(dev, "Failed to set DMA mask\n"); + goto err_mutex_destroy; + } + + ret = vb2_queue_init(q); + if (ret) { + dev_err(dev, "%s: vb2 queue init failed (err=%d)\n", + entity_name, ret); + goto err_clean_m_ent; + } + + /* Initialize buffer list and its lock */ + INIT_LIST_HEAD(&vcap->buffers); + spin_lock_init(&vcap->irqlock); + + /* Set default frame format */ + vcap->format = fmt_default; + + /* Fill the dcmipp_ent_device struct */ + vcap->ved.ent = &vcap->vdev.entity; + vcap->ved.handler = dcmipp_bytecap_irq_callback; + vcap->ved.thread_fn = dcmipp_bytecap_irq_thread; + vcap->dev = dev; + vcap->regs = regs; + + /* Initialize the video_device struct */ + vdev = &vcap->vdev; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->release = dcmipp_bytecap_release; + vdev->fops = &dcmipp_bytecap_fops; + vdev->ioctl_ops = &dcmipp_bytecap_ioctl_ops; + vdev->lock = &vcap->lock; + vdev->queue = q; + vdev->v4l2_dev = v4l2_dev; + strscpy(vdev->name, entity_name, sizeof(vdev->name)); + video_set_drvdata(vdev, &vcap->ved); + + /* Register the video_device with the v4l2 and the media framework */ + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(dev, "%s: video register failed (err=%d)\n", + vcap->vdev.name, ret); + goto err_clean_m_ent; + } + + return &vcap->ved; + +err_clean_m_ent: + media_entity_cleanup(&vcap->vdev.entity); +err_mutex_destroy: + mutex_destroy(&vcap->lock); +err_clean_pads: + dcmipp_pads_cleanup(vcap->ved.pads); +err_free_vcap: + kfree(vcap); + + return ERR_PTR(ret); +} diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c new file mode 100644 index 000000000000..5a361ad6b023 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#include +#include +#include +#include + +#include "dcmipp-common.h" + +#define DCMIPP_P0FCTCR 0x500 +#define DCMIPP_P0FCTCR_FRATE_MASK GENMASK(1, 0) +#define DCMIPP_P0SCSTR 0x504 +#define DCMIPP_P0SCSTR_HSTART_SHIFT 0 +#define DCMIPP_P0SCSTR_VSTART_SHIFT 16 +#define DCMIPP_P0SCSZR 0x508 +#define DCMIPP_P0SCSZR_ENABLE BIT(31) +#define DCMIPP_P0SCSZR_HSIZE_SHIFT 0 +#define DCMIPP_P0SCSZR_VSIZE_SHIFT 16 +#define DCMIPP_P0PPCR 0x5c0 +#define DCMIPP_P0PPCR_BSM_1_2 0x1 +#define DCMIPP_P0PPCR_BSM_1_4 0x2 +#define DCMIPP_P0PPCR_BSM_2_4 0x3 +#define DCMIPP_P0PPCR_BSM_MASK GENMASK(8, 7) +#define DCMIPP_P0PPCR_BSM_SHIFT 0x7 +#define DCMIPP_P0PPCR_LSM BIT(10) +#define DCMIPP_P0PPCR_OELS BIT(11) + +#define IS_SINK(pad) (!(pad)) +#define IS_SRC(pad) ((pad)) + +struct dcmipp_byteproc_pix_map { + unsigned int code; + unsigned int bpp; +}; + +#define PIXMAP_MBUS_BPP(mbus, byteperpixel) \ + { \ + .code = MEDIA_BUS_FMT_##mbus, \ + .bpp = byteperpixel, \ + } +static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = { + PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2), + PIXMAP_MBUS_BPP(YUYV8_2X8, 2), + PIXMAP_MBUS_BPP(YVYU8_2X8, 2), + PIXMAP_MBUS_BPP(UYVY8_2X8, 2), + PIXMAP_MBUS_BPP(VYUY8_2X8, 2), + PIXMAP_MBUS_BPP(Y8_1X8, 1), + PIXMAP_MBUS_BPP(SBGGR8_1X8, 1), + PIXMAP_MBUS_BPP(SGBRG8_1X8, 1), + PIXMAP_MBUS_BPP(SGRBG8_1X8, 1), + PIXMAP_MBUS_BPP(SRGGB8_1X8, 1), + PIXMAP_MBUS_BPP(JPEG_1X8, 1), +}; + +static const struct dcmipp_byteproc_pix_map * +dcmipp_byteproc_pix_map_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) { + if (dcmipp_byteproc_pix_map_list[i].code == code) + return &dcmipp_byteproc_pix_map_list[i]; + } + + return NULL; +} + +struct dcmipp_byteproc_device { + struct dcmipp_ent_device ved; + struct v4l2_subdev sd; + struct device *dev; + void __iomem *regs; + bool streaming; +}; + +static const struct v4l2_mbus_framefmt fmt_default = { + .width = DCMIPP_FMT_WIDTH_DEFAULT, + .height = DCMIPP_FMT_HEIGHT_DEFAULT, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .field = V4L2_FIELD_NONE, + .colorspace = DCMIPP_COLORSPACE_DEFAULT, + .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, + .quantization = DCMIPP_QUANTIZATION_DEFAULT, + .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, +}; + +static const struct v4l2_rect crop_min = { + .width = DCMIPP_FRAME_MIN_WIDTH, + .height = DCMIPP_FRAME_MIN_HEIGHT, + .top = 0, + .left = 0, +}; + +static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r, + struct v4l2_rect *compose) +{ + /* Disallow rectangles smaller than the minimal one. */ + v4l2_rect_set_min_size(r, &crop_min); + v4l2_rect_map_inside(r, compose); +} + +static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r, + const struct v4l2_mbus_framefmt *fmt) +{ + r->top = 0; + r->left = 0; + + /* Compose is not possible for JPEG or Bayer formats */ + if (fmt->code == MEDIA_BUS_FMT_JPEG_1X8 || + fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 || + fmt->code == MEDIA_BUS_FMT_SGBRG8_1X8 || + fmt->code == MEDIA_BUS_FMT_SGRBG8_1X8 || + fmt->code == MEDIA_BUS_FMT_SRGGB8_1X8) { + r->width = fmt->width; + r->height = fmt->height; + return; + } + + /* Adjust height - we can only perform 1/2 decimation */ + if (r->height <= (fmt->height / 2)) + r->height = fmt->height / 2; + else + r->height = fmt->height; + + /* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */ + if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4)) + r->width = fmt->width / 4; + else if (r->width <= (fmt->width / 2)) + r->width = fmt->width / 2; + else + r->width = fmt->width; +} + +static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt) +{ + const struct dcmipp_byteproc_pix_map *vpix; + + /* Only accept code in the pix map table */ + vpix = dcmipp_byteproc_pix_map_by_code(fmt->code); + if (!vpix) + fmt->code = fmt_default.code; + + fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH, + DCMIPP_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT, + DCMIPP_FRAME_MAX_HEIGHT) & ~1; + + if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) + fmt->field = fmt_default.field; + + dcmipp_colorimetry_clamp(fmt); +} + +static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + unsigned int i; + + for (i = 0; i < sd->entity.num_pads; i++) { + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *r; + + mf = v4l2_subdev_state_get_format(sd_state, i); + *mf = fmt_default; + + if (IS_SINK(i)) + r = v4l2_subdev_state_get_compose(sd_state, i); + else + r = v4l2_subdev_state_get_crop(sd_state, i); + + r->top = 0; + r->left = 0; + r->width = DCMIPP_FMT_WIDTH_DEFAULT; + r->height = DCMIPP_FMT_HEIGHT_DEFAULT; + } + + return 0; +} + +static int +dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct dcmipp_byteproc_pix_map *vpix; + struct v4l2_mbus_framefmt *sink_fmt; + + if (IS_SINK(code->pad)) { + if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list)) + return -EINVAL; + vpix = &dcmipp_byteproc_pix_map_list[code->index]; + code->code = vpix->code; + } else { + /* byteproc doesn't support transformation on format */ + if (code->index > 0) + return -EINVAL; + + sink_fmt = v4l2_subdev_state_get_format(sd_state, 0); + code->code = sink_fmt->code; + } + + return 0; +} + +static int +dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_rect *compose; + + if (fse->index) + return -EINVAL; + + fse->min_width = DCMIPP_FRAME_MIN_WIDTH; + fse->min_height = DCMIPP_FRAME_MIN_HEIGHT; + + if (IS_SINK(fse->pad)) { + fse->max_width = DCMIPP_FRAME_MAX_WIDTH; + fse->max_height = DCMIPP_FRAME_MAX_HEIGHT; + } else { + compose = v4l2_subdev_state_get_compose(sd_state, 0); + fse->max_width = compose->width; + fse->max_height = compose->height; + } + + return 0; +} + +static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *crop, *compose; + + if (byteproc->streaming) + return -EBUSY; + + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); + + crop = v4l2_subdev_state_get_crop(sd_state, 1); + compose = v4l2_subdev_state_get_compose(sd_state, 0); + + if (IS_SRC(fmt->pad)) { + fmt->format = *v4l2_subdev_state_get_format(sd_state, 0); + fmt->format.width = crop->width; + fmt->format.height = crop->height; + } else { + dcmipp_byteproc_adjust_fmt(&fmt->format); + crop->top = 0; + crop->left = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + *compose = *crop; + /* Set the same format on SOURCE pad as well */ + *v4l2_subdev_state_get_format(sd_state, 1) = fmt->format; + } + *mf = fmt->format; + + return 0; +} + +static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *s) +{ + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *crop, *compose; + + /* + * In the HW, the decimation block is located prior to the crop hence: + * Compose is done on the sink pad + * Crop is done on the src pad + */ + if (IS_SINK(s->pad) && + (s->target == V4L2_SEL_TGT_CROP || + s->target == V4L2_SEL_TGT_CROP_BOUNDS || + s->target == V4L2_SEL_TGT_CROP_DEFAULT)) + return -EINVAL; + + if (IS_SRC(s->pad) && + (s->target == V4L2_SEL_TGT_COMPOSE || + s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS || + s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT)) + return -EINVAL; + + sink_fmt = v4l2_subdev_state_get_format(sd_state, 0); + crop = v4l2_subdev_state_get_crop(sd_state, 1); + compose = v4l2_subdev_state_get_compose(sd_state, 0); + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r = *crop; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r = *compose; + break; + case V4L2_SEL_TGT_COMPOSE: + s->r = *compose; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.top = 0; + s->r.left = 0; + s->r.width = sink_fmt->width; + s->r.height = sink_fmt->height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *s) +{ + struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *crop, *compose; + + /* + * In the HW, the decimation block is located prior to the crop hence: + * Compose is done on the sink pad + * Crop is done on the src pad + */ + if ((s->target == V4L2_SEL_TGT_CROP || + s->target == V4L2_SEL_TGT_CROP_BOUNDS || + s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad)) + return -EINVAL; + + if ((s->target == V4L2_SEL_TGT_COMPOSE || + s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS || + s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad)) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(sd_state, 1); + compose = v4l2_subdev_state_get_compose(sd_state, 0); + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + dcmipp_byteproc_adjust_crop(&s->r, compose); + + *crop = s->r; + mf = v4l2_subdev_state_get_format(sd_state, 1); + mf->width = s->r.width; + mf->height = s->r.height; + + dev_dbg(byteproc->dev, "s_selection: crop %ux%u@(%u,%u)\n", + crop->width, crop->height, crop->left, crop->top); + break; + case V4L2_SEL_TGT_COMPOSE: + mf = v4l2_subdev_state_get_format(sd_state, 0); + dcmipp_byteproc_adjust_compose(&s->r, mf); + *compose = s->r; + *crop = s->r; + + mf = v4l2_subdev_state_get_format(sd_state, 1); + mf->width = s->r.width; + mf->height = s->r.height; + + dev_dbg(byteproc->dev, "s_selection: compose %ux%u@(%u,%u)\n", + compose->width, compose->height, + compose->left, compose->top); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = { + .enum_mbus_code = dcmipp_byteproc_enum_mbus_code, + .enum_frame_size = dcmipp_byteproc_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = dcmipp_byteproc_set_fmt, + .get_selection = dcmipp_byteproc_get_selection, + .set_selection = dcmipp_byteproc_set_selection, +}; + +static int dcmipp_byteproc_configure_scale_crop + (struct dcmipp_byteproc_device *byteproc) +{ + const struct dcmipp_byteproc_pix_map *vpix; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *sink_fmt; + u32 hprediv, vprediv; + struct v4l2_rect *compose, *crop; + u32 val = 0; + + state = v4l2_subdev_lock_and_get_active_state(&byteproc->sd); + sink_fmt = v4l2_subdev_state_get_format(state, 0); + compose = v4l2_subdev_state_get_compose(state, 0); + crop = v4l2_subdev_state_get_crop(state, 1); + v4l2_subdev_unlock_state(state); + + /* find output format bpp */ + vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code); + if (!vpix) + return -EINVAL; + + /* clear decimation/crop */ + reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK); + reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM); + reg_write(byteproc, DCMIPP_P0SCSTR, 0); + reg_write(byteproc, DCMIPP_P0SCSZR, 0); + + /* Ignore decimation/crop with JPEG */ + if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8) + return 0; + + /* decimation */ + hprediv = sink_fmt->width / compose->width; + if (hprediv == 4) + val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT; + else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2)) + val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT; + else if (hprediv == 2) + val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT; + + vprediv = sink_fmt->height / compose->height; + if (vprediv == 2) + val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS; + + /* decimate using bytes and lines skipping */ + if (val) { + reg_set(byteproc, DCMIPP_P0PPCR, val); + + dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n", + compose->width, compose->height, + hprediv, vprediv); + } + + dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height); + + /* expressed in 32-bits words on X axis, lines on Y axis */ + reg_write(byteproc, DCMIPP_P0SCSTR, + (((crop->left * vpix->bpp) / 4) << + DCMIPP_P0SCSTR_HSTART_SHIFT) | + (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT)); + reg_write(byteproc, DCMIPP_P0SCSZR, + DCMIPP_P0SCSZR_ENABLE | + (((crop->width * vpix->bpp) / 4) << + DCMIPP_P0SCSZR_HSIZE_SHIFT) | + (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT)); + + return 0; +} + +static int dcmipp_byteproc_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd); + struct v4l2_subdev *s_subdev; + struct media_pad *pad; + int ret = 0; + + /* Get source subdev */ + pad = media_pad_remote_pad_first(&sd->entity.pads[0]); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + return -EINVAL; + s_subdev = media_entity_to_v4l2_subdev(pad->entity); + + if (enable) { + ret = dcmipp_byteproc_configure_scale_crop(byteproc); + if (ret) + return ret; + + ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); + if (ret < 0) { + dev_err(byteproc->dev, + "failed to start source subdev streaming (%d)\n", + ret); + return ret; + } + } else { + ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); + if (ret < 0) { + dev_err(byteproc->dev, + "failed to stop source subdev streaming (%d)\n", + ret); + return ret; + } + } + + byteproc->streaming = enable; + + return 0; +} + +static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = { + .s_stream = dcmipp_byteproc_s_stream, +}; + +static const struct v4l2_subdev_ops dcmipp_byteproc_ops = { + .pad = &dcmipp_byteproc_pad_ops, + .video = &dcmipp_byteproc_video_ops, +}; + +static void dcmipp_byteproc_release(struct v4l2_subdev *sd) +{ + struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd); + + kfree(byteproc); +} + +static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = { + .init_state = dcmipp_byteproc_init_state, + .release = dcmipp_byteproc_release, +}; + +void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved) +{ + struct dcmipp_byteproc_device *byteproc = + container_of(ved, struct dcmipp_byteproc_device, ved); + + dcmipp_ent_sd_unregister(ved, &byteproc->sd); +} + +struct dcmipp_ent_device * +dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name, + struct v4l2_device *v4l2_dev, void __iomem *regs) +{ + struct dcmipp_byteproc_device *byteproc; + const unsigned long pads_flag[] = { + MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, + }; + int ret; + + /* Allocate the byteproc struct */ + byteproc = kzalloc(sizeof(*byteproc), GFP_KERNEL); + if (!byteproc) + return ERR_PTR(-ENOMEM); + + byteproc->regs = regs; + + /* Initialize ved and sd */ + ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd, + v4l2_dev, entity_name, + MEDIA_ENT_F_PROC_VIDEO_SCALER, + ARRAY_SIZE(pads_flag), pads_flag, + &dcmipp_byteproc_int_ops, + &dcmipp_byteproc_ops, + NULL, NULL); + if (ret) { + kfree(byteproc); + return ERR_PTR(ret); + } + + byteproc->dev = dev; + + return &byteproc->ved; +} diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c new file mode 100644 index 000000000000..562933e08d62 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#include +#include + +#include "dcmipp-common.h" + +/* Helper function to allocate and initialize pads */ +struct media_pad *dcmipp_pads_init(u16 num_pads, const unsigned long *pads_flags) +{ + struct media_pad *pads; + unsigned int i; + + /* Allocate memory for the pads */ + pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL); + if (!pads) + return ERR_PTR(-ENOMEM); + + /* Initialize the pads */ + for (i = 0; i < num_pads; i++) { + pads[i].index = i; + pads[i].flags = pads_flags[i]; + } + + return pads; +} + +static const struct media_entity_operations dcmipp_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved, + struct v4l2_subdev *sd, + struct v4l2_device *v4l2_dev, + const char *const name, + u32 function, + u16 num_pads, + const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, + const struct v4l2_subdev_ops *sd_ops, + irq_handler_t handler, + irq_handler_t thread_fn) +{ + int ret; + + /* Allocate the pads. Should be released from the sd_int_op release */ + ved->pads = dcmipp_pads_init(num_pads, pads_flag); + if (IS_ERR(ved->pads)) + return PTR_ERR(ved->pads); + + /* Fill the dcmipp_ent_device struct */ + ved->ent = &sd->entity; + + /* Initialize the subdev */ + v4l2_subdev_init(sd, sd_ops); + sd->internal_ops = sd_int_ops; + sd->entity.function = function; + sd->entity.ops = &dcmipp_entity_ops; + sd->owner = THIS_MODULE; + strscpy(sd->name, name, sizeof(sd->name)); + v4l2_set_subdevdata(sd, ved); + + /* Expose this subdev to user space */ + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + + /* Initialize the media entity */ + ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads); + if (ret) + goto err_clean_pads; + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) + goto err_clean_m_ent; + + /* Register the subdev with the v4l2 and the media framework */ + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) { + dev_err(v4l2_dev->dev, + "%s: subdev register failed (err=%d)\n", + name, ret); + goto err_clean_m_ent; + } + + ved->handler = handler; + ved->thread_fn = thread_fn; + + return 0; + +err_clean_m_ent: + media_entity_cleanup(&sd->entity); +err_clean_pads: + dcmipp_pads_cleanup(ved->pads); + return ret; +} + +void +dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved, struct v4l2_subdev *sd) +{ + media_entity_cleanup(ved->ent); + v4l2_device_unregister_subdev(sd); +} diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h new file mode 100644 index 000000000000..7a7cf43baf24 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#ifndef _DCMIPP_COMMON_H_ +#define _DCMIPP_COMMON_H_ + +#include +#include +#include +#include +#include + +#define DCMIPP_PDEV_NAME "dcmipp" + +#define DCMIPP_FRAME_MAX_WIDTH 4096 +#define DCMIPP_FRAME_MAX_HEIGHT 2160 +#define DCMIPP_FRAME_MIN_WIDTH 16 +#define DCMIPP_FRAME_MIN_HEIGHT 16 + +#define DCMIPP_FMT_WIDTH_DEFAULT 640 +#define DCMIPP_FMT_HEIGHT_DEFAULT 480 + +#define DCMIPP_COLORSPACE_DEFAULT V4L2_COLORSPACE_REC709 +#define DCMIPP_YCBCR_ENC_DEFAULT V4L2_YCBCR_ENC_DEFAULT +#define DCMIPP_QUANTIZATION_DEFAULT V4L2_QUANTIZATION_DEFAULT +#define DCMIPP_XFER_FUNC_DEFAULT V4L2_XFER_FUNC_DEFAULT + +/** + * dcmipp_colorimetry_clamp() - Adjust colorimetry parameters + * + * @fmt: the pointer to struct v4l2_pix_format or + * struct v4l2_mbus_framefmt + * + * Entities must check if colorimetry given by the userspace is valid, if not + * then set them as DEFAULT + */ +#define dcmipp_colorimetry_clamp(fmt) \ +do { \ + if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT || \ + (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) { \ + (fmt)->colorspace = DCMIPP_COLORSPACE_DEFAULT; \ + (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \ + (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \ + (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \ + } \ + if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M) \ + (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \ + if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE) \ + (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \ + if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084) \ + (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \ +} while (0) + +/** + * struct dcmipp_ent_device - core struct that represents a node in the topology + * + * @ent: the pointer to struct media_entity for the node + * @pads: the list of pads of the node + * @bus: struct v4l2_mbus_config_parallel describing input bus + * @bus_type: type of input bus (parallel or BT656) + * @handler: irq handler dedicated to the subdev + * @handler_ret: value returned by the irq handler + * @thread_fn: threaded irq handler + * + * The DCMIPP provides a single IRQ line and a IRQ status registers for all + * subdevs, hence once the main irq handler (registered at probe time) is + * called, it will chain calls to the irq handler of each the subdevs of the + * pipelines, using the handler/handler_ret/thread_fn variables. + * + * Each node of the topology must create a dcmipp_ent_device struct. + * Depending on the node it will be of an instance of v4l2_subdev or + * video_device struct where both contains a struct media_entity. + * Those structures should embedded the dcmipp_ent_device struct through + * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the + * dcmipp_ent_device struct to be retrieved from the corresponding struct + * media_entity + */ +struct dcmipp_ent_device { + struct media_entity *ent; + struct media_pad *pads; + + /* Parallel input device */ + struct v4l2_mbus_config_parallel bus; + enum v4l2_mbus_type bus_type; + irq_handler_t handler; + irqreturn_t handler_ret; + irq_handler_t thread_fn; +}; + +/** + * dcmipp_pads_init - initialize pads + * + * @num_pads: number of pads to initialize + * @pads_flags: flags to use in each pad + * + * Helper functions to allocate/initialize pads + */ +struct media_pad *dcmipp_pads_init(u16 num_pads, + const unsigned long *pads_flags); + +/** + * dcmipp_pads_cleanup - free pads + * + * @pads: pointer to the pads + * + * Helper function to free the pads initialized with dcmipp_pads_init + */ +static inline void dcmipp_pads_cleanup(struct media_pad *pads) +{ + kfree(pads); +} + +/** + * dcmipp_ent_sd_register - initialize and register a subdev node + * + * @ved: the dcmipp_ent_device struct to be initialize + * @sd: the v4l2_subdev struct to be initialize and registered + * @v4l2_dev: the v4l2 device to register the v4l2_subdev + * @name: name of the sub-device. Please notice that the name must be + * unique. + * @function: media entity function defined by MEDIA_ENT_F_* macros + * @num_pads: number of pads to initialize + * @pads_flag: flags to use in each pad + * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops + * @sd_ops: pointer to &struct v4l2_subdev_ops. + * @handler: func pointer of the irq handler + * @thread_fn: func pointer of the threaded irq handler + * + * Helper function initialize and register the struct dcmipp_ent_device and + * struct v4l2_subdev which represents a subdev node in the topology + */ +int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved, + struct v4l2_subdev *sd, + struct v4l2_device *v4l2_dev, + const char *const name, + u32 function, + u16 num_pads, + const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, + const struct v4l2_subdev_ops *sd_ops, + irq_handler_t handler, + irq_handler_t thread_fn); + +/** + * dcmipp_ent_sd_unregister - cleanup and unregister a subdev node + * + * @ved: the dcmipp_ent_device struct to be cleaned up + * @sd: the v4l2_subdev struct to be unregistered + * + * Helper function cleanup and unregister the struct dcmipp_ent_device and + * struct v4l2_subdev which represents a subdev node in the topology + */ +void dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved, + struct v4l2_subdev *sd); + +#define reg_write(device, reg, val) \ + (__reg_write((device)->dev, (device)->regs, (reg), (val))) +#define reg_read(device, reg) \ + (__reg_read((device)->dev, (device)->regs, (reg))) +#define reg_set(device, reg, mask) \ + (__reg_set((device)->dev, (device)->regs, (reg), (mask))) +#define reg_clear(device, reg, mask) \ + (__reg_clear((device)->dev, (device)->regs, (reg), (mask))) + +static inline u32 __reg_read(struct device *dev, void __iomem *base, u32 reg) +{ + u32 val = readl_relaxed(base + reg); + + dev_dbg(dev, "RD 0x%x %#10.8x\n", reg, val); + return val; +} + +static inline void __reg_write(struct device *dev, void __iomem *base, u32 reg, + u32 val) +{ + dev_dbg(dev, "WR 0x%x %#10.8x\n", reg, val); + writel_relaxed(val, base + reg); +} + +static inline void __reg_set(struct device *dev, void __iomem *base, u32 reg, + u32 mask) +{ + dev_dbg(dev, "SET 0x%x %#10.8x\n", reg, mask); + __reg_write(dev, base, reg, readl_relaxed(base + reg) | mask); +} + +static inline void __reg_clear(struct device *dev, void __iomem *base, u32 reg, + u32 mask) +{ + dev_dbg(dev, "CLR 0x%x %#10.8x\n", reg, mask); + __reg_write(dev, base, reg, readl_relaxed(base + reg) & ~mask); +} + +/* DCMIPP subdev init / release entry points */ +struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev, + const char *entity_name, + struct v4l2_device *v4l2_dev, + void __iomem *regs); +void dcmipp_par_ent_release(struct dcmipp_ent_device *ved); +struct dcmipp_ent_device * +dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name, + struct v4l2_device *v4l2_dev, void __iomem *regs); +void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved); +struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev, + const char *entity_name, + struct v4l2_device *v4l2_dev, + void __iomem *regs); +void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved); + +#endif diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c new file mode 100644 index 000000000000..32c6619be9a2 --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dcmipp-common.h" + +#define DCMIPP_MDEV_MODEL_NAME "DCMIPP MDEV" + +#define DCMIPP_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ + .src_ent = src, \ + .src_pad = srcpad, \ + .sink_ent = sink, \ + .sink_pad = sinkpad, \ + .flags = link_flags, \ +} + +struct dcmipp_device { + /* The platform device */ + struct platform_device pdev; + struct device *dev; + + /* Hardware resources */ + void __iomem *regs; + struct clk *kclk; + + /* The pipeline configuration */ + const struct dcmipp_pipeline_config *pipe_cfg; + + /* The Associated media_device parent */ + struct media_device mdev; + + /* Internal v4l2 parent device*/ + struct v4l2_device v4l2_dev; + + /* Entities */ + struct dcmipp_ent_device **entity; + + struct v4l2_async_notifier notifier; +}; + +static inline struct dcmipp_device * +notifier_to_dcmipp(struct v4l2_async_notifier *n) +{ + return container_of(n, struct dcmipp_device, notifier); +} + +/* Structure which describes individual configuration for each entity */ +struct dcmipp_ent_config { + const char *name; + struct dcmipp_ent_device *(*init) + (struct device *dev, const char *entity_name, + struct v4l2_device *v4l2_dev, void __iomem *regs); + void (*release)(struct dcmipp_ent_device *ved); +}; + +/* Structure which describes links between entities */ +struct dcmipp_ent_link { + unsigned int src_ent; + u16 src_pad; + unsigned int sink_ent; + u16 sink_pad; + u32 flags; +}; + +/* Structure which describes the whole topology */ +struct dcmipp_pipeline_config { + const struct dcmipp_ent_config *ents; + size_t num_ents; + const struct dcmipp_ent_link *links; + size_t num_links; +}; + +/* -------------------------------------------------------------------------- + * Topology Configuration + */ + +static const struct dcmipp_ent_config stm32mp13_ent_config[] = { + { + .name = "dcmipp_parallel", + .init = dcmipp_par_ent_init, + .release = dcmipp_par_ent_release, + }, + { + .name = "dcmipp_dump_postproc", + .init = dcmipp_byteproc_ent_init, + .release = dcmipp_byteproc_ent_release, + }, + { + .name = "dcmipp_dump_capture", + .init = dcmipp_bytecap_ent_init, + .release = dcmipp_bytecap_ent_release, + }, +}; + +#define ID_PARALLEL 0 +#define ID_DUMP_BYTEPROC 1 +#define ID_DUMP_CAPTURE 2 + +static const struct dcmipp_ent_link stm32mp13_ent_links[] = { + DCMIPP_ENT_LINK(ID_PARALLEL, 1, ID_DUMP_BYTEPROC, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), +}; + +static const struct dcmipp_pipeline_config stm32mp13_pipe_cfg = { + .ents = stm32mp13_ent_config, + .num_ents = ARRAY_SIZE(stm32mp13_ent_config), + .links = stm32mp13_ent_links, + .num_links = ARRAY_SIZE(stm32mp13_ent_links) +}; + +#define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\ + (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\ + (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\ + (f) == (MEDIA_LNK_FL_ENABLED |\ + MEDIA_LNK_FL_IMMUTABLE) ?\ + "ENABLED, IMMUTABLE" :\ + "UNKNOWN") + +static int dcmipp_create_links(struct dcmipp_device *dcmipp) +{ + unsigned int i; + int ret; + + /* Initialize the links between entities */ + for (i = 0; i < dcmipp->pipe_cfg->num_links; i++) { + const struct dcmipp_ent_link *link = + &dcmipp->pipe_cfg->links[i]; + struct dcmipp_ent_device *ved_src = + dcmipp->entity[link->src_ent]; + struct dcmipp_ent_device *ved_sink = + dcmipp->entity[link->sink_ent]; + + dev_dbg(dcmipp->dev, "Create link \"%s\":%d -> %d:\"%s\" [%s]\n", + dcmipp->pipe_cfg->ents[link->src_ent].name, + link->src_pad, link->sink_pad, + dcmipp->pipe_cfg->ents[link->sink_ent].name, + LINK_FLAG_TO_STR(link->flags)); + + ret = media_create_pad_link(ved_src->ent, link->src_pad, + ved_sink->ent, link->sink_pad, + link->flags); + if (ret) + return ret; + } + + return 0; +} + +static int dcmipp_graph_init(struct dcmipp_device *dcmipp); + +static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp) +{ + int ret, i; + + /* Call all subdev inits */ + for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { + const char *name = dcmipp->pipe_cfg->ents[i].name; + + dev_dbg(dcmipp->dev, "add subdev %s\n", name); + dcmipp->entity[i] = + dcmipp->pipe_cfg->ents[i].init(dcmipp->dev, name, + &dcmipp->v4l2_dev, + dcmipp->regs); + if (IS_ERR(dcmipp->entity[i])) { + dev_err(dcmipp->dev, "failed to init subdev %s\n", + name); + ret = PTR_ERR(dcmipp->entity[i]); + goto err_init_entity; + } + } + + /* Initialize links */ + ret = dcmipp_create_links(dcmipp); + if (ret) + goto err_init_entity; + + ret = dcmipp_graph_init(dcmipp); + if (ret < 0) + goto err_init_entity; + + return 0; + +err_init_entity: + while (i > 0) + dcmipp->pipe_cfg->ents[i - 1].release(dcmipp->entity[i - 1]); + return ret; +} + +static const struct of_device_id dcmipp_of_match[] = { + { .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg }, + { /* end node */ }, +}; +MODULE_DEVICE_TABLE(of, dcmipp_of_match); + +static irqreturn_t dcmipp_irq_thread(int irq, void *arg) +{ + struct dcmipp_device *dcmipp = arg; + struct dcmipp_ent_device *ved; + unsigned int i; + + /* Call irq thread of each entities of pipeline */ + for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { + ved = dcmipp->entity[i]; + if (ved->thread_fn && ved->handler_ret == IRQ_WAKE_THREAD) + ved->thread_fn(irq, ved); + } + + return IRQ_HANDLED; +} + +static irqreturn_t dcmipp_irq_callback(int irq, void *arg) +{ + struct dcmipp_device *dcmipp = arg; + struct dcmipp_ent_device *ved; + irqreturn_t ret = IRQ_HANDLED; + unsigned int i; + + /* Call irq handler of each entities of pipeline */ + for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { + ved = dcmipp->entity[i]; + if (ved->handler) + ved->handler_ret = ved->handler(irq, ved); + else if (ved->thread_fn) + ved->handler_ret = IRQ_WAKE_THREAD; + else + ved->handler_ret = IRQ_HANDLED; + if (ved->handler_ret != IRQ_HANDLED) + ret = ved->handler_ret; + } + + return ret; +} + +static int dcmipp_graph_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); + unsigned int ret; + int src_pad; + struct dcmipp_ent_device *sink; + struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_PARALLEL }; + struct fwnode_handle *ep; + + dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name); + + /* + * Link this sub-device to DCMIPP, it could be + * a parallel camera sensor or a CSI-2 to parallel bridge + */ + src_pad = media_entity_get_fwnode_pad(&subdev->entity, + subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + + /* Get bus characteristics from devicetree */ + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) { + dev_err(dcmipp->dev, "Could not find the endpoint\n"); + return -ENODEV; + } + + /* Check for parallel bus-type first, then bt656 */ + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) { + vep.bus_type = V4L2_MBUS_BT656; + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) { + dev_err(dcmipp->dev, "Could not parse the endpoint\n"); + fwnode_handle_put(ep); + return ret; + } + } + + fwnode_handle_put(ep); + + if (vep.bus.parallel.bus_width == 0) { + dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n"); + return -ENODEV; + } + + /* Only 8 bits bus width supported with BT656 bus */ + if (vep.bus_type == V4L2_MBUS_BT656 && + vep.bus.parallel.bus_width != 8) { + dev_err(dcmipp->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n", + vep.bus.parallel.bus_width); + return -ENODEV; + } + + /* Parallel input device detected, connect it to parallel subdev */ + sink = dcmipp->entity[ID_PARALLEL]; + sink->bus.flags = vep.bus.parallel.flags; + sink->bus.bus_width = vep.bus.parallel.bus_width; + sink->bus.data_shift = vep.bus.parallel.data_shift; + sink->bus_type = vep.bus_type; + ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(dcmipp->dev, "Failed to create media pad link with subdev \"%s\"\n", + subdev->name); + return ret; + } + + dev_dbg(dcmipp->dev, "DCMIPP is now linked to \"%s\"\n", subdev->name); + + return 0; +} + +static void dcmipp_graph_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_connection *asd) +{ + struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); + + dev_dbg(dcmipp->dev, "Removing %s\n", sd->name); +} + +static int dcmipp_graph_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); + int ret; + + /* Register the media device */ + ret = media_device_register(&dcmipp->mdev); + if (ret) { + dev_err(dcmipp->mdev.dev, + "media device register failed (err=%d)\n", ret); + return ret; + } + + /* Expose all subdev's nodes*/ + ret = v4l2_device_register_subdev_nodes(&dcmipp->v4l2_dev); + if (ret) { + dev_err(dcmipp->mdev.dev, + "dcmipp subdev nodes registration failed (err=%d)\n", + ret); + media_device_unregister(&dcmipp->mdev); + return ret; + } + + dev_dbg(dcmipp->dev, "Notify complete !\n"); + + return 0; +} + +static const struct v4l2_async_notifier_operations dcmipp_graph_notify_ops = { + .bound = dcmipp_graph_notify_bound, + .unbind = dcmipp_graph_notify_unbind, + .complete = dcmipp_graph_notify_complete, +}; + +static int dcmipp_graph_init(struct dcmipp_device *dcmipp) +{ + struct v4l2_async_connection *asd; + struct fwnode_handle *ep; + int ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) { + dev_err(dcmipp->dev, "Failed to get next endpoint\n"); + return -EINVAL; + } + + v4l2_async_nf_init(&dcmipp->notifier, &dcmipp->v4l2_dev); + + asd = v4l2_async_nf_add_fwnode_remote(&dcmipp->notifier, ep, + struct v4l2_async_connection); + + fwnode_handle_put(ep); + + if (IS_ERR(asd)) { + dev_err(dcmipp->dev, "Failed to add fwnode remote subdev\n"); + return PTR_ERR(asd); + } + + dcmipp->notifier.ops = &dcmipp_graph_notify_ops; + + ret = v4l2_async_nf_register(&dcmipp->notifier); + if (ret < 0) { + dev_err(dcmipp->dev, "Failed to register notifier\n"); + v4l2_async_nf_cleanup(&dcmipp->notifier); + return ret; + } + + return 0; +} + +static int dcmipp_probe(struct platform_device *pdev) +{ + struct dcmipp_device *dcmipp; + struct clk *kclk; + const struct dcmipp_pipeline_config *pipe_cfg; + struct reset_control *rstc; + int irq; + int ret; + + dcmipp = devm_kzalloc(&pdev->dev, sizeof(*dcmipp), GFP_KERNEL); + if (!dcmipp) + return -ENOMEM; + + dcmipp->dev = &pdev->dev; + + pipe_cfg = device_get_match_data(dcmipp->dev); + if (!pipe_cfg) { + dev_err(&pdev->dev, "Can't get device data\n"); + return -ENODEV; + } + dcmipp->pipe_cfg = pipe_cfg; + + platform_set_drvdata(pdev, dcmipp); + + /* Get hardware resources from devicetree */ + rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(&pdev->dev, PTR_ERR(rstc), + "Could not get reset control\n"); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get irq\n"); + return irq ? irq : -ENXIO; + } + + dcmipp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(dcmipp->regs)) { + dev_err(&pdev->dev, "Could not map registers\n"); + return PTR_ERR(dcmipp->regs); + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, dcmipp_irq_callback, + dcmipp_irq_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), dcmipp); + if (ret) { + dev_err(&pdev->dev, "Unable to request irq %d\n", irq); + return ret; + } + + /* Reset device */ + ret = reset_control_assert(rstc); + if (ret) { + dev_err(&pdev->dev, "Failed to assert the reset line\n"); + return ret; + } + + usleep_range(3000, 5000); + + ret = reset_control_deassert(rstc); + if (ret) { + dev_err(&pdev->dev, "Failed to deassert the reset line\n"); + return ret; + } + + kclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(kclk), + "Unable to get kclk\n"); + dcmipp->kclk = kclk; + + dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents, + sizeof(*dcmipp->entity), GFP_KERNEL); + if (!dcmipp->entity) + return -ENOMEM; + + /* Register the v4l2 struct */ + ret = v4l2_device_register(&pdev->dev, &dcmipp->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, + "v4l2 device register failed (err=%d)\n", ret); + return ret; + } + + /* Link the media device within the v4l2_device */ + dcmipp->v4l2_dev.mdev = &dcmipp->mdev; + + /* Initialize media device */ + strscpy(dcmipp->mdev.model, DCMIPP_MDEV_MODEL_NAME, + sizeof(dcmipp->mdev.model)); + dcmipp->mdev.dev = &pdev->dev; + media_device_init(&dcmipp->mdev); + + /* Initialize subdevs */ + ret = dcmipp_create_subdevs(dcmipp); + if (ret) { + media_device_cleanup(&dcmipp->mdev); + v4l2_device_unregister(&dcmipp->v4l2_dev); + return ret; + } + + pm_runtime_enable(dcmipp->dev); + + dev_info(&pdev->dev, "Probe done"); + + return 0; +} + +static int dcmipp_remove(struct platform_device *pdev) +{ + struct dcmipp_device *dcmipp = platform_get_drvdata(pdev); + unsigned int i; + + pm_runtime_disable(&pdev->dev); + + v4l2_async_nf_unregister(&dcmipp->notifier); + v4l2_async_nf_cleanup(&dcmipp->notifier); + + for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) + dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]); + + media_device_unregister(&dcmipp->mdev); + media_device_cleanup(&dcmipp->mdev); + + v4l2_device_unregister(&dcmipp->v4l2_dev); + + return 0; +} + +static int dcmipp_runtime_suspend(struct device *dev) +{ + struct dcmipp_device *dcmipp = dev_get_drvdata(dev); + + clk_disable_unprepare(dcmipp->kclk); + + return 0; +} + +static int dcmipp_runtime_resume(struct device *dev) +{ + struct dcmipp_device *dcmipp = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dcmipp->kclk); + if (ret) + dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__); + + return ret; +} + +static int dcmipp_suspend(struct device *dev) +{ + /* disable clock */ + pm_runtime_force_suspend(dev); + + /* change pinctrl state */ + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int dcmipp_resume(struct device *dev) +{ + /* restore pinctl default state */ + pinctrl_pm_select_default_state(dev); + + /* clock enable */ + pm_runtime_force_resume(dev); + + return 0; +} + +static const struct dev_pm_ops dcmipp_pm_ops = { + SYSTEM_SLEEP_PM_OPS(dcmipp_suspend, dcmipp_resume) + RUNTIME_PM_OPS(dcmipp_runtime_suspend, dcmipp_runtime_resume, NULL) +}; + +static struct platform_driver dcmipp_pdrv = { + .probe = dcmipp_probe, + .remove = dcmipp_remove, + .driver = { + .name = DCMIPP_PDEV_NAME, + .of_match_table = dcmipp_of_match, + .pm = pm_ptr(&dcmipp_pm_ops), + }, +}; + +module_platform_driver(dcmipp_pdrv); + +MODULE_AUTHOR("Hugues Fruchet "); +MODULE_AUTHOR("Alain Volmat "); +MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface with Pixel Processor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c new file mode 100644 index 000000000000..62c5c3331cfe --- /dev/null +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STM32 Digital Camera Memory Interface Pixel Processor + * + * Copyright (C) STMicroelectronics SA 2023 + * Authors: Hugues Fruchet + * Alain Volmat + * for STMicroelectronics. + */ + +#include +#include +#include + +#include "dcmipp-common.h" + +#define DCMIPP_PRCR 0x104 +#define DCMIPP_PRCR_FORMAT_SHIFT 16 +#define DCMIPP_PRCR_FORMAT_YUV422 0x1e +#define DCMIPP_PRCR_FORMAT_RGB565 0x22 +#define DCMIPP_PRCR_FORMAT_RAW8 0x2a +#define DCMIPP_PRCR_FORMAT_G8 0x4a +#define DCMIPP_PRCR_FORMAT_BYTE_STREAM 0x5a +#define DCMIPP_PRCR_ESS BIT(4) +#define DCMIPP_PRCR_PCKPOL BIT(5) +#define DCMIPP_PRCR_HSPOL BIT(6) +#define DCMIPP_PRCR_VSPOL BIT(7) +#define DCMIPP_PRCR_ENABLE BIT(14) +#define DCMIPP_PRCR_SWAPCYCLES BIT(25) + +#define DCMIPP_PRESCR 0x108 +#define DCMIPP_PRESUR 0x10c + +#define IS_SINK(pad) (!(pad)) +#define IS_SRC(pad) ((pad)) + +struct dcmipp_par_pix_map { + unsigned int code_sink; + unsigned int code_src; + u8 prcr_format; + u8 prcr_swapcycles; +}; + +#define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap) \ + { \ + .code_sink = MEDIA_BUS_FMT_##sink, \ + .code_src = MEDIA_BUS_FMT_##src, \ + .prcr_format = DCMIPP_PRCR_FORMAT_##prcr, \ + .prcr_swapcycles = swap, \ + } +static const struct dcmipp_par_pix_map dcmipp_par_pix_map_list[] = { + /* RGB565 */ + PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1), + PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0), + /* YUV422 */ + PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1), + PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0), + PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1), + PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0), + PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1), + PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1), + /* GREY */ + PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0), + /* Raw Bayer */ + PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0), + PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0), + PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0), + PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0), + /* JPEG */ + PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0), +}; + +/* + * Search through the pix_map table, skipping two consecutive entry with the + * same code + */ +static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_index + (unsigned int index, + unsigned int pad) +{ + unsigned int i = 0; + u32 prev_code = 0, cur_code; + + while (i < ARRAY_SIZE(dcmipp_par_pix_map_list)) { + if (IS_SRC(pad)) + cur_code = dcmipp_par_pix_map_list[i].code_src; + else + cur_code = dcmipp_par_pix_map_list[i].code_sink; + + if (cur_code == prev_code) { + i++; + continue; + } + prev_code = cur_code; + + if (index == 0) + break; + i++; + index--; + } + + if (i >= ARRAY_SIZE(dcmipp_par_pix_map_list)) + return NULL; + + return &dcmipp_par_pix_map_list[i]; +} + +static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_code + (u32 code_sink, u32 code_src) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dcmipp_par_pix_map_list); i++) { + if ((dcmipp_par_pix_map_list[i].code_sink == code_sink && + dcmipp_par_pix_map_list[i].code_src == code_src) || + (dcmipp_par_pix_map_list[i].code_sink == code_src && + dcmipp_par_pix_map_list[i].code_src == code_sink) || + (dcmipp_par_pix_map_list[i].code_sink == code_sink && + code_src == 0) || + (code_sink == 0 && + dcmipp_par_pix_map_list[i].code_src == code_src)) + return &dcmipp_par_pix_map_list[i]; + } + return NULL; +} + +struct dcmipp_par_device { + struct dcmipp_ent_device ved; + struct v4l2_subdev sd; + struct device *dev; + void __iomem *regs; + bool streaming; +}; + +static const struct v4l2_mbus_framefmt fmt_default = { + .width = DCMIPP_FMT_WIDTH_DEFAULT, + .height = DCMIPP_FMT_HEIGHT_DEFAULT, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .field = V4L2_FIELD_NONE, + .colorspace = DCMIPP_COLORSPACE_DEFAULT, + .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, + .quantization = DCMIPP_QUANTIZATION_DEFAULT, + .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, +}; + +static int dcmipp_par_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + unsigned int i; + + for (i = 0; i < sd->entity.num_pads; i++) { + struct v4l2_mbus_framefmt *mf; + + mf = v4l2_subdev_state_get_format(sd_state, i); + *mf = fmt_default; + } + + return 0; +} + +static int dcmipp_par_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct dcmipp_par_pix_map *vpix = + dcmipp_par_pix_map_by_index(code->index, code->pad); + + if (!vpix) + return -EINVAL; + + code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink; + + return 0; +} + +static int dcmipp_par_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct dcmipp_par_pix_map *vpix; + + if (fse->index) + return -EINVAL; + + /* Only accept code in the pix map table */ + vpix = dcmipp_par_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0, + IS_SRC(fse->pad) ? fse->code : 0); + if (!vpix) + return -EINVAL; + + fse->min_width = DCMIPP_FRAME_MIN_WIDTH; + fse->max_width = DCMIPP_FRAME_MAX_WIDTH; + fse->min_height = DCMIPP_FRAME_MIN_HEIGHT; + fse->max_height = DCMIPP_FRAME_MAX_HEIGHT; + + return 0; +} + +static void dcmipp_par_adjust_fmt(struct dcmipp_par_device *par, + struct v4l2_mbus_framefmt *fmt, __u32 pad) +{ + const struct dcmipp_par_pix_map *vpix; + + /* Only accept code in the pix map table */ + vpix = dcmipp_par_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0, + IS_SRC(pad) ? fmt->code : 0); + if (!vpix) + fmt->code = fmt_default.code; + + /* Exclude JPEG if BT656 bus is selected */ + if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 && + par->ved.bus_type == V4L2_MBUS_BT656) + fmt->code = fmt_default.code; + + fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH, + DCMIPP_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT, + DCMIPP_FRAME_MAX_HEIGHT) & ~1; + + if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) + fmt->field = fmt_default.field; + + dcmipp_colorimetry_clamp(fmt); +} + +static int dcmipp_par_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct dcmipp_par_device *par = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf; + + if (par->streaming) + return -EBUSY; + + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); + + /* Set the new format */ + dcmipp_par_adjust_fmt(par, &fmt->format, fmt->pad); + + dev_dbg(par->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n", + par->sd.name, + /* old */ + mf->width, mf->height, mf->code, + mf->colorspace, mf->quantization, + mf->xfer_func, mf->ycbcr_enc, + /* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *mf = fmt->format; + + /* When setting the sink format, report that format on the src pad */ + if (IS_SINK(fmt->pad)) { + mf = v4l2_subdev_state_get_format(sd_state, 1); + *mf = fmt->format; + dcmipp_par_adjust_fmt(par, mf, 1); + } + + return 0; +} + +static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = { + .enum_mbus_code = dcmipp_par_enum_mbus_code, + .enum_frame_size = dcmipp_par_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = dcmipp_par_set_fmt, +}; + +static int dcmipp_par_configure(struct dcmipp_par_device *par) +{ + u32 val = 0; + const struct dcmipp_par_pix_map *vpix; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_mbus_framefmt *src_fmt; + + /* Set vertical synchronization polarity */ + if (par->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + val |= DCMIPP_PRCR_VSPOL; + + /* Set horizontal synchronization polarity */ + if (par->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + val |= DCMIPP_PRCR_HSPOL; + + /* Set pixel clock polarity */ + if (par->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + val |= DCMIPP_PRCR_PCKPOL; + + /* + * BT656 embedded synchronisation bus mode. + * + * Default SAV/EAV mode is supported here with default codes + * SAV=0xff000080 & EAV=0xff00009d. + * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d. + */ + if (par->ved.bus_type == V4L2_MBUS_BT656) { + val |= DCMIPP_PRCR_ESS; + + /* Unmask all codes */ + reg_write(par, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ + + /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ + reg_write(par, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ + } + + /* Set format */ + state = v4l2_subdev_lock_and_get_active_state(&par->sd); + sink_fmt = v4l2_subdev_state_get_format(state, 0); + src_fmt = v4l2_subdev_state_get_format(state, 1); + v4l2_subdev_unlock_state(state); + + vpix = dcmipp_par_pix_map_by_code(sink_fmt->code, src_fmt->code); + if (!vpix) { + dev_err(par->dev, "Invalid sink/src format configuration\n"); + return -EINVAL; + } + + val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT; + + /* swap cycles */ + if (vpix->prcr_swapcycles) + val |= DCMIPP_PRCR_SWAPCYCLES; + + reg_write(par, DCMIPP_PRCR, val); + + return 0; +} + +static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct dcmipp_par_device *par = + container_of(sd, struct dcmipp_par_device, sd); + struct v4l2_subdev *s_subdev; + struct media_pad *pad; + int ret = 0; + + /* Get source subdev */ + pad = media_pad_remote_pad_first(&sd->entity.pads[0]); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + return -EINVAL; + s_subdev = media_entity_to_v4l2_subdev(pad->entity); + + if (enable) { + ret = dcmipp_par_configure(par); + if (ret) + return ret; + + /* Enable parallel interface */ + reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); + + ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); + if (ret < 0) { + dev_err(par->dev, + "failed to start source subdev streaming (%d)\n", + ret); + return ret; + } + } else { + ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); + if (ret < 0) { + dev_err(par->dev, + "failed to stop source subdev streaming (%d)\n", + ret); + return ret; + } + + /* Disable parallel interface */ + reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); + } + + par->streaming = enable; + + return ret; +} + +static const struct v4l2_subdev_video_ops dcmipp_par_video_ops = { + .s_stream = dcmipp_par_s_stream, +}; + +static const struct v4l2_subdev_ops dcmipp_par_ops = { + .pad = &dcmipp_par_pad_ops, + .video = &dcmipp_par_video_ops, +}; + +static void dcmipp_par_release(struct v4l2_subdev *sd) +{ + struct dcmipp_par_device *par = + container_of(sd, struct dcmipp_par_device, sd); + + kfree(par); +} + +static const struct v4l2_subdev_internal_ops dcmipp_par_int_ops = { + .init_state = dcmipp_par_init_state, + .release = dcmipp_par_release, +}; + +void dcmipp_par_ent_release(struct dcmipp_ent_device *ved) +{ + struct dcmipp_par_device *par = + container_of(ved, struct dcmipp_par_device, ved); + + dcmipp_ent_sd_unregister(ved, &par->sd); +} + +struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev, + const char *entity_name, + struct v4l2_device *v4l2_dev, + void __iomem *regs) +{ + struct dcmipp_par_device *par; + const unsigned long pads_flag[] = { + MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, + }; + int ret; + + /* Allocate the par struct */ + par = kzalloc(sizeof(*par), GFP_KERNEL); + if (!par) + return ERR_PTR(-ENOMEM); + + par->regs = regs; + + /* Initialize ved and sd */ + ret = dcmipp_ent_sd_register(&par->ved, &par->sd, v4l2_dev, + entity_name, MEDIA_ENT_F_VID_IF_BRIDGE, + ARRAY_SIZE(pads_flag), pads_flag, + &dcmipp_par_int_ops, &dcmipp_par_ops, + NULL, NULL); + if (ret) { + kfree(par); + return ERR_PTR(ret); + } + + par->dev = dev; + + return &par->ved; +} From 687eb09b1d76d01401dd9b22efb34931c3f1e21d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 29 Nov 2023 19:35:06 +0200 Subject: [PATCH 2348/7721] drm/i915/syncmap: squelch a sparse warning The code is fine, really, but tweak it to get rid of the sparse warning: drivers/gpu/drm/i915/selftests/i915_syncmap.c:80:54: warning: dubious: x | !y Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231129173506.1194437-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/selftests/i915_syncmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_syncmap.c b/drivers/gpu/drm/i915/selftests/i915_syncmap.c index 47f4ae18a1ef..88fa845e9f4a 100644 --- a/drivers/gpu/drm/i915/selftests/i915_syncmap.c +++ b/drivers/gpu/drm/i915/selftests/i915_syncmap.c @@ -77,7 +77,7 @@ __sync_print(struct i915_syncmap *p, for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { buf = __sync_print(__sync_child(p)[i], buf, sz, depth + 1, - last << 1 | !!(p->bitmap >> (i + 1)), + last << 1 | ((p->bitmap >> (i + 1)) ? 1 : 0), i); } } From 1116efbff3b106ec131e833f0e78f35c923d0104 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Nov 2023 16:01:28 +0200 Subject: [PATCH 2349/7721] drm/i915/display: Don't use "proxy" headers The driver uses math.h and not util_macros.h. Signed-off-by: Andy Shevchenko Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231129140129.699767-1-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/display/intel_snps_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index ce5a73a4cc89..bc61e736f9b3 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -3,7 +3,7 @@ * Copyright © 2019 Intel Corporation */ -#include +#include #include "i915_reg.h" #include "intel_ddi.h" From efa5fe19c0a9199f49e36e1f5242ed5c88da617d Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Wed, 22 Nov 2023 17:46:06 +0800 Subject: [PATCH 2350/7721] media: imx355: Enable runtime PM before registering async sub-device As the sensor device maybe accessible right after its async sub-device is registered, such as ipu-bridge will try to power up sensor by sensor's client device's runtime PM from the async notifier callback, if runtime PM is not enabled, it will fail. So runtime PM should be ready before its async sub-device is registered and accessible by others. Fixes: df0b5c4a7ddd ("media: add imx355 camera sensor driver") Cc: stable@vger.kernel.org Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx355.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index e1b1d2fc79dd..8c995c58743a 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1747,10 +1747,6 @@ static int imx355_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor(&imx355->sd); - if (ret < 0) - goto error_media_entity; - /* * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. @@ -1759,9 +1755,15 @@ static int imx355_probe(struct i2c_client *client) pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&imx355->sd); + if (ret < 0) + goto error_media_entity_runtime_pm; + return 0; -error_media_entity: +error_media_entity_runtime_pm: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&imx355->sd.entity); error_handler_free: From 47a78052db51b16e8045524fbf33373b58f1323b Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Wed, 22 Nov 2023 17:46:07 +0800 Subject: [PATCH 2351/7721] media: ov01a10: Enable runtime PM before registering async sub-device As the sensor device maybe accessible right after its async sub-device is registered, such as ipu-bridge will try to power up sensor by sensor's client device's runtime PM from the async notifier callback, if runtime PM is not enabled, it will fail. So runtime PM should be ready before its async sub-device is registered and accessible by others. It also sets the runtime PM status to active as the sensor was turned on by i2c-core. Fixes: 0827b58dabff ("media: i2c: add ov01a10 image sensor driver") Cc: stable@vger.kernel.org Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov01a10.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index 7cca9294ea31..5606437f37d0 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -862,6 +862,7 @@ static void ov01a10_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); } static int ov01a10_probe(struct i2c_client *client) @@ -909,17 +910,26 @@ static int ov01a10_probe(struct i2c_client *client) goto err_media_entity_cleanup; } - ret = v4l2_async_register_subdev_sensor(&ov01a10->sd); - if (ret < 0) { - dev_err(dev, "Failed to register subdev: %d\n", ret); - goto err_media_entity_cleanup; - } - + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); pm_runtime_enable(dev); pm_runtime_idle(dev); + ret = v4l2_async_register_subdev_sensor(&ov01a10->sd); + if (ret < 0) { + dev_err(dev, "Failed to register subdev: %d\n", ret); + goto err_pm_disable; + } + return 0; +err_pm_disable: + pm_runtime_disable(dev); + pm_runtime_set_suspended(&client->dev); + err_media_entity_cleanup: media_entity_cleanup(&ov01a10->sd.entity); From 7b0454cfd8edb3509619407c3b9f78a6d0dee1a5 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Wed, 22 Nov 2023 17:46:08 +0800 Subject: [PATCH 2352/7721] media: ov13b10: Enable runtime PM before registering async sub-device As the sensor device maybe accessible right after its async sub-device is registered, such as ipu-bridge will try to power up sensor by sensor's client device's runtime PM from the async notifier callback, if runtime PM is not enabled, it will fail. So runtime PM should be ready before its async sub-device is registered and accessible by others. Fixes: 7ee850546822 ("media: Add sensor driver support for the ov13b10 camera.") Cc: stable@vger.kernel.org Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13b10.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index c06411d5ee2b..73c844aa5697 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -1554,24 +1554,27 @@ static int ov13b10_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor(&ov13b->sd); - if (ret < 0) - goto error_media_entity; /* * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&ov13b->sd); + if (ret < 0) + goto error_media_entity_runtime_pm; + return 0; -error_media_entity: +error_media_entity_runtime_pm: + pm_runtime_disable(&client->dev); + if (full_power) + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&ov13b->sd.entity); error_handler_free: @@ -1594,6 +1597,7 @@ static void ov13b10_remove(struct i2c_client *client) ov13b10_free_controls(ov13b); pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend, From e242e9c144050ed120cf666642ba96b7c4462a4c Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Wed, 22 Nov 2023 17:46:09 +0800 Subject: [PATCH 2353/7721] media: ov9734: Enable runtime PM before registering async sub-device As the sensor device maybe accessible right after its async sub-device is registered, such as ipu-bridge will try to power up sensor by sensor's client device's runtime PM from the async notifier callback, if runtime PM is not enabled, it will fail. So runtime PM should be ready before its async sub-device is registered and accessible by others. Fixes: d3f863a63fe4 ("media: i2c: Add ov9734 image sensor driver") Cc: stable@vger.kernel.org Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9734.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index 2b766bfc98fc..d99728597431 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -893,6 +893,7 @@ static void ov9734_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); mutex_destroy(&ov9734->mutex); } @@ -938,13 +939,6 @@ static int ov9734_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor(&ov9734->sd); - if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", - ret); - goto probe_error_media_entity_cleanup; - } - /* * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. @@ -953,9 +947,18 @@ static int ov9734_probe(struct i2c_client *client) pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&ov9734->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup_pm; + } + return 0; -probe_error_media_entity_cleanup: +probe_error_media_entity_cleanup_pm: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&ov9734->sd.entity); probe_error_v4l2_ctrl_handler_free: From ff0fcda15feb4cc1815656fecbe15bd33f37c4f2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 27 Oct 2023 11:44:05 +0300 Subject: [PATCH 2354/7721] media: ccs: Print ireal and float limits converted to integers A number of CCS register value limits are in ireal or float format. Also convert them to integers for easier interpretation. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 92ef98a2b951..6fd162fe394a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -172,6 +172,8 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; + sensor->ccs_limits = alloc; + for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { u32 reg = ccs_limits[i].reg; unsigned int width = ccs_reg_width(reg); @@ -186,6 +188,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) for (j = 0; j < ccs_limits[i].size / width; j++, reg += width, ptr += width) { + char str[16] = ""; u32 val; ret = ccs_read_addr_noconv(sensor, reg, &val); @@ -204,8 +207,15 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) ccs_assign_limit(ptr, width, val); - dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", - reg, ccs_limits[i].name, val, val); +#ifdef CONFIG_DYNAMIC_DEBUG + if (reg & (CCS_FL_FLOAT_IREAL | CCS_FL_IREAL)) + snprintf(str, sizeof(str), ", %u", + ccs_reg_conv(sensor, reg, val)); +#endif + + dev_dbg(&client->dev, + "0x%8.8x \"%s\" = %u, 0x%x%s\n", + reg, ccs_limits[i].name, val, val, str); } if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) @@ -222,14 +232,13 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) goto out_err; } - sensor->ccs_limits = alloc; - if (CCS_LIM(sensor, SCALER_N_MIN) < 16) ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); return 0; out_err: + sensor->ccs_limits = NULL; kfree(alloc); return ret; From 0e7f68fe16022fc424fc7244287fe23c7c2fe862 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 1 Nov 2023 10:22:20 +0200 Subject: [PATCH 2355/7721] media: imx319: Enable runtime PM before registering async sub-device As the sensor may be accessible right after its async sub-device is registered, enable runtime PM before doing so. Signed-off-by: Sakari Ailus Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx319.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 420984382173..e47eff672e0c 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2463,19 +2463,21 @@ static int imx319_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor(&imx319->sd); - if (ret < 0) - goto error_media_entity; - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&imx319->sd); + if (ret < 0) + goto error_media_entity_pm; + return 0; -error_media_entity: +error_media_entity_pm: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&imx319->sd.entity); error_handler_free: From 6a6e49f89297cdf2c8c4deec54395179643b4a05 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 1 Nov 2023 10:00:05 +0200 Subject: [PATCH 2356/7721] media: Documentation: Initialisation finishes before subdev registration Document that sub-device initialisation needs to complete before the async sub-device is registered as there is no further driver action needed before the sensor becomes accessible via the UAPI. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/camera-sensor.rst | 3 ++- Documentation/driver-api/media/v4l2-subdev.rst | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 6456145f96ed..7a3c610e4c7b 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -60,7 +60,8 @@ management over the pipeline. Camera sensor drivers are responsible for controlling the power state of the device they otherwise control as well. They shall use runtime PM to manage power states. Runtime PM shall be enabled at probe time and disabled at remove -time. Drivers should enable runtime PM autosuspend. +time. Drivers should enable runtime PM autosuspend. Also see +:ref:`async sub-device registration `. The runtime PM handlers shall handle clocks, regulators, GPIOs, and other system resources required to power the sensor up and down. For drivers that diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index a62e4aff31be..1db2ba27c54c 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -181,6 +181,8 @@ You can unregister a sub-device using: Afterwards the subdev module can be unloaded and :c:type:`sd `->dev == ``NULL``. +.. _media-registering-async-subdevs: + Registering asynchronous sub-devices ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -195,6 +197,11 @@ performed using the :c:func:`v4l2_async_unregister_subdev` call. Subdevices registered this way are stored in a global list of subdevices, ready to be picked up by bridge drivers. +Drivers must complete all initialization of the sub-device before +registering it using :c:func:`v4l2_async_register_subdev`, including +enabling runtime PM. This is because the sub-device becomes accessible +as soon as it gets registered. + Asynchronous sub-device notifiers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 9641e8019ae8349c7a487e5165469240257410cd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Oct 2023 12:16:43 +0300 Subject: [PATCH 2357/7721] media: microchip-isc: Remove dead code in pipeline validation The isc_try_fse() function, called from isc_validate(), takes two parameters, an isc_device pointer, and a v4l2_subdev_state pointer. The isc_device is accessed but not modified by the function. The state is modified, including the struct v4l2_subdev_pad_config array it points to, but they are then never used by the caller. Furthermore, the V4L2 subdev operation called by isc_try_fse() doesn't modify the subdev it is called on. The isc_try_fse() function has thus no effect, and can just be dropped. Signed-off-by: Laurent Pinchart Reviewed-by: Eugen Hristev Tested-by: Eugen Hristev [Sakari Ailus: Resolve conflicts due to API changes.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/microchip/microchip-isc-base.c | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 3fba0e2844b6..540cb1378289 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -851,40 +851,6 @@ static int isc_try_configure_pipeline(struct isc_device *isc) return 0; } -static void isc_try_fse(struct isc_device *isc, - struct v4l2_subdev_state *sd_state) -{ - struct v4l2_rect *try_crop = - v4l2_subdev_state_get_crop(sd_state, 0); - struct v4l2_subdev_frame_size_enum fse = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - int ret; - - /* - * If we do not know yet which format the subdev is using, we cannot - * do anything. - */ - if (!isc->config.sd_format) - return; - - fse.code = isc->try_config.sd_format->mbus_code; - - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, - sd_state, &fse); - /* - * Attempt to obtain format size from subdev. If not available, - * just use the maximum ISC can receive. - */ - if (ret) { - try_crop->width = isc->max_width; - try_crop->height = isc->max_height; - } else { - try_crop->width = fse.max_width; - try_crop->height = fse.max_height; - } -} - static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f) { struct v4l2_pix_format *pixfmt = &f->fmt.pix; @@ -946,10 +912,6 @@ static int isc_validate(struct isc_device *isc) .which = V4L2_SUBDEV_FORMAT_ACTIVE, .pad = isc->remote_pad, }; - struct v4l2_subdev_pad_config pad_cfg = {}; - struct v4l2_subdev_state pad_state = { - .pads = &pad_cfg, - }; /* Get current format from subdev */ ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL, @@ -1010,9 +972,6 @@ static int isc_validate(struct isc_device *isc) if (ret) return ret; - /* Obtain frame sizes if possible to have crop requirements ready */ - isc_try_fse(isc, &pad_state); - /* Configure ISC pipeline for the config */ ret = isc_try_configure_pipeline(isc); if (ret) From eba5058633b4d11e2a4d65eae9f1fce0b96365d9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 10:45:30 +0200 Subject: [PATCH 2358/7721] media: v4l: cci: Include linux/bits.h linux/bits.h is needed for GENMASK(). Include it. Signed-off-by: Sakari Ailus Reviewed-by: Hans de Goede Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- include/media/v4l2-cci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h index 0f6803e4b17e..f2c2962e936b 100644 --- a/include/media/v4l2-cci.h +++ b/include/media/v4l2-cci.h @@ -7,6 +7,7 @@ #ifndef _V4L2_CCI_H #define _V4L2_CCI_H +#include #include struct i2c_client; From 94ed00981b5167e22f66fd5bfedcc7cc7fd72551 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 11:31:13 +0200 Subject: [PATCH 2359/7721] media: v4l: cci: Add driver-private bit definitions Provide a few bits for drivers to store private information on register definitions. Signed-off-by: Sakari Ailus Reviewed-by: Hans de Goede Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- include/media/v4l2-cci.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h index f2c2962e936b..ee469f03e440 100644 --- a/include/media/v4l2-cci.h +++ b/include/media/v4l2-cci.h @@ -33,6 +33,11 @@ struct cci_reg_sequence { #define CCI_REG_ADDR_MASK GENMASK(15, 0) #define CCI_REG_WIDTH_SHIFT 16 #define CCI_REG_WIDTH_MASK GENMASK(19, 16) +/* + * Private CCI register flags, for the use of drivers. + */ +#define CCI_REG_PRIVATE_SHIFT 28U +#define CCI_REG_PRIVATE_MASK GENMASK(31U, CCI_REG_PRIVATE_SHIFT) #define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x)) #define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x)) From cd93cc245dfe334c38da98c14b34f9597e1b4ea6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 17:42:40 +0200 Subject: [PATCH 2360/7721] media: v4l: cci: Add macros to obtain register width and address Add CCI_REG_WIDTH() macro to obtain register width in bits and similarly, CCI_REG_WIDTH_BYTES() to obtain it in bytes. Also add CCI_REG_ADDR() macro to obtain the address of a register. Use both macros in v4l2-cci.c, too. Signed-off-by: Sakari Ailus Reviewed-by: Hans de Goede Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-cci.c | 8 ++++---- include/media/v4l2-cci.h | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c index bc2dbec019b0..3179160abde3 100644 --- a/drivers/media/v4l2-core/v4l2-cci.c +++ b/drivers/media/v4l2-core/v4l2-cci.c @@ -25,8 +25,8 @@ int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) if (err && *err) return *err; - len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); - reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); + len = CCI_REG_WIDTH_BYTES(reg); + reg = CCI_REG_ADDR(reg); ret = regmap_bulk_read(map, reg, buf, len); if (ret) { @@ -75,8 +75,8 @@ int cci_write(struct regmap *map, u32 reg, u64 val, int *err) if (err && *err) return *err; - len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); - reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); + len = CCI_REG_WIDTH_BYTES(reg); + reg = CCI_REG_ADDR(reg); switch (len) { case 1: diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h index ee469f03e440..406772a4e32e 100644 --- a/include/media/v4l2-cci.h +++ b/include/media/v4l2-cci.h @@ -7,6 +7,7 @@ #ifndef _V4L2_CCI_H #define _V4L2_CCI_H +#include #include #include @@ -39,6 +40,10 @@ struct cci_reg_sequence { #define CCI_REG_PRIVATE_SHIFT 28U #define CCI_REG_PRIVATE_MASK GENMASK(31U, CCI_REG_PRIVATE_SHIFT) +#define CCI_REG_WIDTH_BYTES(x) FIELD_GET(CCI_REG_WIDTH_MASK, x) +#define CCI_REG_WIDTH(x) (CCI_REG_WIDTH_BYTES(x) << 3) +#define CCI_REG_ADDR(x) FIELD_GET(CCI_REG_ADDR_MASK, x) + #define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x)) #define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x)) #define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x)) From 5d6ce399d986dcf40d331d825fb2e4f8d0329865 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 11:32:46 +0200 Subject: [PATCH 2361/7721] media: ccs: Generate V4L2 CCI compliant register definitions Generate register definitions that are fit for use with V4L2 CCI. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../driver-api/media/drivers/ccs/mk-ccs-regs | 104 +++++++++++++----- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs index 2a4edc7e051a..3d3152b45821 100755 --- a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs +++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs @@ -82,14 +82,6 @@ for my $fh ($H, $LH) { print $fh "/* $license */\n$copyright$note\n"; } -sub bit_def($) { - my $bit = shift @_; - - return "BIT($bit)" if defined $kernel; - return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/; - return "(1U << ($bit))"; -} - print $H <\n\n" if defined $kernel; - print $H < + +#include + EOF - ; + if defined $kernel; -print $H "#define CCS_FL_16BIT " . bit_def("CCS_FL_BASE") . "\n"; -print $H "#define CCS_FL_32BIT " . bit_def("CCS_FL_BASE + 1") . "\n"; -print $H "#define CCS_FL_FLOAT_IREAL " . bit_def("CCS_FL_BASE + 2") . "\n"; -print $H "#define CCS_FL_IREAL " . bit_def("CCS_FL_BASE + 3") . "\n"; +print $H "#define CCS_FL_BASE " . + (defined $kernel ? "CCI_REG_PRIVATE_SHIFT" : 16) . "\n"; + +my $flag = -1; +my $all_flags; + +sub bit_def($) { + my $bit = shift @_; + + if (defined $kernel) { + return "BIT$bit" if $bit =~ /^\(.*\)$/; + return "BIT($bit)"; + } + return "(1U << $bit)"; +} + +sub flag_str($$) { + my ($flag, $check) = @_; + + $$flag++; + + my $flag_str = !$$flag ? "CCS_FL_BASE" : "(CCS_FL_BASE + $$flag)"; + + $flag_str = bit_def($flag_str); + + $$check .= " | " if defined $$check; + + $$check .= $flag_str; + + return $flag_str; +} + +if (! defined $kernel) { + print $H "#define CCS_FL_16BIT " . flag_str(\$flag, \$all_flags) . "\n"; + print $H "#define CCS_FL_32BIT " . flag_str(\$flag, \$all_flags) . "\n"; +} + +print $H "#define CCS_FL_FLOAT_IREAL " . flag_str(\$flag, \$all_flags) . "\n"; +print $H "#define CCS_FL_IREAL " . flag_str(\$flag, \$all_flags) . "\n"; +print $H "#define CCS_BUILD_BUG \\ + BUILD_BUG_ON(~CCI_REG_PRIVATE_MASK & ($all_flags))\n" + if defined $kernel; print $H < @@ -189,12 +221,12 @@ sub tabconv($) { return (join "\n", @l) . "\n"; } -sub elem_size(@) { +sub elem_bits(@) { my @flags = @_; - return 2 if grep /^16$/, @flags; - return 4 if grep /^32$/, @flags; - return 1; + return 16 if grep /^16$/, @flags; + return 32 if grep /^32$/, @flags; + return 8; } sub arr_size($) { @@ -296,9 +328,13 @@ while (<$R>) { next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}}; - my $reg_formula = "($this{addr}"; + my $reg_formula = "$this{addr}"; my $lim_formula; + chop $reg_formula; + + $reg_formula = "(" . $reg_formula if $this{flagstring} ne ""; + foreach my $arg (@{$this{args}}) { my $d = $h->{$arg}->{discontig}; my $times = $h->{$arg}->{elsize} != 1 ? @@ -315,11 +351,13 @@ while (<$R>) { $lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times"; } - $reg_formula .= ")\n"; + $reg_formula .= ")"; $lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i; print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) . - $this{arglist}, $reg_formula); + $this{arglist}, $reg_formula . + (($this{flagstring} eq "") ? "" : + " | " . $this{flagstring} . ")") . "\n"); print $H tabconv $hdr_data; undef $hdr_data; @@ -369,16 +407,23 @@ while (<$R>) { $name =~ s/[,\.-]/_/g; my $flagstring = ""; - my $size = elem_size(@flags); - $flagstring .= "| CCS_FL_16BIT " if $size eq "2"; - $flagstring .= "| CCS_FL_32BIT " if $size eq "4"; + my $bits = elem_bits(@flags); + if (! defined $kernel) { + $flagstring .= "| CCS_FL_16BIT " if $bits == 16; + $flagstring .= "| CCS_FL_32BIT " if $bits == 32; + } $flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags; $flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags; $flagstring =~ s/^\| //; $flagstring =~ s/ $//; $flagstring = "($flagstring)" if $flagstring =~ /\|/; my $base_addr = $addr; - $addr = "($addr | $flagstring)" if $flagstring ne ""; + $addr = "CCI_REG$bits($addr)" if defined $kernel; + + if ($flagstring ne "" && !@$args) { + $addr = "($addr | $flagstring)"; + $flagstring = ""; + } my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : ""; $hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr @@ -388,11 +433,12 @@ while (<$R>) { %this = ( name => $name, addr => $addr, + flagstring => $flagstring, base_addr => $base_addr, argparams => {}, args => $args, arglist => $arglist, - elsize => $size, + elsize => $bits / 8, ); if (!@$args) { From d180509cca583146f5e6386cbc28c4297d1d7aad Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 11:37:21 +0200 Subject: [PATCH 2362/7721] media: ccs: Better separate CCS static data access Separate CCS static data read-only register access in ccs-reg-access.c by naming them differently. The code in this file generally deals with reading and writing registers where as static data (when it comes to ccs_static_data_read_ro_reg()) contains the read-only register values but no hardware registers are accessed in that case. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-reg-access.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 25993445f4fe..03daaa8310a6 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -197,8 +197,8 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, return 0; } -static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs, - u32 reg, u32 *val) +static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs, + u32 reg, u32 *val) { unsigned int width = ccs_reg_width(reg); size_t i; @@ -235,16 +235,17 @@ static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs, return -ENOENT; } -static int ccs_read_data(struct ccs_sensor *sensor, u32 reg, u32 *val) +static int +ccs_static_data_read_ro_reg(struct ccs_sensor *sensor, u32 reg, u32 *val) { - if (!__ccs_read_data(sensor->sdata.sensor_read_only_regs, - sensor->sdata.num_sensor_read_only_regs, - reg, val)) + if (!__ccs_static_data_read_ro_reg(sensor->sdata.sensor_read_only_regs, + sensor->sdata.num_sensor_read_only_regs, + reg, val)) return 0; - return __ccs_read_data(sensor->mdata.module_read_only_regs, - sensor->mdata.num_module_read_only_regs, - reg, val); + return __ccs_static_data_read_ro_reg(sensor->mdata.module_read_only_regs, + sensor->mdata.num_module_read_only_regs, + reg, val); } static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, @@ -253,7 +254,7 @@ static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, int rval; if (data) { - rval = ccs_read_data(sensor, reg, val); + rval = ccs_static_data_read_ro_reg(sensor, reg, val); if (!rval) return 0; } From 529322112a3bcce5906ad8f26b7a7c51e93d0e5f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Nov 2023 12:46:42 +0200 Subject: [PATCH 2363/7721] media: ccs: Use V4L2 CCI for accessing sensor registers Use V4L2 CCI for accessing device's registers. The 8-bit compatibility read option is removed but this is supported by regmap through other means. Also the CCS register definitions are re-generated with V4L2 CCI definitions. The older SMIA++ register definitions have been manually converted. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 84 +-- drivers/media/i2c/ccs/ccs-reg-access.c | 192 +---- drivers/media/i2c/ccs/ccs-regs.h | 906 +++++++++++----------- drivers/media/i2c/ccs/ccs.h | 2 + drivers/media/i2c/ccs/smiapp-reg-defs.h | 951 ++++++++++++------------ 5 files changed, 999 insertions(+), 1136 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6fd162fe394a..e21287d50c15 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -25,8 +25,9 @@ #include #include #include -#include +#include #include +#include #include #include "ccs.h" @@ -98,7 +99,7 @@ static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit, linfo = &ccs_limits[ccs_limit_offsets[limit].info]; if (WARN_ON(!sensor->ccs_limits) || - WARN_ON(offset + ccs_reg_width(linfo->reg) > + WARN_ON(offset + CCI_REG_WIDTH_BYTES(linfo->reg) > ccs_limit_offsets[limit + 1].lim)) return -EINVAL; @@ -124,7 +125,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor, dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n", linfo->reg, linfo->name, offset, val, val); - ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); + ccs_assign_limit(ptr, CCI_REG_WIDTH_BYTES(linfo->reg), val); } u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, @@ -138,7 +139,7 @@ u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, if (ret) return 0; - switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { + switch (CCI_REG_WIDTH_BYTES(ccs_limits[ccs_limit_offsets[limit].info].reg)) { case sizeof(u8): val = *(u8 *)ptr; break; @@ -176,7 +177,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { u32 reg = ccs_limits[i].reg; - unsigned int width = ccs_reg_width(reg); + unsigned int width = CCI_REG_WIDTH_BYTES(reg); unsigned int j; if (l == CCS_L_LAST) { @@ -2725,66 +2726,54 @@ static int ccs_identify_module(struct ccs_sensor *sensor) rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, &minfo->mipi_manufacturer_id); if (!rval && !minfo->mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - SMIAPP_REG_U8_MANUFACTURER_ID, - &minfo->smia_manufacturer_id); + rval = ccs_read_addr(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, + &minfo->smia_manufacturer_id); if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, - &minfo->model_id); + rval = ccs_read(sensor, MODULE_MODEL_ID, &minfo->model_id); if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MAJOR, - &rev); + rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MAJOR, &rev); if (!rval) { - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MINOR, - &minfo->revision_number); + rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MINOR, + &minfo->revision_number); minfo->revision_number |= rev << 8; } if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, - &minfo->module_year); + rval = ccs_read(sensor, MODULE_DATE_YEAR, &minfo->module_year); if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, - &minfo->module_month); + rval = ccs_read(sensor, MODULE_DATE_MONTH, + &minfo->module_month); if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, - &minfo->module_day); + rval = ccs_read(sensor, MODULE_DATE_DAY, &minfo->module_day); /* Sensor info */ if (!rval) rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, &minfo->sensor_mipi_manufacturer_id); if (!rval && !minfo->sensor_mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MANUFACTURER_ID, - &minfo->sensor_smia_manufacturer_id); + rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, + &minfo->sensor_smia_manufacturer_id); if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MODEL_ID, - &minfo->sensor_model_id); + rval = ccs_read(sensor, SENSOR_MODEL_ID, + &minfo->sensor_model_id); if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_REVISION_NUMBER, - &minfo->sensor_revision_number); + rval = ccs_read(sensor, SENSOR_REVISION_NUMBER, + &minfo->sensor_revision_number); if (!rval && !minfo->sensor_revision_number) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_REVISION_NUMBER_16, - &minfo->sensor_revision_number); + rval = ccs_read(sensor, SENSOR_REVISION_NUMBER_16, + &minfo->sensor_revision_number); if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_FIRMWARE_VERSION, - &minfo->sensor_firmware_version); + rval = ccs_read(sensor, SENSOR_FIRMWARE_VERSION, + &minfo->sensor_firmware_version); /* SMIA */ if (!rval) rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, - &minfo->smia_version); + rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIA_VERSION, + &minfo->smia_version); if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, - &minfo->smiapp_version); + rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, + &minfo->smiapp_version); if (rval) { dev_err(&client->dev, "sensor detection failed\n"); @@ -3318,6 +3307,13 @@ static int ccs_probe(struct i2c_client *client) if (IS_ERR(sensor->xshutdown)) return PTR_ERR(sensor->xshutdown); + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) { + dev_err(&client->dev, "can't initialise CCI (%ld)\n", + PTR_ERR(sensor->regmap)); + return PTR_ERR(sensor->regmap); + } + rval = ccs_power_on(&client->dev); if (rval < 0) return rval; @@ -3648,12 +3644,16 @@ static int ccs_module_init(void) { unsigned int i, l; + CCS_BUILD_BUG; + for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { ccs_limit_offsets[l + 1].lim = ALIGN(ccs_limit_offsets[l].lim + ccs_limits[i].size, - ccs_reg_width(ccs_limits[i + 1].reg)); + ccs_limits[i + 1].reg ? + CCI_REG_WIDTH_BYTES(ccs_limits[i + 1].reg) : + 1U); ccs_limit_offsets[l].info = i; l++; } else { diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 03daaa8310a6..ed79075505e6 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -62,87 +62,6 @@ static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat) } -/* - * Read a 8/16/32-bit i2c register. The value is returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len, - u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data_buf[sizeof(u32)] = { 0 }; - unsigned char offset_buf[sizeof(u16)]; - int r; - - if (len > sizeof(data_buf)) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(offset_buf); - msg.buf = offset_buf; - put_unaligned_be16(reg, offset_buf); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - msg.len = len; - msg.flags = I2C_M_RD; - msg.buf = &data_buf[sizeof(data_buf) - len]; - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - *val = get_unaligned_be32(data_buf); - - return 0; - -err: - dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); - - return r; -} - -/* Read a register using 8-bit access only. */ -static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg, - u16 len, u32 *val) -{ - unsigned int i; - int rval; - - *val = 0; - - for (i = 0; i < len; i++) { - u32 val8; - - rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); - if (rval < 0) - return rval; - *val |= val8 << ((len - i - 1) << 3); - } - - return 0; -} - -unsigned int ccs_reg_width(u32 reg) -{ - if (reg & CCS_FL_16BIT) - return sizeof(u16); - if (reg & CCS_FL_32BIT) - return sizeof(u32); - - return sizeof(u8); -} - static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val) { if (val >> 10 > U32_MAX / 15625) { @@ -178,21 +97,14 @@ u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val) static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, bool only8, bool conv) { - unsigned int len = ccs_reg_width(reg); + u64 __val; int rval; - if (!only8) - rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val); - else - rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len, - val); + rval = cci_read(sensor->regmap, reg, &__val, NULL); if (rval < 0) return rval; - if (!conv) - return 0; - - *val = ccs_reg_conv(sensor, reg, *val); + *val = conv ? ccs_reg_conv(sensor, reg, __val) : __val; return 0; } @@ -200,7 +112,7 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs, u32 reg, u32 *val) { - unsigned int width = ccs_reg_width(reg); + unsigned int width = CCI_REG_WIDTH_BYTES(reg); size_t i; for (i = 0; i < num_regs; i++, regs++) { @@ -292,71 +204,13 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val) return ccs_read_addr_raw(sensor, reg, val, false, true, false, true); } -static int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg) -{ - unsigned int retries; - int r; - - for (retries = 0; retries < 10; retries++) { - /* - * Due to unknown reason sensor stops responding. This - * loop is a temporaty solution until the root cause - * is found. - */ - r = i2c_transfer(client->adapter, msg, 1); - if (r != 1) { - usleep_range(1000, 2000); - continue; - } - - if (retries) - dev_err(&client->dev, - "sensor i2c stall encountered. retries: %d\n", - retries); - return 0; - } - - return r; -} - -int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data[6]; - unsigned int len = ccs_reg_width(reg); - int r; - - if (len > sizeof(data) - 2) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; /* Write */ - msg.len = 2 + len; - msg.buf = data; - - put_unaligned_be16(CCS_REG_ADDR(reg), data); - put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); - - dev_dbg(&client->dev, "writing reg 0x%4.4x value 0x%*.*x (%u)\n", - CCS_REG_ADDR(reg), ccs_reg_width(reg) << 1, - ccs_reg_width(reg) << 1, val, val); - - r = ccs_write_retry(client, &msg); - if (r) - dev_err(&client->dev, - "wrote 0x%x to offset 0x%x error %d\n", val, - CCS_REG_ADDR(reg), r); - - return r; -} - /* * Write to a 8/16-bit register. * Returns zero if successful, or non-zero otherwise. */ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) { + unsigned int retries = 10; int rval; rval = ccs_call_quirk(sensor, reg_access, true, ®, &val); @@ -365,7 +219,13 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) if (rval < 0) return rval; - return ccs_write_addr_no_quirk(sensor, reg, val); + rval = 0; + do { + if (cci_write(sensor->regmap, reg, val, &rval)) + fsleep(1000); + } while (rval && --retries); + + return rval; } #define MAX_WRITE_LEN 32U @@ -374,40 +234,38 @@ int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs, size_t num_regs) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned char buf[2 + MAX_WRITE_LEN]; - struct i2c_msg msg = { - .addr = client->addr, - .buf = buf, - }; size_t i; for (i = 0; i < num_regs; i++, regs++) { unsigned char *regdata = regs->value; unsigned int j; + int len; - for (j = 0; j < regs->len; - j += msg.len - 2, regdata += msg.len - 2) { + for (j = 0; j < regs->len; j += len, regdata += len) { char printbuf[(MAX_WRITE_LEN << 1) + 1 /* \0 */] = { 0 }; + unsigned int retries = 10; int rval; - msg.len = min(regs->len - j, MAX_WRITE_LEN); + len = min(regs->len - j, MAX_WRITE_LEN); - bin2hex(printbuf, regdata, msg.len); + bin2hex(printbuf, regdata, len); dev_dbg(&client->dev, "writing msr reg 0x%4.4x value 0x%s\n", regs->addr + j, printbuf); - put_unaligned_be16(regs->addr + j, buf); - memcpy(buf + 2, regdata, msg.len); + do { + rval = regmap_bulk_write(sensor->regmap, + regs->addr + j, + regdata, len); + if (rval) + fsleep(1000); + } while (rval && --retries); - msg.len += 2; - - rval = ccs_write_retry(client, &msg); if (rval) { dev_err(&client->dev, "error writing %u octets to address 0x%4.4x\n", - msg.len, regs->addr + j); + len, regs->addr + j); return rval; } } diff --git a/drivers/media/i2c/ccs/ccs-regs.h b/drivers/media/i2c/ccs/ccs-regs.h index 6ce84c5ecf20..7b5dbc86e4cd 100644 --- a/drivers/media/i2c/ccs/ccs-regs.h +++ b/drivers/media/i2c/ccs/ccs-regs.h @@ -10,59 +10,59 @@ #include -#define CCS_FL_BASE 16 -#define CCS_FL_16BIT BIT(CCS_FL_BASE) -#define CCS_FL_32BIT BIT(CCS_FL_BASE + 1) -#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE + 2) -#define CCS_FL_IREAL BIT(CCS_FL_BASE + 3) -#define CCS_R_ADDR(r) ((r) & 0xffff) +#include -#define CCS_R_MODULE_MODEL_ID (0x0000 | CCS_FL_16BIT) -#define CCS_R_MODULE_REVISION_NUMBER_MAJOR 0x0002 -#define CCS_R_FRAME_COUNT 0x0005 -#define CCS_R_PIXEL_ORDER 0x0006 +#define CCS_FL_BASE CCI_REG_PRIVATE_SHIFT +#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE) +#define CCS_FL_IREAL BIT(CCS_FL_BASE + 1) +#define CCS_BUILD_BUG \ + BUILD_BUG_ON(~CCI_REG_PRIVATE_MASK & (BIT(CCS_FL_BASE) | BIT(CCS_FL_BASE + 1))) +#define CCS_R_MODULE_MODEL_ID CCI_REG16(0x0000) +#define CCS_R_MODULE_REVISION_NUMBER_MAJOR CCI_REG8(0x0002) +#define CCS_R_FRAME_COUNT CCI_REG8(0x0005) +#define CCS_R_PIXEL_ORDER CCI_REG8(0x0006) #define CCS_PIXEL_ORDER_GRBG 0U #define CCS_PIXEL_ORDER_RGGB 1U #define CCS_PIXEL_ORDER_BGGR 2U #define CCS_PIXEL_ORDER_GBRG 3U -#define CCS_R_MIPI_CCS_VERSION 0x0007 +#define CCS_R_MIPI_CCS_VERSION CCI_REG8(0x0007) #define CCS_MIPI_CCS_VERSION_V1_0 0x10 #define CCS_MIPI_CCS_VERSION_V1_1 0x11 #define CCS_MIPI_CCS_VERSION_MAJOR_SHIFT 4U #define CCS_MIPI_CCS_VERSION_MAJOR_MASK 0xf0 #define CCS_MIPI_CCS_VERSION_MINOR_SHIFT 0U #define CCS_MIPI_CCS_VERSION_MINOR_MASK 0xf -#define CCS_R_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) -#define CCS_R_MODULE_MANUFACTURER_ID (0x000e | CCS_FL_16BIT) -#define CCS_R_MODULE_REVISION_NUMBER_MINOR 0x0010 -#define CCS_R_MODULE_DATE_YEAR 0x0012 -#define CCS_R_MODULE_DATE_MONTH 0x0013 -#define CCS_R_MODULE_DATE_DAY 0x0014 -#define CCS_R_MODULE_DATE_PHASE 0x0015 +#define CCS_R_DATA_PEDESTAL CCI_REG16(0x0008) +#define CCS_R_MODULE_MANUFACTURER_ID CCI_REG16(0x000e) +#define CCS_R_MODULE_REVISION_NUMBER_MINOR CCI_REG8(0x0010) +#define CCS_R_MODULE_DATE_YEAR CCI_REG8(0x0012) +#define CCS_R_MODULE_DATE_MONTH CCI_REG8(0x0013) +#define CCS_R_MODULE_DATE_DAY CCI_REG8(0x0014) +#define CCS_R_MODULE_DATE_PHASE CCI_REG8(0x0015) #define CCS_MODULE_DATE_PHASE_SHIFT 0U #define CCS_MODULE_DATE_PHASE_MASK 0x7 #define CCS_MODULE_DATE_PHASE_TS 0U #define CCS_MODULE_DATE_PHASE_ES 1U #define CCS_MODULE_DATE_PHASE_CS 2U #define CCS_MODULE_DATE_PHASE_MP 3U -#define CCS_R_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) -#define CCS_R_SENSOR_REVISION_NUMBER 0x0018 -#define CCS_R_SENSOR_FIRMWARE_VERSION 0x001a -#define CCS_R_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) -#define CCS_R_SENSOR_MANUFACTURER_ID (0x0020 | CCS_FL_16BIT) -#define CCS_R_SENSOR_REVISION_NUMBER_16 (0x0022 | CCS_FL_16BIT) -#define CCS_R_FRAME_FORMAT_MODEL_TYPE 0x0040 +#define CCS_R_SENSOR_MODEL_ID CCI_REG16(0x0016) +#define CCS_R_SENSOR_REVISION_NUMBER CCI_REG8(0x0018) +#define CCS_R_SENSOR_FIRMWARE_VERSION CCI_REG8(0x001a) +#define CCS_R_SERIAL_NUMBER CCI_REG32(0x001c) +#define CCS_R_SENSOR_MANUFACTURER_ID CCI_REG16(0x0020) +#define CCS_R_SENSOR_REVISION_NUMBER_16 CCI_REG16(0x0022) +#define CCS_R_FRAME_FORMAT_MODEL_TYPE CCI_REG8(0x0040) #define CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE 1U #define CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE 2U -#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 +#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE CCI_REG8(0x0041) #define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U #define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf #define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U #define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 -#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) ((0x0042 | CCS_FL_16BIT) + (n) * 2) +#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) CCI_REG16(0x0042 + (n) * 2) #define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MIN_N 0U #define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MAX_N 14U -#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 | CCS_FL_32BIT) + (n) * 4) +#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) CCI_REG32(0x0060 + (n) * 4) #define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_SHIFT 0U #define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK 0xfff #define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT 12U @@ -97,91 +97,91 @@ #define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_4 12U #define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_5 13U #define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_6 14U -#define CCS_R_ANALOG_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CAPABILITY CCI_REG16(0x0080) #define CCS_ANALOG_GAIN_CAPABILITY_GLOBAL 0U #define CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL 2U -#define CCS_R_ANALOG_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_TYPE (0x008a | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_M0 (0x008c | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_C0 (0x008e | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_M1 (0x0090 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_C1 (0x0092 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_MIN (0x0094 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_MAX (0x0096 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE (0x0098 | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN (0x009a | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX (0x009c | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE (0x009e | CCS_FL_16BIT) -#define CCS_R_DATA_FORMAT_MODEL_TYPE 0x00c0 +#define CCS_R_ANALOG_GAIN_CODE_MIN CCI_REG16(0x0084) +#define CCS_R_ANALOG_GAIN_CODE_MAX CCI_REG16(0x0086) +#define CCS_R_ANALOG_GAIN_CODE_STEP CCI_REG16(0x0088) +#define CCS_R_ANALOG_GAIN_TYPE CCI_REG16(0x008a) +#define CCS_R_ANALOG_GAIN_M0 CCI_REG16(0x008c) +#define CCS_R_ANALOG_GAIN_C0 CCI_REG16(0x008e) +#define CCS_R_ANALOG_GAIN_M1 CCI_REG16(0x0090) +#define CCS_R_ANALOG_GAIN_C1 CCI_REG16(0x0092) +#define CCS_R_ANALOG_LINEAR_GAIN_MIN CCI_REG16(0x0094) +#define CCS_R_ANALOG_LINEAR_GAIN_MAX CCI_REG16(0x0096) +#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE CCI_REG16(0x0098) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN CCI_REG16(0x009a) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX CCI_REG16(0x009c) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE CCI_REG16(0x009e) +#define CCS_R_DATA_FORMAT_MODEL_TYPE CCI_REG8(0x00c0) #define CCS_DATA_FORMAT_MODEL_TYPE_NORMAL 1U #define CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED 2U -#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 +#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE CCI_REG8(0x00c1) #define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U #define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf #define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U #define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 -#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 | CCS_FL_16BIT) + (n) * 2) +#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) CCI_REG16(0x00c2 + (n) * 2) #define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MIN_N 0U #define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N 15U #define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_SHIFT 0U #define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK 0xff #define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT 8U #define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_MASK 0xff00 -#define CCS_R_MODE_SELECT 0x0100 +#define CCS_R_MODE_SELECT CCI_REG8(0x0100) #define CCS_MODE_SELECT_SOFTWARE_STANDBY 0U #define CCS_MODE_SELECT_STREAMING 1U -#define CCS_R_IMAGE_ORIENTATION 0x0101 +#define CCS_R_IMAGE_ORIENTATION CCI_REG8(0x0101) #define CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR BIT(0) #define CCS_IMAGE_ORIENTATION_VERTICAL_FLIP BIT(1) -#define CCS_R_SOFTWARE_RESET 0x0103 +#define CCS_R_SOFTWARE_RESET CCI_REG8(0x0103) #define CCS_SOFTWARE_RESET_OFF 0U #define CCS_SOFTWARE_RESET_ON 1U -#define CCS_R_GROUPED_PARAMETER_HOLD 0x0104 -#define CCS_R_MASK_CORRUPTED_FRAMES 0x0105 +#define CCS_R_GROUPED_PARAMETER_HOLD CCI_REG8(0x0104) +#define CCS_R_MASK_CORRUPTED_FRAMES CCI_REG8(0x0105) #define CCS_MASK_CORRUPTED_FRAMES_ALLOW 0U #define CCS_MASK_CORRUPTED_FRAMES_MASK 1U -#define CCS_R_FAST_STANDBY_CTRL 0x0106 +#define CCS_R_FAST_STANDBY_CTRL CCI_REG8(0x0106) #define CCS_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0U #define CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION 1U -#define CCS_R_CCI_ADDRESS_CTRL 0x0107 -#define CCS_R_2ND_CCI_IF_CTRL 0x0108 +#define CCS_R_CCI_ADDRESS_CTRL CCI_REG8(0x0107) +#define CCS_R_2ND_CCI_IF_CTRL CCI_REG8(0x0108) #define CCS_2ND_CCI_IF_CTRL_ENABLE BIT(0) #define CCS_2ND_CCI_IF_CTRL_ACK BIT(1) -#define CCS_R_2ND_CCI_ADDRESS_CTRL 0x0109 -#define CCS_R_CSI_CHANNEL_IDENTIFIER 0x0110 -#define CCS_R_CSI_SIGNALING_MODE 0x0111 +#define CCS_R_2ND_CCI_ADDRESS_CTRL CCI_REG8(0x0109) +#define CCS_R_CSI_CHANNEL_IDENTIFIER CCI_REG8(0x0110) +#define CCS_R_CSI_SIGNALING_MODE CCI_REG8(0x0111) #define CCS_CSI_SIGNALING_MODE_CSI_2_DPHY 2U #define CCS_CSI_SIGNALING_MODE_CSI_2_CPHY 3U -#define CCS_R_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) -#define CCS_R_CSI_LANE_MODE 0x0114 -#define CCS_R_DPCM_FRAME_DT 0x011d -#define CCS_R_BOTTOM_EMBEDDED_DATA_DT 0x011e -#define CCS_R_BOTTOM_EMBEDDED_DATA_VC 0x011f -#define CCS_R_GAIN_MODE 0x0120 +#define CCS_R_CSI_DATA_FORMAT CCI_REG16(0x0112) +#define CCS_R_CSI_LANE_MODE CCI_REG8(0x0114) +#define CCS_R_DPCM_FRAME_DT CCI_REG8(0x011d) +#define CCS_R_BOTTOM_EMBEDDED_DATA_DT CCI_REG8(0x011e) +#define CCS_R_BOTTOM_EMBEDDED_DATA_VC CCI_REG8(0x011f) +#define CCS_R_GAIN_MODE CCI_REG8(0x0120) #define CCS_GAIN_MODE_GLOBAL 0U #define CCS_GAIN_MODE_ALTERNATE 1U -#define CCS_R_ADC_BIT_DEPTH 0x0121 -#define CCS_R_EMB_DATA_CTRL 0x0122 +#define CCS_R_ADC_BIT_DEPTH CCI_REG8(0x0121) +#define CCS_R_EMB_DATA_CTRL CCI_REG8(0x0122) #define CCS_EMB_DATA_CTRL_RAW8_PACKING_FOR_RAW16 BIT(0) #define CCS_EMB_DATA_CTRL_RAW10_PACKING_FOR_RAW20 BIT(1) #define CCS_EMB_DATA_CTRL_RAW12_PACKING_FOR_RAW24 BIT(2) -#define CCS_R_GPIO_TRIG_MODE 0x0130 -#define CCS_R_EXTCLK_FREQUENCY_MHZ (0x0136 | (CCS_FL_16BIT | CCS_FL_IREAL)) -#define CCS_R_TEMP_SENSOR_CTRL 0x0138 +#define CCS_R_GPIO_TRIG_MODE CCI_REG8(0x0130) +#define CCS_R_EXTCLK_FREQUENCY_MHZ (CCI_REG16(0x0136) | CCS_FL_IREAL) +#define CCS_R_TEMP_SENSOR_CTRL CCI_REG8(0x0138) #define CCS_TEMP_SENSOR_CTRL_ENABLE BIT(0) -#define CCS_R_TEMP_SENSOR_MODE 0x0139 -#define CCS_R_TEMP_SENSOR_OUTPUT 0x013a -#define CCS_R_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) -#define CCS_R_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL (0x0206 | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0208 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_GLOBAL (0x020e | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL (0x0216 | CCS_FL_16BIT) -#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL (0x0218 | CCS_FL_16BIT) -#define CCS_R_HDR_MODE 0x0220 +#define CCS_R_TEMP_SENSOR_MODE CCI_REG8(0x0139) +#define CCS_R_TEMP_SENSOR_OUTPUT CCI_REG8(0x013a) +#define CCS_R_FINE_INTEGRATION_TIME CCI_REG16(0x0200) +#define CCS_R_COARSE_INTEGRATION_TIME CCI_REG16(0x0202) +#define CCS_R_ANALOG_GAIN_CODE_GLOBAL CCI_REG16(0x0204) +#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL CCI_REG16(0x0206) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL CCI_REG16(0x0208) +#define CCS_R_DIGITAL_GAIN_GLOBAL CCI_REG16(0x020e) +#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL CCI_REG16(0x0216) +#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL CCI_REG16(0x0218) +#define CCS_R_HDR_MODE CCI_REG8(0x0220) #define CCS_HDR_MODE_ENABLED BIT(0) #define CCS_HDR_MODE_SEPARATE_ANALOG_GAIN BIT(1) #define CCS_HDR_MODE_UPSCALING BIT(2) @@ -189,421 +189,421 @@ #define CCS_HDR_MODE_TIMING_MODE BIT(4) #define CCS_HDR_MODE_EXPOSURE_CTRL_DIRECT BIT(5) #define CCS_HDR_MODE_SEPARATE_DIGITAL_GAIN BIT(6) -#define CCS_R_HDR_RESOLUTION_REDUCTION 0x0221 +#define CCS_R_HDR_RESOLUTION_REDUCTION CCI_REG8(0x0221) #define CCS_HDR_RESOLUTION_REDUCTION_ROW_SHIFT 0U #define CCS_HDR_RESOLUTION_REDUCTION_ROW_MASK 0xf #define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_SHIFT 4U #define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_MASK 0xf0 -#define CCS_R_EXPOSURE_RATIO 0x0222 -#define CCS_R_HDR_INTERNAL_BIT_DEPTH 0x0223 -#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME (0x0224 | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL (0x0226 | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0228 | CCS_FL_16BIT) -#define CCS_R_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) -#define CCS_R_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) -#define CCS_R_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) -#define CCS_R_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) -#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) -#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) -#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT) -#define CCS_R_OP_PLL_MULTIPLIER (0x030e | CCS_FL_16BIT) -#define CCS_R_PLL_MODE 0x0310 +#define CCS_R_EXPOSURE_RATIO CCI_REG8(0x0222) +#define CCS_R_HDR_INTERNAL_BIT_DEPTH CCI_REG8(0x0223) +#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME CCI_REG16(0x0224) +#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL CCI_REG16(0x0226) +#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL CCI_REG16(0x0228) +#define CCS_R_VT_PIX_CLK_DIV CCI_REG16(0x0300) +#define CCS_R_VT_SYS_CLK_DIV CCI_REG16(0x0302) +#define CCS_R_PRE_PLL_CLK_DIV CCI_REG16(0x0304) +#define CCS_R_PLL_MULTIPLIER CCI_REG16(0x0306) +#define CCS_R_OP_PIX_CLK_DIV CCI_REG16(0x0308) +#define CCS_R_OP_SYS_CLK_DIV CCI_REG16(0x030a) +#define CCS_R_OP_PRE_PLL_CLK_DIV CCI_REG16(0x030c) +#define CCS_R_OP_PLL_MULTIPLIER CCI_REG16(0x030e) +#define CCS_R_PLL_MODE CCI_REG8(0x0310) #define CCS_PLL_MODE_SHIFT 0U #define CCS_PLL_MODE_MASK 0x1 #define CCS_PLL_MODE_SINGLE 0U #define CCS_PLL_MODE_DUAL 1U -#define CCS_R_OP_PIX_CLK_DIV_REV (0x0312 | CCS_FL_16BIT) -#define CCS_R_OP_SYS_CLK_DIV_REV (0x0314 | CCS_FL_16BIT) -#define CCS_R_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) -#define CCS_R_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_START (0x0344 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_START (0x0346 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_END (0x0348 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_END (0x034a | CCS_FL_16BIT) -#define CCS_R_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) -#define CCS_R_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) -#define CCS_R_FRAME_LENGTH_CTRL 0x0350 +#define CCS_R_OP_PIX_CLK_DIV_REV CCI_REG16(0x0312) +#define CCS_R_OP_SYS_CLK_DIV_REV CCI_REG16(0x0314) +#define CCS_R_FRAME_LENGTH_LINES CCI_REG16(0x0340) +#define CCS_R_LINE_LENGTH_PCK CCI_REG16(0x0342) +#define CCS_R_X_ADDR_START CCI_REG16(0x0344) +#define CCS_R_Y_ADDR_START CCI_REG16(0x0346) +#define CCS_R_X_ADDR_END CCI_REG16(0x0348) +#define CCS_R_Y_ADDR_END CCI_REG16(0x034a) +#define CCS_R_X_OUTPUT_SIZE CCI_REG16(0x034c) +#define CCS_R_Y_OUTPUT_SIZE CCI_REG16(0x034e) +#define CCS_R_FRAME_LENGTH_CTRL CCI_REG8(0x0350) #define CCS_FRAME_LENGTH_CTRL_AUTOMATIC BIT(0) -#define CCS_R_TIMING_MODE_CTRL 0x0352 +#define CCS_R_TIMING_MODE_CTRL CCI_REG8(0x0352) #define CCS_TIMING_MODE_CTRL_MANUAL_READOUT BIT(0) #define CCS_TIMING_MODE_CTRL_DELAYED_EXPOSURE BIT(1) -#define CCS_R_START_READOUT_RS 0x0353 +#define CCS_R_START_READOUT_RS CCI_REG8(0x0353) #define CCS_START_READOUT_RS_MANUAL_READOUT_START BIT(0) -#define CCS_R_FRAME_MARGIN (0x0354 | CCS_FL_16BIT) -#define CCS_R_X_EVEN_INC (0x0380 | CCS_FL_16BIT) -#define CCS_R_X_ODD_INC (0x0382 | CCS_FL_16BIT) -#define CCS_R_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) -#define CCS_R_Y_ODD_INC (0x0386 | CCS_FL_16BIT) -#define CCS_R_MONOCHROME_EN 0x0390 +#define CCS_R_FRAME_MARGIN CCI_REG16(0x0354) +#define CCS_R_X_EVEN_INC CCI_REG16(0x0380) +#define CCS_R_X_ODD_INC CCI_REG16(0x0382) +#define CCS_R_Y_EVEN_INC CCI_REG16(0x0384) +#define CCS_R_Y_ODD_INC CCI_REG16(0x0386) +#define CCS_R_MONOCHROME_EN CCI_REG8(0x0390) #define CCS_MONOCHROME_EN_ENABLED 0U -#define CCS_R_SCALING_MODE (0x0400 | CCS_FL_16BIT) +#define CCS_R_SCALING_MODE CCI_REG16(0x0400) #define CCS_SCALING_MODE_NO_SCALING 0U #define CCS_SCALING_MODE_HORIZONTAL 1U -#define CCS_R_SCALE_M (0x0404 | CCS_FL_16BIT) -#define CCS_R_SCALE_N (0x0406 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) -#define CCS_R_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) +#define CCS_R_SCALE_M CCI_REG16(0x0404) +#define CCS_R_SCALE_N CCI_REG16(0x0406) +#define CCS_R_DIGITAL_CROP_X_OFFSET CCI_REG16(0x0408) +#define CCS_R_DIGITAL_CROP_Y_OFFSET CCI_REG16(0x040a) +#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH CCI_REG16(0x040c) +#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT CCI_REG16(0x040e) +#define CCS_R_COMPRESSION_MODE CCI_REG16(0x0500) #define CCS_COMPRESSION_MODE_NONE 0U #define CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE 1U -#define CCS_R_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) +#define CCS_R_TEST_PATTERN_MODE CCI_REG16(0x0600) #define CCS_TEST_PATTERN_MODE_NONE 0U #define CCS_TEST_PATTERN_MODE_SOLID_COLOR 1U #define CCS_TEST_PATTERN_MODE_COLOR_BARS 2U #define CCS_TEST_PATTERN_MODE_FADE_TO_GREY 3U #define CCS_TEST_PATTERN_MODE_PN9 4U #define CCS_TEST_PATTERN_MODE_COLOR_TILE 5U -#define CCS_R_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) -#define CCS_R_VALUE_STEP_SIZE_SMOOTH 0x060a -#define CCS_R_VALUE_STEP_SIZE_QUANTISED 0x060b -#define CCS_R_TCLK_POST 0x0800 -#define CCS_R_THS_PREPARE 0x0801 -#define CCS_R_THS_ZERO_MIN 0x0802 -#define CCS_R_THS_TRAIL 0x0803 -#define CCS_R_TCLK_TRAIL_MIN 0x0804 -#define CCS_R_TCLK_PREPARE 0x0805 -#define CCS_R_TCLK_ZERO 0x0806 -#define CCS_R_TLPX 0x0807 -#define CCS_R_PHY_CTRL 0x0808 +#define CCS_R_TEST_DATA_RED CCI_REG16(0x0602) +#define CCS_R_TEST_DATA_GREENR CCI_REG16(0x0604) +#define CCS_R_TEST_DATA_BLUE CCI_REG16(0x0606) +#define CCS_R_TEST_DATA_GREENB CCI_REG16(0x0608) +#define CCS_R_VALUE_STEP_SIZE_SMOOTH CCI_REG8(0x060a) +#define CCS_R_VALUE_STEP_SIZE_QUANTISED CCI_REG8(0x060b) +#define CCS_R_TCLK_POST CCI_REG8(0x0800) +#define CCS_R_THS_PREPARE CCI_REG8(0x0801) +#define CCS_R_THS_ZERO_MIN CCI_REG8(0x0802) +#define CCS_R_THS_TRAIL CCI_REG8(0x0803) +#define CCS_R_TCLK_TRAIL_MIN CCI_REG8(0x0804) +#define CCS_R_TCLK_PREPARE CCI_REG8(0x0805) +#define CCS_R_TCLK_ZERO CCI_REG8(0x0806) +#define CCS_R_TLPX CCI_REG8(0x0807) +#define CCS_R_PHY_CTRL CCI_REG8(0x0808) #define CCS_PHY_CTRL_AUTO 0U #define CCS_PHY_CTRL_UI 1U #define CCS_PHY_CTRL_MANUAL 2U -#define CCS_R_TCLK_POST_EX (0x080a | CCS_FL_16BIT) -#define CCS_R_THS_PREPARE_EX (0x080c | CCS_FL_16BIT) -#define CCS_R_THS_ZERO_MIN_EX (0x080e | CCS_FL_16BIT) -#define CCS_R_THS_TRAIL_EX (0x0810 | CCS_FL_16BIT) -#define CCS_R_TCLK_TRAIL_MIN_EX (0x0812 | CCS_FL_16BIT) -#define CCS_R_TCLK_PREPARE_EX (0x0814 | CCS_FL_16BIT) -#define CCS_R_TCLK_ZERO_EX (0x0816 | CCS_FL_16BIT) -#define CCS_R_TLPX_EX (0x0818 | CCS_FL_16BIT) -#define CCS_R_REQUESTED_LINK_RATE (0x0820 | CCS_FL_32BIT) -#define CCS_R_DPHY_EQUALIZATION_MODE 0x0824 +#define CCS_R_TCLK_POST_EX CCI_REG16(0x080a) +#define CCS_R_THS_PREPARE_EX CCI_REG16(0x080c) +#define CCS_R_THS_ZERO_MIN_EX CCI_REG16(0x080e) +#define CCS_R_THS_TRAIL_EX CCI_REG16(0x0810) +#define CCS_R_TCLK_TRAIL_MIN_EX CCI_REG16(0x0812) +#define CCS_R_TCLK_PREPARE_EX CCI_REG16(0x0814) +#define CCS_R_TCLK_ZERO_EX CCI_REG16(0x0816) +#define CCS_R_TLPX_EX CCI_REG16(0x0818) +#define CCS_R_REQUESTED_LINK_RATE CCI_REG32(0x0820) +#define CCS_R_DPHY_EQUALIZATION_MODE CCI_REG8(0x0824) #define CCS_DPHY_EQUALIZATION_MODE_EQ2 BIT(0) -#define CCS_R_PHY_EQUALIZATION_CTRL 0x0825 +#define CCS_R_PHY_EQUALIZATION_CTRL CCI_REG8(0x0825) #define CCS_PHY_EQUALIZATION_CTRL_ENABLE BIT(0) -#define CCS_R_DPHY_PREAMBLE_CTRL 0x0826 +#define CCS_R_DPHY_PREAMBLE_CTRL CCI_REG8(0x0826) #define CCS_DPHY_PREAMBLE_CTRL_ENABLE BIT(0) -#define CCS_R_DPHY_PREAMBLE_LENGTH 0x0826 -#define CCS_R_PHY_SSC_CTRL 0x0828 +#define CCS_R_DPHY_PREAMBLE_LENGTH CCI_REG8(0x0826) +#define CCS_R_PHY_SSC_CTRL CCI_REG8(0x0828) #define CCS_PHY_SSC_CTRL_ENABLE BIT(0) -#define CCS_R_MANUAL_LP_CTRL 0x0829 +#define CCS_R_MANUAL_LP_CTRL CCI_REG8(0x0829) #define CCS_MANUAL_LP_CTRL_ENABLE BIT(0) -#define CCS_R_TWAKEUP 0x082a -#define CCS_R_TINIT 0x082b -#define CCS_R_THS_EXIT 0x082c -#define CCS_R_THS_EXIT_EX (0x082e | CCS_FL_16BIT) -#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL 0x0830 +#define CCS_R_TWAKEUP CCI_REG8(0x082a) +#define CCS_R_TINIT CCI_REG8(0x082b) +#define CCS_R_THS_EXIT CCI_REG8(0x082c) +#define CCS_R_THS_EXIT_EX CCI_REG16(0x082e) +#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL CCI_REG8(0x0830) #define CCS_PHY_PERIODIC_CALIBRATION_CTRL_FRAME_BLANKING BIT(0) -#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL 0x0831 -#define CCS_R_PHY_INIT_CALIBRATION_CTRL 0x0832 +#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL CCI_REG8(0x0831) +#define CCS_R_PHY_INIT_CALIBRATION_CTRL CCI_REG8(0x0832) #define CCS_PHY_INIT_CALIBRATION_CTRL_STREAM_START BIT(0) -#define CCS_R_DPHY_CALIBRATION_MODE 0x0833 +#define CCS_R_DPHY_CALIBRATION_MODE CCI_REG8(0x0833) #define CCS_DPHY_CALIBRATION_MODE_ALSO_ALTERNATE BIT(0) -#define CCS_R_CPHY_CALIBRATION_MODE 0x0834 +#define CCS_R_CPHY_CALIBRATION_MODE CCI_REG8(0x0834) #define CCS_CPHY_CALIBRATION_MODE_FORMAT_1 0U #define CCS_CPHY_CALIBRATION_MODE_FORMAT_2 1U #define CCS_CPHY_CALIBRATION_MODE_FORMAT_3 2U -#define CCS_R_T3_CALPREAMBLE_LENGTH 0x0835 -#define CCS_R_T3_CALPREAMBLE_LENGTH_PER 0x0836 -#define CCS_R_T3_CALALTSEQ_LENGTH 0x0837 -#define CCS_R_T3_CALALTSEQ_LENGTH_PER 0x0838 -#define CCS_R_FM2_INIT_SEED (0x083a | CCS_FL_16BIT) -#define CCS_R_T3_CALUDEFSEQ_LENGTH (0x083c | CCS_FL_16BIT) -#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER (0x083e | CCS_FL_16BIT) -#define CCS_R_TGR_PREAMBLE_LENGTH 0x0841 +#define CCS_R_T3_CALPREAMBLE_LENGTH CCI_REG8(0x0835) +#define CCS_R_T3_CALPREAMBLE_LENGTH_PER CCI_REG8(0x0836) +#define CCS_R_T3_CALALTSEQ_LENGTH CCI_REG8(0x0837) +#define CCS_R_T3_CALALTSEQ_LENGTH_PER CCI_REG8(0x0838) +#define CCS_R_FM2_INIT_SEED CCI_REG16(0x083a) +#define CCS_R_T3_CALUDEFSEQ_LENGTH CCI_REG16(0x083c) +#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER CCI_REG16(0x083e) +#define CCS_R_TGR_PREAMBLE_LENGTH CCI_REG8(0x0841) #define CCS_TGR_PREAMBLE_LENGTH_PREAMABLE_PROG_SEQ BIT(7) #define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_SHIFT 0U #define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_MASK 0x3f -#define CCS_R_TGR_POST_LENGTH 0x0842 +#define CCS_R_TGR_POST_LENGTH CCI_REG8(0x0842) #define CCS_TGR_POST_LENGTH_POST_LENGTH_SHIFT 0U #define CCS_TGR_POST_LENGTH_POST_LENGTH_MASK 0x1f -#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) (0x0843 + (n2)) +#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) CCI_REG8(0x0843 + (n2)) #define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MIN_N2 0U #define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MAX_N2 6U #define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_SHIFT 3U #define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_MASK 0x38 #define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_SHIFT 0U #define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_MASK 0x7 -#define CCS_R_T3_PREPARE (0x084e | CCS_FL_16BIT) -#define CCS_R_T3_LPX (0x0850 | CCS_FL_16BIT) -#define CCS_R_ALPS_CTRL 0x085a +#define CCS_R_T3_PREPARE CCI_REG16(0x084e) +#define CCS_R_T3_LPX CCI_REG16(0x0850) +#define CCS_R_ALPS_CTRL CCI_REG8(0x085a) #define CCS_ALPS_CTRL_LVLP_DPHY BIT(0) #define CCS_ALPS_CTRL_LVLP_CPHY BIT(1) #define CCS_ALPS_CTRL_ALP_CPHY BIT(2) -#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY (0x0860 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY (0x0862 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY (0x0864 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY (0x0866 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY 0x0868 -#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY 0x0869 -#define CCS_R_SCRAMBLING_CTRL 0x0870 +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY CCI_REG16(0x0860) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY CCI_REG16(0x0862) +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY CCI_REG16(0x0864) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY CCI_REG16(0x0866) +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY CCI_REG8(0x0868) +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY CCI_REG8(0x0869) +#define CCS_R_SCRAMBLING_CTRL CCI_REG8(0x0870) #define CCS_SCRAMBLING_CTRL_ENABLED BIT(0) #define CCS_SCRAMBLING_CTRL_SHIFT 2U #define CCS_SCRAMBLING_CTRL_MASK 0xc #define CCS_SCRAMBLING_CTRL_1_SEED_CPHY 0U #define CCS_SCRAMBLING_CTRL_4_SEED_CPHY 3U -#define CCS_R_LANE_SEED_VALUE(seed, lane) ((0x0872 | CCS_FL_16BIT) + (seed) * 16 + (lane) * 2) +#define CCS_R_LANE_SEED_VALUE(seed, lane) CCI_REG16(0x0872 + (seed) * 16 + (lane) * 2) #define CCS_LIM_LANE_SEED_VALUE_MIN_SEED 0U #define CCS_LIM_LANE_SEED_VALUE_MAX_SEED 3U #define CCS_LIM_LANE_SEED_VALUE_MIN_LANE 0U #define CCS_LIM_LANE_SEED_VALUE_MAX_LANE 7U -#define CCS_R_TX_USL_REV_ENTRY (0x08c0 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_CLOCK_COUNTER (0x08c2 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_LP_COUNTER (0x08c4 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_FRAME_COUNTER (0x08c6 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER (0x08c8 | CCS_FL_16BIT) -#define CCS_R_TX_USL_FWD_ENTRY (0x08ca | CCS_FL_16BIT) -#define CCS_R_TX_USL_GPIO (0x08cc | CCS_FL_16BIT) -#define CCS_R_TX_USL_OPERATION (0x08ce | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_ENTRY CCI_REG16(0x08c0) +#define CCS_R_TX_USL_REV_CLOCK_COUNTER CCI_REG16(0x08c2) +#define CCS_R_TX_USL_REV_LP_COUNTER CCI_REG16(0x08c4) +#define CCS_R_TX_USL_REV_FRAME_COUNTER CCI_REG16(0x08c6) +#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER CCI_REG16(0x08c8) +#define CCS_R_TX_USL_FWD_ENTRY CCI_REG16(0x08ca) +#define CCS_R_TX_USL_GPIO CCI_REG16(0x08cc) +#define CCS_R_TX_USL_OPERATION CCI_REG16(0x08ce) #define CCS_TX_USL_OPERATION_RESET BIT(0) -#define CCS_R_TX_USL_ALP_CTRL (0x08d0 | CCS_FL_16BIT) +#define CCS_R_TX_USL_ALP_CTRL CCI_REG16(0x08d0) #define CCS_TX_USL_ALP_CTRL_CLOCK_PAUSE BIT(0) -#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) -#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) -#define CCS_R_USL_CLOCK_MODE_D_CTRL 0x08d2 +#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT CCI_REG16(0x08d2) +#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT CCI_REG16(0x08d2) +#define CCS_R_USL_CLOCK_MODE_D_CTRL CCI_REG8(0x08d2) #define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_STANDBY BIT(0) #define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_VBLANK BIT(1) #define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_HBLANK BIT(2) -#define CCS_R_BINNING_MODE 0x0900 -#define CCS_R_BINNING_TYPE 0x0901 -#define CCS_R_BINNING_WEIGHTING 0x0902 -#define CCS_R_DATA_TRANSFER_IF_1_CTRL 0x0a00 +#define CCS_R_BINNING_MODE CCI_REG8(0x0900) +#define CCS_R_BINNING_TYPE CCI_REG8(0x0901) +#define CCS_R_BINNING_WEIGHTING CCI_REG8(0x0902) +#define CCS_R_DATA_TRANSFER_IF_1_CTRL CCI_REG8(0x0a00) #define CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE BIT(0) #define CCS_DATA_TRANSFER_IF_1_CTRL_WRITE BIT(1) #define CCS_DATA_TRANSFER_IF_1_CTRL_CLEAR_ERROR BIT(2) -#define CCS_R_DATA_TRANSFER_IF_1_STATUS 0x0a01 +#define CCS_R_DATA_TRANSFER_IF_1_STATUS CCI_REG8(0x0a01) #define CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY BIT(0) #define CCS_DATA_TRANSFER_IF_1_STATUS_WRITE_IF_READY BIT(1) #define CCS_DATA_TRANSFER_IF_1_STATUS_DATA_CORRUPTED BIT(2) #define CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE BIT(3) -#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 -#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) (0x0a04 + (p)) +#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT CCI_REG8(0x0a02) +#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) CCI_REG8(0x0a04 + (p)) #define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MIN_P 0U #define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P 63U -#define CCS_R_SHADING_CORRECTION_EN 0x0b00 +#define CCS_R_SHADING_CORRECTION_EN CCI_REG8(0x0b00) #define CCS_SHADING_CORRECTION_EN_ENABLE BIT(0) -#define CCS_R_LUMINANCE_CORRECTION_LEVEL 0x0b01 -#define CCS_R_GREEN_IMBALANCE_FILTER_EN 0x0b02 +#define CCS_R_LUMINANCE_CORRECTION_LEVEL CCI_REG8(0x0b01) +#define CCS_R_GREEN_IMBALANCE_FILTER_EN CCI_REG8(0x0b02) #define CCS_GREEN_IMBALANCE_FILTER_EN_ENABLE BIT(0) -#define CCS_R_MAPPED_DEFECT_CORRECT_EN 0x0b05 +#define CCS_R_MAPPED_DEFECT_CORRECT_EN CCI_REG8(0x0b05) #define CCS_MAPPED_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_SINGLE_DEFECT_CORRECT_EN 0x0b06 +#define CCS_R_SINGLE_DEFECT_CORRECT_EN CCI_REG8(0x0b06) #define CCS_SINGLE_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN 0x0b08 +#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN CCI_REG8(0x0b08) #define CCS_DYNAMIC_COUPLET_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_COMBINED_DEFECT_CORRECT_EN 0x0b0a +#define CCS_R_COMBINED_DEFECT_CORRECT_EN CCI_REG8(0x0b0a) #define CCS_COMBINED_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN 0x0b0c +#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN CCI_REG8(0x0b0c) #define CCS_MODULE_SPECIFIC_CORRECTION_EN_ENABLE BIT(0) -#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN 0x0b13 +#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN CCI_REG8(0x0b13) #define CCS_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_NF_CTRL 0x0b15 +#define CCS_R_NF_CTRL CCI_REG8(0x0b15) #define CCS_NF_CTRL_LUMA BIT(0) #define CCS_NF_CTRL_CHROMA BIT(1) #define CCS_NF_CTRL_COMBINED BIT(2) -#define CCS_R_OB_READOUT_CONTROL 0x0b30 +#define CCS_R_OB_READOUT_CONTROL CCI_REG8(0x0b30) #define CCS_OB_READOUT_CONTROL_ENABLE BIT(0) #define CCS_OB_READOUT_CONTROL_INTERLEAVING BIT(1) -#define CCS_R_OB_VIRTUAL_CHANNEL 0x0b31 -#define CCS_R_OB_DT 0x0b32 -#define CCS_R_OB_DATA_FORMAT 0x0b33 -#define CCS_R_COLOR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) -#define CCS_R_CFA_CONVERSION_CTRL 0x0ba0 +#define CCS_R_OB_VIRTUAL_CHANNEL CCI_REG8(0x0b31) +#define CCS_R_OB_DT CCI_REG8(0x0b32) +#define CCS_R_OB_DATA_FORMAT CCI_REG8(0x0b33) +#define CCS_R_COLOR_TEMPERATURE CCI_REG16(0x0b8c) +#define CCS_R_ABSOLUTE_GAIN_GREENR CCI_REG16(0x0b8e) +#define CCS_R_ABSOLUTE_GAIN_RED CCI_REG16(0x0b90) +#define CCS_R_ABSOLUTE_GAIN_BLUE CCI_REG16(0x0b92) +#define CCS_R_ABSOLUTE_GAIN_GREENB CCI_REG16(0x0b94) +#define CCS_R_CFA_CONVERSION_CTRL CCI_REG8(0x0ba0) #define CCS_CFA_CONVERSION_CTRL_BAYER_CONVERSION_ENABLE BIT(0) -#define CCS_R_FLASH_STROBE_ADJUSTMENT 0x0c12 -#define CCS_R_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) -#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) -#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) -#define CCS_R_FLASH_MODE_RS 0x0c1a +#define CCS_R_FLASH_STROBE_ADJUSTMENT CCI_REG8(0x0c12) +#define CCS_R_FLASH_STROBE_START_POINT CCI_REG16(0x0c14) +#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL CCI_REG16(0x0c16) +#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL CCI_REG16(0x0c18) +#define CCS_R_FLASH_MODE_RS CCI_REG8(0x0c1a) #define CCS_FLASH_MODE_RS_CONTINUOUS BIT(0) #define CCS_FLASH_MODE_RS_TRUNCATE BIT(1) #define CCS_FLASH_MODE_RS_ASYNC BIT(3) -#define CCS_R_FLASH_TRIGGER_RS 0x0c1b -#define CCS_R_FLASH_STATUS 0x0c1c +#define CCS_R_FLASH_TRIGGER_RS CCI_REG8(0x0c1b) +#define CCS_R_FLASH_STATUS CCI_REG8(0x0c1c) #define CCS_FLASH_STATUS_RETIMED BIT(0) -#define CCS_R_SA_STROBE_MODE 0x0c1d +#define CCS_R_SA_STROBE_MODE CCI_REG8(0x0c1d) #define CCS_SA_STROBE_MODE_CONTINUOUS BIT(0) #define CCS_SA_STROBE_MODE_TRUNCATE BIT(1) #define CCS_SA_STROBE_MODE_ASYNC BIT(3) #define CCS_SA_STROBE_MODE_ADJUST_EDGE BIT(4) -#define CCS_R_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) -#define CCS_R_SA_STROBE_TRIGGER 0x0c24 -#define CCS_R_SA_STROBE_STATUS 0x0c25 +#define CCS_R_SA_STROBE_START_POINT CCI_REG16(0x0c1e) +#define CCS_R_TSA_STROBE_DELAY_CTRL CCI_REG16(0x0c20) +#define CCS_R_TSA_STROBE_WIDTH_CTRL CCI_REG16(0x0c22) +#define CCS_R_SA_STROBE_TRIGGER CCI_REG8(0x0c24) +#define CCS_R_SA_STROBE_STATUS CCI_REG8(0x0c25) #define CCS_SA_STROBE_STATUS_RETIMED BIT(0) -#define CCS_R_TSA_STROBE_RE_DELAY_CTRL (0x0c30 | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_FE_DELAY_CTRL (0x0c32 | CCS_FL_16BIT) -#define CCS_R_PDAF_CTRL (0x0d00 | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_RE_DELAY_CTRL CCI_REG16(0x0c30) +#define CCS_R_TSA_STROBE_FE_DELAY_CTRL CCI_REG16(0x0c32) +#define CCS_R_PDAF_CTRL CCI_REG16(0x0d00) #define CCS_PDAF_CTRL_ENABLE BIT(0) #define CCS_PDAF_CTRL_PROCESSED BIT(1) #define CCS_PDAF_CTRL_INTERLEAVED BIT(2) #define CCS_PDAF_CTRL_VISIBLE_PDAF_CORRECTION BIT(3) -#define CCS_R_PDAF_VC 0x0d02 -#define CCS_R_PDAF_DT 0x0d03 -#define CCS_R_PD_X_ADDR_START (0x0d04 | CCS_FL_16BIT) -#define CCS_R_PD_Y_ADDR_START (0x0d06 | CCS_FL_16BIT) -#define CCS_R_PD_X_ADDR_END (0x0d08 | CCS_FL_16BIT) -#define CCS_R_PD_Y_ADDR_END (0x0d0a | CCS_FL_16BIT) -#define CCS_R_BRACKETING_LUT_CTRL 0x0e00 -#define CCS_R_BRACKETING_LUT_MODE 0x0e01 +#define CCS_R_PDAF_VC CCI_REG8(0x0d02) +#define CCS_R_PDAF_DT CCI_REG8(0x0d03) +#define CCS_R_PD_X_ADDR_START CCI_REG16(0x0d04) +#define CCS_R_PD_Y_ADDR_START CCI_REG16(0x0d06) +#define CCS_R_PD_X_ADDR_END CCI_REG16(0x0d08) +#define CCS_R_PD_Y_ADDR_END CCI_REG16(0x0d0a) +#define CCS_R_BRACKETING_LUT_CTRL CCI_REG8(0x0e00) +#define CCS_R_BRACKETING_LUT_MODE CCI_REG8(0x0e01) #define CCS_BRACKETING_LUT_MODE_CONTINUE_STREAMING BIT(0) #define CCS_BRACKETING_LUT_MODE_LOOP_MODE BIT(1) -#define CCS_R_BRACKETING_LUT_ENTRY_CTRL 0x0e02 -#define CCS_R_BRACKETING_LUT_FRAME(n) (0x0e10 + (n)) +#define CCS_R_BRACKETING_LUT_ENTRY_CTRL CCI_REG8(0x0e02) +#define CCS_R_BRACKETING_LUT_FRAME(n) CCI_REG8(0x0e10 + (n)) #define CCS_LIM_BRACKETING_LUT_FRAME_MIN_N 0U #define CCS_LIM_BRACKETING_LUT_FRAME_MAX_N 239U -#define CCS_R_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) +#define CCS_R_INTEGRATION_TIME_CAPABILITY CCI_REG16(0x1000) #define CCS_INTEGRATION_TIME_CAPABILITY_FINE BIT(0) -#define CCS_R_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) -#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_CAPABILITY 0x1081 +#define CCS_R_COARSE_INTEGRATION_TIME_MIN CCI_REG16(0x1004) +#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x1006) +#define CCS_R_FINE_INTEGRATION_TIME_MIN CCI_REG16(0x1008) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x100a) +#define CCS_R_DIGITAL_GAIN_CAPABILITY CCI_REG8(0x1081) #define CCS_DIGITAL_GAIN_CAPABILITY_NONE 0U #define CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL 2U -#define CCS_R_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) -#define CCS_R_PEDESTAL_CAPABILITY 0x10e0 -#define CCS_R_ADC_CAPABILITY 0x10f0 +#define CCS_R_DIGITAL_GAIN_MIN CCI_REG16(0x1084) +#define CCS_R_DIGITAL_GAIN_MAX CCI_REG16(0x1086) +#define CCS_R_DIGITAL_GAIN_STEP_SIZE CCI_REG16(0x1088) +#define CCS_R_PEDESTAL_CAPABILITY CCI_REG8(0x10e0) +#define CCS_R_ADC_CAPABILITY CCI_REG8(0x10f0) #define CCS_ADC_CAPABILITY_BIT_DEPTH_CTRL BIT(0) -#define CCS_R_ADC_BIT_DEPTH_CAPABILITY (0x10f4 | CCS_FL_32BIT) -#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (0x1100 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (0x1104 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) -#define CCS_R_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) -#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (0x110c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (0x1110 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) -#define CCS_R_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) -#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (0x1118 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (0x111c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) -#define CCS_R_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) -#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (0x1124 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (0x1128 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (0x112c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (0x1130 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) -#define CCS_R_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) -#define CCS_R_CLOCK_CALCULATION 0x1138 +#define CCS_R_ADC_BIT_DEPTH_CAPABILITY CCI_REG32(0x10f4) +#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (CCI_REG32(0x1100) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (CCI_REG32(0x1104) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_PRE_PLL_CLK_DIV CCI_REG16(0x1108) +#define CCS_R_MAX_PRE_PLL_CLK_DIV CCI_REG16(0x110a) +#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x110c) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x1110) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_PLL_MULTIPLIER CCI_REG16(0x1114) +#define CCS_R_MAX_PLL_MULTIPLIER CCI_REG16(0x1116) +#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x1118) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x111c) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_VT_SYS_CLK_DIV CCI_REG16(0x1120) +#define CCS_R_MAX_VT_SYS_CLK_DIV CCI_REG16(0x1122) +#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1124) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1128) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (CCI_REG32(0x112c) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1130) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_VT_PIX_CLK_DIV CCI_REG16(0x1134) +#define CCS_R_MAX_VT_PIX_CLK_DIV CCI_REG16(0x1136) +#define CCS_R_CLOCK_CALCULATION CCI_REG8(0x1138) #define CCS_CLOCK_CALCULATION_LANE_SPEED BIT(0) #define CCS_CLOCK_CALCULATION_LINK_DECOUPLED BIT(1) #define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR BIT(2) #define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR BIT(3) -#define CCS_R_NUM_OF_VT_LANES 0x1139 -#define CCS_R_NUM_OF_OP_LANES 0x113a -#define CCS_R_OP_BITS_PER_LANE 0x113b -#define CCS_R_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) -#define CCS_R_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) -#define CCS_R_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) -#define CCS_R_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c -#define CCS_R_TIMING_MODE_CAPABILITY 0x114d +#define CCS_R_NUM_OF_VT_LANES CCI_REG8(0x1139) +#define CCS_R_NUM_OF_OP_LANES CCI_REG8(0x113a) +#define CCS_R_OP_BITS_PER_LANE CCI_REG8(0x113b) +#define CCS_R_MIN_FRAME_LENGTH_LINES CCI_REG16(0x1140) +#define CCS_R_MAX_FRAME_LENGTH_LINES CCI_REG16(0x1142) +#define CCS_R_MIN_LINE_LENGTH_PCK CCI_REG16(0x1144) +#define CCS_R_MAX_LINE_LENGTH_PCK CCI_REG16(0x1146) +#define CCS_R_MIN_LINE_BLANKING_PCK CCI_REG16(0x1148) +#define CCS_R_MIN_FRAME_BLANKING_LINES CCI_REG16(0x114a) +#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE CCI_REG8(0x114c) +#define CCS_R_TIMING_MODE_CAPABILITY CCI_REG8(0x114d) #define CCS_TIMING_MODE_CAPABILITY_AUTO_FRAME_LENGTH BIT(0) #define CCS_TIMING_MODE_CAPABILITY_ROLLING_SHUTTER_MANUAL_READOUT BIT(2) #define CCS_TIMING_MODE_CAPABILITY_DELAYED_EXPOSURE_START BIT(3) #define CCS_TIMING_MODE_CAPABILITY_MANUAL_EXPOSURE_EMBEDDED_DATA BIT(4) -#define CCS_R_FRAME_MARGIN_MAX_VALUE (0x114e | CCS_FL_16BIT) -#define CCS_R_FRAME_MARGIN_MIN_VALUE 0x1150 -#define CCS_R_GAIN_DELAY_TYPE 0x1151 +#define CCS_R_FRAME_MARGIN_MAX_VALUE CCI_REG16(0x114e) +#define CCS_R_FRAME_MARGIN_MIN_VALUE CCI_REG8(0x1150) +#define CCS_R_GAIN_DELAY_TYPE CCI_REG8(0x1151) #define CCS_GAIN_DELAY_TYPE_FIXED 0U #define CCS_GAIN_DELAY_TYPE_VARIABLE 1U -#define CCS_R_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) -#define CCS_R_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) -#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (0x1164 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (0x1168 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (0x1170 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (0x1174 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) -#define CCS_R_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) -#define CCS_R_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) -#define CCS_R_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) -#define CCS_R_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) -#define CCS_R_X_ADDR_START_DIV_CONSTANT 0x1190 -#define CCS_R_Y_ADDR_START_DIV_CONSTANT 0x1191 -#define CCS_R_X_ADDR_END_DIV_CONSTANT 0x1192 -#define CCS_R_Y_ADDR_END_DIV_CONSTANT 0x1193 -#define CCS_R_X_SIZE_DIV 0x1194 -#define CCS_R_Y_SIZE_DIV 0x1195 -#define CCS_R_X_OUTPUT_DIV 0x1196 -#define CCS_R_Y_OUTPUT_DIV 0x1197 -#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT 0x1198 +#define CCS_R_MIN_OP_SYS_CLK_DIV CCI_REG16(0x1160) +#define CCS_R_MAX_OP_SYS_CLK_DIV CCI_REG16(0x1162) +#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1164) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1168) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_OP_PIX_CLK_DIV CCI_REG16(0x116c) +#define CCS_R_MAX_OP_PIX_CLK_DIV CCI_REG16(0x116e) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1170) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1174) | CCS_FL_FLOAT_IREAL) +#define CCS_R_X_ADDR_MIN CCI_REG16(0x1180) +#define CCS_R_Y_ADDR_MIN CCI_REG16(0x1182) +#define CCS_R_X_ADDR_MAX CCI_REG16(0x1184) +#define CCS_R_Y_ADDR_MAX CCI_REG16(0x1186) +#define CCS_R_MIN_X_OUTPUT_SIZE CCI_REG16(0x1188) +#define CCS_R_MIN_Y_OUTPUT_SIZE CCI_REG16(0x118a) +#define CCS_R_MAX_X_OUTPUT_SIZE CCI_REG16(0x118c) +#define CCS_R_MAX_Y_OUTPUT_SIZE CCI_REG16(0x118e) +#define CCS_R_X_ADDR_START_DIV_CONSTANT CCI_REG8(0x1190) +#define CCS_R_Y_ADDR_START_DIV_CONSTANT CCI_REG8(0x1191) +#define CCS_R_X_ADDR_END_DIV_CONSTANT CCI_REG8(0x1192) +#define CCS_R_Y_ADDR_END_DIV_CONSTANT CCI_REG8(0x1193) +#define CCS_R_X_SIZE_DIV CCI_REG8(0x1194) +#define CCS_R_Y_SIZE_DIV CCI_REG8(0x1195) +#define CCS_R_X_OUTPUT_DIV CCI_REG8(0x1196) +#define CCS_R_Y_OUTPUT_DIV CCI_REG8(0x1197) +#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT CCI_REG8(0x1198) #define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_PIX_ADDR BIT(0) #define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_OUTPUT_RES BIT(1) #define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_CROP_NO_PAD BIT(2) #define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_SIZE_LANE_DEP BIT(3) -#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV (0x11a0 | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV (0x11a2 | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (0x11a4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (0x11a8 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PLL_MULTIPLIER (0x11ac | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PLL_MULTIPLIER (0x11ae | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (0x11b0 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (0x11b4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_CLOCK_TREE_PLL_CAPABILITY 0x11b8 +#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV CCI_REG16(0x11a0) +#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV CCI_REG16(0x11a2) +#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x11a4) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x11a8) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_OP_PLL_MULTIPLIER CCI_REG16(0x11ac) +#define CCS_R_MAX_OP_PLL_MULTIPLIER CCI_REG16(0x11ae) +#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x11b0) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x11b4) | CCS_FL_FLOAT_IREAL) +#define CCS_R_CLOCK_TREE_PLL_CAPABILITY CCI_REG8(0x11b8) #define CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL BIT(0) #define CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL BIT(1) #define CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER BIT(2) #define CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV BIT(3) -#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY 0x11b9 +#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY CCI_REG8(0x11b9) #define CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL BIT(0) -#define CCS_R_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC (0x11c2 | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC (0x11c4 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) -#define CCS_R_AUX_SUBSAMP_CAPABILITY 0x11c8 +#define CCS_R_MIN_EVEN_INC CCI_REG16(0x11c0) +#define CCS_R_MIN_ODD_INC CCI_REG16(0x11c2) +#define CCS_R_MAX_EVEN_INC CCI_REG16(0x11c4) +#define CCS_R_MAX_ODD_INC CCI_REG16(0x11c6) +#define CCS_R_AUX_SUBSAMP_CAPABILITY CCI_REG8(0x11c8) #define CCS_AUX_SUBSAMP_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) -#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY 0x11c9 +#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY CCI_REG8(0x11c9) #define CCS_AUX_SUBSAMP_MONO_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) -#define CCS_R_MONOCHROME_CAPABILITY 0x11ca +#define CCS_R_MONOCHROME_CAPABILITY CCI_REG8(0x11ca) #define CCS_MONOCHROME_CAPABILITY_INC_ODD 0U #define CCS_MONOCHROME_CAPABILITY_INC_EVEN 1U -#define CCS_R_PIXEL_READOUT_CAPABILITY 0x11cb +#define CCS_R_PIXEL_READOUT_CAPABILITY CCI_REG8(0x11cb) #define CCS_PIXEL_READOUT_CAPABILITY_BAYER 0U #define CCS_PIXEL_READOUT_CAPABILITY_MONOCHROME 1U #define CCS_PIXEL_READOUT_CAPABILITY_BAYER_AND_MONO 2U -#define CCS_R_MIN_EVEN_INC_MONO (0x11cc | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_MONO (0x11ce | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_MONO (0x11d0 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_MONO (0x11d2 | CCS_FL_16BIT) -#define CCS_R_MIN_EVEN_INC_BC2 (0x11d4 | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_BC2 (0x11d6 | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_BC2 (0x11d8 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_BC2 (0x11da | CCS_FL_16BIT) -#define CCS_R_MIN_EVEN_INC_MONO_BC2 (0x11dc | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_MONO_BC2 (0x11de | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_MONO_BC2 (0x11f0 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_MONO_BC2 (0x11f2 | CCS_FL_16BIT) -#define CCS_R_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) +#define CCS_R_MIN_EVEN_INC_MONO CCI_REG16(0x11cc) +#define CCS_R_MAX_EVEN_INC_MONO CCI_REG16(0x11ce) +#define CCS_R_MIN_ODD_INC_MONO CCI_REG16(0x11d0) +#define CCS_R_MAX_ODD_INC_MONO CCI_REG16(0x11d2) +#define CCS_R_MIN_EVEN_INC_BC2 CCI_REG16(0x11d4) +#define CCS_R_MAX_EVEN_INC_BC2 CCI_REG16(0x11d6) +#define CCS_R_MIN_ODD_INC_BC2 CCI_REG16(0x11d8) +#define CCS_R_MAX_ODD_INC_BC2 CCI_REG16(0x11da) +#define CCS_R_MIN_EVEN_INC_MONO_BC2 CCI_REG16(0x11dc) +#define CCS_R_MAX_EVEN_INC_MONO_BC2 CCI_REG16(0x11de) +#define CCS_R_MIN_ODD_INC_MONO_BC2 CCI_REG16(0x11f0) +#define CCS_R_MAX_ODD_INC_MONO_BC2 CCI_REG16(0x11f2) +#define CCS_R_SCALING_CAPABILITY CCI_REG16(0x1200) #define CCS_SCALING_CAPABILITY_NONE 0U #define CCS_SCALING_CAPABILITY_HORIZONTAL 1U #define CCS_SCALING_CAPABILITY_RESERVED 2U -#define CCS_R_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) -#define CCS_R_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) -#define CCS_R_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) -#define CCS_R_SCALER_N_MAX (0x120a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_CAPABILITY 0x120e +#define CCS_R_SCALER_M_MIN CCI_REG16(0x1204) +#define CCS_R_SCALER_M_MAX CCI_REG16(0x1206) +#define CCS_R_SCALER_N_MIN CCI_REG16(0x1208) +#define CCS_R_SCALER_N_MAX CCI_REG16(0x120a) +#define CCS_R_DIGITAL_CROP_CAPABILITY CCI_REG8(0x120e) #define CCS_DIGITAL_CROP_CAPABILITY_NONE 0U #define CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1U -#define CCS_R_HDR_CAPABILITY_1 0x1210 +#define CCS_R_HDR_CAPABILITY_1 CCI_REG8(0x1210) #define CCS_HDR_CAPABILITY_1_2X2_BINNING BIT(0) #define CCS_HDR_CAPABILITY_1_COMBINED_ANALOG_GAIN BIT(1) #define CCS_HDR_CAPABILITY_1_SEPARATE_ANALOG_GAIN BIT(2) @@ -611,66 +611,66 @@ #define CCS_HDR_CAPABILITY_1_RESET_SYNC BIT(4) #define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_TIMING BIT(5) #define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_SYNTHESIS BIT(6) -#define CCS_R_MIN_HDR_BIT_DEPTH 0x1211 -#define CCS_R_HDR_RESOLUTION_SUB_TYPES 0x1212 -#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) (0x1213 + (n)) +#define CCS_R_MIN_HDR_BIT_DEPTH CCI_REG8(0x1211) +#define CCS_R_HDR_RESOLUTION_SUB_TYPES CCI_REG8(0x1212) +#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) CCI_REG8(0x1213 + (n)) #define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MIN_N 0U #define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MAX_N 1U #define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_SHIFT 0U #define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_MASK 0xf #define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_SHIFT 4U #define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_MASK 0xf0 -#define CCS_R_HDR_CAPABILITY_2 0x121b +#define CCS_R_HDR_CAPABILITY_2 CCI_REG8(0x121b) #define CCS_HDR_CAPABILITY_2_COMBINED_DIGITAL_GAIN BIT(0) #define CCS_HDR_CAPABILITY_2_SEPARATE_DIGITAL_GAIN BIT(1) #define CCS_HDR_CAPABILITY_2_TIMING_MODE BIT(3) #define CCS_HDR_CAPABILITY_2_SYNTHESIS_MODE BIT(4) -#define CCS_R_MAX_HDR_BIT_DEPTH 0x121c -#define CCS_R_USL_SUPPORT_CAPABILITY 0x1230 +#define CCS_R_MAX_HDR_BIT_DEPTH CCI_REG8(0x121c) +#define CCS_R_USL_SUPPORT_CAPABILITY CCI_REG8(0x1230) #define CCS_USL_SUPPORT_CAPABILITY_CLOCK_TREE BIT(0) #define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_TREE BIT(1) #define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_CALC BIT(2) -#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY 0x1231 +#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY CCI_REG8(0x1231) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_STANDBY BIT(0) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_VBLANK BIT(1) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_HBLANK BIT(2) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_STANDBY BIT(3) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_VBLANK BIT(4) #define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_HBLANK BIT(5) -#define CCS_R_MIN_OP_SYS_CLK_DIV_REV 0x1234 -#define CCS_R_MAX_OP_SYS_CLK_DIV_REV 0x1236 -#define CCS_R_MIN_OP_PIX_CLK_DIV_REV 0x1238 -#define CCS_R_MAX_OP_PIX_CLK_DIV_REV 0x123a -#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (0x123c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (0x1240 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (0x1244 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (0x1248 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (0x124c | (CCS_FL_32BIT | CCS_FL_IREAL)) -#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (0x1250 | (CCS_FL_32BIT | CCS_FL_IREAL)) -#define CCS_R_COMPRESSION_CAPABILITY 0x1300 +#define CCS_R_MIN_OP_SYS_CLK_DIV_REV CCI_REG8(0x1234) +#define CCS_R_MAX_OP_SYS_CLK_DIV_REV CCI_REG8(0x1236) +#define CCS_R_MIN_OP_PIX_CLK_DIV_REV CCI_REG8(0x1238) +#define CCS_R_MAX_OP_PIX_CLK_DIV_REV CCI_REG8(0x123a) +#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (CCI_REG32(0x123c) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (CCI_REG32(0x1240) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (CCI_REG32(0x1244) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (CCI_REG32(0x1248) | CCS_FL_FLOAT_IREAL) +#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (CCI_REG32(0x124c) | CCS_FL_IREAL) +#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (CCI_REG32(0x1250) | CCS_FL_IREAL) +#define CCS_R_COMPRESSION_CAPABILITY CCI_REG8(0x1300) #define CCS_COMPRESSION_CAPABILITY_DPCM_PCM_SIMPLE BIT(0) -#define CCS_R_TEST_MODE_CAPABILITY (0x1310 | CCS_FL_16BIT) +#define CCS_R_TEST_MODE_CAPABILITY CCI_REG16(0x1310) #define CCS_TEST_MODE_CAPABILITY_SOLID_COLOR BIT(0) #define CCS_TEST_MODE_CAPABILITY_COLOR_BARS BIT(1) #define CCS_TEST_MODE_CAPABILITY_FADE_TO_GREY BIT(2) #define CCS_TEST_MODE_CAPABILITY_PN9 BIT(3) #define CCS_TEST_MODE_CAPABILITY_COLOR_TILE BIT(5) -#define CCS_R_PN9_DATA_FORMAT1 0x1312 -#define CCS_R_PN9_DATA_FORMAT2 0x1313 -#define CCS_R_PN9_DATA_FORMAT3 0x1314 -#define CCS_R_PN9_DATA_FORMAT4 0x1315 -#define CCS_R_PN9_MISC_CAPABILITY 0x1316 +#define CCS_R_PN9_DATA_FORMAT1 CCI_REG8(0x1312) +#define CCS_R_PN9_DATA_FORMAT2 CCI_REG8(0x1313) +#define CCS_R_PN9_DATA_FORMAT3 CCI_REG8(0x1314) +#define CCS_R_PN9_DATA_FORMAT4 CCI_REG8(0x1315) +#define CCS_R_PN9_MISC_CAPABILITY CCI_REG8(0x1316) #define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_SHIFT 0U #define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_MASK 0x7 #define CCS_PN9_MISC_CAPABILITY_COMPRESSION BIT(3) -#define CCS_R_TEST_PATTERN_CAPABILITY 0x1317 +#define CCS_R_TEST_PATTERN_CAPABILITY CCI_REG8(0x1317) #define CCS_TEST_PATTERN_CAPABILITY_NO_REPEAT BIT(1) -#define CCS_R_PATTERN_SIZE_DIV_M1 0x1318 -#define CCS_R_FIFO_SUPPORT_CAPABILITY 0x1502 +#define CCS_R_PATTERN_SIZE_DIV_M1 CCI_REG8(0x1318) +#define CCS_R_FIFO_SUPPORT_CAPABILITY CCI_REG8(0x1502) #define CCS_FIFO_SUPPORT_CAPABILITY_NONE 0U #define CCS_FIFO_SUPPORT_CAPABILITY_DERATING 1U #define CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING 2U -#define CCS_R_PHY_CTRL_CAPABILITY 0x1600 +#define CCS_R_PHY_CTRL_CAPABILITY CCI_REG8(0x1600) #define CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL BIT(0) #define CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL BIT(1) #define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_1_CTL BIT(2) @@ -679,7 +679,7 @@ #define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_1_CTL BIT(5) #define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_2_CTL BIT(6) #define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_CTL BIT(7) -#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY 0x1601 +#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY CCI_REG8(0x1601) #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) @@ -688,22 +688,22 @@ #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) #define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) -#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY 0x1602 +#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY CCI_REG8(0x1602) #define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_DPHY BIT(2) #define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_CPHY BIT(3) -#define CCS_R_FAST_STANDBY_CAPABILITY 0x1603 +#define CCS_R_FAST_STANDBY_CAPABILITY CCI_REG8(0x1603) #define CCS_FAST_STANDBY_CAPABILITY_NO_FRAME_TRUNCATION 0U #define CCS_FAST_STANDBY_CAPABILITY_FRAME_TRUNCATION 1U -#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY 0x1604 +#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY CCI_REG8(0x1604) #define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_CCI_ADDR_CHANGE BIT(0) #define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_2ND_CCI_ADDR BIT(1) #define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_SW_CHANGEABLE_2ND_CCI_ADDR BIT(2) -#define CCS_R_DATA_TYPE_CAPABILITY 0x1605 +#define CCS_R_DATA_TYPE_CAPABILITY CCI_REG8(0x1605) #define CCS_DATA_TYPE_CAPABILITY_DPCM_PROGRAMMABLE BIT(0) #define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_DT_PROGRAMMABLE BIT(1) #define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_VC_PROGRAMMABLE BIT(2) #define CCS_DATA_TYPE_CAPABILITY_EXT_VC_RANGE BIT(3) -#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY 0x1606 +#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY CCI_REG8(0x1606) #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) @@ -712,44 +712,44 @@ #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) #define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) -#define CCS_R_EMB_DATA_CAPABILITY 0x1607 +#define CCS_R_EMB_DATA_CAPABILITY CCI_REG8(0x1607) #define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW16 BIT(0) #define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW20 BIT(1) #define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW24 BIT(2) #define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW16 BIT(3) #define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW20 BIT(4) #define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW24 BIT(5) -#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) ((0x1608 | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) (CCI_REG32(0x1608 + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) | CCS_FL_IREAL) #define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MIN_N 0U #define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MAX_N 7U -#define CCS_R_TEMP_SENSOR_CAPABILITY 0x1618 +#define CCS_R_TEMP_SENSOR_CAPABILITY CCI_REG8(0x1618) #define CCS_TEMP_SENSOR_CAPABILITY_SUPPORTED BIT(0) #define CCS_TEMP_SENSOR_CAPABILITY_CCS_FORMAT BIT(1) #define CCS_TEMP_SENSOR_CAPABILITY_RESET_0X80 BIT(2) -#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) ((0x161a | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) (CCI_REG32(0x161a + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) | CCS_FL_IREAL) #define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MIN_N 0U #define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MAX_N 7U -#define CCS_R_DPHY_EQUALIZATION_CAPABILITY 0x162b +#define CCS_R_DPHY_EQUALIZATION_CAPABILITY CCI_REG8(0x162b) #define CCS_DPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) #define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ1 BIT(1) #define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ2 BIT(2) -#define CCS_R_CPHY_EQUALIZATION_CAPABILITY 0x162c +#define CCS_R_CPHY_EQUALIZATION_CAPABILITY CCI_REG8(0x162c) #define CCS_CPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) -#define CCS_R_DPHY_PREAMBLE_CAPABILITY 0x162d +#define CCS_R_DPHY_PREAMBLE_CAPABILITY CCI_REG8(0x162d) #define CCS_DPHY_PREAMBLE_CAPABILITY_PREAMBLE_SEQ_CTRL BIT(0) -#define CCS_R_DPHY_SSC_CAPABILITY 0x162e +#define CCS_R_DPHY_SSC_CAPABILITY CCI_REG8(0x162e) #define CCS_DPHY_SSC_CAPABILITY_SUPPORTED BIT(0) -#define CCS_R_CPHY_CALIBRATION_CAPABILITY 0x162f +#define CCS_R_CPHY_CALIBRATION_CAPABILITY CCI_REG8(0x162f) #define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) #define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) #define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_1_CTRL BIT(2) #define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_2_CTRL BIT(3) #define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_3_CTRL BIT(4) -#define CCS_R_DPHY_CALIBRATION_CAPABILITY 0x1630 +#define CCS_R_DPHY_CALIBRATION_CAPABILITY CCI_REG8(0x1630) #define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) #define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) #define CCS_DPHY_CALIBRATION_CAPABILITY_ALTERNATE_SEQ BIT(2) -#define CCS_R_PHY_CTRL_CAPABILITY_2 0x1631 +#define CCS_R_PHY_CTRL_CAPABILITY_2 CCI_REG8(0x1631) #define CCS_PHY_CTRL_CAPABILITY_2_TGR_LENGTH BIT(0) #define CCS_PHY_CTRL_CAPABILITY_2_TGR_PREAMBLE_PROG_SEQ BIT(1) #define CCS_PHY_CTRL_CAPABILITY_2_EXTRA_CPHY_MANUAL_TIMING BIT(2) @@ -758,13 +758,13 @@ #define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CPHY BIT(5) #define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY BIT(6) #define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY BIT(7) -#define CCS_R_LRTE_CPHY_CAPABILITY 0x1632 +#define CCS_R_LRTE_CPHY_CAPABILITY CCI_REG8(0x1632) #define CCS_LRTE_CPHY_CAPABILITY_PDQ_SHORT BIT(0) #define CCS_LRTE_CPHY_CAPABILITY_SPACER_SHORT BIT(1) #define CCS_LRTE_CPHY_CAPABILITY_PDQ_LONG BIT(2) #define CCS_LRTE_CPHY_CAPABILITY_SPACER_LONG BIT(3) #define CCS_LRTE_CPHY_CAPABILITY_SPACER_NO_PDQ BIT(4) -#define CCS_R_LRTE_DPHY_CAPABILITY 0x1633 +#define CCS_R_LRTE_DPHY_CAPABILITY CCI_REG8(0x1633) #define CCS_LRTE_DPHY_CAPABILITY_PDQ_SHORT_OPT1 BIT(0) #define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT1 BIT(1) #define CCS_LRTE_DPHY_CAPABILITY_PDQ_LONG_OPT1 BIT(2) @@ -773,18 +773,18 @@ #define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT2 BIT(5) #define CCS_LRTE_DPHY_CAPABILITY_SPACER_NO_PDQ_OPT1 BIT(6) #define CCS_LRTE_DPHY_CAPABILITY_SPACER_VARIABLE_OPT2 BIT(7) -#define CCS_R_ALPS_CAPABILITY_DPHY 0x1634 +#define CCS_R_ALPS_CAPABILITY_DPHY CCI_REG8(0x1634) #define CCS_ALPS_CAPABILITY_DPHY_LVLP_NOT_SUPPORTED 0U #define CCS_ALPS_CAPABILITY_DPHY_LVLP_SUPPORTED 1U #define CCS_ALPS_CAPABILITY_DPHY_CONTROLLABLE_LVLP 2U -#define CCS_R_ALPS_CAPABILITY_CPHY 0x1635 +#define CCS_R_ALPS_CAPABILITY_CPHY CCI_REG8(0x1635) #define CCS_ALPS_CAPABILITY_CPHY_LVLP_NOT_SUPPORTED 0U #define CCS_ALPS_CAPABILITY_CPHY_LVLP_SUPPORTED 1U #define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_LVLP 2U #define CCS_ALPS_CAPABILITY_CPHY_ALP_NOT_SUPPORTED 0xc #define CCS_ALPS_CAPABILITY_CPHY_ALP_SUPPORTED 0xd #define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_ALP 0xe -#define CCS_R_SCRAMBLING_CAPABILITY 0x1636 +#define CCS_R_SCRAMBLING_CAPABILITY CCI_REG8(0x1636) #define CCS_SCRAMBLING_CAPABILITY_SCRAMBLING_SUPPORTED BIT(0) #define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_SHIFT 1U #define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_MASK 0x6 @@ -796,11 +796,11 @@ #define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_1 1U #define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_4 4U #define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_PER_LANE BIT(6) -#define CCS_R_DPHY_MANUAL_CONSTANT 0x1637 -#define CCS_R_CPHY_MANUAL_CONSTANT 0x1638 -#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC 0x1639 +#define CCS_R_DPHY_MANUAL_CONSTANT CCI_REG8(0x1637) +#define CCS_R_CPHY_MANUAL_CONSTANT CCI_REG8(0x1638) +#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC CCI_REG8(0x1639) #define CCS_CSI2_INTERFACE_CAPABILITY_MISC_EOTP_SHORT_PKT_OPT2 BIT(0) -#define CCS_R_PHY_CTRL_CAPABILITY_3 0x165c +#define CCS_R_PHY_CTRL_CAPABILITY_3 CCI_REG8(0x165c) #define CCS_PHY_CTRL_CAPABILITY_3_DPHY_TIMING_NOT_MULTIPLE BIT(0) #define CCS_PHY_CTRL_CAPABILITY_3_DPHY_MIN_TIMING_VALUE_1 BIT(1) #define CCS_PHY_CTRL_CAPABILITY_3_TWAKEUP_SUPPORTED BIT(2) @@ -808,130 +808,130 @@ #define CCS_PHY_CTRL_CAPABILITY_3_THS_EXIT_SUPPORTED BIT(4) #define CCS_PHY_CTRL_CAPABILITY_3_CPHY_TIMING_NOT_MULTIPLE BIT(5) #define CCS_PHY_CTRL_CAPABILITY_3_CPHY_MIN_TIMING_VALUE_1 BIT(6) -#define CCS_R_DPHY_SF 0x165d -#define CCS_R_CPHY_SF 0x165e +#define CCS_R_DPHY_SF CCI_REG8(0x165d) +#define CCS_R_CPHY_SF CCI_REG8(0x165e) #define CCS_CPHY_SF_TWAKEUP_SHIFT 0U #define CCS_CPHY_SF_TWAKEUP_MASK 0xf #define CCS_CPHY_SF_TINIT_SHIFT 4U #define CCS_CPHY_SF_TINIT_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_1 0x165f +#define CCS_R_DPHY_LIMITS_1 CCI_REG8(0x165f) #define CCS_DPHY_LIMITS_1_THS_PREPARE_SHIFT 0U #define CCS_DPHY_LIMITS_1_THS_PREPARE_MASK 0xf #define CCS_DPHY_LIMITS_1_THS_ZERO_SHIFT 4U #define CCS_DPHY_LIMITS_1_THS_ZERO_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_2 0x1660 +#define CCS_R_DPHY_LIMITS_2 CCI_REG8(0x1660) #define CCS_DPHY_LIMITS_2_THS_TRAIL_SHIFT 0U #define CCS_DPHY_LIMITS_2_THS_TRAIL_MASK 0xf #define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_SHIFT 4U #define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_3 0x1661 +#define CCS_R_DPHY_LIMITS_3 CCI_REG8(0x1661) #define CCS_DPHY_LIMITS_3_TCLK_PREPARE_SHIFT 0U #define CCS_DPHY_LIMITS_3_TCLK_PREPARE_MASK 0xf #define CCS_DPHY_LIMITS_3_TCLK_ZERO_SHIFT 4U #define CCS_DPHY_LIMITS_3_TCLK_ZERO_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_4 0x1662 +#define CCS_R_DPHY_LIMITS_4 CCI_REG8(0x1662) #define CCS_DPHY_LIMITS_4_TCLK_POST_SHIFT 0U #define CCS_DPHY_LIMITS_4_TCLK_POST_MASK 0xf #define CCS_DPHY_LIMITS_4_TLPX_SHIFT 4U #define CCS_DPHY_LIMITS_4_TLPX_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_5 0x1663 +#define CCS_R_DPHY_LIMITS_5 CCI_REG8(0x1663) #define CCS_DPHY_LIMITS_5_THS_EXIT_SHIFT 0U #define CCS_DPHY_LIMITS_5_THS_EXIT_MASK 0xf #define CCS_DPHY_LIMITS_5_TWAKEUP_SHIFT 4U #define CCS_DPHY_LIMITS_5_TWAKEUP_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_6 0x1664 +#define CCS_R_DPHY_LIMITS_6 CCI_REG8(0x1664) #define CCS_DPHY_LIMITS_6_TINIT_SHIFT 0U #define CCS_DPHY_LIMITS_6_TINIT_MASK 0xf -#define CCS_R_CPHY_LIMITS_1 0x1665 +#define CCS_R_CPHY_LIMITS_1 CCI_REG8(0x1665) #define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_SHIFT 0U #define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_MASK 0xf #define CCS_CPHY_LIMITS_1_T3_LPX_MAX_SHIFT 4U #define CCS_CPHY_LIMITS_1_T3_LPX_MAX_MASK 0xf0 -#define CCS_R_CPHY_LIMITS_2 0x1666 +#define CCS_R_CPHY_LIMITS_2 CCI_REG8(0x1666) #define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_SHIFT 0U #define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_MASK 0xf #define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_SHIFT 4U #define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_MASK 0xf0 -#define CCS_R_CPHY_LIMITS_3 0x1667 +#define CCS_R_CPHY_LIMITS_3 CCI_REG8(0x1667) #define CCS_CPHY_LIMITS_3_TINIT_MAX_SHIFT 0U #define CCS_CPHY_LIMITS_3_TINIT_MAX_MASK 0xf -#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) -#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) -#define CCS_R_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) -#define CCS_R_BINNING_CAPABILITY 0x1710 +#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1700) +#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1702) +#define CCS_R_MIN_LINE_LENGTH_PCK_BIN CCI_REG16(0x1704) +#define CCS_R_MAX_LINE_LENGTH_PCK_BIN CCI_REG16(0x1706) +#define CCS_R_MIN_LINE_BLANKING_PCK_BIN CCI_REG16(0x1708) +#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN CCI_REG16(0x170a) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN CCI_REG16(0x170c) +#define CCS_R_BINNING_CAPABILITY CCI_REG8(0x1710) #define CCS_BINNING_CAPABILITY_UNSUPPORTED 0U #define CCS_BINNING_CAPABILITY_BINNING_THEN_SUBSAMPLING 1U #define CCS_BINNING_CAPABILITY_SUBSAMPLING_THEN_BINNING 2U -#define CCS_R_BINNING_WEIGHTING_CAPABILITY 0x1711 +#define CCS_R_BINNING_WEIGHTING_CAPABILITY CCI_REG8(0x1711) #define CCS_BINNING_WEIGHTING_CAPABILITY_AVERAGED BIT(0) #define CCS_BINNING_WEIGHTING_CAPABILITY_SUMMED BIT(1) #define CCS_BINNING_WEIGHTING_CAPABILITY_BAYER_CORRECTED BIT(2) #define CCS_BINNING_WEIGHTING_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) -#define CCS_R_BINNING_SUB_TYPES 0x1712 -#define CCS_R_BINNING_SUB_TYPE(n) (0x1713 + (n)) +#define CCS_R_BINNING_SUB_TYPES CCI_REG8(0x1712) +#define CCS_R_BINNING_SUB_TYPE(n) CCI_REG8(0x1713 + (n)) #define CCS_LIM_BINNING_SUB_TYPE_MIN_N 0U #define CCS_LIM_BINNING_SUB_TYPE_MAX_N 63U #define CCS_BINNING_SUB_TYPE_ROW_SHIFT 0U #define CCS_BINNING_SUB_TYPE_ROW_MASK 0xf #define CCS_BINNING_SUB_TYPE_COLUMN_SHIFT 4U #define CCS_BINNING_SUB_TYPE_COLUMN_MASK 0xf0 -#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY 0x1771 +#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY CCI_REG8(0x1771) #define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_AVERAGED BIT(0) #define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_SUMMED BIT(1) #define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_BAYER_CORRECTED BIT(2) #define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) -#define CCS_R_BINNING_SUB_TYPES_MONO 0x1772 -#define CCS_R_BINNING_SUB_TYPE_MONO(n) (0x1773 + (n)) +#define CCS_R_BINNING_SUB_TYPES_MONO CCI_REG8(0x1772) +#define CCS_R_BINNING_SUB_TYPE_MONO(n) CCI_REG8(0x1773 + (n)) #define CCS_LIM_BINNING_SUB_TYPE_MONO_MIN_N 0U #define CCS_LIM_BINNING_SUB_TYPE_MONO_MAX_N 63U -#define CCS_R_DATA_TRANSFER_IF_CAPABILITY 0x1800 +#define CCS_R_DATA_TRANSFER_IF_CAPABILITY CCI_REG8(0x1800) #define CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) #define CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING BIT(2) -#define CCS_R_SHADING_CORRECTION_CAPABILITY 0x1900 +#define CCS_R_SHADING_CORRECTION_CAPABILITY CCI_REG8(0x1900) #define CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING BIT(0) #define CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION BIT(1) -#define CCS_R_GREEN_IMBALANCE_CAPABILITY 0x1901 +#define CCS_R_GREEN_IMBALANCE_CAPABILITY CCI_REG8(0x1901) #define CCS_GREEN_IMBALANCE_CAPABILITY_SUPPORTED BIT(0) -#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 -#define CCS_R_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) +#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY CCI_REG8(0x1903) +#define CCS_R_DEFECT_CORRECTION_CAPABILITY CCI_REG16(0x1904) #define CCS_DEFECT_CORRECTION_CAPABILITY_MAPPED_DEFECT BIT(0) #define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_COUPLET BIT(2) #define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_SINGLE BIT(5) #define CCS_DEFECT_CORRECTION_CAPABILITY_COMBINED_DYNAMIC BIT(8) -#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) +#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 CCI_REG16(0x1906) #define CCS_DEFECT_CORRECTION_CAPABILITY_2_DYNAMIC_TRIPLET BIT(3) -#define CCS_R_NF_CAPABILITY 0x1908 +#define CCS_R_NF_CAPABILITY CCI_REG8(0x1908) #define CCS_NF_CAPABILITY_LUMA BIT(0) #define CCS_NF_CAPABILITY_CHROMA BIT(1) #define CCS_NF_CAPABILITY_COMBINED BIT(2) -#define CCS_R_OB_READOUT_CAPABILITY 0x1980 +#define CCS_R_OB_READOUT_CAPABILITY CCI_REG8(0x1980) #define CCS_OB_READOUT_CAPABILITY_CONTROLLABLE_READOUT BIT(0) #define CCS_OB_READOUT_CAPABILITY_VISIBLE_PIXEL_READOUT BIT(1) #define CCS_OB_READOUT_CAPABILITY_DIFFERENT_VC_READOUT BIT(2) #define CCS_OB_READOUT_CAPABILITY_DIFFERENT_DT_READOUT BIT(3) #define CCS_OB_READOUT_CAPABILITY_PROG_DATA_FORMAT BIT(4) -#define CCS_R_COLOR_FEEDBACK_CAPABILITY 0x1987 +#define CCS_R_COLOR_FEEDBACK_CAPABILITY CCI_REG8(0x1987) #define CCS_COLOR_FEEDBACK_CAPABILITY_KELVIN BIT(0) #define CCS_COLOR_FEEDBACK_CAPABILITY_AWB_GAIN BIT(1) -#define CCS_R_CFA_PATTERN_CAPABILITY 0x1990 +#define CCS_R_CFA_PATTERN_CAPABILITY CCI_REG8(0x1990) #define CCS_CFA_PATTERN_CAPABILITY_BAYER 0U #define CCS_CFA_PATTERN_CAPABILITY_MONOCHROME 1U #define CCS_CFA_PATTERN_CAPABILITY_4X4_QUAD_BAYER 2U #define CCS_CFA_PATTERN_CAPABILITY_VENDOR_SPECIFIC 3U -#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY 0x1991 +#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY CCI_REG8(0x1991) #define CCS_CFA_PATTERN_CONVERSION_CAPABILITY_BAYER BIT(0) -#define CCS_R_FLASH_MODE_CAPABILITY 0x1a02 +#define CCS_R_FLASH_MODE_CAPABILITY CCI_REG8(0x1a02) #define CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) -#define CCS_R_SA_STROBE_MODE_CAPABILITY 0x1a03 +#define CCS_R_SA_STROBE_MODE_CAPABILITY CCI_REG8(0x1a03) #define CCS_SA_STROBE_MODE_CAPABILITY_FIXED_WIDTH BIT(0) #define CCS_SA_STROBE_MODE_CAPABILITY_EDGE_CTRL BIT(1) -#define CCS_R_RESET_MAX_DELAY 0x1a10 -#define CCS_R_RESET_MIN_TIME 0x1a11 -#define CCS_R_PDAF_CAPABILITY_1 0x1b80 +#define CCS_R_RESET_MAX_DELAY CCI_REG8(0x1a10) +#define CCS_R_RESET_MIN_TIME CCI_REG8(0x1a11) +#define CCS_R_PDAF_CAPABILITY_1 CCI_REG8(0x1b80) #define CCS_PDAF_CAPABILITY_1_SUPPORTED BIT(0) #define CCS_PDAF_CAPABILITY_1_PROCESSED_BOTTOM_EMBEDDED BIT(1) #define CCS_PDAF_CAPABILITY_1_PROCESSED_INTERLEAVED BIT(2) @@ -940,19 +940,19 @@ #define CCS_PDAF_CAPABILITY_1_VISIBLE_PDAF_CORRECTION BIT(5) #define CCS_PDAF_CAPABILITY_1_VC_INTERLEAVING BIT(6) #define CCS_PDAF_CAPABILITY_1_DT_INTERLEAVING BIT(7) -#define CCS_R_PDAF_CAPABILITY_2 0x1b81 +#define CCS_R_PDAF_CAPABILITY_2 CCI_REG8(0x1b81) #define CCS_PDAF_CAPABILITY_2_ROI BIT(0) #define CCS_PDAF_CAPABILITY_2_AFTER_DIGITAL_CROP BIT(1) #define CCS_PDAF_CAPABILITY_2_CTRL_RETIMED BIT(2) -#define CCS_R_BRACKETING_LUT_CAPABILITY_1 0x1c00 +#define CCS_R_BRACKETING_LUT_CAPABILITY_1 CCI_REG8(0x1c00) #define CCS_BRACKETING_LUT_CAPABILITY_1_COARSE_INTEGRATION BIT(0) #define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_ANALOG_GAIN BIT(1) #define CCS_BRACKETING_LUT_CAPABILITY_1_FLASH BIT(4) #define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_DIGITAL_GAIN BIT(5) #define CCS_BRACKETING_LUT_CAPABILITY_1_ALTERNATE_GLOBAL_ANALOG_GAIN BIT(6) -#define CCS_R_BRACKETING_LUT_CAPABILITY_2 0x1c01 +#define CCS_R_BRACKETING_LUT_CAPABILITY_2 CCI_REG8(0x1c01) #define CCS_BRACKETING_LUT_CAPABILITY_2_SINGLE_BRACKETING_MODE BIT(0) #define CCS_BRACKETING_LUT_CAPABILITY_2_LOOPED_BRACKETING_MODE BIT(1) -#define CCS_R_BRACKETING_LUT_SIZE 0x1c02 +#define CCS_R_BRACKETING_LUT_SIZE CCI_REG8(0x1c02) #endif /* __CCS_REGS_H__ */ diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 2c013d96adcc..096573845a10 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -13,6 +13,7 @@ #define __CCS_H__ #include +#include #include #include @@ -211,6 +212,7 @@ struct ccs_sensor { struct clk *ext_clk; struct gpio_desc *xshutdown; struct gpio_desc *reset; + struct regmap *regmap; void *ccs_limits; u8 nbinning_subtypes; struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; diff --git a/drivers/media/i2c/ccs/smiapp-reg-defs.h b/drivers/media/i2c/ccs/smiapp-reg-defs.h index 177e3e51207a..ebd0f90e1092 100644 --- a/drivers/media/i2c/ccs/smiapp-reg-defs.h +++ b/drivers/media/i2c/ccs/smiapp-reg-defs.h @@ -12,481 +12,484 @@ #ifndef __SMIAPP_REG_DEFS_H__ #define __SMIAPP_REG_DEFS_H__ +#include +#include + /* Register addresses */ -#define SMIAPP_REG_U16_MODEL_ID (0x0000 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR 0x0002 -#define SMIAPP_REG_U8_MANUFACTURER_ID 0x0003 -#define SMIAPP_REG_U8_SMIA_VERSION 0x0004 -#define SMIAPP_REG_U8_FRAME_COUNT 0x0005 -#define SMIAPP_REG_U8_PIXEL_ORDER 0x0006 -#define SMIAPP_REG_U16_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PIXEL_DEPTH 0x000c -#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR 0x0010 -#define SMIAPP_REG_U8_SMIAPP_VERSION 0x0011 -#define SMIAPP_REG_U8_MODULE_DATE_YEAR 0x0012 -#define SMIAPP_REG_U8_MODULE_DATE_MONTH 0x0013 -#define SMIAPP_REG_U8_MODULE_DATE_DAY 0x0014 -#define SMIAPP_REG_U8_MODULE_DATE_PHASE 0x0015 -#define SMIAPP_REG_U16_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER 0x0018 -#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID 0x0019 -#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION 0x001a -#define SMIAPP_REG_U32_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE 0x0040 -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 -#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) ((0x0042 + ((n) << 1)) | CCS_FL_16BIT) /* 0 <= n <= 14 */ -#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 + ((n) << 2)) | CCS_FL_32BIT) /* 0 <= n <= 7 */ -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE (0x008a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 (0x008c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 (0x008e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 (0x0090 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 (0x0092 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE 0x00c0 -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 -#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 + ((n) << 1)) | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MODE_SELECT 0x0100 -#define SMIAPP_REG_U8_IMAGE_ORIENTATION 0x0101 -#define SMIAPP_REG_U8_SOFTWARE_RESET 0x0103 -#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD 0x0104 -#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES 0x0105 -#define SMIAPP_REG_U8_FAST_STANDBY_CTRL 0x0106 -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL 0x0107 -#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL 0x0108 -#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL 0x0109 -#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER 0x0110 -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE 0x0111 -#define SMIAPP_REG_U16_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_CSI_LANE_MODE 0x0114 -#define SMIAPP_REG_U8_CSI2_10_TO_8_DT 0x0115 -#define SMIAPP_REG_U8_CSI2_10_TO_7_DT 0x0116 -#define SMIAPP_REG_U8_CSI2_10_TO_6_DT 0x0117 -#define SMIAPP_REG_U8_CSI2_12_TO_8_DT 0x0118 -#define SMIAPP_REG_U8_CSI2_12_TO_7_DT 0x0119 -#define SMIAPP_REG_U8_CSI2_12_TO_6_DT 0x011a -#define SMIAPP_REG_U8_CSI2_14_TO_10_DT 0x011b -#define SMIAPP_REG_U8_CSI2_14_TO_8_DT 0x011c -#define SMIAPP_REG_U8_CSI2_16_TO_10_DT 0x011d -#define SMIAPP_REG_U8_CSI2_16_TO_8_DT 0x011e -#define SMIAPP_REG_U8_GAIN_MODE 0x0120 -#define SMIAPP_REG_U16_VANA_VOLTAGE (0x0130 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VDIG_VOLTAGE (0x0132 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VIO_VOLTAGE (0x0134 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ (0x0136 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL 0x0138 -#define SMIAPP_REG_U8_TEMP_SENSOR_MODE 0x0139 -#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT 0x013a -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR (0x0206 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED (0x0208 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE (0x020a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB (0x020c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR (0x020e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_RED (0x0210 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE (0x0212 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB (0x0214 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_START (0x0344 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_START (0x0346 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_END (0x0348 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_END (0x034a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_EVEN_INC (0x0380 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ODD_INC (0x0382 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ODD_INC (0x0386 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALING_MODE (0x0400 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING (0x0402 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALE_M (0x0404 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALE_N (0x0406 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH (0x060a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION (0x060c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH (0x060e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION (0x0610 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS (0x0700 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TCLK_POST 0x0800 -#define SMIAPP_REG_U8_THS_PREPARE 0x0801 -#define SMIAPP_REG_U8_THS_ZERO_MIN 0x0802 -#define SMIAPP_REG_U8_THS_TRAIL 0x0803 -#define SMIAPP_REG_U8_TCLK_TRAIL_MIN 0x0804 -#define SMIAPP_REG_U8_TCLK_PREPARE 0x0805 -#define SMIAPP_REG_U8_TCLK_ZERO 0x0806 -#define SMIAPP_REG_U8_TLPX 0x0807 -#define SMIAPP_REG_U8_DPHY_CTRL 0x0808 -#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS (0x0820 | CCS_FL_32BIT) -#define SMIAPP_REG_U8_BINNING_MODE 0x0900 -#define SMIAPP_REG_U8_BINNING_TYPE 0x0901 -#define SMIAPP_REG_U8_BINNING_WEIGHTING 0x0902 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL 0x0a00 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS 0x0a01 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 0x0a04 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 0x0a05 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 0x0a06 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 0x0a07 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 0x0a08 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 0x0a09 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 0x0a10 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 0x0a11 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 0x0a12 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 0x0a13 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 0x0a14 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 0x0a15 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 0x0a16 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 0x0a17 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 0x0a18 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 0x0a19 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 0x0a1a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 0x0a1b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 0x0a1c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 0x0a1d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 0x0a1e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 0x0a1f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 0x0a20 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 0x0a21 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 0x0a22 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 0x0a23 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 0x0a24 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 0x0a25 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 0x0a26 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 0x0a27 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 0x0a28 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 0x0a29 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 0x0a2a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 0x0a2b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 0x0a2c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 0x0a2d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 0x0a2e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 0x0a2f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 0x0a30 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 0x0a31 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 0x0a32 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 0x0a33 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 0x0a34 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 0x0a35 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 0x0a36 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 0x0a37 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 0x0a38 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 0x0a39 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 0x0a3a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 0x0a3b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 0x0a3c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 0x0a3d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 0x0a3e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 0x0a3f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 0x0a40 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 0x0a41 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 0x0a42 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 0x0a43 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL 0x0a44 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS 0x0a45 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT 0x0a46 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 0x0a48 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 0x0a49 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 0x0a4a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 0x0a4b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 0x0a4c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 0x0a4d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 0x0a4e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 0x0a4f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 0x0a50 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 0x0a51 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 0x0a52 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 0x0a53 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 0x0a54 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 0x0a55 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 0x0a56 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 0x0a57 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 0x0a58 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 0x0a59 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 0x0a5a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 0x0a5b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 0x0a5c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 0x0a5d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 0x0a5e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 0x0a5f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 0x0a60 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 0x0a61 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 0x0a62 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 0x0a63 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 0x0a64 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 0x0a65 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 0x0a66 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 0x0a67 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 0x0a68 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 0x0a69 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 0x0a6a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 0x0a6b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 0x0a6c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 0x0a6d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 0x0a6e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 0x0a6f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 0x0a70 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 0x0a71 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 0x0a72 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 0x0a73 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 0x0a74 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 0x0a75 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 0x0a76 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 0x0a77 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 0x0a78 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 0x0a79 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 0x0a7a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 0x0a7b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 0x0a7c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 0x0a7d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 0x0a7e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 0x0a7f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 0x0a80 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 0x0a81 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 0x0a82 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 0x0a83 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 0x0a84 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 0x0a85 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 0x0a86 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 0x0a87 -#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE 0x0b00 -#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL 0x0b01 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE 0x0b02 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT 0x0b03 -#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE 0x0b04 -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE 0x0b05 -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE 0x0b06 -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT 0x0b07 -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE 0x0b08 -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT 0x0b09 -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE 0x0b0a -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT 0x0b0b -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE 0x0b0c -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT 0x0b0d -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE 0x0b0e -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST 0x0b0f -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST 0x0b10 -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b11 -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b12 -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b13 -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b14 -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE 0x0b15 -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST 0x0b16 -#define SMIAPP_REG_U8_EDOF_MODE 0x0b80 -#define SMIAPP_REG_U8_SHARPNESS 0x0b83 -#define SMIAPP_REG_U8_DENOISING 0x0b84 -#define SMIAPP_REG_U8_MODULE_SPECIFIC 0x0b85 -#define SMIAPP_REG_U16_DEPTH_OF_FIELD (0x0b86 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_DISTANCE (0x0b88 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL 0x0b8a -#define SMIAPP_REG_U16_COLOUR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE 0x0bc0 -#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING (0x0bc2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START (0x0bc4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START (0x0bc6 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH (0x0bc8 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT (0x0bca | CCS_FL_16BIT) -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 0x0c00 -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 0x0c01 -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 0x0c02 -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 0x0c03 -#define SMIAPP_REG_U16_TRDY_CTRL (0x0c04 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TRDOUT_CTRL (0x0c06 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL (0x0c08 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL (0x0c0a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL (0x0c0c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL (0x0c0e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL (0x0c10 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT 0x0c12 -#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_MODE_RS 0x0c1a -#define SMIAPP_REG_U8_FLASH_TRIGGER_RS 0x0c1b -#define SMIAPP_REG_U8_FLASH_STATUS 0x0c1c -#define SMIAPP_REG_U8_SA_STROBE_MODE 0x0c1d -#define SMIAPP_REG_U16_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_SA_STROBE_TRIGGER 0x0c24 -#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS 0x0c25 -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL (0x0c26 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL (0x0c28 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL 0x0c2a -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL 0x0c2b -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL (0x0c2c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL (0x0c2e | CCS_FL_16BIT) -#define SMIAPP_REG_U8_LOW_LEVEL_CTRL 0x0c80 -#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT (0x0c82 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 (0x0c84 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT 0x0c86 -#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 (0x0c88 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT 0x0c8a -#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 (0x0c8c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT 0x0c8e -#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL 0x0d00 -#define SMIAPP_REG_U8_OPERATION_MODE 0x0d01 -#define SMIAPP_REG_U8_ACT_STATE1 0x0d02 -#define SMIAPP_REG_U8_ACT_STATE2 0x0d03 -#define SMIAPP_REG_U16_FOCUS_CHANGE (0x0d80 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL (0x0d82 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 (0x0d84 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 (0x0d86 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 0x0d88 -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 0x0d89 -#define SMIAPP_REG_U8_POSITION 0x0d8a -#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL 0x0e00 -#define SMIAPP_REG_U8_BRACKETING_LUT_MODE 0x0e01 -#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL 0x0e02 -#define SMIAPP_REG_U8_LUT_PARAMETERS_START 0x0e10 -#define SMIAPP_REG_U8_LUT_PARAMETERS_END 0x0eff -#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY (0x1080 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (0x1100 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (0x1104 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (0x110c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (0x1110 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (0x1118 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (0x111c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (0x1124 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (0x1128 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (0x112c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (0x1130 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c -#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (0x1164 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (0x1168 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (0x1170 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (0x1174 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_EVEN_INC (0x11c2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_ODD_INC (0x11c4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_N_MAX (0x120a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY (0x120c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY 0x120e -#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY (0x1300 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED (0x1400 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED (0x1402 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED (0x1404 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN (0x1406 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN (0x1408 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN (0x140a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE (0x140c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE (0x140e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE (0x1410 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS (0x1500 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY 0x1502 -#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY 0x1600 -#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY 0x1601 -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY 0x1602 -#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY 0x1603 -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY 0x1604 -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS (0x1608 | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS (0x160c | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS (0x1610 | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS (0x1614 | CCS_FL_32BIT) -#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY 0x1618 -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_BINNING_CAPABILITY 0x1710 -#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY 0x1711 -#define SMIAPP_REG_U8_BINNING_SUBTYPES 0x1712 -#define SMIAPP_REG_U8_BINNING_TYPE_n(n) (0x1713 + (n)) /* 1 <= n <= 237 */ -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY 0x1800 -#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY 0x1900 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY 0x1901 -#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY 0x1902 -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_EDOF_CAPABILITY 0x1980 -#define SMIAPP_REG_U8_ESTIMATION_FRAMES 0x1981 -#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ 0x1982 -#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ 0x1983 -#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ 0x1984 -#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ 0x1985 -#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ 0x1986 -#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY 0x1987 -#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM 0x1988 -#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY 0x19c0 -#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY 0x19c1 -#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD (0x19c2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE (0x19c4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN (0x1a00 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY 0x1a02 -#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR (0x1b02 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY 0x1b04 -#define SMIAPP_REG_U16_ACTUATOR_TYPE (0x1b40 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS 0x1b42 -#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS (0x1b44 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 0x1c00 -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 0x1c01 -#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE 0x1c02 +#define SMIAPP_REG_U16_MODEL_ID CCI_REG16(0x0000) +#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR CCI_REG8(0x0002) +#define SMIAPP_REG_U8_MANUFACTURER_ID CCI_REG8(0x0003) +#define SMIAPP_REG_U8_SMIA_VERSION CCI_REG8(0x0004) +#define SMIAPP_REG_U8_FRAME_COUNT CCI_REG8(0x0005) +#define SMIAPP_REG_U8_PIXEL_ORDER CCI_REG8(0x0006) +#define SMIAPP_REG_U16_DATA_PEDESTAL CCI_REG16(0x0008) +#define SMIAPP_REG_U8_PIXEL_DEPTH CCI_REG8(0x000c) +#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR CCI_REG8(0x0010) +#define SMIAPP_REG_U8_SMIAPP_VERSION CCI_REG8(0x0011) +#define SMIAPP_REG_U8_MODULE_DATE_YEAR CCI_REG8(0x0012) +#define SMIAPP_REG_U8_MODULE_DATE_MONTH CCI_REG8(0x0013) +#define SMIAPP_REG_U8_MODULE_DATE_DAY CCI_REG8(0x0014) +#define SMIAPP_REG_U8_MODULE_DATE_PHASE CCI_REG8(0x0015) +#define SMIAPP_REG_U16_SENSOR_MODEL_ID CCI_REG16(0x0016) +#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER CCI_REG8(0x0018) +#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID CCI_REG8(0x0019) +#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION CCI_REG8(0x001a) +#define SMIAPP_REG_U32_SERIAL_NUMBER CCI_REG32(0x001c) +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE CCI_REG8(0x0040) +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE CCI_REG8(0x0041) +#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) CCI_REG16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */ +#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) CCI_REG32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */ +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY CCI_REG16(0x0080) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN CCI_REG16(0x0084) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX CCI_REG16(0x0086) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP CCI_REG16(0x0088) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE CCI_REG16(0x008a) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 CCI_REG16(0x008c) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 CCI_REG16(0x008e) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 CCI_REG16(0x0090) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 CCI_REG16(0x0092) +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE CCI_REG8(0x00c0) +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE CCI_REG8(0x00c1) +#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) CCI_REG16(0x00c2 + ((n) << 1)) +#define SMIAPP_REG_U8_MODE_SELECT CCI_REG8(0x0100) +#define SMIAPP_REG_U8_IMAGE_ORIENTATION CCI_REG8(0x0101) +#define SMIAPP_REG_U8_SOFTWARE_RESET CCI_REG8(0x0103) +#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD CCI_REG8(0x0104) +#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES CCI_REG8(0x0105) +#define SMIAPP_REG_U8_FAST_STANDBY_CTRL CCI_REG8(0x0106) +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL CCI_REG8(0x0107) +#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL CCI_REG8(0x0108) +#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL CCI_REG8(0x0109) +#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER CCI_REG8(0x0110) +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE CCI_REG8(0x0111) +#define SMIAPP_REG_U16_CSI_DATA_FORMAT CCI_REG16(0x0112) +#define SMIAPP_REG_U8_CSI_LANE_MODE CCI_REG8(0x0114) +#define SMIAPP_REG_U8_CSI2_10_TO_8_DT CCI_REG8(0x0115) +#define SMIAPP_REG_U8_CSI2_10_TO_7_DT CCI_REG8(0x0116) +#define SMIAPP_REG_U8_CSI2_10_TO_6_DT CCI_REG8(0x0117) +#define SMIAPP_REG_U8_CSI2_12_TO_8_DT CCI_REG8(0x0118) +#define SMIAPP_REG_U8_CSI2_12_TO_7_DT CCI_REG8(0x0119) +#define SMIAPP_REG_U8_CSI2_12_TO_6_DT CCI_REG8(0x011a) +#define SMIAPP_REG_U8_CSI2_14_TO_10_DT CCI_REG8(0x011b) +#define SMIAPP_REG_U8_CSI2_14_TO_8_DT CCI_REG8(0x011c) +#define SMIAPP_REG_U8_CSI2_16_TO_10_DT CCI_REG8(0x011d) +#define SMIAPP_REG_U8_CSI2_16_TO_8_DT CCI_REG8(0x011e) +#define SMIAPP_REG_U8_GAIN_MODE CCI_REG8(0x0120) +#define SMIAPP_REG_U16_VANA_VOLTAGE CCI_REG16(0x0130) +#define SMIAPP_REG_U16_VDIG_VOLTAGE CCI_REG16(0x0132) +#define SMIAPP_REG_U16_VIO_VOLTAGE CCI_REG16(0x0134) +#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ CCI_REG16(0x0136) +#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL CCI_REG8(0x0138) +#define SMIAPP_REG_U8_TEMP_SENSOR_MODE CCI_REG8(0x0139) +#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT CCI_REG8(0x013a) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME CCI_REG16(0x0200) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME CCI_REG16(0x0202) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL CCI_REG16(0x0204) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR CCI_REG16(0x0206) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED CCI_REG16(0x0208) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE CCI_REG16(0x020a) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB CCI_REG16(0x020c) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR CCI_REG16(0x020e) +#define SMIAPP_REG_U16_DIGITAL_GAIN_RED CCI_REG16(0x0210) +#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE CCI_REG16(0x0212) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB CCI_REG16(0x0214) +#define SMIAPP_REG_U16_VT_PIX_CLK_DIV CCI_REG16(0x0300) +#define SMIAPP_REG_U16_VT_SYS_CLK_DIV CCI_REG16(0x0302) +#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV CCI_REG16(0x0304) +#define SMIAPP_REG_U16_PLL_MULTIPLIER CCI_REG16(0x0306) +#define SMIAPP_REG_U16_OP_PIX_CLK_DIV CCI_REG16(0x0308) +#define SMIAPP_REG_U16_OP_SYS_CLK_DIV CCI_REG16(0x030a) +#define SMIAPP_REG_U16_FRAME_LENGTH_LINES CCI_REG16(0x0340) +#define SMIAPP_REG_U16_LINE_LENGTH_PCK CCI_REG16(0x0342) +#define SMIAPP_REG_U16_X_ADDR_START CCI_REG16(0x0344) +#define SMIAPP_REG_U16_Y_ADDR_START CCI_REG16(0x0346) +#define SMIAPP_REG_U16_X_ADDR_END CCI_REG16(0x0348) +#define SMIAPP_REG_U16_Y_ADDR_END CCI_REG16(0x034a) +#define SMIAPP_REG_U16_X_OUTPUT_SIZE CCI_REG16(0x034c) +#define SMIAPP_REG_U16_Y_OUTPUT_SIZE CCI_REG16(0x034e) +#define SMIAPP_REG_U16_X_EVEN_INC CCI_REG16(0x0380) +#define SMIAPP_REG_U16_X_ODD_INC CCI_REG16(0x0382) +#define SMIAPP_REG_U16_Y_EVEN_INC CCI_REG16(0x0384) +#define SMIAPP_REG_U16_Y_ODD_INC CCI_REG16(0x0386) +#define SMIAPP_REG_U16_SCALING_MODE CCI_REG16(0x0400) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING CCI_REG16(0x0402) +#define SMIAPP_REG_U16_SCALE_M CCI_REG16(0x0404) +#define SMIAPP_REG_U16_SCALE_N CCI_REG16(0x0406) +#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET CCI_REG16(0x0408) +#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET CCI_REG16(0x040a) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH CCI_REG16(0x040c) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT CCI_REG16(0x040e) +#define SMIAPP_REG_U16_COMPRESSION_MODE CCI_REG16(0x0500) +#define SMIAPP_REG_U16_TEST_PATTERN_MODE CCI_REG16(0x0600) +#define SMIAPP_REG_U16_TEST_DATA_RED CCI_REG16(0x0602) +#define SMIAPP_REG_U16_TEST_DATA_GREENR CCI_REG16(0x0604) +#define SMIAPP_REG_U16_TEST_DATA_BLUE CCI_REG16(0x0606) +#define SMIAPP_REG_U16_TEST_DATA_GREENB CCI_REG16(0x0608) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH CCI_REG16(0x060a) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION CCI_REG16(0x060c) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH CCI_REG16(0x060e) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION CCI_REG16(0x0610) +#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS CCI_REG16(0x0700) +#define SMIAPP_REG_U8_TCLK_POST CCI_REG8(0x0800) +#define SMIAPP_REG_U8_THS_PREPARE CCI_REG8(0x0801) +#define SMIAPP_REG_U8_THS_ZERO_MIN CCI_REG8(0x0802) +#define SMIAPP_REG_U8_THS_TRAIL CCI_REG8(0x0803) +#define SMIAPP_REG_U8_TCLK_TRAIL_MIN CCI_REG8(0x0804) +#define SMIAPP_REG_U8_TCLK_PREPARE CCI_REG8(0x0805) +#define SMIAPP_REG_U8_TCLK_ZERO CCI_REG8(0x0806) +#define SMIAPP_REG_U8_TLPX CCI_REG8(0x0807) +#define SMIAPP_REG_U8_DPHY_CTRL CCI_REG8(0x0808) +#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS CCI_REG32(0x0820) +#define SMIAPP_REG_U8_BINNING_MODE CCI_REG8(0x0900) +#define SMIAPP_REG_U8_BINNING_TYPE CCI_REG8(0x0901) +#define SMIAPP_REG_U8_BINNING_WEIGHTING CCI_REG8(0x0902) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL CCI_REG8(0x0a00) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS CCI_REG8(0x0a01) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT CCI_REG8(0x0a02) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 CCI_REG8(0x0a04) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 CCI_REG8(0x0a05) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 CCI_REG8(0x0a06) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 CCI_REG8(0x0a07) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 CCI_REG8(0x0a08) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 CCI_REG8(0x0a09) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 CCI_REG8(0x0a10) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 CCI_REG8(0x0a11) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 CCI_REG8(0x0a12) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 CCI_REG8(0x0a13) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 CCI_REG8(0x0a14) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 CCI_REG8(0x0a15) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 CCI_REG8(0x0a16) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 CCI_REG8(0x0a17) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 CCI_REG8(0x0a18) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 CCI_REG8(0x0a19) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 CCI_REG8(0x0a1a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 CCI_REG8(0x0a1b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 CCI_REG8(0x0a1c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 CCI_REG8(0x0a1d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 CCI_REG8(0x0a1e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 CCI_REG8(0x0a1f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 CCI_REG8(0x0a20) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 CCI_REG8(0x0a21) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 CCI_REG8(0x0a22) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 CCI_REG8(0x0a23) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 CCI_REG8(0x0a24) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 CCI_REG8(0x0a25) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 CCI_REG8(0x0a26) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 CCI_REG8(0x0a27) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 CCI_REG8(0x0a28) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 CCI_REG8(0x0a29) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 CCI_REG8(0x0a2a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 CCI_REG8(0x0a2b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 CCI_REG8(0x0a2c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 CCI_REG8(0x0a2d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 CCI_REG8(0x0a2e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 CCI_REG8(0x0a2f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 CCI_REG8(0x0a30) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 CCI_REG8(0x0a31) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 CCI_REG8(0x0a32) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 CCI_REG8(0x0a33) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 CCI_REG8(0x0a34) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 CCI_REG8(0x0a35) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 CCI_REG8(0x0a36) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 CCI_REG8(0x0a37) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 CCI_REG8(0x0a38) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 CCI_REG8(0x0a39) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 CCI_REG8(0x0a3a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 CCI_REG8(0x0a3b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 CCI_REG8(0x0a3c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 CCI_REG8(0x0a3d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 CCI_REG8(0x0a3e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 CCI_REG8(0x0a3f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 CCI_REG8(0x0a40) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 CCI_REG8(0x0a41) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 CCI_REG8(0x0a42) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 CCI_REG8(0x0a43) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL CCI_REG8(0x0a44) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS CCI_REG8(0x0a45) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT CCI_REG8(0x0a46) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 CCI_REG8(0x0a48) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 CCI_REG8(0x0a49) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 CCI_REG8(0x0a4a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 CCI_REG8(0x0a4b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 CCI_REG8(0x0a4c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 CCI_REG8(0x0a4d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 CCI_REG8(0x0a4e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 CCI_REG8(0x0a4f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 CCI_REG8(0x0a50) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 CCI_REG8(0x0a51) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 CCI_REG8(0x0a52) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 CCI_REG8(0x0a53) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 CCI_REG8(0x0a54) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 CCI_REG8(0x0a55) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 CCI_REG8(0x0a56) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 CCI_REG8(0x0a57) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 CCI_REG8(0x0a58) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 CCI_REG8(0x0a59) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 CCI_REG8(0x0a5a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 CCI_REG8(0x0a5b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 CCI_REG8(0x0a5c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 CCI_REG8(0x0a5d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 CCI_REG8(0x0a5e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 CCI_REG8(0x0a5f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 CCI_REG8(0x0a60) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 CCI_REG8(0x0a61) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 CCI_REG8(0x0a62) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 CCI_REG8(0x0a63) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 CCI_REG8(0x0a64) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 CCI_REG8(0x0a65) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 CCI_REG8(0x0a66) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 CCI_REG8(0x0a67) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 CCI_REG8(0x0a68) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 CCI_REG8(0x0a69) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 CCI_REG8(0x0a6a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 CCI_REG8(0x0a6b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 CCI_REG8(0x0a6c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 CCI_REG8(0x0a6d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 CCI_REG8(0x0a6e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 CCI_REG8(0x0a6f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 CCI_REG8(0x0a70) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 CCI_REG8(0x0a71) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 CCI_REG8(0x0a72) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 CCI_REG8(0x0a73) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 CCI_REG8(0x0a74) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 CCI_REG8(0x0a75) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 CCI_REG8(0x0a76) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 CCI_REG8(0x0a77) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 CCI_REG8(0x0a78) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 CCI_REG8(0x0a79) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 CCI_REG8(0x0a7a) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 CCI_REG8(0x0a7b) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 CCI_REG8(0x0a7c) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 CCI_REG8(0x0a7d) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 CCI_REG8(0x0a7e) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 CCI_REG8(0x0a7f) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 CCI_REG8(0x0a80) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 CCI_REG8(0x0a81) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 CCI_REG8(0x0a82) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 CCI_REG8(0x0a83) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 CCI_REG8(0x0a84) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 CCI_REG8(0x0a85) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 CCI_REG8(0x0a86) +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 CCI_REG8(0x0a87) +#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE CCI_REG8(0x0b00) +#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL CCI_REG8(0x0b01) +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE CCI_REG8(0x0b02) +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT CCI_REG8(0x0b03) +#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE CCI_REG8(0x0b04) +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE CCI_REG8(0x0b05) +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b06) +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT CCI_REG8(0x0b07) +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE CCI_REG8(0x0b08) +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT CCI_REG8(0x0b09) +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b0a) +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT CCI_REG8(0x0b0b) +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE CCI_REG8(0x0b0c) +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT CCI_REG8(0x0b0d) +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b0e) +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b0f) +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST CCI_REG8(0x0b10) +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b11) +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b12) +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b13) +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b14) +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b15) +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b16) +#define SMIAPP_REG_U8_EDOF_MODE CCI_REG8(0x0b80) +#define SMIAPP_REG_U8_SHARPNESS CCI_REG8(0x0b83) +#define SMIAPP_REG_U8_DENOISING CCI_REG8(0x0b84) +#define SMIAPP_REG_U8_MODULE_SPECIFIC CCI_REG8(0x0b85) +#define SMIAPP_REG_U16_DEPTH_OF_FIELD CCI_REG16(0x0b86) +#define SMIAPP_REG_U16_FOCUS_DISTANCE CCI_REG16(0x0b88) +#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL CCI_REG8(0x0b8a) +#define SMIAPP_REG_U16_COLOUR_TEMPERATURE CCI_REG16(0x0b8c) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR CCI_REG16(0x0b8e) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED CCI_REG16(0x0b90) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE CCI_REG16(0x0b92) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB CCI_REG16(0x0b94) +#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE CCI_REG8(0x0bc0) +#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING CCI_REG16(0x0bc2) +#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START CCI_REG16(0x0bc4) +#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START CCI_REG16(0x0bc6) +#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH CCI_REG16(0x0bc8) +#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT CCI_REG16(0x0bca) +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 CCI_REG8(0x0c00) +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 CCI_REG8(0x0c01) +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 CCI_REG8(0x0c02) +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 CCI_REG8(0x0c03) +#define SMIAPP_REG_U16_TRDY_CTRL CCI_REG16(0x0c04) +#define SMIAPP_REG_U16_TRDOUT_CTRL CCI_REG16(0x0c06) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL CCI_REG16(0x0c08) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL CCI_REG16(0x0c0a) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL CCI_REG16(0x0c0c) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL CCI_REG16(0x0c0e) +#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL CCI_REG16(0x0c10) +#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT CCI_REG8(0x0c12) +#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT CCI_REG16(0x0c14) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL CCI_REG16(0x0c16) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL CCI_REG16(0x0c18) +#define SMIAPP_REG_U8_FLASH_MODE_RS CCI_REG8(0x0c1a) +#define SMIAPP_REG_U8_FLASH_TRIGGER_RS CCI_REG8(0x0c1b) +#define SMIAPP_REG_U8_FLASH_STATUS CCI_REG8(0x0c1c) +#define SMIAPP_REG_U8_SA_STROBE_MODE CCI_REG8(0x0c1d) +#define SMIAPP_REG_U16_SA_STROBE_START_POINT CCI_REG16(0x0c1e) +#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL CCI_REG16(0x0c20) +#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL CCI_REG16(0x0c22) +#define SMIAPP_REG_U8_SA_STROBE_TRIGGER CCI_REG8(0x0c24) +#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS CCI_REG8(0x0c25) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL CCI_REG16(0x0c26) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL CCI_REG16(0x0c28) +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL CCI_REG8(0x0c2a) +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL CCI_REG8(0x0c2b) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL CCI_REG16(0x0c2c) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL CCI_REG16(0x0c2e) +#define SMIAPP_REG_U8_LOW_LEVEL_CTRL CCI_REG8(0x0c80) +#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT CCI_REG16(0x0c82) +#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 CCI_REG16(0x0c84) +#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT CCI_REG8(0x0c86) +#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 CCI_REG16(0x0c88) +#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT CCI_REG8(0x0c8a) +#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 CCI_REG16(0x0c8c) +#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT CCI_REG8(0x0c8e) +#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL CCI_REG8(0x0d00) +#define SMIAPP_REG_U8_OPERATION_MODE CCI_REG8(0x0d01) +#define SMIAPP_REG_U8_ACT_STATE1 CCI_REG8(0x0d02) +#define SMIAPP_REG_U8_ACT_STATE2 CCI_REG8(0x0d03) +#define SMIAPP_REG_U16_FOCUS_CHANGE CCI_REG16(0x0d80) +#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL CCI_REG16(0x0d82) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 CCI_REG16(0x0d84) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 CCI_REG16(0x0d86) +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 CCI_REG8(0x0d88) +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 CCI_REG8(0x0d89) +#define SMIAPP_REG_U8_POSITION CCI_REG8(0x0d8a) +#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL CCI_REG8(0x0e00) +#define SMIAPP_REG_U8_BRACKETING_LUT_MODE CCI_REG8(0x0e01) +#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL CCI_REG8(0x0e02) +#define SMIAPP_REG_U8_LUT_PARAMETERS_START CCI_REG8(0x0e10) +#define SMIAPP_REG_U8_LUT_PARAMETERS_END CCI_REG8(0x0eff) +#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY CCI_REG16(0x1000) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN CCI_REG16(0x1004) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x1006) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN CCI_REG16(0x1008) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x100a) +#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY CCI_REG16(0x1080) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN CCI_REG16(0x1084) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX CCI_REG16(0x1086) +#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE CCI_REG16(0x1088) +#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (CCI_REG32(0x1100) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (CCI_REG32(0x1104) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV CCI_REG16(0x1108) +#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV CCI_REG16(0x110a) +#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (CCI_REG32(0x110c) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (CCI_REG32(0x1110) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER CCI_REG16(0x1114) +#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER CCI_REG16(0x1116) +#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (CCI_REG32(0x1118) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (CCI_REG32(0x111c) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV CCI_REG16(0x1120) +#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV CCI_REG16(0x1122) +#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (CCI_REG32(0x1124) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (CCI_REG32(0x1128) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (CCI_REG32(0x112c) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (CCI_REG32(0x1130) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV CCI_REG16(0x1134) +#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV CCI_REG16(0x1136) +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES CCI_REG16(0x1140) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES CCI_REG16(0x1142) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK CCI_REG16(0x1144) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK CCI_REG16(0x1146) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK CCI_REG16(0x1148) +#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES CCI_REG16(0x114a) +#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE CCI_REG8(0x114c) +#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV CCI_REG16(0x1160) +#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV CCI_REG16(0x1162) +#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (CCI_REG32(0x1164) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (CCI_REG32(0x1168) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV CCI_REG16(0x116c) +#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV CCI_REG16(0x116e) +#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (CCI_REG32(0x1170) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (CCI_REG32(0x1174) | CCS_FL_FLOAT_IREAL) +#define SMIAPP_REG_U16_X_ADDR_MIN CCI_REG16(0x1180) +#define SMIAPP_REG_U16_Y_ADDR_MIN CCI_REG16(0x1182) +#define SMIAPP_REG_U16_X_ADDR_MAX CCI_REG16(0x1184) +#define SMIAPP_REG_U16_Y_ADDR_MAX CCI_REG16(0x1186) +#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE CCI_REG16(0x1188) +#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE CCI_REG16(0x118a) +#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE CCI_REG16(0x118c) +#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE CCI_REG16(0x118e) +#define SMIAPP_REG_U16_MIN_EVEN_INC CCI_REG16(0x11c0) +#define SMIAPP_REG_U16_MAX_EVEN_INC CCI_REG16(0x11c2) +#define SMIAPP_REG_U16_MIN_ODD_INC CCI_REG16(0x11c4) +#define SMIAPP_REG_U16_MAX_ODD_INC CCI_REG16(0x11c6) +#define SMIAPP_REG_U16_SCALING_CAPABILITY CCI_REG16(0x1200) +#define SMIAPP_REG_U16_SCALER_M_MIN CCI_REG16(0x1204) +#define SMIAPP_REG_U16_SCALER_M_MAX CCI_REG16(0x1206) +#define SMIAPP_REG_U16_SCALER_N_MIN CCI_REG16(0x1208) +#define SMIAPP_REG_U16_SCALER_N_MAX CCI_REG16(0x120a) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY CCI_REG16(0x120c) +#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY CCI_REG8(0x120e) +#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY CCI_REG16(0x1300) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED CCI_REG16(0x1400) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED CCI_REG16(0x1402) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED CCI_REG16(0x1404) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN CCI_REG16(0x1406) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN CCI_REG16(0x1408) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN CCI_REG16(0x140a) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE CCI_REG16(0x140c) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE CCI_REG16(0x140e) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE CCI_REG16(0x1410) +#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS CCI_REG16(0x1500) +#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY CCI_REG8(0x1502) +#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY CCI_REG8(0x1600) +#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY CCI_REG8(0x1601) +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY CCI_REG8(0x1602) +#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY CCI_REG8(0x1603) +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY CCI_REG8(0x1604) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS CCI_REG32(0x1608) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS CCI_REG32(0x160c) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS CCI_REG32(0x1610) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS CCI_REG32(0x1614) +#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY CCI_REG8(0x1618) +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1700) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1702) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN CCI_REG16(0x1704) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN CCI_REG16(0x1706) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN CCI_REG16(0x1708) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN CCI_REG16(0x170a) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN CCI_REG16(0x170c) +#define SMIAPP_REG_U8_BINNING_CAPABILITY CCI_REG8(0x1710) +#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY CCI_REG8(0x1711) +#define SMIAPP_REG_U8_BINNING_SUBTYPES CCI_REG8(0x1712) +#define SMIAPP_REG_U8_BINNING_TYPE_n(n) CCI_REG8(0x1713 + (n)) /* 1 <= n <= 237 */ +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY CCI_REG8(0x1800) +#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY CCI_REG8(0x1900) +#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY CCI_REG8(0x1901) +#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY CCI_REG8(0x1902) +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY CCI_REG8(0x1903) +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY CCI_REG16(0x1904) +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 CCI_REG16(0x1906) +#define SMIAPP_REG_U8_EDOF_CAPABILITY CCI_REG8(0x1980) +#define SMIAPP_REG_U8_ESTIMATION_FRAMES CCI_REG8(0x1981) +#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ CCI_REG8(0x1982) +#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ CCI_REG8(0x1983) +#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ CCI_REG8(0x1984) +#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ CCI_REG8(0x1985) +#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ CCI_REG8(0x1986) +#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY CCI_REG8(0x1987) +#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM CCI_REG8(0x1988) +#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY CCI_REG8(0x19c0) +#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY CCI_REG8(0x19c1) +#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD CCI_REG16(0x19c2) +#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE CCI_REG16(0x19c4) +#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN CCI_REG16(0x1a00) +#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY CCI_REG8(0x1a02) +#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR CCI_REG16(0x1b02) +#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY CCI_REG8(0x1b04) +#define SMIAPP_REG_U16_ACTUATOR_TYPE CCI_REG16(0x1b40) +#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS CCI_REG8(0x1b42) +#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS CCI_REG16(0x1b44) +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 CCI_REG8(0x1c00) +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 CCI_REG8(0x1c01) +#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE CCI_REG8(0x1c02) /* Register bit definitions */ #define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) From 2112f3a28e8d9d1e2faaa32d124b450bde055b72 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 23 Oct 2023 21:19:22 +0300 Subject: [PATCH 2364/7721] media: v4l2-subdev: Fix indentation in v4l2-subdev.h Fix a simple indentation issue in the v4l2-subdev.h header. Fixes: f57fa2959244 ("media: v4l2-subdev: Add new ioctl for client capabilities") Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- include/uapi/linux/v4l2-subdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index b383c2fe0cf3..f0fbb4a7c150 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -239,7 +239,7 @@ struct v4l2_subdev_routing { * set (which is the default), the 'stream' fields will be forced to 0 by the * kernel. */ - #define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0) +#define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0) /** * struct v4l2_subdev_client_capability - Capabilities of the client accessing From 3de6ee94aae701fa949cd3b5df6b6a440ddfb8f2 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 13 Nov 2023 23:57:23 +0100 Subject: [PATCH 2365/7721] media: v4l: async: Fix duplicated list deletion The list deletion call dropped here is already called from the helper function in the line before. Having a second list_del() call results in either a warning (with CONFIG_DEBUG_LIST=y): list_del corruption, c46c8198->next is LIST_POISON1 (00000100) If CONFIG_DEBUG_LIST is disabled the operation results in a kernel error due to NULL pointer dereference. Fixes: 28a1295795d8 ("media: v4l: async: Allow multiple connections between entities") Signed-off-by: Sebastian Reichel Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-async.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 091e8cf4114b..8cfd593d293d 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -880,7 +880,6 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) &asc->notifier->waiting_list); v4l2_async_unbind_subdev_one(asc->notifier, asc); - list_del(&asc->asc_subdev_entry); } } From bec3db03911bd85da29c1c8ee556162153002c9a Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 13 Nov 2023 23:57:24 +0100 Subject: [PATCH 2366/7721] media: v4l: async: Drop useless list move operation v4l2_async_unbind_subdev_one(), which is called in the line following the list_move() operation contains list_move_tail() for the same entry and overrides anything list_move() did. Thus it can be removed. Signed-off-by: Sebastian Reichel Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-async.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 8cfd593d293d..3ec323bd528b 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -876,9 +876,6 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) if (sd->asc_list.next) { list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, asc_subdev_entry) { - list_move(&asc->asc_entry, - &asc->notifier->waiting_list); - v4l2_async_unbind_subdev_one(asc->notifier, asc); } } From e4256751df4a0a3860f181588ee730dd19cb0c30 Mon Sep 17 00:00:00 2001 From: Khaled Almahallawy Date: Thu, 30 Nov 2023 15:15:10 -0800 Subject: [PATCH 2367/7721] drm/display/dp: Add the remaining Square PHY patterns DPCD register definitions DP2.1 Specs added new DPCDs definitions for square pattern configs[1] These new definitions are used for UHBR Source Transmitter Equalizations tests[2]. Add the 3 new values for square pattern. v2: rebase [1]: DP2.1 Specs - 2.12.3.6.5 Square Pattern [2]: DP2.1 PHY CTS specs - 4.3 UHBR Source Transmitter Equalization Cc: Jani Nikula Cc: Imre Deak Cc: Lee Shawn C Signed-off-by: Khaled Almahallawy Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231130231510.221143-1-khaled.almahallawy@intel.com --- include/drm/display/drm_dp.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 83d2039c018b..3731828825bd 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -651,6 +651,9 @@ # define DP_LINK_QUAL_PATTERN_PRSBS31 0x38 # define DP_LINK_QUAL_PATTERN_CUSTOM 0x40 # define DP_LINK_QUAL_PATTERN_SQUARE 0x48 +# define DP_LINK_QUAL_PATTERN_SQUARE_PRESHOOT_DISABLED 0x49 +# define DP_LINK_QUAL_PATTERN_SQUARE_DEEMPHASIS_DISABLED 0x4a +# define DP_LINK_QUAL_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED 0x4b #define DP_TRAINING_LANE0_1_SET2 0x10f #define DP_TRAINING_LANE2_3_SET2 0x110 From 51b2804c19cd79e9e4ee384a37796a1d243b8f3d Mon Sep 17 00:00:00 2001 From: Suman Ghosh Date: Thu, 30 Nov 2023 09:13:23 +0530 Subject: [PATCH 2368/7721] octeontx2-af: Add new mbox to support multicast/mirror offload A new mailbox is added to support offloading of multicast/mirror functionality. The mailbox also supports dynamic updation of the multicast/mirror list. Signed-off-by: Suman Ghosh Reviewed-by: Wojciech Drewek Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 72 ++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 6 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 39 +- .../ethernet/marvell/octeontx2/af/rvu_nix.c | 702 +++++++++++++++++- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 14 +- .../marvell/octeontx2/af/rvu_npc_fs.c | 73 +- 6 files changed, 868 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index b4ced739ae44..1a6e04b9c1ef 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -304,6 +304,13 @@ M(NIX_BANDPROF_GET_HWINFO, 0x801f, nix_bandprof_get_hwinfo, msg_req, \ nix_bandprof_get_hwinfo_rsp) \ M(NIX_READ_INLINE_IPSEC_CFG, 0x8023, nix_read_inline_ipsec_cfg, \ msg_req, nix_inline_ipsec_cfg) \ +M(NIX_MCAST_GRP_CREATE, 0x802b, nix_mcast_grp_create, nix_mcast_grp_create_req, \ + nix_mcast_grp_create_rsp) \ +M(NIX_MCAST_GRP_DESTROY, 0x802c, nix_mcast_grp_destroy, nix_mcast_grp_destroy_req, \ + msg_rsp) \ +M(NIX_MCAST_GRP_UPDATE, 0x802d, nix_mcast_grp_update, \ + nix_mcast_grp_update_req, \ + nix_mcast_grp_update_rsp) \ /* MCS mbox IDs (range 0xA000 - 0xBFFF) */ \ M(MCS_ALLOC_RESOURCES, 0xa000, mcs_alloc_resources, mcs_alloc_rsrc_req, \ mcs_alloc_rsrc_rsp) \ @@ -830,6 +837,9 @@ enum nix_af_status { NIX_AF_ERR_CQ_CTX_WRITE_ERR = -429, NIX_AF_ERR_AQ_CTX_RETRY_WRITE = -430, NIX_AF_ERR_LINK_CREDITS = -431, + NIX_AF_ERR_INVALID_MCAST_GRP = -436, + NIX_AF_ERR_INVALID_MCAST_DEL_REQ = -437, + NIX_AF_ERR_NON_CONTIG_MCE_LIST = -438, }; /* For NIX RX vtag action */ @@ -1204,6 +1214,68 @@ struct nix_bp_cfg_rsp { u8 chan_cnt; /* Number of channel for which bpids are assigned */ }; +struct nix_mcast_grp_create_req { + struct mbox_msghdr hdr; +#define NIX_MCAST_INGRESS 0 +#define NIX_MCAST_EGRESS 1 + u8 dir; + u8 reserved[11]; + /* Reserving few bytes for future requirement */ +}; + +struct nix_mcast_grp_create_rsp { + struct mbox_msghdr hdr; + /* This mcast_grp_idx should be passed during MCAM + * write entry for multicast. AF will identify the + * corresponding multicast table index associated + * with the group id and program the same to MCAM entry. + * This group id is also needed during group delete + * and update request. + */ + u32 mcast_grp_idx; +}; + +struct nix_mcast_grp_destroy_req { + struct mbox_msghdr hdr; + /* Group id returned by nix_mcast_grp_create_rsp */ + u32 mcast_grp_idx; + /* If AF is requesting for destroy, then set + * it to '1'. Otherwise keep it to '0' + */ + u8 is_af; +}; + +struct nix_mcast_grp_update_req { + struct mbox_msghdr hdr; + /* Group id returned by nix_mcast_grp_create_rsp */ + u32 mcast_grp_idx; + /* Number of multicast/mirror entries requested */ + u32 num_mce_entry; +#define NIX_MCE_ENTRY_MAX 64 +#define NIX_RX_RQ 0 +#define NIX_RX_RSS 1 + /* Receive queue or RSS index within pf_func */ + u32 rq_rss_index[NIX_MCE_ENTRY_MAX]; + /* pcifunc is required for both ingress and egress multicast */ + u16 pcifunc[NIX_MCE_ENTRY_MAX]; + /* channel is required for egress multicast */ + u16 channel[NIX_MCE_ENTRY_MAX]; +#define NIX_MCAST_OP_ADD_ENTRY 0 +#define NIX_MCAST_OP_DEL_ENTRY 1 + /* Destination type. 0:Receive queue, 1:RSS*/ + u8 dest_type[NIX_MCE_ENTRY_MAX]; + u8 op; + /* If AF is requesting for update, then set + * it to '1'. Otherwise keep it to '0' + */ + u8 is_af; +}; + +struct nix_mcast_grp_update_rsp { + struct mbox_msghdr hdr; + u32 mce_start_index; +}; + /* Global NIX inline IPSec configuration */ struct nix_inline_ipsec_cfg { struct mbox_msghdr hdr; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 22c395c7d040..7cd98f013fde 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -156,7 +156,7 @@ int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc) return start; } -static void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start) +void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start) { if (!rsrc->bmap) return; @@ -2614,6 +2614,10 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc) * 2. Flush and reset SSO/SSOW * 3. Cleanup pools (NPA) */ + + /* Free multicast/mirror node associated with the 'pcifunc' */ + rvu_nix_mcast_flr_free_entries(rvu, pcifunc); + rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NIX0); rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NIX1); rvu_blklf_teardown(rvu, pcifunc, BLKADDR_CPT0); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index c4d999ef5ab4..a3de437f309e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -116,11 +116,12 @@ struct rvu_block { }; struct nix_mcast { - struct qmem *mce_ctx; - struct qmem *mcast_buf; - int replay_pkind; - int next_free_mce; - struct mutex mce_lock; /* Serialize MCE updates */ + struct qmem *mce_ctx; + struct qmem *mcast_buf; + int replay_pkind; + struct rsrc_bmap mce_counter[2]; + /* Counters for both ingress and egress mcast lists */ + struct mutex mce_lock; /* Serialize MCE updates */ }; struct nix_mce_list { @@ -129,6 +130,23 @@ struct nix_mce_list { int max; }; +struct nix_mcast_grp_elem { + struct nix_mce_list mcast_mce_list; + u32 mcast_grp_idx; + u32 pcifunc; + int mcam_index; + int mce_start_index; + struct list_head list; + u8 dir; +}; + +struct nix_mcast_grp { + struct list_head mcast_grp_head; + int count; + int next_grp_index; + struct mutex mcast_grp_lock; /* Serialize MCE updates */ +}; + /* layer metadata to uniquely identify a packet header field */ struct npc_layer_mdata { u8 lid; @@ -339,6 +357,7 @@ struct nix_hw { struct rvu *rvu; struct nix_txsch txsch[NIX_TXSCH_LVL_CNT]; /* Tx schedulers */ struct nix_mcast mcast; + struct nix_mcast_grp mcast_grp; struct nix_flowkey flowkey; struct nix_mark_format mark_format; struct nix_lso lso; @@ -741,6 +760,7 @@ void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id); bool is_rsrc_free(struct rsrc_bmap *rsrc, int id); int rvu_rsrc_free_count(struct rsrc_bmap *rsrc); int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc); +void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start); bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc); u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blkaddr); int rvu_get_pf(u16 pcifunc); @@ -847,6 +867,11 @@ u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu); u32 convert_bytes_to_dwrr_mtu(u32 bytes); void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc, struct nix_txsch *txsch, bool enable); +void rvu_nix_mcast_flr_free_entries(struct rvu *rvu, u16 pcifunc); +int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc, + u32 mcast_grp_idx); +int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc, + u32 mcast_grp_idx, u16 mcam_index); /* NPC APIs */ void rvu_npc_freemem(struct rvu *rvu); @@ -895,6 +920,10 @@ void npc_mcam_enable_flows(struct rvu *rvu, u16 target); void npc_mcam_disable_flows(struct rvu *rvu, u16 target); void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, bool enable); +u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index); +void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index, u64 cfg); void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, u16 src, struct mcam_entry *entry, u8 *intf, u8 *ena); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index c112c71ff576..475a08e4830e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -71,12 +71,19 @@ enum nix_makr_fmt_indexes { /* For now considering MC resources needed for broadcast * pkt replication only. i.e 256 HWVFs + 12 PFs. */ -#define MC_TBL_SIZE MC_TBL_SZ_512 -#define MC_BUF_CNT MC_BUF_CNT_128 +#define MC_TBL_SIZE MC_TBL_SZ_2K +#define MC_BUF_CNT MC_BUF_CNT_1024 + +#define MC_TX_MAX 2048 struct mce { struct hlist_node node; + u32 rq_rss_index; u16 pcifunc; + u16 channel; + u8 dest_type; + u8 is_active; + u8 reserved[2]; }; int rvu_get_next_nix_blkaddr(struct rvu *rvu, int blkaddr) @@ -164,18 +171,33 @@ static void nix_mce_list_init(struct nix_mce_list *list, int max) list->max = max; } -static u16 nix_alloc_mce_list(struct nix_mcast *mcast, int count) +static int nix_alloc_mce_list(struct nix_mcast *mcast, int count, u8 dir) { + struct rsrc_bmap *mce_counter; int idx; if (!mcast) - return 0; + return -EINVAL; - idx = mcast->next_free_mce; - mcast->next_free_mce += count; + mce_counter = &mcast->mce_counter[dir]; + if (!rvu_rsrc_check_contig(mce_counter, count)) + return -ENOSPC; + + idx = rvu_alloc_rsrc_contig(mce_counter, count); return idx; } +static void nix_free_mce_list(struct nix_mcast *mcast, int count, int start, u8 dir) +{ + struct rsrc_bmap *mce_counter; + + if (!mcast) + return; + + mce_counter = &mcast->mce_counter[dir]; + rvu_free_rsrc_contig(mce_counter, count, start); +} + struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr) { int nix_blkaddr = 0, i = 0; @@ -2955,7 +2977,8 @@ int rvu_mbox_handler_nix_vtag_cfg(struct rvu *rvu, } static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw, - int mce, u8 op, u16 pcifunc, int next, bool eol) + int mce, u8 op, u16 pcifunc, int next, + int index, u8 mce_op, bool eol) { struct nix_aq_enq_req aq_req; int err; @@ -2966,8 +2989,8 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw, aq_req.qidx = mce; /* Use RSS with RSS index 0 */ - aq_req.mce.op = 1; - aq_req.mce.index = 0; + aq_req.mce.op = mce_op; + aq_req.mce.index = index; aq_req.mce.eol = eol; aq_req.mce.pf_func = pcifunc; aq_req.mce.next = next; @@ -2984,6 +3007,206 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw, return 0; } +static void nix_delete_mcast_mce_list(struct nix_mce_list *mce_list) +{ + struct hlist_node *tmp; + struct mce *mce; + + /* Scan through the current list */ + hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) { + hlist_del(&mce->node); + kfree(mce); + } + + mce_list->count = 0; + mce_list->max = 0; +} + +static int nix_get_last_mce_list_index(struct nix_mcast_grp_elem *elem) +{ + return elem->mce_start_index + elem->mcast_mce_list.count - 1; +} + +static int nix_update_ingress_mce_list_hw(struct rvu *rvu, + struct nix_hw *nix_hw, + struct nix_mcast_grp_elem *elem) +{ + int idx, last_idx, next_idx, err; + struct nix_mce_list *mce_list; + struct mce *mce, *prev_mce; + + mce_list = &elem->mcast_mce_list; + idx = elem->mce_start_index; + last_idx = nix_get_last_mce_list_index(elem); + hlist_for_each_entry(mce, &mce_list->head, node) { + if (idx > last_idx) + break; + + if (!mce->is_active) { + if (idx == elem->mce_start_index) { + idx++; + prev_mce = mce; + elem->mce_start_index = idx; + continue; + } else if (idx == last_idx) { + err = nix_blk_setup_mce(rvu, nix_hw, idx - 1, NIX_AQ_INSTOP_WRITE, + prev_mce->pcifunc, next_idx, + prev_mce->rq_rss_index, + prev_mce->dest_type, + false); + if (err) + return err; + + break; + } + } + + next_idx = idx + 1; + /* EOL should be set in last MCE */ + err = nix_blk_setup_mce(rvu, nix_hw, idx, NIX_AQ_INSTOP_WRITE, + mce->pcifunc, next_idx, + mce->rq_rss_index, mce->dest_type, + (next_idx > last_idx) ? true : false); + if (err) + return err; + + idx++; + prev_mce = mce; + } + + return 0; +} + +static void nix_update_egress_mce_list_hw(struct rvu *rvu, + struct nix_hw *nix_hw, + struct nix_mcast_grp_elem *elem) +{ + struct nix_mce_list *mce_list; + int idx, last_idx, next_idx; + struct mce *mce, *prev_mce; + u64 regval; + u8 eol; + + mce_list = &elem->mcast_mce_list; + idx = elem->mce_start_index; + last_idx = nix_get_last_mce_list_index(elem); + hlist_for_each_entry(mce, &mce_list->head, node) { + if (idx > last_idx) + break; + + if (!mce->is_active) { + if (idx == elem->mce_start_index) { + idx++; + prev_mce = mce; + elem->mce_start_index = idx; + continue; + } else if (idx == last_idx) { + regval = (next_idx << 16) | (1 << 12) | prev_mce->channel; + rvu_write64(rvu, nix_hw->blkaddr, + NIX_AF_TX_MCASTX(idx - 1), + regval); + break; + } + } + + eol = 0; + next_idx = idx + 1; + /* EOL should be set in last MCE */ + if (next_idx > last_idx) + eol = 1; + + regval = (next_idx << 16) | (eol << 12) | mce->channel; + rvu_write64(rvu, nix_hw->blkaddr, + NIX_AF_TX_MCASTX(idx), + regval); + idx++; + prev_mce = mce; + } +} + +static int nix_del_mce_list_entry(struct rvu *rvu, + struct nix_hw *nix_hw, + struct nix_mcast_grp_elem *elem, + struct nix_mcast_grp_update_req *req) +{ + u32 num_entry = req->num_mce_entry; + struct nix_mce_list *mce_list; + struct mce *mce; + bool is_found; + int i; + + mce_list = &elem->mcast_mce_list; + for (i = 0; i < num_entry; i++) { + is_found = false; + hlist_for_each_entry(mce, &mce_list->head, node) { + /* If already exists, then delete */ + if (mce->pcifunc == req->pcifunc[i]) { + hlist_del(&mce->node); + kfree(mce); + mce_list->count--; + is_found = true; + break; + } + } + + if (!is_found) + return NIX_AF_ERR_INVALID_MCAST_DEL_REQ; + } + + mce_list->max = mce_list->count; + /* Dump the updated list to HW */ + if (elem->dir == NIX_MCAST_INGRESS) + return nix_update_ingress_mce_list_hw(rvu, nix_hw, elem); + + nix_update_egress_mce_list_hw(rvu, nix_hw, elem); + return 0; +} + +static int nix_add_mce_list_entry(struct rvu *rvu, + struct nix_hw *nix_hw, + struct nix_mcast_grp_elem *elem, + struct nix_mcast_grp_update_req *req) +{ + u32 num_entry = req->num_mce_entry; + struct nix_mce_list *mce_list; + struct hlist_node *tmp; + struct mce *mce; + int i; + + mce_list = &elem->mcast_mce_list; + for (i = 0; i < num_entry; i++) { + mce = kzalloc(sizeof(*mce), GFP_KERNEL); + if (!mce) + goto free_mce; + + mce->pcifunc = req->pcifunc[i]; + mce->channel = req->channel[i]; + mce->rq_rss_index = req->rq_rss_index[i]; + mce->dest_type = req->dest_type[i]; + mce->is_active = 1; + hlist_add_head(&mce->node, &mce_list->head); + mce_list->count++; + } + + mce_list->max += num_entry; + + /* Dump the updated list to HW */ + if (elem->dir == NIX_MCAST_INGRESS) + return nix_update_ingress_mce_list_hw(rvu, nix_hw, elem); + + nix_update_egress_mce_list_hw(rvu, nix_hw, elem); + return 0; + +free_mce: + hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) { + hlist_del(&mce->node); + kfree(mce); + mce_list->count--; + } + + return -ENOMEM; +} + static int nix_update_mce_list_entry(struct nix_mce_list *mce_list, u16 pcifunc, bool add) { @@ -3079,6 +3302,7 @@ int nix_update_mce_list(struct rvu *rvu, u16 pcifunc, /* EOL should be set in last MCE */ err = nix_blk_setup_mce(rvu, nix_hw, idx, NIX_AQ_INSTOP_WRITE, mce->pcifunc, next_idx, + 0, 1, (next_idx > last_idx) ? true : false); if (err) goto end; @@ -3159,6 +3383,16 @@ static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc, return err; } +static void nix_setup_mcast_grp(struct nix_hw *nix_hw) +{ + struct nix_mcast_grp *mcast_grp = &nix_hw->mcast_grp; + + INIT_LIST_HEAD(&mcast_grp->mcast_grp_head); + mutex_init(&mcast_grp->mcast_grp_lock); + mcast_grp->next_grp_index = 1; + mcast_grp->count = 0; +} + static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw) { struct nix_mcast *mcast = &nix_hw->mcast; @@ -3183,15 +3417,15 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw) continue; /* save start idx of broadcast mce list */ - pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1); + pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS); nix_mce_list_init(&pfvf->bcast_mce_list, numvfs + 1); /* save start idx of multicast mce list */ - pfvf->mcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1); + pfvf->mcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS); nix_mce_list_init(&pfvf->mcast_mce_list, numvfs + 1); /* save the start idx of promisc mce list */ - pfvf->promisc_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1); + pfvf->promisc_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS); nix_mce_list_init(&pfvf->promisc_mce_list, numvfs + 1); for (idx = 0; idx < (numvfs + 1); idx++) { @@ -3206,7 +3440,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw) err = nix_blk_setup_mce(rvu, nix_hw, pfvf->bcast_mce_idx + idx, NIX_AQ_INSTOP_INIT, - pcifunc, 0, true); + pcifunc, 0, 0, 1, true); if (err) return err; @@ -3214,7 +3448,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw) err = nix_blk_setup_mce(rvu, nix_hw, pfvf->mcast_mce_idx + idx, NIX_AQ_INSTOP_INIT, - pcifunc, 0, true); + pcifunc, 0, 0, 1, true); if (err) return err; @@ -3222,7 +3456,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw) err = nix_blk_setup_mce(rvu, nix_hw, pfvf->promisc_mce_idx + idx, NIX_AQ_INSTOP_INIT, - pcifunc, 0, true); + pcifunc, 0, 0, 1, true); if (err) return err; } @@ -3237,13 +3471,30 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) int err, size; size = (rvu_read64(rvu, blkaddr, NIX_AF_CONST3) >> 16) & 0x0F; - size = (1ULL << size); + size = BIT_ULL(size); + + /* Allocate bitmap for rx mce entries */ + mcast->mce_counter[NIX_MCAST_INGRESS].max = 256UL << MC_TBL_SIZE; + err = rvu_alloc_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]); + if (err) + return -ENOMEM; + + /* Allocate bitmap for tx mce entries */ + mcast->mce_counter[NIX_MCAST_EGRESS].max = MC_TX_MAX; + err = rvu_alloc_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]); + if (err) { + rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]); + return -ENOMEM; + } /* Alloc memory for multicast/mirror replication entries */ err = qmem_alloc(rvu->dev, &mcast->mce_ctx, - (256UL << MC_TBL_SIZE), size); - if (err) + mcast->mce_counter[NIX_MCAST_INGRESS].max, size); + if (err) { + rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]); + rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]); return -ENOMEM; + } rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BASE, (u64)mcast->mce_ctx->iova); @@ -3256,8 +3507,11 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) size = rvu_read64(rvu, blkaddr, NIX_AF_MC_MIRROR_CONST) & 0xFFFF; err = qmem_alloc(rvu->dev, &mcast->mcast_buf, (8UL << MC_BUF_CNT), size); - if (err) + if (err) { + rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]); + rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]); return -ENOMEM; + } rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BUF_BASE, (u64)mcast->mcast_buf->iova); @@ -3271,6 +3525,8 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) mutex_init(&mcast->mce_lock); + nix_setup_mcast_grp(nix_hw); + return nix_setup_mce_tables(rvu, nix_hw); } @@ -4794,6 +5050,74 @@ void rvu_nix_freemem(struct rvu *rvu) } } +static void nix_mcast_update_action(struct rvu *rvu, + struct nix_mcast_grp_elem *elem) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + struct nix_rx_action rx_action = { 0 }; + struct nix_tx_action tx_action = { 0 }; + int npc_blkaddr; + + npc_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (elem->dir == NIX_MCAST_INGRESS) { + *(u64 *)&rx_action = npc_get_mcam_action(rvu, mcam, + npc_blkaddr, + elem->mcam_index); + rx_action.index = elem->mce_start_index; + npc_set_mcam_action(rvu, mcam, npc_blkaddr, elem->mcam_index, + *(u64 *)&rx_action); + } else { + *(u64 *)&tx_action = npc_get_mcam_action(rvu, mcam, + npc_blkaddr, + elem->mcam_index); + tx_action.index = elem->mce_start_index; + npc_set_mcam_action(rvu, mcam, npc_blkaddr, elem->mcam_index, + *(u64 *)&tx_action); + } +} + +static void nix_mcast_update_mce_entry(struct rvu *rvu, u16 pcifunc, u8 is_active) +{ + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + struct nix_hw *nix_hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return; + + mcast_grp = &nix_hw->mcast_grp; + + mutex_lock(&mcast_grp->mcast_grp_lock); + list_for_each_entry(elem, &mcast_grp->mcast_grp_head, list) { + struct nix_mce_list *mce_list; + struct mce *mce; + + /* Iterate the group elements and disable the element which + * received the disable request. + */ + mce_list = &elem->mcast_mce_list; + hlist_for_each_entry(mce, &mce_list->head, node) { + if (mce->pcifunc == pcifunc) { + mce->is_active = is_active; + break; + } + } + + /* Dump the updated list to HW */ + if (elem->dir == NIX_MCAST_INGRESS) + nix_update_ingress_mce_list_hw(rvu, nix_hw, elem); + else + nix_update_egress_mce_list_hw(rvu, nix_hw, elem); + + /* Update the multicast index in NPC rule */ + nix_mcast_update_action(rvu, elem); + } + mutex_unlock(&mcast_grp->mcast_grp_lock); +} + int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp) { @@ -4805,6 +5129,9 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, if (err) return err; + /* Enable the interface if it is in any multicast list */ + nix_mcast_update_mce_entry(rvu, pcifunc, 1); + rvu_npc_enable_default_entries(rvu, pcifunc, nixlf); npc_mcam_enable_flows(rvu, pcifunc); @@ -4829,6 +5156,9 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, return err; rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf); + /* Disable the interface if it is in any multicast list */ + nix_mcast_update_mce_entry(rvu, pcifunc, 0); + pfvf = rvu_get_pfvf(rvu, pcifunc); clear_bit(NIXLF_INITIALIZED, &pfvf->flags); @@ -5797,3 +6127,337 @@ int rvu_mbox_handler_nix_bandprof_get_hwinfo(struct rvu *rvu, struct msg_req *re return 0; } + +static struct nix_mcast_grp_elem *rvu_nix_mcast_find_grp_elem(struct nix_mcast_grp *mcast_grp, + u32 mcast_grp_idx) +{ + struct nix_mcast_grp_elem *iter; + bool is_found = false; + + mutex_lock(&mcast_grp->mcast_grp_lock); + list_for_each_entry(iter, &mcast_grp->mcast_grp_head, list) { + if (iter->mcast_grp_idx == mcast_grp_idx) { + is_found = true; + break; + } + } + mutex_unlock(&mcast_grp->mcast_grp_lock); + + if (is_found) + return iter; + + return NULL; +} + +int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc, u32 mcast_grp_idx) +{ + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + struct nix_hw *nix_hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return NIX_AF_ERR_INVALID_NIXBLK; + + mcast_grp = &nix_hw->mcast_grp; + elem = rvu_nix_mcast_find_grp_elem(mcast_grp, mcast_grp_idx); + if (!elem) + return NIX_AF_ERR_INVALID_MCAST_GRP; + + return elem->mce_start_index; +} + +void rvu_nix_mcast_flr_free_entries(struct rvu *rvu, u16 pcifunc) +{ + struct nix_mcast_grp_destroy_req dreq = { 0 }; + struct nix_mcast_grp_update_req ureq = { 0 }; + struct nix_mcast_grp_update_rsp ursp = { 0 }; + struct nix_mcast_grp_elem *elem, *tmp; + struct nix_mcast_grp *mcast_grp; + struct nix_hw *nix_hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return; + + mcast_grp = &nix_hw->mcast_grp; + + mutex_lock(&mcast_grp->mcast_grp_lock); + list_for_each_entry_safe(elem, tmp, &mcast_grp->mcast_grp_head, list) { + struct nix_mce_list *mce_list; + struct hlist_node *tmp; + struct mce *mce; + + /* If the pcifunc which created the multicast/mirror + * group received an FLR, then delete the entire group. + */ + if (elem->pcifunc == pcifunc) { + /* Delete group */ + dreq.hdr.pcifunc = elem->pcifunc; + dreq.mcast_grp_idx = elem->mcast_grp_idx; + dreq.is_af = 1; + rvu_mbox_handler_nix_mcast_grp_destroy(rvu, &dreq, NULL); + continue; + } + + /* Iterate the group elements and delete the element which + * received the FLR. + */ + mce_list = &elem->mcast_mce_list; + hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) { + if (mce->pcifunc == pcifunc) { + ureq.hdr.pcifunc = pcifunc; + ureq.num_mce_entry = 1; + ureq.mcast_grp_idx = elem->mcast_grp_idx; + ureq.op = NIX_MCAST_OP_DEL_ENTRY; + ureq.pcifunc[0] = pcifunc; + ureq.is_af = 1; + rvu_mbox_handler_nix_mcast_grp_update(rvu, &ureq, &ursp); + break; + } + } + } + mutex_unlock(&mcast_grp->mcast_grp_lock); +} + +int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc, + u32 mcast_grp_idx, u16 mcam_index) +{ + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + struct nix_hw *nix_hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return NIX_AF_ERR_INVALID_NIXBLK; + + mcast_grp = &nix_hw->mcast_grp; + elem = rvu_nix_mcast_find_grp_elem(mcast_grp, mcast_grp_idx); + if (!elem) + return NIX_AF_ERR_INVALID_MCAST_GRP; + + elem->mcam_index = mcam_index; + + return 0; +} + +int rvu_mbox_handler_nix_mcast_grp_create(struct rvu *rvu, + struct nix_mcast_grp_create_req *req, + struct nix_mcast_grp_create_rsp *rsp) +{ + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + struct nix_hw *nix_hw; + int blkaddr, err; + + err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr); + if (err) + return err; + + mcast_grp = &nix_hw->mcast_grp; + elem = kzalloc(sizeof(*elem), GFP_KERNEL); + if (!elem) + return -ENOMEM; + + INIT_HLIST_HEAD(&elem->mcast_mce_list.head); + elem->mcam_index = -1; + elem->mce_start_index = -1; + elem->pcifunc = req->hdr.pcifunc; + elem->dir = req->dir; + elem->mcast_grp_idx = mcast_grp->next_grp_index++; + + mutex_lock(&mcast_grp->mcast_grp_lock); + list_add_tail(&elem->list, &mcast_grp->mcast_grp_head); + mcast_grp->count++; + mutex_unlock(&mcast_grp->mcast_grp_lock); + + rsp->mcast_grp_idx = elem->mcast_grp_idx; + return 0; +} + +int rvu_mbox_handler_nix_mcast_grp_destroy(struct rvu *rvu, + struct nix_mcast_grp_destroy_req *req, + struct msg_rsp *rsp) +{ + struct npc_delete_flow_req uninstall_req = { 0 }; + struct npc_delete_flow_rsp uninstall_rsp = { 0 }; + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + struct nix_mcast *mcast; + struct nix_hw *nix_hw; + int blkaddr, err; + + err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr); + if (err) + return err; + + mcast_grp = &nix_hw->mcast_grp; + elem = rvu_nix_mcast_find_grp_elem(mcast_grp, req->mcast_grp_idx); + if (!elem) + return NIX_AF_ERR_INVALID_MCAST_GRP; + + /* If no mce entries are associated with the group + * then just remove it from the global list. + */ + if (!elem->mcast_mce_list.count) + goto delete_grp; + + /* Delete the associated mcam entry and + * remove all mce entries from the group + */ + mcast = &nix_hw->mcast; + mutex_lock(&mcast->mce_lock); + if (elem->mcam_index != -1) { + uninstall_req.hdr.pcifunc = req->hdr.pcifunc; + uninstall_req.entry = elem->mcam_index; + rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp); + } + + nix_free_mce_list(mcast, elem->mcast_mce_list.count, + elem->mce_start_index, elem->dir); + nix_delete_mcast_mce_list(&elem->mcast_mce_list); + mutex_unlock(&mcast->mce_lock); + +delete_grp: + /* If AF is requesting for the deletion, + * then AF is already taking the lock + */ + if (!req->is_af) + mutex_lock(&mcast_grp->mcast_grp_lock); + + list_del(&elem->list); + kfree(elem); + mcast_grp->count--; + if (!req->is_af) + mutex_unlock(&mcast_grp->mcast_grp_lock); + + return 0; +} + +int rvu_mbox_handler_nix_mcast_grp_update(struct rvu *rvu, + struct nix_mcast_grp_update_req *req, + struct nix_mcast_grp_update_rsp *rsp) +{ + struct nix_mcast_grp_destroy_req dreq = { 0 }; + struct npc_mcam *mcam = &rvu->hw->mcam; + struct nix_mcast_grp_elem *elem; + struct nix_mcast_grp *mcast_grp; + int blkaddr, err, npc_blkaddr; + u16 prev_count, new_count; + struct nix_mcast *mcast; + struct nix_hw *nix_hw; + int i, ret; + + if (!req->num_mce_entry) + return 0; + + err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr); + if (err) + return err; + + mcast_grp = &nix_hw->mcast_grp; + elem = rvu_nix_mcast_find_grp_elem(mcast_grp, req->mcast_grp_idx); + if (!elem) + return NIX_AF_ERR_INVALID_MCAST_GRP; + + /* If any pcifunc matches the group's pcifunc, then we can + * delete the entire group. + */ + if (req->op == NIX_MCAST_OP_DEL_ENTRY) { + for (i = 0; i < req->num_mce_entry; i++) { + if (elem->pcifunc == req->pcifunc[i]) { + /* Delete group */ + dreq.hdr.pcifunc = elem->pcifunc; + dreq.mcast_grp_idx = elem->mcast_grp_idx; + dreq.is_af = req->is_af; + rvu_mbox_handler_nix_mcast_grp_destroy(rvu, &dreq, NULL); + return 0; + } + } + } + + mcast = &nix_hw->mcast; + mutex_lock(&mcast->mce_lock); + npc_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (elem->mcam_index != -1) + npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, elem->mcam_index, false); + + prev_count = elem->mcast_mce_list.count; + if (req->op == NIX_MCAST_OP_ADD_ENTRY) { + new_count = prev_count + req->num_mce_entry; + if (prev_count) + nix_free_mce_list(mcast, prev_count, elem->mce_start_index, elem->dir); + + elem->mce_start_index = nix_alloc_mce_list(mcast, new_count, elem->dir); + + /* It is possible not to get contiguous memory */ + if (elem->mce_start_index < 0) { + if (elem->mcam_index != -1) { + npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, + elem->mcam_index, true); + ret = NIX_AF_ERR_NON_CONTIG_MCE_LIST; + goto done; + } + } + + ret = nix_add_mce_list_entry(rvu, nix_hw, elem, req); + if (ret) { + nix_free_mce_list(mcast, new_count, elem->mce_start_index, elem->dir); + if (prev_count) + elem->mce_start_index = nix_alloc_mce_list(mcast, + prev_count, + elem->dir); + + if (elem->mcam_index != -1) + npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, + elem->mcam_index, true); + + goto done; + } + } else { + if (!prev_count || prev_count < req->num_mce_entry) { + if (elem->mcam_index != -1) + npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, + elem->mcam_index, true); + ret = NIX_AF_ERR_INVALID_MCAST_DEL_REQ; + goto done; + } + + nix_free_mce_list(mcast, prev_count, elem->mce_start_index, elem->dir); + new_count = prev_count - req->num_mce_entry; + elem->mce_start_index = nix_alloc_mce_list(mcast, new_count, elem->dir); + ret = nix_del_mce_list_entry(rvu, nix_hw, elem, req); + if (ret) { + nix_free_mce_list(mcast, new_count, elem->mce_start_index, elem->dir); + elem->mce_start_index = nix_alloc_mce_list(mcast, prev_count, elem->dir); + if (elem->mcam_index != -1) + npc_enable_mcam_entry(rvu, mcam, + npc_blkaddr, + elem->mcam_index, + true); + + goto done; + } + } + + if (elem->mcam_index == -1) { + rsp->mce_start_index = elem->mce_start_index; + ret = 0; + goto done; + } + + nix_mcast_update_action(rvu, elem); + npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, elem->mcam_index, true); + rsp->mce_start_index = elem->mce_start_index; + ret = 0; + +done: + mutex_unlock(&mcast->mce_lock); + return ret; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index 16cfc802e348..49babf968c1b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -589,8 +589,8 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, NPC_AF_MCAMEX_BANKX_CFG(dest, dbank), cfg); } -static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, - int blkaddr, int index) +u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index) { int bank = npc_get_bank(mcam, index); @@ -599,6 +599,16 @@ static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); } +void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index, u64 cfg) +{ + int bank = npc_get_bank(mcam, index); + + index &= (mcam->banksize - 1); + return rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg); +} + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, int nixlf, u64 chan, u8 *mac_addr) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index db8f151636af..c75669c8fde7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1117,13 +1117,40 @@ static void rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc, } } -static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, - struct mcam_entry *entry, - struct npc_install_flow_req *req, - u16 target, bool pf_set_vfs_mac) +static int npc_mcast_update_action_index(struct rvu *rvu, struct npc_install_flow_req *req, + u64 op, void *action) +{ + int mce_index; + + /* If a PF/VF is installing a multicast rule then it is expected + * that the PF/VF should have created a group for the multicast/mirror + * list. Otherwise reject the configuration. + * During this scenario, req->index is set as multicast/mirror + * group index. + */ + if (req->hdr.pcifunc && + (op == NIX_RX_ACTIONOP_MCAST || op == NIX_TX_ACTIONOP_MCAST)) { + mce_index = rvu_nix_mcast_get_mce_index(rvu, req->hdr.pcifunc, req->index); + if (mce_index < 0) + return mce_index; + + if (op == NIX_RX_ACTIONOP_MCAST) + ((struct nix_rx_action *)action)->index = mce_index; + else + ((struct nix_tx_action *)action)->index = mce_index; + } + + return 0; +} + +static int npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct mcam_entry *entry, + struct npc_install_flow_req *req, + u16 target, bool pf_set_vfs_mac) { struct rvu_switch *rswitch = &rvu->rswitch; struct nix_rx_action action; + int ret; if (rswitch->mode == DEVLINK_ESWITCH_MODE_SWITCHDEV && pf_set_vfs_mac) req->chan_mask = 0x0; /* Do not care channel */ @@ -1135,6 +1162,11 @@ static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, action.pf_func = target; action.op = req->op; action.index = req->index; + + ret = npc_mcast_update_action_index(rvu, req, action.op, (void *)&action); + if (ret) + return ret; + action.match_id = req->match_id; action.flow_key_alg = req->flow_key_alg; @@ -1166,14 +1198,17 @@ static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, FIELD_PREP(RX_VTAG1_TYPE_MASK, req->vtag1_type) | FIELD_PREP(RX_VTAG1_LID_MASK, NPC_LID_LB) | FIELD_PREP(RX_VTAG1_RELPTR_MASK, 4); + + return 0; } -static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, - struct mcam_entry *entry, - struct npc_install_flow_req *req, u16 target) +static int npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct mcam_entry *entry, + struct npc_install_flow_req *req, u16 target) { struct nix_tx_action action; u64 mask = ~0ULL; + int ret; /* If AF is installing then do not care about * PF_FUNC in Send Descriptor @@ -1187,6 +1222,11 @@ static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, *(u64 *)&action = 0x00; action.op = req->op; action.index = req->index; + + ret = npc_mcast_update_action_index(rvu, req, action.op, (void *)&action); + if (ret) + return ret; + action.match_id = req->match_id; entry->action = *(u64 *)&action; @@ -1202,6 +1242,8 @@ static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, FIELD_PREP(TX_VTAG1_OP_MASK, req->vtag1_op) | FIELD_PREP(TX_VTAG1_LID_MASK, NPC_LID_LA) | FIELD_PREP(TX_VTAG1_RELPTR_MASK, 24); + + return 0; } static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target, @@ -1231,10 +1273,15 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target, npc_update_flow(rvu, entry, features, &req->packet, &req->mask, &dummy, req->intf, blkaddr); - if (is_npc_intf_rx(req->intf)) - npc_update_rx_entry(rvu, pfvf, entry, req, target, pf_set_vfs_mac); - else - npc_update_tx_entry(rvu, pfvf, entry, req, target); + if (is_npc_intf_rx(req->intf)) { + err = npc_update_rx_entry(rvu, pfvf, entry, req, target, pf_set_vfs_mac); + if (err) + return err; + } else { + err = npc_update_tx_entry(rvu, pfvf, entry, req, target); + if (err) + return err; + } /* Default unicast rules do not exist for TX */ if (is_npc_intf_tx(req->intf)) @@ -1351,6 +1398,10 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target, return rvu_nix_setup_ratelimit_aggr(rvu, req->hdr.pcifunc, req->index, req->match_id); + if (owner && req->op == NIX_RX_ACTIONOP_MCAST) + return rvu_nix_mcast_update_mcam_entry(rvu, req->hdr.pcifunc, + req->index, entry_index); + return 0; } From df094d8fe886b31e7c648cca8bf401062ef1c049 Mon Sep 17 00:00:00 2001 From: Suman Ghosh Date: Thu, 30 Nov 2023 09:13:24 +0530 Subject: [PATCH 2369/7721] octeontx2-pf: TC flower offload support for mirror This patch extends TC flower offload support for mirroring ingress traffic to a different PF/VF. Below is an example command, 'tc filter add dev eth1 ingress protocol ip flower src_ip skip_sw action mirred ingress mirror dev eth2' Signed-off-by: Suman Ghosh Reviewed-by: Wojciech Drewek Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 113 +++++++++++++++++- 1 file changed, 110 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 757806be48a2..4fd44b6eecea 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -29,6 +29,8 @@ #define OTX2_UNSUPP_LSE_DEPTH GENMASK(6, 4) +#define MCAST_INVALID_GRP (-1U) + struct otx2_tc_flow_stats { u64 bytes; u64 pkts; @@ -47,6 +49,7 @@ struct otx2_tc_flow { bool is_act_police; u32 prio; struct npc_install_flow_req req; + u32 mcast_grp_idx; u64 rate; u32 burst; bool is_pps; @@ -355,22 +358,96 @@ static int otx2_tc_act_set_police(struct otx2_nic *nic, return rc; } +static int otx2_tc_update_mcast(struct otx2_nic *nic, + struct npc_install_flow_req *req, + struct netlink_ext_ack *extack, + struct otx2_tc_flow *node, + struct nix_mcast_grp_update_req *ureq, + u8 num_intf) +{ + struct nix_mcast_grp_update_req *grp_update_req; + struct nix_mcast_grp_create_req *creq; + struct nix_mcast_grp_create_rsp *crsp; + u32 grp_index; + int rc; + + mutex_lock(&nic->mbox.lock); + creq = otx2_mbox_alloc_msg_nix_mcast_grp_create(&nic->mbox); + if (!creq) { + rc = -ENOMEM; + goto error; + } + + creq->dir = NIX_MCAST_INGRESS; + /* Send message to AF */ + rc = otx2_sync_mbox_msg(&nic->mbox); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to create multicast group"); + goto error; + } + + crsp = (struct nix_mcast_grp_create_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox, + 0, + &creq->hdr); + if (IS_ERR(crsp)) { + rc = PTR_ERR(crsp); + goto error; + } + + grp_index = crsp->mcast_grp_idx; + grp_update_req = otx2_mbox_alloc_msg_nix_mcast_grp_update(&nic->mbox); + if (!grp_update_req) { + NL_SET_ERR_MSG_MOD(extack, "Failed to update multicast group"); + rc = -ENOMEM; + goto error; + } + + ureq->op = NIX_MCAST_OP_ADD_ENTRY; + ureq->mcast_grp_idx = grp_index; + ureq->num_mce_entry = num_intf; + ureq->pcifunc[0] = nic->pcifunc; + ureq->channel[0] = nic->hw.tx_chan_base; + + ureq->dest_type[0] = NIX_RX_RSS; + ureq->rq_rss_index[0] = 0; + memcpy(&ureq->hdr, &grp_update_req->hdr, sizeof(struct mbox_msghdr)); + memcpy(grp_update_req, ureq, sizeof(struct nix_mcast_grp_update_req)); + + /* Send message to AF */ + rc = otx2_sync_mbox_msg(&nic->mbox); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to update multicast group"); + goto error; + } + + mutex_unlock(&nic->mbox.lock); + req->op = NIX_RX_ACTIONOP_MCAST; + req->index = grp_index; + node->mcast_grp_idx = grp_index; + return 0; + +error: + mutex_unlock(&nic->mbox.lock); + return rc; +} + static int otx2_tc_parse_actions(struct otx2_nic *nic, struct flow_action *flow_action, struct npc_install_flow_req *req, struct flow_cls_offload *f, struct otx2_tc_flow *node) { + struct nix_mcast_grp_update_req dummy_grp_update_req = { 0 }; struct netlink_ext_ack *extack = f->common.extack; + bool pps = false, mcast = false; struct flow_action_entry *act; struct net_device *target; struct otx2_nic *priv; u32 burst, mark = 0; u8 nr_police = 0; - bool pps = false; + u8 num_intf = 1; + int err, i; u64 rate; - int err; - int i; if (!flow_action_has_entries(flow_action)) { NL_SET_ERR_MSG_MOD(extack, "no tc actions specified"); @@ -442,11 +519,30 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, req->index = act->rx_queue; break; + case FLOW_ACTION_MIRRED_INGRESS: + target = act->dev; + priv = netdev_priv(target); + dummy_grp_update_req.pcifunc[num_intf] = priv->pcifunc; + dummy_grp_update_req.channel[num_intf] = priv->hw.tx_chan_base; + dummy_grp_update_req.dest_type[num_intf] = NIX_RX_RSS; + dummy_grp_update_req.rq_rss_index[num_intf] = 0; + mcast = true; + num_intf++; + break; + default: return -EOPNOTSUPP; } } + if (mcast) { + err = otx2_tc_update_mcast(nic, req, extack, node, + &dummy_grp_update_req, + num_intf); + if (err) + return err; + } + if (nr_police > 1) { NL_SET_ERR_MSG_MOD(extack, "rate limit police offload requires a single action"); @@ -1066,6 +1162,7 @@ static int otx2_tc_del_flow(struct otx2_nic *nic, struct flow_cls_offload *tc_flow_cmd) { struct otx2_flow_config *flow_cfg = nic->flow_cfg; + struct nix_mcast_grp_destroy_req *grp_destroy_req; struct otx2_tc_flow *flow_node; int err; @@ -1099,6 +1196,15 @@ static int otx2_tc_del_flow(struct otx2_nic *nic, mutex_unlock(&nic->mbox.lock); } + /* Remove the multicast/mirror related nodes */ + if (flow_node->mcast_grp_idx != MCAST_INVALID_GRP) { + mutex_lock(&nic->mbox.lock); + grp_destroy_req = otx2_mbox_alloc_msg_nix_mcast_grp_destroy(&nic->mbox); + grp_destroy_req->mcast_grp_idx = flow_node->mcast_grp_idx; + otx2_sync_mbox_msg(&nic->mbox); + mutex_unlock(&nic->mbox.lock); + } + free_mcam_flow: otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL); @@ -1138,6 +1244,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, spin_lock_init(&new_node->lock); new_node->cookie = tc_flow_cmd->cookie; new_node->prio = tc_flow_cmd->common.prio; + new_node->mcast_grp_idx = MCAST_INVALID_GRP; memset(&dummy, 0, sizeof(struct npc_install_flow_req)); From e183130c9a87cc57c73ecc9c251e10d07b658530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 13 Jul 2023 09:52:35 +0200 Subject: [PATCH 2370/7721] sparc: Use $(kecho) to announce kernel images being ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My build test setup compiles allmodconfig all various architectures (arm64 m68k powerpc riscv s390 sparc64 x86_64) using make -s. If there is no warning, the only output is kernel: arch/sparc/boot/image is ready kernel: arch/sparc/boot/zImage is ready from the sparc64 build. Copy the incantation from x86 which is silent when building with make -s and also mentions a version indication. Signed-off-by: Uwe Kleine-König Acked-by: Sam Ravnborg Signed-off-by: Arnd Bergmann --- arch/sparc/boot/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index 45e5c76d449e..339c42d35089 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -24,16 +24,16 @@ ifeq ($(CONFIG_SPARC64),y) $(obj)/zImage: $(obj)/image FORCE $(call if_changed,gzip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' $(obj)/vmlinux.aout: vmlinux FORCE $(call if_changed,elftoaout) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' else $(obj)/zImage: $(obj)/image FORCE $(call if_changed,strip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' # The following lines make a readable image for U-Boot. # uImage - Binary file read by U-boot @@ -59,13 +59,13 @@ targets += uImage $(obj)/uImage: $(obj)/image.gz FORCE $(call if_changed,uimage) $(call if_changed,uimage.o) - @echo ' Image $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' endif $(obj)/image: vmlinux FORCE $(call if_changed,strip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback System.map $(ROOT_IMG) FORCE $(call if_changed,elftoaout) From 0b82a2b70f890e8dd7a46dfbfcce00bd7e434762 Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Wed, 15 Nov 2023 13:13:36 +0100 Subject: [PATCH 2371/7721] drm/bridge: lt8912b: Add suspend/resume support Add support for suspend and resume. The lt8912b will power off when going into suspend and power on when resuming. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231115121338.22959-2-francesco@dolcini.it --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 03532efb893b..097ab04234b7 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -634,6 +634,33 @@ static const struct drm_bridge_funcs lt8912_bridge_funcs = { .get_edid = lt8912_bridge_get_edid, }; +static int lt8912_bridge_resume(struct device *dev) +{ + struct lt8912 *lt = dev_get_drvdata(dev); + int ret; + + ret = lt8912_hard_power_on(lt); + if (ret) + return ret; + + ret = lt8912_soft_power_on(lt); + if (ret) + return ret; + + return lt8912_video_on(lt); +} + +static int lt8912_bridge_suspend(struct device *dev) +{ + struct lt8912 *lt = dev_get_drvdata(dev); + + lt8912_hard_power_off(lt); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(lt8912_bridge_pm_ops, lt8912_bridge_suspend, lt8912_bridge_resume); + static int lt8912_parse_dt(struct lt8912 *lt) { struct gpio_desc *gp_reset; @@ -770,6 +797,7 @@ static struct i2c_driver lt8912_i2c_driver = { .driver = { .name = "lt8912", .of_match_table = lt8912_dt_match, + .pm = pm_sleep_ptr(<8912_bridge_pm_ops), }, .probe = lt8912_probe, .remove = lt8912_remove, From f168c7f7d1a0cb12a4888af9f3f907139372f137 Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Wed, 15 Nov 2023 13:13:37 +0100 Subject: [PATCH 2372/7721] dt-bindings: display: bridge: lt8912b: Add power supplies Add Lontium lt8912b power supplies. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Acked-by: Conor Dooley Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231115121338.22959-3-francesco@dolcini.it --- .../display/bridge/lontium,lt8912b.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml index f201ae4af4fb..2cef25215798 100644 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml @@ -55,6 +55,27 @@ properties: - port@0 - port@1 + vcchdmipll-supply: + description: A 1.8V supply that powers the HDMI PLL. + + vcchdmitx-supply: + description: A 1.8V supply that powers the HDMI TX part. + + vcclvdspll-supply: + description: A 1.8V supply that powers the LVDS PLL. + + vcclvdstx-supply: + description: A 1.8V supply that powers the LVDS TX part. + + vccmipirx-supply: + description: A 1.8V supply that powers the MIPI RX part. + + vccsysclk-supply: + description: A 1.8V supply that powers the SYSCLK. + + vdd-supply: + description: A 1.8V supply that powers the digital part. + required: - compatible - reg From f6d8a80f1d10ff01cff3ac26e242165a270bbbad Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Wed, 15 Nov 2023 13:13:38 +0100 Subject: [PATCH 2373/7721] drm/bridge: lt8912b: Add power supplies Add supplies to the driver that can be used to turn the Lontium lt8912b on and off. It can have up to 7 independent supplies, we add them all and enable/disable them with bulk_enable/disable. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231115121338.22959-4-francesco@dolcini.it --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 097ab04234b7..273157428c82 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -43,6 +43,8 @@ struct lt8912 { struct videomode mode; + struct regulator_bulk_data supplies[7]; + u8 data_lanes; bool is_power_on; }; @@ -257,6 +259,12 @@ static int lt8912_free_i2c(struct lt8912 *lt) static int lt8912_hard_power_on(struct lt8912 *lt) { + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(lt->supplies), lt->supplies); + if (ret) + return ret; + gpiod_set_value_cansleep(lt->gp_reset, 0); msleep(20); @@ -267,6 +275,9 @@ static void lt8912_hard_power_off(struct lt8912 *lt) { gpiod_set_value_cansleep(lt->gp_reset, 1); msleep(20); + + regulator_bulk_disable(ARRAY_SIZE(lt->supplies), lt->supplies); + lt->is_power_on = false; } @@ -661,6 +672,21 @@ static int lt8912_bridge_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(lt8912_bridge_pm_ops, lt8912_bridge_suspend, lt8912_bridge_resume); +static int lt8912_get_regulators(struct lt8912 *lt) +{ + unsigned int i; + const char * const supply_names[] = { + "vdd", "vccmipirx", "vccsysclk", "vcclvdstx", + "vcchdmitx", "vcclvdspll", "vcchdmipll" + }; + + for (i = 0; i < ARRAY_SIZE(lt->supplies); i++) + lt->supplies[i].supply = supply_names[i]; + + return devm_regulator_bulk_get(lt->dev, ARRAY_SIZE(lt->supplies), + lt->supplies); +} + static int lt8912_parse_dt(struct lt8912 *lt) { struct gpio_desc *gp_reset; @@ -712,6 +738,10 @@ static int lt8912_parse_dt(struct lt8912 *lt) goto err_free_host_node; } + ret = lt8912_get_regulators(lt); + if (ret) + goto err_free_host_node; + of_node_put(port_node); return 0; From 914437992876838662c968cb416f832110fb1093 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Dec 2023 15:29:00 +0300 Subject: [PATCH 2374/7721] drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking The i2c_master_send/recv() functions return negative error codes or the number of bytes that were able to be sent/received. This code has two problems. 1) Instead of checking if all the bytes were sent or received, it checks that at least one byte was sent or received. 2) If there was a partial send/receive then we should return a negative error code but this code returns success. Fixes: a9fe713d7d45 ("drm/bridge: Add PTN3460 bridge driver") Cc: stable@vger.kernel.org Signed-off-by: Dan Carpenter Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/0cdc2dce-ca89-451a-9774-1482ab2f4762@moroto.mountain --- drivers/gpu/drm/bridge/nxp-ptn3460.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index d81920227a8a..9b7eb8c669c1 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -56,13 +56,13 @@ static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, ret = i2c_master_send(ptn_bridge->client, &addr, 1); if (ret <= 0) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); - return ret; + return ret ?: -EIO; } ret = i2c_master_recv(ptn_bridge->client, buf, len); - if (ret <= 0) { + if (ret != len) { DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); - return ret; + return ret < 0 ? ret : -EIO; } return 0; @@ -78,9 +78,9 @@ static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, buf[1] = val; ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); - if (ret <= 0) { + if (ret != ARRAY_SIZE(buf)) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); - return ret; + return ret < 0 ? ret : -EIO; } return 0; From 69724b3eac9894853e9b044b65e0add009fc88b5 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Tue, 14 Nov 2023 10:52:16 +0100 Subject: [PATCH 2375/7721] optee: add page list to kernel private shared memory Until now has kernel private shared memory allocated as dynamic shared memory (not from the static shared memory pool) been returned without a list of physical pages on allocations via RPC. To support allocations larger than one page add a list of physical pages. Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/optee/core.c | 32 ++++++++++++++------------ drivers/tee/optee/smc_abi.c | 45 +++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 2a258bd3b6b5..38ea2fecfc2e 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -27,7 +27,10 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, unsigned long start)) { unsigned int order = get_order(size); + unsigned int nr_pages = 1 << order; + struct page **pages; struct page *page; + unsigned int i; int rc = 0; /* @@ -42,30 +45,29 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, shm->paddr = page_to_phys(page); shm->size = PAGE_SIZE << order; + pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); + if (!pages) { + rc = -ENOMEM; + goto err; + } + + for (i = 0; i < nr_pages; i++) + pages[i] = page + i; + + shm->pages = pages; + shm->num_pages = nr_pages; + if (shm_register) { - unsigned int nr_pages = 1 << order, i; - struct page **pages; - - pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); - if (!pages) { - rc = -ENOMEM; - goto err; - } - - for (i = 0; i < nr_pages; i++) - pages[i] = page + i; - rc = shm_register(shm->ctx, shm, pages, nr_pages, (unsigned long)shm->kaddr); - kfree(pages); if (rc) goto err; } return 0; - err: free_pages((unsigned long)shm->kaddr, order); + shm->kaddr = NULL; return rc; } @@ -77,6 +79,8 @@ void optee_pool_op_free_helper(struct tee_shm_pool *pool, struct tee_shm *shm, shm_unregister(shm->ctx, shm); free_pages((unsigned long)shm->kaddr, get_order(shm->size)); shm->kaddr = NULL; + kfree(shm->pages); + shm->pages = NULL; } static void optee_bus_scan(struct work_struct *work) diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index d5b28fd35d66..b69410c7cc0a 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -678,10 +678,11 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, struct optee_msg_arg *arg, struct optee_call_ctx *call_ctx) { - phys_addr_t pa; struct tee_shm *shm; size_t sz; size_t n; + struct page **pages; + size_t page_count; arg->ret_origin = TEEC_ORIGIN_COMMS; @@ -716,32 +717,23 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, return; } - if (tee_shm_get_pa(shm, 0, &pa)) { - arg->ret = TEEC_ERROR_BAD_PARAMETERS; - goto bad; - } - - sz = tee_shm_get_size(shm); - - if (tee_shm_is_dynamic(shm)) { - struct page **pages; + /* + * If there are pages it's dynamically allocated shared memory (not + * from the reserved shared memory pool) and needs to be + * registered. + */ + pages = tee_shm_get_pages(shm, &page_count); + if (pages) { u64 *pages_list; - size_t page_num; - pages = tee_shm_get_pages(shm, &page_num); - if (!pages || !page_num) { - arg->ret = TEEC_ERROR_OUT_OF_MEMORY; - goto bad; - } - - pages_list = optee_allocate_pages_list(page_num); + pages_list = optee_allocate_pages_list(page_count); if (!pages_list) { arg->ret = TEEC_ERROR_OUT_OF_MEMORY; goto bad; } call_ctx->pages_list = pages_list; - call_ctx->num_entries = page_num; + call_ctx->num_entries = page_count; arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | OPTEE_MSG_ATTR_NONCONTIG; @@ -752,17 +744,22 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) | (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1)); - arg->params[0].u.tmem.size = tee_shm_get_size(shm); - arg->params[0].u.tmem.shm_ref = (unsigned long)shm; - optee_fill_pages_list(pages_list, pages, page_num, + optee_fill_pages_list(pages_list, pages, page_count, tee_shm_get_page_offset(shm)); } else { + phys_addr_t pa; + + if (tee_shm_get_pa(shm, 0, &pa)) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + goto bad; + } + arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; arg->params[0].u.tmem.buf_ptr = pa; - arg->params[0].u.tmem.size = sz; - arg->params[0].u.tmem.shm_ref = (unsigned long)shm; } + arg->params[0].u.tmem.size = tee_shm_get_size(shm); + arg->params[0].u.tmem.shm_ref = (unsigned long)shm; arg->ret = TEEC_SUCCESS; return; From aa041111311d35cb311543f43bc60b825b8cd109 Mon Sep 17 00:00:00 2001 From: Frank Binns Date: Mon, 4 Dec 2023 13:28:47 +0000 Subject: [PATCH 2376/7721] MAINTAINERS: Document Imagination PowerVR driver patches go via drm-misc This is the tree used by nearly all other DRM drivers, so use it for the PowerVR driver as well. Signed-off-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231204132847.1307340-1-frank.binns@imgtec.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0ba904b46efe..d4b46b3db022 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10397,6 +10397,7 @@ M: Frank Binns M: Donald Robson M: Matt Coster S: Supported +T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/gpu/img,powervr.yaml F: Documentation/gpu/imagination/ F: drivers/gpu/drm/imagination/ From 225a36b96359aceaa9a6399f2dff99627397e637 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Tue, 14 Nov 2023 10:52:17 +0100 Subject: [PATCH 2377/7721] optee: allocate shared memory with alloc_pages_exact() Allocate memory to share with the secure world using alloc_pages_exact() instead of alloc_pages() for more efficient memory usage. Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/optee/core.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 38ea2fecfc2e..4a4b03b4fc7d 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -26,10 +26,8 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, size_t num_pages, unsigned long start)) { - unsigned int order = get_order(size); - unsigned int nr_pages = 1 << order; + size_t nr_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; struct page **pages; - struct page *page; unsigned int i; int rc = 0; @@ -37,13 +35,13 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, * Ignore alignment since this is already going to be page aligned * and there's no need for any larger alignment. */ - page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!page) + shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE, + GFP_KERNEL | __GFP_ZERO); + if (!shm->kaddr) return -ENOMEM; - shm->kaddr = page_address(page); - shm->paddr = page_to_phys(page); - shm->size = PAGE_SIZE << order; + shm->paddr = virt_to_phys(shm->kaddr); + shm->size = nr_pages * PAGE_SIZE; pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); if (!pages) { @@ -52,7 +50,7 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, } for (i = 0; i < nr_pages; i++) - pages[i] = page + i; + pages[i] = virt_to_page((u8 *)shm->kaddr + i * PAGE_SIZE); shm->pages = pages; shm->num_pages = nr_pages; @@ -66,7 +64,7 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, return 0; err: - free_pages((unsigned long)shm->kaddr, order); + free_pages_exact(shm->kaddr, shm->size); shm->kaddr = NULL; return rc; } @@ -77,7 +75,7 @@ void optee_pool_op_free_helper(struct tee_shm_pool *pool, struct tee_shm *shm, { if (shm_unregister) shm_unregister(shm->ctx, shm); - free_pages((unsigned long)shm->kaddr, get_order(shm->size)); + free_pages_exact(shm->kaddr, shm->size); shm->kaddr = NULL; kfree(shm->pages); shm->pages = NULL; From 2a04739139b2b2761571e18937e2400e71eff664 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:28 +0300 Subject: [PATCH 2378/7721] drm/bridge: add transparent bridge helper Define a helper for creating simple transparent bridges which serve the only purpose of linking devices into the bridge chain up to the last bridge representing the connector. This is especially useful for DP/USB-C bridge chains, which can span across several devices, but do not require any additional functionality from the intermediate bridges. Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/bridge/Kconfig | 9 ++ drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/aux-bridge.c | 140 ++++++++++++++++++++++++++++ include/drm/bridge/aux-bridge.h | 19 ++++ 4 files changed, 169 insertions(+) create mode 100644 drivers/gpu/drm/bridge/aux-bridge.c create mode 100644 include/drm/bridge/aux-bridge.h diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index ba82a1142adf..f12eab62799f 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -12,6 +12,15 @@ config DRM_PANEL_BRIDGE help DRM bridge wrapper of DRM panels +config DRM_AUX_BRIDGE + tristate + depends on DRM_BRIDGE && OF + select AUXILIARY_BUS + select DRM_PANEL_BRIDGE + help + Simple transparent bridge that is used by several non-DRM drivers to + build bridges chain. + menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 2b892b7ed59e..918e3bfff079 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c new file mode 100644 index 000000000000..49d7c2ab1ecc --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Linaro Ltd. + * + * Author: Dmitry Baryshkov + */ +#include +#include + +#include +#include + +static DEFINE_IDA(drm_aux_bridge_ida); + +static void drm_aux_bridge_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + ida_free(&drm_aux_bridge_ida, adev->id); + + kfree(adev); +} + +static void drm_aux_bridge_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +/** + * drm_aux_bridge_register - Create a simple bridge device to link the chain + * @parent: device instance providing this bridge + * + * Creates a simple DRM bridge that doesn't implement any drm_bridge + * operations. Such bridges merely fill a place in the bridge chain linking + * surrounding DRM bridges. + * + * Return: zero on success, negative error code on failure + */ +int drm_aux_bridge_register(struct device *parent) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + ret = ida_alloc(&drm_aux_bridge_ida, GFP_KERNEL); + if (ret < 0) { + kfree(adev); + return ret; + } + + adev->id = ret; + adev->name = "aux_bridge"; + adev->dev.parent = parent; + adev->dev.of_node = parent->of_node; + adev->dev.release = drm_aux_bridge_release; + + ret = auxiliary_device_init(adev); + if (ret) { + ida_free(&drm_aux_bridge_ida, adev->id); + kfree(adev); + return ret; + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev); +} +EXPORT_SYMBOL_GPL(drm_aux_bridge_register); + +struct drm_aux_bridge_data { + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct device *dev; +}; + +static int drm_aux_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct drm_aux_bridge_data *data; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + data = container_of(bridge, struct drm_aux_bridge_data, bridge); + + return drm_bridge_attach(bridge->encoder, data->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); +} + +static const struct drm_bridge_funcs drm_aux_bridge_funcs = { + .attach = drm_aux_bridge_attach, +}; + +static int drm_aux_bridge_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct drm_aux_bridge_data *data; + + data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &auxdev->dev; + data->next_bridge = devm_drm_of_get_bridge(&auxdev->dev, auxdev->dev.of_node, 0, 0); + if (IS_ERR(data->next_bridge)) + return dev_err_probe(&auxdev->dev, PTR_ERR(data->next_bridge), + "failed to acquire drm_bridge\n"); + + data->bridge.funcs = &drm_aux_bridge_funcs; + data->bridge.of_node = data->dev->of_node; + + return devm_drm_bridge_add(data->dev, &data->bridge); +} + +static const struct auxiliary_device_id drm_aux_bridge_table[] = { + { .name = KBUILD_MODNAME ".aux_bridge" }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, drm_aux_bridge_table); + +static struct auxiliary_driver drm_aux_bridge_drv = { + .name = "aux_bridge", + .id_table = drm_aux_bridge_table, + .probe = drm_aux_bridge_probe, +}; +module_auxiliary_driver(drm_aux_bridge_drv); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("DRM transparent bridge"); +MODULE_LICENSE("GPL"); diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h new file mode 100644 index 000000000000..b3a9cc9c862f --- /dev/null +++ b/include/drm/bridge/aux-bridge.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023 Linaro Ltd. + * + * Author: Dmitry Baryshkov + */ +#ifndef DRM_AUX_BRIDGE_H +#define DRM_AUX_BRIDGE_H + +#if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) +int drm_aux_bridge_register(struct device *parent); +#else +static inline int drm_aux_bridge_register(struct device *parent) +{ + return 0; +} +#endif + +#endif From 35921910bbd0b6ab595cead16d0c8faadbf2fd94 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:29 +0300 Subject: [PATCH 2379/7721] phy: qcom: qmp-combo: switch to DRM_AUX_BRIDGE Switch to using the new DRM_AUX_BRIDGE helper to create the transparent DRM bridge device instead of handcoding corresponding functionality. Acked-by: Vinod Koul Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-3-dmitry.baryshkov@linaro.org --- drivers/phy/qualcomm/Kconfig | 2 +- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 44 ++--------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index d891058b7c39..846f8c99547f 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -63,7 +63,7 @@ config PHY_QCOM_QMP_COMBO depends on DRM || DRM=n select GENERIC_PHY select MFD_SYSCON - select DRM_PANEL_BRIDGE if DRM + select DRM_AUX_BRIDGE if DRM_BRIDGE help Enable this to support the QMP Combo PHY transceiver that is used with USB3 and DisplayPort controllers on Qualcomm chips. diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 9c87845c78ec..f6c727249104 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include @@ -1419,8 +1419,6 @@ struct qmp_combo { struct clk_hw dp_link_hw; struct clk_hw dp_pixel_hw; - struct drm_bridge bridge; - struct typec_switch_dev *sw; enum typec_orientation orientation; }; @@ -3191,44 +3189,6 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) } #endif -#if IS_ENABLED(CONFIG_DRM) -static int qmp_combo_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct qmp_combo *qmp = container_of(bridge, struct qmp_combo, bridge); - struct drm_bridge *next_bridge; - - if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) - return -EINVAL; - - next_bridge = devm_drm_of_get_bridge(qmp->dev, qmp->dev->of_node, 0, 0); - if (IS_ERR(next_bridge)) { - dev_err(qmp->dev, "failed to acquire drm_bridge: %pe\n", next_bridge); - return PTR_ERR(next_bridge); - } - - return drm_bridge_attach(bridge->encoder, next_bridge, bridge, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); -} - -static const struct drm_bridge_funcs qmp_combo_bridge_funcs = { - .attach = qmp_combo_bridge_attach, -}; - -static int qmp_combo_dp_register_bridge(struct qmp_combo *qmp) -{ - qmp->bridge.funcs = &qmp_combo_bridge_funcs; - qmp->bridge.of_node = qmp->dev->of_node; - - return devm_drm_bridge_add(qmp->dev, &qmp->bridge); -} -#else -static int qmp_combo_dp_register_bridge(struct qmp_combo *qmp) -{ - return 0; -} -#endif - static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np) { struct device *dev = qmp->dev; @@ -3440,7 +3400,7 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_combo_dp_register_bridge(qmp); + ret = drm_aux_bridge_register(dev); if (ret) return ret; From c5d296bad640b190c52ef7508114d70e971a4bba Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:30 +0300 Subject: [PATCH 2380/7721] usb: typec: nb7vpq904m: switch to DRM_AUX_BRIDGE Switch to using the new DRM_AUX_BRIDGE helper to create the transparent DRM bridge device instead of handcoding corresponding functionality. Reviewed-by: Heikki Krogerus Acked-by: Greg Kroah-Hartman Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-4-dmitry.baryshkov@linaro.org --- drivers/usb/typec/mux/Kconfig | 2 +- drivers/usb/typec/mux/nb7vpq904m.c | 44 ++---------------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 816b9bd08355..5120942f309d 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -40,7 +40,7 @@ config TYPEC_MUX_NB7VPQ904M tristate "On Semiconductor NB7VPQ904M Type-C redriver driver" depends on I2C depends on DRM || DRM=n - select DRM_PANEL_BRIDGE if DRM + select DRM_AUX_BRIDGE if DRM_BRIDGE select REGMAP_I2C help Say Y or M if your system has a On Semiconductor NB7VPQ904M Type-C diff --git a/drivers/usb/typec/mux/nb7vpq904m.c b/drivers/usb/typec/mux/nb7vpq904m.c index cda206cf0c38..b17826713753 100644 --- a/drivers/usb/typec/mux/nb7vpq904m.c +++ b/drivers/usb/typec/mux/nb7vpq904m.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,8 +70,6 @@ struct nb7vpq904m { bool swap_data_lanes; struct typec_switch *typec_switch; - struct drm_bridge bridge; - struct mutex lock; /* protect non-concurrent retimer & switch */ enum typec_orientation orientation; @@ -297,44 +295,6 @@ static int nb7vpq904m_retimer_set(struct typec_retimer *retimer, struct typec_re return ret; } -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE) -static int nb7vpq904m_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct nb7vpq904m *nb7 = container_of(bridge, struct nb7vpq904m, bridge); - struct drm_bridge *next_bridge; - - if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) - return -EINVAL; - - next_bridge = devm_drm_of_get_bridge(&nb7->client->dev, nb7->client->dev.of_node, 0, 0); - if (IS_ERR(next_bridge)) { - dev_err(&nb7->client->dev, "failed to acquire drm_bridge: %pe\n", next_bridge); - return PTR_ERR(next_bridge); - } - - return drm_bridge_attach(bridge->encoder, next_bridge, bridge, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); -} - -static const struct drm_bridge_funcs nb7vpq904m_bridge_funcs = { - .attach = nb7vpq904m_bridge_attach, -}; - -static int nb7vpq904m_register_bridge(struct nb7vpq904m *nb7) -{ - nb7->bridge.funcs = &nb7vpq904m_bridge_funcs; - nb7->bridge.of_node = nb7->client->dev.of_node; - - return devm_drm_bridge_add(&nb7->client->dev, &nb7->bridge); -} -#else -static int nb7vpq904m_register_bridge(struct nb7vpq904m *nb7) -{ - return 0; -} -#endif - static const struct regmap_config nb7_regmap = { .max_register = 0x1f, .reg_bits = 8, @@ -461,7 +421,7 @@ static int nb7vpq904m_probe(struct i2c_client *client) gpiod_set_value(nb7->enable_gpio, 1); - ret = nb7vpq904m_register_bridge(nb7); + ret = drm_aux_bridge_register(dev); if (ret) goto err_disable_gpio; From e560518a6c2e60f1566473c146fddcff3281f617 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:31 +0300 Subject: [PATCH 2381/7721] drm/bridge: implement generic DP HPD bridge Several USB-C controllers implement a pretty simple DRM bridge which implements just the HPD notification operations. Add special helper for creating such simple bridges. Acked-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-5-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/bridge/Kconfig | 8 ++ drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/aux-hpd-bridge.c | 163 ++++++++++++++++++++++++ include/drm/bridge/aux-bridge.h | 18 +++ 4 files changed, 190 insertions(+) create mode 100644 drivers/gpu/drm/bridge/aux-hpd-bridge.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index f12eab62799f..19d2dc05c397 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -21,6 +21,14 @@ config DRM_AUX_BRIDGE Simple transparent bridge that is used by several non-DRM drivers to build bridges chain. +config DRM_AUX_HPD_BRIDGE + tristate + depends on DRM_BRIDGE && OF + select AUXILIARY_BUS + help + Simple bridge that terminates the bridge chain and provides HPD + support. + menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 918e3bfff079..017b5832733b 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o +obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.o obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c new file mode 100644 index 000000000000..5d2ab3a715f9 --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Linaro Ltd. + * + * Author: Dmitry Baryshkov + */ +#include +#include +#include + +#include +#include + +static DEFINE_IDA(drm_aux_hpd_bridge_ida); + +struct drm_aux_hpd_bridge_data { + struct drm_bridge bridge; + struct device *dev; +}; + +static void drm_aux_hpd_bridge_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + ida_free(&drm_aux_hpd_bridge_ida, adev->id); + + of_node_put(adev->dev.platform_data); + + kfree(adev); +} + +static void drm_aux_hpd_bridge_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +/** + * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge + * @parent: device instance providing this bridge + * @np: device node pointer corresponding to this bridge instance + * + * Creates a simple DRM bridge with the type set to + * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is + * able to send the HPD events. + * + * Return: device instance that will handle created bridge or an error code + * encoded into the pointer. + */ +struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return ERR_PTR(-ENOMEM); + + ret = ida_alloc(&drm_aux_hpd_bridge_ida, GFP_KERNEL); + if (ret < 0) { + kfree(adev); + return ERR_PTR(ret); + } + + adev->id = ret; + adev->name = "dp_hpd_bridge"; + adev->dev.parent = parent; + adev->dev.of_node = parent->of_node; + adev->dev.release = drm_aux_hpd_bridge_release; + adev->dev.platform_data = np; + + ret = auxiliary_device_init(adev); + if (ret) { + ida_free(&drm_aux_hpd_bridge_ida, adev->id); + kfree(adev); + return ERR_PTR(ret); + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ERR_PTR(ret); + } + + ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev); + if (ret) + return ERR_PTR(ret); + + return &adev->dev; +} +EXPORT_SYMBOL_GPL(drm_dp_hpd_bridge_register); + +/** + * drm_aux_hpd_bridge_notify - notify hot plug detection events + * @dev: device created for the HPD bridge + * @status: output connection status + * + * A wrapper around drm_bridge_hpd_notify() that is used to report hot plug + * detection events for bridges created via drm_dp_hpd_bridge_register(). + * + * This function shall be called in a context that can sleep. + */ +void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct drm_aux_hpd_bridge_data *data = auxiliary_get_drvdata(adev); + + if (!data) + return; + + drm_bridge_hpd_notify(&data->bridge, status); +} +EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify); + +static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; +} + +static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = { + .attach = drm_aux_hpd_bridge_attach, +}; + +static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct drm_aux_hpd_bridge_data *data; + + data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &auxdev->dev; + data->bridge.funcs = &drm_aux_hpd_bridge_funcs; + data->bridge.of_node = dev_get_platdata(data->dev); + data->bridge.ops = DRM_BRIDGE_OP_HPD; + data->bridge.type = id->driver_data; + + auxiliary_set_drvdata(auxdev, data); + + return devm_drm_bridge_add(data->dev, &data->bridge); +} + +static const struct auxiliary_device_id drm_aux_hpd_bridge_table[] = { + { .name = KBUILD_MODNAME ".dp_hpd_bridge", .driver_data = DRM_MODE_CONNECTOR_DisplayPort, }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, drm_aux_hpd_bridge_table); + +static struct auxiliary_driver drm_aux_hpd_bridge_drv = { + .name = "aux_hpd_bridge", + .id_table = drm_aux_hpd_bridge_table, + .probe = drm_aux_hpd_bridge_probe, +}; +module_auxiliary_driver(drm_aux_hpd_bridge_drv); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("DRM HPD bridge"); +MODULE_LICENSE("GPL"); diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h index b3a9cc9c862f..66249ff0858e 100644 --- a/include/drm/bridge/aux-bridge.h +++ b/include/drm/bridge/aux-bridge.h @@ -7,6 +7,8 @@ #ifndef DRM_AUX_BRIDGE_H #define DRM_AUX_BRIDGE_H +#include + #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) int drm_aux_bridge_register(struct device *parent); #else @@ -16,4 +18,20 @@ static inline int drm_aux_bridge_register(struct device *parent) } #endif +#if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE) +struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np); +void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status); +#else +static inline struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np) +{ + return 0; +} + +static inline void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) +{ +} +#endif + #endif From 2bcca96abfbf89d26fc10fc92e40532bb2ae8891 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:32 +0300 Subject: [PATCH 2382/7721] soc: qcom: pmic-glink: switch to DRM_AUX_HPD_BRIDGE Use the freshly defined DRM_AUX_HPD_BRIDGE instead of open-coding the same functionality for the DRM bridge chain termination. Reviewed-by: Bjorn Andersson Acked-by: Bjorn Andersson Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-6-dmitry.baryshkov@linaro.org --- drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/pmic_glink_altmode.c | 33 ++++++++------------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b3634e10f6f5..c954001ae79e 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -86,6 +86,7 @@ config QCOM_PMIC_GLINK depends on OF select AUXILIARY_BUS select QCOM_PDR_HELPERS + select DRM_AUX_HPD_BRIDGE help The Qualcomm PMIC GLINK driver provides access, over GLINK, to the USB and battery firmware running on one of the coprocessors in diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index b78279e2f54c..053b7393e26a 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -76,7 +76,7 @@ struct pmic_glink_altmode_port { struct work_struct work; - struct drm_bridge bridge; + struct device *bridge; enum typec_orientation orientation; u16 svid; @@ -230,10 +230,10 @@ static void pmic_glink_altmode_worker(struct work_struct *work) else pmic_glink_altmode_enable_usb(altmode, alt_port); - if (alt_port->hpd_state) - drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected); - else - drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected); + drm_aux_hpd_bridge_notify(alt_port->bridge, + alt_port->hpd_state ? + connector_status_connected : + connector_status_disconnected); pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index); }; @@ -365,16 +365,6 @@ static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv } } -static int pmic_glink_altmode_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; -} - -static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = { - .attach = pmic_glink_altmode_attach, -}; - static void pmic_glink_altmode_put_retimer(void *data) { typec_retimer_put(data); @@ -464,15 +454,10 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, alt_port->index = port; INIT_WORK(&alt_port->work, pmic_glink_altmode_worker); - alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs; - alt_port->bridge.of_node = to_of_node(fwnode); - alt_port->bridge.ops = DRM_BRIDGE_OP_HPD; - alt_port->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; - - ret = devm_drm_bridge_add(dev, &alt_port->bridge); - if (ret) { + alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode)); + if (IS_ERR(alt_port->bridge)) { fwnode_handle_put(fwnode); - return ret; + return PTR_ERR(alt_port->bridge); } alt_port->dp_alt.svid = USB_TYPEC_DP_SID; From 7d9f1b72b29698e3030c2b163522cf4aa91b47e9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:43:33 +0300 Subject: [PATCH 2383/7721] usb: typec: qcom-pmic-typec: switch to DRM_AUX_HPD_BRIDGE Use the freshly defined DRM_AUX_HPD_BRIDGE instead of open-coding the same functionality for the DRM bridge chain termination. Acked-by: Bryan O'Donoghue Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-7-dmitry.baryshkov@linaro.org --- drivers/usb/typec/tcpm/Kconfig | 1 + drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c | 41 +++---------------- 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 0b2993fef564..64d5421c69e6 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -80,6 +80,7 @@ config TYPEC_QCOM_PMIC tristate "Qualcomm PMIC USB Type-C Port Controller Manager driver" depends on ARCH_QCOM || COMPILE_TEST depends on DRM || DRM=n + select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE help A Type-C port and Power Delivery driver which aggregates two discrete pieces of silicon in the PM8150b PMIC block: the diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c index 581199d37b49..1a2b4bddaa97 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include "qcom_pmic_typec_pdphy.h" #include "qcom_pmic_typec_port.h" @@ -36,7 +36,6 @@ struct pmic_typec { struct pmic_typec_port *pmic_typec_port; bool vbus_enabled; struct mutex lock; /* VBUS state serialization */ - struct drm_bridge bridge; }; #define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc) @@ -150,35 +149,6 @@ static int qcom_pmic_typec_init(struct tcpc_dev *tcpc) return 0; } -#if IS_ENABLED(CONFIG_DRM) -static int qcom_pmic_typec_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; -} - -static const struct drm_bridge_funcs qcom_pmic_typec_bridge_funcs = { - .attach = qcom_pmic_typec_attach, -}; - -static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm) -{ - tcpm->bridge.funcs = &qcom_pmic_typec_bridge_funcs; -#ifdef CONFIG_OF - tcpm->bridge.of_node = of_get_child_by_name(tcpm->dev->of_node, "connector"); -#endif - tcpm->bridge.ops = DRM_BRIDGE_OP_HPD; - tcpm->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; - - return devm_drm_bridge_add(tcpm->dev, &tcpm->bridge); -} -#else -static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm) -{ - return 0; -} -#endif - static int qcom_pmic_typec_probe(struct platform_device *pdev) { struct pmic_typec *tcpm; @@ -186,6 +156,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; const struct pmic_typec_resources *res; struct regmap *regmap; + struct device *bridge_dev; u32 base[2]; int ret; @@ -241,14 +212,14 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) mutex_init(&tcpm->lock); platform_set_drvdata(pdev, tcpm); - ret = qcom_pmic_typec_init_drm(tcpm); - if (ret) - return ret; - tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector"); if (!tcpm->tcpc.fwnode) return -EINVAL; + bridge_dev = drm_dp_hpd_bridge_register(tcpm->dev, to_of_node(tcpm->tcpc.fwnode)); + if (IS_ERR(bridge_dev)) + return PTR_ERR(bridge_dev); + tcpm->tcpm_port = tcpm_register_port(tcpm->dev, &tcpm->tcpc); if (IS_ERR(tcpm->tcpm_port)) { ret = PTR_ERR(tcpm->tcpm_port); From caf525ed45b4960b450cbd4e811d9b247bc2586c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:53:13 +0300 Subject: [PATCH 2384/7721] drm/encoder: register per-encoder debugfs dir Each of connectors and CRTCs used by the DRM device provides debugfs directory, which is used by several standard debugfs files and can further be extended by the driver. Add such generic debugfs directories for encoder. Reviewed-by: Neil Armstrong Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203115315.1306124-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_debugfs.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/drm_encoder.c | 4 ++++ drivers/gpu/drm/drm_internal.h | 10 ++++++++++ include/drm/drm_encoder.h | 16 +++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f291fb4b359f..00406b4f3235 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -589,4 +589,29 @@ void drm_debugfs_crtc_remove(struct drm_crtc *crtc) crtc->debugfs_entry = NULL; } +void drm_debugfs_encoder_add(struct drm_encoder *encoder) +{ + struct drm_minor *minor = encoder->dev->primary; + struct dentry *root; + char *name; + + name = kasprintf(GFP_KERNEL, "encoder-%d", encoder->index); + if (!name) + return; + + root = debugfs_create_dir(name, minor->debugfs_root); + kfree(name); + + encoder->debugfs_entry = root; + + if (encoder->funcs->debugfs_init) + encoder->funcs->debugfs_init(encoder, root); +} + +void drm_debugfs_encoder_remove(struct drm_encoder *encoder) +{ + debugfs_remove_recursive(encoder->debugfs_entry); + encoder->debugfs_entry = NULL; +} + #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 1143bc7f3252..8f2bc6a28482 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -30,6 +30,7 @@ #include #include "drm_crtc_internal.h" +#include "drm_internal.h" /** * DOC: overview @@ -74,6 +75,8 @@ int drm_encoder_register_all(struct drm_device *dev) int ret = 0; drm_for_each_encoder(encoder, dev) { + drm_debugfs_encoder_add(encoder); + if (encoder->funcs && encoder->funcs->late_register) ret = encoder->funcs->late_register(encoder); if (ret) @@ -90,6 +93,7 @@ void drm_encoder_unregister_all(struct drm_device *dev) drm_for_each_encoder(encoder, dev) { if (encoder->funcs && encoder->funcs->early_unregister) encoder->funcs->early_unregister(encoder); + drm_debugfs_encoder_remove(encoder); } } diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b12c463bc460..b7a311efa2b1 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -194,6 +194,8 @@ void drm_debugfs_connector_remove(struct drm_connector *connector); void drm_debugfs_crtc_add(struct drm_crtc *crtc); void drm_debugfs_crtc_remove(struct drm_crtc *crtc); void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc); +void drm_debugfs_encoder_add(struct drm_encoder *encoder); +void drm_debugfs_encoder_remove(struct drm_encoder *encoder); #else static inline void drm_debugfs_dev_fini(struct drm_device *dev) { @@ -231,6 +233,14 @@ static inline void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) { } +static inline void drm_debugfs_encoder_add(struct drm_encoder *encoder) +{ +} + +static inline void drm_debugfs_encoder_remove(struct drm_encoder *encoder) +{ +} + #endif drm_ioctl_t drm_version; diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 3a09682af685..977a9381c8ba 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -60,7 +60,7 @@ struct drm_encoder_funcs { * @late_register: * * This optional hook can be used to register additional userspace - * interfaces attached to the encoder like debugfs interfaces. + * interfaces attached to the encoder. * It is called late in the driver load sequence from drm_dev_register(). * Everything added from this callback should be unregistered in * the early_unregister callback. @@ -81,6 +81,13 @@ struct drm_encoder_funcs { * before data structures are torndown. */ void (*early_unregister)(struct drm_encoder *encoder); + + /** + * @debugfs_init: + * + * Allows encoders to create encoder-specific debugfs files. + */ + void (*debugfs_init)(struct drm_encoder *encoder, struct dentry *root); }; /** @@ -184,6 +191,13 @@ struct drm_encoder { const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; + + /** + * @debugfs_entry: + * + * Debugfs directory for this CRTC. + */ + struct dentry *debugfs_entry; }; #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) From d0b3c318e04cc6c4e2a3c30ee0f6f619aa8d0db5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 14:53:14 +0300 Subject: [PATCH 2385/7721] drm/bridge: migrate bridge_chains to per-encoder file Instead of having a single file with all bridge chains, list bridges under a corresponding per-encoder debugfs directory. While we are at it, also slightly improve the formatting of the bridge data: split a single line entry into multiple lines, include the symbol name of the bridge funcs and add the textual representation of the bridge ops. Example of the listing: $ cat /sys/kernel/debug/dri/0/encoder-0/bridges bridge[0]: dsi_mgr_bridge_funcs type: [0] Unknown ops: [0] bridge[1]: lt9611uxc_bridge_funcs type: [11] HDMI-A OF: /soc@0/geniqup@9c0000/i2c@994000/hdmi-bridge@2b:lontium,lt9611uxc ops: [7] detect edid hpd Reviewed-by: Neil Armstrong Reviewed-by: Tomi Valkeinen Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203115315.1306124-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_bridge.c | 44 ----------------------------------- drivers/gpu/drm/drm_debugfs.c | 40 ++++++++++++++++++++++++++++--- include/drm/drm_bridge.h | 2 -- 3 files changed, 37 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 30d66bee0ec6..cee3188adf3d 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1347,50 +1347,6 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) EXPORT_SYMBOL(of_drm_find_bridge); #endif -#ifdef CONFIG_DEBUG_FS -static int drm_bridge_chains_info(struct seq_file *m, void *data) -{ - struct drm_debugfs_entry *entry = m->private; - struct drm_device *dev = entry->dev; - struct drm_printer p = drm_seq_file_printer(m); - struct drm_mode_config *config = &dev->mode_config; - struct drm_encoder *encoder; - unsigned int bridge_idx = 0; - - list_for_each_entry(encoder, &config->encoder_list, head) { - struct drm_bridge *bridge; - - drm_printf(&p, "encoder[%u]\n", encoder->base.id); - - drm_for_each_bridge_in_chain(encoder, bridge) { - drm_printf(&p, "\tbridge[%u] type: %u, ops: %#x", - bridge_idx, bridge->type, bridge->ops); - -#ifdef CONFIG_OF - if (bridge->of_node) - drm_printf(&p, ", OF: %pOFfc", bridge->of_node); -#endif - - drm_printf(&p, "\n"); - - bridge_idx++; - } - } - - return 0; -} - -static const struct drm_debugfs_info drm_bridge_debugfs_list[] = { - { "bridge_chains", drm_bridge_chains_info, 0 }, -}; - -void drm_bridge_debugfs_init(struct drm_device *dev) -{ - drm_debugfs_add_files(dev, drm_bridge_debugfs_list, - ARRAY_SIZE(drm_bridge_debugfs_list)); -} -#endif - MODULE_AUTHOR("Ajay Kumar "); MODULE_DESCRIPTION("DRM bridge infrastructure"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 00406b4f3235..02e7481758c0 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -314,10 +314,8 @@ void drm_debugfs_dev_register(struct drm_device *dev) drm_framebuffer_debugfs_init(dev); drm_client_debugfs_init(dev); } - if (drm_drv_uses_atomic_modeset(dev)) { + if (drm_drv_uses_atomic_modeset(dev)) drm_atomic_debugfs_init(dev); - drm_bridge_debugfs_init(dev); - } } int drm_debugfs_register(struct drm_minor *minor, int minor_id, @@ -589,6 +587,38 @@ void drm_debugfs_crtc_remove(struct drm_crtc *crtc) crtc->debugfs_entry = NULL; } +static int bridges_show(struct seq_file *m, void *data) +{ + struct drm_encoder *encoder = m->private; + struct drm_printer p = drm_seq_file_printer(m); + struct drm_bridge *bridge; + unsigned int idx = 0; + + drm_for_each_bridge_in_chain(encoder, bridge) { + drm_printf(&p, "bridge[%d]: %ps\n", idx++, bridge->funcs); + drm_printf(&p, "\ttype: [%d] %s\n", + bridge->type, + drm_get_connector_type_name(bridge->type)); +#ifdef CONFIG_OF + if (bridge->of_node) + drm_printf(&p, "\tOF: %pOFfc\n", bridge->of_node); +#endif + drm_printf(&p, "\tops: [0x%x]", bridge->ops); + if (bridge->ops & DRM_BRIDGE_OP_DETECT) + drm_puts(&p, " detect"); + if (bridge->ops & DRM_BRIDGE_OP_EDID) + drm_puts(&p, " edid"); + if (bridge->ops & DRM_BRIDGE_OP_HPD) + drm_puts(&p, " hpd"); + if (bridge->ops & DRM_BRIDGE_OP_MODES) + drm_puts(&p, " modes"); + drm_puts(&p, "\n"); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(bridges); + void drm_debugfs_encoder_add(struct drm_encoder *encoder) { struct drm_minor *minor = encoder->dev->primary; @@ -604,6 +634,10 @@ void drm_debugfs_encoder_add(struct drm_encoder *encoder) encoder->debugfs_entry = root; + /* bridges list */ + debugfs_create_file("bridges", 0444, root, encoder, + &bridges_fops); + if (encoder->funcs->debugfs_init) encoder->funcs->debugfs_init(encoder, root); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 9ef461aa9b9e..e39da5807ba7 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -950,6 +950,4 @@ static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, } #endif -void drm_bridge_debugfs_init(struct drm_device *dev); - #endif From 5bd90cdc65ef9ef5e13c9ff23620079db5c608a0 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Sun, 3 Dec 2023 20:12:48 -0500 Subject: [PATCH 2386/7721] bpf: Minor logging improvement One place where we were logging a register was only logging the variable part, not also the fixed part. Signed-off-by: Andrei Matei Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231204011248.2040084-1-andreimatei1@gmail.com --- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2cd150d6d141..cdb4f5f0ba79 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6585,8 +6585,8 @@ static int check_stack_access_within_bounds( char tn_buf[48]; tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose(env, "invalid variable-offset%s stack R%d var_off=%s size=%d\n", - err_extra, regno, tn_buf, access_size); + verbose(env, "invalid variable-offset%s stack R%d var_off=%s off=%d size=%d\n", + err_extra, regno, tn_buf, off, access_size); } } return err; From 153de60e8bfb4501e1462a2f74cb787c137b996c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 4 Dec 2023 09:39:40 +0000 Subject: [PATCH 2387/7721] selftests/bpf: Fix spelling mistake "get_signaure_size" -> "get_signature_size" There is a spelling mistake in an ASSERT_GT message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231204093940.2611954-1-colin.i.king@gmail.com --- tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c index 6c90372b772d..ab0f02faa80c 100644 --- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -498,7 +498,7 @@ static void test_pkcs7_sig_fsverity(void) if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open")) goto out; ret = get_signature_size(sig_path); - if (!ASSERT_GT(ret, 0, "get_signaure_size")) + if (!ASSERT_GT(ret, 0, "get_signature_size")) goto out; skel->bss->sig_size = ret; skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring", From 4de77156a2acdec0014fa89fc1766a7410d726ff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Dec 2023 17:11:30 +0100 Subject: [PATCH 2388/7721] drm/i915/dsi: Use devm_gpiod_get() for all GPIOs soc_gpio_set_value() already uses devm_gpiod_get(), lets be consistent and use devm_gpiod_get() for all GPIOs. This allows removing the intel_dsi_vbt_gpio_cleanup() function, which only function was to put the GPIO-descriptors. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Acked-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231201161130.23976-1-hdegoede@redhat.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 17 ++--------------- drivers/gpu/drm/i915/display/intel_dsi_vbt.h | 1 - drivers/gpu/drm/i915/display/vlv_dsi.c | 10 +--------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 275d0218394c..a5d7fc8418c9 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -922,7 +922,7 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) gpiod_add_lookup_table(gpiod_lookup_table); if (want_panel_gpio) { - intel_dsi->gpio_panel = gpiod_get(dev->dev, "panel", flags); + intel_dsi->gpio_panel = devm_gpiod_get(dev->dev, "panel", flags); if (IS_ERR(intel_dsi->gpio_panel)) { drm_err(&dev_priv->drm, "Failed to own gpio for panel control\n"); @@ -932,7 +932,7 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) if (want_backlight_gpio) { intel_dsi->gpio_backlight = - gpiod_get(dev->dev, "backlight", flags); + devm_gpiod_get(dev->dev, "backlight", flags); if (IS_ERR(intel_dsi->gpio_backlight)) { drm_err(&dev_priv->drm, "Failed to own gpio for backlight control\n"); @@ -943,16 +943,3 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) if (gpiod_lookup_table) gpiod_remove_lookup_table(gpiod_lookup_table); } - -void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) -{ - if (intel_dsi->gpio_panel) { - gpiod_put(intel_dsi->gpio_panel); - intel_dsi->gpio_panel = NULL; - } - - if (intel_dsi->gpio_backlight) { - gpiod_put(intel_dsi->gpio_backlight); - intel_dsi->gpio_backlight = NULL; - } -} diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h index 468d873fab1a..3462fcc760e6 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h @@ -13,7 +13,6 @@ struct intel_dsi; bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id); void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on); -void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi); void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, enum mipi_seq seq_id); void intel_dsi_log_params(struct intel_dsi *intel_dsi); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 5bda97c96810..9b33b8a74d64 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1532,16 +1532,8 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) } } -static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) -{ - struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(encoder)); - - intel_dsi_vbt_gpio_cleanup(intel_dsi); - intel_encoder_destroy(encoder); -} - static const struct drm_encoder_funcs intel_dsi_funcs = { - .destroy = intel_dsi_encoder_destroy, + .destroy = intel_encoder_destroy, }; static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector, From d0ae9dc48e24f5f704abcbb2dca3e4651bf0ff59 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 4 Dec 2023 11:35:47 +0800 Subject: [PATCH 2389/7721] ASoC: SOF: Move sof_of_machine_select() to core.c from sof-of-dev.c Commit 014fdeb0d747 ("ASoC: SOF: Move sof_of_machine_select() to sof-of-dev.c from sof-audio.c") caused a circular dependency between the snd_sof and snd_sof_of modules: depmod: ERROR: Cycle detected: snd_sof -> snd_sof_of -> snd_sof depmod: ERROR: Found 2 modules in dependency cycles! Move the function back with sof_machine_select(). Fixes: 014fdeb0d747 ("ASoC: SOF: Move sof_of_machine_select() to sof-of-dev.c from sof-audio.c") Signed-off-by: Chen-Yu Tsai Acked-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20231204033549.2020289-1-wenst@chromium.org Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 22 ++++++++++++++++++++++ sound/soc/sof/sof-of-dev.c | 23 ----------------------- sound/soc/sof/sof-of-dev.h | 9 --------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a2afec8f5879..425b023b03b4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -144,6 +144,28 @@ void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state) } EXPORT_SYMBOL(sof_set_fw_state); +static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_sof_of_mach *mach = desc->of_machines; + + if (!mach) + return NULL; + + for (; mach->compatible; mach++) { + if (of_machine_is_compatible(mach->compatible)) { + sof_pdata->tplg_filename = mach->sof_tplg_filename; + if (mach->fw_filename) + sof_pdata->fw_filename = mach->fw_filename; + + return mach; + } + } + + return NULL; +} + /* SOF Driver enumeration */ static int sof_machine_check(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index fa92da5ee9b3..b9a499e92b9a 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -41,29 +41,6 @@ static void sof_of_probe_complete(struct device *dev) pm_runtime_enable(dev); } -struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *sof_pdata = sdev->pdata; - const struct sof_dev_desc *desc = sof_pdata->desc; - struct snd_sof_of_mach *mach = desc->of_machines; - - if (!mach) - return NULL; - - for (; mach->compatible; mach++) { - if (of_machine_is_compatible(mach->compatible)) { - sof_pdata->tplg_filename = mach->sof_tplg_filename; - if (mach->fw_filename) - sof_pdata->fw_filename = mach->fw_filename; - - return mach; - } - } - - return NULL; -} -EXPORT_SYMBOL(sof_of_machine_select); - int sof_of_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/sound/soc/sof/sof-of-dev.h b/sound/soc/sof/sof-of-dev.h index 547e358a37e3..b6cc70595f3b 100644 --- a/sound/soc/sof/sof-of-dev.h +++ b/sound/soc/sof/sof-of-dev.h @@ -16,15 +16,6 @@ struct snd_sof_of_mach { const char *sof_tplg_filename; }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_OF_DEV) -struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev); -#else -static inline struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) -{ - return NULL; -} -#endif - extern const struct dev_pm_ops sof_of_pm; int sof_of_probe(struct platform_device *pdev); From 9c8bec3b63255ca04e5dad87471a35790aec06dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 2 Dec 2023 13:39:43 +0100 Subject: [PATCH 2390/7721] ASoC: es83xx: add ACPI DSM helper module Most of the ES83xx codec configuration is exposed in the DSDT table and accessible via a _DSM method. Start adding basic definitions and helpers to dump the information. Reviewed-by: Mauro Carvalho Chehab Co-developed-by: David Yang Signed-off-by: David Yang Signed-off-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231202123946.54347-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es83xx-dsm-common.c | 89 ++++++ sound/soc/codecs/es83xx-dsm-common.h | 393 +++++++++++++++++++++++++++ 4 files changed, 488 insertions(+) create mode 100644 sound/soc/codecs/es83xx-dsm-common.c create mode 100644 sound/soc/codecs/es83xx-dsm-common.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3429419ca694..59f9742e9ff4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1076,6 +1076,10 @@ config SND_SOC_ES7134 config SND_SOC_ES7241 tristate "Everest Semi ES7241 CODEC" +config SND_SOC_ES83XX_DSM_COMMON + depends on ACPI + tristate + config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2078bb0d981e..f53baa2b9565 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -116,6 +116,7 @@ snd-soc-da9055-objs := da9055.o snd-soc-dmic-objs := dmic.o snd-soc-es7134-objs := es7134.o snd-soc-es7241-objs := es7241.o +snd-soc-es83xx-dsm-common-objs := es83xx-dsm-common.o snd-soc-es8316-objs := es8316.o snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o @@ -505,6 +506,7 @@ obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o +obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c new file mode 100644 index 000000000000..94fd7d54c53b --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (c) Intel Corporation, 2022 +// Copyright Everest Semiconductor Co.,Ltd + +#include +#include +#include "es83xx-dsm-common.h" + +/* UUID ("a9800c04-e016-343e-41f4-6bcce70f4332") */ +static const guid_t es83xx_dsm_guid = + GUID_INIT(0xa9800c04, 0xe016, 0x343e, + 0x41, 0xf4, 0x6b, 0xcc, 0xe7, 0x0f, 0x43, 0x32); + +#define ES83xx_DSM_REVID 1 + +int es83xx_dsm(struct device *dev, int arg, int *value) +{ + acpi_handle dhandle; + union acpi_object *obj; + int ret = 0; + + dhandle = ACPI_HANDLE(dev); + if (!dhandle) + return -ENOENT; + + obj = acpi_evaluate_dsm(dhandle, &es83xx_dsm_guid, ES83xx_DSM_REVID, + arg, NULL); + if (!obj) { + dev_err(dev, "%s: acpi_evaluate_dsm() failed\n", __func__); + ret = -EINVAL; + goto out; + } + + if (obj->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "%s: object is not ACPI_TYPE_INTEGER\n", __func__); + ret = -EINVAL; + goto err; + } + + *value = obj->integer.value; +err: + ACPI_FREE(obj); +out: + return ret; +} +EXPORT_SYMBOL_GPL(es83xx_dsm); + +int es83xx_dsm_dump(struct device *dev) +{ + int value; + int ret; + + ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_MAINMIC_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_HPMIC_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_SPK_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_SPK_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_HPDET_INV %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_PCM_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_PCM_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_MIC_DE_POP_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_MIC_DE_POP %#x\n", value); + + return 0; +} +EXPORT_SYMBOL_GPL(es83xx_dsm_dump); + +MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h new file mode 100644 index 000000000000..91c9a89e75e9 --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -0,0 +1,393 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Intel Corporation, 2022 + * Copyright Everest Semiconductor Co.,Ltd + */ + +/* Definitions extracted from ASL file provided at + * https://github.com/thesofproject/linux/files/9398723/ESSX8326.zip + */ + +#ifndef _ES83XX_DSM_COMMON_H +#define _ES83XX_DSM_COMMON_H + +/*************************************************** + * DSM arguments * + ***************************************************/ + +#define PLATFORM_MAINMIC_TYPE_ARG 0x00 +#define PLATFORM_HPMIC_TYPE_ARG 0x01 +#define PLATFORM_SPK_TYPE_ARG 0x02 +#define PLATFORM_HPDET_INV_ARG 0x03 +#define PLATFORM_PCM_TYPE_ARG 0x04 + +#define PLATFORM_MIC_DE_POP_ARG 0x06 +#define PLATFORM_CODEC_TYPE_ARG 0x0E +#define PLATFORM_BUS_SLOT_ARG 0x0F + +#define HP_CODEC_LINEIN_PGA_GAIN_ARG 0x10 +#define MAIN_CODEC_LINEIN_PGA_GAIN_ARG 0x20 + +#define HP_CODEC_D2SEPGA_GAIN_ARG 0x11 +#define MAIN_CODEC_D2SEPGA_GAIN_ARG 0x21 + +#define HP_CODEC_ADC_VOLUME_ARG 0x12 +#define MAIN_CODEC_ADC_VOLUME_ARG 0x22 + +#define HP_CODEC_ADC_ALC_ENABLE_ARG 0x13 +#define MAIN_CODEC_ADC_ALC_ENABLE_ARG 0x23 + +#define HP_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x14 +#define MAIN_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x24 + +#define HP_CODEC_ADC_ALC_MAXGAIN_ARG 0x15 +#define MAIN_CODEC_ADC_ALC_MAXGAIN_ARG 0x25 + +#define HP_CODEC_ADC_ALC_MINGAIN_ARG 0x16 +#define MAIN_CODEC_ADC_ALC_MINGAIN_ARG 0x26 + +#define HP_CODEC_ADC_ALC_HLDTIME_ARG 0x17 +#define MAIN_CODEC_ADC_ALC_HLDTIME_ARG 0x27 + +#define HP_CODEC_ADC_ALC_DCYTIME_ARG 0x18 +#define MAIN_CODEC_ADC_ALC_DCYTIME_ARG 0x28 + +#define HP_CODEC_ADC_ALC_ATKTIME_ARG 0x19 +#define MAIN_CODEC_ADC_ALC_ATKTIME_ARG 0x29 + +#define HP_CODEC_ADC_ALC_NGTYPE_ARG 0x1a +#define MAIN_CODEC_ADC_ALC_NGTYPE_ARG 0x2a + +#define HP_CODEC_ADC_ALC_NGTHLD_ARG 0x1b +#define MAIN_CODEC_ADC_ALC_NGTHLD_ARG 0x2b + +#define MAIN_CODEC_ADC_GUI_STEP_ARG 0x2c +#define MAIN_CODEC_ADC_GUI_GAIN_RANGE_ARG 0x2c + +#define HEADPHONE_DUMMY_REMOVE_ENABLE_ARG 0x2e + +#define HP_CODEC_DAC_HPMIX_HIGAIN_ARG 0x40 +#define SPK_CODEC_DAC_HPMIX_HIGAIN_ARG 0x50 + +#define HP_CODEC_DAC_HPMIX_VOLUME_ARG 0x41 +#define SPK_CODEC_DAC_HPMIX_VOLUME_ARG 0x51 + +#define HP_CODEC_DAC_HPOUT_VOLUME_ARG 0x42 +#define SPK_CODEC_DAC_HPOUT_VOLUME_ARG 0x52 + +#define HP_CODEC_LDAC_VOLUME_ARG 0x44 +#define HP_CODEC_RDAC_VOLUME_ARG 0x54 + +#define SPK_CODEC_LDAC_VOLUME_ARG 0x45 +#define SPK_CODEC_RDAC_VOLUME_ARG 0x55 + +#define HP_CODEC_DAC_AUTOMUTE_ARG 0x46 +#define SPK_CODEC_DAC_AUTOMUTE_ARG 0x56 + +#define HP_CODEC_DAC_MONO_ARG 0x4A +#define SPK_CODEC_DAC_MONO_ARG 0x5A + +#define HP_CTL_IO_LEVEL_ARG 0x4B +#define SPK_CTL_IO_LEVEL_ARG 0x5B + +#define CODEC_GPIO0_FUNC_ARG 0x80 +#define CODEC_GPIO1_FUNC_ARG 0x81 +#define CODEC_GPIO2_FUNC_ARG 0x82 +#define CODEC_GPIO3_FUNC_ARG 0x83 +#define CODEC_GPIO4_FUNC_ARG 0x84 + +#define PLATFORM_MCLK_LRCK_FREQ_ARG 0x85 + +/*************************************************** + * Values for arguments * + ***************************************************/ + +/* Main and HP Mic */ +#define PLATFORM_MIC_DMIC_HIGH_LEVEL 0xAA +#define PLATFORM_MIC_DMIC_LOW_LEVEL 0x55 +#define PLATFORM_MIC_AMIC_LIN1RIN1 0xBB +#define PLATFORM_MIC_AMIC_LIN2RIN2 0xCC + +/* Speaker */ +#define PLATFORM_SPK_NONE 0x00 +#define PLATFORM_SPK_MONO 0x01 +#define PLATFORM_SPK_STEREO 0x02 + +/* Jack Detection */ +#define PLATFORM_HPDET_NORMAL 0x00 +#define PLATFORM_HPDET_INVERTED 0x01 + +/* PCM type (Port number + protocol) */ +/* + * RETURNED VALUE = 0x00, PCM PORT0, I2S + * 0x01, PCM PORT0, LJ + * 0x02, PCM PORT0, RJ + * 0x03, PCM PORT0, DSP-A + * 0x04, PCM PORT0, DSP-B + * 0x10, PCM PORT1, I2S + * 0x11, PCM PORT1, LJ + * 0x12, PCM PORT1, RJ + * 0x13, PCM PORT1, DSP-A + * 0x14, PCM PORT1, DSP-B + * 0xFF, Use default + * + * This is not used in Linux (defined by topology) and in + * Windows it's always DSP-A + */ + +/* Depop */ +#define PLATFORM_MIC_DE_POP_OFF 0x00 +#define PLATFORM_MIC_DE_POP_ON 0x01 + +/* Codec type */ +#define PLATFORM_CODEC_8316 16 +#define PLATFORM_CODEC_8326 26 +#define PLATFORM_CODEC_8336 36 +#define PLATFORM_CODEC_8395 95 +#define PLATFORM_CODEC_8396 96 + +/* Bus slot (on the host) */ +/* BIT[3:0] FOR BUS NUMBER, BIT[7:4] FOR SLOT NUMBER + * BIT[3:0] 0 for I2S0, 1 for IS21, 2 for I2S2. + * + * On Intel platforms this refers to SSP0..2. This information + * is not really useful for Linux, the information is already + * inferred from NHLT but can be used to double-check NHLT + */ + +/* Volume - Gain */ +#define LINEIN_GAIN_0db 0x00 /* gain = 0db */ +#define LINEIN_GAIN_3db 0x01 /* gain = +3db */ +#define LINEIN_GAIN_6db 0x02 /* gain = +6db */ +#define LINEIN_GAIN_9db 0x03 /* gain = +9db */ +#define LINEIN_GAIN_12db 0x04 /* gain = +12db */ +#define LINEIN_GAIN_15db 0x05 /* gain = +15db */ +#define LINEIN_GAIN_18db 0x06 /* gain = +18db */ +#define LINEIN_GAIN_21db 0x07 /* gain = +21db */ +#define LINEIN_GAIN_24db 0x08 /* gain = +24db */ +#define LINEIN_GAIN_27db 0x09 /* gain = +27db */ +#define LINEIN_GAIN_30db 0x0a /* gain = +30db */ + +#define ADC_GUI_STEP_3db 0x03 /* gain = +3db */ +#define ADC_GUI_STEP_6db 0x06 /* gain = +6db */ +#define ADC_GUI_STEP_10db 0x0a /* gain = +10db */ + +#define D2SEPGA_GAIN_0db 0x00 /* gain = 0db */ +#define D2SEPGA_GAIN_15db 0x01 /* gain = +15db */ + +/* ADC volume: base = 0db, -0.5db/setp, 0xc0 <-> -96db */ + +#define ADC_ALC_DISABLE 0x00 +#define ADC_ALC_ENABLE 0x01 + +#define ADC_ALC_TARGET_LEVEL_m16_5db 0x00 /* gain = -16.5db */ +#define ADC_ALC_TARGET_LEVEL_m15db 0x01 /* gain = -15db */ +#define ADC_ALC_TARGET_LEVEL_m13_5db 0x02 /* gain = -13.5db */ +#define ADC_ALC_TARGET_LEVEL_m12db 0x03 /* gain = -12db */ +#define ADC_ALC_TARGET_LEVEL_m10_5db 0x04 /* gain = -10.5db */ +#define ADC_ALC_TARGET_LEVEL_m9db 0x05 /* gain = -9db */ +#define ADC_ALC_TARGET_LEVEL_m7_5db 0x06 /* gain = -7.5db */ +#define ADC_ALC_TARGET_LEVEL_m6db 0x07 /* gain = -6db */ +#define ADC_ALC_TARGET_LEVEL_m4_5db 0x08 /* gain = -4.5db */ +#define ADC_ALC_TARGET_LEVEL_m_3db 0x09 /* gain = -3db */ +#define ADC_ALC_TARGET_LEVEL_m1_5db 0x0a /* gain = -1.5db */ + +#define ADC_ALC_MAXGAIN_m6_5db 0x00 /* gain = -6.5db */ +#define ADC_ALC_MAXGAIN_m5db 0x01 /* gain = -5db */ +#define ADC_ALC_MAXGAIN_m3_5db 0x02 /* gain = -3.5db */ +#define ADC_ALC_MAXGAIN_m2db 0x03 /* gain = -2db */ +#define ADC_ALC_MAXGAIN_m0_5db 0x04 /* gain = -0.5db */ +#define ADC_ALC_MAXGAIN_1db 0x05 /* gain = +1db */ +#define ADC_ALC_MAXGAIN_2_5db 0x06 /* gain = +2.5db */ +#define ADC_ALC_MAXGAIN_4db 0x07 /* gain = +4db */ +#define ADC_ALC_MAXGAIN_5_5db 0x08 /* gain = +5.5db */ +#define ADC_ALC_MAXGAIN_7db 0x09 /* gain = +7db */ +#define ADC_ALC_MAXGAIN_8_5db 0x0a /* gain = +8.5db */ +#define ADC_ALC_MAXGAIN_10db 0x0b /* gain = +10db */ +#define ADC_ALC_MAXGAIN_11_5db 0x0c /* gain = +11.5db */ +#define ADC_ALC_MAXGAIN_13db 0x0d /* gain = +13db */ +#define ADC_ALC_MAXGAIN_14_5db 0x0e /* gain = +14.5db */ +#define ADC_ALC_MAXGAIN_16db 0x0f /* gain = +16db */ +#define ADC_ALC_MAXGAIN_17_5db 0x10 /* gain = +17.5db */ +#define ADC_ALC_MAXGAIN_19db 0x11 /* gain = +19db */ +#define ADC_ALC_MAXGAIN_20_5db 0x12 /* gain = +20.5db */ +#define ADC_ALC_MAXGAIN_22db 0x13 /* gain = +22db */ +#define ADC_ALC_MAXGAIN_23_5db 0x14 /* gain = +23.5db */ +#define ADC_ALC_MAXGAIN_25db 0x15 /* gain = +25db */ +#define ADC_ALC_MAXGAIN_26_5db 0x16 /* gain = +26.5db */ +#define ADC_ALC_MAXGAIN_28db 0x17 /* gain = +28db */ +#define ADC_ALC_MAXGAIN_29_5db 0x18 /* gain = +29.5db */ +#define ADC_ALC_MAXGAIN_31db 0x19 /* gain = +31db */ +#define ADC_ALC_MAXGAIN_32_5db 0x1a /* gain = +32.5db */ +#define ADC_ALC_MAXGAIN_34db 0x1b /* gain = +34db */ +#define ADC_ALC_MAXGAIN_35_5db 0x1c /* gain = +35.5db */ + +#define ADC_ALC_MINGAIN_m12db 0x00 /* gain = -12db */ +#define ADC_ALC_MINGAIN_m10_5db 0x01 /* gain = -10.5db */ +#define ADC_ALC_MINGAIN_m9db 0x02 /* gain = -9db */ +#define ADC_ALC_MINGAIN_m7_5db 0x03 /* gain = -7.5db */ +#define ADC_ALC_MINGAIN_m6db 0x04 /* gain = -6db */ +#define ADC_ALC_MINGAIN_m4_51db 0x05 /* gain = -4.51db */ +#define ADC_ALC_MINGAIN_m3db 0x06 /* gain = -3db */ +#define ADC_ALC_MINGAIN_m1_5db 0x07 /* gain = -1.5db */ +#define ADC_ALC_MINGAIN_0db 0x08 /* gain = 0db */ +#define ADC_ALC_MINGAIN_1_5db 0x09 /* gain = +1.5db */ +#define ADC_ALC_MINGAIN_3db 0x0a /* gain = +3db */ +#define ADC_ALC_MINGAIN_4_5db 0x0b /* gain = +4.5db */ +#define ADC_ALC_MINGAIN_6db 0x0c /* gain = +6db */ +#define ADC_ALC_MINGAIN_7_5db 0x0d /* gain = +7.5db */ +#define ADC_ALC_MINGAIN_9db 0x0e /* gain = +9db */ +#define ADC_ALC_MINGAIN_10_5db 0x0f /* gain = +10.5db */ +#define ADC_ALC_MINGAIN_12db 0x10 /* gain = +12db */ +#define ADC_ALC_MINGAIN_13_5db 0x11 /* gain = +13.5db */ +#define ADC_ALC_MINGAIN_15db 0x12 /* gain = +15db */ +#define ADC_ALC_MINGAIN_16_5db 0x13 /* gain = +16.5db */ +#define ADC_ALC_MINGAIN_18db 0x14 /* gain = +18db */ +#define ADC_ALC_MINGAIN_19_5db 0x15 /* gain = +19.5db */ +#define ADC_ALC_MINGAIN_21db 0x16 /* gain = +21db */ +#define ADC_ALC_MINGAIN_22_5db 0x17 /* gain = +22.5db */ +#define ADC_ALC_MINGAIN_24db 0x18 /* gain = +24db */ +#define ADC_ALC_MINGAIN_25_5db 0x19 /* gain = +25.5db */ +#define ADC_ALC_MINGAIN_27db 0x1a /* gain = +27db */ +#define ADC_ALC_MINGAIN_28_5db 0x1b /* gain = +28.5db */ +#define ADC_ALC_MINGAIN_30db 0x1c /* gain = +30db */ + +/* ADC volume: step 1dB */ + +/* ALC Hold, Decay, Attack */ +#define ADC_ALC_HLDTIME_0_US 0x00 +#define ADC_ALC_HLDTIME_0000266_US 0x01 //time = 2.67ms +#define ADC_ALC_HLDTIME_0000533_US 0x02 //time = 5.33ms +#define ADC_ALC_HLDTIME_0001066_US 0x03 //time = 10.66ms +#define ADC_ALC_HLDTIME_0002132_US 0x04 //time = 21.32ms +#define ADC_ALC_HLDTIME_0004264_US 0x05 //time = 42.64ms +#define ADC_ALC_HLDTIME_0008538_US 0x06 //time = 85.38ms +#define ADC_ALC_HLDTIME_0017076_US 0x07 //time = 170.76ms +#define ADC_ALC_HLDTIME_0034152_US 0x08 //time = 341.52ms +#define ADC_ALC_HLDTIME_0680000_US 0x09 //time = 0.68s +#define ADC_ALC_HLDTIME_1360000_US 0x0a //time = 1.36s + +#define ADC_ALC_DCYTIME_000410_US 0x00 //time = 410us +#define ADC_ALC_DCYTIME_000820_US 0x01 //time = 820us +#define ADC_ALC_DCYTIME_001640_US 0x02 //time = 1.64ms +#define ADC_ALC_DCYTIME_003280_US 0x03 //time = 3.28ms +#define ADC_ALC_DCYTIME_006560_US 0x04 //time = 6.56ms +#define ADC_ALC_DCYTIME_013120_US 0x05 //time = 13.12ms +#define ADC_ALC_DCYTIME_026240_US 0x06 //time = 26.24ms +#define ADC_ALC_DCYTIME_058480_US 0x07 //time = 52.48ms +#define ADC_ALC_DCYTIME_104960_US 0x08 //time = 104.96ms +#define ADC_ALC_DCYTIME_209920_US 0x09 //time = 209.92ms +#define ADC_ALC_DCYTIME_420000_US 0x0a //time = 420ms + +#define ADC_ALC_ATKTIME_000104_US 0x00 //time = 104us +#define ADC_ALC_ATKTIME_000208_US 0x01 //time = 208us +#define ADC_ALC_ATKTIME_000416_US 0x02 //time = 416ms +#define ADC_ALC_ATKTIME_003832_US 0x03 //time = 832ms +#define ADC_ALC_ATKTIME_001664_US 0x04 //time = 1.664ms +#define ADC_ALC_ATKTIME_003328_US 0x05 //time = 3.328ms +#define ADC_ALC_ATKTIME_006656_US 0x06 //time = 6.656ms +#define ADC_ALC_ATKTIME_013312_US 0x07 //time = 13.312ms +#define ADC_ALC_ATKTIME_026624_US 0x08 //time = 26.624ms +#define ADC_ALC_ATKTIME_053248_US 0x09 //time = 53.248ms +#define ADC_ALC_ATKTIME_106496_US 0x0a //time = 106.496ms + +/* ALC Noise Gate */ +#define ADC_ALC_NGTYPE_DISABLE 0x00 //noise gate disable +#define ADC_ALC_NGTYPE_ENABLE_HOLD 0x01 //noise gate enable, hold gain type +#define ADC_ALC_NGTYPE_ENABLE_MUTE 0x03 //noise gate enable, mute type + +#define ADC_ALC_NGTHLD_m76_5db 0x00 /* Threshold = -76.5db */ +#define ADC_ALC_NGTHLD_m75db 0x01 /* Threshold = -75db */ +#define ADC_ALC_NGTHLD_m73_5db 0x02 /* Threshold = -73.5db */ +#define ADC_ALC_NGTHLD_m72db 0x03 /* Threshold = -72db */ +#define ADC_ALC_NGTHLD_m70_5db 0x04 /* Threshold = -70.5db */ +#define ADC_ALC_NGTHLD_m69db 0x05 /* Threshold = -69db */ +#define ADC_ALC_NGTHLD_m67_5db 0x06 /* Threshold = -67.5db */ +#define ADC_ALC_NGTHLD_m66db 0x07 /* Threshold = -66db */ +#define ADC_ALC_NGTHLD_m64_5db 0x08 /* Threshold = -64.5db */ +#define ADC_ALC_NGTHLD_m63db 0x09 /* Threshold = -63db */ +#define ADC_ALC_NGTHLD_m61_5db 0x0a /* Threshold = -61.5db */ +#define ADC_ALC_NGTHLD_m60db 0x0b /* Threshold = -60db */ +#define ADC_ALC_NGTHLD_m58_5db 0x0c /* Threshold = -58.5db */ +#define ADC_ALC_NGTHLD_m57db 0x0d /* Threshold = -57db */ +#define ADC_ALC_NGTHLD_m55_5db 0x0e /* Threshold = -55.5db */ +#define ADC_ALC_NGTHLD_m54db 0x0f /* Threshold = -54db */ +#define ADC_ALC_NGTHLD_m52_5db 0x10 /* Threshold = -52.5db */ +#define ADC_ALC_NGTHLD_m51db 0x11 /* Threshold = -51db */ +#define ADC_ALC_NGTHLD_m49_5db 0x12 /* Threshold = -49.5db */ +#define ADC_ALC_NGTHLD_m48db 0x13 /* Threshold = -48db */ +#define ADC_ALC_NGTHLD_m46_5db 0x14 /* Threshold = -46.5db */ +#define ADC_ALC_NGTHLD_m45db 0x15 /* Threshold = -45db */ +#define ADC_ALC_NGTHLD_m43_5db 0x16 /* Threshold = -43.5db */ +#define ADC_ALC_NGTHLD_m42db 0x17 /* Threshold = -42db */ +#define ADC_ALC_NGTHLD_m40_5db 0x18 /* Threshold = -40.5db */ +#define ADC_ALC_NGTHLD_m39db 0x19 /* Threshold = -39db */ +#define ADC_ALC_NGTHLD_m37_5db 0x1a /* Threshold = -37.5db */ +#define ADC_ALC_NGTHLD_m36db 0x1b /* Threshold = -36db */ +#define ADC_ALC_NGTHLD_m34_5db 0x1c /* Threshold = -34.5db */ +#define ADC_ALC_NGTHLD_m33db 0x1d /* Threshold = -33db */ +#define ADC_ALC_NGTHLD_m31_5db 0x1e /* Threshold = -31.5db */ +#define ADC_ALC_NGTHLD_m30db 0x1f /* Threshold = -30db */ + +/* Headphone dummy - Windows Specific flag, not needed for Linux */ + +/* HPMIX HIGAIN and VOLUME */ +#define DAC_HPMIX_HIGAIN_0db 0x00 /* gain = 0db */ +#define DAC_HPMIX_HIGAIN_m6db 0x88 /* gain = -6db */ + +#define DAC_HPMIX_VOLUME_m12db 0x00 /* volume = -12db */ +#define DAC_HPMIX_VOLUME_m10_5db 0x11 /* volume = -10.5db */ +#define DAC_HPMIX_VOLUME_m9db 0x22 /* volume = -9db */ +#define DAC_HPMIX_VOLUME_m7_5db 0x33 /* volume = -7.5db */ +#define DAC_HPMIX_VOLUME_m6db 0x44 /* volume = -6db */ +#define DAC_HPMIX_VOLUME_m4_5db 0x88 /* volume = -4.5db */ +#define DAC_HPMIX_VOLUME_m3db 0x99 /* volume = -3db */ +#define DAC_HPMIX_VOLUME_m1_5db 0xaa /* volume = -1.5db */ +#define DAC_HPMIX_VOLUME_0db 0xbb /* volume = 0db */ + +/* HPOUT VOLUME */ +#define DAC_HPOUT_VOLUME_0db 0x00 /* volume = 0db */ +#define DAC_HPOUT_VOLUME_m12db 0x11 /* volume = -12db */ +#define DAC_HPOUT_VOLUME_m24db 0x22 /* volume = -24db */ +#define DAC_HPOUT_VOLUME_m48db 0x33 /* volume = -48db */ + +/* LDAC/RDAC volume = 0db, -0.5db/setp, 0xc0 <-> -96db */ + +/* Automute */ +#define DAC_AUTOMUTE_NONE 0x00 /* no automute */ +#define DAC_AUTOMUTE_DIGITAL 0x01 /* digital mute */ +#define DAC_AUTOMUTE_ANALOG 0x02 /* analog mute */ + +/* Mono - Windows specific, on Linux the information comes from DAI/topology */ +#define HEADPHONE_MONO 0x01 /* on channel */ +#define HEADPHONE_STEREO 0x00 /* stereo */ + +/* Speaker and headphone GPIO control */ +#define GPIO_CTL_IO_LEVEL_LOW 0x00 /* low level enable */ +#define GPIO_CTL_IO_LEVEL_HIGH 0x01 /* high level enable */ + +/* GPIO */ +/* FIXME: for ES8396, no need to use */ + +/* Platform clocks */ +/* + * BCLK AND MCLK FREQ + * BIT[7:4] MCLK FREQ + * 0 - 19.2MHz + * 1 - 24MHz + * 2 - 12.288MHz + * F - Default for 19.2MHz + * + * BIT[3:0] BCLK FREQ + * 0 - 4.8MHz + * 1 - 2.4MHz + * 2 - 2.304MHz + * 3 - 3.072MHz + * 4 - 4.096MHz + * F - Default for 4.8MHz + */ + +int es83xx_dsm(struct device *dev, int arg, int *value); +int es83xx_dsm_dump(struct device *dev); + +#endif From b71e1d3789946a20e0e34349f4a874604ac65c3e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 2 Dec 2023 13:39:44 +0100 Subject: [PATCH 2391/7721] ASoC: Intel: bytcht_es8316: Dump basic _DSM information Instead of adding DMI quirks for each new tablet model which uses the ESS8316 codec, the plan is to switch to querying the same ACPI Device-Specific-Method (DSM) as Windows uses to determine things like speaker and mic routing. Call the new es83xx_dsm_dump() helper which logs various basic settings which can be queried through the ACPI DSM method on the codec ACPI device, this is intended to help with developing a DSM based solution to replace most DMI quirks. Signed-off-by: Pierre-Louis Bossart [hdegoede@redhat.com: improve commit message] Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231202123946.54347-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/bytcht_es8316.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 99ebe48216ea..8fd5e7f83054 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -229,6 +229,7 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH depends on GPIOLIB || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_ES8316 + select SND_SOC_ES83XX_DSM_COMMON help This adds support for ASoC machine driver for Intel(R) Baytrail & Cherrytrail platforms with ES8316 audio codec. diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8a0b0e864fbb..e6ab1ee6ab29 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -27,6 +27,7 @@ #include #include #include +#include "../../codecs/es83xx-dsm-common.h" #include "../atom/sst-atom-controls.h" #include "../common/soc-intel-quirks.h" @@ -520,6 +521,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; } + es83xx_dsm_dump(priv->codec_dev); + /* Check for BYTCR or other platform and setup quirks */ dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { From e8acf91a4013202934313f3c2968e6962daaffff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 13:39:45 +0100 Subject: [PATCH 2392/7721] ASoC: Intel: bytcht_es8316: Add is_bytcr helper variable Add a is_bytcr helper variable to probe(). This is a preparation patch for determining the quirks through querying the ACPI Device-Specific-Method (DSM) on the codec-device. Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231202123946.54347-4-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e6ab1ee6ab29..0d6574678317 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -471,10 +471,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; const struct dmi_system_id *dmi_id; struct fwnode_handle *fwnode; + bool sof_parent, is_bytcr; const char *platform_name; struct acpi_device *adev; struct device *codec_dev; - bool sof_parent; unsigned int cnt = 0; int dai_index = 0; int i; @@ -524,11 +524,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) es83xx_dsm_dump(priv->codec_dev); /* Check for BYTCR or other platform and setup quirks */ + is_bytcr = soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0; dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { quirk = (unsigned long)dmi_id->driver_data; - } else if (soc_intel_is_byt() && - mach->mach_params.acpi_ipc_irq_index == 0) { + } else if (is_bytcr) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | BYT_CHT_ES8316_MONO_SPEAKER; From 7650862f4e72d2533356ec001b8ea8d5839aced0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 13:39:46 +0100 Subject: [PATCH 2393/7721] ASoC: Intel: bytcht_es8316: Determine quirks/routing with codec-dev ACPI DSM Add support for querying the same ACPI Device-Specific-Method (DSM) as Windows uses to determine things like speaker and mic routing. This avoids the need to add DMI quirks for each new ESS8316 tablet model. This has been tested on the following devices: 1. Chuwi Hi12 CHT with stereo speakers and IN2-mic-map, this avoids the need to add a DMI quirk for this model. 2. Nanote UMPC-01 CHT with stereo speakers and IN1-mic-map, the existing DMI quirk is still necessary because of a bug in the DSM return values for the speakers (it returns mono). 3. Onda V80 plus CHT with mono speaker and IN1-mic-map, DSM set quirks match the previously used defaults. 4. GP-electronic T701 BYT with mono speaker and IN2-mic-map, DSM set quirks match the previously used defaults. Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231202123946.54347-5-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 0d6574678317..1564a88a885e 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -462,6 +462,66 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { {} }; +static int byt_cht_es8316_get_quirks_from_dsm(struct byt_cht_es8316_private *priv, + bool is_bytcr) +{ + int ret, val1, val2, dsm_quirk = 0; + + if (is_bytcr) + dsm_quirk |= BYT_CHT_ES8316_SSP0; + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_MAINMIC_TYPE_ARG, &val1); + if (ret < 0) + return ret; + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPMIC_TYPE_ARG, &val2); + if (ret < 0) + return ret; + + if (val1 == PLATFORM_MIC_AMIC_LIN1RIN1 && val2 == PLATFORM_MIC_AMIC_LIN2RIN2) { + dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; + } else if (val1 == PLATFORM_MIC_AMIC_LIN2RIN2 && val2 == PLATFORM_MIC_AMIC_LIN1RIN1) { + dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN2_MAP; + } else { + dev_warn(priv->codec_dev, "Unknown mic settings mainmic 0x%02x hpmic 0x%02x\n", + val1, val2); + return -EINVAL; + } + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_SPK_TYPE_ARG, &val1); + if (ret < 0) + return ret; + + switch (val1) { + case PLATFORM_SPK_MONO: + dsm_quirk |= BYT_CHT_ES8316_MONO_SPEAKER; + break; + case PLATFORM_SPK_STEREO: + break; + default: + dev_warn(priv->codec_dev, "Unknown speaker setting 0x%02x\n", val1); + return -EINVAL; + } + + ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPDET_INV_ARG, &val1); + if (ret < 0) + return ret; + + switch (val1) { + case PLATFORM_HPDET_NORMAL: + break; + case PLATFORM_HPDET_INVERTED: + dsm_quirk |= BYT_CHT_ES8316_JD_INVERTED; + break; + default: + dev_warn(priv->codec_dev, "Unknown hpdet-inv setting 0x%02x\n", val1); + return -EINVAL; + } + + quirk = dsm_quirk; + return 0; +} + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -528,6 +588,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { quirk = (unsigned long)dmi_id->driver_data; + } else if (!byt_cht_es8316_get_quirks_from_dsm(priv, is_bytcr)) { + dev_info(dev, "Using ACPI DSM info for quirks\n"); } else if (is_bytcr) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | From 21a1989963b4c2d8530af9be41c4cc2f7d3b2ee8 Mon Sep 17 00:00:00 2001 From: Aradhya Bhatia Date: Mon, 30 Oct 2023 20:58:34 +0530 Subject: [PATCH 2394/7721] arm64: defconfig: Enable Toshiba TC358767 bridge Siemens' SIMATIC IOT2050 platform[0], based on Texas Instruments' AM65x SoC[1], uses Toshiba TC358767[2] to convert DPI video to DisplayPort (DP) video output. The original DPI signals are generated by AM65x's Display SubSystem (DSS). Toshiba TC358767 is also capable of other video format conversions, viz, DPI to (e)DP, DSI to (e)DP, and DSI to DPI. Enable the video bridge Toshiba TC358767. [0]: https://www.siemens.com/global/en/products/automation/pc-based/iot-gateways/simatic-iot2050.html [1]: https://www.ti.com/product/AM6548 [2]: https://toshiba.semicon-storage.com/info/datasheet_en_20230731.pdf?did=36657 Signed-off-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231030152834.18450-1-a-bhatia1@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index b60aa1f89343..71e7a059111b 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -860,6 +860,7 @@ CONFIG_DRM_SAMSUNG_DSIM=m CONFIG_DRM_SII902X=m CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_THINE_THC63LVD1024=m +CONFIG_DRM_TOSHIBA_TC358767=m CONFIG_DRM_TOSHIBA_TC358768=m CONFIG_DRM_TI_TFP410=m CONFIG_DRM_TI_SN65DSI83=m From 9fba6a55d2ff449e1d796fbda16520715158b1ee Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Tue, 28 Nov 2023 14:15:37 +0530 Subject: [PATCH 2395/7721] arm64: defconfig: Enable TI_ICSSG_PRUETH The Programmable Real-time Unit and Industrial Communication Subsystem Gigabit (PRU_ICSSG) is a low-latency microcontroller subsystem in the TI K3 SoCs such as AM654x, AM64x. This subsystem is provided for the use cases like implementation of custom peripheral interfaces, offloading of tasks from the other processor cores of the SoC, etc. Currently AM654x-EVM uses ICSSG driver. Signed-off-by: MD Danish Anwar Reviewed-by: Ravi Gunasekaran Link: https://lore.kernel.org/r/20231128084537.3946895-1-danishanwar@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 71e7a059111b..329031271148 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -368,6 +368,7 @@ CONFIG_SNI_NETSEC=y CONFIG_STMMAC_ETH=m CONFIG_DWMAC_TEGRA=m CONFIG_TI_K3_AM65_CPSW_NUSS=y +CONFIG_TI_ICSSG_PRUETH=m CONFIG_QCOM_IPA=m CONFIG_MESON_GXL_PHY=m CONFIG_AQUANTIA_PHY=y From 8121e93102b0e09ff1d9589659a823b2271acf62 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:09:09 -0600 Subject: [PATCH 2396/7721] arm64: dts: ti: k3-am65: Add chipid node to wkup_conf bus Like in other K3 SoCs the chipid register is inside the wakeup configuration space. Move the chipid node under a new bus to better represent this topology and match other similar SoCs. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117140910.8747-4-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi index fd2b998ebddc..f037b36243ce 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi @@ -34,9 +34,16 @@ k3_reset: reset-controller { }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x43000014 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { From 82277ed7db29296a2907eab91934c26c405db604 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:09:06 -0600 Subject: [PATCH 2397/7721] arm64: dts: ti: k3-j7200: Add chipid node to wkup_conf bus Like in other K3 SoCs the chipid register is inside the wakeup configuration space. Move the chipid node under a new bus to better represent this topology and match other similar SoCs. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117140910.8747-1-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi index 3fc588b848c6..672cb2acc1be 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi @@ -178,9 +178,16 @@ phy_gmii_sel: phy@4040 { }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */ From 27e5b7330fe31d0aae196f26cf251254f2b923bb Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:09:10 -0600 Subject: [PATCH 2398/7721] arm64: dts: ti: k3-j721e: Add chipid node to wkup_conf bus Like in other K3 SoCs the chipid register is inside the wakeup configuration space. Move the chipid node under a new bus to better represent this topology and match other similar SoCs. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117140910.8747-5-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi index f7ab7719fc07..8f259efe3af9 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi @@ -48,9 +48,16 @@ phy_gmii_sel: phy@4040 { }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x0 0x43000014 0x0 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { From 1026355c21ebe9f7af3bb0a9422bc572c9f4ac91 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:09:08 -0600 Subject: [PATCH 2399/7721] arm64: dts: ti: k3-j721s2: Add chipid node to wkup_conf bus Like in other K3 SoCs the chipid register is inside the wakeup configuration space. Move the chipid node under a new bus to better represent this topology and match other similar SoCs. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117140910.8747-3-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi index 7254f3bd3634..d9e2cab8a8c5 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi @@ -34,9 +34,16 @@ k3_reset: reset-controller { }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { From 3dc5bd24181af7eb90ad764c3b303f697ebf5e87 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:09:07 -0600 Subject: [PATCH 2400/7721] arm64: dts: ti: k3-j784s4: Add chipid node to wkup_conf bus Like in other K3 SoCs the chipid register is inside the wakeup configuration space. Move the chipid node under a new bus to better represent this topology and match other similar SoCs. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117140910.8747-2-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi index adb5ea6b9732..119f4e2cc0d1 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi @@ -38,10 +38,18 @@ k3_reset: reset-controller { }; }; - chipid@43000014 { + wkup_conf: bus@43000000 { bootph-all; - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + bootph-all; + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { From 1a4402e14fa8fa166cd4afd435b903c7867eb7d5 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 08:14:33 -0600 Subject: [PATCH 2401/7721] arm64: dts: ti: k3-am65: Add full compatible to dss-oldi-io-ctrl node This matches the binding for this register region which fixes a couple DTS check warnings. While here trim the leading 0s from the "reg" definition. Signed-off-by: Andrew Davis Reviewed-by: Aradhya Bhatia Link: https://lore.kernel.org/r/20231117141433.9461-1-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 29048d6577cf..72e7c455bf72 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -498,8 +498,8 @@ serdes_mux: mux-controller { }; dss_oldi_io_ctrl: dss-oldi-io-ctrl@41e0 { - compatible = "syscon"; - reg = <0x000041e0 0x14>; + compatible = "ti,am654-dss-oldi-io-ctrl", "syscon"; + reg = <0x41e0 0x14>; }; ehrpwm_tbclk: clock-controller@4140 { From 006d93519db2e0eacbaeac20cf9d55a4d842a006 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 10:33:38 -0600 Subject: [PATCH 2402/7721] arm64: dts: ti: k3-am65: Enable SDHCI nodes at the board level SDHCI nodes defined in the top-level AM65 SoC dtsi files are incomplete and will not be functional unless they are extended. As the attached SD/eMMC is only known about at the board integration level, these nodes should only be enabled when provided with this information. Disable the SDHCI nodes in the dtsi files and only enable the ones that are actually pinned out on a given board. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117163339.89952-1-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 1 + arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 2 ++ arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi | 5 ----- arch/arm64/boot/dts/ti/k3-am654-base-board.dts | 2 ++ .../arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index ab1dffa5c1c6..6cbdf370cfcc 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -1267,6 +1267,7 @@ &mcu_cpsw { }; &sdhci1 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; ti,driver-strength-ohm = <50>; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 72e7c455bf72..cc59fc648b56 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -449,6 +449,7 @@ sdhci0: mmc@4f80000 { ti,otap-del-sel-hs400 = <0x0>; ti,trm-icp = <0x8>; dma-coherent; + status = "disabled"; }; sdhci1: mmc@4fa0000 { @@ -471,6 +472,7 @@ sdhci1: mmc@4fa0000 { ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; + status = "disabled"; }; scm_conf: scm-conf@100000 { diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi index 5ab434c02ab6..e4d7cba7c62f 100644 --- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi @@ -29,11 +29,6 @@ cpu-map { /delete-node/ l2-cache1; }; -/* eMMC */ -&sdhci0 { - status = "disabled"; -}; - &main_pmx0 { main_uart0_pins_default: main-uart0-default-pins { pinctrl-single,pins = < diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts index 1637ec5ab5ed..822c288d2797 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts @@ -449,6 +449,7 @@ flash@0 { }; &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; @@ -463,6 +464,7 @@ &sdhci0 { * disable sdhci1 */ &sdhci1 { + status = "okay"; vmmc-supply = <&vdd_mmc1_sd>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi index be55494b1f3f..a847209c3df5 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi @@ -43,6 +43,7 @@ AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ /* eMMC */ &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; From 3b6345e3fcf4c93a79f396121cd0e6f98f04da13 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Fri, 17 Nov 2023 10:33:39 -0600 Subject: [PATCH 2403/7721] arm64: dts: ti: k3-am64: Enable SDHCI nodes at the board level SDHCI nodes defined in the top-level AM64 SoC dtsi files are incomplete and will not be functional unless they are extended. As the attached SD/eMMC is only known about at the board integration level, these nodes should only be enabled when provided with this information. Disable the SDHCI nodes in the dtsi files and only enable the ones that are actually pinned out on a given board. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231117163339.89952-2-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am64-main.dtsi | 2 ++ arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi | 1 + arch/arm64/boot/dts/ti/k3-am642-evm.dts | 6 ++++-- arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts | 1 + arch/arm64/boot/dts/ti/k3-am642-sk.dts | 4 +++- arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts | 1 - arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi | 1 + 7 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index 745143410146..c7be378492e2 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -623,6 +623,7 @@ sdhci0: mmc@fa10000 { ti,otap-del-sel-mmc-hs = <0x0>; ti,otap-del-sel-ddr52 = <0x6>; ti,otap-del-sel-hs200 = <0x7>; + status = "disabled"; }; sdhci1: mmc@fa00000 { @@ -641,6 +642,7 @@ sdhci1: mmc@fa00000 { ti,otap-del-sel-sdr104 = <0x6>; ti,otap-del-sel-ddr50 = <0x9>; ti,clkbuf-sel = <0x7>; + status = "disabled"; }; cpsw3g: ethernet@8000000 { diff --git a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi index f87f09d83c95..b8f844f667af 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi @@ -211,6 +211,7 @@ flash@0 { }; &sdhci0 { + status = "okay"; bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts index 45f64b6f8281..8c5651d2cf5d 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -491,17 +491,19 @@ eeprom@0 { }; }; +/* eMMC */ &sdhci0 { - /* emmc */ + status = "okay"; bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; disable-wp; }; +/* SD/MMC */ &sdhci1 { - /* SD/MMC */ bootph-all; + status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; bus-width = <4>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts index 9175e96842d8..53b64e55413f 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts @@ -264,6 +264,7 @@ &main_uart1 { }; &sdhci1 { + status = "okay"; vmmc-supply = <&vcc_3v3_mmc>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts index d2d3b5017ac4..1dddd6fc1a0d 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -443,6 +443,7 @@ &mcu_gpio_intr { }; &sdhci0 { + status = "okay"; vmmc-supply = <&wlan_en>; bus-width = <4>; non-removable; @@ -462,9 +463,10 @@ wlcore: wlcore@2 { }; }; +/* SD/MMC */ &sdhci1 { - /* SD/MMC */ bootph-all; + status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; bus-width = <4>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts index d95d80076a42..55102d35cecc 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts @@ -425,7 +425,6 @@ &sdhci1 { ti,driver-strength-ohm = <50>; ti,fails-without-test-cd; /* Enabled by overlay */ - status = "disabled"; }; &tscadc0 { diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi index d82d4a98306a..6c785eff7d2f 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi @@ -219,6 +219,7 @@ partitions { }; &sdhci0 { + status = "okay"; non-removable; disable-wp; no-sdio; From ba78573abba7eb20190b2bb55e5cb5b55a8854fc Mon Sep 17 00:00:00 2001 From: Ronald Wahl Date: Mon, 27 Nov 2023 12:26:57 +0100 Subject: [PATCH 2404/7721] arm64: dts: ti: k3-am62-main: Add gpio-ranges properties On the AM62 platform we have no single 1:1 relation regarding index of gpio and pin controller. Actually there are some linear ranges with small holes inbetween. These ranges can be represented with the gpio-ranges device tree property. They have been extracted manually from the AM62x datasheet (Table 6-1. Pin Attributes). Signed-off-by: Ronald Wahl Link: https://lore.kernel.org/r/20231127112657.2692103-1-rwahl@gmx.de Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62-main.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi index e5c64c86d1d5..0643cd15eeec 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi @@ -502,6 +502,9 @@ main_gpio_intr: interrupt-controller@a00000 { main_gpio0: gpio@600000 { compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00600000 0x0 0x100>; + gpio-ranges = <&main_pmx0 0 0 32>, + <&main_pmx0 32 33 38>, + <&main_pmx0 70 72 22>; gpio-controller; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; @@ -520,6 +523,10 @@ main_gpio1: gpio@601000 { compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00601000 0x0 0x100>; gpio-controller; + gpio-ranges = <&main_pmx0 0 94 41>, + <&main_pmx0 41 136 6>, + <&main_pmx0 47 143 3>, + <&main_pmx0 50 149 2>; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; interrupts = <180>, <181>, <182>, From 26e0124683c000c2a197204e0fdc68e553298bff Mon Sep 17 00:00:00 2001 From: Parth Pancholi Date: Tue, 21 Nov 2023 17:04:36 +0100 Subject: [PATCH 2405/7721] arm64: dts: ti: k3-am625-verdin: Enable Verdin UART2 Enable UART2 for AM62 based SOM's Verdin carrier boards Dahlia, Development and Yavia. Earlier Verdin UART2 was reserved by R5 DM firmware which can be now configured using boardcfg during U-boot compilation. In a default config, no one writes to this UART. Signed-off-by: Parth Pancholi Reviewed-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231121160436.1032364-1-parth105105@gmail.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi | 3 +-- arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi | 3 +-- arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi index 013357d17d48..bf6d27e70bc4 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi @@ -214,6 +214,5 @@ &verdin_gpio_keys { /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi index 6701cb8974bb..680071688dcb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi @@ -235,6 +235,5 @@ &verdin_gpio_keys { /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi index c685df7deaee..997dfafd27eb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi @@ -207,6 +207,5 @@ &verdin_gpio_keys { /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; From e57ba268254bda25a3ddca8b7971d6ad8277e2d8 Mon Sep 17 00:00:00 2001 From: Aradhya Bhatia Date: Thu, 9 Nov 2023 00:46:52 +0530 Subject: [PATCH 2406/7721] arm64: dts: ti: k3-am62a7-sk: Add interrupt support for IO Expander The Hot Plug Detect (HPD) signal for the HDMI display travels from the on-board HDMI connector, through the IO Expander 1, and finally to the main_gpio1 GPIO 23, of the SoC. Add interrupt information for the IO Expander 1 (exp1) along with the relevant pinmux. Signed-off-by: Aradhya Bhatia Reviewed-by: Jai Luthra Link: https://lore.kernel.org/r/20231108191652.1118155-1-a-bhatia1@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts index 8f64ac2c7568..560dad02ef62 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts @@ -274,6 +274,12 @@ AM62AX_IOPAD(0x08c, PIN_OUTPUT, 2) /* (K19) GPMC0_WEn.MCASP1_AXR0 */ AM62AX_IOPAD(0x084, PIN_INPUT, 2) /* (L18) GPMC0_ADVn_ALE.MCASP1_AXR2 */ >; }; + + main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x01d4, PIN_INPUT, 7) /* (C15) UART0_RTSn.GPIO1_23 */ + >; + }; }; &mcu_pmx0 { @@ -407,6 +413,12 @@ exp1: gpio@22 { reg = <0x22>; gpio-controller; #gpio-cells = <2>; + interrupt-parent = <&main_gpio1>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio1_ioexp_intr_pins_default>; gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST", "BT_EN_SOC", "MMC1_SD_EN", From 649e121f9301a4d275b68323a9807b762618e516 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 27 Nov 2023 13:36:02 -0600 Subject: [PATCH 2407/7721] arm64: dts: ti: k3-am625-beagleplay: Use UART name in pinmux name The main_uart0 may not always be the console, but it will always be the UART0 in MAIN domain. Name the pinmux node to match. This makes it consistent with all other TI SoC based boards. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20231127193602.151499-1-afd@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts index 9a6bd0a3c94f..eadbdd9ffe37 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts @@ -443,7 +443,7 @@ AM62X_IOPAD(0x01a8, PIN_INPUT, 7) /* (D20) MCASP0_AFSX.GPIO1_12 */ >; }; - console_pins_default: console-default-pins { + main_uart0_pins_default: main-uart0-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01c8, PIN_INPUT, 0) /* (D14) UART0_RXD */ @@ -877,7 +877,7 @@ wlcore: wlcore@2 { &main_uart0 { bootph-all; pinctrl-names = "default"; - pinctrl-0 = <&console_pins_default>; + pinctrl-0 = <&main_uart0_pins_default>; status = "okay"; }; From 7bb7d31d9e454fc0b13cb0df44c2b4d953b4a152 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Fri, 1 Dec 2023 20:57:32 +0100 Subject: [PATCH 2408/7721] arm64: defconfig: Increase SERIAL_8250_NR_UARTS Increase CONFIG_SERIAL_8250_NR_UARTS from 4 to 8, the current legacy value is not adequate for embedded systems that use SoCs where it's common to have a large number of serial ports. No need to change CONFIG_SERIAL_8250_RUNTIME_UARTS, see commit 9d86719f8769 ("serial: 8250: Allow using ports higher than SERIAL_8250_RUNTIME_UARTS"). The need to increase this value was noticed while working with Toradex Verdin AM62, this board has 4 serial UART instances available to the user plus an internal one that is connected to a Bluetooth module. Without this change the fifth UART connected to the BT module is not instantiated and BT is not working. Instead of increasing the number to the bare minimum (5) that would be required to solve this specific issue, we increase this to 8 which seems a more reasonable number to have in the defconfig and should cover more valid use cases. With this change the kernel image size increases by ~3.2kB. bloat-o-meter summary: add/remove: 1/1 grow/shrink: 7/0 up/down: 3220/-8 (3212) Cc: Tony Lindgren Reviewed-by: Tony Lindgren Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231201195732.4931-1-francesco@dolcini.it Signed-off-by: Nishanth Menon --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 329031271148..755c9de16fbb 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -449,6 +449,7 @@ CONFIG_SERIO_AMBAKMI=y CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_BCM2835AUX=y From 1c0a80f160965c88f16e73ff69015db2f044c486 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:48 +0200 Subject: [PATCH 2409/7721] Revert "drm/atomic: Loosen FB atomic checks" This reverts commit f1e75da5364e780905d9cd6043f9c74cdcf84073. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic.c | 21 +++++++------- drivers/gpu/drm/drm_atomic_helper.c | 43 +++++++++++++---------------- include/drm/drm_atomic_helper.h | 4 +-- include/drm/drm_plane.h | 29 ------------------- 4 files changed, 31 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index aed0a694c74c..c6f2b86c48ae 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -674,16 +674,17 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, { struct drm_plane *plane = new_plane_state->plane; struct drm_crtc *crtc = new_plane_state->crtc; + const struct drm_framebuffer *fb = new_plane_state->fb; int ret; - /* either *both* CRTC and pixel source must be set, or neither */ - if (crtc && !drm_plane_has_visible_data(new_plane_state)) { - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no visible data\n", + /* either *both* CRTC and FB must be set, or neither */ + if (crtc && !fb) { + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no FB\n", plane->base.id, plane->name); return -EINVAL; - } else if (drm_plane_has_visible_data(new_plane_state) && !crtc) { - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] Source %d has visible data but no CRTC\n", - plane->base.id, plane->name, new_plane_state->pixel_source); + } else if (fb && !crtc) { + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] FB set but no CRTC\n", + plane->base.id, plane->name); return -EINVAL; } @@ -714,11 +715,9 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, } - if (new_plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && new_plane_state->fb) { - ret = drm_atomic_plane_check_fb(new_plane_state); - if (ret) - return ret; - } + ret = drm_atomic_plane_check_fb(new_plane_state); + if (ret) + return ret; if (plane_switching_crtc(old_plane_state, new_plane_state)) { drm_dbg_atomic(plane->dev, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index dc048988e3f3..c3f677130def 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -861,6 +861,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, bool can_position, bool can_update_disabled) { + struct drm_framebuffer *fb = plane_state->fb; struct drm_rect *src = &plane_state->src; struct drm_rect *dst = &plane_state->dst; unsigned int rotation = plane_state->rotation; @@ -872,7 +873,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, *src = drm_plane_state_src(plane_state); *dst = drm_plane_state_dest(plane_state); - if (!drm_plane_has_visible_data(plane_state)) { + if (!fb) { plane_state->visible = false; return 0; } @@ -889,32 +890,26 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, return -EINVAL; } - /* Check that selected pixel source is valid */ - if (plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && plane_state->fb) { - struct drm_framebuffer *fb = plane_state->fb; - drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); + drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); - /* Check scaling */ - hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); - vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); - - if (hscale < 0 || vscale < 0) { - drm_dbg_kms(plane_state->plane->dev, - "Invalid scaling of plane\n"); - drm_rect_debug_print("src: ", &plane_state->src, true); - drm_rect_debug_print("dst: ", &plane_state->dst, false); - return -ERANGE; - } - - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); - - plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); - drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); - } else if (drm_plane_solid_fill_enabled(plane_state)) { - plane_state->visible = true; + /* Check scaling */ + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); + if (hscale < 0 || vscale < 0) { + drm_dbg_kms(plane_state->plane->dev, + "Invalid scaling of plane\n"); + drm_rect_debug_print("src: ", &plane_state->src, true); + drm_rect_debug_print("dst: ", &plane_state->dst, false); + return -ERANGE; } + if (crtc_state->enable) + drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); + + plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); + + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); + if (!plane_state->visible) /* * Plane isn't visible; some drivers can handle this diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 6d97f38ac1f6..536a0b0091c3 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -256,8 +256,8 @@ drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state, * Anything else should be considered a bug in the atomic core, so we * gently warn about it. */ - WARN_ON((new_plane_state->crtc == NULL && drm_plane_has_visible_data(new_plane_state)) || - (new_plane_state->crtc != NULL && !drm_plane_has_visible_data(new_plane_state))); + WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) || + (new_plane_state->crtc != NULL && new_plane_state->fb == NULL)); return old_plane_state->crtc && !new_plane_state->crtc; } diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 3b187f3f5466..d14e2f1db234 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -1016,35 +1016,6 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) -/** - * drm_plane_solid_fill_enabled - Check if solid fill is enabled on plane - * @state: plane state - * - * Returns: - * Whether the plane has been assigned a solid_fill_blob - */ -static inline bool drm_plane_solid_fill_enabled(struct drm_plane_state *state) -{ - if (!state) - return false; - return state->pixel_source == DRM_PLANE_PIXEL_SOURCE_SOLID_FILL && state->solid_fill_blob; -} - -static inline bool drm_plane_has_visible_data(const struct drm_plane_state *state) -{ - switch (state->pixel_source) { - case DRM_PLANE_PIXEL_SOURCE_NONE: - return false; - case DRM_PLANE_PIXEL_SOURCE_SOLID_FILL: - return state->solid_fill_blob != NULL; - case DRM_PLANE_PIXEL_SOURCE_FB: - default: - WARN_ON(state->pixel_source != DRM_PLANE_PIXEL_SOURCE_FB); - } - - return state->fb != NULL; -} - bool drm_any_plane_has_format(struct drm_device *dev, u32 format, u64 modifier); From b881ba8faa5c7689eb1cb487ad891c46dbbed0e8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:49 +0200 Subject: [PATCH 2410/7721] Revert "drm/atomic: Move framebuffer checks to helper" This reverts commit 4ba6b7a646321e740c7f2d80c90505019c4e8fce. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic.c | 130 +++++++++++++++-------------------- 1 file changed, 57 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c6f2b86c48ae..1339785fbe80 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -589,76 +589,6 @@ plane_switching_crtc(const struct drm_plane_state *old_plane_state, return true; } -static int drm_atomic_plane_check_fb(const struct drm_plane_state *state) -{ - struct drm_plane *plane = state->plane; - const struct drm_framebuffer *fb = state->fb; - struct drm_mode_rect *clips; - - uint32_t num_clips; - unsigned int fb_width, fb_height; - int ret; - - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->format->format, - fb->modifier); - - if (ret) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n", - plane->base.id, plane->name, - &fb->format->format, fb->modifier); - return ret; - } - - fb_width = fb->width << 16; - fb_height = fb->height << 16; - - /* Make sure source coordinates are inside the fb. */ - if (state->src_w > fb_width || - state->src_x > fb_width - state->src_w || - state->src_h > fb_height || - state->src_y > fb_height - state->src_h) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", - plane->base.id, plane->name, - state->src_w >> 16, - ((state->src_w & 0xffff) * 15625) >> 10, - state->src_h >> 16, - ((state->src_h & 0xffff) * 15625) >> 10, - state->src_x >> 16, - ((state->src_x & 0xffff) * 15625) >> 10, - state->src_y >> 16, - ((state->src_y & 0xffff) * 15625) >> 10, - fb->width, fb->height); - return -ENOSPC; - } - - clips = __drm_plane_get_damage_clips(state); - num_clips = drm_plane_get_damage_clips_count(state); - - /* Make sure damage clips are valid and inside the fb. */ - while (num_clips > 0) { - if (clips->x1 >= clips->x2 || - clips->y1 >= clips->y2 || - clips->x1 < 0 || - clips->y1 < 0 || - clips->x2 > fb_width || - clips->y2 > fb_height) { - drm_dbg_atomic(plane->dev, - "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", - plane->base.id, plane->name, clips->x1, - clips->y1, clips->x2, clips->y2); - return -EINVAL; - } - clips++; - num_clips--; - } - - return 0; -} - /** * drm_atomic_plane_check - check plane state * @old_plane_state: old plane state to check @@ -675,6 +605,9 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, struct drm_plane *plane = new_plane_state->plane; struct drm_crtc *crtc = new_plane_state->crtc; const struct drm_framebuffer *fb = new_plane_state->fb; + unsigned int fb_width, fb_height; + struct drm_mode_rect *clips; + uint32_t num_clips; int ret; /* either *both* CRTC and FB must be set, or neither */ @@ -701,6 +634,17 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, return -EINVAL; } + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); + if (ret) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n", + plane->base.id, plane->name, + &fb->format->format, fb->modifier); + return ret; + } + /* Give drivers some help against integer overflows */ if (new_plane_state->crtc_w > INT_MAX || new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || @@ -714,10 +658,50 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, return -ERANGE; } + fb_width = fb->width << 16; + fb_height = fb->height << 16; - ret = drm_atomic_plane_check_fb(new_plane_state); - if (ret) - return ret; + /* Make sure source coordinates are inside the fb. */ + if (new_plane_state->src_w > fb_width || + new_plane_state->src_x > fb_width - new_plane_state->src_w || + new_plane_state->src_h > fb_height || + new_plane_state->src_y > fb_height - new_plane_state->src_h) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", + plane->base.id, plane->name, + new_plane_state->src_w >> 16, + ((new_plane_state->src_w & 0xffff) * 15625) >> 10, + new_plane_state->src_h >> 16, + ((new_plane_state->src_h & 0xffff) * 15625) >> 10, + new_plane_state->src_x >> 16, + ((new_plane_state->src_x & 0xffff) * 15625) >> 10, + new_plane_state->src_y >> 16, + ((new_plane_state->src_y & 0xffff) * 15625) >> 10, + fb->width, fb->height); + return -ENOSPC; + } + + clips = __drm_plane_get_damage_clips(new_plane_state); + num_clips = drm_plane_get_damage_clips_count(new_plane_state); + + /* Make sure damage clips are valid and inside the fb. */ + while (num_clips > 0) { + if (clips->x1 >= clips->x2 || + clips->y1 >= clips->y2 || + clips->x1 < 0 || + clips->y1 < 0 || + clips->x2 > fb_width || + clips->y2 > fb_height) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", + plane->base.id, plane->name, clips->x1, + clips->y1, clips->x2, clips->y2); + return -EINVAL; + } + clips++; + num_clips--; + } if (plane_switching_crtc(old_plane_state, new_plane_state)) { drm_dbg_atomic(plane->dev, From a513f095b941e9e96196f04f11f253d763310c08 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:50 +0200 Subject: [PATCH 2411/7721] Revert "drm/atomic: Add solid fill data to plane state dump" This reverts commit e86413f5442ee094e66b3e75f2d3419ed0df9520. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic.c | 4 ---- drivers/gpu/drm/drm_plane.c | 8 -------- include/drm/drm_plane.h | 3 --- 3 files changed, 15 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1339785fbe80..02aa7df832cc 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -726,10 +726,6 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); - drm_printf(p, "\tsolid_fill=%u\n", - state->solid_fill_blob ? state->solid_fill_blob->base.id : 0); - if (state->solid_fill_blob) - drm_plane_solid_fill_print_info(p, 2, state); drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); drm_printf(p, "\trotation=%x\n", state->rotation); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index c65c72701dd2..c8dbe5ae60cc 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1641,14 +1641,6 @@ __drm_plane_get_damage_clips(const struct drm_plane_state *state) state->fb_damage_clips->data : NULL); } -void drm_plane_solid_fill_print_info(struct drm_printer *p, unsigned int indent, - const struct drm_plane_state *state) -{ - drm_printf_indent(p, indent, "r=0x%08x\n", state->solid_fill.r); - drm_printf_indent(p, indent, "g=0x%08x\n", state->solid_fill.g); - drm_printf_indent(p, indent, "b=0x%08x\n", state->solid_fill.b); -} - /** * drm_plane_get_damage_clips - Returns damage clips. * @state: Plane state. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index d14e2f1db234..4b7af4381bbe 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -1025,9 +1025,6 @@ drm_plane_get_damage_clips_count(const struct drm_plane_state *state); struct drm_mode_rect * drm_plane_get_damage_clips(const struct drm_plane_state *state); -void drm_plane_solid_fill_print_info(struct drm_printer *p, unsigned int indent, - const struct drm_plane_state *state); - int drm_plane_create_scaling_filter_property(struct drm_plane *plane, unsigned int supported_filters); From fe28421d4fedb90cadcef4932be0e8364f79283d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:51 +0200 Subject: [PATCH 2412/7721] Revert "drm/atomic: Add pixel source to plane state dump" This reverts commit 8283ac7871a959848e09fc6593b8c12b8febfee6. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-5-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic.c | 1 - drivers/gpu/drm/drm_blend.c | 1 - drivers/gpu/drm/drm_crtc_internal.h | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 02aa7df832cc..f1a503aafe5a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -722,7 +722,6 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); - drm_printf(p, "\tpixel-source=%s\n", drm_get_pixel_source_name(state->pixel_source)); drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 9c1608f7c1df..37b31b7e5ce5 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -647,7 +647,6 @@ static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, { DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, "SOLID_FILL" }, }; -DRM_ENUM_NAME_FN(drm_get_pixel_source_name, drm_pixel_source_enum_list); /** * drm_plane_create_pixel_source_property - create a new pixel source property diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 4114675c0728..a514d5207e41 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -269,7 +269,6 @@ int drm_plane_check_pixel_format(struct drm_plane *plane, u32 format, u64 modifier); struct drm_mode_rect * __drm_plane_get_damage_clips(const struct drm_plane_state *state); -const char *drm_get_pixel_source_name(int val); /* drm_bridge.c */ void drm_bridge_detach(struct drm_bridge *bridge); From 5fb1ad3f5725c5c4d1a0c24ba4f82f239dc6878d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:52 +0200 Subject: [PATCH 2413/7721] Revert "drm: Add solid fill pixel source" This reverts commit 4b64167042927531f4cfaf035b8f88c2f7a05f06. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-6-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_blend.c | 10 +--------- include/drm/drm_plane.h | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 37b31b7e5ce5..665c5d9b056f 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -204,9 +204,6 @@ * "FB": * Framebuffer source set by the "FB_ID" property. * - * "SOLID_FILL": - * Solid fill color source set by the "solid_fill" property. - * * solid_fill: * solid_fill is set up with drm_plane_create_solid_fill_property(). It * contains pixel data that drivers can use to fill a plane. @@ -645,7 +642,6 @@ EXPORT_SYMBOL(drm_plane_create_blend_mode_property); static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { { DRM_PLANE_PIXEL_SOURCE_NONE, "NONE" }, { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, - { DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, "SOLID_FILL" }, }; /** @@ -670,9 +666,6 @@ static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { * "FB": * Framebuffer pixel source * - * "SOLID_FILL": - * Solid fill color pixel source - * * Returns: * Zero on success, negative errno on failure. */ @@ -682,8 +675,7 @@ int drm_plane_create_pixel_source_property(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct drm_property *prop; static const unsigned int valid_source_mask = BIT(DRM_PLANE_PIXEL_SOURCE_FB) | - BIT(DRM_PLANE_PIXEL_SOURCE_NONE) | - BIT(DRM_PLANE_PIXEL_SOURCE_SOLID_FILL); + BIT(DRM_PLANE_PIXEL_SOURCE_NONE); int i; /* FB is supported by default */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 4b7af4381bbe..5bac644d4cc3 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -43,7 +43,6 @@ enum drm_scaling_filter { enum drm_plane_pixel_source { DRM_PLANE_PIXEL_SOURCE_NONE, DRM_PLANE_PIXEL_SOURCE_FB, - DRM_PLANE_PIXEL_SOURCE_SOLID_FILL, DRM_PLANE_PIXEL_SOURCE_MAX }; From e5fba1ada1c1d676438138d815acd8f427a1eaf0 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:53 +0200 Subject: [PATCH 2414/7721] Revert "drm: Introduce solid fill DRM plane property" This reverts commit 85863a4e16e77079ee14865905ddc3ef9483a640. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-7-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic_state_helper.c | 9 ------ drivers/gpu/drm/drm_atomic_uapi.c | 26 ---------------- drivers/gpu/drm/drm_blend.c | 30 ------------------- include/drm/drm_blend.h | 1 - include/drm/drm_plane.h | 36 ----------------------- include/uapi/drm/drm_mode.h | 24 --------------- 6 files changed, 126 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index f6c76cea8be4..311b04edf742 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -254,11 +254,6 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; plane_state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; - if (plane_state->solid_fill_blob) { - drm_property_blob_put(plane_state->solid_fill_blob); - plane_state->solid_fill_blob = NULL; - } - if (plane->color_encoding_property) { if (!drm_object_property_get_default_value(&plane->base, plane->color_encoding_property, @@ -355,9 +350,6 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, if (state->fb) drm_framebuffer_get(state->fb); - if (state->solid_fill_blob) - drm_property_blob_get(state->solid_fill_blob); - state->fence = NULL; state->commit = NULL; state->fb_damage_clips = NULL; @@ -407,7 +399,6 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) drm_crtc_commit_put(state->commit); drm_property_blob_put(state->fb_damage_clips); - drm_property_blob_put(state->solid_fill_blob); } EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index d7ae8e2c0265..bd7140531948 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -316,20 +316,6 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, } EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); -static void drm_atomic_set_solid_fill_prop(struct drm_plane_state *state) -{ - struct drm_mode_solid_fill *user_info; - - if (!state->solid_fill_blob) - return; - - user_info = (struct drm_mode_solid_fill *)state->solid_fill_blob->data; - - state->solid_fill.r = user_info->r; - state->solid_fill.g = user_info->g; - state->solid_fill.b = user_info->b; -} - static void set_out_fence_for_crtc(struct drm_atomic_state *state, struct drm_crtc *crtc, s32 __user *fence_ptr) { @@ -578,15 +564,6 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->src_h = val; } else if (property == plane->pixel_source_property) { state->pixel_source = val; - } else if (property == plane->solid_fill_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, - &state->solid_fill_blob, - val, sizeof(struct drm_mode_solid_fill), - -1, &replaced); - if (ret) - return ret; - - drm_atomic_set_solid_fill_prop(state); } else if (property == plane->alpha_property) { state->alpha = val; } else if (property == plane->blend_mode_property) { @@ -677,9 +654,6 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->src_h; } else if (property == plane->pixel_source_property) { *val = state->pixel_source; - } else if (property == plane->solid_fill_property) { - *val = state->solid_fill_blob ? - state->solid_fill_blob->base.id : 0; } else if (property == plane->alpha_property) { *val = state->alpha; } else if (property == plane->blend_mode_property) { diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 665c5d9b056f..fce734cdb85b 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -204,10 +204,6 @@ * "FB": * Framebuffer source set by the "FB_ID" property. * - * solid_fill: - * solid_fill is set up with drm_plane_create_solid_fill_property(). It - * contains pixel data that drivers can use to fill a plane. - * * Note that all the property extensions described here apply either to the * plane or the CRTC (e.g. for the background color, which currently is not * exposed and assumed to be black). @@ -713,29 +709,3 @@ int drm_plane_create_pixel_source_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_pixel_source_property); - -/** - * drm_plane_create_solid_fill_property - create a new solid_fill property - * @plane: drm plane - * - * This creates a new property blob that holds pixel data for solid fill planes. - * The property is exposed to userspace as a property blob called "solid_fill". - * - * For information on what the blob contains, see `drm_mode_solid_fill`. - */ -int drm_plane_create_solid_fill_property(struct drm_plane *plane) -{ - struct drm_property *prop; - - prop = drm_property_create(plane->dev, - DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, - "solid_fill", 0); - if (!prop) - return -ENOMEM; - - drm_object_attach_property(&plane->base, prop, 0); - plane->solid_fill_property = prop; - - return 0; -} -EXPORT_SYMBOL(drm_plane_create_solid_fill_property); diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index e7158fbee389..122bbfbaae33 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -60,5 +60,4 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); int drm_plane_create_pixel_source_property(struct drm_plane *plane, unsigned long extra_sources); -int drm_plane_create_solid_fill_property(struct drm_plane *plane); #endif diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 5bac644d4cc3..bc0176ba25be 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -46,18 +46,6 @@ enum drm_plane_pixel_source { DRM_PLANE_PIXEL_SOURCE_MAX }; -/** - * struct solid_fill_property - RGB values for solid fill plane - * - * TODO: Add solid fill source and corresponding pixel source - * that supports RGBA color - */ -struct drm_solid_fill { - uint32_t r; - uint32_t g; - uint32_t b; -}; - /** * struct drm_plane_state - mutable plane state * @@ -146,23 +134,6 @@ struct drm_plane_state { */ enum drm_plane_pixel_source pixel_source; - /** - * @solid_fill_blob: - * - * Blob containing relevant information for a solid fill plane - * including RGB color values. See - * drm_plane_create_solid_fill_property() for more details. - */ - struct drm_property_blob *solid_fill_blob; - - /** - * @solid_fill: - * - * Pixel data for solid fill planes. See - * drm_plane_create_solid_fill_property() for more details. - */ - struct drm_solid_fill solid_fill; - /** * @alpha: * Opacity of the plane with 0 as completely transparent and 0xffff as @@ -763,13 +734,6 @@ struct drm_plane { */ struct drm_property *pixel_source_property; - /** - * @solid_fill_property: - * Optional solid_fill property for this plane. See - * drm_plane_create_solid_fill_property(). - */ - struct drm_property *solid_fill_property; - /** * @alpha_property: * Optional alpha property for this plane. See diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index cbd943a8c88b..95630f170110 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -259,30 +259,6 @@ struct drm_mode_modeinfo { char name[DRM_DISPLAY_MODE_LEN]; }; -/** - * struct drm_mode_solid_fill - User info for solid fill planes - * - * This is the userspace API solid fill information structure. - * - * Userspace can enable solid fill planes by assigning the plane "solid_fill" - * property to a blob containing a single drm_mode_solid_fill struct populated with an RGB323232 - * color and setting the pixel source to "SOLID_FILL". - * - * For information on the plane property, see drm_plane_create_solid_fill_property() - * - * @r: Red color value of single pixel - * @g: Green color value of single pixel - * @b: Blue color value of single pixel - * @pad: padding, must be zero - */ -struct drm_mode_solid_fill { - __u32 r; - __u32 g; - __u32 b; - __u32 pad; -}; - - struct drm_mode_card_res { __u64 fb_id_ptr; __u64 crtc_id_ptr; From 90422201f8f2b4e26ab7bd43b92786a11c1ffebf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 4 Dec 2023 15:13:54 +0200 Subject: [PATCH 2415/7721] Revert "drm: Introduce pixel_source DRM plane property" This reverts commit e50e5fed41c7eed2db4119645bf3480ec43fec11. Although the Solid Fill planes patchset got all reviews and acknowledgements, it doesn't fulfill requirements for the new uABI. It has neither corresponding open-source userspace implementation nor the IGT tests coverage. Reverting this patchset until userspace obligations are fulfilled. Acked-by: Simon Ser Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231204131455.19023-8-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic_state_helper.c | 1 - drivers/gpu/drm/drm_atomic_uapi.c | 4 - drivers/gpu/drm/drm_blend.c | 94 ----------------------- drivers/gpu/drm/drm_plane.c | 19 +---- include/drm/drm_blend.h | 2 - include/drm/drm_plane.h | 21 ----- 6 files changed, 4 insertions(+), 137 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 311b04edf742..54975de44a0e 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -252,7 +252,6 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE; plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; - plane_state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; if (plane->color_encoding_property) { if (!drm_object_property_get_default_value(&plane->base, diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index bd7140531948..aee4a65d4959 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -562,8 +562,6 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->src_w = val; } else if (property == config->prop_src_h) { state->src_h = val; - } else if (property == plane->pixel_source_property) { - state->pixel_source = val; } else if (property == plane->alpha_property) { state->alpha = val; } else if (property == plane->blend_mode_property) { @@ -652,8 +650,6 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->src_w; } else if (property == config->prop_src_h) { *val = state->src_h; - } else if (property == plane->pixel_source_property) { - *val = state->pixel_source; } else if (property == plane->alpha_property) { *val = state->alpha; } else if (property == plane->blend_mode_property) { diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index fce734cdb85b..6e74de833466 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -185,25 +185,6 @@ * plane does not expose the "alpha" property, then this is * assumed to be 1.0 * - * pixel_source: - * pixel_source is set up with drm_plane_create_pixel_source_property(). - * It is used to toggle the active source of pixel data for the plane. - * The plane will only display data from the set pixel_source -- any - * data from other sources will be ignored. - * - * For non-framebuffer sources, if pixel_source is set to a non-framebuffer - * and non-NONE source, and the corresponding source property is NULL, then - * the atomic commit should return an error. - * - * Possible values: - * - * "NONE": - * No active pixel source. - * Committing with a NONE pixel source will disable the plane. - * - * "FB": - * Framebuffer source set by the "FB_ID" property. - * * Note that all the property extensions described here apply either to the * plane or the CRTC (e.g. for the background color, which currently is not * exposed and assumed to be black). @@ -634,78 +615,3 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_blend_mode_property); - -static const struct drm_prop_enum_list drm_pixel_source_enum_list[] = { - { DRM_PLANE_PIXEL_SOURCE_NONE, "NONE" }, - { DRM_PLANE_PIXEL_SOURCE_FB, "FB" }, -}; - -/** - * drm_plane_create_pixel_source_property - create a new pixel source property - * @plane: DRM plane - * @extra_sources: Bitmask of additional supported pixel_sources for the driver. - * DRM_PLANE_PIXEL_SOURCE_FB and DRM_PLANE_PIXEL_SOURCE_NONE will - * always be enabled as supported sources. - * - * This creates a new property describing the current source of pixel data for the - * plane. The pixel_source will be initialized as DRM_PLANE_PIXEL_SOURCE_FB by default. - * - * Drivers can set a custom default source by overriding the pixel_source value in - * drm_plane_funcs.reset() - * - * The property is exposed to userspace as an enumeration property called - * "pixel_source" and has the following enumeration values: - * - * "NONE": - * No active pixel source - * - * "FB": - * Framebuffer pixel source - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_plane_create_pixel_source_property(struct drm_plane *plane, - unsigned long extra_sources) -{ - struct drm_device *dev = plane->dev; - struct drm_property *prop; - static const unsigned int valid_source_mask = BIT(DRM_PLANE_PIXEL_SOURCE_FB) | - BIT(DRM_PLANE_PIXEL_SOURCE_NONE); - int i; - - /* FB is supported by default */ - unsigned long supported_sources = extra_sources | - BIT(DRM_PLANE_PIXEL_SOURCE_FB) | - BIT(DRM_PLANE_PIXEL_SOURCE_NONE); - - if (WARN_ON(supported_sources & ~valid_source_mask)) - return -EINVAL; - - prop = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_ATOMIC, "pixel_source", - hweight32(supported_sources)); - - if (!prop) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(drm_pixel_source_enum_list); i++) { - int ret; - - if (!test_bit(drm_pixel_source_enum_list[i].type, &supported_sources)) - continue; - - ret = drm_property_add_enum(prop, drm_pixel_source_enum_list[i].type, - drm_pixel_source_enum_list[i].name); - if (ret) { - drm_property_destroy(dev, prop); - - return ret; - } - } - - drm_object_attach_property(&plane->base, prop, DRM_PLANE_PIXEL_SOURCE_FB); - plane->pixel_source_property = prop; - - return 0; -} -EXPORT_SYMBOL(drm_plane_create_pixel_source_property); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index c8dbe5ae60cc..9e8e4c60983d 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -953,14 +953,6 @@ bool drm_any_plane_has_format(struct drm_device *dev, } EXPORT_SYMBOL(drm_any_plane_has_format); -static bool drm_plane_needs_disable(struct drm_plane_state *state, struct drm_framebuffer *fb) -{ - if (state->pixel_source == DRM_PLANE_PIXEL_SOURCE_NONE) - return true; - - return state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && fb == NULL; -} - /* * __setplane_internal - setplane handler for internal callers * @@ -983,8 +975,8 @@ static int __setplane_internal(struct drm_plane *plane, WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); - /* No visible data means shut it down */ - if (drm_plane_needs_disable(plane->state, fb)) { + /* No fb means shut it down */ + if (!fb) { plane->old_fb = plane->fb; ret = plane->funcs->disable_plane(plane, ctx); if (!ret) { @@ -1035,8 +1027,8 @@ static int __setplane_atomic(struct drm_plane *plane, WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev)); - /* No visible data means shut it down */ - if (drm_plane_needs_disable(plane->state, fb)) + /* No fb means shut it down */ + if (!fb) return plane->funcs->disable_plane(plane, ctx); /* @@ -1109,9 +1101,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, return -ENOENT; } - if (plane->state) - plane->state->pixel_source = DRM_PLANE_PIXEL_SOURCE_FB; - if (plane_req->fb_id) { fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id); if (!fb) { diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 122bbfbaae33..88bdfec3bd88 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -58,6 +58,4 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); -int drm_plane_create_pixel_source_property(struct drm_plane *plane, - unsigned long extra_sources); #endif diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index bc0176ba25be..c6565a6f9324 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -40,12 +40,6 @@ enum drm_scaling_filter { DRM_SCALING_FILTER_NEAREST_NEIGHBOR, }; -enum drm_plane_pixel_source { - DRM_PLANE_PIXEL_SOURCE_NONE, - DRM_PLANE_PIXEL_SOURCE_FB, - DRM_PLANE_PIXEL_SOURCE_MAX -}; - /** * struct drm_plane_state - mutable plane state * @@ -126,14 +120,6 @@ struct drm_plane_state { /** @hotspot_y: y offset to mouse cursor hotspot */ int32_t hotspot_x, hotspot_y; - /** - * @pixel_source: - * - * Source of pixel information for the plane. See - * drm_plane_create_pixel_source_property() for more details. - */ - enum drm_plane_pixel_source pixel_source; - /** * @alpha: * Opacity of the plane with 0 as completely transparent and 0xffff as @@ -727,13 +713,6 @@ struct drm_plane { */ struct drm_plane_state *state; - /* - * @pixel_source_property: - * Optional pixel_source property for this plane. See - * drm_plane_create_pixel_source_property(). - */ - struct drm_property *pixel_source_property; - /** * @alpha_property: * Optional alpha property for this plane. See From e17999750649c4bd4ba945419b406d1d1a3e92e2 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 4 Dec 2023 13:56:14 +0000 Subject: [PATCH 2416/7721] ASoC: Intel: soc-acpi-intel-tgl-match: add cs42l43 and cs35l56 support This is a test configuration for UpExtreme with Cirrus Logic CS35L56-EIGHT-C board. The codec layout is configured as: - Link3: CS42L43 Jack - Link0: 2x CS35L56 Speaker (amps 1 and 2) - Link1: 2x CS35L56 Speaker (amps 7 and 8) Signed-off-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20231204135614.2169624-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-tgl-match.c | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 5804926c8b56..e5f721ba5ed4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -41,6 +41,20 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { { .num = 0, @@ -400,6 +414,64 @@ static const struct snd_soc_acpi_link_adr tgl_712_only[] = { {} }; +static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = { + { + .adr = 0x00033001FA424301ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_0_adr[] = { + { + .adr = 0x00003301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00003201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { + { + .adr = 0x00013701FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP8" + }, + { + .adr = 0x00013601FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP7" + } +}; + +static const struct snd_soc_acpi_link_adr tgl_cs42l43_cs35l56[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs42l43_3_adr), + .adr_d = cs42l43_3_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs35l56_0_adr), + .adr_d = cs35l56_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_adr), + .adr_d = cs35l56_1_adr, + }, + {} +}; + static const struct snd_soc_acpi_codecs tgl_max98373_amp = { .num_codecs = 1, .codecs = {"MX98373"} @@ -494,6 +566,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg", }, + { + .link_mask = 0xB, + .links = tgl_cs42l43_cs35l56, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-tgl-cs42l43-l3-cs35l56-l01.tplg", + }, { .link_mask = 0xF, /* 4 active links required */ .links = tgl_3_in_1_default, From 801207c18834e289960c515bc41d243aa623763b Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Mon, 4 Dec 2023 09:13:14 -0800 Subject: [PATCH 2417/7721] drm/msm/dp: add a missing unlock in dp_hpd_plug_handle() When pm_runtime_resume_and_get() fails, unlock before returning. Fixes: 5814b8bf086a ("drm/msm/dp: incorporate pm_runtime framework into DP driver") Signed-off-by: Harshit Mogalapalli Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570395/ Link: https://lore.kernel.org/r/20231204171317.192427-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 3a360c87e2dc..20c5cf7986b2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -564,6 +564,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) ret = pm_runtime_resume_and_get(&pdev->dev); if (ret) { DRM_ERROR("failed to pm_runtime_resume\n"); + mutex_unlock(&dp->event_mutex); return ret; } From 528ee84f0fe08788b2e72aad7bc8a13dd2a169ca Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 4 Dec 2023 15:41:56 -0600 Subject: [PATCH 2418/7721] ASoC: Intel: sof_nau8825: board id cleanup for adl boards Many board configs are duplicated since codec and amplifier type are removed from board quirk. Introduce "adl_nau8825_def" board to reduce the number of adl board configs. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214200.203100-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 28 +------------------ .../intel/common/soc-acpi-intel-adl-match.c | 8 +++--- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 15ea6732ff94..eb3813400593 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -353,33 +353,7 @@ static const struct platform_device_id board_ids[] = { SOF_NAU8825_NUM_HDMIDEV(4)), }, { - .name = "adl_max98373_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - }, - { - /* The limitation of length of char array, shorten the name */ - .name = "adl_mx98360a_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - - }, - { - .name = "adl_rt1015p_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - }, - { - .name = "adl_nau8318_8825", + .name = "adl_nau8825_def", .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | SOF_NAU8825_SSP_AMP(1) | SOF_NAU8825_NUM_HDMIDEV(4) | diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 6e712ad954c8..d3d913458c60 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -528,14 +528,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { }, { .id = "10508825", - .drv_name = "adl_max98373_8825", + .drv_name = "adl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_max98373_amp, .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg", }, { .id = "10508825", - .drv_name = "adl_mx98360a_8825", + .drv_name = "adl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_max98360a_amp, .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg", @@ -549,14 +549,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { }, { .id = "10508825", - .drv_name = "adl_rt1015p_8825", + .drv_name = "adl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_rt1015p_amp, .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg", }, { .id = "10508825", - .drv_name = "adl_nau8318_8825", + .drv_name = "adl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_nau8318_amp, .sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg", From 996727aad856e55f6e65fdc6093281e51f0534da Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 4 Dec 2023 15:41:57 -0600 Subject: [PATCH 2419/7721] ASoC: Intel: sof_nau8825: board id cleanup for rpl boards Many board configs are duplicated since codec and amplifier type are removed from board quirk. Introduce "rpl_nau8825_def" board to reduce the number of rpl board configs. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214200.203100-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 18 +----------------- .../intel/common/soc-acpi-intel-rpl-match.c | 6 +++--- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index eb3813400593..719c2fbaf515 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -361,23 +361,7 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_BT_OFFLOAD_PRESENT), }, { - .name = "rpl_max98373_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - }, - { - .name = "rpl_mx98360a_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - }, - { - .name = "rpl_nau8318_8825", + .name = "rpl_nau8825_def", .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | SOF_NAU8825_SSP_AMP(1) | SOF_NAU8825_NUM_HDMIDEV(4) | diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 5b6f57e3a583..c0a643f4725a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -402,21 +402,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { }, { .id = "10508825", - .drv_name = "rpl_max98373_8825", + .drv_name = "rpl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_max98373_amp, .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", }, { .id = "10508825", - .drv_name = "rpl_mx98360a_8825", + .drv_name = "rpl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_max98360a_amp, .sof_tplg_filename = "sof-rpl-max98360a-nau8825.tplg", }, { .id = "10508825", - .drv_name = "rpl_nau8318_8825", + .drv_name = "rpl_nau8825_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_nau8318_amp, .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", From 486ede0df82dd74472c6f5651e38ff48f7f766c1 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 4 Dec 2023 15:41:58 -0600 Subject: [PATCH 2420/7721] ASoC: Intel: glk_rt5682_max98357a: fix board id mismatch The drv_name in enumeration table for ALC5682I-VS codec does not match the board id string in machine driver. Modify the entry of "10EC5682" to enumerate "RTL5682" as well and remove invalid entry. Fixes: 88b4d77d6035 ("ASoC: Intel: glk_rt5682_max98357a: support ALC5682I-VS codec") Reported-by: Curtis Malainey Reviewed-by: Curtis Malainey Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214200.203100-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 387e73100884..8911c90bbaf6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -19,6 +19,11 @@ static const struct snd_soc_acpi_codecs glk_codecs = { .codecs = {"MX98357A"} }; +static const struct snd_soc_acpi_codecs glk_rt5682_rt5682s_hp = { + .num_codecs = 2, + .codecs = {"10EC5682", "RTL5682"}, +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { { .id = "INT343A", @@ -35,20 +40,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .sof_tplg_filename = "sof-glk-da7219.tplg", }, { - .id = "10EC5682", + .comp_ids = &glk_rt5682_rt5682s_hp, .drv_name = "glk_rt5682_mx98357a", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, .sof_tplg_filename = "sof-glk-rt5682.tplg", }, - { - .id = "RTL5682", - .drv_name = "glk_rt5682_max98357a", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &glk_codecs, - .sof_tplg_filename = "sof-glk-rt5682.tplg", - }, { .id = "10134242", .drv_name = "glk_cs4242_mx98357a", From e38e252dbceeef7d2f848017132efd68e9ae1416 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 4 Dec 2023 15:41:59 -0600 Subject: [PATCH 2421/7721] ASoC: Intel: sof_sdw_rt_sdca_jack_common: ctx->headset_codec_dev = NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sof_sdw_rt_sdca_jack_exit() are used by different codecs, and some of them use the same dai name. For example, rt712 and rt713 both use "rt712-sdca-aif1" and sof_sdw_rt_sdca_jack_exit(). As a result, sof_sdw_rt_sdca_jack_exit() will be called twice by mc_dailink_exit_loop(). Set ctx->headset_codec_dev = NULL; after put_device(ctx->headset_codec_dev); to avoid ctx->headset_codec_dev being put twice. Fixes: 5360c6704638 ("ASoC: Intel: sof_sdw: add rt712 support") Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214200.203100-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c index e430be7681d2..1e5725f0ae33 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c @@ -176,6 +176,7 @@ int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); + ctx->headset_codec_dev = NULL; return 0; } From 70a6b66d6e8e70966274cab2fc9ee75fd60e36bf Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 4 Dec 2023 15:42:00 -0600 Subject: [PATCH 2422/7721] ASoC: Intel: sof_sdw_rt_sdca_jack_common: check ctx->headset_codec_dev instead of playback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'if (!playback)' will not work if the dai is only on capture dai link or is on more than one playback dai links. Check 'if (ctx->headset_codec_dev)' instead. Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214200.203100-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c index 1e5725f0ae33..d9c283829fc7 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c @@ -192,10 +192,10 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, int ret; /* - * headset should be initialized once. - * Do it with dai link for playback. + * Jack detection should be only initialized once for headsets since + * the playback/capture is sharing the same jack */ - if (!playback) + if (ctx->headset_codec_dev) return 0; sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); From 2f03970198d6438d95b96f69041254bd39aafed0 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 4 Dec 2023 15:47:10 -0600 Subject: [PATCH 2423/7721] ASoC: SOF: topology: Use partial match for disconnecting DAI link and DAI widget We use partial match for connecting DAI link and DAI widget. We need to use partial match for disconnecting, too. Fixes: fe88788779fc ("ASoC: SOF: topology: Use partial match for connecting DAI link and DAI widget") Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214713.208951-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9f717366cddc..c1f66ba0e987 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1135,7 +1135,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || - strcmp(sname, rtd->dai_link->stream_name)) + !strstr(rtd->dai_link->stream_name, sname)) continue; for_each_rtd_cpu_dais(rtd, i, cpu_dai) From 6c4df324d78ceb6a3ebb0d42243d131a424c85c3 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Mon, 4 Dec 2023 15:47:11 -0600 Subject: [PATCH 2424/7721] ASoC: SOF: align topology header file with sof topology header Add missed definition and align variable names with sof topology header file. Signed-off-by: Baofeng Tian Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214713.208951-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/topology.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 906e2f327ad2..466ab8e73d98 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -39,6 +39,7 @@ enum sof_comp_type { SOF_COMP_ASRC, /**< Asynchronous sample rate converter */ SOF_COMP_DCBLOCK, SOF_COMP_SMART_AMP, /**< smart amplifier component */ + SOF_COMP_MODULE_ADAPTER, /**< module adapter */ /* keep FILEREAD/FILEWRITE as the last ones */ SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ @@ -68,14 +69,15 @@ struct sof_ipc_comp { /* * SOF memory capabilities, add new ones at the end */ -#define SOF_MEM_CAPS_RAM (1 << 0) -#define SOF_MEM_CAPS_ROM (1 << 1) -#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */ -#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */ -#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */ -#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */ -#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */ -#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */ +#define SOF_MEM_CAPS_RAM BIT(0) +#define SOF_MEM_CAPS_ROM BIT(1) +#define SOF_MEM_CAPS_EXT BIT(2) /**< external */ +#define SOF_MEM_CAPS_LP BIT(3) /**< low power */ +#define SOF_MEM_CAPS_HP BIT(4) /**< high performance */ +#define SOF_MEM_CAPS_DMA BIT(5) /**< DMA'able */ +#define SOF_MEM_CAPS_CACHE BIT(6) /**< cacheable */ +#define SOF_MEM_CAPS_EXEC BIT(7) /**< executable */ +#define SOF_MEM_CAPS_L3 BIT(8) /**< L3 memory */ /* * overrun will cause ring buffer overwrite, instead of XRUN. @@ -87,6 +89,9 @@ struct sof_ipc_comp { */ #define SOF_BUF_UNDERRUN_PERMITTED BIT(1) +/* the UUID size in bytes, shared between FW and host */ +#define SOF_UUID_SIZE 16 + /* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ struct sof_ipc_buffer { struct sof_ipc_comp comp; @@ -140,6 +145,8 @@ enum sof_volume_ramp { SOF_VOLUME_LOG, SOF_VOLUME_LINEAR_ZC, SOF_VOLUME_LOG_ZC, + SOF_VOLUME_WINDOWS_FADE, + SOF_VOLUME_WINDOWS_NO_FADE, }; /* generic volume component */ @@ -234,7 +241,7 @@ struct sof_ipc_comp_process { /* reserved for future use */ uint32_t reserved[7]; - uint8_t data[]; + unsigned char data[]; } __packed; /* frees components, buffers and pipelines From 8ec56af3da4dad008ab10115eb4cec34836afc04 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Mon, 4 Dec 2023 15:47:12 -0600 Subject: [PATCH 2425/7721] ASoC: SOF: add alignment for topology header file struct definition sof header file requires these struct with 4 byte aligned, so add same alignment in sof driver definition. Signed-off-by: Baofeng Tian Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214713.208951-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/topology.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 466ab8e73d98..b3ca886fa28f 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -60,7 +60,7 @@ struct sof_ipc_comp { /* extended data length, 0 if no extended data */ uint32_t ext_data_length; -} __packed; +} __packed __aligned(4); /* * Component Buffers @@ -99,7 +99,7 @@ struct sof_ipc_buffer { uint32_t caps; /**< SOF_MEM_CAPS_ */ uint32_t flags; /**< SOF_BUF_ flags defined above */ uint32_t reserved; /**< reserved for future use */ -} __packed; +} __packed __aligned(4); /* generic component config data - must always be after struct sof_ipc_comp */ struct sof_ipc_comp_config { @@ -112,7 +112,7 @@ struct sof_ipc_comp_config { /* reserved for future use */ uint32_t reserved[2]; -} __packed; +} __packed __aligned(4); /* generic host component */ struct sof_ipc_comp_host { @@ -121,7 +121,7 @@ struct sof_ipc_comp_host { uint32_t direction; /**< SOF_IPC_STREAM_ */ uint32_t no_irq; /**< don't send periodic IRQ to host/DSP */ uint32_t dmac_config; /**< DMA engine specific */ -} __packed; +} __packed __aligned(4); /* generic DAI component */ struct sof_ipc_comp_dai { @@ -131,13 +131,13 @@ struct sof_ipc_comp_dai { uint32_t dai_index; /**< index of this type dai */ uint32_t type; /**< DAI type - SOF_DAI_ */ uint32_t reserved; /**< reserved */ -} __packed; +} __packed __aligned(4); /* generic mixer component */ struct sof_ipc_comp_mixer { struct sof_ipc_comp comp; struct sof_ipc_comp_config config; -} __packed; +} __packed __aligned(4); /* volume ramping types */ enum sof_volume_ramp { @@ -158,7 +158,7 @@ struct sof_ipc_comp_volume { uint32_t max_value; uint32_t ramp; /**< SOF_VOLUME_ */ uint32_t initial_ramp; /**< ramp space in ms */ -} __packed; +} __packed __aligned(4); /* generic SRC component */ struct sof_ipc_comp_src { @@ -168,7 +168,7 @@ struct sof_ipc_comp_src { uint32_t source_rate; /**< source rate or 0 for variable */ uint32_t sink_rate; /**< sink rate or 0 for variable */ uint32_t rate_mask; /**< SOF_RATE_ supported rates */ -} __packed; +} __packed __aligned(4); /* generic ASRC component */ struct sof_ipc_comp_asrc { @@ -194,13 +194,13 @@ struct sof_ipc_comp_asrc { /* reserved for future use */ uint32_t reserved[4]; -} __attribute__((packed)); +} __packed __aligned(4); /* generic MUX component */ struct sof_ipc_comp_mux { struct sof_ipc_comp comp; struct sof_ipc_comp_config config; -} __packed; +} __packed __aligned(4); /* generic tone generator component */ struct sof_ipc_comp_tone { @@ -215,7 +215,7 @@ struct sof_ipc_comp_tone { int32_t period; int32_t repeats; int32_t ramp_step; -} __packed; +} __packed __aligned(4); /** \brief Types of processing components */ enum sof_ipc_process_type { @@ -242,7 +242,7 @@ struct sof_ipc_comp_process { uint32_t reserved[7]; unsigned char data[]; -} __packed; +} __packed __aligned(4); /* frees components, buffers and pipelines * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE @@ -250,13 +250,13 @@ struct sof_ipc_comp_process { struct sof_ipc_free { struct sof_ipc_cmd_hdr hdr; uint32_t id; -} __packed; +} __packed __aligned(4); struct sof_ipc_comp_reply { struct sof_ipc_reply rhdr; uint32_t id; uint32_t offset; -} __packed; +} __packed __aligned(4); /* * Pipeline @@ -281,25 +281,25 @@ struct sof_ipc_pipe_new { uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */ uint32_t xrun_limit_usecs; /**< report xruns greater than limit */ uint32_t time_domain; /**< scheduling time domain */ -} __packed; +} __packed __aligned(4); /* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ struct sof_ipc_pipe_ready { struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; -} __packed; +} __packed __aligned(4); struct sof_ipc_pipe_free { struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; -} __packed; +} __packed __aligned(4); /* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ struct sof_ipc_pipe_comp_connect { struct sof_ipc_cmd_hdr hdr; uint32_t source_id; uint32_t sink_id; -} __packed; +} __packed __aligned(4); /* external events */ enum sof_event_types { From ebd12b2ca6145550a7e42cd2320870db02dd0f3c Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Mon, 4 Dec 2023 15:47:13 -0600 Subject: [PATCH 2426/7721] ASoC: SOF: Wire up buffer flags Buffer flags have been in firmware for ages but were never fully implemented in the topology/kernel system. This commit finishes off the implementation. Reviewed-by: Ranjani Sridharan Signed-off-by: Curtis Malainey Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214713.208951-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/ipc3-topology.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 0fb39780f9bd..ee5708934614 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -35,6 +35,7 @@ /* buffers */ #define SOF_TKN_BUF_SIZE 100 #define SOF_TKN_BUF_CAPS 101 +#define SOF_TKN_BUF_FLAGS 102 /* DAI */ /* Token retired with ABI 3.2, do not use for new capabilities diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 7a4932c152a9..a8e0054cb8a6 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -72,6 +72,8 @@ static const struct sof_topology_token buffer_tokens[] = { offsetof(struct sof_ipc_buffer, size)}, {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_buffer, caps)}, + {SOF_TKN_BUF_FLAGS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, flags)}, }; /* DAI */ From dce94061f0d02f5ab355390a6e63d3dbea938b72 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Mon, 4 Dec 2023 04:21:01 -0800 Subject: [PATCH 2427/7721] drm/v3d: Fix missing error code in v3d_submit_cpu_ioctl() Smatch warns: drivers/gpu/drm/v3d/v3d_submit.c:1222 v3d_submit_cpu_ioctl() warn: missing error code 'ret' When there is no job type or job is submitted with wrong number of BOs it is an error path, ret is zero at this point which is incorrect return. Fix this by changing it to -EINVAL. Fixes: aafc1a2bea67 ("drm/v3d: Add a CPU job submission") Signed-off-by: Harshit Mogalapalli Reviewed-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231204122102.181298-1-harshit.m.mogalapalli@oracle.com --- drivers/gpu/drm/v3d/v3d_submit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index d7a9da2484fd..fcff41dd2315 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -1219,11 +1219,13 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, /* Every CPU job must have a CPU job user extension */ if (!cpu_job->job_type) { DRM_DEBUG("CPU job must have a CPU job user extension.\n"); + ret = -EINVAL; goto fail; } if (args->bo_handle_count != cpu_job_bo_handle_count[cpu_job->job_type]) { DRM_DEBUG("This CPU job was not submitted with the proper number of BOs.\n"); + ret = -EINVAL; goto fail; } From 8ad55b1e73c4e77656e2bea68fa2b484f33a6425 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 1 Dec 2023 19:01:54 +0100 Subject: [PATCH 2428/7721] docs: netlink: add NLMSG_DONE message format for doit actions In case NLMSG_DONE message is sent as a reply to doit action, multiple kernel implementation do not send anything else than struct nlmsghdr. Add this note to the Netlink intro documentation. Signed-off-by: Jiri Pirko Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20231201180154.864007-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/userspace-api/netlink/intro.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/userspace-api/netlink/intro.rst b/Documentation/userspace-api/netlink/intro.rst index 7b1d401210ef..aacffade8f84 100644 --- a/Documentation/userspace-api/netlink/intro.rst +++ b/Documentation/userspace-api/netlink/intro.rst @@ -234,6 +234,10 @@ ACK attributes may be present:: | ** optionally extended ACK | ---------------------------------------------- +Note that some implementations may issue custom ``NLMSG_DONE`` messages +in reply to ``do`` action requests. In that case the payload is +implementation-specific and may also be absent. + .. _res_fam: Resolving the Family ID From 9853294627237b73a6b765162d9c0485b0697db5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 1 Dec 2023 16:01:30 +0100 Subject: [PATCH 2429/7721] net: phy: micrel: use devm_clk_get_optional_enabled for the rmii-ref clock While the external clock input will most likely be enabled, it's not guaranteed and clk_get_rate in some suppliers will even just return valid results when the clock is running. So use devm_clk_get_optional_enabled to retrieve and enable the clock in one go. Signed-off-by: Heiko Stuebner Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20231201150131.326766-2-heiko@sntech.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index bd4cd082662f..de116a0753a1 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -2001,7 +2001,7 @@ static int kszphy_probe(struct phy_device *phydev) kszphy_parse_led_mode(phydev); - clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref"); + clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, "rmii-ref"); /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */ if (!IS_ERR_OR_NULL(clk)) { unsigned long rate = clk_get_rate(clk); From 99ac4cbcc2a50ecc86ffacc7b4b42ba4259a90d4 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 1 Dec 2023 16:01:31 +0100 Subject: [PATCH 2430/7721] net: phy: micrel: allow usage of generic ethernet-phy clock The generic ethernet-phy binding allows describing an external clock since commit 350b7a258f20 ("dt-bindings: net: phy: Document support for external PHY clk") for cases where the phy is not supplied by an oscillator but instead by a clock from the host system. And the old named "rmii-ref" clock from 2014 is only specified for phys of the KSZ8021, KSZ8031, KSZ8081, KSZ8091 types. So allow retrieving and enabling the optional generic clock on phys that do not provide a rmii-ref clock. Signed-off-by: Heiko Stuebner Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20231201150131.326766-3-heiko@sntech.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index de116a0753a1..d2aa3d0695e3 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -2021,6 +2021,11 @@ static int kszphy_probe(struct phy_device *phydev) rate); return -EINVAL; } + } else if (!clk) { + /* unnamed clock from the generic ethernet-phy binding */ + clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); } if (ksz8041_fiber_mode(phydev)) From 91051f003948432f83b5d2766eeb83b2b4993649 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 1 Dec 2023 15:49:52 +0100 Subject: [PATCH 2431/7721] tcp: Dump bound-only sockets in inet_diag. Walk the hashinfo->bhash2 table so that inet_diag can dump TCP sockets that are bound but haven't yet called connect() or listen(). The code is inspired by the ->lhash2 loop. However there's no manual test of the source port, since this kind of filtering is already handled by inet_diag_bc_sk(). Also, a maximum of 16 sockets are dumped at a time, to avoid running with bh disabled for too long. There's no TCP state for bound but otherwise inactive sockets. Such sockets normally map to TCP_CLOSE. However, "ss -l", which is supposed to only dump listening sockets, actually requests the kernel to dump sockets in either the TCP_LISTEN or TCP_CLOSE states. To avoid dumping bound-only sockets with "ss -l", we therefore need to define a new pseudo-state (TCP_BOUND_INACTIVE) that user space will be able to set explicitly. With an IPv4, an IPv6 and an IPv6-only socket, bound respectively to 40000, 64000, 60000, an updated version of iproute2 could work as follow: $ ss -t state bound-inactive Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 0.0.0.0:40000 0.0.0.0:* 0 0 [::]:60000 [::]:* 0 0 *:64000 *:* Reviewed-by: Eric Dumazet Signed-off-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/b3a84ae61e19c06806eea9c602b3b66e8f0cfc81.1701362867.git.gnault@redhat.com Signed-off-by: Jakub Kicinski --- include/net/tcp_states.h | 2 + include/uapi/linux/bpf.h | 1 + net/ipv4/inet_diag.c | 86 +++++++++++++++++++++++++++++++++++++++- net/ipv4/tcp.c | 1 + 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/include/net/tcp_states.h b/include/net/tcp_states.h index cc00118acca1..d60e8148ff4c 100644 --- a/include/net/tcp_states.h +++ b/include/net/tcp_states.h @@ -22,6 +22,7 @@ enum { TCP_LISTEN, TCP_CLOSING, /* Now a valid state */ TCP_NEW_SYN_RECV, + TCP_BOUND_INACTIVE, /* Pseudo-state for inet_diag */ TCP_MAX_STATES /* Leave at the end! */ }; @@ -43,6 +44,7 @@ enum { TCPF_LISTEN = (1 << TCP_LISTEN), TCPF_CLOSING = (1 << TCP_CLOSING), TCPF_NEW_SYN_RECV = (1 << TCP_NEW_SYN_RECV), + TCPF_BOUND_INACTIVE = (1 << TCP_BOUND_INACTIVE), }; #endif /* _LINUX_TCP_STATES_H */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e88746ba7d21..b1e8c5bdfc82 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6902,6 +6902,7 @@ enum { BPF_TCP_LISTEN, BPF_TCP_CLOSING, /* Now a valid state */ BPF_TCP_NEW_SYN_RECV, + BPF_TCP_BOUND_INACTIVE, BPF_TCP_MAX_STATES /* Leave at the end! */ }; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 7d0e7aaa71e0..46b13962ad02 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1077,10 +1077,94 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, s_i = num = s_num = 0; } +/* Process a maximum of SKARR_SZ sockets at a time when walking hash buckets + * with bh disabled. + */ +#define SKARR_SZ 16 + + /* Dump bound but inactive (not listening, connecting, etc.) sockets */ + if (cb->args[0] == 1) { + if (!(idiag_states & TCPF_BOUND_INACTIVE)) + goto skip_bind_ht; + + for (i = s_i; i < hashinfo->bhash_size; i++) { + struct inet_bind_hashbucket *ibb; + struct inet_bind2_bucket *tb2; + struct sock *sk_arr[SKARR_SZ]; + int num_arr[SKARR_SZ]; + int idx, accum, res; + +resume_bind_walk: + num = 0; + accum = 0; + ibb = &hashinfo->bhash2[i]; + + spin_lock_bh(&ibb->lock); + inet_bind_bucket_for_each(tb2, &ibb->chain) { + if (!net_eq(ib2_net(tb2), net)) + continue; + + sk_for_each_bound_bhash2(sk, &tb2->owners) { + struct inet_sock *inet = inet_sk(sk); + + if (num < s_num) + goto next_bind; + + if (sk->sk_state != TCP_CLOSE || + !inet->inet_num) + goto next_bind; + + if (r->sdiag_family != AF_UNSPEC && + r->sdiag_family != sk->sk_family) + goto next_bind; + + if (!inet_diag_bc_sk(bc, sk)) + goto next_bind; + + sock_hold(sk); + num_arr[accum] = num; + sk_arr[accum] = sk; + if (++accum == SKARR_SZ) + goto pause_bind_walk; +next_bind: + num++; + } + } +pause_bind_walk: + spin_unlock_bh(&ibb->lock); + + res = 0; + for (idx = 0; idx < accum; idx++) { + if (res >= 0) { + res = inet_sk_diag_fill(sk_arr[idx], + NULL, skb, cb, + r, NLM_F_MULTI, + net_admin); + if (res < 0) + num = num_arr[idx]; + } + sock_put(sk_arr[idx]); + } + if (res < 0) + goto done; + + cond_resched(); + + if (accum == SKARR_SZ) { + s_num = num + 1; + goto resume_bind_walk; + } + + s_num = 0; + } +skip_bind_ht: + cb->args[0] = 2; + s_i = num = s_num = 0; + } + if (!(idiag_states & ~TCPF_LISTEN)) goto out; -#define SKARR_SZ 16 for (i = s_i; i <= hashinfo->ehash_mask; i++) { struct inet_ehash_bucket *head = &hashinfo->ehash[i]; spinlock_t *lock = inet_ehash_lockp(hashinfo, i); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 53bcc17c91e4..a100df07d34a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2605,6 +2605,7 @@ void tcp_set_state(struct sock *sk, int state) BUILD_BUG_ON((int)BPF_TCP_LISTEN != (int)TCP_LISTEN); BUILD_BUG_ON((int)BPF_TCP_CLOSING != (int)TCP_CLOSING); BUILD_BUG_ON((int)BPF_TCP_NEW_SYN_RECV != (int)TCP_NEW_SYN_RECV); + BUILD_BUG_ON((int)BPF_TCP_BOUND_INACTIVE != (int)TCP_BOUND_INACTIVE); BUILD_BUG_ON((int)BPF_TCP_MAX_STATES != (int)TCP_MAX_STATES); /* bpf uapi header bpf.h defines an anonymous enum with values From 08b386b132c61e06e573d6523a8c0c17b90fb8da Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:10 -0800 Subject: [PATCH 2432/7721] bnxt_en: Fix backing store V2 logic The current code determines the last backing store valid type during bnxt_hwrm_func_backing_store_qcaps_v2(). In effect, the last type is determined based on what firmware advertises. The more correct way is to determine it based on what the driver is configuring. The driver may not configure all the backing store types advertised by firmware. Move the logic to determine the last type to bnxt_backing_store_cfg_v2(). We need to pass the legacy enable flags to the function in case only the legacy types are being configured. Fixes: 236e237f8ffe ("bnxt_en: Add support for HWRM_FUNC_BACKING_STORE_CFG_V2 firmware calls") Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 17 +++++++++++------ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e35e7e02538c..6f37b6ac8996 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7249,7 +7249,6 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) { struct hwrm_func_backing_store_qcaps_v2_output *resp; struct hwrm_func_backing_store_qcaps_v2_input *req; - u16 last_valid_type = BNXT_CTX_INV; struct bnxt_ctx_mem_info *ctx; u16 type; int rc; @@ -7281,7 +7280,6 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) continue; ctxm->type = le16_to_cpu(resp->type); - last_valid_type = ctxm->type; ctxm->entry_size = le16_to_cpu(resp->entry_size); ctxm->flags = flags; ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map); @@ -7298,8 +7296,6 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) i++, p++) ctxm->split[i] = le32_to_cpu(*p); } - if (last_valid_type < BNXT_CTX_V2_MAX) - ctx->ctx_arr[last_valid_type].last = true; rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_V2_MAX); ctx_done: @@ -7751,13 +7747,22 @@ static int bnxt_hwrm_func_backing_store_cfg_v2(struct bnxt *bp, return rc; } -static int bnxt_backing_store_cfg_v2(struct bnxt *bp) +static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena) { struct bnxt_ctx_mem_info *ctx = bp->ctx; struct bnxt_ctx_mem_type *ctxm; + u16 last_type; int rc = 0; u16 type; + if (!ena) + return 0; + else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) + last_type = BNXT_CTX_MAX - 1; + else + last_type = BNXT_CTX_L2_MAX - 1; + ctx->ctx_arr[last_type].last = 1; + for (type = 0 ; type < BNXT_CTX_V2_MAX; type++) { ctxm = &ctx->ctx_arr[type]; @@ -7904,7 +7909,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES; if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2) - rc = bnxt_backing_store_cfg_v2(bp); + rc = bnxt_backing_store_cfg_v2(bp, ena); else rc = bnxt_hwrm_func_backing_store_cfg(bp, ena); if (rc) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 94b3627406c4..f22800c1bb77 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1611,6 +1611,7 @@ struct bnxt_ctx_mem_type { #define BNXT_CTX_XPAR FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_XID_PARTITION #define BNXT_CTX_MAX (BNXT_CTX_TIM + 1) +#define BNXT_CTX_L2_MAX (BNXT_CTX_FTQM + 1) #define BNXT_CTX_V2_MAX (BNXT_CTX_XPAR + 1) #define BNXT_CTX_INV ((u16)-1) From 397d44bf17216f7da6ea7c703e9124c065a61697 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:11 -0800 Subject: [PATCH 2433/7721] bnxt_en: Update firmware interface to 1.10.3.15 This updated interface supports the new 5760X P7 chip family. It has the changes to support the new link speeds/modes and other changes for the basic L2 features. Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 521 +++++++++++++----- 2 files changed, 388 insertions(+), 135 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index f22800c1bb77..8a22b2d7ea94 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -18,7 +18,7 @@ */ #define DRV_VER_MAJ 1 #define DRV_VER_MIN 10 -#define DRV_VER_UPD 2 +#define DRV_VER_UPD 3 #include #include diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index d5fad5a3cdd1..e957abd704db 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -40,6 +40,8 @@ struct hwrm_resp_hdr { #define TLV_TYPE_ROCE_SP_COMMAND 0x3UL #define TLV_TYPE_QUERY_ROCE_CC_GEN1 0x4UL #define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL +#define TLV_TYPE_QUERY_ROCE_CC_GEN2 0x6UL +#define TLV_TYPE_MODIFY_ROCE_CC_GEN2 0x7UL #define TLV_TYPE_ENGINE_CKV_ALIAS_ECC_PUBLIC_KEY 0x8001UL #define TLV_TYPE_ENGINE_CKV_IV 0x8003UL #define TLV_TYPE_ENGINE_CKV_AUTH_TAG 0x8004UL @@ -196,6 +198,9 @@ struct cmd_nums { #define HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_QCFG 0x8aUL #define HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_CFG 0x8bUL #define HWRM_QUEUE_QCAPS 0x8cUL + #define HWRM_QUEUE_ADPTV_QOS_RX_TUNING_QCFG 0x8dUL + #define HWRM_QUEUE_ADPTV_QOS_RX_TUNING_CFG 0x8eUL + #define HWRM_QUEUE_ADPTV_QOS_TX_TUNING_QCFG 0x8fUL #define HWRM_CFA_L2_FILTER_ALLOC 0x90UL #define HWRM_CFA_L2_FILTER_FREE 0x91UL #define HWRM_CFA_L2_FILTER_CFG 0x92UL @@ -214,6 +219,7 @@ struct cmd_nums { #define HWRM_TUNNEL_DST_PORT_QUERY 0xa0UL #define HWRM_TUNNEL_DST_PORT_ALLOC 0xa1UL #define HWRM_TUNNEL_DST_PORT_FREE 0xa2UL + #define HWRM_QUEUE_ADPTV_QOS_TX_TUNING_CFG 0xa3UL #define HWRM_STAT_CTX_ENG_QUERY 0xafUL #define HWRM_STAT_CTX_ALLOC 0xb0UL #define HWRM_STAT_CTX_FREE 0xb1UL @@ -261,6 +267,7 @@ struct cmd_nums { #define HWRM_PORT_EP_TX_CFG 0xdbUL #define HWRM_PORT_CFG 0xdcUL #define HWRM_PORT_QCFG 0xddUL + #define HWRM_PORT_MAC_QCAPS 0xdfUL #define HWRM_TEMP_MONITOR_QUERY 0xe0UL #define HWRM_REG_POWER_QUERY 0xe1UL #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL @@ -392,6 +399,10 @@ struct cmd_nums { #define HWRM_FUNC_KEY_CTX_FREE 0x1adUL #define HWRM_FUNC_LAG_MODE_CFG 0x1aeUL #define HWRM_FUNC_LAG_MODE_QCFG 0x1afUL + #define HWRM_FUNC_LAG_CREATE 0x1b0UL + #define HWRM_FUNC_LAG_UPDATE 0x1b1UL + #define HWRM_FUNC_LAG_FREE 0x1b2UL + #define HWRM_FUNC_LAG_QCFG 0x1b3UL #define HWRM_SELFTEST_QLIST 0x200UL #define HWRM_SELFTEST_EXEC 0x201UL #define HWRM_SELFTEST_IRQ 0x202UL @@ -406,9 +417,9 @@ struct cmd_nums { #define HWRM_MFG_FRU_EEPROM_READ 0x20bUL #define HWRM_MFG_SOC_IMAGE 0x20cUL #define HWRM_MFG_SOC_QSTATUS 0x20dUL - #define HWRM_MFG_PARAM_SEEPROM_SYNC 0x20eUL - #define HWRM_MFG_PARAM_SEEPROM_READ 0x20fUL - #define HWRM_MFG_PARAM_SEEPROM_HEALTH 0x210UL + #define HWRM_MFG_PARAM_CRITICAL_DATA_FINALIZE 0x20eUL + #define HWRM_MFG_PARAM_CRITICAL_DATA_READ 0x20fUL + #define HWRM_MFG_PARAM_CRITICAL_DATA_HEALTH 0x210UL #define HWRM_MFG_PRVSN_EXPORT_CSR 0x211UL #define HWRM_MFG_PRVSN_IMPORT_CERT 0x212UL #define HWRM_MFG_PRVSN_GET_STATE 0x213UL @@ -418,6 +429,16 @@ struct cmd_nums { #define HWRM_MFG_SELFTEST_EXEC 0x217UL #define HWRM_STAT_GENERIC_QSTATS 0x218UL #define HWRM_MFG_PRVSN_EXPORT_CERT 0x219UL + #define HWRM_STAT_DB_ERROR_QSTATS 0x21aUL + #define HWRM_UDCC_QCAPS 0x258UL + #define HWRM_UDCC_CFG 0x259UL + #define HWRM_UDCC_QCFG 0x25aUL + #define HWRM_UDCC_SESSION_CFG 0x25bUL + #define HWRM_UDCC_SESSION_QCFG 0x25cUL + #define HWRM_UDCC_SESSION_QUERY 0x25dUL + #define HWRM_UDCC_COMP_CFG 0x25eUL + #define HWRM_UDCC_COMP_QCFG 0x25fUL + #define HWRM_UDCC_COMP_QUERY 0x260UL #define HWRM_TF 0x2bcUL #define HWRM_TF_VERSION_GET 0x2bdUL #define HWRM_TF_SESSION_OPEN 0x2c6UL @@ -582,9 +603,9 @@ struct hwrm_err_output { #define HWRM_TARGET_ID_TOOLS 0xFFFD #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 -#define HWRM_VERSION_UPDATE 2 -#define HWRM_VERSION_RSVD 171 -#define HWRM_VERSION_STR "1.10.2.171" +#define HWRM_VERSION_UPDATE 3 +#define HWRM_VERSION_RSVD 15 +#define HWRM_VERSION_STR "1.10.3.15" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -816,7 +837,8 @@ struct hwrm_async_event_cmpl { #define ASYNC_EVENT_CMPL_EVENT_ID_DOORBELL_PACING_NQ_UPDATE 0x48UL #define ASYNC_EVENT_CMPL_EVENT_ID_HW_DOORBELL_RECOVERY_READ_ERROR 0x49UL #define ASYNC_EVENT_CMPL_EVENT_ID_CTX_ERROR 0x4aUL - #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x4bUL + #define ASYNC_EVENT_CMPL_EVENT_ID_UDCC_SESSION_CHANGE 0x4bUL + #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x4cUL #define ASYNC_EVENT_CMPL_EVENT_ID_FW_TRACE_MSG 0xfeUL #define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL #define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR @@ -1632,7 +1654,7 @@ struct hwrm_func_qcaps_input { u8 unused_0[6]; }; -/* hwrm_func_qcaps_output (size:896b/112B) */ +/* hwrm_func_qcaps_output (size:1088b/136B) */ struct hwrm_func_qcaps_output { __le16 error_code; __le16 req_type; @@ -1736,21 +1758,29 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_MPC_CHNLS_CAP_PRIMATE 0x10UL __le16 max_key_ctxs_alloc; __le32 flags_ext2; - #define FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED 0x1UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_QUIC_SUPPORTED 0x2UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_KDNET_SUPPORTED 0x4UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_HW_LAG_SUPPORTED 0x400UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_ON_CHIP_CTX_SUPPORTED 0x800UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_STEERING_TAG_SUPPORTED 0x1000UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_ENHANCED_VF_SCALE_SUPPORTED 0x2000UL - #define FUNC_QCAPS_RESP_FLAGS_EXT2_KEY_XID_PARTITION_SUPPORTED 0x4000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED 0x1UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_QUIC_SUPPORTED 0x2UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_KDNET_SUPPORTED 0x4UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_HW_LAG_SUPPORTED 0x400UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_ON_CHIP_CTX_SUPPORTED 0x800UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_STEERING_TAG_SUPPORTED 0x1000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_ENHANCED_VF_SCALE_SUPPORTED 0x2000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_KEY_XID_PARTITION_SUPPORTED 0x4000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_CONCURRENT_KTLS_QUIC_SUPPORTED 0x8000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_CROSS_TC_CAP_SUPPORTED 0x10000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_PER_TC_CAP_SUPPORTED 0x20000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_PER_TC_RESERVATION_SUPPORTED 0x40000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_DB_ERROR_STATS_SUPPORTED 0x80000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_ROCE_VF_RESOURCE_MGMT_SUPPORTED 0x100000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDCC_SUPPORTED 0x200000UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_TIMED_TX_SO_TXTIME_SUPPORTED 0x400000UL __le16 tunnel_disable_flag; #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL @@ -1760,15 +1790,21 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_IPINIP 0x20UL #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_MPLS 0x40UL #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_PPPOE 0x80UL - u8 key_xid_partition_cap; - #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_TKC 0x1UL - #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_RKC 0x2UL - #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_QUIC_TKC 0x4UL - #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_QUIC_RKC 0x8UL - u8 unused_1; + __le16 xid_partition_cap; + #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_KTLS_TKC 0x1UL + #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_KTLS_RKC 0x2UL + #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_QUIC_TKC 0x4UL + #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_QUIC_RKC 0x8UL u8 device_serial_number[8]; __le16 ctxs_per_partition; - u8 unused_2[5]; + u8 unused_2[2]; + __le32 roce_vf_max_av; + __le32 roce_vf_max_cq; + __le32 roce_vf_max_mrw; + __le32 roce_vf_max_qp; + __le32 roce_vf_max_srq; + __le32 roce_vf_max_gid; + u8 unused_3[3]; u8 valid; }; @@ -1783,7 +1819,7 @@ struct hwrm_func_qcfg_input { u8 unused_0[6]; }; -/* hwrm_func_qcfg_output (size:1024b/128B) */ +/* hwrm_func_qcfg_output (size:1280b/160B) */ struct hwrm_func_qcfg_output { __le16 error_code; __le16 req_type; @@ -1892,7 +1928,7 @@ struct hwrm_func_qcfg_output { __le16 alloc_msix; __le16 registered_vfs; __le16 l2_doorbell_bar_size_kb; - u8 unused_1; + u8 active_endpoints; u8 always_1; __le32 reset_addr_poll; __le16 legacy_l2_db_size_kb; @@ -1952,15 +1988,26 @@ struct hwrm_func_qcfg_output { u8 kdnet_pcie_function; __le16 port_kdnet_fid; u8 unused_5[2]; - __le32 alloc_tx_key_ctxs; - __le32 alloc_rx_key_ctxs; + __le32 num_ktls_tx_key_ctxs; + __le32 num_ktls_rx_key_ctxs; u8 lag_id; u8 parif; - u8 unused_6[5]; + u8 fw_lag_id; + u8 unused_6; + __le32 num_quic_tx_key_ctxs; + __le32 num_quic_rx_key_ctxs; + __le32 roce_max_av_per_vf; + __le32 roce_max_cq_per_vf; + __le32 roce_max_mrw_per_vf; + __le32 roce_max_qp_per_vf; + __le32 roce_max_srq_per_vf; + __le32 roce_max_gid_per_vf; + __le16 xid_partition_cfg; + u8 unused_7; u8 valid; }; -/* hwrm_func_cfg_input (size:1088b/136B) */ +/* hwrm_func_cfg_input (size:1280b/160B) */ struct hwrm_func_cfg_input { __le16 req_type; __le16 cmpl_ring; @@ -1996,7 +2043,6 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL #define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL #define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL - #define FUNC_CFG_REQ_FLAGS_KEY_CTX_ASSETS_TEST 0x80000000UL __le32 enables; #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL @@ -2028,8 +2074,8 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_ENABLES_PARTITION_MAX_BW 0x8000000UL #define FUNC_CFG_REQ_ENABLES_TPID 0x10000000UL #define FUNC_CFG_REQ_ENABLES_HOST_MTU 0x20000000UL - #define FUNC_CFG_REQ_ENABLES_TX_KEY_CTXS 0x40000000UL - #define FUNC_CFG_REQ_ENABLES_RX_KEY_CTXS 0x80000000UL + #define FUNC_CFG_REQ_ENABLES_KTLS_TX_KEY_CTXS 0x40000000UL + #define FUNC_CFG_REQ_ENABLES_KTLS_RX_KEY_CTXS 0x80000000UL __le16 admin_mtu; __le16 mru; __le16 num_rsscos_ctxs; @@ -2139,10 +2185,21 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_LAST FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 __be16 tpid; __le16 host_mtu; - u8 unused_0[4]; + __le32 flags2; + #define FUNC_CFG_REQ_FLAGS2_KTLS_KEY_CTX_ASSETS_TEST 0x1UL + #define FUNC_CFG_REQ_FLAGS2_QUIC_KEY_CTX_ASSETS_TEST 0x2UL __le32 enables2; - #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL - #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL + #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL + #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL + #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL + #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL + #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL u8 port_kdnet_mode; #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL @@ -2165,7 +2222,18 @@ struct hwrm_func_cfg_input { __le32 num_ktls_rx_key_ctxs; __le32 num_quic_tx_key_ctxs; __le32 num_quic_rx_key_ctxs; - __le32 unused_2; + __le32 roce_max_av_per_vf; + __le32 roce_max_cq_per_vf; + __le32 roce_max_mrw_per_vf; + __le32 roce_max_qp_per_vf; + __le32 roce_max_srq_per_vf; + __le32 roce_max_gid_per_vf; + __le16 xid_partition_cfg; + #define FUNC_CFG_REQ_XID_PARTITION_CFG_KTLS_TKC 0x1UL + #define FUNC_CFG_REQ_XID_PARTITION_CFG_KTLS_RKC 0x2UL + #define FUNC_CFG_REQ_XID_PARTITION_CFG_QUIC_TKC 0x4UL + #define FUNC_CFG_REQ_XID_PARTITION_CFG_QUIC_RKC 0x8UL + __le16 unused_2; }; /* hwrm_func_cfg_output (size:128b/16B) */ @@ -2604,7 +2672,7 @@ struct hwrm_func_vf_resource_cfg_input { __le32 max_quic_rx_key_ctxs; }; -/* hwrm_func_vf_resource_cfg_output (size:320b/40B) */ +/* hwrm_func_vf_resource_cfg_output (size:384b/48B) */ struct hwrm_func_vf_resource_cfg_output { __le16 error_code; __le16 req_type; @@ -2618,8 +2686,10 @@ struct hwrm_func_vf_resource_cfg_output { __le16 reserved_vnics; __le16 reserved_stat_ctx; __le16 reserved_hw_ring_grps; - __le32 reserved_tx_key_ctxs; - __le32 reserved_rx_key_ctxs; + __le32 reserved_ktls_tx_key_ctxs; + __le32 reserved_ktls_rx_key_ctxs; + __le32 reserved_quic_tx_key_ctxs; + __le32 reserved_quic_rx_key_ctxs; u8 unused_0[7]; u8 valid; }; @@ -3441,7 +3511,8 @@ struct hwrm_func_ptp_cfg_input { #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_4K 0x1UL #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_8K 0x2UL #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M 0x3UL - #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M + #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_25M 0x4UL + #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_25M u8 unused_0[3]; __le32 ptp_freq_adj_ext_period; __le32 ptp_freq_adj_ext_up; @@ -3627,28 +3698,28 @@ struct hwrm_func_backing_store_qcfg_v2_input { __le16 target_id; __le64 resp_addr; __le16 type; - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QP 0x0UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ 0x1UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ 0x2UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_VNIC 0x3UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_STAT 0x4UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SP_TQM_RING 0x5UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_FP_TQM_RING 0x6UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MRAV 0xeUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TIM 0xfUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TKC 0x13UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RKC 0x14UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MP_TQM_RING 0x15UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ_DB_SHADOW 0x18UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ_DB_SHADOW 0x19UL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_TKC 0x1aUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_RKC 0x1bUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TBL_SCOPE 0x1cUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_XID_PARTITION 0x1dUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL - #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QP 0x0UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ 0x1UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ 0x2UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_VNIC 0x3UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_STAT 0x4UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SP_TQM_RING 0x5UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_FP_TQM_RING 0x6UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MRAV 0xeUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TIM 0xfUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TKC 0x13UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RKC 0x14UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MP_TQM_RING 0x15UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ_DB_SHADOW 0x18UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ_DB_SHADOW 0x19UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_TKC 0x1aUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_RKC 0x1bUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TBL_SCOPE 0x1cUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_XID_PARTITION_TABLE 0x1dUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID __le16 instance; u8 rsvd[4]; }; @@ -3744,6 +3815,15 @@ struct mrav_split_entries { __le32 rsvd2[2]; }; +/* ts_split_entries (size:128b/16B) */ +struct ts_split_entries { + __le32 region_num_entries; + u8 tsid; + u8 lkup_static_bkt_cnt_exp[2]; + u8 rsvd; + __le32 rsvd2[2]; +}; + /* hwrm_func_backing_store_qcaps_v2_input (size:192b/24B) */ struct hwrm_func_backing_store_qcaps_v2_input { __le16 req_type; @@ -3761,8 +3841,8 @@ struct hwrm_func_backing_store_qcaps_v2_input { #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING 0x6UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV 0xeUL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM 0xfUL - #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC 0x13UL - #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC 0x14UL + #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_KTLS_TKC 0x13UL + #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_KTLS_RKC 0x14UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING 0x15UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL @@ -3793,8 +3873,8 @@ struct hwrm_func_backing_store_qcaps_v2_output { #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_FP_TQM_RING 0x6UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_MRAV 0xeUL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_TIM 0xfUL - #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_TKC 0x13UL - #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RKC 0x14UL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_KTLS_TKC 0x13UL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_KTLS_RKC 0x14UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_MP_TQM_RING 0x15UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_SQ_DB_SHADOW 0x16UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RQ_DB_SHADOW 0x17UL @@ -3838,56 +3918,55 @@ struct hwrm_func_backing_store_qcaps_v2_output { /* hwrm_func_dbr_pacing_qcfg_input (size:128b/16B) */ struct hwrm_func_dbr_pacing_qcfg_input { - __le16 req_type; - __le16 cmpl_ring; - __le16 seq_id; - __le16 target_id; - __le64 resp_addr; + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; }; /* hwrm_func_dbr_pacing_qcfg_output (size:512b/64B) */ struct hwrm_func_dbr_pacing_qcfg_output { - __le16 error_code; - __le16 req_type; - __le16 seq_id; - __le16 resp_len; - u8 flags; -#define FUNC_DBR_PACING_QCFG_RESP_FLAGS_DBR_NQ_EVENT_ENABLED 0x1UL - u8 unused_0[7]; - __le32 dbr_stat_db_fifo_reg; -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK 0x3UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_SFT 0 -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_PCIE_CFG 0x0UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC 0x1UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR0 0x2UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 0x3UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_LAST \ - FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_MASK 0xfffffffcUL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SFT 2 - __le32 dbr_stat_db_fifo_reg_watermark_mask; - u8 dbr_stat_db_fifo_reg_watermark_shift; - u8 unused_1[3]; - __le32 dbr_stat_db_fifo_reg_fifo_room_mask; - u8 dbr_stat_db_fifo_reg_fifo_room_shift; - u8 unused_2[3]; - __le32 dbr_throttling_aeq_arm_reg; -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_MASK 0x3UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_SFT 0 -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_PCIE_CFG 0x0UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_GRC 0x1UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR0 0x2UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 0x3UL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_LAST \ - FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_MASK 0xfffffffcUL -#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SFT 2 - u8 dbr_throttling_aeq_arm_reg_val; - u8 unused_3[7]; - __le32 primary_nq_id; - __le32 pacing_threshold; - u8 unused_4[7]; - u8 valid; + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 flags; + #define FUNC_DBR_PACING_QCFG_RESP_FLAGS_DBR_NQ_EVENT_ENABLED 0x1UL + u8 unused_0[7]; + __le32 dbr_stat_db_fifo_reg; + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK 0x3UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_SFT 0 + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_PCIE_CFG 0x0UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC 0x1UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR0 0x2UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 0x3UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_LAST FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_MASK 0xfffffffcUL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SFT 2 + __le32 dbr_stat_db_fifo_reg_watermark_mask; + u8 dbr_stat_db_fifo_reg_watermark_shift; + u8 unused_1[3]; + __le32 dbr_stat_db_fifo_reg_fifo_room_mask; + u8 dbr_stat_db_fifo_reg_fifo_room_shift; + u8 unused_2[3]; + __le32 dbr_throttling_aeq_arm_reg; + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_MASK 0x3UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_SFT 0 + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_PCIE_CFG 0x0UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_GRC 0x1UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR0 0x2UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 0x3UL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_LAST FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_MASK 0xfffffffcUL + #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SFT 2 + u8 dbr_throttling_aeq_arm_reg_val; + u8 unused_3[3]; + __le32 dbr_stat_db_max_fifo_depth; + __le32 primary_nq_id; + __le32 pacing_threshold; + u8 unused_4[7]; + u8 valid; }; /* hwrm_func_drv_if_change_input (size:192b/24B) */ @@ -3915,7 +3994,7 @@ struct hwrm_func_drv_if_change_output { u8 valid; }; -/* hwrm_port_phy_cfg_input (size:448b/56B) */ +/* hwrm_port_phy_cfg_input (size:512b/64B) */ struct hwrm_port_phy_cfg_input { __le16 req_type; __le16 cmpl_ring; @@ -3960,6 +4039,8 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_ENABLES_TX_LPI_TIMER 0x400UL #define PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED 0x800UL #define PORT_PHY_CFG_REQ_ENABLES_AUTO_PAM4_LINK_SPEED_MASK 0x1000UL + #define PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2 0x2000UL + #define PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK 0x4000UL __le16 port_id; __le16 force_link_speed; #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB 0x1UL @@ -3990,7 +4071,9 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_AUTO_PAUSE_TX 0x1UL #define PORT_PHY_CFG_REQ_AUTO_PAUSE_RX 0x2UL #define PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE 0x4UL - u8 unused_0; + u8 mgmt_flag; + #define PORT_PHY_CFG_REQ_MGMT_FLAG_LINK_RELEASE 0x1UL + #define PORT_PHY_CFG_REQ_MGMT_FLAG_MGMT_VALID 0x80UL __le16 auto_link_speed; #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB 0x1UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB 0xaUL @@ -4054,7 +4137,36 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_50G 0x1UL #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_100G 0x2UL #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_200G 0x4UL - u8 unused_2[2]; + __le16 force_link_speeds2; + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_1GB 0xaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_10GB 0x64UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_25GB 0xfaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_40GB 0x190UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB 0x1f4UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB 0x3e8UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_LAST PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 + __le16 auto_link_speeds2_mask; + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_1GB 0x1UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_10GB 0x2UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_25GB 0x4UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_40GB 0x8UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB 0x10UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB 0x20UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB_PAM4_56 0x40UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_56 0x80UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_56 0x100UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_56 0x200UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_112 0x400UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_112 0x800UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_112 0x1000UL + u8 unused_2[6]; }; /* hwrm_port_phy_cfg_output (size:128b/16B) */ @@ -4104,7 +4216,8 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_SFT 0 #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ 0x0UL #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 0x1UL - #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 0x2UL + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK 0xf0UL #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_SFT 4 #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE (0x0UL << 4) @@ -4127,6 +4240,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_200GB 0x7d0UL + #define PORT_PHY_QCFG_RESP_LINK_SPEED_400GB 0xfa0UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_QCFG_RESP_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_LINK_SPEED_10MB u8 duplex_cfg; @@ -4270,7 +4384,23 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2 0x25UL #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2 0x26UL #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2 0x27UL - #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2 + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR 0x28UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR 0x29UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR 0x2aUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER 0x2bUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2 0x2cUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2 0x2dUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2 0x2eUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2 0x2fUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8 0x30UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8 0x31UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8 0x32UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8 0x33UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4 0x34UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4 0x35UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4 0x36UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4 0x37UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4 u8 media_type; #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL @@ -4366,6 +4496,7 @@ struct hwrm_port_phy_qcfg_output { u8 option_flags; #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_MEDIA_AUTO_DETECT 0x1UL #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN 0x2UL + #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SPEEDS2_SUPPORTED 0x4UL char phy_vendor_name[16]; char phy_vendor_partnumber[16]; __le16 support_pam4_speeds; @@ -4387,7 +4518,53 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL u8 link_down_reason; #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL - u8 unused_0[7]; + __le16 support_speeds2; + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_25GB 0x4UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_40GB 0x8UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB 0x10UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB 0x20UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_800GB_PAM4_112 0x2000UL + __le16 force_link_speeds2; + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_1GB 0xaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_10GB 0x64UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_25GB 0xfaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_40GB 0x190UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB 0x1f4UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112 0x1f42UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_LAST PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112 + __le16 auto_link_speeds2; + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_1GB 0x1UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_10GB 0x2UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_25GB 0x4UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_40GB 0x8UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB 0x10UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB 0x20UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_800GB_PAM4_112 0x2000UL + u8 active_lanes; u8 valid; }; @@ -4426,6 +4603,7 @@ struct hwrm_port_mac_cfg_input { #define PORT_MAC_CFG_REQ_ENABLES_COS_FIELD_CFG 0x100UL #define PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB 0x200UL #define PORT_MAC_CFG_REQ_ENABLES_PTP_ADJ_PHASE 0x400UL + #define PORT_MAC_CFG_REQ_ENABLES_PTP_LOAD_CONTROL 0x800UL __le16 port_id; u8 ipg; u8 lpbk; @@ -4459,7 +4637,12 @@ struct hwrm_port_mac_cfg_input { #define PORT_MAC_CFG_REQ_COS_FIELD_CFG_DEFAULT_COS_SFT 5 u8 unused_0[3]; __le32 ptp_freq_adj_ppb; - u8 unused_1[4]; + u8 unused_1[3]; + u8 ptp_load_control; + #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_NONE 0x0UL + #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_IMMEDIATE 0x1UL + #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_PPS_EVENT 0x2UL + #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_LAST PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_PPS_EVENT __le64 ptp_adj_phase; }; @@ -4504,6 +4687,7 @@ struct hwrm_port_mac_ptp_qcfg_output { #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x8UL #define PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK 0x10UL #define PORT_MAC_PTP_QCFG_RESP_FLAGS_RTC_CONFIGURED 0x20UL + #define PORT_MAC_PTP_QCFG_RESP_FLAGS_64B_PHC_TIME 0x40UL u8 unused_0[3]; __le32 rx_ts_reg_off_lower; __le32 rx_ts_reg_off_upper; @@ -4968,7 +5152,7 @@ struct hwrm_port_phy_qcaps_input { u8 unused_0[6]; }; -/* hwrm_port_phy_qcaps_output (size:256b/32B) */ +/* hwrm_port_phy_qcaps_output (size:320b/40B) */ struct hwrm_port_phy_qcaps_output { __le16 error_code; __le16 req_type; @@ -5051,7 +5235,40 @@ struct hwrm_port_phy_qcaps_output { #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL #define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED 0x8UL u8 internal_port_cnt; + u8 unused_0; + __le16 supported_speeds2_force_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_1GB 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_10GB 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_25GB 0x4UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_40GB 0x8UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB 0x10UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB 0x20UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_800GB_PAM4_112 0x2000UL + __le16 supported_speeds2_auto_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_1GB 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_10GB 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_25GB 0x4UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_40GB 0x8UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB 0x10UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB 0x20UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_800GB_PAM4_112 0x2000UL + u8 unused_1[3]; u8 valid; }; @@ -5472,6 +5689,30 @@ struct hwrm_port_led_qcaps_output { u8 valid; }; +/* hwrm_port_mac_qcaps_input (size:192b/24B) */ +struct hwrm_port_mac_qcaps_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le16 port_id; + u8 unused_0[6]; +}; + +/* hwrm_port_mac_qcaps_output (size:128b/16B) */ +struct hwrm_port_mac_qcaps_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 flags; + #define PORT_MAC_QCAPS_RESP_FLAGS_LOCAL_LPBK_NOT_SUPPORTED 0x1UL + #define PORT_MAC_QCAPS_RESP_FLAGS_REMOTE_LPBK_SUPPORTED 0x2UL + u8 unused_0[6]; + u8 valid; +}; + /* hwrm_queue_qportcfg_input (size:192b/24B) */ struct hwrm_queue_qportcfg_input { __le16 req_type; @@ -7488,7 +7729,7 @@ struct hwrm_cfa_ntuple_filter_alloc_input { #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD 0xffUL #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD __le16 dst_id; - __le16 mirror_vnic_id; + __le16 rfs_ring_tbl_idx; u8 tunnel_type; #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_NONTUNNEL 0x0UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN 0x1UL @@ -8201,6 +8442,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output { #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NIC_FLOW_STATS_SUPPORTED 0x80000UL #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED 0x100000UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V3_SUPPORTED 0x200000UL u8 unused_0[3]; u8 valid; }; @@ -8223,7 +8465,8 @@ struct hwrm_tunnel_dst_port_query_input { #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI 0xeUL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_SRV6 0xfUL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL - #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GRE 0x11UL + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GRE u8 tunnel_next_proto; u8 unused_0[6]; }; @@ -8245,7 +8488,10 @@ struct hwrm_tunnel_dst_port_query_output { #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR5 0x20UL #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR6 0x40UL #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR7 0x80UL - u8 unused_0[2]; + u8 status; + #define TUNNEL_DST_PORT_QUERY_RESP_STATUS_CHIP_LEVEL 0x1UL + #define TUNNEL_DST_PORT_QUERY_RESP_STATUS_FUNC_LEVEL 0x2UL + u8 unused_0; u8 valid; }; @@ -8267,7 +8513,8 @@ struct hwrm_tunnel_dst_port_alloc_input { #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI 0xeUL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_SRV6 0xfUL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL - #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GRE 0x11UL + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GRE u8 tunnel_next_proto; __be16 tunnel_dst_port_val; u8 unused_0[4]; @@ -8284,7 +8531,8 @@ struct hwrm_tunnel_dst_port_alloc_output { #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_SUCCESS 0x0UL #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ALLOCATED 0x1UL #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE 0x2UL - #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ENABLED 0x3UL + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ENABLED u8 upar_in_use; #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR0 0x1UL #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR1 0x2UL @@ -8316,7 +8564,8 @@ struct hwrm_tunnel_dst_port_free_input { #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI 0xeUL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_SRV6 0xfUL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL - #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GRE 0x11UL + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GRE u8 tunnel_next_proto; __le16 tunnel_dst_port_id; u8 unused_0[4]; @@ -9717,7 +9966,7 @@ struct hwrm_nvm_get_dev_info_input { __le64 resp_addr; }; -/* hwrm_nvm_get_dev_info_output (size:640b/80B) */ +/* hwrm_nvm_get_dev_info_output (size:704b/88B) */ struct hwrm_nvm_get_dev_info_output { __le16 error_code; __le16 req_type; @@ -9747,6 +9996,10 @@ struct hwrm_nvm_get_dev_info_output { __le16 roce_fw_minor; __le16 roce_fw_build; __le16 roce_fw_patch; + __le16 netctrl_fw_major; + __le16 netctrl_fw_minor; + __le16 netctrl_fw_build; + __le16 netctrl_fw_patch; u8 unused_0[7]; u8 valid; }; From a432a45bdba4387b7c511dbbda11ab84b8e767b7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:12 -0800 Subject: [PATCH 2434/7721] bnxt_en: Define basic P7 macros Repurpose the BNXT_FLAG_CHIP_SR2 flag by renaming it to BNXT_FLAG_CHIP_P7 since the SR2 chip never went to production. The SR2 statictics structure is also renamed for the P7 chip. Define the basic P7 doorbell bits (Epoch. Toggle, etc) and implement the Epoch bit logic. The next higher bit beyond the legal doorbell mask is the Epoch bit used for doorbells on P7 chips. This bit is used by the chip to detect dropped doorbells. The 57608 chip ID belonging to the P7 family is also defined. Note that the PCI ID is not added until the last patch in the series. Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-4-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 21 ++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 40 ++++++++++++++----- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6f37b6ac8996..829b2a6a05a0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -260,6 +260,10 @@ static bool bnxt_vf_pciid(enum board_idx idx) bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ | DB_RING_IDX(db, idx),\ (db)->doorbell) +#define BNXT_DB_NQ_P7(db, idx) \ + bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_MASK | \ + DB_RING_IDX(db, idx), (db)->doorbell) + #define BNXT_DB_CQ_ARM(db, idx) \ writel(DB_CP_REARM_FLAGS | DB_RING_IDX(db, idx), (db)->doorbell) @@ -269,7 +273,9 @@ static bool bnxt_vf_pciid(enum board_idx idx) static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) { - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + if (bp->flags & BNXT_FLAG_CHIP_P7) + BNXT_DB_NQ_P7(db, idx); + else if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) BNXT_DB_NQ_P5(db, idx); else BNXT_DB_CQ(db, idx); @@ -5784,7 +5790,7 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) if (BNXT_CHIP_P5(bp)) bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5; else - bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5_SR2; + bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P7; } } hwrm_req_drop(bp, req); @@ -6015,6 +6021,10 @@ static void bnxt_set_db_mask(struct bnxt *bp, struct bnxt_db_info *db, db->db_ring_mask = bp->cp_ring_mask; break; } + if (bp->flags & BNXT_FLAG_CHIP_P7) { + db->db_epoch_mask = db->db_ring_mask + 1; + db->db_epoch_shift = DBR_EPOCH_SFT - ilog2(db->db_epoch_mask); + } } static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, @@ -6041,6 +6051,9 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, break; } db->db_key64 |= (u64)xid << DBR_XID_SFT; + + if (bp->flags & BNXT_FLAG_CHIP_P7) + db->db_key64 |= DBR_VALID; } else { db->doorbell = bp->bar1 + map_idx * 0x80; switch (ring_type) { @@ -14014,8 +14027,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (BNXT_CHIP_P5_PLUS(bp)) { bp->flags |= BNXT_FLAG_CHIP_P5_PLUS; - if (BNXT_CHIP_SR2(bp)) - bp->flags |= BNXT_FLAG_CHIP_SR2; + if (BNXT_CHIP_P7(bp)) + bp->flags |= BNXT_FLAG_CHIP_P7; } rc = bnxt_alloc_rss_indir_tbl(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 8a22b2d7ea94..40b26f7a0f5e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -541,6 +541,8 @@ struct nqe_cn { #define NQ_CN_TYPE_SFT 0 #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION + #define NQ_CN_TOGGLE_MASK 0xc0UL + #define NQ_CN_TOGGLE_SFT 6 __le16 reserved16; __le32 cq_handle_low; __le32 v; @@ -561,6 +563,10 @@ struct nqe_cn { #define BNXT_SET_NQ_HDL(cpr) \ (((cpr)->cp_ring_type << BNXT_NQ_HDL_TYPE_SHIFT) | (cpr)->cp_idx) +#define NQE_CN_TYPE(type) ((type) & NQ_CN_TYPE_MASK) +#define NQE_CN_TOGGLE(type) (((type) & NQ_CN_TOGGLE_MASK) >> \ + NQ_CN_TOGGLE_SFT) + #define DB_IDX_MASK 0xffffff #define DB_IDX_VALID (0x1 << 26) #define DB_IRQ_DIS (0x1 << 27) @@ -576,9 +582,14 @@ struct nqe_cn { /* 64-bit doorbell */ #define DBR_INDEX_MASK 0x0000000000ffffffULL +#define DBR_EPOCH_MASK 0x01000000UL +#define DBR_EPOCH_SFT 24 +#define DBR_TOGGLE_MASK 0x06000000UL +#define DBR_TOGGLE_SFT 25 #define DBR_XID_MASK 0x000fffff00000000ULL #define DBR_XID_SFT 32 #define DBR_PATH_L2 (0x1ULL << 56) +#define DBR_VALID (0x1ULL << 58) #define DBR_TYPE_SQ (0x0ULL << 60) #define DBR_TYPE_RQ (0x1ULL << 60) #define DBR_TYPE_SRQ (0x2ULL << 60) @@ -591,6 +602,7 @@ struct nqe_cn { #define DBR_TYPE_CQ_CUTOFF_ACK (0x9ULL << 60) #define DBR_TYPE_NQ (0xaULL << 60) #define DBR_TYPE_NQ_ARM (0xbULL << 60) +#define DBR_TYPE_NQ_MASK (0xeULL << 60) #define DBR_TYPE_NULL (0xfULL << 60) #define DB_PF_OFFSET_P5 0x10000 @@ -819,9 +831,17 @@ struct bnxt_db_info { u32 db_key32; }; u32 db_ring_mask; + u32 db_epoch_mask; + u8 db_epoch_shift; }; -#define DB_RING_IDX(db, idx) ((idx) & (db)->db_ring_mask) +#define DB_EPOCH(db, idx) (((idx) & (db)->db_epoch_mask) << \ + ((db)->db_epoch_shift)) + +#define DB_TOGGLE(tgl) ((tgl) << DBR_TOGGLE_SFT) + +#define DB_RING_IDX(db, idx) (((idx) & (db)->db_ring_mask) | \ + DB_EPOCH(db, idx)) struct bnxt_tx_ring_info { struct bnxt_napi *bnapi; @@ -1803,14 +1823,14 @@ struct bnxt { #define CHIP_NUM_57504 0x1751 #define CHIP_NUM_57502 0x1752 +#define CHIP_NUM_57608 0x1760 + #define CHIP_NUM_58802 0xd802 #define CHIP_NUM_58804 0xd804 #define CHIP_NUM_58808 0xd808 u8 chip_rev; -#define CHIP_NUM_58818 0xd818 - #define BNXT_CHIP_NUM_5730X(chip_num) \ ((chip_num) >= CHIP_NUM_57301 && \ (chip_num) <= CHIP_NUM_57304) @@ -1888,7 +1908,7 @@ struct bnxt { BNXT_FLAG_ROCEV2_CAP) #define BNXT_FLAG_NO_AGG_RINGS 0x20000 #define BNXT_FLAG_RX_PAGE_MODE 0x40000 - #define BNXT_FLAG_CHIP_SR2 0x80000 + #define BNXT_FLAG_CHIP_P7 0x80000 #define BNXT_FLAG_MULTI_HOST 0x100000 #define BNXT_FLAG_DSN_VALID 0x200000 #define BNXT_FLAG_DOUBLE_DB 0x400000 @@ -1918,8 +1938,8 @@ struct bnxt { (bp)->max_tpa_v2) && !is_kdump_kernel()) #define BNXT_RX_JUMBO_MODE(bp) ((bp)->flags & BNXT_FLAG_JUMBO) -#define BNXT_CHIP_SR2(bp) \ - ((bp)->chip_num == CHIP_NUM_58818) +#define BNXT_CHIP_P7(bp) \ + ((bp)->chip_num == CHIP_NUM_57608) #define BNXT_CHIP_P5(bp) \ ((bp)->chip_num == CHIP_NUM_57508 || \ @@ -1928,7 +1948,7 @@ struct bnxt { /* Chip class phase 5 */ #define BNXT_CHIP_P5_PLUS(bp) \ - (BNXT_CHIP_P5(bp) || BNXT_CHIP_SR2(bp)) + (BNXT_CHIP_P5(bp) || BNXT_CHIP_P7(bp)) /* Chip class phase 4.x */ #define BNXT_CHIP_P4(bp) \ @@ -2272,15 +2292,15 @@ struct bnxt { #define BNXT_NUM_TX_RING_STATS 8 #define BNXT_NUM_TPA_RING_STATS 4 #define BNXT_NUM_TPA_RING_STATS_P5 5 -#define BNXT_NUM_TPA_RING_STATS_P5_SR2 6 +#define BNXT_NUM_TPA_RING_STATS_P7 6 #define BNXT_RING_STATS_SIZE_P5 \ ((BNXT_NUM_RX_RING_STATS + BNXT_NUM_TX_RING_STATS + \ BNXT_NUM_TPA_RING_STATS_P5) * 8) -#define BNXT_RING_STATS_SIZE_P5_SR2 \ +#define BNXT_RING_STATS_SIZE_P7 \ ((BNXT_NUM_RX_RING_STATS + BNXT_NUM_TX_RING_STATS + \ - BNXT_NUM_TPA_RING_STATS_P5_SR2) * 8) + BNXT_NUM_TPA_RING_STATS_P7) * 8) #define BNXT_GET_RING_STATS64(sw, counter) \ (*((sw) + offsetof(struct ctx_hw_stats, counter) / 8)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index b0cea5b600cc..99c8b15bdfbe 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -513,7 +513,7 @@ static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) if (bp->max_tpa_v2) { if (BNXT_CHIP_P5(bp)) return BNXT_NUM_TPA_RING_STATS_P5; - return BNXT_NUM_TPA_RING_STATS_P5_SR2; + return BNXT_NUM_TPA_RING_STATS_P7; } return BNXT_NUM_TPA_RING_STATS; } From d3c16475dc06641a52251bc9948c1d3002ea4388 Mon Sep 17 00:00:00 2001 From: Hongguang Gao Date: Fri, 1 Dec 2023 14:39:13 -0800 Subject: [PATCH 2435/7721] bnxt_en: Consolidate DB offset calculation The doorbell offset on P5 chips is hard coded. On the new P7 chips, it is returned by the firmware. Simplify the logic that determines this offset and store it in a new db_offset field in struct bnxt. Also, provide this offset to the RoCE driver in struct bnxt_en_dev. Reviewed-by: Kalesh AP Signed-off-by: Hongguang Gao Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-5-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 +++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 10 ++++------ drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 4 ++++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 829b2a6a05a0..a17de1aceff4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6031,10 +6031,6 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, u32 map_idx, u32 xid) { if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - if (BNXT_PF(bp)) - db->doorbell = bp->bar1 + DB_PF_OFFSET_P5; - else - db->doorbell = bp->bar1 + DB_VF_OFFSET_P5; switch (ring_type) { case HWRM_RING_ALLOC_TX: db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SQ; @@ -6054,6 +6050,8 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, if (bp->flags & BNXT_FLAG_CHIP_P7) db->db_key64 |= DBR_VALID; + + db->doorbell = bp->bar1 + bp->db_offset; } else { db->doorbell = bp->bar1 + map_idx * 0x80; switch (ring_type) { @@ -7146,7 +7144,6 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) { struct hwrm_func_qcfg_output *resp; struct hwrm_func_qcfg_input *req; - u32 min_db_offset = 0; u16 flags; int rc; @@ -7204,16 +7201,17 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) if (bp->db_size) goto func_qcfg_exit; - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { + bp->db_offset = le16_to_cpu(resp->legacy_l2_db_size_kb) * 1024; + if (BNXT_CHIP_P5(bp)) { if (BNXT_PF(bp)) - min_db_offset = DB_PF_OFFSET_P5; + bp->db_offset = DB_PF_OFFSET_P5; else - min_db_offset = DB_VF_OFFSET_P5; + bp->db_offset = DB_VF_OFFSET_P5; } bp->db_size = PAGE_ALIGN(le16_to_cpu(resp->l2_doorbell_bar_size_kb) * 1024); if (!bp->db_size || bp->db_size > pci_resource_len(bp->pdev, 2) || - bp->db_size <= min_db_offset) + bp->db_size <= bp->db_offset) bp->db_size = pci_resource_len(bp->pdev, 2); func_qcfg_exit: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 40b26f7a0f5e..6d96f66dc8c0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2216,6 +2216,7 @@ struct bnxt { /* ensure atomic 64-bit doorbell writes on 32-bit systems. */ spinlock_t db_lock; #endif + int db_offset; /* db_offset within db_size */ int db_size; #define BNXT_NTP_FLTR_MAX_FLTR 4096 diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index e89731492f5e..93f9bd55020f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -42,13 +42,10 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent) for (i = 0; i < num_msix; i++) { ent[i].vector = bp->irq_tbl[idx + i].vector; ent[i].ring_idx = idx + i; - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - ent[i].db_offset = DB_PF_OFFSET_P5; - if (BNXT_VF(bp)) - ent[i].db_offset = DB_VF_OFFSET_P5; - } else { + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + ent[i].db_offset = bp->db_offset; + else ent[i].db_offset = (idx + i) * 0x80; - } } } @@ -333,6 +330,7 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) edev->pdev = bp->pdev; edev->l2_db_size = bp->db_size; edev->l2_db_size_nc = bp->db_size; + edev->l2_db_offset = bp->db_offset; if (bp->flags & BNXT_FLAG_ROCEV1_CAP) edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index 6ff77f082e6c..b9e73de14b57 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -73,6 +73,10 @@ struct bnxt_en_dev { * bytes mapped as non- * cacheable. */ + int l2_db_offset; /* Doorbell offset in + * bytes within + * l2_db_size_nc. + */ u16 chip_num; u16 hw_ring_stats_size; u16 pf_port_id; From d846992e6387fa1f2142952fe94a4bff5ee61d30 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:14 -0800 Subject: [PATCH 2436/7721] bnxt_en: Implement the new toggle bit doorbell mechanism on P7 chips The new chip family passes the Toggle bits to the driver in the NQE notification. The driver now stores this value and sends it back to hardware when it re-arms the RX and TX CQs. Together with the earlier patch that guarantees the driver will only re-arm the CQ at the end of NAPI polling if it has seen a new NQE, this method allows the hardware to detect any dropped doorbells. Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-6-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 17 +++++++++++++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a17de1aceff4..d4da55e01b2c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2880,13 +2880,18 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, struct bnxt_db_info *db; if (cpr2->had_work_done) { + u32 tgl = 0; + + if (dbr_type == DBR_TYPE_CQ_ARMALL) { + cpr2->had_nqe_notify = 0; + tgl = cpr2->toggle; + } db = &cpr2->cp_db; - bnxt_writeq(bp, db->db_key64 | dbr_type | + bnxt_writeq(bp, + db->db_key64 | dbr_type | DB_TOGGLE(tgl) | DB_RING_IDX(db, cpr2->cp_raw_cons), db->doorbell); cpr2->had_work_done = 0; - if (dbr_type == DBR_TYPE_CQ_ARMALL) - cpr2->had_nqe_notify = 0; } } __bnxt_poll_work_done(bp, bnapi, budget); @@ -2912,6 +2917,8 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) work_done = __bnxt_poll_cqs(bp, bnapi, budget); } while (1) { + u16 type; + cons = RING_CMP(raw_cons); nqcmp = &cpr->nq_desc_ring[CP_RING(cons)][CP_IDX(cons)]; @@ -2933,7 +2940,8 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) */ dma_rmb(); - if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) { + type = le16_to_cpu(nqcmp->type); + if (NQE_CN_TYPE(type) == NQ_CN_TYPE_CQ_NOTIFICATION) { u32 idx = le32_to_cpu(nqcmp->cq_handle_low); u32 cq_type = BNXT_NQ_HDL_TYPE(idx); struct bnxt_cp_ring_info *cpr2; @@ -2946,6 +2954,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) idx = BNXT_NQ_HDL_IDX(idx); cpr2 = &cpr->cp_ring_arr[idx]; cpr2->had_nqe_notify = 1; + cpr2->toggle = NQE_CN_TOGGLE(type); work_done += __bnxt_poll_work(bp, cpr2, budget - work_done); cpr->has_more_work |= cpr2->has_more_work; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 6d96f66dc8c0..79b4deb45cfb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1038,6 +1038,7 @@ struct bnxt_cp_ring_info { u8 had_work_done:1; u8 has_more_work:1; u8 had_nqe_notify:1; + u8 toggle; u8 cp_ring_type; u8 cp_idx; From 8243345bfaec1cdcfd34f83700a19aa241685398 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 1 Dec 2023 14:39:15 -0800 Subject: [PATCH 2437/7721] bnxt_en: Refactor RSS capability fields Add a new rss_cap field in the per device struct bnxt and move all the RSS capability fields there. It will be easier to add new RSS capabilities for the new P7 chips. Signed-off-by: Ajit Khaparde Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-7-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 25 ++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 7 +++--- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 ++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d4da55e01b2c..b38c17a27903 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4268,7 +4268,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp) goto out; } vnic_skip_grps: - if ((bp->flags & BNXT_FLAG_NEW_RSS_CAP) && + if ((bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && !(vnic->flags & BNXT_VNIC_RSS_FLAG)) continue; @@ -5765,7 +5765,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) int rc; bp->hw_ring_stats_size = sizeof(struct ctx_hw_stats); - bp->flags &= ~(BNXT_FLAG_NEW_RSS_CAP | BNXT_FLAG_ROCE_MIRROR_CAP); + bp->flags &= ~BNXT_FLAG_ROCE_MIRROR_CAP; + bp->rss_cap &= ~BNXT_RSS_CAP_NEW_RSS_CAP; if (bp->hwrm_spec_code < 0x10600) return 0; @@ -5780,7 +5781,7 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP)) - bp->flags |= BNXT_FLAG_NEW_RSS_CAP; + bp->rss_cap |= BNXT_RSS_CAP_NEW_RSS_CAP; if (flags & VNIC_QCAPS_RESP_FLAGS_ROCE_MIRRORING_CAPABLE_VNIC_CAP) bp->flags |= BNXT_FLAG_ROCE_MIRROR_CAP; @@ -5793,7 +5794,7 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) !(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED))) bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP; if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_HASH_TYPE_DELTA_CAP) - bp->fw_cap |= BNXT_FW_CAP_RSS_HASH_TYPE_DELTA; + bp->rss_cap |= BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA; bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); if (bp->max_tpa_v2) { if (BNXT_CHIP_P5(bp)) @@ -6456,7 +6457,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, req->num_cmpl_rings = cpu_to_le16(cp_rings); req->num_hw_ring_grps = cpu_to_le16(ring_grps); req->num_rsscos_ctxs = cpu_to_le16(1); - if (!(bp->flags & BNXT_FLAG_NEW_RSS_CAP) && + if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && bnxt_rfs_supported(bp)) req->num_rsscos_ctxs = cpu_to_le16(ring_grps + 1); @@ -9133,7 +9134,7 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) vnic = &bp->vnic_info[vnic_id]; vnic->flags |= BNXT_VNIC_RFS_FLAG; - if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) + if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) vnic->flags |= BNXT_VNIC_RFS_NEW_RSS_FLAG; rc = bnxt_hwrm_vnic_alloc(bp, vnic_id, ring_id, 1); if (rc) { @@ -9227,7 +9228,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) rc = bnxt_setup_vnic(bp, 0); if (rc) goto err_out; - if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) + if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA) bnxt_hwrm_update_rss_hash_cfg(bp); if (bp->flags & BNXT_FLAG_RFS) { @@ -11555,7 +11556,7 @@ static bool bnxt_rfs_supported(struct bnxt *bp) return false; if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp)) return true; - if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) + if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) return true; return false; } @@ -11576,7 +11577,7 @@ static bool bnxt_rfs_capable(struct bnxt *bp) max_rss_ctxs = bnxt_get_max_func_rss_ctxs(bp); /* RSS contexts not a limiting factor */ - if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) + if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) max_rss_ctxs = max_vnics; if (vnics > max_vnics || vnics > max_rss_ctxs) { if (bp->rx_nr_rings > 1) @@ -12697,15 +12698,15 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp) static void bnxt_set_dflt_rss_hash_type(struct bnxt *bp) { - bp->flags &= ~BNXT_FLAG_UDP_RSS_CAP; + bp->rss_cap &= ~BNXT_RSS_CAP_UDP_RSS_CAP; bp->rss_hash_cfg = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; - if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) + if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA) bp->rss_hash_delta = bp->rss_hash_cfg; if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { - bp->flags |= BNXT_FLAG_UDP_RSS_CAP; + bp->rss_cap |= BNXT_RSS_CAP_UDP_RSS_CAP; bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 79b4deb45cfb..d10811f4073b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1900,8 +1900,6 @@ struct bnxt { #define BNXT_FLAG_RFS 0x100 #define BNXT_FLAG_SHARED_RINGS 0x200 #define BNXT_FLAG_PORT_STATS 0x400 - #define BNXT_FLAG_UDP_RSS_CAP 0x800 - #define BNXT_FLAG_NEW_RSS_CAP 0x2000 #define BNXT_FLAG_WOL_CAP 0x4000 #define BNXT_FLAG_ROCEV1_CAP 0x8000 #define BNXT_FLAG_ROCEV2_CAP 0x10000 @@ -2021,6 +2019,10 @@ struct bnxt { u16 rss_indir_tbl_entries; u32 rss_hash_cfg; u32 rss_hash_delta; + u32 rss_cap; +#define BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA BIT(0) +#define BNXT_RSS_CAP_UDP_RSS_CAP BIT(1) +#define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2) u16 max_mtu; u8 max_tc; @@ -2086,7 +2088,6 @@ struct bnxt { #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 BIT_ULL(16) #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED BIT_ULL(17) #define BNXT_FW_CAP_EXT_STATS_SUPPORTED BIT_ULL(18) - #define BNXT_FW_CAP_RSS_HASH_TYPE_DELTA BIT_ULL(19) #define BNXT_FW_CAP_ERR_RECOVER_RELOAD BIT_ULL(20) #define BNXT_FW_CAP_HOT_RESET BIT_ULL(21) #define BNXT_FW_CAP_PTP_RTC BIT_ULL(22) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 99c8b15bdfbe..14cb0512ee93 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1203,7 +1203,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (tuple == 4) rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; } else if (cmd->flow_type == UDP_V4_FLOW) { - if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) + if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP)) return -EINVAL; rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; if (tuple == 4) @@ -1213,7 +1213,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (tuple == 4) rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; } else if (cmd->flow_type == UDP_V6_FLOW) { - if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) + if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP)) return -EINVAL; rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; if (tuple == 4) @@ -1253,7 +1253,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (bp->rss_hash_cfg == rss_hash_cfg) return 0; - if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) + if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA) bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg; bp->rss_hash_cfg = rss_hash_cfg; if (netif_running(bp->dev)) { From 13d2d3d381ee9844f89bd436ab0f44204660027e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:16 -0800 Subject: [PATCH 2438/7721] bnxt_en: Add new P7 hardware interface definitions Add new RX, TX, and TPA hardware interface structures and macros for the P7 chips. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-8-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 85 ++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d10811f4073b..ba9caae923f2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -139,11 +139,15 @@ struct tx_cmp { __le32 tx_cmp_flags_type; #define CMP_TYPE (0x3f << 0) #define CMP_TYPE_TX_L2_CMP 0 + #define CMP_TYPE_TX_L2_COAL_CMP 2 + #define CMP_TYPE_TX_L2_PKT_TS_CMP 4 #define CMP_TYPE_RX_L2_CMP 17 #define CMP_TYPE_RX_AGG_CMP 18 #define CMP_TYPE_RX_L2_TPA_START_CMP 19 #define CMP_TYPE_RX_L2_TPA_END_CMP 21 #define CMP_TYPE_RX_TPA_AGG_CMP 22 + #define CMP_TYPE_RX_L2_V3_CMP 23 + #define CMP_TYPE_RX_L2_TPA_START_V3_CMP 25 #define CMP_TYPE_STATUS_CMP 32 #define CMP_TYPE_REMOTE_DRIVER_REQ 34 #define CMP_TYPE_REMOTE_DRIVER_RESP 36 @@ -170,9 +174,13 @@ struct tx_cmp { #define TX_CMP_ERRORS_DMA_ERROR (1 << 6) #define TX_CMP_ERRORS_HINT_TOO_SHORT (1 << 7) - __le32 tx_cmp_unsed_3; + __le32 sq_cons_idx; + #define TX_CMP_SQ_CONS_IDX_MASK 0x00ffffff }; +#define TX_CMP_SQ_CONS_IDX(txcmp) \ + (le32_to_cpu((txcmp)->sq_cons_idx) & TX_CMP_SQ_CONS_IDX_MASK) + struct rx_cmp { __le32 rx_cmp_len_flags_type; #define RX_CMP_CMP_TYPE (0x3f << 0) @@ -200,8 +208,20 @@ struct rx_cmp { #define RX_CMP_AGG_BUFS_SHIFT 1 #define RX_CMP_RSS_HASH_TYPE (0x7f << 9) #define RX_CMP_RSS_HASH_TYPE_SHIFT 9 + #define RX_CMP_V3_RSS_EXT_OP_LEGACY (0xf << 12) + #define RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT 12 + #define RX_CMP_V3_RSS_EXT_OP_NEW (0xf << 8) + #define RX_CMP_V3_RSS_EXT_OP_NEW_SHIFT 8 #define RX_CMP_PAYLOAD_OFFSET (0xff << 16) #define RX_CMP_PAYLOAD_OFFSET_SHIFT 16 + #define RX_CMP_SUB_NS_TS (0xf << 16) + #define RX_CMP_SUB_NS_TS_SHIFT 16 + #define RX_CMP_METADATA1 (0xf << 28) + #define RX_CMP_METADATA1_SHIFT 28 + #define RX_CMP_METADATA1_TPID_SEL (0x7 << 28) + #define RX_CMP_METADATA1_TPID_8021Q (0x1 << 28) + #define RX_CMP_METADATA1_TPID_8021AD (0x0 << 28) + #define RX_CMP_METADATA1_VALID (0x8 << 28) __le32 rx_cmp_rss_hash; }; @@ -215,6 +235,30 @@ struct rx_cmp { (((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\ RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) +#define RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp) \ + ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_LEGACY) >>\ + RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT) + +#define RX_CMP_V3_HASH_TYPE_NEW(rxcmp) \ + ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_NEW) >>\ + RX_CMP_V3_RSS_EXT_OP_NEW_SHIFT) + +#define RX_CMP_V3_HASH_TYPE(bp, rxcmp) \ + (((bp)->rss_cap & BNXT_RSS_CAP_RSS_TCAM) ? \ + RX_CMP_V3_HASH_TYPE_NEW(rxcmp) : \ + RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp)) + +#define EXT_OP_INNER_4 0x0 +#define EXT_OP_OUTER_4 0x2 +#define EXT_OP_INNFL_3 0x8 +#define EXT_OP_OUTFL_3 0xa + +#define RX_CMP_VLAN_VALID(rxcmp) \ + ((rxcmp)->rx_cmp_misc_v1 & cpu_to_le32(RX_CMP_METADATA1_VALID)) + +#define RX_CMP_VLAN_TPID_SEL(rxcmp) \ + (le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_METADATA1_TPID_SEL) + struct rx_cmp_ext { __le32 rx_cmp_flags2; #define RX_CMP_FLAGS2_IP_CS_CALC 0x1 @@ -262,6 +306,9 @@ struct rx_cmp_ext { #define RX_CMPL_CFA_CODE_MASK (0xffff << 16) #define RX_CMPL_CFA_CODE_SFT 16 + #define RX_CMPL_METADATA0_TCI_MASK (0xffff << 16) + #define RX_CMPL_METADATA0_VID_MASK (0x0fff << 16) + #define RX_CMPL_METADATA0_SFT 16 __le32 rx_cmp_timestamp; }; @@ -287,6 +334,10 @@ struct rx_cmp_ext { ((le32_to_cpu((rxcmpl1)->rx_cmp_cfa_code_errors_v2) & \ RX_CMPL_CFA_CODE_MASK) >> RX_CMPL_CFA_CODE_SFT) +#define RX_CMP_METADATA0_TCI(rxcmp1) \ + ((le32_to_cpu((rxcmp1)->rx_cmp_cfa_code_errors_v2) & \ + RX_CMPL_METADATA0_TCI_MASK) >> RX_CMPL_METADATA0_SFT) + struct rx_agg_cmp { __le32 rx_agg_cmp_len_flags_type; #define RX_AGG_CMP_TYPE (0x3f << 0) @@ -329,10 +380,18 @@ struct rx_tpa_start_cmp { #define RX_TPA_START_CMP_V1 (0x1 << 0) #define RX_TPA_START_CMP_RSS_HASH_TYPE (0x7f << 9) #define RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT 9 + #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE (0x1ff << 7) + #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT 7 #define RX_TPA_START_CMP_AGG_ID (0x7f << 25) #define RX_TPA_START_CMP_AGG_ID_SHIFT 25 #define RX_TPA_START_CMP_AGG_ID_P5 (0xffff << 16) #define RX_TPA_START_CMP_AGG_ID_SHIFT_P5 16 + #define RX_TPA_START_CMP_METADATA1 (0xf << 28) + #define RX_TPA_START_CMP_METADATA1_SHIFT 28 + #define RX_TPA_START_METADATA1_TPID_SEL (0x7 << 28) + #define RX_TPA_START_METADATA1_TPID_8021Q (0x1 << 28) + #define RX_TPA_START_METADATA1_TPID_8021AD (0x0 << 28) + #define RX_TPA_START_METADATA1_VALID (0x8 << 28) __le32 rx_tpa_start_cmp_rss_hash; }; @@ -346,6 +405,11 @@ struct rx_tpa_start_cmp { RX_TPA_START_CMP_RSS_HASH_TYPE) >> \ RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) +#define TPA_START_V3_HASH_TYPE(rx_tpa_start) \ + (((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ + RX_TPA_START_CMP_V3_RSS_HASH_TYPE) >> \ + RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) + #define TPA_START_AGG_ID(rx_tpa_start) \ ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ RX_TPA_START_CMP_AGG_ID) >> RX_TPA_START_CMP_AGG_ID_SHIFT) @@ -358,6 +422,14 @@ struct rx_tpa_start_cmp { ((rx_tpa_start)->rx_tpa_start_cmp_len_flags_type & \ cpu_to_le32(RX_TPA_START_CMP_FLAGS_ERROR)) +#define TPA_START_VLAN_VALID(rx_tpa_start) \ + ((rx_tpa_start)->rx_tpa_start_cmp_misc_v1 & \ + cpu_to_le32(RX_TPA_START_METADATA1_VALID)) + +#define TPA_START_VLAN_TPID_SEL(rx_tpa_start) \ + (le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ + RX_TPA_START_METADATA1_TPID_SEL) + struct rx_tpa_start_cmp_ext { __le32 rx_tpa_start_cmp_flags2; #define RX_TPA_START_CMP_FLAGS2_IP_CS_CALC (0x1 << 0) @@ -368,6 +440,8 @@ struct rx_tpa_start_cmp_ext { #define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL_VALID (0x1 << 9) #define RX_TPA_START_CMP_FLAGS2_EXT_META_FORMAT (0x3 << 10) #define RX_TPA_START_CMP_FLAGS2_EXT_META_FORMAT_SHIFT 10 + #define RX_TPA_START_CMP_V3_FLAGS2_T_IP_TYPE (0x1 << 10) + #define RX_TPA_START_CMP_V3_FLAGS2_AGG_GRO (0x1 << 11) #define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL (0xffff << 16) #define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL_SHIFT 16 @@ -381,6 +455,9 @@ struct rx_tpa_start_cmp_ext { #define RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_FLUSH (0x5 << 1) #define RX_TPA_START_CMP_CFA_CODE (0xffff << 16) #define RX_TPA_START_CMPL_CFA_CODE_SHIFT 16 + #define RX_TPA_START_CMP_METADATA0_TCI_MASK (0xffff << 16) + #define RX_TPA_START_CMP_METADATA0_VID_MASK (0x0fff << 16) + #define RX_TPA_START_CMP_METADATA0_SFT 16 __le32 rx_tpa_start_cmp_hdr_info; }; @@ -397,6 +474,11 @@ struct rx_tpa_start_cmp_ext { RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_MASK) >> \ RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_SHIFT) +#define TPA_START_METADATA0_TCI(rx_tpa_start) \ + ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_cfa_code_v2) & \ + RX_TPA_START_CMP_METADATA0_TCI_MASK) >> \ + RX_TPA_START_CMP_METADATA0_SFT) + struct rx_tpa_end_cmp { __le32 rx_tpa_end_cmp_len_flags_type; #define RX_TPA_END_CMP_TYPE (0x3f << 0) @@ -2023,6 +2105,7 @@ struct bnxt { #define BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA BIT(0) #define BNXT_RSS_CAP_UDP_RSS_CAP BIT(1) #define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2) +#define BNXT_RSS_CAP_RSS_TCAM BIT(3) u16 max_mtu; u8 max_tc; From c2f8063309da9be81679e27cabd4a9dbf9be43cc Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:17 -0800 Subject: [PATCH 2439/7721] bnxt_en: Refactor RX VLAN acceleration logic. Refactor the logic in the RX path that checks for the accelerated VLAN tag by adding a new function. This will make it easier to support the new receive logic on P7 chips. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-9-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 ++++++++++++++++------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b38c17a27903..9aca38b6f196 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1783,6 +1783,34 @@ static void bnxt_deliver_skb(struct bnxt *bp, struct bnxt_napi *bnapi, napi_gro_receive(&bnapi->napi, skb); } +static struct sk_buff *bnxt_rx_vlan(struct sk_buff *skb, u8 cmp_type, + struct rx_cmp *rxcmp, + struct rx_cmp_ext *rxcmp1) +{ + __be16 vlan_proto; + u16 vtag; + + if (cmp_type == CMP_TYPE_RX_L2_CMP) { + __le32 flags2 = rxcmp1->rx_cmp_flags2; + u32 meta_data; + + if (!(flags2 & cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN))) + return skb; + + meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data); + vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK; + vlan_proto = htons(meta_data >> RX_CMP_FLAGS2_METADATA_TPID_SFT); + if (eth_type_vlan(vlan_proto)) + __vlan_hwaccel_put_tag(skb, vlan_proto, vtag); + else + goto vlan_err; + } + return skb; +vlan_err: + dev_kfree_skb(skb); + return NULL; +} + /* returns the following: * 1 - 1 packet successfully received * 0 - successful TPA_START, packet not completed yet @@ -2001,20 +2029,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, cfa_code = RX_CMP_CFA_CODE(rxcmp1); skb->protocol = eth_type_trans(skb, bnxt_get_pkt_dev(bp, cfa_code)); - if ((rxcmp1->rx_cmp_flags2 & - cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN)) && - (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) { - u32 meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data); - u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK; - __be16 vlan_proto = htons(meta_data >> - RX_CMP_FLAGS2_METADATA_TPID_SFT); - - if (eth_type_vlan(vlan_proto)) { - __vlan_hwaccel_put_tag(skb, vlan_proto, vtag); - } else { - dev_kfree_skb(skb); + if (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX) { + skb = bnxt_rx_vlan(skb, cmp_type, rxcmp, rxcmp1); + if (!skb) goto next_rx; - } } skb_checksum_none_assert(skb); From 39b2e62be3704d358c2c82eb326ae4b82a23ce1a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:18 -0800 Subject: [PATCH 2440/7721] bnxt_en: Refactor and refine bnxt_tpa_start() and bnxt_tpa_end(). Refactor bnxt_tpa_start() by adding bnxt_tpa_metadata() to gather the metadata from the TPA_START completion. This makes it easier to support the new P7 chip which has a modified TPA_START completion structure with different metadata formats. We also add vlan_valid and cfa_code_valid fields to the bnxt_tpa_info structure so that the VLAN and VF rep logic can be common for all chips. The VLAN metadata is now collected in bnxt_tpa_start() only when it is valid and the vlan_valid field will be set. bnxt_tpa_end() can now use common VLAN logic for all chips. Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-10-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 35 ++++++++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9aca38b6f196..be016a2a9aac 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1315,8 +1315,22 @@ static u16 bnxt_lookup_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id) return map->agg_id_tbl[agg_id]; } +static void bnxt_tpa_metadata(struct bnxt_tpa_info *tpa_info, + struct rx_tpa_start_cmp *tpa_start, + struct rx_tpa_start_cmp_ext *tpa_start1) +{ + tpa_info->cfa_code_valid = 1; + tpa_info->cfa_code = TPA_START_CFA_CODE(tpa_start1); + tpa_info->vlan_valid = 0; + if (tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) { + tpa_info->vlan_valid = 1; + tpa_info->metadata = + le32_to_cpu(tpa_start1->rx_tpa_start_cmp_metadata); + } +} + static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, - struct rx_tpa_start_cmp *tpa_start, + u8 cmp_type, struct rx_tpa_start_cmp *tpa_start, struct rx_tpa_start_cmp_ext *tpa_start1) { struct bnxt_sw_rx_bd *cons_rx_buf, *prod_rx_buf; @@ -1345,10 +1359,6 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, bnxt_sched_reset_rxr(bp, rxr); return; } - /* Store cfa_code in tpa_info to use in tpa_end - * completion processing. - */ - tpa_info->cfa_code = TPA_START_CFA_CODE(tpa_start1); prod_rx_buf->data = tpa_info->data; prod_rx_buf->data_ptr = tpa_info->data_ptr; @@ -1383,8 +1393,8 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, netif_warn(bp, rx_err, bp->dev, "TPA packet without valid hash\n"); } tpa_info->flags2 = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_flags2); - tpa_info->metadata = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_metadata); tpa_info->hdr_info = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_hdr_info); + bnxt_tpa_metadata(tpa_info, tpa_start, tpa_start1); tpa_info->agg_count = 0; rxr->rx_prod = NEXT_RX(prod); @@ -1619,6 +1629,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, { struct bnxt_napi *bnapi = cpr->bnapi; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; + struct net_device *dev = bp->dev; u8 *data_ptr, agg_bufs; unsigned int len; struct bnxt_tpa_info *tpa_info; @@ -1725,14 +1736,15 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, } } - skb->protocol = - eth_type_trans(skb, bnxt_get_pkt_dev(bp, tpa_info->cfa_code)); + if (tpa_info->cfa_code_valid) + dev = bnxt_get_pkt_dev(bp, tpa_info->cfa_code); + skb->protocol = eth_type_trans(skb, dev); if (tpa_info->hash_type != PKT_HASH_TYPE_NONE) skb_set_hash(skb, tpa_info->rss_hash, tpa_info->hash_type); - if ((tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) && - (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) { + if (tpa_info->vlan_valid && + (dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) { __be16 vlan_proto = htons(tpa_info->metadata >> RX_CMP_FLAGS2_METADATA_TPID_SFT); u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_TCI_MASK; @@ -1864,7 +1876,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, prod = rxr->rx_prod; if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) { - bnxt_tpa_start(bp, rxr, (struct rx_tpa_start_cmp *)rxcmp, + bnxt_tpa_start(bp, rxr, cmp_type, + (struct rx_tpa_start_cmp *)rxcmp, (struct rx_tpa_start_cmp_ext *)rxcmp1); *event |= BNXT_RX_EVENT; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index ba9caae923f2..57694eb7feeb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1027,6 +1027,8 @@ struct bnxt_tpa_info { u16 cfa_code; /* cfa_code in TPA start compl */ u8 agg_count; + u8 vlan_valid:1; + u8 cfa_code_valid:1; struct rx_agg_cmp *agg_arr; }; From a7445d69809fe33619c451a8bf68d6b9cf335909 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:19 -0800 Subject: [PATCH 2441/7721] bnxt_en: Add support for new RX and TPA_START completion types for P7 These new completion types are supported on the new P7 chips. These new types have commonalities with the legacy types. After the refactoring, we mainly have to add new functions to handle the the new meta data formats and the RX hash information in the new types. Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-11-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 109 ++++++++++++++---- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 +- 2 files changed, 89 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index be016a2a9aac..3b0ced2a5f32 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1329,6 +1329,23 @@ static void bnxt_tpa_metadata(struct bnxt_tpa_info *tpa_info, } } +static void bnxt_tpa_metadata_v2(struct bnxt_tpa_info *tpa_info, + struct rx_tpa_start_cmp *tpa_start, + struct rx_tpa_start_cmp_ext *tpa_start1) +{ + tpa_info->vlan_valid = 0; + if (TPA_START_VLAN_VALID(tpa_start)) { + u32 tpid_sel = TPA_START_VLAN_TPID_SEL(tpa_start); + u32 vlan_proto = ETH_P_8021Q; + + tpa_info->vlan_valid = 1; + if (tpid_sel == RX_TPA_START_METADATA1_TPID_8021AD) + vlan_proto = ETH_P_8021AD; + tpa_info->metadata = vlan_proto << 16 | + TPA_START_METADATA0_TCI(tpa_start1); + } +} + static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u8 cmp_type, struct rx_tpa_start_cmp *tpa_start, struct rx_tpa_start_cmp_ext *tpa_start1) @@ -1378,12 +1395,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, le32_to_cpu(tpa_start->rx_tpa_start_cmp_len_flags_type) >> RX_TPA_START_CMP_LEN_SHIFT; if (likely(TPA_START_HASH_VALID(tpa_start))) { - u32 hash_type = TPA_START_HASH_TYPE(tpa_start); - tpa_info->hash_type = PKT_HASH_TYPE_L4; tpa_info->gso_type = SKB_GSO_TCPV4; + if (TPA_START_IS_IPV6(tpa_start1)) + tpa_info->gso_type = SKB_GSO_TCPV6; /* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */ - if (hash_type == 3 || TPA_START_IS_IPV6(tpa_start1)) + else if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP && + TPA_START_HASH_TYPE(tpa_start) == 3) tpa_info->gso_type = SKB_GSO_TCPV6; tpa_info->rss_hash = le32_to_cpu(tpa_start->rx_tpa_start_cmp_rss_hash); @@ -1394,7 +1412,10 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, } tpa_info->flags2 = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_flags2); tpa_info->hdr_info = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_hdr_info); - bnxt_tpa_metadata(tpa_info, tpa_start, tpa_start1); + if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) + bnxt_tpa_metadata(tpa_info, tpa_start, tpa_start1); + else + bnxt_tpa_metadata_v2(tpa_info, tpa_start, tpa_start1); tpa_info->agg_count = 0; rxr->rx_prod = NEXT_RX(prod); @@ -1816,6 +1837,19 @@ static struct sk_buff *bnxt_rx_vlan(struct sk_buff *skb, u8 cmp_type, __vlan_hwaccel_put_tag(skb, vlan_proto, vtag); else goto vlan_err; + } else if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) { + if (RX_CMP_VLAN_VALID(rxcmp)) { + u32 tpid_sel = RX_CMP_VLAN_TPID_SEL(rxcmp); + + if (tpid_sel == RX_CMP_METADATA1_TPID_8021Q) + vlan_proto = htons(ETH_P_8021Q); + else if (tpid_sel == RX_CMP_METADATA1_TPID_8021AD) + vlan_proto = htons(ETH_P_8021AD); + else + goto vlan_err; + vtag = RX_CMP_METADATA0_TCI(rxcmp1); + __vlan_hwaccel_put_tag(skb, vlan_proto, vtag); + } } return skb; vlan_err: @@ -1823,6 +1857,23 @@ static struct sk_buff *bnxt_rx_vlan(struct sk_buff *skb, u8 cmp_type, return NULL; } +static enum pkt_hash_types bnxt_rss_ext_op(struct bnxt *bp, + struct rx_cmp *rxcmp) +{ + u8 ext_op; + + ext_op = RX_CMP_V3_HASH_TYPE(bp, rxcmp); + switch (ext_op) { + case EXT_OP_INNER_4: + case EXT_OP_OUTER_4: + case EXT_OP_INNFL_3: + case EXT_OP_OUTFL_3: + return PKT_HASH_TYPE_L4; + default: + return PKT_HASH_TYPE_L3; + } +} + /* returns the following: * 1 - 1 packet successfully received * 0 - successful TPA_START, packet not completed yet @@ -1839,7 +1890,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, struct rx_cmp *rxcmp; struct rx_cmp_ext *rxcmp1; u32 tmp_raw_cons = *raw_cons; - u16 cfa_code, cons, prod, cp_cons = RING_CMP(tmp_raw_cons); + u16 cons, prod, cp_cons = RING_CMP(tmp_raw_cons); struct bnxt_sw_rx_bd *rx_buf; unsigned int len; u8 *data_ptr, agg_bufs, cmp_type; @@ -1875,7 +1926,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, dma_rmb(); prod = rxr->rx_prod; - if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) { + if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP || + cmp_type == CMP_TYPE_RX_L2_TPA_START_V3_CMP) { bnxt_tpa_start(bp, rxr, cmp_type, (struct rx_tpa_start_cmp *)rxcmp, (struct rx_tpa_start_cmp_ext *)rxcmp1); @@ -2030,17 +2082,27 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } if (RX_CMP_HASH_VALID(rxcmp)) { - u32 hash_type = RX_CMP_HASH_TYPE(rxcmp); - enum pkt_hash_types type = PKT_HASH_TYPE_L4; + enum pkt_hash_types type; - /* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */ - if (hash_type != 1 && hash_type != 3) - type = PKT_HASH_TYPE_L3; + if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) { + type = bnxt_rss_ext_op(bp, rxcmp); + } else { + u32 hash_type = RX_CMP_HASH_TYPE(rxcmp); + + /* RSS profiles 1 and 3 with extract code 0 for inner + * 4-tuple + */ + if (hash_type != 1 && hash_type != 3) + type = PKT_HASH_TYPE_L3; + else + type = PKT_HASH_TYPE_L4; + } skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type); } - cfa_code = RX_CMP_CFA_CODE(rxcmp1); - skb->protocol = eth_type_trans(skb, bnxt_get_pkt_dev(bp, cfa_code)); + if (cmp_type == CMP_TYPE_RX_L2_CMP) + dev = bnxt_get_pkt_dev(bp, RX_CMP_CFA_CODE(rxcmp1)); + skb->protocol = eth_type_trans(skb, dev); if (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX) { skb = bnxt_rx_vlan(skb, cmp_type, rxcmp, rxcmp1); @@ -2127,7 +2189,8 @@ static int bnxt_force_rx_discard(struct bnxt *bp, */ dma_rmb(); cmp_type = RX_CMP_TYPE(rxcmp); - if (cmp_type == CMP_TYPE_RX_L2_CMP) { + if (cmp_type == CMP_TYPE_RX_L2_CMP || + cmp_type == CMP_TYPE_RX_L2_V3_CMP) { rxcmp1->rx_cmp_cfa_code_errors_v2 |= cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR); } else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) { @@ -2651,6 +2714,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, cpr->has_more_work = 0; cpr->had_work_done = 1; while (1) { + u8 cmp_type; int rc; cons = RING_CMP(raw_cons); @@ -2663,7 +2727,8 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, * reading any further. */ dma_rmb(); - if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) { + cmp_type = TX_CMP_TYPE(txcmp); + if (cmp_type == CMP_TYPE_TX_L2_CMP) { u32 opaque = txcmp->tx_cmp_opaque; struct bnxt_tx_ring_info *txr; u16 tx_freed; @@ -2681,7 +2746,8 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, cpr->has_more_work = 1; break; } - } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) { + } else if (cmp_type >= CMP_TYPE_RX_L2_CMP && + cmp_type <= CMP_TYPE_RX_L2_TPA_START_V3_CMP) { if (likely(budget)) rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event); else @@ -2698,12 +2764,9 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, rx_pkts++; else if (rc == -EBUSY) /* partial completion */ break; - } else if (unlikely((TX_CMP_TYPE(txcmp) == - CMPL_BASE_TYPE_HWRM_DONE) || - (TX_CMP_TYPE(txcmp) == - CMPL_BASE_TYPE_HWRM_FWD_REQ) || - (TX_CMP_TYPE(txcmp) == - CMPL_BASE_TYPE_HWRM_ASYNC_EVENT))) { + } else if (unlikely(cmp_type == CMPL_BASE_TYPE_HWRM_DONE || + cmp_type == CMPL_BASE_TYPE_HWRM_FWD_REQ || + cmp_type == CMPL_BASE_TYPE_HWRM_ASYNC_EVENT)) { bnxt_hwrm_handler(bp, txcmp); } raw_cons = NEXT_RAW_CMP(raw_cons); @@ -5826,6 +5889,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP; if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_HASH_TYPE_DELTA_CAP) bp->rss_cap |= BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_PROF_TCAM_MODE_ENABLED) + bp->rss_cap |= BNXT_RSS_CAP_RSS_TCAM; bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); if (bp->max_tpa_v2) { if (BNXT_CHIP_P5(bp)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 14cb0512ee93..ad0b93682771 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3919,7 +3919,8 @@ static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, * reading any further. */ dma_rmb(); - if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { + if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP || + TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_V3_CMP) { rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); raw_cons = NEXT_RAW_CMP(raw_cons); raw_cons = NEXT_RAW_CMP(raw_cons); From cf47fa5ca5bb095c3d7b8222b959f54d952cf9e5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:20 -0800 Subject: [PATCH 2442/7721] bnxt_en: Refactor ethtool speeds logic Add helper functions to refactor the logic that converts firmware speed masks to ethtool speeds. Pass the phy_flags to bnxt_get_ethtool_speeds() and the call chain. The refactoring and the phy_flags will be needed when adding support for the new speeds in the next patches. Reviewed-by: Ajit Khaparde Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-12-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index ad0b93682771..a9b6141337d4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1801,7 +1801,7 @@ static const u16 bnxt_pam4_speed_masks[] = { }; static enum bnxt_link_speed_indices -bnxt_encoding_speed_idx(u8 sig_mode, u16 speed_msk) +bnxt_encoding_speed_idx(u8 sig_mode, u16 phy_flags, u16 speed_msk) { const u16 *speeds; int idx, len; @@ -1831,14 +1831,14 @@ bnxt_encoding_speed_idx(u8 sig_mode, u16 speed_msk) static void __bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media, - u8 sig_mode, unsigned long *et_mask) + u8 sig_mode, u16 phy_flags, unsigned long *et_mask) { enum ethtool_link_mode_bit_indices link_mode; enum bnxt_link_speed_indices speed; u8 bit; for_each_set_bit(bit, &fw_mask, BNXT_FW_SPEED_MSK_BITS) { - speed = bnxt_encoding_speed_idx(sig_mode, 1 << bit); + speed = bnxt_encoding_speed_idx(sig_mode, phy_flags, 1 << bit); if (!speed) continue; @@ -1852,16 +1852,66 @@ __bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media, static void bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media, - u8 sig_mode, unsigned long *et_mask) + u8 sig_mode, u16 phy_flags, unsigned long *et_mask) { if (media) { - __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask); + __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, + et_mask); return; } /* list speeds for all media if unknown */ for (media = 1; media < __BNXT_MEDIA_END; media++) - __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask); + __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, + et_mask); +} + +static void +bnxt_get_all_ethtool_support_speeds(struct bnxt_link_info *link_info, + enum bnxt_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 phy_flags = bp->phy_flags; + + bnxt_get_ethtool_speeds(link_info->support_speeds, media, + BNXT_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.supported); + bnxt_get_ethtool_speeds(link_info->support_pam4_speeds, media, + BNXT_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.supported); +} + +static void +bnxt_get_all_ethtool_adv_speeds(struct bnxt_link_info *link_info, + enum bnxt_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 phy_flags = bp->phy_flags; + + bnxt_get_ethtool_speeds(link_info->advertising, media, + BNXT_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.advertising); + bnxt_get_ethtool_speeds(link_info->advertising_pam4, media, + BNXT_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.advertising); +} + +static void +bnxt_get_all_ethtool_lp_speeds(struct bnxt_link_info *link_info, + enum bnxt_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 phy_flags = bp->phy_flags; + + bnxt_get_ethtool_speeds(link_info->lp_auto_link_speeds, media, + BNXT_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.lp_advertising); + bnxt_get_ethtool_speeds(link_info->lp_auto_pam4_link_speeds, media, + BNXT_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.lp_advertising); } static void bnxt_update_speed(u32 *delta, bool installed_media, u16 *speeds, @@ -2017,12 +2067,7 @@ static int bnxt_get_link_ksettings(struct net_device *dev, mutex_lock(&bp->link_lock); bnxt_get_ethtool_modes(link_info, lk_ksettings); media = bnxt_get_media(link_info); - bnxt_get_ethtool_speeds(link_info->support_speeds, - media, BNXT_SIG_MODE_NRZ, - lk_ksettings->link_modes.supported); - bnxt_get_ethtool_speeds(link_info->support_pam4_speeds, - media, BNXT_SIG_MODE_PAM4, - lk_ksettings->link_modes.supported); + bnxt_get_all_ethtool_support_speeds(link_info, media, lk_ksettings); bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); link_mode = bnxt_get_link_mode(link_info); if (link_mode != BNXT_LINK_MODE_UNKNOWN) @@ -2035,20 +2080,10 @@ static int bnxt_get_link_ksettings(struct net_device *dev, linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, lk_ksettings->link_modes.advertising); base->autoneg = AUTONEG_ENABLE; - bnxt_get_ethtool_speeds(link_info->advertising, - media, BNXT_SIG_MODE_NRZ, - lk_ksettings->link_modes.advertising); - bnxt_get_ethtool_speeds(link_info->advertising_pam4, - media, BNXT_SIG_MODE_PAM4, - lk_ksettings->link_modes.advertising); - if (link_info->phy_link_status == BNXT_LINK_LINK) { - bnxt_get_ethtool_speeds(link_info->lp_auto_link_speeds, - media, BNXT_SIG_MODE_NRZ, - lk_ksettings->link_modes.lp_advertising); - bnxt_get_ethtool_speeds(link_info->lp_auto_pam4_link_speeds, - media, BNXT_SIG_MODE_PAM4, - lk_ksettings->link_modes.lp_advertising); - } + bnxt_get_all_ethtool_adv_speeds(link_info, media, lk_ksettings); + if (link_info->phy_link_status == BNXT_LINK_LINK) + bnxt_get_all_ethtool_lp_speeds(link_info, media, + lk_ksettings); } else { base->autoneg = AUTONEG_DISABLE; } From 30c0bb63c2ea0d7b8a9057afff2317d7b40846b1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:21 -0800 Subject: [PATCH 2443/7721] bnxt_en: Support new firmware link parameters Newer firmware supporting PAM4 112Gbps speeds use new parameters in firmware message structures. Detect the new firmware capability and add basic logic to report and store these new fields. Reviewed-by: Hongguang Gao Reviewed-by: Damodharam Ammepalli Reviewed-by: Ajit Khaparde Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-13-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 93 +++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 46 +++++++++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 10 ++ 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 3b0ced2a5f32..5f6c4644271c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2250,6 +2250,10 @@ static u16 bnxt_agg_ring_id_to_grp_idx(struct bnxt *bp, u16 ring_id) static u16 bnxt_get_force_speed(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) + return link_info->force_link_speed2; if (link_info->req_signal_mode == BNXT_SIG_MODE_PAM4) return link_info->force_pam4_link_speed; return link_info->force_link_speed; @@ -2257,6 +2261,28 @@ static u16 bnxt_get_force_speed(struct bnxt_link_info *link_info) static void bnxt_set_force_speed(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + link_info->req_link_speed = link_info->force_link_speed2; + link_info->req_signal_mode = BNXT_SIG_MODE_NRZ; + switch (link_info->req_link_speed) { + case BNXT_LINK_SPEED_50GB_PAM4: + case BNXT_LINK_SPEED_100GB_PAM4: + case BNXT_LINK_SPEED_200GB_PAM4: + case BNXT_LINK_SPEED_400GB_PAM4: + link_info->req_signal_mode = BNXT_SIG_MODE_PAM4; + break; + case BNXT_LINK_SPEED_100GB_PAM4_112: + case BNXT_LINK_SPEED_200GB_PAM4_112: + case BNXT_LINK_SPEED_400GB_PAM4_112: + link_info->req_signal_mode = BNXT_SIG_MODE_PAM4_112; + break; + default: + link_info->req_signal_mode = BNXT_SIG_MODE_NRZ; + } + return; + } link_info->req_link_speed = link_info->force_link_speed; link_info->req_signal_mode = BNXT_SIG_MODE_NRZ; if (link_info->force_pam4_link_speed) { @@ -2267,12 +2293,25 @@ static void bnxt_set_force_speed(struct bnxt_link_info *link_info) static void bnxt_set_auto_speed(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + link_info->advertising = link_info->auto_link_speeds2; + return; + } link_info->advertising = link_info->auto_link_speeds; link_info->advertising_pam4 = link_info->auto_pam4_link_speeds; } static bool bnxt_force_speed_updated(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + if (link_info->req_link_speed != link_info->force_link_speed2) + return true; + return false; + } if (link_info->req_signal_mode == BNXT_SIG_MODE_NRZ && link_info->req_link_speed != link_info->force_link_speed) return true; @@ -2284,6 +2323,13 @@ static bool bnxt_force_speed_updated(struct bnxt_link_info *link_info) static bool bnxt_auto_speed_updated(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + if (link_info->advertising != link_info->auto_link_speeds2) + return true; + return false; + } if (link_info->advertising != link_info->auto_link_speeds || link_info->advertising_pam4 != link_info->auto_pam4_link_speeds) return true; @@ -10082,7 +10128,10 @@ void bnxt_report_link(struct bnxt *bp) signal = "(NRZ) "; break; case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4: - signal = "(PAM4) "; + signal = "(PAM4 56Gbps) "; + break; + case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112: + signal = "(PAM4 112Gbps) "; break; default: break; @@ -10110,7 +10159,9 @@ static bool bnxt_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *resp) if (!resp->supported_speeds_auto_mode && !resp->supported_speeds_force_mode && !resp->supported_pam4_speeds_auto_mode && - !resp->supported_pam4_speeds_force_mode) + !resp->supported_pam4_speeds_force_mode && + !resp->supported_speeds2_auto_mode && + !resp->supported_speeds2_force_mode) return true; return false; } @@ -10156,6 +10207,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) /* Phy re-enabled, reprobe the speeds */ link_info->support_auto_speeds = 0; link_info->support_pam4_auto_speeds = 0; + link_info->support_auto_speeds2 = 0; } } if (resp->supported_speeds_auto_mode) @@ -10164,6 +10216,9 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) if (resp->supported_pam4_speeds_auto_mode) link_info->support_pam4_auto_speeds = le16_to_cpu(resp->supported_pam4_speeds_auto_mode); + if (resp->supported_speeds2_auto_mode) + link_info->support_auto_speeds2 = + le16_to_cpu(resp->supported_speeds2_auto_mode); bp->port_count = resp->port_cnt; @@ -10181,9 +10236,19 @@ static bool bnxt_support_dropped(u16 advertising, u16 supported) static bool bnxt_support_speed_dropped(struct bnxt_link_info *link_info) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + /* Check if any advertised speeds are no longer supported. The caller * holds the link_lock mutex, so we can modify link_info settings. */ + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + if (bnxt_support_dropped(link_info->advertising, + link_info->support_auto_speeds2)) { + link_info->advertising = link_info->support_auto_speeds2; + return true; + } + return false; + } if (bnxt_support_dropped(link_info->advertising, link_info->support_auto_speeds)) { link_info->advertising = link_info->support_auto_speeds; @@ -10232,18 +10297,25 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) link_info->lp_pause = resp->link_partner_adv_pause; link_info->force_pause_setting = resp->force_pause; link_info->duplex_setting = resp->duplex_cfg; - if (link_info->phy_link_status == BNXT_LINK_LINK) + if (link_info->phy_link_status == BNXT_LINK_LINK) { link_info->link_speed = le16_to_cpu(resp->link_speed); - else + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) + link_info->active_lanes = resp->active_lanes; + } else { link_info->link_speed = 0; + link_info->active_lanes = 0; + } link_info->force_link_speed = le16_to_cpu(resp->force_link_speed); link_info->force_pam4_link_speed = le16_to_cpu(resp->force_pam4_link_speed); + link_info->force_link_speed2 = le16_to_cpu(resp->force_link_speeds2); link_info->support_speeds = le16_to_cpu(resp->support_speeds); link_info->support_pam4_speeds = le16_to_cpu(resp->support_pam4_speeds); + link_info->support_speeds2 = le16_to_cpu(resp->support_speeds2); link_info->auto_link_speeds = le16_to_cpu(resp->auto_link_speed_mask); link_info->auto_pam4_link_speeds = le16_to_cpu(resp->auto_pam4_link_speed_mask); + link_info->auto_link_speeds2 = le16_to_cpu(resp->auto_link_speeds2); link_info->lp_auto_link_speeds = le16_to_cpu(resp->link_partner_adv_speeds); link_info->lp_auto_pam4_link_speeds = @@ -10382,7 +10454,11 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp, struct hwrm_port_phy_cfg_ { if (bp->link_info.autoneg & BNXT_AUTONEG_SPEED) { req->auto_mode |= PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK; - if (bp->link_info.advertising) { + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + req->enables |= + cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK); + req->auto_link_speeds2_mask = cpu_to_le16(bp->link_info.advertising); + } else if (bp->link_info.advertising) { req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK); req->auto_link_speed_mask = cpu_to_le16(bp->link_info.advertising); } @@ -10396,7 +10472,12 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp, struct hwrm_port_phy_cfg_ req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_RESTART_AUTONEG); } else { req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE); - if (bp->link_info.req_signal_mode == BNXT_SIG_MODE_PAM4) { + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + req->force_link_speeds2 = cpu_to_le16(bp->link_info.req_link_speed); + req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2); + netif_info(bp, link, bp->dev, "Forcing FW speed2: %d\n", + (u32)bp->link_info.req_link_speed); + } else if (bp->link_info.req_signal_mode == BNXT_SIG_MODE_PAM4) { req->force_pam4_link_speed = cpu_to_le16(bp->link_info.req_link_speed); req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED); } else { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 57694eb7feeb..d8c2b0790117 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1360,6 +1360,7 @@ struct bnxt_link_info { #define BNXT_LINK_STATE_DOWN 1 #define BNXT_LINK_STATE_UP 2 #define BNXT_LINK_IS_UP(bp) ((bp)->link_info.link_state == BNXT_LINK_STATE_UP) + u8 active_lanes; u8 duplex; #define BNXT_LINK_DUPLEX_HALF PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF #define BNXT_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL @@ -1394,8 +1395,11 @@ struct bnxt_link_info { #define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB #define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB #define BNXT_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB +#define BNXT_LINK_SPEED_400GB PORT_PHY_QCFG_RESP_LINK_SPEED_400GB u16 support_speeds; u16 support_pam4_speeds; + u16 support_speeds2; + u16 auto_link_speeds; /* fw adv setting */ #define BNXT_LINK_SPEED_MSK_100MB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100MB #define BNXT_LINK_SPEED_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_1GB @@ -1411,12 +1415,52 @@ struct bnxt_link_info { #define BNXT_LINK_PAM4_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_50G #define BNXT_LINK_PAM4_SPEED_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_100G #define BNXT_LINK_PAM4_SPEED_MSK_200GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_200G + u16 auto_link_speeds2; +#define BNXT_LINK_SPEEDS2_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB +#define BNXT_LINK_SPEEDS2_MSK_10GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB +#define BNXT_LINK_SPEEDS2_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_25GB +#define BNXT_LINK_SPEEDS2_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_40GB +#define BNXT_LINK_SPEEDS2_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB +#define BNXT_LINK_SPEEDS2_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB +#define BNXT_LINK_SPEEDS2_MSK_50GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56 +#define BNXT_LINK_SPEEDS2_MSK_100GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56 +#define BNXT_LINK_SPEEDS2_MSK_200GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56 +#define BNXT_LINK_SPEEDS2_MSK_400GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56 +#define BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112 +#define BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112 +#define BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112 + u16 support_auto_speeds; u16 support_pam4_auto_speeds; + u16 support_auto_speeds2; + u16 lp_auto_link_speeds; u16 lp_auto_pam4_link_speeds; u16 force_link_speed; u16 force_pam4_link_speed; + u16 force_link_speed2; +#define BNXT_LINK_SPEED_50GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56 +#define BNXT_LINK_SPEED_100GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56 +#define BNXT_LINK_SPEED_200GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56 +#define BNXT_LINK_SPEED_400GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56 +#define BNXT_LINK_SPEED_100GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112 +#define BNXT_LINK_SPEED_200GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112 +#define BNXT_LINK_SPEED_400GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 + u32 preemphasis; u8 module_status; u8 active_fec_sig_mode; @@ -1447,6 +1491,7 @@ struct bnxt_link_info { u8 req_signal_mode; #define BNXT_SIG_MODE_NRZ PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ #define BNXT_SIG_MODE_PAM4 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 +#define BNXT_SIG_MODE_PAM4_112 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 #define BNXT_SIG_MODE_MAX (PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST + 1) u8 req_duplex; u8 req_flow_ctrl; @@ -2337,6 +2382,7 @@ struct bnxt { #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) #define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8) #define BNXT_PHY_FL_BANK_SEL (PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED << 8) +#define BNXT_PHY_FL_SPEEDS2 (PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED << 8) u8 num_tests; struct bnxt_test_info *test_info; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index a9b6141337d4..7bc0bddbb126 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2020,11 +2020,20 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) case BNXT_LINK_SPEED_40GB: return SPEED_40000; case BNXT_LINK_SPEED_50GB: + case BNXT_LINK_SPEED_50GB_PAM4: return SPEED_50000; case BNXT_LINK_SPEED_100GB: + case BNXT_LINK_SPEED_100GB_PAM4: + case BNXT_LINK_SPEED_100GB_PAM4_112: return SPEED_100000; case BNXT_LINK_SPEED_200GB: + case BNXT_LINK_SPEED_200GB_PAM4: + case BNXT_LINK_SPEED_200GB_PAM4_112: return SPEED_200000; + case BNXT_LINK_SPEED_400GB: + case BNXT_LINK_SPEED_400GB_PAM4: + case BNXT_LINK_SPEED_400GB_PAM4_112: + return SPEED_400000; default: return SPEED_UNKNOWN; } @@ -2040,6 +2049,7 @@ static void bnxt_get_default_speeds(struct ethtool_link_ksettings *lk_ksettings, base->duplex = DUPLEX_HALF; if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) base->duplex = DUPLEX_FULL; + lk_ksettings->lanes = link_info->active_lanes; } else if (!link_info->autoneg) { base->speed = bnxt_fw_to_ethtool_speed(link_info->req_link_speed); base->duplex = DUPLEX_HALF; From 7b60cf2b641a0de8117714dd6653e19a05ab4fda Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:22 -0800 Subject: [PATCH 2444/7721] bnxt_en: Support force speed using the new HWRM fields Modify bnxt_force_link_speed() to support the new speeds stored in link_info->support_speeds2, including the new 400G speed. Reviewed-by: Ajit Khaparde Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-14-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 7bc0bddbb126..0a7dd48f1da8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2128,6 +2128,7 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; u16 support_pam4_spds = link_info->support_pam4_speeds; + u16 support_spds2 = link_info->support_speeds2; u16 support_spds = link_info->support_speeds; u8 sig_mode = BNXT_SIG_MODE_NRZ; u32 lanes_needed = 1; @@ -2139,7 +2140,8 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; break; case SPEED_1000: - if (support_spds & BNXT_LINK_SPEED_MSK_1GB) + if ((support_spds & BNXT_LINK_SPEED_MSK_1GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_1GB)) fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; break; case SPEED_2500: @@ -2147,7 +2149,8 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; break; case SPEED_10000: - if (support_spds & BNXT_LINK_SPEED_MSK_10GB) + if ((support_spds & BNXT_LINK_SPEED_MSK_10GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_10GB)) fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; break; case SPEED_20000: @@ -2157,26 +2160,34 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) } break; case SPEED_25000: - if (support_spds & BNXT_LINK_SPEED_MSK_25GB) + if ((support_spds & BNXT_LINK_SPEED_MSK_25GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_25GB)) fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; break; case SPEED_40000: - if (support_spds & BNXT_LINK_SPEED_MSK_40GB) { + if ((support_spds & BNXT_LINK_SPEED_MSK_40GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_40GB)) { fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; lanes_needed = 4; } break; case SPEED_50000: - if ((support_spds & BNXT_LINK_SPEED_MSK_50GB) && lanes != 1) { + if (((support_spds & BNXT_LINK_SPEED_MSK_50GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB)) && + lanes != 1) { fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; lanes_needed = 2; } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; sig_mode = BNXT_SIG_MODE_PAM4; + } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB_PAM4) { + fw_speed = BNXT_LINK_SPEED_50GB_PAM4; + sig_mode = BNXT_SIG_MODE_PAM4; } break; case SPEED_100000: - if ((support_spds & BNXT_LINK_SPEED_MSK_100GB) && + if (((support_spds & BNXT_LINK_SPEED_MSK_100GB) || + (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB)) && lanes != 2 && lanes != 1) { fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; lanes_needed = 4; @@ -2184,6 +2195,14 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; sig_mode = BNXT_SIG_MODE_PAM4; lanes_needed = 2; + } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4) && + lanes != 1) { + fw_speed = BNXT_LINK_SPEED_100GB_PAM4; + sig_mode = BNXT_SIG_MODE_PAM4; + lanes_needed = 2; + } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112) { + fw_speed = BNXT_LINK_SPEED_100GB_PAM4_112; + sig_mode = BNXT_SIG_MODE_PAM4_112; } break; case SPEED_200000: @@ -2191,6 +2210,27 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; sig_mode = BNXT_SIG_MODE_PAM4; lanes_needed = 4; + } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4) && + lanes != 2) { + fw_speed = BNXT_LINK_SPEED_200GB_PAM4; + sig_mode = BNXT_SIG_MODE_PAM4; + lanes_needed = 4; + } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112) { + fw_speed = BNXT_LINK_SPEED_200GB_PAM4_112; + sig_mode = BNXT_SIG_MODE_PAM4_112; + lanes_needed = 2; + } + break; + case SPEED_400000: + if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4) && + lanes != 4) { + fw_speed = BNXT_LINK_SPEED_400GB_PAM4; + sig_mode = BNXT_SIG_MODE_PAM4; + lanes_needed = 8; + } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112) { + fw_speed = BNXT_LINK_SPEED_400GB_PAM4_112; + sig_mode = BNXT_SIG_MODE_PAM4_112; + lanes_needed = 4; } break; } From 047a2d38e40cf37d75548554d6811cb2a305faae Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:23 -0800 Subject: [PATCH 2445/7721] bnxt_en: Report the new ethtool link modes in the new firmware interface Add new look up entries to convert the new supported speeds, advertised speeds, etc to ethtool link modes. Reviewed-by: Damodharam Ammepalli Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-15-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 171 ++++++++++++++++-- 1 file changed, 151 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 0a7dd48f1da8..bb9cab821587 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1577,6 +1577,22 @@ static const enum bnxt_media_type bnxt_phy_types[] = { [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] = BNXT_MEDIA_SR, [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] = BNXT_MEDIA_LR_ER_FR, [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] = BNXT_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] = BNXT_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] = BNXT_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] = BNXT_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] = BNXT_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] = BNXT_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] = BNXT_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] = BNXT_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] = BNXT_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] = BNXT_MEDIA_LR_ER_FR, }; static enum bnxt_media_type @@ -1604,6 +1620,7 @@ enum bnxt_link_speed_indices { BNXT_LINK_SPEED_50GB_IDX, BNXT_LINK_SPEED_100GB_IDX, BNXT_LINK_SPEED_200GB_IDX, + BNXT_LINK_SPEED_400GB_IDX, __BNXT_LINK_SPEED_END }; @@ -1615,9 +1632,21 @@ static enum bnxt_link_speed_indices bnxt_fw_speed_idx(u16 speed) case BNXT_LINK_SPEED_10GB: return BNXT_LINK_SPEED_10GB_IDX; case BNXT_LINK_SPEED_25GB: return BNXT_LINK_SPEED_25GB_IDX; case BNXT_LINK_SPEED_40GB: return BNXT_LINK_SPEED_40GB_IDX; - case BNXT_LINK_SPEED_50GB: return BNXT_LINK_SPEED_50GB_IDX; - case BNXT_LINK_SPEED_100GB: return BNXT_LINK_SPEED_100GB_IDX; - case BNXT_LINK_SPEED_200GB: return BNXT_LINK_SPEED_200GB_IDX; + case BNXT_LINK_SPEED_50GB: + case BNXT_LINK_SPEED_50GB_PAM4: + return BNXT_LINK_SPEED_50GB_IDX; + case BNXT_LINK_SPEED_100GB: + case BNXT_LINK_SPEED_100GB_PAM4: + case BNXT_LINK_SPEED_100GB_PAM4_112: + return BNXT_LINK_SPEED_100GB_IDX; + case BNXT_LINK_SPEED_200GB: + case BNXT_LINK_SPEED_200GB_PAM4: + case BNXT_LINK_SPEED_200GB_PAM4_112: + return BNXT_LINK_SPEED_200GB_IDX; + case BNXT_LINK_SPEED_400GB: + case BNXT_LINK_SPEED_400GB_PAM4: + case BNXT_LINK_SPEED_400GB_PAM4_112: + return BNXT_LINK_SPEED_400GB_IDX; default: return BNXT_LINK_SPEED_UNKNOWN; } } @@ -1690,6 +1719,12 @@ bnxt_link_modes[__BNXT_LINK_SPEED_END][BNXT_SIG_MODE_MAX][__BNXT_MEDIA_END] = { [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, }, + [BNXT_SIG_MODE_PAM4_112] = { + [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, + [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, + [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, + [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, + }, }, [BNXT_LINK_SPEED_200GB_IDX] = { [BNXT_SIG_MODE_PAM4] = { @@ -1698,6 +1733,26 @@ bnxt_link_modes[__BNXT_LINK_SPEED_END][BNXT_SIG_MODE_MAX][__BNXT_MEDIA_END] = { [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, }, + [BNXT_SIG_MODE_PAM4_112] = { + [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, + [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, + [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, + [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, + }, + }, + [BNXT_LINK_SPEED_400GB_IDX] = { + [BNXT_SIG_MODE_PAM4] = { + [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, + [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, + }, + [BNXT_SIG_MODE_PAM4_112] = { + [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, + [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, + [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, + [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, + }, }, }; @@ -1762,7 +1817,8 @@ static void bnxt_get_ethtool_modes(struct bnxt_link_info *link_info, lk_ksettings->link_modes.supported); } - if (link_info->support_auto_speeds || link_info->support_pam4_auto_speeds) + if (link_info->support_auto_speeds || link_info->support_auto_speeds2 || + link_info->support_pam4_auto_speeds) linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, lk_ksettings->link_modes.supported); @@ -1798,6 +1854,30 @@ static const u16 bnxt_pam4_speed_masks[] = { [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_50GB, [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_100GB, [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_200GB, + [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */ +}; + +static const u16 bnxt_nrz_speeds2_masks[] = { + [BNXT_LINK_SPEED_1GB_IDX] = BNXT_LINK_SPEEDS2_MSK_1GB, + [BNXT_LINK_SPEED_10GB_IDX] = BNXT_LINK_SPEEDS2_MSK_10GB, + [BNXT_LINK_SPEED_25GB_IDX] = BNXT_LINK_SPEEDS2_MSK_25GB, + [BNXT_LINK_SPEED_40GB_IDX] = BNXT_LINK_SPEEDS2_MSK_40GB, + [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB, + [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB, + [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */ +}; + +static const u16 bnxt_pam4_speeds2_masks[] = { + [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB_PAM4, + [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4, + [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4, + [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4, +}; + +static const u16 bnxt_pam4_112_speeds2_masks[] = { + [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112, + [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112, + [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112, }; static enum bnxt_link_speed_indices @@ -1808,12 +1888,26 @@ bnxt_encoding_speed_idx(u8 sig_mode, u16 phy_flags, u16 speed_msk) switch (sig_mode) { case BNXT_SIG_MODE_NRZ: - speeds = bnxt_nrz_speed_masks; - len = ARRAY_SIZE(bnxt_nrz_speed_masks); + if (phy_flags & BNXT_PHY_FL_SPEEDS2) { + speeds = bnxt_nrz_speeds2_masks; + len = ARRAY_SIZE(bnxt_nrz_speeds2_masks); + } else { + speeds = bnxt_nrz_speed_masks; + len = ARRAY_SIZE(bnxt_nrz_speed_masks); + } break; case BNXT_SIG_MODE_PAM4: - speeds = bnxt_pam4_speed_masks; - len = ARRAY_SIZE(bnxt_pam4_speed_masks); + if (phy_flags & BNXT_PHY_FL_SPEEDS2) { + speeds = bnxt_pam4_speeds2_masks; + len = ARRAY_SIZE(bnxt_pam4_speeds2_masks); + } else { + speeds = bnxt_pam4_speed_masks; + len = ARRAY_SIZE(bnxt_pam4_speed_masks); + } + break; + case BNXT_SIG_MODE_PAM4_112: + speeds = bnxt_pam4_112_speeds2_masks; + len = ARRAY_SIZE(bnxt_pam4_112_speeds2_masks); break; default: return BNXT_LINK_SPEED_UNKNOWN; @@ -1872,14 +1966,23 @@ bnxt_get_all_ethtool_support_speeds(struct bnxt_link_info *link_info, struct ethtool_link_ksettings *lk_ksettings) { struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 sp_nrz, sp_pam4, sp_pam4_112 = 0; u16 phy_flags = bp->phy_flags; - bnxt_get_ethtool_speeds(link_info->support_speeds, media, - BNXT_SIG_MODE_NRZ, phy_flags, + if (phy_flags & BNXT_PHY_FL_SPEEDS2) { + sp_nrz = link_info->support_speeds2; + sp_pam4 = link_info->support_speeds2; + sp_pam4_112 = link_info->support_speeds2; + } else { + sp_nrz = link_info->support_speeds; + sp_pam4 = link_info->support_pam4_speeds; + } + bnxt_get_ethtool_speeds(sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags, lk_ksettings->link_modes.supported); - bnxt_get_ethtool_speeds(link_info->support_pam4_speeds, media, - BNXT_SIG_MODE_PAM4, phy_flags, + bnxt_get_ethtool_speeds(sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags, lk_ksettings->link_modes.supported); + bnxt_get_ethtool_speeds(sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112, + phy_flags, lk_ksettings->link_modes.supported); } static void @@ -1888,14 +1991,22 @@ bnxt_get_all_ethtool_adv_speeds(struct bnxt_link_info *link_info, struct ethtool_link_ksettings *lk_ksettings) { struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 sp_nrz, sp_pam4, sp_pam4_112 = 0; u16 phy_flags = bp->phy_flags; - bnxt_get_ethtool_speeds(link_info->advertising, media, - BNXT_SIG_MODE_NRZ, phy_flags, + sp_nrz = link_info->advertising; + if (phy_flags & BNXT_PHY_FL_SPEEDS2) { + sp_pam4 = link_info->advertising; + sp_pam4_112 = link_info->advertising; + } else { + sp_pam4 = link_info->advertising_pam4; + } + bnxt_get_ethtool_speeds(sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags, lk_ksettings->link_modes.advertising); - bnxt_get_ethtool_speeds(link_info->advertising_pam4, media, - BNXT_SIG_MODE_PAM4, phy_flags, + bnxt_get_ethtool_speeds(sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags, lk_ksettings->link_modes.advertising); + bnxt_get_ethtool_speeds(sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112, + phy_flags, lk_ksettings->link_modes.advertising); } static void @@ -1940,22 +2051,42 @@ static void bnxt_update_speed(u32 *delta, bool installed_media, u16 *speeds, static void bnxt_set_ethtool_speeds(struct bnxt_link_info *link_info, const unsigned long *et_mask) { + struct bnxt *bp = container_of(link_info, struct bnxt, link_info); + u16 const *sp_msks, *sp_pam4_msks, *sp_pam4_112_msks; enum bnxt_media_type media = bnxt_get_media(link_info); + u16 *adv, *adv_pam4, *adv_pam4_112 = NULL; + u32 delta_pam4_112 = 0; u32 delta_pam4 = 0; u32 delta_nrz = 0; int i, m; + adv = &link_info->advertising; + if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { + adv_pam4 = &link_info->advertising; + adv_pam4_112 = &link_info->advertising; + sp_msks = bnxt_nrz_speeds2_masks; + sp_pam4_msks = bnxt_pam4_speeds2_masks; + sp_pam4_112_msks = bnxt_pam4_112_speeds2_masks; + } else { + adv_pam4 = &link_info->advertising_pam4; + sp_msks = bnxt_nrz_speed_masks; + sp_pam4_msks = bnxt_pam4_speed_masks; + } for (i = 1; i < __BNXT_LINK_SPEED_END; i++) { /* accept any legal media from user */ for (m = 1; m < __BNXT_MEDIA_END; m++) { bnxt_update_speed(&delta_nrz, m == media, - &link_info->advertising, - bnxt_nrz_speed_masks[i], et_mask, + adv, sp_msks[i], et_mask, bnxt_link_modes[i][BNXT_SIG_MODE_NRZ][m]); bnxt_update_speed(&delta_pam4, m == media, - &link_info->advertising_pam4, - bnxt_pam4_speed_masks[i], et_mask, + adv_pam4, sp_pam4_msks[i], et_mask, bnxt_link_modes[i][BNXT_SIG_MODE_PAM4][m]); + if (!adv_pam4_112) + continue; + + bnxt_update_speed(&delta_pam4_112, m == media, + adv_pam4_112, sp_pam4_112_msks[i], et_mask, + bnxt_link_modes[i][BNXT_SIG_MODE_PAM4_112][m]); } } } From 2012a6abc87657c6c8171bb5ff13dd9bafb241bf Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 1 Dec 2023 14:39:24 -0800 Subject: [PATCH 2446/7721] bnxt_en: Add 5760X (P7) PCI IDs Now with basic support for the new chip family, add the PCI IDs of the new devices. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20231201223924.26955-16-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 5f6c4644271c..a405c89b00d3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -120,6 +120,10 @@ static const struct { [BCM57508] = { "Broadcom BCM57508 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" }, [BCM57504] = { "Broadcom BCM57504 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" }, [BCM57502] = { "Broadcom BCM57502 NetXtreme-E 10Gb/25Gb/50Gb Ethernet" }, + [BCM57608] = { "Broadcom BCM57608 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb/400Gb Ethernet" }, + [BCM57604] = { "Broadcom BCM57604 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" }, + [BCM57602] = { "Broadcom BCM57602 NetXtreme-E 10Gb/25Gb/50Gb/100Gb Ethernet" }, + [BCM57601] = { "Broadcom BCM57601 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb/400Gb Ethernet" }, [BCM57508_NPAR] = { "Broadcom BCM57508 NetXtreme-E Ethernet Partition" }, [BCM57504_NPAR] = { "Broadcom BCM57504 NetXtreme-E Ethernet Partition" }, [BCM57502_NPAR] = { "Broadcom BCM57502 NetXtreme-E Ethernet Partition" }, @@ -174,6 +178,10 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 }, { PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 }, { PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 }, + { PCI_VDEVICE(BROADCOM, 0x1760), .driver_data = BCM57608 }, + { PCI_VDEVICE(BROADCOM, 0x1761), .driver_data = BCM57604 }, + { PCI_VDEVICE(BROADCOM, 0x1762), .driver_data = BCM57602 }, + { PCI_VDEVICE(BROADCOM, 0x1763), .driver_data = BCM57601 }, { PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR }, { PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR }, { PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR }, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d8c2b0790117..afa784305fea 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1906,6 +1906,10 @@ enum board_idx { BCM57508_NPAR, BCM57504_NPAR, BCM57502_NPAR, + BCM57608, + BCM57604, + BCM57602, + BCM57601, BCM58802, BCM58804, BCM58808, From 84de14baf81675a98dc0fe617a93eacf9a417de3 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Sun, 3 Dec 2023 17:26:52 +0800 Subject: [PATCH 2447/7721] RDMA/siw: Move tx_cpu ahead We can reduce one cacheline for the usage of struct siw_qp. Before, /* size: 1928, cachelines: 31, members: 38 */ /* sum members: 1920, holes: 2, sum holes: 8 */ /* paddings: 4, sum paddings: 13 */ /* forced alignments: 3 */ after /* size: 1920, cachelines: 30, members: 38 */ /* paddings: 4, sum paddings: 13 */ /* forced alignments: 3 */ Link: https://lore.kernel.org/r/20231203092655.28102-2-guoqing.jiang@linux.dev Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index b36d1ec25327..d14bb965af75 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -417,10 +417,10 @@ struct siw_iwarp_tx { struct siw_qp { struct ib_qp base_qp; struct siw_device *sdev; + int tx_cpu; struct kref ref; struct completion qp_free; struct list_head devq; - int tx_cpu; struct siw_qp_attrs attrs; struct siw_cep *cep; From 51ac45a6636221d94e0b840cb8dd3d08b3622d64 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Sun, 3 Dec 2023 17:26:53 +0800 Subject: [PATCH 2448/7721] RDMA/siw: Reduce memory usage of struct siw_rx_stream We can reduce the memory of the struct by move some of it's member. Before, /* size: 144, cachelines: 3, members: 17 */ /* sum members: 124, holes: 3, sum holes: 12 */ /* sum bitfield members: 7 bits (0 bytes) */ /* padding: 7 */ /* bit_padding: 1 bits */ After /* size: 128, cachelines: 2, members: 17 */ /* padding: 3 */ /* bit_padding: 1 bits */ Link: https://lore.kernel.org/r/20231203092655.28102-3-guoqing.jiang@linux.dev Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index d14bb965af75..2edba2a864bb 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -288,10 +288,11 @@ struct siw_rx_stream { int skb_offset; /* offset in skb */ int skb_copied; /* processed bytes in skb */ + enum siw_rx_state state; + union iwarp_hdr hdr; struct mpa_trailer trailer; - - enum siw_rx_state state; + struct shash_desc *mpa_crc_hd; /* * For each FPDU, main RX loop runs through 3 stages: @@ -313,7 +314,6 @@ struct siw_rx_stream { u64 ddp_to; u32 inval_stag; /* Stag to be invalidated */ - struct shash_desc *mpa_crc_hd; u8 rx_suspend : 1; u8 pad : 2; /* # of pad bytes expected */ u8 rdmap_op : 4; /* opcode of current frame */ From 0b988c1bee28b48f7e4f264ff17d0d3e8817aa69 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Sun, 3 Dec 2023 17:26:54 +0800 Subject: [PATCH 2449/7721] RDMA/siw: Set qp_state in siw_query_qp Run test_query_rc_qp against siw failed since siw didn't set qp_state accordingly. To address it, introduce siw_qp_state_to_ib_qp_state which convert SIW_QP_STATE_IDLE to IB_QPS_INIT which is similar as in cxgb4. rdma-core# ./build/bin/run_tests.py --dev siw0 tests.test_qp.QPTest.test_query_rc_qp -v test_query_rc_qp (tests.test_qp.QPTest) Queries an RC QP after creation. Verifies that its properties are as ... FAIL ====================================================================== FAIL: test_query_rc_qp (tests.test_qp.QPTest) Queries an RC QP after creation. Verifies that its properties are as ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/gjiang/rdma-core/tests/test_qp.py", line 284, in test_query_rc_qp self.query_qp_common_test(e.IBV_QPT_RC) File "/home/gjiang/rdma-core/tests/test_qp.py", line 265, in query_qp_common_test self.verify_qp_attrs(caps, e.IBV_QPS_INIT, qp_init_attr, qp_attr) File "/home/gjiang/rdma-core/tests/test_qp.py", line 239, in verify_qp_attrs self.assertEqual(state, attr.qp_state) AssertionError: != 0 ---------------------------------------------------------------------- Ran 1 test in 0.057s FAILED (failures=1) Link: https://lore.kernel.org/r/20231203092655.28102-4-guoqing.jiang@linux.dev Signed-off-by: Guoqing Jiang Acked-by: Bernard Metzler Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw_verbs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index dca6a155523d..ecf0444666b4 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -19,6 +19,15 @@ #include "siw_verbs.h" #include "siw_mem.h" +static int siw_qp_state_to_ib_qp_state[SIW_QP_STATE_COUNT] = { + [SIW_QP_STATE_IDLE] = IB_QPS_INIT, + [SIW_QP_STATE_RTR] = IB_QPS_RTR, + [SIW_QP_STATE_RTS] = IB_QPS_RTS, + [SIW_QP_STATE_CLOSING] = IB_QPS_SQD, + [SIW_QP_STATE_TERMINATE] = IB_QPS_SQE, + [SIW_QP_STATE_ERROR] = IB_QPS_ERR +}; + static int ib_qp_state_to_siw_qp_state[IB_QPS_ERR + 1] = { [IB_QPS_RESET] = SIW_QP_STATE_IDLE, [IB_QPS_INIT] = SIW_QP_STATE_IDLE, @@ -504,6 +513,7 @@ int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr, } else { return -EINVAL; } + qp_attr->qp_state = siw_qp_state_to_ib_qp_state[qp->attrs.state]; qp_attr->cap.max_inline_data = SIW_MAX_INLINE; qp_attr->cap.max_send_wr = qp->attrs.sq_size; qp_attr->cap.max_send_sge = qp->attrs.sq_max_sges; From b7a2768a1cc3de8947b1fe4b1084de2f5464c606 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Sun, 3 Dec 2023 17:26:55 +0800 Subject: [PATCH 2450/7721] RDMA/siw: Call orq_get_current if possible Use orq_get_current() in siw_orq_empty(). Link: https://lore.kernel.org/r/20231203092655.28102-5-guoqing.jiang@linux.dev Acked-by: Bernard Metzler Signed-off-by: Guoqing Jiang Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index 2edba2a864bb..75253f2b3e3d 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -657,7 +657,7 @@ static inline struct siw_sqe *orq_get_free(struct siw_qp *qp) static inline int siw_orq_empty(struct siw_qp *qp) { - return qp->orq[qp->orq_get % qp->attrs.orq_size].flags == 0 ? 1 : 0; + return orq_get_current(qp)->flags == 0 ? 1 : 0; } static inline struct siw_sqe *irq_alloc_free(struct siw_qp *qp) From 46b1f1b839cad600de3ad7ed999bd0155c528746 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:25 +0200 Subject: [PATCH 2451/7721] drm/msm/dpu: populate SSPP scaler block version The function _dpu_hw_sspp_setup_scaler3() passes and dpu_hw_setup_scaler3() uses scaler_blk.version to determine in which way the scaler (QSEED3) block should be programmed. However up to now we were not setting this field. Set it now, splitting the vig_sblk data which has different version fields. Reported-by: Marijn Suijten Fixes: 9b6f4fedaac2 ("drm/msm/dpu: Add SM6125 support") Fixes: 27f0df03f3ff ("drm/msm/dpu: Add SM6375 support") Fixes: 3186acba5cdc ("drm/msm/dpu: Add SM6350 support") Fixes: efcd0107727c ("drm/msm/dpu: add support for SM8550") Fixes: 4a352c2fc15a ("drm/msm/dpu: Introduce SC8280XP") Fixes: 0e91bcbb0016 ("drm/msm/dpu: Add SM8350 to hw catalog") Fixes: 100d7ef6995d ("drm/msm/dpu: add support for SM8450") Fixes: 3581b7062cec ("drm/msm/disp/dpu1: add support for display on SM6115") Fixes: dabfdd89eaa9 ("drm/msm/disp/dpu1: add inline rotation support for sc7280") Fixes: f3af2d6ee9ab ("drm/msm/dpu: Add SC8180x to hw catalog") Fixes: 94391a14fc27 ("drm/msm/dpu1: Add MSM8998 to hw catalog") Fixes: af776a3e1c30 ("drm/msm/dpu: add SM8250 to hw catalog") Fixes: 386fced3f76f ("drm/msm/dpu: add SM8150 to hw catalog") Fixes: b75ab05a3479 ("msm:disp:dpu1: add scaler support on SC7180 display") Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support") Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570098/ Link: https://lore.kernel.org/r/20231201234234.2065610-2-dmitry.baryshkov@linaro.org --- .../msm/disp/dpu1/catalog/dpu_5_0_sm8150.h | 8 +- .../msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h | 8 +- .../msm/disp/dpu1/catalog/dpu_8_1_sm8450.h | 8 +- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 95 ++++++++++++++----- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 3 +- 5 files changed, 87 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index 9392ad2b4d3f..c022e57864a4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -77,7 +77,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_0, + .sblk = &sm8150_vig_sblk_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -85,7 +85,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_1, + .sblk = &sm8150_vig_sblk_1, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -93,7 +93,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_2, + .sblk = &sm8150_vig_sblk_2, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -101,7 +101,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_3, + .sblk = &sm8150_vig_sblk_3, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index 9ffc8804a6fc..cb0758f0829d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -76,7 +76,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_0, + .sblk = &sm8150_vig_sblk_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -84,7 +84,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_1, + .sblk = &sm8150_vig_sblk_1, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -92,7 +92,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_2, + .sblk = &sm8150_vig_sblk_2, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -100,7 +100,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_3, + .sblk = &sm8150_vig_sblk_3, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index d18145c226da..72b0f547242f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -76,7 +76,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_0, + .sblk = &sm8450_vig_sblk_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -84,7 +84,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_1, + .sblk = &sm8450_vig_sblk_1, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -92,7 +92,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_2, + .sblk = &sm8450_vig_sblk_2, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -100,7 +100,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_3, + .sblk = &sm8450_vig_sblk_3, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index a1aada630780..7056c08b9957 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -249,14 +249,17 @@ static const uint32_t wb2_formats[] = { * SSPP sub blocks config *************************************************************/ +#define SSPP_SCALER_VER(maj, min) (((maj) << 16) | (min)) + /* SSPP common configuration */ -#define _VIG_SBLK(sdma_pri, qseed_ver) \ +#define _VIG_SBLK(sdma_pri, qseed_ver, scaler_ver) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ .id = qseed_ver, \ + .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ .id = DPU_SSPP_CSC_10BIT, \ @@ -268,13 +271,14 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = NULL, \ } -#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, rot_cfg) \ +#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, scaler_ver, rot_cfg) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ .id = qseed_ver, \ + .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ .id = DPU_SSPP_CSC_10BIT, \ @@ -298,13 +302,17 @@ static const uint32_t wb2_formats[] = { } static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 2)); static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { .rot_maxheight = 1088, @@ -313,13 +321,30 @@ static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { }; static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3); + _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 3)); + +static const struct dpu_sspp_sub_blks sm8150_vig_sblk_0 = + _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 4)); +static const struct dpu_sspp_sub_blks sm8150_vig_sblk_1 = + _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 4)); +static const struct dpu_sspp_sub_blks sm8150_vig_sblk_2 = + _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 4)); +static const struct dpu_sspp_sub_blks sm8150_vig_sblk_3 = + _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, + SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(1); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(2); @@ -327,34 +352,60 @@ static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(3); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(4); static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = - _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = - _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, &dpu_rot_sc7280_cfg_v2); + _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0), + &dpu_rot_sc7280_cfg_v2); static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = - _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = - _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE); + _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE, + SSPP_SCALER_VER(2, 4)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 0)); + +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = + _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 1)); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = + _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 1)); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = + _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 1)); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = + _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = - _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = - _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4); + _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4, + SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(5); static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(6); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index df024e10d3a3..62445075306a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -265,7 +265,8 @@ enum { /** * struct dpu_scaler_blk: Scaler information * @info: HW register and features supported by this sub-blk - * @version: qseed block revision + * @version: qseed block revision, on QSEED3+ platforms this is the value of + * scaler_blk.base + QSEED3_HW_VERSION registers. */ struct dpu_scaler_blk { DPU_HW_SUBBLK_INFO; From 07b852c91cbe2c9985d218ab7e2dd1ba51beb9e6 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 2 Dec 2023 01:40:26 +0200 Subject: [PATCH 2452/7721] drm/msm/dpu: Drop unused get_scaler_ver callback from SSPP This pointer callback is never used and should be removed. Signed-off-by: Marijn Suijten Reviewed-by: Dmitry Baryshkov [DB: dropped the helpers completely, which are unused now] Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570096/ Link: https://lore.kernel.org/r/20231201234234.2065610-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 13 +------------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 6 ------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 6 ------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 3 --- 4 files changed, 1 insertion(+), 27 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 8e3c65989c49..b408d456c123 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -395,15 +395,6 @@ static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx, format); } -static u32 _dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_sspp *ctx) -{ - if (!ctx) - return 0; - - return dpu_hw_get_scaler3_ver(&ctx->hw, - ctx->cap->sblk->scaler_blk.base); -} - /* * dpu_hw_sspp_setup_rects() */ @@ -616,10 +607,8 @@ static void _setup_layer_ops(struct dpu_hw_sspp *c, if (test_bit(DPU_SSPP_SCALER_QSEED3, &features) || test_bit(DPU_SSPP_SCALER_QSEED3LITE, &features) || - test_bit(DPU_SSPP_SCALER_QSEED4, &features)) { + test_bit(DPU_SSPP_SCALER_QSEED4, &features)) c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; - c->ops.get_scaler_ver = _dpu_hw_sspp_get_scaler3_ver; - } if (test_bit(DPU_SSPP_CDP, &features)) c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index f93969fddb22..b094ea23ad32 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -296,12 +296,6 @@ struct dpu_hw_sspp_ops { struct dpu_hw_scaler3_cfg *scaler3_cfg, const struct dpu_format *format); - /** - * get_scaler_ver - get scaler h/w version - * @ctx: Pointer to pipe context - */ - u32 (*get_scaler_ver)(struct dpu_hw_sspp *ctx); - /** * setup_cdp - setup client driven prefetch * @pipe: Pointer to software pipe context diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index 18b16b2d2bf5..0b05061e3e62 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -381,12 +381,6 @@ void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, DPU_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); } -u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, - u32 scaler_offset) -{ - return DPU_REG_READ(c, QSEED3_HW_VERSION + scaler_offset); -} - void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, const struct dpu_csc_cfg *data, bool csc10) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index 4bea139081bc..fe083b2e5696 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -340,9 +340,6 @@ void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, u32 scaler_offset, u32 scaler_version, const struct dpu_format *format); -u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, - u32 scaler_offset); - void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, const struct dpu_csc_cfg *data, bool csc10); From 88fc981f8ef232848fb60f77660a27826ea518ef Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 2 Dec 2023 01:40:27 +0200 Subject: [PATCH 2453/7721] drm/msm/dpu: Drop unused qseed_type from catalog dpu_caps The SSPP scaler subblk is responsible for reporting its version (via the .id field, feature bits on the parent SSPP block, and since recently also from reading a register to supersede a read-but-unset version field in the catalog), leaving this global qseed_type field logically unused. Remove this dead code to lighten the catalog and bringup-overhead. Signed-off-by: Marijn Suijten Reviewed-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570109/ Link: https://lore.kernel.org/r/20231201234234.2065610-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h | 1 - drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 2 -- 15 files changed, 16 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index aa1867943c9f..4dcc9f804ac1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -10,7 +10,6 @@ static const struct dpu_caps msm8998_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 38ac0c1a134b..03159d359500 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -10,7 +10,6 @@ static const struct dpu_caps sdm845_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index c022e57864a4..4184c18d81f3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8150_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index cb0758f0829d..83fb7312bc97 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc8180x_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 94278a3e3483..885a2bec8258 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8250_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index c0d88ddccb28..c9d1f1292b3d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc7180_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x9, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 57ce14c18def..320b8f23364f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm6115_dpu_caps = { .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, .max_mixer_blendstages = 0x4, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2160, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h index 62db84bd15f2..6c6bc754aeb7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h @@ -11,7 +11,6 @@ static const struct dpu_caps sm6350_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h index 5a3aad364c78..77703f663e25 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h @@ -11,7 +11,6 @@ static const struct dpu_caps sm6375_dpu_caps = { .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, .max_mixer_blendstages = 0x4, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2160, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 5aaa24281906..03181ba891d5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8350_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 15942fa5a8e0..42bb47181ba1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc7280_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2400, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 1ccd1edd693c..6da122df0b88 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc8280xp_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 11, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 72b0f547242f..330d48b1ea02 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8450_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 69b80af6566a..2b5b342ea0b2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8550_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 62445075306a..1bf2d2d64f2a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -342,7 +342,6 @@ struct dpu_rotation_cfg { * @max_mixer_width max layer mixer line width support. * @max_mixer_blendstages max layer mixer blend stages or * supported z order - * @qseed_type qseed2 or qseed3 support. * @has_src_split source split feature status * @has_dim_layer dim layer feature status * @has_idle_pc indicate if idle power collapse feature is supported @@ -355,7 +354,6 @@ struct dpu_rotation_cfg { struct dpu_caps { u32 max_mixer_width; u32 max_mixer_blendstages; - u32 qseed_type; bool has_src_split; bool has_dim_layer; bool has_idle_pc; From 6876059d7edfcce3d8946f5a49d65ba9b38b1bab Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:28 +0200 Subject: [PATCH 2454/7721] drm/msm/dpu: drop the `id' field from DPU_HW_SUBBLK_INFO The field `id' is not used for subblocks. The handling code usually knows, which sub-block it is now looking at. Drop the field completely. Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570100/ Link: https://lore.kernel.org/r/20231201234234.2065610-5-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 76 +++++++++---------- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 2 - 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 7056c08b9957..eb9dfdcf610e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -252,17 +252,15 @@ static const uint32_t wb2_formats[] = { #define SSPP_SCALER_VER(maj, min) (((maj) << 16) | (min)) /* SSPP common configuration */ -#define _VIG_SBLK(sdma_pri, qseed_ver, scaler_ver) \ +#define _VIG_SBLK(sdma_pri, scaler_ver) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ - .id = qseed_ver, \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ - .id = DPU_SSPP_CSC_10BIT, \ .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ @@ -271,17 +269,15 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = NULL, \ } -#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, scaler_ver, rot_cfg) \ +#define _VIG_SBLK_ROT(sdma_pri, scaler_ver, rot_cfg) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ - .id = qseed_ver, \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ - .id = DPU_SSPP_CSC_10BIT, \ .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ @@ -302,16 +298,16 @@ static const uint32_t wb2_formats[] = { } static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(0, SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(0, SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(0, SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(0, SSPP_SCALER_VER(1, 2)); static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { @@ -321,29 +317,29 @@ static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { }; static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(5, SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(6, SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(7, SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(8, SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(5, SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(6, SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(7, SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, + _VIG_SBLK(8, SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(1); @@ -352,59 +348,59 @@ static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(3); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(4); static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = - _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(4, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = - _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK_ROT(4, SSPP_SCALER_VER(3, 0), &dpu_rot_sc7280_cfg_v2); static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = - _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(2, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = - _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE, + _VIG_SBLK(3, SSPP_SCALER_VER(2, 4)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(5, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(6, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(7, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(8, SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(5, SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(6, SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(7, SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(8, SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(7, SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(8, SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = - _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(9, SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = - _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4, + _VIG_SBLK(10, SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(5); static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(6); @@ -473,12 +469,12 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = { * DSPP sub blocks config *************************************************************/ static const struct dpu_dspp_sub_blks msm8998_dspp_sblk = { - .pcc = {.name = "pcc", .id = DPU_DSPP_PCC, .base = 0x1700, + .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x10007}, }; static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { - .pcc = {.name = "pcc", .id = DPU_DSPP_PCC, .base = 0x1700, + .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x40000}, }; @@ -486,19 +482,19 @@ static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { * PINGPONG sub blocks config *************************************************************/ static const struct dpu_pingpong_sub_blks sdm845_pp_sblk_te = { - .te2 = {.name = "te2", .id = DPU_PINGPONG_TE2, .base = 0x2000, .len = 0x0, + .te2 = {.name = "te2", .base = 0x2000, .len = 0x0, .version = 0x1}, - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .dither = {.name = "dither", .base = 0x30e0, .len = 0x20, .version = 0x10000}, }; static const struct dpu_pingpong_sub_blks sdm845_pp_sblk = { - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .dither = {.name = "dither", .base = 0x30e0, .len = 0x20, .version = 0x10000}, }; static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = { - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0xe0, + .dither = {.name = "dither", .base = 0xe0, .len = 0x20, .version = 0x20000}, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 1bf2d2d64f2a..3cf7d316b475 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -251,14 +251,12 @@ enum { /** * MACRO DPU_HW_SUBBLK_INFO - information of HW sub-block inside DPU * @name: string name for debug purposes - * @id: enum identifying this sub-block * @base: offset of this sub-block relative to the block * offset * @len register block length of this sub-block */ #define DPU_HW_SUBBLK_INFO \ char name[DPU_HW_BLK_NAME_LEN]; \ - u32 id; \ u32 base; \ u32 len From 01fc6c012fad314290af5cc9a8de3fb612ca67c4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:29 +0200 Subject: [PATCH 2455/7721] drm/msm/dpu: drop the `smart_dma_priority' field from struct dpu_sspp_sub_blks In preparation to deduplicating SSPP subblocks, drop the (unused) `smart_dma_priority' field from struct dpu_sspp_sub_blks. If it is needed later (e.g. for SmartDMA v1), it should be added to the SSPP declarations themselves. Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570103/ Link: https://lore.kernel.org/r/20231201234234.2065610-6-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 112 +++++++----------- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 2 - 2 files changed, 40 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index eb9dfdcf610e..4179174ee4ee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -252,11 +252,10 @@ static const uint32_t wb2_formats[] = { #define SSPP_SCALER_VER(maj, min) (((maj) << 16) | (min)) /* SSPP common configuration */ -#define _VIG_SBLK(sdma_pri, scaler_ver) \ +#define _VIG_SBLK(scaler_ver) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ - .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ @@ -269,11 +268,10 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = NULL, \ } -#define _VIG_SBLK_ROT(sdma_pri, scaler_ver, rot_cfg) \ +#define _VIG_SBLK_ROT(scaler_ver, rot_cfg) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ - .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ @@ -286,11 +284,10 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = rot_cfg, \ } -#define _DMA_SBLK(sdma_pri) \ +#define _DMA_SBLK() \ { \ .maxdwnscale = SSPP_UNITY_SCALE, \ .maxupscale = SSPP_UNITY_SCALE, \ - .smart_dma_priority = sdma_pri, \ .format_list = plane_formats, \ .num_formats = ARRAY_SIZE(plane_formats), \ .virt_format_list = plane_formats, \ @@ -298,17 +295,13 @@ static const uint32_t wb2_formats[] = { } static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = - _VIG_SBLK(0, - SSPP_SCALER_VER(1, 2)); + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = - _VIG_SBLK(0, - SSPP_SCALER_VER(1, 2)); + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = - _VIG_SBLK(0, - SSPP_SCALER_VER(1, 2)); + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = - _VIG_SBLK(0, - SSPP_SCALER_VER(1, 2)); + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { .rot_maxheight = 1088, @@ -317,107 +310,82 @@ static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { }; static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = - _VIG_SBLK(5, - SSPP_SCALER_VER(1, 3)); + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = - _VIG_SBLK(6, - SSPP_SCALER_VER(1, 3)); + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = - _VIG_SBLK(7, - SSPP_SCALER_VER(1, 3)); + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = - _VIG_SBLK(8, - SSPP_SCALER_VER(1, 3)); + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_0 = - _VIG_SBLK(5, - SSPP_SCALER_VER(1, 4)); + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_1 = - _VIG_SBLK(6, - SSPP_SCALER_VER(1, 4)); + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_2 = - _VIG_SBLK(7, - SSPP_SCALER_VER(1, 4)); + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); static const struct dpu_sspp_sub_blks sm8150_vig_sblk_3 = - _VIG_SBLK(8, - SSPP_SCALER_VER(1, 4)); + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(1); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(2); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(3); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(4); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(); static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = - _VIG_SBLK(4, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = - _VIG_SBLK_ROT(4, - SSPP_SCALER_VER(3, 0), + _VIG_SBLK_ROT(SSPP_SCALER_VER(3, 0), &dpu_rot_sc7280_cfg_v2); static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = - _VIG_SBLK(2, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = - _VIG_SBLK(3, - SSPP_SCALER_VER(2, 4)); + _VIG_SBLK(SSPP_SCALER_VER(2, 4)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = - _VIG_SBLK(5, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = - _VIG_SBLK(6, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = - _VIG_SBLK(7, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = - _VIG_SBLK(8, - SSPP_SCALER_VER(3, 0)); + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = - _VIG_SBLK(5, - SSPP_SCALER_VER(3, 1)); + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = - _VIG_SBLK(6, - SSPP_SCALER_VER(3, 1)); + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = - _VIG_SBLK(7, - SSPP_SCALER_VER(3, 1)); + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = - _VIG_SBLK(8, - SSPP_SCALER_VER(3, 1)); + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = - _VIG_SBLK(7, - SSPP_SCALER_VER(3, 2)); + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = - _VIG_SBLK(8, - SSPP_SCALER_VER(3, 2)); + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = - _VIG_SBLK(9, - SSPP_SCALER_VER(3, 2)); + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = - _VIG_SBLK(10, - SSPP_SCALER_VER(3, 2)); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(5); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(6); + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); +static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(); +static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(); -#define _VIG_SBLK_NOSCALE(sdma_pri) \ +#define _VIG_SBLK_NOSCALE() \ { \ .maxdwnscale = SSPP_UNITY_SCALE, \ .maxupscale = SSPP_UNITY_SCALE, \ - .smart_dma_priority = sdma_pri, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ .virt_format_list = plane_formats, \ .virt_num_formats = ARRAY_SIZE(plane_formats), \ } -static const struct dpu_sspp_sub_blks qcm2290_vig_sblk_0 = _VIG_SBLK_NOSCALE(2); -static const struct dpu_sspp_sub_blks qcm2290_dma_sblk_0 = _DMA_SBLK(1); +static const struct dpu_sspp_sub_blks qcm2290_vig_sblk_0 = _VIG_SBLK_NOSCALE(); +static const struct dpu_sspp_sub_blks qcm2290_dma_sblk_0 = _DMA_SBLK(); /************************************************************* * MIXER sub blocks config diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 3cf7d316b475..b2a9b2cf2c05 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -368,7 +368,6 @@ struct dpu_caps { * common: Pointer to common configurations shared by sub blocks * @maxdwnscale: max downscale ratio supported(without DECIMATION) * @maxupscale: maxupscale ratio supported - * @smart_dma_priority: hw priority of rect1 of multirect pipe * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps * @qseed_ver: qseed version * @scaler_blk: @@ -382,7 +381,6 @@ struct dpu_caps { struct dpu_sspp_sub_blks { u32 maxdwnscale; u32 maxupscale; - u32 smart_dma_priority; u32 max_per_pipe_bw; u32 qseed_ver; struct dpu_scaler_blk scaler_blk; From 0fd205412e1ee1f60f549269838119969f0883ad Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:30 +0200 Subject: [PATCH 2456/7721] drm/msm/dpu: deduplicate some (most) of SSPP sub-blocks As we have dropped the variadic parts of SSPP sub-blocks declarations, deduplicate them now, reducing memory cruft. Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570112/ Link: https://lore.kernel.org/r/20231201234234.2065610-7-dmitry.baryshkov@linaro.org --- .../msm/disp/dpu1/catalog/dpu_3_0_msm8998.h | 16 +- .../msm/disp/dpu1/catalog/dpu_4_0_sdm845.h | 16 +- .../msm/disp/dpu1/catalog/dpu_5_0_sm8150.h | 16 +- .../msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h | 16 +- .../msm/disp/dpu1/catalog/dpu_5_4_sm6125.h | 6 +- .../msm/disp/dpu1/catalog/dpu_6_0_sm8250.h | 16 +- .../msm/disp/dpu1/catalog/dpu_6_2_sc7180.h | 8 +- .../msm/disp/dpu1/catalog/dpu_6_3_sm6115.h | 4 +- .../msm/disp/dpu1/catalog/dpu_6_4_sm6350.h | 8 +- .../msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h | 4 +- .../msm/disp/dpu1/catalog/dpu_6_9_sm6375.h | 4 +- .../msm/disp/dpu1/catalog/dpu_7_0_sm8350.h | 16 +- .../msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 8 +- .../msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h | 16 +- .../msm/disp/dpu1/catalog/dpu_8_1_sm8450.h | 16 +- .../msm/disp/dpu1/catalog/dpu_9_0_sm8550.h | 20 +-- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 137 ++++++------------ 17 files changed, 140 insertions(+), 187 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index 4dcc9f804ac1..1d3e9666c741 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -69,7 +69,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -77,7 +77,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -85,7 +85,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -93,7 +93,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -101,7 +101,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1ac, .features = DMA_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -109,7 +109,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1ac, .features = DMA_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -117,7 +117,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1ac, .features = DMA_CURSOR_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -125,7 +125,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1ac, .features = DMA_CURSOR_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 03159d359500..7a23389a5732 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -67,7 +67,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1c8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1c8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1c8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1c8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index 4184c18d81f3..145f3d5953a3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -76,7 +76,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -84,7 +84,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -92,7 +92,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -100,7 +100,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -108,7 +108,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -116,7 +116,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -124,7 +124,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -132,7 +132,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index 83fb7312bc97..9e3bec8bc121 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sm8150_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h index cec7af6667dc..3969f2925d89 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h @@ -69,7 +69,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SM6125_MASK, - .sblk = &sm6125_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_2_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -77,7 +77,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -85,7 +85,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 885a2bec8258..f751d63845d1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index c9d1f1292b3d..7627f16c5b2d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -52,7 +52,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK, - .sblk = &sc7180_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -60,7 +60,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -68,7 +68,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -76,7 +76,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 320b8f23364f..7aefdb7eb494 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -39,7 +39,7 @@ static const struct dpu_sspp_cfg sm6115_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK, - .sblk = &sm6115_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -47,7 +47,7 @@ static const struct dpu_sspp_cfg sm6115_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h index 6c6bc754aeb7..99df9816f171 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h @@ -59,7 +59,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK, - .sblk = &sc7180_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -67,7 +67,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h index fb36fba5171c..3cbb2fe8aba2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h @@ -39,7 +39,7 @@ static const struct dpu_sspp_cfg qcm2290_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_QCM2290_MASK, - .sblk = &qcm2290_vig_sblk_0, + .sblk = &dpu_vig_sblk_noscale, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -47,7 +47,7 @@ static const struct dpu_sspp_cfg qcm2290_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &qcm2290_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h index 77703f663e25..2de304d97c9b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h @@ -40,7 +40,7 @@ static const struct dpu_sspp_cfg sm6375_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK, - .sblk = &sm6115_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -48,7 +48,7 @@ static const struct dpu_sspp_cfg sm6375_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 03181ba891d5..ad6eb28ead49 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -74,7 +74,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -82,7 +82,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -90,7 +90,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -98,7 +98,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -106,7 +106,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -114,7 +114,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -122,7 +122,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -130,7 +130,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 42bb47181ba1..93564e9e5fa5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -57,7 +57,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7280_MASK_SDMA, - .sblk = &sc7280_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0_rot_v2, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -65,7 +65,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -73,7 +73,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -81,7 +81,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 6da122df0b88..c2f1acd43524 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x2ac, .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x2ac, .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x2ac, .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x2ac, .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x2ac, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x2ac, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x2ac, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x2ac, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 330d48b1ea02..0559ef780661 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -75,7 +75,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8450_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -83,7 +83,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8450_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -91,7 +91,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8450_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -99,7 +99,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x32c, .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8450_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -107,7 +107,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x32c, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -115,7 +115,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x32c, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -123,7 +123,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x32c, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x32c, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 2b5b342ea0b2..f393d42317af 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -67,70 +67,70 @@ static const struct dpu_sspp_cfg sm8550_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x344, .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 0, .type = SSPP_TYPE_VIG, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x344, .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 4, .type = SSPP_TYPE_VIG, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x344, .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 8, .type = SSPP_TYPE_VIG, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x344, .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 12, .type = SSPP_TYPE_VIG, }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, }, { .name = "sspp_12", .id = SSPP_DMA4, .base = 0x2c000, .len = 0x344, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sm8550_dma_sblk_4, + .sblk = &dpu_dma_sblk, .xin_id = 14, .type = SSPP_TYPE_DMA, }, { .name = "sspp_13", .id = SSPP_DMA5, .base = 0x2e000, .len = 0x344, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sm8550_dma_sblk_5, + .sblk = &dpu_dma_sblk, .xin_id = 15, .type = SSPP_TYPE_DMA, }, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 4179174ee4ee..b8ea33d0f364 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -284,96 +284,6 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = rot_cfg, \ } -#define _DMA_SBLK() \ - { \ - .maxdwnscale = SSPP_UNITY_SCALE, \ - .maxupscale = SSPP_UNITY_SCALE, \ - .format_list = plane_formats, \ - .num_formats = ARRAY_SIZE(plane_formats), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ - } - -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(1, 2)); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(1, 2)); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(1, 2)); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(1, 2)); - -static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { - .rot_maxheight = 1088, - .rot_num_formats = ARRAY_SIZE(rotation_v2_formats), - .rot_format_list = rotation_v2_formats, -}; - -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(1, 3)); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(1, 3)); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(1, 3)); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(1, 3)); - -static const struct dpu_sspp_sub_blks sm8150_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(1, 4)); -static const struct dpu_sspp_sub_blks sm8150_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(1, 4)); -static const struct dpu_sspp_sub_blks sm8150_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(1, 4)); -static const struct dpu_sspp_sub_blks sm8150_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(1, 4)); - -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(); - -static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); - -static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = - _VIG_SBLK_ROT(SSPP_SCALER_VER(3, 0), - &dpu_rot_sc7280_cfg_v2); - -static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); - -static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(2, 4)); - -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(3, 0)); - -static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(3, 1)); -static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(3, 1)); -static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(3, 1)); -static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(3, 1)); - -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = - _VIG_SBLK(SSPP_SCALER_VER(3, 2)); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = - _VIG_SBLK(SSPP_SCALER_VER(3, 2)); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = - _VIG_SBLK(SSPP_SCALER_VER(3, 2)); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = - _VIG_SBLK(SSPP_SCALER_VER(3, 2)); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(); - #define _VIG_SBLK_NOSCALE() \ { \ .maxdwnscale = SSPP_UNITY_SCALE, \ @@ -384,8 +294,51 @@ static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(); .virt_num_formats = ARRAY_SIZE(plane_formats), \ } -static const struct dpu_sspp_sub_blks qcm2290_vig_sblk_0 = _VIG_SBLK_NOSCALE(); -static const struct dpu_sspp_sub_blks qcm2290_dma_sblk_0 = _DMA_SBLK(); +#define _DMA_SBLK() \ + { \ + .maxdwnscale = SSPP_UNITY_SCALE, \ + .maxupscale = SSPP_UNITY_SCALE, \ + .format_list = plane_formats, \ + .num_formats = ARRAY_SIZE(plane_formats), \ + .virt_format_list = plane_formats, \ + .virt_num_formats = ARRAY_SIZE(plane_formats), \ + } + +static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { + .rot_maxheight = 1088, + .rot_num_formats = ARRAY_SIZE(rotation_v2_formats), + .rot_format_list = rotation_v2_formats, +}; + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_noscale = + _VIG_SBLK_NOSCALE(); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_2 = + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_3 = + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_4 = + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_2_4 = + _VIG_SBLK(SSPP_SCALER_VER(2, 4)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_0 = + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_0_rot_v2 = + _VIG_SBLK_ROT(SSPP_SCALER_VER(3, 0), + &dpu_rot_sc7280_cfg_v2); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_1 = + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_2 = + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); + +static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK(); /************************************************************* * MIXER sub blocks config From aa83fa5bf6c78f77873954e757a2fd2dd1018c30 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:31 +0200 Subject: [PATCH 2457/7721] drm/msm/dpu: drop DPU_HW_SUBBLK_INFO macro As the subblock info is now mostly gone, inline and drop the macro DPU_HW_SUBBLK_INFO. Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570106/ Link: https://lore.kernel.org/r/20231201234234.2065610-8-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index b2a9b2cf2c05..f9586ddbafda 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -248,49 +248,51 @@ enum { u32 len; \ unsigned long features -/** - * MACRO DPU_HW_SUBBLK_INFO - information of HW sub-block inside DPU - * @name: string name for debug purposes - * @base: offset of this sub-block relative to the block - * offset - * @len register block length of this sub-block - */ -#define DPU_HW_SUBBLK_INFO \ - char name[DPU_HW_BLK_NAME_LEN]; \ - u32 base; \ - u32 len - /** * struct dpu_scaler_blk: Scaler information - * @info: HW register and features supported by this sub-blk + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block * @version: qseed block revision, on QSEED3+ platforms this is the value of * scaler_blk.base + QSEED3_HW_VERSION registers. */ struct dpu_scaler_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; u32 version; }; struct dpu_csc_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; }; /** * struct dpu_pp_blk : Pixel processing sub-blk information - * @info: HW register and features supported by this sub-blk + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block * @version: HW Algorithm version */ struct dpu_pp_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; u32 version; }; /** * struct dpu_dsc_blk - DSC Encoder sub-blk information - * @info: HW register and features supported by this sub-blk + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block */ struct dpu_dsc_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; }; /** From 2b98aa1d65581a34919ac159cbdc9c2a1b37a258 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:32 +0200 Subject: [PATCH 2458/7721] drm/msm/dpu: rewrite scaler and CSC presense checks In order to check whether the SSPP block has scaler and CSC subblocks the funcion dpu_plane_atomic_check_pipe() uses macros which enumerate all possible scaler and CSC features. Replace those checks with the scaler and CSC subblock length checks in order to be able to drop those two macros. Suggested-by: Abhinav Kumar Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570113/ Link: https://lore.kernel.org/r/20231201234234.2065610-9-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 15 --------------- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 4 ++-- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index b094ea23ad32..28e7d53bd191 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -21,21 +21,6 @@ struct dpu_hw_sspp; #define DPU_SSPP_ROT_90 BIT(3) #define DPU_SSPP_SOLID_FILL BIT(4) -/** - * Define all scaler feature bits in catalog - */ -#define DPU_SSPP_SCALER (BIT(DPU_SSPP_SCALER_RGB) | \ - BIT(DPU_SSPP_SCALER_QSEED2) | \ - BIT(DPU_SSPP_SCALER_QSEED3) | \ - BIT(DPU_SSPP_SCALER_QSEED3LITE) | \ - BIT(DPU_SSPP_SCALER_QSEED4)) - -/* - * Define all CSC feature bits in catalog - */ -#define DPU_SSPP_CSC_ANY (BIT(DPU_SSPP_CSC) | \ - BIT(DPU_SSPP_CSC_10BIT)) - /** * Component indices */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 1e0da38c6f2a..93365332bdac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -774,8 +774,8 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1; if (DPU_FORMAT_IS_YUV(fmt) && - (!(pipe->sspp->cap->features & DPU_SSPP_SCALER) || - !(pipe->sspp->cap->features & DPU_SSPP_CSC_ANY))) { + (!pipe->sspp->cap->sblk->scaler_blk.len || + !pipe->sspp->cap->sblk->csc_blk.len)) { DPU_DEBUG_PLANE(pdpu, "plane doesn't have scaler/csc for yuv\n"); return -EINVAL; From 193838acc1111a7001c9fc99af0a248f284ea79d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:33 +0200 Subject: [PATCH 2459/7721] drm/msm/dpu: merge DPU_SSPP_SCALER_QSEED3, QSEED3LITE, QSEED4 Three different features, DPU_SSPP_SCALER_QSEED3, QSEED3LITE and QSEED4 are all related to different versions of the same HW scaling block. Corresponding driver parts use scaler_blk.version to identify the correct way to program the hardware. In order to simplify the driver codepath, merge these three feature bits into QSEED3_COMPATIBLE bin. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570114/ Link: https://lore.kernel.org/r/20231201234234.2065610-10-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 8 ++++---- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 8 ++------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 9 ++------- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 3 +-- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index b8ea33d0f364..c24817b0e4e5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -22,19 +22,19 @@ BIT(DPU_SSPP_CSC_10BIT)) #define VIG_MSM8998_MASK \ - (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3)) + (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SDM845_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3)) + (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SDM845_MASK_SDMA \ (VIG_SDM845_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) #define VIG_SC7180_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED4)) + (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SM6125_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3LITE)) + (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SC7180_MASK_SDMA \ (VIG_SC7180_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index f9586ddbafda..d6b9000b63b0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -51,9 +51,7 @@ enum { /** * SSPP sub-blocks/features * @DPU_SSPP_SCALER_QSEED2, QSEED2 algorithm support - * @DPU_SSPP_SCALER_QSEED3, QSEED3 alogorithm support - * @DPU_SSPP_SCALER_QSEED3LITE, QSEED3 Lite alogorithm support - * @DPU_SSPP_SCALER_QSEED4, QSEED4 algorithm support + * @DPU_SSPP_SCALER_QSEED3_COMPATIBLE, QSEED3-compatible alogorithm support (includes QSEED3, QSEED3LITE and QSEED4) * @DPU_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes * @DPU_SSPP_CSC, Support of Color space converion * @DPU_SSPP_CSC_10BIT, Support of 10-bit Color space conversion @@ -71,9 +69,7 @@ enum { */ enum { DPU_SSPP_SCALER_QSEED2 = 0x1, - DPU_SSPP_SCALER_QSEED3, - DPU_SSPP_SCALER_QSEED3LITE, - DPU_SSPP_SCALER_QSEED4, + DPU_SSPP_SCALER_QSEED3_COMPATIBLE, DPU_SSPP_SCALER_RGB, DPU_SSPP_CSC, DPU_SSPP_CSC_10BIT, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index b408d456c123..26307d9fc81d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -605,9 +605,7 @@ static void _setup_layer_ops(struct dpu_hw_sspp *c, test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features)) c->ops.setup_multirect = dpu_hw_sspp_setup_multirect; - if (test_bit(DPU_SSPP_SCALER_QSEED3, &features) || - test_bit(DPU_SSPP_SCALER_QSEED3LITE, &features) || - test_bit(DPU_SSPP_SCALER_QSEED4, &features)) + if (test_bit(DPU_SSPP_SCALER_QSEED3_COMPATIBLE, &features)) c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; if (test_bit(DPU_SSPP_CDP, &features)) @@ -643,10 +641,7 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, cfg->len, kms); - if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED3LITE) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED2) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED4)) + if (sblk->scaler_blk.len) dpu_debugfs_create_regset32("scaler_blk", 0400, debugfs_root, sblk->scaler_blk.base + cfg->base, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 93365332bdac..4d7f3894f4d7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -470,8 +470,7 @@ static void _dpu_plane_setup_scaler3(struct dpu_hw_sspp *pipe_hw, scale_cfg->src_height[i] /= chroma_subsmpl_v; } - if (pipe_hw->cap->features & - BIT(DPU_SSPP_SCALER_QSEED4)) { + if (pipe_hw->cap->sblk->scaler_blk.version >= 0x3000) { scale_cfg->preload_x[i] = DPU_QSEED4_DEFAULT_PRELOAD_H; scale_cfg->preload_y[i] = DPU_QSEED4_DEFAULT_PRELOAD_V; } else { From 223fb06fbc26e42f9cdf0ca80fb575916548d74b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 01:40:34 +0200 Subject: [PATCH 2460/7721] drm/msm/gpu: drop duplicating VIG feature masks After folding QSEED3LITE and QSEED4 feature bits into QSEED3_COMPATIBLE several VIG feature masks became equal. Drop these duplicates. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570107/ Link: https://lore.kernel.org/r/20231201234234.2065610-11-dmitry.baryshkov@linaro.org --- .../gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h | 2 +- .../gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h | 8 ++++---- .../gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h | 2 +- .../gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h | 2 +- .../gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h | 2 +- .../gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h | 2 +- .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h | 8 ++++---- .../gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h | 8 ++++---- .../gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h | 8 ++++---- .../gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h | 8 ++++---- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 11 +---------- 11 files changed, 26 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h index 3969f2925d89..76b2ec0d2489 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h @@ -68,7 +68,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, - .features = VIG_SM6125_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_2_4, .xin_id = 0, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index f751d63845d1..9acf07108899 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -74,7 +74,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -82,7 +82,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -90,7 +90,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -98,7 +98,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index 7627f16c5b2d..783269c6ead1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -51,7 +51,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 7aefdb7eb494..43f64a005f5a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -38,7 +38,7 @@ static const struct dpu_sspp_cfg sm6115_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h index 99df9816f171..e17a30be7525 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h @@ -58,7 +58,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h index 2de304d97c9b..a06c8634d2d7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h @@ -39,7 +39,7 @@ static const struct dpu_sspp_cfg sm6375_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index ad6eb28ead49..bed87250e68c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -73,7 +73,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -81,7 +81,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -89,7 +89,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -97,7 +97,7 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index c2f1acd43524..8b5c5031e2d9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -74,7 +74,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x2ac, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -82,7 +82,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x2ac, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -90,7 +90,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x2ac, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -98,7 +98,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x2ac, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 0559ef780661..7a647e1f729d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -74,7 +74,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x32c, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 0, .type = SSPP_TYPE_VIG, @@ -82,7 +82,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x32c, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 4, .type = SSPP_TYPE_VIG, @@ -90,7 +90,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x32c, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 8, .type = SSPP_TYPE_VIG, @@ -98,7 +98,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x32c, - .features = VIG_SC7180_MASK_SDMA, + .features = VIG_SDM845_MASK_SDMA, .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 12, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index f393d42317af..bf56265967c0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -66,28 +66,28 @@ static const struct dpu_sspp_cfg sm8550_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x344, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 0, .type = SSPP_TYPE_VIG, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x344, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 4, .type = SSPP_TYPE_VIG, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x344, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 8, .type = SSPP_TYPE_VIG, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x344, - .features = VIG_SC7180_MASK, + .features = VIG_SDM845_MASK, .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 12, .type = SSPP_TYPE_VIG, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index c24817b0e4e5..ec10f68cf0b2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -30,15 +30,6 @@ #define VIG_SDM845_MASK_SDMA \ (VIG_SDM845_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) -#define VIG_SC7180_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) - -#define VIG_SM6125_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) - -#define VIG_SC7180_MASK_SDMA \ - (VIG_SC7180_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) - #define VIG_QCM2290_MASK (VIG_BASE_MASK | BIT(DPU_SSPP_QOS_8LVL)) #define DMA_MSM8998_MASK \ @@ -47,7 +38,7 @@ BIT(DPU_SSPP_CDP) | BIT(DPU_SSPP_EXCL_RECT)) #define VIG_SC7280_MASK \ - (VIG_SC7180_MASK | BIT(DPU_SSPP_INLINE_ROTATION)) + (VIG_SDM845_MASK | BIT(DPU_SSPP_INLINE_ROTATION)) #define VIG_SC7280_MASK_SDMA \ (VIG_SC7280_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) From bf5a806953118e02accfcaa6f56b1c8b488a0396 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 16 Oct 2023 22:18:08 -0400 Subject: [PATCH 2461/7721] dt-bindings: display/msm: dsi-controller-main: add SDM670 compatible The SDM670 has DSI ports. Add the compatible for the controller. Acked-by: Rob Herring Signed-off-by: Richard Acayan Patchwork: https://patchwork.freedesktop.org/patch/562958/ Link: https://lore.kernel.org/r/20231017021805.1083350-10-mailingradian@gmail.com Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/dsi-controller-main.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index c6dbab65d5f7..887c7dcaf438 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -25,6 +25,7 @@ properties: - qcom,sc7180-dsi-ctrl - qcom,sc7280-dsi-ctrl - qcom,sdm660-dsi-ctrl + - qcom,sdm670-dsi-ctrl - qcom,sdm845-dsi-ctrl - qcom,sm6115-dsi-ctrl - qcom,sm6125-dsi-ctrl From 0e1af3ec823bdb99007aedffa41e711573378839 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 16 Oct 2023 22:18:09 -0400 Subject: [PATCH 2462/7721] dt-bindings: display/msm: sdm845-dpu: Describe SDM670 The SDM670 display controller has the same requirements as the SDM845 display controller, despite having distinct properties as described in the catalog. Add the compatible for SDM670 to the SDM845 controller. Acked-by: Rob Herring Signed-off-by: Richard Acayan Patchwork: https://patchwork.freedesktop.org/patch/562959/ Link: https://lore.kernel.org/r/20231017021805.1083350-11-mailingradian@gmail.com Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml index b917064bdf33..dc11fd421a27 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml @@ -13,7 +13,9 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - const: qcom,sdm845-dpu + enum: + - qcom,sdm670-dpu + - qcom,sdm845-dpu reg: items: From c965007970ed918203a375e55bca874956c67d68 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 16 Oct 2023 22:18:10 -0400 Subject: [PATCH 2463/7721] dt-bindings: display: msm: Add SDM670 MDSS Add documentation for the SDM670 display subsystem, adapted from the SDM845 and SM6125 documentation. Reviewed-by: Rob Herring Signed-off-by: Richard Acayan Patchwork: https://patchwork.freedesktop.org/patch/562961/ Link: https://lore.kernel.org/r/20231017021805.1083350-12-mailingradian@gmail.com Signed-off-by: Dmitry Baryshkov --- .../display/msm/qcom,sdm670-mdss.yaml | 292 ++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml new file mode 100644 index 000000000000..7dc269322b8e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml @@ -0,0 +1,292 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sdm670-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM670 Display MDSS + +maintainers: + - Richard Acayan + +description: + SDM670 MSM Mobile Display Subsystem (MDSS), which encapsulates sub-blocks + like DPU display controller, DSI and DP interfaces etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sdm670-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: core + + iommus: + maxItems: 2 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,sdm670-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,sdm670-dp + + "^dsi@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,sdm670-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,dsi-phy-10nm + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sdm670-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc MDSS_GDSC>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP_PORT0 0 &mem_noc SLAVE_EBI_CH0 0>, + <&mmss_noc MASTER_MDP_PORT1 0 &mem_noc SLAVE_EBI_CH0 0>; + interconnect-names = "mdp0-mem", "mdp1-mem"; + + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sdm670-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SDM670_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&mdss_dsi1_in>; + }; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,sdm670-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&mdss_dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94a00 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + + dsi@ae96000 { + compatible = "qcom,sdm670-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi1_out: endpoint { + }; + }; + }; + }; + + mdss_dsi1_phy: phy@ae96400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae96400 0x200>, + <0x0ae96600 0x280>, + <0x0ae96a00 0x10e>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + }; +... From 3c13a56e435348ffc094ff5a3b3133311673390e Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 16 Oct 2023 22:18:11 -0400 Subject: [PATCH 2464/7721] drm/msm: mdss: add support for SDM670 Add support for the MDSS block on the SDM670 platform. Reviewed-by: Dmitry Baryshkov Signed-off-by: Richard Acayan Patchwork: https://patchwork.freedesktop.org/patch/562963/ Link: https://lore.kernel.org/r/20231017021805.1083350-13-mailingradian@gmail.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_mdss.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 29bb38f0bb2c..6f390c850577 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -549,6 +549,12 @@ static const struct msm_mdss_data sc8280xp_data = { .macrotile_mode = 1, }; +static const struct msm_mdss_data sdm670_data = { + .ubwc_enc_version = UBWC_2_0, + .ubwc_dec_version = UBWC_2_0, + .highest_bank_bit = 1, +}; + static const struct msm_mdss_data sdm845_data = { .ubwc_enc_version = UBWC_2_0, .ubwc_dec_version = UBWC_2_0, @@ -607,6 +613,7 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss" }, { .compatible = "qcom,msm8998-mdss", .data = &msm8998_data }, { .compatible = "qcom,qcm2290-mdss", .data = &qcm2290_data }, + { .compatible = "qcom,sdm670-mdss", .data = &sdm670_data }, { .compatible = "qcom,sdm845-mdss", .data = &sdm845_data }, { .compatible = "qcom,sc7180-mdss", .data = &sc7180_data }, { .compatible = "qcom,sc7280-mdss", .data = &sc7280_data }, From e140b7e496b73c116454b0a0265bec4cacc9ca40 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 16 Oct 2023 22:18:12 -0400 Subject: [PATCH 2465/7721] drm/msm/dpu: Add hw revision 4.1 (SDM670) The Snapdragon 670 uses similar clocks (with one frequency added) to the Snapdragon 845 but reports DPU revision 4.1. Add support for this DPU with configuration from the Pixel 3a downstream kernel. Since revision 4.0 is SDM845, reuse some configuration from its catalog entry. Link: https://android.googlesource.com/kernel/msm/+/368478b0ae76566927a2769a2bf24dfe7f38bb78/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi Signed-off-by: Richard Acayan Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/562965/ Link: https://lore.kernel.org/r/20231017021805.1083350-14-mailingradian@gmail.com Signed-off-by: Dmitry Baryshkov --- .../msm/disp/dpu1/catalog/dpu_4_1_sdm670.h | 104 ++++++++++++++++++ .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 1 + .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 + 4 files changed, 107 insertions(+) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h new file mode 100644 index 000000000000..cbbdaebe357e --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Richard Acayan. All rights reserved. + */ + +#ifndef _DPU_4_1_SDM670_H +#define _DPU_4_1_SDM670_H + +static const struct dpu_mdp_cfg sdm670_mdp = { + .name = "top_0", + .base = 0x0, .len = 0x45c, + .features = BIT(DPU_MDP_AUDIO_SELECT), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + }, +}; + +static const struct dpu_sspp_cfg sdm670_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x1c8, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_1_3, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x1c8, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_1_3, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x1c8, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x1c8, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA1, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x1c8, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA2, + }, +}; + +static const struct dpu_dsc_cfg sdm670_dsc[] = { + { + .name = "dsc_0", .id = DSC_0, + .base = 0x80000, .len = 0x140, + }, { + .name = "dsc_1", .id = DSC_1, + .base = 0x80400, .len = 0x140, + }, +}; + +static const struct dpu_mdss_version sdm670_mdss_ver = { + .core_major_ver = 4, + .core_minor_ver = 1, +}; + +const struct dpu_mdss_cfg dpu_sdm670_cfg = { + .mdss_ver = &sdm670_mdss_ver, + .caps = &sdm845_dpu_caps, + .mdp = &sdm670_mdp, + .ctl_count = ARRAY_SIZE(sdm845_ctl), + .ctl = sdm845_ctl, + .sspp_count = ARRAY_SIZE(sdm670_sspp), + .sspp = sdm670_sspp, + .mixer_count = ARRAY_SIZE(sdm845_lm), + .mixer = sdm845_lm, + .pingpong_count = ARRAY_SIZE(sdm845_pp), + .pingpong = sdm845_pp, + .dsc_count = ARRAY_SIZE(sdm670_dsc), + .dsc = sdm670_dsc, + .intf_count = ARRAY_SIZE(sdm845_intf), + .intf = sdm845_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .perf = &sdm845_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index ec10f68cf0b2..21aaa7cb5acd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -613,6 +613,7 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_3_0_msm8998.h" #include "catalog/dpu_4_0_sdm845.h" +#include "catalog/dpu_4_1_sdm670.h" #include "catalog/dpu_5_0_sm8150.h" #include "catalog/dpu_5_1_sc8180x.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index d6b9000b63b0..476214905e76 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -820,6 +820,7 @@ struct dpu_mdss_cfg { extern const struct dpu_mdss_cfg dpu_msm8998_cfg; extern const struct dpu_mdss_cfg dpu_sdm845_cfg; +extern const struct dpu_mdss_cfg dpu_sdm670_cfg; extern const struct dpu_mdss_cfg dpu_sm8150_cfg; extern const struct dpu_mdss_cfg dpu_sc8180x_cfg; extern const struct dpu_mdss_cfg dpu_sm8250_cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 9b2efd7acc87..4426033252ca 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1334,6 +1334,7 @@ static const struct dev_pm_ops dpu_pm_ops = { static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,msm8998-dpu", .data = &dpu_msm8998_cfg, }, { .compatible = "qcom,qcm2290-dpu", .data = &dpu_qcm2290_cfg, }, + { .compatible = "qcom,sdm670-dpu", .data = &dpu_sdm670_cfg, }, { .compatible = "qcom,sdm845-dpu", .data = &dpu_sdm845_cfg, }, { .compatible = "qcom,sc7180-dpu", .data = &dpu_sc7180_cfg, }, { .compatible = "qcom,sc7280-dpu", .data = &dpu_sc7280_cfg, }, From 0014a4ad6c084dd3af972d44f2b0d0146b65760d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:23 +0100 Subject: [PATCH 2466/7721] dt-bindings: display: msm-dsi-phy-7nm: document the SM8650 DSI PHY Document the DSI PHY on the SM8650 Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564970/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-1-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml index dd6619555a12..7e764eac3ef3 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml @@ -22,6 +22,7 @@ properties: - qcom,sm8350-dsi-phy-5nm - qcom,sm8450-dsi-phy-5nm - qcom,sm8550-dsi-phy-4nm + - qcom,sm8650-dsi-phy-4nm reg: items: From 8adc26fcebaedd6d9a61d7f17793569a90669142 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:24 +0100 Subject: [PATCH 2467/7721] dt-bindings: display: msm-dsi-controller-main: document the SM8650 DSI Controller Document the DSI Controller on the SM8650 Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564972/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-2-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/dsi-controller-main.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index 887c7dcaf438..4219936eda5a 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -36,6 +36,7 @@ properties: - qcom,sm8350-dsi-ctrl - qcom,sm8450-dsi-ctrl - qcom,sm8550-dsi-ctrl + - qcom,sm8650-dsi-ctrl - const: qcom,mdss-dsi-ctrl - enum: - qcom,dsi-ctrl-6g-qcm2290 @@ -334,6 +335,7 @@ allOf: - qcom,sm8350-dsi-ctrl - qcom,sm8450-dsi-ctrl - qcom,sm8550-dsi-ctrl + - qcom,sm8650-dsi-ctrl then: properties: clocks: From 3e135a7700f9d3a2a606d01934c53315fcedf5ac Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:25 +0100 Subject: [PATCH 2468/7721] dt-bindings: display: msm: document the SM8650 DPU Document the DPU Display Controller on the SM8650 Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564974/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-3-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/qcom,sm8650-dpu.yaml | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml new file mode 100644 index 000000000000..a01d15a03317 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8650-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 Display DPU + +maintainers: + - Neil Armstrong + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + const: qcom,sm8650-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display hf axi + - description: Display MDSS ahb + - description: Display lut + - description: Display core + - description: Display vsync + + clock-names: + items: + - const: nrt_bus + - const: iface + - const: lut + - const: core + - const: vsync + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc_axi_clk>, + <&dispcc_ahb_clk>, + <&dispcc_mdp_lut_clk>, + <&dispcc_mdp_clk>, + <&dispcc_vsync_clk>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc_vsync_clk>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; +... From cbcef056fa40e7e00f470e5d0873a906d0170470 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:26 +0100 Subject: [PATCH 2469/7721] dt-bindings: display: msm: document the SM8650 Mobile Display Subsystem Document the Mobile Display Subsystem (MDSS) on the SM8650 Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564982/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-4-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- .../display/msm/qcom,sm8650-mdss.yaml | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml new file mode 100644 index 000000000000..5638c1ea692e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml @@ -0,0 +1,322 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8650-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 Display MDSS + +maintainers: + - Neil Armstrong + +description: + SM8650 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like + DPU display controller, DSI and DP interfaces etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sm8650-mdss + + clocks: + items: + - description: Display AHB + - description: Display hf AXI + - description: Display core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dpu + + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + items: + - const: qcom,sm8650-dsi-ctrl + - const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dsi-phy-4nm + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sm8650-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + resets = <&dispcc_core_bcr>; + + power-domains = <&dispcc_gdsc>; + + clocks = <&gcc_ahb_clk>, + <&gcc_axi_clk>, + <&dispcc_mdp_clk>; + clock-names = "bus", "nrt_bus", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x1c00 0x2>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc_axi_clk>, + <&dispcc_ahb_clk>, + <&dispcc_mdp_lut_clk>, + <&dispcc_mdp_clk>, + <&dispcc_mdp_vsync_clk>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc_mdp_vsync_clk>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispc_byte_clk>, + <&dispcc_intf_clk>, + <&dispcc_pclk>, + <&dispcc_esc_clk>, + <&dispcc_ahb_clk>, + <&gcc_bus_clk>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc_byte_clk>, + <&dispcc_pclk>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + dsi0_phy: phy@ae94400 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0x0ae95000 0x200>, + <0x0ae95200 0x280>, + <0x0ae95500 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc_iface_clk>, + <&rpmhcc_ref_clk>; + clock-names = "iface", "ref"; + }; + + dsi@ae96000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispc_byte_clk>, + <&dispcc_intf_clk>, + <&dispcc_pclk>, + <&dispcc_esc_clk>, + <&dispcc_ahb_clk>, + <&gcc_bus_clk>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc_byte_clk>, + <&dispcc_pclk>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_out: endpoint { + }; + }; + }; + }; + + dsi1_phy: phy@ae96400 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0x0ae97000 0x200>, + <0x0ae97200 0x280>, + <0x0ae97500 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc_iface_clk>, + <&rpmhcc_ref_clk>; + clock-names = "iface", "ref"; + }; + }; +... From b94747f7d8c77e1b261afba8b8cdc9a56e35c9a3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:27 +0100 Subject: [PATCH 2470/7721] drm/msm/dpu: add support for SM8650 DPU Add DPU version 10.0 support for the SM8650 platform. Signed-off-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/564975/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-5-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- .../msm/disp/dpu1/catalog/dpu_10_0_sm8650.h | 457 ++++++++++++++++++ .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 26 + .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 3 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 + 5 files changed, 488 insertions(+) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h new file mode 100644 index 000000000000..04d2a73dd942 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h @@ -0,0 +1,457 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DPU_10_0_SM8650_H +#define _DPU_10_0_SM8650_H + +static const struct dpu_caps sm8650_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 8192, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg sm8650_mdp = { + .name = "top_0", + .base = 0, .len = 0x494, + .features = BIT(DPU_MDP_PERIPH_0_REMOVED), + .clk_ctrls = { + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +/* FIXME: get rid of DPU_CTL_SPLIT_DISPLAY in favour of proper ACTIVE_CTL support */ +static const struct dpu_ctl_cfg sm8650_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1000, + .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY), + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x1000, + .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY), + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_sspp_cfg sm8650_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_12", .id = SSPP_DMA4, + .base = 0x2c000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 14, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_13", .id = SSPP_DMA5, + .base = 0x2e000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 15, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg sm8650_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + }, { + .name = "lm_4", .id = LM_4, + .base = 0x48000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, +}; + +static const struct dpu_dspp_cfg sm8650_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x5a000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg sm8650_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x6d000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x6e000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x66000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x66400, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_8", .id = PINGPONG_8, + .base = 0x7e000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_9", .id = PINGPONG_9, + .base = 0x7e400, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, +}; + +static const struct dpu_merge_3d_cfg sm8650_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x8, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x8, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x50000, .len = 0x8, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x66700, .len = 0x8, + }, { + .name = "merge_3d_4", .id = MERGE_3D_4, + .base = 0x7e700, .len = 0x8, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. + */ +static const struct dpu_dsc_cfg sm8650_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x81000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x82000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x82000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_1, + }, +}; + +static const struct dpu_wb_cfg sm8650_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats, + .num_formats = ARRAY_SIZE(wb2_formats), + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +static const struct dpu_intf_cfg sm8650_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x35000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2), + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x36000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF2_TEAR_INTR, 2), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + }, +}; + +static const struct dpu_perf_cfg sm8650_perf_data = { + .max_bw_low = 17000000, + .max_bw_high = 27000000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + /* FIXME: lut tables */ + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version sm8650_mdss_ver = { + .core_major_ver = 10, + .core_minor_ver = 0, +}; + +const struct dpu_mdss_cfg dpu_sm8650_cfg = { + .mdss_ver = &sm8650_mdss_ver, + .caps = &sm8650_dpu_caps, + .mdp = &sm8650_mdp, + .ctl_count = ARRAY_SIZE(sm8650_ctl), + .ctl = sm8650_ctl, + .sspp_count = ARRAY_SIZE(sm8650_sspp), + .sspp = sm8650_sspp, + .mixer_count = ARRAY_SIZE(sm8650_lm), + .mixer = sm8650_lm, + .dspp_count = ARRAY_SIZE(sm8650_dspp), + .dspp = sm8650_dspp, + .pingpong_count = ARRAY_SIZE(sm8650_pp), + .pingpong = sm8650_pp, + .dsc_count = ARRAY_SIZE(sm8650_dsc), + .dsc = sm8650_dsc, + .merge_3d_count = ARRAY_SIZE(sm8650_merge_3d), + .merge_3d = sm8650_merge_3d, + .wb_count = ARRAY_SIZE(sm8650_wb), + .wb = sm8650_wb, + .intf_count = ARRAY_SIZE(sm8650_intf), + .intf = sm8650_intf, + .vbif_count = ARRAY_SIZE(sm8650_vbif), + .vbif = sm8650_vbif, + .perf = &sm8650_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 21aaa7cb5acd..d52aae54bbd5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -329,6 +329,9 @@ static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_1 = static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_2 = _VIG_SBLK(SSPP_SCALER_VER(3, 2)); +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_3 = + _VIG_SBLK(SSPP_SCALER_VER(3, 3)); + static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK(); /************************************************************* @@ -431,6 +434,7 @@ static const u32 msm8998_rt_pri_lvl[] = {1, 2, 2, 2}; static const u32 msm8998_nrt_pri_lvl[] = {1, 1, 1, 1}; static const u32 sdm845_rt_pri_lvl[] = {3, 3, 4, 4, 5, 5, 6, 6}; static const u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; +static const u32 sm8650_rt_pri_lvl[] = {4, 4, 5, 5, 5, 5, 5, 6}; static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { { @@ -517,6 +521,26 @@ static const struct dpu_vbif_cfg sm8550_vbif[] = { }, }; +static const struct dpu_vbif_cfg sm8650_vbif[] = { + { + .name = "vbif_rt", .id = VBIF_RT, + .base = 0, .len = 0x1074, + .features = BIT(DPU_VBIF_QOS_REMAP), + .xin_halt_timeout = 0x4000, + .qos_rp_remap_size = 0x40, + .qos_rt_tbl = { + .npriority_lvl = ARRAY_SIZE(sm8650_rt_pri_lvl), + .priority_lvl = sm8650_rt_pri_lvl, + }, + .qos_nrt_tbl = { + .npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl), + .priority_lvl = sdm845_nrt_pri_lvl, + }, + .memtype_count = 16, + .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + }, +}; + /************************************************************* * PERF data config *************************************************************/ @@ -633,3 +657,5 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_8_1_sm8450.h" #include "catalog/dpu_9_0_sm8550.h" + +#include "catalog/dpu_10_0_sm8650.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 476214905e76..e3c0d007481b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -835,5 +835,6 @@ extern const struct dpu_mdss_cfg dpu_sc7280_cfg; extern const struct dpu_mdss_cfg dpu_sc8280xp_cfg; extern const struct dpu_mdss_cfg dpu_sm8450_cfg; extern const struct dpu_mdss_cfg dpu_sm8550_cfg; +extern const struct dpu_mdss_cfg dpu_sm8650_cfg; #endif /* _DPU_HW_CATALOG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index d85157acfbf8..a6702b2bfc68 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -195,6 +195,8 @@ enum dpu_pingpong { PINGPONG_5, PINGPONG_6, PINGPONG_7, + PINGPONG_8, + PINGPONG_9, PINGPONG_S0, PINGPONG_MAX }; @@ -204,6 +206,7 @@ enum dpu_merge_3d { MERGE_3D_1, MERGE_3D_2, MERGE_3D_3, + MERGE_3D_4, MERGE_3D_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 4426033252ca..c1cb500adc07 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1349,6 +1349,7 @@ static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sm8350-dpu", .data = &dpu_sm8350_cfg, }, { .compatible = "qcom,sm8450-dpu", .data = &dpu_sm8450_cfg, }, { .compatible = "qcom,sm8550-dpu", .data = &dpu_sm8550_cfg, }, + { .compatible = "qcom,sm8650-dpu", .data = &dpu_sm8650_cfg, }, {} }; MODULE_DEVICE_TABLE(of, dpu_dt_match); From e6488c2a354103b6a3212f2fffa854e235d8a80e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:28 +0100 Subject: [PATCH 2471/7721] drm/msm: mdss: add support for SM8650 Add Mobile Display Subsystem (MDSS) support for the SM8650 platform. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564980/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-6-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_mdss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 6f390c850577..16b567a39b8b 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -628,6 +628,7 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,sm8350-mdss", .data = &sm8250_data }, { .compatible = "qcom,sm8450-mdss", .data = &sm8250_data }, { .compatible = "qcom,sm8550-mdss", .data = &sm8550_data }, + { .compatible = "qcom,sm8650-mdss", .data = &sm8550_data}, {} }; MODULE_DEVICE_TABLE(of, mdss_dt_match); From 3a73e376cff31c6cbc99f0e44068db3a769684d8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:29 +0100 Subject: [PATCH 2472/7721] drm/msm: dsi: add support for DSI-PHY on SM8650 Add DSI PHY support for the SM8650 platform. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564976/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-7-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 ++ drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 27 +++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index e49ebd9f6326..24a347fe2998 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -587,6 +587,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_5nm_8450_cfgs }, { .compatible = "qcom,sm8550-dsi-phy-4nm", .data = &dsi_phy_4nm_8550_cfgs }, + { .compatible = "qcom,sm8650-dsi-phy-4nm", + .data = &dsi_phy_4nm_8650_cfgs }, #endif {} }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 8b640d174785..e4275d3ad581 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -62,6 +62,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs; struct msm_dsi_dphy_timing { u32 clk_zero; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 3b1ed02f644d..c66193f2dc0d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -1121,6 +1121,10 @@ static const struct regulator_bulk_data dsi_phy_7nm_37750uA_regulators[] = { { .supply = "vdds", .init_load_uA = 37550 }, }; +static const struct regulator_bulk_data dsi_phy_7nm_98000uA_regulators[] = { + { .supply = "vdds", .init_load_uA = 98000 }, +}; + static const struct regulator_bulk_data dsi_phy_7nm_97800uA_regulators[] = { { .supply = "vdds", .init_load_uA = 97800 }, }; @@ -1281,3 +1285,26 @@ const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = { .num_dsi_phy = 2, .quirks = DSI_PHY_7NM_QUIRK_V5_2, }; + +const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_98000uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_regulators), + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + .set_continuous_clock = dsi_7nm_set_continuous_clock, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000UL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0xae95000, 0xae97000 }, + .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_V5_2, +}; From fec254cc752d0449714c026f021d3043abda15e5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 11:36:30 +0100 Subject: [PATCH 2473/7721] drm/msm: dsi: add support for DSI 2.8.0 Add DSI Controller version 2.8.0 support for the SM8650 platform. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Patchwork: https://patchwork.freedesktop.org/patch/564977/ Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-mdss-v2-8-43f1887c82b8@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 17 +++++++++++++++++ drivers/gpu/drm/msm/dsi/dsi_cfg.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 1f98ff74ceb0..10ba7d153d1c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -190,6 +190,21 @@ static const struct msm_dsi_config sm8550_dsi_cfg = { }, }; +static const struct regulator_bulk_data sm8650_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 16600 }, /* 1.2 V */ +}; + +static const struct msm_dsi_config sm8650_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .regulator_data = sm8650_dsi_regulators, + .num_regulators = ARRAY_SIZE(sm8650_dsi_regulators), + .bus_clk_names = dsi_v2_4_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_v2_4_clk_names), + .io_start = { + { 0xae94000, 0xae96000 }, + }, +}; + static const struct regulator_bulk_data sc7280_dsi_regulators[] = { { .supply = "vdda", .init_load_uA = 8350 }, /* 1.2 V */ { .supply = "refgen" }, @@ -281,6 +296,8 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_7_0, &sm8550_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_8_0, + &sm8650_dsi_cfg, &msm_dsi_6g_v2_host_ops}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 43f0dd74edb6..4c9b4b37681b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -28,6 +28,7 @@ #define MSM_DSI_6G_VER_MINOR_V2_5_0 0x20050000 #define MSM_DSI_6G_VER_MINOR_V2_6_0 0x20060000 #define MSM_DSI_6G_VER_MINOR_V2_7_0 0x20070000 +#define MSM_DSI_6G_VER_MINOR_V2_8_0 0x20080000 #define MSM_DSI_V2_VER_MINOR_8064 0x0 From ded61d7dc5a0f8cfe7390aba33187c862d09b177 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 01:42:44 +0300 Subject: [PATCH 2474/7721] drm/msm/mdss: switch mdss to use devm_of_icc_get() Stop using hand-written reset function for ICC release, use devm_of_icc_get() instead. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570161/ Link: https://lore.kernel.org/r/20231202224247.1282567-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/msm_mdss.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 16b567a39b8b..92a290b36959 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -50,14 +50,14 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, struct icc_path *path0; struct icc_path *path1; - path0 = of_icc_get(dev, "mdp0-mem"); + path0 = devm_of_icc_get(dev, "mdp0-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); msm_mdss->path[0] = path0; msm_mdss->num_paths = 1; - path1 = of_icc_get(dev, "mdp1-mem"); + path1 = devm_of_icc_get(dev, "mdp1-mem"); if (!IS_ERR_OR_NULL(path1)) { msm_mdss->path[1] = path1; msm_mdss->num_paths++; @@ -66,15 +66,6 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, return 0; } -static void msm_mdss_put_icc_path(void *data) -{ - struct msm_mdss *msm_mdss = data; - int i; - - for (i = 0; i < msm_mdss->num_paths; i++) - icc_put(msm_mdss->path[i]); -} - static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) { int i; @@ -391,9 +382,6 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); - if (ret) - return ERR_PTR(ret); - ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss); if (ret) return ERR_PTR(ret); From fabaf176322d687b91a4acf1630c0d0a7d097faa Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sun, 3 Dec 2023 01:42:45 +0300 Subject: [PATCH 2475/7721] drm/msm/mdss: Rename path references to mdp_path The DPU1 driver needs to handle all MDPn<->DDR paths, as well as CPU<->SLAVE_DISPLAY_CFG. The former ones share how their values are calculated, but the latter one has static predefines spanning all SoCs. In preparation for supporting the CPU<->SLAVE_DISPLAY_CFG path, rename the path-related struct members to include "mdp_". Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570163/ Link: https://lore.kernel.org/r/20231202224247.1282567-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/msm_mdss.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 92a290b36959..a1a077e2bac8 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -40,8 +40,8 @@ struct msm_mdss { struct irq_domain *domain; } irq_controller; const struct msm_mdss_data *mdss_data; - struct icc_path *path[2]; - u32 num_paths; + struct icc_path *mdp_path[2]; + u32 num_mdp_paths; }; static int msm_mdss_parse_data_bus_icc_path(struct device *dev, @@ -54,13 +54,13 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); - msm_mdss->path[0] = path0; - msm_mdss->num_paths = 1; + msm_mdss->mdp_path[0] = path0; + msm_mdss->num_mdp_paths = 1; path1 = devm_of_icc_get(dev, "mdp1-mem"); if (!IS_ERR_OR_NULL(path1)) { - msm_mdss->path[1] = path1; - msm_mdss->num_paths++; + msm_mdss->mdp_path[1] = path1; + msm_mdss->num_mdp_paths++; } return 0; @@ -70,8 +70,8 @@ static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) { int i; - for (i = 0; i < msm_mdss->num_paths; i++) - icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw)); + for (i = 0; i < msm_mdss->num_mdp_paths; i++) + icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(bw)); } static void msm_mdss_irq(struct irq_desc *desc) From 7323694e118a24ab954d3a16fe59a68b311cb462 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 01:42:46 +0300 Subject: [PATCH 2476/7721] drm/msm/mdss: inline msm_mdss_icc_request_bw() There are just two places where we set the bandwidth: in the resume and in the suspend paths. Drop the wrapping function msm_mdss_icc_request_bw() and call icc_set_bw() directly. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570168/ Link: https://lore.kernel.org/r/20231202224247.1282567-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/msm_mdss.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index a1a077e2bac8..776579ac69d8 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -66,14 +66,6 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, return 0; } -static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) -{ - int i; - - for (i = 0; i < msm_mdss->num_mdp_paths; i++) - icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(bw)); -} - static void msm_mdss_irq(struct irq_desc *desc) { struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc); @@ -227,14 +219,15 @@ const struct msm_mdss_data *msm_mdss_get_mdss_data(struct device *dev) static int msm_mdss_enable(struct msm_mdss *msm_mdss) { - int ret; + int ret, i; /* * Several components have AXI clocks that can only be turned on if * the interconnect is enabled (non-zero bandwidth). Let's make sure * that the interconnects are at least at a minimum amount. */ - msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW); + for (i = 0; i < msm_mdss->num_mdp_paths; i++) + icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(MIN_IB_BW)); ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); if (ret) { @@ -286,8 +279,12 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) static int msm_mdss_disable(struct msm_mdss *msm_mdss) { + int i; + clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); - msm_mdss_icc_request_bw(msm_mdss, 0); + + for (i = 0; i < msm_mdss->num_mdp_paths; i++) + icc_set_bw(msm_mdss->mdp_path[i], 0, 0); return 0; } From a55c8ff252d374acb6f78b979cadc38073ce95e8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 01:42:47 +0300 Subject: [PATCH 2477/7721] drm/msm/mdss: Handle the reg bus ICC path Apart from the already handled data bus (MAS_MDP_Pn<->DDR), there's another path that needs to be handled to ensure MDSS functions properly, namely the "reg bus", a.k.a the CPU-MDSS interconnect. Gating that path may have a variety of effects, from none to otherwise inexplicable DSI timeouts. Provide a way for MDSS driver to vote on this bus. A note regarding vote values. Newer platforms have corresponding bandwidth values in the vendor DT files. For the older platforms there was a static vote in the mdss_mdp and rotator drivers. I choose to be conservative here and choose this value as a default. Co-developed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/570164/ Link: https://lore.kernel.org/r/20231202224247.1282567-5-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/msm_mdss.c | 49 +++++++++++++++++++++++++++++++--- drivers/gpu/drm/msm/msm_mdss.h | 1 + 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 776579ac69d8..455b2e3a0cdd 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -28,6 +28,8 @@ #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ +#define DEFAULT_REG_BW 153600 /* Used in mdss fbdev driver */ + struct msm_mdss { struct device *dev; @@ -42,6 +44,7 @@ struct msm_mdss { const struct msm_mdss_data *mdss_data; struct icc_path *mdp_path[2]; u32 num_mdp_paths; + struct icc_path *reg_bus_path; }; static int msm_mdss_parse_data_bus_icc_path(struct device *dev, @@ -49,6 +52,7 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, { struct icc_path *path0; struct icc_path *path1; + struct icc_path *reg_bus_path; path0 = devm_of_icc_get(dev, "mdp0-mem"); if (IS_ERR_OR_NULL(path0)) @@ -63,6 +67,10 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, msm_mdss->num_mdp_paths++; } + reg_bus_path = of_icc_get(dev, "cpu-cfg"); + if (!IS_ERR_OR_NULL(reg_bus_path)) + msm_mdss->reg_bus_path = reg_bus_path; + return 0; } @@ -229,6 +237,13 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) for (i = 0; i < msm_mdss->num_mdp_paths; i++) icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(MIN_IB_BW)); + if (msm_mdss->mdss_data && msm_mdss->mdss_data->reg_bus_bw) + icc_set_bw(msm_mdss->reg_bus_path, 0, + msm_mdss->mdss_data->reg_bus_bw); + else + icc_set_bw(msm_mdss->reg_bus_path, 0, + DEFAULT_REG_BW); + ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); if (ret) { dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); @@ -286,6 +301,9 @@ static int msm_mdss_disable(struct msm_mdss *msm_mdss) for (i = 0; i < msm_mdss->num_mdp_paths; i++) icc_set_bw(msm_mdss->mdp_path[i], 0, 0); + if (msm_mdss->reg_bus_path) + icc_set_bw(msm_mdss->reg_bus_path, 0, 0); + return 0; } @@ -372,6 +390,8 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 if (!msm_mdss) return ERR_PTR(-ENOMEM); + msm_mdss->mdss_data = of_device_get_match_data(&pdev->dev); + msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); if (IS_ERR(msm_mdss->mmio)) return ERR_CAST(msm_mdss->mmio); @@ -462,8 +482,6 @@ static int mdss_probe(struct platform_device *pdev) if (IS_ERR(mdss)) return PTR_ERR(mdss); - mdss->mdss_data = of_device_get_match_data(&pdev->dev); - platform_set_drvdata(pdev, mdss); /* @@ -495,11 +513,13 @@ static const struct msm_mdss_data msm8998_data = { .ubwc_enc_version = UBWC_1_0, .ubwc_dec_version = UBWC_1_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data qcm2290_data = { /* no UBWC */ .highest_bank_bit = 0x2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc7180_data = { @@ -507,6 +527,7 @@ static const struct msm_mdss_data sc7180_data = { .ubwc_dec_version = UBWC_2_0, .ubwc_static = 0x1e, .highest_bank_bit = 0x3, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc7280_data = { @@ -516,6 +537,7 @@ static const struct msm_mdss_data sc7280_data = { .ubwc_static = 1, .highest_bank_bit = 1, .macrotile_mode = 1, + .reg_bus_bw = 74000, }; static const struct msm_mdss_data sc8180x_data = { @@ -523,6 +545,7 @@ static const struct msm_mdss_data sc8180x_data = { .ubwc_dec_version = UBWC_3_0, .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc8280xp_data = { @@ -532,6 +555,7 @@ static const struct msm_mdss_data sc8280xp_data = { .ubwc_static = 1, .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sdm670_data = { @@ -544,6 +568,7 @@ static const struct msm_mdss_data sdm845_data = { .ubwc_enc_version = UBWC_2_0, .ubwc_dec_version = UBWC_2_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6350_data = { @@ -552,12 +577,14 @@ static const struct msm_mdss_data sm6350_data = { .ubwc_swizzle = 6, .ubwc_static = 0x1e, .highest_bank_bit = 1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm8150_data = { .ubwc_enc_version = UBWC_3_0, .ubwc_dec_version = UBWC_3_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6115_data = { @@ -566,6 +593,7 @@ static const struct msm_mdss_data sm6115_data = { .ubwc_swizzle = 7, .ubwc_static = 0x11f, .highest_bank_bit = 0x1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6125_data = { @@ -583,6 +611,18 @@ static const struct msm_mdss_data sm8250_data = { /* TODO: highest_bank_bit = 2 for LP_DDR4 */ .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, +}; + +static const struct msm_mdss_data sm8350_data = { + .ubwc_enc_version = UBWC_4_0, + .ubwc_dec_version = UBWC_4_0, + .ubwc_swizzle = 6, + .ubwc_static = 1, + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + .highest_bank_bit = 3, + .macrotile_mode = 1, + .reg_bus_bw = 74000, }; static const struct msm_mdss_data sm8550_data = { @@ -593,6 +633,7 @@ static const struct msm_mdss_data sm8550_data = { /* TODO: highest_bank_bit = 2 for LP_DDR4 */ .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 57000, }; static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss" }, @@ -610,8 +651,8 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,sm6375-mdss", .data = &sm6350_data }, { .compatible = "qcom,sm8150-mdss", .data = &sm8150_data }, { .compatible = "qcom,sm8250-mdss", .data = &sm8250_data }, - { .compatible = "qcom,sm8350-mdss", .data = &sm8250_data }, - { .compatible = "qcom,sm8450-mdss", .data = &sm8250_data }, + { .compatible = "qcom,sm8350-mdss", .data = &sm8350_data }, + { .compatible = "qcom,sm8450-mdss", .data = &sm8350_data }, { .compatible = "qcom,sm8550-mdss", .data = &sm8550_data }, { .compatible = "qcom,sm8650-mdss", .data = &sm8550_data}, {} diff --git a/drivers/gpu/drm/msm/msm_mdss.h b/drivers/gpu/drm/msm/msm_mdss.h index 02bbab42adbc..3afef4b1786d 100644 --- a/drivers/gpu/drm/msm/msm_mdss.h +++ b/drivers/gpu/drm/msm/msm_mdss.h @@ -14,6 +14,7 @@ struct msm_mdss_data { u32 ubwc_static; u32 highest_bank_bit; u32 macrotile_mode; + u32 reg_bus_bw; }; #define UBWC_1_0 0x10000000 From 15a76c8014f932af7db38ae267ae0e3e4d089d9e Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 1 Dec 2023 17:18:56 -0800 Subject: [PATCH 2478/7721] f2fs: allocate new section if it's not new If fsck can allocate a new zone, it'd be better to use that instead of allocating a new one. And, it modifies kernel messages. Reviewed-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 08e2f44a1264..9081c9af977a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -4949,20 +4949,18 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi, return ret; } - if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { - /* - * If there are valid blocks and the write pointer doesn't match - * with them, we need to report the inconsistency and fill - * the zone till the end to close the zone. This inconsistency - * does not cause write error because the zone will not be - * selected for write operation until it get discarded. - */ - f2fs_notice(sbi, "Valid blocks are not aligned with write " + /* + * If there are valid blocks and the write pointer doesn't match + * with them, we need to report the inconsistency and fill + * the zone till the end to close the zone. This inconsistency + * does not cause write error because the zone will not be + * selected for write operation until it get discarded. + */ + f2fs_notice(sbi, "Valid blocks are not aligned with write " "pointer: valid block[0x%x,0x%x] wp[0x%x,0x%x]", GET_SEGNO(sbi, last_valid_block), GET_BLKOFF_FROM_SEG0(sbi, last_valid_block), wp_segno, wp_blkoff); - } ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH, zone->start, zone->len, GFP_NOFS); @@ -5053,15 +5051,18 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) f2fs_notice(sbi, "Unaligned curseg[%d] with write pointer: " "curseg[0x%x,0x%x] wp[0x%x,0x%x]", type, cs->segno, cs->next_blkoff, wp_segno, wp_blkoff); - } else { - f2fs_notice(sbi, "Not successfully unmounted in the previous " - "mount"); } - f2fs_notice(sbi, "Assign new section to curseg[%d]: " - "curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff); + /* Allocate a new section if it's not new. */ + if (cs->next_blkoff) { + unsigned int old_segno = cs->segno, old_blkoff = cs->next_blkoff; - f2fs_allocate_new_section(sbi, type, true); + f2fs_allocate_new_section(sbi, type, true); + f2fs_notice(sbi, "Assign new section to curseg[%d]: " + "[0x%x,0x%x] -> [0x%x,0x%x]", + type, old_segno, old_blkoff, + cs->segno, cs->next_blkoff); + } /* check consistency of the zone curseg pointed to */ if (check_zone_write_pointer(sbi, zbd, &zone)) From 9dad4d964291295ef48243d4e03972b85138bc9f Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sat, 2 Dec 2023 00:08:57 -0800 Subject: [PATCH 2479/7721] f2fs: fix write pointers on zoned device after roll forward 1. do roll forward recovery 2. update current segments pointers 3. fix the entire zones' write pointers 4. do checkpoint Reviewed-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 16415c770b45..d0f24ccbd1ac 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -917,6 +917,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) if (!err && fix_curseg_write_pointer && !f2fs_readonly(sbi->sb) && f2fs_sb_has_blkzoned(sbi)) { err = f2fs_fix_curseg_write_pointer(sbi); + if (!err) + err = f2fs_check_write_pointer(sbi); ret = err; } From aca90eea8a90b1abc844504109b6f919dfbd4259 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sat, 2 Dec 2023 11:15:41 -0800 Subject: [PATCH 2480/7721] f2fs: check write pointers when checkpoint=disable Even if f2fs was rebooted as staying checkpoint=disable, let's match the write pointers all the time. Reviewed-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 617340e9ea7f..9a874b4d1501 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4741,7 +4741,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) #ifdef CONFIG_QUOTA f2fs_recover_quota_end(sbi, quota_enabled); #endif - +reset_checkpoint: /* * If the f2fs is not readonly and fsync data recovery succeeds, * check zoned block devices' write pointer consistency. @@ -4752,7 +4752,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_meta; } -reset_checkpoint: f2fs_init_inmem_curseg(sbi); /* f2fs_recover_fsync_data() cleared this already */ From e759f2ca29d918d3db57a61cdf838025beb03465 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 29 Nov 2023 23:08:00 +0100 Subject: [PATCH 2481/7721] drm/gpuvm: fall back to drm_exec_lock_obj() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fall back to drm_exec_lock_obj() if num_fences is zero for the drm_gpuvm_prepare_* function family. Otherwise dma_resv_reserve_fences() would actually allocate slots even though num_fences is zero. Cc: Christian König Acked-by: Donald Robson Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231129220835.297885-2-dakr@redhat.com --- drivers/gpu/drm/drm_gpuvm.c | 43 ++++++++++++++++++++++++++++++++----- include/drm/drm_gpuvm.h | 23 +++----------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 54f5e8851de5..07a6676bc4f9 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1085,6 +1085,37 @@ drm_gpuvm_put(struct drm_gpuvm *gpuvm) } EXPORT_SYMBOL_GPL(drm_gpuvm_put); +static int +exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, + unsigned int num_fences) +{ + return num_fences ? drm_exec_prepare_obj(exec, obj, num_fences) : + drm_exec_lock_obj(exec, obj); +} + +/** + * drm_gpuvm_prepare_vm() - prepare the GPUVMs common dma-resv + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec context + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for the GPUVMs dummy &drm_gem_object; if + * @num_fences is zero drm_exec_lock_obj() is called instead. + * + * Using this function directly, it is the drivers responsibility to call + * drm_exec_init() and drm_exec_fini() accordingly. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + return exec_prepare_obj(exec, gpuvm->r_obj, num_fences); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_vm); + static int __drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, struct drm_exec *exec, @@ -1095,7 +1126,7 @@ __drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, int ret = 0; for_each_vm_bo_in_list(gpuvm, extobj, &extobjs, vm_bo) { - ret = drm_exec_prepare_obj(exec, vm_bo->obj, num_fences); + ret = exec_prepare_obj(exec, vm_bo->obj, num_fences); if (ret) break; } @@ -1116,7 +1147,7 @@ drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm, drm_gpuvm_resv_assert_held(gpuvm); list_for_each_entry(vm_bo, &gpuvm->extobj.list, list.entry.extobj) { - ret = drm_exec_prepare_obj(exec, vm_bo->obj, num_fences); + ret = exec_prepare_obj(exec, vm_bo->obj, num_fences); if (ret) break; @@ -1134,7 +1165,8 @@ drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm, * @num_fences: the amount of &dma_fences to reserve * * Calls drm_exec_prepare_obj() for all &drm_gem_objects the given - * &drm_gpuvm contains mappings of. + * &drm_gpuvm contains mappings of; if @num_fences is zero drm_exec_lock_obj() + * is called instead. * * Using this function directly, it is the drivers responsibility to call * drm_exec_init() and drm_exec_fini() accordingly. @@ -1171,7 +1203,8 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_objects); * @num_fences: the amount of &dma_fences to reserve * * Calls drm_exec_prepare_obj() for all &drm_gem_objects mapped between @addr - * and @addr + @range. + * and @addr + @range; if @num_fences is zero drm_exec_lock_obj() is called + * instead. * * Returns: 0 on success, negative error code on failure. */ @@ -1186,7 +1219,7 @@ drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, struct drm_exec *exec, drm_gpuvm_for_each_va_range(va, gpuvm, addr, end) { struct drm_gem_object *obj = va->gem.obj; - ret = drm_exec_prepare_obj(exec, obj, num_fences); + ret = exec_prepare_obj(exec, obj, num_fences); if (ret) return ret; } diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index f94fec9a8517..b3f82ec7fb17 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -544,26 +544,9 @@ struct drm_gpuvm_exec { } extra; }; -/** - * drm_gpuvm_prepare_vm() - prepare the GPUVMs common dma-resv - * @gpuvm: the &drm_gpuvm - * @exec: the &drm_exec context - * @num_fences: the amount of &dma_fences to reserve - * - * Calls drm_exec_prepare_obj() for the GPUVMs dummy &drm_gem_object. - * - * Using this function directly, it is the drivers responsibility to call - * drm_exec_init() and drm_exec_fini() accordingly. - * - * Returns: 0 on success, negative error code on failure. - */ -static inline int -drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, - struct drm_exec *exec, - unsigned int num_fences) -{ - return drm_exec_prepare_obj(exec, gpuvm->r_obj, num_fences); -} +int drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences); int drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, struct drm_exec *exec, From 4bc736f890cec126246a1d65d3b556763670a8d4 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 29 Nov 2023 23:08:01 +0100 Subject: [PATCH 2482/7721] drm/imagination: vm: make use of GPUVM's drm_exec helper Make use of GPUVM's drm_exec helper functions preventing direct access to GPUVM internal data structures, such as the external object list. This is especially important to ensure following the locking rules around the GPUVM external object list. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Reviewed-by: Donald Robson Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231129220835.297885-3-dakr@redhat.com --- drivers/gpu/drm/imagination/pvr_vm.c | 91 +++++++++++----------------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 6f4e07effad2..f42345fbe4bf 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -327,48 +327,6 @@ pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op, return err; } -static int -pvr_vm_bind_op_lock_resvs(struct drm_exec *exec, struct pvr_vm_bind_op *bind_op) -{ - drm_exec_until_all_locked(exec) { - struct drm_gem_object *r_obj = &bind_op->vm_ctx->dummy_gem; - struct drm_gpuvm *gpuvm = &bind_op->vm_ctx->gpuvm_mgr; - struct pvr_gem_object *pvr_obj = bind_op->pvr_obj; - struct drm_gpuvm_bo *gpuvm_bo; - - /* Acquire lock on the vm_context's reserve object. */ - int err = drm_exec_lock_obj(exec, r_obj); - - drm_exec_retry_on_contention(exec); - if (err) - return err; - - /* Acquire lock on all BOs in the context. */ - list_for_each_entry(gpuvm_bo, &gpuvm->extobj.list, - list.entry.extobj) { - err = drm_exec_lock_obj(exec, gpuvm_bo->obj); - - drm_exec_retry_on_contention(exec); - if (err) - return err; - } - - /* Unmap operations don't have an object to lock. */ - if (!pvr_obj) - break; - - /* Acquire lock on the GEM being mapped. */ - err = drm_exec_lock_obj(exec, - gem_from_pvr_gem(bind_op->pvr_obj)); - - drm_exec_retry_on_contention(exec); - if (err) - return err; - } - - return 0; -} - /** * pvr_vm_gpuva_map() - Insert a mapping into a memory context. * @op: gpuva op containing the remap details. @@ -725,6 +683,20 @@ void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file) } } +static int +pvr_vm_lock_extra(struct drm_gpuvm_exec *vm_exec) +{ + struct pvr_vm_bind_op *bind_op = vm_exec->extra.priv; + struct pvr_gem_object *pvr_obj = bind_op->pvr_obj; + + /* Unmap operations don't have an object to lock. */ + if (!pvr_obj) + return 0; + + /* Acquire lock on the GEM being mapped. */ + return drm_exec_lock_obj(&vm_exec->exec, gem_from_pvr_gem(pvr_obj)); +} + /** * pvr_vm_map() - Map a section of physical memory into a section of * device-virtual memory. @@ -752,7 +724,15 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset, u64 device_addr, u64 size) { struct pvr_vm_bind_op bind_op = {0}; - struct drm_exec exec; + struct drm_gpuvm_exec vm_exec = { + .vm = &vm_ctx->gpuvm_mgr, + .flags = DRM_EXEC_INTERRUPTIBLE_WAIT | + DRM_EXEC_IGNORE_DUPLICATES, + .extra = { + .fn = pvr_vm_lock_extra, + .priv = &bind_op, + }, + }; int err = pvr_vm_bind_op_map_init(&bind_op, vm_ctx, pvr_obj, pvr_obj_offset, device_addr, @@ -761,18 +741,15 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, if (err) return err; - drm_exec_init(&exec, - DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); - pvr_gem_object_get(pvr_obj); - err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op); + err = drm_gpuvm_exec_lock(&vm_exec); if (err) goto err_cleanup; err = pvr_vm_bind_op_exec(&bind_op); - drm_exec_fini(&exec); + drm_gpuvm_exec_unlock(&vm_exec); err_cleanup: pvr_vm_bind_op_fini(&bind_op); @@ -798,24 +775,28 @@ int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size) { struct pvr_vm_bind_op bind_op = {0}; - struct drm_exec exec; + struct drm_gpuvm_exec vm_exec = { + .vm = &vm_ctx->gpuvm_mgr, + .flags = DRM_EXEC_INTERRUPTIBLE_WAIT | + DRM_EXEC_IGNORE_DUPLICATES, + .extra = { + .fn = pvr_vm_lock_extra, + .priv = &bind_op, + }, + }; int err = pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, device_addr, size); - if (err) return err; - drm_exec_init(&exec, - DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); - - err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op); + err = drm_gpuvm_exec_lock(&vm_exec); if (err) goto err_cleanup; err = pvr_vm_bind_op_exec(&bind_op); - drm_exec_fini(&exec); + drm_gpuvm_exec_unlock(&vm_exec); err_cleanup: pvr_vm_bind_op_fini(&bind_op); From 169410eba271afc9f0fb476d996795aa26770c6d Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:19 +0800 Subject: [PATCH 2483/7721] bpf: Check rcu_read_lock_trace_held() before calling bpf map helpers These three bpf_map_{lookup,update,delete}_elem() helpers are also available for sleepable bpf program, so add the corresponding lock assertion for sleepable bpf program, otherwise the following warning will be reported when a sleepable bpf program manipulates bpf map under interpreter mode (aka bpf_jit_enable=0): WARNING: CPU: 3 PID: 4985 at kernel/bpf/helpers.c:40 ...... CPU: 3 PID: 4985 Comm: test_progs Not tainted 6.6.0+ #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) ...... RIP: 0010:bpf_map_lookup_elem+0x54/0x60 ...... Call Trace: ? __warn+0xa5/0x240 ? bpf_map_lookup_elem+0x54/0x60 ? report_bug+0x1ba/0x1f0 ? handle_bug+0x40/0x80 ? exc_invalid_op+0x18/0x50 ? asm_exc_invalid_op+0x1b/0x20 ? __pfx_bpf_map_lookup_elem+0x10/0x10 ? rcu_lockdep_current_cpu_online+0x65/0xb0 ? rcu_is_watching+0x23/0x50 ? bpf_map_lookup_elem+0x54/0x60 ? __pfx_bpf_map_lookup_elem+0x10/0x10 ___bpf_prog_run+0x513/0x3b70 __bpf_prog_run32+0x9d/0xd0 ? __bpf_prog_enter_sleepable_recur+0xad/0x120 ? __bpf_prog_enter_sleepable_recur+0x3e/0x120 bpf_trampoline_6442580665+0x4d/0x1000 __x64_sys_getpgid+0x5/0x30 ? do_syscall_64+0x36/0xb0 entry_SYSCALL_64_after_hwframe+0x6e/0x76 Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index b45a8381f9bd..ee9bdf29246a 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -32,12 +32,13 @@ * * Different map implementations will rely on rcu in map methods * lookup/update/delete, therefore eBPF programs must run under rcu lock - * if program is allowed to access maps, so check rcu_read_lock_held in - * all three functions. + * if program is allowed to access maps, so check rcu_read_lock_held() or + * rcu_read_lock_trace_held() in all three functions. */ BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key) { - WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); + WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_trace_held() && + !rcu_read_lock_bh_held()); return (unsigned long) map->ops->map_lookup_elem(map, key); } @@ -53,7 +54,8 @@ const struct bpf_func_proto bpf_map_lookup_elem_proto = { BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key, void *, value, u64, flags) { - WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); + WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_trace_held() && + !rcu_read_lock_bh_held()); return map->ops->map_update_elem(map, key, value, flags); } @@ -70,7 +72,8 @@ const struct bpf_func_proto bpf_map_update_elem_proto = { BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key) { - WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); + WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_trace_held() && + !rcu_read_lock_bh_held()); return map->ops->map_delete_elem(map, key); } From 20c20bd11a0702ce4dc9300c3da58acf551d9725 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:20 +0800 Subject: [PATCH 2484/7721] bpf: Add map and need_defer parameters to .map_fd_put_ptr() map is the pointer of outer map, and need_defer needs some explanation. need_defer tells the implementation to defer the reference release of the passed element and ensure that the element is still alive before the bpf program, which may manipulate it, exits. The following three cases will invoke map_fd_put_ptr() and different need_defer values will be passed to these callers: 1) release the reference of the old element in the map during map update or map deletion. The release must be deferred, otherwise the bpf program may incur use-after-free problem, so need_defer needs to be true. 2) release the reference of the to-be-added element in the error path of map update. The to-be-added element is not visible to any bpf program, so it is OK to pass false for need_defer parameter. 3) release the references of all elements in the map during map release. Any bpf program which has access to the map must have been exited and released, so need_defer=false will be OK. These two parameters will be used by the following patches to fix the potential use-after-free problem for map-in-map. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 6 +++++- kernel/bpf/arraymap.c | 12 +++++++----- kernel/bpf/hashtab.c | 6 +++--- kernel/bpf/map_in_map.c | 2 +- kernel/bpf/map_in_map.h | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index eb447b0a9423..d273348cfb2f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -106,7 +106,11 @@ struct bpf_map_ops { /* funcs called by prog_array and perf_event_array map */ void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file, int fd); - void (*map_fd_put_ptr)(void *ptr); + /* If need_defer is true, the implementation should guarantee that + * the to-be-put element is still alive before the bpf program, which + * may manipulate it, exists. + */ + void (*map_fd_put_ptr)(struct bpf_map *map, void *ptr, bool need_defer); int (*map_gen_lookup)(struct bpf_map *map, struct bpf_insn *insn_buf); u32 (*map_fd_sys_lookup_elem)(void *ptr); void (*map_seq_show_elem)(struct bpf_map *map, void *key, diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 2058e89b5ddd..f9aed5909d6e 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -867,7 +867,7 @@ int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file, } if (old_ptr) - map->ops->map_fd_put_ptr(old_ptr); + map->ops->map_fd_put_ptr(map, old_ptr, true); return 0; } @@ -890,7 +890,7 @@ static long fd_array_map_delete_elem(struct bpf_map *map, void *key) } if (old_ptr) { - map->ops->map_fd_put_ptr(old_ptr); + map->ops->map_fd_put_ptr(map, old_ptr, true); return 0; } else { return -ENOENT; @@ -913,8 +913,9 @@ static void *prog_fd_array_get_ptr(struct bpf_map *map, return prog; } -static void prog_fd_array_put_ptr(void *ptr) +static void prog_fd_array_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { + /* bpf_prog is freed after one RCU or tasks trace grace period */ bpf_prog_put(ptr); } @@ -1239,8 +1240,9 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map, return ee; } -static void perf_event_fd_array_put_ptr(void *ptr) +static void perf_event_fd_array_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { + /* bpf_perf_event is freed after one RCU grace period */ bpf_event_entry_free_rcu(ptr); } @@ -1294,7 +1296,7 @@ static void *cgroup_fd_array_get_ptr(struct bpf_map *map, return cgroup_get_from_fd(fd); } -static void cgroup_fd_array_put_ptr(void *ptr) +static void cgroup_fd_array_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { /* cgroup_put free cgrp after a rcu grace period */ cgroup_put(ptr); diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index fd8d4b0addfc..5b9146fa825f 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -897,7 +897,7 @@ static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l) if (map->ops->map_fd_put_ptr) { ptr = fd_htab_map_get_ptr(map, l); - map->ops->map_fd_put_ptr(ptr); + map->ops->map_fd_put_ptr(map, ptr, true); } } @@ -2484,7 +2484,7 @@ static void fd_htab_map_free(struct bpf_map *map) hlist_nulls_for_each_entry_safe(l, n, head, hash_node) { void *ptr = fd_htab_map_get_ptr(map, l); - map->ops->map_fd_put_ptr(ptr); + map->ops->map_fd_put_ptr(map, ptr, false); } } @@ -2525,7 +2525,7 @@ int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file, ret = htab_map_update_elem(map, key, &ptr, map_flags); if (ret) - map->ops->map_fd_put_ptr(ptr); + map->ops->map_fd_put_ptr(map, ptr, false); return ret; } diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index cd5eafaba97e..2dfeb5835e16 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -127,7 +127,7 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map, return inner_map; } -void bpf_map_fd_put_ptr(void *ptr) +void bpf_map_fd_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { /* ptr->ops->map_free() has to go through one * rcu grace period by itself. diff --git a/kernel/bpf/map_in_map.h b/kernel/bpf/map_in_map.h index bcb7534afb3c..7d61602354de 100644 --- a/kernel/bpf/map_in_map.h +++ b/kernel/bpf/map_in_map.h @@ -13,7 +13,7 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd); void bpf_map_meta_free(struct bpf_map *map_meta); void *bpf_map_fd_get_ptr(struct bpf_map *map, struct file *map_file, int ufd); -void bpf_map_fd_put_ptr(void *ptr); +void bpf_map_fd_put_ptr(struct bpf_map *map, void *ptr, bool need_defer); u32 bpf_map_fd_sys_lookup_elem(void *ptr); #endif From 79d93b3c6ffd79abcd8e43345980aa1e904879c4 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:21 +0800 Subject: [PATCH 2485/7721] bpf: Set need_defer as false when clearing fd array during map free Both map deletion operation, map release and map free operation use fd_array_map_delete_elem() to remove the element from fd array and need_defer is always true in fd_array_map_delete_elem(). For the map deletion operation and map release operation, need_defer=true is necessary, because the bpf program, which accesses the element in fd array, may still alive. However for map free operation, it is certain that the bpf program which owns the fd array has already been exited, so setting need_defer as false is appropriate for map free operation. So fix it by adding need_defer parameter to bpf_fd_array_map_clear() and adding a new helper __fd_array_map_delete_elem() to handle the map deletion, map release and map free operations correspondingly. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/arraymap.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index f9aed5909d6e..4a4a67956e21 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -871,7 +871,7 @@ int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file, return 0; } -static long fd_array_map_delete_elem(struct bpf_map *map, void *key) +static long __fd_array_map_delete_elem(struct bpf_map *map, void *key, bool need_defer) { struct bpf_array *array = container_of(map, struct bpf_array, map); void *old_ptr; @@ -890,13 +890,18 @@ static long fd_array_map_delete_elem(struct bpf_map *map, void *key) } if (old_ptr) { - map->ops->map_fd_put_ptr(map, old_ptr, true); + map->ops->map_fd_put_ptr(map, old_ptr, need_defer); return 0; } else { return -ENOENT; } } +static long fd_array_map_delete_elem(struct bpf_map *map, void *key) +{ + return __fd_array_map_delete_elem(map, key, true); +} + static void *prog_fd_array_get_ptr(struct bpf_map *map, struct file *map_file, int fd) { @@ -925,13 +930,13 @@ static u32 prog_fd_array_sys_lookup_elem(void *ptr) } /* decrement refcnt of all bpf_progs that are stored in this map */ -static void bpf_fd_array_map_clear(struct bpf_map *map) +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++) - fd_array_map_delete_elem(map, &i); + __fd_array_map_delete_elem(map, &i, need_defer); } static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, @@ -1110,7 +1115,7 @@ static void prog_array_map_clear_deferred(struct work_struct *work) { struct bpf_map *map = container_of(work, struct bpf_array_aux, work)->map; - bpf_fd_array_map_clear(map); + bpf_fd_array_map_clear(map, true); bpf_map_put(map); } @@ -1260,7 +1265,7 @@ static void perf_event_fd_array_release(struct bpf_map *map, for (i = 0; i < array->map.max_entries; i++) { ee = READ_ONCE(array->ptrs[i]); if (ee && ee->map_file == map_file) - fd_array_map_delete_elem(map, &i); + __fd_array_map_delete_elem(map, &i, true); } rcu_read_unlock(); } @@ -1268,7 +1273,7 @@ static void perf_event_fd_array_release(struct bpf_map *map, static void perf_event_fd_array_map_free(struct bpf_map *map) { if (map->map_flags & BPF_F_PRESERVE_ELEMS) - bpf_fd_array_map_clear(map); + bpf_fd_array_map_clear(map, false); fd_array_map_free(map); } @@ -1304,7 +1309,7 @@ static void cgroup_fd_array_put_ptr(struct bpf_map *map, void *ptr, bool need_de static void cgroup_fd_array_free(struct bpf_map *map) { - bpf_fd_array_map_clear(map); + bpf_fd_array_map_clear(map, false); fd_array_map_free(map); } @@ -1349,7 +1354,7 @@ static void array_of_map_free(struct bpf_map *map) * is protected by fdget/fdput. */ bpf_map_meta_free(map->inner_map_meta); - bpf_fd_array_map_clear(map); + bpf_fd_array_map_clear(map, false); fd_array_map_free(map); } From 876673364161da50eed6b472d746ef88242b2368 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:22 +0800 Subject: [PATCH 2486/7721] bpf: Defer the free of inner map when necessary When updating or deleting an inner map in map array or map htab, the map may still be accessed by non-sleepable program or sleepable program. However bpf_map_fd_put_ptr() decreases the ref-counter of the inner map directly through bpf_map_put(), if the ref-counter is the last one (which is true for most cases), the inner map will be freed by ops->map_free() in a kworker. But for now, most .map_free() callbacks don't use synchronize_rcu() or its variants to wait for the elapse of a RCU grace period, so after the invocation of ops->map_free completes, the bpf program which is accessing the inner map may incur use-after-free problem. Fix the free of inner map by invoking bpf_map_free_deferred() after both one RCU grace period and one tasks trace RCU grace period if the inner map has been removed from the outer map before. The deferment is accomplished by using call_rcu() or call_rcu_tasks_trace() when releasing the last ref-counter of bpf map. The newly-added rcu_head field in bpf_map shares the same storage space with work field to reduce the size of bpf_map. Fixes: bba1dc0b55ac ("bpf: Remove redundant synchronize_rcu.") Fixes: 638e4b825d52 ("bpf: Allows per-cpu maps and map-in-map in sleepable programs") Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-5-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 7 ++++++- kernel/bpf/map_in_map.c | 11 ++++++++--- kernel/bpf/syscall.c | 32 +++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d273348cfb2f..de3bd03cbeea 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -276,7 +276,11 @@ struct bpf_map { */ atomic64_t refcnt ____cacheline_aligned; atomic64_t usercnt; - struct work_struct work; + /* rcu is used before freeing and work is only used during freeing */ + union { + struct work_struct work; + struct rcu_head rcu; + }; struct mutex freeze_mutex; atomic64_t writecnt; /* 'Ownership' of program-containing map is claimed by the first program @@ -292,6 +296,7 @@ struct bpf_map { } owner; bool bypass_spec_v1; bool frozen; /* write-once; write-protected by freeze_mutex */ + bool free_after_mult_rcu_gp; s64 __percpu *elem_count; }; diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index 2dfeb5835e16..3248ff5d8161 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -129,10 +129,15 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map, void bpf_map_fd_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { - /* ptr->ops->map_free() has to go through one - * rcu grace period by itself. + struct bpf_map *inner_map = ptr; + + /* The inner map may still be used by both non-sleepable and sleepable + * bpf program, so free it after one RCU grace period and one tasks + * trace RCU grace period. */ - bpf_map_put(ptr); + if (need_defer) + WRITE_ONCE(inner_map->free_after_mult_rcu_gp, true); + bpf_map_put(inner_map); } u32 bpf_map_fd_sys_lookup_elem(void *ptr) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 5e43ddd1b83f..dd515f6b9741 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -719,6 +719,28 @@ static void bpf_map_put_uref(struct bpf_map *map) } } +static void bpf_map_free_in_work(struct bpf_map *map) +{ + INIT_WORK(&map->work, bpf_map_free_deferred); + /* Avoid spawning kworkers, since they all might contend + * for the same mutex like slab_mutex. + */ + queue_work(system_unbound_wq, &map->work); +} + +static void bpf_map_free_rcu_gp(struct rcu_head *rcu) +{ + bpf_map_free_in_work(container_of(rcu, struct bpf_map, rcu)); +} + +static void bpf_map_free_mult_rcu_gp(struct rcu_head *rcu) +{ + if (rcu_trace_implies_rcu_gp()) + bpf_map_free_rcu_gp(rcu); + else + call_rcu(rcu, bpf_map_free_rcu_gp); +} + /* decrement map refcnt and schedule it for freeing via workqueue * (underlying map implementation ops->map_free() might sleep) */ @@ -728,11 +750,11 @@ void bpf_map_put(struct bpf_map *map) /* bpf_map_free_id() must be called first */ bpf_map_free_id(map); btf_put(map->btf); - INIT_WORK(&map->work, bpf_map_free_deferred); - /* Avoid spawning kworkers, since they all might contend - * for the same mutex like slab_mutex. - */ - queue_work(system_unbound_wq, &map->work); + + if (READ_ONCE(map->free_after_mult_rcu_gp)) + call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp); + else + bpf_map_free_in_work(map); } } EXPORT_SYMBOL_GPL(bpf_map_put); From af66bfd3c8538ed21cf72af18426fc4a408665cf Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:23 +0800 Subject: [PATCH 2487/7721] bpf: Optimize the free of inner map When removing the inner map from the outer map, the inner map will be freed after one RCU grace period and one RCU tasks trace grace period, so it is certain that the bpf program, which may access the inner map, has exited before the inner map is freed. However there is no need to wait for one RCU tasks trace grace period if the outer map is only accessed by non-sleepable program. So adding sleepable_refcnt in bpf_map and increasing sleepable_refcnt when adding the outer map into env->used_maps for sleepable program. Although the max number of bpf program is INT_MAX - 1, the number of bpf programs which are being loaded may be greater than INT_MAX, so using atomic64_t instead of atomic_t for sleepable_refcnt. When removing the inner map from the outer map, using sleepable_refcnt to decide whether or not a RCU tasks trace grace period is needed before freeing the inner map. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-6-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 2 ++ kernel/bpf/core.c | 4 ++++ kernel/bpf/map_in_map.c | 14 +++++++++----- kernel/bpf/syscall.c | 8 ++++++++ kernel/bpf/verifier.c | 4 +++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index de3bd03cbeea..10e5e4d8a00f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -297,6 +297,8 @@ struct bpf_map { bool bypass_spec_v1; bool frozen; /* write-once; write-protected by freeze_mutex */ bool free_after_mult_rcu_gp; + bool free_after_rcu_gp; + atomic64_t sleepable_refcnt; s64 __percpu *elem_count; }; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index cd3afe57ece3..4b813da8d6c0 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2664,12 +2664,16 @@ void __bpf_free_used_maps(struct bpf_prog_aux *aux, struct bpf_map **used_maps, u32 len) { struct bpf_map *map; + bool sleepable; u32 i; + sleepable = aux->sleepable; for (i = 0; i < len; i++) { map = used_maps[i]; if (map->ops->map_poke_untrack) map->ops->map_poke_untrack(map, aux); + if (sleepable) + atomic64_dec(&map->sleepable_refcnt); bpf_map_put(map); } } diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index 3248ff5d8161..8ef269e66ba5 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -131,12 +131,16 @@ void bpf_map_fd_put_ptr(struct bpf_map *map, void *ptr, bool need_defer) { struct bpf_map *inner_map = ptr; - /* The inner map may still be used by both non-sleepable and sleepable - * bpf program, so free it after one RCU grace period and one tasks - * trace RCU grace period. + /* Defer the freeing of inner map according to the sleepable attribute + * of bpf program which owns the outer map, so unnecessary waiting for + * RCU tasks trace grace period can be avoided. */ - if (need_defer) - WRITE_ONCE(inner_map->free_after_mult_rcu_gp, true); + if (need_defer) { + if (atomic64_read(&map->sleepable_refcnt)) + WRITE_ONCE(inner_map->free_after_mult_rcu_gp, true); + else + WRITE_ONCE(inner_map->free_after_rcu_gp, true); + } bpf_map_put(inner_map); } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index dd515f6b9741..ebaccf77d56e 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -751,8 +751,11 @@ void bpf_map_put(struct bpf_map *map) bpf_map_free_id(map); btf_put(map->btf); + WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt)); if (READ_ONCE(map->free_after_mult_rcu_gp)) call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp); + else if (READ_ONCE(map->free_after_rcu_gp)) + call_rcu(&map->rcu, bpf_map_free_rcu_gp); else bpf_map_free_in_work(map); } @@ -5345,6 +5348,11 @@ static int bpf_prog_bind_map(union bpf_attr *attr) goto out_unlock; } + /* The bpf program will not access the bpf map, but for the sake of + * simplicity, increase sleepable_refcnt for sleepable program as well. + */ + if (prog->aux->sleepable) + atomic64_inc(&map->sleepable_refcnt); memcpy(used_maps_new, used_maps_old, sizeof(used_maps_old[0]) * prog->aux->used_map_cnt); used_maps_new[prog->aux->used_map_cnt] = map; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index cdb4f5f0ba79..1ed39665f802 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17889,10 +17889,12 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env) return -E2BIG; } + if (env->prog->aux->sleepable) + atomic64_inc(&map->sleepable_refcnt); /* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded - * and all maps are released in free_used_maps() + * and all maps are released in bpf_free_used_maps() */ bpf_map_inc(map); From 1624918be84a8bcc4f592e55635bc4fe4a96460a Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:24 +0800 Subject: [PATCH 2488/7721] selftests/bpf: Add test cases for inner map Add test cases to test the race between the destroy of inner map due to map-in-map update and the access of inner map in bpf program. The following 4 combinations are added: (1) array map in map array + bpf program (2) array map in map array + sleepable bpf program (3) array map in map htab + bpf program (4) array map in map htab + sleepable bpf program Before applying the fixes, when running `./test_prog -a map_in_map`, the following error was reported: ================================================================== BUG: KASAN: slab-use-after-free in array_map_update_elem+0x48/0x3e0 Read of size 4 at addr ffff888114f33824 by task test_progs/1858 CPU: 1 PID: 1858 Comm: test_progs Tainted: G O 6.6.0+ #7 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) ...... Call Trace: dump_stack_lvl+0x4a/0x90 print_report+0xd2/0x620 kasan_report+0xd1/0x110 __asan_load4+0x81/0xa0 array_map_update_elem+0x48/0x3e0 bpf_prog_be94a9f26772f5b7_access_map_in_array+0xe6/0xf6 trace_call_bpf+0x1aa/0x580 kprobe_perf_func+0xdd/0x430 kprobe_dispatcher+0xa0/0xb0 kprobe_ftrace_handler+0x18b/0x2e0 0xffffffffc02280f7 RIP: 0010:__x64_sys_getpgid+0x1/0x30 ...... Allocated by task 1857: kasan_save_stack+0x26/0x50 kasan_set_track+0x25/0x40 kasan_save_alloc_info+0x1e/0x30 __kasan_kmalloc+0x98/0xa0 __kmalloc_node+0x6a/0x150 __bpf_map_area_alloc+0x141/0x170 bpf_map_area_alloc+0x10/0x20 array_map_alloc+0x11f/0x310 map_create+0x28a/0xb40 __sys_bpf+0x753/0x37c0 __x64_sys_bpf+0x44/0x60 do_syscall_64+0x36/0xb0 entry_SYSCALL_64_after_hwframe+0x6e/0x76 Freed by task 11: kasan_save_stack+0x26/0x50 kasan_set_track+0x25/0x40 kasan_save_free_info+0x2b/0x50 __kasan_slab_free+0x113/0x190 slab_free_freelist_hook+0xd7/0x1e0 __kmem_cache_free+0x170/0x260 kfree+0x9b/0x160 kvfree+0x2d/0x40 bpf_map_area_free+0xe/0x20 array_map_free+0x120/0x2c0 bpf_map_free_deferred+0xd7/0x1e0 process_one_work+0x462/0x990 worker_thread+0x370/0x670 kthread+0x1b0/0x200 ret_from_fork+0x3a/0x70 ret_from_fork_asm+0x1b/0x30 Last potentially related work creation: kasan_save_stack+0x26/0x50 __kasan_record_aux_stack+0x94/0xb0 kasan_record_aux_stack_noalloc+0xb/0x20 __queue_work+0x331/0x950 queue_work_on+0x75/0x80 bpf_map_put+0xfa/0x160 bpf_map_fd_put_ptr+0xe/0x20 bpf_fd_array_map_update_elem+0x174/0x1b0 bpf_map_update_value+0x2b7/0x4a0 __sys_bpf+0x2551/0x37c0 __x64_sys_bpf+0x44/0x60 do_syscall_64+0x36/0xb0 entry_SYSCALL_64_after_hwframe+0x6e/0x76 Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-7-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/map_in_map.c | 141 ++++++++++++++++++ .../selftests/bpf/progs/access_map_in_map.c | 93 ++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/map_in_map.c create mode 100644 tools/testing/selftests/bpf/progs/access_map_in_map.c diff --git a/tools/testing/selftests/bpf/prog_tests/map_in_map.c b/tools/testing/selftests/bpf/prog_tests/map_in_map.c new file mode 100644 index 000000000000..d2a10eb4e5b5 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/map_in_map.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "access_map_in_map.skel.h" + +struct thread_ctx { + pthread_barrier_t barrier; + int outer_map_fd; + int start, abort; + int loop, err; +}; + +static int wait_for_start_or_abort(struct thread_ctx *ctx) +{ + while (!ctx->start && !ctx->abort) + usleep(1); + return ctx->abort ? -1 : 0; +} + +static void *update_map_fn(void *data) +{ + struct thread_ctx *ctx = data; + int loop = ctx->loop, err = 0; + + if (wait_for_start_or_abort(ctx) < 0) + return NULL; + pthread_barrier_wait(&ctx->barrier); + + while (loop-- > 0) { + int fd, zero = 0; + + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 4, 1, NULL); + if (fd < 0) { + err |= 1; + pthread_barrier_wait(&ctx->barrier); + continue; + } + + /* Remove the old inner map */ + if (bpf_map_update_elem(ctx->outer_map_fd, &zero, &fd, 0) < 0) + err |= 2; + close(fd); + pthread_barrier_wait(&ctx->barrier); + } + + ctx->err = err; + + return NULL; +} + +static void *access_map_fn(void *data) +{ + struct thread_ctx *ctx = data; + int loop = ctx->loop; + + if (wait_for_start_or_abort(ctx) < 0) + return NULL; + pthread_barrier_wait(&ctx->barrier); + + while (loop-- > 0) { + /* Access the old inner map */ + syscall(SYS_getpgid); + pthread_barrier_wait(&ctx->barrier); + } + + return NULL; +} + +static void test_map_in_map_access(const char *prog_name, const char *map_name) +{ + struct access_map_in_map *skel; + struct bpf_map *outer_map; + struct bpf_program *prog; + struct thread_ctx ctx; + pthread_t tid[2]; + int err; + + skel = access_map_in_map__open(); + if (!ASSERT_OK_PTR(skel, "access_map_in_map open")) + return; + + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "find program")) + goto out; + bpf_program__set_autoload(prog, true); + + outer_map = bpf_object__find_map_by_name(skel->obj, map_name); + if (!ASSERT_OK_PTR(outer_map, "find map")) + goto out; + + err = access_map_in_map__load(skel); + if (!ASSERT_OK(err, "access_map_in_map load")) + goto out; + + err = access_map_in_map__attach(skel); + if (!ASSERT_OK(err, "access_map_in_map attach")) + goto out; + + skel->bss->tgid = getpid(); + + memset(&ctx, 0, sizeof(ctx)); + pthread_barrier_init(&ctx.barrier, NULL, 2); + ctx.outer_map_fd = bpf_map__fd(outer_map); + ctx.loop = 4; + + err = pthread_create(&tid[0], NULL, update_map_fn, &ctx); + if (!ASSERT_OK(err, "close_thread")) + goto out; + + err = pthread_create(&tid[1], NULL, access_map_fn, &ctx); + if (!ASSERT_OK(err, "read_thread")) { + ctx.abort = 1; + pthread_join(tid[0], NULL); + goto out; + } + + ctx.start = 1; + pthread_join(tid[0], NULL); + pthread_join(tid[1], NULL); + + ASSERT_OK(ctx.err, "err"); +out: + access_map_in_map__destroy(skel); +} + +void test_map_in_map(void) +{ + if (test__start_subtest("acc_map_in_array")) + test_map_in_map_access("access_map_in_array", "outer_array_map"); + if (test__start_subtest("sleepable_acc_map_in_array")) + test_map_in_map_access("sleepable_access_map_in_array", "outer_array_map"); + if (test__start_subtest("acc_map_in_htab")) + test_map_in_map_access("access_map_in_htab", "outer_htab_map"); + if (test__start_subtest("sleepable_acc_map_in_htab")) + test_map_in_map_access("sleepable_access_map_in_htab", "outer_htab_map"); +} + diff --git a/tools/testing/selftests/bpf/progs/access_map_in_map.c b/tools/testing/selftests/bpf/progs/access_map_in_map.c new file mode 100644 index 000000000000..1126871c2ebd --- /dev/null +++ b/tools/testing/selftests/bpf/progs/access_map_in_map.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include +#include +#include + +#include "bpf_misc.h" + +struct inner_map_type { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, 4); + __uint(value_size, 4); + __uint(max_entries, 1); +} inner_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_array_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_htab_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +char _license[] SEC("license") = "GPL"; + +int tgid = 0; + +static int acc_map_in_map(void *outer_map) +{ + int i, key, value = 0xdeadbeef; + void *inner_map; + + if ((bpf_get_current_pid_tgid() >> 32) != tgid) + return 0; + + /* Find nonexistent inner map */ + key = 1; + inner_map = bpf_map_lookup_elem(outer_map, &key); + if (inner_map) + return 0; + + /* Find the old inner map */ + key = 0; + inner_map = bpf_map_lookup_elem(outer_map, &key); + if (!inner_map) + return 0; + + /* Wait for the old inner map to be replaced */ + for (i = 0; i < 2048; i++) + bpf_map_update_elem(inner_map, &key, &value, 0); + + return 0; +} + +SEC("?kprobe/" SYS_PREFIX "sys_getpgid") +int access_map_in_array(void *ctx) +{ + return acc_map_in_map(&outer_array_map); +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int sleepable_access_map_in_array(void *ctx) +{ + return acc_map_in_map(&outer_array_map); +} + +SEC("?kprobe/" SYS_PREFIX "sys_getpgid") +int access_map_in_htab(void *ctx) +{ + return acc_map_in_map(&outer_htab_map); +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int sleepable_access_map_in_htab(void *ctx) +{ + return acc_map_in_map(&outer_htab_map); +} From e3dd40828534a67931e0dd00fcd35846271fd4e8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Mon, 4 Dec 2023 22:04:25 +0800 Subject: [PATCH 2489/7721] selftests/bpf: Test outer map update operations in syscall program Syscall program is running with rcu_read_lock_trace being held, so if bpf_map_update_elem() or bpf_map_delete_elem() invokes synchronize_rcu_tasks_trace() when operating on an outer map, there will be dead-lock, so add a test to guarantee that it is dead-lock free. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231204140425.1480317-8-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/syscall.c | 30 +++++- tools/testing/selftests/bpf/progs/syscall.c | 96 ++++++++++++++++++- 2 files changed, 119 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/syscall.c b/tools/testing/selftests/bpf/prog_tests/syscall.c index f4d40001155a..0be8301c0ffd 100644 --- a/tools/testing/selftests/bpf/prog_tests/syscall.c +++ b/tools/testing/selftests/bpf/prog_tests/syscall.c @@ -12,7 +12,7 @@ struct args { int btf_fd; }; -void test_syscall(void) +static void test_syscall_load_prog(void) { static char verifier_log[8192]; struct args ctx = { @@ -32,7 +32,7 @@ void test_syscall(void) if (!ASSERT_OK_PTR(skel, "skel_load")) goto cleanup; - prog_fd = bpf_program__fd(skel->progs.bpf_prog); + prog_fd = bpf_program__fd(skel->progs.load_prog); err = bpf_prog_test_run_opts(prog_fd, &tattr); ASSERT_EQ(err, 0, "err"); ASSERT_EQ(tattr.retval, 1, "retval"); @@ -53,3 +53,29 @@ void test_syscall(void) if (ctx.btf_fd > 0) close(ctx.btf_fd); } + +static void test_syscall_update_outer_map(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts); + struct syscall *skel; + int err, prog_fd; + + skel = syscall__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_load")) + goto cleanup; + + prog_fd = bpf_program__fd(skel->progs.update_outer_map); + err = bpf_prog_test_run_opts(prog_fd, &opts); + ASSERT_EQ(err, 0, "err"); + ASSERT_EQ(opts.retval, 1, "retval"); +cleanup: + syscall__destroy(skel); +} + +void test_syscall(void) +{ + if (test__start_subtest("load_prog")) + test_syscall_load_prog(); + if (test__start_subtest("update_outer_map")) + test_syscall_update_outer_map(); +} diff --git a/tools/testing/selftests/bpf/progs/syscall.c b/tools/testing/selftests/bpf/progs/syscall.c index e550f728962d..3d3cafdebe72 100644 --- a/tools/testing/selftests/bpf/progs/syscall.c +++ b/tools/testing/selftests/bpf/progs/syscall.c @@ -6,9 +6,15 @@ #include #include <../../../tools/include/linux/filter.h> #include +#include +#include char _license[] SEC("license") = "GPL"; +struct bpf_map { + int id; +} __attribute__((preserve_access_index)); + struct args { __u64 log_buf; __u32 log_size; @@ -27,6 +33,37 @@ struct args { BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ BTF_INT_ENC(encoding, bits_offset, bits) +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, union bpf_attr); + __uint(max_entries, 1); +} bpf_attr_array SEC(".maps"); + +struct inner_map_type { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, 4); + __uint(value_size, 4); + __uint(max_entries, 1); +} inner_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_array_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64) (unsigned long) ptr; +} + static int btf_load(void) { struct btf_blob { @@ -58,7 +95,7 @@ static int btf_load(void) } SEC("syscall") -int bpf_prog(struct args *ctx) +int load_prog(struct args *ctx) { static char license[] = "GPL"; static struct bpf_insn insns[] = { @@ -94,8 +131,8 @@ int bpf_prog(struct args *ctx) map_create_attr.max_entries = ctx->max_entries; map_create_attr.btf_fd = ret; - prog_load_attr.license = (long) license; - prog_load_attr.insns = (long) insns; + prog_load_attr.license = ptr_to_u64(license); + prog_load_attr.insns = ptr_to_u64(insns); prog_load_attr.log_buf = ctx->log_buf; prog_load_attr.log_size = ctx->log_size; prog_load_attr.log_level = 1; @@ -107,8 +144,8 @@ int bpf_prog(struct args *ctx) insns[3].imm = ret; map_update_attr.map_fd = ret; - map_update_attr.key = (long) &key; - map_update_attr.value = (long) &value; + map_update_attr.key = ptr_to_u64(&key); + map_update_attr.value = ptr_to_u64(&value); ret = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, &map_update_attr, sizeof(map_update_attr)); if (ret < 0) return ret; @@ -119,3 +156,52 @@ int bpf_prog(struct args *ctx) ctx->prog_fd = ret; return 1; } + +SEC("syscall") +int update_outer_map(void *ctx) +{ + int zero = 0, ret = 0, outer_fd = -1, inner_fd = -1, err; + const int attr_sz = sizeof(union bpf_attr); + union bpf_attr *attr; + + attr = bpf_map_lookup_elem((struct bpf_map *)&bpf_attr_array, &zero); + if (!attr) + goto out; + + memset(attr, 0, attr_sz); + attr->map_id = ((struct bpf_map *)&outer_array_map)->id; + outer_fd = bpf_sys_bpf(BPF_MAP_GET_FD_BY_ID, attr, attr_sz); + if (outer_fd < 0) + goto out; + + memset(attr, 0, attr_sz); + attr->map_type = BPF_MAP_TYPE_ARRAY; + attr->key_size = 4; + attr->value_size = 4; + attr->max_entries = 1; + inner_fd = bpf_sys_bpf(BPF_MAP_CREATE, attr, attr_sz); + if (inner_fd < 0) + goto out; + + memset(attr, 0, attr_sz); + attr->map_fd = outer_fd; + attr->key = ptr_to_u64(&zero); + attr->value = ptr_to_u64(&inner_fd); + err = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, attr, attr_sz); + if (err) + goto out; + + memset(attr, 0, attr_sz); + attr->map_fd = outer_fd; + attr->key = ptr_to_u64(&zero); + err = bpf_sys_bpf(BPF_MAP_DELETE_ELEM, attr, attr_sz); + if (err) + goto out; + ret = 1; +out: + if (inner_fd >= 0) + bpf_sys_close(inner_fd); + if (outer_fd >= 0) + bpf_sys_close(outer_fd); + return ret; +} From bc877956272f0521fef107838555817112a450dc Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:29 -0800 Subject: [PATCH 2490/7721] netdev-genl: spec: Extend netdev netlink spec in YAML for queue Add support in netlink spec(netdev.yaml) for queue information. Add code generated from the spec. Note: The "queue-type" attribute takes values 0 and 1 for rx and tx queue type respectively. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147330963.5260.2576294626647300472.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/netdev.yaml | 52 ++++++++ include/uapi/linux/netdev.h | 16 +++ net/core/netdev-genl-gen.c | 26 ++++ net/core/netdev-genl-gen.h | 3 + net/core/netdev-genl.c | 10 ++ tools/include/uapi/linux/netdev.h | 16 +++ tools/net/ynl/generated/netdev-user.c | 153 ++++++++++++++++++++++++ tools/net/ynl/generated/netdev-user.h | 99 +++++++++++++++ 8 files changed, 375 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index eef6358ec587..719e6aafbfdb 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -66,6 +66,10 @@ definitions: name: tx-checksum doc: L3 checksum HW offload is supported by the driver. + - + name: queue-type + type: enum + entries: [ rx, tx ] attribute-sets: - @@ -209,6 +213,31 @@ attribute-sets: name: recycle-released-refcnt type: uint + - + name: queue + attributes: + - + name: id + doc: Queue index; most queue types are indexed like a C array, with + indexes starting at 0 and ending at queue count - 1. Queue indexes + are scoped to an interface and queue type. + type: u32 + - + name: ifindex + doc: ifindex of the netdevice to which the queue belongs. + type: u32 + checks: + min: 1 + - + name: type + doc: Queue type as rx, tx. Each queue type defines a separate ID space. + type: u32 + enum: queue-type + - + name: napi-id + doc: ID of the NAPI instance which services this queue. + type: u32 + operations: list: - @@ -307,6 +336,29 @@ operations: dump: reply: *pp-stats-reply config-cond: page-pool-stats + - + name: queue-get + doc: Get queue information from the kernel. + Only configured queues will be reported (as opposed to all available + hardware queues). + attribute-set: queue + do: + request: + attributes: + - ifindex + - type + - id + reply: &queue-get-op + attributes: + - id + - type + - napi-id + - ifindex + dump: + request: + attributes: + - ifindex + reply: *queue-get-op mcast-groups: list: diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 6244c0164976..f857960a7f06 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -62,6 +62,11 @@ enum netdev_xsk_flags { NETDEV_XSK_FLAGS_TX_CHECKSUM = 2, }; +enum netdev_queue_type { + NETDEV_QUEUE_TYPE_RX, + NETDEV_QUEUE_TYPE_TX, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, @@ -104,6 +109,16 @@ enum { NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) }; +enum { + NETDEV_A_QUEUE_ID = 1, + NETDEV_A_QUEUE_IFINDEX, + NETDEV_A_QUEUE_TYPE, + NETDEV_A_QUEUE_NAPI_ID, + + __NETDEV_A_QUEUE_MAX, + NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, @@ -114,6 +129,7 @@ enum { NETDEV_CMD_PAGE_POOL_DEL_NTF, NETDEV_CMD_PAGE_POOL_CHANGE_NTF, NETDEV_CMD_PAGE_POOL_STATS_GET, + NETDEV_CMD_QUEUE_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index dccd8c3a141e..b1dcf88c82cf 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -46,6 +46,18 @@ static const struct nla_policy netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAG }; #endif /* CONFIG_PAGE_POOL_STATS */ +/* NETDEV_CMD_QUEUE_GET - do */ +static const struct nla_policy netdev_queue_get_do_nl_policy[NETDEV_A_QUEUE_TYPE + 1] = { + [NETDEV_A_QUEUE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), + [NETDEV_A_QUEUE_TYPE] = NLA_POLICY_MAX(NLA_U32, 1), + [NETDEV_A_QUEUE_ID] = { .type = NLA_U32, }, +}; + +/* NETDEV_CMD_QUEUE_GET - dump */ +static const struct nla_policy netdev_queue_get_dump_nl_policy[NETDEV_A_QUEUE_IFINDEX + 1] = { + [NETDEV_A_QUEUE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), +}; + /* Ops table for netdev */ static const struct genl_split_ops netdev_nl_ops[] = { { @@ -88,6 +100,20 @@ static const struct genl_split_ops netdev_nl_ops[] = { .flags = GENL_CMD_CAP_DUMP, }, #endif /* CONFIG_PAGE_POOL_STATS */ + { + .cmd = NETDEV_CMD_QUEUE_GET, + .doit = netdev_nl_queue_get_doit, + .policy = netdev_queue_get_do_nl_policy, + .maxattr = NETDEV_A_QUEUE_TYPE, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = NETDEV_CMD_QUEUE_GET, + .dumpit = netdev_nl_queue_get_dumpit, + .policy = netdev_queue_get_dump_nl_policy, + .maxattr = NETDEV_A_QUEUE_IFINDEX, + .flags = GENL_CMD_CAP_DUMP, + }, }; static const struct genl_multicast_group netdev_nl_mcgrps[] = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index 649e4b46eccf..086623c1797a 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -23,6 +23,9 @@ int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int netdev_nl_queue_get_doit(struct sk_buff *skb, struct genl_info *info); +int netdev_nl_queue_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); enum { NETDEV_NLGRP_MGMT, diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 10f2124e9e23..35e2d692f651 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -140,6 +140,16 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +int netdev_nl_queue_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int netdev_nl_queue_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + return -EOPNOTSUPP; +} + static int netdev_genl_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) { diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 6244c0164976..f857960a7f06 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -62,6 +62,11 @@ enum netdev_xsk_flags { NETDEV_XSK_FLAGS_TX_CHECKSUM = 2, }; +enum netdev_queue_type { + NETDEV_QUEUE_TYPE_RX, + NETDEV_QUEUE_TYPE_TX, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, @@ -104,6 +109,16 @@ enum { NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) }; +enum { + NETDEV_A_QUEUE_ID = 1, + NETDEV_A_QUEUE_IFINDEX, + NETDEV_A_QUEUE_TYPE, + NETDEV_A_QUEUE_NAPI_ID, + + __NETDEV_A_QUEUE_MAX, + NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, @@ -114,6 +129,7 @@ enum { NETDEV_CMD_PAGE_POOL_DEL_NTF, NETDEV_CMD_PAGE_POOL_CHANGE_NTF, NETDEV_CMD_PAGE_POOL_STATS_GET, + NETDEV_CMD_QUEUE_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index 3b9dee94d4ce..fbf7e24ade91 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -23,6 +23,7 @@ static const char * const netdev_op_strmap[] = { [NETDEV_CMD_PAGE_POOL_DEL_NTF] = "page-pool-del-ntf", [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = "page-pool-change-ntf", [NETDEV_CMD_PAGE_POOL_STATS_GET] = "page-pool-stats-get", + [NETDEV_CMD_QUEUE_GET] = "queue-get", }; const char *netdev_op_str(int op) @@ -76,6 +77,18 @@ const char *netdev_xsk_flags_str(enum netdev_xsk_flags value) return netdev_xsk_flags_strmap[value]; } +static const char * const netdev_queue_type_strmap[] = { + [0] = "rx", + [1] = "tx", +}; + +const char *netdev_queue_type_str(enum netdev_queue_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_queue_type_strmap)) + return NULL; + return netdev_queue_type_strmap[value]; +} + /* Policies */ struct ynl_policy_attr netdev_page_pool_info_policy[NETDEV_A_PAGE_POOL_MAX + 1] = { [NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, }, @@ -135,6 +148,18 @@ struct ynl_policy_nest netdev_page_pool_stats_nest = { .table = netdev_page_pool_stats_policy, }; +struct ynl_policy_attr netdev_queue_policy[NETDEV_A_QUEUE_MAX + 1] = { + [NETDEV_A_QUEUE_ID] = { .name = "id", .type = YNL_PT_U32, }, + [NETDEV_A_QUEUE_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, + [NETDEV_A_QUEUE_TYPE] = { .name = "type", .type = YNL_PT_U32, }, + [NETDEV_A_QUEUE_NAPI_ID] = { .name = "napi-id", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest netdev_queue_nest = { + .max_attr = NETDEV_A_QUEUE_MAX, + .table = netdev_queue_policy, +}; + /* Common nested types */ void netdev_page_pool_info_free(struct netdev_page_pool_info *obj) { @@ -617,6 +642,134 @@ netdev_page_pool_stats_get_dump(struct ynl_sock *ys) return NULL; } +/* ============== NETDEV_CMD_QUEUE_GET ============== */ +/* NETDEV_CMD_QUEUE_GET - do */ +void netdev_queue_get_req_free(struct netdev_queue_get_req *req) +{ + free(req); +} + +void netdev_queue_get_rsp_free(struct netdev_queue_get_rsp *rsp) +{ + free(rsp); +} + +int netdev_queue_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct netdev_queue_get_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_QUEUE_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.id = 1; + dst->id = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_QUEUE_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.type = 1; + dst->type = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_QUEUE_NAPI_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.napi_id = 1; + dst->napi_id = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_QUEUE_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct netdev_queue_get_rsp * +netdev_queue_get(struct ynl_sock *ys, struct netdev_queue_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct netdev_queue_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_QUEUE_GET, 1); + ys->req_policy = &netdev_queue_nest; + yrs.yarg.rsp_policy = &netdev_queue_nest; + + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_IFINDEX, req->ifindex); + if (req->_present.type) + mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_TYPE, req->type); + if (req->_present.id) + mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_ID, req->id); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = netdev_queue_get_rsp_parse; + yrs.rsp_cmd = NETDEV_CMD_QUEUE_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + netdev_queue_get_rsp_free(rsp); + return NULL; +} + +/* NETDEV_CMD_QUEUE_GET - dump */ +void netdev_queue_get_list_free(struct netdev_queue_get_list *rsp) +{ + struct netdev_queue_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp); + } +} + +struct netdev_queue_get_list * +netdev_queue_get_dump(struct ynl_sock *ys, + struct netdev_queue_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct netdev_queue_get_list); + yds.cb = netdev_queue_get_rsp_parse; + yds.rsp_cmd = NETDEV_CMD_QUEUE_GET; + yds.rsp_policy = &netdev_queue_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_QUEUE_GET, 1); + ys->req_policy = &netdev_queue_nest; + + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_IFINDEX, req->ifindex); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + netdev_queue_get_list_free(yds.first); + return NULL; +} + static const struct ynl_ntf_info netdev_ntf_info[] = { [NETDEV_CMD_DEV_ADD_NTF] = { .alloc_sz = sizeof(struct netdev_dev_get_ntf), diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index cc3d80d1cf8c..d7daf6df3df0 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -20,6 +20,7 @@ const char *netdev_op_str(int op); const char *netdev_xdp_act_str(enum netdev_xdp_act value); const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); const char *netdev_xsk_flags_str(enum netdev_xsk_flags value); +const char *netdev_queue_type_str(enum netdev_queue_type value); /* Common nested types */ struct netdev_page_pool_info { @@ -261,4 +262,102 @@ netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp struct netdev_page_pool_stats_get_list * netdev_page_pool_stats_get_dump(struct ynl_sock *ys); +/* ============== NETDEV_CMD_QUEUE_GET ============== */ +/* NETDEV_CMD_QUEUE_GET - do */ +struct netdev_queue_get_req { + struct { + __u32 ifindex:1; + __u32 type:1; + __u32 id:1; + } _present; + + __u32 ifindex; + enum netdev_queue_type type; + __u32 id; +}; + +static inline struct netdev_queue_get_req *netdev_queue_get_req_alloc(void) +{ + return calloc(1, sizeof(struct netdev_queue_get_req)); +} +void netdev_queue_get_req_free(struct netdev_queue_get_req *req); + +static inline void +netdev_queue_get_req_set_ifindex(struct netdev_queue_get_req *req, + __u32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} +static inline void +netdev_queue_get_req_set_type(struct netdev_queue_get_req *req, + enum netdev_queue_type type) +{ + req->_present.type = 1; + req->type = type; +} +static inline void +netdev_queue_get_req_set_id(struct netdev_queue_get_req *req, __u32 id) +{ + req->_present.id = 1; + req->id = id; +} + +struct netdev_queue_get_rsp { + struct { + __u32 id:1; + __u32 type:1; + __u32 napi_id:1; + __u32 ifindex:1; + } _present; + + __u32 id; + enum netdev_queue_type type; + __u32 napi_id; + __u32 ifindex; +}; + +void netdev_queue_get_rsp_free(struct netdev_queue_get_rsp *rsp); + +/* + * Get queue information from the kernel. Only configured queues will be reported (as opposed to all available hardware queues). + */ +struct netdev_queue_get_rsp * +netdev_queue_get(struct ynl_sock *ys, struct netdev_queue_get_req *req); + +/* NETDEV_CMD_QUEUE_GET - dump */ +struct netdev_queue_get_req_dump { + struct { + __u32 ifindex:1; + } _present; + + __u32 ifindex; +}; + +static inline struct netdev_queue_get_req_dump * +netdev_queue_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct netdev_queue_get_req_dump)); +} +void netdev_queue_get_req_dump_free(struct netdev_queue_get_req_dump *req); + +static inline void +netdev_queue_get_req_dump_set_ifindex(struct netdev_queue_get_req_dump *req, + __u32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} + +struct netdev_queue_get_list { + struct netdev_queue_get_list *next; + struct netdev_queue_get_rsp obj __attribute__((aligned(8))); +}; + +void netdev_queue_get_list_free(struct netdev_queue_get_list *rsp); + +struct netdev_queue_get_list * +netdev_queue_get_dump(struct ynl_sock *ys, + struct netdev_queue_get_req_dump *req); + #endif /* _LINUX_NETDEV_GEN_H */ From 2a502ff0c4e42a739b5aa550c901bf3852795532 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:34 -0800 Subject: [PATCH 2491/7721] net: Add queue and napi association Add the napi pointer in netdev queue for tracking the napi instance for each queue. This achieves the queue<->napi mapping. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147331483.5260.15723438819994285695.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- include/linux/netdevice.h | 8 ++++++++ include/net/netdev_rx_queue.h | 4 ++++ net/core/dev.c | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c2d74bc112dd..5ddff11cbe26 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -665,6 +665,10 @@ struct netdev_queue { #ifdef CONFIG_XDP_SOCKETS struct xsk_buff_pool *pool; #endif + /* NAPI instance for the queue + * Readers and writers must hold RTNL + */ + struct napi_struct *napi; /* * write-mostly part */ @@ -2657,6 +2661,10 @@ static inline void *netdev_priv(const struct net_device *dev) */ #define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype)) +void netif_queue_set_napi(struct net_device *dev, unsigned int queue_index, + enum netdev_queue_type type, + struct napi_struct *napi); + /* Default NAPI poll() weight * Device drivers are strongly advised to not use bigger value */ diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h index cdcafb30d437..aa1716fb0e53 100644 --- a/include/net/netdev_rx_queue.h +++ b/include/net/netdev_rx_queue.h @@ -21,6 +21,10 @@ struct netdev_rx_queue { #ifdef CONFIG_XDP_SOCKETS struct xsk_buff_pool *pool; #endif + /* NAPI instance for the queue + * Readers and writers must hold RTNL + */ + struct napi_struct *napi; } ____cacheline_aligned_in_smp; /* diff --git a/net/core/dev.c b/net/core/dev.c index 3950ced396b5..0a2eecbeef38 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6400,6 +6400,43 @@ int dev_set_threaded(struct net_device *dev, bool threaded) } EXPORT_SYMBOL(dev_set_threaded); +/** + * netif_queue_set_napi - Associate queue with the napi + * @dev: device to which NAPI and queue belong + * @queue_index: Index of queue + * @type: queue type as RX or TX + * @napi: NAPI context, pass NULL to clear previously set NAPI + * + * Set queue with its corresponding napi context. This should be done after + * registering the NAPI handler for the queue-vector and the queues have been + * mapped to the corresponding interrupt vector. + */ +void netif_queue_set_napi(struct net_device *dev, unsigned int queue_index, + enum netdev_queue_type type, struct napi_struct *napi) +{ + struct netdev_rx_queue *rxq; + struct netdev_queue *txq; + + if (WARN_ON_ONCE(napi && !napi->dev)) + return; + if (dev->reg_state >= NETREG_REGISTERED) + ASSERT_RTNL(); + + switch (type) { + case NETDEV_QUEUE_TYPE_RX: + rxq = __netif_get_rx_queue(dev, queue_index); + rxq->napi = napi; + return; + case NETDEV_QUEUE_TYPE_TX: + txq = netdev_get_tx_queue(dev, queue_index); + txq->napi = napi; + return; + default: + return; + } +} +EXPORT_SYMBOL(netif_queue_set_napi); + void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight) { From 91fdbce7e8d69be255b45bfeb52092629a50e267 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:40 -0800 Subject: [PATCH 2492/7721] ice: Add support in the driver for associating queue with napi After the napi context is initialized, map the napi instance with the queue/queue-set on the corresponding irq line. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147332060.5260.13310934657151560599.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_base.c | 12 +++- drivers/net/ethernet/intel/ice/ice_lib.c | 67 +++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 4 ++ drivers/net/ethernet/intel/ice/ice_main.c | 4 +- 4 files changed, 84 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 7fa43827a3f0..edad5f9ab16c 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -189,10 +189,18 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) } q_vector = vsi->q_vectors[v_idx]; - ice_for_each_tx_ring(tx_ring, q_vector->tx) + ice_for_each_tx_ring(tx_ring, q_vector->tx) { + if (vsi->netdev) + netif_queue_set_napi(vsi->netdev, tx_ring->q_index, + NETDEV_QUEUE_TYPE_TX, NULL); tx_ring->q_vector = NULL; - ice_for_each_rx_ring(rx_ring, q_vector->rx) + } + ice_for_each_rx_ring(rx_ring, q_vector->rx) { + if (vsi->netdev) + netif_queue_set_napi(vsi->netdev, rx_ring->q_index, + NETDEV_QUEUE_TYPE_RX, NULL); rx_ring->q_vector = NULL; + } /* only VSI with an associated netdev is set up with NAPI */ if (vsi->netdev) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index d826b5afa143..83f6977fad22 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2452,6 +2452,10 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) goto unroll_vector_base; ice_vsi_map_rings_to_vectors(vsi); + + /* Associate q_vector rings to napi */ + ice_vsi_set_napi_queues(vsi, true); + vsi->stat_offsets_loaded = false; if (ice_is_xdp_ena_vsi(vsi)) { @@ -2931,6 +2935,69 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) synchronize_irq(vsi->q_vectors[i]->irq.virq); } +/** + * ice_queue_set_napi - Set the napi instance for the queue + * @dev: device to which NAPI and queue belong + * @queue_index: Index of queue + * @type: queue type as RX or TX + * @napi: NAPI context + * @locked: is the rtnl_lock already held + * + * Set the napi instance for the queue + */ +static void +ice_queue_set_napi(struct net_device *dev, unsigned int queue_index, + enum netdev_queue_type type, struct napi_struct *napi, + bool locked) +{ + if (!locked) + rtnl_lock(); + netif_queue_set_napi(dev, queue_index, type, napi); + if (!locked) + rtnl_unlock(); +} + +/** + * ice_q_vector_set_napi_queues - Map queue[s] associated with the napi + * @q_vector: q_vector pointer + * @locked: is the rtnl_lock already held + * + * Associate the q_vector napi with all the queue[s] on the vector + */ +void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked) +{ + struct ice_rx_ring *rx_ring; + struct ice_tx_ring *tx_ring; + + ice_for_each_rx_ring(rx_ring, q_vector->rx) + ice_queue_set_napi(q_vector->vsi->netdev, rx_ring->q_index, + NETDEV_QUEUE_TYPE_RX, &q_vector->napi, + locked); + + ice_for_each_tx_ring(tx_ring, q_vector->tx) + ice_queue_set_napi(q_vector->vsi->netdev, tx_ring->q_index, + NETDEV_QUEUE_TYPE_TX, &q_vector->napi, + locked); +} + +/** + * ice_vsi_set_napi_queues + * @vsi: VSI pointer + * @locked: is the rtnl_lock already held + * + * Associate queue[s] with napi for all vectors + */ +void ice_vsi_set_napi_queues(struct ice_vsi *vsi, bool locked) +{ + int i; + + if (!vsi->netdev) + return; + + ice_for_each_q_vector(vsi, i) + ice_q_vector_set_napi_queues(vsi->q_vectors[i], locked); +} + /** * ice_vsi_release - Delete a VSI and free its resources * @vsi: the VSI being removed diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index f24f5d1e6f9c..71bd27244941 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -91,6 +91,10 @@ void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc); struct ice_vsi * ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params); +void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked); + +void ice_vsi_set_napi_queues(struct ice_vsi *vsi, bool locked); + int ice_vsi_release(struct ice_vsi *vsi); void ice_vsi_close(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 43ba3e55b8c1..9e3d3919307b 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3375,9 +3375,11 @@ static void ice_napi_add(struct ice_vsi *vsi) if (!vsi->netdev) return; - ice_for_each_q_vector(vsi, v_idx) + ice_for_each_q_vector(vsi, v_idx) { netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi, ice_napi_poll); + ice_q_vector_set_napi_queues(vsi->q_vectors[v_idx], false); + } } /** From 6b6171db7fc8f7a6d0f0f0acb7aff16cecf14f42 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:46 -0800 Subject: [PATCH 2493/7721] netdev-genl: Add netlink framework functions for queue Implement the netdev netlink framework functions for exposing queue information. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147332603.5260.7982559672617639065.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- net/core/netdev-genl.c | 187 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 3 deletions(-) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 35e2d692f651..3bc1661e6ebf 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -7,9 +7,23 @@ #include #include #include +#include #include "netdev-genl-gen.h" +struct netdev_nl_dump_ctx { + unsigned long ifindex; + unsigned int rxq_idx; + unsigned int txq_idx; +}; + +static struct netdev_nl_dump_ctx *netdev_dump_ctx(struct netlink_callback *cb) +{ + NL_ASSERT_DUMP_CTX_FITS(struct netdev_nl_dump_ctx); + + return (struct netdev_nl_dump_ctx *)cb->ctx; +} + static int netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, const struct genl_info *info) @@ -122,12 +136,13 @@ int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info) int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { + struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); struct net *net = sock_net(skb->sk); struct net_device *netdev; int err = 0; rtnl_lock(); - for_each_netdev_dump(net, netdev, cb->args[0]) { + for_each_netdev_dump(net, netdev, ctx->ifindex) { err = netdev_nl_dev_fill(netdev, skb, genl_info_dump(cb)); if (err < 0) break; @@ -140,14 +155,180 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static int +netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev, + u32 q_idx, u32 q_type, const struct genl_info *info) +{ + struct netdev_rx_queue *rxq; + struct netdev_queue *txq; + void *hdr; + + hdr = genlmsg_iput(rsp, info); + if (!hdr) + return -EMSGSIZE; + + if (nla_put_u32(rsp, NETDEV_A_QUEUE_ID, q_idx) || + nla_put_u32(rsp, NETDEV_A_QUEUE_TYPE, q_type) || + nla_put_u32(rsp, NETDEV_A_QUEUE_IFINDEX, netdev->ifindex)) + goto nla_put_failure; + + switch (q_type) { + case NETDEV_QUEUE_TYPE_RX: + rxq = __netif_get_rx_queue(netdev, q_idx); + if (rxq->napi && nla_put_u32(rsp, NETDEV_A_QUEUE_NAPI_ID, + rxq->napi->napi_id)) + goto nla_put_failure; + break; + case NETDEV_QUEUE_TYPE_TX: + txq = netdev_get_tx_queue(netdev, q_idx); + if (txq->napi && nla_put_u32(rsp, NETDEV_A_QUEUE_NAPI_ID, + txq->napi->napi_id)) + goto nla_put_failure; + } + + genlmsg_end(rsp, hdr); + + return 0; + +nla_put_failure: + genlmsg_cancel(rsp, hdr); + return -EMSGSIZE; +} + +static int netdev_nl_queue_validate(struct net_device *netdev, u32 q_id, + u32 q_type) +{ + switch (q_type) { + case NETDEV_QUEUE_TYPE_RX: + if (q_id >= netdev->real_num_rx_queues) + return -EINVAL; + return 0; + case NETDEV_QUEUE_TYPE_TX: + if (q_id >= netdev->real_num_tx_queues) + return -EINVAL; + } + return 0; +} + +static int +netdev_nl_queue_fill(struct sk_buff *rsp, struct net_device *netdev, u32 q_idx, + u32 q_type, const struct genl_info *info) +{ + int err = 0; + + if (!(netdev->flags & IFF_UP)) + return err; + + err = netdev_nl_queue_validate(netdev, q_idx, q_type); + if (err) + return err; + + return netdev_nl_queue_fill_one(rsp, netdev, q_idx, q_type, info); +} + int netdev_nl_queue_get_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + u32 q_id, q_type, ifindex; + struct net_device *netdev; + struct sk_buff *rsp; + int err; + + if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_ID) || + GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_TYPE) || + GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_IFINDEX)) + return -EINVAL; + + q_id = nla_get_u32(info->attrs[NETDEV_A_QUEUE_ID]); + q_type = nla_get_u32(info->attrs[NETDEV_A_QUEUE_TYPE]); + ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]); + + rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!rsp) + return -ENOMEM; + + rtnl_lock(); + + netdev = __dev_get_by_index(genl_info_net(info), ifindex); + if (netdev) + err = netdev_nl_queue_fill(rsp, netdev, q_id, q_type, info); + else + err = -ENODEV; + + rtnl_unlock(); + + if (err) + goto err_free_msg; + + return genlmsg_reply(rsp, info); + +err_free_msg: + nlmsg_free(rsp); + return err; +} + +static int +netdev_nl_queue_dump_one(struct net_device *netdev, struct sk_buff *rsp, + const struct genl_info *info, + struct netdev_nl_dump_ctx *ctx) +{ + int err = 0; + int i; + + if (!(netdev->flags & IFF_UP)) + return err; + + for (i = ctx->rxq_idx; i < netdev->real_num_rx_queues;) { + err = netdev_nl_queue_fill_one(rsp, netdev, i, + NETDEV_QUEUE_TYPE_RX, info); + if (err) + return err; + ctx->rxq_idx = i++; + } + for (i = ctx->txq_idx; i < netdev->real_num_tx_queues;) { + err = netdev_nl_queue_fill_one(rsp, netdev, i, + NETDEV_QUEUE_TYPE_TX, info); + if (err) + return err; + ctx->txq_idx = i++; + } + + return err; } int netdev_nl_queue_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - return -EOPNOTSUPP; + struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); + const struct genl_info *info = genl_info_dump(cb); + struct net *net = sock_net(skb->sk); + struct net_device *netdev; + u32 ifindex = 0; + int err = 0; + + if (info->attrs[NETDEV_A_QUEUE_IFINDEX]) + ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]); + + rtnl_lock(); + if (ifindex) { + netdev = __dev_get_by_index(net, ifindex); + if (netdev) + err = netdev_nl_queue_dump_one(netdev, skb, info, ctx); + else + err = -ENODEV; + } else { + for_each_netdev_dump(net, netdev, ctx->ifindex) { + err = netdev_nl_queue_dump_one(netdev, skb, info, ctx); + if (err < 0) + break; + ctx->rxq_idx = 0; + ctx->txq_idx = 0; + } + } + rtnl_unlock(); + + if (err != -EMSGSIZE) + return err; + + return skb->len; } static int netdev_genl_netdevice_event(struct notifier_block *nb, From ff9991499fb53575c45eb92cd064bcd7141bb572 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:51 -0800 Subject: [PATCH 2494/7721] netdev-genl: spec: Extend netdev netlink spec in YAML for NAPI Add support in netlink spec(netdev.yaml) for napi related information. Add code generated from the spec. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147333119.5260.7050639053080529108.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/netdev.yaml | 30 ++++++ include/uapi/linux/netdev.h | 9 ++ net/core/netdev-genl-gen.c | 24 +++++ net/core/netdev-genl-gen.h | 2 + net/core/netdev-genl.c | 10 ++ tools/include/uapi/linux/netdev.h | 9 ++ tools/net/ynl/generated/netdev-user.c | 124 ++++++++++++++++++++++++ tools/net/ynl/generated/netdev-user.h | 75 ++++++++++++++ 8 files changed, 283 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 719e6aafbfdb..76d6b2e15b67 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -213,6 +213,19 @@ attribute-sets: name: recycle-released-refcnt type: uint + - + name: napi + attributes: + - + name: ifindex + doc: ifindex of the netdevice to which NAPI instance belongs. + type: u32 + checks: + min: 1 + - + name: id + doc: ID of the NAPI instance. + type: u32 - name: queue attributes: @@ -359,6 +372,23 @@ operations: attributes: - ifindex reply: *queue-get-op + - + name: napi-get + doc: Get information about NAPI instances configured on the system. + attribute-set: napi + do: + request: + attributes: + - id + reply: &napi-get-op + attributes: + - id + - ifindex + dump: + request: + attributes: + - ifindex + reply: *napi-get-op mcast-groups: list: diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index f857960a7f06..e7bdbcb01f22 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -109,6 +109,14 @@ enum { NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) }; +enum { + NETDEV_A_NAPI_IFINDEX = 1, + NETDEV_A_NAPI_ID, + + __NETDEV_A_NAPI_MAX, + NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) +}; + enum { NETDEV_A_QUEUE_ID = 1, NETDEV_A_QUEUE_IFINDEX, @@ -130,6 +138,7 @@ enum { NETDEV_CMD_PAGE_POOL_CHANGE_NTF, NETDEV_CMD_PAGE_POOL_STATS_GET, NETDEV_CMD_QUEUE_GET, + NETDEV_CMD_NAPI_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index b1dcf88c82cf..be7f2ebd61b2 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -58,6 +58,16 @@ static const struct nla_policy netdev_queue_get_dump_nl_policy[NETDEV_A_QUEUE_IF [NETDEV_A_QUEUE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), }; +/* NETDEV_CMD_NAPI_GET - do */ +static const struct nla_policy netdev_napi_get_do_nl_policy[NETDEV_A_NAPI_ID + 1] = { + [NETDEV_A_NAPI_ID] = { .type = NLA_U32, }, +}; + +/* NETDEV_CMD_NAPI_GET - dump */ +static const struct nla_policy netdev_napi_get_dump_nl_policy[NETDEV_A_NAPI_IFINDEX + 1] = { + [NETDEV_A_NAPI_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), +}; + /* Ops table for netdev */ static const struct genl_split_ops netdev_nl_ops[] = { { @@ -114,6 +124,20 @@ static const struct genl_split_ops netdev_nl_ops[] = { .maxattr = NETDEV_A_QUEUE_IFINDEX, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = NETDEV_CMD_NAPI_GET, + .doit = netdev_nl_napi_get_doit, + .policy = netdev_napi_get_do_nl_policy, + .maxattr = NETDEV_A_NAPI_ID, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = NETDEV_CMD_NAPI_GET, + .dumpit = netdev_nl_napi_get_dumpit, + .policy = netdev_napi_get_dump_nl_policy, + .maxattr = NETDEV_A_NAPI_IFINDEX, + .flags = GENL_CMD_CAP_DUMP, + }, }; static const struct genl_multicast_group netdev_nl_mcgrps[] = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index 086623c1797a..a47f2bcbe4fa 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -26,6 +26,8 @@ int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb, int netdev_nl_queue_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_queue_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info); +int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); enum { NETDEV_NLGRP_MGMT, diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 3bc1661e6ebf..4c8ea6a4f015 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -155,6 +155,16 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + return -EOPNOTSUPP; +} + static int netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev, u32 q_idx, u32 q_type, const struct genl_info *info) diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index f857960a7f06..e7bdbcb01f22 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -109,6 +109,14 @@ enum { NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) }; +enum { + NETDEV_A_NAPI_IFINDEX = 1, + NETDEV_A_NAPI_ID, + + __NETDEV_A_NAPI_MAX, + NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) +}; + enum { NETDEV_A_QUEUE_ID = 1, NETDEV_A_QUEUE_IFINDEX, @@ -130,6 +138,7 @@ enum { NETDEV_CMD_PAGE_POOL_CHANGE_NTF, NETDEV_CMD_PAGE_POOL_STATS_GET, NETDEV_CMD_QUEUE_GET, + NETDEV_CMD_NAPI_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index fbf7e24ade91..906b61554698 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -24,6 +24,7 @@ static const char * const netdev_op_strmap[] = { [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = "page-pool-change-ntf", [NETDEV_CMD_PAGE_POOL_STATS_GET] = "page-pool-stats-get", [NETDEV_CMD_QUEUE_GET] = "queue-get", + [NETDEV_CMD_NAPI_GET] = "napi-get", }; const char *netdev_op_str(int op) @@ -160,6 +161,16 @@ struct ynl_policy_nest netdev_queue_nest = { .table = netdev_queue_policy, }; +struct ynl_policy_attr netdev_napi_policy[NETDEV_A_NAPI_MAX + 1] = { + [NETDEV_A_NAPI_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, + [NETDEV_A_NAPI_ID] = { .name = "id", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest netdev_napi_nest = { + .max_attr = NETDEV_A_NAPI_MAX, + .table = netdev_napi_policy, +}; + /* Common nested types */ void netdev_page_pool_info_free(struct netdev_page_pool_info *obj) { @@ -770,6 +781,119 @@ netdev_queue_get_dump(struct ynl_sock *ys, return NULL; } +/* ============== NETDEV_CMD_NAPI_GET ============== */ +/* NETDEV_CMD_NAPI_GET - do */ +void netdev_napi_get_req_free(struct netdev_napi_get_req *req) +{ + free(req); +} + +void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp) +{ + free(rsp); +} + +int netdev_napi_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct netdev_napi_get_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_NAPI_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.id = 1; + dst->id = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_NAPI_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct netdev_napi_get_rsp * +netdev_napi_get(struct ynl_sock *ys, struct netdev_napi_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct netdev_napi_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_NAPI_GET, 1); + ys->req_policy = &netdev_napi_nest; + yrs.yarg.rsp_policy = &netdev_napi_nest; + + if (req->_present.id) + mnl_attr_put_u32(nlh, NETDEV_A_NAPI_ID, req->id); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = netdev_napi_get_rsp_parse; + yrs.rsp_cmd = NETDEV_CMD_NAPI_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + netdev_napi_get_rsp_free(rsp); + return NULL; +} + +/* NETDEV_CMD_NAPI_GET - dump */ +void netdev_napi_get_list_free(struct netdev_napi_get_list *rsp) +{ + struct netdev_napi_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp); + } +} + +struct netdev_napi_get_list * +netdev_napi_get_dump(struct ynl_sock *ys, struct netdev_napi_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct netdev_napi_get_list); + yds.cb = netdev_napi_get_rsp_parse; + yds.rsp_cmd = NETDEV_CMD_NAPI_GET; + yds.rsp_policy = &netdev_napi_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_NAPI_GET, 1); + ys->req_policy = &netdev_napi_nest; + + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, NETDEV_A_NAPI_IFINDEX, req->ifindex); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + netdev_napi_get_list_free(yds.first); + return NULL; +} + static const struct ynl_ntf_info netdev_ntf_info[] = { [NETDEV_CMD_DEV_ADD_NTF] = { .alloc_sz = sizeof(struct netdev_dev_get_ntf), diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index d7daf6df3df0..481c9e45b689 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -360,4 +360,79 @@ struct netdev_queue_get_list * netdev_queue_get_dump(struct ynl_sock *ys, struct netdev_queue_get_req_dump *req); +/* ============== NETDEV_CMD_NAPI_GET ============== */ +/* NETDEV_CMD_NAPI_GET - do */ +struct netdev_napi_get_req { + struct { + __u32 id:1; + } _present; + + __u32 id; +}; + +static inline struct netdev_napi_get_req *netdev_napi_get_req_alloc(void) +{ + return calloc(1, sizeof(struct netdev_napi_get_req)); +} +void netdev_napi_get_req_free(struct netdev_napi_get_req *req); + +static inline void +netdev_napi_get_req_set_id(struct netdev_napi_get_req *req, __u32 id) +{ + req->_present.id = 1; + req->id = id; +} + +struct netdev_napi_get_rsp { + struct { + __u32 id:1; + __u32 ifindex:1; + } _present; + + __u32 id; + __u32 ifindex; +}; + +void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp); + +/* + * Get information about NAPI instances configured on the system. + */ +struct netdev_napi_get_rsp * +netdev_napi_get(struct ynl_sock *ys, struct netdev_napi_get_req *req); + +/* NETDEV_CMD_NAPI_GET - dump */ +struct netdev_napi_get_req_dump { + struct { + __u32 ifindex:1; + } _present; + + __u32 ifindex; +}; + +static inline struct netdev_napi_get_req_dump * +netdev_napi_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct netdev_napi_get_req_dump)); +} +void netdev_napi_get_req_dump_free(struct netdev_napi_get_req_dump *req); + +static inline void +netdev_napi_get_req_dump_set_ifindex(struct netdev_napi_get_req_dump *req, + __u32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} + +struct netdev_napi_get_list { + struct netdev_napi_get_list *next; + struct netdev_napi_get_rsp obj __attribute__((aligned(8))); +}; + +void netdev_napi_get_list_free(struct netdev_napi_get_list *rsp); + +struct netdev_napi_get_list * +netdev_napi_get_dump(struct ynl_sock *ys, struct netdev_napi_get_req_dump *req); + #endif /* _LINUX_NETDEV_GEN_H */ From 27f91aaf49b3a50e5a02ad5fa27b7c453d029a72 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:28:56 -0800 Subject: [PATCH 2495/7721] netdev-genl: Add netlink framework functions for napi Implement the netdev netlink framework functions for napi support. The netdev structure tracks all the napi instances and napi fields. The napi instances and associated parameters can be retrieved this way. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147333637.5260.14807433239805550815.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 3 +- net/core/dev.h | 2 + net/core/netdev-genl.c | 121 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 0a2eecbeef38..13c9d1580e62 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -165,7 +165,6 @@ static int netif_rx_internal(struct sk_buff *skb); static int call_netdevice_notifiers_extack(unsigned long val, struct net_device *dev, struct netlink_ext_ack *extack); -static struct napi_struct *napi_by_id(unsigned int napi_id); /* * The @dev_base_head list is protected by @dev_base_lock and the rtnl @@ -6139,7 +6138,7 @@ bool napi_complete_done(struct napi_struct *n, int work_done) EXPORT_SYMBOL(napi_complete_done); /* must be called under rcu_read_lock(), as we dont take a reference */ -static struct napi_struct *napi_by_id(unsigned int napi_id) +struct napi_struct *napi_by_id(unsigned int napi_id) { unsigned int hash = napi_id % HASH_SIZE(napi_hash); struct napi_struct *napi; diff --git a/net/core/dev.h b/net/core/dev.h index 5aa45f0fd4ae..7795b8ad841d 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -145,4 +145,6 @@ void xdp_do_check_flushed(struct napi_struct *napi); #else static inline void xdp_do_check_flushed(struct napi_struct *napi) { } #endif + +struct napi_struct *napi_by_id(unsigned int napi_id); #endif diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 4c8ea6a4f015..d55c92f9f26c 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -8,13 +8,16 @@ #include #include #include +#include #include "netdev-genl-gen.h" +#include "dev.h" struct netdev_nl_dump_ctx { unsigned long ifindex; unsigned int rxq_idx; unsigned int txq_idx; + unsigned int napi_id; }; static struct netdev_nl_dump_ctx *netdev_dump_ctx(struct netlink_callback *cb) @@ -155,14 +158,128 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static int +netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, + const struct genl_info *info) +{ + void *hdr; + + if (WARN_ON_ONCE(!napi->dev)) + return -EINVAL; + if (!(napi->dev->flags & IFF_UP)) + return 0; + + hdr = genlmsg_iput(rsp, info); + if (!hdr) + return -EMSGSIZE; + + if (napi->napi_id >= MIN_NAPI_ID && + nla_put_u32(rsp, NETDEV_A_NAPI_ID, napi->napi_id)) + goto nla_put_failure; + + if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex)) + goto nla_put_failure; + + genlmsg_end(rsp, hdr); + return 0; + +nla_put_failure: + genlmsg_cancel(rsp, hdr); + return -EMSGSIZE; +} + int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct napi_struct *napi; + struct sk_buff *rsp; + u32 napi_id; + int err; + + if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_ID)) + return -EINVAL; + + napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_ID]); + + rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!rsp) + return -ENOMEM; + + rtnl_lock(); + + napi = napi_by_id(napi_id); + if (napi) + err = netdev_nl_napi_fill_one(rsp, napi, info); + else + err = -EINVAL; + + rtnl_unlock(); + + if (err) + goto err_free_msg; + + return genlmsg_reply(rsp, info); + +err_free_msg: + nlmsg_free(rsp); + return err; +} + +static int +netdev_nl_napi_dump_one(struct net_device *netdev, struct sk_buff *rsp, + const struct genl_info *info, + struct netdev_nl_dump_ctx *ctx) +{ + struct napi_struct *napi; + int err = 0; + + if (!(netdev->flags & IFF_UP)) + return err; + + list_for_each_entry(napi, &netdev->napi_list, dev_list) { + if (ctx->napi_id && napi->napi_id >= ctx->napi_id) + continue; + + err = netdev_nl_napi_fill_one(rsp, napi, info); + if (err) + return err; + ctx->napi_id = napi->napi_id; + } + return err; } int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - return -EOPNOTSUPP; + struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); + const struct genl_info *info = genl_info_dump(cb); + struct net *net = sock_net(skb->sk); + struct net_device *netdev; + u32 ifindex = 0; + int err = 0; + + if (info->attrs[NETDEV_A_NAPI_IFINDEX]) + ifindex = nla_get_u32(info->attrs[NETDEV_A_NAPI_IFINDEX]); + + rtnl_lock(); + if (ifindex) { + netdev = __dev_get_by_index(net, ifindex); + if (netdev) + err = netdev_nl_napi_dump_one(netdev, skb, info, ctx); + else + err = -ENODEV; + } else { + for_each_netdev_dump(net, netdev, ctx->ifindex) { + err = netdev_nl_napi_dump_one(netdev, skb, info, ctx); + if (err < 0) + break; + ctx->napi_id = 0; + } + } + rtnl_unlock(); + + if (err != -EMSGSIZE) + return err; + + return skb->len; } static int From 5a5131d66fe02337de0b1b2e021b58f0f55c6df5 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:29:02 -0800 Subject: [PATCH 2496/7721] netdev-genl: spec: Add irq in netdev netlink YAML spec Add support in netlink spec(netdev.yaml) for interrupt number among the NAPI attributes. Add code generated from the spec. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147334210.5260.18178387869057516983.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/netdev.yaml | 5 +++++ include/uapi/linux/netdev.h | 1 + tools/include/uapi/linux/netdev.h | 1 + tools/net/ynl/generated/netdev-user.c | 6 ++++++ tools/net/ynl/generated/netdev-user.h | 2 ++ 5 files changed, 15 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 76d6b2e15b67..a3a1c6ad521b 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -226,6 +226,10 @@ attribute-sets: name: id doc: ID of the NAPI instance. type: u32 + - + name: irq + doc: The associated interrupt vector number for the napi + type: u32 - name: queue attributes: @@ -384,6 +388,7 @@ operations: attributes: - id - ifindex + - irq dump: request: attributes: diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index e7bdbcb01f22..30fea409b71e 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -112,6 +112,7 @@ enum { enum { NETDEV_A_NAPI_IFINDEX = 1, NETDEV_A_NAPI_ID, + NETDEV_A_NAPI_IRQ, __NETDEV_A_NAPI_MAX, NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index e7bdbcb01f22..30fea409b71e 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -112,6 +112,7 @@ enum { enum { NETDEV_A_NAPI_IFINDEX = 1, NETDEV_A_NAPI_ID, + NETDEV_A_NAPI_IRQ, __NETDEV_A_NAPI_MAX, NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index 906b61554698..58e5196da4bd 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -164,6 +164,7 @@ struct ynl_policy_nest netdev_queue_nest = { struct ynl_policy_attr netdev_napi_policy[NETDEV_A_NAPI_MAX + 1] = { [NETDEV_A_NAPI_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, [NETDEV_A_NAPI_ID] = { .name = "id", .type = YNL_PT_U32, }, + [NETDEV_A_NAPI_IRQ] = { .name = "irq", .type = YNL_PT_U32, }, }; struct ynl_policy_nest netdev_napi_nest = { @@ -210,6 +211,11 @@ int netdev_page_pool_info_parse(struct ynl_parse_arg *yarg, return MNL_CB_ERROR; dst->_present.ifindex = 1; dst->ifindex = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_NAPI_IRQ) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.irq = 1; + dst->irq = mnl_attr_get_u32(attr); } } diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index 481c9e45b689..0c3224017c12 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -387,10 +387,12 @@ struct netdev_napi_get_rsp { struct { __u32 id:1; __u32 ifindex:1; + __u32 irq:1; } _present; __u32 id; __u32 ifindex; + __u32 irq; }; void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp); From 26793bfb5d6072326d1465343e7cbf6156abca4f Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:29:07 -0800 Subject: [PATCH 2497/7721] net: Add NAPI IRQ support Add support to associate the interrupt vector number for a NAPI instance. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147334728.5260.13221803396905901904.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_lib.c | 2 ++ include/linux/netdevice.h | 6 ++++++ net/core/dev.c | 1 + net/core/netdev-genl.c | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 83f6977fad22..626577c7d5b2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2978,6 +2978,8 @@ void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked) ice_queue_set_napi(q_vector->vsi->netdev, tx_ring->q_index, NETDEV_QUEUE_TYPE_TX, &q_vector->napi, locked); + /* Also set the interrupt number for the NAPI */ + netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq); } /** diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5ddff11cbe26..5551177e024e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -382,6 +382,7 @@ struct napi_struct { /* control-path-only fields follow */ struct list_head dev_list; struct hlist_node napi_hash_node; + int irq; }; enum { @@ -2665,6 +2666,11 @@ void netif_queue_set_napi(struct net_device *dev, unsigned int queue_index, enum netdev_queue_type type, struct napi_struct *napi); +static inline void netif_napi_set_irq(struct napi_struct *napi, int irq) +{ + napi->irq = irq; +} + /* Default NAPI poll() weight * Device drivers are strongly advised to not use bigger value */ diff --git a/net/core/dev.c b/net/core/dev.c index 13c9d1580e62..1d720fc59161 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6471,6 +6471,7 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, */ if (dev->threaded && napi_kthread_create(napi)) dev->threaded = 0; + netif_napi_set_irq(napi, -1); } EXPORT_SYMBOL(netif_napi_add_weight); diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index d55c92f9f26c..9753c19e36de 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -180,7 +180,11 @@ netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex)) goto nla_put_failure; + if (napi->irq >= 0 && nla_put_u32(rsp, NETDEV_A_NAPI_IRQ, napi->irq)) + goto nla_put_failure; + genlmsg_end(rsp, hdr); + return 0; nla_put_failure: From 8481a249a0eaf0000dbb18f7689ccd50ea9835cd Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:29:13 -0800 Subject: [PATCH 2498/7721] netdev-genl: spec: Add PID in netdev netlink YAML spec Add support in netlink spec(netdev.yaml) for PID of the NAPI thread. Add code generated from the spec. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147335301.5260.11872351477120434501.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/netdev.yaml | 7 +++++++ include/uapi/linux/netdev.h | 1 + tools/include/uapi/linux/netdev.h | 1 + tools/net/ynl/generated/netdev-user.c | 6 ++++++ tools/net/ynl/generated/netdev-user.h | 2 ++ 5 files changed, 17 insertions(+) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index a3a1c6ad521b..f2c76d103bd8 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -230,6 +230,12 @@ attribute-sets: name: irq doc: The associated interrupt vector number for the napi type: u32 + - + name: pid + doc: PID of the napi thread, if NAPI is configured to operate in + threaded mode. If NAPI is not in threaded mode (i.e. uses normal + softirq context), the attribute will be absent. + type: u32 - name: queue attributes: @@ -389,6 +395,7 @@ operations: - id - ifindex - irq + - pid dump: request: attributes: diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 30fea409b71e..424c5e28f495 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -113,6 +113,7 @@ enum { NETDEV_A_NAPI_IFINDEX = 1, NETDEV_A_NAPI_ID, NETDEV_A_NAPI_IRQ, + NETDEV_A_NAPI_PID, __NETDEV_A_NAPI_MAX, NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 30fea409b71e..424c5e28f495 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -113,6 +113,7 @@ enum { NETDEV_A_NAPI_IFINDEX = 1, NETDEV_A_NAPI_ID, NETDEV_A_NAPI_IRQ, + NETDEV_A_NAPI_PID, __NETDEV_A_NAPI_MAX, NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index 58e5196da4bd..ed8bcb855a1d 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -165,6 +165,7 @@ struct ynl_policy_attr netdev_napi_policy[NETDEV_A_NAPI_MAX + 1] = { [NETDEV_A_NAPI_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, [NETDEV_A_NAPI_ID] = { .name = "id", .type = YNL_PT_U32, }, [NETDEV_A_NAPI_IRQ] = { .name = "irq", .type = YNL_PT_U32, }, + [NETDEV_A_NAPI_PID] = { .name = "pid", .type = YNL_PT_U32, }, }; struct ynl_policy_nest netdev_napi_nest = { @@ -216,6 +217,11 @@ int netdev_page_pool_info_parse(struct ynl_parse_arg *yarg, return MNL_CB_ERROR; dst->_present.irq = 1; dst->irq = mnl_attr_get_u32(attr); + } else if (type == NETDEV_A_NAPI_PID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pid = 1; + dst->pid = mnl_attr_get_u32(attr); } } diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index 0c3224017c12..3830cf2ab6b8 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -388,11 +388,13 @@ struct netdev_napi_get_rsp { __u32 id:1; __u32 ifindex:1; __u32 irq:1; + __u32 pid:1; } _present; __u32 id; __u32 ifindex; __u32 irq; + __u32 pid; }; void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp); From db4704f4e4dfce835e934609fca735a648ce26e8 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Fri, 1 Dec 2023 15:29:18 -0800 Subject: [PATCH 2499/7721] netdev-genl: Add PID for the NAPI thread In the threaded NAPI mode, expose the PID of the NAPI thread. Signed-off-by: Amritha Nambiar Reviewed-by: Sridhar Samudrala Link: https://lore.kernel.org/r/170147335818.5260.10253384006102593087.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- net/core/netdev-genl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 9753c19e36de..fd98936da3ae 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -163,6 +163,7 @@ netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, const struct genl_info *info) { void *hdr; + pid_t pid; if (WARN_ON_ONCE(!napi->dev)) return -EINVAL; @@ -183,6 +184,12 @@ netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, if (napi->irq >= 0 && nla_put_u32(rsp, NETDEV_A_NAPI_IRQ, napi->irq)) goto nla_put_failure; + if (napi->thread) { + pid = task_pid_nr(napi->thread); + if (nla_put_u32(rsp, NETDEV_A_NAPI_PID, pid)) + goto nla_put_failure; + } + genlmsg_end(rsp, hdr); return 0; From e3b57ffdb3256e4ff2cf83be0dc076c4b07f92b9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 1 Dec 2023 15:29:23 -0800 Subject: [PATCH 2500/7721] eth: bnxt: link NAPI instances to queues and IRQs Make bnxt compatible with the newly added netlink queue GET APIs. Signed-off-by: Amritha Nambiar Reviewed-by: Michael Chan Link: https://lore.kernel.org/r/170147336340.5260.6773000274196548907.stgit@anambiarhost.jf.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a405c89b00d3..92a54113f872 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4008,6 +4008,9 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr) ring = &rxr->rx_ring_struct; bnxt_init_rxbd_pages(ring, type); + netif_queue_set_napi(bp->dev, ring_nr, NETDEV_QUEUE_TYPE_RX, + &rxr->bnapi->napi); + if (BNXT_RX_PAGE_MODE(bp) && bp->xdp_prog) { bpf_prog_add(bp->xdp_prog, 1); rxr->xdp_prog = bp->xdp_prog; @@ -4084,6 +4087,11 @@ static int bnxt_init_tx_rings(struct bnxt *bp) struct bnxt_ring_struct *ring = &txr->tx_ring_struct; ring->fw_ring_id = INVALID_HW_RING_ID; + + if (i >= bp->tx_nr_rings_xdp) + netif_queue_set_napi(bp->dev, i - bp->tx_nr_rings_xdp, + NETDEV_QUEUE_TYPE_TX, + &txr->bnapi->napi); } return 0; @@ -9930,6 +9938,7 @@ static int bnxt_request_irq(struct bnxt *bp) if (rc) break; + netif_napi_set_irq(&bp->bnapi[i]->napi, irq->vector); irq->requested = 1; if (zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL)) { @@ -9957,6 +9966,11 @@ static void bnxt_del_napi(struct bnxt *bp) if (!bp->bnapi) return; + for (i = 0; i < bp->rx_nr_rings; i++) + netif_queue_set_napi(bp->dev, i, NETDEV_QUEUE_TYPE_RX, NULL); + for (i = 0; i < bp->tx_nr_rings - bp->tx_nr_rings_xdp; i++) + netif_queue_set_napi(bp->dev, i, NETDEV_QUEUE_TYPE_TX, NULL); + for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; From be5fc78a0084472dcc392cbea75f86202467437c Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Fri, 1 Dec 2023 18:50:33 +0530 Subject: [PATCH 2501/7721] net: ethernet: ti: davinci_mdio: Update K3 SoCs list for errata i2329 The errata i2329 affects all the currently available silicon revisions of AM62x, AM64x, AM65x, J7200, J721E and J721S2. So remove the revision string from the SoC list. The silicon revisions affected by the errata i2329 can be found under the MDIO module in the "Advisories by Modules" section of each SoC errata document listed below AM62x: https://www.ti.com/lit/er/sprz487c/sprz487c.pdf AM64X: https://www.ti.com/lit/er/sprz457g/sprz457g.pdf AM65X: https://www.ti.com/lit/er/sprz452i/sprz452i.pdf J7200: https://www.ti.com/lit/er/sprz491d/sprz491d.pdf J721E: https://www.ti.com/lit/er/sprz455d/sprz455d.pdf J721S2: https://www.ti.com/lit/er/sprz530b/sprz530b.pdf Signed-off-by: Ravi Gunasekaran Reviewed-by: Nishanth Menon Link: https://lore.kernel.org/r/20231201132033.29576-1-r-gunasekaran@ti.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ti/davinci_mdio.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 628c87dc1d28..8e07d4a1b6ba 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -511,16 +511,12 @@ static const struct k3_mdio_soc_data am65_mdio_soc_data = { }; static const struct soc_device_attribute k3_mdio_socinfo[] = { - { .family = "AM62X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM64X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM64X", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "AM65X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM65X", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J7200", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "J7200", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J721E", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "J721E", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J721S2", .revision = "SR1.0", .data = &am65_mdio_soc_data}, + { .family = "AM62X", .data = &am65_mdio_soc_data }, + { .family = "AM64X", .data = &am65_mdio_soc_data }, + { .family = "AM65X", .data = &am65_mdio_soc_data }, + { .family = "J7200", .data = &am65_mdio_soc_data }, + { .family = "J721E", .data = &am65_mdio_soc_data }, + { .family = "J721S2", .data = &am65_mdio_soc_data }, { /* sentinel */ }, }; From 58f3240b3b93f880cae759ec2ff6ccfbf11903b7 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Fri, 1 Dec 2023 13:52:50 +0800 Subject: [PATCH 2502/7721] net: stmmac: xgmac: EST interrupts handling Enabled the following EST related interrupts: 1) Constant Gate Control Error (CGCE) 2) Head-of-Line Blocking due to Scheduling (HLBS) 3) Head-of-Line Blocking due to Frame Size (HLBF) 4) Base Time Register error (BTRE) 5) Switch to S/W owned list Complete (SWLC) Also, add EST errors into the ethtool statistic. The commit e49aa315cb01 ("net: stmmac: EST interrupts handling and error reporting") and commit 9f298959191b ("net: stmmac: Add EST errors into ethtool statistic") add EST interrupts handling and error reporting support to DWMAC4 core. This patch enables the same support for XGMAC. Signed-off-by: Rohan G Thomas Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231201055252.1302-2-rohan.g.thomas@intel.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwxgmac2.h | 27 ++++++ .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 90 +++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index a4e8b498dea9..489f66094c49 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -289,6 +289,33 @@ #define XGMAC_PTOV_SHIFT 23 #define XGMAC_SSWL BIT(1) #define XGMAC_EEST BIT(0) +#define XGMAC_MTL_EST_STATUS 0x00001058 +#define XGMAC_BTRL GENMASK(15, 8) +#define XGMAC_BTRL_SHIFT 8 +#define XGMAC_BTRL_MAX GENMASK(15, 8) +#define XGMAC_CGCE BIT(4) +#define XGMAC_HLBS BIT(3) +#define XGMAC_HLBF BIT(2) +#define XGMAC_BTRE BIT(1) +#define XGMAC_SWLC BIT(0) +#define XGMAC_MTL_EST_SCH_ERR 0x00001060 +#define XGMAC_MTL_EST_FRM_SZ_ERR 0x00001064 +#define XGMAC_MTL_EST_FRM_SZ_CAP 0x00001068 +#define XGMAC_SZ_CAP_HBFS_MASK GENMASK(14, 0) +#define XGMAC_SZ_CAP_HBFQ_SHIFT 16 +#define XGMAC_SZ_CAP_HBFQ_MASK(val) \ + ({ \ + typeof(val) _val = (val); \ + (_val > 4 ? GENMASK(18, 16) : \ + _val > 2 ? GENMASK(17, 16) : \ + BIT(16)); \ + }) +#define XGMAC_MTL_EST_INT_EN 0x00001070 +#define XGMAC_IECGCE BIT(4) +#define XGMAC_IEHS BIT(3) +#define XGMAC_IEHF BIT(2) +#define XGMAC_IEBE BIT(1) +#define XGMAC_IECC BIT(0) #define XGMAC_MTL_EST_GCL_CONTROL 0x00001080 #define XGMAC_BTR_LOW 0x0 #define XGMAC_BTR_HIGH 0x1 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 453e88b75be0..c770683300e2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -1481,9 +1481,97 @@ static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, ctrl &= ~XGMAC_EEST; writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL); + + /* Configure EST interrupt */ + if (cfg->enable) + ctrl = XGMAC_IECGCE | XGMAC_IEHS | XGMAC_IEHF | XGMAC_IEBE | + XGMAC_IECC; + else + ctrl = 0; + + writel(ctrl, ioaddr + XGMAC_MTL_EST_INT_EN); return 0; } +static void dwxgmac3_est_irq_status(void __iomem *ioaddr, + struct net_device *dev, + struct stmmac_extra_stats *x, u32 txqcnt) +{ + u32 status, value, feqn, hbfq, hbfs, btrl; + u32 txqcnt_mask = BIT(txqcnt) - 1; + + status = readl(ioaddr + XGMAC_MTL_EST_STATUS); + + value = XGMAC_CGCE | XGMAC_HLBS | XGMAC_HLBF | XGMAC_BTRE | XGMAC_SWLC; + + /* Return if there is no error */ + if (!(status & value)) + return; + + if (status & XGMAC_CGCE) { + /* Clear Interrupt */ + writel(XGMAC_CGCE, ioaddr + XGMAC_MTL_EST_STATUS); + + x->mtl_est_cgce++; + } + + if (status & XGMAC_HLBS) { + value = readl(ioaddr + XGMAC_MTL_EST_SCH_ERR); + value &= txqcnt_mask; + + x->mtl_est_hlbs++; + + /* Clear Interrupt */ + writel(value, ioaddr + XGMAC_MTL_EST_SCH_ERR); + + /* Collecting info to shows all the queues that has HLBS + * issue. The only way to clear this is to clear the + * statistic. + */ + if (net_ratelimit()) + netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value); + } + + if (status & XGMAC_HLBF) { + value = readl(ioaddr + XGMAC_MTL_EST_FRM_SZ_ERR); + feqn = value & txqcnt_mask; + + value = readl(ioaddr + XGMAC_MTL_EST_FRM_SZ_CAP); + hbfq = (value & XGMAC_SZ_CAP_HBFQ_MASK(txqcnt)) >> + XGMAC_SZ_CAP_HBFQ_SHIFT; + hbfs = value & XGMAC_SZ_CAP_HBFS_MASK; + + x->mtl_est_hlbf++; + + /* Clear Interrupt */ + writel(feqn, ioaddr + XGMAC_MTL_EST_FRM_SZ_ERR); + + if (net_ratelimit()) + netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n", + hbfq, hbfs); + } + + if (status & XGMAC_BTRE) { + if ((status & XGMAC_BTRL) == XGMAC_BTRL_MAX) + x->mtl_est_btrlm++; + else + x->mtl_est_btre++; + + btrl = (status & XGMAC_BTRL) >> XGMAC_BTRL_SHIFT; + + if (net_ratelimit()) + netdev_info(dev, "EST: BTR Error Loop Count %u\n", + btrl); + + writel(XGMAC_BTRE, ioaddr + XGMAC_MTL_EST_STATUS); + } + + if (status & XGMAC_SWLC) { + writel(XGMAC_SWLC, ioaddr + XGMAC_MTL_EST_STATUS); + netdev_info(dev, "EST: SWOL has been switched\n"); + } +} + static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable) { @@ -1553,6 +1641,7 @@ const struct stmmac_ops dwxgmac210_ops = { .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, .est_configure = dwxgmac3_est_configure, + .est_irq_status = dwxgmac3_est_irq_status, .fpe_configure = dwxgmac3_fpe_configure, }; @@ -1615,6 +1704,7 @@ const struct stmmac_ops dwxlgmac2_ops = { .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, .est_configure = dwxgmac3_est_configure, + .est_irq_status = dwxgmac3_est_irq_status, .fpe_configure = dwxgmac3_fpe_configure, }; From c3f3b97238f6fd87b9d90b9a995ee5e69f751a74 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Fri, 1 Dec 2023 13:52:51 +0800 Subject: [PATCH 2503/7721] net: stmmac: Refactor EST implementation Refactor EST implementation by moving common code for DWMAC4 and DWXGMAC IPs into a separate EST module. EST implementation for DWMAC4 and DWXGMAC differs only for CSR base address, PTOV field offset width, and PTOV clock multiplier value. Thanks, Serge Semin and Jakub Kicinski for the suggestions on refactoring EST implementation into a separate EST module. Signed-off-by: Rohan G Thomas Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231201055252.1302-3-rohan.g.thomas@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 4 - drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 137 --------------- drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 51 ------ .../net/ethernet/stmicro/stmmac/dwxgmac2.h | 43 ----- .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 143 --------------- drivers/net/ethernet/stmicro/stmmac/hwif.c | 21 +++ drivers/net/ethernet/stmicro/stmmac/hwif.h | 22 ++- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + .../net/ethernet/stmicro/stmmac/stmmac_est.c | 165 ++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_est.h | 64 +++++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- .../net/ethernet/stmicro/stmmac/stmmac_ptp.c | 4 +- .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 4 +- 15 files changed, 272 insertions(+), 392 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_est.c create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_est.h diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 80e598bd4255..26cad4344701 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \ stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \ - stmmac_xdp.o \ + stmmac_xdp.o stmmac_est.o \ $(stmmac-y) stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 6b935922054d..721c1f8e892f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -563,6 +563,7 @@ struct mac_device_info { const struct stmmac_hwtimestamp *ptp; const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; + const struct stmmac_est_ops *est; struct dw_xpcs *xpcs; struct phylink_pcs *lynx_pcs; /* Lynx external PCS */ struct mii_regs mii; /* MII register Addresses */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 5f35faf90963..6b6d0de09619 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -1247,8 +1247,6 @@ const struct stmmac_ops dwmac410_ops = { .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, - .est_configure = dwmac5_est_configure, - .est_irq_status = dwmac5_est_irq_status, .fpe_configure = dwmac5_fpe_configure, .fpe_send_mpacket = dwmac5_fpe_send_mpacket, .fpe_irq_status = dwmac5_fpe_irq_status, @@ -1302,8 +1300,6 @@ const struct stmmac_ops dwmac510_ops = { .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, - .est_configure = dwmac5_est_configure, - .est_irq_status = dwmac5_est_irq_status, .fpe_configure = dwmac5_fpe_configure, .fpe_send_mpacket = dwmac5_fpe_send_mpacket, .fpe_irq_status = dwmac5_fpe_irq_status, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c index e95d35f1e5a0..ea92650f5c97 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c @@ -573,143 +573,6 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, return 0; } -static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl) -{ - u32 ctrl; - - writel(val, ioaddr + MTL_EST_GCL_DATA); - - ctrl = (reg << ADDR_SHIFT); - ctrl |= gcl ? 0 : GCRR; - - writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL); - - ctrl |= SRWO; - writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL); - - return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL, - ctrl, !(ctrl & SRWO), 100, 5000); -} - -int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, - unsigned int ptp_rate) -{ - int i, ret = 0x0; - u32 ctrl; - - ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false); - ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false); - ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false); - ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false); - ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false); - ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false); - if (ret) - return ret; - - for (i = 0; i < cfg->gcl_size; i++) { - ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true); - if (ret) - return ret; - } - - ctrl = readl(ioaddr + MTL_EST_CONTROL); - ctrl &= ~PTOV; - ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT; - if (cfg->enable) - ctrl |= EEST | SSWL; - else - ctrl &= ~EEST; - - writel(ctrl, ioaddr + MTL_EST_CONTROL); - - /* Configure EST interrupt */ - if (cfg->enable) - ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC); - else - ctrl = 0; - - writel(ctrl, ioaddr + MTL_EST_INT_EN); - - return 0; -} - -void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, - struct stmmac_extra_stats *x, u32 txqcnt) -{ - u32 status, value, feqn, hbfq, hbfs, btrl; - u32 txqcnt_mask = (1 << txqcnt) - 1; - - status = readl(ioaddr + MTL_EST_STATUS); - - value = (CGCE | HLBS | HLBF | BTRE | SWLC); - - /* Return if there is no error */ - if (!(status & value)) - return; - - if (status & CGCE) { - /* Clear Interrupt */ - writel(CGCE, ioaddr + MTL_EST_STATUS); - - x->mtl_est_cgce++; - } - - if (status & HLBS) { - value = readl(ioaddr + MTL_EST_SCH_ERR); - value &= txqcnt_mask; - - x->mtl_est_hlbs++; - - /* Clear Interrupt */ - writel(value, ioaddr + MTL_EST_SCH_ERR); - - /* Collecting info to shows all the queues that has HLBS - * issue. The only way to clear this is to clear the - * statistic - */ - if (net_ratelimit()) - netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value); - } - - if (status & HLBF) { - value = readl(ioaddr + MTL_EST_FRM_SZ_ERR); - feqn = value & txqcnt_mask; - - value = readl(ioaddr + MTL_EST_FRM_SZ_CAP); - hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT; - hbfs = value & SZ_CAP_HBFS_MASK; - - x->mtl_est_hlbf++; - - /* Clear Interrupt */ - writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR); - - if (net_ratelimit()) - netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n", - hbfq, hbfs); - } - - if (status & BTRE) { - if ((status & BTRL) == BTRL_MAX) - x->mtl_est_btrlm++; - else - x->mtl_est_btre++; - - btrl = (status & BTRL) >> BTRL_SHIFT; - - if (net_ratelimit()) - netdev_info(dev, "EST: BTR Error Loop Count %u\n", - btrl); - - writel(BTRE, ioaddr + MTL_EST_STATUS); - } - - if (status & SWLC) { - writel(SWLC, ioaddr + MTL_EST_STATUS); - netdev_info(dev, "EST: SWOL has been switched\n"); - } -} - void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable) { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h index 53c138d0ff48..8b0f2c90faef 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h @@ -39,53 +39,6 @@ #define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10)) #define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10)) -#define MTL_EST_CONTROL 0x00000c50 -#define PTOV GENMASK(31, 24) -#define PTOV_SHIFT 24 -#define SSWL BIT(1) -#define EEST BIT(0) - -#define MTL_EST_STATUS 0x00000c58 -#define BTRL GENMASK(11, 8) -#define BTRL_SHIFT 8 -#define BTRL_MAX (0xF << BTRL_SHIFT) -#define SWOL BIT(7) -#define SWOL_SHIFT 7 -#define CGCE BIT(4) -#define HLBS BIT(3) -#define HLBF BIT(2) -#define BTRE BIT(1) -#define SWLC BIT(0) - -#define MTL_EST_SCH_ERR 0x00000c60 -#define MTL_EST_FRM_SZ_ERR 0x00000c64 -#define MTL_EST_FRM_SZ_CAP 0x00000c68 -#define SZ_CAP_HBFS_MASK GENMASK(14, 0) -#define SZ_CAP_HBFQ_SHIFT 16 -#define SZ_CAP_HBFQ_MASK(_val) ({ typeof(_val) (val) = (_val); \ - ((val) > 4 ? GENMASK(18, 16) : \ - (val) > 2 ? GENMASK(17, 16) : \ - BIT(16)); }) - -#define MTL_EST_INT_EN 0x00000c70 -#define IECGCE CGCE -#define IEHS HLBS -#define IEHF HLBF -#define IEBE BTRE -#define IECC SWLC - -#define MTL_EST_GCL_CONTROL 0x00000c80 -#define BTR_LOW 0x0 -#define BTR_HIGH 0x1 -#define CTR_LOW 0x2 -#define CTR_HIGH 0x3 -#define TER 0x4 -#define LLR 0x5 -#define ADDR_SHIFT 8 -#define GCRR BIT(2) -#define SRWO BIT(0) -#define MTL_EST_GCL_DATA 0x00000c84 - #define MTL_RXP_CONTROL_STATUS 0x00000ca0 #define RXPI BIT(31) #define NPE GENMASK(23, 16) @@ -149,10 +102,6 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries, int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, struct stmmac_pps_cfg *cfg, bool enable, u32 sub_second_inc, u32 systime_flags); -int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, - unsigned int ptp_rate); -void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, - struct stmmac_extra_stats *x, u32 txqcnt); void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable); void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 489f66094c49..207ff1799f2c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -284,49 +284,6 @@ #define XGMAC_TC_PRTY_MAP1 0x00001044 #define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8) #define XGMAC_PSTC_SHIFT(x) ((x) * 8) -#define XGMAC_MTL_EST_CONTROL 0x00001050 -#define XGMAC_PTOV GENMASK(31, 23) -#define XGMAC_PTOV_SHIFT 23 -#define XGMAC_SSWL BIT(1) -#define XGMAC_EEST BIT(0) -#define XGMAC_MTL_EST_STATUS 0x00001058 -#define XGMAC_BTRL GENMASK(15, 8) -#define XGMAC_BTRL_SHIFT 8 -#define XGMAC_BTRL_MAX GENMASK(15, 8) -#define XGMAC_CGCE BIT(4) -#define XGMAC_HLBS BIT(3) -#define XGMAC_HLBF BIT(2) -#define XGMAC_BTRE BIT(1) -#define XGMAC_SWLC BIT(0) -#define XGMAC_MTL_EST_SCH_ERR 0x00001060 -#define XGMAC_MTL_EST_FRM_SZ_ERR 0x00001064 -#define XGMAC_MTL_EST_FRM_SZ_CAP 0x00001068 -#define XGMAC_SZ_CAP_HBFS_MASK GENMASK(14, 0) -#define XGMAC_SZ_CAP_HBFQ_SHIFT 16 -#define XGMAC_SZ_CAP_HBFQ_MASK(val) \ - ({ \ - typeof(val) _val = (val); \ - (_val > 4 ? GENMASK(18, 16) : \ - _val > 2 ? GENMASK(17, 16) : \ - BIT(16)); \ - }) -#define XGMAC_MTL_EST_INT_EN 0x00001070 -#define XGMAC_IECGCE BIT(4) -#define XGMAC_IEHS BIT(3) -#define XGMAC_IEHF BIT(2) -#define XGMAC_IEBE BIT(1) -#define XGMAC_IECC BIT(0) -#define XGMAC_MTL_EST_GCL_CONTROL 0x00001080 -#define XGMAC_BTR_LOW 0x0 -#define XGMAC_BTR_HIGH 0x1 -#define XGMAC_CTR_LOW 0x2 -#define XGMAC_CTR_HIGH 0x3 -#define XGMAC_TER 0x4 -#define XGMAC_LLR 0x5 -#define XGMAC_ADDR_SHIFT 8 -#define XGMAC_GCRR BIT(2) -#define XGMAC_SRWO BIT(0) -#define XGMAC_MTL_EST_GCL_DATA 0x00001084 #define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0 #define XGMAC_RXPI BIT(31) #define XGMAC_NPE GENMASK(23, 16) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index c770683300e2..f33f73de5cfe 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -1433,145 +1433,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en, writel(value, ioaddr + XGMAC_RX_CONFIG); } -static int dwxgmac3_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl) -{ - u32 ctrl; - - writel(val, ioaddr + XGMAC_MTL_EST_GCL_DATA); - - ctrl = (reg << XGMAC_ADDR_SHIFT); - ctrl |= gcl ? 0 : XGMAC_GCRR; - - writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL); - - ctrl |= XGMAC_SRWO; - writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL); - - return readl_poll_timeout_atomic(ioaddr + XGMAC_MTL_EST_GCL_CONTROL, - ctrl, !(ctrl & XGMAC_SRWO), 100, 5000); -} - -static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, - unsigned int ptp_rate) -{ - int i, ret = 0x0; - u32 ctrl; - - ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_LOW, cfg->btr[0], false); - ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_HIGH, cfg->btr[1], false); - ret |= dwxgmac3_est_write(ioaddr, XGMAC_TER, cfg->ter, false); - ret |= dwxgmac3_est_write(ioaddr, XGMAC_LLR, cfg->gcl_size, false); - ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_LOW, cfg->ctr[0], false); - ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_HIGH, cfg->ctr[1], false); - if (ret) - return ret; - - for (i = 0; i < cfg->gcl_size; i++) { - ret = dwxgmac3_est_write(ioaddr, i, cfg->gcl[i], true); - if (ret) - return ret; - } - - ctrl = readl(ioaddr + XGMAC_MTL_EST_CONTROL); - ctrl &= ~XGMAC_PTOV; - ctrl |= ((1000000000 / ptp_rate) * 9) << XGMAC_PTOV_SHIFT; - if (cfg->enable) - ctrl |= XGMAC_EEST | XGMAC_SSWL; - else - ctrl &= ~XGMAC_EEST; - - writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL); - - /* Configure EST interrupt */ - if (cfg->enable) - ctrl = XGMAC_IECGCE | XGMAC_IEHS | XGMAC_IEHF | XGMAC_IEBE | - XGMAC_IECC; - else - ctrl = 0; - - writel(ctrl, ioaddr + XGMAC_MTL_EST_INT_EN); - return 0; -} - -static void dwxgmac3_est_irq_status(void __iomem *ioaddr, - struct net_device *dev, - struct stmmac_extra_stats *x, u32 txqcnt) -{ - u32 status, value, feqn, hbfq, hbfs, btrl; - u32 txqcnt_mask = BIT(txqcnt) - 1; - - status = readl(ioaddr + XGMAC_MTL_EST_STATUS); - - value = XGMAC_CGCE | XGMAC_HLBS | XGMAC_HLBF | XGMAC_BTRE | XGMAC_SWLC; - - /* Return if there is no error */ - if (!(status & value)) - return; - - if (status & XGMAC_CGCE) { - /* Clear Interrupt */ - writel(XGMAC_CGCE, ioaddr + XGMAC_MTL_EST_STATUS); - - x->mtl_est_cgce++; - } - - if (status & XGMAC_HLBS) { - value = readl(ioaddr + XGMAC_MTL_EST_SCH_ERR); - value &= txqcnt_mask; - - x->mtl_est_hlbs++; - - /* Clear Interrupt */ - writel(value, ioaddr + XGMAC_MTL_EST_SCH_ERR); - - /* Collecting info to shows all the queues that has HLBS - * issue. The only way to clear this is to clear the - * statistic. - */ - if (net_ratelimit()) - netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value); - } - - if (status & XGMAC_HLBF) { - value = readl(ioaddr + XGMAC_MTL_EST_FRM_SZ_ERR); - feqn = value & txqcnt_mask; - - value = readl(ioaddr + XGMAC_MTL_EST_FRM_SZ_CAP); - hbfq = (value & XGMAC_SZ_CAP_HBFQ_MASK(txqcnt)) >> - XGMAC_SZ_CAP_HBFQ_SHIFT; - hbfs = value & XGMAC_SZ_CAP_HBFS_MASK; - - x->mtl_est_hlbf++; - - /* Clear Interrupt */ - writel(feqn, ioaddr + XGMAC_MTL_EST_FRM_SZ_ERR); - - if (net_ratelimit()) - netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n", - hbfq, hbfs); - } - - if (status & XGMAC_BTRE) { - if ((status & XGMAC_BTRL) == XGMAC_BTRL_MAX) - x->mtl_est_btrlm++; - else - x->mtl_est_btre++; - - btrl = (status & XGMAC_BTRL) >> XGMAC_BTRL_SHIFT; - - if (net_ratelimit()) - netdev_info(dev, "EST: BTR Error Loop Count %u\n", - btrl); - - writel(XGMAC_BTRE, ioaddr + XGMAC_MTL_EST_STATUS); - } - - if (status & XGMAC_SWLC) { - writel(XGMAC_SWLC, ioaddr + XGMAC_MTL_EST_STATUS); - netdev_info(dev, "EST: SWOL has been switched\n"); - } -} - static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable) { @@ -1640,8 +1501,6 @@ const struct stmmac_ops dwxgmac210_ops = { .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, - .est_configure = dwxgmac3_est_configure, - .est_irq_status = dwxgmac3_est_irq_status, .fpe_configure = dwxgmac3_fpe_configure, }; @@ -1703,8 +1562,6 @@ const struct stmmac_ops dwxlgmac2_ops = { .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, - .est_configure = dwxgmac3_est_configure, - .est_irq_status = dwxgmac3_est_irq_status, .fpe_configure = dwxgmac3_fpe_configure, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index b8ba8f2d8041..1bd34b2a47e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -7,6 +7,7 @@ #include "common.h" #include "stmmac.h" #include "stmmac_ptp.h" +#include "stmmac_est.h" static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg) { @@ -114,6 +115,7 @@ static const struct stmmac_hwif_entry { const void *mode; const void *tc; const void *mmc; + const void *est; int (*setup)(struct stmmac_priv *priv); int (*quirks)(struct stmmac_priv *priv); } stmmac_hw[] = { @@ -162,6 +164,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, + .est_off = EST_GMAC4_OFFSET, }, .desc = &dwmac4_desc_ops, .dma = &dwmac4_dma_ops, @@ -170,6 +173,7 @@ static const struct stmmac_hwif_entry { .mode = NULL, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwmac4_setup, .quirks = stmmac_dwmac4_quirks, }, { @@ -180,6 +184,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, + .est_off = EST_GMAC4_OFFSET, }, .desc = &dwmac4_desc_ops, .dma = &dwmac4_dma_ops, @@ -188,6 +193,7 @@ static const struct stmmac_hwif_entry { .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwmac4_setup, .quirks = NULL, }, { @@ -198,6 +204,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, + .est_off = EST_GMAC4_OFFSET, }, .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, @@ -206,6 +213,7 @@ static const struct stmmac_hwif_entry { .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwmac4_setup, .quirks = NULL, }, { @@ -216,6 +224,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, + .est_off = EST_XGMAC_OFFSET, }, .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, @@ -224,6 +233,7 @@ static const struct stmmac_hwif_entry { .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwmac4_setup, .quirks = NULL, }, { @@ -235,6 +245,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_XGMAC_OFFSET, .mmc_off = MMC_XGMAC_OFFSET, + .est_off = EST_XGMAC_OFFSET, }, .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, @@ -243,6 +254,7 @@ static const struct stmmac_hwif_entry { .mode = NULL, .tc = &dwmac510_tc_ops, .mmc = &dwxgmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwxgmac2_setup, .quirks = NULL, }, { @@ -254,6 +266,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_XGMAC_OFFSET, .mmc_off = MMC_XGMAC_OFFSET, + .est_off = EST_XGMAC_OFFSET, }, .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, @@ -262,6 +275,7 @@ static const struct stmmac_hwif_entry { .mode = NULL, .tc = &dwmac510_tc_ops, .mmc = &dwxgmac_mmc_ops, + .est = &dwmac510_est_ops, .setup = dwxlgmac2_setup, .quirks = stmmac_dwxlgmac_quirks, }, @@ -296,6 +310,10 @@ int stmmac_hwif_init(struct stmmac_priv *priv) (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET); priv->mmcaddr = priv->ioaddr + (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET); + if (needs_gmac4) + priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET; + else if (needs_xgmac) + priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET; /* Check for HW specific setup first */ if (priv->plat->setup) { @@ -332,10 +350,13 @@ int stmmac_hwif_init(struct stmmac_priv *priv) mac->mode = mac->mode ? : entry->mode; mac->tc = mac->tc ? : entry->tc; mac->mmc = mac->mmc ? : entry->mmc; + mac->est = mac->est ? : entry->est; priv->hw = mac; priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; + if (entry->est) + priv->estaddr = priv->ioaddr + entry->regs.est_off; /* Entry found */ if (needs_setup) { diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 1d424c9bf037..72412d733856 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -419,10 +419,6 @@ struct stmmac_ops { bool en, bool udp, bool sa, bool inv, u32 match); void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr); - int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg, - unsigned int ptp_rate); - void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev, - struct stmmac_extra_stats *x, u32 txqcnt); void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, bool enable); void (*fpe_send_mpacket)(void __iomem *ioaddr, @@ -528,10 +524,6 @@ struct stmmac_ops { stmmac_do_callback(__priv, mac, config_l4_filter, __args) #define stmmac_set_arp_offload(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, set_arp_offload, __args) -#define stmmac_est_configure(__priv, __args...) \ - stmmac_do_callback(__priv, mac, est_configure, __args) -#define stmmac_est_irq_status(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, est_irq_status, __args) #define stmmac_fpe_configure(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, fpe_configure, __args) #define stmmac_fpe_send_mpacket(__priv, __args...) \ @@ -657,9 +649,22 @@ struct stmmac_mmc_ops { #define stmmac_mmc_read(__priv, __args...) \ stmmac_do_void_callback(__priv, mmc, read, __args) +struct stmmac_est_ops { + int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg, + unsigned int ptp_rate); + void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev, + struct stmmac_extra_stats *x, u32 txqcnt); +}; + +#define stmmac_est_configure(__priv, __args...) \ + stmmac_do_callback(__priv, est, configure, __args) +#define stmmac_est_irq_status(__priv, __args...) \ + stmmac_do_void_callback(__priv, est, irq_status, __args) + struct stmmac_regs_off { u32 ptp_off; u32 mmc_off; + u32 est_off; }; extern const struct stmmac_ops dwmac100_ops; @@ -678,6 +683,7 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops; extern const struct stmmac_desc_ops dwxgmac210_desc_ops; extern const struct stmmac_mmc_ops dwmac_mmc_ops; extern const struct stmmac_mmc_ops dwxgmac_mmc_ops; +extern const struct stmmac_est_ops dwmac510_est_ops; #define GMAC_VERSION 0x00000020 /* GMAC CORE Version */ #define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 686c94c2e8a7..9f89acf31050 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -295,6 +295,7 @@ struct stmmac_priv { void __iomem *mmcaddr; void __iomem *ptpaddr; + void __iomem *estaddr; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; int sfty_ce_irq; int sfty_ue_irq; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c new file mode 100644 index 000000000000..4da6ccc17c20 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023, Intel Corporation + * stmmac EST(802.3 Qbv) handling + */ +#include +#include +#include "stmmac.h" +#include "stmmac_est.h" + +static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl) +{ + u32 ctrl; + + writel(val, est_addr + EST_GCL_DATA); + + ctrl = (reg << EST_ADDR_SHIFT); + ctrl |= gcl ? 0 : EST_GCRR; + writel(ctrl, est_addr + EST_GCL_CONTROL); + + ctrl |= EST_SRWO; + writel(ctrl, est_addr + EST_GCL_CONTROL); + + return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl, + !(ctrl & EST_SRWO), 100, 5000); +} + +static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg, + unsigned int ptp_rate) +{ + void __iomem *est_addr = priv->estaddr; + int i, ret = 0; + u32 ctrl; + + ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false); + ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false); + ret |= est_write(est_addr, EST_TER, cfg->ter, false); + ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false); + ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false); + ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false); + if (ret) + return ret; + + for (i = 0; i < cfg->gcl_size; i++) { + ret = est_write(est_addr, i, cfg->gcl[i], true); + if (ret) + return ret; + } + + ctrl = readl(est_addr + EST_CONTROL); + if (priv->plat->has_xgmac) { + ctrl &= ~EST_XGMAC_PTOV; + ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) << + EST_XGMAC_PTOV_SHIFT; + } else { + ctrl &= ~EST_GMAC5_PTOV; + ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) << + EST_GMAC5_PTOV_SHIFT; + } + if (cfg->enable) + ctrl |= EST_EEST | EST_SSWL; + else + ctrl &= ~EST_EEST; + + writel(ctrl, est_addr + EST_CONTROL); + + /* Configure EST interrupt */ + if (cfg->enable) + ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC; + else + ctrl = 0; + + writel(ctrl, est_addr + EST_INT_EN); + + return 0; +} + +static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, + struct stmmac_extra_stats *x, u32 txqcnt) +{ + u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max; + void __iomem *est_addr = priv->estaddr; + u32 txqcnt_mask = BIT(txqcnt) - 1; + + status = readl(est_addr + EST_STATUS); + + value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC; + + /* Return if there is no error */ + if (!(status & value)) + return; + + if (status & EST_CGCE) { + /* Clear Interrupt */ + writel(EST_CGCE, est_addr + EST_STATUS); + + x->mtl_est_cgce++; + } + + if (status & EST_HLBS) { + value = readl(est_addr + EST_SCH_ERR); + value &= txqcnt_mask; + + x->mtl_est_hlbs++; + + /* Clear Interrupt */ + writel(value, est_addr + EST_SCH_ERR); + + /* Collecting info to shows all the queues that has HLBS + * issue. The only way to clear this is to clear the + * statistic + */ + if (net_ratelimit()) + netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value); + } + + if (status & EST_HLBF) { + value = readl(est_addr + EST_FRM_SZ_ERR); + feqn = value & txqcnt_mask; + + value = readl(est_addr + EST_FRM_SZ_CAP); + hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >> + EST_SZ_CAP_HBFQ_SHIFT; + hbfs = value & EST_SZ_CAP_HBFS_MASK; + + x->mtl_est_hlbf++; + + /* Clear Interrupt */ + writel(feqn, est_addr + EST_FRM_SZ_ERR); + + if (net_ratelimit()) + netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n", + hbfq, hbfs); + } + + if (status & EST_BTRE) { + if (priv->plat->has_xgmac) { + btrl = FIELD_GET(EST_XGMAC_BTRL, status); + btrl_max = FIELD_MAX(EST_XGMAC_BTRL); + } else { + btrl = FIELD_GET(EST_GMAC5_BTRL, status); + btrl_max = FIELD_MAX(EST_GMAC5_BTRL); + } + if (btrl == btrl_max) + x->mtl_est_btrlm++; + else + x->mtl_est_btre++; + + if (net_ratelimit()) + netdev_info(dev, "EST: BTR Error Loop Count %u\n", + btrl); + + writel(EST_BTRE, est_addr + EST_STATUS); + } + + if (status & EST_SWLC) { + writel(EST_SWLC, est_addr + EST_STATUS); + netdev_info(dev, "EST: SWOL has been switched\n"); + } +} + +const struct stmmac_est_ops dwmac510_est_ops = { + .configure = est_configure, + .irq_status = est_irq_status, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h new file mode 100644 index 000000000000..7a858c566e7e --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023, Intel Corporation + * stmmac EST(802.3 Qbv) handling + */ + +#define EST_GMAC4_OFFSET 0x00000c50 +#define EST_XGMAC_OFFSET 0x00001050 + +#define EST_CONTROL 0x00000000 +#define EST_GMAC5_PTOV GENMASK(31, 24) +#define EST_GMAC5_PTOV_SHIFT 24 +#define EST_GMAC5_PTOV_MUL 6 +#define EST_XGMAC_PTOV GENMASK(31, 23) +#define EST_XGMAC_PTOV_SHIFT 23 +#define EST_XGMAC_PTOV_MUL 9 +#define EST_SSWL BIT(1) +#define EST_EEST BIT(0) + +#define EST_STATUS 0x00000008 +#define EST_GMAC5_BTRL GENMASK(11, 8) +#define EST_XGMAC_BTRL GENMASK(15, 8) +#define EST_SWOL BIT(7) +#define EST_SWOL_SHIFT 7 +#define EST_CGCE BIT(4) +#define EST_HLBS BIT(3) +#define EST_HLBF BIT(2) +#define EST_BTRE BIT(1) +#define EST_SWLC BIT(0) + +#define EST_SCH_ERR 0x00000010 + +#define EST_FRM_SZ_ERR 0x00000014 + +#define EST_FRM_SZ_CAP 0x00000018 +#define EST_SZ_CAP_HBFS_MASK GENMASK(14, 0) +#define EST_SZ_CAP_HBFQ_SHIFT 16 +#define EST_SZ_CAP_HBFQ_MASK(val) \ + ({ \ + typeof(val) _val = (val); \ + (_val > 4 ? GENMASK(18, 16) : \ + _val > 2 ? GENMASK(17, 16) : \ + BIT(16)); \ + }) + +#define EST_INT_EN 0x00000020 +#define EST_IECGCE EST_CGCE +#define EST_IEHS EST_HLBS +#define EST_IEHF EST_HLBF +#define EST_IEBE EST_BTRE +#define EST_IECC EST_SWLC + +#define EST_GCL_CONTROL 0x00000030 +#define EST_BTR_LOW 0x0 +#define EST_BTR_HIGH 0x1 +#define EST_CTR_LOW 0x2 +#define EST_CTR_HIGH 0x3 +#define EST_TER 0x4 +#define EST_LLR 0x5 +#define EST_ADDR_SHIFT 8 +#define EST_GCRR BIT(2) +#define EST_SRWO BIT(0) + +#define EST_GCL_DATA 0x00000034 diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c2ac88aaffed..5b7d45f2e2a9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5960,7 +5960,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) pm_wakeup_event(priv->device, 0); if (priv->dma_cap.estsel) - stmmac_est_irq_status(priv, priv->ioaddr, priv->dev, + stmmac_est_irq_status(priv, priv, priv->dev, &priv->xstats, tx_cnt); if (priv->dma_cap.fpesel) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index bffa5c017032..e04830a3a1fb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -72,7 +72,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) est_rst = true; mutex_lock(&priv->plat->est->lock); priv->plat->est->enable = false; - stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); mutex_unlock(&priv->plat->est->lock); } @@ -102,7 +102,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) priv->plat->est->btr[0] = (u32)time.tv_nsec; priv->plat->est->btr[1] = (u32)time.tv_sec; priv->plat->est->enable = true; - ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + ret = stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); mutex_unlock(&priv->plat->est->lock); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index ac41ef4cbd2f..d4ee4684bc70 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -1051,7 +1051,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, */ priv->plat->fpe_cfg->enable = fpe; - ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + ret = stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); mutex_unlock(&priv->plat->est->lock); if (ret) { @@ -1072,7 +1072,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, if (priv->plat->est) { mutex_lock(&priv->plat->est->lock); priv->plat->est->enable = false; - stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); mutex_unlock(&priv->plat->est->lock); } From 9e95505fecb6b5a25b5230eb49c4d5b9e18077d0 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Fri, 1 Dec 2023 13:52:52 +0800 Subject: [PATCH 2504/7721] net: stmmac: Add support for EST cycle-time-extension Add support for cycle-time-extension. TER GCL-register needs to be updated with the cycle-time-extension. Width of TER register is EST time interval width + 7 bits. Signed-off-by: Rohan G Thomas Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231201055252.1302-4-rohan.g.thomas@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index d4ee4684bc70..287767f6d671 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -975,6 +975,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, return -EINVAL; if (!qopt->cycle_time) return -ERANGE; + if (qopt->cycle_time_extension >= BIT(wid + 7)) + return -ERANGE; if (!plat->est) { plat->est = devm_kzalloc(priv->device, sizeof(*plat->est), @@ -1041,6 +1043,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC); priv->plat->est->ctr[1] = (u32)ctr; + priv->plat->est->ter = qopt->cycle_time_extension; + if (fpe && !priv->dma_cap.fpesel) { mutex_unlock(&priv->plat->est->lock); return -EOPNOTSUPP; From b76bbf835d8945080b22b52fc1e6f41cde06865d Mon Sep 17 00:00:00 2001 From: Andrejs Cainikovs Date: Fri, 20 Oct 2023 17:30:22 +0200 Subject: [PATCH 2505/7721] ARM: dts: imx6q-apalis: add can power-up delay on ixora board Newer variants of Ixora boards require a power-up delay when powering up the CAN transceiver of up to 1ms. Cc: stable@vger.kernel.org Signed-off-by: Andrejs Cainikovs Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts index 717decda0ceb..3ac7a4501620 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts @@ -76,6 +76,7 @@ reg_can1_supply: regulator-can1-supply { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enable_can1_power>; regulator-name = "can1_supply"; + startup-delay-us = <1000>; }; reg_can2_supply: regulator-can2-supply { @@ -85,6 +86,7 @@ reg_can2_supply: regulator-can2-supply { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enable_can2_power>; regulator-name = "can2_supply"; + startup-delay-us = <1000>; }; }; From 4777dded21717c31d2d8471bccaf7c0ff58feaa4 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 27 Nov 2023 07:15:43 +0200 Subject: [PATCH 2506/7721] dt-bindings: display: simple: Add boe,bp101wx1-100 panel This panel is found on Motorola mapphone tablets mz615 to mz617. Signed-off-by: Tony Lindgren Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231127051547.15023-1-tony@atomide.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231127051547.15023-1-tony@atomide.com --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 3ec9ee95045f..f00275e50531 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -73,6 +73,8 @@ properties: - auo,t215hvn01 # Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel - avic,tm070ddh03 + # BOE BP101WX1-100 10.1" WXGA (1280x800) LVDS panel + - boe,bp101wx1-100 # BOE EV121WXM-N10-1850 12.1" WXGA (1280x800) TFT LCD panel - boe,ev121wxm-n10-1850 # BOE HV070WSA-100 7.01" WSVGA TFT LCD panel From eeaddab4c14beb02157db5ca8f9e074066759bfd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 27 Nov 2023 07:15:44 +0200 Subject: [PATCH 2507/7721] drm/panel: simple: Add BOE BP101WX1-100 panel This panel is found on Motorola mapphone tablets from mz615 to mz617. Signed-off-by: Tony Lindgren Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231127051547.15023-2-tony@atomide.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231127051547.15023-2-tony@atomide.com --- drivers/gpu/drm/panel/panel-simple.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 9367a4572dcf..876e1b40cfb3 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1324,6 +1324,35 @@ static const struct panel_desc bananapi_s070wv20_ct16 = { }, }; +static const struct drm_display_mode boe_bp101wx1_100_mode = { + .clock = 78945, + .hdisplay = 1280, + .hsync_start = 1280 + 0, + .hsync_end = 1280 + 0 + 2, + .htotal = 1280 + 62 + 0 + 2, + .vdisplay = 800, + .vsync_start = 800 + 8, + .vsync_end = 800 + 8 + 2, + .vtotal = 800 + 6 + 8 + 2, +}; + +static const struct panel_desc boe_bp101wx1_100 = { + .modes = &boe_bp101wx1_100_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 217, + .height = 136, + }, + .delay = { + .enable = 50, + .disable = 50, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing boe_ev121wxm_n10_1850_timing = { .pixelclock = { 69922000, 71000000, 72293000 }, .hactive = { 1280, 1280, 1280 }, @@ -4253,6 +4282,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "bananapi,s070wv20-ct16", .data = &bananapi_s070wv20_ct16, + }, { + .compatible = "boe,bp101wx1-100", + .data = &boe_bp101wx1_100, }, { .compatible = "boe,ev121wxm-n10-1850", .data = &boe_ev121wxm_n10_1850, From 8c2c5d1d33f0725b7995f44f87a81311d13a441d Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:10 -0600 Subject: [PATCH 2508/7721] drm/panel: himax-hx8394: Drop prepare/unprepare tracking Drop the panel specific prepare/unprepare logic. This is now tracked by the DRM stack [1]. [1] commit d2aacaf07395 ("drm/panel: Check for already prepared/enabled in drm_panel") Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231204185719.569021-2-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-2-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-himax-hx8394.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index c73243d85de7..3823ff388b96 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -68,7 +68,6 @@ struct hx8394 { struct gpio_desc *reset_gpio; struct regulator *vcc; struct regulator *iovcc; - bool prepared; const struct hx8394_panel_desc *desc; }; @@ -262,16 +261,11 @@ static int hx8394_unprepare(struct drm_panel *panel) { struct hx8394 *ctx = panel_to_hx8394(panel); - if (!ctx->prepared) - return 0; - gpiod_set_value_cansleep(ctx->reset_gpio, 1); regulator_disable(ctx->iovcc); regulator_disable(ctx->vcc); - ctx->prepared = false; - return 0; } @@ -280,9 +274,6 @@ static int hx8394_prepare(struct drm_panel *panel) struct hx8394 *ctx = panel_to_hx8394(panel); int ret; - if (ctx->prepared) - return 0; - gpiod_set_value_cansleep(ctx->reset_gpio, 1); ret = regulator_enable(ctx->vcc); @@ -301,8 +292,6 @@ static int hx8394_prepare(struct drm_panel *panel) msleep(180); - ctx->prepared = true; - return 0; disable_vcc: From e4f53a4d921eba6187a2599cf184a3beeb604fe2 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:11 -0600 Subject: [PATCH 2509/7721] drm/panel: himax-hx8394: Drop shutdown logic The driver shutdown is duplicate as it calls drm_unprepare and drm_disable which are called anyway when associated drivers are shutdown/removed. Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231204185719.569021-3-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-3-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-himax-hx8394.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index 3823ff388b96..d8e590d5e1da 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -390,27 +390,11 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) return 0; } -static void hx8394_shutdown(struct mipi_dsi_device *dsi) -{ - struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); - - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); -} - static void hx8394_remove(struct mipi_dsi_device *dsi) { struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi); int ret; - hx8394_shutdown(dsi); - ret = mipi_dsi_detach(dsi); if (ret < 0) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); @@ -427,7 +411,6 @@ MODULE_DEVICE_TABLE(of, hx8394_of_match); static struct mipi_dsi_driver hx8394_driver = { .probe = hx8394_probe, .remove = hx8394_remove, - .shutdown = hx8394_shutdown, .driver = { .name = DRV_NAME, .of_match_table = hx8394_of_match, From be478bc7ab08127473ce9ed893378cc2a8762611 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:12 -0600 Subject: [PATCH 2510/7721] dt-bindings: display: Document Himax HX8394 panel rotation Document panel rotation for Himax HX8394 display panel. Signed-off-by: Chris Morgan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204185719.569021-4-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-4-macroalpha82@gmail.com --- .../devicetree/bindings/display/panel/himax,hx8394.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml index ffb35288ffbb..3096debca55c 100644 --- a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml +++ b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml @@ -31,6 +31,8 @@ properties: backlight: true + rotation: true + port: true vcc-supply: From a695a5009c8fd239a98d98209489997ff5397d2b Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:13 -0600 Subject: [PATCH 2511/7721] drm/panel: himax-hx8394: Add Panel Rotation Support Add support for setting the rotation property for the Himax HX8394 panel. Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231204185719.569021-5-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-5-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-himax-hx8394.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index d8e590d5e1da..b68ea09f4725 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -68,6 +68,7 @@ struct hx8394 { struct gpio_desc *reset_gpio; struct regulator *vcc; struct regulator *iovcc; + enum drm_panel_orientation orientation; const struct hx8394_panel_desc *desc; }; @@ -324,12 +325,20 @@ static int hx8394_get_modes(struct drm_panel *panel, return 1; } +static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel) +{ + struct hx8394 *ctx = panel_to_hx8394(panel); + + return ctx->orientation; +} + static const struct drm_panel_funcs hx8394_drm_funcs = { .disable = hx8394_disable, .unprepare = hx8394_unprepare, .prepare = hx8394_prepare, .enable = hx8394_enable, .get_modes = hx8394_get_modes, + .get_orientation = hx8394_get_orientation, }; static int hx8394_probe(struct mipi_dsi_device *dsi) @@ -347,6 +356,12 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n"); + ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); + if (ret < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); + return ret; + } + mipi_dsi_set_drvdata(dsi, ctx); ctx->dev = dev; From 00830a0d8f0d820335e7beb26e251069d90f2574 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:14 -0600 Subject: [PATCH 2512/7721] dt-bindings: display: himax-hx8394: Add Powkiddy X55 panel Add compatible string for the Powkiddy X55 panel. Signed-off-by: Chris Morgan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204185719.569021-6-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-6-macroalpha82@gmail.com --- .../devicetree/bindings/display/panel/himax,hx8394.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml index 3096debca55c..916bb7f94206 100644 --- a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml +++ b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml @@ -23,6 +23,7 @@ properties: items: - enum: - hannstar,hsd060bhw4 + - powkiddy,x55-panel - const: himax,hx8394 reg: true From 38db985966d2f0f89f7e1891253489a16936fc5e Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:15 -0600 Subject: [PATCH 2513/7721] drm/panel: himax-hx8394: Add Support for Powkiddy X55 panel Add support for the Powkiddy X55 panel as used on the Powkiddy X55 handheld gaming console. This panel uses a Himax HX8394 display controller and requires a vendor provided init sequence. The display resolution is 720x1280 and is 67mm by 121mm as measured with calipers. Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231204185719.569021-7-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231204185719.569021-7-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-himax-hx8394.c | 137 +++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index b68ea09f4725..ff0dc08b9829 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -38,6 +38,7 @@ #define HX8394_CMD_SETMIPI 0xba #define HX8394_CMD_SETOTP 0xbb #define HX8394_CMD_SETREGBANK 0xbd +#define HX8394_CMD_UNKNOWN5 0xbf #define HX8394_CMD_UNKNOWN1 0xc0 #define HX8394_CMD_SETDGCLUT 0xc1 #define HX8394_CMD_SETID 0xc3 @@ -52,6 +53,7 @@ #define HX8394_CMD_SETGIP1 0xd5 #define HX8394_CMD_SETGIP2 0xd6 #define HX8394_CMD_SETGPO 0xd6 +#define HX8394_CMD_UNKNOWN4 0xd8 #define HX8394_CMD_SETSCALING 0xdd #define HX8394_CMD_SETIDLE 0xdf #define HX8394_CMD_SETGAMMA 0xe0 @@ -203,6 +205,140 @@ static const struct hx8394_panel_desc hsd060bhw4_desc = { .init_sequence = hsd060bhw4_init_sequence, }; +static int powkiddy_x55_init_sequence(struct hx8394 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* 5.19.8 SETEXTC: Set extension command (B9h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, + 0xff, 0x83, 0x94); + + /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, + 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + + /* 5.19.2 SETPOWER: Set power (B1h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, + 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); + + /* 5.19.3 SETDISP: Set display related register (B2h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); + + /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, + 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, + 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, + 0x86); + + /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, + 0x6e, 0x6e); + + /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, + 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, + 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, + 0x07, 0x0c, 0x40); + + /* 5.19.20 Set GIP Option1 (D5h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, + 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, + 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, + 0x18, 0x18, 0x18, 0x18); + + /* 5.19.21 Set GIP Option2 (D6h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, + 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, + 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, + 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, + 0x18, 0x18, 0x18, 0x18); + + /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, + 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, + 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, + 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, + 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, + 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, + 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, + 0x1f, 0x31); + + /* 5.19.17 SETPANEL (CCh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, + 0x0b); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, + 0x02); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x02); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x00); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x01); + + /* 5.19.2 SETPOWER: Set power (B1h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, + 0x00); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x00); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN5, + 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2, + 0xed); + + return 0; +} + +static const struct drm_display_mode powkiddy_x55_mode = { + .hdisplay = 720, + .hsync_start = 720 + 44, + .hsync_end = 720 + 44 + 20, + .htotal = 720 + 44 + 20 + 20, + .vdisplay = 1280, + .vsync_start = 1280 + 12, + .vsync_end = 1280 + 12 + 10, + .vtotal = 1280 + 12 + 10 + 10, + .clock = 63290, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 67, + .height_mm = 121, +}; + +static const struct hx8394_panel_desc powkiddy_x55_desc = { + .mode = &powkiddy_x55_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = powkiddy_x55_init_sequence, +}; + static int hx8394_enable(struct drm_panel *panel) { struct hx8394 *ctx = panel_to_hx8394(panel); @@ -419,6 +555,7 @@ static void hx8394_remove(struct mipi_dsi_device *dsi) static const struct of_device_id hx8394_of_match[] = { { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, + { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, hx8394_of_match); From edc4802d5a72bae467f7781e184b6687eb833de5 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 4 Dec 2023 16:35:45 +0100 Subject: [PATCH 2514/7721] ARM: dts: rockchip: Add power-controller for RK3128 Add power controller and qos nodes for RK3128 in order to use them as powerdomains. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231204153547.97877-2-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index c0c9f0eaffa3..0676d8b22a1e 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { compatible = "rockchip,rk3128"; @@ -133,6 +134,93 @@ smp-sram@0 { pmu: syscon@100a0000 { compatible = "rockchip,rk3128-pmu", "syscon", "simple-mfd"; reg = <0x100a0000 0x1000>; + + power: power-controller { + compatible = "rockchip,rk3128-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3128_PD_VIO { + reg = ; + clocks = <&cru ACLK_CIF>, + <&cru HCLK_CIF>, + <&cru DCLK_EBC>, + <&cru HCLK_EBC>, + <&cru ACLK_IEP>, + <&cru HCLK_IEP>, + <&cru ACLK_LCDC0>, + <&cru HCLK_LCDC0>, + <&cru PCLK_MIPI>, + <&cru ACLK_RGA>, + <&cru HCLK_RGA>, + <&cru ACLK_VIO0>, + <&cru ACLK_VIO1>, + <&cru HCLK_VIO>, + <&cru HCLK_VIO_H2P>, + <&cru DCLK_VOP>, + <&cru SCLK_VOP>; + pm_qos = <&qos_ebc>, + <&qos_iep>, + <&qos_lcdc>, + <&qos_rga>, + <&qos_vip>; + #power-domain-cells = <0>; + }; + + power-domain@RK3128_PD_VIDEO { + reg = ; + clocks = <&cru ACLK_VDPU>, + <&cru HCLK_VDPU>, + <&cru ACLK_VEPU>, + <&cru HCLK_VEPU>, + <&cru SCLK_HEVC_CORE>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3128_PD_GPU { + reg = ; + clocks = <&cru ACLK_GPU>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + }; + }; + + qos_gpu: qos@1012d000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012d000 0x20>; + }; + + qos_vpu: qos@1012e000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012e000 0x20>; + }; + + qos_rga: qos@1012f000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f000 0x20>; + }; + + qos_ebc: qos@1012f080 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f080 0x20>; + }; + + qos_iep: qos@1012f100 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f100 0x20>; + }; + + qos_lcdc: qos@1012f180 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f180 0x20>; + }; + + qos_vip: qos@1012f200 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f200 0x20>; }; gic: interrupt-controller@10139000 { From 9ca8b8f880f2ebfe87780d553ca73fd2825a8988 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 4 Dec 2023 16:35:46 +0100 Subject: [PATCH 2515/7721] ARM: dts: rockchip: Add GPU node for RK3128 RK3128 SoCs have Mali400 MP2 GPU. Add the respective device tree node and the correspondending opp-table. The frequencies and voltages of the opp-table have been taken from downstream kernel. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231204153547.97877-3-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128.dtsi | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 0676d8b22a1e..414b690f96e4 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -101,6 +101,27 @@ opp-1200000000 { }; }; + gpu_opp_table: opp-table-1 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <975000 975000 1250000>; + }; + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <1050000 1050000 1250000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1150000 1150000 1250000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <1250000 1250000 1250000>; + }; + }; + timer { compatible = "arm,armv7-timer"; interrupts = , @@ -131,6 +152,29 @@ smp-sram@0 { }; }; + gpu: gpu@10090000 { + compatible = "rockchip,rk3128-mali", "arm,mali-400"; + reg = <0x10090000 0x10000>; + interrupts = , + , + , + , + , + ; + interrupt-names = "gp", + "gpmmu", + "pp0", + "ppmmu0", + "pp1", + "ppmmu1"; + clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; + clock-names = "bus", "core"; + operating-points-v2 = <&gpu_opp_table>; + resets = <&cru SRST_GPU>; + power-domains = <&power RK3128_PD_GPU>; + status = "disabled"; + }; + pmu: syscon@100a0000 { compatible = "rockchip,rk3128-pmu", "syscon", "simple-mfd"; reg = <0x100a0000 0x1000>; From d85a7e34565f331579730b67a0977fd3373b8077 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 4 Dec 2023 16:35:47 +0100 Subject: [PATCH 2516/7721] ARM: dts: rockchip: Enable GPU for XPI-3128 Add the supply and enable gpu node for XPI-3128 board. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231204153547.97877-4-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index e979425f11a0..de497f6e9456 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -328,6 +328,11 @@ &gpio3 { "", "", "", ""; }; +&gpu { + mali-supply = <&vdd_log>; + status = "okay"; +}; + &mdio { phy0: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; From 2d93f9dc42623f0812f66f7cdc1d66cc9f263e34 Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:39:57 +1100 Subject: [PATCH 2517/7721] ARM: dts: rockchip: Add alternate UART pins to rv1126 Add uart3m2_xfer and uart4m2_xfer pins for Rockchip RV1126. These are used as serial ports for the indicator and Zigbee radio on the iHost. Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-2-tim@feathertop.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi index bb34b0c9cb4a..4f85b7b3fc4c 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi @@ -263,6 +263,14 @@ uart3m0_xfer: uart3m0-xfer { /* uart3_tx_m0 */ <3 RK_PC6 4 &pcfg_pull_up>; }; + /omit-if-no-ref/ + uart3m2_xfer: uart3m2-xfer { + rockchip,pins = + /* uart3_rx_m2 */ + <3 RK_PA1 4 &pcfg_pull_up>, + /* uart3_tx_m2 */ + <3 RK_PA0 4 &pcfg_pull_up>; + }; }; uart4 { /omit-if-no-ref/ @@ -273,6 +281,14 @@ uart4m0_xfer: uart4m0-xfer { /* uart4_tx_m0 */ <3 RK_PA4 4 &pcfg_pull_up>; }; + /omit-if-no-ref/ + uart4m2_xfer: uart4m2-xfer { + rockchip,pins = + /* uart4_rx_m2 */ + <1 RK_PD4 3 &pcfg_pull_up>, + /* uart4_tx_m2 */ + <1 RK_PD5 3 &pcfg_pull_up>; + }; }; uart5 { /omit-if-no-ref/ From 9f35b08ab08b913abf65cc4ff8d2655ad7912d77 Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:39:58 +1100 Subject: [PATCH 2518/7721] ARM: dts: rockchip: Serial aliases for rv1126 Add serial aliases for uart nodes so that serial devices are created Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-3-tim@feathertop.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rv1126.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rv1126.dtsi b/arch/arm/boot/dts/rockchip/rv1126.dtsi index 9ccd1bad6229..adb11a43c5db 100644 --- a/arch/arm/boot/dts/rockchip/rv1126.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126.dtsi @@ -21,6 +21,12 @@ / { aliases { i2c0 = &i2c0; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; }; cpus { From b1ed25667f5f88531bcb51f3683029693e7a9b8c Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:40:00 +1100 Subject: [PATCH 2519/7721] ARM: dts: rockchip: Add i2c2 node to rv1126 Add i2c2 node and i2c2_xfer pinctrl for Rockchip RV1126 Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-5-tim@feathertop.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi | 10 ++++++++++ arch/arm/boot/dts/rockchip/rv1126.dtsi | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi index 4f85b7b3fc4c..167a48afa3a4 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi @@ -87,6 +87,16 @@ i2c0_xfer: i2c0-xfer { <0 RK_PB5 1 &pcfg_pull_none_drv_level_0_smt>; }; }; + i2c2 { + /omit-if-no-ref/ + i2c2_xfer: i2c2-xfer { + rockchip,pins = + /* i2c2_scl */ + <0 RK_PC2 1 &pcfg_pull_none_drv_level_0_smt>, + /* i2c2_sda */ + <0 RK_PC3 1 &pcfg_pull_none_drv_level_0_smt>; + }; + }; pwm2 { /omit-if-no-ref/ pwm2m0_pins: pwm2m0-pins { diff --git a/arch/arm/boot/dts/rockchip/rv1126.dtsi b/arch/arm/boot/dts/rockchip/rv1126.dtsi index adb11a43c5db..bb603cae13df 100644 --- a/arch/arm/boot/dts/rockchip/rv1126.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126.dtsi @@ -21,6 +21,7 @@ / { aliases { i2c0 = &i2c0; + i2c2 = &i2c2; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -237,6 +238,20 @@ i2c0: i2c@ff3f0000 { status = "disabled"; }; + i2c2: i2c@ff400000 { + compatible = "rockchip,rv1126-i2c", "rockchip,rk3399-i2c"; + reg = <0xff400000 0x1000>; + interrupts = ; + rockchip,grf = <&pmugrf>; + clocks = <&pmucru CLK_I2C2>, <&pmucru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + uart1: serial@ff410000 { compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart"; reg = <0xff410000 0x100>; From 32de939ae49d541a7892f77da8fe78bc6fe73f13 Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:40:01 +1100 Subject: [PATCH 2520/7721] ARM: dts: rockchip: Split up rgmii1 pinctrl on rv1126 Split up the pinctrl definitions for rgmii1 so it can be shared with devices using an RMII PHY. Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-6-tim@feathertop.org Signed-off-by: Heiko Stuebner --- .../dts/rockchip/rv1126-edgeble-neu2-io.dts | 2 +- .../arm/boot/dts/rockchip/rv1126-pinctrl.dtsi | 46 +++++++++++++------ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts index f09be8405964..0c2396b8f8db 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts +++ b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts @@ -61,7 +61,7 @@ &gmac { phy-mode = "rgmii"; phy-supply = <&vcc_3v3>; pinctrl-names = "default"; - pinctrl-0 = <&rgmiim1_pins &clk_out_ethernetm1_pins>; + pinctrl-0 = <&rgmiim1_miim &rgmiim1_bus2 &rgmiim1_bus4 &clk_out_ethernetm1_pins>; tx_delay = <0x2a>; rx_delay = <0x1a>; status = "okay"; diff --git a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi index 167a48afa3a4..06b1d7f2d858 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi @@ -115,36 +115,56 @@ pwm11m0_pins: pwm11m0-pins { }; rgmii { /omit-if-no-ref/ - rgmiim1_pins: rgmiim1-pins { + rgmiim1_miim: rgmiim1-miim { rockchip,pins = /* rgmii_mdc_m1 */ <2 RK_PC2 2 &pcfg_pull_none>, /* rgmii_mdio_m1 */ - <2 RK_PC1 2 &pcfg_pull_none>, - /* rgmii_rxclk_m1 */ - <2 RK_PD3 2 &pcfg_pull_none>, + <2 RK_PC1 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + rgmiim1_rxer: rgmiim1-rxer { + rockchip,pins = + /* rgmii_rxer_m1 */ + <2 RK_PC0 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + rgmiim1_bus2: rgmiim1-bus2 { + rockchip,pins = /* rgmii_rxd0_m1 */ <2 RK_PB5 2 &pcfg_pull_none>, /* rgmii_rxd1_m1 */ <2 RK_PB6 2 &pcfg_pull_none>, - /* rgmii_rxd2_m1 */ - <2 RK_PC7 2 &pcfg_pull_none>, - /* rgmii_rxd3_m1 */ - <2 RK_PD0 2 &pcfg_pull_none>, /* rgmii_rxdv_m1 */ <2 RK_PB4 2 &pcfg_pull_none>, - /* rgmii_txclk_m1 */ - <2 RK_PD2 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd0_m1 */ <2 RK_PC3 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd1_m1 */ <2 RK_PC4 2 &pcfg_pull_none_drv_level_3>, + /* rgmii_txen_m1 */ + <2 RK_PC6 2 &pcfg_pull_none_drv_level_3>; + }; + /omit-if-no-ref/ + rgmiim1_bus4: rgmiim1-bus4 { + rockchip,pins = + /* rgmii_rxclk_m1 */ + <2 RK_PD3 2 &pcfg_pull_none>, + /* rgmii_rxd2_m1 */ + <2 RK_PC7 2 &pcfg_pull_none>, + /* rgmii_rxd3_m1 */ + <2 RK_PD0 2 &pcfg_pull_none>, + /* rgmii_txclk_m1 */ + <2 RK_PD2 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd2_m1 */ <2 RK_PD1 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd3_m1 */ - <2 RK_PA4 2 &pcfg_pull_none_drv_level_3>, - /* rgmii_txen_m1 */ - <2 RK_PC6 2 &pcfg_pull_none_drv_level_3>; + <2 RK_PA4 2 &pcfg_pull_none_drv_level_3>; + }; + /omit-if-no-ref/ + rgmiim1_mclkinout: rgmiim1-mclkinout { + rockchip,pins = + /* rgmii_clk_m1 */ + <2 RK_PB7 2 &pcfg_pull_none>; }; }; sdmmc0 { From 36ad2e479f69d93a27bc0721308e90a4c1101e70 Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:40:02 +1100 Subject: [PATCH 2521/7721] ARM: dts: rockchip: Add rv1109 SoC The Rockchip rv1109 SoC is a dual core version of the rv1126. It is otherwise identical and shares the same device tree config. This patch introduces a dtsi file to drop the additional cpu nodes. Taken from Rockchip BSP kernel. Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-7-tim@feathertop.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rv1109.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 arch/arm/boot/dts/rockchip/rv1109.dtsi diff --git a/arch/arm/boot/dts/rockchip/rv1109.dtsi b/arch/arm/boot/dts/rockchip/rv1109.dtsi new file mode 100644 index 000000000000..9cbaa08ab1b8 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1109.dtsi @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include "rv1126.dtsi" + +/ { + compatible = "rockchip,rv1109"; + + cpus { + /delete-node/ cpu@f02; + /delete-node/ cpu@f03; + }; + + arm-pmu { + interrupts = , + ; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; +}; From 56bde00f7d151d90c66dada007f13f92b95b0d05 Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:40:04 +1100 Subject: [PATCH 2522/7721] dt-bindings: arm: rockchip: Add Sonoff iHost Sonoff iHost is a smart home hub with built in radios for wifi/bt and Zigbee. It is based off the Rockchip RV1126 (or RV1109) SoC. Signed-off-by: Tim Lunn Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231203124004.2676174-9-tim@feathertop.org Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index d3c5b25fc2fd..560177823d4a 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -927,6 +927,13 @@ properties: - const: rockchip,rk3568-bpi-r2pro - const: rockchip,rk3568 + - description: Sonoff iHost Smart Home Hub + items: + - const: itead,sonoff-ihost + - enum: + - rockchip,rv1126 + - rockchip,rv1109 + additionalProperties: true ... From 5d7d06e7c0700388dfd1f59ac9f5d6ac0870bd2e Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:40:03 +1100 Subject: [PATCH 2523/7721] ARM: dts: rockchip: Add Sonoff iHost Smart Home Hub Sonoff iHost is gateway device designed to provide a Smart Home Hub, it is based on Rockchip RV1126. There is also a version with 2GB RAM based off the RV1109 dual core SoC. Features: - Rockchip RV1126 - 4GB DDR4 - 8GB eMMC - microSD slot - RMII Ethernet PHY - 1x USB 2.0 Host - 1x USB 2.0 OTG - Realtek RTL8723DS WiFi/BT - EFR32MG21 Silabs Zigbee radio - Speaker/Microphone This patch adds the initial device tree for this device, it is largely based off the device trees for mainline Edgeble Neu2 and downstream Rockchip rv1126-evb-v13 configs. It has been adapted with relevant peripheral and GPIO pins for the iHost. Signed-off-by: Tim Lunn Link: https://lore.kernel.org/r/20231203124004.2676174-8-tim@feathertop.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/Makefile | 2 + .../boot/dts/rockchip/rv1109-sonoff-ihost.dts | 21 + .../boot/dts/rockchip/rv1126-sonoff-ihost.dts | 29 ++ .../dts/rockchip/rv1126-sonoff-ihost.dtsi | 404 ++++++++++++++++++ 4 files changed, 456 insertions(+) create mode 100644 arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts create mode 100644 arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts create mode 100644 arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi diff --git a/arch/arm/boot/dts/rockchip/Makefile b/arch/arm/boot/dts/rockchip/Makefile index 58868cf0510b..ab4cd9aab722 100644 --- a/arch/arm/boot/dts/rockchip/Makefile +++ b/arch/arm/boot/dts/rockchip/Makefile @@ -2,7 +2,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1108-elgin-r1.dtb \ rv1108-evb.dtb \ + rv1109-sonoff-ihost.dtb \ rv1126-edgeble-neu2-io.dtb \ + rv1126-sonoff-ihost.dtb \ rk3036-evb.dtb \ rk3036-kylin.dtb \ rk3066a-bqcurie2.dtb \ diff --git a/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts b/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts new file mode 100644 index 000000000000..45dced8087a3 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1109.dtsi" +#include "rv1126-sonoff-ihost.dtsi" + +/ { + model = "Sonoff iHost 2G"; + compatible = "itead,sonoff-ihost", "rockchip,rv1109"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts new file mode 100644 index 000000000000..77386a48d81e --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126.dtsi" +#include "rv1126-sonoff-ihost.dtsi" + +/ { + model = "Sonoff iHost 4G"; + compatible = "itead,sonoff-ihost", "rockchip,rv1126"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi new file mode 100644 index 000000000000..32b329e87a0c --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd. + */ + +/ { + aliases { + ethernet0 = &gmac; + mmc0 = &emmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + sdio_pwrseq: pwrseq-sdio { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk809 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_h>; + reset-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_LOW>; + }; +}; + +&emmc { + bus-width = <8>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_bus8 &emmc_cmd &emmc_clk &emmc_rstnout>; + rockchip,default-sample-phase = <90>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vcc_1v8>; + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = ; + #clock-cells = <1>; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + rockchip,system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc_buck5>; + vcc6-supply = <&vcc_buck5>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc3v3_sys>; + vcc9-supply = <&vcc5v0_sys>; + + regulators { + vdd_npu_vepu: DCDC_REG1 { + regulator-name = "vdd_npu_vepu"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc3v3_sys: DCDC_REG4 { + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_buck5: DCDC_REG5 { + regulator-name = "vcc_buck5"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <2200000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2200000>; + }; + }; + + vcc_0v8: LDO_REG1 { + regulator-name = "vcc_0v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_pmu: LDO_REG2 { + regulator-name = "vcc1v8_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd0v8_pmu: LDO_REG3 { + regulator-name = "vcc0v8_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <800000>; + }; + }; + + vcc_1v8: LDO_REG4 { + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_dovdd: LDO_REG5 { + regulator-name = "vcc_dovdd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_dvdd: LDO_REG6 { + regulator-name = "vcc_dvdd"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_avdd: LDO_REG7 { + regulator-name = "vcc_avdd"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG8 { + regulator-name = "vccio_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_sd: LDO_REG9 { + regulator-name = "vcc3v3_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_5v0: SWITCH_REG1 { + regulator-name = "vcc_5v0"; + }; + + vcc_3v3: SWITCH_REG2 { + regulator-name = "vcc_3v3"; + regulator-always-on; + regulator-boot-on; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; + clock-frequency = <400000>; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = ; + clock-output-names = "xin32k"; + }; +}; + +&gmac { + assigned-clocks = <&cru CLK_GMAC_SRC_M1>, <&cru CLK_GMAC_SRC>, + <&cru CLK_GMAC_TX_RX>; + assigned-clock-parents = <&cru CLK_GMAC_RGMII_M1>, <&cru CLK_GMAC_SRC_M1>, + <&cru RMII_MODE_CLK>; + assigned-clock-rates = <0>, <50000000>; + clock_in_out = "output"; + phy-handle = <&phy>; + phy-mode = "rmii"; + phy-supply = <&vcc_3v3>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim1_miim &rgmiim1_rxer &rgmiim1_bus2 &rgmiim1_mclkinout>; + status = "okay"; +}; + +&mdio { + phy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x0>; + pinctrl-names = "default"; + pinctrl-0 = <ð_phy_rst>; + reset-active-low; + reset-assert-us = <50000>; + reset-deassert-us = <10000>; + reset-gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>; + }; +}; + +&pinctrl { + ethernet { + eth_phy_rst: eth-phy-rst { + rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + bt { + bt_enable: bt-enable { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_dev: bt-wake-dev { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_host: bt-wake-host { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wifi { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + pmuio0-supply = <&vcc1v8_pmu>; + pmuio1-supply = <&vcc3v3_sys>; + vccio1-supply = <&vcc_1v8>; + vccio2-supply = <&vccio_sd>; + vccio3-supply = <&vcc_1v8>; + vccio4-supply = <&vcc_dovdd>; + vccio5-supply = <&vcc_1v8>; + vccio6-supply = <&vcc_1v8>; + vccio7-supply = <&vcc_dovdd>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdio { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + max-frequency = <100000000>; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_clk &sdmmc1_cmd &sdmmc1_bus4>; + rockchip,default-sample-phase = <90>; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sys>; + vqmmc-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_bus4 &sdmmc0_det>; + rockchip,default-sample-phase = <90>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr104; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_ctsn &uart0_rtsn>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8723ds-bt"; + device-wake-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; /* BT_WAKE */ + enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; /* BT_RST */ + host-wake-gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>; /* BT_WAKE_HOST */ + max-speed = <2000000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_enable>, <&bt_wake_dev>, <&bt_wake_host>; + }; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3m2_xfer>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4m2_xfer>; + status = "okay"; +}; From 5ca860fb438bafdf8501567b320239ea99910748 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 14:05:05 +0100 Subject: [PATCH 2524/7721] ARM: dts: rockchip: Move gpio aliases to SoC dtsi for RK3128 SoC TRM, SoC datasheet and board schematics always refer to the same gpio numbers - even if not all are used for a specific board. In order to not have to re-define them for every board move the aliases to SoC dtsi for RK3128 like it's being done for most other Rockchip ARM SoCs. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231202130506.66738-3-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128-evb.dts | 4 ---- arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 4 ---- arch/arm/boot/dts/rockchip/rk3128.dtsi | 7 +++++++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/rockchip/rk3128-evb.dts b/arch/arm/boot/dts/rockchip/rk3128-evb.dts index c38f42497cbd..776a483cc26b 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-evb.dts @@ -12,10 +12,6 @@ / { compatible = "rockchip,rk3128-evb", "rockchip,rk3128"; aliases { - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; i2c1 = &i2c1; mmc0 = &emmc; }; diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index de497f6e9456..931c03f1410c 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -12,10 +12,6 @@ / { aliases { ethernet0 = &gmac; - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; mmc0 = &emmc; mmc1 = &sdmmc; serial0 = &uart1; diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 414b690f96e4..8e5a13eb4eff 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -16,6 +16,13 @@ / { #address-cells = <1>; #size-cells = <1>; + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + }; + arm-pmu { compatible = "arm,cortex-a7-pmu"; interrupts = , From 697b39733df961910755f49284f87c0b2a9e5ad3 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 14:05:06 +0100 Subject: [PATCH 2525/7721] ARM: dts: rockchip: Move i2c aliases to SoC dtsi for RK3128 SoC TRM, SoC datasheet and board schematics always refer to the same i2c numbers - even if not all are used for a specific board. In order to not have to re-define them for every board move the aliases to SoC dtsi for RK3128 like it's being done for all other Rockchip ARM SoCs. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231202130506.66738-4-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128-evb.dts | 1 - arch/arm/boot/dts/rockchip/rk3128.dtsi | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/rockchip/rk3128-evb.dts b/arch/arm/boot/dts/rockchip/rk3128-evb.dts index 776a483cc26b..c7ab7fcdb436 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-evb.dts @@ -12,7 +12,6 @@ / { compatible = "rockchip,rk3128-evb", "rockchip,rk3128"; aliases { - i2c1 = &i2c1; mmc0 = &emmc; }; diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 8e5a13eb4eff..35f09e1b6e89 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -21,6 +21,10 @@ aliases { gpio1 = &gpio1; gpio2 = &gpio2; gpio3 = &gpio3; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; }; arm-pmu { From 33898f21283b5ab995e3e65fabae167168288399 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 2 Dec 2023 14:05:07 +0100 Subject: [PATCH 2526/7721] ARM: dts: rockchip: Move uart aliases to SoC dtsi for RK3128 SoC TRM, SoC datasheet and board schematics always refer to the same uart numbers - even if not all are used for a specific board. In order to not have to re-define them for every board move the aliases to SoC dtsi for RK3128 like it's being done for all other Rockchip ARM SoCs. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20231202130506.66738-5-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 3 +-- arch/arm/boot/dts/rockchip/rk3128.dtsi | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index 931c03f1410c..03a97881519a 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -14,7 +14,6 @@ aliases { ethernet0 = &gmac; mmc0 = &emmc; mmc1 = &sdmmc; - serial0 = &uart1; }; memory@60000000 { @@ -23,7 +22,7 @@ memory@60000000 { }; chosen { - stdout-path = "serial0:115200n8"; + stdout-path = &uart1; }; adc-keys { diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 35f09e1b6e89..44700cbbfd20 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -25,6 +25,9 @@ aliases { i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; }; arm-pmu { From 68c193c8d4a403222ce51c8b08bd1715f8b74274 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Thu, 23 Nov 2023 18:08:04 +0100 Subject: [PATCH 2527/7721] drm/panel: ilitek-ili9881c: make use of prepare_prev_first The panel.prepare() call requires an initialized MIPI-DSI host, so set the prepare_prev_first flag to indicate that the host must be initialized first. Signed-off-by: Marco Felsch Signed-off-by: Philipp Zabel Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231123-drm-panel-ili9881c-am8001280g-v1-1-fdf4d624c211@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231123-drm-panel-ili9881c-am8001280g-v1-1-fdf4d624c211@pengutronix.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 7838947a1bf3..0c911ed9141b 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1094,6 +1094,8 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) return ret; } + ctx->panel.prepare_prev_first = true; + ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; From 7ff02f82c3e9ddd5dd81957c8659d350261196ae Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 23 Nov 2023 18:08:05 +0100 Subject: [PATCH 2528/7721] dt-bindings: ili9881c: Add Ampire AM8001280G LCD panel Document the compatible value for Ampire AM8001280G LCD panels. Signed-off-by: Philipp Zabel Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231123-drm-panel-ili9881c-am8001280g-v1-2-fdf4d624c211@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231123-drm-panel-ili9881c-am8001280g-v1-2-fdf4d624c211@pengutronix.de --- .../devicetree/bindings/display/panel/ilitek,ili9881c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index e7ab6224b52e..b1e624be3e33 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -16,6 +16,7 @@ properties: compatible: items: - enum: + - ampire,am8001280g - bananapi,lhr050h41 - feixin,k101-im2byl02 - tdo,tl050hdv35 From 2748848ceaf32671927c3b19672ba3104a1dba7e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 23 Nov 2023 18:08:06 +0100 Subject: [PATCH 2529/7721] drm/panel: ilitek-ili9881c: Add Ampire AM8001280G LCD panel Add support for Ampire AM8001280G LCD panels. Signed-off-by: Philipp Zabel Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231123-drm-panel-ili9881c-am8001280g-v1-3-fdf4d624c211@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231123-drm-panel-ili9881c-am8001280g-v1-3-fdf4d624c211@pengutronix.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 0c911ed9141b..2ffe5f68a890 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -830,6 +830,203 @@ static const struct ili9881c_instr w552946ab_init[] = { ILI9881C_SWITCH_PAGE_INSTR(0), }; +static const struct ili9881c_instr am8001280g_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0xD3), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0A), + ILI9881C_COMMAND_INSTR(0x07, 0x0E), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x01), + ILI9881C_COMMAND_INSTR(0x0a, 0x01), + ILI9881C_COMMAND_INSTR(0x0b, 0x01), + ILI9881C_COMMAND_INSTR(0x0c, 0x01), + ILI9881C_COMMAND_INSTR(0x0d, 0x01), + ILI9881C_COMMAND_INSTR(0x0e, 0x01), + ILI9881C_COMMAND_INSTR(0x0f, 0x01), + ILI9881C_COMMAND_INSTR(0x10, 0x01), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0x40), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x03), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x03), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x00), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x40), + ILI9881C_COMMAND_INSTR(0x3b, 0x40), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + + ILI9881C_COMMAND_INSTR(0x50, 0x01), + ILI9881C_COMMAND_INSTR(0x51, 0x23), + ILI9881C_COMMAND_INSTR(0x52, 0x45), + ILI9881C_COMMAND_INSTR(0x53, 0x67), + ILI9881C_COMMAND_INSTR(0x54, 0x89), + ILI9881C_COMMAND_INSTR(0x55, 0xab), + ILI9881C_COMMAND_INSTR(0x56, 0x01), + ILI9881C_COMMAND_INSTR(0x57, 0x23), + ILI9881C_COMMAND_INSTR(0x58, 0x45), + ILI9881C_COMMAND_INSTR(0x59, 0x67), + ILI9881C_COMMAND_INSTR(0x5a, 0x89), + ILI9881C_COMMAND_INSTR(0x5b, 0xab), + ILI9881C_COMMAND_INSTR(0x5c, 0xcd), + ILI9881C_COMMAND_INSTR(0x5d, 0xef), + + ILI9881C_COMMAND_INSTR(0x5e, 0x11), + ILI9881C_COMMAND_INSTR(0x5f, 0x02), + ILI9881C_COMMAND_INSTR(0x60, 0x00), + ILI9881C_COMMAND_INSTR(0x61, 0x01), + ILI9881C_COMMAND_INSTR(0x62, 0x0D), + ILI9881C_COMMAND_INSTR(0x63, 0x0C), + ILI9881C_COMMAND_INSTR(0x64, 0x0F), + ILI9881C_COMMAND_INSTR(0x65, 0x0E), + ILI9881C_COMMAND_INSTR(0x66, 0x06), + ILI9881C_COMMAND_INSTR(0x67, 0x07), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x02), + ILI9881C_COMMAND_INSTR(0x6a, 0x08), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x02), + ILI9881C_COMMAND_INSTR(0x6d, 0x02), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x02), + ILI9881C_COMMAND_INSTR(0x76, 0x00), + ILI9881C_COMMAND_INSTR(0x77, 0x01), + ILI9881C_COMMAND_INSTR(0x78, 0x0D), + ILI9881C_COMMAND_INSTR(0x79, 0x0C), + ILI9881C_COMMAND_INSTR(0x7a, 0x0F), + ILI9881C_COMMAND_INSTR(0x7b, 0x0E), + ILI9881C_COMMAND_INSTR(0x7c, 0x06), + ILI9881C_COMMAND_INSTR(0x7d, 0x07), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x02), + ILI9881C_COMMAND_INSTR(0x80, 0x08), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x02), + ILI9881C_COMMAND_INSTR(0x83, 0x02), + ILI9881C_COMMAND_INSTR(0x84, 0x02), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6e, 0x30), + ILI9881C_COMMAND_INSTR(0x6f, 0x33), + ILI9881C_COMMAND_INSTR(0x8d, 0x15), + ILI9881C_COMMAND_INSTR(0x3a, 0xa4), + ILI9881C_COMMAND_INSTR(0x87, 0xba), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xb2, 0xd1), + + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), + ILI9881C_COMMAND_INSTR(0x31, 0x0B), + ILI9881C_COMMAND_INSTR(0x50, 0xa5), + ILI9881C_COMMAND_INSTR(0x51, 0xa0), + ILI9881C_COMMAND_INSTR(0x53, 0x70), + ILI9881C_COMMAND_INSTR(0x55, 0x7A), + ILI9881C_COMMAND_INSTR(0x60, 0x14), + + ILI9881C_COMMAND_INSTR(0xA0, 0x00), + ILI9881C_COMMAND_INSTR(0xA1, 0x53), + ILI9881C_COMMAND_INSTR(0xA2, 0x50), + ILI9881C_COMMAND_INSTR(0xA3, 0x20), + ILI9881C_COMMAND_INSTR(0xA4, 0x27), + ILI9881C_COMMAND_INSTR(0xA5, 0x33), + ILI9881C_COMMAND_INSTR(0xA6, 0x25), + ILI9881C_COMMAND_INSTR(0xA7, 0x25), + ILI9881C_COMMAND_INSTR(0xA8, 0xD4), + ILI9881C_COMMAND_INSTR(0xA9, 0x1A), + ILI9881C_COMMAND_INSTR(0xAA, 0x2B), + ILI9881C_COMMAND_INSTR(0xAB, 0xB5), + ILI9881C_COMMAND_INSTR(0xAC, 0x19), + ILI9881C_COMMAND_INSTR(0xAD, 0x18), + ILI9881C_COMMAND_INSTR(0xAE, 0x53), + ILI9881C_COMMAND_INSTR(0xAF, 0x1A), + ILI9881C_COMMAND_INSTR(0xB0, 0x25), + ILI9881C_COMMAND_INSTR(0xB1, 0x62), + ILI9881C_COMMAND_INSTR(0xB2, 0x6A), + ILI9881C_COMMAND_INSTR(0xB3, 0x31), + + ILI9881C_COMMAND_INSTR(0xC0, 0x00), + ILI9881C_COMMAND_INSTR(0xC1, 0x53), + ILI9881C_COMMAND_INSTR(0xC2, 0x50), + ILI9881C_COMMAND_INSTR(0xC3, 0x20), + ILI9881C_COMMAND_INSTR(0xC4, 0x27), + ILI9881C_COMMAND_INSTR(0xC5, 0x33), + ILI9881C_COMMAND_INSTR(0xC6, 0x25), + ILI9881C_COMMAND_INSTR(0xC7, 0x25), + ILI9881C_COMMAND_INSTR(0xC8, 0xD4), + ILI9881C_COMMAND_INSTR(0xC9, 0x1A), + ILI9881C_COMMAND_INSTR(0xCA, 0x2B), + ILI9881C_COMMAND_INSTR(0xCB, 0xB5), + ILI9881C_COMMAND_INSTR(0xCC, 0x19), + ILI9881C_COMMAND_INSTR(0xCD, 0x18), + ILI9881C_COMMAND_INSTR(0xCE, 0x53), + ILI9881C_COMMAND_INSTR(0xCF, 0x1A), + ILI9881C_COMMAND_INSTR(0xD0, 0x25), + ILI9881C_COMMAND_INSTR(0xD1, 0x62), + ILI9881C_COMMAND_INSTR(0xD2, 0x6A), + ILI9881C_COMMAND_INSTR(0xD3, 0x31), + ILI9881C_SWITCH_PAGE_INSTR(0), + ILI9881C_COMMAND_INSTR(MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c), + ILI9881C_COMMAND_INSTR(MIPI_DCS_WRITE_POWER_SAVE, 0x00), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -1014,6 +1211,23 @@ static const struct drm_display_mode w552946aba_default_mode = { .height_mm = 121, }; +static const struct drm_display_mode am8001280g_default_mode = { + .clock = 67911, + + .hdisplay = 800, + .hsync_start = 800 + 20, + .hsync_end = 800 + 20 + 32, + .htotal = 800 + 20 + 32 + 20, + + .vdisplay = 1280, + .vsync_start = 1280 + 6, + .vsync_end = 1280 + 6 + 8, + .vtotal = 1280 + 6 + 8 + 4, + + .width_mm = 94, + .height_mm = 151, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -1147,11 +1361,20 @@ static const struct ili9881c_desc w552946aba_desc = { MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; +static const struct ili9881c_desc am8001280g_desc = { + .init = am8001280g_init, + .init_length = ARRAY_SIZE(am8001280g_init), + .mode = &am8001280g_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, +}; + static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, + { .compatible = "ampire,am8001280g", .data = &am8001280g_desc }, { } }; MODULE_DEVICE_TABLE(of, ili9881c_of_match); From 2a5244a04e751c8617d5e7707550d97a83b1102d Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 23 Nov 2023 11:24:03 +0100 Subject: [PATCH 2530/7721] dt-bindings: display: simple: add Evervision VGG644804 panel Add Evervision VGG644804 5.7" 640x480 LVDS panel compatible string. Signed-off-by: Michael Walle Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231123102404.2022201-1-mwalle@kernel.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231123102404.2022201-1-mwalle@kernel.org --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index f00275e50531..2021aa82871a 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -146,6 +146,8 @@ properties: - edt,etmv570g2dhu # E Ink VB3300-KCA - eink,vb3300-kca + # Evervision Electronics Co. Ltd. VGG644804 5.7" VGA TFT LCD Panel + - evervision,vgg644804 # Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel - evervision,vgg804821 # Foxlink Group 5" WVGA TFT LCD panel From 1319f2178bdf1898a76ea8c4f00d57b240bbc5fd Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 23 Nov 2023 11:24:04 +0100 Subject: [PATCH 2531/7721] drm/panel-simple: add Evervision VGG644804 panel entry Timings taken from the datasheet, although sometimes there are just typical values and it's not clear if they are no min and max values or if you must use the typical value exactly. To make things worse, there is no back porch but only a combined sync and back porch length. Unfortunately, there is not public datasheet. Therefore, here are the relevant timings: | min | typ | max | -----------------+-----+--------+-----+ CLK frequency | - | 25.175 | - | HS period | - | 800 | - | HS pulse width | 5 | 30 | - | HS-DEN time | 112 | 144 | 175 | DEN pulse width | - | 640 | - | VS pulse width | 1 | 3 | 5 | VS-DEN time | - | 35 | - | VS period | - | 525 | - | Signed-off-by: Michael Walle Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231123102404.2022201-2-mwalle@kernel.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231123102404.2022201-2-mwalle@kernel.org --- drivers/gpu/drm/panel/panel-simple.c | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 876e1b40cfb3..8017ad33cf18 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2002,6 +2002,33 @@ static const struct panel_desc eink_vb3300_kca = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct display_timing evervision_vgg644804_timing = { + .pixelclock = { 25175000, 25175000, 25175000 }, + .hactive = { 640, 640, 640 }, + .hfront_porch = { 16, 16, 16 }, + .hback_porch = { 82, 114, 170 }, + .hsync_len = { 5, 30, 30 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 10, 10, 10 }, + .vback_porch = { 30, 32, 34 }, + .vsync_len = { 1, 3, 5 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, +}; + +static const struct panel_desc evervision_vgg644804 = { + .timings = &evervision_vgg644804_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 115, + .height = 86, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, +}; + static const struct display_timing evervision_vgg804821_timing = { .pixelclock = { 27600000, 33300000, 50000000 }, .hactive = { 800, 800, 800 }, @@ -4366,6 +4393,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "eink,vb3300-kca", .data = &eink_vb3300_kca, + }, { + .compatible = "evervision,vgg644804", + .data = &evervision_vgg644804, }, { .compatible = "evervision,vgg804821", .data = &evervision_vgg804821, From 685da6972647b486980c0cc8fd6bb5d3863fd6b7 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:17 -0600 Subject: [PATCH 2532/7721] clk: rockchip: rk3568: Add PLL rate for 126.4MHz Add support for a PLL rate of 126.4MHz so that the Powkiddy X55 panel can run at a requested 60hz. I have confirmed this rate fits with all the constraints listed in the TRM for the VPLL (as an integer PLL) in Part 1 "Chapter 2 Clock & Reset Unit (CRU)." Signed-off-by: Chris Morgan Link: https://lore.kernel.org/r/20231204185719.569021-9-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 43185668daf6..497a7e51ffda 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -77,6 +77,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { RK3036_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0), RK3036_PLL_RATE(148500000, 1, 99, 4, 4, 1, 0), RK3036_PLL_RATE(135000000, 2, 45, 4, 1, 1, 0), + RK3036_PLL_RATE(126400000, 1, 79, 5, 3, 1, 0), RK3036_PLL_RATE(119000000, 3, 119, 4, 2, 1, 0), RK3036_PLL_RATE(115200000, 1, 24, 5, 1, 1, 0), RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0), From 721bf080f249ab2adcc4337abe164230bfb8594f Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Mon, 4 Dec 2023 12:57:16 -0600 Subject: [PATCH 2533/7721] clk: rockchip: rk3568: Mark pclk_usb as critical In the reference manual under "2.8.6 NIU Clock gating reliance" it is stated that pclk_usb_niu has a dependency on hclk_usb_niu. While the manual does not state that this is a bi-directional relationship it was noted that the sdmmc2 failed to operate for me in mmc mode if the pclk_usb was not marked as critical. The parent clock of the hclk_sdmmc2 is hclk_usb. Signed-off-by: Chris Morgan Link: https://lore.kernel.org/r/20231204185719.569021-8-macroalpha82@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 497a7e51ffda..feb9ae484387 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -1594,6 +1594,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = { "hclk_php", "pclk_php", "hclk_usb", + "pclk_usb", "hclk_vo", }; From e8a4195d843fe81a86a97db9ce830c78bfd3f19b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:41 +0800 Subject: [PATCH 2534/7721] docs: bridge: update doc format to rst The current bridge kernel doc is too old. It only pointed to the linuxfoundation wiki page which lacks of the new features. Here let's start the new bridge document and put all the bridge info so new developers and users could catch up the last bridge status soon. In this patch, Convert the doc to rst format. Add bridge brief introduction, FAQ and contact info. Reviewed-by: Florian Fainelli Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 47 +++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index c859f3c1636e..6ad8b42b2c50 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -4,18 +4,45 @@ Ethernet Bridging ================= -In order to use the Ethernet bridging functionality, you'll need the -userspace tools. +Introduction +============ -Documentation for Linux bridging is on: - https://wiki.linuxfoundation.org/networking/bridge +The IEEE 802.1Q-2022 (Bridges and Bridged Networks) standard defines the +operation of bridges in computer networks. A bridge, in the context of this +standard, is a device that connects two or more network segments and operates +at the data link layer (Layer 2) of the OSI (Open Systems Interconnection) +model. The purpose of a bridge is to filter and forward frames between +different segments based on the destination MAC (Media Access Control) address. -The bridge-utilities are maintained at: - git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git +FAQ +=== -Additionally, the iproute2 utilities can be used to configure -bridge devices. +What does a bridge do? +---------------------- -If you still have questions, don't hesitate to post to the mailing list -(more info https://lists.linux-foundation.org/mailman/listinfo/bridge). +A bridge transparently forwards traffic between multiple network interfaces. +In plain English this means that a bridge connects two or more physical +Ethernet networks, to form one larger (logical) Ethernet network. +Is it L3 protocol independent? +------------------------------ + +Yes. The bridge sees all frames, but it *uses* only L2 headers/information. +As such, the bridging functionality is protocol independent, and there should +be no trouble forwarding IPX, NetBEUI, IP, IPv6, etc. + +Contact Info +============ + +The code is currently maintained by Roopa Prabhu and +Nikolay Aleksandrov . Bridge bugs and enhancements +are discussed on the linux-netdev mailing list netdev@vger.kernel.org and +bridge@lists.linux-foundation.org. + +The list is open to anyone interested: http://vger.kernel.org/vger-lists.html#netdev + +External Links +============== + +The old Documentation for Linux bridging is on: +https://wiki.linuxfoundation.org/networking/bridge From 8ebe06611666a399162de31cdd6f2f48ffa87748 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:42 +0800 Subject: [PATCH 2535/7721] net: bridge: add document for IFLA_BR enum Add document for IFLA_BR enum so we can use it in Documentation/networking/bridge.rst. Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: Paolo Abeni --- include/uapi/linux/if_link.h | 280 +++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 8181ef23a7a2..a5f873c85a72 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -461,6 +461,286 @@ enum in6_addr_gen_mode { /* Bridge section */ +/** + * DOC: Bridge enum definition + * + * Please *note* that the timer values in the following section are expected + * in clock_t format, which is seconds multiplied by USER_HZ (generally + * defined as 100). + * + * @IFLA_BR_FORWARD_DELAY + * The bridge forwarding delay is the time spent in LISTENING state + * (before moving to LEARNING) and in LEARNING state (before moving + * to FORWARDING). Only relevant if STP is enabled. + * + * The valid values are between (2 * USER_HZ) and (30 * USER_HZ). + * The default value is (15 * USER_HZ). + * + * @IFLA_BR_HELLO_TIME + * The time between hello packets sent by the bridge, when it is a root + * bridge or a designated bridge. Only relevant if STP is enabled. + * + * The valid values are between (1 * USER_HZ) and (10 * USER_HZ). + * The default value is (2 * USER_HZ). + * + * @IFLA_BR_MAX_AGE + * The hello packet timeout is the time until another bridge in the + * spanning tree is assumed to be dead, after reception of its last hello + * message. Only relevant if STP is enabled. + * + * The valid values are between (6 * USER_HZ) and (40 * USER_HZ). + * The default value is (20 * USER_HZ). + * + * @IFLA_BR_AGEING_TIME + * Configure the bridge's FDB entries aging time. It is the time a MAC + * address will be kept in the FDB after a packet has been received from + * that address. After this time has passed, entries are cleaned up. + * Allow values outside the 802.1 standard specification for special cases: + * + * * 0 - entry never ages (all permanent) + * * 1 - entry disappears (no persistence) + * + * The default value is (300 * USER_HZ). + * + * @IFLA_BR_STP_STATE + * Turn spanning tree protocol on (*IFLA_BR_STP_STATE* > 0) or off + * (*IFLA_BR_STP_STATE* == 0) for this bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_PRIORITY + * Set this bridge's spanning tree priority, used during STP root bridge + * election. + * + * The valid values are between 0 and 65535. + * + * @IFLA_BR_VLAN_FILTERING + * Turn VLAN filtering on (*IFLA_BR_VLAN_FILTERING* > 0) or off + * (*IFLA_BR_VLAN_FILTERING* == 0). When disabled, the bridge will not + * consider the VLAN tag when handling packets. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_VLAN_PROTOCOL + * Set the protocol used for VLAN filtering. + * + * The valid values are 0x8100(802.1Q) or 0x88A8(802.1AD). The default value + * is 0x8100(802.1Q). + * + * @IFLA_BR_GROUP_FWD_MASK + * The group forwarding mask. This is the bitmask that is applied to + * decide whether to forward incoming frames destined to link-local + * addresses (of the form 01:80:C2:00:00:0X). + * + * The default value is 0, which means the bridge does not forward any + * link-local frames coming on this port. + * + * @IFLA_BR_ROOT_ID + * The bridge root id, read only. + * + * @IFLA_BR_BRIDGE_ID + * The bridge id, read only. + * + * @IFLA_BR_ROOT_PORT + * The bridge root port, read only. + * + * @IFLA_BR_ROOT_PATH_COST + * The bridge root path cost, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE + * The bridge topology change, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE_DETECTED + * The bridge topology change detected, read only. + * + * @IFLA_BR_HELLO_TIMER + * The bridge hello timer, read only. + * + * @IFLA_BR_TCN_TIMER + * The bridge tcn timer, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE_TIMER + * The bridge topology change timer, read only. + * + * @IFLA_BR_GC_TIMER + * The bridge gc timer, read only. + * + * @IFLA_BR_GROUP_ADDR + * Set the MAC address of the multicast group this bridge uses for STP. + * The address must be a link-local address in standard Ethernet MAC address + * format. It is an address of the form 01:80:C2:00:00:0X, with X in [0, 4..f]. + * + * The default value is 0. + * + * @IFLA_BR_FDB_FLUSH + * Flush bridge's fdb dynamic entries. + * + * @IFLA_BR_MCAST_ROUTER + * Set bridge's multicast router if IGMP snooping is enabled. + * The valid values are: + * + * * 0 - disabled. + * * 1 - automatic (queried). + * * 2 - permanently enabled. + * + * The default value is 1. + * + * @IFLA_BR_MCAST_SNOOPING + * Turn multicast snooping on (*IFLA_BR_MCAST_SNOOPING* > 0) or off + * (*IFLA_BR_MCAST_SNOOPING* == 0). + * + * The default value is 1. + * + * @IFLA_BR_MCAST_QUERY_USE_IFADDR + * If enabled use the bridge's own IP address as source address for IGMP + * queries (*IFLA_BR_MCAST_QUERY_USE_IFADDR* > 0) or the default of 0.0.0.0 + * (*IFLA_BR_MCAST_QUERY_USE_IFADDR* == 0). + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_QUERIER + * Enable (*IFLA_BR_MULTICAST_QUERIER* > 0) or disable + * (*IFLA_BR_MULTICAST_QUERIER* == 0) IGMP querier, ie sending of multicast + * queries by the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_HASH_ELASTICITY + * Set multicast database hash elasticity, It is the maximum chain length in + * the multicast hash table. This attribute is *deprecated* and the value + * is always 16. + * + * @IFLA_BR_MCAST_HASH_MAX + * Set maximum size of the multicast hash table + * + * The default value is 4096, the value must be a power of 2. + * + * @IFLA_BR_MCAST_LAST_MEMBER_CNT + * The Last Member Query Count is the number of Group-Specific Queries + * sent before the router assumes there are no local members. The Last + * Member Query Count is also the number of Group-and-Source-Specific + * Queries sent before the router assumes there are no listeners for a + * particular source. + * + * The default value is 2. + * + * @IFLA_BR_MCAST_STARTUP_QUERY_CNT + * The Startup Query Count is the number of Queries sent out on startup, + * separated by the Startup Query Interval. + * + * The default value is 2. + * + * @IFLA_BR_MCAST_LAST_MEMBER_INTVL + * The Last Member Query Interval is the Max Response Time inserted into + * Group-Specific Queries sent in response to Leave Group messages, and + * is also the amount of time between Group-Specific Query messages. + * + * The default value is (1 * USER_HZ). + * + * @IFLA_BR_MCAST_MEMBERSHIP_INTVL + * The interval after which the bridge will leave a group, if no membership + * reports for this group are received. + * + * The default value is (260 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERIER_INTVL + * The interval between queries sent by other routers. if no queries are + * seen after this delay has passed, the bridge will start to send its own + * queries (as if *IFLA_BR_MCAST_QUERIER_INTVL* was enabled). + * + * The default value is (255 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERY_INTVL + * The Query Interval is the interval between General Queries sent by + * the Querier. + * + * The default value is (125 * USER_HZ). The minimum value is (1 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERY_RESPONSE_INTVL + * The Max Response Time used to calculate the Max Resp Code inserted + * into the periodic General Queries. + * + * The default value is (10 * USER_HZ). + * + * @IFLA_BR_MCAST_STARTUP_QUERY_INTVL + * The interval between queries in the startup phase. + * + * The default value is (125 * USER_HZ) / 4. The minimum value is (1 * USER_HZ). + * + * @IFLA_BR_NF_CALL_IPTABLES + * Enable (*NF_CALL_IPTABLES* > 0) or disable (*NF_CALL_IPTABLES* == 0) + * iptables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_NF_CALL_IP6TABLES + * Enable (*NF_CALL_IP6TABLES* > 0) or disable (*NF_CALL_IP6TABLES* == 0) + * ip6tables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_NF_CALL_ARPTABLES + * Enable (*NF_CALL_ARPTABLES* > 0) or disable (*NF_CALL_ARPTABLES* == 0) + * arptables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_VLAN_DEFAULT_PVID + * VLAN ID applied to untagged and priority-tagged incoming packets. + * + * The default value is 1. Setting to the special value 0 makes all ports of + * this bridge not have a PVID by default, which means that they will + * not accept VLAN-untagged traffic. + * + * @IFLA_BR_PAD + * Bridge attribute padding type for netlink message. + * + * @IFLA_BR_VLAN_STATS_ENABLED + * Enable (*IFLA_BR_VLAN_STATS_ENABLED* == 1) or disable + * (*IFLA_BR_VLAN_STATS_ENABLED* == 0) per-VLAN stats accounting. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_STATS_ENABLED + * Enable (*IFLA_BR_MCAST_STATS_ENABLED* > 0) or disable + * (*IFLA_BR_MCAST_STATS_ENABLED* == 0) multicast (IGMP/MLD) stats + * accounting. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_IGMP_VERSION + * Set the IGMP version. + * + * The valid values are 2 and 3. The default value is 2. + * + * @IFLA_BR_MCAST_MLD_VERSION + * Set the MLD version. + * + * The valid values are 1 and 2. The default value is 1. + * + * @IFLA_BR_VLAN_STATS_PER_PORT + * Enable (*IFLA_BR_VLAN_STATS_PER_PORT* == 1) or disable + * (*IFLA_BR_VLAN_STATS_PER_PORT* == 0) per-VLAN per-port stats accounting. + * Can be changed only when there are no port VLANs configured. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MULTI_BOOLOPT + * The multi_boolopt is used to control new boolean options to avoid adding + * new netlink attributes. You can look at ``enum br_boolopt_id`` for those + * options. + * + * @IFLA_BR_MCAST_QUERIER_STATE + * Bridge mcast querier states, read only. + * + * @IFLA_BR_FDB_N_LEARNED + * The number of dynamically learned FDB entries for the current bridge, + * read only. + * + * @IFLA_BR_FDB_MAX_LEARNED + * Set the number of max dynamically learned FDB entries for the current + * bridge. + */ enum { IFLA_BR_UNSPEC, IFLA_BR_FORWARD_DELAY, From 8c4bafdb01cc7809903aced4981f563e3708ea37 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:43 +0800 Subject: [PATCH 2536/7721] net: bridge: add document for IFLA_BRPORT enum Add document for IFLA_BRPORT enum so we can use it in Documentation/networking/bridge.rst. Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: Paolo Abeni --- include/uapi/linux/if_link.h | 241 +++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index a5f873c85a72..ab9bcff96e4d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -802,11 +802,252 @@ struct ifla_bridge_id { __u8 addr[6]; /* ETH_ALEN */ }; +/** + * DOC: Bridge mode enum definition + * + * @BRIDGE_MODE_HAIRPIN + * Controls whether traffic may be sent back out of the port on which it + * was received. This option is also called reflective relay mode, and is + * used to support basic VEPA (Virtual Ethernet Port Aggregator) + * capabilities. By default, this flag is turned off and the bridge will + * not forward traffic back out of the receiving port. + */ enum { BRIDGE_MODE_UNSPEC, BRIDGE_MODE_HAIRPIN, }; +/** + * DOC: Bridge port enum definition + * + * @IFLA_BRPORT_STATE + * The operation state of the port. Here are the valid values. + * + * * 0 - port is in STP *DISABLED* state. Make this port completely + * inactive for STP. This is also called BPDU filter and could be used + * to disable STP on an untrusted port, like a leaf virtual device. + * The traffic forwarding is also stopped on this port. + * * 1 - port is in STP *LISTENING* state. Only valid if STP is enabled + * on the bridge. In this state the port listens for STP BPDUs and + * drops all other traffic frames. + * * 2 - port is in STP *LEARNING* state. Only valid if STP is enabled on + * the bridge. In this state the port will accept traffic only for the + * purpose of updating MAC address tables. + * * 3 - port is in STP *FORWARDING* state. Port is fully active. + * * 4 - port is in STP *BLOCKING* state. Only valid if STP is enabled on + * the bridge. This state is used during the STP election process. + * In this state, port will only process STP BPDUs. + * + * @IFLA_BRPORT_PRIORITY + * The STP port priority. The valid values are between 0 and 255. + * + * @IFLA_BRPORT_COST + * The STP path cost of the port. The valid values are between 1 and 65535. + * + * @IFLA_BRPORT_MODE + * Set the bridge port mode. See *BRIDGE_MODE_HAIRPIN* for more details. + * + * @IFLA_BRPORT_GUARD + * Controls whether STP BPDUs will be processed by the bridge port. By + * default, the flag is turned off to allow BPDU processing. Turning this + * flag on will disable the bridge port if a STP BPDU packet is received. + * + * If the bridge has Spanning Tree enabled, hostile devices on the network + * may send BPDU on a port and cause network failure. Setting *guard on* + * will detect and stop this by disabling the port. The port will be + * restarted if the link is brought down, or removed and reattached. + * + * @IFLA_BRPORT_PROTECT + * Controls whether a given port is allowed to become a root port or not. + * Only used when STP is enabled on the bridge. By default the flag is off. + * + * This feature is also called root port guard. If BPDU is received from a + * leaf (edge) port, it should not be elected as root port. This could + * be used if using STP on a bridge and the downstream bridges are not fully + * trusted; this prevents a hostile guest from rerouting traffic. + * + * @IFLA_BRPORT_FAST_LEAVE + * This flag allows the bridge to immediately stop multicast traffic + * forwarding on a port that receives an IGMP Leave message. It is only used + * when IGMP snooping is enabled on the bridge. By default the flag is off. + * + * @IFLA_BRPORT_LEARNING + * Controls whether a given port will learn *source* MAC addresses from + * received traffic or not. Also controls whether dynamic FDB entries + * (which can also be added by software) will be refreshed by incoming + * traffic. By default this flag is on. + * + * @IFLA_BRPORT_UNICAST_FLOOD + * Controls whether unicast traffic for which there is no FDB entry will + * be flooded towards this port. By default this flag is on. + * + * @IFLA_BRPORT_PROXYARP + * Enable proxy ARP on this port. + * + * @IFLA_BRPORT_LEARNING_SYNC + * Controls whether a given port will sync MAC addresses learned on device + * port to bridge FDB. + * + * @IFLA_BRPORT_PROXYARP_WIFI + * Enable proxy ARP on this port which meets extended requirements by + * IEEE 802.11 and Hotspot 2.0 specifications. + * + * @IFLA_BRPORT_ROOT_ID + * + * @IFLA_BRPORT_BRIDGE_ID + * + * @IFLA_BRPORT_DESIGNATED_PORT + * + * @IFLA_BRPORT_DESIGNATED_COST + * + * @IFLA_BRPORT_ID + * + * @IFLA_BRPORT_NO + * + * @IFLA_BRPORT_TOPOLOGY_CHANGE_ACK + * + * @IFLA_BRPORT_CONFIG_PENDING + * + * @IFLA_BRPORT_MESSAGE_AGE_TIMER + * + * @IFLA_BRPORT_FORWARD_DELAY_TIMER + * + * @IFLA_BRPORT_HOLD_TIMER + * + * @IFLA_BRPORT_FLUSH + * Flush bridge ports' fdb dynamic entries. + * + * @IFLA_BRPORT_MULTICAST_ROUTER + * Configure the port's multicast router presence. A port with + * a multicast router will receive all multicast traffic. + * The valid values are: + * + * * 0 disable multicast routers on this port + * * 1 let the system detect the presence of routers (default) + * * 2 permanently enable multicast traffic forwarding on this port + * * 3 enable multicast routers temporarily on this port, not depending + * on incoming queries. + * + * @IFLA_BRPORT_PAD + * + * @IFLA_BRPORT_MCAST_FLOOD + * Controls whether a given port will flood multicast traffic for which + * there is no MDB entry. By default this flag is on. + * + * @IFLA_BRPORT_MCAST_TO_UCAST + * Controls whether a given port will replicate packets using unicast + * instead of multicast. By default this flag is off. + * + * This is done by copying the packet per host and changing the multicast + * destination MAC to a unicast one accordingly. + * + * *mcast_to_unicast* works on top of the multicast snooping feature of the + * bridge. Which means unicast copies are only delivered to hosts which + * are interested in unicast and signaled this via IGMP/MLD reports previously. + * + * This feature is intended for interface types which have a more reliable + * and/or efficient way to deliver unicast packets than broadcast ones + * (e.g. WiFi). + * + * However, it should only be enabled on interfaces where no IGMPv2/MLDv1 + * report suppression takes place. IGMP/MLD report suppression issue is + * usually overcome by the network daemon (supplicant) enabling AP isolation + * and by that separating all STAs. + * + * Delivery of STA-to-STA IP multicast is made possible again by enabling + * and utilizing the bridge hairpin mode, which considers the incoming port + * as a potential outgoing port, too (see *BRIDGE_MODE_HAIRPIN* option). + * Hairpin mode is performed after multicast snooping, therefore leading + * to only deliver reports to STAs running a multicast router. + * + * @IFLA_BRPORT_VLAN_TUNNEL + * Controls whether vlan to tunnel mapping is enabled on the port. + * By default this flag is off. + * + * @IFLA_BRPORT_BCAST_FLOOD + * Controls flooding of broadcast traffic on the given port. By default + * this flag is on. + * + * @IFLA_BRPORT_GROUP_FWD_MASK + * Set the group forward mask. This is a bitmask that is applied to + * decide whether to forward incoming frames destined to link-local + * addresses. The addresses of the form are 01:80:C2:00:00:0X (defaults + * to 0, which means the bridge does not forward any link-local frames + * coming on this port). + * + * @IFLA_BRPORT_NEIGH_SUPPRESS + * Controls whether neighbor discovery (arp and nd) proxy and suppression + * is enabled on the port. By default this flag is off. + * + * @IFLA_BRPORT_ISOLATED + * Controls whether a given port will be isolated, which means it will be + * able to communicate with non-isolated ports only. By default this + * flag is off. + * + * @IFLA_BRPORT_BACKUP_PORT + * Set a backup port. If the port loses carrier all traffic will be + * redirected to the configured backup port. Set the value to 0 to disable + * it. + * + * @IFLA_BRPORT_MRP_RING_OPEN + * + * @IFLA_BRPORT_MRP_IN_OPEN + * + * @IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT + * The number of per-port EHT hosts limit. The default value is 512. + * Setting to 0 is not allowed. + * + * @IFLA_BRPORT_MCAST_EHT_HOSTS_CNT + * The current number of tracked hosts, read only. + * + * @IFLA_BRPORT_LOCKED + * Controls whether a port will be locked, meaning that hosts behind the + * port will not be able to communicate through the port unless an FDB + * entry with the unit's MAC address is in the FDB. The common use case is + * that hosts are allowed access through authentication with the IEEE 802.1X + * protocol or based on whitelists. By default this flag is off. + * + * Please note that secure 802.1X deployments should always use the + * *BR_BOOLOPT_NO_LL_LEARN* flag, to not permit the bridge to populate its + * FDB based on link-local (EAPOL) traffic received on the port. + * + * @IFLA_BRPORT_MAB + * Controls whether a port will use MAC Authentication Bypass (MAB), a + * technique through which select MAC addresses may be allowed on a locked + * port, without using 802.1X authentication. Packets with an unknown source + * MAC address generates a "locked" FDB entry on the incoming bridge port. + * The common use case is for user space to react to these bridge FDB + * notifications and optionally replace the locked FDB entry with a normal + * one, allowing traffic to pass for whitelisted MAC addresses. + * + * Setting this flag also requires *IFLA_BRPORT_LOCKED* and + * *IFLA_BRPORT_LEARNING*. *IFLA_BRPORT_LOCKED* ensures that unauthorized + * data packets are dropped, and *IFLA_BRPORT_LEARNING* allows the dynamic + * FDB entries installed by user space (as replacements for the locked FDB + * entries) to be refreshed and/or aged out. + * + * @IFLA_BRPORT_MCAST_N_GROUPS + * + * @IFLA_BRPORT_MCAST_MAX_GROUPS + * Sets the maximum number of MDB entries that can be registered for a + * given port. Attempts to register more MDB entries at the port than this + * limit allows will be rejected, whether they are done through netlink + * (e.g. the bridge tool), or IGMP or MLD membership reports. Setting a + * limit of 0 disables the limit. The default value is 0. + * + * @IFLA_BRPORT_NEIGH_VLAN_SUPPRESS + * Controls whether neighbor discovery (arp and nd) proxy and suppression is + * enabled for a given port. By default this flag is off. + * + * Note that this option only takes effect when *IFLA_BRPORT_NEIGH_SUPPRESS* + * is enabled for a given port. + * + * @IFLA_BRPORT_BACKUP_NHID + * The FDB nexthop object ID to attach to packets being redirected to a + * backup port that has VLAN tunnel mapping enabled (via the + * *IFLA_BRPORT_VLAN_TUNNEL* option). Setting a value of 0 (default) has + * the effect of not attaching any ID. + */ enum { IFLA_BRPORT_UNSPEC, IFLA_BRPORT_STATE, /* Spanning tree state */ From bcc1f84e4d3480636d8ff7458bfdda9ff908a3d7 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:44 +0800 Subject: [PATCH 2537/7721] docs: bridge: Add kAPI/uAPI fields Add kAPI/uAPI field for bridge doc. Update struct net_bridge_vlan comments to fix doc build warning. Reviewed-by: Florian Fainelli Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 33 +++++++++++++++++++++++++++++ net/bridge/br_private.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index 6ad8b42b2c50..a717563eaa15 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -14,6 +14,39 @@ at the data link layer (Layer 2) of the OSI (Open Systems Interconnection) model. The purpose of a bridge is to filter and forward frames between different segments based on the destination MAC (Media Access Control) address. +Bridge kAPI +=========== + +Here are some core structures of bridge code. Note that the kAPI is *unstable*, +and can be changed at any time. + +.. kernel-doc:: net/bridge/br_private.h + :identifiers: net_bridge_vlan + +Bridge uAPI +=========== + +Modern Linux bridge uAPI is accessed via Netlink interface. You can find +below files where the bridge and bridge port netlink attributes are defined. + +Bridge netlink attributes +------------------------- + +.. kernel-doc:: include/uapi/linux/if_link.h + :doc: Bridge enum definition + +Bridge port netlink attributes +------------------------------ + +.. kernel-doc:: include/uapi/linux/if_link.h + :doc: Bridge port enum definition + +Bridge sysfs +------------ + +The sysfs interface is deprecated and should not be extended if new +options are added. + FAQ === diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6b7f36769d03..051ea81864ac 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -186,6 +186,7 @@ enum { * struct net_bridge_vlan - per-vlan entry * * @vnode: rhashtable member + * @tnode: rhashtable member * @vid: VLAN id * @flags: bridge vlan flags * @priv_flags: private (in-kernel) bridge vlan flags @@ -196,6 +197,7 @@ enum { * @refcnt: if MASTER flag set, this is bumped for each port referencing it * @brvlan: if MASTER flag unset, this points to the global per-VLAN context * for this VLAN entry + * @tinfo: bridge tunnel info * @br_mcast_ctx: if MASTER flag set, this is the global vlan multicast context * @port_mcast_ctx: if MASTER flag unset, this is the per-port/vlan multicast * context From 567d2608209ffd694b19ee2c602d02aeae7fd16d Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:45 +0800 Subject: [PATCH 2538/7721] docs: bridge: add STP doc Add STP part for bridge document. Reviewed-by: Florian Fainelli Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 101 ++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index a717563eaa15..c14410008ddf 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -47,6 +47,107 @@ Bridge sysfs The sysfs interface is deprecated and should not be extended if new options are added. +STP +=== + +The STP (Spanning Tree Protocol) implementation in the Linux bridge driver +is a critical feature that helps prevent loops and broadcast storms in +Ethernet networks by identifying and disabling redundant links. In a Linux +bridge context, STP is crucial for network stability and availability. + +STP is a Layer 2 protocol that operates at the Data Link Layer of the OSI +model. It was originally developed as IEEE 802.1D and has since evolved into +multiple versions, including Rapid Spanning Tree Protocol (RSTP) and +`Multiple Spanning Tree Protocol (MSTP) +`_. + +The 802.1D-2004 removed the original Spanning Tree Protocol, instead +incorporating the Rapid Spanning Tree Protocol (RSTP). By 2014, all the +functionality defined by IEEE 802.1D has been incorporated into either +IEEE 802.1Q (Bridges and Bridged Networks) or IEEE 802.1AC (MAC Service +Definition). 802.1D has been officially withdrawn in 2022. + +Bridge Ports and STP States +--------------------------- + +In the context of STP, bridge ports can be in one of the following states: + * Blocking: The port is disabled for data traffic and only listens for + BPDUs (Bridge Protocol Data Units) from other devices to determine the + network topology. + * Listening: The port begins to participate in the STP process and listens + for BPDUs. + * Learning: The port continues to listen for BPDUs and begins to learn MAC + addresses from incoming frames but does not forward data frames. + * Forwarding: The port is fully operational and forwards both BPDUs and + data frames. + * Disabled: The port is administratively disabled and does not participate + in the STP process. The data frames forwarding are also disabled. + +Root Bridge and Convergence +--------------------------- + +In the context of networking and Ethernet bridging in Linux, the root bridge +is a designated switch in a bridged network that serves as a reference point +for the spanning tree algorithm to create a loop-free topology. + +Here's how the STP works and root bridge is chosen: + 1. Bridge Priority: Each bridge running a spanning tree protocol, has a + configurable Bridge Priority value. The lower the value, the higher the + priority. By default, the Bridge Priority is set to a standard value + (e.g., 32768). + 2. Bridge ID: The Bridge ID is composed of two components: Bridge Priority + and the MAC address of the bridge. It uniquely identifies each bridge + in the network. The Bridge ID is used to compare the priorities of + different bridges. + 3. Bridge Election: When the network starts, all bridges initially assume + that they are the root bridge. They start advertising Bridge Protocol + Data Units (BPDU) to their neighbors, containing their Bridge ID and + other information. + 4. BPDU Comparison: Bridges exchange BPDUs to determine the root bridge. + Each bridge examines the received BPDUs, including the Bridge Priority + and Bridge ID, to determine if it should adjust its own priorities. + The bridge with the lowest Bridge ID will become the root bridge. + 5. Root Bridge Announcement: Once the root bridge is determined, it sends + BPDUs with information about the root bridge to all other bridges in the + network. This information is used by other bridges to calculate the + shortest path to the root bridge and, in doing so, create a loop-free + topology. + 6. Forwarding Ports: After the root bridge is selected and the spanning tree + topology is established, each bridge determines which of its ports should + be in the forwarding state (used for data traffic) and which should be in + the blocking state (used to prevent loops). The root bridge's ports are + all in the forwarding state. while other bridges have some ports in the + blocking state to avoid loops. + 7. Root Ports: After the root bridge is selected and the spanning tree + topology is established, each non-root bridge processes incoming + BPDUs and determines which of its ports provides the shortest path to the + root bridge based on the information in the received BPDUs. This port is + designated as the root port. And it is in the Forwarding state, allowing + it to actively forward network traffic. + 8. Designated ports: A designated port is the port through which the non-root + bridge will forward traffic towards the designated segment. Designated ports + are placed in the Forwarding state. All other ports on the non-root + bridge that are not designated for specific segments are placed in the + Blocking state to prevent network loops. + +STP ensures network convergence by calculating the shortest path and disabling +redundant links. When network topology changes occur (e.g., a link failure), +STP recalculates the network topology to restore connectivity while avoiding loops. + +Proper configuration of STP parameters, such as the bridge priority, can +influence network performance, path selection and which bridge becomes the +Root Bridge. + +User space STP helper +--------------------- + +The user space STP helper *bridge-stp* is a program to control whether to use +user mode spanning tree. The ``/sbin/bridge-stp `` is +called by the kernel when STP is enabled/disabled on a bridge +(via ``brctl stp `` or ``ip link set type bridge +stp_state <0|1>``). The kernel enables user_stp mode if that command returns +0, or enables kernel_stp mode if that command returns any other value. + FAQ === From 041a6ac4bf792eaf4c5898b3a744e98cfdc43a7a Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:46 +0800 Subject: [PATCH 2539/7721] docs: bridge: add VLAN doc Add VLAN part for bridge document. Acked-by: Nikolay Aleksandrov Reviewed-by: Florian Fainelli Reviewed-by: Vladimir Oltean Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index c14410008ddf..97936b9564fd 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -148,6 +148,35 @@ called by the kernel when STP is enabled/disabled on a bridge stp_state <0|1>``). The kernel enables user_stp mode if that command returns 0, or enables kernel_stp mode if that command returns any other value. +VLAN +==== + +A LAN (Local Area Network) is a network that covers a small geographic area, +typically within a single building or a campus. LANs are used to connect +computers, servers, printers, and other networked devices within a localized +area. LANs can be wired (using Ethernet cables) or wireless (using Wi-Fi). + +A VLAN (Virtual Local Area Network) is a logical segmentation of a physical +network into multiple isolated broadcast domains. VLANs are used to divide +a single physical LAN into multiple virtual LANs, allowing different groups of +devices to communicate as if they were on separate physical networks. + +Typically there are two VLAN implementations, IEEE 802.1Q and IEEE 802.1ad +(also known as QinQ). IEEE 802.1Q is a standard for VLAN tagging in Ethernet +networks. It allows network administrators to create logical VLANs on a +physical network and tag Ethernet frames with VLAN information, which is +called *VLAN-tagged frames*. IEEE 802.1ad, commonly known as QinQ or Double +VLAN, is an extension of the IEEE 802.1Q standard. QinQ allows for the +stacking of multiple VLAN tags within a single Ethernet frame. The Linux +bridge supports both the IEEE 802.1Q and `802.1AD +`_ +protocol for VLAN tagging. + +`VLAN filtering `_ +on a bridge is disabled by default. After enabling VLAN filtering on a bridge, +it will start forwarding frames to appropriate destinations based on their +destination MAC address and VLAN tag (both must match). + FAQ === From 75ceac88efb84c72b684d73a16c37842ca08fb14 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:47 +0800 Subject: [PATCH 2540/7721] docs: bridge: add multicast doc Add multicast part for bridge document. Acked-by: Nikolay Aleksandrov Reviewed-by: Florian Fainelli Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index 97936b9564fd..863ad2c8d146 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -177,6 +177,62 @@ on a bridge is disabled by default. After enabling VLAN filtering on a bridge, it will start forwarding frames to appropriate destinations based on their destination MAC address and VLAN tag (both must match). +Multicast +========= + +The Linux bridge driver has multicast support allowing it to process Internet +Group Management Protocol (IGMP) or Multicast Listener Discovery (MLD) +messages, and to efficiently forward multicast data packets. The bridge +driver supports IGMPv2/IGMPv3 and MLDv1/MLDv2. + +Multicast snooping +------------------ + +Multicast snooping is a networking technology that allows network switches +to intelligently manage multicast traffic within a local area network (LAN). + +The switch maintains a multicast group table, which records the association +between multicast group addresses and the ports where hosts have joined these +groups. The group table is dynamically updated based on the IGMP/MLD messages +received. With the multicast group information gathered through snooping, the +switch optimizes the forwarding of multicast traffic. Instead of blindly +broadcasting the multicast traffic to all ports, it sends the multicast +traffic based on the destination MAC address only to ports which have +subscribed the respective destination multicast group. + +When created, the Linux bridge devices have multicast snooping enabled by +default. It maintains a Multicast forwarding database (MDB) which keeps track +of port and group relationships. + +IGMPv3/MLDv2 EHT support +------------------------ + +The Linux bridge supports IGMPv3/MLDv2 EHT (Explicit Host Tracking), which +was added by `474ddb37fa3a ("net: bridge: multicast: add EHT allow/block handling") +`_ + +The explicit host tracking enables the device to keep track of each +individual host that is joined to a particular group or channel. The main +benefit of the explicit host tracking in IGMP is to allow minimal leave +latencies when a host leaves a multicast group or channel. + +The length of time between a host wanting to leave and a device stopping +traffic forwarding is called the IGMP leave latency. A device configured +with IGMPv3 or MLDv2 and explicit tracking can immediately stop forwarding +traffic if the last host to request to receive traffic from the device +indicates that it no longer wants to receive traffic. The leave latency +is thus bound only by the packet transmission latencies in the multiaccess +network and the processing time in the device. + +Other multicast features +------------------------ + +The Linux bridge also supports `per-VLAN multicast snooping +`_, +which is disabled by default but can be enabled. And `Multicast Router Discovery +`_, +which help identify the location of multicast routers. + FAQ === From 3c37f17d6ca9a2153486e2893f996a9f1525c410 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:48 +0800 Subject: [PATCH 2541/7721] docs: bridge: add switchdev doc Add switchdev part for bridge document. Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Acked-by: Nikolay Aleksandrov Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index 863ad2c8d146..e96af89cd061 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -233,6 +233,24 @@ which is disabled by default but can be enabled. And `Multicast Router Discovery `_, which help identify the location of multicast routers. +Switchdev +========= + +Linux Bridge Switchdev is a feature in the Linux kernel that extends the +capabilities of the traditional Linux bridge to work more efficiently with +hardware switches that support switchdev. With Linux Bridge Switchdev, certain +networking functions like forwarding, filtering, and learning of Ethernet +frames can be offloaded to a hardware switch. This offloading reduces the +burden on the Linux kernel and CPU, leading to improved network performance +and lower latency. + +To use Linux Bridge Switchdev, you need hardware switches that support the +switchdev interface. This means that the switch hardware needs to have the +necessary drivers and functionality to work in conjunction with the Linux +kernel. + +Please see the :ref:`switchdev` document for more details. + FAQ === From 1b1a4c7e82aeebef6bd68c94b0531aa72531f60c Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:49 +0800 Subject: [PATCH 2542/7721] docs: bridge: add netfilter doc Add netfilter part for bridge document. Reviewed-by: Florian Westphal Reviewed-by: Florian Fainelli Acked-by: Nikolay Aleksandrov Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index e96af89cd061..39ff8d126a04 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -251,6 +251,42 @@ kernel. Please see the :ref:`switchdev` document for more details. +Netfilter +========= + +The bridge netfilter module is a legacy feature that allows to filter bridged +packets with iptables and ip6tables. Its use is discouraged. Users should +consider using nftables for packet filtering. + +The older ebtables tool is more feature-limited compared to nftables, but +just like nftables it doesn't need this module either to function. + +The br_netfilter module intercepts packets entering the bridge, performs +minimal sanity tests on ipv4 and ipv6 packets and then pretends that +these packets are being routed, not bridged. br_netfilter then calls +the ip and ipv6 netfilter hooks from the bridge layer, i.e. ip(6)tables +rulesets will also see these packets. + +br_netfilter is also the reason for the iptables *physdev* match: +This match is the only way to reliably tell routed and bridged packets +apart in an iptables ruleset. + +Note that ebtables and nftables will work fine without the br_netfilter module. +iptables/ip6tables/arptables do not work for bridged traffic because they +plug in the routing stack. nftables rules in ip/ip6/inet/arp families won't +see traffic that is forwarded by a bridge either, but that's very much how it +should be. + +Historically the feature set of ebtables was very limited (it still is), +this module was added to pretend packets are routed and invoke the ipv4/ipv6 +netfilter hooks from the bridge so users had access to the more feature-rich +iptables matching capabilities (including conntrack). nftables doesn't have +this limitation, pretty much all features work regardless of the protocol family. + +So, br_netfilter is only needed if users, for some reason, need to use +ip(6)tables to filter packets forwarded by the bridge, or NAT bridged +traffic. For pure link layer filtering, this module isn't needed. + FAQ === From d2afc2cd7f1f46500e7ca830c453266f365ee43d Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 1 Dec 2023 16:19:50 +0800 Subject: [PATCH 2543/7721] docs: bridge: add other features Add some features that are not appropriate for the existing section to the "Others" part of the bridge document. Acked-by: Nikolay Aleksandrov Reviewed-by: Florian Fainelli Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- Documentation/networking/bridge.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index 39ff8d126a04..ba14e7b07869 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -287,6 +287,20 @@ So, br_netfilter is only needed if users, for some reason, need to use ip(6)tables to filter packets forwarded by the bridge, or NAT bridged traffic. For pure link layer filtering, this module isn't needed. +Other Features +============== + +The Linux bridge also supports `IEEE 802.11 Proxy ARP +`_, +`Media Redundancy Protocol (MRP) +`_, +`Media Redundancy Protocol (MRP) LC mode +`_, +`IEEE 802.1X port authentication +`_, +and `MAC Authentication Bypass (MAB) +`_. + FAQ === From 3872347e0a16876279bb21642e03842f283f0e38 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 1 Dec 2023 14:50:12 -0300 Subject: [PATCH 2544/7721] net/sched: act_api: use tcf_act_for_each_action Use the auxiliary macro tcf_act_for_each_action in all the functions that expect a contiguous action array Suggested-by: Marcelo Ricardo Leitner Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Acked-by: Marcelo Ricardo Leitner Signed-off-by: Paolo Abeni --- net/sched/act_api.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index c39252d61ebb..05aae374c159 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1118,8 +1118,7 @@ int tcf_action_destroy(struct tc_action *actions[], int bind) struct tc_action *a; int ret = 0, i; - for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) { - a = actions[i]; + tcf_act_for_each_action(i, a, actions) { actions[i] = NULL; ops = a->ops; ret = __tcf_idr_release(a, bind, true); @@ -1211,8 +1210,7 @@ int tcf_action_dump(struct sk_buff *skb, struct tc_action *actions[], int err = -EINVAL, i; struct nlattr *nest; - for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) { - a = actions[i]; + tcf_act_for_each_action(i, a, actions) { nest = nla_nest_start_noflag(skb, i + 1); if (nest == NULL) goto nla_put_failure; @@ -1753,10 +1751,10 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, static int tcf_action_delete(struct net *net, struct tc_action *actions[]) { + struct tc_action *a; int i; - for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) { - struct tc_action *a = actions[i]; + tcf_act_for_each_action(i, a, actions) { const struct tc_action_ops *ops = a->ops; /* Actions can be deleted concurrently so we must save their * type and id to search again after reference is released. @@ -1768,7 +1766,7 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[]) if (tcf_action_put(a)) { /* last reference, action was deleted concurrently */ module_put(ops->owner); - } else { + } else { int ret; /* now do the delete */ From a0e947c9ccffe47d45aca793d9e7fe4f4494e381 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 1 Dec 2023 14:50:13 -0300 Subject: [PATCH 2545/7721] net/sched: act_api: avoid non-contiguous action array In tcf_action_add, when putting the reference for the bound actions it assigns NULLs to just created actions passing a non contiguous array to tcf_action_put_many. Refactor the code so the actions array is always contiguous. Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Acked-by: Marcelo Ricardo Leitner Signed-off-by: Paolo Abeni --- net/sched/act_api.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 05aae374c159..2e948e5992b6 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1135,18 +1135,29 @@ static int tcf_action_put(struct tc_action *p) return __tcf_action_put(p, false); } -/* Put all actions in this array, skip those NULL's. */ static void tcf_action_put_many(struct tc_action *actions[]) { + struct tc_action *a; int i; - for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { - struct tc_action *a = actions[i]; - const struct tc_action_ops *ops; + tcf_act_for_each_action(i, a, actions) { + const struct tc_action_ops *ops = a->ops; + if (tcf_action_put(a)) + module_put(ops->owner); + } +} - if (!a) +static void tca_put_bound_many(struct tc_action *actions[], int init_res[]) +{ + struct tc_action *a; + int i; + + tcf_act_for_each_action(i, a, actions) { + const struct tc_action_ops *ops = a->ops; + + if (init_res[i] == ACT_P_CREATED) continue; - ops = a->ops; + if (tcf_action_put(a)) module_put(ops->owner); } @@ -1975,7 +1986,7 @@ static int tcf_action_add(struct net *net, struct nlattr *nla, struct netlink_ext_ack *extack) { size_t attr_size = 0; - int loop, ret, i; + int loop, ret; struct tc_action *actions[TCA_ACT_MAX_PRIO] = {}; int init_res[TCA_ACT_MAX_PRIO] = {}; @@ -1988,13 +1999,11 @@ static int tcf_action_add(struct net *net, struct nlattr *nla, if (ret < 0) return ret; + ret = tcf_add_notify(net, n, actions, portid, attr_size, extack); - /* only put existing actions */ - for (i = 0; i < TCA_ACT_MAX_PRIO; i++) - if (init_res[i] == ACT_P_CREATED) - actions[i] = NULL; - tcf_action_put_many(actions); + /* only put bound actions */ + tca_put_bound_many(actions, init_res); return ret; } From e09ac779f736e75eab501b77f2a4f13d245f0a6d Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 1 Dec 2023 14:50:14 -0300 Subject: [PATCH 2546/7721] net/sched: act_api: stop loop over ops array on NULL in tcf_action_init The ops array is contiguous, so stop processing whenever a NULL is found Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Acked-by: Marcelo Ricardo Leitner Signed-off-by: Paolo Abeni --- net/sched/act_api.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 2e948e5992b6..d3cb9f5b25da 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1506,10 +1506,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, err: tcf_action_destroy(actions, flags & TCA_ACT_FLAGS_BIND); err_mod: - for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { - if (ops[i]) - module_put(ops[i]->owner); - } + for (i = 0; i < TCA_ACT_MAX_PRIO && ops[i]; i++) + module_put(ops[i]->owner); return err; } From f9bfc8eb1342c7ddbe1b7be9d1ebd5bc80fb72b0 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 1 Dec 2023 14:50:15 -0300 Subject: [PATCH 2547/7721] net/sched: act_api: use tcf_act_for_each_action in tcf_idr_insert_many The actions array is contiguous, so stop processing whenever a NULL is found. This is already the assumption for tcf_action_destroy[1], which is called from tcf_actions_init. [1] https://elixir.bootlin.com/linux/v6.7-rc3/source/net/sched/act_api.c#L1115 Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Acked-by: Marcelo Ricardo Leitner Signed-off-by: Paolo Abeni --- net/sched/act_api.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index d3cb9f5b25da..abec5c45b5a4 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1285,14 +1285,12 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = { void tcf_idr_insert_many(struct tc_action *actions[]) { + struct tc_action *a; int i; - for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { - struct tc_action *a = actions[i]; + tcf_act_for_each_action(i, a, actions) { struct tcf_idrinfo *idrinfo; - if (!a) - continue; idrinfo = a->idrinfo; mutex_lock(&idrinfo->lock); /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc if From a4f5892914ca7709ea6d191f0edace93a5935966 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 4 Dec 2023 12:42:13 +0100 Subject: [PATCH 2548/7721] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq Some SoCs may be equipped with a GPU containing two core groups and this is exactly the case of Samsung's Exynos 5422 featuring an ARM Mali-T628 MP6 GPU: the support for this GPU in Panfrost is partial, as this driver currently supports using only one core group and that's reflected on all parts of it, including the power on (and power off, previously to this patch) function. The issue with this is that even though executing the soft reset operation should power off all cores unconditionally, on at least one platform we're seeing a crash that seems to be happening due to an interrupt firing which may be because we are calling power transition only on the first core group, leaving the second one unchanged, or because ISR execution was pending before entering the panfrost_gpu_power_off() function and executed after powering off the GPU cores, or all of the above. Finally, solve this by: - Avoid to enable the power transition interrupt on reset; and - Ignoring the core_mask and ask the GPU to poweroff both core groups Fixes: 22aa1a209018 ("drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off()") Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Signed-off-by: AngeloGioacchino Del Regno Tested-by: Marek Szyprowski Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20231204114215.54575-2-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 09f5e1563ebd..bd41617c5e4b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -78,7 +78,12 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) } gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); - gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); + + /* Only enable the interrupts we care about */ + gpu_write(pfdev, GPU_INT_MASK, + GPU_IRQ_MASK_ERROR | + GPU_IRQ_PERFCNT_SAMPLE_COMPLETED | + GPU_IRQ_CLEAN_CACHES_COMPLETED); /* * All in-flight jobs should have released their cycle @@ -425,11 +430,10 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) void panfrost_gpu_power_off(struct panfrost_device *pfdev) { - u64 core_mask = panfrost_get_core_mask(pfdev); int ret; u32 val; - gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present & core_mask); + gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present); ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO, val, !val, 1, 1000); if (ret) @@ -441,7 +445,7 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev) if (ret) dev_err(pfdev->dev, "tiler power transition timeout"); - gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present & core_mask); + gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present); ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO, val, !val, 0, 1000); if (ret) From b98e9a84d38ac88f9fd2accbcd45b656eeea7a04 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 4 Dec 2023 12:42:14 +0100 Subject: [PATCH 2549/7721] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device In preparation for adding a IRQ synchronization mechanism for PM suspend, add gpu_irq and mmu_irq variables to struct panfrost_device and change functions panfrost_gpu_init() and panfrost_mmu_init() to use those. Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Signed-off-by: AngeloGioacchino Del Regno Tested-by: Marek Szyprowski Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20231204114215.54575-3-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_device.h | 2 ++ drivers/gpu/drm/panfrost/panfrost_gpu.c | 10 +++++----- drivers/gpu/drm/panfrost/panfrost_mmu.c | 10 +++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 0fc558db6bfd..54a8aad54259 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -94,6 +94,8 @@ struct panfrost_device { struct device *dev; struct drm_device *ddev; struct platform_device *pdev; + int gpu_irq; + int mmu_irq; void __iomem *iomem; struct clk *clock; diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index bd41617c5e4b..7adc4441fa14 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -454,7 +454,7 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev) int panfrost_gpu_init(struct panfrost_device *pfdev) { - int err, irq; + int err; err = panfrost_gpu_soft_reset(pfdev); if (err) @@ -469,11 +469,11 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) dma_set_max_seg_size(pfdev->dev, UINT_MAX); - irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); - if (irq < 0) - return irq; + pfdev->gpu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); + if (pfdev->gpu_irq < 0) + return pfdev->gpu_irq; - err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, + err = devm_request_irq(pfdev->dev, pfdev->gpu_irq, panfrost_gpu_irq_handler, IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev); if (err) { dev_err(pfdev->dev, "failed to request gpu irq"); diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 846dd697c410..ac4296c1e54b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -753,13 +753,13 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data) int panfrost_mmu_init(struct panfrost_device *pfdev) { - int err, irq; + int err; - irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); - if (irq < 0) - return irq; + pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); + if (pfdev->mmu_irq < 0) + return pfdev->mmu_irq; - err = devm_request_threaded_irq(pfdev->dev, irq, + err = devm_request_threaded_irq(pfdev->dev, pfdev->mmu_irq, panfrost_mmu_irq_handler, panfrost_mmu_irq_handler_thread, IRQF_SHARED, KBUILD_MODNAME "-mmu", From 157ad4ccff0754d9eb57d3a4fa31264ee6e9716b Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 4 Dec 2023 12:42:15 +0100 Subject: [PATCH 2550/7721] drm/panfrost: Synchronize and disable interrupts before powering off To make sure that we don't unintentionally perform any unclocked and/or unpowered R/W operation on GPU registers, before turning off clocks and regulators we must make sure that no GPU, JOB or MMU ISR execution is pending: doing that requires to add a mechanism to synchronize the interrupts on suspend. Add functions panfrost_{gpu,job,mmu}_suspend_irq() which will perform interrupts masking and ISR execution synchronization, and then call those in the panfrost_device_runtime_suspend() handler in the exact sequence of job (may require mmu!) -> mmu -> gpu. As a side note, JOB and MMU suspend_irq functions needed some special treatment: as their interrupt handlers will unmask interrupts, it was necessary to add an `is_suspended` bitmap which is used to address the possible corner case of unintentional IRQ unmasking because of ISR execution after a call to synchronize_irq(). At resume, clear each is_suspended bit in the reset path of JOB/MMU to allow unmasking the interrupts. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Boris Brezillon Tested-by: Marek Szyprowski Reviewed-by: Steven Price Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20231204114215.54575-4-angelogioacchino.delregno@collabora.com --- drivers/gpu/drm/panfrost/panfrost_device.c | 3 +++ drivers/gpu/drm/panfrost/panfrost_device.h | 8 +++++++ drivers/gpu/drm/panfrost/panfrost_gpu.c | 18 +++++++++++++-- drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 + drivers/gpu/drm/panfrost/panfrost_job.c | 26 ++++++++++++++++++---- drivers/gpu/drm/panfrost/panfrost_job.h | 1 + drivers/gpu/drm/panfrost/panfrost_mmu.c | 22 +++++++++++++++--- drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 + 8 files changed, 71 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index c90ad5ee34e7..a45e4addcc19 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -421,6 +421,9 @@ static int panfrost_device_runtime_suspend(struct device *dev) return -EBUSY; panfrost_devfreq_suspend(pfdev); + panfrost_job_suspend_irq(pfdev); + panfrost_mmu_suspend_irq(pfdev); + panfrost_gpu_suspend_irq(pfdev); panfrost_gpu_power_off(pfdev); return 0; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 54a8aad54259..62f7e3527385 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -25,6 +25,13 @@ struct panfrost_perfcnt; #define NUM_JOB_SLOTS 3 #define MAX_PM_DOMAINS 5 +enum panfrost_drv_comp_bits { + PANFROST_COMP_BIT_GPU, + PANFROST_COMP_BIT_JOB, + PANFROST_COMP_BIT_MMU, + PANFROST_COMP_BIT_MAX +}; + /** * enum panfrost_gpu_pm - Supported kernel power management features * @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend @@ -109,6 +116,7 @@ struct panfrost_device { struct panfrost_features features; const struct panfrost_compatible *comp; + DECLARE_BITMAP(is_suspended, PANFROST_COMP_BIT_MAX); spinlock_t as_lock; unsigned long as_in_use_mask; diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 7adc4441fa14..9063ce254642 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -22,9 +22,13 @@ static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data) { struct panfrost_device *pfdev = data; - u32 state = gpu_read(pfdev, GPU_INT_STAT); - u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS); + u32 fault_status, state; + if (test_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended)) + return IRQ_NONE; + + fault_status = gpu_read(pfdev, GPU_FAULT_STATUS); + state = gpu_read(pfdev, GPU_INT_STAT); if (!state) return IRQ_NONE; @@ -61,6 +65,8 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_INT_MASK, 0); gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); + clear_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended); + gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000); @@ -452,6 +458,14 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev) dev_err(pfdev->dev, "l2 power transition timeout"); } +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev) +{ + set_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended); + + gpu_write(pfdev, GPU_INT_MASK, 0); + synchronize_irq(pfdev->gpu_irq); +} + int panfrost_gpu_init(struct panfrost_device *pfdev) { int err; diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h index 876fdad9f721..d841b86504ea 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h @@ -15,6 +15,7 @@ u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev); int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); void panfrost_gpu_power_on(struct panfrost_device *pfdev); void panfrost_gpu_power_off(struct panfrost_device *pfdev); +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev); void panfrost_cycle_counter_get(struct panfrost_device *pfdev); void panfrost_cycle_counter_put(struct panfrost_device *pfdev); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index f9446e197428..0c2dbf6ef2a5 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -405,6 +405,8 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev) int j; u32 irq_mask = 0; + clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended); + for (j = 0; j < NUM_JOB_SLOTS; j++) { irq_mask |= MK_JS_MASK(j); } @@ -413,6 +415,14 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev) job_write(pfdev, JOB_INT_MASK, irq_mask); } +void panfrost_job_suspend_irq(struct panfrost_device *pfdev) +{ + set_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended); + + job_write(pfdev, JOB_INT_MASK, 0); + synchronize_irq(pfdev->js->irq); +} + static void panfrost_job_handle_err(struct panfrost_device *pfdev, struct panfrost_job *job, unsigned int js) @@ -792,17 +802,25 @@ static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data) struct panfrost_device *pfdev = data; panfrost_job_handle_irqs(pfdev); - job_write(pfdev, JOB_INT_MASK, - GENMASK(16 + NUM_JOB_SLOTS - 1, 16) | - GENMASK(NUM_JOB_SLOTS - 1, 0)); + + /* Enable interrupts only if we're not about to get suspended */ + if (!test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended)) + job_write(pfdev, JOB_INT_MASK, + GENMASK(16 + NUM_JOB_SLOTS - 1, 16) | + GENMASK(NUM_JOB_SLOTS - 1, 0)); + return IRQ_HANDLED; } static irqreturn_t panfrost_job_irq_handler(int irq, void *data) { struct panfrost_device *pfdev = data; - u32 status = job_read(pfdev, JOB_INT_STAT); + u32 status; + if (test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended)) + return IRQ_NONE; + + status = job_read(pfdev, JOB_INT_STAT); if (!status) return IRQ_NONE; diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h index 17ff808dba07..ec581b97852b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.h +++ b/drivers/gpu/drm/panfrost/panfrost_job.h @@ -47,6 +47,7 @@ int panfrost_job_get_slot(struct panfrost_job *job); int panfrost_job_push(struct panfrost_job *job); void panfrost_job_put(struct panfrost_job *job); void panfrost_job_enable_interrupts(struct panfrost_device *pfdev); +void panfrost_job_suspend_irq(struct panfrost_device *pfdev); int panfrost_job_is_idle(struct panfrost_device *pfdev); #endif diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index ac4296c1e54b..f38385fe76bb 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -231,6 +231,8 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev) { struct panfrost_mmu *mmu, *mmu_tmp; + clear_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended); + spin_lock(&pfdev->as_lock); pfdev->as_alloc_mask = 0; @@ -670,6 +672,9 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) { struct panfrost_device *pfdev = data; + if (test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) + return IRQ_NONE; + if (!mmu_read(pfdev, MMU_INT_STAT)) return IRQ_NONE; @@ -744,9 +749,12 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data) status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask; } - spin_lock(&pfdev->as_lock); - mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask); - spin_unlock(&pfdev->as_lock); + /* Enable interrupts only if we're not about to get suspended */ + if (!test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) { + spin_lock(&pfdev->as_lock); + mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask); + spin_unlock(&pfdev->as_lock); + } return IRQ_HANDLED; }; @@ -777,3 +785,11 @@ void panfrost_mmu_fini(struct panfrost_device *pfdev) { mmu_write(pfdev, MMU_INT_MASK, 0); } + +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev) +{ + set_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended); + + mmu_write(pfdev, MMU_INT_MASK, 0); + synchronize_irq(pfdev->mmu_irq); +} diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h index cc2a0d307feb..022a9a74a114 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.h +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h @@ -14,6 +14,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping); int panfrost_mmu_init(struct panfrost_device *pfdev); void panfrost_mmu_fini(struct panfrost_device *pfdev); void panfrost_mmu_reset(struct panfrost_device *pfdev); +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev); u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu); void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu); From 4da71a77fc3be1fcb680c8d78e1a1fb8017905ad Mon Sep 17 00:00:00 2001 From: Konrad Knitter Date: Fri, 1 Dec 2023 10:08:39 -0800 Subject: [PATCH 2551/7721] ice: read internal temperature sensor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 4.30 firmware exposes internal thermal sensor reading via admin queue commands. Expose those readouts via hwmon API when supported. Datasheet: Get Sensor Reading Command (Opcode: 0x0632) +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Flags | 1-0 | | | | Opcode | 2-3 | 0x0632 | Command opcode | | Datalen | 4-5 | 0 | No external buffer. | | Return value | 6-7 | | Return value. | | Cookie High | 8-11 | Cookie | | | Cookie Low | 12-15 | Cookie | | | Sensor | 16 | | 0x00: Internal temp | | | | | 0x01-0xFF: Reserved. | | Format | 17 | Requested response | Only 0x00 is supported. | | | | format | 0x01-0xFF: Reserved. | | Reserved | 18-23 | | | | Data Address high | 24-27 | Response buffer | | | | | address | | | Data Address low | 28-31 | Response buffer | | | | | address | | +--------------------+--------+--------------------+-------------------------+ Get Sensor Reading Response (Opcode: 0x0632) +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Flags | 1-0 | | | | Opcode | 2-3 | 0x0632 | Command opcode | | Datalen | 4-5 | 0 | No external buffer | | Return value | 6-7 | | Return value. | | | | | EINVAL: Invalid | | | | | parameters | | | | | ENOENT: Unsupported | | | | | sensor | | | | | EIO: Sensor access | | | | | error | | Cookie High | 8-11 | Cookie | | | Cookie Low | 12-15 | Cookie | | | Sensor Reading | 16-23 | | Format of the reading | | | | | is dependent on request | | Data Address high | 24-27 | Response buffer | | | | | address | | | Data Address low | 28-31 | Response buffer | | | | | address | | +--------------------+--------+--------------------+-------------------------+ Sensor Reading for Sensor 0x00 (Internal Chip Temperature): +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Thermal Sensor | 0 | | Reading in degrees | | reading | | | Celsius. Signed int8 | | Warning High | 1 | | Warning High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Critical High | 2 | | Critical High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Fatal High | 3 | | Fatal High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Reserved | 4-7 | | | +--------------------+--------+--------------------+-------------------------+ Driver provides current reading from HW as well as device specific thresholds for thermal alarm (Warning, Critical, Fatal) events. $ sensors Output ========================================================= ice-pci-b100 Adapter: PCI adapter temp1: +62.0°C (high = +95.0°C, crit = +105.0°C) (emerg = +115.0°C) Tested on Intel Corporation Ethernet Controller E810-C for SFP Co-developed-by: Marcin Domagala Signed-off-by: Marcin Domagala Co-developed-by: Eric Joyner Signed-off-by: Eric Joyner Reviewed-by: Marcin Szycik Reviewed-by: Przemek Kitszel Signed-off-by: Konrad Knitter Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/Kconfig | 11 ++ drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice.h | 1 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 28 ++++ drivers/net/ethernet/intel/ice/ice_common.c | 54 +++++++- drivers/net/ethernet/intel/ice/ice_common.h | 2 + drivers/net/ethernet/intel/ice/ice_hwmon.c | 126 ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_hwmon.h | 15 +++ drivers/net/ethernet/intel/ice/ice_main.c | 5 + drivers/net/ethernet/intel/ice/ice_type.h | 7 + 10 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_hwmon.c create mode 100644 drivers/net/ethernet/intel/ice/ice_hwmon.h diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 06ddd7147c7f..d55638ad8704 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -299,6 +299,17 @@ config ICE To compile this driver as a module, choose M here. The module will be called ice. +config ICE_HWMON + bool "Intel(R) Ethernet Connection E800 Series Support HWMON support" + default y + depends on ICE && HWMON && !(ICE=y && HWMON=m) + help + Say Y if you want to expose thermal sensor data on Intel devices. + + Some of our devices contain internal thermal sensors. + This data is available via the hwmon sysfs interface and exposes + the onboard sensors. + config ICE_SWITCHDEV bool "Switchdev Support" default y diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 0679907980f7..b40b4179b9f4 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -49,3 +49,4 @@ ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o ice_eswitch_br.o ice-$(CONFIG_GNSS) += ice_gnss.o +ice-$(CONFIG_ICE_HWMON) += ice_hwmon.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index cd7dcd0fa7f2..3ea33947b878 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -655,6 +655,7 @@ struct ice_pf { #define ICE_MAX_VF_AGG_NODES 32 struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES]; struct ice_dplls dplls; + struct device *hwmon_dev; }; extern struct workqueue_struct *ice_lag_wq; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index d7fdb7ba7268..f77a3c70f262 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -117,6 +117,7 @@ struct ice_aqc_list_caps_elem { #define ICE_AQC_CAPS_NET_VER 0x004C #define ICE_AQC_CAPS_PENDING_NET_VER 0x004D #define ICE_AQC_CAPS_RDMA 0x0051 +#define ICE_AQC_CAPS_SENSOR_READING 0x0067 #define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076 #define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077 #define ICE_AQC_CAPS_NVM_MGMT 0x0080 @@ -1413,6 +1414,30 @@ struct ice_aqc_get_phy_rec_clk_out { __le16 node_handle; }; +/* Get sensor reading (direct 0x0632) */ +struct ice_aqc_get_sensor_reading { + u8 sensor; + u8 format; + u8 reserved[6]; + __le32 addr_high; + __le32 addr_low; +}; + +/* Get sensor reading response (direct 0x0632) */ +struct ice_aqc_get_sensor_reading_resp { + union { + u8 raw[8]; + /* Output data for sensor 0x00, format 0x00 */ + struct _packed { + s8 temp; + u8 temp_warning_threshold; + u8 temp_critical_threshold; + u8 temp_fatal_threshold; + u8 reserved[4]; + } s0f0; + } data; +}; + struct ice_aqc_link_topo_params { u8 lport_num; u8 lport_num_valid; @@ -2443,6 +2468,8 @@ struct ice_aq_desc { struct ice_aqc_restart_an restart_an; struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out; struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out; + struct ice_aqc_get_sensor_reading get_sensor_reading; + struct ice_aqc_get_sensor_reading_resp get_sensor_reading_resp; struct ice_aqc_gpio read_write_gpio; struct ice_aqc_sff_eeprom read_write_sff_param; struct ice_aqc_set_port_id_led set_port_id_led; @@ -2618,6 +2645,7 @@ enum ice_adminq_opc { ice_aqc_opc_set_mac_lb = 0x0620, ice_aqc_opc_set_phy_rec_clk_out = 0x0630, ice_aqc_opc_get_phy_rec_clk_out = 0x0631, + ice_aqc_opc_get_sensor_reading = 0x0632, ice_aqc_opc_get_link_topo = 0x06E0, ice_aqc_opc_read_i2c = 0x06E2, ice_aqc_opc_write_i2c = 0x06E3, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 9a6c25f98632..8d97434e1413 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2710,6 +2710,26 @@ ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, dev_p->num_flow_director_fltr); } +/** + * ice_parse_sensor_reading_cap - Parse ICE_AQC_CAPS_SENSOR_READING cap + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @cap: capability element to parse + * + * Parse ICE_AQC_CAPS_SENSOR_READING for device capability for reading + * enabled sensors. + */ +static void +ice_parse_sensor_reading_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, + struct ice_aqc_list_caps_elem *cap) +{ + dev_p->supported_sensors = le32_to_cpu(cap->number); + + ice_debug(hw, ICE_DBG_INIT, + "dev caps: supported sensors (bitmap) = 0x%x\n", + dev_p->supported_sensors); +} + /** * ice_parse_dev_caps - Parse device capabilities * @hw: pointer to the HW struct @@ -2755,9 +2775,12 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, case ICE_AQC_CAPS_1588: ice_parse_1588_dev_caps(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_FD: + case ICE_AQC_CAPS_FD: ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); break; + case ICE_AQC_CAPS_SENSOR_READING: + ice_parse_sensor_reading_cap(hw, dev_p, &cap_resp[i]); + break; default: /* Don't list common capabilities as unknown */ if (!found) @@ -5540,6 +5563,35 @@ ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num, return status; } +/** + * ice_aq_get_sensor_reading + * @hw: pointer to the HW struct + * @data: pointer to data to be read from the sensor + * + * Get sensor reading (0x0632) + */ +int ice_aq_get_sensor_reading(struct ice_hw *hw, + struct ice_aqc_get_sensor_reading_resp *data) +{ + struct ice_aqc_get_sensor_reading *cmd; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sensor_reading); + cmd = &desc.params.get_sensor_reading; +#define ICE_INTERNAL_TEMP_SENSOR_FORMAT 0 +#define ICE_INTERNAL_TEMP_SENSOR 0 + cmd->sensor = ICE_INTERNAL_TEMP_SENSOR; + cmd->format = ICE_INTERNAL_TEMP_SENSOR_FORMAT; + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) + memcpy(data, &desc.params.get_sensor_reading_resp, + sizeof(*data)); + + return status; +} + /** * ice_replay_pre_init - replay pre initialization * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 31fdcac33986..5f7aa293d4ae 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -241,6 +241,8 @@ ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, int ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num, u8 *flags, u16 *node_handle); +int ice_aq_get_sensor_reading(struct ice_hw *hw, + struct ice_aqc_get_sensor_reading_resp *data); void ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); diff --git a/drivers/net/ethernet/intel/ice/ice_hwmon.c b/drivers/net/ethernet/intel/ice/ice_hwmon.c new file mode 100644 index 000000000000..e4c2c1bff6c0 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_hwmon.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023, Intel Corporation. */ + +#include "ice.h" +#include "ice_hwmon.h" +#include "ice_adminq_cmd.h" + +#include + +#define TEMP_FROM_REG(reg) ((reg) * 1000) + +static const struct hwmon_channel_info *ice_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | + HWMON_T_CRIT | HWMON_T_EMERGENCY), + NULL +}; + +static int ice_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct ice_aqc_get_sensor_reading_resp resp; + struct ice_pf *pf = dev_get_drvdata(dev); + int ret; + + if (type != hwmon_temp) + return -EOPNOTSUPP; + + ret = ice_aq_get_sensor_reading(&pf->hw, &resp); + if (ret) { + dev_warn_ratelimited(dev, + "%s HW read failure (%d)\n", + __func__, + ret); + return ret; + } + + switch (attr) { + case hwmon_temp_input: + *val = TEMP_FROM_REG(resp.data.s0f0.temp); + break; + case hwmon_temp_max: + *val = TEMP_FROM_REG(resp.data.s0f0.temp_warning_threshold); + break; + case hwmon_temp_crit: + *val = TEMP_FROM_REG(resp.data.s0f0.temp_critical_threshold); + break; + case hwmon_temp_emergency: + *val = TEMP_FROM_REG(resp.data.s0f0.temp_fatal_threshold); + break; + default: + dev_dbg(dev, "%s unsupported attribute (%d)\n", + __func__, attr); + return -EOPNOTSUPP; + } + + return 0; +} + +static umode_t ice_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_crit: + case hwmon_temp_max: + case hwmon_temp_emergency: + return 0444; + } + + return 0; +} + +static const struct hwmon_ops ice_hwmon_ops = { + .is_visible = ice_hwmon_is_visible, + .read = ice_hwmon_read +}; + +static const struct hwmon_chip_info ice_chip_info = { + .ops = &ice_hwmon_ops, + .info = ice_hwmon_info +}; + +static bool ice_is_internal_reading_supported(struct ice_pf *pf) +{ + /* Only the first PF will report temperature for a chip. + * Note that internal temp reading is not supported + * for older FW (< v4.30). + */ + if (pf->hw.pf_id) + return false; + + unsigned long sensors = pf->hw.dev_caps.supported_sensors; + + return _test_bit(ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT, &sensors); +}; + +void ice_hwmon_init(struct ice_pf *pf) +{ + struct device *dev = ice_pf_to_dev(pf); + struct device *hdev; + + if (!ice_is_internal_reading_supported(pf)) + return; + + hdev = hwmon_device_register_with_info(dev, "ice", pf, &ice_chip_info, + NULL); + if (IS_ERR(hdev)) { + dev_warn(dev, + "hwmon_device_register_with_info returns error (%ld)", + PTR_ERR(hdev)); + return; + } + pf->hwmon_dev = hdev; +} + +void ice_hwmon_exit(struct ice_pf *pf) +{ + if (!pf->hwmon_dev) + return; + hwmon_device_unregister(pf->hwmon_dev); +} diff --git a/drivers/net/ethernet/intel/ice/ice_hwmon.h b/drivers/net/ethernet/intel/ice/ice_hwmon.h new file mode 100644 index 000000000000..d66d40354f5a --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_hwmon.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2023, Intel Corporation. */ + +#ifndef _ICE_HWMON_H_ +#define _ICE_HWMON_H_ + +#ifdef CONFIG_ICE_HWMON +void ice_hwmon_init(struct ice_pf *pf); +void ice_hwmon_exit(struct ice_pf *pf); +#else /* CONFIG_ICE_HWMON */ +static inline void ice_hwmon_init(struct ice_pf *pf) { } +static inline void ice_hwmon_exit(struct ice_pf *pf) { } +#endif /* CONFIG_ICE_HWMON */ + +#endif /* _ICE_HWMON_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 9e3d3919307b..0a7eed9b43a6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -14,6 +14,7 @@ #include "ice_dcb_lib.h" #include "ice_dcb_nl.h" #include "ice_devlink.h" +#include "ice_hwmon.h" /* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the * ice tracepoint functions. This must be done exactly once across the * ice driver. @@ -4687,6 +4688,8 @@ static void ice_init_features(struct ice_pf *pf) if (ice_init_lag(pf)) dev_warn(dev, "Failed to init link aggregation support\n"); + + ice_hwmon_init(pf); } static void ice_deinit_features(struct ice_pf *pf) @@ -5212,6 +5215,8 @@ static void ice_remove(struct pci_dev *pdev) ice_free_vfs(pf); } + ice_hwmon_exit(pf); + ice_service_task_stop(pf); ice_aq_cancel_waiting_tasks(pf); set_bit(ICE_DOWN, pf->state); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index a18ca0ff879f..5a80158e49ed 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -377,6 +377,8 @@ struct ice_hw_func_caps { struct ice_ts_func_info ts_func_info; }; +#define ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT 0 + /* Device wide capabilities */ struct ice_hw_dev_caps { struct ice_hw_common_caps common_cap; @@ -385,6 +387,11 @@ struct ice_hw_dev_caps { u32 num_flow_director_fltr; /* Number of FD filters available */ struct ice_ts_dev_info ts_dev_info; u32 num_funcs; + /* bitmap of supported sensors + * bit 0 - internal temperature sensor + * bit 31:1 - Reserved + */ + u32 supported_sensors; }; /* MAC info */ From b86455a1cbef6829e8da3f93d37a233be2616569 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 1 Dec 2023 10:08:40 -0800 Subject: [PATCH 2552/7721] ice: add CGU info to devlink info callback If Clock Generation Unit is present on NIC board user shall know its details. Provide the devlink info callback with a new: - fixed type object (cgu.id) indicating hardware variant of onboard CGU, - running type object (fw.cgu) consisting of CGU id, config and firmware versions. These information shall be known for debugging purposes. Test (on NIC board with CGU) $ devlink dev info / | grep cgu cgu.id 36 fw.cgu 8032.16973825.6021 Test (on NIC board without CGU) $ devlink dev info / | grep cgu -c 0 Reviewed-by: Larysa Zaremba Signed-off-by: Arkadiusz Kubalewski Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- Documentation/networking/devlink/ice.rst | 9 +++++++++ drivers/net/ethernet/intel/ice/ice_devlink.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/networking/devlink/ice.rst b/Documentation/networking/devlink/ice.rst index 2f60e34ab926..7f30ebd5debb 100644 --- a/Documentation/networking/devlink/ice.rst +++ b/Documentation/networking/devlink/ice.rst @@ -38,6 +38,10 @@ The ``ice`` driver reports the following versions - fixed - K65390-000 - The Product Board Assembly (PBA) identifier of the board. + * - ``cgu.id`` + - fixed + - 36 + - The Clock Generation Unit (CGU) hardware revision identifier. * - ``fw.mgmt`` - running - 2.1.7 @@ -104,6 +108,11 @@ The ``ice`` driver reports the following versions - running - 0xee16ced7 - The first 4 bytes of the hash of the netlist module contents. + * - ``fw.cgu`` + - running + - 8032.16973825.6021 + - The version of Clock Generation Unit (CGU). Format: + ... Flash Update ============ diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index f4e24d11ebd0..65be56f2af9e 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -193,6 +193,24 @@ ice_info_pending_netlist_build(struct ice_pf __always_unused *pf, snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); } +static void ice_info_cgu_fw_build(struct ice_pf *pf, struct ice_info_ctx *ctx) +{ + u32 id, cfg_ver, fw_ver; + + if (!ice_is_feature_supported(pf, ICE_F_CGU)) + return; + if (ice_aq_get_cgu_info(&pf->hw, &id, &cfg_ver, &fw_ver)) + return; + snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", id, cfg_ver, fw_ver); +} + +static void ice_info_cgu_id(struct ice_pf *pf, struct ice_info_ctx *ctx) +{ + if (!ice_is_feature_supported(pf, ICE_F_CGU)) + return; + snprintf(ctx->buf, sizeof(ctx->buf), "%u", pf->hw.cgu_part_number); +} + #define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL } #define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL } #define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback } @@ -235,6 +253,8 @@ static const struct ice_devlink_version { running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id), combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver), combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build), + fixed("cgu.id", ice_info_cgu_id), + running("fw.cgu", ice_info_cgu_fw_build), }; /** From e9fd08a9a7fb98000757ca1971271ec846ea3065 Mon Sep 17 00:00:00 2001 From: Pawel Kaminski Date: Fri, 1 Dec 2023 10:08:41 -0800 Subject: [PATCH 2553/7721] ice: Improve logs for max ntuple errors Supported number of ntuple filters affect also maximum location value that can be provided to ethtool command. Update error message to provide info about max supported value. Fix double spaces in the error messages. Reviewed-by: Jesse Brandeburg Signed-off-by: Pawel Kaminski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c index d151e5bacfec..3cc9d703428e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c @@ -668,7 +668,7 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg, * then return error. */ if (hw->fdir_fltr_cnt[flow]) { - dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n"); + dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n"); return -EINVAL; } @@ -770,7 +770,7 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg, ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h); err_prof: ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id); - dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n"); + dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n"); return err; } @@ -1853,6 +1853,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) struct ice_pf *pf; struct ice_hw *hw; int fltrs_needed; + u32 max_location; u16 tunnel_port; int ret; @@ -1884,8 +1885,10 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) if (ret) return ret; - if (fsp->location >= ice_get_fdir_cnt_all(hw)) { - dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n"); + max_location = ice_get_fdir_cnt_all(hw); + if (fsp->location >= max_location) { + dev_err(dev, "Failed to add filter. The number of ntuple filters or provided location exceed max %d.\n", + max_location); return -ENOSPC; } @@ -1893,7 +1896,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) fltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port, TNL_ALL) ? 2 : 1; if (!ice_fdir_find_fltr_by_idx(hw, fsp->location) && ice_fdir_num_avail_fltr(hw, pf->vsi[vsi->idx]) < fltrs_needed) { - dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n"); + dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n"); return -ENOSPC; } From 1cc5b6eaad92d69fe4d84bbee5c12ee297d56296 Mon Sep 17 00:00:00 2001 From: Karol Kolacinski Date: Fri, 1 Dec 2023 10:08:42 -0800 Subject: [PATCH 2554/7721] ice: Re-enable timestamping correctly after reset During reset, TX_TSYN interrupt should be processed as it may process timestamps in brief moments before and after reset. Timestamping should be enabled on VSIs at the end of reset procedure. On ice_get_phy_tx_tstamp_ready error, interrupt should not be rearmed because error only happens on resets. Reviewed-by: Jesse Brandeburg Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_ptp.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0a7eed9b43a6..a39c2d9bdafe 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3151,7 +3151,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) if (oicr & PFINT_OICR_TSYN_TX_M) { ena_mask &= ~PFINT_OICR_TSYN_TX_M; - if (!hw->reset_ongoing && ice_ptp_pf_handles_tx_interrupt(pf)) + if (ice_ptp_pf_handles_tx_interrupt(pf)) set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 71f405f8a6fe..ac3f24693a50 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -705,7 +705,9 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf) /* Read the Tx ready status first */ err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); - if (err || tstamp_ready) + if (err) + break; + else if (tstamp_ready) return ICE_TX_TSTAMP_WORK_PENDING; } @@ -2468,12 +2470,10 @@ void ice_ptp_reset(struct ice_pf *pf) int err, itr = 1; u64 time_diff; - if (test_bit(ICE_PFR_REQ, pf->state)) + if (test_bit(ICE_PFR_REQ, pf->state) || + !ice_pf_src_tmr_owned(pf)) goto pfr; - if (!ice_pf_src_tmr_owned(pf)) - goto reset_ts; - err = ice_ptp_init_phc(hw); if (err) goto err; @@ -2517,10 +2517,6 @@ void ice_ptp_reset(struct ice_pf *pf) goto err; } -reset_ts: - /* Restart the PHY timestamping block */ - ice_ptp_reset_phy_timestamping(pf); - pfr: /* Init Tx structures */ if (ice_is_e810(&pf->hw)) { @@ -2536,6 +2532,11 @@ void ice_ptp_reset(struct ice_pf *pf) set_bit(ICE_FLAG_PTP, pf->flags); + /* Restart the PHY timestamping block */ + if (!test_bit(ICE_PFR_REQ, pf->state) && + ice_pf_src_tmr_owned(pf)) + ice_ptp_restart_all_phy(pf); + /* Start periodic work going */ kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0); From 712e876371f8350c446a33577cf4a0aedcd4742a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 1 Dec 2023 10:08:43 -0800 Subject: [PATCH 2555/7721] ice: periodically kick Tx timestamp interrupt The E822 hardware for Tx timestamping keeps track of how many outstanding timestamps are still in the PHY memory block. It will not generate a new interrupt to the MAC until all of the timestamps in the region have been read. If somehow all the available data is not read, but the driver has exited its interrupt routine already, the PHY will not generate a new interrupt even if new timestamp data is captured. Because no interrupt is generated, the driver never processes the timestamp data. This state results in a permanent failure for all future Tx timestamps. It is not clear how the driver and hardware could enter this state. However, if it does, there is currently no recovery mechanism. Add a recovery mechanism via the periodic PTP work thread which invokes ice_ptp_periodic_work(). Introduce a new check, ice_ptp_maybe_trigger_tx_interrupt() which checks the PHY timestamp ready bitmask. If any bits are set, trigger a software interrupt by writing to PFINT_OICR. Once triggered, the main timestamp processing thread will read through the PHY data and clear the outstanding timestamp data. Once cleared, new data should trigger interrupts as expected. This should allow recovery from such a state rather than leaving the device in a state where we cannot process Tx timestamps. It is possible that this function checks for timestamp data simultaneously with the interrupt, and it might trigger additional unnecessary interrupts. This will cause a small amount of additional processing. Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Andrii Staikov Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index ac3f24693a50..03fc9c7cd21a 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2442,6 +2442,54 @@ enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf) } } +/** + * ice_ptp_maybe_trigger_tx_interrupt - Trigger Tx timstamp interrupt + * @pf: Board private structure + * + * The device PHY issues Tx timestamp interrupts to the driver for processing + * timestamp data from the PHY. It will not interrupt again until all + * current timestamp data is read. In rare circumstances, it is possible that + * the driver fails to read all outstanding data. + * + * To avoid getting permanently stuck, periodically check if the PHY has + * outstanding timestamp data. If so, trigger an interrupt from software to + * process this data. + */ +static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) +{ + struct device *dev = ice_pf_to_dev(pf); + struct ice_hw *hw = &pf->hw; + bool trigger_oicr = false; + unsigned int i; + + if (ice_is_e810(hw)) + return; + + if (!ice_pf_src_tmr_owned(pf)) + return; + + for (i = 0; i < ICE_MAX_QUAD; i++) { + u64 tstamp_ready; + int err; + + err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); + if (!err && tstamp_ready) { + trigger_oicr = true; + break; + } + } + + if (trigger_oicr) { + /* Trigger a software interrupt, to ensure this data + * gets processed. + */ + dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); + + wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); + ice_flush(hw); + } +} + static void ice_ptp_periodic_work(struct kthread_work *work) { struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work); @@ -2453,6 +2501,8 @@ static void ice_ptp_periodic_work(struct kthread_work *work) err = ice_ptp_update_cached_phctime(pf); + ice_ptp_maybe_trigger_tx_interrupt(pf); + /* Run twice a second or reschedule if phc update failed */ kthread_queue_delayed_work(ptp->kworker, &ptp->work, msecs_to_jiffies(err ? 10 : 500)); From a39dd252d552ab3212fea55330081ee64a9e5573 Mon Sep 17 00:00:00 2001 From: Karol Kolacinski Date: Fri, 1 Dec 2023 10:08:44 -0800 Subject: [PATCH 2556/7721] ice: Rename E822 to E82X When code is applicable for both E822 and E823 devices, rename it from E822 to E82X. ICE_PHY_PER_NAC_E822 was unused, so just remove it. Signed-off-by: Karol Kolacinski Reviewed-by: Przemek Kitszel Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 48 +- drivers/net/ethernet/intel/ice/ice_ptp.h | 2 +- .../net/ethernet/intel/ice/ice_ptp_consts.h | 12 +- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 444 +++++++++--------- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 48 +- drivers/net/ethernet/intel/ice/ice_type.h | 7 +- 6 files changed, 280 insertions(+), 281 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 03fc9c7cd21a..e9e59f4b5580 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -7,7 +7,7 @@ #define E810_OUT_PROP_DELAY_NS 1 -#define UNKNOWN_INCVAL_E822 0x100000000ULL +#define UNKNOWN_INCVAL_E82X 0x100000000ULL static const struct ptp_pin_desc ice_pin_desc_e810t[] = { /* name idx func chan */ @@ -877,7 +877,7 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx) } /** - * ice_ptp_init_tx_e822 - Initialize tracking for Tx timestamps + * ice_ptp_init_tx_e82x - Initialize tracking for Tx timestamps * @pf: Board private structure * @tx: the Tx tracking structure to initialize * @port: the port this structure tracks @@ -888,11 +888,11 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx) * registers into chunks based on the port number. */ static int -ice_ptp_init_tx_e822(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port) +ice_ptp_init_tx_e82x(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port) { tx->block = port / ICE_PORTS_PER_QUAD; - tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E822; - tx->len = INDEX_PER_PORT_E822; + tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E82X; + tx->len = INDEX_PER_PORT_E82X; tx->verify_cached = 0; return ice_ptp_alloc_tx_tracker(tx); @@ -1095,10 +1095,10 @@ static u64 ice_base_incval(struct ice_pf *pf) if (ice_is_e810(hw)) incval = ICE_PTP_NOMINAL_INCVAL_E810; - else if (ice_e822_time_ref(hw) < NUM_ICE_TIME_REF_FREQ) - incval = ice_e822_nominal_incval(ice_e822_time_ref(hw)); + else if (ice_e82x_time_ref(hw) < NUM_ICE_TIME_REF_FREQ) + incval = ice_e82x_nominal_incval(ice_e82x_time_ref(hw)); else - incval = UNKNOWN_INCVAL_E822; + incval = UNKNOWN_INCVAL_E82X; dev_dbg(ice_pf_to_dev(pf), "PTP: using base increment value of 0x%016llx\n", incval); @@ -1127,10 +1127,10 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port) /* need to read FIFO state */ if (offs == 0 || offs == 1) - err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO01_STATUS, + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_FIFO01_STATUS, &val); else - err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO23_STATUS, + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_FIFO23_STATUS, &val); if (err) { @@ -1158,7 +1158,7 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port) dev_dbg(ice_pf_to_dev(pf), "Port %d Tx FIFO still not empty; resetting quad %d\n", port->port_num, quad); - ice_ptp_reset_ts_memory_quad_e822(hw, quad); + ice_ptp_reset_ts_memory_quad_e82x(hw, quad); port->tx_fifo_busy_cnt = FIFO_OK; return 0; } @@ -1203,8 +1203,8 @@ static void ice_ptp_wait_for_offsets(struct kthread_work *work) tx_err = ice_ptp_check_tx_fifo(port); if (!tx_err) - tx_err = ice_phy_cfg_tx_offset_e822(hw, port->port_num); - rx_err = ice_phy_cfg_rx_offset_e822(hw, port->port_num); + tx_err = ice_phy_cfg_tx_offset_e82x(hw, port->port_num); + rx_err = ice_phy_cfg_rx_offset_e82x(hw, port->port_num); if (tx_err || rx_err) { /* Tx and/or Rx offset not yet configured, try again later */ kthread_queue_delayed_work(pf->ptp.kworker, @@ -1233,7 +1233,7 @@ ice_ptp_port_phy_stop(struct ice_ptp_port *ptp_port) kthread_cancel_delayed_work_sync(&ptp_port->ov_work); - err = ice_stop_phy_timer_e822(hw, port, true); + err = ice_stop_phy_timer_e82x(hw, port, true); if (err) dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d down, err %d\n", port, err); @@ -1276,7 +1276,7 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port) ptp_port->tx_fifo_busy_cnt = 0; /* Start the PHY timer in Vernier mode */ - err = ice_start_phy_timer_e822(hw, port); + err = ice_start_phy_timer_e82x(hw, port); if (err) goto out_unlock; @@ -1325,7 +1325,7 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) case ICE_PHY_E810: /* Do not reconfigure E810 PHY */ return; - case ICE_PHY_E822: + case ICE_PHY_E82X: ice_ptp_port_phy_restart(ptp_port); return; default: @@ -1351,7 +1351,7 @@ static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold) ice_ptp_reset_ts_memory(hw); for (quad = 0; quad < ICE_MAX_QUAD; quad++) { - err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); if (err) break; @@ -1365,7 +1365,7 @@ static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold) val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M; } - err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, + err = ice_write_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); if (err) break; @@ -1603,7 +1603,7 @@ static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan, if (ice_is_e810(hw)) start_time -= E810_OUT_PROP_DELAY_NS; else - start_time -= ice_e822_pps_delay(ice_e822_time_ref(hw)); + start_time -= ice_e82x_pps_delay(ice_e82x_time_ref(hw)); /* 2. Write TARGET time */ wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time)); @@ -1842,7 +1842,7 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts) ice_ptp_enable_all_clkout(pf); /* Recalibrate and re-enable timestamp blocks for E822/E823 */ - if (hw->phy_model == ICE_PHY_E822) + if (hw->phy_model == ICE_PHY_E82X) ice_ptp_restart_all_phy(pf); exit: if (err) { @@ -2574,7 +2574,7 @@ void ice_ptp_reset(struct ice_pf *pf) } else { kthread_init_delayed_work(&ptp->port.ov_work, ice_ptp_wait_for_offsets); - err = ice_ptp_init_tx_e822(pf, &ptp->port.tx, + err = ice_ptp_init_tx_e82x(pf, &ptp->port.tx, ptp->port.port_num); } if (err) @@ -2947,11 +2947,11 @@ static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port) switch (hw->phy_model) { case ICE_PHY_E810: return ice_ptp_init_tx_e810(pf, &ptp_port->tx); - case ICE_PHY_E822: + case ICE_PHY_E82X: kthread_init_delayed_work(&ptp_port->ov_work, ice_ptp_wait_for_offsets); - return ice_ptp_init_tx_e822(pf, &ptp_port->tx, + return ice_ptp_init_tx_e82x(pf, &ptp_port->tx, ptp_port->port_num); default: return -ENODEV; @@ -3038,7 +3038,7 @@ static void ice_ptp_remove_auxbus_device(struct ice_pf *pf) static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf) { switch (pf->hw.phy_model) { - case ICE_PHY_E822: + case ICE_PHY_E82X: /* E822 based PHY has the clock owner process the interrupt * for all ports. */ diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 06a330867fc9..d79281061409 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -147,7 +147,7 @@ struct ice_ptp_tx { /* Quad and port information for initializing timestamp blocks */ #define INDEX_PER_QUAD 64 -#define INDEX_PER_PORT_E822 16 +#define INDEX_PER_PORT_E82X 16 #define INDEX_PER_PORT_E810 64 /** diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h index 4109aa3b2fcd..2c4dab0c48ab 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h @@ -9,17 +9,17 @@ */ /* Constants defined for the PTP 1588 clock hardware. */ -/* struct ice_time_ref_info_e822 +/* struct ice_time_ref_info_e82x * * E822 hardware can use different sources as the reference for the PTP * hardware clock. Each clock has different characteristics such as a slightly * different frequency, etc. * * This lookup table defines several constants that depend on the current time - * reference. See the struct ice_time_ref_info_e822 for information about the + * reference. See the struct ice_time_ref_info_e82x for information about the * meaning of each constant. */ -const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = { +const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ] = { /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ { /* pll_freq */ @@ -81,7 +81,7 @@ const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = { }, }; -const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = { +const struct ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = { /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ { /* refclk_pre_div */ @@ -155,7 +155,7 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = { }, }; -/* struct ice_vernier_info_e822 +/* struct ice_vernier_info_e82x * * E822 hardware calibrates the delay of the timestamp indication from the * actual packet transmission or reception during the initialization of the @@ -168,7 +168,7 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = { * used by this link speed, and that the register should be cleared by writing * 0. Other values specify the clock frequency in Hz. */ -const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD] = { +const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD] = { /* ICE_PTP_LNK_SPD_1G */ { /* tx_par_clk */ diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index a00b55e14aac..187ce9b54e1a 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -284,19 +284,19 @@ static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw) */ /** - * ice_fill_phy_msg_e822 - Fill message data for a PHY register access + * ice_fill_phy_msg_e82x - Fill message data for a PHY register access * @msg: the PHY message buffer to fill in * @port: the port to access * @offset: the register offset */ static void -ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) +ice_fill_phy_msg_e82x(struct ice_sbq_msg_input *msg, u8 port, u16 offset) { int phy_port, phy, quadtype; - phy_port = port % ICE_PORTS_PER_PHY_E822; - phy = port / ICE_PORTS_PER_PHY_E822; - quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E822; + phy_port = port % ICE_PORTS_PER_PHY_E82X; + phy = port / ICE_PORTS_PER_PHY_E82X; + quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E82X; if (quadtype == 0) { msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port); @@ -315,7 +315,7 @@ ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) } /** - * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register + * ice_is_64b_phy_reg_e82x - Check if this is a 64bit PHY register * @low_addr: the low address to check * @high_addr: on return, contains the high address of the 64bit register * @@ -323,7 +323,7 @@ ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) * represented as two 32bit registers. If it is, return the appropriate high * register offset to use. */ -static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) +static bool ice_is_64b_phy_reg_e82x(u16 low_addr, u16 *high_addr) { switch (low_addr) { case P_REG_PAR_PCS_TX_OFFSET_L: @@ -368,7 +368,7 @@ static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) } /** - * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register + * ice_is_40b_phy_reg_e82x - Check if this is a 40bit PHY register * @low_addr: the low address to check * @high_addr: on return, contains the high address of the 40bit value * @@ -377,7 +377,7 @@ static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) * upper 32 bits in the high register. If it is, return the appropriate high * register offset to use. */ -static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) +static bool ice_is_40b_phy_reg_e82x(u16 low_addr, u16 *high_addr) { switch (low_addr) { case P_REG_TIMETUS_L: @@ -413,7 +413,7 @@ static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) } /** - * ice_read_phy_reg_e822 - Read a PHY register + * ice_read_phy_reg_e82x - Read a PHY register * @hw: pointer to the HW struct * @port: PHY port to read from * @offset: PHY register offset to read @@ -422,12 +422,12 @@ static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) * Read a PHY register for the given port over the device sideband queue. */ static int -ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) +ice_read_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 *val) { struct ice_sbq_msg_input msg = {0}; int err; - ice_fill_phy_msg_e822(&msg, port, offset); + ice_fill_phy_msg_e82x(&msg, port, offset); msg.opcode = ice_sbq_msg_rd; err = ice_sbq_rw_reg(hw, &msg); @@ -443,7 +443,7 @@ ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) } /** - * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers + * ice_read_64b_phy_reg_e82x - Read a 64bit value from PHY registers * @hw: pointer to the HW struct * @port: PHY port to read from * @low_addr: offset of the lower register to read from @@ -455,7 +455,7 @@ ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) * known to be two parts of a 64bit value. */ static int -ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) +ice_read_64b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) { u32 low, high; u16 high_addr; @@ -464,20 +464,20 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) /* Only operate on registers known to be split into two 32bit * registers. */ - if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { + if (!ice_is_64b_phy_reg_e82x(low_addr, &high_addr)) { ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", low_addr); return -EINVAL; } - err = ice_read_phy_reg_e822(hw, port, low_addr, &low); + err = ice_read_phy_reg_e82x(hw, port, low_addr, &low); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d", low_addr, err); return err; } - err = ice_read_phy_reg_e822(hw, port, high_addr, &high); + err = ice_read_phy_reg_e82x(hw, port, high_addr, &high); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d", high_addr, err); @@ -490,7 +490,7 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) } /** - * ice_write_phy_reg_e822 - Write a PHY register + * ice_write_phy_reg_e82x - Write a PHY register * @hw: pointer to the HW struct * @port: PHY port to write to * @offset: PHY register offset to write @@ -499,12 +499,12 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) * Write a PHY register for the given port over the device sideband queue. */ static int -ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) +ice_write_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 val) { struct ice_sbq_msg_input msg = {0}; int err; - ice_fill_phy_msg_e822(&msg, port, offset); + ice_fill_phy_msg_e82x(&msg, port, offset); msg.opcode = ice_sbq_msg_wr; msg.data = val; @@ -519,7 +519,7 @@ ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) } /** - * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY + * ice_write_40b_phy_reg_e82x - Write a 40b value to the PHY * @hw: pointer to the HW struct * @port: port to write to * @low_addr: offset of the low register @@ -529,7 +529,7 @@ ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) * it up into two chunks, the lower 8 bits and the upper 32 bits. */ static int -ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) +ice_write_40b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) { u32 low, high; u16 high_addr; @@ -538,7 +538,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) /* Only operate on registers known to be split into a lower 8 bit * register and an upper 32 bit register. */ - if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) { + if (!ice_is_40b_phy_reg_e82x(low_addr, &high_addr)) { ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n", low_addr); return -EINVAL; @@ -547,14 +547,14 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) low = (u32)(val & P_REG_40B_LOW_M); high = (u32)(val >> P_REG_40B_HIGH_S); - err = ice_write_phy_reg_e822(hw, port, low_addr, low); + err = ice_write_phy_reg_e82x(hw, port, low_addr, low); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", low_addr, err); return err; } - err = ice_write_phy_reg_e822(hw, port, high_addr, high); + err = ice_write_phy_reg_e82x(hw, port, high_addr, high); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", high_addr, err); @@ -565,7 +565,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) } /** - * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers + * ice_write_64b_phy_reg_e82x - Write a 64bit value to PHY registers * @hw: pointer to the HW struct * @port: PHY port to read from * @low_addr: offset of the lower register to read from @@ -577,7 +577,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) * a 64bit value. */ static int -ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) +ice_write_64b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) { u32 low, high; u16 high_addr; @@ -586,7 +586,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) /* Only operate on registers known to be split into two 32bit * registers. */ - if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { + if (!ice_is_64b_phy_reg_e82x(low_addr, &high_addr)) { ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", low_addr); return -EINVAL; @@ -595,14 +595,14 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) low = lower_32_bits(val); high = upper_32_bits(val); - err = ice_write_phy_reg_e822(hw, port, low_addr, low); + err = ice_write_phy_reg_e82x(hw, port, low_addr, low); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", low_addr, err); return err; } - err = ice_write_phy_reg_e822(hw, port, high_addr, high); + err = ice_write_phy_reg_e82x(hw, port, high_addr, high); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", high_addr, err); @@ -613,7 +613,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) } /** - * ice_fill_quad_msg_e822 - Fill message data for quad register access + * ice_fill_quad_msg_e82x - Fill message data for quad register access * @msg: the PHY message buffer to fill in * @quad: the quad to access * @offset: the register offset @@ -622,7 +622,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) * multiple PHYs. */ static int -ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) +ice_fill_quad_msg_e82x(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) { u32 addr; @@ -631,7 +631,7 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) msg->dest_dev = rmn_0; - if ((quad % ICE_QUADS_PER_PHY_E822) == 0) + if ((quad % ICE_QUADS_PER_PHY_E82X) == 0) addr = Q_0_BASE + offset; else addr = Q_1_BASE + offset; @@ -643,7 +643,7 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) } /** - * ice_read_quad_reg_e822 - Read a PHY quad register + * ice_read_quad_reg_e82x - Read a PHY quad register * @hw: pointer to the HW struct * @quad: quad to read from * @offset: quad register offset to read @@ -653,12 +653,12 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) * shared between multiple PHYs. */ int -ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) +ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) { struct ice_sbq_msg_input msg = {0}; int err; - err = ice_fill_quad_msg_e822(&msg, quad, offset); + err = ice_fill_quad_msg_e82x(&msg, quad, offset); if (err) return err; @@ -677,7 +677,7 @@ ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) } /** - * ice_write_quad_reg_e822 - Write a PHY quad register + * ice_write_quad_reg_e82x - Write a PHY quad register * @hw: pointer to the HW struct * @quad: quad to write to * @offset: quad register offset to write @@ -687,12 +687,12 @@ ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) * shared between multiple PHYs. */ int -ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) +ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val) { struct ice_sbq_msg_input msg = {0}; int err; - err = ice_fill_quad_msg_e822(&msg, quad, offset); + err = ice_fill_quad_msg_e82x(&msg, quad, offset); if (err) return err; @@ -710,7 +710,7 @@ ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) } /** - * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block + * ice_read_phy_tstamp_e82x - Read a PHY timestamp out of the quad block * @hw: pointer to the HW struct * @quad: the quad to read from * @idx: the timestamp index to read @@ -721,7 +721,7 @@ ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) * family of devices. */ static int -ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) +ice_read_phy_tstamp_e82x(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) { u16 lo_addr, hi_addr; u32 lo, hi; @@ -730,14 +730,14 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); - err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo); + err = ice_read_quad_reg_e82x(hw, quad, lo_addr, &lo); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", err); return err; } - err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi); + err = ice_read_quad_reg_e82x(hw, quad, hi_addr, &hi); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", err); @@ -754,7 +754,7 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) } /** - * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block + * ice_clear_phy_tstamp_e82x - Clear a timestamp from the quad block * @hw: pointer to the HW struct * @quad: the quad to read from * @idx: the timestamp index to reset @@ -770,18 +770,18 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) * * To directly clear the contents of the timestamp block entirely, discarding * all timestamp data at once, software should instead use - * ice_ptp_reset_ts_memory_quad_e822(). + * ice_ptp_reset_ts_memory_quad_e82x(). * * This function should only be called on an idx whose bit is set according to * ice_get_phy_tx_tstamp_ready(). */ static int -ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx) +ice_clear_phy_tstamp_e82x(struct ice_hw *hw, u8 quad, u8 idx) { u64 unused_tstamp; int err; - err = ice_read_phy_tstamp_e822(hw, quad, idx, &unused_tstamp); + err = ice_read_phy_tstamp_e82x(hw, quad, idx, &unused_tstamp); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read the timestamp register for quad %u, idx %u, err %d\n", quad, idx, err); @@ -792,33 +792,33 @@ ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx) } /** - * ice_ptp_reset_ts_memory_quad_e822 - Clear all timestamps from the quad block + * ice_ptp_reset_ts_memory_quad_e82x - Clear all timestamps from the quad block * @hw: pointer to the HW struct * @quad: the quad to read from * * Clear all timestamps from the PHY quad block that is shared between the * internal PHYs on the E822 devices. */ -void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad) +void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad) { - ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M); - ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M); + ice_write_quad_reg_e82x(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M); + ice_write_quad_reg_e82x(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M); } /** - * ice_ptp_reset_ts_memory_e822 - Clear all timestamps from all quad blocks + * ice_ptp_reset_ts_memory_e82x - Clear all timestamps from all quad blocks * @hw: pointer to the HW struct */ -static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw) +static void ice_ptp_reset_ts_memory_e82x(struct ice_hw *hw) { unsigned int quad; for (quad = 0; quad < ICE_MAX_QUAD; quad++) - ice_ptp_reset_ts_memory_quad_e822(hw, quad); + ice_ptp_reset_ts_memory_quad_e82x(hw, quad); } /** - * ice_read_cgu_reg_e822 - Read a CGU register + * ice_read_cgu_reg_e82x - Read a CGU register * @hw: pointer to the HW struct * @addr: Register address to read * @val: storage for register value read @@ -827,7 +827,7 @@ static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw) * applicable to E822 devices. */ static int -ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) +ice_read_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 *val) { struct ice_sbq_msg_input cgu_msg; int err; @@ -850,7 +850,7 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) } /** - * ice_write_cgu_reg_e822 - Write a CGU register + * ice_write_cgu_reg_e82x - Write a CGU register * @hw: pointer to the HW struct * @addr: Register address to write * @val: value to write into the register @@ -859,7 +859,7 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) * applicable to E822 devices. */ static int -ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val) +ice_write_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 val) { struct ice_sbq_msg_input cgu_msg; int err; @@ -925,7 +925,7 @@ static const char *ice_clk_src_str(u8 clk_src) } /** - * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit + * ice_cfg_cgu_pll_e82x - Configure the Clock Generation Unit * @hw: pointer to the HW struct * @clk_freq: Clock frequency to program * @clk_src: Clock source to select (TIME_REF, or TCX0) @@ -934,7 +934,7 @@ static const char *ice_clk_src_str(u8 clk_src) * time reference, enabling the PLL which drives the PTP hardware clock. */ static int -ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, +ice_cfg_cgu_pll_e82x(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, enum ice_clk_src clk_src) { union tspll_ro_bwm_lf bwm_lf; @@ -963,15 +963,15 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, return -EINVAL; } - err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); if (err) return err; - err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); if (err) return err; - err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); if (err) return err; @@ -986,43 +986,43 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, if (dw24.field.ts_pll_enable) { dw24.field.ts_pll_enable = 0; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (err) return err; } /* Set the frequency */ dw9.field.time_ref_freq_sel = clk_freq; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); if (err) return err; /* Configure the TS PLL feedback divisor */ - err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val); if (err) return err; dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; dw19.field.tspll_ndivratio = 1; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val); if (err) return err; /* Configure the TS PLL post divisor */ - err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val); if (err) return err; dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; dw22.field.time1588clk_sel_div2 = 0; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val); if (err) return err; /* Configure the TS PLL pre divisor and clock source */ - err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); if (err) return err; @@ -1030,21 +1030,21 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; dw24.field.time_ref_sel = clk_src; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (err) return err; /* Finally, enable the PLL */ dw24.field.ts_pll_enable = 1; - err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (err) return err; /* Wait to verify if the PLL locks */ usleep_range(1000, 5000); - err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); if (err) return err; @@ -1064,18 +1064,18 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, } /** - * ice_init_cgu_e822 - Initialize CGU with settings from firmware + * ice_init_cgu_e82x - Initialize CGU with settings from firmware * @hw: pointer to the HW structure * * Initialize the Clock Generation Unit of the E822 device. */ -static int ice_init_cgu_e822(struct ice_hw *hw) +static int ice_init_cgu_e82x(struct ice_hw *hw) { struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; union tspll_cntr_bist_settings cntr_bist; int err; - err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, + err = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, &cntr_bist.val); if (err) return err; @@ -1084,7 +1084,7 @@ static int ice_init_cgu_e822(struct ice_hw *hw) cntr_bist.field.i_plllock_sel_0 = 0; cntr_bist.field.i_plllock_sel_1 = 0; - err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, + err = ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, cntr_bist.val); if (err) return err; @@ -1092,7 +1092,7 @@ static int ice_init_cgu_e822(struct ice_hw *hw) /* Configure the CGU PLL using the parameters from the function * capabilities. */ - err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, + err = ice_cfg_cgu_pll_e82x(hw, ts_info->time_ref, (enum ice_clk_src)ts_info->clk_src); if (err) return err; @@ -1113,7 +1113,7 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw) for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { int err; - err = ice_write_phy_reg_e822(hw, port, P_REG_WL, + err = ice_write_phy_reg_e82x(hw, port, P_REG_WL, PTP_VERNIER_WL); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n", @@ -1126,12 +1126,12 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw) } /** - * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization + * ice_ptp_init_phc_e82x - Perform E822 specific PHC initialization * @hw: pointer to HW struct * * Perform PHC initialization steps specific to E822 devices. */ -static int ice_ptp_init_phc_e822(struct ice_hw *hw) +static int ice_ptp_init_phc_e82x(struct ice_hw *hw) { int err; u32 regval; @@ -1145,7 +1145,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw) wr32(hw, PF_SB_REM_DEV_CTL, regval); /* Initialize the Clock Generation Unit */ - err = ice_init_cgu_e822(hw); + err = ice_init_cgu_e82x(hw); if (err) return err; @@ -1154,7 +1154,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw) } /** - * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time + * ice_ptp_prep_phy_time_e82x - Prepare PHY port with initial time * @hw: pointer to the HW struct * @time: Time to initialize the PHY port clocks to * @@ -1164,7 +1164,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw) * units of nominal nanoseconds. */ static int -ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) +ice_ptp_prep_phy_time_e82x(struct ice_hw *hw, u32 time) { u64 phy_time; u8 port; @@ -1177,14 +1177,14 @@ ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { /* Tx case */ - err = ice_write_64b_phy_reg_e822(hw, port, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_TX_TIMER_INC_PRE_L, phy_time); if (err) goto exit_err; /* Rx case */ - err = ice_write_64b_phy_reg_e822(hw, port, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_RX_TIMER_INC_PRE_L, phy_time); if (err) @@ -1201,7 +1201,7 @@ ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) } /** - * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust + * ice_ptp_prep_port_adj_e82x - Prepare a single port for time adjust * @hw: pointer to HW struct * @port: Port number to be programmed * @time: time in cycles to adjust the port Tx and Rx clocks @@ -1216,7 +1216,7 @@ ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) * Negative adjustments are supported using 2s complement arithmetic. */ static int -ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) +ice_ptp_prep_port_adj_e82x(struct ice_hw *hw, u8 port, s64 time) { u32 l_time, u_time; int err; @@ -1225,23 +1225,23 @@ ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) u_time = upper_32_bits(time); /* Tx case */ - err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L, + err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TIMER_INC_PRE_L, l_time); if (err) goto exit_err; - err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U, + err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TIMER_INC_PRE_U, u_time); if (err) goto exit_err; /* Rx case */ - err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L, + err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TIMER_INC_PRE_L, l_time); if (err) goto exit_err; - err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U, + err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TIMER_INC_PRE_U, u_time); if (err) goto exit_err; @@ -1255,7 +1255,7 @@ ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) } /** - * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment + * ice_ptp_prep_phy_adj_e82x - Prep PHY ports for a time adjustment * @hw: pointer to HW struct * @adj: adjustment in nanoseconds * @@ -1264,7 +1264,7 @@ ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) * ICE_PTP_ADJ_TIME or ICE_PTP_ADJ_TIME_AT_TIME sync command. */ static int -ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) +ice_ptp_prep_phy_adj_e82x(struct ice_hw *hw, s32 adj) { s64 cycles; u8 port; @@ -1281,7 +1281,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { int err; - err = ice_ptp_prep_port_adj_e822(hw, port, cycles); + err = ice_ptp_prep_port_adj_e82x(hw, port, cycles); if (err) return err; } @@ -1290,7 +1290,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) } /** - * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment + * ice_ptp_prep_phy_incval_e82x - Prepare PHY ports for time adjustment * @hw: pointer to HW struct * @incval: new increment value to prepare * @@ -1299,13 +1299,13 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) * issuing an ICE_PTP_INIT_INCVAL command. */ static int -ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) +ice_ptp_prep_phy_incval_e82x(struct ice_hw *hw, u64 incval) { int err; u8 port; for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_TIMETUS_L, incval); if (err) goto exit_err; @@ -1337,7 +1337,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) int err; /* Tx case */ - err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts); + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_TX_CAPTURE_L, tx_ts); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n", err); @@ -1348,7 +1348,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) (unsigned long long)*tx_ts); /* Rx case */ - err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts); + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_RX_CAPTURE_L, rx_ts); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n", err); @@ -1362,7 +1362,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) } /** - * ice_ptp_write_port_cmd_e822 - Prepare a single PHY port for a timer command + * ice_ptp_write_port_cmd_e82x - Prepare a single PHY port for a timer command * @hw: pointer to HW struct * @port: Port to which cmd has to be sent * @cmd: Command to be sent to the port @@ -1372,8 +1372,8 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) * Do not use this function directly. If you want to configure exactly one * port, use ice_ptp_one_port_cmd() instead. */ -static int -ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) +static int ice_ptp_write_port_cmd_e82x(struct ice_hw *hw, u8 port, + enum ice_ptp_tmr_cmd cmd) { u32 cmd_val, val; u8 tmr_idx; @@ -1403,7 +1403,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd /* Tx case */ /* Read, modify, write */ - err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val); + err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_TMR_CMD, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n", err); @@ -1414,7 +1414,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd val &= ~TS_CMD_MASK; val |= cmd_val; - err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TMR_CMD, val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n", err); @@ -1423,7 +1423,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd /* Rx case */ /* Read, modify, write */ - err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val); + err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_TMR_CMD, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n", err); @@ -1434,7 +1434,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd val &= ~TS_CMD_MASK; val |= cmd_val; - err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TMR_CMD, val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n", err); @@ -1469,7 +1469,7 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, else cmd = ICE_PTP_NOP; - err = ice_ptp_write_port_cmd_e822(hw, port, cmd); + err = ice_ptp_write_port_cmd_e82x(hw, port, cmd); if (err) return err; } @@ -1478,7 +1478,7 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, } /** - * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command + * ice_ptp_port_cmd_e82x - Prepare all ports for a timer command * @hw: pointer to the HW struct * @cmd: timer command to prepare * @@ -1486,14 +1486,14 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, * command. */ static int -ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) +ice_ptp_port_cmd_e82x(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) { u8 port; for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { int err; - err = ice_ptp_write_port_cmd_e822(hw, port, cmd); + err = ice_ptp_write_port_cmd_e82x(hw, port, cmd); if (err) return err; } @@ -1509,7 +1509,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) */ /** - * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode + * ice_phy_get_speed_and_fec_e82x - Get link speed and FEC based on serdes mode * @hw: pointer to HW struct * @port: the port to read from * @link_out: if non-NULL, holds link speed on success @@ -1519,7 +1519,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) * algorithm. */ static int -ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, +ice_phy_get_speed_and_fec_e82x(struct ice_hw *hw, u8 port, enum ice_ptp_link_spd *link_out, enum ice_ptp_fec_mode *fec_out) { @@ -1528,7 +1528,7 @@ ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, u32 serdes; int err; - err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes); + err = ice_read_phy_reg_e82x(hw, port, P_REG_LINK_SPEED, &serdes); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n"); return err; @@ -1585,18 +1585,18 @@ ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, } /** - * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp + * ice_phy_cfg_lane_e82x - Configure PHY quad for single/multi-lane timestamp * @hw: pointer to HW struct * @port: to configure the quad for */ -static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) +static void ice_phy_cfg_lane_e82x(struct ice_hw *hw, u8 port) { enum ice_ptp_link_spd link_spd; int err; u32 val; u8 quad; - err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL); + err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, NULL); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n", err); @@ -1605,7 +1605,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) quad = port / ICE_PORTS_PER_QUAD; - err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n", err); @@ -1617,7 +1617,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) else val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; - err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); + err = ice_write_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n", err); @@ -1626,7 +1626,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) } /** - * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822 + * ice_phy_cfg_uix_e82x - Configure Serdes UI to TU conversion for E822 * @hw: pointer to the HW structure * @port: the port to configure * @@ -1671,12 +1671,12 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) * a divide by 390,625,000. This does lose some precision, but avoids * miscalculation due to arithmetic overflow. */ -static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) +static int ice_phy_cfg_uix_e82x(struct ice_hw *hw, u8 port) { u64 cur_freq, clk_incval, tu_per_sec, uix; int err; - cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); + cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw)); clk_incval = ice_ptp_read_src_incval(hw); /* Calculate TUs per second divided by 256 */ @@ -1688,7 +1688,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) /* Program the 10Gb/40Gb conversion ratio */ uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000); - err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_UIX66_10G_40G_L, uix); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n", @@ -1699,7 +1699,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) /* Program the 25Gb/100Gb conversion ratio */ uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000); - err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_UIX66_25G_100G_L, uix); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n", @@ -1711,7 +1711,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) } /** - * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle + * ice_phy_cfg_parpcs_e82x - Configure TUs per PAR/PCS clock cycle * @hw: pointer to the HW struct * @port: port to configure * @@ -1753,18 +1753,18 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) * frequency is ~29 bits, so multiplying them together should fit within the * 64 bit arithmetic. */ -static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) +static int ice_phy_cfg_parpcs_e82x(struct ice_hw *hw, u8 port) { u64 cur_freq, clk_incval, tu_per_sec, phy_tus; enum ice_ptp_link_spd link_spd; enum ice_ptp_fec_mode fec_mode; int err; - err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); + err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode); if (err) return err; - cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); + cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw)); clk_incval = ice_ptp_read_src_incval(hw); /* Calculate TUs per cycle of the PHC clock */ @@ -1784,7 +1784,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PAR_TX_TUS_L, phy_tus); if (err) return err; @@ -1796,7 +1796,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PAR_RX_TUS_L, phy_tus); if (err) return err; @@ -1808,7 +1808,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PCS_TX_TUS_L, phy_tus); if (err) return err; @@ -1820,7 +1820,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PCS_RX_TUS_L, phy_tus); if (err) return err; @@ -1832,7 +1832,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PAR_TX_TUS_L, phy_tus); if (err) return err; @@ -1844,7 +1844,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PAR_RX_TUS_L, phy_tus); if (err) return err; @@ -1856,7 +1856,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L, + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PCS_TX_TUS_L, phy_tus); if (err) return err; @@ -1868,23 +1868,23 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) else phy_tus = 0; - return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L, + return ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PCS_RX_TUS_L, phy_tus); } /** - * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port + * ice_calc_fixed_tx_offset_e82x - Calculated Fixed Tx offset for a port * @hw: pointer to the HW struct * @link_spd: the Link speed to calculate for * * Calculate the fixed offset due to known static latency data. */ static u64 -ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) +ice_calc_fixed_tx_offset_e82x(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) { u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; - cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); + cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw)); clk_incval = ice_ptp_read_src_incval(hw); /* Calculate TUs per second */ @@ -1904,7 +1904,7 @@ ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) } /** - * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset + * ice_phy_cfg_tx_offset_e82x - Configure total Tx timestamp offset * @hw: pointer to the HW struct * @port: the PHY port to configure * @@ -1926,7 +1926,7 @@ ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) * Returns zero on success, -EBUSY if the hardware vernier offset * calibration has not completed, or another error code on failure. */ -int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) +int ice_phy_cfg_tx_offset_e82x(struct ice_hw *hw, u8 port) { enum ice_ptp_link_spd link_spd; enum ice_ptp_fec_mode fec_mode; @@ -1935,7 +1935,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) u32 reg; /* Nothing to do if we've already programmed the offset */ - err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OR, ®); + err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_OR, ®); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OR for port %u, err %d\n", port, err); @@ -1945,7 +1945,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) if (reg) return 0; - err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, ®); + err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_OV_STATUS, ®); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", port, err); @@ -1955,11 +1955,11 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) if (!(reg & P_REG_TX_OV_STATUS_OV_M)) return -EBUSY; - err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); + err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode); if (err) return err; - total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); + total_offset = ice_calc_fixed_tx_offset_e82x(hw, link_spd); /* Read the first Vernier offset from the PHY register and add it to * the total offset. @@ -1970,7 +1970,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) link_spd == ICE_PTP_LNK_SPD_25G_RS || link_spd == ICE_PTP_LNK_SPD_40G || link_spd == ICE_PTP_LNK_SPD_50G) { - err = ice_read_64b_phy_reg_e822(hw, port, + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_PAR_PCS_TX_OFFSET_L, &val); if (err) @@ -1985,7 +1985,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) */ if (link_spd == ICE_PTP_LNK_SPD_50G_RS || link_spd == ICE_PTP_LNK_SPD_100G_RS) { - err = ice_read_64b_phy_reg_e822(hw, port, + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_PAR_TX_TIME_L, &val); if (err) @@ -1998,12 +1998,12 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) * PHY and indicate that the Tx offset is ready. After this, * timestamps will be enabled. */ - err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_TOTAL_TX_OFFSET_L, total_offset); if (err) return err; - err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); + err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_OR, 1); if (err) return err; @@ -2014,7 +2014,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) } /** - * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx + * ice_phy_calc_pmd_adj_e82x - Calculate PMD adjustment for Rx * @hw: pointer to the HW struct * @port: the PHY port to adjust for * @link_spd: the current link speed of the PHY @@ -2026,7 +2026,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) * various delays caused when receiving a packet. */ static int -ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, +ice_phy_calc_pmd_adj_e82x(struct ice_hw *hw, u8 port, enum ice_ptp_link_spd link_spd, enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) { @@ -2035,7 +2035,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, u32 val; int err; - err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); + err = ice_read_phy_reg_e82x(hw, port, P_REG_PMD_ALIGNMENT, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", err); @@ -2044,7 +2044,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, pmd_align = (u8)val; - cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); + cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw)); clk_incval = ice_ptp_read_src_incval(hw); /* Calculate TUs per second */ @@ -2123,7 +2123,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, u64 cycle_adj; u8 rx_cycle; - err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, + err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_40_TO_160_CNT, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", @@ -2145,7 +2145,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, u64 cycle_adj; u8 rx_cycle; - err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, + err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_80_TO_160_CNT, &val); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", @@ -2172,18 +2172,18 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, } /** - * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port + * ice_calc_fixed_rx_offset_e82x - Calculated the fixed Rx offset for a port * @hw: pointer to HW struct * @link_spd: The Link speed to calculate for * * Determine the fixed Rx latency for a given link speed. */ static u64 -ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) +ice_calc_fixed_rx_offset_e82x(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) { u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; - cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); + cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw)); clk_incval = ice_ptp_read_src_incval(hw); /* Calculate TUs per second */ @@ -2203,7 +2203,7 @@ ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) } /** - * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset + * ice_phy_cfg_rx_offset_e82x - Configure total Rx timestamp offset * @hw: pointer to the HW struct * @port: the PHY port to configure * @@ -2229,7 +2229,7 @@ ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) * Returns zero on success, -EBUSY if the hardware vernier offset * calibration has not completed, or another error code on failure. */ -int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) +int ice_phy_cfg_rx_offset_e82x(struct ice_hw *hw, u8 port) { enum ice_ptp_link_spd link_spd; enum ice_ptp_fec_mode fec_mode; @@ -2238,7 +2238,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) u32 reg; /* Nothing to do if we've already programmed the offset */ - err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OR, ®); + err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_OR, ®); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OR for port %u, err %d\n", port, err); @@ -2248,7 +2248,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) if (reg) return 0; - err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, ®); + err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_OV_STATUS, ®); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", port, err); @@ -2258,16 +2258,16 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) if (!(reg & P_REG_RX_OV_STATUS_OV_M)) return -EBUSY; - err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); + err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode); if (err) return err; - total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); + total_offset = ice_calc_fixed_rx_offset_e82x(hw, link_spd); /* Read the first Vernier offset from the PHY register and add it to * the total offset. */ - err = ice_read_64b_phy_reg_e822(hw, port, + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_PAR_PCS_RX_OFFSET_L, &val); if (err) @@ -2282,7 +2282,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) link_spd == ICE_PTP_LNK_SPD_50G || link_spd == ICE_PTP_LNK_SPD_50G_RS || link_spd == ICE_PTP_LNK_SPD_100G_RS) { - err = ice_read_64b_phy_reg_e822(hw, port, + err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_PAR_RX_TIME_L, &val); if (err) @@ -2292,7 +2292,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) } /* In addition, Rx must account for the PMD alignment */ - err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); + err = ice_phy_calc_pmd_adj_e82x(hw, port, link_spd, fec_mode, &pmd); if (err) return err; @@ -2308,12 +2308,12 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) * PHY and indicate that the Rx offset is ready. After this, * timestamps will be enabled. */ - err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, + err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_TOTAL_RX_OFFSET_L, total_offset); if (err) return err; - err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); + err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_OR, 1); if (err) return err; @@ -2324,7 +2324,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) } /** - * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time + * ice_read_phy_and_phc_time_e82x - Simultaneously capture PHC and PHY time * @hw: pointer to the HW struct * @port: the PHY port to read * @phy_time: on return, the 64bit PHY timer value @@ -2334,7 +2334,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) * and PHC timer values. */ static int -ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, +ice_read_phy_and_phc_time_e82x(struct ice_hw *hw, u8 port, u64 *phy_time, u64 *phc_time) { u64 tx_time, rx_time; @@ -2381,7 +2381,7 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, } /** - * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer + * ice_sync_phy_timer_e82x - Synchronize the PHY timer with PHC timer * @hw: pointer to the HW struct * @port: the PHY port to synchronize * @@ -2392,7 +2392,7 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, * to the PHY timer in order to ensure it reads the same value as the * primary PHC timer. */ -static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) +static int ice_sync_phy_timer_e82x(struct ice_hw *hw, u8 port) { u64 phc_time, phy_time, difference; int err; @@ -2402,7 +2402,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) return -EBUSY; } - err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); + err = ice_read_phy_and_phc_time_e82x(hw, port, &phy_time, &phc_time); if (err) goto err_unlock; @@ -2416,7 +2416,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) */ difference = phc_time - phy_time; - err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); + err = ice_ptp_prep_port_adj_e82x(hw, port, (s64)difference); if (err) goto err_unlock; @@ -2433,7 +2433,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) /* Re-capture the timer values to flush the command registers and * verify that the time was properly adjusted. */ - err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); + err = ice_read_phy_and_phc_time_e82x(hw, port, &phy_time, &phc_time); if (err) goto err_unlock; @@ -2452,7 +2452,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) } /** - * ice_stop_phy_timer_e822 - Stop the PHY clock timer + * ice_stop_phy_timer_e82x - Stop the PHY clock timer * @hw: pointer to the HW struct * @port: the PHY port to stop * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS @@ -2462,36 +2462,36 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) * initialized or when link speed changes. */ int -ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) +ice_stop_phy_timer_e82x(struct ice_hw *hw, u8 port, bool soft_reset) { int err; u32 val; - err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); + err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_OR, 0); if (err) return err; - err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); + err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_OR, 0); if (err) return err; - err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); + err = ice_read_phy_reg_e82x(hw, port, P_REG_PS, &val); if (err) return err; val &= ~P_REG_PS_START_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; val &= ~P_REG_PS_ENA_CLK_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; if (soft_reset) { val |= P_REG_PS_SFT_RESET_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; } @@ -2502,7 +2502,7 @@ ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) } /** - * ice_start_phy_timer_e822 - Start the PHY clock timer + * ice_start_phy_timer_e82x - Start the PHY clock timer * @hw: pointer to the HW struct * @port: the PHY port to start * @@ -2512,7 +2512,7 @@ ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) * * Hardware will take Vernier measurements on Tx or Rx of packets. */ -int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) +int ice_start_phy_timer_e82x(struct ice_hw *hw, u8 port) { u32 lo, hi, val; u64 incval; @@ -2521,17 +2521,17 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) tmr_idx = ice_get_ptp_src_clock_index(hw); - err = ice_stop_phy_timer_e822(hw, port, false); + err = ice_stop_phy_timer_e82x(hw, port, false); if (err) return err; - ice_phy_cfg_lane_e822(hw, port); + ice_phy_cfg_lane_e82x(hw, port); - err = ice_phy_cfg_uix_e822(hw, port); + err = ice_phy_cfg_uix_e82x(hw, port); if (err) return err; - err = ice_phy_cfg_parpcs_e822(hw, port); + err = ice_phy_cfg_parpcs_e82x(hw, port); if (err) return err; @@ -2539,7 +2539,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); incval = (u64)hi << 32 | lo; - err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); + err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_TIMETUS_L, incval); if (err) return err; @@ -2552,22 +2552,22 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) ice_ptp_exec_tmr_cmd(hw); - err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); + err = ice_read_phy_reg_e82x(hw, port, P_REG_PS, &val); if (err) return err; val |= P_REG_PS_SFT_RESET_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; val |= P_REG_PS_START_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; val &= ~P_REG_PS_SFT_RESET_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; @@ -2578,18 +2578,18 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) ice_ptp_exec_tmr_cmd(hw); val |= P_REG_PS_ENA_CLK_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; val |= P_REG_PS_LOAD_OFFSET_M; - err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); + err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val); if (err) return err; ice_ptp_exec_tmr_cmd(hw); - err = ice_sync_phy_timer_e822(hw, port); + err = ice_sync_phy_timer_e82x(hw, port); if (err) return err; @@ -2599,7 +2599,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) } /** - * ice_get_phy_tx_tstamp_ready_e822 - Read Tx memory status register + * ice_get_phy_tx_tstamp_ready_e82x - Read Tx memory status register * @hw: pointer to the HW struct * @quad: the timestamp quad to read from * @tstamp_ready: contents of the Tx memory status register @@ -2609,19 +2609,19 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) * ready to be captured from the PHY timestamp block. */ static int -ice_get_phy_tx_tstamp_ready_e822(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) +ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) { u32 hi, lo; int err; - err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi); + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_U for quad %u, err %d\n", quad, err); return err; } - err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo); + err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_L for quad %u, err %d\n", quad, err); @@ -3307,7 +3307,7 @@ void ice_ptp_init_phy_model(struct ice_hw *hw) if (ice_is_e810(hw)) hw->phy_model = ICE_PHY_E810; else - hw->phy_model = ICE_PHY_E822; + hw->phy_model = ICE_PHY_E82X; } /** @@ -3332,8 +3332,8 @@ static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) case ICE_PHY_E810: err = ice_ptp_port_cmd_e810(hw, cmd); break; - case ICE_PHY_E822: - err = ice_ptp_port_cmd_e822(hw, cmd); + case ICE_PHY_E82X: + err = ice_ptp_port_cmd_e82x(hw, cmd); break; default: err = -EOPNOTSUPP; @@ -3384,8 +3384,8 @@ int ice_ptp_init_time(struct ice_hw *hw, u64 time) case ICE_PHY_E810: err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); break; - case ICE_PHY_E822: - err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); + case ICE_PHY_E82X: + err = ice_ptp_prep_phy_time_e82x(hw, time & 0xFFFFFFFF); break; default: err = -EOPNOTSUPP; @@ -3426,8 +3426,8 @@ int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) case ICE_PHY_E810: err = ice_ptp_prep_phy_incval_e810(hw, incval); break; - case ICE_PHY_E822: - err = ice_ptp_prep_phy_incval_e822(hw, incval); + case ICE_PHY_E82X: + err = ice_ptp_prep_phy_incval_e82x(hw, incval); break; default: err = -EOPNOTSUPP; @@ -3492,8 +3492,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) case ICE_PHY_E810: err = ice_ptp_prep_phy_adj_e810(hw, adj); break; - case ICE_PHY_E822: - err = ice_ptp_prep_phy_adj_e822(hw, adj); + case ICE_PHY_E82X: + err = ice_ptp_prep_phy_adj_e82x(hw, adj); break; default: err = -EOPNOTSUPP; @@ -3521,8 +3521,8 @@ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) switch (hw->phy_model) { case ICE_PHY_E810: return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); - case ICE_PHY_E822: - return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); + case ICE_PHY_E82X: + return ice_read_phy_tstamp_e82x(hw, block, idx, tstamp); default: return -EOPNOTSUPP; } @@ -3549,8 +3549,8 @@ int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) switch (hw->phy_model) { case ICE_PHY_E810: return ice_clear_phy_tstamp_e810(hw, block, idx); - case ICE_PHY_E822: - return ice_clear_phy_tstamp_e822(hw, block, idx); + case ICE_PHY_E82X: + return ice_clear_phy_tstamp_e82x(hw, block, idx); default: return -EOPNOTSUPP; } @@ -3608,8 +3608,8 @@ static int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx) void ice_ptp_reset_ts_memory(struct ice_hw *hw) { switch (hw->phy_model) { - case ICE_PHY_E822: - ice_ptp_reset_ts_memory_e822(hw); + case ICE_PHY_E82X: + ice_ptp_reset_ts_memory_e82x(hw); break; case ICE_PHY_E810: default: @@ -3636,8 +3636,8 @@ int ice_ptp_init_phc(struct ice_hw *hw) switch (hw->phy_model) { case ICE_PHY_E810: return ice_ptp_init_phc_e810(hw); - case ICE_PHY_E822: - return ice_ptp_init_phc_e822(hw); + case ICE_PHY_E82X: + return ice_ptp_init_phc_e82x(hw); default: return -EOPNOTSUPP; } @@ -3660,8 +3660,8 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) case ICE_PHY_E810: return ice_get_phy_tx_tstamp_ready_e810(hw, block, tstamp_ready); - case ICE_PHY_E822: - return ice_get_phy_tx_tstamp_ready_e822(hw, block, + case ICE_PHY_E82X: + return ice_get_phy_tx_tstamp_ready_e82x(hw, block, tstamp_ready); break; default: @@ -3942,7 +3942,7 @@ int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num) case ICE_DEV_ID_E823C_QSFP: case ICE_DEV_ID_E823C_SFP: case ICE_DEV_ID_E823C_SGMII: - *pin_num = ICE_E822_RCLK_PINS_NUM; + *pin_num = ICE_E82X_RCLK_PINS_NUM; ret = 0; if (hw->cgu_part_number == ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index cf76701566c7..e976138e934a 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -42,7 +42,7 @@ enum ice_ptp_fec_mode { }; /** - * struct ice_time_ref_info_e822 + * struct ice_time_ref_info_e82x * @pll_freq: Frequency of PLL that drives timer ticks in Hz * @nominal_incval: increment to generate nanoseconds in GLTSYN_TIME_L * @pps_delay: propagation delay of the PPS output signal @@ -50,14 +50,14 @@ enum ice_ptp_fec_mode { * Characteristic information for the various TIME_REF sources possible in the * E822 devices */ -struct ice_time_ref_info_e822 { +struct ice_time_ref_info_e82x { u64 pll_freq; u64 nominal_incval; u8 pps_delay; }; /** - * struct ice_vernier_info_e822 + * struct ice_vernier_info_e82x * @tx_par_clk: Frequency used to calculate P_REG_PAR_TX_TUS * @rx_par_clk: Frequency used to calculate P_REG_PAR_RX_TUS * @tx_pcs_clk: Frequency used to calculate P_REG_PCS_TX_TUS @@ -80,7 +80,7 @@ struct ice_time_ref_info_e822 { * different link speeds, either the deskew marker for multi-lane link speeds * or the Reed Solomon gearbox marker for RS-FEC. */ -struct ice_vernier_info_e822 { +struct ice_vernier_info_e82x { u32 tx_par_clk; u32 rx_par_clk; u32 tx_pcs_clk; @@ -95,7 +95,7 @@ struct ice_vernier_info_e822 { }; /** - * struct ice_cgu_pll_params_e822 + * struct ice_cgu_pll_params_e82x * @refclk_pre_div: Reference clock pre-divisor * @feedback_div: Feedback divisor * @frac_n_div: Fractional divisor @@ -104,7 +104,7 @@ struct ice_vernier_info_e822 { * Clock Generation Unit parameters used to program the PLL based on the * selected TIME_REF frequency. */ -struct ice_cgu_pll_params_e822 { +struct ice_cgu_pll_params_e82x { u32 refclk_pre_div; u32 feedback_div; u32 frac_n_div; @@ -124,7 +124,7 @@ enum ice_phy_rclk_pins { }; #define ICE_E810_RCLK_PINS_NUM (ICE_RCLKB_PIN + 1) -#define ICE_E822_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1) +#define ICE_E82X_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1) #define E810T_CGU_INPUT_C827(_phy, _pin) ((_phy) * ICE_E810_RCLK_PINS_NUM + \ (_pin) + ZL_REF1P) @@ -183,16 +183,16 @@ struct ice_cgu_pin_desc { }; extern const struct -ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ]; +ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ]; #define E810C_QSFP_C827_0_HANDLE 2 #define E810C_QSFP_C827_1_HANDLE 3 /* Table of constants related to possible TIME_REF sources */ -extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ]; +extern const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ]; /* Table of constants for Vernier calibration on E822 */ -extern const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD]; +extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; /* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for * the E810 devices. Based off of a PLL with an 812.5 MHz frequency. @@ -215,23 +215,23 @@ int ice_ptp_init_phc(struct ice_hw *hw); int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); /* E822 family functions */ -int ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val); -int ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val); -void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad); +int ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val); +int ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val); +void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad); /** - * ice_e822_time_ref - Get the current TIME_REF from capabilities + * ice_e82x_time_ref - Get the current TIME_REF from capabilities * @hw: pointer to the HW structure * * Returns the current TIME_REF from the capabilities structure. */ -static inline enum ice_time_ref_freq ice_e822_time_ref(struct ice_hw *hw) +static inline enum ice_time_ref_freq ice_e82x_time_ref(struct ice_hw *hw) { return hw->func_caps.ts_func_info.time_ref; } /** - * ice_set_e822_time_ref - Set new TIME_REF + * ice_set_e82x_time_ref - Set new TIME_REF * @hw: pointer to the HW structure * @time_ref: new TIME_REF to set * @@ -239,31 +239,31 @@ static inline enum ice_time_ref_freq ice_e822_time_ref(struct ice_hw *hw) * change, such as an update to the CGU registers. */ static inline void -ice_set_e822_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref) +ice_set_e82x_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref) { hw->func_caps.ts_func_info.time_ref = time_ref; } -static inline u64 ice_e822_pll_freq(enum ice_time_ref_freq time_ref) +static inline u64 ice_e82x_pll_freq(enum ice_time_ref_freq time_ref) { return e822_time_ref[time_ref].pll_freq; } -static inline u64 ice_e822_nominal_incval(enum ice_time_ref_freq time_ref) +static inline u64 ice_e82x_nominal_incval(enum ice_time_ref_freq time_ref) { return e822_time_ref[time_ref].nominal_incval; } -static inline u64 ice_e822_pps_delay(enum ice_time_ref_freq time_ref) +static inline u64 ice_e82x_pps_delay(enum ice_time_ref_freq time_ref) { return e822_time_ref[time_ref].pps_delay; } /* E822 Vernier calibration functions */ -int ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset); -int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port); -int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port); -int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port); +int ice_stop_phy_timer_e82x(struct ice_hw *hw, u8 port, bool soft_reset); +int ice_start_phy_timer_e82x(struct ice_hw *hw, u8 port); +int ice_phy_cfg_tx_offset_e82x(struct ice_hw *hw, u8 port); +int ice_phy_cfg_rx_offset_e82x(struct ice_hw *hw, u8 port); /* E810 family functions */ int ice_ptp_init_phy_e810(struct ice_hw *hw); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 5a80158e49ed..2be3955e249e 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -834,7 +834,7 @@ struct ice_mbx_data { enum ice_phy_model { ICE_PHY_UNSUP = -1, ICE_PHY_E810 = 1, - ICE_PHY_E822, + ICE_PHY_E82X, }; /* Port hardware description */ @@ -917,10 +917,9 @@ struct ice_hw { /* INTRL granularity in 1 us */ u8 intrl_gran; -#define ICE_PHY_PER_NAC_E822 1 #define ICE_MAX_QUAD 2 -#define ICE_QUADS_PER_PHY_E822 2 -#define ICE_PORTS_PER_PHY_E822 8 +#define ICE_QUADS_PER_PHY_E82X 2 +#define ICE_PORTS_PER_PHY_E82X 8 #define ICE_PORTS_PER_QUAD 4 #define ICE_PORTS_PER_PHY_E810 4 #define ICE_NUM_EXTERNAL_PORTS (ICE_MAX_QUAD * ICE_PORTS_PER_QUAD) From c50a291d621aa7abaa27b05f56d450a388b64948 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 4 Dec 2023 16:14:06 +0100 Subject: [PATCH 2557/7721] drm/gpuvm: Let drm_gpuvm_bo_put() report when the vm_bo object is destroyed Some users need to release resources attached to the vm_bo object when it's destroyed. In Panthor's case, we need to release the pin ref so BO pages can be returned to the system when all GPU mappings are gone. This could be done through a custom drm_gpuvm::vm_bo_free() hook, but this has all sort of locking implications that would force us to expose a drm_gem_shmem_unpin_locked() helper, not to mention the fact that having a ::vm_bo_free() implementation without a ::vm_bo_alloc() one seems odd. So let's keep things simple, and extend drm_gpuvm_bo_put() to report when the object is destroyed. Signed-off-by: Boris Brezillon Reviewed-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20231204151406.1977285-1-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_gpuvm.c | 8 ++++++-- include/drm/drm_gpuvm.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 07a6676bc4f9..9c0922c1a5a2 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1535,14 +1535,18 @@ drm_gpuvm_bo_destroy(struct kref *kref) * hold the dma-resv or driver specific GEM gpuva lock. * * This function may only be called from non-atomic context. + * + * Returns: true if vm_bo was destroyed, false otherwise. */ -void +bool drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo) { might_sleep(); if (vm_bo) - kref_put(&vm_bo->kref, drm_gpuvm_bo_destroy); + return !!kref_put(&vm_bo->kref, drm_gpuvm_bo_destroy); + + return false; } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put); diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index b3f82ec7fb17..6258849382e1 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -721,7 +721,7 @@ drm_gpuvm_bo_get(struct drm_gpuvm_bo *vm_bo) return vm_bo; } -void drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo); +bool drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo); struct drm_gpuvm_bo * drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, From c8fa1cc07759dde17c97796f41696a0da35c6ea7 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 03:05:28 +0300 Subject: [PATCH 2558/7721] drm/atomic: add private obj state to state dump The drm_atomic_print_new_state() already prints private object state via drm_atomic_private_obj_print_state(). Add private object state dumping to __drm_state_dump(), so that it is also included into drm_state_dump() output and into debugfs/dri/N/state file. Reviewed-by: Rob Clark Acked-by: Maxime Ripard Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231203000532.1290480-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f1a503aafe5a..c31fc0b48c31 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1773,6 +1773,7 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, struct drm_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; + struct drm_private_obj *obj; if (!drm_drv_uses_atomic_modeset(dev)) return; @@ -1801,6 +1802,14 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, if (take_locks) drm_modeset_unlock(&dev->mode_config.connection_mutex); drm_connector_list_iter_end(&conn_iter); + + list_for_each_entry(obj, &config->privobj_list, head) { + if (take_locks) + drm_modeset_lock(&obj->lock, NULL); + drm_atomic_private_obj_print_state(p, obj->state); + if (take_locks) + drm_modeset_unlock(&obj->lock); + } } /** From 25ae948b447881bf689d459cd5bd4629d9c04b20 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:00:57 +0800 Subject: [PATCH 2559/7721] selftests/net: add lib.sh Add a lib.sh for net selftests. This file can be used to define commonly used variables and functions. Some commonly used functions can be moved from forwarding/lib.sh to this lib file. e.g. busywait(). Add function setup_ns() for user to create unique namespaces with given prefix name. Reviewed-by: Petr Machata Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/Makefile | 2 +- tools/testing/selftests/net/forwarding/lib.sh | 27 +----- tools/testing/selftests/net/lib.sh | 85 +++++++++++++++++++ 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 tools/testing/selftests/net/lib.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 9274edfb76ff..14bd68da7466 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -54,7 +54,7 @@ TEST_PROGS += ip_local_port_range.sh TEST_PROGS += rps_default_mask.sh TEST_PROGS += big_tcp.sh TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh -TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh +TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh lib.sh TEST_GEN_FILES = socket nettest TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index e37a15eda6c2..8f6ca458af9a 100755 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -4,9 +4,6 @@ ############################################################################## # Defines -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 - # Can be overridden by the configuration file. PING=${PING:=ping} PING6=${PING6:=ping6} @@ -41,6 +38,7 @@ if [[ -f $relative_path/forwarding.config ]]; then source "$relative_path/forwarding.config" fi +source ../lib.sh ############################################################################## # Sanity checks @@ -395,29 +393,6 @@ log_info() echo "INFO: $msg" } -busywait() -{ - local timeout=$1; shift - - local start_time="$(date -u +%s%3N)" - while true - do - local out - out=$("$@") - local ret=$? - if ((!ret)); then - echo -n "$out" - return 0 - fi - - local current_time="$(date -u +%s%3N)" - if ((current_time - start_time > timeout)); then - echo -n "$out" - return 1 - fi - done -} - not() { "$@" diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh new file mode 100644 index 000000000000..518eca57b815 --- /dev/null +++ b/tools/testing/selftests/net/lib.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Defines + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +############################################################################## +# Helpers +busywait() +{ + local timeout=$1; shift + + local start_time="$(date -u +%s%3N)" + while true + do + local out + out=$("$@") + local ret=$? + if ((!ret)); then + echo -n "$out" + return 0 + fi + + local current_time="$(date -u +%s%3N)" + if ((current_time - start_time > timeout)); then + echo -n "$out" + return 1 + fi + done +} + +cleanup_ns() +{ + local ns="" + local errexit=0 + local ret=0 + + # disable errexit temporary + if [[ $- =~ "e" ]]; then + errexit=1 + set +e + fi + + for ns in "$@"; do + ip netns delete "${ns}" &> /dev/null + if ! busywait 2 ip netns list \| grep -vq "^$ns$" &> /dev/null; then + echo "Warn: Failed to remove namespace $ns" + ret=1 + fi + done + + [ $errexit -eq 1 ] && set -e + return $ret +} + +# setup netns with given names as prefix. e.g +# setup_ns local remote +setup_ns() +{ + local ns="" + local ns_name="" + local ns_list="" + for ns_name in "$@"; do + # Some test may setup/remove same netns multi times + if unset ${ns_name} 2> /dev/null; then + ns="${ns_name,,}-$(mktemp -u XXXXXX)" + eval readonly ${ns_name}="$ns" + else + eval ns='$'${ns_name} + cleanup_ns "$ns" + + fi + + if ! ip netns add "$ns"; then + echo "Failed to create namespace $ns_name" + cleanup_ns "$ns_list" + return $ksft_skip + fi + ip -n "$ns" link set lo up + ns_list="$ns_list $ns" + done +} From 64227511ad57796fac514ad8df6f2830cc887563 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:00:58 +0800 Subject: [PATCH 2560/7721] selftests/net: convert arp_ndisc_evict_nocarrier.sh to run it in unique namespace Here is the test result after conversion. ]# ./arp_ndisc_evict_nocarrier.sh run arp_evict_nocarrier=1 test ok run arp_evict_nocarrier=0 test ok run all.arp_evict_nocarrier=0 test ok run ndisc_evict_nocarrier=1 test ok run ndisc_evict_nocarrier=0 test ok run all.ndisc_evict_nocarrier=0 test ok Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- .../net/arp_ndisc_evict_nocarrier.sh | 46 +++++++------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh b/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh index 4a110bb01e53..92eb880c52f2 100755 --- a/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh +++ b/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh @@ -12,7 +12,8 @@ # {arp,ndisc}_evict_nocarrer=0 should still contain the single ARP/ND entry # -readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" +source lib.sh + readonly V4_ADDR0=10.0.10.1 readonly V4_ADDR1=10.0.10.2 readonly V6_ADDR0=2001:db8:91::1 @@ -22,43 +23,29 @@ ret=0 cleanup_v6() { - ip netns del me - ip netns del peer + cleanup_ns ${me} ${peer} sysctl -w net.ipv6.conf.veth1.ndisc_evict_nocarrier=1 >/dev/null 2>&1 sysctl -w net.ipv6.conf.all.ndisc_evict_nocarrier=1 >/dev/null 2>&1 } -create_ns() -{ - local n=${1} - - ip netns del ${n} 2>/dev/null - - ip netns add ${n} - ip netns set ${n} $((nsid++)) - ip -netns ${n} link set lo up -} - - setup_v6() { - create_ns me - create_ns peer + setup_ns me peer - IP="ip -netns me" + IP="ip -netns ${me}" $IP li add veth1 type veth peer name veth2 $IP li set veth1 up $IP -6 addr add $V6_ADDR0/64 dev veth1 nodad - $IP li set veth2 netns peer up - ip -netns peer -6 addr add $V6_ADDR1/64 dev veth2 nodad + $IP li set veth2 netns ${peer} up + ip -netns ${peer} -6 addr add $V6_ADDR1/64 dev veth2 nodad - ip netns exec me sysctl -w $1 >/dev/null 2>&1 + ip netns exec ${me} sysctl -w $1 >/dev/null 2>&1 # Establish an ND cache entry - ip netns exec me ping -6 -c1 -Iveth1 $V6_ADDR1 >/dev/null 2>&1 + ip netns exec ${me} ping -6 -c1 -Iveth1 $V6_ADDR1 >/dev/null 2>&1 # Should have the veth1 entry in ND table - ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 + ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 if [ $? -ne 0 ]; then cleanup_v6 echo "failed" @@ -66,11 +53,11 @@ setup_v6() { fi # Set veth2 down, which will put veth1 in NOCARRIER state - ip netns exec peer ip link set veth2 down + ip netns exec ${peer} ip link set veth2 down } setup_v4() { - ip netns add "${PEER_NS}" + setup_ns PEER_NS ip link add name veth0 type veth peer name veth1 ip link set dev veth0 up ip link set dev veth1 netns "${PEER_NS}" @@ -99,8 +86,7 @@ setup_v4() { cleanup_v4() { ip neigh flush dev veth0 ip link del veth0 - local -r ns="$(ip netns list|grep $PEER_NS)" - [ -n "$ns" ] && ip netns del $ns 2>/dev/null + cleanup_ns $PEER_NS sysctl -w net.ipv4.conf.veth0.arp_evict_nocarrier=1 >/dev/null 2>&1 sysctl -w net.ipv4.conf.all.arp_evict_nocarrier=1 >/dev/null 2>&1 @@ -163,7 +149,7 @@ run_ndisc_evict_nocarrier_enabled() { setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=1" - ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 + ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 if [ $? -eq 0 ];then echo "failed" @@ -180,7 +166,7 @@ run_ndisc_evict_nocarrier_disabled() { setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=0" - ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 + ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 if [ $? -eq 0 ];then echo "ok" @@ -197,7 +183,7 @@ run_ndisc_evict_nocarrier_disabled_all() { setup_v6 "net.ipv6.conf.all.ndisc_evict_nocarrier=0" - ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 + ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1 if [ $? -eq 0 ];then echo "ok" From 7f770d28f2e5abfd442ad689ba1129dd66593529 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:00:59 +0800 Subject: [PATCH 2561/7721] selftests/net: specify the interface when do arping When do arping, the interface need to be specified. Or we will get error: Interface "lo" is not ARPable. And the test failed. ]# ./arp_ndisc_untracked_subnets.sh TEST: test_arp: accept_arp=0 [ OK ] TEST: test_arp: accept_arp=1 [FAIL] TEST: test_arp: accept_arp=2 same_subnet=0 [ OK ] TEST: test_arp: accept_arp=2 same_subnet=1 [FAIL] After fix: ]# ./arp_ndisc_untracked_subnets.sh TEST: test_arp: accept_arp=0 [ OK ] TEST: test_arp: accept_arp=1 [ OK ] TEST: test_arp: accept_arp=2 same_subnet=0 [ OK ] TEST: test_arp: accept_arp=2 same_subnet=1 [ OK ] Fixes: 0ea7b0a454ca ("selftests: net: arp_ndisc_untracked_subnets: test for arp_accept and accept_untracked_na") Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh index c899b446acb6..327427ec10f5 100755 --- a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh +++ b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh @@ -150,7 +150,7 @@ arp_test_gratuitous() { fi # Supply arp_accept option to set up which sets it in sysctl setup ${arp_accept} - ip netns exec ${HOST_NS} arping -A -U ${HOST_ADDR} -c1 2>&1 >/dev/null + ip netns exec ${HOST_NS} arping -A -I ${HOST_INTF} -U ${HOST_ADDR} -c1 2>&1 >/dev/null if verify_arp $1 $2; then printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}" From 3a0f3367006f7cb4203e8eecc77ce7d63190a1df Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:00 +0800 Subject: [PATCH 2562/7721] selftests/net: convert arp_ndisc_untracked_subnets.sh to run it in unique namespace Here is the test result after conversion. 2 tests also failed without this patch ]# ./arp_ndisc_untracked_subnets.sh TEST: test_arp: accept_arp=0 [ OK ] TEST: test_arp: accept_arp=1 [ OK ] TEST: test_arp: accept_arp=2 same_subnet=0 [ OK ] TEST: test_arp: accept_arp=2 same_subnet=1 [ OK ] TEST: test_ndisc: accept_untracked_na=0 [ OK ] TEST: test_ndisc: accept_untracked_na=1 [ OK ] TEST: test_ndisc: accept_untracked_na=2 same_subnet=0 [ OK ] TEST: test_ndisc: accept_untracked_na=2 same_subnet=1 [ OK ] Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- .../net/arp_ndisc_untracked_subnets.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh index 327427ec10f5..a40c0e9bd023 100755 --- a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh +++ b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh @@ -5,16 +5,14 @@ # garp to the router. Router accepts or ignores based on its arp_accept # or accept_untracked_na configuration. +source lib.sh + TESTS="arp ndisc" -ROUTER_NS="ns-router" -ROUTER_NS_V6="ns-router-v6" ROUTER_INTF="veth-router" ROUTER_ADDR="10.0.10.1" ROUTER_ADDR_V6="2001:db8:abcd:0012::1" -HOST_NS="ns-host" -HOST_NS_V6="ns-host-v6" HOST_INTF="veth-host" HOST_ADDR="10.0.10.2" HOST_ADDR_V6="2001:db8:abcd:0012::2" @@ -23,13 +21,11 @@ SUBNET_WIDTH=24 PREFIX_WIDTH_V6=64 cleanup() { - ip netns del ${HOST_NS} - ip netns del ${ROUTER_NS} + cleanup_ns ${HOST_NS} ${ROUTER_NS} } cleanup_v6() { - ip netns del ${HOST_NS_V6} - ip netns del ${ROUTER_NS_V6} + cleanup_ns ${HOST_NS_V6} ${ROUTER_NS_V6} } setup() { @@ -37,8 +33,7 @@ setup() { local arp_accept=$1 # Set up two namespaces - ip netns add ${ROUTER_NS} - ip netns add ${HOST_NS} + setup_ns HOST_NS ROUTER_NS # Set up interfaces veth0 and veth1, which are pairs in separate # namespaces. veth0 is veth-router, veth1 is veth-host. @@ -72,8 +67,7 @@ setup_v6() { local accept_untracked_na=$1 # Set up two namespaces - ip netns add ${ROUTER_NS_V6} - ip netns add ${HOST_NS_V6} + setup_ns HOST_NS_V6 ROUTER_NS_V6 # Set up interfaces veth0 and veth1, which are pairs in separate # namespaces. veth0 is veth-router, veth1 is veth-host. From 7c16d485fec5d0010b992e75ad996e7382950879 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:01 +0800 Subject: [PATCH 2563/7721] selftests/net: convert cmsg tests to make them run in unique namespace Here is the test result after conversion. ]# ./cmsg_ipv6.sh OK ]# ./cmsg_so_mark.sh OK ]# ./cmsg_time.sh OK Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/cmsg_ipv6.sh | 10 ++++------ tools/testing/selftests/net/cmsg_so_mark.sh | 7 ++++--- tools/testing/selftests/net/cmsg_time.sh | 7 ++++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh index 330d0b1ceced..f30bd57d5e38 100755 --- a/tools/testing/selftests/net/cmsg_ipv6.sh +++ b/tools/testing/selftests/net/cmsg_ipv6.sh @@ -1,9 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -ksft_skip=4 +source lib.sh -NS=ns IP6=2001:db8:1::1/64 TGT6=2001:db8:1::2 TMPF=$(mktemp --suffix ".pcap") @@ -11,13 +10,11 @@ TMPF=$(mktemp --suffix ".pcap") cleanup() { rm -f $TMPF - ip netns del $NS + cleanup_ns $NS } trap cleanup EXIT -NSEXE="ip netns exec $NS" - tcpdump -h | grep immediate-mode >> /dev/null if [ $? -ne 0 ]; then echo "SKIP - tcpdump with --immediate-mode option required" @@ -25,7 +22,8 @@ if [ $? -ne 0 ]; then fi # Namespaces -ip netns add $NS +setup_ns NS +NSEXE="ip netns exec $NS" $NSEXE sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null diff --git a/tools/testing/selftests/net/cmsg_so_mark.sh b/tools/testing/selftests/net/cmsg_so_mark.sh index 1650b8622f2f..772ad0cc2630 100755 --- a/tools/testing/selftests/net/cmsg_so_mark.sh +++ b/tools/testing/selftests/net/cmsg_so_mark.sh @@ -1,7 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -NS=ns +source lib.sh + IP4=172.16.0.1/24 TGT4=172.16.0.2 IP6=2001:db8:1::1/64 @@ -10,13 +11,13 @@ MARK=1000 cleanup() { - ip netns del $NS + cleanup_ns $NS } trap cleanup EXIT # Namespaces -ip netns add $NS +setup_ns NS ip netns exec $NS sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null diff --git a/tools/testing/selftests/net/cmsg_time.sh b/tools/testing/selftests/net/cmsg_time.sh index 91161e1da734..af85267ad1e3 100755 --- a/tools/testing/selftests/net/cmsg_time.sh +++ b/tools/testing/selftests/net/cmsg_time.sh @@ -1,7 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -NS=ns +source lib.sh + IP4=172.16.0.1/24 TGT4=172.16.0.2 IP6=2001:db8:1::1/64 @@ -9,13 +10,13 @@ TGT6=2001:db8:1::2 cleanup() { - ip netns del $NS + cleanup_ns $NS } trap cleanup EXIT # Namespaces -ip netns add $NS +setup_ns NS ip netns exec $NS sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null From 0d8b488792e4f2e26f54248f8a0380b73e1ff992 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:02 +0800 Subject: [PATCH 2564/7721] selftests/net: convert drop_monitor_tests.sh to run it in unique namespace Here is the test result after conversion. ]# ./drop_monitor_tests.sh Software drops test TEST: Capturing active software drops [ OK ] TEST: Capturing inactive software drops [ OK ] Hardware drops test TEST: Capturing active hardware drops [ OK ] TEST: Capturing inactive hardware drops [ OK ] Tests passed: 4 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- .../selftests/net/drop_monitor_tests.sh | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/net/drop_monitor_tests.sh b/tools/testing/selftests/net/drop_monitor_tests.sh index b7650e30d18b..7c4818c971fc 100755 --- a/tools/testing/selftests/net/drop_monitor_tests.sh +++ b/tools/testing/selftests/net/drop_monitor_tests.sh @@ -2,10 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 # This test is for checking drop monitor functionality. - +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 # all tests in this script. Can be overridden with -t option TESTS=" @@ -13,10 +11,6 @@ TESTS=" hw_drops " -IP="ip -netns ns1" -TC="tc -netns ns1" -DEVLINK="devlink -N ns1" -NS_EXEC="ip netns exec ns1" NETDEVSIM_PATH=/sys/bus/netdevsim/ DEV_ADDR=1337 DEV=netdevsim${DEV_ADDR} @@ -43,7 +37,7 @@ setup() modprobe netdevsim &> /dev/null set -e - ip netns add ns1 + setup_ns NS1 $IP link add dummy10 up type dummy $NS_EXEC echo "$DEV_ADDR 1" > ${NETDEVSIM_PATH}/new_device @@ -57,7 +51,7 @@ setup() cleanup() { $NS_EXEC echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device - ip netns del ns1 + cleanup_ns ${NS1} } sw_drops_test() @@ -194,8 +188,15 @@ if [ $? -ne 0 ]; then exit $ksft_skip fi -# start clean +# create netns first so we can get the namespace name +setup_ns NS1 cleanup &> /dev/null +trap cleanup EXIT + +IP="ip -netns ${NS1}" +TC="tc -netns ${NS1}" +DEVLINK="devlink -N ${NS1}" +NS_EXEC="ip netns exec ${NS1}" for t in $TESTS do From baf37f213c88ae9e620195f34509a9a4be7ffccd Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:03 +0800 Subject: [PATCH 2565/7721] selftests/net: convert traceroute.sh to run it in unique namespace Here is the test result after conversion. ]# ./traceroute.sh TEST: IPV6 traceroute [ OK ] TEST: IPV4 traceroute [ OK ] Tests passed: 2 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/traceroute.sh | 82 ++++++++++------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/tools/testing/selftests/net/traceroute.sh b/tools/testing/selftests/net/traceroute.sh index de9ca97abc30..282f14760940 100755 --- a/tools/testing/selftests/net/traceroute.sh +++ b/tools/testing/selftests/net/traceroute.sh @@ -4,6 +4,7 @@ # Run traceroute/traceroute6 tests # +source lib.sh VERBOSE=0 PAUSE_ON_FAIL=no @@ -69,9 +70,6 @@ create_ns() [ -z "${addr}" ] && addr="-" [ -z "${addr6}" ] && addr6="-" - ip netns add ${ns} - - ip netns exec ${ns} ip link set lo up if [ "${addr}" != "-" ]; then ip netns exec ${ns} ip addr add dev lo ${addr} fi @@ -160,12 +158,7 @@ connect_ns() cleanup_traceroute6() { - local ns - - for ns in host-1 host-2 router-1 router-2 - do - ip netns del ${ns} 2>/dev/null - done + cleanup_ns $h1 $h2 $r1 $r2 } setup_traceroute6() @@ -176,33 +169,34 @@ setup_traceroute6() cleanup_traceroute6 set -e - create_ns host-1 - create_ns host-2 - create_ns router-1 - create_ns router-2 + setup_ns h1 h2 r1 r2 + create_ns $h1 + create_ns $h2 + create_ns $r1 + create_ns $r2 # Setup N3 - connect_ns router-2 eth3 - 2000:103::2/64 host-2 eth3 - 2000:103::4/64 - ip netns exec host-2 ip route add default via 2000:103::2 + connect_ns $r2 eth3 - 2000:103::2/64 $h2 eth3 - 2000:103::4/64 + ip netns exec $h2 ip route add default via 2000:103::2 # Setup N2 - connect_ns router-1 eth2 - 2000:102::1/64 router-2 eth2 - 2000:102::2/64 - ip netns exec router-1 ip route add default via 2000:102::2 + connect_ns $r1 eth2 - 2000:102::1/64 $r2 eth2 - 2000:102::2/64 + ip netns exec $r1 ip route add default via 2000:102::2 # Setup N1. host-1 and router-2 connect to a bridge in router-1. - ip netns exec router-1 ip link add name ${brdev} type bridge - ip netns exec router-1 ip link set ${brdev} up - ip netns exec router-1 ip addr add 2000:101::1/64 dev ${brdev} + ip netns exec $r1 ip link add name ${brdev} type bridge + ip netns exec $r1 ip link set ${brdev} up + ip netns exec $r1 ip addr add 2000:101::1/64 dev ${brdev} - connect_ns host-1 eth0 - 2000:101::3/64 router-1 eth0 - - - ip netns exec router-1 ip link set dev eth0 master ${brdev} - ip netns exec host-1 ip route add default via 2000:101::1 + connect_ns $h1 eth0 - 2000:101::3/64 $r1 eth0 - - + ip netns exec $r1 ip link set dev eth0 master ${brdev} + ip netns exec $h1 ip route add default via 2000:101::1 - connect_ns router-2 eth1 - 2000:101::2/64 router-1 eth1 - - - ip netns exec router-1 ip link set dev eth1 master ${brdev} + connect_ns $r2 eth1 - 2000:101::2/64 $r1 eth1 - - + ip netns exec $r1 ip link set dev eth1 master ${brdev} # Prime the network - ip netns exec host-1 ping6 -c5 2000:103::4 >/dev/null 2>&1 + ip netns exec $h1 ping6 -c5 2000:103::4 >/dev/null 2>&1 set +e } @@ -217,7 +211,7 @@ run_traceroute6() setup_traceroute6 # traceroute6 host-2 from host-1 (expects 2000:102::2) - run_cmd host-1 "traceroute6 2000:103::4 | grep -q 2000:102::2" + run_cmd $h1 "traceroute6 2000:103::4 | grep -q 2000:102::2" log_test $? 0 "IPV6 traceroute" cleanup_traceroute6 @@ -240,12 +234,7 @@ run_traceroute6() cleanup_traceroute() { - local ns - - for ns in host-1 host-2 router - do - ip netns del ${ns} 2>/dev/null - done + cleanup_ns $h1 $h2 $router } setup_traceroute() @@ -254,24 +243,25 @@ setup_traceroute() cleanup_traceroute set -e - create_ns host-1 - create_ns host-2 - create_ns router + setup_ns h1 h2 router + create_ns $h1 + create_ns $h2 + create_ns $router - connect_ns host-1 eth0 1.0.1.3/24 - \ - router eth1 1.0.3.1/24 - - ip netns exec host-1 ip route add default via 1.0.1.1 + connect_ns $h1 eth0 1.0.1.3/24 - \ + $router eth1 1.0.3.1/24 - + ip netns exec $h1 ip route add default via 1.0.1.1 - ip netns exec router ip addr add 1.0.1.1/24 dev eth1 - ip netns exec router sysctl -qw \ + ip netns exec $router ip addr add 1.0.1.1/24 dev eth1 + ip netns exec $router sysctl -qw \ net.ipv4.icmp_errors_use_inbound_ifaddr=1 - connect_ns host-2 eth0 1.0.2.4/24 - \ - router eth2 1.0.2.1/24 - - ip netns exec host-2 ip route add default via 1.0.2.1 + connect_ns $h2 eth0 1.0.2.4/24 - \ + $router eth2 1.0.2.1/24 - + ip netns exec $h2 ip route add default via 1.0.2.1 # Prime the network - ip netns exec host-1 ping -c5 1.0.2.4 >/dev/null 2>&1 + ip netns exec $h1 ping -c5 1.0.2.4 >/dev/null 2>&1 set +e } @@ -286,7 +276,7 @@ run_traceroute() setup_traceroute # traceroute host-2 from host-1 (expects 1.0.1.1). Takes a while. - run_cmd host-1 "traceroute 1.0.2.4 | grep -q 1.0.1.1" + run_cmd $h1 "traceroute 1.0.2.4 | grep -q 1.0.1.1" log_test $? 0 "IPV4 traceroute" cleanup_traceroute From c1516b3563aca82a35277dc8999370868cf20175 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:04 +0800 Subject: [PATCH 2566/7721] selftests/net: convert icmp_redirect.sh to run it in unique namespace Here is the test result after conversion. # ./icmp_redirect.sh ########################################################################### Legacy routing ########################################################################### TEST: IPv4: redirect exception [ OK ] ... TEST: IPv4: mtu exception plus redirect [ OK ] TEST: IPv6: mtu exception plus redirect [ OK ] Tests passed: 40 Tests failed: 0 Tests xfailed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/icmp_redirect.sh | 180 +++++++++---------- 1 file changed, 87 insertions(+), 93 deletions(-) diff --git a/tools/testing/selftests/net/icmp_redirect.sh b/tools/testing/selftests/net/icmp_redirect.sh index 7b9d6e31b8e7..d6f0e449c029 100755 --- a/tools/testing/selftests/net/icmp_redirect.sh +++ b/tools/testing/selftests/net/icmp_redirect.sh @@ -19,6 +19,7 @@ # Route on r1 changed to go to r2 via eth0. This causes a redirect to be sent # from r1 to h1 telling h1 to use r2 when talking to h2. +source lib.sh VERBOSE=0 PAUSE_ON_FAIL=no @@ -140,11 +141,7 @@ get_linklocal() cleanup() { - local ns - - for ns in h1 h2 r1 r2; do - ip netns del $ns 2>/dev/null - done + cleanup_ns $h1 $h2 $r1 $r2 } create_vrf() @@ -171,102 +168,99 @@ setup() # # create nodes as namespaces - # - for ns in h1 h2 r1 r2; do - ip netns add $ns - ip -netns $ns li set lo up + setup_ns h1 h2 r1 r2 + for ns in $h1 $h2 $r1 $r2; do + if echo $ns | grep -q h[12]-; then + ip netns exec $ns sysctl -q -w net.ipv4.conf.all.accept_redirects=1 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.accept_redirects=1 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 + else + ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 + ip netns exec $ns sysctl -q -w net.ipv4.conf.all.send_redirects=1 + ip netns exec $ns sysctl -q -w net.ipv4.conf.default.rp_filter=0 + ip netns exec $ns sysctl -q -w net.ipv4.conf.all.rp_filter=0 - case "${ns}" in - h[12]) ip netns exec $ns sysctl -q -w net.ipv4.conf.all.accept_redirects=1 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.accept_redirects=1 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 - ;; - r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 - ip netns exec $ns sysctl -q -w net.ipv4.conf.all.send_redirects=1 - ip netns exec $ns sysctl -q -w net.ipv4.conf.default.rp_filter=0 - ip netns exec $ns sysctl -q -w net.ipv4.conf.all.rp_filter=0 - - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 - ip netns exec $ns sysctl -q -w net.ipv6.route.mtu_expires=10 - esac + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 + ip netns exec $ns sysctl -q -w net.ipv6.route.mtu_expires=10 + fi done # # create interconnects # - ip -netns h1 li add eth0 type veth peer name r1h1 - ip -netns h1 li set r1h1 netns r1 name eth0 up + ip -netns $h1 li add eth0 type veth peer name r1h1 + ip -netns $h1 li set r1h1 netns $r1 name eth0 up - ip -netns h1 li add eth1 type veth peer name r2h1 - ip -netns h1 li set r2h1 netns r2 name eth0 up + ip -netns $h1 li add eth1 type veth peer name r2h1 + ip -netns $h1 li set r2h1 netns $r2 name eth0 up - ip -netns h2 li add eth0 type veth peer name r2h2 - ip -netns h2 li set eth0 up - ip -netns h2 li set r2h2 netns r2 name eth2 up + ip -netns $h2 li add eth0 type veth peer name r2h2 + ip -netns $h2 li set eth0 up + ip -netns $h2 li set r2h2 netns $r2 name eth2 up - ip -netns r1 li add eth1 type veth peer name r2r1 - ip -netns r1 li set eth1 up - ip -netns r1 li set r2r1 netns r2 name eth1 up + ip -netns $r1 li add eth1 type veth peer name r2r1 + ip -netns $r1 li set eth1 up + ip -netns $r1 li set r2r1 netns $r2 name eth1 up # # h1 # if [ "${WITH_VRF}" = "yes" ]; then - create_vrf "h1" + create_vrf "$h1" H1_VRF_ARG="vrf ${VRF}" H1_PING_ARG="-I ${VRF}" else H1_VRF_ARG= H1_PING_ARG= fi - ip -netns h1 li add br0 type bridge + ip -netns $h1 li add br0 type bridge if [ "${WITH_VRF}" = "yes" ]; then - ip -netns h1 li set br0 vrf ${VRF} up + ip -netns $h1 li set br0 vrf ${VRF} up else - ip -netns h1 li set br0 up + ip -netns $h1 li set br0 up fi - ip -netns h1 addr add dev br0 ${H1_N1_IP}/24 - ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad - ip -netns h1 li set eth0 master br0 up - ip -netns h1 li set eth1 master br0 up + ip -netns $h1 addr add dev br0 ${H1_N1_IP}/24 + ip -netns $h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad + ip -netns $h1 li set eth0 master br0 up + ip -netns $h1 li set eth1 master br0 up # # h2 # - ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24 - ip -netns h2 ro add default via ${R2_N2_IP} dev eth0 - ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad - ip -netns h2 -6 ro add default via ${R2_N2_IP6} dev eth0 + ip -netns $h2 addr add dev eth0 ${H2_N2_IP}/24 + ip -netns $h2 ro add default via ${R2_N2_IP} dev eth0 + ip -netns $h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad + ip -netns $h2 -6 ro add default via ${R2_N2_IP6} dev eth0 # # r1 # - ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24 - ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad - ip -netns r1 addr add dev eth1 ${R1_R2_N1_IP}/30 - ip -netns r1 -6 addr add dev eth1 ${R1_R2_N1_IP6}/126 nodad + ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24 + ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad + ip -netns $r1 addr add dev eth1 ${R1_R2_N1_IP}/30 + ip -netns $r1 -6 addr add dev eth1 ${R1_R2_N1_IP6}/126 nodad # # r2 # - ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24 - ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad - ip -netns r2 addr add dev eth1 ${R2_R1_N1_IP}/30 - ip -netns r2 -6 addr add dev eth1 ${R2_R1_N1_IP6}/126 nodad - ip -netns r2 addr add dev eth2 ${R2_N2_IP}/24 - ip -netns r2 -6 addr add dev eth2 ${R2_N2_IP6}/64 nodad + ip -netns $r2 addr add dev eth0 ${R2_N1_IP}/24 + ip -netns $r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad + ip -netns $r2 addr add dev eth1 ${R2_R1_N1_IP}/30 + ip -netns $r2 -6 addr add dev eth1 ${R2_R1_N1_IP6}/126 nodad + ip -netns $r2 addr add dev eth2 ${R2_N2_IP}/24 + ip -netns $r2 -6 addr add dev eth2 ${R2_N2_IP6}/64 nodad sleep 2 - R1_LLADDR=$(get_linklocal r1 eth0) + R1_LLADDR=$(get_linklocal $r1 eth0) if [ $? -ne 0 ]; then echo "Error: Failed to get link-local address of r1's eth0" exit 1 fi log_debug "initial gateway is R1's lladdr = ${R1_LLADDR}" - R2_LLADDR=$(get_linklocal r2 eth0) + R2_LLADDR=$(get_linklocal $r2 eth0) if [ $? -ne 0 ]; then echo "Error: Failed to get link-local address of r2's eth0" exit 1 @@ -278,8 +272,8 @@ change_h2_mtu() { local mtu=$1 - run_cmd ip -netns h2 li set eth0 mtu ${mtu} - run_cmd ip -netns r2 li set eth2 mtu ${mtu} + run_cmd ip -netns $h2 li set eth0 mtu ${mtu} + run_cmd ip -netns $r2 li set eth2 mtu ${mtu} } check_exception() @@ -291,40 +285,40 @@ check_exception() # From 172.16.1.101: icmp_seq=1 Redirect Host(New nexthop: 172.16.1.102) if [ "$VERBOSE" = "1" ]; then echo "Commands to check for exception:" - run_cmd ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} - run_cmd ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} + run_cmd ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} + run_cmd ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} fi if [ -n "${mtu}" ]; then mtu=" mtu ${mtu}" fi if [ "$with_redirect" = "yes" ]; then - ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ + ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ grep -q "cache expires [0-9]*sec${mtu}" elif [ -n "${mtu}" ]; then - ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ + ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ grep -q "cache expires [0-9]*sec${mtu}" else # want to verify that neither mtu nor redirected appears in # the route get output. The -v will wipe out the cache line # if either are set so the last grep -q will not find a match - ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ + ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \ grep -E -v 'mtu|redirected' | grep -q "cache" fi log_test $? 0 "IPv4: ${desc}" 0 # No PMTU info for test "redirect" and "mtu exception plus redirect" if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then - ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ + ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ grep -v "mtu" | grep -q "${H2_N2_IP6} .*via ${R2_LLADDR} dev br0" elif [ -n "${mtu}" ]; then - ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ + ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ grep -q "${mtu}" else # IPv6 is a bit harder. First strip out the match if it # contains an mtu exception and then look for the first # gateway - R1's lladdr - ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ + ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ grep -v "mtu" | grep -q "${R1_LLADDR}" fi log_test $? 0 "IPv6: ${desc}" 1 @@ -334,21 +328,21 @@ run_ping() { local sz=$1 - run_cmd ip netns exec h1 ping -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP} - run_cmd ip netns exec h1 ${ping6} -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP6} + run_cmd ip netns exec $h1 ping -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP} + run_cmd ip netns exec $h1 ${ping6} -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP6} } replace_route_new() { # r1 to h2 via r2 and eth0 - run_cmd ip -netns r1 nexthop replace id 1 via ${R2_N1_IP} dev eth0 - run_cmd ip -netns r1 nexthop replace id 2 via ${R2_LLADDR} dev eth0 + run_cmd ip -netns $r1 nexthop replace id 1 via ${R2_N1_IP} dev eth0 + run_cmd ip -netns $r1 nexthop replace id 2 via ${R2_LLADDR} dev eth0 } reset_route_new() { - run_cmd ip -netns r1 nexthop flush - run_cmd ip -netns h1 nexthop flush + run_cmd ip -netns $r1 nexthop flush + run_cmd ip -netns $h1 nexthop flush initial_route_new } @@ -356,34 +350,34 @@ reset_route_new() initial_route_new() { # r1 to h2 via r2 and eth1 - run_cmd ip -netns r1 nexthop add id 1 via ${R2_R1_N1_IP} dev eth1 - run_cmd ip -netns r1 ro add ${H2_N2} nhid 1 + run_cmd ip -netns $r1 nexthop add id 1 via ${R2_R1_N1_IP} dev eth1 + run_cmd ip -netns $r1 ro add ${H2_N2} nhid 1 - run_cmd ip -netns r1 nexthop add id 2 via ${R2_R1_N1_IP6} dev eth1 - run_cmd ip -netns r1 -6 ro add ${H2_N2_6} nhid 2 + run_cmd ip -netns $r1 nexthop add id 2 via ${R2_R1_N1_IP6} dev eth1 + run_cmd ip -netns $r1 -6 ro add ${H2_N2_6} nhid 2 # h1 to h2 via r1 - run_cmd ip -netns h1 nexthop add id 1 via ${R1_N1_IP} dev br0 - run_cmd ip -netns h1 ro add ${H1_VRF_ARG} ${H2_N2} nhid 1 + run_cmd ip -netns $h1 nexthop add id 1 via ${R1_N1_IP} dev br0 + run_cmd ip -netns $h1 ro add ${H1_VRF_ARG} ${H2_N2} nhid 1 - run_cmd ip -netns h1 nexthop add id 2 via ${R1_LLADDR} dev br0 - run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} nhid 2 + run_cmd ip -netns $h1 nexthop add id 2 via ${R1_LLADDR} dev br0 + run_cmd ip -netns $h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} nhid 2 } replace_route_legacy() { # r1 to h2 via r2 and eth0 - run_cmd ip -netns r1 ro replace ${H2_N2} via ${R2_N1_IP} dev eth0 - run_cmd ip -netns r1 -6 ro replace ${H2_N2_6} via ${R2_LLADDR} dev eth0 + run_cmd ip -netns $r1 ro replace ${H2_N2} via ${R2_N1_IP} dev eth0 + run_cmd ip -netns $r1 -6 ro replace ${H2_N2_6} via ${R2_LLADDR} dev eth0 } reset_route_legacy() { - run_cmd ip -netns r1 ro del ${H2_N2} - run_cmd ip -netns r1 -6 ro del ${H2_N2_6} + run_cmd ip -netns $r1 ro del ${H2_N2} + run_cmd ip -netns $r1 -6 ro del ${H2_N2_6} - run_cmd ip -netns h1 ro del ${H1_VRF_ARG} ${H2_N2} - run_cmd ip -netns h1 -6 ro del ${H1_VRF_ARG} ${H2_N2_6} + run_cmd ip -netns $h1 ro del ${H1_VRF_ARG} ${H2_N2} + run_cmd ip -netns $h1 -6 ro del ${H1_VRF_ARG} ${H2_N2_6} initial_route_legacy } @@ -391,22 +385,22 @@ reset_route_legacy() initial_route_legacy() { # r1 to h2 via r2 and eth1 - run_cmd ip -netns r1 ro add ${H2_N2} via ${R2_R1_N1_IP} dev eth1 - run_cmd ip -netns r1 -6 ro add ${H2_N2_6} via ${R2_R1_N1_IP6} dev eth1 + run_cmd ip -netns $r1 ro add ${H2_N2} via ${R2_R1_N1_IP} dev eth1 + run_cmd ip -netns $r1 -6 ro add ${H2_N2_6} via ${R2_R1_N1_IP6} dev eth1 # h1 to h2 via r1 # - IPv6 redirect only works if gateway is the LLA - run_cmd ip -netns h1 ro add ${H1_VRF_ARG} ${H2_N2} via ${R1_N1_IP} dev br0 - run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} via ${R1_LLADDR} dev br0 + run_cmd ip -netns $h1 ro add ${H1_VRF_ARG} ${H2_N2} via ${R1_N1_IP} dev br0 + run_cmd ip -netns $h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} via ${R1_LLADDR} dev br0 } check_connectivity() { local rc - run_cmd ip netns exec h1 ping -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP} + run_cmd ip netns exec $h1 ping -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP} rc=$? - run_cmd ip netns exec h1 ${ping6} -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP6} + run_cmd ip netns exec $h1 ${ping6} -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP6} [ $? -ne 0 ] && rc=$? return $rc From 80b74bd33421ddde1b716563e2e6e0da5edc5d9b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:05 +0800 Subject: [PATCH 2567/7721] sleftests/net: convert icmp.sh to run it in unique namespace Here is the test result after conversion. ]# ./icmp.sh OK Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/icmp.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/icmp.sh b/tools/testing/selftests/net/icmp.sh index e4b04cd1644a..824cb0e35eff 100755 --- a/tools/testing/selftests/net/icmp.sh +++ b/tools/testing/selftests/net/icmp.sh @@ -18,8 +18,8 @@ # that address space, so the kernel should substitute the dummy address # 192.0.0.8 defined in RFC7600. -NS1=ns1 -NS2=ns2 +source lib.sh + H1_IP=172.16.0.1/32 H1_IP6=2001:db8:1::1 RT1=172.16.1.0/24 @@ -32,15 +32,13 @@ TMPFILE=$(mktemp) cleanup() { rm -f "$TMPFILE" - ip netns del $NS1 - ip netns del $NS2 + cleanup_ns $NS1 $NS2 } trap cleanup EXIT # Namespaces -ip netns add $NS1 -ip netns add $NS2 +setup_ns NS1 NS2 # Connectivity ip -netns $NS1 link add veth0 type veth peer name veth0 netns $NS2 From 2ab1ee827e976d411fd140225016c2e532e4df12 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:06 +0800 Subject: [PATCH 2568/7721] selftests/net: convert ioam6.sh to run it in unique namespace Here is the test result after conversion. ]# ./ioam6.sh -------------------------------------------------------------------------- OUTPUT tests -------------------------------------------------------------------------- TEST: Unknown IOAM namespace (inline mode) [ OK ] TEST: Unknown IOAM namespace (encap mode) [ OK ] TEST: Missing trace room (inline mode) [ OK ] TEST: Missing trace room (encap mode) [ OK ] TEST: Trace type with bit 0 only (inline mode) [ OK ] ... TEST: Full supported trace (encap mode) [ OK ] -------------------------------------------------------------------------- GLOBAL tests -------------------------------------------------------------------------- TEST: Forward - Full supported trace (inline mode) [ OK ] TEST: Forward - Full supported trace (encap mode) [ OK ] - Tests passed: 88 - Tests failed: 0 Acked-by: David Ahern Reviewed-by: Justin Iurman Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/ioam6.sh | 233 +++++++++++++-------------- 1 file changed, 114 insertions(+), 119 deletions(-) diff --git a/tools/testing/selftests/net/ioam6.sh b/tools/testing/selftests/net/ioam6.sh index 4ceb401da1bf..fe59ca3e5596 100755 --- a/tools/testing/selftests/net/ioam6.sh +++ b/tools/testing/selftests/net/ioam6.sh @@ -117,8 +117,7 @@ # | Schema Data | | # +-----------------------------------------------------------+ -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 +source lib.sh ################################################################################ # # @@ -195,32 +194,32 @@ TESTS_GLOBAL=" check_kernel_compatibility() { - ip netns add ioam-tmp-node - ip link add name veth0 netns ioam-tmp-node type veth \ - peer name veth1 netns ioam-tmp-node + setup_ns ioam_tmp_node + ip link add name veth0 netns $ioam_tmp_node type veth \ + peer name veth1 netns $ioam_tmp_node - ip -netns ioam-tmp-node link set veth0 up - ip -netns ioam-tmp-node link set veth1 up + ip -netns $ioam_tmp_node link set veth0 up + ip -netns $ioam_tmp_node link set veth1 up - ip -netns ioam-tmp-node ioam namespace add 0 + ip -netns $ioam_tmp_node ioam namespace add 0 ns_ad=$? - ip -netns ioam-tmp-node ioam namespace show | grep -q "namespace 0" + ip -netns $ioam_tmp_node ioam namespace show | grep -q "namespace 0" ns_sh=$? if [[ $ns_ad != 0 || $ns_sh != 0 ]] then echo "SKIP: kernel version probably too old, missing ioam support" ip link del veth0 2>/dev/null || true - ip netns del ioam-tmp-node || true + cleanup_ns $ioam_tmp_node || true exit $ksft_skip fi - ip -netns ioam-tmp-node route add db02::/64 encap ioam6 mode inline \ + ip -netns $ioam_tmp_node route add db02::/64 encap ioam6 mode inline \ trace prealloc type 0x800000 ns 0 size 4 dev veth0 tr_ad=$? - ip -netns ioam-tmp-node -6 route | grep -q "encap ioam6" + ip -netns $ioam_tmp_node -6 route | grep -q "encap ioam6" tr_sh=$? if [[ $tr_ad != 0 || $tr_sh != 0 ]] @@ -228,12 +227,12 @@ check_kernel_compatibility() echo "SKIP: cannot attach an ioam trace to a route, did you compile" \ "without CONFIG_IPV6_IOAM6_LWTUNNEL?" ip link del veth0 2>/dev/null || true - ip netns del ioam-tmp-node || true + cleanup_ns $ioam_tmp_node || true exit $ksft_skip fi ip link del veth0 2>/dev/null || true - ip netns del ioam-tmp-node || true + cleanup_ns $ioam_tmp_node || true lsmod | grep -q "ip6_tunnel" ip6tnl_loaded=$? @@ -265,9 +264,7 @@ cleanup() ip link del ioam-veth-alpha 2>/dev/null || true ip link del ioam-veth-gamma 2>/dev/null || true - ip netns del ioam-node-alpha || true - ip netns del ioam-node-beta || true - ip netns del ioam-node-gamma || true + cleanup_ns $ioam_node_alpha $ioam_node_beta $ioam_node_gamma || true if [ $ip6tnl_loaded != 0 ] then @@ -277,69 +274,67 @@ cleanup() setup() { - ip netns add ioam-node-alpha - ip netns add ioam-node-beta - ip netns add ioam-node-gamma + setup_ns ioam_node_alpha ioam_node_beta ioam_node_gamma - ip link add name ioam-veth-alpha netns ioam-node-alpha type veth \ - peer name ioam-veth-betaL netns ioam-node-beta - ip link add name ioam-veth-betaR netns ioam-node-beta type veth \ - peer name ioam-veth-gamma netns ioam-node-gamma + ip link add name ioam-veth-alpha netns $ioam_node_alpha type veth \ + peer name ioam-veth-betaL netns $ioam_node_beta + ip link add name ioam-veth-betaR netns $ioam_node_beta type veth \ + peer name ioam-veth-gamma netns $ioam_node_gamma - ip -netns ioam-node-alpha link set ioam-veth-alpha name veth0 - ip -netns ioam-node-beta link set ioam-veth-betaL name veth0 - ip -netns ioam-node-beta link set ioam-veth-betaR name veth1 - ip -netns ioam-node-gamma link set ioam-veth-gamma name veth0 + ip -netns $ioam_node_alpha link set ioam-veth-alpha name veth0 + ip -netns $ioam_node_beta link set ioam-veth-betaL name veth0 + ip -netns $ioam_node_beta link set ioam-veth-betaR name veth1 + ip -netns $ioam_node_gamma link set ioam-veth-gamma name veth0 - ip -netns ioam-node-alpha addr add db01::2/64 dev veth0 - ip -netns ioam-node-alpha link set veth0 up - ip -netns ioam-node-alpha link set lo up - ip -netns ioam-node-alpha route add db02::/64 via db01::1 dev veth0 - ip -netns ioam-node-alpha route del db01::/64 - ip -netns ioam-node-alpha route add db01::/64 dev veth0 + ip -netns $ioam_node_alpha addr add db01::2/64 dev veth0 + ip -netns $ioam_node_alpha link set veth0 up + ip -netns $ioam_node_alpha link set lo up + ip -netns $ioam_node_alpha route add db02::/64 via db01::1 dev veth0 + ip -netns $ioam_node_alpha route del db01::/64 + ip -netns $ioam_node_alpha route add db01::/64 dev veth0 - ip -netns ioam-node-beta addr add db01::1/64 dev veth0 - ip -netns ioam-node-beta addr add db02::1/64 dev veth1 - ip -netns ioam-node-beta link set veth0 up - ip -netns ioam-node-beta link set veth1 up - ip -netns ioam-node-beta link set lo up + ip -netns $ioam_node_beta addr add db01::1/64 dev veth0 + ip -netns $ioam_node_beta addr add db02::1/64 dev veth1 + ip -netns $ioam_node_beta link set veth0 up + ip -netns $ioam_node_beta link set veth1 up + ip -netns $ioam_node_beta link set lo up - ip -netns ioam-node-gamma addr add db02::2/64 dev veth0 - ip -netns ioam-node-gamma link set veth0 up - ip -netns ioam-node-gamma link set lo up - ip -netns ioam-node-gamma route add db01::/64 via db02::1 dev veth0 + ip -netns $ioam_node_gamma addr add db02::2/64 dev veth0 + ip -netns $ioam_node_gamma link set veth0 up + ip -netns $ioam_node_gamma link set lo up + ip -netns $ioam_node_gamma route add db01::/64 via db02::1 dev veth0 # - IOAM config - - ip netns exec ioam-node-alpha sysctl -wq net.ipv6.ioam6_id=${ALPHA[0]} - ip netns exec ioam-node-alpha sysctl -wq net.ipv6.ioam6_id_wide=${ALPHA[1]} - ip netns exec ioam-node-alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id=${ALPHA[4]} - ip netns exec ioam-node-alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${ALPHA[5]} - ip -netns ioam-node-alpha ioam namespace add 123 data ${ALPHA[6]} wide ${ALPHA[7]} - ip -netns ioam-node-alpha ioam schema add ${ALPHA[8]} "${ALPHA[9]}" - ip -netns ioam-node-alpha ioam namespace set 123 schema ${ALPHA[8]} + ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.ioam6_id=${ALPHA[0]} + ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.ioam6_id_wide=${ALPHA[1]} + ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id=${ALPHA[4]} + ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${ALPHA[5]} + ip -netns $ioam_node_alpha ioam namespace add 123 data ${ALPHA[6]} wide ${ALPHA[7]} + ip -netns $ioam_node_alpha ioam schema add ${ALPHA[8]} "${ALPHA[9]}" + ip -netns $ioam_node_alpha ioam namespace set 123 schema ${ALPHA[8]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.all.forwarding=1 - ip netns exec ioam-node-beta sysctl -wq net.ipv6.ioam6_id=${BETA[0]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.ioam6_id_wide=${BETA[1]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_id=${BETA[2]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${BETA[3]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth1.ioam6_id=${BETA[4]} - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth1.ioam6_id_wide=${BETA[5]} - ip -netns ioam-node-beta ioam namespace add 123 data ${BETA[6]} wide ${BETA[7]} - ip -netns ioam-node-beta ioam schema add ${BETA[8]} "${BETA[9]}" - ip -netns ioam-node-beta ioam namespace set 123 schema ${BETA[8]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.all.forwarding=1 + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.ioam6_id=${BETA[0]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.ioam6_id_wide=${BETA[1]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_id=${BETA[2]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${BETA[3]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth1.ioam6_id=${BETA[4]} + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth1.ioam6_id_wide=${BETA[5]} + ip -netns $ioam_node_beta ioam namespace add 123 data ${BETA[6]} wide ${BETA[7]} + ip -netns $ioam_node_beta ioam schema add ${BETA[8]} "${BETA[9]}" + ip -netns $ioam_node_beta ioam namespace set 123 schema ${BETA[8]} - ip netns exec ioam-node-gamma sysctl -wq net.ipv6.ioam6_id=${GAMMA[0]} - ip netns exec ioam-node-gamma sysctl -wq net.ipv6.ioam6_id_wide=${GAMMA[1]} - ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 - ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id=${GAMMA[2]} - ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${GAMMA[3]} - ip -netns ioam-node-gamma ioam namespace add 123 data ${GAMMA[6]} wide ${GAMMA[7]} + ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.ioam6_id=${GAMMA[0]} + ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.ioam6_id_wide=${GAMMA[1]} + ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 + ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id=${GAMMA[2]} + ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${GAMMA[3]} + ip -netns $ioam_node_gamma ioam namespace add 123 data ${GAMMA[6]} wide ${GAMMA[7]} sleep 1 - ip netns exec ioam-node-alpha ping6 -c 5 -W 1 db02::2 &>/dev/null + ip netns exec $ioam_node_alpha ping6 -c 5 -W 1 db02::2 &>/dev/null if [ $? != 0 ] then echo "Setup FAILED" @@ -412,7 +407,7 @@ run() echo # set OUTPUT settings - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=0 + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=0 for t in $TESTS_OUTPUT do @@ -421,8 +416,8 @@ run() done # clean OUTPUT settings - ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 - ip -netns ioam-node-alpha route change db01::/64 dev veth0 + ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1 + ip -netns $ioam_node_alpha route change db01::/64 dev veth0 echo @@ -433,7 +428,7 @@ run() echo # set INPUT settings - ip -netns ioam-node-alpha ioam namespace del 123 + ip -netns $ioam_node_alpha ioam namespace del 123 for t in $TESTS_INPUT do @@ -442,10 +437,10 @@ run() done # clean INPUT settings - ip -netns ioam-node-alpha ioam namespace add 123 \ + ip -netns $ioam_node_alpha ioam namespace add 123 \ data ${ALPHA[6]} wide ${ALPHA[7]} - ip -netns ioam-node-alpha ioam namespace set 123 schema ${ALPHA[8]} - ip -netns ioam-node-alpha route change db01::/64 dev veth0 + ip -netns $ioam_node_alpha ioam namespace set 123 schema ${ALPHA[8]} + ip -netns $ioam_node_alpha route change db01::/64 dev veth0 echo printf "%0.s-" {1..74} @@ -488,15 +483,15 @@ out_undef_ns() local desc="Unknown IOAM namespace" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0x800000 ns 0 size 4 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0x800000 0 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } out_no_room() @@ -508,15 +503,15 @@ out_no_room() local desc="Missing trace room" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0xc00000 ns 123 size 4 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0xc00000 123 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } out_bits() @@ -532,11 +527,11 @@ out_bits() bit2size[22]=$(( $tmp + ${#ALPHA[9]} + ((4 - (${#ALPHA[9]} % 4)) % 4) )) [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up for i in {0..22} do - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} \ dev veth0 &>/dev/null @@ -554,12 +549,12 @@ out_bits() log_test_failed "$descr" fi else - run_test "out_bit$i" "$descr ($1 mode)" ioam-node-alpha \ - ioam-node-beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 + run_test "out_bit$i" "$descr ($1 mode)" $ioam_node_alpha \ + $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 fi done - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down bit2size[22]=$tmp } @@ -573,15 +568,15 @@ out_full_supp_trace() local desc="Full supported trace" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0xfff002 ns 123 size 100 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0xfff002 123 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } @@ -603,15 +598,15 @@ in_undef_ns() local desc="Unknown IOAM namespace" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0x800000 ns 0 size 4 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0x800000 0 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } in_no_room() @@ -623,15 +618,15 @@ in_no_room() local desc="Missing trace room" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0xc00000 ns 123 size 4 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0xc00000 123 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } in_bits() @@ -647,19 +642,19 @@ in_bits() bit2size[22]=$(( $tmp + ${#BETA[9]} + ((4 - (${#BETA[9]} % 4)) % 4) )) [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up for i in {0..11} {22..22} do - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} \ dev veth0 - run_test "in_bit$i" "${desc//$i} ($1 mode)" ioam-node-alpha \ - ioam-node-beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 + run_test "in_bit$i" "${desc//$i} ($1 mode)" $ioam_node_alpha \ + $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 done - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down bit2size[22]=$tmp } @@ -675,22 +670,22 @@ in_oflag() # Exception: # Here, we need the sender to set the Overflow flag. For that, we will add # back the IOAM namespace that was previously configured on the sender. - ip -netns ioam-node-alpha ioam namespace add 123 + ip -netns $ioam_node_alpha ioam namespace add 123 [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0xc00000 ns 123 size 4 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0xc00000 123 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down # And we clean the exception for this test to get things back to normal for # other INPUT tests - ip -netns ioam-node-alpha ioam namespace del 123 + ip -netns $ioam_node_alpha ioam namespace del 123 } in_full_supp_trace() @@ -702,15 +697,15 @@ in_full_supp_trace() local desc="Full supported trace" [ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up - ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \ trace prealloc type 0xfff002 ns 123 size 80 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ db01::2 db01::1 veth0 0xfff002 123 - [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down } @@ -730,15 +725,15 @@ fwd_full_supp_trace() local desc="Forward - Full supported trace" [ "$1" = "encap" ] && mode="$1 tundst db02::2" || mode="$1" - [ "$1" = "encap" ] && ip -netns ioam-node-gamma link set ip6tnl0 up + [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 up - ip -netns ioam-node-alpha route change db02::/64 encap ioam6 mode $mode \ + ip -netns $ioam_node_alpha route change db02::/64 encap ioam6 mode $mode \ trace prealloc type 0xfff002 ns 123 size 244 via db01::1 dev veth0 - run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-gamma \ + run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_gamma \ db01::2 db02::2 veth0 0xfff002 123 - [ "$1" = "encap" ] && ip -netns ioam-node-gamma link set ip6tnl0 down + [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 down } From 4affb17c0d0e3708cd0088e81564af51e7e4d693 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:07 +0800 Subject: [PATCH 2569/7721] selftests/net: convert l2tp.sh to run it in unique namespace Here is the test result after conversion. ]# ./l2tp.sh TEST: IPv4 basic L2TP tunnel [ OK ] TEST: IPv4 route through L2TP tunnel [ OK ] TEST: IPv6 basic L2TP tunnel [ OK ] TEST: IPv6 route through L2TP tunnel [ OK ] TEST: IPv4 basic L2TP tunnel - with IPsec [ OK ] TEST: IPv4 route through L2TP tunnel - with IPsec [ OK ] TEST: IPv6 basic L2TP tunnel - with IPsec [ OK ] TEST: IPv6 route through L2TP tunnel - with IPsec [ OK ] TEST: IPv4 basic L2TP tunnel [ OK ] TEST: IPv4 route through L2TP tunnel [ OK ] TEST: IPv6 basic L2TP tunnel - with IPsec [ OK ] TEST: IPv6 route through L2TP tunnel - with IPsec [ OK ] TEST: IPv4 basic L2TP tunnel - after IPsec teardown [ OK ] TEST: IPv4 route through L2TP tunnel - after IPsec teardown [ OK ] TEST: IPv6 basic L2TP tunnel - after IPsec teardown [ OK ] TEST: IPv6 route through L2TP tunnel - after IPsec teardown [ OK ] Tests passed: 16 Tests failed: 0 Acked-by: David Ahern Reviewed-by: James Chapman Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/l2tp.sh | 130 +++++++++++++--------------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/tools/testing/selftests/net/l2tp.sh b/tools/testing/selftests/net/l2tp.sh index 5782433886fc..88de7166c8ae 100755 --- a/tools/testing/selftests/net/l2tp.sh +++ b/tools/testing/selftests/net/l2tp.sh @@ -13,6 +13,7 @@ # 10.1.1.1 | | 10.1.2.1 # 2001:db8:1::1 | | 2001:db8:2::1 +source lib.sh VERBOSE=0 PAUSE_ON_FAIL=no @@ -80,9 +81,6 @@ create_ns() [ -z "${addr}" ] && addr="-" [ -z "${addr6}" ] && addr6="-" - ip netns add ${ns} - - ip -netns ${ns} link set lo up if [ "${addr}" != "-" ]; then ip -netns ${ns} addr add dev lo ${addr} fi @@ -133,12 +131,7 @@ connect_ns() cleanup() { - local ns - - for ns in host-1 host-2 router - do - ip netns del ${ns} 2>/dev/null - done + cleanup_ns $host_1 $host_2 $router } setup_l2tp_ipv4() @@ -146,28 +139,28 @@ setup_l2tp_ipv4() # # configure l2tpv3 tunnel on host-1 # - ip -netns host-1 l2tp add tunnel tunnel_id 1041 peer_tunnel_id 1042 \ + ip -netns $host_1 l2tp add tunnel tunnel_id 1041 peer_tunnel_id 1042 \ encap ip local 10.1.1.1 remote 10.1.2.1 - ip -netns host-1 l2tp add session name l2tp4 tunnel_id 1041 \ + ip -netns $host_1 l2tp add session name l2tp4 tunnel_id 1041 \ session_id 1041 peer_session_id 1042 - ip -netns host-1 link set dev l2tp4 up - ip -netns host-1 addr add dev l2tp4 172.16.1.1 peer 172.16.1.2 + ip -netns $host_1 link set dev l2tp4 up + ip -netns $host_1 addr add dev l2tp4 172.16.1.1 peer 172.16.1.2 # # configure l2tpv3 tunnel on host-2 # - ip -netns host-2 l2tp add tunnel tunnel_id 1042 peer_tunnel_id 1041 \ + ip -netns $host_2 l2tp add tunnel tunnel_id 1042 peer_tunnel_id 1041 \ encap ip local 10.1.2.1 remote 10.1.1.1 - ip -netns host-2 l2tp add session name l2tp4 tunnel_id 1042 \ + ip -netns $host_2 l2tp add session name l2tp4 tunnel_id 1042 \ session_id 1042 peer_session_id 1041 - ip -netns host-2 link set dev l2tp4 up - ip -netns host-2 addr add dev l2tp4 172.16.1.2 peer 172.16.1.1 + ip -netns $host_2 link set dev l2tp4 up + ip -netns $host_2 addr add dev l2tp4 172.16.1.2 peer 172.16.1.1 # # add routes to loopback addresses # - ip -netns host-1 ro add 172.16.101.2/32 via 172.16.1.2 - ip -netns host-2 ro add 172.16.101.1/32 via 172.16.1.1 + ip -netns $host_1 ro add 172.16.101.2/32 via 172.16.1.2 + ip -netns $host_2 ro add 172.16.101.1/32 via 172.16.1.1 } setup_l2tp_ipv6() @@ -175,28 +168,28 @@ setup_l2tp_ipv6() # # configure l2tpv3 tunnel on host-1 # - ip -netns host-1 l2tp add tunnel tunnel_id 1061 peer_tunnel_id 1062 \ + ip -netns $host_1 l2tp add tunnel tunnel_id 1061 peer_tunnel_id 1062 \ encap ip local 2001:db8:1::1 remote 2001:db8:2::1 - ip -netns host-1 l2tp add session name l2tp6 tunnel_id 1061 \ + ip -netns $host_1 l2tp add session name l2tp6 tunnel_id 1061 \ session_id 1061 peer_session_id 1062 - ip -netns host-1 link set dev l2tp6 up - ip -netns host-1 addr add dev l2tp6 fc00:1::1 peer fc00:1::2 + ip -netns $host_1 link set dev l2tp6 up + ip -netns $host_1 addr add dev l2tp6 fc00:1::1 peer fc00:1::2 # # configure l2tpv3 tunnel on host-2 # - ip -netns host-2 l2tp add tunnel tunnel_id 1062 peer_tunnel_id 1061 \ + ip -netns $host_2 l2tp add tunnel tunnel_id 1062 peer_tunnel_id 1061 \ encap ip local 2001:db8:2::1 remote 2001:db8:1::1 - ip -netns host-2 l2tp add session name l2tp6 tunnel_id 1062 \ + ip -netns $host_2 l2tp add session name l2tp6 tunnel_id 1062 \ session_id 1062 peer_session_id 1061 - ip -netns host-2 link set dev l2tp6 up - ip -netns host-2 addr add dev l2tp6 fc00:1::2 peer fc00:1::1 + ip -netns $host_2 link set dev l2tp6 up + ip -netns $host_2 addr add dev l2tp6 fc00:1::2 peer fc00:1::1 # # add routes to loopback addresses # - ip -netns host-1 -6 ro add fc00:101::2/128 via fc00:1::2 - ip -netns host-2 -6 ro add fc00:101::1/128 via fc00:1::1 + ip -netns $host_1 -6 ro add fc00:101::2/128 via fc00:1::2 + ip -netns $host_2 -6 ro add fc00:101::1/128 via fc00:1::1 } setup() @@ -205,21 +198,22 @@ setup() cleanup set -e - create_ns host-1 172.16.101.1/32 fc00:101::1/128 - create_ns host-2 172.16.101.2/32 fc00:101::2/128 - create_ns router + setup_ns host_1 host_2 router + create_ns $host_1 172.16.101.1/32 fc00:101::1/128 + create_ns $host_2 172.16.101.2/32 fc00:101::2/128 + create_ns $router - connect_ns host-1 eth0 10.1.1.1/24 2001:db8:1::1/64 \ - router eth1 10.1.1.2/24 2001:db8:1::2/64 + connect_ns $host_1 eth0 10.1.1.1/24 2001:db8:1::1/64 \ + $router eth1 10.1.1.2/24 2001:db8:1::2/64 - connect_ns host-2 eth0 10.1.2.1/24 2001:db8:2::1/64 \ - router eth2 10.1.2.2/24 2001:db8:2::2/64 + connect_ns $host_2 eth0 10.1.2.1/24 2001:db8:2::1/64 \ + $router eth2 10.1.2.2/24 2001:db8:2::2/64 - ip -netns host-1 ro add 10.1.2.0/24 via 10.1.1.2 - ip -netns host-1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2 + ip -netns $host_1 ro add 10.1.2.0/24 via 10.1.1.2 + ip -netns $host_1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2 - ip -netns host-2 ro add 10.1.1.0/24 via 10.1.2.2 - ip -netns host-2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2 + ip -netns $host_2 ro add 10.1.1.0/24 via 10.1.2.2 + ip -netns $host_2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2 setup_l2tp_ipv4 setup_l2tp_ipv6 @@ -231,38 +225,38 @@ setup_ipsec() # # IPv4 # - run_cmd host-1 ip xfrm policy add \ + run_cmd $host_1 ip xfrm policy add \ src 10.1.1.1 dst 10.1.2.1 dir out \ tmpl proto esp mode transport - run_cmd host-1 ip xfrm policy add \ + run_cmd $host_1 ip xfrm policy add \ src 10.1.2.1 dst 10.1.1.1 dir in \ tmpl proto esp mode transport - run_cmd host-2 ip xfrm policy add \ + run_cmd $host_2 ip xfrm policy add \ src 10.1.1.1 dst 10.1.2.1 dir in \ tmpl proto esp mode transport - run_cmd host-2 ip xfrm policy add \ + run_cmd $host_2 ip xfrm policy add \ src 10.1.2.1 dst 10.1.1.1 dir out \ tmpl proto esp mode transport - ip -netns host-1 xfrm state add \ + ip -netns $host_1 xfrm state add \ src 10.1.1.1 dst 10.1.2.1 \ spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-1 xfrm state add \ + ip -netns $host_1 xfrm state add \ src 10.1.2.1 dst 10.1.1.1 \ spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-2 xfrm state add \ + ip -netns $host_2 xfrm state add \ src 10.1.1.1 dst 10.1.2.1 \ spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-2 xfrm state add \ + ip -netns $host_2 xfrm state add \ src 10.1.2.1 dst 10.1.1.1 \ spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport @@ -270,38 +264,38 @@ setup_ipsec() # # IPV6 # - run_cmd host-1 ip -6 xfrm policy add \ + run_cmd $host_1 ip -6 xfrm policy add \ src 2001:db8:1::1 dst 2001:db8:2::1 dir out \ tmpl proto esp mode transport - run_cmd host-1 ip -6 xfrm policy add \ + run_cmd $host_1 ip -6 xfrm policy add \ src 2001:db8:2::1 dst 2001:db8:1::1 dir in \ tmpl proto esp mode transport - run_cmd host-2 ip -6 xfrm policy add \ + run_cmd $host_2 ip -6 xfrm policy add \ src 2001:db8:1::1 dst 2001:db8:2::1 dir in \ tmpl proto esp mode transport - run_cmd host-2 ip -6 xfrm policy add \ + run_cmd $host_2 ip -6 xfrm policy add \ src 2001:db8:2::1 dst 2001:db8:1::1 dir out \ tmpl proto esp mode transport - ip -netns host-1 -6 xfrm state add \ + ip -netns $host_1 -6 xfrm state add \ src 2001:db8:1::1 dst 2001:db8:2::1 \ spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-1 -6 xfrm state add \ + ip -netns $host_1 -6 xfrm state add \ src 2001:db8:2::1 dst 2001:db8:1::1 \ spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-2 -6 xfrm state add \ + ip -netns $host_2 -6 xfrm state add \ src 2001:db8:1::1 dst 2001:db8:2::1 \ spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport - ip -netns host-2 -6 xfrm state add \ + ip -netns $host_2 -6 xfrm state add \ src 2001:db8:2::1 dst 2001:db8:1::1 \ spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport @@ -309,10 +303,10 @@ setup_ipsec() teardown_ipsec() { - run_cmd host-1 ip xfrm state flush - run_cmd host-1 ip xfrm policy flush - run_cmd host-2 ip xfrm state flush - run_cmd host-2 ip xfrm policy flush + run_cmd $host_1 ip xfrm state flush + run_cmd $host_1 ip xfrm policy flush + run_cmd $host_2 ip xfrm state flush + run_cmd $host_2 ip xfrm policy flush } ################################################################################ @@ -322,16 +316,16 @@ run_ping() { local desc="$1" - run_cmd host-1 ping -c1 -w1 172.16.1.2 + run_cmd $host_1 ping -c1 -w1 172.16.1.2 log_test $? 0 "IPv4 basic L2TP tunnel ${desc}" - run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 + run_cmd $host_1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 log_test $? 0 "IPv4 route through L2TP tunnel ${desc}" - run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2 + run_cmd $host_1 ${ping6} -c1 -w1 fc00:1::2 log_test $? 0 "IPv6 basic L2TP tunnel ${desc}" - run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 + run_cmd $host_1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 log_test $? 0 "IPv6 route through L2TP tunnel ${desc}" } @@ -344,16 +338,16 @@ run_tests() setup_ipsec run_ping "- with IPsec" - run_cmd host-1 ping -c1 -w1 172.16.1.2 + run_cmd $host_1 ping -c1 -w1 172.16.1.2 log_test $? 0 "IPv4 basic L2TP tunnel ${desc}" - run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 + run_cmd $host_1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 log_test $? 0 "IPv4 route through L2TP tunnel ${desc}" - run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2 + run_cmd $host_1 ${ping6} -c1 -w1 fc00:1::2 log_test $? 0 "IPv6 basic L2TP tunnel - with IPsec" - run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 + run_cmd $host_1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 log_test $? 0 "IPv6 route through L2TP tunnel - with IPsec" teardown_ipsec From 3e05fc0c56bbbd1470a80f63b156be52f1101c64 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:08 +0800 Subject: [PATCH 2570/7721] selftests/net: convert ndisc_unsolicited_na_test.sh to run it in unique namespace Here is the test result after conversion. ]# ./ndisc_unsolicited_na_test.sh TEST: test_unsolicited_na: drop_unsolicited_na=0 accept_untracked_na=1 forwarding=1 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=0 accept_untracked_na=0 forwarding=0 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=0 accept_untracked_na=0 forwarding=1 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=0 accept_untracked_na=1 forwarding=0 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=1 accept_untracked_na=0 forwarding=0 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=1 accept_untracked_na=0 forwarding=1 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=1 accept_untracked_na=1 forwarding=0 [ OK ] TEST: test_unsolicited_na: drop_unsolicited_na=1 accept_untracked_na=1 forwarding=1 [ OK ] Tests passed: 8 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- .../net/ndisc_unsolicited_na_test.sh | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh index 86e621b7b9c7..5db69dad0cfc 100755 --- a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh +++ b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh @@ -10,16 +10,12 @@ # 0 1 0 Don't update NC # 0 1 1 Add a STALE NC entry +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 PAUSE_ON_FAIL=no PAUSE=no -HOST_NS="ns-host" -ROUTER_NS="ns-router" - HOST_INTF="veth-host" ROUTER_INTF="veth-router" @@ -29,11 +25,6 @@ SUBNET_WIDTH=64 ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}" HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}" -IP_HOST="ip -6 -netns ${HOST_NS}" -IP_HOST_EXEC="ip netns exec ${HOST_NS}" -IP_ROUTER="ip -6 -netns ${ROUTER_NS}" -IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}" - tcpdump_stdout= tcpdump_stderr= @@ -76,8 +67,12 @@ setup() # Setup two namespaces and a veth tunnel across them. # On end of the tunnel is a router and the other end is a host. - ip netns add ${HOST_NS} - ip netns add ${ROUTER_NS} + setup_ns HOST_NS ROUTER_NS + IP_HOST="ip -6 -netns ${HOST_NS}" + IP_HOST_EXEC="ip netns exec ${HOST_NS}" + IP_ROUTER="ip -6 -netns ${ROUTER_NS}" + IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}" + ${IP_ROUTER} link add ${ROUTER_INTF} type veth \ peer name ${HOST_INTF} netns ${HOST_NS} From 90e271f65ee428ae5a75e783f5ba50a10dece09d Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:09 +0800 Subject: [PATCH 2571/7721] selftests/net: convert sctp_vrf.sh to run it in unique namespace Here is the test result after conversion. ]# ./sctp_vrf.sh Testing For SCTP VRF: TEST 01: nobind, connect from client 1, l3mdev_accept=1, Y [PASS] ... TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, N [PASS] ***v6 Tests Done*** Acked-by: David Ahern Reviewed-by: Xin Long Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/sctp_vrf.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/net/sctp_vrf.sh b/tools/testing/selftests/net/sctp_vrf.sh index c721e952e5f3..c854034b6aa1 100755 --- a/tools/testing/selftests/net/sctp_vrf.sh +++ b/tools/testing/selftests/net/sctp_vrf.sh @@ -6,13 +6,11 @@ # SERVER_NS # CLIENT_NS2 (veth1) <---> (veth2) -> vrf_s2 -CLIENT_NS1="client-ns1" -CLIENT_NS2="client-ns2" +source lib.sh CLIENT_IP4="10.0.0.1" CLIENT_IP6="2000::1" CLIENT_PORT=1234 -SERVER_NS="server-ns" SERVER_IP4="10.0.0.2" SERVER_IP6="2000::2" SERVER_PORT=1234 @@ -20,9 +18,7 @@ SERVER_PORT=1234 setup() { modprobe sctp modprobe sctp_diag - ip netns add $CLIENT_NS1 - ip netns add $CLIENT_NS2 - ip netns add $SERVER_NS + setup_ns CLIENT_NS1 CLIENT_NS2 SERVER_NS ip net exec $CLIENT_NS1 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null ip net exec $CLIENT_NS2 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null @@ -67,9 +63,7 @@ setup() { cleanup() { ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null - ip netns del "$CLIENT_NS1" - ip netns del "$CLIENT_NS2" - ip netns del "$SERVER_NS" + cleanup_ns $CLIENT_NS1 $CLIENT_NS2 $SERVER_NS } wait_server() { From 0f4765d0b48d90ede9788c7edb2e072eee20f88e Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 2 Dec 2023 10:01:10 +0800 Subject: [PATCH 2572/7721] selftests/net: convert unicast_extensions.sh to run it in unique namespace Here is the test result after conversion. # ./unicast_extensions.sh /usr/bin/which: no nettest in (/root/.local/bin:/root/bin:/usr/share/Modules/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin) ########################################################################### Unicast address extensions tests (behavior of reserved IPv4 addresses) ########################################################################### TEST: assign and ping within 240/4 (1 of 2) (is allowed) [ OK ] TEST: assign and ping within 240/4 (2 of 2) (is allowed) [ OK ] TEST: assign and ping within 0/8 (1 of 2) (is allowed) [ OK ] ... TEST: assign and ping class D address (is forbidden) [ OK ] TEST: routing using class D (is forbidden) [ OK ] TEST: routing using 127/8 (is forbidden) [ OK ] Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: Paolo Abeni --- .../selftests/net/unicast_extensions.sh | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/tools/testing/selftests/net/unicast_extensions.sh b/tools/testing/selftests/net/unicast_extensions.sh index 2d10ccac898a..b7a2cb9e7477 100755 --- a/tools/testing/selftests/net/unicast_extensions.sh +++ b/tools/testing/selftests/net/unicast_extensions.sh @@ -28,8 +28,7 @@ # These tests provide an easy way to flip the expected result of any # of these behaviors for testing kernel patches that change them. -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 +source ./lib.sh # nettest can be run from PATH or from same directory as this selftest if ! which nettest >/dev/null; then @@ -61,20 +60,20 @@ _do_segmenttest(){ # foo --- bar # Arguments: ip_a ip_b prefix_length test_description # - # Caller must set up foo-ns and bar-ns namespaces + # Caller must set up $foo_ns and $bar_ns namespaces # containing linked veth devices foo and bar, # respectively. - ip -n foo-ns address add $1/$3 dev foo || return 1 - ip -n foo-ns link set foo up || return 1 - ip -n bar-ns address add $2/$3 dev bar || return 1 - ip -n bar-ns link set bar up || return 1 + ip -n $foo_ns address add $1/$3 dev foo || return 1 + ip -n $foo_ns link set foo up || return 1 + ip -n $bar_ns address add $2/$3 dev bar || return 1 + ip -n $bar_ns link set bar up || return 1 - ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1 - ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1 + ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1 + ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1 - nettest -B -N bar-ns -O foo-ns -r $1 || return 1 - nettest -B -N foo-ns -O bar-ns -r $2 || return 1 + nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1 + nettest -B -N $foo_ns -O $bar_ns -r $2 || return 1 return 0 } @@ -88,31 +87,31 @@ _do_route_test(){ # Arguments: foo_ip foo1_ip bar1_ip bar_ip prefix_len test_description # Displays test result and returns success or failure. - # Caller must set up foo-ns, bar-ns, and router-ns + # Caller must set up $foo_ns, $bar_ns, and $router_ns # containing linked veth devices foo-foo1, bar1-bar - # (foo in foo-ns, foo1 and bar1 in router-ns, and - # bar in bar-ns). + # (foo in $foo_ns, foo1 and bar1 in $router_ns, and + # bar in $bar_ns). - ip -n foo-ns address add $1/$5 dev foo || return 1 - ip -n foo-ns link set foo up || return 1 - ip -n foo-ns route add default via $2 || return 1 - ip -n bar-ns address add $4/$5 dev bar || return 1 - ip -n bar-ns link set bar up || return 1 - ip -n bar-ns route add default via $3 || return 1 - ip -n router-ns address add $2/$5 dev foo1 || return 1 - ip -n router-ns link set foo1 up || return 1 - ip -n router-ns address add $3/$5 dev bar1 || return 1 - ip -n router-ns link set bar1 up || return 1 + ip -n $foo_ns address add $1/$5 dev foo || return 1 + ip -n $foo_ns link set foo up || return 1 + ip -n $foo_ns route add default via $2 || return 1 + ip -n $bar_ns address add $4/$5 dev bar || return 1 + ip -n $bar_ns link set bar up || return 1 + ip -n $bar_ns route add default via $3 || return 1 + ip -n $router_ns address add $2/$5 dev foo1 || return 1 + ip -n $router_ns link set foo1 up || return 1 + ip -n $router_ns address add $3/$5 dev bar1 || return 1 + ip -n $router_ns link set bar1 up || return 1 - echo 1 | ip netns exec router-ns tee /proc/sys/net/ipv4/ip_forward + echo 1 | ip netns exec $router_ns tee /proc/sys/net/ipv4/ip_forward - ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1 - ip netns exec foo-ns timeout 2 ping -c 1 $4 || return 1 - ip netns exec bar-ns timeout 2 ping -c 1 $3 || return 1 - ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1 + ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1 + ip netns exec $foo_ns timeout 2 ping -c 1 $4 || return 1 + ip netns exec $bar_ns timeout 2 ping -c 1 $3 || return 1 + ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1 - nettest -B -N bar-ns -O foo-ns -r $1 || return 1 - nettest -B -N foo-ns -O bar-ns -r $4 || return 1 + nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1 + nettest -B -N $foo_ns -O $bar_ns -r $4 || return 1 return 0 } @@ -121,17 +120,15 @@ segmenttest(){ # Sets up veth link and tries to connect over it. # Arguments: ip_a ip_b prefix_len test_description hide_output - ip netns add foo-ns - ip netns add bar-ns - ip link add foo netns foo-ns type veth peer name bar netns bar-ns + setup_ns foo_ns bar_ns + ip link add foo netns $foo_ns type veth peer name bar netns $bar_ns test_result=0 _do_segmenttest "$@" || test_result=1 - ip netns pids foo-ns | xargs -r kill -9 - ip netns pids bar-ns | xargs -r kill -9 - ip netns del foo-ns - ip netns del bar-ns + ip netns pids $foo_ns | xargs -r kill -9 + ip netns pids $bar_ns | xargs -r kill -9 + cleanup_ns $foo_ns $bar_ns show_output # inverted tests will expect failure instead of success @@ -147,21 +144,17 @@ route_test(){ # Returns success or failure. hide_output - ip netns add foo-ns - ip netns add bar-ns - ip netns add router-ns - ip link add foo netns foo-ns type veth peer name foo1 netns router-ns - ip link add bar netns bar-ns type veth peer name bar1 netns router-ns + setup_ns foo_ns bar_ns router_ns + ip link add foo netns $foo_ns type veth peer name foo1 netns $router_ns + ip link add bar netns $bar_ns type veth peer name bar1 netns $router_ns test_result=0 _do_route_test "$@" || test_result=1 - ip netns pids foo-ns | xargs -r kill -9 - ip netns pids bar-ns | xargs -r kill -9 - ip netns pids router-ns | xargs -r kill -9 - ip netns del foo-ns - ip netns del bar-ns - ip netns del router-ns + ip netns pids $foo_ns | xargs -r kill -9 + ip netns pids $bar_ns | xargs -r kill -9 + ip netns pids $router_ns | xargs -r kill -9 + cleanup_ns $foo_ns $bar_ns $router_ns show_output From 235a59c373b15e84df1a254c96066fc5fc47ae41 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Dec 2023 12:57:06 +0100 Subject: [PATCH 2573/7721] mips: remove extraneous asm-generic/iomap.h include When this file is included before defining readq(), it misses the declarations for a couple of functions that now become unusable: lib/iomap.c:156:5: warning: no previous prototype for 'ioread64_lo_hi' [-Wmissing-prototypes] lib/iomap.c:163:5: warning: no previous prototype for 'ioread64_hi_lo' [-Wmissing-prototypes] lib/iomap.c:170:5: warning: no previous prototype for 'ioread64be_lo_hi' [-Wmissing-prototypes] lib/iomap.c:178:5: warning: no previous prototype for 'ioread64be_hi_lo' [-Wmissing-prototypes] lib/iomap.c:264:6: warning: no previous prototype for 'iowrite64_lo_hi' [-Wmissing-prototypes] lib/iomap.c:272:6: warning: no previous prototype for 'iowrite64_hi_lo' [-Wmissing-prototypes] lib/iomap.c:280:6: warning: no previous prototype for 'iowrite64be_lo_hi' [-Wmissing-prototypes] lib/iomap.c:288:6: warning: no previous prototype for 'iowrite64be_hi_lo' [-Wmissing-prototypes] The file is included again later from asm-generic/io.h, so dropping the initial include statement makes it do the right thing, both for avoiding the warning and for actually providing these functions. Link: https://lkml.kernel.org/r/20231204115710.2247097-17-arnd@kernel.org Signed-off-by: Arnd Bergmann Cc: Stephen Rothwell Cc: Thomas Bogendoerfer --- arch/mips/include/asm/io.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index b0866100baf2..85bbd967e05f 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -187,8 +187,6 @@ void iounmap(const volatile void __iomem *addr); #define ioremap_wc(offset, size) \ ioremap_prot((offset), (size), boot_cpu_data.writecombine) -#include - #if defined(CONFIG_CPU_CAVIUM_OCTEON) #define war_io_reorder_wmb() wmb() #else From da4382a7207e7d2243b860146442243a8daf33de Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Nov 2023 14:28:14 +0100 Subject: [PATCH 2574/7721] ARC: mm: Make virt_to_pfn() a static inline Making virt_to_pfn() a static inline taking a strongly typed (const void *) makes the contract of a passing a pointer of that type to the function explicit and exposes any misuse of the macro virt_to_pfn() acting polymorphic and accepting many types such as (void *), (unitptr_t) or (unsigned long) as arguments without warnings. In order to do this we move the virt_to_phys() and below the definition of the __pa() and __va() macros so it compiles. The macro version was also able to do recursive symbol resolution. Signed-off-by: Linus Walleij Signed-off-by: Arnd Bergmann --- arch/arc/include/asm/page.h | 21 ++++++++++++--------- arch/arc/include/asm/pgtable-levels.h | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 02b53ad811fb..def0dfb95b43 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -84,15 +84,6 @@ typedef struct { typedef struct page *pgtable_t; -/* - * Use virt_to_pfn with caution: - * If used in pte or paddr related macros, it could cause truncation - * in PAE40 builds - * As a rule of thumb, only use it in helpers starting with virt_ - * You have been warned ! - */ -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) - /* * When HIGHMEM is enabled we have holes in the memory map so we need * pfn_valid() that takes into account the actual extents of the physical @@ -122,6 +113,18 @@ extern int pfn_valid(unsigned long pfn); #define __pa(vaddr) ((unsigned long)(vaddr)) #define __va(paddr) ((void *)((unsigned long)(paddr))) +/* + * Use virt_to_pfn with caution: + * If used in pte or paddr related macros, it could cause truncation + * in PAE40 builds + * As a rule of thumb, only use it in helpers starting with virt_ + * You have been warned ! + */ +static inline unsigned long virt_to_pfn(const void *kaddr) +{ + return __pa(kaddr) >> PAGE_SHIFT; +} + #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) diff --git a/arch/arc/include/asm/pgtable-levels.h b/arch/arc/include/asm/pgtable-levels.h index fc417c75c24d..86e148226463 100644 --- a/arch/arc/include/asm/pgtable-levels.h +++ b/arch/arc/include/asm/pgtable-levels.h @@ -159,7 +159,7 @@ #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) #define pmd_pfn(pmd) ((pmd_val(pmd) & PAGE_MASK) >> PAGE_SHIFT) -#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd)) +#define pmd_page(pmd) virt_to_page((void *)pmd_page_vaddr(pmd)) #define set_pmd(pmdp, pmd) (*(pmdp) = pmd) #define pmd_pgtable(pmd) ((pgtable_t) pmd_page(pmd)) From d6e81532b10d8deb2bc30f7b44f09534876893e3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Nov 2023 14:28:15 +0100 Subject: [PATCH 2575/7721] Hexagon: Make pfn accessors statics inlines Making virt_to_pfn() a static inline taking a strongly typed (const void *) makes the contract of a passing a pointer of that type to the function explicit and exposes any misuse of the macro virt_to_pfn() acting polymorphic and accepting many types such as (void *), (unitptr_t) or (unsigned long) as arguments without warnings. For symmetry do the same with pfn_to_virt(). For compiletime resolution of __pa() we need PAGE_OFFSET which was not available to __pa() and resolved by the preprocessor wherever __pa() was used. Fix this by explicitly including where required, following the pattern of the architectures page.h file. Acked-by: Brian Cain Signed-off-by: Linus Walleij Signed-off-by: Arnd Bergmann --- arch/hexagon/include/asm/page.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h index 9c03b9965f07..10f1bc07423c 100644 --- a/arch/hexagon/include/asm/page.h +++ b/arch/hexagon/include/asm/page.h @@ -78,6 +78,9 @@ typedef struct page *pgtable_t; #define __pgd(x) ((pgd_t) { (x) }) #define __pgprot(x) ((pgprot_t) { (x) }) +/* Needed for PAGE_OFFSET used in the macro right below */ +#include + /* * We need a __pa and a __va routine for kernel space. * MIPS says they're only used during mem_init. @@ -125,8 +128,16 @@ static inline void clear_page(void *page) */ #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) +static inline unsigned long virt_to_pfn(const void *kaddr) +{ + return __pa(kaddr) >> PAGE_SHIFT; +} + +static inline void *pfn_to_virt(unsigned long pfn) +{ + return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT); +} + #define page_to_virt(page) __va(page_to_phys(page)) From c9d4affbe60a9597ca9df878b5c02bdb9a636e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Rodrigues?= Date: Thu, 2 Nov 2023 23:11:30 +0100 Subject: [PATCH 2576/7721] ARM: dts: imx: tqma7: add lm75a sensor (rev. 01xxx) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TQMa7x (revision 01xxx) uses a LM75A temperature sensor. The two sensors use different I2C addresses, so we can set both sensors simultaneously. Signed-off-by: João Rodrigues Reviewed-by: Bruno Thomsen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi b/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi index fe42b0a46831..3fc3130f9def 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi @@ -128,11 +128,16 @@ vgen6_reg: vldo4 { }; }; - /* NXP SE97BTP with temperature sensor + eeprom */ + /* LM75A temperature sensor, TQMa7x 01xx */ + lm75a: temperature-sensor@48 { + compatible = "national,lm75a"; + reg = <0x48>; + }; + + /* NXP SE97BTP with temperature sensor + eeprom, TQMa7x 02xx */ se97b: temperature-sensor-eeprom@1e { compatible = "nxp,se97b", "jedec,jc-42.4-temp"; reg = <0x1e>; - status = "okay"; }; /* ST M24C64 */ From cb297cc5e194a2ea3cb8aaf722005286ee42b011 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Sat, 2 Dec 2023 21:06:58 +0800 Subject: [PATCH 2577/7721] macvlan: implement .parse_protocol hook function in macvlan_hard_header_ops The .parse_protocol hook function in the macvlan_header_ops structure is not implemented. As a result, when the AF_PACKET family is used to send packets, skb->protocol will be set to 0. Macvlan is a device of type ARPHRD_ETHER (ether_setup). Therefore, use eth_header_parse_protocol function to obtain the protocol. Suggested-by: Eric Dumazet Signed-off-by: Zhengchao Shao Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231202130658.2266526-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni --- drivers/net/macvlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 88dd8a2245b0..a3cc665757e8 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -609,6 +609,7 @@ static const struct header_ops macvlan_hard_header_ops = { .parse = eth_header_parse, .cache = eth_header_cache, .cache_update = eth_header_cache_update, + .parse_protocol = eth_header_parse_protocol, }; static int macvlan_open(struct net_device *dev) From fb70136ded2e1ea3cde27d0393cfadab4240a141 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Sat, 2 Dec 2023 21:04:38 +0800 Subject: [PATCH 2578/7721] ipvlan: implement .parse_protocol hook function in ipvlan_header_ops The .parse_protocol hook function in the ipvlan_header_ops structure is not implemented. As a result, when the AF_PACKET family is used to send packets, skb->protocol will be set to 0. Ipvlan is a device of type ARPHRD_ETHER (ether_setup). Therefore, use eth_header_parse_protocol function to obtain the protocol. Signed-off-by: Zhengchao Shao Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20231202130438.2266343-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni --- drivers/net/ipvlan/ipvlan_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 57c79f5f2991..f28fd7b6b708 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -387,6 +387,7 @@ static const struct header_ops ipvlan_header_ops = { .parse = eth_header_parse, .cache = eth_header_cache, .cache_update = eth_header_cache_update, + .parse_protocol = eth_header_parse_protocol, }; static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) From 6da9a662154c8d55fd39820ca882d0646d526e53 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 4 Dec 2023 15:37:21 -0600 Subject: [PATCH 2579/7721] ASoC: rt722-sdca: Set lane_control_support for multilane The RT722 SDCA codec supports 3 data lanes, lane_control_support property has to be set to use additional two lanes. Reviewed-by: Jack Yu Reviewed-by: Rander Wang Signed-off-by: Chao Song Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204213721.197785-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt722-sdca-sdw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index a38ec5862214..e24b9cbdc10c 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -256,6 +256,9 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave) /* wake-up event */ prop->wake_capable = 1; + /* Three data lanes are supported by rt722-sdca codec */ + prop->lane_control_support = true; + return 0; } From 0be9595d8a1170474867b8ee2caf14394db45d8b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Dec 2023 10:17:40 +0000 Subject: [PATCH 2580/7721] ASoC: cs4271: Fix spelling mistake "retrieveing" -> "retrieving" There is a spelling mistake in a dev_err_probe error message. Fix it. Signed-off-by: Colin Ian King Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20231205101740.2820813-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 74a84832d958..e864188ae5eb 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -643,7 +643,7 @@ static int cs4271_common_probe(struct device *dev, cs4271->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); if (IS_ERR(cs4271->reset)) return dev_err_probe(dev, PTR_ERR(cs4271->reset), - "error retrieveing RESET GPIO\n"); + "error retrieving RESET GPIO\n"); gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset"); for (i = 0; i < ARRAY_SIZE(supply_names); i++) From f31c166a5027e927e5c032d40ef2e484d9ecd612 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 4 Dec 2023 15:44:07 -0600 Subject: [PATCH 2581/7721] ASoC: SOF: Intel: lnl: add core get and set support for dsp core Driver uses get and set ops to change the power state of dsp core. Closes: https://github.com/thesofproject/sof/issues/8478 Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231204214407.208528-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 4 ++++ sound/soc/sof/intel/mtl.c | 4 ++-- sound/soc/sof/intel/mtl.h | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 03308721ebd4..a095f5bcf50d 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -120,6 +120,10 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; + /* dsp core get/put */ + sof_lnl_ops.core_get = mtl_dsp_core_get; + sof_lnl_ops.core_put = mtl_dsp_core_put; + sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index f941e2c49d78..3121a89219dd 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -638,7 +638,7 @@ u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, return ((u64)llp_u << 32) | llp_l; } -static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) +int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; @@ -651,7 +651,7 @@ static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) return 0; } -static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) +int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; int ret; diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 95696b3d7c4c..cc5a1f46fd09 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -106,3 +106,6 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev); u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, struct snd_soc_component *component, struct snd_pcm_substream *substream); + +int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core); +int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core); From 144f1b70ea9ebebd21390bfcc78ba3192f12b0c1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 21 Nov 2023 14:34:45 +0800 Subject: [PATCH 2582/7721] dt-bindings: clock: support i.MX93 ANATOP clock module Support i.MX93 ANATOP module which contains PLL and OSC for Clock Controller Module Reviewed-by: Conor Dooley Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20231121063446.155300-1-peng.fan@oss.nxp.com [abel.vesa@linaro.org: renamed to ANATOP instead of Analog] Signed-off-by: Abel Vesa --- .../bindings/clock/fsl,imx93-anatop.yaml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml diff --git a/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml new file mode 100644 index 000000000000..8a3b2476419a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/fsl,imx93-anatop.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX93 ANATOP Clock Module + +maintainers: + - Peng Fan + +description: | + NXP i.MX93 ANATOP module which contains PLL and OSC to Clock Controller + Module. + +properties: + compatible: + items: + - const: fsl,imx93-anatop + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@44480000 { + compatible = "fsl,imx93-anatop"; + reg = <0x44480000 0x2000>; + #clock-cells = <1>; + }; + +... From 1b4c7e20bfd6cfe0efbc51756d930a9406d41ea7 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Mon, 4 Dec 2023 13:17:22 -0800 Subject: [PATCH 2583/7721] selftests/bpf: Test bpf_kptr_xchg stashing of bpf_rb_root There was some confusion amongst Meta sched_ext folks regarding whether stashing bpf_rb_root - the tree itself, rather than a single node - was supported. This patch adds a small test which demonstrates this functionality: a local kptr with rb_root is created, a node is created and added to the tree, then the tree is kptr_xchg'd into a mapval. Signed-off-by: Dave Marchevsky Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20231204211722.571346-1-davemarchevsky@fb.com --- .../bpf/prog_tests/local_kptr_stash.c | 23 ++++++++ .../selftests/bpf/progs/local_kptr_stash.c | 53 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c index e6e50a394472..827e713f6cf1 100644 --- a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c @@ -48,6 +48,27 @@ static void test_local_kptr_stash_plain(void) local_kptr_stash__destroy(skel); } +static void test_local_kptr_stash_local_with_root(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_in = &pkt_v4, + .data_size_in = sizeof(pkt_v4), + .repeat = 1, + ); + struct local_kptr_stash *skel; + int ret; + + skel = local_kptr_stash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) + return; + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_local_with_root), &opts); + ASSERT_OK(ret, "local_kptr_stash_add_local_with_root run"); + ASSERT_OK(opts.retval, "local_kptr_stash_add_local_with_root retval"); + + local_kptr_stash__destroy(skel); +} + static void test_local_kptr_stash_unstash(void) { LIBBPF_OPTS(bpf_test_run_opts, opts, @@ -115,6 +136,8 @@ void test_local_kptr_stash(void) test_local_kptr_stash_simple(); if (test__start_subtest("local_kptr_stash_plain")) test_local_kptr_stash_plain(); + if (test__start_subtest("local_kptr_stash_local_with_root")) + test_local_kptr_stash_local_with_root(); if (test__start_subtest("local_kptr_stash_unstash")) test_local_kptr_stash_unstash(); if (test__start_subtest("refcount_acquire_without_unstash")) diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash.c b/tools/testing/selftests/bpf/progs/local_kptr_stash.c index 1769fdff6aea..75043ffc5dad 100644 --- a/tools/testing/selftests/bpf/progs/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/progs/local_kptr_stash.c @@ -37,11 +37,18 @@ struct plain_local { long data; }; +struct local_with_root { + long key; + struct bpf_spin_lock l; + struct bpf_rb_root r __contains(node_data, node); +}; + struct map_value { struct prog_test_ref_kfunc *not_kptr; struct prog_test_ref_kfunc __kptr *val; struct node_data __kptr *node; struct plain_local __kptr *plain; + struct local_with_root __kptr *local_root; }; /* This is necessary so that LLVM generates BTF for node_data struct @@ -65,6 +72,17 @@ struct { __uint(max_entries, 2); } some_nodes SEC(".maps"); +static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) +{ + struct node_data *node_a; + struct node_data *node_b; + + node_a = container_of(a, struct node_data, node); + node_b = container_of(b, struct node_data, node); + + return node_a->key < node_b->key; +} + static int create_and_stash(int idx, int val) { struct map_value *mapval; @@ -113,6 +131,41 @@ long stash_plain(void *ctx) return 0; } +SEC("tc") +long stash_local_with_root(void *ctx) +{ + struct local_with_root *res; + struct map_value *mapval; + struct node_data *n; + int idx = 0; + + mapval = bpf_map_lookup_elem(&some_nodes, &idx); + if (!mapval) + return 1; + + res = bpf_obj_new(typeof(*res)); + if (!res) + return 2; + res->key = 41; + + n = bpf_obj_new(typeof(*n)); + if (!n) { + bpf_obj_drop(res); + return 3; + } + + bpf_spin_lock(&res->l); + bpf_rbtree_add(&res->r, &n->node, less); + bpf_spin_unlock(&res->l); + + res = bpf_kptr_xchg(&mapval->local_root, res); + if (res) { + bpf_obj_drop(res); + return 4; + } + return 0; +} + SEC("tc") long unstash_rb_node(void *ctx) { From 5c399ae080ae507954f6f2efefc7349f8ed0e051 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 4 Dec 2023 09:42:31 -0800 Subject: [PATCH 2584/7721] xsk: Add missing SPDX to AF_XDP TX metadata documentation Not sure how I missed that. I even acknowledged it explicitly in the changelog [0]. Add the tag for real now. [0] https://lore.kernel.org/bpf/20231127190319.1190813-1-sdf@google.com/ Fixes: 11614723af26 ("xsk: Add option to calculate TX checksum in SW") Suggested-by: Simon Horman Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231204174231.3457705-1-sdf@google.com --- Documentation/networking/xsk-tx-metadata.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst index 97ecfa480d00..bd033fe95cca 100644 --- a/Documentation/networking/xsk-tx-metadata.rst +++ b/Documentation/networking/xsk-tx-metadata.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + ================== AF_XDP TX Metadata ================== From 5ffb260f754bf838507fe0c23d05254b33e2bf3d Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 4 Dec 2023 09:44:23 -0800 Subject: [PATCH 2585/7721] selftests/bpf: Make sure we trigger metadata kfuncs for dst 8080 xdp_metadata test is flaky sometimes: verify_xsk_metadata:FAIL:rx_hash_type unexpected rx_hash_type: actual 8 != expected 0 Where 8 means XDP_RSS_TYPE_L4_ANY and is exported from veth driver only when 'skb->l4_hash' condition is met. This makes me think that the program is triggering again for some other packet. Let's have a filter, similar to xdp_hw_metadata, where we trigger XDP kfuncs only for UDP packets destined to port 8080. Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20231204174423.3460052-1-sdf@google.com --- .../selftests/bpf/progs/xdp_metadata.c | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/xdp_metadata.c b/tools/testing/selftests/bpf/progs/xdp_metadata.c index d151d406a123..5d6c1245c310 100644 --- a/tools/testing/selftests/bpf/progs/xdp_metadata.c +++ b/tools/testing/selftests/bpf/progs/xdp_metadata.c @@ -27,11 +27,40 @@ extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash, SEC("xdp") int rx(struct xdp_md *ctx) { - void *data, *data_meta; + void *data, *data_meta, *data_end; + struct ipv6hdr *ip6h = NULL; + struct ethhdr *eth = NULL; + struct udphdr *udp = NULL; + struct iphdr *iph = NULL; struct xdp_meta *meta; u64 timestamp = -1; int ret; + data = (void *)(long)ctx->data; + data_end = (void *)(long)ctx->data_end; + eth = data; + if (eth + 1 < data_end) { + if (eth->h_proto == bpf_htons(ETH_P_IP)) { + iph = (void *)(eth + 1); + if (iph + 1 < data_end && iph->protocol == IPPROTO_UDP) + udp = (void *)(iph + 1); + } + if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { + ip6h = (void *)(eth + 1); + if (ip6h + 1 < data_end && ip6h->nexthdr == IPPROTO_UDP) + udp = (void *)(ip6h + 1); + } + if (udp && udp + 1 > data_end) + udp = NULL; + } + + if (!udp) + return XDP_PASS; + + /* Forwarding UDP:8080 to AF_XDP */ + if (udp->dest != bpf_htons(8080)) + return XDP_PASS; + /* Reserve enough for all custom metadata. */ ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct xdp_meta)); From 1b66601d14161f8128760742236eb26324f04fb9 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2586/7721] wifi: ath12k: get msi_data again after request_irq is called The reservation mode of interrupts in kernel assigns a dummy vector when the interrupt is allocated and assigns a real vector when the request_irq is called. The reservation mode helps to ease vector pressure when devices with a large amount of queues/interrupts are initialized, but only a minimal subset of those queues/interrupts is actually used. So on reservation mode, the msi_data may change after request_irq is called, then it will lead to spurious interrupt. But when VT-d in BIOS is enabled and ath12k can get 32 MSI vectors, ath12k always get the same msi_data before and after request_irq. So in case of one MSI vector, ath12k need read msi_data again after request_irq is called, and then the correct msi_data is programmed into WCN7850 hardware components. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-2-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index a6a5f9bcffbd..cab68540b6b1 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -708,6 +708,25 @@ static void ath12k_pci_msi_free(struct ath12k_pci *ab_pci) pci_free_irq_vectors(ab_pci->pdev); } +static int ath12k_pci_config_msi_data(struct ath12k_pci *ab_pci) +{ + struct msi_desc *msi_desc; + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { + ath12k_err(ab_pci->ab, "msi_desc is NULL!\n"); + pci_free_irq_vectors(ab_pci->pdev); + return -EINVAL; + } + + ab_pci->msi_ep_base_data = msi_desc->msg.data; + + ath12k_dbg(ab_pci->ab, ATH12K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", + ab_pci->msi_ep_base_data); + + return 0; +} + static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev) { struct ath12k_base *ab = ab_pci->ab; @@ -1286,6 +1305,17 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_ce_free; } + /* kernel may allocate a dummy vector before request_irq and + * then allocate a real vector when request_irq is called. + * So get msi_data here again to avoid spurious interrupt + * as msi_data will configured to srngs. + */ + ret = ath12k_pci_config_msi_data(ab_pci); + if (ret) { + ath12k_err(ab, "failed to config msi_data: %d\n", ret); + goto err_free_irq; + } + ret = ath12k_core_init(ab); if (ret) { ath12k_err(ab, "failed to init core: %d\n", ret); From 604308a34487eaa382c50fcdb4396c435030b4fa Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2587/7721] wifi: ath12k: add CE and ext IRQ flag to indicate irq_handler Add two flags to indicate whether IRQ handler for CE and DP can be called. This is because in one MSI vector case, interrupt is not disabled in hif_stop and hif_irq_disable. So if interrupt is disabled, MHI interrupt is disabled too. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-3-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/pci.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 6dbe817d2ec7..8458dc292821 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -199,6 +199,8 @@ enum ath12k_dev_flags { ATH12K_FLAG_REGISTERED, ATH12K_FLAG_QMI_FAIL, ATH12K_FLAG_HTC_SUSPEND_COMPLETE, + ATH12K_FLAG_CE_IRQ_ENABLED, + ATH12K_FLAG_EXT_IRQ_ENABLED, }; enum ath12k_monitor_flags { diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index cab68540b6b1..b22859cec9bf 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -373,6 +373,8 @@ static void ath12k_pci_ce_irqs_disable(struct ath12k_base *ab) { int i; + clear_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params->ce_count; i++) { if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -406,6 +408,10 @@ static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) { struct ath12k_ce_pipe *ce_pipe = arg; + struct ath12k_base *ab = ce_pipe->ab; + + if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; /* last interrupt received for this CE */ ce_pipe->timestamp = jiffies; @@ -428,6 +434,8 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) { int i; + clear_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -483,6 +491,10 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) { struct ath12k_ext_irq_grp *irq_grp = arg; + struct ath12k_base *ab = irq_grp->ab; + + if (!test_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; ath12k_dbg(irq_grp->ab, ATH12K_DBG_PCI, "ext irq:%d\n", irq); @@ -626,6 +638,8 @@ static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab) { int i; + set_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params->ce_count; i++) { if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -975,6 +989,8 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) { int i; + set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; From 1f1f7d548a00ebe50808cb1f580df9693e194a7c Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2588/7721] wifi: ath12k: use ATH12K_PCI_IRQ_DP_OFFSET for DP IRQ Like ATH12K_PCI_IRQ_CE0_OFFSET, define ATH12K_PCI_IRQ_DP_OFFSET for DP to save the IRQ instead of base_vector from MSI config. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-4-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index b22859cec9bf..9c8dfa002760 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -17,7 +17,8 @@ #define ATH12K_PCI_BAR_NUM 0 #define ATH12K_PCI_DMA_MASK 32 -#define ATH12K_PCI_IRQ_CE0_OFFSET 3 +#define ATH12K_PCI_IRQ_CE0_OFFSET 3 +#define ATH12K_PCI_IRQ_DP_OFFSET 14 #define WINDOW_ENABLE_BIT 0x40000000 #define WINDOW_REG_ADDRESS 0x310c @@ -511,9 +512,8 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) { int i, j, ret, num_vectors = 0; - u32 user_base_data = 0, base_vector = 0, base_idx; + u32 user_base_data = 0, base_vector = 0; - base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; ret = ath12k_pci_get_user_msi_assignment(ab, "DP", &num_vectors, &user_base_data, @@ -542,7 +542,7 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) } irq_grp->num_irq = num_irq; - irq_grp->irqs[0] = base_idx + i; + irq_grp->irqs[0] = ATH12K_PCI_IRQ_DP_OFFSET + i; for (j = 0; j < irq_grp->num_irq; j++) { int irq_idx = irq_grp->irqs[j]; From 6711b2a80b9a9bf7d10042a526b1f92a5ba69362 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2589/7721] wifi: ath12k: refactor multiple MSI vector implementation This is to prepare for one MSI vector support. IRQ enable and disable of CE and DP are done only in case of multiple MSI vectors. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-5-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 48 ++++++++++++++++++++++----- drivers/net/wireless/ath/ath12k/pci.h | 2 ++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 9c8dfa002760..30be938e168a 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -356,16 +356,30 @@ static void ath12k_pci_free_irq(struct ath12k_base *ab) static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id; enable_irq(ab->irq_num[irq_idx]); } static void ath12k_pci_ce_irq_disable(struct ath12k_base *ab, u16 ce_id) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id; disable_irq_nosync(ab->irq_num[irq_idx]); } @@ -425,8 +439,15 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) static void ath12k_pci_ext_grp_disable(struct ath12k_ext_irq_grp *irq_grp) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable + * in a uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -449,8 +470,15 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) static void ath12k_pci_ext_grp_enable(struct ath12k_ext_irq_grp *irq_grp) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -511,6 +539,7 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); int i, j, ret, num_vectors = 0; u32 user_base_data = 0, base_vector = 0; @@ -556,16 +585,15 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); ret = request_irq(irq, ath12k_pci_ext_interrupt_handler, - IRQF_SHARED, + ab_pci->irq_flags, "DP_EXT_IRQ", irq_grp); if (ret) { ath12k_err(ab, "failed request irq %d: %d\n", vector, ret); return ret; } - - disable_irq_nosync(ab->irq_num[irq_idx]); } + ath12k_pci_ext_grp_disable(irq_grp); } return 0; @@ -573,6 +601,7 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) static int ath12k_pci_config_irq(struct ath12k_base *ab) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); struct ath12k_ce_pipe *ce_pipe; u32 msi_data_start; u32 msi_data_count, msi_data_idx; @@ -601,7 +630,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab) tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet); ret = request_irq(irq, ath12k_pci_ce_interrupt_handler, - IRQF_SHARED, irq_name[irq_idx], + ab_pci->irq_flags, irq_name[irq_idx], ce_pipe); if (ret) { ath12k_err(ab, "failed to request irq %d: %d\n", @@ -692,6 +721,9 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci) return -EINVAL; else return num_vectors; + } else { + set_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->irq_flags = IRQF_SHARED; } ath12k_pci_msi_disable(ab_pci); @@ -924,11 +956,11 @@ int ath12k_pci_get_user_msi_assignment(struct ath12k_base *ab, char *user_name, for (idx = 0; idx < msi_config->total_users; idx++) { if (strcmp(user_name, msi_config->users[idx].name) == 0) { *num_vectors = msi_config->users[idx].num_vectors; - *user_base_data = msi_config->users[idx].base_vector - + ab_pci->msi_ep_base_data; - *base_vector = msi_config->users[idx].base_vector; + *base_vector = msi_config->users[idx].base_vector; + *user_base_data = *base_vector + ab_pci->msi_ep_base_data; - ath12k_dbg(ab, ATH12K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + ath12k_dbg(ab, ATH12K_DBG_PCI, + "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", user_name, *num_vectors, *user_base_data, *base_vector); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 9a17a7dcdd6a..b2edf32ada20 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -84,6 +84,7 @@ enum ath12k_pci_flags { ATH12K_PCI_FLAG_INIT_DONE, ATH12K_PCI_FLAG_IS_MSI_64, ATH12K_PCI_ASPM_RESTORE, + ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, }; struct ath12k_pci_ops { @@ -108,6 +109,7 @@ struct ath12k_pci { /* enum ath12k_pci_flags */ unsigned long flags; u16 link_ctl; + unsigned long irq_flags; const struct ath12k_pci_ops *pci_ops; }; From 8398654398c2a97d28a3f0cc97e9a1f2e99113b9 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2590/7721] wifi: ath12k: add support one MSI vector On some platforms it's not possible to allocate 32 MSI vectors for various reasons, maybe kernel configuration, VT-d disabled, buggy BIOS etc. So ath12k was not able to use WCN7850 PCI devices on those platforms. Add support for one MSI vector to solve that. In case of one MSI vector, interrupt migration needs to be disabled. This is because when interrupt migration happens, the msi_data may change. However, msi_data is already programmed to rings during initial phase and ath12k has no way to know that msi_data is changed during run time and reprogram again. In case of one MSI vector, MHI subsystem should not use IRQF_NO_SUSPEND as WCN7850 doesn't set this flag too. Ath12k doesn't need to leave IRQ enabled in suspend state. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-6-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mhi.c | 16 +++++++-- drivers/net/wireless/ath/ath12k/pci.c | 51 ++++++++++++++++++++------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 27eb38b2b1bd..d5441ddb374b 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -251,6 +251,7 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) u32 user_base_data, base_vector; int ret, num_vectors, i; int *irq; + unsigned int msi_data; ret = ath12k_pci_get_user_msi_assignment(ab, "MHI", &num_vectors, @@ -265,9 +266,15 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) if (!irq) return -ENOMEM; - for (i = 0; i < num_vectors; i++) - irq[i] = ath12k_pci_get_msi_irq(ab->dev, - base_vector + i); + msi_data = base_vector; + for (i = 0; i < num_vectors; i++) { + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + irq[i] = ath12k_pci_get_msi_irq(ab->dev, + msi_data++); + else + irq[i] = ath12k_pci_get_msi_irq(ab->dev, + msi_data); + } ab_pci->mhi_ctrl->irq = irq; ab_pci->mhi_ctrl->nr_irqs = num_vectors; @@ -374,6 +381,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) goto free_controller; } + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + mhi_ctrl->iova_start = 0; mhi_ctrl->iova_stop = 0xffffffff; mhi_ctrl->sbl_size = SZ_512K; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 30be938e168a..32dcf91e0a06 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -61,6 +61,17 @@ static const struct ath12k_msi_config ath12k_msi_config[] = { }, }; +static const struct ath12k_msi_config msi_config_one_msi = { + .total_vectors = 1, + .total_users = 4, + .users = (struct ath12k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 1, .base_vector = 0 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, + { .name = "DP", .num_vectors = 1, .base_vector = 0 }, + }, +}; + static const char *irq_name[ATH12K_IRQ_NUM_MAX] = { "bhi", "mhi-er0", @@ -414,16 +425,18 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab) static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) { struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); - ath12k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); + enable_irq(ce_pipe->ab->irq_num[irq_idx]); } static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) { struct ath12k_ce_pipe *ce_pipe = arg; struct ath12k_base *ab = ce_pipe->ab; + int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) return IRQ_HANDLED; @@ -431,7 +444,8 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) /* last interrupt received for this CE */ ce_pipe->timestamp = jiffies; - ath12k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); + disable_irq_nosync(ab->irq_num[irq_idx]); + tasklet_schedule(&ce_pipe->intr_tq); return IRQ_HANDLED; @@ -504,11 +518,13 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) napi); struct ath12k_base *ab = irq_grp->ab; int work_done; + int i; work_done = ath12k_dp_service_srng(ab, irq_grp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); - ath12k_pci_ext_grp_enable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } if (work_done > budget) @@ -521,6 +537,7 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) { struct ath12k_ext_irq_grp *irq_grp = arg; struct ath12k_base *ab = irq_grp->ab; + int i; if (!test_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) return IRQ_HANDLED; @@ -530,7 +547,8 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) /* last interrupt received for this group */ irq_grp->timestamp = jiffies; - ath12k_pci_ext_grp_disable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); napi_schedule(&irq_grp->napi); @@ -713,19 +731,27 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci) msi_config->total_vectors, msi_config->total_vectors, PCI_IRQ_MSI); - if (num_vectors != msi_config->total_vectors) { - ath12k_err(ab, "failed to get %d MSI vectors, only %d available", - msi_config->total_vectors, num_vectors); - if (num_vectors >= 0) - return -EINVAL; - else - return num_vectors; - } else { + if (num_vectors == msi_config->total_vectors) { set_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ab_pci->irq_flags = IRQF_SHARED; + } else { + num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, + 1, + 1, + PCI_IRQ_MSI); + if (num_vectors < 0) { + ret = -EINVAL; + goto reset_msi_config; + } + clear_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->msi_config = &msi_config_one_msi; + ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + ath12k_dbg(ab, ATH12K_DBG_PCI, "request MSI one vector\n"); } + ath12k_info(ab, "MSI vectors: %d\n", num_vectors); + ath12k_pci_msi_disable(ab_pci); msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); @@ -746,6 +772,7 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci) free_msi_vector: pci_free_irq_vectors(ab_pci->pdev); +reset_msi_config: return ret; } From 08d52ba2967898723bf6fc57a9fb5dc0018cc5bc Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:47 +0200 Subject: [PATCH 2591/7721] wifi: ath12k: do not restore ASPM in case of single MSI vector Current code enables ASPM by default, it allows MHI to enter M2 state. In case of one MSI vector, system hang is observed if ath12k does MHI register reading in this state. The workaround here is to prevent MHI from entering M2 state, this can be done by disabling ASPM if only one MSI vector is used. When using 32 vectors ASPM is enabled as before. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-7-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 32dcf91e0a06..2d9ef7add95f 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1094,7 +1094,10 @@ int ath12k_pci_start(struct ath12k_base *ab) set_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags); - ath12k_pci_aspm_restore(ab_pci); + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + ath12k_pci_aspm_restore(ab_pci); + else + ath12k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ath12k_pci_ce_irqs_enable(ab); ath12k_ce_rx_post_buf(ab); From a3012f206d07fa62b5c2e384cbc3a81a4dbba3c9 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:48 +0200 Subject: [PATCH 2592/7721] wifi: ath12k: set IRQ affinity to CPU0 in case of one MSI vector With VT-d disabled on Intel platform, ath12k gets only one MSI vector. In that case, ath12k does not free IRQ when doing suspend, hence the kernel has to migrate it to CPU0 (if it was affine to other CPUs) and allocates a new MSI vector. However, ath12k has no chance to reconfig it to HW srngs during this phase, thus ath12k fails to resume. This issue can be fixed by setting IRQ affinity to CPU0 before request_irq is called. With such affinity, migration will not happen and thus the vector keeps unchanged during suspend/resume. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121021304.12966-8-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 2d9ef7add95f..b11563754d16 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -617,6 +617,15 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) return 0; } +static int ath12k_pci_set_irq_affinity_hint(struct ath12k_pci *ab_pci, + const struct cpumask *m) +{ + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return 0; + + return irq_set_affinity_hint(ab_pci->pdev->irq, m); +} + static int ath12k_pci_config_irq(struct ath12k_base *ab) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); @@ -1359,10 +1368,16 @@ static int ath12k_pci_probe(struct pci_dev *pdev, if (ret) goto err_pci_msi_free; + ret = ath12k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); + if (ret) { + ath12k_err(ab, "failed to set irq affinity %d\n", ret); + goto err_pci_msi_free; + } + ret = ath12k_mhi_register(ab_pci); if (ret) { ath12k_err(ab, "failed to register mhi: %d\n", ret); - goto err_pci_msi_free; + goto err_irq_affinity_cleanup; } ret = ath12k_hal_srng_init(ab); @@ -1416,6 +1431,9 @@ static int ath12k_pci_probe(struct pci_dev *pdev, err_pci_msi_free: ath12k_pci_msi_free(ab_pci); +err_irq_affinity_cleanup: + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); + err_pci_free_region: ath12k_pci_free_region(ab_pci); @@ -1430,6 +1448,8 @@ static void ath12k_pci_remove(struct pci_dev *pdev) struct ath12k_base *ab = pci_get_drvdata(pdev); struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); + if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) { ath12k_pci_power_down(ab); ath12k_qmi_deinit_service(ab); @@ -1456,7 +1476,9 @@ static void ath12k_pci_remove(struct pci_dev *pdev) static void ath12k_pci_shutdown(struct pci_dev *pdev) { struct ath12k_base *ab = pci_get_drvdata(pdev); + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); ath12k_pci_power_down(ab); } From ed7e818a7b501012038d6bc6fedadaf7375a380a Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 1 Dec 2023 18:09:48 +0200 Subject: [PATCH 2593/7721] wifi: ath12k: fix and enable AP mode for WCN7850 For AP mode, the peer is created earlier in ath12k_mac_op_add_interface() but ath12k_mac_op_assign_vif_chanctx() will try to create peer again. Then an error will return which makes AP mode startup fail. Kernel log: [ 5017.665006] ath12k_pci 0000:04:00.0: failed to create peer after vdev start delay: -22 wpa_supplicant log: Failed to set beacon parameters Interface initialization failed wls1: interface state UNINITIALIZED->DISABLED wls1: AP-DISABLED wls1: Unable to setup interface. Failed to initialize AP interface wls1: interface state DISABLED->DISABLED wls1: AP-DISABLED So fix this check and enable AP mode for WCN7850, as now AP mode works normally. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231121022459.17209-1-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 3 ++- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index ea3eda1f1948..de60d988d860 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -949,7 +949,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rx_mac_buf_ring = true, .vdev_start_delay = true, - .interface_modes = BIT(NL80211_IFTYPE_STATION), + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), .supports_monitor = false, .idle_ps = true, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 556013f8c609..a27135436f41 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6389,8 +6389,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, } if (ab->hw_params->vdev_start_delay && - (arvif->vdev_type == WMI_VDEV_TYPE_AP || - arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)) { + arvif->vdev_type != WMI_VDEV_TYPE_AP && + arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { param.vdev_id = arvif->vdev_id; param.peer_type = WMI_PEER_TYPE_DEFAULT; param.peer_addr = ar->mac_addr; From c8a5f34ad811743d1b3aeb5c54198eebd413bc6d Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 1 Dec 2023 07:07:35 +0530 Subject: [PATCH 2594/7721] wifi: ath12k: avoid repeated wiphy access from hw Currently repeated access of wiphy data from mac80211 hw structure is happen inside the mac80211 registration helper functions. So optimize these helper functions by storing wiphy data locally and accessing it directly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231201013735.2292313-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 72 ++++++++++++++------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a27135436f41..88cec54c6c2e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7255,6 +7255,7 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; @@ -7305,8 +7306,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80); - hw->wiphy->iface_combinations = combinations; - hw->wiphy->n_iface_combinations = 1; + wiphy->iface_combinations = combinations; + wiphy->n_iface_combinations = 1; return 0; } @@ -7351,6 +7352,7 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { static void __ath12k_mac_unregister(struct ath12k *ar) { struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; cancel_work_sync(&ar->regd_update_work); @@ -7363,8 +7365,8 @@ static void __ath12k_mac_unregister(struct ath12k *ar) kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); - kfree(hw->wiphy->iface_combinations[0].limits); - kfree(hw->wiphy->iface_combinations); + kfree(wiphy->iface_combinations[0].limits); + kfree(wiphy->iface_combinations); SET_IEEE80211_DEV(hw, NULL); } @@ -7389,6 +7391,7 @@ static int __ath12k_mac_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; struct ath12k_pdev_cap *cap = &ar->pdev->cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, @@ -7424,14 +7427,14 @@ static int __ath12k_mac_register(struct ath12k *ar) goto err_free_channels; } - hw->wiphy->available_antennas_rx = cap->rx_chain_mask; - hw->wiphy->available_antennas_tx = cap->tx_chain_mask; + wiphy->available_antennas_rx = cap->rx_chain_mask; + wiphy->available_antennas_tx = cap->tx_chain_mask; - hw->wiphy->interface_modes = ab->hw_params->interface_modes; + wiphy->interface_modes = ab->hw_params->interface_modes; - if (hw->wiphy->bands[NL80211_BAND_2GHZ] && - hw->wiphy->bands[NL80211_BAND_5GHZ] && - hw->wiphy->bands[NL80211_BAND_6GHZ]) + if (wiphy->bands[NL80211_BAND_2GHZ] && + wiphy->bands[NL80211_BAND_5GHZ] && + wiphy->bands[NL80211_BAND_6GHZ]) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, SIGNAL_DBM); @@ -7457,60 +7460,59 @@ static int __ath12k_mac_register(struct ath12k *ar) ieee80211_hw_set(hw, USES_RSS); } - hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy->features |= NL80211_FEATURE_STATIC_SMPS; + wiphy->flags |= WIPHY_FLAG_IBSS_RSN; /* TODO: Check if HT capability advertised from firmware is different * for each band for a dual band capable radio. It will be tricky to * handle it when the ht capability different for each band. */ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) - hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; - hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; - hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; + wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; + wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; - hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - hw->wiphy->max_remain_on_channel_duration = 5000; + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->max_remain_on_channel_duration = 5000; - hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; ar->max_num_stations = TARGET_NUM_STATIONS; ar->max_num_peers = TARGET_NUM_PEERS_PDEV; - hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + wiphy->max_ap_assoc_sta = ar->max_num_stations; hw->queues = ATH12K_HW_MAX_QUEUES; - hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN; + wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; hw->vif_data_size = sizeof(struct ath12k_vif); hw->sta_data_size = sizeof(struct ath12k_sta); - wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); - wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); - hw->wiphy->cipher_suites = cipher_suites; - hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wiphy->cipher_suites = cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; - hw->wiphy->num_iftype_ext_capab = - ARRAY_SIZE(ath12k_iftypes_ext_capa); + wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); if (ar->supports_6ghz) { - wiphy_ext_feature_set(hw->wiphy, + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); - wiphy_ext_feature_set(hw->wiphy, + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); } - wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); ath12k_reg_init(hw); @@ -7532,7 +7534,7 @@ static int __ath12k_mac_register(struct ath12k *ar) * while. But that time is so short and in practise it make * a difference in real life. */ - hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); + wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); /* Apply the regd received during initialization */ ret = ath12k_regd_update(ar, true); @@ -7547,8 +7549,8 @@ static int __ath12k_mac_register(struct ath12k *ar) ieee80211_unregister_hw(hw); err_free_if_combs: - kfree(hw->wiphy->iface_combinations[0].limits); - kfree(hw->wiphy->iface_combinations); + kfree(wiphy->iface_combinations[0].limits); + kfree(wiphy->iface_combinations); err_free_channels: kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); From 138a4e2a26ec73197e22fe64ee3957b1594eabb3 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 5 Dec 2023 13:50:01 +0000 Subject: [PATCH 2595/7721] ASoC: Intel: sof_sdw_cs_amp: Connect outputs to a speaker widget Hookup the CS35L56 DAPM_OUTPUT widgets to a DAPM_SPK widget so that there is a complete logical path to a speaker. There is no particular reason to use multiple speaker widgets. The CS35L56 are designed to work together as a set so they have all been connected to a single speaker widget. Instead of a hardcoded list of codec widget names, the code walks through all the codecs on the dailink and for every cs35l56 it uses its name prefix to construct the source end of the route. This adds a small amount of overhead during probe but has the benefit that it isn't dependent on every system using the same prefixes. Signed-off-by: Richard Fitzgerald Acked-by: Pierre-Louis Bossart Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231205135001.2506070-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw_cs_amp.c | 30 +++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c index 98f6546f484b..f88c01552a92 100644 --- a/sound/soc/intel/boards/sof_sdw_cs_amp.c +++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c @@ -9,15 +9,24 @@ #include #include #include +#include #include "sof_sdw_common.h" #define CODEC_NAME_SIZE 8 +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), +}; + static int cs_spk_init(struct snd_soc_pcm_runtime *rtd) { const char *dai_name = rtd->dai_link->codecs->dai_name; struct snd_soc_card *card = rtd->card; char codec_name[CODEC_NAME_SIZE]; + char widget_name[16]; + struct snd_soc_dapm_route route = { "Speakers", NULL, widget_name }; + struct snd_soc_dai *codec_dai; + int i, ret; snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); card->components = devm_kasprintf(card->dev, GFP_KERNEL, @@ -26,17 +35,34 @@ static int cs_spk_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; + ret = snd_soc_dapm_new_controls(&card->dapm, sof_widgets, + ARRAY_SIZE(sof_widgets)); + if (ret) { + dev_err(card->dev, "widgets addition failed: %d\n", ret); + return ret; + } + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (!strstr(codec_dai->name, "cs35l56")) + continue; + + snprintf(widget_name, sizeof(widget_name), "%s SPK", + codec_dai->component->name_prefix); + ret = snd_soc_dapm_add_routes(&card->dapm, &route, 1); + if (ret) + return ret; + } + return 0; } - int sof_sdw_cs_amp_init(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, struct sof_sdw_codec_info *info, bool playback) { - /* Count amp number and do init on playback link only. */ + /* Do init on playback link only. */ if (!playback) return 0; From 1ac23674a971d8596648695f72168815c3f52e11 Mon Sep 17 00:00:00 2001 From: Alex Austin Date: Thu, 30 Nov 2023 13:58:25 +0000 Subject: [PATCH 2596/7721] sfc: Implement ndo_hwtstamp_(get|set) Update efx->ptp_data to use kernel_hwtstamp_config and implement ndo_hwtstamp_(get|set). Remove SIOCGHWTSTAMP and SIOCSHWTSTAMP from efx_ioctl. Signed-off-by: Alex Austin Acked-by: Martin Habets Reviewed-by: Edward Cree Link: https://lore.kernel.org/r/20231130135826.19018-2-alex.austin@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/ef10.c | 4 ++-- drivers/net/ethernet/sfc/efx.c | 24 ++++++++++++++++----- drivers/net/ethernet/sfc/net_driver.h | 2 +- drivers/net/ethernet/sfc/ptp.c | 30 ++++++++++----------------- drivers/net/ethernet/sfc/ptp.h | 7 +++++-- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 6dfa062feebc..8fa6c0e9195b 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3706,13 +3706,13 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en, } static int efx_ef10_ptp_set_ts_config_vf(struct efx_nic *efx, - struct hwtstamp_config *init) + struct kernel_hwtstamp_config *init) { return -EOPNOTSUPP; } static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, - struct hwtstamp_config *init) + struct kernel_hwtstamp_config *init) { int rc; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 19f4b4d0b851..e9d9de8e648a 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -495,11 +495,6 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) struct efx_nic *efx = efx_netdev_priv(net_dev); struct mii_ioctl_data *data = if_mii(ifr); - if (cmd == SIOCSHWTSTAMP) - return efx_ptp_set_ts_config(efx, ifr); - if (cmd == SIOCGHWTSTAMP) - return efx_ptp_get_ts_config(efx, ifr); - /* Convert phy_id from older PRTAD/DEVAD format */ if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && (data->phy_id & 0xfc00) == 0x0400) @@ -581,6 +576,23 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi return -EOPNOTSUPP; } +static int efx_hwtstamp_set(struct net_device *net_dev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + struct efx_nic *efx = efx_netdev_priv(net_dev); + + return efx_ptp_set_ts_config(efx, config, extack); +} + +static int efx_hwtstamp_get(struct net_device *net_dev, + struct kernel_hwtstamp_config *config) +{ + struct efx_nic *efx = efx_netdev_priv(net_dev); + + return efx_ptp_get_ts_config(efx, config); +} + static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, @@ -596,6 +608,8 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_features_check = efx_features_check, .ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid, + .ndo_hwtstamp_set = efx_hwtstamp_set, + .ndo_hwtstamp_get = efx_hwtstamp_get, #ifdef CONFIG_SFC_SRIOV .ndo_set_vf_mac = efx_sriov_set_vf_mac, .ndo_set_vf_vlan = efx_sriov_set_vf_vlan, diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 27d86e90a3bb..f2dd7feb0e0c 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1473,7 +1473,7 @@ struct efx_nic_type { void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time); int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp); int (*ptp_set_ts_config)(struct efx_nic *efx, - struct hwtstamp_config *init); + struct kernel_hwtstamp_config *init); int (*sriov_configure)(struct efx_nic *efx, int num_vfs); int (*vlan_rx_add_vid)(struct efx_nic *efx, __be16 proto, u16 vid); int (*vlan_rx_kill_vid)(struct efx_nic *efx, __be16 proto, u16 vid); diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index b04fdbb8aece..c3bffbf0ba2b 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -301,7 +301,7 @@ struct efx_ptp_data { bool reset_required; struct list_head rxfilters_mcast; struct list_head rxfilters_ucast; - struct hwtstamp_config config; + struct kernel_hwtstamp_config config; bool enabled; unsigned int mode; void (*ns_to_nic_time)(s64 ns, u32 *nic_major, u32 *nic_minor); @@ -1848,7 +1848,7 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, return 0; } -static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init) +static int efx_ptp_ts_init(struct efx_nic *efx, struct kernel_hwtstamp_config *init) { int rc; @@ -1895,33 +1895,25 @@ void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info) ts_info->rx_filters = ptp->efx->type->hwtstamp_filters; } -int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr) +int efx_ptp_set_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack __always_unused *extack) { - struct hwtstamp_config config; - int rc; - /* Not a PTP enabled port */ if (!efx->ptp_data) return -EOPNOTSUPP; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; - - rc = efx_ptp_ts_init(efx, &config); - if (rc != 0) - return rc; - - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) - ? -EFAULT : 0; + return efx_ptp_ts_init(efx, config); } -int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr) +int efx_ptp_get_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config) { + /* Not a PTP enabled port */ if (!efx->ptp_data) return -EOPNOTSUPP; - - return copy_to_user(ifr->ifr_data, &efx->ptp_data->config, - sizeof(efx->ptp_data->config)) ? -EFAULT : 0; + *config = efx->ptp_data->config; + return 0; } static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len) diff --git a/drivers/net/ethernet/sfc/ptp.h b/drivers/net/ethernet/sfc/ptp.h index 7b1ef7002b3f..2f30dbb490d2 100644 --- a/drivers/net/ethernet/sfc/ptp.h +++ b/drivers/net/ethernet/sfc/ptp.h @@ -18,8 +18,11 @@ void efx_ptp_defer_probe_with_channel(struct efx_nic *efx); struct efx_channel *efx_ptp_channel(struct efx_nic *efx); void efx_ptp_update_channel(struct efx_nic *efx, struct efx_channel *channel); void efx_ptp_remove(struct efx_nic *efx); -int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr); -int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr); +int efx_ptp_set_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); +int efx_ptp_get_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config); void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info); bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); int efx_ptp_get_mode(struct efx_nic *efx); From d82afc800c1e385205da9618f75369843e856e7a Mon Sep 17 00:00:00 2001 From: Alex Austin Date: Thu, 30 Nov 2023 13:58:26 +0000 Subject: [PATCH 2597/7721] sfc-siena: Implement ndo_hwtstamp_(get|set) Update efx->ptp_data to use kernel_hwtstamp_config and implement ndo_hwtstamp_(get|set). Remove SIOCGHWTSTAMP and SIOCSHWTSTAMP from efx_ioctl. Signed-off-by: Alex Austin Acked-by: Martin Habets Reviewed-by: Edward Cree Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20231130135826.19018-3-alex.austin@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/siena/efx.c | 24 +++++++++++++---- drivers/net/ethernet/sfc/siena/net_driver.h | 2 +- drivers/net/ethernet/sfc/siena/ptp.c | 30 +++++++++------------ drivers/net/ethernet/sfc/siena/ptp.h | 7 +++-- drivers/net/ethernet/sfc/siena/siena.c | 2 +- 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/sfc/siena/efx.c b/drivers/net/ethernet/sfc/siena/efx.c index 8c557f6a183c..59d3a6043379 100644 --- a/drivers/net/ethernet/sfc/siena/efx.c +++ b/drivers/net/ethernet/sfc/siena/efx.c @@ -495,11 +495,6 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) struct efx_nic *efx = netdev_priv(net_dev); struct mii_ioctl_data *data = if_mii(ifr); - if (cmd == SIOCSHWTSTAMP) - return efx_siena_ptp_set_ts_config(efx, ifr); - if (cmd == SIOCGHWTSTAMP) - return efx_siena_ptp_get_ts_config(efx, ifr); - /* Convert phy_id from older PRTAD/DEVAD format */ if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && (data->phy_id & 0xfc00) == 0x0400) @@ -579,6 +574,23 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi return -EOPNOTSUPP; } +static int efx_siena_hwtstamp_set(struct net_device *net_dev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + return efx_siena_ptp_set_ts_config(efx, config, extack); +} + +static int efx_siena_hwtstamp_get(struct net_device *net_dev, + struct kernel_hwtstamp_config *config) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + return efx_siena_ptp_get_ts_config(efx, config); +} + static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, @@ -594,6 +606,8 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_features_check = efx_siena_features_check, .ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid, + .ndo_hwtstamp_set = efx_siena_hwtstamp_set, + .ndo_hwtstamp_get = efx_siena_hwtstamp_get, #ifdef CONFIG_SFC_SIENA_SRIOV .ndo_set_vf_mac = efx_sriov_set_vf_mac, .ndo_set_vf_vlan = efx_sriov_set_vf_vlan, diff --git a/drivers/net/ethernet/sfc/siena/net_driver.h b/drivers/net/ethernet/sfc/siena/net_driver.h index ff7bbc325952..94152f595acd 100644 --- a/drivers/net/ethernet/sfc/siena/net_driver.h +++ b/drivers/net/ethernet/sfc/siena/net_driver.h @@ -1424,7 +1424,7 @@ struct efx_nic_type { void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time); int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp); int (*ptp_set_ts_config)(struct efx_nic *efx, - struct hwtstamp_config *init); + struct kernel_hwtstamp_config *init); int (*sriov_configure)(struct efx_nic *efx, int num_vfs); int (*vlan_rx_add_vid)(struct efx_nic *efx, __be16 proto, u16 vid); int (*vlan_rx_kill_vid)(struct efx_nic *efx, __be16 proto, u16 vid); diff --git a/drivers/net/ethernet/sfc/siena/ptp.c b/drivers/net/ethernet/sfc/siena/ptp.c index 38e666561bcd..4b5e2f0ba350 100644 --- a/drivers/net/ethernet/sfc/siena/ptp.c +++ b/drivers/net/ethernet/sfc/siena/ptp.c @@ -297,7 +297,7 @@ struct efx_ptp_data { u32 rxfilter_event; u32 rxfilter_general; bool rxfilter_installed; - struct hwtstamp_config config; + struct kernel_hwtstamp_config config; bool enabled; unsigned int mode; void (*ns_to_nic_time)(s64 ns, u32 *nic_major, u32 *nic_minor); @@ -1762,7 +1762,8 @@ int efx_siena_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, return 0; } -static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init) +static int efx_ptp_ts_init(struct efx_nic *efx, + struct kernel_hwtstamp_config *init) { int rc; @@ -1799,33 +1800,26 @@ void efx_siena_ptp_get_ts_info(struct efx_nic *efx, ts_info->rx_filters = ptp->efx->type->hwtstamp_filters; } -int efx_siena_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr) +int efx_siena_ptp_set_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack __always_unused *extack) { - struct hwtstamp_config config; - int rc; - /* Not a PTP enabled port */ if (!efx->ptp_data) return -EOPNOTSUPP; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; - - rc = efx_ptp_ts_init(efx, &config); - if (rc != 0) - return rc; - - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) - ? -EFAULT : 0; + return efx_ptp_ts_init(efx, config); } -int efx_siena_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr) +int efx_siena_ptp_get_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config) { + /* Not a PTP enabled port */ if (!efx->ptp_data) return -EOPNOTSUPP; - return copy_to_user(ifr->ifr_data, &efx->ptp_data->config, - sizeof(efx->ptp_data->config)) ? -EFAULT : 0; + *config = efx->ptp_data->config; + return 0; } static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len) diff --git a/drivers/net/ethernet/sfc/siena/ptp.h b/drivers/net/ethernet/sfc/siena/ptp.h index 4172f90e9f6f..6352f84424f6 100644 --- a/drivers/net/ethernet/sfc/siena/ptp.h +++ b/drivers/net/ethernet/sfc/siena/ptp.h @@ -15,8 +15,11 @@ struct ethtool_ts_info; void efx_siena_ptp_defer_probe_with_channel(struct efx_nic *efx); struct efx_channel *efx_siena_ptp_channel(struct efx_nic *efx); -int efx_siena_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr); -int efx_siena_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr); +int efx_siena_ptp_set_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); +int efx_siena_ptp_get_ts_config(struct efx_nic *efx, + struct kernel_hwtstamp_config *config); void efx_siena_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info); bool efx_siena_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); diff --git a/drivers/net/ethernet/sfc/siena/siena.c b/drivers/net/ethernet/sfc/siena/siena.c index a44c8fa25748..ca33dc08e555 100644 --- a/drivers/net/ethernet/sfc/siena/siena.c +++ b/drivers/net/ethernet/sfc/siena/siena.c @@ -136,7 +136,7 @@ static void siena_ptp_write_host_time(struct efx_nic *efx, u32 host_time) } static int siena_ptp_set_ts_config(struct efx_nic *efx, - struct hwtstamp_config *init) + struct kernel_hwtstamp_config *init) { int rc; From 01a39f1c4f1220a4e6a25729fae87ff5794cbc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Dec 2023 22:24:43 +0200 Subject: [PATCH 2598/7721] drm/i915: Fix ADL+ tiled plane stride when the POT stride is smaller than the original MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plane_view_scanout_stride() currently assumes that we had to pad the mapping stride with dummy pages in order to align it. But that is not the case if the original fb stride exceeds the aligned stride used to populate the remapped view, which is calculated from the user specified framebuffer width rather than the user specified framebuffer stride. Ignore the original fb stride in this case and just stick to the POT aligned stride. Getting this wrong will cause the plane to fetch the wrong data, and can lead to fault errors if the page tables at the bogus location aren't even populated. TODO: figure out if this is OK for CCS, or if we should instead increase the width of the view to cover the entire user specified fb stride instead... Cc: Imre Deak Cc: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231204202443.31247-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila --- drivers/gpu/drm/i915/display/intel_fb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 96663f9ac431..32a7ee1c5b34 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1381,7 +1381,8 @@ plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane, struct drm_i915_private *i915 = to_i915(fb->base.dev); unsigned int stride_tiles; - if (IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) + if ((IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) && + src_stride_tiles < dst_stride_tiles) stride_tiles = src_stride_tiles; else stride_tiles = dst_stride_tiles; From 8ebb1fc2e69ab8b89a425e402c7bd85e053b7b01 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Mon, 4 Dec 2023 10:54:25 +0200 Subject: [PATCH 2599/7721] drm/panel-edp: Add SDC ATNA45AF01 Add support for the SDC ATNA45AF01 panel. Signed-off-by: Abel Vesa Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231201-x1e80100-drm-panel-edp-v2-1-b0173484631a@linaro.org --- drivers/gpu/drm/panel/panel-edp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 825fa2a0d8a5..78565c99b54d 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1983,6 +1983,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), + EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), From 4900e0396e59be233cfa636369d4eec6b40dbeca Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Tue, 5 Dec 2023 20:35:35 +0800 Subject: [PATCH 2600/7721] drm/edp-panel: Sort the panel entries Move the order of CMN 0x14e5 to make the list sorted. Signed-off-by: Pin-yen Lin Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231205123630.988663-3-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 78565c99b54d..c76f186c4baa 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1967,9 +1967,9 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), - EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), From f7c0e362a25f99fafa73d62a2e8c3da00cf1fc0e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Dec 2023 13:17:59 -0800 Subject: [PATCH 2601/7721] tools: ynl: remove generated user space code from git The ynl-generated user space C code is already above 25kLoC and is growing. The initial reason to commit these files was to make reviewing changes to the generator easier. Unfortunately, it has the opposite effect on reviewing changes to specs, and we get far more changes to specs than to the generator. Uncommit those fails, as they are generated on the fly as needed. netdev patchwork now runs a script on each series to create a diff of generated code on the fly, for the rare cases when looking at it is helpful: https://github.com/kuba-moo/nipa/blob/master/tests/series/ynl/ynl.sh Suggested-by: Paolo Abeni Acked-by: Chuck Lever Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/.gitignore | 2 + tools/net/ynl/generated/devlink-user.c | 6864 ---------------------- tools/net/ynl/generated/devlink-user.h | 5255 ----------------- tools/net/ynl/generated/ethtool-user.c | 6370 -------------------- tools/net/ynl/generated/ethtool-user.h | 5535 ----------------- tools/net/ynl/generated/fou-user.c | 330 -- tools/net/ynl/generated/fou-user.h | 343 -- tools/net/ynl/generated/handshake-user.c | 332 -- tools/net/ynl/generated/handshake-user.h | 145 - tools/net/ynl/generated/netdev-user.c | 952 --- tools/net/ynl/generated/netdev-user.h | 442 -- tools/net/ynl/generated/nfsd-user.c | 203 - tools/net/ynl/generated/nfsd-user.h | 67 - 13 files changed, 2 insertions(+), 26838 deletions(-) create mode 100644 tools/net/ynl/generated/.gitignore delete mode 100644 tools/net/ynl/generated/devlink-user.c delete mode 100644 tools/net/ynl/generated/devlink-user.h delete mode 100644 tools/net/ynl/generated/ethtool-user.c delete mode 100644 tools/net/ynl/generated/ethtool-user.h delete mode 100644 tools/net/ynl/generated/fou-user.c delete mode 100644 tools/net/ynl/generated/fou-user.h delete mode 100644 tools/net/ynl/generated/handshake-user.c delete mode 100644 tools/net/ynl/generated/handshake-user.h delete mode 100644 tools/net/ynl/generated/netdev-user.c delete mode 100644 tools/net/ynl/generated/netdev-user.h delete mode 100644 tools/net/ynl/generated/nfsd-user.c delete mode 100644 tools/net/ynl/generated/nfsd-user.h diff --git a/tools/net/ynl/generated/.gitignore b/tools/net/ynl/generated/.gitignore new file mode 100644 index 000000000000..ade488626d26 --- /dev/null +++ b/tools/net/ynl/generated/.gitignore @@ -0,0 +1,2 @@ +*-user.c +*-user.h diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c deleted file mode 100644 index 8e757e249dab..000000000000 --- a/tools/net/ynl/generated/devlink-user.c +++ /dev/null @@ -1,6864 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "devlink-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const devlink_op_strmap[] = { - [3] = "get", - // skip "port-get", duplicate reply value - [DEVLINK_CMD_PORT_NEW] = "port-new", - [13] = "sb-get", - [17] = "sb-pool-get", - [21] = "sb-port-pool-get", - [25] = "sb-tc-pool-bind-get", - [DEVLINK_CMD_ESWITCH_GET] = "eswitch-get", - [DEVLINK_CMD_DPIPE_TABLE_GET] = "dpipe-table-get", - [DEVLINK_CMD_DPIPE_ENTRIES_GET] = "dpipe-entries-get", - [DEVLINK_CMD_DPIPE_HEADERS_GET] = "dpipe-headers-get", - [DEVLINK_CMD_RESOURCE_DUMP] = "resource-dump", - [DEVLINK_CMD_RELOAD] = "reload", - [DEVLINK_CMD_PARAM_GET] = "param-get", - [DEVLINK_CMD_REGION_GET] = "region-get", - [DEVLINK_CMD_REGION_NEW] = "region-new", - [DEVLINK_CMD_REGION_READ] = "region-read", - [DEVLINK_CMD_PORT_PARAM_GET] = "port-param-get", - [DEVLINK_CMD_INFO_GET] = "info-get", - [DEVLINK_CMD_HEALTH_REPORTER_GET] = "health-reporter-get", - [DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET] = "health-reporter-dump-get", - [63] = "trap-get", - [67] = "trap-group-get", - [71] = "trap-policer-get", - [76] = "rate-get", - [80] = "linecard-get", - [DEVLINK_CMD_SELFTESTS_GET] = "selftests-get", -}; - -const char *devlink_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(devlink_op_strmap)) - return NULL; - return devlink_op_strmap[op]; -} - -static const char * const devlink_sb_pool_type_strmap[] = { - [0] = "ingress", - [1] = "egress", -}; - -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_pool_type_strmap)) - return NULL; - return devlink_sb_pool_type_strmap[value]; -} - -static const char * const devlink_port_type_strmap[] = { - [0] = "notset", - [1] = "auto", - [2] = "eth", - [3] = "ib", -}; - -const char *devlink_port_type_str(enum devlink_port_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_type_strmap)) - return NULL; - return devlink_port_type_strmap[value]; -} - -static const char * const devlink_port_flavour_strmap[] = { - [0] = "physical", - [1] = "cpu", - [2] = "dsa", - [3] = "pci_pf", - [4] = "pci_vf", - [5] = "virtual", - [6] = "unused", - [7] = "pci_sf", -}; - -const char *devlink_port_flavour_str(enum devlink_port_flavour value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_flavour_strmap)) - return NULL; - return devlink_port_flavour_strmap[value]; -} - -static const char * const devlink_port_fn_state_strmap[] = { - [0] = "inactive", - [1] = "active", -}; - -const char *devlink_port_fn_state_str(enum devlink_port_fn_state value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_state_strmap)) - return NULL; - return devlink_port_fn_state_strmap[value]; -} - -static const char * const devlink_port_fn_opstate_strmap[] = { - [0] = "detached", - [1] = "attached", -}; - -const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_opstate_strmap)) - return NULL; - return devlink_port_fn_opstate_strmap[value]; -} - -static const char * const devlink_port_fn_attr_cap_strmap[] = { - [0] = "roce-bit", - [1] = "migratable-bit", - [2] = "ipsec-crypto-bit", - [3] = "ipsec-packet-bit", -}; - -const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_attr_cap_strmap)) - return NULL; - return devlink_port_fn_attr_cap_strmap[value]; -} - -static const char * const devlink_sb_threshold_type_strmap[] = { - [0] = "static", - [1] = "dynamic", -}; - -const char *devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_threshold_type_strmap)) - return NULL; - return devlink_sb_threshold_type_strmap[value]; -} - -static const char * const devlink_eswitch_mode_strmap[] = { - [0] = "legacy", - [1] = "switchdev", -}; - -const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_mode_strmap)) - return NULL; - return devlink_eswitch_mode_strmap[value]; -} - -static const char * const devlink_eswitch_inline_mode_strmap[] = { - [0] = "none", - [1] = "link", - [2] = "network", - [3] = "transport", -}; - -const char * -devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_inline_mode_strmap)) - return NULL; - return devlink_eswitch_inline_mode_strmap[value]; -} - -static const char * const devlink_eswitch_encap_mode_strmap[] = { - [0] = "none", - [1] = "basic", -}; - -const char * -devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_encap_mode_strmap)) - return NULL; - return devlink_eswitch_encap_mode_strmap[value]; -} - -static const char * const devlink_dpipe_match_type_strmap[] = { - [0] = "field-exact", -}; - -const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_match_type_strmap)) - return NULL; - return devlink_dpipe_match_type_strmap[value]; -} - -static const char * const devlink_dpipe_action_type_strmap[] = { - [0] = "field-modify", -}; - -const char *devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_action_type_strmap)) - return NULL; - return devlink_dpipe_action_type_strmap[value]; -} - -static const char * const devlink_dpipe_field_mapping_type_strmap[] = { - [0] = "none", - [1] = "ifindex", -}; - -const char * -devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_field_mapping_type_strmap)) - return NULL; - return devlink_dpipe_field_mapping_type_strmap[value]; -} - -static const char * const devlink_resource_unit_strmap[] = { - [0] = "entry", -}; - -const char *devlink_resource_unit_str(enum devlink_resource_unit value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_resource_unit_strmap)) - return NULL; - return devlink_resource_unit_strmap[value]; -} - -static const char * const devlink_reload_action_strmap[] = { - [1] = "driver-reinit", - [2] = "fw-activate", -}; - -const char *devlink_reload_action_str(enum devlink_reload_action value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_reload_action_strmap)) - return NULL; - return devlink_reload_action_strmap[value]; -} - -static const char * const devlink_param_cmode_strmap[] = { - [0] = "runtime", - [1] = "driverinit", - [2] = "permanent", -}; - -const char *devlink_param_cmode_str(enum devlink_param_cmode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_param_cmode_strmap)) - return NULL; - return devlink_param_cmode_strmap[value]; -} - -static const char * const devlink_flash_overwrite_strmap[] = { - [0] = "settings-bit", - [1] = "identifiers-bit", -}; - -const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_flash_overwrite_strmap)) - return NULL; - return devlink_flash_overwrite_strmap[value]; -} - -static const char * const devlink_trap_action_strmap[] = { - [0] = "drop", - [1] = "trap", - [2] = "mirror", -}; - -const char *devlink_trap_action_str(enum devlink_trap_action value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_trap_action_strmap)) - return NULL; - return devlink_trap_action_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr devlink_dl_dpipe_match_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_match_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_match_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_match_value_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_match_value_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_match_value_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_action_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_action_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_action_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_action_value_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_action_value_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_action_value_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_field_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_field_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_field_policy, -}; - -struct ynl_policy_attr devlink_dl_resource_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_resource_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_resource_policy, -}; - -struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest devlink_dl_info_version_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_info_version_policy, -}; - -struct ynl_policy_attr devlink_dl_fmsg_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest devlink_dl_fmsg_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_fmsg_policy, -}; - -struct ynl_policy_attr devlink_dl_port_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = { - [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .name = "hw-addr", .type = YNL_PT_BINARY,}, - [DEVLINK_PORT_FN_ATTR_STATE] = { .name = "state", .type = YNL_PT_U8, }, - [DEVLINK_PORT_FN_ATTR_OPSTATE] = { .name = "opstate", .type = YNL_PT_U8, }, - [DEVLINK_PORT_FN_ATTR_CAPS] = { .name = "caps", .type = YNL_PT_BITFIELD32, }, -}; - -struct ynl_policy_nest devlink_dl_port_function_nest = { - .max_attr = DEVLINK_PORT_FUNCTION_ATTR_MAX, - .table = devlink_dl_port_function_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_entry_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_entry_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_selftest_id_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { - [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .name = "flash", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest devlink_dl_selftest_id_nest = { - .max_attr = DEVLINK_ATTR_SELFTEST_ID_MAX, - .table = devlink_dl_selftest_id_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_matches_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_matches_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_matches_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_actions_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_actions_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_actions_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_match_values_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_match_values_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_match_values_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_action_values_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_action_values_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_action_values_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_header_fields_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_header_fields_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_header_fields_policy, -}; - -struct ynl_policy_attr devlink_dl_resource_list_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, -}; - -struct ynl_policy_nest devlink_dl_resource_list_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_resource_list_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_info_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_info_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_header_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_header_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_header_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_tables_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_tables_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_tables_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entries_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entries_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entries_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_headers_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_headers_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_headers_policy, -}; - -struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dev_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dev_stats_policy, -}; - -struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_PORT_TYPE] = { .name = "port-type", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .name = "port-split-count", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_INDEX] = { .name = "sb-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_POOL_INDEX] = { .name = "sb-pool-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_SB_POOL_TYPE] = { .name = "sb-pool-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_SB_POOL_SIZE] = { .name = "sb-pool-size", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .name = "sb-pool-threshold-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_SB_THRESHOLD] = { .name = "sb-threshold", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_TC_INDEX] = { .name = "sb-tc-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_ESWITCH_MODE] = { .name = "eswitch-mode", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .name = "eswitch-inline-mode", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_DPIPE_TABLES] = { .name = "dpipe-tables", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_tables_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_ENTRIES] = { .name = "dpipe-entries", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entries_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, - [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, - [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, - [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, - [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADERS] = { .name = "dpipe-headers", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_headers_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, - [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .name = "eswitch-encap-mode", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_LIST] = { .name = "resource-list", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_list_nest, }, - [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, - [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_PORT_FLAVOUR] = { .name = "port-flavour", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_PARAM_NAME] = { .name = "param-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PARAM_TYPE] = { .name = "param-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .name = "param-value-cmode", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_REGION_NAME] = { .name = "region-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .name = "region-snapshot-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .name = "region-chunk-addr", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .name = "region-chunk-len", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_RUNNING] = { .name = "info-version-running", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_FMSG] = { .name = "fmsg", .type = YNL_PT_NEST, .nest = &devlink_dl_fmsg_nest, }, - [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .name = "health-reporter-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .name = "health-reporter-graceful-period", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .name = "health-reporter-auto-recover", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .name = "flash-update-file-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .name = "flash-update-component", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .name = "port-pci-pf-number", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_TRAP_NAME] = { .name = "trap-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_TRAP_ACTION] = { .name = "trap-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .name = "trap-group-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_NETNS_FD] = { .name = "netns-fd", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_NETNS_PID] = { .name = "netns-pid", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_NETNS_ID] = { .name = "netns-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .name = "health-reporter-auto-dump", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_TRAP_POLICER_ID] = { .name = "trap-policer-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .name = "trap-policer-rate", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .name = "trap-policer-burst", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_PORT_FUNCTION] = { .name = "port-function", .type = YNL_PT_NEST, .nest = &devlink_dl_port_function_nest, }, - [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .name = "port-controller-number", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = { .name = "flash-update-overwrite-mask", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED] = { .name = "reload-actions-performed", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_RELOAD_LIMITS] = { .name = "reload-limits", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, - [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .name = "port-pci-sf-number", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_RATE_TX_SHARE] = { .name = "rate-tx-share", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RATE_TX_MAX] = { .name = "rate-tx-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RATE_NODE_NAME] = { .name = "rate-node-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .name = "rate-parent-node-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_LINECARD_INDEX] = { .name = "linecard-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_LINECARD_TYPE] = { .name = "linecard-type", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_SELFTESTS] = { .name = "selftests", .type = YNL_PT_NEST, .nest = &devlink_dl_selftest_id_nest, }, - [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .name = "rate-tx-priority", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .name = "rate-tx-weight", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REGION_DIRECT] = { .name = "region-direct", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest devlink_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_policy, -}; - -/* Common nested types */ -void devlink_dl_dpipe_match_free(struct devlink_dl_dpipe_match *obj) -{ -} - -int devlink_dl_dpipe_match_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_match *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_match_type = 1; - dst->dpipe_match_type = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_index = 1; - dst->dpipe_header_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void -devlink_dl_dpipe_match_value_free(struct devlink_dl_dpipe_match_value *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match; i++) - devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); - free(obj->dpipe_match); - free(obj->dpipe_value); - free(obj->dpipe_value_mask); -} - -int devlink_dl_dpipe_match_value_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_match_value *dst = yarg->data; - unsigned int n_dpipe_match = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-match-value.dpipe-match)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH) { - n_dpipe_match++; - } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_len = len; - dst->dpipe_value = malloc(len); - memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_mask_len = len; - dst->dpipe_value_mask = malloc(len); - memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_value_mapping = 1; - dst->dpipe_value_mapping = mnl_attr_get_u32(attr); - } - } - - if (n_dpipe_match) { - dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); - dst->n_dpipe_match = n_dpipe_match; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { - parg.data = &dst->dpipe_match[i]; - if (devlink_dl_dpipe_match_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_action_free(struct devlink_dl_dpipe_action *obj) -{ -} - -int devlink_dl_dpipe_action_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_action *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_action_type = 1; - dst->dpipe_action_type = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_index = 1; - dst->dpipe_header_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void -devlink_dl_dpipe_action_value_free(struct devlink_dl_dpipe_action_value *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action; i++) - devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); - free(obj->dpipe_action); - free(obj->dpipe_value); - free(obj->dpipe_value_mask); -} - -int devlink_dl_dpipe_action_value_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_action_value *dst = yarg->data; - unsigned int n_dpipe_action = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-action-value.dpipe-action)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION) { - n_dpipe_action++; - } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_len = len; - dst->dpipe_value = malloc(len); - memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_mask_len = len; - dst->dpipe_value_mask = malloc(len); - memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_value_mapping = 1; - dst->dpipe_value_mapping = mnl_attr_get_u32(attr); - } - } - - if (n_dpipe_action) { - dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); - dst->n_dpipe_action = n_dpipe_action; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { - parg.data = &dst->dpipe_action[i]; - if (devlink_dl_dpipe_action_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_field_free(struct devlink_dl_dpipe_field *obj) -{ - free(obj->dpipe_field_name); -} - -int devlink_dl_dpipe_field_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_field *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_FIELD_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_field_name_len = len; - dst->dpipe_field_name = malloc(len + 1); - memcpy(dst->dpipe_field_name, mnl_attr_get_str(attr), len); - dst->dpipe_field_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_bitwidth = 1; - dst->dpipe_field_bitwidth = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_mapping_type = 1; - dst->dpipe_field_mapping_type = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void devlink_dl_resource_free(struct devlink_dl_resource *obj) -{ - free(obj->resource_name); -} - -int devlink_dl_resource_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_resource *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RESOURCE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.resource_name_len = len; - dst->resource_name = malloc(len + 1); - memcpy(dst->resource_name, mnl_attr_get_str(attr), len); - dst->resource_name[len] = 0; - } else if (type == DEVLINK_ATTR_RESOURCE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_id = 1; - dst->resource_id = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size = 1; - dst->resource_size = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_NEW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_new = 1; - dst->resource_size_new = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_VALID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_valid = 1; - dst->resource_size_valid = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MIN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_min = 1; - dst->resource_size_min = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_max = 1; - dst->resource_size_max = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_GRAN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_gran = 1; - dst->resource_size_gran = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_UNIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_unit = 1; - dst->resource_unit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_OCC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_occ = 1; - dst->resource_occ = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) -{ - free(obj->info_version_name); - free(obj->info_version_value); -} - -int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_info_version *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_name_len = len; - dst->info_version_name = malloc(len + 1); - memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); - dst->info_version_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_value_len = len; - dst->info_version_value = malloc(len + 1); - memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); - dst->info_version_value[len] = 0; - } - } - - return 0; -} - -void devlink_dl_fmsg_free(struct devlink_dl_fmsg *obj) -{ - free(obj->fmsg_obj_name); -} - -int devlink_dl_fmsg_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_fmsg *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_FMSG_OBJ_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_obj_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_PAIR_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_pair_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_ARR_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_arr_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_NEST_END) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_nest_end = 1; - } else if (type == DEVLINK_ATTR_FMSG_OBJ_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.fmsg_obj_name_len = len; - dst->fmsg_obj_name = malloc(len + 1); - memcpy(dst->fmsg_obj_name, mnl_attr_get_str(attr), len); - dst->fmsg_obj_name[len] = 0; - } - } - - return 0; -} - -void devlink_dl_port_function_free(struct devlink_dl_port_function *obj) -{ - free(obj->hw_addr); -} - -int devlink_dl_port_function_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct devlink_dl_port_function *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.hw_addr_len) - mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, obj->_present.hw_addr_len, obj->hw_addr); - if (obj->_present.state) - mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_STATE, obj->state); - if (obj->_present.opstate) - mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_OPSTATE, obj->opstate); - if (obj->_present.caps) - mnl_attr_put(nlh, DEVLINK_PORT_FN_ATTR_CAPS, sizeof(struct nla_bitfield32), &obj->caps); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -void -devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) -{ -} - -int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_limit = 1; - dst->reload_stats_limit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_value = 1; - dst->reload_stats_value = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_stats_entry; i++) - devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); - free(obj->reload_stats_entry); -} - -int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_stats *dst = yarg->data; - unsigned int n_reload_stats_entry = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_stats_entry) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - n_reload_stats_entry++; - } - } - - if (n_reload_stats_entry) { - dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); - dst->n_reload_stats_entry = n_reload_stats_entry; - i = 0; - parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - parg.data = &dst->reload_stats_entry[i]; - if (devlink_dl_reload_stats_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_selftest_id_free(struct devlink_dl_selftest_id *obj) -{ -} - -int devlink_dl_selftest_id_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct devlink_dl_selftest_id *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.flash) - mnl_attr_put(nlh, DEVLINK_ATTR_SELFTEST_ID_FLASH, 0, NULL); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -void -devlink_dl_dpipe_table_matches_free(struct devlink_dl_dpipe_table_matches *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match; i++) - devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); - free(obj->dpipe_match); -} - -int devlink_dl_dpipe_table_matches_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table_matches *dst = yarg->data; - unsigned int n_dpipe_match = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-matches.dpipe-match)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH) { - n_dpipe_match++; - } - } - - if (n_dpipe_match) { - dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); - dst->n_dpipe_match = n_dpipe_match; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { - parg.data = &dst->dpipe_match[i]; - if (devlink_dl_dpipe_match_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_table_actions_free(struct devlink_dl_dpipe_table_actions *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action; i++) - devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); - free(obj->dpipe_action); -} - -int devlink_dl_dpipe_table_actions_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table_actions *dst = yarg->data; - unsigned int n_dpipe_action = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-actions.dpipe-action)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION) { - n_dpipe_action++; - } - } - - if (n_dpipe_action) { - dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); - dst->n_dpipe_action = n_dpipe_action; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { - parg.data = &dst->dpipe_action[i]; - if (devlink_dl_dpipe_action_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_entry_match_values_free(struct devlink_dl_dpipe_entry_match_values *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match_value; i++) - devlink_dl_dpipe_match_value_free(&obj->dpipe_match_value[i]); - free(obj->dpipe_match_value); -} - -int devlink_dl_dpipe_entry_match_values_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry_match_values *dst = yarg->data; - unsigned int n_dpipe_match_value = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match_value) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-match-values.dpipe-match-value)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { - n_dpipe_match_value++; - } - } - - if (n_dpipe_match_value) { - dst->dpipe_match_value = calloc(n_dpipe_match_value, sizeof(*dst->dpipe_match_value)); - dst->n_dpipe_match_value = n_dpipe_match_value; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_value_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { - parg.data = &dst->dpipe_match_value[i]; - if (devlink_dl_dpipe_match_value_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_entry_action_values_free(struct devlink_dl_dpipe_entry_action_values *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action_value; i++) - devlink_dl_dpipe_action_value_free(&obj->dpipe_action_value[i]); - free(obj->dpipe_action_value); -} - -int devlink_dl_dpipe_entry_action_values_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry_action_values *dst = yarg->data; - unsigned int n_dpipe_action_value = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action_value) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-action-values.dpipe-action-value)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { - n_dpipe_action_value++; - } - } - - if (n_dpipe_action_value) { - dst->dpipe_action_value = calloc(n_dpipe_action_value, sizeof(*dst->dpipe_action_value)); - dst->n_dpipe_action_value = n_dpipe_action_value; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_value_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { - parg.data = &dst->dpipe_action_value[i]; - if (devlink_dl_dpipe_action_value_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_header_fields_free(struct devlink_dl_dpipe_header_fields *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_field; i++) - devlink_dl_dpipe_field_free(&obj->dpipe_field[i]); - free(obj->dpipe_field); -} - -int devlink_dl_dpipe_header_fields_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_header_fields *dst = yarg->data; - unsigned int n_dpipe_field = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_field) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-header-fields.dpipe-field)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_FIELD) { - n_dpipe_field++; - } - } - - if (n_dpipe_field) { - dst->dpipe_field = calloc(n_dpipe_field, sizeof(*dst->dpipe_field)); - dst->n_dpipe_field = n_dpipe_field; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_field_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_FIELD) { - parg.data = &dst->dpipe_field[i]; - if (devlink_dl_dpipe_field_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_resource_list_free(struct devlink_dl_resource_list *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_resource; i++) - devlink_dl_resource_free(&obj->resource[i]); - free(obj->resource); -} - -int devlink_dl_resource_list_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_resource_list *dst = yarg->data; - unsigned int n_resource = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->resource) - return ynl_error_parse(yarg, "attribute already present (dl-resource-list.resource)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RESOURCE) { - n_resource++; - } - } - - if (n_resource) { - dst->resource = calloc(n_resource, sizeof(*dst->resource)); - dst->n_resource = n_resource; - i = 0; - parg.rsp_policy = &devlink_dl_resource_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RESOURCE) { - parg.data = &dst->resource[i]; - if (devlink_dl_resource_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_stats; i++) - devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); - free(obj->reload_action_stats); -} - -int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_info *dst = yarg->data; - unsigned int n_reload_action_stats = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_stats) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - n_reload_action_stats++; - } - } - - if (n_reload_action_stats) { - dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); - dst->n_reload_action_stats = n_reload_action_stats; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_stats_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - parg.data = &dst->reload_action_stats[i]; - if (devlink_dl_reload_act_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_table_free(struct devlink_dl_dpipe_table *obj) -{ - free(obj->dpipe_table_name); - devlink_dl_dpipe_table_matches_free(&obj->dpipe_table_matches); - devlink_dl_dpipe_table_actions_free(&obj->dpipe_table_actions); -} - -int devlink_dl_dpipe_table_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_TABLE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_table_name_len = len; - dst->dpipe_table_name = malloc(len + 1); - memcpy(dst->dpipe_table_name, mnl_attr_get_str(attr), len); - dst->dpipe_table_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_size = 1; - dst->dpipe_table_size = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_MATCHES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_matches = 1; - - parg.rsp_policy = &devlink_dl_dpipe_table_matches_nest; - parg.data = &dst->dpipe_table_matches; - if (devlink_dl_dpipe_table_matches_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_ACTIONS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_actions = 1; - - parg.rsp_policy = &devlink_dl_dpipe_table_actions_nest; - parg.data = &dst->dpipe_table_actions; - if (devlink_dl_dpipe_table_actions_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_counters_enabled = 1; - dst->dpipe_table_counters_enabled = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_resource_id = 1; - dst->dpipe_table_resource_id = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_resource_units = 1; - dst->dpipe_table_resource_units = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_dpipe_entry_free(struct devlink_dl_dpipe_entry *obj) -{ - devlink_dl_dpipe_entry_match_values_free(&obj->dpipe_entry_match_values); - devlink_dl_dpipe_entry_action_values_free(&obj->dpipe_entry_action_values); -} - -int devlink_dl_dpipe_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ENTRY_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_index = 1; - dst->dpipe_entry_index = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_match_values = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entry_match_values_nest; - parg.data = &dst->dpipe_entry_match_values; - if (devlink_dl_dpipe_entry_match_values_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_action_values = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entry_action_values_nest; - parg.data = &dst->dpipe_entry_action_values; - if (devlink_dl_dpipe_entry_action_values_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_COUNTER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_counter = 1; - dst->dpipe_entry_counter = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_dpipe_header_free(struct devlink_dl_dpipe_header *obj) -{ - free(obj->dpipe_header_name); - devlink_dl_dpipe_header_fields_free(&obj->dpipe_header_fields); -} - -int devlink_dl_dpipe_header_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_header *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_HEADER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_header_name_len = len; - dst->dpipe_header_name = malloc(len + 1); - memcpy(dst->dpipe_header_name, mnl_attr_get_str(attr), len); - dst->dpipe_header_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_FIELDS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_fields = 1; - - parg.rsp_policy = &devlink_dl_dpipe_header_fields_nest; - parg.data = &dst->dpipe_header_fields; - if (devlink_dl_dpipe_header_fields_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_info; i++) - devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); - free(obj->reload_action_info); -} - -int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats *dst = yarg->data; - unsigned int n_reload_action_info = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_info) - return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - n_reload_action_info++; - } - } - - if (n_reload_action_info) { - dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); - dst->n_reload_action_info = n_reload_action_info; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_info_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - parg.data = &dst->reload_action_info[i]; - if (devlink_dl_reload_act_info_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_tables_free(struct devlink_dl_dpipe_tables *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_table; i++) - devlink_dl_dpipe_table_free(&obj->dpipe_table[i]); - free(obj->dpipe_table); -} - -int devlink_dl_dpipe_tables_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_tables *dst = yarg->data; - unsigned int n_dpipe_table = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_table) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-tables.dpipe-table)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_TABLE) { - n_dpipe_table++; - } - } - - if (n_dpipe_table) { - dst->dpipe_table = calloc(n_dpipe_table, sizeof(*dst->dpipe_table)); - dst->n_dpipe_table = n_dpipe_table; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_table_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_TABLE) { - parg.data = &dst->dpipe_table[i]; - if (devlink_dl_dpipe_table_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_entries_free(struct devlink_dl_dpipe_entries *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_entry; i++) - devlink_dl_dpipe_entry_free(&obj->dpipe_entry[i]); - free(obj->dpipe_entry); -} - -int devlink_dl_dpipe_entries_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entries *dst = yarg->data; - unsigned int n_dpipe_entry = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_entry) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entries.dpipe-entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ENTRY) { - n_dpipe_entry++; - } - } - - if (n_dpipe_entry) { - dst->dpipe_entry = calloc(n_dpipe_entry, sizeof(*dst->dpipe_entry)); - dst->n_dpipe_entry = n_dpipe_entry; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ENTRY) { - parg.data = &dst->dpipe_entry[i]; - if (devlink_dl_dpipe_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_headers_free(struct devlink_dl_dpipe_headers *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_header; i++) - devlink_dl_dpipe_header_free(&obj->dpipe_header[i]); - free(obj->dpipe_header); -} - -int devlink_dl_dpipe_headers_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_headers *dst = yarg->data; - unsigned int n_dpipe_header = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_header) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-headers.dpipe-header)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_HEADER) { - n_dpipe_header++; - } - } - - if (n_dpipe_header) { - dst->dpipe_header = calloc(n_dpipe_header, sizeof(*dst->dpipe_header)); - dst->n_dpipe_header = n_dpipe_header; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_header_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_HEADER) { - parg.data = &dst->dpipe_header[i]; - if (devlink_dl_dpipe_header_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) -{ - devlink_dl_reload_stats_free(&obj->reload_stats); - devlink_dl_reload_stats_free(&obj->remote_reload_stats); -} - -int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dev_stats *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remote_reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->remote_reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -void devlink_get_req_free(struct devlink_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dev_stats_free(&rsp->dev_stats); - free(rsp); -} - -int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_failed = 1; - dst->reload_failed = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DEV_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_stats = 1; - - parg.rsp_policy = &devlink_dl_dev_stats_nest; - parg.data = &dst->dev_stats; - if (devlink_dl_dev_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_get_rsp_parse; - yrs.rsp_cmd = 3; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_GET - dump */ -void devlink_get_list_free(struct devlink_get_list *rsp) -{ - struct devlink_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - devlink_dl_dev_stats_free(&rsp->obj.dev_stats); - free(rsp); - } -} - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_get_list); - yds.cb = devlink_get_rsp_parse; - yds.rsp_cmd = 3; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -void devlink_port_get_req_free(struct devlink_port_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_port_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_get_rsp_parse; - yrs.rsp_cmd = 7; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PORT_GET - dump */ -int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_port_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp) -{ - struct devlink_port_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_get_rsp_list); - yds.cb = devlink_port_get_rsp_dump_parse; - yds.rsp_cmd = 7; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_port_get_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_SET ============== */ -/* DEVLINK_CMD_PORT_SET - do */ -void devlink_port_set_req_free(struct devlink_port_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - devlink_dl_port_function_free(&req->port_function); - free(req); -} - -int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_type) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, req->port_type); - if (req->_present.port_function) - devlink_dl_port_function_put(nlh, DEVLINK_ATTR_PORT_FUNCTION, &req->port_function); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_NEW ============== */ -/* DEVLINK_CMD_PORT_NEW - do */ -void devlink_port_new_req_free(struct devlink_port_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_new_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_port_new_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_new_rsp * -devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_new_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_NEW, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_flavour) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_FLAVOUR, req->port_flavour); - if (req->_present.port_pci_pf_number) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, req->port_pci_pf_number); - if (req->_present.port_pci_sf_number) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, req->port_pci_sf_number); - if (req->_present.port_controller_number) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, req->port_controller_number); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_new_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PORT_NEW; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_new_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_DEL ============== */ -/* DEVLINK_CMD_PORT_DEL - do */ -void devlink_port_del_req_free(struct devlink_port_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ -/* DEVLINK_CMD_PORT_SPLIT - do */ -void devlink_port_split_req_free(struct devlink_port_split_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SPLIT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_split_count) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, req->port_split_count); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ -/* DEVLINK_CMD_PORT_UNSPLIT - do */ -void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_unsplit(struct ynl_sock *ys, - struct devlink_port_unsplit_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_UNSPLIT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -void devlink_sb_get_req_free(struct devlink_sb_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_sb_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_get_rsp_parse; - yrs.rsp_cmd = 13; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_GET - dump */ -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp) -{ - struct devlink_sb_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_get_list); - yds.cb = devlink_sb_get_rsp_parse; - yds.rsp_cmd = 13; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_pool_get_rsp_parse; - yrs.rsp_cmd = 17; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) -{ - struct devlink_sb_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list); - yds.cb = devlink_sb_pool_get_rsp_parse; - yds.rsp_cmd = 17; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ -/* DEVLINK_CMD_SB_POOL_SET - do */ -void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_pool_set(struct ynl_sock *ys, - struct devlink_sb_pool_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_pool_threshold_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, req->sb_pool_threshold_type); - if (req->_present.sb_pool_size) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, req->sb_pool_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_port_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_port_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_port_pool_get_rsp_parse; - yrs.rsp_cmd = 21; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_port_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) -{ - struct devlink_sb_port_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list); - yds.cb = devlink_sb_port_pool_get_rsp_parse; - yds.rsp_cmd = 21; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_port_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ -void -devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_port_pool_set(struct ynl_sock *ys, - struct devlink_sb_port_pool_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_threshold) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_sb_tc_pool_bind_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_type = 1; - dst->sb_pool_type = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_SB_TC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_tc_index = 1; - dst->sb_tc_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_tc_pool_bind_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yrs.rsp_cmd = 25; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_tc_pool_bind_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp) -{ - struct devlink_sb_tc_pool_bind_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list); - yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yds.rsp_cmd = 25; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_tc_pool_bind_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ -void -devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); - if (req->_present.sb_threshold) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ -/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ -void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_occ_snapshot(struct ynl_sock *ys, - struct devlink_sb_occ_snapshot_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_SNAPSHOT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ -/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ -void -devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_occ_max_clear(struct ynl_sock *ys, - struct devlink_sb_occ_max_clear_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_MAX_CLEAR, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ -/* DEVLINK_CMD_ESWITCH_GET - do */ -void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_eswitch_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_eswitch_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_ESWITCH_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_mode = 1; - dst->eswitch_mode = mnl_attr_get_u16(attr); - } else if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_inline_mode = 1; - dst->eswitch_inline_mode = mnl_attr_get_u16(attr); - } else if (type == DEVLINK_ATTR_ESWITCH_ENCAP_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_encap_mode = 1; - dst->eswitch_encap_mode = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_eswitch_get_rsp * -devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_eswitch_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_eswitch_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_ESWITCH_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_eswitch_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ -/* DEVLINK_CMD_ESWITCH_SET - do */ -void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_eswitch_set(struct ynl_sock *ys, - struct devlink_eswitch_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.eswitch_mode) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, req->eswitch_mode); - if (req->_present.eswitch_inline_mode) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, req->eswitch_inline_mode); - if (req->_present.eswitch_encap_mode) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, req->eswitch_encap_mode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ -void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_tables_free(&rsp->dpipe_tables); - free(rsp); -} - -int devlink_dpipe_table_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_table_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_TABLES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_tables = 1; - - parg.rsp_policy = &devlink_dl_dpipe_tables_nest; - parg.data = &dst->dpipe_tables; - if (devlink_dl_dpipe_tables_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_table_get_rsp * -devlink_dpipe_table_get(struct ynl_sock *ys, - struct devlink_dpipe_table_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_table_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_table_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_TABLE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_table_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ -/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ -void -devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -void -devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_entries_free(&rsp->dpipe_entries); - free(rsp); -} - -int devlink_dpipe_entries_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_entries_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRIES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entries = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entries_nest; - parg.data = &dst->dpipe_entries; - if (devlink_dl_dpipe_entries_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_entries_get_rsp * -devlink_dpipe_entries_get(struct ynl_sock *ys, - struct devlink_dpipe_entries_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_entries_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_ENTRIES_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_entries_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_entries_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ -/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ -void -devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_headers_free(&rsp->dpipe_headers); - free(rsp); -} - -int devlink_dpipe_headers_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_headers_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_HEADERS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_headers = 1; - - parg.rsp_policy = &devlink_dl_dpipe_headers_nest; - parg.data = &dst->dpipe_headers; - if (devlink_dl_dpipe_headers_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_headers_get_rsp * -devlink_dpipe_headers_get(struct ynl_sock *ys, - struct devlink_dpipe_headers_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_headers_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_HEADERS_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_headers_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_HEADERS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_headers_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ -void -devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -int devlink_dpipe_table_counters_set(struct ynl_sock *ys, - struct devlink_dpipe_table_counters_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - if (req->_present.dpipe_table_counters_enabled) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, req->dpipe_table_counters_enabled); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ -/* DEVLINK_CMD_RESOURCE_SET - do */ -void devlink_resource_set_req_free(struct devlink_resource_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_resource_set(struct ynl_sock *ys, - struct devlink_resource_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.resource_id) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID, req->resource_id); - if (req->_present.resource_size) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE, req->resource_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ -/* DEVLINK_CMD_RESOURCE_DUMP - do */ -void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_resource_list_free(&rsp->resource_list); - free(rsp); -} - -int devlink_resource_dump_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_resource_dump_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RESOURCE_LIST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_list = 1; - - parg.rsp_policy = &devlink_dl_resource_list_nest; - parg.data = &dst->resource_list; - if (devlink_dl_resource_list_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_resource_dump_rsp * -devlink_resource_dump(struct ynl_sock *ys, - struct devlink_resource_dump_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_resource_dump_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_DUMP, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_resource_dump_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_RESOURCE_DUMP; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_resource_dump_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_RELOAD ============== */ -/* DEVLINK_CMD_RELOAD - do */ -void devlink_reload_req_free(struct devlink_reload_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_reload_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_reload_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_actions_performed = 1; - memcpy(&dst->reload_actions_performed, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32)); - } - } - - return MNL_CB_OK; -} - -struct devlink_reload_rsp * -devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_reload_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RELOAD, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.reload_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION, req->reload_action); - if (req->_present.reload_limits) - mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(struct nla_bitfield32), &req->reload_limits); - if (req->_present.netns_pid) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_PID, req->netns_pid); - if (req->_present.netns_fd) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_FD, req->netns_fd); - if (req->_present.netns_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_ID, req->netns_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_reload_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_RELOAD; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_reload_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -void devlink_param_get_req_free(struct devlink_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->param_name); - free(rsp); -} - -int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_param_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PARAM_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.param_name_len = len; - dst->param_name = malloc(len + 1); - memcpy(dst->param_name, mnl_attr_get_str(attr), len); - dst->param_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PARAM_GET - dump */ -void devlink_param_get_list_free(struct devlink_param_get_list *rsp) -{ - struct devlink_param_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.param_name); - free(rsp); - } -} - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_param_get_list); - yds.cb = devlink_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PARAM_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_param_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_SET ============== */ -/* DEVLINK_CMD_PARAM_SET - do */ -void devlink_param_set_req_free(struct devlink_param_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} - -int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - if (req->_present.param_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, req->param_type); - if (req->_present.param_value_cmode) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, req->param_value_cmode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -void devlink_region_get_req_free(struct devlink_region_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->region_name); - free(rsp); -} - -int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_region_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_region_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_REGION_GET - dump */ -void devlink_region_get_list_free(struct devlink_region_get_list *rsp) -{ - struct devlink_region_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.region_name); - free(rsp); - } -} - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_get_list); - yds.cb = devlink_region_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_region_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_REGION_NEW ============== */ -/* DEVLINK_CMD_REGION_NEW - do */ -void devlink_region_new_req_free(struct devlink_region_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->region_name); - free(rsp); -} - -int devlink_region_new_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_new_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } else if (type == DEVLINK_ATTR_REGION_SNAPSHOT_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.region_snapshot_id = 1; - dst->region_snapshot_id = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_region_new_rsp * -devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_new_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_NEW, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_region_new_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_NEW; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_region_new_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_REGION_DEL ============== */ -/* DEVLINK_CMD_REGION_DEL - do */ -void devlink_region_del_req_free(struct devlink_region_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_REGION_READ ============== */ -/* DEVLINK_CMD_REGION_READ - dump */ -int devlink_region_read_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_read_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -void -devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp) -{ - struct devlink_region_read_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.region_name); - free(rsp); - } -} - -struct devlink_region_read_rsp_list * -devlink_region_read_dump(struct ynl_sock *ys, - struct devlink_region_read_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_read_rsp_list); - yds.cb = devlink_region_read_rsp_dump_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_READ; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_READ, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - if (req->_present.region_direct) - mnl_attr_put(nlh, DEVLINK_ATTR_REGION_DIRECT, 0, NULL); - if (req->_present.region_chunk_addr) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR, req->region_chunk_addr); - if (req->_present.region_chunk_len) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, req->region_chunk_len); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_region_read_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ -/* DEVLINK_CMD_PORT_PARAM_GET - do */ -void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_port_param_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_param_get_rsp * -devlink_port_param_get(struct ynl_sock *ys, - struct devlink_port_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PORT_PARAM_GET - dump */ -void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp) -{ - struct devlink_port_param_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_param_get_list * -devlink_port_param_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_param_get_list); - yds.cb = devlink_port_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_port_param_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ -/* DEVLINK_CMD_PORT_PARAM_SET - do */ -void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_param_set(struct ynl_sock *ys, - struct devlink_port_param_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -void devlink_info_get_req_free(struct devlink_info_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp) -{ - unsigned int i; - - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->info_driver_name); - free(rsp->info_serial_number); - for (i = 0; i < rsp->n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->info_version_fixed[i]); - free(rsp->info_version_fixed); - for (i = 0; i < rsp->n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->info_version_running[i]); - free(rsp->info_version_running); - for (i = 0; i < rsp->n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->info_version_stored[i]); - free(rsp->info_version_stored); - free(rsp); -} - -int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - unsigned int n_info_version_running = 0; - unsigned int n_info_version_stored = 0; - unsigned int n_info_version_fixed = 0; - struct ynl_parse_arg *yarg = data; - struct devlink_info_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->info_version_fixed) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-fixed)"); - if (dst->info_version_running) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-running)"); - if (dst->info_version_stored) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_DRIVER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_driver_name_len = len; - dst->info_driver_name = malloc(len + 1); - memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len); - dst->info_driver_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_serial_number_len = len; - dst->info_serial_number = malloc(len + 1); - memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len); - dst->info_serial_number[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_FIXED) { - n_info_version_fixed++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - n_info_version_running++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_STORED) { - n_info_version_stored++; - } - } - - if (n_info_version_fixed) { - dst->info_version_fixed = calloc(n_info_version_fixed, sizeof(*dst->info_version_fixed)); - dst->n_info_version_fixed = n_info_version_fixed; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { - parg.data = &dst->info_version_fixed[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_running) { - dst->info_version_running = calloc(n_info_version_running, sizeof(*dst->info_version_running)); - dst->n_info_version_running = n_info_version_running; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - parg.data = &dst->info_version_running[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_stored) { - dst->info_version_stored = calloc(n_info_version_stored, sizeof(*dst->info_version_stored)); - dst->n_info_version_stored = n_info_version_stored; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { - parg.data = &dst->info_version_stored[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return MNL_CB_OK; -} - -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_info_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_INFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_info_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_INFO_GET - dump */ -void devlink_info_get_list_free(struct devlink_info_get_list *rsp) -{ - struct devlink_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - unsigned int i; - - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.info_driver_name); - free(rsp->obj.info_serial_number); - for (i = 0; i < rsp->obj.n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_fixed[i]); - free(rsp->obj.info_version_fixed); - for (i = 0; i < rsp->obj.n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_running[i]); - free(rsp->obj.info_version_running); - for (i = 0; i < rsp->obj.n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_stored[i]); - free(rsp->obj.info_version_stored); - free(rsp); - } -} - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_info_get_list); - yds.cb = devlink_info_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_INFO_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_info_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->health_reporter_name); - free(rsp); -} - -int devlink_health_reporter_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_health_reporter_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_HEALTH_REPORTER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.health_reporter_name_len = len; - dst->health_reporter_name = malloc(len + 1); - memcpy(dst->health_reporter_name, mnl_attr_get_str(attr), len); - dst->health_reporter_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_health_reporter_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_health_reporter_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_health_reporter_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp) -{ - struct devlink_health_reporter_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.health_reporter_name); - free(rsp); - } -} - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_get_list); - yds.cb = devlink_health_reporter_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_health_reporter_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ -void -devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_set(struct ynl_sock *ys, - struct devlink_health_reporter_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - if (req->_present.health_reporter_graceful_period) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, req->health_reporter_graceful_period); - if (req->_present.health_reporter_auto_recover) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, req->health_reporter_auto_recover); - if (req->_present.health_reporter_auto_dump) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP, req->health_reporter_auto_dump); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ -void -devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_recover(struct ynl_sock *ys, - struct devlink_health_reporter_recover_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ -void -devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_diagnose(struct ynl_sock *ys, - struct devlink_health_reporter_diagnose_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ -int devlink_health_reporter_dump_get_rsp_dump_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_health_reporter_dump_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_FMSG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg = 1; - - parg.rsp_policy = &devlink_dl_fmsg_nest; - parg.data = &dst->fmsg; - if (devlink_dl_fmsg_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -void -devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp) -{ - struct devlink_health_reporter_dump_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - devlink_dl_fmsg_free(&rsp->obj.fmsg); - free(rsp); - } -} - -struct devlink_health_reporter_dump_get_rsp_list * -devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_dump_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_dump_get_rsp_list); - yds.cb = devlink_health_reporter_dump_get_rsp_dump_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_health_reporter_dump_get_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ -void -devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_dump_clear(struct ynl_sock *ys, - struct devlink_health_reporter_dump_clear_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ -/* DEVLINK_CMD_FLASH_UPDATE - do */ -void devlink_flash_update_req_free(struct devlink_flash_update_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->flash_update_file_name); - free(req->flash_update_component); - free(req); -} - -int devlink_flash_update(struct ynl_sock *ys, - struct devlink_flash_update_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_FLASH_UPDATE, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.flash_update_file_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, req->flash_update_file_name); - if (req->_present.flash_update_component_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, req->flash_update_component); - if (req->_present.flash_update_overwrite_mask) - mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK, sizeof(struct nla_bitfield32), &req->flash_update_overwrite_mask); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -void devlink_trap_get_req_free(struct devlink_trap_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_name); - free(req); -} - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_name); - free(rsp); -} - -int devlink_trap_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_trap_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_name_len = len; - dst->trap_name = malloc(len + 1); - memcpy(dst->trap_name, mnl_attr_get_str(attr), len); - dst->trap_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_get_rsp_parse; - yrs.rsp_cmd = 63; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GET - dump */ -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp) -{ - struct devlink_trap_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_name); - free(rsp); - } -} - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_get_list); - yds.cb = devlink_trap_get_rsp_parse; - yds.rsp_cmd = 63; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_SET ============== */ -/* DEVLINK_CMD_TRAP_SET - do */ -void devlink_trap_set_req_free(struct devlink_trap_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_name); - free(req); -} - -int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); - if (req->_present.trap_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_group_name); - free(req); -} - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_group_name); - free(rsp); -} - -int devlink_trap_group_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_group_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_GROUP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_group_name_len = len; - dst->trap_group_name = malloc(len + 1); - memcpy(dst->trap_group_name, mnl_attr_get_str(attr), len); - dst->trap_group_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_group_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_group_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_group_get_rsp_parse; - yrs.rsp_cmd = 67; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_group_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp) -{ - struct devlink_trap_group_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_group_name); - free(rsp); - } -} - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_group_get_list); - yds.cb = devlink_trap_group_get_rsp_parse; - yds.rsp_cmd = 67; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_group_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_SET - do */ -void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_group_name); - free(req); -} - -int devlink_trap_group_set(struct ynl_sock *ys, - struct devlink_trap_group_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_group_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); - if (req->_present.trap_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_trap_policer_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_policer_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_POLICER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.trap_policer_id = 1; - dst->trap_policer_id = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_policer_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_policer_get_rsp_parse; - yrs.rsp_cmd = 71; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_policer_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp) -{ - struct devlink_trap_policer_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_policer_get_list); - yds.cb = devlink_trap_policer_get_rsp_parse; - yds.rsp_cmd = 71; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_policer_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_SET - do */ -void -devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_trap_policer_set(struct ynl_sock *ys, - struct devlink_trap_policer_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - if (req->_present.trap_policer_rate) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE, req->trap_policer_rate); - if (req->_present.trap_policer_burst) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST, req->trap_policer_burst); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ -void -devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_test(struct ynl_sock *ys, - struct devlink_health_reporter_test_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_TEST, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -void devlink_rate_get_req_free(struct devlink_rate_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req); -} - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->rate_node_name); - free(rsp); -} - -int devlink_rate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_rate_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_RATE_NODE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.rate_node_name_len = len; - dst->rate_node_name = malloc(len + 1); - memcpy(dst->rate_node_name, mnl_attr_get_str(attr), len); - dst->rate_node_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_rate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_rate_get_rsp_parse; - yrs.rsp_cmd = 76; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_rate_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_RATE_GET - dump */ -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp) -{ - struct devlink_rate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.rate_node_name); - free(rsp); - } -} - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_rate_get_list); - yds.cb = devlink_rate_get_rsp_parse; - yds.rsp_cmd = 76; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_rate_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_RATE_SET ============== */ -/* DEVLINK_CMD_RATE_SET - do */ -void devlink_rate_set_req_free(struct devlink_rate_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req->rate_parent_node_name); - free(req); -} - -int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - if (req->_present.rate_tx_share) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); - if (req->_present.rate_tx_max) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); - if (req->_present.rate_tx_priority) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); - if (req->_present.rate_tx_weight) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); - if (req->_present.rate_parent_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_NEW ============== */ -/* DEVLINK_CMD_RATE_NEW - do */ -void devlink_rate_new_req_free(struct devlink_rate_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req->rate_parent_node_name); - free(req); -} - -int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_NEW, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - if (req->_present.rate_tx_share) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); - if (req->_present.rate_tx_max) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); - if (req->_present.rate_tx_priority) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); - if (req->_present.rate_tx_weight) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); - if (req->_present.rate_parent_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_DEL ============== */ -/* DEVLINK_CMD_RATE_DEL - do */ -void devlink_rate_del_req_free(struct devlink_rate_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req); -} - -int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_linecard_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_linecard_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_LINECARD_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.linecard_index = 1; - dst->linecard_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_linecard_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.linecard_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_linecard_get_rsp_parse; - yrs.rsp_cmd = 80; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_linecard_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_LINECARD_GET - dump */ -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp) -{ - struct devlink_linecard_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_linecard_get_list); - yds.cb = devlink_linecard_get_rsp_parse; - yds.rsp_cmd = 80; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_linecard_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_LINECARD_SET ============== */ -/* DEVLINK_CMD_LINECARD_SET - do */ -void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->linecard_type); - free(req); -} - -int devlink_linecard_set(struct ynl_sock *ys, - struct devlink_linecard_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.linecard_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); - if (req->_present.linecard_type_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_LINECARD_TYPE, req->linecard_type); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_selftests_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_selftests_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_selftests_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_selftests_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_selftests_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp) -{ - struct devlink_selftests_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_selftests_get_list); - yds.cb = devlink_selftests_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_selftests_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ -/* DEVLINK_CMD_SELFTESTS_RUN - do */ -void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req) -{ - free(req->bus_name); - free(req->dev_name); - devlink_dl_selftest_id_free(&req->selftests); - free(req); -} - -int devlink_selftests_run(struct ynl_sock *ys, - struct devlink_selftests_run_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_RUN, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.selftests) - devlink_dl_selftest_id_put(nlh, DEVLINK_ATTR_SELFTESTS, &req->selftests); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -const struct ynl_family ynl_devlink_family = { - .name = "devlink", -}; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h deleted file mode 100644 index 1db4edc36eaa..000000000000 --- a/tools/net/ynl/generated/devlink-user.h +++ /dev/null @@ -1,5255 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_DEVLINK_GEN_H -#define _LINUX_DEVLINK_GEN_H - -#include -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_devlink_family; - -/* Enums */ -const char *devlink_op_str(int op); -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value); -const char *devlink_port_type_str(enum devlink_port_type value); -const char *devlink_port_flavour_str(enum devlink_port_flavour value); -const char *devlink_port_fn_state_str(enum devlink_port_fn_state value); -const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value); -const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value); -const char * -devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value); -const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value); -const char * -devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value); -const char * -devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value); -const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value); -const char * -devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value); -const char * -devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value); -const char *devlink_resource_unit_str(enum devlink_resource_unit value); -const char *devlink_reload_action_str(enum devlink_reload_action value); -const char *devlink_param_cmode_str(enum devlink_param_cmode value); -const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value); -const char *devlink_trap_action_str(enum devlink_trap_action value); - -/* Common nested types */ -struct devlink_dl_dpipe_match { - struct { - __u32 dpipe_match_type:1; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_index:1; - __u32 dpipe_field_id:1; - } _present; - - enum devlink_dpipe_match_type dpipe_match_type; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - __u32 dpipe_header_index; - __u32 dpipe_field_id; -}; - -struct devlink_dl_dpipe_match_value { - struct { - __u32 dpipe_value_len; - __u32 dpipe_value_mask_len; - __u32 dpipe_value_mapping:1; - } _present; - - unsigned int n_dpipe_match; - struct devlink_dl_dpipe_match *dpipe_match; - void *dpipe_value; - void *dpipe_value_mask; - __u32 dpipe_value_mapping; -}; - -struct devlink_dl_dpipe_action { - struct { - __u32 dpipe_action_type:1; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_index:1; - __u32 dpipe_field_id:1; - } _present; - - enum devlink_dpipe_action_type dpipe_action_type; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - __u32 dpipe_header_index; - __u32 dpipe_field_id; -}; - -struct devlink_dl_dpipe_action_value { - struct { - __u32 dpipe_value_len; - __u32 dpipe_value_mask_len; - __u32 dpipe_value_mapping:1; - } _present; - - unsigned int n_dpipe_action; - struct devlink_dl_dpipe_action *dpipe_action; - void *dpipe_value; - void *dpipe_value_mask; - __u32 dpipe_value_mapping; -}; - -struct devlink_dl_dpipe_field { - struct { - __u32 dpipe_field_name_len; - __u32 dpipe_field_id:1; - __u32 dpipe_field_bitwidth:1; - __u32 dpipe_field_mapping_type:1; - } _present; - - char *dpipe_field_name; - __u32 dpipe_field_id; - __u32 dpipe_field_bitwidth; - enum devlink_dpipe_field_mapping_type dpipe_field_mapping_type; -}; - -struct devlink_dl_resource { - struct { - __u32 resource_name_len; - __u32 resource_id:1; - __u32 resource_size:1; - __u32 resource_size_new:1; - __u32 resource_size_valid:1; - __u32 resource_size_min:1; - __u32 resource_size_max:1; - __u32 resource_size_gran:1; - __u32 resource_unit:1; - __u32 resource_occ:1; - } _present; - - char *resource_name; - __u64 resource_id; - __u64 resource_size; - __u64 resource_size_new; - __u8 resource_size_valid; - __u64 resource_size_min; - __u64 resource_size_max; - __u64 resource_size_gran; - enum devlink_resource_unit resource_unit; - __u64 resource_occ; -}; - -struct devlink_dl_info_version { - struct { - __u32 info_version_name_len; - __u32 info_version_value_len; - } _present; - - char *info_version_name; - char *info_version_value; -}; - -struct devlink_dl_fmsg { - struct { - __u32 fmsg_obj_nest_start:1; - __u32 fmsg_pair_nest_start:1; - __u32 fmsg_arr_nest_start:1; - __u32 fmsg_nest_end:1; - __u32 fmsg_obj_name_len; - } _present; - - char *fmsg_obj_name; -}; - -struct devlink_dl_port_function { - struct { - __u32 hw_addr_len; - __u32 state:1; - __u32 opstate:1; - __u32 caps:1; - } _present; - - void *hw_addr; - enum devlink_port_fn_state state; - enum devlink_port_fn_opstate opstate; - struct nla_bitfield32 caps; -}; - -struct devlink_dl_reload_stats_entry { - struct { - __u32 reload_stats_limit:1; - __u32 reload_stats_value:1; - } _present; - - __u8 reload_stats_limit; - __u32 reload_stats_value; -}; - -struct devlink_dl_reload_act_stats { - unsigned int n_reload_stats_entry; - struct devlink_dl_reload_stats_entry *reload_stats_entry; -}; - -struct devlink_dl_selftest_id { - struct { - __u32 flash:1; - } _present; -}; - -struct devlink_dl_dpipe_table_matches { - unsigned int n_dpipe_match; - struct devlink_dl_dpipe_match *dpipe_match; -}; - -struct devlink_dl_dpipe_table_actions { - unsigned int n_dpipe_action; - struct devlink_dl_dpipe_action *dpipe_action; -}; - -struct devlink_dl_dpipe_entry_match_values { - unsigned int n_dpipe_match_value; - struct devlink_dl_dpipe_match_value *dpipe_match_value; -}; - -struct devlink_dl_dpipe_entry_action_values { - unsigned int n_dpipe_action_value; - struct devlink_dl_dpipe_action_value *dpipe_action_value; -}; - -struct devlink_dl_dpipe_header_fields { - unsigned int n_dpipe_field; - struct devlink_dl_dpipe_field *dpipe_field; -}; - -struct devlink_dl_resource_list { - unsigned int n_resource; - struct devlink_dl_resource *resource; -}; - -struct devlink_dl_reload_act_info { - struct { - __u32 reload_action:1; - } _present; - - enum devlink_reload_action reload_action; - unsigned int n_reload_action_stats; - struct devlink_dl_reload_act_stats *reload_action_stats; -}; - -struct devlink_dl_dpipe_table { - struct { - __u32 dpipe_table_name_len; - __u32 dpipe_table_size:1; - __u32 dpipe_table_matches:1; - __u32 dpipe_table_actions:1; - __u32 dpipe_table_counters_enabled:1; - __u32 dpipe_table_resource_id:1; - __u32 dpipe_table_resource_units:1; - } _present; - - char *dpipe_table_name; - __u64 dpipe_table_size; - struct devlink_dl_dpipe_table_matches dpipe_table_matches; - struct devlink_dl_dpipe_table_actions dpipe_table_actions; - __u8 dpipe_table_counters_enabled; - __u64 dpipe_table_resource_id; - __u64 dpipe_table_resource_units; -}; - -struct devlink_dl_dpipe_entry { - struct { - __u32 dpipe_entry_index:1; - __u32 dpipe_entry_match_values:1; - __u32 dpipe_entry_action_values:1; - __u32 dpipe_entry_counter:1; - } _present; - - __u64 dpipe_entry_index; - struct devlink_dl_dpipe_entry_match_values dpipe_entry_match_values; - struct devlink_dl_dpipe_entry_action_values dpipe_entry_action_values; - __u64 dpipe_entry_counter; -}; - -struct devlink_dl_dpipe_header { - struct { - __u32 dpipe_header_name_len; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_fields:1; - } _present; - - char *dpipe_header_name; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - struct devlink_dl_dpipe_header_fields dpipe_header_fields; -}; - -struct devlink_dl_reload_stats { - unsigned int n_reload_action_info; - struct devlink_dl_reload_act_info *reload_action_info; -}; - -struct devlink_dl_dpipe_tables { - unsigned int n_dpipe_table; - struct devlink_dl_dpipe_table *dpipe_table; -}; - -struct devlink_dl_dpipe_entries { - unsigned int n_dpipe_entry; - struct devlink_dl_dpipe_entry *dpipe_entry; -}; - -struct devlink_dl_dpipe_headers { - unsigned int n_dpipe_header; - struct devlink_dl_dpipe_header *dpipe_header; -}; - -struct devlink_dl_dev_stats { - struct { - __u32 reload_stats:1; - __u32 remote_reload_stats:1; - } _present; - - struct devlink_dl_reload_stats reload_stats; - struct devlink_dl_reload_stats remote_reload_stats; -}; - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -struct devlink_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_get_req *devlink_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_get_req)); -} -void devlink_get_req_free(struct devlink_get_req *req); - -static inline void -devlink_get_req_set_bus_name(struct devlink_get_req *req, const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_get_req_set_dev_name(struct devlink_get_req *req, const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_failed:1; - __u32 dev_stats:1; - } _present; - - char *bus_name; - char *dev_name; - __u8 reload_failed; - struct devlink_dl_dev_stats dev_stats; -}; - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp); - -/* - * Get devlink instances. - */ -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req); - -/* DEVLINK_CMD_GET - dump */ -struct devlink_get_list { - struct devlink_get_list *next; - struct devlink_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_get_list_free(struct devlink_get_list *rsp); - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -struct devlink_port_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_get_req *devlink_port_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req)); -} -void devlink_port_get_req_free(struct devlink_port_get_req *req); - -static inline void -devlink_port_get_req_set_bus_name(struct devlink_port_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_set_dev_name(struct devlink_port_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_get_req_set_port_index(struct devlink_port_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_port_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp); - -/* - * Get devlink port instances. - */ -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req); - -/* DEVLINK_CMD_PORT_GET - dump */ -struct devlink_port_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_port_get_req_dump * -devlink_port_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req_dump)); -} -void devlink_port_get_req_dump_free(struct devlink_port_get_req_dump *req); - -static inline void -devlink_port_get_req_dump_set_bus_name(struct devlink_port_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_dump_set_dev_name(struct devlink_port_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_port_get_rsp_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -struct devlink_port_get_rsp_list { - struct devlink_port_get_rsp_list *next; - struct devlink_port_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp); - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req); - -/* ============== DEVLINK_CMD_PORT_SET ============== */ -/* DEVLINK_CMD_PORT_SET - do */ -struct devlink_port_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_type:1; - __u32 port_function:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - enum devlink_port_type port_type; - struct devlink_dl_port_function port_function; -}; - -static inline struct devlink_port_set_req *devlink_port_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_set_req)); -} -void devlink_port_set_req_free(struct devlink_port_set_req *req); - -static inline void -devlink_port_set_req_set_bus_name(struct devlink_port_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_set_req_set_dev_name(struct devlink_port_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_set_req_set_port_index(struct devlink_port_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_set_req_set_port_type(struct devlink_port_set_req *req, - enum devlink_port_type port_type) -{ - req->_present.port_type = 1; - req->port_type = port_type; -} -static inline void -devlink_port_set_req_set_port_function_hw_addr(struct devlink_port_set_req *req, - const void *hw_addr, size_t len) -{ - free(req->port_function.hw_addr); - req->port_function._present.hw_addr_len = len; - req->port_function.hw_addr = malloc(req->port_function._present.hw_addr_len); - memcpy(req->port_function.hw_addr, hw_addr, req->port_function._present.hw_addr_len); -} -static inline void -devlink_port_set_req_set_port_function_state(struct devlink_port_set_req *req, - enum devlink_port_fn_state state) -{ - req->_present.port_function = 1; - req->port_function._present.state = 1; - req->port_function.state = state; -} -static inline void -devlink_port_set_req_set_port_function_opstate(struct devlink_port_set_req *req, - enum devlink_port_fn_opstate opstate) -{ - req->_present.port_function = 1; - req->port_function._present.opstate = 1; - req->port_function.opstate = opstate; -} -static inline void -devlink_port_set_req_set_port_function_caps(struct devlink_port_set_req *req, - struct nla_bitfield32 *caps) -{ - req->_present.port_function = 1; - req->port_function._present.caps = 1; - memcpy(&req->port_function.caps, caps, sizeof(struct nla_bitfield32)); -} - -/* - * Set devlink port instances. - */ -int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req); - -/* ============== DEVLINK_CMD_PORT_NEW ============== */ -/* DEVLINK_CMD_PORT_NEW - do */ -struct devlink_port_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_flavour:1; - __u32 port_pci_pf_number:1; - __u32 port_pci_sf_number:1; - __u32 port_controller_number:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - enum devlink_port_flavour port_flavour; - __u16 port_pci_pf_number; - __u32 port_pci_sf_number; - __u32 port_controller_number; -}; - -static inline struct devlink_port_new_req *devlink_port_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_new_req)); -} -void devlink_port_new_req_free(struct devlink_port_new_req *req); - -static inline void -devlink_port_new_req_set_bus_name(struct devlink_port_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_new_req_set_dev_name(struct devlink_port_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_new_req_set_port_index(struct devlink_port_new_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_new_req_set_port_flavour(struct devlink_port_new_req *req, - enum devlink_port_flavour port_flavour) -{ - req->_present.port_flavour = 1; - req->port_flavour = port_flavour; -} -static inline void -devlink_port_new_req_set_port_pci_pf_number(struct devlink_port_new_req *req, - __u16 port_pci_pf_number) -{ - req->_present.port_pci_pf_number = 1; - req->port_pci_pf_number = port_pci_pf_number; -} -static inline void -devlink_port_new_req_set_port_pci_sf_number(struct devlink_port_new_req *req, - __u32 port_pci_sf_number) -{ - req->_present.port_pci_sf_number = 1; - req->port_pci_sf_number = port_pci_sf_number; -} -static inline void -devlink_port_new_req_set_port_controller_number(struct devlink_port_new_req *req, - __u32 port_controller_number) -{ - req->_present.port_controller_number = 1; - req->port_controller_number = port_controller_number; -} - -struct devlink_port_new_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp); - -/* - * Create devlink port instances. - */ -struct devlink_port_new_rsp * -devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req); - -/* ============== DEVLINK_CMD_PORT_DEL ============== */ -/* DEVLINK_CMD_PORT_DEL - do */ -struct devlink_port_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_del_req *devlink_port_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_del_req)); -} -void devlink_port_del_req_free(struct devlink_port_del_req *req); - -static inline void -devlink_port_del_req_set_bus_name(struct devlink_port_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_del_req_set_dev_name(struct devlink_port_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_del_req_set_port_index(struct devlink_port_del_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Delete devlink port instances. - */ -int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req); - -/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ -/* DEVLINK_CMD_PORT_SPLIT - do */ -struct devlink_port_split_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_split_count:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 port_split_count; -}; - -static inline struct devlink_port_split_req *devlink_port_split_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_split_req)); -} -void devlink_port_split_req_free(struct devlink_port_split_req *req); - -static inline void -devlink_port_split_req_set_bus_name(struct devlink_port_split_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_split_req_set_dev_name(struct devlink_port_split_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_split_req_set_port_index(struct devlink_port_split_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_split_req_set_port_split_count(struct devlink_port_split_req *req, - __u32 port_split_count) -{ - req->_present.port_split_count = 1; - req->port_split_count = port_split_count; -} - -/* - * Split devlink port instances. - */ -int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req); - -/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ -/* DEVLINK_CMD_PORT_UNSPLIT - do */ -struct devlink_port_unsplit_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_unsplit_req * -devlink_port_unsplit_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_unsplit_req)); -} -void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req); - -static inline void -devlink_port_unsplit_req_set_bus_name(struct devlink_port_unsplit_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_unsplit_req_set_dev_name(struct devlink_port_unsplit_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_unsplit_req_set_port_index(struct devlink_port_unsplit_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Unplit devlink port instances. - */ -int devlink_port_unsplit(struct ynl_sock *ys, - struct devlink_port_unsplit_req *req); - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -struct devlink_sb_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_get_req *devlink_sb_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req)); -} -void devlink_sb_get_req_free(struct devlink_sb_get_req *req); - -static inline void -devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_sb_index(struct devlink_sb_get_req *req, __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -struct devlink_sb_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp); - -/* - * Get shared buffer instances. - */ -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req); - -/* DEVLINK_CMD_SB_GET - dump */ -struct devlink_sb_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_get_req_dump * -devlink_sb_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req_dump)); -} -void devlink_sb_get_req_dump_free(struct devlink_sb_get_req_dump *req); - -static inline void -devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_get_list { - struct devlink_sb_get_list *next; - struct devlink_sb_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp); - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -struct devlink_sb_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_pool_get_req * -devlink_sb_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req)); -} -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req); - -static inline void -devlink_sb_pool_get_req_set_bus_name(struct devlink_sb_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_dev_name(struct devlink_sb_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_sb_index(struct devlink_sb_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_pool_get_req_set_sb_pool_index(struct devlink_sb_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp); - -/* - * Get shared buffer pool instances. - */ -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req); - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -struct devlink_sb_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_pool_get_req_dump * -devlink_sb_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req_dump)); -} -void -devlink_sb_pool_get_req_dump_free(struct devlink_sb_pool_get_req_dump *req); - -static inline void -devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_pool_get_list { - struct devlink_sb_pool_get_list *next; - struct devlink_sb_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp); - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ -/* DEVLINK_CMD_SB_POOL_SET - do */ -struct devlink_sb_pool_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_pool_threshold_type:1; - __u32 sb_pool_size:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; - enum devlink_sb_threshold_type sb_pool_threshold_type; - __u32 sb_pool_size; -}; - -static inline struct devlink_sb_pool_set_req * -devlink_sb_pool_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_set_req)); -} -void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req); - -static inline void -devlink_sb_pool_set_req_set_bus_name(struct devlink_sb_pool_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_set_req_set_dev_name(struct devlink_sb_pool_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_pool_set_req_set_sb_index(struct devlink_sb_pool_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_index(struct devlink_sb_pool_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_threshold_type(struct devlink_sb_pool_set_req *req, - enum devlink_sb_threshold_type sb_pool_threshold_type) -{ - req->_present.sb_pool_threshold_type = 1; - req->sb_pool_threshold_type = sb_pool_threshold_type; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_size(struct devlink_sb_pool_set_req *req, - __u32 sb_pool_size) -{ - req->_present.sb_pool_size = 1; - req->sb_pool_size = sb_pool_size; -} - -/* - * Set shared buffer pool instances. - */ -int devlink_sb_pool_set(struct ynl_sock *ys, - struct devlink_sb_pool_set_req *req); - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -struct devlink_sb_port_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_port_pool_get_req * -devlink_sb_port_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req)); -} -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req); - -static inline void -devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_port_index(struct devlink_sb_port_pool_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_index(struct devlink_sb_port_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_pool_index(struct devlink_sb_port_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_port_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp); - -/* - * Get shared buffer port-pool combinations and threshold. - */ -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req); - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -struct devlink_sb_port_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_port_pool_get_req_dump * -devlink_sb_port_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req_dump)); -} -void -devlink_sb_port_pool_get_req_dump_free(struct devlink_sb_port_pool_get_req_dump *req); - -static inline void -devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_port_pool_get_list { - struct devlink_sb_port_pool_get_list *next; - struct devlink_sb_port_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp); - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ -struct devlink_sb_port_pool_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_threshold:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; - __u32 sb_threshold; -}; - -static inline struct devlink_sb_port_pool_set_req * -devlink_sb_port_pool_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_set_req)); -} -void -devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req); - -static inline void -devlink_sb_port_pool_set_req_set_bus_name(struct devlink_sb_port_pool_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_set_req_set_dev_name(struct devlink_sb_port_pool_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_port_pool_set_req_set_port_index(struct devlink_sb_port_pool_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_index(struct devlink_sb_port_pool_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_pool_index(struct devlink_sb_port_pool_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_threshold(struct devlink_sb_port_pool_set_req *req, - __u32 sb_threshold) -{ - req->_present.sb_threshold = 1; - req->sb_threshold = sb_threshold; -} - -/* - * Set shared buffer port-pool combinations and threshold. - */ -int devlink_sb_port_pool_set(struct ynl_sock *ys, - struct devlink_sb_port_pool_set_req *req); - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -struct devlink_sb_tc_pool_bind_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req * -devlink_sb_tc_pool_bind_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req)); -} -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_port_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_get_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} - -struct devlink_sb_tc_pool_bind_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp); - -/* - * Get shared buffer port-TC to pool bindings and threshold. - */ -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req); - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -struct devlink_sb_tc_pool_bind_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req_dump * -devlink_sb_tc_pool_bind_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req_dump)); -} -void -devlink_sb_tc_pool_bind_get_req_dump_free(struct devlink_sb_tc_pool_bind_get_req_dump *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_tc_pool_bind_get_list { - struct devlink_sb_tc_pool_bind_get_list *next; - struct devlink_sb_tc_pool_bind_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp); - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ -struct devlink_sb_tc_pool_bind_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - __u32 sb_threshold:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; - __u32 sb_threshold; -}; - -static inline struct devlink_sb_tc_pool_bind_set_req * -devlink_sb_tc_pool_bind_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_set_req)); -} -void -devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req); - -static inline void -devlink_sb_tc_pool_bind_set_req_set_bus_name(struct devlink_sb_tc_pool_bind_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_dev_name(struct devlink_sb_tc_pool_bind_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_port_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_pool_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_set_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_threshold(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 sb_threshold) -{ - req->_present.sb_threshold = 1; - req->sb_threshold = sb_threshold; -} - -/* - * Set shared buffer port-TC to pool bindings and threshold. - */ -int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_set_req *req); - -/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ -/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ -struct devlink_sb_occ_snapshot_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_occ_snapshot_req * -devlink_sb_occ_snapshot_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_occ_snapshot_req)); -} -void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req); - -static inline void -devlink_sb_occ_snapshot_req_set_bus_name(struct devlink_sb_occ_snapshot_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_occ_snapshot_req_set_dev_name(struct devlink_sb_occ_snapshot_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_occ_snapshot_req_set_sb_index(struct devlink_sb_occ_snapshot_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -/* - * Take occupancy snapshot of shared buffer. - */ -int devlink_sb_occ_snapshot(struct ynl_sock *ys, - struct devlink_sb_occ_snapshot_req *req); - -/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ -/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ -struct devlink_sb_occ_max_clear_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_occ_max_clear_req * -devlink_sb_occ_max_clear_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_occ_max_clear_req)); -} -void -devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req); - -static inline void -devlink_sb_occ_max_clear_req_set_bus_name(struct devlink_sb_occ_max_clear_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_occ_max_clear_req_set_dev_name(struct devlink_sb_occ_max_clear_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_occ_max_clear_req_set_sb_index(struct devlink_sb_occ_max_clear_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -/* - * Clear occupancy watermarks of shared buffer. - */ -int devlink_sb_occ_max_clear(struct ynl_sock *ys, - struct devlink_sb_occ_max_clear_req *req); - -/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ -/* DEVLINK_CMD_ESWITCH_GET - do */ -struct devlink_eswitch_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_eswitch_get_req * -devlink_eswitch_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_eswitch_get_req)); -} -void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req); - -static inline void -devlink_eswitch_get_req_set_bus_name(struct devlink_eswitch_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_eswitch_get_req_set_dev_name(struct devlink_eswitch_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_eswitch_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 eswitch_mode:1; - __u32 eswitch_inline_mode:1; - __u32 eswitch_encap_mode:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_eswitch_mode eswitch_mode; - enum devlink_eswitch_inline_mode eswitch_inline_mode; - enum devlink_eswitch_encap_mode eswitch_encap_mode; -}; - -void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp); - -/* - * Get eswitch attributes. - */ -struct devlink_eswitch_get_rsp * -devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req); - -/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ -/* DEVLINK_CMD_ESWITCH_SET - do */ -struct devlink_eswitch_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 eswitch_mode:1; - __u32 eswitch_inline_mode:1; - __u32 eswitch_encap_mode:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_eswitch_mode eswitch_mode; - enum devlink_eswitch_inline_mode eswitch_inline_mode; - enum devlink_eswitch_encap_mode eswitch_encap_mode; -}; - -static inline struct devlink_eswitch_set_req * -devlink_eswitch_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_eswitch_set_req)); -} -void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req); - -static inline void -devlink_eswitch_set_req_set_bus_name(struct devlink_eswitch_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_eswitch_set_req_set_dev_name(struct devlink_eswitch_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_eswitch_set_req_set_eswitch_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_mode eswitch_mode) -{ - req->_present.eswitch_mode = 1; - req->eswitch_mode = eswitch_mode; -} -static inline void -devlink_eswitch_set_req_set_eswitch_inline_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_inline_mode eswitch_inline_mode) -{ - req->_present.eswitch_inline_mode = 1; - req->eswitch_inline_mode = eswitch_inline_mode; -} -static inline void -devlink_eswitch_set_req_set_eswitch_encap_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_encap_mode eswitch_encap_mode) -{ - req->_present.eswitch_encap_mode = 1; - req->eswitch_encap_mode = eswitch_encap_mode; -} - -/* - * Set eswitch attributes. - */ -int devlink_eswitch_set(struct ynl_sock *ys, - struct devlink_eswitch_set_req *req); - -/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ -struct devlink_dpipe_table_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; -}; - -static inline struct devlink_dpipe_table_get_req * -devlink_dpipe_table_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_table_get_req)); -} -void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req); - -static inline void -devlink_dpipe_table_get_req_set_bus_name(struct devlink_dpipe_table_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_table_get_req_set_dev_name(struct devlink_dpipe_table_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_table_get_req_set_dpipe_table_name(struct devlink_dpipe_table_get_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} - -struct devlink_dpipe_table_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_tables:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_tables dpipe_tables; -}; - -void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp); - -/* - * Get dpipe table attributes. - */ -struct devlink_dpipe_table_get_rsp * -devlink_dpipe_table_get(struct ynl_sock *ys, - struct devlink_dpipe_table_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ -/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ -struct devlink_dpipe_entries_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; -}; - -static inline struct devlink_dpipe_entries_get_req * -devlink_dpipe_entries_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_entries_get_req)); -} -void -devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req); - -static inline void -devlink_dpipe_entries_get_req_set_bus_name(struct devlink_dpipe_entries_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_entries_get_req_set_dev_name(struct devlink_dpipe_entries_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_entries_get_req_set_dpipe_table_name(struct devlink_dpipe_entries_get_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} - -struct devlink_dpipe_entries_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_entries:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_entries dpipe_entries; -}; - -void -devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp); - -/* - * Get dpipe entries attributes. - */ -struct devlink_dpipe_entries_get_rsp * -devlink_dpipe_entries_get(struct ynl_sock *ys, - struct devlink_dpipe_entries_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ -/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ -struct devlink_dpipe_headers_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_dpipe_headers_get_req * -devlink_dpipe_headers_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_headers_get_req)); -} -void -devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req); - -static inline void -devlink_dpipe_headers_get_req_set_bus_name(struct devlink_dpipe_headers_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_headers_get_req_set_dev_name(struct devlink_dpipe_headers_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_dpipe_headers_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_headers:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_headers dpipe_headers; -}; - -void -devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp); - -/* - * Get dpipe headers attributes. - */ -struct devlink_dpipe_headers_get_rsp * -devlink_dpipe_headers_get(struct ynl_sock *ys, - struct devlink_dpipe_headers_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ -struct devlink_dpipe_table_counters_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - __u32 dpipe_table_counters_enabled:1; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; - __u8 dpipe_table_counters_enabled; -}; - -static inline struct devlink_dpipe_table_counters_set_req * -devlink_dpipe_table_counters_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_table_counters_set_req)); -} -void -devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req); - -static inline void -devlink_dpipe_table_counters_set_req_set_bus_name(struct devlink_dpipe_table_counters_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dev_name(struct devlink_dpipe_table_counters_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dpipe_table_name(struct devlink_dpipe_table_counters_set_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dpipe_table_counters_enabled(struct devlink_dpipe_table_counters_set_req *req, - __u8 dpipe_table_counters_enabled) -{ - req->_present.dpipe_table_counters_enabled = 1; - req->dpipe_table_counters_enabled = dpipe_table_counters_enabled; -} - -/* - * Set dpipe counter attributes. - */ -int devlink_dpipe_table_counters_set(struct ynl_sock *ys, - struct devlink_dpipe_table_counters_set_req *req); - -/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ -/* DEVLINK_CMD_RESOURCE_SET - do */ -struct devlink_resource_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 resource_id:1; - __u32 resource_size:1; - } _present; - - char *bus_name; - char *dev_name; - __u64 resource_id; - __u64 resource_size; -}; - -static inline struct devlink_resource_set_req * -devlink_resource_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_resource_set_req)); -} -void devlink_resource_set_req_free(struct devlink_resource_set_req *req); - -static inline void -devlink_resource_set_req_set_bus_name(struct devlink_resource_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_resource_set_req_set_dev_name(struct devlink_resource_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_resource_set_req_set_resource_id(struct devlink_resource_set_req *req, - __u64 resource_id) -{ - req->_present.resource_id = 1; - req->resource_id = resource_id; -} -static inline void -devlink_resource_set_req_set_resource_size(struct devlink_resource_set_req *req, - __u64 resource_size) -{ - req->_present.resource_size = 1; - req->resource_size = resource_size; -} - -/* - * Set resource attributes. - */ -int devlink_resource_set(struct ynl_sock *ys, - struct devlink_resource_set_req *req); - -/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ -/* DEVLINK_CMD_RESOURCE_DUMP - do */ -struct devlink_resource_dump_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_resource_dump_req * -devlink_resource_dump_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_resource_dump_req)); -} -void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req); - -static inline void -devlink_resource_dump_req_set_bus_name(struct devlink_resource_dump_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_resource_dump_req_set_dev_name(struct devlink_resource_dump_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_resource_dump_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 resource_list:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_resource_list resource_list; -}; - -void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp); - -/* - * Get resource attributes. - */ -struct devlink_resource_dump_rsp * -devlink_resource_dump(struct ynl_sock *ys, - struct devlink_resource_dump_req *req); - -/* ============== DEVLINK_CMD_RELOAD ============== */ -/* DEVLINK_CMD_RELOAD - do */ -struct devlink_reload_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_action:1; - __u32 reload_limits:1; - __u32 netns_pid:1; - __u32 netns_fd:1; - __u32 netns_id:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_reload_action reload_action; - struct nla_bitfield32 reload_limits; - __u32 netns_pid; - __u32 netns_fd; - __u32 netns_id; -}; - -static inline struct devlink_reload_req *devlink_reload_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_reload_req)); -} -void devlink_reload_req_free(struct devlink_reload_req *req); - -static inline void -devlink_reload_req_set_bus_name(struct devlink_reload_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_reload_req_set_dev_name(struct devlink_reload_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_reload_req_set_reload_action(struct devlink_reload_req *req, - enum devlink_reload_action reload_action) -{ - req->_present.reload_action = 1; - req->reload_action = reload_action; -} -static inline void -devlink_reload_req_set_reload_limits(struct devlink_reload_req *req, - struct nla_bitfield32 *reload_limits) -{ - req->_present.reload_limits = 1; - memcpy(&req->reload_limits, reload_limits, sizeof(struct nla_bitfield32)); -} -static inline void -devlink_reload_req_set_netns_pid(struct devlink_reload_req *req, - __u32 netns_pid) -{ - req->_present.netns_pid = 1; - req->netns_pid = netns_pid; -} -static inline void -devlink_reload_req_set_netns_fd(struct devlink_reload_req *req, __u32 netns_fd) -{ - req->_present.netns_fd = 1; - req->netns_fd = netns_fd; -} -static inline void -devlink_reload_req_set_netns_id(struct devlink_reload_req *req, __u32 netns_id) -{ - req->_present.netns_id = 1; - req->netns_id = netns_id; -} - -struct devlink_reload_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_actions_performed:1; - } _present; - - char *bus_name; - char *dev_name; - struct nla_bitfield32 reload_actions_performed; -}; - -void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp); - -/* - * Reload devlink. - */ -struct devlink_reload_rsp * -devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req); - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -struct devlink_param_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -static inline struct devlink_param_get_req *devlink_param_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req)); -} -void devlink_param_get_req_free(struct devlink_param_get_req *req); - -static inline void -devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_param_get_req_set_param_name(struct devlink_param_get_req *req, - const char *param_name) -{ - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; -} - -struct devlink_param_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp); - -/* - * Get param instances. - */ -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req); - -/* DEVLINK_CMD_PARAM_GET - dump */ -struct devlink_param_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_param_get_req_dump * -devlink_param_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req_dump)); -} -void devlink_param_get_req_dump_free(struct devlink_param_get_req_dump *req); - -static inline void -devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_param_get_list { - struct devlink_param_get_list *next; - struct devlink_param_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_param_get_list_free(struct devlink_param_get_list *rsp); - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req); - -/* ============== DEVLINK_CMD_PARAM_SET ============== */ -/* DEVLINK_CMD_PARAM_SET - do */ -struct devlink_param_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - __u32 param_type:1; - __u32 param_value_cmode:1; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; - __u8 param_type; - enum devlink_param_cmode param_value_cmode; -}; - -static inline struct devlink_param_set_req *devlink_param_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_set_req)); -} -void devlink_param_set_req_free(struct devlink_param_set_req *req); - -static inline void -devlink_param_set_req_set_bus_name(struct devlink_param_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_set_req_set_dev_name(struct devlink_param_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_param_set_req_set_param_name(struct devlink_param_set_req *req, - const char *param_name) -{ - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; -} -static inline void -devlink_param_set_req_set_param_type(struct devlink_param_set_req *req, - __u8 param_type) -{ - req->_present.param_type = 1; - req->param_type = param_type; -} -static inline void -devlink_param_set_req_set_param_value_cmode(struct devlink_param_set_req *req, - enum devlink_param_cmode param_value_cmode) -{ - req->_present.param_value_cmode = 1; - req->param_value_cmode = param_value_cmode; -} - -/* - * Set param instances. - */ -int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req); - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -struct devlink_region_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -static inline struct devlink_region_get_req *devlink_region_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req)); -} -void devlink_region_get_req_free(struct devlink_region_get_req *req); - -static inline void -devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_get_req_set_port_index(struct devlink_region_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_get_req_set_region_name(struct devlink_region_get_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} - -struct devlink_region_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp); - -/* - * Get region instances. - */ -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req); - -/* DEVLINK_CMD_REGION_GET - dump */ -struct devlink_region_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_region_get_req_dump * -devlink_region_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req_dump)); -} -void devlink_region_get_req_dump_free(struct devlink_region_get_req_dump *req); - -static inline void -devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_region_get_list { - struct devlink_region_get_list *next; - struct devlink_region_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_region_get_list_free(struct devlink_region_get_list *rsp); - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req); - -/* ============== DEVLINK_CMD_REGION_NEW ============== */ -/* DEVLINK_CMD_REGION_NEW - do */ -struct devlink_region_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -static inline struct devlink_region_new_req *devlink_region_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_new_req)); -} -void devlink_region_new_req_free(struct devlink_region_new_req *req); - -static inline void -devlink_region_new_req_set_bus_name(struct devlink_region_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_new_req_set_dev_name(struct devlink_region_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_new_req_set_port_index(struct devlink_region_new_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_new_req_set_region_name(struct devlink_region_new_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_new_req_set_region_snapshot_id(struct devlink_region_new_req *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} - -struct devlink_region_new_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp); - -/* - * Create region snapshot. - */ -struct devlink_region_new_rsp * -devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req); - -/* ============== DEVLINK_CMD_REGION_DEL ============== */ -/* DEVLINK_CMD_REGION_DEL - do */ -struct devlink_region_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -static inline struct devlink_region_del_req *devlink_region_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_del_req)); -} -void devlink_region_del_req_free(struct devlink_region_del_req *req); - -static inline void -devlink_region_del_req_set_bus_name(struct devlink_region_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_del_req_set_dev_name(struct devlink_region_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_del_req_set_port_index(struct devlink_region_del_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_del_req_set_region_name(struct devlink_region_del_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_del_req_set_region_snapshot_id(struct devlink_region_del_req *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} - -/* - * Delete region snapshot. - */ -int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req); - -/* ============== DEVLINK_CMD_REGION_READ ============== */ -/* DEVLINK_CMD_REGION_READ - dump */ -struct devlink_region_read_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - __u32 region_direct:1; - __u32 region_chunk_addr:1; - __u32 region_chunk_len:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; - __u64 region_chunk_addr; - __u64 region_chunk_len; -}; - -static inline struct devlink_region_read_req_dump * -devlink_region_read_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_read_req_dump)); -} -void -devlink_region_read_req_dump_free(struct devlink_region_read_req_dump *req); - -static inline void -devlink_region_read_req_dump_set_bus_name(struct devlink_region_read_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_dev_name(struct devlink_region_read_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_port_index(struct devlink_region_read_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_read_req_dump_set_region_name(struct devlink_region_read_req_dump *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_region_snapshot_id(struct devlink_region_read_req_dump *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} -static inline void -devlink_region_read_req_dump_set_region_direct(struct devlink_region_read_req_dump *req) -{ - req->_present.region_direct = 1; -} -static inline void -devlink_region_read_req_dump_set_region_chunk_addr(struct devlink_region_read_req_dump *req, - __u64 region_chunk_addr) -{ - req->_present.region_chunk_addr = 1; - req->region_chunk_addr = region_chunk_addr; -} -static inline void -devlink_region_read_req_dump_set_region_chunk_len(struct devlink_region_read_req_dump *req, - __u64 region_chunk_len) -{ - req->_present.region_chunk_len = 1; - req->region_chunk_len = region_chunk_len; -} - -struct devlink_region_read_rsp_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -struct devlink_region_read_rsp_list { - struct devlink_region_read_rsp_list *next; - struct devlink_region_read_rsp_dump obj __attribute__((aligned(8))); -}; - -void -devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp); - -struct devlink_region_read_rsp_list * -devlink_region_read_dump(struct ynl_sock *ys, - struct devlink_region_read_req_dump *req); - -/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ -/* DEVLINK_CMD_PORT_PARAM_GET - do */ -struct devlink_port_param_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_param_get_req * -devlink_port_param_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_param_get_req)); -} -void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req); - -static inline void -devlink_port_param_get_req_set_bus_name(struct devlink_port_param_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_param_get_req_set_dev_name(struct devlink_port_param_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_param_get_req_set_port_index(struct devlink_port_param_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_port_param_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp); - -/* - * Get port param instances. - */ -struct devlink_port_param_get_rsp * -devlink_port_param_get(struct ynl_sock *ys, - struct devlink_port_param_get_req *req); - -/* DEVLINK_CMD_PORT_PARAM_GET - dump */ -struct devlink_port_param_get_list { - struct devlink_port_param_get_list *next; - struct devlink_port_param_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp); - -struct devlink_port_param_get_list * -devlink_port_param_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ -/* DEVLINK_CMD_PORT_PARAM_SET - do */ -struct devlink_port_param_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_param_set_req * -devlink_port_param_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_param_set_req)); -} -void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req); - -static inline void -devlink_port_param_set_req_set_bus_name(struct devlink_port_param_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_param_set_req_set_dev_name(struct devlink_port_param_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_param_set_req_set_port_index(struct devlink_port_param_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Set port param instances. - */ -int devlink_port_param_set(struct ynl_sock *ys, - struct devlink_port_param_set_req *req); - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -struct devlink_info_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_info_get_req)); -} -void devlink_info_get_req_free(struct devlink_info_get_req *req); - -static inline void -devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_info_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 info_driver_name_len; - __u32 info_serial_number_len; - } _present; - - char *bus_name; - char *dev_name; - char *info_driver_name; - char *info_serial_number; - unsigned int n_info_version_fixed; - struct devlink_dl_info_version *info_version_fixed; - unsigned int n_info_version_running; - struct devlink_dl_info_version *info_version_running; - unsigned int n_info_version_stored; - struct devlink_dl_info_version *info_version_stored; -}; - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); - -/* - * Get device information, like driver name, hardware and firmware versions etc. - */ -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); - -/* DEVLINK_CMD_INFO_GET - dump */ -struct devlink_info_get_list { - struct devlink_info_get_list *next; - struct devlink_info_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_info_get_list_free(struct devlink_info_get_list *rsp); - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -struct devlink_health_reporter_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_get_req * -devlink_health_reporter_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req)); -} -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req); - -static inline void -devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_port_index(struct devlink_health_reporter_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_reporter_get_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -struct devlink_health_reporter_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp); - -/* - * Get health reporter instances. - */ -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req); - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -struct devlink_health_reporter_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_health_reporter_get_req_dump * -devlink_health_reporter_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req_dump)); -} -void -devlink_health_reporter_get_req_dump_free(struct devlink_health_reporter_get_req_dump *req); - -static inline void -devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_port_index(struct devlink_health_reporter_get_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_health_reporter_get_list { - struct devlink_health_reporter_get_list *next; - struct devlink_health_reporter_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp); - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ -struct devlink_health_reporter_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - __u32 health_reporter_graceful_period:1; - __u32 health_reporter_auto_recover:1; - __u32 health_reporter_auto_dump:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; - __u64 health_reporter_graceful_period; - __u8 health_reporter_auto_recover; - __u8 health_reporter_auto_dump; -}; - -static inline struct devlink_health_reporter_set_req * -devlink_health_reporter_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_set_req)); -} -void -devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req); - -static inline void -devlink_health_reporter_set_req_set_bus_name(struct devlink_health_reporter_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_dev_name(struct devlink_health_reporter_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_port_index(struct devlink_health_reporter_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_name(struct devlink_health_reporter_set_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_graceful_period(struct devlink_health_reporter_set_req *req, - __u64 health_reporter_graceful_period) -{ - req->_present.health_reporter_graceful_period = 1; - req->health_reporter_graceful_period = health_reporter_graceful_period; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_auto_recover(struct devlink_health_reporter_set_req *req, - __u8 health_reporter_auto_recover) -{ - req->_present.health_reporter_auto_recover = 1; - req->health_reporter_auto_recover = health_reporter_auto_recover; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_auto_dump(struct devlink_health_reporter_set_req *req, - __u8 health_reporter_auto_dump) -{ - req->_present.health_reporter_auto_dump = 1; - req->health_reporter_auto_dump = health_reporter_auto_dump; -} - -/* - * Set health reporter instances. - */ -int devlink_health_reporter_set(struct ynl_sock *ys, - struct devlink_health_reporter_set_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ -struct devlink_health_reporter_recover_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_recover_req * -devlink_health_reporter_recover_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_recover_req)); -} -void -devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req); - -static inline void -devlink_health_reporter_recover_req_set_bus_name(struct devlink_health_reporter_recover_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_recover_req_set_dev_name(struct devlink_health_reporter_recover_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_recover_req_set_port_index(struct devlink_health_reporter_recover_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_recover_req_set_health_reporter_name(struct devlink_health_reporter_recover_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Recover health reporter instances. - */ -int devlink_health_reporter_recover(struct ynl_sock *ys, - struct devlink_health_reporter_recover_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ -struct devlink_health_reporter_diagnose_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_diagnose_req * -devlink_health_reporter_diagnose_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_diagnose_req)); -} -void -devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req); - -static inline void -devlink_health_reporter_diagnose_req_set_bus_name(struct devlink_health_reporter_diagnose_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_diagnose_req_set_dev_name(struct devlink_health_reporter_diagnose_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_diagnose_req_set_port_index(struct devlink_health_reporter_diagnose_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_diagnose_req_set_health_reporter_name(struct devlink_health_reporter_diagnose_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Diagnose health reporter instances. - */ -int devlink_health_reporter_diagnose(struct ynl_sock *ys, - struct devlink_health_reporter_diagnose_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ -struct devlink_health_reporter_dump_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_dump_get_req_dump * -devlink_health_reporter_dump_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_dump_get_req_dump)); -} -void -devlink_health_reporter_dump_get_req_dump_free(struct devlink_health_reporter_dump_get_req_dump *req); - -static inline void -devlink_health_reporter_dump_get_req_dump_set_bus_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_dev_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_port_index(struct devlink_health_reporter_dump_get_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_health_reporter_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -struct devlink_health_reporter_dump_get_rsp_dump { - struct { - __u32 fmsg:1; - } _present; - - struct devlink_dl_fmsg fmsg; -}; - -struct devlink_health_reporter_dump_get_rsp_list { - struct devlink_health_reporter_dump_get_rsp_list *next; - struct devlink_health_reporter_dump_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void -devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp); - -struct devlink_health_reporter_dump_get_rsp_list * -devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_dump_get_req_dump *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ -struct devlink_health_reporter_dump_clear_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_dump_clear_req * -devlink_health_reporter_dump_clear_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_dump_clear_req)); -} -void -devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req); - -static inline void -devlink_health_reporter_dump_clear_req_set_bus_name(struct devlink_health_reporter_dump_clear_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_clear_req_set_dev_name(struct devlink_health_reporter_dump_clear_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_clear_req_set_port_index(struct devlink_health_reporter_dump_clear_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_dump_clear_req_set_health_reporter_name(struct devlink_health_reporter_dump_clear_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Clear dump of health reporter instances. - */ -int devlink_health_reporter_dump_clear(struct ynl_sock *ys, - struct devlink_health_reporter_dump_clear_req *req); - -/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ -/* DEVLINK_CMD_FLASH_UPDATE - do */ -struct devlink_flash_update_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 flash_update_file_name_len; - __u32 flash_update_component_len; - __u32 flash_update_overwrite_mask:1; - } _present; - - char *bus_name; - char *dev_name; - char *flash_update_file_name; - char *flash_update_component; - struct nla_bitfield32 flash_update_overwrite_mask; -}; - -static inline struct devlink_flash_update_req * -devlink_flash_update_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_flash_update_req)); -} -void devlink_flash_update_req_free(struct devlink_flash_update_req *req); - -static inline void -devlink_flash_update_req_set_bus_name(struct devlink_flash_update_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_dev_name(struct devlink_flash_update_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_file_name(struct devlink_flash_update_req *req, - const char *flash_update_file_name) -{ - free(req->flash_update_file_name); - req->_present.flash_update_file_name_len = strlen(flash_update_file_name); - req->flash_update_file_name = malloc(req->_present.flash_update_file_name_len + 1); - memcpy(req->flash_update_file_name, flash_update_file_name, req->_present.flash_update_file_name_len); - req->flash_update_file_name[req->_present.flash_update_file_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_component(struct devlink_flash_update_req *req, - const char *flash_update_component) -{ - free(req->flash_update_component); - req->_present.flash_update_component_len = strlen(flash_update_component); - req->flash_update_component = malloc(req->_present.flash_update_component_len + 1); - memcpy(req->flash_update_component, flash_update_component, req->_present.flash_update_component_len); - req->flash_update_component[req->_present.flash_update_component_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_overwrite_mask(struct devlink_flash_update_req *req, - struct nla_bitfield32 *flash_update_overwrite_mask) -{ - req->_present.flash_update_overwrite_mask = 1; - memcpy(&req->flash_update_overwrite_mask, flash_update_overwrite_mask, sizeof(struct nla_bitfield32)); -} - -/* - * Flash update devlink instances. - */ -int devlink_flash_update(struct ynl_sock *ys, - struct devlink_flash_update_req *req); - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -struct devlink_trap_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -static inline struct devlink_trap_get_req *devlink_trap_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req)); -} -void devlink_trap_get_req_free(struct devlink_trap_get_req *req); - -static inline void -devlink_trap_get_req_set_bus_name(struct devlink_trap_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_dev_name(struct devlink_trap_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_trap_name(struct devlink_trap_get_req *req, - const char *trap_name) -{ - free(req->trap_name); - req->_present.trap_name_len = strlen(trap_name); - req->trap_name = malloc(req->_present.trap_name_len + 1); - memcpy(req->trap_name, trap_name, req->_present.trap_name_len); - req->trap_name[req->_present.trap_name_len] = 0; -} - -struct devlink_trap_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp); - -/* - * Get trap instances. - */ -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req); - -/* DEVLINK_CMD_TRAP_GET - dump */ -struct devlink_trap_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_get_req_dump * -devlink_trap_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req_dump)); -} -void devlink_trap_get_req_dump_free(struct devlink_trap_get_req_dump *req); - -static inline void -devlink_trap_get_req_dump_set_bus_name(struct devlink_trap_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_dump_set_dev_name(struct devlink_trap_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_get_list { - struct devlink_trap_get_list *next; - struct devlink_trap_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp); - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_SET ============== */ -/* DEVLINK_CMD_TRAP_SET - do */ -struct devlink_trap_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - __u32 trap_action:1; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; - enum devlink_trap_action trap_action; -}; - -static inline struct devlink_trap_set_req *devlink_trap_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_set_req)); -} -void devlink_trap_set_req_free(struct devlink_trap_set_req *req); - -static inline void -devlink_trap_set_req_set_bus_name(struct devlink_trap_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_dev_name(struct devlink_trap_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_trap_name(struct devlink_trap_set_req *req, - const char *trap_name) -{ - free(req->trap_name); - req->_present.trap_name_len = strlen(trap_name); - req->trap_name = malloc(req->_present.trap_name_len + 1); - memcpy(req->trap_name, trap_name, req->_present.trap_name_len); - req->trap_name[req->_present.trap_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_trap_action(struct devlink_trap_set_req *req, - enum devlink_trap_action trap_action) -{ - req->_present.trap_action = 1; - req->trap_action = trap_action; -} - -/* - * Set trap instances. - */ -int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req); - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -struct devlink_trap_group_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -static inline struct devlink_trap_group_get_req * -devlink_trap_group_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req)); -} -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req); - -static inline void -devlink_trap_group_get_req_set_bus_name(struct devlink_trap_group_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_dev_name(struct devlink_trap_group_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_trap_group_name(struct devlink_trap_group_get_req *req, - const char *trap_group_name) -{ - free(req->trap_group_name); - req->_present.trap_group_name_len = strlen(trap_group_name); - req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); - memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); - req->trap_group_name[req->_present.trap_group_name_len] = 0; -} - -struct devlink_trap_group_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp); - -/* - * Get trap group instances. - */ -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req); - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -struct devlink_trap_group_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_group_get_req_dump * -devlink_trap_group_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req_dump)); -} -void -devlink_trap_group_get_req_dump_free(struct devlink_trap_group_get_req_dump *req); - -static inline void -devlink_trap_group_get_req_dump_set_bus_name(struct devlink_trap_group_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_dump_set_dev_name(struct devlink_trap_group_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_group_get_list { - struct devlink_trap_group_get_list *next; - struct devlink_trap_group_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp); - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_SET - do */ -struct devlink_trap_group_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - __u32 trap_action:1; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; - enum devlink_trap_action trap_action; - __u32 trap_policer_id; -}; - -static inline struct devlink_trap_group_set_req * -devlink_trap_group_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_set_req)); -} -void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req); - -static inline void -devlink_trap_group_set_req_set_bus_name(struct devlink_trap_group_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_dev_name(struct devlink_trap_group_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_trap_group_name(struct devlink_trap_group_set_req *req, - const char *trap_group_name) -{ - free(req->trap_group_name); - req->_present.trap_group_name_len = strlen(trap_group_name); - req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); - memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); - req->trap_group_name[req->_present.trap_group_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_trap_action(struct devlink_trap_group_set_req *req, - enum devlink_trap_action trap_action) -{ - req->_present.trap_action = 1; - req->trap_action = trap_action; -} -static inline void -devlink_trap_group_set_req_set_trap_policer_id(struct devlink_trap_group_set_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} - -/* - * Set trap group instances. - */ -int devlink_trap_group_set(struct ynl_sock *ys, - struct devlink_trap_group_set_req *req); - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -struct devlink_trap_policer_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -static inline struct devlink_trap_policer_get_req * -devlink_trap_policer_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req)); -} -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req); - -static inline void -devlink_trap_policer_get_req_set_bus_name(struct devlink_trap_policer_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_dev_name(struct devlink_trap_policer_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_trap_policer_id(struct devlink_trap_policer_get_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} - -struct devlink_trap_policer_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp); - -/* - * Get trap policer instances. - */ -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req); - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -struct devlink_trap_policer_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_policer_get_req_dump * -devlink_trap_policer_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req_dump)); -} -void -devlink_trap_policer_get_req_dump_free(struct devlink_trap_policer_get_req_dump *req); - -static inline void -devlink_trap_policer_get_req_dump_set_bus_name(struct devlink_trap_policer_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_dump_set_dev_name(struct devlink_trap_policer_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_policer_get_list { - struct devlink_trap_policer_get_list *next; - struct devlink_trap_policer_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp); - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_SET - do */ -struct devlink_trap_policer_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - __u32 trap_policer_rate:1; - __u32 trap_policer_burst:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; - __u64 trap_policer_rate; - __u64 trap_policer_burst; -}; - -static inline struct devlink_trap_policer_set_req * -devlink_trap_policer_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_set_req)); -} -void -devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req); - -static inline void -devlink_trap_policer_set_req_set_bus_name(struct devlink_trap_policer_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_set_req_set_dev_name(struct devlink_trap_policer_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_id(struct devlink_trap_policer_set_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_rate(struct devlink_trap_policer_set_req *req, - __u64 trap_policer_rate) -{ - req->_present.trap_policer_rate = 1; - req->trap_policer_rate = trap_policer_rate; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_burst(struct devlink_trap_policer_set_req *req, - __u64 trap_policer_burst) -{ - req->_present.trap_policer_burst = 1; - req->trap_policer_burst = trap_policer_burst; -} - -/* - * Get trap policer instances. - */ -int devlink_trap_policer_set(struct ynl_sock *ys, - struct devlink_trap_policer_set_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ -struct devlink_health_reporter_test_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_test_req * -devlink_health_reporter_test_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_test_req)); -} -void -devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req); - -static inline void -devlink_health_reporter_test_req_set_bus_name(struct devlink_health_reporter_test_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_test_req_set_dev_name(struct devlink_health_reporter_test_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_test_req_set_port_index(struct devlink_health_reporter_test_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_test_req_set_health_reporter_name(struct devlink_health_reporter_test_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Test health reporter instances. - */ -int devlink_health_reporter_test(struct ynl_sock *ys, - struct devlink_health_reporter_test_req *req); - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -struct devlink_rate_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -static inline struct devlink_rate_get_req *devlink_rate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req)); -} -void devlink_rate_get_req_free(struct devlink_rate_get_req *req); - -static inline void -devlink_rate_get_req_set_bus_name(struct devlink_rate_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_dev_name(struct devlink_rate_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_port_index(struct devlink_rate_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_rate_get_req_set_rate_node_name(struct devlink_rate_get_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} - -struct devlink_rate_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp); - -/* - * Get rate instances. - */ -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req); - -/* DEVLINK_CMD_RATE_GET - dump */ -struct devlink_rate_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_rate_get_req_dump * -devlink_rate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req_dump)); -} -void devlink_rate_get_req_dump_free(struct devlink_rate_get_req_dump *req); - -static inline void -devlink_rate_get_req_dump_set_bus_name(struct devlink_rate_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_dump_set_dev_name(struct devlink_rate_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_rate_get_list { - struct devlink_rate_get_list *next; - struct devlink_rate_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp); - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req); - -/* ============== DEVLINK_CMD_RATE_SET ============== */ -/* DEVLINK_CMD_RATE_SET - do */ -struct devlink_rate_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - __u32 rate_tx_share:1; - __u32 rate_tx_max:1; - __u32 rate_tx_priority:1; - __u32 rate_tx_weight:1; - __u32 rate_parent_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; - __u64 rate_tx_share; - __u64 rate_tx_max; - __u32 rate_tx_priority; - __u32 rate_tx_weight; - char *rate_parent_node_name; -}; - -static inline struct devlink_rate_set_req *devlink_rate_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_set_req)); -} -void devlink_rate_set_req_free(struct devlink_rate_set_req *req); - -static inline void -devlink_rate_set_req_set_bus_name(struct devlink_rate_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_dev_name(struct devlink_rate_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_rate_node_name(struct devlink_rate_set_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_rate_tx_share(struct devlink_rate_set_req *req, - __u64 rate_tx_share) -{ - req->_present.rate_tx_share = 1; - req->rate_tx_share = rate_tx_share; -} -static inline void -devlink_rate_set_req_set_rate_tx_max(struct devlink_rate_set_req *req, - __u64 rate_tx_max) -{ - req->_present.rate_tx_max = 1; - req->rate_tx_max = rate_tx_max; -} -static inline void -devlink_rate_set_req_set_rate_tx_priority(struct devlink_rate_set_req *req, - __u32 rate_tx_priority) -{ - req->_present.rate_tx_priority = 1; - req->rate_tx_priority = rate_tx_priority; -} -static inline void -devlink_rate_set_req_set_rate_tx_weight(struct devlink_rate_set_req *req, - __u32 rate_tx_weight) -{ - req->_present.rate_tx_weight = 1; - req->rate_tx_weight = rate_tx_weight; -} -static inline void -devlink_rate_set_req_set_rate_parent_node_name(struct devlink_rate_set_req *req, - const char *rate_parent_node_name) -{ - free(req->rate_parent_node_name); - req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); - req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); - memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); - req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; -} - -/* - * Set rate instances. - */ -int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req); - -/* ============== DEVLINK_CMD_RATE_NEW ============== */ -/* DEVLINK_CMD_RATE_NEW - do */ -struct devlink_rate_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - __u32 rate_tx_share:1; - __u32 rate_tx_max:1; - __u32 rate_tx_priority:1; - __u32 rate_tx_weight:1; - __u32 rate_parent_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; - __u64 rate_tx_share; - __u64 rate_tx_max; - __u32 rate_tx_priority; - __u32 rate_tx_weight; - char *rate_parent_node_name; -}; - -static inline struct devlink_rate_new_req *devlink_rate_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_new_req)); -} -void devlink_rate_new_req_free(struct devlink_rate_new_req *req); - -static inline void -devlink_rate_new_req_set_bus_name(struct devlink_rate_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_dev_name(struct devlink_rate_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_rate_node_name(struct devlink_rate_new_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_rate_tx_share(struct devlink_rate_new_req *req, - __u64 rate_tx_share) -{ - req->_present.rate_tx_share = 1; - req->rate_tx_share = rate_tx_share; -} -static inline void -devlink_rate_new_req_set_rate_tx_max(struct devlink_rate_new_req *req, - __u64 rate_tx_max) -{ - req->_present.rate_tx_max = 1; - req->rate_tx_max = rate_tx_max; -} -static inline void -devlink_rate_new_req_set_rate_tx_priority(struct devlink_rate_new_req *req, - __u32 rate_tx_priority) -{ - req->_present.rate_tx_priority = 1; - req->rate_tx_priority = rate_tx_priority; -} -static inline void -devlink_rate_new_req_set_rate_tx_weight(struct devlink_rate_new_req *req, - __u32 rate_tx_weight) -{ - req->_present.rate_tx_weight = 1; - req->rate_tx_weight = rate_tx_weight; -} -static inline void -devlink_rate_new_req_set_rate_parent_node_name(struct devlink_rate_new_req *req, - const char *rate_parent_node_name) -{ - free(req->rate_parent_node_name); - req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); - req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); - memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); - req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; -} - -/* - * Create rate instances. - */ -int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req); - -/* ============== DEVLINK_CMD_RATE_DEL ============== */ -/* DEVLINK_CMD_RATE_DEL - do */ -struct devlink_rate_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; -}; - -static inline struct devlink_rate_del_req *devlink_rate_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_del_req)); -} -void devlink_rate_del_req_free(struct devlink_rate_del_req *req); - -static inline void -devlink_rate_del_req_set_bus_name(struct devlink_rate_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_del_req_set_dev_name(struct devlink_rate_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_del_req_set_rate_node_name(struct devlink_rate_del_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} - -/* - * Delete rate instances. - */ -int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req); - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -struct devlink_linecard_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -static inline struct devlink_linecard_get_req * -devlink_linecard_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req)); -} -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req); - -static inline void -devlink_linecard_get_req_set_bus_name(struct devlink_linecard_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_dev_name(struct devlink_linecard_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_linecard_index(struct devlink_linecard_get_req *req, - __u32 linecard_index) -{ - req->_present.linecard_index = 1; - req->linecard_index = linecard_index; -} - -struct devlink_linecard_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp); - -/* - * Get line card instances. - */ -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req); - -/* DEVLINK_CMD_LINECARD_GET - dump */ -struct devlink_linecard_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_linecard_get_req_dump * -devlink_linecard_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req_dump)); -} -void -devlink_linecard_get_req_dump_free(struct devlink_linecard_get_req_dump *req); - -static inline void -devlink_linecard_get_req_dump_set_bus_name(struct devlink_linecard_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_dump_set_dev_name(struct devlink_linecard_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_linecard_get_list { - struct devlink_linecard_get_list *next; - struct devlink_linecard_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp); - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req); - -/* ============== DEVLINK_CMD_LINECARD_SET ============== */ -/* DEVLINK_CMD_LINECARD_SET - do */ -struct devlink_linecard_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - __u32 linecard_type_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; - char *linecard_type; -}; - -static inline struct devlink_linecard_set_req * -devlink_linecard_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_set_req)); -} -void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req); - -static inline void -devlink_linecard_set_req_set_bus_name(struct devlink_linecard_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_set_req_set_dev_name(struct devlink_linecard_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_linecard_set_req_set_linecard_index(struct devlink_linecard_set_req *req, - __u32 linecard_index) -{ - req->_present.linecard_index = 1; - req->linecard_index = linecard_index; -} -static inline void -devlink_linecard_set_req_set_linecard_type(struct devlink_linecard_set_req *req, - const char *linecard_type) -{ - free(req->linecard_type); - req->_present.linecard_type_len = strlen(linecard_type); - req->linecard_type = malloc(req->_present.linecard_type_len + 1); - memcpy(req->linecard_type, linecard_type, req->_present.linecard_type_len); - req->linecard_type[req->_present.linecard_type_len] = 0; -} - -/* - * Set line card instances. - */ -int devlink_linecard_set(struct ynl_sock *ys, - struct devlink_linecard_set_req *req); - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -struct devlink_selftests_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_selftests_get_req * -devlink_selftests_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_selftests_get_req)); -} -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req); - -static inline void -devlink_selftests_get_req_set_bus_name(struct devlink_selftests_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_selftests_get_req_set_dev_name(struct devlink_selftests_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_selftests_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp); - -/* - * Get device selftest instances. - */ -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req); - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -struct devlink_selftests_get_list { - struct devlink_selftests_get_list *next; - struct devlink_selftests_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp); - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ -/* DEVLINK_CMD_SELFTESTS_RUN - do */ -struct devlink_selftests_run_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 selftests:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_selftest_id selftests; -}; - -static inline struct devlink_selftests_run_req * -devlink_selftests_run_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_selftests_run_req)); -} -void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req); - -static inline void -devlink_selftests_run_req_set_bus_name(struct devlink_selftests_run_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_selftests_run_req_set_dev_name(struct devlink_selftests_run_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_selftests_run_req_set_selftests_flash(struct devlink_selftests_run_req *req) -{ - req->_present.selftests = 1; - req->selftests._present.flash = 1; -} - -/* - * Run device selftest instances. - */ -int devlink_selftests_run(struct ynl_sock *ys, - struct devlink_selftests_run_req *req); - -#endif /* _LINUX_DEVLINK_GEN_H */ diff --git a/tools/net/ynl/generated/ethtool-user.c b/tools/net/ynl/generated/ethtool-user.c deleted file mode 100644 index 660435639e2b..000000000000 --- a/tools/net/ynl/generated/ethtool-user.c +++ /dev/null @@ -1,6370 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user source */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#include -#include -#include "ethtool-user.h" -#include "ynl.h" -#include - -#include -#include - -#include "linux/ethtool_netlink.h" - -/* Enums */ -static const char * const ethtool_op_strmap[] = { - [ETHTOOL_MSG_STRSET_GET] = "strset-get", - [ETHTOOL_MSG_LINKINFO_GET] = "linkinfo-get", - [3] = "linkinfo-ntf", - [ETHTOOL_MSG_LINKMODES_GET] = "linkmodes-get", - [5] = "linkmodes-ntf", - [ETHTOOL_MSG_LINKSTATE_GET] = "linkstate-get", - [ETHTOOL_MSG_DEBUG_GET] = "debug-get", - [8] = "debug-ntf", - [ETHTOOL_MSG_WOL_GET] = "wol-get", - [10] = "wol-ntf", - [ETHTOOL_MSG_FEATURES_GET] = "features-get", - [ETHTOOL_MSG_FEATURES_SET] = "features-set", - [13] = "features-ntf", - [14] = "privflags-get", - [15] = "privflags-ntf", - [16] = "rings-get", - [17] = "rings-ntf", - [18] = "channels-get", - [19] = "channels-ntf", - [20] = "coalesce-get", - [21] = "coalesce-ntf", - [22] = "pause-get", - [23] = "pause-ntf", - [24] = "eee-get", - [25] = "eee-ntf", - [26] = "tsinfo-get", - [27] = "cable-test-ntf", - [28] = "cable-test-tdr-ntf", - [29] = "tunnel-info-get", - [30] = "fec-get", - [31] = "fec-ntf", - [32] = "module-eeprom-get", - [34] = "phc-vclocks-get", - [35] = "module-get", - [36] = "module-ntf", - [37] = "pse-get", - [ETHTOOL_MSG_RSS_GET] = "rss-get", - [ETHTOOL_MSG_PLCA_GET_CFG] = "plca-get-cfg", - [40] = "plca-get-status", - [41] = "plca-ntf", - [ETHTOOL_MSG_MM_GET] = "mm-get", - [43] = "mm-ntf", -}; - -const char *ethtool_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(ethtool_op_strmap)) - return NULL; - return ethtool_op_strmap[op]; -} - -static const char * const ethtool_udp_tunnel_type_strmap[] = { - [0] = "vxlan", - [1] = "geneve", - [2] = "vxlan-gpe", -}; - -const char *ethtool_udp_tunnel_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_udp_tunnel_type_strmap)) - return NULL; - return ethtool_udp_tunnel_type_strmap[value]; -} - -static const char * const ethtool_stringset_strmap[] = { -}; - -const char *ethtool_stringset_str(enum ethtool_stringset value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_stringset_strmap)) - return NULL; - return ethtool_stringset_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr ethtool_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { - [ETHTOOL_A_HEADER_DEV_INDEX] = { .name = "dev-index", .type = YNL_PT_U32, }, - [ETHTOOL_A_HEADER_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_HEADER_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_header_nest = { - .max_attr = ETHTOOL_A_HEADER_MAX, - .table = ethtool_header_policy, -}; - -struct ynl_policy_attr ethtool_pause_stat_policy[ETHTOOL_A_PAUSE_STAT_MAX + 1] = { - [ETHTOOL_A_PAUSE_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_PAUSE_STAT_TX_FRAMES] = { .name = "tx-frames", .type = YNL_PT_U64, }, - [ETHTOOL_A_PAUSE_STAT_RX_FRAMES] = { .name = "rx-frames", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_pause_stat_nest = { - .max_attr = ETHTOOL_A_PAUSE_STAT_MAX, - .table = ethtool_pause_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .name = "first", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .name = "last", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .name = "step", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_cfg_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, - .table = ethtool_cable_test_tdr_cfg_policy, -}; - -struct ynl_policy_attr ethtool_fec_stat_policy[ETHTOOL_A_FEC_STAT_MAX + 1] = { - [ETHTOOL_A_FEC_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_FEC_STAT_CORRECTED] = { .name = "corrected", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_UNCORR] = { .name = "uncorr", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_CORR_BITS] = { .name = "corr-bits", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_fec_stat_nest = { - .max_attr = ETHTOOL_A_FEC_STAT_MAX, - .table = ethtool_fec_stat_policy, -}; - -struct ynl_policy_attr ethtool_mm_stat_policy[ETHTOOL_A_MM_STAT_MAX + 1] = { - [ETHTOOL_A_MM_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS] = { .name = "reassembly-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_SMD_ERRORS] = { .name = "smd-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_OK] = { .name = "reassembly-ok", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_RX_FRAG_COUNT] = { .name = "rx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_TX_FRAG_COUNT] = { .name = "tx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_HOLD_COUNT] = { .name = "hold-count", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_mm_stat_nest = { - .max_attr = ETHTOOL_A_MM_STAT_MAX, - .table = ethtool_mm_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_result_policy[ETHTOOL_A_CABLE_RESULT_MAX + 1] = { - [ETHTOOL_A_CABLE_RESULT_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_RESULT_CODE] = { .name = "code", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_result_nest = { - .max_attr = ETHTOOL_A_CABLE_RESULT_MAX, - .table = ethtool_cable_result_policy, -}; - -struct ynl_policy_attr ethtool_cable_fault_length_policy[ETHTOOL_A_CABLE_FAULT_LENGTH_MAX + 1] = { - [ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_FAULT_LENGTH_CM] = { .name = "cm", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_cable_fault_length_nest = { - .max_attr = ETHTOOL_A_CABLE_FAULT_LENGTH_MAX, - .table = ethtool_cable_fault_length_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { - [ETHTOOL_A_BITSET_BIT_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BIT_NAME] = { .name = "name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_BITSET_BIT_VALUE] = { .name = "value", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_bitset_bit_nest = { - .max_attr = ETHTOOL_A_BITSET_BIT_MAX, - .table = ethtool_bitset_bit_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_entry_policy[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE] = { .name = "type", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_entry_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX, - .table = ethtool_tunnel_udp_entry_policy, -}; - -struct ynl_policy_attr ethtool_string_policy[ETHTOOL_A_STRING_MAX + 1] = { - [ETHTOOL_A_STRING_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRING_VALUE] = { .name = "value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest ethtool_string_nest = { - .max_attr = ETHTOOL_A_STRING_MAX, - .table = ethtool_string_policy, -}; - -struct ynl_policy_attr ethtool_cable_nest_policy[ETHTOOL_A_CABLE_NEST_MAX + 1] = { - [ETHTOOL_A_CABLE_NEST_RESULT] = { .name = "result", .type = YNL_PT_NEST, .nest = ðtool_cable_result_nest, }, - [ETHTOOL_A_CABLE_NEST_FAULT_LENGTH] = { .name = "fault-length", .type = YNL_PT_NEST, .nest = ðtool_cable_fault_length_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_nest_nest = { - .max_attr = ETHTOOL_A_CABLE_NEST_MAX, - .table = ethtool_cable_nest_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bits_policy[ETHTOOL_A_BITSET_BITS_MAX + 1] = { - [ETHTOOL_A_BITSET_BITS_BIT] = { .name = "bit", .type = YNL_PT_NEST, .nest = ðtool_bitset_bit_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_bits_nest = { - .max_attr = ETHTOOL_A_BITSET_BITS_MAX, - .table = ethtool_bitset_bits_policy, -}; - -struct ynl_policy_attr ethtool_strings_policy[ETHTOOL_A_STRINGS_MAX + 1] = { - [ETHTOOL_A_STRINGS_STRING] = { .name = "string", .type = YNL_PT_NEST, .nest = ðtool_string_nest, }, -}; - -struct ynl_policy_nest ethtool_strings_nest = { - .max_attr = ETHTOOL_A_STRINGS_MAX, - .table = ethtool_strings_policy, -}; - -struct ynl_policy_attr ethtool_bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { - [ETHTOOL_A_BITSET_NOMASK] = { .name = "nomask", .type = YNL_PT_FLAG, }, - [ETHTOOL_A_BITSET_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BITS] = { .name = "bits", .type = YNL_PT_NEST, .nest = ðtool_bitset_bits_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_nest = { - .max_attr = ETHTOOL_A_BITSET_MAX, - .table = ethtool_bitset_policy, -}; - -struct ynl_policy_attr ethtool_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { - [ETHTOOL_A_STRINGSET_ID] = { .name = "id", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_COUNT] = { .name = "count", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_STRINGS] = { .name = "strings", .type = YNL_PT_NEST, .nest = ðtool_strings_nest, }, -}; - -struct ynl_policy_nest ethtool_stringset_nest = { - .max_attr = ETHTOOL_A_STRINGSET_MAX, - .table = ethtool_stringset_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_table_policy[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES] = { .name = "types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY] = { .name = "entry", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_entry_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_table_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_TABLE_MAX, - .table = ethtool_tunnel_udp_table_policy, -}; - -struct ynl_policy_attr ethtool_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { - [ETHTOOL_A_STRINGSETS_STRINGSET] = { .name = "stringset", .type = YNL_PT_NEST, .nest = ðtool_stringset_nest, }, -}; - -struct ynl_policy_nest ethtool_stringsets_nest = { - .max_attr = ETHTOOL_A_STRINGSETS_MAX, - .table = ethtool_stringsets_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_policy[ETHTOOL_A_TUNNEL_UDP_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE] = { .name = "table", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_table_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_MAX, - .table = ethtool_tunnel_udp_policy, -}; - -struct ynl_policy_attr ethtool_strset_policy[ETHTOOL_A_STRSET_MAX + 1] = { - [ETHTOOL_A_STRSET_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_STRSET_STRINGSETS] = { .name = "stringsets", .type = YNL_PT_NEST, .nest = ðtool_stringsets_nest, }, - [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .name = "counts-only", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_strset_nest = { - .max_attr = ETHTOOL_A_STRSET_MAX, - .table = ethtool_strset_policy, -}; - -struct ynl_policy_attr ethtool_linkinfo_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { - [ETHTOOL_A_LINKINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKINFO_PORT] = { .name = "port", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_PHYADDR] = { .name = "phyaddr", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .name = "tp-mdix", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .name = "tp-mdix-ctrl", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .name = "transceiver", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkinfo_nest = { - .max_attr = ETHTOOL_A_LINKINFO_MAX, - .table = ethtool_linkinfo_policy, -}; - -struct ynl_policy_attr ethtool_linkmodes_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { - [ETHTOOL_A_LINKMODES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKMODES_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_OURS] = { .name = "ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_PEER] = { .name = "peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_SPEED] = { .name = "speed", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_DUPLEX] = { .name = "duplex", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .name = "master-slave-cfg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .name = "master-slave-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_LANES] = { .name = "lanes", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_RATE_MATCHING] = { .name = "rate-matching", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkmodes_nest = { - .max_attr = ETHTOOL_A_LINKMODES_MAX, - .table = ethtool_linkmodes_policy, -}; - -struct ynl_policy_attr ethtool_linkstate_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { - [ETHTOOL_A_LINKSTATE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKSTATE_LINK] = { .name = "link", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_SQI] = { .name = "sqi", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .name = "sqi-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .name = "ext-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .name = "ext-substate", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT] = { .name = "ext-down-cnt", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_linkstate_nest = { - .max_attr = ETHTOOL_A_LINKSTATE_MAX, - .table = ethtool_linkstate_policy, -}; - -struct ynl_policy_attr ethtool_debug_policy[ETHTOOL_A_DEBUG_MAX + 1] = { - [ETHTOOL_A_DEBUG_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_DEBUG_MSGMASK] = { .name = "msgmask", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_debug_nest = { - .max_attr = ETHTOOL_A_DEBUG_MAX, - .table = ethtool_debug_policy, -}; - -struct ynl_policy_attr ethtool_wol_policy[ETHTOOL_A_WOL_MAX + 1] = { - [ETHTOOL_A_WOL_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_WOL_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_WOL_SOPASS] = { .name = "sopass", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_wol_nest = { - .max_attr = ETHTOOL_A_WOL_MAX, - .table = ethtool_wol_policy, -}; - -struct ynl_policy_attr ethtool_features_policy[ETHTOOL_A_FEATURES_MAX + 1] = { - [ETHTOOL_A_FEATURES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEATURES_HW] = { .name = "hw", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_WANTED] = { .name = "wanted", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_ACTIVE] = { .name = "active", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_NOCHANGE] = { .name = "nochange", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_features_nest = { - .max_attr = ETHTOOL_A_FEATURES_MAX, - .table = ethtool_features_policy, -}; - -struct ynl_policy_attr ethtool_privflags_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .name = "flags", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_privflags_nest = { - .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, - .table = ethtool_privflags_policy, -}; - -struct ynl_policy_attr ethtool_rings_policy[ETHTOOL_A_RINGS_MAX + 1] = { - [ETHTOOL_A_RINGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RINGS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .name = "rx-mini-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .name = "rx-jumbo-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX] = { .name = "rx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI] = { .name = "rx-mini", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO] = { .name = "rx-jumbo", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX] = { .name = "tx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_BUF_LEN] = { .name = "rx-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TCP_DATA_SPLIT] = { .name = "tcp-data-split", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_CQE_SIZE] = { .name = "cqe-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH] = { .name = "tx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_RX_PUSH] = { .name = "rx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .name = "tx-push-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX] = { .name = "tx-push-buf-len-max", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_rings_nest = { - .max_attr = ETHTOOL_A_RINGS_MAX, - .table = ethtool_rings_policy, -}; - -struct ynl_policy_attr ethtool_channels_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { - [ETHTOOL_A_CHANNELS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CHANNELS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .name = "other-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .name = "combined-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_RX_COUNT] = { .name = "rx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_COUNT] = { .name = "tx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .name = "other-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .name = "combined-count", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_channels_nest = { - .max_attr = ETHTOOL_A_CHANNELS_MAX, - .table = ethtool_channels_policy, -}; - -struct ynl_policy_attr ethtool_coalesce_policy[ETHTOOL_A_COALESCE_MAX + 1] = { - [ETHTOOL_A_COALESCE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_COALESCE_RX_USECS] = { .name = "rx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .name = "rx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .name = "rx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .name = "rx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS] = { .name = "tx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .name = "tx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .name = "tx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .name = "tx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .name = "stats-block-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .name = "use-adaptive-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .name = "use-adaptive-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .name = "pkt-rate-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .name = "rx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .name = "rx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .name = "tx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .name = "tx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .name = "pkt-rate-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .name = "rx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .name = "rx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .name = "tx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .name = "tx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .name = "rate-sample-interval", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX] = { .name = "use-cqe-mode-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX] = { .name = "use-cqe-mode-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES] = { .name = "tx-aggr-max-bytes", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES] = { .name = "tx-aggr-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .name = "tx-aggr-time-usecs", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_coalesce_nest = { - .max_attr = ETHTOOL_A_COALESCE_MAX, - .table = ethtool_coalesce_policy, -}; - -struct ynl_policy_attr ethtool_pause_policy[ETHTOOL_A_PAUSE_MAX + 1] = { - [ETHTOOL_A_PAUSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PAUSE_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_RX] = { .name = "rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_TX] = { .name = "tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_pause_stat_nest, }, - [ETHTOOL_A_PAUSE_STATS_SRC] = { .name = "stats-src", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pause_nest = { - .max_attr = ETHTOOL_A_PAUSE_MAX, - .table = ethtool_pause_policy, -}; - -struct ynl_policy_attr ethtool_eee_policy[ETHTOOL_A_EEE_MAX + 1] = { - [ETHTOOL_A_EEE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_EEE_MODES_OURS] = { .name = "modes-ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_MODES_PEER] = { .name = "modes-peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_ACTIVE] = { .name = "active", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .name = "tx-lpi-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .name = "tx-lpi-timer", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_eee_nest = { - .max_attr = ETHTOOL_A_EEE_MAX, - .table = ethtool_eee_policy, -}; - -struct ynl_policy_attr ethtool_tsinfo_policy[ETHTOOL_A_TSINFO_MAX + 1] = { - [ETHTOOL_A_TSINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .name = "timestamping", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_TX_TYPES] = { .name = "tx-types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_RX_FILTERS] = { .name = "rx-filters", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_PHC_INDEX] = { .name = "phc-index", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tsinfo_nest = { - .max_attr = ETHTOOL_A_TSINFO_MAX, - .table = ethtool_tsinfo_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_MAX, - .table = ethtool_cable_test_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_ntf_policy[ETHTOOL_A_CABLE_TEST_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_NTF_MAX, - .table = ethtool_cable_test_ntf_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .name = "cfg", .type = YNL_PT_NEST, .nest = ðtool_cable_test_tdr_cfg_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_MAX, - .table = ethtool_cable_test_tdr_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_ntf_policy[ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX, - .table = ethtool_cable_test_tdr_ntf_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { - [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TUNNEL_INFO_UDP_PORTS] = { .name = "udp-ports", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_info_nest = { - .max_attr = ETHTOOL_A_TUNNEL_INFO_MAX, - .table = ethtool_tunnel_info_policy, -}; - -struct ynl_policy_attr ethtool_fec_policy[ETHTOOL_A_FEC_MAX + 1] = { - [ETHTOOL_A_FEC_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEC_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEC_AUTO] = { .name = "auto", .type = YNL_PT_U8, }, - [ETHTOOL_A_FEC_ACTIVE] = { .name = "active", .type = YNL_PT_U32, }, - [ETHTOOL_A_FEC_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_fec_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_fec_nest = { - .max_attr = ETHTOOL_A_FEC_MAX, - .table = ethtool_fec_policy, -}; - -struct ynl_policy_attr ethtool_module_eeprom_policy[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = { - [ETHTOOL_A_MODULE_EEPROM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_EEPROM_OFFSET] = { .name = "offset", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_LENGTH] = { .name = "length", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .name = "page", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_BANK] = { .name = "bank", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] = { .name = "i2c-address", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_DATA] = { .name = "data", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_module_eeprom_nest = { - .max_attr = ETHTOOL_A_MODULE_EEPROM_MAX, - .table = ethtool_module_eeprom_policy, -}; - -struct ynl_policy_attr ethtool_phc_vclocks_policy[ETHTOOL_A_PHC_VCLOCKS_MAX + 1] = { - [ETHTOOL_A_PHC_VCLOCKS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PHC_VCLOCKS_NUM] = { .name = "num", .type = YNL_PT_U32, }, - [ETHTOOL_A_PHC_VCLOCKS_INDEX] = { .name = "index", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_phc_vclocks_nest = { - .max_attr = ETHTOOL_A_PHC_VCLOCKS_MAX, - .table = ethtool_phc_vclocks_policy, -}; - -struct ynl_policy_attr ethtool_module_policy[ETHTOOL_A_MODULE_MAX + 1] = { - [ETHTOOL_A_MODULE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_POWER_MODE_POLICY] = { .name = "power-mode-policy", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_POWER_MODE] = { .name = "power-mode", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_module_nest = { - .max_attr = ETHTOOL_A_MODULE_MAX, - .table = ethtool_module_policy, -}; - -struct ynl_policy_attr ethtool_pse_policy[ETHTOOL_A_PSE_MAX + 1] = { - [ETHTOOL_A_PSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PODL_PSE_ADMIN_STATE] = { .name = "admin-state", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_ADMIN_CONTROL] = { .name = "admin-control", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_PW_D_STATUS] = { .name = "pw-d-status", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pse_nest = { - .max_attr = ETHTOOL_A_PSE_MAX, - .table = ethtool_pse_policy, -}; - -struct ynl_policy_attr ethtool_rss_policy[ETHTOOL_A_RSS_MAX + 1] = { - [ETHTOOL_A_RSS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RSS_CONTEXT] = { .name = "context", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_HFUNC] = { .name = "hfunc", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_INDIR] = { .name = "indir", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_RSS_HKEY] = { .name = "hkey", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_rss_nest = { - .max_attr = ETHTOOL_A_RSS_MAX, - .table = ethtool_rss_policy, -}; - -struct ynl_policy_attr ethtool_plca_policy[ETHTOOL_A_PLCA_MAX + 1] = { - [ETHTOOL_A_PLCA_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PLCA_VERSION] = { .name = "version", .type = YNL_PT_U16, }, - [ETHTOOL_A_PLCA_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_NODE_CNT] = { .name = "node-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_NODE_ID] = { .name = "node-id", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_TO_TMR] = { .name = "to-tmr", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_CNT] = { .name = "burst-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_TMR] = { .name = "burst-tmr", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_plca_nest = { - .max_attr = ETHTOOL_A_PLCA_MAX, - .table = ethtool_plca_policy, -}; - -struct ynl_policy_attr ethtool_mm_policy[ETHTOOL_A_MM_MAX + 1] = { - [ETHTOOL_A_MM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MM_PMAC_ENABLED] = { .name = "pmac-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ENABLED] = { .name = "tx-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ACTIVE] = { .name = "tx-active", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE] = { .name = "tx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_RX_MIN_FRAG_SIZE] = { .name = "rx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_VERIFY_ENABLED] = { .name = "verify-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_STATUS] = { .name = "verify-status", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_TIME] = { .name = "verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_MAX_VERIFY_TIME] = { .name = "max-verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_mm_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_mm_nest = { - .max_attr = ETHTOOL_A_MM_MAX, - .table = ethtool_mm_policy, -}; - -/* Common nested types */ -void ethtool_header_free(struct ethtool_header *obj) -{ - free(obj->dev_name); -} - -int ethtool_header_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_header *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.dev_index) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_DEV_INDEX, obj->dev_index); - if (obj->_present.dev_name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_HEADER_DEV_NAME, obj->dev_name); - if (obj->_present.flags) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_FLAGS, obj->flags); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_header_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_header *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_HEADER_DEV_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_index = 1; - dst->dev_index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_HEADER_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == ETHTOOL_A_HEADER_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - dst->flags = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_pause_stat_free(struct ethtool_pause_stat *obj) -{ -} - -int ethtool_pause_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_pause_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.tx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_TX_FRAMES, obj->tx_frames); - if (obj->_present.rx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_RX_FRAMES, obj->rx_frames); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_pause_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_pause_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_STAT_TX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frames = 1; - dst->tx_frames = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_PAUSE_STAT_RX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frames = 1; - dst->rx_frames = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_test_tdr_cfg_free(struct ethtool_cable_test_tdr_cfg *obj) -{ -} - -void ethtool_fec_stat_free(struct ethtool_fec_stat *obj) -{ - free(obj->corrected); - free(obj->uncorr); - free(obj->corr_bits); -} - -int ethtool_fec_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_fec_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.corrected_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORRECTED, obj->_present.corrected_len, obj->corrected); - if (obj->_present.uncorr_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_UNCORR, obj->_present.uncorr_len, obj->uncorr); - if (obj->_present.corr_bits_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORR_BITS, obj->_present.corr_bits_len, obj->corr_bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_fec_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_fec_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_STAT_CORRECTED) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corrected_len = len; - dst->corrected = malloc(len); - memcpy(dst->corrected, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_UNCORR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.uncorr_len = len; - dst->uncorr = malloc(len); - memcpy(dst->uncorr, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_CORR_BITS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corr_bits_len = len; - dst->corr_bits = malloc(len); - memcpy(dst->corr_bits, mnl_attr_get_payload(attr), len); - } - } - - return 0; -} - -void ethtool_mm_stat_free(struct ethtool_mm_stat *obj) -{ -} - -int ethtool_mm_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_mm_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_errors = 1; - dst->reassembly_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_SMD_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.smd_errors = 1; - dst->smd_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_OK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_ok = 1; - dst->reassembly_ok = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_RX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frag_count = 1; - dst->rx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_TX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frag_count = 1; - dst->tx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_HOLD_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hold_count = 1; - dst->hold_count = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_result_free(struct ethtool_cable_result *obj) -{ -} - -int ethtool_cable_result_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_result *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_RESULT_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_RESULT_CODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.code = 1; - dst->code = mnl_attr_get_u8(attr); - } - } - - return 0; -} - -void ethtool_cable_fault_length_free(struct ethtool_cable_fault_length *obj) -{ -} - -int ethtool_cable_fault_length_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_fault_length *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_CM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cm = 1; - dst->cm = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_bitset_bit_free(struct ethtool_bitset_bit *obj) -{ - free(obj->name); -} - -int ethtool_bitset_bit_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bit *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_BIT_INDEX, obj->index); - if (obj->_present.name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_BITSET_BIT_NAME, obj->name); - if (obj->_present.value) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_BIT_VALUE, 0, NULL); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bit_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bit *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BIT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BIT_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.name_len = len; - dst->name = malloc(len + 1); - memcpy(dst->name, mnl_attr_get_str(attr), len); - dst->name[len] = 0; - } else if (type == ETHTOOL_A_BITSET_BIT_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.value = 1; - } - } - - return 0; -} - -void ethtool_tunnel_udp_entry_free(struct ethtool_tunnel_udp_entry *obj) -{ -} - -int ethtool_tunnel_udp_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_string_free(struct ethtool_string *obj) -{ - free(obj->value); -} - -int ethtool_string_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_string *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRING_INDEX, obj->index); - if (obj->_present.value_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_STRING_VALUE, obj->value); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_string_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_string *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRING_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRING_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.value_len = len; - dst->value = malloc(len + 1); - memcpy(dst->value, mnl_attr_get_str(attr), len); - dst->value[len] = 0; - } - } - - return 0; -} - -void ethtool_cable_nest_free(struct ethtool_cable_nest *obj) -{ - ethtool_cable_result_free(&obj->result); - ethtool_cable_fault_length_free(&obj->fault_length); -} - -int ethtool_cable_nest_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_nest *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_NEST_RESULT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.result = 1; - - parg.rsp_policy = ðtool_cable_result_nest; - parg.data = &dst->result; - if (ethtool_cable_result_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_NEST_FAULT_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fault_length = 1; - - parg.rsp_policy = ðtool_cable_fault_length_nest; - parg.data = &dst->fault_length; - if (ethtool_cable_fault_length_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_bitset_bits_free(struct ethtool_bitset_bits *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_free(&obj->bit[i]); - free(obj->bit); -} - -int ethtool_bitset_bits_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bits *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_put(nlh, ETHTOOL_A_BITSET_BITS_BIT, &obj->bit[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bits_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bits *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_bit = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->bit) - return ynl_error_parse(yarg, "attribute already present (bitset-bits.bit)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BITS_BIT) { - n_bit++; - } - } - - if (n_bit) { - dst->bit = calloc(n_bit, sizeof(*dst->bit)); - dst->n_bit = n_bit; - i = 0; - parg.rsp_policy = ðtool_bitset_bit_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_BITSET_BITS_BIT) { - parg.data = &dst->bit[i]; - if (ethtool_bitset_bit_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_strings_free(struct ethtool_strings *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_string; i++) - ethtool_string_free(&obj->string[i]); - free(obj->string); -} - -int ethtool_strings_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_strings *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_string; i++) - ethtool_string_put(nlh, ETHTOOL_A_STRINGS_STRING, &obj->string[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_strings_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_strings *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_string = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->string) - return ynl_error_parse(yarg, "attribute already present (strings.string)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGS_STRING) { - n_string++; - } - } - - if (n_string) { - dst->string = calloc(n_string, sizeof(*dst->string)); - dst->n_string = n_string; - i = 0; - parg.rsp_policy = ðtool_string_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGS_STRING) { - parg.data = &dst->string[i]; - if (ethtool_string_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_bitset_free(struct ethtool_bitset *obj) -{ - ethtool_bitset_bits_free(&obj->bits); -} - -int ethtool_bitset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.nomask) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_NOMASK, 0, NULL); - if (obj->_present.size) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_SIZE, obj->size); - if (obj->_present.bits) - ethtool_bitset_bits_put(nlh, ETHTOOL_A_BITSET_BITS, &obj->bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_NOMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nomask = 1; - } else if (type == ETHTOOL_A_BITSET_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BITS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bits = 1; - - parg.rsp_policy = ðtool_bitset_bits_nest; - parg.data = &dst->bits; - if (ethtool_bitset_bits_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_stringset_free(struct ethtool_stringset_ *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_strings; i++) - ethtool_strings_free(&obj->strings[i]); - free(obj->strings); -} - -int ethtool_stringset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringset_ *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.id) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_ID, obj->id); - if (obj->_present.count) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_COUNT, obj->count); - for (unsigned int i = 0; i < obj->n_strings; i++) - ethtool_strings_put(nlh, ETHTOOL_A_STRINGSET_STRINGS, &obj->strings[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringset_ *dst = yarg->data; - unsigned int n_strings = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->strings) - return ynl_error_parse(yarg, "attribute already present (stringset.strings)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSET_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.count = 1; - dst->count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_STRINGS) { - n_strings++; - } - } - - if (n_strings) { - dst->strings = calloc(n_strings, sizeof(*dst->strings)); - dst->n_strings = n_strings; - i = 0; - parg.rsp_policy = ðtool_strings_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSET_STRINGS) { - parg.data = &dst->strings[i]; - if (ethtool_strings_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_table_free(struct ethtool_tunnel_udp_table *obj) -{ - unsigned int i; - - ethtool_bitset_free(&obj->types); - for (i = 0; i < obj->n_entry; i++) - ethtool_tunnel_udp_entry_free(&obj->entry[i]); - free(obj->entry); -} - -int ethtool_tunnel_udp_table_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_table *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_entry = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->entry) - return ynl_error_parse(yarg, "attribute already present (tunnel-udp-table.entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - n_entry++; - } - } - - if (n_entry) { - dst->entry = calloc(n_entry, sizeof(*dst->entry)); - dst->n_entry = n_entry; - i = 0; - parg.rsp_policy = ðtool_tunnel_udp_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - parg.data = &dst->entry[i]; - if (ethtool_tunnel_udp_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_stringsets_free(struct ethtool_stringsets *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_stringset; i++) - ethtool_stringset_free(&obj->stringset[i]); - free(obj->stringset); -} - -int ethtool_stringsets_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringsets *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_stringset; i++) - ethtool_stringset_put(nlh, ETHTOOL_A_STRINGSETS_STRINGSET, &obj->stringset[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringsets_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringsets *dst = yarg->data; - unsigned int n_stringset = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->stringset) - return ynl_error_parse(yarg, "attribute already present (stringsets.stringset)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSETS_STRINGSET) { - n_stringset++; - } - } - - if (n_stringset) { - dst->stringset = calloc(n_stringset, sizeof(*dst->stringset)); - dst->n_stringset = n_stringset; - i = 0; - parg.rsp_policy = ðtool_stringset_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSETS_STRINGSET) { - parg.data = &dst->stringset[i]; - if (ethtool_stringset_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_free(struct ethtool_tunnel_udp *obj) -{ - ethtool_tunnel_udp_table_free(&obj->table); -} - -int ethtool_tunnel_udp_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.table = 1; - - parg.rsp_policy = ðtool_tunnel_udp_table_nest; - parg.data = &dst->table; - if (ethtool_tunnel_udp_table_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req) -{ - ethtool_header_free(&req->header); - ethtool_stringsets_free(&req->stringsets); - free(req); -} - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_stringsets_free(&rsp->stringsets); - free(rsp); -} - -int ethtool_strset_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_strset_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRSET_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_STRSET_STRINGSETS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stringsets = 1; - - parg.rsp_policy = ðtool_stringsets_nest; - parg.data = &dst->stringsets; - if (ethtool_stringsets_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_strset_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - yrs.yarg.rsp_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_strset_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_strset_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_STRSET_GET - dump */ -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp) -{ - struct ethtool_strset_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_stringsets_free(&rsp->obj.stringsets); - free(rsp); - } -} - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_strset_get_list); - yds.cb = ethtool_strset_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - yds.rsp_policy = ðtool_strset_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_strset_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKINFO_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_PHYADDR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phyaddr = 1; - dst->phyaddr = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix = 1; - dst->tp_mdix = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX_CTRL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix_ctrl = 1; - dst->tp_mdix_ctrl = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TRANSCEIVER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.transceiver = 1; - dst->transceiver = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - yrs.yarg.rsp_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkinfo_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp) -{ - struct ethtool_linkinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkinfo_get_list); - yds.cb = ethtool_linkinfo_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - yds.rsp_policy = ðtool_linkinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkinfo_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_SET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - if (req->_present.port) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PORT, req->port); - if (req->_present.phyaddr) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PHYADDR, req->phyaddr); - if (req->_present.tp_mdix) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX, req->tp_mdix); - if (req->_present.tp_mdix_ctrl) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, req->tp_mdix_ctrl); - if (req->_present.transceiver) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TRANSCEIVER, req->transceiver); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->ours); - ethtool_bitset_free(&rsp->peer); - free(rsp); -} - -int ethtool_linkmodes_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkmodes_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKMODES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_SPEED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.speed = 1; - dst->speed = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_DUPLEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.duplex = 1; - dst->duplex = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_cfg = 1; - dst->master_slave_cfg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_state = 1; - dst->master_slave_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_LANES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.lanes = 1; - dst->lanes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_RATE_MATCHING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_matching = 1; - dst->rate_matching = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkmodes_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - yrs.yarg.rsp_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkmodes_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkmodes_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp) -{ - struct ethtool_linkmodes_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); - } -} - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkmodes_get_list); - yds.cb = ethtool_linkmodes_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - yds.rsp_policy = ðtool_linkmodes_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkmodes_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->ours); - ethtool_bitset_free(&req->peer); - free(req); -} - -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_SET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_AUTONEG, req->autoneg); - if (req->_present.ours) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_OURS, &req->ours); - if (req->_present.peer) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_PEER, &req->peer); - if (req->_present.speed) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_SPEED, req->speed); - if (req->_present.duplex) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_DUPLEX, req->duplex); - if (req->_present.master_slave_cfg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, req->master_slave_cfg); - if (req->_present.master_slave_state) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, req->master_slave_state); - if (req->_present.lanes) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_LANES, req->lanes); - if (req->_present.rate_matching) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_RATE_MATCHING, req->rate_matching); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkstate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkstate_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKSTATE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKSTATE_LINK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.link = 1; - dst->link = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi = 1; - dst->sqi = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi_max = 1; - dst->sqi_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_state = 1; - dst->ext_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_SUBSTATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_substate = 1; - dst->ext_substate = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_down_cnt = 1; - dst->ext_down_cnt = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkstate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - yrs.yarg.rsp_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkstate_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkstate_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp) -{ - struct ethtool_linkstate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkstate_get_list); - yds.cb = ethtool_linkstate_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - yds.rsp_policy = ðtool_linkstate_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkstate_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->msgmask); - free(rsp); -} - -int ethtool_debug_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_debug_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_DEBUG_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_DEBUG_MSGMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.msgmask = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->msgmask; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_debug_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - yrs.yarg.rsp_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_debug_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_debug_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp) -{ - struct ethtool_debug_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); - } -} - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_debug_get_list); - yds.cb = ethtool_debug_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - yds.rsp_policy = ðtool_debug_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_debug_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); -} - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->msgmask); - free(req); -} - -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_SET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - if (req->_present.msgmask) - ethtool_bitset_put(nlh, ETHTOOL_A_DEBUG_MSGMASK, &req->msgmask); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - free(rsp->sopass); - free(rsp); -} - -int ethtool_wol_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_wol_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_WOL_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_SOPASS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.sopass_len = len; - dst->sopass = malloc(len); - memcpy(dst->sopass, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_wol_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - yrs.yarg.rsp_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_wol_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_WOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_wol_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - dump */ -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp) -{ - struct ethtool_wol_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); - } -} - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_wol_get_list); - yds.cb = ethtool_wol_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_WOL_GET; - yds.rsp_policy = ðtool_wol_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_wol_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - notify */ -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); -} - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - free(req->sopass); - free(req); -} - -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_SET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_WOL_MODES, &req->modes); - if (req->_present.sopass_len) - mnl_attr_put(nlh, ETHTOOL_A_WOL_SOPASS, req->_present.sopass_len, req->sopass); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -void ethtool_features_get_req_free(struct ethtool_features_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp) -{ - struct ethtool_features_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); - } -} - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_features_get_list); - yds.cb = ethtool_features_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - yds.rsp_policy = ðtool_features_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_features_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -void ethtool_features_set_req_free(struct ethtool_features_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->hw); - ethtool_bitset_free(&req->wanted); - ethtool_bitset_free(&req->active); - ethtool_bitset_free(&req->nochange); - free(req); -} - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_set_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_set_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_set_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_SET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - if (req->_present.hw) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_HW, &req->hw); - if (req->_present.wanted) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_WANTED, &req->wanted); - if (req->_present.active) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_ACTIVE, &req->active); - if (req->_present.nochange) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_NOCHANGE, &req->nochange); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_set_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_SET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_set_rsp_free(rsp); - return NULL; -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->flags); - free(rsp); -} - -int ethtool_privflags_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_privflags_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PRIVFLAGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PRIVFLAGS_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->flags; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_privflags_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - yrs.yarg.rsp_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_privflags_get_rsp_parse; - yrs.rsp_cmd = 14; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_privflags_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp) -{ - struct ethtool_privflags_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); - } -} - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_privflags_get_list); - yds.cb = ethtool_privflags_get_rsp_parse; - yds.rsp_cmd = 14; - yds.rsp_policy = ðtool_privflags_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_privflags_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->flags); - free(req); -} - -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_SET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - if (req->_present.flags) - ethtool_bitset_put(nlh, ETHTOOL_A_PRIVFLAGS_FLAGS, &req->flags); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_rings_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_rings_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RINGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RINGS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini_max = 1; - dst->rx_mini_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo_max = 1; - dst->rx_jumbo_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini = 1; - dst->rx_mini = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo = 1; - dst->rx_jumbo = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_buf_len = 1; - dst->rx_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TCP_DATA_SPLIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tcp_data_split = 1; - dst->tcp_data_split = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_CQE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cqe_size = 1; - dst->cqe_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push = 1; - dst->tx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_RX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_push = 1; - dst->rx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len = 1; - dst->tx_push_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len_max = 1; - dst->tx_push_buf_len_max = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rings_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - yrs.yarg.rsp_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rings_get_rsp_parse; - yrs.rsp_cmd = 16; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rings_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - dump */ -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp) -{ - struct ethtool_rings_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rings_get_list); - yds.cb = ethtool_rings_get_rsp_parse; - yds.rsp_cmd = 16; - yds.rsp_policy = ðtool_rings_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rings_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - notify */ -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_SET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MAX, req->rx_max); - if (req->_present.rx_mini_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI_MAX, req->rx_mini_max); - if (req->_present.rx_jumbo_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO_MAX, req->rx_jumbo_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_MAX, req->tx_max); - if (req->_present.rx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX, req->rx); - if (req->_present.rx_mini) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI, req->rx_mini); - if (req->_present.rx_jumbo) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO, req->rx_jumbo); - if (req->_present.tx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX, req->tx); - if (req->_present.rx_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_BUF_LEN, req->rx_buf_len); - if (req->_present.tcp_data_split) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TCP_DATA_SPLIT, req->tcp_data_split); - if (req->_present.cqe_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_CQE_SIZE, req->cqe_size); - if (req->_present.tx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TX_PUSH, req->tx_push); - if (req->_present.rx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_RX_PUSH, req->rx_push); - if (req->_present.tx_push_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, req->tx_push_buf_len); - if (req->_present.tx_push_buf_len_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, req->tx_push_buf_len_max); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_channels_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_channels_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CHANNELS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CHANNELS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_max = 1; - dst->other_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_max = 1; - dst->combined_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_RX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_count = 1; - dst->rx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_count = 1; - dst->tx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_count = 1; - dst->other_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_count = 1; - dst->combined_count = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_channels_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - yrs.yarg.rsp_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_channels_get_rsp_parse; - yrs.rsp_cmd = 18; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_channels_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp) -{ - struct ethtool_channels_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_channels_get_list); - yds.cb = ethtool_channels_get_rsp_parse; - yds.rsp_cmd = 18; - yds.rsp_policy = ðtool_channels_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_channels_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_SET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_MAX, req->rx_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_MAX, req->tx_max); - if (req->_present.other_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_MAX, req->other_max); - if (req->_present.combined_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_MAX, req->combined_max); - if (req->_present.rx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_COUNT, req->rx_count); - if (req->_present.tx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_COUNT, req->tx_count); - if (req->_present.other_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_COUNT, req->other_count); - if (req->_present.combined_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_COUNT, req->combined_count); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_coalesce_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_coalesce_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_COALESCE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_COALESCE_RX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs = 1; - dst->rx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames = 1; - dst->rx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_irq = 1; - dst->rx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_irq = 1; - dst->rx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs = 1; - dst->tx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames = 1; - dst->tx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_irq = 1; - dst->tx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_irq = 1; - dst->tx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_STATS_BLOCK_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_block_usecs = 1; - dst->stats_block_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_rx = 1; - dst->use_adaptive_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_tx = 1; - dst->use_adaptive_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_low = 1; - dst->pkt_rate_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_low = 1; - dst->rx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_low = 1; - dst->rx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_low = 1; - dst->tx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_low = 1; - dst->tx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_high = 1; - dst->pkt_rate_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_high = 1; - dst->rx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_high = 1; - dst->rx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_high = 1; - dst->tx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_high = 1; - dst->tx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_sample_interval = 1; - dst->rate_sample_interval = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_tx = 1; - dst->use_cqe_mode_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_rx = 1; - dst->use_cqe_mode_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_bytes = 1; - dst->tx_aggr_max_bytes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_frames = 1; - dst->tx_aggr_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_time_usecs = 1; - dst->tx_aggr_time_usecs = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_coalesce_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - yrs.yarg.rsp_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_coalesce_get_rsp_parse; - yrs.rsp_cmd = 20; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_coalesce_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp) -{ - struct ethtool_coalesce_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_coalesce_get_list); - yds.cb = ethtool_coalesce_get_rsp_parse; - yds.rsp_cmd = 20; - yds.rsp_policy = ðtool_coalesce_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_coalesce_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_SET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - if (req->_present.rx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS, req->rx_usecs); - if (req->_present.rx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES, req->rx_max_frames); - if (req->_present.rx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_IRQ, req->rx_usecs_irq); - if (req->_present.rx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, req->rx_max_frames_irq); - if (req->_present.tx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS, req->tx_usecs); - if (req->_present.tx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES, req->tx_max_frames); - if (req->_present.tx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_IRQ, req->tx_usecs_irq); - if (req->_present.tx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, req->tx_max_frames_irq); - if (req->_present.stats_block_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, req->stats_block_usecs); - if (req->_present.use_adaptive_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, req->use_adaptive_rx); - if (req->_present.use_adaptive_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, req->use_adaptive_tx); - if (req->_present.pkt_rate_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_LOW, req->pkt_rate_low); - if (req->_present.rx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_LOW, req->rx_usecs_low); - if (req->_present.rx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, req->rx_max_frames_low); - if (req->_present.tx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_LOW, req->tx_usecs_low); - if (req->_present.tx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, req->tx_max_frames_low); - if (req->_present.pkt_rate_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_HIGH, req->pkt_rate_high); - if (req->_present.rx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_HIGH, req->rx_usecs_high); - if (req->_present.rx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, req->rx_max_frames_high); - if (req->_present.tx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_HIGH, req->tx_usecs_high); - if (req->_present.tx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, req->tx_max_frames_high); - if (req->_present.rate_sample_interval) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, req->rate_sample_interval); - if (req->_present.use_cqe_mode_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, req->use_cqe_mode_tx); - if (req->_present.use_cqe_mode_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, req->use_cqe_mode_rx); - if (req->_present.tx_aggr_max_bytes) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, req->tx_aggr_max_bytes); - if (req->_present.tx_aggr_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, req->tx_aggr_max_frames); - if (req->_present.tx_aggr_time_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, req->tx_aggr_time_usecs); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_pause_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_pause_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_pause_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_pause_stat_nest; - parg.data = &dst->stats; - if (ethtool_pause_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_STATS_SRC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_src = 1; - dst->stats_src = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pause_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - yrs.yarg.rsp_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pause_get_rsp_parse; - yrs.rsp_cmd = 22; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pause_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp) -{ - struct ethtool_pause_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pause_get_list); - yds.cb = ethtool_pause_get_rsp_parse; - yds.rsp_cmd = 22; - yds.rsp_policy = ðtool_pause_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pause_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_pause_stat_free(&req->stats); - free(req); -} - -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_SET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_AUTONEG, req->autoneg); - if (req->_present.rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_RX, req->rx); - if (req->_present.tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_TX, req->tx); - if (req->_present.stats) - ethtool_pause_stat_put(nlh, ETHTOOL_A_PAUSE_STATS, &req->stats); - if (req->_present.stats_src) - mnl_attr_put_u32(nlh, ETHTOOL_A_PAUSE_STATS_SRC, req->stats_src); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes_ours); - ethtool_bitset_free(&rsp->modes_peer); - free(rsp); -} - -int ethtool_eee_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_eee_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_EEE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_enabled = 1; - dst->tx_lpi_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_TIMER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_timer = 1; - dst->tx_lpi_timer = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_eee_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - yrs.yarg.rsp_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_eee_get_rsp_parse; - yrs.rsp_cmd = 24; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_eee_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - dump */ -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp) -{ - struct ethtool_eee_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); - } -} - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_eee_get_list); - yds.cb = ethtool_eee_get_rsp_parse; - yds.rsp_cmd = 24; - yds.rsp_policy = ðtool_eee_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_eee_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - notify */ -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes_ours); - ethtool_bitset_free(&req->modes_peer); - free(req); -} - -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_SET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - if (req->_present.modes_ours) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_OURS, &req->modes_ours); - if (req->_present.modes_peer) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_PEER, &req->modes_peer); - if (req->_present.active) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ACTIVE, req->active); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ENABLED, req->enabled); - if (req->_present.tx_lpi_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_TX_LPI_ENABLED, req->tx_lpi_enabled); - if (req->_present.tx_lpi_timer) - mnl_attr_put_u32(nlh, ETHTOOL_A_EEE_TX_LPI_TIMER, req->tx_lpi_timer); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->timestamping); - ethtool_bitset_free(&rsp->tx_types); - ethtool_bitset_free(&rsp->rx_filters); - free(rsp); -} - -int ethtool_tsinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tsinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TSINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TIMESTAMPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timestamping = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->timestamping; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TX_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->tx_types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_RX_FILTERS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_filters = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->rx_filters; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_PHC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phc_index = 1; - dst->phc_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tsinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - yrs.yarg.rsp_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tsinfo_get_rsp_parse; - yrs.rsp_cmd = 26; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tsinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp) -{ - struct ethtool_tsinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.timestamping); - ethtool_bitset_free(&rsp->obj.tx_types); - ethtool_bitset_free(&rsp->obj.rx_filters); - free(rsp); - } -} - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tsinfo_get_list); - yds.cb = ethtool_tsinfo_get_rsp_parse; - yds.rsp_cmd = 26; - yds.rsp_policy = ðtool_tsinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tsinfo_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_ACT, 1); - ys->req_policy = ðtool_cable_test_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_HEADER, &req->header); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_TDR_ACT, 1); - ys->req_policy = ðtool_cable_test_tdr_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_TDR_HEADER, &req->header); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_tunnel_udp_free(&rsp->udp_ports); - free(rsp); -} - -int ethtool_tunnel_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tunnel_info_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_INFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_INFO_UDP_PORTS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.udp_ports = 1; - - parg.rsp_policy = ðtool_tunnel_udp_nest; - parg.data = &dst->udp_ports; - if (ethtool_tunnel_udp_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tunnel_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - yrs.yarg.rsp_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tunnel_info_get_rsp_parse; - yrs.rsp_cmd = 29; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tunnel_info_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp) -{ - struct ethtool_tunnel_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_tunnel_udp_free(&rsp->obj.udp_ports); - free(rsp); - } -} - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tunnel_info_get_list); - yds.cb = ethtool_tunnel_info_get_rsp_parse; - yds.rsp_cmd = 29; - yds.rsp_policy = ðtool_tunnel_info_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tunnel_info_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - ethtool_fec_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_fec_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_fec_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_AUTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auto_ = 1; - dst->auto_ = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_FEC_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_FEC_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_fec_stat_nest; - parg.data = &dst->stats; - if (ethtool_fec_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_fec_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - yrs.yarg.rsp_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_fec_get_rsp_parse; - yrs.rsp_cmd = 30; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_fec_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - dump */ -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp) -{ - struct ethtool_fec_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_fec_get_list); - yds.cb = ethtool_fec_get_rsp_parse; - yds.rsp_cmd = 30; - yds.rsp_policy = ðtool_fec_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_fec_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - notify */ -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - ethtool_fec_stat_free(&req->stats); - free(req); -} - -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_SET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_FEC_MODES, &req->modes); - if (req->_present.auto_) - mnl_attr_put_u8(nlh, ETHTOOL_A_FEC_AUTO, req->auto_); - if (req->_present.active) - mnl_attr_put_u32(nlh, ETHTOOL_A_FEC_ACTIVE, req->active); - if (req->_present.stats) - ethtool_fec_stat_put(nlh, ETHTOOL_A_FEC_STATS, &req->stats); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->data); - free(rsp); -} - -int ethtool_module_eeprom_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_eeprom_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_EEPROM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_EEPROM_OFFSET) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.offset = 1; - dst->offset = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.length = 1; - dst->length = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_PAGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.page = 1; - dst->page = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_BANK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bank = 1; - dst->bank = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.i2c_address = 1; - dst->i2c_address = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_DATA) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.data_len = len; - dst->data = malloc(len); - memcpy(dst->data, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_eeprom_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - yrs.yarg.rsp_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_eeprom_get_rsp_parse; - yrs.rsp_cmd = 32; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_eeprom_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp) -{ - struct ethtool_module_eeprom_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.data); - free(rsp); - } -} - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_eeprom_get_list); - yds.cb = ethtool_module_eeprom_get_rsp_parse; - yds.rsp_cmd = 32; - yds.rsp_policy = ðtool_module_eeprom_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_eeprom_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_phc_vclocks_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_phc_vclocks_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PHC_VCLOCKS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PHC_VCLOCKS_NUM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.num = 1; - dst->num = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_phc_vclocks_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - yrs.yarg.rsp_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_phc_vclocks_get_rsp_parse; - yrs.rsp_cmd = 34; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_phc_vclocks_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp) -{ - struct ethtool_phc_vclocks_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_phc_vclocks_get_list); - yds.cb = ethtool_phc_vclocks_get_rsp_parse; - yds.rsp_cmd = 34; - yds.rsp_policy = ðtool_phc_vclocks_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_phc_vclocks_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -void ethtool_module_get_req_free(struct ethtool_module_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_module_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_POWER_MODE_POLICY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode_policy = 1; - dst->power_mode_policy = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_POWER_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode = 1; - dst->power_mode = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - yrs.yarg.rsp_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_get_rsp_parse; - yrs.rsp_cmd = 35; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - dump */ -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp) -{ - struct ethtool_module_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_get_list); - yds.cb = ethtool_module_get_rsp_parse; - yds.rsp_cmd = 35; - yds.rsp_policy = ðtool_module_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - notify */ -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -void ethtool_module_set_req_free(struct ethtool_module_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_SET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - if (req->_present.power_mode_policy) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE_POLICY, req->power_mode_policy); - if (req->_present.power_mode) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE, req->power_mode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_pse_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_pse_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_state = 1; - dst->admin_state = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_CONTROL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_control = 1; - dst->admin_control = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_PW_D_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pw_d_status = 1; - dst->pw_d_status = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pse_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - yrs.yarg.rsp_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pse_get_rsp_parse; - yrs.rsp_cmd = 37; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pse_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PSE_GET - dump */ -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp) -{ - struct ethtool_pse_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pse_get_list); - yds.cb = ethtool_pse_get_rsp_parse; - yds.rsp_cmd = 37; - yds.rsp_policy = ðtool_pse_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pse_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_SET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - if (req->_present.admin_state) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_STATE, req->admin_state); - if (req->_present.admin_control) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, req->admin_control); - if (req->_present.pw_d_status) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_PW_D_STATUS, req->pw_d_status); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->indir); - free(rsp->hkey); - free(rsp); -} - -int ethtool_rss_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_rss_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RSS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RSS_CONTEXT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.context = 1; - dst->context = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_HFUNC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hfunc = 1; - dst->hfunc = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_INDIR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.indir_len = len; - dst->indir = malloc(len); - memcpy(dst->indir, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_RSS_HKEY) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.hkey_len = len; - dst->hkey = malloc(len); - memcpy(dst->hkey, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rss_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - yrs.yarg.rsp_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rss_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_RSS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rss_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RSS_GET - dump */ -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp) -{ - struct ethtool_rss_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.indir); - free(rsp->obj.hkey); - free(rsp); - } -} - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rss_get_list); - yds.cb = ethtool_rss_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_RSS_GET; - yds.rsp_policy = ðtool_rss_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rss_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_cfg_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_cfg_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_cfg_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_cfg_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_cfg_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp) -{ - struct ethtool_plca_get_cfg_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_cfg_list); - yds.cb = ethtool_plca_get_cfg_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_cfg_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_SET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - if (req->_present.version) - mnl_attr_put_u16(nlh, ETHTOOL_A_PLCA_VERSION, req->version); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_ENABLED, req->enabled); - if (req->_present.status) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_STATUS, req->status); - if (req->_present.node_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_CNT, req->node_cnt); - if (req->_present.node_id) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_ID, req->node_id); - if (req->_present.to_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_TO_TMR, req->to_tmr); - if (req->_present.burst_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_CNT, req->burst_cnt); - if (req->_present.burst_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_TMR, req->burst_tmr); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_status_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_status_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_status_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_status_rsp_parse; - yrs.rsp_cmd = 40; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_status_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp) -{ - struct ethtool_plca_get_status_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_status_list); - yds.cb = ethtool_plca_get_status_rsp_parse; - yds.rsp_cmd = 40; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_status_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_mm_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_mm_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_mm_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MM_PMAC_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pmac_enabled = 1; - dst->pmac_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_enabled = 1; - dst->tx_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_active = 1; - dst->tx_active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_min_frag_size = 1; - dst->tx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_RX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_min_frag_size = 1; - dst->rx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_enabled = 1; - dst->verify_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_time = 1; - dst->verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_MAX_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.max_verify_time = 1; - dst->max_verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_mm_stat_nest; - parg.data = &dst->stats; - if (ethtool_mm_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_mm_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - yrs.yarg.rsp_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_mm_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_MM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_mm_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - dump */ -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp) -{ - struct ethtool_mm_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_mm_get_list); - yds.cb = ethtool_mm_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_MM_GET; - yds.rsp_policy = ðtool_mm_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_mm_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - notify */ -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_SET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - if (req->_present.verify_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_VERIFY_ENABLED, req->verify_enabled); - if (req->_present.verify_time) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_VERIFY_TIME, req->verify_time); - if (req->_present.tx_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_TX_ENABLED, req->tx_enabled); - if (req->_present.pmac_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_PMAC_ENABLED, req->pmac_enabled); - if (req->_present.tx_min_frag_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, req->tx_min_frag_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -int ethtool_cable_test_ntf_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_cable_test_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -int ethtool_cable_test_tdr_ntf_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct ethtool_cable_test_tdr_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nest = 1; - - parg.rsp_policy = ðtool_cable_nest_nest; - parg.data = &dst->nest; - if (ethtool_cable_nest_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_cable_nest_free(&rsp->obj.nest); - free(rsp); -} - -static const struct ynl_ntf_info ethtool_ntf_info[] = { - [ETHTOOL_MSG_LINKINFO_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkinfo_get_ntf), - .cb = ethtool_linkinfo_get_rsp_parse, - .policy = ðtool_linkinfo_nest, - .free = (void *)ethtool_linkinfo_get_ntf_free, - }, - [ETHTOOL_MSG_LINKMODES_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkmodes_get_ntf), - .cb = ethtool_linkmodes_get_rsp_parse, - .policy = ðtool_linkmodes_nest, - .free = (void *)ethtool_linkmodes_get_ntf_free, - }, - [ETHTOOL_MSG_DEBUG_NTF] = { - .alloc_sz = sizeof(struct ethtool_debug_get_ntf), - .cb = ethtool_debug_get_rsp_parse, - .policy = ðtool_debug_nest, - .free = (void *)ethtool_debug_get_ntf_free, - }, - [ETHTOOL_MSG_WOL_NTF] = { - .alloc_sz = sizeof(struct ethtool_wol_get_ntf), - .cb = ethtool_wol_get_rsp_parse, - .policy = ðtool_wol_nest, - .free = (void *)ethtool_wol_get_ntf_free, - }, - [ETHTOOL_MSG_FEATURES_NTF] = { - .alloc_sz = sizeof(struct ethtool_features_get_ntf), - .cb = ethtool_features_get_rsp_parse, - .policy = ðtool_features_nest, - .free = (void *)ethtool_features_get_ntf_free, - }, - [ETHTOOL_MSG_PRIVFLAGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_privflags_get_ntf), - .cb = ethtool_privflags_get_rsp_parse, - .policy = ðtool_privflags_nest, - .free = (void *)ethtool_privflags_get_ntf_free, - }, - [ETHTOOL_MSG_RINGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_rings_get_ntf), - .cb = ethtool_rings_get_rsp_parse, - .policy = ðtool_rings_nest, - .free = (void *)ethtool_rings_get_ntf_free, - }, - [ETHTOOL_MSG_CHANNELS_NTF] = { - .alloc_sz = sizeof(struct ethtool_channels_get_ntf), - .cb = ethtool_channels_get_rsp_parse, - .policy = ðtool_channels_nest, - .free = (void *)ethtool_channels_get_ntf_free, - }, - [ETHTOOL_MSG_COALESCE_NTF] = { - .alloc_sz = sizeof(struct ethtool_coalesce_get_ntf), - .cb = ethtool_coalesce_get_rsp_parse, - .policy = ðtool_coalesce_nest, - .free = (void *)ethtool_coalesce_get_ntf_free, - }, - [ETHTOOL_MSG_PAUSE_NTF] = { - .alloc_sz = sizeof(struct ethtool_pause_get_ntf), - .cb = ethtool_pause_get_rsp_parse, - .policy = ðtool_pause_nest, - .free = (void *)ethtool_pause_get_ntf_free, - }, - [ETHTOOL_MSG_EEE_NTF] = { - .alloc_sz = sizeof(struct ethtool_eee_get_ntf), - .cb = ethtool_eee_get_rsp_parse, - .policy = ðtool_eee_nest, - .free = (void *)ethtool_eee_get_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_ntf), - .cb = ethtool_cable_test_ntf_rsp_parse, - .policy = ðtool_cable_test_ntf_nest, - .free = (void *)ethtool_cable_test_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_TDR_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_tdr_ntf), - .cb = ethtool_cable_test_tdr_ntf_rsp_parse, - .policy = ðtool_cable_test_tdr_ntf_nest, - .free = (void *)ethtool_cable_test_tdr_ntf_free, - }, - [ETHTOOL_MSG_FEC_NTF] = { - .alloc_sz = sizeof(struct ethtool_fec_get_ntf), - .cb = ethtool_fec_get_rsp_parse, - .policy = ðtool_fec_nest, - .free = (void *)ethtool_fec_get_ntf_free, - }, - [ETHTOOL_MSG_MODULE_NTF] = { - .alloc_sz = sizeof(struct ethtool_module_get_ntf), - .cb = ethtool_module_get_rsp_parse, - .policy = ðtool_module_nest, - .free = (void *)ethtool_module_get_ntf_free, - }, - [ETHTOOL_MSG_PLCA_NTF] = { - .alloc_sz = sizeof(struct ethtool_plca_get_cfg_ntf), - .cb = ethtool_plca_get_cfg_rsp_parse, - .policy = ðtool_plca_nest, - .free = (void *)ethtool_plca_get_cfg_ntf_free, - }, - [ETHTOOL_MSG_MM_NTF] = { - .alloc_sz = sizeof(struct ethtool_mm_get_ntf), - .cb = ethtool_mm_get_rsp_parse, - .policy = ðtool_mm_nest, - .free = (void *)ethtool_mm_get_ntf_free, - }, -}; - -const struct ynl_family ynl_ethtool_family = { - .name = "ethtool", - .ntf_info = ethtool_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(ethtool_ntf_info), -}; diff --git a/tools/net/ynl/generated/ethtool-user.h b/tools/net/ynl/generated/ethtool-user.h deleted file mode 100644 index ca0ec5fd7798..000000000000 --- a/tools/net/ynl/generated/ethtool-user.h +++ /dev/null @@ -1,5535 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user header */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#ifndef _LINUX_ETHTOOL_GEN_H -#define _LINUX_ETHTOOL_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_ethtool_family; - -/* Enums */ -const char *ethtool_op_str(int op); -const char *ethtool_udp_tunnel_type_str(int value); -const char *ethtool_stringset_str(enum ethtool_stringset value); - -/* Common nested types */ -struct ethtool_header { - struct { - __u32 dev_index:1; - __u32 dev_name_len; - __u32 flags:1; - } _present; - - __u32 dev_index; - char *dev_name; - __u32 flags; -}; - -struct ethtool_pause_stat { - struct { - __u32 tx_frames:1; - __u32 rx_frames:1; - } _present; - - __u64 tx_frames; - __u64 rx_frames; -}; - -struct ethtool_cable_test_tdr_cfg { - struct { - __u32 first:1; - __u32 last:1; - __u32 step:1; - __u32 pair:1; - } _present; - - __u32 first; - __u32 last; - __u32 step; - __u8 pair; -}; - -struct ethtool_fec_stat { - struct { - __u32 corrected_len; - __u32 uncorr_len; - __u32 corr_bits_len; - } _present; - - void *corrected; - void *uncorr; - void *corr_bits; -}; - -struct ethtool_mm_stat { - struct { - __u32 reassembly_errors:1; - __u32 smd_errors:1; - __u32 reassembly_ok:1; - __u32 rx_frag_count:1; - __u32 tx_frag_count:1; - __u32 hold_count:1; - } _present; - - __u64 reassembly_errors; - __u64 smd_errors; - __u64 reassembly_ok; - __u64 rx_frag_count; - __u64 tx_frag_count; - __u64 hold_count; -}; - -struct ethtool_cable_result { - struct { - __u32 pair:1; - __u32 code:1; - } _present; - - __u8 pair; - __u8 code; -}; - -struct ethtool_cable_fault_length { - struct { - __u32 pair:1; - __u32 cm:1; - } _present; - - __u8 pair; - __u32 cm; -}; - -struct ethtool_bitset_bit { - struct { - __u32 index:1; - __u32 name_len; - __u32 value:1; - } _present; - - __u32 index; - char *name; -}; - -struct ethtool_tunnel_udp_entry { - struct { - __u32 port:1; - __u32 type:1; - } _present; - - __u16 port /* big-endian */; - __u32 type; -}; - -struct ethtool_string { - struct { - __u32 index:1; - __u32 value_len; - } _present; - - __u32 index; - char *value; -}; - -struct ethtool_cable_nest { - struct { - __u32 result:1; - __u32 fault_length:1; - } _present; - - struct ethtool_cable_result result; - struct ethtool_cable_fault_length fault_length; -}; - -struct ethtool_bitset_bits { - unsigned int n_bit; - struct ethtool_bitset_bit *bit; -}; - -struct ethtool_strings { - unsigned int n_string; - struct ethtool_string *string; -}; - -struct ethtool_bitset { - struct { - __u32 nomask:1; - __u32 size:1; - __u32 bits:1; - } _present; - - __u32 size; - struct ethtool_bitset_bits bits; -}; - -struct ethtool_stringset_ { - struct { - __u32 id:1; - __u32 count:1; - } _present; - - __u32 id; - __u32 count; - unsigned int n_strings; - struct ethtool_strings *strings; -}; - -struct ethtool_tunnel_udp_table { - struct { - __u32 size:1; - __u32 types:1; - } _present; - - __u32 size; - struct ethtool_bitset types; - unsigned int n_entry; - struct ethtool_tunnel_udp_entry *entry; -}; - -struct ethtool_stringsets { - unsigned int n_stringset; - struct ethtool_stringset_ *stringset; -}; - -struct ethtool_tunnel_udp { - struct { - __u32 table:1; - } _present; - - struct ethtool_tunnel_udp_table table; -}; - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -struct ethtool_strset_get_req { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req *ethtool_strset_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req)); -} -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req); - -static inline void -ethtool_strset_get_req_set_header_dev_index(struct ethtool_strset_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_set_header_dev_name(struct ethtool_strset_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_set_header_flags(struct ethtool_strset_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_set_stringsets_stringset(struct ethtool_strset_get_req *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_set_counts_only(struct ethtool_strset_get_req *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_rsp { - struct { - __u32 header:1; - __u32 stringsets:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp); - -/* - * Get string set from the kernel. - */ -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req); - -/* ETHTOOL_MSG_STRSET_GET - dump */ -struct ethtool_strset_get_req_dump { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req_dump * -ethtool_strset_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req_dump)); -} -void ethtool_strset_get_req_dump_free(struct ethtool_strset_get_req_dump *req); - -static inline void -ethtool_strset_get_req_dump_set_header_dev_index(struct ethtool_strset_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_dump_set_header_dev_name(struct ethtool_strset_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_dump_set_header_flags(struct ethtool_strset_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_dump_set_stringsets_stringset(struct ethtool_strset_get_req_dump *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_dump_set_counts_only(struct ethtool_strset_get_req_dump *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_list { - struct ethtool_strset_get_list *next; - struct ethtool_strset_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp); - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req); - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -struct ethtool_linkinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req * -ethtool_linkinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req)); -} -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req); - -static inline void -ethtool_linkinfo_get_req_set_header_dev_index(struct ethtool_linkinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_set_header_dev_name(struct ethtool_linkinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_set_header_flags(struct ethtool_linkinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_rsp { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp); - -/* - * Get link info. - */ -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req); - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -struct ethtool_linkinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req_dump * -ethtool_linkinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req_dump)); -} -void -ethtool_linkinfo_get_req_dump_free(struct ethtool_linkinfo_get_req_dump *req); - -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_index(struct ethtool_linkinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_name(struct ethtool_linkinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_flags(struct ethtool_linkinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_list { - struct ethtool_linkinfo_get_list *next; - struct ethtool_linkinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp); - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req); - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -struct ethtool_linkinfo_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkinfo_get_ntf *ntf); - struct ethtool_linkinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -struct ethtool_linkinfo_set_req { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -static inline struct ethtool_linkinfo_set_req * -ethtool_linkinfo_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_set_req)); -} -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req); - -static inline void -ethtool_linkinfo_set_req_set_header_dev_index(struct ethtool_linkinfo_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_set_req_set_header_dev_name(struct ethtool_linkinfo_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_set_req_set_header_flags(struct ethtool_linkinfo_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkinfo_set_req_set_port(struct ethtool_linkinfo_set_req *req, - __u8 port) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -ethtool_linkinfo_set_req_set_phyaddr(struct ethtool_linkinfo_set_req *req, - __u8 phyaddr) -{ - req->_present.phyaddr = 1; - req->phyaddr = phyaddr; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix) -{ - req->_present.tp_mdix = 1; - req->tp_mdix = tp_mdix; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix_ctrl(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix_ctrl) -{ - req->_present.tp_mdix_ctrl = 1; - req->tp_mdix_ctrl = tp_mdix_ctrl; -} -static inline void -ethtool_linkinfo_set_req_set_transceiver(struct ethtool_linkinfo_set_req *req, - __u8 transceiver) -{ - req->_present.transceiver = 1; - req->transceiver = transceiver; -} - -/* - * Set link info. - */ -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req); - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -struct ethtool_linkmodes_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req * -ethtool_linkmodes_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req)); -} -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req); - -static inline void -ethtool_linkmodes_get_req_set_header_dev_index(struct ethtool_linkmodes_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_set_header_dev_name(struct ethtool_linkmodes_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_set_header_flags(struct ethtool_linkmodes_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp); - -/* - * Get link modes. - */ -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req); - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -struct ethtool_linkmodes_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req_dump * -ethtool_linkmodes_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req_dump)); -} -void -ethtool_linkmodes_get_req_dump_free(struct ethtool_linkmodes_get_req_dump *req); - -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_index(struct ethtool_linkmodes_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_name(struct ethtool_linkmodes_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_flags(struct ethtool_linkmodes_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_list { - struct ethtool_linkmodes_get_list *next; - struct ethtool_linkmodes_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp); - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req); - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -struct ethtool_linkmodes_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkmodes_get_ntf *ntf); - struct ethtool_linkmodes_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -struct ethtool_linkmodes_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -static inline struct ethtool_linkmodes_set_req * -ethtool_linkmodes_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_set_req)); -} -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req); - -static inline void -ethtool_linkmodes_set_req_set_header_dev_index(struct ethtool_linkmodes_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_set_req_set_header_dev_name(struct ethtool_linkmodes_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_set_req_set_header_flags(struct ethtool_linkmodes_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkmodes_set_req_set_autoneg(struct ethtool_linkmodes_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_linkmodes_set_req_set_ours_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.ours = 1; - req->ours._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_ours_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.ours = 1; - req->ours._present.size = 1; - req->ours.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_ours_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->ours.bits.bit); - req->ours.bits.bit = bit; - req->ours.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_peer_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.peer = 1; - req->peer._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_peer_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.peer = 1; - req->peer._present.size = 1; - req->peer.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_peer_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->peer.bits.bit); - req->peer.bits.bit = bit; - req->peer.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_speed(struct ethtool_linkmodes_set_req *req, - __u32 speed) -{ - req->_present.speed = 1; - req->speed = speed; -} -static inline void -ethtool_linkmodes_set_req_set_duplex(struct ethtool_linkmodes_set_req *req, - __u8 duplex) -{ - req->_present.duplex = 1; - req->duplex = duplex; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_cfg(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_cfg) -{ - req->_present.master_slave_cfg = 1; - req->master_slave_cfg = master_slave_cfg; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_state(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_state) -{ - req->_present.master_slave_state = 1; - req->master_slave_state = master_slave_state; -} -static inline void -ethtool_linkmodes_set_req_set_lanes(struct ethtool_linkmodes_set_req *req, - __u32 lanes) -{ - req->_present.lanes = 1; - req->lanes = lanes; -} -static inline void -ethtool_linkmodes_set_req_set_rate_matching(struct ethtool_linkmodes_set_req *req, - __u8 rate_matching) -{ - req->_present.rate_matching = 1; - req->rate_matching = rate_matching; -} - -/* - * Set link modes. - */ -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req); - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -struct ethtool_linkstate_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req * -ethtool_linkstate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req)); -} -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req); - -static inline void -ethtool_linkstate_get_req_set_header_dev_index(struct ethtool_linkstate_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_set_header_dev_name(struct ethtool_linkstate_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_set_header_flags(struct ethtool_linkstate_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_rsp { - struct { - __u32 header:1; - __u32 link:1; - __u32 sqi:1; - __u32 sqi_max:1; - __u32 ext_state:1; - __u32 ext_substate:1; - __u32 ext_down_cnt:1; - } _present; - - struct ethtool_header header; - __u8 link; - __u32 sqi; - __u32 sqi_max; - __u8 ext_state; - __u8 ext_substate; - __u32 ext_down_cnt; -}; - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp); - -/* - * Get link state. - */ -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req); - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -struct ethtool_linkstate_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req_dump * -ethtool_linkstate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req_dump)); -} -void -ethtool_linkstate_get_req_dump_free(struct ethtool_linkstate_get_req_dump *req); - -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_index(struct ethtool_linkstate_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_name(struct ethtool_linkstate_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_flags(struct ethtool_linkstate_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_list { - struct ethtool_linkstate_get_list *next; - struct ethtool_linkstate_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp); - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req); - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -struct ethtool_debug_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req *ethtool_debug_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req)); -} -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req); - -static inline void -ethtool_debug_get_req_set_header_dev_index(struct ethtool_debug_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_set_header_dev_name(struct ethtool_debug_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_set_header_flags(struct ethtool_debug_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_rsp { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp); - -/* - * Get debug message mask. - */ -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req); - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -struct ethtool_debug_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req_dump * -ethtool_debug_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req_dump)); -} -void ethtool_debug_get_req_dump_free(struct ethtool_debug_get_req_dump *req); - -static inline void -ethtool_debug_get_req_dump_set_header_dev_index(struct ethtool_debug_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_dump_set_header_dev_name(struct ethtool_debug_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_dump_set_header_flags(struct ethtool_debug_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_list { - struct ethtool_debug_get_list *next; - struct ethtool_debug_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp); - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req); - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -struct ethtool_debug_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_debug_get_ntf *ntf); - struct ethtool_debug_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -struct ethtool_debug_set_req { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -static inline struct ethtool_debug_set_req *ethtool_debug_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_set_req)); -} -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req); - -static inline void -ethtool_debug_set_req_set_header_dev_index(struct ethtool_debug_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_set_req_set_header_dev_name(struct ethtool_debug_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_set_req_set_header_flags(struct ethtool_debug_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_debug_set_req_set_msgmask_nomask(struct ethtool_debug_set_req *req) -{ - req->_present.msgmask = 1; - req->msgmask._present.nomask = 1; -} -static inline void -ethtool_debug_set_req_set_msgmask_size(struct ethtool_debug_set_req *req, - __u32 size) -{ - req->_present.msgmask = 1; - req->msgmask._present.size = 1; - req->msgmask.size = size; -} -static inline void -__ethtool_debug_set_req_set_msgmask_bits_bit(struct ethtool_debug_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->msgmask.bits.bit); - req->msgmask.bits.bit = bit; - req->msgmask.bits.n_bit = n_bit; -} - -/* - * Set debug message mask. - */ -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req); - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -struct ethtool_wol_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req *ethtool_wol_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req)); -} -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req); - -static inline void -ethtool_wol_get_req_set_header_dev_index(struct ethtool_wol_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_set_header_dev_name(struct ethtool_wol_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_set_header_flags(struct ethtool_wol_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp); - -/* - * Get WOL params. - */ -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req); - -/* ETHTOOL_MSG_WOL_GET - dump */ -struct ethtool_wol_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req_dump * -ethtool_wol_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req_dump)); -} -void ethtool_wol_get_req_dump_free(struct ethtool_wol_get_req_dump *req); - -static inline void -ethtool_wol_get_req_dump_set_header_dev_index(struct ethtool_wol_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_dump_set_header_dev_name(struct ethtool_wol_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_dump_set_header_flags(struct ethtool_wol_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_list { - struct ethtool_wol_get_list *next; - struct ethtool_wol_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp); - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req); - -/* ETHTOOL_MSG_WOL_GET - notify */ -struct ethtool_wol_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_wol_get_ntf *ntf); - struct ethtool_wol_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -struct ethtool_wol_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -static inline struct ethtool_wol_set_req *ethtool_wol_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_set_req)); -} -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req); - -static inline void -ethtool_wol_set_req_set_header_dev_index(struct ethtool_wol_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_set_req_set_header_dev_name(struct ethtool_wol_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_set_req_set_header_flags(struct ethtool_wol_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_wol_set_req_set_modes_nomask(struct ethtool_wol_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_wol_set_req_set_modes_size(struct ethtool_wol_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_wol_set_req_set_modes_bits_bit(struct ethtool_wol_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_wol_set_req_set_sopass(struct ethtool_wol_set_req *req, - const void *sopass, size_t len) -{ - free(req->sopass); - req->_present.sopass_len = len; - req->sopass = malloc(req->_present.sopass_len); - memcpy(req->sopass, sopass, req->_present.sopass_len); -} - -/* - * Set WOL params. - */ -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req); - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -struct ethtool_features_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req * -ethtool_features_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req)); -} -void ethtool_features_get_req_free(struct ethtool_features_get_req *req); - -static inline void -ethtool_features_get_req_set_header_dev_index(struct ethtool_features_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_set_header_dev_name(struct ethtool_features_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_set_header_flags(struct ethtool_features_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp); - -/* - * Get features. - */ -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req); - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -struct ethtool_features_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req_dump * -ethtool_features_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req_dump)); -} -void -ethtool_features_get_req_dump_free(struct ethtool_features_get_req_dump *req); - -static inline void -ethtool_features_get_req_dump_set_header_dev_index(struct ethtool_features_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_dump_set_header_dev_name(struct ethtool_features_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_dump_set_header_flags(struct ethtool_features_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_list { - struct ethtool_features_get_list *next; - struct ethtool_features_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp); - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req); - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -struct ethtool_features_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_features_get_ntf *ntf); - struct ethtool_features_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -struct ethtool_features_set_req { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -static inline struct ethtool_features_set_req * -ethtool_features_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_set_req)); -} -void ethtool_features_set_req_free(struct ethtool_features_set_req *req); - -static inline void -ethtool_features_set_req_set_header_dev_index(struct ethtool_features_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_set_req_set_header_dev_name(struct ethtool_features_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_set_req_set_header_flags(struct ethtool_features_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_features_set_req_set_hw_nomask(struct ethtool_features_set_req *req) -{ - req->_present.hw = 1; - req->hw._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_hw_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.hw = 1; - req->hw._present.size = 1; - req->hw.size = size; -} -static inline void -__ethtool_features_set_req_set_hw_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->hw.bits.bit); - req->hw.bits.bit = bit; - req->hw.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_wanted_nomask(struct ethtool_features_set_req *req) -{ - req->_present.wanted = 1; - req->wanted._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_wanted_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.wanted = 1; - req->wanted._present.size = 1; - req->wanted.size = size; -} -static inline void -__ethtool_features_set_req_set_wanted_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->wanted.bits.bit); - req->wanted.bits.bit = bit; - req->wanted.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_active_nomask(struct ethtool_features_set_req *req) -{ - req->_present.active = 1; - req->active._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_active_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.active = 1; - req->active._present.size = 1; - req->active.size = size; -} -static inline void -__ethtool_features_set_req_set_active_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->active.bits.bit); - req->active.bits.bit = bit; - req->active.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_nochange_nomask(struct ethtool_features_set_req *req) -{ - req->_present.nochange = 1; - req->nochange._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_nochange_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.nochange = 1; - req->nochange._present.size = 1; - req->nochange.size = size; -} -static inline void -__ethtool_features_set_req_set_nochange_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->nochange.bits.bit); - req->nochange.bits.bit = bit; - req->nochange.bits.n_bit = n_bit; -} - -struct ethtool_features_set_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp); - -/* - * Set features. - */ -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -struct ethtool_privflags_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req * -ethtool_privflags_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req)); -} -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req); - -static inline void -ethtool_privflags_get_req_set_header_dev_index(struct ethtool_privflags_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_set_header_dev_name(struct ethtool_privflags_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_set_header_flags(struct ethtool_privflags_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_rsp { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp); - -/* - * Get device private flags. - */ -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -struct ethtool_privflags_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req_dump * -ethtool_privflags_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req_dump)); -} -void -ethtool_privflags_get_req_dump_free(struct ethtool_privflags_get_req_dump *req); - -static inline void -ethtool_privflags_get_req_dump_set_header_dev_index(struct ethtool_privflags_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_dump_set_header_dev_name(struct ethtool_privflags_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_dump_set_header_flags(struct ethtool_privflags_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_list { - struct ethtool_privflags_get_list *next; - struct ethtool_privflags_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp); - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -struct ethtool_privflags_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_privflags_get_ntf *ntf); - struct ethtool_privflags_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -struct ethtool_privflags_set_req { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -static inline struct ethtool_privflags_set_req * -ethtool_privflags_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_set_req)); -} -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req); - -static inline void -ethtool_privflags_set_req_set_header_dev_index(struct ethtool_privflags_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_set_req_set_header_dev_name(struct ethtool_privflags_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_set_req_set_header_flags(struct ethtool_privflags_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_privflags_set_req_set_flags_nomask(struct ethtool_privflags_set_req *req) -{ - req->_present.flags = 1; - req->flags._present.nomask = 1; -} -static inline void -ethtool_privflags_set_req_set_flags_size(struct ethtool_privflags_set_req *req, - __u32 size) -{ - req->_present.flags = 1; - req->flags._present.size = 1; - req->flags.size = size; -} -static inline void -__ethtool_privflags_set_req_set_flags_bits_bit(struct ethtool_privflags_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->flags.bits.bit); - req->flags.bits.bit = bit; - req->flags.bits.n_bit = n_bit; -} - -/* - * Set device private flags. - */ -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req); - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -struct ethtool_rings_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req *ethtool_rings_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req)); -} -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req); - -static inline void -ethtool_rings_get_req_set_header_dev_index(struct ethtool_rings_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_set_header_dev_name(struct ethtool_rings_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_set_header_flags(struct ethtool_rings_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp); - -/* - * Get ring params. - */ -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req); - -/* ETHTOOL_MSG_RINGS_GET - dump */ -struct ethtool_rings_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req_dump * -ethtool_rings_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req_dump)); -} -void ethtool_rings_get_req_dump_free(struct ethtool_rings_get_req_dump *req); - -static inline void -ethtool_rings_get_req_dump_set_header_dev_index(struct ethtool_rings_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_dump_set_header_dev_name(struct ethtool_rings_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_dump_set_header_flags(struct ethtool_rings_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_list { - struct ethtool_rings_get_list *next; - struct ethtool_rings_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp); - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req); - -/* ETHTOOL_MSG_RINGS_GET - notify */ -struct ethtool_rings_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_rings_get_ntf *ntf); - struct ethtool_rings_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -struct ethtool_rings_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -static inline struct ethtool_rings_set_req *ethtool_rings_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_set_req)); -} -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req); - -static inline void -ethtool_rings_set_req_set_header_dev_index(struct ethtool_rings_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_set_req_set_header_dev_name(struct ethtool_rings_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_set_req_set_header_flags(struct ethtool_rings_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_rings_set_req_set_rx_max(struct ethtool_rings_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_rings_set_req_set_rx_mini_max(struct ethtool_rings_set_req *req, - __u32 rx_mini_max) -{ - req->_present.rx_mini_max = 1; - req->rx_mini_max = rx_mini_max; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo_max(struct ethtool_rings_set_req *req, - __u32 rx_jumbo_max) -{ - req->_present.rx_jumbo_max = 1; - req->rx_jumbo_max = rx_jumbo_max; -} -static inline void -ethtool_rings_set_req_set_tx_max(struct ethtool_rings_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_rings_set_req_set_rx(struct ethtool_rings_set_req *req, __u32 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_rings_set_req_set_rx_mini(struct ethtool_rings_set_req *req, - __u32 rx_mini) -{ - req->_present.rx_mini = 1; - req->rx_mini = rx_mini; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo(struct ethtool_rings_set_req *req, - __u32 rx_jumbo) -{ - req->_present.rx_jumbo = 1; - req->rx_jumbo = rx_jumbo; -} -static inline void -ethtool_rings_set_req_set_tx(struct ethtool_rings_set_req *req, __u32 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_rings_set_req_set_rx_buf_len(struct ethtool_rings_set_req *req, - __u32 rx_buf_len) -{ - req->_present.rx_buf_len = 1; - req->rx_buf_len = rx_buf_len; -} -static inline void -ethtool_rings_set_req_set_tcp_data_split(struct ethtool_rings_set_req *req, - __u8 tcp_data_split) -{ - req->_present.tcp_data_split = 1; - req->tcp_data_split = tcp_data_split; -} -static inline void -ethtool_rings_set_req_set_cqe_size(struct ethtool_rings_set_req *req, - __u32 cqe_size) -{ - req->_present.cqe_size = 1; - req->cqe_size = cqe_size; -} -static inline void -ethtool_rings_set_req_set_tx_push(struct ethtool_rings_set_req *req, - __u8 tx_push) -{ - req->_present.tx_push = 1; - req->tx_push = tx_push; -} -static inline void -ethtool_rings_set_req_set_rx_push(struct ethtool_rings_set_req *req, - __u8 rx_push) -{ - req->_present.rx_push = 1; - req->rx_push = rx_push; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len) -{ - req->_present.tx_push_buf_len = 1; - req->tx_push_buf_len = tx_push_buf_len; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len_max(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len_max) -{ - req->_present.tx_push_buf_len_max = 1; - req->tx_push_buf_len_max = tx_push_buf_len_max; -} - -/* - * Set ring params. - */ -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req); - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -struct ethtool_channels_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req * -ethtool_channels_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req)); -} -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req); - -static inline void -ethtool_channels_get_req_set_header_dev_index(struct ethtool_channels_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_set_header_dev_name(struct ethtool_channels_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_set_header_flags(struct ethtool_channels_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp); - -/* - * Get channel params. - */ -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req); - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -struct ethtool_channels_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req_dump * -ethtool_channels_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req_dump)); -} -void -ethtool_channels_get_req_dump_free(struct ethtool_channels_get_req_dump *req); - -static inline void -ethtool_channels_get_req_dump_set_header_dev_index(struct ethtool_channels_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_dump_set_header_dev_name(struct ethtool_channels_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_dump_set_header_flags(struct ethtool_channels_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_list { - struct ethtool_channels_get_list *next; - struct ethtool_channels_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp); - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req); - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -struct ethtool_channels_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_channels_get_ntf *ntf); - struct ethtool_channels_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -struct ethtool_channels_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -static inline struct ethtool_channels_set_req * -ethtool_channels_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_set_req)); -} -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req); - -static inline void -ethtool_channels_set_req_set_header_dev_index(struct ethtool_channels_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_set_req_set_header_dev_name(struct ethtool_channels_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_set_req_set_header_flags(struct ethtool_channels_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_channels_set_req_set_rx_max(struct ethtool_channels_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_channels_set_req_set_tx_max(struct ethtool_channels_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_channels_set_req_set_other_max(struct ethtool_channels_set_req *req, - __u32 other_max) -{ - req->_present.other_max = 1; - req->other_max = other_max; -} -static inline void -ethtool_channels_set_req_set_combined_max(struct ethtool_channels_set_req *req, - __u32 combined_max) -{ - req->_present.combined_max = 1; - req->combined_max = combined_max; -} -static inline void -ethtool_channels_set_req_set_rx_count(struct ethtool_channels_set_req *req, - __u32 rx_count) -{ - req->_present.rx_count = 1; - req->rx_count = rx_count; -} -static inline void -ethtool_channels_set_req_set_tx_count(struct ethtool_channels_set_req *req, - __u32 tx_count) -{ - req->_present.tx_count = 1; - req->tx_count = tx_count; -} -static inline void -ethtool_channels_set_req_set_other_count(struct ethtool_channels_set_req *req, - __u32 other_count) -{ - req->_present.other_count = 1; - req->other_count = other_count; -} -static inline void -ethtool_channels_set_req_set_combined_count(struct ethtool_channels_set_req *req, - __u32 combined_count) -{ - req->_present.combined_count = 1; - req->combined_count = combined_count; -} - -/* - * Set channel params. - */ -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req); - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -struct ethtool_coalesce_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req * -ethtool_coalesce_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req)); -} -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req); - -static inline void -ethtool_coalesce_get_req_set_header_dev_index(struct ethtool_coalesce_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_set_header_dev_name(struct ethtool_coalesce_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_set_header_flags(struct ethtool_coalesce_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_rsp { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp); - -/* - * Get coalesce params. - */ -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req); - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -struct ethtool_coalesce_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req_dump * -ethtool_coalesce_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req_dump)); -} -void -ethtool_coalesce_get_req_dump_free(struct ethtool_coalesce_get_req_dump *req); - -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_index(struct ethtool_coalesce_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_name(struct ethtool_coalesce_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_flags(struct ethtool_coalesce_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_list { - struct ethtool_coalesce_get_list *next; - struct ethtool_coalesce_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp); - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req); - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -struct ethtool_coalesce_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_coalesce_get_ntf *ntf); - struct ethtool_coalesce_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -struct ethtool_coalesce_set_req { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -static inline struct ethtool_coalesce_set_req * -ethtool_coalesce_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_set_req)); -} -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req); - -static inline void -ethtool_coalesce_set_req_set_header_dev_index(struct ethtool_coalesce_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_set_req_set_header_dev_name(struct ethtool_coalesce_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_set_req_set_header_flags(struct ethtool_coalesce_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs) -{ - req->_present.rx_usecs = 1; - req->rx_usecs = rx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames) -{ - req->_present.rx_max_frames = 1; - req->rx_max_frames = rx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_irq) -{ - req->_present.rx_usecs_irq = 1; - req->rx_usecs_irq = rx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_irq) -{ - req->_present.rx_max_frames_irq = 1; - req->rx_max_frames_irq = rx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs) -{ - req->_present.tx_usecs = 1; - req->tx_usecs = tx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames) -{ - req->_present.tx_max_frames = 1; - req->tx_max_frames = tx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_irq) -{ - req->_present.tx_usecs_irq = 1; - req->tx_usecs_irq = tx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_irq) -{ - req->_present.tx_max_frames_irq = 1; - req->tx_max_frames_irq = tx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_stats_block_usecs(struct ethtool_coalesce_set_req *req, - __u32 stats_block_usecs) -{ - req->_present.stats_block_usecs = 1; - req->stats_block_usecs = stats_block_usecs; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_rx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_rx) -{ - req->_present.use_adaptive_rx = 1; - req->use_adaptive_rx = use_adaptive_rx; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_tx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_tx) -{ - req->_present.use_adaptive_tx = 1; - req->use_adaptive_tx = use_adaptive_tx; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_low(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_low) -{ - req->_present.pkt_rate_low = 1; - req->pkt_rate_low = pkt_rate_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_low) -{ - req->_present.rx_usecs_low = 1; - req->rx_usecs_low = rx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_low) -{ - req->_present.rx_max_frames_low = 1; - req->rx_max_frames_low = rx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_low) -{ - req->_present.tx_usecs_low = 1; - req->tx_usecs_low = tx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_low) -{ - req->_present.tx_max_frames_low = 1; - req->tx_max_frames_low = tx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_high(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_high) -{ - req->_present.pkt_rate_high = 1; - req->pkt_rate_high = pkt_rate_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_high) -{ - req->_present.rx_usecs_high = 1; - req->rx_usecs_high = rx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_high) -{ - req->_present.rx_max_frames_high = 1; - req->rx_max_frames_high = rx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_high) -{ - req->_present.tx_usecs_high = 1; - req->tx_usecs_high = tx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_high) -{ - req->_present.tx_max_frames_high = 1; - req->tx_max_frames_high = tx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_rate_sample_interval(struct ethtool_coalesce_set_req *req, - __u32 rate_sample_interval) -{ - req->_present.rate_sample_interval = 1; - req->rate_sample_interval = rate_sample_interval; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_tx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_tx) -{ - req->_present.use_cqe_mode_tx = 1; - req->use_cqe_mode_tx = use_cqe_mode_tx; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_rx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_rx) -{ - req->_present.use_cqe_mode_rx = 1; - req->use_cqe_mode_rx = use_cqe_mode_rx; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_bytes(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_bytes) -{ - req->_present.tx_aggr_max_bytes = 1; - req->tx_aggr_max_bytes = tx_aggr_max_bytes; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_frames) -{ - req->_present.tx_aggr_max_frames = 1; - req->tx_aggr_max_frames = tx_aggr_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_time_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_time_usecs) -{ - req->_present.tx_aggr_time_usecs = 1; - req->tx_aggr_time_usecs = tx_aggr_time_usecs; -} - -/* - * Set coalesce params. - */ -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req); - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -struct ethtool_pause_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req *ethtool_pause_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req)); -} -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req); - -static inline void -ethtool_pause_get_req_set_header_dev_index(struct ethtool_pause_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_set_header_dev_name(struct ethtool_pause_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_set_header_flags(struct ethtool_pause_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp); - -/* - * Get pause params. - */ -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req); - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -struct ethtool_pause_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req_dump * -ethtool_pause_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req_dump)); -} -void ethtool_pause_get_req_dump_free(struct ethtool_pause_get_req_dump *req); - -static inline void -ethtool_pause_get_req_dump_set_header_dev_index(struct ethtool_pause_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_dump_set_header_dev_name(struct ethtool_pause_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_dump_set_header_flags(struct ethtool_pause_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_list { - struct ethtool_pause_get_list *next; - struct ethtool_pause_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp); - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req); - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -struct ethtool_pause_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_pause_get_ntf *ntf); - struct ethtool_pause_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -struct ethtool_pause_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -static inline struct ethtool_pause_set_req *ethtool_pause_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_set_req)); -} -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req); - -static inline void -ethtool_pause_set_req_set_header_dev_index(struct ethtool_pause_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_set_req_set_header_dev_name(struct ethtool_pause_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_set_req_set_header_flags(struct ethtool_pause_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pause_set_req_set_autoneg(struct ethtool_pause_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_pause_set_req_set_rx(struct ethtool_pause_set_req *req, __u8 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_pause_set_req_set_tx(struct ethtool_pause_set_req *req, __u8 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_pause_set_req_set_stats_tx_frames(struct ethtool_pause_set_req *req, - __u64 tx_frames) -{ - req->_present.stats = 1; - req->stats._present.tx_frames = 1; - req->stats.tx_frames = tx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_rx_frames(struct ethtool_pause_set_req *req, - __u64 rx_frames) -{ - req->_present.stats = 1; - req->stats._present.rx_frames = 1; - req->stats.rx_frames = rx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_src(struct ethtool_pause_set_req *req, - __u32 stats_src) -{ - req->_present.stats_src = 1; - req->stats_src = stats_src; -} - -/* - * Set pause params. - */ -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req); - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -struct ethtool_eee_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req *ethtool_eee_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req)); -} -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req); - -static inline void -ethtool_eee_get_req_set_header_dev_index(struct ethtool_eee_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_set_header_dev_name(struct ethtool_eee_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_set_header_flags(struct ethtool_eee_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_rsp { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp); - -/* - * Get eee params. - */ -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req); - -/* ETHTOOL_MSG_EEE_GET - dump */ -struct ethtool_eee_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req_dump * -ethtool_eee_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req_dump)); -} -void ethtool_eee_get_req_dump_free(struct ethtool_eee_get_req_dump *req); - -static inline void -ethtool_eee_get_req_dump_set_header_dev_index(struct ethtool_eee_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_dump_set_header_dev_name(struct ethtool_eee_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_dump_set_header_flags(struct ethtool_eee_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_list { - struct ethtool_eee_get_list *next; - struct ethtool_eee_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp); - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req); - -/* ETHTOOL_MSG_EEE_GET - notify */ -struct ethtool_eee_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_eee_get_ntf *ntf); - struct ethtool_eee_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -struct ethtool_eee_set_req { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -static inline struct ethtool_eee_set_req *ethtool_eee_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_set_req)); -} -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req); - -static inline void -ethtool_eee_set_req_set_header_dev_index(struct ethtool_eee_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_set_req_set_header_dev_name(struct ethtool_eee_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_set_req_set_header_flags(struct ethtool_eee_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_eee_set_req_set_modes_ours_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_ours_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.size = 1; - req->modes_ours.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_ours_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_ours.bits.bit); - req->modes_ours.bits.bit = bit; - req->modes_ours.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_modes_peer_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_peer_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.size = 1; - req->modes_peer.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_peer_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_peer.bits.bit); - req->modes_peer.bits.bit = bit; - req->modes_peer.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_active(struct ethtool_eee_set_req *req, __u8 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_eee_set_req_set_enabled(struct ethtool_eee_set_req *req, __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_enabled(struct ethtool_eee_set_req *req, - __u8 tx_lpi_enabled) -{ - req->_present.tx_lpi_enabled = 1; - req->tx_lpi_enabled = tx_lpi_enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_timer(struct ethtool_eee_set_req *req, - __u32 tx_lpi_timer) -{ - req->_present.tx_lpi_timer = 1; - req->tx_lpi_timer = tx_lpi_timer; -} - -/* - * Set eee params. - */ -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req); - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -struct ethtool_tsinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req *ethtool_tsinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req)); -} -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req); - -static inline void -ethtool_tsinfo_get_req_set_header_dev_index(struct ethtool_tsinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_set_header_dev_name(struct ethtool_tsinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_set_header_flags(struct ethtool_tsinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_rsp { - struct { - __u32 header:1; - __u32 timestamping:1; - __u32 tx_types:1; - __u32 rx_filters:1; - __u32 phc_index:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset timestamping; - struct ethtool_bitset tx_types; - struct ethtool_bitset rx_filters; - __u32 phc_index; -}; - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req); - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -struct ethtool_tsinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req_dump * -ethtool_tsinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req_dump)); -} -void ethtool_tsinfo_get_req_dump_free(struct ethtool_tsinfo_get_req_dump *req); - -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_index(struct ethtool_tsinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_name(struct ethtool_tsinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_flags(struct ethtool_tsinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_list { - struct ethtool_tsinfo_get_list *next; - struct ethtool_tsinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp); - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -struct ethtool_cable_test_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_act_req * -ethtool_cable_test_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_act_req)); -} -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req); - -static inline void -ethtool_cable_test_act_req_set_header_dev_index(struct ethtool_cable_test_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_act_req_set_header_dev_name(struct ethtool_cable_test_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_act_req_set_header_flags(struct ethtool_cable_test_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test. - */ -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -struct ethtool_cable_test_tdr_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_tdr_act_req * -ethtool_cable_test_tdr_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_tdr_act_req)); -} -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req); - -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_index(struct ethtool_cable_test_tdr_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_name(struct ethtool_cable_test_tdr_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_flags(struct ethtool_cable_test_tdr_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test TDR. - */ -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req); - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -struct ethtool_tunnel_info_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req * -ethtool_tunnel_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req)); -} -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req); - -static inline void -ethtool_tunnel_info_get_req_set_header_dev_index(struct ethtool_tunnel_info_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_set_header_dev_name(struct ethtool_tunnel_info_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_set_header_flags(struct ethtool_tunnel_info_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_rsp { - struct { - __u32 header:1; - __u32 udp_ports:1; - } _present; - - struct ethtool_header header; - struct ethtool_tunnel_udp udp_ports; -}; - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req); - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -struct ethtool_tunnel_info_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req_dump * -ethtool_tunnel_info_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req_dump)); -} -void -ethtool_tunnel_info_get_req_dump_free(struct ethtool_tunnel_info_get_req_dump *req); - -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_index(struct ethtool_tunnel_info_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_name(struct ethtool_tunnel_info_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_flags(struct ethtool_tunnel_info_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_list { - struct ethtool_tunnel_info_get_list *next; - struct ethtool_tunnel_info_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp); - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req); - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -struct ethtool_fec_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req *ethtool_fec_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req)); -} -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req); - -static inline void -ethtool_fec_get_req_set_header_dev_index(struct ethtool_fec_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_set_header_dev_name(struct ethtool_fec_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_set_header_flags(struct ethtool_fec_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp); - -/* - * Get FEC params. - */ -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req); - -/* ETHTOOL_MSG_FEC_GET - dump */ -struct ethtool_fec_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req_dump * -ethtool_fec_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req_dump)); -} -void ethtool_fec_get_req_dump_free(struct ethtool_fec_get_req_dump *req); - -static inline void -ethtool_fec_get_req_dump_set_header_dev_index(struct ethtool_fec_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_dump_set_header_dev_name(struct ethtool_fec_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_dump_set_header_flags(struct ethtool_fec_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_list { - struct ethtool_fec_get_list *next; - struct ethtool_fec_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp); - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req); - -/* ETHTOOL_MSG_FEC_GET - notify */ -struct ethtool_fec_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_fec_get_ntf *ntf); - struct ethtool_fec_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -struct ethtool_fec_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -static inline struct ethtool_fec_set_req *ethtool_fec_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_set_req)); -} -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req); - -static inline void -ethtool_fec_set_req_set_header_dev_index(struct ethtool_fec_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_set_req_set_header_dev_name(struct ethtool_fec_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_set_req_set_header_flags(struct ethtool_fec_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_fec_set_req_set_modes_nomask(struct ethtool_fec_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_fec_set_req_set_modes_size(struct ethtool_fec_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_fec_set_req_set_modes_bits_bit(struct ethtool_fec_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_fec_set_req_set_auto_(struct ethtool_fec_set_req *req, __u8 auto_) -{ - req->_present.auto_ = 1; - req->auto_ = auto_; -} -static inline void -ethtool_fec_set_req_set_active(struct ethtool_fec_set_req *req, __u32 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_fec_set_req_set_stats_corrected(struct ethtool_fec_set_req *req, - const void *corrected, size_t len) -{ - free(req->stats.corrected); - req->stats._present.corrected_len = len; - req->stats.corrected = malloc(req->stats._present.corrected_len); - memcpy(req->stats.corrected, corrected, req->stats._present.corrected_len); -} -static inline void -ethtool_fec_set_req_set_stats_uncorr(struct ethtool_fec_set_req *req, - const void *uncorr, size_t len) -{ - free(req->stats.uncorr); - req->stats._present.uncorr_len = len; - req->stats.uncorr = malloc(req->stats._present.uncorr_len); - memcpy(req->stats.uncorr, uncorr, req->stats._present.uncorr_len); -} -static inline void -ethtool_fec_set_req_set_stats_corr_bits(struct ethtool_fec_set_req *req, - const void *corr_bits, size_t len) -{ - free(req->stats.corr_bits); - req->stats._present.corr_bits_len = len; - req->stats.corr_bits = malloc(req->stats._present.corr_bits_len); - memcpy(req->stats.corr_bits, corr_bits, req->stats._present.corr_bits_len); -} - -/* - * Set FEC params. - */ -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req); - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -struct ethtool_module_eeprom_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req * -ethtool_module_eeprom_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req)); -} -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req); - -static inline void -ethtool_module_eeprom_get_req_set_header_dev_index(struct ethtool_module_eeprom_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_set_header_dev_name(struct ethtool_module_eeprom_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_set_header_flags(struct ethtool_module_eeprom_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_rsp { - struct { - __u32 header:1; - __u32 offset:1; - __u32 length:1; - __u32 page:1; - __u32 bank:1; - __u32 i2c_address:1; - __u32 data_len; - } _present; - - struct ethtool_header header; - __u32 offset; - __u32 length; - __u8 page; - __u8 bank; - __u8 i2c_address; - void *data; -}; - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp); - -/* - * Get module EEPROM params. - */ -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req); - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -struct ethtool_module_eeprom_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req_dump * -ethtool_module_eeprom_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req_dump)); -} -void -ethtool_module_eeprom_get_req_dump_free(struct ethtool_module_eeprom_get_req_dump *req); - -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_index(struct ethtool_module_eeprom_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_name(struct ethtool_module_eeprom_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_flags(struct ethtool_module_eeprom_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_list { - struct ethtool_module_eeprom_get_list *next; - struct ethtool_module_eeprom_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp); - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -struct ethtool_phc_vclocks_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req * -ethtool_phc_vclocks_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req)); -} -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req); - -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_index(struct ethtool_phc_vclocks_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_name(struct ethtool_phc_vclocks_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_flags(struct ethtool_phc_vclocks_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_rsp { - struct { - __u32 header:1; - __u32 num:1; - } _present; - - struct ethtool_header header; - __u32 num; -}; - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp); - -/* - * Get PHC VCLOCKs. - */ -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req); - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -struct ethtool_phc_vclocks_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req_dump * -ethtool_phc_vclocks_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req_dump)); -} -void -ethtool_phc_vclocks_get_req_dump_free(struct ethtool_phc_vclocks_get_req_dump *req); - -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_index(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_name(struct ethtool_phc_vclocks_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_flags(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_list { - struct ethtool_phc_vclocks_get_list *next; - struct ethtool_phc_vclocks_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp); - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req); - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -struct ethtool_module_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req *ethtool_module_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req)); -} -void ethtool_module_get_req_free(struct ethtool_module_get_req *req); - -static inline void -ethtool_module_get_req_set_header_dev_index(struct ethtool_module_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_set_header_dev_name(struct ethtool_module_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_set_header_flags(struct ethtool_module_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_rsp { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp); - -/* - * Get module params. - */ -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req); - -/* ETHTOOL_MSG_MODULE_GET - dump */ -struct ethtool_module_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req_dump * -ethtool_module_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req_dump)); -} -void ethtool_module_get_req_dump_free(struct ethtool_module_get_req_dump *req); - -static inline void -ethtool_module_get_req_dump_set_header_dev_index(struct ethtool_module_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_dump_set_header_dev_name(struct ethtool_module_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_dump_set_header_flags(struct ethtool_module_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_list { - struct ethtool_module_get_list *next; - struct ethtool_module_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp); - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req); - -/* ETHTOOL_MSG_MODULE_GET - notify */ -struct ethtool_module_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_module_get_ntf *ntf); - struct ethtool_module_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -struct ethtool_module_set_req { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -static inline struct ethtool_module_set_req *ethtool_module_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_set_req)); -} -void ethtool_module_set_req_free(struct ethtool_module_set_req *req); - -static inline void -ethtool_module_set_req_set_header_dev_index(struct ethtool_module_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_set_req_set_header_dev_name(struct ethtool_module_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_set_req_set_header_flags(struct ethtool_module_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_module_set_req_set_power_mode_policy(struct ethtool_module_set_req *req, - __u8 power_mode_policy) -{ - req->_present.power_mode_policy = 1; - req->power_mode_policy = power_mode_policy; -} -static inline void -ethtool_module_set_req_set_power_mode(struct ethtool_module_set_req *req, - __u8 power_mode) -{ - req->_present.power_mode = 1; - req->power_mode = power_mode; -} - -/* - * Set module params. - */ -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req); - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -struct ethtool_pse_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req *ethtool_pse_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req)); -} -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req); - -static inline void -ethtool_pse_get_req_set_header_dev_index(struct ethtool_pse_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_set_header_dev_name(struct ethtool_pse_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_set_header_flags(struct ethtool_pse_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_rsp { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp); - -/* - * Get Power Sourcing Equipment params. - */ -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req); - -/* ETHTOOL_MSG_PSE_GET - dump */ -struct ethtool_pse_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req_dump * -ethtool_pse_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req_dump)); -} -void ethtool_pse_get_req_dump_free(struct ethtool_pse_get_req_dump *req); - -static inline void -ethtool_pse_get_req_dump_set_header_dev_index(struct ethtool_pse_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_dump_set_header_dev_name(struct ethtool_pse_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_dump_set_header_flags(struct ethtool_pse_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_list { - struct ethtool_pse_get_list *next; - struct ethtool_pse_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp); - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -struct ethtool_pse_set_req { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -static inline struct ethtool_pse_set_req *ethtool_pse_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_set_req)); -} -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req); - -static inline void -ethtool_pse_set_req_set_header_dev_index(struct ethtool_pse_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_set_req_set_header_dev_name(struct ethtool_pse_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_set_req_set_header_flags(struct ethtool_pse_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pse_set_req_set_admin_state(struct ethtool_pse_set_req *req, - __u32 admin_state) -{ - req->_present.admin_state = 1; - req->admin_state = admin_state; -} -static inline void -ethtool_pse_set_req_set_admin_control(struct ethtool_pse_set_req *req, - __u32 admin_control) -{ - req->_present.admin_control = 1; - req->admin_control = admin_control; -} -static inline void -ethtool_pse_set_req_set_pw_d_status(struct ethtool_pse_set_req *req, - __u32 pw_d_status) -{ - req->_present.pw_d_status = 1; - req->pw_d_status = pw_d_status; -} - -/* - * Set Power Sourcing Equipment params. - */ -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req); - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -struct ethtool_rss_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req *ethtool_rss_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req)); -} -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req); - -static inline void -ethtool_rss_get_req_set_header_dev_index(struct ethtool_rss_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_set_header_dev_name(struct ethtool_rss_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_set_header_flags(struct ethtool_rss_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_rsp { - struct { - __u32 header:1; - __u32 context:1; - __u32 hfunc:1; - __u32 indir_len; - __u32 hkey_len; - } _present; - - struct ethtool_header header; - __u32 context; - __u32 hfunc; - void *indir; - void *hkey; -}; - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp); - -/* - * Get RSS params. - */ -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req); - -/* ETHTOOL_MSG_RSS_GET - dump */ -struct ethtool_rss_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req_dump * -ethtool_rss_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req_dump)); -} -void ethtool_rss_get_req_dump_free(struct ethtool_rss_get_req_dump *req); - -static inline void -ethtool_rss_get_req_dump_set_header_dev_index(struct ethtool_rss_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_dump_set_header_dev_name(struct ethtool_rss_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_dump_set_header_flags(struct ethtool_rss_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_list { - struct ethtool_rss_get_list *next; - struct ethtool_rss_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp); - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -struct ethtool_plca_get_cfg_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req * -ethtool_plca_get_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req)); -} -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req); - -static inline void -ethtool_plca_get_cfg_req_set_header_dev_index(struct ethtool_plca_get_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_set_header_dev_name(struct ethtool_plca_get_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_set_header_flags(struct ethtool_plca_get_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp); - -/* - * Get PLCA params. - */ -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -struct ethtool_plca_get_cfg_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req_dump * -ethtool_plca_get_cfg_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req_dump)); -} -void -ethtool_plca_get_cfg_req_dump_free(struct ethtool_plca_get_cfg_req_dump *req); - -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_index(struct ethtool_plca_get_cfg_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_name(struct ethtool_plca_get_cfg_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_flags(struct ethtool_plca_get_cfg_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_list { - struct ethtool_plca_get_cfg_list *next; - struct ethtool_plca_get_cfg_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp); - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -struct ethtool_plca_get_cfg_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_plca_get_cfg_ntf *ntf); - struct ethtool_plca_get_cfg_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp); - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -struct ethtool_plca_set_cfg_req { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -static inline struct ethtool_plca_set_cfg_req * -ethtool_plca_set_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_set_cfg_req)); -} -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req); - -static inline void -ethtool_plca_set_cfg_req_set_header_dev_index(struct ethtool_plca_set_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_set_cfg_req_set_header_dev_name(struct ethtool_plca_set_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_set_cfg_req_set_header_flags(struct ethtool_plca_set_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_plca_set_cfg_req_set_version(struct ethtool_plca_set_cfg_req *req, - __u16 version) -{ - req->_present.version = 1; - req->version = version; -} -static inline void -ethtool_plca_set_cfg_req_set_enabled(struct ethtool_plca_set_cfg_req *req, - __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_plca_set_cfg_req_set_status(struct ethtool_plca_set_cfg_req *req, - __u8 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -ethtool_plca_set_cfg_req_set_node_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 node_cnt) -{ - req->_present.node_cnt = 1; - req->node_cnt = node_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_node_id(struct ethtool_plca_set_cfg_req *req, - __u32 node_id) -{ - req->_present.node_id = 1; - req->node_id = node_id; -} -static inline void -ethtool_plca_set_cfg_req_set_to_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 to_tmr) -{ - req->_present.to_tmr = 1; - req->to_tmr = to_tmr; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 burst_cnt) -{ - req->_present.burst_cnt = 1; - req->burst_cnt = burst_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 burst_tmr) -{ - req->_present.burst_tmr = 1; - req->burst_tmr = burst_tmr; -} - -/* - * Set PLCA params. - */ -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -struct ethtool_plca_get_status_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req * -ethtool_plca_get_status_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req)); -} -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req); - -static inline void -ethtool_plca_get_status_req_set_header_dev_index(struct ethtool_plca_get_status_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_set_header_dev_name(struct ethtool_plca_get_status_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_set_header_flags(struct ethtool_plca_get_status_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp); - -/* - * Get PLCA status params. - */ -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req); - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -struct ethtool_plca_get_status_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req_dump * -ethtool_plca_get_status_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req_dump)); -} -void -ethtool_plca_get_status_req_dump_free(struct ethtool_plca_get_status_req_dump *req); - -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_index(struct ethtool_plca_get_status_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_name(struct ethtool_plca_get_status_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_flags(struct ethtool_plca_get_status_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_list { - struct ethtool_plca_get_status_list *next; - struct ethtool_plca_get_status_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp); - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req); - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -struct ethtool_mm_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req *ethtool_mm_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req)); -} -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req); - -static inline void -ethtool_mm_get_req_set_header_dev_index(struct ethtool_mm_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_set_header_dev_name(struct ethtool_mm_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_set_header_flags(struct ethtool_mm_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_rsp { - struct { - __u32 header:1; - __u32 pmac_enabled:1; - __u32 tx_enabled:1; - __u32 tx_active:1; - __u32 tx_min_frag_size:1; - __u32 rx_min_frag_size:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 max_verify_time:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - __u8 pmac_enabled; - __u8 tx_enabled; - __u8 tx_active; - __u32 tx_min_frag_size; - __u32 rx_min_frag_size; - __u8 verify_enabled; - __u32 verify_time; - __u32 max_verify_time; - struct ethtool_mm_stat stats; -}; - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp); - -/* - * Get MAC Merge configuration and state - */ -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req); - -/* ETHTOOL_MSG_MM_GET - dump */ -struct ethtool_mm_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req_dump * -ethtool_mm_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req_dump)); -} -void ethtool_mm_get_req_dump_free(struct ethtool_mm_get_req_dump *req); - -static inline void -ethtool_mm_get_req_dump_set_header_dev_index(struct ethtool_mm_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_dump_set_header_dev_name(struct ethtool_mm_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_dump_set_header_flags(struct ethtool_mm_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_list { - struct ethtool_mm_get_list *next; - struct ethtool_mm_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp); - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req); - -/* ETHTOOL_MSG_MM_GET - notify */ -struct ethtool_mm_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_mm_get_ntf *ntf); - struct ethtool_mm_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -struct ethtool_mm_set_req { - struct { - __u32 header:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 tx_enabled:1; - __u32 pmac_enabled:1; - __u32 tx_min_frag_size:1; - } _present; - - struct ethtool_header header; - __u8 verify_enabled; - __u32 verify_time; - __u8 tx_enabled; - __u8 pmac_enabled; - __u32 tx_min_frag_size; -}; - -static inline struct ethtool_mm_set_req *ethtool_mm_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_set_req)); -} -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req); - -static inline void -ethtool_mm_set_req_set_header_dev_index(struct ethtool_mm_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_set_req_set_header_dev_name(struct ethtool_mm_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_set_req_set_header_flags(struct ethtool_mm_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_mm_set_req_set_verify_enabled(struct ethtool_mm_set_req *req, - __u8 verify_enabled) -{ - req->_present.verify_enabled = 1; - req->verify_enabled = verify_enabled; -} -static inline void -ethtool_mm_set_req_set_verify_time(struct ethtool_mm_set_req *req, - __u32 verify_time) -{ - req->_present.verify_time = 1; - req->verify_time = verify_time; -} -static inline void -ethtool_mm_set_req_set_tx_enabled(struct ethtool_mm_set_req *req, - __u8 tx_enabled) -{ - req->_present.tx_enabled = 1; - req->tx_enabled = tx_enabled; -} -static inline void -ethtool_mm_set_req_set_pmac_enabled(struct ethtool_mm_set_req *req, - __u8 pmac_enabled) -{ - req->_present.pmac_enabled = 1; - req->pmac_enabled = pmac_enabled; -} -static inline void -ethtool_mm_set_req_set_tx_min_frag_size(struct ethtool_mm_set_req *req, - __u32 tx_min_frag_size) -{ - req->_present.tx_min_frag_size = 1; - req->tx_min_frag_size = tx_min_frag_size; -} - -/* - * Set MAC Merge configuration - */ -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req); - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -struct ethtool_cable_test_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - } _present; - - struct ethtool_header header; - __u8 status; -}; - -struct ethtool_cable_test_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_ntf *ntf); - struct ethtool_cable_test_ntf_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp); - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -struct ethtool_cable_test_tdr_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - __u32 nest:1; - } _present; - - struct ethtool_header header; - __u8 status; - struct ethtool_cable_nest nest; -}; - -struct ethtool_cable_test_tdr_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_tdr_ntf *ntf); - struct ethtool_cable_test_tdr_ntf_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp); - -#endif /* _LINUX_ETHTOOL_GEN_H */ diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c deleted file mode 100644 index f30bef23bc31..000000000000 --- a/tools/net/ynl/generated/fou-user.c +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "fou-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const fou_op_strmap[] = { - [FOU_CMD_ADD] = "add", - [FOU_CMD_DEL] = "del", - [FOU_CMD_GET] = "get", -}; - -const char *fou_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(fou_op_strmap)) - return NULL; - return fou_op_strmap[op]; -} - -static const char * const fou_encap_type_strmap[] = { - [0] = "unspec", - [1] = "direct", - [2] = "gue", -}; - -const char *fou_encap_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(fou_encap_type_strmap)) - return NULL; - return fou_encap_type_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = { - [FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, }, - [FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [FOU_ATTR_AF] = { .name = "af", .type = YNL_PT_U8, }, - [FOU_ATTR_IPPROTO] = { .name = "ipproto", .type = YNL_PT_U8, }, - [FOU_ATTR_TYPE] = { .name = "type", .type = YNL_PT_U8, }, - [FOU_ATTR_REMCSUM_NOPARTIAL] = { .name = "remcsum_nopartial", .type = YNL_PT_FLAG, }, - [FOU_ATTR_LOCAL_V4] = { .name = "local_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_LOCAL_V6] = { .name = "local_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_V4] = { .name = "peer_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_PEER_V6] = { .name = "peer_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_PORT] = { .name = "peer_port", .type = YNL_PT_U16, }, - [FOU_ATTR_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest fou_nest = { - .max_attr = FOU_ATTR_MAX, - .table = fou_policy, -}; - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -void fou_add_req_free(struct fou_add_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_add(struct ynl_sock *ys, struct fou_add_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_ADD, 1); - ys->req_policy = &fou_nest; - - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.ipproto) - mnl_attr_put_u8(nlh, FOU_ATTR_IPPROTO, req->ipproto); - if (req->_present.type) - mnl_attr_put_u8(nlh, FOU_ATTR_TYPE, req->type); - if (req->_present.remcsum_nopartial) - mnl_attr_put(nlh, FOU_ATTR_REMCSUM_NOPARTIAL, 0, NULL); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -void fou_del_req_free(struct fou_del_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_del(struct ynl_sock *ys, struct fou_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_DEL, 1); - ys->req_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -void fou_get_req_free(struct fou_get_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -void fou_get_rsp_free(struct fou_get_rsp *rsp) -{ - free(rsp->local_v6); - free(rsp->peer_v6); - free(rsp); -} - -int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct fou_get_rsp *dst; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == FOU_ATTR_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IPPROTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ipproto = 1; - dst->ipproto = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_REMCSUM_NOPARTIAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remcsum_nopartial = 1; - } else if (type == FOU_ATTR_LOCAL_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.local_v4 = 1; - dst->local_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_PEER_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_v4 = 1; - dst->peer_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_LOCAL_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.local_v6_len = len; - dst->local_v6 = malloc(len); - memcpy(dst->local_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.peer_v6_len = len; - dst->peer_v6 = malloc(len); - memcpy(dst->peer_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_port = 1; - dst->peer_port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct fou_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_GET, 1); - ys->req_policy = &fou_nest; - yrs.yarg.rsp_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = fou_get_rsp_parse; - yrs.rsp_cmd = FOU_CMD_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - fou_get_rsp_free(rsp); - return NULL; -} - -/* FOU_CMD_GET - dump */ -void fou_get_list_free(struct fou_get_list *rsp) -{ - struct fou_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.local_v6); - free(rsp->obj.peer_v6); - free(rsp); - } -} - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct fou_get_list); - yds.cb = fou_get_rsp_parse; - yds.rsp_cmd = FOU_CMD_GET; - yds.rsp_policy = &fou_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, FOU_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - fou_get_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_fou_family = { - .name = "fou", -}; diff --git a/tools/net/ynl/generated/fou-user.h b/tools/net/ynl/generated/fou-user.h deleted file mode 100644 index fd566716ddd6..000000000000 --- a/tools/net/ynl/generated/fou-user.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_FOU_GEN_H -#define _LINUX_FOU_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_fou_family; - -/* Enums */ -const char *fou_op_str(int op); -const char *fou_encap_type_str(int value); - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -struct fou_add_req { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -static inline struct fou_add_req *fou_add_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_add_req)); -} -void fou_add_req_free(struct fou_add_req *req); - -static inline void -fou_add_req_set_port(struct fou_add_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_add_req_set_ipproto(struct fou_add_req *req, __u8 ipproto) -{ - req->_present.ipproto = 1; - req->ipproto = ipproto; -} -static inline void fou_add_req_set_type(struct fou_add_req *req, __u8 type) -{ - req->_present.type = 1; - req->type = type; -} -static inline void fou_add_req_set_remcsum_nopartial(struct fou_add_req *req) -{ - req->_present.remcsum_nopartial = 1; -} -static inline void -fou_add_req_set_local_v4(struct fou_add_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_add_req_set_peer_v4(struct fou_add_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_add_req_set_local_v6(struct fou_add_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_add_req_set_peer_v6(struct fou_add_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} -static inline void -fou_add_req_set_peer_port(struct fou_add_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_add_req_set_ifindex(struct fou_add_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -/* - * Add port. - */ -int fou_add(struct ynl_sock *ys, struct fou_add_req *req); - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -struct fou_del_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_del_req *fou_del_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_del_req)); -} -void fou_del_req_free(struct fou_del_req *req); - -static inline void fou_del_req_set_af(struct fou_del_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_del_req_set_ifindex(struct fou_del_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_del_req_set_port(struct fou_del_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_del_req_set_peer_port(struct fou_del_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_del_req_set_local_v4(struct fou_del_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_del_req_set_peer_v4(struct fou_del_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_del_req_set_local_v6(struct fou_del_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_del_req_set_peer_v6(struct fou_del_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -/* - * Delete port. - */ -int fou_del(struct ynl_sock *ys, struct fou_del_req *req); - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -struct fou_get_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_get_req *fou_get_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_get_req)); -} -void fou_get_req_free(struct fou_get_req *req); - -static inline void fou_get_req_set_af(struct fou_get_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_get_req_set_ifindex(struct fou_get_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_get_req_set_port(struct fou_get_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_get_req_set_peer_port(struct fou_get_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_get_req_set_local_v4(struct fou_get_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_get_req_set_peer_v4(struct fou_get_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_get_req_set_local_v6(struct fou_get_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_get_req_set_peer_v6(struct fou_get_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -struct fou_get_rsp { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -void fou_get_rsp_free(struct fou_get_rsp *rsp); - -/* - * Get tunnel info. - */ -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req); - -/* FOU_CMD_GET - dump */ -struct fou_get_list { - struct fou_get_list *next; - struct fou_get_rsp obj __attribute__((aligned(8))); -}; - -void fou_get_list_free(struct fou_get_list *rsp); - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_FOU_GEN_H */ diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c deleted file mode 100644 index 6901f8462cca..000000000000 --- a/tools/net/ynl/generated/handshake-user.c +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "handshake-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const handshake_op_strmap[] = { - [HANDSHAKE_CMD_READY] = "ready", - [HANDSHAKE_CMD_ACCEPT] = "accept", - [HANDSHAKE_CMD_DONE] = "done", -}; - -const char *handshake_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(handshake_op_strmap)) - return NULL; - return handshake_op_strmap[op]; -} - -static const char * const handshake_handler_class_strmap[] = { - [0] = "none", - [1] = "tlshd", - [2] = "max", -}; - -const char *handshake_handler_class_str(enum handshake_handler_class value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_handler_class_strmap)) - return NULL; - return handshake_handler_class_strmap[value]; -} - -static const char * const handshake_msg_type_strmap[] = { - [0] = "unspec", - [1] = "clienthello", - [2] = "serverhello", -}; - -const char *handshake_msg_type_str(enum handshake_msg_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_msg_type_strmap)) - return NULL; - return handshake_msg_type_strmap[value]; -} - -static const char * const handshake_auth_strmap[] = { - [0] = "unspec", - [1] = "unauth", - [2] = "psk", - [3] = "x509", -}; - -const char *handshake_auth_str(enum handshake_auth value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_auth_strmap)) - return NULL; - return handshake_auth_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = { - [HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, }, - [HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_x509_nest = { - .max_attr = HANDSHAKE_A_X509_MAX, - .table = handshake_x509_policy, -}; - -struct ynl_policy_attr handshake_accept_policy[HANDSHAKE_A_ACCEPT_MAX + 1] = { - [HANDSHAKE_A_ACCEPT_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_HANDLER_CLASS] = { .name = "handler-class", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_MESSAGE_TYPE] = { .name = "message-type", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_TIMEOUT] = { .name = "timeout", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_AUTH_MODE] = { .name = "auth-mode", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_PEER_IDENTITY] = { .name = "peer-identity", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_CERTIFICATE] = { .name = "certificate", .type = YNL_PT_NEST, .nest = &handshake_x509_nest, }, - [HANDSHAKE_A_ACCEPT_PEERNAME] = { .name = "peername", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest handshake_accept_nest = { - .max_attr = HANDSHAKE_A_ACCEPT_MAX, - .table = handshake_accept_policy, -}; - -struct ynl_policy_attr handshake_done_policy[HANDSHAKE_A_DONE_MAX + 1] = { - [HANDSHAKE_A_DONE_STATUS] = { .name = "status", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .name = "remote-auth", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_done_nest = { - .max_attr = HANDSHAKE_A_DONE_MAX, - .table = handshake_done_policy, -}; - -/* Common nested types */ -void handshake_x509_free(struct handshake_x509 *obj) -{ -} - -int handshake_x509_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct handshake_x509 *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_X509_CERT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cert = 1; - dst->cert = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_X509_PRIVKEY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.privkey = 1; - dst->privkey = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -void handshake_accept_req_free(struct handshake_accept_req *req) -{ - free(req); -} - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp) -{ - unsigned int i; - - free(rsp->peer_identity); - for (i = 0; i < rsp->n_certificate; i++) - handshake_x509_free(&rsp->certificate[i]); - free(rsp->certificate); - free(rsp->peername); - free(rsp); -} - -int handshake_accept_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct handshake_accept_rsp *dst; - unsigned int n_peer_identity = 0; - unsigned int n_certificate = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->certificate) - return ynl_error_parse(yarg, "attribute already present (accept.certificate)"); - if (dst->peer_identity) - return ynl_error_parse(yarg, "attribute already present (accept.peer-identity)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_ACCEPT_SOCKFD) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sockfd = 1; - dst->sockfd = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.message_type = 1; - dst->message_type = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_TIMEOUT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timeout = 1; - dst->timeout = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_AUTH_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auth_mode = 1; - dst->auth_mode = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - n_peer_identity++; - } else if (type == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - n_certificate++; - } else if (type == HANDSHAKE_A_ACCEPT_PEERNAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.peername_len = len; - dst->peername = malloc(len + 1); - memcpy(dst->peername, mnl_attr_get_str(attr), len); - dst->peername[len] = 0; - } - } - - if (n_certificate) { - dst->certificate = calloc(n_certificate, sizeof(*dst->certificate)); - dst->n_certificate = n_certificate; - i = 0; - parg.rsp_policy = &handshake_x509_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - parg.data = &dst->certificate[i]; - if (handshake_x509_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_peer_identity) { - dst->peer_identity = calloc(n_peer_identity, sizeof(*dst->peer_identity)); - dst->n_peer_identity = n_peer_identity; - i = 0; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - dst->peer_identity[i] = mnl_attr_get_u32(attr); - i++; - } - } - } - - return MNL_CB_OK; -} - -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct handshake_accept_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_ACCEPT, 1); - ys->req_policy = &handshake_accept_nest; - yrs.yarg.rsp_policy = &handshake_accept_nest; - - if (req->_present.handler_class) - mnl_attr_put_u32(nlh, HANDSHAKE_A_ACCEPT_HANDLER_CLASS, req->handler_class); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = handshake_accept_rsp_parse; - yrs.rsp_cmd = HANDSHAKE_CMD_ACCEPT; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - handshake_accept_rsp_free(rsp); - return NULL; -} - -/* HANDSHAKE_CMD_ACCEPT - notify */ -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp) -{ - unsigned int i; - - free(rsp->obj.peer_identity); - for (i = 0; i < rsp->obj.n_certificate; i++) - handshake_x509_free(&rsp->obj.certificate[i]); - free(rsp->obj.certificate); - free(rsp->obj.peername); - free(rsp); -} - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -void handshake_done_req_free(struct handshake_done_req *req) -{ - free(req->remote_auth); - free(req); -} - -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_DONE, 1); - ys->req_policy = &handshake_done_nest; - - if (req->_present.status) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_STATUS, req->status); - if (req->_present.sockfd) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_SOCKFD, req->sockfd); - for (unsigned int i = 0; i < req->n_remote_auth; i++) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_REMOTE_AUTH, req->remote_auth[i]); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -static const struct ynl_ntf_info handshake_ntf_info[] = { - [HANDSHAKE_CMD_READY] = { - .alloc_sz = sizeof(struct handshake_accept_ntf), - .cb = handshake_accept_rsp_parse, - .policy = &handshake_accept_nest, - .free = (void *)handshake_accept_ntf_free, - }, -}; - -const struct ynl_family ynl_handshake_family = { - .name = "handshake", - .ntf_info = handshake_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(handshake_ntf_info), -}; diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h deleted file mode 100644 index bce537d8b8cc..000000000000 --- a/tools/net/ynl/generated/handshake-user.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_HANDSHAKE_GEN_H -#define _LINUX_HANDSHAKE_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_handshake_family; - -/* Enums */ -const char *handshake_op_str(int op); -const char *handshake_handler_class_str(enum handshake_handler_class value); -const char *handshake_msg_type_str(enum handshake_msg_type value); -const char *handshake_auth_str(enum handshake_auth value); - -/* Common nested types */ -struct handshake_x509 { - struct { - __u32 cert:1; - __u32 privkey:1; - } _present; - - __s32 cert; - __s32 privkey; -}; - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -struct handshake_accept_req { - struct { - __u32 handler_class:1; - } _present; - - enum handshake_handler_class handler_class; -}; - -static inline struct handshake_accept_req *handshake_accept_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_accept_req)); -} -void handshake_accept_req_free(struct handshake_accept_req *req); - -static inline void -handshake_accept_req_set_handler_class(struct handshake_accept_req *req, - enum handshake_handler_class handler_class) -{ - req->_present.handler_class = 1; - req->handler_class = handler_class; -} - -struct handshake_accept_rsp { - struct { - __u32 sockfd:1; - __u32 message_type:1; - __u32 timeout:1; - __u32 auth_mode:1; - __u32 peername_len; - } _present; - - __s32 sockfd; - enum handshake_msg_type message_type; - __u32 timeout; - enum handshake_auth auth_mode; - unsigned int n_peer_identity; - __u32 *peer_identity; - unsigned int n_certificate; - struct handshake_x509 *certificate; - char *peername; -}; - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp); - -/* - * Handler retrieves next queued handshake request - */ -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req); - -/* HANDSHAKE_CMD_ACCEPT - notify */ -struct handshake_accept_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct handshake_accept_ntf *ntf); - struct handshake_accept_rsp obj __attribute__((aligned(8))); -}; - -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp); - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -struct handshake_done_req { - struct { - __u32 status:1; - __u32 sockfd:1; - } _present; - - __u32 status; - __s32 sockfd; - unsigned int n_remote_auth; - __u32 *remote_auth; -}; - -static inline struct handshake_done_req *handshake_done_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_done_req)); -} -void handshake_done_req_free(struct handshake_done_req *req); - -static inline void -handshake_done_req_set_status(struct handshake_done_req *req, __u32 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -handshake_done_req_set_sockfd(struct handshake_done_req *req, __s32 sockfd) -{ - req->_present.sockfd = 1; - req->sockfd = sockfd; -} -static inline void -__handshake_done_req_set_remote_auth(struct handshake_done_req *req, - __u32 *remote_auth, - unsigned int n_remote_auth) -{ - free(req->remote_auth); - req->remote_auth = remote_auth; - req->n_remote_auth = n_remote_auth; -} - -/* - * Handler reports handshake completion - */ -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req); - -#endif /* _LINUX_HANDSHAKE_GEN_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c deleted file mode 100644 index ed8bcb855a1d..000000000000 --- a/tools/net/ynl/generated/netdev-user.c +++ /dev/null @@ -1,952 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "netdev-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const netdev_op_strmap[] = { - [NETDEV_CMD_DEV_GET] = "dev-get", - [NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf", - [NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf", - [NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf", - [NETDEV_CMD_PAGE_POOL_GET] = "page-pool-get", - [NETDEV_CMD_PAGE_POOL_ADD_NTF] = "page-pool-add-ntf", - [NETDEV_CMD_PAGE_POOL_DEL_NTF] = "page-pool-del-ntf", - [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = "page-pool-change-ntf", - [NETDEV_CMD_PAGE_POOL_STATS_GET] = "page-pool-stats-get", - [NETDEV_CMD_QUEUE_GET] = "queue-get", - [NETDEV_CMD_NAPI_GET] = "napi-get", -}; - -const char *netdev_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(netdev_op_strmap)) - return NULL; - return netdev_op_strmap[op]; -} - -static const char * const netdev_xdp_act_strmap[] = { - [0] = "basic", - [1] = "redirect", - [2] = "ndo-xmit", - [3] = "xsk-zerocopy", - [4] = "hw-offload", - [5] = "rx-sg", - [6] = "ndo-xmit-sg", -}; - -const char *netdev_xdp_act_str(enum netdev_xdp_act value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) - return NULL; - return netdev_xdp_act_strmap[value]; -} - -static const char * const netdev_xdp_rx_metadata_strmap[] = { - [0] = "timestamp", - [1] = "hash", -}; - -const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_rx_metadata_strmap)) - return NULL; - return netdev_xdp_rx_metadata_strmap[value]; -} - -static const char * const netdev_xsk_flags_strmap[] = { - [0] = "tx-timestamp", - [1] = "tx-checksum", -}; - -const char *netdev_xsk_flags_str(enum netdev_xsk_flags value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xsk_flags_strmap)) - return NULL; - return netdev_xsk_flags_strmap[value]; -} - -static const char * const netdev_queue_type_strmap[] = { - [0] = "rx", - [1] = "tx", -}; - -const char *netdev_queue_type_str(enum netdev_queue_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_queue_type_strmap)) - return NULL; - return netdev_queue_type_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr netdev_page_pool_info_policy[NETDEV_A_PAGE_POOL_MAX + 1] = { - [NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest netdev_page_pool_info_nest = { - .max_attr = NETDEV_A_PAGE_POOL_MAX, - .table = netdev_page_pool_info_policy, -}; - -struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { - [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [NETDEV_A_DEV_XDP_FEATURES] = { .name = "xdp-features", .type = YNL_PT_U64, }, - [NETDEV_A_DEV_XDP_ZC_MAX_SEGS] = { .name = "xdp-zc-max-segs", .type = YNL_PT_U32, }, - [NETDEV_A_DEV_XDP_RX_METADATA_FEATURES] = { .name = "xdp-rx-metadata-features", .type = YNL_PT_U64, }, - [NETDEV_A_DEV_XSK_FEATURES] = { .name = "xsk-features", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest netdev_dev_nest = { - .max_attr = NETDEV_A_DEV_MAX, - .table = netdev_dev_policy, -}; - -struct ynl_policy_attr netdev_page_pool_policy[NETDEV_A_PAGE_POOL_MAX + 1] = { - [NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_PAGE_POOL_NAPI_ID] = { .name = "napi-id", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_INFLIGHT] = { .name = "inflight", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_INFLIGHT_MEM] = { .name = "inflight-mem", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_DETACH_TIME] = { .name = "detach-time", .type = YNL_PT_UINT, }, -}; - -struct ynl_policy_nest netdev_page_pool_nest = { - .max_attr = NETDEV_A_PAGE_POOL_MAX, - .table = netdev_page_pool_policy, -}; - -struct ynl_policy_attr netdev_page_pool_stats_policy[NETDEV_A_PAGE_POOL_STATS_MAX + 1] = { - [NETDEV_A_PAGE_POOL_STATS_INFO] = { .name = "info", .type = YNL_PT_NEST, .nest = &netdev_page_pool_info_nest, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST] = { .name = "alloc-fast", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW] = { .name = "alloc-slow", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER] = { .name = "alloc-slow-high-order", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY] = { .name = "alloc-empty", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL] = { .name = "alloc-refill", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE] = { .name = "alloc-waive", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED] = { .name = "recycle-cached", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL] = { .name = "recycle-cache-full", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING] = { .name = "recycle-ring", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL] = { .name = "recycle-ring-full", .type = YNL_PT_UINT, }, - [NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT] = { .name = "recycle-released-refcnt", .type = YNL_PT_UINT, }, -}; - -struct ynl_policy_nest netdev_page_pool_stats_nest = { - .max_attr = NETDEV_A_PAGE_POOL_STATS_MAX, - .table = netdev_page_pool_stats_policy, -}; - -struct ynl_policy_attr netdev_queue_policy[NETDEV_A_QUEUE_MAX + 1] = { - [NETDEV_A_QUEUE_ID] = { .name = "id", .type = YNL_PT_U32, }, - [NETDEV_A_QUEUE_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_QUEUE_TYPE] = { .name = "type", .type = YNL_PT_U32, }, - [NETDEV_A_QUEUE_NAPI_ID] = { .name = "napi-id", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest netdev_queue_nest = { - .max_attr = NETDEV_A_QUEUE_MAX, - .table = netdev_queue_policy, -}; - -struct ynl_policy_attr netdev_napi_policy[NETDEV_A_NAPI_MAX + 1] = { - [NETDEV_A_NAPI_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_NAPI_ID] = { .name = "id", .type = YNL_PT_U32, }, - [NETDEV_A_NAPI_IRQ] = { .name = "irq", .type = YNL_PT_U32, }, - [NETDEV_A_NAPI_PID] = { .name = "pid", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest netdev_napi_nest = { - .max_attr = NETDEV_A_NAPI_MAX, - .table = netdev_napi_policy, -}; - -/* Common nested types */ -void netdev_page_pool_info_free(struct netdev_page_pool_info *obj) -{ -} - -int netdev_page_pool_info_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct netdev_page_pool_info *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.id) - mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, obj->id); - if (obj->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_PAGE_POOL_IFINDEX, obj->ifindex); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int netdev_page_pool_info_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct netdev_page_pool_info *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_PAGE_POOL_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_NAPI_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.irq = 1; - dst->irq = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_NAPI_PID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pid = 1; - dst->pid = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -void netdev_dev_get_req_free(struct netdev_dev_get_req *req) -{ - free(req); -} - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct netdev_dev_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_DEV_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_DEV_XDP_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_features = 1; - dst->xdp_features = mnl_attr_get_u64(attr); - } else if (type == NETDEV_A_DEV_XDP_ZC_MAX_SEGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_zc_max_segs = 1; - dst->xdp_zc_max_segs = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_DEV_XDP_RX_METADATA_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_rx_metadata_features = 1; - dst->xdp_rx_metadata_features = mnl_attr_get_u64(attr); - } else if (type == NETDEV_A_DEV_XSK_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xsk_features = 1; - dst->xsk_features = mnl_attr_get_u64(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_dev_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - ys->req_policy = &netdev_dev_nest; - yrs.yarg.rsp_policy = &netdev_dev_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_DEV_IFINDEX, req->ifindex); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_dev_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_DEV_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_dev_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - dump */ -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp) -{ - struct netdev_dev_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_dev_get_list); - yds.cb = netdev_dev_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_DEV_GET; - yds.rsp_policy = &netdev_dev_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_dev_get_list_free(yds.first); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - notify */ -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) -{ - free(rsp); -} - -/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */ -/* NETDEV_CMD_PAGE_POOL_GET - do */ -void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req) -{ - free(req); -} - -void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_page_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct netdev_page_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_PAGE_POOL_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_PAGE_POOL_NAPI_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.napi_id = 1; - dst->napi_id = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_INFLIGHT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.inflight = 1; - dst->inflight = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_INFLIGHT_MEM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.inflight_mem = 1; - dst->inflight_mem = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_DETACH_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.detach_time = 1; - dst->detach_time = mnl_attr_get_uint(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_page_pool_get_rsp * -netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_page_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1); - ys->req_policy = &netdev_page_pool_nest; - yrs.yarg.rsp_policy = &netdev_page_pool_nest; - - if (req->_present.id) - mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, req->id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_page_pool_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_page_pool_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_PAGE_POOL_GET - dump */ -void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp) -{ - struct netdev_page_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_page_pool_get_list * -netdev_page_pool_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_page_pool_get_list); - yds.cb = netdev_page_pool_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET; - yds.rsp_policy = &netdev_page_pool_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_page_pool_get_list_free(yds.first); - return NULL; -} - -/* NETDEV_CMD_PAGE_POOL_GET - notify */ -void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp) -{ - free(rsp); -} - -/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */ -/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ -void -netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req) -{ - netdev_page_pool_info_free(&req->info); - free(req); -} - -void -netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp) -{ - netdev_page_pool_info_free(&rsp->info); - free(rsp); -} - -int netdev_page_pool_stats_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct netdev_page_pool_stats_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_PAGE_POOL_STATS_INFO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.info = 1; - - parg.rsp_policy = &netdev_page_pool_info_nest; - parg.data = &dst->info; - if (netdev_page_pool_info_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_fast = 1; - dst->alloc_fast = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_slow = 1; - dst->alloc_slow = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_slow_high_order = 1; - dst->alloc_slow_high_order = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_empty = 1; - dst->alloc_empty = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_refill = 1; - dst->alloc_refill = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.alloc_waive = 1; - dst->alloc_waive = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.recycle_cached = 1; - dst->recycle_cached = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.recycle_cache_full = 1; - dst->recycle_cache_full = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.recycle_ring = 1; - dst->recycle_ring = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.recycle_ring_full = 1; - dst->recycle_ring_full = mnl_attr_get_uint(attr); - } else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.recycle_released_refcnt = 1; - dst->recycle_released_refcnt = mnl_attr_get_uint(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_page_pool_stats_get_rsp * -netdev_page_pool_stats_get(struct ynl_sock *ys, - struct netdev_page_pool_stats_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_page_pool_stats_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1); - ys->req_policy = &netdev_page_pool_stats_nest; - yrs.yarg.rsp_policy = &netdev_page_pool_stats_nest; - - if (req->_present.info) - netdev_page_pool_info_put(nlh, NETDEV_A_PAGE_POOL_STATS_INFO, &req->info); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_page_pool_stats_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_page_pool_stats_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */ -void -netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp) -{ - struct netdev_page_pool_stats_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - netdev_page_pool_info_free(&rsp->obj.info); - free(rsp); - } -} - -struct netdev_page_pool_stats_get_list * -netdev_page_pool_stats_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_page_pool_stats_get_list); - yds.cb = netdev_page_pool_stats_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET; - yds.rsp_policy = &netdev_page_pool_stats_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_page_pool_stats_get_list_free(yds.first); - return NULL; -} - -/* ============== NETDEV_CMD_QUEUE_GET ============== */ -/* NETDEV_CMD_QUEUE_GET - do */ -void netdev_queue_get_req_free(struct netdev_queue_get_req *req) -{ - free(req); -} - -void netdev_queue_get_rsp_free(struct netdev_queue_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_queue_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct netdev_queue_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_QUEUE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_QUEUE_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_QUEUE_NAPI_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.napi_id = 1; - dst->napi_id = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_QUEUE_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_queue_get_rsp * -netdev_queue_get(struct ynl_sock *ys, struct netdev_queue_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_queue_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_QUEUE_GET, 1); - ys->req_policy = &netdev_queue_nest; - yrs.yarg.rsp_policy = &netdev_queue_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_IFINDEX, req->ifindex); - if (req->_present.type) - mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_TYPE, req->type); - if (req->_present.id) - mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_ID, req->id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_queue_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_QUEUE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_queue_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_QUEUE_GET - dump */ -void netdev_queue_get_list_free(struct netdev_queue_get_list *rsp) -{ - struct netdev_queue_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_queue_get_list * -netdev_queue_get_dump(struct ynl_sock *ys, - struct netdev_queue_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_queue_get_list); - yds.cb = netdev_queue_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_QUEUE_GET; - yds.rsp_policy = &netdev_queue_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_QUEUE_GET, 1); - ys->req_policy = &netdev_queue_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_QUEUE_IFINDEX, req->ifindex); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_queue_get_list_free(yds.first); - return NULL; -} - -/* ============== NETDEV_CMD_NAPI_GET ============== */ -/* NETDEV_CMD_NAPI_GET - do */ -void netdev_napi_get_req_free(struct netdev_napi_get_req *req) -{ - free(req); -} - -void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_napi_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct netdev_napi_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_NAPI_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_NAPI_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_napi_get_rsp * -netdev_napi_get(struct ynl_sock *ys, struct netdev_napi_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_napi_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_NAPI_GET, 1); - ys->req_policy = &netdev_napi_nest; - yrs.yarg.rsp_policy = &netdev_napi_nest; - - if (req->_present.id) - mnl_attr_put_u32(nlh, NETDEV_A_NAPI_ID, req->id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_napi_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_NAPI_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_napi_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_NAPI_GET - dump */ -void netdev_napi_get_list_free(struct netdev_napi_get_list *rsp) -{ - struct netdev_napi_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_napi_get_list * -netdev_napi_get_dump(struct ynl_sock *ys, struct netdev_napi_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_napi_get_list); - yds.cb = netdev_napi_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_NAPI_GET; - yds.rsp_policy = &netdev_napi_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_NAPI_GET, 1); - ys->req_policy = &netdev_napi_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_NAPI_IFINDEX, req->ifindex); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_napi_get_list_free(yds.first); - return NULL; -} - -static const struct ynl_ntf_info netdev_ntf_info[] = { - [NETDEV_CMD_DEV_ADD_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_DEL_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_CHANGE_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_PAGE_POOL_ADD_NTF] = { - .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), - .cb = netdev_page_pool_get_rsp_parse, - .policy = &netdev_page_pool_nest, - .free = (void *)netdev_page_pool_get_ntf_free, - }, - [NETDEV_CMD_PAGE_POOL_DEL_NTF] = { - .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), - .cb = netdev_page_pool_get_rsp_parse, - .policy = &netdev_page_pool_nest, - .free = (void *)netdev_page_pool_get_ntf_free, - }, - [NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = { - .alloc_sz = sizeof(struct netdev_page_pool_get_ntf), - .cb = netdev_page_pool_get_rsp_parse, - .policy = &netdev_page_pool_nest, - .free = (void *)netdev_page_pool_get_ntf_free, - }, -}; - -const struct ynl_family ynl_netdev_family = { - .name = "netdev", - .ntf_info = netdev_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(netdev_ntf_info), -}; diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h deleted file mode 100644 index 3830cf2ab6b8..000000000000 --- a/tools/net/ynl/generated/netdev-user.h +++ /dev/null @@ -1,442 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_NETDEV_GEN_H -#define _LINUX_NETDEV_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_netdev_family; - -/* Enums */ -const char *netdev_op_str(int op); -const char *netdev_xdp_act_str(enum netdev_xdp_act value); -const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); -const char *netdev_xsk_flags_str(enum netdev_xsk_flags value); -const char *netdev_queue_type_str(enum netdev_queue_type value); - -/* Common nested types */ -struct netdev_page_pool_info { - struct { - __u32 id:1; - __u32 ifindex:1; - } _present; - - __u64 id; - __u32 ifindex; -}; - -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -struct netdev_dev_get_req { - struct { - __u32 ifindex:1; - } _present; - - __u32 ifindex; -}; - -static inline struct netdev_dev_get_req *netdev_dev_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_dev_get_req)); -} -void netdev_dev_get_req_free(struct netdev_dev_get_req *req); - -static inline void -netdev_dev_get_req_set_ifindex(struct netdev_dev_get_req *req, __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -struct netdev_dev_get_rsp { - struct { - __u32 ifindex:1; - __u32 xdp_features:1; - __u32 xdp_zc_max_segs:1; - __u32 xdp_rx_metadata_features:1; - __u32 xsk_features:1; - } _present; - - __u32 ifindex; - __u64 xdp_features; - __u32 xdp_zc_max_segs; - __u64 xdp_rx_metadata_features; - __u64 xsk_features; -}; - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp); - -/* - * Get / dump information about a netdev. - */ -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req); - -/* NETDEV_CMD_DEV_GET - dump */ -struct netdev_dev_get_list { - struct netdev_dev_get_list *next; - struct netdev_dev_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp); - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys); - -/* NETDEV_CMD_DEV_GET - notify */ -struct netdev_dev_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct netdev_dev_get_ntf *ntf); - struct netdev_dev_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); - -/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */ -/* NETDEV_CMD_PAGE_POOL_GET - do */ -struct netdev_page_pool_get_req { - struct { - __u32 id:1; - } _present; - - __u64 id; -}; - -static inline struct netdev_page_pool_get_req * -netdev_page_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_page_pool_get_req)); -} -void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req); - -static inline void -netdev_page_pool_get_req_set_id(struct netdev_page_pool_get_req *req, __u64 id) -{ - req->_present.id = 1; - req->id = id; -} - -struct netdev_page_pool_get_rsp { - struct { - __u32 id:1; - __u32 ifindex:1; - __u32 napi_id:1; - __u32 inflight:1; - __u32 inflight_mem:1; - __u32 detach_time:1; - } _present; - - __u64 id; - __u32 ifindex; - __u64 napi_id; - __u64 inflight; - __u64 inflight_mem; - __u64 detach_time; -}; - -void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp); - -/* - * Get / dump information about Page Pools. -(Only Page Pools associated with a net_device can be listed.) - - */ -struct netdev_page_pool_get_rsp * -netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req); - -/* NETDEV_CMD_PAGE_POOL_GET - dump */ -struct netdev_page_pool_get_list { - struct netdev_page_pool_get_list *next; - struct netdev_page_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp); - -struct netdev_page_pool_get_list * -netdev_page_pool_get_dump(struct ynl_sock *ys); - -/* NETDEV_CMD_PAGE_POOL_GET - notify */ -struct netdev_page_pool_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct netdev_page_pool_get_ntf *ntf); - struct netdev_page_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp); - -/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */ -/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ -struct netdev_page_pool_stats_get_req { - struct { - __u32 info:1; - } _present; - - struct netdev_page_pool_info info; -}; - -static inline struct netdev_page_pool_stats_get_req * -netdev_page_pool_stats_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_page_pool_stats_get_req)); -} -void -netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req); - -static inline void -netdev_page_pool_stats_get_req_set_info_id(struct netdev_page_pool_stats_get_req *req, - __u64 id) -{ - req->_present.info = 1; - req->info._present.id = 1; - req->info.id = id; -} -static inline void -netdev_page_pool_stats_get_req_set_info_ifindex(struct netdev_page_pool_stats_get_req *req, - __u32 ifindex) -{ - req->_present.info = 1; - req->info._present.ifindex = 1; - req->info.ifindex = ifindex; -} - -struct netdev_page_pool_stats_get_rsp { - struct { - __u32 info:1; - __u32 alloc_fast:1; - __u32 alloc_slow:1; - __u32 alloc_slow_high_order:1; - __u32 alloc_empty:1; - __u32 alloc_refill:1; - __u32 alloc_waive:1; - __u32 recycle_cached:1; - __u32 recycle_cache_full:1; - __u32 recycle_ring:1; - __u32 recycle_ring_full:1; - __u32 recycle_released_refcnt:1; - } _present; - - struct netdev_page_pool_info info; - __u64 alloc_fast; - __u64 alloc_slow; - __u64 alloc_slow_high_order; - __u64 alloc_empty; - __u64 alloc_refill; - __u64 alloc_waive; - __u64 recycle_cached; - __u64 recycle_cache_full; - __u64 recycle_ring; - __u64 recycle_ring_full; - __u64 recycle_released_refcnt; -}; - -void -netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp); - -/* - * Get page pool statistics. - */ -struct netdev_page_pool_stats_get_rsp * -netdev_page_pool_stats_get(struct ynl_sock *ys, - struct netdev_page_pool_stats_get_req *req); - -/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */ -struct netdev_page_pool_stats_get_list { - struct netdev_page_pool_stats_get_list *next; - struct netdev_page_pool_stats_get_rsp obj __attribute__((aligned(8))); -}; - -void -netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp); - -struct netdev_page_pool_stats_get_list * -netdev_page_pool_stats_get_dump(struct ynl_sock *ys); - -/* ============== NETDEV_CMD_QUEUE_GET ============== */ -/* NETDEV_CMD_QUEUE_GET - do */ -struct netdev_queue_get_req { - struct { - __u32 ifindex:1; - __u32 type:1; - __u32 id:1; - } _present; - - __u32 ifindex; - enum netdev_queue_type type; - __u32 id; -}; - -static inline struct netdev_queue_get_req *netdev_queue_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_queue_get_req)); -} -void netdev_queue_get_req_free(struct netdev_queue_get_req *req); - -static inline void -netdev_queue_get_req_set_ifindex(struct netdev_queue_get_req *req, - __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -netdev_queue_get_req_set_type(struct netdev_queue_get_req *req, - enum netdev_queue_type type) -{ - req->_present.type = 1; - req->type = type; -} -static inline void -netdev_queue_get_req_set_id(struct netdev_queue_get_req *req, __u32 id) -{ - req->_present.id = 1; - req->id = id; -} - -struct netdev_queue_get_rsp { - struct { - __u32 id:1; - __u32 type:1; - __u32 napi_id:1; - __u32 ifindex:1; - } _present; - - __u32 id; - enum netdev_queue_type type; - __u32 napi_id; - __u32 ifindex; -}; - -void netdev_queue_get_rsp_free(struct netdev_queue_get_rsp *rsp); - -/* - * Get queue information from the kernel. Only configured queues will be reported (as opposed to all available hardware queues). - */ -struct netdev_queue_get_rsp * -netdev_queue_get(struct ynl_sock *ys, struct netdev_queue_get_req *req); - -/* NETDEV_CMD_QUEUE_GET - dump */ -struct netdev_queue_get_req_dump { - struct { - __u32 ifindex:1; - } _present; - - __u32 ifindex; -}; - -static inline struct netdev_queue_get_req_dump * -netdev_queue_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct netdev_queue_get_req_dump)); -} -void netdev_queue_get_req_dump_free(struct netdev_queue_get_req_dump *req); - -static inline void -netdev_queue_get_req_dump_set_ifindex(struct netdev_queue_get_req_dump *req, - __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -struct netdev_queue_get_list { - struct netdev_queue_get_list *next; - struct netdev_queue_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_queue_get_list_free(struct netdev_queue_get_list *rsp); - -struct netdev_queue_get_list * -netdev_queue_get_dump(struct ynl_sock *ys, - struct netdev_queue_get_req_dump *req); - -/* ============== NETDEV_CMD_NAPI_GET ============== */ -/* NETDEV_CMD_NAPI_GET - do */ -struct netdev_napi_get_req { - struct { - __u32 id:1; - } _present; - - __u32 id; -}; - -static inline struct netdev_napi_get_req *netdev_napi_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_napi_get_req)); -} -void netdev_napi_get_req_free(struct netdev_napi_get_req *req); - -static inline void -netdev_napi_get_req_set_id(struct netdev_napi_get_req *req, __u32 id) -{ - req->_present.id = 1; - req->id = id; -} - -struct netdev_napi_get_rsp { - struct { - __u32 id:1; - __u32 ifindex:1; - __u32 irq:1; - __u32 pid:1; - } _present; - - __u32 id; - __u32 ifindex; - __u32 irq; - __u32 pid; -}; - -void netdev_napi_get_rsp_free(struct netdev_napi_get_rsp *rsp); - -/* - * Get information about NAPI instances configured on the system. - */ -struct netdev_napi_get_rsp * -netdev_napi_get(struct ynl_sock *ys, struct netdev_napi_get_req *req); - -/* NETDEV_CMD_NAPI_GET - dump */ -struct netdev_napi_get_req_dump { - struct { - __u32 ifindex:1; - } _present; - - __u32 ifindex; -}; - -static inline struct netdev_napi_get_req_dump * -netdev_napi_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct netdev_napi_get_req_dump)); -} -void netdev_napi_get_req_dump_free(struct netdev_napi_get_req_dump *req); - -static inline void -netdev_napi_get_req_dump_set_ifindex(struct netdev_napi_get_req_dump *req, - __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -struct netdev_napi_get_list { - struct netdev_napi_get_list *next; - struct netdev_napi_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_napi_get_list_free(struct netdev_napi_get_list *rsp); - -struct netdev_napi_get_list * -netdev_napi_get_dump(struct ynl_sock *ys, struct netdev_napi_get_req_dump *req); - -#endif /* _LINUX_NETDEV_GEN_H */ diff --git a/tools/net/ynl/generated/nfsd-user.c b/tools/net/ynl/generated/nfsd-user.c deleted file mode 100644 index 360b6448c6e9..000000000000 --- a/tools/net/ynl/generated/nfsd-user.c +++ /dev/null @@ -1,203 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/nfsd.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "nfsd-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const nfsd_op_strmap[] = { - [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", -}; - -const char *nfsd_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(nfsd_op_strmap)) - return NULL; - return nfsd_op_strmap[op]; -} - -/* Policies */ -struct ynl_policy_attr nfsd_rpc_status_policy[NFSD_A_RPC_STATUS_MAX + 1] = { - [NFSD_A_RPC_STATUS_XID] = { .name = "xid", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_PROG] = { .name = "prog", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_VERSION] = { .name = "version", .type = YNL_PT_U8, }, - [NFSD_A_RPC_STATUS_PROC] = { .name = "proc", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_SERVICE_TIME] = { .name = "service_time", .type = YNL_PT_U64, }, - [NFSD_A_RPC_STATUS_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [NFSD_A_RPC_STATUS_SADDR4] = { .name = "saddr4", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_DADDR4] = { .name = "daddr4", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_SADDR6] = { .name = "saddr6", .type = YNL_PT_BINARY,}, - [NFSD_A_RPC_STATUS_DADDR6] = { .name = "daddr6", .type = YNL_PT_BINARY,}, - [NFSD_A_RPC_STATUS_SPORT] = { .name = "sport", .type = YNL_PT_U16, }, - [NFSD_A_RPC_STATUS_DPORT] = { .name = "dport", .type = YNL_PT_U16, }, - [NFSD_A_RPC_STATUS_COMPOUND_OPS] = { .name = "compound-ops", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest nfsd_rpc_status_nest = { - .max_attr = NFSD_A_RPC_STATUS_MAX, - .table = nfsd_rpc_status_policy, -}; - -/* Common nested types */ -/* ============== NFSD_CMD_RPC_STATUS_GET ============== */ -/* NFSD_CMD_RPC_STATUS_GET - dump */ -int nfsd_rpc_status_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct nfsd_rpc_status_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - unsigned int n_compound_ops = 0; - const struct nlattr *attr; - int i; - - dst = yarg->data; - - if (dst->compound_ops) - return ynl_error_parse(yarg, "attribute already present (rpc-status.compound-ops)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NFSD_A_RPC_STATUS_XID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xid = 1; - dst->xid = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - dst->flags = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_PROG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.prog = 1; - dst->prog = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u8(attr); - } else if (type == NFSD_A_RPC_STATUS_PROC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.proc = 1; - dst->proc = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_SERVICE_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.service_time = 1; - dst->service_time = mnl_attr_get_u64(attr); - } else if (type == NFSD_A_RPC_STATUS_SADDR4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.saddr4 = 1; - dst->saddr4 = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_DADDR4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.daddr4 = 1; - dst->daddr4 = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_SADDR6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.saddr6_len = len; - dst->saddr6 = malloc(len); - memcpy(dst->saddr6, mnl_attr_get_payload(attr), len); - } else if (type == NFSD_A_RPC_STATUS_DADDR6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.daddr6_len = len; - dst->daddr6 = malloc(len); - memcpy(dst->daddr6, mnl_attr_get_payload(attr), len); - } else if (type == NFSD_A_RPC_STATUS_SPORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sport = 1; - dst->sport = mnl_attr_get_u16(attr); - } else if (type == NFSD_A_RPC_STATUS_DPORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dport = 1; - dst->dport = mnl_attr_get_u16(attr); - } else if (type == NFSD_A_RPC_STATUS_COMPOUND_OPS) { - n_compound_ops++; - } - } - - if (n_compound_ops) { - dst->compound_ops = calloc(n_compound_ops, sizeof(*dst->compound_ops)); - dst->n_compound_ops = n_compound_ops; - i = 0; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == NFSD_A_RPC_STATUS_COMPOUND_OPS) { - dst->compound_ops[i] = mnl_attr_get_u32(attr); - i++; - } - } - } - - return MNL_CB_OK; -} - -void -nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp) -{ - struct nfsd_rpc_status_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.saddr6); - free(rsp->obj.daddr6); - free(rsp->obj.compound_ops); - free(rsp); - } -} - -struct nfsd_rpc_status_get_rsp_list * -nfsd_rpc_status_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct nfsd_rpc_status_get_rsp_list); - yds.cb = nfsd_rpc_status_get_rsp_dump_parse; - yds.rsp_cmd = NFSD_CMD_RPC_STATUS_GET; - yds.rsp_policy = &nfsd_rpc_status_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NFSD_CMD_RPC_STATUS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - nfsd_rpc_status_get_rsp_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_nfsd_family = { - .name = "nfsd", -}; diff --git a/tools/net/ynl/generated/nfsd-user.h b/tools/net/ynl/generated/nfsd-user.h deleted file mode 100644 index 989c6e209ced..000000000000 --- a/tools/net/ynl/generated/nfsd-user.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/nfsd.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_NFSD_GEN_H -#define _LINUX_NFSD_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_nfsd_family; - -/* Enums */ -const char *nfsd_op_str(int op); - -/* Common nested types */ -/* ============== NFSD_CMD_RPC_STATUS_GET ============== */ -/* NFSD_CMD_RPC_STATUS_GET - dump */ -struct nfsd_rpc_status_get_rsp_dump { - struct { - __u32 xid:1; - __u32 flags:1; - __u32 prog:1; - __u32 version:1; - __u32 proc:1; - __u32 service_time:1; - __u32 saddr4:1; - __u32 daddr4:1; - __u32 saddr6_len; - __u32 daddr6_len; - __u32 sport:1; - __u32 dport:1; - } _present; - - __u32 xid /* big-endian */; - __u32 flags; - __u32 prog; - __u8 version; - __u32 proc; - __s64 service_time; - __u32 saddr4 /* big-endian */; - __u32 daddr4 /* big-endian */; - void *saddr6; - void *daddr6; - __u16 sport /* big-endian */; - __u16 dport /* big-endian */; - unsigned int n_compound_ops; - __u32 *compound_ops; -}; - -struct nfsd_rpc_status_get_rsp_list { - struct nfsd_rpc_status_get_rsp_list *next; - struct nfsd_rpc_status_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void -nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp); - -struct nfsd_rpc_status_get_rsp_list * -nfsd_rpc_status_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_NFSD_GEN_H */ From 134c78c962279e423f5d699e3d3b379cbf4885c8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:33 +0300 Subject: [PATCH 2602/7721] drm/msm/dpu: cleanup dpu_kms_hw_init error path It was noticed that dpu_kms_hw_init()'s error path contains several labels which point to the same code path. Replace all of them with a single label. Suggested-by: Konrad Dybcio Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570035/ Link: https://lore.kernel.org/r/20231201211845.1026967-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index c1cb500adc07..cc6e2c05e794 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1063,7 +1063,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) if (!dpu_kms->catalog) { DPU_ERROR("device config not known!\n"); rc = -EINVAL; - goto power_error; + goto err_pm_put; } /* @@ -1073,26 +1073,26 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_mmu_init(dpu_kms); if (rc) { DPU_ERROR("dpu_kms_mmu_init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } dpu_kms->mdss = msm_mdss_get_mdss_data(dpu_kms->pdev->dev.parent); if (IS_ERR(dpu_kms->mdss)) { rc = PTR_ERR(dpu_kms->mdss); DPU_ERROR("failed to get MDSS data: %d\n", rc); - goto power_error; + goto err_pm_put; } if (!dpu_kms->mdss) { rc = -EINVAL; DPU_ERROR("NULL MDSS data\n"); - goto power_error; + goto err_pm_put; } rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); if (rc) { DPU_ERROR("rm init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } dpu_kms->rm_init = true; @@ -1104,7 +1104,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = PTR_ERR(dpu_kms->hw_mdp); DPU_ERROR("failed to get hw_mdp: %d\n", rc); dpu_kms->hw_mdp = NULL; - goto power_error; + goto err_pm_put; } for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { @@ -1115,7 +1115,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc); - goto power_error; + goto err_pm_put; } dpu_kms->hw_vbif[vbif->id] = hw; @@ -1131,7 +1131,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = dpu_core_perf_init(&dpu_kms->perf, dpu_kms->catalog->perf, max_core_clk_rate); if (rc) { DPU_ERROR("failed to init perf %d\n", rc); - goto perf_err; + goto err_pm_put; } dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); @@ -1139,7 +1139,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = PTR_ERR(dpu_kms->hw_intr); DPU_ERROR("hw_intr init failed: %d\n", rc); dpu_kms->hw_intr = NULL; - goto hw_intr_init_err; + goto err_pm_put; } dev->mode_config.min_width = 0; @@ -1164,7 +1164,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_drm_obj_init(dpu_kms); if (rc) { DPU_ERROR("modeset init failed: %d\n", rc); - goto drm_obj_init_err; + goto err_pm_put; } dpu_vbif_init_memtypes(dpu_kms); @@ -1173,10 +1173,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) return 0; -drm_obj_init_err: -hw_intr_init_err: -perf_err: -power_error: +err_pm_put: pm_runtime_put_sync(&dpu_kms->pdev->dev); error: _dpu_kms_hw_destroy(dpu_kms); From b830b06f008755526646bb1d12500c8ccd8be335 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:34 +0300 Subject: [PATCH 2603/7721] drm/msm/dpu: remove IS_ERR_OR_NULL for dpu_hw_intr_init() error handling Using IS_ERR_OR_NULL() together with PTR_ERR() is a typical mistake. If the value is NULL, then the function will return 0 instead of a proper return code. Replace IS_ERR_OR_NULL() with IS_ERR() in the dpu_hw_intr_init() error check. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570036/ Link: https://lore.kernel.org/r/20231201211845.1026967-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index cc6e2c05e794..75663f162618 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1135,7 +1135,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) } dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); - if (IS_ERR_OR_NULL(dpu_kms->hw_intr)) { + if (IS_ERR(dpu_kms->hw_intr)) { rc = PTR_ERR(dpu_kms->hw_intr); DPU_ERROR("hw_intr init failed: %d\n", rc); dpu_kms->hw_intr = NULL; From b19e6f7dd2e7cc47bed565064fd7ff52f9424e52 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:35 +0300 Subject: [PATCH 2604/7721] drm/msm/dpu: use devres-managed allocation for interrupts data Use devm_kzalloc to create interrupts data structure. This allows us to remove corresponding kfree and drop dpu_hw_intr_destroy() function. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570038/ Link: https://lore.kernel.org/r/20231201211845.1026967-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 14 ++++++-------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 11 ++++------- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 +--- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 088807db2c83..946dd0135dff 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -6,6 +6,8 @@ #include #include +#include + #include "dpu_core_irq.h" #include "dpu_kms.h" #include "dpu_hw_interrupts.h" @@ -472,8 +474,9 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, return intr_status; } -struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, - const struct dpu_mdss_cfg *m) +struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, + void __iomem *addr, + const struct dpu_mdss_cfg *m) { struct dpu_hw_intr *intr; unsigned int i; @@ -481,7 +484,7 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, if (!addr || !m) return ERR_PTR(-EINVAL); - intr = kzalloc(sizeof(*intr), GFP_KERNEL); + intr = drmm_kzalloc(dev, sizeof(*intr), GFP_KERNEL); if (!intr) return ERR_PTR(-ENOMEM); @@ -512,11 +515,6 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, return intr; } -void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) -{ - kfree(intr); -} - int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, unsigned int irq_idx, void (*irq_cb)(void *arg), diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index 53a21ebc57e8..564b750a28fe 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -70,15 +70,12 @@ struct dpu_hw_intr { /** * dpu_hw_intr_init(): Initializes the interrupts hw object + * @dev: Corresponding device for devres management * @addr: mapped register io address of MDP * @m: pointer to MDSS catalog data */ -struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, - const struct dpu_mdss_cfg *m); +struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, + void __iomem *addr, + const struct dpu_mdss_cfg *m); -/** - * dpu_hw_intr_destroy(): Cleanup interrutps hw object - * @intr: pointer to interrupts hw object - */ -void dpu_hw_intr_destroy(struct dpu_hw_intr *intr); #endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 75663f162618..34d707db1d0c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -795,8 +795,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) { int i; - if (dpu_kms->hw_intr) - dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; /* safe to call these more than once during shutdown */ @@ -1134,7 +1132,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) goto err_pm_put; } - dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); + dpu_kms->hw_intr = dpu_hw_intr_init(dev, dpu_kms->mmio, dpu_kms->catalog); if (IS_ERR(dpu_kms->hw_intr)) { rc = PTR_ERR(dpu_kms->hw_intr); DPU_ERROR("hw_intr init failed: %d\n", rc); From bdfa47d9b17a2335666a741a98857f9e5e482dc8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:36 +0300 Subject: [PATCH 2605/7721] drm/msm/dpu: use devres-managed allocation for VBIF data Use devm_kzalloc to create VBIF data structure. This allows us to remove corresponding kfree and drop dpu_hw_vbif_destroy() function. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570040/ Link: https://lore.kernel.org/r/20231201211845.1026967-5-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c | 14 ++++++-------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h | 8 ++++---- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 11 +++-------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c index a5121a50b2bb..98e34afde2d2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_vbif.h" @@ -211,12 +213,13 @@ static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops, ops->set_write_gather_en = dpu_hw_set_write_gather_en; } -struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, - void __iomem *addr) +struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, + const struct dpu_vbif_cfg *cfg, + void __iomem *addr) { struct dpu_hw_vbif *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -234,8 +237,3 @@ struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, return c; } - -void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif) -{ - kfree(vbif); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 7e10d2a172b4..e2b4307500e4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -108,12 +108,12 @@ struct dpu_hw_vbif { /** * dpu_hw_vbif_init() - Initializes the VBIF driver for the passed * VBIF catalog entry. + * @dev: Corresponding device for devres management * @cfg: VBIF catalog entry for which driver object is required * @addr: Mapped register io address of MDSS */ -struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, - void __iomem *addr); - -void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif); +struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, + const struct dpu_vbif_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_VBIF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 34d707db1d0c..a1753c54aaac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -800,13 +800,8 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) /* safe to call these more than once during shutdown */ _dpu_kms_mmu_destroy(dpu_kms); - if (dpu_kms->catalog) { - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - if (dpu_kms->hw_vbif[i]) { - dpu_hw_vbif_destroy(dpu_kms->hw_vbif[i]); - dpu_kms->hw_vbif[i] = NULL; - } - } + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + dpu_kms->hw_vbif[i] = NULL; } if (dpu_kms->rm_init) @@ -1109,7 +1104,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) struct dpu_hw_vbif *hw; const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; - hw = dpu_hw_vbif_init(vbif, dpu_kms->vbif[vbif->id]); + hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif[vbif->id]); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc); From 1e897dcc4c673b9d585c09ddcdbe7fab0934e64f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:37 +0300 Subject: [PATCH 2606/7721] drm/msm/dpu: use devres-managed allocation for MDP TOP Use devm_kzalloc to create MDP TOP structure. This allows us to remove corresponding kfree and drop dpu_hw_mdp_destroy() function. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570047/ Link: https://lore.kernel.org/r/20231201211845.1026967-6-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 17 +++++++---------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h | 8 +++++--- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 ++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c index 24e734768a72..05e48cf4ec1d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_top.h" @@ -247,16 +249,17 @@ static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops, ops->intf_audio_select = dpu_hw_intf_audio_select; } -struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, - void __iomem *addr, - const struct dpu_mdss_cfg *m) +struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, + const struct dpu_mdp_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_cfg *m) { struct dpu_hw_mdp *mdp; if (!addr) return ERR_PTR(-EINVAL); - mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); + mdp = drmm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); if (!mdp) return ERR_PTR(-ENOMEM); @@ -271,9 +274,3 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, return mdp; } - -void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp) -{ - kfree(mdp); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index 8b1463d2b2f0..6f3dc98087df 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -145,13 +145,15 @@ struct dpu_hw_mdp { /** * dpu_hw_mdptop_init - initializes the top driver for the passed config + * @dev: Corresponding device for devres management * @cfg: MDP TOP configuration from catalog * @addr: Mapped register io address of MDP * @m: Pointer to mdss catalog data */ -struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, - void __iomem *addr, - const struct dpu_mdss_cfg *m); +struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, + const struct dpu_mdp_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_cfg *m); void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index a1753c54aaac..5fcb256302b2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -810,8 +810,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_kms->catalog = NULL; - if (dpu_kms->hw_mdp) - dpu_hw_mdp_destroy(dpu_kms->hw_mdp); dpu_kms->hw_mdp = NULL; } @@ -1090,7 +1088,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms->rm_init = true; - dpu_kms->hw_mdp = dpu_hw_mdptop_init(dpu_kms->catalog->mdp, + dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev, + dpu_kms->catalog->mdp, dpu_kms->mmio, dpu_kms->catalog); if (IS_ERR(dpu_kms->hw_mdp)) { From a106ed98af6848ef5810b12f5c9e2e0566f1d9c4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:38 +0300 Subject: [PATCH 2607/7721] drm/msm/dpu: use devres-managed allocation for HW blocks Use devm_kzalloc to create HW block structure. This allows us to remove corresponding kfree and drop all dpu_hw_*_destroy() functions as well as dpu_rm_destroy(), which becomes empty afterwards. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570041/ Link: https://lore.kernel.org/r/20231201211845.1026967-7-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 19 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 16 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c | 12 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 10 ++- .../gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 7 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c | 16 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h | 12 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 16 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 13 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c | 14 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h | 12 +-- .../gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c | 14 ++- .../gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h | 13 +-- .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 15 ++-- .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 14 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 17 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 16 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c | 15 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h | 13 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 8 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 90 +++---------------- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 11 +-- 23 files changed, 127 insertions(+), 247 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 86182c734606..e7b680a151d6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -4,6 +4,9 @@ */ #include + +#include + #include "dpu_hwio.h" #include "dpu_hw_ctl.h" #include "dpu_kms.h" @@ -680,14 +683,15 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active; }; -struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, - void __iomem *addr, - u32 mixer_count, - const struct dpu_lm_cfg *mixer) +struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, + const struct dpu_ctl_cfg *cfg, + void __iomem *addr, + u32 mixer_count, + const struct dpu_lm_cfg *mixer) { struct dpu_hw_ctl *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -702,8 +706,3 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, return c; } - -void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx) -{ - kfree(ctx); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 1c242298ff2e..279ebd8dfbff 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -274,20 +274,16 @@ static inline struct dpu_hw_ctl *to_dpu_hw_ctl(struct dpu_hw_blk *hw) /** * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object. * Should be called before accessing any ctl_path register. + * @dev: Corresponding device for devres management * @cfg: ctl_path catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mixer_count: Number of mixers in @mixer * @mixer: Pointer to an array of Layer Mixers defined in the catalog */ -struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, - void __iomem *addr, - u32 mixer_count, - const struct dpu_lm_cfg *mixer); - -/** - * dpu_hw_ctl_destroy(): Destroys ctl driver context - * should be called to free the context - */ -void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx); +struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, + const struct dpu_ctl_cfg *cfg, + void __iomem *addr, + u32 mixer_count, + const struct dpu_lm_cfg *mixer); #endif /*_DPU_HW_CTL_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index 509dbaa51d87..5e9aad1b2aa2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -3,6 +3,8 @@ * Copyright (c) 2020-2022, Linaro Limited */ +#include + #include #include "dpu_kms.h" @@ -188,12 +190,13 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk; }; -struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr) { struct dpu_hw_dsc *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -206,8 +209,3 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, return c; } - -void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc) -{ - kfree(dsc); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index d5b597ab8c5c..989c88d2449b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -64,20 +64,24 @@ struct dpu_hw_dsc { /** * dpu_hw_dsc_init() - Initializes the DSC hw driver object. + * @dev: Corresponding device for devres management * @cfg: DSC catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: Error code or allocated dpu_hw_dsc context */ -struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, - void __iomem *addr); +struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, + void __iomem *addr); /** * dpu_hw_dsc_init_1_2() - initializes the v1.2 DSC hw driver object + * @dev: Corresponding device for devres management * @cfg: DSC catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Returns: Error code or allocated dpu_hw_dsc context */ -struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr); /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c index 24fe1d98eb86..ba193b0376fe 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c @@ -4,6 +4,8 @@ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved */ +#include + #include #include "dpu_kms.h" @@ -367,12 +369,13 @@ static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; } -struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr) { struct dpu_hw_dsc *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index 9419b2209af8..b1da88e2935f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_lm.h" @@ -68,15 +70,16 @@ static void _setup_dspp_ops(struct dpu_hw_dspp *c, c->ops.setup_pcc = dpu_setup_dspp_pcc; } -struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, - void __iomem *addr) +struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, + const struct dpu_dspp_cfg *cfg, + void __iomem *addr) { struct dpu_hw_dspp *c; if (!addr) return ERR_PTR(-EINVAL); - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -90,10 +93,3 @@ struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, return c; } - -void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp) -{ - kfree(dspp); -} - - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index bea965681330..3b435690b6cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -81,18 +81,14 @@ static inline struct dpu_hw_dspp *to_dpu_hw_dspp(struct dpu_hw_blk *hw) /** * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. * should be called once before accessing every DSPP. + * @dev: Corresponding device for devres management * @cfg: DSPP catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: pointer to structure or ERR_PTR */ -struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_dspp_destroy(): Destroys DSPP driver context - * @dspp: Pointer to DSPP driver context - */ -void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp); +struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, + const struct dpu_dspp_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_DSPP_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index e8b8908d3e12..0b6a0a7dcc39 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -12,6 +12,8 @@ #include +#include + #define INTF_TIMING_ENGINE_EN 0x000 #define INTF_CONFIG 0x004 #define INTF_HSYNC_CTL 0x008 @@ -527,8 +529,10 @@ static void dpu_hw_intf_program_intf_cmd_cfg(struct dpu_hw_intf *ctx, DPU_REG_WRITE(&ctx->hw, INTF_CONFIG2, intf_cfg2); } -struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + const struct dpu_intf_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_intf *c; @@ -537,7 +541,7 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, return NULL; } - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -581,9 +585,3 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, return c; } - -void dpu_hw_intf_destroy(struct dpu_hw_intf *intf) -{ - kfree(intf); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index c539025c418b..215401bb042e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -131,17 +131,14 @@ struct dpu_hw_intf { /** * dpu_hw_intf_init() - Initializes the INTF driver for the passed * interface catalog entry. + * @dev: Corresponding device for devres management * @cfg: interface catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions */ -struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_intf_destroy(): Destroys INTF driver context - * @intf: Pointer to INTF driver context - */ -void dpu_hw_intf_destroy(struct dpu_hw_intf *intf); +struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + const struct dpu_intf_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_INTF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index d1c3bd8379ea..25af52ab602f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -4,6 +4,8 @@ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_kms.h" #include "dpu_hw_catalog.h" #include "dpu_hwio.h" @@ -156,8 +158,9 @@ static void _setup_mixer_ops(struct dpu_hw_lm_ops *ops, ops->collect_misr = dpu_hw_lm_collect_misr; } -struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, - void __iomem *addr) +struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, + const struct dpu_lm_cfg *cfg, + void __iomem *addr) { struct dpu_hw_mixer *c; @@ -166,7 +169,7 @@ struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, return NULL; } - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -180,8 +183,3 @@ struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, return c; } - -void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm) -{ - kfree(lm); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 36992d046a53..8835fd106413 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -95,16 +95,12 @@ static inline struct dpu_hw_mixer *to_dpu_hw_mixer(struct dpu_hw_blk *hw) /** * dpu_hw_lm_init() - Initializes the mixer hw driver object. * should be called once before accessing every mixer. + * @dev: Corresponding device for devres management * @cfg: mixer catalog entry for which driver object is required * @addr: mapped register io address of MDP */ -struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_lm_destroy(): Destroys layer mixer driver context - * @lm: Pointer to LM driver context - */ -void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm); +struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, + const struct dpu_lm_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_LM_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c index 90e0e05eff8d..ddfa40a959cb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c @@ -4,6 +4,8 @@ #include +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -37,12 +39,13 @@ static void _setup_merge_3d_ops(struct dpu_hw_merge_3d *c, c->ops.setup_3d_mode = dpu_hw_merge_3d_setup_3d_mode; }; -struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, - void __iomem *addr) +struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, + const struct dpu_merge_3d_cfg *cfg, + void __iomem *addr) { struct dpu_hw_merge_3d *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -55,8 +58,3 @@ struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, return c; } - -void dpu_hw_merge_3d_destroy(struct dpu_hw_merge_3d *hw) -{ - kfree(hw); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index 19cec5e88722..c192f02ec1ab 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -48,18 +48,13 @@ static inline struct dpu_hw_merge_3d *to_dpu_hw_merge_3d(struct dpu_hw_blk *hw) /** * dpu_hw_merge_3d_init() - Initializes the merge_3d driver for the passed * merge3d catalog entry. + * @dev: Corresponding device for devres management * @cfg: Pingpong catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: Error code or allocated dpu_hw_merge_3d context */ -struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_merge_3d_destroy - destroys merge_3d driver context - * should be called to free the context - * @pp: Pointer to PP driver context returned by dpu_hw_merge_3d_init - */ -void dpu_hw_merge_3d_destroy(struct dpu_hw_merge_3d *pp); +struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, + const struct dpu_merge_3d_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_MERGE3D_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index 057cac7f5d93..2db4c6fba37a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -4,6 +4,8 @@ #include +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -281,12 +283,14 @@ static int dpu_hw_pp_setup_dsc(struct dpu_hw_pingpong *pp) return 0; } -struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, + const struct dpu_pingpong_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_pingpong *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -317,8 +321,3 @@ struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, return c; } - -void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp) -{ - kfree(pp); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index 0d541ca5b056..a48b69fd79a3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -121,19 +121,15 @@ static inline struct dpu_hw_pingpong *to_dpu_hw_pingpong(struct dpu_hw_blk *hw) /** * dpu_hw_pingpong_init() - initializes the pingpong driver for the passed * pingpong catalog entry. + * @dev: Corresponding device for devres management * @cfg: Pingpong catalog entry for which driver object is required * @addr: Mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions * Return: Error code or allocated dpu_hw_pingpong context */ -struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_pingpong_destroy - destroys pingpong driver context - * should be called to free the context - * @pp: Pointer to PP driver context returned by dpu_hw_pingpong_init - */ -void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp); +struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, + const struct dpu_pingpong_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_PINGPONG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 26307d9fc81d..0bf8a83e8df3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -11,6 +11,7 @@ #include "msm_mdss.h" #include +#include #define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087 @@ -669,16 +670,18 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, } #endif -struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, - void __iomem *addr, const struct msm_mdss_data *mdss_data, - const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, + const struct dpu_sspp_cfg *cfg, + void __iomem *addr, + const struct msm_mdss_data *mdss_data, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_sspp *hw_pipe; if (!addr) return ERR_PTR(-EINVAL); - hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL); + hw_pipe = drmm_kzalloc(dev, sizeof(*hw_pipe), GFP_KERNEL); if (!hw_pipe) return ERR_PTR(-ENOMEM); @@ -693,9 +696,3 @@ struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, return hw_pipe; } - -void dpu_hw_sspp_destroy(struct dpu_hw_sspp *ctx) -{ - kfree(ctx); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index 28e7d53bd191..b7dc52312c39 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -318,21 +318,17 @@ struct dpu_kms; /** * dpu_hw_sspp_init() - Initializes the sspp hw driver object. * Should be called once before accessing every pipe. + * @dev: Corresponding device for devres management * @cfg: Pipe catalog entry for which driver object is required * @addr: Mapped register io address of MDP * @mdss_data: UBWC / MDSS configuration data * @mdss_rev: dpu core's major and minor versions */ -struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, - void __iomem *addr, const struct msm_mdss_data *mdss_data, - const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_sspp_destroy(): Destroys SSPP driver context - * should be called during Hw pipe cleanup. - * @ctx: Pointer to SSPP driver context returned by dpu_hw_sspp_init - */ -void dpu_hw_sspp_destroy(struct dpu_hw_sspp *ctx); +struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, + const struct dpu_sspp_cfg *cfg, + void __iomem *addr, + const struct msm_mdss_data *mdss_data, + const struct dpu_mdss_version *mdss_rev); int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, struct dentry *entry); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c index 9668fb97c047..ed0e80616129 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c @@ -3,6 +3,8 @@ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved */ +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -208,15 +210,17 @@ static void _setup_wb_ops(struct dpu_hw_wb_ops *ops, ops->setup_clk_force_ctrl = dpu_hw_wb_setup_clk_force_ctrl; } -struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, + const struct dpu_wb_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_wb *c; if (!addr) return ERR_PTR(-EINVAL); - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -230,8 +234,3 @@ struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, return c; } - -void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb) -{ - kfree(hw_wb); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index 88792f450a92..e671796ea379 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -76,18 +76,15 @@ struct dpu_hw_wb { /** * dpu_hw_wb_init() - Initializes the writeback hw driver object. + * @dev: Corresponding device for devres management * @cfg: wb_path catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions * Return: Error code or allocated dpu_hw_wb context */ -struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_wb_destroy(): Destroy writeback hw driver object. - * @hw_wb: Pointer to writeback hw driver object - */ -void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb); +struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, + const struct dpu_wb_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_WB_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 5fcb256302b2..dc24fe4bb3b0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -804,10 +804,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_kms->hw_vbif[i] = NULL; } - if (dpu_kms->rm_init) - dpu_rm_destroy(&dpu_kms->rm); - dpu_kms->rm_init = false; - dpu_kms->catalog = NULL; dpu_kms->hw_mdp = NULL; @@ -1080,14 +1076,12 @@ static int dpu_kms_hw_init(struct msm_kms *kms) goto err_pm_put; } - rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); + rc = dpu_rm_init(dev, &dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); if (rc) { DPU_ERROR("rm init failed: %d\n", rc); goto err_pm_put; } - dpu_kms->rm_init = true; - dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev, dpu_kms->catalog->mdp, dpu_kms->mmio, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index b6f53ca6e962..df6271017b80 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -88,7 +88,6 @@ struct dpu_kms { struct drm_private_obj global_state; struct dpu_rm rm; - bool rm_init; struct dpu_hw_vbif *hw_vbif[VBIF_MAX]; struct dpu_hw_mdp *hw_mdp; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 8759466e2f37..0bb28cf4a6cb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -34,72 +34,8 @@ struct dpu_rm_requirements { struct msm_display_topology topology; }; -int dpu_rm_destroy(struct dpu_rm *rm) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(rm->dspp_blks); i++) { - struct dpu_hw_dspp *hw; - - if (rm->dspp_blks[i]) { - hw = to_dpu_hw_dspp(rm->dspp_blks[i]); - dpu_hw_dspp_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) { - struct dpu_hw_pingpong *hw; - - if (rm->pingpong_blks[i]) { - hw = to_dpu_hw_pingpong(rm->pingpong_blks[i]); - dpu_hw_pingpong_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->merge_3d_blks); i++) { - struct dpu_hw_merge_3d *hw; - - if (rm->merge_3d_blks[i]) { - hw = to_dpu_hw_merge_3d(rm->merge_3d_blks[i]); - dpu_hw_merge_3d_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->mixer_blks); i++) { - struct dpu_hw_mixer *hw; - - if (rm->mixer_blks[i]) { - hw = to_dpu_hw_mixer(rm->mixer_blks[i]); - dpu_hw_lm_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->ctl_blks); i++) { - struct dpu_hw_ctl *hw; - - if (rm->ctl_blks[i]) { - hw = to_dpu_hw_ctl(rm->ctl_blks[i]); - dpu_hw_ctl_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->hw_intf); i++) - dpu_hw_intf_destroy(rm->hw_intf[i]); - - for (i = 0; i < ARRAY_SIZE(rm->dsc_blks); i++) { - struct dpu_hw_dsc *hw; - - if (rm->dsc_blks[i]) { - hw = to_dpu_hw_dsc(rm->dsc_blks[i]); - dpu_hw_dsc_destroy(hw); - } - } - - for (i = 0; i < ARRAY_SIZE(rm->hw_wb); i++) - dpu_hw_wb_destroy(rm->hw_wb[i]); - - for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) - dpu_hw_sspp_destroy(rm->hw_sspp[i]); - - return 0; -} - -int dpu_rm_init(struct dpu_rm *rm, +int dpu_rm_init(struct drm_device *dev, + struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, const struct msm_mdss_data *mdss_data, void __iomem *mmio) @@ -119,7 +55,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_mixer *hw; const struct dpu_lm_cfg *lm = &cat->mixer[i]; - hw = dpu_hw_lm_init(lm, mmio); + hw = dpu_hw_lm_init(dev, lm, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed lm object creation: err %d\n", rc); @@ -132,7 +68,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_merge_3d *hw; const struct dpu_merge_3d_cfg *merge_3d = &cat->merge_3d[i]; - hw = dpu_hw_merge_3d_init(merge_3d, mmio); + hw = dpu_hw_merge_3d_init(dev, merge_3d, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed merge_3d object creation: err %d\n", @@ -146,7 +82,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_pingpong *hw; const struct dpu_pingpong_cfg *pp = &cat->pingpong[i]; - hw = dpu_hw_pingpong_init(pp, mmio, cat->mdss_ver); + hw = dpu_hw_pingpong_init(dev, pp, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed pingpong object creation: err %d\n", @@ -162,7 +98,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_intf *hw; const struct dpu_intf_cfg *intf = &cat->intf[i]; - hw = dpu_hw_intf_init(intf, mmio, cat->mdss_ver); + hw = dpu_hw_intf_init(dev, intf, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed intf object creation: err %d\n", rc); @@ -175,7 +111,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_wb *hw; const struct dpu_wb_cfg *wb = &cat->wb[i]; - hw = dpu_hw_wb_init(wb, mmio, cat->mdss_ver); + hw = dpu_hw_wb_init(dev, wb, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed wb object creation: err %d\n", rc); @@ -188,7 +124,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_ctl *hw; const struct dpu_ctl_cfg *ctl = &cat->ctl[i]; - hw = dpu_hw_ctl_init(ctl, mmio, cat->mixer_count, cat->mixer); + hw = dpu_hw_ctl_init(dev, ctl, mmio, cat->mixer_count, cat->mixer); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed ctl object creation: err %d\n", rc); @@ -201,7 +137,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_dspp *hw; const struct dpu_dspp_cfg *dspp = &cat->dspp[i]; - hw = dpu_hw_dspp_init(dspp, mmio); + hw = dpu_hw_dspp_init(dev, dspp, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed dspp object creation: err %d\n", rc); @@ -215,9 +151,9 @@ int dpu_rm_init(struct dpu_rm *rm, const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) - hw = dpu_hw_dsc_init_1_2(dsc, mmio); + hw = dpu_hw_dsc_init_1_2(dev, dsc, mmio); else - hw = dpu_hw_dsc_init(dsc, mmio); + hw = dpu_hw_dsc_init(dev, dsc, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); @@ -231,7 +167,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_sspp *hw; const struct dpu_sspp_cfg *sspp = &cat->sspp[i]; - hw = dpu_hw_sspp_init(sspp, mmio, mdss_data, cat->mdss_ver); + hw = dpu_hw_sspp_init(dev, sspp, mmio, mdss_data, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed sspp object creation: err %d\n", rc); @@ -243,8 +179,6 @@ int dpu_rm_init(struct dpu_rm *rm, return 0; fail: - dpu_rm_destroy(rm); - return rc ? rc : -EFAULT; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 2b551566cbf4..36752d837be4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -38,24 +38,19 @@ struct dpu_rm { /** * dpu_rm_init - Read hardware catalog and create reservation tracking objects * for all HW blocks. + * @dev: Corresponding device for devres management * @rm: DPU Resource Manager handle * @cat: Pointer to hardware catalog * @mdss_data: Pointer to MDSS / UBWC configuration * @mmio: mapped register io address of MDP * @Return: 0 on Success otherwise -ERROR */ -int dpu_rm_init(struct dpu_rm *rm, +int dpu_rm_init(struct drm_device *dev, + struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, const struct msm_mdss_data *mdss_data, void __iomem *mmio); -/** - * dpu_rm_destroy - Free all memory allocated by dpu_rm_init - * @rm: DPU Resource Manager handle - * @Return: 0 on Success otherwise -ERROR - */ -int dpu_rm_destroy(struct dpu_rm *rm); - /** * dpu_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze * the use connections and user requirements, specified through related From b0311c1c4e069e2e15f2e2a32bccbcf628be42ec Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:39 +0300 Subject: [PATCH 2608/7721] drm/msm/dpu: drop unused dpu_plane::lock The field dpu_plane::lock was never used for protecting any kind of data. Drop it now. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570043/ Link: https://lore.kernel.org/r/20231201211845.1026967-8-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 4d7f3894f4d7..97d2211de0e3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -78,8 +78,6 @@ static const uint32_t qcom_compressed_supported_formats[] = { struct dpu_plane { struct drm_plane base; - struct mutex lock; - enum dpu_sspp pipe; uint32_t color_fill; @@ -1230,8 +1228,6 @@ static void dpu_plane_destroy(struct drm_plane *plane) if (pstate->r_pipe.sspp) _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false); - mutex_destroy(&pdpu->lock); - /* this will destroy the states as well */ drm_plane_cleanup(plane); @@ -1491,8 +1487,6 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, /* success! finalize initialization */ drm_plane_helper_add(plane, &dpu_plane_helper_funcs); - mutex_init(&pdpu->lock); - DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name, pipe, plane->base.id); return plane; From bcc54a4c063a823cb75b71116762673b380a1ef6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:40 +0300 Subject: [PATCH 2609/7721] drm/msm/dpu: remove QoS teardown on plane destruction There is little point in disabling QoS on plane destruction: it happens during DPU device destruction process, after which there will be no running planes. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570049/ Link: https://lore.kernel.org/r/20231201211845.1026967-9-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 97d2211de0e3..dae7d57f5881 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1217,17 +1217,10 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, static void dpu_plane_destroy(struct drm_plane *plane) { struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; - struct dpu_plane_state *pstate; DPU_DEBUG_PLANE(pdpu, "\n"); if (pdpu) { - pstate = to_dpu_plane_state(plane->state); - _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false); - - if (pstate->r_pipe.sspp) - _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false); - /* this will destroy the states as well */ drm_plane_cleanup(plane); From 0e00f9af95bbce1f1d2f193d08e80b446329dd57 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:41 +0300 Subject: [PATCH 2610/7721] drm/msm/dpu: use drmm-managed allocation for dpu_plane Change struct dpu_plane allocation to use drmm_universal_plane_alloc(). This removes the need to perform any actions on plane destruction. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570042/ Link: https://lore.kernel.org/r/20231201211845.1026967-10-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 46 +++++------------------ 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index dae7d57f5881..3235ab132540 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1214,20 +1214,6 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, } } -static void dpu_plane_destroy(struct drm_plane *plane) -{ - struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; - - DPU_DEBUG_PLANE(pdpu, "\n"); - - if (pdpu) { - /* this will destroy the states as well */ - drm_plane_cleanup(plane); - - kfree(pdpu); - } -} - static void dpu_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { @@ -1397,7 +1383,6 @@ static bool dpu_plane_format_mod_supported(struct drm_plane *plane, static const struct drm_plane_funcs dpu_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = dpu_plane_destroy, .reset = dpu_plane_reset, .atomic_duplicate_state = dpu_plane_duplicate_state, .atomic_destroy_state = dpu_plane_destroy_state, @@ -1425,35 +1410,28 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, struct dpu_hw_sspp *pipe_hw; uint32_t num_formats; uint32_t supported_rotations; - int ret = -EINVAL; - - /* create and zero local structure */ - pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL); - if (!pdpu) { - DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe); - ret = -ENOMEM; - return ERR_PTR(ret); - } - - /* cache local stuff for later */ - plane = &pdpu->base; - pdpu->pipe = pipe; + int ret; /* initialize underlying h/w driver */ pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe); if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) { DPU_ERROR("[%u]SSPP is invalid\n", pipe); - goto clean_plane; + return ERR_PTR(-EINVAL); } format_list = pipe_hw->cap->sblk->format_list; num_formats = pipe_hw->cap->sblk->num_formats; - ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, + pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base, + 0xff, &dpu_plane_funcs, format_list, num_formats, supported_format_modifiers, type, NULL); - if (ret) - goto clean_plane; + if (IS_ERR(pdpu)) + return ERR_CAST(pdpu); + + /* cache local stuff for later */ + plane = &pdpu->base; + pdpu->pipe = pipe; pdpu->catalog = kms->catalog; @@ -1483,8 +1461,4 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name, pipe, plane->base.id); return plane; - -clean_plane: - kfree(pdpu); - return ERR_PTR(ret); } From 3637af92de2b1f51a4ecd5e21ada2d62d3a5a6b5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:42 +0300 Subject: [PATCH 2611/7721] drm/msm/dpu: use drmm-managed allocation for dpu_crtc Change struct dpu_crtc allocation to use drmm_crtc_alloc_with_planes(). This removes the need to perform any actions on CRTC destruction. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570054/ Link: https://lore.kernel.org/r/20231201211845.1026967-11-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 25 +++++++----------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 3c475f8042b0..a798c10036e1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -51,17 +51,6 @@ static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) return to_dpu_kms(priv->kms); } -static void dpu_crtc_destroy(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - - if (!crtc) - return; - - drm_crtc_cleanup(crtc); - kfree(dpu_crtc); -} - static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -1435,7 +1424,6 @@ static int dpu_crtc_late_register(struct drm_crtc *crtc) static const struct drm_crtc_funcs dpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = dpu_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = dpu_crtc_reset, .atomic_duplicate_state = dpu_crtc_duplicate_state, @@ -1469,9 +1457,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct dpu_crtc *dpu_crtc; int i, ret; - dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); - if (!dpu_crtc) - return ERR_PTR(-ENOMEM); + dpu_crtc = drmm_crtc_alloc_with_planes(dev, struct dpu_crtc, base, + plane, cursor, + &dpu_crtc_funcs, + NULL); + + if (IS_ERR(dpu_crtc)) + return ERR_CAST(dpu_crtc); crtc = &dpu_crtc->base; crtc->dev = dev; @@ -1491,9 +1483,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, dpu_crtc_frame_event_work); } - drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, - NULL); - drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); if (dpu_kms->catalog->dspp_count) From 73169b45e1ed296b4357a694f5fa586ac0643ac1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:43 +0300 Subject: [PATCH 2612/7721] drm/msm/dpu: use drmm-managed allocation for dpu_encoder_phys Change struct allocation of encoder's phys backend data to use drmm_kzalloc(). This removes the need to perform any actions on encoder destruction. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570051/ Link: https://lore.kernel.org/r/20231201211845.1026967-12-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 9 ++++---- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 8 ++++--- .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 15 ++++--------- .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 13 ++++-------- .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 21 ++++--------------- 5 files changed, 22 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 1c3560e1c625..cd2e153860b5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2179,6 +2179,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder) } static int dpu_encoder_virt_add_phys_encs( + struct drm_device *dev, struct msm_display_info *disp_info, struct dpu_encoder_virt *dpu_enc, struct dpu_enc_phys_init_params *params) @@ -2200,7 +2201,7 @@ static int dpu_encoder_virt_add_phys_encs( if (disp_info->intf_type == INTF_WB) { - enc = dpu_encoder_phys_wb_init(params); + enc = dpu_encoder_phys_wb_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n", @@ -2211,7 +2212,7 @@ static int dpu_encoder_virt_add_phys_encs( dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; ++dpu_enc->num_phys_encs; } else if (disp_info->is_cmd_mode) { - enc = dpu_encoder_phys_cmd_init(params); + enc = dpu_encoder_phys_cmd_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n", @@ -2222,7 +2223,7 @@ static int dpu_encoder_virt_add_phys_encs( dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; ++dpu_enc->num_phys_encs; } else { - enc = dpu_encoder_phys_vid_init(params); + enc = dpu_encoder_phys_vid_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n", @@ -2311,7 +2312,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, break; } - ret = dpu_encoder_virt_add_phys_encs(disp_info, + ret = dpu_encoder_virt_add_phys_encs(dpu_kms->dev, disp_info, dpu_enc, &phys_params); if (ret) { DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n"); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 6f04c3d56e77..5dc53b65040e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -281,22 +281,24 @@ struct dpu_encoder_wait_info { * @p: Pointer to init params structure * Return: Error code or newly allocated encoder */ -struct dpu_encoder_phys *dpu_encoder_phys_vid_init( +struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder + * @dev: Corresponding device for devres management * @p: Pointer to init params structure * Return: Error code or newly allocated encoder */ -struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_wb_init - initialize writeback encoder + * @dev: Corresponding device for devres management * @init: Pointer to init info structure with initialization params */ -struct dpu_encoder_phys *dpu_encoder_phys_wb_init( +struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index be185fe69793..d24f45d1f654 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -13,6 +13,8 @@ #include "dpu_trace.h" #include "disp/msm_disp_snapshot.h" +#include + #define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->base.parent ? \ (e)->base.parent->base.id : -1, \ @@ -558,14 +560,6 @@ static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_DISABLED; } -static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc) -{ - struct dpu_encoder_phys_cmd *cmd_enc = - to_dpu_encoder_phys_cmd(phys_enc); - - kfree(cmd_enc); -} - static void dpu_encoder_phys_cmd_prepare_for_kickoff( struct dpu_encoder_phys *phys_enc) { @@ -731,7 +725,6 @@ static void dpu_encoder_phys_cmd_init_ops( ops->atomic_mode_set = dpu_encoder_phys_cmd_atomic_mode_set; ops->enable = dpu_encoder_phys_cmd_enable; ops->disable = dpu_encoder_phys_cmd_disable; - ops->destroy = dpu_encoder_phys_cmd_destroy; ops->control_vblank_irq = dpu_encoder_phys_cmd_control_vblank_irq; ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done; ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff; @@ -746,7 +739,7 @@ static void dpu_encoder_phys_cmd_init_ops( ops->get_line_count = dpu_encoder_phys_cmd_get_line_count; } -struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -754,7 +747,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( DPU_DEBUG("intf\n"); - cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL); + cmd_enc = drmm_kzalloc(dev, sizeof(*cmd_enc), GFP_KERNEL); if (!cmd_enc) { DPU_ERROR("failed to allocate\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index a01fda711883..69bc1b2e514c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -11,6 +11,8 @@ #include "dpu_trace.h" #include "disp/msm_disp_snapshot.h" +#include + #define DPU_DEBUG_VIDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->parent ? \ (e)->parent->base.id : -1, \ @@ -438,12 +440,6 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_ENABLING; } -static void dpu_encoder_phys_vid_destroy(struct dpu_encoder_phys *phys_enc) -{ - DPU_DEBUG_VIDENC(phys_enc, "\n"); - kfree(phys_enc); -} - static int dpu_encoder_phys_vid_wait_for_vblank( struct dpu_encoder_phys *phys_enc) { @@ -681,7 +677,6 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->atomic_mode_set = dpu_encoder_phys_vid_atomic_mode_set; ops->enable = dpu_encoder_phys_vid_enable; ops->disable = dpu_encoder_phys_vid_disable; - ops->destroy = dpu_encoder_phys_vid_destroy; ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; @@ -694,7 +689,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->get_frame_count = dpu_encoder_phys_vid_get_frame_count; } -struct dpu_encoder_phys *dpu_encoder_phys_vid_init( +struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -704,7 +699,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( return ERR_PTR(-EINVAL); } - phys_enc = kzalloc(sizeof(*phys_enc), GFP_KERNEL); + phys_enc = drmm_kzalloc(dev, sizeof(*phys_enc), GFP_KERNEL); if (!phys_enc) { DPU_ERROR("failed to create encoder due to memory allocation error\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 0b6a761d68b7..bb94909caa25 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -8,6 +8,7 @@ #include #include +#include #include "dpu_encoder_phys.h" #include "dpu_formats.h" @@ -580,20 +581,6 @@ static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_DISABLED; } -/** - * dpu_encoder_phys_wb_destroy - destroy writeback encoder - * @phys_enc: Pointer to physical encoder - */ -static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc) -{ - if (!phys_enc) - return; - - DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0); - - kfree(phys_enc); -} - static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc, struct drm_writeback_job *job) { @@ -689,7 +676,6 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set; ops->enable = dpu_encoder_phys_wb_enable; ops->disable = dpu_encoder_phys_wb_disable; - ops->destroy = dpu_encoder_phys_wb_destroy; ops->atomic_check = dpu_encoder_phys_wb_atomic_check; ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done; ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff; @@ -705,9 +691,10 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) /** * dpu_encoder_phys_wb_init - initialize writeback encoder + * @dev: Corresponding device for devres management * @p: Pointer to init info structure with initialization params */ -struct dpu_encoder_phys *dpu_encoder_phys_wb_init( +struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -720,7 +707,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( return ERR_PTR(-EINVAL); } - wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); + wb_enc = drmm_kzalloc(dev, sizeof(*wb_enc), GFP_KERNEL); if (!wb_enc) { DPU_ERROR("failed to allocate wb phys_enc enc\n"); return ERR_PTR(-ENOMEM); From 3285f4acb23c6ea611583fe32c4ad231daf15a08 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:44 +0300 Subject: [PATCH 2613/7721] drm/msm/dpu: drop dpu_encoder_phys_ops::destroy Drop the dpu_encoder_phys_ops' destroy() callback. No phys backend implements it anymore, so it is useless. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570058/ Link: https://lore.kernel.org/r/20231201211845.1026967-13-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 18 ------------------ .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index cd2e153860b5..6167aa664b30 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -455,24 +455,6 @@ static void dpu_encoder_destroy(struct drm_encoder *drm_enc) dpu_enc = to_dpu_encoder_virt(drm_enc); DPU_DEBUG_ENC(dpu_enc, "\n"); - mutex_lock(&dpu_enc->enc_lock); - - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys->ops.destroy) { - phys->ops.destroy(phys); - --dpu_enc->num_phys_encs; - dpu_enc->phys_encs[i] = NULL; - } - } - - if (dpu_enc->num_phys_encs) - DPU_ERROR_ENC(dpu_enc, "expected 0 num_phys_encs not %d\n", - dpu_enc->num_phys_encs); - dpu_enc->num_phys_encs = 0; - mutex_unlock(&dpu_enc->enc_lock); - drm_encoder_cleanup(drm_enc); mutex_destroy(&dpu_enc->enc_lock); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 5dc53b65040e..b6b48e2c63ef 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -72,7 +72,6 @@ struct dpu_encoder_phys; * @enable: DRM Call. Enable a DRM mode. * @disable: DRM Call. Disable mode. * @atomic_check: DRM Call. Atomic check new DRM state. - * @destroy: DRM Call. Destroy and release resources. * @control_vblank_irq Register/Deregister for VBLANK IRQ * @wait_for_commit_done: Wait for hardware to have flushed the * current pending frames to hardware @@ -102,7 +101,6 @@ struct dpu_encoder_phys_ops { int (*atomic_check)(struct dpu_encoder_phys *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state); - void (*destroy)(struct dpu_encoder_phys *encoder); int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable); int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); From cd42c56d9c0bb6007939408b4fbc62bbeccc9037 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Dec 2023 00:18:45 +0300 Subject: [PATCH 2614/7721] drm/msm/dpu: use drmm-managed allocation for dpu_encoder_virt It is incorrect to use devm-managed memory allocations for DRM data structures exposed to userspace. They should use drmm_ allocations. Change struct dpu_encoder allocation to use drmm_encoder_alloc(). This removes the need to perform any actions on encoder destruction. Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570053/ Link: https://lore.kernel.org/r/20231201211845.1026967-14-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 50 +++++---------------- 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 6167aa664b30..aa1a1646b322 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -442,23 +442,6 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) return linecount; } -static void dpu_encoder_destroy(struct drm_encoder *drm_enc) -{ - struct dpu_encoder_virt *dpu_enc = NULL; - int i = 0; - - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - - dpu_enc = to_dpu_encoder_virt(drm_enc); - DPU_DEBUG_ENC(dpu_enc, "\n"); - - drm_encoder_cleanup(drm_enc); - mutex_destroy(&dpu_enc->enc_lock); -} - void dpu_encoder_helper_split_config( struct dpu_encoder_phys *phys_enc, enum dpu_intf interface) @@ -2346,7 +2329,6 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { }; static const struct drm_encoder_funcs dpu_encoder_funcs = { - .destroy = dpu_encoder_destroy, .late_register = dpu_encoder_late_register, .early_unregister = dpu_encoder_early_unregister, }; @@ -2357,20 +2339,13 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, { struct msm_drm_private *priv = dev->dev_private; struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - struct drm_encoder *drm_enc = NULL; - struct dpu_encoder_virt *dpu_enc = NULL; - int ret = 0; + struct dpu_encoder_virt *dpu_enc; + int ret; - dpu_enc = devm_kzalloc(dev->dev, sizeof(*dpu_enc), GFP_KERNEL); - if (!dpu_enc) - return ERR_PTR(-ENOMEM); - - ret = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs, - drm_enc_mode, NULL); - if (ret) { - devm_kfree(dev->dev, dpu_enc); - return ERR_PTR(ret); - } + dpu_enc = drmm_encoder_alloc(dev, struct dpu_encoder_virt, base, + &dpu_encoder_funcs, drm_enc_mode, NULL); + if (IS_ERR(dpu_enc)) + return ERR_CAST(dpu_enc); drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs); @@ -2380,8 +2355,10 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, mutex_init(&dpu_enc->rc_lock); ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info); - if (ret) - goto fail; + if (ret) { + DPU_ERROR("failed to setup encoder\n"); + return ERR_PTR(-ENOMEM); + } atomic_set(&dpu_enc->frame_done_timeout_ms, 0); atomic_set(&dpu_enc->frame_done_timeout_cnt, 0); @@ -2397,13 +2374,6 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, DPU_DEBUG_ENC(dpu_enc, "created\n"); return &dpu_enc->base; - -fail: - DPU_ERROR("failed to create encoder\n"); - if (drm_enc) - dpu_encoder_destroy(drm_enc); - - return ERR_PTR(ret); } int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, From 1ccd91963bd48b8da4148c128a946c2312407243 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sat, 2 Dec 2023 10:16:24 -0800 Subject: [PATCH 2615/7721] f2fs: let's finish or reset zones all the time In order to limit # of open zones, let's finish or reset zones given # of valid blocks per section and its zone condition. Reviewed-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 75 +++++++++++------------------------------------ 1 file changed, 17 insertions(+), 58 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9081c9af977a..007ebb107236 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -4870,82 +4870,43 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi, struct f2fs_dev_info *fdev, struct blk_zone *zone) { - unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno; - block_t zone_block, wp_block, last_valid_block; + unsigned int zone_segno; + block_t zone_block, valid_block_cnt; unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; - int i, s, b, ret; - struct seg_entry *se; + int ret; if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ) return 0; - wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block); - wp_segno = GET_SEGNO(sbi, wp_block); - wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block); zone_segno = GET_SEGNO(sbi, zone_block); - zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno); - - if (zone_segno >= MAIN_SEGS(sbi)) - return 0; /* * Skip check of zones cursegs point to, since * fix_curseg_write_pointer() checks them. */ - for (i = 0; i < NO_CHECK_TYPE; i++) - if (zone_secno == GET_SEC_FROM_SEG(sbi, - CURSEG_I(sbi, i)->segno)) - return 0; + if (zone_segno >= MAIN_SEGS(sbi) || + IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno))) + return 0; /* - * Get last valid block of the zone. + * Get # of valid block of the zone. */ - last_valid_block = zone_block - 1; - for (s = sbi->segs_per_sec - 1; s >= 0; s--) { - segno = zone_segno + s; - se = get_seg_entry(sbi, segno); - for (b = sbi->blocks_per_seg - 1; b >= 0; b--) - if (f2fs_test_bit(b, se->cur_valid_map)) { - last_valid_block = START_BLOCK(sbi, segno) + b; - break; - } - if (last_valid_block >= zone_block) - break; - } + valid_block_cnt = get_valid_blocks(sbi, zone_segno, true); - /* - * When safely unmounted in the previous mount, we can trust write - * pointers. Otherwise, finish zones. - */ - if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { - /* - * The write pointer matches with the valid blocks or - * already points to the end of the zone. - */ - if ((last_valid_block + 1 == wp_block) || - (zone->wp == zone->start + zone->len)) - return 0; - } + if ((!valid_block_cnt && zone->cond == BLK_ZONE_COND_EMPTY) || + (valid_block_cnt && zone->cond == BLK_ZONE_COND_FULL)) + return 0; - if (last_valid_block + 1 == zone_block) { - if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { - /* - * If there is no valid block in the zone and if write - * pointer is not at zone start, reset the write - * pointer. - */ - f2fs_notice(sbi, - "Zone without valid block has non-zero write " - "pointer. Reset the write pointer: wp[0x%x,0x%x]", - wp_segno, wp_blkoff); - } + if (!valid_block_cnt) { + f2fs_notice(sbi, "Zone without valid block has non-zero write " + "pointer. Reset the write pointer: cond[0x%x]", + zone->cond); ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block, zone->len >> log_sectors_per_block); if (ret) f2fs_err(sbi, "Discard zone failed: %s (errno=%d)", fdev->path, ret); - return ret; } @@ -4957,10 +4918,8 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi, * selected for write operation until it get discarded. */ f2fs_notice(sbi, "Valid blocks are not aligned with write " - "pointer: valid block[0x%x,0x%x] wp[0x%x,0x%x]", - GET_SEGNO(sbi, last_valid_block), - GET_BLKOFF_FROM_SEG0(sbi, last_valid_block), - wp_segno, wp_blkoff); + "pointer: valid block[0x%x,0x%x] cond[0x%x]", + zone_segno, valid_block_cnt, zone->cond); ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH, zone->start, zone->len, GFP_NOFS); From fcb97d190c3ca411b37d8dd0b2650fa1378f08d4 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 5 Dec 2023 10:23:58 -0600 Subject: [PATCH 2616/7721] arm64: dts: ti: k3-am65: Add AM652 dtsi file The AM652 is basically a AM654 but with 2 cores instead of 4. Add a DTSI file for AM652 matching AM654 except this core difference. This removes the need to remove the extra cores from AM654 manually in DT files for boards that use the AM652 variant. Do that for the IOT2050 boards here. Signed-off-by: Andrew Davis Reviewed-by: Bryan Brattlof Link: https://lore.kernel.org/r/20231205162358.23904-1-afd@ti.com Signed-off-by: Nishanth Menon --- .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 1 - arch/arm64/boot/dts/ti/k3-am652.dtsi | 74 +++++++++++++++++++ .../ti/k3-am6528-iot2050-basic-common.dtsi | 11 +-- .../ti/k3-am6548-iot2050-advanced-common.dtsi | 1 + 4 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 arch/arm64/boot/dts/ti/k3-am652.dtsi diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index 6cbdf370cfcc..61a634afaa4f 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -9,7 +9,6 @@ * Common bits of the IOT2050 Basic and Advanced variants, PG1 and PG2 */ -#include "k3-am654.dtsi" #include #include diff --git a/arch/arm64/boot/dts/ti/k3-am652.dtsi b/arch/arm64/boot/dts/ti/k3-am652.dtsi new file mode 100644 index 000000000000..0f22e00faa90 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am652.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM65 SoC family in Dual core configuration + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "k3-am65.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x000>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <512>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + + thermal_zones: thermal-zones { + #include "k3-am654-industrial-thermal.dtsi" + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi index e4d7cba7c62f..1d6cddb11991 100644 --- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi @@ -9,6 +9,7 @@ * Common bits of the IOT2050 Basic variant, PG1 and PG2 */ +#include "k3-am652.dtsi" #include "k3-am65-iot2050-common.dtsi" / { @@ -17,16 +18,6 @@ memory@80000000 { /* 1G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x40000000>; }; - - cpus { - cpu-map { - /delete-node/ cluster1; - }; - /delete-node/ cpu@100; - /delete-node/ cpu@101; - }; - - /delete-node/ l2-cache1; }; &main_pmx0 { diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi index a847209c3df5..3864ec54e371 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi @@ -11,6 +11,7 @@ /dts-v1/; +#include "k3-am654.dtsi" #include "k3-am65-iot2050-common.dtsi" / { From bd62d91f42d015e173809214badaf750b75be2d1 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:16 +0530 Subject: [PATCH 2617/7721] arm64: defconfig: Enable J721E CSI2RX AM62 and other K3 based SoCs use Cadence DPHY and CSI-RX bridge drivers, along with a DMA wrapper CSI IP for the camera pipeline. Enable the same to get camera functionality on AM62x-SK, BeaglePlay and AM62Ax SK among other platforms. Tested-by: Martyn Welch Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-1-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/configs/defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 755c9de16fbb..405044ad72c5 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -785,6 +785,7 @@ CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SDR_PLATFORM_DRIVERS=y CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CADENCE_CSI2RX=m CONFIG_VIDEO_MEDIATEK_JPEG=m CONFIG_VIDEO_MEDIATEK_VCODEC=m CONFIG_VIDEO_IMX7_CSI=m @@ -806,6 +807,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m CONFIG_VIDEO_SAMSUNG_S5P_MFC=m CONFIG_VIDEO_SUN6I_CSI=m +CONFIG_VIDEO_TI_J721E_CSI2RX=m CONFIG_VIDEO_HANTRO=m CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX412=m @@ -1424,6 +1426,7 @@ CONFIG_PHY_XGENE=y CONFIG_PHY_CAN_TRANSCEIVER=m CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_CADENCE_TORRENT=m +CONFIG_PHY_CADENCE_DPHY_RX=m CONFIG_PHY_CADENCE_SIERRA=m CONFIG_PHY_MIXEL_MIPI_DPHY=m CONFIG_PHY_FSL_IMX8M_PCIE=y From 2017f5a610a998cd414c7d9e8b19051014f3126b Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:17 +0530 Subject: [PATCH 2618/7721] arm64: dts: ti: k3-am62-main: Enable CSI2-RX The CSI2RX subsystem can be used to capture video frames from CSI-2 cameras. Add nodes for the CSI core, SHIM layer, and the DPHY. Tested-by: Martyn Welch Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-2-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62-main.dtsi | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi index 0643cd15eeec..49000a97c153 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi @@ -972,4 +972,66 @@ mcasp2: audio-controller@2b20000 { power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma 0 0x4700 0>; + dma-names = "rx0"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + }; From c45e3b54ad1e84f59b3193abc6f451a8cdf7d69f Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:18 +0530 Subject: [PATCH 2619/7721] arm64: dts: ti: k3-am62a-main: Enable CSI2-RX Add nodes for Cadence DPHY, CSI2RX and TI's pixel-grabbing wrapper. AM62A uses a dedicated BCDMA instance for CSI-RX traffic, so enable that as well. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-3-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a-main.dtsi | 99 +++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi index ccd708b09acd..2338a92a4c9f 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi @@ -144,6 +144,44 @@ main_pktdma: dma-controller@485c0000 { }; }; + dmss_csi: bus@4e000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ranges = <0x00 0x4e000000 0x00 0x4e000000 0x00 0x300000>; + + ti,sci-dev-id = <198>; + + inta_main_dmss_csi: interrupt-controller@4e0a0000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x4e0a0000 0x00 0x8000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <200>; + ti,interrupt-ranges = <0 237 8>; + ti,unmapped-event-sources = <&main_bcdma_csi>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + + main_bcdma_csi: dma-controller@4e230000 { + compatible = "ti,am62a-dmss-bcdma-csirx"; + reg = <0x00 0x4e230000 0x00 0x100>, + <0x00 0x4e180000 0x00 0x8000>, + <0x00 0x4e100000 0x00 0x10000>; + reg-names = "gcfg", "rchanrt", "ringrt"; + msi-parent = <&inta_main_dmss_csi>; + #dma-cells = <3>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <199>; + ti,sci-rm-range-rchan = <0x21>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + }; + dmsc: system-controller@44043000 { compatible = "ti,k2g-sci"; reg = <0x00 0x44043000 0x00 0xfe0>; @@ -876,4 +914,65 @@ mcasp2: audio-controller@2b20000 { power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5000 0>; + dma-names = "rx0"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; }; From defa1438c5b34af13fb56c7faefaeec648805530 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:19 +0530 Subject: [PATCH 2620/7721] arm64: dts: ti: k3-am625-beagleplay: Add overlays for OV5640 Three different OV5640 modules are supported using the FFC connector on BeaglePlay: - Digilent PCam 5C - ALINX AN5641 - TEVI-OV5640-*-RPI The Digilent and ALINX modules supply a 12Mhz XCLK to the sensor, while the TEVI module supplies a 24Mhz XCLK, thus requiring a separate overlay. Reviewed-by: Andrew Davis Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-4-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/Makefile | 11 +++ .../ti/k3-am625-beagleplay-csi2-ov5640.dtso | 77 +++++++++++++++++++ .../k3-am625-beagleplay-csi2-tevi-ov5640.dtso | 77 +++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 77a347f9f47d..c6c7825b4cb2 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -12,6 +12,8 @@ k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia.dtb @@ -80,7 +82,16 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb +# Build time test only, enabled by CONFIG_OF_ALL_DTBS +k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-ov5640.dtbo +k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtb + # Enable support for device-tree overlays +DTC_FLAGS_k3-am625-beagleplay += -@ DTC_FLAGS_k3-am625-sk += -@ DTC_FLAGS_k3-am62-lp-sk += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso new file mode 100644 index 000000000000..5e80ca7033ba --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso new file mode 100644 index 000000000000..5e1cbbc27c8f --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; From fed1e53ecf9f0ecf04bd931428287fd1002899ef Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:20 +0530 Subject: [PATCH 2621/7721] arm64: dts: ti: k3-am62x-sk: Enable camera peripherals CSI cameras are controlled using I2C, on SK-AM62 and derivative boards this is routed to I2C-2, so enable that bus. Specific sensor connected to this bus will be described in the DT overlay for each sensor. Tested-by: Martyn Welch Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-5-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi index 3b9729316739..33768c02d8eb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi @@ -399,6 +399,13 @@ sii9022_out: endpoint { }; }; +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + &sdhci0 { bootph-all; status = "okay"; From 635ed97151945a7fdf104ef1227d86f0a9e3678e Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:21 +0530 Subject: [PATCH 2622/7721] arm64: dts: ti: k3-am62x: Add overlays for OV5640 Three different OV5640 modules are supported using the 15-pin FFC connector on SK-AM62: - Digilent PCam 5C - ALINX AN5641 - TEVI-OV5640-*-RPI The Digilent and ALINX modules supply a 12Mhz XCLK to the sensor, while the TEVI module supplies a 24Mhz XCLK, thus requiring a separate overlay. These overlays can be used on other boards of the SK-AM62* family that have a 15/22-pin FFC connector, so we name the overlays with the prefix k3-am62x-. Tested-by: Martyn Welch Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-6-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/Makefile | 19 ++++- .../boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso | 82 +++++++++++++++++++ .../dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso | 82 +++++++++++++++++++ 3 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index c6c7825b4cb2..f957b5f741ff 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -32,6 +32,10 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb # Boards with AM62Px SoC dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb +# Common overlays for SK-AM62* family of boards +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-tevi-ov5640.dtbo + # Boards with AM64x SoC dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-phyboard-electra-rdk.dtb @@ -87,13 +91,26 @@ k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-ov5640.dtbo k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am625-sk-csi2-tevi-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ - k3-am625-beagleplay-csi2-tevi-ov5640.dtb + k3-am625-beagleplay-csi2-tevi-ov5640.dtb \ + k3-am625-sk-csi2-ov5640.dtb \ + k3-am625-sk-csi2-tevi-ov5640.dtb \ + k3-am62a7-sk-csi2-ov5640.dtb \ + k3-am62a7-sk-csi2-tevi-ov5640.dtb # Enable support for device-tree overlays DTC_FLAGS_k3-am625-beagleplay += -@ DTC_FLAGS_k3-am625-sk += -@ DTC_FLAGS_k3-am62-lp-sk += -@ +DTC_FLAGS_k3-am62a7-sk += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso new file mode 100644 index 000000000000..9323a4b38389 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso new file mode 100644 index 000000000000..dcaa33a4c8d3 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; From 00d7f8f9efdbdf551e92683f5cd274145dce2c4b Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:22 +0530 Subject: [PATCH 2623/7721] arm64: dts: ti: k3-am62a7-sk: Enable camera peripherals Enable I2C-2 as it is used to control CSI based sensors. Also enable IO-EXP-2 as it controls the mux between different CSI-2 connectors. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-7-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts index 560dad02ef62..7b7142586295 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts @@ -446,6 +446,33 @@ tlv320aic3106: audio-codec@1b { DRVDD-supply = <&vcc_3v3_sys>; DVDD-supply = <&buck5>; }; + + exp2: gpio@23 { + compatible = "ti,tca6424"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = "", "", + "", "", + "", "", + "", "", + "WL_LT_EN", "CSI_RSTz", + "", "", + "", "", + "", "", + "SPI0_FET_SEL", "SPI0_FET_OE", + "RGMII2_BRD_CONN_DET", "CSI_SEL2", + "CSI_EN", "AUTO_100M_1000M_CONFIG", + "CSI_VLDO_SEL", "SoC_WLAN_SDIO_RST"; + }; +}; + +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; }; &sdhci1 { From 4111db03dc05c49ded2d9ec21b52c0ca45b59303 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:23 +0530 Subject: [PATCH 2624/7721] arm64: dts: ti: k3-am62x: Add overlay for IMX219 RPi v2 Camera (IMX219) is an 8MP camera that can be used with SK-AM62A through the 22-pin CSI-RX connector. Same overlay can be used across SK-AM62* boards that have a 15/22-pin FFC connector, so we name it with the k3-am62x- prefix. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-8-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/Makefile | 7 ++ .../boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso | 84 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index f957b5f741ff..fd9166497c32 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -35,6 +35,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb # Common overlays for SK-AM62* family of boards dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-tevi-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-imx219.dtbo # Boards with AM64x SoC dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb @@ -91,18 +92,24 @@ k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-ov5640.dtbo k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +k3-am625-sk-csi2-imx219-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \ k3-am62x-sk-csi2-ov5640.dtbo k3-am625-sk-csi2-tevi-ov5640-dtbs := k3-am625-sk.dtb \ k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am62a7-sk-csi2-imx219-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \ k3-am62x-sk-csi2-ov5640.dtbo k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \ k3-am62x-sk-csi2-tevi-ov5640.dtbo dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ k3-am625-beagleplay-csi2-tevi-ov5640.dtb \ + k3-am625-sk-csi2-imx219.dtb \ k3-am625-sk-csi2-ov5640.dtb \ k3-am625-sk-csi2-tevi-ov5640.dtb \ + k3-am62a7-sk-csi2-imx219.dtb \ k3-am62a7-sk-csi2-ov5640.dtb \ k3-am62a7-sk-csi2-tevi-ov5640.dtb diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso new file mode 100644 index 000000000000..6f4cd73c2f43 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 (RPi v2) Camera Module + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed: imx219-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + reset-gpios = <&exp1 13 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; From b0044823a6607e535fdb083c89f487fbf183b171 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Fri, 1 Dec 2023 10:39:24 +0530 Subject: [PATCH 2625/7721] arm64: dts: ti: Use OF_ALL_DTBS for combined blobs Combined dtb builds are only useful for making sure that the overlay applies cleanly on the base dtb. So we move all such combined blobs under a `dtb- +=` section that is only built when CONFIG_OF_ALL_DTBS is enabled. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20231201-csi_dts-v3-9-9f06f31080fe@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/Makefile | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index fd9166497c32..5ef49b02c71f 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -9,8 +9,6 @@ # alphabetically. # Boards with AM62x SoC -k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo -k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo @@ -23,8 +21,6 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-hdmi-audio.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-hdmi-audio.dtb # Boards with AM62Ax SoC dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb @@ -36,20 +32,15 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-hdmi-audio.dtbo # Boards with AM64x SoC dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-phyboard-electra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl.dtb - -k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo -k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo - -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-wlan.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo # Boards with AM65x SoC k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb k3-am654-base-board-rocktech-rk101-panel.dtbo @@ -98,26 +89,36 @@ k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \ k3-am62x-sk-csi2-ov5640.dtbo k3-am625-sk-csi2-tevi-ov5640-dtbs := k3-am625-sk.dtb \ k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo k3-am62a7-sk-csi2-imx219-dtbs := k3-am62a7-sk.dtb \ k3-am62x-sk-csi2-imx219.dtbo k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \ k3-am62x-sk-csi2-ov5640.dtbo k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \ k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ k3-am625-beagleplay-csi2-tevi-ov5640.dtb \ k3-am625-sk-csi2-imx219.dtb \ k3-am625-sk-csi2-ov5640.dtb \ k3-am625-sk-csi2-tevi-ov5640.dtb \ + k3-am625-sk-hdmi-audio.dtb \ + k3-am62-lp-sk-hdmi-audio.dtb \ k3-am62a7-sk-csi2-imx219.dtb \ k3-am62a7-sk-csi2-ov5640.dtb \ - k3-am62a7-sk-csi2-tevi-ov5640.dtb + k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb \ + k3-am642-tqma64xxl-mbax4xxl-wlan.dtb # Enable support for device-tree overlays DTC_FLAGS_k3-am625-beagleplay += -@ DTC_FLAGS_k3-am625-sk += -@ DTC_FLAGS_k3-am62-lp-sk += -@ DTC_FLAGS_k3-am62a7-sk += -@ +DTC_FLAGS_k3-am642-tqma64xxl-mbax4xxl += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ From 41f6f64e6999a837048b1bd13a2f8742964eca6b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:39 -0800 Subject: [PATCH 2626/7721] bpf: support non-r10 register spill/fill to/from stack in precision tracking Use instruction (jump) history to record instructions that performed register spill/fill to/from stack, regardless if this was done through read-only r10 register, or any other register after copying r10 into it *and* potentially adjusting offset. To make this work reliably, we push extra per-instruction flags into instruction history, encoding stack slot index (spi) and stack frame number in extra 10 bit flags we take away from prev_idx in instruction history. We don't touch idx field for maximum performance, as it's checked most frequently during backtracking. This change removes basically the last remaining practical limitation of precision backtracking logic in BPF verifier. It fixes known deficiencies, but also opens up new opportunities to reduce number of verified states, explored in the subsequent patches. There are only three differences in selftests' BPF object files according to veristat, all in the positive direction (less states). File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) -------------------------------------- ------------- --------- --------- ------------- ---------- ---------- ------------- test_cls_redirect_dynptr.bpf.linked3.o cls_redirect 2987 2864 -123 (-4.12%) 240 231 -9 (-3.75%) xdp_synproxy_kern.bpf.linked3.o syncookie_tc 82848 82661 -187 (-0.23%) 5107 5073 -34 (-0.67%) xdp_synproxy_kern.bpf.linked3.o syncookie_xdp 85116 84964 -152 (-0.18%) 5162 5130 -32 (-0.62%) Note, I avoided renaming jmp_history to more generic insn_hist to minimize number of lines changed and potential merge conflicts between bpf and bpf-next trees. Notice also cur_hist_entry pointer reset to NULL at the beginning of instruction verification loop. This pointer avoids the problem of relying on last jump history entry's insn_idx to determine whether we already have entry for current instruction or not. It can happen that we added jump history entry because current instruction is_jmp_point(), but also we need to add instruction flags for stack access. In this case, we don't want to entries, so we need to reuse last added entry, if it is present. Relying on insn_idx comparison has the same ambiguity problem as the one that was fixed recently in [0], so we avoid that. [0] https://patchwork.kernel.org/project/netdevbpf/patch/20231110002638.4168352-3-andrii@kernel.org/ Acked-by: Eduard Zingerman Reported-by: Tao Lyu Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 33 +++- kernel/bpf/verifier.c | 175 ++++++++++-------- .../bpf/progs/verifier_subprog_precision.c | 23 ++- .../testing/selftests/bpf/verifier/precise.c | 38 ++-- 4 files changed, 170 insertions(+), 99 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 3378cc753061..bada59812e00 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -325,12 +325,34 @@ struct bpf_func_state { int allocated_stack; }; -struct bpf_idx_pair { - u32 prev_idx; - u32 idx; +#define MAX_CALL_FRAMES 8 + +/* instruction history flags, used in bpf_jmp_history_entry.flags field */ +enum { + /* instruction references stack slot through PTR_TO_STACK register; + * we also store stack's frame number in lower 3 bits (MAX_CALL_FRAMES is 8) + * and accessed stack slot's index in next 6 bits (MAX_BPF_STACK is 512, + * 8 bytes per slot, so slot index (spi) is [0, 63]) + */ + INSN_F_FRAMENO_MASK = 0x7, /* 3 bits */ + + INSN_F_SPI_MASK = 0x3f, /* 6 bits */ + INSN_F_SPI_SHIFT = 3, /* shifted 3 bits to the left */ + + INSN_F_STACK_ACCESS = BIT(9), /* we need 10 bits total */ +}; + +static_assert(INSN_F_FRAMENO_MASK + 1 >= MAX_CALL_FRAMES); +static_assert(INSN_F_SPI_MASK + 1 >= MAX_BPF_STACK / 8); + +struct bpf_jmp_history_entry { + u32 idx; + /* insn idx can't be bigger than 1 million */ + u32 prev_idx : 22; + /* special flags, e.g., whether insn is doing register stack spill/load */ + u32 flags : 10; }; -#define MAX_CALL_FRAMES 8 /* Maximum number of register states that can exist at once */ #define BPF_ID_MAP_SIZE ((MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) * MAX_CALL_FRAMES) struct bpf_verifier_state { @@ -413,7 +435,7 @@ struct bpf_verifier_state { * For most states jmp_history_cnt is [0-3]. * For loops can go up to ~40. */ - struct bpf_idx_pair *jmp_history; + struct bpf_jmp_history_entry *jmp_history; u32 jmp_history_cnt; u32 dfs_depth; u32 callback_unroll_depth; @@ -656,6 +678,7 @@ struct bpf_verifier_env { int cur_stack; } cfg; struct backtrack_state bt; + struct bpf_jmp_history_entry *cur_hist_ent; u32 pass_cnt; /* number of times do_check() was called */ u32 subprog_cnt; /* number of instructions analyzed by the verifier */ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1ed39665f802..9bc16dc66465 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1355,8 +1355,8 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state, int i, err; dst_state->jmp_history = copy_array(dst_state->jmp_history, src->jmp_history, - src->jmp_history_cnt, sizeof(struct bpf_idx_pair), - GFP_USER); + src->jmp_history_cnt, sizeof(*dst_state->jmp_history), + GFP_USER); if (!dst_state->jmp_history) return -ENOMEM; dst_state->jmp_history_cnt = src->jmp_history_cnt; @@ -3221,6 +3221,21 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, return __check_reg_arg(env, state->regs, regno, t); } +static int insn_stack_access_flags(int frameno, int spi) +{ + return INSN_F_STACK_ACCESS | (spi << INSN_F_SPI_SHIFT) | frameno; +} + +static int insn_stack_access_spi(int insn_flags) +{ + return (insn_flags >> INSN_F_SPI_SHIFT) & INSN_F_SPI_MASK; +} + +static int insn_stack_access_frameno(int insn_flags) +{ + return insn_flags & INSN_F_FRAMENO_MASK; +} + static void mark_jmp_point(struct bpf_verifier_env *env, int idx) { env->insn_aux_data[idx].jmp_point = true; @@ -3232,28 +3247,51 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx) } /* for any branch, call, exit record the history of jmps in the given state */ -static int push_jmp_history(struct bpf_verifier_env *env, - struct bpf_verifier_state *cur) +static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_state *cur, + int insn_flags) { u32 cnt = cur->jmp_history_cnt; - struct bpf_idx_pair *p; + struct bpf_jmp_history_entry *p; size_t alloc_size; - if (!is_jmp_point(env, env->insn_idx)) + /* combine instruction flags if we already recorded this instruction */ + if (env->cur_hist_ent) { + /* atomic instructions push insn_flags twice, for READ and + * WRITE sides, but they should agree on stack slot + */ + WARN_ONCE((env->cur_hist_ent->flags & insn_flags) && + (env->cur_hist_ent->flags & insn_flags) != insn_flags, + "verifier insn history bug: insn_idx %d cur flags %x new flags %x\n", + env->insn_idx, env->cur_hist_ent->flags, insn_flags); + env->cur_hist_ent->flags |= insn_flags; return 0; + } cnt++; alloc_size = kmalloc_size_roundup(size_mul(cnt, sizeof(*p))); p = krealloc(cur->jmp_history, alloc_size, GFP_USER); if (!p) return -ENOMEM; - p[cnt - 1].idx = env->insn_idx; - p[cnt - 1].prev_idx = env->prev_insn_idx; cur->jmp_history = p; + + p = &cur->jmp_history[cnt - 1]; + p->idx = env->insn_idx; + p->prev_idx = env->prev_insn_idx; + p->flags = insn_flags; cur->jmp_history_cnt = cnt; + env->cur_hist_ent = p; + return 0; } +static struct bpf_jmp_history_entry *get_jmp_hist_entry(struct bpf_verifier_state *st, + u32 hist_end, int insn_idx) +{ + if (hist_end > 0 && st->jmp_history[hist_end - 1].idx == insn_idx) + return &st->jmp_history[hist_end - 1]; + return NULL; +} + /* Backtrack one insn at a time. If idx is not at the top of recorded * history then previous instruction came from straight line execution. * Return -ENOENT if we exhausted all instructions within given state. @@ -3415,9 +3453,14 @@ static inline bool bt_is_reg_set(struct backtrack_state *bt, u32 reg) return bt->reg_masks[bt->frame] & (1 << reg); } +static inline bool bt_is_frame_slot_set(struct backtrack_state *bt, u32 frame, u32 slot) +{ + return bt->stack_masks[frame] & (1ull << slot); +} + static inline bool bt_is_slot_set(struct backtrack_state *bt, u32 slot) { - return bt->stack_masks[bt->frame] & (1ull << slot); + return bt_is_frame_slot_set(bt, bt->frame, slot); } /* format registers bitmask, e.g., "r0,r2,r4" for 0x15 mask */ @@ -3471,7 +3514,7 @@ static bool calls_callback(struct bpf_verifier_env *env, int insn_idx); * - *was* processed previously during backtracking. */ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, - struct backtrack_state *bt) + struct bpf_jmp_history_entry *hist, struct backtrack_state *bt) { const struct bpf_insn_cbs cbs = { .cb_call = disasm_kfunc_name, @@ -3484,7 +3527,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, u8 mode = BPF_MODE(insn->code); u32 dreg = insn->dst_reg; u32 sreg = insn->src_reg; - u32 spi, i; + u32 spi, i, fr; if (insn->code == 0) return 0; @@ -3545,20 +3588,15 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, * by 'precise' mark in corresponding register of this state. * No further tracking necessary. */ - if (insn->src_reg != BPF_REG_FP) + if (!hist || !(hist->flags & INSN_F_STACK_ACCESS)) return 0; - /* dreg = *(u64 *)[fp - off] was a fill from the stack. * that [fp - off] slot contains scalar that needs to be * tracked with precision */ - spi = (-insn->off - 1) / BPF_REG_SIZE; - if (spi >= 64) { - verbose(env, "BUG spi %d\n", spi); - WARN_ONCE(1, "verifier backtracking bug"); - return -EFAULT; - } - bt_set_slot(bt, spi); + spi = insn_stack_access_spi(hist->flags); + fr = insn_stack_access_frameno(hist->flags); + bt_set_frame_slot(bt, fr, spi); } else if (class == BPF_STX || class == BPF_ST) { if (bt_is_reg_set(bt, dreg)) /* stx & st shouldn't be using _scalar_ dst_reg @@ -3567,17 +3605,13 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, */ return -ENOTSUPP; /* scalars can only be spilled into stack */ - if (insn->dst_reg != BPF_REG_FP) + if (!hist || !(hist->flags & INSN_F_STACK_ACCESS)) return 0; - spi = (-insn->off - 1) / BPF_REG_SIZE; - if (spi >= 64) { - verbose(env, "BUG spi %d\n", spi); - WARN_ONCE(1, "verifier backtracking bug"); - return -EFAULT; - } - if (!bt_is_slot_set(bt, spi)) + spi = insn_stack_access_spi(hist->flags); + fr = insn_stack_access_frameno(hist->flags); + if (!bt_is_frame_slot_set(bt, fr, spi)) return 0; - bt_clear_slot(bt, spi); + bt_clear_frame_slot(bt, fr, spi); if (class == BPF_STX) bt_set_reg(bt, sreg); } else if (class == BPF_JMP || class == BPF_JMP32) { @@ -3621,10 +3655,14 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } - /* we don't track register spills perfectly, - * so fallback to force-precise instead of failing */ - if (bt_stack_mask(bt) != 0) - return -ENOTSUPP; + /* we are now tracking register spills correctly, + * so any instance of leftover slots is a bug + */ + if (bt_stack_mask(bt) != 0) { + verbose(env, "BUG stack slots %llx\n", bt_stack_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug (subprog leftover stack slots)"); + return -EFAULT; + } /* propagate r1-r5 to the caller */ for (i = BPF_REG_1; i <= BPF_REG_5; i++) { if (bt_is_reg_set(bt, i)) { @@ -3649,8 +3687,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } - if (bt_stack_mask(bt) != 0) - return -ENOTSUPP; + if (bt_stack_mask(bt) != 0) { + verbose(env, "BUG stack slots %llx\n", bt_stack_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug (callback leftover stack slots)"); + return -EFAULT; + } /* clear r1-r5 in callback subprog's mask */ for (i = BPF_REG_1; i <= BPF_REG_5; i++) bt_clear_reg(bt, i); @@ -4087,6 +4128,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) for (;;) { DECLARE_BITMAP(mask, 64); u32 history = st->jmp_history_cnt; + struct bpf_jmp_history_entry *hist; if (env->log.level & BPF_LOG_LEVEL2) { verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d subseq_idx %d \n", @@ -4150,7 +4192,8 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) err = 0; skip_first = false; } else { - err = backtrack_insn(env, i, subseq_idx, bt); + hist = get_jmp_hist_entry(st, history, i); + err = backtrack_insn(env, i, subseq_idx, hist, bt); } if (err == -ENOTSUPP) { mark_all_scalars_precise(env, env->cur_state); @@ -4203,22 +4246,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); for_each_set_bit(i, mask, 64) { if (i >= func->allocated_stack / BPF_REG_SIZE) { - /* the sequence of instructions: - * 2: (bf) r3 = r10 - * 3: (7b) *(u64 *)(r3 -8) = r0 - * 4: (79) r4 = *(u64 *)(r10 -8) - * doesn't contain jmps. It's backtracked - * as a single block. - * During backtracking insn 3 is not recognized as - * stack access, so at the end of backtracking - * stack slot fp-8 is still marked in stack_mask. - * However the parent state may not have accessed - * fp-8 and it's "unallocated" stack space. - * In such case fallback to conservative. - */ - mark_all_scalars_precise(env, env->cur_state); - bt_reset(bt); - return 0; + verbose(env, "BUG backtracking (stack slot %d, total slots %d)\n", + i, func->allocated_stack / BPF_REG_SIZE); + WARN_ONCE(1, "verifier backtracking bug (stack slot out of bounds)"); + return -EFAULT; } if (!is_spilled_scalar_reg(&func->stack[i])) { @@ -4391,7 +4422,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err; struct bpf_insn *insn = &env->prog->insnsi[insn_idx]; struct bpf_reg_state *reg = NULL; - u32 dst_reg = insn->dst_reg; + int insn_flags = insn_stack_access_flags(state->frameno, spi); err = grow_stack_state(state, round_up(slot + 1, BPF_REG_SIZE)); if (err) @@ -4432,17 +4463,6 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, mark_stack_slot_scratched(env, spi); if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && !register_is_null(reg) && env->bpf_capable) { - if (dst_reg != BPF_REG_FP) { - /* The backtracking logic can only recognize explicit - * stack slot address like [fp - 8]. Other spill of - * scalar via different register has to be conservative. - * Backtrack from here and mark all registers as precise - * that contributed into 'reg' being a constant. - */ - err = mark_chain_precision(env, value_regno); - if (err) - return err; - } save_register_state(state, spi, reg, size); /* Break the relation on a narrowing spill. */ if (fls64(reg->umax_value) > BITS_PER_BYTE * size) @@ -4454,6 +4474,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, __mark_reg_known(&fake_reg, insn->imm); fake_reg.type = SCALAR_VALUE; save_register_state(state, spi, &fake_reg, size); + insn_flags = 0; /* not a register spill */ } else if (reg && is_spillable_regtype(reg->type)) { /* register containing pointer is being spilled into stack */ if (size != BPF_REG_SIZE) { @@ -4499,9 +4520,12 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, /* Mark slots affected by this stack write. */ for (i = 0; i < size; i++) - state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] = - type; + state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] = type; + insn_flags = 0; /* not a register spill */ } + + if (insn_flags) + return push_jmp_history(env, env->cur_state, insn_flags); return 0; } @@ -4694,6 +4718,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, int i, slot = -off - 1, spi = slot / BPF_REG_SIZE; struct bpf_reg_state *reg; u8 *stype, type; + int insn_flags = insn_stack_access_flags(reg_state->frameno, spi); stype = reg_state->stack[spi].slot_type; reg = ®_state->stack[spi].spilled_ptr; @@ -4739,12 +4764,10 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, return -EACCES; } mark_reg_unknown(env, state->regs, dst_regno); + insn_flags = 0; /* not restoring original register state */ } state->regs[dst_regno].live |= REG_LIVE_WRITTEN; - return 0; - } - - if (dst_regno >= 0) { + } else if (dst_regno >= 0) { /* restore register state from stack */ copy_register_state(&state->regs[dst_regno], reg); /* mark reg as written since spilled pointer state likely @@ -4780,7 +4803,10 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); if (dst_regno >= 0) mark_reg_stack_read(env, reg_state, off, off + size, dst_regno); + insn_flags = 0; /* we are not restoring spilled register */ } + if (insn_flags) + return push_jmp_history(env, env->cur_state, insn_flags); return 0; } @@ -6940,7 +6966,6 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i BPF_SIZE(insn->code), BPF_WRITE, -1, true, false); if (err) return err; - return 0; } @@ -16910,7 +16935,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) * the precision needs to be propagated back in * the current state. */ - err = err ? : push_jmp_history(env, cur); + if (is_jmp_point(env, env->insn_idx)) + err = err ? : push_jmp_history(env, cur, 0); err = err ? : propagate_precision(env, &sl->state); if (err) return err; @@ -17135,6 +17161,9 @@ static int do_check(struct bpf_verifier_env *env) u8 class; int err; + /* reset current history entry on each new instruction */ + env->cur_hist_ent = NULL; + env->prev_insn_idx = prev_insn_idx; if (env->insn_idx >= insn_cnt) { verbose(env, "invalid insn idx %d insn_cnt %d\n", @@ -17174,7 +17203,7 @@ static int do_check(struct bpf_verifier_env *env) } if (is_jmp_point(env, env->insn_idx)) { - err = push_jmp_history(env, state); + err = push_jmp_history(env, state, 0); if (err) return err; } diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index 0dfe3f8b69ac..eba98fab2f54 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -589,11 +589,24 @@ static __u64 subprog_spill_reg_precise(void) SEC("?raw_tp") __success __log_level(2) -/* precision backtracking can't currently handle stack access not through r10, - * so we won't be able to mark stack slot fp-8 as precise, and so will - * fallback to forcing all as precise - */ -__msg("mark_precise: frame0: falling back to forcing all scalars precise") +__msg("10: (0f) r1 += r7") +__msg("mark_precise: frame0: last_idx 10 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r7 stack= before 9: (bf) r1 = r8") +__msg("mark_precise: frame0: regs=r7 stack= before 8: (27) r7 *= 4") +__msg("mark_precise: frame0: regs=r7 stack= before 7: (79) r7 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=2 R6_w=1 R8_rw=map_value(map=.data.vals,ks=4,vs=16) R10=fp0 fp-8_rw=P1") +__msg("mark_precise: frame0: last_idx 18 first_idx 0 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 17: (0f) r0 += r2") +__msg("mark_precise: frame1: regs= stack= before 16: (79) r2 = *(u64 *)(r1 +0)") +__msg("mark_precise: frame1: regs= stack= before 15: (79) r0 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame1: regs= stack= before 14: (7b) *(u64 *)(r10 -16) = r2") +__msg("mark_precise: frame1: regs= stack= before 13: (7b) *(u64 *)(r1 +0) = r2") +__msg("mark_precise: frame1: regs=r2 stack= before 6: (85) call pc+6") +__msg("mark_precise: frame0: regs=r2 stack= before 5: (bf) r2 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (07) r1 += -8") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (bf) r1 = r10") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1") __naked int subprog_spill_into_parent_stack_slot_precise(void) { asm volatile ( diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 0d84dd1f38b6..8a2ff81d8350 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -140,10 +140,11 @@ .result = REJECT, }, { - "precise: ST insn causing spi > allocated_stack", + "precise: ST zero to stack insn is supported", .insns = { BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), + /* not a register spill, so we stop precision propagation for R4 here */ BPF_ST_MEM(BPF_DW, BPF_REG_3, -8, 0), BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), BPF_MOV64_IMM(BPF_REG_0, -1), @@ -157,11 +158,11 @@ mark_precise: frame0: last_idx 4 first_idx 2\ mark_precise: frame0: regs=r4 stack= before 4\ mark_precise: frame0: regs=r4 stack= before 3\ - mark_precise: frame0: regs= stack=-8 before 2\ - mark_precise: frame0: falling back to forcing all scalars precise\ - force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - mark_precise: frame0: parent state regs= stack=:", + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 4 first_idx 2\ + mark_precise: frame0: regs=r0 stack= before 4\ + 5: R0=-1 R4=0", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -169,6 +170,8 @@ "precise: STX insn causing spi > allocated_stack", .insns = { BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), + /* make later reg spill more interesting by having somewhat known scalar */ + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xff), BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, -8), @@ -179,18 +182,21 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ + .errstr = "mark_precise: frame0: last_idx 7 first_idx 7\ mark_precise: frame0: parent state regs=r4 stack=:\ - mark_precise: frame0: last_idx 5 first_idx 3\ - mark_precise: frame0: regs=r4 stack= before 5\ - mark_precise: frame0: regs=r4 stack= before 4\ - mark_precise: frame0: regs= stack=-8 before 3\ - mark_precise: frame0: falling back to forcing all scalars precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - mark_precise: frame0: last_idx 6 first_idx 6\ + mark_precise: frame0: last_idx 6 first_idx 4\ + mark_precise: frame0: regs=r4 stack= before 6: (b7) r0 = -1\ + mark_precise: frame0: regs=r4 stack= before 5: (79) r4 = *(u64 *)(r10 -8)\ + mark_precise: frame0: regs= stack=-8 before 4: (7b) *(u64 *)(r3 -8) = r0\ + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 3 first_idx 3\ + mark_precise: frame0: regs=r0 stack= before 3: (55) if r3 != 0x7b goto pc+0\ + mark_precise: frame0: regs=r0 stack= before 2: (bf) r3 = r10\ + mark_precise: frame0: regs=r0 stack= before 1: (57) r0 &= 255\ + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 0 first_idx 0\ + mark_precise: frame0: regs=r0 stack= before 0: (85) call bpf_get_prandom_u32#7\ + mark_precise: frame0: last_idx 7 first_idx 7\ mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, From 876301881c436bf38e83a2c0d276a24b642e4aab Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:40 -0800 Subject: [PATCH 2627/7721] selftests/bpf: add stack access precision test Add a new selftests that validates precision tracking for stack access instruction, using both r10-based and non-r10-based accesses. For non-r10 ones we also make sure to have non-zero var_off to validate that final stack offset is tracked properly in instruction history information inside verifier. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/progs/verifier_subprog_precision.c | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index eba98fab2f54..6f5d19665cf6 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -641,14 +641,68 @@ __naked int subprog_spill_into_parent_stack_slot_precise(void) ); } -__naked __noinline __used -static __u64 subprog_with_checkpoint(void) +SEC("?raw_tp") +__success __log_level(2) +__msg("17: (0f) r1 += r0") +__msg("mark_precise: frame0: last_idx 17 first_idx 0 subseq_idx -1") +__msg("mark_precise: frame0: regs=r0 stack= before 16: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 15: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 14: (79) r0 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 13: (7b) *(u64 *)(r7 -8) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 12: (79) r0 = *(u64 *)(r8 +16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (7b) *(u64 *)(r8 +16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 10: (79) r0 = *(u64 *)(r7 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 8: (07) r8 += -32") +__msg("mark_precise: frame0: regs=r0 stack= before 7: (bf) r8 = r10") +__msg("mark_precise: frame0: regs=r0 stack= before 6: (07) r7 += -8") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (bf) r7 = r10") +__msg("mark_precise: frame0: regs=r0 stack= before 21: (95) exit") +__msg("mark_precise: frame1: regs=r0 stack= before 20: (bf) r0 = r1") +__msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+15") +__msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1") +__naked int stack_slot_aliases_precision(void) { asm volatile ( - "r0 = 0;" - /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */ - "goto +0;" + "r6 = 1;" + /* pass r6 through r1 into subprog to get it back as r0; + * this whole chain will have to be marked as precise later + */ + "r1 = r6;" + "call identity_subprog;" + /* let's setup two registers that are aliased to r10 */ + "r7 = r10;" + "r7 += -8;" /* r7 = r10 - 8 */ + "r8 = r10;" + "r8 += -32;" /* r8 = r10 - 32 */ + /* now spill subprog's return value (a r6 -> r1 -> r0 chain) + * a few times through different stack pointer regs, making + * sure to use r10, r7, and r8 both in LDX and STX insns, and + * *importantly* also using a combination of const var_off and + * insn->off to validate that we record final stack slot + * correctly, instead of relying on just insn->off derivation, + * which is only valid for r10-based stack offset + */ + "*(u64 *)(r10 - 16) = r0;" + "r0 = *(u64 *)(r7 - 8);" /* r7 - 8 == r10 - 16 */ + "*(u64 *)(r8 + 16) = r0;" /* r8 + 16 = r10 - 16 */ + "r0 = *(u64 *)(r8 + 16);" + "*(u64 *)(r7 - 8) = r0;" + "r0 = *(u64 *)(r10 - 16);" + /* get ready to use r0 as an index into array to force precision */ + "r0 *= 4;" + "r1 = %[vals];" + /* here r0->r1->r6 chain is forced to be precise and has to be + * propagated back to the beginning, including through the + * subprog call and all the stack spills and loads + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" ); } From ab125ed3ec1c10ccc36bc98c7a4256ad114a3dae Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:41 -0800 Subject: [PATCH 2628/7721] bpf: fix check for attempt to corrupt spilled pointer When register is spilled onto a stack as a 1/2/4-byte register, we set slot_type[BPF_REG_SIZE - 1] (plus potentially few more below it, depending on actual spill size). So to check if some stack slot has spilled register we need to consult slot_type[7], not slot_type[0]. To avoid the need to remember and double-check this in the future, just use is_spilled_reg() helper. Fixes: 27113c59b6d0 ("bpf: Check the other end of slot_type for STACK_SPILL") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9bc16dc66465..3edca06de9fd 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4431,7 +4431,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, * so it's aligned access and [off, off + size) are within stack limits */ if (!env->allow_ptr_leaks && - state->stack[spi].slot_type[0] == STACK_SPILL && + is_spilled_reg(&state->stack[spi]) && size != BPF_REG_SIZE) { verbose(env, "attempt to corrupt spilled pointer on stack\n"); return -EACCES; From eaf18febd6ebc381aeb61543705148b3e28c7c47 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:42 -0800 Subject: [PATCH 2629/7721] bpf: preserve STACK_ZERO slots on partial reg spills Instead of always forcing STACK_ZERO slots to STACK_MISC, preserve it in situations where this is possible. E.g., when spilling register as 1/2/4-byte subslots on the stack, all the remaining bytes in the stack slot do not automatically become unknown. If we knew they contained zeroes, we can preserve those STACK_ZERO markers. Add a helper mark_stack_slot_misc(), similar to scrub_spilled_slot(), but that doesn't overwrite either STACK_INVALID nor STACK_ZERO. Note that we need to take into account possibility of being in unprivileged mode, in which case STACK_INVALID is forced to STACK_MISC for correctness, as treating STACK_INVALID as equivalent STACK_MISC is only enabled in privileged mode. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3edca06de9fd..93de39a6e36e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1144,6 +1144,21 @@ static bool is_spilled_scalar_reg(const struct bpf_stack_state *stack) stack->spilled_ptr.type == SCALAR_VALUE; } +/* Mark stack slot as STACK_MISC, unless it is already STACK_INVALID, in which + * case they are equivalent, or it's STACK_ZERO, in which case we preserve + * more precise STACK_ZERO. + * Note, in uprivileged mode leaving STACK_INVALID is wrong, so we take + * env->allow_ptr_leaks into account and force STACK_MISC, if necessary. + */ +static void mark_stack_slot_misc(struct bpf_verifier_env *env, u8 *stype) +{ + if (*stype == STACK_ZERO) + return; + if (env->allow_ptr_leaks && *stype == STACK_INVALID) + return; + *stype = STACK_MISC; +} + static void scrub_spilled_slot(u8 *stype) { if (*stype != STACK_INVALID) @@ -4386,7 +4401,8 @@ static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_ dst->live = live; } -static void save_register_state(struct bpf_func_state *state, +static void save_register_state(struct bpf_verifier_env *env, + struct bpf_func_state *state, int spi, struct bpf_reg_state *reg, int size) { @@ -4401,7 +4417,7 @@ static void save_register_state(struct bpf_func_state *state, /* size < 8 bytes spill */ for (; i; i--) - scrub_spilled_slot(&state->stack[spi].slot_type[i - 1]); + mark_stack_slot_misc(env, &state->stack[spi].slot_type[i - 1]); } static bool is_bpf_st_mem(struct bpf_insn *insn) @@ -4463,7 +4479,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, mark_stack_slot_scratched(env, spi); if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && !register_is_null(reg) && env->bpf_capable) { - save_register_state(state, spi, reg, size); + save_register_state(env, state, spi, reg, size); /* Break the relation on a narrowing spill. */ if (fls64(reg->umax_value) > BITS_PER_BYTE * size) state->stack[spi].spilled_ptr.id = 0; @@ -4473,7 +4489,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, __mark_reg_known(&fake_reg, insn->imm); fake_reg.type = SCALAR_VALUE; - save_register_state(state, spi, &fake_reg, size); + save_register_state(env, state, spi, &fake_reg, size); insn_flags = 0; /* not a register spill */ } else if (reg && is_spillable_regtype(reg->type)) { /* register containing pointer is being spilled into stack */ @@ -4486,7 +4502,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, verbose(env, "cannot spill pointers to stack into stack frame of the caller\n"); return -EINVAL; } - save_register_state(state, spi, reg, size); + save_register_state(env, state, spi, reg, size); } else { u8 type = STACK_MISC; @@ -4757,6 +4773,8 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, continue; if (type == STACK_MISC) continue; + if (type == STACK_ZERO) + continue; if (type == STACK_INVALID && env->allow_uninit_stack) continue; verbose(env, "invalid read from stack off %d+%d size %d\n", From b33ceb6a3d2ee07fdd836373383a6d4783581324 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:43 -0800 Subject: [PATCH 2630/7721] selftests/bpf: validate STACK_ZERO is preserved on subreg spill Add tests validating that STACK_ZERO slots are preserved when slot is partially overwritten with subregister spill. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 6115520154e3..d9dabae81176 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -4,6 +4,7 @@ #include #include #include "bpf_misc.h" +#include <../../../tools/include/linux/filter.h> struct { __uint(type, BPF_MAP_TYPE_RINGBUF); @@ -450,4 +451,43 @@ l0_%=: r1 >>= 16; \ : __clobber_all); } +SEC("raw_tp") +__log_level(2) +__success +__msg("fp-8=0m??mmmm") +__msg("fp-16=00mm??mm") +__msg("fp-24=00mm???m") +__naked void spill_subregs_preserve_stack_zero(void) +{ + asm volatile ( + "call %[bpf_get_prandom_u32];" + + /* 32-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp1_u8_st_zero];" /* ZERO, LLVM-18+: *(u8 *)(r10 -1) = 0; */ + "*(u8 *)(r10 -2) = r0;" /* MISC */ + /* fp-3 and fp-4 stay INVALID */ + "*(u32 *)(r10 -8) = r0;" + + /* 16-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp10_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r10 -10) = 0; */ + "*(u16 *)(r10 -12) = r0;" /* MISC */ + /* fp-13 and fp-14 stay INVALID */ + "*(u16 *)(r10 -16) = r0;" + + /* 8-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp18_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r18 -10) = 0; */ + "*(u16 *)(r10 -20) = r0;" /* MISC */ + /* fp-21, fp-22, and fp-23 stay INVALID */ + "*(u8 *)(r10 -24) = r0;" + + "r0 = 0;" + "exit;" + : + : __imm(bpf_get_prandom_u32), + __imm_insn(fp1_u8_st_zero, BPF_ST_MEM(BPF_B, BPF_REG_FP, -1, 0)), + __imm_insn(fp10_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -10, 0)), + __imm_insn(fp18_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -18, 0)) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From e322f0bcb8d371f4606eaf141c7f967e1a79bcb7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:44 -0800 Subject: [PATCH 2631/7721] bpf: preserve constant zero when doing partial register restore Similar to special handling of STACK_ZERO, when reading 1/2/4 bytes from stack from slot that has register spilled into it and that register has a constant value zero, preserve that zero and mark spilled register as precise for that. This makes spilled const zero register and STACK_ZERO cases equivalent in their behavior. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 93de39a6e36e..1ebe76c98451 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4767,22 +4767,39 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, copy_register_state(&state->regs[dst_regno], reg); state->regs[dst_regno].subreg_def = subreg_def; } else { + int spill_cnt = 0, zero_cnt = 0; + for (i = 0; i < size; i++) { type = stype[(slot - i) % BPF_REG_SIZE]; - if (type == STACK_SPILL) + if (type == STACK_SPILL) { + spill_cnt++; continue; + } if (type == STACK_MISC) continue; - if (type == STACK_ZERO) + if (type == STACK_ZERO) { + zero_cnt++; continue; + } if (type == STACK_INVALID && env->allow_uninit_stack) continue; verbose(env, "invalid read from stack off %d+%d size %d\n", off, i, size); return -EACCES; } - mark_reg_unknown(env, state->regs, dst_regno); - insn_flags = 0; /* not restoring original register state */ + + if (spill_cnt == size && + tnum_is_const(reg->var_off) && reg->var_off.value == 0) { + __mark_reg_const_zero(&state->regs[dst_regno]); + /* this IS register fill, so keep insn_flags */ + } else if (zero_cnt == size) { + /* similarly to mark_reg_stack_read(), preserve zeroes */ + __mark_reg_const_zero(&state->regs[dst_regno]); + insn_flags = 0; /* not restoring original register state */ + } else { + mark_reg_unknown(env, state->regs, dst_regno); + insn_flags = 0; /* not restoring original register state */ + } } state->regs[dst_regno].live |= REG_LIVE_WRITTEN; } else if (dst_regno >= 0) { From add1cd7f22e61756987865ada9fe95cd86569025 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:45 -0800 Subject: [PATCH 2632/7721] selftests/bpf: validate zero preservation for sub-slot loads Validate that 1-, 2-, and 4-byte loads from stack slots not aligned on 8-byte boundary still preserve zero, when loading from all-STACK_ZERO sub-slots, or when stack sub-slots are covered by spilled register with known constant zero value. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index d9dabae81176..41fd61299eab 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -490,4 +490,75 @@ __naked void spill_subregs_preserve_stack_zero(void) : __clobber_all); } +char single_byte_buf[1] SEC(".data.single_byte_buf"); + +SEC("raw_tp") +__log_level(2) +__success +__naked void partial_stack_load_preserves_zeros(void) +{ + asm volatile ( + /* fp-8 is all STACK_ZERO */ + ".8byte %[fp8_st_zero];" /* LLVM-18+: *(u64 *)(r10 -8) = 0; */ + + /* fp-16 is const zero register */ + "r0 = 0;" + "*(u64 *)(r10 -16) = r0;" + + /* load single U8 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u8 *)(r10 -1);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U8 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u8 *)(r10 -9);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U16 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u16 *)(r10 -2);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U16 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u16 *)(r10 -10);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u32 *)(r10 -4);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u32 *)(r10 -12);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* for completeness, load U64 from STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u64 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* for completeness, load U64 from ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u64 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(single_byte_buf), + __imm_insn(fp8_st_zero, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0)) + : __clobber_common); +} + char _license[] SEC("license") = "GPL"; From 18a433b62061e3d787bfc3e670fa711fecbd7cb4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:46 -0800 Subject: [PATCH 2633/7721] bpf: track aligned STACK_ZERO cases as imprecise spilled registers Now that precision backtracing is supporting register spill/fill to/from stack, there is another oportunity to be exploited here: minimizing precise STACK_ZERO cases. With a simple code change we can rely on initially imprecise register spill tracking for cases when register spilled to stack was a known zero. This is a very common case for initializing on the stack variables, including rather large structures. Often times zero has no special meaning for the subsequent BPF program logic and is often overwritten with non-zero values soon afterwards. But due to STACK_ZERO vs STACK_MISC tracking, such initial zero initialization actually causes duplication of verifier states as STACK_ZERO is clearly different than STACK_MISC or spilled SCALAR_VALUE register. The effect of this (now) trivial change is huge, as can be seen below. These are differences between BPF selftests, Cilium, and Meta-internal BPF object files relative to previous patch in this series. You can see improvements ranging from single-digit percentage improvement for instructions and states, all the way to 50-60% reduction for some of Meta-internal host agent programs, and even some Cilium programs. For Meta-internal ones I left only the differences for largest BPF object files by states/instructions, as there were too many differences in the overall output. All the differences were improvements, reducting number of states and thus instructions validated. Note, Meta-internal BPF object file names are not printed below. Many copies of balancer_ingress are actually many different configurations of Katran, so they are different BPF programs, which explains state reduction going from -16% all the way to 31%, depending on BPF program logic complexity. I also tooked a closer look at a few small-ish BPF programs to validate the behavior. Let's take bpf_iter_netrlink.bpf.o (first row below). While it's just 8 vs 5 states, verifier log is still pretty long to include it here. But the reduction in states is due to the following piece of C code: unsigned long ino; ... sk = s->sk_socket; if (!sk) { ino = 0; } else { inode = SOCK_INODE(sk); bpf_probe_read_kernel(&ino, sizeof(ino), &inode->i_ino); } BPF_SEQ_PRINTF(seq, "%-8u %-8lu\n", s->sk_drops.counter, ino); return 0; You can see that in some situations `ino` is zero-initialized, while in others it's unknown value filled out by bpf_probe_read_kernel(). Before this change code after if/else branches have to be validated twice. Once with (precise) ino == 0, due to eager STACK_ZERO logic, and then again for when ino is just STACK_MISC. But BPF_SEQ_PRINTF() doesn't care about precise value of ino, so with the change in this patch verifier is able to prune states from after one of the branches, reducing number of total states (and instructions) required for successful validation. Similar principle applies to bigger real-world applications, just at a much larger scale. SELFTESTS ========= File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) --------------------------------------- ----------------------- --------- --------- --------------- ---------- ---------- ------------- bpf_iter_netlink.bpf.linked3.o dump_netlink 148 104 -44 (-29.73%) 8 5 -3 (-37.50%) bpf_iter_unix.bpf.linked3.o dump_unix 8474 8404 -70 (-0.83%) 151 147 -4 (-2.65%) bpf_loop.bpf.linked3.o stack_check 560 324 -236 (-42.14%) 42 24 -18 (-42.86%) local_storage_bench.bpf.linked3.o get_local 120 77 -43 (-35.83%) 9 6 -3 (-33.33%) loop6.bpf.linked3.o trace_virtqueue_add_sgs 10167 9868 -299 (-2.94%) 226 206 -20 (-8.85%) pyperf600_bpf_loop.bpf.linked3.o on_event 4872 3423 -1449 (-29.74%) 322 229 -93 (-28.88%) strobemeta.bpf.linked3.o on_event 180697 176036 -4661 (-2.58%) 4780 4734 -46 (-0.96%) test_cls_redirect.bpf.linked3.o cls_redirect 65594 65401 -193 (-0.29%) 4230 4212 -18 (-0.43%) test_global_func_args.bpf.linked3.o test_cls 145 136 -9 (-6.21%) 10 9 -1 (-10.00%) test_l4lb.bpf.linked3.o balancer_ingress 4760 2612 -2148 (-45.13%) 113 102 -11 (-9.73%) test_l4lb_noinline.bpf.linked3.o balancer_ingress 4845 4877 +32 (+0.66%) 219 221 +2 (+0.91%) test_l4lb_noinline_dynptr.bpf.linked3.o balancer_ingress 2072 2087 +15 (+0.72%) 97 98 +1 (+1.03%) test_seg6_loop.bpf.linked3.o __add_egr_x 12440 9975 -2465 (-19.82%) 364 353 -11 (-3.02%) test_tcp_hdr_options.bpf.linked3.o estab 2558 2572 +14 (+0.55%) 179 180 +1 (+0.56%) test_xdp_dynptr.bpf.linked3.o _xdp_tx_iptunnel 645 596 -49 (-7.60%) 26 24 -2 (-7.69%) test_xdp_noinline.bpf.linked3.o balancer_ingress_v6 3520 3516 -4 (-0.11%) 216 216 +0 (+0.00%) xdp_synproxy_kern.bpf.linked3.o syncookie_tc 82661 81241 -1420 (-1.72%) 5073 5155 +82 (+1.62%) xdp_synproxy_kern.bpf.linked3.o syncookie_xdp 84964 82297 -2667 (-3.14%) 5130 5157 +27 (+0.53%) META-INTERNAL ============= Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) -------------------------------------- --------- --------- ----------------- ---------- ---------- --------------- balancer_ingress 27925 23608 -4317 (-15.46%) 1488 1482 -6 (-0.40%) balancer_ingress 31824 27546 -4278 (-13.44%) 1658 1652 -6 (-0.36%) balancer_ingress 32213 27935 -4278 (-13.28%) 1689 1683 -6 (-0.36%) balancer_ingress 32213 27935 -4278 (-13.28%) 1689 1683 -6 (-0.36%) balancer_ingress 31824 27546 -4278 (-13.44%) 1658 1652 -6 (-0.36%) balancer_ingress 38647 29562 -9085 (-23.51%) 2069 1835 -234 (-11.31%) balancer_ingress 38647 29562 -9085 (-23.51%) 2069 1835 -234 (-11.31%) balancer_ingress 40339 30792 -9547 (-23.67%) 2193 1934 -259 (-11.81%) balancer_ingress 37321 29055 -8266 (-22.15%) 1972 1795 -177 (-8.98%) balancer_ingress 38176 29753 -8423 (-22.06%) 2008 1831 -177 (-8.81%) balancer_ingress 29193 20910 -8283 (-28.37%) 1599 1422 -177 (-11.07%) balancer_ingress 30013 21452 -8561 (-28.52%) 1645 1447 -198 (-12.04%) balancer_ingress 28691 24290 -4401 (-15.34%) 1545 1531 -14 (-0.91%) balancer_ingress 34223 28965 -5258 (-15.36%) 1984 1875 -109 (-5.49%) balancer_ingress 35481 26158 -9323 (-26.28%) 2095 1806 -289 (-13.79%) balancer_ingress 35481 26158 -9323 (-26.28%) 2095 1806 -289 (-13.79%) balancer_ingress 35868 26455 -9413 (-26.24%) 2140 1827 -313 (-14.63%) balancer_ingress 35868 26455 -9413 (-26.24%) 2140 1827 -313 (-14.63%) balancer_ingress 35481 26158 -9323 (-26.28%) 2095 1806 -289 (-13.79%) balancer_ingress 35481 26158 -9323 (-26.28%) 2095 1806 -289 (-13.79%) balancer_ingress 34844 29485 -5359 (-15.38%) 2036 1918 -118 (-5.80%) fbflow_egress 3256 2652 -604 (-18.55%) 218 192 -26 (-11.93%) fbflow_ingress 1026 944 -82 (-7.99%) 70 63 -7 (-10.00%) sslwall_tc_egress 8424 7360 -1064 (-12.63%) 498 458 -40 (-8.03%) syar_accept_protect 15040 9539 -5501 (-36.58%) 364 220 -144 (-39.56%) syar_connect_tcp_v6 15036 9535 -5501 (-36.59%) 360 216 -144 (-40.00%) syar_connect_udp_v4 15039 9538 -5501 (-36.58%) 361 217 -144 (-39.89%) syar_connect_connect4_protect4 24805 15833 -8972 (-36.17%) 756 480 -276 (-36.51%) syar_lsm_file_open 167772 151813 -15959 (-9.51%) 1836 1667 -169 (-9.20%) syar_namespace_create_new 14805 9304 -5501 (-37.16%) 353 209 -144 (-40.79%) syar_python3_detect 17531 12030 -5501 (-31.38%) 391 247 -144 (-36.83%) syar_ssh_post_fork 16412 10911 -5501 (-33.52%) 405 261 -144 (-35.56%) syar_enter_execve 14728 9227 -5501 (-37.35%) 345 201 -144 (-41.74%) syar_enter_execveat 14728 9227 -5501 (-37.35%) 345 201 -144 (-41.74%) syar_exit_execve 16622 11121 -5501 (-33.09%) 376 232 -144 (-38.30%) syar_exit_execveat 16622 11121 -5501 (-33.09%) 376 232 -144 (-38.30%) syar_syscalls_kill 15288 9787 -5501 (-35.98%) 398 254 -144 (-36.18%) syar_task_enter_pivot_root 14898 9397 -5501 (-36.92%) 357 213 -144 (-40.34%) syar_syscalls_setreuid 16678 11177 -5501 (-32.98%) 429 285 -144 (-33.57%) syar_syscalls_setuid 16678 11177 -5501 (-32.98%) 429 285 -144 (-33.57%) syar_syscalls_process_vm_readv 14959 9458 -5501 (-36.77%) 364 220 -144 (-39.56%) syar_syscalls_process_vm_writev 15757 10256 -5501 (-34.91%) 390 246 -144 (-36.92%) do_uprobe 15519 10018 -5501 (-35.45%) 373 229 -144 (-38.61%) edgewall 179715 55783 -123932 (-68.96%) 12607 3999 -8608 (-68.28%) bictcp_state 7570 4131 -3439 (-45.43%) 496 269 -227 (-45.77%) cubictcp_state 7570 4131 -3439 (-45.43%) 496 269 -227 (-45.77%) tcp_rate_skb_delivered 447 272 -175 (-39.15%) 29 18 -11 (-37.93%) kprobe__bbr_set_state 4566 2615 -1951 (-42.73%) 209 124 -85 (-40.67%) kprobe__bictcp_state 4566 2615 -1951 (-42.73%) 209 124 -85 (-40.67%) inet_sock_set_state 1501 1337 -164 (-10.93%) 93 85 -8 (-8.60%) tcp_retransmit_skb 1145 981 -164 (-14.32%) 67 59 -8 (-11.94%) tcp_retransmit_synack 1183 951 -232 (-19.61%) 67 55 -12 (-17.91%) bpf_tcptuner 1459 1187 -272 (-18.64%) 99 80 -19 (-19.19%) tw_egress 801 776 -25 (-3.12%) 69 66 -3 (-4.35%) tw_ingress 795 770 -25 (-3.14%) 69 66 -3 (-4.35%) ttls_tc_ingress 19025 19383 +358 (+1.88%) 470 465 -5 (-1.06%) ttls_nat_egress 490 299 -191 (-38.98%) 33 20 -13 (-39.39%) ttls_nat_ingress 448 285 -163 (-36.38%) 32 21 -11 (-34.38%) tw_twfw_egress 511127 212071 -299056 (-58.51%) 16733 8504 -8229 (-49.18%) tw_twfw_ingress 500095 212069 -288026 (-57.59%) 16223 8504 -7719 (-47.58%) tw_twfw_tc_eg 511113 212064 -299049 (-58.51%) 16732 8504 -8228 (-49.18%) tw_twfw_tc_in 500095 212069 -288026 (-57.59%) 16223 8504 -7719 (-47.58%) tw_twfw_egress 12632 12435 -197 (-1.56%) 276 260 -16 (-5.80%) tw_twfw_ingress 12631 12454 -177 (-1.40%) 278 261 -17 (-6.12%) tw_twfw_tc_eg 12595 12435 -160 (-1.27%) 274 259 -15 (-5.47%) tw_twfw_tc_in 12631 12454 -177 (-1.40%) 278 261 -17 (-6.12%) tw_xdp_dump 266 209 -57 (-21.43%) 9 8 -1 (-11.11%) CILIUM ========= File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) ------------- -------------------------------- --------- --------- ---------------- ---------- ---------- -------------- bpf_host.o cil_to_netdev 6047 4578 -1469 (-24.29%) 362 249 -113 (-31.22%) bpf_host.o handle_lxc_traffic 2227 1585 -642 (-28.83%) 156 103 -53 (-33.97%) bpf_host.o tail_handle_ipv4_from_netdev 2244 1458 -786 (-35.03%) 163 106 -57 (-34.97%) bpf_host.o tail_handle_nat_fwd_ipv4 21022 10479 -10543 (-50.15%) 1289 670 -619 (-48.02%) bpf_host.o tail_handle_nat_fwd_ipv6 15433 11375 -4058 (-26.29%) 905 643 -262 (-28.95%) bpf_host.o tail_ipv4_host_policy_ingress 2219 1367 -852 (-38.40%) 161 96 -65 (-40.37%) bpf_host.o tail_nodeport_nat_egress_ipv4 22460 19862 -2598 (-11.57%) 1469 1293 -176 (-11.98%) bpf_host.o tail_nodeport_nat_ingress_ipv4 5526 3534 -1992 (-36.05%) 366 243 -123 (-33.61%) bpf_host.o tail_nodeport_nat_ingress_ipv6 5132 4256 -876 (-17.07%) 241 219 -22 (-9.13%) bpf_host.o tail_nodeport_nat_ipv6_egress 3702 3542 -160 (-4.32%) 215 205 -10 (-4.65%) bpf_lxc.o tail_handle_nat_fwd_ipv4 21022 10479 -10543 (-50.15%) 1289 670 -619 (-48.02%) bpf_lxc.o tail_handle_nat_fwd_ipv6 15433 11375 -4058 (-26.29%) 905 643 -262 (-28.95%) bpf_lxc.o tail_ipv4_ct_egress 5073 3374 -1699 (-33.49%) 262 172 -90 (-34.35%) bpf_lxc.o tail_ipv4_ct_ingress 5093 3385 -1708 (-33.54%) 262 172 -90 (-34.35%) bpf_lxc.o tail_ipv4_ct_ingress_policy_only 5093 3385 -1708 (-33.54%) 262 172 -90 (-34.35%) bpf_lxc.o tail_ipv6_ct_egress 4593 3878 -715 (-15.57%) 194 151 -43 (-22.16%) bpf_lxc.o tail_ipv6_ct_ingress 4606 3891 -715 (-15.52%) 194 151 -43 (-22.16%) bpf_lxc.o tail_ipv6_ct_ingress_policy_only 4606 3891 -715 (-15.52%) 194 151 -43 (-22.16%) bpf_lxc.o tail_nodeport_nat_ingress_ipv4 5526 3534 -1992 (-36.05%) 366 243 -123 (-33.61%) bpf_lxc.o tail_nodeport_nat_ingress_ipv6 5132 4256 -876 (-17.07%) 241 219 -22 (-9.13%) bpf_overlay.o tail_handle_nat_fwd_ipv4 20524 10114 -10410 (-50.72%) 1271 638 -633 (-49.80%) bpf_overlay.o tail_nodeport_nat_egress_ipv4 22718 19490 -3228 (-14.21%) 1475 1275 -200 (-13.56%) bpf_overlay.o tail_nodeport_nat_ingress_ipv4 5526 3534 -1992 (-36.05%) 366 243 -123 (-33.61%) bpf_overlay.o tail_nodeport_nat_ingress_ipv6 5132 4256 -876 (-17.07%) 241 219 -22 (-9.13%) bpf_overlay.o tail_nodeport_nat_ipv6_egress 3638 3548 -90 (-2.47%) 209 203 -6 (-2.87%) bpf_overlay.o tail_rev_nodeport_lb4 4368 3820 -548 (-12.55%) 248 215 -33 (-13.31%) bpf_overlay.o tail_rev_nodeport_lb6 2867 2428 -439 (-15.31%) 167 140 -27 (-16.17%) bpf_sock.o cil_sock6_connect 1718 1703 -15 (-0.87%) 100 99 -1 (-1.00%) bpf_xdp.o tail_handle_nat_fwd_ipv4 12917 12443 -474 (-3.67%) 875 849 -26 (-2.97%) bpf_xdp.o tail_handle_nat_fwd_ipv6 13515 13264 -251 (-1.86%) 715 702 -13 (-1.82%) bpf_xdp.o tail_lb_ipv4 39492 36367 -3125 (-7.91%) 2430 2251 -179 (-7.37%) bpf_xdp.o tail_lb_ipv6 80441 78058 -2383 (-2.96%) 3647 3523 -124 (-3.40%) bpf_xdp.o tail_nodeport_ipv6_dsr 1038 901 -137 (-13.20%) 61 55 -6 (-9.84%) bpf_xdp.o tail_nodeport_nat_egress_ipv4 13027 12096 -931 (-7.15%) 868 809 -59 (-6.80%) bpf_xdp.o tail_nodeport_nat_ingress_ipv4 7617 5900 -1717 (-22.54%) 522 413 -109 (-20.88%) bpf_xdp.o tail_nodeport_nat_ingress_ipv6 7575 7395 -180 (-2.38%) 383 374 -9 (-2.35%) bpf_xdp.o tail_rev_nodeport_lb4 6808 6739 -69 (-1.01%) 403 396 -7 (-1.74%) bpf_xdp.o tail_rev_nodeport_lb6 16173 15847 -326 (-2.02%) 1010 990 -20 (-1.98%) Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1ebe76c98451..e5ce530641ba 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4477,8 +4477,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, return err; mark_stack_slot_scratched(env, spi); - if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && - !register_is_null(reg) && env->bpf_capable) { + if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && env->bpf_capable) { save_register_state(env, state, spi, reg, size); /* Break the relation on a narrowing spill. */ if (fls64(reg->umax_value) > BITS_PER_BYTE * size) @@ -4527,7 +4526,12 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, /* when we zero initialize stack slots mark them as such */ if ((reg && register_is_null(reg)) || (!reg && is_bpf_st_mem(insn) && insn->imm == 0)) { - /* backtracking doesn't work for STACK_ZERO yet. */ + /* STACK_ZERO case happened because register spill + * wasn't properly aligned at the stack slot boundary, + * so it's not a register spill anymore; force + * originating register to be precise to make + * STACK_ZERO correct for subsequent states + */ err = mark_chain_precision(env, value_regno); if (err) return err; From 064e0bea19b356c5d5f48a4549d80a3c03ce898b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 5 Dec 2023 10:42:47 -0800 Subject: [PATCH 2634/7721] selftests/bpf: validate precision logic in partial_stack_load_preserves_zeros Enhance partial_stack_load_preserves_zeros subtest with detailed precision propagation log checks. We know expect fp-16 to be spilled, initially imprecise, zero const register, which is later marked as precise even when partial stack slot load is performed, even if it's not a register fill (!). Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231205184248.1502704-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 41fd61299eab..df4920da3472 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -495,6 +495,22 @@ char single_byte_buf[1] SEC(".data.single_byte_buf"); SEC("raw_tp") __log_level(2) __success +/* make sure fp-8 is all STACK_ZERO */ +__msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=00000000") +/* but fp-16 is spilled IMPRECISE zero const reg */ +__msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=0 R10=fp0 fp-16_w=0") +/* and now check that precision propagation works even for such tricky case */ +__msg("10: (71) r2 = *(u8 *)(r10 -9) ; R2_w=P0 R10=fp0 fp-16_w=0") +__msg("11: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 11 first_idx 0 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 10: (71) r2 = *(u8 *)(r10 -9)") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (71) r2 = *(u8 *)(r10 -1)") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 4: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 3: (b7) r0 = 0") __naked void partial_stack_load_preserves_zeros(void) { asm volatile ( From dadc77c93b6e8ca8edd1e290fc1702dc5cef18e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 22 Nov 2023 15:42:08 +0100 Subject: [PATCH 2635/7721] ARM: dts: broadcom: Add BCM63138's high speed UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's designed for hardwiring Bluetooth devices to it. Signed-off-by: Rafał Miłecki Link: https://lore.kernel.org/r/20231122144208.21114-2-zajec5@gmail.com Signed-off-by: Florian Fainelli --- arch/arm/boot/dts/broadcom/bcm63138.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/broadcom/bcm63138.dtsi b/arch/arm/boot/dts/broadcom/bcm63138.dtsi index 93281c47c9ba..4ef02283612b 100644 --- a/arch/arm/boot/dts/broadcom/bcm63138.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm63138.dtsi @@ -232,6 +232,12 @@ nand_controller: nand-controller@2000 { interrupt-names = "nand"; }; + serial@4400 { + compatible = "brcm,bcm63138-hs-uart", "brcm,bcmbca-hs-uart"; + reg = <0x4400 0x1e0>; + interrupts = ; + }; + bootlut: bootlut@8000 { compatible = "brcm,bcm63138-bootlut"; reg = <0x8000 0x50>; From 29b560a4e37ed70d6c233a50ecad84097d50b816 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 5 Dec 2023 10:08:12 -0500 Subject: [PATCH 2636/7721] dt-bindings: vendor-prefixes: add rve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vendor prefix for Recharge Véhicule Électrique (RVE), which manufactures electric vehicle chargers infrastructure components. Acked-by: Krzysztof Kozlowski Signed-off-by: Hugo Villeneuve Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 309b94c328c8..71dcd6240a99 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1179,6 +1179,8 @@ patternProperties: description: Shenzhen Roofull Technology Co, Ltd "^roseapplepi,.*": description: RoseapplePi.org + "^rve,.*": + description: Recharge Véhicule Électrique (RVE) inc. "^saef,.*": description: Saef Technology Limited "^samsung,.*": From bb405e8b5336344c02a80d10979e17ff7629541c Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 5 Dec 2023 10:08:13 -0500 Subject: [PATCH 2637/7721] dt-bindings: arm: fsl: add RVE gateway board Add DT compatible string for RVE gateway board based on a Variscite VAR-SOM-NANO with a NXP MX8MN nano CPU. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Hugo Villeneuve Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 32b195852a75..5b98a17b65b5 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -1022,7 +1022,9 @@ properties: - description: Variscite VAR-SOM-MX8MN based boards items: - - const: variscite,var-som-mx8mn-symphony + - enum: + - rve,rve-gateway # i.MX8MN RVE Gateway Board + - variscite,var-som-mx8mn-symphony - const: variscite,var-som-mx8mn - const: fsl,imx8mn From 37dbc39776db525e1738ed5d67251f30ad5e6f19 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 13 Nov 2023 12:38:54 +0100 Subject: [PATCH 2638/7721] dt-bindings: arm: Add compatible for SKOV i.MX8MP RevB board Add DT compatible string for a SKOV i.MX8MP RevB climate controller board. Signed-off-by: Oleksij Rempel Acked-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 5b98a17b65b5..dc45b4cd867f 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -1050,6 +1050,9 @@ properties: - gateworks,imx8mp-gw73xx-2x # i.MX8MP Gateworks Board - gateworks,imx8mp-gw74xx # i.MX8MP Gateworks Board - gateworks,imx8mp-gw7905-2x # i.MX8MP Gateworks Board + - skov,imx8mp-skov-revb-hdmi # SKOV i.MX8MP climate control without panel + - skov,imx8mp-skov-revb-lt6 # SKOV i.MX8MP climate control with 7” panel + - skov,imx8mp-skov-revb-mi1010ait-1cp1 # SKOV i.MX8MP climate control with 10.1" panel - toradex,verdin-imx8mp # Verdin iMX8M Plus Modules - toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Modules without Wi-Fi / BT - toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Modules From d99cfab43cbd5206ac3eb79fec0fda817dd8f536 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 15 Nov 2023 15:03:18 -0600 Subject: [PATCH 2639/7721] ARM: imx: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mmdc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 2157493b78a9..897e6def59ee 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include #include #include @@ -103,7 +104,7 @@ struct mmdc_pmu { struct device *dev; struct perf_event *mmdc_events[MMDC_NUM_COUNTERS]; struct hlist_node node; - struct fsl_mmdc_devtype_data *devtype_data; + const struct fsl_mmdc_devtype_data *devtype_data; struct clk *mmdc_ipg_clk; }; @@ -474,8 +475,6 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b struct mmdc_pmu *pmu_mmdc; char *name; int ret; - const struct of_device_id *of_id = - of_match_device(imx_mmdc_dt_ids, &pdev->dev); pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL); if (!pmu_mmdc) { @@ -503,7 +502,7 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b GFP_KERNEL, "mmdc%d", ret); pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk; - pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data; + pmu_mmdc->devtype_data = device_get_match_data(&pdev->dev); hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); From 32596b101f6cd87ab1f6e6a1c2a44c70546dde48 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Sat, 18 Nov 2023 00:23:52 +0100 Subject: [PATCH 2640/7721] ARM: dts: nxp: imx7d-pico: add cpu-supply nodes The PICO-IMX7D SoM has the usual power supply configuration using output sw1a of PF3000 PMIC, which was defined in downstream derivative of linux-imx (see link) in the sources for "Android Things" devkit. It is required to support CPU frequency scaling. Map the respective "cpu-supply" nodes of each core to sw1a of the PMIC. Enabling them causes cpufreq-dt, and imx-thermal drivers to probe successfully, and CPU frequency scaling to function. Link: https://android.googlesource.com/platform/hardware/bsp/kernel/nxp/imx-v4.1/+/o-iot-preview-5/arch/arm/boot/dts/imx7d-pico.dtsi#849 Cc: Fabio Estevam Cc: Shawn Guo Cc: Sascha Hauer Signed-off-by: Lech Perczak Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi index c5eefe89cd99..8d5037ac03c7 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi @@ -108,6 +108,14 @@ &clks { assigned-clock-rates = <0>, <32768>; }; +&cpu0 { + cpu-supply = <&sw1a_reg>; +}; + +&cpu1 { + cpu-supply = <&sw1a_reg>; +}; + &ecspi3 { cs-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; From cdb7389abe3065be80e70e8112afb1f625e7a770 Mon Sep 17 00:00:00 2001 From: Hiago De Franco Date: Mon, 20 Nov 2023 21:58:16 +0100 Subject: [PATCH 2641/7721] ARM: dts: imx6qdl-apalis: Add usdhc aliases Add mmc aliases to ensure a consistent mmc device naming across the Toradex SoM family, with this commit mmc0 is the on-module eMMC boot device and the not available mmc interfaces are removed. Signed-off-by: Hiago De Franco Signed-off-by: Francesco Dolcini Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi index 4cc965277c52..dec2a1c9db14 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi @@ -12,6 +12,13 @@ / { model = "Toradex Apalis iMX6Q/D Module"; compatible = "toradex,apalis_imx6q", "fsl,imx6q"; + aliases { + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC1 slot */ + mmc2 = &usdhc2; /* SD1 slot */ + /delete-property/ mmc3; + }; + /* Will be filled by the bootloader */ memory@10000000 { device_type = "memory"; From 265f56542a936fa2edac21ee2cd45f0d331707a6 Mon Sep 17 00:00:00 2001 From: Hiago De Franco Date: Mon, 20 Nov 2023 21:58:17 +0100 Subject: [PATCH 2642/7721] ARM: dts: imx6qdl-colibri: Add usdhc aliases Add mmc aliases to ensure a consistent mmc device naming across the Toradex SoM family, with this commit mmc0 is the on-module eMMC boot device and the not available mmc interfaces are removed. Signed-off-by: Hiago De Franco Signed-off-by: Francesco Dolcini Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi index 11d9c7a2dacb..55c90f6393ad 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi @@ -12,6 +12,13 @@ / { model = "Toradex Colibri iMX6DL/S Module"; compatible = "toradex,colibri_imx6dl", "fsl,imx6dl"; + aliases { + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC/SD Slot */ + /delete-property/ mmc2; + /delete-property/ mmc3; + }; + backlight: backlight { compatible = "pwm-backlight"; brightness-levels = <0 45 63 88 119 158 203 255>; From d53314dd068e782ba0fa808405026f37dbedeb1e Mon Sep 17 00:00:00 2001 From: Hiago De Franco Date: Mon, 20 Nov 2023 21:58:18 +0100 Subject: [PATCH 2643/7721] ARM: dts: imx7d-colibri-emmc: Add usdhc aliases Add mmc aliases to ensure a consistent mmc device naming across the Toradex SoM family, with this commit mmc0 is the on-module eMMC boot device and the not available mmc interfaces are removed. Signed-off-by: Hiago De Franco Signed-off-by: Francesco Dolcini Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi index 3740e34ef99f..9670f45eab3b 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi @@ -11,6 +11,10 @@ aliases { /* Required to properly pass MAC addresses from bootloader. */ ethernet0 = &fec1; ethernet1 = &fec2; + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC/SD slot */ + /delete-property/ mmc2; + /delete-property/ mmc3; }; memory@80000000 { From 60ae7e9e91641de9d517c4c09f4b87d71afce6f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:51:03 +0100 Subject: [PATCH 2644/7721] ARM: dts: nxp: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts | 4 ++-- arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi | 2 +- arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi | 2 +- arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi | 2 +- arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi | 2 +- arch/arm/boot/dts/nxp/imx/imx6sx.dtsi | 8 ++++---- arch/arm/boot/dts/nxp/imx/imx6ul.dtsi | 2 +- arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts | 2 +- arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts | 2 +- arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi | 2 +- arch/arm/boot/dts/nxp/ls/ls1021a.dtsi | 2 +- arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi | 2 +- arch/arm/boot/dts/nxp/vf/vf610-bk4.dts | 4 ++-- arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts | 6 +++--- 20 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts b/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts index 055d23a9aee7..0814f5665a59 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts @@ -22,7 +22,7 @@ memory@70000000 { }; display-0 { - #address-cells =<1>; + #address-cells = <1>; #size-cells = <0>; compatible = "fsl,imx-parallel-display"; interface-pix-fmt = "rgb24"; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts index 7d4ae113c381..63cdf24eb397 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts @@ -22,7 +22,7 @@ touchscreen@41 { compatible = "ilitek,ili251x"; reg = <0x41>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts index 9c5938e16d99..2e75d700efdb 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts @@ -22,7 +22,7 @@ touchscreen@41 { compatible = "ilitek,ili251x"; reg = <0x41>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts index 01df7cffcef2..94625d5d5918 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts @@ -22,7 +22,7 @@ touchscreen@2a { compatible = "eeti,exc80h60"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts index a015453daf10..b3cfa8110ade 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts @@ -22,7 +22,7 @@ touchscreen@2a { compatible = "eeti,exc80h60"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts index b71ee6b79208..7edc788bcb8f 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts @@ -22,7 +22,7 @@ touchscreen@2a { compatible = "eeti,exc80h84"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; touchscreen-inverted-x; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts b/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts index 6f9d094dd6d0..18a620832a2a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts @@ -16,7 +16,7 @@ / { compatible = "variscite,mx6customboard", "variscite,var-som-imx6q", "fsl,imx6q"; panel0: lvds-panel0 { - compatible = "panel-lvds"; + compatible = "panel-lvds"; backlight = <&backlight_lvds>; width-mm = <152>; height-mm = <91>; @@ -43,7 +43,7 @@ panel_in_lvds0: endpoint { }; panel1: lvds-panel1 { - compatible = "panel-lvds"; + compatible = "panel-lvds"; width-mm = <152>; height-mm = <91>; data-mapping = "jeida-18"; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi index dec2a1c9db14..2ae93f57fe5a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi @@ -173,7 +173,7 @@ reg_usb_host_vbus_hub: regulator-usb-host-vbus-hub { reg_usb_host_vbus: regulator-usb-host-vbus { compatible = "regulator-fixed"; enable-active-high; - gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_regulator_usbh_pwr>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi index f1a41c76729c..5587069b6052 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi @@ -54,7 +54,7 @@ reg_usb_otg: reg-otgvbus { clk_codec: clock-codec { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <12000000>; + clock-frequency = <12000000>; }; sound { diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi index b81799d7076a..596b3bb3ddd1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi @@ -25,7 +25,7 @@ adc_ts: adc@0 { compatible = "ti,tsc2046e-adc"; reg = <0>; pinctrl-0 = <&pinctrl_touch>; - pinctrl-names ="default"; + pinctrl-names = "default"; spi-max-frequency = <1000000>; interrupts-extended = <&gpio3 19 IRQ_TYPE_LEVEL_LOW>; #io-channel-cells = <1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi index bda182edc589..81142c523fa8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi @@ -475,7 +475,7 @@ asrc: asrc@2034000 { <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi index f6b35923ad83..df3a375f0a3e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi @@ -418,7 +418,7 @@ asrc: asrc@2034000 { <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; @@ -1010,7 +1010,7 @@ usdhc1: mmc@2190000 { clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; @@ -1024,7 +1024,7 @@ usdhc2: mmc@2194000 { clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; @@ -1038,7 +1038,7 @@ usdhc3: mmc@2198000 { clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi index 3b87d980e9f4..a27a7554c2e7 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi @@ -364,7 +364,7 @@ asrc: asrc@2034000 { <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts b/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts index dd8003bd1fc0..f0fda15f3020 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts @@ -212,7 +212,7 @@ &usdhc3 { keep-power-in-suspend; wakeup-source; vmmc-supply = <®_wlreg_on>; - vqmmc-supply =<®_3p3v>; + vqmmc-supply = <®_3p3v>; status = "okay"; brcmf: wifi@1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts b/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts index 85b97b5f64e7..7ed27c7ad726 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts @@ -149,7 +149,7 @@ &fec2 { &i2c2 { pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_i2c2>; + pinctrl-0 = <&pinctrl_i2c2>; clock-frequency = <100000>; status = "okay"; diff --git a/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi index 9cf09c183b85..6dd73290f0c6 100644 --- a/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi +++ b/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi @@ -74,7 +74,7 @@ soc { sct_pwm: pwm@40000000 { compatible = "nxp,lpc1850-sct-pwm"; reg = <0x40000000 0x1000>; - clocks =<&ccu1 CLK_CPU_SCT>; + clocks = <&ccu1 CLK_CPU_SCT>; clock-names = "pwm"; resets = <&rgu 37>; #pwm-cells = <3>; diff --git a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi index 49c78c84cd5d..d471cc5efa94 100644 --- a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi +++ b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi @@ -112,7 +112,7 @@ msi1: msi-controller@1570e00 { compatible = "fsl,ls1021a-msi"; reg = <0x0 0x1570e00 0x0 0x8>; msi-controller; - interrupts = ; + interrupts = ; }; msi2: msi-controller@1570e08 { diff --git a/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi index 14c411f146f5..5a19da9313ae 100644 --- a/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi @@ -55,7 +55,7 @@ &bl { brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; power-supply = <®_3v3>; - status = "okay"; + status = "okay"; }; &dcu0 { diff --git a/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts b/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts index e4f691d601cc..722182f5fd17 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts @@ -68,7 +68,7 @@ spi { #address-cells = <1>; #size-cells = <0>; /* PTD12 ->RPIO[91] */ - sck-gpios = <&gpio2 27 GPIO_ACTIVE_LOW>; + sck-gpios = <&gpio2 27 GPIO_ACTIVE_LOW>; /* PTD10 ->RPIO[89] */ miso-gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>; num-chipselects = <0>; @@ -79,7 +79,7 @@ gpio@0 { gpio-controller; #gpio-cells = <2>; /* PTB18 -> RGPIO[40] */ - load-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + load-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; spi-max-frequency = <100000>; }; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts index 16b4e06c4efa..b0ed68af0546 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts @@ -294,11 +294,11 @@ spi-0 { pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; - sck-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>; mosi-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; miso-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW - &gpio1 8 GPIO_ACTIVE_HIGH>; + cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW + &gpio1 8 GPIO_ACTIVE_HIGH>; num-chipselects = <2>; flash@0 { From 85e51f62a38b5d83454dc30c74d5b19c29aa49b8 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 18 Oct 2023 11:10:28 -0700 Subject: [PATCH 2645/7721] arm64: dts: imx8mp-venice-gw74xx: remove unecessary propreties in tpm node Remove unnecessary #address-cells and #size-cells from tpm node. Fixes: 531936b218d8 ("arm64: dts: imx8mp-venice-gw74xx: update to revB PCB") Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts index 2ab9f4cc12cc..dcf9bababffc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts @@ -182,8 +182,6 @@ &ecspi1 { tpm@0 { compatible = "tcg,tpm_tis-spi"; - #address-cells = <0x1>; - #size-cells = <0x1>; reg = <0x0>; spi-max-frequency = <36000000>; }; From 3eb1b39b2415bcb29077c4cbaf4a0cb489b9a50e Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 20 Oct 2023 15:07:55 +0200 Subject: [PATCH 2646/7721] arm64: dts: freescale: Add dual-channel LVDS overlay for TQMa8MPxL This adds an overlay for the supported LVDS display AUO G133HAN01. Configure the video PLL frequency to exactly match typical pixel clock of 141.200 MHz. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 2 + ...8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index a3c5fc814adb..6d83f84090e1 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -129,7 +129,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dev.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-yavia.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds.dtbo +imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtbo dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl-lvds.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso new file mode 100644 index 000000000000..5058cd9409c7 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * Copyright (c) 2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Alexander Stein + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + compatible = "tq,imx8mp-tqma8mpql-mba8mpxl", "tq,imx8mp-tqma8mpql", "fsl,imx8mp"; +}; + +&backlight_lvds { + status = "okay"; +}; + +&display { + compatible = "auo,g133han01"; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + panel_in_lvds0: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + panel_in_lvds1: endpoint { + remote-endpoint = <&ldb_lvds_ch1>; + }; + }; + }; +}; + +&lcdif2 { + status = "okay"; +}; + +&lvds_bridge { + assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>, + <&clk IMX8MP_VIDEO_PLL1>; + assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>; + assigned-clock-rates = <0>, <988400000>; + status = "okay"; + + ports { + port@1 { + ldb_lvds_ch0: endpoint { + remote-endpoint = <&panel_in_lvds0>; + }; + }; + + port@2 { + ldb_lvds_ch1: endpoint { + remote-endpoint = <&panel_in_lvds1>; + }; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; From 949208664fe8255f092ffcd75a2d93509f666ba9 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 1 Nov 2023 10:43:04 +0000 Subject: [PATCH 2647/7721] arm64: dts: freescale: debix-som: Add heartbeat LED Map the 'RUN' LED present on the Debix-SOM as a heartbeat. Reviewed-by: Marco Felsch Signed-off-by: Kieran Bingham Signed-off-by: Shawn Guo --- .../dts/freescale/imx8mp-debix-som-a.dtsi | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 bc312aa1bfc8..91094c227744 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi @@ -6,6 +6,8 @@ #include "imx8mp.dtsi" +#include + / { model = "Polyhex i.MX8MPlus Debix SOM A"; compatible = "polyhex,imx8mp-debix-som-a", "fsl,imx8mp"; @@ -20,6 +22,20 @@ reg_usdhc2_vmmc: regulator-usdhc2 { gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-0 { + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_STATUS; + color = ; + }; + }; }; &A53_0 { @@ -203,6 +219,12 @@ &wdog1 { }; &iomuxc { + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2 From 4bedc468b725d55655dc8c9f5528932f4d77ccb0 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sun, 22 Oct 2023 11:19:10 -0500 Subject: [PATCH 2648/7721] arm64: dts: imx8mp: Add NPU Node The NPU is based on the Vivante GC8000 and its power-domain is controlled my pgc_mlmix. Since the power-domain uses some of these clocks, setup the clock parent and rates inside the power-domain, and add the NPU node. The data sheet states the CLK_ML_AHB should be 300MHz for nominal, but 800MHz clock will divide down to 266 instead. Boards which operate in over-drive mode should update the clocks on their boards accordingly. When the driver loads, the NPU numerates as: etnaviv-gpu 38500000.npu: model: GC8000, revision: 8002 Signed-off-by: Adam Ford Reviewed-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 3ad97b7dcb2c..28f2c6daddec 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -889,6 +889,15 @@ pgc_mlmix: power-domain@24 { clocks = <&clk IMX8MP_CLK_ML_AXI>, <&clk IMX8MP_CLK_ML_AHB>, <&clk IMX8MP_CLK_NPU_ROOT>; + assigned-clocks = <&clk IMX8MP_CLK_ML_CORE>, + <&clk IMX8MP_CLK_ML_AXI>, + <&clk IMX8MP_CLK_ML_AHB>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>; + assigned-clock-rates = <800000000>, + <800000000>, + <300000000>; }; }; }; @@ -2014,6 +2023,18 @@ vpumix_blk_ctrl: blk-ctrl@38330000 { interconnect-names = "g1", "g2", "vc8000e"; }; + npu: npu@38500000 { + compatible = "vivante,gc"; + reg = <0x38500000 0x200000>; + interrupts = ; + clocks = <&clk IMX8MP_CLK_NPU_ROOT>, + <&clk IMX8MP_CLK_NPU_ROOT>, + <&clk IMX8MP_CLK_ML_AXI>, + <&clk IMX8MP_CLK_ML_AHB>; + clock-names = "core", "shader", "bus", "reg"; + power-domains = <&pgc_mlmix>; + }; + gic: interrupt-controller@38800000 { compatible = "arm,gic-v3"; reg = <0x38800000 0x10000>, From 010dc015b811a4e715a25273df2e357fa099de24 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 25 Oct 2023 09:28:32 +0200 Subject: [PATCH 2649/7721] arm64: dts: imx8mp: Disable dsp reserved memory by default Even if the 'dsp' node is disabled the memory intended to be used by the DSP is reserved. This limits the memory range suitable for CMA allocation. Thus disable the dsp_reserved node. DSP users need to enable it in parallel to the 'dsp' node. Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 28f2c6daddec..0601fed9a7fb 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -264,6 +264,7 @@ reserved-memory { dsp_reserved: dsp@92400000 { reg = <0 0x92400000 0 0x2000000>; no-map; + status = "disabled"; }; }; From 31e2689b9985e5226ef866dd9842c7c14c69a6d2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 30 Oct 2023 15:32:13 -0300 Subject: [PATCH 2650/7721] arm64: dts: imx8mm-venice-gw7: Fix pci sub-nodes Several schema warnings are seen when running: make dtbs_check DT_SCHEMA_FILES=pci-bus.yaml Fix them. Signed-off-by: Fabio Estevam Acked-by: Tim Harvey Signed-off-by: Shawn Guo --- .../dts/freescale/imx8mm-venice-gw72xx.dtsi | 30 ++++++++++++------- .../dts/freescale/imx8mm-venice-gw73xx.dtsi | 30 ++++++++++++------- .../dts/freescale/imx8mm-venice-gw7902.dts | 14 +++++---- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index 02d96f4a2d23..a337e8f20441 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -159,23 +159,31 @@ &pcie0 { pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@1,0 { + pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@2,3 { + pcie@3,0 { reg = <0x1800 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@5,0 { + eth1: pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi index d79fe9f62b95..2247d1c4e2af 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi @@ -179,23 +179,31 @@ &pcie0 { pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@1,0 { + pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@2,4 { + pcie@4,0 { reg = <0x2000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@6,0 { + eth1: pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts index 06a394a41d7c..7ef17c2b0e9d 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts @@ -635,13 +635,17 @@ &pcie0 { pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@1,0 { + eth1: pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; From 2f05cd74fe2be3138c30aa1b7109c33ae0a245ed Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Mon, 30 Oct 2023 11:19:20 -0400 Subject: [PATCH 2651/7721] arm64: dts: imx8mn-var-som: add fixed 3.3V regulator for EEPROM When the EEPROM is probed, we have this warning: at24 0-0052: supply vcc not found, using dummy regulator Add fixed 3.3v regulator to silence the warning. Signed-off-by: Hugo Villeneuve Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi index b8946edf317b..b364307868f2 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi @@ -31,6 +31,14 @@ reg_eth_phy: regulator-eth-phy { gpio = <&gpio2 9 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + reg_3v3_fixed: regulator-3v3-fixed { + compatible = "regulator-fixed"; + regulator-name = "fixed_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; }; &A53_0 { @@ -234,6 +242,7 @@ eeprom_som: eeprom@52 { compatible = "atmel,24c04"; reg = <0x52>; pagesize = <16>; + vcc-supply = <®_3v3_fixed>; }; }; From dfd3647c13b98478bd4b725ed95ea72e1e577cf6 Mon Sep 17 00:00:00 2001 From: Andrejs Cainikovs Date: Fri, 20 Oct 2023 17:30:21 +0200 Subject: [PATCH 2652/7721] arm64: dts: imx8-apalis: add can power-up delay on ixora board Newer variants of Ixora boards require a power-up delay when powering up the CAN transceiver of up to 1ms. Signed-off-by: Andrejs Cainikovs Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi | 2 ++ 1 file changed, 2 insertions(+) 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 72136c436a70..f6654fdcb147 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 @@ -68,6 +68,7 @@ reg_can1_supply: regulator-can1-supply { gpio = <&lsio_gpio5 22 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-name = "can1_supply"; + startup-delay-us = <1000>; }; reg_can2_supply: regulator-can2-supply { @@ -77,6 +78,7 @@ reg_can2_supply: regulator-can2-supply { gpio = <&lsio_gpio2 8 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-name = "can2_supply"; + startup-delay-us = <1000>; }; reg_usb_host_vbus: regulator-usb-host-vbus { From 4168df27f54a37bd661b363459e4e28ea4e6242f Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 27 Nov 2023 12:40:34 +0000 Subject: [PATCH 2653/7721] arm64: dts: freescale: debix-som-a-bmb-08: Add CSI Power Regulators Provide the 1.8 and 3.3 volt regulators that are utilised on the Debix SOM BMB-08 base board. Facilitate this by also supplying the pin control used to enable the regulators on the second MIPI CSI port. Reviewed-by: Marco Felsch Signed-off-by: Kieran Bingham Signed-off-by: Shawn Guo --- .../freescale/imx8mp-debix-som-a-bmb-08.dts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) 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 0afd90224a59..b11d694b98e1 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 @@ -63,6 +63,50 @@ regulator-som-vdd3v3 { regulator-always-on; }; + reg_csi1_1v8: regulator-csi1-vdd1v8 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "CSI1_VDD1V8"; + gpio = <&expander0 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_baseboard_vdd3v3>; + }; + + reg_csi1_3v3: regulator-csi1-vdd3v3 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "CSI1_VDD3V3"; + gpio = <&expander0 14 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_vdd5v0>; + }; + + reg_csi2_1v8: regulator-csi2-vdd1v8 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_csi2_1v8>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "CSI2_VDD1V8"; + gpio = <&gpio3 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_baseboard_vdd3v3>; + }; + + reg_csi2_3v3: regulator-csi2-vdd3v3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_csi2_3v3>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "CSI2_VDD3V3"; + gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_vdd5v0>; + }; + regulator-vbus-usb20 { compatible = "regulator-fixed"; regulator-min-microvolt = <5000000>; @@ -413,6 +457,18 @@ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 >; }; + pinctrl_reg_csi2_1v8: regcsi21v8grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21 0x19 + >; + }; + + pinctrl_reg_csi2_3v3: regcsi23v3grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x19 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x14f From 67275c2f3d9ba6106e7195fb8f0f4b355138b8a5 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 5 Dec 2023 10:08:14 -0500 Subject: [PATCH 2654/7721] arm64: dts: freescale: introduce rve-gateway board The RVE gateway board is based on a Variscite VAR-SOM-NANO, with a NXP MX8MN nano CPU. Signed-off-by: Hugo Villeneuve Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 1 + .../boot/dts/freescale/imx8mn-rve-gateway.dts | 285 ++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 6d83f84090e1..b87eb792c9c7 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -98,6 +98,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-bsh-smm-s2pro.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr3l-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mn-rve-gateway.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb diff --git a/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts b/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts new file mode 100644 index 000000000000..1b633bd1ebb6 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2023 DimOnOff + */ + +/dts-v1/; + +#include +#include "imx8mn-var-som.dtsi" + +/ { + model = "RVE gateway"; + compatible = "rve,rve-gateway", "variscite,var-som-mx8mn", "fsl,imx8mn"; + + crystal_duart_24m: crystal-duart-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + key-enter { + label = "enter"; + gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + key-exit { + label = "exit"; + gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + lcd { + compatible = "hit,hd44780"; + display-height-chars = <2>; + display-width-chars = <20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd>; + data-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>, + <&gpio1 6 GPIO_ACTIVE_HIGH>, + <&gpio1 14 GPIO_ACTIVE_HIGH>, + <&gpio4 28 GPIO_ACTIVE_HIGH>, + <&gpio5 24 GPIO_ACTIVE_HIGH>, + <&gpio5 2 GPIO_ACTIVE_HIGH>, + <&gpio1 12 GPIO_ACTIVE_HIGH>, + <&gpio5 25 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>; + rs-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + rw-gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + /* Bourns PEC12R rotary encoder, 24 steps. */ + rotary: rotary-encoder { + compatible = "rotary-encoder"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rotary>; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>, /* A */ + <&gpio3 21 GPIO_ACTIVE_LOW>; /* B */ + linux,axis = <0>; /* REL_X */ + rotary-encoder,encoding = "gray"; + rotary-encoder,relative-axis; + }; +}; + +&ecspi1 { + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + + duart1: serial@0 { + compatible = "nxp,sc16is752"; + reg = <0>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + spi-max-frequency = <4000000>; + clocks = <&crystal_duart_24m>; + interrupt-parent = <&gpio3>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "RADIO0", "RADIO1", "RADIO2", "RADIO3", + "RADIO4", "RADIO_RESET", "TP12", "TP11"; + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; + }; + + /delete-node/ touchscreen@0; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + /delete-property/ dmas; + /delete-property/ dma-names; + status = "okay"; + + duart2: serial@0 { + compatible = "nxp,sc16is752"; + reg = <0>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + spi-max-frequency = <4000000>; + clocks = <&crystal_duart_24m>; + interrupt-parent = <&gpio3>; + interrupts = <20 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_USER", "LED_R_USER", "LED_G_USER", + "GPIO_EXT3", "GPIO_EXT2", "GPIO_EXT1", + "GPIO_EXT0", "TP13"; + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; + }; +}; + +/* Configure PWM pins in GPIO mode: */ +&gpio5 { + gpio-line-names = "", "", "", "PWM3", "PWM2", "PWM1"; +}; + +&gpu { + status = "disabled"; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + /* Carrier board EEPROM */ + eeprom_cb: eeprom@56 { + compatible = "atmel,24c04"; + reg = <0x56>; + pagesize = <16>; + vcc-supply = <®_3p3v>; + }; + + lm75: sensor@48 { + compatible = "st,stlm75"; + reg = <0x48>; + vs-supply = <®_3p3v>; + }; + + mcp7940: rtc@6f { + compatible = "microchip,mcp7940x"; + reg = <0x6f>; + }; +}; + +&i2c3 { + codec@1a { + status = "disabled"; + }; +}; + +&i2c4 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + pcf8574_1: gpio@38 { + compatible = "nxp,pcf8574"; + reg = <0x38>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_COMM3", "LED_R_COMM3", "LED_G_COMM3", + "TP14", "TP15", "LED_G_COMM4", "LED_R_COMM4", + "LED_B_COMM4"; + }; + + pcf8574_2: gpio@39 { + compatible = "nxp,pcf8574"; + reg = <0x39>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_COMM2", "LED_G_COMM2", "LED_B_COMM1", + "LED_R_COMM2", "LED_R_COMM1", "LED_G_COMM1", + "TP16", "TP17"; + }; +}; + +/* Bluetooth */ +&uart2 { + status = "disabled"; +}; + +&usbotg1 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +/* SD interface on expansion connector. */ +&usdhc2 { + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK 0x13 + MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI 0x13 + MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO 0x13 + MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x13 /* SS0 */ + MX8MN_IOMUXC_SAI5_RXD1_GPIO3_IO22 0x13 /* SC16 IRQ */ + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x13 + MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x13 + MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x13 + MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x13 /* SS0 */ + MX8MN_IOMUXC_SAI5_RXC_GPIO3_IO20 0x13 /* SC16 IRQ */ + >; + }; + + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1 0xc6 /* Enter */ + MX8MN_IOMUXC_SAI5_RXD2_GPIO3_IO23 0xc6 /* Exit */ + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_lcd: lcdgrp { + fsl,pins = < + MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1 0x00000156 /* D0 */ + MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x00000156 /* D1 */ + MX8MN_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x00000156 /* D2 */ + MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x00000156 /* D3 */ + MX8MN_IOMUXC_UART2_RXD_GPIO5_IO24 0x00000156 /* D4 */ + MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x00000156 /* D5 */ + MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x00000156 /* D6 */ + MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25 0x00000156 /* D7 */ + MX8MN_IOMUXC_UART1_TXD_GPIO5_IO23 0x00000156 /* E */ + MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x00000156 /* RS */ + MX8MN_IOMUXC_SAI2_MCLK_GPIO4_IO27 0x00000156 /* R/W */ + >; + }; + + pinctrl_rotary: rotarygrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x00000156 /* A */ + MX8MN_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x00000156 /* B */ + >; + }; + + /* Override Card Detect function GPIO value (GPIO1_IO10) from SOM: */ + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x41 + >; + }; +}; From c8e6e06edec287ef7fd9b034d93be51e27497853 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 7 Nov 2023 10:50:40 -0500 Subject: [PATCH 2655/7721] arm64: dts: imx8mn-var-som-symphony: add vcc supply for PCA9534 The following warning is shown when probing device: pca953x 1-0020: supply vcc not found, using dummy regulator Define a new fixed 3.3v regulator for carrier board peripherals, enabled by mosfet switch Q2 after the SOM_3V3 supply rises (no software control). Add this new regulator as vcc supply to the PCA9534 to silence the warning. Signed-off-by: Hugo Villeneuve Signed-off-by: Shawn Guo --- .../boot/dts/freescale/imx8mn-var-som-symphony.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts index a7a57442cb81..a6b94d1957c9 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts @@ -57,6 +57,15 @@ led { linux,default-trigger = "heartbeat"; }; }; + + /* Peripherals supply, enabled by Q2 after SOM_3V3 rises. */ + reg_per_3v3: regulator-peripheral-3v3 { + compatible = "regulator-fixed"; + regulator-name = "per_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; }; ðphy { @@ -79,6 +88,7 @@ pca9534: gpio@20 { interrupts = <7 IRQ_TYPE_EDGE_FALLING>; #gpio-cells = <2>; wakeup-source; + vcc-supply = <®_per_3v3>; /* USB 3.0 OTG (usbotg1) / SATA port switch, set to USB 3.0 */ usb3-sata-sel-hog { From 6d382d51d9799d3610fccc451dd69c842710c364 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 13 Nov 2023 12:38:55 +0100 Subject: [PATCH 2656/7721] arm64: dts: freescale: Add SKOV IMX8MP CPU revB board Add Skov i.MX8MP based climate controller. Signed-off-by: Oleksij Rempel Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 3 + .../boot/dts/freescale/imx8mp-skov-reva.dtsi | 711 ++++++++++++++++++ .../dts/freescale/imx8mp-skov-revb-hdmi.dts | 20 + .../dts/freescale/imx8mp-skov-revb-lt6.dts | 101 +++ .../imx8mp-skov-revb-mi1010ait-1cp1.dts | 100 +++ 5 files changed, 935 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index b87eb792c9c7..a1082a097656 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -116,6 +116,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-hdmi.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-lt6.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-mi1010ait-1cp1.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw71xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw72xx-2x.dtb diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi new file mode 100644 index 000000000000..59813ef8e2bb --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi @@ -0,0 +1,711 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +#include "imx8mp.dtsi" + +#include + +/ { + aliases { + /* some of this aliases like backlight0, ethernetX and switch0 + * are needed for the bootloader. + */ + backlight0 = &backlight; + ethernet0 = &eqos; + ethernet1 = &lan1; + ethernet2 = &lan2; + rtc0 = &i2c_rtc; + rtc1 = &snvs_rtc; + switch0 = &switch; + }; + + /* + * Backlight is present only on some of boards, so it is disabled by + * default. + */ + backlight: backlight { + compatible = "pwm-backlight"; + pinctrl-0 = <&pinctrl_backlight>; + pwms = <&pwm1 0 20000 0>; + power-supply = <®_24v>; + enable-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; + brightness-levels = <0 255>; + num-interpolated-steps = <17>; + default-brightness-level = <8>; + status = "disabled"; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-0 { + label = "D1"; + color = ; + gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_STATUS; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led-1 { + label = "D2"; + color = ; + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-2 { + label = "D3"; + color = ; + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + }; + + reg_1v2: regulator-1v2 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_p>; + regulator-name = "1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + reg_2v5: regulator-2v5 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_s>; + regulator-name = "2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_s>; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + /* + * This regulator will provide power as long as possible even if + * undervoltage is detected. + */ + reg_5v_p: regulator-5v-p { + compatible = "regulator-fixed"; + regulator-name = "5V_P"; + vin-supply = <®_24v>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + /* + * This regulator will be automatically shutdown if undervoltage is + * detected. + */ + reg_5v_s: regulator-5v-s { + compatible = "regulator-fixed"; + regulator-name = "5V_S"; + vin-supply = <®_24v>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_24v: regulator-24v { + compatible = "regulator-fixed"; + regulator-name = "24V"; + regulator-min-microvolt = <24000000>; + regulator-max-microvolt = <24000000>; + }; + + reg_can2rs: regulator-can2rs { + compatible = "regulator-fixed"; + regulator-name = "CAN2RS"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can2rs>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 22 GPIO_ACTIVE_LOW>; + }; + + reg_canrs: regulator-canrs { + compatible = "regulator-fixed"; + regulator-name = "CANRS"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_canrs>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 21 GPIO_ACTIVE_LOW>; + }; + + reg_tft_vcom: regulator-tft-vcom { + compatible = "pwm-regulator"; + pwms = <&pwm4 0 20000 0>; + regulator-name = "VCOM"; + vin-supply = <®_5v_s>; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + regulator-always-on; + voltage-table = <3600000 26>; + status = "disabled"; + }; + + reg_vsd_3v3: regulator-vsd-3v3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_vsd_3v3>; + vin-supply = <®_vdd_3v3>; + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&A53_0 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_1 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_2 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_3 { + cpu-supply = <®_vdd_arm>; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + status = "okay"; + + adc: adc@0 { + compatible = "microchip,mcp3002"; + reg = <0>; + vref-supply = <®_vdd_3v3>; + spi-max-frequency = <1000000>; + #io-channel-cells = <1>; + }; +}; + +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-txid"; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_canrs>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2rs>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupts-extended = <&gpio1 3 IRQ_TYPE_EDGE_RISING>; + sd-vsel-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + + regulators { + reg_vdd_soc: BUCK1 { + regulator-name = "VDD_SOC"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + }; + + reg_vdd_arm: BUCK2 { + regulator-name = "VDD_ARM"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + reg_vdd_3v3: BUCK4 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdd_1v8: BUCK5 { + regulator-name = "VDD_1V8"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_dram_1v1: BUCK6 { + regulator-name = "NVCC_DRAM_1V1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_snvs_1v8: LDO1 { + regulator-name = "NVCC_SNVS_1V8"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdda_1v8: LDO3 { + regulator-name = "VDDA_1V8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_sd2: LDO5 { + regulator-name = "NVCC_SD2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + i2c_rtc: rtc@51 { + compatible = "nxp,pcf85063tp"; + reg = <0x51>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + interrupts-extended = <&gpio4 31 IRQ_TYPE_EDGE_FALLING>; + quartz-load-femtofarads = <12500>; + }; +}; + +&i2c4 { + clock-frequency = <380000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + switch: switch@5f { + compatible = "microchip,ksz9893"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_switch>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + reg = <0x5f>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + lan1: port@0 { + reg = <0>; + phy-mode = "internal"; + label = "lan1"; + }; + + lan2: port@1 { + reg = <1>; + phy-mode = "internal"; + label = "lan2"; + }; + + port@2 { + reg = <2>; + label = "cpu"; + ethernet = <&eqos>; + phy-mode = "rgmii"; + /* 2ns RX delay is implemented on PCB */ + tx-internal-delay-ps = <2000>; + rx-internal-delay-ps = <0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb3_phy0 { + vbus-supply = <®_3v3>; + status = "okay"; +}; + +&usb3_phy1 { + vbus-supply = <®_3v3>; + status = "okay"; +}; + +&usb_dwc3_0 { + dr_mode = "host"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; +}; + +/* SD Card */ +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + vmmc-supply = <®_vsd_3v3>; + vqmmc-supply = <®_nvcc_sd2>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + bus-width = <4>; + status = "okay"; +}; + +/* eMMC */ +&usdhc3 { + assigned-clocks = <&clk IMX8MP_CLK_USDHC3>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + vmmc-supply = <®_vdd_3v3>; + vqmmc-supply = <®_vdd_1v8>; + bus-width = <8>; + no-sd; + no-sdio; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_backlight: backlightgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24 0x0100 + >; + }; + + pinctrl_can2rs: can2rsgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x154 + >; + }; + + pinctrl_canrs: canrsgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21 0x154 + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x44 + MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x44 + MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x44 + MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x40 + >; + }; + + pinctrl_eqos: eqosgrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91 + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91 + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91 + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91 + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91 + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91 + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__CAN1_RX 0x154 + MX8MP_IOMUXC_SPDIF_TX__CAN1_TX 0x154 + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_MCLK__CAN2_RX 0x154 + MX8MP_IOMUXC_SAI2_TXD0__CAN2_TX 0x154 + >; + }; + + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 + MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19 + MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c2 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2 + MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x400001c2 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL 0x400001c3 + MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 + MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04 0x41 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_EXT_CLK__PWM1_OUT 0x116 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_MCLK__PWM4_OUT 0x116 + >; + }; + + pinctrl_reg_vsd_3v3: regvsd3v3grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40 + >; + }; + + pinctrl_rtc: rtcgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31 0x41 + >; + }; + + pinctrl_switch: switchgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00 0x41 + MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01 0x41 + >; + }; + + pinctrl_touchscreen: touchscreengrp { + fsl,pins = < + /* external 10 k pull up */ + /* CTP_INT */ + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x41 + /* CTP_RST */ + MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x41 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 + MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 + MX8MP_IOMUXC_UART3_RXD__UART1_DTE_RTS 0x140 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x14f + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x14f + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x1c4 + MX8MP_IOMUXC_SD2_WP__GPIO2_IO20 0x1c4 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d0 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d0 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d0 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d0 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d0 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d0 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d0 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d0 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d0 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x194 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d4 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d4 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d4 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d4 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d4 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d4 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d4 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d4 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d4 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x196 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d6 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d6 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d6 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d6 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d6 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d6 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d6 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d6 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d6 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x196 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts new file mode 100644 index 000000000000..c1ca69da3cb8 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - HDMI"; + compatible = "skov,imx8mp-skov-revb-hdmi", "fsl,imx8mp"; +}; + +&iomuxc { + pinctrl_hdmi: hdmigrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x1c3 + MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x1c3 + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x19 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts new file mode 100644 index 000000000000..ccbd3abedd69 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - LT6"; + compatible = "skov,imx8mp-skov-revb-lt6", "fsl,imx8mp"; + + touchscreen { + compatible = "resistive-adc-touch"; + io-channels = <&adc_ts 1>, <&adc_ts 3>, <&adc_ts 4>, <&adc_ts 5>; + io-channel-names = "y", "z1", "z2", "x"; + touchscreen-min-pressure = <65000>; + touchscreen-inverted-y; + touchscreen-swapped-x-y; + touchscreen-x-plate-ohms = <300>; + }; +}; + +®_tft_vcom { + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + voltage-table = <3600000 26>; + status = "okay"; +}; + +&pwm4 { + status = "okay"; +}; + +&backlight { + status = "okay"; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + status = "okay"; + + adc_ts: adc@0 { + compatible = "ti,tsc2046e-adc"; + reg = <0>; + pinctrl-0 = <&pinctrl_touch>; + pinctrl-names ="default"; + spi-max-frequency = <1000000>; + interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@3 { + reg = <3>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@4 { + reg = <4>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@5 { + reg = <5>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK 0x44 + MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI 0x44 + MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO 0x44 + MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09 0x40 + >; + }; + + pinctrl_touch: touchgrp { + fsl,pins = < + /* external pull up */ + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x40 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts new file mode 100644 index 000000000000..3c2efdc59bfa --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - MI1010AIT-1CP1"; + compatible = "skov,imx8mp-skov-revb-mi1010ait-1cp1", "fsl,imx8mp"; + + panel { + compatible = "multi-inno,mi1010ait-1cp"; + backlight = <&backlight>; + power-supply = <®_tft_vcom>; + + port { + in_lvds0: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + }; +}; + +&backlight { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + touchscreen@38 { + compatible = "edt,edt-ft5406"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touchscreen>; + interrupts-extended = <&gpio4 28 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1280>; + touchscreen-size-y = <800>; + vcc-supply = <®_vdd_3v3>; + iovcc-supply = <®_vdd_3v3>; + wakeup-source; + }; +}; + +&lcdif2 { + status = "okay"; +}; + +&lvds_bridge { + /* IMX8MP_CLK_MEDIA_LDB = IMX8MP_CLK_MEDIA_DISP2_PIX * 7 */ + assigned-clock-rates = <482300000>; + status = "okay"; + + ports { + port@1 { + ldb_lvds_ch0: endpoint { + remote-endpoint = <&in_lvds0>; + }; + }; + }; +}; + +&media_blk_ctrl { + /* currently it is not possible to let display clocks confugure + * automatically, so we need to set them manually + */ + assigned-clock-rates = <500000000>, <200000000>, <0>, + /* IMX8MP_CLK_MEDIA_DISP2_PIX = pixelclk of lvds panel */ + <68900000>, + /* IMX8MP_VIDEO_PLL1 = IMX8MP_CLK_MEDIA_LDB * 2 */ + <964600000>; +}; + +&pwm4 { + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +®_tft_vcom { + regulator-min-microvolt = <3160000>; + regulator-max-microvolt = <3160000>; + voltage-table = <3160000 73>; + status = "okay"; +}; + +&iomuxc { + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2 + MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2 + >; + }; +}; From 5a8e9b022e569f9f8fdb5106c3c6e0636ad3ebcf Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 16:21:39 -0300 Subject: [PATCH 2657/7721] arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names Per fsl-lpuart.yaml, when the 'dmas' property is used 'dma-names' should also be present. Pass the lpuart 'dma-names' property to fix the following schema warnings: imx8dxl-evk.dtb: serial@5a060000: dma-names:0: 'rx' was expected from schema $id: http://devicetree.org/schemas/serial/fsl-lpuart.yaml# imx8dxl-evk.dtb: serial@5a060000: dma-names:1: 'tx' was expected from schema $id: http://devicetree.org/schemas/serial/fsl-lpuart.yaml# imx8dxl-evk.dtb: serial@5a060000: Unevaluated properties are not allowed ('dma-names' was unexpected) from schema $id: http://devicetree.org/schemas/serial/fsl-lpuart.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi index 01539df335f8..f125a044dc3c 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi @@ -117,21 +117,25 @@ &flexcan3 { &lpuart0 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 13 0 0>, <&edma2 12 0 1>; + dma-names = "rx","tx"; }; &lpuart1 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 15 0 0>, <&edma2 14 0 1>; + dma-names = "rx","tx"; }; &lpuart2 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 17 0 0>, <&edma2 16 0 1>; + dma-names = "rx","tx"; }; &lpuart3 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 19 0 0>, <&edma2 18 0 1>; + dma-names = "rx","tx"; }; &i2c0 { From 7c1d1944e6372a9ea5a35f82c0362111c5504964 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 16:26:49 -0300 Subject: [PATCH 2658/7721] arm64: dts: imx8mm-emcon-avari: Fix gpio-cells Per nxp,pcf8575.yaml, #gpio-cells should be 2. Change it to fix the following schema warning: imx8mm-emcon-avari.dtb: gpio@3a: #gpio-cells:0:0: 2 was expected from schema $id: http://devicetree.org/schemas/gpio/nxp,pcf8575.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi index d897a8527335..44c2cba41a1f 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi @@ -104,7 +104,7 @@ boardID: gpio@3a { compatible = "nxp,pca8574"; reg = <0x3a>; gpio-controller; - #gpio-cells = <1>; + #gpio-cells = <2>; }; }; From f29c19a6e488154713a55db727bb90d85e4aaa6b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 16:35:48 -0300 Subject: [PATCH 2659/7721] arm64: dts: imx8dxl-ss-conn: Fix Ethernet interrupt-names order Per snps,dwmac.yaml, the interrupt-names entries should be in the following order: "macirq", "eth_wake_irq"; Change it to fix the following schema warnings. imx8dxl-evk.dtb: ethernet@5b050000: interrupt-names:0: 'macirq' was expected from schema $id: http://devicetree.org/schemas/net/snps,dwmac.yaml# imx8dxl-evk.dtb: ethernet@5b050000: interrupt-names:1: 'macirq' is not one of ['eth_wake_irq', 'eth_lpi'] from schema $id: http://devicetree.org/schemas/net/snps,dwmac.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index a414df645351..6e2d97c2fdf1 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -22,7 +22,7 @@ eqos: ethernet@5b050000 { interrupt-parent = <&gic>; interrupts = , ; - interrupt-names = "eth_wake_irq", "macirq"; + interrupt-names = "macirq", "eth_wake_irq"; clocks = <&eqos_lpcg IMX_LPCG_CLK_4>, <&eqos_lpcg IMX_LPCG_CLK_6>, <&eqos_lpcg IMX_LPCG_CLK_0>, From 1a95c9090bbc1fbf74c03ef01eb51bd2902025b2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 17:25:21 -0300 Subject: [PATCH 2660/7721] arm64: dts: imx8mm-nitrogen-r2: Fix I2C mux subnode name Per i2c-mux-pca954x.yaml, the I2C subnodes should follow the 'i2c@' format. Change it to fix the following schema warning: imx8mm-nitrogen-r2.dtb: i2c-mux@70: Unevaluated properties are not allowed ('i2c3@0' was unexpected) from schema $id: http://devicetree.org/schemas/i2c/i2c-mux-pca954x.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts index 0e8f0d7161ad..12fb79d20b29 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts @@ -220,7 +220,7 @@ i2c-mux@70 { #address-cells = <1>; #size-cells = <0>; - i2c3@0 { + i2c@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; From 190efda73985767e6408e5a15577d428b9c80b27 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 20:04:00 -0300 Subject: [PATCH 2661/7721] arm64: dts: imx8mp-debix-model-a: Use phy-mode The property 'phy-connection-type' can be used to describe the interface type between the Ethernet device and the Ethernet PHY device. However, snps,dwmac.yaml gives the following warning: imx8mp-debix-model-a.dtb: ethernet@30bf0000: 'phy-mode' is a required property from schema $id: http://devicetree.org/schemas/net/snps,dwmac.yaml# To avoid the warning, switch to the more commonly used, 'phy-mode' property instead. Signed-off-by: Fabio Estevam Reviewed-by: Andrew Lunn Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 267ceffc02d8..2c19766ebf09 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts @@ -75,7 +75,7 @@ &A53_3 { &eqos { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_eqos>; - phy-connection-type = "rgmii-id"; + phy-mode = "rgmii-id"; phy-handle = <ðphy0>; status = "okay"; From 58efd84f73d96ffa2573204a7d591ad08ff1d633 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 20:12:29 -0300 Subject: [PATCH 2662/7721] arm64: dts: imx8qxp-mek: Fix gpio-sbu-mux compatible Per gpio-sbu-mux.yaml, the compatible entry is incomplete. The imx8qxp-mek board uses a CBDTU02043, so complete the gpio-sbu-mux compatible accordingly. This fixes the following schema warning: imx8qxp-mek.dtb: gpio-sbu-mux: compatible:0: 'gpio-sbu-mux' is not one of ['onnn,fsusb43l10x', 'pericom,pi3usb102'] from schema $id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index 99611729943c..6c3d8715bc11 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -31,7 +31,7 @@ reg_usdhc2_vmmc: usdhc2-vmmc { }; gpio-sbu-mux { - compatible = "gpio-sbu-mux"; + compatible = "nxp,cbdtu02043", "gpio-sbu-mux"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_typec_mux>; select-gpios = <&lsio_gpio5 9 GPIO_ACTIVE_HIGH>; From edef8f1a0127870577e8f3e4d6b23d2da8534dd5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 20:20:15 -0300 Subject: [PATCH 2663/7721] arm64: dts: imx93: Remove unexistent 'shared-interrupt' The 'shared-interrupt' property is not documented nor used anywhere. Remove it. This fixes the following schema warning: imx93-11x11-evk.dtb: dma-controller@42000000: Unevaluated properties are not allowed ('shared-interrupt' was unexpected) from schema $id: http://devicetree.org/schemas/dma/fsl,edma.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index d3a99d7abba4..5a5fbef48a1c 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -518,7 +518,6 @@ edma2: dma-controller@42000000 { compatible = "fsl,imx93-edma4"; reg = <0x42000000 0x210000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <64>; interrupts = , , From adf8745db47488bff78b1b9b33efc9b9e24d9256 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 13 Nov 2023 20:20:16 -0300 Subject: [PATCH 2664/7721] arm64: dts: imx8-ss-audio: Remove unexistent'shared-interrupt' The 'shared-interrupt' property is not documented nor used anywhere. Remove it. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi index 9d75ce467569..f057c6b21b30 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi @@ -24,7 +24,6 @@ edma0: dma-controller@591f0000 { compatible = "fsl,imx8qm-edma"; reg = <0x591f0000 0x190000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <24>; dma-channel-mask = <0x5c0c00>; interrupts = , /* 0 asrc 0 */ @@ -127,7 +126,6 @@ edma1: dma-controller@599f0000 { compatible = "fsl,imx8qm-edma"; reg = <0x599f0000 0xc0000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <11>; dma-channel-mask = <0xc0>; interrupts = , /* 0 asrc 1 */ From 0548761f8ed8613d8ab6266391c9285503b62a75 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 17 Nov 2023 08:59:57 +0100 Subject: [PATCH 2665/7721] arm64: dts: tqma8mpql: Remove invalid/unused property 'dr_mode' is part of the USB DWC3 core, not the glue layer. Remove the property from glue layer. Fixes the dtbs_check warning: arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dtb: usb@32f10108: 'dr_mode' does not match any of the regexes: '^usb@[0-9a-f]+$', 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/usb/fsl,imx8mp-dwc3.yaml# Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts index 4240e20d38ac..4b161564a284 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts @@ -602,7 +602,6 @@ &usb3_0 { &usb3_1 { fsl,disable-port-power-control; fsl,permanently-attached; - dr_mode = "host"; status = "okay"; }; From d3e94d202ca2d05793005fca76fcf18a7b3e908d Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Mon, 20 Nov 2023 17:33:17 +0800 Subject: [PATCH 2666/7721] arm64: dts: imx8dxl-ss-ddr: change ddr_pmu0 compatible i.MX8DXL's ddr pmu has port/channel filter capabilities, but it still is compatible with "fsl,imx8-ddr-pmu". This will change the compatible. Signed-off-by: Xu Yang Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi index 550f513708d8..3569abb5bb9b 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi @@ -4,6 +4,6 @@ */ &ddr_pmu0 { - compatible = "fsl,imx8-ddr-pmu"; + compatible = "fsl,imx8dxl-ddr-pmu", "fsl,imx8-ddr-pmu"; interrupts = ; }; From ff2dbdf6175408108370b4d2ac6672dd13bf6d85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:51:04 +0100 Subject: [PATCH 2667/7721] arm64: dts: freescale: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts | 4 ++-- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 4 ++-- arch/arm64/boot/dts/freescale/imx93.dtsi | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts b/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts index e4215c83ee0f..da4b1807c275 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts @@ -57,8 +57,8 @@ sgtl5000: audio-codec@a { clocks = <&clk IMX8MP_CLK_CLKOUT1>; #sound-dai-cells = <0>; - VDDA-supply = <®_vcc_3v3_audio>; - VDDD-supply = <®_vcc_1v8_audio>; + VDDA-supply = <®_vcc_3v3_audio>; + VDDD-supply = <®_vcc_1v8_audio>; VDDIO-supply = <®_vcc_1v8_audio>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 0601fed9a7fb..a56d737101ea 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -796,8 +796,8 @@ pgc_audio: power-domain@5 { <&clk IMX8MP_CLK_AUDIO_AXI>; assigned-clocks = <&clk IMX8MP_CLK_AUDIO_AHB>, <&clk IMX8MP_CLK_AUDIO_AXI_SRC>; - assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, - <&clk IMX8MP_SYS_PLL1_800M>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>; assigned-clock-rates = <400000000>, <600000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index 5a5fbef48a1c..6fd4cee34544 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -844,7 +844,7 @@ lpuart8: serial@426a0000 { interrupts = ; clocks = <&clk IMX93_CLK_LPUART8_GATE>; clock-names = "ipg"; - dmas = <&edma2 90 0 1>, <&edma2 89 0 0>; + dmas = <&edma2 90 0 1>, <&edma2 89 0 0>; dma-names = "rx", "tx"; status = "disabled"; }; From 0b6b2650b7c6c718421b393984054c61c3f50930 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 27 Nov 2023 16:55:20 +0100 Subject: [PATCH 2668/7721] ARM: dts: nxp: Fix some common switch mistakes Fix some errors in the Marvell MV88E6xxx switch descriptions: - switch0@0 is not OK, should be ethernet-switch@0 - ports should be ethernet-ports - port should be ethernet-port - phy should be ethernet-phy Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts | 14 ++-- .../boot/dts/nxp/vf/vf610-zii-scu4-aib.dts | 70 +++++++++---------- arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts | 18 ++--- .../boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts | 20 +++--- .../boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts | 18 ++--- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts index 1a19aec8957b..7e72f860c3c5 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts @@ -162,7 +162,7 @@ mdio1: mdio { suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6085"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_switch>; @@ -173,26 +173,26 @@ switch0: switch0@0 { interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "eth_cu_1000_1"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_2"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_3"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -200,7 +200,7 @@ port@5 { sfp = <&sff>; }; - port@6 { + ethernet-port@6 { reg = <6>; phy-mode = "rmii"; ethernet = <&fec1>; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts index df1335492a19..77492eeea450 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts @@ -47,17 +47,17 @@ mdio_mux_1: mdio@1 { #address-cells = <1>; #size-cells = <0>; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 0>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -68,37 +68,37 @@ fixed-link { }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "aib2main_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "aib2main_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_5"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_6"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_7"; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "modem_pic"; @@ -108,7 +108,7 @@ fixed-link { }; }; - switch0port10: port@10 { + switch0port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -130,32 +130,32 @@ mdio_mux_2: mdio@2 { #address-cells = <1>; #size-cells = <0>; - switch1: switch1@0 { + switch1: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 1>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_3"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_100_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_100_3"; }; - switch1port9: port@9 { + switch1port9: ethernet-port@9 { reg = <9>; label = "dsa"; phy-mode = "xgmii"; @@ -168,7 +168,7 @@ fixed-link { }; }; - switch1port10: port@10 { + switch1port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -188,17 +188,17 @@ mdio_mux_4: mdio@4 { #address-cells = <1>; #size-cells = <0>; - switch2: switch2@0 { + switch2: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 2>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_fc_1000_2"; phy-mode = "1000base-x"; @@ -206,7 +206,7 @@ port@2 { sfp = <&sff1>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_fc_1000_3"; phy-mode = "1000base-x"; @@ -214,7 +214,7 @@ port@3 { sfp = <&sff2>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_fc_1000_4"; phy-mode = "1000base-x"; @@ -222,7 +222,7 @@ port@4 { sfp = <&sff3>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_fc_1000_5"; phy-mode = "1000base-x"; @@ -230,7 +230,7 @@ port@5 { sfp = <&sff4>; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_fc_1000_6"; phy-mode = "1000base-x"; @@ -238,7 +238,7 @@ port@6 { sfp = <&sff5>; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "eth_fc_1000_7"; phy-mode = "1000base-x"; @@ -246,7 +246,7 @@ port@7 { sfp = <&sff6>; }; - port@9 { + ethernet-port@9 { reg = <9>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -254,7 +254,7 @@ port@9 { sfp = <&sff0>; }; - switch2port10: port@10 { + switch2port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "2500base-x"; @@ -276,17 +276,17 @@ mdio_mux_8: mdio@8 { #address-cells = <1>; #size-cells = <0>; - switch3: switch3@0 { + switch3: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 3>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_fc_1000_8"; phy-mode = "1000base-x"; @@ -294,7 +294,7 @@ port@2 { sfp = <&sff7>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_fc_1000_9"; phy-mode = "1000base-x"; @@ -302,7 +302,7 @@ port@3 { sfp = <&sff8>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_fc_1000_10"; phy-mode = "1000base-x"; @@ -310,7 +310,7 @@ port@4 { sfp = <&sff9>; }; - switch3port9: port@9 { + switch3port9: ethernet-port@9 { reg = <9>; label = "dsa"; phy-mode = "2500base-x"; @@ -322,7 +322,7 @@ fixed-link { }; }; - switch3port10: port@10 { + switch3port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts index 1461804ecaea..2a490464660c 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts @@ -123,7 +123,7 @@ mdio1: mdio { suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -134,11 +134,11 @@ switch0: switch0@0 { interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -149,32 +149,32 @@ fixed-link { }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_6"; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts index 463c2452b9b7..078d8699e16d 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts @@ -112,7 +112,7 @@ mdio1: mdio { suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -123,11 +123,11 @@ switch0: switch0@0 { interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -138,27 +138,27 @@ fixed-link { }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_100_3"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_5"; }; - port@8 { + ethernet-port@8 { reg = <8>; label = "eth_cu_1000_1"; }; - port@9 { + ethernet-port@9 { reg = <9>; label = "eth_cu_1000_2"; phy-handle = <&phy9>; @@ -167,12 +167,12 @@ port@9 { }; }; - mdio1 { + mdio-external { compatible = "marvell,mv88e6xxx-mdio-external"; #address-cells = <1>; #size-cells = <0>; - phy9: phy9@0 { + phy9: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; pinctrl-0 = <&pinctrl_gpio_phy9>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts index f5ae0d5de315..22c8f44390a9 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts @@ -137,7 +137,7 @@ mdio1: mdio { suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -148,11 +148,11 @@ switch0: switch0@0 { interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -163,32 +163,32 @@ fixed-link { }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_6"; }; From af85d689ae08860e4f9648f05e09f1de868091f4 Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Tue, 28 Nov 2023 12:07:47 +0800 Subject: [PATCH 2669/7721] scsi: ufs: dt-bindings: Add msi-parent for UFS MCQ The Message Signaled Interrupts (MSI) support has been introduced in UFSHCI version 4.0 (JESD223E). The MSI is the recommended interrupt approach for MCQ. If choose to use MSI, in UFS DT, we need to provide msi-parent property that point to the hardware entity which serves as the MSI controller for this UFS controller. Acked-by: Krzysztof Kozlowski Acked-by: Conor Dooley Signed-off-by: Ziqi Chen Link: https://lore.kernel.org/r/1701144469-1018-1-git-send-email-quic_ziqichen@quicinc.com Reviewed-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/ufs-common.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml index 985ea8f64de8..31fe7f30ff5b 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml +++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml @@ -87,6 +87,8 @@ properties: description: Specifies max. load that can be drawn from VCCQ2 supply. + msi-parent: true + dependencies: freq-table-hz: [ clocks ] operating-points-v2: [ clocks, clock-names ] From f5f27a332a14f43463aa0075efa3a0c662c0f4a8 Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Tue, 28 Nov 2023 14:10:08 +0300 Subject: [PATCH 2670/7721] scsi: fnic: Return error if vmalloc() failed In fnic_init_module() exists redundant check for return value from fnic_debugfs_init(), because at moment it only can return zero. It make sense to process theoretical vmalloc() failure. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 9730ddfb123d ("scsi: fnic: remove redundant assignment of variable rc") Signed-off-by: Artem Chernyshev Link: https://lore.kernel.org/r/20231128111008.2280507-1-artem.chernyshev@red-soft.ru Reviewed-by: Karan Tilak Kumar Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index c4d9ed0d7d75..2619a2d4f5f1 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -52,9 +52,10 @@ int fnic_debugfs_init(void) fc_trc_flag->fnic_trace = 2; fc_trc_flag->fc_trace = 3; fc_trc_flag->fc_clear = 4; + return 0; } - return 0; + return -ENOMEM; } /* From 28c58f8a0947f70ddee275b90fe45431146bb2cc Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Wed, 29 Nov 2023 11:13:54 -0500 Subject: [PATCH 2671/7721] scsi: target: Enable READ CAPACITY for PR EARO SBC-4, Table 13 allows READ CAPACITY for all PR types. Signed-off-by: Benjamin Coddington Link: https://lore.kernel.org/r/ad095388dbc550c5b199a1dfa71bcbfc575a7abe.1701272679.git.bcodding@redhat.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_pr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 49d9167bb263..80b7d85030d0 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -470,6 +470,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, case INQUIRY: case LOG_SENSE: case SERVICE_ACTION_IN_12: + case READ_CAPACITY: case REPORT_LUNS: case REQUEST_SENSE: case PERSISTENT_RESERVE_IN: From 0d224b1088afef95f7069b7ca907cb199a5802ff Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 30 Nov 2023 12:41:00 -0800 Subject: [PATCH 2672/7721] scsi: zfcp: Replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated[1]. Additionally, it returns the size of the source string, not the resulting size of the destination string. In an effort to remove strlcpy() completely[2], replace strlcpy() here with strscpy(). Overflow should be impossible here, but actually check for buffer sizes being identical with BUILD_BUG_ON(), and include a run-time check as well. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1] Link: https://github.com/KSPP/linux/issues/89 [2] Cc: Martin K. Petersen Cc: James E.J. Bottomley Cc: Steffen Maier Cc: Benjamin Block Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Alexander Gordeev Cc: Christian Borntraeger Cc: Sven Schnelle Cc: Azeem Shaikh Cc: Cc: Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20231130204056.it.978-kees@kernel.org Acked-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_fc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 4f0d0e55f0d4..d6516ab00437 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -900,8 +900,19 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter, zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID, FC_SYMBOLIC_NAME_SIZE); hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost)); - len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost), - FC_SYMBOLIC_NAME_SIZE); + + BUILD_BUG_ON(sizeof(rspn_req->name) != + sizeof(fc_host_symbolic_name(shost))); + BUILD_BUG_ON(sizeof(rspn_req->name) != + type_max(typeof(rspn_req->rspn.fr_name_len)) + 1); + len = strscpy(rspn_req->name, fc_host_symbolic_name(shost), + sizeof(rspn_req->name)); + /* + * It should be impossible for this to truncate (see BUILD_BUG_ON() + * above), but be robust anyway. + */ + if (WARN_ON(len < 0)) + len = sizeof(rspn_req->name) - 1; rspn_req->rspn.fr_name_len = len; sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req)); From a9baa16b4fc11d07953b65298b05d5ee707f093a Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 30 Oct 2023 19:04:33 +0000 Subject: [PATCH 2673/7721] scsi: ibmvfc: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect these fields to be NUL-terminated as the property names from which they are derived are also NUL-terminated. Moreover, NUL-padding is not required as our destination buffers are already NUL-allocated and any future NUL-byte assignments are redundant (like the ones that strncpy() does). ibmvfc_probe() -> | struct ibmvfc_host *vhost; | struct Scsi_Host *shost; ... | shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); ... **side note: is this a bug? Looks like a type to me ^^^^^** ... | vhost = shost_priv(shost); ... where shost_priv() is: | static inline void *shost_priv(struct Scsi_Host *shost) | { | return (void *)shost->hostdata; | } .. and: scsi_host_alloc() -> | shost = kzalloc(sizeof(struct Scsi_Host) + privsize, GFP_KERNEL); And for login_info->..., NUL-padding is also not required as it is explicitly memset to 0: | memset(login_info, 0, sizeof(*login_info)); Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231030-strncpy-drivers-scsi-ibmvscsi-ibmvfc-c-v1-1-5a4909688435@google.com Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvfc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 92c440f2e3a7..46d0b3a0e12f 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1464,7 +1464,7 @@ static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) name = of_get_property(rootdn, "ibm,partition-name", NULL); if (name) - strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); + strscpy(vhost->partition_name, name, sizeof(vhost->partition_name)); num = of_get_property(rootdn, "ibm,partition-no", NULL); if (num) vhost->partition_number = *num; @@ -1513,13 +1513,15 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) login_info->async.va = cpu_to_be64(vhost->async_crq.msg_token); login_info->async.len = cpu_to_be32(async_crq->size * sizeof(*async_crq->msgs.async)); - strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); - strncpy(login_info->device_name, - dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME); + strscpy(login_info->partition_name, vhost->partition_name, + sizeof(login_info->partition_name)); + + strscpy(login_info->device_name, + dev_name(&vhost->host->shost_gendev), sizeof(login_info->device_name)); location = of_get_property(of_node, "ibm,loc-code", NULL); location = location ? location : dev_name(vhost->dev); - strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); + strscpy(login_info->drc_name, location, sizeof(login_info->drc_name)); } /** From 712b3f43ba0e5f86db69cf601ffb06085c606642 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 30 Oct 2023 20:40:48 +0000 Subject: [PATCH 2674/7721] scsi: ibmvscsi: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect partition_name to be NUL-terminated based on its usage with format strings: | dev_info(hostdata->dev, "host srp version: %s, " | "host partition %s (%d), OS %d, max io %u\n", | hostdata->madapter_info.srp_version, | hostdata->madapter_info.partition_name, | be32_to_cpu(hostdata->madapter_info.partition_number), | be32_to_cpu(hostdata->madapter_info.os_type), | be32_to_cpu(hostdata->madapter_info.port_max_txu[0])); ... | len = snprintf(buf, PAGE_SIZE, "%s\n", | hostdata->madapter_info.partition_name); Moreover, NUL-padding is not required as madapter_info is explicitly memset to 0: | memset(&hostdata->madapter_info, 0x00, | sizeof(hostdata->madapter_info)); Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231030-strncpy-drivers-scsi-ibmvscsi-ibmvscsi-c-v1-1-f8b06ae9e3d5@google.com Reviewed-by: Kees Cook Tested-by: Michael Ellerman Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 59599299615d..71f3e9563520 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -266,7 +266,7 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION); strcpy(hostdata->madapter_info.srp_version, SRP_VERSION); - strncpy(hostdata->madapter_info.partition_name, partition_name, + strscpy(hostdata->madapter_info.partition_name, partition_name, sizeof(hostdata->madapter_info.partition_name)); hostdata->madapter_info.partition_number = From edbbae7fba495284f72f05768696572691231558 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Mon, 27 Nov 2023 17:12:29 +0100 Subject: [PATCH 2675/7721] ARM: dts: imx7: add MIPI-DSI support This adds the device tree support for the MIPI-DSI block. The block can be used as encoder for the parallel signals coming from the lcdif block. Signed-off-by: Marco Felsch Signed-off-by: Roland Hieber Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 38a72f969b4e..5d71f3deb34c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -825,6 +825,16 @@ lcdif: lcdif@30730000 { <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>; clock-names = "pix", "axi"; status = "disabled"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + lcdif_out_mipi_dsi: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi_dsi_in_lcdif>; + }; + }; }; mipi_csi: mipi-csi@30750000 { @@ -857,6 +867,42 @@ mipi_vc0_to_csi_mux: endpoint { }; }; }; + + mipi_dsi: dsi@30760000 { + compatible = "fsl,imx7d-mipi-dsim", "fsl,imx8mm-mipi-dsim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30760000 0x400>; + clocks = <&clks IMX7D_MIPI_DSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "bus_clk", "sclk_mipi"; + assigned-clocks = <&clks IMX7D_MIPI_DSI_ROOT_SRC>, + <&clks IMX7D_PLL_SYS_PFD5_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_SYS_PFD5_CLK>; + assigned-clock-rates = <0>, <333000000>; + power-domains = <&pgc_mipi_phy>; + interrupts = ; + samsung,burst-clock-frequency = <891000000>; + samsung,esc-clock-frequency = <20000000>; + samsung,pll-clock-frequency = <24000000>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_dsi_in_lcdif: endpoint@0 { + reg = <0>; + remote-endpoint = <&lcdif_out_mipi_dsi>; + }; + }; + }; + }; }; aips3: bus@30800000 { From 84e46978b91f387d5d153f7f76ddc87471f4a52c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 27 Nov 2023 22:17:40 +1100 Subject: [PATCH 2676/7721] scsi: ipr: Remove obsolete check for old CPUs The IPR driver has a routine to check whether it's running on certain CPU versions and if so whether the adapter is supported on that CPU. But none of the CPUs it checks for are supported by Linux anymore. The most recent CPU it checks for is Power4+ which was removed in commit 471d7ff8b51b ("powerpc/64s: Remove POWER4 support"). So drop the check. That makes the "testmode" module parameter unused, so remove it as well. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20231127111740.1288463-1-mpe@ellerman.id.au Acked-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 55 ---------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 81e3d464d1f6..3819f7c42788 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -77,7 +77,6 @@ static LIST_HEAD(ipr_ioa_head); static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; static unsigned int ipr_max_speed = 1; -static int ipr_testmode = 0; static unsigned int ipr_fastfail = 0; static unsigned int ipr_transop_timeout = 0; static unsigned int ipr_debug = 0; @@ -193,8 +192,6 @@ module_param_named(max_speed, ipr_max_speed, uint, 0); MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320"); module_param_named(log_level, ipr_log_level, uint, 0); MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); -module_param_named(testmode, ipr_testmode, int, 0); -MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); module_param_named(transop_timeout, ipr_transop_timeout, int, 0); @@ -6416,45 +6413,6 @@ static const struct scsi_host_template driver_template = { .proc_name = IPR_NAME, }; -#ifdef CONFIG_PPC_PSERIES -static const u16 ipr_blocked_processors[] = { - PVR_NORTHSTAR, - PVR_PULSAR, - PVR_POWER4, - PVR_ICESTAR, - PVR_SSTAR, - PVR_POWER4p, - PVR_630, - PVR_630p -}; - -/** - * ipr_invalid_adapter - Determine if this adapter is supported on this hardware - * @ioa_cfg: ioa cfg struct - * - * Adapters that use Gemstone revision < 3.1 do not work reliably on - * certain pSeries hardware. This function determines if the given - * adapter is in one of these confgurations or not. - * - * Return value: - * 1 if adapter is not supported / 0 if adapter is supported - **/ -static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { - for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++) { - if (pvr_version_is(ipr_blocked_processors[i])) - return 1; - } - } - return 0; -} -#else -#define ipr_invalid_adapter(ioa_cfg) 0 -#endif - /** * ipr_ioa_bringdown_done - IOA bring down completion. * @ipr_cmd: ipr command struct @@ -7385,19 +7343,6 @@ static int ipr_ioafp_page0_inquiry(struct ipr_cmnd *ipr_cmd) type[4] = '\0'; ioa_cfg->type = simple_strtoul((char *)type, NULL, 16); - if (ipr_invalid_adapter(ioa_cfg)) { - dev_err(&ioa_cfg->pdev->dev, - "Adapter not supported in this hardware configuration.\n"); - - if (!ipr_testmode) { - ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - list_add_tail(&ipr_cmd->queue, - &ioa_cfg->hrrq->hrrq_free_q); - return IPR_RC_JOB_RETURN; - } - } - ipr_cmd->job_step = ipr_ioafp_page3_inquiry; ipr_ioafp_inquiry(ipr_cmd, 1, 0, From 3a306eacda02e87fc4582947f1c0b81de5c35cb7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 27 Nov 2023 17:15:01 +0100 Subject: [PATCH 2677/7721] ARM: dts: imx7s: Add on-chip memory Add the 128 KiB on-chip SRAM at address 0x900000. Signed-off-by: Philipp Zabel Signed-off-by: Roland Hieber Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx7s.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 5d71f3deb34c..c72e1efc16cc 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -183,6 +183,15 @@ soc: soc { interrupt-parent = <&gpc>; ranges; + ocram: sram@900000 { + compatible = "mmio-sram"; + reg = <0x00900000 0x20000>; + ranges = <0 0x00900000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + funnel@30041000 { compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0x30041000 0x1000>; From 25cba909ade2a24f7356dc547dc417042bcef722 Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Tue, 28 Nov 2023 15:11:59 +0300 Subject: [PATCH 2678/7721] scsi: isci: Remove redundant check in isci_task_request_build() sci_task_request_construct_ssp() has invariant return. Change this function to void and get rid of unnecessary checks. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Artem Chernyshev Link: https://lore.kernel.org/r/20231128121159.2373975-1-artem.chernyshev@red-soft.ru Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/request.c | 5 +---- drivers/scsi/isci/request.h | 2 +- drivers/scsi/isci/task.c | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index a7b3243b471d..71f711cb0628 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -738,8 +738,7 @@ static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *i return SCI_SUCCESS; } -enum sci_status sci_task_request_construct_ssp( - struct isci_request *ireq) +void sci_task_request_construct_ssp(struct isci_request *ireq) { /* Construct the SSP Task SCU Task Context */ scu_ssp_task_request_construct_task_context(ireq); @@ -748,8 +747,6 @@ enum sci_status sci_task_request_construct_ssp( sci_task_request_build_ssp_task_iu(ireq); sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return SCI_SUCCESS; } static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *ireq) diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index 20b141739e4d..79ddfffbf73c 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h @@ -300,7 +300,7 @@ sci_task_request_construct(struct isci_host *ihost, struct isci_remote_device *idev, u16 io_tag, struct isci_request *ireq); -enum sci_status sci_task_request_construct_ssp(struct isci_request *ireq); +void sci_task_request_construct_ssp(struct isci_request *ireq); void sci_smp_request_copy_response(struct isci_request *ireq); static inline int isci_task_is_ncq_recovery(struct sas_task *task) diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c514b20293b2..3a25b1a2c52d 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -243,9 +243,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEVICE) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = sci_task_request_construct_ssp(ireq); - if (status != SCI_SUCCESS) - return NULL; + sci_task_request_construct_ssp(ireq); } return ireq; From b918ab2616115c1ea441e00b054ba8d1bb912ac8 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Mon, 27 Nov 2023 22:54:13 -0600 Subject: [PATCH 2679/7721] arm64: dts: imx8mm: Simplify mipi_dsi clocks The device tree clock structure for the mipi_dsi is unnecessarily redundant. The default clock parent of IMX8MM_CLK_DSI_PHY_REF is already IMX8MM_CLK_24M, so there is no need to set the parent-child relationship between them. The default clock rates for IMX8MM_SYS_PLL1_266M and IMX8MM_CLK_24M are already defined to be 266MHz and 24MHz respectively, so there is no need to define those clock rates. On i.MX8M[MNP] the samsung,pll-clock-frequency is not necessary, because the driver will read it from sclk_mipi which is also already set to 24MHz making it also redundant. Signed-off-by: Adam Ford Reviewed-by: Frieder Schrempf Tested-by: Frieder Schrempf # Kontron BL i.MX8MM Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm.dtsi | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index e76fc9fb1bf4..62b4190012cf 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -1153,12 +1153,8 @@ mipi_dsi: dsi@32e10000 { clocks = <&clk IMX8MM_CLK_DSI_CORE>, <&clk IMX8MM_CLK_DSI_PHY_REF>; clock-names = "bus_clk", "sclk_mipi"; - assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE>, - <&clk IMX8MM_CLK_DSI_PHY_REF>; - assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>, - <&clk IMX8MM_CLK_24M>; - assigned-clock-rates = <266000000>, <24000000>; - samsung,pll-clock-frequency = <24000000>; + assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MM_DISPBLK_PD_MIPI_DSI>; status = "disabled"; From 5b28b39dda772e7acc52f02c907aa5497c93e280 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Mon, 27 Nov 2023 22:54:14 -0600 Subject: [PATCH 2680/7721] arm64: dts: imx8mm: Remove video_pll1 clock rate from clk node There are two clock-rate assignments for video_pll1, and the only one it should really have belongs inside the lcdif node, since it's the only consumer of this clock. Remove it from the clk node. Signed-off-by: Adam Ford Reviewed-by: Frieder Schrempf Tested-by: Frieder Schrempf # Kontron BL i.MX8MM Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 62b4190012cf..5b07716e941c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -649,7 +649,6 @@ clk: clock-controller@30380000 { <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_IPG_AUDIO_ROOT>, <&clk IMX8MM_SYS_PLL3>, - <&clk IMX8MM_VIDEO_PLL1>, <&clk IMX8MM_AUDIO_PLL1>; assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>, <&clk IMX8MM_ARM_PLL_OUT>, @@ -659,7 +658,6 @@ clk: clock-controller@30380000 { <400000000>, <400000000>, <750000000>, - <594000000>, <393216000>; }; From a0deedcc0cf0631c7856c16109ee6f08845956c0 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Mon, 27 Nov 2023 22:54:15 -0600 Subject: [PATCH 2681/7721] arm64: dts: imx8mm: Slow default video_pll1 clock rate Since commit 8208181fe536 ("clk: imx: composite-8m: Add imx8m_divider_determine_rate") the lcdif controller has had the ability to set the lcdif_pixel rate which propagates up the tree and sets the video_pll1 rate automatically. By setting this value low, it will force the recalculation of video_pll1 to the lowest rate needed by lcdif instead of dividing a larger clock down to the desired clock speed. This has the advantage of being able to lower the video_pll1 rate from 594MHz to 148.5MHz when operating at 1080p. It can go even lower when operating at lower resolutions and refresh rates. Signed-off-by: Adam Ford Reviewed-by: Frieder Schrempf Tested-by: Frieder Schrempf # Kontron BL i.MX8MM Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 5b07716e941c..74f60913ae4a 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -1133,7 +1133,7 @@ lcdif: lcdif@32e00000 { assigned-clock-parents = <&clk IMX8MM_VIDEO_PLL1_OUT>, <&clk IMX8MM_SYS_PLL2_1000M>, <&clk IMX8MM_SYS_PLL1_800M>; - assigned-clock-rates = <594000000>, <500000000>, <200000000>; + assigned-clock-rates = <24000000>, <500000000>, <200000000>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MM_DISPBLK_PD_LCDIF>; status = "disabled"; From 573eb4a3410a9d4e0612cca50e2c67a46c3824f0 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Fri, 1 Dec 2023 10:59:54 +0800 Subject: [PATCH 2682/7721] scsi: aic7xxx: Return negative error codes in ahc_linux_register_host() ahc_linux_register_host() returns both positive and negative error codes. It's better to make this function only return negative error codes. Signed-off-by: Su Hui Link: https://lore.kernel.org/r/20231201025955.1584260-2-suhui@nfschina.com Reviewed-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 4ae0a1c4d374..b0c4f2345321 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1085,7 +1085,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa template->name = ahc->description; host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); if (host == NULL) - return (ENOMEM); + return -ENOMEM; *((struct ahc_softc **)host->hostdata) = ahc; ahc->platform_data->host = host; From 70dfaf84ec777c0590316a8785df22ca5e97bf10 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Fri, 1 Dec 2023 10:59:55 +0800 Subject: [PATCH 2683/7721] scsi: aic7xxx: Return ahc_linux_register_host()'s value rather than zero ahc_linux_register_host() can return an error code in case of failure. So ahc_linux_pci_dev_probe() should return the value of ahc_linux_register_host() rather than zero. An earlier commit made ahc_linux_register_host() return negative error codes, which makes sure ahc_linux_pci_dev_probe() returns negative error codes. Signed-off-by: Su Hui Link: https://lore.kernel.org/r/20231201025955.1584260-3-suhui@nfschina.com Reviewed-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index a07e94fac673..198440dc0918 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -241,8 +241,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_linux_pci_inherit_flags(ahc); pci_set_drvdata(pdev, ahc); - ahc_linux_register_host(ahc, &aic7xxx_driver_template); - return (0); + return ahc_linux_register_host(ahc, &aic7xxx_driver_template); } /******************************* PCI Routines *********************************/ From aef6ac123609c4365f0270ec689ef215d13c3061 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Fri, 1 Dec 2023 10:59:56 +0800 Subject: [PATCH 2684/7721] scsi: aic7xxx: Return negative error codes in aic7770_probe() aic7770_config() returns both negative and positive error codes. It's better to make aic7770_probe() only return negative error codes. A previous commit made ahc_linux_register_host() return negative error codes, which makes sure aic7770_probe() returns negative error codes. Signed-off-by: Su Hui Link: https://lore.kernel.org/r/20231201025955.1584260-4-suhui@nfschina.com Reviewed-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7770_osm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index bdd177e3d762..a19cdd87c453 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -87,17 +87,17 @@ aic7770_probe(struct device *dev) sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); name = kstrdup(buf, GFP_ATOMIC); if (name == NULL) - return (ENOMEM); + return -ENOMEM; ahc = ahc_alloc(&aic7xxx_driver_template, name); if (ahc == NULL) - return (ENOMEM); + return -ENOMEM; ahc->dev = dev; error = aic7770_config(ahc, aic7770_ident_table + edev->id.driver_data, eisaBase); if (error != 0) { ahc->bsh.ioport = 0; ahc_free(ahc); - return (error); + return error < 0 ? error : -error; } dev_set_drvdata(dev, ahc); From b57c4db5d23b9df0118a25e2441c9288edd73710 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Nov 2023 17:58:30 +0100 Subject: [PATCH 2685/7721] scsi: libfc: Don't schedule abort twice The current FC error recovery is sending up to three REC (recovery) frames in 10 second intervals, and as a final step sending an ABTS after 30 seconds for the command itself. Unfortunately sending an ABTS is also the action for the SCSI abort handler, and the default timeout for SCSI commands is also 30 seconds. This causes two ABTS to be scheduled, with the libfc one slightly earlier. The ABTS scheduled by SCSI EH then sees the command to be already aborted, and will always return with a 'GOOD' status irrespective on the actual result from the first ABTS. This causes the SCSI EH abort handler to always succeed, and SCSI EH never to be engaged. Fix this by not issuing an ABTS when a SCSI command is present for the exchange, but rather wait for the abort scheduled from SCSI EH. And warn if an abort is already scheduled to avoid similar errors in the future. Signed-off-by: Hannes Reinecke Link: https://lore.kernel.org/r/20231129165832.224100-2-hare@kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 945adca5e72f..3f189cedf6db 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -265,6 +265,11 @@ static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp) if (!fsp->seq_ptr) return -EINVAL; + if (fsp->state & FC_SRB_ABORT_PENDING) { + FC_FCP_DBG(fsp, "abort already pending\n"); + return -EBUSY; + } + this_cpu_inc(fsp->lp->stats->FcpPktAborts); fsp->state |= FC_SRB_ABORT_PENDING; @@ -1690,11 +1695,12 @@ static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code) fsp->status_code = code; fsp->cdb_status = 0; fsp->io_status = 0; - /* - * if this fails then we let the scsi command timer fire and - * scsi-ml escalate. - */ - fc_fcp_send_abort(fsp); + if (!fsp->cmd) + /* + * Only abort non-scsi commands; otherwise let the + * scsi command timer fire and scsi-ml escalate. + */ + fc_fcp_send_abort(fsp); } /** From 53122a49f49796beb2c4a1bb702303b66347e29f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Nov 2023 17:58:31 +0100 Subject: [PATCH 2686/7721] scsi: libfc: Fix up timeout error in fc_fcp_rec_error() We should set the status to FC_TIMED_OUT when a timeout error is passed to fc_fcp_rec_error(). Signed-off-by: Hannes Reinecke Link: https://lore.kernel.org/r/20231129165832.224100-3-hare@kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 3f189cedf6db..05be0810b5e3 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1676,7 +1676,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) fc_fcp_rec(fsp); else - fc_fcp_recovery(fsp, FC_ERROR); + fc_fcp_recovery(fsp, FC_TIMED_OUT); break; } fc_fcp_unlock_pkt(fsp); From be40572c22cc734f5836b4faec8a60340dc7ab67 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Nov 2023 17:58:32 +0100 Subject: [PATCH 2687/7721] scsi: libfc: Map FC_TIMED_OUT to DID_TIME_OUT When an exchange is completed with FC_TIMED_OUT we should map it to DID_TIME_OUT to inform the SCSI midlayer that this was a command timeout; DID_BUS_BUSY implies that the command was never sent which is not the case here. Signed-off-by: Hannes Reinecke Link: https://lore.kernel.org/r/20231129165832.224100-4-hare@kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 05be0810b5e3..80be3a936d92 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2062,9 +2062,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) sc_cmd->result = (DID_PARITY << 16); break; case FC_TIMED_OUT: - FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml " + FC_FCP_DBG(fsp, "Returning DID_TIME_OUT to scsi-ml " "due to FC_TIMED_OUT\n"); - sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; + sc_cmd->result = (DID_TIME_OUT << 16); break; default: FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " From e5aab848dfdf7996d20ece4d28d2733c732c5e5a Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Sun, 26 Nov 2023 11:01:31 +0530 Subject: [PATCH 2688/7721] scsi: mpi3mr: Refresh sdev queue depth after controller reset After a controller reset, the firmware may modify the device queue depth. Therefore, update the device queue depth accordingly. Cc: # v5.15+ Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231126053134.10133-2-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 91a22e6e5c3f..561fe0857bc0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1070,8 +1070,14 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) tgtdev = NULL; list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) && - !tgtdev->is_hidden && !tgtdev->host_exposed) - mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id); + !tgtdev->is_hidden) { + if (!tgtdev->host_exposed) + mpi3mr_report_tgtdev_to_host(mrioc, + tgtdev->perst_id); + else if (tgtdev->starget) + starget_for_each_device(tgtdev->starget, + (void *)tgtdev, mpi3mr_update_sdev); + } } } From c01d515687e358b22aa8414d6dac60d7defa6eb9 Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Sun, 26 Nov 2023 11:01:32 +0530 Subject: [PATCH 2689/7721] scsi: mpi3mr: Clean up block devices post controller reset After a controller reset, if the firmware changes the state of devices to "hide", then remove those devices from the OS. Cc: # v6.6+ Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231126053134.10133-3-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 561fe0857bc0..872d4b809d08 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1047,8 +1047,9 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, list) { if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) && - tgtdev->host_exposed && tgtdev->starget && - tgtdev->starget->hostdata) { + tgtdev->is_hidden && + tgtdev->host_exposed && tgtdev->starget && + tgtdev->starget->hostdata) { tgt_priv = tgtdev->starget->hostdata; tgt_priv->dev_removed = 1; atomic_set(&tgt_priv->block_io, 0); @@ -1064,6 +1065,10 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true); mpi3mr_tgtdev_put(tgtdev); + } else if (tgtdev->is_hidden & tgtdev->host_exposed) { + dprint_reset(mrioc, "hiding target device with perst_id(%d)\n", + tgtdev->perst_id); + mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); } } From f8fb3f39148e8010479e4b2003ba4728818ec661 Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Sun, 26 Nov 2023 11:01:33 +0530 Subject: [PATCH 2690/7721] scsi: mpi3mr: Block PEL Enable Command on Controller Reset and Unrecoverable State If a controller reset is underway or the controller is in an unrecoverable state, the PEL enable management command will be returned as EAGAIN or EFAULT. Cc: # v6.1+ Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231126053134.10133-4-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_app.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 08645a99ad6b..9dacbb8570c9 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -223,6 +223,22 @@ static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc, return rval; } + if (mrioc->unrecoverable) { + dprint_bsg_err(mrioc, "%s: unrecoverable controller\n", + __func__); + return -EFAULT; + } + + if (mrioc->reset_in_progress) { + dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__); + return -EAGAIN; + } + + if (mrioc->stop_bsgs) { + dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__); + return -EAGAIN; + } + sg_copy_to_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, &pel_enable, sizeof(pel_enable)); From 07ac6adda4d3daa9410d716e96ffaa3192b6ac04 Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Sun, 26 Nov 2023 11:01:34 +0530 Subject: [PATCH 2691/7721] scsi: mpi3mr: Fetch correct device dev handle for status reply descriptor The current dev handle for the status reply is 0xFFFF, which is invalid. So fetch the correct value. Co-developed-by: Sumit Saxena Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231126053134.10133-5-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 872d4b809d08..1bffd629c124 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -3205,6 +3205,7 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, tg = stgt_priv_data->throttle_group; throttle_enabled_dev = stgt_priv_data->io_throttle_enabled; + dev_handle = stgt_priv_data->dev_handle; } } if (unlikely((data_len_blks >= mrioc->io_throttle_data_length) && From c432e167523939e64ff882c86cdbf28e279a56ab Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Wed, 6 Dec 2023 00:46:27 +0530 Subject: [PATCH 2692/7721] scsi: mpi3mr: Support for preallocation of SGL BSG data buffers part-1 The driver now supports SGLs for BSG data transfer. Upon loading, the driver pre-allocates SGLs in chunks of 8k, results in a total of 256 * 8k, equal to 2MB. These pre-allocated SGLs are reserved for handling BSG commands and are deallocated during driver unload. Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231205191630.12201-2-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 15 +++++ drivers/scsi/mpi3mr/mpi3mr_fw.c | 112 ++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 4f49f8396309..8fce57894f8f 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -477,6 +477,10 @@ struct mpi3mr_throttle_group_info { /* HBA port flags */ #define MPI3MR_HBA_PORT_FLAG_DIRTY 0x01 +/* IOCTL data transfer sge*/ +#define MPI3MR_NUM_IOCTL_SGE 256 +#define MPI3MR_IOCTL_SGE_SIZE (8 * 1024) + /** * struct mpi3mr_hba_port - HBA's port information * @port_id: Port number @@ -1042,6 +1046,11 @@ struct scmd_priv { * @sas_node_lock: Lock to protect SAS node list * @hba_port_table_list: List of HBA Ports * @enclosure_list: List of Enclosure objects + * @ioctl_dma_pool: DMA pool for IOCTL data buffers + * @ioctl_sge: DMA buffer descriptors for IOCTL data + * @ioctl_chain_sge: DMA buffer descriptor for IOCTL chain + * @ioctl_resp_sge: DMA buffer descriptor for Mgmt cmd response + * @ioctl_sges_allocated: Flag for IOCTL SGEs allocated or not */ struct mpi3mr_ioc { struct list_head list; @@ -1227,6 +1236,12 @@ struct mpi3mr_ioc { spinlock_t sas_node_lock; struct list_head hba_port_table_list; struct list_head enclosure_list; + + struct dma_pool *ioctl_dma_pool; + struct dma_memory_desc ioctl_sge[MPI3MR_NUM_IOCTL_SGE]; + struct dma_memory_desc ioctl_chain_sge; + struct dma_memory_desc ioctl_resp_sge; + bool ioctl_sges_allocated; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 1ad2f88e0528..d8c57a0a518f 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1058,6 +1058,114 @@ enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) return MRIOC_STATE_RESET_REQUESTED; } +/** + * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma + * @mrioc: Adapter instance reference + * + * Free the DMA memory allocated for IOCTL handling purpose. + + * + * Return: None + */ +static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) +{ + struct dma_memory_desc *mem_desc; + u16 i; + + if (!mrioc->ioctl_dma_pool) + return; + + for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) { + mem_desc = &mrioc->ioctl_sge[i]; + if (mem_desc->addr) { + dma_pool_free(mrioc->ioctl_dma_pool, + mem_desc->addr, + mem_desc->dma_addr); + mem_desc->addr = NULL; + } + } + dma_pool_destroy(mrioc->ioctl_dma_pool); + mrioc->ioctl_dma_pool = NULL; + mem_desc = &mrioc->ioctl_chain_sge; + + if (mem_desc->addr) { + dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, + mem_desc->addr, mem_desc->dma_addr); + mem_desc->addr = NULL; + } + mem_desc = &mrioc->ioctl_resp_sge; + if (mem_desc->addr) { + dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, + mem_desc->addr, mem_desc->dma_addr); + mem_desc->addr = NULL; + } + + mrioc->ioctl_sges_allocated = false; +} + +/** + * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma + * @mrioc: Adapter instance reference + + * + * This function allocates dmaable memory required to handle the + * application issued MPI3 IOCTL requests. + * + * Return: None + */ +static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) + +{ + struct dma_memory_desc *mem_desc; + u16 i; + + mrioc->ioctl_dma_pool = dma_pool_create("ioctl dma pool", + &mrioc->pdev->dev, + MPI3MR_IOCTL_SGE_SIZE, + MPI3MR_PAGE_SIZE_4K, 0); + + if (!mrioc->ioctl_dma_pool) { + ioc_err(mrioc, "ioctl_dma_pool: dma_pool_create failed\n"); + goto out_failed; + } + + for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) { + mem_desc = &mrioc->ioctl_sge[i]; + mem_desc->size = MPI3MR_IOCTL_SGE_SIZE; + mem_desc->addr = dma_pool_zalloc(mrioc->ioctl_dma_pool, + GFP_KERNEL, + &mem_desc->dma_addr); + if (!mem_desc->addr) + goto out_failed; + } + + mem_desc = &mrioc->ioctl_chain_sge; + mem_desc->size = MPI3MR_PAGE_SIZE_4K; + mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, + mem_desc->size, + &mem_desc->dma_addr, + GFP_KERNEL); + if (!mem_desc->addr) + goto out_failed; + + mem_desc = &mrioc->ioctl_resp_sge; + mem_desc->size = MPI3MR_PAGE_SIZE_4K; + mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, + mem_desc->size, + &mem_desc->dma_addr, + GFP_KERNEL); + if (!mem_desc->addr) + goto out_failed; + + mrioc->ioctl_sges_allocated = true; + + return; +out_failed: + ioc_warn(mrioc, "cannot allocate DMA memory for the mpt commands\n" + "from the applications, application interface for MPT command is disabled\n"); + mpi3mr_free_ioctl_dma_memory(mrioc); +} + /** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference @@ -3874,6 +3982,9 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) } } + dprint_init(mrioc, "allocating ioctl dma buffers\n"); + mpi3mr_alloc_ioctl_dma_memory(mrioc); + if (!mrioc->init_cmds.reply) { retval = mpi3mr_alloc_reply_sense_bufs(mrioc); if (retval) { @@ -4293,6 +4404,7 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) struct mpi3mr_intr_info *intr_info; mpi3mr_free_enclosure_list(mrioc); + mpi3mr_free_ioctl_dma_memory(mrioc); if (mrioc->sense_buf_pool) { if (mrioc->sense_buf) From fb231d7deffb41fd445929a3b79815277b883fec Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Wed, 6 Dec 2023 00:46:28 +0530 Subject: [PATCH 2693/7721] scsi: mpi3mr: Support for preallocation of SGL BSG data buffers part-2 The driver acquires the required SGLs from the pre-allocated pool. Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231205191630.12201-3-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 2 + drivers/scsi/mpi3mr/mpi3mr_app.c | 396 ++++++++++++++++++++++++------- 2 files changed, 313 insertions(+), 85 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 8fce57894f8f..dfff3df3a666 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -247,6 +247,8 @@ struct mpi3mr_buf_map { u32 kern_buf_len; dma_addr_t kern_buf_dma; u8 data_dir; + u16 num_dma_desc; + struct dma_memory_desc *dma_desc; }; /* IOC State definitions */ diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 9dacbb8570c9..e8b0b121a6e3 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -563,8 +563,37 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job) return rval; } +/** + * mpi3mr_total_num_ioctl_sges - Count number of SGEs required + * @drv_bufs: DMA address of the buffers to be placed in sgl + * @bufcnt: Number of DMA buffers + * + * This function returns total number of data SGEs required + * including zero length SGEs and excluding management request + * and response buffer for the given list of data buffer + * descriptors + * + * Return: Number of SGE elements needed + */ +static inline u16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_buf_map *drv_bufs, + u8 bufcnt) +{ + u16 i, sge_count = 0; + + for (i = 0; i < bufcnt; i++, drv_bufs++) { + if (drv_bufs->data_dir == DMA_NONE || + drv_bufs->kern_buf) + continue; + sge_count += drv_bufs->num_dma_desc; + if (!drv_bufs->num_dma_desc) + sge_count++; + } + return sge_count; +} + /** * mpi3mr_bsg_build_sgl - SGL construction for MPI commands + * @mrioc: Adapter instance reference * @mpi_req: MPI request * @sgl_offset: offset to start sgl in the MPI request * @drv_bufs: DMA address of the buffers to be placed in sgl @@ -576,27 +605,45 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job) * This function places the DMA address of the given buffers in * proper format as SGEs in the given MPI request. * - * Return: Nothing + * Return: 0 on success,-1 on failure */ -static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset, - struct mpi3mr_buf_map *drv_bufs, u8 bufcnt, u8 is_rmc, - u8 is_rmr, u8 num_datasges) +static int mpi3mr_bsg_build_sgl(struct mpi3mr_ioc *mrioc, u8 *mpi_req, + u32 sgl_offset, struct mpi3mr_buf_map *drv_bufs, + u8 bufcnt, u8 is_rmc, u8 is_rmr, u8 num_datasges) { + struct mpi3_request_header *mpi_header = + (struct mpi3_request_header *)mpi_req; u8 *sgl = (mpi_req + sgl_offset), count = 0; struct mpi3_mgmt_passthrough_request *rmgmt_req = (struct mpi3_mgmt_passthrough_request *)mpi_req; struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; - u8 sgl_flags, sgl_flags_last; + u8 flag, sgl_flags, sgl_flag_eob, sgl_flags_last, last_chain_sgl_flag; + u16 available_sges, i, sges_needed; + u32 sge_element_size = sizeof(struct mpi3_sge_common); + bool chain_used = false; sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | - MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_BUFFER; - sgl_flags_last = sgl_flags | MPI3_SGE_FLAGS_END_OF_LIST; + MPI3_SGE_FLAGS_DLAS_SYSTEM; + sgl_flag_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; + sgl_flags_last = sgl_flag_eob | MPI3_SGE_FLAGS_END_OF_LIST; + last_chain_sgl_flag = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | + MPI3_SGE_FLAGS_DLAS_SYSTEM; + + sges_needed = mpi3mr_total_num_ioctl_sges(drv_bufs, bufcnt); if (is_rmc) { mpi3mr_add_sg_single(&rmgmt_req->command_sgl, sgl_flags_last, drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - sgl = (u8 *)drv_buf_iter->kern_buf + drv_buf_iter->bsg_buf_len; + sgl = (u8 *)drv_buf_iter->kern_buf + + drv_buf_iter->bsg_buf_len; + available_sges = (drv_buf_iter->kern_buf_len - + drv_buf_iter->bsg_buf_len) / sge_element_size; + + if (sges_needed > available_sges) + return -1; + + chain_used = true; drv_buf_iter++; count++; if (is_rmr) { @@ -608,23 +655,95 @@ static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset, } else mpi3mr_build_zero_len_sge( &rmgmt_req->response_sgl); + if (num_datasges) { + i = 0; + goto build_sges; + } + } else { + if (sgl_offset >= MPI3MR_ADMIN_REQ_FRAME_SZ) + return -1; + available_sges = (MPI3MR_ADMIN_REQ_FRAME_SZ - sgl_offset) / + sge_element_size; + if (!available_sges) + return -1; } if (!num_datasges) { mpi3mr_build_zero_len_sge(sgl); - return; + return 0; } + if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { + if ((sges_needed > 2) || (sges_needed > available_sges)) + return -1; + for (; count < bufcnt; count++, drv_buf_iter++) { + if (drv_buf_iter->data_dir == DMA_NONE || + !drv_buf_iter->num_dma_desc) + continue; + mpi3mr_add_sg_single(sgl, sgl_flags_last, + drv_buf_iter->dma_desc[0].size, + drv_buf_iter->dma_desc[0].dma_addr); + sgl += sge_element_size; + } + return 0; + } + i = 0; + +build_sges: for (; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - if (num_datasges == 1 || !is_rmc) - mpi3mr_add_sg_single(sgl, sgl_flags_last, - drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - else - mpi3mr_add_sg_single(sgl, sgl_flags, - drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - sgl += sizeof(struct mpi3_sge_common); + if (!drv_buf_iter->num_dma_desc) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flag_eob; + if (num_datasges == 1) + flag = sgl_flags_last; + mpi3mr_add_sg_single(sgl, flag, 0, 0); + sgl += sge_element_size; + sges_needed--; + available_sges--; + num_datasges--; + continue; + } + for (; i < drv_buf_iter->num_dma_desc; i++) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flags; + if (i == (drv_buf_iter->num_dma_desc - 1)) { + if (num_datasges == 1) + flag = sgl_flags_last; + else + flag = sgl_flag_eob; + } + + mpi3mr_add_sg_single(sgl, flag, + drv_buf_iter->dma_desc[i].size, + drv_buf_iter->dma_desc[i].dma_addr); + sgl += sge_element_size; + available_sges--; + sges_needed--; + } num_datasges--; + i = 0; } + return 0; + +setup_chain: + available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; + if (sges_needed > available_sges) + return -1; + mpi3mr_add_sg_single(sgl, last_chain_sgl_flag, + (sges_needed * sge_element_size), + mrioc->ioctl_chain_sge.dma_addr); + memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); + sgl = (u8 *)mrioc->ioctl_chain_sge.addr; + chain_used = true; + goto build_sges; } /** @@ -935,10 +1054,66 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, } return -1; } + +/** + * mpi3mr_map_data_buffer_dma - build dma descriptors for data + * buffers + * @mrioc: Adapter instance reference + * @drv_buf: buffer map descriptor + * @desc_count: Number of already consumed dma descriptors + * + * This function computes how many pre-allocated DMA descriptors + * are required for the given data buffer and if those number of + * descriptors are free, then setup the mapping of the scattered + * DMA address to the given data buffer, if the data direction + * of the buffer is DMA_TO_DEVICE then the actual data is copied to + * the DMA buffers + * + * Return: 0 on success, -1 on failure + */ +static int mpi3mr_map_data_buffer_dma(struct mpi3mr_ioc *mrioc, + struct mpi3mr_buf_map *drv_buf, + u16 desc_count) +{ + u16 i, needed_desc = drv_buf->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE; + u32 buf_len = drv_buf->kern_buf_len, copied_len = 0; + + if (drv_buf->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) + needed_desc++; + if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { + dprint_bsg_err(mrioc, "%s: DMA descriptor mapping error %d:%d:%d\n", + __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); + return -1; + } + drv_buf->dma_desc = kzalloc(sizeof(*drv_buf->dma_desc) * needed_desc, + GFP_KERNEL); + if (!drv_buf->dma_desc) + return -1; + for (i = 0; i < needed_desc; i++, desc_count++) { + drv_buf->dma_desc[i].addr = mrioc->ioctl_sge[desc_count].addr; + drv_buf->dma_desc[i].dma_addr = + mrioc->ioctl_sge[desc_count].dma_addr; + if (buf_len < mrioc->ioctl_sge[desc_count].size) + drv_buf->dma_desc[i].size = buf_len; + else + drv_buf->dma_desc[i].size = + mrioc->ioctl_sge[desc_count].size; + buf_len -= drv_buf->dma_desc[i].size; + memset(drv_buf->dma_desc[i].addr, 0, + mrioc->ioctl_sge[desc_count].size); + if (drv_buf->data_dir == DMA_TO_DEVICE) { + memcpy(drv_buf->dma_desc[i].addr, + drv_buf->bsg_buf + copied_len, + drv_buf->dma_desc[i].size); + copied_len += drv_buf->dma_desc[i].size; + } + } + drv_buf->num_dma_desc = needed_desc; + return 0; +} /** * mpi3mr_bsg_process_mpt_cmds - MPI Pass through BSG handler * @job: BSG job reference - * @reply_payload_rcv_len: length of payload recvd * * This function is the top level handler for MPI Pass through * command, this does basic validation of the input data buffers, @@ -954,10 +1129,9 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, * Return: 0 on success and proper error codes on failure */ -static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply_payload_rcv_len) +static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) { long rval = -EINVAL; - struct mpi3mr_ioc *mrioc = NULL; u8 *mpi_req = NULL, *sense_buff_k = NULL; u8 mpi_msg_size = 0; @@ -965,9 +1139,10 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply struct mpi3mr_bsg_mptcmd *karg; struct mpi3mr_buf_entry *buf_entries = NULL; struct mpi3mr_buf_map *drv_bufs = NULL, *drv_buf_iter = NULL; - u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; - u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF, sg_entries = 0; - u8 block_io = 0, resp_code = 0, nvme_fmt = 0; + u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0; + u8 din_cnt = 0, dout_cnt = 0; + u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; + u8 block_io = 0, nvme_fmt = 0, resp_code = 0; struct mpi3_request_header *mpi_header = NULL; struct mpi3_status_reply_descriptor *status_desc; struct mpi3_scsi_task_mgmt_request *tm_req; @@ -979,6 +1154,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply u32 din_size = 0, dout_size = 0; u8 *din_buf = NULL, *dout_buf = NULL; u8 *sgl_iter = NULL, *sgl_din_iter = NULL, *sgl_dout_iter = NULL; + u16 rmc_size = 0, desc_count = 0; bsg_req = job->request; karg = (struct mpi3mr_bsg_mptcmd *)&bsg_req->cmd.mptcmd; @@ -987,6 +1163,12 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply if (!mrioc) return -ENODEV; + if (!mrioc->ioctl_sges_allocated) { + dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", + __func__); + return -ENOMEM; + } + if (karg->timeout < MPI3MR_APP_DEFAULT_TIMEOUT) karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT; @@ -1027,26 +1209,13 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply for (count = 0; count < bufcnt; count++, buf_entries++, drv_buf_iter++) { - if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { - dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", - __func__); - rval = -EINVAL; - goto out; - } - if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { - dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", - __func__); - rval = -EINVAL; - goto out; - } - switch (buf_entries->buf_type) { case MPI3MR_BSG_BUFTYPE_RAIDMGMT_CMD: sgl_iter = sgl_dout_iter; sgl_dout_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_TO_DEVICE; is_rmcb = 1; - if (count != 0) + if ((count != 0) || !buf_entries->buf_len) invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_RAIDMGMT_RESP: @@ -1054,7 +1223,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_FROM_DEVICE; is_rmrb = 1; - if (count != 1 || !is_rmcb) + if (count != 1 || !is_rmcb || !buf_entries->buf_len) invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_DATA_IN: @@ -1062,7 +1231,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_FROM_DEVICE; din_cnt++; - din_size += drv_buf_iter->bsg_buf_len; + din_size += buf_entries->buf_len; if ((din_cnt > 1) && !is_rmcb) invalid_be = 1; break; @@ -1071,7 +1240,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_dout_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_TO_DEVICE; dout_cnt++; - dout_size += drv_buf_iter->bsg_buf_len; + dout_size += buf_entries->buf_len; if ((dout_cnt > 1) && !is_rmcb) invalid_be = 1; break; @@ -1080,12 +1249,16 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_NONE; mpirep_offset = count; + if (!buf_entries->buf_len) + invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_ERR_RESPONSE: sgl_iter = sgl_din_iter; sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_NONE; erb_offset = count; + if (!buf_entries->buf_len) + invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_MPI_REQUEST: sgl_iter = sgl_dout_iter; @@ -1112,21 +1285,31 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } - drv_buf_iter->bsg_buf = sgl_iter; - drv_buf_iter->bsg_buf_len = buf_entries->buf_len; - - } - if (!is_rmcb && (dout_cnt || din_cnt)) { - sg_entries = dout_cnt + din_cnt; - if (((mpi_msg_size) + (sg_entries * - sizeof(struct mpi3_sge_common))) > MPI3MR_ADMIN_REQ_FRAME_SZ) { - dprint_bsg_err(mrioc, - "%s:%d: invalid message size passed\n", - __func__, __LINE__); + if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { + dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", + __func__); rval = -EINVAL; goto out; } + if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { + dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", + __func__); + rval = -EINVAL; + goto out; + } + + drv_buf_iter->bsg_buf = sgl_iter; + drv_buf_iter->bsg_buf_len = buf_entries->buf_len; } + + if (is_rmcb && ((din_size + dout_size) > MPI3MR_MAX_APP_XFER_SIZE)) { + dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size = %d, dout_size = %d\n", + __func__, __LINE__, mpi_header->function, din_size, + dout_size); + rval = -EINVAL; + goto out; + } + if (din_size > MPI3MR_MAX_APP_XFER_SIZE) { dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n", @@ -1142,30 +1325,64 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } + if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { + if (din_size > MPI3MR_IOCTL_SGE_SIZE || + dout_size > MPI3MR_IOCTL_SGE_SIZE) { + dprint_bsg_err(mrioc, "%s:%d: invalid message size passed:%d:%d:%d:%d\n", + __func__, __LINE__, din_cnt, dout_cnt, din_size, + dout_size); + rval = -EINVAL; + goto out; + } + } + drv_buf_iter = drv_bufs; for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; drv_buf_iter->kern_buf_len = drv_buf_iter->bsg_buf_len; - if (is_rmcb && !count) - drv_buf_iter->kern_buf_len += ((dout_cnt + din_cnt) * - sizeof(struct mpi3_sge_common)); - - if (!drv_buf_iter->kern_buf_len) - continue; - - drv_buf_iter->kern_buf = dma_alloc_coherent(&mrioc->pdev->dev, - drv_buf_iter->kern_buf_len, &drv_buf_iter->kern_buf_dma, - GFP_KERNEL); - if (!drv_buf_iter->kern_buf) { - rval = -ENOMEM; + if (is_rmcb && !count) { + drv_buf_iter->kern_buf_len = + mrioc->ioctl_chain_sge.size; + drv_buf_iter->kern_buf = + mrioc->ioctl_chain_sge.addr; + drv_buf_iter->kern_buf_dma = + mrioc->ioctl_chain_sge.dma_addr; + drv_buf_iter->dma_desc = NULL; + drv_buf_iter->num_dma_desc = 0; + memset(drv_buf_iter->kern_buf, 0, + drv_buf_iter->kern_buf_len); + tmplen = min(drv_buf_iter->kern_buf_len, + drv_buf_iter->bsg_buf_len); + rmc_size = tmplen; + memcpy(drv_buf_iter->kern_buf, drv_buf_iter->bsg_buf, tmplen); + } else if (is_rmrb && (count == 1)) { + drv_buf_iter->kern_buf_len = + mrioc->ioctl_resp_sge.size; + drv_buf_iter->kern_buf = + mrioc->ioctl_resp_sge.addr; + drv_buf_iter->kern_buf_dma = + mrioc->ioctl_resp_sge.dma_addr; + drv_buf_iter->dma_desc = NULL; + drv_buf_iter->num_dma_desc = 0; + memset(drv_buf_iter->kern_buf, 0, + drv_buf_iter->kern_buf_len); + tmplen = min(drv_buf_iter->kern_buf_len, + drv_buf_iter->bsg_buf_len); + drv_buf_iter->kern_buf_len = tmplen; + memset(drv_buf_iter->bsg_buf, 0, + drv_buf_iter->bsg_buf_len); + } else { + if (!drv_buf_iter->kern_buf_len) + continue; + if (mpi3mr_map_data_buffer_dma(mrioc, drv_buf_iter, desc_count)) { + rval = -ENOMEM; + dprint_bsg_err(mrioc, "%s:%d: mapping data buffers failed\n", + __func__, __LINE__); goto out; } - if (drv_buf_iter->data_dir == DMA_TO_DEVICE) { - tmplen = min(drv_buf_iter->kern_buf_len, - drv_buf_iter->bsg_buf_len); - memcpy(drv_buf_iter->kern_buf, drv_buf_iter->bsg_buf, tmplen); + desc_count += drv_buf_iter->num_dma_desc; } } @@ -1235,9 +1452,14 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } } else { - mpi3mr_bsg_build_sgl(mpi_req, (mpi_msg_size), - drv_bufs, bufcnt, is_rmcb, is_rmrb, - (dout_cnt + din_cnt)); + if (mpi3mr_bsg_build_sgl(mrioc, mpi_req, mpi_msg_size, + drv_bufs, bufcnt, is_rmcb, is_rmrb, + (dout_cnt + din_cnt))) { + dprint_bsg_err(mrioc, "%s: sgl build failed\n", __func__); + rval = -EAGAIN; + mutex_unlock(&mrioc->bsg_cmds.mutex); + goto out; + } } if (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_TASK_MGMT) { @@ -1273,7 +1495,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply if (mpi_header->function == MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) { drv_buf_iter = &drv_bufs[0]; dprint_dump(drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); + rmc_size, "mpi3_mgmt_req"); } } @@ -1308,10 +1530,9 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) { drv_buf_iter = &drv_bufs[0]; dprint_dump(drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); + rmc_size, "mpi3_mgmt_req"); } } - if ((mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) || (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO)) mpi3mr_issue_tm(mrioc, @@ -1382,17 +1603,27 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { - tmplen = min(drv_buf_iter->kern_buf_len, - drv_buf_iter->bsg_buf_len); + if ((count == 1) && is_rmrb) { memcpy(drv_buf_iter->bsg_buf, - drv_buf_iter->kern_buf, tmplen); + drv_buf_iter->kern_buf, + drv_buf_iter->kern_buf_len); + } else if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { + tmplen = 0; + for (desc_count = 0; + desc_count < drv_buf_iter->num_dma_desc; + desc_count++) { + memcpy(((u8 *)drv_buf_iter->bsg_buf + tmplen), + drv_buf_iter->dma_desc[desc_count].addr, + drv_buf_iter->dma_desc[desc_count].size); + tmplen += + drv_buf_iter->dma_desc[desc_count].size; } } + } out_unlock: if (din_buf) { - *reply_payload_rcv_len = + job->reply_payload_rcv_len = sg_copy_from_buffer(job->reply_payload.sg_list, job->reply_payload.sg_cnt, din_buf, job->reply_payload.payload_len); @@ -1408,13 +1639,8 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply kfree(mpi_req); if (drv_bufs) { drv_buf_iter = drv_bufs; - for (count = 0; count < bufcnt; count++, drv_buf_iter++) { - if (drv_buf_iter->kern_buf && drv_buf_iter->kern_buf_dma) - dma_free_coherent(&mrioc->pdev->dev, - drv_buf_iter->kern_buf_len, - drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_dma); - } + for (count = 0; count < bufcnt; count++, drv_buf_iter++) + kfree(drv_buf_iter->dma_desc); kfree(drv_bufs); } kfree(bsg_reply_buf); @@ -1473,7 +1699,7 @@ static int mpi3mr_bsg_request(struct bsg_job *job) rval = mpi3mr_bsg_process_drv_cmds(job); break; case MPI3MR_MPT_CMD: - rval = mpi3mr_bsg_process_mpt_cmds(job, &reply_payload_rcv_len); + rval = mpi3mr_bsg_process_mpt_cmds(job); break; default: pr_err("%s: unsupported BSG command(0x%08x)\n", From 9536af615dc9ded0357341e8bd0efc8b34b2b484 Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Wed, 6 Dec 2023 00:46:29 +0530 Subject: [PATCH 2694/7721] scsi: mpi3mr: Support for preallocation of SGL BSG data buffers part-3 The driver acquires the required NVMe SGLs from the pre-allocated pool. Co-developed-by: Sathya Prakash Signed-off-by: Sathya Prakash Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231205191630.12201-4-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 10 ++- drivers/scsi/mpi3mr/mpi3mr_app.c | 124 ++++++++++++++++++++++------ include/uapi/scsi/scsi_bsg_mpi3mr.h | 2 + 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index dfff3df3a666..795e86626101 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -218,14 +218,16 @@ extern atomic64_t event_counter; * @length: SGE length * @rsvd: Reserved * @rsvd1: Reserved - * @sgl_type: sgl type + * @sub_type: sgl sub type + * @type: sgl type */ struct mpi3mr_nvme_pt_sge { - u64 base_addr; - u32 length; + __le64 base_addr; + __le32 length; u16 rsvd; u8 rsvd1; - u8 sgl_type; + u8 sub_type:4; + u8 type:4; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index e8b0b121a6e3..4b93b7440da6 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -783,14 +783,20 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc, struct mpi3mr_buf_map *drv_bufs, u8 bufcnt) { struct mpi3mr_nvme_pt_sge *nvme_sgl; - u64 sgl_ptr; + __le64 sgl_dma; u8 count; size_t length = 0; + u16 available_sges = 0, i; + u32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << mrioc->facts.sge_mod_shift) << 32); u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) << mrioc->facts.sge_mod_shift) << 32; + u32 size; + + nvme_sgl = (struct mpi3mr_nvme_pt_sge *) + ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); /* * Not all commands require a data transfer. If no data, just return @@ -799,27 +805,59 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc, for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - sgl_ptr = (u64)drv_buf_iter->kern_buf_dma; length = drv_buf_iter->kern_buf_len; break; } - if (!length) + if (!length || !drv_buf_iter->num_dma_desc) return 0; - if (sgl_ptr & sgemod_mask) { + if (drv_buf_iter->num_dma_desc == 1) { + available_sges = 1; + goto build_sges; + } + + sgl_dma = cpu_to_le64(mrioc->ioctl_chain_sge.dma_addr); + if (sgl_dma & sgemod_mask) { dprint_bsg_err(mrioc, - "%s: SGL address collides with SGE modifier\n", + "%s: SGL chain address collides with SGE modifier\n", __func__); return -1; } - sgl_ptr &= ~sgemod_mask; - sgl_ptr |= sgemod_val; - nvme_sgl = (struct mpi3mr_nvme_pt_sge *) - ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); + available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; + if (available_sges < drv_buf_iter->num_dma_desc) + return -1; memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); - nvme_sgl->base_addr = sgl_ptr; - nvme_sgl->length = length; + nvme_sgl->base_addr = sgl_dma; + size = drv_buf_iter->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); + nvme_sgl->length = cpu_to_le32(size); + nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; + nvme_sgl = (struct mpi3mr_nvme_pt_sge *)mrioc->ioctl_chain_sge.addr; + +build_sges: + for (i = 0; i < drv_buf_iter->num_dma_desc; i++) { + sgl_dma = cpu_to_le64(drv_buf_iter->dma_desc[i].dma_addr); + if (sgl_dma & sgemod_mask) { + dprint_bsg_err(mrioc, + "%s: SGL address collides with SGE modifier\n", + __func__); + return -1; + } + + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + nvme_sgl->base_addr = sgl_dma; + nvme_sgl->length = cpu_to_le32(drv_buf_iter->dma_desc[i].size); + nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; + nvme_sgl++; + available_sges--; + } + return 0; } @@ -847,7 +885,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, dma_addr_t prp_entry_dma, prp_page_dma, dma_addr; u32 offset, entry_len, dev_pgsz; u32 page_mask_result, page_mask; - size_t length = 0; + size_t length = 0, desc_len; u8 count; struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << @@ -856,6 +894,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, mrioc->facts.sge_mod_shift) << 32; u16 dev_handle = nvme_encap_request->dev_handle; struct mpi3mr_tgt_dev *tgtdev; + u16 desc_count = 0; tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); if (!tgtdev) { @@ -874,6 +913,21 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); mpi3mr_tgtdev_put(tgtdev); + page_mask = dev_pgsz - 1; + + if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE) { + dprint_bsg_err(mrioc, + "%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", + __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); + return -1; + } + + if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz) { + dprint_bsg_err(mrioc, + "%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", + __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); + return -1; + } /* * Not all commands require a data transfer. If no data, just return @@ -882,14 +936,26 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - dma_addr = drv_buf_iter->kern_buf_dma; length = drv_buf_iter->kern_buf_len; break; } - if (!length) + if (!length || !drv_buf_iter->num_dma_desc) return 0; + for (count = 0; count < drv_buf_iter->num_dma_desc; count++) { + dma_addr = drv_buf_iter->dma_desc[count].dma_addr; + if (dma_addr & page_mask) { + dprint_bsg_err(mrioc, + "%s:dma_addr 0x%llx is not aligned with page size 0x%x\n", + __func__, dma_addr, dev_pgsz); + return -1; + } + } + + dma_addr = drv_buf_iter->dma_desc[0].dma_addr; + desc_len = drv_buf_iter->dma_desc[0].size; + mrioc->prp_sz = 0; mrioc->prp_list_virt = dma_alloc_coherent(&mrioc->pdev->dev, dev_pgsz, &mrioc->prp_list_dma, GFP_KERNEL); @@ -919,7 +985,6 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, * Check if we are within 1 entry of a page boundary we don't * want our first entry to be a PRP List entry. */ - page_mask = dev_pgsz - 1; page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; if (!page_mask_result) { dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n", @@ -1033,18 +1098,31 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, prp_entry_dma += prp_size; } - /* - * Bump the phys address of the command's data buffer by the - * entry_len. - */ - dma_addr += entry_len; - /* decrement length accounting for last partial page. */ - if (entry_len > length) + if (entry_len >= length) { length = 0; - else + } else { + if (entry_len <= desc_len) { + dma_addr += entry_len; + desc_len -= entry_len; + } + if (!desc_len) { + if ((++desc_count) >= + drv_buf_iter->num_dma_desc) { + dprint_bsg_err(mrioc, + "%s: Invalid len %ld while building PRP\n", + __func__, length); + goto err_out; + } + dma_addr = + drv_buf_iter->dma_desc[desc_count].dma_addr; + desc_len = + drv_buf_iter->dma_desc[desc_count].size; + } length -= entry_len; + } } + return 0; err_out: if (mrioc->prp_list_virt) { diff --git a/include/uapi/scsi/scsi_bsg_mpi3mr.h b/include/uapi/scsi/scsi_bsg_mpi3mr.h index 907d345f04f9..c72ce387286a 100644 --- a/include/uapi/scsi/scsi_bsg_mpi3mr.h +++ b/include/uapi/scsi/scsi_bsg_mpi3mr.h @@ -491,6 +491,8 @@ struct mpi3_nvme_encapsulated_error_reply { #define MPI3MR_NVME_DATA_FORMAT_PRP 0 #define MPI3MR_NVME_DATA_FORMAT_SGL1 1 #define MPI3MR_NVME_DATA_FORMAT_SGL2 2 +#define MPI3MR_NVMESGL_DATA_SEGMENT 0x00 +#define MPI3MR_NVMESGL_LAST_SEGMENT 0x03 /* MPI3: task management related definitions */ struct mpi3_scsi_task_mgmt_request { From d0a60e3edaa4a12e52fe8ea1d8b125f0405934cf Mon Sep 17 00:00:00 2001 From: Chandrakanth patil Date: Wed, 6 Dec 2023 00:46:30 +0530 Subject: [PATCH 2695/7721] scsi: mpi3mr: Update driver version to 8.5.1.0.0 Update driver version to 8.5.1.0.0 Signed-off-by: Chandrakanth patil Link: https://lore.kernel.org/r/20231205191630.12201-5-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 795e86626101..3de1ee05c44e 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -55,8 +55,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.5.0.0.50" -#define MPI3MR_DRIVER_RELDATE "22-November-2023" +#define MPI3MR_DRIVER_VERSION "8.5.1.0.0" +#define MPI3MR_DRIVER_RELDATE "5-December-2023" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" From 5854cdd04163ea7aa454b619708f710cef9e04e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:46 +0100 Subject: [PATCH 2696/7721] scsi: a3000: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/811d180950b76c2d95cd080e3c251757ca011380.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/a3000.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index c3028726bbe4..378906f77909 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -282,7 +282,7 @@ static int __init amiga_a3000_scsi_probe(struct platform_device *pdev) return error; } -static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) +static void __exit amiga_a3000_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); struct a3000_hostdata *hdata = shost_priv(instance); @@ -293,11 +293,10 @@ static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) free_irq(IRQ_AMIGA_PORTS, instance); scsi_host_put(instance); release_mem_region(res->start, resource_size(res)); - return 0; } static struct platform_driver amiga_a3000_scsi_driver = { - .remove = __exit_p(amiga_a3000_scsi_remove), + .remove_new = __exit_p(amiga_a3000_scsi_remove), .driver = { .name = "amiga-a3000-scsi", }, From 688bbe398ca63bace6b8fb40b9dbc605c5add034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:47 +0100 Subject: [PATCH 2697/7721] scsi: a4000t: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/c15ffc57efebc5da3f7e6dd558d69181e129cafe.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/a4000t.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index 5e575afce134..e435fc06a624 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -95,7 +95,7 @@ static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev) return -ENODEV; } -static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) +static void __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); @@ -106,11 +106,10 @@ static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) kfree(hostdata); free_irq(host->irq, host); release_mem_region(res->start, resource_size(res)); - return 0; } static struct platform_driver amiga_a4000t_scsi_driver = { - .remove = __exit_p(amiga_a4000t_scsi_remove), + .remove_new = __exit_p(amiga_a4000t_scsi_remove), .driver = { .name = "amiga-a4000t-scsi", }, From 3becb4cdf1c1250b880d04f00506f185b614c5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:48 +0100 Subject: [PATCH 2698/7721] scsi: atari: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/27a2b133b1b88a9baf51353c511e93a5027f9602.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/atari_scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index d401cf27113a..d99e70914817 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -865,7 +865,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev) return error; } -static int __exit atari_scsi_remove(struct platform_device *pdev) +static void __exit atari_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); @@ -876,11 +876,10 @@ static int __exit atari_scsi_remove(struct platform_device *pdev) scsi_host_put(instance); if (atari_dma_buffer) atari_stram_free(atari_dma_buffer); - return 0; } static struct platform_driver atari_scsi_driver = { - .remove = __exit_p(atari_scsi_remove), + .remove_new = __exit_p(atari_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, From 51a41ec6d36e586e978785709d33b22cc8ee455c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:49 +0100 Subject: [PATCH 2699/7721] scsi: bvme6000: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/63294479a4e745210c078859afa88904fa0b3be8.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/bvme6000_scsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index 8d72b25535c5..f893e9779e9d 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -89,7 +89,7 @@ bvme6000_probe(struct platform_device *dev) return -ENODEV; } -static int +static void bvme6000_device_remove(struct platform_device *dev) { struct Scsi_Host *host = platform_get_drvdata(dev); @@ -99,8 +99,6 @@ bvme6000_device_remove(struct platform_device *dev) NCR_700_release(host); kfree(hostdata); free_irq(host->irq, host); - - return 0; } static struct platform_driver bvme6000_scsi_driver = { @@ -108,7 +106,7 @@ static struct platform_driver bvme6000_scsi_driver = { .name = "bvme6000-scsi", }, .probe = bvme6000_probe, - .remove = bvme6000_device_remove, + .remove_new = bvme6000_device_remove, }; static int __init bvme6000_scsi_init(void) From c71ef3d1fb39ee4503b5d3f5e358c6588c071520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:50 +0100 Subject: [PATCH 2700/7721] scsi: jazz_esp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/f71efbe17973c97fd2a1e78f8d7fcf456644510b.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/jazz_esp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 0c842fb29aa0..494a671fb556 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -176,7 +176,7 @@ static int esp_jazz_probe(struct platform_device *dev) return err; } -static int esp_jazz_remove(struct platform_device *dev) +static void esp_jazz_remove(struct platform_device *dev) { struct esp *esp = dev_get_drvdata(&dev->dev); unsigned int irq = esp->host->irq; @@ -189,8 +189,6 @@ static int esp_jazz_remove(struct platform_device *dev) esp->command_block_dma); scsi_host_put(esp->host); - - return 0; } /* work with hotplug and coldplug */ @@ -198,7 +196,7 @@ MODULE_ALIAS("platform:jazz_esp"); static struct platform_driver esp_jazz_driver = { .probe = esp_jazz_probe, - .remove = esp_jazz_remove, + .remove_new = esp_jazz_remove, .driver = { .name = "jazz_esp", }, From 0b649224f712cdfb90c8e9c22929dcb55868fc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:51 +0100 Subject: [PATCH 2701/7721] scsi: mac_esp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/9013c84059b8ccd6a5c8305aa35cfdfa314ba74c.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_esp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 3f0061b00494..187ae0a65d40 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -407,7 +407,7 @@ static int esp_mac_probe(struct platform_device *dev) return err; } -static int esp_mac_remove(struct platform_device *dev) +static void esp_mac_remove(struct platform_device *dev) { struct mac_esp_priv *mep = platform_get_drvdata(dev); struct esp *esp = mep->esp; @@ -428,13 +428,11 @@ static int esp_mac_remove(struct platform_device *dev) kfree(esp->command_block); scsi_host_put(esp->host); - - return 0; } static struct platform_driver esp_mac_driver = { .probe = esp_mac_probe, - .remove = esp_mac_remove, + .remove_new = esp_mac_remove, .driver = { .name = DRV_MODULE_NAME, }, From 69b43bf38b11cf361a1372281aa0ffe0c5cb2d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:52 +0100 Subject: [PATCH 2702/7721] scsi: mac: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/89ce161dad52d99df07135531512ccecb7f25d14.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 2e511697fce3..181f16899fdc 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -523,7 +523,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev) return error; } -static int __exit mac_scsi_remove(struct platform_device *pdev) +static void __exit mac_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); @@ -532,11 +532,10 @@ static int __exit mac_scsi_remove(struct platform_device *pdev) free_irq(instance->irq, instance); NCR5380_exit(instance); scsi_host_put(instance); - return 0; } static struct platform_driver mac_scsi_driver = { - .remove = __exit_p(mac_scsi_remove), + .remove_new = __exit_p(mac_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, From f0baf76a22049d55a4901c1a933e479c638af94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:53 +0100 Subject: [PATCH 2703/7721] scsi: mvme16x: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/1d16e93a498831abd64df8b8cf54fd8872cdd1cd.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/mvme16x_scsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index 21d638299ab8..e08a38e2a442 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -103,7 +103,7 @@ static int mvme16x_probe(struct platform_device *dev) return -ENODEV; } -static int mvme16x_device_remove(struct platform_device *dev) +static void mvme16x_device_remove(struct platform_device *dev) { struct Scsi_Host *host = platform_get_drvdata(dev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); @@ -120,8 +120,6 @@ static int mvme16x_device_remove(struct platform_device *dev) NCR_700_release(host); kfree(hostdata); free_irq(host->irq, host); - - return 0; } static struct platform_driver mvme16x_scsi_driver = { @@ -129,7 +127,7 @@ static struct platform_driver mvme16x_scsi_driver = { .name = "mvme16x-scsi", }, .probe = mvme16x_probe, - .remove = mvme16x_device_remove, + .remove_new = mvme16x_device_remove, }; static int __init mvme16x_scsi_init(void) From e26eec9a4d25752404b35e7700f84834002ee75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:54 +0100 Subject: [PATCH 2704/7721] scsi: qlogicpti: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/8242c07f617fc946aab857c9357f540598fe964e.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/qlogicpti.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 3b95f7a6216f..5d560d9b8944 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1409,7 +1409,7 @@ static int qpti_sbus_probe(struct platform_device *op) return -ENODEV; } -static int qpti_sbus_remove(struct platform_device *op) +static void qpti_sbus_remove(struct platform_device *op) { struct qlogicpti *qpti = dev_get_drvdata(&op->dev); @@ -1438,8 +1438,6 @@ static int qpti_sbus_remove(struct platform_device *op) of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char)); scsi_host_put(qpti->qhost); - - return 0; } static const struct of_device_id qpti_match[] = { @@ -1465,7 +1463,7 @@ static struct platform_driver qpti_sbus_driver = { .of_match_table = qpti_match, }, .probe = qpti_sbus_probe, - .remove = qpti_sbus_remove, + .remove_new = qpti_sbus_remove, }; module_platform_driver(qpti_sbus_driver); From 358987af1bda5c0b6a9aacc0644a108e711266b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:55 +0100 Subject: [PATCH 2705/7721] scsi: sgiwd93: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/92114604fd1274073915e515cae15003ff07aa4a.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/sgiwd93.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 88e2b5eb9caa..b0bef83db7b6 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -291,7 +291,7 @@ static int sgiwd93_probe(struct platform_device *pdev) return err; } -static int sgiwd93_remove(struct platform_device *pdev) +static void sgiwd93_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; @@ -302,12 +302,11 @@ static int sgiwd93_remove(struct platform_device *pdev) dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma, DMA_TO_DEVICE); scsi_host_put(host); - return 0; } static struct platform_driver sgiwd93_driver = { .probe = sgiwd93_probe, - .remove = sgiwd93_remove, + .remove_new = sgiwd93_remove, .driver = { .name = "sgiwd93", } From 357a7fd2434e857bc3911cfbb02285f8b25e8d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:56 +0100 Subject: [PATCH 2706/7721] scsi: sni_53c710: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/2f4b7366ca00a107a9595514795e909e632980da.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/sni_53c710.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 678651b9b4dd..9df1c90a24c1 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -104,7 +104,7 @@ static int snirm710_probe(struct platform_device *dev) return -ENODEV; } -static int snirm710_driver_remove(struct platform_device *dev) +static void snirm710_driver_remove(struct platform_device *dev) { struct Scsi_Host *host = dev_get_drvdata(&dev->dev); struct NCR_700_Host_Parameters *hostdata = @@ -115,13 +115,11 @@ static int snirm710_driver_remove(struct platform_device *dev) free_irq(host->irq, host); iounmap(hostdata->base); kfree(hostdata); - - return 0; } static struct platform_driver snirm710_driver = { .probe = snirm710_probe, - .remove = snirm710_driver_remove, + .remove_new = snirm710_driver_remove, .driver = { .name = "snirm_53c710", }, From 15b016b2d023e4ba3603daa21aa346033c486930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:57 +0100 Subject: [PATCH 2707/7721] scsi: sun3: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/84239a68fe06143d1d6fed6c9aaae6a4680ead71.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/sun3_scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index abf229b847a1..4a8cc2e8238e 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -641,7 +641,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev) return error; } -static int __exit sun3_scsi_remove(struct platform_device *pdev) +static void __exit sun3_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); struct NCR5380_hostdata *hostdata = shost_priv(instance); @@ -654,11 +654,10 @@ static int __exit sun3_scsi_remove(struct platform_device *pdev) if (udc_regs) dvma_free(udc_regs); iounmap(ioaddr); - return 0; } static struct platform_driver sun3_scsi_driver = { - .remove = __exit_p(sun3_scsi_remove), + .remove_new = __exit_p(sun3_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, From e84bd0bb30689023410f3cd5090c8ed11937096f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:58 +0100 Subject: [PATCH 2708/7721] scsi: sun3x_esp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/5010d1a4f3d77eaa1114fa254c343c4f23313901.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/sun3x_esp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 30f67cbf4a7a..09219c362acc 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -243,7 +243,7 @@ static int esp_sun3x_probe(struct platform_device *dev) return err; } -static int esp_sun3x_remove(struct platform_device *dev) +static void esp_sun3x_remove(struct platform_device *dev) { struct esp *esp = dev_get_drvdata(&dev->dev); unsigned int irq = esp->host->irq; @@ -261,13 +261,11 @@ static int esp_sun3x_remove(struct platform_device *dev) esp->command_block_dma); scsi_host_put(esp->host); - - return 0; } static struct platform_driver esp_sun3x_driver = { .probe = esp_sun3x_probe, - .remove = esp_sun3x_remove, + .remove_new = esp_sun3x_remove, .driver = { .name = "sun3x_esp", }, From 6ff482eeebe57ee7becee66f7de4b864dcc4175d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 3 Dec 2023 17:05:59 +0100 Subject: [PATCH 2709/7721] scsi: sun_esp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/1d385231c23c2a1e6e7dc1968eb111327386d1f6.1701619134.git.u.kleine-koenig@pengutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/sun_esp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index afa9d02a33ec..64a7c2c6c5ff 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -550,7 +550,7 @@ static int esp_sbus_probe(struct platform_device *op) return ret; } -static int esp_sbus_remove(struct platform_device *op) +static void esp_sbus_remove(struct platform_device *op) { struct esp *esp = dev_get_drvdata(&op->dev); struct platform_device *dma_of = esp->dma; @@ -581,8 +581,6 @@ static int esp_sbus_remove(struct platform_device *op) dev_set_drvdata(&op->dev, NULL); put_device(&dma_of->dev); - - return 0; } static const struct of_device_id esp_match[] = { @@ -605,7 +603,7 @@ static struct platform_driver esp_sbus_driver = { .of_match_table = esp_match, }, .probe = esp_sbus_probe, - .remove = esp_sbus_remove, + .remove_new = esp_sbus_remove, }; module_platform_driver(esp_sbus_driver); From ffce67b61108aaab6061f122b5cffe6c4e59fee2 Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Fri, 1 Dec 2023 16:07:32 +0100 Subject: [PATCH 2710/7721] dt-bindings: arm: fsl: add verdin imx8mm mallow board Add Mallow carrier board for wifi and nonwifi variants of Toradex Verdin IMX8MM SoM. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Acked-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index dc45b4cd867f..810857bacaa9 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -967,6 +967,7 @@ properties: - menlo,mx8menlo # Verdin iMX8M Mini Module on i.MX8MM Menlo board - toradex,verdin-imx8mm-nonwifi-dahlia # Verdin iMX8M Mini Module on Dahlia - toradex,verdin-imx8mm-nonwifi-dev # Verdin iMX8M Mini Module on Verdin Development Board + - toradex,verdin-imx8mm-nonwifi-mallow # Verdin iMX8M Mini Module on Mallow - toradex,verdin-imx8mm-nonwifi-yavia # Verdin iMX8M Mini Module on Yavia - const: toradex,verdin-imx8mm-nonwifi # Verdin iMX8M Mini Module without Wi-Fi / BT - const: toradex,verdin-imx8mm # Verdin iMX8M Mini Module @@ -977,6 +978,7 @@ properties: - enum: - toradex,verdin-imx8mm-wifi-dahlia # Verdin iMX8M Mini Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mm-wifi-dev # Verdin iMX8M Mini Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mm-wifi-mallow # Verdin iMX8M Mini Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mm-wifi-yavia # Verdin iMX8M Mini Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mm-wifi # Verdin iMX8M Mini Wi-Fi / BT Module - const: toradex,verdin-imx8mm # Verdin iMX8M Mini Module From 63ff54dfa832695263e60215c07768adad98f573 Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Fri, 1 Dec 2023 16:39:28 +0100 Subject: [PATCH 2711/7721] dt-bindings: arm: fsl: add verdin imx8mp mallow board Add Mallow carrier board for wifi and nonwifi variants of Toradex Verdin IMX8MP SoM. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Acked-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 810857bacaa9..cd87d1afe7b7 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -1107,6 +1107,7 @@ properties: - enum: - toradex,verdin-imx8mp-nonwifi-dahlia # Verdin iMX8M Plus Module on Dahlia - toradex,verdin-imx8mp-nonwifi-dev # Verdin iMX8M Plus Module on Verdin Development Board + - toradex,verdin-imx8mp-nonwifi-mallow # Verdin iMX8M Plus Module on Mallow - toradex,verdin-imx8mp-nonwifi-yavia # Verdin iMX8M Plus Module on Yavia - const: toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Module without Wi-Fi / BT - const: toradex,verdin-imx8mp # Verdin iMX8M Plus Module @@ -1117,6 +1118,7 @@ properties: - enum: - toradex,verdin-imx8mp-wifi-dahlia # Verdin iMX8M Plus Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mp-wifi-dev # Verdin iMX8M Plus Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mp-wifi-mallow # Verdin iMX8M Plus Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mp-wifi-yavia # Verdin iMX8M Plus Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Module - const: toradex,verdin-imx8mp # Verdin iMX8M Plus Module From e3873abfe0f7f65bff320ca9d97fe6a7410746f7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 30 Nov 2023 19:52:42 -0300 Subject: [PATCH 2712/7721] arm64: dts: imx8mm-venice-gw7: Adjust PCI Ethernet nodes As per Rob Herring's feedback: "The ethernet device should have a node name of 'ethernet'. The 'pcie' node name and 'device_type = "pci"' is for PCI buses/bridges only." Do it as suggested. Fixes: d61c5068729a ("arm64: dts: imx8mm-venice-gw7: Fix pci sub-nodes") Suggested-by: Rob Herring Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi | 3 +-- arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi | 3 +-- arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index a337e8f20441..3f3f2a2c89cd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -178,9 +178,8 @@ pcie@3,0 { #size-cells = <2>; ranges; - eth1: pcie@0,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi index 2247d1c4e2af..06fed9376996 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi @@ -198,9 +198,8 @@ pcie@4,0 { #size-cells = <2>; ranges; - eth1: pcie@0,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts index 7ef17c2b0e9d..c11260c26d0b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts @@ -640,9 +640,8 @@ pcie@0,0 { #size-cells = <2>; ranges; - eth1: pcie@0,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges; From eb9348865fabe4e0bc0b0453813dba8ecbfd9deb Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Fri, 1 Dec 2023 16:07:33 +0100 Subject: [PATCH 2713/7721] arm64: dts: freescale: verdin-imx8mm: add support to mallow board Add Toradex Verdin IMX8MM Mallow carrier board support. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 2 + .../dts/freescale/imx8mm-verdin-mallow.dtsi | 173 ++++++++++++++++++ .../imx8mm-verdin-nonwifi-mallow.dts | 18 ++ .../freescale/imx8mm-verdin-wifi-mallow.dts | 18 ++ 4 files changed, 211 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index a1082a097656..3571efe67a7f 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -84,9 +84,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7905-0x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33.dtbo diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi new file mode 100644 index 000000000000..4a0799d63446 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin IMX8MM SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-mini-nano + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Verdin SPI_1 */ +&ecspi2 { + pinctrl-0 = <&pinctrl_ecspi2>, <&pinctrl_tpm_cs>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, <&gpio3 2 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm_irq>; + interrupt-parent = <&gpio3>; + interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + spi-max-frequency = <18500000>; + }; +}; + +/* EEPROM on Mallow */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&fec1 { + status = "okay"; +}; + +/* Temperature sensor on Mallow */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_2_DSI */ +&i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4_CSI */ +&i2c3 { + status = "okay"; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie0 { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin PWM_3_DSI */ +&pwm1 { + status = "okay"; +}; + +/* Verdin PWM_1 */ +&pwm2 { + status = "okay"; +}; + +/* Verdin PWM_2 */ +&pwm3 { + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&uart2 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart3 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usbotg1 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbotg2 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + pinctrl_leds: ledsgrp { + fsl,pins = + , /* SODIMM 52 */ + , /* SODIMM 54 */ + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_tpm_cs: tpmcsgrp { + fsl,pins = + ; /* SODIMM 64 */ + }; + + pinctrl_tpm_irq: tpmirqgrp { + fsl,pins = + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts new file mode 100644 index 000000000000..1b1999f3a80e --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-nonwifi.dtsi" +#include "imx8mm-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini on Mallow"; + compatible = "toradex,verdin-imx8mm-nonwifi-mallow", + "toradex,verdin-imx8mm-nonwifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts new file mode 100644 index 000000000000..2916145f31bb --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-wifi.dtsi" +#include "imx8mm-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini WB on Mallow"; + compatible = "toradex,verdin-imx8mm-wifi-mallow", + "toradex,verdin-imx8mm-wifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; From 12f2486ebe70098944444057f7b5b592fe325870 Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Fri, 1 Dec 2023 16:39:29 +0100 Subject: [PATCH 2714/7721] arm64: dts: freescale: verdin-imx8mp: add support to mallow board Add Toradex Verdin IMX8MP Mallow carrier board support. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 2 + .../dts/freescale/imx8mp-verdin-mallow.dtsi | 199 ++++++++++++++++++ .../imx8mp-verdin-nonwifi-mallow.dts | 18 ++ .../freescale/imx8mp-verdin-wifi-mallow.dts | 18 ++ 4 files changed, 237 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 3571efe67a7f..d22e4f4f886d 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -129,9 +129,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw74xx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw7905-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-yavia.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds.dtbo diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi new file mode 100644 index 000000000000..8482393f3cac --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin IMX8MP SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-plus + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&backlight { + power-supply = <®_3p3v>; +}; + +/* Verdin SPI_1 */ +&ecspi1 { + pinctrl-0 = <&pinctrl_ecspi1>, <&pinctrl_tpm_cs>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio3 16 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm_irq>; + interrupt-parent = <&gpio3>; + interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + spi-max-frequency = <18500000>; + }; +}; + +/* EEPROM on Mallow */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&eqos { + status = "okay"; +}; + +/* Verdin CAN_1 */ +&flexcan1 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&flexcan2 { + status = "okay"; +}; + +/* Temperature sensor on Mallow */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_2_DSI */ +&i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4_CSI */ +&i2c3 { + status = "okay"; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin PWM_1 */ +&pwm1 { + status = "okay"; +}; + +/* Verdin PWM_2 */ +&pwm2 { + status = "okay"; +}; + +/* Verdin PWM_3_DSI */ +&pwm3 { + status = "okay"; +}; + +®_usdhc2_vmmc { + vin-supply = <®_3p3v>; +}; + +/* Verdin UART_1 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart2 { + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart3 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usb3_0 { + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usb3_1 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + pinctrl_leds: ledsgrp { + fsl,pins = + , /* SODIMM 52 */ + , /* SODIMM 54 */ + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_tpm_cs: tpmcsgrp { + fsl,pins = + ; /* SODIMM 64 */ + }; + + pinctrl_tpm_irq: tpmirqgrp { + fsl,pins = + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts new file mode 100644 index 000000000000..6a536a4964bb --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-nonwifi.dtsi" +#include "imx8mp-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus on Mallow Board"; + compatible = "toradex,verdin-imx8mp-nonwifi-mallow", + "toradex,verdin-imx8mp-nonwifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts new file mode 100644 index 000000000000..08b7aef3fdde --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-wifi.dtsi" +#include "imx8mp-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus WB on Mallow Board"; + compatible = "toradex,verdin-imx8mp-wifi-mallow", + "toradex,verdin-imx8mp-wifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; From c0ac4eb8b8e9d351d3e546ed0b120926ceebdc30 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Sat, 2 Dec 2023 23:29:01 +0100 Subject: [PATCH 2715/7721] arm64: dts: imx8mq-phanbell: make dts use gpio-fan matrix instead of array No functional changes. Adjust to comply with dt-schema requirements and make possible to validate values. Signed-off-by: David Heidelberg Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts index a3b9d615a3b4..e34045d10a12 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts @@ -39,7 +39,7 @@ reg_usdhc2_vmmc: regulator-usdhc2-vmmc { fan: gpio-fan { compatible = "gpio-fan"; - gpio-fan,speed-map = <0 0 8600 1>; + gpio-fan,speed-map = <0 0>, <8600 1>; gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; #cooling-cells = <2>; pinctrl-names = "default"; From 620360bf7dbfe3c61bdbf3a88535a0030ff787b5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Dec 2023 11:53:35 -0300 Subject: [PATCH 2716/7721] ARM: dts: imx28-tx28: Pass #sound-dai-cells Per sgtl5000.yaml, '#sound-dai-cells' is a required property. Pass it to fix the following dt-schema warning: imx28-tx28.dtb: sgtl5000@a: '#sound-dai-cells' is a required property from schema $id: http://devicetree.org/schemas/sound/sgtl5000.yaml# Signed-off-by: Fabio Estevam Reviewed-by: Stefan Wahren Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts b/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts index 153e4017951d..5485fe118dc4 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts +++ b/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts @@ -260,6 +260,7 @@ &i2c0 { sgtl5000: sgtl5000@a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + #sound-dai-cells = <0>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; clocks = <&mclk>; From 844542b0fcec8f4db4a714fab96d4d99a1122ed7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Dec 2023 09:57:31 -0300 Subject: [PATCH 2717/7721] ARM: dts: imx23/28: Remove unneeded "fsl,mxs-gpio" According to gpio-mxs.yaml, only "fsl,imx23-gpio" or "fsl,imx28-gpio" are valid compatible strings. This fixes the following dt-schema warnings: imx23-evk.dtb: pinctrl@80018000: gpio@0:compatible: ['fsl,imx23-gpio', 'fsl,mxs-gpio'] is too long from schema $id: http://devicetree.org/schemas/gpio/gpio-mxs.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/mxs/imx23.dtsi | 6 +++--- arch/arm/boot/dts/nxp/mxs/imx28.dtsi | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi index fdf18b7cb2f6..60bd88585bb4 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi @@ -110,7 +110,7 @@ pinctrl@80018000 { reg = <0x80018000 0x2000>; gpio0: gpio@0 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <0>; interrupts = <16>; gpio-controller; @@ -120,7 +120,7 @@ gpio0: gpio@0 { }; gpio1: gpio@1 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <1>; interrupts = <17>; gpio-controller; @@ -130,7 +130,7 @@ gpio1: gpio@1 { }; gpio2: gpio@2 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <2>; interrupts = <18>; gpio-controller; diff --git a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi index 6932d23fb29d..409952feec2c 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi @@ -164,7 +164,7 @@ pinctrl: pinctrl@80018000 { reg = <0x80018000 0x2000>; gpio0: gpio@0 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <0>; interrupts = <127>; gpio-controller; @@ -174,7 +174,7 @@ gpio0: gpio@0 { }; gpio1: gpio@1 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <1>; interrupts = <126>; gpio-controller; @@ -184,7 +184,7 @@ gpio1: gpio@1 { }; gpio2: gpio@2 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <2>; interrupts = <125>; gpio-controller; @@ -194,7 +194,7 @@ gpio2: gpio@2 { }; gpio3: gpio@3 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <3>; interrupts = <124>; gpio-controller; @@ -204,7 +204,7 @@ gpio3: gpio@3 { }; gpio4: gpio@4 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <4>; interrupts = <123>; gpio-controller; From 287e256c1a6e2b92da938efc87a34e3c008d8319 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Dec 2023 10:18:38 -0300 Subject: [PATCH 2718/7721] ARM: dts: imx28-lwe: Pass device_type to the memory node Per memory.yaml, 'device_type' is a required property. Pass it to fix the following dt-schema warning: imx28-xea.dtb: /: memory@40000000: 'device_type' is a required property from schema $id: http://devicetree.org/schemas/memory.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi index bb971e660db8..69fcb0dde940 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi @@ -18,6 +18,7 @@ chosen { memory@40000000 { reg = <0x40000000 0x08000000>; + device_type = "memory"; }; reg_3v3: regulator-reg-3v3 { From c8705471b94d0d869e2e3ac80c0d960f0215474f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Dec 2023 11:47:12 -0300 Subject: [PATCH 2719/7721] ARM: mxs: Do not search for "fsl,clkctrl" The "fsl,clkctrl" compatible string is not documented. It is used only to find the base address of the clock controller. Instead of searching for an undocumented compatible string, search for "fsl,imx23-clkctrl" and "fsl,imx28-clkctrl". Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-mxs/mach-mxs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 3faf9a1e3e36..6e017fa306c8 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -356,7 +356,9 @@ static int __init mxs_restart_init(void) { struct device_node *np; - np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); + np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); + if (!np) + np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); reset_addr = of_iomap(np, 0); if (!reset_addr) return -ENODEV; From 2ff46b9eca2bb86c364942e86fd0145d56b62e40 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Dec 2023 09:57:21 +0100 Subject: [PATCH 2720/7721] net: hns3: reduce stack usage in hclge_dbg_dump_tm_pri() This function exceeds the stack frame warning limit: drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c: In function 'hclge_dbg_dump_tm_pri': drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c:1039:1: error: the frame size of 1408 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Use dynamic allocation for the largest stack object instead. It would be nice to rewrite this file to completely avoid the extra buffer and just use the one that was already allocated by debugfs, but that is a much larger change. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231204085735.4112882-1-arnd@kernel.org Signed-off-by: Jakub Kicinski --- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index ff3f8f424ad9..9ec471ced3d6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -981,19 +981,24 @@ static const struct hclge_dbg_item tm_pri_items[] = { static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len) { - char data_str[ARRAY_SIZE(tm_pri_items)][HCLGE_DBG_DATA_STR_LEN]; struct hclge_tm_shaper_para c_shaper_para, p_shaper_para; char *result[ARRAY_SIZE(tm_pri_items)], *sch_mode_str; char content[HCLGE_DBG_TM_INFO_LEN]; u8 pri_num, sch_mode, weight, i, j; + char *data_str; int pos, ret; ret = hclge_tm_get_pri_num(hdev, &pri_num); if (ret) return ret; + data_str = kcalloc(ARRAY_SIZE(tm_pri_items), HCLGE_DBG_DATA_STR_LEN, + GFP_KERNEL); + if (!data_str) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(tm_pri_items); i++) - result[i] = &data_str[i][0]; + result[i] = &data_str[i * HCLGE_DBG_DATA_STR_LEN]; hclge_dbg_fill_content(content, sizeof(content), tm_pri_items, NULL, ARRAY_SIZE(tm_pri_items)); @@ -1002,23 +1007,23 @@ static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len) for (i = 0; i < pri_num; i++) { ret = hclge_tm_get_pri_sch_mode(hdev, i, &sch_mode); if (ret) - return ret; + goto out; ret = hclge_tm_get_pri_weight(hdev, i, &weight); if (ret) - return ret; + goto out; ret = hclge_tm_get_pri_shaper(hdev, i, HCLGE_OPC_TM_PRI_C_SHAPPING, &c_shaper_para); if (ret) - return ret; + goto out; ret = hclge_tm_get_pri_shaper(hdev, i, HCLGE_OPC_TM_PRI_P_SHAPPING, &p_shaper_para); if (ret) - return ret; + goto out; sch_mode_str = sch_mode & HCLGE_TM_TX_SCHD_DWRR_MSK ? "dwrr" : "sp"; @@ -1035,7 +1040,9 @@ static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len) pos += scnprintf(buf + pos, len - pos, "%s", content); } - return 0; +out: + kfree(data_str); + return ret; } static const struct hclge_dbg_item tm_qset_items[] = { From a92dbb9cdf0465d56c7e0fc5d674e6834f7c6a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:41 +0100 Subject: [PATCH 2721/7721] net: ipa: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231117095922.876489-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/c43193b9a002e88da36b111bb44ce2973ecde722.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_main.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 86884c21e792..00475fd7a205 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -943,7 +943,7 @@ static int ipa_probe(struct platform_device *pdev) return ret; } -static int ipa_remove(struct platform_device *pdev) +static void ipa_remove(struct platform_device *pdev) { struct ipa *ipa = dev_get_drvdata(&pdev->dev); struct ipa_power *power = ipa->power; @@ -966,8 +966,16 @@ static int ipa_remove(struct platform_device *pdev) usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); ret = ipa_modem_stop(ipa); } - if (ret) - return ret; + if (ret) { + /* + * Not cleaning up here properly might also yield a + * crash later on. As the device is still unregistered + * in this case, this might even yield a crash later on. + */ + dev_err(dev, "Failed to stop modem (%pe), leaking resources\n", + ERR_PTR(ret)); + return; + } ipa_teardown(ipa); } @@ -985,17 +993,6 @@ static int ipa_remove(struct platform_device *pdev) ipa_power_exit(power); dev_info(dev, "IPA driver removed"); - - return 0; -} - -static void ipa_shutdown(struct platform_device *pdev) -{ - int ret; - - ret = ipa_remove(pdev); - if (ret) - dev_err(&pdev->dev, "shutdown: remove returned %d\n", ret); } static const struct attribute_group *ipa_attribute_groups[] = { @@ -1008,8 +1005,8 @@ static const struct attribute_group *ipa_attribute_groups[] = { static struct platform_driver ipa_driver = { .probe = ipa_probe, - .remove = ipa_remove, - .shutdown = ipa_shutdown, + .remove_new = ipa_remove, + .shutdown = ipa_remove, .driver = { .name = "ipa", .pm = &ipa_pm_ops, From 2ce19934a4dc1f7ca4f73041c64c816605c5d756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:42 +0100 Subject: [PATCH 2722/7721] net: fjes: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231117095922.876489-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/4889ac6a7ffa9b02fa5cdd2d3212e739741f80b8.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/fjes/fjes_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index cd8cf08477ec..5fbe33a09bb0 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1438,7 +1438,7 @@ static int fjes_probe(struct platform_device *plat_dev) } /* fjes_remove - Device Removal Routine */ -static int fjes_remove(struct platform_device *plat_dev) +static void fjes_remove(struct platform_device *plat_dev) { struct net_device *netdev = dev_get_drvdata(&plat_dev->dev); struct fjes_adapter *adapter = netdev_priv(netdev); @@ -1462,8 +1462,6 @@ static int fjes_remove(struct platform_device *plat_dev) netif_napi_del(&adapter->napi); free_netdev(netdev); - - return 0; } static struct platform_driver fjes_driver = { @@ -1471,7 +1469,7 @@ static struct platform_driver fjes_driver = { .name = DRV_NAME, }, .probe = fjes_probe, - .remove = fjes_remove, + .remove_new = fjes_remove, }; static acpi_status From e36dc85c245f2416c4404e2d4416de798c0733e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:43 +0100 Subject: [PATCH 2723/7721] net: pcs: rzn1-miic: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231117095922.876489-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/82b728e14a68c421e269eff3b8083d9d6e62d956.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-rzn1-miic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c index 97139c07130f..d93f84fbb1fd 100644 --- a/drivers/net/pcs/pcs-rzn1-miic.c +++ b/drivers/net/pcs/pcs-rzn1-miic.c @@ -505,11 +505,9 @@ static int miic_probe(struct platform_device *pdev) return ret; } -static int miic_remove(struct platform_device *pdev) +static void miic_remove(struct platform_device *pdev) { pm_runtime_put(&pdev->dev); - - return 0; } static const struct of_device_id miic_of_mtable[] = { @@ -525,7 +523,7 @@ static struct platform_driver miic_driver = { .of_match_table = miic_of_mtable, }, .probe = miic_probe, - .remove = miic_remove, + .remove_new = miic_remove, }; module_platform_driver(miic_driver); From bb1afee984663d66c3d1c062179e1684a46a6ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:44 +0100 Subject: [PATCH 2724/7721] net: sfp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231117095922.876489-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/7c1d50d559c0e0e36a20eb3e410f6e9d3f884b6f.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 5eb00295b8bf..3780a96d2caa 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -3097,7 +3097,7 @@ static int sfp_probe(struct platform_device *pdev) return 0; } -static int sfp_remove(struct platform_device *pdev) +static void sfp_remove(struct platform_device *pdev) { struct sfp *sfp = platform_get_drvdata(pdev); @@ -3107,8 +3107,6 @@ static int sfp_remove(struct platform_device *pdev) rtnl_lock(); sfp_sm_event(sfp, SFP_E_REMOVE); rtnl_unlock(); - - return 0; } static void sfp_shutdown(struct platform_device *pdev) @@ -3129,7 +3127,7 @@ static void sfp_shutdown(struct platform_device *pdev) static struct platform_driver sfp_driver = { .probe = sfp_probe, - .remove = sfp_remove, + .remove_new = sfp_remove, .shutdown = sfp_shutdown, .driver = { .name = "sfp", From 2d0c06fd39be2edb222dafa3aeb51770fca45263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:45 +0100 Subject: [PATCH 2725/7721] net: wan/fsl_ucc_hdlc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231117095922.876489-7-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/8c9ffca75ea24810f9ba05a514d5ad59847cc4fe.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/wan/fsl_ucc_hdlc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index fd50bb313b92..605e70f7baac 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -1259,7 +1259,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) return ret; } -static int ucc_hdlc_remove(struct platform_device *pdev) +static void ucc_hdlc_remove(struct platform_device *pdev) { struct ucc_hdlc_private *priv = dev_get_drvdata(&pdev->dev); @@ -1277,8 +1277,6 @@ static int ucc_hdlc_remove(struct platform_device *pdev) kfree(priv); dev_info(&pdev->dev, "UCC based hdlc module removed\n"); - - return 0; } static const struct of_device_id fsl_ucc_hdlc_of_match[] = { @@ -1292,7 +1290,7 @@ MODULE_DEVICE_TABLE(of, fsl_ucc_hdlc_of_match); static struct platform_driver ucc_hdlc_driver = { .probe = ucc_hdlc_probe, - .remove = ucc_hdlc_remove, + .remove_new = ucc_hdlc_remove, .driver = { .name = DRV_NAME, .pm = HDLC_PM_OPS, From 2d859085875333ee5e74f51e35f3f66f68da89f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:46 +0100 Subject: [PATCH 2726/7721] net: wan/ixp4xx_hss: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Link: https://lore.kernel.org/r/20231117095922.876489-8-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Acked-by: Linus Walleij Link: https://lore.kernel.org/r/b0488fa6181a47668e5737905ae7adc8d7cd055e.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/wan/ixp4xx_hss.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index b09f4c235142..931c5ca79ea5 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -1522,20 +1522,19 @@ static int ixp4xx_hss_probe(struct platform_device *pdev) return err; } -static int ixp4xx_hss_remove(struct platform_device *pdev) +static void ixp4xx_hss_remove(struct platform_device *pdev) { struct port *port = platform_get_drvdata(pdev); unregister_hdlc_device(port->netdev); free_netdev(port->netdev); npe_release(port->npe); - return 0; } static struct platform_driver ixp4xx_hss_driver = { .driver.name = DRV_NAME, .probe = ixp4xx_hss_probe, - .remove = ixp4xx_hss_remove, + .remove_new = ixp4xx_hss_remove, }; module_platform_driver(ixp4xx_hss_driver); From a06041e2f4aeb4d903e57c16812dfe72cdfc3efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Dec 2023 19:30:47 +0100 Subject: [PATCH 2727/7721] net: wwan: qcom_bam_dmux: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Sergey Ryazanov Link: https://lore.kernel.org/r/20231117095922.876489-9-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/49795ee930be6a9a24565e5e7133e6f8383ab532.1701713943.git.u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/wwan/qcom_bam_dmux.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wwan/qcom_bam_dmux.c b/drivers/net/wwan/qcom_bam_dmux.c index 17d46f4d2913..26ca719fa0de 100644 --- a/drivers/net/wwan/qcom_bam_dmux.c +++ b/drivers/net/wwan/qcom_bam_dmux.c @@ -846,7 +846,7 @@ static int bam_dmux_probe(struct platform_device *pdev) return 0; } -static int bam_dmux_remove(struct platform_device *pdev) +static void bam_dmux_remove(struct platform_device *pdev) { struct bam_dmux *dmux = platform_get_drvdata(pdev); struct device *dev = dmux->dev; @@ -877,8 +877,6 @@ static int bam_dmux_remove(struct platform_device *pdev) disable_irq(dmux->pc_irq); bam_dmux_power_off(dmux); bam_dmux_free_skbs(dmux->tx_skbs, DMA_TO_DEVICE); - - return 0; } static const struct dev_pm_ops bam_dmux_pm_ops = { @@ -893,7 +891,7 @@ MODULE_DEVICE_TABLE(of, bam_dmux_of_match); static struct platform_driver bam_dmux_driver = { .probe = bam_dmux_probe, - .remove = bam_dmux_remove, + .remove_new = bam_dmux_remove, .driver = { .name = "bam-dmux", .pm = &bam_dmux_pm_ops, From e136735f0c263b8bb9572ff8d35d8d5bc9fd9b66 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Dec 2023 13:10:05 -0800 Subject: [PATCH 2728/7721] tools: pynl: make flags argument optional for do() Commit 1768d8a767f8 ("tools/net/ynl: Add support for create flags") added support for setting legacy netlink CRUD flags on netlink messages (NLM_F_REPLACE, _EXCL, _CREATE etc.). Most of genetlink won't need these, don't force callers to pass in an empty argument to each do() call. Reviewed-by: Donald Hunter Link: https://lore.kernel.org/r/20231202211005.341613-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 92995bca14e1..c56dad9593c6 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -705,7 +705,7 @@ class YnlFamily(SpecFamily): return op['do']['request']['attributes'].copy() - def _op(self, method, vals, flags, dump=False): + def _op(self, method, vals, flags=None, dump=False): op = self.ops[method] nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK @@ -769,7 +769,7 @@ class YnlFamily(SpecFamily): return rsp[0] return rsp - def do(self, method, vals, flags): + def do(self, method, vals, flags=None): return self._op(method, vals, flags) def dump(self, method, vals): From f2d4d9ad809a1c7173ce66c47cd45e11184a554c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Dec 2023 13:13:10 -0800 Subject: [PATCH 2729/7721] tools: ynl: use strerror() if no extack of note provided If kernel didn't give use any meaningful error - print a strerror() to the ynl error message. Reviewed-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20231202211310.342716-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 830d25097009..587286de10b5 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -145,8 +145,10 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, const struct nlattr *attr; const char *str = NULL; - if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) { + yerr_msg(ys, "%s", strerror(ys->err.code)); return MNL_CB_OK; + } mnl_attr_for_each(attr, nlh, hlen) { unsigned int len, type; @@ -249,6 +251,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, yerr_msg(ys, "Kernel %s: %s%s", ys->err.code ? "error" : "warning", bad_attr, miss_attr); + else + yerr_msg(ys, "%s", strerror(ys->err.code)); return MNL_CB_OK; } From f3c928008ab218055e26917ffdbdaf429e8e616a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Dec 2023 13:12:25 -0800 Subject: [PATCH 2730/7721] tools: ynl: move private definitions to a separate header ynl.h has a growing amount of "internal" stuff, which may confuse users who try to take a look at the external API. Currently the internals are at the bottom of the file with a banner in between, but this arrangement makes it hard to add external APIs / inline helpers which need internal definitions. Move internals to a separate header. Link: https://lore.kernel.org/r/20231202211225.342466-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 144 ++++++++++++++++++++++++++++++++++ tools/net/ynl/lib/ynl.h | 148 +---------------------------------- 2 files changed, 145 insertions(+), 147 deletions(-) create mode 100644 tools/net/ynl/lib/ynl-priv.h diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h new file mode 100644 index 000000000000..7491da8e7555 --- /dev/null +++ b/tools/net/ynl/lib/ynl-priv.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +#ifndef __YNL_C_PRIV_H +#define __YNL_C_PRIV_H 1 + +#include +#include +#include + +/* + * YNL internals / low level stuff + */ + +/* Generic mnl helper code */ + +enum ynl_policy_type { + YNL_PT_REJECT = 1, + YNL_PT_IGNORE, + YNL_PT_NEST, + YNL_PT_FLAG, + YNL_PT_BINARY, + YNL_PT_U8, + YNL_PT_U16, + YNL_PT_U32, + YNL_PT_U64, + YNL_PT_UINT, + YNL_PT_NUL_STR, + YNL_PT_BITFIELD32, +}; + +struct ynl_policy_attr { + enum ynl_policy_type type; + unsigned int len; + const char *name; + struct ynl_policy_nest *nest; +}; + +struct ynl_policy_nest { + unsigned int max_attr; + struct ynl_policy_attr *table; +}; + +struct ynl_parse_arg { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *data; +}; + +struct ynl_dump_list_type { + struct ynl_dump_list_type *next; + unsigned char data[] __attribute__((aligned(8))); +}; +extern struct ynl_dump_list_type *YNL_LIST_END; + +static inline bool ynl_dump_obj_is_last(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + + uptr -= offsetof(struct ynl_dump_list_type, data); + return uptr == (unsigned long)YNL_LIST_END; +} + +static inline void *ynl_dump_obj_next(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + struct ynl_dump_list_type *list; + + uptr -= offsetof(struct ynl_dump_list_type, data); + list = (void *)uptr; + uptr = (unsigned long)list->next; + uptr += offsetof(struct ynl_dump_list_type, data); + + return (void *)uptr; +} + +struct ynl_ntf_base_type { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ynl_ntf_base_type *ntf); + unsigned char data[] __attribute__((aligned(8))); +}; + +extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; + +struct nlmsghdr * +ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); +struct nlmsghdr * +ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); + +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); + +int ynl_recv_ack(struct ynl_sock *ys, int ret); +int ynl_cb_null(const struct nlmsghdr *nlh, void *data); + +/* YNL specific helpers used by the auto-generated code */ + +struct ynl_req_state { + struct ynl_parse_arg yarg; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_dump_state { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *first; + struct ynl_dump_list_type *last; + size_t alloc_sz; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_ntf_info { + struct ynl_policy_nest *policy; + mnl_cb_t cb; + size_t alloc_sz; + void (*free)(struct ynl_ntf_base_type *ntf); +}; + +int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_req_state *yrs); +int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_dump_state *yds); + +void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); +int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); + +#ifndef MNL_HAS_AUTO_SCALARS +static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) +{ + if (mnl_attr_get_payload_len(attr) == 4) + return mnl_attr_get_u32(attr); + return mnl_attr_get_u64(attr); +} + +static inline void +mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) +{ + if ((uint32_t)data == (uint64_t)data) + return mnl_attr_put_u32(nlh, type, data); + return mnl_attr_put_u64(nlh, type, data); +} +#endif +#endif diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 075d868f3b57..5de580b992b8 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -3,20 +3,10 @@ #define __YNL_C_H 1 #include -#include #include #include -struct mnl_socket; -struct nlmsghdr; - -/* - * User facing code - */ - -struct ynl_ntf_base_type; -struct ynl_ntf_info; -struct ynl_sock; +#include "ynl-priv.h" enum ynl_error_code { YNL_ERROR_NONE = 0, @@ -116,140 +106,4 @@ static inline bool ynl_has_ntf(struct ynl_sock *ys) struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys); void ynl_ntf_free(struct ynl_ntf_base_type *ntf); - -/* - * YNL internals / low level stuff - */ - -/* Generic mnl helper code */ - -enum ynl_policy_type { - YNL_PT_REJECT = 1, - YNL_PT_IGNORE, - YNL_PT_NEST, - YNL_PT_FLAG, - YNL_PT_BINARY, - YNL_PT_U8, - YNL_PT_U16, - YNL_PT_U32, - YNL_PT_U64, - YNL_PT_UINT, - YNL_PT_NUL_STR, - YNL_PT_BITFIELD32, -}; - -struct ynl_policy_attr { - enum ynl_policy_type type; - unsigned int len; - const char *name; - struct ynl_policy_nest *nest; -}; - -struct ynl_policy_nest { - unsigned int max_attr; - struct ynl_policy_attr *table; -}; - -struct ynl_parse_arg { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *data; -}; - -struct ynl_dump_list_type { - struct ynl_dump_list_type *next; - unsigned char data[] __attribute__((aligned(8))); -}; -extern struct ynl_dump_list_type *YNL_LIST_END; - -static inline bool ynl_dump_obj_is_last(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - - uptr -= offsetof(struct ynl_dump_list_type, data); - return uptr == (unsigned long)YNL_LIST_END; -} - -static inline void *ynl_dump_obj_next(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - struct ynl_dump_list_type *list; - - uptr -= offsetof(struct ynl_dump_list_type, data); - list = (void *)uptr; - uptr = (unsigned long)list->next; - uptr += offsetof(struct ynl_dump_list_type, data); - - return (void *)uptr; -} - -struct ynl_ntf_base_type { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ynl_ntf_base_type *ntf); - unsigned char data[] __attribute__((aligned(8))); -}; - -extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; - -struct nlmsghdr * -ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); -struct nlmsghdr * -ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); - -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); - -int ynl_recv_ack(struct ynl_sock *ys, int ret); -int ynl_cb_null(const struct nlmsghdr *nlh, void *data); - -/* YNL specific helpers used by the auto-generated code */ - -struct ynl_req_state { - struct ynl_parse_arg yarg; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_dump_state { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *first; - struct ynl_dump_list_type *last; - size_t alloc_sz; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_ntf_info { - struct ynl_policy_nest *policy; - mnl_cb_t cb; - size_t alloc_sz; - void (*free)(struct ynl_ntf_base_type *ntf); -}; - -int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_req_state *yrs); -int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_dump_state *yds); - -void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); -int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); - -#ifndef MNL_HAS_AUTO_SCALARS -static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) -{ - if (mnl_attr_get_payload_len(attr) == 4) - return mnl_attr_get_u32(attr); - return mnl_attr_get_u64(attr); -} - -static inline void -mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) -{ - if ((uint32_t)data == (uint64_t)data) - return mnl_attr_put_u32(nlh, type, data); - return mnl_attr_put_u64(nlh, type, data); -} -#endif #endif From 7dd12fe34686d89c332b1a05104d18d728591f0a Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 4 Dec 2023 11:08:10 +0100 Subject: [PATCH 2731/7721] net: mvmdio: Avoid excessive sleeps in polled mode Before this change, when operating in polled mode, i.e. no IRQ is available, every individual C45 access would be hit with a 150us sleep after the bus access. For example, on a board with a CN9130 SoC connected to an MV88X3310 PHY, a single C45 read would take around 165us: root@infix:~$ mdio f212a600.mdio-mii mmd 4:1 bench 0xc003 Performed 1000 reads in 165ms By replacing the long sleep with a tighter poll loop, we observe a 10x increase in bus throughput: root@infix:~$ mdio f212a600.mdio-mii mmd 4:1 bench 0xc003 Performed 1000 reads in 15ms Signed-off-by: Tobias Waldekranz Reviewed-by: Andrew Lunn Tested-by: Andrew Lunn Link: https://lore.kernel.org/r/20231204100811.2708884-3-tobias@waldekranz.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/mvmdio.c | 51 ++++++++------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 89f26402f8fb..5f66f779e56f 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -58,11 +59,6 @@ * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled) */ #define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */ -#define MVMDIO_SMI_POLL_INTERVAL_MIN 45 -#define MVMDIO_SMI_POLL_INTERVAL_MAX 55 - -#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150 -#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160 struct orion_mdio_dev { void __iomem *regs; @@ -84,8 +80,6 @@ enum orion_mdio_bus_type { struct orion_mdio_ops { int (*is_done)(struct orion_mdio_dev *); - unsigned int poll_interval_min; - unsigned int poll_interval_max; }; /* Wait for the SMI unit to be ready for another operation @@ -94,34 +88,23 @@ static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops, struct mii_bus *bus) { struct orion_mdio_dev *dev = bus->priv; - unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT); - unsigned long end = jiffies + timeout; - int timedout = 0; + unsigned long timeout; + int done; - while (1) { - if (ops->is_done(dev)) + if (dev->err_interrupt <= 0) { + if (!read_poll_timeout_atomic(ops->is_done, done, done, 2, + MVMDIO_SMI_TIMEOUT, false, dev)) return 0; - else if (timedout) - break; + } else { + /* wait_event_timeout does not guarantee a delay of at + * least one whole jiffie, so timeout must be no less + * than two. + */ + timeout = max(usecs_to_jiffies(MVMDIO_SMI_TIMEOUT), 2); - if (dev->err_interrupt <= 0) { - usleep_range(ops->poll_interval_min, - ops->poll_interval_max); - - if (time_is_before_jiffies(end)) - ++timedout; - } else { - /* wait_event_timeout does not guarantee a delay of at - * least one whole jiffie, so timeout must be no less - * than two. - */ - if (timeout < 2) - timeout = 2; - wait_event_timeout(dev->smi_busy_wait, - ops->is_done(dev), timeout); - - ++timedout; - } + if (wait_event_timeout(dev->smi_busy_wait, + ops->is_done(dev), timeout)) + return 0; } dev_err(bus->parent, "Timeout: SMI busy for too long\n"); @@ -135,8 +118,6 @@ static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) static const struct orion_mdio_ops orion_mdio_smi_ops = { .is_done = orion_mdio_smi_is_done, - .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN, - .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX, }; static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id, @@ -194,8 +175,6 @@ static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev) static const struct orion_mdio_ops orion_mdio_xsmi_ops = { .is_done = orion_mdio_xsmi_is_done, - .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN, - .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX, }; static int orion_mdio_xsmi_read_c45(struct mii_bus *bus, int mii_id, From eb6a6605ff5a2b2ad2ceada49bba2464f6ad26a4 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 4 Dec 2023 11:08:11 +0100 Subject: [PATCH 2732/7721] net: mvmdio: Support setting the MDC frequency on XSMI controllers Support the standard "clock-frequency" attribute to set the generated MDC frequency. If not specified, the driver will leave the divisor untouched. Signed-off-by: Tobias Waldekranz Reviewed-by: Andrew Lunn Tested-by: Andrew Lunn Link: https://lore.kernel.org/r/20231204100811.2708884-4-tobias@waldekranz.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/mvmdio.c | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 5f66f779e56f..9190eff6c0bb 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -53,6 +53,13 @@ #define MVMDIO_XSMI_BUSY BIT(30) #define MVMDIO_XSMI_ADDR_REG 0x8 +#define MVMDIO_XSMI_CFG_REG 0xc +#define MVMDIO_XSMI_CLKDIV_MASK 0x3 +#define MVMDIO_XSMI_CLKDIV_256 0x0 +#define MVMDIO_XSMI_CLKDIV_64 0x1 +#define MVMDIO_XSMI_CLKDIV_32 0x2 +#define MVMDIO_XSMI_CLKDIV_8 0x3 + /* * SMI Timeout measurements: * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt) @@ -225,6 +232,40 @@ static int orion_mdio_xsmi_write_c45(struct mii_bus *bus, int mii_id, return 0; } +static void orion_mdio_xsmi_set_mdc_freq(struct mii_bus *bus) +{ + struct orion_mdio_dev *dev = bus->priv; + struct clk *mg_core; + u32 div, freq, cfg; + + if (device_property_read_u32(bus->parent, "clock-frequency", &freq)) + return; + + mg_core = of_clk_get_by_name(bus->parent->of_node, "mg_core_clk"); + if (IS_ERR(mg_core)) { + dev_err(bus->parent, + "MG core clock unknown, not changing MDC frequency"); + return; + } + + div = clk_get_rate(mg_core) / (freq + 1) + 1; + clk_put(mg_core); + + if (div <= 8) + div = MVMDIO_XSMI_CLKDIV_8; + else if (div <= 32) + div = MVMDIO_XSMI_CLKDIV_32; + else if (div <= 64) + div = MVMDIO_XSMI_CLKDIV_64; + else + div = MVMDIO_XSMI_CLKDIV_256; + + cfg = readl(dev->regs + MVMDIO_XSMI_CFG_REG); + cfg &= ~MVMDIO_XSMI_CLKDIV_MASK; + cfg |= div; + writel(cfg, dev->regs + MVMDIO_XSMI_CFG_REG); +} + static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id) { struct orion_mdio_dev *dev = dev_id; @@ -303,6 +344,9 @@ static int orion_mdio_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "unsupported number of clocks, limiting to the first " __stringify(ARRAY_SIZE(dev->clk)) "\n"); + + if (type == BUS_TYPE_XSMI) + orion_mdio_xsmi_set_mdc_freq(bus); } else { dev->clk[0] = clk_get(&pdev->dev, NULL); if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) { From 5aa00e9e41f2742223fe4ca89d94410d2477118d Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Mon, 4 Dec 2023 07:49:39 -0800 Subject: [PATCH 2733/7721] octeon_ep: control net API framework to support offloads Inquire firmware on supported offloads, as well as convey offloads enabled dynamically to firmware. New control net API functionality is required for the above. Implement control net API framework for offloads. Additionally, fetch/insert offload metadata from hardware RX/TX buffer respectively during receive/transmit. Currently supported offloads include checksum and TSO. Signed-off-by: Shinas Rasheed Link: https://lore.kernel.org/r/20231204154940.2583140-1-srasheed@marvell.com Signed-off-by: Jakub Kicinski --- .../marvell/octeon_ep/octep_cn9k_pf.c | 1 - .../ethernet/marvell/octeon_ep/octep_config.h | 33 +++++++-- .../marvell/octeon_ep/octep_ctrl_net.c | 22 +++++- .../marvell/octeon_ep/octep_ctrl_net.h | 37 ++++++++++ .../ethernet/marvell/octeon_ep/octep_main.c | 68 ++++++++++++++++-- .../ethernet/marvell/octeon_ep/octep_main.h | 3 +- .../net/ethernet/marvell/octeon_ep/octep_rx.c | 12 ++-- .../net/ethernet/marvell/octeon_ep/octep_rx.h | 34 +++++++-- .../net/ethernet/marvell/octeon_ep/octep_tx.h | 72 ++++++++++++------- 9 files changed, 231 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c index 8baabd07e91f..9209f1ec1b52 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c @@ -231,7 +231,6 @@ static void octep_init_config_cn93_pf(struct octep_device *oct) conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS; conf->iq.instr_type = OCTEP_64BYTE_INSTR; - conf->iq.pkind = 0; conf->iq.db_min = OCTEP_DB_MIN; conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h index c528344a7d0c..1627660175c2 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h @@ -60,7 +60,6 @@ #define CFG_GET_IQ_CFG(cfg) ((cfg)->iq) #define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs) #define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type) -#define CFG_GET_IQ_PKIND(cfg) ((cfg)->iq.pkind) #define CFG_GET_IQ_INSTR_SIZE(cfg) (64) #define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min) #define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold) @@ -76,7 +75,6 @@ #define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings) #define CFG_GET_PORTS_PF_SRN(cfg) ((cfg)->pf_ring_cfg.srn) -#define CFG_GET_DPI_PKIND(cfg) ((cfg)->core_cfg.dpi_pkind) #define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us) #define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us) @@ -100,9 +98,6 @@ struct octep_iq_config { /* Command size - 32 or 64 bytes */ u16 instr_type; - /* pkind for packets sent to Octeon */ - u16 pkind; - /* Minimum number of commands pending to be posted to Octeon before driver * hits the Input queue doorbell. */ @@ -198,11 +193,37 @@ struct octep_ctrl_mbox_config { /* Info from firmware */ struct octep_fw_info { /* interface pkind */ - u16 pkind; + u8 pkind; + + /* front size data */ + u8 fsz; + /* heartbeat interval in milliseconds */ u16 hb_interval; + /* heartbeat miss count */ u16 hb_miss_count; + + /* reserved */ + u16 reserved1; + + /* supported rx offloads OCTEP_ETH_RX_OFFLOAD_* */ + u16 rx_ol_flags; + + /* supported tx offloads OCTEP_ETH_TX_OFFLOAD_* */ + u16 tx_ol_flags; + + /* reserved */ + u32 reserved_offloads; + + /* extra offload flags */ + u64 ext_ol_flags; + + /* supported features */ + u64 features[2]; + + /* reserved */ + u64 reserved2[3]; }; /* Data Structure to hold configuration limits and active config */ diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c index 4c39e2fabe0a..9dff2166dbb7 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c @@ -22,12 +22,15 @@ static const u32 mtu_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mtu); static const u32 mac_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mac); static const u32 state_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_state); static const u32 link_info_sz = sizeof(struct octep_ctrl_net_link_info); +static const u32 offloads_sz = sizeof(struct octep_ctrl_net_offloads); static atomic_t ctrl_net_msg_id; /* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */ static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = { [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE] = - OCTEP_CP_VERSION(1, 0, 0) + OCTEP_CP_VERSION(1, 0, 0), + [OCTEP_CTRL_NET_H2F_CMD_OFFLOADS] = OCTEP_CP_VERSION(1, 0, 1) + }; /* Control plane version in which OCTEP_CTRL_NET_F2H_CMD was added */ @@ -405,6 +408,23 @@ int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid) return octep_send_mbox_req(oct, &d, false); } + +int octep_ctrl_net_set_offloads(struct octep_device *oct, int vfid, + struct octep_ctrl_net_offloads *offloads, + bool wait_for_response) +{ + struct octep_ctrl_net_wait_data d = {}; + struct octep_ctrl_net_h2f_req *req; + + req = &d.data.req; + init_send_req(&d.msg, req, offloads_sz, vfid); + req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_OFFLOADS; + req->offloads.cmd = OCTEP_CTRL_NET_CMD_SET; + req->offloads.offloads = *offloads; + + return octep_send_mbox_req(oct, &d, wait_for_response); +} + int octep_ctrl_net_uninit(struct octep_device *oct) { struct octep_ctrl_net_wait_data *pos, *n; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h index 0de4de2ceb8f..0b823bea9cd8 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h @@ -43,6 +43,7 @@ enum octep_ctrl_net_h2f_cmd { OCTEP_CTRL_NET_H2F_CMD_LINK_INFO, OCTEP_CTRL_NET_H2F_CMD_GET_INFO, OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE, + OCTEP_CTRL_NET_H2F_CMD_OFFLOADS, OCTEP_CTRL_NET_H2F_CMD_MAX }; @@ -113,6 +114,26 @@ struct octep_ctrl_net_h2f_req_cmd_link_info { struct octep_ctrl_net_link_info info; }; +/* offloads */ +struct octep_ctrl_net_offloads { + /* supported rx offloads OCTEP_RX_OFFLOAD_* */ + u16 rx_offloads; + /* supported tx offloads OCTEP_TX_OFFLOAD_* */ + u16 tx_offloads; + /* reserved */ + u32 reserved_offloads; + /* extra offloads */ + u64 ext_offloads; +}; + +/* get/set offloads */ +struct octep_ctrl_net_h2f_req_cmd_offloads { + /* enum octep_ctrl_net_cmd */ + u16 cmd; + /* struct octep_ctrl_net_offloads */ + struct octep_ctrl_net_offloads offloads; +}; + /* Host to fw request data */ struct octep_ctrl_net_h2f_req { union octep_ctrl_net_req_hdr hdr; @@ -122,6 +143,7 @@ struct octep_ctrl_net_h2f_req { struct octep_ctrl_net_h2f_req_cmd_state link; struct octep_ctrl_net_h2f_req_cmd_state rx; struct octep_ctrl_net_h2f_req_cmd_link_info link_info; + struct octep_ctrl_net_h2f_req_cmd_offloads offloads; }; } __packed; @@ -179,6 +201,7 @@ struct octep_ctrl_net_h2f_resp { struct octep_ctrl_net_h2f_resp_cmd_state rx; struct octep_ctrl_net_link_info link_info; struct octep_ctrl_net_h2f_resp_cmd_get_info info; + struct octep_ctrl_net_offloads offloads; }; } __packed; @@ -381,6 +404,20 @@ int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, */ int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid); +/** + * octep_ctrl_net_set_offloads() - Set offloads in firmware. + * + * @oct: non-null pointer to struct octep_device. + * @vfid: Index of virtual function. + * @offloads: non-null pointer to struct octep_ctrl_net_offloads. + * @wait_for_response: poll for response. + * + * return value: 0 on success, -errno on failure. + */ +int octep_ctrl_net_set_offloads(struct octep_device *oct, int vfid, + struct octep_ctrl_net_offloads *offloads, + bool wait_for_response); + /** * octep_ctrl_net_uninit() - Uninitialize data for ctrl net. * diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index f22fd309a78f..bbfc06581e77 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -822,6 +822,7 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct octep_device *oct = netdev_priv(netdev); + netdev_features_t feat = netdev->features; struct octep_tx_sglist_desc *sglist; struct octep_tx_buffer *tx_buffer; struct octep_tx_desc_hw *hw_desc; @@ -855,8 +856,9 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, tx_buffer->skb = skb; ih = &hw_desc->ih; - ih->tlen = skb->len; - ih->pkind = oct->pkind; + ih->pkind = oct->conf->fw_info.pkind; + ih->fsz = oct->conf->fw_info.fsz; + ih->tlen = skb->len + ih->fsz; if (!nr_frags) { tx_buffer->gather = 0; @@ -903,6 +905,19 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, hw_desc->dptr = tx_buffer->sglist_dma; } + if (oct->conf->fw_info.tx_ol_flags) { + if ((feat & (NETIF_F_TSO)) && (skb_is_gso(skb))) { + hw_desc->txm.ol_flags = OCTEP_TX_OFFLOAD_CKSUM; + hw_desc->txm.ol_flags |= OCTEP_TX_OFFLOAD_TSO; + hw_desc->txm.gso_size = skb_shinfo(skb)->gso_size; + hw_desc->txm.gso_segs = skb_shinfo(skb)->gso_segs; + } else if (feat & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { + hw_desc->txm.ol_flags = OCTEP_TX_OFFLOAD_CKSUM; + } + /* due to ESR txm will be swapped by hw */ + hw_desc->txm64[0] = (__force u64)cpu_to_be64(hw_desc->txm64[0]); + } + xmit_more = netdev_xmit_more(); __netdev_tx_sent_queue(iq->netdev_q, skb->len, xmit_more); @@ -1067,6 +1082,41 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu) return err; } +static int octep_set_features(struct net_device *dev, netdev_features_t features) +{ + struct octep_ctrl_net_offloads offloads = { 0 }; + struct octep_device *oct = netdev_priv(dev); + int err; + + /* We only support features received from firmware */ + if ((features & dev->hw_features) != features) + return -EINVAL; + + if (features & NETIF_F_TSO) + offloads.tx_offloads |= OCTEP_TX_OFFLOAD_TSO; + + if (features & NETIF_F_TSO6) + offloads.tx_offloads |= OCTEP_TX_OFFLOAD_TSO; + + if (features & NETIF_F_IP_CSUM) + offloads.tx_offloads |= OCTEP_TX_OFFLOAD_CKSUM; + + if (features & NETIF_F_IPV6_CSUM) + offloads.tx_offloads |= OCTEP_TX_OFFLOAD_CKSUM; + + if (features & NETIF_F_RXCSUM) + offloads.rx_offloads |= OCTEP_RX_OFFLOAD_CKSUM; + + err = octep_ctrl_net_set_offloads(oct, + OCTEP_CTRL_NET_INVALID_VFID, + &offloads, + true); + if (!err) + dev->features = features; + + return err; +} + static const struct net_device_ops octep_netdev_ops = { .ndo_open = octep_open, .ndo_stop = octep_stop, @@ -1075,6 +1125,7 @@ static const struct net_device_ops octep_netdev_ops = { .ndo_tx_timeout = octep_tx_timeout, .ndo_set_mac_address = octep_set_mac, .ndo_change_mtu = octep_change_mtu, + .ndo_set_features = octep_set_features, }; /** @@ -1222,7 +1273,6 @@ int octep_device_setup(struct octep_device *oct) goto unsupported_dev; } - oct->pkind = CFG_GET_IQ_PKIND(oct->conf); ret = octep_ctrl_net_init(oct); if (ret) @@ -1381,7 +1431,11 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_carrier_off(netdev); netdev->hw_features = NETIF_F_SG; - netdev->features |= netdev->hw_features; + if (OCTEP_TX_IP_CSUM(octep_dev->conf->fw_info.tx_ol_flags)) + netdev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + + if (OCTEP_RX_IP_CSUM(octep_dev->conf->fw_info.rx_ol_flags)) + netdev->hw_features |= NETIF_F_RXCSUM; max_rx_pktlen = octep_ctrl_net_get_mtu(octep_dev, OCTEP_CTRL_NET_INVALID_VFID); if (max_rx_pktlen < 0) { @@ -1394,6 +1448,12 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->max_mtu = max_rx_pktlen - (ETH_HLEN + ETH_FCS_LEN); netdev->mtu = OCTEP_DEFAULT_MTU; + if (OCTEP_TX_TSO(octep_dev->conf->fw_info.tx_ol_flags)) { + netdev->hw_features |= NETIF_F_TSO; + netif_set_tso_max_size(netdev, netdev->max_mtu); + } + + netdev->features |= netdev->hw_features; err = octep_ctrl_net_get_mac_addr(octep_dev, OCTEP_CTRL_NET_INVALID_VFID, octep_dev->mac_addr); if (err) { diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h index e1b4b2af618e..2cb93d425744 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h @@ -247,8 +247,7 @@ struct octep_device { /* Tx queues (IQ: Instruction Queue) */ u16 num_iqs; - /* pkind value to be used in every Tx hardware descriptor */ - u8 pkind; + /* Pointers to Octeon Tx queues */ struct octep_iq *iq[OCTEP_MAX_IQ]; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c index 3c43f8078528..4746a6b258f0 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c @@ -143,7 +143,7 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) * additional header is filled-in by Octeon after length field in * Rx packets. this header contains additional packet information. */ - if (oct->caps_enabled) + if (oct->conf->fw_info.rx_ol_flags) oq->max_single_buffer_size -= OCTEP_OQ_RESP_HW_EXT_SIZE; oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf); @@ -353,11 +353,13 @@ static int __octep_oq_process_rx(struct octep_device *oct, struct octep_oq *oq, u16 pkts_to_process) { struct octep_oq_resp_hw_ext *resp_hw_ext = NULL; + netdev_features_t feat = oq->netdev->features; struct octep_rx_buffer *buff_info; struct octep_oq_resp_hw *resp_hw; u32 pkt, rx_bytes, desc_used; struct sk_buff *skb; u16 data_offset; + u16 rx_ol_flags; u32 read_idx; read_idx = oq->host_read_idx; @@ -372,7 +374,7 @@ static int __octep_oq_process_rx(struct octep_device *oct, /* Swap the length field that is in Big-Endian to CPU */ buff_info->len = be64_to_cpu(resp_hw->length); - if (oct->caps_enabled & OCTEP_CAP_RX_CHECKSUM) { + if (oct->conf->fw_info.rx_ol_flags) { /* Extended response header is immediately after * response header (resp_hw) */ @@ -384,11 +386,13 @@ static int __octep_oq_process_rx(struct octep_device *oct, */ data_offset = OCTEP_OQ_RESP_HW_SIZE + OCTEP_OQ_RESP_HW_EXT_SIZE; + rx_ol_flags = resp_hw_ext->rx_ol_flags; } else { /* Data is immediately after * Hardware Rx response header. */ data_offset = OCTEP_OQ_RESP_HW_SIZE; + rx_ol_flags = 0; } rx_bytes += buff_info->len; @@ -444,8 +448,8 @@ static int __octep_oq_process_rx(struct octep_device *oct, skb->dev = oq->netdev; skb->protocol = eth_type_trans(skb, skb->dev); - if (resp_hw_ext && - resp_hw_ext->csum_verified == OCTEP_CSUM_VERIFIED) + if (feat & NETIF_F_RXCSUM && + OCTEP_RX_CSUM_VERIFIED(rx_ol_flags)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h index 49feae80d7d2..3b08e2d560dc 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h @@ -20,13 +20,33 @@ struct octep_oq_desc_hw { dma_addr_t buffer_ptr; u64 info_ptr; }; + static_assert(sizeof(struct octep_oq_desc_hw) == 16); #define OCTEP_OQ_DESC_SIZE (sizeof(struct octep_oq_desc_hw)) -#define OCTEP_CSUM_L4_VERIFIED 0x1 -#define OCTEP_CSUM_IP_VERIFIED 0x2 -#define OCTEP_CSUM_VERIFIED (OCTEP_CSUM_L4_VERIFIED | OCTEP_CSUM_IP_VERIFIED) +/* Rx offload flags */ +#define OCTEP_RX_OFFLOAD_VLAN_STRIP BIT(0) +#define OCTEP_RX_OFFLOAD_IPV4_CKSUM BIT(1) +#define OCTEP_RX_OFFLOAD_UDP_CKSUM BIT(2) +#define OCTEP_RX_OFFLOAD_TCP_CKSUM BIT(3) + +#define OCTEP_RX_OFFLOAD_CKSUM (OCTEP_RX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_RX_OFFLOAD_UDP_CKSUM | \ + OCTEP_RX_OFFLOAD_TCP_CKSUM) + +#define OCTEP_RX_IP_CSUM(flags) ((flags) & \ + (OCTEP_RX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_RX_OFFLOAD_TCP_CKSUM | \ + OCTEP_RX_OFFLOAD_UDP_CKSUM)) + +/* bit 0 is vlan strip */ +#define OCTEP_RX_CSUM_IP_VERIFIED BIT(1) +#define OCTEP_RX_CSUM_L4_VERIFIED BIT(2) + +#define OCTEP_RX_CSUM_VERIFIED(flags) ((flags) & \ + (OCTEP_RX_CSUM_L4_VERIFIED | \ + OCTEP_RX_CSUM_IP_VERIFIED)) /* Extended Response Header in packet data received from Hardware. * Includes metadata like checksum status. @@ -35,11 +55,12 @@ static_assert(sizeof(struct octep_oq_desc_hw) == 16); */ struct octep_oq_resp_hw_ext { /* Reserved. */ - u64 reserved:62; + u64 rsvd:48; - /* checksum verified. */ - u64 csum_verified:2; + /* offload flags */ + u16 rx_ol_flags; }; + static_assert(sizeof(struct octep_oq_resp_hw_ext) == 8); #define OCTEP_OQ_RESP_HW_EXT_SIZE (sizeof(struct octep_oq_resp_hw_ext)) @@ -52,6 +73,7 @@ struct octep_oq_resp_hw { /* The Length of the packet. */ __be64 length; }; + static_assert(sizeof(struct octep_oq_resp_hw) == 8); #define OCTEP_OQ_RESP_HW_SIZE (sizeof(struct octep_oq_resp_hw)) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h index 1ba4ff65e54d..059fa921069f 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h @@ -36,6 +36,7 @@ struct octep_tx_sglist_desc { u16 len[4]; dma_addr_t dma_ptr[4]; }; + static_assert(sizeof(struct octep_tx_sglist_desc) == 40); /* Each Scatter/Gather entry sent to hardwar hold four pointers. @@ -237,32 +238,53 @@ struct octep_instr_hdr { /* Reserved3 */ u64 reserved3:1; }; + static_assert(sizeof(struct octep_instr_hdr) == 8); -/* Hardware Tx completion response header */ -struct octep_instr_resp_hdr { - /* Request ID */ - u64 rid:16; +/* Tx offload flags */ +#define OCTEP_TX_OFFLOAD_VLAN_INSERT BIT(0) +#define OCTEP_TX_OFFLOAD_IPV4_CKSUM BIT(1) +#define OCTEP_TX_OFFLOAD_UDP_CKSUM BIT(2) +#define OCTEP_TX_OFFLOAD_TCP_CKSUM BIT(3) +#define OCTEP_TX_OFFLOAD_SCTP_CKSUM BIT(4) +#define OCTEP_TX_OFFLOAD_TCP_TSO BIT(5) +#define OCTEP_TX_OFFLOAD_UDP_TSO BIT(6) - /* PCIe port to use for response */ - u64 pcie_port:3; +#define OCTEP_TX_OFFLOAD_CKSUM (OCTEP_TX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_TX_OFFLOAD_UDP_CKSUM | \ + OCTEP_TX_OFFLOAD_TCP_CKSUM) - /* Scatter indicator 1=scatter */ - u64 scatter:1; +#define OCTEP_TX_OFFLOAD_TSO (OCTEP_TX_OFFLOAD_TCP_TSO | \ + OCTEP_TX_OFFLOAD_UDP_TSO) - /* Size of Expected result OR no. of entries in scatter list */ - u64 rlenssz:14; +#define OCTEP_TX_IP_CSUM(flags) ((flags) & \ + (OCTEP_TX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_TX_OFFLOAD_TCP_CKSUM | \ + OCTEP_TX_OFFLOAD_UDP_CKSUM)) - /* Desired destination port for result */ - u64 dport:6; +#define OCTEP_TX_TSO(flags) ((flags) & \ + (OCTEP_TX_OFFLOAD_TCP_TSO | \ + OCTEP_TX_OFFLOAD_UDP_TSO)) - /* Opcode Specific parameters */ - u64 param:8; +struct tx_mdata { - /* Opcode for the return packet */ - u64 opcode:16; + /* offload flags */ + u16 ol_flags; + + /* gso size */ + u16 gso_size; + + /* gso flags */ + u16 gso_segs; + + /* reserved */ + u16 rsvd1; + + /* reserved */ + u64 rsvd2; }; -static_assert(sizeof(struct octep_instr_hdr) == 8); + +static_assert(sizeof(struct tx_mdata) == 16); /* 64-byte Tx instruction format. * Format of instruction for a 64-byte mode input queue. @@ -281,18 +303,14 @@ struct octep_tx_desc_hw { struct octep_instr_hdr ih; u64 ih64; }; - - /* Pointer where the response for a RAW mode packet will be written - * by Octeon. - */ - u64 rptr; - - /* Input Instruction Response Header. */ - struct octep_instr_resp_hdr irh; - + union { + u64 txm64[2]; + struct tx_mdata txm; + }; /* Additional headers available in a 64-byte instruction. */ - u64 exhdr[4]; + u64 exthdr[4]; }; + static_assert(sizeof(struct octep_tx_desc_hw) == 64); #define OCTEP_IQ_DESC_SIZE (sizeof(struct octep_tx_desc_hw)) From 43a71cd66b9c0a4af3d15d8644359fde35bdbed0 Mon Sep 17 00:00:00 2001 From: Coco Li Date: Mon, 4 Dec 2023 20:12:30 +0000 Subject: [PATCH 2734/7721] net-device: reorganize net_device fast path variables Reorganize fast path variables on tx-txrx-rx order Fastpath variables end after npinfo. Below data generated with pahole on x86 architecture. Fast path variables span cache lines before change: 12 Fast path variables span cache lines after change: 4 Suggested-by: Eric Dumazet Signed-off-by: Coco Li Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231204201232.520025-2-lixiaoyan@google.com Signed-off-by: Jakub Kicinski --- include/linux/netdevice.h | 117 +++++++++++++++++++++----------------- net/core/dev.c | 56 ++++++++++++++++++ 2 files changed, 120 insertions(+), 53 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5551177e024e..cb96aad6a6ee 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2097,6 +2097,70 @@ enum netdev_stat_type { */ struct net_device { + /* Cacheline organization can be found documented in + * Documentation/networking/net_cachelines/net_device.rst. + * Please update the document when adding new fields. + */ + + /* TX read-mostly hotpath */ + __cacheline_group_begin(net_device_read_tx); + unsigned long long priv_flags; + const struct net_device_ops *netdev_ops; + const struct header_ops *header_ops; + struct netdev_queue *_tx; + unsigned int real_num_tx_queues; + unsigned int gso_max_size; + unsigned int gso_ipv4_max_size; + u16 gso_max_segs; + s16 num_tc; + /* Note : dev->mtu is often read without holding a lock. + * Writers usually hold RTNL. + * It is recommended to use READ_ONCE() to annotate the reads, + * and to use WRITE_ONCE() to annotate the writes. + */ + unsigned int mtu; + unsigned short needed_headroom; + struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; +#ifdef CONFIG_XPS + struct xps_dev_maps __rcu *xps_maps[XPS_MAPS_MAX]; +#endif +#ifdef CONFIG_NETFILTER_EGRESS + struct nf_hook_entries __rcu *nf_hooks_egress; +#endif +#ifdef CONFIG_NET_XGRESS + struct bpf_mprog_entry __rcu *tcx_egress; +#endif + __cacheline_group_end(net_device_read_tx); + + /* TXRX read-mostly hotpath */ + __cacheline_group_begin(net_device_read_txrx); + unsigned int flags; + unsigned short hard_header_len; + netdev_features_t features; + struct inet6_dev __rcu *ip6_ptr; + __cacheline_group_end(net_device_read_txrx); + + /* RX read-mostly hotpath */ + __cacheline_group_begin(net_device_read_rx); + struct list_head ptype_specific; + int ifindex; + unsigned int real_num_rx_queues; + struct netdev_rx_queue *_rx; + unsigned long gro_flush_timeout; + int napi_defer_hard_irqs; + unsigned int gro_max_size; + unsigned int gro_ipv4_max_size; + rx_handler_func_t __rcu *rx_handler; + void __rcu *rx_handler_data; + possible_net_t nd_net; +#ifdef CONFIG_NETPOLL + struct netpoll_info __rcu *npinfo; +#endif +#ifdef CONFIG_NET_XGRESS + struct bpf_mprog_entry __rcu *tcx_ingress; +#endif + __cacheline_group_end(net_device_read_rx); + char name[IFNAMSIZ]; struct netdev_name_node *name_node; struct dev_ifalias __rcu *ifalias; @@ -2121,7 +2185,6 @@ struct net_device { struct list_head unreg_list; struct list_head close_list; struct list_head ptype_all; - struct list_head ptype_specific; struct { struct list_head upper; @@ -2129,26 +2192,13 @@ struct net_device { } adj_list; /* Read-mostly cache-line for fast-path access */ - unsigned int flags; xdp_features_t xdp_features; - unsigned long long priv_flags; - const struct net_device_ops *netdev_ops; const struct xdp_metadata_ops *xdp_metadata_ops; const struct xsk_tx_metadata_ops *xsk_tx_metadata_ops; - int ifindex; unsigned short gflags; - unsigned short hard_header_len; - /* Note : dev->mtu is often read without holding a lock. - * Writers usually hold RTNL. - * It is recommended to use READ_ONCE() to annotate the reads, - * and to use WRITE_ONCE() to annotate the writes. - */ - unsigned int mtu; - unsigned short needed_headroom; unsigned short needed_tailroom; - netdev_features_t features; netdev_features_t hw_features; netdev_features_t wanted_features; netdev_features_t vlan_features; @@ -2192,8 +2242,6 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif - const struct header_ops *header_ops; - unsigned char operstate; unsigned char link_mode; @@ -2234,9 +2282,7 @@ struct net_device { /* Protocol-specific pointers */ - struct in_device __rcu *ip_ptr; - struct inet6_dev __rcu *ip6_ptr; #if IS_ENABLED(CONFIG_VLAN_8021Q) struct vlan_info __rcu *vlan_info; #endif @@ -2271,26 +2317,14 @@ struct net_device { /* Interface address info used in eth_type_trans() */ const unsigned char *dev_addr; - struct netdev_rx_queue *_rx; unsigned int num_rx_queues; - unsigned int real_num_rx_queues; - struct bpf_prog __rcu *xdp_prog; - unsigned long gro_flush_timeout; - int napi_defer_hard_irqs; #define GRO_LEGACY_MAX_SIZE 65536u /* TCP minimal MSS is 8 (TCP_MIN_GSO_SIZE), * and shinfo->gso_segs is a 16bit field. */ #define GRO_MAX_SIZE (8 * 65535u) - unsigned int gro_max_size; - unsigned int gro_ipv4_max_size; unsigned int xdp_zc_max_segs; - rx_handler_func_t __rcu *rx_handler; - void __rcu *rx_handler_data; -#ifdef CONFIG_NET_XGRESS - struct bpf_mprog_entry __rcu *tcx_ingress; -#endif struct netdev_queue __rcu *ingress_queue; #ifdef CONFIG_NETFILTER_INGRESS struct nf_hook_entries __rcu *nf_hooks_ingress; @@ -2305,25 +2339,13 @@ struct net_device { /* * Cache lines mostly used on transmit path */ - struct netdev_queue *_tx ____cacheline_aligned_in_smp; unsigned int num_tx_queues; - unsigned int real_num_tx_queues; struct Qdisc __rcu *qdisc; unsigned int tx_queue_len; spinlock_t tx_global_lock; struct xdp_dev_bulk_queue __percpu *xdp_bulkq; -#ifdef CONFIG_XPS - struct xps_dev_maps __rcu *xps_maps[XPS_MAPS_MAX]; -#endif -#ifdef CONFIG_NET_XGRESS - struct bpf_mprog_entry __rcu *tcx_egress; -#endif -#ifdef CONFIG_NETFILTER_EGRESS - struct nf_hook_entries __rcu *nf_hooks_egress; -#endif - #ifdef CONFIG_NET_SCHED DECLARE_HASHTABLE (qdisc_hash, 4); #endif @@ -2362,12 +2384,6 @@ struct net_device { bool needs_free_netdev; void (*priv_destructor)(struct net_device *dev); -#ifdef CONFIG_NETPOLL - struct netpoll_info __rcu *npinfo; -#endif - - possible_net_t nd_net; - /* mid-layer private */ void *ml_priv; enum netdev_ml_priv_type ml_priv_type; @@ -2402,20 +2418,15 @@ struct net_device { */ #define GSO_MAX_SIZE (8 * GSO_MAX_SEGS) - unsigned int gso_max_size; #define TSO_LEGACY_MAX_SIZE 65536 #define TSO_MAX_SIZE UINT_MAX unsigned int tso_max_size; - u16 gso_max_segs; #define TSO_MAX_SEGS U16_MAX u16 tso_max_segs; - unsigned int gso_ipv4_max_size; #ifdef CONFIG_DCB const struct dcbnl_rtnl_ops *dcbnl_ops; #endif - s16 num_tc; - struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; u8 prio_tc_map[TC_BITMASK + 1]; #if IS_ENABLED(CONFIG_FCOE) diff --git a/net/core/dev.c b/net/core/dev.c index 1d720fc59161..c5679dfbaa70 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11609,6 +11609,60 @@ static struct pernet_operations __net_initdata default_device_ops = { .exit_batch = default_device_exit_batch, }; +static void __init net_dev_struct_check(void) +{ + /* TX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, priv_flags); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, netdev_ops); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, header_ops); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, _tx); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, real_num_tx_queues); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_max_size); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_ipv4_max_size); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_max_segs); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, num_tc); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, mtu); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, needed_headroom); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, tc_to_txq); +#ifdef CONFIG_XPS + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, xps_maps); +#endif +#ifdef CONFIG_NETFILTER_EGRESS + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, nf_hooks_egress); +#endif +#ifdef CONFIG_NET_XGRESS + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, tcx_egress); +#endif + CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_tx, 152); + + /* TXRX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr); + CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 30); + + /* RX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ifindex); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, real_num_rx_queues); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, _rx); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_flush_timeout); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, napi_defer_hard_irqs); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_max_size); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_ipv4_max_size); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, rx_handler); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, rx_handler_data); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, nd_net); +#ifdef CONFIG_NETPOLL + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, npinfo); +#endif +#ifdef CONFIG_NET_XGRESS + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, tcx_ingress); +#endif + CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_rx, 96); +} + /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not @@ -11626,6 +11680,8 @@ static int __init net_dev_init(void) BUG_ON(!dev_boot_phase); + net_dev_struct_check(); + if (dev_proc_init()) goto out; From d5fed5addb2b6bc13035de4338b7ea2052a2e006 Mon Sep 17 00:00:00 2001 From: Coco Li Date: Mon, 4 Dec 2023 20:12:31 +0000 Subject: [PATCH 2735/7721] tcp: reorganize tcp_sock fast path variables The variables are organized according in the following way: - TX read-mostly hotpath cache lines - TXRX read-mostly hotpath cache lines - RX read-mostly hotpath cache lines - TX read-write hotpath cache line - TXRX read-write hotpath cache line - RX read-write hotpath cache line Fastpath cachelines end after rcvq_space. Cache line boundaries are enforced only between read-mostly and read-write. That is, if read-mostly tx cachelines bleed into read-mostly txrx cachelines, we do not care. We care about the boundaries between read and write cachelines because we want to prevent false sharing. Fast path variables span cache lines before change: 12 Fast path variables span cache lines after change: 8 Suggested-by: Eric Dumazet Reviewed-by: Wei Wang Signed-off-by: Coco Li Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231204201232.520025-3-lixiaoyan@google.com Signed-off-by: Jakub Kicinski --- include/linux/tcp.h | 262 ++++++++++++++++++++++++-------------------- net/ipv4/tcp.c | 93 ++++++++++++++++ 2 files changed, 234 insertions(+), 121 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 68f3d315d2e1..f55ec155f5b7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -194,36 +194,62 @@ static inline bool tcp_rsk_used_ao(const struct request_sock *req) #define TCP_RMEM_TO_WIN_SCALE 8 struct tcp_sock { + /* Cacheline organization can be found documented in + * Documentation/networking/net_cachelines/tcp_sock.rst. + * Please update the document when adding new fields. + */ + /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; - u16 tcp_header_len; /* Bytes of tcp header to send */ + + /* TX read-mostly hotpath cache lines */ + __cacheline_group_begin(tcp_sock_read_tx); + /* timestamp of last sent data packet (for restart window) */ + u32 max_window; /* Maximal window ever seen from peer */ + u32 rcv_ssthresh; /* Current window clamp */ + u32 reordering; /* Packet reordering metric. */ + u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */ u16 gso_segs; /* Max number of segs per GSO packet */ + /* from STCP, retrans queue hinting */ + struct sk_buff *lost_skb_hint; + struct sk_buff *retransmit_skb_hint; + __cacheline_group_end(tcp_sock_read_tx); -/* - * Header prediction flags - * 0x5?10 << 16 + snd_wnd in net byte order - */ - __be32 pred_flags; + /* TXRX read-mostly hotpath cache lines */ + __cacheline_group_begin(tcp_sock_read_txrx); + u32 tsoffset; /* timestamp offset */ + u32 snd_wnd; /* The window we expect to receive */ + u32 mss_cache; /* Cached effective mss, not including SACKS */ + u32 snd_cwnd; /* Sending congestion window */ + u32 prr_out; /* Total number of pkts sent during Recovery. */ + u32 lost_out; /* Lost packets */ + u32 sacked_out; /* SACK'd packets */ + u16 tcp_header_len; /* Bytes of tcp header to send */ + u8 chrono_type : 2, /* current chronograph type */ + repair : 1, + is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ + is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ + __cacheline_group_end(tcp_sock_read_txrx); -/* - * RFC793 variables by their proper names. This means you can - * read the code and the spec side by side (and laugh ...) - * See RFC793 and RFC1122. The RFC writes these in capitals. - */ - u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived - * sum(delta(rcv_nxt)), or how many bytes - * were acked. - */ - u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn - * total number of segments in. - */ - u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn - * total number of data segments in. - */ - u32 rcv_nxt; /* What we want to receive next */ - u32 copied_seq; /* Head of yet unread data */ - u32 rcv_wup; /* rcv_nxt on last window update sent */ - u32 snd_nxt; /* Next sequence we send */ + /* RX read-mostly hotpath cache lines */ + __cacheline_group_begin(tcp_sock_read_rx); + u32 copied_seq; /* Head of yet unread data */ + u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ + u32 snd_wl1; /* Sequence for window update */ + u32 tlp_high_seq; /* snd_nxt at the time of TLP */ + u32 rttvar_us; /* smoothed mdev_max */ + u32 retrans_out; /* Retransmitted packets out */ + u16 advmss; /* Advertised MSS */ + u16 urg_data; /* Saved octet of OOB data and control flags */ + u32 lost; /* Total data packets lost incl. rexmits */ + struct minmax rtt_min; + /* OOO segments go in this rbtree. Socket lock must be held. */ + struct rb_root out_of_order_queue; + u32 snd_ssthresh; /* Slow start size threshold */ + __cacheline_group_end(tcp_sock_read_rx); + + /* TX read-write hotpath cache lines */ + __cacheline_group_begin(tcp_sock_write_tx) ____cacheline_aligned; u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut * The total number of segments sent. */ @@ -233,32 +259,103 @@ struct tcp_sock { u64 bytes_sent; /* RFC4898 tcpEStatsPerfHCDataOctetsOut * total number of data bytes sent. */ + u32 snd_sml; /* Last byte of the most recently transmitted small packet */ + u32 chrono_start; /* Start time in jiffies of a TCP chrono */ + u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ + u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ + u32 pushed_seq; /* Last pushed seq, required to talk to windows */ + u32 lsndtime; + u32 mdev_us; /* medium deviation */ + u64 tcp_wstamp_ns; /* departure time for next sent data packet */ + u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ + u64 tcp_mstamp; /* most recent packet received/sent */ + u32 rtt_seq; /* sequence number to update rttvar */ + struct list_head tsorted_sent_queue; /* time-sorted sent but un-SACKed skbs */ + struct sk_buff *highest_sack; /* skb just after the highest + * skb with SACKed bit set + * (validity guaranteed only if + * sacked_out > 0) + */ + u8 ecn_flags; /* ECN status bits. */ + __cacheline_group_end(tcp_sock_write_tx); + + /* TXRX read-write hotpath cache lines */ + __cacheline_group_begin(tcp_sock_write_txrx); +/* + * Header prediction flags + * 0x5?10 << 16 + snd_wnd in net byte order + */ + __be32 pred_flags; + u32 rcv_nxt; /* What we want to receive next */ + u32 snd_nxt; /* Next sequence we send */ + u32 snd_una; /* First byte we want an ack for */ + u32 window_clamp; /* Maximal window to advertise */ + u32 srtt_us; /* smoothed round trip time << 3 in usecs */ + u32 packets_out; /* Packets which are "in flight" */ + u32 snd_up; /* Urgent pointer */ + u32 delivered; /* Total data packets delivered incl. rexmits */ + u32 delivered_ce; /* Like the above but only ECE marked packets */ + u32 app_limited; /* limited until "delivered" reaches this val */ + u32 rcv_wnd; /* Current receiver window */ +/* + * Options received (usually on last packet, some only on SYN packets). + */ + struct tcp_options_received rx_opt; + u8 nonagle : 4,/* Disable Nagle algorithm? */ + rate_app_limited:1; /* rate_{delivered,interval_us} limited? */ + __cacheline_group_end(tcp_sock_write_txrx); + + /* RX read-write hotpath cache lines */ + __cacheline_group_begin(tcp_sock_write_rx); + u64 bytes_received; + /* RFC4898 tcpEStatsAppHCThruOctetsReceived + * sum(delta(rcv_nxt)), or how many bytes + * were acked. + */ + u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn + * total number of segments in. + */ + u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn + * total number of data segments in. + */ + u32 rcv_wup; /* rcv_nxt on last window update sent */ + u32 max_packets_out; /* max packets_out in last window */ + u32 cwnd_usage_seq; /* right edge of cwnd usage tracking flight */ + u32 rate_delivered; /* saved rate sample: packets delivered */ + u32 rate_interval_us; /* saved rate sample: time elapsed */ + u32 rcv_rtt_last_tsecr; + u64 first_tx_mstamp; /* start of window send phase */ + u64 delivered_mstamp; /* time we reached "delivered" */ u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked * sum(delta(snd_una)), or how many bytes * were acked. */ + struct { + u32 rtt_us; + u32 seq; + u64 time; + } rcv_rtt_est; +/* Receiver queue space */ + struct { + u32 space; + u32 seq; + u64 time; + } rcvq_space; + __cacheline_group_end(tcp_sock_write_rx); + /* End of Hot Path */ + +/* + * RFC793 variables by their proper names. This means you can + * read the code and the spec side by side (and laugh ...) + * See RFC793 and RFC1122. The RFC writes these in capitals. + */ u32 dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups * total number of DSACK blocks received */ - u32 snd_una; /* First byte we want an ack for */ - u32 snd_sml; /* Last byte of the most recently transmitted small packet */ - u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ - u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */ u32 compressed_ack_rcv_nxt; - - u32 tsoffset; /* timestamp offset */ - struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ - struct list_head tsorted_sent_queue; /* time-sorted sent but un-SACKed skbs */ - u32 snd_wl1; /* Sequence for window update */ - u32 snd_wnd; /* The window we expect to receive */ - u32 max_window; /* Maximal window ever seen from peer */ - u32 mss_cache; /* Cached effective mss, not including SACKS */ - - u32 window_clamp; /* Maximal window to advertise */ - u32 rcv_ssthresh; /* Current window clamp */ u8 scaling_ratio; /* see tcp_win_from_space() */ /* Information of the most recently (s)acked skb */ struct tcp_rack { @@ -272,24 +369,16 @@ struct tcp_sock { dsack_seen:1, /* Whether DSACK seen after last adj */ advanced:1; /* mstamp advanced since last lost marking */ } rack; - u16 advmss; /* Advertised MSS */ u8 compressed_ack; u8 dup_ack_counter:2, tlp_retrans:1, /* TLP is a retransmission */ tcp_usec_ts:1, /* TSval values in usec */ unused:4; - u32 chrono_start; /* Start time in jiffies of a TCP chrono */ - u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ - u8 chrono_type:2, /* current chronograph type */ - rate_app_limited:1, /* rate_{delivered,interval_us} limited? */ + u8 thin_lto : 1,/* Use linear timeouts for thin streams */ + recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ - is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ - fastopen_client_fail:2; /* reason why fastopen failed */ - u8 nonagle : 4,/* Disable Nagle algorithm? */ - thin_lto : 1,/* Use linear timeouts for thin streams */ - recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ - repair : 1, + fastopen_client_fail:2, /* reason why fastopen failed */ frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */ u8 repair_queue; u8 save_syn:2, /* Save headers of SYN packet */ @@ -297,45 +386,19 @@ struct tcp_sock { syn_fastopen:1, /* SYN includes Fast Open option */ syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ syn_fastopen_ch:1, /* Active TFO re-enabling probe */ - syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ - is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ - u32 tlp_high_seq; /* snd_nxt at the time of TLP */ + syn_data_acked:1;/* data in SYN is acked by SYN-ACK */ u32 tcp_tx_delay; /* delay (in usec) added to TX packets */ - u64 tcp_wstamp_ns; /* departure time for next sent data packet */ - u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ /* RTT measurement */ - u64 tcp_mstamp; /* most recent packet received/sent */ - u32 srtt_us; /* smoothed round trip time << 3 in usecs */ - u32 mdev_us; /* medium deviation */ u32 mdev_max_us; /* maximal mdev for the last rtt period */ - u32 rttvar_us; /* smoothed mdev_max */ - u32 rtt_seq; /* sequence number to update rttvar */ - struct minmax rtt_min; - u32 packets_out; /* Packets which are "in flight" */ - u32 retrans_out; /* Retransmitted packets out */ - u32 max_packets_out; /* max packets_out in last window */ - u32 cwnd_usage_seq; /* right edge of cwnd usage tracking flight */ - - u16 urg_data; /* Saved octet of OOB data and control flags */ - u8 ecn_flags; /* ECN status bits. */ u8 keepalive_probes; /* num of allowed keep alive probes */ - u32 reordering; /* Packet reordering metric. */ u32 reord_seen; /* number of data packet reordering events */ - u32 snd_up; /* Urgent pointer */ - -/* - * Options received (usually on last packet, some only on SYN packets). - */ - struct tcp_options_received rx_opt; /* * Slow start and congestion control (see also Nagle, and Karn & Partridge) */ - u32 snd_ssthresh; /* Slow start size threshold */ - u32 snd_cwnd; /* Sending congestion window */ u32 snd_cwnd_cnt; /* Linear increase counter */ u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ u32 snd_cwnd_used; @@ -343,32 +406,10 @@ struct tcp_sock { u32 prior_cwnd; /* cwnd right before starting loss recovery */ u32 prr_delivered; /* Number of newly delivered packets to * receiver in Recovery. */ - u32 prr_out; /* Total number of pkts sent during Recovery. */ - u32 delivered; /* Total data packets delivered incl. rexmits */ - u32 delivered_ce; /* Like the above but only ECE marked packets */ - u32 lost; /* Total data packets lost incl. rexmits */ - u32 app_limited; /* limited until "delivered" reaches this val */ - u64 first_tx_mstamp; /* start of window send phase */ - u64 delivered_mstamp; /* time we reached "delivered" */ - u32 rate_delivered; /* saved rate sample: packets delivered */ - u32 rate_interval_us; /* saved rate sample: time elapsed */ - - u32 rcv_wnd; /* Current receiver window */ - u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ - u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */ - u32 pushed_seq; /* Last pushed seq, required to talk to windows */ - u32 lost_out; /* Lost packets */ - u32 sacked_out; /* SACK'd packets */ struct hrtimer pacing_timer; struct hrtimer compressed_ack_timer; - /* from STCP, retrans queue hinting */ - struct sk_buff* lost_skb_hint; - struct sk_buff *retransmit_skb_hint; - - /* OOO segments go in this rbtree. Socket lock must be held. */ - struct rb_root out_of_order_queue; struct sk_buff *ooo_last_skb; /* cache rb_last(out_of_order_queue) */ /* SACKs data, these 2 need to be together (see tcp_options_write) */ @@ -377,12 +418,6 @@ struct tcp_sock { struct tcp_sack_block recv_sack_cache[4]; - struct sk_buff *highest_sack; /* skb just after the highest - * skb with SACKed bit set - * (validity guaranteed only if - * sacked_out > 0) - */ - int lost_cnt_hint; u32 prior_ssthresh; /* ssthresh saved at recovery start */ @@ -433,21 +468,6 @@ struct tcp_sock { u32 rcv_ooopack; /* Received out-of-order packets, for tcpinfo */ -/* Receiver side RTT estimation */ - u32 rcv_rtt_last_tsecr; - struct { - u32 rtt_us; - u32 seq; - u64 time; - } rcv_rtt_est; - -/* Receiver queue space */ - struct { - u32 space; - u32 seq; - u64 time; - } rcvq_space; - /* TCP-specific MTU probe information. */ struct { u32 probe_seq_start; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index a100df07d34a..70a1bafbefba 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4564,6 +4564,97 @@ static void __init tcp_init_mem(void) sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2; /* 9.37 % */ } +static void __init tcp_struct_check(void) +{ + /* TX read-mostly hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, max_window); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, rcv_ssthresh); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, reordering); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, notsent_lowat); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, gso_segs); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, lost_skb_hint); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, retransmit_skb_hint); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_tx, 40); + + /* TXRX read-mostly hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, tsoffset); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, snd_wnd); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, mss_cache); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, snd_cwnd); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, prr_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, lost_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, sacked_out); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 31); + + /* RX read-mostly hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, copied_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rcv_tstamp); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, snd_wl1); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, tlp_high_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rttvar_us); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, retrans_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, advmss); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, urg_data); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, lost); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rtt_min); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, out_of_order_queue); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, snd_ssthresh); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_rx, 69); + + /* TX read-write hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, segs_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, data_segs_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, bytes_sent); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, snd_sml); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, chrono_start); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, chrono_stat); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, write_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, pushed_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, lsndtime); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, mdev_us); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_wstamp_ns); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_clock_cache); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_mstamp); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, rtt_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tsorted_sent_queue); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, highest_sack); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, ecn_flags); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_tx, 113); + + /* TXRX read-write hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, pred_flags); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rcv_nxt); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_nxt); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_una); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, window_clamp); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, srtt_us); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, packets_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_up); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, delivered); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, delivered_ce); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, app_limited); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rcv_wnd); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rx_opt); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_txrx, 76); + + /* RX read-write hotpath cache lines */ + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_received); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, segs_in); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, data_segs_in); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_wup); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, max_packets_out); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, cwnd_usage_seq); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rate_delivered); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rate_interval_us); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_rtt_last_tsecr); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, first_tx_mstamp); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, delivered_mstamp); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_acked); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_rtt_est); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcvq_space); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_rx, 99); +} + void __init tcp_init(void) { int max_rshare, max_wshare, cnt; @@ -4574,6 +4665,8 @@ void __init tcp_init(void) BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof_field(struct sk_buff, cb)); + tcp_struct_check(); + percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL); timer_setup(&tcp_orphan_timer, tcp_orphan_update, TIMER_DEFERRABLE); From facd15dfd69122042502d99ab8c9f888b48ee994 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Dec 2023 21:47:07 +0100 Subject: [PATCH 2736/7721] net: core: synchronize link-watch when carrier is queried There are multiple ways to query for the carrier state: through rtnetlink, sysfs, and (possibly) ethtool. Synchronize linkwatch work before these operations so that we don't have a situation where userspace queries the carrier state between the driver's carrier off->on transition and linkwatch running and expects it to work, when really (at least) TX cannot work until linkwatch has run. I previously posted a longer explanation of how this applies to wireless [1] but with this wireless can simply query the state before sending data, to ensure the kernel is ready for it. [1] https://lore.kernel.org/all/346b21d87c69f817ea3c37caceb34f1f56255884.camel@sipsolutions.net/ Signed-off-by: Johannes Berg Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20231204214706.303c62768415.I1caedccae72ee5a45c9085c5eb49c145ce1c0dd5@changeid Signed-off-by: Jakub Kicinski --- include/linux/netdevice.h | 9 +++++++++ net/core/dev.c | 2 +- net/core/dev.h | 1 - net/core/link_watch.c | 2 +- net/core/net-sysfs.c | 8 +++++++- net/core/rtnetlink.c | 8 ++++++++ net/ethtool/ioctl.c | 3 +++ 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cb96aad6a6ee..1b935ee341b4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4229,6 +4229,15 @@ static inline void netdev_ref_replace(struct net_device *odev, */ void linkwatch_fire_event(struct net_device *dev); +/** + * linkwatch_sync_dev - sync linkwatch for the given device + * @dev: network device to sync linkwatch for + * + * Sync linkwatch for the given device, removing it from the + * pending work list (if queued). + */ +void linkwatch_sync_dev(struct net_device *dev); + /** * netif_carrier_ok - test if carrier present * @dev: network device diff --git a/net/core/dev.c b/net/core/dev.c index c5679dfbaa70..0432b04cf9b0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10548,7 +10548,7 @@ void netdev_run_todo(void) write_lock(&dev_base_lock); dev->reg_state = NETREG_UNREGISTERED; write_unlock(&dev_base_lock); - linkwatch_forget_dev(dev); + linkwatch_sync_dev(dev); } while (!list_empty(&list)) { diff --git a/net/core/dev.h b/net/core/dev.h index 7795b8ad841d..cf93e188785b 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -30,7 +30,6 @@ int __init dev_proc_init(void); #endif void linkwatch_init_dev(struct net_device *dev); -void linkwatch_forget_dev(struct net_device *dev); void linkwatch_run_queue(void); void dev_addr_flush(struct net_device *dev); diff --git a/net/core/link_watch.c b/net/core/link_watch.c index c469d1c4db5d..a19f21403339 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -245,7 +245,7 @@ static void __linkwatch_run_queue(int urgent_only) spin_unlock_irq(&lweventlist_lock); } -void linkwatch_forget_dev(struct net_device *dev) +void linkwatch_sync_dev(struct net_device *dev) { unsigned long flags; int clean = 0; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index fccaa5bac0ed..d9b33e923b18 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -194,8 +194,14 @@ static ssize_t carrier_show(struct device *dev, { struct net_device *netdev = to_net_dev(dev); - if (netif_running(netdev)) + if (netif_running(netdev)) { + /* Synchronize carrier state with link watch, + * see also rtnl_getlink(). + */ + linkwatch_sync_dev(netdev); + return sysfs_emit(buf, fmt_dec, !!netif_carrier_ok(netdev)); + } return -EINVAL; } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 592164c2a540..5e0ab4c08f72 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3853,6 +3853,14 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, if (nskb == NULL) goto out; + /* Synchronize the carrier state so we don't report a state + * that we're not actually going to honour immediately; if + * the driver just did a carrier off->on transition, we can + * only TX if link watch work has run, but without this we'd + * already report carrier on, even if it doesn't work yet. + */ + linkwatch_sync_dev(dev); + err = rtnl_fill_ifinfo(nskb, dev, net, RTM_NEWLINK, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, 0, ext_filter_mask, diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 0b0ce4f81c01..a977f8903467 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -58,6 +58,9 @@ static struct devlink *netdev_to_devlink_get(struct net_device *dev) u32 ethtool_op_get_link(struct net_device *dev) { + /* Synchronize carrier state with link watch, see also rtnl_getlink() */ + linkwatch_sync_dev(dev); + return netif_carrier_ok(dev) ? 1 : 0; } EXPORT_SYMBOL(ethtool_op_get_link); From 19b707c3f23a7923ab40732521123d9b59965cc4 Mon Sep 17 00:00:00 2001 From: Coco Li Date: Mon, 4 Dec 2023 22:07:28 +0000 Subject: [PATCH 2737/7721] Documentations: fix net_cachelines documentation build warning Original errors: Documentation/networking/net_cachelines/index.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/inet_connection_sock.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/inet_sock.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/net_device.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/snmp.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Documentation/networking/net_cachelines/tcp_sock.rst:3: WARNING: Explicit markup ends without a blank line; unexpected unindent. Fixes: 14006f1d8fa2 ("Documentations: Analyze heavily used Networking related structs") Signed-off-by: Coco Li Link: https://lore.kernel.org/r/20231204220728.746134-1-lixiaoyan@google.com Signed-off-by: Jakub Kicinski --- Documentation/networking/net_cachelines/index.rst | 1 + Documentation/networking/net_cachelines/inet_connection_sock.rst | 1 + Documentation/networking/net_cachelines/inet_sock.rst | 1 + Documentation/networking/net_cachelines/net_device.rst | 1 + Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst | 1 + Documentation/networking/net_cachelines/snmp.rst | 1 + Documentation/networking/net_cachelines/tcp_sock.rst | 1 + 7 files changed, 7 insertions(+) diff --git a/Documentation/networking/net_cachelines/index.rst b/Documentation/networking/net_cachelines/index.rst index 6f1a99989bbd..2669e4cda086 100644 --- a/Documentation/networking/net_cachelines/index.rst +++ b/Documentation/networking/net_cachelines/index.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + =================================== Common Networking Struct Cachelines =================================== diff --git a/Documentation/networking/net_cachelines/inet_connection_sock.rst b/Documentation/networking/net_cachelines/inet_connection_sock.rst index ad2b200147a6..7a911dc95652 100644 --- a/Documentation/networking/net_cachelines/inet_connection_sock.rst +++ b/Documentation/networking/net_cachelines/inet_connection_sock.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + ===================================================== inet_connection_sock struct fast path usage breakdown ===================================================== diff --git a/Documentation/networking/net_cachelines/inet_sock.rst b/Documentation/networking/net_cachelines/inet_sock.rst index 4077febdb995..a2babd0d7954 100644 --- a/Documentation/networking/net_cachelines/inet_sock.rst +++ b/Documentation/networking/net_cachelines/inet_sock.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + ===================================================== inet_connection_sock struct fast path usage breakdown ===================================================== diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst index 98508aa4f800..6cab1b797739 100644 --- a/Documentation/networking/net_cachelines/net_device.rst +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + =========================================== net_device struct fast path usage breakdown =========================================== diff --git a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst index 47e1a0105384..9b87089a84c6 100644 --- a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst +++ b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + =========================================== netns_ipv4 struct fast path usage breakdown =========================================== diff --git a/Documentation/networking/net_cachelines/snmp.rst b/Documentation/networking/net_cachelines/snmp.rst index 1eaeb8bc252c..6a071538566c 100644 --- a/Documentation/networking/net_cachelines/snmp.rst +++ b/Documentation/networking/net_cachelines/snmp.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + =========================================== netns_ipv4 enum fast path usage breakdown =========================================== diff --git a/Documentation/networking/net_cachelines/tcp_sock.rst b/Documentation/networking/net_cachelines/tcp_sock.rst index 802ad22015d7..97d7a5c8e01c 100644 --- a/Documentation/networking/net_cachelines/tcp_sock.rst +++ b/Documentation/networking/net_cachelines/tcp_sock.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 .. Copyright (C) 2023 Google LLC + ========================================= tcp_sock struct fast path usage breakdown ========================================= From 2f57dd94bdef083855366138646b26b05f410d99 Mon Sep 17 00:00:00 2001 From: Yan Zhai Date: Mon, 4 Dec 2023 11:33:28 -0800 Subject: [PATCH 2738/7721] packet: add a generic drop reason for receive Commit da37845fdce2 ("packet: uses kfree_skb() for errors.") switches from consume_skb to kfree_skb to improve error handling. However, this could bring a lot of noises when we monitor real packet drops in kfree_skb[1], because in tpacket_rcv or packet_rcv only packet clones can be freed, not actual packets. Adding a generic drop reason to allow distinguish these "clone drops". [1]: https://lore.kernel.org/netdev/CABWYdi00L+O30Q=Zah28QwZ_5RU-xcxLFUK2Zj08A8MrLk9jzg@mail.gmail.com/ Fixes: da37845fdce2 ("packet: uses kfree_skb() for errors.") Suggested-by: Eric Dumazet Suggested-by: Willem de Bruijn Signed-off-by: Yan Zhai Reviewed-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/ZW4piNbx3IenYnuw@debian.debian Signed-off-by: Jakub Kicinski --- include/net/dropreason-core.h | 6 ++++++ net/packet/af_packet.c | 20 +++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index 3c70ad53a49c..278e4c7d465c 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -86,6 +86,7 @@ FN(IPV6_NDISC_NS_OTHERHOST) \ FN(QUEUE_PURGE) \ FN(TC_ERROR) \ + FN(PACKET_SOCK_ERROR) \ FNe(MAX) /** @@ -378,6 +379,11 @@ enum skb_drop_reason { SKB_DROP_REASON_QUEUE_PURGE, /** @SKB_DROP_REASON_TC_ERROR: generic internal tc error. */ SKB_DROP_REASON_TC_ERROR, + /** + * @SKB_DROP_REASON_PACKET_SOCK_ERROR: generic packet socket errors + * after its filter matches an incoming packet. + */ + SKB_DROP_REASON_PACKET_SOCK_ERROR, /** * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which * shouldn't be used as a real 'reason' - only for tracing code gen diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a84e00b5904b..f92edba4c40f 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2121,13 +2121,13 @@ static int packet_rcv_vnet(struct msghdr *msg, const struct sk_buff *skb, static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { + enum skb_drop_reason drop_reason = SKB_CONSUMED; struct sock *sk; struct sockaddr_ll *sll; struct packet_sock *po; u8 *skb_head = skb->data; int skb_len = skb->len; unsigned int snaplen, res; - bool is_drop_n_account = false; if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -2217,9 +2217,9 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, return 0; drop_n_acct: - is_drop_n_account = true; atomic_inc(&po->tp_drops); atomic_inc(&sk->sk_drops); + drop_reason = SKB_DROP_REASON_PACKET_SOCK_ERROR; drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { @@ -2227,16 +2227,14 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, skb->len = skb_len; } drop: - if (!is_drop_n_account) - consume_skb(skb); - else - kfree_skb(skb); + kfree_skb_reason(skb, drop_reason); return 0; } static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { + enum skb_drop_reason drop_reason = SKB_CONSUMED; struct sock *sk; struct packet_sock *po; struct sockaddr_ll *sll; @@ -2250,7 +2248,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct sk_buff *copy_skb = NULL; struct timespec64 ts; __u32 ts_status; - bool is_drop_n_account = false; unsigned int slot_id = 0; int vnet_hdr_sz = 0; @@ -2498,19 +2495,16 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, skb->len = skb_len; } drop: - if (!is_drop_n_account) - consume_skb(skb); - else - kfree_skb(skb); + kfree_skb_reason(skb, drop_reason); return 0; drop_n_account: spin_unlock(&sk->sk_receive_queue.lock); atomic_inc(&po->tp_drops); - is_drop_n_account = true; + drop_reason = SKB_DROP_REASON_PACKET_SOCK_ERROR; sk->sk_data_ready(sk); - kfree_skb(copy_skb); + kfree_skb_reason(copy_skb, drop_reason); goto drop_n_restore; } From 15e54faa5d5e4840974de7fb5cd737c2179a309a Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Mon, 4 Dec 2023 13:09:32 -0800 Subject: [PATCH 2739/7721] ionic: Use cached VF attributes Each time a VF attribute is set via iproute a call to get the VF configuration is also made. This is currently problematic because for each VF configuration call there are multiple commands sent to the device. Unfortunately, this doesn't scale well. Fix this by reporting the cached VF attributes. The original change to query the device for getting the VF attributes f16f5be31009 ("ionic: Query FW when getting VF info via ndo_get_vf_config") was made to remain consistent with device set VF attributes. However, after further investigation there is no need to query the device. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Florian Fainelli Reviewed-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20231204210936.16587-2-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic.h | 2 - .../net/ethernet/pensando/ionic/ionic_dev.c | 40 -------- .../net/ethernet/pensando/ionic/ionic_dev.h | 3 +- .../net/ethernet/pensando/ionic/ionic_lif.c | 91 ++----------------- .../net/ethernet/pensando/ionic/ionic_main.c | 22 ----- 5 files changed, 10 insertions(+), 148 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index 2453a40f6ee8..9ffef2e06885 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -91,6 +91,4 @@ int ionic_port_identify(struct ionic *ionic); int ionic_port_init(struct ionic *ionic); int ionic_port_reset(struct ionic *ionic); -const char *ionic_vf_attr_to_str(enum ionic_vf_attr attr); - #endif /* _IONIC_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index c06576f43916..bb9245d933e4 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -469,46 +469,6 @@ int ionic_set_vf_config(struct ionic *ionic, int vf, return err; } -int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr, - struct ionic_vf_getattr_comp *comp) -{ - union ionic_dev_cmd cmd = { - .vf_getattr.opcode = IONIC_CMD_VF_GETATTR, - .vf_getattr.attr = attr, - .vf_getattr.vf_index = cpu_to_le16(vf), - }; - int err; - - if (vf >= ionic->num_vfs) - return -EINVAL; - - switch (attr) { - case IONIC_VF_ATTR_SPOOFCHK: - case IONIC_VF_ATTR_TRUST: - case IONIC_VF_ATTR_LINKSTATE: - case IONIC_VF_ATTR_MAC: - case IONIC_VF_ATTR_VLAN: - case IONIC_VF_ATTR_RATE: - break; - case IONIC_VF_ATTR_STATSADDR: - default: - return -EINVAL; - } - - mutex_lock(&ionic->dev_cmd_lock); - ionic_dev_cmd_go(&ionic->idev, &cmd); - err = ionic_dev_cmd_wait_nomsg(ionic, DEVCMD_TIMEOUT); - memcpy_fromio(comp, &ionic->idev.dev_cmd_regs->comp.vf_getattr, - sizeof(*comp)); - mutex_unlock(&ionic->dev_cmd_lock); - - if (err && comp->status != IONIC_RC_ENOSUPP) - ionic_dev_cmd_dev_err_print(ionic, cmd.vf_getattr.opcode, - comp->status, err); - - return err; -} - void ionic_vf_start(struct ionic *ionic) { union ionic_dev_cmd cmd = { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 1dbc3cb50b1d..19edcb42d9fd 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -341,8 +341,7 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type); int ionic_set_vf_config(struct ionic *ionic, int vf, struct ionic_vf_setattr_cmd *vfc); -int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr, - struct ionic_vf_getattr_comp *comp); + void ionic_dev_cmd_queue_identify(struct ionic_dev *idev, u16 lif_type, u8 qtype, u8 qver); void ionic_vf_start(struct ionic *ionic); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index edc14730ce88..afb77e2d04c5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -2332,82 +2332,11 @@ static int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd } } -static int ionic_get_fw_vf_config(struct ionic *ionic, int vf, struct ionic_vf *vfdata) -{ - struct ionic_vf_getattr_comp comp = { 0 }; - int err; - u8 attr; - - attr = IONIC_VF_ATTR_VLAN; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) - vfdata->vlanid = comp.vlanid; - - attr = IONIC_VF_ATTR_SPOOFCHK; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) - vfdata->spoofchk = comp.spoofchk; - - attr = IONIC_VF_ATTR_LINKSTATE; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) { - switch (comp.linkstate) { - case IONIC_VF_LINK_STATUS_UP: - vfdata->linkstate = IFLA_VF_LINK_STATE_ENABLE; - break; - case IONIC_VF_LINK_STATUS_DOWN: - vfdata->linkstate = IFLA_VF_LINK_STATE_DISABLE; - break; - case IONIC_VF_LINK_STATUS_AUTO: - vfdata->linkstate = IFLA_VF_LINK_STATE_AUTO; - break; - default: - dev_warn(ionic->dev, "Unexpected link state %u\n", comp.linkstate); - break; - } - } - - attr = IONIC_VF_ATTR_RATE; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) - vfdata->maxrate = comp.maxrate; - - attr = IONIC_VF_ATTR_TRUST; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) - vfdata->trusted = comp.trust; - - attr = IONIC_VF_ATTR_MAC; - err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); - if (err && comp.status != IONIC_RC_ENOSUPP) - goto err_out; - if (!err) - ether_addr_copy(vfdata->macaddr, comp.macaddr); - -err_out: - if (err) - dev_err(ionic->dev, "Failed to get %s for VF %d\n", - ionic_vf_attr_to_str(attr), vf); - - return err; -} - static int ionic_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivf) { struct ionic_lif *lif = netdev_priv(netdev); struct ionic *ionic = lif->ionic; - struct ionic_vf vfdata = { 0 }; int ret = 0; if (!netif_device_present(netdev)) @@ -2418,18 +2347,16 @@ static int ionic_get_vf_config(struct net_device *netdev, if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { ret = -EINVAL; } else { - ivf->vf = vf; - ivf->qos = 0; + struct ionic_vf *vfdata = &ionic->vfs[vf]; - ret = ionic_get_fw_vf_config(ionic, vf, &vfdata); - if (!ret) { - ivf->vlan = le16_to_cpu(vfdata.vlanid); - ivf->spoofchk = vfdata.spoofchk; - ivf->linkstate = vfdata.linkstate; - ivf->max_tx_rate = le32_to_cpu(vfdata.maxrate); - ivf->trusted = vfdata.trusted; - ether_addr_copy(ivf->mac, vfdata.macaddr); - } + ivf->vf = vf; + ivf->qos = 0; + ivf->vlan = le16_to_cpu(vfdata->vlanid); + ivf->spoofchk = vfdata->spoofchk; + ivf->linkstate = vfdata->linkstate; + ivf->max_tx_rate = le32_to_cpu(vfdata->maxrate); + ivf->trusted = vfdata->trusted; + ether_addr_copy(ivf->mac, vfdata->macaddr); } up_read(&ionic->vf_op_lock); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 835577392178..8d15f9203bd5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -188,28 +188,6 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode) } } -const char *ionic_vf_attr_to_str(enum ionic_vf_attr attr) -{ - switch (attr) { - case IONIC_VF_ATTR_SPOOFCHK: - return "IONIC_VF_ATTR_SPOOFCHK"; - case IONIC_VF_ATTR_TRUST: - return "IONIC_VF_ATTR_TRUST"; - case IONIC_VF_ATTR_LINKSTATE: - return "IONIC_VF_ATTR_LINKSTATE"; - case IONIC_VF_ATTR_MAC: - return "IONIC_VF_ATTR_MAC"; - case IONIC_VF_ATTR_VLAN: - return "IONIC_VF_ATTR_VLAN"; - case IONIC_VF_ATTR_RATE: - return "IONIC_VF_ATTR_RATE"; - case IONIC_VF_ATTR_STATSADDR: - return "IONIC_VF_ATTR_STATSADDR"; - default: - return "IONIC_VF_ATTR_UNKNOWN"; - } -} - static void ionic_adminq_flush(struct ionic_lif *lif) { struct ionic_desc_info *desc_info; From 46ca79d28fd7f2bbccf226fc0be59c2bd8d63dfe Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 4 Dec 2023 13:09:33 -0800 Subject: [PATCH 2740/7721] ionic: set ionic ptr before setting up ethtool ops Set the lif->ionic value that is used in some ethtool callbacks before setting ethtool ops. There really shouldn't be any race issues before this change since the netdev hasn't been registered yet, but this seems more correct. Signed-off-by: Shannon Nelson Reviewed-by: Brett Creeley Reviewed-by: Florian Fainelli Reviewed-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20231204210936.16587-3-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index afb77e2d04c5..a5e6b1e2f5ee 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -3054,6 +3054,7 @@ int ionic_lif_alloc(struct ionic *ionic) lif = netdev_priv(netdev); lif->netdev = netdev; ionic->lif = lif; + lif->ionic = ionic; netdev->netdev_ops = &ionic_netdev_ops; ionic_ethtool_set_ops(netdev); @@ -3076,7 +3077,6 @@ int ionic_lif_alloc(struct ionic *ionic) lif->neqs = ionic->neqs_per_lif; lif->nxqs = ionic->ntxqs_per_lif; - lif->ionic = ionic; lif->index = 0; if (is_kdump_kernel()) { From 2d0b80c3a550f7828f26dba029c2b9346be789af Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Mon, 4 Dec 2023 13:09:34 -0800 Subject: [PATCH 2741/7721] ionic: Don't check null when calling vfree() vfree() checks for null internally, so there's no need to check in the caller. So, always vfree() on variables allocated with valloc(). If the variables are never alloc'd vfree() is still safe. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Florian Fainelli Reviewed-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20231204210936.16587-4-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index a5e6b1e2f5ee..6842a31fc04b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -424,14 +424,10 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq) ionic_qcq_intr_free(lif, qcq); - if (qcq->cq.info) { - vfree(qcq->cq.info); - qcq->cq.info = NULL; - } - if (qcq->q.info) { - vfree(qcq->q.info); - qcq->q.info = NULL; - } + vfree(qcq->cq.info); + qcq->cq.info = NULL; + vfree(qcq->q.info); + qcq->q.info = NULL; } void ionic_qcqs_free(struct ionic_lif *lif) From ab807e9183425ddf6dd85ca622a51fe4cad2c577 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Mon, 4 Dec 2023 13:09:35 -0800 Subject: [PATCH 2742/7721] ionic: Make the check for Tx HW timestamping more obvious Currently the checks are: [1] unlikely(q->features & IONIC_TXQ_F_HWSTAMP) [2] !unlikely(q->features & IONIC_TXQ_F_HWSTAMP) [1] is clear enough, but [2] isn't exactly obvious to the reader because !unlikely reads as likely. However, that's not what this means. [2] means that it's unlikely that the q has IONIC_TXQ_F_HWSTAMP enabled. Write an inline helper function to hide the unlikely optimization to make these checks more readable. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Florian Fainelli Reviewed-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20231204210936.16587-5-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic_lif.h | 5 +++++ drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 457c24195ca6..61548b3eea93 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -312,6 +312,11 @@ static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs) return (usecs * mult) / div; } +static inline bool ionic_txq_hwstamp_enabled(struct ionic_queue *q) +{ + return unlikely(q->features & IONIC_TXQ_F_HWSTAMP); +} + void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep); void ionic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *ns); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index ccc1b1d407e4..54cd96b035d6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -803,7 +803,7 @@ static void ionic_tx_clean(struct ionic_queue *q, qi = skb_get_queue_mapping(skb); - if (unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) { + if (ionic_txq_hwstamp_enabled(q)) { if (cq_info) { struct skb_shared_hwtstamps hwts = {}; __le64 *cq_desc_hwstamp; @@ -870,7 +870,7 @@ bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) desc_info->cb_arg = NULL; } while (index != le16_to_cpu(comp->comp_index)); - if (pkts && bytes && !unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) + if (pkts && bytes && !ionic_txq_hwstamp_enabled(q)) netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes); return true; @@ -908,7 +908,7 @@ void ionic_tx_empty(struct ionic_queue *q) desc_info->cb_arg = NULL; } - if (pkts && bytes && !unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) + if (pkts && bytes && !ionic_txq_hwstamp_enabled(q)) netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes); } @@ -986,7 +986,7 @@ static void ionic_tx_tso_post(struct ionic_queue *q, if (start) { skb_tx_timestamp(skb); - if (!unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) + if (!ionic_txq_hwstamp_enabled(q)) netdev_tx_sent_queue(q_to_ndq(q), skb->len); ionic_txq_post(q, false, ionic_tx_clean, skb); } else { @@ -1233,7 +1233,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) stats->pkts++; stats->bytes += skb->len; - if (!unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) + if (!ionic_txq_hwstamp_enabled(q)) netdev_tx_sent_queue(q_to_ndq(q), skb->len); ionic_txq_post(q, !netdev_xmit_more(), ionic_tx_clean, skb); From 5858036ca05658051ec61551e6699cca9c7d3369 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Mon, 4 Dec 2023 13:09:36 -0800 Subject: [PATCH 2743/7721] ionic: Re-arrange ionic_intr_info struct for cache perf dim_coal_hw is accessed in the hotpath along with other values from the first cacheline of ionic_intr_info. So, re-arrange the structure so the hot path variables are on the first cacheline. Before: struct ionic_intr_info { char name[32]; /* 0 32 */ unsigned int index; /* 32 4 */ unsigned int vector; /* 36 4 */ u64 rearm_count; /* 40 8 */ unsigned int cpu; /* 48 4 */ /* XXX 4 bytes hole, try to pack */ cpumask_t affinity_mask; /* 56 1024 */ /* --- cacheline 16 boundary (1024 bytes) was 56 bytes ago --- */ u32 dim_coal_hw; /* 1080 4 */ /* size: 1088, cachelines: 17, members: 7 */ /* sum members: 1080, holes: 1, sum holes: 4 */ /* padding: 4 */ }; After: struct ionic_intr_info { char name[32]; /* 0 32 */ u64 rearm_count; /* 32 8 */ unsigned int index; /* 40 4 */ unsigned int vector; /* 44 4 */ unsigned int cpu; /* 48 4 */ u32 dim_coal_hw; /* 52 4 */ cpumask_t affinity_mask; /* 56 1024 */ /* size: 1080, cachelines: 17, members: 7 */ /* last cacheline: 56 bytes */ }; Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Florian Fainelli Reviewed-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20231204210936.16587-6-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic_dev.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 19edcb42d9fd..cee4e5c3d09a 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -269,12 +269,12 @@ struct ionic_queue { struct ionic_intr_info { char name[IONIC_INTR_NAME_MAX_SZ]; + u64 rearm_count; unsigned int index; unsigned int vector; - u64 rearm_count; unsigned int cpu; - cpumask_t affinity_mask; u32 dim_coal_hw; + cpumask_t affinity_mask; }; struct ionic_cq { From 9cf5ca1f485cae406968947a92bf304603999fa1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:31 +0100 Subject: [PATCH 2744/7721] drm: Fix TODO list mentioning non-KMS drivers Non-KMS drivers have been removed from DRM. Update the TODO list accordingly. Signed-off-by: Thomas Zimmermann Fixes: a276afc19eec ("drm: Remove some obsolete drm pciids(tdfx, mga, i810, savage, r128, sis, via)") Cc: Cai Huoqing Cc: Daniel Vetter Cc: Dave Airlie Cc: Thomas Zimmermann Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: David Airlie Cc: Daniel Vetter Cc: Jonathan Corbet Cc: dri-devel@lists.freedesktop.org Cc: # v6.3+ Cc: linux-doc@vger.kernel.org Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-3-tzimmermann@suse.de --- Documentation/gpu/todo.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 503d57c75215..41a264bf84ce 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -337,8 +337,8 @@ connector register/unregister fixes Level: Intermediate -Remove load/unload callbacks from all non-DRIVER_LEGACY drivers ---------------------------------------------------------------- +Remove load/unload callbacks +---------------------------- The load/unload callbacks in struct &drm_driver are very much midlayers, plus for historical reasons they get the ordering wrong (and we can't fix that) @@ -347,8 +347,7 @@ between setting up the &drm_driver structure and calling drm_dev_register(). - Rework drivers to no longer use the load/unload callbacks, directly coding the load/unload sequence into the driver's probe function. -- Once all non-DRIVER_LEGACY drivers are converted, disallow the load/unload - callbacks for all modern drivers. +- Once all drivers are converted, remove the load/unload callbacks. Contact: Daniel Vetter From 972c45e892448f698047f312763eb984c0b8d7c3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:32 +0100 Subject: [PATCH 2745/7721] drm: Include One of the source files includes via , which will be removed. Include drm_auth.h directly. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 39d35fc3a43b..67907dd42721 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include From 786b96d01919f8876187d75a6a995ac5783ed0f5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:33 +0100 Subject: [PATCH 2746/7721] drm/i915: Include One of the source files includes via , which will be removed. Include drm_auth.h directly. Signed-off-by: Thomas Zimmermann Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: intel-gfx@lists.freedesktop.org Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-5-tzimmermann@suse.de --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 683fd8d3151c..ccc077b74d2d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "display/intel_frontbuffer.h" From 64c39a93ef6c45447bc093e34e02afeb4c063579 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:34 +0100 Subject: [PATCH 2747/7721] accel: Include One of the source files includes via , which will be removed. Include drm_auth.h directly. Signed-off-by: Thomas Zimmermann Cc: Oded Gabbay Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-6-tzimmermann@suse.de --- drivers/accel/drm_accel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index 294b572a9c33..24cac4c0274b 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include From 9f4db4495b6fa551f18a892f32c71899a20f4923 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:35 +0100 Subject: [PATCH 2748/7721] drm: Include Include in drm_ioc32.c. Resolves a depenency on , which will be removed. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-7-tzimmermann@suse.de --- drivers/gpu/drm/drm_ioc32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 025dc558c94e..c0163cb076ad 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -31,6 +31,7 @@ #include #include +#include #include #include From c45a1e0a2e9d3f6b37d27e636ba905678c84a41a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:36 +0100 Subject: [PATCH 2749/7721] drm/radeon: Do not include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Including is not required by radeon. Signed-off-by: Thomas Zimmermann Cc: Alex Deucher Cc: "Christian König" Cc: "Pan, Xinhui" Cc: amd-gfx@lists.freedesktop.org Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-8-tzimmermann@suse.de --- drivers/gpu/drm/radeon/radeon_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 34a1c73d3938..02a65971d140 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -33,7 +33,6 @@ #include #include -#include #include "radeon_family.h" From 184dcdc251420929bf195f99f0b9fb6960788b6d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:37 +0100 Subject: [PATCH 2750/7721] drm: Remove entry points for legacy ioctls DRM drivers with user-space mode setting have been removed in Linux v6.3. [1] Now remove the ioctl entry points for these drivers. Invoking any of the ioctl ops will unconditionally return -EINVAL to user space. This has already been the behavior for kernels without CONFIG_DRM_LEGACY set. Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/series/111602/ # [1] Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-9-tzimmermann@suse.de --- drivers/gpu/drm/drm_ioc32.c | 610 ------------------------------------ drivers/gpu/drm/drm_ioctl.c | 57 ---- 2 files changed, 667 deletions(-) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index c0163cb076ad..910cadf14756 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -37,7 +37,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) @@ -164,92 +163,6 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, return -EINVAL; } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -typedef struct drm_map32 { - u32 offset; /* Requested physical address (0 for SAREA) */ - u32 size; /* Requested physical size (bytes) */ - enum drm_map_type type; /* Type of memory to map */ - enum drm_map_flags flags; /* Flags */ - u32 handle; /* User-space: "Handle" to pass to mmap() */ - int mtrr; /* MTRR slot used */ -} drm_map32_t; - -static int compat_drm_getmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - drm_map32_t m32; - struct drm_map map; - int err; - - if (copy_from_user(&m32, argp, sizeof(m32))) - return -EFAULT; - - map.offset = m32.offset; - err = drm_ioctl_kernel(file, drm_legacy_getmap_ioctl, &map, 0); - if (err) - return err; - - m32.offset = map.offset; - m32.size = map.size; - m32.type = map.type; - m32.flags = map.flags; - m32.handle = ptr_to_compat((void __user *)map.handle); - m32.mtrr = map.mtrr; - if (copy_to_user(argp, &m32, sizeof(m32))) - return -EFAULT; - return 0; - -} - -static int compat_drm_addmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - drm_map32_t m32; - struct drm_map map; - int err; - - if (copy_from_user(&m32, argp, sizeof(m32))) - return -EFAULT; - - map.offset = m32.offset; - map.size = m32.size; - map.type = m32.type; - map.flags = m32.flags; - - err = drm_ioctl_kernel(file, drm_legacy_addmap_ioctl, &map, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - m32.offset = map.offset; - m32.mtrr = map.mtrr; - m32.handle = ptr_to_compat((void __user *)map.handle); - if (map.handle != compat_ptr(m32.handle)) - pr_err_ratelimited("compat_drm_addmap truncated handle %p for type %d offset %x\n", - map.handle, m32.type, m32.offset); - - if (copy_to_user(argp, &m32, sizeof(m32))) - return -EFAULT; - - return 0; -} - -static int compat_drm_rmmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - struct drm_map map; - u32 handle; - - if (get_user(handle, &argp->handle)) - return -EFAULT; - map.handle = compat_ptr(handle); - return drm_ioctl_kernel(file, drm_legacy_rmmap_ioctl, &map, DRM_AUTH); -} -#endif - typedef struct drm_client32 { int idx; /* Which client desired? */ int auth; /* Is client authenticated? */ @@ -309,501 +222,6 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, return 0; } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -typedef struct drm_buf_desc32 { - int count; /* Number of buffers of this size */ - int size; /* Size in bytes */ - int low_mark; /* Low water mark */ - int high_mark; /* High water mark */ - int flags; - u32 agp_start; /* Start address in the AGP aperture */ -} drm_buf_desc32_t; - -static int compat_drm_addbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_desc32_t __user *argp = (void __user *)arg; - drm_buf_desc32_t desc32; - struct drm_buf_desc desc; - int err; - - if (copy_from_user(&desc32, argp, sizeof(drm_buf_desc32_t))) - return -EFAULT; - - desc = (struct drm_buf_desc){ - desc32.count, desc32.size, desc32.low_mark, desc32.high_mark, - desc32.flags, desc32.agp_start - }; - - err = drm_ioctl_kernel(file, drm_legacy_addbufs, &desc, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - desc32 = (drm_buf_desc32_t){ - desc.count, desc.size, desc.low_mark, desc.high_mark, - desc.flags, desc.agp_start - }; - if (copy_to_user(argp, &desc32, sizeof(drm_buf_desc32_t))) - return -EFAULT; - - return 0; -} - -static int compat_drm_markbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_desc32_t b32; - drm_buf_desc32_t __user *argp = (void __user *)arg; - struct drm_buf_desc buf; - - if (copy_from_user(&b32, argp, sizeof(b32))) - return -EFAULT; - - buf.size = b32.size; - buf.low_mark = b32.low_mark; - buf.high_mark = b32.high_mark; - - return drm_ioctl_kernel(file, drm_legacy_markbufs, &buf, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_buf_info32 { - int count; /**< Entries in list */ - u32 list; -} drm_buf_info32_t; - -static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from) -{ - drm_buf_info32_t *request = data; - drm_buf_desc32_t __user *to = compat_ptr(request->list); - drm_buf_desc32_t v = {.count = from->buf_count, - .size = from->buf_size, - .low_mark = from->low_mark, - .high_mark = from->high_mark}; - - if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags))) - return -EFAULT; - return 0; -} - -static int drm_legacy_infobufs32(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_buf_info32_t *request = data; - - return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf32); -} - -static int compat_drm_infobufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_info32_t req32; - drm_buf_info32_t __user *argp = (void __user *)arg; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - if (req32.count < 0) - req32.count = 0; - - err = drm_ioctl_kernel(file, drm_legacy_infobufs32, &req32, DRM_AUTH); - if (err) - return err; - - if (put_user(req32.count, &argp->count)) - return -EFAULT; - - return 0; -} - -typedef struct drm_buf_pub32 { - int idx; /**< Index into the master buffer list */ - int total; /**< Buffer size */ - int used; /**< Amount of buffer in use (for DMA) */ - u32 address; /**< Address of buffer */ -} drm_buf_pub32_t; - -typedef struct drm_buf_map32 { - int count; /**< Length of the buffer list */ - u32 virtual; /**< Mmap'd area in user-virtual */ - u32 list; /**< Buffer information */ -} drm_buf_map32_t; - -static int map_one_buf32(void *data, int idx, unsigned long virtual, - struct drm_buf *buf) -{ - drm_buf_map32_t *request = data; - drm_buf_pub32_t __user *to = compat_ptr(request->list) + idx; - drm_buf_pub32_t v; - - v.idx = buf->idx; - v.total = buf->total; - v.used = 0; - v.address = virtual + buf->offset; - if (copy_to_user(to, &v, sizeof(v))) - return -EFAULT; - return 0; -} - -static int drm_legacy_mapbufs32(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_buf_map32_t *request = data; - void __user *v; - int err = __drm_legacy_mapbufs(dev, data, &request->count, - &v, map_one_buf32, - file_priv); - request->virtual = ptr_to_compat(v); - return err; -} - -static int compat_drm_mapbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_map32_t __user *argp = (void __user *)arg; - drm_buf_map32_t req32; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - if (req32.count < 0) - return -EINVAL; - - err = drm_ioctl_kernel(file, drm_legacy_mapbufs32, &req32, DRM_AUTH); - if (err) - return err; - - if (put_user(req32.count, &argp->count) - || put_user(req32.virtual, &argp->virtual)) - return -EFAULT; - - return 0; -} - -typedef struct drm_buf_free32 { - int count; - u32 list; -} drm_buf_free32_t; - -static int compat_drm_freebufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_free32_t req32; - struct drm_buf_free request; - drm_buf_free32_t __user *argp = (void __user *)arg; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.count = req32.count; - request.list = compat_ptr(req32.list); - return drm_ioctl_kernel(file, drm_legacy_freebufs, &request, DRM_AUTH); -} - -typedef struct drm_ctx_priv_map32 { - unsigned int ctx_id; /**< Context requesting private mapping */ - u32 handle; /**< Handle of map */ -} drm_ctx_priv_map32_t; - -static int compat_drm_setsareactx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_priv_map32_t req32; - struct drm_ctx_priv_map request; - drm_ctx_priv_map32_t __user *argp = (void __user *)arg; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.ctx_id = req32.ctx_id; - request.handle = compat_ptr(req32.handle); - return drm_ioctl_kernel(file, drm_legacy_setsareactx, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -static int compat_drm_getsareactx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct drm_ctx_priv_map req; - drm_ctx_priv_map32_t req32; - drm_ctx_priv_map32_t __user *argp = (void __user *)arg; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - req.ctx_id = req32.ctx_id; - err = drm_ioctl_kernel(file, drm_legacy_getsareactx, &req, DRM_AUTH); - if (err) - return err; - - req32.handle = ptr_to_compat((void __user *)req.handle); - if (copy_to_user(argp, &req32, sizeof(req32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_ctx_res32 { - int count; - u32 contexts; -} drm_ctx_res32_t; - -static int compat_drm_resctx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_res32_t __user *argp = (void __user *)arg; - drm_ctx_res32_t res32; - struct drm_ctx_res res; - int err; - - if (copy_from_user(&res32, argp, sizeof(res32))) - return -EFAULT; - - res.count = res32.count; - res.contexts = compat_ptr(res32.contexts); - err = drm_ioctl_kernel(file, drm_legacy_resctx, &res, DRM_AUTH); - if (err) - return err; - - res32.count = res.count; - if (copy_to_user(argp, &res32, sizeof(res32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_dma32 { - int context; /**< Context handle */ - int send_count; /**< Number of buffers to send */ - u32 send_indices; /**< List of handles to buffers */ - u32 send_sizes; /**< Lengths of data to send */ - enum drm_dma_flags flags; /**< Flags */ - int request_count; /**< Number of buffers requested */ - int request_size; /**< Desired size for buffers */ - u32 request_indices; /**< Buffer information */ - u32 request_sizes; - int granted_count; /**< Number of buffers granted */ -} drm_dma32_t; - -static int compat_drm_dma(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_dma32_t d32; - drm_dma32_t __user *argp = (void __user *)arg; - struct drm_dma d; - int err; - - if (copy_from_user(&d32, argp, sizeof(d32))) - return -EFAULT; - - d.context = d32.context; - d.send_count = d32.send_count; - d.send_indices = compat_ptr(d32.send_indices); - d.send_sizes = compat_ptr(d32.send_sizes); - d.flags = d32.flags; - d.request_count = d32.request_count; - d.request_indices = compat_ptr(d32.request_indices); - d.request_sizes = compat_ptr(d32.request_sizes); - err = drm_ioctl_kernel(file, drm_legacy_dma_ioctl, &d, DRM_AUTH); - if (err) - return err; - - if (put_user(d.request_size, &argp->request_size) - || put_user(d.granted_count, &argp->granted_count)) - return -EFAULT; - - return 0; -} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -#if IS_ENABLED(CONFIG_AGP) -typedef struct drm_agp_mode32 { - u32 mode; /**< AGP mode */ -} drm_agp_mode32_t; - -static int compat_drm_agp_enable(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_mode32_t __user *argp = (void __user *)arg; - struct drm_agp_mode mode; - - if (get_user(mode.mode, &argp->mode)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_enable_ioctl, &mode, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_agp_info32 { - int agp_version_major; - int agp_version_minor; - u32 mode; - u32 aperture_base; /* physical address */ - u32 aperture_size; /* bytes */ - u32 memory_allowed; /* bytes */ - u32 memory_used; - - /* PCI information */ - unsigned short id_vendor; - unsigned short id_device; -} drm_agp_info32_t; - -static int compat_drm_agp_info(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_info32_t __user *argp = (void __user *)arg; - drm_agp_info32_t i32; - struct drm_agp_info info; - int err; - - err = drm_ioctl_kernel(file, drm_legacy_agp_info_ioctl, &info, DRM_AUTH); - if (err) - return err; - - i32.agp_version_major = info.agp_version_major; - i32.agp_version_minor = info.agp_version_minor; - i32.mode = info.mode; - i32.aperture_base = info.aperture_base; - i32.aperture_size = info.aperture_size; - i32.memory_allowed = info.memory_allowed; - i32.memory_used = info.memory_used; - i32.id_vendor = info.id_vendor; - i32.id_device = info.id_device; - if (copy_to_user(argp, &i32, sizeof(i32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_agp_buffer32 { - u32 size; /**< In bytes -- will round to page boundary */ - u32 handle; /**< Used for binding / unbinding */ - u32 type; /**< Type of memory to allocate */ - u32 physical; /**< Physical used by i810 */ -} drm_agp_buffer32_t; - -static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_buffer32_t __user *argp = (void __user *)arg; - drm_agp_buffer32_t req32; - struct drm_agp_buffer request; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.size = req32.size; - request.type = req32.type; - err = drm_ioctl_kernel(file, drm_legacy_agp_alloc_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - req32.handle = request.handle; - req32.physical = request.physical; - if (copy_to_user(argp, &req32, sizeof(req32))) { - drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - return -EFAULT; - } - - return 0; -} - -static int compat_drm_agp_free(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_buffer32_t __user *argp = (void __user *)arg; - struct drm_agp_buffer request; - - if (get_user(request.handle, &argp->handle)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_agp_binding32 { - u32 handle; /**< From drm_agp_buffer */ - u32 offset; /**< In bytes -- will round to page boundary */ -} drm_agp_binding32_t; - -static int compat_drm_agp_bind(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_binding32_t __user *argp = (void __user *)arg; - drm_agp_binding32_t req32; - struct drm_agp_binding request; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.handle = req32.handle; - request.offset = req32.offset; - return drm_ioctl_kernel(file, drm_legacy_agp_bind_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_binding32_t __user *argp = (void __user *)arg; - struct drm_agp_binding request; - - if (get_user(request.handle, &argp->handle)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_unbind_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} -#endif /* CONFIG_AGP */ - -typedef struct drm_scatter_gather32 { - u32 size; /**< In bytes -- will round to page boundary */ - u32 handle; /**< Used for mapping / unmapping */ -} drm_scatter_gather32_t; - -static int compat_drm_sg_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_scatter_gather32_t __user *argp = (void __user *)arg; - struct drm_scatter_gather request; - int err; - - if (get_user(request.size, &argp->size)) - return -EFAULT; - - err = drm_ioctl_kernel(file, drm_legacy_sg_alloc, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - /* XXX not sure about the handle conversion here... */ - if (put_user(request.handle >> PAGE_SHIFT, &argp->handle)) - return -EFAULT; - - return 0; -} - -static int compat_drm_sg_free(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_scatter_gather32_t __user *argp = (void __user *)arg; - struct drm_scatter_gather request; - unsigned long x; - - if (get_user(x, &argp->handle)) - return -EFAULT; - request.handle = x << PAGE_SHIFT; - return drm_ioctl_kernel(file, drm_legacy_sg_free, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} -#endif #if defined(CONFIG_X86) typedef struct drm_update_draw32 { drm_drawable_t handle; @@ -915,37 +333,9 @@ static struct { #define DRM_IOCTL32_DEF(n, f) [DRM_IOCTL_NR(n##32)] = {.fn = f, .name = #n} DRM_IOCTL32_DEF(DRM_IOCTL_VERSION, compat_drm_version), DRM_IOCTL32_DEF(DRM_IOCTL_GET_UNIQUE, compat_drm_getunique), -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_GET_MAP, compat_drm_getmap), -#endif DRM_IOCTL32_DEF(DRM_IOCTL_GET_CLIENT, compat_drm_getclient), DRM_IOCTL32_DEF(DRM_IOCTL_GET_STATS, compat_drm_getstats), DRM_IOCTL32_DEF(DRM_IOCTL_SET_UNIQUE, compat_drm_setunique), -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_ADD_MAP, compat_drm_addmap), - DRM_IOCTL32_DEF(DRM_IOCTL_ADD_BUFS, compat_drm_addbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_MARK_BUFS, compat_drm_markbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_INFO_BUFS, compat_drm_infobufs), - DRM_IOCTL32_DEF(DRM_IOCTL_MAP_BUFS, compat_drm_mapbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_FREE_BUFS, compat_drm_freebufs), - DRM_IOCTL32_DEF(DRM_IOCTL_RM_MAP, compat_drm_rmmap), - DRM_IOCTL32_DEF(DRM_IOCTL_SET_SAREA_CTX, compat_drm_setsareactx), - DRM_IOCTL32_DEF(DRM_IOCTL_GET_SAREA_CTX, compat_drm_getsareactx), - DRM_IOCTL32_DEF(DRM_IOCTL_RES_CTX, compat_drm_resctx), - DRM_IOCTL32_DEF(DRM_IOCTL_DMA, compat_drm_dma), -#if IS_ENABLED(CONFIG_AGP) - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ENABLE, compat_drm_agp_enable), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_INFO, compat_drm_agp_info), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ALLOC, compat_drm_agp_alloc), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_FREE, compat_drm_agp_free), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_BIND, compat_drm_agp_bind), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_UNBIND, compat_drm_agp_unbind), -#endif -#endif -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_SG_ALLOC, compat_drm_sg_alloc), - DRM_IOCTL32_DEF(DRM_IOCTL_SG_FREE, compat_drm_sg_free), -#endif #if defined(CONFIG_X86) DRM_IOCTL32_DEF(DRM_IOCTL_UPDATE_DRAW, compat_drm_update_draw), #endif diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index ea303386e688..93f6bf15c0ae 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -42,7 +42,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" /** * DOC: getunique and setversion story @@ -572,21 +571,11 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) .name = #ioctl \ } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, _func, _flags) -#else -#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, drm_invalid_op, _flags) -#endif - /* Ioctl table */ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_legacy_irq_by_busid, - DRM_MASTER|DRM_ROOT_ONLY), - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), @@ -599,60 +588,14 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_LOCK, drm_legacy_lock, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_legacy_unlock, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_legacy_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_legacy_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_legacy_infobufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_legacy_mapbufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_legacy_freebufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_DMA, drm_legacy_dma_ioctl, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_legacy_irq_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - -#if IS_ENABLED(CONFIG_AGP) - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_legacy_agp_acquire_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_legacy_agp_release_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_legacy_agp_enable_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_legacy_agp_info_ioctl, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_legacy_agp_alloc_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_legacy_agp_free_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_legacy_agp_bind_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_legacy_agp_unbind_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -#endif - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_legacy_modeset_ctl_ioctl, 0), From 6bb0814be42e109555dd63e59e6eabf968b9b016 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:38 +0100 Subject: [PATCH 2751/7721] drm: Remove the legacy DRM_IOCTL_MODESET_CTL ioctl DRM drivers with user-space mode setting have been removed in Linux v6.3. [1] Now remove the ioctl entry points for these drivers. Invoking any of the ioctl ops will unconditionally return -EINVAL to user space. Invoking DRM_IOCTL_MODESET_CTL is different from the other legacy ioctl ops as it returns 0 even without CONFIG_DRM_LEGACY set. From the original commit 29935554b384 ("drm: Disallow DRM_IOCTL_MODESET_CTL for KMS drivers") it is not apparent how or why the operation differs from the others. It is likely just an oversight in commit 61ae227032e7 ("drm: allow removal of legacy codepaths (v4.1)"), which allowed disabling leagacy ioctls in the first place. Still keep this removal separate from the other ioctls to allow an easy revert, if necessary. Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/series/111602/ # [1] Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-10-tzimmermann@suse.de --- drivers/gpu/drm/drm_internal.h | 2 - drivers/gpu/drm/drm_ioctl.c | 2 - drivers/gpu/drm/drm_vblank.c | 82 ---------------------------------- 3 files changed, 86 deletions(-) diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b7a311efa2b1..fa08a313127e 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -117,8 +117,6 @@ void drm_handle_vblank_works(struct drm_vblank_crtc *vblank); /* IOCTLS */ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); -int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); /* drm_irq.c */ diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 93f6bf15c0ae..ebba34ba734e 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -598,8 +598,6 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_legacy_modeset_ctl_ioctl, 0), - DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 877e2067534f..a11f164b2384 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -1574,88 +1574,6 @@ void drm_crtc_vblank_restore(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_restore); -static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, - unsigned int pipe) -{ - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - - /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!drm_dev_has_vblank(dev)) - return; - - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) - return; - - /* - * To avoid all the problems that might happen if interrupts - * were enabled/disabled around or between these calls, we just - * have the kernel take a reference on the CRTC (just once though - * to avoid corrupting the count if multiple, mismatch calls occur), - * so that interrupts remain enabled in the interim. - */ - if (!vblank->inmodeset) { - vblank->inmodeset = 0x1; - if (drm_vblank_get(dev, pipe) == 0) - vblank->inmodeset |= 0x2; - } -} - -static void drm_legacy_vblank_post_modeset(struct drm_device *dev, - unsigned int pipe) -{ - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - - /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!drm_dev_has_vblank(dev)) - return; - - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) - return; - - if (vblank->inmodeset) { - spin_lock_irq(&dev->vbl_lock); - drm_reset_vblank_timestamp(dev, pipe); - spin_unlock_irq(&dev->vbl_lock); - - if (vblank->inmodeset & 0x2) - drm_vblank_put(dev, pipe); - - vblank->inmodeset = 0; - } -} - -int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_modeset_ctl *modeset = data; - unsigned int pipe; - - /* If drm_vblank_init() hasn't been called yet, just no-op */ - if (!drm_dev_has_vblank(dev)) - return 0; - - /* KMS drivers handle this internally */ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - - pipe = modeset->crtc; - if (pipe >= dev->num_crtcs) - return -EINVAL; - - switch (modeset->cmd) { - case _DRM_PRE_MODESET: - drm_legacy_vblank_pre_modeset(dev, pipe); - break; - case _DRM_POST_MODESET: - drm_legacy_vblank_post_modeset(dev, pipe); - break; - default: - return -EINVAL; - } - - return 0; -} - static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, u64 req_seq, union drm_wait_vblank *vblwait, From 2722ac1ce1c1f3e6a3a0c59f0072b2f9ba136551 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:39 +0100 Subject: [PATCH 2752/7721] drm: Remove support for legacy drivers Remove all hooks and calls into code for user-space mode setting from the DRM core. Without the drivers and ioctl entry points, none of this is required any longer. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-11-tzimmermann@suse.de --- drivers/gpu/drm/drm_auth.c | 8 +---- drivers/gpu/drm/drm_drv.c | 17 ---------- drivers/gpu/drm/drm_file.c | 64 ++---------------------------------- drivers/gpu/drm/drm_vblank.c | 19 ----------- 4 files changed, 3 insertions(+), 105 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 2ed2585ded37..252c105d614f 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -37,13 +37,12 @@ #include #include "drm_internal.h" -#include "drm_legacy.h" /** * DOC: master and authentication * * &struct drm_master is used to track groups of clients with open - * primary/legacy device nodes. For every &struct drm_file which has had at + * primary device nodes. For every &struct drm_file which has had at * least once successfully became the device master (either through the * SET_MASTER IOCTL, or implicitly through opening the primary device node when * no one else is the current master that time) there exists one &drm_master. @@ -139,7 +138,6 @@ struct drm_master *drm_master_create(struct drm_device *dev) return NULL; kref_init(&master->refcount); - drm_master_legacy_init(master); idr_init_base(&master->magic_map, 1); master->dev = dev; @@ -365,8 +363,6 @@ void drm_master_release(struct drm_file *file_priv) if (!drm_is_current_master_locked(file_priv)) goto out; - drm_legacy_lock_master_cleanup(dev, master); - if (dev->master == file_priv->master) drm_drop_master(dev, file_priv); out: @@ -429,8 +425,6 @@ static void drm_master_destroy(struct kref *kref) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_lease_destroy(master); - drm_legacy_master_rmmaps(dev, master); - idr_destroy(&master->magic_map); idr_destroy(&master->leases); idr_destroy(&master->lessee_idr); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3c835c99daad..243cacb3575c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -48,7 +48,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); MODULE_DESCRIPTION("DRM shared core routines"); @@ -585,8 +584,6 @@ static void drm_fs_inode_free(struct inode *inode) static void drm_dev_init_release(struct drm_device *dev, void *res) { - drm_legacy_ctxbitmap_cleanup(dev); - drm_legacy_remove_map_hash(dev); drm_fs_inode_free(dev->anon_inode); put_device(dev->dev); @@ -597,7 +594,6 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); - drm_legacy_destroy_members(dev); } static int drm_dev_init(struct drm_device *dev, @@ -632,7 +628,6 @@ static int drm_dev_init(struct drm_device *dev, return -EINVAL; } - drm_legacy_init_members(dev); INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->filelist_internal); INIT_LIST_HEAD(&dev->clientlist); @@ -673,12 +668,6 @@ static int drm_dev_init(struct drm_device *dev, goto err; } - ret = drm_legacy_create_map_hash(dev); - if (ret) - goto err; - - drm_legacy_ctxbitmap_init(dev); - if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); if (ret) { @@ -996,9 +985,6 @@ EXPORT_SYMBOL(drm_dev_register); */ void drm_dev_unregister(struct drm_device *dev) { - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_lastclose(dev); - dev->registered = false; drm_client_dev_unregister(dev); @@ -1009,9 +995,6 @@ void drm_dev_unregister(struct drm_device *dev) if (dev->driver->unload) dev->driver->unload(dev); - drm_legacy_pci_agp_destroy(dev); - drm_legacy_rmmaps(dev); - remove_compat_control_link(dev); drm_minor_unregister(dev, DRM_MINOR_ACCEL); drm_minor_unregister(dev, DRM_MINOR_PRIMARY); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 5ddaffd32586..987c1a5d1773 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -47,21 +47,12 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); bool drm_dev_needs_global_mutex(struct drm_device *dev) { - /* - * Legacy drivers rely on all kinds of BKL locking semantics, don't - * bother. They also still need BKL locking for their ioctls, so better - * safe than sorry. - */ - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - return true; - /* * The deprecated ->load callback must be called after the driver is * already registered. This means such drivers rely on the BKL to make @@ -107,9 +98,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) * drm_send_event() as the main starting points. * * The memory mapping implementation will vary depending on how the driver - * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() - * function, modern drivers should use one of the provided memory-manager - * specific implementations. For GEM-based drivers this is drm_gem_mmap(). + * manages memory. For GEM-based drivers this is drm_gem_mmap(). * * No other file operations are supported by the DRM userspace API. Overall the * following is an example &file_operations structure:: @@ -254,18 +243,6 @@ void drm_file_free(struct drm_file *file) (long)old_encode_dev(file->minor->kdev->devt), atomic_read(&dev->open_count)); -#ifdef CONFIG_DRM_LEGACY - if (drm_core_check_feature(dev, DRIVER_LEGACY) && - dev->driver->preclose) - dev->driver->preclose(dev, file); -#endif - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_legacy_lock_release(dev, file->filp); - - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - drm_legacy_reclaim_buffers(dev, file); - drm_events_release(file); if (drm_core_check_feature(dev, DRIVER_MODESET)) { @@ -279,8 +256,6 @@ void drm_file_free(struct drm_file *file) if (drm_core_check_feature(dev, DRIVER_GEM)) drm_gem_release(dev, file); - drm_legacy_ctxbitmap_flush(dev, file); - if (drm_is_primary_client(file)) drm_master_release(file); @@ -367,29 +342,6 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor) list_add(&priv->lhead, &dev->filelist); mutex_unlock(&dev->filelist_mutex); -#ifdef CONFIG_DRM_LEGACY -#ifdef __alpha__ - /* - * Default the hose - */ - if (!dev->hose) { - struct pci_dev *pci_dev; - - pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); - if (pci_dev) { - dev->hose = pci_dev->sysdata; - pci_dev_put(pci_dev); - } - if (!dev->hose) { - struct pci_bus *b = list_entry(pci_root_buses.next, - struct pci_bus, node); - if (b) - dev->hose = b->sysdata; - } - } -#endif -#endif - return 0; } @@ -411,7 +363,6 @@ int drm_open(struct inode *inode, struct file *filp) struct drm_device *dev; struct drm_minor *minor; int retcode; - int need_setup = 0; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) @@ -421,8 +372,7 @@ int drm_open(struct inode *inode, struct file *filp) if (drm_dev_needs_global_mutex(dev)) mutex_lock(&drm_global_mutex); - if (!atomic_fetch_inc(&dev->open_count)) - need_setup = 1; + atomic_fetch_inc(&dev->open_count); /* share address_space across all char-devs of a single device */ filp->f_mapping = dev->anon_inode->i_mapping; @@ -430,13 +380,6 @@ int drm_open(struct inode *inode, struct file *filp) retcode = drm_open_helper(filp, minor); if (retcode) goto err_undo; - if (need_setup) { - retcode = drm_legacy_setup(dev); - if (retcode) { - drm_close_helper(filp); - goto err_undo; - } - } if (drm_dev_needs_global_mutex(dev)) mutex_unlock(&drm_global_mutex); @@ -460,9 +403,6 @@ void drm_lastclose(struct drm_device * dev) dev->driver->lastclose(dev); drm_dbg_core(dev, "driver lastclose completed\n"); - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_legacy_dev_reinit(dev); - drm_client_dev_restore(dev); } diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index a11f164b2384..702a12bc93bd 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -210,11 +210,6 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->get_vblank_counter) return crtc->funcs->get_vblank_counter(crtc); } -#ifdef CONFIG_DRM_LEGACY - else if (dev->driver->get_vblank_counter) { - return dev->driver->get_vblank_counter(dev, pipe); - } -#endif return drm_vblank_no_hw_counter(dev, pipe); } @@ -433,11 +428,6 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->disable_vblank) crtc->funcs->disable_vblank(crtc); } -#ifdef CONFIG_DRM_LEGACY - else { - dev->driver->disable_vblank(dev, pipe); - } -#endif } /* @@ -1151,11 +1141,6 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->enable_vblank) return crtc->funcs->enable_vblank(crtc); } -#ifdef CONFIG_DRM_LEGACY - else if (dev->driver->enable_vblank) { - return dev->driver->enable_vblank(dev, pipe); - } -#endif return -EINVAL; } @@ -1698,10 +1683,6 @@ static void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe, static bool drm_wait_vblank_supported(struct drm_device *dev) { -#if IS_ENABLED(CONFIG_DRM_LEGACY) - if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY))) - return dev->irq_enabled; -#endif return drm_dev_has_vblank(dev); } From 2798ffcc1d6a788b5769b1fbcf0750dfc06ae98a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:40 +0100 Subject: [PATCH 2753/7721] drm: Remove locking for legacy ioctls and DRM_UNLOCKED Modern DRM drivers acquire ioctl locks by themselves. Legacy ioctls for user-space mode setting used to acquire drm_global_mutex. After removing the ioctl entry points, also remove the locking code. The only legacy ioctl without global locking was VBLANK_WAIT, which has been removed as well. Hence remove the related DRM_UNLOCKED flag. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-12-tzimmermann@suse.de --- drivers/gpu/drm/drm_ioc32.c | 2 +- drivers/gpu/drm/drm_ioctl.c | 21 ++++++--------------- include/drm/drm_ioctl.h | 11 ----------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 910cadf14756..129e2b91dbfe 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -273,7 +273,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, req.request.type = req32.request.type; req.request.sequence = req32.request.sequence; req.request.signal = req32.request.signal; - err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED); + err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, 0); req32.reply.type = req.reply.type; req32.reply.sequence = req.reply.sequence; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index ebba34ba734e..e368fc084c77 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -596,7 +596,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -729,7 +729,7 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, { struct drm_file *file_priv = file->private_data; struct drm_device *dev = file_priv->minor->dev; - int retcode; + int ret; /* Update drm_file owner if fd was passed along. */ drm_file_update_pid(file_priv); @@ -737,20 +737,11 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, if (drm_dev_is_unplugged(dev)) return -ENODEV; - retcode = drm_ioctl_permit(flags, file_priv); - if (unlikely(retcode)) - return retcode; + ret = drm_ioctl_permit(flags, file_priv); + if (unlikely(ret)) + return ret; - /* Enforce sane locking for modern driver ioctls. */ - if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || - (flags & DRM_UNLOCKED)) - retcode = func(dev, kdata, file_priv); - else { - mutex_lock(&drm_global_mutex); - retcode = func(dev, kdata, file_priv); - mutex_unlock(&drm_global_mutex); - } - return retcode; + return func(dev, kdata, file_priv); } EXPORT_SYMBOL(drm_ioctl_kernel); diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h index 6ed61c371f6c..171760b6c4a1 100644 --- a/include/drm/drm_ioctl.h +++ b/include/drm/drm_ioctl.h @@ -109,17 +109,6 @@ enum drm_ioctl_flags { * This is equivalent to callers with the SYSADMIN capability. */ DRM_ROOT_ONLY = BIT(2), - /** - * @DRM_UNLOCKED: - * - * Whether &drm_ioctl_desc.func should be called with the DRM BKL held - * or not. Enforced as the default for all modern drivers, hence there - * should never be a need to set this flag. - * - * Do not use anywhere else than for the VBLANK_WAIT IOCTL, which is the - * only legacy IOCTL which needs this. - */ - DRM_UNLOCKED = BIT(4), /** * @DRM_RENDER_ALLOW: * From 2504c7ec728b7a2b6ca067e2a908fd1af2aad57c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:41 +0100 Subject: [PATCH 2754/7721] drm: Remove source code for non-KMS drivers Remove all remaining source code for non-KMS drivers. These drivers have been removed in v6.3 and won't comeback. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-13-tzimmermann@suse.de --- drivers/gpu/drm/Makefile | 12 - drivers/gpu/drm/drm_agpsupport.c | 451 -------- drivers/gpu/drm/drm_bufs.c | 1627 ----------------------------- drivers/gpu/drm/drm_context.c | 513 --------- drivers/gpu/drm/drm_dma.c | 178 ---- drivers/gpu/drm/drm_hashtab.c | 203 ---- drivers/gpu/drm/drm_internal.h | 5 - drivers/gpu/drm/drm_irq.c | 204 ---- drivers/gpu/drm/drm_legacy.h | 290 ----- drivers/gpu/drm/drm_legacy_misc.c | 105 -- drivers/gpu/drm/drm_lock.c | 373 ------- drivers/gpu/drm/drm_memory.c | 138 --- drivers/gpu/drm/drm_pci.c | 203 ---- drivers/gpu/drm/drm_scatter.c | 220 ---- drivers/gpu/drm/drm_vm.c | 665 ------------ include/drm/drm_auth.h | 22 - include/drm/drm_device.h | 71 +- include/drm/drm_drv.h | 19 - include/drm/drm_file.h | 5 - include/drm/drm_legacy.h | 331 ------ 20 files changed, 2 insertions(+), 5633 deletions(-) delete mode 100644 drivers/gpu/drm/drm_agpsupport.c delete mode 100644 drivers/gpu/drm/drm_bufs.c delete mode 100644 drivers/gpu/drm/drm_context.c delete mode 100644 drivers/gpu/drm/drm_dma.c delete mode 100644 drivers/gpu/drm/drm_hashtab.c delete mode 100644 drivers/gpu/drm/drm_irq.c delete mode 100644 drivers/gpu/drm/drm_legacy.h delete mode 100644 drivers/gpu/drm/drm_legacy_misc.c delete mode 100644 drivers/gpu/drm/drm_lock.c delete mode 100644 drivers/gpu/drm/drm_memory.c delete mode 100644 drivers/gpu/drm/drm_scatter.c delete mode 100644 drivers/gpu/drm/drm_vm.c delete mode 100644 include/drm/drm_legacy.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index b4cb0835620a..8ac6f4b9546e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -47,18 +47,6 @@ drm-y := \ drm_vblank_work.o \ drm_vma_manager.o \ drm_writeback.o -drm-$(CONFIG_DRM_LEGACY) += \ - drm_agpsupport.o \ - drm_bufs.o \ - drm_context.o \ - drm_dma.o \ - drm_hashtab.o \ - drm_irq.o \ - drm_legacy_misc.o \ - drm_lock.o \ - drm_memory.o \ - drm_scatter.o \ - drm_vm.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c deleted file mode 100644 index a4ad6fd13abc..000000000000 --- a/drivers/gpu/drm/drm_agpsupport.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * \file drm_agpsupport.c - * DRM support for AGP/GART backend - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#if IS_ENABLED(CONFIG_AGP) -#include -#endif - -#include -#include -#include -#include - -#include "drm_legacy.h" - -#if IS_ENABLED(CONFIG_AGP) - -/* - * Get AGP information. - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been initialized and acquired and fills in the - * drm_agp_info structure with the information in drm_agp_head::agp_info. - */ -int drm_legacy_agp_info(struct drm_device *dev, struct drm_agp_info *info) -{ - struct agp_kern_info *kern; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - - kern = &dev->agp->agp_info; - info->agp_version_major = kern->version.major; - info->agp_version_minor = kern->version.minor; - info->mode = kern->mode; - info->aperture_base = kern->aper_base; - info->aperture_size = kern->aper_size * 1024 * 1024; - info->memory_allowed = kern->max_memory << PAGE_SHIFT; - info->memory_used = kern->current_memory << PAGE_SHIFT; - info->id_vendor = kern->device->vendor; - info->id_device = kern->device->device; - - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_info); - -int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_info *info = data; - int err; - - err = drm_legacy_agp_info(dev, info); - if (err) - return err; - - return 0; -} - -/* - * Acquire the AGP device. - * - * \param dev DRM device that is to acquire AGP. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device hasn't been acquired before and calls - * \c agp_backend_acquire. - */ -int drm_legacy_agp_acquire(struct drm_device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - - if (!dev->agp) - return -ENODEV; - if (dev->agp->acquired) - return -EBUSY; - dev->agp->bridge = agp_backend_acquire(pdev); - if (!dev->agp->bridge) - return -ENODEV; - dev->agp->acquired = 1; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_acquire); - -/* - * Acquire the AGP device (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device hasn't been acquired before and calls - * \c agp_backend_acquire. - */ -int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return drm_legacy_agp_acquire((struct drm_device *)file_priv->minor->dev); -} - -/* - * Release the AGP device. - * - * \param dev DRM device that is to release AGP. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been acquired and calls \c agp_backend_release. - */ -int drm_legacy_agp_release(struct drm_device *dev) -{ - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - agp_backend_release(dev->agp->bridge); - dev->agp->acquired = 0; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_release); - -int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return drm_legacy_agp_release(dev); -} - -/* - * Enable the AGP bus. - * - * \param dev DRM device that has previously acquired AGP. - * \param mode Requested AGP mode. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been acquired but not enabled, and calls - * \c agp_enable. - */ -int drm_legacy_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) -{ - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - - dev->agp->mode = mode.mode; - agp_enable(dev->agp->bridge, mode.mode); - dev->agp->enabled = 1; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_enable); - -int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_mode *mode = data; - - return drm_legacy_agp_enable(dev, *mode); -} - -/* - * Allocate AGP memory. - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired, allocates the - * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it. - */ -int drm_legacy_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) -{ - struct drm_agp_mem *entry; - struct agp_memory *memory; - unsigned long pages; - u32 type; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - pages = DIV_ROUND_UP(request->size, PAGE_SIZE); - type = (u32) request->type; - memory = agp_allocate_memory(dev->agp->bridge, pages, type); - if (!memory) { - kfree(entry); - return -ENOMEM; - } - - entry->handle = (unsigned long)memory->key + 1; - entry->memory = memory; - entry->bound = 0; - entry->pages = pages; - list_add(&entry->head, &dev->agp->memory); - - request->handle = entry->handle; - request->physical = memory->physical; - - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_alloc); - - -int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_buffer *request = data; - - return drm_legacy_agp_alloc(dev, request); -} - -/* - * Search for the AGP memory entry associated with a handle. - * - * \param dev DRM device structure. - * \param handle AGP memory handle. - * \return pointer to the drm_agp_mem structure associated with \p handle. - * - * Walks through drm_agp_head::memory until finding a matching handle. - */ -static struct drm_agp_mem *drm_legacy_agp_lookup_entry(struct drm_device *dev, - unsigned long handle) -{ - struct drm_agp_mem *entry; - - list_for_each_entry(entry, &dev->agp->memory, head) { - if (entry->handle == handle) - return entry; - } - return NULL; -} - -/* - * Unbind AGP memory from the GATT (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and acquired, looks-up the AGP memory - * entry and passes it to the unbind_agp() function. - */ -int drm_legacy_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) -{ - struct drm_agp_mem *entry; - int ret; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry || !entry->bound) - return -EINVAL; - ret = agp_unbind_memory(entry->memory); - if (ret == 0) - entry->bound = 0; - return ret; -} -EXPORT_SYMBOL(drm_legacy_agp_unbind); - - -int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_binding *request = data; - - return drm_legacy_agp_unbind(dev, request); -} - -/* - * Bind AGP memory into the GATT (ioctl) - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired and that no memory - * is currently bound into the GATT. Looks-up the AGP memory entry and passes - * it to bind_agp() function. - */ -int drm_legacy_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) -{ - struct drm_agp_mem *entry; - int retcode; - int page; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry || entry->bound) - return -EINVAL; - page = DIV_ROUND_UP(request->offset, PAGE_SIZE); - retcode = agp_bind_memory(entry->memory, page); - if (retcode) - return retcode; - entry->bound = dev->agp->base + (page << PAGE_SHIFT); - DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", - dev->agp->base, entry->bound); - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_bind); - - -int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_binding *request = data; - - return drm_legacy_agp_bind(dev, request); -} - -/* - * Free AGP memory (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired and looks up the - * AGP memory entry. If the memory is currently bound, unbind it via - * unbind_agp(). Frees it via free_agp() as well as the entry itself - * and unlinks from the doubly linked list it's inserted in. - */ -int drm_legacy_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) -{ - struct drm_agp_mem *entry; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry) - return -EINVAL; - if (entry->bound) - agp_unbind_memory(entry->memory); - - list_del(&entry->head); - - agp_free_memory(entry->memory); - kfree(entry); - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_free); - - -int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_buffer *request = data; - - return drm_legacy_agp_free(dev, request); -} - -/* - * Initialize the AGP resources. - * - * \return pointer to a drm_agp_head structure. - * - * Gets the drm_agp_t structure which is made available by the agpgart module - * via the inter_module_* functions. Creates and initializes a drm_agp_head - * structure. - * - * Note that final cleanup of the kmalloced structure is directly done in - * drm_pci_agp_destroy. - */ -struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - struct drm_agp_head *head = NULL; - - head = kzalloc(sizeof(*head), GFP_KERNEL); - if (!head) - return NULL; - head->bridge = agp_find_bridge(pdev); - if (!head->bridge) { - head->bridge = agp_backend_acquire(pdev); - if (!head->bridge) { - kfree(head); - return NULL; - } - agp_copy_info(head->bridge, &head->agp_info); - agp_backend_release(head->bridge); - } else { - agp_copy_info(head->bridge, &head->agp_info); - } - if (head->agp_info.chipset == NOT_SUPPORTED) { - kfree(head); - return NULL; - } - INIT_LIST_HEAD(&head->memory); - head->cant_use_aperture = head->agp_info.cant_use_aperture; - head->page_mask = head->agp_info.page_mask; - head->base = head->agp_info.aper_base; - return head; -} -/* Only exported for i810.ko */ -EXPORT_SYMBOL(drm_legacy_agp_init); - -/** - * drm_legacy_agp_clear - Clear AGP resource list - * @dev: DRM device - * - * Iterate over all AGP resources and remove them. But keep the AGP head - * intact so it can still be used. It is safe to call this if AGP is disabled or - * was already removed. - * - * Cleanup is only done for drivers who have DRIVER_LEGACY set. - */ -void drm_legacy_agp_clear(struct drm_device *dev) -{ - struct drm_agp_mem *entry, *tempe; - - if (!dev->agp) - return; - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) { - if (entry->bound) - agp_unbind_memory(entry->memory); - agp_free_memory(entry->memory); - kfree(entry); - } - INIT_LIST_HEAD(&dev->agp->memory); - - if (dev->agp->acquired) - drm_legacy_agp_release(dev); - - dev->agp->acquired = 0; - dev->agp->enabled = 0; -} - -#endif diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c deleted file mode 100644 index 86700560fea2..000000000000 --- a/drivers/gpu/drm/drm_bufs.c +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * Legacy: Generic DRM Buffer Management - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Author: Rickard E. (Rik) Faith - * Author: Gareth Hughes - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "drm_legacy.h" - - -static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, - struct drm_local_map *map) -{ - struct drm_map_list *entry; - - list_for_each_entry(entry, &dev->maplist, head) { - /* - * Because the kernel-userspace ABI is fixed at a 32-bit offset - * while PCI resources may live above that, we only compare the - * lower 32 bits of the map offset for maps of type - * _DRM_FRAMEBUFFER or _DRM_REGISTERS. - * It is assumed that if a driver have more than one resource - * of each type, the lower 32 bits are different. - */ - if (!entry->map || - map->type != entry->map->type || - entry->master != dev->master) - continue; - switch (map->type) { - case _DRM_SHM: - if (map->flags != _DRM_CONTAINS_LOCK) - break; - return entry; - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: - if ((entry->map->offset & 0xffffffff) == - (map->offset & 0xffffffff)) - return entry; - break; - default: /* Make gcc happy */ - break; - } - if (entry->map->offset == map->offset) - return entry; - } - - return NULL; -} - -static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, - unsigned long user_token, int hashed_handle, int shm) -{ - int use_hashed_handle, shift; - unsigned long add; - -#if (BITS_PER_LONG == 64) - use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); -#elif (BITS_PER_LONG == 32) - use_hashed_handle = hashed_handle; -#else -#error Unsupported long size. Neither 64 nor 32 bits. -#endif - - if (!use_hashed_handle) { - int ret; - - hash->key = user_token >> PAGE_SHIFT; - ret = drm_ht_insert_item(&dev->map_hash, hash); - if (ret != -EINVAL) - return ret; - } - - shift = 0; - add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT; - if (shm && (SHMLBA > PAGE_SIZE)) { - int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1; - - /* For shared memory, we have to preserve the SHMLBA - * bits of the eventual vma->vm_pgoff value during - * mmap(). Otherwise we run into cache aliasing problems - * on some platforms. On these platforms, the pgoff of - * a mmap() request is used to pick a suitable virtual - * address for the mmap() region such that it will not - * cause cache aliasing problems. - * - * Therefore, make sure the SHMLBA relevant bits of the - * hash value we use are equal to those in the original - * kernel virtual address. - */ - shift = bits; - add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL)); - } - - return drm_ht_just_insert_please(&dev->map_hash, hash, - user_token, 32 - PAGE_SHIFT - 3, - shift, add); -} - -/* - * Core function to create a range of memory available for mapping by a - * non-root process. - * - * Adjusts the memory offset to its absolute value according to the mapping - * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where - * applicable and if supported by the kernel. - */ -static int drm_addmap_core(struct drm_device *dev, resource_size_t offset, - unsigned int size, enum drm_map_type type, - enum drm_map_flags flags, - struct drm_map_list **maplist) -{ - struct drm_local_map *map; - struct drm_map_list *list; - unsigned long user_token; - int ret; - - map = kmalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - - map->offset = offset; - map->size = size; - map->flags = flags; - map->type = type; - - /* Only allow shared memory to be removable since we only keep enough - * book keeping information about shared memory to allow for removal - * when processes fork. - */ - if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { - kfree(map); - return -EINVAL; - } - DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", - (unsigned long long)map->offset, map->size, map->type); - - /* page-align _DRM_SHM maps. They are allocated here so there is no security - * hole created by that and it works around various broken drivers that use - * a non-aligned quantity to map the SAREA. --BenH - */ - if (map->type == _DRM_SHM) - map->size = PAGE_ALIGN(map->size); - - if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) { - kfree(map); - return -EINVAL; - } - map->mtrr = -1; - map->handle = NULL; - - switch (map->type) { - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: -#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) - if (map->offset + (map->size-1) < map->offset || - map->offset < virt_to_phys(high_memory)) { - kfree(map); - return -EINVAL; - } -#endif - /* Some drivers preinitialize some maps, without the X Server - * needing to be aware of it. Therefore, we just return success - * when the server tries to create a duplicate map. - */ - list = drm_find_matching_map(dev, map); - if (list != NULL) { - if (list->map->size != map->size) { - DRM_DEBUG("Matching maps of type %d with " - "mismatched sizes, (%ld vs %ld)\n", - map->type, map->size, - list->map->size); - list->map->size = map->size; - } - - kfree(map); - *maplist = list; - return 0; - } - - if (map->type == _DRM_FRAME_BUFFER || - (map->flags & _DRM_WRITE_COMBINING)) { - map->mtrr = - arch_phys_wc_add(map->offset, map->size); - } - if (map->type == _DRM_REGISTERS) { - if (map->flags & _DRM_WRITE_COMBINING) - map->handle = ioremap_wc(map->offset, - map->size); - else - map->handle = ioremap(map->offset, map->size); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - } - - break; - case _DRM_SHM: - list = drm_find_matching_map(dev, map); - if (list != NULL) { - if (list->map->size != map->size) { - DRM_DEBUG("Matching maps of type %d with " - "mismatched sizes, (%ld vs %ld)\n", - map->type, map->size, list->map->size); - list->map->size = map->size; - } - - kfree(map); - *maplist = list; - return 0; - } - map->handle = vmalloc_user(map->size); - DRM_DEBUG("%lu %d %p\n", - map->size, order_base_2(map->size), map->handle); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - map->offset = (unsigned long)map->handle; - if (map->flags & _DRM_CONTAINS_LOCK) { - /* Prevent a 2nd X Server from creating a 2nd lock */ - if (dev->master->lock.hw_lock != NULL) { - vfree(map->handle); - kfree(map); - return -EBUSY; - } - dev->sigdata.lock = dev->master->lock.hw_lock = map->handle; /* Pointer to lock */ - } - break; - case _DRM_AGP: { - struct drm_agp_mem *entry; - int valid = 0; - - if (!dev->agp) { - kfree(map); - return -EINVAL; - } -#ifdef __alpha__ - map->offset += dev->hose->mem_space->start; -#endif - /* In some cases (i810 driver), user space may have already - * added the AGP base itself, because dev->agp->base previously - * only got set during AGP enable. So, only add the base - * address if the map's offset isn't already within the - * aperture. - */ - if (map->offset < dev->agp->base || - map->offset > dev->agp->base + - dev->agp->agp_info.aper_size * 1024 * 1024 - 1) { - map->offset += dev->agp->base; - } - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ - - /* This assumes the DRM is in total control of AGP space. - * It's not always the case as AGP can be in the control - * of user space (i.e. i810 driver). So this loop will get - * skipped and we double check that dev->agp->memory is - * actually set as well as being invalid before EPERM'ing - */ - list_for_each_entry(entry, &dev->agp->memory, head) { - if ((map->offset >= entry->bound) && - (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { - valid = 1; - break; - } - } - if (!list_empty(&dev->agp->memory) && !valid) { - kfree(map); - return -EPERM; - } - DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n", - (unsigned long long)map->offset, map->size); - - break; - } - case _DRM_SCATTER_GATHER: - if (!dev->sg) { - kfree(map); - return -EINVAL; - } - map->offset += (unsigned long)dev->sg->virtual; - break; - case _DRM_CONSISTENT: - /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, - * As we're limiting the address to 2^32-1 (or less), - * casting it down to 32 bits is no problem, but we - * need to point to a 64bit variable first. - */ - map->handle = dma_alloc_coherent(dev->dev, - map->size, - &map->offset, - GFP_KERNEL); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - break; - default: - kfree(map); - return -EINVAL; - } - - list = kzalloc(sizeof(*list), GFP_KERNEL); - if (!list) { - if (map->type == _DRM_REGISTERS) - iounmap(map->handle); - kfree(map); - return -EINVAL; - } - list->map = map; - - mutex_lock(&dev->struct_mutex); - list_add(&list->head, &dev->maplist); - - /* Assign a 32-bit handle */ - /* We do it here so that dev->struct_mutex protects the increment */ - user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle : - map->offset; - ret = drm_map_handle(dev, &list->hash, user_token, 0, - (map->type == _DRM_SHM)); - if (ret) { - if (map->type == _DRM_REGISTERS) - iounmap(map->handle); - kfree(map); - kfree(list); - mutex_unlock(&dev->struct_mutex); - return ret; - } - - list->user_token = list->hash.key << PAGE_SHIFT; - mutex_unlock(&dev->struct_mutex); - - if (!(map->flags & _DRM_DRIVER)) - list->master = dev->master; - *maplist = list; - return 0; -} - -int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset, - unsigned int size, enum drm_map_type type, - enum drm_map_flags flags, struct drm_local_map **map_ptr) -{ - struct drm_map_list *list; - int rc; - - rc = drm_addmap_core(dev, offset, size, type, flags, &list); - if (!rc) - *map_ptr = list->map; - return rc; -} -EXPORT_SYMBOL(drm_legacy_addmap); - -struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, - unsigned int token) -{ - struct drm_map_list *_entry; - - list_for_each_entry(_entry, &dev->maplist, head) - if (_entry->user_token == token) - return _entry->map; - return NULL; -} -EXPORT_SYMBOL(drm_legacy_findmap); - -/* - * Ioctl to specify a range of memory that is available for mapping by a - * non-root process. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_map structure. - * \return zero on success or a negative value on error. - * - */ -int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *map = data; - struct drm_map_list *maplist; - int err; - - if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM)) - return -EPERM; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - err = drm_addmap_core(dev, map->offset, map->size, map->type, - map->flags, &maplist); - - if (err) - return err; - - /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ - map->handle = (void *)(unsigned long)maplist->user_token; - - /* - * It appears that there are no users of this value whatsoever -- - * drmAddMap just discards it. Let's not encourage its use. - * (Keeping drm_addmap_core's returned mtrr value would be wrong -- - * it's not a real mtrr index anymore.) - */ - map->mtrr = -1; - - return 0; -} - -/* - * Get a mapping information. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_map structure. - * - * \return zero on success or a negative number on failure. - * - * Searches for the mapping with the specified offset and copies its information - * into userspace - */ -int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *map = data; - struct drm_map_list *r_list = NULL; - struct list_head *list; - int idx; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - idx = map->offset; - if (idx < 0) - return -EINVAL; - - i = 0; - mutex_lock(&dev->struct_mutex); - list_for_each(list, &dev->maplist) { - if (i == idx) { - r_list = list_entry(list, struct drm_map_list, head); - break; - } - i++; - } - if (!r_list || !r_list->map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - map->offset = r_list->map->offset; - map->size = r_list->map->size; - map->type = r_list->map->type; - map->flags = r_list->map->flags; - map->handle = (void *)(unsigned long) r_list->user_token; - map->mtrr = arch_phys_wc_index(r_list->map->mtrr); - - mutex_unlock(&dev->struct_mutex); - - return 0; -} - -/* - * Remove a map private from list and deallocate resources if the mapping - * isn't in use. - * - * Searches the map on drm_device::maplist, removes it from the list, see if - * it's being used, and free any associated resource (such as MTRR's) if it's not - * being on use. - * - * \sa drm_legacy_addmap - */ -int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) -{ - struct drm_map_list *r_list = NULL, *list_t; - int found = 0; - struct drm_master *master; - - /* Find the list entry for the map and remove it */ - list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { - if (r_list->map == map) { - master = r_list->master; - list_del(&r_list->head); - drm_ht_remove_key(&dev->map_hash, - r_list->user_token >> PAGE_SHIFT); - kfree(r_list); - found = 1; - break; - } - } - - if (!found) - return -EINVAL; - - switch (map->type) { - case _DRM_REGISTERS: - iounmap(map->handle); - fallthrough; - case _DRM_FRAME_BUFFER: - arch_phys_wc_del(map->mtrr); - break; - case _DRM_SHM: - vfree(map->handle); - if (master) { - if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; /* SHM removed */ - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - break; - case _DRM_AGP: - case _DRM_SCATTER_GATHER: - break; - case _DRM_CONSISTENT: - dma_free_coherent(dev->dev, - map->size, - map->handle, - map->offset); - break; - } - kfree(map); - - return 0; -} -EXPORT_SYMBOL(drm_legacy_rmmap_locked); - -void drm_legacy_rmmap(struct drm_device *dev, struct drm_local_map *map) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - drm_legacy_rmmap_locked(dev, map); - mutex_unlock(&dev->struct_mutex); -} -EXPORT_SYMBOL(drm_legacy_rmmap); - -void drm_legacy_master_rmmaps(struct drm_device *dev, struct drm_master *master) -{ - struct drm_map_list *r_list, *list_temp; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { - if (r_list->master == master) { - drm_legacy_rmmap_locked(dev, r_list->map); - r_list = NULL; - } - } - mutex_unlock(&dev->struct_mutex); -} - -void drm_legacy_rmmaps(struct drm_device *dev) -{ - struct drm_map_list *r_list, *list_temp; - - list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) - drm_legacy_rmmap(dev, r_list->map); -} - -/* The rmmap ioctl appears to be unnecessary. All mappings are torn down on - * the last close of the device, and this is necessary for cleanup when things - * exit uncleanly. Therefore, having userland manually remove mappings seems - * like a pointless exercise since they're going away anyway. - * - * One use case might be after addmap is allowed for normal users for SHM and - * gets used by drivers that the server doesn't need to care about. This seems - * unlikely. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a struct drm_map structure. - * \return zero on success or a negative value on error. - */ -int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *request = data; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map && - r_list->user_token == (unsigned long)request->handle && - r_list->map->flags & _DRM_REMOVABLE) { - map = r_list->map; - break; - } - } - - /* List has wrapped around to the head pointer, or it's empty we didn't - * find anything. - */ - if (list_empty(&dev->maplist) || !map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - /* Register and framebuffer maps are permanent */ - if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { - mutex_unlock(&dev->struct_mutex); - return 0; - } - - ret = drm_legacy_rmmap_locked(dev, map); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -/* - * Cleanup after an error on one of the addbufs() functions. - * - * \param dev DRM device. - * \param entry buffer entry where the error occurred. - * - * Frees any pages and buffers associated with the given entry. - */ -static void drm_cleanup_buf_error(struct drm_device *dev, - struct drm_buf_entry *entry) -{ - drm_dma_handle_t *dmah; - int i; - - if (entry->seg_count) { - for (i = 0; i < entry->seg_count; i++) { - if (entry->seglist[i]) { - dmah = entry->seglist[i]; - dma_free_coherent(dev->dev, - dmah->size, - dmah->vaddr, - dmah->busaddr); - kfree(dmah); - } - } - kfree(entry->seglist); - - entry->seg_count = 0; - } - - if (entry->buf_count) { - for (i = 0; i < entry->buf_count; i++) { - kfree(entry->buflist[i].dev_private); - } - kfree(entry->buflist); - - entry->buf_count = 0; - } -} - -#if IS_ENABLED(CONFIG_AGP) -/* - * Add AGP buffers for DMA transfers. - * - * \param dev struct drm_device to which the buffers are to be added. - * \param request pointer to a struct drm_buf_desc describing the request. - * \return zero on success or a negative number on failure. - * - * After some sanity checks creates a drm_buf structure for each buffer and - * reallocates the buffer list of the same size order to accommodate the new - * buffers. - */ -int drm_legacy_addbufs_agp(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_entry *entry; - struct drm_agp_mem *agp_entry; - struct drm_buf *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i, valid; - struct drm_buf **temp_buflist; - - if (!dma) - return -EINVAL; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - byte_count = 0; - agp_offset = dev->agp->base + request->agp_start; - - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %lx\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - /* Make sure buffers are located in AGP memory that we own */ - valid = 0; - list_for_each_entry(agp_entry, &dev->agp->memory, head) { - if ((agp_offset >= agp_entry->bound) && - (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { - valid = 1; - break; - } - } - if (!list_empty(&dev->agp->memory) && !valid) { - DRM_DEBUG("zone invalid\n"); - return -EINVAL; - } - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->buf_size = size; - entry->page_order = page_order; - - offset = 0; - - while (entry->buf_count < count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - - buf->offset = (dma->byte_count + offset); - buf->bus_address = agp_offset + offset; - buf->address = (void *)(agp_offset + offset); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); - - offset += alignment; - entry->buf_count++; - byte_count += PAGE_SIZE << page_order; - } - - DRM_DEBUG("byte_count: %d\n", byte_count); - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += byte_count >> PAGE_SHIFT; - dma->byte_count += byte_count; - - DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); - DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - dma->flags = _DRM_DMA_USE_AGP; - - atomic_dec(&dev->buf_alloc); - return 0; -} -EXPORT_SYMBOL(drm_legacy_addbufs_agp); -#endif /* CONFIG_AGP */ - -int drm_legacy_addbufs_pci(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - int count; - int order; - int size; - int total; - int page_order; - struct drm_buf_entry *entry; - drm_dma_handle_t *dmah; - struct drm_buf *buf; - int alignment; - unsigned long offset; - int i; - int byte_count; - int page_count; - unsigned long *temp_pagelist; - struct drm_buf **temp_buflist; - - if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", - request->count, request->size, size, order); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->seglist = kcalloc(count, sizeof(*entry->seglist), GFP_KERNEL); - if (!entry->seglist) { - kfree(entry->buflist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - /* Keep the original pagelist until we know all the allocations - * have succeeded - */ - temp_pagelist = kmalloc_array(dma->page_count + (count << page_order), - sizeof(*dma->pagelist), - GFP_KERNEL); - if (!temp_pagelist) { - kfree(entry->buflist); - kfree(entry->seglist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memcpy(temp_pagelist, - dma->pagelist, dma->page_count * sizeof(*dma->pagelist)); - DRM_DEBUG("pagelist: %d entries\n", - dma->page_count + (count << page_order)); - - entry->buf_size = size; - entry->page_order = page_order; - byte_count = 0; - page_count = 0; - - while (entry->buf_count < count) { - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); - if (!dmah) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - dmah->size = total; - dmah->vaddr = dma_alloc_coherent(dev->dev, - dmah->size, - &dmah->busaddr, - GFP_KERNEL); - if (!dmah->vaddr) { - kfree(dmah); - - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - entry->seglist[entry->seg_count++] = dmah; - for (i = 0; i < (1 << page_order); i++) { - DRM_DEBUG("page %d @ 0x%08lx\n", - dma->page_count + page_count, - (unsigned long)dmah->vaddr + PAGE_SIZE * i); - temp_pagelist[dma->page_count + page_count++] - = (unsigned long)dmah->vaddr + PAGE_SIZE * i; - } - for (offset = 0; - offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = (dma->byte_count + byte_count + offset); - buf->address = (void *)(dmah->vaddr + offset); - buf->bus_address = dmah->busaddr + offset; - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, - GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } - byte_count += PAGE_SIZE << page_order; - } - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - /* No allocations failed, so now we can replace the original pagelist - * with the new one. - */ - if (dma->page_count) { - kfree(dma->pagelist); - } - dma->pagelist = temp_pagelist; - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += entry->seg_count << page_order; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - if (request->flags & _DRM_PCI_BUFFER_RO) - dma->flags = _DRM_DMA_USE_PCI_RO; - - atomic_dec(&dev->buf_alloc); - return 0; - -} -EXPORT_SYMBOL(drm_legacy_addbufs_pci); - -static int drm_legacy_addbufs_sg(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_entry *entry; - struct drm_buf *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i; - struct drm_buf **temp_buflist; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - byte_count = 0; - agp_offset = request->agp_start; - - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %lu\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->buf_size = size; - entry->page_order = page_order; - - offset = 0; - - while (entry->buf_count < count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - - buf->offset = (dma->byte_count + offset); - buf->bus_address = agp_offset + offset; - buf->address = (void *)(agp_offset + offset - + (unsigned long)dev->sg->virtual); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); - - offset += alignment; - entry->buf_count++; - byte_count += PAGE_SIZE << page_order; - } - - DRM_DEBUG("byte_count: %d\n", byte_count); - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += byte_count >> PAGE_SHIFT; - dma->byte_count += byte_count; - - DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); - DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - dma->flags = _DRM_DMA_USE_SG; - - atomic_dec(&dev->buf_alloc); - return 0; -} - -/* - * Add buffers for DMA transfers (ioctl). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a struct drm_buf_desc request. - * \return zero on success or a negative number on failure. - * - * According with the memory type specified in drm_buf_desc::flags and the - * build options, it dispatches the call either to addbufs_agp(), - * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent - * PCI memory respectively. - */ -int drm_legacy_addbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_desc *request = data; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - -#if IS_ENABLED(CONFIG_AGP) - if (request->flags & _DRM_AGP_BUFFER) - ret = drm_legacy_addbufs_agp(dev, request); - else -#endif - if (request->flags & _DRM_SG_BUFFER) - ret = drm_legacy_addbufs_sg(dev, request); - else if (request->flags & _DRM_FB_BUFFER) - ret = -EINVAL; - else - ret = drm_legacy_addbufs_pci(dev, request); - - return ret; -} - -/* - * Get information about the buffer mappings. - * - * This was originally mean for debugging purposes, or by a sophisticated - * client library to determine how best to use the available buffers (e.g., - * large buffers can be used for image transfer). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_info structure. - * \return zero on success or a negative number on failure. - * - * Increments drm_device::buf_use while holding the drm_device::buf_lock - * lock, preventing of allocating more buffers after this call. Information - * about each requested buffer is then copied into user space. - */ -int __drm_legacy_infobufs(struct drm_device *dev, - void *data, int *p, - int (*f)(void *, int, struct drm_buf_entry *)) -{ - struct drm_device_dma *dma = dev->dma; - int i; - int count; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->buf_lock); - - for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { - if (dma->bufs[i].buf_count) - ++count; - } - - DRM_DEBUG("count = %d\n", count); - - if (*p >= count) { - for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { - struct drm_buf_entry *from = &dma->bufs[i]; - - if (from->buf_count) { - if (f(data, count, from) < 0) - return -EFAULT; - DRM_DEBUG("%d %d %d %d %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].buf_size, - dma->bufs[i].low_mark, - dma->bufs[i].high_mark); - ++count; - } - } - } - *p = count; - - return 0; -} - -static int copy_one_buf(void *data, int count, struct drm_buf_entry *from) -{ - struct drm_buf_info *request = data; - struct drm_buf_desc __user *to = &request->list[count]; - struct drm_buf_desc v = {.count = from->buf_count, - .size = from->buf_size, - .low_mark = from->low_mark, - .high_mark = from->high_mark}; - - if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags))) - return -EFAULT; - return 0; -} - -int drm_legacy_infobufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_info *request = data; - - return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf); -} - -/* - * Specifies a low and high water mark for buffer allocation - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg a pointer to a drm_buf_desc structure. - * \return zero on success or a negative number on failure. - * - * Verifies that the size order is bounded between the admissible orders and - * updates the respective drm_device_dma::bufs entry low and high water mark. - * - * \note This ioctl is deprecated and mostly never used. - */ -int drm_legacy_markbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_desc *request = data; - int order; - struct drm_buf_entry *entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - DRM_DEBUG("%d, %d, %d\n", - request->size, request->low_mark, request->high_mark); - order = order_base_2(request->size); - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - entry = &dma->bufs[order]; - - if (request->low_mark < 0 || request->low_mark > entry->buf_count) - return -EINVAL; - if (request->high_mark < 0 || request->high_mark > entry->buf_count) - return -EINVAL; - - entry->low_mark = request->low_mark; - entry->high_mark = request->high_mark; - - return 0; -} - -/* - * Unreserve the buffers in list, previously reserved using drmDMA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_free structure. - * \return zero on success or a negative number on failure. - * - * Calls free_buffer() for each used buffer. - * This function is primarily used for debugging. - */ -int drm_legacy_freebufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_free *request = data; - int i; - int idx; - struct drm_buf *buf; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - DRM_DEBUG("%d\n", request->count); - for (i = 0; i < request->count; i++) { - if (copy_from_user(&idx, &request->list[i], sizeof(idx))) - return -EFAULT; - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - idx, dma->buf_count - 1); - return -EINVAL; - } - idx = array_index_nospec(idx, dma->buf_count); - buf = dma->buflist[idx]; - if (buf->file_priv != file_priv) { - DRM_ERROR("Process %d freeing buffer not owned\n", - task_pid_nr(current)); - return -EINVAL; - } - drm_legacy_free_buffer(dev, buf); - } - - return 0; -} - -/* - * Maps all of the DMA buffers into client-virtual space (ioctl). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_map structure. - * \return zero on success or a negative number on failure. - * - * Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information - * about each buffer into user space. For PCI buffers, it calls vm_mmap() with - * offset equal to 0, which drm_mmap() interprets as PCI buffers and calls - * drm_mmap_dma(). - */ -int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p, - void __user **v, - int (*f)(void *, int, unsigned long, - struct drm_buf *), - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - int retcode = 0; - unsigned long virtual; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - dev->buf_use++; /* Can't allocate more after this call */ - spin_unlock(&dev->buf_lock); - - if (*p >= dma->buf_count) { - if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) - || (drm_core_check_feature(dev, DRIVER_SG) - && (dma->flags & _DRM_DMA_USE_SG))) { - struct drm_local_map *map = dev->agp_buffer_map; - unsigned long token = dev->agp_buffer_token; - - if (!map) { - retcode = -EINVAL; - goto done; - } - virtual = vm_mmap(file_priv->filp, 0, map->size, - PROT_READ | PROT_WRITE, - MAP_SHARED, - token); - } else { - virtual = vm_mmap(file_priv->filp, 0, dma->byte_count, - PROT_READ | PROT_WRITE, - MAP_SHARED, 0); - } - if (virtual > -1024UL) { - /* Real error */ - retcode = (signed long)virtual; - goto done; - } - *v = (void __user *)virtual; - - for (i = 0; i < dma->buf_count; i++) { - if (f(data, i, virtual, dma->buflist[i]) < 0) { - retcode = -EFAULT; - goto done; - } - } - } - done: - *p = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", *p, retcode); - - return retcode; -} - -static int map_one_buf(void *data, int idx, unsigned long virtual, - struct drm_buf *buf) -{ - struct drm_buf_map *request = data; - unsigned long address = virtual + buf->offset; /* *** */ - - if (copy_to_user(&request->list[idx].idx, &buf->idx, - sizeof(request->list[0].idx))) - return -EFAULT; - if (copy_to_user(&request->list[idx].total, &buf->total, - sizeof(request->list[0].total))) - return -EFAULT; - if (clear_user(&request->list[idx].used, sizeof(int))) - return -EFAULT; - if (copy_to_user(&request->list[idx].address, &address, - sizeof(address))) - return -EFAULT; - return 0; -} - -int drm_legacy_mapbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_map *request = data; - - return __drm_legacy_mapbufs(dev, data, &request->count, - &request->virtual, map_one_buf, - file_priv); -} - -int drm_legacy_dma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (dev->driver->dma_ioctl) - return dev->driver->dma_ioctl(dev, data, file_priv); - else - return -EINVAL; -} - -struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev) -{ - struct drm_map_list *entry; - - list_for_each_entry(entry, &dev->maplist, head) { - if (entry->map && entry->map->type == _DRM_SHM && - (entry->map->flags & _DRM_CONTAINS_LOCK)) { - return entry->map; - } - } - return NULL; -} -EXPORT_SYMBOL(drm_legacy_getsarea); diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c deleted file mode 100644 index a0fc779e5e1e..000000000000 --- a/drivers/gpu/drm/drm_context.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Legacy: Generic DRM Contexts - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Author: Rickard E. (Rik) Faith - * Author: Gareth Hughes - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include -#include -#include - -#include "drm_legacy.h" - -struct drm_ctx_list { - struct list_head head; - drm_context_t handle; - struct drm_file *tag; -}; - -/******************************************************************/ -/** \name Context bitmap support */ -/*@{*/ - -/* - * Free a handle from the context bitmap. - * - * \param dev DRM device. - * \param ctx_handle context handle. - * - * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry - * in drm_device::ctx_idr, while holding the drm_device::struct_mutex - * lock. - */ -void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - idr_remove(&dev->ctx_idr, ctx_handle); - mutex_unlock(&dev->struct_mutex); -} - -/* - * Context bitmap allocation. - * - * \param dev DRM device. - * \return (non-negative) context handle on success or a negative number on failure. - * - * Allocate a new idr from drm_device::ctx_idr while holding the - * drm_device::struct_mutex lock. - */ -static int drm_legacy_ctxbitmap_next(struct drm_device * dev) -{ - int ret; - - mutex_lock(&dev->struct_mutex); - ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0, - GFP_KERNEL); - mutex_unlock(&dev->struct_mutex); - return ret; -} - -/* - * Context bitmap initialization. - * - * \param dev DRM device. - * - * Initialise the drm_device::ctx_idr - */ -void drm_legacy_ctxbitmap_init(struct drm_device * dev) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - idr_init(&dev->ctx_idr); -} - -/* - * Context bitmap cleanup. - * - * \param dev DRM device. - * - * Free all idr members using drm_ctx_sarea_free helper function - * while holding the drm_device::struct_mutex lock. - */ -void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - idr_destroy(&dev->ctx_idr); - mutex_unlock(&dev->struct_mutex); -} - -/** - * drm_legacy_ctxbitmap_flush() - Flush all contexts owned by a file - * @dev: DRM device to operate on - * @file: Open file to flush contexts for - * - * This iterates over all contexts on @dev and drops them if they're owned by - * @file. Note that after this call returns, new contexts might be added if - * the file is still alive. - */ -void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) -{ - struct drm_ctx_list *pos, *tmp; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->ctxlist_mutex); - - list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) { - if (pos->tag == file && - pos->handle != DRM_KERNEL_CONTEXT) { - if (dev->driver->context_dtor) - dev->driver->context_dtor(dev, pos->handle); - - drm_legacy_ctxbitmap_free(dev, pos->handle); - list_del(&pos->head); - kfree(pos); - } - } - - mutex_unlock(&dev->ctxlist_mutex); -} - -/*@}*/ - -/******************************************************************/ -/** \name Per Context SAREA Support */ -/*@{*/ - -/* - * Get per-context SAREA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_priv_map structure. - * \return zero on success or a negative number on failure. - * - * Gets the map from drm_device::ctx_idr with the handle specified and - * returns its handle. - */ -int drm_legacy_getsareactx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_priv_map *request = data; - struct drm_local_map *map; - struct drm_map_list *_entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - - map = idr_find(&dev->ctx_idr, request->ctx_id); - if (!map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - request->handle = NULL; - list_for_each_entry(_entry, &dev->maplist, head) { - if (_entry->map == map) { - request->handle = - (void *)(unsigned long)_entry->user_token; - break; - } - } - - mutex_unlock(&dev->struct_mutex); - - if (request->handle == NULL) - return -EINVAL; - - return 0; -} - -/* - * Set per-context SAREA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_priv_map structure. - * \return zero on success or a negative number on failure. - * - * Searches the mapping specified in \p arg and update the entry in - * drm_device::ctx_idr with it. - */ -int drm_legacy_setsareactx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_priv_map *request = data; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list = NULL; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map - && r_list->user_token == (unsigned long) request->handle) - goto found; - } - bad: - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - - found: - map = r_list->map; - if (!map) - goto bad; - - if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id))) - goto bad; - - mutex_unlock(&dev->struct_mutex); - - return 0; -} - -/*@}*/ - -/******************************************************************/ -/** \name The actual DRM context handling routines */ -/*@{*/ - -/* - * Switch context. - * - * \param dev DRM device. - * \param old old context handle. - * \param new new context handle. - * \return zero on success or a negative number on failure. - * - * Attempt to set drm_device::context_flag. - */ -static int drm_context_switch(struct drm_device * dev, int old, int new) -{ - if (test_and_set_bit(0, &dev->context_flag)) { - DRM_ERROR("Reentering -- FIXME\n"); - return -EBUSY; - } - - DRM_DEBUG("Context switch from %d to %d\n", old, new); - - if (new == dev->last_context) { - clear_bit(0, &dev->context_flag); - return 0; - } - - return 0; -} - -/* - * Complete context switch. - * - * \param dev DRM device. - * \param new new context handle. - * \return zero on success or a negative number on failure. - * - * Updates drm_device::last_context and drm_device::last_switch. Verifies the - * hardware lock is held, clears the drm_device::context_flag and wakes up - * drm_device::context_wait. - */ -static int drm_context_switch_complete(struct drm_device *dev, - struct drm_file *file_priv, int new) -{ - dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ - - if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { - DRM_ERROR("Lock isn't held after context switch\n"); - } - - /* If a context switch is ever initiated - when the kernel holds the lock, release - that lock here. - */ - clear_bit(0, &dev->context_flag); - - return 0; -} - -/* - * Reserve contexts. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_res structure. - * \return zero on success or a negative number on failure. - */ -int drm_legacy_resctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_res *res = data; - struct drm_ctx ctx; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (res->count >= DRM_RESERVED_CONTEXTS) { - memset(&ctx, 0, sizeof(ctx)); - for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { - ctx.handle = i; - if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx))) - return -EFAULT; - } - } - res->count = DRM_RESERVED_CONTEXTS; - - return 0; -} - -/* - * Add context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Get a new handle for the context and copy to userspace. - */ -int drm_legacy_addctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_list *ctx_entry; - struct drm_ctx *ctx = data; - int tmp_handle; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - tmp_handle = drm_legacy_ctxbitmap_next(dev); - if (tmp_handle == DRM_KERNEL_CONTEXT) { - /* Skip kernel's context and get a new one. */ - tmp_handle = drm_legacy_ctxbitmap_next(dev); - } - DRM_DEBUG("%d\n", tmp_handle); - if (tmp_handle < 0) { - DRM_DEBUG("Not enough free contexts.\n"); - /* Should this return -EBUSY instead? */ - return tmp_handle; - } - - ctx->handle = tmp_handle; - - ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL); - if (!ctx_entry) { - DRM_DEBUG("out of memory\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&ctx_entry->head); - ctx_entry->handle = ctx->handle; - ctx_entry->tag = file_priv; - - mutex_lock(&dev->ctxlist_mutex); - list_add(&ctx_entry->head, &dev->ctxlist); - mutex_unlock(&dev->ctxlist_mutex); - - return 0; -} - -/* - * Get context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - */ -int drm_legacy_getctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - /* This is 0, because we don't handle any context flags */ - ctx->flags = 0; - - return 0; -} - -/* - * Switch context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Calls context_switch(). - */ -int drm_legacy_switchctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - return drm_context_switch(dev, dev->last_context, ctx->handle); -} - -/* - * New context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Calls context_switch_complete(). - */ -int drm_legacy_newctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - drm_context_switch_complete(dev, file_priv, ctx->handle); - - return 0; -} - -/* - * Remove context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * If not the special kernel context, calls ctxbitmap_free() to free the specified context. - */ -int drm_legacy_rmctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - if (ctx->handle != DRM_KERNEL_CONTEXT) { - if (dev->driver->context_dtor) - dev->driver->context_dtor(dev, ctx->handle); - drm_legacy_ctxbitmap_free(dev, ctx->handle); - } - - mutex_lock(&dev->ctxlist_mutex); - if (!list_empty(&dev->ctxlist)) { - struct drm_ctx_list *pos, *n; - - list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { - if (pos->handle == ctx->handle) { - list_del(&pos->head); - kfree(pos); - } - } - } - mutex_unlock(&dev->ctxlist_mutex); - - return 0; -} - -/*@}*/ diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c deleted file mode 100644 index eb6b741a6f99..000000000000 --- a/drivers/gpu/drm/drm_dma.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * \file drm_dma.c - * DMA IOCTL and function support - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include -#include - -#include "drm_legacy.h" - -/** - * drm_legacy_dma_setup() - Initialize the DMA data. - * - * @dev: DRM device. - * Return: zero on success or a negative value on failure. - * - * Allocate and initialize a drm_device_dma structure. - */ -int drm_legacy_dma_setup(struct drm_device *dev) -{ - int i; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || - !drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - - dev->buf_use = 0; - atomic_set(&dev->buf_alloc, 0); - - dev->dma = kzalloc(sizeof(*dev->dma), GFP_KERNEL); - if (!dev->dma) - return -ENOMEM; - - for (i = 0; i <= DRM_MAX_ORDER; i++) - memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); - - return 0; -} - -/** - * drm_legacy_dma_takedown() - Cleanup the DMA resources. - * - * @dev: DRM device. - * - * Free all pages associated with DMA buffers, the buffers and pages lists, and - * finally the drm_device::dma structure itself. - */ -void drm_legacy_dma_takedown(struct drm_device *dev) -{ - struct drm_device_dma *dma = dev->dma; - drm_dma_handle_t *dmah; - int i, j; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || - !drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - if (!dma) - return; - - /* Clear dma buffers */ - for (i = 0; i <= DRM_MAX_ORDER; i++) { - if (dma->bufs[i].seg_count) { - DRM_DEBUG("order %d: buf_count = %d," - " seg_count = %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].seg_count); - for (j = 0; j < dma->bufs[i].seg_count; j++) { - if (dma->bufs[i].seglist[j]) { - dmah = dma->bufs[i].seglist[j]; - dma_free_coherent(dev->dev, - dmah->size, - dmah->vaddr, - dmah->busaddr); - kfree(dmah); - } - } - kfree(dma->bufs[i].seglist); - } - if (dma->bufs[i].buf_count) { - for (j = 0; j < dma->bufs[i].buf_count; j++) { - kfree(dma->bufs[i].buflist[j].dev_private); - } - kfree(dma->bufs[i].buflist); - } - } - - kfree(dma->buflist); - kfree(dma->pagelist); - kfree(dev->dma); - dev->dma = NULL; -} - -/** - * drm_legacy_free_buffer() - Free a buffer. - * - * @dev: DRM device. - * @buf: buffer to free. - * - * Resets the fields of \p buf. - */ -void drm_legacy_free_buffer(struct drm_device *dev, struct drm_buf * buf) -{ - if (!buf) - return; - - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - buf->used = 0; -} - -/** - * drm_legacy_reclaim_buffers() - Reclaim the buffers. - * - * @dev: DRM device. - * @file_priv: DRM file private. - * - * Frees each buffer associated with \p file_priv not already on the hardware. - */ -void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - int i; - - if (!dma) - return; - for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->file_priv == file_priv) { - switch (dma->buflist[i]->list) { - case DRM_LIST_NONE: - drm_legacy_free_buffer(dev, dma->buflist[i]); - break; - case DRM_LIST_WAIT: - dma->buflist[i]->list = DRM_LIST_RECLAIM; - break; - default: - /* Buffer already on hardware. */ - break; - } - } - } -} diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c deleted file mode 100644 index 60afa1865559..000000000000 --- a/drivers/gpu/drm/drm_hashtab.c +++ /dev/null @@ -1,203 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * - **************************************************************************/ -/* - * Simple open hash tab implementation. - * - * Authors: - * Thomas Hellström - */ - -#include -#include -#include -#include -#include - -#include - -#include "drm_legacy.h" - -int drm_ht_create(struct drm_open_hash *ht, unsigned int order) -{ - unsigned int size = 1 << order; - - ht->order = order; - ht->table = NULL; - if (size <= PAGE_SIZE / sizeof(*ht->table)) - ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); - else - ht->table = vzalloc(array_size(size, sizeof(*ht->table))); - if (!ht->table) { - DRM_ERROR("Out of memory for hash table\n"); - return -ENOMEM; - } - return 0; -} - -void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - int count = 0; - - hashed_key = hash_long(key, ht->order); - DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) - DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); -} - -static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, - unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht, - unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry_rcu(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - struct hlist_node *parent; - unsigned int hashed_key; - unsigned long key = item->key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - parent = NULL; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return -EINVAL; - if (entry->key > key) - break; - parent = &entry->head; - } - if (parent) { - hlist_add_behind_rcu(&item->head, parent); - } else { - hlist_add_head_rcu(&item->head, h_list); - } - return 0; -} - -/* - * Just insert an item and return any "bits" bit key that hasn't been - * used before. - */ -int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add) -{ - int ret; - unsigned long mask = (1UL << bits) - 1; - unsigned long first, unshifted_key; - - unshifted_key = hash_long(seed, bits); - first = unshifted_key; - do { - item->key = (unshifted_key << shift) + add; - ret = drm_ht_insert_item(ht, item); - if (ret) - unshifted_key = (unshifted_key + 1) & mask; - } while(ret && (unshifted_key != first)); - - if (ret) { - DRM_ERROR("Available key bit space exhausted\n"); - return -EINVAL; - } - return 0; -} - -int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, - struct drm_hash_item **item) -{ - struct hlist_node *list; - - list = drm_ht_find_key_rcu(ht, key); - if (!list) - return -EINVAL; - - *item = hlist_entry(list, struct drm_hash_item, head); - return 0; -} - -int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key) -{ - struct hlist_node *list; - - list = drm_ht_find_key(ht, key); - if (list) { - hlist_del_init_rcu(list); - return 0; - } - return -EINVAL; -} - -int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item) -{ - hlist_del_init_rcu(&item->head); - return 0; -} - -void drm_ht_remove(struct drm_open_hash *ht) -{ - if (ht->table) { - kvfree(ht->table); - ht->table = NULL; - } -} diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index fa08a313127e..8e4faf0a28e6 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -121,11 +121,6 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, /* drm_irq.c */ /* IOCTLS */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_irq_control(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#endif - int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c deleted file mode 100644 index d327638e15ee..000000000000 --- a/drivers/gpu/drm/drm_irq.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * drm_irq.c IRQ and vblank support - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include -#include /* For task queue support */ -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "drm_internal.h" - -static int drm_legacy_irq_install(struct drm_device *dev, int irq) -{ - int ret; - unsigned long sh_flags = 0; - - if (irq == 0) - return -EINVAL; - - if (dev->irq_enabled) - return -EBUSY; - dev->irq_enabled = true; - - DRM_DEBUG("irq=%d\n", irq); - - /* Before installing handler */ - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); - - /* PCI devices require shared interrupts. */ - if (dev_is_pci(dev->dev)) - sh_flags = IRQF_SHARED; - - ret = request_irq(irq, dev->driver->irq_handler, - sh_flags, dev->driver->name, dev); - - if (ret < 0) { - dev->irq_enabled = false; - return ret; - } - - /* After installing handler */ - if (dev->driver->irq_postinstall) - ret = dev->driver->irq_postinstall(dev); - - if (ret < 0) { - dev->irq_enabled = false; - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - vga_client_unregister(to_pci_dev(dev->dev)); - free_irq(irq, dev); - } else { - dev->irq = irq; - } - - return ret; -} - -int drm_legacy_irq_uninstall(struct drm_device *dev) -{ - unsigned long irqflags; - bool irq_enabled; - int i; - - irq_enabled = dev->irq_enabled; - dev->irq_enabled = false; - - /* - * Wake up any waiters so they don't hang. This is just to paper over - * issues for UMS drivers which aren't in full control of their - * vblank/irq handling. KMS drivers must ensure that vblanks are all - * disabled when uninstalling the irq handler. - */ - if (drm_dev_has_vblank(dev)) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for (i = 0; i < dev->num_crtcs; i++) { - struct drm_vblank_crtc *vblank = &dev->vblank[i]; - - if (!vblank->enabled) - continue; - - WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET)); - - drm_vblank_disable_and_save(dev, i); - wake_up(&vblank->queue); - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } - - if (!irq_enabled) - return -EINVAL; - - DRM_DEBUG("irq=%d\n", dev->irq); - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - vga_client_unregister(to_pci_dev(dev->dev)); - - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); - - free_irq(dev->irq, dev); - - return 0; -} -EXPORT_SYMBOL(drm_legacy_irq_uninstall); - -int drm_legacy_irq_control(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_control *ctl = data; - int ret = 0, irq; - struct pci_dev *pdev; - - /* if we haven't irq we fallback for compatibility reasons - - * this used to be a separate function in drm_dma.h - */ - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return 0; - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - /* UMS was only ever supported on pci devices. */ - if (WARN_ON(!dev_is_pci(dev->dev))) - return -EINVAL; - - switch (ctl->func) { - case DRM_INST_HANDLER: - pdev = to_pci_dev(dev->dev); - irq = pdev->irq; - - if (dev->if_version < DRM_IF_VERSION(1, 2) && - ctl->irq != irq) - return -EINVAL; - mutex_lock(&dev->struct_mutex); - ret = drm_legacy_irq_install(dev, irq); - mutex_unlock(&dev->struct_mutex); - - return ret; - case DRM_UNINST_HANDLER: - mutex_lock(&dev->struct_mutex); - ret = drm_legacy_irq_uninstall(dev); - mutex_unlock(&dev->struct_mutex); - - return ret; - default: - return -EINVAL; - } -} diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h deleted file mode 100644 index 70c9dba114a6..000000000000 --- a/drivers/gpu/drm/drm_legacy.h +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef __DRM_LEGACY_H__ -#define __DRM_LEGACY_H__ - -/* - * Copyright (c) 2014 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * This file contains legacy interfaces that modern drm drivers - * should no longer be using. They cannot be removed as legacy - * drivers use them, and removing them are API breaks. - */ -#include - -#include -#include -#include - -struct agp_memory; -struct drm_buf_desc; -struct drm_device; -struct drm_file; -struct drm_hash_item; -struct drm_open_hash; - -/* - * Hash-table Support - */ - -#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) - -/* drm_hashtab.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_ht_create(struct drm_open_hash *ht, unsigned int order); -int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); -int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); - -void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); -int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); -int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); -void drm_ht_remove(struct drm_open_hash *ht); -#endif - -/* - * RCU-safe interface - * - * The user of this API needs to make sure that two or more instances of the - * hash table manipulation functions are never run simultaneously. - * The lookup function drm_ht_find_item_rcu may, however, run simultaneously - * with any of the manipulation functions as long as it's called from within - * an RCU read-locked section. - */ -#define drm_ht_insert_item_rcu drm_ht_insert_item -#define drm_ht_just_insert_please_rcu drm_ht_just_insert_please -#define drm_ht_remove_key_rcu drm_ht_remove_key -#define drm_ht_remove_item_rcu drm_ht_remove_item -#define drm_ht_find_item_rcu drm_ht_find_item - -/* - * Generic DRM Contexts - */ - -#define DRM_KERNEL_CONTEXT 0 -#define DRM_RESERVED_CONTEXTS 1 - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_ctxbitmap_init(struct drm_device *dev); -void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev); -void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file); -#else -static inline void drm_legacy_ctxbitmap_init(struct drm_device *dev) {} -static inline void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev) {} -static inline void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) {} -#endif - -void drm_legacy_ctxbitmap_free(struct drm_device *dev, int ctx_handle); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_resctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_addctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_getctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_switchctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_newctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_rmctx(struct drm_device *d, void *v, struct drm_file *f); - -int drm_legacy_setsareactx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_getsareactx(struct drm_device *d, void *v, struct drm_file *f); -#endif - -/* - * Generic Buffer Management - */ - -#define DRM_MAP_HASH_OFFSET 0x10000000 - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -static inline int drm_legacy_create_map_hash(struct drm_device *dev) -{ - return drm_ht_create(&dev->map_hash, 12); -} - -static inline void drm_legacy_remove_map_hash(struct drm_device *dev) -{ - drm_ht_remove(&dev->map_hash); -} -#else -static inline int drm_legacy_create_map_hash(struct drm_device *dev) -{ - return 0; -} - -static inline void drm_legacy_remove_map_hash(struct drm_device *dev) {} -#endif - - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_addmap_ioctl(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_rmmap_ioctl(struct drm_device *d, void *v, struct drm_file *f); - -int drm_legacy_addbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_infobufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_markbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_freebufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f); -#endif - -int __drm_legacy_infobufs(struct drm_device *, void *, int *, - int (*)(void *, int, struct drm_buf_entry *)); -int __drm_legacy_mapbufs(struct drm_device *, void *, int *, - void __user **, - int (*)(void *, int, unsigned long, struct drm_buf *), - struct drm_file *); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_master_rmmaps(struct drm_device *dev, - struct drm_master *master); -void drm_legacy_rmmaps(struct drm_device *dev); -#else -static inline void drm_legacy_master_rmmaps(struct drm_device *dev, - struct drm_master *master) {} -static inline void drm_legacy_rmmaps(struct drm_device *dev) {} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_vma_flush(struct drm_device *d); -#else -static inline void drm_legacy_vma_flush(struct drm_device *d) -{ - /* do nothing */ -} -#endif - -/* - * AGP Support - */ - -struct drm_agp_mem { - unsigned long handle; - struct agp_memory *memory; - unsigned long bound; - int pages; - struct list_head head; -}; - -/* drm_agpsupport.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_AGP) -void drm_legacy_agp_clear(struct drm_device *dev); - -int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#else -static inline void drm_legacy_agp_clear(struct drm_device *dev) {} -#endif - -/* drm_lock.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f); -void drm_legacy_lock_release(struct drm_device *dev, struct file *filp); -#else -static inline void drm_legacy_lock_release(struct drm_device *dev, struct file *filp) {} -#endif - -/* DMA support */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_dma_setup(struct drm_device *dev); -void drm_legacy_dma_takedown(struct drm_device *dev); -#else -static inline int drm_legacy_dma_setup(struct drm_device *dev) -{ - return 0; -} -#endif - -void drm_legacy_free_buffer(struct drm_device *dev, - struct drm_buf * buf); -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *filp); -#else -static inline void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *filp) {} -#endif - -/* Scatter Gather Support */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_sg_cleanup(struct drm_device *dev); -int drm_legacy_sg_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_sg_free(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_init_members(struct drm_device *dev); -void drm_legacy_destroy_members(struct drm_device *dev); -void drm_legacy_dev_reinit(struct drm_device *dev); -int drm_legacy_setup(struct drm_device * dev); -#else -static inline void drm_legacy_init_members(struct drm_device *dev) {} -static inline void drm_legacy_destroy_members(struct drm_device *dev) {} -static inline void drm_legacy_dev_reinit(struct drm_device *dev) {} -static inline int drm_legacy_setup(struct drm_device * dev) { return 0; } -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master); -#else -static inline void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master) {} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_master_legacy_init(struct drm_master *master); -#else -static inline void drm_master_legacy_init(struct drm_master *master) {} -#endif - -/* drm_pci.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_PCI) -int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); -void drm_legacy_pci_agp_destroy(struct drm_device *dev); -#else -static inline int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return -EINVAL; -} - -static inline void drm_legacy_pci_agp_destroy(struct drm_device *dev) {} -#endif - -#endif /* __DRM_LEGACY_H__ */ diff --git a/drivers/gpu/drm/drm_legacy_misc.c b/drivers/gpu/drm/drm_legacy_misc.c deleted file mode 100644 index d4c5434062d7..000000000000 --- a/drivers/gpu/drm/drm_legacy_misc.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * \file drm_legacy_misc.c - * Misc legacy support functions. - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -void drm_legacy_init_members(struct drm_device *dev) -{ - INIT_LIST_HEAD(&dev->ctxlist); - INIT_LIST_HEAD(&dev->vmalist); - INIT_LIST_HEAD(&dev->maplist); - spin_lock_init(&dev->buf_lock); - mutex_init(&dev->ctxlist_mutex); -} - -void drm_legacy_destroy_members(struct drm_device *dev) -{ - mutex_destroy(&dev->ctxlist_mutex); -} - -int drm_legacy_setup(struct drm_device * dev) -{ - int ret; - - if (dev->driver->firstopen && - drm_core_check_feature(dev, DRIVER_LEGACY)) { - ret = dev->driver->firstopen(dev); - if (ret != 0) - return ret; - } - - ret = drm_legacy_dma_setup(dev); - if (ret < 0) - return ret; - - - DRM_DEBUG("\n"); - return 0; -} - -void drm_legacy_dev_reinit(struct drm_device *dev) -{ - if (dev->irq_enabled) - drm_legacy_irq_uninstall(dev); - - mutex_lock(&dev->struct_mutex); - - drm_legacy_agp_clear(dev); - - drm_legacy_sg_cleanup(dev); - drm_legacy_vma_flush(dev); - drm_legacy_dma_takedown(dev); - - mutex_unlock(&dev->struct_mutex); - - dev->sigdata.lock = NULL; - - dev->context_flag = 0; - dev->last_context = 0; - dev->if_version = 0; - - DRM_DEBUG("lastclose completed\n"); -} - -void drm_master_legacy_init(struct drm_master *master) -{ - spin_lock_init(&master->lock.spinlock); - init_waitqueue_head(&master->lock.lock_queue); -} diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c deleted file mode 100644 index 1efbd5389d89..000000000000 --- a/drivers/gpu/drm/drm_lock.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * \file drm_lock.c - * IOCTLs for locking - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); - -/* - * Take the heavyweight lock. - * - * \param lock lock pointer. - * \param context locking context. - * \return one if the lock is held, or zero otherwise. - * - * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. - */ -static -int drm_lock_take(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - do { - old = *lock; - if (old & _DRM_LOCK_HELD) - new = old | _DRM_LOCK_CONT; - else { - new = context | _DRM_LOCK_HELD | - ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? - _DRM_LOCK_CONT : 0); - } - prev = cmpxchg(lock, old, new); - } while (prev != old); - spin_unlock_bh(&lock_data->spinlock); - - if (_DRM_LOCKING_CONTEXT(old) == context) { - if (old & _DRM_LOCK_HELD) { - if (context != DRM_KERNEL_CONTEXT) { - DRM_ERROR("%d holds heavyweight lock\n", - context); - } - return 0; - } - } - - if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { - /* Have lock */ - return 1; - } - return 0; -} - -/* - * This takes a lock forcibly and hands it to context. Should ONLY be used - * inside *_unlock to give lock to kernel before calling *_dma_schedule. - * - * \param dev DRM device. - * \param lock lock pointer. - * \param context locking context. - * \return always one. - * - * Resets the lock file pointer. - * Marks the lock as held by the given context, via the \p cmpxchg instruction. - */ -static int drm_lock_transfer(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - lock_data->file_priv = NULL; - do { - old = *lock; - new = context | _DRM_LOCK_HELD; - prev = cmpxchg(lock, old, new); - } while (prev != old); - return 1; -} - -static int drm_legacy_lock_free(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - if (lock_data->kernel_waiters != 0) { - drm_lock_transfer(lock_data, 0); - lock_data->idle_has_lock = 1; - spin_unlock_bh(&lock_data->spinlock); - return 1; - } - spin_unlock_bh(&lock_data->spinlock); - - do { - old = *lock; - new = _DRM_LOCKING_CONTEXT(old); - prev = cmpxchg(lock, old, new); - } while (prev != old); - - if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", - context, _DRM_LOCKING_CONTEXT(old)); - return 1; - } - wake_up_interruptible(&lock_data->lock_queue); - return 0; -} - -/* - * Lock ioctl. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_lock structure. - * \return zero on success or negative number on failure. - * - * Add the current task to the lock wait queue, and attempt to take to lock. - */ -int drm_legacy_lock(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - DECLARE_WAITQUEUE(entry, current); - struct drm_lock *lock = data; - struct drm_master *master = file_priv->master; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - ++file_priv->lock_count; - - if (lock->context == DRM_KERNEL_CONTEXT) { - DRM_ERROR("Process %d using kernel context %d\n", - task_pid_nr(current), lock->context); - return -EINVAL; - } - - DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock->context, task_pid_nr(current), - master->lock.hw_lock ? master->lock.hw_lock->lock : -1, - lock->flags); - - add_wait_queue(&master->lock.lock_queue, &entry); - spin_lock_bh(&master->lock.spinlock); - master->lock.user_waiters++; - spin_unlock_bh(&master->lock.spinlock); - - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - if (!master->lock.hw_lock) { - /* Device has been unregistered */ - send_sig(SIGTERM, current, 0); - ret = -EINTR; - break; - } - if (drm_lock_take(&master->lock, lock->context)) { - master->lock.file_priv = file_priv; - master->lock.lock_time = jiffies; - break; /* Got lock */ - } - - /* Contention */ - mutex_unlock(&drm_global_mutex); - schedule(); - mutex_lock(&drm_global_mutex); - if (signal_pending(current)) { - ret = -EINTR; - break; - } - } - spin_lock_bh(&master->lock.spinlock); - master->lock.user_waiters--; - spin_unlock_bh(&master->lock.spinlock); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&master->lock.lock_queue, &entry); - - DRM_DEBUG("%d %s\n", lock->context, - ret ? "interrupted" : "has lock"); - if (ret) return ret; - - /* don't set the block all signals on the master process for now - * really probably not the correct answer but lets us debug xkb - * xserver for now */ - if (!drm_is_current_master(file_priv)) { - dev->sigdata.context = lock->context; - dev->sigdata.lock = master->lock.hw_lock; - } - - if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT)) - { - if (dev->driver->dma_quiescent(dev)) { - DRM_DEBUG("%d waiting for DMA quiescent\n", - lock->context); - return -EBUSY; - } - } - - return 0; -} - -/* - * Unlock ioctl. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_lock structure. - * \return zero on success or negative number on failure. - * - * Transfer and free the lock. - */ -int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_lock *lock = data; - struct drm_master *master = file_priv->master; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (lock->context == DRM_KERNEL_CONTEXT) { - DRM_ERROR("Process %d using kernel context %d\n", - task_pid_nr(current), lock->context); - return -EINVAL; - } - - if (drm_legacy_lock_free(&master->lock, lock->context)) { - /* FIXME: Should really bail out here. */ - } - - return 0; -} - -/* - * This function returns immediately and takes the hw lock - * with the kernel context if it is free, otherwise it gets the highest priority when and if - * it is eventually released. - * - * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held - * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause - * a deadlock, which is why the "idlelock" was invented). - * - * This should be sufficient to wait for GPU idle without - * having to worry about starvation. - */ -void drm_legacy_idlelock_take(struct drm_lock_data *lock_data) -{ - int ret; - - spin_lock_bh(&lock_data->spinlock); - lock_data->kernel_waiters++; - if (!lock_data->idle_has_lock) { - - spin_unlock_bh(&lock_data->spinlock); - ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); - spin_lock_bh(&lock_data->spinlock); - - if (ret == 1) - lock_data->idle_has_lock = 1; - } - spin_unlock_bh(&lock_data->spinlock); -} -EXPORT_SYMBOL(drm_legacy_idlelock_take); - -void drm_legacy_idlelock_release(struct drm_lock_data *lock_data) -{ - unsigned int old, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - if (--lock_data->kernel_waiters == 0) { - if (lock_data->idle_has_lock) { - do { - old = *lock; - prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT); - } while (prev != old); - wake_up_interruptible(&lock_data->lock_queue); - lock_data->idle_has_lock = 0; - } - } - spin_unlock_bh(&lock_data->spinlock); -} -EXPORT_SYMBOL(drm_legacy_idlelock_release); - -static int drm_legacy_i_have_hw_lock(struct drm_device *dev, - struct drm_file *file_priv) -{ - struct drm_master *master = file_priv->master; - - return (file_priv->lock_count && master->lock.hw_lock && - _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && - master->lock.file_priv == file_priv); -} - -void drm_legacy_lock_release(struct drm_device *dev, struct file *filp) -{ - struct drm_file *file_priv = filp->private_data; - - /* if the master has gone away we can't do anything with the lock */ - if (!dev->master) - return; - - if (drm_legacy_i_have_hw_lock(dev, file_priv)) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - drm_legacy_lock_free(&file_priv->master->lock, - _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - } -} - -void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - /* - * Since the master is disappearing, so is the - * possibility to lock. - */ - mutex_lock(&dev->struct_mutex); - if (master->lock.hw_lock) { - if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - mutex_unlock(&dev->struct_mutex); -} diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c deleted file mode 100644 index d2e1dccd8113..000000000000 --- a/drivers/gpu/drm/drm_memory.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * \file drm_memory.c - * Memory management wrappers for DRM - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include - -#include "drm_legacy.h" - -#if IS_ENABLED(CONFIG_AGP) - -#ifdef HAVE_PAGE_AGP -# include -#else -# ifdef __powerpc__ -# define PAGE_AGP pgprot_noncached_wc(PAGE_KERNEL) -# else -# define PAGE_AGP PAGE_KERNEL -# endif -#endif - -static void *agp_remap(unsigned long offset, unsigned long size, - struct drm_device *dev) -{ - unsigned long i, num_pages = - PAGE_ALIGN(size) / PAGE_SIZE; - struct drm_agp_mem *agpmem; - struct page **page_map; - struct page **phys_page_map; - void *addr; - - size = PAGE_ALIGN(size); - -#ifdef __alpha__ - offset -= dev->hose->mem_space->start; -#endif - - list_for_each_entry(agpmem, &dev->agp->memory, head) - if (agpmem->bound <= offset - && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= - (offset + size)) - break; - if (&agpmem->head == &dev->agp->memory) - return NULL; - - /* - * OK, we're mapping AGP space on a chipset/platform on which memory accesses by - * the CPU do not get remapped by the GART. We fix this by using the kernel's - * page-table instead (that's probably faster anyhow...). - */ - /* note: use vmalloc() because num_pages could be large... */ - page_map = vmalloc(array_size(num_pages, sizeof(struct page *))); - if (!page_map) - return NULL; - - phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE); - for (i = 0; i < num_pages; ++i) - page_map[i] = phys_page_map[i]; - addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); - vfree(page_map); - - return addr; -} - -#else /* CONFIG_AGP */ -static inline void *agp_remap(unsigned long offset, unsigned long size, - struct drm_device *dev) -{ - return NULL; -} - -#endif /* CONFIG_AGP */ - -void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev) -{ - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - map->handle = agp_remap(map->offset, map->size, dev); - else - map->handle = ioremap(map->offset, map->size); -} -EXPORT_SYMBOL(drm_legacy_ioremap); - -void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) -{ - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - map->handle = agp_remap(map->offset, map->size, dev); - else - map->handle = ioremap_wc(map->offset, map->size); -} -EXPORT_SYMBOL(drm_legacy_ioremap_wc); - -void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev) -{ - if (!map->handle || !map->size) - return; - - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - vunmap(map->handle); - else - iounmap(map->handle); -} -EXPORT_SYMBOL(drm_legacy_ioremapfree); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 67907dd42721..c585f1e8803e 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -35,13 +35,6 @@ #include #include "drm_internal.h" -#include "drm_legacy.h" - -#ifdef CONFIG_DRM_LEGACY -/* List of devices hanging off drivers with stealth attach. */ -static LIST_HEAD(legacy_dev_list); -static DEFINE_MUTEX(legacy_dev_list_lock); -#endif static int drm_get_pci_domain(struct drm_device *dev) { @@ -72,199 +65,3 @@ int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) master->unique_len = strlen(master->unique); return 0; } - -#ifdef CONFIG_DRM_LEGACY - -static int drm_legacy_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - - if ((p->busnum >> 8) != drm_get_pci_domain(dev) || - (p->busnum & 0xff) != pdev->bus->number || - p->devnum != PCI_SLOT(pdev->devfn) || p->funcnum != PCI_FUNC(pdev->devfn)) - return -EINVAL; - - p->irq = pdev->irq; - - DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, - p->irq); - return 0; -} - -/** - * drm_legacy_irq_by_busid - Get interrupt from bus ID - * @dev: DRM device - * @data: IOCTL parameter pointing to a drm_irq_busid structure - * @file_priv: DRM file private. - * - * Finds the PCI device with the specified bus id and gets its IRQ number. - * This IOCTL is deprecated, and will now return EINVAL for any busid not equal - * to that of the device that this DRM instance attached to. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_irq_busid *p = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - /* UMS was only ever support on PCI devices. */ - if (WARN_ON(!dev_is_pci(dev->dev))) - return -EINVAL; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return -EOPNOTSUPP; - - return drm_legacy_pci_irq_by_busid(dev, p); -} - -void drm_legacy_pci_agp_destroy(struct drm_device *dev) -{ - if (dev->agp) { - arch_phys_wc_del(dev->agp->agp_mtrr); - drm_legacy_agp_clear(dev); - kfree(dev->agp); - dev->agp = NULL; - } -} - -static void drm_legacy_pci_agp_init(struct drm_device *dev) -{ - if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { - if (pci_find_capability(to_pci_dev(dev->dev), PCI_CAP_ID_AGP)) - dev->agp = drm_legacy_agp_init(dev); - if (dev->agp) { - dev->agp->agp_mtrr = arch_phys_wc_add( - dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size * - 1024 * 1024); - } - } -} - -static int drm_legacy_get_pci_dev(struct pci_dev *pdev, - const struct pci_device_id *ent, - const struct drm_driver *driver) -{ - struct drm_device *dev; - int ret; - - DRM_DEBUG("\n"); - - dev = drm_dev_alloc(driver, &pdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - ret = pci_enable_device(pdev); - if (ret) - goto err_free; - -#ifdef __alpha__ - dev->hose = pdev->sysdata; -#endif - - drm_legacy_pci_agp_init(dev); - - ret = drm_dev_register(dev, ent->driver_data); - if (ret) - goto err_agp; - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) { - mutex_lock(&legacy_dev_list_lock); - list_add_tail(&dev->legacy_dev_list, &legacy_dev_list); - mutex_unlock(&legacy_dev_list_lock); - } - - return 0; - -err_agp: - drm_legacy_pci_agp_destroy(dev); - pci_disable_device(pdev); -err_free: - drm_dev_put(dev); - return ret; -} - -/** - * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver - * @driver: DRM device driver - * @pdriver: PCI device driver - * - * This is only used by legacy dri1 drivers and deprecated. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_legacy_pci_init(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ - struct pci_dev *pdev = NULL; - const struct pci_device_id *pid; - int i; - - DRM_DEBUG("\n"); - - if (WARN_ON(!(driver->driver_features & DRIVER_LEGACY))) - return -EINVAL; - - /* If not using KMS, fall back to stealth mode manual scanning. */ - for (i = 0; pdriver->id_table[i].vendor != 0; i++) { - pid = &pdriver->id_table[i]; - - /* Loop around setting up a DRM device for each PCI device - * matching our ID and device class. If we had the internal - * function that pci_get_subsys and pci_get_class used, we'd - * be able to just pass pid in instead of doing a two-stage - * thing. - */ - pdev = NULL; - while ((pdev = - pci_get_subsys(pid->vendor, pid->device, pid->subvendor, - pid->subdevice, pdev)) != NULL) { - if ((pdev->class & pid->class_mask) != pid->class) - continue; - - /* stealth mode requires a manual probe */ - pci_dev_get(pdev); - drm_legacy_get_pci_dev(pdev, pid, driver); - } - } - return 0; -} -EXPORT_SYMBOL(drm_legacy_pci_init); - -/** - * drm_legacy_pci_exit - unregister shadow-attach legacy DRM driver - * @driver: DRM device driver - * @pdriver: PCI device driver - * - * Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This - * is deprecated and only used by dri1 drivers. - */ -void drm_legacy_pci_exit(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ - struct drm_device *dev, *tmp; - - DRM_DEBUG("\n"); - - if (!(driver->driver_features & DRIVER_LEGACY)) { - WARN_ON(1); - } else { - mutex_lock(&legacy_dev_list_lock); - list_for_each_entry_safe(dev, tmp, &legacy_dev_list, - legacy_dev_list) { - if (dev->driver == driver) { - list_del(&dev->legacy_dev_list); - drm_put_dev(dev); - } - } - mutex_unlock(&legacy_dev_list_lock); - } - DRM_INFO("Module unloaded\n"); -} -EXPORT_SYMBOL(drm_legacy_pci_exit); - -#endif diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c deleted file mode 100644 index f4e6184d1877..000000000000 --- a/drivers/gpu/drm/drm_scatter.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * \file drm_scatter.c - * IOCTLs to manage scatter/gather memory - * - * \author Gareth Hughes - */ - -/* - * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com - * - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include - -#include "drm_legacy.h" - -#define DEBUG_SCATTER 0 - -static void drm_sg_cleanup(struct drm_sg_mem * entry) -{ - struct page *page; - int i; - - for (i = 0; i < entry->pages; i++) { - page = entry->pagelist[i]; - if (page) - ClearPageReserved(page); - } - - vfree(entry->virtual); - - kfree(entry->busaddr); - kfree(entry->pagelist); - kfree(entry); -} - -void drm_legacy_sg_cleanup(struct drm_device *dev) -{ - if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg && - drm_core_check_feature(dev, DRIVER_LEGACY)) { - drm_sg_cleanup(dev->sg); - dev->sg = NULL; - } -} -#ifdef _LP64 -# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1))) -#else -# define ScatterHandle(x) (unsigned int)(x) -#endif - -int drm_legacy_sg_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_scatter_gather *request = data; - struct drm_sg_mem *entry; - unsigned long pages, i, j; - - DRM_DEBUG("\n"); - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - if (request->size > SIZE_MAX - PAGE_SIZE) - return -EINVAL; - - if (dev->sg) - return -EINVAL; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; - DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); - - entry->pages = pages; - entry->pagelist = kcalloc(pages, sizeof(*entry->pagelist), GFP_KERNEL); - if (!entry->pagelist) { - kfree(entry); - return -ENOMEM; - } - - entry->busaddr = kcalloc(pages, sizeof(*entry->busaddr), GFP_KERNEL); - if (!entry->busaddr) { - kfree(entry->pagelist); - kfree(entry); - return -ENOMEM; - } - - entry->virtual = vmalloc_32(pages << PAGE_SHIFT); - if (!entry->virtual) { - kfree(entry->busaddr); - kfree(entry->pagelist); - kfree(entry); - return -ENOMEM; - } - - /* This also forces the mapping of COW pages, so our page list - * will be valid. Please don't remove it... - */ - memset(entry->virtual, 0, pages << PAGE_SHIFT); - - entry->handle = ScatterHandle((unsigned long)entry->virtual); - - DRM_DEBUG("handle = %08lx\n", entry->handle); - DRM_DEBUG("virtual = %p\n", entry->virtual); - - for (i = (unsigned long)entry->virtual, j = 0; j < pages; - i += PAGE_SIZE, j++) { - entry->pagelist[j] = vmalloc_to_page((void *)i); - if (!entry->pagelist[j]) - goto failed; - SetPageReserved(entry->pagelist[j]); - } - - request->handle = entry->handle; - - dev->sg = entry; - -#if DEBUG_SCATTER - /* Verify that each page points to its virtual address, and vice - * versa. - */ - { - int error = 0; - - for (i = 0; i < pages; i++) { - unsigned long *tmp; - - tmp = page_address(entry->pagelist[i]); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - *tmp = 0xcafebabe; - } - tmp = (unsigned long *)((u8 *) entry->virtual + - (PAGE_SIZE * i)); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - if (*tmp != 0xcafebabe && error == 0) { - error = 1; - DRM_ERROR("Scatter allocation error, " - "pagelist does not match " - "virtual mapping\n"); - } - } - tmp = page_address(entry->pagelist[i]); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - *tmp = 0; - } - } - if (error == 0) - DRM_ERROR("Scatter allocation matches pagelist\n"); - } -#endif - - return 0; - - failed: - drm_sg_cleanup(entry); - return -ENOMEM; -} - -int drm_legacy_sg_free(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_scatter_gather *request = data; - struct drm_sg_mem *entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - entry = dev->sg; - dev->sg = NULL; - - if (!entry || entry->handle != request->handle) - return -EINVAL; - - DRM_DEBUG("virtual = %p\n", entry->virtual); - - drm_sg_cleanup(entry); - - return 0; -} diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c deleted file mode 100644 index 87c9fe55dec7..000000000000 --- a/drivers/gpu/drm/drm_vm.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - * \file drm_vm.c - * Memory mapping for DRM - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#if defined(__ia64__) -#include -#include -#endif -#include - -#include -#include -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -struct drm_vma_entry { - struct list_head head; - struct vm_area_struct *vma; - pid_t pid; -}; - -static void drm_vm_open(struct vm_area_struct *vma); -static void drm_vm_close(struct vm_area_struct *vma); - -static pgprot_t drm_io_prot(struct drm_local_map *map, - struct vm_area_struct *vma) -{ - pgprot_t tmp = vm_get_page_prot(vma->vm_flags); - -#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \ - defined(__mips__) || defined(__loongarch__) - if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING)) - tmp = pgprot_noncached(tmp); - else - tmp = pgprot_writecombine(tmp); -#elif defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - - vma->vm_start)) - tmp = pgprot_writecombine(tmp); - else - tmp = pgprot_noncached(tmp); -#elif defined(__sparc__) || defined(__arm__) - tmp = pgprot_noncached(tmp); -#endif - return tmp; -} - -static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) -{ - pgprot_t tmp = vm_get_page_prot(vma->vm_flags); - -#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) - tmp = pgprot_noncached_wc(tmp); -#endif - return tmp; -} - -/* - * \c fault method for AGP virtual memory. - * - * \param vma virtual memory area. - * \param address access address. - * \return pointer to the page structure. - * - * Find the right map and if it's AGP memory find the real physical page to - * map, get the page, increment the use count and return it. - */ -#if IS_ENABLED(CONFIG_AGP) -static vm_fault_t drm_vm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list; - struct drm_hash_item *hash; - - /* - * Find the right map - */ - if (!dev->agp) - goto vm_fault_error; - - if (!dev->agp || !dev->agp->cant_use_aperture) - goto vm_fault_error; - - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) - goto vm_fault_error; - - r_list = drm_hash_entry(hash, struct drm_map_list, hash); - map = r_list->map; - - if (map && map->type == _DRM_AGP) { - /* - * Using vm_pgoff as a selector forces us to use this unusual - * addressing scheme. - */ - resource_size_t offset = vmf->address - vma->vm_start; - resource_size_t baddr = map->offset + offset; - struct drm_agp_mem *agpmem; - struct page *page; - -#ifdef __alpha__ - /* - * Adjust to a bus-relative address - */ - baddr -= dev->hose->mem_space->start; -#endif - - /* - * It's AGP memory - find the real physical page to map - */ - list_for_each_entry(agpmem, &dev->agp->memory, head) { - if (agpmem->bound <= baddr && - agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) - break; - } - - if (&agpmem->head == &dev->agp->memory) - goto vm_fault_error; - - /* - * Get the page, inc the use count, and return it - */ - offset = (baddr - agpmem->bound) >> PAGE_SHIFT; - page = agpmem->memory->pages[offset]; - get_page(page); - vmf->page = page; - - DRM_DEBUG - ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n", - (unsigned long long)baddr, - agpmem->memory->pages[offset], - (unsigned long long)offset, - page_count(page)); - return 0; - } -vm_fault_error: - return VM_FAULT_SIGBUS; /* Disallow mremap */ -} -#else -static vm_fault_t drm_vm_fault(struct vm_fault *vmf) -{ - return VM_FAULT_SIGBUS; -} -#endif - -/* - * \c nopage method for shared virtual memory. - * - * \param vma virtual memory area. - * \param address access address. - * \return pointer to the page structure. - * - * Get the mapping, find the real physical page to map, get the page, and - * return it. - */ -static vm_fault_t drm_vm_shm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_local_map *map = vma->vm_private_data; - unsigned long offset; - unsigned long i; - struct page *page; - - if (!map) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - i = (unsigned long)map->handle + offset; - page = vmalloc_to_page((void *)i); - if (!page) - return VM_FAULT_SIGBUS; - get_page(page); - vmf->page = page; - - DRM_DEBUG("shm_fault 0x%lx\n", offset); - return 0; -} - -/* - * \c close method for shared virtual memory. - * - * \param vma virtual memory area. - * - * Deletes map information if we are the last - * person to close a mapping and it's not in the global maplist. - */ -static void drm_vm_shm_close(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_vma_entry *pt, *temp; - struct drm_local_map *map; - struct drm_map_list *r_list; - int found_maps = 0; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - map = vma->vm_private_data; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { - if (pt->vma->vm_private_data == map) - found_maps++; - if (pt->vma == vma) { - list_del(&pt->head); - kfree(pt); - } - } - - /* We were the only map that was found */ - if (found_maps == 1 && map->flags & _DRM_REMOVABLE) { - /* Check to see if we are in the maplist, if we are not, then - * we delete this mappings information. - */ - found_maps = 0; - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map == map) - found_maps++; - } - - if (!found_maps) { - switch (map->type) { - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: - arch_phys_wc_del(map->mtrr); - iounmap(map->handle); - break; - case _DRM_SHM: - vfree(map->handle); - break; - case _DRM_AGP: - case _DRM_SCATTER_GATHER: - break; - case _DRM_CONSISTENT: - dma_free_coherent(dev->dev, - map->size, - map->handle, - map->offset); - break; - } - kfree(map); - } - } - mutex_unlock(&dev->struct_mutex); -} - -/* - * \c fault method for DMA virtual memory. - * - * \param address access address. - * \return pointer to the page structure. - * - * Determine the page number from the page offset and get it from drm_device_dma::pagelist. - */ -static vm_fault_t drm_vm_dma_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_device_dma *dma = dev->dma; - unsigned long offset; - unsigned long page_nr; - struct page *page; - - if (!dma) - return VM_FAULT_SIGBUS; /* Error */ - if (!dma->pagelist) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - /* vm_[pg]off[set] should be 0 */ - page_nr = offset >> PAGE_SHIFT; /* page_nr could just be vmf->pgoff */ - page = virt_to_page((void *)dma->pagelist[page_nr]); - - get_page(page); - vmf->page = page; - - DRM_DEBUG("dma_fault 0x%lx (page %lu)\n", offset, page_nr); - return 0; -} - -/* - * \c fault method for scatter-gather virtual memory. - * - * \param address access address. - * \return pointer to the page structure. - * - * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist. - */ -static vm_fault_t drm_vm_sg_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_local_map *map = vma->vm_private_data; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_sg_mem *entry = dev->sg; - unsigned long offset; - unsigned long map_offset; - unsigned long page_offset; - struct page *page; - - if (!entry) - return VM_FAULT_SIGBUS; /* Error */ - if (!entry->pagelist) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - map_offset = map->offset - (unsigned long)dev->sg->virtual; - page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); - page = entry->pagelist[page_offset]; - get_page(page); - vmf->page = page; - - return 0; -} - -/** AGP virtual memory operations */ -static const struct vm_operations_struct drm_vm_ops = { - .fault = drm_vm_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -/** Shared virtual memory operations */ -static const struct vm_operations_struct drm_vm_shm_ops = { - .fault = drm_vm_shm_fault, - .open = drm_vm_open, - .close = drm_vm_shm_close, -}; - -/** DMA virtual memory operations */ -static const struct vm_operations_struct drm_vm_dma_ops = { - .fault = drm_vm_dma_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -/** Scatter-gather virtual memory operations */ -static const struct vm_operations_struct drm_vm_sg_ops = { - .fault = drm_vm_sg_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -static void drm_vm_open_locked(struct drm_device *dev, - struct vm_area_struct *vma) -{ - struct drm_vma_entry *vma_entry; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL); - if (vma_entry) { - vma_entry->vma = vma; - vma_entry->pid = current->pid; - list_add(&vma_entry->head, &dev->vmalist); - } -} - -static void drm_vm_open(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - - mutex_lock(&dev->struct_mutex); - drm_vm_open_locked(dev, vma); - mutex_unlock(&dev->struct_mutex); -} - -static void drm_vm_close_locked(struct drm_device *dev, - struct vm_area_struct *vma) -{ - struct drm_vma_entry *pt, *temp; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { - if (pt->vma == vma) { - list_del(&pt->head); - kfree(pt); - break; - } - } -} - -/* - * \c close method for all virtual memory types. - * - * \param vma virtual memory area. - * - * Search the \p vma private data entry in drm_device::vmalist, unlink it, and - * free it. - */ -static void drm_vm_close(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - - mutex_lock(&dev->struct_mutex); - drm_vm_close_locked(dev, vma); - mutex_unlock(&dev->struct_mutex); -} - -/* - * mmap DMA memory. - * - * \param file_priv DRM file private. - * \param vma virtual memory area. - * \return zero on success or a negative number on failure. - * - * Sets the virtual memory area operations structure to vm_dma_ops, the file - * pointer, and calls vm_open(). - */ -static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev; - struct drm_device_dma *dma; - unsigned long length = vma->vm_end - vma->vm_start; - - dev = priv->minor->dev; - dma = dev->dma; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); - - /* Length must match exact page count */ - if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { - return -EINVAL; - } - - if (!capable(CAP_SYS_ADMIN) && - (dma->flags & _DRM_DMA_USE_PCI_RO)) { - vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE); -#if defined(__i386__) || defined(__x86_64__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; -#else - /* Ye gads this is ugly. With more thought - we could move this up higher and use - `protection_map' instead. */ - vma->vm_page_prot = - __pgprot(pte_val - (pte_wrprotect - (__pte(pgprot_val(vma->vm_page_prot))))); -#endif - } - - vma->vm_ops = &drm_vm_dma_ops; - - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - - drm_vm_open_locked(dev, vma); - return 0; -} - -static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev) -{ -#ifdef __alpha__ - return dev->hose->dense_mem_base; -#else - return 0; -#endif -} - -/* - * mmap DMA memory. - * - * \param file_priv DRM file private. - * \param vma virtual memory area. - * \return zero on success or a negative number on failure. - * - * If the virtual memory area has no offset associated with it then it's a DMA - * area, so calls mmap_dma(). Otherwise searches the map in drm_device::maplist, - * checks that the restricted flag is not set, sets the virtual memory operations - * according to the mapping type and remaps the pages. Finally sets the file - * pointer and calls vm_open(). - */ -static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_local_map *map = NULL; - resource_size_t offset = 0; - struct drm_hash_item *hash; - - DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); - - if (!priv->authenticated) - return -EACCES; - - /* We check for "dma". On Apple's UniNorth, it's valid to have - * the AGP mapped at physical address 0 - * --BenH. - */ - if (!vma->vm_pgoff -#if IS_ENABLED(CONFIG_AGP) - && (!dev->agp - || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) -#endif - ) - return drm_mmap_dma(filp, vma); - - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { - DRM_ERROR("Could not find map\n"); - return -EINVAL; - } - - map = drm_hash_entry(hash, struct drm_map_list, hash)->map; - if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) - return -EPERM; - - /* Check for valid size. */ - if (map->size < vma->vm_end - vma->vm_start) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { - vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE); -#if defined(__i386__) || defined(__x86_64__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; -#else - /* Ye gads this is ugly. With more thought - we could move this up higher and use - `protection_map' instead. */ - vma->vm_page_prot = - __pgprot(pte_val - (pte_wrprotect - (__pte(pgprot_val(vma->vm_page_prot))))); -#endif - } - - switch (map->type) { -#if !defined(__arm__) - case _DRM_AGP: - if (dev->agp && dev->agp->cant_use_aperture) { - /* - * On some platforms we can't talk to bus dma address from the CPU, so for - * memory of type DRM_AGP, we'll deal with sorting out the real physical - * pages and mappings in fault() - */ -#if defined(__powerpc__) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif - vma->vm_ops = &drm_vm_ops; - break; - } - fallthrough; /* to _DRM_FRAME_BUFFER... */ -#endif - case _DRM_FRAME_BUFFER: - case _DRM_REGISTERS: - offset = drm_core_get_reg_ofs(dev); - vma->vm_page_prot = drm_io_prot(map, vma); - if (io_remap_pfn_range(vma, vma->vm_start, - (map->offset + offset) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," - " offset = 0x%llx\n", - map->type, - vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset)); - - vma->vm_ops = &drm_vm_ops; - break; - case _DRM_CONSISTENT: - /* Consistent memory is really like shared memory. But - * it's allocated in a different way, so avoid fault */ - if (remap_pfn_range(vma, vma->vm_start, - page_to_pfn(virt_to_page(map->handle)), - vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; - vma->vm_page_prot = drm_dma_prot(map->type, vma); - fallthrough; /* to _DRM_SHM */ - case _DRM_SHM: - vma->vm_ops = &drm_vm_shm_ops; - vma->vm_private_data = (void *)map; - break; - case _DRM_SCATTER_GATHER: - vma->vm_ops = &drm_vm_sg_ops; - vma->vm_private_data = (void *)map; - vma->vm_page_prot = drm_dma_prot(map->type, vma); - break; - default: - return -EINVAL; /* This should never happen. */ - } - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - - drm_vm_open_locked(dev, vma); - return 0; -} - -int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - int ret; - - if (drm_dev_is_unplugged(dev)) - return -ENODEV; - - mutex_lock(&dev->struct_mutex); - ret = drm_mmap_locked(filp, vma); - mutex_unlock(&dev->struct_mutex); - - return ret; -} -EXPORT_SYMBOL(drm_legacy_mmap); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_vma_flush(struct drm_device *dev) -{ - struct drm_vma_entry *vma, *vma_temp; - - /* Clear vma list (only needed for legacy drivers) */ - list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { - list_del(&vma->head); - kfree(vma); - } -} -#endif diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h index ba248ca8866f..50131383ed81 100644 --- a/include/drm/drm_auth.h +++ b/include/drm/drm_auth.h @@ -33,24 +33,6 @@ #include struct drm_file; -struct drm_hw_lock; - -/* - * Legacy DRI1 locking data structure. Only here instead of in drm_legacy.h for - * include ordering reasons. - * - * DO NOT USE. - */ -struct drm_lock_data { - struct drm_hw_lock *hw_lock; - struct drm_file *file_priv; - wait_queue_head_t lock_queue; - unsigned long lock_time; - spinlock_t spinlock; - uint32_t kernel_waiters; - uint32_t user_waiters; - int idle_has_lock; -}; /** * struct drm_master - drm master structure @@ -145,10 +127,6 @@ struct drm_master { * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex. */ struct idr lessee_idr; - /* private: */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) - struct drm_lock_data lock; -#endif }; struct drm_master *drm_master_get(struct drm_master *master); diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index c490977ee250..63767cf24371 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -6,7 +6,6 @@ #include #include -#include #include struct drm_driver; @@ -153,8 +152,8 @@ struct drm_device { * * Lock for others (not &drm_minor.master and &drm_file.is_master) * - * WARNING: - * Only drivers annotated with DRIVER_LEGACY should be using this. + * TODO: This lock used to be the BKL of the DRM subsystem. Move the + * lock into i915, which is the only remaining user. */ struct mutex struct_mutex; @@ -317,72 +316,6 @@ struct drm_device { * Root directory for debugfs files. */ struct dentry *debugfs_root; - - /* Everything below here is for legacy driver, never use! */ - /* private: */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) - /* List of devices per driver for stealth attach cleanup */ - struct list_head legacy_dev_list; - -#ifdef __alpha__ - /** @hose: PCI hose, only used on ALPHA platforms. */ - struct pci_controller *hose; -#endif - - /* AGP data */ - struct drm_agp_head *agp; - - /* Context handle management - linked list of context handles */ - struct list_head ctxlist; - - /* Context handle management - mutex for &ctxlist */ - struct mutex ctxlist_mutex; - - /* Context handle management */ - struct idr ctx_idr; - - /* Memory management - linked list of regions */ - struct list_head maplist; - - /* Memory management - user token hash table for maps */ - struct drm_open_hash map_hash; - - /* Context handle management - list of vmas (for debugging) */ - struct list_head vmalist; - - /* Optional pointer for DMA support */ - struct drm_device_dma *dma; - - /* Context swapping flag */ - __volatile__ long context_flag; - - /* Last current context */ - int last_context; - - /* Lock for &buf_use and a few other things. */ - spinlock_t buf_lock; - - /* Usage counter for buffers in use -- cannot alloc */ - int buf_use; - - /* Buffer allocation in progress */ - atomic_t buf_alloc; - - struct { - int context; - struct drm_hw_lock *lock; - } sigdata; - - struct drm_local_map *agp_buffer_map; - unsigned int agp_buffer_token; - - /* Scatter gather memory */ - struct drm_sg_mem *sg; - - /* IRQs */ - bool irq_enabled; - int irq; -#endif }; #endif diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index ea36aa79dca2..8878260d7529 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -442,25 +442,6 @@ struct drm_driver { * some examples. */ const struct file_operations *fops; - -#ifdef CONFIG_DRM_LEGACY - /* Everything below here is for legacy driver, never use! */ - /* private: */ - - int (*firstopen) (struct drm_device *); - void (*preclose) (struct drm_device *, struct drm_file *file_priv); - int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); - int (*dma_quiescent) (struct drm_device *); - int (*context_dtor) (struct drm_device *dev, int context); - irqreturn_t (*irq_handler)(int irq, void *arg); - void (*irq_preinstall)(struct drm_device *dev); - int (*irq_postinstall)(struct drm_device *dev); - void (*irq_uninstall)(struct drm_device *dev); - u32 (*get_vblank_counter)(struct drm_device *dev, unsigned int pipe); - int (*enable_vblank)(struct drm_device *dev, unsigned int pipe); - void (*disable_vblank)(struct drm_device *dev, unsigned int pipe); - int dev_priv_size; -#endif }; void *__devm_drm_dev_alloc(struct device *parent, diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 8f35dcea82d3..ab230d3af138 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -386,11 +386,6 @@ struct drm_file { * Per-file buffer caches used by the PRIME buffer sharing code. */ struct drm_prime_file_private prime; - - /* private: */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) - unsigned long lock_count; /* DRI1 legacy lock count */ -#endif }; /** diff --git a/include/drm/drm_legacy.h b/include/drm/drm_legacy.h deleted file mode 100644 index 0fc85418aad8..000000000000 --- a/include/drm/drm_legacy.h +++ /dev/null @@ -1,331 +0,0 @@ -#ifndef __DRM_DRM_LEGACY_H__ -#define __DRM_DRM_LEGACY_H__ -/* - * Legacy driver interfaces for the Direct Rendering Manager - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright (c) 2009-2010, Code Aurora Forum. - * All rights reserved. - * Copyright © 2014 Intel Corporation - * Daniel Vetter - * - * Author: Rickard E. (Rik) Faith - * Author: Gareth Hughes - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include -#include - -struct drm_device; -struct drm_driver; -struct file; -struct pci_driver; - -/* - * Legacy Support for palateontologic DRM drivers - * - * If you add a new driver and it uses any of these functions or structures, - * you're doing it terribly wrong. - */ - -/* - * Hash-table Support - */ - -struct drm_hash_item { - struct hlist_node head; - unsigned long key; -}; - -struct drm_open_hash { - struct hlist_head *table; - u8 order; -}; - -/** - * DMA buffer. - */ -struct drm_buf { - int idx; /**< Index into master buflist */ - int total; /**< Buffer size */ - int order; /**< log-base-2(total) */ - int used; /**< Amount of buffer in use (for DMA) */ - unsigned long offset; /**< Byte offset (used internally) */ - void *address; /**< Address of buffer */ - unsigned long bus_address; /**< Bus address of buffer */ - struct drm_buf *next; /**< Kernel-only: used for free list */ - __volatile__ int waiting; /**< On kernel DMA queue */ - __volatile__ int pending; /**< On hardware DMA queue */ - struct drm_file *file_priv; /**< Private of holding file descr */ - int context; /**< Kernel queue for this buffer */ - int while_locked; /**< Dispatch this buffer while locked */ - enum { - DRM_LIST_NONE = 0, - DRM_LIST_FREE = 1, - DRM_LIST_WAIT = 2, - DRM_LIST_PEND = 3, - DRM_LIST_PRIO = 4, - DRM_LIST_RECLAIM = 5 - } list; /**< Which list we're on */ - - int dev_priv_size; /**< Size of buffer private storage */ - void *dev_private; /**< Per-buffer private storage */ -}; - -typedef struct drm_dma_handle { - dma_addr_t busaddr; - void *vaddr; - size_t size; -} drm_dma_handle_t; - -/** - * Buffer entry. There is one of this for each buffer size order. - */ -struct drm_buf_entry { - int buf_size; /**< size */ - int buf_count; /**< number of buffers */ - struct drm_buf *buflist; /**< buffer list */ - int seg_count; - int page_order; - struct drm_dma_handle **seglist; - - int low_mark; /**< Low water mark */ - int high_mark; /**< High water mark */ -}; - -/** - * DMA data. - */ -struct drm_device_dma { - - struct drm_buf_entry bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */ - int buf_count; /**< total number of buffers */ - struct drm_buf **buflist; /**< Vector of pointers into drm_device_dma::bufs */ - int seg_count; - int page_count; /**< number of pages */ - unsigned long *pagelist; /**< page list */ - unsigned long byte_count; - enum { - _DRM_DMA_USE_AGP = 0x01, - _DRM_DMA_USE_SG = 0x02, - _DRM_DMA_USE_FB = 0x04, - _DRM_DMA_USE_PCI_RO = 0x08 - } flags; - -}; - -/** - * Scatter-gather memory. - */ -struct drm_sg_mem { - unsigned long handle; - void *virtual; - int pages; - struct page **pagelist; - dma_addr_t *busaddr; -}; - -/** - * Kernel side of a mapping - */ -struct drm_local_map { - dma_addr_t offset; /**< Requested physical address (0 for SAREA)*/ - unsigned long size; /**< Requested physical size (bytes) */ - enum drm_map_type type; /**< Type of memory to map */ - enum drm_map_flags flags; /**< Flags */ - void *handle; /**< User-space: "Handle" to pass to mmap() */ - /**< Kernel-space: kernel-virtual address */ - int mtrr; /**< MTRR slot used */ -}; - -typedef struct drm_local_map drm_local_map_t; - -/** - * Mappings list - */ -struct drm_map_list { - struct list_head head; /**< list head */ - struct drm_hash_item hash; - struct drm_local_map *map; /**< mapping */ - uint64_t user_token; - struct drm_master *master; -}; - -int drm_legacy_addmap(struct drm_device *d, resource_size_t offset, - unsigned int size, enum drm_map_type type, - enum drm_map_flags flags, struct drm_local_map **map_p); -struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, unsigned int token); -void drm_legacy_rmmap(struct drm_device *d, struct drm_local_map *map); -int drm_legacy_rmmap_locked(struct drm_device *d, struct drm_local_map *map); -struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev); -int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma); - -int drm_legacy_addbufs_agp(struct drm_device *d, struct drm_buf_desc *req); -int drm_legacy_addbufs_pci(struct drm_device *d, struct drm_buf_desc *req); - -/** - * Test that the hardware lock is held by the caller, returning otherwise. - * - * \param dev DRM device. - * \param filp file pointer of the caller. - */ -#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \ -do { \ - if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \ - _file_priv->master->lock.file_priv != _file_priv) { \ - DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ - __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\ - _file_priv->master->lock.file_priv, _file_priv); \ - return -EINVAL; \ - } \ -} while (0) - -void drm_legacy_idlelock_take(struct drm_lock_data *lock); -void drm_legacy_idlelock_release(struct drm_lock_data *lock); - -/* drm_irq.c */ -int drm_legacy_irq_uninstall(struct drm_device *dev); - -/* drm_pci.c */ - -#ifdef CONFIG_PCI - -int drm_legacy_pci_init(const struct drm_driver *driver, - struct pci_driver *pdriver); -void drm_legacy_pci_exit(const struct drm_driver *driver, - struct pci_driver *pdriver); - -#else - -static inline struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, - size_t size, size_t align) -{ - return NULL; -} - -static inline void drm_pci_free(struct drm_device *dev, - struct drm_dma_handle *dmah) -{ -} - -static inline int drm_legacy_pci_init(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ - return -EINVAL; -} - -static inline void drm_legacy_pci_exit(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ -} - -#endif - -/* - * AGP Support - */ - -struct drm_agp_head { - struct agp_kern_info agp_info; - struct list_head memory; - unsigned long mode; - struct agp_bridge_data *bridge; - int enabled; - int acquired; - unsigned long base; - int agp_mtrr; - int cant_use_aperture; - unsigned long page_mask; -}; - -#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_AGP) -struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev); -int drm_legacy_agp_acquire(struct drm_device *dev); -int drm_legacy_agp_release(struct drm_device *dev); -int drm_legacy_agp_enable(struct drm_device *dev, struct drm_agp_mode mode); -int drm_legacy_agp_info(struct drm_device *dev, struct drm_agp_info *info); -int drm_legacy_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request); -int drm_legacy_agp_free(struct drm_device *dev, struct drm_agp_buffer *request); -int drm_legacy_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); -int drm_legacy_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); -#else -static inline struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev) -{ - return NULL; -} - -static inline int drm_legacy_agp_acquire(struct drm_device *dev) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_release(struct drm_device *dev) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_enable(struct drm_device *dev, - struct drm_agp_mode mode) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_info(struct drm_device *dev, - struct drm_agp_info *info) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_alloc(struct drm_device *dev, - struct drm_agp_buffer *request) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_free(struct drm_device *dev, - struct drm_agp_buffer *request) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_unbind(struct drm_device *dev, - struct drm_agp_binding *request) -{ - return -ENODEV; -} - -static inline int drm_legacy_agp_bind(struct drm_device *dev, - struct drm_agp_binding *request) -{ - return -ENODEV; -} -#endif - -/* drm_memory.c */ -void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev); -void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev); -void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev); - -#endif /* __DRM_DRM_LEGACY_H__ */ From 87be41f09ac92cee6d0124636f49fac21dfd445e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:42 +0100 Subject: [PATCH 2755/7721] char/agp: Remove frontend code The AGP subsystem supports a user-space interface via /dev/agpgart. It is only enabled with DRM support for mode setting in user space. (i.e., CONFIG_DRM_LEGACY). All of that DRM code has been removed and the option will go away. Hence remove the AGP frontend. Modern DRM drivers with kernel mode setting handle AGP support internally. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-14-tzimmermann@suse.de --- drivers/char/agp/Makefile | 6 - drivers/char/agp/agp.h | 9 - drivers/char/agp/backend.c | 11 - drivers/char/agp/compat_ioctl.c | 291 --------- drivers/char/agp/compat_ioctl.h | 106 --- drivers/char/agp/frontend.c | 1068 ------------------------------- 6 files changed, 1491 deletions(-) delete mode 100644 drivers/char/agp/compat_ioctl.c delete mode 100644 drivers/char/agp/compat_ioctl.h delete mode 100644 drivers/char/agp/frontend.c diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 25834557e486..43b09cf193bb 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -1,12 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 agpgart-y := backend.o generic.o isoch.o -ifeq ($(CONFIG_DRM_LEGACY),y) -agpgart-$(CONFIG_COMPAT) += compat_ioctl.o -agpgart-y += frontend.o -endif - - obj-$(CONFIG_AGP) += agpgart.o obj-$(CONFIG_AGP_ALI) += ali-agp.o obj-$(CONFIG_AGP_ATI) += ati-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8771dcc9b8e2..5c36ab85f80b 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -185,15 +185,6 @@ void agp_put_bridge(struct agp_bridge_data *bridge); int agp_add_bridge(struct agp_bridge_data *bridge); void agp_remove_bridge(struct agp_bridge_data *bridge); -/* Frontend routines. */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int agp_frontend_initialize(void); -void agp_frontend_cleanup(void); -#else -static inline int agp_frontend_initialize(void) { return 0; } -static inline void agp_frontend_cleanup(void) {} -#endif - /* Generic routines. */ void agp_generic_enable(struct agp_bridge_data *bridge, u32 mode); int agp_generic_create_gatt_table(struct agp_bridge_data *bridge); diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 0e19c600db53..1776afd3ee07 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -293,13 +293,6 @@ int agp_add_bridge(struct agp_bridge_data *bridge) } if (list_empty(&agp_bridges)) { - error = agp_frontend_initialize(); - if (error) { - dev_info(&bridge->dev->dev, - "agp_frontend_initialize() failed\n"); - goto frontend_err; - } - dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n", bridge->driver->fetch_size(), bridge->gart_bus_addr); @@ -308,8 +301,6 @@ int agp_add_bridge(struct agp_bridge_data *bridge) list_add(&bridge->list, &agp_bridges); return 0; -frontend_err: - agp_backend_cleanup(bridge); err_out: module_put(bridge->driver->owner); err_put_bridge: @@ -323,8 +314,6 @@ void agp_remove_bridge(struct agp_bridge_data *bridge) { agp_backend_cleanup(bridge); list_del(&bridge->list); - if (list_empty(&agp_bridges)) - agp_frontend_cleanup(); module_put(bridge->driver->owner); } EXPORT_SYMBOL_GPL(agp_remove_bridge); diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c deleted file mode 100644 index 52ffe1706ce0..000000000000 --- a/drivers/char/agp/compat_ioctl.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * AGPGART driver frontend compatibility ioctls - * Copyright (C) 2004 Silicon Graphics, Inc. - * Copyright (C) 2002-2003 Dave Jones - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#include -#include -#include -#include "agp.h" -#include "compat_ioctl.h" - -static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_info32 userinfo; - struct agp_kern_info kerninfo; - - agp_copy_info(agp_bridge, &kerninfo); - - userinfo.version.major = kerninfo.version.major; - userinfo.version.minor = kerninfo.version.minor; - userinfo.bridge_id = kerninfo.device->vendor | - (kerninfo.device->device << 16); - userinfo.agp_mode = kerninfo.mode; - userinfo.aper_base = (compat_long_t)kerninfo.aper_base; - userinfo.aper_size = kerninfo.aper_size; - userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; - userinfo.pg_used = kerninfo.current_memory; - - if (copy_to_user(arg, &userinfo, sizeof(userinfo))) - return -EFAULT; - - return 0; -} - -static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_region32 ureserve; - struct agp_region kreserve; - struct agp_client *client; - struct agp_file_private *client_priv; - - DBG(""); - if (copy_from_user(&ureserve, arg, sizeof(ureserve))) - return -EFAULT; - - if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) - return -EFAULT; - - kreserve.pid = ureserve.pid; - kreserve.seg_count = ureserve.seg_count; - - client = agp_find_client_by_pid(kreserve.pid); - - if (kreserve.seg_count == 0) { - /* remove a client */ - client_priv = agp_find_private(kreserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - if (client == NULL) { - /* client is already removed */ - return 0; - } - return agp_remove_client(kreserve.pid); - } else { - struct agp_segment32 *usegment; - struct agp_segment *ksegment; - int seg; - - if (ureserve.seg_count >= 16384) - return -EINVAL; - - usegment = kmalloc_array(ureserve.seg_count, - sizeof(*usegment), - GFP_KERNEL); - if (!usegment) - return -ENOMEM; - - ksegment = kmalloc_array(kreserve.seg_count, - sizeof(*ksegment), - GFP_KERNEL); - if (!ksegment) { - kfree(usegment); - return -ENOMEM; - } - - if (copy_from_user(usegment, (void __user *) ureserve.seg_list, - sizeof(*usegment) * ureserve.seg_count)) { - kfree(usegment); - kfree(ksegment); - return -EFAULT; - } - - for (seg = 0; seg < ureserve.seg_count; seg++) { - ksegment[seg].pg_start = usegment[seg].pg_start; - ksegment[seg].pg_count = usegment[seg].pg_count; - ksegment[seg].prot = usegment[seg].prot; - } - - kfree(usegment); - kreserve.seg_list = ksegment; - - if (client == NULL) { - /* Create the client and add the segment */ - client = agp_create_client(kreserve.pid); - - if (client == NULL) { - kfree(ksegment); - return -ENOMEM; - } - client_priv = agp_find_private(kreserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - } - return agp_create_segment(client, &kreserve); - } - /* Will never really happen */ - return -EINVAL; -} - -static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_allocate32 alloc; - - DBG(""); - if (copy_from_user(&alloc, arg, sizeof(alloc))) - return -EFAULT; - - memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); - - if (memory == NULL) - return -ENOMEM; - - alloc.key = memory->key; - alloc.physical = memory->physical; - - if (copy_to_user(arg, &alloc, sizeof(alloc))) { - agp_free_memory_wrap(memory); - return -EFAULT; - } - return 0; -} - -static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_bind32 bind_info; - struct agp_memory *memory; - - DBG(""); - if (copy_from_user(&bind_info, arg, sizeof(bind_info))) - return -EFAULT; - - memory = agp_find_mem_by_key(bind_info.key); - - if (memory == NULL) - return -EINVAL; - - return agp_bind_memory(memory, bind_info.pg_start); -} - -static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_unbind32 unbind; - - DBG(""); - if (copy_from_user(&unbind, arg, sizeof(unbind))) - return -EFAULT; - - memory = agp_find_mem_by_key(unbind.key); - - if (memory == NULL) - return -EINVAL; - - return agp_unbind_memory(memory); -} - -long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct agp_file_private *curr_priv = file->private_data; - int ret_val = -ENOTTY; - - mutex_lock(&(agp_fe.agp_mutex)); - - if ((agp_fe.current_controller == NULL) && - (cmd != AGPIOC_ACQUIRE32)) { - ret_val = -EINVAL; - goto ioctl_out; - } - if ((agp_fe.backend_acquired != true) && - (cmd != AGPIOC_ACQUIRE32)) { - ret_val = -EBUSY; - goto ioctl_out; - } - if (cmd != AGPIOC_ACQUIRE32) { - if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { - ret_val = -EPERM; - goto ioctl_out; - } - /* Use the original pid of the controller, - * in case it's threaded */ - - if (agp_fe.current_controller->pid != curr_priv->my_pid) { - ret_val = -EBUSY; - goto ioctl_out; - } - } - - switch (cmd) { - case AGPIOC_INFO32: - ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_ACQUIRE32: - ret_val = agpioc_acquire_wrap(curr_priv); - break; - - case AGPIOC_RELEASE32: - ret_val = agpioc_release_wrap(curr_priv); - break; - - case AGPIOC_SETUP32: - ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_RESERVE32: - ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_PROTECT32: - ret_val = agpioc_protect_wrap(curr_priv); - break; - - case AGPIOC_ALLOCATE32: - ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_DEALLOCATE32: - ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); - break; - - case AGPIOC_BIND32: - ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_UNBIND32: - ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_CHIPSET_FLUSH32: - break; - } - -ioctl_out: - DBG("ioctl returns %d\n", ret_val); - mutex_unlock(&(agp_fe.agp_mutex)); - return ret_val; -} - diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h deleted file mode 100644 index f30e0fd97963..000000000000 --- a/drivers/char/agp/compat_ioctl.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _AGP_COMPAT_IOCTL_H -#define _AGP_COMPAT_IOCTL_H - -#include -#include - -#define AGPIOC_INFO32 _IOR (AGPIOC_BASE, 0, compat_uptr_t) -#define AGPIOC_ACQUIRE32 _IO (AGPIOC_BASE, 1) -#define AGPIOC_RELEASE32 _IO (AGPIOC_BASE, 2) -#define AGPIOC_SETUP32 _IOW (AGPIOC_BASE, 3, compat_uptr_t) -#define AGPIOC_RESERVE32 _IOW (AGPIOC_BASE, 4, compat_uptr_t) -#define AGPIOC_PROTECT32 _IOW (AGPIOC_BASE, 5, compat_uptr_t) -#define AGPIOC_ALLOCATE32 _IOWR(AGPIOC_BASE, 6, compat_uptr_t) -#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t) -#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t) -#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t) -#define AGPIOC_CHIPSET_FLUSH32 _IO (AGPIOC_BASE, 10) - -struct agp_info32 { - struct agp_version version; /* version of the driver */ - u32 bridge_id; /* bridge vendor/device */ - u32 agp_mode; /* mode info of bridge */ - compat_long_t aper_base; /* base of aperture */ - compat_size_t aper_size; /* size of aperture */ - compat_size_t pg_total; /* max pages (swap + system) */ - compat_size_t pg_system; /* max pages (system) */ - compat_size_t pg_used; /* current pages used */ -}; - -/* - * The "prot" down below needs still a "sleep" flag somehow ... - */ -struct agp_segment32 { - compat_off_t pg_start; /* starting page to populate */ - compat_size_t pg_count; /* number of pages */ - compat_int_t prot; /* prot flags for mmap */ -}; - -struct agp_region32 { - compat_pid_t pid; /* pid of process */ - compat_size_t seg_count; /* number of segments */ - struct agp_segment32 *seg_list; -}; - -struct agp_allocate32 { - compat_int_t key; /* tag of allocation */ - compat_size_t pg_count; /* number of pages */ - u32 type; /* 0 == normal, other devspec */ - u32 physical; /* device specific (some devices - * need a phys address of the - * actual page behind the gatt - * table) */ -}; - -struct agp_bind32 { - compat_int_t key; /* tag of allocation */ - compat_off_t pg_start; /* starting page to populate */ -}; - -struct agp_unbind32 { - compat_int_t key; /* tag of allocation */ - u32 priority; /* priority for paging out */ -}; - -extern struct agp_front_data agp_fe; - -int agpioc_acquire_wrap(struct agp_file_private *priv); -int agpioc_release_wrap(struct agp_file_private *priv); -int agpioc_protect_wrap(struct agp_file_private *priv); -int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg); -int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg); -struct agp_file_private *agp_find_private(pid_t pid); -struct agp_client *agp_create_client(pid_t id); -int agp_remove_client(pid_t id); -int agp_create_segment(struct agp_client *client, struct agp_region *region); -void agp_free_memory_wrap(struct agp_memory *memory); -struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); -struct agp_memory *agp_find_mem_by_key(int key); -struct agp_client *agp_find_client_by_pid(pid_t id); - -#endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c deleted file mode 100644 index 321118a9cfa5..000000000000 --- a/drivers/char/agp/frontend.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * AGPGART driver frontend - * Copyright (C) 2004 Silicon Graphics, Inc. - * Copyright (C) 2002-2003 Dave Jones - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "agp.h" -#include "compat_ioctl.h" - -struct agp_front_data agp_fe; - -struct agp_memory *agp_find_mem_by_key(int key) -{ - struct agp_memory *curr; - - if (agp_fe.current_controller == NULL) - return NULL; - - curr = agp_fe.current_controller->pool; - - while (curr != NULL) { - if (curr->key == key) - break; - curr = curr->next; - } - - DBG("key=%d -> mem=%p", key, curr); - return curr; -} - -static void agp_remove_from_pool(struct agp_memory *temp) -{ - struct agp_memory *prev; - struct agp_memory *next; - - /* Check to see if this is even in the memory pool */ - - DBG("mem=%p", temp); - if (agp_find_mem_by_key(temp->key) != NULL) { - next = temp->next; - prev = temp->prev; - - if (prev != NULL) { - prev->next = next; - if (next != NULL) - next->prev = prev; - - } else { - /* This is the first item on the list */ - if (next != NULL) - next->prev = NULL; - - agp_fe.current_controller->pool = next; - } - } -} - -/* - * Routines for managing each client's segment list - - * These routines handle adding and removing segments - * to each auth'ed client. - */ - -static struct -agp_segment_priv *agp_find_seg_in_client(const struct agp_client *client, - unsigned long offset, - int size, pgprot_t page_prot) -{ - struct agp_segment_priv *seg; - int i; - off_t pg_start; - size_t pg_count; - - pg_start = offset / 4096; - pg_count = size / 4096; - seg = *(client->segments); - - for (i = 0; i < client->num_segments; i++) { - if ((seg[i].pg_start == pg_start) && - (seg[i].pg_count == pg_count) && - (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) { - return seg + i; - } - } - - return NULL; -} - -static void agp_remove_seg_from_client(struct agp_client *client) -{ - DBG("client=%p", client); - - if (client->segments != NULL) { - if (*(client->segments) != NULL) { - DBG("Freeing %p from client %p", *(client->segments), client); - kfree(*(client->segments)); - } - DBG("Freeing %p from client %p", client->segments, client); - kfree(client->segments); - client->segments = NULL; - } -} - -static void agp_add_seg_to_client(struct agp_client *client, - struct agp_segment_priv ** seg, int num_segments) -{ - struct agp_segment_priv **prev_seg; - - prev_seg = client->segments; - - if (prev_seg != NULL) - agp_remove_seg_from_client(client); - - DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client); - client->num_segments = num_segments; - client->segments = seg; -} - -static pgprot_t agp_convert_mmap_flags(int prot) -{ - unsigned long prot_bits; - - prot_bits = calc_vm_prot_bits(prot, 0) | VM_SHARED; - return vm_get_page_prot(prot_bits); -} - -int agp_create_segment(struct agp_client *client, struct agp_region *region) -{ - struct agp_segment_priv **ret_seg; - struct agp_segment_priv *seg; - struct agp_segment *user_seg; - size_t i; - - seg = kzalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); - if (seg == NULL) { - kfree(region->seg_list); - region->seg_list = NULL; - return -ENOMEM; - } - user_seg = region->seg_list; - - for (i = 0; i < region->seg_count; i++) { - seg[i].pg_start = user_seg[i].pg_start; - seg[i].pg_count = user_seg[i].pg_count; - seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); - } - kfree(region->seg_list); - region->seg_list = NULL; - - ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); - if (ret_seg == NULL) { - kfree(seg); - return -ENOMEM; - } - *ret_seg = seg; - agp_add_seg_to_client(client, ret_seg, region->seg_count); - return 0; -} - -/* End - Routines for managing each client's segment list */ - -/* This function must only be called when current_controller != NULL */ -static void agp_insert_into_pool(struct agp_memory * temp) -{ - struct agp_memory *prev; - - prev = agp_fe.current_controller->pool; - - if (prev != NULL) { - prev->prev = temp; - temp->next = prev; - } - agp_fe.current_controller->pool = temp; -} - - -/* File private list routines */ - -struct agp_file_private *agp_find_private(pid_t pid) -{ - struct agp_file_private *curr; - - curr = agp_fe.file_priv_list; - - while (curr != NULL) { - if (curr->my_pid == pid) - return curr; - curr = curr->next; - } - - return NULL; -} - -static void agp_insert_file_private(struct agp_file_private * priv) -{ - struct agp_file_private *prev; - - prev = agp_fe.file_priv_list; - - if (prev != NULL) - prev->prev = priv; - priv->next = prev; - agp_fe.file_priv_list = priv; -} - -static void agp_remove_file_private(struct agp_file_private * priv) -{ - struct agp_file_private *next; - struct agp_file_private *prev; - - next = priv->next; - prev = priv->prev; - - if (prev != NULL) { - prev->next = next; - - if (next != NULL) - next->prev = prev; - - } else { - if (next != NULL) - next->prev = NULL; - - agp_fe.file_priv_list = next; - } -} - -/* End - File flag list routines */ - -/* - * Wrappers for agp_free_memory & agp_allocate_memory - * These make sure that internal lists are kept updated. - */ -void agp_free_memory_wrap(struct agp_memory *memory) -{ - agp_remove_from_pool(memory); - agp_free_memory(memory); -} - -struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) -{ - struct agp_memory *memory; - - memory = agp_allocate_memory(agp_bridge, pg_count, type); - if (memory == NULL) - return NULL; - - agp_insert_into_pool(memory); - return memory; -} - -/* Routines for managing the list of controllers - - * These routines manage the current controller, and the list of - * controllers - */ - -static struct agp_controller *agp_find_controller_by_pid(pid_t id) -{ - struct agp_controller *controller; - - controller = agp_fe.controllers; - - while (controller != NULL) { - if (controller->pid == id) - return controller; - controller = controller->next; - } - - return NULL; -} - -static struct agp_controller *agp_create_controller(pid_t id) -{ - struct agp_controller *controller; - - controller = kzalloc(sizeof(struct agp_controller), GFP_KERNEL); - if (controller == NULL) - return NULL; - - controller->pid = id; - return controller; -} - -static int agp_insert_controller(struct agp_controller *controller) -{ - struct agp_controller *prev_controller; - - prev_controller = agp_fe.controllers; - controller->next = prev_controller; - - if (prev_controller != NULL) - prev_controller->prev = controller; - - agp_fe.controllers = controller; - - return 0; -} - -static void agp_remove_all_clients(struct agp_controller *controller) -{ - struct agp_client *client; - struct agp_client *temp; - - client = controller->clients; - - while (client) { - struct agp_file_private *priv; - - temp = client; - agp_remove_seg_from_client(temp); - priv = agp_find_private(temp->pid); - - if (priv != NULL) { - clear_bit(AGP_FF_IS_VALID, &priv->access_flags); - clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - } - client = client->next; - kfree(temp); - } -} - -static void agp_remove_all_memory(struct agp_controller *controller) -{ - struct agp_memory *memory; - struct agp_memory *temp; - - memory = controller->pool; - - while (memory) { - temp = memory; - memory = memory->next; - agp_free_memory_wrap(temp); - } -} - -static int agp_remove_controller(struct agp_controller *controller) -{ - struct agp_controller *prev_controller; - struct agp_controller *next_controller; - - prev_controller = controller->prev; - next_controller = controller->next; - - if (prev_controller != NULL) { - prev_controller->next = next_controller; - if (next_controller != NULL) - next_controller->prev = prev_controller; - - } else { - if (next_controller != NULL) - next_controller->prev = NULL; - - agp_fe.controllers = next_controller; - } - - agp_remove_all_memory(controller); - agp_remove_all_clients(controller); - - if (agp_fe.current_controller == controller) { - agp_fe.current_controller = NULL; - agp_fe.backend_acquired = false; - agp_backend_release(agp_bridge); - } - kfree(controller); - return 0; -} - -static void agp_controller_make_current(struct agp_controller *controller) -{ - struct agp_client *clients; - - clients = controller->clients; - - while (clients != NULL) { - struct agp_file_private *priv; - - priv = agp_find_private(clients->pid); - - if (priv != NULL) { - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - } - clients = clients->next; - } - - agp_fe.current_controller = controller; -} - -static void agp_controller_release_current(struct agp_controller *controller, - struct agp_file_private *controller_priv) -{ - struct agp_client *clients; - - clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); - clients = controller->clients; - - while (clients != NULL) { - struct agp_file_private *priv; - - priv = agp_find_private(clients->pid); - - if (priv != NULL) - clear_bit(AGP_FF_IS_VALID, &priv->access_flags); - - clients = clients->next; - } - - agp_fe.current_controller = NULL; - agp_fe.used_by_controller = false; - agp_backend_release(agp_bridge); -} - -/* - * Routines for managing client lists - - * These routines are for managing the list of auth'ed clients. - */ - -static struct agp_client -*agp_find_client_in_controller(struct agp_controller *controller, pid_t id) -{ - struct agp_client *client; - - if (controller == NULL) - return NULL; - - client = controller->clients; - - while (client != NULL) { - if (client->pid == id) - return client; - client = client->next; - } - - return NULL; -} - -static struct agp_controller *agp_find_controller_for_client(pid_t id) -{ - struct agp_controller *controller; - - controller = agp_fe.controllers; - - while (controller != NULL) { - if ((agp_find_client_in_controller(controller, id)) != NULL) - return controller; - controller = controller->next; - } - - return NULL; -} - -struct agp_client *agp_find_client_by_pid(pid_t id) -{ - struct agp_client *temp; - - if (agp_fe.current_controller == NULL) - return NULL; - - temp = agp_find_client_in_controller(agp_fe.current_controller, id); - return temp; -} - -static void agp_insert_client(struct agp_client *client) -{ - struct agp_client *prev_client; - - prev_client = agp_fe.current_controller->clients; - client->next = prev_client; - - if (prev_client != NULL) - prev_client->prev = client; - - agp_fe.current_controller->clients = client; - agp_fe.current_controller->num_clients++; -} - -struct agp_client *agp_create_client(pid_t id) -{ - struct agp_client *new_client; - - new_client = kzalloc(sizeof(struct agp_client), GFP_KERNEL); - if (new_client == NULL) - return NULL; - - new_client->pid = id; - agp_insert_client(new_client); - return new_client; -} - -int agp_remove_client(pid_t id) -{ - struct agp_client *client; - struct agp_client *prev_client; - struct agp_client *next_client; - struct agp_controller *controller; - - controller = agp_find_controller_for_client(id); - if (controller == NULL) - return -EINVAL; - - client = agp_find_client_in_controller(controller, id); - if (client == NULL) - return -EINVAL; - - prev_client = client->prev; - next_client = client->next; - - if (prev_client != NULL) { - prev_client->next = next_client; - if (next_client != NULL) - next_client->prev = prev_client; - - } else { - if (next_client != NULL) - next_client->prev = NULL; - controller->clients = next_client; - } - - controller->num_clients--; - agp_remove_seg_from_client(client); - kfree(client); - return 0; -} - -/* End - Routines for managing client lists */ - -/* File Operations */ - -static int agp_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned int size, current_size; - unsigned long offset; - struct agp_client *client; - struct agp_file_private *priv = file->private_data; - struct agp_kern_info kerninfo; - - mutex_lock(&(agp_fe.agp_mutex)); - - if (agp_fe.backend_acquired != true) - goto out_eperm; - - if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) - goto out_eperm; - - agp_copy_info(agp_bridge, &kerninfo); - size = vma->vm_end - vma->vm_start; - current_size = kerninfo.aper_size; - current_size = current_size * 0x100000; - offset = vma->vm_pgoff << PAGE_SHIFT; - DBG("%lx:%lx", offset, offset+size); - - if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { - if ((size + offset) > current_size) - goto out_inval; - - client = agp_find_client_by_pid(current->pid); - - if (client == NULL) - goto out_eperm; - - if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot)) - goto out_inval; - - DBG("client vm_ops=%p", kerninfo.vm_ops); - if (kerninfo.vm_ops) { - vma->vm_ops = kerninfo.vm_ops; - } else if (io_remap_pfn_range(vma, vma->vm_start, - (kerninfo.aper_base + offset) >> PAGE_SHIFT, - size, - pgprot_writecombine(vma->vm_page_prot))) { - goto out_again; - } - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; - } - - if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { - if (size != current_size) - goto out_inval; - - DBG("controller vm_ops=%p", kerninfo.vm_ops); - if (kerninfo.vm_ops) { - vma->vm_ops = kerninfo.vm_ops; - } else if (io_remap_pfn_range(vma, vma->vm_start, - kerninfo.aper_base >> PAGE_SHIFT, - size, - pgprot_writecombine(vma->vm_page_prot))) { - goto out_again; - } - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; - } - -out_eperm: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EPERM; - -out_inval: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EINVAL; - -out_again: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EAGAIN; -} - -static int agp_release(struct inode *inode, struct file *file) -{ - struct agp_file_private *priv = file->private_data; - - mutex_lock(&(agp_fe.agp_mutex)); - - DBG("priv=%p", priv); - - if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { - struct agp_controller *controller; - - controller = agp_find_controller_by_pid(priv->my_pid); - - if (controller != NULL) { - if (controller == agp_fe.current_controller) - agp_controller_release_current(controller, priv); - agp_remove_controller(controller); - controller = NULL; - } - } - - if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) - agp_remove_client(priv->my_pid); - - agp_remove_file_private(priv); - kfree(priv); - file->private_data = NULL; - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; -} - -static int agp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct agp_file_private *priv; - struct agp_client *client; - - if (minor != AGPGART_MINOR) - return -ENXIO; - - mutex_lock(&(agp_fe.agp_mutex)); - - priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL); - if (priv == NULL) { - mutex_unlock(&(agp_fe.agp_mutex)); - return -ENOMEM; - } - - set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); - priv->my_pid = current->pid; - - if (capable(CAP_SYS_RAWIO)) - /* Root priv, can be controller */ - set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); - - client = agp_find_client_by_pid(current->pid); - - if (client != NULL) { - set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - } - file->private_data = (void *) priv; - agp_insert_file_private(priv); - DBG("private=%p, client=%p", priv, client); - - mutex_unlock(&(agp_fe.agp_mutex)); - - return 0; -} - -static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_info userinfo; - struct agp_kern_info kerninfo; - - agp_copy_info(agp_bridge, &kerninfo); - - memset(&userinfo, 0, sizeof(userinfo)); - userinfo.version.major = kerninfo.version.major; - userinfo.version.minor = kerninfo.version.minor; - userinfo.bridge_id = kerninfo.device->vendor | - (kerninfo.device->device << 16); - userinfo.agp_mode = kerninfo.mode; - userinfo.aper_base = kerninfo.aper_base; - userinfo.aper_size = kerninfo.aper_size; - userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; - userinfo.pg_used = kerninfo.current_memory; - - if (copy_to_user(arg, &userinfo, sizeof(struct agp_info))) - return -EFAULT; - - return 0; -} - -int agpioc_acquire_wrap(struct agp_file_private *priv) -{ - struct agp_controller *controller; - - DBG(""); - - if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) - return -EPERM; - - if (agp_fe.current_controller != NULL) - return -EBUSY; - - if (!agp_bridge) - return -ENODEV; - - if (atomic_read(&agp_bridge->agp_in_use)) - return -EBUSY; - - atomic_inc(&agp_bridge->agp_in_use); - - agp_fe.backend_acquired = true; - - controller = agp_find_controller_by_pid(priv->my_pid); - - if (controller != NULL) { - agp_controller_make_current(controller); - } else { - controller = agp_create_controller(priv->my_pid); - - if (controller == NULL) { - agp_fe.backend_acquired = false; - agp_backend_release(agp_bridge); - return -ENOMEM; - } - agp_insert_controller(controller); - agp_controller_make_current(controller); - } - - set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags); - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - return 0; -} - -int agpioc_release_wrap(struct agp_file_private *priv) -{ - DBG(""); - agp_controller_release_current(agp_fe.current_controller, priv); - return 0; -} - -int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_setup mode; - - DBG(""); - if (copy_from_user(&mode, arg, sizeof(struct agp_setup))) - return -EFAULT; - - agp_enable(agp_bridge, mode.agp_mode); - return 0; -} - -static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_region reserve; - struct agp_client *client; - struct agp_file_private *client_priv; - - DBG(""); - if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) - return -EFAULT; - - if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) - return -EFAULT; - - client = agp_find_client_by_pid(reserve.pid); - - if (reserve.seg_count == 0) { - /* remove a client */ - client_priv = agp_find_private(reserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - if (client == NULL) { - /* client is already removed */ - return 0; - } - return agp_remove_client(reserve.pid); - } else { - struct agp_segment *segment; - - if (reserve.seg_count >= 16384) - return -EINVAL; - - segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count), - GFP_KERNEL); - - if (segment == NULL) - return -ENOMEM; - - if (copy_from_user(segment, (void __user *) reserve.seg_list, - sizeof(struct agp_segment) * reserve.seg_count)) { - kfree(segment); - return -EFAULT; - } - reserve.seg_list = segment; - - if (client == NULL) { - /* Create the client and add the segment */ - client = agp_create_client(reserve.pid); - - if (client == NULL) { - kfree(segment); - return -ENOMEM; - } - client_priv = agp_find_private(reserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - } - return agp_create_segment(client, &reserve); - } - /* Will never really happen */ - return -EINVAL; -} - -int agpioc_protect_wrap(struct agp_file_private *priv) -{ - DBG(""); - /* This function is not currently implemented */ - return -EINVAL; -} - -static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_allocate alloc; - - DBG(""); - if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate))) - return -EFAULT; - - if (alloc.type >= AGP_USER_TYPES) - return -EINVAL; - - memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); - - if (memory == NULL) - return -ENOMEM; - - alloc.key = memory->key; - alloc.physical = memory->physical; - - if (copy_to_user(arg, &alloc, sizeof(struct agp_allocate))) { - agp_free_memory_wrap(memory); - return -EFAULT; - } - return 0; -} - -int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) -{ - struct agp_memory *memory; - - DBG(""); - memory = agp_find_mem_by_key(arg); - - if (memory == NULL) - return -EINVAL; - - agp_free_memory_wrap(memory); - return 0; -} - -static int agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_bind bind_info; - struct agp_memory *memory; - - DBG(""); - if (copy_from_user(&bind_info, arg, sizeof(struct agp_bind))) - return -EFAULT; - - memory = agp_find_mem_by_key(bind_info.key); - - if (memory == NULL) - return -EINVAL; - - return agp_bind_memory(memory, bind_info.pg_start); -} - -static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_unbind unbind; - - DBG(""); - if (copy_from_user(&unbind, arg, sizeof(struct agp_unbind))) - return -EFAULT; - - memory = agp_find_mem_by_key(unbind.key); - - if (memory == NULL) - return -EINVAL; - - return agp_unbind_memory(memory); -} - -static long agp_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct agp_file_private *curr_priv = file->private_data; - int ret_val = -ENOTTY; - - DBG("priv=%p, cmd=%x", curr_priv, cmd); - mutex_lock(&(agp_fe.agp_mutex)); - - if ((agp_fe.current_controller == NULL) && - (cmd != AGPIOC_ACQUIRE)) { - ret_val = -EINVAL; - goto ioctl_out; - } - if ((agp_fe.backend_acquired != true) && - (cmd != AGPIOC_ACQUIRE)) { - ret_val = -EBUSY; - goto ioctl_out; - } - if (cmd != AGPIOC_ACQUIRE) { - if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { - ret_val = -EPERM; - goto ioctl_out; - } - /* Use the original pid of the controller, - * in case it's threaded */ - - if (agp_fe.current_controller->pid != curr_priv->my_pid) { - ret_val = -EBUSY; - goto ioctl_out; - } - } - - switch (cmd) { - case AGPIOC_INFO: - ret_val = agpioc_info_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_ACQUIRE: - ret_val = agpioc_acquire_wrap(curr_priv); - break; - - case AGPIOC_RELEASE: - ret_val = agpioc_release_wrap(curr_priv); - break; - - case AGPIOC_SETUP: - ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_RESERVE: - ret_val = agpioc_reserve_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_PROTECT: - ret_val = agpioc_protect_wrap(curr_priv); - break; - - case AGPIOC_ALLOCATE: - ret_val = agpioc_allocate_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_DEALLOCATE: - ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); - break; - - case AGPIOC_BIND: - ret_val = agpioc_bind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_UNBIND: - ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_CHIPSET_FLUSH: - break; - } - -ioctl_out: - DBG("ioctl returns %d\n", ret_val); - mutex_unlock(&(agp_fe.agp_mutex)); - return ret_val; -} - -static const struct file_operations agp_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = agp_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_agp_ioctl, -#endif - .mmap = agp_mmap, - .open = agp_open, - .release = agp_release, -}; - -static struct miscdevice agp_miscdev = -{ - .minor = AGPGART_MINOR, - .name = "agpgart", - .fops = &agp_fops -}; - -int agp_frontend_initialize(void) -{ - memset(&agp_fe, 0, sizeof(struct agp_front_data)); - mutex_init(&(agp_fe.agp_mutex)); - - if (misc_register(&agp_miscdev)) { - printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); - return -EIO; - } - return 0; -} - -void agp_frontend_cleanup(void) -{ - misc_deregister(&agp_miscdev); -} From 94f8f319cbcbddce8f82bfaf8ed39eb57efdd457 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 22 Nov 2023 13:09:43 +0100 Subject: [PATCH 2756/7721] drm: Remove Kconfig option for legacy support (CONFIG_DRM_LEGACY) Remove CONFIG_DRM_LEGACY from Kconfig. Nothing depends on the option. Signed-off-by: Thomas Zimmermann Reviewed-by: David Airlie Reviewed-by: Daniel Vetter Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231122122449.11588-15-tzimmermann@suse.de --- drivers/gpu/drm/Kconfig | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index b7abd436455f..31cfe2c2a2af 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -410,27 +410,6 @@ config DRM_HYPERV If M is selected the module will be called hyperv_drm. -# Keep legacy drivers last - -menuconfig DRM_LEGACY - bool "Enable legacy drivers (DANGEROUS)" - depends on DRM && MMU - help - Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous - APIs to user-space, which can be used to circumvent access - restrictions and other security measures. For backwards compatibility - those drivers are still available, but their use is highly - inadvisable and might harm your system. - - You are recommended to use the safe modeset-only drivers instead, and - perform 3D emulation in user-space. - - Unless you have strong reasons to go rogue, say "N". - -if DRM_LEGACY -# leave here to list legacy drivers -endif # DRM_LEGACY - config DRM_EXPORT_FOR_TESTS bool From e843ca2f30e630675e2d2a75c96f4844f2854430 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 03:24:37 +0300 Subject: [PATCH 2757/7721] drm/msm/dpu: correct clk bit for WB2 block On sc7280 there are two clk bits for WB2: vbif_cli and clk_ctrl. While programming the VBIF params of WB, the driver should be toggling the former bit, while the sc7180_mdp, sc7280_mdp and sm8250_mdp structs list the latter one. Correct that to ensure proper programming sequence for WB2 on these platforms. Fixes: 255f056181ac ("drm/msm/dpu: sc7180: add missing WB2 clock control") Fixes: 3ce166380567 ("drm/msm/dpu: add writeback support for sc7280") Fixes: 53324b99bd7b ("drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Tested-by: Paloma Arellano Patchwork: https://patchwork.freedesktop.org/patch/570185/ Link: https://lore.kernel.org/r/20231203002437.1291595-1-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h | 2 +- drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h | 2 +- drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 9acf07108899..2359c16e9206 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -31,7 +31,7 @@ static const struct dpu_mdp_cfg sm8250_mdp = { [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index 783269c6ead1..bcfedfc8251a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -24,7 +24,7 @@ static const struct dpu_mdp_cfg sc7180_mdp = { [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 93564e9e5fa5..209675de6742 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -24,7 +24,7 @@ static const struct dpu_mdp_cfg sc7280_mdp = { [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; From ebd6292926d88c1b2614f809b51367ee3dc8955e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Dec 2023 11:47:13 -0300 Subject: [PATCH 2758/7721] ARM: dts: imx23/28: Remove undocumented "fsl,clkctrl" Per imx23-clock.yaml and imx28-clock.yaml, fsl,clkctrl is not a valid compatible string. Remove it to fix the following dt-schema warning: imx28-evk.dtb: clkctrl@80040000: compatible: ['fsl,imx28-clkctrl', 'fsl,clkctrl'] is too long from schema $id: http://devicetree.org/schemas/clock/imx28-clock.yaml# Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/mxs/imx23.dtsi | 2 +- arch/arm/boot/dts/nxp/mxs/imx28.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi index 60bd88585bb4..7d82c03ef402 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi @@ -484,7 +484,7 @@ apbx@80040000 { ranges; clks: clkctrl@80040000 { - compatible = "fsl,imx23-clkctrl", "fsl,clkctrl"; + compatible = "fsl,imx23-clkctrl"; reg = <0x80040000 0x2000>; #clock-cells = <1>; }; diff --git a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi index 409952feec2c..9817ef7c0880 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi @@ -1100,7 +1100,7 @@ apbx@80040000 { ranges; clks: clkctrl@80040000 { - compatible = "fsl,imx28-clkctrl", "fsl,clkctrl"; + compatible = "fsl,imx28-clkctrl"; reg = <0x80040000 0x2000>; #clock-cells = <1>; }; From a0fce84cb1b3b88d3d5853f7ac5f1a3ef7e38620 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:46 +0100 Subject: [PATCH 2759/7721] drm/plane-helper: Move drm_plane_helper_atomic_check() into udl The udl driver is the only caller of drm_plane_helper_atomic_check(). Move the function into the driver. No functional changes. v2: * fix documenation (Sui) Signed-off-by: Thomas Zimmermann Reviewed-by: Alex Deucher Acked-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_crtc_helper.c | 7 ++----- drivers/gpu/drm/drm_plane_helper.c | 32 ------------------------------ drivers/gpu/drm/udl/udl_modeset.c | 19 ++++++++++++++++-- include/drm/drm_plane_helper.h | 2 -- 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a209659a996c..2dafc39a27cb 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -439,11 +439,8 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode); * @state: atomic state object * * Provides a default CRTC-state check handler for CRTCs that only have - * one primary plane attached to it. - * - * This is often the case for the CRTC of simple framebuffers. See also - * drm_plane_helper_atomic_check() for the respective plane-state check - * helper function. + * one primary plane attached to it. This is often the case for the CRTC + * of simple framebuffers. * * RETURNS: * Zero on success, or an errno code otherwise. diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5e95089676ff..7982be4b0306 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -279,35 +279,3 @@ void drm_plane_helper_destroy(struct drm_plane *plane) kfree(plane); } EXPORT_SYMBOL(drm_plane_helper_destroy); - -/** - * drm_plane_helper_atomic_check() - Helper to check plane atomic-state - * @plane: plane to check - * @state: atomic state object - * - * Provides a default plane-state check handler for planes whose atomic-state - * scale and positioning are not expected to change since the plane is always - * a fullscreen scanout buffer. - * - * This is often the case for the primary plane of simple framebuffers. See - * also drm_crtc_helper_atomic_check() for the respective CRTC-state check - * helper function. - * - * RETURNS: - * Zero on success, or an errno code otherwise. - */ -int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); - struct drm_crtc *new_crtc = new_plane_state->crtc; - struct drm_crtc_state *new_crtc_state = NULL; - - if (new_crtc) - new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); - - return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); -} -EXPORT_SYMBOL(drm_plane_helper_atomic_check); diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 40876bcdd79a..7702359c90c2 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -261,6 +260,22 @@ static const uint64_t udl_primary_plane_fmtmods[] = { DRM_FORMAT_MOD_INVALID }; +static int udl_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -296,7 +311,7 @@ static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, - .atomic_check = drm_plane_helper_atomic_check, + .atomic_check = udl_primary_plane_helper_atomic_check, .atomic_update = udl_primary_plane_helper_atomic_update, }; diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 3a574e8cd22f..75f9c4830564 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -26,7 +26,6 @@ #include -struct drm_atomic_state; struct drm_crtc; struct drm_framebuffer; struct drm_modeset_acquire_ctx; @@ -42,7 +41,6 @@ int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *cr int drm_plane_helper_disable_primary(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); void drm_plane_helper_destroy(struct drm_plane *plane); -int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state); /** * DRM_PLANE_NON_ATOMIC_FUNCS - Default plane functions for non-atomic drivers From bb8532601260209d1ee40c52d15e98578b703e47 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:47 +0100 Subject: [PATCH 2760/7721] drm/amdgpu: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Alex Deucher Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-3-tzimmermann@suse.de --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index aa43f1761acd..b8c3a9b104a4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -92,7 +92,6 @@ #include #include #include -#include #include From 85ddae2392b5673aa4bda3c7d14d205d1ed069fe Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:48 +0100 Subject: [PATCH 2761/7721] drm/loongson: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sui Jingfeng Reviewed-by: Alex Deucher Tested-by: Sui Jingfeng Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-4-tzimmermann@suse.de --- drivers/gpu/drm/loongson/lsdc_plane.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/loongson/lsdc_plane.c b/drivers/gpu/drm/loongson/lsdc_plane.c index 0d5094633222..d227a2c1dcf1 100644 --- a/drivers/gpu/drm/loongson/lsdc_plane.c +++ b/drivers/gpu/drm/loongson/lsdc_plane.c @@ -9,7 +9,6 @@ #include #include #include -#include #include "lsdc_drv.h" #include "lsdc_regs.h" From 2887875256d486c0cbb544e67932526bd681e209 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:49 +0100 Subject: [PATCH 2762/7721] drm/shmobile: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Geert Uytterhoeven Reviewed-by: Alex Deucher Acked-by: Geert Uytterhoeven Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-5-tzimmermann@suse.de --- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 8f9a728affde..07ad17d24294 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "shmob_drm_drv.h" #include "shmob_drm_kms.h" From 9e8f373e8a77c5192532bab6ea267b329fe66b77 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:50 +0100 Subject: [PATCH 2763/7721] drm/solomon: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Geert Uytterhoeven Reviewed-by: Javier Martinez Canillas Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-6-tzimmermann@suse.de --- drivers/gpu/drm/solomon/ssd130x.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index acf7cedf0c1a..075c5c3ee75a 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -17,7 +17,6 @@ #include #include #include -#include #include From 7e661a06998e06455563b2ff6198c7f3efe31cf2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:51 +0100 Subject: [PATCH 2764/7721] drm/ofdrm: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sui Jingfeng Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-7-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 05a72473cfc6..ab89b7fc7bf6 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include From 81b32f4393cde612e022ff35b556b28001350d3b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:52 +0100 Subject: [PATCH 2765/7721] drm/simpledrm: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sui Jingfeng Reviewed-by: Javier Martinez Canillas Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-8-tzimmermann@suse.de --- drivers/gpu/drm/tiny/simpledrm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 34bbbd7b53dd..7ce1c4617675 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #define DRIVER_NAME "simpledrm" From aa5d7cf88bdebe5376970d79878f16d28536f7e2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 4 Dec 2023 10:07:53 +0100 Subject: [PATCH 2766/7721] drm/xlnx: Do not include Remove unnecessary include statements for . The file contains helpers for non-atomic code and should not be required by most drivers. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Laurent Pinchart Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231204090852.1650-9-tzimmermann@suse.de --- drivers/gpu/drm/xlnx/zynqmp_kms.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index a7f8611be6f4..db3bb4afbfc4 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include From 4a23d0f9814c38308dc82b6dbc466666a400b27d Mon Sep 17 00:00:00 2001 From: Ashish Mhetre Date: Tue, 5 Dec 2023 11:30:45 +0530 Subject: [PATCH 2767/7721] memory: tegra: Protect SID override call under CONFIG_IOMMU_API tegra186_mc_client_sid_override() is protected under CONFIG_IOMMU_API. Call to this function is being made from tegra186_mc_resume() without any protection which is leading to build failure when CONFIG_IOMMU_API is not set. Fix this by protecting SID override function call from tegra186_mc_resume() under CONFIG_IOMMU_API. Fixes: fe3b082a6eb8 ("memory: tegra: Add SID override programming for MC clients") Signed-off-by: Ashish Mhetre Reported-by: Randy Dunlap Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Link: https://lore.kernel.org/r/20231205060045.7985-1-amhetre@nvidia.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra186.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index d1f1dfb42716..0ff014a9d3cd 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -141,6 +141,7 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) static int tegra186_mc_resume(struct tegra_mc *mc) { +#if IS_ENABLED(CONFIG_IOMMU_API) unsigned int i; for (i = 0; i < mc->soc->num_clients; i++) { @@ -148,6 +149,7 @@ static int tegra186_mc_resume(struct tegra_mc *mc) tegra186_mc_client_sid_override(mc, client, client->sid); } +#endif return 0; } From a3a44d2d3a5c5ff6e73c711db5b1911b5a676bb0 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 5 Dec 2023 09:50:30 +0800 Subject: [PATCH 2768/7721] HID: Intel-ish-hid: Ishtp: Add helper functions for client connection For every ishtp client driver during initialization state, the flow is: 1 - Allocate an ISHTP client instance 2 - Reserve a host id and link the client instance 3 - Search a firmware client using UUID and get related client information 4 - Bind firmware client id to the ISHTP client instance 5 - Set the state the ISHTP client instance to CONNECTING 6 - Send connect request to firmware 7 - Register event callback for messages from the firmware During deinitizalization state, the flow is: 9 - Set the state the ISHTP client instance to ISHTP_CL_DISCONNECTING 10 - Issue disconnect request to firmware 11 - Unlike the client instance 12 - Flush message queue 13 - Free ISHTP client instance Step 2-7 are identical to the steps of client driver initialization and driver reset flow, but reallocation of the RX/TX ring buffers can be avoided in reset flow. Also for step 9-12, they are identical to the steps of client driver failure handling after connect request, driver reset flow and driver removing. So, add two helper functions to simplify client driver code. ishtp_cl_establish_connection() ishtp_cl_destroy_connection() No functional changes are expected. Signed-off-by: Even Xu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp/client.c | 185 +++++++++++++++++++++-- include/linux/intel-ish-client-if.h | 3 + 2 files changed, 177 insertions(+), 11 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c index 2d92fc129ce4..82c907f01bd3 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.c +++ b/drivers/hid/intel-ish-hid/ishtp/client.c @@ -339,16 +339,17 @@ static bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl) } /** - * ishtp_cl_connect() - Send connect request to firmware + * ishtp_cl_connect_to_fw() - Send connect request to firmware * @cl: client device instance * - * Send a connect request for a client to firmware. If successful it will - * RX and TX ring buffers + * Send a connect request to the firmware and wait for firmware response. + * If there is successful connection response from the firmware, change + * client state to ISHTP_CL_CONNECTED, and bind client to related + * firmware client_id. * - * Return: 0 if successful connect response from the firmware and able - * to bind and allocate ring buffers or error code on failure + * Return: 0 for success and error code on failure */ -int ishtp_cl_connect(struct ishtp_cl *cl) +static int ishtp_cl_connect_to_fw(struct ishtp_cl *cl) { struct ishtp_device *dev; int rets; @@ -358,8 +359,6 @@ int ishtp_cl_connect(struct ishtp_cl *cl) dev = cl->dev; - dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); - if (ishtp_cl_is_other_connecting(cl)) { dev->print_log(dev, "%s() Busy\n", __func__); return -EBUSY; @@ -405,6 +404,38 @@ int ishtp_cl_connect(struct ishtp_cl *cl) return rets; } + return rets; +} + +/** + * ishtp_cl_connect() - Build connection with firmware + * @cl: client device instance + * + * Call ishtp_cl_connect_to_fw() to connect and bind to firmware. If successful, + * allocate RX and TX ring buffers, and start flow control with firmware to + * start communication. + * + * Return: 0 if there is successful connection to the firmware, allocate + * ring buffers. + */ +int ishtp_cl_connect(struct ishtp_cl *cl) +{ + struct ishtp_device *dev; + int rets; + + if (!cl || !cl->dev) + return -ENODEV; + + dev = cl->dev; + + dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); + + rets = ishtp_cl_connect_to_fw(cl); + if (rets) { + dev->print_log(dev, "%s() Connect to fw failed\n", __func__); + return rets; + } + rets = ishtp_cl_alloc_rx_ring(cl); if (rets) { dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__); @@ -422,15 +453,147 @@ int ishtp_cl_connect(struct ishtp_cl *cl) return rets; } - /* Upon successful connection and allocation, emit flow-control */ + /* + * Upon successful connection and allocation, start flow-control. + */ rets = ishtp_cl_read_start(cl); - dev->print_log(dev, "%s() successful\n", __func__); - return rets; } EXPORT_SYMBOL(ishtp_cl_connect); +/** + * ishtp_cl_establish_connection() - Establish connection with the firmware + * @cl: client device instance + * @uuid: uuid of the client to search + * @tx_size: TX ring buffer size + * @rx_size: RX ring buffer size + * @reset: true if called for reset connection, otherwise for first connection + * + * This is a helper function for client driver to build connection with firmware. + * If it's first time connecting to the firmware, set reset to false, this + * function will link client to bus, find client id and send connect request to + * the firmware. + * + * If it's called for reset handler where client lost connection after + * firmware reset, set reset to true, this function will reinit client state and + * establish connection again. In this case, this function reuses current client + * structure and ring buffers to avoid allocation failure and memory fragments. + * + * Return: 0 for successful connection with the firmware, + * or error code on failure + */ +int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid, + int tx_size, int rx_size, bool reset) +{ + struct ishtp_device *dev; + struct ishtp_fw_client *fw_client; + int rets; + + if (!cl || !cl->dev) + return -ENODEV; + + dev = cl->dev; + + ishtp_set_connection_state(cl, ISHTP_CL_INITIALIZING); + + /* reinit ishtp_cl structure if call for reset */ + if (reset) { + cl->host_client_id = 0; + cl->fw_client_id = 0; + cl->ishtp_flow_ctrl_creds = 0; + cl->out_flow_ctrl_creds = 0; + + cl->last_tx_path = CL_TX_PATH_IPC; + cl->last_dma_acked = 1; + cl->last_dma_addr = NULL; + cl->last_ipc_acked = 1; + + cl->sending = 0; + cl->err_send_msg = 0; + cl->err_send_fc = 0; + + cl->send_msg_cnt_ipc = 0; + cl->send_msg_cnt_dma = 0; + cl->recv_msg_cnt_ipc = 0; + cl->recv_msg_cnt_dma = 0; + cl->recv_msg_num_frags = 0; + cl->ishtp_flow_ctrl_cnt = 0; + cl->out_flow_ctrl_cnt = 0; + } + + /* link to bus */ + rets = ishtp_cl_link(cl); + if (rets) { + dev->print_log(dev, "%s() ishtp_cl_link failed\n", __func__); + return rets; + } + + /* find firmware client */ + fw_client = ishtp_fw_cl_get_client(dev, uuid); + if (!fw_client) { + dev->print_log(dev, + "%s() ish client uuid not found\n", __func__); + return -ENOENT; + } + + ishtp_set_tx_ring_size(cl, tx_size); + ishtp_set_rx_ring_size(cl, rx_size); + + ishtp_cl_set_fw_client_id(cl, ishtp_get_fw_client_id(fw_client)); + + ishtp_set_connection_state(cl, ISHTP_CL_CONNECTING); + + /* + * For reset case, not allocate tx/rx ring buffer which are already + * done in ishtp_cl_connect() during first connection. + */ + if (reset) { + rets = ishtp_cl_connect_to_fw(cl); + if (!rets) + rets = ishtp_cl_read_start(cl); + else + dev->print_log(dev, + "%s() connect to fw failed\n", __func__); + } else { + rets = ishtp_cl_connect(cl); + } + + return rets; +} +EXPORT_SYMBOL(ishtp_cl_establish_connection); + +/** + * ishtp_cl_destroy_connection() - Disconnect with the firmware + * @cl: client device instance + * @reset: true if called for firmware reset, false for normal disconnection + * + * This is a helper function for client driver to disconnect with firmware, + * unlink to bus and flush message queue. + */ +void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset) +{ + if (!cl) + return; + + if (reset) { + /* + * For reset case, connection is already lost during fw reset. + * Just set state to DISCONNECTED is enough. + */ + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTED); + } else { + if (cl->state != ISHTP_CL_DISCONNECTED) { + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTING); + ishtp_cl_disconnect(cl); + } + } + + ishtp_cl_unlink(cl); + ishtp_cl_flush_queues(cl); +} +EXPORT_SYMBOL(ishtp_cl_destroy_connection); + /** * ishtp_cl_read_start() - Prepare to read client message * @cl: client device instance diff --git a/include/linux/intel-ish-client-if.h b/include/linux/intel-ish-client-if.h index f45f13304add..771622650247 100644 --- a/include/linux/intel-ish-client-if.h +++ b/include/linux/intel-ish-client-if.h @@ -94,6 +94,9 @@ int ishtp_cl_link(struct ishtp_cl *cl); void ishtp_cl_unlink(struct ishtp_cl *cl); int ishtp_cl_disconnect(struct ishtp_cl *cl); int ishtp_cl_connect(struct ishtp_cl *cl); +int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid, + int tx_size, int rx_size, bool reset); +void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset); int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length); int ishtp_cl_flush_queues(struct ishtp_cl *cl); int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb); From f645a90e8ff732c48dd9f18815baef08c44ac8a0 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 5 Dec 2023 09:50:31 +0800 Subject: [PATCH 2769/7721] HID: intel-ish-hid: ishtp-hid-client: use helper functions for connection Use helper functions ishtp_cl_establish_connection() and ishtp_cl_destroy_connection() to establish and destroy connection respectively. These functions are used during initialization, reset and deinitialization flows. No functional changes are expected. Signed-off-by: Even Xu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 63 ++++---------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index e3d70c5460e9..fbd4f8ea1951 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -639,47 +639,26 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl, * * Return: 0 on success, non zero on error */ -static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) +static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, bool reset) { - struct ishtp_device *dev; struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); - struct ishtp_fw_client *fw_client; int i; int rv; dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__); hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset); - rv = ishtp_cl_link(hid_ishtp_cl); - if (rv) { - dev_err(cl_data_to_dev(client_data), - "ishtp_cl_link failed\n"); - return -ENOMEM; - } - client_data->init_done = 0; - dev = ishtp_get_ishtp_device(hid_ishtp_cl); - - /* Connect to FW client */ - ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE); - ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE); - - fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_id_table[0].guid); - if (!fw_client) { - dev_err(cl_data_to_dev(client_data), - "ish client uuid not found\n"); - return -ENOENT; - } - ishtp_cl_set_fw_client_id(hid_ishtp_cl, - ishtp_get_fw_client_id(fw_client)); - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING); - - rv = ishtp_cl_connect(hid_ishtp_cl); + rv = ishtp_cl_establish_connection(hid_ishtp_cl, + &hid_ishtp_id_table[0].guid, + HID_CL_TX_RING_SIZE, + HID_CL_RX_RING_SIZE, + reset); if (rv) { dev_err(cl_data_to_dev(client_data), "client connect fail\n"); - goto err_cl_unlink; + goto err_cl_disconnect; } hid_ishtp_trace(client_data, "%s client connected\n", __func__); @@ -723,10 +702,7 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) return 0; err_cl_disconnect: - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING); - ishtp_cl_disconnect(hid_ishtp_cl); -err_cl_unlink: - ishtp_cl_unlink(hid_ishtp_cl); + ishtp_cl_destroy_connection(hid_ishtp_cl, reset); return rv; } @@ -738,8 +714,7 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) */ static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl) { - ishtp_cl_unlink(hid_ishtp_cl); - ishtp_cl_flush_queues(hid_ishtp_cl); + ishtp_cl_destroy_connection(hid_ishtp_cl, false); /* disband and free all Tx and Rx client-level rings */ ishtp_cl_free(hid_ishtp_cl); @@ -749,33 +724,23 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work) { struct ishtp_cl_data *client_data; struct ishtp_cl *hid_ishtp_cl; - struct ishtp_cl_device *cl_device; int retry; int rv; client_data = container_of(work, struct ishtp_cl_data, work); hid_ishtp_cl = client_data->hid_ishtp_cl; - cl_device = client_data->cl_device; hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_cl); dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__); - hid_ishtp_cl_deinit(hid_ishtp_cl); - - hid_ishtp_cl = ishtp_cl_allocate(cl_device); - if (!hid_ishtp_cl) - return; - - ishtp_set_drvdata(cl_device, hid_ishtp_cl); - ishtp_set_client_data(hid_ishtp_cl, client_data); - client_data->hid_ishtp_cl = hid_ishtp_cl; + ishtp_cl_destroy_connection(hid_ishtp_cl, true); client_data->num_hid_devices = 0; for (retry = 0; retry < 3; ++retry) { - rv = hid_ishtp_cl_init(hid_ishtp_cl, 1); + rv = hid_ishtp_cl_init(hid_ishtp_cl, true); if (!rv) break; dev_err(cl_data_to_dev(client_data), "Retry reset init\n"); @@ -841,7 +806,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) ishtp_hid_print_trace = ishtp_trace_callback(cl_device); - rv = hid_ishtp_cl_init(hid_ishtp_cl, 0); + rv = hid_ishtp_cl_init(hid_ishtp_cl, false); if (rv) { ishtp_cl_free(hid_ishtp_cl); return rv; @@ -868,11 +833,9 @@ static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) hid_ishtp_cl); dev_dbg(ishtp_device(cl_device), "%s\n", __func__); - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING); - ishtp_cl_disconnect(hid_ishtp_cl); + hid_ishtp_cl_deinit(hid_ishtp_cl); ishtp_put_device(cl_device); ishtp_hid_remove(client_data); - hid_ishtp_cl_deinit(hid_ishtp_cl); hid_ishtp_cl = NULL; From 09b57d983e0d85d223e11e1e69de4d3f0b675bf1 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 5 Dec 2023 09:50:32 +0800 Subject: [PATCH 2770/7721] HID: intel-ish-hid: ishtp-fw-loader: use helper functions for connection Use helper functions ishtp_cl_establish_connection() and ishtp_cl_destroy_connection() to establish and destroy connection respectively. These functions are used during initialization, reset and deinitialization flows. No functional changes are expected. Signed-off-by: Even Xu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-fw-loader.c | 60 +++++---------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index 16aa030af845..e157863a8b25 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -840,43 +840,22 @@ static void load_fw_from_host_handler(struct work_struct *work) * * Return: 0 for success, negative error code for failure */ -static int loader_init(struct ishtp_cl *loader_ishtp_cl, int reset) +static int loader_init(struct ishtp_cl *loader_ishtp_cl, bool reset) { int rv; - struct ishtp_fw_client *fw_client; struct ishtp_cl_data *client_data = ishtp_get_client_data(loader_ishtp_cl); dev_dbg(cl_data_to_dev(client_data), "reset flag: %d\n", reset); - rv = ishtp_cl_link(loader_ishtp_cl); - if (rv < 0) { - dev_err(cl_data_to_dev(client_data), "ishtp_cl_link failed\n"); - return rv; - } - - /* Connect to firmware client */ - ishtp_set_tx_ring_size(loader_ishtp_cl, LOADER_CL_TX_RING_SIZE); - ishtp_set_rx_ring_size(loader_ishtp_cl, LOADER_CL_RX_RING_SIZE); - - fw_client = - ishtp_fw_cl_get_client(ishtp_get_ishtp_device(loader_ishtp_cl), - &loader_ishtp_id_table[0].guid); - if (!fw_client) { - dev_err(cl_data_to_dev(client_data), - "ISH client uuid not found\n"); - rv = -ENOENT; - goto err_cl_unlink; - } - - ishtp_cl_set_fw_client_id(loader_ishtp_cl, - ishtp_get_fw_client_id(fw_client)); - ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_CONNECTING); - - rv = ishtp_cl_connect(loader_ishtp_cl); + rv = ishtp_cl_establish_connection(loader_ishtp_cl, + &loader_ishtp_id_table[0].guid, + LOADER_CL_TX_RING_SIZE, + LOADER_CL_RX_RING_SIZE, + reset); if (rv < 0) { dev_err(cl_data_to_dev(client_data), "Client connect fail\n"); - goto err_cl_unlink; + goto err_cl_disconnect; } dev_dbg(cl_data_to_dev(client_data), "Client connected\n"); @@ -885,17 +864,14 @@ static int loader_init(struct ishtp_cl *loader_ishtp_cl, int reset) return 0; -err_cl_unlink: - ishtp_cl_unlink(loader_ishtp_cl); +err_cl_disconnect: + ishtp_cl_destroy_connection(loader_ishtp_cl, reset); return rv; } static void loader_deinit(struct ishtp_cl *loader_ishtp_cl) { - ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_DISCONNECTING); - ishtp_cl_disconnect(loader_ishtp_cl); - ishtp_cl_unlink(loader_ishtp_cl); - ishtp_cl_flush_queues(loader_ishtp_cl); + ishtp_cl_destroy_connection(loader_ishtp_cl, false); /* Disband and free all Tx and Rx client-level rings */ ishtp_cl_free(loader_ishtp_cl); @@ -914,19 +890,7 @@ static void reset_handler(struct work_struct *work) loader_ishtp_cl = client_data->loader_ishtp_cl; cl_device = client_data->cl_device; - /* Unlink, flush queues & start again */ - ishtp_cl_unlink(loader_ishtp_cl); - ishtp_cl_flush_queues(loader_ishtp_cl); - ishtp_cl_free(loader_ishtp_cl); - - loader_ishtp_cl = ishtp_cl_allocate(cl_device); - if (!loader_ishtp_cl) - return; - - ishtp_set_drvdata(cl_device, loader_ishtp_cl); - ishtp_set_client_data(loader_ishtp_cl, client_data); - client_data->loader_ishtp_cl = loader_ishtp_cl; - client_data->cl_device = cl_device; + ishtp_cl_destroy_connection(loader_ishtp_cl, true); rv = loader_init(loader_ishtp_cl, 1); if (rv < 0) { @@ -974,7 +938,7 @@ static int loader_ishtp_cl_probe(struct ishtp_cl_device *cl_device) INIT_WORK(&client_data->work_fw_load, load_fw_from_host_handler); - rv = loader_init(loader_ishtp_cl, 0); + rv = loader_init(loader_ishtp_cl, false); if (rv < 0) { ishtp_cl_free(loader_ishtp_cl); return rv; From 42a244be36cda2da571c72feb5d1d2b45866735f Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 5 Dec 2023 09:50:33 +0800 Subject: [PATCH 2771/7721] platform/chrome: cros_ec_ishtp: use helper functions for connection Use helper functions ishtp_cl_establish_connection() and ishtp_cl_destroy_connection() to establish and destroy connection respectively. These functions are used during initialization, reset and deinitialization flows. No functional changes are expected. Signed-off-by: Even Xu Acked-by: Srinivas Pandruvada Acked-by: Tzung-Bi Shih Signed-off-by: Jiri Kosina --- drivers/platform/chrome/cros_ec_ishtp.c | 74 +++++-------------------- 1 file changed, 15 insertions(+), 59 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c index cb2031cf7106..5ac37bd024c8 100644 --- a/drivers/platform/chrome/cros_ec_ishtp.c +++ b/drivers/platform/chrome/cros_ec_ishtp.c @@ -367,55 +367,33 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device) /** * cros_ish_init() - Init function for ISHTP client * @cros_ish_cl: ISHTP client instance + * @reset: true if called from reset handler * * This function complete the initializtion of the client. * * Return: 0 for success, negative error code for failure. */ -static int cros_ish_init(struct ishtp_cl *cros_ish_cl) +static int cros_ish_init(struct ishtp_cl *cros_ish_cl, bool reset) { int rv; - struct ishtp_device *dev; - struct ishtp_fw_client *fw_client; struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl); - rv = ishtp_cl_link(cros_ish_cl); - if (rv) { - dev_err(cl_data_to_dev(client_data), - "ishtp_cl_link failed\n"); - return rv; - } - - dev = ishtp_get_ishtp_device(cros_ish_cl); - - /* Connect to firmware client */ - ishtp_set_tx_ring_size(cros_ish_cl, CROS_ISH_CL_TX_RING_SIZE); - ishtp_set_rx_ring_size(cros_ish_cl, CROS_ISH_CL_RX_RING_SIZE); - - fw_client = ishtp_fw_cl_get_client(dev, &cros_ec_ishtp_id_table[0].guid); - if (!fw_client) { - dev_err(cl_data_to_dev(client_data), - "ish client uuid not found\n"); - rv = -ENOENT; - goto err_cl_unlink; - } - - ishtp_cl_set_fw_client_id(cros_ish_cl, - ishtp_get_fw_client_id(fw_client)); - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_CONNECTING); - - rv = ishtp_cl_connect(cros_ish_cl); + rv = ishtp_cl_establish_connection(cros_ish_cl, + &cros_ec_ishtp_id_table[0].guid, + CROS_ISH_CL_TX_RING_SIZE, + CROS_ISH_CL_RX_RING_SIZE, + reset); if (rv) { dev_err(cl_data_to_dev(client_data), "client connect fail\n"); - goto err_cl_unlink; + goto err_cl_disconnect; } ishtp_register_event_cb(client_data->cl_device, ish_event_cb); return 0; -err_cl_unlink: - ishtp_cl_unlink(cros_ish_cl); +err_cl_disconnect: + ishtp_cl_destroy_connection(cros_ish_cl, reset); return rv; } @@ -427,10 +405,7 @@ static int cros_ish_init(struct ishtp_cl *cros_ish_cl) */ static void cros_ish_deinit(struct ishtp_cl *cros_ish_cl) { - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING); - ishtp_cl_disconnect(cros_ish_cl); - ishtp_cl_unlink(cros_ish_cl); - ishtp_cl_flush_queues(cros_ish_cl); + ishtp_cl_destroy_connection(cros_ish_cl, false); /* Disband and free all Tx and Rx client-level rings */ ishtp_cl_free(cros_ish_cl); @@ -592,7 +567,6 @@ static void reset_handler(struct work_struct *work) int rv; struct device *dev; struct ishtp_cl *cros_ish_cl; - struct ishtp_cl_device *cl_device; struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, work_ishtp_reset); @@ -600,26 +574,11 @@ static void reset_handler(struct work_struct *work) down_write(&init_lock); cros_ish_cl = client_data->cros_ish_cl; - cl_device = client_data->cl_device; - /* Unlink, flush queues & start again */ - ishtp_cl_unlink(cros_ish_cl); - ishtp_cl_flush_queues(cros_ish_cl); - ishtp_cl_free(cros_ish_cl); + ishtp_cl_destroy_connection(cros_ish_cl, true); - cros_ish_cl = ishtp_cl_allocate(cl_device); - if (!cros_ish_cl) { - up_write(&init_lock); - return; - } - - ishtp_set_drvdata(cl_device, cros_ish_cl); - ishtp_set_client_data(cros_ish_cl, client_data); - client_data->cros_ish_cl = cros_ish_cl; - - rv = cros_ish_init(cros_ish_cl); + rv = cros_ish_init(cros_ish_cl, true); if (rv) { - ishtp_cl_free(cros_ish_cl); dev_err(cl_data_to_dev(client_data), "Reset Failed\n"); up_write(&init_lock); return; @@ -672,7 +631,7 @@ static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device) INIT_WORK(&client_data->work_ec_evt, ish_evt_handler); - rv = cros_ish_init(cros_ish_cl); + rv = cros_ish_init(cros_ish_cl, false); if (rv) goto end_ishtp_cl_init_error; @@ -690,10 +649,7 @@ static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device) return 0; end_cros_ec_dev_init_error: - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING); - ishtp_cl_disconnect(cros_ish_cl); - ishtp_cl_unlink(cros_ish_cl); - ishtp_cl_flush_queues(cros_ish_cl); + ishtp_cl_destroy_connection(cros_ish_cl, false); ishtp_put_device(cl_device); end_ishtp_cl_init_error: ishtp_cl_free(cros_ish_cl); From f023605d1de6f150d9266747a2630f029956041f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:08 +0100 Subject: [PATCH 2772/7721] HID: i2c-hid: Fold i2c_hid_execute_reset() into i2c_hid_hwreset() i2c_hid_hwreset() is the only caller of i2c_hid_execute_reset(), fold the latter into the former. This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows. No functional changes intended. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 79 +++++++++++++----------------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 2735cd585af0..ca2a4ccb9abf 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -426,49 +426,9 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) return ret; } -static int i2c_hid_execute_reset(struct i2c_hid *ihid) -{ - size_t length = 0; - int ret; - - i2c_hid_dbg(ihid, "resetting...\n"); - - /* Prepare reset command. Command register goes first. */ - *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; - length += sizeof(__le16); - /* Next is RESET command itself */ - length += i2c_hid_encode_command(ihid->cmdbuf + length, - I2C_HID_OPCODE_RESET, 0, 0); - - set_bit(I2C_HID_RESET_PENDING, &ihid->flags); - - ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); - if (ret) { - dev_err(&ihid->client->dev, "failed to reset device.\n"); - goto out; - } - - if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) { - msleep(100); - goto out; - } - - i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); - if (!wait_event_timeout(ihid->wait, - !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), - msecs_to_jiffies(5000))) { - ret = -ENODATA; - goto out; - } - i2c_hid_dbg(ihid, "%s: finished.\n", __func__); - -out: - clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); - return ret; -} - static int i2c_hid_hwreset(struct i2c_hid *ihid) { + size_t length = 0; int ret; i2c_hid_dbg(ihid, "%s\n", __func__); @@ -482,21 +442,48 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid) ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); if (ret) - goto out_unlock; + goto err_unlock; - ret = i2c_hid_execute_reset(ihid); + /* Prepare reset command. Command register goes first. */ + *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; + length += sizeof(__le16); + /* Next is RESET command itself */ + length += i2c_hid_encode_command(ihid->cmdbuf + length, + I2C_HID_OPCODE_RESET, 0, 0); + + set_bit(I2C_HID_RESET_PENDING, &ihid->flags); + + ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); if (ret) { dev_err(&ihid->client->dev, "failed to reset device: %d\n", ret); - i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); - goto out_unlock; + goto err_clear_reset; } + i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); + + if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) { + msleep(100); + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); + } else if (!wait_event_timeout(ihid->wait, + !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), + msecs_to_jiffies(5000))) { + ret = -ENODATA; + goto err_clear_reset; + } + i2c_hid_dbg(ihid, "%s: finished.\n", __func__); + /* At least some SIS devices need this after reset */ if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET)) ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); -out_unlock: + mutex_unlock(&ihid->reset_lock); + return ret; + +err_clear_reset: + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); +err_unlock: mutex_unlock(&ihid->reset_lock); return ret; } From 96d3098db835d58649b73a5788898bd7672a319b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:09 +0100 Subject: [PATCH 2773/7721] HID: i2c-hid: Split i2c_hid_hwreset() in start() and finish() functions Split i2c_hid_hwreset() into: i2c_hid_start_hwreset() which sends the PWR_ON and reset commands; and i2c_hid_finish_hwreset() which actually waits for the reset to complete. This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows. No functional changes intended. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 38 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index ca2a4ccb9abf..21d65ca32866 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -426,7 +426,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) return ret; } -static int i2c_hid_hwreset(struct i2c_hid *ihid) +static int i2c_hid_start_hwreset(struct i2c_hid *ihid) { size_t length = 0; int ret; @@ -438,11 +438,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid) * being reset. Otherwise we may lose the reset complete * interrupt. */ - mutex_lock(&ihid->reset_lock); + lockdep_assert_held(&ihid->reset_lock); ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); if (ret) - goto err_unlock; + return ret; /* Prepare reset command. Command register goes first. */ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; @@ -460,6 +460,18 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid) goto err_clear_reset; } + return 0; + +err_clear_reset: + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); + return ret; +} + +static int i2c_hid_finish_hwreset(struct i2c_hid *ihid) +{ + int ret = 0; + i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) { @@ -477,14 +489,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid) if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET)) ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); - mutex_unlock(&ihid->reset_lock); return ret; err_clear_reset: clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); -err_unlock: - mutex_unlock(&ihid->reset_lock); return ret; } @@ -731,7 +740,11 @@ static int i2c_hid_parse(struct hid_device *hid) } do { - ret = i2c_hid_hwreset(ihid); + mutex_lock(&ihid->reset_lock); + ret = i2c_hid_start_hwreset(ihid); + if (ret == 0) + ret = i2c_hid_finish_hwreset(ihid); + mutex_unlock(&ihid->reset_lock); if (ret) msleep(1000); } while (tries-- > 0 && ret); @@ -974,10 +987,15 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid) * However some ALPS touchpads generate IRQ storm without reset, so * let's still reset them here. */ - if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) - ret = i2c_hid_hwreset(ihid); - else + if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) { + mutex_lock(&ihid->reset_lock); + ret = i2c_hid_start_hwreset(ihid); + if (ret == 0) + ret = i2c_hid_finish_hwreset(ihid); + mutex_unlock(&ihid->reset_lock); + } else { ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); + } if (ret) return ret; From aa69d6974185e9f7a552ba982540a38e34f69690 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:10 +0100 Subject: [PATCH 2774/7721] HID: i2c-hid: Switch i2c_hid_parse() to goto style error handling Switch i2c_hid_parse() to goto style error handling. This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows. Note this changes the descriptor read error path to propagate the actual i2c_hid_read_register() error code (which is always negative) instead of hardcoding a -EIO return. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 21d65ca32866..71d742aeaf35 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -773,23 +773,21 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc, rsize); if (ret) { hid_err(hid, "reading report descriptor failed\n"); - kfree(rdesc); - return -EIO; + goto out; } } i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); ret = hid_parse_report(hid, rdesc, rsize); + if (ret) + dbg_hid("parsing report descriptor failed\n"); + +out: if (!use_override) kfree(rdesc); - if (ret) { - dbg_hid("parsing report descriptor failed\n"); - return ret; - } - - return 0; + return ret; } static int i2c_hid_start(struct hid_device *hid) From af93a167eda90192563bce64c4bb989836afac1f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:11 +0100 Subject: [PATCH 2775/7721] HID: i2c-hid: Move i2c_hid_finish_hwreset() to after reading the report-descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A recent bug made me look at Microsoft's i2c-hid docs again and I noticed the following: """ 4. Issue a RESET (Host Initiated Reset) to the Device. 5. Retrieve report descriptor from the device. Note: Steps 4 and 5 may be done in parallel to optimize for time on I²C. Since report descriptors are (a) static and (b) quite long, Windows 8 may issue a request for 5 while it is waiting for a response from the device on 4. """ Which made me think that maybe on some touchpads the reset ack is delayed till after the report descriptor is read ? Testing a T-BAO Tbook Air 12.5 with a 0911:5288 (SIPODEV SP1064?) touchpad, for which the I2C_HID_QUIRK_NO_IRQ_AFTER_RESET quirk was first introduced, shows that reading the report descriptor before waiting for the reset helps with the missing reset IRQ. Now the reset does get acked properly, but the ack sometimes still does not happen unfortunately. Still moving the wait for ack to after reading the report-descriptor, is probably a good idea, both to make i2c-hid's behavior closer to Windows as well as to speed up probing i2c-hid devices. While at it drop the dbg_hid() for a malloc failure, malloc failures already get logged extensively by malloc itself. Link: https://bugzilla.redhat.com/show_bug.cgi?id=2247751 Signed-off-by: Hans de Goede Reviewed-by: Douglas Anderson Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 71d742aeaf35..400c15a180b5 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -725,11 +725,10 @@ static int i2c_hid_parse(struct hid_device *hid) struct i2c_client *client = hid->driver_data; struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid_desc *hdesc = &ihid->hdesc; + char *rdesc = NULL, *use_override = NULL; unsigned int rsize; - char *rdesc; int ret; int tries = 3; - char *use_override; i2c_hid_dbg(ihid, "entering %s\n", __func__); @@ -739,18 +738,15 @@ static int i2c_hid_parse(struct hid_device *hid) return -EINVAL; } + mutex_lock(&ihid->reset_lock); do { - mutex_lock(&ihid->reset_lock); ret = i2c_hid_start_hwreset(ihid); - if (ret == 0) - ret = i2c_hid_finish_hwreset(ihid); - mutex_unlock(&ihid->reset_lock); if (ret) msleep(1000); } while (tries-- > 0 && ret); if (ret) - return ret; + goto abort_reset; use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, &rsize); @@ -762,8 +758,8 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc = kzalloc(rsize, GFP_KERNEL); if (!rdesc) { - dbg_hid("couldn't allocate rdesc memory\n"); - return -ENOMEM; + ret = -ENOMEM; + goto abort_reset; } i2c_hid_dbg(ihid, "asking HID report descriptor\n"); @@ -773,10 +769,23 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc, rsize); if (ret) { hid_err(hid, "reading report descriptor failed\n"); - goto out; + goto abort_reset; } } + /* + * Windows directly reads the report-descriptor after sending reset + * and then waits for resets completion afterwards. Some touchpads + * actually wait for the report-descriptor to be read before signalling + * reset completion. + */ + ret = i2c_hid_finish_hwreset(ihid); +abort_reset: + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); + mutex_unlock(&ihid->reset_lock); + if (ret) + goto out; + i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); ret = hid_parse_report(hid, rdesc, rsize); From 7bcf9ebb50f2afc84b33b06edfd20d47218af758 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:12 +0100 Subject: [PATCH 2776/7721] HID: i2c-hid: Turn missing reset ack into a warning On all i2c-hid devices seen sofar the reset-ack either works, or the hw is somehow buggy and does not (always) ack the reset properly, yet it still works fine. Lower the very long reset timeout to 1 second which should be plenty and change the reset not getting acked from an error into a warning. This results in a bit cleaner code and avoids the need to add more I2C_HID_QUIRK_NO_IRQ_AFTER_RESET quirks in the future. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 400c15a180b5..88a203e920de 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -479,9 +479,9 @@ static int i2c_hid_finish_hwreset(struct i2c_hid *ihid) clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); } else if (!wait_event_timeout(ihid->wait, !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), - msecs_to_jiffies(5000))) { - ret = -ENODATA; - goto err_clear_reset; + msecs_to_jiffies(1000))) { + dev_warn(&ihid->client->dev, "device did not ack reset within 1000 ms\n"); + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); } i2c_hid_dbg(ihid, "%s: finished.\n", __func__); @@ -490,11 +490,6 @@ static int i2c_hid_finish_hwreset(struct i2c_hid *ihid) ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); return ret; - -err_clear_reset: - clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); - i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); - return ret; } static void i2c_hid_get_input(struct i2c_hid *ihid) From bd008acdac45011f2246ec2518ef19c2da9e6008 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:13 +0100 Subject: [PATCH 2777/7721] HID: i2c-hid: Remove I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV quirk Re-trying the power-on command on failure on all devices should not be a problem, drop the I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV quirk and simply retry power-on on all devices. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 88a203e920de..0c1a7cd84e4c 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -44,7 +44,6 @@ #include "i2c-hid.h" /* quirks to control the device */ -#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) #define I2C_HID_QUIRK_BOGUS_IRQ BIT(4) #define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5) @@ -120,8 +119,6 @@ static const struct i2c_hid_quirks { __u16 idProduct; __u32 quirks; } i2c_hid_quirks[] = { - { USB_VENDOR_ID_WEIDA, HID_ANY_ID, - I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, { I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15, @@ -395,8 +392,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) * The call will get a return value (EREMOTEIO) but device will be * triggered and activated. After that, it goes like a normal device. */ - if (power_state == I2C_HID_PWR_ON && - ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { + if (power_state == I2C_HID_PWR_ON) { ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON); /* Device was already activated */ From 7d7a252842ecafb9b4541dc8470907e97bc6df62 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 2 Dec 2023 23:46:14 +0100 Subject: [PATCH 2778/7721] HID: i2c-hid: Renumber I2C_HID_QUIRK_ defines The quirks variable and the I2C_HID_QUIRK_ defines are never used / exported outside of the i2c-hid code renumber them to start at BIT(0) again. Reviewed-by: Douglas Anderson Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 0c1a7cd84e4c..90f316ae9819 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -44,11 +44,11 @@ #include "i2c-hid.h" /* quirks to control the device */ -#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) -#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4) -#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5) -#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6) -#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7) +#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(0) +#define I2C_HID_QUIRK_BOGUS_IRQ BIT(1) +#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2) +#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3) +#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4) /* Command opcodes */ #define I2C_HID_OPCODE_RESET 0x01 From ccf7dd94c7a710a095a56e786a5e0e819618c597 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Nov 2023 22:39:41 +0100 Subject: [PATCH 2779/7721] wifi: nl80211: refactor nl80211_send_mlme_event() arguments This function has so many arguments already, before adding yet another one, refactor it to take a struct instead. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 98 +++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 31 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 12b7bd92bb86..46a79ed1c97c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17736,21 +17736,29 @@ void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, nlmsg_free(msg); } +struct nl80211_mlme_event { + enum nl80211_commands cmd; + const u8 *buf; + size_t buf_len; + int uapsd_queues; + const u8 *req_ies; + size_t req_ies_len; + bool reconnect; +}; + static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len, - enum nl80211_commands cmd, gfp_t gfp, - int uapsd_queues, const u8 *req_ies, - size_t req_ies_len, bool reconnect) + const struct nl80211_mlme_event *event, + gfp_t gfp) { struct sk_buff *msg; void *hdr; - msg = nlmsg_new(100 + len + req_ies_len, gfp); + msg = nlmsg_new(100 + event->buf_len + event->req_ies_len, gfp); if (!msg) return; - hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + hdr = nl80211hdr_put(msg, 0, 0, 0, event->cmd); if (!hdr) { nlmsg_free(msg); return; @@ -17758,22 +17766,24 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || - (req_ies && - nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies))) + nla_put(msg, NL80211_ATTR_FRAME, event->buf_len, event->buf) || + (event->req_ies && + nla_put(msg, NL80211_ATTR_REQ_IE, event->req_ies_len, + event->req_ies))) goto nla_put_failure; - if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED)) + if (event->reconnect && + nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED)) goto nla_put_failure; - if (uapsd_queues >= 0) { + if (event->uapsd_queues >= 0) { struct nlattr *nla_wmm = nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME); if (!nla_wmm) goto nla_put_failure; if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES, - uapsd_queues)) + event->uapsd_queues)) goto nla_put_failure; nla_nest_end(msg, nla_wmm); @@ -17793,37 +17803,60 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, gfp_t gfp) { - nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0, - false); + struct nl80211_mlme_event event = { + .cmd = NL80211_CMD_AUTHENTICATE, + .buf = buf, + .buf_len = len, + .uapsd_queues = -1, + }; + + nl80211_send_mlme_event(rdev, netdev, &event, gfp); } void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, struct cfg80211_rx_assoc_resp_data *data) { - nl80211_send_mlme_event(rdev, netdev, data->buf, data->len, - NL80211_CMD_ASSOCIATE, GFP_KERNEL, - data->uapsd_queues, - data->req_ies, data->req_ies_len, false); + struct nl80211_mlme_event event = { + .cmd = NL80211_CMD_ASSOCIATE, + .buf = data->buf, + .buf_len = data->len, + .uapsd_queues = data->uapsd_queues, + .req_ies = data->req_ies, + .req_ies_len = data->req_ies_len, + }; + + nl80211_send_mlme_event(rdev, netdev, &event, GFP_KERNEL); } void nl80211_send_deauth(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, bool reconnect, gfp_t gfp) { - nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0, - reconnect); + struct nl80211_mlme_event event = { + .cmd = NL80211_CMD_DEAUTHENTICATE, + .buf = buf, + .buf_len = len, + .reconnect = reconnect, + .uapsd_queues = -1, + }; + + nl80211_send_mlme_event(rdev, netdev, &event, gfp); } void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, bool reconnect, gfp_t gfp) { - nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0, - reconnect); + struct nl80211_mlme_event event = { + .cmd = NL80211_CMD_DISASSOCIATE, + .buf = buf, + .buf_len = len, + .reconnect = reconnect, + .uapsd_queues = -1, + }; + + nl80211_send_mlme_event(rdev, netdev, &event, gfp); } void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, @@ -17833,28 +17866,31 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); const struct ieee80211_mgmt *mgmt = (void *)buf; - u32 cmd; + struct nl80211_mlme_event event = { + .buf = buf, + .buf_len = len, + .uapsd_queues = -1, + }; if (WARN_ON(len < 2)) return; if (ieee80211_is_deauth(mgmt->frame_control)) { - cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE; + event.cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE; } else if (ieee80211_is_disassoc(mgmt->frame_control)) { - cmd = NL80211_CMD_UNPROT_DISASSOCIATE; + event.cmd = NL80211_CMD_UNPROT_DISASSOCIATE; } else if (ieee80211_is_beacon(mgmt->frame_control)) { if (wdev->unprot_beacon_reported && elapsed_jiffies_msecs(wdev->unprot_beacon_reported) < 10000) return; - cmd = NL80211_CMD_UNPROT_BEACON; + event.cmd = NL80211_CMD_UNPROT_BEACON; wdev->unprot_beacon_reported = jiffies; } else { return; } trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); - nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1, - NULL, 0, false); + nl80211_send_mlme_event(rdev, dev, &event, GFP_ATOMIC); } EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); From 88f29324042752a28245ec0ab285d71c7f4d9c6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Nov 2023 22:50:58 +0100 Subject: [PATCH 2780/7721] wifi: cfg80211: make RX assoc data const This is just a collection of data and we only read it, so make it const. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- net/wireless/mlme.c | 2 +- net/wireless/nl80211.c | 2 +- net/wireless/nl80211.h | 2 +- net/wireless/trace.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d36ad4cedf3b..d59669d86718 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7312,7 +7312,7 @@ struct cfg80211_rx_assoc_resp_data { * This function may sleep. The caller must hold the corresponding wdev's mutex. */ void cfg80211_rx_assoc_resp(struct net_device *dev, - struct cfg80211_rx_assoc_resp_data *data); + const struct cfg80211_rx_assoc_resp_data *data); /** * struct cfg80211_assoc_failure - association failure data diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bad9e4fd842f..f635a8b6ca2e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -22,7 +22,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, - struct cfg80211_rx_assoc_resp_data *data) + const struct cfg80211_rx_assoc_resp_data *data) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 46a79ed1c97c..403a4a38966a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17815,7 +17815,7 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - struct cfg80211_rx_assoc_resp_data *data) + const struct cfg80211_rx_assoc_resp_data *data) { struct nl80211_mlme_event event = { .cmd = NL80211_CMD_ASSOCIATE, diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index aad40240d9cb..6376f3a87f8a 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -60,7 +60,7 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - struct cfg80211_rx_assoc_resp_data *data); + const struct cfg80211_rx_assoc_resp_data *data); void nl80211_send_deauth(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 30cd1bd58aac..4de710efa47e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2928,7 +2928,7 @@ DEFINE_EVENT(netdev_evt_only, cfg80211_send_rx_auth, TRACE_EVENT(cfg80211_send_rx_assoc, TP_PROTO(struct net_device *netdev, - struct cfg80211_rx_assoc_resp_data *data), + const struct cfg80211_rx_assoc_resp_data *data), TP_ARGS(netdev, data), TP_STRUCT__entry( NETDEV_ENTRY From 98d62e97c39f9b54143d504290481bed96b9bab2 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:39 +0100 Subject: [PATCH 2781/7721] dt-bindings: soc: microchip: add a property for system controller flash The system controller "shares" a SPI flash device with a QSPI controller in the MSS. This flash is used to store FPGA bitstreams & other metadata. IAP and Auto Upgrade both write images to this flash that the System Controller will use to re-program the FPGA. Add a phandle property signifying which flash device is connected to the system controller. Reviewed-by: Rob Herring Signed-off-by: Conor Dooley --- .../soc/microchip/microchip,mpfs-sys-controller.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml b/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml index 365a9fed5914..a3fa04f3a1bd 100644 --- a/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml +++ b/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml @@ -26,6 +26,16 @@ properties: compatible: const: microchip,mpfs-sys-controller + microchip,bitstream-flash: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The SPI flash connected to the system controller's QSPI controller. + The system controller may retrieve FPGA bitstreams from this flash to + perform In-Application Programming (IAP) or during device initialisation + for Auto Update. The MSS and system controller have separate QSPI + controllers and this flash is connected to both. Software running in the + MSS can write bitstreams to the flash. + required: - compatible - mboxes From 742aa6c563d29c367edbf0ef7236a7a853ed9be4 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:40 +0100 Subject: [PATCH 2782/7721] soc: microchip: mpfs: enable access to the system controller's flash The system controller has a flash that contains images used to reprogram the FPGA using IAP (In-Application Programming). Introduce a function that allows a driver with a reference to the system controller to get one to a flash device attached to it. Signed-off-by: Conor Dooley --- drivers/soc/microchip/Kconfig | 1 + drivers/soc/microchip/mpfs-sys-controller.c | 20 ++++++++++++++++++++ include/soc/microchip/mpfs.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/drivers/soc/microchip/Kconfig b/drivers/soc/microchip/Kconfig index eb656b33156b..9b0fdd95276e 100644 --- a/drivers/soc/microchip/Kconfig +++ b/drivers/soc/microchip/Kconfig @@ -1,6 +1,7 @@ config POLARFIRE_SOC_SYS_CTRL tristate "POLARFIRE_SOC_SYS_CTRL" depends on POLARFIRE_SOC_MAILBOX + depends on MTD help This driver adds support for the PolarFire SoC (MPFS) system controller. diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index 0935e9e94172..c7e063993d92 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -30,6 +32,7 @@ struct mpfs_sys_controller { struct mbox_client client; struct mbox_chan *chan; struct completion c; + struct mtd_info *flash; struct kref consumers; }; @@ -99,6 +102,12 @@ static void mpfs_sys_controller_put(void *data) kref_put(&sys_controller->consumers, mpfs_sys_controller_delete); } +struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_client) +{ + return mpfs_client->flash; +} +EXPORT_SYMBOL(mpfs_sys_controller_get_flash); + static struct platform_device subdevs[] = { { .name = "mpfs-rng", @@ -114,12 +123,23 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mpfs_sys_controller *sys_controller; + struct device_node *np; int i, ret; sys_controller = kzalloc(sizeof(*sys_controller), GFP_KERNEL); if (!sys_controller) return -ENOMEM; + np = of_parse_phandle(dev->of_node, "microchip,bitstream-flash", 0); + if (!np) + goto no_flash; + + sys_controller->flash = of_get_mtd_device_by_node(np); + of_node_put(np); + if (IS_ERR(sys_controller->flash)) + return dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n"); + +no_flash: sys_controller->client.dev = dev; sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback; sys_controller->client.tx_block = 1U; diff --git a/include/soc/microchip/mpfs.h b/include/soc/microchip/mpfs.h index f916dcde457f..09722f83b0ca 100644 --- a/include/soc/microchip/mpfs.h +++ b/include/soc/microchip/mpfs.h @@ -38,6 +38,8 @@ int mpfs_blocking_transaction(struct mpfs_sys_controller *mpfs_client, struct mp struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev); +struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_client); + #endif /* if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL) */ #if IS_ENABLED(CONFIG_MCHP_CLK_MPFS) From a8f00589be7b9dfeae801bd3087ec7da57c1913e Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:41 +0100 Subject: [PATCH 2783/7721] soc: microchip: mpfs: print service status in warning message Now that resp_status is set for failed services, print the status in the error path's warning. Signed-off-by: Conor Dooley --- drivers/soc/microchip/mpfs-sys-controller.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index c7e063993d92..d438efde3278 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -66,7 +66,9 @@ int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct */ if (!wait_for_completion_timeout(&sys_controller->c, timeout)) { ret = -EBADMSG; - dev_warn(sys_controller->client.dev, "MPFS sys controller service failed\n"); + dev_warn(sys_controller->client.dev, + "MPFS sys controller service failed with status: %d\n", + msg->response->resp_status); } else { ret = 0; } From fad13b5b73e0689d19316e5d62341d8396bb261e Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:42 +0100 Subject: [PATCH 2784/7721] soc: microchip: mpfs: add auto-update subdev to system controller The PolarFire SoC's system controller offers the ability to re-program the FPGA from a user application via two, related, mechanisms. In-Application Programming (IAP) is not ideal for use in Linux, as it will immediately take down the system when requested. Auto Update is preferred, as it will only take affect at device power up*, allowing the OS (and potential applications in AMP) to be shut down gracefully. * Auto Update occurs at device initialisation, which can also be triggered by device reset - possible with the v2023.02 version of the Hart Software Services (HSS) and reference design. Signed-off-by: Conor Dooley --- drivers/soc/microchip/mpfs-sys-controller.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index d438efde3278..7a4936019329 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -118,7 +118,11 @@ static struct platform_device subdevs[] = { { .name = "mpfs-generic-service", .id = -1, - } + }, + { + .name = "mpfs-auto-update", + .id = -1, + }, }; static int mpfs_sys_controller_probe(struct platform_device *pdev) @@ -160,7 +164,6 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sys_controller); - dev_info(&pdev->dev, "Registered MPFS system controller\n"); for (i = 0; i < ARRAY_SIZE(subdevs); i++) { subdevs[i].dev.parent = dev; @@ -168,6 +171,8 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev) dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name); } + dev_info(&pdev->dev, "Registered MPFS system controller\n"); + return 0; } From ec5b0f1193ad461e53d083edad8fab0298fe68e3 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:43 +0100 Subject: [PATCH 2785/7721] firmware: microchip: add PolarFire SoC Auto Update support Add support for Auto Update reprogramming of the FPGA fabric on PolarFire SoC, using the fw_upload mechanism a la the intel-m10-bmc-sec-update driver. This driver only writes the image to the spi flash & performs validation on it, as the entire FPGA becomes unusable during the actual reprogramming of a bitstream. To initiate the reprogramming itself, a device reset is required. The SBI SRST extension's "cold reboot" can trigger such a device reset, provided corresponding support has been enabled in the HSS (Hart Software Services), the provider of SBI runtime services on PolarFire SoC. While this is a driver responsible for the reprogramming of an FPGA, there is no dynamic discovery of devices involved, as runtime reconfiguration is not possible due to the device reset requirements. Therefore FPGA manager subsystem is not used by this driver and the FPGA subsystem maintainers were unwilling to accept it there. Signed-off-by: Conor Dooley --- drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/microchip/Kconfig | 12 + drivers/firmware/microchip/Makefile | 3 + drivers/firmware/microchip/mpfs-auto-update.c | 494 ++++++++++++++++++ 5 files changed, 511 insertions(+) create mode 100644 drivers/firmware/microchip/Kconfig create mode 100644 drivers/firmware/microchip/Makefile create mode 100644 drivers/firmware/microchip/mpfs-auto-update.c diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 74d00b0c83fe..9c2541abe320 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -272,6 +272,7 @@ source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" source "drivers/firmware/imx/Kconfig" source "drivers/firmware/meson/Kconfig" +source "drivers/firmware/microchip/Kconfig" source "drivers/firmware/psci/Kconfig" source "drivers/firmware/qcom/Kconfig" source "drivers/firmware/smccc/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5f9dab82e1a0..d305d66bc820 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -28,6 +28,7 @@ obj-y += arm_scmi/ obj-y += broadcom/ obj-y += cirrus/ obj-y += meson/ +obj-y += microchip/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-y += efi/ obj-y += imx/ diff --git a/drivers/firmware/microchip/Kconfig b/drivers/firmware/microchip/Kconfig new file mode 100644 index 000000000000..434b923e08c2 --- /dev/null +++ b/drivers/firmware/microchip/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config POLARFIRE_SOC_AUTO_UPDATE + tristate "Microchip PolarFire SoC AUTO UPDATE" + depends on POLARFIRE_SOC_SYS_CTRL + select FW_LOADER + select FW_UPLOAD + help + Support for reprogramming PolarFire SoC from within Linux, using the + Auto Upgrade feature of the system controller. + + If built as a module, it will be called mpfs-auto-update. diff --git a/drivers/firmware/microchip/Makefile b/drivers/firmware/microchip/Makefile new file mode 100644 index 000000000000..38796fd82893 --- /dev/null +++ b/drivers/firmware/microchip/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_POLARFIRE_SOC_AUTO_UPDATE) += mpfs-auto-update.o diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c new file mode 100644 index 000000000000..d56a95b36b85 --- /dev/null +++ b/drivers/firmware/microchip/mpfs-auto-update.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Polarfire SoC "Auto Update" FPGA reprogramming. + * + * Documentation of this functionality is available in the "PolarFire® FPGA and + * PolarFire SoC FPGA Programming" User Guide. + * + * Copyright (c) 2022-2023 Microchip Corporation. All rights reserved. + * + * Author: Conor Dooley + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AUTO_UPDATE_DEFAULT_MBOX_OFFSET 0u +#define AUTO_UPDATE_DEFAULT_RESP_OFFSET 0u + +#define AUTO_UPDATE_FEATURE_CMD_OPCODE 0x05u +#define AUTO_UPDATE_FEATURE_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_FEATURE_RESP_SIZE 33u +#define AUTO_UPDATE_FEATURE_CMD_DATA NULL +#define AUTO_UPDATE_FEATURE_ENABLED BIT(5) + +#define AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE 0x22u +#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_AUTHENTICATE_RESP_SIZE 1u +#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA NULL + +#define AUTO_UPDATE_PROGRAM_CMD_OPCODE 0x46u +#define AUTO_UPDATE_PROGRAM_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_PROGRAM_RESP_SIZE 1u +#define AUTO_UPDATE_PROGRAM_CMD_DATA NULL + +/* + * SPI Flash layout example: + * |------------------------------| 0x0000000 + * | 1 KiB | + * | SPI "directories" | + * |------------------------------| 0x0000400 + * | 1 MiB | + * | Reserved area | + * | Used for bitstream info | + * |------------------------------| 0x0100400 + * | 20 MiB | + * | Golden Image | + * |------------------------------| 0x1500400 + * | 20 MiB | + * | Auto Upgrade Image | + * |------------------------------| 0x2900400 + * | 20 MiB | + * | Reserved for multi-image IAP | + * | Unused for Auto Upgrade | + * |------------------------------| 0x3D00400 + * | ? B | + * | Unused | + * |------------------------------| 0x? + */ +#define AUTO_UPDATE_DIRECTORY_BASE 0u +#define AUTO_UPDATE_DIRECTORY_WIDTH 4u +#define AUTO_UPDATE_GOLDEN_INDEX 0u +#define AUTO_UPDATE_UPGRADE_INDEX 1u +#define AUTO_UPDATE_BLANK_INDEX 2u +#define AUTO_UPDATE_GOLDEN_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_GOLDEN_INDEX) +#define AUTO_UPDATE_UPGRADE_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_UPGRADE_INDEX) +#define AUTO_UPDATE_BLANK_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_BLANK_INDEX) +#define AUTO_UPDATE_DIRECTORY_SIZE SZ_1K +#define AUTO_UPDATE_RESERVED_SIZE SZ_1M +#define AUTO_UPDATE_BITSTREAM_BASE (AUTO_UPDATE_DIRECTORY_SIZE + AUTO_UPDATE_RESERVED_SIZE) + +#define AUTO_UPDATE_TIMEOUT_MS 60000 + +struct mpfs_auto_update_priv { + struct mpfs_sys_controller *sys_controller; + struct device *dev; + struct mtd_info *flash; + struct fw_upload *fw_uploader; + struct completion programming_complete; + size_t size_per_bitstream; + bool cancel_request; +}; + +static enum fw_upload_err mpfs_auto_update_prepare(struct fw_upload *fw_uploader, const u8 *data, + u32 size) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + + /* + * Verifying the Golden Image is idealistic. It will be evaluated + * against the currently programmed image and thus may fail - due to + * either rollback protection (if its an older version than that in use) + * or if the version is the same as that of the in-use image. + * Extracting the information as to why a failure occurred is not + * currently possible due to limitations of the system controller + * driver. If those are fixed, verification of the Golden Image should + * be added here. + */ + + priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller); + if (!priv->flash) + return FW_UPLOAD_ERR_HW_ERROR; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + /* + * We need to calculate if we have enough space in the flash for the + * new image. + * First, chop off the first 1 KiB as it's reserved for the directory. + * The 1 MiB reserved for design info needs to be ignored also. + * All that remains is carved into 3 & rounded down to the erasesize. + * If this is smaller than the image size, we abort. + * There's also no need to consume more than 20 MiB per image. + */ + priv->size_per_bitstream = priv->flash->size - SZ_1K - SZ_1M; + priv->size_per_bitstream = round_down(priv->size_per_bitstream / 3, erase_size); + if (priv->size_per_bitstream > 20 * SZ_1M) + priv->size_per_bitstream = 20 * SZ_1M; + + if (priv->size_per_bitstream < size) { + dev_err(priv->dev, + "flash device has insufficient capacity to store this bitstream\n"); + return FW_UPLOAD_ERR_INVALID_SIZE; + } + + priv->cancel_request = false; + + return FW_UPLOAD_ERR_NONE; +} + +static void mpfs_auto_update_cancel(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + + priv->cancel_request = true; +} + +static enum fw_upload_err mpfs_auto_update_poll_complete(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + int ret; + + /* + * There is no meaningful way to get the status of the programming while + * it is in progress, so attempting anything other than waiting for it + * to complete would be misplaced. + */ + ret = wait_for_completion_timeout(&priv->programming_complete, + msecs_to_jiffies(AUTO_UPDATE_TIMEOUT_MS)); + if (ret) + return FW_UPLOAD_ERR_TIMEOUT; + + return FW_UPLOAD_ERR_NONE; +} + +static int mpfs_auto_update_verify_image(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + struct mpfs_mss_response *response; + struct mpfs_mss_msg *message; + u32 *response_msg; + int ret; + + response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg), + GFP_KERNEL); + if (!response_msg) + return -ENOMEM; + + response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL); + if (!response) { + ret = -ENOMEM; + goto free_response_msg; + } + + message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL); + if (!message) { + ret = -ENOMEM; + goto free_response; + } + + /* + * The system controller can verify that an image in the flash is valid. + * Rather than duplicate the check in this driver, call the relevant + * service from the system controller instead. + * This service has no command data and no response data. It overloads + * mbox_offset with the image index in the flash's SPI directory where + * the bitstream is located. + */ + response->resp_msg = response_msg; + response->resp_size = AUTO_UPDATE_AUTHENTICATE_RESP_SIZE; + message->cmd_opcode = AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE; + message->cmd_data_size = AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE; + message->response = response; + message->cmd_data = AUTO_UPDATE_AUTHENTICATE_CMD_DATA; + message->mbox_offset = AUTO_UPDATE_UPGRADE_INDEX; + message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET; + + dev_info(priv->dev, "Running verification of Upgrade Image\n"); + ret = mpfs_blocking_transaction(priv->sys_controller, message); + if (ret | response->resp_status) { + dev_warn(priv->dev, "Verification of Upgrade Image failed!\n"); + ret = ret ? ret : -EBADMSG; + } + + dev_info(priv->dev, "Verification of Upgrade Image passed!\n"); + + devm_kfree(priv->dev, message); +free_response: + devm_kfree(priv->dev, response); +free_response_msg: + devm_kfree(priv->dev, response_msg); + + return ret; +} + +static int mpfs_auto_update_set_image_address(struct mpfs_auto_update_priv *priv, char *buffer, + u32 image_address, loff_t directory_address) +{ + struct erase_info erase; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + size_t bytes_written = 0, bytes_read = 0; + int ret; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + erase.addr = AUTO_UPDATE_DIRECTORY_BASE; + erase.len = erase_size; + + /* + * We need to write the "SPI DIRECTORY" to the first 1 KiB, telling + * the system controller where to find the actual bitstream. Since + * this is spi-nor, we have to read the first eraseblock, erase that + * portion of the flash, modify the data and then write it back. + * There's no need to do this though if things are already the way they + * should be, so check and save the write in that case. + */ + ret = mtd_read(priv->flash, AUTO_UPDATE_DIRECTORY_BASE, erase_size, &bytes_read, + (u_char *)buffer); + if (ret) + return ret; + + if (bytes_read != erase_size) + return -EIO; + + if ((*(u32 *)(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY) == image_address) && + !(*(u32 *)(buffer + AUTO_UPDATE_BLANK_DIRECTORY))) + return 0; + + ret = mtd_erase(priv->flash, &erase); + if (ret) + return ret; + + /* + * Populate the image address and then zero out the next directory so + * that the system controller doesn't complain if in "Single Image" + * mode. + */ + memcpy(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY, &image_address, + AUTO_UPDATE_DIRECTORY_WIDTH); + memset(buffer + AUTO_UPDATE_BLANK_DIRECTORY, 0x0, AUTO_UPDATE_DIRECTORY_WIDTH); + + dev_info(priv->dev, "Writing the image address (%x) to the flash directory (%llx)\n", + image_address, directory_address); + + ret = mtd_write(priv->flash, 0x0, erase_size, &bytes_written, (u_char *)buffer); + if (ret) + return ret; + + if (bytes_written != erase_size) + return ret; + + return 0; +} + +static int mpfs_auto_update_write_bitstream(struct fw_upload *fw_uploader, const u8 *data, + u32 offset, u32 size, u32 *written) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + struct erase_info erase; + char *buffer; + loff_t directory_address = AUTO_UPDATE_UPGRADE_DIRECTORY; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + size_t bytes_written = 0; + u32 image_address; + int ret; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + image_address = AUTO_UPDATE_BITSTREAM_BASE + + AUTO_UPDATE_UPGRADE_INDEX * priv->size_per_bitstream; + + buffer = devm_kzalloc(priv->dev, erase_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = mpfs_auto_update_set_image_address(priv, buffer, image_address, directory_address); + if (ret) { + dev_err(priv->dev, "failed to set image address in the SPI directory: %d\n", ret); + goto out; + } + + /* + * Now the .spi image itself can be written to the flash. Preservation + * of contents here is not important here, unlike the spi "directory" + * which must be RMWed. + */ + erase.len = round_up(size, (size_t)priv->flash->erasesize); + erase.addr = image_address; + + dev_info(priv->dev, "Erasing the flash at address (%x)\n", image_address); + ret = mtd_erase(priv->flash, &erase); + if (ret) + goto out; + + /* + * No parsing etc of the bitstream is required. The system controller + * will do all of that itself - including verifying that the bitstream + * is valid. + */ + dev_info(priv->dev, "Writing the image to the flash at address (%x)\n", image_address); + ret = mtd_write(priv->flash, (loff_t)image_address, size, &bytes_written, data); + if (ret) + goto out; + + if (bytes_written != size) { + ret = -EIO; + goto out; + } + + *written = bytes_written; + +out: + devm_kfree(priv->dev, buffer); + return ret; +} + +static enum fw_upload_err mpfs_auto_update_write(struct fw_upload *fw_uploader, const u8 *data, + u32 offset, u32 size, u32 *written) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + enum fw_upload_err err = FW_UPLOAD_ERR_NONE; + int ret; + + reinit_completion(&priv->programming_complete); + + ret = mpfs_auto_update_write_bitstream(fw_uploader, data, offset, size, written); + if (ret) { + err = FW_UPLOAD_ERR_RW_ERROR; + goto out; + } + + if (priv->cancel_request) { + err = FW_UPLOAD_ERR_CANCELED; + goto out; + } + + ret = mpfs_auto_update_verify_image(fw_uploader); + if (ret) + err = FW_UPLOAD_ERR_FW_INVALID; + +out: + complete(&priv->programming_complete); + + return err; +} + +static const struct fw_upload_ops mpfs_auto_update_ops = { + .prepare = mpfs_auto_update_prepare, + .write = mpfs_auto_update_write, + .poll_complete = mpfs_auto_update_poll_complete, + .cancel = mpfs_auto_update_cancel, +}; + +static int mpfs_auto_update_available(struct mpfs_auto_update_priv *priv) +{ + struct mpfs_mss_response *response; + struct mpfs_mss_msg *message; + u32 *response_msg; + int ret; + + response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg), + GFP_KERNEL); + if (!response_msg) + return -ENOMEM; + + response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL); + if (!response) + return -ENOMEM; + + message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL); + if (!message) + return -ENOMEM; + + /* + * To verify that Auto Update is possible, the "Query Security Service + * Request" is performed. + * This service has no command data & does not overload mbox_offset. + */ + response->resp_msg = response_msg; + response->resp_size = AUTO_UPDATE_FEATURE_RESP_SIZE; + message->cmd_opcode = AUTO_UPDATE_FEATURE_CMD_OPCODE; + message->cmd_data_size = AUTO_UPDATE_FEATURE_CMD_DATA_SIZE; + message->response = response; + message->cmd_data = AUTO_UPDATE_FEATURE_CMD_DATA; + message->mbox_offset = AUTO_UPDATE_DEFAULT_MBOX_OFFSET; + message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET; + + ret = mpfs_blocking_transaction(priv->sys_controller, message); + if (ret) + return ret; + + /* + * Currently, the system controller's firmware does not generate any + * interrupts for failed services, so mpfs_blocking_transaction() should + * time out & therefore return an error. + * Hitting this check is highly unlikely at present, but if the system + * controller's behaviour changes so that it does generate interrupts + * for failed services, it will be required. + */ + if (response->resp_status) + return -EIO; + + /* + * Bit 5 of byte 1 is "UL_Auto Update" & if it is set, Auto Update is + * not possible. + */ + if (response_msg[1] & AUTO_UPDATE_FEATURE_ENABLED) + return -EPERM; + + return 0; +} + +static int mpfs_auto_update_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpfs_auto_update_priv *priv; + struct fw_upload *fw_uploader; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->sys_controller = mpfs_sys_controller_get(dev); + if (IS_ERR(priv->sys_controller)) + return dev_err_probe(dev, PTR_ERR(priv->sys_controller), + "Could not register as a sub device of the system controller\n"); + + priv->dev = dev; + platform_set_drvdata(pdev, priv); + + ret = mpfs_auto_update_available(priv); + if (ret) + return dev_err_probe(dev, ret, + "The current bitstream does not support auto-update\n"); + + init_completion(&priv->programming_complete); + + fw_uploader = firmware_upload_register(THIS_MODULE, dev, "mpfs-auto-update", + &mpfs_auto_update_ops, priv); + if (IS_ERR(fw_uploader)) + return dev_err_probe(dev, PTR_ERR(fw_uploader), + "Failed to register the bitstream uploader\n"); + + priv->fw_uploader = fw_uploader; + + return 0; +} + +static void mpfs_auto_update_remove(struct platform_device *pdev) +{ + struct mpfs_auto_update_priv *priv = platform_get_drvdata(pdev); + + firmware_upload_unregister(priv->fw_uploader); +} + +static struct platform_driver mpfs_auto_update_driver = { + .driver = { + .name = "mpfs-auto-update", + }, + .probe = mpfs_auto_update_probe, + .remove_new = mpfs_auto_update_remove, +}; +module_platform_driver(mpfs_auto_update_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Conor Dooley "); +MODULE_DESCRIPTION("PolarFire SoC Auto Update FPGA reprogramming"); From 0678df8271820bcf8fb4f877129f05d68a237de4 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 20 Oct 2023 14:18:44 +0100 Subject: [PATCH 2786/7721] riscv: dts: microchip: add the mpfs' system controller qspi & associated flash The system controller's flash can be accessed via an MSS-exposed QSPI controller sitting, which sits between the mailbox's control & data registers. On Icicle, it has an MT25QL01GBBB8ESF connected to it. The system controller and MSS both have separate QSPI controllers, both of which can access the flash, although the system controller takes priority. Unfortunately, on engineering sample silicon, such as that on Icicle kits, the MSS' QSPI controller cannot write to the flash due to a bug. As a workaround, a QSPI controller can be implemented in the FPGA fabric and the IO routing modified to connect it to the flash in place of the "hard" controller in the MSS. Signed-off-by: Conor Dooley --- .../boot/dts/microchip/mpfs-icicle-kit.dts | 21 +++++++++++++++++++ arch/riscv/boot/dts/microchip/mpfs.dtsi | 17 +++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts index 90b261114763..2dae3f8f33f6 100644 --- a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts @@ -199,6 +199,27 @@ &syscontroller { status = "okay"; }; +&syscontroller_qspi { + /* + * The flash *is* there, but Icicle kits that have engineering sample + * silicon (write?) access to this flash to non-functional. The system + * controller itself can actually access it, but the MSS cannot write + * an image there. Instantiating a coreQSPI in the fabric & connecting + * it to the flash instead should work though. Pre-production or later + * silicon does not have this issue. + */ + status = "disabled"; + + sys_ctrl_flash: flash@0 { // MT25QL01GBBB8ESF-0SIT + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + spi-rx-bus-width = <1>; + reg = <0>; + }; +}; + &usb { status = "okay"; dr_mode = "host"; diff --git a/arch/riscv/boot/dts/microchip/mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi index a6faf24f1dba..7ebce6dde6e4 100644 --- a/arch/riscv/boot/dts/microchip/mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi @@ -193,6 +193,12 @@ syscontroller: syscontroller { mboxes = <&mbox 0>; }; + scbclk: mssclkclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <80000000>; + }; + soc { #address-cells = <2>; #size-cells = <2>; @@ -523,5 +529,16 @@ mbox: mailbox@37020000 { #mbox-cells = <1>; status = "disabled"; }; + + syscontroller_qspi: spi@37020100 { + compatible = "microchip,mpfs-qspi", "microchip,coreqspi-rtl-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x37020100 0x0 0x100>; + interrupt-parent = <&plic>; + interrupts = <110>; + clocks = <&scbclk>; + status = "disabled"; + }; }; }; From 074ac38d5b955a6b2241c2b483470501f318a6f1 Mon Sep 17 00:00:00 2001 From: Pavan Nikhilesh Date: Tue, 5 Dec 2023 11:22:41 +0530 Subject: [PATCH 2787/7721] octeontx2-af: cn10k: Increase outstanding LMTST transactions Currently the number of outstanding store transactions issued by AP as a part of LMTST operation is set to 1 i.e default value. This patch set to max supported value to increase the performance. Signed-off-by: Pavan Nikhilesh Signed-off-by: Geetha sowjanya Link: https://lore.kernel.org/r/20231205055241.26355-1-gakula@marvell.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 3 +++ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 1 + drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c | 9 +++++++++ drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h | 2 ++ 4 files changed, 15 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 7cd98f013fde..c1e868a2610e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -935,6 +935,9 @@ static int rvu_setup_hw_resources(struct rvu *rvu) hw->total_vfs = (cfg >> 20) & 0xFFF; hw->max_vfs_per_pf = (cfg >> 40) & 0xFF; + if (!is_rvu_otx2(rvu)) + rvu_apr_block_cn10k_init(rvu); + /* Init NPA LF's bitmap */ block = &hw->block[BLKADDR_NPA]; if (!block->implemented) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index a3de437f309e..814945aa619e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -969,6 +969,7 @@ void rvu_nix_block_cn10k_init(struct rvu *rvu, struct nix_hw *nix_hw); /* CN10K RVU - LMT*/ void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc); +void rvu_apr_block_cn10k_init(struct rvu *rvu); #ifdef CONFIG_DEBUG_FS void rvu_dbg_init(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c index 0e74c5a2231e..7fa98aeb3663 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c @@ -559,3 +559,12 @@ void rvu_nix_block_cn10k_init(struct rvu *rvu, struct nix_hw *nix_hw) cfg |= BIT_ULL(1) | BIT_ULL(2); rvu_write64(rvu, blkaddr, NIX_AF_CFG, cfg); } + +void rvu_apr_block_cn10k_init(struct rvu *rvu) +{ + u64 reg; + + reg = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG); + reg |= FIELD_PREP(LMTST_THROTTLE_MASK, LMTST_WR_PEND_MAX); + rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CFG, reg); +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index b42e631e52d0..189f0eafd5ff 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -733,5 +733,7 @@ #define APR_LMT_MAP_ENT_DIS_SCH_CMP_SHIFT 23 #define APR_LMT_MAP_ENT_SCH_ENA_SHIFT 22 #define APR_LMT_MAP_ENT_DIS_LINE_PREF_SHIFT 21 +#define LMTST_THROTTLE_MASK GENMASK_ULL(38, 35) +#define LMTST_WR_PEND_MAX 15 #endif /* RVU_REG_H */ From e9d5ae8a9e7e32d0b1bc582996de4f7180cb2ff2 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Mon, 4 Dec 2023 15:13:37 +0000 Subject: [PATCH 2788/7721] drm/imagination: Removed unused functions in pvr_fw_trace Fixing the warning below due to an unused file level vtable. Removing only this causes additional warnings for the now unused functions, so I've removed those too. >> drivers/gpu/drm/imagination/pvr_fw_trace.c:205:37: warning: 'pvr_fw_trace_group_mask_fops' defined but not used [-Wunused-const-variable=] 205 | static const struct file_operations pvr_fw_trace_group_mask_fops = { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Changes since v1: - Corrected hash in Fixes tag. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311302054.MVYPxFCE-lkp@intel.com/ Fixes: cb56cd610866 ("drm/imagination: Add firmware trace to debugfs") Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231204151337.60930-1-donald.robson@imgtec.com --- drivers/gpu/drm/imagination/pvr_fw_trace.c | 44 ---------------------- 1 file changed, 44 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 87a42fb6ace6..30f41a10a0cf 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -167,50 +167,6 @@ update_logtype(struct pvr_device *pvr_dev, u32 group_mask) #if defined(CONFIG_DEBUG_FS) -static int fw_trace_group_mask_show(struct seq_file *m, void *data) -{ - struct pvr_device *pvr_dev = m->private; - - seq_printf(m, "%08x\n", pvr_dev->fw_dev.fw_trace.group_mask); - - return 0; -} - -static int fw_trace_group_mask_open(struct inode *inode, struct file *file) -{ - return single_open(file, fw_trace_group_mask_show, inode->i_private); -} - -static ssize_t fw_trace_group_mask_write(struct file *file, const char __user *ubuf, size_t len, - loff_t *offp) -{ - struct seq_file *m = file->private_data; - struct pvr_device *pvr_dev = m->private; - u32 new_group_mask; - int err; - - err = kstrtouint_from_user(ubuf, len, 0, &new_group_mask); - if (err) - return err; - - err = update_logtype(pvr_dev, new_group_mask); - if (err) - return err; - - pvr_dev->fw_dev.fw_trace.group_mask = new_group_mask; - - return (ssize_t)len; -} - -static const struct file_operations pvr_fw_trace_group_mask_fops = { - .owner = THIS_MODULE, - .open = fw_trace_group_mask_open, - .read = seq_read, - .write = fw_trace_group_mask_write, - .llseek = default_llseek, - .release = single_release, -}; - struct pvr_fw_trace_seq_data { /** @buffer: Pointer to copy of trace data. */ u32 *buffer; From 4b83b783ad778f7e69312fa61d1bee8e76e2156f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Dec 2023 08:32:10 +0100 Subject: [PATCH 2789/7721] drm/imagination: move update_logtype() into ifdef section This function is only used when debugfs is enabled, and otherwise causes a build warning: drivers/gpu/drm/imagination/pvr_fw_trace.c:135:1: error: 'update_logtype' defined but not used [-Werror=unused-function] Move the #ifdef check to include this function as well. Fixes: cb56cd610866 ("drm/imagination: Add firmware trace to debugfs") Acked-by: Frank Binns Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231204073231.1164163-1-arnd@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/imagination/pvr_fw_trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 30f41a10a0cf..7159fc479001 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -121,6 +121,8 @@ void pvr_fw_trace_fini(struct pvr_device *pvr_dev) pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj); } +#if defined(CONFIG_DEBUG_FS) + /** * update_logtype() - Send KCCB command to trigger FW to update logtype * @pvr_dev: Target PowerVR device @@ -165,8 +167,6 @@ update_logtype(struct pvr_device *pvr_dev, u32 group_mask) return err; } -#if defined(CONFIG_DEBUG_FS) - struct pvr_fw_trace_seq_data { /** @buffer: Pointer to copy of trace data. */ u32 *buffer; From 3ba080bf46e4a9039d0d41356f4a2515e00bf747 Mon Sep 17 00:00:00 2001 From: Neha Malcom Francis Date: Mon, 16 Oct 2023 15:46:08 +0530 Subject: [PATCH 2790/7721] soc: ti: k3-socinfo: Revamp driver to accommodate different rev structs k3-socinfo.c driver assumes silicon revisions for every platform are incremental and one-to-one, corresponding to JTAG_ID's variant field: 1.0, 2.0 etc. This assumption is wrong for SoCs such as J721E, where the variant field to revision mapping is 1.0, 1.1. Further, there are SoCs such as AM65x where the sub-variant version requires custom decoding of other registers. Address this by using conditional handling per JTAG ID that requires an exception with J721E as the first example. To facilitate this conversion, use macros to identify the JTAG_ID part number and map them to predefined string array. Signed-off-by: Neha Malcom Francis Co-developed-by: Thejasvi Konduru Signed-off-by: Thejasvi Konduru Link: https://lore.kernel.org/r/20231016101608.993921-4-n-francis@ti.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/k3-socinfo.c | 73 ++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index 7fc3548e084c..7517a9c8c8fa 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -33,19 +33,33 @@ #define CTRLMMR_WKUP_JTAGID_MFG_TI 0x17 +#define JTAG_ID_PARTNO_AM65X 0xBB5A +#define JTAG_ID_PARTNO_J721E 0xBB64 +#define JTAG_ID_PARTNO_J7200 0xBB6D +#define JTAG_ID_PARTNO_AM64X 0xBB38 +#define JTAG_ID_PARTNO_J721S2 0xBB75 +#define JTAG_ID_PARTNO_AM62X 0xBB7E +#define JTAG_ID_PARTNO_J784S4 0xBB80 +#define JTAG_ID_PARTNO_AM62AX 0xBB8D +#define JTAG_ID_PARTNO_AM62PX 0xBB9D + static const struct k3_soc_id { unsigned int id; const char *family_name; } k3_soc_ids[] = { - { 0xBB5A, "AM65X" }, - { 0xBB64, "J721E" }, - { 0xBB6D, "J7200" }, - { 0xBB38, "AM64X" }, - { 0xBB75, "J721S2"}, - { 0xBB7E, "AM62X" }, - { 0xBB80, "J784S4" }, - { 0xBB8D, "AM62AX" }, - { 0xBB9D, "AM62PX" }, + { JTAG_ID_PARTNO_AM65X, "AM65X" }, + { JTAG_ID_PARTNO_J721E, "J721E" }, + { JTAG_ID_PARTNO_J7200, "J7200" }, + { JTAG_ID_PARTNO_AM64X, "AM64X" }, + { JTAG_ID_PARTNO_J721S2, "J721S2"}, + { JTAG_ID_PARTNO_AM62X, "AM62X" }, + { JTAG_ID_PARTNO_J784S4, "J784S4" }, + { JTAG_ID_PARTNO_AM62AX, "AM62AX" }, + { JTAG_ID_PARTNO_AM62PX, "AM62PX" }, +}; + +static const char * const j721e_rev_string_map[] = { + "1.0", "1.1", }; static int @@ -63,6 +77,32 @@ k3_chipinfo_partno_to_names(unsigned int partno, return -ENODEV; } +static int +k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant, + struct soc_device_attribute *soc_dev_attr) +{ + switch (partno) { + case JTAG_ID_PARTNO_J721E: + if (variant >= ARRAY_SIZE(j721e_rev_string_map)) + goto err_unknown_variant; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s", + j721e_rev_string_map[variant]); + break; + default: + variant++; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", + variant); + } + + if (!soc_dev_attr->revision) + return -ENOMEM; + + return 0; + +err_unknown_variant: + return -ENODEV; +} + static int k3_chipinfo_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -94,7 +134,6 @@ static int k3_chipinfo_probe(struct platform_device *pdev) variant = (jtag_id & CTRLMMR_WKUP_JTAGID_VARIANT_MASK) >> CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT; - variant++; partno_id = (jtag_id & CTRLMMR_WKUP_JTAGID_PARTNO_MASK) >> CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT; @@ -103,16 +142,16 @@ static int k3_chipinfo_probe(struct platform_device *pdev) if (!soc_dev_attr) return -ENOMEM; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", variant); - if (!soc_dev_attr->revision) { - ret = -ENOMEM; - goto err; - } - ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr); if (ret) { dev_err(dev, "Unknown SoC JTAGID[0x%08X]: %d\n", jtag_id, ret); - goto err_free_rev; + goto err; + } + + ret = k3_chipinfo_variant_to_sr(partno_id, variant, soc_dev_attr); + if (ret) { + dev_err(dev, "Unknown SoC SR[0x%08X]: %d\n", jtag_id, ret); + goto err; } node = of_find_node_by_path("/"); From 5709a6809a6869970ef47bbad7451d32e9081ce1 Mon Sep 17 00:00:00 2001 From: Garrett Giordano Date: Mon, 4 Dec 2023 13:23:04 -0800 Subject: [PATCH 2791/7721] arm64: dts: ti: phycore-am64: Add R5F DMA Region and Mailboxes Communication between the R5F subsystem and Linux takes place using DMA memory regions and mailboxes. Here we add DT nodes for the memory regions and mailboxes to facilitate communication between the R5 clusters and Linux as remoteproc will fail to start if no memory regions or mailboxes are provided. Fixes: c48ac0efe6d7 ("arm64: dts: ti: Add support for phyBOARD-Electra-AM642") Signed-off-by: Garrett Giordano Reviewed-by: Wadim Egorov Link: https://lore.kernel.org/r/20231204212304.1736306-1-ggiordano@phytec.com Signed-off-by: Nishanth Menon --- .../boot/dts/ti/k3-am64-phycore-som.dtsi | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi index b8f844f667af..1678e74cb750 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi @@ -29,7 +29,7 @@ memory@80000000 { reg = <0x00000000 0x80000000 0x00000000 0x80000000>; }; - reserved-memory { + reserved_memory: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; @@ -39,6 +39,54 @@ secure_ddr: optee@9e800000 { alignment = <0x1000>; no-map; }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; }; leds { @@ -166,6 +214,34 @@ &cpsw_port2 { status = "disabled"; }; +&mailbox0_cluster2 { + status = "okay"; + + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + &main_i2c0 { status = "okay"; pinctrl-names = "default"; @@ -191,6 +267,30 @@ i2c_som_rtc: rtc@52 { }; }; +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + &ospi0 { status = "okay"; pinctrl-names = "default"; From 9c316d58c238e58d6346458462e8b0fd308e7332 Mon Sep 17 00:00:00 2001 From: Garrett Giordano Date: Mon, 4 Dec 2023 14:28:09 -0800 Subject: [PATCH 2792/7721] arm64: dts: ti: k3-am625-phyboard-lyra-rdk: Lower I2C1 frequency The gpio-expander on i2c-1 has a maximum frequency of 100kHz. Update our main_i2c1 frequency to allow the nxp,pcf8574 gpio-expander to function properly. Signed-off-by: Garrett Giordano Reviewed-by: Wadim Egorov Link: https://lore.kernel.org/r/20231204222811.2344460-1-ggiordano@phytec.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts index a438baf542c2..171354b13e33 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts @@ -187,7 +187,7 @@ cpsw3g_phy3: ethernet-phy@3 { &main_i2c1 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c1_pins_default>; - clock-frequency = <400000>; + clock-frequency = <100000>; status = "okay"; gpio_exp: gpio-expander@21 { From bac441710306a84c52f0f9a561aa9839b91caa14 Mon Sep 17 00:00:00 2001 From: Garrett Giordano Date: Mon, 4 Dec 2023 14:28:10 -0800 Subject: [PATCH 2793/7721] arm64: dts: ti: k3-am625-phyboard-lyra-rdk: Add HDMI support The DSS outputs DPI signals via its second video port (VP2). The DPI output from DSS is 24 bits (RGB888) and is forwarded to an HDMI transmitter (SIL9022) on the board. Add pinmux for DSS DPI output and HDMI Interrupt. Add DT nodes for SIL9022 HDMI transmitter (TX), and the HDMI connector on the phyBOARD-Lyra. Additionally, connect the output of DSS (VP2) with input of the HDMI TX, and the output of HDMI TX to the input of the HDMI connector. Signed-off-by: Garrett Giordano Reviewed-by: Wadim Egorov Link: https://lore.kernel.org/r/20231204222811.2344460-2-ggiordano@phytec.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-am625-phyboard-lyra-rdk.dts | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts index 171354b13e33..81319d68b624 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts @@ -35,6 +35,18 @@ can_tc1: can-phy0 { standby-gpios = <&gpio_exp 1 GPIO_ACTIVE_HIGH>; }; + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; + keys { compatible = "gpio-keys"; autorepeat; @@ -93,6 +105,37 @@ AM62X_IOPAD(0x244, PIN_INPUT, 7) /* (C17) MMC1_SDWP.GPIO1_49 */ >; }; + hdmi_int_pins_default: hdmi-int-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x040, PIN_INPUT, 7) /* (N23) GPMC0_AD1.GPIO0_16 */ + >; + }; + + main_dss0_pins_default: main-dss0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ + AM62X_IOPAD(0x0bc, PIN_OUTPUT, 0) /* (V24) VOUT0_DATA1 */ + AM62X_IOPAD(0x0e0, PIN_OUTPUT, 0) /* (V20) VOUT0_DATA10 */ + AM62X_IOPAD(0x0e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11 */ + AM62X_IOPAD(0x0e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12 */ + AM62X_IOPAD(0x0ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13 */ + AM62X_IOPAD(0x0f0, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA14 */ + AM62X_IOPAD(0x0f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15 */ + AM62X_IOPAD(0x0c0, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA2 */ + AM62X_IOPAD(0x0c4, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA3 */ + AM62X_IOPAD(0x0c8, PIN_OUTPUT, 0) /* (Y25) VOUT0_DATA4 */ + AM62X_IOPAD(0x0cc, PIN_OUTPUT, 0) /* (Y24) VOUT0_DATA5 */ + AM62X_IOPAD(0x0d0, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA6 */ + AM62X_IOPAD(0x0d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7 */ + AM62X_IOPAD(0x0d8, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA8 */ + AM62X_IOPAD(0x0dc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA9 */ + AM62X_IOPAD(0x0fc, PIN_OUTPUT, 0) /* (Y20) VOUT0_DE */ + AM62X_IOPAD(0x0f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + AM62X_IOPAD(0x104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK */ + AM62X_IOPAD(0x100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC */ + >; + }; + main_i2c1_pins_default: main-i2c1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x1e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ @@ -184,6 +227,26 @@ cpsw3g_phy3: ethernet-phy@3 { }; }; +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&main_dss0_pins_default>; + status = "okay"; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP2: DPI/HDMI Output */ + port@1 { + reg = <1>; + + dpi1_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; +}; + &main_i2c1 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c1_pins_default>; @@ -207,6 +270,37 @@ gpio_exp: gpio-expander@21 { "GPIO6_ETH1_USER_RESET", "GPIO7_AUDIO_USER_RESET"; }; + sii9022: bridge-hdmi@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + + interrupt-parent = <&main_gpio0>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_int_pins_default>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dpi1_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + eeprom@51 { compatible = "atmel,24c02"; pagesize = <16>; From fecdf6de7e47849504d0edaaff55fa0baadef420 Mon Sep 17 00:00:00 2001 From: Garrett Giordano Date: Mon, 4 Dec 2023 14:28:11 -0800 Subject: [PATCH 2794/7721] arm64: dts: ti: k3-am625-phyboard-lyra-rdk: Remove HDMI Reset Line Name The GPIO Expander has a line name defined as GPIO0_HDMI_RST. This line is no longer associated with the HDMI Reset so we removed it. Signed-off-by: Garrett Giordano Reviewed-by: Wadim Egorov Link: https://lore.kernel.org/r/20231204222811.2344460-3-ggiordano@phytec.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts index 81319d68b624..4bc0134c987d 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts @@ -264,7 +264,7 @@ gpio_exp: gpio-expander@21 { gpio-controller; interrupt-controller; #interrupt-cells = <2>; - gpio-line-names = "GPIO0_HDMI_RST", "GPIO1_CAN0_nEN", + gpio-line-names = "", "GPIO1_CAN0_nEN", "GPIO2_LED2", "GPIO3_LVDS_GPIO", "GPIO4_BUT2", "GPIO5_LVDS_BKLT_EN", "GPIO6_ETH1_USER_RESET", "GPIO7_AUDIO_USER_RESET"; From fcb335934c5132f6f0646475ece5db729fcfbf84 Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Tue, 5 Dec 2023 19:46:03 +0100 Subject: [PATCH 2795/7721] arm64: dts: ti: verdin-am62: Improve spi1 chip-select pinctrl Verdin SPI_1 interface has a dedicated hardware controlled chip select that is currently configured in the same pinctrl group as MISO/MOSI/CLK, however it is possible that it can be used only as a standard GPIO be it a chip select or not. To maximize flexibility and avoid duplication in the carrier board dts files move the SPI_1 CS in a dedicated pinctrl and also adds an additional pinctrl to simplify using SPI_1 CS as a GPIO. Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231205184605.35225-2-francesco@dolcini.it Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi index 5db52f237253..6a06724b6d16 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi @@ -233,6 +233,13 @@ AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */ >; }; + /* Verdin SPI_1 CS as GPIO */ + pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; + }; + /* Verdin QSPI_1_CS# as GPIO (conflict with Verdin QSPI_1 interface) */ pinctrl_qspi1_cs_gpio: main-gpio0-11-default-pins { pinctrl-single,pins = < @@ -599,12 +606,18 @@ AM62X_IOPAD(0x164, PIN_OUTPUT, 0) /* (AA19) RGMII2_TX_CTL */ /* SODIMM 211 */ pinctrl_spi1: main-spi1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x0020, PIN_INPUT, 1) /* (J25) OSPI0_D5.SPI1_CLK */ /* SODIMM 196 */ - AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ AM62X_IOPAD(0x0024, PIN_INPUT, 1) /* (H25) OSPI0_D6.SPI1_D0 */ /* SODIMM 200 */ AM62X_IOPAD(0x0028, PIN_INPUT, 1) /* (J22) OSPI0_D7.SPI1_D1 */ /* SODIMM 198 */ >; }; + /* Verdin SPI_1 CS */ + pinctrl_spi1_cs0: main-spi1-cs0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ + >; + }; + /* ETH_25MHz_CLK */ pinctrl_eth_clock: main-system-clkout0-default-pins { pinctrl-single,pins = < @@ -1278,7 +1291,7 @@ &main_mcan0 { /* Verdin SPI_1 */ &main_spi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_spi1>; + pinctrl-0 = <&pinctrl_spi1>, <&pinctrl_spi1_cs0>; ti,pindir-d0-out-d1-in; status = "disabled"; }; From 658902913c7044ac5d56b14cea54e735a071fe41 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:41:01 +0100 Subject: [PATCH 2796/7721] dt-bindings: interconnect: Add Qualcomm SM6115 NoC Add bindings for Qualcomm SM6115 Network-On-Chip interconnect. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231125-topic-6115icc-v3-1-bd8907b8cfd7@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,sm6115.yaml | 152 ++++++++++++++++++ .../dt-bindings/interconnect/qcom,sm6115.h | 111 +++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sm6115.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml new file mode 100644 index 000000000000..14b1a0b08e73 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml @@ -0,0 +1,152 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm6115.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM6115 Network-On-Chip interconnect + +maintainers: + - Konrad Dybcio + +description: + The Qualcomm SM6115 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + compatible: + enum: + - qcom,sm6115-bimc + - qcom,sm6115-cnoc + - qcom,sm6115-snoc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 4 + + clock-names: + minItems: 1 + maxItems: 4 + +# Child node's properties +patternProperties: + '^interconnect-[a-z0-9]+$': + type: object + description: + The interconnect providers do not have a separate QoS register space, + but share parent's space. + + $ref: qcom,rpm-common.yaml# + + properties: + compatible: + enum: + - qcom,sm6115-clk-virt + - qcom,sm6115-mmrt-virt + - qcom,sm6115-mmnrt-virt + + required: + - compatible + + unevaluatedProperties: false + +required: + - compatible + - reg + +allOf: + - $ref: qcom,rpm-common.yaml# + - if: + properties: + compatible: + const: qcom,sm6115-cnoc + + then: + properties: + clocks: + items: + - description: USB-NoC AXI clock + + clock-names: + items: + - const: usb_axi + + - if: + properties: + compatible: + const: qcom,sm6115-snoc + + then: + properties: + clocks: + items: + - description: CPU-NoC AXI clock. + - description: UFS-NoC AXI clock. + - description: USB-NoC AXI clock. + - description: IPA clock. + + clock-names: + items: + - const: cpu_axi + - const: ufs_axi + - const: usb_axi + - const: ipa + + - if: + properties: + compatible: + enum: + - qcom,sm6115-bimc + - qcom,sm6115-clk-virt + - qcom,sm6115-mmrt-virt + - qcom,sm6115-mmnrt-virt + + then: + properties: + clocks: false + clock-names: false + +unevaluatedProperties: false + +examples: + - | + #include + #include + + snoc: interconnect@1880000 { + compatible = "qcom,sm6115-snoc"; + reg = <0x01880000 0x60200>; + clocks = <&gcc GCC_SYS_NOC_CPUSS_AHB_CLK>, + <&gcc GCC_SYS_NOC_UFS_PHY_AXI_CLK>, + <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, + <&rpmcc RPM_SMD_IPA_CLK>; + clock-names = "cpu_axi", + "ufs_axi", + "usb_axi", + "ipa"; + #interconnect-cells = <1>; + + qup_virt: interconnect-clk { + compatible = "qcom,sm6115-clk-virt"; + #interconnect-cells = <1>; + }; + + mmnrt_virt: interconnect-mmnrt { + compatible = "qcom,sm6115-mmnrt-virt"; + #interconnect-cells = <1>; + }; + + mmrt_virt: interconnect-mmrt { + compatible = "qcom,sm6115-mmrt-virt"; + #interconnect-cells = <1>; + }; + }; + + cnoc: interconnect@1900000 { + compatible = "qcom,sm6115-cnoc"; + reg = <0x01900000 0x8200>; + #interconnect-cells = <1>; + }; diff --git a/include/dt-bindings/interconnect/qcom,sm6115.h b/include/dt-bindings/interconnect/qcom,sm6115.h new file mode 100644 index 000000000000..21090e585f05 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm6115.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM6115_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM6115_H + +/* BIMC */ +#define MASTER_AMPSS_M0 0 +#define MASTER_SNOC_BIMC_RT 1 +#define MASTER_SNOC_BIMC_NRT 2 +#define SNOC_BIMC_MAS 3 +#define MASTER_GRAPHICS_3D 4 +#define MASTER_TCU_0 5 +#define SLAVE_EBI_CH0 6 +#define BIMC_SNOC_SLV 7 + +/* CNOC */ +#define SNOC_CNOC_MAS 0 +#define MASTER_QDSS_DAP 1 +#define SLAVE_AHB2PHY_USB 2 +#define SLAVE_APSS_THROTTLE_CFG 3 +#define SLAVE_BIMC_CFG 4 +#define SLAVE_BOOT_ROM 5 +#define SLAVE_CAMERA_NRT_THROTTLE_CFG 6 +#define SLAVE_CAMERA_RT_THROTTLE_CFG 7 +#define SLAVE_CAMERA_CFG 8 +#define SLAVE_CLK_CTL 9 +#define SLAVE_RBCPR_CX_CFG 10 +#define SLAVE_RBCPR_MX_CFG 11 +#define SLAVE_CRYPTO_0_CFG 12 +#define SLAVE_DCC_CFG 13 +#define SLAVE_DDR_PHY_CFG 14 +#define SLAVE_DDR_SS_CFG 15 +#define SLAVE_DISPLAY_CFG 16 +#define SLAVE_DISPLAY_THROTTLE_CFG 17 +#define SLAVE_GPU_CFG 18 +#define SLAVE_GPU_THROTTLE_CFG 19 +#define SLAVE_HWKM_CORE 20 +#define SLAVE_IMEM_CFG 21 +#define SLAVE_IPA_CFG 22 +#define SLAVE_LPASS 23 +#define SLAVE_MAPSS 24 +#define SLAVE_MDSP_MPU_CFG 25 +#define SLAVE_MESSAGE_RAM 26 +#define SLAVE_CNOC_MSS 27 +#define SLAVE_PDM 28 +#define SLAVE_PIMEM_CFG 29 +#define SLAVE_PKA_CORE 30 +#define SLAVE_PMIC_ARB 31 +#define SLAVE_QDSS_CFG 32 +#define SLAVE_QM_CFG 33 +#define SLAVE_QM_MPU_CFG 34 +#define SLAVE_QPIC 35 +#define SLAVE_QUP_0 36 +#define SLAVE_RPM 37 +#define SLAVE_SDCC_1 38 +#define SLAVE_SDCC_2 39 +#define SLAVE_SECURITY 40 +#define SLAVE_SNOC_CFG 41 +#define SLAVE_TCSR 42 +#define SLAVE_TLMM 43 +#define SLAVE_USB3 44 +#define SLAVE_VENUS_CFG 45 +#define SLAVE_VENUS_THROTTLE_CFG 46 +#define SLAVE_VSENSE_CTRL_CFG 47 +#define SLAVE_SERVICE_CNOC 48 + +/* SNOC */ +#define MASTER_CRYPTO_CORE0 0 +#define MASTER_SNOC_CFG 1 +#define MASTER_TIC 2 +#define MASTER_ANOC_SNOC 3 +#define BIMC_SNOC_MAS 4 +#define MASTER_PIMEM 5 +#define MASTER_QDSS_BAM 6 +#define MASTER_QPIC 7 +#define MASTER_QUP_0 8 +#define MASTER_IPA 9 +#define MASTER_QDSS_ETR 10 +#define MASTER_SDCC_1 11 +#define MASTER_SDCC_2 12 +#define MASTER_USB3 13 +#define SLAVE_APPSS 14 +#define SNOC_CNOC_SLV 15 +#define SLAVE_OCIMEM 16 +#define SLAVE_PIMEM 17 +#define SNOC_BIMC_SLV 18 +#define SLAVE_SERVICE_SNOC 19 +#define SLAVE_QDSS_STM 20 +#define SLAVE_TCU 21 +#define SLAVE_ANOC_SNOC 22 + +/* CLK Virtual */ +#define MASTER_QUP_CORE_0 0 +#define SLAVE_QUP_CORE_0 1 + +/* MMRT Virtual */ +#define MASTER_CAMNOC_HF 0 +#define MASTER_MDP_PORT0 1 +#define SLAVE_SNOC_BIMC_RT 2 + +/* MMNRT Virtual */ +#define MASTER_CAMNOC_SF 0 +#define MASTER_VIDEO_P0 1 +#define MASTER_VIDEO_PROC 2 +#define SLAVE_SNOC_BIMC_NRT 3 + +#endif From 28d3d0696688154cc04983f343011d07bf0508e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Dec 2023 18:05:15 +0300 Subject: [PATCH 2797/7721] drm/bridge: nxp-ptn3460: simplify some error checking The i2c_master_send/recv() functions return negative error codes or they return "len" on success. So the error handling here can be written as just normal checks for "if (ret < 0) return ret;". No need to complicate things. Btw, in this code the "len" parameter can never be zero, but even if it were, then I feel like this would still be the best way to write it. Fixes: 914437992876 ("drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking") Suggested-by: Neil Armstrong Signed-off-by: Dan Carpenter Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/04242630-42d8-4920-8c67-24ac9db6b3c9@moroto.mountain --- drivers/gpu/drm/bridge/nxp-ptn3460.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 9b7eb8c669c1..7c0076e49953 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -54,15 +54,15 @@ static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, int ret; ret = i2c_master_send(ptn_bridge->client, &addr, 1); - if (ret <= 0) { + if (ret < 0) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); - return ret ?: -EIO; + return ret; } ret = i2c_master_recv(ptn_bridge->client, buf, len); - if (ret != len) { + if (ret < 0) { DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); - return ret < 0 ? ret : -EIO; + return ret; } return 0; @@ -78,9 +78,9 @@ static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, buf[1] = val; ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); - if (ret != ARRAY_SIZE(buf)) { + if (ret < 0) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); - return ret < 0 ? ret : -EIO; + return ret; } return 0; From e88b859cab4b8decd9e545678a66aecb2506d106 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Fri, 3 Nov 2023 09:54:00 +0100 Subject: [PATCH 2798/7721] ARM: multi_v7_defconfig: Add SCMI reset support SCMI reset controllers are used in the ARMv7 STMicroelectronics stm32mp boards: - for STM32MP13: stm32mp135f-dk - for STM32MP15 boards with SCMI variant, introduced by commit 5b7e58313a77 ("ARM: dts: stm32: Add SCMI version of STM32 boards (DK1/DK2/ED1/EV1)") * stm32mp157c-ev1-scmi * stm32mp157c-ed1-scmi * stm32mp157c-dk2-scmi * stm32mp157a-dk1-scmi Cc: Arnd Bergmann Cc: Alexandre Torgue Signed-off-by: Etienne Carriere Link: https://lore.kernel.org/r/20231103085400.2924282-1-etienne.carriere@foss.st.com Signed-off-by: Arnd Bergmann --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 10fd74bf85f9..9303061a6f21 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1191,6 +1191,7 @@ CONFIG_PWM_TEGRA=y CONFIG_PWM_VT8500=y CONFIG_KEYSTONE_IRQ=y CONFIG_RESET_MCHP_SPARX5=y +CONFIG_RESET_SCMI=y CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_SUN9I_USB=y CONFIG_PHY_BRCM_USB=m From a6b5f50fefe93676af8798ecc1f633581d1702f8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 6 Dec 2023 08:30:47 -0300 Subject: [PATCH 2799/7721] ASoC: dt-bindings: fsl,xcvr: Adjust the number of interrupts Unlike i.MX8MP, i.MX93 has two XCVR interrupts. Describe the two interrupts for the i.MX93 to fix the following dt-schema warning: imx93-11x11-evk.dtb: xcvr@42680000: interrupts: [[0, 203, 4], [0, 204, 4]] is too long from schema $id: http://devicetree.org/schemas/sound/fsl,xcvr.yaml# Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231206113047.2240055-1-festevam@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,xcvr.yaml | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 799b362ba498..0eb0c1ba8710 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -38,7 +38,10 @@ properties: - const: txfifo interrupts: - maxItems: 1 + items: + - description: WAKEUPMIX Audio XCVR Interrupt 1 + - description: WAKEUPMIX Audio XCVR Interrupt 2 + minItems: 1 clocks: items: @@ -78,6 +81,23 @@ required: - dma-names - resets +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx93-xcvr + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + else: + properties: + interrupts: + maxItems: 1 + additionalProperties: false examples: From f9b5aae471dca94de2ea525136a59927e9b1d7cf Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Tue, 5 Dec 2023 19:46:04 +0100 Subject: [PATCH 2800/7721] dt-bindings: arm: ti: Add verdin am62 mallow board Add Mallow carrier board for wifi and nonwifi variants of Toradex Verdin AM62 SoM. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Acked-by: Krzysztof Kozlowski Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231205184605.35225-3-francesco@dolcini.it Signed-off-by: Nishanth Menon --- Documentation/devicetree/bindings/arm/ti/k3.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml index 03d2a0d79fb0..c6506bccfe88 100644 --- a/Documentation/devicetree/bindings/arm/ti/k3.yaml +++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml @@ -50,6 +50,7 @@ properties: - enum: - toradex,verdin-am62-nonwifi-dahlia # Verdin AM62 Module on Dahlia - toradex,verdin-am62-nonwifi-dev # Verdin AM62 Module on Verdin Development Board + - toradex,verdin-am62-nonwifi-mallow # Verdin AM62 Module on Mallow - toradex,verdin-am62-nonwifi-yavia # Verdin AM62 Module on Yavia - const: toradex,verdin-am62-nonwifi # Verdin AM62 Module without Wi-Fi / BT - const: toradex,verdin-am62 # Verdin AM62 Module @@ -60,6 +61,7 @@ properties: - enum: - toradex,verdin-am62-wifi-dahlia # Verdin AM62 Wi-Fi / BT Module on Dahlia - toradex,verdin-am62-wifi-dev # Verdin AM62 Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-am62-wifi-mallow # Verdin AM62 Wi-Fi / BT Module on Mallow - toradex,verdin-am62-wifi-yavia # Verdin AM62 Wi-Fi / BT Module on Yavia - const: toradex,verdin-am62-wifi # Verdin AM62 Wi-Fi / BT Module - const: toradex,verdin-am62 # Verdin AM62 Module From 7698622fbcf4fef2ec7e2fcbae35eb5e503dfddf Mon Sep 17 00:00:00 2001 From: Joao Paulo Goncalves Date: Tue, 5 Dec 2023 19:46:05 +0100 Subject: [PATCH 2801/7721] arm64: dts: ti: Add verdin am62 mallow board Add Toradex Verdin AM62 Mallow carrier board support. Mallow is a low-cost carrier board in the Verdin family with a small form factor and build for volume production making it ideal for industrial and embedded applications. https://www.toradex.com/products/carrier-board/mallow-carrier-board Signed-off-by: Joao Paulo Goncalves Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231205184605.35225-4-francesco@dolcini.it Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/Makefile | 2 + .../boot/dts/ti/k3-am62-verdin-mallow.dtsi | 188 ++++++++++++++++++ .../dts/ti/k3-am625-verdin-nonwifi-mallow.dts | 22 ++ .../dts/ti/k3-am625-verdin-wifi-mallow.dts | 22 ++ 4 files changed, 234 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 5ef49b02c71f..1ac47876bc99 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -16,9 +16,11 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi new file mode 100644 index 000000000000..17b93534f658 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin AM62 SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_clk_gpio>, + <&pinctrl_qspi1_cs_gpio>, + <&pinctrl_qspi1_io0_gpio>, + <&pinctrl_qspi1_io1_gpio>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 11 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Verdin ETH */ +&cpsw3g { + status = "okay"; +}; + +/* Verdin MDIO */ +&cpsw3g_mdio { + status = "okay"; +}; + +/* Verdin ETH_1*/ +&cpsw_port1 { + status = "okay"; +}; + +/* Verdin PWM_1 and PWM_2*/ +&epwm0 { + status = "okay"; +}; + +/* Verdin PWM_3 DSI */ +&epwm1 { + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ctrl_sleep_moci>, + <&pinctrl_gpio_1>, + <&pinctrl_gpio_2>, + <&pinctrl_gpio_3>, + <&pinctrl_gpio_4>; +}; + +/* Verdin I2C_1 */ +&main_i2c1 { + status = "okay"; + + /* Temperature sensor */ + sensor@4f { + compatible = "ti,tmp1075"; + reg = <0x4f>; + }; + + /* EEPROM */ + eeprom@57 { + compatible = "st,24c02", "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +/* Verdin I2C_2 DSI */ +&main_i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4 CSI */ +&main_i2c3 { + status = "okay"; +}; + +/* Verdin CAN_1 */ +&main_mcan0 { + status = "okay"; +}; + +/* Verdin SPI_1 */ +&main_spi1 { + pinctrl-0 = <&pinctrl_spi1>, + <&pinctrl_spi1_cs0>, + <&pinctrl_qspi1_cs2_gpio>; + cs-gpios = <0>, <&main_gpio0 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +/* Verdin UART_3 */ +&main_uart0 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&main_uart1 { + status = "okay"; +}; + +/* Verdin I2C_3_HDMI */ +&mcu_i2c0 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&mcu_mcan0 { + status = "okay"; +}; + +/* Verdin UART_4 */ +&mcu_uart0 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&sdhci1 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usbss0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbss1 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +/* Verdin CTRL_WAKE1_MICO# */ +&verdin_gpio_keys { + status = "okay"; +}; + +/* Verdin UART_2 */ +&wkup_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts new file mode 100644 index 000000000000..9cae12106e0e --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-nonwifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 on Mallow Board"; + compatible = "toradex,verdin-am62-nonwifi-mallow", + "toradex,verdin-am62-nonwifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts new file mode 100644 index 000000000000..81d834b22649 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-wifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 WB on Mallow Board"; + compatible = "toradex,verdin-am62-wifi-mallow", + "toradex,verdin-am62-wifi", + "toradex,verdin-am62", + "ti,am625"; +}; From 909fa05dd3c181e5b403912889057f7cdbf3906c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:13 -0800 Subject: [PATCH 2802/7721] bpf: align CAP_NET_ADMIN checks with bpf_capable() approach Within BPF syscall handling code CAP_NET_ADMIN checks stand out a bit compared to CAP_BPF and CAP_PERFMON checks. For the latter, CAP_BPF or CAP_PERFMON are checked first, but if they are not set, CAP_SYS_ADMIN takes over and grants whatever part of BPF syscall is required. Similar kind of checks that involve CAP_NET_ADMIN are not so consistent. One out of four uses does follow CAP_BPF/CAP_PERFMON model: during BPF_PROG_LOAD, if the type of BPF program is "network-related" either CAP_NET_ADMIN or CAP_SYS_ADMIN is required to proceed. But in three other cases CAP_NET_ADMIN is required even if CAP_SYS_ADMIN is set: - when creating DEVMAP/XDKMAP/CPU_MAP maps; - when attaching CGROUP_SKB programs; - when handling BPF_PROG_QUERY command. This patch is changing the latter three cases to follow BPF_PROG_LOAD model, that is allowing to proceed under either CAP_NET_ADMIN or CAP_SYS_ADMIN. This also makes it cleaner in subsequent BPF token patches to switch wholesomely to a generic bpf_token_capable(int cap) check, that always falls back to CAP_SYS_ADMIN if requested capability is missing. Cc: Jakub Kicinski Acked-by: Yafang Shao Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index ebaccf77d56e..ee33a52abf18 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1121,6 +1121,11 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf, return ret; } +static bool bpf_net_capable(void) +{ + return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); +} + #define BPF_MAP_CREATE_LAST_FIELD map_extra /* called via syscall */ static int map_create(union bpf_attr *attr) @@ -1224,7 +1229,7 @@ static int map_create(union bpf_attr *attr) case BPF_MAP_TYPE_DEVMAP: case BPF_MAP_TYPE_DEVMAP_HASH: case BPF_MAP_TYPE_XSKMAP: - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) return -EPERM; break; default: @@ -2625,7 +2630,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) !bpf_capable()) return -EPERM; - if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) + if (is_net_admin_prog_type(type) && !bpf_net_capable()) return -EPERM; if (is_perfmon_prog_type(type) && !perfmon_capable()) return -EPERM; @@ -3777,7 +3782,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, case BPF_PROG_TYPE_SK_LOOKUP: return attach_type == prog->expected_attach_type ? 0 : -EINVAL; case BPF_PROG_TYPE_CGROUP_SKB: - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) /* cg-skb progs can be loaded by unpriv user. * check permissions at attach time. */ @@ -3980,7 +3985,7 @@ static int bpf_prog_detach(const union bpf_attr *attr) static int bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) { - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) return -EPERM; if (CHECK_ATTR(BPF_PROG_QUERY)) return -EINVAL; From 40bba140c60fbb3ee8df6203c82fbd3de9f19d95 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:14 -0800 Subject: [PATCH 2803/7721] bpf: add BPF token delegation mount options to BPF FS Add few new mount options to BPF FS that allow to specify that a given BPF FS instance allows creation of BPF token (added in the next patch), and what sort of operations are allowed under BPF token. As such, we get 4 new mount options, each is a bit mask - `delegate_cmds` allow to specify which bpf() syscall commands are allowed with BPF token derived from this BPF FS instance; - if BPF_MAP_CREATE command is allowed, `delegate_maps` specifies a set of allowable BPF map types that could be created with BPF token; - if BPF_PROG_LOAD command is allowed, `delegate_progs` specifies a set of allowable BPF program types that could be loaded with BPF token; - if BPF_PROG_LOAD command is allowed, `delegate_attachs` specifies a set of allowable BPF program attach types that could be loaded with BPF token; delegate_progs and delegate_attachs are meant to be used together, as full BPF program type is, in general, determined through both program type and program attach type. Currently, these mount options accept the following forms of values: - a special value "any", that enables all possible values of a given bit set; - numeric value (decimal or hexadecimal, determined by kernel automatically) that specifies a bit mask value directly; - all the values for a given mount option are combined, if specified multiple times. E.g., `mount -t bpf nodev /path/to/mount -o delegate_maps=0x1 -o delegate_maps=0x2` will result in a combined 0x3 mask. Ideally, more convenient (for humans) symbolic form derived from corresponding UAPI enums would be accepted (e.g., `-o delegate_progs=kprobe|tracepoint`) and I intend to implement this, but it requires a bunch of UAPI header churn, so I postponed it until this feature lands upstream or at least there is a definite consensus that this feature is acceptable and is going to make it, just to minimize amount of wasted effort and not increase amount of non-essential code to be reviewed. Attentive reader will notice that BPF FS is now marked as FS_USERNS_MOUNT, which theoretically makes it mountable inside non-init user namespace as long as the process has sufficient *namespaced* capabilities within that user namespace. But in reality we still restrict BPF FS to be mountable only by processes with CAP_SYS_ADMIN *in init userns* (extra check in bpf_fill_super()). FS_USERNS_MOUNT is added to allow creating BPF FS context object (i.e., fsopen("bpf")) from inside unprivileged process inside non-init userns, to capture that userns as the owning userns. It will still be required to pass this context object back to privileged process to instantiate and mount it. This manipulation is important, because capturing non-init userns as the owning userns of BPF FS instance (super block) allows to use that userns to constraint BPF token to that userns later on (see next patch). So creating BPF FS with delegation inside unprivileged userns will restrict derived BPF token objects to only "work" inside that intended userns, making it scoped to a intended "container". Also, setting these delegation options requires capable(CAP_SYS_ADMIN), so unprivileged process cannot set this up without involvement of a privileged process. There is a set of selftests at the end of the patch set that simulates this sequence of steps and validates that everything works as intended. But careful review is requested to make sure there are no missed gaps in the implementation and testing. This somewhat subtle set of aspects is the result of previous discussions ([0]) about various user namespace implications and interactions with BPF token functionality and is necessary to contain BPF token inside intended user namespace. [0] https://lore.kernel.org/bpf/20230704-hochverdient-lehne-eeb9eeef785e@brauner/ Acked-by: Christian Brauner Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 10 ++++++ kernel/bpf/inode.c | 88 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 10e5e4d8a00f..d3c9acc593ea 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1581,6 +1581,16 @@ struct bpf_link_primer { u32 id; }; +struct bpf_mount_opts { + umode_t mode; + + /* BPF token-related delegation options */ + u64 delegate_cmds; + u64 delegate_maps; + u64 delegate_progs; + u64 delegate_attachs; +}; + struct bpf_struct_ops_value; struct btf_member; diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 1aafb2ff2e95..220fe0f99095 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "preload/bpf_preload.h" enum bpf_type { @@ -599,10 +600,31 @@ EXPORT_SYMBOL(bpf_prog_get_type_path); */ static int bpf_show_options(struct seq_file *m, struct dentry *root) { + struct bpf_mount_opts *opts = root->d_sb->s_fs_info; umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX; if (mode != S_IRWXUGO) seq_printf(m, ",mode=%o", mode); + + if (opts->delegate_cmds == ~0ULL) + seq_printf(m, ",delegate_cmds=any"); + else if (opts->delegate_cmds) + seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); + + if (opts->delegate_maps == ~0ULL) + seq_printf(m, ",delegate_maps=any"); + else if (opts->delegate_maps) + seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); + + if (opts->delegate_progs == ~0ULL) + seq_printf(m, ",delegate_progs=any"); + else if (opts->delegate_progs) + seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); + + if (opts->delegate_attachs == ~0ULL) + seq_printf(m, ",delegate_attachs=any"); + else if (opts->delegate_attachs) + seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); return 0; } @@ -626,22 +648,27 @@ static const struct super_operations bpf_super_ops = { enum { OPT_MODE, + OPT_DELEGATE_CMDS, + OPT_DELEGATE_MAPS, + OPT_DELEGATE_PROGS, + OPT_DELEGATE_ATTACHS, }; static const struct fs_parameter_spec bpf_fs_parameters[] = { fsparam_u32oct ("mode", OPT_MODE), + fsparam_string ("delegate_cmds", OPT_DELEGATE_CMDS), + fsparam_string ("delegate_maps", OPT_DELEGATE_MAPS), + fsparam_string ("delegate_progs", OPT_DELEGATE_PROGS), + fsparam_string ("delegate_attachs", OPT_DELEGATE_ATTACHS), {} }; -struct bpf_mount_opts { - umode_t mode; -}; - static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct bpf_mount_opts *opts = fc->fs_private; + struct bpf_mount_opts *opts = fc->s_fs_info; struct fs_parse_result result; - int opt; + int opt, err; + u64 msk; opt = fs_parse(fc, bpf_fs_parameters, param, &result); if (opt < 0) { @@ -665,6 +692,28 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) case OPT_MODE: opts->mode = result.uint_32 & S_IALLUGO; break; + case OPT_DELEGATE_CMDS: + case OPT_DELEGATE_MAPS: + case OPT_DELEGATE_PROGS: + case OPT_DELEGATE_ATTACHS: + if (strcmp(param->string, "any") == 0) { + msk = ~0ULL; + } else { + err = kstrtou64(param->string, 0, &msk); + if (err) + return err; + } + /* Setting delegation mount options requires privileges */ + if (msk && !capable(CAP_SYS_ADMIN)) + return -EPERM; + switch (opt) { + case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break; + case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break; + case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break; + case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break; + default: return -EINVAL; + } + break; } return 0; @@ -739,10 +788,14 @@ static int populate_bpffs(struct dentry *parent) static int bpf_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr bpf_rfiles[] = { { "" } }; - struct bpf_mount_opts *opts = fc->fs_private; + struct bpf_mount_opts *opts = sb->s_fs_info; struct inode *inode; int ret; + /* Mounting an instance of BPF FS requires privileges */ + if (fc->user_ns != &init_user_ns && !capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles); if (ret) return ret; @@ -764,7 +817,7 @@ static int bpf_get_tree(struct fs_context *fc) static void bpf_free_fc(struct fs_context *fc) { - kfree(fc->fs_private); + kfree(fc->s_fs_info); } static const struct fs_context_operations bpf_context_ops = { @@ -786,17 +839,32 @@ static int bpf_init_fs_context(struct fs_context *fc) opts->mode = S_IRWXUGO; - fc->fs_private = opts; + /* start out with no BPF token delegation enabled */ + opts->delegate_cmds = 0; + opts->delegate_maps = 0; + opts->delegate_progs = 0; + opts->delegate_attachs = 0; + + fc->s_fs_info = opts; fc->ops = &bpf_context_ops; return 0; } +static void bpf_kill_super(struct super_block *sb) +{ + struct bpf_mount_opts *opts = sb->s_fs_info; + + kill_litter_super(sb); + kfree(opts); +} + static struct file_system_type bpf_fs_type = { .owner = THIS_MODULE, .name = "bpf", .init_fs_context = bpf_init_fs_context, .parameters = bpf_fs_parameters, - .kill_sb = kill_litter_super, + .kill_sb = bpf_kill_super, + .fs_flags = FS_USERNS_MOUNT, }; static int __init bpf_init(void) From 4527358b76861dfd64ee34aba45d81648fbc8a61 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:15 -0800 Subject: [PATCH 2804/7721] bpf: introduce BPF token object Add new kind of BPF kernel object, BPF token. BPF token is meant to allow delegating privileged BPF functionality, like loading a BPF program or creating a BPF map, from privileged process to a *trusted* unprivileged process, all while having a good amount of control over which privileged operations could be performed using provided BPF token. This is achieved through mounting BPF FS instance with extra delegation mount options, which determine what operations are delegatable, and also constraining it to the owning user namespace (as mentioned in the previous patch). BPF token itself is just a derivative from BPF FS and can be created through a new bpf() syscall command, BPF_TOKEN_CREATE, which accepts BPF FS FD, which can be attained through open() API by opening BPF FS mount point. Currently, BPF token "inherits" delegated command, map types, prog type, and attach type bit sets from BPF FS as is. In the future, having an BPF token as a separate object with its own FD, we can allow to further restrict BPF token's allowable set of things either at the creation time or after the fact, allowing the process to guard itself further from unintentionally trying to load undesired kind of BPF programs. But for now we keep things simple and just copy bit sets as is. When BPF token is created from BPF FS mount, we take reference to the BPF super block's owning user namespace, and then use that namespace for checking all the {CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN} capabilities that are normally only checked against init userns (using capable()), but now we check them using ns_capable() instead (if BPF token is provided). See bpf_token_capable() for details. Such setup means that BPF token in itself is not sufficient to grant BPF functionality. User namespaced process has to *also* have necessary combination of capabilities inside that user namespace. So while previously CAP_BPF was useless when granted within user namespace, now it gains a meaning and allows container managers and sys admins to have a flexible control over which processes can and need to use BPF functionality within the user namespace (i.e., container in practice). And BPF FS delegation mount options and derived BPF tokens serve as a per-container "flag" to grant overall ability to use bpf() (plus further restrict on which parts of bpf() syscalls are treated as namespaced). Note also, BPF_TOKEN_CREATE command itself requires ns_capable(CAP_BPF) within the BPF FS owning user namespace, rounding up the ns_capable() story of BPF token. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 41 +++++++ include/uapi/linux/bpf.h | 37 ++++++ kernel/bpf/Makefile | 2 +- kernel/bpf/inode.c | 12 +- kernel/bpf/syscall.c | 17 +++ kernel/bpf/token.c | 214 +++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 37 ++++++ 7 files changed, 354 insertions(+), 6 deletions(-) create mode 100644 kernel/bpf/token.c diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d3c9acc593ea..aa9cf8e5fab1 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -51,6 +51,10 @@ struct module; struct bpf_func_state; struct ftrace_ops; struct cgroup; +struct bpf_token; +struct user_namespace; +struct super_block; +struct inode; extern struct idr btf_idr; extern spinlock_t btf_idr_lock; @@ -1591,6 +1595,13 @@ struct bpf_mount_opts { u64 delegate_attachs; }; +struct bpf_token { + struct work_struct work; + atomic64_t refcnt; + struct user_namespace *userns; + u64 allowed_cmds; +}; + struct bpf_struct_ops_value; struct btf_member; @@ -2048,6 +2059,7 @@ static inline void bpf_enable_instrumentation(void) migrate_enable(); } +extern const struct super_operations bpf_super_ops; extern const struct file_operations bpf_map_fops; extern const struct file_operations bpf_prog_fops; extern const struct file_operations bpf_iter_fops; @@ -2182,6 +2194,8 @@ static inline void bpf_map_dec_elem_count(struct bpf_map *map) extern int sysctl_unprivileged_bpf_disabled; +bool bpf_token_capable(const struct bpf_token *token, int cap); + static inline bool bpf_allow_ptr_leaks(void) { return perfmon_capable(); @@ -2216,8 +2230,17 @@ int bpf_link_new_fd(struct bpf_link *link); struct bpf_link *bpf_link_get_from_fd(u32 ufd); struct bpf_link *bpf_link_get_curr_or_next(u32 *id); +void bpf_token_inc(struct bpf_token *token); +void bpf_token_put(struct bpf_token *token); +int bpf_token_create(union bpf_attr *attr); +struct bpf_token *bpf_token_get_from_fd(u32 ufd); + +bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); + int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); +struct inode *bpf_get_inode(struct super_block *sb, const struct inode *dir, + umode_t mode); #define BPF_ITER_FUNC_PREFIX "bpf_iter_" #define DEFINE_BPF_ITER_FUNC(target, args...) \ @@ -2580,6 +2603,24 @@ static inline int bpf_obj_get_user(const char __user *pathname, int flags) return -EOPNOTSUPP; } +static inline bool bpf_token_capable(const struct bpf_token *token, int cap) +{ + return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN)); +} + +static inline void bpf_token_inc(struct bpf_token *token) +{ +} + +static inline void bpf_token_put(struct bpf_token *token) +{ +} + +static inline struct bpf_token *bpf_token_get_from_fd(u32 ufd) +{ + return ERR_PTR(-EOPNOTSUPP); +} + static inline void __dev_flush(void) { } diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e88746ba7d21..d4a567e5bc3c 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -847,6 +847,36 @@ union bpf_iter_link_info { * Returns zero on success. On error, -1 is returned and *errno* * is set appropriately. * + * BPF_TOKEN_CREATE + * Description + * Create BPF token with embedded information about what + * BPF-related functionality it allows: + * - a set of allowed bpf() syscall commands; + * - a set of allowed BPF map types to be created with + * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed; + * - a set of allowed BPF program types and BPF program attach + * types to be loaded with BPF_PROG_LOAD command, if + * BPF_PROG_LOAD itself is allowed. + * + * BPF token is created (derived) from an instance of BPF FS, + * assuming it has necessary delegation mount options specified. + * This BPF token can be passed as an extra parameter to various + * bpf() syscall commands to grant BPF subsystem functionality to + * unprivileged processes. + * + * When created, BPF token is "associated" with the owning + * user namespace of BPF FS instance (super block) that it was + * derived from, and subsequent BPF operations performed with + * BPF token would be performing capabilities checks (i.e., + * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within + * that user namespace. Without BPF token, such capabilities + * have to be granted in init user namespace, making bpf() + * syscall incompatible with user namespace, for the most part. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * * NOTES * eBPF objects (maps and programs) can be shared between processes. * @@ -901,6 +931,8 @@ enum bpf_cmd { BPF_ITER_CREATE, BPF_LINK_DETACH, BPF_PROG_BIND_MAP, + BPF_TOKEN_CREATE, + __MAX_BPF_CMD, }; enum bpf_map_type { @@ -1712,6 +1744,11 @@ union bpf_attr { __u32 flags; /* extra flags */ } prog_bind_map; + struct { /* struct used by BPF_TOKEN_CREATE command */ + __u32 flags; + __u32 bpffs_fd; + } token_create; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index f526b7573e97..4ce95acfcaa7 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse endif CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy) -obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o +obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 220fe0f99095..6ce3f9696e72 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -99,9 +99,9 @@ static const struct inode_operations bpf_prog_iops = { }; static const struct inode_operations bpf_map_iops = { }; static const struct inode_operations bpf_link_iops = { }; -static struct inode *bpf_get_inode(struct super_block *sb, - const struct inode *dir, - umode_t mode) +struct inode *bpf_get_inode(struct super_block *sb, + const struct inode *dir, + umode_t mode) { struct inode *inode; @@ -602,11 +602,13 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) { struct bpf_mount_opts *opts = root->d_sb->s_fs_info; umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX; + u64 mask; if (mode != S_IRWXUGO) seq_printf(m, ",mode=%o", mode); - if (opts->delegate_cmds == ~0ULL) + mask = (1ULL << __MAX_BPF_CMD) - 1; + if ((opts->delegate_cmds & mask) == mask) seq_printf(m, ",delegate_cmds=any"); else if (opts->delegate_cmds) seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); @@ -639,7 +641,7 @@ static void bpf_free_inode(struct inode *inode) free_inode_nonrcu(inode); } -static const struct super_operations bpf_super_ops = { +const struct super_operations bpf_super_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .show_options = bpf_show_options, diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index ee33a52abf18..a156d549b356 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5377,6 +5377,20 @@ static int bpf_prog_bind_map(union bpf_attr *attr) return ret; } +#define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd + +static int token_create(union bpf_attr *attr) +{ + if (CHECK_ATTR(BPF_TOKEN_CREATE)) + return -EINVAL; + + /* no flags are supported yet */ + if (attr->token_create.flags) + return -EINVAL; + + return bpf_token_create(attr); +} + static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) { union bpf_attr attr; @@ -5510,6 +5524,9 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) case BPF_PROG_BIND_MAP: err = bpf_prog_bind_map(&attr); break; + case BPF_TOKEN_CREATE: + err = token_create(&attr); + break; default: err = -EINVAL; break; diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c new file mode 100644 index 000000000000..e18aaecc67e9 --- /dev/null +++ b/kernel/bpf/token.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool bpf_token_capable(const struct bpf_token *token, int cap) +{ + /* BPF token allows ns_capable() level of capabilities, but only if + * token's userns is *exactly* the same as current user's userns + */ + if (token && current_user_ns() == token->userns) { + if (ns_capable(token->userns, cap)) + return true; + if (cap != CAP_SYS_ADMIN && ns_capable(token->userns, CAP_SYS_ADMIN)) + return true; + } + /* otherwise fallback to capable() checks */ + return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN)); +} + +void bpf_token_inc(struct bpf_token *token) +{ + atomic64_inc(&token->refcnt); +} + +static void bpf_token_free(struct bpf_token *token) +{ + put_user_ns(token->userns); + kvfree(token); +} + +static void bpf_token_put_deferred(struct work_struct *work) +{ + struct bpf_token *token = container_of(work, struct bpf_token, work); + + bpf_token_free(token); +} + +void bpf_token_put(struct bpf_token *token) +{ + if (!token) + return; + + if (!atomic64_dec_and_test(&token->refcnt)) + return; + + INIT_WORK(&token->work, bpf_token_put_deferred); + schedule_work(&token->work); +} + +static int bpf_token_release(struct inode *inode, struct file *filp) +{ + struct bpf_token *token = filp->private_data; + + bpf_token_put(token); + return 0; +} + +static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) +{ + struct bpf_token *token = filp->private_data; + u64 mask; + + BUILD_BUG_ON(__MAX_BPF_CMD >= 64); + mask = (1ULL << __MAX_BPF_CMD) - 1; + if ((token->allowed_cmds & mask) == mask) + seq_printf(m, "allowed_cmds:\tany\n"); + else + seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds); +} + +#define BPF_TOKEN_INODE_NAME "bpf-token" + +static const struct inode_operations bpf_token_iops = { }; + +static const struct file_operations bpf_token_fops = { + .release = bpf_token_release, + .show_fdinfo = bpf_token_show_fdinfo, +}; + +int bpf_token_create(union bpf_attr *attr) +{ + struct bpf_mount_opts *mnt_opts; + struct bpf_token *token = NULL; + struct user_namespace *userns; + struct inode *inode; + struct file *file; + struct path path; + struct fd f; + umode_t mode; + int err, fd; + + f = fdget(attr->token_create.bpffs_fd); + if (!f.file) + return -EBADF; + + path = f.file->f_path; + path_get(&path); + fdput(f); + + if (path.dentry != path.mnt->mnt_sb->s_root) { + err = -EINVAL; + goto out_path; + } + if (path.mnt->mnt_sb->s_op != &bpf_super_ops) { + err = -EINVAL; + goto out_path; + } + err = path_permission(&path, MAY_ACCESS); + if (err) + goto out_path; + + userns = path.dentry->d_sb->s_user_ns; + /* + * Enforce that creators of BPF tokens are in the same user + * namespace as the BPF FS instance. This makes reasoning about + * permissions a lot easier and we can always relax this later. + */ + if (current_user_ns() != userns) { + err = -EPERM; + goto out_path; + } + if (!ns_capable(userns, CAP_BPF)) { + err = -EPERM; + goto out_path; + } + + mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); + inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out_path; + } + + inode->i_op = &bpf_token_iops; + inode->i_fop = &bpf_token_fops; + clear_nlink(inode); /* make sure it is unlinked */ + + file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops); + if (IS_ERR(file)) { + iput(inode); + err = PTR_ERR(file); + goto out_path; + } + + token = kvzalloc(sizeof(*token), GFP_USER); + if (!token) { + err = -ENOMEM; + goto out_file; + } + + atomic64_set(&token->refcnt, 1); + + /* remember bpffs owning userns for future ns_capable() checks */ + token->userns = get_user_ns(userns); + + mnt_opts = path.dentry->d_sb->s_fs_info; + token->allowed_cmds = mnt_opts->delegate_cmds; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + err = fd; + goto out_token; + } + + file->private_data = token; + fd_install(fd, file); + + path_put(&path); + return fd; + +out_token: + bpf_token_free(token); +out_file: + fput(file); +out_path: + path_put(&path); + return err; +} + +struct bpf_token *bpf_token_get_from_fd(u32 ufd) +{ + struct fd f = fdget(ufd); + struct bpf_token *token; + + if (!f.file) + return ERR_PTR(-EBADF); + if (f.file->f_op != &bpf_token_fops) { + fdput(f); + return ERR_PTR(-EINVAL); + } + + token = f.file->private_data; + bpf_token_inc(token); + fdput(f); + + return token; +} + +bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + /* BPF token can be used only within exactly the same userns in which + * it was created + */ + if (!token || current_user_ns() != token->userns) + return false; + + return token->allowed_cmds & (1ULL << cmd); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e88746ba7d21..d4a567e5bc3c 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -847,6 +847,36 @@ union bpf_iter_link_info { * Returns zero on success. On error, -1 is returned and *errno* * is set appropriately. * + * BPF_TOKEN_CREATE + * Description + * Create BPF token with embedded information about what + * BPF-related functionality it allows: + * - a set of allowed bpf() syscall commands; + * - a set of allowed BPF map types to be created with + * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed; + * - a set of allowed BPF program types and BPF program attach + * types to be loaded with BPF_PROG_LOAD command, if + * BPF_PROG_LOAD itself is allowed. + * + * BPF token is created (derived) from an instance of BPF FS, + * assuming it has necessary delegation mount options specified. + * This BPF token can be passed as an extra parameter to various + * bpf() syscall commands to grant BPF subsystem functionality to + * unprivileged processes. + * + * When created, BPF token is "associated" with the owning + * user namespace of BPF FS instance (super block) that it was + * derived from, and subsequent BPF operations performed with + * BPF token would be performing capabilities checks (i.e., + * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within + * that user namespace. Without BPF token, such capabilities + * have to be granted in init user namespace, making bpf() + * syscall incompatible with user namespace, for the most part. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * * NOTES * eBPF objects (maps and programs) can be shared between processes. * @@ -901,6 +931,8 @@ enum bpf_cmd { BPF_ITER_CREATE, BPF_LINK_DETACH, BPF_PROG_BIND_MAP, + BPF_TOKEN_CREATE, + __MAX_BPF_CMD, }; enum bpf_map_type { @@ -1712,6 +1744,11 @@ union bpf_attr { __u32 flags; /* extra flags */ } prog_bind_map; + struct { /* struct used by BPF_TOKEN_CREATE command */ + __u32 flags; + __u32 bpffs_fd; + } token_create; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF From 688b7270b3cb75e8ac78123d719967db40336e5b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:16 -0800 Subject: [PATCH 2805/7721] bpf: add BPF token support to BPF_MAP_CREATE command Allow providing token_fd for BPF_MAP_CREATE command to allow controlled BPF map creation from unprivileged process through delegated BPF token. Wire through a set of allowed BPF map types to BPF token, derived from BPF FS at BPF token creation time. This, in combination with allowed_cmds allows to create a narrowly-focused BPF token (controlled by privileged agent) with a restrictive set of BPF maps that application can attempt to create. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 2 + include/uapi/linux/bpf.h | 2 + kernel/bpf/inode.c | 3 +- kernel/bpf/syscall.c | 52 ++++++++++++++----- kernel/bpf/token.c | 16 ++++++ tools/include/uapi/linux/bpf.h | 2 + .../selftests/bpf/prog_tests/libbpf_probes.c | 2 + .../selftests/bpf/prog_tests/libbpf_str.c | 3 ++ 8 files changed, 67 insertions(+), 15 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index aa9cf8e5fab1..e08e8436df38 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1600,6 +1600,7 @@ struct bpf_token { atomic64_t refcnt; struct user_namespace *userns; u64 allowed_cmds; + u64 allowed_maps; }; struct bpf_struct_ops_value; @@ -2236,6 +2237,7 @@ int bpf_token_create(union bpf_attr *attr); struct bpf_token *bpf_token_get_from_fd(u32 ufd); bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); +bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type); int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d4a567e5bc3c..0bba3392b17a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -983,6 +983,7 @@ enum bpf_map_type { BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_USER_RINGBUF, BPF_MAP_TYPE_CGRP_STORAGE, + __MAX_BPF_MAP_TYPE }; /* Note that tracing related programs such as @@ -1433,6 +1434,7 @@ union bpf_attr { * to using 5 hash functions). */ __u64 map_extra; + __u32 map_token_fd; }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 6ce3f9696e72..9c7865d1c53d 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -613,7 +613,8 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) else if (opts->delegate_cmds) seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); - if (opts->delegate_maps == ~0ULL) + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + if ((opts->delegate_maps & mask) == mask) seq_printf(m, ",delegate_maps=any"); else if (opts->delegate_maps) seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a156d549b356..22e14124cd61 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1009,8 +1009,8 @@ int map_check_no_btf(const struct bpf_map *map, return -ENOTSUPP; } -static int map_check_btf(struct bpf_map *map, const struct btf *btf, - u32 btf_key_id, u32 btf_value_id) +static int map_check_btf(struct bpf_map *map, struct bpf_token *token, + const struct btf *btf, u32 btf_key_id, u32 btf_value_id) { const struct btf_type *key_type, *value_type; u32 key_size, value_size; @@ -1038,7 +1038,7 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf, if (!IS_ERR_OR_NULL(map->record)) { int i; - if (!bpf_capable()) { + if (!bpf_token_capable(token, CAP_BPF)) { ret = -EPERM; goto free_map_tab; } @@ -1126,11 +1126,12 @@ static bool bpf_net_capable(void) return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); } -#define BPF_MAP_CREATE_LAST_FIELD map_extra +#define BPF_MAP_CREATE_LAST_FIELD map_token_fd /* called via syscall */ static int map_create(union bpf_attr *attr) { const struct bpf_map_ops *ops; + struct bpf_token *token = NULL; int numa_node = bpf_map_attr_numa_node(attr); u32 map_type = attr->map_type; struct bpf_map *map; @@ -1181,14 +1182,32 @@ static int map_create(union bpf_attr *attr) if (!ops->map_mem_usage) return -EINVAL; + if (attr->map_token_fd) { + token = bpf_token_get_from_fd(attr->map_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + + /* if current token doesn't grant map creation permissions, + * then we can't use this token, so ignore it and rely on + * system-wide capabilities checks + */ + if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) || + !bpf_token_allow_map_type(token, attr->map_type)) { + bpf_token_put(token); + token = NULL; + } + } + + err = -EPERM; + /* Intent here is for unprivileged_bpf_disabled to block BPF map * creation for unprivileged users; other actions depend * on fd availability and access to bpffs, so are dependent on * object creation success. Even with unprivileged BPF disabled, * capability checks are still carried out. */ - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) - return -EPERM; + if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF)) + goto put_token; /* check privileged map type permissions */ switch (map_type) { @@ -1221,25 +1240,27 @@ static int map_create(union bpf_attr *attr) case BPF_MAP_TYPE_LRU_PERCPU_HASH: case BPF_MAP_TYPE_STRUCT_OPS: case BPF_MAP_TYPE_CPUMAP: - if (!bpf_capable()) - return -EPERM; + if (!bpf_token_capable(token, CAP_BPF)) + goto put_token; break; case BPF_MAP_TYPE_SOCKMAP: case BPF_MAP_TYPE_SOCKHASH: case BPF_MAP_TYPE_DEVMAP: case BPF_MAP_TYPE_DEVMAP_HASH: case BPF_MAP_TYPE_XSKMAP: - if (!bpf_net_capable()) - return -EPERM; + if (!bpf_token_capable(token, CAP_NET_ADMIN)) + goto put_token; break; default: WARN(1, "unsupported map type %d", map_type); - return -EPERM; + goto put_token; } map = ops->map_alloc(attr); - if (IS_ERR(map)) - return PTR_ERR(map); + if (IS_ERR(map)) { + err = PTR_ERR(map); + goto put_token; + } map->ops = ops; map->map_type = map_type; @@ -1276,7 +1297,7 @@ static int map_create(union bpf_attr *attr) map->btf = btf; if (attr->btf_value_type_id) { - err = map_check_btf(map, btf, attr->btf_key_type_id, + err = map_check_btf(map, token, btf, attr->btf_key_type_id, attr->btf_value_type_id); if (err) goto free_map; @@ -1297,6 +1318,7 @@ static int map_create(union bpf_attr *attr) goto free_map_sec; bpf_map_save_memcg(map); + bpf_token_put(token); err = bpf_map_new_fd(map, f_flags); if (err < 0) { @@ -1317,6 +1339,8 @@ static int map_create(union bpf_attr *attr) free_map: btf_put(map->btf); map->ops->map_free(map); +put_token: + bpf_token_put(token); return err; } diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index e18aaecc67e9..06c34dae658e 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -72,6 +72,13 @@ static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) seq_printf(m, "allowed_cmds:\tany\n"); else seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds); + + BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64); + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + if ((token->allowed_maps & mask) == mask) + seq_printf(m, "allowed_maps:\tany\n"); + else + seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps); } #define BPF_TOKEN_INODE_NAME "bpf-token" @@ -161,6 +168,7 @@ int bpf_token_create(union bpf_attr *attr) mnt_opts = path.dentry->d_sb->s_fs_info; token->allowed_cmds = mnt_opts->delegate_cmds; + token->allowed_maps = mnt_opts->delegate_maps; fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { @@ -212,3 +220,11 @@ bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) return token->allowed_cmds & (1ULL << cmd); } + +bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type) +{ + if (!token || type >= __MAX_BPF_MAP_TYPE) + return false; + + return token->allowed_maps & (1ULL << type); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d4a567e5bc3c..0bba3392b17a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -983,6 +983,7 @@ enum bpf_map_type { BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_USER_RINGBUF, BPF_MAP_TYPE_CGRP_STORAGE, + __MAX_BPF_MAP_TYPE }; /* Note that tracing related programs such as @@ -1433,6 +1434,7 @@ union bpf_attr { * to using 5 hash functions). */ __u64 map_extra; + __u32 map_token_fd; }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c index 9f766ddd946a..573249a2814d 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c @@ -68,6 +68,8 @@ void test_libbpf_probe_map_types(void) if (map_type == BPF_MAP_TYPE_UNSPEC) continue; + if (strcmp(map_type_name, "__MAX_BPF_MAP_TYPE") == 0) + continue; if (!test__start_subtest(map_type_name)) continue; diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index c440ea3311ed..2a0633f43c73 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -132,6 +132,9 @@ static void test_libbpf_bpf_map_type_str(void) const char *map_type_str; char buf[256]; + if (map_type == __MAX_BPF_MAP_TYPE) + continue; + map_type_name = btf__str_by_offset(btf, e->name_off); map_type_str = libbpf_bpf_map_type_str(map_type); ASSERT_OK_PTR(map_type_str, map_type_name); From ee54b1a910e4d49c9a104f31ae3f5b979131adf8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:17 -0800 Subject: [PATCH 2806/7721] bpf: add BPF token support to BPF_BTF_LOAD command Accept BPF token FD in BPF_BTF_LOAD command to allow BTF data loading through delegated BPF token. BTF loading is a pretty straightforward operation, so as long as BPF token is created with allow_cmds granting BPF_BTF_LOAD command, kernel proceeds to parsing BTF data and creating BTF object. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 1 + kernel/bpf/syscall.c | 20 ++++++++++++++++++-- tools/include/uapi/linux/bpf.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 0bba3392b17a..9f9989e0d062 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1616,6 +1616,7 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 btf_log_true_size; + __u32 btf_token_fd; }; struct { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 22e14124cd61..d87c5c27cde3 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4777,15 +4777,31 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, return err; } -#define BPF_BTF_LOAD_LAST_FIELD btf_log_true_size +#define BPF_BTF_LOAD_LAST_FIELD btf_token_fd static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size) { + struct bpf_token *token = NULL; + if (CHECK_ATTR(BPF_BTF_LOAD)) return -EINVAL; - if (!bpf_capable()) + if (attr->btf_token_fd) { + token = bpf_token_get_from_fd(attr->btf_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) { + bpf_token_put(token); + token = NULL; + } + } + + if (!bpf_token_capable(token, CAP_BPF)) { + bpf_token_put(token); return -EPERM; + } + + bpf_token_put(token); return btf_new_fd(attr, uattr, uattr_size); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 0bba3392b17a..9f9989e0d062 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1616,6 +1616,7 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 btf_log_true_size; + __u32 btf_token_fd; }; struct { From e1cef620f598853a90f17701fcb1057a6768f7b8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:18 -0800 Subject: [PATCH 2807/7721] bpf: add BPF token support to BPF_PROG_LOAD command Add basic support of BPF token to BPF_PROG_LOAD. Wire through a set of allowed BPF program types and attach types, derived from BPF FS at BPF token creation time. Then make sure we perform bpf_token_capable() checks everywhere where it's relevant. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 6 ++ include/uapi/linux/bpf.h | 2 + kernel/bpf/core.c | 1 + kernel/bpf/inode.c | 6 +- kernel/bpf/syscall.c | 87 ++++++++++++++----- kernel/bpf/token.c | 27 ++++++ tools/include/uapi/linux/bpf.h | 2 + .../selftests/bpf/prog_tests/libbpf_probes.c | 2 + .../selftests/bpf/prog_tests/libbpf_str.c | 3 + 9 files changed, 110 insertions(+), 26 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e08e8436df38..20af87b59d70 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1461,6 +1461,7 @@ struct bpf_prog_aux { #ifdef CONFIG_SECURITY void *security; #endif + struct bpf_token *token; struct bpf_prog_offload *offload; struct btf *btf; struct bpf_func_info *func_info; @@ -1601,6 +1602,8 @@ struct bpf_token { struct user_namespace *userns; u64 allowed_cmds; u64 allowed_maps; + u64 allowed_progs; + u64 allowed_attachs; }; struct bpf_struct_ops_value; @@ -2238,6 +2241,9 @@ struct bpf_token *bpf_token_get_from_fd(u32 ufd); bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type); +bool bpf_token_allow_prog_type(const struct bpf_token *token, + enum bpf_prog_type prog_type, + enum bpf_attach_type attach_type); int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 9f9989e0d062..4df2d025c784 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1028,6 +1028,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ BPF_PROG_TYPE_NETFILTER, + __MAX_BPF_PROG_TYPE }; enum bpf_attach_type { @@ -1504,6 +1505,7 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 log_true_size; + __u32 prog_token_fd; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 4b813da8d6c0..47085839af8d 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2751,6 +2751,7 @@ void bpf_prog_free(struct bpf_prog *fp) if (aux->dst_prog) bpf_prog_put(aux->dst_prog); + bpf_token_put(aux->token); INIT_WORK(&aux->work, bpf_prog_free_deferred); schedule_work(&aux->work); } diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 9c7865d1c53d..5359a0929c35 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -619,12 +619,14 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) else if (opts->delegate_maps) seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); - if (opts->delegate_progs == ~0ULL) + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + if ((opts->delegate_progs & mask) == mask) seq_printf(m, ",delegate_progs=any"); else if (opts->delegate_progs) seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); - if (opts->delegate_attachs == ~0ULL) + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + if ((opts->delegate_attachs & mask) == mask) seq_printf(m, ",delegate_attachs=any"); else if (opts->delegate_attachs) seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d87c5c27cde3..2c8393c21b8c 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2608,13 +2608,15 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) } /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD log_true_size +#define BPF_PROG_LOAD_LAST_FIELD prog_token_fd static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) { enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog, *dst_prog = NULL; struct btf *attach_btf = NULL; + struct bpf_token *token = NULL; + bool bpf_cap; int err; char license[128]; @@ -2631,10 +2633,31 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_TEST_REG_INVARIANTS)) return -EINVAL; + bpf_prog_load_fixup_attach_type(attr); + + if (attr->prog_token_fd) { + token = bpf_token_get_from_fd(attr->prog_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + /* if current token doesn't grant prog loading permissions, + * then we can't use this token, so ignore it and rely on + * system-wide capabilities checks + */ + if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) || + !bpf_token_allow_prog_type(token, attr->prog_type, + attr->expected_attach_type)) { + bpf_token_put(token); + token = NULL; + } + } + + bpf_cap = bpf_token_capable(token, CAP_BPF); + err = -EPERM; + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && - !bpf_capable()) - return -EPERM; + !bpf_cap) + goto put_token; /* Intent here is for unprivileged_bpf_disabled to block BPF program * creation for unprivileged users; other actions depend @@ -2643,21 +2666,23 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) * capability checks are still carried out for these * and other operations. */ - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) - return -EPERM; + if (sysctl_unprivileged_bpf_disabled && !bpf_cap) + goto put_token; if (attr->insn_cnt == 0 || - attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) - return -E2BIG; + attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) { + err = -E2BIG; + goto put_token; + } if (type != BPF_PROG_TYPE_SOCKET_FILTER && type != BPF_PROG_TYPE_CGROUP_SKB && - !bpf_capable()) - return -EPERM; + !bpf_cap) + goto put_token; - if (is_net_admin_prog_type(type) && !bpf_net_capable()) - return -EPERM; - if (is_perfmon_prog_type(type) && !perfmon_capable()) - return -EPERM; + if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN)) + goto put_token; + if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON)) + goto put_token; /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog * or btf, we need to check which one it is @@ -2667,27 +2692,33 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (IS_ERR(dst_prog)) { dst_prog = NULL; attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); - if (IS_ERR(attach_btf)) - return -EINVAL; + if (IS_ERR(attach_btf)) { + err = -EINVAL; + goto put_token; + } if (!btf_is_kernel(attach_btf)) { /* attaching through specifying bpf_prog's BTF * objects directly might be supported eventually */ btf_put(attach_btf); - return -ENOTSUPP; + err = -ENOTSUPP; + goto put_token; } } } else if (attr->attach_btf_id) { /* fall back to vmlinux BTF, if BTF type ID is specified */ attach_btf = bpf_get_btf_vmlinux(); - if (IS_ERR(attach_btf)) - return PTR_ERR(attach_btf); - if (!attach_btf) - return -EINVAL; + if (IS_ERR(attach_btf)) { + err = PTR_ERR(attach_btf); + goto put_token; + } + if (!attach_btf) { + err = -EINVAL; + goto put_token; + } btf_get(attach_btf); } - bpf_prog_load_fixup_attach_type(attr); if (bpf_prog_load_check_attach(type, attr->expected_attach_type, attach_btf, attr->attach_btf_id, dst_prog)) { @@ -2695,7 +2726,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) bpf_prog_put(dst_prog); if (attach_btf) btf_put(attach_btf); - return -EINVAL; + err = -EINVAL; + goto put_token; } /* plain bpf_prog allocation */ @@ -2705,7 +2737,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) bpf_prog_put(dst_prog); if (attach_btf) btf_put(attach_btf); - return -ENOMEM; + err = -EINVAL; + goto put_token; } prog->expected_attach_type = attr->expected_attach_type; @@ -2716,6 +2749,10 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS; + /* move token into prog->aux, reuse taken refcnt */ + prog->aux->token = token; + token = NULL; + err = security_bpf_prog_alloc(prog->aux); if (err) goto free_prog; @@ -2817,6 +2854,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (prog->aux->attach_btf) btf_put(prog->aux->attach_btf); bpf_prog_free(prog); +put_token: + bpf_token_put(token); return err; } @@ -3806,7 +3845,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, case BPF_PROG_TYPE_SK_LOOKUP: return attach_type == prog->expected_attach_type ? 0 : -EINVAL; case BPF_PROG_TYPE_CGROUP_SKB: - if (!bpf_net_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN)) /* cg-skb progs can be loaded by unpriv user. * check permissions at attach time. */ diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index 06c34dae658e..5a51e6b8f6bf 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -79,6 +79,20 @@ static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) seq_printf(m, "allowed_maps:\tany\n"); else seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps); + + BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64); + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + if ((token->allowed_progs & mask) == mask) + seq_printf(m, "allowed_progs:\tany\n"); + else + seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs); + + BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64); + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + if ((token->allowed_attachs & mask) == mask) + seq_printf(m, "allowed_attachs:\tany\n"); + else + seq_printf(m, "allowed_attachs:\t0x%llx\n", token->allowed_attachs); } #define BPF_TOKEN_INODE_NAME "bpf-token" @@ -169,6 +183,8 @@ int bpf_token_create(union bpf_attr *attr) mnt_opts = path.dentry->d_sb->s_fs_info; token->allowed_cmds = mnt_opts->delegate_cmds; token->allowed_maps = mnt_opts->delegate_maps; + token->allowed_progs = mnt_opts->delegate_progs; + token->allowed_attachs = mnt_opts->delegate_attachs; fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { @@ -228,3 +244,14 @@ bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type t return token->allowed_maps & (1ULL << type); } + +bool bpf_token_allow_prog_type(const struct bpf_token *token, + enum bpf_prog_type prog_type, + enum bpf_attach_type attach_type) +{ + if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE) + return false; + + return (token->allowed_progs & (1ULL << prog_type)) && + (token->allowed_attachs & (1ULL << attach_type)); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 9f9989e0d062..4df2d025c784 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1028,6 +1028,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ BPF_PROG_TYPE_NETFILTER, + __MAX_BPF_PROG_TYPE }; enum bpf_attach_type { @@ -1504,6 +1505,7 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 log_true_size; + __u32 prog_token_fd; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c index 573249a2814d..4ed46ed58a7b 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c @@ -30,6 +30,8 @@ void test_libbpf_probe_prog_types(void) if (prog_type == BPF_PROG_TYPE_UNSPEC) continue; + if (strcmp(prog_type_name, "__MAX_BPF_PROG_TYPE") == 0) + continue; if (!test__start_subtest(prog_type_name)) continue; diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index 2a0633f43c73..384bc1f7a65e 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -189,6 +189,9 @@ static void test_libbpf_bpf_prog_type_str(void) const char *prog_type_str; char buf[256]; + if (prog_type == __MAX_BPF_PROG_TYPE) + continue; + prog_type_name = btf__str_by_offset(btf, e->name_off); prog_type_str = libbpf_bpf_prog_type_str(prog_type); ASSERT_OK_PTR(prog_type_str, prog_type_name); From 4cbb270e115bc197ff2046aeb54cc951666b16ec Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:19 -0800 Subject: [PATCH 2808/7721] bpf: take into account BPF token when fetching helper protos Instead of performing unconditional system-wide bpf_capable() and perfmon_capable() calls inside bpf_base_func_proto() function (and other similar ones) to determine eligibility of a given BPF helper for a given program, use previously recorded BPF token during BPF_PROG_LOAD command handling to inform the decision. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- drivers/media/rc/bpf-lirc.c | 2 +- include/linux/bpf.h | 5 +++-- kernel/bpf/cgroup.c | 6 +++--- kernel/bpf/helpers.c | 6 +++--- kernel/bpf/syscall.c | 5 +++-- kernel/trace/bpf_trace.c | 2 +- net/core/filter.c | 32 ++++++++++++++++---------------- net/ipv4/bpf_tcp_ca.c | 2 +- net/netfilter/nf_bpf_link.c | 2 +- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c index fe17c7f98e81..6d07693c6b9f 100644 --- a/drivers/media/rc/bpf-lirc.c +++ b/drivers/media/rc/bpf-lirc.c @@ -110,7 +110,7 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_get_prandom_u32: return &bpf_get_prandom_u32_proto; case BPF_FUNC_trace_printk: - if (perfmon_capable()) + if (bpf_token_capable(prog->aux->token, CAP_PERFMON)) return bpf_get_trace_printk_proto(); fallthrough; default: diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 20af87b59d70..2a3ab4f3dd8c 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2492,7 +2492,8 @@ const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type struct bpf_prog *bpf_prog_by_id(u32 id); struct bpf_link *bpf_link_by_id(u32 id); -const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id); +const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id, + const struct bpf_prog *prog); void bpf_task_storage_free(struct task_struct *task); void bpf_cgrp_storage_free(struct cgroup *cgroup); bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog); @@ -2752,7 +2753,7 @@ static inline int btf_struct_access(struct bpf_verifier_log *log, } static inline const struct bpf_func_proto * -bpf_base_func_proto(enum bpf_func_id func_id) +bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { return NULL; } diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 491d20038cbe..98e0e3835b28 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1630,7 +1630,7 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -2191,7 +2191,7 @@ sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -2348,7 +2348,7 @@ cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index ee9bdf29246a..b3be5742d6f1 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1679,7 +1679,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak; const struct bpf_func_proto bpf_task_pt_regs_proto __weak; const struct bpf_func_proto * -bpf_base_func_proto(enum bpf_func_id func_id) +bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_map_lookup_elem: @@ -1730,7 +1730,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) break; } - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return NULL; switch (func_id) { @@ -1788,7 +1788,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) break; } - if (!perfmon_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_PERFMON)) return NULL; switch (func_id) { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 2c8393c21b8c..1cc03f08c9cd 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5712,7 +5712,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = { const struct bpf_func_proto * __weak tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } BPF_CALL_1(bpf_sys_close, u32, fd) @@ -5762,7 +5762,8 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_sys_bpf: - return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto; + return !bpf_token_capable(prog->aux->token, CAP_PERFMON) + ? NULL : &bpf_sys_bpf_proto; case BPF_FUNC_btf_find_by_name_kind: return &bpf_btf_find_by_name_kind_proto; case BPF_FUNC_sys_close: diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 1648bde28f01..774cf476a892 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1626,7 +1626,7 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_trace_vprintk: return bpf_get_trace_vprintk_proto(); default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/net/core/filter.c b/net/core/filter.c index 0adaa4afa35f..0bf2a03d8203 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -87,7 +87,7 @@ #include "dev.h" static const struct bpf_func_proto * -bpf_sk_base_func_proto(enum bpf_func_id func_id); +bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog); int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len) { @@ -7841,7 +7841,7 @@ sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -7934,7 +7934,7 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return NULL; } default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -7953,7 +7953,7 @@ sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_skb_event_output_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8140,7 +8140,7 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8199,7 +8199,7 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } #if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES) @@ -8260,7 +8260,7 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_sock_proto; #endif /* CONFIG_INET */ default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8302,7 +8302,7 @@ sk_msg_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_get_cgroup_classid_curr_proto; #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8346,7 +8346,7 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_skc_lookup_tcp_proto; #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8357,7 +8357,7 @@ flow_dissector_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_load_bytes: return &bpf_flow_dissector_load_bytes_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8384,7 +8384,7 @@ lwt_out_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_under_cgroup: return &bpf_skb_under_cgroup_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -11215,7 +11215,7 @@ sk_reuseport_func_proto(enum bpf_func_id func_id, case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -11397,7 +11397,7 @@ sk_lookup_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_sk_release: return &bpf_sk_release_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -11731,7 +11731,7 @@ const struct bpf_func_proto bpf_sock_from_file_proto = { }; static const struct bpf_func_proto * -bpf_sk_base_func_proto(enum bpf_func_id func_id) +bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { const struct bpf_func_proto *func; @@ -11760,10 +11760,10 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id) case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } - if (!perfmon_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_PERFMON)) return NULL; return func; diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index 39dcccf0f174..c7bbd8f3c708 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -191,7 +191,7 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id, case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/net/netfilter/nf_bpf_link.c b/net/netfilter/nf_bpf_link.c index e502ec00b2fe..1969facac91c 100644 --- a/net/netfilter/nf_bpf_link.c +++ b/net/netfilter/nf_bpf_link.c @@ -314,7 +314,7 @@ static bool nf_is_valid_access(int off, int size, enum bpf_access_type type, static const struct bpf_func_proto * bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } const struct bpf_verifier_ops netfilter_verifier_ops = { From 8062fb12de99b2da33754c6a3be1bfc30d9a35f4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:20 -0800 Subject: [PATCH 2809/7721] bpf: consistently use BPF token throughout BPF verifier logic Remove remaining direct queries to perfmon_capable() and bpf_capable() in BPF verifier logic and instead use BPF token (if available) to make decisions about privileges. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 16 ++++++++-------- include/linux/filter.h | 2 +- kernel/bpf/arraymap.c | 2 +- kernel/bpf/core.c | 2 +- kernel/bpf/verifier.c | 13 ++++++------- net/core/filter.c | 4 ++-- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2a3ab4f3dd8c..435abad3cc61 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2200,24 +2200,24 @@ extern int sysctl_unprivileged_bpf_disabled; bool bpf_token_capable(const struct bpf_token *token, int cap); -static inline bool bpf_allow_ptr_leaks(void) +static inline bool bpf_allow_ptr_leaks(const struct bpf_token *token) { - return perfmon_capable(); + return bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_allow_uninit_stack(void) +static inline bool bpf_allow_uninit_stack(const struct bpf_token *token) { - return perfmon_capable(); + return bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_bypass_spec_v1(void) +static inline bool bpf_bypass_spec_v1(const struct bpf_token *token) { - return cpu_mitigations_off() || perfmon_capable(); + return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_bypass_spec_v4(void) +static inline bool bpf_bypass_spec_v4(const struct bpf_token *token) { - return cpu_mitigations_off() || perfmon_capable(); + return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON); } int bpf_map_new_fd(struct bpf_map *map, int flags); diff --git a/include/linux/filter.h b/include/linux/filter.h index a4953fafc8cb..14354605ad26 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1139,7 +1139,7 @@ static inline bool bpf_jit_blinding_enabled(struct bpf_prog *prog) return false; if (!bpf_jit_harden) return false; - if (bpf_jit_harden == 1 && bpf_capable()) + if (bpf_jit_harden == 1 && bpf_token_capable(prog->aux->token, CAP_BPF)) return false; return true; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 4a4a67956e21..8d365bda9a8b 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -82,7 +82,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; int numa_node = bpf_map_attr_numa_node(attr); u32 elem_size, index_mask, max_entries; - bool bypass_spec_v1 = bpf_bypass_spec_v1(); + bool bypass_spec_v1 = bpf_bypass_spec_v1(NULL); u64 array_size, mask64; struct bpf_array *array; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 47085839af8d..ced511f44174 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -675,7 +675,7 @@ static bool bpf_prog_kallsyms_candidate(const struct bpf_prog *fp) void bpf_prog_kallsyms_add(struct bpf_prog *fp) { if (!bpf_prog_kallsyms_candidate(fp) || - !bpf_capable()) + !bpf_token_capable(fp->aux->token, CAP_BPF)) return; bpf_prog_ksym_set_addr(fp); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e5ce530641ba..45e85fb76d82 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20597,7 +20597,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 env->prog = *prog; env->ops = bpf_verifier_ops[env->prog->type]; env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel); - is_priv = bpf_capable(); + + env->allow_ptr_leaks = bpf_allow_ptr_leaks(env->prog->aux->token); + env->allow_uninit_stack = bpf_allow_uninit_stack(env->prog->aux->token); + env->bypass_spec_v1 = bpf_bypass_spec_v1(env->prog->aux->token); + env->bypass_spec_v4 = bpf_bypass_spec_v4(env->prog->aux->token); + env->bpf_capable = is_priv = bpf_token_capable(env->prog->aux->token, CAP_BPF); bpf_get_btf_vmlinux(); @@ -20629,12 +20634,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (attr->prog_flags & BPF_F_ANY_ALIGNMENT) env->strict_alignment = false; - env->allow_ptr_leaks = bpf_allow_ptr_leaks(); - env->allow_uninit_stack = bpf_allow_uninit_stack(); - env->bypass_spec_v1 = bpf_bypass_spec_v1(); - env->bypass_spec_v4 = bpf_bypass_spec_v4(); - env->bpf_capable = bpf_capable(); - if (is_priv) env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ; env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS; diff --git a/net/core/filter.c b/net/core/filter.c index 0bf2a03d8203..adcfc2c25754 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8559,7 +8559,7 @@ static bool cg_skb_is_valid_access(int off, int size, return false; case bpf_ctx_range(struct __sk_buff, data): case bpf_ctx_range(struct __sk_buff, data_end): - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return false; break; } @@ -8571,7 +8571,7 @@ static bool cg_skb_is_valid_access(int off, int size, case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]): break; case bpf_ctx_range(struct __sk_buff, tstamp): - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return false; break; default: From c3dd6e94df7193f33f45d33303f5e85afb2a72dc Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:21 -0800 Subject: [PATCH 2810/7721] bpf,lsm: refactor bpf_prog_alloc/bpf_prog_free LSM hooks Based on upstream discussion ([0]), rework existing bpf_prog_alloc_security LSM hook. Rename it to bpf_prog_load and instead of passing bpf_prog_aux, pass proper bpf_prog pointer for a full BPF program struct. Also, we pass bpf_attr union with all the user-provided arguments for BPF_PROG_LOAD command. This will give LSMs as much information as we can basically provide. The hook is also BPF token-aware now, and optional bpf_token struct is passed as a third argument. bpf_prog_load LSM hook is called after a bunch of sanity checks were performed, bpf_prog and bpf_prog_aux were allocated and filled out, but right before performing full-fledged BPF verification step. bpf_prog_free LSM hook is now accepting struct bpf_prog argument, for consistency. SELinux code is adjusted to all new names, types, and signatures. Note, given that bpf_prog_load (previously bpf_prog_alloc) hook can be used by some LSMs to allocate extra security blob, but also by other LSMs to reject BPF program loading, we need to make sure that bpf_prog_free LSM hook is called after bpf_prog_load/bpf_prog_alloc one *even* if the hook itself returned error. If we don't do that, we run the risk of leaking memory. This seems to be possible today when combining SELinux and BPF LSM, as one example, depending on their relative ordering. Also, for BPF LSM setup, add bpf_prog_load and bpf_prog_free to sleepable LSM hooks list, as they are both executed in sleepable context. Also drop bpf_prog_load hook from untrusted, as there is no issue with refcount or anything else anymore, that originally forced us to add it to untrusted list in c0c852dd1876 ("bpf: Do not mark certain LSM hook arguments as trusted"). We now trigger this hook much later and it should not be an issue anymore. [0] https://lore.kernel.org/bpf/9fe88aef7deabbe87d3fc38c4aea3c69.paul@paul-moore.com/ Acked-by: Paul Moore Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/lsm_hook_defs.h | 5 +++-- include/linux/security.h | 12 +++++++----- kernel/bpf/bpf_lsm.c | 5 +++-- kernel/bpf/syscall.c | 25 +++++++++++++------------ security/security.c | 25 +++++++++++++++---------- security/selinux/hooks.c | 15 ++++++++------- 6 files changed, 49 insertions(+), 38 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index ff217a5ce552..41ec4a7c070e 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -400,8 +400,9 @@ LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode) LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog) LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map) LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map) -LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux) -LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux) +LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) +LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) #endif /* CONFIG_BPF_SYSCALL */ LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) diff --git a/include/linux/security.h b/include/linux/security.h index 1d1df326c881..65467eef6678 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2020,15 +2020,16 @@ static inline void securityfs_remove(struct dentry *dentry) union bpf_attr; struct bpf_map; struct bpf_prog; -struct bpf_prog_aux; +struct bpf_token; #ifdef CONFIG_SECURITY extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size); extern int security_bpf_map(struct bpf_map *map, fmode_t fmode); extern int security_bpf_prog(struct bpf_prog *prog); extern int security_bpf_map_alloc(struct bpf_map *map); extern void security_bpf_map_free(struct bpf_map *map); -extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux); -extern void security_bpf_prog_free(struct bpf_prog_aux *aux); +extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token); +extern void security_bpf_prog_free(struct bpf_prog *prog); #else static inline int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) @@ -2054,12 +2055,13 @@ static inline int security_bpf_map_alloc(struct bpf_map *map) static inline void security_bpf_map_free(struct bpf_map *map) { } -static inline int security_bpf_prog_alloc(struct bpf_prog_aux *aux) +static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { return 0; } -static inline void security_bpf_prog_free(struct bpf_prog_aux *aux) +static inline void security_bpf_prog_free(struct bpf_prog *prog) { } #endif /* CONFIG_SECURITY */ #endif /* CONFIG_BPF_SYSCALL */ diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index e14c822f8911..3e956f6302f3 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -263,6 +263,8 @@ BTF_ID(func, bpf_lsm_bpf_map) BTF_ID(func, bpf_lsm_bpf_map_alloc_security) BTF_ID(func, bpf_lsm_bpf_map_free_security) BTF_ID(func, bpf_lsm_bpf_prog) +BTF_ID(func, bpf_lsm_bpf_prog_load) +BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_bprm_check_security) BTF_ID(func, bpf_lsm_bprm_committed_creds) BTF_ID(func, bpf_lsm_bprm_committing_creds) @@ -346,8 +348,7 @@ BTF_SET_END(sleepable_lsm_hooks) BTF_SET_START(untrusted_lsm_hooks) BTF_ID(func, bpf_lsm_bpf_map_free_security) -BTF_ID(func, bpf_lsm_bpf_prog_alloc_security) -BTF_ID(func, bpf_lsm_bpf_prog_free_security) +BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_file_alloc_security) BTF_ID(func, bpf_lsm_file_free_security) #ifdef CONFIG_SECURITY_NETWORK diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 1cc03f08c9cd..7717c7c7b95d 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2162,7 +2162,7 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu) kvfree(aux->func_info); kfree(aux->func_info_aux); free_uid(aux->user); - security_bpf_prog_free(aux); + security_bpf_prog_free(aux->prog); bpf_prog_free(aux->prog); } @@ -2753,10 +2753,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->aux->token = token; token = NULL; - err = security_bpf_prog_alloc(prog->aux); - if (err) - goto free_prog; - prog->aux->user = get_current_user(); prog->len = attr->insn_cnt; @@ -2764,12 +2760,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (copy_from_bpfptr(prog->insns, make_bpfptr(attr->insns, uattr.is_kernel), bpf_prog_insn_size(prog)) != 0) - goto free_prog_sec; + goto free_prog; /* copy eBPF program license from user space */ if (strncpy_from_bpfptr(license, make_bpfptr(attr->license, uattr.is_kernel), sizeof(license) - 1) < 0) - goto free_prog_sec; + goto free_prog; license[sizeof(license) - 1] = 0; /* eBPF programs must be GPL compatible to use GPL-ed functions */ @@ -2783,25 +2779,29 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (bpf_prog_is_dev_bound(prog->aux)) { err = bpf_prog_dev_bound_init(prog, attr); if (err) - goto free_prog_sec; + goto free_prog; } if (type == BPF_PROG_TYPE_EXT && dst_prog && bpf_prog_is_dev_bound(dst_prog->aux)) { err = bpf_prog_dev_bound_inherit(prog, dst_prog); if (err) - goto free_prog_sec; + goto free_prog; } /* find program type: socket_filter vs tracing_filter */ err = find_prog_type(type, prog); if (err < 0) - goto free_prog_sec; + goto free_prog; prog->aux->load_time = ktime_get_boottime_ns(); err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, sizeof(attr->prog_name)); if (err < 0) + goto free_prog; + + err = security_bpf_prog_load(prog, attr, token); + if (err) goto free_prog_sec; /* run eBPF verifier */ @@ -2847,10 +2847,11 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) */ __bpf_prog_put_noref(prog, prog->aux->real_func_cnt); return err; + free_prog_sec: - free_uid(prog->aux->user); - security_bpf_prog_free(prog->aux); + security_bpf_prog_free(prog); free_prog: + free_uid(prog->aux->user); if (prog->aux->attach_btf) btf_put(prog->aux->attach_btf); bpf_prog_free(prog); diff --git a/security/security.c b/security/security.c index dcb3e7014f9b..c8a1c66cfaad 100644 --- a/security/security.c +++ b/security/security.c @@ -5180,16 +5180,21 @@ int security_bpf_map_alloc(struct bpf_map *map) } /** - * security_bpf_prog_alloc() - Allocate a bpf program LSM blob - * @aux: bpf program aux info struct + * security_bpf_prog_load() - Check if loading of BPF program is allowed + * @prog: BPF program object + * @attr: BPF syscall attributes used to create BPF program + * @token: BPF token used to grant user access to BPF subsystem * - * Initialize the security field inside bpf program. + * Perform an access control check when the kernel loads a BPF program and + * allocates associated BPF program object. This hook is also responsible for + * allocating any required LSM state for the BPF program. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_prog_alloc(struct bpf_prog_aux *aux) +int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_prog_alloc_security, 0, aux); + return call_int_hook(bpf_prog_load, 0, prog, attr, token); } /** @@ -5204,14 +5209,14 @@ void security_bpf_map_free(struct bpf_map *map) } /** - * security_bpf_prog_free() - Free a bpf program's LSM blob - * @aux: bpf program aux info struct + * security_bpf_prog_free() - Free a BPF program's LSM blob + * @prog: BPF program struct * - * Clean up the security information stored inside bpf prog. + * Clean up the security information stored inside BPF program. */ -void security_bpf_prog_free(struct bpf_prog_aux *aux) +void security_bpf_prog_free(struct bpf_prog *prog) { - call_void_hook(bpf_prog_free_security, aux); + call_void_hook(bpf_prog_free, prog); } #endif /* CONFIG_BPF_SYSCALL */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index feda711c6b7b..eabee39e983c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6805,7 +6805,8 @@ static void selinux_bpf_map_free(struct bpf_map *map) kfree(bpfsec); } -static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) +static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { struct bpf_security_struct *bpfsec; @@ -6814,16 +6815,16 @@ static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) return -ENOMEM; bpfsec->sid = current_sid(); - aux->security = bpfsec; + prog->aux->security = bpfsec; return 0; } -static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) +static void selinux_bpf_prog_free(struct bpf_prog *prog) { - struct bpf_security_struct *bpfsec = aux->security; + struct bpf_security_struct *bpfsec = prog->aux->security; - aux->security = NULL; + prog->aux->security = NULL; kfree(bpfsec); } #endif @@ -7180,7 +7181,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), - LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), #endif #ifdef CONFIG_PERF_EVENTS @@ -7238,7 +7239,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { #endif #ifdef CONFIG_BPF_SYSCALL LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), - LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), + LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), #endif #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), From 66d636d70a79c1d37e3eea67ab50969e6aaef983 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:22 -0800 Subject: [PATCH 2811/7721] bpf,lsm: refactor bpf_map_alloc/bpf_map_free LSM hooks Similarly to bpf_prog_alloc LSM hook, rename and extend bpf_map_alloc hook into bpf_map_create, taking not just struct bpf_map, but also bpf_attr and bpf_token, to give a fuller context to LSMs. Unlike bpf_prog_alloc, there is no need to move the hook around, as it currently is firing right before allocating BPF map ID and FD, which seems to be a sweet spot. But like bpf_prog_alloc/bpf_prog_free combo, make sure that bpf_map_free LSM hook is called even if bpf_map_create hook returned error, as if few LSMs are combined together it could be that one LSM successfully allocated security blob for its needs, while subsequent LSM rejected BPF map creation. The former LSM would still need to free up LSM blob, so we need to ensure security_bpf_map_free() is called regardless of the outcome. Acked-by: Paul Moore Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-11-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/lsm_hook_defs.h | 5 +++-- include/linux/security.h | 6 ++++-- kernel/bpf/bpf_lsm.c | 6 +++--- kernel/bpf/syscall.c | 4 ++-- security/security.c | 16 ++++++++++------ security/selinux/hooks.c | 7 ++++--- 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 41ec4a7c070e..adb25cc63ce3 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -398,8 +398,9 @@ LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule) LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size) LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode) LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog) -LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map) -LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map) +LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) +LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map) LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token) LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) diff --git a/include/linux/security.h b/include/linux/security.h index 65467eef6678..08fd777cbe94 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2025,7 +2025,8 @@ struct bpf_token; extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size); extern int security_bpf_map(struct bpf_map *map, fmode_t fmode); extern int security_bpf_prog(struct bpf_prog *prog); -extern int security_bpf_map_alloc(struct bpf_map *map); +extern int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token); extern void security_bpf_map_free(struct bpf_map *map); extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token); @@ -2047,7 +2048,8 @@ static inline int security_bpf_prog(struct bpf_prog *prog) return 0; } -static inline int security_bpf_map_alloc(struct bpf_map *map) +static inline int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { return 0; } diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 3e956f6302f3..9e4e615f11eb 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -260,8 +260,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) BTF_SET_START(sleepable_lsm_hooks) BTF_ID(func, bpf_lsm_bpf) BTF_ID(func, bpf_lsm_bpf_map) -BTF_ID(func, bpf_lsm_bpf_map_alloc_security) -BTF_ID(func, bpf_lsm_bpf_map_free_security) +BTF_ID(func, bpf_lsm_bpf_map_create) +BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog) BTF_ID(func, bpf_lsm_bpf_prog_load) BTF_ID(func, bpf_lsm_bpf_prog_free) @@ -347,7 +347,7 @@ BTF_ID(func, bpf_lsm_userns_create) BTF_SET_END(sleepable_lsm_hooks) BTF_SET_START(untrusted_lsm_hooks) -BTF_ID(func, bpf_lsm_bpf_map_free_security) +BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_file_alloc_security) BTF_ID(func, bpf_lsm_file_free_security) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 7717c7c7b95d..aff045eed375 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1309,9 +1309,9 @@ static int map_create(union bpf_attr *attr) attr->btf_vmlinux_value_type_id; } - err = security_bpf_map_alloc(map); + err = security_bpf_map_create(map, attr, token); if (err) - goto free_map; + goto free_map_sec; err = bpf_map_alloc_id(map); if (err) diff --git a/security/security.c b/security/security.c index c8a1c66cfaad..ad24cf36da94 100644 --- a/security/security.c +++ b/security/security.c @@ -5167,16 +5167,20 @@ int security_bpf_prog(struct bpf_prog *prog) } /** - * security_bpf_map_alloc() - Allocate a bpf map LSM blob - * @map: bpf map + * security_bpf_map_create() - Check if BPF map creation is allowed + * @map: BPF map object + * @attr: BPF syscall attributes used to create BPF map + * @token: BPF token used to grant user access * - * Initialize the security field inside bpf map. + * Do a check when the kernel creates a new BPF map. This is also the + * point where LSM blob is allocated for LSMs that need them. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_map_alloc(struct bpf_map *map) +int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_map_alloc_security, 0, map); + return call_int_hook(bpf_map_create, 0, map, attr, token); } /** @@ -5205,7 +5209,7 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, */ void security_bpf_map_free(struct bpf_map *map) { - call_void_hook(bpf_map_free_security, map); + call_void_hook(bpf_map_free, map); } /** diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index eabee39e983c..002351ab67b7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6783,7 +6783,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog) BPF__PROG_RUN, NULL); } -static int selinux_bpf_map_alloc(struct bpf_map *map) +static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { struct bpf_security_struct *bpfsec; @@ -7180,7 +7181,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf, selinux_bpf), LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), - LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), + LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), #endif @@ -7238,7 +7239,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init), #endif #ifdef CONFIG_BPF_SYSCALL - LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), + LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), #endif #ifdef CONFIG_PERF_EVENTS From d734ca7b33dbf60eb15dcf7c44f3da7073356777 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:23 -0800 Subject: [PATCH 2812/7721] bpf,lsm: add BPF token LSM hooks Wire up bpf_token_create and bpf_token_free LSM hooks, which allow to allocate LSM security blob (we add `void *security` field to struct bpf_token for that), but also control who can instantiate BPF token. This follows existing pattern for BPF map and BPF prog. Also add security_bpf_token_allow_cmd() and security_bpf_token_capable() LSM hooks that allow LSM implementation to control and negate (if necessary) BPF token's delegation of a specific bpf_cmd and capability, respectively. Acked-by: Paul Moore Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-12-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 3 ++ include/linux/lsm_hook_defs.h | 5 +++ include/linux/security.h | 25 +++++++++++++++ kernel/bpf/bpf_lsm.c | 4 +++ kernel/bpf/token.c | 18 +++++++---- security/security.c | 60 +++++++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 6 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 435abad3cc61..7a483f6b6d5f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1604,6 +1604,9 @@ struct bpf_token { u64 allowed_maps; u64 allowed_progs; u64 allowed_attachs; +#ifdef CONFIG_SECURITY + void *security; +#endif }; struct bpf_struct_ops_value; diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index adb25cc63ce3..3fdd00b452ac 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -404,6 +404,11 @@ LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map) LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token) LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) +LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr, + struct path *path) +LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token) +LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd) +LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap) #endif /* CONFIG_BPF_SYSCALL */ LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) diff --git a/include/linux/security.h b/include/linux/security.h index 08fd777cbe94..00809d2d5c38 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -32,6 +32,7 @@ #include #include #include +#include struct linux_binprm; struct cred; @@ -2031,6 +2032,11 @@ extern void security_bpf_map_free(struct bpf_map *map); extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token); extern void security_bpf_prog_free(struct bpf_prog *prog); +extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path); +extern void security_bpf_token_free(struct bpf_token *token); +extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd); +extern int security_bpf_token_capable(const struct bpf_token *token, int cap); #else static inline int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) @@ -2065,6 +2071,25 @@ static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr * static inline void security_bpf_prog_free(struct bpf_prog *prog) { } + +static inline int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + return 0; +} + +static inline void security_bpf_token_free(struct bpf_token *token) +{ } + +static inline int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + return 0; +} + +static inline int security_bpf_token_capable(const struct bpf_token *token, int cap) +{ + return 0; +} #endif /* CONFIG_SECURITY */ #endif /* CONFIG_BPF_SYSCALL */ diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 9e4e615f11eb..7d2f96413a57 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -265,6 +265,10 @@ BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog) BTF_ID(func, bpf_lsm_bpf_prog_load) BTF_ID(func, bpf_lsm_bpf_prog_free) +BTF_ID(func, bpf_lsm_bpf_token_create) +BTF_ID(func, bpf_lsm_bpf_token_free) +BTF_ID(func, bpf_lsm_bpf_token_cmd) +BTF_ID(func, bpf_lsm_bpf_token_capable) BTF_ID(func, bpf_lsm_bprm_check_security) BTF_ID(func, bpf_lsm_bprm_committed_creds) BTF_ID(func, bpf_lsm_bprm_committing_creds) diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index 5a51e6b8f6bf..17212efcde60 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -7,6 +7,7 @@ #include #include #include +#include bool bpf_token_capable(const struct bpf_token *token, int cap) { @@ -14,10 +15,9 @@ bool bpf_token_capable(const struct bpf_token *token, int cap) * token's userns is *exactly* the same as current user's userns */ if (token && current_user_ns() == token->userns) { - if (ns_capable(token->userns, cap)) - return true; - if (cap != CAP_SYS_ADMIN && ns_capable(token->userns, CAP_SYS_ADMIN)) - return true; + if (ns_capable(token->userns, cap) || + (cap != CAP_SYS_ADMIN && ns_capable(token->userns, CAP_SYS_ADMIN))) + return security_bpf_token_capable(token, cap) == 0; } /* otherwise fallback to capable() checks */ return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN)); @@ -30,6 +30,7 @@ void bpf_token_inc(struct bpf_token *token) static void bpf_token_free(struct bpf_token *token) { + security_bpf_token_free(token); put_user_ns(token->userns); kvfree(token); } @@ -186,6 +187,10 @@ int bpf_token_create(union bpf_attr *attr) token->allowed_progs = mnt_opts->delegate_progs; token->allowed_attachs = mnt_opts->delegate_attachs; + err = security_bpf_token_create(token, attr, &path); + if (err) + goto out_token; + fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { err = fd; @@ -233,8 +238,9 @@ bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) */ if (!token || current_user_ns() != token->userns) return false; - - return token->allowed_cmds & (1ULL << cmd); + if (!(token->allowed_cmds & (1ULL << cmd))) + return false; + return security_bpf_token_cmd(token, cmd) == 0; } bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type) diff --git a/security/security.c b/security/security.c index ad24cf36da94..088a79c35c26 100644 --- a/security/security.c +++ b/security/security.c @@ -5201,6 +5201,55 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, return call_int_hook(bpf_prog_load, 0, prog, attr, token); } +/** + * security_bpf_token_create() - Check if creating of BPF token is allowed + * @token: BPF token object + * @attr: BPF syscall attributes used to create BPF token + * @path: path pointing to BPF FS mount point from which BPF token is created + * + * Do a check when the kernel instantiates a new BPF token object from BPF FS + * instance. This is also the point where LSM blob can be allocated for LSMs. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + return call_int_hook(bpf_token_create, 0, token, attr, path); +} + +/** + * security_bpf_token_cmd() - Check if BPF token is allowed to delegate + * requested BPF syscall command + * @token: BPF token object + * @cmd: BPF syscall command requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF syscall command. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + return call_int_hook(bpf_token_cmd, 0, token, cmd); +} + +/** + * security_bpf_token_capable() - Check if BPF token is allowed to delegate + * requested BPF-related capability + * @token: BPF token object + * @cap: capabilities requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF-related capabilities. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_capable(const struct bpf_token *token, int cap) +{ + return call_int_hook(bpf_token_capable, 0, token, cap); +} + /** * security_bpf_map_free() - Free a bpf map's LSM blob * @map: bpf map @@ -5222,6 +5271,17 @@ void security_bpf_prog_free(struct bpf_prog *prog) { call_void_hook(bpf_prog_free, prog); } + +/** + * security_bpf_token_free() - Free a BPF token's LSM blob + * @token: BPF token struct + * + * Clean up the security information stored inside BPF token. + */ +void security_bpf_token_free(struct bpf_token *token) +{ + call_void_hook(bpf_token_free, token); +} #endif /* CONFIG_BPF_SYSCALL */ /** From ecd435143eb03611e25694141bf59d1c04ad5b9e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:24 -0800 Subject: [PATCH 2813/7721] libbpf: add bpf_token_create() API Add low-level wrapper API for BPF_TOKEN_CREATE command in bpf() syscall. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-13-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf.c | 17 +++++++++++++++++ tools/lib/bpf/bpf.h | 24 ++++++++++++++++++++++++ tools/lib/bpf/libbpf.map | 1 + 3 files changed, 42 insertions(+) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9dc9625651dc..d4019928a864 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1287,3 +1287,20 @@ int bpf_prog_bind_map(int prog_fd, int map_fd, ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, attr_sz); return libbpf_err_errno(ret); } + +int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts) +{ + const size_t attr_sz = offsetofend(union bpf_attr, token_create); + union bpf_attr attr; + int fd; + + if (!OPTS_VALID(opts, bpf_token_create_opts)) + return libbpf_err(-EINVAL); + + memset(&attr, 0, attr_sz); + attr.token_create.bpffs_fd = bpffs_fd; + attr.token_create.flags = OPTS_GET(opts, flags, 0); + + fd = sys_bpf_fd(BPF_TOKEN_CREATE, &attr, attr_sz); + return libbpf_err_errno(fd); +} diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index d0f53772bdc0..e49254c9f68f 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -640,6 +640,30 @@ struct bpf_test_run_opts { LIBBPF_API int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts); +struct bpf_token_create_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + __u32 flags; + size_t :0; +}; +#define bpf_token_create_opts__last_field flags + +/** + * @brief **bpf_token_create()** creates a new instance of BPF token derived + * from specified BPF FS mount point. + * + * BPF token created with this API can be passed to bpf() syscall for + * commands like BPF_PROG_LOAD, BPF_MAP_CREATE, etc. + * + * @param bpffs_fd FD for BPF FS instance from which to derive a BPF token + * instance. + * @param opts optional BPF token creation options, can be NULL + * + * @return BPF token FD > 0, on success; negative error code, otherwise (errno + * is also set to the error code) + */ +LIBBPF_API int bpf_token_create(int bpffs_fd, + struct bpf_token_create_opts *opts); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 91c5aef7dae7..df7657b65c47 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -401,6 +401,7 @@ LIBBPF_1.3.0 { bpf_program__attach_netkit; bpf_program__attach_tcx; bpf_program__attach_uprobe_multi; + bpf_token_create; ring__avail_data_size; ring__consume; ring__consumer_pos; From 37891cea6699200fb83eae464ebe1c0f73040474 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:25 -0800 Subject: [PATCH 2814/7721] libbpf: add BPF token support to bpf_map_create() API Add ability to provide token_fd for BPF_MAP_CREATE command through bpf_map_create() API. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-14-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf.c | 4 +++- tools/lib/bpf/bpf.h | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index d4019928a864..1653b64b7015 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -169,7 +169,7 @@ int bpf_map_create(enum bpf_map_type map_type, __u32 max_entries, const struct bpf_map_create_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, map_extra); + const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd); union bpf_attr attr; int fd; @@ -198,6 +198,8 @@ int bpf_map_create(enum bpf_map_type map_type, attr.numa_node = OPTS_GET(opts, numa_node, 0); attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0); + attr.map_token_fd = OPTS_GET(opts, token_fd, 0); + fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz); return libbpf_err_errno(fd); } diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index e49254c9f68f..ae2136f596b4 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -51,8 +51,11 @@ struct bpf_map_create_opts { __u32 numa_node; __u32 map_ifindex; + + __u32 token_fd; + size_t :0; }; -#define bpf_map_create_opts__last_field map_ifindex +#define bpf_map_create_opts__last_field token_fd LIBBPF_API int bpf_map_create(enum bpf_map_type map_type, const char *map_name, From 1a8df7fa00aac35aff9ef1941c5334b3a01d09e4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:26 -0800 Subject: [PATCH 2815/7721] libbpf: add BPF token support to bpf_btf_load() API Allow user to specify token_fd for bpf_btf_load() API that wraps kernel's BPF_BTF_LOAD command. This allows loading BTF from unprivileged process as long as it has BPF token allowing BPF_BTF_LOAD command, which can be created and delegated by privileged process. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-15-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf.c | 4 +++- tools/lib/bpf/bpf.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1653b64b7015..544ae2376b6b 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1184,7 +1184,7 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd) int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, btf_log_true_size); + const size_t attr_sz = offsetofend(union bpf_attr, btf_token_fd); union bpf_attr attr; char *log_buf; size_t log_size; @@ -1209,6 +1209,8 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts attr.btf = ptr_to_u64(btf_data); attr.btf_size = btf_size; + attr.btf_token_fd = OPTS_GET(opts, token_fd, 0); + /* log_level == 0 and log_buf != NULL means "try loading without * log_buf, but retry with log_buf and log_level=1 on error", which is * consistent across low-level and high-level BTF and program loading diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index ae2136f596b4..4b0f25e97b0d 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -133,9 +133,10 @@ struct bpf_btf_load_opts { * If kernel doesn't support this feature, log_size is left unchanged. */ __u32 log_true_size; + __u32 token_fd; size_t :0; }; -#define bpf_btf_load_opts__last_field log_true_size +#define bpf_btf_load_opts__last_field token_fd LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts); From 1571740a9ba036f26cc5211a86021199987219e8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:27 -0800 Subject: [PATCH 2816/7721] libbpf: add BPF token support to bpf_prog_load() API Wire through token_fd into bpf_prog_load(). Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-16-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf.c | 3 ++- tools/lib/bpf/bpf.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 544ae2376b6b..f4e1da3c6d5f 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -234,7 +234,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, size_t insn_cnt, struct bpf_prog_load_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, log_true_size); + const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd); void *finfo = NULL, *linfo = NULL; const char *func_info, *line_info; __u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd; @@ -263,6 +263,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, attr.prog_flags = OPTS_GET(opts, prog_flags, 0); attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0); attr.kern_version = OPTS_GET(opts, kern_version, 0); + attr.prog_token_fd = OPTS_GET(opts, token_fd, 0); if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME)) libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name)); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 4b0f25e97b0d..991b86bfe7e4 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -105,9 +105,10 @@ struct bpf_prog_load_opts { * If kernel doesn't support this feature, log_size is left unchanged. */ __u32 log_true_size; + __u32 token_fd; size_t :0; }; -#define bpf_prog_load_opts__last_field log_true_size +#define bpf_prog_load_opts__last_field token_fd LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type, const char *prog_name, const char *license, From dc5196fac40c2cb96330bcb98eef868a7fd225b3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:28 -0800 Subject: [PATCH 2817/7721] selftests/bpf: add BPF token-enabled tests Add a selftest that attempts to conceptually replicate intended BPF token use cases inside user namespaced container. Child process is forked. It is then put into its own userns and mountns. Child creates BPF FS context object. This ensures child userns is captured as the owning userns for this instance of BPF FS. Given setting delegation mount options is privileged operation, we ensure that child cannot set them. This context is passed back to privileged parent process through Unix socket, where parent sets up delegation options, creates, and mounts it as a detached mount. This mount FD is passed back to the child to be used for BPF token creation, which allows otherwise privileged BPF operations to succeed inside userns. We validate that all of token-enabled privileged commands (BPF_BTF_LOAD, BPF_MAP_CREATE, and BPF_PROG_LOAD) work as intended. They should only succeed inside the userns if a) BPF token is provided with proper allowed sets of commands and types; and b) namespaces CAP_BPF and other privileges are set. Lacking a) or b) should lead to -EPERM failures. Based on suggested workflow by Christian Brauner ([0]). [0] https://lore.kernel.org/bpf/20230704-hochverdient-lehne-eeb9eeef785e@brauner/ Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-17-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../testing/selftests/bpf/prog_tests/token.c | 672 ++++++++++++++++++ 1 file changed, 672 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/token.c diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c new file mode 100644 index 000000000000..dc03790c6272 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#define _GNU_SOURCE +#include +#include +#include "cap_helpers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline int sys_mount(const char *dev_name, const char *dir_name, + const char *type, unsigned long flags, + const void *data) +{ + return syscall(__NR_mount, dev_name, dir_name, type, flags, data); +} + +static inline int sys_fsopen(const char *fsname, unsigned flags) +{ + return syscall(__NR_fsopen, fsname, flags); +} + +static inline int sys_fspick(int dfd, const char *path, unsigned flags) +{ + return syscall(__NR_fspick, dfd, path, flags); +} + +static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux) +{ + return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux); +} + +static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) +{ + return syscall(__NR_fsmount, fs_fd, flags, ms_flags); +} + +static int drop_priv_caps(__u64 *old_caps) +{ + return cap_disable_effective((1ULL << CAP_BPF) | + (1ULL << CAP_PERFMON) | + (1ULL << CAP_NET_ADMIN) | + (1ULL << CAP_SYS_ADMIN), old_caps); +} + +static int restore_priv_caps(__u64 old_caps) +{ + return cap_enable_effective(old_caps, NULL); +} + +static int set_delegate_mask(int fs_fd, const char *key, __u64 mask) +{ + char buf[32]; + int err; + + snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); + err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key, + mask == ~0ULL ? "any" : buf, 0); + if (err < 0) + err = -errno; + return err; +} + +#define zclose(fd) do { if (fd >= 0) close(fd); fd = -1; } while (0) + +struct bpffs_opts { + __u64 cmds; + __u64 maps; + __u64 progs; + __u64 attachs; +}; + +static int create_bpffs_fd(void) +{ + int fs_fd; + + /* create VFS context */ + fs_fd = sys_fsopen("bpf", 0); + ASSERT_GE(fs_fd, 0, "fs_fd"); + + return fs_fd; +} + +static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts) +{ + int mnt_fd, err; + + /* set up token delegation mount options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds); + if (!ASSERT_OK(err, "fs_cfg_cmds")) + return err; + err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps); + if (!ASSERT_OK(err, "fs_cfg_maps")) + return err; + err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs); + if (!ASSERT_OK(err, "fs_cfg_progs")) + return err; + err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs); + if (!ASSERT_OK(err, "fs_cfg_attachs")) + return err; + + /* instantiate FS object */ + err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + if (err < 0) + return -errno; + + /* create O_PATH fd for detached mount */ + mnt_fd = sys_fsmount(fs_fd, 0, 0); + if (err < 0) + return -errno; + + return mnt_fd; +} + +/* send FD over Unix domain (AF_UNIX) socket */ +static int sendfd(int sockfd, int fd) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + int fds[1] = { fd }, err; + char iobuf[1]; + struct iovec io = { + .iov_base = iobuf, + .iov_len = sizeof(iobuf), + }; + union { + char buf[CMSG_SPACE(sizeof(fds))]; + struct cmsghdr align; + } u; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); + + err = sendmsg(sockfd, &msg, 0); + if (err < 0) + err = -errno; + if (!ASSERT_EQ(err, 1, "sendmsg")) + return -EINVAL; + + return 0; +} + +/* receive FD over Unix domain (AF_UNIX) socket */ +static int recvfd(int sockfd, int *fd) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + int fds[1], err; + char iobuf[1]; + struct iovec io = { + .iov_base = iobuf, + .iov_len = sizeof(iobuf), + }; + union { + char buf[CMSG_SPACE(sizeof(fds))]; + struct cmsghdr align; + } u; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + + err = recvmsg(sockfd, &msg, 0); + if (err < 0) + err = -errno; + if (!ASSERT_EQ(err, 1, "recvmsg")) + return -EINVAL; + + cmsg = CMSG_FIRSTHDR(&msg); + if (!ASSERT_OK_PTR(cmsg, "cmsg_null") || + !ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(fds)), "cmsg_len") || + !ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET, "cmsg_level") || + !ASSERT_EQ(cmsg->cmsg_type, SCM_RIGHTS, "cmsg_type")) + return -EINVAL; + + memcpy(fds, CMSG_DATA(cmsg), sizeof(fds)); + *fd = fds[0]; + + return 0; +} + +static ssize_t write_nointr(int fd, const void *buf, size_t count) +{ + ssize_t ret; + + do { + ret = write(fd, buf, count); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +static int write_file(const char *path, const void *buf, size_t count) +{ + int fd; + ssize_t ret; + + fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); + if (fd < 0) + return -1; + + ret = write_nointr(fd, buf, count); + close(fd); + if (ret < 0 || (size_t)ret != count) + return -1; + + return 0; +} + +static int create_and_enter_userns(void) +{ + uid_t uid; + gid_t gid; + char map[100]; + + uid = getuid(); + gid = getgid(); + + if (unshare(CLONE_NEWUSER)) + return -1; + + if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) && + errno != ENOENT) + return -1; + + snprintf(map, sizeof(map), "0 %d 1", uid); + if (write_file("/proc/self/uid_map", map, strlen(map))) + return -1; + + + snprintf(map, sizeof(map), "0 %d 1", gid); + if (write_file("/proc/self/gid_map", map, strlen(map))) + return -1; + + if (setgid(0)) + return -1; + + if (setuid(0)) + return -1; + + return 0; +} + +typedef int (*child_callback_fn)(int); + +static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callback) +{ + LIBBPF_OPTS(bpf_map_create_opts, map_opts); + int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1; + + /* setup userns with root mappings */ + err = create_and_enter_userns(); + if (!ASSERT_OK(err, "create_and_enter_userns")) + goto cleanup; + + /* setup mountns to allow creating BPF FS (fsopen("bpf")) from unpriv process */ + err = unshare(CLONE_NEWNS); + if (!ASSERT_OK(err, "create_mountns")) + goto cleanup; + + err = sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); + if (!ASSERT_OK(err, "remount_root")) + goto cleanup; + + fs_fd = create_bpffs_fd(); + if (!ASSERT_GE(fs_fd, 0, "create_bpffs_fd")) { + err = -EINVAL; + goto cleanup; + } + + /* ensure unprivileged child cannot set delegation options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm"); + err = set_delegate_mask(fs_fd, "delegate_maps", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_maps_eperm"); + err = set_delegate_mask(fs_fd, "delegate_progs", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_progs_eperm"); + err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm"); + + /* pass BPF FS context object to parent */ + err = sendfd(sock_fd, fs_fd); + if (!ASSERT_OK(err, "send_fs_fd")) + goto cleanup; + zclose(fs_fd); + + /* avoid mucking around with mount namespaces and mounting at + * well-known path, just get detach-mounted BPF FS fd back from parent + */ + err = recvfd(sock_fd, &mnt_fd); + if (!ASSERT_OK(err, "recv_mnt_fd")) + goto cleanup; + + /* try to fspick() BPF FS and try to add some delegation options */ + fs_fd = sys_fspick(mnt_fd, "", FSPICK_EMPTY_PATH); + if (!ASSERT_GE(fs_fd, 0, "bpffs_fspick")) { + err = -EINVAL; + goto cleanup; + } + + /* ensure unprivileged child cannot reconfigure to set delegation options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_maps", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_maps_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_progs", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_progs_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_attachs", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + zclose(fs_fd); + + bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR); + if (!ASSERT_GE(bpffs_fd, 0, "bpffs_open")) { + err = -EINVAL; + goto cleanup; + } + + /* do custom test logic with customly set up BPF FS instance */ + err = callback(bpffs_fd); + if (!ASSERT_OK(err, "test_callback")) + goto cleanup; + + err = 0; +cleanup: + zclose(sock_fd); + zclose(mnt_fd); + zclose(fs_fd); + zclose(bpffs_fd); + + exit(-err); +} + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (!WIFEXITED(status)) + return -1; + + return WEXITSTATUS(status); +} + +static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd) +{ + int fs_fd = -1, mnt_fd = -1, err; + + err = recvfd(sock_fd, &fs_fd); + if (!ASSERT_OK(err, "recv_bpffs_fd")) + goto cleanup; + + mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts); + if (!ASSERT_GE(mnt_fd, 0, "materialize_bpffs_fd")) { + err = -EINVAL; + goto cleanup; + } + zclose(fs_fd); + + /* pass BPF FS context object to parent */ + err = sendfd(sock_fd, mnt_fd); + if (!ASSERT_OK(err, "send_mnt_fd")) + goto cleanup; + zclose(mnt_fd); + + err = wait_for_pid(child_pid); + ASSERT_OK(err, "waitpid_child"); + +cleanup: + zclose(sock_fd); + zclose(fs_fd); + zclose(mnt_fd); + + if (child_pid > 0) + (void)kill(child_pid, SIGKILL); +} + +static void subtest_userns(struct bpffs_opts *bpffs_opts, child_callback_fn cb) +{ + int sock_fds[2] = { -1, -1 }; + int child_pid = 0, err; + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds); + if (!ASSERT_OK(err, "socketpair")) + goto cleanup; + + child_pid = fork(); + if (!ASSERT_GE(child_pid, 0, "fork")) + goto cleanup; + + if (child_pid == 0) { + zclose(sock_fds[0]); + return child(sock_fds[1], bpffs_opts, cb); + + } else { + zclose(sock_fds[1]); + return parent(child_pid, bpffs_opts, sock_fds[0]); + } + +cleanup: + zclose(sock_fds[0]); + zclose(sock_fds[1]); + if (child_pid > 0) + (void)kill(child_pid, SIGKILL); +} + +static int userns_map_create(int mnt_fd) +{ + LIBBPF_OPTS(bpf_map_create_opts, map_opts); + int err, token_fd = -1, map_fd = -1; + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* while inside non-init userns, we need both a BPF token *and* + * CAP_BPF inside current userns to create privileged map; let's test + * that neither BPF token alone nor namespaced CAP_BPF is sufficient + */ + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* no token, no CAP_BPF -> fail */ + map_opts.token_fd = 0; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_wo_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_wo_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* token without CAP_BPF -> fail */ + map_opts.token_fd = token_fd; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_wo_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_w_token_wo_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */ + err = restore_priv_caps(old_caps); + if (!ASSERT_OK(err, "restore_caps")) + goto cleanup; + + /* CAP_BPF without token -> fail */ + map_opts.token_fd = 0; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_w_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_w_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* finally, namespaced CAP_BPF + token -> success */ + map_opts.token_fd = token_fd; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_w_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_GT(map_fd, 0, "stack_map_w_token_w_cap_bpf")) { + err = -EINVAL; + goto cleanup; + } + +cleanup: + zclose(token_fd); + zclose(map_fd); + return err; +} + +static int userns_btf_load(int mnt_fd) +{ + LIBBPF_OPTS(bpf_btf_load_opts, btf_opts); + int err, token_fd = -1, btf_fd = -1; + const void *raw_btf_data; + struct btf *btf = NULL; + __u32 raw_btf_size; + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* while inside non-init userns, we need both a BPF token *and* + * CAP_BPF inside current userns to create privileged map; let's test + * that neither BPF token alone nor namespaced CAP_BPF is sufficient + */ + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* setup a trivial BTF data to load to the kernel */ + btf = btf__new_empty(); + if (!ASSERT_OK_PTR(btf, "empty_btf")) + goto cleanup; + + ASSERT_GT(btf__add_int(btf, "int", 4, 0), 0, "int_type"); + + raw_btf_data = btf__raw_data(btf, &raw_btf_size); + if (!ASSERT_OK_PTR(raw_btf_data, "raw_btf_data")) + goto cleanup; + + /* no token + no CAP_BPF -> failure */ + btf_opts.token_fd = 0; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_LT(btf_fd, 0, "no_token_no_cap_should_fail")) + goto cleanup; + + /* token + no CAP_BPF -> failure */ + btf_opts.token_fd = token_fd; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_LT(btf_fd, 0, "token_no_cap_should_fail")) + goto cleanup; + + /* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */ + err = restore_priv_caps(old_caps); + if (!ASSERT_OK(err, "restore_caps")) + goto cleanup; + + /* token + CAP_BPF -> success */ + btf_opts.token_fd = token_fd; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_GT(btf_fd, 0, "token_and_cap_success")) + goto cleanup; + + err = 0; +cleanup: + btf__free(btf); + zclose(btf_fd); + zclose(token_fd); + return err; +} + +static int userns_prog_load(int mnt_fd) +{ + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts); + int err, token_fd = -1, prog_fd = -1; + struct bpf_insn insns[] = { + /* bpf_jiffies64() requires CAP_BPF */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64), + /* bpf_get_current_task() requires CAP_PERFMON */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_current_task), + /* r0 = 0; exit; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + size_t insn_cnt = ARRAY_SIZE(insns); + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* validate we can successfully load BPF program with token; this + * being XDP program (CAP_NET_ADMIN) using bpf_jiffies64() (CAP_BPF) + * and bpf_get_current_task() (CAP_PERFMON) helpers validates we have + * BPF token wired properly in a bunch of places in the kernel + */ + prog_opts.token_fd = token_fd; + prog_opts.expected_attach_type = BPF_XDP; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_GT(prog_fd, 0, "prog_fd")) { + err = -EPERM; + goto cleanup; + } + + /* no token + caps -> failure */ + prog_opts.token_fd = 0; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* no caps + token -> failure */ + prog_opts.token_fd = token_fd; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + /* no caps + no token -> definitely a failure */ + prog_opts.token_fd = 0; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + err = 0; +cleanup: + zclose(prog_fd); + zclose(token_fd); + return err; +} + +void test_token(void) +{ + if (test__start_subtest("map_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_MAP_CREATE, + .maps = 1ULL << BPF_MAP_TYPE_STACK, + }; + + subtest_userns(&opts, userns_map_create); + } + if (test__start_subtest("btf_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_BTF_LOAD, + }; + + subtest_userns(&opts, userns_btf_load); + } + if (test__start_subtest("prog_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_PROG_LOAD, + .progs = 1ULL << BPF_PROG_TYPE_XDP, + .attachs = 1ULL << BPF_XDP, + }; + + subtest_userns(&opts, userns_prog_load); + } +} From 36fb94944b35062db15ab3059f4123048cac658c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 30 Nov 2023 10:52:29 -0800 Subject: [PATCH 2818/7721] bpf,selinux: allocate bpf_security_struct per BPF token Utilize newly added bpf_token_create/bpf_token_free LSM hooks to allocate struct bpf_security_struct for each BPF token object in SELinux. This just follows similar pattern for BPF prog and map. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231130185229.2688956-18-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- security/selinux/hooks.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 002351ab67b7..1501e95366a1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6828,6 +6828,29 @@ static void selinux_bpf_prog_free(struct bpf_prog *prog) prog->aux->security = NULL; kfree(bpfsec); } + +static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + struct bpf_security_struct *bpfsec; + + bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); + if (!bpfsec) + return -ENOMEM; + + bpfsec->sid = current_sid(); + token->security = bpfsec; + + return 0; +} + +static void selinux_bpf_token_free(struct bpf_token *token) +{ + struct bpf_security_struct *bpfsec = token->security; + + token->security = NULL; + kfree(bpfsec); +} #endif struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { @@ -7183,6 +7206,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), #endif #ifdef CONFIG_PERF_EVENTS @@ -7241,6 +7265,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { #ifdef CONFIG_BPF_SYSCALL LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), + LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create), #endif #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), From c3ab23a10771bbe06300e5374efa809789c65455 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:12 +0530 Subject: [PATCH 2819/7721] ASoC: amd: Add new dmi entries for acp5x platform Add sys_vendor and product_name dmi entries for acp5x platform. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 20cee7104c2b..19a30f145143 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey // @@ -47,6 +47,19 @@ static const struct config_entry config_table[] = { {} }, }, + { + .flags = FLAG_AMD_LEGACY, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Jupiter"), + }, + }, + {} + }, + }, { .flags = FLAG_AMD_SOF, .device = ACP_PCI_DEV_ID, From f18818eb0dbe0339c0efd02a34a3f5651749cb84 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:13 +0530 Subject: [PATCH 2820/7721] ASoC: amd: vangogh: Add condition check for acp config flag Add condition check for acp config flag to load legacy driver only. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/vangogh/pci-acp5x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/vangogh/pci-acp5x.c b/sound/soc/amd/vangogh/pci-acp5x.c index c4634a8a17cd..3826443d77b9 100644 --- a/sound/soc/amd/vangogh/pci-acp5x.c +++ b/sound/soc/amd/vangogh/pci-acp5x.c @@ -2,7 +2,7 @@ // // AMD Vangogh ACP PCI Driver // -// Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (C) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. #include #include @@ -13,6 +13,7 @@ #include #include "acp5x.h" +#include "../mach-config.h" struct acp5x_dev_data { void __iomem *acp5x_base; @@ -131,7 +132,7 @@ static int snd_acp5x_probe(struct pci_dev *pci, /* Return if acp config flag is defined */ flag = snd_amd_acp_find_config(pci); - if (flag) + if (flag != FLAG_AMD_LEGACY) return -ENODEV; irqflags = IRQF_SHARED; From e12678141835c539fc17a2318ec4017a845935bd Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:14 +0530 Subject: [PATCH 2821/7721] ASoC: amd: Remove extra dmi parameter Remove extra dmi_product_family entry in amd config entry table. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 19a30f145143..04b58fb29a35 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -68,7 +68,6 @@ static const struct config_entry config_table[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Valve"), DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), - DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), }, }, {} From 671dd2ffbd8b92e2228fa84ea4274a051b704dec Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:15 +0530 Subject: [PATCH 2822/7721] ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance Add sof_bt cpu id and create dailink for i2s bt instance in acp common machine driver. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-4-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 25 ++++++++++++++++++++++++- sound/soc/amd/acp/acp-mach.h | 3 +++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 34b14f2611ba..4631af028f15 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey // Vijendar Mukunda @@ -1290,6 +1290,8 @@ SND_SOC_DAILINK_DEF(sof_hs, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs"))); SND_SOC_DAILINK_DEF(sof_hs_virtual, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs-virtual"))); +SND_SOC_DAILINK_DEF(sof_bt, + DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-bt"))); SND_SOC_DAILINK_DEF(sof_dmic, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic"))); SND_SOC_DAILINK_DEF(pdm_dmic, @@ -1348,6 +1350,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) if (drv_data->hs_cpu_id) num_links++; + if (drv_data->bt_cpu_id) + num_links++; if (drv_data->amp_cpu_id) num_links++; if (drv_data->dmic_cpu_id) @@ -1497,6 +1501,25 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->bt_cpu_id == I2S_BT) { + links[i].name = "acp-bt-codec"; + links[i].id = BT_BE_ID; + links[i].cpus = sof_bt; + links[i].num_cpus = ARRAY_SIZE(sof_bt); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->bt_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = &snd_soc_dummy_dlc; + links[i].num_codecs = 1; + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index cd681101bea7..a48546d8d407 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -28,6 +28,7 @@ enum be_id { HEADSET_BE_ID = 0, AMP_BE_ID, DMIC_BE_ID, + BT_BE_ID, }; enum cpu_endpoints { @@ -68,9 +69,11 @@ struct acp_mach_ops { struct acp_card_drvdata { unsigned int hs_cpu_id; unsigned int amp_cpu_id; + unsigned int bt_cpu_id; unsigned int dmic_cpu_id; unsigned int hs_codec_id; unsigned int amp_codec_id; + unsigned int bt_codec_id; unsigned int dmic_codec_id; unsigned int dai_fmt; unsigned int platform; From e6a382cf7a69cc80e57978bbf0c7a674dfb09621 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:16 +0530 Subject: [PATCH 2823/7721] ASoC: amd: acp: Add i2s bt support for nau8821-max card Add i2s bt support for sof-nau8821-max sound card. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-5-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sof-mach.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 5223033a122f..2a9fd3275e42 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey // @@ -86,9 +86,11 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { static struct acp_card_drvdata sof_nau8821_max98388_data = { .hs_cpu_id = I2S_SP, .amp_cpu_id = I2S_HS, + .bt_cpu_id = I2S_BT, .dmic_cpu_id = NONE, .hs_codec_id = NAU8821, .amp_codec_id = MAX98388, + .bt_codec_id = NONE, .dmic_codec_id = NONE, .soc_mclk = true, .tdm_mode = false, From e249839bf33f3f9727d6220536ed5c7d4f5bc31d Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:17 +0530 Subject: [PATCH 2824/7721] ASoC: amd: acp: Enable dpcm_capture for MAX98388 codec Enable dpcm_capture for amplifier codec MAX98388 for reference stream capture in smart amplifier case. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-6-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 4631af028f15..b72beb8e9b13 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -1483,6 +1483,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].init = acp_card_maxim_init; } if (drv_data->amp_codec_id == MAX98388) { + links[i].dpcm_capture = 1; links[i].codecs = max98388; links[i].num_codecs = ARRAY_SIZE(max98388); links[i].ops = &acp_max98388_ops; From ff5a698c0ffb08eee9c1ce0dfc79c91f273122d5 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:18 +0530 Subject: [PATCH 2825/7721] ASoC: amd: acp: Set bclk as source to set pll for rt5682s codec Some platforms doesn't have reference mclk pin to codec, so set bclk as a clk source for rt5682s codec pll in tdm mode. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-7-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index b72beb8e9b13..74e83c2dae53 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -464,6 +464,22 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream, return ret; } + if (drvdata->tdm_mode) { + ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1, + 6144000, 49152000); + if (ret < 0) { + dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL1, + 49152000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); + return ret; + } + } + /* Set tdm/i2s1 master bclk ratio */ ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format); if (ret < 0) { From fd2ef5fa3556549c565f5b7a07776d899a8ed8b7 Mon Sep 17 00:00:00 2001 From: Jiadong Zhu Date: Fri, 1 Dec 2023 08:38:15 +0800 Subject: [PATCH 2826/7721] drm/amdgpu: disable MCBP by default Disable MCBP(mid command buffer preemption) by default as old Mesa hangs with it. We shall not enable the feature that breaks old usermode driver. Fixes: 50a7c8765ca6 ("drm/amdgpu: enable mcbp by default on gfx9") Signed-off-by: Jiadong Zhu Acked-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6c0cf64d465a..d5b950fd1d85 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3861,10 +3861,6 @@ static void amdgpu_device_set_mcbp(struct amdgpu_device *adev) adev->gfx.mcbp = true; else if (amdgpu_mcbp == 0) adev->gfx.mcbp = false; - else if ((amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(9, 0, 0)) && - (amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(10, 0, 0)) && - adev->gfx.num_gfx_rings) - adev->gfx.mcbp = true; if (amdgpu_sriov_vf(adev)) adev->gfx.mcbp = true; From d5e78f1c2611e22204490b679d962d8f51762969 Mon Sep 17 00:00:00 2001 From: Bokun Zhang Date: Wed, 29 Nov 2023 19:02:57 -0500 Subject: [PATCH 2827/7721] drm/amd/amdgpu: Move vcn4 fw_shared init to a single function - Move VCN4's fw_shared initialization to a separated function. This way, the function can be reused at different locations. Signed-off-by: Bokun Zhang Reviewed-by: Emily Deng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 45 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 48bfcd0d558b..28b7f96b42e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -100,6 +100,31 @@ static int vcn_v4_0_early_init(void *handle) return amdgpu_vcn_early_init(adev); } +static int vcn_v4_0_fw_shared_init(struct amdgpu_device *adev, int inst_idx) +{ + volatile struct amdgpu_vcn4_fw_shared *fw_shared; + + fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr; + fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); + fw_shared->sq.is_enabled = 1; + + fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG); + fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ? + AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU; + + if (amdgpu_ip_version(adev, VCN_HWIP, 0) == + IP_VERSION(4, 0, 2)) { + fw_shared->present_flag_0 |= AMDGPU_FW_SHARED_FLAG_0_DRM_KEY_INJECT; + fw_shared->drm_key_wa.method = + AMDGPU_DRM_KEY_INJECT_WORKAROUND_VCNFW_ASD_HANDSHAKING; + } + + if (amdgpu_vcnfw_log) + amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]); + + return 0; +} + /** * vcn_v4_0_sw_init - sw init for VCN block * @@ -124,8 +149,6 @@ static int vcn_v4_0_sw_init(void *handle) return r; for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - volatile struct amdgpu_vcn4_fw_shared *fw_shared; - if (adev->vcn.harvest_config & (1 << i)) continue; @@ -161,23 +184,7 @@ static int vcn_v4_0_sw_init(void *handle) if (r) return r; - fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; - fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); - fw_shared->sq.is_enabled = 1; - - fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG); - fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ? - AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU; - - if (amdgpu_ip_version(adev, VCN_HWIP, 0) == - IP_VERSION(4, 0, 2)) { - fw_shared->present_flag_0 |= AMDGPU_FW_SHARED_FLAG_0_DRM_KEY_INJECT; - fw_shared->drm_key_wa.method = - AMDGPU_DRM_KEY_INJECT_WORKAROUND_VCNFW_ASD_HANDSHAKING; - } - - if (amdgpu_vcnfw_log) - amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]); + vcn_v4_0_fw_shared_init(adev, i); } if (amdgpu_sriov_vf(adev)) { From e57cd73f971194e94bc42d57b9fcb184c93a8754 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Fri, 1 Dec 2023 06:24:57 -0700 Subject: [PATCH 2828/7721] drm/amd/display: Optimize fast validation cases Optimize fast validation cases to only validate the highest voltage level. This works because during fast validation we only care if the mode can be supported or not (at any vlevel). Tested-by: Daniel Wheeler Reviewed-by: Aric Cyr Acked-by: Rodrigo Siqueira Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- .../dc/dml/dcn30/display_mode_vba_30.c | 29 +++++++++++-------- .../dc/resource/dcn30/dcn30_resource.c | 2 ++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 3686f1e7de3a..63c48c29ba49 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -3542,7 +3542,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l { struct vba_vars_st *v = &mode_lib->vba; int MinPrefetchMode, MaxPrefetchMode; - int i; + int i, start_state; unsigned int j, k, m; bool EnoughWritebackUnits = true; bool WritebackModeSupport = true; @@ -3553,6 +3553,11 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/ + if (mode_lib->validate_max_state) + start_state = v->soc.num_states - 1; + else + start_state = 0; + CalculateMinAndMaxPrefetchMode( mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, &MinPrefetchMode, &MaxPrefetchMode); @@ -3851,7 +3856,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->SingleDPPViewportSizeSupportPerPlane, &v->ViewportSizeSupport[0][0]); - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (j = 0; j < 2; j++) { v->MaxDispclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDispclk[i], v->DISPCLKDPPCLKVCOSpeed); v->MaxDppclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDppclk[i], v->DISPCLKDPPCLKVCOSpeed); @@ -4007,7 +4012,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*Total Available Pipes Support Check*/ - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (j = 0; j < 2; j++) { if (v->TotalNumberOfActiveDPP[i][j] <= v->MaxNumDPP) { v->TotalAvailablePipesSupport[i][j] = true; @@ -4046,7 +4051,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } } - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { v->RequiresDSC[i][k] = false; v->RequiresFEC[i][k] = false; @@ -4174,7 +4179,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } } } - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { v->DIOSupport[i] = true; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { if (!v->skip_dio_check[k] && v->BlendingAndTiming[k] == k && (v->Output[k] == dm_dp || v->Output[k] == dm_edp || v->Output[k] == dm_hdmi) @@ -4185,7 +4190,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } } - for (i = 0; i < v->soc.num_states; ++i) { + for (i = start_state; i < v->soc.num_states; ++i) { v->ODMCombine4To1SupportCheckOK[i] = true; for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (v->BlendingAndTiming[k] == k && v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1 @@ -4197,7 +4202,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /* Skip dscclk validation: as long as dispclk is supported, dscclk is also implicitly supported */ - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { v->NotEnoughDSCUnits[i] = false; v->TotalDSCUnitsRequired = 0.0; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { @@ -4217,7 +4222,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } /*DSC Delay per state*/ - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { if (v->OutputBppPerState[i][k] == BPP_INVALID) { v->BPP = 0.0; @@ -4333,7 +4338,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->cursor_bw[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k]; } - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (j = 0; j < 2; j++) { for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { v->swath_width_luma_ub_this_state[k] = v->swath_width_luma_ub_all_states[i][j][k]; @@ -5075,7 +5080,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*PTE Buffer Size Check*/ - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { for (j = 0; j < 2; j++) { v->PTEBufferSizeNotExceeded[i][j] = true; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { @@ -5136,7 +5141,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } /*Mode Support, Voltage State and SOC Configuration*/ - for (i = v->soc.num_states - 1; i >= 0; i--) { + for (i = v->soc.num_states - 1; i >= start_state; i--) { for (j = 0; j < 2; j++) { if (v->ScaleRatioAndTapsSupport == 1 && v->SourceFormatPixelAndScanSupport == 1 && v->ViewportSizeSupport[i][j] == 1 && v->DIOSupport[i] == 1 && v->ODMCombine4To1SupportCheckOK[i] == 1 @@ -5158,7 +5163,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } { unsigned int MaximumMPCCombine = 0; - for (i = v->soc.num_states; i >= 0; i--) { + for (i = v->soc.num_states; i >= start_state; i--) { if (i == v->soc.num_states || v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true) { v->VoltageLevel = i; v->ModeIsSupported = v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 2b6dcb489b90..37a64186f324 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -1682,6 +1682,7 @@ noinline bool dcn30_internal_validate_bw( * We don't actually support prefetch mode 2, so require that we * at least support prefetch mode 1. */ + context->bw_ctx.dml.validate_max_state = fast_validate; context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = dm_allow_self_refresh; @@ -1691,6 +1692,7 @@ noinline bool dcn30_internal_validate_bw( memset(merge, 0, sizeof(merge)); vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); } + context->bw_ctx.dml.validate_max_state = false; } dml_log_mode_support_params(&context->bw_ctx.dml); From 885c71ad791c1709f668a37f701d33e6872a902f Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 1 Dec 2023 06:24:58 -0700 Subject: [PATCH 2829/7721] drm/amd/display: initialize all the dpm level's stutter latency Fix issue when override level bigger than default. Levels 5, 6, and 7 had zero stutter latency, this is because override level being initialized after stutter latency inits. Tested-by: Daniel Wheeler Reviewed-by: Syed Hassan Reviewed-by: Allen Pan Acked-by: Rodrigo Siqueira Signed-off-by: Charlene Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index fa8fe5bf7e57..255af7875c08 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -341,6 +341,9 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, break; } + if (dml2->config.bbox_overrides.clks_table.num_states) + p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; + /* Override from passed values, if available */ for (i = 0; i < p->in_states->num_states; i++) { if (dml2->config.bbox_overrides.sr_exit_latency_us) { @@ -397,7 +400,6 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, } /* Copy clocks tables entries, if available */ if (dml2->config.bbox_overrides.clks_table.num_states) { - p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; for (i = 0; i < dml2->config.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels; i++) { p->in_states->state_array[i].dcfclk_mhz = dml2->config.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz; From dd2c5fac91d46df9dc1bf025ef23eff4704bd85f Mon Sep 17 00:00:00 2001 From: Relja Vojvodic Date: Fri, 1 Dec 2023 06:24:59 -0700 Subject: [PATCH 2830/7721] drm/amd/display: Add ODM check during pipe split/merge validation [why] When querying DML for a vlevel after pipes have been split or merged the ODM policy would revert to a default policy, which could cause the query to use the incorrect ODM status. In this case ODM 2to1 was validated, but the last DML query would assume no ODM and return the incorrect vlevel. [how] Added ODM check to apply the correct ODM policy before querying DML. Tested-by: Daniel Wheeler Reviewed-by: Alvin Lee Acked-by: Rodrigo Siqueira Signed-off-by: Relja Vojvodic Signed-off-by: Alex Deucher --- .../display/dc/dcn32/dcn32_resource_helpers.c | 26 +++++++++++++++++++ .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 3 +++ .../dc/resource/dcn32/dcn32_resource.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 389ac7ae1154..e8159a459bce 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -806,3 +806,29 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int return result; } + +void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe = NULL; + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + int odm_slice_count = 0; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + odm_slice_count = resource_get_odm_slice_count(pipe); + + if (odm_slice_count == 1) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + else if (odm_slice_count == 2) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; + else if (odm_slice_count == 4) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_4to1; + + pipe_cnt++; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 26411d4e9730..de209ca0cf8c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -2192,6 +2192,7 @@ bool dcn32_internal_validate_bw(struct dc *dc, int i; pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + dcn32_update_dml_pipes_odm_policy_based_on_context(dc, context, pipes); /* repopulate_pipes = 1 means the pipes were either split or merged. In this case * we have to re-calculate the DET allocation and run through DML once more to @@ -2200,7 +2201,9 @@ bool dcn32_internal_validate_bw(struct dc *dc, * */ context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = dm_prefetch_support_uclk_fclk_and_stutter_if_possible; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel == context->bw_ctx.dml.soc.num_states) { /* failed after DET size changes */ goto validate_fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h index b2f20e6cfb38..9ca799da1a56 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h @@ -193,6 +193,8 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context); bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int vlevel); +void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes); + /* definitions for run time init of reg offsets */ /* CLK SRC */ From fa745b554733ff0ed9ff918a0a53267300444c88 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Fri, 1 Dec 2023 06:25:00 -0700 Subject: [PATCH 2831/7721] drm/amd/display: Only enumerate top local sink as DP2 output [WHY] Many DCN generations only have two HPO link encoders and therefore only support driving a max of two DP2 PHYs. DP2 MST hubs currently can not pass 3x display validation as each downstream sink is enumerated as separate DP2 output. [HOW] Count MST hubs once by treating only 1st remote sink in topology as an encoder. Tested-by: Daniel Wheeler Reviewed-by: Nicholas Kazlauskas Acked-by: Rodrigo Siqueira Signed-off-by: Michael Strauss Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c index 33eab80e89a8..6ba393e5b8ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c @@ -157,6 +157,15 @@ bool is_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx) { /* If this assert is hit then we have a link encoder dynamic management issue */ ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); + + /* Count MST hubs once by treating only 1st remote sink in topology as an encoder */ + if (pipe_ctx->stream->link && pipe_ctx->stream->link->remote_sinks[0]) { + return (pipe_ctx->stream_res.hpo_dp_stream_enc && + pipe_ctx->link_res.hpo_dp_link_enc && + dc_is_dp_signal(pipe_ctx->stream->signal) && + (pipe_ctx->stream->link->remote_sinks[0] == pipe_ctx->stream->sink)); + } + return (pipe_ctx->stream_res.hpo_dp_stream_enc && pipe_ctx->link_res.hpo_dp_link_enc && dc_is_dp_signal(pipe_ctx->stream->signal)); From a546a27684407942604bccdf3b62f0765c0f6399 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Fri, 1 Dec 2023 23:38:12 -0600 Subject: [PATCH 2832/7721] drm/amdkfd: Use partial migrations/mapping for GPU/CPU page faults in SVM This patch implements partial migration/mapping for gpu/cpu page faults in SVM according to migration granularity(default 2MB). A svm range may include pages from both system ram and vram of one gpu now. These chagnes are expected to improve migration performance and reduce mmu callback and TLB flush workloads. Signed-off-by: Xiaogang Chen Reviewed-by: Philip Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 146 ++++++++++--------- drivers/gpu/drm/amd/amdkfd/kfd_migrate.h | 4 + drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 176 +++++++++++------------ drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 9 +- 4 files changed, 176 insertions(+), 159 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 6c25dab051d5..b854cbf06dce 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -442,10 +442,10 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, goto out_free; } if (cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + pr_debug("partial migration, 0x%lx/0x%llx pages collected\n", cpages, npages); else - pr_debug("0x%lx pages migrated\n", cpages); + pr_debug("0x%lx pages collected\n", cpages); r = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset); migrate_vma_pages(&migrate); @@ -479,6 +479,8 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, * svm_migrate_ram_to_vram - migrate svm range from system to device * @prange: range structure * @best_loc: the device to migrate to + * @start_mgr: start page to migrate + * @last_mgr: last page to migrate * @mm: the process mm structure * @trigger: reason of migration * @@ -489,6 +491,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, */ static int svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start_mgr, unsigned long last_mgr, struct mm_struct *mm, uint32_t trigger) { unsigned long addr, start, end; @@ -498,10 +501,10 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, unsigned long cpages = 0; long r = 0; - if (prange->actual_loc == best_loc) { - pr_debug("svms 0x%p [0x%lx 0x%lx] already on best_loc 0x%x\n", - prange->svms, prange->start, prange->last, best_loc); - return 0; + if (start_mgr < prange->start || last_mgr > prange->last) { + pr_debug("range [0x%lx 0x%lx] out prange [0x%lx 0x%lx]\n", + start_mgr, last_mgr, prange->start, prange->last); + return -EFAULT; } node = svm_range_get_node_by_id(prange, best_loc); @@ -510,18 +513,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, return -ENODEV; } - pr_debug("svms 0x%p [0x%lx 0x%lx] to gpu 0x%x\n", prange->svms, - prange->start, prange->last, best_loc); + pr_debug("svms 0x%p [0x%lx 0x%lx] in [0x%lx 0x%lx] to gpu 0x%x\n", + prange->svms, start_mgr, last_mgr, prange->start, prange->last, + best_loc); - start = prange->start << PAGE_SHIFT; - end = (prange->last + 1) << PAGE_SHIFT; + start = start_mgr << PAGE_SHIFT; + end = (last_mgr + 1) << PAGE_SHIFT; r = svm_range_vram_node_new(node, prange, true); if (r) { dev_dbg(node->adev->dev, "fail %ld to alloc vram\n", r); return r; } - ttm_res_offset = prange->offset << PAGE_SHIFT; + ttm_res_offset = (start_mgr - prange->start + prange->offset) << PAGE_SHIFT; for (addr = start; addr < end;) { unsigned long next; @@ -544,8 +548,11 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, if (cpages) { prange->actual_loc = best_loc; - svm_range_dma_unmap(prange); - } else { + prange->vram_pages = prange->vram_pages + cpages; + } else if (!prange->actual_loc) { + /* if no page migrated and all pages from prange are at + * sys ram drop svm_bo got from svm_range_vram_node_new + */ svm_range_vram_node_free(prange); } @@ -663,9 +670,8 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, * Context: Process context, caller hold mmap read lock, prange->migrate_mutex * * Return: - * 0 - success with all pages migrated * negative values - indicate error - * positive values - partial migration, number of pages not migrated + * positive values or zero - number of pages got migrated */ static long svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, @@ -676,6 +682,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, uint64_t npages = (end - start) >> PAGE_SHIFT; unsigned long upages = npages; unsigned long cpages = 0; + unsigned long mpages = 0; struct amdgpu_device *adev = node->adev; struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; @@ -725,10 +732,10 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, goto out_free; } if (cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + pr_debug("partial migration, 0x%lx/0x%llx pages collected\n", cpages, npages); else - pr_debug("0x%lx pages migrated\n", cpages); + pr_debug("0x%lx pages collected\n", cpages); r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, scratch, npages); @@ -751,17 +758,21 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, kvfree(buf); out: if (!r && cpages) { + mpages = cpages - upages; pdd = svm_range_get_pdd_by_node(prange, node); if (pdd) - WRITE_ONCE(pdd->page_out, pdd->page_out + cpages); + WRITE_ONCE(pdd->page_out, pdd->page_out + mpages); } - return r ? r : upages; + + return r ? r : mpages; } /** * svm_migrate_vram_to_ram - migrate svm range from device to system * @prange: range structure * @mm: process mm, use current->mm if NULL + * @start_mgr: start page need be migrated to sys ram + * @last_mgr: last page need be migrated to sys ram * @trigger: reason of migration * @fault_page: is from vmf->page, svm_migrate_to_ram(), this is CPU page fault callback * @@ -771,6 +782,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, * 0 - OK, otherwise error code */ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, + unsigned long start_mgr, unsigned long last_mgr, uint32_t trigger, struct page *fault_page) { struct kfd_node *node; @@ -778,26 +790,33 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, unsigned long addr; unsigned long start; unsigned long end; - unsigned long upages = 0; + unsigned long mpages = 0; long r = 0; + /* this pragne has no any vram page to migrate to sys ram */ if (!prange->actual_loc) { pr_debug("[0x%lx 0x%lx] already migrated to ram\n", prange->start, prange->last); return 0; } + if (start_mgr < prange->start || last_mgr > prange->last) { + pr_debug("range [0x%lx 0x%lx] out prange [0x%lx 0x%lx]\n", + start_mgr, last_mgr, prange->start, prange->last); + return -EFAULT; + } + node = svm_range_get_node_by_id(prange, prange->actual_loc); if (!node) { pr_debug("failed to get kfd node by id 0x%x\n", prange->actual_loc); return -ENODEV; } pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx] from gpu 0x%x to ram\n", - prange->svms, prange, prange->start, prange->last, + prange->svms, prange, start_mgr, last_mgr, prange->actual_loc); - start = prange->start << PAGE_SHIFT; - end = (prange->last + 1) << PAGE_SHIFT; + start = start_mgr << PAGE_SHIFT; + end = (last_mgr + 1) << PAGE_SHIFT; for (addr = start; addr < end;) { unsigned long next; @@ -816,14 +835,21 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, pr_debug("failed %ld to migrate prange %p\n", r, prange); break; } else { - upages += r; + mpages += r; } addr = next; } - if (r >= 0 && !upages) { - svm_range_vram_node_free(prange); - prange->actual_loc = 0; + if (r >= 0) { + prange->vram_pages -= mpages; + + /* prange does not have vram page set its actual_loc to system + * and drop its svm_bo ref + */ + if (prange->vram_pages == 0 && prange->ttm_res) { + prange->actual_loc = 0; + svm_range_vram_node_free(prange); + } } return r < 0 ? r : 0; @@ -833,17 +859,23 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, * svm_migrate_vram_to_vram - migrate svm range from device to device * @prange: range structure * @best_loc: the device to migrate to + * @start: start page need be migrated to sys ram + * @last: last page need be migrated to sys ram * @mm: process mm, use current->mm if NULL * @trigger: reason of migration * * Context: Process context, caller hold mmap read lock, svms lock, prange lock * + * migrate all vram pages in prange to sys ram, then migrate + * [start, last] pages from sys ram to gpu node best_loc. + * * Return: * 0 - OK, otherwise error code */ static int svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, - struct mm_struct *mm, uint32_t trigger) + unsigned long start, unsigned long last, + struct mm_struct *mm, uint32_t trigger) { int r, retries = 3; @@ -855,7 +887,8 @@ svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, pr_debug("from gpu 0x%x to gpu 0x%x\n", prange->actual_loc, best_loc); do { - r = svm_migrate_vram_to_ram(prange, mm, trigger, NULL); + r = svm_migrate_vram_to_ram(prange, mm, prange->start, prange->last, + trigger, NULL); if (r) return r; } while (prange->actual_loc && --retries); @@ -863,17 +896,21 @@ svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, if (prange->actual_loc) return -EDEADLK; - return svm_migrate_ram_to_vram(prange, best_loc, mm, trigger); + return svm_migrate_ram_to_vram(prange, best_loc, start, last, mm, trigger); } int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start, unsigned long last, struct mm_struct *mm, uint32_t trigger) { - if (!prange->actual_loc) - return svm_migrate_ram_to_vram(prange, best_loc, mm, trigger); + if (!prange->actual_loc || prange->actual_loc == best_loc) + return svm_migrate_ram_to_vram(prange, best_loc, start, last, + mm, trigger); + else - return svm_migrate_vram_to_vram(prange, best_loc, mm, trigger); + return svm_migrate_vram_to_vram(prange, best_loc, start, last, + mm, trigger); } @@ -889,10 +926,9 @@ svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, */ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) { + unsigned long start, last, size; unsigned long addr = vmf->address; struct svm_range_bo *svm_bo; - enum svm_work_list_ops op; - struct svm_range *parent; struct svm_range *prange; struct kfd_process *p; struct mm_struct *mm; @@ -929,51 +965,31 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) mutex_lock(&p->svms.lock); - prange = svm_range_from_addr(&p->svms, addr, &parent); + prange = svm_range_from_addr(&p->svms, addr, NULL); if (!prange) { pr_debug("failed get range svms 0x%p addr 0x%lx\n", &p->svms, addr); r = -EFAULT; goto out_unlock_svms; } - mutex_lock(&parent->migrate_mutex); - if (prange != parent) - mutex_lock_nested(&prange->migrate_mutex, 1); + mutex_lock(&prange->migrate_mutex); if (!prange->actual_loc) goto out_unlock_prange; - svm_range_lock(parent); - if (prange != parent) - mutex_lock_nested(&prange->lock, 1); - r = svm_range_split_by_granularity(p, mm, addr, parent, prange); - if (prange != parent) - mutex_unlock(&prange->lock); - svm_range_unlock(parent); - if (r) { - pr_debug("failed %d to split range by granularity\n", r); - goto out_unlock_prange; - } + /* Align migration range start and size to granularity size */ + size = 1UL << prange->granularity; + start = max(ALIGN_DOWN(addr, size), prange->start); + last = min(ALIGN(addr + 1, size) - 1, prange->last); - r = svm_migrate_vram_to_ram(prange, vmf->vma->vm_mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU, - vmf->page); + r = svm_migrate_vram_to_ram(prange, vmf->vma->vm_mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU, vmf->page); if (r) pr_debug("failed %d migrate svms 0x%p range 0x%p [0x%lx 0x%lx]\n", - r, prange->svms, prange, prange->start, prange->last); - - /* xnack on, update mapping on GPUs with ACCESS_IN_PLACE */ - if (p->xnack_enabled && parent == prange) - op = SVM_OP_UPDATE_RANGE_NOTIFIER_AND_MAP; - else - op = SVM_OP_UPDATE_RANGE_NOTIFIER; - svm_range_add_list_work(&p->svms, parent, mm, op); - schedule_deferred_list_work(&p->svms); + r, prange->svms, prange, start, last); out_unlock_prange: - if (prange != parent) - mutex_unlock(&prange->migrate_mutex); - mutex_unlock(&parent->migrate_mutex); + mutex_unlock(&prange->migrate_mutex); out_unlock_svms: mutex_unlock(&p->svms.lock); out_unref_process: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h index 487f26368164..2eebf67f9c2c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h @@ -41,9 +41,13 @@ enum MIGRATION_COPY_DIR { }; int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start, unsigned long last, struct mm_struct *mm, uint32_t trigger); + int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, + unsigned long start, unsigned long last, uint32_t trigger, struct page *fault_page); + unsigned long svm_migrate_addr_to_pfn(struct amdgpu_device *adev, unsigned long addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 613f19510287..617d20f0380f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -158,12 +158,13 @@ svm_is_valid_dma_mapping_addr(struct device *dev, dma_addr_t dma_addr) static int svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, unsigned long offset, unsigned long npages, - unsigned long *hmm_pfns, uint32_t gpuidx) + unsigned long *hmm_pfns, uint32_t gpuidx, uint64_t *vram_pages) { enum dma_data_direction dir = DMA_BIDIRECTIONAL; dma_addr_t *addr = prange->dma_addr[gpuidx]; struct device *dev = adev->dev; struct page *page; + uint64_t vram_pages_dev; int i, r; if (!addr) { @@ -173,6 +174,7 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, prange->dma_addr[gpuidx] = addr; } + vram_pages_dev = 0; addr += offset; for (i = 0; i < npages; i++) { if (svm_is_valid_dma_mapping_addr(dev, addr[i])) @@ -182,6 +184,7 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, if (is_zone_device_page(page)) { struct amdgpu_device *bo_adev = prange->svm_bo->node->adev; + vram_pages_dev++; addr[i] = (hmm_pfns[i] << PAGE_SHIFT) + bo_adev->vm_manager.vram_base_offset - bo_adev->kfd.pgmap.range.start; @@ -198,13 +201,14 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, pr_debug_ratelimited("dma mapping 0x%llx for page addr 0x%lx\n", addr[i] >> PAGE_SHIFT, page_to_pfn(page)); } + *vram_pages = vram_pages_dev; return 0; } static int svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap, unsigned long offset, unsigned long npages, - unsigned long *hmm_pfns) + unsigned long *hmm_pfns, uint64_t *vram_pages) { struct kfd_process *p; uint32_t gpuidx; @@ -223,7 +227,7 @@ svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap, } r = svm_range_dma_map_dev(pdd->dev->adev, prange, offset, npages, - hmm_pfns, gpuidx); + hmm_pfns, gpuidx, vram_pages); if (r) break; } @@ -349,6 +353,7 @@ svm_range *svm_range_new(struct svm_range_list *svms, uint64_t start, INIT_LIST_HEAD(&prange->child_list); atomic_set(&prange->invalid, 0); prange->validate_timestamp = 0; + prange->vram_pages = 0; mutex_init(&prange->migrate_mutex); mutex_init(&prange->lock); @@ -395,6 +400,8 @@ static void svm_range_bo_release(struct kref *kref) prange->start, prange->last); mutex_lock(&prange->lock); prange->svm_bo = NULL; + /* prange should not hold vram page now */ + WARN_ONCE(prange->actual_loc, "prange should not hold vram page"); mutex_unlock(&prange->lock); spin_lock(&svm_bo->list_lock); @@ -975,6 +982,11 @@ svm_range_split_nodes(struct svm_range *new, struct svm_range *old, new->svm_bo = svm_range_bo_ref(old->svm_bo); new->ttm_res = old->ttm_res; + /* set new's vram_pages as old range's now, the acurate vram_pages + * will be updated during mapping + */ + new->vram_pages = min(old->vram_pages, new->npages); + spin_lock(&new->svm_bo->list_lock); list_add(&new->svm_bo_list, &new->svm_bo->range_list); spin_unlock(&new->svm_bo->list_lock); @@ -1135,66 +1147,6 @@ svm_range_add_child(struct svm_range *prange, struct mm_struct *mm, list_add_tail(&pchild->child_list, &prange->child_list); } -/** - * svm_range_split_by_granularity - collect ranges within granularity boundary - * - * @p: the process with svms list - * @mm: mm structure - * @addr: the vm fault address in pages, to split the prange - * @parent: parent range if prange is from child list - * @prange: prange to split - * - * Trims @prange to be a single aligned block of prange->granularity if - * possible. The head and tail are added to the child_list in @parent. - * - * Context: caller must hold mmap_read_lock and prange->lock - * - * Return: - * 0 - OK, otherwise error code - */ -int -svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, - unsigned long addr, struct svm_range *parent, - struct svm_range *prange) -{ - struct svm_range *head, *tail; - unsigned long start, last, size; - int r; - - /* Align splited range start and size to granularity size, then a single - * PTE will be used for whole range, this reduces the number of PTE - * updated and the L1 TLB space used for translation. - */ - size = 1UL << prange->granularity; - start = ALIGN_DOWN(addr, size); - last = ALIGN(addr + 1, size) - 1; - - pr_debug("svms 0x%p split [0x%lx 0x%lx] to [0x%lx 0x%lx] size 0x%lx\n", - prange->svms, prange->start, prange->last, start, last, size); - - if (start > prange->start) { - r = svm_range_split(prange, start, prange->last, &head); - if (r) - return r; - svm_range_add_child(parent, mm, head, SVM_OP_ADD_RANGE); - } - - if (last < prange->last) { - r = svm_range_split(prange, prange->start, last, &tail); - if (r) - return r; - svm_range_add_child(parent, mm, tail, SVM_OP_ADD_RANGE); - } - - /* xnack on, update mapping on GPUs with ACCESS_IN_PLACE */ - if (p->xnack_enabled && prange->work_item.op == SVM_OP_ADD_RANGE) { - prange->work_item.op = SVM_OP_ADD_RANGE_AND_MAP; - pr_debug("change prange 0x%p [0x%lx 0x%lx] op %d\n", - prange, prange->start, prange->last, - SVM_OP_ADD_RANGE_AND_MAP); - } - return 0; -} static bool svm_nodes_in_same_hive(struct kfd_node *node_a, struct kfd_node *node_b) { @@ -1614,12 +1566,14 @@ static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx) * 5. Release page table (and SVM BO) reservation */ static int svm_range_validate_and_map(struct mm_struct *mm, + unsigned long map_start, unsigned long map_last, struct svm_range *prange, int32_t gpuidx, bool intr, bool wait, bool flush_tlb) { struct svm_validate_context *ctx; unsigned long start, end, addr; struct kfd_process *p; + uint64_t vram_pages; void *owner; int32_t idx; int r = 0; @@ -1688,11 +1642,15 @@ static int svm_range_validate_and_map(struct mm_struct *mm, } } + vram_pages = 0; start = prange->start << PAGE_SHIFT; end = (prange->last + 1) << PAGE_SHIFT; for (addr = start; !r && addr < end; ) { struct hmm_range *hmm_range; + unsigned long map_start_vma; + unsigned long map_last_vma; struct vm_area_struct *vma; + uint64_t vram_pages_vma; unsigned long next = 0; unsigned long offset; unsigned long npages; @@ -1721,9 +1679,11 @@ static int svm_range_validate_and_map(struct mm_struct *mm, if (!r) { offset = (addr - start) >> PAGE_SHIFT; r = svm_range_dma_map(prange, ctx->bitmap, offset, npages, - hmm_range->hmm_pfns); + hmm_range->hmm_pfns, &vram_pages_vma); if (r) pr_debug("failed %d to dma map range\n", r); + else + vram_pages += vram_pages_vma; } svm_range_lock(prange); @@ -1737,9 +1697,16 @@ static int svm_range_validate_and_map(struct mm_struct *mm, r = -EAGAIN; } - if (!r) - r = svm_range_map_to_gpus(prange, offset, npages, readonly, - ctx->bitmap, wait, flush_tlb); + if (!r) { + map_start_vma = max(map_start, prange->start + offset); + map_last_vma = min(map_last, prange->start + offset + npages - 1); + if (map_start_vma <= map_last_vma) { + offset = map_start_vma - prange->start; + npages = map_last_vma - map_start_vma + 1; + r = svm_range_map_to_gpus(prange, offset, npages, readonly, + ctx->bitmap, wait, flush_tlb); + } + } if (!r && next == end) prange->mapped_to_gpu = true; @@ -1749,6 +1716,19 @@ static int svm_range_validate_and_map(struct mm_struct *mm, addr = next; } + if (addr == end) { + prange->vram_pages = vram_pages; + + /* if prange does not include any vram page and it + * has not released svm_bo drop its svm_bo reference + * and set its actaul_loc to sys ram + */ + if (!vram_pages && prange->ttm_res) { + prange->actual_loc = 0; + svm_range_vram_node_free(prange); + } + } + svm_range_unreserve_bos(ctx); if (!r) prange->validate_timestamp = ktime_get_boottime(); @@ -1832,8 +1812,8 @@ static void svm_range_restore_work(struct work_struct *work) */ mutex_lock(&prange->migrate_mutex); - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - false, true, false); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, false, true, false); if (r) pr_debug("failed %d to map 0x%lx to gpus\n", r, prange->start); @@ -2001,6 +1981,7 @@ static struct svm_range *svm_range_clone(struct svm_range *old) new->actual_loc = old->actual_loc; new->granularity = old->granularity; new->mapped_to_gpu = old->mapped_to_gpu; + new->vram_pages = old->vram_pages; bitmap_copy(new->bitmap_access, old->bitmap_access, MAX_GPU_INSTANCE); bitmap_copy(new->bitmap_aip, old->bitmap_aip, MAX_GPU_INSTANCE); @@ -2908,6 +2889,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint32_t vmid, uint32_t node_id, uint64_t addr, bool write_fault) { + unsigned long start, last, size; struct mm_struct *mm = NULL; struct svm_range_list *svms; struct svm_range *prange; @@ -3043,40 +3025,44 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, kfd_smi_event_page_fault_start(node, p->lead_thread->pid, addr, write_fault, timestamp); - if (prange->actual_loc != best_loc) { + /* Align migration range start and size to granularity size */ + size = 1UL << prange->granularity; + start = max_t(unsigned long, ALIGN_DOWN(addr, size), prange->start); + last = min_t(unsigned long, ALIGN(addr + 1, size) - 1, prange->last); + if (prange->actual_loc != 0 || best_loc != 0) { migration = true; + if (best_loc) { - r = svm_migrate_to_vram(prange, best_loc, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU); + r = svm_migrate_to_vram(prange, best_loc, start, last, + mm, KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU); if (r) { pr_debug("svm_migrate_to_vram failed (%d) at %llx, falling back to system memory\n", r, addr); /* Fallback to system memory if migration to * VRAM failed */ - if (prange->actual_loc) - r = svm_migrate_vram_to_ram(prange, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, - NULL); + if (prange->actual_loc && prange->actual_loc != best_loc) + r = svm_migrate_vram_to_ram(prange, mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, NULL); else r = 0; } } else { - r = svm_migrate_vram_to_ram(prange, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, - NULL); + r = svm_migrate_vram_to_ram(prange, mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, NULL); } if (r) { pr_debug("failed %d to migrate svms %p [0x%lx 0x%lx]\n", - r, svms, prange->start, prange->last); + r, svms, start, last); goto out_unlock_range; } } - r = svm_range_validate_and_map(mm, prange, gpuidx, false, false, false); + r = svm_range_validate_and_map(mm, start, last, prange, gpuidx, false, + false, false); if (r) pr_debug("failed %d to map svms 0x%p [0x%lx 0x%lx] to gpus\n", - r, svms, prange->start, prange->last); + r, svms, start, last); kfd_smi_event_page_fault_end(node, p->lead_thread->pid, addr, migration); @@ -3422,18 +3408,24 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, *migrated = false; best_loc = svm_range_best_prefetch_location(prange); - if (best_loc == KFD_IOCTL_SVM_LOCATION_UNDEFINED || - best_loc == prange->actual_loc) + /* when best_loc is a gpu node and same as prange->actual_loc + * we still need do migration as prange->actual_loc !=0 does + * not mean all pages in prange are vram. hmm migrate will pick + * up right pages during migration. + */ + if ((best_loc == KFD_IOCTL_SVM_LOCATION_UNDEFINED) || + (best_loc == 0 && prange->actual_loc == 0)) return 0; if (!best_loc) { - r = svm_migrate_vram_to_ram(prange, mm, + r = svm_migrate_vram_to_ram(prange, mm, prange->start, prange->last, KFD_MIGRATE_TRIGGER_PREFETCH, NULL); *migrated = !r; return r; } - r = svm_migrate_to_vram(prange, best_loc, mm, KFD_MIGRATE_TRIGGER_PREFETCH); + r = svm_migrate_to_vram(prange, best_loc, prange->start, prange->last, + mm, KFD_MIGRATE_TRIGGER_PREFETCH); *migrated = !r; return r; @@ -3488,7 +3480,11 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work) mutex_lock(&prange->migrate_mutex); do { + /* migrate all vram pages in this prange to sys ram + * after that prange->actual_loc should be zero + */ r = svm_migrate_vram_to_ram(prange, mm, + prange->start, prange->last, KFD_MIGRATE_TRIGGER_TTM_EVICTION, NULL); } while (!r && prange->actual_loc && --retries); @@ -3612,8 +3608,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, flush_tlb = !migrated && update_mapping && prange->mapped_to_gpu; - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - true, true, flush_tlb); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, true, true, flush_tlb); if (r) pr_debug("failed %d to map svm range\n", r); @@ -3627,8 +3623,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, pr_debug("Remapping prange 0x%p [0x%lx 0x%lx]\n", prange, prange->start, prange->last); mutex_lock(&prange->migrate_mutex); - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - true, true, prange->mapped_to_gpu); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, true, true, prange->mapped_to_gpu); if (r) pr_debug("failed %d on remap svm range\n", r); mutex_unlock(&prange->migrate_mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index c528df1d0ba2..026863a0abcd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -78,6 +78,7 @@ struct svm_work_list_item { * @update_list:link list node used to add to update_list * @mapping: bo_va mapping structure to create and update GPU page table * @npages: number of pages + * @vram_pages: vram pages number in this svm_range * @dma_addr: dma mapping address on each GPU for system memory physical page * @ttm_res: vram ttm resource map * @offset: range start offset within mm_nodes @@ -88,7 +89,9 @@ struct svm_work_list_item { * @flags: flags defined as KFD_IOCTL_SVM_FLAG_* * @perferred_loc: perferred location, 0 for CPU, or GPU id * @perfetch_loc: last prefetch location, 0 for CPU, or GPU id - * @actual_loc: the actual location, 0 for CPU, or GPU id + * @actual_loc: this svm_range location. 0: all pages are from sys ram; + * GPU id: this svm_range may include vram pages from GPU with + * id actual_loc. * @granularity:migration granularity, log2 num pages * @invalid: not 0 means cpu page table is invalidated * @validate_timestamp: system timestamp when range is validated @@ -112,6 +115,7 @@ struct svm_range { struct list_head list; struct list_head update_list; uint64_t npages; + uint64_t vram_pages; dma_addr_t *dma_addr[MAX_GPU_INSTANCE]; struct ttm_resource *ttm_res; uint64_t offset; @@ -168,9 +172,6 @@ struct kfd_node *svm_range_get_node_by_id(struct svm_range *prange, int svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, bool clear); void svm_range_vram_node_free(struct svm_range *prange); -int svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, - unsigned long addr, struct svm_range *parent, - struct svm_range *prange); int svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint32_t vmid, uint32_t node_id, uint64_t addr, bool write_fault); From 62fbfdbbe3a1f188a6310d9418956b918840cd33 Mon Sep 17 00:00:00 2001 From: Daniel Miess Date: Fri, 1 Dec 2023 06:25:01 -0700 Subject: [PATCH 2833/7721] drm/amd/display: Add missing dcn35 RCO registers [Why] Some registers needed for root clock gating in dcn35 are not defined in the dccg header. [How] Add the needed registers and temporarily disable some register writes that are now taking place successfully until the registers can be properly enabled. Tested-by: Daniel Wheeler Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Daniel Miess Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 32 ++++++++++ .../gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c | 62 ++++++++++++++++++- .../gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h | 51 +++++++++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 76da59d8caaf..ef5c22f41563 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -296,6 +296,38 @@ type DTBCLK_P1_GATE_DISABLE;\ type DTBCLK_P2_GATE_DISABLE;\ type DTBCLK_P3_GATE_DISABLE;\ + type DSCCLK0_ROOT_GATE_DISABLE;\ + type DSCCLK1_ROOT_GATE_DISABLE;\ + type DSCCLK2_ROOT_GATE_DISABLE;\ + type DSCCLK3_ROOT_GATE_DISABLE;\ + type SYMCLKA_FE_ROOT_GATE_DISABLE;\ + type SYMCLKB_FE_ROOT_GATE_DISABLE;\ + type SYMCLKC_FE_ROOT_GATE_DISABLE;\ + type SYMCLKD_FE_ROOT_GATE_DISABLE;\ + type SYMCLKE_FE_ROOT_GATE_DISABLE;\ + type DPPCLK0_ROOT_GATE_DISABLE;\ + type DPPCLK1_ROOT_GATE_DISABLE;\ + type DPPCLK2_ROOT_GATE_DISABLE;\ + type DPPCLK3_ROOT_GATE_DISABLE;\ + type HDMISTREAMCLK0_ROOT_GATE_DISABLE;\ + type SYMCLKA_ROOT_GATE_DISABLE;\ + type SYMCLKB_ROOT_GATE_DISABLE;\ + type SYMCLKC_ROOT_GATE_DISABLE;\ + type SYMCLKD_ROOT_GATE_DISABLE;\ + type SYMCLKE_ROOT_GATE_DISABLE;\ + type PHYA_REFCLK_ROOT_GATE_DISABLE;\ + type PHYB_REFCLK_ROOT_GATE_DISABLE;\ + type PHYC_REFCLK_ROOT_GATE_DISABLE;\ + type PHYD_REFCLK_ROOT_GATE_DISABLE;\ + type PHYE_REFCLK_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK0_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK1_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK2_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK3_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK0_GATE_DISABLE;\ + type DPSTREAMCLK1_GATE_DISABLE;\ + type DPSTREAMCLK2_GATE_DISABLE;\ + type DPSTREAMCLK3_GATE_DISABLE;\ struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c index 142efd390d86..f1ba7bb792ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c @@ -506,6 +506,64 @@ static void dccg35_dpp_root_clock_control( dccg->dpp_clock_gated[dpp_inst] = !clock_on; } +static void dccg35_disable_symclk32_se( + struct dccg *dccg, + int hpo_se_inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + /* set refclk as the source for symclk32_se */ + switch (hpo_se_inst) { + case 0: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE0_SRC_SEL, 0, + SYMCLK32_SE0_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE0_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE0_GATE_DISABLE, 0); + } + break; + case 1: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE1_SRC_SEL, 0, + SYMCLK32_SE1_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE1_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE1_GATE_DISABLE, 0); + } + break; + case 2: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE2_SRC_SEL, 0, + SYMCLK32_SE2_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE2_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE2_GATE_DISABLE, 0); + } + break; + case 3: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE3_SRC_SEL, 0, + SYMCLK32_SE3_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE3_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE3_GATE_DISABLE, 0); + } + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + void dccg35_init(struct dccg *dccg) { int otg_inst; @@ -514,7 +572,7 @@ void dccg35_init(struct dccg *dccg) * will cause DCN to hang. */ for (otg_inst = 0; otg_inst < 4; otg_inst++) - dccg31_disable_symclk32_se(dccg, otg_inst); + dccg35_disable_symclk32_se(dccg, otg_inst); if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) for (otg_inst = 0; otg_inst < 2; otg_inst++) @@ -788,7 +846,7 @@ static const struct dccg_funcs dccg35_funcs = { .dccg_init = dccg35_init, .set_dpstreamclk = dccg35_set_dpstreamclk, .enable_symclk32_se = dccg31_enable_symclk32_se, - .disable_symclk32_se = dccg31_disable_symclk32_se, + .disable_symclk32_se = dccg35_disable_symclk32_se, .enable_symclk32_le = dccg31_enable_symclk32_le, .disable_symclk32_le = dccg31_disable_symclk32_le, .set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating, diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h index bde48bee0119..1586a45ca3bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h @@ -34,6 +34,7 @@ #define DCCG_REG_LIST_DCN35() \ DCCG_REG_LIST_DCN314(),\ SR(DPPCLK_CTRL),\ + SR(DCCG_GATE_DISABLE_CNTL4),\ SR(DCCG_GATE_DISABLE_CNTL5),\ SR(DCCG_GATE_DISABLE_CNTL6),\ SR(DCCG_GLOBAL_FGCG_REP_CNTL),\ @@ -180,6 +181,56 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYA_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYB_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYC_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYE_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL, DISPCLK_DCCG_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ struct dccg *dccg35_create( struct dc_context *ctx, From b17ef04bf3a4346d66404454d6a646343ddc9749 Mon Sep 17 00:00:00 2001 From: Lewis Huang Date: Fri, 1 Dec 2023 06:25:02 -0700 Subject: [PATCH 2834/7721] drm/amd/display: Pass pwrseq inst for backlight and ABM [Why] OTG inst and pwrseq inst mapping is not align therefore we cannot use otg_inst as pwrseq inst to get DCIO register. [How] 1. Pass the correct pwrseq instance to dmub when set abm pipe. 2. LVTMA control index change from panel_inst to pwrseq_inst. Tested-by: Daniel Wheeler Reviewed-by: Phil Hsieh Acked-by: Rodrigo Siqueira Signed-off-by: Lewis Huang Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/bios/bios_parser2.c | 4 +- .../drm/amd/display/dc/bios/command_table2.c | 12 ++-- .../drm/amd/display/dc/bios/command_table2.h | 2 +- .../gpu/drm/amd/display/dc/dc_bios_types.h | 2 +- drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c | 8 ++- .../gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c | 7 ++- .../gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h | 2 +- .../amd/display/dc/dcn31/dcn31_panel_cntl.c | 5 +- .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 16 ++--- .../amd/display/dc/hwss/dcn21/dcn21_hwseq.c | 36 ++++++++--- drivers/gpu/drm/amd/display/dc/inc/hw/abm.h | 3 +- .../drm/amd/display/dc/inc/hw/panel_cntl.h | 2 + .../drm/amd/display/dc/link/link_factory.c | 59 +++++++++++++------ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 14 ++++- 14 files changed, 119 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 7cdb1a8a0ba0..2fb804eb5702 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1691,7 +1691,7 @@ static enum bp_result bios_parser_enable_disp_power_gating( static enum bp_result bios_parser_enable_lvtma_control( struct dc_bios *dcb, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait) { struct bios_parser *bp = BP_FROM_DCB(dcb); @@ -1699,7 +1699,7 @@ static enum bp_result bios_parser_enable_lvtma_control( if (!bp->cmd_tbl.enable_lvtma_control) return BP_RESULT_FAILURE; - return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance, bypass_panel_control_wait); + return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, pwrseq_instance, bypass_panel_control_wait); } static bool bios_parser_is_accelerated_mode( diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 90a02d7bd3da..ab0adabf9dd4 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -976,7 +976,7 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait); static void init_enable_lvtma_control(struct bios_parser *bp) @@ -989,7 +989,7 @@ static void init_enable_lvtma_control(struct bios_parser *bp) static void enable_lvtma_control_dmcub( struct dc_dmub_srv *dmcub, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait) { @@ -1002,8 +1002,8 @@ static void enable_lvtma_control_dmcub( DMUB_CMD__VBIOS_LVTMA_CONTROL; cmd.lvtma_control.data.uc_pwr_action = uc_pwr_on; - cmd.lvtma_control.data.panel_inst = - panel_instance; + cmd.lvtma_control.data.pwrseq_inst = + pwrseq_instance; cmd.lvtma_control.data.bypass_panel_control_wait = bypass_panel_control_wait; dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); @@ -1012,7 +1012,7 @@ static void enable_lvtma_control_dmcub( static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait) { enum bp_result result = BP_RESULT_FAILURE; @@ -1021,7 +1021,7 @@ static enum bp_result enable_lvtma_control( bp->base.ctx->dc->debug.dmub_command_table) { enable_lvtma_control_dmcub(bp->base.ctx->dmub_srv, uc_pwr_on, - panel_instance, + pwrseq_instance, bypass_panel_control_wait); return BP_RESULT_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h index b6d09bf6cf72..41c8c014397f 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h @@ -96,7 +96,7 @@ struct cmd_tbl { struct bios_parser *bp, uint8_t id); enum bp_result (*enable_lvtma_control)(struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait); }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index be9aa1a71847..26940d94d8fb 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -140,7 +140,7 @@ struct dc_vbios_funcs { enum bp_result (*enable_lvtma_control)( struct dc_bios *bios, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait); enum bp_result (*get_soc_bb_info)( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c index d3e6544022b7..930fd929e93a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -145,7 +145,11 @@ static bool dmub_abm_save_restore_ex( return ret; } -static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +static bool dmub_abm_set_pipe_ex(struct abm *abm, + uint32_t otg_inst, + uint32_t option, + uint32_t panel_inst, + uint32_t pwrseq_inst) { bool ret = false; unsigned int feature_support; @@ -153,7 +157,7 @@ static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t op feature_support = abm_feature_support(abm, panel_inst); if (feature_support == ABM_LCD_SUPPORT) - ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst); + ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); return ret; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c index 592a8f7a1c6d..42c802afc468 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c @@ -254,7 +254,11 @@ bool dmub_abm_save_restore( return true; } -bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +bool dmub_abm_set_pipe(struct abm *abm, + uint32_t otg_inst, + uint32_t option, + uint32_t panel_inst, + uint32_t pwrseq_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = abm->ctx; @@ -264,6 +268,7 @@ bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; + cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h index 853564d7f471..07ea6c8d414f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h @@ -44,7 +44,7 @@ bool dmub_abm_save_restore( struct dc_context *dc, unsigned int panel_inst, struct abm_save_restore *pData); -bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst); +bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst); bool dmub_abm_set_backlight_level(struct abm *abm, unsigned int backlight_pwm_u16_16, unsigned int frame_ramp, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c index 217acd4e292a..d849b1eaa4a5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c @@ -50,7 +50,7 @@ static bool dcn31_query_backlight_info(struct panel_cntl *panel_cntl, union dmub cmd->panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; cmd->panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO; cmd->panel_cntl.header.payload_bytes = sizeof(cmd->panel_cntl.data); - cmd->panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + cmd->panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; return dm_execute_dmub_cmd(dc_dmub_srv->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); } @@ -78,7 +78,7 @@ static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl) cmd.panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; cmd.panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_HW_INIT; cmd.panel_cntl.header.payload_bytes = sizeof(cmd.panel_cntl.data); - cmd.panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + cmd.panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; cmd.panel_cntl.data.bl_pwm_cntl = panel_cntl->stored_backlight_registers.BL_PWM_CNTL; cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL; cmd.panel_cntl.data.bl_pwm_ref_div1 = @@ -157,4 +157,5 @@ void dcn31_panel_cntl_construct( dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs; dcn31_panel_cntl->base.ctx = init_data->ctx; dcn31_panel_cntl->base.inst = init_data->inst; + dcn31_panel_cntl->base.pwrseq_inst = init_data->pwrseq_inst; } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 0a331d17ee92..c73fe5e9b361 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -790,7 +790,7 @@ void dce110_edp_power_control( struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result bp_result; - uint8_t panel_instance; + uint8_t pwrseq_instance; if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) @@ -873,7 +873,7 @@ void dce110_edp_power_control( cntl.coherent = false; cntl.lanes_number = LANE_COUNT_FOUR; cntl.hpd_sel = link->link_enc->hpd_source; - panel_instance = link->panel_cntl->inst; + pwrseq_instance = link->panel_cntl->pwrseq_inst; if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { @@ -881,11 +881,11 @@ void dce110_edp_power_control( if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) { bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_POWER_ON, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } else { bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_POWER_OFF, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } } @@ -956,7 +956,7 @@ void dce110_edp_backlight_control( { struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; - uint8_t panel_instance; + uint8_t pwrseq_instance; unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; unsigned int post_T7_delay = OLED_POST_T7_DELAY; @@ -1009,7 +1009,7 @@ void dce110_edp_backlight_control( */ /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ - panel_instance = link->panel_cntl->inst; + pwrseq_instance = link->panel_cntl->pwrseq_inst; if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { if (!link->dc->config.edp_no_power_sequencing) @@ -1034,11 +1034,11 @@ void dce110_edp_backlight_control( if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLON, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); else ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLOFF, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } link_transmitter_control(ctx->dc_bios, &cntl); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index 467812cf3368..08783ad097d2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -137,7 +137,8 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) pipe_ctx->stream->dpms_off = true; } -static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, + uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = abm->ctx; @@ -147,6 +148,7 @@ static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t optio cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; + cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; @@ -179,7 +181,6 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) struct abm *abm = pipe_ctx->stream_res.abm; uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; if (dmcu) { @@ -190,9 +191,13 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, - panel_cntl->inst); + panel_cntl->inst, panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst); + dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_IMMEDIATELY_DISABLE, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } panel_cntl->funcs->store_backlight_level(panel_cntl); } @@ -212,9 +217,16 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + abm->funcs->set_pipe_ex(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + dmub_abm_set_pipe(abm, otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } } } @@ -237,9 +249,17 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + abm->funcs->set_pipe_ex(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } } } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h index 33db15d69f23..9f521cf0fc5a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h @@ -64,7 +64,8 @@ struct abm_funcs { bool (*set_pipe_ex)(struct abm *abm, unsigned int otg_inst, unsigned int option, - unsigned int panel_inst); + unsigned int panel_inst, + unsigned int pwrseq_inst); }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h index 24af9d80b937..248adc1705e3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h @@ -56,12 +56,14 @@ struct panel_cntl_funcs { struct panel_cntl_init_data { struct dc_context *ctx; uint32_t inst; + uint32_t pwrseq_inst; }; struct panel_cntl { const struct panel_cntl_funcs *funcs; struct dc_context *ctx; uint32_t inst; + uint32_t pwrseq_inst; /* registers setting needs to be saved and restored at InitBacklight */ struct panel_cntl_backlight_registers stored_backlight_registers; }; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 6b306ea58b9b..5464d8d26bd3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -369,6 +369,30 @@ static enum transmitter translate_encoder_to_transmitter( } } +static uint8_t translate_dig_inst_to_pwrseq_inst(struct dc_link *link) +{ + uint8_t pwrseq_inst = 0xF; + struct dc_context *dc_ctx = link->dc->ctx; + + DC_LOGGER_INIT(dc_ctx->logger); + + switch (link->eng_id) { + case ENGINE_ID_DIGA: + pwrseq_inst = 0; + break; + case ENGINE_ID_DIGB: + pwrseq_inst = 1; + break; + default: + DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", link->eng_id); + ASSERT(false); + break; + } + + return pwrseq_inst; +} + + static void link_destruct(struct dc_link *link) { int i; @@ -596,24 +620,6 @@ static bool construct_phy(struct dc_link *link, link->ddc_hw_inst = dal_ddc_get_line(get_ddc_pin(link->ddc)); - - if (link->dc->res_pool->funcs->panel_cntl_create && - (link->link_id.id == CONNECTOR_ID_EDP || - link->link_id.id == CONNECTOR_ID_LVDS)) { - panel_cntl_init_data.ctx = dc_ctx; - panel_cntl_init_data.inst = - panel_cntl_init_data.ctx->dc_edp_id_count; - link->panel_cntl = - link->dc->res_pool->funcs->panel_cntl_create( - &panel_cntl_init_data); - panel_cntl_init_data.ctx->dc_edp_id_count++; - - if (link->panel_cntl == NULL) { - DC_ERROR("Failed to create link panel_cntl!\n"); - goto panel_cntl_create_fail; - } - } - enc_init_data.ctx = dc_ctx; bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0, &enc_init_data.encoder); @@ -644,6 +650,23 @@ static bool construct_phy(struct dc_link *link, link->dc->res_pool->dig_link_enc_count++; link->link_enc_hw_inst = link->link_enc->transmitter; + + if (link->dc->res_pool->funcs->panel_cntl_create && + (link->link_id.id == CONNECTOR_ID_EDP || + link->link_id.id == CONNECTOR_ID_LVDS)) { + panel_cntl_init_data.ctx = dc_ctx; + panel_cntl_init_data.inst = panel_cntl_init_data.ctx->dc_edp_id_count; + panel_cntl_init_data.pwrseq_inst = translate_dig_inst_to_pwrseq_inst(link); + link->panel_cntl = + link->dc->res_pool->funcs->panel_cntl_create( + &panel_cntl_init_data); + panel_cntl_init_data.ctx->dc_edp_id_count++; + + if (link->panel_cntl == NULL) { + DC_ERROR("Failed to create link panel_cntl!\n"); + goto panel_cntl_create_fail; + } + } for (i = 0; i < 4; i++) { if (bp_funcs->get_device_tag(dc_ctx->dc_bios, link->link_id, i, diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index a365f6c096de..3c092064c72e 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -3498,6 +3498,16 @@ struct dmub_cmd_abm_set_pipe_data { * TODO: Remove. */ uint8_t ramping_boundary; + + /** + * PwrSeq HW Instance. + */ + uint8_t pwrseq_inst; + + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[3]; }; /** @@ -3878,7 +3888,7 @@ enum dmub_cmd_panel_cntl_type { * struct dmub_cmd_panel_cntl_data - Panel control data. */ struct dmub_cmd_panel_cntl_data { - uint32_t inst; /**< panel instance */ + uint32_t pwrseq_inst; /**< pwrseq instance */ uint32_t current_backlight; /* in/out */ uint32_t bl_pwm_cntl; /* in/out */ uint32_t bl_pwm_period_cntl; /* in/out */ @@ -3937,7 +3947,7 @@ struct dmub_cmd_lvtma_control_data { uint8_t uc_pwr_action; /**< LVTMA_ACTION */ uint8_t bypass_panel_control_wait; uint8_t reserved_0[2]; /**< For future use */ - uint8_t panel_inst; /**< LVTMA control instance */ + uint8_t pwrseq_inst; /**< LVTMA control instance */ uint8_t reserved_1[3]; /**< For future use */ }; From d5df648ec830cfd775bdacb3a3640c1e16de90f2 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac Date: Fri, 1 Dec 2023 06:25:03 -0700 Subject: [PATCH 2835/7721] drm/amd/display: Change dither policy for 10bpc to round We use spatial dither by default for all output bpc (6/8/10). While it makes some sense for FP16, for ARGB2101010 surfaces it makes little sense as even if we skip color pipeline to preserve bit accuracy, spatial dither adds random noise so a few percent pixels are 1 bit off. This commit chages the 10bpc out dither policy to rounding. Also, in Polaris/Vega times, policy used to be round for 10bpc out; it looks like it got inadvertently changed for Navi. Difference is only detectable with capture cards. Tested-by: Daniel Wheeler Reviewed-by: Aric Cyr Reviewed-by: Anthony Koo Acked-by: Rodrigo Siqueira Signed-off-by: Krunoslav Kovac Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index e1c02527d04a..4382d9ae4292 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -4773,7 +4773,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, option = DITHER_OPTION_SPATIAL8; break; case COLOR_DEPTH_101010: - option = DITHER_OPTION_SPATIAL10; + option = DITHER_OPTION_TRUN10; break; default: option = DITHER_OPTION_DISABLE; @@ -4799,6 +4799,8 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; + if (option == DITHER_OPTION_TRUN10) + fmt_bit_depth->flags.TRUNCATE_MODE = 1; } /* special case - Formatter can only reduce by 4 bits at most. From ab779466166348eecf17d20f620aa9a47965c934 Mon Sep 17 00:00:00 2001 From: Josip Pavic Date: Fri, 1 Dec 2023 06:25:04 -0700 Subject: [PATCH 2836/7721] drm/amd/display: Increase scratch buffer size [Why] Larger data blocks are expected to be transferred between driver and FW in the future. [How] Embiggen the scratch buffer to a cromulent size. Tested-by: Daniel Wheeler Reviewed-by: Nicholas Kazlauskas Acked-by: Rodrigo Siqueira Signed-off-by: Josip Pavic Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 38360adc53d9..a329a6ecf4dd 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -64,7 +64,7 @@ /* Default scratch mem size. */ -#define DMUB_SCRATCH_MEM_SIZE (256) +#define DMUB_SCRATCH_MEM_SIZE (1024) /* Number of windows in use. */ #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL) From 23cf5a5cd33a518b6bdbe9966dc49f1cf6bfe532 Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 1 Dec 2023 06:25:05 -0700 Subject: [PATCH 2837/7721] drm/amd/display: insert drv-pmfw log + rollback to new context Rollback to new context for active display: this was previous tested sequence. Avoid to do OTG master toggle is no active display at all, this w/a was for fifo err. Tested-by: Daniel Wheeler Reviewed-by: Chris Park Acked-by: Rodrigo Siqueira Signed-off-by: Charlene Liu Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 27 ++++++------ .../amd/display/dc/clk_mgr/dcn35/dcn35_smu.c | 43 ++++++++++++++----- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index d5fde7d23fbf..9e0fa01ecb79 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -80,12 +80,12 @@ static int dcn35_get_active_display_cnt_wa( struct dc *dc, - struct dc_state *context) + struct dc_state *context, + int *all_active_disps) { - int i, display_count; + int i, display_count = 0; bool tmds_present = false; - display_count = 0; for (i = 0; i < context->stream_count; i++) { const struct dc_stream_state *stream = context->streams[i]; @@ -103,7 +103,8 @@ static int dcn35_get_active_display_cnt_wa( link->link_enc->funcs->is_dig_enabled(link->link_enc)) display_count++; } - + if (all_active_disps != NULL) + *all_active_disps = display_count; /* WA for hang on HDMI after display off back on*/ if (display_count == 0 && tmds_present) display_count = 1; @@ -224,15 +225,16 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; struct dc *dc = clk_mgr_base->ctx->dc; - int display_count; + int display_count = 0; bool update_dppclk = false; bool update_dispclk = false; bool dpp_clock_lowered = false; + int all_active_disps = 0; if (dc->work_arounds.skip_clock_update) return; - /* DTBCLK is fixed, so set a default if unspecified. */ + display_count = dcn35_get_active_display_cnt_wa(dc, context, &all_active_disps); if (new_clocks->dtbclk_en && !new_clocks->ref_dtbclk_khz) new_clocks->ref_dtbclk_khz = 600000; @@ -254,7 +256,6 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, } /* check that we're not already in lower */ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { - display_count = dcn35_get_active_display_cnt_wa(dc, context); /* if we can go lower, go lower */ if (display_count == 0) clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; @@ -311,11 +312,13 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { - dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); - clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; - dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + if (all_active_disps != 0) { + dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + } else + dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); update_dispclk = true; } @@ -826,7 +829,7 @@ static void dcn35_set_low_power_state(struct clk_mgr *clk_mgr_base) struct dc_state *context = dc->current_state; if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { - display_count = dcn35_get_active_display_cnt_wa(dc, context); + display_count = dcn35_get_active_display_cnt_wa(dc, context, NULL); /* if we can go lower, go lower */ if (display_count == 0) clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c index af0a0f292595..786b62ab8d0f 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c @@ -279,7 +279,7 @@ void dcn35_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, u clk_mgr, VBIOSSMC_MSG_SetDisplayIdleOptimizations, idle_info); - smu_print("VBIOSSMC_MSG_SetDisplayIdleOptimizations idle_info = %d\n", idle_info); + smu_print("%s: VBIOSSMC_MSG_SetDisplayIdleOptimizations idle_info = %x\n", __func__, idle_info); } void dcn35_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) @@ -298,7 +298,7 @@ void dcn35_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool e clk_mgr, VBIOSSMC_MSG_SetDisplayIdleOptimizations, idle_info.data); - smu_print("dcn35_smu_enable_phy_refclk_pwrdwn = %d\n", enable ? 1 : 0); + smu_print("%s smu_enable_phy_refclk_pwrdwn = %d\n", __func__, enable ? 1 : 0); } void dcn35_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) @@ -310,6 +310,7 @@ void dcn35_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) clk_mgr, VBIOSSMC_MSG_UpdatePmeRestore, 0); + smu_print("%s: SMC_MSG_UpdatePmeRestore\n", __func__); } void dcn35_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high) @@ -350,7 +351,7 @@ void dcn35_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr) void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support) { - unsigned int msg_id, param; + unsigned int msg_id, param, retv; if (!clk_mgr->smu_present) return; @@ -360,27 +361,32 @@ void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst case DCN_ZSTATE_SUPPORT_ALLOW: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10) | (1 << 9) | (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntr msg = ALLOW, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_DISALLOW: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = 0; + smu_print("%s: SMC_MSG_AllowZstatesEntr msg_id = DISALLOW, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10); + smu_print("%s: SMC_MSG_AllowZstatesEntr msg = ALLOW_Z10_ONLY, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10) | (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntr msg = ALLOW_Z8_Z10_ONLY, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntry msg = ALLOW_Z8_ONLY, param = %d\n", __func__, param); break; default: //DCN_ZSTATE_SUPPORT_UNKNOWN @@ -390,11 +396,11 @@ void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst } - dcn35_smu_send_msg_with_param( + retv = dcn35_smu_send_msg_with_param( clk_mgr, msg_id, param); - smu_print("dcn35_smu_set_zstate_support msg_id = %d, param = %d\n", msg_id, param); + smu_print("%s: msg_id = %d, param = 0x%x, return = %d\n", __func__, msg_id, param, retv); } int dcn35_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr) @@ -408,7 +414,7 @@ int dcn35_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_GetDprefclkFreq, 0); - smu_print("dcn35_smu_get_DPREF clk = %d mhz\n", dprefclk); + smu_print("%s: SMU DPREF clk = %d mhz\n", __func__, dprefclk); return dprefclk * 1000; } @@ -423,7 +429,7 @@ int dcn35_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_GetDtbclkFreq, 0); - smu_print("dcn35_smu_get_dtbclk = %d mhz\n", dtbclk); + smu_print("%s: get_dtbclk = %dmhz\n", __func__, dtbclk); return dtbclk * 1000; } /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */ @@ -436,7 +442,7 @@ void dcn35_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) clk_mgr, VBIOSSMC_MSG_SetDtbClk, enable); - smu_print("dcn35_smu_set_dtbclk = %d \n", enable ? 1 : 0); + smu_print("%s: smu_set_dtbclk = %d\n", __func__, enable ? 1 : 0); } void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) @@ -445,30 +451,45 @@ void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *cl clk_mgr, VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown, enable); + smu_print("%s: smu_enable_48mhz_tmdp_refclk_pwrdwn = %d\n", __func__, enable ? 1 : 0); } int dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr) { - return dcn35_smu_send_msg_with_param( + int retv; + + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_DispPsrExit, 0); + smu_print("%s: smu_exit_low_power_state return = %d\n", __func__, retv); + return retv; } int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr) { - return dcn35_smu_send_msg_with_param( + int retv; + + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_QueryIPS2Support, 0); + + smu_print("%s: VBIOSSMC_MSG_QueryIPS2Support return = %x\n", __func__, retv); + return retv; } void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param) { REG_WRITE(MP1_SMN_C2PMSG_71, param); + smu_print("%s: write_ips_scratch = %x\n", __func__, param); } uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr) { - return REG_READ(MP1_SMN_C2PMSG_71); + uint32_t retv; + + retv = REG_READ(MP1_SMN_C2PMSG_71); + smu_print("%s: dcn35_smu_read_ips_scratch = %x\n", __func__, retv); + return retv; } From 94bbf802efd0a8f13147d6664af6e653637340a8 Mon Sep 17 00:00:00 2001 From: Ilya Bakoulin Date: Fri, 1 Dec 2023 06:25:06 -0700 Subject: [PATCH 2838/7721] drm/amd/display: Fix MST PBN/X.Y value calculations Changing PBN calculation to be more in line with spec. We don't need to inflate PBN_NATIVE value by the 1.006 margin, since that is already taken care of in the get_pbn_per_slot function. Tested-by: Daniel Wheeler Reviewed-by: Wenjing Liu Acked-by: Rodrigo Siqueira Signed-off-by: Ilya Bakoulin Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index aa0a086aa7fc..b16b2e14312e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -1057,18 +1057,21 @@ static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps) uint32_t denominator = 1; /* - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 + * The 1.006 factor (margin 5300ppm + 300ppm ~ 0.6% as per spec) is not + * required when determining PBN/time slot utilization on the link between + * us and the branch, since that overhead is already accounted for in + * the get_pbn_per_slot function. + * * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on * common multiplier to render an integer PBN for all link rate/lane * counts combinations * calculate - * peak_kbps *= (1006/1000) * peak_kbps *= (64/54) - * peak_kbps *= 8 convert to bytes + * peak_kbps /= (8 * 1000) convert to bytes */ - numerator = 64 * PEAK_FACTOR_X1000; - denominator = 54 * 8 * 1000 * 1000; + numerator = 64; + denominator = 54 * 8 * 1000; kbps *= numerator; peak_kbps = dc_fixpt_from_fraction(kbps, denominator); From 823423b8ec7b56e22dad83e171c9ca6418679169 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Fri, 1 Dec 2023 06:25:07 -0700 Subject: [PATCH 2839/7721] drm/amd/display: Use channel_width = 2 for vram table 3.0 VBIOS has suggested to use channel_width=2 for any ASIC that uses vram info 3.0. This is because channel_width in the vram table no longer represents the memory width Tested-by: Daniel Wheeler Reviewed-by: Samson Tam Acked-by: Rodrigo Siqueira Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 2fb804eb5702..01abc2f3081a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -2386,7 +2386,13 @@ static enum bp_result get_vram_info_v30( return BP_RESULT_BADBIOSTABLE; info->num_chans = info_v30->channel_num; - info->dram_channel_width_bytes = (1 << info_v30->channel_width) / 8; + /* As suggested by VBIOS we should always use + * dram_channel_width_bytes = 2 when using VRAM + * table version 3.0. This is because the channel_width + * param in the VRAM info table is changed in 7000 series and + * no longer represents the memory channel width. + */ + info->dram_channel_width_bytes = 2; return result; } From 2cbed167d2698f10a67f47f14aaac7d498f6dfb7 Mon Sep 17 00:00:00 2001 From: Johnson Chen Date: Fri, 1 Dec 2023 06:25:08 -0700 Subject: [PATCH 2840/7721] drm/amd/display: Fix null pointer Add guard for NULL pointer access Tested-by: Daniel Wheeler Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Johnson Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c index 6ba393e5b8ee..38fa7441df51 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c @@ -158,6 +158,8 @@ bool is_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx) /* If this assert is hit then we have a link encoder dynamic management issue */ ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); + if (pipe_ctx->stream == NULL) + return false; /* Count MST hubs once by treating only 1st remote sink in topology as an encoder */ if (pipe_ctx->stream->link && pipe_ctx->stream->link->remote_sinks[0]) { return (pipe_ctx->stream_res.hpo_dp_stream_enc && From d24e50e1005fd584e0fea138aa153349e13b4d94 Mon Sep 17 00:00:00 2001 From: George Shen Date: Fri, 1 Dec 2023 06:25:09 -0700 Subject: [PATCH 2841/7721] drm/amd/display: Skip DPIA-specific DP LL automation flag for non-DPIA links [Why] The is_automated flag logic only applies to USB4 DPIA links during DP LL compliance test automation. The flag should not be set for non-DPIA cases. [How] Add check for DPIA link endpoint type before setting the flag. Also, rename is_automated to skip_fallback_on_link_loss for clarity. Tested-by: Daniel Wheeler Reviewed-by: Meenakshikumar Somasundaram Reviewed-by: Wenjing Liu Acked-by: Rodrigo Siqueira Signed-off-by: George Shen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 8 +++++++- .../amd/display/dc/link/protocols/link_dp_irq_handler.c | 6 ++++-- .../amd/display/dc/link/protocols/link_dp_training_dpia.c | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e8c1599ab18a..6ee4db8c0548 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1541,7 +1541,13 @@ struct dc_link { bool is_dig_mapping_flexible; bool hpd_status; /* HPD status of link without physical HPD pin. */ bool is_hpd_pending; /* Indicates a new received hpd */ - bool is_automated; /* Indicates automated testing */ + + /* USB4 DPIA links skip verifying link cap, instead performing the fallback method + * for every link training. This is incompatible with DP LL compliance automation, + * which expects the same link settings to be used every retry on a link loss. + * This flag is used to skip the fallback when link loss occurs during automation. + */ + bool skip_fallback_on_link_loss; bool edp_sink_present; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 0c00e94e90b1..ae271c830c9a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -265,7 +265,7 @@ void dp_handle_link_loss(struct dc_link *link) for (i = count - 1; i >= 0; i--) { // Always use max settings here for DP 1.4a LL Compliance CTS - if (link->is_automated) { + if (link->skip_fallback_on_link_loss) { pipes[i]->link_config.dp_link_settings.lane_count = link->verified_link_cap.lane_count; pipes[i]->link_config.dp_link_settings.link_rate = @@ -404,7 +404,9 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link, if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) { // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC - link->is_automated = true; + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + link->skip_fallback_on_link_loss = true; + device_service_clear.bits.AUTOMATED_TEST = 1; core_link_write_dpcd( link, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index 4f4e899e5c46..e8dda44b23cb 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -811,7 +811,7 @@ static enum link_training_result dpia_training_eq_transparent( /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4 * has to share encoders unlike DP and USBC */ - if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) { + if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->skip_fallback_on_link_loss && retries_eq)) { result = LINK_TRAINING_SUCCESS; break; } @@ -1037,7 +1037,7 @@ enum link_training_result dpia_perform_link_training( */ if (result == LINK_TRAINING_SUCCESS) { fsleep(5000); - if (!link->is_automated) + if (!link->skip_fallback_on_link_loss) result = dp_check_link_loss_status(link, <_settings); } else if (result == LINK_TRAINING_ABORT) dpia_training_abort(link, <_settings, repeater_id); From d218291579de53fad8242ad1ae732604de25b635 Mon Sep 17 00:00:00 2001 From: Chris Park Date: Fri, 1 Dec 2023 06:25:10 -0700 Subject: [PATCH 2842/7721] drm/amd/display: Update BIOS FW info table revision [Why] BIOS FW info version 3.5 is introduced to support new ASICs, but it's content is currently same as 3.4. [How] Include minor version 5 in parsing to enable support. Tested-by: Daniel Wheeler Reviewed-by: Dillon Varone Acked-by: Rodrigo Siqueira Signed-off-by: Chris Park Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 01abc2f3081a..971473c69b32 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1747,6 +1747,7 @@ static enum bp_result bios_parser_get_firmware_info( result = get_firmware_info_v3_2(bp, info); break; case 4: + case 5: result = get_firmware_info_v3_4(bp, info); break; default: From c59397eff9439bbc8b9a9835142e99ea0abf9cde Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 1 Dec 2023 06:25:11 -0700 Subject: [PATCH 2843/7721] drm/amd/display: revert removing otg toggle w/a back when no active display w/a use case: - dual display, compliance, toggling between the displays - switching between 120Hz 420 -> 144Hz 444 and vice versa - switching between 144Hz -> 60Hz TMDS or vice versa It'd typically involve TMDS in some capacity since that's the only link signal we leave the OTG running but DIO/PHY off you can hit this in cases where you have multiple displays as well it syncs with the first active OTG, so if you had OTG[0] mapped and FIFO off you'd hit it even if OTG[1] was mapped and had FIFO Tested-by: Daniel Wheeler Reviewed-by: Nicholas Kazlauskas Acked-by: Rodrigo Siqueira Signed-off-by: Charlene Liu Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 10 ++++------ .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 9e0fa01ecb79..439414ef464a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -312,13 +312,11 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { + dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; - if (all_active_disps != 0) { - dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); - dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); - } else - dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); update_dispclk = true; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c index 786b62ab8d0f..d6db9d7fced2 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c @@ -475,14 +475,14 @@ int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_QueryIPS2Support, 0); - smu_print("%s: VBIOSSMC_MSG_QueryIPS2Support return = %x\n", __func__, retv); + //smu_print("%s: VBIOSSMC_MSG_QueryIPS2Support return = %x\n", __func__, retv); return retv; } void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param) { REG_WRITE(MP1_SMN_C2PMSG_71, param); - smu_print("%s: write_ips_scratch = %x\n", __func__, param); + //smu_print("%s: write_ips_scratch = %x\n", __func__, param); } uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr) @@ -490,6 +490,6 @@ uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr) uint32_t retv; retv = REG_READ(MP1_SMN_C2PMSG_71); - smu_print("%s: dcn35_smu_read_ips_scratch = %x\n", __func__, retv); + //smu_print("%s: dcn35_smu_read_ips_scratch = %x\n", __func__, retv); return retv; } From e6ae4c47e8f8941fde115434fd8884e4e972cf6b Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 1 Dec 2023 06:25:12 -0700 Subject: [PATCH 2844/7721] drm/amd/display: Pass debug watermarks through to DCN35 DML2 [Why] The DC debug options currently do not function for dynamically adjusting our watermarks. [How] Hook them up before passing them to DML2. Also make sure we're using dc->bb_overrides since dc->debug isn't populated during dc_construct. Tested-by: Daniel Wheeler Reviewed-by: Michael Strauss Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index 39cf1ae3a3e1..e9d88f52717b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -326,6 +326,25 @@ void dcn35_update_bw_bounding_box_fpu(struct dc *dc, dcn3_5_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000.0; } + + if (dc->bb_overrides.dram_clock_change_latency_ns > 0) + dcn3_5_soc.dram_clock_change_latency_us = + dc->bb_overrides.dram_clock_change_latency_ns / 1000.0; + + if (dc->bb_overrides.sr_exit_time_ns > 0) + dcn3_5_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0; + + if (dc->bb_overrides.sr_enter_plus_exit_time_ns > 0) + dcn3_5_soc.sr_enter_plus_exit_time_us = + dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0; + + if (dc->bb_overrides.sr_exit_z8_time_ns > 0) + dcn3_5_soc.sr_exit_z8_time_us = dc->bb_overrides.sr_exit_z8_time_ns / 1000.0; + + if (dc->bb_overrides.sr_enter_plus_exit_z8_time_ns > 0) + dcn3_5_soc.sr_enter_plus_exit_z8_time_us = + dc->bb_overrides.sr_enter_plus_exit_z8_time_ns / 1000.0; + /*temp till dml2 fully work without dml1*/ dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); From 43484c4bdb6eb2f74cec61e4e7cfcb6ce8e69e2f Mon Sep 17 00:00:00 2001 From: Relja Vojvodic Date: Fri, 1 Dec 2023 06:25:13 -0700 Subject: [PATCH 2845/7721] drm/amd/display: Added delay to DPM log HW registers were being read to quickly, causing incorrect values to be logged after a clock frequency was changed Tested-by: Daniel Wheeler Reviewed-by: Martin Leung Acked-by: Rodrigo Siqueira Signed-off-by: Relja Vojvodic Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index a496930b1f9c..95c0b49b531a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -460,18 +460,24 @@ static int dcn32_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base) static void dcn32_auto_dpm_test_log(struct dc_clocks *new_clocks, struct clk_mgr_internal *clk_mgr) { - unsigned int dispclk_khz_reg = REG_READ(CLK1_CLK0_CURRENT_CNT); // DISPCLK - unsigned int dppclk_khz_reg = REG_READ(CLK1_CLK1_CURRENT_CNT); // DPPCLK - unsigned int dprefclk_khz_reg = REG_READ(CLK1_CLK2_CURRENT_CNT); // DPREFCLK - unsigned int dcfclk_khz_reg = REG_READ(CLK1_CLK3_CURRENT_CNT); // DCFCLK - unsigned int dtbclk_khz_reg = REG_READ(CLK1_CLK4_CURRENT_CNT); // DTBCLK - unsigned int fclk_khz_reg = REG_READ(CLK4_CLK0_CURRENT_CNT); // FCLK + unsigned int dispclk_khz_reg, dppclk_khz_reg, dprefclk_khz_reg, dcfclk_khz_reg, dtbclk_khz_reg, + fclk_khz_reg; + int dramclk_khz_override, fclk_khz_override, num_fclk_levels; + + msleep(5); + + dispclk_khz_reg = REG_READ(CLK1_CLK0_CURRENT_CNT); // DISPCLK + dppclk_khz_reg = REG_READ(CLK1_CLK1_CURRENT_CNT); // DPPCLK + dprefclk_khz_reg = REG_READ(CLK1_CLK2_CURRENT_CNT); // DPREFCLK + dcfclk_khz_reg = REG_READ(CLK1_CLK3_CURRENT_CNT); // DCFCLK + dtbclk_khz_reg = REG_READ(CLK1_CLK4_CURRENT_CNT); // DTBCLK + fclk_khz_reg = REG_READ(CLK4_CLK0_CURRENT_CNT); // FCLK // Overrides for these clocks in case there is no p_state change support - int dramclk_khz_override = new_clocks->dramclk_khz; - int fclk_khz_override = new_clocks->fclk_khz; + dramclk_khz_override = new_clocks->dramclk_khz; + fclk_khz_override = new_clocks->fclk_khz; - int num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1; + num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1; if (!new_clocks->p_state_change_support) { dramclk_khz_override = clk_mgr->base.bw_params->max_memclk_mhz * 1000; @@ -707,7 +713,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, dmcu->funcs->set_psr_wait_loop(dmcu, clk_mgr_base->clks.dispclk_khz / 1000 / 7); - if (dc->config.enable_auto_dpm_test_logs) { + if (dc->config.enable_auto_dpm_test_logs && safe_to_lower) { dcn32_auto_dpm_test_log(new_clocks, clk_mgr); } } From d3586c707b8f64cbe5b778cfe59ac4b8a4be0d3b Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 1 Dec 2023 06:25:14 -0700 Subject: [PATCH 2846/7721] drm/amd/display: keep domain24 power on if eDP not exist This is w/a: we need to keep domain 24 power up in driver side, and let dmubfw handle it for S0i3. For last display unplugged, if OTG in PG, no interrupt call back coming. Tested-by: Daniel Wheeler Reviewed-by: Chris Park Acked-by: Rodrigo Siqueira Signed-off-by: Charlene Liu Signed-off-by: Alex Deucher --- .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 39260371beb9..09498aa92096 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -979,6 +979,8 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, bool hpo_frl_stream_enc_acquired = false; bool hpo_dp_stream_enc_acquired = false; int i = 0, j = 0; + int edp_num = 0; + struct dc_link *edp_links[MAX_NUM_EDP] = { NULL }; memset(update_state, 0, sizeof(struct pg_block_update)); @@ -1019,10 +1021,24 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, if (pipe_ctx->stream_res.opp) update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false; - - if (pipe_ctx->stream_res.tg) - update_state->pg_pipe_res_update[PG_OPTC][pipe_ctx->stream_res.tg->inst] = false; } + /*domain24 controls all the otg, mpc, opp, as long as one otg is still up, avoid enabling OTG PG*/ + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + if (tg && tg->funcs->is_tg_enabled(tg)) { + update_state->pg_pipe_res_update[PG_OPTC][i] = false; + break; + } + } + + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num == 0 || + ((!edp_links[0] || !edp_links[0]->edp_sink_present) && + (!edp_links[1] || !edp_links[1]->edp_sink_present))) { + /*eDP not exist on this config, keep Domain24 power on, for S0i3, this will be handled in dmubfw*/ + update_state->pg_pipe_res_update[PG_OPTC][0] = false; + } + } void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, @@ -1156,8 +1172,10 @@ void dcn35_block_power_control(struct dc *dc, pg_cntl->funcs->dwb_pg_control(pg_cntl, power_on); } + /*this will need all the clients to unregister optc interruts let dmubfw handle this*/ if (pg_cntl->funcs->plane_otg_pg_control) pg_cntl->funcs->plane_otg_pg_control(pg_cntl, power_on); + } void dcn35_root_clock_control(struct dc *dc, From 2ce156482a6fef349d2eba98e5070c412d3af662 Mon Sep 17 00:00:00 2001 From: Nicholas Susanto Date: Fri, 1 Dec 2023 06:25:15 -0700 Subject: [PATCH 2847/7721] drm/amd/display: Fix disable_otg_wa logic [Why] When switching to another HDMI mode, we are unnecesarilly disabling/enabling FIFO causing both HPO and DIG registers to be set at the same time when only HPO is supposed to be set. This can lead to a system hang the next time we change refresh rates as there are cases when we don't disable OTG/FIFO but FIFO is enabled when it isn't supposed to be. [How] Removing the enable/disable FIFO entirely. Tested-by: Daniel Wheeler Reviewed-by: Nicholas Kazlauskas Acked-by: Rodrigo Siqueira Signed-off-by: Nicholas Susanto Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 439414ef464a..8d4c0b209872 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -127,21 +127,13 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state * continue; if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || !pipe->stream->link_enc)) { - struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; - if (disable) { - if (stream_enc && stream_enc->funcs->disable_fifo) - pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); - if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); reset_sync_context_for_pipe(dc, context, i); } else { pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); - - if (stream_enc && stream_enc->funcs->enable_fifo) - pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); } } } From 21afc872fbc29cd68cfde816d1df4d55848c3f61 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Fri, 1 Dec 2023 06:25:16 -0700 Subject: [PATCH 2848/7721] drm/amd/display: Add monitor patch for specific eDP [WHY] Some eDP panels's ext caps don't write initial value cause the value of dpcd_addr(0x317) is random. It means that sometimes the eDP will clarify it is OLED, miniLED...etc cause the backlight control interface is incorrect. [HOW] Add a new panel patch to remove sink ext caps(HDR,OLED...etc) Tested-by: Daniel Wheeler Reviewed-by: Sun peng Li Acked-by: Rodrigo Siqueira Signed-off-by: Ivan Lipski Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index b4696ec621c4..eaf8d9f48244 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -64,6 +64,12 @@ static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps *edid_caps) DRM_DEBUG_DRIVER("Disabling FAMS on monitor with panel id %X\n", panel_id); edid_caps->panel_patch.disable_fams = true; break; + /* Workaround for some monitors that do not clear DPCD 0x317 if FreeSync is unsupported */ + case drm_edid_encode_panel_id('A', 'U', 'O', 0xA7AB): + case drm_edid_encode_panel_id('A', 'U', 'O', 0xE69B): + DRM_DEBUG_DRIVER("Clearing DPCD 0x317 on monitor with panel id %X\n", panel_id); + edid_caps->panel_patch.remove_sink_ext_caps = true; + break; default: return; } From cfa96a14e89d8341a7308acc4c6168991d4fdac0 Mon Sep 17 00:00:00 2001 From: Yihan Zhu Date: Fri, 1 Dec 2023 06:25:17 -0700 Subject: [PATCH 2849/7721] drm/amd/display: add MPC MCM 1D LUT clock gating programming Missing clock gating programming blocks memory power on from boot up. Tested-by: Daniel Wheeler Reviewed-by: Chris Park Acked-by: Rodrigo Siqueira Signed-off-by: Yihan Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c | 3 ++- drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 994b21ed272f..e789e654c387 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -71,12 +71,13 @@ void mpc32_power_on_blnd_lut( { struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); + REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, MPCC_MCM_1DLUT_MEM_PWR_DIS, power_on); + if (mpc->ctx->dc->debug.enable_mem_low_power.bits.cm) { if (power_on) { REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0); REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5); } else if (!mpc->ctx->dc->debug.disable_mem_low_power) { - ASSERT(false); /* TODO: change to mpc * dpp_base->ctx->dc->optimized_required = true; * dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 1a0ed1c7e2d4..13324422ff50 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -736,7 +736,7 @@ static const struct dc_debug_options debug_defaults_drv = { .i2c = true, .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled .dscl = true, - .cm = false, + .cm = true, .mpc = true, .optc = true, .vpg = true, From abd26a3252cbd1a3ae4e46d37596d176fe50b41a Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Fri, 1 Dec 2023 06:25:18 -0700 Subject: [PATCH 2850/7721] drm/amd/display: Add dml2 copy functions Add function to handle deep copying dml2 context. Tested-by: Daniel Wheeler Reviewed-by: Chaitanya Dhere Acked-by: Rodrigo Siqueira Signed-off-by: Dillon Varone Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 15 +++------- .../drm/amd/display/dc/dml2/dml2_wrapper.c | 29 ++++++++++++++++++- .../drm/amd/display/dc/dml2/dml2_wrapper.h | 4 +++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index eab713c0da0d..102d00a9a24f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2258,23 +2258,16 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx) { int i, j; struct dc_state *new_ctx = kvmalloc(sizeof(struct dc_state), GFP_KERNEL); -#ifdef CONFIG_DRM_AMD_DC_FP - struct dml2_context *dml2 = NULL; -#endif if (!new_ctx) return NULL; memcpy(new_ctx, src_ctx, sizeof(struct dc_state)); #ifdef CONFIG_DRM_AMD_DC_FP - if (new_ctx->bw_ctx.dml2) { - dml2 = kzalloc(sizeof(struct dml2_context), GFP_KERNEL); - if (!dml2) - return NULL; - - memcpy(dml2, src_ctx->bw_ctx.dml2, sizeof(struct dml2_context)); - new_ctx->bw_ctx.dml2 = dml2; - } + if (new_ctx->bw_ctx.dml2 && !dml2_create_copy(&new_ctx->bw_ctx.dml2, src_ctx->bw_ctx.dml2)) { + dc_release_state(new_ctx); + return NULL; + } #endif for (i = 0; i < MAX_PIPES; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c index 8f231418870f..9d354fde6908 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c @@ -691,10 +691,15 @@ bool dml2_validate(const struct dc *in_dc, struct dc_state *context, bool fast_v return out; } +static inline struct dml2_context *dml2_allocate_memory(void) +{ + return (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL); +} + bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) { // Allocate Mode Lib Ctx - *dml2 = (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL); + *dml2 = dml2_allocate_memory(); if (!(*dml2)) return false; @@ -745,3 +750,25 @@ void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2, *fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0]; *dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0]; } + +void dml2_copy(struct dml2_context *dst_dml2, + struct dml2_context *src_dml2) +{ + /* copy Mode Lib Ctx */ + memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context)); +} + +bool dml2_create_copy(struct dml2_context **dst_dml2, + struct dml2_context *src_dml2) +{ + /* Allocate Mode Lib Ctx */ + *dst_dml2 = dml2_allocate_memory(); + + if (!(*dst_dml2)) + return false; + + /* copy Mode Lib Ctx */ + dml2_copy(*dst_dml2, src_dml2); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h index fe15baa4bf09..0de6886969c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h @@ -191,6 +191,10 @@ bool dml2_create(const struct dc *in_dc, struct dml2_context **dml2); void dml2_destroy(struct dml2_context *dml2); +void dml2_copy(struct dml2_context *dst_dml2, + struct dml2_context *src_dml2); +bool dml2_create_copy(struct dml2_context **dst_dml2, + struct dml2_context *src_dml2); /* * dml2_validate - Determines if a display configuration is supported or not. From dd5c6362ddcd8bdb07704faff8648593885ecfa1 Mon Sep 17 00:00:00 2001 From: Dennis Chan Date: Fri, 1 Dec 2023 06:25:19 -0700 Subject: [PATCH 2851/7721] drm/amd/display: Fix Replay Desync Error IRQ handler In previous case, Replay didn't identify the IRQ type, This commit fixes the issues for the interrupt. Tested-by: Daniel Wheeler Reviewed-by: Robin Chen Acked-by: Rodrigo Siqueira Signed-off-by: Dennis Chan Signed-off-by: Alex Deucher --- .../display/dc/link/protocols/link_dp_irq_handler.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index ae271c830c9a..ba69874be5a4 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -190,9 +190,6 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) /*AMD Replay version reuse DP_PSR_ERROR_STATUS for REPLAY_ERROR status.*/ union psr_error_status replay_error_status; - if (link->replay_settings.config.force_disable_desync_error_check) - return; - if (!link->replay_settings.replay_feature_enabled) return; @@ -210,9 +207,6 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) &replay_error_status.raw, sizeof(replay_error_status.raw)); - if (replay_configuration.bits.DESYNC_ERROR_STATUS) - link->replay_settings.config.received_desync_error_hpd = 1; - link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR = replay_error_status.bits.LINK_CRC_ERROR; link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR = @@ -225,6 +219,12 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR) { bool allow_active; + if (link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR) + link->replay_settings.config.received_desync_error_hpd = 1; + + if (link->replay_settings.config.force_disable_desync_error_check) + return; + /* Acknowledge and clear configuration bits */ dm_helpers_dp_write_dpcd( link->ctx, From 08a32addf17317b9fac55be9b31275cbf6e41fb7 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 1 Dec 2023 06:25:20 -0700 Subject: [PATCH 2852/7721] drm/amd/display: add support for DTO genarated dscclk Current implementation will choose to use refclk as dscclk. This is not recommended by hardware team as refclk is a fixed value which could cause unnecessary power consumption or it could be not enough for large DSC timings. So we are adding new interfaces so we could switch to use dynamically generated DSCCLK by DTO. So DSCCLK is programmable based on current pixel clock and dispclk. Tested-by: Daniel Wheeler Reviewed-by: Chaitanya Dhere Acked-by: Rodrigo Siqueira Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 25 +++++++++++++++++ drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 4 +++ .../gpu/drm/amd/display/dc/link/link_dpms.c | 27 ++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 5f7f474ef51c..5c323718ec90 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -989,9 +989,22 @@ static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) { struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; struct pipe_ctx *odm_pipe; int opp_cnt = 1; + struct dccg *dccg = dc->res_pool->dccg; + /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN + * register access hung. When DSCCLk is based on refclk, DSCCLk is always a + * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is + * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings + * with DSC such as 480p60Hz, the dispclk could be low enough to trigger + * this problem. We are implementing a workaround here to keep using dscclk + * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e + * 48Mhz) pixel clock to avoid hitting this problem. + */ + bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) && + stream->timing.pix_clk_100hz > 480000; ASSERT(dsc); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) @@ -1014,12 +1027,16 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, dsc->inst); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; ASSERT(odm_dsc); odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); } dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.pic_width *= opp_cnt; @@ -1039,9 +1056,13 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) OPTC_DSC_DISABLED, 0, 0); /* disable DSC block */ + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { ASSERT(odm_pipe->stream_res.dsc); + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); } } @@ -1124,6 +1145,10 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx * if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe->stream_res.dsc) { struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; + struct dccg *dccg = dc->res_pool->dccg; + + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, dsc->inst); /* disconnect DSC block from stream */ dsc->funcs->dsc_disconnect(dsc); } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index ce2f0c0e82bd..6b44557fcb1a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -201,6 +201,10 @@ struct dccg_funcs { struct dccg *dccg, enum streamclk_source src, uint32_t otg_inst); + void (*set_dto_dscclk)( + struct dccg *dccg, + uint32_t dsc_inst); + void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index b16b2e14312e..5fe8b4871c77 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -776,10 +776,26 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) */ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) { + /* TODO: Move this to HWSS as this is hardware programming sequence not a + * link layer sequence + */ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; struct pipe_ctx *odm_pipe; int opp_cnt = 1; + struct dccg *dccg = dc->res_pool->dccg; + /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN + * register access hung. When DSCCLk is based on refclk, DSCCLk is always a + * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is + * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings + * with DSC such as 480p60Hz, the dispclk could be low enough to trigger + * this problem. We are implementing a workaround here to keep using dscclk + * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e + * 48Mhz) pixel clock to avoid hitting this problem. + */ + bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) && + stream->timing.pix_clk_100hz > 480000; DC_LOGGER_INIT(dsc->ctx->logger); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) @@ -802,11 +818,15 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, dsc->inst); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); } dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.pic_width *= opp_cnt; @@ -856,9 +876,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) } /* disable DSC block */ + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } } } From b6411638c026fde33046f5515a5a7d37af1da146 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:21 -0700 Subject: [PATCH 2853/7721] drm/amd/display: Avoid virtual stream encoder if not explicitly requested Virtual stream encoder should not be a free match for thunderbolt or usbc, and thus should be avoided. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Acked-by: Rodrigo Siqueira Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index af1b31f4e69a..d08d10969251 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -1250,7 +1250,10 @@ struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( /* Store first available for MST second display * in daisy chain use case */ - j = i; + + if (pool->stream_enc[i]->id != ENGINE_ID_VIRTUAL) + j = i; + if (link->ep_type == DISPLAY_ENDPOINT_PHY && pool->stream_enc[i]->id == link->link_enc->preferred_engine) return pool->stream_enc[i]; From 80af8859b46d1fa386871f71bad95db9ff50ad62 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:22 -0700 Subject: [PATCH 2854/7721] drm/amd/display: Skip entire amdgpu_dm build if !CONFIG_DRM_AMD_DC [WHY] Previously this only excluded build for a few amdgpu_dm binaries which makes no sense. [HOW] Wrap the entire Makefile in "ifneq ($(CONFIG_DRM_AMD_DC),)" Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/Makefile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 8bf94920d23e..063205ecb137 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -25,22 +25,24 @@ +ifneq ($(CONFIG_DRM_AMD_DC),) AMDGPUDM = \ amdgpu_dm.o \ amdgpu_dm_plane.o \ amdgpu_dm_crtc.o \ amdgpu_dm_irq.o \ amdgpu_dm_mst_types.o \ - amdgpu_dm_color.o + amdgpu_dm_color.o \ + amdgpu_dm_services.o \ + amdgpu_dm_helpers.o \ + amdgpu_dm_pp_smu.o \ + amdgpu_dm_psr.o \ + amdgpu_dm_replay.o ifdef CONFIG_DRM_AMD_DC_FP AMDGPUDM += dc_fpu.o endif -ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o amdgpu_dm_psr.o amdgpu_dm_replay.o -endif - AMDGPUDM += amdgpu_dm_hdcp.o ifneq ($(CONFIG_DEBUG_FS),) @@ -52,3 +54,4 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM)) AMD_DISPLAY_FILES += $(AMDGPU_DM) +endif From 198891fd2902fba155fe23f8ad27c9cf8cd8286d Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:23 -0700 Subject: [PATCH 2855/7721] drm/amd/display: Create one virtual connector in DC [WHAT] Prepare a virtual connector for writeback. Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 +++++++++-- .../gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index bc7b8a325353..9b791e3f7e33 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1675,6 +1675,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0]; init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0]; + /* Enable DWB for tested platforms only */ + if (adev->ip_versions[DCE_HWIP][0] >= IP_VERSION(3, 0, 0)) + init_data.num_virtual_links = 1; + INIT_LIST_HEAD(&adev->dm.da_list); retrieve_dmi_info(&adev->dm); @@ -4465,6 +4469,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) continue; } + link = dc_get_link_at_index(dm->dc, i); + + if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) + continue; + aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL); if (!aconnector) goto fail; @@ -4483,8 +4492,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } - link = dc_get_link_at_index(dm->dc, i); - if (!dc_link_detect_connection_type(link, &new_connection_type)) DRM_ERROR("KMS: Failed to detect connector\n"); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 97798cee876e..5d62805f3bdf 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -96,7 +96,8 @@ static void enable_memory_low_power(struct dc *dc) if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { // Power down VPGs for (i = 0; i < dc->res_pool->stream_enc_count; i++) - dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); + if (dc->res_pool->stream_enc[i]->vpg) + dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); #if defined(CONFIG_DRM_AMD_DC_FP) for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); From dfc03588cf8ce2af8ef810cd226dc98ee4fbac38 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:24 -0700 Subject: [PATCH 2856/7721] drm/amd/display: Initialize writeback connector [WHAT] Create a drm_writeback_connector when connector signal equals SIGNAL_TYPE_VIRTUAL. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/Makefile | 3 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 20 +- .../drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c | 209 ++++++++++++++++++ .../drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h | 35 +++ 4 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 063205ecb137..ab2a97e354da 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -37,7 +37,8 @@ AMDGPUDM = \ amdgpu_dm_helpers.o \ amdgpu_dm_pp_smu.o \ amdgpu_dm_psr.o \ - amdgpu_dm_replay.o + amdgpu_dm_replay.o \ + amdgpu_dm_wb.o ifdef CONFIG_DRM_AMD_DC_FP AMDGPUDM += dc_fpu.o diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 9b791e3f7e33..51a873658535 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -54,6 +54,7 @@ #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_hdcp.h" #include +#include "amdgpu_dm_wb.h" #include "amdgpu_pm.h" #include "amdgpu_atombios.h" @@ -4471,8 +4472,25 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) link = dc_get_link_at_index(dm->dc, i); - if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) + if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) { + struct drm_writeback_connector *wbcon = kzalloc(sizeof(*wbcon), GFP_KERNEL); + + if (!wbcon) { + DRM_ERROR("KMS: Failed to allocate writeback connector\n"); + continue; + } + + if (amdgpu_dm_wb_connector_init(dm, wbcon)) { + DRM_ERROR("KMS: Failed to initialize writeback connector\n"); + kfree(wbcon); + continue; + } + + link->psr_settings.psr_feature_enabled = false; + link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + continue; + } aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL); if (!aconnector) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c new file mode 100644 index 000000000000..74e656696d8e --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services_types.h" + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_wb.h" +#include "amdgpu_display.h" + +#include +#include + +static const u32 amdgpu_dm_wb_formats[] = { + DRM_FORMAT_XRGB2101010, +}; + +static int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_framebuffer *fb; + const struct drm_display_mode *mode = &crtc_state->mode; + bool found = false; + uint8_t i; + + if (!conn_state->writeback_job || !conn_state->writeback_job->fb) + return 0; + + fb = conn_state->writeback_job->fb; + if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + for (i = 0; i < sizeof(amdgpu_dm_wb_formats) / sizeof(u32); i++) { + if (fb->format->format == amdgpu_dm_wb_formats[i]) + found = true; + } + + if (!found) { + DRM_DEBUG_KMS("Invalid pixel format %p4cc\n", + &fb->format->format); + return -EINVAL; + } + + return 0; +} + + +static int amdgpu_dm_wb_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + return drm_add_modes_noedid(connector, dev->mode_config.max_width, + dev->mode_config.max_height); +} + +static int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb_connector, + struct drm_writeback_job *job) +{ + struct amdgpu_framebuffer *afb; + struct drm_gem_object *obj; + struct amdgpu_device *adev; + struct amdgpu_bo *rbo; + uint32_t domain; + int r; + + if (!job->fb) { + DRM_DEBUG_KMS("No FB bound\n"); + return 0; + } + + afb = to_amdgpu_framebuffer(job->fb); + obj = job->fb->obj[0]; + rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); + + r = amdgpu_bo_reserve(rbo, true); + if (r) { + dev_err(adev->dev, "fail to reserve bo (%d)\n", r); + return r; + } + + r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1); + if (r) { + dev_err(adev->dev, "reserving fence slot failed (%d)\n", r); + goto error_unlock; + } + + domain = amdgpu_display_supported_domains(adev, rbo->flags); + + r = amdgpu_bo_pin(rbo, domain); + if (unlikely(r != 0)) { + if (r != -ERESTARTSYS) + DRM_ERROR("Failed to pin framebuffer with error %d\n", r); + goto error_unlock; + } + + r = amdgpu_ttm_alloc_gart(&rbo->tbo); + if (unlikely(r != 0)) { + DRM_ERROR("%p bind failed\n", rbo); + goto error_unpin; + } + + amdgpu_bo_unreserve(rbo); + + afb->address = amdgpu_bo_gpu_offset(rbo); + + amdgpu_bo_ref(rbo); + + return 0; + +error_unpin: + amdgpu_bo_unpin(rbo); + +error_unlock: + amdgpu_bo_unreserve(rbo); + return r; +} + +static void amdgpu_dm_wb_cleanup_job(struct drm_writeback_connector *connector, + struct drm_writeback_job *job) +{ + struct amdgpu_bo *rbo; + int r; + + if (!job->fb) + return; + + rbo = gem_to_amdgpu_bo(job->fb->obj[0]); + r = amdgpu_bo_reserve(rbo, false); + if (unlikely(r)) { + DRM_ERROR("failed to reserve rbo before unpin\n"); + return; + } + + amdgpu_bo_unpin(rbo); + amdgpu_bo_unreserve(rbo); + amdgpu_bo_unref(&rbo); +} + +static const struct drm_encoder_helper_funcs amdgpu_dm_wb_encoder_helper_funcs = { + .atomic_check = amdgpu_dm_wb_encoder_atomic_check, +}; + +static const struct drm_connector_funcs amdgpu_dm_wb_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = amdgpu_dm_connector_funcs_reset, + .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_connector_helper_funcs amdgpu_dm_wb_conn_helper_funcs = { + .get_modes = amdgpu_dm_wb_connector_get_modes, + .prepare_writeback_job = amdgpu_dm_wb_prepare_job, + .cleanup_writeback_job = amdgpu_dm_wb_cleanup_job, +}; + +int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, + struct drm_writeback_connector *wbcon) +{ + int res = 0; + + drm_connector_helper_add(&wbcon->base, &amdgpu_dm_wb_conn_helper_funcs); + + res = drm_writeback_connector_init(&dm->adev->ddev, wbcon, + &amdgpu_dm_wb_connector_funcs, + &amdgpu_dm_wb_encoder_helper_funcs, + amdgpu_dm_wb_formats, + ARRAY_SIZE(amdgpu_dm_wb_formats), + amdgpu_dm_get_encoder_crtc_mask(dm->adev)); + + if (res) + return res; + /* + * Some of the properties below require access to state, like bpc. + * Allocate some default initial connector state with our reset helper. + */ + if (wbcon->base.funcs->reset) + wbcon->base.funcs->reset(&wbcon->base); + + return 0; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h new file mode 100644 index 000000000000..0bc9df7e7ee1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __AMDGPU_DM_WB_H__ +#define __AMDGPU_DM_WB_H__ + +#include + +int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, + struct drm_writeback_connector *wbcon); + +#endif From 7db7ade270ae8e177cc8bd09753745e7c2dc92e7 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:25 -0700 Subject: [PATCH 2857/7721] drm/amd/display: Skip writeback connector when we get amdgpu_dm_connector [WHY] Writeback connectors are based on a different object: drm_writeback_connector, and are therefore different from amdgpu_dm_connector. We need to be careful to ensure code designed for amdgpu_dm_connector doesn't inadvertently try to operate on a drm_writeback_connector. [HOW] Skip them when connector type is DRM_MODE_CONNECTOR_WRITEBACK. Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 62 +++++++++++++++++-- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 3 + .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 22 +++++-- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 51a873658535..1d9a10384f93 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -728,6 +728,10 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (link && aconnector->dc_link == link) { if (notify->type == DMUB_NOTIFICATION_HPD) @@ -951,6 +955,10 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->audio_inst != port) continue; @@ -2257,6 +2265,10 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->dc_link->type == dc_connection_mst_branch && aconnector->mst_mgr.aux) { @@ -2385,6 +2397,10 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->dc_link->type != dc_connection_mst_branch || aconnector->mst_root) @@ -2906,6 +2922,10 @@ static int dm_resume(void *handle) /* Do detection*/ drm_connector_list_iter_begin(ddev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->dc_link) @@ -3479,6 +3499,9 @@ static void register_hpd_handlers(struct amdgpu_device *adev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); dc_link = aconnector->dc_link; @@ -5516,10 +5539,13 @@ static void fill_stream_properties_from_drm_display_mode( { struct dc_crtc_timing *timing_out = &stream->timing; const struct drm_display_info *info = &connector->display_info; - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *aconnector = NULL; struct hdmi_vendor_infoframe hv_frame; struct hdmi_avi_infoframe avi_frame; + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + aconnector = to_amdgpu_dm_connector(connector); + memset(&hv_frame, 0, sizeof(hv_frame)); memset(&avi_frame, 0, sizeof(avi_frame)); @@ -6964,6 +6990,9 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, for_each_new_connector_in_state(state, connector, new_con_state, i) { + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->mst_output_port) @@ -8523,6 +8552,9 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev, if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + notify: aconnector = to_amdgpu_dm_connector(connector); @@ -8556,6 +8588,9 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev, if (!status) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); mutex_lock(&adev->dm.audio_lock); @@ -8779,7 +8814,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *aconnector; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); if (!adev->dm.hdcp_workqueue) continue; @@ -9173,10 +9213,15 @@ static int dm_force_atomic_commit(struct drm_connector *connector) void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector) { - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *aconnector; struct amdgpu_crtc *disconnected_acrtc; struct dm_crtc_state *acrtc_state; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return; + + aconnector = to_amdgpu_dm_connector(connector); + if (!aconnector->dc_sink || !connector->state || !connector->encoder) return; @@ -9253,12 +9298,16 @@ static void get_freesync_config_for_crtc( struct dm_connector_state *new_con_state) { struct mod_freesync_config config = {0}; - struct amdgpu_dm_connector *aconnector = - to_amdgpu_dm_connector(new_con_state->base.connector); + struct amdgpu_dm_connector *aconnector; struct drm_display_mode *mode = &new_crtc_state->base.mode; int vrefresh = drm_mode_vrefresh(mode); bool fs_vid_mode = false; + if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return; + + aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); + new_crtc_state->vrr_supported = new_con_state->freesync_capable && vrefresh >= aconnector->min_vfreq && vrefresh <= aconnector->max_vfreq; @@ -10088,6 +10137,9 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm if (conn_state->crtc != crtc) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->mst_output_port || !aconnector->mst_root) aconnector = NULL; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 52ecfa746b54..f936a35fa9eb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -326,6 +326,9 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) if (!connector->state || connector->state->crtc != crtc) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconn = to_amdgpu_dm_connector(connector); break; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 51467f132c26..58b880acb087 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -894,10 +894,15 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *amdgpu_dm_connector; + const struct dc_link *dc_link; - const struct dc_link *dc_link = amdgpu_dm_connector->dc_link; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + + dc_link = amdgpu_dm_connector->dc_link; if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { dc_interrupt_set(adev->dm.dc, @@ -930,9 +935,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - const struct dc_link *dc_link = amdgpu_dm_connector->dc_link; + struct amdgpu_dm_connector *amdgpu_dm_connector; + const struct dc_link *dc_link; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + dc_link = amdgpu_dm_connector->dc_link; if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { dc_interrupt_set(adev->dm.dc, From 748b091d641638e68330b1b24195eaba9aadf997 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:26 -0700 Subject: [PATCH 2858/7721] drm/amd/display: Return drm_connector from find_first_crtc_matching_connector [WHY] We will be dealing with two types of connector: amdgpu_dm_connector and drm_writeback_connector. [HOW] We want to find both and then cast to the appriopriate type afterwards. Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++++--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1d9a10384f93..5c89a043ac10 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2664,7 +2664,7 @@ static int dm_suspend(void *handle) return 0; } -struct amdgpu_dm_connector * +struct drm_connector * amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc) { @@ -2677,7 +2677,7 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, crtc_from_state = new_con_state->crtc; if (crtc_from_state == crtc) - return to_amdgpu_dm_connector(connector); + return connector; } return NULL; @@ -9407,6 +9407,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * update changed items */ struct amdgpu_crtc *acrtc = NULL; + struct drm_connector *connector = NULL; struct amdgpu_dm_connector *aconnector = NULL; struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL; struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL; @@ -9416,7 +9417,8 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); acrtc = to_amdgpu_crtc(crtc); - aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); + connector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); + aconnector = to_amdgpu_dm_connector(connector); /* TODO This hack should go away */ if (aconnector && enable) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 3d480be802cb..3710f4d0f2cb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -834,7 +834,7 @@ struct dc_stream_state * int dm_atomic_get_state(struct drm_atomic_state *state, struct dm_atomic_state **dm_state); -struct amdgpu_dm_connector * +struct drm_connector * amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index b599efda3b19..19ae5587dd5a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1500,14 +1500,16 @@ int pre_validate_dsc(struct drm_atomic_state *state, int ind = find_crtc_index_in_state_by_stream(state, stream); if (ind >= 0) { + struct drm_connector *connector; struct amdgpu_dm_connector *aconnector; struct drm_connector_state *drm_new_conn_state; struct dm_connector_state *dm_new_conn_state; struct dm_crtc_state *dm_old_crtc_state; - aconnector = + connector = amdgpu_dm_find_first_crtc_matching_connector(state, state->crtcs[ind].ptr); + aconnector = to_amdgpu_dm_connector(connector); drm_new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base); From 3e094a2875260543ca74838decc0c995d3765096 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:27 -0700 Subject: [PATCH 2859/7721] drm/amd/display: Use drm_connector in create_stream_for_sink [WHAT] We need to use this function for both amdgpu_dm_connectors and drm_writeback_connectors. Modify it to operate on a drm_connector as a common base. Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5c89a043ac10..46477192265e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5558,6 +5558,7 @@ static void fill_stream_properties_from_drm_display_mode( && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if (drm_mode_is_420_also(info, mode_in) + && aconnector && aconnector->force_yuv420_output) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) @@ -5593,7 +5594,7 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->hdmi_vic = hv_frame.vic; } - if (is_freesync_video_mode(mode_in, aconnector)) { + if (aconnector && is_freesync_video_mode(mode_in, aconnector)) { timing_out->h_addressable = mode_in->hdisplay; timing_out->h_total = mode_in->htotal; timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start; @@ -6070,14 +6071,14 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, } static struct dc_stream_state * -create_stream_for_sink(struct amdgpu_dm_connector *aconnector, +create_stream_for_sink(struct drm_connector *connector, const struct drm_display_mode *drm_mode, const struct dm_connector_state *dm_state, const struct dc_stream_state *old_stream, int requested_bpc) { + struct amdgpu_dm_connector *aconnector = NULL; struct drm_display_mode *preferred_mode = NULL; - struct drm_connector *drm_connector; const struct drm_connector_state *con_state = &dm_state->base; struct dc_stream_state *stream = NULL; struct drm_display_mode mode; @@ -6096,20 +6097,22 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_mode_init(&mode, drm_mode); memset(&saved_mode, 0, sizeof(saved_mode)); - if (aconnector == NULL) { - DRM_ERROR("aconnector is NULL!\n"); + if (connector == NULL) { + DRM_ERROR("connector is NULL!\n"); return stream; } - drm_connector = &aconnector->base; - - if (!aconnector->dc_sink) { - sink = create_fake_sink(aconnector); - if (!sink) - return stream; - } else { - sink = aconnector->dc_sink; - dc_sink_retain(sink); + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { + aconnector = NULL; + aconnector = to_amdgpu_dm_connector(connector); + if (!aconnector->dc_sink) { + sink = create_fake_sink(aconnector); + if (!sink) + return stream; + } else { + sink = aconnector->dc_sink; + dc_sink_retain(sink); + } } stream = dc_create_stream_for_sink(sink); @@ -6119,12 +6122,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, goto finish; } + /* We leave this NULL for writeback connectors */ stream->dm_stream_context = aconnector; stream->timing.flags.LTE_340MCSC_SCRAMBLE = - drm_connector->display_info.hdmi.scdc.scrambling.low_rates; + connector->display_info.hdmi.scdc.scrambling.low_rates; - list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { + list_for_each_entry(preferred_mode, &connector->modes, head) { /* Search for preferred mode */ if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) { native_mode_found = true; @@ -6133,7 +6137,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, } if (!native_mode_found) preferred_mode = list_first_entry_or_null( - &aconnector->base.modes, + &connector->modes, struct drm_display_mode, head); @@ -6147,7 +6151,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, * and the modelist may not be filled in time. */ DRM_DEBUG_DRIVER("No preferred mode found\n"); - } else { + } else if (aconnector) { recalculate_timing = is_freesync_video_mode(&mode, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); @@ -6170,13 +6174,17 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode( - stream, &mode, &aconnector->base, con_state, NULL, + stream, &mode, connector, con_state, NULL, requested_bpc); else fill_stream_properties_from_drm_display_mode( - stream, &mode, &aconnector->base, con_state, old_stream, + stream, &mode, connector, con_state, old_stream, requested_bpc); + /* The rest isn't needed for writeback connectors */ + if (!aconnector) + goto finish; + if (aconnector->timing_changed) { drm_dbg(aconnector->base.dev, "overriding timing for automated test, bpc %d, changing to %d\n", @@ -6194,7 +6202,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, fill_audio_info( &stream->audio_info, - drm_connector, + connector, sink); update_stream_signal(stream, sink); @@ -6662,7 +6670,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, enum dc_status dc_result = DC_OK; do { - stream = create_stream_for_sink(aconnector, drm_mode, + stream = create_stream_for_sink(connector, drm_mode, dm_state, old_stream, requested_bpc); if (stream == NULL) { @@ -9418,15 +9426,16 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); acrtc = to_amdgpu_crtc(crtc); connector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); - aconnector = to_amdgpu_dm_connector(connector); + if (connector && connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + aconnector = to_amdgpu_dm_connector(connector); /* TODO This hack should go away */ - if (aconnector && enable) { + if (connector && enable) { /* Make sure fake sink is created in plug-in scenario */ drm_new_conn_state = drm_atomic_get_new_connector_state(state, - &aconnector->base); + connector); drm_old_conn_state = drm_atomic_get_old_connector_state(state, - &aconnector->base); + connector); if (IS_ERR(drm_new_conn_state)) { ret = PTR_ERR_OR_ZERO(drm_new_conn_state); @@ -9573,7 +9582,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * added MST connectors not found in existing crtc_state in the chained mode * TODO: need to dig out the root cause of that */ - if (!aconnector) + if (!connector) goto skip_modeset; if (modereset_required(new_crtc_state)) @@ -9616,7 +9625,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * We want to do dc stream updates that do not require a * full modeset below. */ - if (!(enable && aconnector && new_crtc_state->active)) + if (!(enable && connector && new_crtc_state->active)) return 0; /* * Given above conditions, the dc state cannot be NULL because: From dbf5d3d02987faa0eec3710dd687cd912362d7b5 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:28 -0700 Subject: [PATCH 2860/7721] drm/amd/display: Check writeback connectors in create_validate_stream_for_sink [WHY & HOW] This is to check connector type to avoid unhandled null pointer for writeback connectors. Tested-by: Daniel Wheeler Fixes: 60e034f28600 ("drm/amd/display: Revert "drm/amd/display: Use drm_connector in create_validate_stream_for_sink"") Signed-off-by: Alex Hung Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 46477192265e..315a747f9750 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6678,6 +6678,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, break; } + if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return stream; + dc_result = dc_validate_stream(adev->dm.dc, stream); if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream); @@ -9426,7 +9429,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); acrtc = to_amdgpu_crtc(crtc); connector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); - if (connector && connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + if (connector) aconnector = to_amdgpu_dm_connector(connector); /* TODO This hack should go away */ From ff73d4cdde18bc4607ff10c53351715ee1164be0 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:29 -0700 Subject: [PATCH 2861/7721] drm/amd/display: Create amdgpu_dm_wb_connector [WHY] We need to track the dc_link and it would get confusing if re-using the amdgpu_dm_connector. [HOW] Creating new amdgpu_dm_wb_connector. Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +++-- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 8 ++++++++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c | 16 +++++++++++----- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h | 3 ++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 315a747f9750..0f41328510c2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4496,14 +4496,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) link = dc_get_link_at_index(dm->dc, i); if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) { - struct drm_writeback_connector *wbcon = kzalloc(sizeof(*wbcon), GFP_KERNEL); + struct amdgpu_dm_wb_connector *wbcon = kzalloc(sizeof(*wbcon), GFP_KERNEL); if (!wbcon) { DRM_ERROR("KMS: Failed to allocate writeback connector\n"); continue; } - if (amdgpu_dm_wb_connector_init(dm, wbcon)) { + if (amdgpu_dm_wb_connector_init(dm, wbcon, i)) { DRM_ERROR("KMS: Failed to initialize writeback connector\n"); kfree(wbcon); continue; @@ -7609,6 +7609,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, struct dc_link *link = dc_get_link_at_index(dc, link_index); struct amdgpu_i2c_adapter *i2c; + /* Not needed for writeback connector */ link->priv = aconnector; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 3710f4d0f2cb..0a9974017eba 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -32,6 +32,7 @@ #include #include #include "link_service_types.h" +#include /* * This file contains the definition for amdgpu_display_manager @@ -714,6 +715,13 @@ static inline void amdgpu_dm_set_mst_status(uint8_t *status, #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) +struct amdgpu_dm_wb_connector { + struct drm_writeback_connector base; + struct dc_link *link; +}; + +#define to_amdgpu_dm_wb_connector(x) container_of(x, struct amdgpu_dm_wb_connector, base) + extern const struct amdgpu_ip_block_version dm_ip_block; struct dm_plane_state { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c index 74e656696d8e..b3e634b0f712 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c @@ -30,6 +30,7 @@ #include "amdgpu_dm.h" #include "amdgpu_dm_wb.h" #include "amdgpu_display.h" +#include "dc.h" #include #include @@ -183,13 +184,18 @@ static const struct drm_connector_helper_funcs amdgpu_dm_wb_conn_helper_funcs = }; int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, - struct drm_writeback_connector *wbcon) + struct amdgpu_dm_wb_connector *wbcon, + uint32_t link_index) { + struct dc *dc = dm->dc; + struct dc_link *link = dc_get_link_at_index(dc, link_index); int res = 0; - drm_connector_helper_add(&wbcon->base, &amdgpu_dm_wb_conn_helper_funcs); + wbcon->link = link; - res = drm_writeback_connector_init(&dm->adev->ddev, wbcon, + drm_connector_helper_add(&wbcon->base.base, &amdgpu_dm_wb_conn_helper_funcs); + + res = drm_writeback_connector_init(&dm->adev->ddev, &wbcon->base, &amdgpu_dm_wb_connector_funcs, &amdgpu_dm_wb_encoder_helper_funcs, amdgpu_dm_wb_formats, @@ -202,8 +208,8 @@ int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, * Some of the properties below require access to state, like bpc. * Allocate some default initial connector state with our reset helper. */ - if (wbcon->base.funcs->reset) - wbcon->base.funcs->reset(&wbcon->base); + if (wbcon->base.base.funcs->reset) + wbcon->base.base.funcs->reset(&wbcon->base.base); return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h index 0bc9df7e7ee1..13d31c857dee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h @@ -30,6 +30,7 @@ #include int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, - struct drm_writeback_connector *wbcon); + struct amdgpu_dm_wb_connector *dm_wbcon, + uint32_t link_index); #endif From 1fb9d7b975baba081724be8ff6370b1a71a8aea4 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 1 Dec 2023 06:25:30 -0700 Subject: [PATCH 2862/7721] drm/amd/display: Create fake sink and stream for writeback connector [WHAT] Writeback connectors don't have a physical sink but DC still needs a sink to function. Create a fake sink and stream for writeback connectors Tested-by: Daniel Wheeler Reviewed-by: Alex Hung Signed-off-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0f41328510c2..06ccfc9669c7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5715,13 +5715,13 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, } static struct dc_sink * -create_fake_sink(struct amdgpu_dm_connector *aconnector) +create_fake_sink(struct dc_link *link) { struct dc_sink_init_data sink_init_data = { 0 }; struct dc_sink *sink = NULL; - sink_init_data.link = aconnector->dc_link; - sink_init_data.sink_signal = aconnector->dc_link->connector_signal; + sink_init_data.link = link; + sink_init_data.sink_signal = link->connector_signal; sink = dc_sink_create(&sink_init_data); if (!sink) { @@ -6092,6 +6092,7 @@ create_stream_for_sink(struct drm_connector *connector, enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; struct dsc_dec_dpcd_caps dsc_caps; + struct dc_link *link = NULL; struct dc_sink *sink = NULL; drm_mode_init(&mode, drm_mode); @@ -6105,14 +6106,24 @@ create_stream_for_sink(struct drm_connector *connector, if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { aconnector = NULL; aconnector = to_amdgpu_dm_connector(connector); - if (!aconnector->dc_sink) { - sink = create_fake_sink(aconnector); - if (!sink) - return stream; - } else { - sink = aconnector->dc_sink; - dc_sink_retain(sink); - } + link = aconnector->dc_link; + } else { + struct drm_writeback_connector *wbcon = NULL; + struct amdgpu_dm_wb_connector *dm_wbcon = NULL; + + wbcon = drm_connector_to_writeback(connector); + dm_wbcon = to_amdgpu_dm_wb_connector(wbcon); + link = dm_wbcon->link; + } + + if (!aconnector || !aconnector->dc_sink) { + sink = create_fake_sink(link); + if (!sink) + return stream; + + } else { + sink = aconnector->dc_sink; + dc_sink_retain(sink); } stream = dc_create_stream_for_sink(sink); From c81e13b929df2fd16dce87ac36672978f10eae1c Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:31 -0700 Subject: [PATCH 2863/7721] drm/amd/display: Hande writeback request from userspace [WHAT] Handle writeback requests and fill in the required information for DWB programming and setup. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 3 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 159 ++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 32fe05c810c6..a166d7684719 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -416,6 +416,9 @@ struct amdgpu_crtc { int otg_inst; struct drm_pending_vblank_event *event; + + bool wb_pending; + struct drm_writeback_connector *wb_conn; }; struct amdgpu_encoder_atom_dig { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 06ccfc9669c7..311f815452e0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -578,6 +578,7 @@ static void dm_crtc_high_irq(void *interrupt_params) { struct common_irq_params *irq_params = interrupt_params; struct amdgpu_device *adev = irq_params->adev; + struct drm_writeback_job *job; struct amdgpu_crtc *acrtc; unsigned long flags; int vrr_active; @@ -586,6 +587,21 @@ static void dm_crtc_high_irq(void *interrupt_params) if (!acrtc) return; + if (acrtc->wb_pending) { + if (acrtc->wb_conn) { + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); + job = list_first_entry_or_null(&acrtc->wb_conn->job_queue, + struct drm_writeback_job, + list_entry); + spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); + + if (job) + drm_writeback_signal_completion(acrtc->wb_conn, 0); + } else + DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__); + acrtc->wb_pending = false; + } + vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); drm_dbg_vbl(adev_to_drm(adev), @@ -8639,6 +8655,12 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state); } +static void dm_clear_writeback(struct amdgpu_display_manager *dm, + struct dm_crtc_state *crtc_state) +{ + dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0); +} + static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, struct dc_state *dc_state) { @@ -8648,9 +8670,34 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; + struct drm_connector_state *old_con_state; + struct drm_connector *connector; bool mode_set_reset_required = false; u32 i; + /* Disable writeback */ + for_each_old_connector_in_state(state, connector, old_con_state, i) { + struct dm_connector_state *dm_old_con_state; + struct amdgpu_crtc *acrtc; + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + old_crtc_state = NULL; + + dm_old_con_state = to_dm_connector_state(old_con_state); + if (!dm_old_con_state->base.crtc) + continue; + + acrtc = to_amdgpu_crtc(dm_old_con_state->base.crtc); + if (acrtc) + old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + + dm_clear_writeback(dm, dm_old_crtc_state); + } + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); @@ -8787,6 +8834,97 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, } } +static void dm_set_writeback(struct amdgpu_display_manager *dm, + struct dm_crtc_state *crtc_state, + struct drm_connector *connector, + struct drm_connector_state *new_con_state) +{ + struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector); + struct amdgpu_crtc *acrtc; + struct dc_writeback_info *wb_info; + struct pipe_ctx *pipe = NULL; + struct amdgpu_framebuffer *afb; + int i = 0; + + wb_info = kzalloc(sizeof(*wb_info), GFP_KERNEL); + if (!wb_info) { + DRM_ERROR("Failed to allocate wb_info\n"); + return; + } + + acrtc = to_amdgpu_crtc(wb_conn->encoder.crtc); + if (!acrtc) { + DRM_ERROR("no amdgpu_crtc found\n"); + return; + } + + afb = to_amdgpu_framebuffer(new_con_state->writeback_job->fb); + if (!afb) { + DRM_ERROR("No amdgpu_framebuffer found\n"); + return; + } + + for (i = 0; i < MAX_PIPES; i++) { + if (dm->dc->current_state->res_ctx.pipe_ctx[i].stream == crtc_state->stream) { + pipe = &dm->dc->current_state->res_ctx.pipe_ctx[i]; + break; + } + } + + /* fill in wb_info */ + wb_info->wb_enabled = true; + + wb_info->dwb_pipe_inst = 0; + wb_info->dwb_params.dwbscl_black_color = 0; + wb_info->dwb_params.hdr_mult = 0x1F000; + wb_info->dwb_params.csc_params.gamut_adjust_type = CM_GAMUT_ADJUST_TYPE_BYPASS; + wb_info->dwb_params.csc_params.gamut_coef_format = CM_GAMUT_REMAP_COEF_FORMAT_S2_13; + wb_info->dwb_params.output_depth = DWB_OUTPUT_PIXEL_DEPTH_10BPC; + wb_info->dwb_params.cnv_params.cnv_out_bpc = DWB_CNV_OUT_BPC_10BPC; + + /* width & height from crtc */ + wb_info->dwb_params.cnv_params.src_width = acrtc->base.mode.crtc_hdisplay; + wb_info->dwb_params.cnv_params.src_height = acrtc->base.mode.crtc_vdisplay; + wb_info->dwb_params.dest_width = acrtc->base.mode.crtc_hdisplay; + wb_info->dwb_params.dest_height = acrtc->base.mode.crtc_vdisplay; + + wb_info->dwb_params.cnv_params.crop_en = false; + wb_info->dwb_params.stereo_params.stereo_enabled = false; + + wb_info->dwb_params.cnv_params.out_max_pix_val = 0x3ff; // 10 bits + wb_info->dwb_params.cnv_params.out_min_pix_val = 0; + wb_info->dwb_params.cnv_params.fc_out_format = DWB_OUT_FORMAT_32BPP_ARGB; + wb_info->dwb_params.cnv_params.out_denorm_mode = DWB_OUT_DENORM_BYPASS; + + wb_info->dwb_params.out_format = dwb_scaler_mode_bypass444; + + wb_info->dwb_params.capture_rate = dwb_capture_rate_0; + + wb_info->dwb_params.scaler_taps.h_taps = 4; + wb_info->dwb_params.scaler_taps.v_taps = 4; + wb_info->dwb_params.scaler_taps.h_taps_c = 2; + wb_info->dwb_params.scaler_taps.v_taps_c = 2; + wb_info->dwb_params.subsample_position = DWB_INTERSTITIAL_SUBSAMPLING; + + wb_info->mcif_buf_params.luma_pitch = afb->base.pitches[0]; + wb_info->mcif_buf_params.chroma_pitch = afb->base.pitches[1]; + + for (i = 0; i < DWB_MCIF_BUF_COUNT; i++) { + wb_info->mcif_buf_params.luma_address[i] = afb->address; + wb_info->mcif_buf_params.chroma_address[i] = 0; + } + + wb_info->mcif_buf_params.p_vmid = 1; + wb_info->mcif_warmup_params.p_vmid = 1; + wb_info->writeback_source_plane = pipe->plane_state; + + dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info); + + acrtc->wb_pending = true; + acrtc->wb_conn = wb_conn; + drm_writeback_queue_job(wb_conn, new_con_state); +} + /** * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation. * @state: The atomic state to commit @@ -9119,6 +9257,27 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) amdgpu_dm_commit_planes(state, dev, dm, crtc, wait_for_vblank); } + /* Enable writeback */ + for_each_new_connector_in_state(state, connector, new_con_state, i) { + struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + if (!new_con_state->writeback_job) + continue; + + new_crtc_state = NULL; + + if (acrtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); + + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + + dm_set_writeback(dm, dm_new_crtc_state, connector, new_con_state); + } + /* Update audio instances for each connector. */ amdgpu_dm_commit_audio(dev, state); From f772f902b28662188636faba88e2a10bdb08e128 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:32 -0700 Subject: [PATCH 2864/7721] drm/amd/display: Add writeback enable/disable in dc [WHAT] The enable and disable writeback calls need to be included in the coressponding functions in dc_stream. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_stream.c | 33 +++++++++++++++++++ .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 4 +++ 2 files changed, 37 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 4bdf105d1d71..e71d622098d7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -467,6 +467,25 @@ bool dc_stream_add_writeback(struct dc *dc, struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; dwb->otg_inst = stream_status->primary_otg_inst; } + + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* enable writeback */ + if (dc->hwss.enable_writeback) { + struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) { + /* writeback pipe already enabled, only need to update */ + dc->hwss.update_writeback(dc, wb_info, dc->current_state); + } else { + /* Enable writeback pipe from scratch*/ + dc->hwss.enable_writeback(dc, wb_info, dc->current_state); + } + } + return true; } @@ -511,6 +530,20 @@ bool dc_stream_remove_writeback(struct dc *dc, } stream->num_wb_info = j; + /* recalculate and apply DML parameters */ + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* disable writeback */ + if (dc->hwss.disable_writeback) { + struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) + dc->hwss.disable_writeback(dc, dwb_pipe_inst); + } + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index d71faf2ecd41..fd8a8c10a201 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -367,6 +367,10 @@ void dcn30_enable_writeback( DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ __func__, wb_info->dwb_pipe_inst,\ wb_info->mpcc_inst); + + /* Warmup interface */ + dcn30_mmhubbub_warmup(dc, 1, wb_info); + /* Update writeback pipe */ dcn30_set_writeback(dc, wb_info, context); From c09919e6ea5fefd49d8b7b54aa5b222937163108 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:33 -0700 Subject: [PATCH 2865/7721] drm/amd/display: Fix writeback_info never got updated [WHY] wb_enabled field is set to false before it is used, and the following code will never be executed. [HOW] Setting wb_enable to false after all removal work is completed. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index e71d622098d7..8e7bc4a30f27 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -509,18 +509,13 @@ bool dc_stream_remove_writeback(struct dc *dc, return false; } -// stream->writeback_info[dwb_pipe_inst].wb_enabled = false; - for (i = 0; i < stream->num_wb_info; i++) { - /*dynamic update*/ - if (stream->writeback_info[i].wb_enabled && - stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) { - stream->writeback_info[i].wb_enabled = false; - } - } - /* remove writeback info for disabled writeback pipes from stream */ for (i = 0, j = 0; i < stream->num_wb_info; i++) { if (stream->writeback_info[i].wb_enabled) { + + if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) + stream->writeback_info[i].wb_enabled = false; + if (j < i) /* trim the array */ memcpy(&stream->writeback_info[j], &stream->writeback_info[i], From 86ecd796a88e26e025f184ff6a2e8872a6dc9ac7 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:34 -0700 Subject: [PATCH 2866/7721] drm/amd/display: Validate hw_points_num before using it [WHAT] hw_points_num is 0 before ogam LUT is programmed; however, function "dwb3_program_ogam_pwl" assumes hw_points_num is always greater than 0, i.e. substracting it by 1 as an array index. [HOW] Check hw_points_num is not equal to 0 before using it. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c index 701c7d8bc038..03a50c32fcfe 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c @@ -243,6 +243,9 @@ static bool dwb3_program_ogam_lut( return false; } + if (params->hw_points_num == 0) + return false; + REG_SET(DWB_OGAM_CONTROL, 0, DWB_OGAM_MODE, 2); current_mode = dwb3_get_ogam_current(dwbc30); From ab37b88ed9de9de8d582683f7ea17059f1251a7f Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:35 -0700 Subject: [PATCH 2867/7721] drm/amd/display: Fix writeback_info is not removed [WHY] Counter j was not updated to present the num of writeback_info when writeback pipes are removed. [HOW] update j (num of writeback info) under the correct condition. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 8e7bc4a30f27..3dd9f4ab2261 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -516,11 +516,12 @@ bool dc_stream_remove_writeback(struct dc *dc, if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) stream->writeback_info[i].wb_enabled = false; - if (j < i) - /* trim the array */ + /* trim the array */ + if (j < i) { memcpy(&stream->writeback_info[j], &stream->writeback_info[i], sizeof(struct dc_writeback_info)); - j++; + j++; + } } } stream->num_wb_info = j; From f872e2f5f0beabd34c03799a5c597f6ba47b51cc Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:36 -0700 Subject: [PATCH 2868/7721] drm/amd/display: Add writeback enable field (wb_enabled) [WHAT] Add a new field to keep track whether a crtc is previously writeback-enabled. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 1 + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index a166d7684719..d8083972e393 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -418,6 +418,7 @@ struct amdgpu_crtc { struct drm_pending_vblank_event *event; bool wb_pending; + bool wb_enabled; struct drm_writeback_connector *wb_conn; }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 311f815452e0..b45b248808f7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8693,9 +8693,13 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, if (acrtc) old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + if (!acrtc->wb_enabled) + continue; + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); dm_clear_writeback(dm, dm_old_crtc_state); + acrtc->wb_enabled = false; } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, @@ -9273,9 +9277,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) if (acrtc) new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); + if (acrtc->wb_enabled) + continue; + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_set_writeback(dm, dm_new_crtc_state, connector, new_con_state); + acrtc->wb_enabled = true; } /* Update audio instances for each connector. */ From fdf43d25e38f9e6e6a3cdb15335c198fb6d5dcb9 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:37 -0700 Subject: [PATCH 2869/7721] drm/amd/display: Setup for mmhubbub3_warmup_mcif with big buffer [WHY] Hardware may require different warmup approaches - big buffer or individual buffers. [HOW] Setup warmup for big buffer when it is required by specific hardware. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index b45b248808f7..7e5e4be99b60 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8844,6 +8844,7 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm, struct drm_connector_state *new_con_state) { struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector); + struct amdgpu_device *adev = dm->adev; struct amdgpu_crtc *acrtc; struct dc_writeback_info *wb_info; struct pipe_ctx *pipe = NULL; @@ -8919,6 +8920,11 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm, } wb_info->mcif_buf_params.p_vmid = 1; + if (adev->ip_versions[DCE_HWIP][0] >= IP_VERSION(3, 0, 0)) { + wb_info->mcif_warmup_params.start_address.quad_part = afb->address; + wb_info->mcif_warmup_params.region_size = + wb_info->mcif_buf_params.luma_pitch * wb_info->dwb_params.dest_height; + } wb_info->mcif_warmup_params.p_vmid = 1; wb_info->writeback_source_plane = pipe->plane_state; From 50ad10cba6cd1c7f0ac9049f2c2c6b7589b510d0 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:38 -0700 Subject: [PATCH 2870/7721] drm/amd/display: Add new set_fc_enable to struct dwbc_funcs [WHAT] Add a function to enable and disable DWB's frame captures. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c | 23 +++++++++++++++++++ .../gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h | 2 ++ drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c index 0d98918bf0fc..1b9d9495f76d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c @@ -130,6 +130,28 @@ bool dwb3_disable(struct dwbc *dwbc) return true; } +void dwb3_set_fc_enable(struct dwbc *dwbc, enum dwb_frame_capture_enable enable) +{ + struct dcn30_dwbc *dwbc30 = TO_DCN30_DWBC(dwbc); + unsigned int pre_locked; + + REG_GET(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, &pre_locked); + + /* Lock DWB registers */ + if (pre_locked == 0) + REG_UPDATE(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, 1); + + /* Disable FC */ + REG_UPDATE(FC_MODE_CTRL, FC_FRAME_CAPTURE_EN, enable); + + /* Unlock DWB registers */ + if (pre_locked == 0) + REG_UPDATE(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, 0); + + DC_LOG_DWB("%s dwb3_fc_disabled at inst = %d", __func__, dwbc->inst); +} + + bool dwb3_update(struct dwbc *dwbc, struct dc_dwb_params *params) { struct dcn30_dwbc *dwbc30 = TO_DCN30_DWBC(dwbc); @@ -226,6 +248,7 @@ static const struct dwbc_funcs dcn30_dwbc_funcs = { .disable = dwb3_disable, .update = dwb3_update, .is_enabled = dwb3_is_enabled, + .set_fc_enable = dwb3_set_fc_enable, .set_stereo = dwb3_set_stereo, .set_new_content = dwb3_set_new_content, .dwb_program_output_csc = NULL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h index a5d1b81e768d..332634b76aac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h @@ -877,6 +877,8 @@ bool dwb3_update(struct dwbc *dwbc, struct dc_dwb_params *params); bool dwb3_is_enabled(struct dwbc *dwbc); +void dwb3_set_fc_enable(struct dwbc *dwbc, enum dwb_frame_capture_enable enable); + void dwb3_set_stereo(struct dwbc *dwbc, struct dwb_stereo_params *stereo_params); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h index 86b711dcc785..729ca0064e94 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h @@ -188,6 +188,10 @@ struct dwbc_funcs { bool (*is_enabled)( struct dwbc *dwbc); + void (*set_fc_enable)( + struct dwbc *dwbc, + enum dwb_frame_capture_enable enable); + void (*set_stereo)( struct dwbc *dwbc, struct dwb_stereo_params *stereo_params); From 87ce0e62694115cfe4210a17c269d6855d2a139b Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 1 Dec 2023 06:25:39 -0700 Subject: [PATCH 2871/7721] drm/amd/display: Disable DWB frame capture to emulate oneshot [WHY] drm_writeback requires to capture exact one frame in each writeback call. [HOW] frame_capture is disabled after each writeback is completed. Tested-by: Daniel Wheeler Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++++++++- .../gpu/drm/amd/display/dc/core/dc_stream.c | 27 +++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_stream.h | 4 +++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7e5e4be99b60..6aabe8a3ffef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -595,8 +595,20 @@ static void dm_crtc_high_irq(void *interrupt_params) list_entry); spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); - if (job) + if (job) { + unsigned int v_total, refresh_hz; + struct dc_stream_state *stream = acrtc->dm_irq_params.stream; + + v_total = stream->adjust.v_total_max ? + stream->adjust.v_total_max : stream->timing.v_total; + refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz * + 100LL, (v_total * stream->timing.h_total)); + mdelay(1000 / refresh_hz); + drm_writeback_signal_completion(acrtc->wb_conn, 0); + dc_stream_fc_disable_writeback(adev->dm.dc, + acrtc->dm_irq_params.stream, 0); + } } else DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__); acrtc->wb_pending = false; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 3dd9f4ab2261..38cd29b210c0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -489,6 +489,33 @@ bool dc_stream_add_writeback(struct dc *dc, return true; } +bool dc_stream_fc_disable_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst) +{ + struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } + + if (dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; + } + + if (stream->num_wb_info > MAX_DWB_PIPES) { + dm_error("DC: num_wb_info is invalid!\n"); + return false; + } + + if (dwb->funcs->set_fc_enable) + dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE); + + return true; +} + bool dc_stream_remove_writeback(struct dc *dc, struct dc_stream_state *stream, uint32_t dwb_pipe_inst) diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index e61eea6db29c..4ac48c346a33 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -454,6 +454,10 @@ bool dc_stream_add_writeback(struct dc *dc, struct dc_stream_state *stream, struct dc_writeback_info *wb_info); +bool dc_stream_fc_disable_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst); + bool dc_stream_remove_writeback(struct dc *dc, struct dc_stream_state *stream, uint32_t dwb_pipe_inst); From 514a1cc940c264007805c02173dd5490c0a59f48 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Fri, 1 Dec 2023 06:25:40 -0700 Subject: [PATCH 2872/7721] drm/amd/display: Fix array-index-out-of-bounds in dml2 [Why] UBSAN errors observed in dmesg. array-index-out-of-bounds in dml2/display_mode_core.c [How] Fix the index. Tested-by: Daniel Wheeler Acked-by: Rodrigo Siqueira Signed-off-by: Roman Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c index 59718ee33e51..4d1336e5afc2 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c @@ -9447,12 +9447,12 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc // Output CalculateWatermarks_params->Watermark = &s->dummy_watermark; // Watermarks *Watermark - CalculateWatermarks_params->DRAMClockChangeSupport = &mode_lib->ms.support.DRAMClockChangeSupport[j]; + CalculateWatermarks_params->DRAMClockChangeSupport = &mode_lib->ms.support.DRAMClockChangeSupport[0]; CalculateWatermarks_params->MaxActiveDRAMClockChangeLatencySupported = &s->dummy_single_array[0][0]; // dml_float_t *MaxActiveDRAMClockChangeLatencySupported[] CalculateWatermarks_params->SubViewportLinesNeededInMALL = &mode_lib->ms.SubViewportLinesNeededInMALL[j]; // dml_uint_t SubViewportLinesNeededInMALL[] - CalculateWatermarks_params->FCLKChangeSupport = &mode_lib->ms.support.FCLKChangeSupport[j]; + CalculateWatermarks_params->FCLKChangeSupport = &mode_lib->ms.support.FCLKChangeSupport[0]; CalculateWatermarks_params->MaxActiveFCLKChangeLatencySupported = &s->dummy_single[0]; // dml_float_t *MaxActiveFCLKChangeLatencySupported - CalculateWatermarks_params->USRRetrainingSupport = &mode_lib->ms.support.USRRetrainingSupport[j]; + CalculateWatermarks_params->USRRetrainingSupport = &mode_lib->ms.support.USRRetrainingSupport[0]; CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport( &mode_lib->scratch, From d3e78612e949e16088b6ee83647b28499c24954d Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Fri, 1 Dec 2023 06:25:41 -0700 Subject: [PATCH 2873/7721] drm/amd/display: Adjust code style This simple commit adjusts part of the code style in some of the dc bios files. Tested-by: Daniel Wheeler Reviewed-by: Aurabindo Pillai Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/bios/bios_parser2.c | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 971473c69b32..aef964f1bcbe 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -2215,22 +2215,22 @@ static enum bp_result bios_parser_get_disp_connector_caps_info( switch (bp->object_info_tbl.revision.minor) { case 4: - default: - object = get_bios_object(bp, object_id); + default: + object = get_bios_object(bp, object_id); - if (!object) - return BP_RESULT_BADINPUT; + if (!object) + return BP_RESULT_BADINPUT; - record = get_disp_connector_caps_record(bp, object); - if (!record) - return BP_RESULT_NORECORD; + record = get_disp_connector_caps_record(bp, object); + if (!record) + return BP_RESULT_NORECORD; - info->INTERNAL_DISPLAY = - (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY) ? 1 : 0; - info->INTERNAL_DISPLAY_BL = - (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL) ? 1 : 0; - break; - case 5: + info->INTERNAL_DISPLAY = + (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY) ? 1 : 0; + info->INTERNAL_DISPLAY_BL = + (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL) ? 1 : 0; + break; + case 5: object_path_v3 = get_bios_object_from_path_v3(bp, object_id); if (!object_path_v3) @@ -3330,27 +3330,28 @@ static enum bp_result get_bracket_layout_record( DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); return BP_RESULT_BADINPUT; } + tbl = &bp->object_info_tbl; v1_4 = tbl->v1_4; v1_5 = tbl->v1_5; result = BP_RESULT_NORECORD; switch (bp->object_info_tbl.revision.minor) { - case 4: - default: - for (i = 0; i < v1_4->number_of_path; ++i) { - if (bracket_layout_id == - v1_4->display_path[i].display_objid) { - result = update_slot_layout_info(dcb, i, slot_layout_info); - break; - } + case 4: + default: + for (i = 0; i < v1_4->number_of_path; ++i) { + if (bracket_layout_id == v1_4->display_path[i].display_objid) { + result = update_slot_layout_info(dcb, i, slot_layout_info); + break; } - break; - case 5: - for (i = 0; i < v1_5->number_of_path; ++i) - result = update_slot_layout_info_v2(dcb, i, slot_layout_info); - break; + } + break; + case 5: + for (i = 0; i < v1_5->number_of_path; ++i) + result = update_slot_layout_info_v2(dcb, i, slot_layout_info); + break; } + return result; } @@ -3359,9 +3360,7 @@ static enum bp_result bios_get_board_layout_info( struct board_layout_info *board_layout_info) { unsigned int i; - struct bios_parser *bp; - static enum bp_result record_result; unsigned int max_slots; @@ -3371,7 +3370,6 @@ static enum bp_result bios_get_board_layout_info( 0, 0 }; - bp = BP_FROM_DCB(dcb); if (board_layout_info == NULL) { @@ -3552,7 +3550,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .bios_parser_destroy = firmware_parser_destroy, .get_board_layout_info = bios_get_board_layout_info, - /* TODO: use this fn in hw init?*/ .pack_data_tables = bios_parser_pack_data_tables, .get_atom_dc_golden_table = bios_get_atom_dc_golden_table, From 107d678f6aecb4421975a25127b6bf521504b39e Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Fri, 1 Dec 2023 06:25:42 -0700 Subject: [PATCH 2874/7721] drm/amd/display: Update code comment to be more accurate Tested-by: Daniel Wheeler Reviewed-by: Aurabindo Pillai Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 102d00a9a24f..9d3925603979 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1521,7 +1521,7 @@ static void program_timing_sync( } - /* remove any other pipes that are already been synced */ + /* remove any other unblanked pipes as they have already been synced */ if (dc->config.use_pipe_ctx_sync_logic) { /* check pipe's syncd to decide which pipe to be removed */ for (j = 1; j < group_size; j++) { @@ -1534,6 +1534,7 @@ static void program_timing_sync( pipe_set[j]->pipe_idx_syncd = pipe_set[0]->pipe_idx_syncd; } } else { + /* remove any other pipes by checking valid plane */ for (j = j + 1; j < group_size; j++) { bool is_blanked; From c0c22ed7c9fd6e6d50f61ed7347e60342e958e6f Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Fri, 1 Dec 2023 06:25:43 -0700 Subject: [PATCH 2875/7721] drm/amd/display: 3.2.263 This version brings along following fixes: * Enable writeback. * Add multiple fixes for DML2 and DCN35. * Introduce small code style adjustments. Acked-by: Rodrigo Siqueira Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6ee4db8c0548..61d08349a0d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -49,7 +49,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.262" +#define DC_VER "3.2.263" #define MAX_SURFACES 3 #define MAX_PLANES 6 From 24d29d5b189590497947510046eb685e5e2452b6 Mon Sep 17 00:00:00 2001 From: Li Ma Date: Tue, 14 Nov 2023 16:17:51 +0800 Subject: [PATCH 2876/7721] drm/amd/swsmu: update smu v14_0_0 driver if version and metrics table Increment the driver if version and add new mems to the mertics table. Signed-off-by: Li Ma Reviewed-by: Yifan Zhang Signed-off-by: Alex Deucher --- .../gpu/drm/amd/include/kgd_pp_interface.h | 17 ++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 10 +++ .../inc/pmfw_if/smu14_driver_if_v14_0_0.h | 77 +++++++++++-------- .../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 46 ++++++++++- 4 files changed, 115 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 8ebba87f4289..36a5ad8c00c5 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -1086,6 +1086,10 @@ struct gpu_metrics_v3_0 { uint16_t average_dram_reads; /* time filtered DRAM write bandwidth [MB/sec] */ uint16_t average_dram_writes; + /* time filtered IPU read bandwidth [MB/sec] */ + uint16_t average_ipu_reads; + /* time filtered IPU write bandwidth [MB/sec] */ + uint16_t average_ipu_writes; /* Driver attached timestamp (in ns) */ uint64_t system_clock_counter; @@ -1105,6 +1109,8 @@ struct gpu_metrics_v3_0 { uint32_t average_all_core_power; /* calculated core power [mW] */ uint16_t average_core_power[16]; + /* time filtered total system power [mW] */ + uint16_t average_sys_power; /* maximum IRM defined STAPM power limit [mW] */ uint16_t stapm_power_limit; /* time filtered STAPM power limit [mW] */ @@ -1117,6 +1123,8 @@ struct gpu_metrics_v3_0 { uint16_t average_ipuclk_frequency; uint16_t average_fclk_frequency; uint16_t average_vclk_frequency; + uint16_t average_uclk_frequency; + uint16_t average_mpipu_frequency; /* Current clocks */ /* target core frequency [MHz] */ @@ -1126,6 +1134,15 @@ struct gpu_metrics_v3_0 { /* GFXCLK frequency limit enforced on GFX [MHz] */ uint16_t current_gfx_maxfreq; + /* Throttle Residency (ASIC dependent) */ + uint32_t throttle_residency_prochot; + uint32_t throttle_residency_spl; + uint32_t throttle_residency_fppt; + uint32_t throttle_residency_sppt; + uint32_t throttle_residency_thm_core; + uint32_t throttle_residency_thm_gfx; + uint32_t throttle_residency_thm_soc; + /* Metrics table alpha filter time constant [us] */ uint32_t time_filter_alphavalue; }; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index c125253df20b..c2265e027ca8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1418,6 +1418,16 @@ typedef enum { METRICS_PCIE_WIDTH, METRICS_CURR_FANPWM, METRICS_CURR_SOCKETPOWER, + METRICS_AVERAGE_VPECLK, + METRICS_AVERAGE_IPUCLK, + METRICS_AVERAGE_MPIPUCLK, + METRICS_THROTTLER_RESIDENCY_PROCHOT, + METRICS_THROTTLER_RESIDENCY_SPL, + METRICS_THROTTLER_RESIDENCY_FPPT, + METRICS_THROTTLER_RESIDENCY_SPPT, + METRICS_THROTTLER_RESIDENCY_THM_CORE, + METRICS_THROTTLER_RESIDENCY_THM_GFX, + METRICS_THROTTLER_RESIDENCY_THM_SOC, } MetricsMember_t; enum smu_cmn2asic_mapping_type { diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h index 22f88842a7fd..8f42771e1f0a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h @@ -27,7 +27,7 @@ // *** IMPORTANT *** // SMU TEAM: Always increment the interface version if // any structure is changed in this file -#define PMFW_DRIVER_IF_VERSION 6 +#define PMFW_DRIVER_IF_VERSION 7 typedef struct { int32_t value; @@ -150,37 +150,50 @@ typedef struct { } DpmClocks_t; typedef struct { - uint16_t CoreFrequency[16]; //Target core frequency [MHz] - uint16_t CorePower[16]; //CAC calculated core power [mW] - uint16_t CoreTemperature[16]; //TSEN measured core temperature [centi-C] - uint16_t GfxTemperature; //TSEN measured GFX temperature [centi-C] - uint16_t SocTemperature; //TSEN measured SOC temperature [centi-C] - uint16_t StapmOpnLimit; //Maximum IRM defined STAPM power limit [mW] - uint16_t StapmCurrentLimit; //Time filtered STAPM power limit [mW] - uint16_t InfrastructureCpuMaxFreq; //CCLK frequency limit enforced on classic cores [MHz] - uint16_t InfrastructureGfxMaxFreq; //GFXCLK frequency limit enforced on GFX [MHz] - uint16_t SkinTemp; //Maximum skin temperature reported by APU and HS2 chassis sensors [centi-C] - uint16_t GfxclkFrequency; //Time filtered target GFXCLK frequency [MHz] - uint16_t FclkFrequency; //Time filtered target FCLK frequency [MHz] - uint16_t GfxActivity; //Time filtered GFX busy % [0-100] - uint16_t SocclkFrequency; //Time filtered target SOCCLK frequency [MHz] - uint16_t VclkFrequency; //Time filtered target VCLK frequency [MHz] - uint16_t VcnActivity; //Time filtered VCN busy % [0-100] - uint16_t VpeclkFrequency; //Time filtered target VPECLK frequency [MHz] - uint16_t IpuclkFrequency; //Time filtered target IPUCLK frequency [MHz] - uint16_t IpuBusy[8]; //Time filtered IPU per-column busy % [0-100] - uint16_t DRAMReads; //Time filtered DRAM read bandwidth [MB/sec] - uint16_t DRAMWrites; //Time filtered DRAM write bandwidth [MB/sec] - uint16_t CoreC0Residency[16]; //Time filtered per-core C0 residency % [0-100] - uint16_t IpuPower; //Time filtered IPU power [mW] - uint32_t ApuPower; //Time filtered APU power [mW] - uint32_t GfxPower; //Time filtered GFX power [mW] - uint32_t dGpuPower; //Time filtered dGPU power [mW] - uint32_t SocketPower; //Time filtered power used for PPT/STAPM [APU+dGPU] [mW] - uint32_t AllCorePower; //Time filtered sum of core power across all cores in the socket [mW] - uint32_t FilterAlphaValue; //Metrics table alpha filter time constant [us] - uint32_t MetricsCounter; //Counter that is incremented on every metrics table update [PM_TIMER cycles] - uint32_t spare[16]; + uint16_t CoreFrequency[16]; //Target core frequency [MHz] + uint16_t CorePower[16]; //CAC calculated core power [mW] + uint16_t CoreTemperature[16]; //TSEN measured core temperature [centi-C] + uint16_t GfxTemperature; //TSEN measured GFX temperature [centi-C] + uint16_t SocTemperature; //TSEN measured SOC temperature [centi-C] + uint16_t StapmOpnLimit; //Maximum IRM defined STAPM power limit [mW] + uint16_t StapmCurrentLimit; //Time filtered STAPM power limit [mW] + uint16_t InfrastructureCpuMaxFreq; //CCLK frequency limit enforced on classic cores [MHz] + uint16_t InfrastructureGfxMaxFreq; //GFXCLK frequency limit enforced on GFX [MHz] + uint16_t SkinTemp; //Maximum skin temperature reported by APU and HS2 chassis sensors [centi-C] + uint16_t GfxclkFrequency; //Time filtered target GFXCLK frequency [MHz] + uint16_t FclkFrequency; //Time filtered target FCLK frequency [MHz] + uint16_t GfxActivity; //Time filtered GFX busy % [0-100] + uint16_t SocclkFrequency; //Time filtered target SOCCLK frequency [MHz] + uint16_t VclkFrequency; //Time filtered target VCLK frequency [MHz] + uint16_t VcnActivity; //Time filtered VCN busy % [0-100] + uint16_t VpeclkFrequency; //Time filtered target VPECLK frequency [MHz] + uint16_t IpuclkFrequency; //Time filtered target IPUCLK frequency [MHz] + uint16_t IpuBusy[8]; //Time filtered IPU per-column busy % [0-100] + uint16_t DRAMReads; //Time filtered DRAM read bandwidth [MB/sec] + uint16_t DRAMWrites; //Time filtered DRAM write bandwidth [MB/sec] + uint16_t CoreC0Residency[16]; //Time filtered per-core C0 residency % [0-100] + uint16_t IpuPower; //Time filtered IPU power [mW] + uint32_t ApuPower; //Time filtered APU power [mW] + uint32_t GfxPower; //Time filtered GFX power [mW] + uint32_t dGpuPower; //Time filtered dGPU power [mW] + uint32_t SocketPower; //Time filtered power used for PPT/STAPM [APU+dGPU] [mW] + uint32_t AllCorePower; //Time filtered sum of core power across all cores in the socket [mW] + uint32_t FilterAlphaValue; //Metrics table alpha filter time constant [us] + uint32_t MetricsCounter; //Counter that is incremented on every metrics table update [PM_TIMER cycles] + uint16_t MemclkFrequency; //Time filtered target MEMCLK frequency [MHz] + uint16_t MpipuclkFrequency; //Time filtered target MPIPUCLK frequency [MHz] + uint16_t IpuReads; //Time filtered IPU read bandwidth [MB/sec] + uint16_t IpuWrites; //Time filtered IPU write bandwidth [MB/sec] + uint32_t ThrottleResidency_PROCHOT; //Counter that is incremented on every metrics table update when PROCHOT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_SPL; //Counter that is incremented on every metrics table update when SPL was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_FPPT; //Counter that is incremented on every metrics table update when fast PPT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_SPPT; //Counter that is incremented on every metrics table update when slow PPT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_THM_CORE; //Counter that is incremented on every metrics table update when CORE thermal throttling was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_THM_GFX; //Counter that is incremented on every metrics table update when GFX thermal throttling was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_THM_SOC; //Counter that is incremented on every metrics table update when SOC thermal throttling was engaged [PM_TIMER cycles] + uint16_t Psys; //Time filtered Psys power [mW] + uint16_t spare1; + uint32_t spare[6]; } SmuMetrics_t; //ISP tile definitions diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 03b38c3a9968..94ccdbfd7090 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -246,11 +246,20 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu, *value = 0; break; case METRICS_AVERAGE_UCLK: - *value = 0; + *value = metrics->MemclkFrequency; break; case METRICS_AVERAGE_FCLK: *value = metrics->FclkFrequency; break; + case METRICS_AVERAGE_VPECLK: + *value = metrics->VpeclkFrequency; + break; + case METRICS_AVERAGE_IPUCLK: + *value = metrics->IpuclkFrequency; + break; + case METRICS_AVERAGE_MPIPUCLK: + *value = metrics->MpipuclkFrequency; + break; case METRICS_AVERAGE_GFXACTIVITY: *value = metrics->GfxActivity / 100; break; @@ -270,8 +279,26 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu, *value = metrics->SocTemperature / 100 * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; - case METRICS_THROTTLER_STATUS: - *value = 0; + case METRICS_THROTTLER_RESIDENCY_PROCHOT: + *value = metrics->ThrottleResidency_PROCHOT; + break; + case METRICS_THROTTLER_RESIDENCY_SPL: + *value = metrics->ThrottleResidency_SPL; + break; + case METRICS_THROTTLER_RESIDENCY_FPPT: + *value = metrics->ThrottleResidency_FPPT; + break; + case METRICS_THROTTLER_RESIDENCY_SPPT: + *value = metrics->ThrottleResidency_SPPT; + break; + case METRICS_THROTTLER_RESIDENCY_THM_CORE: + *value = metrics->ThrottleResidency_THM_CORE; + break; + case METRICS_THROTTLER_RESIDENCY_THM_GFX: + *value = metrics->ThrottleResidency_THM_GFX; + break; + case METRICS_THROTTLER_RESIDENCY_THM_SOC: + *value = metrics->ThrottleResidency_THM_SOC; break; case METRICS_VOLTAGE_VDDGFX: *value = 0; @@ -498,6 +525,8 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, sizeof(uint16_t) * 16); gpu_metrics->average_dram_reads = metrics.DRAMReads; gpu_metrics->average_dram_writes = metrics.DRAMWrites; + gpu_metrics->average_ipu_reads = metrics.IpuReads; + gpu_metrics->average_ipu_writes = metrics.IpuWrites; gpu_metrics->average_socket_power = metrics.SocketPower; gpu_metrics->average_ipu_power = metrics.IpuPower; @@ -505,6 +534,7 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_gfx_power = metrics.GfxPower; gpu_metrics->average_dgpu_power = metrics.dGpuPower; gpu_metrics->average_all_core_power = metrics.AllCorePower; + gpu_metrics->average_sys_power = metrics.Psys; memcpy(&gpu_metrics->average_core_power[0], &metrics.CorePower[0], sizeof(uint16_t) * 16); @@ -515,6 +545,8 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_fclk_frequency = metrics.FclkFrequency; gpu_metrics->average_vclk_frequency = metrics.VclkFrequency; gpu_metrics->average_ipuclk_frequency = metrics.IpuclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency; + gpu_metrics->average_mpipu_frequency = metrics.MpipuclkFrequency; memcpy(&gpu_metrics->current_coreclk[0], &metrics.CoreFrequency[0], @@ -522,6 +554,14 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, gpu_metrics->current_core_maxfreq = metrics.InfrastructureCpuMaxFreq; gpu_metrics->current_gfx_maxfreq = metrics.InfrastructureGfxMaxFreq; + gpu_metrics->throttle_residency_prochot = metrics.ThrottleResidency_PROCHOT; + gpu_metrics->throttle_residency_spl = metrics.ThrottleResidency_SPL; + gpu_metrics->throttle_residency_fppt = metrics.ThrottleResidency_FPPT; + gpu_metrics->throttle_residency_sppt = metrics.ThrottleResidency_SPPT; + gpu_metrics->throttle_residency_thm_core = metrics.ThrottleResidency_THM_CORE; + gpu_metrics->throttle_residency_thm_gfx = metrics.ThrottleResidency_THM_GFX; + gpu_metrics->throttle_residency_thm_soc = metrics.ThrottleResidency_THM_SOC; + gpu_metrics->time_filter_alphavalue = metrics.FilterAlphaValue; gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); From 0d65efcbe350f1e9e96f24905df4929188e80d56 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 4 Dec 2023 10:17:57 +0800 Subject: [PATCH 2877/7721] drm/amd/pm: support new mca smu error code decoding support new mca smu error code decoding from smu 85.86.0 for smu v13.0.6 Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h | 2 ++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h index 2b488fcf2f95..e51e8918e667 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h @@ -46,6 +46,8 @@ #define MCA_REG__STATUS__ERRORCODEEXT(x) MCA_REG_FIELD(x, 21, 16) #define MCA_REG__STATUS__ERRORCODE(x) MCA_REG_FIELD(x, 15, 0) +#define MCA_REG__SYND__ERRORINFORMATION(x) MCA_REG_FIELD(x, 17, 0) + enum amdgpu_mca_ip { AMDGPU_MCA_IP_UNKNOW = -1, AMDGPU_MCA_IP_PSP = 0, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index dda2249c4994..ddd782fbee7a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -2635,6 +2635,7 @@ static bool mca_gfx_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_entry *entry) { + struct smu_context *smu = adev->powerplay.pp_handle; uint32_t errcode, instlo; instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); @@ -2642,7 +2643,13 @@ static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amd if (instlo != 0x03b30400) return false; - errcode = REG_GET_FIELD(entry->regs[MCA_REG_IDX_STATUS], MCMP1_STATUST0, ErrorCode); + if (!(adev->flags & AMD_IS_APU) && smu->smc_fw_version >= 0x00555600) { + errcode = MCA_REG__SYND__ERRORINFORMATION(entry->regs[MCA_REG_IDX_SYND]); + errcode &= 0xff; + } else { + errcode = REG_GET_FIELD(entry->regs[MCA_REG_IDX_STATUS], MCMP1_STATUST0, ErrorCode); + } + return mca_smu_check_error_code(adev, mca_ras, errcode); } From 71a9d7a2a1034e72074335ac2aff4f9b8013ae6c Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Mon, 20 Nov 2023 10:43:02 +0800 Subject: [PATCH 2878/7721] drm/amdgpu: Update fw version for boot time error query Boot time error query is not available until fw a10109 Signed-off-by: Hawking Zhang Reviewed-by: Stanley Yang Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index 3cf4684d0d3f..5f46877f78cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -821,7 +821,7 @@ static int psp_v13_0_query_boot_status(struct psp_context *psp) if (amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 6)) return 0; - if (RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_59) < 0x00a10007) + if (RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_59) < 0x00a10109) return 0; for_each_inst(i, inst_mask) { From 04a71f110446eb6ffdaaa13407b4c1bf286db760 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 4 Dec 2023 10:44:32 +0800 Subject: [PATCH 2879/7721] drm/amdgpu: optimize the printing order of error data sort error data list to optimize the printing order. Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 72634d675e27..bacb59d8b701 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "amdgpu.h" #include "amdgpu_ras.h" @@ -3674,6 +3675,21 @@ static struct ras_err_node *amdgpu_ras_error_node_new(void) return err_node; } +static int ras_err_info_cmp(void *priv, const struct list_head *a, const struct list_head *b) +{ + struct ras_err_node *nodea = container_of(a, struct ras_err_node, node); + struct ras_err_node *nodeb = container_of(b, struct ras_err_node, node); + struct amdgpu_smuio_mcm_config_info *infoa = &nodea->err_info.mcm_info; + struct amdgpu_smuio_mcm_config_info *infob = &nodeb->err_info.mcm_info; + + if (unlikely(infoa->socket_id != infob->socket_id)) + return infoa->socket_id - infob->socket_id; + else + return infoa->die_id - infob->die_id; + + return 0; +} + static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_data, struct amdgpu_smuio_mcm_config_info *mcm_info) { @@ -3691,6 +3707,7 @@ static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_d err_data->err_list_count++; list_add_tail(&err_node->node, &err_data->err_node_list); + list_sort(NULL, &err_data->err_node_list, ras_err_info_cmp); return &err_node->err_info; } From 7a2464fac80d42f6f8819fed97a553e9c2f43310 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 30 Nov 2023 15:50:16 +0800 Subject: [PATCH 2880/7721] drm/radeon: check the alloc_workqueue return value in radeon_crtc_init() check the alloc_workqueue return value in radeon_crtc_init() to avoid null-ptr-deref. Fixes: fa7f517cb26e ("drm/radeon: rework page flip handling v4") Signed-off-by: Yang Yingliang Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 901e75ec70ff..efd18c8d84c8 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -687,11 +687,16 @@ static void radeon_crtc_init(struct drm_device *dev, int index) if (radeon_crtc == NULL) return; + radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0); + if (!radeon_crtc->flip_queue) { + kfree(radeon_crtc); + return; + } + drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs); drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); radeon_crtc->crtc_id = index; - radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0); rdev->mode_info.crtcs[index] = radeon_crtc; if (rdev->family >= CHIP_BONAIRE) { From 72ada8603e36291ad91e4f40f10ef742ef79bc4e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Nov 2023 17:34:07 -0500 Subject: [PATCH 2881/7721] drm/amd/display: Increase frame warning limit with KASAN or KCSAN in dml Does the same thing as: commit 6740ec97bcdb ("drm/amd/display: Increase frame warning limit with KASAN or KCSAN in dml2") Reviewed-by: Harry Wentland Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311302107.hUDXVyWT-lkp@intel.com/ Fixes: 67e38874b85b ("drm/amd/display: Increase num voltage states to 40") Signed-off-by: Alex Deucher Cc: Alvin Lee Cc: Hamza Mahfooz Cc: Samson Tam Cc: Harry Wentland --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index ea7d60f9a9b4..6042a5a6a44f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -61,8 +61,12 @@ endif endif ifneq ($(CONFIG_FRAME_WARN),0) +ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) +frame_warn_flag := -Wframe-larger-than=3072 +else frame_warn_flag := -Wframe-larger-than=2048 endif +endif CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags) From 13ac7c0e30e87e006cfad67ce4337268f65d4333 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 7 Oct 2023 16:53:24 +0530 Subject: [PATCH 2882/7721] drm/amdgpu: Read aquavanjaram WAFL register state Add support to read state of WAFL links in aquavanjaram SOC. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 76 ++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index a00b8c6f0a94..eec15f1c143f 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -848,6 +848,79 @@ static ssize_t aqua_vanjaram_read_xgmi_state(struct amdgpu_device *adev, return xgmi_reg_state->common_header.structure_size; } +#define smnreg_0x11C00070 0x11C00070 +#define smnreg_0x11C00210 0x11C00210 + +static struct aqua_reg_list wafl_reg_addrs[] = { + { smnreg_0x11C00070, 4, DW_ADDR_INCR }, + { smnreg_0x11C00210, 1, 0 }, +}; + +#define WAFL_LINK_REG(smnreg, l) ((smnreg) | (l << 20)) + +#define NUM_WAFL_SMN_REGS 5 + +static ssize_t aqua_vanjaram_read_wafl_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_wafl_v1_0 *wafl_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_wafl_v1_0 *wafl_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_wafl_instances = 8; + int inst = 0, i, j, r, n; + const int wafl_inst = 2; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + wafl_reg_state = (struct amdgpu_reg_state_wafl_v1_0 *)buf; + + szbuf = sizeof(*wafl_reg_state) + + amdgpu_reginst_size(max_wafl_instances, sizeof(*wafl_regs), + NUM_WAFL_SMN_REGS); + + if (max_size < szbuf) + return -EOVERFLOW; + + p = &wafl_reg_state->wafl_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + for (j = 0; j < wafl_inst; ++j) { + wafl_regs = (struct amdgpu_regs_wafl_v1_0 *)p; + wafl_regs->inst_header.instance = inst++; + + wafl_regs->inst_header.state = AMDGPU_INST_S_OK; + wafl_regs->inst_header.num_smn_regs = NUM_WAFL_SMN_REGS; + + reg_data = wafl_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(wafl_reg_addrs); r++) { + start_addr = wafl_reg_addrs[r].start_addr; + incrx = wafl_reg_addrs[r].incrx; + num_regs = wafl_reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext( + adev, reg_data, + WAFL_LINK_REG(start_addr, j) + + n * incrx, + i); + ++reg_data; + } + } + p = reg_data; + } + } + + wafl_reg_state->common_header.structure_size = szbuf; + wafl_reg_state->common_header.format_revision = 1; + wafl_reg_state->common_header.content_revision = 0; + wafl_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_WAFL; + wafl_reg_state->common_header.num_instances = max_wafl_instances; + + return wafl_reg_state->common_header.structure_size; +} + ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, enum amdgpu_reg_state reg_state, void *buf, size_t max_size) @@ -861,6 +934,9 @@ ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, case AMDGPU_REG_STATE_TYPE_XGMI: size = aqua_vanjaram_read_xgmi_state(adev, buf, max_size); break; + case AMDGPU_REG_STATE_TYPE_WAFL: + size = aqua_vanjaram_read_wafl_state(adev, buf, max_size); + break; default: return -EINVAL; } From 650f0487d6cd95c4e07a41d3a464d0f60a983a15 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 7 Oct 2023 19:52:11 +0530 Subject: [PATCH 2883/7721] drm/amdgpu: Read aquavanjaram USR register state Add support to read state of USR links in aquavanjaram SOC. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 127 +++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index eec15f1c143f..d6f808acfb17 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -921,6 +921,125 @@ static ssize_t aqua_vanjaram_read_wafl_state(struct amdgpu_device *adev, return wafl_reg_state->common_header.structure_size; } +#define smnreg_0x1B311060 0x1B311060 +#define smnreg_0x1B411060 0x1B411060 +#define smnreg_0x1B511060 0x1B511060 +#define smnreg_0x1B611060 0x1B611060 + +#define smnreg_0x1C307120 0x1C307120 +#define smnreg_0x1C317120 0x1C317120 + +#define smnreg_0x1C320830 0x1C320830 +#define smnreg_0x1C380830 0x1C380830 +#define smnreg_0x1C3D0830 0x1C3D0830 +#define smnreg_0x1C420830 0x1C420830 + +#define smnreg_0x1C320100 0x1C320100 +#define smnreg_0x1C380100 0x1C380100 +#define smnreg_0x1C3D0100 0x1C3D0100 +#define smnreg_0x1C420100 0x1C420100 + +#define smnreg_0x1B310500 0x1B310500 +#define smnreg_0x1C300400 0x1C300400 + +#define USR_CAKE_INCR 0x11000 +#define USR_LINK_INCR 0x100000 +#define USR_CP_INCR 0x10000 + +#define NUM_USR_SMN_REGS 20 + +struct aqua_reg_list usr_reg_addrs[] = { + { smnreg_0x1B311060, 4, DW_ADDR_INCR }, + { smnreg_0x1B411060, 4, DW_ADDR_INCR }, + { smnreg_0x1B511060, 4, DW_ADDR_INCR }, + { smnreg_0x1B611060, 4, DW_ADDR_INCR }, + { smnreg_0x1C307120, 2, DW_ADDR_INCR }, + { smnreg_0x1C317120, 2, DW_ADDR_INCR }, +}; + +#define NUM_USR1_SMN_REGS 46 +struct aqua_reg_list usr1_reg_addrs[] = { + { smnreg_0x1C320830, 6, USR_CAKE_INCR }, + { smnreg_0x1C380830, 5, USR_CAKE_INCR }, + { smnreg_0x1C3D0830, 5, USR_CAKE_INCR }, + { smnreg_0x1C420830, 4, USR_CAKE_INCR }, + { smnreg_0x1C320100, 6, USR_CAKE_INCR }, + { smnreg_0x1C380100, 5, USR_CAKE_INCR }, + { smnreg_0x1C3D0100, 5, USR_CAKE_INCR }, + { smnreg_0x1C420100, 4, USR_CAKE_INCR }, + { smnreg_0x1B310500, 4, USR_LINK_INCR }, + { smnreg_0x1C300400, 2, USR_CP_INCR }, +}; + +static ssize_t aqua_vanjaram_read_usr_state(struct amdgpu_device *adev, + void *buf, size_t max_size, + int reg_state) +{ + uint32_t start_addr, incrx, num_regs, szbuf, num_smn; + struct amdgpu_reg_state_usr_v1_0 *usr_reg_state; + struct amdgpu_regs_usr_v1_0 *usr_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_usr_instances = 4; + struct aqua_reg_list *reg_addrs; + int inst = 0, i, n, r, arr_size; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + switch (reg_state) { + case AMDGPU_REG_STATE_TYPE_USR: + arr_size = ARRAY_SIZE(usr_reg_addrs); + reg_addrs = usr_reg_addrs; + num_smn = NUM_USR_SMN_REGS; + break; + case AMDGPU_REG_STATE_TYPE_USR_1: + arr_size = ARRAY_SIZE(usr1_reg_addrs); + reg_addrs = usr1_reg_addrs; + num_smn = NUM_USR1_SMN_REGS; + break; + default: + return -EINVAL; + } + + usr_reg_state = (struct amdgpu_reg_state_usr_v1_0 *)buf; + + szbuf = sizeof(*usr_reg_state) + amdgpu_reginst_size(max_usr_instances, + sizeof(*usr_regs), + num_smn); + if (max_size < szbuf) + return -EOVERFLOW; + + p = &usr_reg_state->usr_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + usr_regs = (struct amdgpu_regs_usr_v1_0 *)p; + usr_regs->inst_header.instance = inst++; + usr_regs->inst_header.state = AMDGPU_INST_S_OK; + usr_regs->inst_header.num_smn_regs = num_smn; + reg_data = usr_regs->smn_reg_values; + + for (r = 0; r < arr_size; r++) { + start_addr = reg_addrs[r].start_addr; + incrx = reg_addrs[r].incrx; + num_regs = reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext(adev, reg_data, + start_addr + n * incrx, i); + reg_data++; + } + } + p = reg_data; + } + + usr_reg_state->common_header.structure_size = szbuf; + usr_reg_state->common_header.format_revision = 1; + usr_reg_state->common_header.content_revision = 0; + usr_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_USR; + usr_reg_state->common_header.num_instances = max_usr_instances; + + return usr_reg_state->common_header.structure_size; +} + ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, enum amdgpu_reg_state reg_state, void *buf, size_t max_size) @@ -937,6 +1056,14 @@ ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, case AMDGPU_REG_STATE_TYPE_WAFL: size = aqua_vanjaram_read_wafl_state(adev, buf, max_size); break; + case AMDGPU_REG_STATE_TYPE_USR: + size = aqua_vanjaram_read_usr_state(adev, buf, max_size, + AMDGPU_REG_STATE_TYPE_USR); + break; + case AMDGPU_REG_STATE_TYPE_USR_1: + size = aqua_vanjaram_read_usr_state( + adev, buf, max_size, AMDGPU_REG_STATE_TYPE_USR_1); + break; default: return -EINVAL; } From 3b35dd87c5969637ab5aa6666bbab6e6929c9e16 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Thu, 30 Nov 2023 16:53:21 -0500 Subject: [PATCH 2884/7721] drm/amd: Add a DC debug mask for DML2 [Why&How] To enable testing/development of DML2, expose a new debug mask for future use. Signed-off-by: Aurabindo Pillai Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/amd_shared.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 7f98394338c2..bf7f258c324a 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -257,6 +257,7 @@ enum DC_DEBUG_MASK { DC_DISABLE_MPO = 0x40, DC_DISABLE_REPLAY = 0x50, DC_ENABLE_DPIA_TRACE = 0x80, + DC_ENABLE_DML2 = 0x100, }; enum amd_dpm_forced_level; From 4657b3e45683223b5d982ec13a6e2cd367004bb6 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 29 Nov 2023 18:06:55 +0530 Subject: [PATCH 2885/7721] drm/amdgpu: Restrict extended wait to PSP v13.0.6 Only PSPv13.0.6 SOCs take a longer time to reach steady state. Other PSPv13 based SOCs don't need extended wait. Also, reduce PSPv13.0.6 wait time. Cc: stable@vger.kernel.org Fixes: fc5988907156 ("drm/amdgpu: update retry times for psp vmbx wait") Fixes: d8c1925ba8cd ("drm/amdgpu: update retry times for psp BL wait") Link: https://lore.kernel.org/amd-gfx/34dd4c66-f7bf-44aa-af8f-c82889dd652c@amd.com/ Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Reviewed-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index 5f46877f78cf..df1844d0800f 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -60,7 +60,7 @@ MODULE_FIRMWARE("amdgpu/psp_14_0_0_ta.bin"); #define GFX_CMD_USB_PD_USE_LFB 0x480 /* Retry times for vmbx ready wait */ -#define PSP_VMBX_POLLING_LIMIT 20000 +#define PSP_VMBX_POLLING_LIMIT 3000 /* VBIOS gfl defines */ #define MBOX_READY_MASK 0x80000000 @@ -161,14 +161,18 @@ static int psp_v13_0_wait_for_vmbx_ready(struct psp_context *psp) static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - int retry_loop, ret; + int retry_loop, retry_cnt, ret; + retry_cnt = + (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6)) ? + PSP_VMBX_POLLING_LIMIT : + 10; /* Wait for bootloader to signify that it is ready having bit 31 of * C2PMSG_35 set to 1. All other bits are expected to be cleared. * If there is an error in processing command, bits[7:0] will be set. * This is applicable for PSP v13.0.6 and newer. */ - for (retry_loop = 0; retry_loop < PSP_VMBX_POLLING_LIMIT; retry_loop++) { + for (retry_loop = 0; retry_loop < retry_cnt; retry_loop++) { ret = psp_wait_for( psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), 0x80000000, 0xffffffff, false); From 0737df9ed0997f5b8addd6e2b9699a8c6edba2e4 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 4 Dec 2023 16:57:56 +0800 Subject: [PATCH 2886/7721] drm/radeon/dpm: fix a memleak in sumo_parse_power_table The rdev->pm.dpm.ps allocated by kcalloc should be freed in every following error-handling path. However, in the error-handling of rdev->pm.power_state[i].clock_info the rdev->pm.dpm.ps is not freed, resulting in a memleak in this function. Fixes: 80ea2c129c76 ("drm/radeon/kms: add dpm support for sumo asics (v2)") Signed-off-by: Zhipeng Lu Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/sumo_dpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index f74f381af05f..d49c145db437 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1493,8 +1493,10 @@ static int sumo_parse_power_table(struct radeon_device *rdev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - if (!rdev->pm.power_state[i].clock_info) + if (!rdev->pm.power_state[i].clock_info) { + kfree(rdev->pm.dpm.ps); return -EINVAL; + } ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); if (ps == NULL) { kfree(rdev->pm.dpm.ps); From 28c28d7f77c06ac2c0b8f9c82bc04eba22912b3b Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 4 Dec 2023 18:21:54 +0800 Subject: [PATCH 2887/7721] drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table The rdev->pm.dpm.ps allocated by kcalloc should be freed in every following error-handling path. However, in the error-handling of rdev->pm.power_state[i].clock_info the rdev->pm.dpm.ps is not freed, resulting in a memleak in this function. Fixes: d70229f70447 ("drm/radeon/kms: add dpm support for trinity asics") Signed-off-by: Zhipeng Lu Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/trinity_dpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 08ea1c864cb2..ef1cc7bad20a 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1726,8 +1726,10 @@ static int trinity_parse_power_table(struct radeon_device *rdev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - if (!rdev->pm.power_state[i].clock_info) + if (!rdev->pm.power_state[i].clock_info) { + kfree(rdev->pm.dpm.ps); return -EINVAL; + } ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); if (ps == NULL) { kfree(rdev->pm.dpm.ps); From 44f3356e36c2082f0f91c4f6b8859c577cee14a4 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Fri, 24 Nov 2023 08:32:06 -0500 Subject: [PATCH 2888/7721] drm/amd/amdgpu: Add SMUIO headers for 10.0.2 These were requested by a UMR user for debugging purposes. Signed-off-by: Tom St Denis Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- .../asic_reg/smuio/smuio_10_0_2_offset.h | 102 ++++++++++ .../asic_reg/smuio/smuio_10_0_2_sh_mask.h | 184 ++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h create mode 100644 drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h new file mode 100644 index 000000000000..a4dd372c0541 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _smuio_10_0_2_OFFSET_HEADER + +// addressBlock: smuio_smuio_misc_SmuSmuioDec +// base address: 0x5a000 +#define mmSMUIO_MCM_CONFIG 0x0023 +#define mmSMUIO_MCM_CONFIG_BASE_IDX 0 +#define mmIP_DISCOVERY_VERSION 0x0000 +#define mmIP_DISCOVERY_VERSION_BASE_IDX 1 +#define mmIO_SMUIO_PINSTRAP 0x01b1 +#define mmIO_SMUIO_PINSTRAP_BASE_IDX 1 +#define mmSCRATCH_REGISTER0 0x01b2 +#define mmSCRATCH_REGISTER0_BASE_IDX 1 +#define mmSCRATCH_REGISTER1 0x01b3 +#define mmSCRATCH_REGISTER1_BASE_IDX 1 +#define mmSCRATCH_REGISTER2 0x01b4 +#define mmSCRATCH_REGISTER2_BASE_IDX 1 +#define mmSCRATCH_REGISTER3 0x01b5 +#define mmSCRATCH_REGISTER3_BASE_IDX 1 +#define mmSCRATCH_REGISTER4 0x01b6 +#define mmSCRATCH_REGISTER4_BASE_IDX 1 +#define mmSCRATCH_REGISTER5 0x01b7 +#define mmSCRATCH_REGISTER5_BASE_IDX 1 +#define mmSCRATCH_REGISTER6 0x01b8 +#define mmSCRATCH_REGISTER6_BASE_IDX 1 +#define mmSCRATCH_REGISTER7 0x01b9 +#define mmSCRATCH_REGISTER7_BASE_IDX 1 + + +// addressBlock: smuio_smuio_reset_SmuSmuioDec +// base address: 0x5a300 +#define mmSMUIO_MP_RESET_INTR 0x00c1 +#define mmSMUIO_MP_RESET_INTR_BASE_IDX 0 +#define mmSMUIO_SOC_HALT 0x00c2 +#define mmSMUIO_SOC_HALT_BASE_IDX 0 +#define mmSMUIO_GFX_MISC_CNTL 0x00c8 +#define mmSMUIO_GFX_MISC_CNTL_BASE_IDX 0 + + +// addressBlock: smuio_smuio_ccxctrl_SmuSmuioDec +// base address: 0x5a000 +#define mmPWROK_REFCLK_GAP_CYCLES 0x0001 +#define mmPWROK_REFCLK_GAP_CYCLES_BASE_IDX 1 +#define mmGOLDEN_TSC_INCREMENT_UPPER 0x0004 +#define mmGOLDEN_TSC_INCREMENT_UPPER_BASE_IDX 1 +#define mmGOLDEN_TSC_INCREMENT_LOWER 0x0005 +#define mmGOLDEN_TSC_INCREMENT_LOWER_BASE_IDX 1 +#define mmGOLDEN_TSC_COUNT_UPPER 0x0025 +#define mmGOLDEN_TSC_COUNT_UPPER_BASE_IDX 1 +#define mmGOLDEN_TSC_COUNT_LOWER 0x0026 +#define mmGOLDEN_TSC_COUNT_LOWER_BASE_IDX 1 +#define mmGFX_GOLDEN_TSC_SHADOW_UPPER 0x0029 +#define mmGFX_GOLDEN_TSC_SHADOW_UPPER_BASE_IDX 1 +#define mmGFX_GOLDEN_TSC_SHADOW_LOWER 0x002a +#define mmGFX_GOLDEN_TSC_SHADOW_LOWER_BASE_IDX 1 +#define mmSOC_GOLDEN_TSC_SHADOW_UPPER 0x002b +#define mmSOC_GOLDEN_TSC_SHADOW_UPPER_BASE_IDX 1 +#define mmSOC_GOLDEN_TSC_SHADOW_LOWER 0x002c +#define mmSOC_GOLDEN_TSC_SHADOW_LOWER_BASE_IDX 1 +#define mmSOC_GAP_PWROK 0x002d +#define mmSOC_GAP_PWROK_BASE_IDX 1 + +// addressBlock: smuio_smuio_swtimer_SmuSmuioDec +// base address: 0x5ac40 +#define mmPWR_VIRT_RESET_REQ 0x0110 +#define mmPWR_VIRT_RESET_REQ_BASE_IDX 1 +#define mmPWR_DISP_TIMER_CONTROL 0x0111 +#define mmPWR_DISP_TIMER_CONTROL_BASE_IDX 1 +#define mmPWR_DISP_TIMER2_CONTROL 0x0113 +#define mmPWR_DISP_TIMER2_CONTROL_BASE_IDX 1 +#define mmPWR_DISP_TIMER_GLOBAL_CONTROL 0x0115 +#define mmPWR_DISP_TIMER_GLOBAL_CONTROL_BASE_IDX 1 +#define mmPWR_IH_CONTROL 0x0116 +#define mmPWR_IH_CONTROL_BASE_IDX 1 + +// addressBlock: smuio_smuio_svi0_SmuSmuioDec +// base address: 0x6f000 +#define mmSMUSVI0_TEL_PLANE0 0x520e +#define mmSMUSVI0_TEL_PLANE0_BASE_IDX 1 +#define mmSMUSVI0_PLANE0_CURRENTVID 0x5217 +#define mmSMUSVI0_PLANE0_CURRENTVID_BASE_IDX 1 + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h new file mode 100644 index 000000000000..d10ae61c346b --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _smuio_10_0_2_SH_MASK_HEADER + +// addressBlock: smuio_smuio_misc_SmuSmuioDec +//SMUIO_MCM_CONFIG +#define SMUIO_MCM_CONFIG__DIE_ID__SHIFT 0x0 +#define SMUIO_MCM_CONFIG__PKG_TYPE__SHIFT 0x2 +#define SMUIO_MCM_CONFIG__SOCKET_ID__SHIFT 0x5 +#define SMUIO_MCM_CONFIG__PKG_SUBTYPE__SHIFT 0x6 +#define SMUIO_MCM_CONFIG__CONSOLE_K__SHIFT 0x10 +#define SMUIO_MCM_CONFIG__CONSOLE_A__SHIFT 0x11 +#define SMUIO_MCM_CONFIG__DIE_ID_MASK 0x00000003L +#define SMUIO_MCM_CONFIG__PKG_TYPE_MASK 0x0000001CL +#define SMUIO_MCM_CONFIG__SOCKET_ID_MASK 0x00000020L +#define SMUIO_MCM_CONFIG__PKG_SUBTYPE_MASK 0x000000C0L +#define SMUIO_MCM_CONFIG__CONSOLE_K_MASK 0x00010000L +#define SMUIO_MCM_CONFIG__CONSOLE_A_MASK 0x00020000L +//IP_DISCOVERY_VERSION +#define IP_DISCOVERY_VERSION__IP_DISCOVERY_VERSION__SHIFT 0x0 +#define IP_DISCOVERY_VERSION__IP_DISCOVERY_VERSION_MASK 0xFFFFFFFFL +//IO_SMUIO_PINSTRAP +#define IO_SMUIO_PINSTRAP__AUD_PORT_CONN__SHIFT 0x0 +#define IO_SMUIO_PINSTRAP__AUD__SHIFT 0x3 +#define IO_SMUIO_PINSTRAP__AUD_PORT_CONN_MASK 0x00000007L +#define IO_SMUIO_PINSTRAP__AUD_MASK 0x00000018L +//SCRATCH_REGISTER0 +#define SCRATCH_REGISTER0__ScratchPad0__SHIFT 0x0 +#define SCRATCH_REGISTER0__ScratchPad0_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER1 +#define SCRATCH_REGISTER1__ScratchPad1__SHIFT 0x0 +#define SCRATCH_REGISTER1__ScratchPad1_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER2 +#define SCRATCH_REGISTER2__ScratchPad2__SHIFT 0x0 +#define SCRATCH_REGISTER2__ScratchPad2_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER3 +#define SCRATCH_REGISTER3__ScratchPad3__SHIFT 0x0 +#define SCRATCH_REGISTER3__ScratchPad3_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER4 +#define SCRATCH_REGISTER4__ScratchPad4__SHIFT 0x0 +#define SCRATCH_REGISTER4__ScratchPad4_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER5 +#define SCRATCH_REGISTER5__ScratchPad5__SHIFT 0x0 +#define SCRATCH_REGISTER5__ScratchPad5_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER6 +#define SCRATCH_REGISTER6__ScratchPad6__SHIFT 0x0 +#define SCRATCH_REGISTER6__ScratchPad6_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER7 +#define SCRATCH_REGISTER7__ScratchPad7__SHIFT 0x0 +#define SCRATCH_REGISTER7__ScratchPad7_MASK 0xFFFFFFFFL + +// addressBlock: smuio_smuio_reset_SmuSmuioDec +//SMUIO_MP_RESET_INTR +#define SMUIO_MP_RESET_INTR__SMUIO_MP_RESET_INTR__SHIFT 0x0 +#define SMUIO_MP_RESET_INTR__SMUIO_MP_RESET_INTR_MASK 0x00000001L +//SMUIO_SOC_HALT +#define SMUIO_SOC_HALT__WDT_FORCE_PWROK_EN__SHIFT 0x2 +#define SMUIO_SOC_HALT__WDT_FORCE_RESETn_EN__SHIFT 0x3 +#define SMUIO_SOC_HALT__WDT_FORCE_PWROK_EN_MASK 0x00000004L +#define SMUIO_SOC_HALT__WDT_FORCE_RESETn_EN_MASK 0x00000008L +//SMUIO_GFX_MISC_CNTL +#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff__SHIFT 0x0 +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT 0x1 +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_DLDO_CLK_SWITCH__SHIFT 0x3 +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_RLC_CGPG_EN__SHIFT 0x4 +#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_DLDO_CLK_SWITCH_MASK 0x00000008L +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_RLC_CGPG_EN_MASK 0x00000010L + +// addressBlock: smuio_smuio_ccxctrl_SmuSmuioDec +//PWROK_REFCLK_GAP_CYCLES +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PreAssertion_clkgap_cycles__SHIFT 0x0 +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PostAssertion_clkgap_cycles__SHIFT 0x8 +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PreAssertion_clkgap_cycles_MASK 0x000000FFL +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PostAssertion_clkgap_cycles_MASK 0x0000FF00L +//GOLDEN_TSC_INCREMENT_UPPER +#define GOLDEN_TSC_INCREMENT_UPPER__GoldenTscIncrementUpper__SHIFT 0x0 +#define GOLDEN_TSC_INCREMENT_UPPER__GoldenTscIncrementUpper_MASK 0x00FFFFFFL +//GOLDEN_TSC_INCREMENT_LOWER +#define GOLDEN_TSC_INCREMENT_LOWER__GoldenTscIncrementLower__SHIFT 0x0 +#define GOLDEN_TSC_INCREMENT_LOWER__GoldenTscIncrementLower_MASK 0xFFFFFFFFL +//GOLDEN_TSC_COUNT_UPPER +#define GOLDEN_TSC_COUNT_UPPER__GoldenTscCountUpper__SHIFT 0x0 +#define GOLDEN_TSC_COUNT_UPPER__GoldenTscCountUpper_MASK 0x00FFFFFFL +//GOLDEN_TSC_COUNT_LOWER +#define GOLDEN_TSC_COUNT_LOWER__GoldenTscCountLower__SHIFT 0x0 +#define GOLDEN_TSC_COUNT_LOWER__GoldenTscCountLower_MASK 0xFFFFFFFFL +//GFX_GOLDEN_TSC_SHADOW_UPPER +#define GFX_GOLDEN_TSC_SHADOW_UPPER__GfxGoldenTscShadowUpper__SHIFT 0x0 +#define GFX_GOLDEN_TSC_SHADOW_UPPER__GfxGoldenTscShadowUpper_MASK 0x00FFFFFFL +//GFX_GOLDEN_TSC_SHADOW_LOWER +#define GFX_GOLDEN_TSC_SHADOW_LOWER__GfxGoldenTscShadowLower__SHIFT 0x0 +#define GFX_GOLDEN_TSC_SHADOW_LOWER__GfxGoldenTscShadowLower_MASK 0xFFFFFFFFL +//SOC_GOLDEN_TSC_SHADOW_UPPER +#define SOC_GOLDEN_TSC_SHADOW_UPPER__SocGoldenTscShadowUpper__SHIFT 0x0 +#define SOC_GOLDEN_TSC_SHADOW_UPPER__SocGoldenTscShadowUpper_MASK 0x00FFFFFFL +//SOC_GOLDEN_TSC_SHADOW_LOWER +#define SOC_GOLDEN_TSC_SHADOW_LOWER__SocGoldenTscShadowLower__SHIFT 0x0 +#define SOC_GOLDEN_TSC_SHADOW_LOWER__SocGoldenTscShadowLower_MASK 0xFFFFFFFFL +//SOC_GAP_PWROK +#define SOC_GAP_PWROK__soc_gap_pwrok__SHIFT 0x0 +#define SOC_GAP_PWROK__soc_gap_pwrok_MASK 0x00000001L + +// addressBlock: smuio_smuio_swtimer_SmuSmuioDec +//PWR_VIRT_RESET_REQ +#define PWR_VIRT_RESET_REQ__VF_FLR__SHIFT 0x0 +#define PWR_VIRT_RESET_REQ__PF_FLR__SHIFT 0x1f +#define PWR_VIRT_RESET_REQ__VF_FLR_MASK 0x7FFFFFFFL +#define PWR_VIRT_RESET_REQ__PF_FLR_MASK 0x80000000L +//PWR_DISP_TIMER_CONTROL +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_COUNT__SHIFT 0x0 +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_ENABLE__SHIFT 0x19 +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_DISABLE__SHIFT 0x1a +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MASK__SHIFT 0x1b +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_STAT_AK__SHIFT 0x1c +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_TYPE__SHIFT 0x1d +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MODE__SHIFT 0x1e +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_COUNT_MASK 0x01FFFFFFL +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_ENABLE_MASK 0x02000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_DISABLE_MASK 0x04000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MASK_MASK 0x08000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_STAT_AK_MASK 0x10000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_TYPE_MASK 0x20000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MODE_MASK 0x40000000L +//PWR_DISP_TIMER2_CONTROL +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_COUNT__SHIFT 0x0 +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_ENABLE__SHIFT 0x19 +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_DISABLE__SHIFT 0x1a +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MASK__SHIFT 0x1b +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_STAT_AK__SHIFT 0x1c +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_TYPE__SHIFT 0x1d +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MODE__SHIFT 0x1e +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_COUNT_MASK 0x01FFFFFFL +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_ENABLE_MASK 0x02000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_DISABLE_MASK 0x04000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MASK_MASK 0x08000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_STAT_AK_MASK 0x10000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_TYPE_MASK 0x20000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MODE_MASK 0x40000000L +//PWR_DISP_TIMER_GLOBAL_CONTROL +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_WIDTH__SHIFT 0x0 +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_EN__SHIFT 0xa +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_WIDTH_MASK 0x000003FFL +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_EN_MASK 0x00000400L +//PWR_IH_CONTROL +#define PWR_IH_CONTROL__MAX_CREDIT__SHIFT 0x0 +#define PWR_IH_CONTROL__DISP_TIMER_TRIGGER_MASK__SHIFT 0x5 +#define PWR_IH_CONTROL__DISP_TIMER2_TRIGGER_MASK__SHIFT 0x6 +#define PWR_IH_CONTROL__PWR_IH_CLK_GATE_EN__SHIFT 0x1f +#define PWR_IH_CONTROL__MAX_CREDIT_MASK 0x0000001FL +#define PWR_IH_CONTROL__DISP_TIMER_TRIGGER_MASK_MASK 0x00000020L +#define PWR_IH_CONTROL__DISP_TIMER2_TRIGGER_MASK_MASK 0x00000040L +#define PWR_IH_CONTROL__PWR_IH_CLK_GATE_EN_MASK 0x80000000L + +// addressBlock: smuio_smuio_svi0_SmuSmuioDec +//SMUSVI0_TEL_PLANE0 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_IDDCOR__SHIFT 0x0 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT 0x10 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_IDDCOR_MASK 0x000000FFL +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK 0x01FF0000L +//SMUSVI0_PLANE0_CURRENTVID +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID__SHIFT 0x18 +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID_MASK 0xFF000000L + +#endif From 6146081d58e3dd0c50ceb5a70a6906640727ff96 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 29 Nov 2023 12:37:34 +0530 Subject: [PATCH 2889/7721] drm/amdgpu: Add NULL checks for function pointers Check if function is implemented before making the call. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc15.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 9ad4d6d3122b..9043ebf1e161 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1424,9 +1424,11 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags) if (amdgpu_sriov_vf(adev)) *flags = 0; - adev->nbio.funcs->get_clockgating_state(adev, flags); + if (adev->nbio.funcs && adev->nbio.funcs->get_clockgating_state) + adev->nbio.funcs->get_clockgating_state(adev, flags); - adev->hdp.funcs->get_clock_gating_state(adev, flags); + if (adev->hdp.funcs && adev->hdp.funcs->get_clock_gating_state) + adev->hdp.funcs->get_clock_gating_state(adev, flags); if (amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 2)) { /* AMD_CG_SUPPORT_DRM_MGCG */ @@ -1441,9 +1443,11 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags) } /* AMD_CG_SUPPORT_ROM_MGCG */ - adev->smuio.funcs->get_clock_gating_state(adev, flags); + if (adev->smuio.funcs && adev->smuio.funcs->get_clock_gating_state) + adev->smuio.funcs->get_clock_gating_state(adev, flags); - adev->df.funcs->get_clockgating_state(adev, flags); + if (adev->df.funcs && adev->df.funcs->get_clockgating_state) + adev->df.funcs->get_clockgating_state(adev, flags); } static int soc15_common_set_powergating_state(void *handle, From 828afefd4b0636d92386d4b2c1f53fff87505aba Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 30 Nov 2023 15:58:21 +0530 Subject: [PATCH 2890/7721] drm/amdgpu: Update HDP 4.4.2 clock gating flags HDP 4.4.2 clockgating is enabled by default, update the flags accordingly. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c index 49e934975719..4db6bb73ead4 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c @@ -129,6 +129,11 @@ static void hdp_v4_0_get_clockgating_state(struct amdgpu_device *adev, { int data; + if (amdgpu_ip_version(adev, HDP_HWIP, 0) == IP_VERSION(4, 4, 2)) { + /* Default enabled */ + *flags |= AMD_CG_SUPPORT_HDP_MGCG; + return; + } /* AMD_CG_SUPPORT_HDP_LS */ data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS)); if (data & HDP_MEM_POWER_LS__LS_ENABLE_MASK) From b12fb2953915b092aaef956f6e80783fa70b9f40 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 30 Nov 2023 16:35:58 +0530 Subject: [PATCH 2891/7721] drm/amdgpu: Avoid querying DRM MGCG status MP0 v13.0.6 SOCs don't support DRM MGCG. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc15.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 9043ebf1e161..15033efec2ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1430,7 +1430,8 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags) if (adev->hdp.funcs && adev->hdp.funcs->get_clock_gating_state) adev->hdp.funcs->get_clock_gating_state(adev, flags); - if (amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 2)) { + if ((amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 2)) && + (amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 6))) { /* AMD_CG_SUPPORT_DRM_MGCG */ data = RREG32(SOC15_REG_OFFSET(MP0, 0, mmMP0_MISC_CGTT_CTRL0)); if (!(data & 0x01000000)) From c03581986234044f2eeae308b7840e0083981034 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 29 Nov 2023 15:44:25 -0500 Subject: [PATCH 2892/7721] drm/amdgpu: fix buffer funcs setting order on suspend We need to disable this after the last eviction call, but before we disable the SDMA IP. Fixes: b70438004a14 ("drm/amdgpu: move buffer funcs setting up a level") Link: https://lore.kernel.org/r/87edgv4x3i.fsf@vps.thesusis.net Reviewed-by: Luben Tuikov Tested-by: Phillip Susi Signed-off-by: Alex Deucher Cc: Phillip Susi Cc: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d5b950fd1d85..138c7b37af69 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4600,6 +4600,8 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) if (r) return r; + amdgpu_ttm_set_buffer_funcs_status(adev, false); + amdgpu_fence_driver_hw_fini(adev); amdgpu_device_ip_suspend_phase2(adev); From e17768691dd8d0664413de3123621daa0504054c Mon Sep 17 00:00:00 2001 From: Bokun Zhang Date: Wed, 29 Nov 2023 19:11:22 -0500 Subject: [PATCH 2893/7721] drm/amd/amdgpu: SRIOV full reset issue with VCN - After a full reset, VF's FB will be cleaned. This includes the VCN's fw_shared memory. However, there is no suspend-resume routine for SRIOV VF. Therefore, the data in the fw_shared memory will be lost forever and it causes engine hang later on. We must repopulate the data in fw_shared during SRIOV hw_init Signed-off-by: Bokun Zhang Reviewed-by: Emily Deng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 28b7f96b42e5..169ed400ee7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -1280,6 +1280,9 @@ static int vcn_v4_0_start_sriov(struct amdgpu_device *adev) if (adev->vcn.harvest_config & (1 << i)) continue; + // Must re/init fw_shared at beginning + vcn_v4_0_fw_shared_init(adev, i); + table_size = 0; MMSCH_V4_0_INSERT_DIRECT_RD_MOD_WT(SOC15_REG_OFFSET(VCN, i, From 68999d1dd23a71b991a36201db29c8787f35a23f Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Tue, 5 Dec 2023 15:37:39 +0800 Subject: [PATCH 2894/7721] nvme: introduce nvme_check_ctrl_fabric_info helper Inroduce nvme_check_ctrl_fabric_info helper to check fabric controller info returned by target. Signed-off-by: Guixin Liu Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 42 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 46a4c9c5ea96..9b38f37c872a 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3003,6 +3003,28 @@ static int nvme_init_effects(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) return 0; } +static int nvme_check_ctrl_fabric_info(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) +{ + /* + * In fabrics we need to verify the cntlid matches the + * admin connect + */ + if (ctrl->cntlid != le16_to_cpu(id->cntlid)) { + dev_err(ctrl->device, + "Mismatching cntlid: Connect %u vs Identify %u, rejecting\n", + ctrl->cntlid, le16_to_cpu(id->cntlid)); + return -EINVAL; + } + + if (!nvme_discovery_ctrl(ctrl) && !ctrl->kas) { + dev_err(ctrl->device, + "keep-alive support is mandatory for fabrics\n"); + return -EINVAL; + } + + return 0; +} + static int nvme_init_identify(struct nvme_ctrl *ctrl) { struct nvme_id_ctrl *id; @@ -3115,25 +3137,9 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl) ctrl->iorcsz = le32_to_cpu(id->iorcsz); ctrl->maxcmd = le16_to_cpu(id->maxcmd); - /* - * In fabrics we need to verify the cntlid matches the - * admin connect - */ - if (ctrl->cntlid != le16_to_cpu(id->cntlid)) { - dev_err(ctrl->device, - "Mismatching cntlid: Connect %u vs Identify " - "%u, rejecting\n", - ctrl->cntlid, le16_to_cpu(id->cntlid)); - ret = -EINVAL; + ret = nvme_check_ctrl_fabric_info(ctrl, id); + if (ret) goto out_free; - } - - if (!nvme_discovery_ctrl(ctrl) && !ctrl->kas) { - dev_err(ctrl->device, - "keep-alive support is mandatory for fabrics\n"); - ret = -EINVAL; - goto out_free; - } } else { ctrl->hmpre = le32_to_cpu(id->hmpre); ctrl->hmmin = le32_to_cpu(id->hmmin); From 2fcd3ab398260a113fd4434b4d72929066c73121 Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Tue, 5 Dec 2023 15:37:40 +0800 Subject: [PATCH 2895/7721] nvme-fabrics: check ioccsz and iorcsz Make sure that ioccsz and iorcsz returned by target are correct before use it. Per 2.0a base NVMe spec: I/O Queue Command Capsule Supported Size (IOCCSZ): This field defines the maximum I/O command capsule size in 16 byte units. The minimum value that shall be indicated is 4 corresponding to 64 bytes. Signed-off-by: Guixin Liu Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 9b38f37c872a..590cd4f097c2 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3022,6 +3022,20 @@ static int nvme_check_ctrl_fabric_info(struct nvme_ctrl *ctrl, struct nvme_id_ct return -EINVAL; } + if (ctrl->ioccsz < 4) { + dev_err(ctrl->device, + "I/O queue command capsule supported size %d < 4\n", + ctrl->ioccsz); + return -EINVAL; + } + + if (ctrl->iorcsz < 1) { + dev_err(ctrl->device, + "I/O queue response capsule supported size %d < 1\n", + ctrl->iorcsz); + return -EINVAL; + } + return 0; } From 14b4b5fd3d7aac2f17800b821a0fac30d705a25d Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 6 Dec 2023 16:36:18 +0530 Subject: [PATCH 2896/7721] ASoC: amd: acp: Set bclk as source to set pll for rt5682s codec Some platforms doesn't have reference mclk pin to codec, so set bclk as a clk source for rt5682s codec pll in tdm mode. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20231206110620.1695591-7-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 74e83c2dae53..f7bcf210f0fd 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -282,6 +282,22 @@ static int acp_card_rt5682_hw_params(struct snd_pcm_substream *substream, return ret; } + if (drvdata->tdm_mode) { + ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1, + 6144000, 49152000); + if (ret < 0) { + dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL1, + 49152000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); + return ret; + } + } + /* Set tdm/i2s1 master bclk ratio */ ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format); if (ret < 0) { From 7065eefb38f16c91e9ace36fb7c873e4c9857c27 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 6 Dec 2023 11:09:20 -0800 Subject: [PATCH 2897/7721] bpf: rename MAX_BPF_LINK_TYPE into __MAX_BPF_LINK_TYPE for consistency To stay consistent with the naming pattern used for similar cases in BPF UAPI (__MAX_BPF_ATTACH_TYPE, etc), rename MAX_BPF_LINK_TYPE into __MAX_BPF_LINK_TYPE. Also similar to MAX_BPF_ATTACH_TYPE and MAX_BPF_REG, add: #define MAX_BPF_LINK_TYPE __MAX_BPF_LINK_TYPE Not all __MAX_xxx enums have such #define, so I'm not sure if we should add it or not, but I figured I'll start with a completely backwards compatible way, and we can drop that, if necessary. Also adjust a selftest that used MAX_BPF_LINK_TYPE enum. Suggested-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231206190920.1651226-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 4 +++- tools/include/uapi/linux/bpf.h | 4 +++- tools/testing/selftests/bpf/prog_tests/libbpf_str.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 4df2d025c784..e0545201b55f 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1108,9 +1108,11 @@ enum bpf_link_type { BPF_LINK_TYPE_TCX = 11, BPF_LINK_TYPE_UPROBE_MULTI = 12, BPF_LINK_TYPE_NETKIT = 13, - MAX_BPF_LINK_TYPE, + __MAX_BPF_LINK_TYPE, }; +#define MAX_BPF_LINK_TYPE __MAX_BPF_LINK_TYPE + enum bpf_perf_event_type { BPF_PERF_EVENT_UNSPEC = 0, BPF_PERF_EVENT_UPROBE = 1, diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4df2d025c784..e0545201b55f 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1108,9 +1108,11 @@ enum bpf_link_type { BPF_LINK_TYPE_TCX = 11, BPF_LINK_TYPE_UPROBE_MULTI = 12, BPF_LINK_TYPE_NETKIT = 13, - MAX_BPF_LINK_TYPE, + __MAX_BPF_LINK_TYPE, }; +#define MAX_BPF_LINK_TYPE __MAX_BPF_LINK_TYPE + enum bpf_perf_event_type { BPF_PERF_EVENT_UNSPEC = 0, BPF_PERF_EVENT_UPROBE = 1, diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index 384bc1f7a65e..62ea855ec4d0 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -87,7 +87,7 @@ static void test_libbpf_bpf_link_type_str(void) const char *link_type_str; char buf[256]; - if (link_type == MAX_BPF_LINK_TYPE) + if (link_type == __MAX_BPF_LINK_TYPE) continue; link_type_name = btf__str_by_offset(btf, e->name_off); From f08a1c658257c73697a819c4ded3a84b6f0ead74 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:48 -0800 Subject: [PATCH 2898/7721] bpf: Let bpf_prog_pack_free handle any pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, bpf_prog_pack_free only can only free pointer to struct bpf_binary_header, which is not flexible. Add a size argument to bpf_prog_pack_free so that it can handle any pointer. Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Tested-by: Ilya Leoshkevich # on s390x Reviewed-by: Björn Töpel Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20231206224054.492250-2-song@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/filter.h | 2 +- kernel/bpf/core.c | 21 ++++++++++----------- kernel/bpf/dispatcher.c | 5 +---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 14354605ad26..12d907f17d36 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1067,7 +1067,7 @@ struct bpf_binary_header * bpf_jit_binary_pack_hdr(const struct bpf_prog *fp); void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns); -void bpf_prog_pack_free(struct bpf_binary_header *hdr); +void bpf_prog_pack_free(void *ptr, u32 size); static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp) { diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index ced511f44174..c34513d645c4 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -928,20 +928,20 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) return ptr; } -void bpf_prog_pack_free(struct bpf_binary_header *hdr) +void bpf_prog_pack_free(void *ptr, u32 size) { struct bpf_prog_pack *pack = NULL, *tmp; unsigned int nbits; unsigned long pos; mutex_lock(&pack_mutex); - if (hdr->size > BPF_PROG_PACK_SIZE) { - bpf_jit_free_exec(hdr); + if (size > BPF_PROG_PACK_SIZE) { + bpf_jit_free_exec(ptr); goto out; } list_for_each_entry(tmp, &pack_list, list) { - if ((void *)hdr >= tmp->ptr && (tmp->ptr + BPF_PROG_PACK_SIZE) > (void *)hdr) { + if (ptr >= tmp->ptr && (tmp->ptr + BPF_PROG_PACK_SIZE) > ptr) { pack = tmp; break; } @@ -950,10 +950,10 @@ void bpf_prog_pack_free(struct bpf_binary_header *hdr) if (WARN_ONCE(!pack, "bpf_prog_pack bug\n")) goto out; - nbits = BPF_PROG_SIZE_TO_NBITS(hdr->size); - pos = ((unsigned long)hdr - (unsigned long)pack->ptr) >> BPF_PROG_CHUNK_SHIFT; + nbits = BPF_PROG_SIZE_TO_NBITS(size); + pos = ((unsigned long)ptr - (unsigned long)pack->ptr) >> BPF_PROG_CHUNK_SHIFT; - WARN_ONCE(bpf_arch_text_invalidate(hdr, hdr->size), + WARN_ONCE(bpf_arch_text_invalidate(ptr, size), "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n"); bitmap_clear(pack->bitmap, pos, nbits); @@ -1100,8 +1100,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, *rw_header = kvmalloc(size, GFP_KERNEL); if (!*rw_header) { - bpf_arch_text_copy(&ro_header->size, &size, sizeof(size)); - bpf_prog_pack_free(ro_header); + bpf_prog_pack_free(ro_header, size); bpf_jit_uncharge_modmem(size); return NULL; } @@ -1132,7 +1131,7 @@ int bpf_jit_binary_pack_finalize(struct bpf_prog *prog, kvfree(rw_header); if (IS_ERR(ptr)) { - bpf_prog_pack_free(ro_header); + bpf_prog_pack_free(ro_header, ro_header->size); return PTR_ERR(ptr); } return 0; @@ -1153,7 +1152,7 @@ void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header, { u32 size = ro_header->size; - bpf_prog_pack_free(ro_header); + bpf_prog_pack_free(ro_header, size); kvfree(rw_header); bpf_jit_uncharge_modmem(size); } diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c index fa3e9225aedc..56760fc10e78 100644 --- a/kernel/bpf/dispatcher.c +++ b/kernel/bpf/dispatcher.c @@ -150,10 +150,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, goto out; d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE); if (!d->rw_image) { - u32 size = PAGE_SIZE; - - bpf_arch_text_copy(d->image, &size, sizeof(size)); - bpf_prog_pack_free((struct bpf_binary_header *)d->image); + bpf_prog_pack_free(d->image, PAGE_SIZE); d->image = NULL; goto out; } From 7a3d9a159b178e87306a6e989071ed9a114a1a31 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:49 -0800 Subject: [PATCH 2899/7721] bpf: Adjust argument names of arch_prepare_bpf_trampoline() We are using "im" for "struct bpf_tramp_image" and "tr" for "struct bpf_trampoline" in most of the code base. The only exception is the prototype and fallback version of arch_prepare_bpf_trampoline(). Update them to match the rest of the code base. We mix "orig_call" and "func_addr" for the argument in different versions of arch_prepare_bpf_trampoline(). s/orig_call/func_addr/g so they match. Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Tested-by: Ilya Leoshkevich # on s390x Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20231206224054.492250-3-song@kernel.org Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 10 +++++----- include/linux/bpf.h | 4 ++-- kernel/bpf/trampoline.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7d4af64e3982..d81b886ea4df 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1828,7 +1828,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nregs) * */ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, - struct bpf_tramp_links *tlinks, void *orig_call, + struct bpf_tramp_links *tlinks, void *func_addr, int nregs, u32 flags) { int i; @@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, if (flags & BPF_TRAMP_F_IP_ARG) { /* save ip address of the traced function */ - emit_addr_mov_i64(A64_R(10), (const u64)orig_call, ctx); + emit_addr_mov_i64(A64_R(10), (const u64)func_addr, ctx); emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx); } @@ -2029,7 +2029,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, - void *orig_call) + void *func_addr) { int i, ret; int nregs = m->nr_args; @@ -2050,7 +2050,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, if (nregs > 8) return -ENOTSUPP; - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); + ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); if (ret < 0) return ret; @@ -2061,7 +2061,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, ctx.idx = 0; jit_fill_hole(image, (unsigned int)(image_end - image)); - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); + ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); if (ret > 0 && validate_code(&ctx) < 0) ret = -EINVAL; diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7a483f6b6d5f..17eb6d905204 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1098,10 +1098,10 @@ struct bpf_tramp_run_ctx; * fexit = a set of program to run after original function */ struct bpf_tramp_image; -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end, +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, - void *orig_call); + void *func_addr); u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog, struct bpf_tramp_run_ctx *run_ctx); void notrace __bpf_prog_exit_sleepable_recur(struct bpf_prog *prog, u64 start, diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index e97aeda3a86b..e114a1c7961e 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -1032,10 +1032,10 @@ bpf_trampoline_exit_t bpf_trampoline_exit(const struct bpf_prog *prog) } int __weak -arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end, +arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, - void *orig_call) + void *func_addr) { return -ENOTSUPP; } From 82583daa2efc2e336962b231a46bad03a280b3e0 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:50 -0800 Subject: [PATCH 2900/7721] bpf: Add helpers for trampoline image management As BPF trampoline of different archs moves from bpf_jit_[alloc|free]_exec() to bpf_prog_pack_[alloc|free](), we need to use different _alloc, _free for different archs during the transition. Add the following helpers for this transition: void *arch_alloc_bpf_trampoline(unsigned int size); void arch_free_bpf_trampoline(void *image, unsigned int size); void arch_protect_bpf_trampoline(void *image, unsigned int size); void arch_unprotect_bpf_trampoline(void *image, unsigned int size); The fallback version of these helpers require size <= PAGE_SIZE, but they are only called with size == PAGE_SIZE. They will be called with size < PAGE_SIZE when arch_bpf_trampoline_size() helper is introduced later. Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Tested-by: Ilya Leoshkevich # on s390x Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20231206224054.492250-4-song@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 5 ++++ kernel/bpf/bpf_struct_ops.c | 12 ++++----- kernel/bpf/trampoline.c | 46 ++++++++++++++++++++++++++++------ net/bpf/bpf_dummy_struct_ops.c | 7 +++--- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 17eb6d905204..b7fca151cf1b 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1102,6 +1102,11 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, void *func_addr); +void *arch_alloc_bpf_trampoline(unsigned int size); +void arch_free_bpf_trampoline(void *image, unsigned int size); +void arch_protect_bpf_trampoline(void *image, unsigned int size); +void arch_unprotect_bpf_trampoline(void *image, unsigned int size); + u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog, struct bpf_tramp_run_ctx *run_ctx); void notrace __bpf_prog_exit_sleepable_recur(struct bpf_prog *prog, u64 start, diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index db6176fb64dc..e9e95879bce2 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -515,7 +515,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (err) goto reset_unlock; } - set_memory_rox((long)st_map->image, 1); + arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE); /* Let bpf_link handle registration & unregistration. * * Pair with smp_load_acquire() during lookup_elem(). @@ -524,7 +524,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, goto unlock; } - set_memory_rox((long)st_map->image, 1); + arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE); err = st_ops->reg(kdata); if (likely(!err)) { /* This refcnt increment on the map here after @@ -547,8 +547,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, * there was a race in registering the struct_ops (under the same name) to * a sub-system through different struct_ops's maps. */ - set_memory_nx((long)st_map->image, 1); - set_memory_rw((long)st_map->image, 1); + arch_unprotect_bpf_trampoline(st_map->image, PAGE_SIZE); reset_unlock: bpf_struct_ops_map_put_progs(st_map); @@ -616,7 +615,7 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map) bpf_struct_ops_map_put_progs(st_map); bpf_map_area_free(st_map->links); if (st_map->image) { - bpf_jit_free_exec(st_map->image); + arch_free_bpf_trampoline(st_map->image, PAGE_SIZE); bpf_jit_uncharge_modmem(PAGE_SIZE); } bpf_map_area_free(st_map->uvalue); @@ -691,7 +690,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) return ERR_PTR(ret); } - st_map->image = bpf_jit_alloc_exec(PAGE_SIZE); + st_map->image = arch_alloc_bpf_trampoline(PAGE_SIZE); if (!st_map->image) { /* __bpf_struct_ops_map_free() uses st_map->image as flag * for "charged or not". In this case, we need to unchange @@ -711,7 +710,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) } mutex_init(&st_map->lock); - set_vm_flush_reset_perms(st_map->image); bpf_map_init_from_attr(map, attr); return map; diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index e114a1c7961e..affbcbf7e76e 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -254,7 +254,7 @@ bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total, bool *ip_a static void bpf_tramp_image_free(struct bpf_tramp_image *im) { bpf_image_ksym_del(&im->ksym); - bpf_jit_free_exec(im->image); + arch_free_bpf_trampoline(im->image, PAGE_SIZE); bpf_jit_uncharge_modmem(PAGE_SIZE); percpu_ref_exit(&im->pcref); kfree_rcu(im, rcu); @@ -365,10 +365,9 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) goto out_free_im; err = -ENOMEM; - im->image = image = bpf_jit_alloc_exec(PAGE_SIZE); + im->image = image = arch_alloc_bpf_trampoline(PAGE_SIZE); if (!image) goto out_uncharge; - set_vm_flush_reset_perms(image); err = percpu_ref_init(&im->pcref, __bpf_tramp_image_release, 0, GFP_KERNEL); if (err) @@ -381,7 +380,7 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) return im; out_free_image: - bpf_jit_free_exec(im->image); + arch_free_bpf_trampoline(im->image, PAGE_SIZE); out_uncharge: bpf_jit_uncharge_modmem(PAGE_SIZE); out_free_im: @@ -444,7 +443,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut if (err < 0) goto out_free; - set_memory_rox((long)im->image, 1); + arch_protect_bpf_trampoline(im->image, PAGE_SIZE); WARN_ON(tr->cur_image && total == 0); if (tr->cur_image) @@ -465,8 +464,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut tr->fops->trampoline = 0; /* reset im->image memory attr for arch_prepare_bpf_trampoline */ - set_memory_nx((long)im->image, 1); - set_memory_rw((long)im->image, 1); + arch_unprotect_bpf_trampoline(im->image, PAGE_SIZE); goto again; } #endif @@ -1040,6 +1038,40 @@ arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image return -ENOTSUPP; } +void * __weak arch_alloc_bpf_trampoline(unsigned int size) +{ + void *image; + + if (WARN_ON_ONCE(size > PAGE_SIZE)) + return NULL; + image = bpf_jit_alloc_exec(PAGE_SIZE); + if (image) + set_vm_flush_reset_perms(image); + return image; +} + +void __weak arch_free_bpf_trampoline(void *image, unsigned int size) +{ + WARN_ON_ONCE(size > PAGE_SIZE); + /* bpf_jit_free_exec doesn't need "size", but + * bpf_prog_pack_free() needs it. + */ + bpf_jit_free_exec(image); +} + +void __weak arch_protect_bpf_trampoline(void *image, unsigned int size) +{ + WARN_ON_ONCE(size > PAGE_SIZE); + set_memory_rox((long)image, 1); +} + +void __weak arch_unprotect_bpf_trampoline(void *image, unsigned int size) +{ + WARN_ON_ONCE(size > PAGE_SIZE); + set_memory_nx((long)image, 1); + set_memory_rw((long)image, 1); +} + static int __init init_trampolines(void) { int i; diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c index 5918d1b32e19..2748f9d77b18 100644 --- a/net/bpf/bpf_dummy_struct_ops.c +++ b/net/bpf/bpf_dummy_struct_ops.c @@ -101,12 +101,11 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, goto out; } - image = bpf_jit_alloc_exec(PAGE_SIZE); + image = arch_alloc_bpf_trampoline(PAGE_SIZE); if (!image) { err = -ENOMEM; goto out; } - set_vm_flush_reset_perms(image); link = kzalloc(sizeof(*link), GFP_USER); if (!link) { @@ -124,7 +123,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, if (err < 0) goto out; - set_memory_rox((long)image, 1); + arch_protect_bpf_trampoline(image, PAGE_SIZE); prog_ret = dummy_ops_call_op(image, args); err = dummy_ops_copy_args(args); @@ -134,7 +133,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, err = -EFAULT; out: kfree(args); - bpf_jit_free_exec(image); + arch_free_bpf_trampoline(image, PAGE_SIZE); if (link) bpf_link_put(&link->link); kfree(tlinks); From 38b8b58ae776bf748bd1bd7a24c3fd1d10f76f45 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:51 -0800 Subject: [PATCH 2901/7721] bpf, x86: Adjust arch_prepare_bpf_trampoline return value x86's implementation of arch_prepare_bpf_trampoline() requires BPF_INSN_SAFETY buffer space between end of program and image_end. OTOH, the return value does not include BPF_INSN_SAFETY. This doesn't cause any real issue at the moment. However, "image" of size retval is not enough for arch_prepare_bpf_trampoline(). This will cause confusion when we introduce a new helper arch_bpf_trampoline_size(). To avoid future confusion, adjust the return value to include BPF_INSN_SAFETY. Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20231206224054.492250-5-song@kernel.org Signed-off-by: Alexei Starovoitov --- arch/x86/net/bpf_jit_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 8c10d9abc239..5f7528cac344 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -2671,7 +2671,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i ret = -EFAULT; goto cleanup; } - ret = prog - (u8 *)image; + ret = prog - (u8 *)image + BPF_INSN_SAFETY; cleanup: kfree(branches); From 96d1b7c081c0c96cbe8901045f4ff15a2e9974a2 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:52 -0800 Subject: [PATCH 2902/7721] bpf: Add arch_bpf_trampoline_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helper will be used to calculate the size of the trampoline before allocating the memory. arch_prepare_bpf_trampoline() for arm64 and riscv64 can use arch_bpf_trampoline_size() to check the trampoline fits in the image. OTOH, arch_prepare_bpf_trampoline() for s390 has to call the JIT process twice, so it cannot use arch_bpf_trampoline_size(). Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Tested-by: Ilya Leoshkevich # on s390x Acked-by: Jiri Olsa Acked-by: Björn Töpel Tested-by: Björn Töpel # on riscv Link: https://lore.kernel.org/r/20231206224054.492250-6-song@kernel.org Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 56 ++++++++++++++++++++++++--------- arch/riscv/net/bpf_jit_comp64.c | 22 ++++++++++--- arch/s390/net/bpf_jit_comp.c | 56 ++++++++++++++++++++------------- arch/x86/net/bpf_jit_comp.c | 40 ++++++++++++++++++++--- include/linux/bpf.h | 2 ++ kernel/bpf/trampoline.c | 6 ++++ 6 files changed, 136 insertions(+), 46 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index d81b886ea4df..a6671253b7ed 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -2026,18 +2026,10 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, return ctx->idx; } -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, - void *image_end, const struct btf_func_model *m, - u32 flags, struct bpf_tramp_links *tlinks, - void *func_addr) +static int btf_func_model_nregs(const struct btf_func_model *m) { - int i, ret; int nregs = m->nr_args; - int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE; - struct jit_ctx ctx = { - .image = NULL, - .idx = 0, - }; + int i; /* extra registers needed for struct argument */ for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { @@ -2046,19 +2038,53 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, nregs += (m->arg_size[i] + 7) / 8 - 1; } + return nregs; +} + +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct jit_ctx ctx = { + .image = NULL, + .idx = 0, + }; + struct bpf_tramp_image im; + int nregs, ret; + + nregs = btf_func_model_nregs(m); /* the first 8 registers are used for arguments */ if (nregs > 8) return -ENOTSUPP; - ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); + ret = prepare_trampoline(&ctx, &im, tlinks, func_addr, nregs, flags); if (ret < 0) return ret; - if (ret > max_insns) - return -EFBIG; + return ret < 0 ? ret : ret * AARCH64_INSN_SIZE; +} - ctx.image = image; - ctx.idx = 0; +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, + void *image_end, const struct btf_func_model *m, + u32 flags, struct bpf_tramp_links *tlinks, + void *func_addr) +{ + int ret, nregs; + struct jit_ctx ctx = { + .image = image, + .idx = 0, + }; + + nregs = btf_func_model_nregs(m); + /* the first 8 registers are used for arguments */ + if (nregs > 8) + return -ENOTSUPP; + + ret = arch_bpf_trampoline_size(m, flags, tlinks, func_addr); + if (ret < 0) + return ret; + + if (ret > ((long)image_end - (long)image)) + return -EFBIG; jit_fill_hole(image, (unsigned int)(image_end - image)); ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 8581693e62d3..35747fafde57 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1029,6 +1029,21 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, return ret; } +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct bpf_tramp_image im; + struct rv_jit_context ctx; + int ret; + + ctx.ninsns = 0; + ctx.insns = NULL; + ctx.ro_insns = NULL; + ret = __arch_prepare_bpf_trampoline(&im, m, tlinks, func_addr, flags, &ctx); + + return ret < 0 ? ret : ninsns_rvoff(ctx.ninsns); +} + int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, @@ -1037,14 +1052,11 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, int ret; struct rv_jit_context ctx; - ctx.ninsns = 0; - ctx.insns = NULL; - ctx.ro_insns = NULL; - ret = __arch_prepare_bpf_trampoline(im, m, tlinks, func_addr, flags, &ctx); + ret = arch_bpf_trampoline_size(im, m, flags, tlinks, func_addr); if (ret < 0) return ret; - if (ninsns_rvoff(ret) > (long)image_end - (long)image) + if (ret > (long)image_end - (long)image) return -EFBIG; ctx.ninsns = 0; diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index bf06b7283f0c..cc129617480a 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -2637,6 +2637,21 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, return 0; } +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *orig_call) +{ + struct bpf_tramp_image im; + struct bpf_tramp_jit tjit; + int ret; + + memset(&tjit, 0, sizeof(tjit)); + + ret = __arch_prepare_bpf_trampoline(&im, &tjit, m, flags, + tlinks, orig_call); + + return ret < 0 ? ret : tjit.common.prg; +} + int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, @@ -2644,30 +2659,27 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, { struct bpf_tramp_jit tjit; int ret; - int i; - for (i = 0; i < 2; i++) { - if (i == 0) { - /* Compute offsets, check whether the code fits. */ - memset(&tjit, 0, sizeof(tjit)); - } else { - /* Generate the code. */ - tjit.common.prg = 0; - tjit.common.prg_buf = image; - } - ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, - tlinks, func_addr); - if (ret < 0) - return ret; - if (tjit.common.prg > (char *)image_end - (char *)image) - /* - * Use the same error code as for exceeding - * BPF_MAX_TRAMP_LINKS. - */ - return -E2BIG; - } + /* Compute offsets, check whether the code fits. */ + memset(&tjit, 0, sizeof(tjit)); + ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, + tlinks, func_addr); - return tjit.common.prg; + if (ret < 0) + return ret; + if (tjit.common.prg > (char *)image_end - (char *)image) + /* + * Use the same error code as for exceeding + * BPF_MAX_TRAMP_LINKS. + */ + return -E2BIG; + + tjit.common.prg = 0; + tjit.common.prg_buf = image; + ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, + tlinks, func_addr); + + return ret < 0 ? ret : tjit.common.prg; } bool bpf_jit_supports_subprog_tailcalls(void) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 5f7528cac344..5d75069fdcc2 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -2422,10 +2422,10 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, * add rsp, 8 // skip eth_type_trans's frame * ret // return to its caller */ -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, - const struct btf_func_model *m, u32 flags, - struct bpf_tramp_links *tlinks, - void *func_addr) +static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) { int i, ret, nr_regs = m->nr_args, stack_size = 0; int regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off, rbx_off; @@ -2678,6 +2678,38 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i return ret; } +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) +{ + return __arch_prepare_bpf_trampoline(im, image, image_end, m, flags, tlinks, func_addr); +} + +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct bpf_tramp_image im; + void *image; + int ret; + + /* Allocate a temporary buffer for __arch_prepare_bpf_trampoline(). + * This will NOT cause fragmentation in direct map, as we do not + * call set_memory_*() on this buffer. + * + * We cannot use kvmalloc here, because we need image to be in + * module memory range. + */ + image = bpf_jit_alloc_exec(PAGE_SIZE); + if (!image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, m, flags, + tlinks, func_addr); + bpf_jit_free_exec(image); + return ret; +} + static int emit_bpf_dispatcher(u8 **pprog, int a, int b, s64 *progs, u8 *image, u8 *buf) { u8 *jg_reloc, *prog = *pprog; diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b7fca151cf1b..2332ddeb396b 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1106,6 +1106,8 @@ void *arch_alloc_bpf_trampoline(unsigned int size); void arch_free_bpf_trampoline(void *image, unsigned int size); void arch_protect_bpf_trampoline(void *image, unsigned int size); void arch_unprotect_bpf_trampoline(void *image, unsigned int size); +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr); u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog, struct bpf_tramp_run_ctx *run_ctx); diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index affbcbf7e76e..b553cbd89e55 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -1072,6 +1072,12 @@ void __weak arch_unprotect_bpf_trampoline(void *image, unsigned int size) set_memory_rw((long)image, 1); } +int __weak arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + return -ENOTSUPP; +} + static int __init init_trampolines(void) { int i; From 26ef208c209a0e6eed8942a5d191b39dccfa6e38 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:53 -0800 Subject: [PATCH 2903/7721] bpf: Use arch_bpf_trampoline_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of blindly allocating PAGE_SIZE for each trampoline, check the size of the trampoline with arch_bpf_trampoline_size(). This size is saved in bpf_tramp_image->size, and used for modmem charge/uncharge. The fallback arch_alloc_bpf_trampoline() still allocates a whole page because we need to use set_memory_* to protect the memory. struct_ops trampoline still uses a whole page for multiple trampolines. With this size check at caller (regular trampoline and struct_ops trampoline), remove arch_bpf_trampoline_size() from arch_prepare_bpf_trampoline() in archs. Also, update bpf_image_ksym_add() to handle symbol of different sizes. Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Tested-by: Ilya Leoshkevich # on s390x Acked-by: Jiri Olsa Acked-by: Björn Töpel Tested-by: Björn Töpel # on riscv Link: https://lore.kernel.org/r/20231206224054.492250-7-song@kernel.org Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 7 ----- arch/riscv/net/bpf_jit_comp64.c | 7 ----- include/linux/bpf.h | 3 +- kernel/bpf/bpf_struct_ops.c | 7 +++++ kernel/bpf/dispatcher.c | 2 +- kernel/bpf/trampoline.c | 55 ++++++++++++++++++++------------- 6 files changed, 44 insertions(+), 37 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index a6671253b7ed..8955da5c47cf 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -2079,13 +2079,6 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, if (nregs > 8) return -ENOTSUPP; - ret = arch_bpf_trampoline_size(m, flags, tlinks, func_addr); - if (ret < 0) - return ret; - - if (ret > ((long)image_end - (long)image)) - return -EFBIG; - jit_fill_hole(image, (unsigned int)(image_end - image)); ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 35747fafde57..58dc64dd94a8 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1052,13 +1052,6 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, int ret; struct rv_jit_context ctx; - ret = arch_bpf_trampoline_size(im, m, flags, tlinks, func_addr); - if (ret < 0) - return ret; - - if (ret > (long)image_end - (long)image) - return -EFBIG; - ctx.ninsns = 0; /* * The bpf_int_jit_compile() uses a RW buffer (ctx.insns) to write the diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2332ddeb396b..c1a06263a4f3 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1141,6 +1141,7 @@ enum bpf_tramp_prog_type { struct bpf_tramp_image { void *image; + int size; struct bpf_ksym ksym; struct percpu_ref pcref; void *ip_after_call; @@ -1325,7 +1326,7 @@ int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_func void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, struct bpf_prog *to); /* Called only from JIT-enabled code, so there's no need for stubs. */ -void bpf_image_ksym_add(void *data, struct bpf_ksym *ksym); +void bpf_image_ksym_add(void *data, unsigned int size, struct bpf_ksym *ksym); void bpf_image_ksym_del(struct bpf_ksym *ksym); void bpf_ksym_add(struct bpf_ksym *ksym); void bpf_ksym_del(struct bpf_ksym *ksym); diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index e9e95879bce2..4d53c53fc5aa 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -355,6 +355,7 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, void *image, void *image_end) { u32 flags; + int size; tlinks[BPF_TRAMP_FENTRY].links[0] = link; tlinks[BPF_TRAMP_FENTRY].nr_links = 1; @@ -362,6 +363,12 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, * and it must be used alone. */ flags = model->ret_size > 0 ? BPF_TRAMP_F_RET_FENTRY_RET : 0; + + size = arch_bpf_trampoline_size(model, flags, tlinks, NULL); + if (size < 0) + return size; + if (size > (unsigned long)image_end - (unsigned long)image) + return -E2BIG; return arch_prepare_bpf_trampoline(NULL, image, image_end, model, flags, tlinks, NULL); } diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c index 56760fc10e78..70fb82bf1637 100644 --- a/kernel/bpf/dispatcher.c +++ b/kernel/bpf/dispatcher.c @@ -154,7 +154,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, d->image = NULL; goto out; } - bpf_image_ksym_add(d->image, &d->ksym); + bpf_image_ksym_add(d->image, PAGE_SIZE, &d->ksym); } prev_num_progs = d->num_progs; diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index b553cbd89e55..d382f5ebe06c 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -115,10 +115,10 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog) (ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC); } -void bpf_image_ksym_add(void *data, struct bpf_ksym *ksym) +void bpf_image_ksym_add(void *data, unsigned int size, struct bpf_ksym *ksym) { ksym->start = (unsigned long) data; - ksym->end = ksym->start + PAGE_SIZE; + ksym->end = ksym->start + size; bpf_ksym_add(ksym); perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_BPF, ksym->start, PAGE_SIZE, false, ksym->name); @@ -254,8 +254,8 @@ bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total, bool *ip_a static void bpf_tramp_image_free(struct bpf_tramp_image *im) { bpf_image_ksym_del(&im->ksym); - arch_free_bpf_trampoline(im->image, PAGE_SIZE); - bpf_jit_uncharge_modmem(PAGE_SIZE); + arch_free_bpf_trampoline(im->image, im->size); + bpf_jit_uncharge_modmem(im->size); percpu_ref_exit(&im->pcref); kfree_rcu(im, rcu); } @@ -349,7 +349,7 @@ static void bpf_tramp_image_put(struct bpf_tramp_image *im) call_rcu_tasks_trace(&im->rcu, __bpf_tramp_image_put_rcu_tasks); } -static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) +static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, int size) { struct bpf_tramp_image *im; struct bpf_ksym *ksym; @@ -360,12 +360,13 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) if (!im) goto out; - err = bpf_jit_charge_modmem(PAGE_SIZE); + err = bpf_jit_charge_modmem(size); if (err) goto out_free_im; + im->size = size; err = -ENOMEM; - im->image = image = arch_alloc_bpf_trampoline(PAGE_SIZE); + im->image = image = arch_alloc_bpf_trampoline(size); if (!image) goto out_uncharge; @@ -376,13 +377,13 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) ksym = &im->ksym; INIT_LIST_HEAD_RCU(&ksym->lnode); snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu", key); - bpf_image_ksym_add(image, ksym); + bpf_image_ksym_add(image, size, ksym); return im; out_free_image: - arch_free_bpf_trampoline(im->image, PAGE_SIZE); + arch_free_bpf_trampoline(im->image, im->size); out_uncharge: - bpf_jit_uncharge_modmem(PAGE_SIZE); + bpf_jit_uncharge_modmem(size); out_free_im: kfree(im); out: @@ -395,7 +396,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut struct bpf_tramp_links *tlinks; u32 orig_flags = tr->flags; bool ip_arg = false; - int err, total; + int err, total, size; tlinks = bpf_trampoline_get_progs(tr, &total, &ip_arg); if (IS_ERR(tlinks)) @@ -408,12 +409,6 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut goto out; } - im = bpf_tramp_image_alloc(tr->key); - if (IS_ERR(im)) { - err = PTR_ERR(im); - goto out; - } - /* clear all bits except SHARE_IPMODIFY and TAIL_CALL_CTX */ tr->flags &= (BPF_TRAMP_F_SHARE_IPMODIFY | BPF_TRAMP_F_TAIL_CALL_CTX); @@ -437,13 +432,31 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut tr->flags |= BPF_TRAMP_F_ORIG_STACK; #endif - err = arch_prepare_bpf_trampoline(im, im->image, im->image + PAGE_SIZE, + size = arch_bpf_trampoline_size(&tr->func.model, tr->flags, + tlinks, tr->func.addr); + if (size < 0) { + err = size; + goto out; + } + + if (size > PAGE_SIZE) { + err = -E2BIG; + goto out; + } + + im = bpf_tramp_image_alloc(tr->key, size); + if (IS_ERR(im)) { + err = PTR_ERR(im); + goto out; + } + + err = arch_prepare_bpf_trampoline(im, im->image, im->image + size, &tr->func.model, tr->flags, tlinks, tr->func.addr); if (err < 0) goto out_free; - arch_protect_bpf_trampoline(im->image, PAGE_SIZE); + arch_protect_bpf_trampoline(im->image, im->size); WARN_ON(tr->cur_image && total == 0); if (tr->cur_image) @@ -463,8 +476,8 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut tr->fops->func = NULL; tr->fops->trampoline = 0; - /* reset im->image memory attr for arch_prepare_bpf_trampoline */ - arch_unprotect_bpf_trampoline(im->image, PAGE_SIZE); + /* free im memory and reallocate later */ + bpf_tramp_image_free(im); goto again; } #endif From 3ba026fca8786161b0c4d75be396e61d6816e0a1 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 6 Dec 2023 14:40:54 -0800 Subject: [PATCH 2904/7721] x86, bpf: Use bpf_prog_pack for bpf trampoline There are three major changes here: 1. Add arch_[alloc|free]_bpf_trampoline based on bpf_prog_pack; 2. Let arch_prepare_bpf_trampoline handle ROX input image, this requires arch_prepare_bpf_trampoline allocating a temporary RW buffer; 3. Update __arch_prepare_bpf_trampoline() to handle a RW buffer (rw_image) and a ROX buffer (image). This part is similar to the image/rw_image logic in bpf_int_jit_compile(). Signed-off-by: Song Liu Acked-by: Ilya Leoshkevich Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20231206224054.492250-8-song@kernel.org Signed-off-by: Alexei Starovoitov --- arch/x86/net/bpf_jit_comp.c | 98 +++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 5d75069fdcc2..af4a5de7d93a 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -2198,7 +2198,8 @@ static void restore_regs(const struct btf_func_model *m, u8 **prog, static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_link *l, int stack_size, - int run_ctx_off, bool save_ret) + int run_ctx_off, bool save_ret, + void *image, void *rw_image) { u8 *prog = *pprog; u8 *jmp_insn; @@ -2226,7 +2227,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, else EMIT4(0x48, 0x8D, 0x75, -run_ctx_off); - if (emit_rsb_call(&prog, bpf_trampoline_enter(p), prog)) + if (emit_rsb_call(&prog, bpf_trampoline_enter(p), image + (prog - (u8 *)rw_image))) return -EINVAL; /* remember prog start time returned by __bpf_prog_enter */ emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); @@ -2250,7 +2251,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, (long) p->insnsi >> 32, (u32) (long) p->insnsi); /* call JITed bpf program or interpreter */ - if (emit_rsb_call(&prog, p->bpf_func, prog)) + if (emit_rsb_call(&prog, p->bpf_func, image + (prog - (u8 *)rw_image))) return -EINVAL; /* @@ -2277,7 +2278,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, EMIT3_off32(0x48, 0x8D, 0x95, -run_ctx_off); else EMIT4(0x48, 0x8D, 0x55, -run_ctx_off); - if (emit_rsb_call(&prog, bpf_trampoline_exit(p), prog)) + if (emit_rsb_call(&prog, bpf_trampoline_exit(p), image + (prog - (u8 *)rw_image))) return -EINVAL; *pprog = prog; @@ -2312,14 +2313,15 @@ static int emit_cond_near_jump(u8 **pprog, void *func, void *ip, u8 jmp_cond) static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_links *tl, int stack_size, - int run_ctx_off, bool save_ret) + int run_ctx_off, bool save_ret, + void *image, void *rw_image) { int i; u8 *prog = *pprog; for (i = 0; i < tl->nr_links; i++) { if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, - run_ctx_off, save_ret)) + run_ctx_off, save_ret, image, rw_image)) return -EINVAL; } *pprog = prog; @@ -2328,7 +2330,8 @@ static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_links *tl, int stack_size, - int run_ctx_off, u8 **branches) + int run_ctx_off, u8 **branches, + void *image, void *rw_image) { u8 *prog = *pprog; int i; @@ -2339,7 +2342,8 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, emit_mov_imm32(&prog, false, BPF_REG_0, 0); emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); for (i = 0; i < tl->nr_links; i++) { - if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true)) + if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true, + image, rw_image)) return -EINVAL; /* mod_ret prog stored return value into [rbp - 8]. Emit: @@ -2422,7 +2426,8 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, * add rsp, 8 // skip eth_type_trans's frame * ret // return to its caller */ -static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, +static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_image, + void *rw_image_end, void *image, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, void *func_addr) @@ -2521,7 +2526,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image orig_call += X86_PATCH_SIZE; } - prog = image; + prog = rw_image; EMIT_ENDBR(); /* @@ -2563,7 +2568,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image if (flags & BPF_TRAMP_F_CALL_ORIG) { /* arg1: mov rdi, im */ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); - if (emit_rsb_call(&prog, __bpf_tramp_enter, prog)) { + if (emit_rsb_call(&prog, __bpf_tramp_enter, + image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } @@ -2571,7 +2577,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image if (fentry->nr_links) if (invoke_bpf(m, &prog, fentry, regs_off, run_ctx_off, - flags & BPF_TRAMP_F_RET_FENTRY_RET)) + flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image)) return -EINVAL; if (fmod_ret->nr_links) { @@ -2581,7 +2587,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image return -ENOMEM; if (invoke_bpf_mod_ret(m, &prog, fmod_ret, regs_off, - run_ctx_off, branches)) { + run_ctx_off, branches, image, rw_image)) { ret = -EINVAL; goto cleanup; } @@ -2602,14 +2608,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image EMIT2(0xff, 0xd3); /* call *rbx */ } else { /* call original function */ - if (emit_rsb_call(&prog, orig_call, prog)) { + if (emit_rsb_call(&prog, orig_call, image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } } /* remember return value in a stack for bpf prog to access */ emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); - im->ip_after_call = prog; + im->ip_after_call = image + (prog - (u8 *)rw_image); memcpy(prog, x86_nops[5], X86_PATCH_SIZE); prog += X86_PATCH_SIZE; } @@ -2625,12 +2631,13 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image * aligned address of do_fexit. */ for (i = 0; i < fmod_ret->nr_links; i++) - emit_cond_near_jump(&branches[i], prog, branches[i], - X86_JNE); + emit_cond_near_jump(&branches[i], image + (prog - (u8 *)rw_image), + image + (branches[i] - (u8 *)rw_image), X86_JNE); } if (fexit->nr_links) - if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, false)) { + if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, + false, image, rw_image)) { ret = -EINVAL; goto cleanup; } @@ -2643,10 +2650,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image * restored to R0. */ if (flags & BPF_TRAMP_F_CALL_ORIG) { - im->ip_epilogue = prog; + im->ip_epilogue = image + (prog - (u8 *)rw_image); /* arg1: mov rdi, im */ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); - if (emit_rsb_call(&prog, __bpf_tramp_exit, prog)) { + if (emit_rsb_call(&prog, __bpf_tramp_exit, image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } @@ -2665,25 +2672,64 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image if (flags & BPF_TRAMP_F_SKIP_FRAME) /* skip our return address and return to parent */ EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */ - emit_return(&prog, prog); + emit_return(&prog, image + (prog - (u8 *)rw_image)); /* Make sure the trampoline generation logic doesn't overflow */ - if (WARN_ON_ONCE(prog > (u8 *)image_end - BPF_INSN_SAFETY)) { + if (WARN_ON_ONCE(prog > (u8 *)rw_image_end - BPF_INSN_SAFETY)) { ret = -EFAULT; goto cleanup; } - ret = prog - (u8 *)image + BPF_INSN_SAFETY; + ret = prog - (u8 *)rw_image + BPF_INSN_SAFETY; cleanup: kfree(branches); return ret; } +void *arch_alloc_bpf_trampoline(unsigned int size) +{ + return bpf_prog_pack_alloc(size, jit_fill_hole); +} + +void arch_free_bpf_trampoline(void *image, unsigned int size) +{ + bpf_prog_pack_free(image, size); +} + +void arch_protect_bpf_trampoline(void *image, unsigned int size) +{ +} + +void arch_unprotect_bpf_trampoline(void *image, unsigned int size) +{ +} + int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, void *func_addr) { - return __arch_prepare_bpf_trampoline(im, image, image_end, m, flags, tlinks, func_addr); + void *rw_image, *tmp; + int ret; + u32 size = image_end - image; + + /* rw_image doesn't need to be in module memory range, so we can + * use kvmalloc. + */ + rw_image = kvmalloc(size, GFP_KERNEL); + if (!rw_image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(im, rw_image, rw_image + size, image, m, + flags, tlinks, func_addr); + if (ret < 0) + goto out; + + tmp = bpf_arch_text_copy(image, rw_image, size); + if (IS_ERR(tmp)) + ret = PTR_ERR(tmp); +out: + kvfree(rw_image); + return ret; } int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, @@ -2704,8 +2750,8 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, if (!image) return -ENOMEM; - ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, m, flags, - tlinks, func_addr); + ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, image, + m, flags, tlinks, func_addr); bpf_jit_free_exec(image); return ret; } From 07bcbdf020c9fd3c14bec51c50225a2a02707b94 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 23 Nov 2023 09:48:09 -0800 Subject: [PATCH 2905/7721] xfs: don't leak recovered attri intent items If recovery finds an xattr log intent item calling for the removal of an attribute and the file doesn't even have an attr fork, we know that the removal is trivially complete. However, we can't just exit the recovery function without doing something about the recovered log intent item -- it's still on the AIL, and not logging an attrd item means it stays there forever. This has likely not been seen in practice because few people use LARP and the runtime code won't log the attri for a no-attrfork removexattr operation. But let's fix this anyway. Also we shouldn't really be testing the attr fork presence until we've taken the ILOCK, though this doesn't matter much in recovery, which is single threaded. Fixes: fdaf1bb3cafc ("xfs: ATTR_REPLACE algorithm with LARP enabled needs rework") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 36fe2abb16e6..11e88a76a33c 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -329,6 +329,13 @@ xfs_xattri_finish_update( goto out; } + /* If an attr removal is trivially complete, we're done. */ + if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE && + !xfs_inode_hasattr(args->dp)) { + error = 0; + goto out; + } + error = xfs_attr_set_iter(attr); if (!error && attr->xattri_dela_state != XFS_DAS_DONE) error = -EAGAIN; @@ -608,8 +615,6 @@ xfs_attri_item_recover( attr->xattri_dela_state = xfs_attr_init_add_state(args); break; case XFS_ATTRI_OP_FLAGS_REMOVE: - if (!xfs_inode_hasattr(args->dp)) - goto out; attr->xattri_dela_state = xfs_attr_init_remove_state(args); break; default: From 03f7767c9f6120ac933378fdec3bfd78bf07bc11 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 10:23:23 -0800 Subject: [PATCH 2906/7721] xfs: use xfs_defer_pending objects to recover intent items One thing I never quite got around to doing is porting the log intent item recovery code to reconstruct the deferred pending work state. As a result, each intent item open codes xfs_defer_finish_one in its recovery method, because that's what the EFI code did before xfs_defer.c even existed. This is a gross thing to have left unfixed -- if an EFI cannot proceed due to busy extents, we end up creating separate new EFIs for each unfinished work item, which is a change in behavior from what runtime would have done. Worse yet, Long Li pointed out that there's a UAF in the recovery code. The ->commit_pass2 function adds the intent item to the AIL and drops the refcount. The one remaining refcount is now owned by the recovery mechanism (aka the log intent items in the AIL) with the intent of giving the refcount to the intent done item in the ->iop_recover function. However, if something fails later in recovery, xlog_recover_finish will walk the recovered intent items in the AIL and release them. If the CIL hasn't been pushed before that point (which is possible since we don't force the log until later) then the intent done release will try to free its associated intent, which has already been freed. This patch starts to address this mess by having the ->commit_pass2 functions recreate the xfs_defer_pending state. The next few patches will fix the recovery functions. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 105 ++++++++++++++++++++++-------- fs/xfs/libxfs/xfs_defer.h | 5 ++ fs/xfs/libxfs/xfs_log_recover.h | 3 + fs/xfs/xfs_attr_item.c | 10 +-- fs/xfs/xfs_bmap_item.c | 9 +-- fs/xfs/xfs_extfree_item.c | 9 +-- fs/xfs/xfs_log.c | 1 + fs/xfs/xfs_log_priv.h | 1 + fs/xfs/xfs_log_recover.c | 111 ++++++++++++++++---------------- fs/xfs/xfs_refcount_item.c | 9 +-- fs/xfs/xfs_rmap_item.c | 9 +-- 11 files changed, 157 insertions(+), 115 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index f71679ce23b9..363da37a8e7f 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -245,23 +245,53 @@ xfs_defer_create_intents( return ret; } -STATIC void +static inline void xfs_defer_pending_abort( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp) +{ + const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; + + trace_xfs_defer_pending_abort(mp, dfp); + + if (dfp->dfp_intent && !dfp->dfp_done) { + ops->abort_intent(dfp->dfp_intent); + dfp->dfp_intent = NULL; + } +} + +static inline void +xfs_defer_pending_cancel_work( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp) +{ + const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; + struct list_head *pwi; + struct list_head *n; + + trace_xfs_defer_cancel_list(mp, dfp); + + list_del(&dfp->dfp_list); + list_for_each_safe(pwi, n, &dfp->dfp_work) { + list_del(pwi); + dfp->dfp_count--; + trace_xfs_defer_cancel_item(mp, dfp, pwi); + ops->cancel_item(pwi); + } + ASSERT(dfp->dfp_count == 0); + kmem_cache_free(xfs_defer_pending_cache, dfp); +} + +STATIC void +xfs_defer_pending_abort_list( struct xfs_mount *mp, struct list_head *dop_list) { struct xfs_defer_pending *dfp; - const struct xfs_defer_op_type *ops; /* Abort intent items that don't have a done item. */ - list_for_each_entry(dfp, dop_list, dfp_list) { - ops = defer_op_types[dfp->dfp_type]; - trace_xfs_defer_pending_abort(mp, dfp); - if (dfp->dfp_intent && !dfp->dfp_done) { - ops->abort_intent(dfp->dfp_intent); - dfp->dfp_intent = NULL; - } - } + list_for_each_entry(dfp, dop_list, dfp_list) + xfs_defer_pending_abort(mp, dfp); } /* Abort all the intents that were committed. */ @@ -271,7 +301,7 @@ xfs_defer_trans_abort( struct list_head *dop_pending) { trace_xfs_defer_trans_abort(tp, _RET_IP_); - xfs_defer_pending_abort(tp->t_mountp, dop_pending); + xfs_defer_pending_abort_list(tp->t_mountp, dop_pending); } /* @@ -389,27 +419,13 @@ xfs_defer_cancel_list( { struct xfs_defer_pending *dfp; struct xfs_defer_pending *pli; - struct list_head *pwi; - struct list_head *n; - const struct xfs_defer_op_type *ops; /* * Free the pending items. Caller should already have arranged * for the intent items to be released. */ - list_for_each_entry_safe(dfp, pli, dop_list, dfp_list) { - ops = defer_op_types[dfp->dfp_type]; - trace_xfs_defer_cancel_list(mp, dfp); - list_del(&dfp->dfp_list); - list_for_each_safe(pwi, n, &dfp->dfp_work) { - list_del(pwi); - dfp->dfp_count--; - trace_xfs_defer_cancel_item(mp, dfp, pwi); - ops->cancel_item(pwi); - } - ASSERT(dfp->dfp_count == 0); - kmem_cache_free(xfs_defer_pending_cache, dfp); - } + list_for_each_entry_safe(dfp, pli, dop_list, dfp_list) + xfs_defer_pending_cancel_work(mp, dfp); } /* @@ -665,6 +681,39 @@ xfs_defer_add( dfp->dfp_count++; } +/* + * Create a pending deferred work item to replay the recovered intent item + * and add it to the list. + */ +void +xfs_defer_start_recovery( + struct xfs_log_item *lip, + enum xfs_defer_ops_type dfp_type, + struct list_head *r_dfops) +{ + struct xfs_defer_pending *dfp; + + dfp = kmem_cache_zalloc(xfs_defer_pending_cache, + GFP_NOFS | __GFP_NOFAIL); + dfp->dfp_type = dfp_type; + dfp->dfp_intent = lip; + INIT_LIST_HEAD(&dfp->dfp_work); + list_add_tail(&dfp->dfp_list, r_dfops); +} + +/* + * Cancel a deferred work item created to recover a log intent item. @dfp + * will be freed after this function returns. + */ +void +xfs_defer_cancel_recovery( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp) +{ + xfs_defer_pending_abort(mp, dfp); + xfs_defer_pending_cancel_work(mp, dfp); +} + /* * Move deferred ops from one transaction to another and reset the source to * initial state. This is primarily used to carry state forward across @@ -769,7 +818,7 @@ xfs_defer_ops_capture_abort( { unsigned short i; - xfs_defer_pending_abort(mp, &dfc->dfc_dfops); + xfs_defer_pending_abort_list(mp, &dfc->dfc_dfops); xfs_defer_cancel_list(mp, &dfc->dfc_dfops); for (i = 0; i < dfc->dfc_held.dr_bufs; i++) diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index 8788ad5f6a73..5dce938ba3d5 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -125,6 +125,11 @@ void xfs_defer_ops_capture_abort(struct xfs_mount *mp, struct xfs_defer_capture *d); void xfs_defer_resources_rele(struct xfs_defer_resources *dres); +void xfs_defer_start_recovery(struct xfs_log_item *lip, + enum xfs_defer_ops_type dfp_type, struct list_head *r_dfops); +void xfs_defer_cancel_recovery(struct xfs_mount *mp, + struct xfs_defer_pending *dfp); + int __init xfs_defer_init_item_caches(void); void xfs_defer_destroy_item_caches(void); diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index a5100a11faf9..271a4ce7375c 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -153,4 +153,7 @@ xlog_recover_resv(const struct xfs_trans_res *r) return ret; } +void xlog_recover_intent_item(struct xlog *log, struct xfs_log_item *lip, + xfs_lsn_t lsn, unsigned int dfp_type); + #endif /* __XFS_LOG_RECOVER_H__ */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 11e88a76a33c..a32716b8cbbd 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -772,14 +772,8 @@ xlog_recover_attri_commit_pass2( attrip = xfs_attri_init(mp, nv); memcpy(&attrip->attri_format, attri_formatp, len); - /* - * The ATTRI has two references. One for the ATTRD and one for ATTRI to - * ensure it makes it into the AIL. Insert the ATTRI into the AIL - * directly and drop the ATTRI reference. Note that - * xfs_trans_ail_update() drops the AIL lock. - */ - xfs_trans_ail_insert(log->l_ailp, &attrip->attri_item, lsn); - xfs_attri_release(attrip); + xlog_recover_intent_item(log, &attrip->attri_item, lsn, + XFS_DEFER_OPS_TYPE_ATTR); xfs_attri_log_nameval_put(nv); return 0; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index e736a0844c89..6cbae4fdf43f 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -681,12 +681,9 @@ xlog_recover_bui_commit_pass2( buip = xfs_bui_init(mp); xfs_bui_copy_format(&buip->bui_format, bui_formatp); atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents); - /* - * Insert the intent into the AIL directly and drop one reference so - * that finishing or canceling the work will drop the other. - */ - xfs_trans_ail_insert(log->l_ailp, &buip->bui_item, lsn); - xfs_bui_release(buip); + + xlog_recover_intent_item(log, &buip->bui_item, lsn, + XFS_DEFER_OPS_TYPE_BMAP); return 0; } diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 3fa8789820ad..cf0ddeb70580 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -820,12 +820,9 @@ xlog_recover_efi_commit_pass2( return error; } atomic_set(&efip->efi_next_extent, efi_formatp->efi_nextents); - /* - * Insert the intent into the AIL directly and drop one reference so - * that finishing or canceling the work will drop the other. - */ - xfs_trans_ail_insert(log->l_ailp, &efip->efi_item, lsn); - xfs_efi_release(efip); + + xlog_recover_intent_item(log, &efip->efi_item, lsn, + XFS_DEFER_OPS_TYPE_FREE); return 0; } diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index ee206facf0dc..a1650fc81382 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -1542,6 +1542,7 @@ xlog_alloc_log( log->l_covered_state = XLOG_STATE_COVER_IDLE; set_bit(XLOG_ACTIVE_RECOVERY, &log->l_opstate); INIT_DELAYED_WORK(&log->l_work, xfs_log_worker); + INIT_LIST_HEAD(&log->r_dfops); log->l_prev_block = -1; /* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */ diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index fa3ad1d7b31c..e30c06ec20e3 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -407,6 +407,7 @@ struct xlog { long l_opstate; /* operational state */ uint l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */ struct list_head *l_buf_cancel_table; + struct list_head r_dfops; /* recovered log intent items */ int l_iclog_hsize; /* size of iclog header */ int l_iclog_heads; /* # of iclog header sectors */ uint l_sectBBsize; /* sector size in BBs (2^n) */ diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index a1e18b24971a..b9d2152a2bad 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1723,30 +1723,24 @@ xlog_clear_stale_blocks( */ void xlog_recover_release_intent( - struct xlog *log, - unsigned short intent_type, - uint64_t intent_id) + struct xlog *log, + unsigned short intent_type, + uint64_t intent_id) { - struct xfs_ail_cursor cur; - struct xfs_log_item *lip; - struct xfs_ail *ailp = log->l_ailp; + struct xfs_defer_pending *dfp, *n; + + list_for_each_entry_safe(dfp, n, &log->r_dfops, dfp_list) { + struct xfs_log_item *lip = dfp->dfp_intent; - spin_lock(&ailp->ail_lock); - for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); lip != NULL; - lip = xfs_trans_ail_cursor_next(ailp, &cur)) { if (lip->li_type != intent_type) continue; if (!lip->li_ops->iop_match(lip, intent_id)) continue; - spin_unlock(&ailp->ail_lock); - lip->li_ops->iop_release(lip); - spin_lock(&ailp->ail_lock); - break; - } + ASSERT(xlog_item_is_intent(lip)); - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->ail_lock); + xfs_defer_cancel_recovery(log->l_mp, dfp); + } } int @@ -1939,6 +1933,29 @@ xlog_buf_readahead( xfs_buf_readahead(log->l_mp->m_ddev_targp, blkno, len, ops); } +/* + * Create a deferred work structure for resuming and tracking the progress of a + * log intent item that was found during recovery. + */ +void +xlog_recover_intent_item( + struct xlog *log, + struct xfs_log_item *lip, + xfs_lsn_t lsn, + unsigned int dfp_type) +{ + ASSERT(xlog_item_is_intent(lip)); + + xfs_defer_start_recovery(lip, dfp_type, &log->r_dfops); + + /* + * Insert the intent into the AIL directly and drop one reference so + * that finishing or canceling the work will drop the other. + */ + xfs_trans_ail_insert(log->l_ailp, lip, lsn); + lip->li_ops->iop_unpin(lip, 0); +} + STATIC int xlog_recover_items_pass2( struct xlog *log, @@ -2533,29 +2550,22 @@ xlog_abort_defer_ops( */ STATIC int xlog_recover_process_intents( - struct xlog *log) + struct xlog *log) { LIST_HEAD(capture_list); - struct xfs_ail_cursor cur; - struct xfs_log_item *lip; - struct xfs_ail *ailp; - int error = 0; + struct xfs_defer_pending *dfp, *n; + int error = 0; #if defined(DEBUG) || defined(XFS_WARN) - xfs_lsn_t last_lsn; -#endif + xfs_lsn_t last_lsn; - ailp = log->l_ailp; - spin_lock(&ailp->ail_lock); -#if defined(DEBUG) || defined(XFS_WARN) last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block); #endif - for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - lip != NULL; - lip = xfs_trans_ail_cursor_next(ailp, &cur)) { - const struct xfs_item_ops *ops; - if (!xlog_item_is_intent(lip)) - break; + list_for_each_entry_safe(dfp, n, &log->r_dfops, dfp_list) { + struct xfs_log_item *lip = dfp->dfp_intent; + const struct xfs_item_ops *ops = lip->li_ops; + + ASSERT(xlog_item_is_intent(lip)); /* * We should never see a redo item with a LSN higher than @@ -2573,19 +2583,22 @@ xlog_recover_process_intents( * The recovery function can free the log item, so we must not * access lip after it returns. */ - spin_unlock(&ailp->ail_lock); - ops = lip->li_ops; error = ops->iop_recover(lip, &capture_list); - spin_lock(&ailp->ail_lock); if (error) { trace_xlog_intent_recovery_failed(log->l_mp, error, ops->iop_recover); break; } - } - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->ail_lock); + /* + * XXX: @lip could have been freed, so detach the log item from + * the pending item before freeing the pending item. This does + * not fix the existing UAF bug that occurs if ->iop_recover + * fails after creating the intent done item. + */ + dfp->dfp_intent = NULL; + xfs_defer_cancel_recovery(log->l_mp, dfp); + } if (error) goto err; @@ -2606,27 +2619,15 @@ xlog_recover_process_intents( */ STATIC void xlog_recover_cancel_intents( - struct xlog *log) + struct xlog *log) { - struct xfs_log_item *lip; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp; + struct xfs_defer_pending *dfp, *n; - ailp = log->l_ailp; - spin_lock(&ailp->ail_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - if (!xlog_item_is_intent(lip)) - break; + list_for_each_entry_safe(dfp, n, &log->r_dfops, dfp_list) { + ASSERT(xlog_item_is_intent(dfp->dfp_intent)); - spin_unlock(&ailp->ail_lock); - lip->li_ops->iop_release(lip); - spin_lock(&ailp->ail_lock); - lip = xfs_trans_ail_cursor_next(ailp, &cur); + xfs_defer_cancel_recovery(log->l_mp, dfp); } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->ail_lock); } /* diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 2d4444d61e98..b88cb2e98227 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -696,12 +696,9 @@ xlog_recover_cui_commit_pass2( cuip = xfs_cui_init(mp, cui_formatp->cui_nextents); xfs_cui_copy_format(&cuip->cui_format, cui_formatp); atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents); - /* - * Insert the intent into the AIL directly and drop one reference so - * that finishing or canceling the work will drop the other. - */ - xfs_trans_ail_insert(log->l_ailp, &cuip->cui_item, lsn); - xfs_cui_release(cuip); + + xlog_recover_intent_item(log, &cuip->cui_item, lsn, + XFS_DEFER_OPS_TYPE_REFCOUNT); return 0; } diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 0e0e747028da..c30d4a4a14b2 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -702,12 +702,9 @@ xlog_recover_rui_commit_pass2( ruip = xfs_rui_init(mp, rui_formatp->rui_nextents); xfs_rui_copy_format(&ruip->rui_format, rui_formatp); atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents); - /* - * Insert the intent into the AIL directly and drop one reference so - * that finishing or canceling the work will drop the other. - */ - xfs_trans_ail_insert(log->l_ailp, &ruip->rui_item, lsn); - xfs_rui_release(ruip); + + xlog_recover_intent_item(log, &ruip->rui_item, lsn, + XFS_DEFER_OPS_TYPE_RMAP); return 0; } From a050acdfa8003a44eae4558fddafc7afb1aef458 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 10:38:10 -0800 Subject: [PATCH 2907/7721] xfs: pass the xfs_defer_pending object to iop_recover Now that log intent item recovery recreates the xfs_defer_pending state, we should pass that into the ->iop_recover routines so that the intent item can finish the recreation work. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 3 ++- fs/xfs/xfs_bmap_item.c | 3 ++- fs/xfs/xfs_extfree_item.c | 3 ++- fs/xfs/xfs_log_recover.c | 2 +- fs/xfs/xfs_refcount_item.c | 3 ++- fs/xfs/xfs_rmap_item.c | 3 ++- fs/xfs/xfs_trans.h | 4 +++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index a32716b8cbbd..6119a7a480a0 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -545,9 +545,10 @@ xfs_attri_validate( */ STATIC int xfs_attri_item_recover( - struct xfs_log_item *lip, + struct xfs_defer_pending *dfp, struct list_head *capture_list) { + struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); struct xfs_attr_intent *attr; struct xfs_mount *mp = lip->li_log->l_mp; diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 6cbae4fdf43f..3ef55de370b5 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -486,11 +486,12 @@ xfs_bui_validate( */ STATIC int xfs_bui_item_recover( - struct xfs_log_item *lip, + struct xfs_defer_pending *dfp, struct list_head *capture_list) { struct xfs_bmap_intent fake = { }; struct xfs_trans_res resv; + struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_bui_log_item *buip = BUI_ITEM(lip); struct xfs_trans *tp; struct xfs_inode *ip = NULL; diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index cf0ddeb70580..a8245c5ffe49 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -657,10 +657,11 @@ xfs_efi_validate_ext( */ STATIC int xfs_efi_item_recover( - struct xfs_log_item *lip, + struct xfs_defer_pending *dfp, struct list_head *capture_list) { struct xfs_trans_res resv; + struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_efi_log_item *efip = EFI_ITEM(lip); struct xfs_mount *mp = lip->li_log->l_mp; struct xfs_efd_log_item *efdp; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index b9d2152a2bad..ff768217f2c7 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2583,7 +2583,7 @@ xlog_recover_process_intents( * The recovery function can free the log item, so we must not * access lip after it returns. */ - error = ops->iop_recover(lip, &capture_list); + error = ops->iop_recover(dfp, &capture_list); if (error) { trace_xlog_intent_recovery_failed(log->l_mp, error, ops->iop_recover); diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index b88cb2e98227..3456201aa3e6 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -474,10 +474,11 @@ xfs_cui_validate_phys( */ STATIC int xfs_cui_item_recover( - struct xfs_log_item *lip, + struct xfs_defer_pending *dfp, struct list_head *capture_list) { struct xfs_trans_res resv; + struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_cui_log_item *cuip = CUI_ITEM(lip); struct xfs_cud_log_item *cudp; struct xfs_trans *tp; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index c30d4a4a14b2..dfd5a3e4b1fb 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -504,10 +504,11 @@ xfs_rui_validate_map( */ STATIC int xfs_rui_item_recover( - struct xfs_log_item *lip, + struct xfs_defer_pending *dfp, struct list_head *capture_list) { struct xfs_trans_res resv; + struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_rui_log_item *ruip = RUI_ITEM(lip); struct xfs_rud_log_item *rudp; struct xfs_trans *tp; diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 6e3646d524ce..4e38357237c3 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -66,6 +66,8 @@ struct xfs_log_item { { (1u << XFS_LI_DIRTY), "DIRTY" }, \ { (1u << XFS_LI_WHITEOUT), "WHITEOUT" } +struct xfs_defer_pending; + struct xfs_item_ops { unsigned flags; void (*iop_size)(struct xfs_log_item *, int *, int *); @@ -78,7 +80,7 @@ struct xfs_item_ops { xfs_lsn_t (*iop_committed)(struct xfs_log_item *, xfs_lsn_t); uint (*iop_push)(struct xfs_log_item *, struct list_head *); void (*iop_release)(struct xfs_log_item *); - int (*iop_recover)(struct xfs_log_item *lip, + int (*iop_recover)(struct xfs_defer_pending *dfp, struct list_head *capture_list); bool (*iop_match)(struct xfs_log_item *item, uint64_t id); struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent, From deb4cd8ba87f17b12c72b3827820d9c703e9fd95 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 10:47:10 -0800 Subject: [PATCH 2908/7721] xfs: transfer recovered intent item ownership in ->iop_recover Now that we pass the xfs_defer_pending object into the intent item recovery functions, we know exactly when ownership of the sole refcount passes from the recovery context to the intent done item. At that point, we need to null out dfp_intent so that the recovery mechanism won't release it. This should fix the UAF problem reported by Long Li. Note that we still want to recreate the full deferred work state. That will be addressed in the next patches. Fixes: 2e76f188fd90 ("xfs: cancel intents immediately if process_intents fails") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_log_recover.h | 2 ++ fs/xfs/xfs_attr_item.c | 1 + fs/xfs/xfs_bmap_item.c | 2 ++ fs/xfs/xfs_extfree_item.c | 2 ++ fs/xfs/xfs_log_recover.c | 19 ++++++++++++------- fs/xfs/xfs_refcount_item.c | 1 + fs/xfs/xfs_rmap_item.c | 2 ++ 7 files changed, 22 insertions(+), 7 deletions(-) diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index 271a4ce7375c..13583df9f239 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -155,5 +155,7 @@ xlog_recover_resv(const struct xfs_trans_res *r) void xlog_recover_intent_item(struct xlog *log, struct xfs_log_item *lip, xfs_lsn_t lsn, unsigned int dfp_type); +void xlog_recover_transfer_intent(struct xfs_trans *tp, + struct xfs_defer_pending *dfp); #endif /* __XFS_LOG_RECOVER_H__ */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 6119a7a480a0..82775e9537df 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -632,6 +632,7 @@ xfs_attri_item_recover( args->trans = tp; done_item = xfs_trans_get_attrd(tp, attrip); + xlog_recover_transfer_intent(tp, dfp); xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 3ef55de370b5..b6d63b8bdad5 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -524,6 +524,8 @@ xfs_bui_item_recover( goto err_rele; budp = xfs_trans_get_bud(tp, buip); + xlog_recover_transfer_intent(tp, dfp); + xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index a8245c5ffe49..c9908fb33765 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -689,7 +689,9 @@ xfs_efi_item_recover( error = xfs_trans_alloc(mp, &resv, 0, 0, 0, &tp); if (error) return error; + efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); + xlog_recover_transfer_intent(tp, dfp); for (i = 0; i < efip->efi_format.efi_nextents; i++) { struct xfs_extent_free_item fake = { diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index ff768217f2c7..cc14cd1c2282 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2590,13 +2590,6 @@ xlog_recover_process_intents( break; } - /* - * XXX: @lip could have been freed, so detach the log item from - * the pending item before freeing the pending item. This does - * not fix the existing UAF bug that occurs if ->iop_recover - * fails after creating the intent done item. - */ - dfp->dfp_intent = NULL; xfs_defer_cancel_recovery(log->l_mp, dfp); } if (error) @@ -2630,6 +2623,18 @@ xlog_recover_cancel_intents( } } +/* + * Transfer ownership of the recovered log intent item to the recovery + * transaction. + */ +void +xlog_recover_transfer_intent( + struct xfs_trans *tp, + struct xfs_defer_pending *dfp) +{ + dfp->dfp_intent = NULL; +} + /* * This routine performs a transaction to null out a bad inode pointer * in an agi unlinked inode hash bucket. diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 3456201aa3e6..f1b259223802 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -523,6 +523,7 @@ xfs_cui_item_recover( return error; cudp = xfs_trans_get_cud(tp, cuip); + xlog_recover_transfer_intent(tp, dfp); for (i = 0; i < cuip->cui_format.cui_nextents; i++) { struct xfs_refcount_intent fake = { }; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index dfd5a3e4b1fb..5e8a02d2b045 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -537,7 +537,9 @@ xfs_rui_item_recover( XFS_TRANS_RESERVE, &tp); if (error) return error; + rudp = xfs_trans_get_rud(tp, ruip); + xlog_recover_transfer_intent(tp, dfp); for (i = 0; i < ruip->rui_format.rui_nextents; i++) { struct xfs_rmap_intent fake = { }; From e70fb328d5277297ea2d9169a3a046de6412d777 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 11:13:03 -0800 Subject: [PATCH 2909/7721] xfs: recreate work items when recovering intent items Recreate work items for each xfs_defer_pending object when we are recovering intent items. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 3 +- fs/xfs/libxfs/xfs_defer.h | 9 +++ fs/xfs/xfs_attr_item.c | 90 ++++++++++++++++------------- fs/xfs/xfs_bmap_item.c | 55 +++++++++++------- fs/xfs/xfs_extfree_item.c | 49 +++++++++------- fs/xfs/xfs_refcount_item.c | 60 ++++++++++---------- fs/xfs/xfs_rmap_item.c | 112 ++++++++++++++++++++----------------- 7 files changed, 215 insertions(+), 163 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 363da37a8e7f..8fb523e4f669 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -676,9 +676,8 @@ xfs_defer_add( list_add_tail(&dfp->dfp_list, &tp->t_dfops); } - list_add_tail(li, &dfp->dfp_work); + xfs_defer_add_item(dfp, li); trace_xfs_defer_add_item(tp->t_mountp, dfp, li); - dfp->dfp_count++; } /* diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index 5dce938ba3d5..bef5823f61fb 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -130,6 +130,15 @@ void xfs_defer_start_recovery(struct xfs_log_item *lip, void xfs_defer_cancel_recovery(struct xfs_mount *mp, struct xfs_defer_pending *dfp); +static inline void +xfs_defer_add_item( + struct xfs_defer_pending *dfp, + struct list_head *work) +{ + list_add_tail(work, &dfp->dfp_work); + dfp->dfp_count++; +} + int __init xfs_defer_init_item_caches(void); void xfs_defer_destroy_item_caches(void); diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 82775e9537df..c4441eacf51c 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -539,42 +539,17 @@ xfs_attri_validate( return xfs_verify_ino(mp, attrp->alfi_ino); } -/* - * Process an attr intent item that was recovered from the log. We need to - * delete the attr that it describes. - */ -STATIC int -xfs_attri_item_recover( +static inline struct xfs_attr_intent * +xfs_attri_recover_work( + struct xfs_mount *mp, struct xfs_defer_pending *dfp, - struct list_head *capture_list) + struct xfs_attri_log_format *attrp, + struct xfs_inode *ip, + struct xfs_attri_log_nameval *nv) { - struct xfs_log_item *lip = dfp->dfp_intent; - struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); struct xfs_attr_intent *attr; - struct xfs_mount *mp = lip->li_log->l_mp; - struct xfs_inode *ip; struct xfs_da_args *args; - struct xfs_trans *tp; - struct xfs_trans_res resv; - struct xfs_attri_log_format *attrp; - struct xfs_attri_log_nameval *nv = attrip->attri_nameval; - int error; - int total; int local; - struct xfs_attrd_log_item *done_item = NULL; - - /* - * First check the validity of the attr described by the ATTRI. If any - * are bad, then assume that all are bad and just toss the ATTRI. - */ - attrp = &attrip->attri_format; - if (!xfs_attri_validate(mp, attrp) || - !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) - return -EFSCORRUPTED; - - error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); - if (error) - return error; attr = kmem_zalloc(sizeof(struct xfs_attr_intent) + sizeof(struct xfs_da_args), KM_NOFS); @@ -618,19 +593,58 @@ xfs_attri_item_recover( case XFS_ATTRI_OP_FLAGS_REMOVE: attr->xattri_dela_state = xfs_attr_init_remove_state(args); break; - default: - ASSERT(0); - error = -EFSCORRUPTED; - goto out; } + xfs_defer_add_item(dfp, &attr->xattri_list); + return attr; +} + +/* + * Process an attr intent item that was recovered from the log. We need to + * delete the attr that it describes. + */ +STATIC int +xfs_attri_item_recover( + struct xfs_defer_pending *dfp, + struct list_head *capture_list) +{ + struct xfs_log_item *lip = dfp->dfp_intent; + struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); + struct xfs_attr_intent *attr; + struct xfs_mount *mp = lip->li_log->l_mp; + struct xfs_inode *ip; + struct xfs_da_args *args; + struct xfs_trans *tp; + struct xfs_trans_res resv; + struct xfs_attri_log_format *attrp; + struct xfs_attri_log_nameval *nv = attrip->attri_nameval; + int error; + int total; + struct xfs_attrd_log_item *done_item = NULL; + + /* + * First check the validity of the attr described by the ATTRI. If any + * are bad, then assume that all are bad and just toss the ATTRI. + */ + attrp = &attrip->attri_format; + if (!xfs_attri_validate(mp, attrp) || + !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) + return -EFSCORRUPTED; + + error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); + if (error) + return error; + + attr = xfs_attri_recover_work(mp, dfp, attrp, ip, nv); + args = attr->xattri_da_args; + xfs_init_attr_trans(args, &resv, &total); resv = xlog_recover_resv(&resv); error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp); if (error) - goto out; - + return error; args->trans = tp; + done_item = xfs_trans_get_attrd(tp, attrip); xlog_recover_transfer_intent(tp, dfp); @@ -661,8 +675,6 @@ xfs_attri_item_recover( out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_irele(ip); -out: - xfs_attr_free_item(attr); return error; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index b6d63b8bdad5..b65999bf0ea3 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -480,6 +480,28 @@ xfs_bui_validate( return xfs_verify_fsbext(mp, map->me_startblock, map->me_len); } +static inline struct xfs_bmap_intent * +xfs_bui_recover_work( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp, + struct xfs_map_extent *map) +{ + struct xfs_bmap_intent *bi; + + bi = kmem_cache_zalloc(xfs_bmap_intent_cache, GFP_NOFS | __GFP_NOFAIL); + bi->bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + bi->bi_type = map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; + bi->bi_bmap.br_startblock = map->me_startblock; + bi->bi_bmap.br_startoff = map->me_startoff; + bi->bi_bmap.br_blockcount = map->me_len; + bi->bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? + XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + + xfs_defer_add_item(dfp, &bi->bi_list); + return bi; +} + /* * Process a bmap update intent item that was recovered from the log. * We need to update some inode's bmbt. @@ -489,7 +511,6 @@ xfs_bui_item_recover( struct xfs_defer_pending *dfp, struct list_head *capture_list) { - struct xfs_bmap_intent fake = { }; struct xfs_trans_res resv; struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_bui_log_item *buip = BUI_ITEM(lip); @@ -498,6 +519,7 @@ xfs_bui_item_recover( struct xfs_mount *mp = lip->li_log->l_mp; struct xfs_map_extent *map; struct xfs_bud_log_item *budp; + struct xfs_bmap_intent *fake; int iext_delta; int error = 0; @@ -508,9 +530,7 @@ xfs_bui_item_recover( } map = &buip->bui_format.bui_extents[0]; - fake.bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? - XFS_ATTR_FORK : XFS_DATA_FORK; - fake.bi_type = map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; + fake = xfs_bui_recover_work(mp, dfp, map); error = xlog_recover_iget(mp, map->me_owner, &ip); if (error) @@ -529,36 +549,31 @@ xfs_bui_item_recover( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - if (fake.bi_type == XFS_BMAP_MAP) + if (fake->bi_type == XFS_BMAP_MAP) iext_delta = XFS_IEXT_ADD_NOSPLIT_CNT; else iext_delta = XFS_IEXT_PUNCH_HOLE_CNT; - error = xfs_iext_count_may_overflow(ip, fake.bi_whichfork, iext_delta); + error = xfs_iext_count_may_overflow(ip, fake->bi_whichfork, iext_delta); if (error == -EFBIG) error = xfs_iext_count_upgrade(tp, ip, iext_delta); if (error) goto err_cancel; - fake.bi_owner = ip; - fake.bi_bmap.br_startblock = map->me_startblock; - fake.bi_bmap.br_startoff = map->me_startoff; - fake.bi_bmap.br_blockcount = map->me_len; - fake.bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? - XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + fake->bi_owner = ip; - xfs_bmap_update_get_group(mp, &fake); - error = xfs_trans_log_finish_bmap_update(tp, budp, &fake); + xfs_bmap_update_get_group(mp, fake); + error = xfs_trans_log_finish_bmap_update(tp, budp, fake); if (error == -EFSCORRUPTED) - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, map, - sizeof(*map)); - xfs_bmap_update_put_group(&fake); + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &buip->bui_format, sizeof(buip->bui_format)); + xfs_bmap_update_put_group(fake); if (error) goto err_cancel; - if (fake.bi_bmap.br_blockcount > 0) { - ASSERT(fake.bi_type == XFS_BMAP_UNMAP); - xfs_bmap_unmap_extent(tp, ip, &fake.bi_bmap); + if (fake->bi_bmap.br_blockcount > 0) { + ASSERT(fake->bi_type == XFS_BMAP_UNMAP); + xfs_bmap_unmap_extent(tp, ip, &fake->bi_bmap); } /* diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index c9908fb33765..41108a0b60c9 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -651,6 +651,24 @@ xfs_efi_validate_ext( return xfs_verify_fsbext(mp, extp->ext_start, extp->ext_len); } +static inline void +xfs_efi_recover_work( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp, + struct xfs_extent *extp) +{ + struct xfs_extent_free_item *xefi; + + xefi = kmem_cache_zalloc(xfs_extfree_item_cache, + GFP_KERNEL | __GFP_NOFAIL); + xefi->xefi_startblock = extp->ext_start; + xefi->xefi_blockcount = extp->ext_len; + xefi->xefi_agresv = XFS_AG_RESV_NONE; + xefi->xefi_owner = XFS_RMAP_OWN_UNKNOWN; + + xfs_defer_add_item(dfp, &xefi->xefi_list); +} + /* * Process an extent free intent item that was recovered from * the log. We need to free the extents that it describes. @@ -666,6 +684,7 @@ xfs_efi_item_recover( struct xfs_mount *mp = lip->li_log->l_mp; struct xfs_efd_log_item *efdp; struct xfs_trans *tp; + struct xfs_extent_free_item *fake; int i; int error = 0; bool requeue_only = false; @@ -683,6 +702,8 @@ xfs_efi_item_recover( sizeof(efip->efi_format)); return -EFSCORRUPTED; } + + xfs_efi_recover_work(mp, dfp, &efip->efi_format.efi_extents[i]); } resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate); @@ -693,22 +714,11 @@ xfs_efi_item_recover( efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); xlog_recover_transfer_intent(tp, dfp); - for (i = 0; i < efip->efi_format.efi_nextents; i++) { - struct xfs_extent_free_item fake = { - .xefi_owner = XFS_RMAP_OWN_UNKNOWN, - .xefi_agresv = XFS_AG_RESV_NONE, - }; - struct xfs_extent *extp; - - extp = &efip->efi_format.efi_extents[i]; - - fake.xefi_startblock = extp->ext_start; - fake.xefi_blockcount = extp->ext_len; - + list_for_each_entry(fake, &dfp->dfp_work, xefi_list) { if (!requeue_only) { - xfs_extent_free_get_group(mp, &fake); - error = xfs_trans_free_extent(tp, efdp, &fake); - xfs_extent_free_put_group(&fake); + xfs_extent_free_get_group(mp, fake); + error = xfs_trans_free_extent(tp, efdp, fake); + xfs_extent_free_put_group(fake); } /* @@ -717,10 +727,10 @@ xfs_efi_item_recover( * run again later with a new transaction context. */ if (error == -EAGAIN || requeue_only) { - error = xfs_free_extent_later(tp, fake.xefi_startblock, - fake.xefi_blockcount, + error = xfs_free_extent_later(tp, fake->xefi_startblock, + fake->xefi_blockcount, &XFS_RMAP_OINFO_ANY_OWNER, - fake.xefi_agresv); + fake->xefi_agresv); if (!error) { requeue_only = true; continue; @@ -729,7 +739,8 @@ xfs_efi_item_recover( if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - extp, sizeof(*extp)); + &efip->efi_format, + sizeof(efip->efi_format)); if (error) goto abort_error; diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index f1b259223802..4ffc34e6f0a0 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -468,6 +468,23 @@ xfs_cui_validate_phys( return xfs_verify_fsbext(mp, pmap->pe_startblock, pmap->pe_len); } +static inline void +xfs_cui_recover_work( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp, + struct xfs_phys_extent *pmap) +{ + struct xfs_refcount_intent *ri; + + ri = kmem_cache_alloc(xfs_refcount_intent_cache, + GFP_NOFS | __GFP_NOFAIL); + ri->ri_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK; + ri->ri_startblock = pmap->pe_startblock; + ri->ri_blockcount = pmap->pe_len; + + xfs_defer_add_item(dfp, &ri->ri_list); +} + /* * Process a refcount update intent item that was recovered from the log. * We need to update the refcountbt. @@ -484,7 +501,7 @@ xfs_cui_item_recover( struct xfs_trans *tp; struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_log->l_mp; - unsigned int refc_type; + struct xfs_refcount_intent *fake; bool requeue_only = false; int i; int error = 0; @@ -502,6 +519,8 @@ xfs_cui_item_recover( sizeof(cuip->cui_format)); return -EFSCORRUPTED; } + + xfs_cui_recover_work(mp, dfp, &cuip->cui_format.cui_extents[i]); } /* @@ -525,35 +544,12 @@ xfs_cui_item_recover( cudp = xfs_trans_get_cud(tp, cuip); xlog_recover_transfer_intent(tp, dfp); - for (i = 0; i < cuip->cui_format.cui_nextents; i++) { - struct xfs_refcount_intent fake = { }; - struct xfs_phys_extent *pmap; - - pmap = &cuip->cui_format.cui_extents[i]; - refc_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK; - switch (refc_type) { - case XFS_REFCOUNT_INCREASE: - case XFS_REFCOUNT_DECREASE: - case XFS_REFCOUNT_ALLOC_COW: - case XFS_REFCOUNT_FREE_COW: - fake.ri_type = refc_type; - break; - default: - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - &cuip->cui_format, - sizeof(cuip->cui_format)); - error = -EFSCORRUPTED; - goto abort_error; - } - - fake.ri_startblock = pmap->pe_startblock; - fake.ri_blockcount = pmap->pe_len; - + list_for_each_entry(fake, &dfp->dfp_work, ri_list) { if (!requeue_only) { - xfs_refcount_update_get_group(mp, &fake); + xfs_refcount_update_get_group(mp, fake); error = xfs_trans_log_finish_refcount_update(tp, cudp, - &fake, &rcur); - xfs_refcount_update_put_group(&fake); + fake, &rcur); + xfs_refcount_update_put_group(fake); } if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, @@ -563,13 +559,13 @@ xfs_cui_item_recover( goto abort_error; /* Requeue what we didn't finish. */ - if (fake.ri_blockcount > 0) { + if (fake->ri_blockcount > 0) { struct xfs_bmbt_irec irec = { - .br_startblock = fake.ri_startblock, - .br_blockcount = fake.ri_blockcount, + .br_startblock = fake->ri_startblock, + .br_blockcount = fake->ri_blockcount, }; - switch (fake.ri_type) { + switch (fake->ri_type) { case XFS_REFCOUNT_INCREASE: xfs_refcount_increase_extent(tp, &irec); break; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 5e8a02d2b045..9fb3ae4bfd59 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -498,6 +498,58 @@ xfs_rui_validate_map( return xfs_verify_fsbext(mp, map->me_startblock, map->me_len); } +static inline void +xfs_rui_recover_work( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp, + const struct xfs_map_extent *map) +{ + struct xfs_rmap_intent *ri; + + ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL); + + switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { + case XFS_RMAP_EXTENT_MAP: + ri->ri_type = XFS_RMAP_MAP; + break; + case XFS_RMAP_EXTENT_MAP_SHARED: + ri->ri_type = XFS_RMAP_MAP_SHARED; + break; + case XFS_RMAP_EXTENT_UNMAP: + ri->ri_type = XFS_RMAP_UNMAP; + break; + case XFS_RMAP_EXTENT_UNMAP_SHARED: + ri->ri_type = XFS_RMAP_UNMAP_SHARED; + break; + case XFS_RMAP_EXTENT_CONVERT: + ri->ri_type = XFS_RMAP_CONVERT; + break; + case XFS_RMAP_EXTENT_CONVERT_SHARED: + ri->ri_type = XFS_RMAP_CONVERT_SHARED; + break; + case XFS_RMAP_EXTENT_ALLOC: + ri->ri_type = XFS_RMAP_ALLOC; + break; + case XFS_RMAP_EXTENT_FREE: + ri->ri_type = XFS_RMAP_FREE; + break; + default: + ASSERT(0); + return; + } + + ri->ri_owner = map->me_owner; + ri->ri_whichfork = (map->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + ri->ri_bmap.br_startblock = map->me_startblock; + ri->ri_bmap.br_startoff = map->me_startoff; + ri->ri_bmap.br_blockcount = map->me_len; + ri->ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? + XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + + xfs_defer_add_item(dfp, &ri->ri_list); +} + /* * Process an rmap update intent item that was recovered from the log. * We need to update the rmapbt. @@ -514,6 +566,7 @@ xfs_rui_item_recover( struct xfs_trans *tp; struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_log->l_mp; + struct xfs_rmap_intent *fake; int i; int error = 0; @@ -530,6 +583,8 @@ xfs_rui_item_recover( sizeof(ruip->rui_format)); return -EFSCORRUPTED; } + + xfs_rui_recover_work(mp, dfp, &ruip->rui_format.rui_extents[i]); } resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate); @@ -541,60 +596,15 @@ xfs_rui_item_recover( rudp = xfs_trans_get_rud(tp, ruip); xlog_recover_transfer_intent(tp, dfp); - for (i = 0; i < ruip->rui_format.rui_nextents; i++) { - struct xfs_rmap_intent fake = { }; - struct xfs_map_extent *map; - - map = &ruip->rui_format.rui_extents[i]; - switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { - case XFS_RMAP_EXTENT_MAP: - fake.ri_type = XFS_RMAP_MAP; - break; - case XFS_RMAP_EXTENT_MAP_SHARED: - fake.ri_type = XFS_RMAP_MAP_SHARED; - break; - case XFS_RMAP_EXTENT_UNMAP: - fake.ri_type = XFS_RMAP_UNMAP; - break; - case XFS_RMAP_EXTENT_UNMAP_SHARED: - fake.ri_type = XFS_RMAP_UNMAP_SHARED; - break; - case XFS_RMAP_EXTENT_CONVERT: - fake.ri_type = XFS_RMAP_CONVERT; - break; - case XFS_RMAP_EXTENT_CONVERT_SHARED: - fake.ri_type = XFS_RMAP_CONVERT_SHARED; - break; - case XFS_RMAP_EXTENT_ALLOC: - fake.ri_type = XFS_RMAP_ALLOC; - break; - case XFS_RMAP_EXTENT_FREE: - fake.ri_type = XFS_RMAP_FREE; - break; - default: - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - &ruip->rui_format, - sizeof(ruip->rui_format)); - error = -EFSCORRUPTED; - goto abort_error; - } - - fake.ri_owner = map->me_owner; - fake.ri_whichfork = (map->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ? - XFS_ATTR_FORK : XFS_DATA_FORK; - fake.ri_bmap.br_startblock = map->me_startblock; - fake.ri_bmap.br_startoff = map->me_startoff; - fake.ri_bmap.br_blockcount = map->me_len; - fake.ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? - XFS_EXT_UNWRITTEN : XFS_EXT_NORM; - - xfs_rmap_update_get_group(mp, &fake); - error = xfs_trans_log_finish_rmap_update(tp, rudp, &fake, + list_for_each_entry(fake, &dfp->dfp_work, ri_list) { + xfs_rmap_update_get_group(mp, fake); + error = xfs_trans_log_finish_rmap_update(tp, rudp, fake, &rcur); if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - map, sizeof(*map)); - xfs_rmap_update_put_group(&fake); + &ruip->rui_format, + sizeof(ruip->rui_format)); + xfs_rmap_update_put_group(fake); if (error) goto abort_error; From a51489e140d302c7afae763eacf882a23513f7e4 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 09:57:42 -0800 Subject: [PATCH 2910/7721] xfs: dump the recovered xattri log item if corruption happens If xfs_attri_item_recover receives a corruption error when it tries to finish a recovered log intent item, it should dump the log item for debugging, just like all the other log intent items. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index c4441eacf51c..c7c308d2f897 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -666,6 +666,10 @@ xfs_attri_item_recover( xfs_irele(ip); return 0; } + if (error == -EFSCORRUPTED) + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &attrip->attri_format, + sizeof(attrip->attri_format)); if (error) { xfs_trans_cancel(tp); goto out_unlock; From 172538beba82e7b65d3d7c84cb558f287381cd7a Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 10:27:10 -0800 Subject: [PATCH 2911/7721] xfs: don't set XFS_TRANS_HAS_INTENT_DONE when there's no ATTRD log item XFS_TRANS_HAS_INTENT_DONE is a flag to the CIL that we've added a log intent done item to the transaction. This enables an optimization wherein we avoid writing out log intent and log intent done items if they would have ended up in the same checkpoint. This reduces writes to the ondisk log and speeds up recovery as a result. However, callers can use the defer ops machinery to modify xattrs without using the log items. In this situation, there won't be an intent done item, so we do not need to set the flag. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index bd23c9594a0d..d19a385f9289 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -347,13 +347,15 @@ xfs_xattri_finish_update( * 1.) releases the ATTRI and frees the ATTRD * 2.) shuts down the filesystem */ - args->trans->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; + args->trans->t_flags |= XFS_TRANS_DIRTY; /* * attr intent/done items are null when logged attributes are disabled */ - if (attrdp) + if (attrdp) { + args->trans->t_flags |= XFS_TRANS_HAS_INTENT_DONE; set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags); + } return error; } From e5f1a5146ec35f3ed5d7f5ac7807a10c0062b6b8 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 11:25:45 -0800 Subject: [PATCH 2912/7721] xfs: use xfs_defer_finish_one to finish recovered work items Get rid of the open-coded calls to xfs_defer_finish_one. This also means that the recovery transaction takes care of cleaning up the dfp, and we have solved (I hope) all the ownership issues in recovery. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 2 +- fs/xfs/libxfs/xfs_defer.h | 1 + fs/xfs/libxfs/xfs_log_recover.h | 2 +- fs/xfs/xfs_attr_item.c | 20 +---------- fs/xfs/xfs_bmap_item.c | 24 ++++--------- fs/xfs/xfs_extfree_item.c | 45 +++++------------------- fs/xfs/xfs_log_recover.c | 22 +++++++----- fs/xfs/xfs_refcount_item.c | 61 +++++---------------------------- fs/xfs/xfs_rmap_item.c | 29 +++++----------- 9 files changed, 49 insertions(+), 157 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 8fb523e4f669..eb262ea06122 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -484,7 +484,7 @@ xfs_defer_relog( * Log an intent-done item for the first pending intent, and finish the work * items. */ -static int +int xfs_defer_finish_one( struct xfs_trans *tp, struct xfs_defer_pending *dfp) diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index bef5823f61fb..c1a648e99174 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -41,6 +41,7 @@ void xfs_defer_add(struct xfs_trans *tp, enum xfs_defer_ops_type type, struct list_head *h); int xfs_defer_finish_noroll(struct xfs_trans **tp); int xfs_defer_finish(struct xfs_trans **tp); +int xfs_defer_finish_one(struct xfs_trans *tp, struct xfs_defer_pending *dfp); void xfs_defer_cancel(struct xfs_trans *); void xfs_defer_move(struct xfs_trans *dtp, struct xfs_trans *stp); diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index 13583df9f239..52162a17fc5e 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -155,7 +155,7 @@ xlog_recover_resv(const struct xfs_trans_res *r) void xlog_recover_intent_item(struct xlog *log, struct xfs_log_item *lip, xfs_lsn_t lsn, unsigned int dfp_type); -void xlog_recover_transfer_intent(struct xfs_trans *tp, +int xlog_recover_finish_intent(struct xfs_trans *tp, struct xfs_defer_pending *dfp); #endif /* __XFS_LOG_RECOVER_H__ */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index c7c308d2f897..eaf8a877c2cc 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -620,7 +620,6 @@ xfs_attri_item_recover( struct xfs_attri_log_nameval *nv = attrip->attri_nameval; int error; int total; - struct xfs_attrd_log_item *done_item = NULL; /* * First check the validity of the attr described by the ATTRI. If any @@ -645,27 +644,10 @@ xfs_attri_item_recover( return error; args->trans = tp; - done_item = xfs_trans_get_attrd(tp, attrip); - xlog_recover_transfer_intent(tp, dfp); - xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_xattri_finish_update(attr, done_item); - if (error == -EAGAIN) { - /* - * There's more work to do, so add the intent item to this - * transaction so that we can continue it later. - */ - xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &attr->xattri_list); - error = xfs_defer_ops_capture_and_commit(tp, capture_list); - if (error) - goto out_unlock; - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - xfs_irele(ip); - return 0; - } + error = xlog_recover_finish_intent(tp, dfp); if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, &attrip->attri_format, diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index b65999bf0ea3..89f2d9e89607 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -497,6 +497,7 @@ xfs_bui_recover_work( bi->bi_bmap.br_blockcount = map->me_len; bi->bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + xfs_bmap_update_get_group(mp, bi); xfs_defer_add_item(dfp, &bi->bi_list); return bi; @@ -518,8 +519,7 @@ xfs_bui_item_recover( struct xfs_inode *ip = NULL; struct xfs_mount *mp = lip->li_log->l_mp; struct xfs_map_extent *map; - struct xfs_bud_log_item *budp; - struct xfs_bmap_intent *fake; + struct xfs_bmap_intent *work; int iext_delta; int error = 0; @@ -530,7 +530,7 @@ xfs_bui_item_recover( } map = &buip->bui_format.bui_extents[0]; - fake = xfs_bui_recover_work(mp, dfp, map); + work = xfs_bui_recover_work(mp, dfp, map); error = xlog_recover_iget(mp, map->me_owner, &ip); if (error) @@ -543,39 +543,29 @@ xfs_bui_item_recover( if (error) goto err_rele; - budp = xfs_trans_get_bud(tp, buip); - xlog_recover_transfer_intent(tp, dfp); - xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - if (fake->bi_type == XFS_BMAP_MAP) + if (work->bi_type == XFS_BMAP_MAP) iext_delta = XFS_IEXT_ADD_NOSPLIT_CNT; else iext_delta = XFS_IEXT_PUNCH_HOLE_CNT; - error = xfs_iext_count_may_overflow(ip, fake->bi_whichfork, iext_delta); + error = xfs_iext_count_may_overflow(ip, work->bi_whichfork, iext_delta); if (error == -EFBIG) error = xfs_iext_count_upgrade(tp, ip, iext_delta); if (error) goto err_cancel; - fake->bi_owner = ip; + work->bi_owner = ip; - xfs_bmap_update_get_group(mp, fake); - error = xfs_trans_log_finish_bmap_update(tp, budp, fake); + error = xlog_recover_finish_intent(tp, dfp); if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, &buip->bui_format, sizeof(buip->bui_format)); - xfs_bmap_update_put_group(fake); if (error) goto err_cancel; - if (fake->bi_bmap.br_blockcount > 0) { - ASSERT(fake->bi_type == XFS_BMAP_UNMAP); - xfs_bmap_unmap_extent(tp, ip, &fake->bi_bmap); - } - /* * Commit transaction, which frees the transaction and saves the inode * for later replay activities. diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 41108a0b60c9..6a434ade486c 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -665,6 +665,7 @@ xfs_efi_recover_work( xefi->xefi_blockcount = extp->ext_len; xefi->xefi_agresv = XFS_AG_RESV_NONE; xefi->xefi_owner = XFS_RMAP_OWN_UNKNOWN; + xfs_extent_free_get_group(mp, xefi); xfs_defer_add_item(dfp, &xefi->xefi_list); } @@ -682,12 +683,9 @@ xfs_efi_item_recover( struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_efi_log_item *efip = EFI_ITEM(lip); struct xfs_mount *mp = lip->li_log->l_mp; - struct xfs_efd_log_item *efdp; struct xfs_trans *tp; - struct xfs_extent_free_item *fake; int i; int error = 0; - bool requeue_only = false; /* * First check the validity of the extents described by the @@ -711,40 +709,13 @@ xfs_efi_item_recover( if (error) return error; - efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); - xlog_recover_transfer_intent(tp, dfp); - - list_for_each_entry(fake, &dfp->dfp_work, xefi_list) { - if (!requeue_only) { - xfs_extent_free_get_group(mp, fake); - error = xfs_trans_free_extent(tp, efdp, fake); - xfs_extent_free_put_group(fake); - } - - /* - * If we can't free the extent without potentially deadlocking, - * requeue the rest of the extents to a new so that they get - * run again later with a new transaction context. - */ - if (error == -EAGAIN || requeue_only) { - error = xfs_free_extent_later(tp, fake->xefi_startblock, - fake->xefi_blockcount, - &XFS_RMAP_OINFO_ANY_OWNER, - fake->xefi_agresv); - if (!error) { - requeue_only = true; - continue; - } - } - - if (error == -EFSCORRUPTED) - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - &efip->efi_format, - sizeof(efip->efi_format)); - if (error) - goto abort_error; - - } + error = xlog_recover_finish_intent(tp, dfp); + if (error == -EFSCORRUPTED) + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &efip->efi_format, + sizeof(efip->efi_format)); + if (error) + goto abort_error; return xfs_defer_ops_capture_and_commit(tp, capture_list); diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index cc14cd1c2282..6fab490959d4 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2581,7 +2581,8 @@ xlog_recover_process_intents( * replayed in the wrong order! * * The recovery function can free the log item, so we must not - * access lip after it returns. + * access lip after it returns. It must dispose of @dfp if it + * returns 0. */ error = ops->iop_recover(dfp, &capture_list); if (error) { @@ -2589,8 +2590,6 @@ xlog_recover_process_intents( ops->iop_recover); break; } - - xfs_defer_cancel_recovery(log->l_mp, dfp); } if (error) goto err; @@ -2624,15 +2623,22 @@ xlog_recover_cancel_intents( } /* - * Transfer ownership of the recovered log intent item to the recovery - * transaction. + * Transfer ownership of the recovered pending work to the recovery transaction + * and try to finish the work. If there is more work to be done, the dfp will + * remain attached to the transaction. If not, the dfp is freed. */ -void -xlog_recover_transfer_intent( +int +xlog_recover_finish_intent( struct xfs_trans *tp, struct xfs_defer_pending *dfp) { - dfp->dfp_intent = NULL; + int error; + + list_move(&dfp->dfp_list, &tp->t_dfops); + error = xfs_defer_finish_one(tp, dfp); + if (error == -EAGAIN) + return 0; + return error; } /* diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 4ffc34e6f0a0..f561ca73c784 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -481,6 +481,7 @@ xfs_cui_recover_work( ri->ri_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK; ri->ri_startblock = pmap->pe_startblock; ri->ri_blockcount = pmap->pe_len; + xfs_refcount_update_get_group(mp, ri); xfs_defer_add_item(dfp, &ri->ri_list); } @@ -497,12 +498,8 @@ xfs_cui_item_recover( struct xfs_trans_res resv; struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_cui_log_item *cuip = CUI_ITEM(lip); - struct xfs_cud_log_item *cudp; struct xfs_trans *tp; - struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_log->l_mp; - struct xfs_refcount_intent *fake; - bool requeue_only = false; int i; int error = 0; @@ -541,59 +538,17 @@ xfs_cui_item_recover( if (error) return error; - cudp = xfs_trans_get_cud(tp, cuip); - xlog_recover_transfer_intent(tp, dfp); + error = xlog_recover_finish_intent(tp, dfp); + if (error == -EFSCORRUPTED) + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &cuip->cui_format, + sizeof(cuip->cui_format)); + if (error) + goto abort_error; - list_for_each_entry(fake, &dfp->dfp_work, ri_list) { - if (!requeue_only) { - xfs_refcount_update_get_group(mp, fake); - error = xfs_trans_log_finish_refcount_update(tp, cudp, - fake, &rcur); - xfs_refcount_update_put_group(fake); - } - if (error == -EFSCORRUPTED) - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - &cuip->cui_format, - sizeof(cuip->cui_format)); - if (error) - goto abort_error; - - /* Requeue what we didn't finish. */ - if (fake->ri_blockcount > 0) { - struct xfs_bmbt_irec irec = { - .br_startblock = fake->ri_startblock, - .br_blockcount = fake->ri_blockcount, - }; - - switch (fake->ri_type) { - case XFS_REFCOUNT_INCREASE: - xfs_refcount_increase_extent(tp, &irec); - break; - case XFS_REFCOUNT_DECREASE: - xfs_refcount_decrease_extent(tp, &irec); - break; - case XFS_REFCOUNT_ALLOC_COW: - xfs_refcount_alloc_cow_extent(tp, - irec.br_startblock, - irec.br_blockcount); - break; - case XFS_REFCOUNT_FREE_COW: - xfs_refcount_free_cow_extent(tp, - irec.br_startblock, - irec.br_blockcount); - break; - default: - ASSERT(0); - } - requeue_only = true; - } - } - - xfs_refcount_finish_one_cleanup(tp, rcur, error); return xfs_defer_ops_capture_and_commit(tp, capture_list); abort_error: - xfs_refcount_finish_one_cleanup(tp, rcur, error); xfs_trans_cancel(tp); return error; } diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 9fb3ae4bfd59..23e736179894 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -546,6 +546,7 @@ xfs_rui_recover_work( ri->ri_bmap.br_blockcount = map->me_len; ri->ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + xfs_rmap_update_get_group(mp, ri); xfs_defer_add_item(dfp, &ri->ri_list); } @@ -562,11 +563,8 @@ xfs_rui_item_recover( struct xfs_trans_res resv; struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_rui_log_item *ruip = RUI_ITEM(lip); - struct xfs_rud_log_item *rudp; struct xfs_trans *tp; - struct xfs_btree_cur *rcur = NULL; struct xfs_mount *mp = lip->li_log->l_mp; - struct xfs_rmap_intent *fake; int i; int error = 0; @@ -593,28 +591,17 @@ xfs_rui_item_recover( if (error) return error; - rudp = xfs_trans_get_rud(tp, ruip); - xlog_recover_transfer_intent(tp, dfp); + error = xlog_recover_finish_intent(tp, dfp); + if (error == -EFSCORRUPTED) + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + &ruip->rui_format, + sizeof(ruip->rui_format)); + if (error) + goto abort_error; - list_for_each_entry(fake, &dfp->dfp_work, ri_list) { - xfs_rmap_update_get_group(mp, fake); - error = xfs_trans_log_finish_rmap_update(tp, rudp, fake, - &rcur); - if (error == -EFSCORRUPTED) - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - &ruip->rui_format, - sizeof(ruip->rui_format)); - xfs_rmap_update_put_group(fake); - if (error) - goto abort_error; - - } - - xfs_rmap_finish_one_cleanup(tp, rcur, error); return xfs_defer_ops_capture_and_commit(tp, capture_list); abort_error: - xfs_rmap_finish_one_cleanup(tp, rcur, error); xfs_trans_cancel(tp); return error; } From 3dd75c8db1c1675a26d3e228bab349c1fc065867 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 10:45:28 -0800 Subject: [PATCH 2913/7721] xfs: hoist intent done flag setting to ->finish_item callsite Each log intent item's ->finish_item call chain inevitably includes some code to set the dirty flag of the transaction. If there's an associated log intent done item, it also sets the item's dirty flag and the transaction's INTENT_DONE flag. This is repeated throughout the codebase. Reduce the LOC by moving all that to xfs_defer_finish_one. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 28 +++++++++++++++++++++++++++- fs/xfs/xfs_attr_item.c | 30 ++++-------------------------- fs/xfs/xfs_bmap_item.c | 16 +--------------- fs/xfs/xfs_extfree_item.c | 20 -------------------- fs/xfs/xfs_refcount_item.c | 16 +--------------- fs/xfs/xfs_rmap_item.c | 16 +--------------- 6 files changed, 34 insertions(+), 92 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index dd565e4e3daf..6214abedf394 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -191,6 +191,32 @@ static const struct xfs_defer_op_type *defer_op_types[] = { [XFS_DEFER_OPS_TYPE_ATTR] = &xfs_attr_defer_type, }; +/* Create a log intent done item for a log intent item. */ +static inline void +xfs_defer_create_done( + struct xfs_trans *tp, + struct xfs_defer_pending *dfp) +{ + const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; + struct xfs_log_item *lip; + + /* + * Mark the transaction dirty, even on error. This ensures the + * transaction is aborted, which: + * + * 1.) releases the log intent item and frees the log done item + * 2.) shuts down the filesystem + */ + tp->t_flags |= XFS_TRANS_DIRTY; + lip = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count); + if (!lip) + return; + + tp->t_flags |= XFS_TRANS_HAS_INTENT_DONE; + set_bit(XFS_LI_DIRTY, &lip->li_flags); + dfp->dfp_done = lip; +} + /* * Ensure there's a log intent item associated with this deferred work item if * the operation must be restarted on crash. Returns 1 if there's a log item; @@ -496,7 +522,7 @@ xfs_defer_finish_one( trace_xfs_defer_pending_finish(tp->t_mountp, dfp); - dfp->dfp_done = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count); + xfs_defer_create_done(tp, dfp); list_for_each_safe(li, n, &dfp->dfp_work) { list_del(li); dfp->dfp_count--; diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index d19a385f9289..e7acbb736bee 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -324,39 +324,17 @@ xfs_xattri_finish_update( struct xfs_da_args *args = attr->xattri_da_args; int error; - if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) { - error = -EIO; - goto out; - } + if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) + return -EIO; /* If an attr removal is trivially complete, we're done. */ if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE && - !xfs_inode_hasattr(args->dp)) { - error = 0; - goto out; - } + !xfs_inode_hasattr(args->dp)) + return 0; error = xfs_attr_set_iter(attr); if (!error && attr->xattri_dela_state != XFS_DAS_DONE) error = -EAGAIN; -out: - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the ATTRI and frees the ATTRD - * 2.) shuts down the filesystem - */ - args->trans->t_flags |= XFS_TRANS_DIRTY; - - /* - * attr intent/done items are null when logged attributes are disabled - */ - if (attrdp) { - args->trans->t_flags |= XFS_TRANS_HAS_INTENT_DONE; - set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags); - } - return error; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index bd8f6fe22b40..913315cb5123 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -249,21 +249,7 @@ xfs_trans_log_finish_bmap_update( struct xfs_bud_log_item *budp, struct xfs_bmap_intent *bi) { - int error; - - error = xfs_bmap_finish_one(tp, bi); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the BUI and frees the BUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; - set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags); - - return error; + return xfs_bmap_finish_one(tp, bi); } /* Sort bmap intents by inode. */ diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 49e96ffd64e0..e8e02f816cbe 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -396,16 +396,6 @@ xfs_trans_free_extent( xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv, xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the EFI and frees the EFD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; - set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags); - /* * If we need a new transaction to make progress, the caller will log a * new EFI with the current contents. It will also log an EFD to cancel @@ -601,16 +591,6 @@ xfs_agfl_free_finish_item( error = xfs_free_agfl_block(tp, xefi->xefi_pag->pag_agno, agbno, agbp, &oinfo); - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the EFI and frees the EFD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags); - next_extent = efdp->efd_next_extent; ASSERT(next_extent < efdp->efd_format.efd_nextents); extp = &(efdp->efd_format.efd_extents[next_extent]); diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 48f1a38b272e..2628b1e3969c 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -256,21 +256,7 @@ xfs_trans_log_finish_refcount_update( struct xfs_refcount_intent *ri, struct xfs_btree_cur **pcur) { - int error; - - error = xfs_refcount_finish_one(tp, ri, pcur); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the CUI and frees the CUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; - set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags); - - return error; + return xfs_refcount_finish_one(tp, ri, pcur); } /* Sort refcount intents by AG. */ diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 23684bc2ab85..8f216a13a7f2 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -297,21 +297,7 @@ xfs_trans_log_finish_rmap_update( struct xfs_rmap_intent *ri, struct xfs_btree_cur **pcur) { - int error; - - error = xfs_rmap_finish_one(tp, ri, pcur); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the RUI and frees the RUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; - set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags); - - return error; + return xfs_rmap_finish_one(tp, ri, pcur); } /* Sort rmap intents by AG. */ From db7ccc0bac2add5a41b66578e376b49328fc99d0 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 22 Nov 2023 13:39:25 -0800 Subject: [PATCH 2914/7721] xfs: move ->iop_recover to xfs_defer_op_type Finish off the series by moving the intent item recovery function pointer to the xfs_defer_op_type struct, since this is really a deferred work function now. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 17 +++++++++++++ fs/xfs/libxfs/xfs_defer.h | 4 +++ fs/xfs/libxfs/xfs_log_recover.h | 2 ++ fs/xfs/xfs_attr_item.c | 21 +++++++++------- fs/xfs/xfs_bmap_item.c | 39 ++++++++++++++++-------------- fs/xfs/xfs_extfree_item.c | 43 +++++++++++++++++---------------- fs/xfs/xfs_log_recover.c | 19 ++++++--------- fs/xfs/xfs_refcount_item.c | 24 +++++++++--------- fs/xfs/xfs_rmap_item.c | 24 +++++++++--------- fs/xfs/xfs_trans.h | 4 --- 10 files changed, 109 insertions(+), 88 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index eb262ea06122..dd565e4e3daf 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -713,6 +713,23 @@ xfs_defer_cancel_recovery( xfs_defer_pending_cancel_work(mp, dfp); } +/* Replay the deferred work item created from a recovered log intent item. */ +int +xfs_defer_finish_recovery( + struct xfs_mount *mp, + struct xfs_defer_pending *dfp, + struct list_head *capture_list) +{ + const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; + int error; + + error = ops->recover_work(dfp, capture_list); + if (error) + trace_xlog_intent_recovery_failed(mp, error, + ops->recover_work); + return error; +} + /* * Move deferred ops from one transaction to another and reset the source to * initial state. This is primarily used to carry state forward across diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index c1a648e99174..ef86a7f9b059 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -57,6 +57,8 @@ struct xfs_defer_op_type { void (*finish_cleanup)(struct xfs_trans *tp, struct xfs_btree_cur *state, int error); void (*cancel_item)(struct list_head *item); + int (*recover_work)(struct xfs_defer_pending *dfp, + struct list_head *capture_list); unsigned int max_items; }; @@ -130,6 +132,8 @@ void xfs_defer_start_recovery(struct xfs_log_item *lip, enum xfs_defer_ops_type dfp_type, struct list_head *r_dfops); void xfs_defer_cancel_recovery(struct xfs_mount *mp, struct xfs_defer_pending *dfp); +int xfs_defer_finish_recovery(struct xfs_mount *mp, + struct xfs_defer_pending *dfp, struct list_head *capture_list); static inline void xfs_defer_add_item( diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index 52162a17fc5e..c8e5d912895b 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -153,6 +153,8 @@ xlog_recover_resv(const struct xfs_trans_res *r) return ret; } +struct xfs_defer_pending; + void xlog_recover_intent_item(struct xlog *log, struct xfs_log_item *lip, xfs_lsn_t lsn, unsigned int dfp_type); int xlog_recover_finish_intent(struct xfs_trans *tp, diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index eaf8a877c2cc..bd23c9594a0d 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -544,12 +544,17 @@ xfs_attri_recover_work( struct xfs_mount *mp, struct xfs_defer_pending *dfp, struct xfs_attri_log_format *attrp, - struct xfs_inode *ip, + struct xfs_inode **ipp, struct xfs_attri_log_nameval *nv) { struct xfs_attr_intent *attr; struct xfs_da_args *args; int local; + int error; + + error = xlog_recover_iget(mp, attrp->alfi_ino, ipp); + if (error) + return ERR_PTR(error); attr = kmem_zalloc(sizeof(struct xfs_attr_intent) + sizeof(struct xfs_da_args), KM_NOFS); @@ -567,7 +572,7 @@ xfs_attri_recover_work( attr->xattri_nameval = xfs_attri_log_nameval_get(nv); ASSERT(attr->xattri_nameval); - args->dp = ip; + args->dp = *ipp; args->geo = mp->m_attr_geo; args->whichfork = XFS_ATTR_FORK; args->name = nv->name.i_addr; @@ -604,7 +609,7 @@ xfs_attri_recover_work( * delete the attr that it describes. */ STATIC int -xfs_attri_item_recover( +xfs_attr_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list) { @@ -630,11 +635,9 @@ xfs_attri_item_recover( !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) return -EFSCORRUPTED; - error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); - if (error) - return error; - - attr = xfs_attri_recover_work(mp, dfp, attrp, ip, nv); + attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv); + if (IS_ERR(attr)) + return PTR_ERR(attr); args = attr->xattri_da_args; xfs_init_attr_trans(args, &resv, &total); @@ -820,6 +823,7 @@ const struct xfs_defer_op_type xfs_attr_defer_type = { .create_done = xfs_attr_create_done, .finish_item = xfs_attr_finish_item, .cancel_item = xfs_attr_cancel_item, + .recover_work = xfs_attr_recover_work, }; /* @@ -856,7 +860,6 @@ static const struct xfs_item_ops xfs_attri_item_ops = { .iop_format = xfs_attri_item_format, .iop_unpin = xfs_attri_item_unpin, .iop_release = xfs_attri_item_release, - .iop_recover = xfs_attri_item_recover, .iop_match = xfs_attri_item_match, .iop_relog = xfs_attri_item_relog, }; diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 89f2d9e89607..bd8f6fe22b40 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -437,15 +437,6 @@ xfs_bmap_update_cancel_item( kmem_cache_free(xfs_bmap_intent_cache, bi); } -const struct xfs_defer_op_type xfs_bmap_update_defer_type = { - .max_items = XFS_BUI_MAX_FAST_EXTENTS, - .create_intent = xfs_bmap_update_create_intent, - .abort_intent = xfs_bmap_update_abort_intent, - .create_done = xfs_bmap_update_create_done, - .finish_item = xfs_bmap_update_finish_item, - .cancel_item = xfs_bmap_update_cancel_item, -}; - /* Is this recovered BUI ok? */ static inline bool xfs_bui_validate( @@ -484,9 +475,15 @@ static inline struct xfs_bmap_intent * xfs_bui_recover_work( struct xfs_mount *mp, struct xfs_defer_pending *dfp, + struct xfs_inode **ipp, struct xfs_map_extent *map) { struct xfs_bmap_intent *bi; + int error; + + error = xlog_recover_iget(mp, map->me_owner, ipp); + if (error) + return ERR_PTR(error); bi = kmem_cache_zalloc(xfs_bmap_intent_cache, GFP_NOFS | __GFP_NOFAIL); bi->bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? @@ -497,6 +494,7 @@ xfs_bui_recover_work( bi->bi_bmap.br_blockcount = map->me_len; bi->bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? XFS_EXT_UNWRITTEN : XFS_EXT_NORM; + bi->bi_owner = *ipp; xfs_bmap_update_get_group(mp, bi); xfs_defer_add_item(dfp, &bi->bi_list); @@ -508,7 +506,7 @@ xfs_bui_recover_work( * We need to update some inode's bmbt. */ STATIC int -xfs_bui_item_recover( +xfs_bmap_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list) { @@ -530,11 +528,9 @@ xfs_bui_item_recover( } map = &buip->bui_format.bui_extents[0]; - work = xfs_bui_recover_work(mp, dfp, map); - - error = xlog_recover_iget(mp, map->me_owner, &ip); - if (error) - return error; + work = xfs_bui_recover_work(mp, dfp, &ip, map); + if (IS_ERR(work)) + return PTR_ERR(work); /* Allocate transaction and do the work. */ resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate); @@ -557,8 +553,6 @@ xfs_bui_item_recover( if (error) goto err_cancel; - work->bi_owner = ip; - error = xlog_recover_finish_intent(tp, dfp); if (error == -EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, @@ -587,6 +581,16 @@ xfs_bui_item_recover( return error; } +const struct xfs_defer_op_type xfs_bmap_update_defer_type = { + .max_items = XFS_BUI_MAX_FAST_EXTENTS, + .create_intent = xfs_bmap_update_create_intent, + .abort_intent = xfs_bmap_update_abort_intent, + .create_done = xfs_bmap_update_create_done, + .finish_item = xfs_bmap_update_finish_item, + .cancel_item = xfs_bmap_update_cancel_item, + .recover_work = xfs_bmap_recover_work, +}; + STATIC bool xfs_bui_item_match( struct xfs_log_item *lip, @@ -627,7 +631,6 @@ static const struct xfs_item_ops xfs_bui_item_ops = { .iop_format = xfs_bui_item_format, .iop_unpin = xfs_bui_item_unpin, .iop_release = xfs_bui_item_release, - .iop_recover = xfs_bui_item_recover, .iop_match = xfs_bui_item_match, .iop_relog = xfs_bui_item_relog, }; diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 6a434ade486c..49e96ffd64e0 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -567,15 +567,6 @@ xfs_extent_free_cancel_item( kmem_cache_free(xfs_extfree_item_cache, xefi); } -const struct xfs_defer_op_type xfs_extent_free_defer_type = { - .max_items = XFS_EFI_MAX_FAST_EXTENTS, - .create_intent = xfs_extent_free_create_intent, - .abort_intent = xfs_extent_free_abort_intent, - .create_done = xfs_extent_free_create_done, - .finish_item = xfs_extent_free_finish_item, - .cancel_item = xfs_extent_free_cancel_item, -}; - /* * AGFL blocks are accounted differently in the reserve pools and are not * inserted into the busy extent list. @@ -632,16 +623,6 @@ xfs_agfl_free_finish_item( return error; } -/* sub-type with special handling for AGFL deferred frees */ -const struct xfs_defer_op_type xfs_agfl_free_defer_type = { - .max_items = XFS_EFI_MAX_FAST_EXTENTS, - .create_intent = xfs_extent_free_create_intent, - .abort_intent = xfs_extent_free_abort_intent, - .create_done = xfs_extent_free_create_done, - .finish_item = xfs_agfl_free_finish_item, - .cancel_item = xfs_extent_free_cancel_item, -}; - /* Is this recovered EFI ok? */ static inline bool xfs_efi_validate_ext( @@ -675,7 +656,7 @@ xfs_efi_recover_work( * the log. We need to free the extents that it describes. */ STATIC int -xfs_efi_item_recover( +xfs_extent_free_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list) { @@ -724,6 +705,27 @@ xfs_efi_item_recover( return error; } +const struct xfs_defer_op_type xfs_extent_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_extent_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, + .recover_work = xfs_extent_free_recover_work, +}; + +/* sub-type with special handling for AGFL deferred frees */ +const struct xfs_defer_op_type xfs_agfl_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_agfl_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, + .recover_work = xfs_extent_free_recover_work, +}; + STATIC bool xfs_efi_item_match( struct xfs_log_item *lip, @@ -766,7 +768,6 @@ static const struct xfs_item_ops xfs_efi_item_ops = { .iop_format = xfs_efi_item_format, .iop_unpin = xfs_efi_item_unpin, .iop_release = xfs_efi_item_release, - .iop_recover = xfs_efi_item_recover, .iop_match = xfs_efi_item_match, .iop_relog = xfs_efi_item_relog, }; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 6fab490959d4..c18692af2c65 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2562,17 +2562,14 @@ xlog_recover_process_intents( #endif list_for_each_entry_safe(dfp, n, &log->r_dfops, dfp_list) { - struct xfs_log_item *lip = dfp->dfp_intent; - const struct xfs_item_ops *ops = lip->li_ops; - - ASSERT(xlog_item_is_intent(lip)); + ASSERT(xlog_item_is_intent(dfp->dfp_intent)); /* * We should never see a redo item with a LSN higher than * the last transaction we found in the log at the start * of recovery. */ - ASSERT(XFS_LSN_CMP(last_lsn, lip->li_lsn) >= 0); + ASSERT(XFS_LSN_CMP(last_lsn, dfp->dfp_intent->li_lsn) >= 0); /* * NOTE: If your intent processing routine can create more @@ -2581,15 +2578,13 @@ xlog_recover_process_intents( * replayed in the wrong order! * * The recovery function can free the log item, so we must not - * access lip after it returns. It must dispose of @dfp if it - * returns 0. + * access dfp->dfp_intent after it returns. It must dispose of + * @dfp if it returns 0. */ - error = ops->iop_recover(dfp, &capture_list); - if (error) { - trace_xlog_intent_recovery_failed(log->l_mp, error, - ops->iop_recover); + error = xfs_defer_finish_recovery(log->l_mp, dfp, + &capture_list); + if (error) break; - } } if (error) goto err; diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index f561ca73c784..48f1a38b272e 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -433,16 +433,6 @@ xfs_refcount_update_cancel_item( kmem_cache_free(xfs_refcount_intent_cache, ri); } -const struct xfs_defer_op_type xfs_refcount_update_defer_type = { - .max_items = XFS_CUI_MAX_FAST_EXTENTS, - .create_intent = xfs_refcount_update_create_intent, - .abort_intent = xfs_refcount_update_abort_intent, - .create_done = xfs_refcount_update_create_done, - .finish_item = xfs_refcount_update_finish_item, - .finish_cleanup = xfs_refcount_finish_one_cleanup, - .cancel_item = xfs_refcount_update_cancel_item, -}; - /* Is this recovered CUI ok? */ static inline bool xfs_cui_validate_phys( @@ -491,7 +481,7 @@ xfs_cui_recover_work( * We need to update the refcountbt. */ STATIC int -xfs_cui_item_recover( +xfs_refcount_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list) { @@ -553,6 +543,17 @@ xfs_cui_item_recover( return error; } +const struct xfs_defer_op_type xfs_refcount_update_defer_type = { + .max_items = XFS_CUI_MAX_FAST_EXTENTS, + .create_intent = xfs_refcount_update_create_intent, + .abort_intent = xfs_refcount_update_abort_intent, + .create_done = xfs_refcount_update_create_done, + .finish_item = xfs_refcount_update_finish_item, + .finish_cleanup = xfs_refcount_finish_one_cleanup, + .cancel_item = xfs_refcount_update_cancel_item, + .recover_work = xfs_refcount_recover_work, +}; + STATIC bool xfs_cui_item_match( struct xfs_log_item *lip, @@ -593,7 +594,6 @@ static const struct xfs_item_ops xfs_cui_item_ops = { .iop_format = xfs_cui_item_format, .iop_unpin = xfs_cui_item_unpin, .iop_release = xfs_cui_item_release, - .iop_recover = xfs_cui_item_recover, .iop_match = xfs_cui_item_match, .iop_relog = xfs_cui_item_relog, }; diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 23e736179894..23684bc2ab85 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -452,16 +452,6 @@ xfs_rmap_update_cancel_item( kmem_cache_free(xfs_rmap_intent_cache, ri); } -const struct xfs_defer_op_type xfs_rmap_update_defer_type = { - .max_items = XFS_RUI_MAX_FAST_EXTENTS, - .create_intent = xfs_rmap_update_create_intent, - .abort_intent = xfs_rmap_update_abort_intent, - .create_done = xfs_rmap_update_create_done, - .finish_item = xfs_rmap_update_finish_item, - .finish_cleanup = xfs_rmap_finish_one_cleanup, - .cancel_item = xfs_rmap_update_cancel_item, -}; - /* Is this recovered RUI ok? */ static inline bool xfs_rui_validate_map( @@ -556,7 +546,7 @@ xfs_rui_recover_work( * We need to update the rmapbt. */ STATIC int -xfs_rui_item_recover( +xfs_rmap_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list) { @@ -606,6 +596,17 @@ xfs_rui_item_recover( return error; } +const struct xfs_defer_op_type xfs_rmap_update_defer_type = { + .max_items = XFS_RUI_MAX_FAST_EXTENTS, + .create_intent = xfs_rmap_update_create_intent, + .abort_intent = xfs_rmap_update_abort_intent, + .create_done = xfs_rmap_update_create_done, + .finish_item = xfs_rmap_update_finish_item, + .finish_cleanup = xfs_rmap_finish_one_cleanup, + .cancel_item = xfs_rmap_update_cancel_item, + .recover_work = xfs_rmap_recover_work, +}; + STATIC bool xfs_rui_item_match( struct xfs_log_item *lip, @@ -646,7 +647,6 @@ static const struct xfs_item_ops xfs_rui_item_ops = { .iop_format = xfs_rui_item_format, .iop_unpin = xfs_rui_item_unpin, .iop_release = xfs_rui_item_release, - .iop_recover = xfs_rui_item_recover, .iop_match = xfs_rui_item_match, .iop_relog = xfs_rui_item_relog, }; diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 4e38357237c3..5fb018ad9fc0 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -66,8 +66,6 @@ struct xfs_log_item { { (1u << XFS_LI_DIRTY), "DIRTY" }, \ { (1u << XFS_LI_WHITEOUT), "WHITEOUT" } -struct xfs_defer_pending; - struct xfs_item_ops { unsigned flags; void (*iop_size)(struct xfs_log_item *, int *, int *); @@ -80,8 +78,6 @@ struct xfs_item_ops { xfs_lsn_t (*iop_committed)(struct xfs_log_item *, xfs_lsn_t); uint (*iop_push)(struct xfs_log_item *, struct list_head *); void (*iop_release)(struct xfs_log_item *); - int (*iop_recover)(struct xfs_defer_pending *dfp, - struct list_head *capture_list); bool (*iop_match)(struct xfs_log_item *item, uint64_t id); struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent, struct xfs_trans *tp); From e6e5299fcbf0b18cad45cd58f99787549c790857 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 10:23:19 -0800 Subject: [PATCH 2915/7721] xfs: collapse the ->finish_item helpers Each log item's ->finish_item function sets up a small amount of state and calls another function to do the work. Collapse that other function into ->finish_item to reduce the call stack height. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 60 +++++++++---------------- fs/xfs/xfs_bmap_item.c | 18 +------- fs/xfs/xfs_extfree_item.c | 90 ++++++++++++++------------------------ fs/xfs/xfs_refcount_item.c | 18 +------- fs/xfs/xfs_rmap_item.c | 18 +------- 5 files changed, 58 insertions(+), 146 deletions(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index e7acbb736bee..96438cd38633 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -310,34 +310,6 @@ xfs_attrd_item_intent( return &ATTRD_ITEM(lip)->attrd_attrip->attri_item; } -/* - * Performs one step of an attribute update intent and marks the attrd item - * dirty.. An attr operation may be a set or a remove. Note that the - * transaction is marked dirty regardless of whether the operation succeeds or - * fails to support the ATTRI/ATTRD lifecycle rules. - */ -STATIC int -xfs_xattri_finish_update( - struct xfs_attr_intent *attr, - struct xfs_attrd_log_item *attrdp) -{ - struct xfs_da_args *args = attr->xattri_da_args; - int error; - - if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) - return -EIO; - - /* If an attr removal is trivially complete, we're done. */ - if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE && - !xfs_inode_hasattr(args->dp)) - return 0; - - error = xfs_attr_set_iter(attr); - if (!error && attr->xattri_dela_state != XFS_DAS_DONE) - error = -EAGAIN; - return error; -} - /* Log an attr to the intent item. */ STATIC void xfs_attr_log_item( @@ -434,23 +406,33 @@ xfs_attr_finish_item( struct xfs_btree_cur **state) { struct xfs_attr_intent *attr; - struct xfs_attrd_log_item *done_item = NULL; + struct xfs_da_args *args; int error; attr = container_of(item, struct xfs_attr_intent, xattri_list); - if (done) - done_item = ATTRD_ITEM(done); + args = attr->xattri_da_args; - /* - * Always reset trans after EAGAIN cycle - * since the transaction is new - */ - attr->xattri_da_args->trans = tp; + /* Reset trans after EAGAIN cycle since the transaction is new */ + args->trans = tp; - error = xfs_xattri_finish_update(attr, done_item); - if (error != -EAGAIN) - xfs_attr_free_item(attr); + if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) { + error = -EIO; + goto out; + } + /* If an attr removal is trivially complete, we're done. */ + if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE && + !xfs_inode_hasattr(args->dp)) { + error = 0; + goto out; + } + + error = xfs_attr_set_iter(attr); + if (!error && attr->xattri_dela_state != XFS_DAS_DONE) + return -EAGAIN; + +out: + xfs_attr_free_item(attr); return error; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 913315cb5123..79d19b5b0e5e 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -238,20 +238,6 @@ xfs_trans_get_bud( return budp; } -/* - * Finish an bmap update and log it to the BUD. Note that the - * transaction is marked dirty regardless of whether the bmap update - * succeeds or fails to support the BUI/BUD lifecycle rules. - */ -static int -xfs_trans_log_finish_bmap_update( - struct xfs_trans *tp, - struct xfs_bud_log_item *budp, - struct xfs_bmap_intent *bi) -{ - return xfs_bmap_finish_one(tp, bi); -} - /* Sort bmap intents by inode. */ static int xfs_bmap_update_diff_items( @@ -378,7 +364,7 @@ xfs_bmap_update_put_group( xfs_perag_intent_put(bi->bi_pag); } -/* Process a deferred rmap update. */ +/* Process a deferred bmap update. */ STATIC int xfs_bmap_update_finish_item( struct xfs_trans *tp, @@ -391,7 +377,7 @@ xfs_bmap_update_finish_item( bi = container_of(item, struct xfs_bmap_intent, bi_list); - error = xfs_trans_log_finish_bmap_update(tp, BUD_ITEM(done), bi); + error = xfs_bmap_finish_one(tp, bi); if (!error && bi->bi_bmap.br_blockcount > 0) { ASSERT(bi->bi_type == XFS_BMAP_UNMAP); return -EAGAIN; diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index e8e02f816cbe..581a70acd1ac 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -364,59 +364,6 @@ xfs_efd_from_efi( efdp->efd_next_extent = efip->efi_format.efi_nextents; } -/* - * Free an extent and log it to the EFD. Note that the transaction is marked - * dirty regardless of whether the extent free succeeds or fails to support the - * EFI/EFD lifecycle rules. - */ -static int -xfs_trans_free_extent( - struct xfs_trans *tp, - struct xfs_efd_log_item *efdp, - struct xfs_extent_free_item *xefi) -{ - struct xfs_owner_info oinfo = { }; - struct xfs_mount *mp = tp->t_mountp; - struct xfs_extent *extp; - uint next_extent; - xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, - xefi->xefi_startblock); - int error; - - oinfo.oi_owner = xefi->xefi_owner; - if (xefi->xefi_flags & XFS_EFI_ATTR_FORK) - oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK; - if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK) - oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK; - - trace_xfs_bmap_free_deferred(tp->t_mountp, xefi->xefi_pag->pag_agno, 0, - agbno, xefi->xefi_blockcount); - - error = __xfs_free_extent(tp, xefi->xefi_pag, agbno, - xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv, - xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); - - /* - * If we need a new transaction to make progress, the caller will log a - * new EFI with the current contents. It will also log an EFD to cancel - * the existing EFI, and so we need to copy all the unprocessed extents - * in this EFI to the EFD so this works correctly. - */ - if (error == -EAGAIN) { - xfs_efd_from_efi(efdp); - return error; - } - - next_extent = efdp->efd_next_extent; - ASSERT(next_extent < efdp->efd_format.efd_nextents); - extp = &(efdp->efd_format.efd_extents[next_extent]); - extp->ext_start = xefi->xefi_startblock; - extp->ext_len = xefi->xefi_blockcount; - efdp->efd_next_extent++; - - return error; -} - /* Sort bmap items by AG. */ static int xfs_extent_free_diff_items( @@ -517,19 +464,48 @@ xfs_extent_free_finish_item( struct list_head *item, struct xfs_btree_cur **state) { + struct xfs_owner_info oinfo = { }; struct xfs_extent_free_item *xefi; + struct xfs_efd_log_item *efdp = EFD_ITEM(done); + struct xfs_mount *mp = tp->t_mountp; + struct xfs_extent *extp; + uint next_extent; + xfs_agblock_t agbno; int error; xefi = container_of(item, struct xfs_extent_free_item, xefi_list); + agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock); - error = xfs_trans_free_extent(tp, EFD_ITEM(done), xefi); + oinfo.oi_owner = xefi->xefi_owner; + if (xefi->xefi_flags & XFS_EFI_ATTR_FORK) + oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK; + if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK) + oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK; + + trace_xfs_bmap_free_deferred(tp->t_mountp, xefi->xefi_pag->pag_agno, 0, + agbno, xefi->xefi_blockcount); /* - * Don't free the XEFI if we need a new transaction to complete - * processing of it. + * If we need a new transaction to make progress, the caller will log a + * new EFI with the current contents. It will also log an EFD to cancel + * the existing EFI, and so we need to copy all the unprocessed extents + * in this EFI to the EFD so this works correctly. */ - if (error == -EAGAIN) + error = __xfs_free_extent(tp, xefi->xefi_pag, agbno, + xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv, + xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); + if (error == -EAGAIN) { + xfs_efd_from_efi(efdp); return error; + } + + /* Add the work we finished to the EFD, even though nobody uses that */ + next_extent = efdp->efd_next_extent; + ASSERT(next_extent < efdp->efd_format.efd_nextents); + extp = &(efdp->efd_format.efd_extents[next_extent]); + extp->ext_start = xefi->xefi_startblock; + extp->ext_len = xefi->xefi_blockcount; + efdp->efd_next_extent++; xfs_extent_free_put_group(xefi); kmem_cache_free(xfs_extfree_item_cache, xefi); diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 2628b1e3969c..7273f538db2e 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -244,21 +244,6 @@ xfs_trans_get_cud( return cudp; } -/* - * Finish an refcount update and log it to the CUD. Note that the - * transaction is marked dirty regardless of whether the refcount - * update succeeds or fails to support the CUI/CUD lifecycle rules. - */ -static int -xfs_trans_log_finish_refcount_update( - struct xfs_trans *tp, - struct xfs_cud_log_item *cudp, - struct xfs_refcount_intent *ri, - struct xfs_btree_cur **pcur) -{ - return xfs_refcount_finish_one(tp, ri, pcur); -} - /* Sort refcount intents by AG. */ static int xfs_refcount_update_diff_items( @@ -383,10 +368,9 @@ xfs_refcount_update_finish_item( int error; ri = container_of(item, struct xfs_refcount_intent, ri_list); - error = xfs_trans_log_finish_refcount_update(tp, CUD_ITEM(done), ri, - state); /* Did we run out of reservation? Requeue what we didn't finish. */ + error = xfs_refcount_finish_one(tp, ri, state); if (!error && ri->ri_blockcount > 0) { ASSERT(ri->ri_type == XFS_REFCOUNT_INCREASE || ri->ri_type == XFS_REFCOUNT_DECREASE); diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 8f216a13a7f2..d54fd925b746 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -285,21 +285,6 @@ xfs_trans_set_rmap_flags( } } -/* - * Finish an rmap update and log it to the RUD. Note that the transaction is - * marked dirty regardless of whether the rmap update succeeds or fails to - * support the RUI/RUD lifecycle rules. - */ -static int -xfs_trans_log_finish_rmap_update( - struct xfs_trans *tp, - struct xfs_rud_log_item *rudp, - struct xfs_rmap_intent *ri, - struct xfs_btree_cur **pcur) -{ - return xfs_rmap_finish_one(tp, ri, pcur); -} - /* Sort rmap intents by AG. */ static int xfs_rmap_update_diff_items( @@ -409,8 +394,7 @@ xfs_rmap_update_finish_item( ri = container_of(item, struct xfs_rmap_intent, ri_list); - error = xfs_trans_log_finish_rmap_update(tp, RUD_ITEM(done), ri, - state); + error = xfs_rmap_finish_one(tp, ri, state); xfs_rmap_update_put_group(ri); kmem_cache_free(xfs_rmap_intent_cache, ri); From f3fd7f6fce1cc9b8eb59705b27f823330207b7c9 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 10:58:37 -0800 Subject: [PATCH 2916/7721] xfs: hoist ->create_intent boilerplate to its callsite Hoist the dirty flag setting code out of each ->create_intent implementation up to the callsite to reduce boilerplate further. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 2 ++ fs/xfs/xfs_attr_item.c | 3 --- fs/xfs/xfs_bmap_item.c | 3 --- fs/xfs/xfs_extfree_item.c | 3 --- fs/xfs/xfs_refcount_item.c | 3 --- fs/xfs/xfs_rmap_item.c | 3 --- 6 files changed, 2 insertions(+), 15 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 6214abedf394..2871c773a122 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -240,6 +240,8 @@ xfs_defer_create_intent( if (IS_ERR(lip)) return PTR_ERR(lip); + tp->t_flags |= XFS_TRANS_DIRTY; + set_bit(XFS_LI_DIRTY, &lip->li_flags); dfp->dfp_intent = lip; return 1; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 96438cd38633..fc199256fc8e 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -319,9 +319,6 @@ xfs_attr_log_item( { struct xfs_attri_log_format *attrp; - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags); - /* * At this point the xfs_attr_intent has been constructed, and we've * created the log intent. Fill in the attri log item and log format diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 79d19b5b0e5e..24cf70154a54 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -286,9 +286,6 @@ xfs_bmap_update_log_item( uint next_extent; struct xfs_map_extent *map; - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags); - /* * atomic_inc_return gives us the value after the increment; * we want to use it as an array index so we need to subtract 1 from diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 581a70acd1ac..d07cdc3eb809 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -390,9 +390,6 @@ xfs_extent_free_log_item( uint next_extent; struct xfs_extent *extp; - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags); - /* * atomic_inc_return gives us the value after the increment; * we want to use it as an array index so we need to subtract 1 from diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 7273f538db2e..f604b7e3b77e 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -289,9 +289,6 @@ xfs_refcount_update_log_item( uint next_extent; struct xfs_phys_extent *pmap; - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); - /* * atomic_inc_return gives us the value after the increment; * we want to use it as an array index so we need to subtract 1 from diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index d54fd925b746..05841548691d 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -311,9 +311,6 @@ xfs_rmap_update_log_item( uint next_extent; struct xfs_map_extent *map; - tp->t_flags |= XFS_TRANS_DIRTY; - set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags); - /* * atomic_inc_return gives us the value after the increment; * we want to use it as an array index so we need to subtract 1 from From bd3a88f6b71c7509566b44b7021581191cc11ae3 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 11:44:56 -0800 Subject: [PATCH 2917/7721] xfs: use xfs_defer_create_done for the relogging operation Now that we have a helper to handle creating a log intent done item and updating all the necessary state flags, use it to reduce boilerplate in the ->iop_relog implementations. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 6 +++++- fs/xfs/xfs_attr_item.c | 6 +----- fs/xfs/xfs_bmap_item.c | 6 +----- fs/xfs/xfs_extfree_item.c | 6 ++---- fs/xfs/xfs_refcount_item.c | 6 +----- fs/xfs/xfs_rmap_item.c | 6 +----- fs/xfs/xfs_trans.h | 4 +++- 7 files changed, 14 insertions(+), 26 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 2871c773a122..63b9960a96e1 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -500,7 +500,11 @@ xfs_defer_relog( trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp); XFS_STATS_INC((*tpp)->t_mountp, defer_relog); - dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, *tpp); + + xfs_defer_create_done(*tpp, dfp); + dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, + dfp->dfp_done, *tpp); + dfp->dfp_done = NULL; } if ((*tpp)->t_flags & XFS_TRANS_DIRTY) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index fc199256fc8e..e9813fa64461 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -630,9 +630,9 @@ xfs_attr_recover_work( static struct xfs_log_item * xfs_attri_item_relog( struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp) { - struct xfs_attrd_log_item *attrdp; struct xfs_attri_log_item *old_attrip; struct xfs_attri_log_item *new_attrip; struct xfs_attri_log_format *new_attrp; @@ -641,10 +641,6 @@ xfs_attri_item_relog( old_attrip = ATTRI_ITEM(intent); old_attrp = &old_attrip->attri_format; - tp->t_flags |= XFS_TRANS_DIRTY; - attrdp = xfs_trans_get_attrd(tp, old_attrip); - set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags); - /* * Create a new log item that shares the same name/value buffer as the * old log item. diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 24cf70154a54..ba385c06de5d 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -572,9 +572,9 @@ xfs_bui_item_match( static struct xfs_log_item * xfs_bui_item_relog( struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp) { - struct xfs_bud_log_item *budp; struct xfs_bui_log_item *buip; struct xfs_map_extent *map; unsigned int count; @@ -582,10 +582,6 @@ xfs_bui_item_relog( count = BUI_ITEM(intent)->bui_format.bui_nextents; map = BUI_ITEM(intent)->bui_format.bui_extents; - tp->t_flags |= XFS_TRANS_DIRTY; - budp = xfs_trans_get_bud(tp, BUI_ITEM(intent)); - set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags); - buip = xfs_bui_init(tp->t_mountp); memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map)); atomic_set(&buip->bui_next_extent, count); diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index d07cdc3eb809..807398479187 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -691,9 +691,10 @@ xfs_efi_item_match( static struct xfs_log_item * xfs_efi_item_relog( struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp) { - struct xfs_efd_log_item *efdp; + struct xfs_efd_log_item *efdp = EFD_ITEM(done_item); struct xfs_efi_log_item *efip; struct xfs_extent *extp; unsigned int count; @@ -701,11 +702,8 @@ xfs_efi_item_relog( count = EFI_ITEM(intent)->efi_format.efi_nextents; extp = EFI_ITEM(intent)->efi_format.efi_extents; - tp->t_flags |= XFS_TRANS_DIRTY; - efdp = xfs_trans_get_efd(tp, EFI_ITEM(intent), count); efdp->efd_next_extent = count; memcpy(efdp->efd_format.efd_extents, extp, count * sizeof(*extp)); - set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags); efip = xfs_efi_init(tp->t_mountp, count); memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp)); diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index f604b7e3b77e..142839a8e7b1 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -533,9 +533,9 @@ xfs_cui_item_match( static struct xfs_log_item * xfs_cui_item_relog( struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp) { - struct xfs_cud_log_item *cudp; struct xfs_cui_log_item *cuip; struct xfs_phys_extent *pmap; unsigned int count; @@ -543,10 +543,6 @@ xfs_cui_item_relog( count = CUI_ITEM(intent)->cui_format.cui_nextents; pmap = CUI_ITEM(intent)->cui_format.cui_extents; - tp->t_flags |= XFS_TRANS_DIRTY; - cudp = xfs_trans_get_cud(tp, CUI_ITEM(intent)); - set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags); - cuip = xfs_cui_init(tp->t_mountp, count); memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap)); atomic_set(&cuip->cui_next_extent, count); diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 05841548691d..e2730b3e0d96 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -586,9 +586,9 @@ xfs_rui_item_match( static struct xfs_log_item * xfs_rui_item_relog( struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp) { - struct xfs_rud_log_item *rudp; struct xfs_rui_log_item *ruip; struct xfs_map_extent *map; unsigned int count; @@ -596,10 +596,6 @@ xfs_rui_item_relog( count = RUI_ITEM(intent)->rui_format.rui_nextents; map = RUI_ITEM(intent)->rui_format.rui_extents; - tp->t_flags |= XFS_TRANS_DIRTY; - rudp = xfs_trans_get_rud(tp, RUI_ITEM(intent)); - set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags); - ruip = xfs_rui_init(tp->t_mountp, count); memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map)); atomic_set(&ruip->rui_next_extent, count); diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 5fb018ad9fc0..25646e2b12f4 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -80,6 +80,7 @@ struct xfs_item_ops { void (*iop_release)(struct xfs_log_item *); bool (*iop_match)(struct xfs_log_item *item, uint64_t id); struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent, + struct xfs_log_item *done_item, struct xfs_trans *tp); struct xfs_log_item *(*iop_intent)(struct xfs_log_item *intent_done); }; @@ -248,9 +249,10 @@ extern struct kmem_cache *xfs_trans_cache; static inline struct xfs_log_item * xfs_trans_item_relog( struct xfs_log_item *lip, + struct xfs_log_item *done_lip, struct xfs_trans *tp) { - return lip->li_ops->iop_relog(lip, tp); + return lip->li_ops->iop_relog(lip, done_lip, tp); } struct xfs_dquot; From 3e0958be2156d90ef908a1a547b4e27a3ec38da9 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 11:47:45 -0800 Subject: [PATCH 2918/7721] xfs: clean out XFS_LI_DIRTY setting boilerplate from ->iop_relog Hoist this dirty flag setting to the ->iop_relog callsite to reduce boilerplate. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 9 +++++++-- fs/xfs/xfs_attr_item.c | 1 - fs/xfs/xfs_bmap_item.c | 2 +- fs/xfs/xfs_extfree_item.c | 2 +- fs/xfs/xfs_refcount_item.c | 2 +- fs/xfs/xfs_rmap_item.c | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 63b9960a96e1..aa19ede91a57 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -474,6 +474,8 @@ xfs_defer_relog( ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES); list_for_each_entry(dfp, dfops, dfp_list) { + struct xfs_log_item *lip; + /* * If the log intent item for this deferred op is not a part of * the current log checkpoint, relog the intent item to keep @@ -502,9 +504,12 @@ xfs_defer_relog( XFS_STATS_INC((*tpp)->t_mountp, defer_relog); xfs_defer_create_done(*tpp, dfp); - dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, - dfp->dfp_done, *tpp); + lip = xfs_trans_item_relog(dfp->dfp_intent, dfp->dfp_done, + *tpp); + if (lip) + set_bit(XFS_LI_DIRTY, &lip->li_flags); dfp->dfp_done = NULL; + dfp->dfp_intent = lip; } if ((*tpp)->t_flags & XFS_TRANS_DIRTY) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index e9813fa64461..5d86a4b8b457 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -655,7 +655,6 @@ xfs_attri_item_relog( new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter; xfs_trans_add_item(tp, &new_attrip->attri_item); - set_bit(XFS_LI_DIRTY, &new_attrip->attri_item.li_flags); return &new_attrip->attri_item; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index ba385c06de5d..ef72061d7cec 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -586,7 +586,7 @@ xfs_bui_item_relog( memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map)); atomic_set(&buip->bui_next_extent, count); xfs_trans_add_item(tp, &buip->bui_item); - set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags); + return &buip->bui_item; } diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 807398479187..e2e86f2edb3c 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -709,7 +709,7 @@ xfs_efi_item_relog( memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp)); atomic_set(&efip->efi_next_extent, count); xfs_trans_add_item(tp, &efip->efi_item); - set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags); + return &efip->efi_item; } diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 142839a8e7b1..01d16e795068 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -547,7 +547,7 @@ xfs_cui_item_relog( memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap)); atomic_set(&cuip->cui_next_extent, count); xfs_trans_add_item(tp, &cuip->cui_item); - set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); + return &cuip->cui_item; } diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index e2730b3e0d96..96b2dc832d62 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -600,7 +600,7 @@ xfs_rui_item_relog( memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map)); atomic_set(&ruip->rui_next_extent, count); xfs_trans_add_item(tp, &ruip->rui_item); - set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags); + return &ruip->rui_item; } From b28852a5bd08654634e4e32eb072fba14c5fae26 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 12:06:08 -0800 Subject: [PATCH 2919/7721] xfs: hoist xfs_trans_add_item calls to defer ops functions Remove even more repeated boilerplate. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 7 ++++++- fs/xfs/xfs_attr_item.c | 4 ---- fs/xfs/xfs_bmap_item.c | 3 --- fs/xfs/xfs_extfree_item.c | 3 --- fs/xfs/xfs_refcount_item.c | 3 --- fs/xfs/xfs_rmap_item.c | 3 --- 6 files changed, 6 insertions(+), 17 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index aa19ede91a57..95f15a4b2126 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -26,6 +26,7 @@ #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_attr.h" +#include "xfs_trans_priv.h" static struct kmem_cache *xfs_defer_pending_cache; @@ -213,6 +214,7 @@ xfs_defer_create_done( return; tp->t_flags |= XFS_TRANS_HAS_INTENT_DONE; + xfs_trans_add_item(tp, lip); set_bit(XFS_LI_DIRTY, &lip->li_flags); dfp->dfp_done = lip; } @@ -241,6 +243,7 @@ xfs_defer_create_intent( return PTR_ERR(lip); tp->t_flags |= XFS_TRANS_DIRTY; + xfs_trans_add_item(tp, lip); set_bit(XFS_LI_DIRTY, &lip->li_flags); dfp->dfp_intent = lip; return 1; @@ -506,8 +509,10 @@ xfs_defer_relog( xfs_defer_create_done(*tpp, dfp); lip = xfs_trans_item_relog(dfp->dfp_intent, dfp->dfp_done, *tpp); - if (lip) + if (lip) { + xfs_trans_add_item(*tpp, lip); set_bit(XFS_LI_DIRTY, &lip->li_flags); + } dfp->dfp_done = NULL; dfp->dfp_intent = lip; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 5d86a4b8b457..c815811d937a 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -375,7 +375,6 @@ xfs_attr_create_intent( } attrip = xfs_attri_init(mp, attr->xattri_nameval); - xfs_trans_add_item(tp, &attrip->attri_item); xfs_attr_log_item(tp, attrip, attr); return &attrip->attri_item; @@ -654,8 +653,6 @@ xfs_attri_item_relog( new_attrp->alfi_name_len = old_attrp->alfi_name_len; new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter; - xfs_trans_add_item(tp, &new_attrip->attri_item); - return &new_attrip->attri_item; } @@ -753,7 +750,6 @@ xfs_trans_get_attrd(struct xfs_trans *tp, attrdp->attrd_attrip = attrip; attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id; - xfs_trans_add_item(tp, &attrdp->attrd_item); return attrdp; } diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index ef72061d7cec..0be7a1224a81 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -234,7 +234,6 @@ xfs_trans_get_bud( budp->bud_buip = buip; budp->bud_format.bud_bui_id = buip->bui_format.bui_id; - xfs_trans_add_item(tp, &budp->bud_item); return budp; } @@ -315,7 +314,6 @@ xfs_bmap_update_create_intent( ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); - xfs_trans_add_item(tp, &buip->bui_item); if (sort) list_sort(mp, items, xfs_bmap_update_diff_items); list_for_each_entry(bi, items, bi_list) @@ -585,7 +583,6 @@ xfs_bui_item_relog( buip = xfs_bui_init(tp->t_mountp); memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map)); atomic_set(&buip->bui_next_extent, count); - xfs_trans_add_item(tp, &buip->bui_item); return &buip->bui_item; } diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index e2e86f2edb3c..44bbf620e0cf 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -332,7 +332,6 @@ xfs_trans_get_efd( efdp->efd_format.efd_nextents = nextents; efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; - xfs_trans_add_item(tp, &efdp->efd_item); return efdp; } @@ -415,7 +414,6 @@ xfs_extent_free_create_intent( ASSERT(count > 0); - xfs_trans_add_item(tp, &efip->efi_item); if (sort) list_sort(mp, items, xfs_extent_free_diff_items); list_for_each_entry(xefi, items, xefi_list) @@ -708,7 +706,6 @@ xfs_efi_item_relog( efip = xfs_efi_init(tp->t_mountp, count); memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp)); atomic_set(&efip->efi_next_extent, count); - xfs_trans_add_item(tp, &efip->efi_item); return &efip->efi_item; } diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index 01d16e795068..a66bb6aa2e5d 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -240,7 +240,6 @@ xfs_trans_get_cud( cudp->cud_cuip = cuip; cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id; - xfs_trans_add_item(tp, &cudp->cud_item); return cudp; } @@ -315,7 +314,6 @@ xfs_refcount_update_create_intent( ASSERT(count > 0); - xfs_trans_add_item(tp, &cuip->cui_item); if (sort) list_sort(mp, items, xfs_refcount_update_diff_items); list_for_each_entry(ri, items, ri_list) @@ -546,7 +544,6 @@ xfs_cui_item_relog( cuip = xfs_cui_init(tp->t_mountp, count); memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap)); atomic_set(&cuip->cui_next_extent, count); - xfs_trans_add_item(tp, &cuip->cui_item); return &cuip->cui_item; } diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 96b2dc832d62..d668eb4d099e 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -238,7 +238,6 @@ xfs_trans_get_rud( rudp->rud_ruip = ruip; rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id; - xfs_trans_add_item(tp, &rudp->rud_item); return rudp; } @@ -340,7 +339,6 @@ xfs_rmap_update_create_intent( ASSERT(count > 0); - xfs_trans_add_item(tp, &ruip->rui_item); if (sort) list_sort(mp, items, xfs_rmap_update_diff_items); list_for_each_entry(ri, items, ri_list) @@ -599,7 +597,6 @@ xfs_rui_item_relog( ruip = xfs_rui_init(tp->t_mountp, count); memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map)); atomic_set(&ruip->rui_next_extent, count); - xfs_trans_add_item(tp, &ruip->rui_item); return &ruip->rui_item; } From 8a9aa763e17c5490d3526cbf4c9484d76ecbbe39 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 12:17:37 -0800 Subject: [PATCH 2920/7721] xfs: collapse the ->create_done functions Move the meat of the ->create_done function helpers into ->create_done to reduce the amount of boilerplate. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_attr_item.c | 37 ++++++++++---------------- fs/xfs/xfs_bmap_item.c | 29 ++++++++------------- fs/xfs/xfs_extfree_item.c | 53 ++++++++++++++------------------------ fs/xfs/xfs_refcount_item.c | 27 +++++++------------ fs/xfs/xfs_rmap_item.c | 27 +++++++------------ 5 files changed, 64 insertions(+), 109 deletions(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index c815811d937a..27553388da99 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -33,8 +33,6 @@ struct kmem_cache *xfs_attrd_cache; static const struct xfs_item_ops xfs_attri_item_ops; static const struct xfs_item_ops xfs_attrd_item_ops; -static struct xfs_attrd_log_item *xfs_trans_get_attrd(struct xfs_trans *tp, - struct xfs_attri_log_item *attrip); static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip) { @@ -732,16 +730,20 @@ xlog_recover_attri_commit_pass2( return 0; } -/* - * This routine is called to allocate an "attr free done" log item. - */ -static struct xfs_attrd_log_item * -xfs_trans_get_attrd(struct xfs_trans *tp, - struct xfs_attri_log_item *attrip) +/* Get an ATTRD so we can process all the attrs. */ +static struct xfs_log_item * +xfs_attr_create_done( + struct xfs_trans *tp, + struct xfs_log_item *intent, + unsigned int count) { - struct xfs_attrd_log_item *attrdp; + struct xfs_attri_log_item *attrip; + struct xfs_attrd_log_item *attrdp; - ASSERT(tp != NULL); + if (!intent) + return NULL; + + attrip = ATTRI_ITEM(intent); attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL); @@ -750,20 +752,7 @@ xfs_trans_get_attrd(struct xfs_trans *tp, attrdp->attrd_attrip = attrip; attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id; - return attrdp; -} - -/* Get an ATTRD so we can process all the attrs. */ -static struct xfs_log_item * -xfs_attr_create_done( - struct xfs_trans *tp, - struct xfs_log_item *intent, - unsigned int count) -{ - if (!intent) - return NULL; - - return &xfs_trans_get_attrd(tp, ATTRI_ITEM(intent))->attrd_item; + return &attrdp->attrd_item; } const struct xfs_defer_op_type xfs_attr_defer_type = { diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index 0be7a1224a81..f3421e615e1c 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -221,22 +221,6 @@ static const struct xfs_item_ops xfs_bud_item_ops = { .iop_intent = xfs_bud_item_intent, }; -static struct xfs_bud_log_item * -xfs_trans_get_bud( - struct xfs_trans *tp, - struct xfs_bui_log_item *buip) -{ - struct xfs_bud_log_item *budp; - - budp = kmem_cache_zalloc(xfs_bud_cache, GFP_KERNEL | __GFP_NOFAIL); - xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD, - &xfs_bud_item_ops); - budp->bud_buip = buip; - budp->bud_format.bud_bui_id = buip->bui_format.bui_id; - - return budp; -} - /* Sort bmap intents by inode. */ static int xfs_bmap_update_diff_items( @@ -321,14 +305,23 @@ xfs_bmap_update_create_intent( return &buip->bui_item; } -/* Get an BUD so we can process all the deferred rmap updates. */ +/* Get an BUD so we can process all the deferred bmap updates. */ static struct xfs_log_item * xfs_bmap_update_create_done( struct xfs_trans *tp, struct xfs_log_item *intent, unsigned int count) { - return &xfs_trans_get_bud(tp, BUI_ITEM(intent))->bud_item; + struct xfs_bui_log_item *buip = BUI_ITEM(intent); + struct xfs_bud_log_item *budp; + + budp = kmem_cache_zalloc(xfs_bud_cache, GFP_KERNEL | __GFP_NOFAIL); + xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD, + &xfs_bud_item_ops); + budp->bud_buip = buip; + budp->bud_format.bud_bui_id = buip->bui_format.bui_id; + + return &budp->bud_item; } /* Take a passive ref to the AG containing the space we're mapping. */ diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 44bbf620e0cf..518569c64e9c 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -303,38 +303,6 @@ static const struct xfs_item_ops xfs_efd_item_ops = { .iop_intent = xfs_efd_item_intent, }; -/* - * Allocate an "extent free done" log item that will hold nextents worth of - * extents. The caller must use all nextents extents, because we are not - * flexible about this at all. - */ -static struct xfs_efd_log_item * -xfs_trans_get_efd( - struct xfs_trans *tp, - struct xfs_efi_log_item *efip, - unsigned int nextents) -{ - struct xfs_efd_log_item *efdp; - - ASSERT(nextents > 0); - - if (nextents > XFS_EFD_MAX_FAST_EXTENTS) { - efdp = kzalloc(xfs_efd_log_item_sizeof(nextents), - GFP_KERNEL | __GFP_NOFAIL); - } else { - efdp = kmem_cache_zalloc(xfs_efd_cache, - GFP_KERNEL | __GFP_NOFAIL); - } - - xfs_log_item_init(tp->t_mountp, &efdp->efd_item, XFS_LI_EFD, - &xfs_efd_item_ops); - efdp->efd_efip = efip; - efdp->efd_format.efd_nextents = nextents; - efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; - - return efdp; -} - /* * Fill the EFD with all extents from the EFI when we need to roll the * transaction and continue with a new EFI. @@ -428,7 +396,26 @@ xfs_extent_free_create_done( struct xfs_log_item *intent, unsigned int count) { - return &xfs_trans_get_efd(tp, EFI_ITEM(intent), count)->efd_item; + struct xfs_efi_log_item *efip = EFI_ITEM(intent); + struct xfs_efd_log_item *efdp; + + ASSERT(count > 0); + + if (count > XFS_EFD_MAX_FAST_EXTENTS) { + efdp = kzalloc(xfs_efd_log_item_sizeof(count), + GFP_KERNEL | __GFP_NOFAIL); + } else { + efdp = kmem_cache_zalloc(xfs_efd_cache, + GFP_KERNEL | __GFP_NOFAIL); + } + + xfs_log_item_init(tp->t_mountp, &efdp->efd_item, XFS_LI_EFD, + &xfs_efd_item_ops); + efdp->efd_efip = efip; + efdp->efd_format.efd_nextents = count; + efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; + + return &efdp->efd_item; } /* Take a passive ref to the AG containing the space we're freeing. */ diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index a66bb6aa2e5d..d218a9ed4d82 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -227,22 +227,6 @@ static const struct xfs_item_ops xfs_cud_item_ops = { .iop_intent = xfs_cud_item_intent, }; -static struct xfs_cud_log_item * -xfs_trans_get_cud( - struct xfs_trans *tp, - struct xfs_cui_log_item *cuip) -{ - struct xfs_cud_log_item *cudp; - - cudp = kmem_cache_zalloc(xfs_cud_cache, GFP_KERNEL | __GFP_NOFAIL); - xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD, - &xfs_cud_item_ops); - cudp->cud_cuip = cuip; - cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id; - - return cudp; -} - /* Sort refcount intents by AG. */ static int xfs_refcount_update_diff_items( @@ -328,7 +312,16 @@ xfs_refcount_update_create_done( struct xfs_log_item *intent, unsigned int count) { - return &xfs_trans_get_cud(tp, CUI_ITEM(intent))->cud_item; + struct xfs_cui_log_item *cuip = CUI_ITEM(intent); + struct xfs_cud_log_item *cudp; + + cudp = kmem_cache_zalloc(xfs_cud_cache, GFP_KERNEL | __GFP_NOFAIL); + xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD, + &xfs_cud_item_ops); + cudp->cud_cuip = cuip; + cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id; + + return &cudp->cud_item; } /* Take a passive ref to the AG containing the space we're refcounting. */ diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index d668eb4d099e..96e0c2b0d059 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -225,22 +225,6 @@ static const struct xfs_item_ops xfs_rud_item_ops = { .iop_intent = xfs_rud_item_intent, }; -static struct xfs_rud_log_item * -xfs_trans_get_rud( - struct xfs_trans *tp, - struct xfs_rui_log_item *ruip) -{ - struct xfs_rud_log_item *rudp; - - rudp = kmem_cache_zalloc(xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL); - xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD, - &xfs_rud_item_ops); - rudp->rud_ruip = ruip; - rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id; - - return rudp; -} - /* Set the map extent flags for this reverse mapping. */ static void xfs_trans_set_rmap_flags( @@ -353,7 +337,16 @@ xfs_rmap_update_create_done( struct xfs_log_item *intent, unsigned int count) { - return &xfs_trans_get_rud(tp, RUI_ITEM(intent))->rud_item; + struct xfs_rui_log_item *ruip = RUI_ITEM(intent); + struct xfs_rud_log_item *rudp; + + rudp = kmem_cache_zalloc(xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL); + xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD, + &xfs_rud_item_ops); + rudp->rud_ruip = ruip; + rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id; + + return &rudp->rud_item; } /* Take a passive ref to the AG containing the space we're rmapping. */ From a6a38f309afc4a7ede01242b603f36c433997780 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 1 Dec 2023 09:17:40 -0800 Subject: [PATCH 2921/7721] xfs: make rextslog computation consistent with mkfs There's a weird discrepancy in xfsprogs dating back to the creation of the Linux port -- if there are zero rt extents, mkfs will set sb_rextents and sb_rextslog both to zero: sbp->sb_rextslog = (uint8_t)(rtextents ? libxfs_highbit32((unsigned int)rtextents) : 0); However, that's not the check that xfs_repair uses for nonzero rtblocks: if (sb->sb_rextslog != libxfs_highbit32((unsigned int)sb->sb_rextents)) The difference here is that xfs_highbit32 returns -1 if its argument is zero. Unfortunately, this means that in the weird corner case of a realtime volume shorter than 1 rt extent, xfs_repair will immediately flag a freshly formatted filesystem as corrupt. Because mkfs has been writing ondisk artifacts like this for decades, we have to accept that as "correct". TBH, zero rextslog for zero rtextents makes more sense to me anyway. Regrettably, the superblock verifier checks created in commit copied xfs_repair even though mkfs has been writing out such filesystems for ages. Fix the superblock verifier to accept what mkfs spits out; the userspace version of this patch will have to fix xfs_repair as well. Note that the new helper leaves the zeroday bug where the upper 32 bits of sb_rextents is ripped off and fed to highbit32. This leads to a seriously undersized rt summary file, which immediately breaks mkfs: $ hugedisk.sh foo /dev/sdc $(( 0x100000080 * 4096))B $ /sbin/mkfs.xfs -f /dev/sda -m rmapbt=0,reflink=0 -r rtdev=/dev/mapper/foo meta-data=/dev/sda isize=512 agcount=4, agsize=1298176 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=0 bigtime=1 inobtcount=1 nrext64=1 data = bsize=4096 blocks=5192704, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=16384, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =/dev/mapper/foo extsz=4096 blocks=4294967424, rtextents=4294967424 Discarding blocks...Done. mkfs.xfs: Error initializing the realtime space [117 - Structure needs cleaning] The next patch will drop support for rt volumes with fewer than 1 or more than 2^32-1 rt extents, since they've clearly been broken forever. Fixes: f8e566c0f5e1f ("xfs: validate the realtime geometry in xfs_validate_sb_common") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_rtbitmap.c | 12 ++++++++++++ fs/xfs/libxfs/xfs_rtbitmap.h | 3 +++ fs/xfs/libxfs/xfs_sb.c | 3 ++- fs/xfs/xfs_rtalloc.c | 4 ++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c index c269d704314d..1c9fed76a356 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.c +++ b/fs/xfs/libxfs/xfs_rtbitmap.c @@ -1130,6 +1130,18 @@ xfs_rtbitmap_blockcount( return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize); } +/* + * Compute the maximum level number of the realtime summary file, as defined by + * mkfs. The use of highbit32 on a 64-bit quantity is a historic artifact that + * prohibits correct use of rt volumes with more than 2^32 extents. + */ +uint8_t +xfs_compute_rextslog( + xfs_rtbxlen_t rtextents) +{ + return rtextents ? xfs_highbit32(rtextents) : 0; +} + /* * Compute the number of rtbitmap words needed to populate every block of a * bitmap that is large enough to track the given number of rt extents. diff --git a/fs/xfs/libxfs/xfs_rtbitmap.h b/fs/xfs/libxfs/xfs_rtbitmap.h index c0637057d69c..6e5bae324cc3 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.h +++ b/fs/xfs/libxfs/xfs_rtbitmap.h @@ -351,6 +351,8 @@ xfs_rtfree_extent( int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno, xfs_filblks_t rtlen); +uint8_t xfs_compute_rextslog(xfs_rtbxlen_t rtextents); + xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents); unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp, @@ -369,6 +371,7 @@ unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp, # define xfs_rtsummary_read_buf(a,b) (-ENOSYS) # define xfs_rtbuf_cache_relse(a) (0) # define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS) +# define xfs_compute_rextslog(rtx) (0) static inline xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents) { diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 1f74d0cd1618..df12bf82ed18 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -25,6 +25,7 @@ #include "xfs_da_format.h" #include "xfs_health.h" #include "xfs_ag.h" +#include "xfs_rtbitmap.h" /* * Physical superblock buffer manipulations. Shared with libxfs in userspace. @@ -509,7 +510,7 @@ xfs_validate_sb_common( NBBY * sbp->sb_blocksize); if (sbp->sb_rextents != rexts || - sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) || + sbp->sb_rextslog != xfs_compute_rextslog(rexts) || sbp->sb_rbmblocks != rbmblocks) { xfs_notice(mp, "realtime geometry sanity check failed"); diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 88c48de5c9c8..7c5a50163d2d 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -964,7 +964,7 @@ xfs_growfs_rt( nrextents = nrblocks; do_div(nrextents, in->extsize); nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents); - nrextslog = xfs_highbit32(nrextents); + nrextslog = xfs_compute_rextslog(nrextents); nrsumlevels = nrextslog + 1; nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels, nrbmblocks); nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); @@ -1031,7 +1031,7 @@ xfs_growfs_rt( nsbp->sb_rblocks = min(nrblocks, nrblocks_step); nsbp->sb_rextents = xfs_rtb_to_rtx(nmp, nsbp->sb_rblocks); ASSERT(nsbp->sb_rextents != 0); - nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); + nsbp->sb_rextslog = xfs_compute_rextslog(nsbp->sb_rextents); nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels, nsbp->sb_rbmblocks); From cf8f0e6c1429be7652869059ea44696b72d5b726 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 3 Dec 2023 09:19:44 -0800 Subject: [PATCH 2922/7721] xfs: fix 32-bit truncation in xfs_compute_rextslog It's quite reasonable that some customer somewhere will want to configure a realtime volume with more than 2^32 extents. If they try to do this, the highbit32() call will truncate the upper bits of the xfs_rtbxlen_t and produce the wrong value for rextslog. This in turn causes the rsumlevels to be wrong, which results in a realtime summary file that is the wrong length. Fix that. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_rtbitmap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c index 1c9fed76a356..30a2844f62e3 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.c +++ b/fs/xfs/libxfs/xfs_rtbitmap.c @@ -1132,14 +1132,16 @@ xfs_rtbitmap_blockcount( /* * Compute the maximum level number of the realtime summary file, as defined by - * mkfs. The use of highbit32 on a 64-bit quantity is a historic artifact that - * prohibits correct use of rt volumes with more than 2^32 extents. + * mkfs. The historic use of highbit32 on a 64-bit quantity prohibited correct + * use of rt volumes with more than 2^32 extents. */ uint8_t xfs_compute_rextslog( xfs_rtbxlen_t rtextents) { - return rtextents ? xfs_highbit32(rtextents) : 0; + if (!rtextents) + return 0; + return xfs_highbit64(rtextents); } /* From 94da54d582e6866a9613514b59f326456e88446d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 4 Dec 2023 12:13:26 -0800 Subject: [PATCH 2923/7721] xfs: document what LARP means Christoph requested a blurb somewhere explaining exactly what LARP means. I don't know of a good place other than the source code (debug knobs aren't covered in Documentation/), so here it is. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_sysfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c index a3c6b1548723..871f16a4a5d8 100644 --- a/fs/xfs/xfs_sysfs.c +++ b/fs/xfs/xfs_sysfs.c @@ -229,6 +229,15 @@ pwork_threads_show( } XFS_SYSFS_ATTR_RW(pwork_threads); +/* + * The "LARP" (Logged extended Attribute Recovery Persistence) debugging knob + * sets the XFS_DA_OP_LOGGED flag on all xfs_attr_set operations performed on + * V5 filesystems. As a result, the intermediate progress of all setxattr and + * removexattr operations are tracked via the log and can be restarted during + * recovery. This is useful for testing xattr recovery prior to merging of the + * parent pointer feature which requires it to maintain consistency, and may be + * enabled for userspace xattrs in the future. + */ static ssize_t larp_store( struct kobject *kobject, From a49c708f9a445457f6a5905732081871234f61c6 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Nov 2023 12:31:30 -0800 Subject: [PATCH 2924/7721] xfs: move ->iop_relog to struct xfs_defer_op_type The only log items that need relogging are the ones created for deferred work operations, and the only part of the code base that relogs log items is the deferred work machinery. Move the function pointers. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 31 +++++++++++------- fs/xfs/libxfs/xfs_defer.h | 3 ++ fs/xfs/xfs_attr_item.c | 8 ++--- fs/xfs/xfs_bmap_item.c | 44 ++++++++++++------------- fs/xfs/xfs_extfree_item.c | 67 +++++++++++++++++++------------------- fs/xfs/xfs_refcount_item.c | 46 +++++++++++++------------- fs/xfs/xfs_rmap_item.c | 46 +++++++++++++------------- fs/xfs/xfs_trans.h | 12 ------- 8 files changed, 129 insertions(+), 128 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 95f15a4b2126..54a6be06e6cd 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -459,6 +459,25 @@ xfs_defer_cancel_list( xfs_defer_pending_cancel_work(mp, dfp); } +static inline void +xfs_defer_relog_intent( + struct xfs_trans *tp, + struct xfs_defer_pending *dfp) +{ + struct xfs_log_item *lip; + const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; + + xfs_defer_create_done(tp, dfp); + + lip = ops->relog_intent(tp, dfp->dfp_intent, dfp->dfp_done); + if (lip) { + xfs_trans_add_item(tp, lip); + set_bit(XFS_LI_DIRTY, &lip->li_flags); + } + dfp->dfp_done = NULL; + dfp->dfp_intent = lip; +} + /* * Prevent a log intent item from pinning the tail of the log by logging a * done item to release the intent item; and then log a new intent item. @@ -477,8 +496,6 @@ xfs_defer_relog( ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES); list_for_each_entry(dfp, dfops, dfp_list) { - struct xfs_log_item *lip; - /* * If the log intent item for this deferred op is not a part of * the current log checkpoint, relog the intent item to keep @@ -506,15 +523,7 @@ xfs_defer_relog( trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp); XFS_STATS_INC((*tpp)->t_mountp, defer_relog); - xfs_defer_create_done(*tpp, dfp); - lip = xfs_trans_item_relog(dfp->dfp_intent, dfp->dfp_done, - *tpp); - if (lip) { - xfs_trans_add_item(*tpp, lip); - set_bit(XFS_LI_DIRTY, &lip->li_flags); - } - dfp->dfp_done = NULL; - dfp->dfp_intent = lip; + xfs_defer_relog_intent(*tpp, dfp); } if ((*tpp)->t_flags & XFS_TRANS_DIRTY) diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index ef86a7f9b059..78d6dcd1af2c 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -59,6 +59,9 @@ struct xfs_defer_op_type { void (*cancel_item)(struct list_head *item); int (*recover_work)(struct xfs_defer_pending *dfp, struct list_head *capture_list); + struct xfs_log_item *(*relog_intent)(struct xfs_trans *tp, + struct xfs_log_item *intent, + struct xfs_log_item *done_item); unsigned int max_items; }; diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 27553388da99..988d395a48ad 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -625,10 +625,10 @@ xfs_attr_recover_work( /* Re-log an intent item to push the log tail forward. */ static struct xfs_log_item * -xfs_attri_item_relog( +xfs_attr_relog_intent( + struct xfs_trans *tp, struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp) + struct xfs_log_item *done_item) { struct xfs_attri_log_item *old_attrip; struct xfs_attri_log_item *new_attrip; @@ -763,6 +763,7 @@ const struct xfs_defer_op_type xfs_attr_defer_type = { .finish_item = xfs_attr_finish_item, .cancel_item = xfs_attr_cancel_item, .recover_work = xfs_attr_recover_work, + .relog_intent = xfs_attr_relog_intent, }; /* @@ -800,7 +801,6 @@ static const struct xfs_item_ops xfs_attri_item_ops = { .iop_unpin = xfs_attri_item_unpin, .iop_release = xfs_attri_item_release, .iop_match = xfs_attri_item_match, - .iop_relog = xfs_attri_item_relog, }; const struct xlog_recover_item_ops xlog_attri_item_ops = { diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index f3421e615e1c..bc48d733634a 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -541,30 +541,12 @@ xfs_bmap_recover_work( return error; } -const struct xfs_defer_op_type xfs_bmap_update_defer_type = { - .max_items = XFS_BUI_MAX_FAST_EXTENTS, - .create_intent = xfs_bmap_update_create_intent, - .abort_intent = xfs_bmap_update_abort_intent, - .create_done = xfs_bmap_update_create_done, - .finish_item = xfs_bmap_update_finish_item, - .cancel_item = xfs_bmap_update_cancel_item, - .recover_work = xfs_bmap_recover_work, -}; - -STATIC bool -xfs_bui_item_match( - struct xfs_log_item *lip, - uint64_t intent_id) -{ - return BUI_ITEM(lip)->bui_format.bui_id == intent_id; -} - /* Relog an intent item to push the log tail forward. */ static struct xfs_log_item * -xfs_bui_item_relog( +xfs_bmap_relog_intent( + struct xfs_trans *tp, struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp) + struct xfs_log_item *done_item) { struct xfs_bui_log_item *buip; struct xfs_map_extent *map; @@ -580,6 +562,25 @@ xfs_bui_item_relog( return &buip->bui_item; } +const struct xfs_defer_op_type xfs_bmap_update_defer_type = { + .max_items = XFS_BUI_MAX_FAST_EXTENTS, + .create_intent = xfs_bmap_update_create_intent, + .abort_intent = xfs_bmap_update_abort_intent, + .create_done = xfs_bmap_update_create_done, + .finish_item = xfs_bmap_update_finish_item, + .cancel_item = xfs_bmap_update_cancel_item, + .recover_work = xfs_bmap_recover_work, + .relog_intent = xfs_bmap_relog_intent, +}; + +STATIC bool +xfs_bui_item_match( + struct xfs_log_item *lip, + uint64_t intent_id) +{ + return BUI_ITEM(lip)->bui_format.bui_id == intent_id; +} + static const struct xfs_item_ops xfs_bui_item_ops = { .flags = XFS_ITEM_INTENT, .iop_size = xfs_bui_item_size, @@ -587,7 +588,6 @@ static const struct xfs_item_ops xfs_bui_item_ops = { .iop_unpin = xfs_bui_item_unpin, .iop_release = xfs_bui_item_release, .iop_match = xfs_bui_item_match, - .iop_relog = xfs_bui_item_relog, }; static inline void diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 518569c64e9c..3ca23ab8d92a 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -643,41 +643,12 @@ xfs_extent_free_recover_work( return error; } -const struct xfs_defer_op_type xfs_extent_free_defer_type = { - .max_items = XFS_EFI_MAX_FAST_EXTENTS, - .create_intent = xfs_extent_free_create_intent, - .abort_intent = xfs_extent_free_abort_intent, - .create_done = xfs_extent_free_create_done, - .finish_item = xfs_extent_free_finish_item, - .cancel_item = xfs_extent_free_cancel_item, - .recover_work = xfs_extent_free_recover_work, -}; - -/* sub-type with special handling for AGFL deferred frees */ -const struct xfs_defer_op_type xfs_agfl_free_defer_type = { - .max_items = XFS_EFI_MAX_FAST_EXTENTS, - .create_intent = xfs_extent_free_create_intent, - .abort_intent = xfs_extent_free_abort_intent, - .create_done = xfs_extent_free_create_done, - .finish_item = xfs_agfl_free_finish_item, - .cancel_item = xfs_extent_free_cancel_item, - .recover_work = xfs_extent_free_recover_work, -}; - -STATIC bool -xfs_efi_item_match( - struct xfs_log_item *lip, - uint64_t intent_id) -{ - return EFI_ITEM(lip)->efi_format.efi_id == intent_id; -} - /* Relog an intent item to push the log tail forward. */ static struct xfs_log_item * -xfs_efi_item_relog( +xfs_extent_free_relog_intent( + struct xfs_trans *tp, struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp) + struct xfs_log_item *done_item) { struct xfs_efd_log_item *efdp = EFD_ITEM(done_item); struct xfs_efi_log_item *efip; @@ -697,6 +668,37 @@ xfs_efi_item_relog( return &efip->efi_item; } +const struct xfs_defer_op_type xfs_extent_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_extent_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, + .recover_work = xfs_extent_free_recover_work, + .relog_intent = xfs_extent_free_relog_intent, +}; + +/* sub-type with special handling for AGFL deferred frees */ +const struct xfs_defer_op_type xfs_agfl_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_agfl_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, + .recover_work = xfs_extent_free_recover_work, + .relog_intent = xfs_extent_free_relog_intent, +}; + +STATIC bool +xfs_efi_item_match( + struct xfs_log_item *lip, + uint64_t intent_id) +{ + return EFI_ITEM(lip)->efi_format.efi_id == intent_id; +} + static const struct xfs_item_ops xfs_efi_item_ops = { .flags = XFS_ITEM_INTENT, .iop_size = xfs_efi_item_size, @@ -704,7 +706,6 @@ static const struct xfs_item_ops xfs_efi_item_ops = { .iop_unpin = xfs_efi_item_unpin, .iop_release = xfs_efi_item_release, .iop_match = xfs_efi_item_match, - .iop_relog = xfs_efi_item_relog, }; /* diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index d218a9ed4d82..9974be81cb2b 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -501,31 +501,12 @@ xfs_refcount_recover_work( return error; } -const struct xfs_defer_op_type xfs_refcount_update_defer_type = { - .max_items = XFS_CUI_MAX_FAST_EXTENTS, - .create_intent = xfs_refcount_update_create_intent, - .abort_intent = xfs_refcount_update_abort_intent, - .create_done = xfs_refcount_update_create_done, - .finish_item = xfs_refcount_update_finish_item, - .finish_cleanup = xfs_refcount_finish_one_cleanup, - .cancel_item = xfs_refcount_update_cancel_item, - .recover_work = xfs_refcount_recover_work, -}; - -STATIC bool -xfs_cui_item_match( - struct xfs_log_item *lip, - uint64_t intent_id) -{ - return CUI_ITEM(lip)->cui_format.cui_id == intent_id; -} - /* Relog an intent item to push the log tail forward. */ static struct xfs_log_item * -xfs_cui_item_relog( +xfs_refcount_relog_intent( + struct xfs_trans *tp, struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp) + struct xfs_log_item *done_item) { struct xfs_cui_log_item *cuip; struct xfs_phys_extent *pmap; @@ -541,6 +522,26 @@ xfs_cui_item_relog( return &cuip->cui_item; } +const struct xfs_defer_op_type xfs_refcount_update_defer_type = { + .max_items = XFS_CUI_MAX_FAST_EXTENTS, + .create_intent = xfs_refcount_update_create_intent, + .abort_intent = xfs_refcount_update_abort_intent, + .create_done = xfs_refcount_update_create_done, + .finish_item = xfs_refcount_update_finish_item, + .finish_cleanup = xfs_refcount_finish_one_cleanup, + .cancel_item = xfs_refcount_update_cancel_item, + .recover_work = xfs_refcount_recover_work, + .relog_intent = xfs_refcount_relog_intent, +}; + +STATIC bool +xfs_cui_item_match( + struct xfs_log_item *lip, + uint64_t intent_id) +{ + return CUI_ITEM(lip)->cui_format.cui_id == intent_id; +} + static const struct xfs_item_ops xfs_cui_item_ops = { .flags = XFS_ITEM_INTENT, .iop_size = xfs_cui_item_size, @@ -548,7 +549,6 @@ static const struct xfs_item_ops xfs_cui_item_ops = { .iop_unpin = xfs_cui_item_unpin, .iop_release = xfs_cui_item_release, .iop_match = xfs_cui_item_match, - .iop_relog = xfs_cui_item_relog, }; static inline void diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index 96e0c2b0d059..488c4a2a80a3 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c @@ -554,31 +554,12 @@ xfs_rmap_recover_work( return error; } -const struct xfs_defer_op_type xfs_rmap_update_defer_type = { - .max_items = XFS_RUI_MAX_FAST_EXTENTS, - .create_intent = xfs_rmap_update_create_intent, - .abort_intent = xfs_rmap_update_abort_intent, - .create_done = xfs_rmap_update_create_done, - .finish_item = xfs_rmap_update_finish_item, - .finish_cleanup = xfs_rmap_finish_one_cleanup, - .cancel_item = xfs_rmap_update_cancel_item, - .recover_work = xfs_rmap_recover_work, -}; - -STATIC bool -xfs_rui_item_match( - struct xfs_log_item *lip, - uint64_t intent_id) -{ - return RUI_ITEM(lip)->rui_format.rui_id == intent_id; -} - /* Relog an intent item to push the log tail forward. */ static struct xfs_log_item * -xfs_rui_item_relog( +xfs_rmap_relog_intent( + struct xfs_trans *tp, struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp) + struct xfs_log_item *done_item) { struct xfs_rui_log_item *ruip; struct xfs_map_extent *map; @@ -594,6 +575,26 @@ xfs_rui_item_relog( return &ruip->rui_item; } +const struct xfs_defer_op_type xfs_rmap_update_defer_type = { + .max_items = XFS_RUI_MAX_FAST_EXTENTS, + .create_intent = xfs_rmap_update_create_intent, + .abort_intent = xfs_rmap_update_abort_intent, + .create_done = xfs_rmap_update_create_done, + .finish_item = xfs_rmap_update_finish_item, + .finish_cleanup = xfs_rmap_finish_one_cleanup, + .cancel_item = xfs_rmap_update_cancel_item, + .recover_work = xfs_rmap_recover_work, + .relog_intent = xfs_rmap_relog_intent, +}; + +STATIC bool +xfs_rui_item_match( + struct xfs_log_item *lip, + uint64_t intent_id) +{ + return RUI_ITEM(lip)->rui_format.rui_id == intent_id; +} + static const struct xfs_item_ops xfs_rui_item_ops = { .flags = XFS_ITEM_INTENT, .iop_size = xfs_rui_item_size, @@ -601,7 +602,6 @@ static const struct xfs_item_ops xfs_rui_item_ops = { .iop_unpin = xfs_rui_item_unpin, .iop_release = xfs_rui_item_release, .iop_match = xfs_rui_item_match, - .iop_relog = xfs_rui_item_relog, }; static inline void diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 25646e2b12f4..2cb1e143fc49 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -79,9 +79,6 @@ struct xfs_item_ops { uint (*iop_push)(struct xfs_log_item *, struct list_head *); void (*iop_release)(struct xfs_log_item *); bool (*iop_match)(struct xfs_log_item *item, uint64_t id); - struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent, - struct xfs_log_item *done_item, - struct xfs_trans *tp); struct xfs_log_item *(*iop_intent)(struct xfs_log_item *intent_done); }; @@ -246,15 +243,6 @@ void xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, extern struct kmem_cache *xfs_trans_cache; -static inline struct xfs_log_item * -xfs_trans_item_relog( - struct xfs_log_item *lip, - struct xfs_log_item *done_lip, - struct xfs_trans *tp) -{ - return lip->li_ops->iop_relog(lip, done_lip, tp); -} - struct xfs_dquot; int xfs_trans_alloc_inode(struct xfs_inode *ip, struct xfs_trans_res *resv, From e14293803f4e84eb23a417b462b56251033b5a66 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 1 Dec 2023 09:24:18 -0800 Subject: [PATCH 2925/7721] xfs: don't allow overly small or large realtime volumes Don't allow realtime volumes that are less than one rt extent long. This has been broken across 4 LTS kernels with nobody noticing, so let's just disable it. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_rtbitmap.h | 13 +++++++++++++ fs/xfs/libxfs/xfs_sb.c | 3 ++- fs/xfs/xfs_rtalloc.c | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_rtbitmap.h b/fs/xfs/libxfs/xfs_rtbitmap.h index 6e5bae324cc3..1c84b52de3d4 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.h +++ b/fs/xfs/libxfs/xfs_rtbitmap.h @@ -353,6 +353,18 @@ int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno, uint8_t xfs_compute_rextslog(xfs_rtbxlen_t rtextents); +/* Do we support an rt volume having this number of rtextents? */ +static inline bool +xfs_validate_rtextents( + xfs_rtbxlen_t rtextents) +{ + /* No runt rt volumes */ + if (rtextents == 0) + return false; + + return true; +} + xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents); unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp, @@ -372,6 +384,7 @@ unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp, # define xfs_rtbuf_cache_relse(a) (0) # define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS) # define xfs_compute_rextslog(rtx) (0) +# define xfs_validate_rtextents(rtx) (false) static inline xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents) { diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index df12bf82ed18..4a9e8588f4c9 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -509,7 +509,8 @@ xfs_validate_sb_common( rbmblocks = howmany_64(sbp->sb_rextents, NBBY * sbp->sb_blocksize); - if (sbp->sb_rextents != rexts || + if (!xfs_validate_rtextents(rexts) || + sbp->sb_rextents != rexts || sbp->sb_rextslog != xfs_compute_rextslog(rexts) || sbp->sb_rbmblocks != rbmblocks) { xfs_notice(mp, diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 7c5a50163d2d..8feb58c6241c 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -963,6 +963,8 @@ xfs_growfs_rt( */ nrextents = nrblocks; do_div(nrextents, in->extsize); + if (!xfs_validate_rtextents(nrextents)) + return -EINVAL; nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents); nrextslog = xfs_compute_rextslog(nrextents); nrsumlevels = nrextslog + 1; From 9c07bca793b4ff9f0b7871e2a928a1b28b8fa4e3 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 4 Dec 2023 12:21:06 -0800 Subject: [PATCH 2926/7721] xfs: elide ->create_done calls for unlogged deferred work Extended attribute updates use the deferred work machinery to manage state across a chain of smaller transactions. All previous deferred work users have employed log intent items and log done items to manage restarting of interrupted operations, which means that ->create_intent sets dfp_intent to a log intent item and ->create_done uses that item to create a log intent done item. However, xattrs have used the INCOMPLETE flag to deal with the lack of recovery support for an interrupted transaction chain. Log items are optional if the xattr update caller didn't set XFS_DA_OP_LOGGED to require a restartable sequence. In other words, ->create_intent can return NULL to say that there's no log intent item. If that's the case, no log intent done item should be created. Clean up xfs_defer_create_done not to do this, so that the ->create_done functions don't have to check for non-null dfp_intent themselves. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 4 ++++ fs/xfs/xfs_attr_item.c | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 54a6be06e6cd..06e890b44c52 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -201,6 +201,10 @@ xfs_defer_create_done( const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; struct xfs_log_item *lip; + /* If there is no log intent item, there can be no log done item. */ + if (!dfp->dfp_intent) + return; + /* * Mark the transaction dirty, even on error. This ensures the * transaction is aborted, which: diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 988d395a48ad..39f2c5a46179 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -740,9 +740,6 @@ xfs_attr_create_done( struct xfs_attri_log_item *attrip; struct xfs_attrd_log_item *attrdp; - if (!intent) - return NULL; - attrip = ATTRI_ITEM(intent); attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL); From 3f113c2739b1b068854c7ffed635c2bd790d1492 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:54 -0800 Subject: [PATCH 2927/7721] xfs: make xchk_iget safer in the presence of corrupt inode btrees When scrub is trying to iget an inode, ensure that it won't end up deadlocked on a cycle in the inode btree by using an empty transaction to store all the buffers. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/scrub/common.c | 6 ++++-- fs/xfs/scrub/common.h | 25 +++++++++++++++++++++++++ fs/xfs/scrub/inode.c | 4 ++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c index de24532fe083..23944fcc1a6c 100644 --- a/fs/xfs/scrub/common.c +++ b/fs/xfs/scrub/common.c @@ -733,6 +733,8 @@ xchk_iget( xfs_ino_t inum, struct xfs_inode **ipp) { + ASSERT(sc->tp != NULL); + return xfs_iget(sc->mp, sc->tp, inum, XFS_IGET_UNTRUSTED, 0, ipp); } @@ -882,8 +884,8 @@ xchk_iget_for_scrubbing( if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino)) return -ENOENT; - /* Try a regular untrusted iget. */ - error = xchk_iget(sc, sc->sm->sm_ino, &ip); + /* Try a safe untrusted iget. */ + error = xchk_iget_safe(sc, sc->sm->sm_ino, &ip); if (!error) return xchk_install_handle_inode(sc, ip); if (error == -ENOENT) diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h index cabdc0e16838..c83cf9e5b55f 100644 --- a/fs/xfs/scrub/common.h +++ b/fs/xfs/scrub/common.h @@ -151,12 +151,37 @@ void xchk_iunlock(struct xfs_scrub *sc, unsigned int ilock_flags); void xchk_buffer_recheck(struct xfs_scrub *sc, struct xfs_buf *bp); +/* + * Grab the inode at @inum. The caller must have created a scrub transaction + * so that we can confirm the inumber by walking the inobt and not deadlock on + * a loop in the inobt. + */ int xchk_iget(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_inode **ipp); int xchk_iget_agi(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_buf **agi_bpp, struct xfs_inode **ipp); void xchk_irele(struct xfs_scrub *sc, struct xfs_inode *ip); int xchk_install_handle_inode(struct xfs_scrub *sc, struct xfs_inode *ip); +/* + * Safe version of (untrusted) xchk_iget that uses an empty transaction to + * avoid deadlocking on loops in the inobt. This should only be used in a + * scrub or repair setup routine, and only prior to grabbing a transaction. + */ +static inline int +xchk_iget_safe(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_inode **ipp) +{ + int error; + + ASSERT(sc->tp == NULL); + + error = xchk_trans_alloc(sc, 0); + if (error) + return error; + error = xchk_iget(sc, inum, ipp); + xchk_trans_cancel(sc); + return error; +} + /* * Don't bother cross-referencing if we already found corruption or cross * referencing discrepancies. diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c index 889f556bc98f..b7a93380a1ab 100644 --- a/fs/xfs/scrub/inode.c +++ b/fs/xfs/scrub/inode.c @@ -95,8 +95,8 @@ xchk_setup_inode( if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino)) return -ENOENT; - /* Try a regular untrusted iget. */ - error = xchk_iget(sc, sc->sm->sm_ino, &ip); + /* Try a safe untrusted iget. */ + error = xchk_iget_safe(sc, sc->sm->sm_ino, &ip); if (!error) return xchk_install_handle_iscrub(sc, ip); if (error == -ENOENT) From 6b126139401a2284402d7c38fe3168d5a26da41d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:55 -0800 Subject: [PATCH 2928/7721] xfs: don't append work items to logged xfs_defer_pending objects When someone tries to add a deferred work item to xfs_defer_add, it will try to attach the work item to the most recently added xfs_defer_pending object attached to the transaction. However, it doesn't check if the pending object has a log intent item attached to it. This is incorrect behavior because we cannot add more work to an object that has already been committed to the ondisk log. Therefore, change the behavior not to append to pending items with a non null dfp_intent. In practice this has not been an issue because the only way xfs_defer_add gets called after log intent items have been committed is from the defer ops ->finish_item functions themselves, and the @dop_pending isolation in xfs_defer_finish_noroll protects the pending items that have already been logged. However, the next patch will add the ability to pause a deferred extent free object during online btree rebuilding, and any new extfree work items need to have their own pending event. While we're at it, hoist the predicate to its own static inline function for readability. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 61 ++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 06e890b44c52..7f9b1c5f2588 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -695,6 +695,51 @@ xfs_defer_cancel( xfs_defer_cancel_list(mp, &tp->t_dfops); } +/* + * Return the last pending work item attached to this transaction if it matches + * the deferred op type. + */ +static inline struct xfs_defer_pending * +xfs_defer_find_last( + struct xfs_trans *tp, + enum xfs_defer_ops_type type, + const struct xfs_defer_op_type *ops) +{ + struct xfs_defer_pending *dfp = NULL; + + /* No dfops at all? */ + if (list_empty(&tp->t_dfops)) + return NULL; + + dfp = list_last_entry(&tp->t_dfops, struct xfs_defer_pending, + dfp_list); + + /* Wrong type? */ + if (dfp->dfp_type != type) + return NULL; + return dfp; +} + +/* + * Decide if we can add a deferred work item to the last dfops item attached + * to the transaction. + */ +static inline bool +xfs_defer_can_append( + struct xfs_defer_pending *dfp, + const struct xfs_defer_op_type *ops) +{ + /* Already logged? */ + if (dfp->dfp_intent) + return false; + + /* Already full? */ + if (ops->max_items && dfp->dfp_count >= ops->max_items) + return false; + + return true; +} + /* Add an item for later deferred processing. */ void xfs_defer_add( @@ -708,19 +753,9 @@ xfs_defer_add( ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); BUILD_BUG_ON(ARRAY_SIZE(defer_op_types) != XFS_DEFER_OPS_TYPE_MAX); - /* - * Add the item to a pending item at the end of the intake list. - * If the last pending item has the same type, reuse it. Else, - * create a new pending item at the end of the intake list. - */ - if (!list_empty(&tp->t_dfops)) { - dfp = list_last_entry(&tp->t_dfops, - struct xfs_defer_pending, dfp_list); - if (dfp->dfp_type != type || - (ops->max_items && dfp->dfp_count >= ops->max_items)) - dfp = NULL; - } - if (!dfp) { + dfp = xfs_defer_find_last(tp, type, ops); + if (!dfp || !xfs_defer_can_append(dfp, ops)) { + /* Create a new pending item at the end of the intake list. */ dfp = kmem_cache_zalloc(xfs_defer_pending_cache, GFP_NOFS | __GFP_NOFAIL); dfp->dfp_type = type; From 4dffb2cbb4839fd6f9bbac0b3fd06cc9015cbb9b Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:56 -0800 Subject: [PATCH 2929/7721] xfs: allow pausing of pending deferred work items Traditionally, all pending deferred work attached to a transaction is finished when one of the xfs_defer_finish* functions is called. However, online repair wants to be able to allocate space for a new data structure, format a new metadata structure into the allocated space, and commit that into the filesystem. As a hedge against system crashes during repairs, we also want to log some EFI items for the allocated space speculatively, and cancel them if we elect to commit the new data structure. Therefore, introduce the idea of pausing a pending deferred work item. Log intent items are still created for paused items and relogged as necessary. However, paused items are pushed onto a side list before we start calling ->finish_item, and the whole list is reattach to the transaction afterwards. New work items are never attached to paused pending items. Modify xfs_defer_cancel to clean up pending deferred work items holding a log intent item but not a log intent done item, since that is now possible. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 97 ++++++++++++++++++++++++++++++++++----- fs/xfs/libxfs/xfs_defer.h | 17 ++++++- fs/xfs/xfs_trace.h | 13 +++++- 3 files changed, 111 insertions(+), 16 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 7f9b1c5f2588..c4480dec29ec 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -487,7 +487,7 @@ xfs_defer_relog_intent( * done item to release the intent item; and then log a new intent item. * The caller should provide a fresh transaction and roll it after we're done. */ -static int +static void xfs_defer_relog( struct xfs_trans **tpp, struct list_head *dfops) @@ -529,10 +529,6 @@ xfs_defer_relog( xfs_defer_relog_intent(*tpp, dfp); } - - if ((*tpp)->t_flags & XFS_TRANS_DIRTY) - return xfs_defer_trans_roll(tpp); - return 0; } /* @@ -588,6 +584,24 @@ xfs_defer_finish_one( return error; } +/* Move all paused deferred work from @tp to @paused_list. */ +static void +xfs_defer_isolate_paused( + struct xfs_trans *tp, + struct list_head *paused_list) +{ + struct xfs_defer_pending *dfp; + struct xfs_defer_pending *pli; + + list_for_each_entry_safe(dfp, pli, &tp->t_dfops, dfp_list) { + if (!(dfp->dfp_flags & XFS_DEFER_PAUSED)) + continue; + + list_move_tail(&dfp->dfp_list, paused_list); + trace_xfs_defer_isolate_paused(tp->t_mountp, dfp); + } +} + /* * Finish all the pending work. This involves logging intent items for * any work items that wandered in since the last transaction roll (if @@ -603,6 +617,7 @@ xfs_defer_finish_noroll( struct xfs_defer_pending *dfp = NULL; int error = 0; LIST_HEAD(dop_pending); + LIST_HEAD(dop_paused); ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); @@ -621,6 +636,8 @@ xfs_defer_finish_noroll( */ int has_intents = xfs_defer_create_intents(*tp); + xfs_defer_isolate_paused(*tp, &dop_paused); + list_splice_init(&(*tp)->t_dfops, &dop_pending); if (has_intents < 0) { @@ -633,22 +650,33 @@ xfs_defer_finish_noroll( goto out_shutdown; /* Relog intent items to keep the log moving. */ - error = xfs_defer_relog(tp, &dop_pending); - if (error) - goto out_shutdown; + xfs_defer_relog(tp, &dop_pending); + xfs_defer_relog(tp, &dop_paused); + + if ((*tp)->t_flags & XFS_TRANS_DIRTY) { + error = xfs_defer_trans_roll(tp); + if (error) + goto out_shutdown; + } } - dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, - dfp_list); + dfp = list_first_entry_or_null(&dop_pending, + struct xfs_defer_pending, dfp_list); + if (!dfp) + break; error = xfs_defer_finish_one(*tp, dfp); if (error && error != -EAGAIN) goto out_shutdown; } + /* Requeue the paused items in the outgoing transaction. */ + list_splice_tail_init(&dop_paused, &(*tp)->t_dfops); + trace_xfs_defer_finish_done(*tp, _RET_IP_); return 0; out_shutdown: + list_splice_tail_init(&dop_paused, &dop_pending); xfs_defer_trans_abort(*tp, &dop_pending); xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); trace_xfs_defer_finish_error(*tp, error); @@ -661,6 +689,9 @@ int xfs_defer_finish( struct xfs_trans **tp) { +#ifdef DEBUG + struct xfs_defer_pending *dfp; +#endif int error; /* @@ -680,7 +711,10 @@ xfs_defer_finish( } /* Reset LOWMODE now that we've finished all the dfops. */ - ASSERT(list_empty(&(*tp)->t_dfops)); +#ifdef DEBUG + list_for_each_entry(dfp, &(*tp)->t_dfops, dfp_list) + ASSERT(dfp->dfp_flags & XFS_DEFER_PAUSED); +#endif (*tp)->t_flags &= ~XFS_TRANS_LOWMODE; return 0; } @@ -692,6 +726,7 @@ xfs_defer_cancel( struct xfs_mount *mp = tp->t_mountp; trace_xfs_defer_cancel(tp, _RET_IP_); + xfs_defer_trans_abort(tp, &tp->t_dfops); xfs_defer_cancel_list(mp, &tp->t_dfops); } @@ -733,6 +768,10 @@ xfs_defer_can_append( if (dfp->dfp_intent) return false; + /* Paused items cannot absorb more work */ + if (dfp->dfp_flags & XFS_DEFER_PAUSED) + return NULL; + /* Already full? */ if (ops->max_items && dfp->dfp_count >= ops->max_items) return false; @@ -741,7 +780,7 @@ xfs_defer_can_append( } /* Add an item for later deferred processing. */ -void +struct xfs_defer_pending * xfs_defer_add( struct xfs_trans *tp, enum xfs_defer_ops_type type, @@ -768,6 +807,7 @@ xfs_defer_add( xfs_defer_add_item(dfp, li); trace_xfs_defer_add_item(tp->t_mountp, dfp, li); + return dfp; } /* @@ -1093,3 +1133,36 @@ xfs_defer_destroy_item_caches(void) xfs_rmap_intent_destroy_cache(); xfs_defer_destroy_cache(); } + +/* + * Mark a deferred work item so that it will be requeued indefinitely without + * being finished. Caller must ensure there are no data dependencies on this + * work item in the meantime. + */ +void +xfs_defer_item_pause( + struct xfs_trans *tp, + struct xfs_defer_pending *dfp) +{ + ASSERT(!(dfp->dfp_flags & XFS_DEFER_PAUSED)); + + dfp->dfp_flags |= XFS_DEFER_PAUSED; + + trace_xfs_defer_item_pause(tp->t_mountp, dfp); +} + +/* + * Release a paused deferred work item so that it will be finished during the + * next transaction roll. + */ +void +xfs_defer_item_unpause( + struct xfs_trans *tp, + struct xfs_defer_pending *dfp) +{ + ASSERT(dfp->dfp_flags & XFS_DEFER_PAUSED); + + dfp->dfp_flags &= ~XFS_DEFER_PAUSED; + + trace_xfs_defer_item_unpause(tp->t_mountp, dfp); +} diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index 78d6dcd1af2c..b0284154f4e0 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -34,11 +34,24 @@ struct xfs_defer_pending { struct xfs_log_item *dfp_intent; /* log intent item */ struct xfs_log_item *dfp_done; /* log done item */ unsigned int dfp_count; /* # extent items */ + unsigned int dfp_flags; enum xfs_defer_ops_type dfp_type; }; -void xfs_defer_add(struct xfs_trans *tp, enum xfs_defer_ops_type type, - struct list_head *h); +/* + * Create a log intent item for this deferred item, but don't actually finish + * the work. Caller must clear this before the final transaction commit. + */ +#define XFS_DEFER_PAUSED (1U << 0) + +#define XFS_DEFER_PENDING_STRINGS \ + { XFS_DEFER_PAUSED, "paused" } + +void xfs_defer_item_pause(struct xfs_trans *tp, struct xfs_defer_pending *dfp); +void xfs_defer_item_unpause(struct xfs_trans *tp, struct xfs_defer_pending *dfp); + +struct xfs_defer_pending *xfs_defer_add(struct xfs_trans *tp, + enum xfs_defer_ops_type type, struct list_head *h); int xfs_defer_finish_noroll(struct xfs_trans **tp); int xfs_defer_finish(struct xfs_trans **tp); int xfs_defer_finish_one(struct xfs_trans *tp, struct xfs_defer_pending *dfp); diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 3926cf7f2a6e..514095b6ba2b 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -2551,6 +2551,7 @@ DECLARE_EVENT_CLASS(xfs_defer_pending_class, __field(dev_t, dev) __field(int, type) __field(void *, intent) + __field(unsigned int, flags) __field(char, committed) __field(int, nr) ), @@ -2558,13 +2559,15 @@ DECLARE_EVENT_CLASS(xfs_defer_pending_class, __entry->dev = mp ? mp->m_super->s_dev : 0; __entry->type = dfp->dfp_type; __entry->intent = dfp->dfp_intent; + __entry->flags = dfp->dfp_flags; __entry->committed = dfp->dfp_done != NULL; __entry->nr = dfp->dfp_count; ), - TP_printk("dev %d:%d optype %d intent %p committed %d nr %d", + TP_printk("dev %d:%d optype %d intent %p flags %s committed %d nr %d", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->type, __entry->intent, + __print_flags(__entry->flags, "|", XFS_DEFER_PENDING_STRINGS), __entry->committed, __entry->nr) ) @@ -2675,6 +2678,9 @@ DEFINE_DEFER_PENDING_EVENT(xfs_defer_cancel_list); DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish); DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort); DEFINE_DEFER_PENDING_EVENT(xfs_defer_relog_intent); +DEFINE_DEFER_PENDING_EVENT(xfs_defer_isolate_paused); +DEFINE_DEFER_PENDING_EVENT(xfs_defer_item_pause); +DEFINE_DEFER_PENDING_EVENT(xfs_defer_item_unpause); #define DEFINE_BMAP_FREE_DEFERRED_EVENT DEFINE_PHYS_EXTENT_DEFERRED_EVENT DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_defer); @@ -2692,6 +2698,7 @@ DECLARE_EVENT_CLASS(xfs_defer_pending_item_class, __field(void *, intent) __field(void *, item) __field(char, committed) + __field(unsigned int, flags) __field(int, nr) ), TP_fast_assign( @@ -2700,13 +2707,15 @@ DECLARE_EVENT_CLASS(xfs_defer_pending_item_class, __entry->intent = dfp->dfp_intent; __entry->item = item; __entry->committed = dfp->dfp_done != NULL; + __entry->flags = dfp->dfp_flags; __entry->nr = dfp->dfp_count; ), - TP_printk("dev %d:%d optype %d intent %p item %p committed %d nr %d", + TP_printk("dev %d:%d optype %d intent %p item %p flags %s committed %d nr %d", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->type, __entry->intent, __entry->item, + __print_flags(__entry->flags, "|", XFS_DEFER_PENDING_STRINGS), __entry->committed, __entry->nr) ) From 4c88fef3af4a51c2cdba6a28237e98da4873e8dc Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:57 -0800 Subject: [PATCH 2930/7721] xfs: remove __xfs_free_extent_later xfs_free_extent_later is a trivial helper, so remove it to reduce the amount of thinking required to understand the deferred freeing interface. This will make it easier to introduce automatic reaping of speculative allocations in the next patch. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_ag.c | 2 +- fs/xfs/libxfs/xfs_alloc.c | 2 +- fs/xfs/libxfs/xfs_alloc.h | 14 +------------- fs/xfs/libxfs/xfs_bmap.c | 4 ++-- fs/xfs/libxfs/xfs_bmap_btree.c | 2 +- fs/xfs/libxfs/xfs_ialloc.c | 5 +++-- fs/xfs/libxfs/xfs_ialloc_btree.c | 2 +- fs/xfs/libxfs/xfs_refcount.c | 6 +++--- fs/xfs/libxfs/xfs_refcount_btree.c | 2 +- fs/xfs/scrub/reap.c | 2 +- fs/xfs/xfs_reflink.c | 2 +- 11 files changed, 16 insertions(+), 27 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c index f9f4d694640d..f62ff125a50a 100644 --- a/fs/xfs/libxfs/xfs_ag.c +++ b/fs/xfs/libxfs/xfs_ag.c @@ -984,7 +984,7 @@ xfs_ag_shrink_space( if (err2 != -ENOSPC) goto resv_err; - err2 = __xfs_free_extent_later(*tpp, args.fsbno, delta, NULL, + err2 = xfs_free_extent_later(*tpp, args.fsbno, delta, NULL, XFS_AG_RESV_NONE, true); if (err2) goto resv_err; diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 100ab5931b31..c35224ad9428 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2523,7 +2523,7 @@ xfs_defer_agfl_block( * The list is maintained sorted (by block number). */ int -__xfs_free_extent_later( +xfs_free_extent_later( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h index 6bb8d295c321..6b95d1d8a853 100644 --- a/fs/xfs/libxfs/xfs_alloc.h +++ b/fs/xfs/libxfs/xfs_alloc.h @@ -231,7 +231,7 @@ xfs_buf_to_agfl_bno( return bp->b_addr; } -int __xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno, +int xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type, bool skip_discard); @@ -256,18 +256,6 @@ void xfs_extent_free_get_group(struct xfs_mount *mp, #define XFS_EFI_ATTR_FORK (1U << 1) /* freeing attr fork block */ #define XFS_EFI_BMBT_BLOCK (1U << 2) /* freeing bmap btree block */ -static inline int -xfs_free_extent_later( - struct xfs_trans *tp, - xfs_fsblock_t bno, - xfs_filblks_t len, - const struct xfs_owner_info *oinfo, - enum xfs_ag_resv_type type) -{ - return __xfs_free_extent_later(tp, bno, len, oinfo, type, false); -} - - extern struct kmem_cache *xfs_extfree_item_cache; int __init xfs_extfree_intent_init_cache(void); diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index be62acffad6c..68be1dd4f0f2 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -575,7 +575,7 @@ xfs_bmap_btree_to_extents( xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) return error; @@ -5218,7 +5218,7 @@ xfs_bmap_del_extent_real( if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) { xfs_refcount_decrease_extent(tp, del); } else { - error = __xfs_free_extent_later(tp, del->br_startblock, + error = xfs_free_extent_later(tp, del->br_startblock, del->br_blockcount, NULL, XFS_AG_RESV_NONE, ((bflags & XFS_BMAPI_NODISCARD) || diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index bf3f1b36fdd2..8360256cff16 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -272,7 +272,7 @@ xfs_bmbt_free_block( xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork); error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) return error; diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index b83e54c70906..d61d03e5b853 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1854,7 +1854,7 @@ xfs_difree_inode_chunk( return xfs_free_extent_later(tp, XFS_AGB_TO_FSB(mp, agno, sagbno), M_IGEO(mp)->ialloc_blks, &XFS_RMAP_OINFO_INODES, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); } /* holemask is only 16-bits (fits in an unsigned long) */ @@ -1900,7 +1900,8 @@ xfs_difree_inode_chunk( ASSERT(contigblk % mp->m_sb.sb_spino_align == 0); error = xfs_free_extent_later(tp, XFS_AGB_TO_FSB(mp, agno, agbno), contigblk, - &XFS_RMAP_OINFO_INODES, XFS_AG_RESV_NONE); + &XFS_RMAP_OINFO_INODES, XFS_AG_RESV_NONE, + false); if (error) return error; diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c index 9258f01c0015..42a5e1f227a0 100644 --- a/fs/xfs/libxfs/xfs_ialloc_btree.c +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c @@ -161,7 +161,7 @@ __xfs_inobt_free_block( xfs_inobt_mod_blockcount(cur, -1); fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp)); return xfs_free_extent_later(cur->bc_tp, fsbno, 1, - &XFS_RMAP_OINFO_INOBT, resv); + &XFS_RMAP_OINFO_INOBT, resv, false); } STATIC int diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 646b3fa362ad..3702b4a07110 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c @@ -1153,7 +1153,7 @@ xfs_refcount_adjust_extents( tmp.rc_startblock); error = xfs_free_extent_later(cur->bc_tp, fsbno, tmp.rc_blockcount, NULL, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) goto out_error; } @@ -1215,7 +1215,7 @@ xfs_refcount_adjust_extents( ext.rc_startblock); error = xfs_free_extent_later(cur->bc_tp, fsbno, ext.rc_blockcount, NULL, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) goto out_error; } @@ -1985,7 +1985,7 @@ xfs_refcount_recover_cow_leftovers( /* Free the block. */ error = xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) goto out_trans; diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c index 5c3987d8dc24..3fa795e2488d 100644 --- a/fs/xfs/libxfs/xfs_refcount_btree.c +++ b/fs/xfs/libxfs/xfs_refcount_btree.c @@ -112,7 +112,7 @@ xfs_refcountbt_free_block( be32_add_cpu(&agf->agf_refcount_blocks, -1); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); return xfs_free_extent_later(cur->bc_tp, fsbno, 1, - &XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA); + &XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA, false); } STATIC int diff --git a/fs/xfs/scrub/reap.c b/fs/xfs/scrub/reap.c index 86a62420e02c..78c9f2085db4 100644 --- a/fs/xfs/scrub/reap.c +++ b/fs/xfs/scrub/reap.c @@ -410,7 +410,7 @@ xreap_agextent_iter( * Use deferred frees to get rid of the old btree blocks to try to * minimize the window in which we could crash and lose the old blocks. */ - error = __xfs_free_extent_later(sc->tp, fsbno, *aglenp, rs->oinfo, + error = xfs_free_extent_later(sc->tp, fsbno, *aglenp, rs->oinfo, rs->resv, true); if (error) return error; diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index e5b62dc28466..d5ca8bcae65b 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -618,7 +618,7 @@ xfs_reflink_cancel_cow_blocks( error = xfs_free_extent_later(*tpp, del.br_startblock, del.br_blockcount, NULL, - XFS_AG_RESV_NONE); + XFS_AG_RESV_NONE, false); if (error) break; From e3042be36c343207b7af249a09f50b4e37e9fda4 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:57 -0800 Subject: [PATCH 2931/7721] xfs: automatic freeing of freshly allocated unwritten space As mentioned in the previous commit, online repair wants to allocate space to write out a new metadata structure, and it also wants to hedge against system crashes during repairs by logging (and later cancelling) EFIs to free the space if we crash before committing the new data structure. Therefore, create a trio of functions to schedule automatic reaping of freshly allocated unwritten space. xfs_alloc_schedule_autoreap creates a paused EFI representing the space we just allocated. Once the allocations are made and the autoreaps scheduled, we can start writing to disk. If the writes succeed, xfs_alloc_cancel_autoreap marks the EFI work items as stale and unpauses the pending deferred work item. Assuming that's done in the same transaction that commits the new structure into the filesystem, we guarantee that either the new object is fully visible, or that all the space gets reclaimed. If the writes succeed but only part of an extent was used, repair must call the same _cancel_autoreap function to kill the first EFI and then log a new EFI to free the unused space. The first EFI is already committed, so it cannot be changed. For full extents that aren't used, xfs_alloc_commit_autoreap will unpause the EFI, which results in the space being freed during the next _defer_finish cycle. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_alloc.c | 104 ++++++++++++++++++++++++++++++++++++-- fs/xfs/libxfs/xfs_alloc.h | 12 +++++ fs/xfs/xfs_extfree_item.c | 9 ++-- 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index c35224ad9428..4940f9377f21 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2522,14 +2522,15 @@ xfs_defer_agfl_block( * Add the extent to the list of extents to be free at transaction end. * The list is maintained sorted (by block number). */ -int -xfs_free_extent_later( +static int +xfs_defer_extent_free( struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type, - bool skip_discard) + bool skip_discard, + struct xfs_defer_pending **dfpp) { struct xfs_extent_free_item *xefi; struct xfs_mount *mp = tp->t_mountp; @@ -2577,10 +2578,105 @@ xfs_free_extent_later( XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len); xfs_extent_free_get_group(mp, xefi); - xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list); + *dfpp = xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list); return 0; } +int +xfs_free_extent_later( + struct xfs_trans *tp, + xfs_fsblock_t bno, + xfs_filblks_t len, + const struct xfs_owner_info *oinfo, + enum xfs_ag_resv_type type, + bool skip_discard) +{ + struct xfs_defer_pending *dontcare = NULL; + + return xfs_defer_extent_free(tp, bno, len, oinfo, type, skip_discard, + &dontcare); +} + +/* + * Set up automatic freeing of unwritten space in the filesystem. + * + * This function attached a paused deferred extent free item to the + * transaction. Pausing means that the EFI will be logged in the next + * transaction commit, but the pending EFI will not be finished until the + * pending item is unpaused. + * + * If the system goes down after the EFI has been persisted to the log but + * before the pending item is unpaused, log recovery will find the EFI, fail to + * find the EFD, and free the space. + * + * If the pending item is unpaused, the next transaction commit will log an EFD + * without freeing the space. + * + * Caller must ensure that the tp, fsbno, len, oinfo, and resv flags of the + * @args structure are set to the relevant values. + */ +int +xfs_alloc_schedule_autoreap( + const struct xfs_alloc_arg *args, + bool skip_discard, + struct xfs_alloc_autoreap *aarp) +{ + int error; + + error = xfs_defer_extent_free(args->tp, args->fsbno, args->len, + &args->oinfo, args->resv, skip_discard, &aarp->dfp); + if (error) + return error; + + xfs_defer_item_pause(args->tp, aarp->dfp); + return 0; +} + +/* + * Cancel automatic freeing of unwritten space in the filesystem. + * + * Earlier, we created a paused deferred extent free item and attached it to + * this transaction so that we could automatically roll back a new space + * allocation if the system went down. Now we want to cancel the paused work + * item by marking the EFI stale so we don't actually free the space, unpausing + * the pending item and logging an EFD. + * + * The caller generally should have already mapped the space into the ondisk + * filesystem. If the reserved space was partially used, the caller must call + * xfs_free_extent_later to create a new EFI to free the unused space. + */ +void +xfs_alloc_cancel_autoreap( + struct xfs_trans *tp, + struct xfs_alloc_autoreap *aarp) +{ + struct xfs_defer_pending *dfp = aarp->dfp; + struct xfs_extent_free_item *xefi; + + if (!dfp) + return; + + list_for_each_entry(xefi, &dfp->dfp_work, xefi_list) + xefi->xefi_flags |= XFS_EFI_CANCELLED; + + xfs_defer_item_unpause(tp, dfp); +} + +/* + * Commit automatic freeing of unwritten space in the filesystem. + * + * This unpauses an earlier _schedule_autoreap and commits to freeing the + * allocated space. Call this if none of the reserved space was used. + */ +void +xfs_alloc_commit_autoreap( + struct xfs_trans *tp, + struct xfs_alloc_autoreap *aarp) +{ + if (aarp->dfp) + xfs_defer_item_unpause(tp, aarp->dfp); +} + #ifdef DEBUG /* * Check if an AGF has a free extent record whose length is equal to diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h index 6b95d1d8a853..851cafbd6449 100644 --- a/fs/xfs/libxfs/xfs_alloc.h +++ b/fs/xfs/libxfs/xfs_alloc.h @@ -255,6 +255,18 @@ void xfs_extent_free_get_group(struct xfs_mount *mp, #define XFS_EFI_SKIP_DISCARD (1U << 0) /* don't issue discard */ #define XFS_EFI_ATTR_FORK (1U << 1) /* freeing attr fork block */ #define XFS_EFI_BMBT_BLOCK (1U << 2) /* freeing bmap btree block */ +#define XFS_EFI_CANCELLED (1U << 3) /* dont actually free the space */ + +struct xfs_alloc_autoreap { + struct xfs_defer_pending *dfp; +}; + +int xfs_alloc_schedule_autoreap(const struct xfs_alloc_arg *args, + bool skip_discard, struct xfs_alloc_autoreap *aarp); +void xfs_alloc_cancel_autoreap(struct xfs_trans *tp, + struct xfs_alloc_autoreap *aarp); +void xfs_alloc_commit_autoreap(struct xfs_trans *tp, + struct xfs_alloc_autoreap *aarp); extern struct kmem_cache *xfs_extfree_item_cache; diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 3ca23ab8d92a..3e3469504271 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -453,7 +453,7 @@ xfs_extent_free_finish_item( struct xfs_extent *extp; uint next_extent; xfs_agblock_t agbno; - int error; + int error = 0; xefi = container_of(item, struct xfs_extent_free_item, xefi_list); agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock); @@ -473,9 +473,10 @@ xfs_extent_free_finish_item( * the existing EFI, and so we need to copy all the unprocessed extents * in this EFI to the EFD so this works correctly. */ - error = __xfs_free_extent(tp, xefi->xefi_pag, agbno, - xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv, - xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); + if (!(xefi->xefi_flags & XFS_EFI_CANCELLED)) + error = __xfs_free_extent(tp, xefi->xefi_pag, agbno, + xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv, + xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); if (error == -EAGAIN) { xfs_efd_from_efi(efdp); return error; From 4c8ecd1cfdd01fb727121035014d9f654a30bdf2 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:58 -0800 Subject: [PATCH 2932/7721] xfs: remove unused fields from struct xbtree_ifakeroot Remove these unused fields since nobody uses them. They should have been removed years ago in a different cleanup series from Christoph Hellwig. Fixes: daf83964a3681 ("xfs: move the per-fork nextents fields into struct xfs_ifork") Fixes: f7e67b20ecbbc ("xfs: move the fork format fields into struct xfs_ifork") Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner --- fs/xfs/libxfs/xfs_btree_staging.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree_staging.h b/fs/xfs/libxfs/xfs_btree_staging.h index f0d2976050ae..5f638f711246 100644 --- a/fs/xfs/libxfs/xfs_btree_staging.h +++ b/fs/xfs/libxfs/xfs_btree_staging.h @@ -37,12 +37,6 @@ struct xbtree_ifakeroot { /* Number of bytes available for this fork in the inode. */ unsigned int if_fork_size; - - /* Fork format. */ - unsigned int if_format; - - /* Number of records. */ - unsigned int if_extents; }; /* Cursor interactions with fake roots for inode-rooted btrees. */ From be408417630427984a1fddd069f30b245793234c Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:40:59 -0800 Subject: [PATCH 2933/7721] xfs: implement block reservation accounting for btrees we're staging Create a new xrep_newbt structure to encapsulate a fake root for creating a staged btree cursor as well as to track all the blocks that we need to reserve in order to build that btree. As for the particular choice of lowspace thresholds and btree block slack factors -- at this point one could say that the thresholds in online repair come from bulkload_estimate_ag_slack in xfs_repair[1]. But that's not the entire story, since the offline btree rebuilding code in xfs_repair was merged as a retroport of the online btree code in this patchset! Before xfs_btree_staging.[ch] came along, xfs_repair determined the slack factor (aka the number of slots to leave unfilled in each new btree block) via open-coded logic in repair/phase5.c[2]. At that point the slack factors were arbitrary quantities per btree. The rmapbt automatically left 10 slots free; everything else left zero. That had a noticeable effect on performance straight after mounting because adding records to /any/ btree would result in splits. A few years ago when this patch was first written, Dave and I decided that repair should generate btree blocks that were 75% full unless space was tight, in which case it should try to fill the blocks to nearly full. We defined tight as ~10% free to avoid repair failures but settled on 3/32 (~9%) to avoid div64. IOWs, we mostly pulled the thresholds out of thin air. We've been QAing with those geometry numbers ever since. ;) Link: https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/tree/repair/bulkload.c?h=v6.5.0#n114 Link: https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/tree/repair/phase5.c?h=v4.19.0#n1349 Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner --- fs/xfs/Makefile | 1 + fs/xfs/scrub/newbt.c | 495 +++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/newbt.h | 62 ++++++ fs/xfs/scrub/trace.h | 37 ++++ 4 files changed, 595 insertions(+) create mode 100644 fs/xfs/scrub/newbt.c create mode 100644 fs/xfs/scrub/newbt.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 7762c01a85cf..1537d66e5ab0 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -181,6 +181,7 @@ xfs-$(CONFIG_XFS_QUOTA) += scrub/quota.o ifeq ($(CONFIG_XFS_ONLINE_REPAIR),y) xfs-y += $(addprefix scrub/, \ agheader_repair.o \ + newbt.o \ reap.o \ repair.o \ ) diff --git a/fs/xfs/scrub/newbt.c b/fs/xfs/scrub/newbt.c new file mode 100644 index 000000000000..5d1d75d2b1ad --- /dev/null +++ b/fs/xfs/scrub/newbt.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022-2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_btree.h" +#include "xfs_btree_staging.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_rmap.h" +#include "xfs_ag.h" +#include "xfs_defer.h" +#include "scrub/scrub.h" +#include "scrub/common.h" +#include "scrub/trace.h" +#include "scrub/repair.h" +#include "scrub/newbt.h" + +/* + * Estimate proper slack values for a btree that's being reloaded. + * + * Under most circumstances, we'll take whatever default loading value the + * btree bulk loading code calculates for us. However, there are some + * exceptions to this rule: + * + * (1) If this is a per-AG btree and the AG has less than 10% space free. + * (2) If this is an inode btree and the FS has less than 10% space free. + + * In either case, format the new btree blocks almost completely full to + * minimize space usage. + */ +static void +xrep_newbt_estimate_slack( + struct xrep_newbt *xnr) +{ + struct xfs_scrub *sc = xnr->sc; + struct xfs_btree_bload *bload = &xnr->bload; + uint64_t free; + uint64_t sz; + + /* Let the btree code compute the default slack values. */ + bload->leaf_slack = -1; + bload->node_slack = -1; + + if (sc->ops->type == ST_PERAG) { + free = sc->sa.pag->pagf_freeblks; + sz = xfs_ag_block_count(sc->mp, sc->sa.pag->pag_agno); + } else { + free = percpu_counter_sum(&sc->mp->m_fdblocks); + sz = sc->mp->m_sb.sb_dblocks; + } + + /* No further changes if there's more than 10% free space left. */ + if (free >= div_u64(sz, 10)) + return; + + /* + * We're low on space; load the btrees as tightly as possible. Leave + * a couple of open slots in each btree block so that we don't end up + * splitting the btrees like crazy after a mount. + */ + if (bload->leaf_slack < 0) + bload->leaf_slack = 2; + if (bload->node_slack < 0) + bload->node_slack = 2; +} + +/* Initialize accounting resources for staging a new AG btree. */ +void +xrep_newbt_init_ag( + struct xrep_newbt *xnr, + struct xfs_scrub *sc, + const struct xfs_owner_info *oinfo, + xfs_fsblock_t alloc_hint, + enum xfs_ag_resv_type resv) +{ + memset(xnr, 0, sizeof(struct xrep_newbt)); + xnr->sc = sc; + xnr->oinfo = *oinfo; /* structure copy */ + xnr->alloc_hint = alloc_hint; + xnr->resv = resv; + INIT_LIST_HEAD(&xnr->resv_list); + xrep_newbt_estimate_slack(xnr); +} + +/* Initialize accounting resources for staging a new inode fork btree. */ +int +xrep_newbt_init_inode( + struct xrep_newbt *xnr, + struct xfs_scrub *sc, + int whichfork, + const struct xfs_owner_info *oinfo) +{ + struct xfs_ifork *ifp; + + ifp = kmem_cache_zalloc(xfs_ifork_cache, XCHK_GFP_FLAGS); + if (!ifp) + return -ENOMEM; + + xrep_newbt_init_ag(xnr, sc, oinfo, + XFS_INO_TO_FSB(sc->mp, sc->ip->i_ino), + XFS_AG_RESV_NONE); + xnr->ifake.if_fork = ifp; + xnr->ifake.if_fork_size = xfs_inode_fork_size(sc->ip, whichfork); + return 0; +} + +/* + * Initialize accounting resources for staging a new btree. Callers are + * expected to add their own reservations (and clean them up) manually. + */ +void +xrep_newbt_init_bare( + struct xrep_newbt *xnr, + struct xfs_scrub *sc) +{ + xrep_newbt_init_ag(xnr, sc, &XFS_RMAP_OINFO_ANY_OWNER, NULLFSBLOCK, + XFS_AG_RESV_NONE); +} + +/* + * Designate specific blocks to be used to build our new btree. @pag must be + * a passive reference. + */ +STATIC int +xrep_newbt_add_blocks( + struct xrep_newbt *xnr, + struct xfs_perag *pag, + const struct xfs_alloc_arg *args) +{ + struct xfs_mount *mp = xnr->sc->mp; + struct xrep_newbt_resv *resv; + + resv = kmalloc(sizeof(struct xrep_newbt_resv), XCHK_GFP_FLAGS); + if (!resv) + return -ENOMEM; + + INIT_LIST_HEAD(&resv->list); + resv->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + resv->len = args->len; + resv->used = 0; + resv->pag = xfs_perag_hold(pag); + + list_add_tail(&resv->list, &xnr->resv_list); + return 0; +} + +/* Don't let our allocation hint take us beyond this AG */ +static inline void +xrep_newbt_validate_ag_alloc_hint( + struct xrep_newbt *xnr) +{ + struct xfs_scrub *sc = xnr->sc; + xfs_agnumber_t agno = XFS_FSB_TO_AGNO(sc->mp, xnr->alloc_hint); + + if (agno == sc->sa.pag->pag_agno && + xfs_verify_fsbno(sc->mp, xnr->alloc_hint)) + return; + + xnr->alloc_hint = XFS_AGB_TO_FSB(sc->mp, sc->sa.pag->pag_agno, + XFS_AGFL_BLOCK(sc->mp) + 1); +} + +/* Allocate disk space for a new per-AG btree. */ +STATIC int +xrep_newbt_alloc_ag_blocks( + struct xrep_newbt *xnr, + uint64_t nr_blocks) +{ + struct xfs_scrub *sc = xnr->sc; + struct xfs_mount *mp = sc->mp; + int error = 0; + + ASSERT(sc->sa.pag != NULL); + + while (nr_blocks > 0) { + struct xfs_alloc_arg args = { + .tp = sc->tp, + .mp = mp, + .oinfo = xnr->oinfo, + .minlen = 1, + .maxlen = nr_blocks, + .prod = 1, + .resv = xnr->resv, + }; + xfs_agnumber_t agno; + + xrep_newbt_validate_ag_alloc_hint(xnr); + + error = xfs_alloc_vextent_near_bno(&args, xnr->alloc_hint); + if (error) + return error; + if (args.fsbno == NULLFSBLOCK) + return -ENOSPC; + + agno = XFS_FSB_TO_AGNO(mp, args.fsbno); + + trace_xrep_newbt_alloc_ag_blocks(mp, agno, + XFS_FSB_TO_AGBNO(mp, args.fsbno), args.len, + xnr->oinfo.oi_owner); + + if (agno != sc->sa.pag->pag_agno) { + ASSERT(agno == sc->sa.pag->pag_agno); + return -EFSCORRUPTED; + } + + error = xrep_newbt_add_blocks(xnr, sc->sa.pag, &args); + if (error) + return error; + + nr_blocks -= args.len; + xnr->alloc_hint = args.fsbno + args.len; + + error = xrep_defer_finish(sc); + if (error) + return error; + } + + return 0; +} + +/* Don't let our allocation hint take us beyond EOFS */ +static inline void +xrep_newbt_validate_file_alloc_hint( + struct xrep_newbt *xnr) +{ + struct xfs_scrub *sc = xnr->sc; + + if (xfs_verify_fsbno(sc->mp, xnr->alloc_hint)) + return; + + xnr->alloc_hint = XFS_AGB_TO_FSB(sc->mp, 0, XFS_AGFL_BLOCK(sc->mp) + 1); +} + +/* Allocate disk space for our new file-based btree. */ +STATIC int +xrep_newbt_alloc_file_blocks( + struct xrep_newbt *xnr, + uint64_t nr_blocks) +{ + struct xfs_scrub *sc = xnr->sc; + struct xfs_mount *mp = sc->mp; + int error = 0; + + while (nr_blocks > 0) { + struct xfs_alloc_arg args = { + .tp = sc->tp, + .mp = mp, + .oinfo = xnr->oinfo, + .minlen = 1, + .maxlen = nr_blocks, + .prod = 1, + .resv = xnr->resv, + }; + struct xfs_perag *pag; + xfs_agnumber_t agno; + + xrep_newbt_validate_file_alloc_hint(xnr); + + error = xfs_alloc_vextent_start_ag(&args, xnr->alloc_hint); + if (error) + return error; + if (args.fsbno == NULLFSBLOCK) + return -ENOSPC; + + agno = XFS_FSB_TO_AGNO(mp, args.fsbno); + + trace_xrep_newbt_alloc_file_blocks(mp, agno, + XFS_FSB_TO_AGBNO(mp, args.fsbno), args.len, + xnr->oinfo.oi_owner); + + pag = xfs_perag_get(mp, agno); + if (!pag) { + ASSERT(0); + return -EFSCORRUPTED; + } + + error = xrep_newbt_add_blocks(xnr, pag, &args); + xfs_perag_put(pag); + if (error) + return error; + + nr_blocks -= args.len; + xnr->alloc_hint = args.fsbno + args.len; + + error = xrep_defer_finish(sc); + if (error) + return error; + } + + return 0; +} + +/* Allocate disk space for our new btree. */ +int +xrep_newbt_alloc_blocks( + struct xrep_newbt *xnr, + uint64_t nr_blocks) +{ + if (xnr->sc->ip) + return xrep_newbt_alloc_file_blocks(xnr, nr_blocks); + return xrep_newbt_alloc_ag_blocks(xnr, nr_blocks); +} + +/* + * Free the unused part of a space extent that was reserved for a new ondisk + * structure. Returns the number of EFIs logged or a negative errno. + */ +STATIC int +xrep_newbt_free_extent( + struct xrep_newbt *xnr, + struct xrep_newbt_resv *resv, + bool btree_committed) +{ + struct xfs_scrub *sc = xnr->sc; + xfs_agblock_t free_agbno = resv->agbno; + xfs_extlen_t free_aglen = resv->len; + xfs_fsblock_t fsbno; + int error; + + if (!btree_committed || resv->used == 0) { + /* + * If we're not committing a new btree or we didn't use the + * space reservation, free the entire space extent. + */ + goto free; + } + + /* + * We used space and committed the btree. Remove the written blocks + * from the reservation and possibly log a new EFI to free any unused + * reservation space. + */ + free_agbno += resv->used; + free_aglen -= resv->used; + + if (free_aglen == 0) + return 0; + + trace_xrep_newbt_free_blocks(sc->mp, resv->pag->pag_agno, free_agbno, + free_aglen, xnr->oinfo.oi_owner); + + ASSERT(xnr->resv != XFS_AG_RESV_AGFL); + +free: + /* + * Use EFIs to free the reservations. This reduces the chance + * that we leak blocks if the system goes down. + */ + fsbno = XFS_AGB_TO_FSB(sc->mp, resv->pag->pag_agno, free_agbno); + error = xfs_free_extent_later(sc->tp, fsbno, free_aglen, &xnr->oinfo, + xnr->resv, true); + if (error) + return error; + + return 1; +} + +/* Free all the accounting info and disk space we reserved for a new btree. */ +STATIC int +xrep_newbt_free( + struct xrep_newbt *xnr, + bool btree_committed) +{ + struct xfs_scrub *sc = xnr->sc; + struct xrep_newbt_resv *resv, *n; + unsigned int freed = 0; + int error = 0; + + /* + * If the filesystem already went down, we can't free the blocks. Skip + * ahead to freeing the incore metadata because we can't fix anything. + */ + if (xfs_is_shutdown(sc->mp)) + goto junkit; + + list_for_each_entry_safe(resv, n, &xnr->resv_list, list) { + int ret; + + ret = xrep_newbt_free_extent(xnr, resv, btree_committed); + list_del(&resv->list); + xfs_perag_put(resv->pag); + kfree(resv); + if (ret < 0) { + error = ret; + goto junkit; + } + + freed += ret; + if (freed >= XREP_MAX_ITRUNCATE_EFIS) { + error = xrep_defer_finish(sc); + if (error) + goto junkit; + freed = 0; + } + } + + if (freed) + error = xrep_defer_finish(sc); + +junkit: + /* + * If we still have reservations attached to @newbt, cleanup must have + * failed and the filesystem is about to go down. Clean up the incore + * reservations. + */ + list_for_each_entry_safe(resv, n, &xnr->resv_list, list) { + list_del(&resv->list); + xfs_perag_put(resv->pag); + kfree(resv); + } + + if (sc->ip) { + kmem_cache_free(xfs_ifork_cache, xnr->ifake.if_fork); + xnr->ifake.if_fork = NULL; + } + + return error; +} + +/* + * Free all the accounting info and unused disk space allocations after + * committing a new btree. + */ +int +xrep_newbt_commit( + struct xrep_newbt *xnr) +{ + return xrep_newbt_free(xnr, true); +} + +/* + * Free all the accounting info and all of the disk space we reserved for a new + * btree that we're not going to commit. We want to try to roll things back + * cleanly for things like ENOSPC midway through allocation. + */ +void +xrep_newbt_cancel( + struct xrep_newbt *xnr) +{ + xrep_newbt_free(xnr, false); +} + +/* Feed one of the reserved btree blocks to the bulk loader. */ +int +xrep_newbt_claim_block( + struct xfs_btree_cur *cur, + struct xrep_newbt *xnr, + union xfs_btree_ptr *ptr) +{ + struct xrep_newbt_resv *resv; + struct xfs_mount *mp = cur->bc_mp; + xfs_agblock_t agbno; + + /* + * The first item in the list should always have a free block unless + * we're completely out. + */ + resv = list_first_entry(&xnr->resv_list, struct xrep_newbt_resv, list); + if (resv->used == resv->len) + return -ENOSPC; + + /* + * Peel off a block from the start of the reservation. We allocate + * blocks in order to place blocks on disk in increasing record or key + * order. The block reservations tend to end up on the list in + * decreasing order, which hopefully results in leaf blocks ending up + * together. + */ + agbno = resv->agbno + resv->used; + resv->used++; + + /* If we used all the blocks in this reservation, move it to the end. */ + if (resv->used == resv->len) + list_move_tail(&resv->list, &xnr->resv_list); + + trace_xrep_newbt_claim_block(mp, resv->pag->pag_agno, agbno, 1, + xnr->oinfo.oi_owner); + + if (cur->bc_flags & XFS_BTREE_LONG_PTRS) + ptr->l = cpu_to_be64(XFS_AGB_TO_FSB(mp, resv->pag->pag_agno, + agbno)); + else + ptr->s = cpu_to_be32(agbno); + return 0; +} diff --git a/fs/xfs/scrub/newbt.h b/fs/xfs/scrub/newbt.h new file mode 100644 index 000000000000..ca53271f3a4c --- /dev/null +++ b/fs/xfs/scrub/newbt.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022-2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_SCRUB_NEWBT_H__ +#define __XFS_SCRUB_NEWBT_H__ + +struct xrep_newbt_resv { + /* Link to list of extents that we've reserved. */ + struct list_head list; + + struct xfs_perag *pag; + + /* AG block of the extent we reserved. */ + xfs_agblock_t agbno; + + /* Length of the reservation. */ + xfs_extlen_t len; + + /* How much of this reservation has been used. */ + xfs_extlen_t used; +}; + +struct xrep_newbt { + struct xfs_scrub *sc; + + /* List of extents that we've reserved. */ + struct list_head resv_list; + + /* Fake root for new btree. */ + union { + struct xbtree_afakeroot afake; + struct xbtree_ifakeroot ifake; + }; + + /* rmap owner of these blocks */ + struct xfs_owner_info oinfo; + + /* btree geometry for the bulk loader */ + struct xfs_btree_bload bload; + + /* Allocation hint */ + xfs_fsblock_t alloc_hint; + + /* per-ag reservation type */ + enum xfs_ag_resv_type resv; +}; + +void xrep_newbt_init_bare(struct xrep_newbt *xnr, struct xfs_scrub *sc); +void xrep_newbt_init_ag(struct xrep_newbt *xnr, struct xfs_scrub *sc, + const struct xfs_owner_info *oinfo, xfs_fsblock_t alloc_hint, + enum xfs_ag_resv_type resv); +int xrep_newbt_init_inode(struct xrep_newbt *xnr, struct xfs_scrub *sc, + int whichfork, const struct xfs_owner_info *oinfo); +int xrep_newbt_alloc_blocks(struct xrep_newbt *xnr, uint64_t nr_blocks); +void xrep_newbt_cancel(struct xrep_newbt *xnr); +int xrep_newbt_commit(struct xrep_newbt *xnr); +int xrep_newbt_claim_block(struct xfs_btree_cur *cur, struct xrep_newbt *xnr, + union xfs_btree_ptr *ptr); + +#endif /* __XFS_SCRUB_NEWBT_H__ */ diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index 4a8bc6f3c8f2..aa7683075319 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -1332,6 +1332,43 @@ TRACE_EVENT(xrep_ialloc_insert, __entry->freemask) ) +DECLARE_EVENT_CLASS(xrep_newbt_extent_class, + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno, xfs_extlen_t len, + int64_t owner), + TP_ARGS(mp, agno, agbno, len, owner), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_agnumber_t, agno) + __field(xfs_agblock_t, agbno) + __field(xfs_extlen_t, len) + __field(int64_t, owner) + ), + TP_fast_assign( + __entry->dev = mp->m_super->s_dev; + __entry->agno = agno; + __entry->agbno = agbno; + __entry->len = len; + __entry->owner = owner; + ), + TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x owner 0x%llx", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->agno, + __entry->agbno, + __entry->len, + __entry->owner) +); +#define DEFINE_NEWBT_EXTENT_EVENT(name) \ +DEFINE_EVENT(xrep_newbt_extent_class, name, \ + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ + xfs_agblock_t agbno, xfs_extlen_t len, \ + int64_t owner), \ + TP_ARGS(mp, agno, agbno, len, owner)) +DEFINE_NEWBT_EXTENT_EVENT(xrep_newbt_alloc_ag_blocks); +DEFINE_NEWBT_EXTENT_EVENT(xrep_newbt_alloc_file_blocks); +DEFINE_NEWBT_EXTENT_EVENT(xrep_newbt_free_blocks); +DEFINE_NEWBT_EXTENT_EVENT(xrep_newbt_claim_block); + #endif /* IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) */ #endif /* _TRACE_XFS_SCRUB_TRACE_H */ From 6bb9ea8ecd2c58a66324cb799838e7d49d78a877 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:41:00 -0800 Subject: [PATCH 2934/7721] xfs: log EFIs for all btree blocks being used to stage a btree We need to log EFIs for every extent that we allocate for the purpose of staging a new btree so that if we fail then the blocks will be freed during log recovery. Use the autoreaping mechanism provided by the previous patch to attach paused freeing work to the scrub transaction. We can then mark the EFIs stale if we decide to commit the new btree, or we can unpause the EFIs if we decide to abort the repair. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/scrub/newbt.c | 34 ++++++++++++++++++++++++++-------- fs/xfs/scrub/newbt.h | 3 +++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/fs/xfs/scrub/newbt.c b/fs/xfs/scrub/newbt.c index 5d1d75d2b1ad..992cf34a13e7 100644 --- a/fs/xfs/scrub/newbt.c +++ b/fs/xfs/scrub/newbt.c @@ -139,6 +139,7 @@ xrep_newbt_add_blocks( { struct xfs_mount *mp = xnr->sc->mp; struct xrep_newbt_resv *resv; + int error; resv = kmalloc(sizeof(struct xrep_newbt_resv), XCHK_GFP_FLAGS); if (!resv) @@ -150,8 +151,18 @@ xrep_newbt_add_blocks( resv->used = 0; resv->pag = xfs_perag_hold(pag); + ASSERT(xnr->oinfo.oi_offset == 0); + + error = xfs_alloc_schedule_autoreap(args, true, &resv->autoreap); + if (error) + goto out_pag; + list_add_tail(&resv->list, &xnr->resv_list); return 0; +out_pag: + xfs_perag_put(resv->pag); + kfree(resv); + return error; } /* Don't let our allocation hint take us beyond this AG */ @@ -330,16 +341,21 @@ xrep_newbt_free_extent( if (!btree_committed || resv->used == 0) { /* * If we're not committing a new btree or we didn't use the - * space reservation, free the entire space extent. + * space reservation, let the existing EFI free the entire + * space extent. */ - goto free; + trace_xrep_newbt_free_blocks(sc->mp, resv->pag->pag_agno, + free_agbno, free_aglen, xnr->oinfo.oi_owner); + xfs_alloc_commit_autoreap(sc->tp, &resv->autoreap); + return 1; } /* - * We used space and committed the btree. Remove the written blocks - * from the reservation and possibly log a new EFI to free any unused - * reservation space. + * We used space and committed the btree. Cancel the autoreap, remove + * the written blocks from the reservation, and possibly log a new EFI + * to free any unused reservation space. */ + xfs_alloc_cancel_autoreap(sc->tp, &resv->autoreap); free_agbno += resv->used; free_aglen -= resv->used; @@ -351,7 +367,6 @@ xrep_newbt_free_extent( ASSERT(xnr->resv != XFS_AG_RESV_AGFL); -free: /* * Use EFIs to free the reservations. This reduces the chance * that we leak blocks if the system goes down. @@ -411,9 +426,10 @@ xrep_newbt_free( /* * If we still have reservations attached to @newbt, cleanup must have * failed and the filesystem is about to go down. Clean up the incore - * reservations. + * reservations and try to commit to freeing the space we used. */ list_for_each_entry_safe(resv, n, &xnr->resv_list, list) { + xfs_alloc_commit_autoreap(sc->tp, &resv->autoreap); list_del(&resv->list); xfs_perag_put(resv->pag); kfree(resv); @@ -491,5 +507,7 @@ xrep_newbt_claim_block( agbno)); else ptr->s = cpu_to_be32(agbno); - return 0; + + /* Relog all the EFIs. */ + return xrep_defer_finish(xnr->sc); } diff --git a/fs/xfs/scrub/newbt.h b/fs/xfs/scrub/newbt.h index ca53271f3a4c..d2baffa17b1a 100644 --- a/fs/xfs/scrub/newbt.h +++ b/fs/xfs/scrub/newbt.h @@ -12,6 +12,9 @@ struct xrep_newbt_resv { struct xfs_perag *pag; + /* Auto-freeing this reservation if we don't commit. */ + struct xfs_alloc_autoreap autoreap; + /* AG block of the extent we reserved. */ xfs_agblock_t agbno; From 3f3cec031099c37513727efc978a12b6346e326d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 6 Dec 2023 18:41:00 -0800 Subject: [PATCH 2935/7721] xfs: force small EFIs for reaping btree extents Introduce the concept of a defer ops barrier to separate consecutively queued pending work items of the same type. With a barrier in place, the two work items will be tracked separately, and receive separate log intent items. The goal here is to prevent reaping of old metadata blocks from creating unnecessarily huge EFIs that could then run the risk of overflowing the scrub transaction. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_defer.c | 107 ++++++++++++++++++++++++++++++++++---- fs/xfs/libxfs/xfs_defer.h | 3 ++ fs/xfs/scrub/reap.c | 5 ++ 3 files changed, 104 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index c4480dec29ec..ecc2f7ec6991 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -182,6 +182,58 @@ static struct kmem_cache *xfs_defer_pending_cache; * Note that the continuation requested between t2 and t3 is likely to * reoccur. */ +STATIC struct xfs_log_item * +xfs_defer_barrier_create_intent( + struct xfs_trans *tp, + struct list_head *items, + unsigned int count, + bool sort) +{ + return NULL; +} + +STATIC void +xfs_defer_barrier_abort_intent( + struct xfs_log_item *intent) +{ + /* empty */ +} + +STATIC struct xfs_log_item * +xfs_defer_barrier_create_done( + struct xfs_trans *tp, + struct xfs_log_item *intent, + unsigned int count) +{ + return NULL; +} + +STATIC int +xfs_defer_barrier_finish_item( + struct xfs_trans *tp, + struct xfs_log_item *done, + struct list_head *item, + struct xfs_btree_cur **state) +{ + ASSERT(0); + return -EFSCORRUPTED; +} + +STATIC void +xfs_defer_barrier_cancel_item( + struct list_head *item) +{ + ASSERT(0); +} + +static const struct xfs_defer_op_type xfs_barrier_defer_type = { + .max_items = 1, + .create_intent = xfs_defer_barrier_create_intent, + .abort_intent = xfs_defer_barrier_abort_intent, + .create_done = xfs_defer_barrier_create_done, + .finish_item = xfs_defer_barrier_finish_item, + .cancel_item = xfs_defer_barrier_cancel_item, +}; static const struct xfs_defer_op_type *defer_op_types[] = { [XFS_DEFER_OPS_TYPE_BMAP] = &xfs_bmap_update_defer_type, @@ -190,6 +242,7 @@ static const struct xfs_defer_op_type *defer_op_types[] = { [XFS_DEFER_OPS_TYPE_FREE] = &xfs_extent_free_defer_type, [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, [XFS_DEFER_OPS_TYPE_ATTR] = &xfs_attr_defer_type, + [XFS_DEFER_OPS_TYPE_BARRIER] = &xfs_barrier_defer_type, }; /* Create a log intent done item for a log intent item. */ @@ -779,6 +832,23 @@ xfs_defer_can_append( return true; } +/* Create a new pending item at the end of the transaction list. */ +static inline struct xfs_defer_pending * +xfs_defer_alloc( + struct xfs_trans *tp, + enum xfs_defer_ops_type type) +{ + struct xfs_defer_pending *dfp; + + dfp = kmem_cache_zalloc(xfs_defer_pending_cache, + GFP_NOFS | __GFP_NOFAIL); + dfp->dfp_type = type; + INIT_LIST_HEAD(&dfp->dfp_work); + list_add_tail(&dfp->dfp_list, &tp->t_dfops); + + return dfp; +} + /* Add an item for later deferred processing. */ struct xfs_defer_pending * xfs_defer_add( @@ -793,23 +863,38 @@ xfs_defer_add( BUILD_BUG_ON(ARRAY_SIZE(defer_op_types) != XFS_DEFER_OPS_TYPE_MAX); dfp = xfs_defer_find_last(tp, type, ops); - if (!dfp || !xfs_defer_can_append(dfp, ops)) { - /* Create a new pending item at the end of the intake list. */ - dfp = kmem_cache_zalloc(xfs_defer_pending_cache, - GFP_NOFS | __GFP_NOFAIL); - dfp->dfp_type = type; - dfp->dfp_intent = NULL; - dfp->dfp_done = NULL; - dfp->dfp_count = 0; - INIT_LIST_HEAD(&dfp->dfp_work); - list_add_tail(&dfp->dfp_list, &tp->t_dfops); - } + if (!dfp || !xfs_defer_can_append(dfp, ops)) + dfp = xfs_defer_alloc(tp, type); xfs_defer_add_item(dfp, li); trace_xfs_defer_add_item(tp->t_mountp, dfp, li); return dfp; } +/* + * Add a defer ops barrier to force two otherwise adjacent deferred work items + * to be tracked separately and have separate log items. + */ +void +xfs_defer_add_barrier( + struct xfs_trans *tp) +{ + struct xfs_defer_pending *dfp; + const enum xfs_defer_ops_type type = XFS_DEFER_OPS_TYPE_BARRIER; + const struct xfs_defer_op_type *ops = defer_op_types[type]; + + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + + /* If the last defer op added was a barrier, we're done. */ + dfp = xfs_defer_find_last(tp, type, ops); + if (dfp) + return; + + xfs_defer_alloc(tp, type); + + trace_xfs_defer_add_item(tp->t_mountp, dfp, NULL); +} + /* * Create a pending deferred work item to replay the recovered intent item * and add it to the list. diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index b0284154f4e0..5b1990ef3e5d 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -20,6 +20,7 @@ enum xfs_defer_ops_type { XFS_DEFER_OPS_TYPE_FREE, XFS_DEFER_OPS_TYPE_AGFL_FREE, XFS_DEFER_OPS_TYPE_ATTR, + XFS_DEFER_OPS_TYPE_BARRIER, XFS_DEFER_OPS_TYPE_MAX, }; @@ -163,4 +164,6 @@ xfs_defer_add_item( int __init xfs_defer_init_item_caches(void); void xfs_defer_destroy_item_caches(void); +void xfs_defer_add_barrier(struct xfs_trans *tp); + #endif /* __XFS_DEFER_H__ */ diff --git a/fs/xfs/scrub/reap.c b/fs/xfs/scrub/reap.c index 78c9f2085db4..ee26fcb500b7 100644 --- a/fs/xfs/scrub/reap.c +++ b/fs/xfs/scrub/reap.c @@ -31,6 +31,7 @@ #include "xfs_da_btree.h" #include "xfs_attr.h" #include "xfs_attr_remote.h" +#include "xfs_defer.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" @@ -409,6 +410,8 @@ xreap_agextent_iter( /* * Use deferred frees to get rid of the old btree blocks to try to * minimize the window in which we could crash and lose the old blocks. + * Add a defer ops barrier every other extent to avoid stressing the + * system with large EFIs. */ error = xfs_free_extent_later(sc->tp, fsbno, *aglenp, rs->oinfo, rs->resv, true); @@ -416,6 +419,8 @@ xreap_agextent_iter( return error; rs->deferred++; + if (rs->deferred % 2 == 0) + xfs_defer_add_barrier(sc->tp); return 0; } From 5a08d0065a915ccf325563d7ca57fa8b4897881c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Dec 2023 17:32:50 +0000 Subject: [PATCH 2936/7721] ipv6: add debug checks in fib6_info_release() Some elusive syzbot reports are hinting to fib6_info_release(), with a potential dangling f6i->gc_link anchor. Add debug checks so that syzbot can catch the issue earlier eventually. BUG: KASAN: slab-use-after-free in __hlist_del include/linux/list.h:990 [inline] BUG: KASAN: slab-use-after-free in hlist_del_init include/linux/list.h:1016 [inline] BUG: KASAN: slab-use-after-free in fib6_clean_expires_locked include/net/ip6_fib.h:533 [inline] BUG: KASAN: slab-use-after-free in fib6_purge_rt+0x986/0x9c0 net/ipv6/ip6_fib.c:1064 Write of size 8 at addr ffff88802805a840 by task syz-executor.1/10057 CPU: 1 PID: 10057 Comm: syz-executor.1 Not tainted 6.7.0-rc2-syzkaller-00029-g9b6de136b5f0 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/10/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xd9/0x1b0 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:364 [inline] print_report+0xc4/0x620 mm/kasan/report.c:475 kasan_report+0xda/0x110 mm/kasan/report.c:588 __hlist_del include/linux/list.h:990 [inline] hlist_del_init include/linux/list.h:1016 [inline] fib6_clean_expires_locked include/net/ip6_fib.h:533 [inline] fib6_purge_rt+0x986/0x9c0 net/ipv6/ip6_fib.c:1064 fib6_del_route net/ipv6/ip6_fib.c:1993 [inline] fib6_del+0xa7a/0x1750 net/ipv6/ip6_fib.c:2038 __ip6_del_rt net/ipv6/route.c:3866 [inline] ip6_del_rt+0xf7/0x200 net/ipv6/route.c:3881 ndisc_router_discovery+0x295b/0x3560 net/ipv6/ndisc.c:1372 ndisc_rcv+0x3de/0x5f0 net/ipv6/ndisc.c:1856 icmpv6_rcv+0x1470/0x19c0 net/ipv6/icmp.c:979 ip6_protocol_deliver_rcu+0x170/0x13e0 net/ipv6/ip6_input.c:438 ip6_input_finish+0x14f/0x2f0 net/ipv6/ip6_input.c:483 NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ip6_input+0xa1/0xc0 net/ipv6/ip6_input.c:492 ip6_mc_input+0x48b/0xf40 net/ipv6/ip6_input.c:586 dst_input include/net/dst.h:461 [inline] ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline] NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ipv6_rcv+0x24e/0x380 net/ipv6/ip6_input.c:310 __netif_receive_skb_one_core+0x115/0x180 net/core/dev.c:5529 __netif_receive_skb+0x1f/0x1b0 net/core/dev.c:5643 netif_receive_skb_internal net/core/dev.c:5729 [inline] netif_receive_skb+0x133/0x700 net/core/dev.c:5788 tun_rx_batched+0x429/0x780 drivers/net/tun.c:1579 tun_get_user+0x29e3/0x3bc0 drivers/net/tun.c:2002 tun_chr_write_iter+0xe8/0x210 drivers/net/tun.c:2048 call_write_iter include/linux/fs.h:2020 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x64f/0xdf0 fs/read_write.c:584 ksys_write+0x12f/0x250 fs/read_write.c:637 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b RIP: 0033:0x7f38e387b82f Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 b9 80 02 00 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 0c 81 02 00 48 RSP: 002b:00007f38e45c9090 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f38e399bf80 RCX: 00007f38e387b82f RDX: 00000000000003b6 RSI: 0000000020000680 RDI: 00000000000000c8 RBP: 00007f38e38c847a R08: 0000000000000000 R09: 0000000000000000 R10: 00000000000003b6 R11: 0000000000000293 R12: 0000000000000000 R13: 000000000000000b R14: 00007f38e399bf80 R15: 00007f38e3abfa48 Allocated by task 10044: kasan_save_stack+0x33/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 ____kasan_kmalloc mm/kasan/common.c:374 [inline] __kasan_kmalloc+0xa2/0xb0 mm/kasan/common.c:383 kasan_kmalloc include/linux/kasan.h:198 [inline] __do_kmalloc_node mm/slab_common.c:1007 [inline] __kmalloc+0x59/0x90 mm/slab_common.c:1020 kmalloc include/linux/slab.h:604 [inline] kzalloc include/linux/slab.h:721 [inline] fib6_info_alloc+0x40/0x160 net/ipv6/ip6_fib.c:155 ip6_route_info_create+0x337/0x1e70 net/ipv6/route.c:3749 ip6_route_add+0x26/0x150 net/ipv6/route.c:3843 rt6_add_route_info+0x2e7/0x4b0 net/ipv6/route.c:4316 rt6_route_rcv+0x76c/0xbf0 net/ipv6/route.c:985 ndisc_router_discovery+0x138b/0x3560 net/ipv6/ndisc.c:1529 ndisc_rcv+0x3de/0x5f0 net/ipv6/ndisc.c:1856 icmpv6_rcv+0x1470/0x19c0 net/ipv6/icmp.c:979 ip6_protocol_deliver_rcu+0x170/0x13e0 net/ipv6/ip6_input.c:438 ip6_input_finish+0x14f/0x2f0 net/ipv6/ip6_input.c:483 NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ip6_input+0xa1/0xc0 net/ipv6/ip6_input.c:492 ip6_mc_input+0x48b/0xf40 net/ipv6/ip6_input.c:586 dst_input include/net/dst.h:461 [inline] ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline] NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ipv6_rcv+0x24e/0x380 net/ipv6/ip6_input.c:310 __netif_receive_skb_one_core+0x115/0x180 net/core/dev.c:5529 __netif_receive_skb+0x1f/0x1b0 net/core/dev.c:5643 netif_receive_skb_internal net/core/dev.c:5729 [inline] netif_receive_skb+0x133/0x700 net/core/dev.c:5788 tun_rx_batched+0x429/0x780 drivers/net/tun.c:1579 tun_get_user+0x29e3/0x3bc0 drivers/net/tun.c:2002 tun_chr_write_iter+0xe8/0x210 drivers/net/tun.c:2048 call_write_iter include/linux/fs.h:2020 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x64f/0xdf0 fs/read_write.c:584 ksys_write+0x12f/0x250 fs/read_write.c:637 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b Freed by task 5123: kasan_save_stack+0x33/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:522 ____kasan_slab_free mm/kasan/common.c:236 [inline] ____kasan_slab_free+0x15b/0x1b0 mm/kasan/common.c:200 kasan_slab_free include/linux/kasan.h:164 [inline] slab_free_hook mm/slub.c:1800 [inline] slab_free_freelist_hook+0x114/0x1e0 mm/slub.c:1826 slab_free mm/slub.c:3809 [inline] __kmem_cache_free+0xc0/0x180 mm/slub.c:3822 rcu_do_batch kernel/rcu/tree.c:2158 [inline] rcu_core+0x819/0x1680 kernel/rcu/tree.c:2431 __do_softirq+0x21a/0x8de kernel/softirq.c:553 Last potentially related work creation: kasan_save_stack+0x33/0x50 mm/kasan/common.c:45 __kasan_record_aux_stack+0xbc/0xd0 mm/kasan/generic.c:492 __call_rcu_common.constprop.0+0x9a/0x7a0 kernel/rcu/tree.c:2681 fib6_info_release include/net/ip6_fib.h:332 [inline] fib6_info_release include/net/ip6_fib.h:329 [inline] rt6_route_rcv+0xa4e/0xbf0 net/ipv6/route.c:997 ndisc_router_discovery+0x138b/0x3560 net/ipv6/ndisc.c:1529 ndisc_rcv+0x3de/0x5f0 net/ipv6/ndisc.c:1856 icmpv6_rcv+0x1470/0x19c0 net/ipv6/icmp.c:979 ip6_protocol_deliver_rcu+0x170/0x13e0 net/ipv6/ip6_input.c:438 ip6_input_finish+0x14f/0x2f0 net/ipv6/ip6_input.c:483 NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ip6_input+0xa1/0xc0 net/ipv6/ip6_input.c:492 ip6_mc_input+0x48b/0xf40 net/ipv6/ip6_input.c:586 dst_input include/net/dst.h:461 [inline] ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline] NF_HOOK include/linux/netfilter.h:314 [inline] NF_HOOK include/linux/netfilter.h:308 [inline] ipv6_rcv+0x24e/0x380 net/ipv6/ip6_input.c:310 __netif_receive_skb_one_core+0x115/0x180 net/core/dev.c:5529 __netif_receive_skb+0x1f/0x1b0 net/core/dev.c:5643 netif_receive_skb_internal net/core/dev.c:5729 [inline] netif_receive_skb+0x133/0x700 net/core/dev.c:5788 tun_rx_batched+0x429/0x780 drivers/net/tun.c:1579 tun_get_user+0x29e3/0x3bc0 drivers/net/tun.c:2002 tun_chr_write_iter+0xe8/0x210 drivers/net/tun.c:2048 call_write_iter include/linux/fs.h:2020 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x64f/0xdf0 fs/read_write.c:584 ksys_write+0x12f/0x250 fs/read_write.c:637 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b Second to last potentially related work creation: kasan_save_stack+0x33/0x50 mm/kasan/common.c:45 __kasan_record_aux_stack+0xbc/0xd0 mm/kasan/generic.c:492 insert_work+0x38/0x230 kernel/workqueue.c:1647 __queue_work+0xcdc/0x11f0 kernel/workqueue.c:1803 call_timer_fn+0x193/0x590 kernel/time/timer.c:1700 expire_timers kernel/time/timer.c:1746 [inline] __run_timers+0x585/0xb20 kernel/time/timer.c:2022 run_timer_softirq+0x58/0xd0 kernel/time/timer.c:2035 __do_softirq+0x21a/0x8de kernel/softirq.c:553 The buggy address belongs to the object at ffff88802805a800 which belongs to the cache kmalloc-512 of size 512 The buggy address is located 64 bytes inside of freed 512-byte region [ffff88802805a800, ffff88802805aa00) The buggy address belongs to the physical page: page:ffffea0000a01600 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x28058 head:ffffea0000a01600 order:2 entire_mapcount:0 nr_pages_mapped:0 pincount:0 flags: 0xfff00000000840(slab|head|node=0|zone=1|lastcpupid=0x7ff) page_type: 0xffffffff() raw: 00fff00000000840 ffff888013041c80 ffffea0001e02600 dead000000000002 raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected page_owner tracks the page as allocated page last allocated via order 2, migratetype Unmovable, gfp_mask 0x1d20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC|__GFP_HARDWALL), pid 18706, tgid 18699 (syz-executor.2), ts 999991973280, free_ts 996884464281 set_page_owner include/linux/page_owner.h:31 [inline] post_alloc_hook+0x2d0/0x350 mm/page_alloc.c:1537 prep_new_page mm/page_alloc.c:1544 [inline] get_page_from_freelist+0xa25/0x36d0 mm/page_alloc.c:3312 __alloc_pages+0x22e/0x2420 mm/page_alloc.c:4568 alloc_pages_mpol+0x258/0x5f0 mm/mempolicy.c:2133 alloc_slab_page mm/slub.c:1870 [inline] allocate_slab mm/slub.c:2017 [inline] new_slab+0x283/0x3c0 mm/slub.c:2070 ___slab_alloc+0x979/0x1500 mm/slub.c:3223 __slab_alloc.constprop.0+0x56/0xa0 mm/slub.c:3322 __slab_alloc_node mm/slub.c:3375 [inline] slab_alloc_node mm/slub.c:3468 [inline] __kmem_cache_alloc_node+0x131/0x310 mm/slub.c:3517 __do_kmalloc_node mm/slab_common.c:1006 [inline] __kmalloc+0x49/0x90 mm/slab_common.c:1020 kmalloc include/linux/slab.h:604 [inline] kzalloc include/linux/slab.h:721 [inline] copy_splice_read+0x1ac/0x8f0 fs/splice.c:338 vfs_splice_read fs/splice.c:992 [inline] vfs_splice_read+0x2ea/0x3b0 fs/splice.c:962 splice_direct_to_actor+0x2a5/0xa30 fs/splice.c:1069 do_splice_direct+0x1af/0x280 fs/splice.c:1194 do_sendfile+0xb3e/0x1310 fs/read_write.c:1254 __do_sys_sendfile64 fs/read_write.c:1322 [inline] __se_sys_sendfile64 fs/read_write.c:1308 [inline] __x64_sys_sendfile64+0x1d6/0x220 fs/read_write.c:1308 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 page last free stack trace: reset_page_owner include/linux/page_owner.h:24 [inline] free_pages_prepare mm/page_alloc.c:1137 [inline] free_unref_page_prepare+0x4fa/0xaa0 mm/page_alloc.c:2347 free_unref_page_list+0xe6/0xb40 mm/page_alloc.c:2533 release_pages+0x32a/0x14f0 mm/swap.c:1042 tlb_batch_pages_flush+0x9a/0x190 mm/mmu_gather.c:98 tlb_flush_mmu_free mm/mmu_gather.c:293 [inline] tlb_flush_mmu mm/mmu_gather.c:300 [inline] tlb_finish_mmu+0x14b/0x6f0 mm/mmu_gather.c:392 exit_mmap+0x38b/0xa70 mm/mmap.c:3321 __mmput+0x12a/0x4d0 kernel/fork.c:1349 mmput+0x62/0x70 kernel/fork.c:1371 exit_mm kernel/exit.c:567 [inline] do_exit+0x9ad/0x2ae0 kernel/exit.c:858 do_group_exit+0xd4/0x2a0 kernel/exit.c:1021 get_signal+0x23be/0x2790 kernel/signal.c:2904 arch_do_signal_or_restart+0x90/0x7f0 arch/x86/kernel/signal.c:309 exit_to_user_mode_loop kernel/entry/common.c:168 [inline] exit_to_user_mode_prepare+0x121/0x240 kernel/entry/common.c:204 irqentry_exit_to_user_mode+0xa/0x40 kernel/entry/common.c:309 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:645 Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231205173250.2982846-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/ip6_fib.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 1ba9f4ddf2f6..e1e7a894863a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -328,8 +328,11 @@ static inline bool fib6_info_hold_safe(struct fib6_info *f6i) static inline void fib6_info_release(struct fib6_info *f6i) { - if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) + if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) { + DEBUG_NET_WARN_ON_ONCE(fib6_has_expires(f6i)); + DEBUG_NET_WARN_ON_ONCE(!hlist_unhashed(&f6i->gc_link)); call_rcu(&f6i->rcu, fib6_info_destroy_rcu); + } } enum fib6_walk_state { From b8dbbbc535a95acd66035cf75872cd7524c0b12f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Dec 2023 17:00:11 +0100 Subject: [PATCH 2937/7721] net: rtnetlink: remove local list in __linkwatch_run_queue() Due to linkwatch_forget_dev() (and perhaps others?) checking for list_empty(&dev->link_watch_list), we must have all manipulations of even the local on-stack list 'wrk' here under spinlock, since even that list can be reached otherwise via dev->link_watch_list. This is already the case, but makes this a bit counter-intuitive, often local lists are used to _not_ have to use locking for their local use. Remove the local list as it doesn't seem to serve any purpose. While at it, move a variable declaration into the loop using it. Reviewed-by: Jiri Pirko Signed-off-by: Johannes Berg Link: https://lore.kernel.org/r/20231205170011.56576dcc1727.I698b72219d9f6ce789bd209b8f6dffd0ca32a8f2@changeid Signed-off-by: Jakub Kicinski --- net/core/link_watch.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/net/core/link_watch.c b/net/core/link_watch.c index a19f21403339..7be5b3ab32bd 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -192,8 +192,6 @@ static void __linkwatch_run_queue(int urgent_only) #define MAX_DO_DEV_PER_LOOP 100 int do_dev = MAX_DO_DEV_PER_LOOP; - struct net_device *dev; - LIST_HEAD(wrk); /* Give urgent case more budget */ if (urgent_only) @@ -215,11 +213,11 @@ static void __linkwatch_run_queue(int urgent_only) clear_bit(LW_URGENT, &linkwatch_flags); spin_lock_irq(&lweventlist_lock); - list_splice_init(&lweventlist, &wrk); + while (!list_empty(&lweventlist) && do_dev > 0) { + struct net_device *dev; - while (!list_empty(&wrk) && do_dev > 0) { - - dev = list_first_entry(&wrk, struct net_device, link_watch_list); + dev = list_first_entry(&lweventlist, struct net_device, + link_watch_list); list_del_init(&dev->link_watch_list); if (!netif_device_present(dev) || @@ -237,9 +235,6 @@ static void __linkwatch_run_queue(int urgent_only) spin_lock_irq(&lweventlist_lock); } - /* Add the remaining work back to lweventlist */ - list_splice_init(&wrk, &lweventlist); - if (!list_empty(&lweventlist)) linkwatch_schedule_work(0); spin_unlock_irq(&lweventlist_lock); From 734add1a278f05db2d5a0b9d280a8bce94ce5eeb Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 1 Dec 2023 11:45:30 +0800 Subject: [PATCH 2938/7721] soc: hisilicon: kunpeng_hccs: Fix some incorrect format strings Fix some incorrect format strings. Signed-off-by: Huisong Li Reviewed-by: Jonathan Cameron Signed-off-by: Wei Xu --- drivers/soc/hisilicon/kunpeng_hccs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index e31791659560..dad6235dbf1a 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -155,7 +155,7 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr, pcc_chan->shmem_size); if (!cl_info->pcc_comm_addr) { - dev_err(dev, "Failed to ioremap PCC communication region for channel-%d.\n", + dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n", hdev->chan_id); rc = -ENOMEM; goto err_mbx_channel_free; @@ -1097,7 +1097,7 @@ static int hccs_create_hccs_dir(struct hccs_dev *hdev, int ret; ret = kobject_init_and_add(&port->kobj, &hccs_port_type, - &die->kobj, "hccs%d", port->port_id); + &die->kobj, "hccs%u", port->port_id); if (ret) { kobject_put(&port->kobj); return ret; @@ -1115,7 +1115,7 @@ static int hccs_create_die_dir(struct hccs_dev *hdev, u16 i; ret = kobject_init_and_add(&die->kobj, &hccs_die_type, - &chip->kobj, "die%d", die->die_id); + &chip->kobj, "die%u", die->die_id); if (ret) { kobject_put(&die->kobj); return ret; @@ -1125,7 +1125,7 @@ static int hccs_create_die_dir(struct hccs_dev *hdev, port = &die->ports[i]; ret = hccs_create_hccs_dir(hdev, die, port); if (ret) { - dev_err(hdev->dev, "create hccs%d dir failed.\n", + dev_err(hdev->dev, "create hccs%u dir failed.\n", port->port_id); goto err; } @@ -1147,7 +1147,7 @@ static int hccs_create_chip_dir(struct hccs_dev *hdev, u16 id; ret = kobject_init_and_add(&chip->kobj, &hccs_chip_type, - &hdev->dev->kobj, "chip%d", chip->chip_id); + &hdev->dev->kobj, "chip%u", chip->chip_id); if (ret) { kobject_put(&chip->kobj); return ret; @@ -1178,7 +1178,7 @@ static int hccs_create_topo_dirs(struct hccs_dev *hdev) chip = &hdev->chips[id]; ret = hccs_create_chip_dir(hdev, chip); if (ret) { - dev_err(hdev->dev, "init chip%d dir failed!\n", id); + dev_err(hdev->dev, "init chip%u dir failed!\n", id); goto err; } } From e1e720f3f2c50a6f3440b3684decd7b7c046e111 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 1 Dec 2023 11:45:31 +0800 Subject: [PATCH 2939/7721] soc: hisilicon: kunpeng_hccs: Add failure log for no _CRS method Driver gets the PCC channel id by using the PCC GAS in _CRS. But, currently, if the firmware has no _CRS method on platform, there is not any failure log. So this patch adds the log for this. Signed-off-by: Huisong Li Reviewed-by: Jonathan Cameron Signed-off-by: Wei Xu --- drivers/soc/hisilicon/kunpeng_hccs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index dad6235dbf1a..fd3ca0eb8175 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -85,8 +85,10 @@ static int hccs_get_pcc_chan_id(struct hccs_dev *hdev) struct hccs_register_ctx ctx = {0}; acpi_status status; - if (!acpi_has_method(handle, METHOD_NAME__CRS)) + if (!acpi_has_method(handle, METHOD_NAME__CRS)) { + dev_err(hdev->dev, "No _CRS method.\n"); return -ENODEV; + } ctx.dev = hdev->dev; status = acpi_walk_resources(handle, METHOD_NAME__CRS, From a079f3244563a4c4dc32b0a9bfa0e3e519f3c9ed Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 1 Dec 2023 11:45:32 +0800 Subject: [PATCH 2940/7721] soc: hisilicon: kunpeng_hccs: Remove an unused blank line Remove an unused blank line. Signed-off-by: Huisong Li Reviewed-by: Jonathan Cameron Signed-off-by: Wei Xu --- drivers/soc/hisilicon/kunpeng_hccs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index fd3ca0eb8175..15125f1e0f3e 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -529,7 +529,6 @@ static int hccs_get_all_port_info_on_die(struct hccs_dev *hdev, static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) { - struct device *dev = hdev->dev; struct hccs_chip_info *chip; struct hccs_die_info *die; From a07d8fc358af5f297b41b2182a5fce710e3c9bd7 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 1 Dec 2023 11:45:33 +0800 Subject: [PATCH 2941/7721] doc: kunpeng_hccs: Fix incorrect email domain name The email domain name in Contact is wrong. So this patch has to modify it. Signed-off-by: Huisong Li Signed-off-by: Wei Xu --- .../ABI/testing/sysfs-devices-platform-kunpeng_hccs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs index fdb4e36310fb..1666340820f7 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs +++ b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs @@ -3,7 +3,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/linked_full_lane What: /sys/devices/platform/HISI04Bx:00/chipX/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx:00/chipX/ directory contains read-only attributes exposing some summarization @@ -26,7 +26,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/linked_full_lane What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx:00/chipX/dieY/ directory contains read-only attributes exposing some summarization @@ -54,7 +54,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/lane_mask What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx/chipX/dieX/hccsN/ directory contains read-only attributes exposing information about From be2f78a8a638e71bbbc2109bc052524143e8f42a Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 1 Dec 2023 11:45:34 +0800 Subject: [PATCH 2942/7721] soc: hisilicon: kunpeng_hccs: Support the platform with PCC type3 and interrupt ack Support the platform with PCC type3 and interrupt ack. And a version specific structure is introduced to handle the difference between the device in the code. Signed-off-by: Huisong Li Reviewed-by: Jonathan Cameron Signed-off-by: Wei Xu --- drivers/soc/hisilicon/kunpeng_hccs.c | 135 ++++++++++++++++++++++----- drivers/soc/hisilicon/kunpeng_hccs.h | 15 +++ 2 files changed, 125 insertions(+), 25 deletions(-) diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index 15125f1e0f3e..9ff70b38e5e9 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -110,6 +110,14 @@ static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret) *(u8 *)msg, ret); } +static void hccs_pcc_rx_callback(struct mbox_client *cl, void *mssg) +{ + struct hccs_mbox_client_info *cl_info = + container_of(cl, struct hccs_mbox_client_info, client); + + complete(&cl_info->done); +} + static void hccs_unregister_pcc_channel(struct hccs_dev *hdev) { struct hccs_mbox_client_info *cl_info = &hdev->cl_info; @@ -131,6 +139,9 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) cl->tx_block = false; cl->knows_txdone = true; cl->tx_done = hccs_chan_tx_done; + cl->rx_callback = hdev->verspec_data->rx_callback; + init_completion(&cl_info->done); + pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id); if (IS_ERR(pcc_chan)) { dev_err(dev, "PPC channel request failed.\n"); @@ -147,10 +158,16 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) */ cl_info->deadline_us = HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency; - if (cl_info->mbox_chan->mbox->txdone_irq) { + if (!hdev->verspec_data->has_txdone_irq && + cl_info->mbox_chan->mbox->txdone_irq) { dev_err(dev, "PCC IRQ in PCCT is enabled.\n"); rc = -EINVAL; goto err_mbx_channel_free; + } else if (hdev->verspec_data->has_txdone_irq && + !cl_info->mbox_chan->mbox->txdone_irq) { + dev_err(dev, "PCC IRQ in PCCT isn't supported.\n"); + rc = -EINVAL; + goto err_mbx_channel_free; } if (pcc_chan->shmem_base_addr) { @@ -172,7 +189,7 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) return rc; } -static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) +static int hccs_wait_cmd_complete_by_poll(struct hccs_dev *hdev) { struct hccs_mbox_client_info *cl_info = &hdev->cl_info; struct acpi_pcct_shared_memory __iomem *comm_base = @@ -194,30 +211,74 @@ static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) return ret; } +static int hccs_wait_cmd_complete_by_irq(struct hccs_dev *hdev) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + + if (!wait_for_completion_timeout(&cl_info->done, + usecs_to_jiffies(cl_info->deadline_us))) { + dev_err(hdev->dev, "PCC command executed timeout!\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static inline void hccs_fill_pcc_shared_mem_region(struct hccs_dev *hdev, + u8 cmd, + struct hccs_desc *desc, + void __iomem *comm_space, + u16 space_size) +{ + struct acpi_pcct_shared_memory tmp = { + .signature = PCC_SIGNATURE | hdev->chan_id, + .command = cmd, + .status = 0, + }; + + memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, + sizeof(struct acpi_pcct_shared_memory)); + + /* Copy the message to the PCC comm space */ + memcpy_toio(comm_space, (void *)desc, space_size); +} + +static inline void hccs_fill_ext_pcc_shared_mem_region(struct hccs_dev *hdev, + u8 cmd, + struct hccs_desc *desc, + void __iomem *comm_space, + u16 space_size) +{ + struct acpi_pcct_ext_pcc_shared_memory tmp = { + .signature = PCC_SIGNATURE | hdev->chan_id, + .flags = PCC_CMD_COMPLETION_NOTIFY, + .length = HCCS_PCC_SHARE_MEM_BYTES, + .command = cmd, + }; + + memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, + sizeof(struct acpi_pcct_ext_pcc_shared_memory)); + + /* Copy the message to the PCC comm space */ + memcpy_toio(comm_space, (void *)desc, space_size); +} + static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, struct hccs_desc *desc) { + const struct hccs_verspecific_data *verspec_data = hdev->verspec_data; struct hccs_mbox_client_info *cl_info = &hdev->cl_info; - void __iomem *comm_space = cl_info->pcc_comm_addr + - sizeof(struct acpi_pcct_shared_memory); struct hccs_fw_inner_head *fw_inner_head; - struct acpi_pcct_shared_memory tmp = {0}; - u16 comm_space_size; + void __iomem *comm_space; + u16 space_size; int ret; - /* Write signature for this subspace */ - tmp.signature = PCC_SIGNATURE | hdev->chan_id; - /* Write to the shared command region */ - tmp.command = cmd; - /* Clear cmd complete bit */ - tmp.status = 0; - memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp, - sizeof(struct acpi_pcct_shared_memory)); - - /* Copy the message to the PCC comm space */ - comm_space_size = HCCS_PCC_SHARE_MEM_BYTES - - sizeof(struct acpi_pcct_shared_memory); - memcpy_toio(comm_space, (void *)desc, comm_space_size); + comm_space = cl_info->pcc_comm_addr + verspec_data->shared_mem_size; + space_size = HCCS_PCC_SHARE_MEM_BYTES - verspec_data->shared_mem_size; + verspec_data->fill_pcc_shared_mem(hdev, cmd, desc, + comm_space, space_size); + if (verspec_data->has_txdone_irq) + reinit_completion(&cl_info->done); /* Ring doorbell */ ret = mbox_send_message(cl_info->mbox_chan, &cmd); @@ -227,13 +288,12 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, goto end; } - /* Wait for completion */ - ret = hccs_check_chan_cmd_complete(hdev); + ret = verspec_data->wait_cmd_complete(hdev); if (ret) goto end; /* Copy response data */ - memcpy_fromio((void *)desc, comm_space, comm_space_size); + memcpy_fromio((void *)desc, comm_space, space_size); fw_inner_head = &desc->rsp.fw_inner_head; if (fw_inner_head->retStatus) { dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n", @@ -242,7 +302,10 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, } end: - mbox_client_txdone(cl_info->mbox_chan, ret); + if (verspec_data->has_txdone_irq) + mbox_chan_txdone(cl_info->mbox_chan, ret); + else + mbox_client_txdone(cl_info->mbox_chan, ret); return ret; } @@ -1213,6 +1276,11 @@ static int hccs_probe(struct platform_device *pdev) hdev->dev = &pdev->dev; platform_set_drvdata(pdev, hdev); + /* + * Here would never be failure as the driver and device has been matched. + */ + hdev->verspec_data = acpi_device_get_match_data(hdev->dev); + mutex_init(&hdev->lock); rc = hccs_get_pcc_chan_id(hdev); if (rc) @@ -1249,9 +1317,26 @@ static void hccs_remove(struct platform_device *pdev) hccs_unregister_pcc_channel(hdev); } +static const struct hccs_verspecific_data hisi04b1_verspec_data = { + .rx_callback = NULL, + .wait_cmd_complete = hccs_wait_cmd_complete_by_poll, + .fill_pcc_shared_mem = hccs_fill_pcc_shared_mem_region, + .shared_mem_size = sizeof(struct acpi_pcct_shared_memory), + .has_txdone_irq = false, +}; + +static const struct hccs_verspecific_data hisi04b2_verspec_data = { + .rx_callback = hccs_pcc_rx_callback, + .wait_cmd_complete = hccs_wait_cmd_complete_by_irq, + .fill_pcc_shared_mem = hccs_fill_ext_pcc_shared_mem_region, + .shared_mem_size = sizeof(struct acpi_pcct_ext_pcc_shared_memory), + .has_txdone_irq = true, +}; + static const struct acpi_device_id hccs_acpi_match[] = { - { "HISI04B1"}, - { ""}, + { "HISI04B1", (unsigned long)&hisi04b1_verspec_data}, + { "HISI04B2", (unsigned long)&hisi04b2_verspec_data}, + { } }; MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); diff --git a/drivers/soc/hisilicon/kunpeng_hccs.h b/drivers/soc/hisilicon/kunpeng_hccs.h index 6012d2776028..c3adbc01b471 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.h +++ b/drivers/soc/hisilicon/kunpeng_hccs.h @@ -51,11 +51,26 @@ struct hccs_mbox_client_info { struct pcc_mbox_chan *pcc_chan; u64 deadline_us; void __iomem *pcc_comm_addr; + struct completion done; +}; + +struct hccs_desc; + +struct hccs_verspecific_data { + void (*rx_callback)(struct mbox_client *cl, void *mssg); + int (*wait_cmd_complete)(struct hccs_dev *hdev); + void (*fill_pcc_shared_mem)(struct hccs_dev *hdev, + u8 cmd, struct hccs_desc *desc, + void __iomem *comm_space, + u16 space_size); + u16 shared_mem_size; + bool has_txdone_irq; }; struct hccs_dev { struct device *dev; struct acpi_device *acpi_dev; + const struct hccs_verspecific_data *verspec_data; u64 caps; u8 chip_num; struct hccs_chip_info *chips; From 1d3062fad9c7313fff9970a88e0538a24480ffb8 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 3 Nov 2023 15:14:03 +0200 Subject: [PATCH 2943/7721] drm/drm_file: fix use of uninitialized variable smatch reports: drivers/gpu/drm/drm_file.c:967 drm_show_memory_stats() error: uninitialized symbol 'supported_status'. 'supported_status' is only set in one code path. I'm not familiar with the code to say if that path will always be ran in real life, but whether that is the case or not, I think it is good to initialize 'supported_status' to 0 to silence the warning (and possibly fix a bug). Reviewed-by: Laurent Pinchart Acked-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231103-uninit-fixes-v2-1-c22b2444f5f5@ideasonboard.com --- drivers/gpu/drm/drm_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 987c1a5d1773..8c87287c3e16 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -898,7 +898,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) { struct drm_gem_object *obj; struct drm_memory_stats status = {}; - enum drm_gem_object_status supported_status; + enum drm_gem_object_status supported_status = 0; int id; spin_lock(&file->table_lock); From f9af8f0c1dc567a5a6a6318ff324c45d80d4a60f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 3 Nov 2023 15:14:04 +0200 Subject: [PATCH 2944/7721] drm/framebuffer: Fix use of uninitialized variable smatch reports: drivers/gpu/drm/drm_framebuffer.c:654 drm_mode_getfb2_ioctl() error: uninitialized symbol 'ret'. 'ret' is possibly not set when there are no errors, causing the error above. I can't say if that ever happens in real-life, but in any case I think it is good to initialize 'ret' to 0. Reviewed-by: Laurent Pinchart Acked-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231103-uninit-fixes-v2-2-c22b2444f5f5@ideasonboard.com --- drivers/gpu/drm/drm_framebuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 09e289fca5c3..3cc0ffc28e86 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -583,7 +583,7 @@ int drm_mode_getfb2_ioctl(struct drm_device *dev, struct drm_mode_fb_cmd2 *r = data; struct drm_framebuffer *fb; unsigned int i; - int ret; + int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; From 155d6fb61270dd297f128731cd155080deee8f3a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 3 Nov 2023 15:14:05 +0200 Subject: [PATCH 2945/7721] drm/bridge: cdns-mhdp8546: Fix use of uninitialized variable 'ret' could be uninitialized at the end of the function, although it's not clear if that can happen in practice. Fixes: 6a3608eae6d3 ("drm: bridge: cdns-mhdp8546: Enable HDCP") Acked-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231103-uninit-fixes-v2-3-c22b2444f5f5@ideasonboard.com --- drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c index 946212a95598..5e3b8edcf794 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -403,7 +403,8 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) { - int ret, tries = 3; + int ret = -EINVAL; + int tries = 3; u32 i; for (i = 0; i < tries; i++) { From 32bd29b619638256c5b75fb021d6d9f12fc4a984 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 3 Nov 2023 15:14:06 +0200 Subject: [PATCH 2946/7721] drm/bridge: tc358767: Fix return value on error case If the hpd_pin is invalid, the driver returns 'ret'. But 'ret' contains 0, instead of an error value. Return -EINVAL instead. Fixes: f25ee5017e4f ("drm/bridge: tc358767: add IRQ and HPD support") Acked-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231103-uninit-fixes-v2-4-c22b2444f5f5@ideasonboard.com --- drivers/gpu/drm/bridge/tc358767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index ef2e373606ba..615cc8f950d7 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2273,7 +2273,7 @@ static int tc_probe(struct i2c_client *client) } else { if (tc->hpd_pin < 0 || tc->hpd_pin > 1) { dev_err(dev, "failed to parse HPD number\n"); - return ret; + return -EINVAL; } } From 90d50b8d85834e73536fdccd5aa913b30494fef0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 21 Sep 2023 13:50:32 +0300 Subject: [PATCH 2947/7721] drm/mipi-dsi: Fix detach call without attach It's been reported that DSI host driver's detach can be called without the attach ever happening: https://lore.kernel.org/all/20230412073954.20601-1-tony@atomide.com/ After reading the code, I think this is what happens: We have a DSI host defined in the device tree and a DSI peripheral under that host (i.e. an i2c device using the DSI as data bus doesn't exhibit this behavior). The host driver calls mipi_dsi_host_register(), which causes (via a few functions) mipi_dsi_device_add() to be called for the DSI peripheral. So now we have a DSI device under the host, but attach hasn't been called. Normally the probing of the devices continues, and eventually the DSI peripheral's driver will call mipi_dsi_attach(), attaching the peripheral. However, if the host driver's probe encounters an error after calling mipi_dsi_host_register(), and before the peripheral has called mipi_dsi_attach(), the host driver will do cleanups and return an error from its probe function. The cleanups include calling mipi_dsi_host_unregister(). mipi_dsi_host_unregister() will call two functions for all its DSI peripheral devices: mipi_dsi_detach() and mipi_dsi_device_unregister(). The latter makes sense, as the device exists, but the former may be wrong as attach has not necessarily been done. To fix this, track the attached state of the peripheral, and only detach from mipi_dsi_host_unregister() if the peripheral was attached. Note that I have only tested this with a board with an i2c DSI peripheral, not with a "pure" DSI peripheral. However, slightly related, the unregister machinery still seems broken. E.g. if the DSI host driver is unbound, it'll detach and unregister the DSI peripherals. After that, when the DSI peripheral driver unbound it'll call detach either directly or using the devm variant, leading to a crash. And probably the driver will crash if it happens, for some reason, to try to send a message via the DSI bus. But that's another topic. Tested-by: H. Nikolaus Schaller Acked-by: Maxime Ripard Reviewed-by: Sebastian Reichel Tested-by: Tony Lindgren Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20230921-dsi-detach-fix-v1-1-d0de2d1621d9@ideasonboard.com --- drivers/gpu/drm/drm_mipi_dsi.c | 17 +++++++++++++++-- include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 14201f73aab1..843a6dbda93a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -347,7 +347,8 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); - mipi_dsi_detach(dsi); + if (dsi->attached) + mipi_dsi_detach(dsi); mipi_dsi_device_unregister(dsi); return 0; @@ -370,11 +371,18 @@ EXPORT_SYMBOL(mipi_dsi_host_unregister); int mipi_dsi_attach(struct mipi_dsi_device *dsi) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; + int ret; if (!ops || !ops->attach) return -ENOSYS; - return ops->attach(dsi->host, dsi); + ret = ops->attach(dsi->host, dsi); + if (ret) + return ret; + + dsi->attached = true; + + return 0; } EXPORT_SYMBOL(mipi_dsi_attach); @@ -386,9 +394,14 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; + if (WARN_ON(!dsi->attached)) + return -EINVAL; + if (!ops || !ops->detach) return -ENOSYS; + dsi->attached = false; + return ops->detach(dsi->host, dsi); } EXPORT_SYMBOL(mipi_dsi_detach); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index c9df0407980c..c0aec0d4d664 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -168,6 +168,7 @@ struct mipi_dsi_device_info { * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @attached: the DSI device has been successfully attached * @name: DSI peripheral chip type * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode @@ -184,6 +185,7 @@ struct mipi_dsi_device_info { struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev; + bool attached; char name[DSI_DEV_NAME_SIZE]; unsigned int channel; From a60577cef7de982166baa132a8423f413b617b63 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 5 Oct 2023 12:49:04 +0200 Subject: [PATCH 2948/7721] media: dt-bindings: mediatek: Add phandle to mediatek,scp on MDP3 RDMA The MDP3 RDMA needs to communicate with the SCP remote processor: allow specifying a phandle to a SCP core. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Conor Dooley Reviewed-by: Alexandre Mergnat Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/mediatek,mdp3-rdma.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml index 7032c7e15039..59dcea797b71 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml @@ -45,6 +45,14 @@ properties: include/dt-bindings/gce/-gce.h of each chips. $ref: /schemas/types.yaml#/definitions/uint32-array + mediatek,scp: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the System Control Processor (SCP) used for initializing + and stopping the MDP3, for sending frame data locations to the MDP3's + VPU and to install Inter-Processor Interrupt handlers to control + processing states. + power-domains: maxItems: 1 From 52e1fc9aa8282d783f6cfedd79b79db98259900c Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 5 Oct 2023 12:49:05 +0200 Subject: [PATCH 2949/7721] media: platform: mtk-mdp3: Use devicetree phandle to retrieve SCP Instead of walking the entire parent node for something that has the right compatible, use the scp_get() function provided by the MediaTek SCP remoteproc driver to retrieve a handle to mtk_scp through the devicetree "mediatek,scp" (phandle) property. In case of multi-core SCP, this also allows to select a specific core. Reviewed-by: Chen-Yu Tsai Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/mdp3/mtk-mdp3-core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index cc44be10fdb7..94f4ed78523b 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -208,13 +208,17 @@ static int mdp_probe(struct platform_device *pdev) goto err_destroy_job_wq; } - mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP); - if (WARN_ON(!mm_pdev)) { - dev_err(&pdev->dev, "Could not get scp device\n"); - ret = -ENODEV; - goto err_destroy_clock_wq; + mdp->scp = scp_get(pdev); + if (!mdp->scp) { + mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP); + if (WARN_ON(!mm_pdev)) { + dev_err(&pdev->dev, "Could not get scp device\n"); + ret = -ENODEV; + goto err_destroy_clock_wq; + } + mdp->scp = platform_get_drvdata(mm_pdev); } - mdp->scp = platform_get_drvdata(mm_pdev); + mdp->rproc_handle = scp_get_rproc(mdp->scp); dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle); From 9f0f0013d3d9395d535d91c623ecb0e82ce4c020 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 23 Nov 2023 11:38:08 +0100 Subject: [PATCH 2950/7721] media: exynos-gsc: remove unused improper CONFIG definition Defines prefixed with "CONFIG" should be limited to proper Kconfig options, that are introduced in a Kconfig file. In the driver code, there is a define for CONFIG_VB2_GSC_DMA_CONTIG, but this is not used anywhere in the code. Just remove this unused definition. No functional change. Signed-off-by: Lukas Bulwahn Reviewed-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/exynos-gsc/gsc-core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index 1ea5fa1bf3c8..b9777e07fb6d 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -26,7 +26,6 @@ #include "gsc-regs.h" -#define CONFIG_VB2_GSC_DMA_CONTIG 1 #define GSC_MODULE_NAME "exynos-gsc" #define GSC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) From 98b3cd0bfc5c07809166421e8b8f82bf74ee8970 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Thu, 23 Nov 2023 10:52:25 -0500 Subject: [PATCH 2951/7721] media: visl: Add AV1 support Let the visl test driver accept the AV1 pixel format. Reviewed-by: Daniel Almeida Tested-by: Daniel Almeida Signed-off-by: Detlev Casanova Signed-off-by: Hans Verkuil --- drivers/media/test-drivers/visl/visl-core.c | 21 ++ drivers/media/test-drivers/visl/visl-dec.c | 72 +++- drivers/media/test-drivers/visl/visl-dec.h | 8 + .../media/test-drivers/visl/visl-trace-av1.h | 314 ++++++++++++++++++ .../test-drivers/visl/visl-trace-points.c | 1 + drivers/media/test-drivers/visl/visl-video.c | 18 + drivers/media/test-drivers/visl/visl-video.h | 1 + drivers/media/test-drivers/visl/visl.h | 1 + 8 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 drivers/media/test-drivers/visl/visl-trace-av1.h diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index 9970dc739ca5..68dac896277b 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -211,6 +211,27 @@ const struct visl_ctrls visl_hevc_ctrls = { .num_ctrls = ARRAY_SIZE(visl_hevc_ctrl_descs), }; +static const struct visl_ctrl_desc visl_av1_ctrl_descs[] = { + { + .cfg.id = V4L2_CID_STATELESS_AV1_FRAME, + }, + { + .cfg.id = V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY, + .cfg.dims = { V4L2_AV1_MAX_TILE_COUNT }, + }, + { + .cfg.id = V4L2_CID_STATELESS_AV1_SEQUENCE, + }, + { + .cfg.id = V4L2_CID_STATELESS_AV1_FILM_GRAIN, + }, +}; + +const struct visl_ctrls visl_av1_ctrls = { + .ctrls = visl_av1_ctrl_descs, + .num_ctrls = ARRAY_SIZE(visl_av1_ctrl_descs), +}; + struct v4l2_ctrl *visl_find_control(struct visl_ctx *ctx, u32 id) { struct v4l2_ctrl_handler *hdl = &ctx->hdl; diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c index 4672dc5e52bb..f21260054e0f 100644 --- a/drivers/media/test-drivers/visl/visl-dec.c +++ b/drivers/media/test-drivers/visl/visl-dec.c @@ -13,12 +13,21 @@ #include "visl-trace-vp9.h" #include "visl-trace-h264.h" #include "visl-trace-hevc.h" +#include "visl-trace-av1.h" #include #include #include #include +#define LAST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define LAST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define LAST3_BUF_IDX (V4L2_AV1_REF_LAST3_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define GOLDEN_BUF_IDX (V4L2_AV1_REF_GOLDEN_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define BWD_BUF_IDX (V4L2_AV1_REF_BWDREF_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define ALT2_BUF_IDX (V4L2_AV1_REF_ALTREF2_FRAME - V4L2_AV1_REF_LAST_FRAME) +#define ALT_BUF_IDX (V4L2_AV1_REF_ALTREF_FRAME - V4L2_AV1_REF_LAST_FRAME) + static void *plane_vaddr(struct tpg_data *tpg, struct vb2_buffer *buf, u32 p, u32 bpl[TPG_MAX_PLANES], u32 h) { @@ -152,6 +161,55 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf, break; } + + case VISL_CODEC_AV1: { + int idx_last = run->av1.frame->ref_frame_idx[LAST_BUF_IDX]; + int idx_last2 = run->av1.frame->ref_frame_idx[LAST2_BUF_IDX]; + int idx_last3 = run->av1.frame->ref_frame_idx[LAST3_BUF_IDX]; + int idx_golden = run->av1.frame->ref_frame_idx[GOLDEN_BUF_IDX]; + int idx_bwd = run->av1.frame->ref_frame_idx[BWD_BUF_IDX]; + int idx_alt2 = run->av1.frame->ref_frame_idx[ALT2_BUF_IDX]; + int idx_alt = run->av1.frame->ref_frame_idx[ALT_BUF_IDX]; + + struct vb2_buffer *ref_last = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last]); + struct vb2_buffer *ref_last2 = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last2]); + struct vb2_buffer *ref_last3 = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last3]); + struct vb2_buffer *ref_golden = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_golden]); + struct vb2_buffer *ref_bwd = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_bwd]); + struct vb2_buffer *ref_alt2 = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_alt2]); + struct vb2_buffer *ref_alt = + vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_alt]); + + scnprintf(buf, buflen, + "ref_last_ts: %llu, vb2_idx: %d\n" + "ref_last2_ts: %llu, vb2_idx: %d\n" + "ref_last3_ts: %llu, vb2_idx: %d\n" + "ref_golden_ts: %llu, vb2_idx: %d\n" + "ref_bwd_ts: %llu, vb2_idx: %d\n" + "ref_alt2_ts: %llu, vb2_idx: %d\n" + "ref_alt_ts: %llu, vb2_idx: %d\n", + run->av1.frame->reference_frame_ts[idx_last], + ref_last ? ref_last->index : -1, + run->av1.frame->reference_frame_ts[idx_last2], + ref_last2 ? ref_last2->index : -1, + run->av1.frame->reference_frame_ts[idx_last3], + ref_last3 ? ref_last3->index : -1, + run->av1.frame->reference_frame_ts[idx_golden], + ref_golden ? ref_golden->index : -1, + run->av1.frame->reference_frame_ts[idx_bwd], + ref_bwd ? ref_bwd->index : -1, + run->av1.frame->reference_frame_ts[idx_alt2], + ref_alt2 ? ref_alt2->index : -1, + run->av1.frame->reference_frame_ts[idx_alt], + ref_alt ? ref_alt->index : -1); + break; + } } } @@ -424,7 +482,13 @@ static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run) trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]); trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table); - break; + break; + case VISL_CODEC_AV1: + trace_v4l2_ctrl_av1_sequence(run->av1.seq); + trace_v4l2_ctrl_av1_frame(run->av1.frame); + trace_v4l2_ctrl_av1_film_grain(run->av1.grain); + trace_v4l2_ctrl_av1_tile_group_entry(run->av1.tge); + break; } } @@ -483,6 +547,12 @@ void visl_device_run(void *priv) run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); break; + case VISL_CODEC_AV1: + run.av1.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE); + run.av1.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FRAME); + run.av1.tge = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY); + run.av1.grain = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN); + break; } frame_dprintk(ctx->dev, run.dst->sequence, diff --git a/drivers/media/test-drivers/visl/visl-dec.h b/drivers/media/test-drivers/visl/visl-dec.h index 4a706a9de02e..c2c2ef3a8798 100644 --- a/drivers/media/test-drivers/visl/visl-dec.h +++ b/drivers/media/test-drivers/visl/visl-dec.h @@ -45,6 +45,13 @@ struct visl_hevc_run { const struct v4l2_ctrl_hevc_decode_params *dpram; }; +struct visl_av1_run { + const struct v4l2_ctrl_av1_sequence *seq; + const struct v4l2_ctrl_av1_frame *frame; + const struct v4l2_ctrl_av1_tile_group_entry *tge; + const struct v4l2_ctrl_av1_film_grain *grain; +}; + struct visl_run { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; @@ -56,6 +63,7 @@ struct visl_run { struct visl_vp9_run vp9; struct visl_h264_run h264; struct visl_hevc_run hevc; + struct visl_av1_run av1; }; }; diff --git a/drivers/media/test-drivers/visl/visl-trace-av1.h b/drivers/media/test-drivers/visl/visl-trace-av1.h new file mode 100644 index 000000000000..09f205de53df --- /dev/null +++ b/drivers/media/test-drivers/visl/visl-trace-av1.h @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#if !defined(_VISL_TRACE_AV1_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _VISL_TRACE_AV1_H_ + +#include +#include "visl.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM visl_av1_controls + +DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl, + TP_PROTO(const struct v4l2_ctrl_av1_sequence *s), + TP_ARGS(s), + TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_sequence, s)), + TP_fast_assign(__entry->s = *s;), + TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n" + "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n", + __print_flags(__entry->s.flags, "|", + {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"}, + {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA, "ENABLE_FILTER_INTRA"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER, "ENABLE_INTRA_EDGE_FILTER"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND, "ENABLE_INTERINTRA_COMPOUND"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND, "ENABLE_MASKED_COMPOUND"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION, "ENABLE_WARPED_MOTION"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER, "ENABLE_DUAL_FILTER"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT, "ENABLE_ORDER_HINT"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP, "ENABLE_JNT_COMP"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS, "ENABLE_REF_FRAME_MVS"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES, "ENABLE_SUPERRES"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF, "ENABLE_CDEF"}, + {V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION, "ENABLE_RESTORATION"}, + {V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME, "MONO_CHROME"}, + {V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE, "COLOR_RANGE"}, + {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X, "SUBSAMPLING_X"}, + {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y, "SUBSAMPLING_Y"}, + {V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT, "FILM_GRAIN_PARAMS_PRESENT"}, + {V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q, "SEPARATE_UV_DELTA_Q"}), + __entry->s.seq_profile, + __entry->s.order_hint_bits, + __entry->s.bit_depth, + __entry->s.max_frame_width_minus_1, + __entry->s.max_frame_height_minus_1 + ) +); + +DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl, + TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t), + TP_ARGS(t), + TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_tile_group_entry, t)), + TP_fast_assign(__entry->t = *t;), + TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n", + __entry->t.tile_offset, + __entry->t.tile_size, + __entry->t.tile_row, + __entry->t.tile_col + ) +); + +DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl, + TP_PROTO(const struct v4l2_ctrl_av1_frame *f), + TP_ARGS(f), + TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_frame, f)), + TP_fast_assign(__entry->f = *f;), + TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n" + "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n" + "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n" + "tile_info.width_in_sbs_minus_1: %s\ntile_info.height_in_sbs_minus_1: %s\n" + "tile_info.tile_size_bytes: %u\nquantization.flags: %s\n" + "quantization.base_q_idx: %u\nquantization.delta_q_y_dc: %d\n" + "quantization.delta_q_u_dc: %d\nquantization.delta_q_u_ac: %d\n" + "quantization.delta_q_v_dc: %d\nquantization.delta_q_v_ac: %d\n" + "quantization.qm_y: %u\nquantization.qm_u: %u\nquantization.qm_v: %u\n" + "quantization.delta_q_res: %u\nsuperres_denom: %u\nsegmentation.flags: %s\n" + "segmentation.last_active_seg_id: %u\nsegmentation.feature_enabled:%s\n" + "loop_filter.flags: %s\nloop_filter.level: %s\nloop_filter.sharpness: %u\n" + "loop_filter.ref_deltas: %s\nloop_filter.mode_deltas: %s\n" + "loop_filter.delta_lf_res: %u\ncdef.damping_minus_3: %u\ncdef.bits: %u\n" + "cdef.y_pri_strength: %s\ncdef.y_sec_strength: %s\n" + "cdef.uv_pri_strength: %s\ncdef.uv_sec_strength:%s\nskip_mode_frame: %s\n" + "primary_ref_frame: %u\nloop_restoration.flags: %s\n" + "loop_restoration.lr_unit_shift: %u\nloop_restoration.lr_uv_shift: %u\n" + "loop_restoration.frame_restoration_type: %s\n" + "loop_restoration.loop_restoration_size: %s\nflags: %s\norder_hint: %u\n" + "upscaled_width: %u\nframe_width_minus_1: %u\nframe_height_minus_1: %u\n" + "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n" + "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n" + "ref_frame_idx: %s\nrefresh_frame_flags: %u\n", + __print_flags(__entry->f.tile_info.flags, "|", + {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}), + __entry->f.tile_info.context_update_tile_id, + __entry->f.tile_info.tile_cols, + __entry->f.tile_info.tile_rows, + __print_array(__entry->f.tile_info.mi_col_starts, + ARRAY_SIZE(__entry->f.tile_info.mi_col_starts), + sizeof(__entry->f.tile_info.mi_col_starts[0])), + __print_array(__entry->f.tile_info.mi_row_starts, + ARRAY_SIZE(__entry->f.tile_info.mi_row_starts), + sizeof(__entry->f.tile_info.mi_row_starts[0])), + __print_array(__entry->f.tile_info.width_in_sbs_minus_1, + ARRAY_SIZE(__entry->f.tile_info.width_in_sbs_minus_1), + sizeof(__entry->f.tile_info.width_in_sbs_minus_1[0])), + __print_array(__entry->f.tile_info.height_in_sbs_minus_1, + ARRAY_SIZE(__entry->f.tile_info.height_in_sbs_minus_1), + sizeof(__entry->f.tile_info.height_in_sbs_minus_1[0])), + __entry->f.tile_info.tile_size_bytes, + __print_flags(__entry->f.quantization.flags, "|", + {V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA, "DIFF_UV_DELTA"}, + {V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX, "USING_QMATRIX"}, + {V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT, "DELTA_Q_PRESENT"}), + __entry->f.quantization.base_q_idx, + __entry->f.quantization.delta_q_y_dc, + __entry->f.quantization.delta_q_u_dc, + __entry->f.quantization.delta_q_u_ac, + __entry->f.quantization.delta_q_v_dc, + __entry->f.quantization.delta_q_v_ac, + __entry->f.quantization.qm_y, + __entry->f.quantization.qm_u, + __entry->f.quantization.qm_v, + __entry->f.quantization.delta_q_res, + __entry->f.superres_denom, + __print_flags(__entry->f.segmentation.flags, "|", + {V4L2_AV1_SEGMENTATION_FLAG_ENABLED, "ENABLED"}, + {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"}, + {V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"}, + {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"}, + {V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP, "SEG_ID_PRE_SKIP"}), + __entry->f.segmentation.last_active_seg_id, + __print_array(__entry->f.segmentation.feature_enabled, + ARRAY_SIZE(__entry->f.segmentation.feature_enabled), + sizeof(__entry->f.segmentation.feature_enabled[0])), + __print_flags(__entry->f.loop_filter.flags, "|", + {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"}, + {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"}, + {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT, "DELTA_LF_PRESENT"}, + {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI, "DELTA_LF_MULTI"}), + __print_array(__entry->f.loop_filter.level, + ARRAY_SIZE(__entry->f.loop_filter.level), + sizeof(__entry->f.loop_filter.level[0])), + __entry->f.loop_filter.sharpness, + __print_array(__entry->f.loop_filter.ref_deltas, + ARRAY_SIZE(__entry->f.loop_filter.ref_deltas), + sizeof(__entry->f.loop_filter.ref_deltas[0])), + __print_array(__entry->f.loop_filter.mode_deltas, + ARRAY_SIZE(__entry->f.loop_filter.mode_deltas), + sizeof(__entry->f.loop_filter.mode_deltas[0])), + __entry->f.loop_filter.delta_lf_res, + __entry->f.cdef.damping_minus_3, + __entry->f.cdef.bits, + __print_array(__entry->f.cdef.y_pri_strength, + ARRAY_SIZE(__entry->f.cdef.y_pri_strength), + sizeof(__entry->f.cdef.y_pri_strength[0])), + __print_array(__entry->f.cdef.y_sec_strength, + ARRAY_SIZE(__entry->f.cdef.y_sec_strength), + sizeof(__entry->f.cdef.y_sec_strength[0])), + __print_array(__entry->f.cdef.uv_pri_strength, + ARRAY_SIZE(__entry->f.cdef.uv_pri_strength), + sizeof(__entry->f.cdef.uv_pri_strength[0])), + __print_array(__entry->f.cdef.uv_sec_strength, + ARRAY_SIZE(__entry->f.cdef.uv_sec_strength), + sizeof(__entry->f.cdef.uv_sec_strength[0])), + __print_array(__entry->f.skip_mode_frame, + ARRAY_SIZE(__entry->f.skip_mode_frame), + sizeof(__entry->f.skip_mode_frame[0])), + __entry->f.primary_ref_frame, + __print_flags(__entry->f.loop_restoration.flags, "|", + {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR, "USES_LR"}, + {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR, "USES_CHROMA_LR"}), + __entry->f.loop_restoration.lr_unit_shift, + __entry->f.loop_restoration.lr_uv_shift, + __print_array(__entry->f.loop_restoration.frame_restoration_type, + ARRAY_SIZE(__entry->f.loop_restoration.frame_restoration_type), + sizeof(__entry->f.loop_restoration.frame_restoration_type[0])), + __print_array(__entry->f.loop_restoration.loop_restoration_size, + ARRAY_SIZE(__entry->f.loop_restoration.loop_restoration_size), + sizeof(__entry->f.loop_restoration.loop_restoration_size[0])), + __print_flags(__entry->f.flags, "|", + {V4L2_AV1_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"}, + {V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME, "SHOWABLE_FRAME"}, + {V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE, "ERROR_RESILIENT_MODE"}, + {V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE, "DISABLE_CDF_UPDATE"}, + {V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS, "ALLOW_SCREEN_CONTENT_TOOLS"}, + {V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV, "FORCE_INTEGER_MV"}, + {V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC, "ALLOW_INTRABC"}, + {V4L2_AV1_FRAME_FLAG_USE_SUPERRES, "USE_SUPERRES"}, + {V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV, "ALLOW_HIGH_PRECISION_MV"}, + {V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE, "IS_MOTION_MODE_SWITCHABLE"}, + {V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS, "USE_REF_FRAME_MVS"}, + {V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF, + "DISABLE_FRAME_END_UPDATE_CDF"}, + {V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION, "ALLOW_WARPED_MOTION"}, + {V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT, "REFERENCE_SELECT"}, + {V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET, "REDUCED_TX_SET"}, + {V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED, "SKIP_MODE_ALLOWED"}, + {V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT, "SKIP_MODE_PRESENT"}, + {V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE, "FRAME_SIZE_OVERRIDE"}, + {V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT, "BUFFER_REMOVAL_TIME_PRESENT"}, + {V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING, "FRAME_REFS_SHORT_SIGNALING"}), + __entry->f.order_hint, + __entry->f.upscaled_width, + __entry->f.frame_width_minus_1, + __entry->f.frame_height_minus_1, + __entry->f.render_width_minus_1, + __entry->f.render_height_minus_1, + __entry->f.current_frame_id, + __print_array(__entry->f.buffer_removal_time, + ARRAY_SIZE(__entry->f.buffer_removal_time), + sizeof(__entry->f.buffer_removal_time[0])), + __print_array(__entry->f.order_hints, + ARRAY_SIZE(__entry->f.order_hints), + sizeof(__entry->f.order_hints[0])), + __print_array(__entry->f.reference_frame_ts, + ARRAY_SIZE(__entry->f.reference_frame_ts), + sizeof(__entry->f.reference_frame_ts[0])), + __print_array(__entry->f.ref_frame_idx, + ARRAY_SIZE(__entry->f.ref_frame_idx), + sizeof(__entry->f.ref_frame_idx[0])), + __entry->f.refresh_frame_flags + ) +); + + +DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl, + TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f), + TP_ARGS(f), + TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_film_grain, f)), + TP_fast_assign(__entry->f = *f;), + TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n" + "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n" + "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n" + "point_cb_scaling: %s\nnum_cr_points: %u\npoint_cr_value: %s\n" + "point_cr_scaling: %s\ngrain_scaling_minus_8: %u\nar_coeff_lag: %u\n" + "ar_coeffs_y_plus_128: %s\nar_coeffs_cb_plus_128: %s\n" + "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n" + "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n" + "cb_offset: %u\ncr_offset: %u\n", + __print_flags(__entry->f.flags, "|", + {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"}, + {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"}, + {V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA, "CHROMA_SCALING_FROM_LUMA"}, + {V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP, "OVERLAP"}, + {V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE, "CLIP_TO_RESTRICTED_RANGE"}), + __entry->f.cr_mult, + __entry->f.grain_seed, + __entry->f.film_grain_params_ref_idx, + __entry->f.num_y_points, + __print_array(__entry->f.point_y_value, + ARRAY_SIZE(__entry->f.point_y_value), + sizeof(__entry->f.point_y_value[0])), + __print_array(__entry->f.point_y_scaling, + ARRAY_SIZE(__entry->f.point_y_scaling), + sizeof(__entry->f.point_y_scaling[0])), + __entry->f.num_cb_points, + __print_array(__entry->f.point_cb_value, + ARRAY_SIZE(__entry->f.point_cb_value), + sizeof(__entry->f.point_cb_value[0])), + __print_array(__entry->f.point_cb_scaling, + ARRAY_SIZE(__entry->f.point_cb_scaling), + sizeof(__entry->f.point_cb_scaling[0])), + __entry->f.num_cr_points, + __print_array(__entry->f.point_cr_value, + ARRAY_SIZE(__entry->f.point_cr_value), + sizeof(__entry->f.point_cr_value[0])), + __print_array(__entry->f.point_cr_scaling, + ARRAY_SIZE(__entry->f.point_cr_scaling), + sizeof(__entry->f.point_cr_scaling[0])), + __entry->f.grain_scaling_minus_8, + __entry->f.ar_coeff_lag, + __print_array(__entry->f.ar_coeffs_y_plus_128, + ARRAY_SIZE(__entry->f.ar_coeffs_y_plus_128), + sizeof(__entry->f.ar_coeffs_y_plus_128[0])), + __print_array(__entry->f.ar_coeffs_cb_plus_128, + ARRAY_SIZE(__entry->f.ar_coeffs_cb_plus_128), + sizeof(__entry->f.ar_coeffs_cb_plus_128[0])), + __print_array(__entry->f.ar_coeffs_cr_plus_128, + ARRAY_SIZE(__entry->f.ar_coeffs_cr_plus_128), + sizeof(__entry->f.ar_coeffs_cr_plus_128[0])), + __entry->f.ar_coeff_shift_minus_6, + __entry->f.grain_scale_shift, + __entry->f.cb_mult, + __entry->f.cb_luma_mult, + __entry->f.cr_luma_mult, + __entry->f.cb_offset, + __entry->f.cr_offset + ) +) + +DEFINE_EVENT(v4l2_ctrl_av1_seq_tmpl, v4l2_ctrl_av1_sequence, + TP_PROTO(const struct v4l2_ctrl_av1_sequence *s), + TP_ARGS(s) +); + +DEFINE_EVENT(v4l2_ctrl_av1_frame_tmpl, v4l2_ctrl_av1_frame, + TP_PROTO(const struct v4l2_ctrl_av1_frame *f), + TP_ARGS(f) +); + +DEFINE_EVENT(v4l2_ctrl_av1_tge_tmpl, v4l2_ctrl_av1_tile_group_entry, + TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t), + TP_ARGS(t) +); + +DEFINE_EVENT(v4l2_ctrl_av1_film_grain_tmpl, v4l2_ctrl_av1_film_grain, + TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f), + TP_ARGS(f) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl +#define TRACE_INCLUDE_FILE visl-trace-av1 +#include diff --git a/drivers/media/test-drivers/visl/visl-trace-points.c b/drivers/media/test-drivers/visl/visl-trace-points.c index f7b866534f1e..321ff732c682 100644 --- a/drivers/media/test-drivers/visl/visl-trace-points.c +++ b/drivers/media/test-drivers/visl/visl-trace-points.c @@ -8,3 +8,4 @@ #include "visl-trace-vp9.h" #include "visl-trace-h264.h" #include "visl-trace-hevc.h" +#include "visl-trace-av1.h" diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index 9303a3e118d7..b9a4b44bd0ed 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -40,6 +40,9 @@ static void visl_set_current_codec(struct visl_ctx *ctx) case V4L2_PIX_FMT_HEVC_SLICE: ctx->current_codec = VISL_CODEC_HEVC; break; + case V4L2_PIX_FMT_AV1_FRAME: + ctx->current_codec = VISL_CODEC_AV1; + break; default: dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n", fourcc); ctx->current_codec = VISL_CODEC_NONE; @@ -218,6 +221,21 @@ const struct visl_coded_format_desc visl_coded_fmts[] = { .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), .decoded_fmts = visl_decoded_fmts, }, + { + .pixelformat = V4L2_PIX_FMT_AV1_FRAME, + .frmsize = { + .min_width = 64, + .max_width = 4096, + .step_width = 1, + .min_height = 64, + .max_height = 2304, + .step_height = 1, + }, + .ctrls = &visl_av1_ctrls, + .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), + .decoded_fmts = visl_decoded_fmts, + }, + }; const size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts); diff --git a/drivers/media/test-drivers/visl/visl-video.h b/drivers/media/test-drivers/visl/visl-video.h index 27ad70a558db..92e274894c20 100644 --- a/drivers/media/test-drivers/visl/visl-video.h +++ b/drivers/media/test-drivers/visl/visl-video.h @@ -17,6 +17,7 @@ extern const struct visl_ctrls visl_vp8_ctrls; extern const struct visl_ctrls visl_vp9_ctrls; extern const struct visl_ctrls visl_h264_ctrls; extern const struct visl_ctrls visl_hevc_ctrls; +extern const struct visl_ctrls visl_av1_ctrls; int visl_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h index 31639f2e593d..c593b1337f11 100644 --- a/drivers/media/test-drivers/visl/visl.h +++ b/drivers/media/test-drivers/visl/visl.h @@ -127,6 +127,7 @@ enum visl_codec { VISL_CODEC_VP9, VISL_CODEC_H264, VISL_CODEC_HEVC, + VISL_CODEC_AV1, }; struct visl_blob { From 357547b87673ca88455c40aafffeea161207a52a Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Thu, 23 Nov 2023 10:52:26 -0500 Subject: [PATCH 2952/7721] doc: media: visl: Add AV1 support Add AV1 information in visl documentation. Reviewed-by: Daniel Almeida Signed-off-by: Detlev Casanova Signed-off-by: Hans Verkuil --- Documentation/admin-guide/media/visl.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/admin-guide/media/visl.rst b/Documentation/admin-guide/media/visl.rst index 4328c6c72d30..db1ef29438e1 100644 --- a/Documentation/admin-guide/media/visl.rst +++ b/Documentation/admin-guide/media/visl.rst @@ -71,6 +71,7 @@ The following codecs are supported: - VP9 - H.264 - HEVC +- AV1 visl trace events ----------------- @@ -79,6 +80,7 @@ The trace events are defined on a per-codec basis, e.g.: .. code-block:: bash $ ls /sys/kernel/tracing/events/ | grep visl + visl_av1_controls visl_fwht_controls visl_h264_controls visl_hevc_controls From 608ca5a60ee47b48fec210aeb7a795a64eb5dcee Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Thu, 23 Nov 2023 23:32:05 +0100 Subject: [PATCH 2953/7721] media: videobuf2-dma-sg: fix vmap callback For dmabuf import users to be able to use the vaddr from another videobuf2-dma-sg source, the exporter needs to set a proper vaddr on vb2_dma_sg_dmabuf_ops_vmap callback. This patch adds vmap on map if buf->vaddr was not set. Cc: stable@kernel.org Fixes: 7938f4218168 ("dma-buf-map: Rename to iosys-map") Signed-off-by: Michael Grzeschik Acked-by: Tomasz Figa Signed-off-by: Hans Verkuil --- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 28f3fdfe23a2..6975a71d740f 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -487,9 +487,15 @@ vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf, struct iosys_map *map) { - struct vb2_dma_sg_buf *buf = dbuf->priv; + struct vb2_dma_sg_buf *buf; + void *vaddr; - iosys_map_set_vaddr(map, buf->vaddr); + buf = dbuf->priv; + vaddr = vb2_dma_sg_vaddr(buf->vb, buf); + if (!vaddr) + return -EINVAL; + + iosys_map_set_vaddr(map, vaddr); return 0; } From fca4797af415bd346c4b2737eee7bbbc4bf1866c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Nov 2023 17:40:14 +0300 Subject: [PATCH 2954/7721] media: staging: starfive: camss: fix off by one in isp_enum_mbus_code() These > comparisons should be >=. The formats->fmts[] array is either a pointer to isp_formats_sink[] or isp_formats_source[] respectively. Fixes: e57854628f58 ("media: staging: media: starfive: camss: Add ISP driver") Signed-off-by: Dan Carpenter Reviewed-by: Changhuang Liang Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/stf-isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/starfive/camss/stf-isp.c b/drivers/staging/media/starfive/camss/stf-isp.c index 6bffffb2b20c..d50616ef351e 100644 --- a/drivers/staging/media/starfive/camss/stf-isp.c +++ b/drivers/staging/media/starfive/camss/stf-isp.c @@ -120,7 +120,7 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd, const struct stf_isp_format_table *formats; if (code->pad == STF_ISP_PAD_SINK) { - if (code->index > ARRAY_SIZE(isp_formats_sink)) + if (code->index >= ARRAY_SIZE(isp_formats_sink)) return -EINVAL; formats = &isp_dev->formats[SINK_FORMATS_INDEX]; @@ -128,7 +128,7 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd, } else { struct v4l2_mbus_framefmt *sink_fmt; - if (code->index > ARRAY_SIZE(isp_formats_source)) + if (code->index >= ARRAY_SIZE(isp_formats_source)) return -EINVAL; sink_fmt = v4l2_subdev_state_get_format(state, From 15dfed5b4933564470d608705c1630b6ad822160 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Nov 2023 19:26:36 +0100 Subject: [PATCH 2955/7721] media: chips-media: wave5: VIDEO_WAVE_VPU should depend on ARCH_K3 The Chips&Media Wave 5 Series multi-standard codec IP is currently only supported on Texas Instruments K3 architecture. Hence add a dependency on ARCH_K3, to prevent asking the user about this driver when configuring a kernel without Texas Instruments K3 Multicore SoC support. Fixes: 9707a6254a8a ("media: chips-media: wave5: Add the v4l2 layer") Signed-off-by: Geert Uytterhoeven Reviewed-by: Nishanth Menon Signed-off-by: Hans Verkuil [hverkuil: small update in commit log, and reformatted the Fixes tag] --- drivers/media/platform/chips-media/wave5/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig index 77e7ae5c8f35..9ccc1f7e32f3 100644 --- a/drivers/media/platform/chips-media/wave5/Kconfig +++ b/drivers/media/platform/chips-media/wave5/Kconfig @@ -3,6 +3,7 @@ config VIDEO_WAVE_VPU tristate "Chips&Media Wave Codec Driver" depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV && OF + depends on ARCH_K3 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV From b58253793f4fe7495af3157d7f29cf0919183009 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Nov 2023 19:31:53 +0100 Subject: [PATCH 2956/7721] staging: media: VIDEO_STARFIVE_CAMSS should depend on ARCH_STARFIVE The StarFive Camera Subsystem is only present on the StarFive JH7110 SoC. Hence add a dependency on ARCH_STARFIVE, to prevent asking the user about this driver when configuring a kernel without StarFive SoC support. Fixes: bba185d141b1 ("media: staging: media: starfive: camss: Add core driver") Signed-off-by: Geert Uytterhoeven Reviewed-by: Changhuang Liang Signed-off-by: Hans Verkuil --- drivers/staging/media/starfive/camss/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/starfive/camss/Kconfig b/drivers/staging/media/starfive/camss/Kconfig index bd184f42c98f..9ea5708fe409 100644 --- a/drivers/staging/media/starfive/camss/Kconfig +++ b/drivers/staging/media/starfive/camss/Kconfig @@ -5,6 +5,7 @@ config VIDEO_STARFIVE_CAMSS depends on VIDEO_DEV && OF depends on HAS_DMA depends on PM + depends on ARCH_STARFIVE || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG From 5d3c8990e2bbf929cb211563dadd70708f42e4e6 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 1 Dec 2023 21:22:55 +0800 Subject: [PATCH 2957/7721] media: cx231xx: fix a memleak in cx231xx_init_isoc The dma_q->p_left_data alloced by kzalloc should be freed in all the following error handling paths. However, it hasn't been freed in the allocation error paths of dev->video_mode.isoc_ctl.urb and dev->video_mode.isoc_ctl.transfer_buffer. On the other hand, the dma_q->p_left_data did be freed in the error-handling paths after that of dev->video_mode.isoc_ctl.urb and dev->video_mode.isoc_ctl.transfer_buffer, by calling cx231xx_uninit_isoc(dev). So the same free operation should be done in error-handling paths of those two allocation. Fixes: 64fbf4445526 ("[media] cx231xx: Added support for Carraera, Shelby, RDx_253S and VIDEO_GRABBER") Signed-off-by: Zhipeng Lu Signed-off-by: Hans Verkuil --- drivers/media/usb/cx231xx/cx231xx-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 7b7e2a26ef93..d8312201694f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1023,6 +1023,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, if (!dev->video_mode.isoc_ctl.urb) { dev_err(dev->dev, "cannot alloc memory for usb buffers\n"); + kfree(dma_q->p_left_data); return -ENOMEM; } @@ -1032,6 +1033,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, dev_err(dev->dev, "cannot allocate memory for usbtransfer\n"); kfree(dev->video_mode.isoc_ctl.urb); + kfree(dma_q->p_left_data); return -ENOMEM; } From b3695e86d25aafbe175dd51f6aaf6f68d341d590 Mon Sep 17 00:00:00 2001 From: Ghanshyam Agrawal Date: Sat, 25 Nov 2023 14:32:36 +0530 Subject: [PATCH 2958/7721] media: stk1160: Fixed high volume of stk1160_dbg messages The function stk1160_dbg gets called too many times, which causes the output to get flooded with messages. Since stk1160_dbg uses printk, it is now replaced with printk_ratelimited. Suggested-by: Phillip Potter Signed-off-by: Ghanshyam Agrawal Signed-off-by: Hans Verkuil --- drivers/media/usb/stk1160/stk1160-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 4e966f6bf608..366f0e4a5dc0 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -107,8 +107,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* * TODO: These stk1160_dbg are very spammy! - * We should 1) check why we are getting them - * and 2) add ratelimit. + * We should check why we are getting them. * * UPDATE: One of the reasons (the only one?) for getting these * is incorrect standard (mismatch between expected and configured). @@ -151,7 +150,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* Let the bug hunt begin! sanity checks! */ if (lencopy < 0) { - stk1160_dbg("copy skipped: negative lencopy\n"); + printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n"); return; } From ac6494e0ca444d82ff9dc0df87fcfca1d91c5cd2 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 23 Nov 2023 17:03:00 +0000 Subject: [PATCH 2959/7721] media: qcom: camss: Flag which VFEs require a power-domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment we have some complex code for determining if a VFE requires a power-domain attachment. Particularly discordant in this scheme is the subtle reliance on VFE and VFE Lite declaration ordering in our resources. VFE id is used to determine if a VFE is lite or not and consequently if a VFE requires power-domain attachment. VFE Lite though is not a correct delineation between power-domain and non power-domain state since early SoCs have neither VFE Lite nor power-domains attached to VFEs. Introduce has_pd to the VFE resource structure to allow the CAMSS code to understand if it needs to try to attach a power-domain for a given VFE. As a side-effect from this we no longer need to care about VFE Lite or non-Lite or the id number associated with either and which order the VFE/VFE Lite was declared in. Reviewed-by: Konrad Dybcio Tested-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 8 ++++++++ drivers/media/platform/qcom/camss/camss.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 8e78dd8d5961..ed01a3ac7a38 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -278,6 +278,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_4_7 }, @@ -298,6 +299,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_4_7 } }; @@ -468,6 +470,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_4_8 }, @@ -491,6 +494,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_4_8 } }; @@ -658,6 +662,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = 4, + .has_pd = true, .ops = &vfe_ops_170 }, @@ -680,6 +685,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = 4, + .has_pd = true, .ops = &vfe_ops_170 }, @@ -840,6 +846,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_480 }, /* VFE1 */ @@ -860,6 +867,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = 3, + .has_pd = true, .ops = &vfe_ops_480 }, /* VFE2 (lite) */ diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 8acad7321c09..b854cff1774d 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -49,6 +49,7 @@ struct camss_subdev_resources { char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; u8 line_num; + bool has_pd; const void *ops; }; From a409b3f08dbed4b866cffeee48cce703290c300b Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 23 Nov 2023 17:03:01 +0000 Subject: [PATCH 2960/7721] media: qcom: camss: Convert to per-VFE pointer for power-domain linkages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now we use the top-level camss structure to provide pointers via VFE id index back to genpd linkages. In effect this hard-codes VFE indexes to power-domain indexes in the dtsi and mandates a very particular ordering of power domains in the dtsi, which bears no relationship to a real hardware dependency. As a first step to rationalising the VFE power-domain code and breaking the magic indexing in dtsi use per-VFE pointers to genpd linkages. The top-level index in msm_vfe_subdev_init is still used to attain the initial so no functional or logical change arises from this change. Reviewed-by: Konrad Dybcio Tested-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe-170.c | 15 +++++++-------- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 15 +++++---------- drivers/media/platform/qcom/camss/camss-vfe-4-8.c | 13 +++++-------- drivers/media/platform/qcom/camss/camss-vfe-480.c | 15 +++++++-------- drivers/media/platform/qcom/camss/camss-vfe.c | 3 +++ drivers/media/platform/qcom/camss/camss-vfe.h | 2 ++ 6 files changed, 29 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 0b211fed1276..7451484317cc 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -638,7 +638,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) if (vfe->id >= camss->res->vfe_num) return; - device_link_del(camss->genpd_link[vfe->id]); + device_link_del(vfe->genpd_link); } /* @@ -648,16 +648,15 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) static int vfe_pm_domain_on(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - enum vfe_line_id id = vfe->id; - if (id >= camss->res->vfe_num) + if (vfe->id >= camss->res->vfe_num) return 0; - camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!camss->genpd_link[id]) + vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!vfe->genpd_link) return -EINVAL; return 0; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index b65ed0fef595..2b4e7e039407 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -1109,14 +1109,10 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) */ static void vfe_pm_domain_off(struct vfe_device *vfe) { - struct camss *camss; - if (!vfe) return; - camss = vfe->camss; - - device_link_del(camss->genpd_link[vfe->id]); + device_link_del(vfe->genpd_link); } /* @@ -1126,13 +1122,12 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) static int vfe_pm_domain_on(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - enum vfe_line_id id = vfe->id; - camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (!camss->genpd_link[id]) { - dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); + if (!vfe->genpd_link) { + dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", vfe->id); return -EINVAL; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 7b3805177f03..5e9534324130 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -1099,9 +1099,7 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) */ static void vfe_pm_domain_off(struct vfe_device *vfe) { - struct camss *camss = vfe->camss; - - device_link_del(camss->genpd_link[vfe->id]); + device_link_del(vfe->genpd_link); } /* @@ -1111,13 +1109,12 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) static int vfe_pm_domain_on(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - enum vfe_line_id id = vfe->id; - camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (!camss->genpd_link[id]) { - dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); + if (!vfe->genpd_link) { + dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", vfe->id); return -EINVAL; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index f2368b77fc6d..a70b8633bb3e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -463,7 +463,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) if (vfe->id >= camss->res->vfe_num) return; - device_link_del(camss->genpd_link[vfe->id]); + device_link_del(vfe->genpd_link); } /* @@ -473,16 +473,15 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) static int vfe_pm_domain_on(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - enum vfe_line_id id = vfe->id; - if (id >= camss->res->vfe_num) + if (vfe->id >= camss->res->vfe_num) return 0; - camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!camss->genpd_link[id]) + vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!vfe->genpd_link) return -EINVAL; return 0; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 74fe577a84aa..32a9cd32ffde 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1345,6 +1345,9 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, if (!res->line_num) return -EINVAL; + if (res->has_pd) + vfe->genpd = camss->genpd[id]; + vfe->line_num = res->line_num; vfe->ops->subdev_init(dev, vfe); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 09baded0dcdd..c1c50023d487 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -150,6 +150,8 @@ struct vfe_device { const struct vfe_hw_ops_gen1 *ops_gen1; struct vfe_isr_ops isr_ops; struct camss_video_ops video_ops; + struct device *genpd; + struct device_link *genpd_link; }; struct camss_subdev_resources; From eb73facec2c261c92ad271e87ee37894e0bef9a8 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 23 Nov 2023 17:03:02 +0000 Subject: [PATCH 2961/7721] media: qcom: camss: Use common VFE pm_domain_on/pm_domain_off where applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the various versions of VFE we have a boiler-plate pm_domain_on/pm_domain_off callback pair of the general form. - Error check. Not always done but applicable to all. - device_link_add (DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - Error check returning -EINVAL on error. - Return 0 Reduce the pattern down to a common callback. VFE 4.1 is a special case which to me also indicates that it is worthwhile maintaining an indirection for the vfe_pm_domain_{on|off} for now. Otherwise lets chuck out a bunch of needlessly replicated code. Reviewed-by: Konrad Dybcio Suggested-by: Matti Lehtimäki Tested-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-170.c | 35 ------------------- .../media/platform/qcom/camss/camss-vfe-4-1.c | 8 ++--- .../media/platform/qcom/camss/camss-vfe-4-7.c | 31 ---------------- .../media/platform/qcom/camss/camss-vfe-4-8.c | 28 --------------- .../media/platform/qcom/camss/camss-vfe-480.c | 35 ------------------- drivers/media/platform/qcom/camss/camss-vfe.c | 34 ++++++++++++++++++ drivers/media/platform/qcom/camss/camss-vfe.h | 12 +++++++ 7 files changed, 50 insertions(+), 133 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 7451484317cc..795ac3815339 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -627,41 +627,6 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) spin_unlock_irqrestore(&vfe->output_lock, flags); } -/* - * vfe_pm_domain_off - Disable power domains specific to this VFE. - * @vfe: VFE Device - */ -static void vfe_pm_domain_off(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - if (vfe->id >= camss->res->vfe_num) - return; - - device_link_del(vfe->genpd_link); -} - -/* - * vfe_pm_domain_on - Enable power domains specific to this VFE. - * @vfe: VFE Device - */ -static int vfe_pm_domain_on(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - if (vfe->id >= camss->res->vfe_num) - return 0; - - vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!vfe->genpd_link) - return -EINVAL; - - return 0; -} - /* * vfe_queue_buffer - Add empty buffer * @vid: Video device structure diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 2911e4126e7a..ef6b34c915df 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -936,7 +936,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) * vfe_pm_domain_off - Disable power domains specific to this VFE. * @vfe: VFE Device */ -static void vfe_pm_domain_off(struct vfe_device *vfe) +static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) { /* nop */ } @@ -945,7 +945,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) * vfe_pm_domain_on - Enable power domains specific to this VFE. * @vfe: VFE Device */ -static int vfe_pm_domain_on(struct vfe_device *vfe) +static int vfe_4_1_pm_domain_on(struct vfe_device *vfe) { return 0; } @@ -999,8 +999,8 @@ const struct vfe_hw_ops vfe_ops_4_1 = { .hw_version = vfe_hw_version, .isr_read = vfe_isr_read, .isr = vfe_isr, - .pm_domain_off = vfe_pm_domain_off, - .pm_domain_on = vfe_pm_domain_on, + .pm_domain_off = vfe_4_1_pm_domain_off, + .pm_domain_on = vfe_4_1_pm_domain_on, .reg_update_clear = vfe_reg_update_clear, .reg_update = vfe_reg_update, .subdev_init = vfe_subdev_init, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 2b4e7e039407..7655d22a9fda 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -1103,37 +1103,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); } -/* - * vfe_pm_domain_off - Disable power domains specific to this VFE. - * @vfe: VFE Device - */ -static void vfe_pm_domain_off(struct vfe_device *vfe) -{ - if (!vfe) - return; - - device_link_del(vfe->genpd_link); -} - -/* - * vfe_pm_domain_on - Enable power domains specific to this VFE. - * @vfe: VFE Device - */ -static int vfe_pm_domain_on(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - - if (!vfe->genpd_link) { - dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", vfe->id); - return -EINVAL; - } - - return 0; -} - static void vfe_violation_read(struct vfe_device *vfe) { u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 5e9534324130..f52fa30f3853 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -1093,34 +1093,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); } -/* - * vfe_pm_domain_off - Disable power domains specific to this VFE. - * @vfe: VFE Device - */ -static void vfe_pm_domain_off(struct vfe_device *vfe) -{ - device_link_del(vfe->genpd_link); -} - -/* - * vfe_pm_domain_on - Enable power domains specific to this VFE. - * @vfe: VFE Device - */ -static int vfe_pm_domain_on(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - - if (!vfe->genpd_link) { - dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", vfe->id); - return -EINVAL; - } - - return 0; -} - static void vfe_violation_read(struct vfe_device *vfe) { u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index a70b8633bb3e..4652e8b4cff5 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -452,41 +452,6 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) spin_unlock_irqrestore(&vfe->output_lock, flags); } -/* - * vfe_pm_domain_off - Disable power domains specific to this VFE. - * @vfe: VFE Device - */ -static void vfe_pm_domain_off(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - if (vfe->id >= camss->res->vfe_num) - return; - - device_link_del(vfe->genpd_link); -} - -/* - * vfe_pm_domain_on - Enable power domains specific to this VFE. - * @vfe: VFE Device - */ -static int vfe_pm_domain_on(struct vfe_device *vfe) -{ - struct camss *camss = vfe->camss; - - if (vfe->id >= camss->res->vfe_num) - return 0; - - vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!vfe->genpd_link) - return -EINVAL; - - return 0; -} - /* * vfe_queue_buffer - Add empty buffer * @vid: Video device structure diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 32a9cd32ffde..577afd16fdda 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -474,6 +474,40 @@ void vfe_isr_reset_ack(struct vfe_device *vfe) complete(&vfe->reset_complete); } +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +void vfe_pm_domain_off(struct vfe_device *vfe) +{ + if (!vfe->genpd) + return; + + device_link_del(vfe->genpd_link); + vfe->genpd_link = NULL; +} + +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +int vfe_pm_domain_on(struct vfe_device *vfe) +{ + struct camss *camss = vfe->camss; + + if (!vfe->genpd) + return 0; + + vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!vfe->genpd_link) + return -EINVAL; + + return 0; +} + static int vfe_match_clock_names(struct vfe_device *vfe, struct camss_clock *clock) { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index c1c50023d487..992a2103ec44 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -203,6 +203,18 @@ int vfe_reset(struct vfe_device *vfe); */ int vfe_disable(struct vfe_line *line); +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +void vfe_pm_domain_off(struct vfe_device *vfe); + +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +int vfe_pm_domain_on(struct vfe_device *vfe); + extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; extern const struct vfe_hw_ops vfe_ops_4_8; From 23aa4f0cd3273b269560a9236c48b43a3982ac13 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 23 Nov 2023 17:03:03 +0000 Subject: [PATCH 2962/7721] media: qcom: camss: Move VFE power-domain specifics into vfe.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving the location of the hooks to VFE power domains has several advantages. 1. Separation of concerns and functional decomposition. vfe.c should be responsible for and know best how manage power-domains for a VFE, excising from camss.c follows this principle. 2. Embedding a pointer to genpd in struct camss_vfe{} meas that we can dispense with a bunch of kmalloc array inside of camss.c. 3. Splitting up titan top gdsc from vfe/ife gdsc provides a base for breaking up magic indexes in dtsi. Suggested-by: Matti Lehtimäki Tested-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 21 +++++- drivers/media/platform/qcom/camss/camss-vfe.h | 2 + drivers/media/platform/qcom/camss/camss.c | 67 ++++++++++--------- drivers/media/platform/qcom/camss/camss.h | 4 +- 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 577afd16fdda..60286dac60e0 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1379,8 +1380,11 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, if (!res->line_num) return -EINVAL; - if (res->has_pd) - vfe->genpd = camss->genpd[id]; + if (res->has_pd) { + vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id); + if (IS_ERR(vfe->genpd)) + return PTR_ERR(vfe->genpd); + } vfe->line_num = res->line_num; vfe->ops->subdev_init(dev, vfe); @@ -1504,6 +1508,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return 0; } +/* + * msm_vfe_genpd_cleanup - Cleanup VFE genpd linkages + * @vfe: VFE device + */ +void msm_vfe_genpd_cleanup(struct vfe_device *vfe) +{ + if (vfe->genpd_link) + device_link_del(vfe->genpd_link); + + if (vfe->genpd) + dev_pm_domain_detach(vfe->genpd, true); +} + /* * vfe_link_setup - Setup VFE connections * @entity: Pointer to media entity structure diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 992a2103ec44..cdbe59d8d437 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -159,6 +159,8 @@ struct camss_subdev_resources; int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, const struct camss_subdev_resources *res, u8 id); +void msm_vfe_genpd_cleanup(struct vfe_device *vfe); + int msm_vfe_register_entities(struct vfe_device *vfe, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index ed01a3ac7a38..35918cf837bd 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1486,7 +1486,9 @@ static const struct media_device_ops camss_media_ops = { static int camss_configure_pd(struct camss *camss) { + const struct camss_resources *res = camss->res; struct device *dev = camss->dev; + int vfepd_num; int i; int ret; @@ -1506,45 +1508,41 @@ static int camss_configure_pd(struct camss *camss) if (camss->genpd_num == 1) return 0; - camss->genpd = devm_kmalloc_array(dev, camss->genpd_num, - sizeof(*camss->genpd), GFP_KERNEL); - if (!camss->genpd) - return -ENOMEM; + /* count the # of VFEs which have flagged power-domain */ + for (vfepd_num = i = 0; i < camss->vfe_total_num; i++) { + if (res->vfe_res[i].has_pd) + vfepd_num++; + } - camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num, - sizeof(*camss->genpd_link), - GFP_KERNEL); - if (!camss->genpd_link) - return -ENOMEM; + /* + * If the number of power-domains is greater than the number of VFEs + * then the additional power-domain is for the entire CAMSS block. + */ + if (!(camss->genpd_num > vfepd_num)) + return 0; /* * VFE power domains are in the beginning of the list, and while all * power domains should be attached, only if TITAN_TOP power domain is * found in the list, it should be linked over here. */ - for (i = 0; i < camss->genpd_num; i++) { - camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); - if (IS_ERR(camss->genpd[i])) { - ret = PTR_ERR(camss->genpd[i]); - goto fail_pm; - } + camss->genpd = dev_pm_domain_attach_by_id(camss->dev, camss->genpd_num - 1); + if (IS_ERR(camss->genpd)) { + ret = PTR_ERR(camss->genpd); + goto fail_pm; } - - if (i > camss->res->vfe_num) { - camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!camss->genpd_link[i - 1]) { - ret = -EINVAL; - goto fail_pm; - } + camss->genpd_link = device_link_add(camss->dev, camss->genpd, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!camss->genpd_link) { + ret = -EINVAL; + goto fail_pm; } return 0; fail_pm: - for (--i ; i >= 0; i--) - dev_pm_domain_detach(camss->genpd[i], true); + dev_pm_domain_detach(camss->genpd, true); return ret; } @@ -1566,18 +1564,25 @@ static int camss_icc_get(struct camss *camss) return 0; } -static void camss_genpd_cleanup(struct camss *camss) +static void camss_genpd_subdevice_cleanup(struct camss *camss) { int i; + for (i = 0; i < camss->vfe_total_num; i++) + msm_vfe_genpd_cleanup(&camss->vfe[i]); +} + +static void camss_genpd_cleanup(struct camss *camss) +{ if (camss->genpd_num == 1) return; - if (camss->genpd_num > camss->res->vfe_num) - device_link_del(camss->genpd_link[camss->genpd_num - 1]); + camss_genpd_subdevice_cleanup(camss); - for (i = 0; i < camss->genpd_num; i++) - dev_pm_domain_detach(camss->genpd[i], true); + if (camss->genpd_link) + device_link_del(camss->genpd_link); + + dev_pm_domain_detach(camss->genpd, true); } /* diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index b854cff1774d..1ba824a2cb76 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -107,8 +107,8 @@ struct camss { struct vfe_device *vfe; atomic_t ref_count; int genpd_num; - struct device **genpd; - struct device_link **genpd_link; + struct device *genpd; + struct device_link *genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; const struct camss_resources *res; unsigned int vfe_total_num; From d89751c61279f692684fe82a416dffef7f243cbe Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 6 Dec 2023 13:25:00 +0100 Subject: [PATCH 2963/7721] media: qcom: camss: Add support for named power-domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now we use fixed indexes to assign power-domains, with a requirement for the TOP GDSC to come last in the list. Adding support for named power-domains means the declaration in the dtsi can come in any order. After this change we continue to support the old indexing - if a SoC resource declaration or the in-use dtb doesn't declare power-domain names we fall back to the default legacy indexing. From this point on though new SoC additions should contain named power-domains, eventually we will drop support for legacy indexing. Tested-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 24 +++++++++++++- drivers/media/platform/qcom/camss/camss.c | 31 +++++++++++++++---- drivers/media/platform/qcom/camss/camss.h | 2 ++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 60286dac60e0..b2f91c00acaf 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1380,7 +1380,29 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, if (!res->line_num) return -EINVAL; - if (res->has_pd) { + /* Power domain */ + + if (res->pd_name) { + vfe->genpd = dev_pm_domain_attach_by_name(camss->dev, + res->pd_name); + if (IS_ERR(vfe->genpd)) { + ret = PTR_ERR(vfe->genpd); + return ret; + } + } + + if (!vfe->genpd && res->has_pd) { + /* + * Legacy magic index. + * Requires + * power-domain = , + * , + * + * id must correspondng to the index of the VFE which must + * come before the TOP GDSC. VFE Lite has no individually + * collapasible domain which is why id < vfe_num is a valid + * check. + */ vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id); if (IS_ERR(vfe->genpd)) return PTR_ERR(vfe->genpd); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 35918cf837bd..8de0e9e8d34b 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1522,13 +1522,32 @@ static int camss_configure_pd(struct camss *camss) return 0; /* - * VFE power domains are in the beginning of the list, and while all - * power domains should be attached, only if TITAN_TOP power domain is - * found in the list, it should be linked over here. + * If a power-domain name is defined try to use it. + * It is possible we are running a new kernel with an old dtb so + * fallback to indexes even if a pd_name is defined but not found. */ - camss->genpd = dev_pm_domain_attach_by_id(camss->dev, camss->genpd_num - 1); - if (IS_ERR(camss->genpd)) { - ret = PTR_ERR(camss->genpd); + if (camss->res->pd_name) { + camss->genpd = dev_pm_domain_attach_by_name(camss->dev, + camss->res->pd_name); + if (IS_ERR(camss->genpd)) { + ret = PTR_ERR(camss->genpd); + goto fail_pm; + } + } + + if (!camss->genpd) { + /* + * Legacy magic index. TITAN_TOP GDSC must be the last + * item in the power-domain list. + */ + camss->genpd = dev_pm_domain_attach_by_id(camss->dev, + camss->genpd_num - 1); + } + if (IS_ERR_OR_NULL(camss->genpd)) { + if (!camss->genpd) + ret = -ENODEV; + else + ret = PTR_ERR(camss->genpd); goto fail_pm; } camss->genpd_link = device_link_add(camss->dev, camss->genpd, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 1ba824a2cb76..cd8186fe1797 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -48,6 +48,7 @@ struct camss_subdev_resources { u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; + char *pd_name; u8 line_num; bool has_pd; const void *ops; @@ -84,6 +85,7 @@ enum icc_count { struct camss_resources { enum camss_version version; + const char *pd_name; const struct camss_subdev_resources *csiphy_res; const struct camss_subdev_resources *csid_res; const struct camss_subdev_resources *ispif_res; From 6997278ae5f0ad09400750977ddc08aa5543ff86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Thu, 23 Nov 2023 17:03:05 +0000 Subject: [PATCH 2964/7721] media: qcom: camss: Flag VFE-lites to support more VFEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platforms such as SC7280 have three VFEs and two VFE-lites. Current code has hard-coded two as the maximum number of VFEs. Remove the hard-coded maximum number of VFEs to handle all possible combinations of VFEs and VFE-lites. Signed-off-by: Matti Lehtimäki Reviewed-by: Konrad Dybcio Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311200405.h6G4L9oe-lkp@intel.com Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-480.c | 33 +++++++++---------- drivers/media/platform/qcom/camss/camss-vfe.c | 5 +++ drivers/media/platform/qcom/camss/camss-vfe.h | 10 ++++++ drivers/media/platform/qcom/camss/camss.c | 26 +++++++-------- drivers/media/platform/qcom/camss/camss.h | 3 +- 5 files changed, 44 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 4652e8b4cff5..dc2735476c82 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -15,31 +15,28 @@ #include "camss.h" #include "camss-vfe.h" -/* VFE 2/3 are lite and have a different register layout */ -#define IS_LITE (vfe->id >= 2 ? 1 : 0) - #define VFE_HW_VERSION (0x00) -#define VFE_GLOBAL_RESET_CMD (IS_LITE ? 0x0c : 0x1c) -#define GLOBAL_RESET_HW_AND_REG (IS_LITE ? BIT(1) : BIT(0)) +#define VFE_GLOBAL_RESET_CMD (vfe_is_lite(vfe) ? 0x0c : 0x1c) +#define GLOBAL_RESET_HW_AND_REG (vfe_is_lite(vfe) ? BIT(1) : BIT(0)) -#define VFE_REG_UPDATE_CMD (IS_LITE ? 0x20 : 0x34) +#define VFE_REG_UPDATE_CMD (vfe_is_lite(vfe) ? 0x20 : 0x34) static inline int reg_update_rdi(struct vfe_device *vfe, int n) { - return IS_LITE ? BIT(n) : BIT(1 + (n)); + return vfe_is_lite(vfe) ? BIT(n) : BIT(1 + (n)); } #define REG_UPDATE_RDI reg_update_rdi -#define VFE_IRQ_CMD (IS_LITE ? 0x24 : 0x38) +#define VFE_IRQ_CMD (vfe_is_lite(vfe) ? 0x24 : 0x38) #define IRQ_CMD_GLOBAL_CLEAR BIT(0) -#define VFE_IRQ_MASK(n) ((IS_LITE ? 0x28 : 0x3c) + (n) * 4) -#define IRQ_MASK_0_RESET_ACK (IS_LITE ? BIT(17) : BIT(0)) -#define IRQ_MASK_0_BUS_TOP_IRQ (IS_LITE ? BIT(4) : BIT(7)) -#define VFE_IRQ_CLEAR(n) ((IS_LITE ? 0x34 : 0x48) + (n) * 4) -#define VFE_IRQ_STATUS(n) ((IS_LITE ? 0x40 : 0x54) + (n) * 4) +#define VFE_IRQ_MASK(n) ((vfe_is_lite(vfe) ? 0x28 : 0x3c) + (n) * 4) +#define IRQ_MASK_0_RESET_ACK (vfe_is_lite(vfe) ? BIT(17) : BIT(0)) +#define IRQ_MASK_0_BUS_TOP_IRQ (vfe_is_lite(vfe) ? BIT(4) : BIT(7)) +#define VFE_IRQ_CLEAR(n) ((vfe_is_lite(vfe) ? 0x34 : 0x48) + (n) * 4) +#define VFE_IRQ_STATUS(n) ((vfe_is_lite(vfe) ? 0x40 : 0x54) + (n) * 4) -#define BUS_REG_BASE (IS_LITE ? 0x1a00 : 0xaa00) +#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x1a00 : 0xaa00) #define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x08) #define WM_CGC_OVERRIDE_ALL (0x3FFFFFF) @@ -49,13 +46,13 @@ static inline int reg_update_rdi(struct vfe_device *vfe, int n) #define VFE_BUS_IRQ_MASK(n) (BUS_REG_BASE + 0x18 + (n) * 4) static inline int bus_irq_mask_0_rdi_rup(struct vfe_device *vfe, int n) { - return IS_LITE ? BIT(n) : BIT(3 + (n)); + return vfe_is_lite(vfe) ? BIT(n) : BIT(3 + (n)); } #define BUS_IRQ_MASK_0_RDI_RUP bus_irq_mask_0_rdi_rup static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n) { - return IS_LITE ? BIT(4 + (n)) : BIT(6 + (n)); + return vfe_is_lite(vfe) ? BIT(4 + (n)) : BIT(6 + (n)); } #define BUS_IRQ_MASK_0_COMP_DONE bus_irq_mask_0_comp_done @@ -90,8 +87,8 @@ static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n) /* for titan 480, each bus client is hardcoded to a specific path * and each bus client is part of a hardcoded "comp group" */ -#define RDI_WM(n) ((IS_LITE ? 0 : 23) + (n)) -#define RDI_COMP_GROUP(n) ((IS_LITE ? 0 : 11) + (n)) +#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0 : 23) + (n)) +#define RDI_COMP_GROUP(n) ((vfe_is_lite(vfe) ? 0 : 11) + (n)) #define MAX_VFE_OUTPUT_LINES 4 diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index b2f91c00acaf..2062be668f49 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1737,3 +1737,8 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe) media_entity_cleanup(&sd->entity); } } + +bool vfe_is_lite(struct vfe_device *vfe) +{ + return vfe->camss->res->vfe_res[vfe->id].is_lite; +} diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index cdbe59d8d437..0572c9b08e11 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -226,4 +226,14 @@ extern const struct vfe_hw_ops vfe_ops_480; int vfe_get(struct vfe_device *vfe); void vfe_put(struct vfe_device *vfe); +/* + * vfe_is_lite - Return if VFE is VFE lite. + * @vfe: VFE Device + * + * Some VFE lites have a different register layout. + * + * Return whether VFE is VFE lite + */ +bool vfe_is_lite(struct vfe_device *vfe); + #endif /* QC_MSM_CAMSS_VFE_H */ diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 8de0e9e8d34b..cdb9254cd8b4 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -706,6 +706,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 384000000 } }, .reg = { "vfe_lite" }, .interrupt = { "vfe_lite" }, + .is_lite = true, .line_num = 4, .ops = &vfe_ops_170 } @@ -886,6 +887,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe_lite0" }, .interrupt = { "vfe_lite0" }, + .is_lite = true, .line_num = 4, .ops = &vfe_ops_480 }, @@ -905,6 +907,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe_lite1" }, .interrupt = { "vfe_lite1" }, + .is_lite = true, .line_num = 4, .ops = &vfe_ops_480 }, @@ -1204,7 +1207,7 @@ static int camss_init_subdevices(struct camss *camss) } /* note: SM8250 requires VFE to be initialized before CSID */ - for (i = 0; i < camss->vfe_total_num; i++) { + for (i = 0; i < camss->res->vfe_num; i++) { ret = msm_vfe_subdev_init(camss, &camss->vfe[i], &res->vfe_res[i], i); if (ret < 0) { @@ -1276,7 +1279,7 @@ static int camss_register_entities(struct camss *camss) goto err_reg_ispif; } - for (i = 0; i < camss->vfe_total_num; i++) { + for (i = 0; i < camss->res->vfe_num; i++) { ret = msm_vfe_register_entities(&camss->vfe[i], &camss->v4l2_dev); if (ret < 0) { @@ -1348,7 +1351,7 @@ static int camss_register_entities(struct camss *camss) } } else { for (i = 0; i < camss->res->csid_num; i++) - for (k = 0; k < camss->vfe_total_num; k++) + for (k = 0; k < camss->res->vfe_num; k++) for (j = 0; j < camss->vfe[k].line_num; j++) { struct v4l2_subdev *csid = &camss->csid[i].subdev; struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; @@ -1372,7 +1375,7 @@ static int camss_register_entities(struct camss *camss) return 0; err_link: - i = camss->vfe_total_num; + i = camss->res->vfe_num; err_reg_vfe: for (i--; i >= 0; i--) msm_vfe_unregister_entities(&camss->vfe[i]); @@ -1411,7 +1414,7 @@ static void camss_unregister_entities(struct camss *camss) msm_ispif_unregister_entities(camss->ispif); - for (i = 0; i < camss->vfe_total_num; i++) + for (i = 0; i < camss->res->vfe_num; i++) msm_vfe_unregister_entities(&camss->vfe[i]); } @@ -1509,7 +1512,7 @@ static int camss_configure_pd(struct camss *camss) return 0; /* count the # of VFEs which have flagged power-domain */ - for (vfepd_num = i = 0; i < camss->vfe_total_num; i++) { + for (vfepd_num = i = 0; i < camss->res->vfe_num; i++) { if (res->vfe_res[i].has_pd) vfepd_num++; } @@ -1587,7 +1590,7 @@ static void camss_genpd_subdevice_cleanup(struct camss *camss) { int i; - for (i = 0; i < camss->vfe_total_num; i++) + for (i = 0; i < camss->res->vfe_num; i++) msm_vfe_genpd_cleanup(&camss->vfe[i]); } @@ -1644,8 +1647,7 @@ static int camss_probe(struct platform_device *pdev) return -ENOMEM; } - camss->vfe_total_num = camss->res->vfe_num + camss->res->vfe_lite_num; - camss->vfe = devm_kcalloc(dev, camss->vfe_total_num, + camss->vfe = devm_kcalloc(dev, camss->res->vfe_num, sizeof(*camss->vfe), GFP_KERNEL); if (!camss->vfe) return -ENOMEM; @@ -1803,8 +1805,7 @@ static const struct camss_resources sdm845_resources = { .vfe_res = vfe_res_845, .csiphy_num = ARRAY_SIZE(csiphy_res_845), .csid_num = ARRAY_SIZE(csid_res_845), - .vfe_num = 2, - .vfe_lite_num = 1, + .vfe_num = ARRAY_SIZE(vfe_res_845), }; static const struct camss_resources sm8250_resources = { @@ -1816,8 +1817,7 @@ static const struct camss_resources sm8250_resources = { .icc_path_num = ARRAY_SIZE(icc_res_sm8250), .csiphy_num = ARRAY_SIZE(csiphy_res_8250), .csid_num = ARRAY_SIZE(csid_res_8250), - .vfe_num = 2, - .vfe_lite_num = 2, + .vfe_num = ARRAY_SIZE(vfe_res_8250), }; static const struct of_device_id camss_dt_match[] = { diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index cd8186fe1797..a0c2dcc779f0 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -51,6 +51,7 @@ struct camss_subdev_resources { char *pd_name; u8 line_num; bool has_pd; + bool is_lite; const void *ops; }; @@ -95,7 +96,6 @@ struct camss_resources { const unsigned int csiphy_num; const unsigned int csid_num; const unsigned int vfe_num; - const unsigned int vfe_lite_num; }; struct camss { @@ -113,7 +113,6 @@ struct camss { struct device_link *genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; const struct camss_resources *res; - unsigned int vfe_total_num; }; struct camss_camera_interface { From 801ca0e7f9be141ae8a7b17e47d6af588768ae49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Thu, 23 Nov 2023 17:03:06 +0000 Subject: [PATCH 2965/7721] media: qcom: camss: Flag CSID-lites to support more CSIDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platforms such as SC7280 have 3 CSIDs and 2 CSID-lites but current code has hardcoded 2 as the maximum number of CSIDs. Remove the hardcoded maximum number of VFEs to handle all possible combinations of CSIDs and CSID-lites. Signed-off-by: Matti Lehtimäki Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Hans Verkuil --- .../platform/qcom/camss/camss-csid-gen2.c | 31 +++++++++---------- .../media/platform/qcom/camss/camss-csid.c | 5 +++ .../media/platform/qcom/camss/camss-csid.h | 7 +++++ drivers/media/platform/qcom/camss/camss.c | 3 ++ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 05ff5fa8095a..b11de4797cca 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -21,7 +21,6 @@ * interface support. As a result of that it has an * alternate register layout. */ -#define IS_LITE (csid->id >= 2 ? 1 : 0) #define CSID_HW_VERSION 0x0 #define HW_VERSION_STEPPING 0 @@ -35,13 +34,13 @@ #define CSID_CSI2_RX_IRQ_MASK 0x24 #define CSID_CSI2_RX_IRQ_CLEAR 0x28 -#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((IS_LITE ? 0x30 : 0x40) \ +#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((csid_is_lite(csid) ? 0x30 : 0x40) \ + 0x10 * (rdi)) -#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((IS_LITE ? 0x34 : 0x44) \ +#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((csid_is_lite(csid) ? 0x34 : 0x44) \ + 0x10 * (rdi)) -#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((IS_LITE ? 0x38 : 0x48) \ +#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((csid_is_lite(csid) ? 0x38 : 0x48) \ + 0x10 * (rdi)) -#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((IS_LITE ? 0x3C : 0x4C) \ +#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((csid_is_lite(csid) ? 0x3C : 0x4C) \ + 0x10 * (rdi)) #define CSID_TOP_IRQ_STATUS 0x70 @@ -73,7 +72,7 @@ #define CGC_MODE_DYNAMIC_GATING 0 #define CGC_MODE_ALWAYS_ON 1 -#define CSID_RDI_CFG0(rdi) ((IS_LITE ? 0x200 : 0x300) \ +#define CSID_RDI_CFG0(rdi) ((csid_is_lite(csid) ? 0x200 : 0x300) \ + 0x100 * (rdi)) #define RDI_CFG0_BYTE_CNTR_EN 0 #define RDI_CFG0_FORMAT_MEASURE_EN 1 @@ -98,32 +97,32 @@ #define RDI_CFG0_PACKING_FORMAT 30 #define RDI_CFG0_ENABLE 31 -#define CSID_RDI_CFG1(rdi) ((IS_LITE ? 0x204 : 0x304)\ +#define CSID_RDI_CFG1(rdi) ((csid_is_lite(csid) ? 0x204 : 0x304)\ + 0x100 * (rdi)) #define RDI_CFG1_TIMESTAMP_STB_SEL 0 -#define CSID_RDI_CTRL(rdi) ((IS_LITE ? 0x208 : 0x308)\ +#define CSID_RDI_CTRL(rdi) ((csid_is_lite(csid) ? 0x208 : 0x308)\ + 0x100 * (rdi)) #define RDI_CTRL_HALT_CMD 0 #define HALT_CMD_HALT_AT_FRAME_BOUNDARY 0 #define HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 #define RDI_CTRL_HALT_MODE 2 -#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((IS_LITE ? 0x20C : 0x30C)\ +#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x20C : 0x30C)\ + 0x100 * (rdi)) -#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((IS_LITE ? 0x210 : 0x310)\ +#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x210 : 0x310)\ + 0x100 * (rdi)) -#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((IS_LITE ? 0x214 : 0x314)\ +#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((csid_is_lite(csid) ? 0x214 : 0x314)\ + 0x100 * (rdi)) -#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((IS_LITE ? 0x218 : 0x318)\ +#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((csid_is_lite(csid) ? 0x218 : 0x318)\ + 0x100 * (rdi)) -#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((IS_LITE ? 0x224 : 0x324)\ +#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x224 : 0x324)\ + 0x100 * (rdi)) -#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((IS_LITE ? 0x228 : 0x328)\ +#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x228 : 0x328)\ + 0x100 * (rdi)) -#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((IS_LITE ? 0x22C : 0x32C)\ +#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x22C : 0x32C)\ + 0x100 * (rdi)) -#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((IS_LITE ? 0x230 : 0x330)\ +#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x230 : 0x330)\ + 0x100 * (rdi)) #define CSID_TPG_CTRL 0x600 diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index bbe253f7571f..eb27d69e89a1 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -896,3 +896,8 @@ void msm_csid_unregister_entity(struct csid_device *csid) media_entity_cleanup(&csid->subdev.entity); v4l2_ctrl_handler_free(&csid->ctrls); } + +inline bool csid_is_lite(struct csid_device *csid) +{ + return csid->camss->res->csid_res[csid->id].is_lite; +} diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 30d94eb2eb04..fddccb69da13 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -215,5 +215,12 @@ extern const struct csid_hw_ops csid_ops_4_1; extern const struct csid_hw_ops csid_ops_4_7; extern const struct csid_hw_ops csid_ops_gen2; +/* + * csid_is_lite - Check if CSID is CSID lite. + * @csid: CSID Device + * + * Return whether CSID is CSID lite + */ +bool csid_is_lite(struct csid_device *csid); #endif /* QC_MSM_CAMSS_CSID_H */ diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index cdb9254cd8b4..6fc291f40b39 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -638,6 +638,7 @@ static const struct camss_subdev_resources csid_res_845[] = { { 384000000 } }, .reg = { "csid2" }, .interrupt = { "csid2" }, + .is_lite = true, .ops = &csid_ops_gen2 } }; @@ -812,6 +813,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 0 } }, .reg = { "csid2" }, .interrupt = { "csid2" }, + .is_lite = true, .ops = &csid_ops_gen2 }, /* CSID3 */ @@ -824,6 +826,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 0 } }, .reg = { "csid3" }, .interrupt = { "csid3" }, + .is_lite = true, .ops = &csid_ops_gen2 } }; From 8016943b5947cd485078e23899945c51e818aa63 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 23 Nov 2023 17:03:07 +0000 Subject: [PATCH 2966/7721] media: qcom: camss: Add sm8250 named power-domain support Declare power-domain names "top", "ife0" and "ife1" eponymously for the power-domains TITAN_TOP_GDSC, IFE_0_GDSC and IFE_1_GDSC respectively. Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 6fc291f40b39..58f4be660290 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -849,6 +849,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, + .pd_name = "ife0", .line_num = 3, .has_pd = true, .ops = &vfe_ops_480 @@ -870,6 +871,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe1" }, .interrupt = { "vfe1" }, + .pd_name = "ife1", .line_num = 3, .has_pd = true, .ops = &vfe_ops_480 @@ -1813,6 +1815,7 @@ static const struct camss_resources sdm845_resources = { static const struct camss_resources sm8250_resources = { .version = CAMSS_8250, + .pd_name = "top", .csiphy_res = csiphy_res_8250, .csid_res = csid_res_8250, .vfe_res = vfe_res_8250, From 9e7dc39260edac180c206bb6149595a40eabae3e Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:22 +0200 Subject: [PATCH 2967/7721] media: rockchip: rga: fix swizzling for RGB formats When using 32 bit RGB formats, the RGA on the rk3568 produces wrong colors as the wrong color channels are read or written. The reason is that the format description for the channel swizzeling is wrong and the wrong bits are configured. For example, when converting ARGB32 to NV12, the alpha channel is used as blue channel.. This doesn't happen if the color format is the same on both sides. Fix the color_swap settings of the formats to correctly handle 32 bit RGB formats. For RGA_COLOR_FMT_XBGR8888, the RGA_COLOR_ALPHA_SWAP bit doesn't have an effect. Thus, it isn't possible to handle the V4L2_PIX_FMT_XRGB32. Thus, it is removed from the list of supported formats. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index f1c532a5802a..25f5b5eebf13 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -184,25 +184,16 @@ static int rga_setup_ctrls(struct rga_ctx *ctx) static struct rga_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB32, - .color_swap = RGA_COLOR_RB_SWAP, + .color_swap = RGA_COLOR_ALPHA_SWAP, .hw_format = RGA_COLOR_FMT_ABGR8888, .depth = 32, .uv_factor = 1, .y_div = 1, .x_div = 1, }, - { - .fourcc = V4L2_PIX_FMT_XRGB32, - .color_swap = RGA_COLOR_RB_SWAP, - .hw_format = RGA_COLOR_FMT_XBGR8888, - .depth = 32, - .uv_factor = 1, - .y_div = 1, - .x_div = 1, - }, { .fourcc = V4L2_PIX_FMT_ABGR32, - .color_swap = RGA_COLOR_ALPHA_SWAP, + .color_swap = RGA_COLOR_RB_SWAP, .hw_format = RGA_COLOR_FMT_ABGR8888, .depth = 32, .uv_factor = 1, @@ -211,7 +202,7 @@ static struct rga_fmt formats[] = { }, { .fourcc = V4L2_PIX_FMT_XBGR32, - .color_swap = RGA_COLOR_ALPHA_SWAP, + .color_swap = RGA_COLOR_RB_SWAP, .hw_format = RGA_COLOR_FMT_XBGR8888, .depth = 32, .uv_factor = 1, From 77f2e2b255ce05b9d63566e5290ac66c49913abd Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:23 +0200 Subject: [PATCH 2968/7721] media: rockchip: rga: extract helper to fill descriptors The IOMMU of the RGA is programmed with a list of DMA descriptors that contain an 32 bit address per 4k page in the video buffers. The address in the descriptor points to the start address of the page. Introduce 'struct rga_dma_desc' to make the handling of the DMA descriptors explicit instead of hiding them behind standard types. While at it, use provided helpers for iterating the sg_table instead of manually calculating the DMA addresses. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga-buf.c | 43 ++++++++++--------- drivers/media/platform/rockchip/rga/rga.c | 4 +- drivers/media/platform/rockchip/rga/rga.h | 8 +++- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 81508ed5abf3..fc3f38f6b5e1 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -15,6 +16,23 @@ #include "rga-hw.h" #include "rga.h" +static size_t fill_descriptors(struct rga_dma_desc *desc, struct sg_table *sgt) +{ + struct sg_dma_page_iter iter; + struct rga_dma_desc *tmp = desc; + size_t n_desc = 0; + dma_addr_t addr; + + for_each_sgtable_dma_page(sgt, &iter, 0) { + addr = sg_page_iter_dma_address(&iter); + tmp->addr = lower_32_bits(addr); + tmp++; + n_desc++; + } + + return n_desc; +} + static int rga_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, @@ -114,11 +132,8 @@ void rga_buf_map(struct vb2_buffer *vb) { struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct rockchip_rga *rga = ctx->rga; - struct sg_table *sgt; - struct scatterlist *sgl; - unsigned int *pages; - unsigned int address, len, i, p; - unsigned int mapped_size = 0; + struct rga_dma_desc *pages; + size_t n_desc = 0; if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) pages = rga->src_mmu_pages; @@ -126,23 +141,9 @@ void rga_buf_map(struct vb2_buffer *vb) pages = rga->dst_mmu_pages; /* Create local MMU table for RGA */ - sgt = vb2_plane_cookie(vb, 0); - - for_each_sg(sgt->sgl, sgl, sgt->nents, i) { - len = sg_dma_len(sgl) >> PAGE_SHIFT; - address = sg_phys(sgl); - - for (p = 0; p < len; p++) { - dma_addr_t phys = address + - ((dma_addr_t)p << PAGE_SHIFT); - - pages[mapped_size + p] = phys; - } - - mapped_size += len; - } + n_desc = fill_descriptors(pages, vb2_dma_sg_plane_desc(vb, 0)); /* sync local MMU table for RGA */ dma_sync_single_for_device(rga->dev, virt_to_phys(pages), - 8 * PAGE_SIZE, DMA_BIDIRECTIONAL); + n_desc * sizeof(*pages), DMA_BIDIRECTIONAL); } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 25f5b5eebf13..36d7f255af90 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -873,13 +873,13 @@ static int rga_probe(struct platform_device *pdev) } rga->src_mmu_pages = - (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + (struct rga_dma_desc *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); if (!rga->src_mmu_pages) { ret = -ENOMEM; goto free_dma; } rga->dst_mmu_pages = - (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + (struct rga_dma_desc *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); if (!rga->dst_mmu_pages) { ret = -ENOMEM; goto free_src_pages; diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index 5fa9d2f366dc..22f7da28ac51 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -40,6 +40,10 @@ struct rga_frame { u32 size; }; +struct rga_dma_desc { + u32 addr; +}; + struct rockchip_rga_version { u32 major; u32 minor; @@ -81,8 +85,8 @@ struct rockchip_rga { struct rga_ctx *curr; dma_addr_t cmdbuf_phy; void *cmdbuf_virt; - unsigned int *src_mmu_pages; - unsigned int *dst_mmu_pages; + struct rga_dma_desc *src_mmu_pages; + struct rga_dma_desc *dst_mmu_pages; }; struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type); From 6040702ade234c8212dcfdef85e2f5549aa2f0f5 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:24 +0200 Subject: [PATCH 2969/7721] media: rockchip: rga: allocate DMA descriptors per buffer The RGA driver allocates two buffers for the DMA descriptors of the input and output buffers. Whenever a new job is processed, the descriptor list is updated for the current buffers. By updating the descriptor list during buf_prepare, it is possible to correctly fail DMABUF imports if the buffers that shall be imported are not within the 32 bit address range that can be addressed by the RGA. Managing the DMA descriptor list with the buffer also makes it easier to track the buffer mapping and the plane offsets into this mapping. The cost is that the driver now requires DMA coherent memory per buffer for the descriptor list. However, the size scales with the size of the video buffers and is not allocated if the RGA is not used. While at it, use dma_alloc_coherent to allocate the descriptors and get rid of the virt_to_phys calls to get the physical addresses. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga-buf.c | 62 ++++++++++++------- drivers/media/platform/rockchip/rga/rga-hw.c | 26 ++++---- drivers/media/platform/rockchip/rga/rga.c | 31 ++-------- drivers/media/platform/rockchip/rga/rga.h | 21 +++++-- 4 files changed, 74 insertions(+), 66 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index fc3f38f6b5e1..ff36efade060 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -53,8 +53,31 @@ rga_queue_setup(struct vb2_queue *vq, return 0; } +static int rga_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rga_vb_buffer *rbuf = vb_to_rga(vbuf); + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rockchip_rga *rga = ctx->rga; + struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); + size_t n_desc = 0; + + n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE); + + rbuf->n_desc = n_desc; + rbuf->dma_desc = dma_alloc_coherent(rga->dev, + rbuf->n_desc * sizeof(*rbuf->dma_desc), + &rbuf->dma_desc_pa, GFP_KERNEL); + if (!rbuf->dma_desc) + return -ENOMEM; + + return 0; +} + static int rga_buf_prepare(struct vb2_buffer *vb) { + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rga_vb_buffer *rbuf = vb_to_rga(vbuf); struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); @@ -63,6 +86,9 @@ static int rga_buf_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(vb, 0, f->size); + /* Create local MMU table for RGA */ + fill_descriptors(rbuf->dma_desc, vb2_dma_sg_plane_desc(vb, 0)); + return 0; } @@ -74,6 +100,17 @@ static void rga_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } +static void rga_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rga_vb_buffer *rbuf = vb_to_rga(vbuf); + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rockchip_rga *rga = ctx->rga; + + dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc), + rbuf->dma_desc, rbuf->dma_desc_pa); +} + static void rga_buf_return_buffers(struct vb2_queue *q, enum vb2_buffer_state state) { @@ -117,33 +154,12 @@ static void rga_buf_stop_streaming(struct vb2_queue *q) const struct vb2_ops rga_qops = { .queue_setup = rga_queue_setup, + .buf_init = rga_buf_init, .buf_prepare = rga_buf_prepare, .buf_queue = rga_buf_queue, + .buf_cleanup = rga_buf_cleanup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, .start_streaming = rga_buf_start_streaming, .stop_streaming = rga_buf_stop_streaming, }; - -/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API. - * We use it more like a scatter-gather list. - */ -void rga_buf_map(struct vb2_buffer *vb) -{ - struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct rockchip_rga *rga = ctx->rga; - struct rga_dma_desc *pages; - size_t n_desc = 0; - - if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pages = rga->src_mmu_pages; - else - pages = rga->dst_mmu_pages; - - /* Create local MMU table for RGA */ - n_desc = fill_descriptors(pages, vb2_dma_sg_plane_desc(vb, 0)); - - /* sync local MMU table for RGA */ - dma_sync_single_for_device(rga->dev, virt_to_phys(pages), - n_desc * sizeof(*pages), DMA_BIDIRECTIONAL); -} diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index aaa96f256356..b391d97d4632 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -119,40 +119,40 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct return NULL; } -static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages) +static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr) { struct rockchip_rga *rga = ctx->rga; u32 *dest = rga->cmdbuf_virt; unsigned int reg; reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; - dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + dest[reg >> 2] = dma_addr >> 4; reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; dest[reg >> 2] |= 0x7; } -static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages) +static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr) { struct rockchip_rga *rga = ctx->rga; u32 *dest = rga->cmdbuf_virt; unsigned int reg; reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; - dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + dest[reg >> 2] = dma_addr >> 4; reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; dest[reg >> 2] |= 0x7 << 4; } -static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages) +static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr) { struct rockchip_rga *rga = ctx->rga; u32 *dest = rga->cmdbuf_virt; unsigned int reg; reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; - dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + dest[reg >> 2] = dma_addr >> 4; reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; dest[reg >> 2] |= 0x7 << 8; @@ -375,20 +375,21 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx) dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; } -static void rga_cmd_set(struct rga_ctx *ctx) +static void rga_cmd_set(struct rga_ctx *ctx, + struct rga_vb_buffer *src, struct rga_vb_buffer *dst) { struct rockchip_rga *rga = ctx->rga; memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4); - rga_cmd_set_src_addr(ctx, rga->src_mmu_pages); + rga_cmd_set_src_addr(ctx, src->dma_desc_pa); /* * Due to hardware bug, * src1 mmu also should be configured when using alpha blending. */ - rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages); + rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa); - rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages); + rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa); rga_cmd_set_mode(ctx); rga_cmd_set_trans_info(ctx); @@ -400,11 +401,12 @@ static void rga_cmd_set(struct rga_ctx *ctx) PAGE_SIZE, DMA_BIDIRECTIONAL); } -void rga_hw_start(struct rockchip_rga *rga) +void rga_hw_start(struct rockchip_rga *rga, + struct rga_vb_buffer *src, struct rga_vb_buffer *dst) { struct rga_ctx *ctx = rga->curr; - rga_cmd_set(ctx); + rga_cmd_set(ctx, src, dst); rga_write(rga, RGA_SYS_CTRL, 0x00); diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 36d7f255af90..f18fccc7b204 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -45,10 +45,7 @@ static void device_run(void *prv) src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - rga_buf_map(&src->vb2_buf); - rga_buf_map(&dst->vb2_buf); - - rga_hw_start(rga); + rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst)); spin_unlock_irqrestore(&rga->ctrl_lock, flags); } @@ -101,7 +98,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) src_vq->drv_priv = ctx; src_vq->ops = &rga_qops; src_vq->mem_ops = &vb2_dma_sg_memops; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->buf_struct_size = sizeof(struct rga_vb_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->rga->mutex; src_vq->dev = ctx->rga->v4l2_dev.dev; @@ -115,7 +112,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) dst_vq->drv_priv = ctx; dst_vq->ops = &rga_qops; dst_vq->mem_ops = &vb2_dma_sg_memops; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer); dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->rga->mutex; dst_vq->dev = ctx->rga->v4l2_dev.dev; @@ -872,26 +869,13 @@ static int rga_probe(struct platform_device *pdev) goto rel_m2m; } - rga->src_mmu_pages = - (struct rga_dma_desc *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); - if (!rga->src_mmu_pages) { - ret = -ENOMEM; - goto free_dma; - } - rga->dst_mmu_pages = - (struct rga_dma_desc *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); - if (!rga->dst_mmu_pages) { - ret = -ENOMEM; - goto free_src_pages; - } - def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; def_frame.size = def_frame.stride * def_frame.height; ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); - goto free_dst_pages; + goto free_dma; } v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n", @@ -899,10 +883,6 @@ static int rga_probe(struct platform_device *pdev) return 0; -free_dst_pages: - free_pages((unsigned long)rga->dst_mmu_pages, 3); -free_src_pages: - free_pages((unsigned long)rga->src_mmu_pages, 3); free_dma: dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); @@ -925,9 +905,6 @@ static void rga_remove(struct platform_device *pdev) dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); - free_pages((unsigned long)rga->src_mmu_pages, 3); - free_pages((unsigned long)rga->dst_mmu_pages, 3); - v4l2_info(&rga->v4l2_dev, "Removing\n"); v4l2_m2m_release(rga->m2m_dev); diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index 22f7da28ac51..678f0f627bdd 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -85,15 +85,27 @@ struct rockchip_rga { struct rga_ctx *curr; dma_addr_t cmdbuf_phy; void *cmdbuf_virt; - struct rga_dma_desc *src_mmu_pages; - struct rga_dma_desc *dst_mmu_pages; }; +struct rga_vb_buffer { + struct vb2_v4l2_buffer vb_buf; + struct list_head queue; + + /* RGA MMU mapping for this buffer */ + struct rga_dma_desc *dma_desc; + dma_addr_t dma_desc_pa; + size_t n_desc; +}; + +static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct rga_vb_buffer, vb_buf); +} + struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type); /* RGA Buffers Manage */ extern const struct vb2_ops rga_qops; -void rga_buf_map(struct vb2_buffer *vb); /* RGA Hardware */ static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value) @@ -114,6 +126,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask) rga_write(rga, reg, temp); }; -void rga_hw_start(struct rockchip_rga *rga); +void rga_hw_start(struct rockchip_rga *rga, + struct rga_vb_buffer *src, struct rga_vb_buffer *dst); #endif From 558c248f930e6829bd7af160d4a9451a15dbee41 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:25 +0200 Subject: [PATCH 2970/7721] media: rockchip: rga: split src and dst buffer setup Split the register setup for the source and destination video buffers into separate functions. This is a cleanup to make the code more readable by separating the offset calculation for the different buffers and prepares the driver for using pre-calculated offsets of planes. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga-hw.c | 110 +++++++++++++------ 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index b391d97d4632..836ec7721b21 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -163,7 +163,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) struct rockchip_rga *rga = ctx->rga; u32 *dest = rga->cmdbuf_virt; unsigned int scale_dst_w, scale_dst_h; - unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y; + unsigned int src_h, src_w, dst_h, dst_w; union rga_src_info src_info; union rga_dst_info dst_info; union rga_src_x_factor x_factor; @@ -173,18 +173,10 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) union rga_dst_vir_info dst_vir_info; union rga_dst_act_info dst_act_info; - struct rga_addr_offset *dst_offset; - struct rga_corners_addr_offset offsets; - struct rga_corners_addr_offset src_offsets; - src_h = ctx->in.crop.height; src_w = ctx->in.crop.width; - src_x = ctx->in.crop.left; - src_y = ctx->in.crop.top; dst_h = ctx->out.crop.height; dst_w = ctx->out.crop.width; - dst_x = ctx->out.crop.left; - dst_y = ctx->out.crop.top; src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2]; dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2]; @@ -312,26 +304,6 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) dst_act_info.data.act_height = dst_h - 1; dst_act_info.data.act_width = dst_w - 1; - /* - * Calculate the source framebuffer base address with offset pixel. - */ - src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, - src_w, src_h); - - /* - * Configure the dest framebuffer base address with pixel offset. - */ - offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); - dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode, - src_info.data.mir_mode); - - dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = - src_offsets.left_top.y_off; - dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = - src_offsets.left_top.u_off; - dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = - src_offsets.left_top.v_off; - dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val; dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val; dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val; @@ -339,17 +311,85 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val; + dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val; + dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val; + + dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; +} + +static void rga_cmd_set_src_info(struct rga_ctx *ctx) +{ + struct rga_corners_addr_offset src_offsets; + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int src_h, src_w, src_x, src_y; + + src_h = ctx->in.crop.height; + src_w = ctx->in.crop.width; + src_x = ctx->in.crop.left; + src_y = ctx->in.crop.top; + + /* + * Calculate the source framebuffer base address with offset pixel. + */ + src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, + src_w, src_h); + + dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.y_off; + dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.u_off; + dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.v_off; +} + +static void rga_cmd_set_dst_info(struct rga_ctx *ctx) +{ + struct rga_addr_offset *dst_offset; + struct rga_corners_addr_offset offsets; + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int dst_h, dst_w, dst_x, dst_y; + unsigned int mir_mode = 0; + unsigned int rot_mode = 0; + + dst_h = ctx->out.crop.height; + dst_w = ctx->out.crop.width; + dst_x = ctx->out.crop.left; + dst_y = ctx->out.crop.top; + + if (ctx->vflip) + mir_mode |= RGA_SRC_MIRR_MODE_X; + if (ctx->hflip) + mir_mode |= RGA_SRC_MIRR_MODE_Y; + + switch (ctx->rotate) { + case 90: + rot_mode = RGA_SRC_ROT_MODE_90_DEGREE; + break; + case 180: + rot_mode = RGA_SRC_ROT_MODE_180_DEGREE; + break; + case 270: + rot_mode = RGA_SRC_ROT_MODE_270_DEGREE; + break; + default: + rot_mode = RGA_SRC_ROT_MODE_0_DEGREE; + break; + } + + /* + * Configure the dest framebuffer base address with pixel offset. + */ + offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); + dst_offset = rga_lookup_draw_pos(&offsets, mir_mode, rot_mode); + dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = dst_offset->y_off; dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = dst_offset->u_off; dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = dst_offset->v_off; - - dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val; - dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val; - - dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; } static void rga_cmd_set_mode(struct rga_ctx *ctx) @@ -392,6 +432,8 @@ static void rga_cmd_set(struct rga_ctx *ctx, rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa); rga_cmd_set_mode(ctx); + rga_cmd_set_src_info(ctx); + rga_cmd_set_dst_info(ctx); rga_cmd_set_trans_info(ctx); rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy); From 25783e2a984eadd7718f4fcdf1d82ee7e088d52d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:26 +0200 Subject: [PATCH 2971/7721] media: rockchip: rga: pre-calculate plane offsets Calculate the plane offsets and store them with the video buffer while creating the buffer mapping. This allows the driver to more freely handle the memory of the DMA mapping as the offsets and the mapping can be kept in sync. The driver still has to update the offsets to respect the configured cropping and rotation, but this calculation is now separated from the calculation of the plane offsets. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga-buf.c | 16 +++++++++ drivers/media/platform/rockchip/rga/rga-hw.c | 36 ++++++++----------- drivers/media/platform/rockchip/rga/rga.h | 9 +++++ 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index ff36efade060..d6774a844d9b 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -74,6 +74,18 @@ static int rga_buf_init(struct vb2_buffer *vb) return 0; } +static int get_plane_offset(struct rga_frame *f, int plane) +{ + if (plane == 0) + return 0; + if (plane == 1) + return f->width * f->height; + if (plane == 2) + return f->width * f->height + (f->width * f->height / f->fmt->uv_factor); + + return -EINVAL; +} + static int rga_buf_prepare(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -89,6 +101,10 @@ static int rga_buf_prepare(struct vb2_buffer *vb) /* Create local MMU table for RGA */ fill_descriptors(rbuf->dma_desc, vb2_dma_sg_plane_desc(vb, 0)); + rbuf->offset.y_off = get_plane_offset(f, 0); + rbuf->offset.u_off = get_plane_offset(f, 1); + rbuf->offset.v_off = get_plane_offset(f, 2); + return 0; } diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index 836ec7721b21..11c3d7234757 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -16,12 +16,6 @@ enum e_rga_start_pos { RB = 3, }; -struct rga_addr_offset { - unsigned int y_off; - unsigned int u_off; - unsigned int v_off; -}; - struct rga_corners_addr_offset { struct rga_addr_offset left_top; struct rga_addr_offset right_top; @@ -43,13 +37,13 @@ static unsigned int rga_get_scaling(unsigned int src, unsigned int dst) } static struct rga_corners_addr_offset -rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y, - unsigned int w, unsigned int h) +rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset, + unsigned int x, unsigned int y, unsigned int w, unsigned int h) { struct rga_corners_addr_offset offsets; struct rga_addr_offset *lt, *lb, *rt, *rb; unsigned int x_div = 0, - y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0; + y_div = 0, uv_stride = 0, pixel_width = 0; lt = &offsets.left_top; lb = &offsets.left_bottom; @@ -58,14 +52,12 @@ rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y, x_div = frm->fmt->x_div; y_div = frm->fmt->y_div; - uv_factor = frm->fmt->uv_factor; uv_stride = frm->stride / x_div; pixel_width = frm->stride / frm->width; - lt->y_off = y * frm->stride + x * pixel_width; - lt->u_off = - frm->width * frm->height + (y / y_div) * uv_stride + x / x_div; - lt->v_off = lt->u_off + frm->width * frm->height / uv_factor; + lt->y_off = offset->y_off + y * frm->stride + x * pixel_width; + lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div; + lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div; lb->y_off = lt->y_off + (h - 1) * frm->stride; lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride; @@ -317,7 +309,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; } -static void rga_cmd_set_src_info(struct rga_ctx *ctx) +static void rga_cmd_set_src_info(struct rga_ctx *ctx, + struct rga_addr_offset *offset) { struct rga_corners_addr_offset src_offsets; struct rockchip_rga *rga = ctx->rga; @@ -332,8 +325,8 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx) /* * Calculate the source framebuffer base address with offset pixel. */ - src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, - src_w, src_h); + src_offsets = rga_get_addr_offset(&ctx->in, offset, + src_x, src_y, src_w, src_h); dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = src_offsets.left_top.y_off; @@ -343,7 +336,8 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx) src_offsets.left_top.v_off; } -static void rga_cmd_set_dst_info(struct rga_ctx *ctx) +static void rga_cmd_set_dst_info(struct rga_ctx *ctx, + struct rga_addr_offset *offset) { struct rga_addr_offset *dst_offset; struct rga_corners_addr_offset offsets; @@ -381,7 +375,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx) /* * Configure the dest framebuffer base address with pixel offset. */ - offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); + offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h); dst_offset = rga_lookup_draw_pos(&offsets, mir_mode, rot_mode); dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = @@ -432,8 +426,8 @@ static void rga_cmd_set(struct rga_ctx *ctx, rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa); rga_cmd_set_mode(ctx); - rga_cmd_set_src_info(ctx); - rga_cmd_set_dst_info(ctx); + rga_cmd_set_src_info(ctx, &src->offset); + rga_cmd_set_dst_info(ctx, &dst->offset); rga_cmd_set_trans_info(ctx); rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy); diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index 678f0f627bdd..f3953a07d9e7 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -87,6 +87,12 @@ struct rockchip_rga { void *cmdbuf_virt; }; +struct rga_addr_offset { + unsigned int y_off; + unsigned int u_off; + unsigned int v_off; +}; + struct rga_vb_buffer { struct vb2_v4l2_buffer vb_buf; struct list_head queue; @@ -95,6 +101,9 @@ struct rga_vb_buffer { struct rga_dma_desc *dma_desc; dma_addr_t dma_desc_pa; size_t n_desc; + + /* Plane offsets of this buffer into the mapping */ + struct rga_addr_offset offset; }; static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb) From ec9ef8dda2a24ce1c13904f0d46867c0aa6b4ee7 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:27 +0200 Subject: [PATCH 2972/7721] media: rockchip: rga: set dma mask to 32 bits The RGA DMA descriptor list contains only 32-bit addresses. Set the dma_mask to only allocate memory that is addressable by the descriptors. This prevents errors when preparing vb2 buffers that were allocated by the RGA. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index f18fccc7b204..ea566c11734a 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -98,6 +98,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) src_vq->drv_priv = ctx; src_vq->ops = &rga_qops; src_vq->mem_ops = &vb2_dma_sg_memops; + dst_vq->gfp_flags = __GFP_DMA32; src_vq->buf_struct_size = sizeof(struct rga_vb_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->rga->mutex; @@ -112,6 +113,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) dst_vq->drv_priv = ctx; dst_vq->ops = &rga_qops; dst_vq->mem_ops = &vb2_dma_sg_memops; + dst_vq->gfp_flags = __GFP_DMA32; dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer); dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->rga->mutex; @@ -824,6 +826,12 @@ static int rga_probe(struct platform_device *pdev) goto err_put_clk; } + ret = dma_set_mask_and_coherent(rga->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(rga->dev, "32-bit DMA not supported"); + goto err_put_clk; + } + ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev); if (ret) goto err_put_clk; From 60faf2b82b52ffc3f75ad7ddc28691ce3c367d82 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:28 +0200 Subject: [PATCH 2973/7721] media: rockchip: rga: use clamp() to clamp size to limits The try_fmt should limit the width and height to the know limits of the RGA. Use the clamp() helper instead of open coding the clamping. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index ea566c11734a..792084918798 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -482,15 +482,10 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) f->fmt.pix.field = V4L2_FIELD_NONE; - if (f->fmt.pix.width > MAX_WIDTH) - f->fmt.pix.width = MAX_WIDTH; - if (f->fmt.pix.height > MAX_HEIGHT) - f->fmt.pix.height = MAX_HEIGHT; - - if (f->fmt.pix.width < MIN_WIDTH) - f->fmt.pix.width = MIN_WIDTH; - if (f->fmt.pix.height < MIN_HEIGHT) - f->fmt.pix.height = MIN_HEIGHT; + f->fmt.pix.width = clamp(f->fmt.pix.width, + (u32)MIN_WIDTH, (u32)MAX_WIDTH); + f->fmt.pix.height = clamp(f->fmt.pix.height, + (u32)MIN_HEIGHT, (u32)MAX_HEIGHT); if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) f->fmt.pix.bytesperline = f->fmt.pix.width; From 012602c560b43a6de4c82a463bb4f282d50c38b4 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:29 +0200 Subject: [PATCH 2974/7721] media: rockchip: rga: use pixelformat to find format Use the pixelformat instead of the v4l2_format to find the rga_fmt. This avoids knowing the structure and type of v4l2_format in rga_fmt_find and simplifies the function. Also cleanup the users of the function. In try_fmt always return the found pixel format to make sure that the pixel format is always set. Thus, we can be sure that we will find the rga_fmt in s_fmt and can drop the check if a given format has been found. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 792084918798..8ae68890a8f7 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -320,12 +320,12 @@ static struct rga_fmt formats[] = { #define NUM_FORMATS ARRAY_SIZE(formats) -static struct rga_fmt *rga_fmt_find(struct v4l2_format *f) +static struct rga_fmt *rga_fmt_find(u32 pixelformat) { unsigned int i; for (i = 0; i < NUM_FORMATS; i++) { - if (formats[i].fourcc == f->fmt.pix.pixelformat) + if (formats[i].fourcc == pixelformat) return &formats[i]; } return NULL; @@ -474,11 +474,11 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) { struct rga_fmt *fmt; - fmt = rga_fmt_find(f); - if (!fmt) { + fmt = rga_fmt_find(f->fmt.pix.pixelformat); + if (!fmt) fmt = &formats[0]; - f->fmt.pix.pixelformat = fmt->fourcc; - } + + f->fmt.pix.pixelformat = fmt->fourcc; f->fmt.pix.field = V4L2_FIELD_NONE; @@ -504,7 +504,6 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) struct rockchip_rga *rga = ctx->rga; struct vb2_queue *vq; struct rga_frame *frm; - struct rga_fmt *fmt; int ret = 0; /* Adjust all values accordingly to the hardware capabilities @@ -521,13 +520,10 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) frm = rga_get_frame(ctx, f->type); if (IS_ERR(frm)) return PTR_ERR(frm); - fmt = rga_fmt_find(f); - if (!fmt) - return -EINVAL; frm->width = f->fmt.pix.width; frm->height = f->fmt.pix.height; frm->size = f->fmt.pix.sizeimage; - frm->fmt = fmt; + frm->fmt = rga_fmt_find(f->fmt.pix.pixelformat); frm->stride = f->fmt.pix.bytesperline; frm->colorspace = f->fmt.pix.colorspace; From 4e4dd24e309dbd9a3cac7a228b62991a8dfe8390 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:30 +0200 Subject: [PATCH 2975/7721] media: rockchip: rga: add local variable for pix_format The local variable allows to simplify the accessed to the format and makes it easier to change the type of the format. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 55 +++++++++++++---------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 8ae68890a8f7..f5d0d87cce22 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -448,6 +448,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) { + struct v4l2_pix_format *pix_fmt = &f->fmt.pix; struct rga_ctx *ctx = prv; struct vb2_queue *vq; struct rga_frame *frm; @@ -459,47 +460,49 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) if (IS_ERR(frm)) return PTR_ERR(frm); - f->fmt.pix.width = frm->width; - f->fmt.pix.height = frm->height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = frm->fmt->fourcc; - f->fmt.pix.bytesperline = frm->stride; - f->fmt.pix.sizeimage = frm->size; - f->fmt.pix.colorspace = frm->colorspace; + pix_fmt->width = frm->width; + pix_fmt->height = frm->height; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->pixelformat = frm->fmt->fourcc; + pix_fmt->bytesperline = frm->stride; + pix_fmt->sizeimage = frm->size; + pix_fmt->colorspace = frm->colorspace; return 0; } static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) { + struct v4l2_pix_format *pix_fmt = &f->fmt.pix; struct rga_fmt *fmt; fmt = rga_fmt_find(f->fmt.pix.pixelformat); if (!fmt) fmt = &formats[0]; - f->fmt.pix.pixelformat = fmt->fourcc; + pix_fmt->pixelformat = fmt->fourcc; - f->fmt.pix.field = V4L2_FIELD_NONE; + pix_fmt->field = V4L2_FIELD_NONE; - f->fmt.pix.width = clamp(f->fmt.pix.width, - (u32)MIN_WIDTH, (u32)MAX_WIDTH); - f->fmt.pix.height = clamp(f->fmt.pix.height, - (u32)MIN_HEIGHT, (u32)MAX_HEIGHT); + pix_fmt->width = clamp(pix_fmt->width, + (u32)MIN_WIDTH, (u32)MAX_WIDTH); + pix_fmt->height = clamp(pix_fmt->height, + (u32)MIN_HEIGHT, (u32)MAX_HEIGHT); if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) - f->fmt.pix.bytesperline = f->fmt.pix.width; + pix_fmt->bytesperline = pix_fmt->width; else - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + pix_fmt->bytesperline = (pix_fmt->width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3; + pix_fmt->sizeimage = + pix_fmt->height * (pix_fmt->width * fmt->depth) >> 3; return 0; } static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) { + struct v4l2_pix_format *pix_fmt = &f->fmt.pix; struct rga_ctx *ctx = prv; struct rockchip_rga *rga = ctx->rga; struct vb2_queue *vq; @@ -520,12 +523,12 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) frm = rga_get_frame(ctx, f->type); if (IS_ERR(frm)) return PTR_ERR(frm); - frm->width = f->fmt.pix.width; - frm->height = f->fmt.pix.height; - frm->size = f->fmt.pix.sizeimage; - frm->fmt = rga_fmt_find(f->fmt.pix.pixelformat); - frm->stride = f->fmt.pix.bytesperline; - frm->colorspace = f->fmt.pix.colorspace; + frm->width = pix_fmt->width; + frm->height = pix_fmt->height; + frm->size = pix_fmt->sizeimage; + frm->fmt = rga_fmt_find(pix_fmt->pixelformat); + frm->stride = pix_fmt->bytesperline; + frm->colorspace = pix_fmt->colorspace; /* Reset crop settings */ frm->crop.left = 0; @@ -533,6 +536,12 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) frm->crop.width = frm->width; frm->crop.height = frm->height; + v4l2_dbg(debug, 1, &rga->v4l2_dev, + "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n", + V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE", + &frm->fmt->fourcc, frm->width, frm->height, + frm->stride, frm->size); + return 0; } From 2addee7aeff25260f35e688f7ced057b8651c1c5 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:31 +0200 Subject: [PATCH 2976/7721] media: rockchip: rga: use macros for testing buffer type Use the provided V4L2_TYPE_IS_{OUTPUT,CAPTURE} macros to check if the buffer or queue is OUTPUT or CAPTURE. The macros work also work for the _MPLANE buffer and queue types and make it easier to switch to the multi-planar API. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index f5d0d87cce22..91be87e01dab 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -344,14 +344,11 @@ static struct rga_frame def_frame = { struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type) { - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (V4L2_TYPE_IS_OUTPUT(type)) return &ctx->in; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (V4L2_TYPE_IS_CAPTURE(type)) return &ctx->out; - default: - return ERR_PTR(-EINVAL); - } + return ERR_PTR(-EINVAL); } static int rga_open(struct file *file) @@ -559,21 +556,21 @@ static int vidioc_g_selection(struct file *file, void *prv, switch (s->target) { case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (!V4L2_TYPE_IS_CAPTURE(s->type)) return -EINVAL; break; case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (!V4L2_TYPE_IS_OUTPUT(s->type)) return -EINVAL; break; case V4L2_SEL_TGT_COMPOSE: - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (!V4L2_TYPE_IS_CAPTURE(s->type)) return -EINVAL; use_frame = true; break; case V4L2_SEL_TGT_CROP: - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (!V4L2_TYPE_IS_OUTPUT(s->type)) return -EINVAL; use_frame = true; break; @@ -611,7 +608,7 @@ static int vidioc_s_selection(struct file *file, void *prv, * COMPOSE target is only valid for capture buffer type, return * error for output buffer type */ - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (!V4L2_TYPE_IS_CAPTURE(s->type)) return -EINVAL; break; case V4L2_SEL_TGT_CROP: @@ -619,7 +616,7 @@ static int vidioc_s_selection(struct file *file, void *prv, * CROP target is only valid for output buffer type, return * error for capture buffer type */ - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (!V4L2_TYPE_IS_OUTPUT(s->type)) return -EINVAL; break; /* From 0148bcd77d0a2a381818d4d1a8f445217fdbcae8 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:32 +0200 Subject: [PATCH 2977/7721] media: rockchip: rga: switch to multi-planar API Switch to the multi-planar API, which allows to handle buffers with separate planes. The RGA driver doesn't expose multi-planar formats, yet. The existing contiguous planar formats can be used with the multi-planar API as well, but the multi-planar API is required for multi-planar formats. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 60 +++++++++++------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 91be87e01dab..f549966c3649 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -93,7 +93,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) struct rga_ctx *ctx = priv; int ret; - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; src_vq->io_modes = VB2_MMAP | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->ops = &rga_qops; @@ -108,7 +108,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) if (ret) return ret; - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->ops = &rga_qops; @@ -445,7 +445,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_ctx *ctx = prv; struct vb2_queue *vq; struct rga_frame *frm; @@ -457,12 +457,9 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) if (IS_ERR(frm)) return PTR_ERR(frm); - pix_fmt->width = frm->width; - pix_fmt->height = frm->height; + v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height); + pix_fmt->field = V4L2_FIELD_NONE; - pix_fmt->pixelformat = frm->fmt->fourcc; - pix_fmt->bytesperline = frm->stride; - pix_fmt->sizeimage = frm->size; pix_fmt->colorspace = frm->colorspace; return 0; @@ -470,41 +467,33 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_fmt *fmt; - fmt = rga_fmt_find(f->fmt.pix.pixelformat); + fmt = rga_fmt_find(pix_fmt->pixelformat); if (!fmt) fmt = &formats[0]; - pix_fmt->pixelformat = fmt->fourcc; - - pix_fmt->field = V4L2_FIELD_NONE; - pix_fmt->width = clamp(pix_fmt->width, (u32)MIN_WIDTH, (u32)MAX_WIDTH); pix_fmt->height = clamp(pix_fmt->height, (u32)MIN_HEIGHT, (u32)MAX_HEIGHT); - if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) - pix_fmt->bytesperline = pix_fmt->width; - else - pix_fmt->bytesperline = (pix_fmt->width * fmt->depth) >> 3; - - pix_fmt->sizeimage = - pix_fmt->height * (pix_fmt->width * fmt->depth) >> 3; + v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height); + pix_fmt->field = V4L2_FIELD_NONE; return 0; } static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_ctx *ctx = prv; struct rockchip_rga *rga = ctx->rga; struct vb2_queue *vq; struct rga_frame *frm; int ret = 0; + int i; /* Adjust all values accordingly to the hardware capabilities * and chosen format. @@ -522,9 +511,11 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) return PTR_ERR(frm); frm->width = pix_fmt->width; frm->height = pix_fmt->height; - frm->size = pix_fmt->sizeimage; + frm->size = 0; + for (i = 0; i < pix_fmt->num_planes; i++) + frm->size += pix_fmt->plane_fmt[i].sizeimage; frm->fmt = rga_fmt_find(pix_fmt->pixelformat); - frm->stride = pix_fmt->bytesperline; + frm->stride = pix_fmt->plane_fmt[0].bytesperline; frm->colorspace = pix_fmt->colorspace; /* Reset crop settings */ @@ -539,6 +530,13 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) &frm->fmt->fourcc, frm->width, frm->height, frm->stride, frm->size); + for (i = 0; i < pix_fmt->num_planes; i++) { + v4l2_dbg(debug, 1, &rga->v4l2_dev, + "plane[%d]: size %d, bytesperline %d\n", + i, pix_fmt->plane_fmt[i].sizeimage, + pix_fmt->plane_fmt[i].bytesperline); + } + return 0; } @@ -649,14 +647,14 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, - .vidioc_g_fmt_vid_out = vidioc_g_fmt, - .vidioc_try_fmt_vid_out = vidioc_try_fmt, - .vidioc_s_fmt_vid_out = vidioc_s_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, @@ -683,7 +681,7 @@ static const struct video_device rga_videodev = { .minor = -1, .release = video_device_release, .vfl_dir = VFL_DIR_M2M, - .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, }; static int rga_enable_clocks(struct rockchip_rga *rga) From a61ff67ffb9d6e6506bd563fa078d98bc8033a9e Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:33 +0200 Subject: [PATCH 2978/7721] media: rockchip: rga: rework buffer handling for multi-planar formats Multi-planar formats may have multiple planes that must be handled and correctly mapped into a continuous buffer for the RGA by using the DMA descriptors. The plane offsets in the continuous mapping may now start at page boundaries and the previous calculation based on the frame sizes is only valid for planar buffers in a single memory. Therefore, the offsets must be detected and set while creating the mapping. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga-buf.c | 61 +++++++++++++++---- drivers/media/platform/rockchip/rga/rga.c | 7 +++ drivers/media/platform/rockchip/rga/rga.h | 1 + 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index d6774a844d9b..662c81b6d0b5 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,8 @@ #include "rga-hw.h" #include "rga.h" -static size_t fill_descriptors(struct rga_dma_desc *desc, struct sg_table *sgt) +static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc, + struct sg_table *sgt) { struct sg_dma_page_iter iter; struct rga_dma_desc *tmp = desc; @@ -24,6 +26,8 @@ static size_t fill_descriptors(struct rga_dma_desc *desc, struct sg_table *sgt) dma_addr_t addr; for_each_sgtable_dma_page(sgt, &iter, 0) { + if (n_desc > max_desc) + return -EINVAL; addr = sg_page_iter_dma_address(&iter); tmp->addr = lower_32_bits(addr); tmp++; @@ -40,15 +44,29 @@ rga_queue_setup(struct vb2_queue *vq, { struct rga_ctx *ctx = vb2_get_drv_priv(vq); struct rga_frame *f = rga_get_frame(ctx, vq->type); + const struct v4l2_pix_format_mplane *pix_fmt; + int i; if (IS_ERR(f)) return PTR_ERR(f); - if (*nplanes) - return sizes[0] < f->size ? -EINVAL : 0; + pix_fmt = &f->pix; - sizes[0] = f->size; - *nplanes = 1; + if (*nplanes) { + if (*nplanes != pix_fmt->num_planes) + return -EINVAL; + + for (i = 0; i < pix_fmt->num_planes; i++) + if (sizes[i] < pix_fmt->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *nplanes = pix_fmt->num_planes; + + for (i = 0; i < pix_fmt->num_planes; i++) + sizes[i] = pix_fmt->plane_fmt[i].sizeimage; return 0; } @@ -92,18 +110,39 @@ static int rga_buf_prepare(struct vb2_buffer *vb) struct rga_vb_buffer *rbuf = vb_to_rga(vbuf); struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); + ssize_t n_desc = 0; + size_t curr_desc = 0; + int i; + const struct v4l2_format_info *info; + unsigned int offsets[VIDEO_MAX_PLANES]; if (IS_ERR(f)) return PTR_ERR(f); - vb2_set_plane_payload(vb, 0, f->size); + for (i = 0; i < vb->num_planes; i++) { + vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage); - /* Create local MMU table for RGA */ - fill_descriptors(rbuf->dma_desc, vb2_dma_sg_plane_desc(vb, 0)); + /* Create local MMU table for RGA */ + n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc], + rbuf->n_desc - curr_desc, + vb2_dma_sg_plane_desc(vb, i)); + if (n_desc < 0) { + v4l2_err(&ctx->rga->v4l2_dev, + "Failed to map video buffer to RGA\n"); + return n_desc; + } + offsets[i] = curr_desc << PAGE_SHIFT; + curr_desc += n_desc; + } - rbuf->offset.y_off = get_plane_offset(f, 0); - rbuf->offset.u_off = get_plane_offset(f, 1); - rbuf->offset.v_off = get_plane_offset(f, 2); + /* Fill the remaining planes */ + info = v4l2_format_info(f->fmt->fourcc); + for (i = info->mem_planes; i < info->comp_planes; i++) + offsets[i] = get_plane_offset(f, i); + + rbuf->offset.y_off = offsets[0]; + rbuf->offset.u_off = offsets[1]; + rbuf->offset.v_off = offsets[2]; return 0; } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index f549966c3649..57d845c57d7d 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -365,6 +365,11 @@ static int rga_open(struct file *file) ctx->in = def_frame; ctx->out = def_frame; + v4l2_fill_pixfmt_mp(&ctx->in.pix, + ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height); + v4l2_fill_pixfmt_mp(&ctx->out.pix, + ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height); + if (mutex_lock_interruptible(&rga->mutex)) { kfree(ctx); return -ERESTARTSYS; @@ -524,6 +529,8 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) frm->crop.width = frm->width; frm->crop.height = frm->height; + frm->pix = *pix_fmt; + v4l2_dbg(debug, 1, &rga->v4l2_dev, "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n", V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE", diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index f3953a07d9e7..3502dff6055c 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -34,6 +34,7 @@ struct rga_frame { /* Image format */ struct rga_fmt *fmt; + struct v4l2_pix_format_mplane pix; /* Variables that can calculated once and reused */ u32 stride; From db71a7f5cbb8d41beed8352b2313f9079371cd98 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Oct 2023 13:00:34 +0200 Subject: [PATCH 2979/7721] media: rockchip: rga: add NV12M support Add support for the multi-planar variants of NV12. The RGA is now able to exchange DMABUFs with other devices that only support multi-planar NV12, for example the Hantro JPEG encoder. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 57d845c57d7d..00fdfa9e10bc 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -280,6 +280,15 @@ static struct rga_fmt formats[] = { .y_div = 2, .x_div = 1, }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420SP, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 1, + }, { .fourcc = V4L2_PIX_FMT_NV16, .color_swap = RGA_COLOR_NONE_SWAP, From 6c826061c5ee42fe547d1ac4792b30125fa8cb13 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 5 Dec 2023 19:05:23 -0800 Subject: [PATCH 2980/7721] gpio: max730x: don't use kernel-doc marker for regular comment Use a common C comment (/*) instead of kernel-doc notation to prevent warnings from scripts/kernel-doc. gpio-max730x.c:3: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst gpio-max730x.c:3: warning: missing initial short description on line: * Copyright (C) 2006 Juergen Beisert, Pengutronix Signed-off-by: Randy Dunlap Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-max730x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index bb5cf14ae4c8..701795b9d329 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix From 5ec42bf04d72fd6d0a6855810cc779e0ee31dfd7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Dec 2023 15:27:06 -0600 Subject: [PATCH 2981/7721] PCI: add INTEL_HDA_ARL to pci_ids.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI ID insertion follows the increasing order in the table, but this hardware follows MTL (MeteorLake). Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231204212710.185976-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 275799b5f535..97cc0baad0f4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3065,6 +3065,7 @@ #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_HDA_ARL 0x7728 #define PCI_DEVICE_ID_INTEL_HDA_RPL_S 0x7a50 #define PCI_DEVICE_ID_INTEL_HDA_ADL_S 0x7ad0 #define PCI_DEVICE_ID_INTEL_HDA_MTL 0x7e28 From a31014ebad617868c246d3985ff80d891f03711e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Dec 2023 15:27:07 -0600 Subject: [PATCH 2982/7721] ALSA: hda: Intel: add HDA_ARL PCI ID support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yet another PCI ID. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231204212710.185976-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index db90feb49c16..d0ade91ab5ac 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2502,6 +2502,8 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Arrow Lake-S */ { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Arrow Lake */ + { PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Apollolake (Broxton-P) */ { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ From 7a9d6bbe8a663c817080be55d9fecf19a4a8fd8f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Dec 2023 15:27:08 -0600 Subject: [PATCH 2983/7721] ALSA: hda: intel-dspcfg: add filters for ARL-S and ARL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same usual filters, SOF is required for DMIC and/or SoundWire support. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231204212710.185976-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 756fa0aa69bb..6a384b922e4f 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -521,6 +521,16 @@ static const struct config_entry config_table[] = { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_MTL, }, + /* ArrowLake-S */ + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_ARL_S, + }, + /* ArrowLake */ + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_ARL, + }, #endif /* Lunar Lake */ From a00be6dc9bb80796244196033aa5eb258b6af47a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Dec 2023 15:27:09 -0600 Subject: [PATCH 2984/7721] ASoC: SOF: Intel: pci-mtl: fix ARL-S definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial copy/paste from MTL was incorrect, the hardware is different and requires different descriptors along with a dedicated firmware binary. Fixes: 3851831f529e ("ASoC: SOF: Intel: pci-mtl: use ARL specific firmware definitions") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231204212710.185976-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/mtl.c | 28 ++++++++++++++++++++++++++++ sound/soc/sof/intel/pci-mtl.c | 12 ++++++------ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d628d6a3a7e5..1592e27bc14d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -882,6 +882,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc mtl_chip_info; +extern const struct sof_intel_dsp_desc arl_s_chip_info; extern const struct sof_intel_dsp_desc lnl_chip_info; /* Probes support */ diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 254dbbeac1d0..7946110e7adf 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -746,3 +746,31 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .hw_ip_version = SOF_INTEL_ACE_1_0, }; EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc arl_s_chip_info = { + .cores_num = 2, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, + .sdw_shim_base = SDW_SHIM_BASE_ACE, + .sdw_alh_base = SDW_ALH_BASE_ACE, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = mtl_enable_sdw_irq, + .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = mtl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_1_0, +}; +EXPORT_SYMBOL_NS(arl_s_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 0f378f45486d..60d5e73cdad2 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -50,7 +50,7 @@ static const struct sof_dev_desc mtl_desc = { .ops_free = hda_ops_free, }; -static const struct sof_dev_desc arl_desc = { +static const struct sof_dev_desc arl_s_desc = { .use_acpi_target_states = true, .machines = snd_soc_acpi_intel_arl_machines, .alt_machines = snd_soc_acpi_intel_arl_sdw_machines, @@ -58,21 +58,21 @@ static const struct sof_dev_desc arl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .chip_info = &mtl_chip_info, + .chip_info = &arl_s_chip_info, .ipc_supported_mask = BIT(SOF_IPC_TYPE_4), .ipc_default = SOF_IPC_TYPE_4, .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl-s", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl-s", }, .default_tplg_path = { [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", }, .default_fw_filename = { - [SOF_IPC_TYPE_4] = "sof-arl.ri", + [SOF_IPC_TYPE_4] = "sof-arl-s.ri", }, .nocodec_tplg_filename = "sof-arl-nocodec.tplg", .ops = &sof_mtl_ops, @@ -83,7 +83,7 @@ static const struct sof_dev_desc arl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) }, - { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, &arl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, &arl_s_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); From 1ccffc2f760a960372093106558411e644b89c57 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Dec 2023 15:27:10 -0600 Subject: [PATCH 2985/7721] ASoC: SOF: Intel: pci-mtl: add HDA_ARL PCI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add yet another PCI ID - the hardware shares the same descriptors as MTL but we use a dedicated firmware binary file to allow for different signature keys. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Acked-by: Mark Brown Link: https://lore.kernel.org/r/20231204212710.185976-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/pci-mtl.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 60d5e73cdad2..cacc985d80f4 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -50,6 +50,36 @@ static const struct sof_dev_desc mtl_desc = { .ops_free = hda_ops_free, }; +static const struct sof_dev_desc arl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_arl_machines, + .alt_machines = snd_soc_acpi_intel_arl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &mtl_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_4), + .ipc_default = SOF_IPC_TYPE_4, + .dspless_mode_supported = true, /* Only supported for HDaudio */ + .default_fw_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl", + }, + .default_lib_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_4] = "sof-arl.ri", + }, + .nocodec_tplg_filename = "sof-arl-nocodec.tplg", + .ops = &sof_mtl_ops, + .ops_init = sof_mtl_ops_init, + .ops_free = hda_ops_free, +}; + static const struct sof_dev_desc arl_s_desc = { .use_acpi_target_states = true, .machines = snd_soc_acpi_intel_arl_machines, @@ -84,6 +114,7 @@ static const struct sof_dev_desc arl_s_desc = { static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, &arl_s_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ARL, &arl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); From c598dc3bc41ed079408633d7d66eefa440e15a12 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 5 Dec 2023 16:54:30 +0100 Subject: [PATCH 2986/7721] gpio: sim: fix the email address in MODULE_AUTHOR() Fix unterminated angle brackets in the email address in MODULE_AUTHOR(). Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 1928209491e1..1e8b92e9df80 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -1546,6 +1546,6 @@ static void __exit gpio_sim_exit(void) } module_exit(gpio_sim_exit); -MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_DESCRIPTION("GPIO Simulator Module"); MODULE_LICENSE("GPL"); From 887f8094b3352127d1bc68f768774e97acf4e7fa Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:52 +0100 Subject: [PATCH 2987/7721] selftests/hid: vmtest.sh: update vm2c and container boot2container is now on an official project, so let's use that. The container image is now the same I use for the CI, so let's keep to it. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-1-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/vmtest.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/hid/vmtest.sh b/tools/testing/selftests/hid/vmtest.sh index 4da48bf6b328..301b4e162336 100755 --- a/tools/testing/selftests/hid/vmtest.sh +++ b/tools/testing/selftests/hid/vmtest.sh @@ -19,12 +19,12 @@ esac SCRIPT_DIR="$(dirname $(realpath $0))" OUTPUT_DIR="$SCRIPT_DIR/results" KCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}") -B2C_URL="https://gitlab.freedesktop.org/mupuf/boot2container/-/raw/master/vm2c.py" +B2C_URL="https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/main/vm2c.py" NUM_COMPILE_JOBS="$(nproc)" LOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")" LOG_FILE="${LOG_FILE_BASE}.log" EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status" -CONTAINER_IMAGE="registry.freedesktop.org/libevdev/hid-tools/fedora/37:2023-02-17.1" +CONTAINER_IMAGE="registry.freedesktop.org/bentiss/hid/fedora/39:2023-11-22.1" TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}" DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests" From 46bc0277c2507338d98e166826afec330962309e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:53 +0100 Subject: [PATCH 2988/7721] selftests/hid: vmtest.sh: allow finer control on the build steps vmtest.sh works great for a one shot test, but not so much for CI where I want to build (with different configs) the bzImage in a separate job than the one I am running it. Add a "build_only" option to specify whether we need to boot the currently built kernel in the vm. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-2-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/vmtest.sh | 46 +++++++++++++++------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/hid/vmtest.sh b/tools/testing/selftests/hid/vmtest.sh index 301b4e162336..db534e9099a8 100755 --- a/tools/testing/selftests/hid/vmtest.sh +++ b/tools/testing/selftests/hid/vmtest.sh @@ -32,7 +32,7 @@ DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS usage() { cat <] -- [] +Usage: $0 [-j N] [-s] [-b] [-d ] -- [] is the command you would normally run when you are in the source kernel direcory. e.g: @@ -55,6 +55,7 @@ Options: -u) Update the boot2container script to a newer version. -d) Update the output directory (default: ${OUTPUT_DIR}) + -b) Run only the build steps for the kernel and the selftests -j) Number of jobs for compilation, similar to -j in make (default: ${NUM_COMPILE_JOBS}) -s) Instead of powering off the VM, start an interactive @@ -191,8 +192,9 @@ main() local command="${DEFAULT_COMMAND}" local update_b2c="no" local debug_shell="no" + local build_only="no" - while getopts ':hsud:j:' opt; do + while getopts ':hsud:j:b' opt; do case ${opt} in u) update_b2c="yes" @@ -207,6 +209,9 @@ main() command="/bin/sh" debug_shell="yes" ;; + b) + build_only="yes" + ;; h) usage exit 0 @@ -226,8 +231,7 @@ main() shift $((OPTIND -1)) # trap 'catch "$?"' EXIT - - if [[ "${debug_shell}" == "no" ]]; then + if [[ "${build_only}" == "no" && "${debug_shell}" == "no" ]]; then if [[ $# -eq 0 ]]; then echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" else @@ -267,24 +271,26 @@ main() update_kconfig "${kernel_checkout}" "${kconfig_file}" recompile_kernel "${kernel_checkout}" "${make_command}" - - if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then - echo "vm2c script not found in ${b2c}" - update_b2c="yes" - fi - - if [[ "${update_b2c}" == "yes" ]]; then - download $B2C_URL $b2c - chmod +x $b2c - fi - update_selftests "${kernel_checkout}" "${make_command}" - run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}" - if [[ "${debug_shell}" != "yes" ]]; then - echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}" - fi - exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE}) + if [[ "${build_only}" == "no" ]]; then + if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then + echo "vm2c script not found in ${b2c}" + update_b2c="yes" + fi + + if [[ "${update_b2c}" == "yes" ]]; then + download $B2C_URL $b2c + chmod +x $b2c + fi + + run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}" + if [[ "${debug_shell}" != "yes" ]]; then + echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}" + fi + + exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE}) + fi } main "$@" From 110292a77f7c8d11eaa472e65f6a2084b25be2db Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:54 +0100 Subject: [PATCH 2989/7721] selftests/hid: base: allow for multiple skip_if_uhdev We can actually have multiple occurences of `skip_if_uhdev` if we follow the information from the pytest doc[0]. This is not immediately used, but can be if we need multiple conditions on a given test. [0] https://docs.pytest.org/en/latest/historical-notes.html#update-marker-code Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-3-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/hid/tests/base.py b/tools/testing/selftests/hid/tests/base.py index 1305cfc9646e..5d9c26dfc460 100644 --- a/tools/testing/selftests/hid/tests/base.py +++ b/tools/testing/selftests/hid/tests/base.py @@ -238,8 +238,7 @@ class BaseTestCase: try: with HIDTestUdevRule.instance(): with new_uhdev as self.uhdev: - skip_cond = request.node.get_closest_marker("skip_if_uhdev") - if skip_cond: + for skip_cond in request.node.iter_markers("skip_if_uhdev"): test, message, *rest = skip_cond.args if test(self.uhdev): From b5edacf79c8e1990200f9392e6354583298e8765 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:55 +0100 Subject: [PATCH 2990/7721] selftests/hid: tablets: remove unused class Looks like this is a leftover Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-4-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/test_tablet.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 303ffff9ee8d..cd9c1269afa6 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -133,10 +133,6 @@ class PenState(Enum): return tuple() -class Data(object): - pass - - class Pen(object): def __init__(self, x, y): self.x = x From d52f52069fed639113b1014cde5eff8902d3064d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:56 +0100 Subject: [PATCH 2991/7721] selftests/hid: tablets: move the transitions to PenState Those transitions have nothing to do with `Pen`, so migrate them to `PenState`. The hidden agenda is to remove `Pen` and integrate it into `PenDigitizer` so that we can tweak the events in each state to emulate firmware bugs. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-5-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 273 +++++++++--------- 1 file changed, 138 insertions(+), 135 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index cd9c1269afa6..ddf28c245046 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -132,6 +132,136 @@ class PenState(Enum): return tuple() + @staticmethod + def legal_transitions() -> Dict[str, Tuple["PenState", ...]]: + """This is the first half of the Windows Pen Implementation state machine: + we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. + https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states + """ + return { + "in-range": (PenState.PEN_IS_IN_RANGE,), + "in-range -> out-of-range": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + ), + "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT), + "in-range -> touch -> release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> touch -> release -> out-of-range": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + ), + } + + @staticmethod + def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: + """This is the second half of the Windows Pen Implementation state machine: + we now have Invert and Erase bits, so move in/out or proximity with the intend + to erase. + https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states + """ + return { + "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,), + "hover-erasing -> out-of-range": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_OUT_OF_RANGE, + ), + "hover-erasing -> erase": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_ERASING, + ), + "hover-erasing -> erase -> release": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + ), + "hover-erasing -> erase -> release -> out-of-range": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_OUT_OF_RANGE, + ), + "hover-erasing -> in-range": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> hover-erasing": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + ), + } + + @staticmethod + def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: + """This is not adhering to the Windows Pen Implementation state machine + but we should expect the kernel to behave properly, mostly for historical + reasons.""" + return { + "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,), + "direct-in-contact -> out-of-range": ( + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_OUT_OF_RANGE, + ), + } + + @staticmethod + def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: + """This is the second half of the Windows Pen Implementation state machine: + we now have Invert and Erase bits, so move in/out or proximity with the intend + to erase. + https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states + """ + return { + "direct-erase": (PenState.PEN_IS_ERASING,), + "direct-erase -> out-of-range": ( + PenState.PEN_IS_ERASING, + PenState.PEN_IS_OUT_OF_RANGE, + ), + } + + @staticmethod + def broken_transitions() -> Dict[str, Tuple["PenState", ...]]: + """Those tests are definitely not part of the Windows specification. + However, a half broken device might export those transitions. + For example, a pen that has the eraser button might wobble between + touching and erasing if the tablet doesn't enforce the Windows + state machine.""" + return { + "in-range -> touch -> erase -> hover-erase": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + ), + "in-range -> erase -> hover-erase": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + ), + "hover-erase -> erase -> touch -> in-range": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + ), + "hover-erase -> touch -> in-range": ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + ), + "touch -> erase -> touch -> erase": ( + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_ERASING, + ), + } + class Pen(object): def __init__(self, x, y): @@ -228,136 +358,6 @@ class Pen(object): assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y assert self.current_state == PenState.from_evdev(evdev) - @staticmethod - def legal_transitions() -> Dict[str, Tuple[PenState, ...]]: - """This is the first half of the Windows Pen Implementation state machine: - we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. - https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states - """ - return { - "in-range": (PenState.PEN_IS_IN_RANGE,), - "in-range -> out-of-range": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_OUT_OF_RANGE, - ), - "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT), - "in-range -> touch -> release": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_IN_RANGE, - ), - "in-range -> touch -> release -> out-of-range": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_OUT_OF_RANGE, - ), - } - - @staticmethod - def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]: - """This is the second half of the Windows Pen Implementation state machine: - we now have Invert and Erase bits, so move in/out or proximity with the intend - to erase. - https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states - """ - return { - "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,), - "hover-erasing -> out-of-range": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_OUT_OF_RANGE, - ), - "hover-erasing -> erase": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_ERASING, - ), - "hover-erasing -> erase -> release": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - ), - "hover-erasing -> erase -> release -> out-of-range": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_OUT_OF_RANGE, - ), - "hover-erasing -> in-range": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_IN_RANGE, - ), - "in-range -> hover-erasing": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - ), - } - - @staticmethod - def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]: - """This is not adhering to the Windows Pen Implementation state machine - but we should expect the kernel to behave properly, mostly for historical - reasons.""" - return { - "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,), - "direct-in-contact -> out-of-range": ( - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_OUT_OF_RANGE, - ), - } - - @staticmethod - def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]: - """This is the second half of the Windows Pen Implementation state machine: - we now have Invert and Erase bits, so move in/out or proximity with the intend - to erase. - https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states - """ - return { - "direct-erase": (PenState.PEN_IS_ERASING,), - "direct-erase -> out-of-range": ( - PenState.PEN_IS_ERASING, - PenState.PEN_IS_OUT_OF_RANGE, - ), - } - - @staticmethod - def broken_transitions() -> Dict[str, Tuple[PenState, ...]]: - """Those tests are definitely not part of the Windows specification. - However, a half broken device might export those transitions. - For example, a pen that has the eraser button might wobble between - touching and erasing if the tablet doesn't enforce the Windows - state machine.""" - return { - "in-range -> touch -> erase -> hover-erase": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - ), - "in-range -> erase -> hover-erase": ( - PenState.PEN_IS_IN_RANGE, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - ), - "hover-erase -> erase -> touch -> in-range": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_IN_RANGE, - ), - "hover-erase -> touch -> in-range": ( - PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_IN_RANGE, - ), - "touch -> erase -> touch -> erase": ( - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_ERASING, - PenState.PEN_IS_IN_CONTACT, - PenState.PEN_IS_ERASING, - ), - } - class PenDigitizer(base.UHIDTestDevice): def __init__( @@ -486,7 +486,7 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=k) for k, v in Pen.legal_transitions().items()], + [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()], ) def test_valid_pen_states(self, state_list, scribble): """This is the first half of the Windows Pen Implementation state machine: @@ -498,7 +498,10 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=k) for k, v in Pen.tolerated_transitions().items()], + [ + pytest.param(v, id=k) + for k, v in PenState.tolerated_transitions().items() + ], ) def test_tolerated_pen_states(self, state_list, scribble): """This is not adhering to the Windows Pen Implementation state machine @@ -515,7 +518,7 @@ class BaseTest: "state_list", [ pytest.param(v, id=k) - for k, v in Pen.legal_transitions_with_invert().items() + for k, v in PenState.legal_transitions_with_invert().items() ], ) def test_valid_invert_pen_states(self, state_list, scribble): @@ -535,7 +538,7 @@ class BaseTest: "state_list", [ pytest.param(v, id=k) - for k, v in Pen.tolerated_transitions_with_invert().items() + for k, v in PenState.tolerated_transitions_with_invert().items() ], ) def test_tolerated_invert_pen_states(self, state_list, scribble): @@ -553,7 +556,7 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=k) for k, v in Pen.broken_transitions().items()], + [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()], ) def test_tolerated_broken_pen_states(self, state_list, scribble): """Those tests are definitely not part of the Windows specification. From 881ccc36b42670ebbd5fb32a79b239ce1136e84d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:57 +0100 Subject: [PATCH 2992/7721] selftests/hid: tablets: move move_to function to PenDigitizer We can easily subclass PenDigitizer for introducing firmware bugs when subclassing Pen is harder. Move move_to from Pen to PenDigitizer so we get that ability Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-6-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 97 ++++++++++--------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index ddf28c245046..27260dc02cc4 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -282,7 +282,7 @@ class Pen(object): self._old_values = None self.current_state = None - def _restore(self): + def restore(self): if self._old_values is not None: for i in [ "x", @@ -297,50 +297,8 @@ class Pen(object): ]: setattr(self, i, getattr(self._old_values, i)) - def move_to(self, state): - # fill in the previous values - if self.current_state == PenState.PEN_IS_OUT_OF_RANGE: - self._restore() - - print(f"\n *** pen is moving to {state} ***") - - if state == PenState.PEN_IS_OUT_OF_RANGE: - self._old_values = copy.copy(self) - self.x = 0 - self.y = 0 - self.tipswitch = False - self.tippressure = 0 - self.azimuth = 0 - self.inrange = False - self.width = 0 - self.height = 0 - self.invert = False - self.eraser = False - self.x_tilt = 0 - self.y_tilt = 0 - self.twist = 0 - elif state == PenState.PEN_IS_IN_RANGE: - self.tipswitch = False - self.inrange = True - self.invert = False - self.eraser = False - elif state == PenState.PEN_IS_IN_CONTACT: - self.tipswitch = True - self.inrange = True - self.invert = False - self.eraser = False - elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: - self.tipswitch = False - self.inrange = True - self.invert = True - self.eraser = False - elif state == PenState.PEN_IS_ERASING: - self.tipswitch = False - self.inrange = True - self.invert = True - self.eraser = True - - self.current_state = state + def backup(self): + self._old_values = copy.copy(self) def __assert_axis(self, evdev, axis, value): if ( @@ -384,6 +342,51 @@ class PenDigitizer(base.UHIDTestDevice): continue self.fields = [f.usage_name for f in r] + def move_to(self, pen, state): + # fill in the previous values + if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE: + pen.restore() + + print(f"\n *** pen is moving to {state} ***") + + if state == PenState.PEN_IS_OUT_OF_RANGE: + pen.backup() + pen.x = 0 + pen.y = 0 + pen.tipswitch = False + pen.tippressure = 0 + pen.azimuth = 0 + pen.inrange = False + pen.width = 0 + pen.height = 0 + pen.invert = False + pen.eraser = False + pen.x_tilt = 0 + pen.y_tilt = 0 + pen.twist = 0 + elif state == PenState.PEN_IS_IN_RANGE: + pen.tipswitch = False + pen.inrange = True + pen.invert = False + pen.eraser = False + elif state == PenState.PEN_IS_IN_CONTACT: + pen.tipswitch = True + pen.inrange = True + pen.invert = False + pen.eraser = False + elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: + pen.tipswitch = False + pen.inrange = True + pen.invert = True + pen.eraser = False + elif state == PenState.PEN_IS_ERASING: + pen.tipswitch = False + pen.inrange = True + pen.invert = True + pen.eraser = True + + pen.current_state = state + def event(self, pen): rs = [] r = self.create_report(application=self.cur_application, data=pen) @@ -462,7 +465,7 @@ class BaseTest: cur_state = PenState.PEN_IS_OUT_OF_RANGE p = Pen(50, 60) - p.move_to(PenState.PEN_IS_OUT_OF_RANGE) + uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE) events = self.post(uhdev, p) self.validate_transitions(cur_state, p, evdev, events) @@ -475,7 +478,7 @@ class BaseTest: events = self.post(uhdev, p) self.validate_transitions(cur_state, p, evdev, events) assert len(events) >= 3 # X, Y, SYN - p.move_to(state) + uhdev.move_to(p, state) if scribble and state != PenState.PEN_IS_OUT_OF_RANGE: p.x += 1 p.y -= 1 From d8d7aa2266a7957e24cf05392b2b899be1031ed4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:58 +0100 Subject: [PATCH 2993/7721] selftests/hid: tablets: do not set invert when the eraser is used Turns out that the chart from Microsoft is not exactly what I got here: when the rubber is used, and is touching the surface, invert can (should) be set to 0... [0] https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-7-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/test_tablet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 27260dc02cc4..cb3955bf0ec5 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -382,7 +382,7 @@ class PenDigitizer(base.UHIDTestDevice): elif state == PenState.PEN_IS_ERASING: pen.tipswitch = False pen.inrange = True - pen.invert = True + pen.invert = False pen.eraser = True pen.current_state = state From e08e493ff9619daab9c11e61a80c604895a4d671 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:45:59 +0100 Subject: [PATCH 2994/7721] selftests/hid: tablets: set initial data for tilt/twist Avoids getting a null event when these usages are set Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-8-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/test_tablet.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index cb3955bf0ec5..0ddf82695ed9 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -276,9 +276,9 @@ class Pen(object): self.barrelswitch = False self.invert = False self.eraser = False - self.x_tilt = 0 - self.y_tilt = 0 - self.twist = 0 + self.xtilt = 1 + self.ytilt = 1 + self.twist = 1 self._old_values = None self.current_state = None @@ -292,8 +292,8 @@ class Pen(object): "width", "height", "twist", - "x_tilt", - "y_tilt", + "xtilt", + "ytilt", ]: setattr(self, i, getattr(self._old_values, i)) @@ -361,8 +361,8 @@ class PenDigitizer(base.UHIDTestDevice): pen.height = 0 pen.invert = False pen.eraser = False - pen.x_tilt = 0 - pen.y_tilt = 0 + pen.xtilt = 0 + pen.ytilt = 0 pen.twist = 0 elif state == PenState.PEN_IS_IN_RANGE: pen.tipswitch = False From 83912f83fabcb5086613e6382756750390ed48aa Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:00 +0100 Subject: [PATCH 2995/7721] selftests/hid: tablets: define the elements of PenState This introduces a little bit more readability by not using the raw values but a dedicated Enum Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-9-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 0ddf82695ed9..cec65294c9ec 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -13,40 +13,52 @@ from hidtools.util import BusType import libevdev import logging import pytest -from typing import Dict, Tuple +from typing import Dict, Optional, Tuple logger = logging.getLogger("hidtools.test.tablet") +class BtnTouch(Enum): + """Represents whether the BTN_TOUCH event is set to True or False""" + + DOWN = True + UP = False + + +class ToolType(Enum): + PEN = libevdev.EV_KEY.BTN_TOOL_PEN + RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER + + class PenState(Enum): """Pen states according to Microsoft reference: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states """ - PEN_IS_OUT_OF_RANGE = (False, None) - PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN) - PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN) - PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER) - PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER) + PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None + PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN + PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN + PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER + PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER - def __init__(self, touch, tool): + def __init__(self, touch: BtnTouch, tool: Optional[ToolType]): self.touch = touch self.tool = tool @classmethod def from_evdev(cls, evdev) -> "PenState": - touch = bool(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) + touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) tool = None if ( evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] ): - tool = libevdev.EV_KEY.BTN_TOOL_RUBBER + tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER) elif ( evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] ): - tool = libevdev.EV_KEY.BTN_TOOL_PEN + tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN) elif ( evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] @@ -68,7 +80,7 @@ class PenState(Enum): if touch_found: raise ValueError(f"duplicated BTN_TOUCH in {events}") touch_found = True - touch = bool(ev.value) + touch = BtnTouch(ev.value) elif ev in ( libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN), libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER), @@ -77,7 +89,7 @@ class PenState(Enum): raise ValueError(f"duplicated BTN_TOOL_* in {events}") tool_found = True if ev.value: - tool = ev.code + tool = ToolType(ev.code) else: tool = None From 74452d6329be73dd2f5562005e5eef2c7bda7c5b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:01 +0100 Subject: [PATCH 2996/7721] selftests/hid: tablets: add variants of states with buttons Turns out that there are transitions that are unlikely to happen: for example, having both the tip switch and a button being changed at the same time (in the same report) would require either a very talented and precise user or a very bad hardware with a very low sampling rate. So instead of manually building the button test by hand and forgetting about some cases, let's reuse the state machine and transitions we have. This patch only adds the states and the valid transitions. The actual tests will be replaced later. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-10-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 171 ++++++++++++++++-- 1 file changed, 159 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index cec65294c9ec..a77534f23c75 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -30,25 +30,72 @@ class ToolType(Enum): RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER +class BtnPressed(Enum): + """Represents whether a button is pressed on the stylus""" + + PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS + SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2 + + class PenState(Enum): """Pen states according to Microsoft reference: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states + + We extend it with the various buttons when we need to check them. """ - PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None - PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN - PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN - PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER - PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER + PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, None + PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, None + PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, BtnPressed.PRIMARY_PRESSED + PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = ( + BtnTouch.UP, + ToolType.PEN, + BtnPressed.SECONDARY_PRESSED, + ) + PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, None + PEN_IS_IN_CONTACT_WITH_BUTTON = ( + BtnTouch.DOWN, + ToolType.PEN, + BtnPressed.PRIMARY_PRESSED, + ) + PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = ( + BtnTouch.DOWN, + ToolType.PEN, + BtnPressed.SECONDARY_PRESSED, + ) + PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, None + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = ( + BtnTouch.UP, + ToolType.RUBBER, + BtnPressed.PRIMARY_PRESSED, + ) + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = ( + BtnTouch.UP, + ToolType.RUBBER, + BtnPressed.SECONDARY_PRESSED, + ) + PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, None + PEN_IS_ERASING_WITH_BUTTON = ( + BtnTouch.DOWN, + ToolType.RUBBER, + BtnPressed.PRIMARY_PRESSED, + ) + PEN_IS_ERASING_WITH_SECOND_BUTTON = ( + BtnTouch.DOWN, + ToolType.RUBBER, + BtnPressed.SECONDARY_PRESSED, + ) - def __init__(self, touch: BtnTouch, tool: Optional[ToolType]): + def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]): self.touch = touch self.tool = tool + self.button = button @classmethod def from_evdev(cls, evdev) -> "PenState": touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) tool = None + button = None if ( evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] @@ -65,7 +112,17 @@ class PenState(Enum): ): raise ValueError("2 tools are not allowed") - return cls((touch, tool)) + # we take only the highest button in account + for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: + if bool(evdev.value[b]): + button = b + + # the kernel tends to insert an EV_SYN once removing the tool, so + # the button will be released after + if tool is None: + button = None + + return cls((touch, tool, button)) def apply(self, events) -> "PenState": if libevdev.EV_SYN.SYN_REPORT in events: @@ -74,6 +131,8 @@ class PenState(Enum): touch_found = False tool = self.tool tool_found = False + button = self.button + button_found = False for ev in events: if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH): @@ -88,12 +147,22 @@ class PenState(Enum): if tool_found: raise ValueError(f"duplicated BTN_TOOL_* in {events}") tool_found = True - if ev.value: - tool = ToolType(ev.code) - else: - tool = None + tool = ToolType(ev.code) if ev.value else None + elif ev in ( + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS), + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2), + ): + if button_found: + raise ValueError(f"duplicated BTN_STYLUS* in {events}") + button_found = True + button = ev.code if ev.value else None - new_state = PenState((touch, tool)) + # the kernel tends to insert an EV_SYN once removing the tool, so + # the button will be released after + if tool is None: + button = None + + new_state = PenState((touch, tool, button)) assert ( new_state in self.valid_transitions() ), f"moving from {self} to {new_state} is forbidden" @@ -109,14 +178,20 @@ class PenState(Enum): return ( PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, PenState.PEN_IS_ERASING, ) if self == PenState.PEN_IS_IN_RANGE: return ( PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_IN_CONTACT, ) @@ -124,6 +199,8 @@ class PenState(Enum): if self == PenState.PEN_IS_IN_CONTACT: return ( PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_OUT_OF_RANGE, ) @@ -142,6 +219,38 @@ class PenState(Enum): PenState.PEN_IS_OUT_OF_RANGE, ) + if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: + return ( + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + ) + + if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: + return ( + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_OUT_OF_RANGE, + ) + + if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: + return ( + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + ) + + if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: + return ( + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_OUT_OF_RANGE, + ) + return tuple() @staticmethod @@ -376,26 +485,64 @@ class PenDigitizer(base.UHIDTestDevice): pen.xtilt = 0 pen.ytilt = 0 pen.twist = 0 + pen.barrelswitch = False + pen.secondarybarrelswitch = False elif state == PenState.PEN_IS_IN_RANGE: pen.tipswitch = False pen.inrange = True pen.invert = False pen.eraser = False + pen.barrelswitch = False + pen.secondarybarrelswitch = False elif state == PenState.PEN_IS_IN_CONTACT: pen.tipswitch = True pen.inrange = True pen.invert = False pen.eraser = False + pen.barrelswitch = False + pen.secondarybarrelswitch = False + elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: + pen.tipswitch = False + pen.inrange = True + pen.invert = False + pen.eraser = False + pen.barrelswitch = True + pen.secondarybarrelswitch = False + elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: + pen.tipswitch = True + pen.inrange = True + pen.invert = False + pen.eraser = False + pen.barrelswitch = True + pen.secondarybarrelswitch = False + elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: + pen.tipswitch = False + pen.inrange = True + pen.invert = False + pen.eraser = False + pen.barrelswitch = False + pen.secondarybarrelswitch = True + elif state == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: + pen.tipswitch = True + pen.inrange = True + pen.invert = False + pen.eraser = False + pen.barrelswitch = False + pen.secondarybarrelswitch = True elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: pen.tipswitch = False pen.inrange = True pen.invert = True pen.eraser = False + pen.barrelswitch = False + pen.secondarybarrelswitch = False elif state == PenState.PEN_IS_ERASING: pen.tipswitch = False pen.inrange = True pen.invert = False pen.eraser = True + pen.barrelswitch = False + pen.secondarybarrelswitch = False pen.current_state = state From 1f01537ef17efec97a8936c62e4ffa704cab7c06 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:02 +0100 Subject: [PATCH 2997/7721] selftests/hid: tablets: convert the primary button tests We get more descriptive in what we are doing, and also get more information of what is actually being tested. Instead of having a non exhaustive button changes that are semi-randomly done, we can describe all the states we want to test. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-11-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 160 +++++++----------- 1 file changed, 65 insertions(+), 95 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index a77534f23c75..20a7a7fdcd9d 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -317,6 +317,55 @@ class PenState(Enum): ), } + @staticmethod + def legal_transitions_with_primary_button() -> Dict[str, Tuple["PenState", ...]]: + """We revisit the Windows Pen Implementation state machine: + we now have a primary button. + """ + return { + "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,), + "hover-button -> out-of-range": ( + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_OUT_OF_RANGE, + ), + "in-range -> button-press": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + ), + "in-range -> button-press -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> touch -> button-press -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT, + ), + "in-range -> touch -> button-press -> release -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> button-press -> touch -> release -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> button-press -> touch -> button-release -> release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + ), + } + @staticmethod def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: """This is not adhering to the Windows Pen Implementation state machine @@ -671,6 +720,22 @@ class BaseTest: reasons.""" self._test_states(state_list, scribble) + @pytest.mark.skip_if_uhdev( + lambda uhdev: "Barrel Switch" not in uhdev.fields, + "Device not compatible, missing Barrel Switch usage", + ) + @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) + @pytest.mark.parametrize( + "state_list", + [ + pytest.param(v, id=k) + for k, v in PenState.legal_transitions_with_primary_button().items() + ], + ) + def test_valid_primary_button_pen_states(self, state_list, scribble): + """Rework the transition state machine by adding the primary button.""" + self._test_states(state_list, scribble) + @pytest.mark.skip_if_uhdev( lambda uhdev: "Invert" not in uhdev.fields, "Device not compatible, missing Invert usage", @@ -728,101 +793,6 @@ class BaseTest: state machine.""" self._test_states(state_list, scribble) - @pytest.mark.skip_if_uhdev( - lambda uhdev: "Barrel Switch" not in uhdev.fields, - "Device not compatible, missing Barrel Switch usage", - ) - def test_primary_button(self): - """Primary button (stylus) pressed, reports as pressed even while hovering. - Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN): - { 0, 0, 1 } <- hover - { 0, 1, 1 } <- primary button pressed - { 0, 1, 1 } <- liftoff - { 0, 0, 0 } <- leaves - """ - - uhdev = self.uhdev - evdev = uhdev.get_evdev() - - p = Pen(50, 60) - p.inrange = True - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events - assert evdev.value[libevdev.EV_ABS.ABS_X] == 50 - assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60 - assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS] - - p.barrelswitch = True - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events - - p.x += 1 - p.y -= 1 - events = self.post(uhdev, p) - assert len(events) == 3 # X, Y, SYN - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events - - p.barrelswitch = False - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events - - p.inrange = False - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events - - @pytest.mark.skip_if_uhdev( - lambda uhdev: "Barrel Switch" not in uhdev.fields, - "Device not compatible, missing Barrel Switch usage", - ) - def test_contact_primary_button(self): - """Primary button (stylus) pressed, reports as pressed even while hovering. - Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN): - { 0, 0, 1 } <- hover - { 0, 1, 1 } <- primary button pressed - { 1, 1, 1 } <- touch-down - { 1, 1, 1 } <- still touch, scribble on the screen - { 0, 1, 1 } <- liftoff - { 0, 0, 0 } <- leaves - """ - - uhdev = self.uhdev - evdev = uhdev.get_evdev() - - p = Pen(50, 60) - p.inrange = True - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events - assert evdev.value[libevdev.EV_ABS.ABS_X] == 50 - assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60 - assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS] - - p.barrelswitch = True - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events - - p.tipswitch = True - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events - assert evdev.value[libevdev.EV_KEY.BTN_STYLUS] - - p.x += 1 - p.y -= 1 - events = self.post(uhdev, p) - assert len(events) == 3 # X, Y, SYN - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events - - p.tipswitch = False - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events - - p.barrelswitch = False - p.inrange = False - events = self.post(uhdev, p) - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events - class GXTP_pen(PenDigitizer): def event(self, pen): From 76df1f72fb258cc7da6eff5dd8db95f4e2856517 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:03 +0100 Subject: [PATCH 2998/7721] selftests/hid: tablets: add a secondary barrel switch test Some tablets report 2 barrel switches. We better test those too. Use the same transistions description from the primary button tests. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-12-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 20a7a7fdcd9d..a82db66264c5 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -366,6 +366,56 @@ class PenState(Enum): ), } + @staticmethod + def legal_transitions_with_secondary_button() -> Dict[str, Tuple["PenState", ...]]: + """We revisit the Windows Pen Implementation state machine: + we now have a secondary button. + Note: we don't looks for 2 buttons interactions. + """ + return { + "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,), + "hover-button -> out-of-range": ( + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_OUT_OF_RANGE, + ), + "in-range -> button-press": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + ), + "in-range -> button-press -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> touch -> button-press -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT, + ), + "in-range -> touch -> button-press -> release -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> button-press -> touch -> release -> button-release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + ), + "in-range -> button-press -> touch -> button-release -> release": ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE, + ), + } + @staticmethod def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: """This is not adhering to the Windows Pen Implementation state machine @@ -444,6 +494,7 @@ class Pen(object): self.width = 10 self.height = 10 self.barrelswitch = False + self.secondarybarrelswitch = False self.invert = False self.eraser = False self.xtilt = 1 @@ -736,6 +787,22 @@ class BaseTest: """Rework the transition state machine by adding the primary button.""" self._test_states(state_list, scribble) + @pytest.mark.skip_if_uhdev( + lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields, + "Device not compatible, missing Secondary Barrel Switch usage", + ) + @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) + @pytest.mark.parametrize( + "state_list", + [ + pytest.param(v, id=k) + for k, v in PenState.legal_transitions_with_secondary_button().items() + ], + ) + def test_valid_secondary_button_pen_states(self, state_list, scribble): + """Rework the transition state machine by adding the secondary button.""" + self._test_states(state_list, scribble) + @pytest.mark.skip_if_uhdev( lambda uhdev: "Invert" not in uhdev.fields, "Device not compatible, missing Invert usage", From ab9b82909e9baa5b559d6457487525cfd4df2738 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:04 +0100 Subject: [PATCH 2999/7721] selftests/hid: tablets: be stricter for some transitions To accommodate for legacy devices, we rely on the last state of a transition to be valid: for example when we test PEN_IS_OUT_OF_RANGE to PEN_IS_IN_CONTACT, any "normal" device that reports an InRange bit would insert a PEN_IS_IN_RANGE state between the 2. This is of course valid, but this solution prevents to detect false releases emitted by some firmware: when pressing an "eraser mode" button, they might send an extra PEN_IS_OUT_OF_RANGE that we may want to filter. So define 2 sets of transitions: one that is the ideal behavior, and one that is OK, it won't break user space, but we have serious doubts if we are doing the right thing. And depending on the test, either ask only for valid transitions, or tolerate weird ones. Reviewed-by: Peter Hutterer Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-13-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/tests/test_tablet.py | 132 +++++++++++++++--- 1 file changed, 113 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index a82db66264c5..9374bd7524ef 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -13,7 +13,7 @@ from hidtools.util import BusType import libevdev import logging import pytest -from typing import Dict, Optional, Tuple +from typing import Dict, List, Optional, Tuple logger = logging.getLogger("hidtools.test.tablet") @@ -124,7 +124,7 @@ class PenState(Enum): return cls((touch, tool, button)) - def apply(self, events) -> "PenState": + def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState": if libevdev.EV_SYN.SYN_REPORT in events: raise ValueError("EV_SYN is in the event sequence") touch = self.touch @@ -163,13 +163,97 @@ class PenState(Enum): button = None new_state = PenState((touch, tool, button)) - assert ( - new_state in self.valid_transitions() - ), f"moving from {self} to {new_state} is forbidden" + if strict: + assert ( + new_state in self.valid_transitions() + ), f"moving from {self} to {new_state} is forbidden" + else: + assert ( + new_state in self.historically_tolerated_transitions() + ), f"moving from {self} to {new_state} is forbidden" return new_state def valid_transitions(self) -> Tuple["PenState", ...]: + """Following the state machine in the URL above. + + Note that those transitions are from the evdev point of view, not HID""" + if self == PenState.PEN_IS_OUT_OF_RANGE: + return ( + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_ERASING, + ) + + if self == PenState.PEN_IS_IN_RANGE: + return ( + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_CONTACT, + ) + + if self == PenState.PEN_IS_IN_CONTACT: + return ( + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + ) + + if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: + return ( + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_ERASING, + ) + + if self == PenState.PEN_IS_ERASING: + return ( + PenState.PEN_IS_ERASING, + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, + ) + + if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: + return ( + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + ) + + if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: + return ( + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, + ) + + if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: + return ( + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_RANGE, + PenState.PEN_IS_OUT_OF_RANGE, + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + ) + + if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: + return ( + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, + PenState.PEN_IS_IN_CONTACT, + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, + ) + + return tuple() + + def historically_tolerated_transitions(self) -> Tuple["PenState", ...]: """Following the state machine in the URL above, with a couple of addition for skipping the in-range state, due to historical reasons. @@ -693,10 +777,14 @@ class BaseTest: self.debug_reports(r, uhdev, events) return events - def validate_transitions(self, from_state, pen, evdev, events): + def validate_transitions( + self, from_state, pen, evdev, events, allow_intermediate_states + ): # check that the final state is correct pen.assert_expected_input_events(evdev) + state = from_state + # check that the transitions are valid sync_events = [] while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events: @@ -706,12 +794,12 @@ class BaseTest: events = events[idx + 1 :] # now check for a valid transition - from_state = from_state.apply(sync_events) + state = state.apply(sync_events, not allow_intermediate_states) if events: - from_state = from_state.apply(sync_events) + state = state.apply(sync_events, not allow_intermediate_states) - def _test_states(self, state_list, scribble): + def _test_states(self, state_list, scribble, allow_intermediate_states): """Internal method to test against a list of transition between states. state_list is a list of PenState objects @@ -726,7 +814,9 @@ class BaseTest: p = Pen(50, 60) uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE) events = self.post(uhdev, p) - self.validate_transitions(cur_state, p, evdev, events) + self.validate_transitions( + cur_state, p, evdev, events, allow_intermediate_states + ) cur_state = p.current_state @@ -735,14 +825,18 @@ class BaseTest: p.x += 1 p.y -= 1 events = self.post(uhdev, p) - self.validate_transitions(cur_state, p, evdev, events) + self.validate_transitions( + cur_state, p, evdev, events, allow_intermediate_states + ) assert len(events) >= 3 # X, Y, SYN uhdev.move_to(p, state) if scribble and state != PenState.PEN_IS_OUT_OF_RANGE: p.x += 1 p.y -= 1 events = self.post(uhdev, p) - self.validate_transitions(cur_state, p, evdev, events) + self.validate_transitions( + cur_state, p, evdev, events, allow_intermediate_states + ) cur_state = p.current_state @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) @@ -755,7 +849,7 @@ class BaseTest: we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states """ - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=False) @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) @pytest.mark.parametrize( @@ -769,7 +863,7 @@ class BaseTest: """This is not adhering to the Windows Pen Implementation state machine but we should expect the kernel to behave properly, mostly for historical reasons.""" - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=True) @pytest.mark.skip_if_uhdev( lambda uhdev: "Barrel Switch" not in uhdev.fields, @@ -785,7 +879,7 @@ class BaseTest: ) def test_valid_primary_button_pen_states(self, state_list, scribble): """Rework the transition state machine by adding the primary button.""" - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=False) @pytest.mark.skip_if_uhdev( lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields, @@ -801,7 +895,7 @@ class BaseTest: ) def test_valid_secondary_button_pen_states(self, state_list, scribble): """Rework the transition state machine by adding the secondary button.""" - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=False) @pytest.mark.skip_if_uhdev( lambda uhdev: "Invert" not in uhdev.fields, @@ -821,7 +915,7 @@ class BaseTest: to erase. https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states """ - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=False) @pytest.mark.skip_if_uhdev( lambda uhdev: "Invert" not in uhdev.fields, @@ -841,7 +935,7 @@ class BaseTest: to erase. https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states """ - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=True) @pytest.mark.skip_if_uhdev( lambda uhdev: "Invert" not in uhdev.fields, @@ -858,7 +952,7 @@ class BaseTest: For example, a pen that has the eraser button might wobble between touching and erasing if the tablet doesn't enforce the Windows state machine.""" - self._test_states(state_list, scribble) + self._test_states(state_list, scribble, allow_intermediate_states=True) class GXTP_pen(PenDigitizer): From ed5bc56cedca19ac429533aa527bce5287ab0a5a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:05 +0100 Subject: [PATCH 3000/7721] selftests/hid: fix mypy complains No code change, only typing information added/ignored Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-14-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/base.py | 4 ++-- tools/testing/selftests/hid/tests/test_tablet.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/hid/tests/base.py b/tools/testing/selftests/hid/tests/base.py index 5d9c26dfc460..51433063b227 100644 --- a/tools/testing/selftests/hid/tests/base.py +++ b/tools/testing/selftests/hid/tests/base.py @@ -14,7 +14,7 @@ import logging from hidtools.device.base_device import BaseDevice, EvdevMatch, SysfsFile from pathlib import Path -from typing import Final +from typing import Final, List, Tuple logger = logging.getLogger("hidtools.test.base") @@ -155,7 +155,7 @@ class BaseTestCase: # if any module is not available (not compiled), the test will skip. # Each element is a tuple '(kernel driver name, kernel module)', # for example ("playstation", "hid-playstation") - kernel_modules = [] + kernel_modules: List[Tuple[str, str]] = [] def assertInputEventsIn(self, expected_events, effective_events): effective_events = effective_events.copy() diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 9374bd7524ef..dc8b0fe9e7f3 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -87,9 +87,9 @@ class PenState(Enum): ) def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]): - self.touch = touch - self.tool = tool - self.button = button + self.touch = touch # type: ignore + self.tool = tool # type: ignore + self.button = button # type: ignore @classmethod def from_evdev(cls, evdev) -> "PenState": @@ -122,7 +122,7 @@ class PenState(Enum): if tool is None: button = None - return cls((touch, tool, button)) + return cls((touch, tool, button)) # type: ignore def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState": if libevdev.EV_SYN.SYN_REPORT in events: @@ -162,7 +162,7 @@ class PenState(Enum): if tool is None: button = None - new_state = PenState((touch, tool, button)) + new_state = PenState((touch, tool, button)) # type: ignore if strict: assert ( new_state in self.valid_transitions() From f556aa957df8cb3e98af0f54bf1fa65f59ae47a3 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Dec 2023 11:46:06 +0100 Subject: [PATCH 3001/7721] selftests/hid: fix ruff linter complains rename ambiguous variables l, r, and m, and ignore the return values of uhdev.get_evdev() and uhdev.get_slot() Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-15-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/test_mouse.py | 14 +++++++------- .../selftests/hid/tests/test_wacom_generic.py | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_mouse.py b/tools/testing/selftests/hid/tests/test_mouse.py index fd2ba62e783a..66daf7e5975c 100644 --- a/tools/testing/selftests/hid/tests/test_mouse.py +++ b/tools/testing/selftests/hid/tests/test_mouse.py @@ -52,13 +52,13 @@ class BaseMouse(base.UHIDTestDevice): :param reportID: the numeric report ID for this report, if needed """ if buttons is not None: - l, r, m = buttons - if l is not None: - self.left = l - if r is not None: - self.right = r - if m is not None: - self.middle = m + left, right, middle = buttons + if left is not None: + self.left = left + if right is not None: + self.right = right + if middle is not None: + self.middle = middle left = self.left right = self.right middle = self.middle diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py index f92fe8e02c1b..49186a27467e 100644 --- a/tools/testing/selftests/hid/tests/test_wacom_generic.py +++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py @@ -909,7 +909,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest Ensure that the confidence bit being set to false should not result in a touch event. """ uhdev = self.uhdev - evdev = uhdev.get_evdev() + _evdev = uhdev.get_evdev() t0 = test_multitouch.Touch(1, 50, 100) t0.confidence = False @@ -917,6 +917,6 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest events = uhdev.next_sync_events() self.debug_reports(r, uhdev, events) - slot = self.get_slot(uhdev, t0, 0) + _slot = self.get_slot(uhdev, t0, 0) - assert not events \ No newline at end of file + assert not events From fa422b353d212373fb2b2857a5ea5a6fa4876f9c Mon Sep 17 00:00:00 2001 From: Shiyang Ruan Date: Mon, 23 Oct 2023 15:20:46 +0800 Subject: [PATCH 3002/7721] mm, pmem, xfs: Introduce MF_MEM_PRE_REMOVE for unbind Now, if we suddenly remove a PMEM device(by calling unbind) which contains FSDAX while programs are still accessing data in this device, e.g.: ``` $FSSTRESS_PROG -d $SCRATCH_MNT -n 99999 -p 4 & # $FSX_PROG -N 1000000 -o 8192 -l 500000 $SCRATCH_MNT/t001 & echo "pfn1.1" > /sys/bus/nd/drivers/nd_pmem/unbind ``` it could come into an unacceptable state: 1. device has gone but mount point still exists, and umount will fail with "target is busy" 2. programs will hang and cannot be killed 3. may crash with NULL pointer dereference To fix this, we introduce a MF_MEM_PRE_REMOVE flag to let it know that we are going to remove the whole device, and make sure all related processes could be notified so that they could end up gracefully. This patch is inspired by Dan's "mm, dax, pmem: Introduce dev_pagemap_failure()"[1]. With the help of dax_holder and ->notify_failure() mechanism, the pmem driver is able to ask filesystem on it to unmap all files in use, and notify processes who are using those files. Call trace: trigger unbind -> unbind_store() -> ... (skip) -> devres_release_all() -> kill_dax() -> dax_holder_notify_failure(dax_dev, 0, U64_MAX, MF_MEM_PRE_REMOVE) -> xfs_dax_notify_failure() `-> freeze_super() // freeze (kernel call) `-> do xfs rmap ` -> mf_dax_kill_procs() ` -> collect_procs_fsdax() // all associated processes ` -> unmap_and_kill() ` -> invalidate_inode_pages2_range() // drop file's cache `-> thaw_super() // thaw (both kernel & user call) Introduce MF_MEM_PRE_REMOVE to let filesystem know this is a remove event. Use the exclusive freeze/thaw[2] to lock the filesystem to prevent new dax mapping from being created. Do not shutdown filesystem directly if configuration is not supported, or if failure range includes metadata area. Make sure all files and processes(not only the current progress) are handled correctly. Also drop the cache of associated files before pmem is removed. [1]: https://lore.kernel.org/linux-mm/161604050314.1463742.14151665140035795571.stgit@dwillia2-desk3.amr.corp.intel.com/ [2]: https://lore.kernel.org/linux-xfs/169116275623.3187159.16862410128731457358.stg-ugh@frogsfrogsfrogs/ Signed-off-by: Shiyang Ruan Reviewed-by: Darrick J. Wong Reviewed-by: Dan Williams Signed-off-by: Chandan Babu R --- drivers/dax/super.c | 3 +- fs/xfs/xfs_notify_failure.c | 108 ++++++++++++++++++++++++++++++++++-- include/linux/mm.h | 1 + mm/memory-failure.c | 21 +++++-- 4 files changed, 122 insertions(+), 11 deletions(-) diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 0da9232ea175..f4b635526345 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -326,7 +326,8 @@ void kill_dax(struct dax_device *dax_dev) return; if (dax_dev->holder_data != NULL) - dax_holder_notify_failure(dax_dev, 0, U64_MAX, 0); + dax_holder_notify_failure(dax_dev, 0, U64_MAX, + MF_MEM_PRE_REMOVE); clear_bit(DAXDEV_ALIVE, &dax_dev->flags); synchronize_srcu(&dax_srcu); diff --git a/fs/xfs/xfs_notify_failure.c b/fs/xfs/xfs_notify_failure.c index a7daa522e00f..fa50e5308292 100644 --- a/fs/xfs/xfs_notify_failure.c +++ b/fs/xfs/xfs_notify_failure.c @@ -22,6 +22,7 @@ #include #include +#include struct xfs_failure_info { xfs_agblock_t startblock; @@ -73,10 +74,16 @@ xfs_dax_failure_fn( struct xfs_mount *mp = cur->bc_mp; struct xfs_inode *ip; struct xfs_failure_info *notify = data; + struct address_space *mapping; + pgoff_t pgoff; + unsigned long pgcnt; int error = 0; if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) { + /* Continue the query because this isn't a failure. */ + if (notify->mf_flags & MF_MEM_PRE_REMOVE) + return 0; notify->want_shutdown = true; return 0; } @@ -92,14 +99,60 @@ xfs_dax_failure_fn( return 0; } - error = mf_dax_kill_procs(VFS_I(ip)->i_mapping, - xfs_failure_pgoff(mp, rec, notify), - xfs_failure_pgcnt(mp, rec, notify), - notify->mf_flags); + mapping = VFS_I(ip)->i_mapping; + pgoff = xfs_failure_pgoff(mp, rec, notify); + pgcnt = xfs_failure_pgcnt(mp, rec, notify); + + /* Continue the rmap query if the inode isn't a dax file. */ + if (dax_mapping(mapping)) + error = mf_dax_kill_procs(mapping, pgoff, pgcnt, + notify->mf_flags); + + /* Invalidate the cache in dax pages. */ + if (notify->mf_flags & MF_MEM_PRE_REMOVE) + invalidate_inode_pages2_range(mapping, pgoff, + pgoff + pgcnt - 1); + xfs_irele(ip); return error; } +static int +xfs_dax_notify_failure_freeze( + struct xfs_mount *mp) +{ + struct super_block *sb = mp->m_super; + int error; + + error = freeze_super(sb, FREEZE_HOLDER_KERNEL); + if (error) + xfs_emerg(mp, "already frozen by kernel, err=%d", error); + + return error; +} + +static void +xfs_dax_notify_failure_thaw( + struct xfs_mount *mp, + bool kernel_frozen) +{ + struct super_block *sb = mp->m_super; + int error; + + if (kernel_frozen) { + error = thaw_super(sb, FREEZE_HOLDER_KERNEL); + if (error) + xfs_emerg(mp, "still frozen after notify failure, err=%d", + error); + } + + /* + * Also thaw userspace call anyway because the device is about to be + * removed immediately. + */ + thaw_super(sb, FREEZE_HOLDER_USERSPACE); +} + static int xfs_dax_notify_ddev_failure( struct xfs_mount *mp, @@ -112,15 +165,29 @@ xfs_dax_notify_ddev_failure( struct xfs_btree_cur *cur = NULL; struct xfs_buf *agf_bp = NULL; int error = 0; + bool kernel_frozen = false; xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr); xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen - 1); xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno); + if (mf_flags & MF_MEM_PRE_REMOVE) { + xfs_info(mp, "Device is about to be removed!"); + /* + * Freeze fs to prevent new mappings from being created. + * - Keep going on if others already hold the kernel forzen. + * - Keep going on if other errors too because this device is + * starting to fail. + * - If kernel frozen state is hold successfully here, thaw it + * here as well at the end. + */ + kernel_frozen = xfs_dax_notify_failure_freeze(mp) == 0; + } + error = xfs_trans_alloc_empty(mp, &tp); if (error) - return error; + goto out; for (; agno <= end_agno; agno++) { struct xfs_rmap_irec ri_low = { }; @@ -165,11 +232,26 @@ xfs_dax_notify_ddev_failure( } xfs_trans_cancel(tp); - if (error || notify.want_shutdown) { + + /* + * Shutdown fs from a force umount in pre-remove case which won't fail, + * so errors can be ignored. Otherwise, shutdown the filesystem with + * CORRUPT flag if error occured or notify.want_shutdown was set during + * RMAP querying. + */ + if (mf_flags & MF_MEM_PRE_REMOVE) + xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); + else if (error || notify.want_shutdown) { xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); if (!error) error = -EFSCORRUPTED; } + +out: + /* Thaw the fs if it has been frozen before. */ + if (mf_flags & MF_MEM_PRE_REMOVE) + xfs_dax_notify_failure_thaw(mp, kernel_frozen); + return error; } @@ -197,6 +279,14 @@ xfs_dax_notify_failure( if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev && mp->m_logdev_targp != mp->m_ddev_targp) { + /* + * In the pre-remove case the failure notification is attempting + * to trigger a force unmount. The expectation is that the + * device is still present, but its removal is in progress and + * can not be cancelled, proceed with accessing the log device. + */ + if (mf_flags & MF_MEM_PRE_REMOVE) + return 0; xfs_err(mp, "ondisk log corrupt, shutting down fs!"); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); return -EFSCORRUPTED; @@ -210,6 +300,12 @@ xfs_dax_notify_failure( ddev_start = mp->m_ddev_targp->bt_dax_part_off; ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1; + /* Notify failure on the whole device. */ + if (offset == 0 && len == U64_MAX) { + offset = ddev_start; + len = bdev_nr_bytes(mp->m_ddev_targp->bt_bdev); + } + /* Ignore the range out of filesystem area */ if (offset + len - 1 < ddev_start) return -ENXIO; diff --git a/include/linux/mm.h b/include/linux/mm.h index 418d26608ece..caf13e94260e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3904,6 +3904,7 @@ enum mf_flags { MF_UNPOISON = 1 << 4, MF_SW_SIMULATED = 1 << 5, MF_NO_RETRY = 1 << 6, + MF_MEM_PRE_REMOVE = 1 << 7, }; int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index, unsigned long count, int mf_flags); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 660c21859118..cff3bda60691 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -679,7 +679,7 @@ static void add_to_kill_fsdax(struct task_struct *tsk, struct page *p, */ static void collect_procs_fsdax(struct page *page, struct address_space *mapping, pgoff_t pgoff, - struct list_head *to_kill) + struct list_head *to_kill, bool pre_remove) { struct vm_area_struct *vma; struct task_struct *tsk; @@ -687,8 +687,15 @@ static void collect_procs_fsdax(struct page *page, i_mmap_lock_read(mapping); rcu_read_lock(); for_each_process(tsk) { - struct task_struct *t = task_early_kill(tsk, true); + struct task_struct *t = tsk; + /* + * Search for all tasks while MF_MEM_PRE_REMOVE is set, because + * the current may not be the one accessing the fsdax page. + * Otherwise, search for the current task. + */ + if (!pre_remove) + t = task_early_kill(tsk, true); if (!t) continue; vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) { @@ -1795,6 +1802,7 @@ int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index, dax_entry_t cookie; struct page *page; size_t end = index + count; + bool pre_remove = mf_flags & MF_MEM_PRE_REMOVE; mf_flags |= MF_ACTION_REQUIRED | MF_MUST_KILL; @@ -1806,9 +1814,14 @@ int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index, if (!page) goto unlock; - SetPageHWPoison(page); + if (!pre_remove) + SetPageHWPoison(page); - collect_procs_fsdax(page, mapping, index, &to_kill); + /* + * The pre_remove case is revoking access, the memory is still + * good and could theoretically be put back into service. + */ + collect_procs_fsdax(page, mapping, index, &to_kill, pre_remove); unmap_and_kill(&to_kill, page_to_pfn(page), mapping, index, mf_flags); unlock: From 011f129fee4bd064a3db30ca1a0139548a619482 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Wed, 29 Nov 2023 19:39:47 +0700 Subject: [PATCH 3003/7721] Documentation: xfs: consolidate XFS docs into its own subdirectory XFS docs are currently in upper-level Documentation/filesystems. Although these are currently 4 docs, they are already outstanding as a group and can be moved to its own subdirectory. Consolidate them into Documentation/filesystems/xfs/. Signed-off-by: Bagas Sanjaya Reviewed-by: Bill O'Donnell Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- Documentation/filesystems/index.rst | 5 +---- Documentation/filesystems/xfs/index.rst | 14 ++++++++++++++ .../{ => xfs}/xfs-delayed-logging-design.rst | 0 .../{ => xfs}/xfs-maintainer-entry-profile.rst | 0 .../{ => xfs}/xfs-online-fsck-design.rst | 2 +- .../{ => xfs}/xfs-self-describing-metadata.rst | 0 .../maintainer/maintainer-entry-profile.rst | 2 +- MAINTAINERS | 4 ++-- 8 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 Documentation/filesystems/xfs/index.rst rename Documentation/filesystems/{ => xfs}/xfs-delayed-logging-design.rst (100%) rename Documentation/filesystems/{ => xfs}/xfs-maintainer-entry-profile.rst (100%) rename Documentation/filesystems/{ => xfs}/xfs-online-fsck-design.rst (99%) rename Documentation/filesystems/{ => xfs}/xfs-self-describing-metadata.rst (100%) diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index 09cade7eaefc..e18bc5ae3b35 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -121,8 +121,5 @@ Documentation for filesystem implementations. udf virtiofs vfat - xfs-delayed-logging-design - xfs-maintainer-entry-profile - xfs-self-describing-metadata - xfs-online-fsck-design + xfs/index zonefs diff --git a/Documentation/filesystems/xfs/index.rst b/Documentation/filesystems/xfs/index.rst new file mode 100644 index 000000000000..ab66c57a5d18 --- /dev/null +++ b/Documentation/filesystems/xfs/index.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================ +XFS Filesystem Documentation +============================ + +.. toctree:: + :maxdepth: 2 + :numbered: + + xfs-delayed-logging-design + xfs-maintainer-entry-profile + xfs-self-describing-metadata + xfs-online-fsck-design diff --git a/Documentation/filesystems/xfs-delayed-logging-design.rst b/Documentation/filesystems/xfs/xfs-delayed-logging-design.rst similarity index 100% rename from Documentation/filesystems/xfs-delayed-logging-design.rst rename to Documentation/filesystems/xfs/xfs-delayed-logging-design.rst diff --git a/Documentation/filesystems/xfs-maintainer-entry-profile.rst b/Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst similarity index 100% rename from Documentation/filesystems/xfs-maintainer-entry-profile.rst rename to Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst diff --git a/Documentation/filesystems/xfs-online-fsck-design.rst b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst similarity index 99% rename from Documentation/filesystems/xfs-online-fsck-design.rst rename to Documentation/filesystems/xfs/xfs-online-fsck-design.rst index a0678101a7d0..352516feef6f 100644 --- a/Documentation/filesystems/xfs-online-fsck-design.rst +++ b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst @@ -962,7 +962,7 @@ disk, but these buffer verifiers cannot provide any consistency checking between metadata structures. For more information, please see the documentation for -Documentation/filesystems/xfs-self-describing-metadata.rst +Documentation/filesystems/xfs/xfs-self-describing-metadata.rst Reverse Mapping --------------- diff --git a/Documentation/filesystems/xfs-self-describing-metadata.rst b/Documentation/filesystems/xfs/xfs-self-describing-metadata.rst similarity index 100% rename from Documentation/filesystems/xfs-self-describing-metadata.rst rename to Documentation/filesystems/xfs/xfs-self-describing-metadata.rst diff --git a/Documentation/maintainer/maintainer-entry-profile.rst b/Documentation/maintainer/maintainer-entry-profile.rst index 7ad4bfc2cc03..18cee1edaecb 100644 --- a/Documentation/maintainer/maintainer-entry-profile.rst +++ b/Documentation/maintainer/maintainer-entry-profile.rst @@ -105,4 +105,4 @@ to do something different in the near future. ../driver-api/media/maintainer-entry-profile ../driver-api/vfio-pci-device-specific-driver-acceptance ../nvme/feature-and-quirk-policy - ../filesystems/xfs-maintainer-entry-profile + ../filesystems/xfs/xfs-maintainer-entry-profile diff --git a/MAINTAINERS b/MAINTAINERS index 788be9ab5b73..76896b511c6a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23894,10 +23894,10 @@ S: Supported W: http://xfs.org/ C: irc://irc.oftc.net/xfs T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git -P: Documentation/filesystems/xfs-maintainer-entry-profile.rst +P: Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst F: Documentation/ABI/testing/sysfs-fs-xfs F: Documentation/admin-guide/xfs.rst -F: Documentation/filesystems/xfs-* +F: Documentation/filesystems/xfs/* F: fs/xfs/ F: include/uapi/linux/dqblk_xfs.h F: include/uapi/linux/fsmap.h From 64f08b152a3bc171f4651271bfe973ad3d085ab6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 18:40:54 +0100 Subject: [PATCH 3004/7721] xfs: clean up the XFS_IOC_{GS}ET_RESBLKS handler The XFS_IOC_GET_RESBLKS and XFS_IOC_SET_RESBLKS already share a fair amount of code, and will share even more soon. Move the logic for both of them out of the main xfs_file_ioctl function into a xfs_ioctl_getset_resblocks helper to share the code and prepare for additional changes. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/xfs_ioctl.c | 87 +++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 6c3919687ea6..7edc1d892f0c 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1872,6 +1872,46 @@ xfs_fs_eofblocks_from_user( return 0; } +static int +xfs_ioctl_getset_resblocks( + struct file *filp, + unsigned int cmd, + void __user *arg) +{ + struct xfs_mount *mp = XFS_I(file_inode(filp))->i_mount; + struct xfs_fsop_resblks fsop = { }; + int error; + uint64_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (cmd == XFS_IOC_SET_RESBLKS) { + if (xfs_is_readonly(mp)) + return -EROFS; + + if (copy_from_user(&fsop, arg, sizeof(fsop))) + return -EFAULT; + + error = mnt_want_write_file(filp); + if (error) + return error; + in = fsop.resblks; + error = xfs_reserve_blocks(mp, &in, &fsop); + mnt_drop_write_file(filp); + if (error) + return error; + } else { + error = xfs_reserve_blocks(mp, NULL, &fsop); + if (error) + return error; + } + + if (copy_to_user(arg, &fsop, sizeof(fsop))) + return -EFAULT; + return 0; +} + /* * These long-unused ioctls were removed from the official ioctl API in 5.17, * but retain these definitions so that we can log warnings about them. @@ -2018,50 +2058,9 @@ xfs_file_ioctl( return 0; } - case XFS_IOC_SET_RESBLKS: { - xfs_fsop_resblks_t inout; - uint64_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (xfs_is_readonly(mp)) - return -EROFS; - - if (copy_from_user(&inout, arg, sizeof(inout))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - - /* input parameter is passed in resblks field of structure */ - in = inout.resblks; - error = xfs_reserve_blocks(mp, &in, &inout); - mnt_drop_write_file(filp); - if (error) - return error; - - if (copy_to_user(arg, &inout, sizeof(inout))) - return -EFAULT; - return 0; - } - - case XFS_IOC_GET_RESBLKS: { - xfs_fsop_resblks_t out; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - error = xfs_reserve_blocks(mp, NULL, &out); - if (error) - return error; - - if (copy_to_user(arg, &out, sizeof(out))) - return -EFAULT; - - return 0; - } + case XFS_IOC_SET_RESBLKS: + case XFS_IOC_GET_RESBLKS: + return xfs_ioctl_getset_resblocks(filp, cmd, arg); case XFS_IOC_FSGROWFSDATA: { struct xfs_growfs_data in; From c2c2620de7577db66a859b934715e98e4501e4f4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 18:40:55 +0100 Subject: [PATCH 3005/7721] xfs: clean up the XFS_IOC_FSCOUNTS handler Split XFS_IOC_FSCOUNTS out of the main xfs_file_ioctl function, and merge the xfs_fs_counts helper into the ioctl handler. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/xfs_fsops.c | 16 ---------------- fs/xfs/xfs_fsops.h | 1 - fs/xfs/xfs_ioctl.c | 29 ++++++++++++++++++++--------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 7cb75cb6b8e9..01681783e2c3 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -343,22 +343,6 @@ xfs_growfs_log( return error; } -/* - * exported through ioctl XFS_IOC_FSCOUNTS - */ - -void -xfs_fs_counts( - xfs_mount_t *mp, - xfs_fsop_counts_t *cnt) -{ - cnt->allocino = percpu_counter_read_positive(&mp->m_icount); - cnt->freeino = percpu_counter_read_positive(&mp->m_ifree); - cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) - - xfs_fdblocks_unavailable(mp); - cnt->freertx = percpu_counter_read_positive(&mp->m_frextents); -} - /* * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS * diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h index 2cffe51a31e8..45f0cb6e8059 100644 --- a/fs/xfs/xfs_fsops.h +++ b/fs/xfs/xfs_fsops.h @@ -8,7 +8,6 @@ extern int xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in); extern int xfs_growfs_log(struct xfs_mount *mp, struct xfs_growfs_log *in); -extern void xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt); extern int xfs_reserve_blocks(xfs_mount_t *mp, uint64_t *inval, xfs_fsop_resblks_t *outval); extern int xfs_fs_goingdown(xfs_mount_t *mp, uint32_t inflags); diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 7edc1d892f0c..8244210f6786 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1912,6 +1912,24 @@ xfs_ioctl_getset_resblocks( return 0; } +static int +xfs_ioctl_fs_counts( + struct xfs_mount *mp, + struct xfs_fsop_counts __user *uarg) +{ + struct xfs_fsop_counts out = { + .allocino = percpu_counter_read_positive(&mp->m_icount), + .freeino = percpu_counter_read_positive(&mp->m_ifree), + .freedata = percpu_counter_read_positive(&mp->m_fdblocks) - + xfs_fdblocks_unavailable(mp), + .freertx = percpu_counter_read_positive(&mp->m_frextents), + }; + + if (copy_to_user(uarg, &out, sizeof(out))) + return -EFAULT; + return 0; +} + /* * These long-unused ioctls were removed from the official ioctl API in 5.17, * but retain these definitions so that we can log warnings about them. @@ -2048,15 +2066,8 @@ xfs_file_ioctl( return error; } - case XFS_IOC_FSCOUNTS: { - xfs_fsop_counts_t out; - - xfs_fs_counts(mp, &out); - - if (copy_to_user(arg, &out, sizeof(out))) - return -EFAULT; - return 0; - } + case XFS_IOC_FSCOUNTS: + return xfs_ioctl_fs_counts(mp, arg); case XFS_IOC_SET_RESBLKS: case XFS_IOC_GET_RESBLKS: From 646ddf0c4df5181a7057ecccd29e535baaf034b2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 18:40:56 +0100 Subject: [PATCH 3006/7721] xfs: clean up the xfs_reserve_blocks interface xfs_reserve_blocks has a very odd interface that can only be explained by it directly deriving from the IRIX fcntl handler back in the day. Split reporting out the reserved blocks out of xfs_reserve_blocks into the only caller that cares. This means that the value reported from XFS_IOC_SET_RESBLKS isn't atomically sampled in the same critical section as when it was set anymore, but as the values could change right after setting them anyway that does not matter. It does provide atomic sampling of both values for XFS_IOC_GET_RESBLKS now, though. Also pass a normal scalar integer value for the requested value instead of the pointless pointer. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/xfs_fsops.c | 34 +++------------------------------- fs/xfs/xfs_fsops.h | 3 +-- fs/xfs/xfs_ioctl.c | 13 ++++++------- fs/xfs/xfs_mount.c | 8 ++------ fs/xfs/xfs_super.c | 6 ++---- 5 files changed, 14 insertions(+), 50 deletions(-) diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 01681783e2c3..4f5da19142f2 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -344,43 +344,20 @@ xfs_growfs_log( } /* - * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS - * - * xfs_reserve_blocks is called to set m_resblks - * in the in-core mount table. The number of unused reserved blocks - * is kept in m_resblks_avail. - * * Reserve the requested number of blocks if available. Otherwise return * as many as possible to satisfy the request. The actual number - * reserved are returned in outval - * - * A null inval pointer indicates that only the current reserved blocks - * available should be returned no settings are changed. + * reserved are returned in outval. */ - int xfs_reserve_blocks( - xfs_mount_t *mp, - uint64_t *inval, - xfs_fsop_resblks_t *outval) + struct xfs_mount *mp, + uint64_t request) { int64_t lcounter, delta; int64_t fdblks_delta = 0; - uint64_t request; int64_t free; int error = 0; - /* If inval is null, report current values and return */ - if (inval == (uint64_t *)NULL) { - if (!outval) - return -EINVAL; - outval->resblks = mp->m_resblks; - outval->resblks_avail = mp->m_resblks_avail; - return 0; - } - - request = *inval; - /* * With per-cpu counters, this becomes an interesting problem. we need * to work out if we are freeing or allocation blocks first, then we can @@ -450,11 +427,6 @@ xfs_reserve_blocks( spin_lock(&mp->m_sb_lock); } out: - if (outval) { - outval->resblks = mp->m_resblks; - outval->resblks_avail = mp->m_resblks_avail; - } - spin_unlock(&mp->m_sb_lock); return error; } diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h index 45f0cb6e8059..7536f8a92746 100644 --- a/fs/xfs/xfs_fsops.h +++ b/fs/xfs/xfs_fsops.h @@ -8,8 +8,7 @@ extern int xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in); extern int xfs_growfs_log(struct xfs_mount *mp, struct xfs_growfs_log *in); -extern int xfs_reserve_blocks(xfs_mount_t *mp, uint64_t *inval, - xfs_fsop_resblks_t *outval); +int xfs_reserve_blocks(struct xfs_mount *mp, uint64_t request); extern int xfs_fs_goingdown(xfs_mount_t *mp, uint32_t inflags); extern int xfs_fs_reserve_ag_blocks(struct xfs_mount *mp); diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 8244210f6786..f02b6e558af5 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1881,7 +1881,6 @@ xfs_ioctl_getset_resblocks( struct xfs_mount *mp = XFS_I(file_inode(filp))->i_mount; struct xfs_fsop_resblks fsop = { }; int error; - uint64_t in; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1896,17 +1895,17 @@ xfs_ioctl_getset_resblocks( error = mnt_want_write_file(filp); if (error) return error; - in = fsop.resblks; - error = xfs_reserve_blocks(mp, &in, &fsop); + error = xfs_reserve_blocks(mp, fsop.resblks); mnt_drop_write_file(filp); if (error) return error; - } else { - error = xfs_reserve_blocks(mp, NULL, &fsop); - if (error) - return error; } + spin_lock(&mp->m_sb_lock); + fsop.resblks = mp->m_resblks; + fsop.resblks_avail = mp->m_resblks_avail; + spin_unlock(&mp->m_sb_lock); + if (copy_to_user(arg, &fsop, sizeof(fsop))) return -EFAULT; return 0; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index aed5be5508fe..aabb25dc3efa 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -637,7 +637,6 @@ xfs_mountfs( struct xfs_sb *sbp = &(mp->m_sb); struct xfs_inode *rip; struct xfs_ino_geometry *igeo = M_IGEO(mp); - uint64_t resblks; uint quotamount = 0; uint quotaflags = 0; int error = 0; @@ -974,8 +973,7 @@ xfs_mountfs( * we were already there on the last unmount. Warn if this occurs. */ if (!xfs_is_readonly(mp)) { - resblks = xfs_default_resblks(mp); - error = xfs_reserve_blocks(mp, &resblks, NULL); + error = xfs_reserve_blocks(mp, xfs_default_resblks(mp)); if (error) xfs_warn(mp, "Unable to allocate reserve blocks. Continuing without reserve pool."); @@ -1053,7 +1051,6 @@ void xfs_unmountfs( struct xfs_mount *mp) { - uint64_t resblks; int error; /* @@ -1090,8 +1087,7 @@ xfs_unmountfs( * we only every apply deltas to the superblock and hence the incore * value does not matter.... */ - resblks = 0; - error = xfs_reserve_blocks(mp, &resblks, NULL); + error = xfs_reserve_blocks(mp, 0); if (error) xfs_warn(mp, "Unable to free reserved block pool. " "Freespace may not be correct on next mount."); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 764304595e8b..d0009430a627 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -906,10 +906,8 @@ xfs_fs_statfs( STATIC void xfs_save_resvblks(struct xfs_mount *mp) { - uint64_t resblks = 0; - mp->m_resblks_save = mp->m_resblks; - xfs_reserve_blocks(mp, &resblks, NULL); + xfs_reserve_blocks(mp, 0); } STATIC void @@ -923,7 +921,7 @@ xfs_restore_resvblks(struct xfs_mount *mp) } else resblks = xfs_default_resblks(mp); - xfs_reserve_blocks(mp, &resblks, NULL); + xfs_reserve_blocks(mp, resblks); } /* From 08e54ca42d6a0d88709a1be38eb95843142b5101 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 18:40:57 +0100 Subject: [PATCH 3007/7721] xfs: clean up xfs_fsops.h Use struct types instead of typedefs so that the header can be included with pulling in the headers that define the typedefs, and remove the pointless externs. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/xfs_fsops.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h index 7536f8a92746..44457b0a0593 100644 --- a/fs/xfs/xfs_fsops.h +++ b/fs/xfs/xfs_fsops.h @@ -6,12 +6,12 @@ #ifndef __XFS_FSOPS_H__ #define __XFS_FSOPS_H__ -extern int xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in); -extern int xfs_growfs_log(struct xfs_mount *mp, struct xfs_growfs_log *in); +int xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in); +int xfs_growfs_log(struct xfs_mount *mp, struct xfs_growfs_log *in); int xfs_reserve_blocks(struct xfs_mount *mp, uint64_t request); -extern int xfs_fs_goingdown(xfs_mount_t *mp, uint32_t inflags); +int xfs_fs_goingdown(struct xfs_mount *mp, uint32_t inflags); -extern int xfs_fs_reserve_ag_blocks(struct xfs_mount *mp); -extern int xfs_fs_unreserve_ag_blocks(struct xfs_mount *mp); +int xfs_fs_reserve_ag_blocks(struct xfs_mount *mp); +int xfs_fs_unreserve_ag_blocks(struct xfs_mount *mp); #endif /* __XFS_FSOPS_H__ */ From e6af9c98cbf0164a619d95572136bfb54d482dd6 Mon Sep 17 00:00:00 2001 From: Jiachen Zhang Date: Tue, 5 Dec 2023 13:58:58 +0800 Subject: [PATCH 3008/7721] xfs: ensure logflagsp is initialized in xfs_bmap_del_extent_real In the case of returning -ENOSPC, ensure logflagsp is initialized by 0. Otherwise the caller __xfs_bunmapi will set uninitialized illegal tmp_logflags value into xfs log, which might cause unpredictable error in the log recovery procedure. Also, remove the flags variable and set the *logflagsp directly, so that the code should be more robust in the long run. Fixes: 1b24b633aafe ("xfs: move some more code into xfs_bmap_del_extent_real") Signed-off-by: Jiachen Zhang Reviewed-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/libxfs/xfs_bmap.c | 73 +++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 68be1dd4f0f2..ca6614f4eac5 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -5010,7 +5010,6 @@ xfs_bmap_del_extent_real( xfs_fileoff_t del_endoff; /* first offset past del */ int do_fx; /* free extent at end of routine */ int error; /* error return value */ - int flags = 0;/* inode logging flags */ struct xfs_bmbt_irec got; /* current extent entry */ xfs_fileoff_t got_endoff; /* first offset past got */ int i; /* temp state */ @@ -5023,6 +5022,8 @@ xfs_bmap_del_extent_real( uint32_t state = xfs_bmap_fork_to_state(whichfork); struct xfs_bmbt_irec old; + *logflagsp = 0; + mp = ip->i_mount; XFS_STATS_INC(mp, xs_del_exlist); @@ -5035,7 +5036,6 @@ xfs_bmap_del_extent_real( ASSERT(got_endoff >= del_endoff); ASSERT(!isnullstartblock(got.br_startblock)); qfield = 0; - error = 0; /* * If it's the case where the directory code is running with no block @@ -5051,13 +5051,13 @@ xfs_bmap_del_extent_real( del->br_startoff > got.br_startoff && del_endoff < got_endoff) return -ENOSPC; - flags = XFS_ILOG_CORE; + *logflagsp = XFS_ILOG_CORE; if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { if (!(bflags & XFS_BMAPI_REMAP)) { error = xfs_rtfree_blocks(tp, del->br_startblock, del->br_blockcount); if (error) - goto done; + return error; } do_fx = 0; @@ -5072,11 +5072,9 @@ xfs_bmap_del_extent_real( if (cur) { error = xfs_bmbt_lookup_eq(cur, &got, &i); if (error) - goto done; - if (XFS_IS_CORRUPT(mp, i != 1)) { - error = -EFSCORRUPTED; - goto done; - } + return error; + if (XFS_IS_CORRUPT(mp, i != 1)) + return -EFSCORRUPTED; } if (got.br_startoff == del->br_startoff) @@ -5093,17 +5091,15 @@ xfs_bmap_del_extent_real( xfs_iext_prev(ifp, icur); ifp->if_nextents--; - flags |= XFS_ILOG_CORE; + *logflagsp |= XFS_ILOG_CORE; if (!cur) { - flags |= xfs_ilog_fext(whichfork); + *logflagsp |= xfs_ilog_fext(whichfork); break; } if ((error = xfs_btree_delete(cur, &i))) - goto done; - if (XFS_IS_CORRUPT(mp, i != 1)) { - error = -EFSCORRUPTED; - goto done; - } + return error; + if (XFS_IS_CORRUPT(mp, i != 1)) + return -EFSCORRUPTED; break; case BMAP_LEFT_FILLING: /* @@ -5114,12 +5110,12 @@ xfs_bmap_del_extent_real( got.br_blockcount -= del->br_blockcount; xfs_iext_update_extent(ip, state, icur, &got); if (!cur) { - flags |= xfs_ilog_fext(whichfork); + *logflagsp |= xfs_ilog_fext(whichfork); break; } error = xfs_bmbt_update(cur, &got); if (error) - goto done; + return error; break; case BMAP_RIGHT_FILLING: /* @@ -5128,12 +5124,12 @@ xfs_bmap_del_extent_real( got.br_blockcount -= del->br_blockcount; xfs_iext_update_extent(ip, state, icur, &got); if (!cur) { - flags |= xfs_ilog_fext(whichfork); + *logflagsp |= xfs_ilog_fext(whichfork); break; } error = xfs_bmbt_update(cur, &got); if (error) - goto done; + return error; break; case 0: /* @@ -5150,18 +5146,18 @@ xfs_bmap_del_extent_real( new.br_state = got.br_state; new.br_startblock = del_endblock; - flags |= XFS_ILOG_CORE; + *logflagsp |= XFS_ILOG_CORE; if (cur) { error = xfs_bmbt_update(cur, &got); if (error) - goto done; + return error; error = xfs_btree_increment(cur, 0, &i); if (error) - goto done; + return error; cur->bc_rec.b = new; error = xfs_btree_insert(cur, &i); if (error && error != -ENOSPC) - goto done; + return error; /* * If get no-space back from btree insert, it tried a * split, and we have a zero block reservation. Fix up @@ -5174,33 +5170,28 @@ xfs_bmap_del_extent_real( */ error = xfs_bmbt_lookup_eq(cur, &got, &i); if (error) - goto done; - if (XFS_IS_CORRUPT(mp, i != 1)) { - error = -EFSCORRUPTED; - goto done; - } + return error; + if (XFS_IS_CORRUPT(mp, i != 1)) + return -EFSCORRUPTED; /* * Update the btree record back * to the original value. */ error = xfs_bmbt_update(cur, &old); if (error) - goto done; + return error; /* * Reset the extent record back * to the original value. */ xfs_iext_update_extent(ip, state, icur, &old); - flags = 0; - error = -ENOSPC; - goto done; - } - if (XFS_IS_CORRUPT(mp, i != 1)) { - error = -EFSCORRUPTED; - goto done; + *logflagsp = 0; + return -ENOSPC; } + if (XFS_IS_CORRUPT(mp, i != 1)) + return -EFSCORRUPTED; } else - flags |= xfs_ilog_fext(whichfork); + *logflagsp |= xfs_ilog_fext(whichfork); ifp->if_nextents++; xfs_iext_next(ifp, icur); @@ -5224,7 +5215,7 @@ xfs_bmap_del_extent_real( ((bflags & XFS_BMAPI_NODISCARD) || del->br_state == XFS_EXT_UNWRITTEN)); if (error) - goto done; + return error; } } @@ -5239,9 +5230,7 @@ xfs_bmap_del_extent_real( if (qfield && !(bflags & XFS_BMAPI_REMAP)) xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); -done: - *logflagsp = flags; - return error; + return 0; } /* From 5759aa4f956034b289b0ae2c99daddfc775442e1 Mon Sep 17 00:00:00 2001 From: Zhang Tianci Date: Tue, 5 Dec 2023 13:58:59 +0800 Subject: [PATCH 3009/7721] xfs: update dir3 leaf block metadata after swap xfs_da3_swap_lastblock() copy the last block content to the dead block, but do not update the metadata in it. We need update some metadata for some kinds of type block, such as dir3 leafn block records its blkno, we shall update it to the dead block blkno. Otherwise, before write the xfs_buf to disk, the verify_write() will fail in blk_hdr->blkno != xfs_buf->b_bn, then xfs will be shutdown. We will get this warning: XFS (dm-0): Metadata corruption detected at xfs_dir3_leaf_verify+0xa8/0xe0 [xfs], xfs_dir3_leafn block 0x178 XFS (dm-0): Unmount and run xfs_repair XFS (dm-0): First 128 bytes of corrupted metadata buffer: 00000000e80f1917: 00 80 00 0b 00 80 00 07 3d ff 00 00 00 00 00 00 ........=....... 000000009604c005: 00 00 00 00 00 00 01 a0 00 00 00 00 00 00 00 00 ................ 000000006b6fb2bf: e4 44 e3 97 b5 64 44 41 8b 84 60 0e 50 43 d9 bf .D...dDA..`.PC.. 00000000678978a2: 00 00 00 00 00 00 00 83 01 73 00 93 00 00 00 00 .........s...... 00000000b28b247c: 99 29 1d 38 00 00 00 00 99 29 1d 40 00 00 00 00 .).8.....).@.... 000000002b2a662c: 99 29 1d 48 00 00 00 00 99 49 11 00 00 00 00 00 .).H.....I...... 00000000ea2ffbb8: 99 49 11 08 00 00 45 25 99 49 11 10 00 00 48 fe .I....E%.I....H. 0000000069e86440: 99 49 11 18 00 00 4c 6b 99 49 11 20 00 00 4d 97 .I....Lk.I. ..M. XFS (dm-0): xfs_do_force_shutdown(0x8) called from line 1423 of file fs/xfs/xfs_buf.c. Return address = 00000000c0ff63c1 XFS (dm-0): Corruption of in-memory data detected. Shutting down filesystem XFS (dm-0): Please umount the filesystem and rectify the problem(s) >From the log above, we know xfs_buf->b_no is 0x178, but the block's hdr record its blkno is 0x1a0. Fixes: 24df33b45ecf ("xfs: add CRC checking to dir2 leaf blocks") Signed-off-by: Zhang Tianci Suggested-by: Dave Chinner Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- fs/xfs/libxfs/xfs_da_btree.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index e576560b46e9..282c7cf032f4 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -2316,10 +2316,17 @@ xfs_da3_swap_lastblock( return error; /* * Copy the last block into the dead buffer and log it. + * On CRC-enabled file systems, also update the stamped in blkno. */ memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize); + if (xfs_has_crc(mp)) { + struct xfs_da3_blkinfo *da3 = dead_buf->b_addr; + + da3->blkno = cpu_to_be64(xfs_buf_daddr(dead_buf)); + } xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1); dead_info = dead_buf->b_addr; + /* * Get values from the moved block. */ From fd45ddb9dd606b3eaddf26e13f64340636955986 Mon Sep 17 00:00:00 2001 From: Zhang Tianci Date: Tue, 5 Dec 2023 13:59:00 +0800 Subject: [PATCH 3010/7721] xfs: extract xfs_da_buf_copy() helper function This patch does not modify logic. xfs_da_buf_copy() will copy one block from src xfs_buf to dst xfs_buf, and update the block metadata in dst directly. Signed-off-by: Zhang Tianci Suggested-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Signed-off-by: Chandan Babu R --- fs/xfs/libxfs/xfs_attr_leaf.c | 12 ++---- fs/xfs/libxfs/xfs_da_btree.c | 74 ++++++++++++++--------------------- fs/xfs/libxfs/xfs_da_btree.h | 2 + 3 files changed, 36 insertions(+), 52 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 2580ae47209a..654e17e6610d 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -1244,14 +1244,10 @@ xfs_attr3_leaf_to_node( if (error) goto out; - /* copy leaf to new buffer, update identifiers */ - xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF); - bp2->b_ops = bp1->b_ops; - memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize); - if (xfs_has_crc(mp)) { - struct xfs_da3_blkinfo *hdr3 = bp2->b_addr; - hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp2)); - } + /* + * Copy leaf to new buffer and log it. + */ + xfs_da_buf_copy(bp2, bp1, args->geo->blksize); xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1); /* diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index 282c7cf032f4..5457188bb4de 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -421,6 +421,25 @@ xfs_da3_node_read_mapped( return xfs_da3_node_set_type(tp, *bpp); } +/* + * Copy src directory/attr leaf/node buffer to the dst. + * For v5 file systems make sure the right blkno is stamped in. + */ +void +xfs_da_buf_copy( + struct xfs_buf *dst, + struct xfs_buf *src, + size_t size) +{ + struct xfs_da3_blkinfo *da3 = dst->b_addr; + + memcpy(dst->b_addr, src->b_addr, size); + dst->b_ops = src->b_ops; + xfs_trans_buf_copy_type(dst, src); + if (xfs_has_crc(dst->b_mount)) + da3->blkno = cpu_to_be64(xfs_buf_daddr(dst)); +} + /*======================================================================== * Routines used for growing the Btree. *========================================================================*/ @@ -690,12 +709,6 @@ xfs_da3_root_split( btree = icnodehdr.btree; size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot); level = icnodehdr.level; - - /* - * we are about to copy oldroot to bp, so set up the type - * of bp while we know exactly what it will be. - */ - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); } else { struct xfs_dir3_icleaf_hdr leafhdr; @@ -707,31 +720,17 @@ xfs_da3_root_split( size = (int)((char *)&leafhdr.ents[leafhdr.count] - (char *)leaf); level = 0; - - /* - * we are about to copy oldroot to bp, so set up the type - * of bp while we know exactly what it will be. - */ - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); } /* - * we can copy most of the information in the node from one block to - * another, but for CRC enabled headers we have to make sure that the - * block specific identifiers are kept intact. We update the buffer - * directly for this. + * Copy old root to new buffer and log it. */ - memcpy(node, oldroot, size); - if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || - oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { - struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node; - - node3->hdr.info.blkno = cpu_to_be64(xfs_buf_daddr(bp)); - } + xfs_da_buf_copy(bp, blk1->bp, size); xfs_trans_log_buf(tp, bp, 0, size - 1); - bp->b_ops = blk1->bp->b_ops; - xfs_trans_buf_copy_type(bp, blk1->bp); + /* + * Update blk1 to point to new buffer. + */ blk1->bp = bp; blk1->blkno = blkno; @@ -1220,21 +1219,14 @@ xfs_da3_root_join( xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level); /* - * This could be copying a leaf back into the root block in the case of - * there only being a single leaf block left in the tree. Hence we have - * to update the b_ops pointer as well to match the buffer type change - * that could occur. For dir3 blocks we also need to update the block - * number in the buffer header. + * Copy child to root buffer and log it. */ - memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize); - root_blk->bp->b_ops = bp->b_ops; - xfs_trans_buf_copy_type(root_blk->bp, bp); - if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) { - struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr; - da3->blkno = cpu_to_be64(xfs_buf_daddr(root_blk->bp)); - } + xfs_da_buf_copy(root_blk->bp, bp, args->geo->blksize); xfs_trans_log_buf(args->trans, root_blk->bp, 0, args->geo->blksize - 1); + /* + * Now we can drop the child buffer. + */ error = xfs_da_shrink_inode(args, child, bp); return error; } @@ -2316,14 +2308,8 @@ xfs_da3_swap_lastblock( return error; /* * Copy the last block into the dead buffer and log it. - * On CRC-enabled file systems, also update the stamped in blkno. */ - memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize); - if (xfs_has_crc(mp)) { - struct xfs_da3_blkinfo *da3 = dead_buf->b_addr; - - da3->blkno = cpu_to_be64(xfs_buf_daddr(dead_buf)); - } + xfs_da_buf_copy(dead_buf, last_buf, args->geo->blksize); xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1); dead_info = dead_buf->b_addr; diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h index ffa3df5b2893..706baf36e175 100644 --- a/fs/xfs/libxfs/xfs_da_btree.h +++ b/fs/xfs/libxfs/xfs_da_btree.h @@ -219,6 +219,8 @@ int xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno, const struct xfs_buf_ops *ops); int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf); +void xfs_da_buf_copy(struct xfs_buf *dst, struct xfs_buf *src, + size_t size); uint xfs_da_hashname(const uint8_t *name_string, int name_length); enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, From c12c50393c1f6f7d7e45c7f55da9c013c0cc0522 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 21:07:18 +0100 Subject: [PATCH 3011/7721] xfs: use static_assert to check struct sizes and offsets Use the compiler-provided static_assert built-in from C11 instead of the kernel-specific BUILD_BUG_ON_MSG for the structure size and offset checks in xfs_ondisk. This not only gives slightly nicer error messages in case things go south, but can also be trivially used as-is in userspace. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Reviewed-by: Carlos Maiolino Signed-off-by: Chandan Babu R --- fs/xfs/xfs_ondisk.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index 21a7e350b4c5..d9c988c5ad69 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -7,16 +7,16 @@ #define __XFS_ONDISK_H #define XFS_CHECK_STRUCT_SIZE(structname, size) \ - BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \ - #structname ") is wrong, expected " #size) + static_assert(sizeof(structname) == (size), \ + "XFS: sizeof(" #structname ") is wrong, expected " #size) #define XFS_CHECK_OFFSET(structname, member, off) \ - BUILD_BUG_ON_MSG(offsetof(structname, member) != (off), \ + static_assert(offsetof(structname, member) == (off), \ "XFS: offsetof(" #structname ", " #member ") is wrong, " \ "expected " #off) #define XFS_CHECK_VALUE(value, expected) \ - BUILD_BUG_ON_MSG((value) != (expected), \ + static_assert((value) == (expected), \ "XFS: value of " #value " is wrong, expected " #expected) static inline void __init From 18793e050504288345eb455a471677b57117bcc6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Dec 2023 21:07:19 +0100 Subject: [PATCH 3012/7721] xfs: move xfs_ondisk.h to libxfs/ Move xfs_ondisk.h to libxfs so that we can do the struct sanity checks in userspace libxfs as well. This should allow us to retire the somewhat fragile xfs/122 test on xfstests. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" Reviewed-by: Carlos Maiolino Signed-off-by: Chandan Babu R --- fs/xfs/{ => libxfs}/xfs_ondisk.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fs/xfs/{ => libxfs}/xfs_ondisk.h (100%) diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h similarity index 100% rename from fs/xfs/xfs_ondisk.h rename to fs/xfs/libxfs/xfs_ondisk.h From dcdf1bbe82f4b2a301a3692a0b1942c3fda70644 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 1 Dec 2023 12:00:32 +0200 Subject: [PATCH 3013/7721] drm/i915: handle uncore spinlock when not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uncore code may not always be available (e.g. when we build the display code with Xe), so we can't always rely on having the uncore's spinlock. To handle this, split the spin_lock/unlock_irqsave/restore() into spin_lock/unlock() followed by a call to local_irq_save/restore() and create wrapper functions for locking and unlocking the uncore's spinlock. In these functions, we have a condition check and only actually try to lock/unlock the spinlock when I915 is defined, and thus uncore is available. This keeps the ifdefs contained in these new functions and all such logic inside the display code. Cc: Tvrtko Ursulin Cc: Jani Nikula Cc: Ville Syrjala Cc: Rodrigo Vivi Signed-off-by: Luca Coelho Reviewed-by: Jouni Högander Signed-off-by: Jouni Högander Link: https://patchwork.freedesktop.org/patch/msgid/20231201100032.1367589-1-luciano.coelho@intel.com --- drivers/gpu/drm/i915/display/intel_vblank.c | 51 +++++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index 2cec2abf9746..fe256bf7b485 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -265,6 +265,32 @@ int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline) return (scanline + vtotal - crtc->scanline_offset) % vtotal; } +/* + * The uncore version of the spin lock functions is used to decide + * whether we need to lock the uncore lock or not. This is only + * needed in i915, not in Xe. + * + * This lock in i915 is needed because some old platforms (at least + * IVB and possibly HSW as well), which are not supported in Xe, need + * all register accesses to the same cacheline to be serialized, + * otherwise they may hang. + */ +static void intel_vblank_section_enter(struct drm_i915_private *i915) + __acquires(i915->uncore.lock) +{ +#ifdef I915 + spin_lock(&i915->uncore.lock); +#endif +} + +static void intel_vblank_section_exit(struct drm_i915_private *i915) + __releases(i915->uncore.lock) +{ +#ifdef I915 + spin_unlock(&i915->uncore.lock); +#endif +} + static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, bool in_vblank_irq, int *vpos, int *hpos, @@ -302,11 +328,12 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, } /* - * Lock uncore.lock, as we will do multiple timing critical raw - * register reads, potentially with preemption disabled, so the - * following code must not block on uncore.lock. + * Enter vblank critical section, as we will do multiple + * timing critical raw register reads, potentially with + * preemption disabled, so the following code must not block. */ - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + local_irq_save(irqflags); + intel_vblank_section_enter(dev_priv); /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ @@ -374,7 +401,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + intel_vblank_section_exit(dev_priv); + local_irq_restore(irqflags); /* * While in vblank, position will be negative @@ -412,9 +440,13 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc) unsigned long irqflags; int position; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + local_irq_save(irqflags); + intel_vblank_section_enter(dev_priv); + position = __intel_get_crtc_scanline(crtc); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_vblank_section_exit(dev_priv); + local_irq_restore(irqflags); return position; } @@ -537,7 +569,7 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, * Need to audit everything to make sure it's safe. */ spin_lock_irqsave(&i915->drm.vblank_time_lock, irqflags); - spin_lock(&i915->uncore.lock); + intel_vblank_section_enter(i915); drm_calc_timestamping_constants(&crtc->base, &adjusted_mode); @@ -546,7 +578,6 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, crtc->mode_flags = mode_flags; crtc->scanline_offset = intel_crtc_scanline_offset(crtc_state); - - spin_unlock(&i915->uncore.lock); + intel_vblank_section_exit(i915); spin_unlock_irqrestore(&i915->drm.vblank_time_lock, irqflags); } From 63b896629353157e8ca77cabdfab340b5c69ca59 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Tue, 5 Dec 2023 17:15:36 +0200 Subject: [PATCH 3014/7721] wifi: ath10k: add support to allow broadcast action frame RX Broadcast action frames are needed for the Device Provisioning Protocol (DPP) for Presence and PKEX Exchange requests. Currently just ath9k has this capability so this is being enabled for ath10k (for at least one hardware variant). Add a new capability flag in ath10k_hw_params to indicate support for receiving multicast action frames. This bit is then checked when configuring the RX filter and (if set) multicast action frame registration is enabled. Until more hardware can be tested only the "qca6174 hw3.2" variant is enabling this feature. Note: I went ahead and removed the 'changed_flags' mask operation since it had no effect, that parameter was not being used anywhere. Tested-on: QCA6174 hw3.2 WLAN.RM.4.4.1-00288- Signed-off-by: James Prestwood Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231116173246.40458-1-prestwoj@gmail.com --- drivers/net/wireless/ath/ath10k/core.c | 16 ++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 3 +++ drivers/net/wireless/ath/ath10k/mac.c | 13 +++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e9a434f1eb42..0032f8aa892f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -101,6 +101,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -141,6 +142,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -182,6 +184,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -218,6 +221,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -258,6 +262,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -298,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -338,6 +344,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -382,6 +389,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -428,6 +436,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -481,6 +490,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -531,6 +541,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -571,6 +582,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -613,6 +625,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -646,6 +659,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -693,6 +707,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -726,6 +741,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = true, .use_fw_tx_credits = false, .delay_unmap_buffer = true, + .mcast_frame_registration = false, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 2e65902f8b21..93c073091996 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -640,6 +640,9 @@ struct ath10k_hw_params { bool use_fw_tx_credits; bool delay_unmap_buffer; + + /* The hardware support multicast frame registrations */ + bool mcast_frame_registration; }; struct htt_resp; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ed2db79b7b18..090bcf148d0c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1243,7 +1243,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar) return ar->monitor || (!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST, ar->running_fw->fw_file.fw_features) && - (ar->filter_flags & FIF_OTHER_BSS)) || + (ar->filter_flags & (FIF_OTHER_BSS | FIF_MCAST_ACTION))) || test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); } @@ -6026,10 +6026,15 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; int ret; + unsigned int supported = SUPPORTED_FILTERS; mutex_lock(&ar->conf_mutex); - *total_flags &= SUPPORTED_FILTERS; + if (ar->hw_params.mcast_frame_registration) + supported |= FIF_MCAST_ACTION; + + *total_flags &= supported; + ar->filter_flags = *total_flags; ret = ath10k_monitor_recalc(ar); @@ -10118,6 +10123,10 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL); + if (ar->hw_params.mcast_frame_registration) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) wiphy_ext_feature_set(ar->hw->wiphy, From 6783f10a1d076297a66b5b57e0a96d8c8363271b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Tue, 5 Dec 2023 12:15:15 +0100 Subject: [PATCH 3015/7721] wifi: ath5k: remove unused ath5k_eeprom_info::ee_antenna clang-struct [1] found that ee_antenna in struct ath5k_eeprom_info is unused. The commit 1048643ea94d ("ath5k: Clean up eeprom parsing and add missing calibration data") added it, but did not use it in any way. Neither, there is a later user. So remove that unused member. [1] https://github.com/jirislaby/clang-struct Signed-off-by: Jiri Slaby (SUSE) Cc: Felix Fietkau Cc: Nick Kossifidis Cc: Luis Chamberlain Cc: Kalle Valo Cc: linux-wireless@vger.kernel.org Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231205111515.21470-1-jirislaby@kernel.org --- drivers/net/wireless/ath/ath5k/eeprom.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 693296ee9693..e85b713950b1 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -489,7 +489,4 @@ struct ath5k_eeprom_info { /* Spur mitigation data (fbin values for spur channels) */ u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS]; - - /* Antenna raw switch tables */ - u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; From 8e3bfaab2ad956aa551a3cf8f7108f4b2c3b18d0 Mon Sep 17 00:00:00 2001 From: Ante Knezic Date: Tue, 5 Dec 2023 11:03:38 +0100 Subject: [PATCH 3016/7721] dt-bindings: net: microchip,ksz: document microchip,rmii-clk-internal Add documentation for selecting reference rmii clock on KSZ88X3 devices Signed-off-by: Ante Knezic Reviewed-by: Rob Herring Signed-off-by: David S. Miller --- .../bindings/net/dsa/microchip,ksz.yaml | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index b3029c64d0d5..c963dc09e8e1 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -11,7 +11,6 @@ maintainers: - Woojung Huh allOf: - - $ref: dsa.yaml#/$defs/ethernet-ports - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: @@ -78,6 +77,39 @@ required: - compatible - reg +if: + not: + properties: + compatible: + enum: + - microchip,ksz8863 + - microchip,ksz8873 +then: + $ref: dsa.yaml#/$defs/ethernet-ports +else: + patternProperties: + "^(ethernet-)?ports$": + patternProperties: + "^(ethernet-)?port@[0-2]$": + $ref: dsa-port.yaml# + unevaluatedProperties: false + properties: + microchip,rmii-clk-internal: + $ref: /schemas/types.yaml#/definitions/flag + description: + When ksz88x3 is acting as clock provier (via REFCLKO) it + can select between internal and external RMII reference + clock. Internal reference clock means that the clock for + the RMII of ksz88x3 is provided by the ksz88x3 internally + and the REFCLKI pin is unconnected. For the external + reference clock, the clock needs to be fed back to ksz88x3 + via REFCLKI. + If microchip,rmii-clk-internal is set, ksz88x3 will provide + rmii reference clock internally, otherwise reference clock + should be provided externally. + dependencies: + microchip,rmii-clk-internal: [ethernet] + unevaluatedProperties: false examples: From 9f19a4ebc80af64bddda1cbfb9bf574b689222c0 Mon Sep 17 00:00:00 2001 From: Ante Knezic Date: Tue, 5 Dec 2023 11:03:39 +0100 Subject: [PATCH 3017/7721] net: dsa: microchip: add property to select internal RMII reference clock Microchip KSZ8863/KSZ8873 have the ability to select between internal and external RMII reference clock. By default, reference clock needs to be provided via REFCLKI_3 pin. If required, device can be setup to provide RMII clock internally so that REFCLKI_3 pin can be left unconnected. Add a new "microchip,rmii-clk-internal" property which will set RMII clock reference to internal. If property is not set, reference clock needs to be provided externally. While at it, move the ksz8795_cpu_interface_select() to ksz8_config_cpu_port() to get a cleaner call path for cpu port. Signed-off-by: Ante Knezic Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz8795.c | 29 ++++++++++++++++++++----- drivers/net/dsa/microchip/ksz8795_reg.h | 3 +++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index ec1ddfcf7473..61b71bcfe396 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1358,6 +1358,9 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port) { struct ksz_port *p = &dev->ports[port]; + if (!ksz_is_ksz87xx(dev)) + return; + if (!p->interface && dev->compat_interface) { dev_warn(dev->dev, "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. " @@ -1391,18 +1394,29 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) /* enable 802.1p priority */ ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true); - if (cpu_port) { - if (!ksz_is_ksz88x3(dev)) - ksz8795_cpu_interface_select(dev, port); - + if (cpu_port) member = dsa_user_ports(ds); - } else { + else member = BIT(dsa_upstream_port(ds, port)); - } ksz8_cfg_port_member(dev, port, member); } +static void ksz88x3_config_rmii_clk(struct ksz_device *dev) +{ + struct dsa_port *cpu_dp = dsa_to_port(dev->ds, dev->cpu_port); + bool rmii_clk_internal; + + if (!ksz_is_ksz88x3(dev)) + return; + + rmii_clk_internal = of_property_read_bool(cpu_dp->dn, + "microchip,rmii-clk-internal"); + + ksz_cfg(dev, KSZ88X3_REG_FVID_AND_HOST_MODE, + KSZ88X3_PORT3_RMII_CLK_INTERNAL, rmii_clk_internal); +} + void ksz8_config_cpu_port(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -1419,6 +1433,9 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) ksz8_port_setup(dev, dev->cpu_port, true); + ksz8795_cpu_interface_select(dev, dev->cpu_port); + ksz88x3_config_rmii_clk(dev); + for (i = 0; i < dev->phy_port_cnt; i++) { ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); } diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index 3c9dae53e4d8..beca974e0171 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -22,6 +22,9 @@ #define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4) #define KSZ8863_PCS_RESET BIT(0) +#define KSZ88X3_REG_FVID_AND_HOST_MODE 0xC6 +#define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3) + #define REG_SW_CTRL_0 0x02 #define SW_NEW_BACKOFF BIT(7) From 5908cbe82ef77f6019349c450d7f1c8b3c29bb0e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 5 Dec 2023 13:13:34 -0700 Subject: [PATCH 3018/7721] usb: typec: nb7vpq904m: Only select DRM_AUX_BRIDGE with OF CONFIG_DRM_AUX_BRIDGE depends on CONFIG_OF but that dependency is not included when CONFIG_TYPEC_MUX_NB7VPQ904M selects it, resulting in a Kconfig warning when CONFIG_OF is disabled: WARNING: unmet direct dependencies detected for DRM_AUX_BRIDGE Depends on [n]: HAS_IOMEM [=y] && DRM_BRIDGE [=y] && OF [=n] Selected by [y]: - TYPEC_MUX_NB7VPQ904M [=y] && USB_SUPPORT [=y] && TYPEC [=y] && I2C [=y] && (DRM [=y] || DRM [=y]=n) && DRM_BRIDGE [=y] Only select CONFIG_DRM_AUX_BRIDGE with both CONFIG_DRM_BRIDGE and CONFIG_OF to clear up the warning. Fixes: c5d296bad640 ("usb: typec: nb7vpq904m: switch to DRM_AUX_BRIDGE") Signed-off-by: Nathan Chancellor Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231205-drm_aux_bridge-fixes-v1-1-d242a0ae9df4@kernel.org --- drivers/usb/typec/mux/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 5120942f309d..38416fb0cc3c 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -40,7 +40,7 @@ config TYPEC_MUX_NB7VPQ904M tristate "On Semiconductor NB7VPQ904M Type-C redriver driver" depends on I2C depends on DRM || DRM=n - select DRM_AUX_BRIDGE if DRM_BRIDGE + select DRM_AUX_BRIDGE if DRM_BRIDGE && OF select REGMAP_I2C help Say Y or M if your system has a On Semiconductor NB7VPQ904M Type-C From 03c0343bdf8d43fee6dfe92a7b66308b60e9e77c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 5 Dec 2023 13:13:35 -0700 Subject: [PATCH 3019/7721] usb: typec: qcom-pmic-typec: Only select DRM_AUX_HPD_BRIDGE with OF CONFIG_DRM_AUX_HPD_BRIDGE depends on CONFIG_OF but that dependency is not included when CONFIG_TYPEC_QCOM_PMIC selects it, resulting in a Kconfig warning when CONFIG_OF is disabled: WARNING: unmet direct dependencies detected for DRM_AUX_HPD_BRIDGE Depends on [n]: HAS_IOMEM [=y] && DRM_BRIDGE [=y] && OF [=n] Selected by [m]: - TYPEC_QCOM_PMIC [=m] && USB_SUPPORT [=y] && TYPEC [=m] && TYPEC_TCPM [=m] && (ARCH_QCOM || COMPILE_TEST [=y]) && (DRM [=m] || DRM [=m]=n) && DRM_BRIDGE [=y] Only select CONFIG_DRM_AUX_HPD_BRIDGE with both CONFIG_DRM_BRIDGE and CONFIG_OF to clear up the warning. Fixes: 7d9f1b72b296 ("usb: typec: qcom-pmic-typec: switch to DRM_AUX_HPD_BRIDGE") Signed-off-by: Nathan Chancellor Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Reviewed-by: Bryan O'Donoghue Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231205-drm_aux_bridge-fixes-v1-2-d242a0ae9df4@kernel.org --- drivers/usb/typec/tcpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 64d5421c69e6..8cdd84ca5d6f 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -80,7 +80,7 @@ config TYPEC_QCOM_PMIC tristate "Qualcomm PMIC USB Type-C Port Controller Manager driver" depends on ARCH_QCOM || COMPILE_TEST depends on DRM || DRM=n - select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE + select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF help A Type-C port and Power Delivery driver which aggregates two discrete pieces of silicon in the PM8150b PMIC block: the From 812cc1da7ffd9e178ef66b8a22113be10fba466c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 5 Dec 2023 13:13:36 -0700 Subject: [PATCH 3020/7721] drm/bridge: Return NULL instead of plain 0 in drm_dp_hpd_bridge_register() stub sparse complains: drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c: note: in included file: include/drm/bridge/aux-bridge.h:29:16: sparse: sparse: Using plain integer as NULL pointer Return NULL to clear up the warning. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312060025.BdeqZrWx-lkp@intel.com/ Fixes: e560518a6c2e ("drm/bridge: implement generic DP HPD bridge") Signed-off-by: Nathan Chancellor Reviewed-by: Bryan O'Donoghue Reviewed-by: Guenter Roeck Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231205-drm_aux_bridge-fixes-v1-3-d242a0ae9df4@kernel.org --- include/drm/bridge/aux-bridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h index 66249ff0858e..c4c423e97f06 100644 --- a/include/drm/bridge/aux-bridge.h +++ b/include/drm/bridge/aux-bridge.h @@ -26,7 +26,7 @@ void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status sta static inline struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device_node *np) { - return 0; + return NULL; } static inline void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) From 76385d493c2137460ee7735a5d3a494099c35188 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 5 Dec 2023 14:06:31 +0100 Subject: [PATCH 3021/7721] drm/debugfs: fix potential NULL pointer dereference encoder->funcs entry might be NULL, so check it first before calling its methods. This fixes NULL pointer dereference observed on Rasberry Pi 3b/4b boards. Fixes: caf525ed45b4 ("drm/encoder: register per-encoder debugfs dir") Signed-off-by: Marek Szyprowski Tested-by: Nishanth Menon Reviewed-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231205130631.3456986-1-m.szyprowski@samsung.com --- drivers/gpu/drm/drm_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 02e7481758c0..f4715a67e340 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -638,7 +638,7 @@ void drm_debugfs_encoder_add(struct drm_encoder *encoder) debugfs_create_file("bridges", 0444, root, encoder, &bridges_fops); - if (encoder->funcs->debugfs_init) + if (encoder->funcs && encoder->funcs->debugfs_init) encoder->funcs->debugfs_init(encoder, root); } From 261200eb7030dc796f08c1ad778bd0b18b19451b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Dec 2023 14:15:45 +0200 Subject: [PATCH 3022/7721] drm/i915/rpm: add rpm_to_i915() helper around container_of() Reduce the duplication. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231205121545.2338665-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_runtime_pm.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8743153fad87..156cb1536b47 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -50,6 +50,11 @@ * present for a given platform. */ +static struct drm_i915_private *rpm_to_i915(struct intel_runtime_pm *rpm) +{ + return container_of(rpm, struct drm_i915_private, runtime_pm); +} + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) #include @@ -349,9 +354,7 @@ intel_runtime_pm_release(struct intel_runtime_pm *rpm, int wakelock) static intel_wakeref_t __intel_runtime_pm_get(struct intel_runtime_pm *rpm, bool wakelock) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); int ret; ret = pm_runtime_get_sync(rpm->kdev); @@ -556,9 +559,7 @@ void intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) */ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct device *kdev = rpm->kdev; /* @@ -611,9 +612,7 @@ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct device *kdev = rpm->kdev; /* Transfer rpm ownership back to core */ @@ -628,9 +627,7 @@ void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); int count = atomic_read(&rpm->wakeref_count); intel_wakeref_auto_fini(&rpm->userfault_wakeref); @@ -645,8 +642,7 @@ void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = - container_of(rpm, struct drm_i915_private, runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct device *kdev = &pdev->dev; From 922181a52de923a2220998a26d84d94889dd6e97 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Dec 2023 15:41:41 +0200 Subject: [PATCH 3023/7721] drm/i915: use intel_connector in intel_connector_debugfs_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer struct intel_connector over struct drm_connector. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231205134143.2427661-1-jani.nikula@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index a7675a7339c3..32539dfd506e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1566,59 +1566,58 @@ DEFINE_SHOW_ATTRIBUTE(intel_crtc_pipe); /** * intel_connector_debugfs_add - add i915 specific connector debugfs files - * @intel_connector: pointer to a registered drm_connector + * @connector: pointer to a registered intel_connector * * Cleanup will be done by drm_connector_unregister() through a call to * drm_debugfs_connector_remove(). */ -void intel_connector_debugfs_add(struct intel_connector *intel_connector) +void intel_connector_debugfs_add(struct intel_connector *connector) { - struct drm_connector *connector = &intel_connector->base; - struct dentry *root = connector->debugfs_entry; - struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct dentry *root = connector->base.debugfs_entry; + int connector_type = connector->base.connector_type; /* The connector must have been registered beforehands. */ if (!root) return; - intel_drrs_connector_debugfs_add(intel_connector); - intel_psr_connector_debugfs_add(intel_connector); + intel_drrs_connector_debugfs_add(connector); + intel_psr_connector_debugfs_add(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + if (connector_type == DRM_MODE_CONNECTOR_eDP) debugfs_create_file("i915_panel_timings", S_IRUGO, root, - connector, &i915_panel_fops); + &connector->base, &i915_panel_fops); - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) { debugfs_create_file("i915_hdcp_sink_capability", S_IRUGO, root, - connector, &i915_hdcp_sink_capability_fops); + &connector->base, &i915_hdcp_sink_capability_fops); } - if (DISPLAY_VER(dev_priv) >= 11 && - ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && - !to_intel_connector(connector)->mst_port) || - connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + if (DISPLAY_VER(i915) >= 11 && + ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !connector->mst_port) || + connector_type == DRM_MODE_CONNECTOR_eDP)) { debugfs_create_file("i915_dsc_fec_support", 0644, root, - connector, &i915_dsc_fec_support_fops); + &connector->base, &i915_dsc_fec_support_fops); debugfs_create_file("i915_dsc_bpc", 0644, root, - connector, &i915_dsc_bpc_fops); + &connector->base, &i915_dsc_bpc_fops); debugfs_create_file("i915_dsc_output_format", 0644, root, - connector, &i915_dsc_output_format_fops); + &connector->base, &i915_dsc_output_format_fops); debugfs_create_file("i915_dsc_fractional_bpp", 0644, root, - connector, &i915_dsc_fractional_bpp_fops); + &connector->base, &i915_dsc_fractional_bpp_fops); } - if (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP || - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) + if (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP || + connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) debugfs_create_file("i915_lpsp_capability", 0444, root, - connector, &i915_lpsp_capability_fops); + &connector->base, &i915_lpsp_capability_fops); } /** From 77bdb83f0dbc8dd64c07bba08ecd2ac83030a508 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Dec 2023 15:41:42 +0200 Subject: [PATCH 3024/7721] drm/i915: pass struct intel_connector to connector debugfs fops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer struct intel_connector over struct drm_connector, and unify the declarations in the fops. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231205134143.2427661-2-jani.nikula@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 134 +++++++++--------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 32539dfd506e..85e5e21a859c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1117,11 +1117,10 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) static int i915_panel_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct intel_dp *intel_dp = - intel_attached_dp(to_intel_connector(connector)); + struct intel_connector *connector = m->private; + struct intel_dp *intel_dp = intel_attached_dp(connector); - if (connector->status != connector_status_connected) + if (connector->base.status != connector_status_connected) return -ENODEV; seq_printf(m, "Panel power up delay: %d\n", @@ -1139,23 +1138,23 @@ DEFINE_SHOW_ATTRIBUTE(i915_panel); static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); int ret; ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - if (!connector->encoder || connector->status != connector_status_connected) { + if (!connector->base.encoder || + connector->base.status != connector_status_connected) { ret = -ENODEV; goto out; } - seq_printf(m, "%s:%d HDCP version: ", connector->name, - connector->base.id); - intel_hdcp_info(m, intel_connector); + seq_printf(m, "%s:%d HDCP version: ", connector->base.name, + connector->base.base.id); + intel_hdcp_info(m, connector); out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); @@ -1166,16 +1165,16 @@ DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); static int i915_lpsp_capability_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_encoder *encoder; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); + int connector_type = connector->base.connector_type; bool lpsp_capable = false; - encoder = intel_attached_encoder(to_intel_connector(connector)); if (!encoder) return -ENODEV; - if (connector->status != connector_status_connected) + if (connector->base.status != connector_status_connected) return -ENODEV; if (DISPLAY_VER(i915) >= 13) @@ -1188,15 +1187,15 @@ static int i915_lpsp_capability_show(struct seq_file *m, void *data) */ lpsp_capable = encoder->port <= PORT_B; else if (DISPLAY_VER(i915) == 11) - lpsp_capable = (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP); + lpsp_capable = (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP); else if (IS_DISPLAY_VER(i915, 9, 10)) lpsp_capable = (encoder->port == PORT_A && - (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP || - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)); + (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP || + connector_type == DRM_MODE_CONNECTOR_DisplayPort)); else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) - lpsp_capable = connector->connector_type == DRM_MODE_CONNECTOR_eDP; + lpsp_capable = connector_type == DRM_MODE_CONNECTOR_eDP; seq_printf(m, "LPSP: %s\n", lpsp_capable ? "capable" : "incapable"); @@ -1206,7 +1205,7 @@ DEFINE_SHOW_ATTRIBUTE(i915_lpsp_capability); static int i915_dsc_fec_support_show(struct seq_file *m, void *data) { - struct intel_connector *connector = to_intel_connector(m->private); + struct intel_connector *connector = m->private; struct drm_i915_private *i915 = to_i915(connector->base.dev); struct drm_crtc *crtc; struct intel_dp *intel_dp; @@ -1276,13 +1275,13 @@ static ssize_t i915_dsc_fec_support_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); bool dsc_enable = false; int ret; - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (len == 0) return 0; @@ -1320,22 +1319,22 @@ static const struct file_operations i915_dsc_fec_support_fops = { static int i915_dsc_bpc_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); int ret; if (!encoder) return -ENODEV; - ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; goto out; } @@ -1343,7 +1342,7 @@ static int i915_dsc_bpc_show(struct seq_file *m, void *data) crtc_state = to_intel_crtc_state(crtc->state); seq_printf(m, "Input_BPC: %d\n", crtc_state->dsc.config.bits_per_component); -out: drm_modeset_unlock(&dev->mode_config.connection_mutex); +out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); return ret; } @@ -1352,9 +1351,9 @@ static ssize_t i915_dsc_bpc_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int dsc_bpc = 0; int ret; @@ -1386,22 +1385,22 @@ static const struct file_operations i915_dsc_bpc_fops = { static int i915_dsc_output_format_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); int ret; if (!encoder) return -ENODEV; - ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; goto out; } @@ -1410,7 +1409,7 @@ static int i915_dsc_output_format_show(struct seq_file *m, void *data) seq_printf(m, "DSC_Output_Format: %s\n", intel_output_format_name(crtc_state->output_format)); -out: drm_modeset_unlock(&dev->mode_config.connection_mutex); +out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); return ret; } @@ -1419,9 +1418,9 @@ static ssize_t i915_dsc_output_format_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int dsc_output_format = 0; int ret; @@ -1453,33 +1452,32 @@ static const struct file_operations i915_dsc_output_format_fops = { static int i915_dsc_fractional_bpp_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; struct intel_dp *intel_dp; - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_encoder *encoder = intel_attached_encoder(intel_connector); int ret; if (!encoder) return -ENODEV; - ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; goto out; } - intel_dp = intel_attached_dp(intel_connector); + intel_dp = intel_attached_dp(connector); seq_printf(m, "Force_DSC_Fractional_BPP_Enable: %s\n", str_yes_no(intel_dp->force_dsc_fractional_bpp_en)); out: - drm_modeset_unlock(&dev->mode_config.connection_mutex); + drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); return ret; } @@ -1488,10 +1486,10 @@ static ssize_t i915_dsc_fractional_bpp_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); - struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); bool dsc_fractional_bpp_enable = false; int ret; @@ -1586,29 +1584,29 @@ void intel_connector_debugfs_add(struct intel_connector *connector) if (connector_type == DRM_MODE_CONNECTOR_eDP) debugfs_create_file("i915_panel_timings", S_IRUGO, root, - &connector->base, &i915_panel_fops); + connector, &i915_panel_fops); if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_HDMIB) { debugfs_create_file("i915_hdcp_sink_capability", S_IRUGO, root, - &connector->base, &i915_hdcp_sink_capability_fops); + connector, &i915_hdcp_sink_capability_fops); } if (DISPLAY_VER(i915) >= 11 && ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !connector->mst_port) || connector_type == DRM_MODE_CONNECTOR_eDP)) { debugfs_create_file("i915_dsc_fec_support", 0644, root, - &connector->base, &i915_dsc_fec_support_fops); + connector, &i915_dsc_fec_support_fops); debugfs_create_file("i915_dsc_bpc", 0644, root, - &connector->base, &i915_dsc_bpc_fops); + connector, &i915_dsc_bpc_fops); debugfs_create_file("i915_dsc_output_format", 0644, root, - &connector->base, &i915_dsc_output_format_fops); + connector, &i915_dsc_output_format_fops); debugfs_create_file("i915_dsc_fractional_bpp", 0644, root, - &connector->base, &i915_dsc_fractional_bpp_fops); + connector, &i915_dsc_fractional_bpp_fops); } if (connector_type == DRM_MODE_CONNECTOR_DSI || @@ -1617,7 +1615,7 @@ void intel_connector_debugfs_add(struct intel_connector *connector) connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_HDMIB) debugfs_create_file("i915_lpsp_capability", 0444, root, - &connector->base, &i915_lpsp_capability_fops); + connector, &i915_lpsp_capability_fops); } /** From f270b7087dc8369d21018541157a270a023e7f21 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Dec 2023 15:41:43 +0200 Subject: [PATCH 3025/7721] drm/i915: use octal permissions in display debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Octal permissions are preferred over the symbolics ones. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231205134143.2427661-3-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 85e5e21a859c..0cb819fc2a0c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1096,7 +1096,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) for (i = 0; i < ARRAY_SIZE(intel_display_debugfs_files); i++) { debugfs_create_file(intel_display_debugfs_files[i].name, - S_IRUGO | S_IWUSR, + 0644, minor->debugfs_root, to_i915(minor->dev), intel_display_debugfs_files[i].fops); @@ -1583,13 +1583,13 @@ void intel_connector_debugfs_add(struct intel_connector *connector) intel_psr_connector_debugfs_add(connector); if (connector_type == DRM_MODE_CONNECTOR_eDP) - debugfs_create_file("i915_panel_timings", S_IRUGO, root, + debugfs_create_file("i915_panel_timings", 0444, root, connector, &i915_panel_fops); if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_HDMIB) { - debugfs_create_file("i915_hdcp_sink_capability", S_IRUGO, root, + debugfs_create_file("i915_hdcp_sink_capability", 0444, root, connector, &i915_hdcp_sink_capability_fops); } From 7054b551de18e9875fbdf8d4f3baade428353545 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 25 Oct 2023 12:11:31 +0200 Subject: [PATCH 3026/7721] drm/i915/display: Use i915_gem_object_get_dma_address to get dma address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Works better for xe like that. obj is no longer const. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20231204134946.16219-1-maarten.lankhorst@linux.intel.com Reviewed-by: Jouni Högander --- drivers/gpu/drm/i915/display/intel_cursor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index a515ae2831f8..926e2de00eb5 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -24,6 +24,8 @@ #include "intel_psr_regs.h" #include "skl_watermark.h" +#include "gem/i915_gem_object.h" + /* Cursor formats */ static const u32 intel_cursor_formats[] = { DRM_FORMAT_ARGB8888, @@ -34,11 +36,11 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; - const struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); u32 base; if (DISPLAY_INFO(dev_priv)->cursor_needs_physical) - base = sg_dma_address(obj->mm.pages->sgl); + base = i915_gem_object_get_dma_address(obj, 0); else base = intel_plane_ggtt_offset(plane_state); From 0647ece3819b018cb62a71c3bcb7c2c3243e78ac Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 1 Dec 2023 12:21:08 +0000 Subject: [PATCH 3027/7721] drm/i915/selftests: Fix engine reset count storage for multi-tile Engine->id namespace is per-tile so struct igt_live_test->reset_engine[] needs to be two-dimensional so engine reset counts from all tiles can be stored with no aliasing. With aliasing, if we had a real multi-tile platform, the reset counts would be incorrect for same engine instance on different tiles. Signed-off-by: Tvrtko Ursulin Fixes: 0c29efa23f5c ("drm/i915/selftests: Consider multi-gt instead of to_gt()") Reported-by: Alan Previn Teres Alexis Cc: Tejas Upadhyay Cc: Andi Shyti Cc: Daniele Ceraolo Spurio Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231201122109.729006-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/selftests/igt_live_test.c | 9 +++++---- drivers/gpu/drm/i915/selftests/igt_live_test.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/igt_live_test.c b/drivers/gpu/drm/i915/selftests/igt_live_test.c index 4ddc6d902752..7d41874a49c5 100644 --- a/drivers/gpu/drm/i915/selftests/igt_live_test.c +++ b/drivers/gpu/drm/i915/selftests/igt_live_test.c @@ -37,8 +37,9 @@ int igt_live_test_begin(struct igt_live_test *t, } for_each_engine(engine, gt, id) - t->reset_engine[id] = - i915_reset_engine_count(&i915->gpu_error, engine); + t->reset_engine[i][id] = + i915_reset_engine_count(&i915->gpu_error, + engine); } t->reset_global = i915_reset_count(&i915->gpu_error); @@ -66,14 +67,14 @@ int igt_live_test_end(struct igt_live_test *t) for_each_gt(gt, i915, i) { for_each_engine(engine, gt, id) { - if (t->reset_engine[id] == + if (t->reset_engine[i][id] == i915_reset_engine_count(&i915->gpu_error, engine)) continue; gt_err(gt, "%s(%s): engine '%s' was reset %d times!\n", t->func, t->name, engine->name, i915_reset_engine_count(&i915->gpu_error, engine) - - t->reset_engine[id]); + t->reset_engine[i][id]); return -EIO; } } diff --git a/drivers/gpu/drm/i915/selftests/igt_live_test.h b/drivers/gpu/drm/i915/selftests/igt_live_test.h index 36ed42736c52..83e3ad430922 100644 --- a/drivers/gpu/drm/i915/selftests/igt_live_test.h +++ b/drivers/gpu/drm/i915/selftests/igt_live_test.h @@ -7,6 +7,7 @@ #ifndef IGT_LIVE_TEST_H #define IGT_LIVE_TEST_H +#include "gt/intel_gt_defines.h" /* for I915_MAX_GT */ #include "gt/intel_engine.h" /* for I915_NUM_ENGINES */ struct drm_i915_private; @@ -17,7 +18,7 @@ struct igt_live_test { const char *name; unsigned int reset_global; - unsigned int reset_engine[I915_NUM_ENGINES]; + unsigned int reset_engine[I915_MAX_GT][I915_NUM_ENGINES]; }; /* From cf9cb028ac56696ff879af1154c4b2f0b12701fd Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 1 Dec 2023 12:21:09 +0000 Subject: [PATCH 3028/7721] drm/i915: Use internal class when counting engine resets Commit 503579448db9 ("drm/i915/gsc: Mark internal GSC engine with reserved uabi class") made the GSC0 engine not have a valid uabi class and so broke the engine reset counting, which in turn was made class based in cb823ed9915b ("drm/i915/gt: Use intel_gt as the primary object for handling resets"). Despite the title and commit text of the latter is not mentioning it (and has left the storage array incorrectly sized), tracking by class, despite it adding aliasing in hypthotetical multi-tile systems, is handy for virtual engines which for instance do not have a valid engine->id. Therefore we keep that but just change it to use the internal class which is always valid. We also add a helper to increment the count, which aligns with the existing getter. What was broken without this fix were out of bounds reads every time a reset would happen on the GSC0 engine, or during selftests when storing and cross-checking the counts in igt_live_test_begin and igt_live_test_end. Signed-off-by: Tvrtko Ursulin Fixes: dfed6b58d54f ("drm/i915/gsc: Mark internal GSC engine with reserved uabi class") [tursulin: fixed Fixes tag] Reported-by: Alan Previn Teres Alexis Cc: Daniele Ceraolo Spurio Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20231201122109.729006-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_reset.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 5 +++-- drivers/gpu/drm/i915/i915_gpu_error.h | 12 ++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index d5ed904f355d..6801f8b95c53 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -1293,7 +1293,7 @@ int __intel_engine_reset_bh(struct intel_engine_cs *engine, const char *msg) if (msg) drm_notice(&engine->i915->drm, "Resetting %s for %s\n", engine->name, msg); - atomic_inc(&engine->i915->gpu_error.reset_engine_count[engine->uabi_class]); + i915_increase_reset_engine_count(&engine->i915->gpu_error, engine); ret = intel_gt_reset_engine(engine); if (ret) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 04f8377fd7a3..58ea285c51d4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -5003,7 +5003,8 @@ static void capture_error_state(struct intel_guc *guc, if (match) { intel_engine_set_hung_context(e, ce); engine_mask |= e->mask; - atomic_inc(&i915->gpu_error.reset_engine_count[e->uabi_class]); + i915_increase_reset_engine_count(&i915->gpu_error, + e); } } @@ -5015,7 +5016,7 @@ static void capture_error_state(struct intel_guc *guc, } else { intel_engine_set_hung_context(ce->engine, ce); engine_mask = ce->engine->mask; - atomic_inc(&i915->gpu_error.reset_engine_count[ce->engine->uabi_class]); + i915_increase_reset_engine_count(&i915->gpu_error, ce->engine); } with_intel_runtime_pm(&i915->runtime_pm, wakeref) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 68c964d6720a..b75052e69a2b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -16,6 +16,7 @@ #include "display/intel_display_device.h" #include "gt/intel_engine.h" +#include "gt/intel_engine_types.h" #include "gt/intel_gt_types.h" #include "gt/uc/intel_uc_fw.h" @@ -232,7 +233,7 @@ struct i915_gpu_error { atomic_t reset_count; /** Number of times an engine has been reset */ - atomic_t reset_engine_count[I915_NUM_ENGINES]; + atomic_t reset_engine_count[MAX_ENGINE_CLASS]; }; struct drm_i915_error_state_buf { @@ -255,7 +256,14 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error) static inline u32 i915_reset_engine_count(struct i915_gpu_error *error, const struct intel_engine_cs *engine) { - return atomic_read(&error->reset_engine_count[engine->uabi_class]); + return atomic_read(&error->reset_engine_count[engine->class]); +} + +static inline void +i915_increase_reset_engine_count(struct i915_gpu_error *error, + const struct intel_engine_cs *engine) +{ + atomic_inc(&error->reset_engine_count[engine->class]); } #define CORE_DUMP_FLAG_NONE 0x0 From 3bc05faf37876f99e2a7baffa9c66fdcfb11d1f7 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 5 Dec 2023 17:42:30 +0100 Subject: [PATCH 3029/7721] net: dsa: microchip: properly support platform_data probing The ksz driver has bits and pieces of platform_data probing support, but it doesn't work. The conventional thing to do is to have an encapsulating structure for struct dsa_chip_data that gets put into dev->platform_data. This driver expects a struct ksz_platform_data, but that doesn't contain a struct dsa_chip_data as first element, which will obviously not work with dsa_switch_probe() -> dsa_switch_parse(). Pointing dev->platform_data to a struct dsa_chip_data directly is in principle possible, but that doesn't work either. The driver has ksz_switch_detect() to read the device ID from hardware, followed by ksz_check_device_id() to compare it against a predetermined expected value. This protects against early errors in the SPI/I2C communication. With platform_data, the mechanism in ksz_check_device_id() doesn't work and even leads to NULL pointer dereferences, since of_device_get_match_data() doesn't work in that probe path. So obviously, the platform_data support is actually missing, and the existing handling of struct ksz_platform_data is bogus. Complete the support by adding a struct dsa_chip_data as first element, and fixing up ksz_check_device_id() to pick up the platform_data instead of the unavailable of_device_get_match_data(). The early dev->chip_id assignment from ksz_switch_register() is also bogus, because ksz_switch_detect() sets it to an initial value. So remove it. Also, ksz_platform_data :: enabled_ports isn't used anywhere, delete it. Link: https://lore.kernel.org/netdev/20231204154315.3906267-1-dd@embedd.com/ Signed-off-by: Vladimir Oltean Signed-off-by: Daniel Danzberger Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 21 +++++++++++++-------- include/linux/platform_data/microchip-ksz.h | 4 +++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 9545aed905f5..db1bbcf3a5f2 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1673,15 +1673,23 @@ static const struct ksz_chip_data *ksz_lookup_info(unsigned int prod_num) static int ksz_check_device_id(struct ksz_device *dev) { - const struct ksz_chip_data *dt_chip_data; + const struct ksz_chip_data *expected_chip_data; + u32 expected_chip_id; - dt_chip_data = of_device_get_match_data(dev->dev); + if (dev->pdata) { + expected_chip_id = dev->pdata->chip_id; + expected_chip_data = ksz_lookup_info(expected_chip_id); + if (WARN_ON(!expected_chip_data)) + return -ENODEV; + } else { + expected_chip_data = of_device_get_match_data(dev->dev); + expected_chip_id = expected_chip_data->chip_id; + } - /* Check for Device Tree and Chip ID */ - if (dt_chip_data->chip_id != dev->chip_id) { + if (expected_chip_id != dev->chip_id) { dev_err(dev->dev, "Device tree specifies chip %s but found %s, please fix it!\n", - dt_chip_data->dev_name, dev->info->dev_name); + expected_chip_data->dev_name, dev->info->dev_name); return -ENODEV; } @@ -4156,9 +4164,6 @@ int ksz_switch_register(struct ksz_device *dev) int ret; int i; - if (dev->pdata) - dev->chip_id = dev->pdata->chip_id; - dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(dev->reset_gpio)) diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h index ea1cc6d829e9..6480bf4af0fb 100644 --- a/include/linux/platform_data/microchip-ksz.h +++ b/include/linux/platform_data/microchip-ksz.h @@ -20,10 +20,12 @@ #define __MICROCHIP_KSZ_H #include +#include struct ksz_platform_data { + /* Must be first such that dsa_register_switch() can access it */ + struct dsa_chip_data cd; u32 chip_id; - u16 enabled_ports; }; #endif From d16f1096b320d42e41ad9dee4d4098afd140d3e1 Mon Sep 17 00:00:00 2001 From: Daniel Danzberger Date: Tue, 5 Dec 2023 17:42:31 +0100 Subject: [PATCH 3030/7721] net: dsa: microchip: move ksz_chip_id enum to platform include With the ksz_chip_id enums moved to the platform include file for ksz switches, platform code that instantiates a device can now use these to set ksz_platform_data::chip_id. Signed-off-by: Daniel Danzberger Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.h | 20 +------------------- include/linux/platform_data/microchip-ksz.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index d1a1c876ba0d..15612101a155 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "ksz_ptp.h" @@ -203,25 +204,6 @@ enum ksz_model { LAN9374, }; -enum ksz_chip_id { - KSZ8563_CHIP_ID = 0x8563, - KSZ8795_CHIP_ID = 0x8795, - KSZ8794_CHIP_ID = 0x8794, - KSZ8765_CHIP_ID = 0x8765, - KSZ8830_CHIP_ID = 0x8830, - KSZ9477_CHIP_ID = 0x00947700, - KSZ9896_CHIP_ID = 0x00989600, - KSZ9897_CHIP_ID = 0x00989700, - KSZ9893_CHIP_ID = 0x00989300, - KSZ9563_CHIP_ID = 0x00956300, - KSZ9567_CHIP_ID = 0x00956700, - LAN9370_CHIP_ID = 0x00937000, - LAN9371_CHIP_ID = 0x00937100, - LAN9372_CHIP_ID = 0x00937200, - LAN9373_CHIP_ID = 0x00937300, - LAN9374_CHIP_ID = 0x00937400, -}; - enum ksz_regs { REG_SW_MAC_ADDR, REG_IND_CTRL_0, diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h index 6480bf4af0fb..f177416635a2 100644 --- a/include/linux/platform_data/microchip-ksz.h +++ b/include/linux/platform_data/microchip-ksz.h @@ -22,6 +22,25 @@ #include #include +enum ksz_chip_id { + KSZ8563_CHIP_ID = 0x8563, + KSZ8795_CHIP_ID = 0x8795, + KSZ8794_CHIP_ID = 0x8794, + KSZ8765_CHIP_ID = 0x8765, + KSZ8830_CHIP_ID = 0x8830, + KSZ9477_CHIP_ID = 0x00947700, + KSZ9896_CHIP_ID = 0x00989600, + KSZ9897_CHIP_ID = 0x00989700, + KSZ9893_CHIP_ID = 0x00989300, + KSZ9563_CHIP_ID = 0x00956300, + KSZ9567_CHIP_ID = 0x00956700, + LAN9370_CHIP_ID = 0x00937000, + LAN9371_CHIP_ID = 0x00937100, + LAN9372_CHIP_ID = 0x00937200, + LAN9373_CHIP_ID = 0x00937300, + LAN9374_CHIP_ID = 0x00937400, +}; + struct ksz_platform_data { /* Must be first such that dsa_register_switch() can access it */ struct dsa_chip_data cd; From ce17aa4cf2db7d6b95a3f854ac52d0d49881dd49 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 Dec 2023 11:54:25 +0200 Subject: [PATCH 3031/7721] ASoC: SOF: Intel: hda-codec: Delay the codec device registration The current code flow is: 1. snd_hdac_device_register() 2. set parameters needed by the hdac driver 3. request_codec_module() the hdac driver is probed at this point During boot the codec drivers are not loaded when the hdac device is registered, it is going to be probed later when loading the codec module, which point the parameters are set. On module remove/insert rmmod snd_sof_pci_intel_tgl modprobe snd_sof_pci_intel_tgl The codec module remains loaded and the driver will be probed when the hdac device is created right away, before the parameters for the driver has been configured: 1. snd_hdac_device_register() the hdac driver is probed at this point 2. set parameters needed by the hdac driver 3. request_codec_module() will be a NOP as the module is already loaded Move the snd_hdac_device_register() later, to be done right before requesting the codec module to make sure that the parameters are all set before the device is created: 1. set parameters needed by the hdac driver 2. snd_hdac_device_register() 3. request_codec_module() This way at the hdac driver probe all parameters will be set in all cases. Link: https://github.com/thesofproject/linux/issues/4731 Fixes: a0575b4add21 ("ASoC: hdac_hda: Conditionally register dais for HDMI and Analog") Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20231207095425.19597-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-codec.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 28ecbebb4b84..9f84b0d287a5 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -54,8 +54,16 @@ static int request_codec_module(struct hda_codec *codec) static int hda_codec_load_module(struct hda_codec *codec) { - int ret = request_codec_module(codec); + int ret; + ret = snd_hdac_device_register(&codec->core); + if (ret) { + dev_err(&codec->core.dev, "failed to register hdac device\n"); + put_device(&codec->core.dev); + return ret; + } + + ret = request_codec_module(codec); if (ret <= 0) { codec->probe_id = HDA_CODEC_ID_GENERIC; ret = request_codec_module(codec); @@ -116,7 +124,6 @@ EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, int type) { struct hda_codec *codec; - int ret; codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); if (IS_ERR(codec)) { @@ -126,13 +133,6 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i codec->core.type = type; - ret = snd_hdac_device_register(&codec->core); - if (ret) { - dev_err(bus->dev, "failed to register hdac device\n"); - put_device(&codec->core.dev); - return ERR_PTR(ret); - } - return codec; } From 8527ecc6cf25417a1940f91eb91fca0c69a5c553 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Thu, 7 Dec 2023 10:25:01 +0530 Subject: [PATCH 3032/7721] ASoC: amd: acp: modify config flag read logic Modify acp config flag read logic from ACP v7.0 onwards. Instead of reading from DMI table match entry, read the config flag value from BIOS ACPI table. This will remove updating DMI table when new platform support is added. Use FLAG_AMD_LEGACY_ONLY_DMIC flag as default one. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20231207045505.1519151-1-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 04b58fb29a35..067b1fdfbc9d 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -19,6 +19,8 @@ #include "../sof/amd/acp.h" #include "mach-config.h" +#define ACP_7_0_REV 0x70 + static int acp_quirk_data; static const struct config_entry config_table[] = { @@ -145,15 +147,33 @@ static const struct config_entry config_table[] = { }, }; +static int snd_amd_acp_acpi_find_config(struct pci_dev *pci) +{ + const union acpi_object *obj; + int acp_flag = FLAG_AMD_LEGACY_ONLY_DMIC; + + if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-audio-config-flag", + ACPI_TYPE_INTEGER, &obj)) + acp_flag = obj->integer.value; + + return acp_flag; +} + int snd_amd_acp_find_config(struct pci_dev *pci) { const struct config_entry *table = config_table; u16 device = pci->device; int i; - /* Do not enable FLAGS on older platforms with Rev id zero */ + /* Do not enable FLAGS on older platforms with Rev Id zero + * For platforms which has ACP 7.0 or higher, read the acp + * config flag from BIOS ACPI table and for older platforms + * read it from DMI tables. + */ if (!pci->revision) return 0; + else if (pci->revision >= ACP_7_0_REV) + return snd_amd_acp_acpi_find_config(pci); for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) { if (table->device != device) From 37c8ceb6d92c955f5dd8223c3f6c90b277322210 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Mon, 30 Oct 2023 08:22:26 +0200 Subject: [PATCH 3033/7721] mmc: core: Remove packed command leftovers Packed commands support was removed long time ago, but some bits got left behind. Remove them. Signed-off-by: Avri Altman Link: https://lore.kernel.org/r/20231030062226.1895692-1-avri.altman@wdc.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 5 ----- include/linux/mmc/card.h | 3 --- include/linux/mmc/core.h | 1 - include/linux/mmc/mmc.h | 10 ---------- 4 files changed, 19 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 705942edacc6..7b996db570c9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -613,11 +613,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) } else { card->ext_csd.data_tag_unit_size = 0; } - - card->ext_csd.max_packed_writes = - ext_csd[EXT_CSD_MAX_PACKED_WRITES]; - card->ext_csd.max_packed_reads = - ext_csd[EXT_CSD_MAX_PACKED_READS]; } else { card->ext_csd.data_sector_size = 512; } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 7b12eebc5586..47eeb122524c 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -52,9 +52,6 @@ struct mmc_ext_csd { u8 part_config; u8 cache_ctrl; u8 rst_n_function; - u8 max_packed_writes; - u8 max_packed_reads; - u8 packed_event_en; unsigned int part_time; /* Units: ms */ unsigned int sa_timeout; /* Units: 100ns */ unsigned int generic_cmd6_time; /* Units: 10ms */ diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 6efec0b9820c..2c7928a50907 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -27,7 +27,6 @@ struct mmc_command { u32 opcode; u32 arg; #define MMC_CMD23_ARG_REL_WR (1 << 31) -#define MMC_CMD23_ARG_PACKED ((0 << 31) | (1 << 30)) #define MMC_CMD23_ARG_TAG_REQ (1 << 29) u32 resp[4]; unsigned int flags; /* expected response type */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 6f7993803ee7..cf2bcb5da30d 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -257,8 +257,6 @@ static inline bool mmc_ready_for_data(u32 status) #define EXT_CSD_FLUSH_CACHE 32 /* W */ #define EXT_CSD_CACHE_CTRL 33 /* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ -#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ -#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ #define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ #define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ @@ -321,8 +319,6 @@ static inline bool mmc_ready_for_data(u32 status) #define EXT_CSD_SUPPORTED_MODE 493 /* RO */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ -#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ -#define EXT_CSD_MAX_PACKED_READS 501 /* RO */ #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ #define EXT_CSD_HPI_FEATURES 503 /* RO */ @@ -402,18 +398,12 @@ static inline bool mmc_ready_for_data(u32 status) #define EXT_CSD_PWR_CL_8BIT_SHIFT 4 #define EXT_CSD_PWR_CL_4BIT_SHIFT 0 -#define EXT_CSD_PACKED_EVENT_EN BIT(3) - /* * EXCEPTION_EVENT_STATUS field */ #define EXT_CSD_URGENT_BKOPS BIT(0) #define EXT_CSD_DYNCAP_NEEDED BIT(1) #define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) -#define EXT_CSD_PACKED_FAILURE BIT(3) - -#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0) -#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1) /* * BKOPS status level From 1bcfbfd7c9aa716f61a01682345a1b329f6a6e66 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Wed, 8 Nov 2023 15:16:37 +0100 Subject: [PATCH 3034/7721] mmc: mmci: stm32: add SDIO in-band interrupt mode Add the support of SDIO in-band interrupt mode for STM32 and Ux500 variants. It allows the SD I/O card to interrupt the host on SDMMC_D1 data line. It is not enabled by default on Ux500 variant as this is unstable and Ux500 users should use out-of-band IRQs. Signed-off-by: Christophe Kerello Signed-off-by: Yann Gautier Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231108141637.119497-1-yann.gautier@foss.st.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 69 +++++++++++++++++++++++++++++++++++++++-- drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e967cca7a16f..b790c3c3c8f9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -273,6 +273,7 @@ static struct variant_data variant_stm32_sdmmc = { .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .stm32_idmabsize_mask = GENMASK(12, 5), .stm32_idmabsize_align = BIT(5), + .supports_sdio_irq = true, .busy_timeout = true, .busy_detect = true, .busy_detect_flag = MCI_STM32_BUSYD0, @@ -300,6 +301,7 @@ static struct variant_data variant_stm32_sdmmcv2 = { .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .stm32_idmabsize_mask = GENMASK(16, 5), .stm32_idmabsize_align = BIT(5), + .supports_sdio_irq = true, .dma_lli = true, .busy_timeout = true, .busy_detect = true, @@ -328,6 +330,7 @@ static struct variant_data variant_stm32_sdmmcv3 = { .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .stm32_idmabsize_mask = GENMASK(16, 6), .stm32_idmabsize_align = BIT(6), + .supports_sdio_irq = true, .dma_lli = true, .busy_timeout = true, .busy_detect = true, @@ -421,8 +424,9 @@ void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) */ static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) { - /* Keep busy mode in DPSM if enabled */ - datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag; + /* Keep busy mode in DPSM and SDIO mask if enabled */ + datactrl |= host->datactrl_reg & (host->variant->busy_dpsm_flag | + host->variant->datactrl_mask_sdio); if (host->datactrl_reg != datactrl) { host->datactrl_reg = datactrl; @@ -1762,6 +1766,25 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void mmci_write_sdio_irq_bit(struct mmci_host *host, int enable) +{ + void __iomem *base = host->base; + u32 mask = readl_relaxed(base + MMCIMASK0); + + if (enable) + writel_relaxed(mask | MCI_ST_SDIOITMASK, base + MMCIMASK0); + else + writel_relaxed(mask & ~MCI_ST_SDIOITMASK, base + MMCIMASK0); +} + +static void mmci_signal_sdio_irq(struct mmci_host *host, u32 status) +{ + if (status & MCI_ST_SDIOIT) { + mmci_write_sdio_irq_bit(host, 0); + sdio_signal_irq(host->mmc); + } +} + /* * Handle completion of command and data transfers. */ @@ -1806,6 +1829,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) mmci_data_irq(host, host->data, status); } + if (host->variant->supports_sdio_irq) + mmci_signal_sdio_irq(host, status); + /* * Busy detection has been handled by mmci_cmd_irq() above. * Clear the status bit to prevent polling in IRQ context. @@ -2042,6 +2068,35 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) return ret; } +static void mmci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned long flags; + + if (enable) + /* Keep the SDIO mode bit if SDIO irqs are enabled */ + pm_runtime_get_sync(mmc_dev(mmc)); + + spin_lock_irqsave(&host->lock, flags); + mmci_write_sdio_irq_bit(host, enable); + spin_unlock_irqrestore(&host->lock, flags); + + if (!enable) { + pm_runtime_mark_last_busy(mmc_dev(mmc)); + pm_runtime_put_autosuspend(mmc_dev(mmc)); + } +} + +static void mmci_ack_sdio_irq(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + mmci_write_sdio_irq_bit(host, 1); + spin_unlock_irqrestore(&host->lock, flags); +} + static struct mmc_host_ops mmci_ops = { .request = mmci_request, .pre_req = mmci_pre_request, @@ -2317,6 +2372,16 @@ static int mmci_probe(struct amba_device *dev, mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; } + if (variant->supports_sdio_irq && host->mmc->caps & MMC_CAP_SDIO_IRQ) { + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + + mmci_ops.enable_sdio_irq = mmci_enable_sdio_irq; + mmci_ops.ack_sdio_irq = mmci_ack_sdio_irq; + + mmci_write_datactrlreg(host, + host->variant->datactrl_mask_sdio); + } + /* Variants with mandatory busy timeout in HW needs R1B responses. */ if (variant->busy_timeout) mmc->caps |= MMC_CAP_NEED_RSP_BUSY; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 34d9897c289b..a5eb4ced4d5d 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -331,6 +331,7 @@ enum mmci_busy_state { * register. * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register * @dma_lli: true if variant has dma link list feature. + * @supports_sdio_irq: allow SD I/O card to interrupt the host * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size. * @dma_flow_controller: use peripheral as flow controller for DMA. */ @@ -377,6 +378,7 @@ struct variant_data { u32 start_err; u32 opendrain; u8 dma_lli:1; + bool supports_sdio_irq; u32 stm32_idmabsize_mask; u32 stm32_idmabsize_align; bool dma_flow_controller; From edee955389176dfd798d29a69098ce5744d09833 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 9 Nov 2023 21:41:11 -0800 Subject: [PATCH 3035/7721] dt-bindings: mmc: sdhci-of-dwcmhsc: Add T-Head TH1520 support Add compatible value for the T-Head TH1520 dwcmshc controller. Acked-by: Guo Ren Acked-by: Krzysztof Kozlowski Signed-off-by: Drew Fustini Link: https://lore.kernel.org/r/20231109-th1520-mmc-v5-1-018bd039cf17@baylibre.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml index a43eb837f8da..42804d955293 100644 --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml @@ -19,6 +19,7 @@ properties: - rockchip,rk3568-dwcmshc - rockchip,rk3588-dwcmshc - snps,dwcmshc-sdhci + - thead,th1520-dwcmshc reg: maxItems: 1 From 9cc811a342be78270d20d1fff3832bc0b23ef364 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 9 Nov 2023 21:41:12 -0800 Subject: [PATCH 3036/7721] mmc: sdhci: add __sdhci_execute_tuning() to header Expose __sdhci_execute_tuning() so that it can be called from the mmc host controller drivers. In the sdhci-of-dwcmshc driver, sdhci_dwcmshc_th1520_ops sets platform_execute_tuning to th1520_execute_tuning(). That function has to manipulate phy registers before tuning can be performed. To avoid copying the code verbatim from __sdhci_execute_tuning() into th1520_execute_tuning(), make it possible for __sdhci_execute_tuning() to be called from sdhci-of-dwcmshc. Acked-by: Adrian Hunter Signed-off-by: Drew Fustini Link: https://lore.kernel.org/r/20231109-th1520-mmc-v5-2-018bd039cf17@baylibre.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 3 ++- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ff41aa56564e..c79f73459915 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2841,7 +2841,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) } EXPORT_SYMBOL_GPL(sdhci_send_tuning); -static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) { int i; @@ -2879,6 +2879,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) sdhci_reset_tuning(host); return -EAGAIN; } +EXPORT_SYMBOL_GPL(__sdhci_execute_tuning); int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f219bdea8f28..a20864fc0641 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); +int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode); void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios); From 43658a542ebf13f1bb80cfaa8ae58f061d0d71b0 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 9 Nov 2023 21:41:13 -0800 Subject: [PATCH 3037/7721] mmc: sdhci-of-dwcmshc: Add support for T-Head TH1520 Add support for the mmc controller in the T-Head TH1520 with the new compatible "thead,th1520-dwcmshc". Implement custom sdhci_ops for set_uhs_signaling, reset, voltage_switch, and platform_execute_tuning. Acked-by: Adrian Hunter Signed-off-by: Drew Fustini Link: https://lore.kernel.org/r/20231109-th1520-mmc-v5-3-018bd039cf17@baylibre.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 349 ++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 3a3bae6948a8..0eb72544c09e 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -35,6 +36,21 @@ #define DWCMSHC_CARD_IS_EMMC BIT(0) #define DWCMSHC_ENHANCED_STROBE BIT(8) #define DWCMSHC_EMMC_ATCTRL 0x40 +/* Tuning and auto-tuning fields in AT_CTRL_R control register */ +#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */ +#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */ +#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */ +#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */ +#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */ +#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits [11:8] */ +#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */ +#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */ +#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits [18:17] */ +#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */ +#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits [20:19] */ +#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */ +#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */ +#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ /* Rockchip specific Registers */ #define DWCMSHC_EMMC_DLL_CTRL 0x800 @@ -72,6 +88,82 @@ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) #define RK35xx_MAX_CLKS 3 +/* PHY register area pointer */ +#define DWC_MSHC_PTR_PHY_R 0x300 + +/* PHY general configuration */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ + +/* PHY command/response pad settings */ +#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04) + +/* PHY data pad settings */ +#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06) + +/* PHY clock pad settings */ +#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08) + +/* PHY strobe pad settings */ +#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a) + +/* PHY reset pad settings */ +#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c) + +/* Bitfields are common for all pad settings */ +#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */ +#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */ + +#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits [4:3] */ +#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */ +#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */ + +#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits [8:5] */ +#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */ +#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits [12:9] */ +#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */ + +/* PHY CLK delay line settings */ +#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ + +/* PHY CLK delay line delay code */ +#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e) +#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */ +#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */ +#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */ + +/* PHY drift_cclk_rx delay line configuration setting */ +#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21) +#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits [3:2] */ +#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */ + +/* PHY DLL control settings */ +#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24) +#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */ +#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */ + +/* PHY DLL configuration register 1 */ +#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25) +#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits [5:4] */ +#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */ +#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */ + +/* PHY DLL configuration register 2 */ +#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26) +#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */ + +/* PHY DLL master and slave delay line configuration settings */ +#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28) +#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits [6:5] */ +#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */ + +#define FLAG_IO_FIXED_1V8 BIT(0) + #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) @@ -92,6 +184,8 @@ struct dwcmshc_priv { struct clk *bus_clk; int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ void *priv; /* pointer to SoC private stuff */ + u16 delay_line; + u16 flags; }; /* @@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_request(mmc, mrq); } +static void dwcmshc_phy_1_8v_init(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val; + + /* deassert phy reset & set tx drive strength */ + val = PHY_CNFG_RSTN_DEASSERT; + val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); + val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); + sdhci_writel(host, val, PHY_CNFG_R); + + /* disable delay line */ + sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); + + /* set delay line */ + sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); + sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); + + /* enable delay lane */ + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE); + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + + /* configure phy pads */ + val = PHY_PAD_RXSEL_1V8; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); + sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); + sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); + + val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); + + val = PHY_PAD_RXSEL_1V8; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_STBPAD_CNFG_R); + + /* enable data strobe mode */ + sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL), + PHY_DLLDL_CNFG_R); + + /* enable phy dll */ + sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); +} + +static void dwcmshc_phy_3_3v_init(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val; + + /* deassert phy reset & set tx drive strength */ + val = PHY_CNFG_RSTN_DEASSERT; + val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); + val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); + sdhci_writel(host, val, PHY_CNFG_R); + + /* disable delay line */ + sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); + + /* set delay line */ + sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); + sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); + + /* enable delay lane */ + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE); + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + + /* configure phy pads */ + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); + sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); + sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); + + val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); + + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_STBPAD_CNFG_R); + + /* enable phy dll */ + sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); +} + +static void th1520_sdhci_set_phy(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + u16 emmc_ctrl; + + /* Before power on, set PHY configs */ + if (priv->flags & FLAG_IO_FIXED_1V8) + dwcmshc_phy_1_8v_init(host); + else + dwcmshc_phy_3_3v_init(host); + + if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { + emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); + emmc_ctrl |= DWCMSHC_CARD_IS_EMMC; + sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); + } + + sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) | + PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R); +} + static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { @@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, ctrl_2 |= DWCMSHC_CTRL_HS400; } + if (priv->flags & FLAG_IO_FIXED_1V8) + ctrl_2 |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } +static void th1520_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + + dwcmshc_set_uhs_signaling(host, timing); + if (timing == MMC_TIMING_MMC_HS400) + priv->delay_line = PHY_SDCLKDL_DC_HS400; + else + sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R); + th1520_sdhci_set_phy(host); +} + static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_reset(host, mask); } +static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val = 0; + + if (host->flags & SDHCI_HS400_TUNING) + return 0; + + sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL), + PHY_ATDL_CNFG_R); + val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + + /* + * configure tuning settings: + * - center phase select code driven in block gap interval + * - disable reporting of framing errors + * - disable software managed tuning + * - disable user selection of sampling window edges, + * instead tuning calculated edges are used + */ + val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN | + FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL)); + + /* + * configure tuning settings: + * - enable auto-tuning + * - enable sampling window threshold + * - stop clocks during phase code change + * - set max latency in cycles between tx and rx clocks + * - set max latency in cycles to switch output phase + * - set max sampling window threshold value + */ + val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN; + val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY); + val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY); + val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL); + + sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + + /* perform tuning */ + sdhci_start_tuning(host); + host->tuning_err = __sdhci_execute_tuning(host, opcode); + if (host->tuning_err) { + /* disable auto-tuning upon tuning error */ + val &= ~AT_CTRL_AT_EN; + sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err); + return -EIO; + } + sdhci_end_tuning(host); + + return 0; +} + +static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u16 ctrl_2; + + sdhci_reset(host, mask); + + if (priv->flags & FLAG_IO_FIXED_1V8) { + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) { + ctrl_2 |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + } +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { .adma_write_desc = dwcmshc_adma_write_desc, }; +static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = th1520_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .reset = th1520_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .voltage_switch = dwcmshc_phy_1_8v_init, + .platform_execute_tuning = &th1520_execute_tuning, +}; + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { .ops = &sdhci_dwcmshc_ops, .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, @@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { + .ops = &sdhci_dwcmshc_th1520_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) { int err; @@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "snps,dwcmshc-sdhci", .data = &sdhci_dwcmshc_pdata, }, + { + .compatible = "thead,th1520-dwcmshc", + .data = &sdhci_dwcmshc_th1520_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); @@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev) goto err_clk; } + if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { + priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; + + if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | + (device_property_read_bool(dev, "mmc-hs200-1_8v")) | + (device_property_read_bool(dev, "mmc-hs400-1_8v"))) + priv->flags |= FLAG_IO_FIXED_1V8; + else + priv->flags &= ~FLAG_IO_FIXED_1V8; + + /* + * start_signal_voltage_switch() will try 3.3V first + * then 1.8V. Use SDHCI_SIGNALING_180 rather than + * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V + * in sdhci_start_signal_voltage_switch(). + */ + if (priv->flags & FLAG_IO_FIXED_1V8) { + host->flags &= ~SDHCI_SIGNALING_330; + host->flags |= SDHCI_SIGNALING_180; + } + + sdhci_enable_v4_mode(host); + } + #ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) sdhci_enable_v4_mode(host); From dd69bd870998648c53fb11ea152c6b960b870b0b Mon Sep 17 00:00:00 2001 From: Swati Agarwal Date: Tue, 14 Nov 2023 15:53:21 +0530 Subject: [PATCH 3038/7721] dt-bindings: mmc: arasan,sdci: Add gate property for Xilinx platforms Add gate property in example node for Xilinx platforms which will be used to ungate the DLL clock. DLL clock is required for higher frequencies like 50MHz, 100MHz and 200MHz. DLL clock is automatically selected by the SD controller when the SD output clock frequency is more than 25 MHz. Signed-off-by: Swati Agarwal Co-developed-by: Sai Krishna Potthuri Signed-off-by: Sai Krishna Potthuri Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231114102321.1147951-1-sai.krishna.potthuri@amd.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml index 3e99801f77d2..9075add020bf 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml @@ -226,8 +226,8 @@ examples: interrupt-parent = <&gic>; interrupts = <0 48 4>; reg = <0xff160000 0x1000>; - clocks = <&clk200>, <&clk200>; - clock-names = "clk_xin", "clk_ahb"; + clocks = <&clk200>, <&clk200>, <&clk1200>; + clock-names = "clk_xin", "clk_ahb", "gate"; clock-output-names = "clk_out_sd0", "clk_in_sd0"; #clock-cells = <1>; clk-phase-sd-hs = <63>, <72>; @@ -239,8 +239,8 @@ examples: interrupt-parent = <&gic>; interrupts = <0 126 4>; reg = <0xf1040000 0x10000>; - clocks = <&clk200>, <&clk200>; - clock-names = "clk_xin", "clk_ahb"; + clocks = <&clk200>, <&clk200>, <&clk1200>; + clock-names = "clk_xin", "clk_ahb", "gate"; clock-output-names = "clk_out_sd0", "clk_in_sd0"; #clock-cells = <1>; clk-phase-sd-hs = <132>, <60>; From 3e3ce6314fc0eaa91d4cf7a663f6f3a793b4988c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 15 Nov 2023 20:32:54 +0000 Subject: [PATCH 3039/7721] dt-bindings: mmc: renesas,sdhi: Document RZ/Five SoC The SDHI block on the RZ/Five SoC is identical to one found on the RZ/G2UL SoC. "renesas,sdhi-r9a07g043" compatible string will be used on the RZ/Five SoC so to make this clear and to keep this file consistent, update the comment to include RZ/Five SoC. No driver changes are required as generic compatible string "renesas,rcar-gen3-sdhi" will be used as a fallback on RZ/Five SoC. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20231115203254.30544-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml index 94e228787630..f7a4c6bc70f6 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml +++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml @@ -56,7 +56,7 @@ properties: - renesas,sdhi-r8a77980 # R-Car V3H - renesas,sdhi-r8a77990 # R-Car E3 - renesas,sdhi-r8a77995 # R-Car D3 - - renesas,sdhi-r9a07g043 # RZ/G2UL + - renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five - renesas,sdhi-r9a07g044 # RZ/G2{L,LC} - renesas,sdhi-r9a07g054 # RZ/V2L - renesas,sdhi-r9a08g045 # RZ/G3S From e18a38660786dbe8536ecf74563df25936a3532a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 16 Nov 2023 18:46:00 -0700 Subject: [PATCH 3040/7721] mmc: sdhci-of-dwcmshc: Use logical OR instead of bitwise OR in dwcmshc_probe() Clang warns (or errors with CONFIG_WERROR=y): drivers/mmc/host/sdhci-of-dwcmshc.c:873:7: error: use of bitwise '|' with boolean operands [-Werror,-Wbitwise-instead-of-logical] 873 | if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 874 | (device_property_read_bool(dev, "mmc-hs200-1_8v")) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | || 875 | (device_property_read_bool(dev, "mmc-hs400-1_8v"))) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mmc/host/sdhci-of-dwcmshc.c:873:7: note: cast one or both operands to int to silence this warning drivers/mmc/host/sdhci-of-dwcmshc.c:873:7: error: use of bitwise '|' with boolean operands [-Werror,-Wbitwise-instead-of-logical] 873 | if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | || 874 | (device_property_read_bool(dev, "mmc-hs200-1_8v")) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mmc/host/sdhci-of-dwcmshc.c:873:7: note: cast one or both operands to int to silence this warning 2 errors generated. There is little reason for this if statement to use bitwise ORs, as the short circuiting of logical OR does not need to be avoided in this context; it would be wasteful to call device_property_read_bool() three times if the first two calls returned true. Switch to logical OR to fix the warning. While in the area, the parentheses around the calls to device_property_read_bool() are not necessary and make the if statement harder to read, so remove them. Closes: https://github.com/ClangBuiltLinux/linux/issues/1960 Signed-off-by: Nathan Chancellor Acked-by: Adrian Hunter Tested-by: Drew Fustini Link: https://lore.kernel.org/r/20231116-sdhci-of-dwcmshc-fix-wbitwise-instead-of-logical-v1-1-7e1a7f4ccaab@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 0eb72544c09e..a1f57af6acfb 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -870,9 +870,9 @@ static int dwcmshc_probe(struct platform_device *pdev) if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; - if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | - (device_property_read_bool(dev, "mmc-hs200-1_8v")) | - (device_property_read_bool(dev, "mmc-hs400-1_8v"))) + if (device_property_read_bool(dev, "mmc-ddr-1_8v") || + device_property_read_bool(dev, "mmc-hs200-1_8v") || + device_property_read_bool(dev, "mmc-hs400-1_8v")) priv->flags |= FLAG_IO_FIXED_1V8; else priv->flags &= ~FLAG_IO_FIXED_1V8; From 5cb2f9286a31f33dc732c57540838ad9339393ab Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 22 Nov 2023 11:32:14 +0530 Subject: [PATCH 3041/7721] mmc: sdhci_am654: Drop lookup for deprecated ti,otap-del-sel ti,otap-del-sel has been deprecated since v5.7 and there are no users of this property and no documentation in the DT bindings either. Drop the fallback code looking for this property, this makes sdhci_am654_get_otap_delay() much easier to read as all the TAP values can be handled via a single iterator loop. Signed-off-by: Vignesh Raghavendra Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20231122060215.2074799-1-vigneshr@ti.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 37 ++++++---------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 967bd2dfcda1..d659c59422e1 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -141,7 +141,6 @@ static const struct timing_data td[] = { struct sdhci_am654_data { struct regmap *base; - bool legacy_otapdly; int otap_del_sel[ARRAY_SIZE(td)]; int itap_del_sel[ARRAY_SIZE(td)]; int clkbuf_sel; @@ -272,11 +271,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_set_clock(host, clock); /* Setup DLL Output TAP delay */ - if (sdhci_am654->legacy_otapdly) - otap_del_sel = sdhci_am654->otap_del_sel[0]; - else - otap_del_sel = sdhci_am654->otap_del_sel[timing]; - + otap_del_sel = sdhci_am654->otap_del_sel[timing]; otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; @@ -314,10 +309,7 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, u32 mask, val; /* Setup DLL Output TAP delay */ - if (sdhci_am654->legacy_otapdly) - otap_del_sel = sdhci_am654->otap_del_sel[0]; - else - otap_del_sel = sdhci_am654->otap_del_sel[timing]; + otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; val = (0x1 << OTAPDLYENA_SHIFT) | @@ -577,32 +569,15 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, int i; int ret; - ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding, - &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); - if (ret) { - /* - * ti,otap-del-sel-legacy is mandatory, look for old binding - * if not found. - */ - ret = device_property_read_u32(dev, "ti,otap-del-sel", - &sdhci_am654->otap_del_sel[0]); - if (ret) { - dev_err(dev, "Couldn't find otap-del-sel\n"); - - return ret; - } - - dev_info(dev, "Using legacy binding ti,otap-del-sel\n"); - sdhci_am654->legacy_otapdly = true; - - return 0; - } - for (i = MMC_TIMING_LEGACY; i <= MMC_TIMING_MMC_HS400; i++) { ret = device_property_read_u32(dev, td[i].otap_binding, &sdhci_am654->otap_del_sel[i]); if (ret) { + if (i == MMC_TIMING_LEGACY) { + dev_err(dev, "Couldn't find mandatory ti,otap-del-sel-legacy\n"); + return ret; + } dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding); /* From 4d0c8d0aef6355660b6775d57ccd5d4ea2e15802 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 29 Nov 2023 11:25:35 +0200 Subject: [PATCH 3042/7721] mmc: core: Use mrq.sbc in close-ended ffu Field Firmware Update (ffu) may use close-ended or open ended sequence. Each such sequence is comprised of a write commands enclosed between 2 switch commands - to and from ffu mode. So for the close-ended case, it will be: cmd6->cmd23-cmd25-cmd6. Some host controllers however, get confused when multi-block rw is sent without sbc, and may generate auto-cmd12 which breaks the ffu sequence. I encountered this issue while testing fwupd (github.com/fwupd/fwupd) on HP Chromebook x2, a qualcomm based QC-7c, code name - strongbad. Instead of a quirk, or hooking the request function of the msm ops, it would be better to fix the ioctl handling and make it use mrq.sbc instead of issuing SET_BLOCK_COUNT separately. Signed-off-by: Avri Altman Acked-by: Adrian Hunter Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20231129092535.3278-1-avri.altman@wdc.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 46 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index f9a5cffa64b1..892e74e611a0 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -400,6 +400,10 @@ struct mmc_blk_ioc_data { struct mmc_ioc_cmd ic; unsigned char *buf; u64 buf_bytes; + unsigned int flags; +#define MMC_BLK_IOC_DROP BIT(0) /* drop this mrq */ +#define MMC_BLK_IOC_SBC BIT(1) /* use mrq.sbc */ + struct mmc_rpmb_data *rpmb; }; @@ -465,7 +469,7 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, } static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, - struct mmc_blk_ioc_data *idata) + struct mmc_blk_ioc_data **idatas, int i) { struct mmc_command cmd = {}, sbc = {}; struct mmc_data data = {}; @@ -475,10 +479,18 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, unsigned int busy_timeout_ms; int err; unsigned int target_part; + struct mmc_blk_ioc_data *idata = idatas[i]; + struct mmc_blk_ioc_data *prev_idata = NULL; if (!card || !md || !idata) return -EINVAL; + if (idata->flags & MMC_BLK_IOC_DROP) + return 0; + + if (idata->flags & MMC_BLK_IOC_SBC) + prev_idata = idatas[i - 1]; + /* * The RPMB accesses comes in from the character device, so we * need to target these explicitly. Else we just target the @@ -532,7 +544,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, return err; } - if (idata->rpmb) { + if (idata->rpmb || prev_idata) { sbc.opcode = MMC_SET_BLOCK_COUNT; /* * We don't do any blockcount validation because the max size @@ -540,6 +552,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, * 'Reliable Write' bit here. */ sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31)); + if (prev_idata) + sbc.arg = prev_idata->ic.arg; sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; mrq.sbc = &sbc; } @@ -557,6 +571,15 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, mmc_wait_for_req(card->host, &mrq); memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp)); + if (prev_idata) { + memcpy(&prev_idata->ic.response, sbc.resp, sizeof(sbc.resp)); + if (sbc.error) { + dev_err(mmc_dev(card->host), "%s: sbc error %d\n", + __func__, sbc.error); + return sbc.error; + } + } + if (cmd.error) { dev_err(mmc_dev(card->host), "%s: cmd error %d\n", __func__, cmd.error); @@ -1032,6 +1055,20 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) md->reset_done &= ~type; } +static void mmc_blk_check_sbc(struct mmc_queue_req *mq_rq) +{ + struct mmc_blk_ioc_data **idata = mq_rq->drv_op_data; + int i; + + for (i = 1; i < mq_rq->ioc_count; i++) { + if (idata[i - 1]->ic.opcode == MMC_SET_BLOCK_COUNT && + mmc_op_multi(idata[i]->ic.opcode)) { + idata[i - 1]->flags |= MMC_BLK_IOC_DROP; + idata[i]->flags |= MMC_BLK_IOC_SBC; + } + } +} + /* * The non-block commands come back from the block layer after it queued it and * processed it with all other requests and then they get issued in this @@ -1059,11 +1096,14 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) if (ret) break; } + + mmc_blk_check_sbc(mq_rq); + fallthrough; case MMC_DRV_OP_IOCTL_RPMB: idata = mq_rq->drv_op_data; for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) { - ret = __mmc_blk_ioctl_cmd(card, md, idata[i]); + ret = __mmc_blk_ioctl_cmd(card, md, idata, i); if (ret) break; } From 95f6b40082aaf37fd0553828982402af36f81685 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Thu, 7 Dec 2023 19:42:27 +0800 Subject: [PATCH 3043/7721] RDMA/hns: Rename the interrupts Now, different devices may have the same interrupt name, which makes it difficult for users to distinguish between these interrupts. Modify the naming style to be consistent with our network devices. Before: "hns-aeq-0" "hns-ceq-0" ... Now: "hns-0000:35:00.0-aeq-0" "hns-0000:35:00.0-ceq-0" ... Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231207114231.2872104-2-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 5d0a7a1394fc..4258b6daaded 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -6473,15 +6473,16 @@ static int __hns_roce_request_irq(struct hns_roce_dev *hr_dev, int irq_num, /* irq contains: abnormal + AEQ + CEQ */ for (j = 0; j < other_num; j++) snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN, - "hns-abn-%d", j); + "hns-%s-abn-%d", pci_name(hr_dev->pci_dev), j); for (j = other_num; j < (other_num + aeq_num); j++) snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN, - "hns-aeq-%d", j - other_num); + "hns-%s-aeq-%d", pci_name(hr_dev->pci_dev), j - other_num); for (j = (other_num + aeq_num); j < irq_num; j++) snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN, - "hns-ceq-%d", j - other_num - aeq_num); + "hns-%s-ceq-%d", pci_name(hr_dev->pci_dev), + j - other_num - aeq_num); for (j = 0; j < irq_num; j++) { if (j < other_num) From d3f4020a213e1cb125eed2363fca372a23f7de7a Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Thu, 7 Dec 2023 19:42:28 +0800 Subject: [PATCH 3044/7721] RDMA/hns: Response dmac to userspace While creating AH, dmac is already resolved in kernel. Response dmac to userspace so that userspace doesn't need to resolve dmac repeatedly. Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231207114231.2872104-3-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_ah.c | 7 +++++++ include/uapi/rdma/hns-abi.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c index fbf046982374..b4209b6aed8d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_ah.c +++ b/drivers/infiniband/hw/hns/hns_roce_ah.c @@ -57,6 +57,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, struct rdma_ah_attr *ah_attr = init_attr->ah_attr; const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr); struct hns_roce_dev *hr_dev = to_hr_dev(ibah->device); + struct hns_roce_ib_create_ah_resp resp = {}; struct hns_roce_ah *ah = to_hr_ah(ibah); int ret = 0; u32 max_sl; @@ -97,6 +98,12 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, ah->av.vlan_en = ah->av.vlan_id < VLAN_N_VID; } + if (udata) { + memcpy(resp.dmac, ah_attr->roce.dmac, ETH_ALEN); + ret = ib_copy_to_udata(udata, &resp, + min(udata->outlen, sizeof(resp))); + } + err_out: if (ret) atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_AH_CREATE_ERR_CNT]); diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h index ce0f37f83416..c996e151081e 100644 --- a/include/uapi/rdma/hns-abi.h +++ b/include/uapi/rdma/hns-abi.h @@ -125,4 +125,9 @@ struct hns_roce_ib_alloc_pd_resp { __u32 pdn; }; +struct hns_roce_ib_create_ah_resp { + __u8 dmac[6]; + __u8 reserved[2]; +}; + #endif /* HNS_ABI_USER_H */ From 7243396aaf12385ba514764b6401bcd15e1a52c7 Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Thu, 7 Dec 2023 19:42:29 +0800 Subject: [PATCH 3045/7721] RDMA/hns: Add a max length of gid table IB-core and rdma-core restrict the sgid_index specified by users, which is uint8_t/u8 data type, to only be within the range of 0-255, so it's meaningless to support excessively large gid_table_len. On the other hand, ib-core creates as many sysfs gid files as gid_table_len, most of which are not only useless because of the reason above, but also greatly increase the traversal time of the sysfs gid files for applications. This patch limits the maximum length of gid table to 256. Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231207114231.2872104-4-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 4258b6daaded..93a71db527d8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2060,6 +2060,7 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev) /* Apply all loaded caps before setting to hardware */ static void apply_func_caps(struct hns_roce_dev *hr_dev) { +#define MAX_GID_TBL_LEN 256 struct hns_roce_caps *caps = &hr_dev->caps; struct hns_roce_v2_priv *priv = hr_dev->priv; @@ -2095,8 +2096,14 @@ static void apply_func_caps(struct hns_roce_dev *hr_dev) caps->gmv_entry_sz = HNS_ROCE_V3_GMV_ENTRY_SZ; caps->gmv_hop_num = HNS_ROCE_HOP_NUM_0; - caps->gid_table_len[0] = caps->gmv_bt_num * - (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz); + + /* It's meaningless to support excessively large gid_table_len, + * as the type of sgid_index in kernel struct ib_global_route + * and userspace struct ibv_global_route are u8/uint8_t (0-255). + */ + caps->gid_table_len[0] = min_t(u32, MAX_GID_TBL_LEN, + caps->gmv_bt_num * + (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz)); caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE / caps->gmv_entry_sz); From f31683a5227b1a0febae8e2a85d7fdf9514c10f1 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Thu, 7 Dec 2023 19:42:30 +0800 Subject: [PATCH 3046/7721] RDMA/hns: Remove unnecessary checks for NULL in mtr_alloc_bufs() ib_umem_get() never return NULL. Fixes: 3c873161a0d7 ("RDMA/hns: Add support for addressing when hopnum is 0") Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231207114231.2872104-5-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index d68074b6ca17..91cd580480fe 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -686,7 +686,7 @@ static int mtr_alloc_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr, mtr->kmem = NULL; mtr->umem = ib_umem_get(ibdev, user_addr, total_size, buf_attr->user_access); - if (IS_ERR_OR_NULL(mtr->umem)) { + if (IS_ERR(mtr->umem)) { ibdev_err(ibdev, "failed to get umem, ret = %ld.\n", PTR_ERR(mtr->umem)); return -ENOMEM; From 288f535951aa81ed674f5e5477ab11b9d9351b8c Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Thu, 7 Dec 2023 19:42:31 +0800 Subject: [PATCH 3047/7721] RDMA/hns: Fix memory leak in free_mr_init() When a reserved QP fails to be created, the memory of the remaining created reserved QPs is leaked. Fixes: 70f92521584f ("RDMA/hns: Use the reserved loopback QPs to free MR before destroying MPT") Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20231207114231.2872104-6-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 93a71db527d8..b8dde04bd573 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2710,6 +2710,10 @@ static int free_mr_alloc_res(struct hns_roce_dev *hr_dev) return 0; create_failed_qp: + for (i--; i >= 0; i--) { + hns_roce_v2_destroy_qp(&free_mr->rsv_qp[i]->ibqp, NULL); + kfree(free_mr->rsv_qp[i]); + } hns_roce_destroy_cq(cq, NULL); kfree(cq); From 7677fdbc036b93a882f660ca2484a6807e72f0be Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:24 +0100 Subject: [PATCH 3048/7721] dt-bindings: i2c: exynos5: add specific compatible for Tesla FSD Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. Acked-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-2-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml index c1f5d2cb7709..df9c57bca2a8 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml @@ -29,6 +29,7 @@ properties: - items: - enum: - samsung,exynos5433-hsi2c + - tesla,fsd-hsi2c - const: samsung,exynos7-hsi2c - items: - enum: From edb32ec3cea79b518e6af841ecb01c839818f562 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:25 +0100 Subject: [PATCH 3049/7721] dt-bindings: pwm: samsung: add specific compatible for Tesla FSD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. Acked-by: Rob Herring Acked-by: Uwe Kleine-König Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-3-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/pwm/pwm-samsung.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml index 16de6434693b..17a2b927af33 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml @@ -33,6 +33,7 @@ properties: - samsung,exynos7-pwm - samsung,exynosautov9-pwm - samsung,exynosautov920-pwm + - tesla,fsd-pwm - const: samsung,exynos4210-pwm reg: From 921f4f1db7f5bf6798349db8a4382c032f144b98 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:26 +0100 Subject: [PATCH 3050/7721] dt-bindings: serial: samsung: add specific compatible for Tesla FSD Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. Acked-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-4-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index e32c1b462836..4b6fc82c2edf 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -29,6 +29,7 @@ properties: - items: - enum: - samsung,exynos7-uart + - tesla,fsd-uart - const: samsung,exynos4210-uart - items: - enum: From 54772f1d61cd99ea1ed0febd4187bf24ef63bccd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:27 +0100 Subject: [PATCH 3051/7721] dt-bindings: samsung: exynos-pmu: add specific compatible for Tesla FSD Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. Acked-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-5-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index 28e2cb50d85e..65f77442ff23 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -53,6 +53,7 @@ properties: - samsung,exynos7885-pmu - samsung,exynosautov9-pmu - samsung,exynosautov920-pmu + - tesla,fsd-pmu - const: samsung,exynos7-pmu - const: syscon - items: From bf1e24c5330af06b2f7f1a166a1011d8d48e8651 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:28 +0100 Subject: [PATCH 3052/7721] dt-bindings: watchdog: samsung: add specific compatible for Tesla FSD Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. Acked-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-6-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/watchdog/samsung-wdt.yaml | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml index 8fb6656ba0c2..ea2d206b05ab 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml @@ -16,14 +16,19 @@ description: |+ properties: compatible: - enum: - - samsung,s3c2410-wdt # for S3C2410 - - samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4 - - samsung,exynos5250-wdt # for Exynos5250 - - samsung,exynos5420-wdt # for Exynos5420 - - samsung,exynos7-wdt # for Exynos7 - - samsung,exynos850-wdt # for Exynos850 - - samsung,exynosautov9-wdt # for Exynosautov9 + oneOf: + - enum: + - samsung,s3c2410-wdt # for S3C2410 + - samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4 + - samsung,exynos5250-wdt # for Exynos5250 + - samsung,exynos5420-wdt # for Exynos5420 + - samsung,exynos7-wdt # for Exynos7 + - samsung,exynos850-wdt # for Exynos850 + - samsung,exynosautov9-wdt # for Exynosautov9 + - items: + - enum: + - tesla,fsd-wdt + - const: samsung,exynos7-wdt reg: maxItems: 1 From 5f257922c5948c58669346d5cda371632108f266 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Dec 2023 10:22:29 +0100 Subject: [PATCH 3053/7721] arm64: dts: fsd: add specific compatibles for Tesla FSD Tesla FSD is a derivative of Samsung Exynos SoC, thus just like the others it reuses several devices from older designs. Historically we kept the old (block's) compatible only. This works fine and there is no bug here, however guidelines expressed in Documentation/devicetree/bindings/writing-bindings.rst state that: 1. Compatibles should be specific. 2. We should add new compatibles in case of bugs or features. Add Tesla FSD compatible specific to be used with an existing fallback. This will also help reviews of new code using existing DTS as template. No functional impact on Linux drivers behavior. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231205092229.19135-7-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/tesla/fsd.dtsi | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi index bb50a9f7db4a..9db162afc834 100644 --- a/arch/arm64/boot/dts/tesla/fsd.dtsi +++ b/arch/arm64/boot/dts/tesla/fsd.dtsi @@ -581,7 +581,7 @@ pdma1: dma-controller@14290000 { }; serial_0: serial@14180000 { - compatible = "samsung,exynos4210-uart"; + compatible = "tesla,fsd-uart", "samsung,exynos4210-uart"; reg = <0x0 0x14180000 0x0 0x100>; interrupts = ; dmas = <&pdma1 1>, <&pdma1 0>; @@ -593,7 +593,7 @@ serial_0: serial@14180000 { }; serial_1: serial@14190000 { - compatible = "samsung,exynos4210-uart"; + compatible = "tesla,fsd-uart", "samsung,exynos4210-uart"; reg = <0x0 0x14190000 0x0 0x100>; interrupts = ; dmas = <&pdma1 3>, <&pdma1 2>; @@ -605,12 +605,12 @@ serial_1: serial@14190000 { }; pmu_system_controller: system-controller@11400000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "tesla,fsd-pmu", "samsung,exynos7-pmu", "syscon"; reg = <0x0 0x11400000 0x0 0x5000>; }; watchdog_0: watchdog@100a0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100a0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -619,7 +619,7 @@ watchdog_0: watchdog@100a0000 { }; watchdog_1: watchdog@100b0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100b0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -628,7 +628,7 @@ watchdog_1: watchdog@100b0000 { }; watchdog_2: watchdog@100c0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100c0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -637,7 +637,7 @@ watchdog_2: watchdog@100c0000 { }; pwm_0: pwm@14100000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "tesla,fsd-pwm", "samsung,exynos4210-pwm"; reg = <0x0 0x14100000 0x0 0x100>; samsung,pwm-outputs = <0>, <1>, <2>, <3>; #pwm-cells = <3>; @@ -647,7 +647,7 @@ pwm_0: pwm@14100000 { }; pwm_1: pwm@14110000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "tesla,fsd-pwm", "samsung,exynos4210-pwm"; reg = <0x0 0x14110000 0x0 0x100>; samsung,pwm-outputs = <0>, <1>, <2>, <3>; #pwm-cells = <3>; @@ -657,7 +657,7 @@ pwm_1: pwm@14110000 { }; hsi2c_0: i2c@14200000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14200000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -670,7 +670,7 @@ hsi2c_0: i2c@14200000 { }; hsi2c_1: i2c@14210000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14210000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -683,7 +683,7 @@ hsi2c_1: i2c@14210000 { }; hsi2c_2: i2c@14220000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14220000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -696,7 +696,7 @@ hsi2c_2: i2c@14220000 { }; hsi2c_3: i2c@14230000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14230000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -709,7 +709,7 @@ hsi2c_3: i2c@14230000 { }; hsi2c_4: i2c@14240000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14240000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -722,7 +722,7 @@ hsi2c_4: i2c@14240000 { }; hsi2c_5: i2c@14250000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14250000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -735,7 +735,7 @@ hsi2c_5: i2c@14250000 { }; hsi2c_6: i2c@14260000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14260000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -748,7 +748,7 @@ hsi2c_6: i2c@14260000 { }; hsi2c_7: i2c@14270000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14270000 0x0 0x1000>; interrupts = ; #address-cells = <1>; From 9463571b29bf03a0dc1114f0cb17042b179066f9 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Fri, 1 Dec 2023 18:26:51 +0800 Subject: [PATCH 3054/7721] mmc: mtk-sd: Increase the verbosity of msdc_track_cmd_data This log message is necessary for debugging, so enable it by default to debug issues that are hard to reproduce locally. Signed-off-by: Pin-yen Lin Reviewed-by: Wenbin Mei Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231201102747.3854573-1-treapking@chromium.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 97f7c3d4be6e..6ae5e0a9fca9 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1149,9 +1149,11 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host) static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd) { - if (host->error) - dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", - __func__, cmd->opcode, cmd->arg, host->error); + if (host->error && + ((!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning) || + cmd->error == -ETIMEDOUT)) + dev_warn(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", + __func__, cmd->opcode, cmd->arg, host->error); } static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) From 0e63dd27f456f30c9501cf044141758db2d34fb3 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 8 Nov 2023 14:19:39 +0200 Subject: [PATCH 3055/7721] HID: intel-ish-hid: ipc: Rework EHL OOB wakeup Since PCI core and ACPI core already handles PCI PME wake and GPE wake when the device has wakeup capability, use device_init_wakeup() to let them do the wakeup setting work. Also add a shutdown callback which uses pci_prepare_to_sleep() to let PCI and ACPI set OOB wakeup for S5. Cc: Jian Hui Lee Signed-off-by: Kai-Heng Feng Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 67 ++++++------------------- 1 file changed, 15 insertions(+), 52 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 710fda5f19e1..65e7eeb2fa64 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -119,50 +119,6 @@ static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID; } -static int enable_gpe(struct device *dev) -{ -#ifdef CONFIG_ACPI - acpi_status acpi_sts; - struct acpi_device *adev; - struct acpi_device_wakeup *wakeup; - - adev = ACPI_COMPANION(dev); - if (!adev) { - dev_err(dev, "get acpi handle failed\n"); - return -ENODEV; - } - wakeup = &adev->wakeup; - - /* - * Call acpi_disable_gpe(), so that reference count - * gpe_event_info->runtime_count doesn't overflow. - * When gpe_event_info->runtime_count = 0, the call - * to acpi_disable_gpe() simply return. - */ - acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); - - acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); - if (ACPI_FAILURE(acpi_sts)) { - dev_err(dev, "enable ose_gpe failed\n"); - return -EIO; - } - - return 0; -#else - return -ENODEV; -#endif -} - -static void enable_pme_wake(struct pci_dev *pdev) -{ - if ((pci_pme_capable(pdev, PCI_D0) || - pci_pme_capable(pdev, PCI_D3hot) || - pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) { - pci_pme_active(pdev, true); - dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n"); - } -} - /** * ish_probe() - PCI driver probe callback * @pdev: pci device @@ -233,7 +189,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Enable PME for EHL */ if (pdev->device == EHL_Ax_DEVICE_ID) - enable_pme_wake(pdev); + device_init_wakeup(dev, true); ret = ish_init(ishtp); if (ret) @@ -256,6 +212,19 @@ static void ish_remove(struct pci_dev *pdev) ish_device_disable(ishtp_dev); } + +/** + * ish_shutdown() - PCI driver shutdown callback + * @pdev: pci device + * + * This function sets up wakeup for S5 + */ +static void ish_shutdown(struct pci_dev *pdev) +{ + if (pdev->device == EHL_Ax_DEVICE_ID) + pci_prepare_to_sleep(pdev); +} + static struct device __maybe_unused *ish_resume_device; /* 50ms to get resume response */ @@ -378,13 +347,6 @@ static int __maybe_unused ish_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); - /* add this to finish power flow for EHL */ - if (dev->pdev->device == EHL_Ax_DEVICE_ID) { - pci_set_power_state(pdev, PCI_D0); - enable_pme_wake(pdev); - dev_dbg(dev->devc, "set power state to D0 for ehl\n"); - } - ish_resume_device = device; dev->resume_flag = 1; @@ -400,6 +362,7 @@ static struct pci_driver ish_driver = { .id_table = ish_pci_tbl, .probe = ish_probe, .remove = ish_remove, + .shutdown = ish_shutdown, .driver.pm = &ish_pm_ops, }; From da2c1b861065b452590d75a1e2f5ee9b396fef92 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 7 Dec 2023 13:22:39 +0100 Subject: [PATCH 3056/7721] selftests/hid: fix failing tablet button tests An overlook from commit 74452d6329be ("selftests/hid: tablets: add variants of states with buttons"), where I don't use the Enum... Fixes: 74452d6329be ("selftests/hid: tablets: add variants of states with buttons") Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20231207-b4-wip-selftests-v1-1-c4e13fe04a70@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/tests/test_tablet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index dc8b0fe9e7f3..903f19f7cbe9 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -115,7 +115,7 @@ class PenState(Enum): # we take only the highest button in account for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: if bool(evdev.value[b]): - button = b + button = BtnPressed(b) # the kernel tends to insert an EV_SYN once removing the tool, so # the button will be released after @@ -155,7 +155,7 @@ class PenState(Enum): if button_found: raise ValueError(f"duplicated BTN_STYLUS* in {events}") button_found = True - button = ev.code if ev.value else None + button = BtnPressed(ev.code) if ev.value else None # the kernel tends to insert an EV_SYN once removing the tool, so # the button will be released after From d685aea5e0a89b66679e5266320ab2ba4378c754 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Dec 2023 15:42:07 +0300 Subject: [PATCH 3057/7721] ASoC: audio-graph-card2: fix off by one in graph_parse_node_multi_nm() The > comparison should be >= to avoid writing one element beyond the end of the dai_link->ch_maps[] array. The dai_link->ch_maps[] array is allocated in graph_parse_node_multi() and it has "nm_max" elements. Fixes: e2de6808df4a ("ASoC: audio-graph-card2: add CPU:Codec = N:M support") Signed-off-by: Dan Carpenter Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/1032216f-902f-48f9-aa49-9d5ece8e87f2@moroto.mountain Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index d9e10308a508..78d9679decda 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -557,7 +557,7 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, struct device_node *mcodec_port; int codec_idx; - if (*nm_idx > nm_max) + if (*nm_idx >= nm_max) break; mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n); From 1f30f51053715af81a25d902511079aca3fdb213 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 5 Dec 2023 21:58:55 -0800 Subject: [PATCH 3058/7721] mmc: sdhci-omap: don't misuse kernel-doc marker Use "/*" instead of "/**" for common C comments to prevent warnings from scripts/kernel-doc. sdhci-omap.c:3: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst sdhci-omap.c:3: warning: missing initial short description on line: * SDHCI Controller driver for TI's OMAP SoCs Signed-off-by: Randy Dunlap Reported-by: kernel test robot Link: https://lore.kernel.org/oe-kbuild-all/202311201117.lFxgJTK6-lkp@intel.com/ Link: https://lore.kernel.org/r/20231206055855.21092-1-rdunlap@infradead.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 1e0bc7bace1b..e78faef67d7a 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * SDHCI Controller driver for TI's OMAP SoCs * * Copyright (C) 2017 Texas Instruments From ec1aaf792d9aafbe1d1ffd414c423ddc2a3d3103 Mon Sep 17 00:00:00 2001 From: Axe Yang Date: Thu, 7 Dec 2023 14:35:34 +0800 Subject: [PATCH 3059/7721] dt-bindings: mmc: mtk-sd: add tuning steps related property Add 'mediatek,tuning-steps' setting. This property will give MSDC a chance to extend tuning steps up to 64. With more tuning steps, MSDC may achieve a more optimal calibration result, thus avoiding potential CRC issues. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Axe Yang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231207063535.29546-2-axe.yang@mediatek.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/mtk-sd.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index 3fffa467e4e1..c532ec92d2d9 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -145,6 +145,15 @@ properties: minimum: 0 maximum: 7 + mediatek,tuning-step: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Some SoCs need extend tuning step for better delay value to avoid CRC issue. + If not present, default tuning step is 32. For eMMC and SD, this can yield + satisfactory calibration results in most cases. + enum: [32, 64] + default: 32 + resets: maxItems: 1 From d3ddafd34bc4e353dc9fc2d193abc4c4463dc588 Mon Sep 17 00:00:00 2001 From: Axe Yang Date: Thu, 7 Dec 2023 14:35:35 +0800 Subject: [PATCH 3060/7721] mmc: mtk-sd: Extend number of tuning steps Previously, during the MSDC calibration process, a full clock cycle actually not be covered, which in some cases didn't yield the best results and could cause CRC errors. This problem is particularly evident when MSDC is used as an SDIO host. In fact, MSDC support tuning up to a maximum of 64 steps, but by default, the step number is 32. By increase the tuning step, we are more likely to cover more parts of a clock cycle, and get better calibration result. To illustrate, when tuning 32 steps, if the obtained window has a hole near the middle, like this: 0xffc07ff (hex), then the selected delay will be the 6 (counting from right to left). (32 <- 1) 1111 1111 1100 0000 0000 0111 11(1)1 1111 However, if we tune 64 steps, the window obtained may look like this: 0xfffffffffffc07ff. The final selected delay will be 44, which is safer as it is further away from the hole: (64 <- 1) 1111 ... (1)111 1111 1111 1111 1111 1100 0000 0000 0111 1111 1111 In this case, delay 6 selected through 32 steps tuning is obviously not optimal, and this delay is closer to the hole, using it would easily cause CRC problems. As per mesaurements taken on mediatek SoC platform, the tuning phase will take: eMMC - 32 steps: ~3ms - 64 steps: ~6ms SDIO - 32 steps: ~4ms - 64 steos: ~7ms Tuning more steps won't prolong boot times by any meaningful amount of time, so for SD/SDIO the default tuning steps will be adjust to 64. But for eMMC, it is still preferred to use 32 steps tuning as otherwise there would be performance lose when accessing the RPMB partition(requiring retuning each time). You can configure property "mediatek,tuning-step" in MSDC dts node to adjust the step number. Signed-off-by: Axe Yang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231207063535.29546-3-axe.yang@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 158 ++++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 48 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 6ae5e0a9fca9..1634b1f5d201 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -252,12 +252,16 @@ #define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */ #define MSDC_PAD_TUNE_DATRRDLY GENMASK(12, 8) /* RW */ +#define MSDC_PAD_TUNE_DATRRDLY2 GENMASK(12, 8) /* RW */ #define MSDC_PAD_TUNE_CMDRDLY GENMASK(20, 16) /* RW */ +#define MSDC_PAD_TUNE_CMDRDLY2 GENMASK(20, 16) /* RW */ #define MSDC_PAD_TUNE_CMDRRDLY GENMASK(26, 22) /* RW */ #define MSDC_PAD_TUNE_CLKTDLY GENMASK(31, 27) /* RW */ #define MSDC_PAD_TUNE_RXDLYSEL BIT(15) /* RW */ #define MSDC_PAD_TUNE_RD_SEL BIT(13) /* RW */ #define MSDC_PAD_TUNE_CMD_SEL BIT(21) /* RW */ +#define MSDC_PAD_TUNE_RD2_SEL BIT(13) /* RW */ +#define MSDC_PAD_TUNE_CMD2_SEL BIT(21) /* RW */ #define PAD_DS_TUNE_DLY_SEL BIT(0) /* RW */ #define PAD_DS_TUNE_DLY1 GENMASK(6, 2) /* RW */ @@ -325,7 +329,9 @@ #define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */ -#define PAD_DELAY_MAX 32 /* PAD delay cells */ +#define TUNING_REG2_FIXED_OFFEST 4 +#define PAD_DELAY_HALF 32 /* PAD delay cells */ +#define PAD_DELAY_FULL 64 /*--------------------------------------------------------------------------*/ /* Descriptor Structure */ /*--------------------------------------------------------------------------*/ @@ -461,6 +467,7 @@ struct msdc_host { u32 hs400_ds_dly3; u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ + u32 tuning_step; bool hs400_cmd_resp_sel_rising; /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ @@ -1617,7 +1624,7 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) } if (cmd_err || dat_err) { - dev_err(host->dev, "cmd_err = %d, dat_err =%d, intsts = 0x%x", + dev_err(host->dev, "cmd_err = %d, dat_err = %d, intsts = 0x%x", cmd_err, dat_err, intsts); } @@ -1782,10 +1789,20 @@ static void msdc_init_hw(struct msdc_host *host) DATA_K_VALUE_SEL); sdr_set_bits(host->top_base + EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL); + if (host->tuning_step > PAD_DELAY_HALF) { + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2_SEL); + sdr_set_bits(host->top_base + EMMC_TOP_CMD, + PAD_CMD_RD_RXDLY2_SEL); + } } else { sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL); + if (host->tuning_step > PAD_DELAY_HALF) + sdr_set_bits(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_RD2_SEL | + MSDC_PAD_TUNE_CMD2_SEL); } } else { /* choose clock tune */ @@ -1927,24 +1944,24 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) msdc_set_mclk(host, ios->timing, ios->clock); } -static u32 test_delay_bit(u32 delay, u32 bit) +static u64 test_delay_bit(u64 delay, u32 bit) { - bit %= PAD_DELAY_MAX; - return delay & BIT(bit); + bit %= PAD_DELAY_FULL; + return delay & BIT_ULL(bit); } -static int get_delay_len(u32 delay, u32 start_bit) +static int get_delay_len(u64 delay, u32 start_bit) { int i; - for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) { + for (i = 0; i < (PAD_DELAY_FULL - start_bit); i++) { if (test_delay_bit(delay, start_bit + i) == 0) return i; } - return PAD_DELAY_MAX - start_bit; + return PAD_DELAY_FULL - start_bit; } -static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) +static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u64 delay) { int start = 0, len = 0; int start_final = 0, len_final = 0; @@ -1952,28 +1969,28 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) struct msdc_delay_phase delay_phase = { 0, }; if (delay == 0) { - dev_err(host->dev, "phase error: [map:%x]\n", delay); + dev_err(host->dev, "phase error: [map:%016llx]\n", delay); delay_phase.final_phase = final_phase; return delay_phase; } - while (start < PAD_DELAY_MAX) { + while (start < PAD_DELAY_FULL) { len = get_delay_len(delay, start); if (len_final < len) { start_final = start; len_final = len; } start += len ? len : 1; - if (len >= 12 && start_final < 4) + if (!upper_32_bits(delay) && len >= 12 && start_final < 4) break; } /* The rule is that to find the smallest delay cell */ if (start_final == 0) - final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX; + final_phase = (start_final + len_final / 3) % PAD_DELAY_FULL; else - final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX; - dev_dbg(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", + final_phase = (start_final + len_final / 2) % PAD_DELAY_FULL; + dev_dbg(host->dev, "phase: [map:%016llx] [maxlen:%d] [final:%d]\n", delay, len_final, final_phase); delay_phase.maxlen = len_final; @@ -1986,30 +2003,64 @@ static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value) { u32 tune_reg = host->dev_comp->pad_tune_reg; - if (host->top_base) - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, - value); - else - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, - value); + if (host->top_base) { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, value); + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, 0); + } else { + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, + value - PAD_DELAY_HALF); + } + } else { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, value); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_CMDRDLY2, 0); + } else { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_CMDRDLY2, value - PAD_DELAY_HALF); + } + } } static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) { u32 tune_reg = host->dev_comp->pad_tune_reg; - if (host->top_base) - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY, value); - else - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, - value); + if (host->top_base) { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY, value); + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2, 0); + } else { + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY, PAD_DELAY_HALF - 1); + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2, value - PAD_DELAY_HALF); + } + } else { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, value); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_DATRRDLY2, 0); + } else { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_DATRRDLY2, value - PAD_DELAY_HALF); + } + } } static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; struct msdc_delay_phase internal_delay_phase; u8 final_delay, final_maxlen; @@ -2025,7 +2076,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) host->hs200_cmd_int_delay); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, @@ -2035,9 +2086,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } else { - rise_delay &= ~BIT(i); + rise_delay &= ~BIT_ULL(i); break; } } @@ -2049,7 +2100,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) goto skip_fall; sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, @@ -2059,9 +2110,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } else { - fall_delay &= ~BIT(i); + fall_delay &= ~BIT_ULL(i); break; } } @@ -2084,12 +2135,12 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay) goto skip_internal; - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY, i); mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) - internal_delay |= BIT(i); + internal_delay |= BIT_ULL(i); } dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay); internal_delay_phase = get_best_delay(host, internal_delay); @@ -2123,7 +2174,8 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); else sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + + for (i = 0; i < PAD_DELAY_HALF; i++) { sdr_set_field(host->base + PAD_CMD_TUNE, PAD_CMD_TUNE_RX_DLY3, i); /* @@ -2153,7 +2205,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int i, ret; @@ -2162,11 +2214,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) host->latch_ck); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2176,11 +2228,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2208,7 +2260,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int i, ret; @@ -2219,12 +2271,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2235,12 +2287,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2348,7 +2400,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card } host->hs400_tuning = true; - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < PAD_DELAY_HALF; i++) { if (host->top_base) sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE, PAD_DS_DLY1, i); @@ -2582,6 +2634,8 @@ static const struct cqhci_host_ops msdc_cmdq_ops = { static void msdc_of_property_parse(struct platform_device *pdev, struct msdc_host *host) { + struct mmc_host *mmc = mmc_from_priv(host); + of_property_read_u32(pdev->dev.of_node, "mediatek,latch-ck", &host->latch_ck); @@ -2603,6 +2657,14 @@ static void msdc_of_property_parse(struct platform_device *pdev, else host->hs400_cmd_resp_sel_rising = false; + if (of_property_read_u32(pdev->dev.of_node, "mediatek,tuning-step", + &host->tuning_step)) { + if (mmc->caps2 & MMC_CAP2_NO_MMC) + host->tuning_step = PAD_DELAY_FULL; + else + host->tuning_step = PAD_DELAY_HALF; + } + if (of_property_read_bool(pdev->dev.of_node, "supports-cqe")) host->cqhci = true; From 73380e2573c34a45e01786750a4a2efafc2248bd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 6 Dec 2023 13:37:06 +0100 Subject: [PATCH 3061/7721] soc: qcom: stats: fix 64-bit division MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unguarded 64-bit division is not allowed on 32-bit kernels because this is very slow. The result of trying anyway is a link failure: arm-linux-gnueabi-ld: drivers/soc/qcom/qcom_stats.o: in function `qcom_ddr_stats_show': qcom_stats.c:(.text+0x334): undefined reference to `__aeabi_uldivmod' As this function is only used for debugging and not performance critical, rewrite it to use div_u64() instead. ARCH_TIMER_FREQ is a multiple of MSEC_PER_SEC anyway, so there is no loss in precisison. Fixes: e84e61bdb97c ("soc: qcom: stats: Add DDR sleep stats") Signed-off-by: Arnd Bergmann Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20231206123717.524009-1-arnd@kernel.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 4763d62a8cb0..5ec8a754b22b 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -221,7 +221,7 @@ static int qcom_ddr_stats_show(struct seq_file *s, void *unused) for (i = 0; i < ddr.entry_count; i++) { /* Convert the period to ms */ - entry[i].dur = mult_frac(MSEC_PER_SEC, entry[i].dur, ARCH_TIMER_FREQ); + entry[i].dur = div_u64(entry[i].dur, ARCH_TIMER_FREQ / MSEC_PER_SEC); } for (i = 0; i < ddr.entry_count; i++) From 70b139a7af7106b59ca5ca77673a9c56982b3089 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 5 Dec 2023 20:38:40 -0800 Subject: [PATCH 3062/7721] soc: qcom: stats: Express AOSS QMP module dependency In the case that the Qualcomm Sleep stats driver is builtin and the AOSS QMP driver is built as a module, neither the implementation nor the stub functions are available during linking, resulting in the following errors: qcom_stats.c:(.text+0x33c): undefined reference to `qmp_send' qcom_stats.c:(.text+0x8a0): undefined reference to `qmp_get' Resolve this by expressing the dependency between the two modules. Fixes: e84e61bdb97c ("soc: qcom: stats: Add DDR sleep stats") Reported-by: kernel test robot Closes: https://lore.kernel.org/linux-arm-msm/202312061258.nAVYPFq2-lkp@intel.com/ Signed-off-by: Bjorn Andersson Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231205-qcom_stats-aoss_qmp-dependency-v1-1-8dabe1b5c32a@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 2686fda9fe27..aa5956246f60 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -221,6 +221,7 @@ config QCOM_STATS tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver" depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST depends on QCOM_SMEM + depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n help Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read the shared memory exported by the remote processor related to From 10690b8a49bceafb1badf0ad91842a359e796d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Thu, 7 Dec 2023 10:34:51 +0200 Subject: [PATCH 3063/7721] drm/i915/display: Add intel_fb_bo_framebuffer_fini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xe needs intel_fb_bo_framebuffer_fini for taking care of unpinning the fb and taking reference. In i915 this can be empty. Also move intel_frontbuffer_get to be done after intel_fb_bo_framebuffer_init to have reasonable sequences: intel_fb_bo_framebuffer_init intel_frontbuffer_get ... intel_frontbuffer_put intel_fb_bo_framebuffer_fini v2: Empty function instead of define Signed-off-by: Jouni Högander Reviewed-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20231207083451.2184562-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 32 +++++++++++++--------- drivers/gpu/drm/i915/display/intel_fb_bo.c | 5 ++++ drivers/gpu/drm/i915/display/intel_fb_bo.h | 2 ++ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 32a7ee1c5b34..4f9d2e57a770 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1889,6 +1889,8 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) intel_frontbuffer_put(intel_fb->frontbuffer); + intel_fb_bo_framebuffer_fini(intel_fb_obj(fb)); + kfree(intel_fb); } @@ -1989,13 +1991,15 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, int ret = -EINVAL; int i; - intel_fb->frontbuffer = intel_frontbuffer_get(obj); - if (!intel_fb->frontbuffer) - return -ENOMEM; - ret = intel_fb_bo_framebuffer_init(intel_fb, obj, mode_cmd); if (ret) + return ret; + + intel_fb->frontbuffer = intel_frontbuffer_get(obj); + if (!intel_fb->frontbuffer) { + ret = -ENOMEM; goto err; + } ret = -EINVAL; if (!drm_any_plane_has_format(&dev_priv->drm, @@ -2004,7 +2008,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, drm_dbg_kms(&dev_priv->drm, "unsupported pixel format %p4cc / modifier 0x%llx\n", &mode_cmd->pixel_format, mode_cmd->modifier[0]); - goto err; + goto err_frontbuffer_put; } max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format, @@ -2015,7 +2019,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ? "tiled" : "linear", mode_cmd->pitches[0], max_stride); - goto err; + goto err_frontbuffer_put; } /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ @@ -2023,7 +2027,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, drm_dbg_kms(&dev_priv->drm, "plane 0 offset (0x%08x) must be 0\n", mode_cmd->offsets[0]); - goto err; + goto err_frontbuffer_put; } drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd); @@ -2034,7 +2038,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (mode_cmd->handles[i] != mode_cmd->handles[0]) { drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n", i); - goto err; + goto err_frontbuffer_put; } stride_alignment = intel_fb_stride_alignment(fb, i); @@ -2042,7 +2046,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, drm_dbg_kms(&dev_priv->drm, "plane %d pitch (%d) must be at least %u byte aligned\n", i, fb->pitches[i], stride_alignment); - goto err; + goto err_frontbuffer_put; } if (intel_fb_is_gen12_ccs_aux_plane(fb, i)) { @@ -2053,7 +2057,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, "ccs aux plane %d pitch (%d) must be %d\n", i, fb->pitches[i], ccs_aux_stride); - goto err; + goto err_frontbuffer_put; } } @@ -2062,7 +2066,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, ret = intel_fill_fb_info(dev_priv, intel_fb); if (ret) - goto err; + goto err_frontbuffer_put; if (intel_fb_uses_dpt(fb)) { struct i915_address_space *vm; @@ -2071,7 +2075,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (IS_ERR(vm)) { drm_dbg_kms(&dev_priv->drm, "failed to create DPT\n"); ret = PTR_ERR(vm); - goto err; + goto err_frontbuffer_put; } intel_fb->dpt_vm = vm; @@ -2088,8 +2092,10 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, err_free_dpt: if (intel_fb_uses_dpt(fb)) intel_dpt_destroy(intel_fb->dpt_vm); -err: +err_frontbuffer_put: intel_frontbuffer_put(intel_fb->frontbuffer); +err: + intel_fb_bo_framebuffer_fini(obj); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.c b/drivers/gpu/drm/i915/display/intel_fb_bo.c index ce86eff7b226..4be09541e509 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_bo.c +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.c @@ -11,6 +11,11 @@ #include "intel_fb.h" #include "intel_fb_bo.h" +void intel_fb_bo_framebuffer_fini(struct drm_i915_gem_object *obj) +{ + /* Nothing to do for i915 */ +} + int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd) diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.h b/drivers/gpu/drm/i915/display/intel_fb_bo.h index dd06ceec8601..232bf898b013 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_bo.h +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.h @@ -12,6 +12,8 @@ struct drm_i915_gem_object; struct drm_i915_private; struct intel_framebuffer; +void intel_fb_bo_framebuffer_fini(struct drm_i915_gem_object *obj); + int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd); From 8c1f28ff1356dd1f0ede9b378c9dadbfa7539187 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:18:27 +0200 Subject: [PATCH 3064/7721] dt-bindings: soc: qcom,aoss-qmp: document the SM8560 Always-On Subsystem side channel Document the Always-On Subsystem side channel on the SM8650 Platform. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231025-topic-sm8650-upstream-bindings-aoss-qmp-v1-1-8940621d704c@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index d1c7c2be865f..109f52a0b524 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -38,6 +38,7 @@ properties: - qcom,sm8350-aoss-qmp - qcom,sm8450-aoss-qmp - qcom,sm8550-aoss-qmp + - qcom,sm8650-aoss-qmp - const: qcom,aoss-qmp reg: From 98e8bc43c225d77966fde6e0138e3ee307d3c208 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:27:57 +0200 Subject: [PATCH 3065/7721] dt-bindings: soc: qcom: pmic-glink: document SM8650 compatible Document the PMIC GLINK firmware interface on the SM8650 Platform by using the SM8550 bindings as fallback. Signed-off-by: Neil Armstrong Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231025-topic-sm8650-upstream-bindings-pmic-glink-v1-1-0c2829a62565@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/soc/qcom/qcom,pmic-glink.yaml | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 422921cf1f82..61df97ffe1e4 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -20,14 +20,20 @@ description: properties: compatible: - items: - - enum: - - qcom,sc8180x-pmic-glink - - qcom,sc8280xp-pmic-glink - - qcom,sm8350-pmic-glink - - qcom,sm8450-pmic-glink - - qcom,sm8550-pmic-glink - - const: qcom,pmic-glink + oneOf: + - items: + - enum: + - qcom,sc8180x-pmic-glink + - qcom,sc8280xp-pmic-glink + - qcom,sm8350-pmic-glink + - qcom,sm8450-pmic-glink + - qcom,sm8550-pmic-glink + - const: qcom,pmic-glink + - items: + - enum: + - qcom,sm8650-pmic-glink + - const: qcom,sm8550-pmic-glink + - const: qcom,pmic-glink '#address-cells': const: 1 From 6da02af3f910bbcdd2914050cfcab1a9d7980494 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 25 Oct 2023 09:29:17 +0200 Subject: [PATCH 3066/7721] dt-bindings: firmware: qcom,scm: document SM8650 SCM Firmware Interface Document the SCM Firmware Interface on the SM8650 Platform. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231025-topic-sm8650-upstream-bindings-scm-v1-1-f687b5aa3c9e@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/firmware/qcom,scm.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 0613a37a851a..3212c8b30ed9 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -63,6 +63,7 @@ properties: - qcom,scm-sm8350 - qcom,scm-sm8450 - qcom,scm-sm8550 + - qcom,scm-sm8650 - qcom,scm-qcs404 - const: qcom,scm @@ -189,6 +190,7 @@ allOf: - qcom,scm-sc8280xp - qcom,scm-sm8450 - qcom,scm-sm8550 + - qcom,scm-sm8650 then: properties: interconnects: false @@ -202,6 +204,7 @@ allOf: enum: - qcom,scm-sm8450 - qcom,scm-sm8550 + - qcom,scm-sm8650 then: properties: interrupts: false From 1d103d6af241dbfc7e11eb9a46dff65db257a37f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 25 Oct 2023 14:49:29 +0300 Subject: [PATCH 3067/7721] usb: typec: ucsi: fix UCSI on buggy Qualcomm devices On sevral Qualcomm platforms (SC8180X, SM8350, SC8280XP) a call to UCSI_GET_PDOS for non-PD partners will cause a firmware crash with no easy way to recover from it. Since we have no easy way to determine whether the partner really has PD support, shortcut UCSI_GET_PDOS on such platforms. This allows us to enable UCSI support on such devices. Signed-off-by: Dmitry Baryshkov Acked-by: Heikki Krogerus Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231025115620.905538-2-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- drivers/usb/typec/ucsi/ucsi.c | 3 +++ drivers/usb/typec/ucsi/ucsi.h | 3 +++ drivers/usb/typec/ucsi/ucsi_glink.c | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 61b64558f96c..5392ec698959 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -578,6 +578,9 @@ static int ucsi_read_pdos(struct ucsi_connector *con, u64 command; int ret; + if (ucsi->quirks & UCSI_NO_PARTNER_PDOS) + return 0; + command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner); command |= UCSI_GET_PDOS_PDO_OFFSET(offset); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 474315a72c77..6478016d5cb8 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -317,6 +317,9 @@ struct ucsi { #define EVENT_PENDING 0 #define COMMAND_PENDING 1 #define ACK_PENDING 2 + + unsigned long quirks; +#define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ }; #define UCSI_MAX_SVID 5 diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index db6e248f8208..a94e2df6fd45 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -296,11 +297,19 @@ static void pmic_glink_ucsi_destroy(void *data) mutex_unlock(&ucsi->lock); } +static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { + { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, + { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, + { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, + {} +}; + static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { struct pmic_glink_ucsi *ucsi; struct device *dev = &adev->dev; + const struct of_device_id *match; struct fwnode_handle *fwnode; int ret; @@ -327,6 +336,10 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, if (ret) return ret; + match = of_match_device(pmic_glink_ucsi_of_quirks, dev->parent); + if (match) + ucsi->ucsi->quirks = (unsigned long)match->data; + ucsi_set_drvdata(ucsi->ucsi, ucsi); device_for_each_child_node(dev, fwnode) { From 4db09e7b967b905ba3036a4d96e81c06b896b1bf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 25 Oct 2023 14:49:30 +0300 Subject: [PATCH 3068/7721] soc: qcom: pmic_glink: enable UCSI by default Now as the issue with the UCSI_GET_PDOS is worked around, enable UCSI support for all PMIC_GLINK platforms except Qualcomm SC8180X. The mentioned SoC has slightly different UCSI implementation, which I would like be tested properly before enabling it. Signed-off-by: Dmitry Baryshkov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231025115620.905538-3-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pmic_glink.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index 914057331afd..71d8901a9389 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -18,9 +18,6 @@ enum { PMIC_GLINK_CLIENT_UCSI, }; -#define PMIC_GLINK_CLIENT_DEFAULT (BIT(PMIC_GLINK_CLIENT_BATT) | \ - BIT(PMIC_GLINK_CLIENT_ALTMODE)) - struct pmic_glink { struct device *dev; struct pdr_handle *pdr; @@ -263,10 +260,10 @@ static int pmic_glink_probe(struct platform_device *pdev) mutex_init(&pg->state_lock); match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); - if (match_data) - pg->client_mask = *match_data; - else - pg->client_mask = PMIC_GLINK_CLIENT_DEFAULT; + if (!match_data) + return -EINVAL; + + pg->client_mask = *match_data; if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); @@ -336,14 +333,16 @@ static void pmic_glink_remove(struct platform_device *pdev) mutex_unlock(&__pmic_glink_lock); } +static const unsigned long pmic_glink_sc8180x_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE); + static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | BIT(PMIC_GLINK_CLIENT_ALTMODE) | BIT(PMIC_GLINK_CLIENT_UCSI); static const struct of_device_id pmic_glink_of_match[] = { - { .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, - { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, - { .compatible = "qcom,pmic-glink" }, + { .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, + { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, {} }; MODULE_DEVICE_TABLE(of, pmic_glink_of_match); From e0cee8dc6757f9f18718eec553be9fffa503e103 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Wed, 25 Oct 2023 12:58:00 +0100 Subject: [PATCH 3069/7721] arm64: dts: qcom: qrb2210-rb1: use USB host mode The default for the QCM2290 platform that this board is based on is OTG mode, however the role detection logic is not hooked up for this board and the dwc3 driver is configured to not allow role switching from userspace. Force this board to host mode as this is the preferred usecase until we get role switching hooked up. Fixes: e18771961336 ("arm64: dts: qcom: Add initial QTI RB1 device tree") Signed-off-by: Caleb Connolly Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231025-b4-rb1-usb-host-v1-1-522616c575ef@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index bd7bcf803654..aa53b6af6d9c 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -523,6 +523,10 @@ &usb_qmpphy { status = "okay"; }; +&usb_dwc3 { + dr_mode = "host"; +}; + &usb_hsphy { vdd-supply = <&pm2250_l12>; vdda-pll-supply = <&pm2250_l13>; From 2928212b6ef24d6a4f2af849157ac18546030b97 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Wed, 25 Oct 2023 19:01:25 +0530 Subject: [PATCH 3070/7721] arm64: dts: qcom: ipq9574: enable GPIO based LED Add support for wlan-2g LED on GPIO64. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231025-ipq9574-led-v2-1-59b2725697ad@quicinc.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/ipq9574-rdp-common.dtsi | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi index 49c9b6478357..91e104b0f865 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi @@ -10,6 +10,7 @@ #include #include +#include #include "ipq9574.dtsi" / { @@ -51,6 +52,20 @@ button-wps { debounce-interval = <60>; }; }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&gpio_leds_default>; + pinctrl-names = "default"; + + led-0 { + color = ; + function = LED_FUNCTION_WLAN; + gpios = <&tlmm 64 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tx"; + default-state = "off"; + }; + }; }; &blsp1_spi0 { @@ -117,6 +132,13 @@ gpio_keys_default: gpio-keys-default-state { drive-strength = <8>; bias-pull-up; }; + + gpio_leds_default: gpio-leds-default-state { + pins = "gpio64"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; }; &usb_0_dwc3 { From 63a021f52f69092f17d24707cd8e81f914f8d1e6 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Wed, 25 Oct 2023 19:20:05 +0530 Subject: [PATCH 3071/7721] arm64: dts: qcom: ipq5332: add missing properties to the GPIO LED node Add the color and function property to the GPIO LED node, which are missed out in the initial submission. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231025-ipq5332-gpio-led-v1-1-0f0f52617648@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi index 4870cdb764d0..b37ae7749083 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi @@ -9,6 +9,7 @@ #include #include +#include #include "ipq5332.dtsi" / { @@ -39,6 +40,8 @@ leds { pinctrl-names = "default"; led-0 { + color = ; + function = LED_FUNCTION_WLAN; gpios = <&tlmm 36 GPIO_ACTIVE_HIGH>; linux,default-trigger = "phy0tx"; default-state = "off"; From a427dd16e61f3d145bc24f0ed09692fc25931250 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Wed, 25 Oct 2023 22:12:12 +0530 Subject: [PATCH 3072/7721] arm64: dts: qcom: ipq5018: add few more reserved memory regions Like all other IPQ SoCs, bootloader will collect the system RAM contents upon crash for the post morterm analysis. If we don't reserve the memory region used by bootloader, obviously linux will consume it and upon next boot on crash, bootloader will be loaded in the same region, which will lead to loose some of the data, sometimes we may miss out critical information. So lets reserve the region used by the bootloader. Similarly SBL copies some data into the reserved region and it will be used in the crash scenario. So reserve 1MB for SBL as well. While at it, enable the SMEM support along with TCSR mutex. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231025-ipq5018-misc-v1-1-7d14fde97fe7@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index ae31bd72f0b7..32b178b639f0 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -104,6 +104,24 @@ reserved-memory { #size-cells = <2>; ranges; + bootloader@4a800000 { + reg = <0x0 0x4a800000 0x0 0x200000>; + no-map; + }; + + sbl@4aa00000 { + reg = <0x0 0x4aa00000 0x0 0x100000>; + no-map; + }; + + smem@4ab00000 { + compatible = "qcom,smem"; + reg = <0x0 0x4ab00000 0x0 0x100000>; + no-map; + + hwlocks = <&tcsr_mutex 3>; + }; + tz_region: tz@4ac00000 { reg = <0x0 0x4ac00000 0x0 0x200000>; no-map; @@ -164,6 +182,12 @@ gcc: clock-controller@1800000 { #power-domain-cells = <1>; }; + tcsr_mutex: hwlock@1905000 { + compatible = "qcom,tcsr-mutex"; + reg = <0x01905000 0x20000>; + #hwlock-cells = <1>; + }; + sdhc_1: mmc@7804000 { compatible = "qcom,ipq5018-sdhci", "qcom,sdhci-msm-v5"; reg = <0x7804000 0x1000>; From d59653233e8779e3fe082eb5635b9785f2095af6 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 25 Oct 2023 22:36:39 +0530 Subject: [PATCH 3073/7721] arm64: dts: qcom: sm8250: Add TCSR halt register space Enable download mode for sm8250 which can help collect ramdump for this SoC. Signed-off-by: Mukesh Ojha Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/1698253601-11957-2-git-send-email-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 9a64e8ab2046..7ab6c9953d74 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -671,6 +671,7 @@ cpu7_opp20: opp-2841600000 { firmware { scm: scm { compatible = "qcom,scm-sm8250", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x13000>; #reset-cells = <1>; }; }; @@ -2564,6 +2565,11 @@ tcsr_mutex: hwlock@1f40000 { #hwlock-cells = <1>; }; + tcsr: syscon@1fc0000 { + compatible = "qcom,sm8250-tcsr", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + wsamacro: codec@3240000 { compatible = "qcom,sm8250-lpass-wsa-macro"; reg = <0 0x03240000 0 0x1000>; From 1accc6031d925c6045c4776d5f3646996b0b242a Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 25 Oct 2023 22:36:40 +0530 Subject: [PATCH 3074/7721] arm64: dts: qcom: sm8350: Add TCSR halt register space Enable download mode for sm8350 which can help collect ramdump for this SoC. Signed-off-by: Mukesh Ojha Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/1698253601-11957-3-git-send-email-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 4978f691e3c5..94dcc4b64105 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -289,6 +289,7 @@ CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 { firmware { scm: scm { compatible = "qcom,scm-sm8350", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x13000>; #reset-cells = <1>; }; }; @@ -1818,6 +1819,11 @@ tcsr_mutex: hwlock@1f40000 { #hwlock-cells = <1>; }; + tcsr: syscon@1fc0000 { + compatible = "qcom,sm8350-tcsr", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + lpass_tlmm: pinctrl@33c0000 { compatible = "qcom,sm8350-lpass-lpi-pinctrl"; reg = <0 0x033c0000 0 0x20000>, From 44b1f64cad5703c87918cc9ffbf9b79bb959418d Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 25 Oct 2023 22:36:41 +0530 Subject: [PATCH 3075/7721] arm64: dts: qcom: sm8550: Enable download mode register write Enable download mode setting for sm8550 which can help collect ramdump for this SoC. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/1698253601-11957-4-git-send-email-quic_mojha@quicinc.com [bjorn: Updated tcsr offset, per Mukesh correction] Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 17c4f0a7638a..7310a2a19f01 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -324,6 +324,7 @@ CLUSTER_SLEEP_1: cluster-sleep-1 { firmware { scm: scm { compatible = "qcom,scm-sm8550", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x19000>; interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>; }; }; From 216382b1555de2fe11684ffd99d598ac77a92ed8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 10:55:19 +0100 Subject: [PATCH 3076/7721] dt-bindings: arm: qcom,ids: Add SoC ID for SM8650 Add the ID for the Qualcomm SM8650 SoC. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Reviewed-by: Mukesh Ojha Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-socinfo-v2-1-4751e7391dc9@linaro.org Signed-off-by: Bjorn Andersson --- include/dt-bindings/arm/qcom,ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index f7248348a459..51e0f6059410 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -255,6 +255,7 @@ #define QCOM_ID_SA8775P 534 #define QCOM_ID_QRU1000 539 #define QCOM_ID_QDU1000 545 +#define QCOM_ID_SM8650 557 #define QCOM_ID_SM4450 568 #define QCOM_ID_QDU1010 587 #define QCOM_ID_QRU1032 588 From f61319e57d89e6e3d1ad16cb916074fdb7289806 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 10:55:20 +0100 Subject: [PATCH 3077/7721] soc: qcom: socinfo: Add SM8650 SoC ID table entry Add SoC Info support for the SM8650 platform. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Reviewed-by: Mukesh Ojha Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-socinfo-v2-2-4751e7391dc9@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 51e05bec5bfc..8e8cd4ea58d1 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -417,6 +417,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SA8775P) }, { qcom_board_id(QRU1000) }, { qcom_board_id(QDU1000) }, + { qcom_board_id(SM8650) }, { qcom_board_id(SM4450) }, { qcom_board_id(QDU1010) }, { qcom_board_id(QRU1032) }, From 3e743b0fcb90551106c13837548079b91d661384 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 12 Apr 2023 14:46:33 +0800 Subject: [PATCH 3078/7721] drm/mediatek: Use devm_platform_ioremap_resource() Remove variable 'res' and convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yang Li Reviewed-by: Matthias Brugger Reviewed-by: Alexandre Mergnat Link: https://patchwork.kernel.org/project/dri-devel/patch/20230412064635.41315-1-yang.lee@linux.alibaba.com/ Link: https://patchwork.kernel.org/project/dri-devel/patch/20230412064635.41315-2-yang.lee@linux.alibaba.com/ Link: https://patchwork.kernel.org/project/dri-devel/patch/20230412064635.41315-3-yang.lee@linux.alibaba.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_cec.c | 4 +--- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 4 +--- drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c index f47f417d8ba6..8519e9bade36 100644 --- a/drivers/gpu/drm/mediatek/mtk_cec.c +++ b/drivers/gpu/drm/mediatek/mtk_cec.c @@ -185,7 +185,6 @@ static int mtk_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_cec *cec; - struct resource *res; int ret; cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); @@ -195,8 +194,7 @@ static int mtk_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cec); spin_lock_init(&cec->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cec->regs = devm_ioremap_resource(dev, res); + cec->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cec->regs)) { ret = PTR_ERR(cec->regs); dev_err(dev, "Failed to ioremap cec: %d\n", ret); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index 2209159d8855..40fe403086c3 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -168,7 +168,6 @@ static int mtk_disp_aal_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_aal *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -181,8 +180,7 @@ static int mtk_disp_aal_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) { dev_err(dev, "failed to ioremap aal\n"); return PTR_ERR(priv->regs); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c index 4234ff7485e8..465cddce0d32 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c @@ -153,7 +153,6 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_ccorr *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -166,8 +165,7 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) { dev_err(dev, "failed to ioremap ccorr\n"); return PTR_ERR(priv->regs); From cec1f2ffcc065568fea9718921698576c6d1c62d Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 26 Oct 2023 12:18:37 +0200 Subject: [PATCH 3079/7721] dt-bindings: clock: qcom,gcc-ipq6018: split to separate schema The Qualcomm IPQ6018 GCC clock controller has clock inputs, thus existing gcc-other.yaml was not describing it fully so move it to a separate schema. Fully document the allowed and required XO and sleep clock inputs, as well as update the provided example. Signed-off-by: Robert Marko Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231026101931.695497-1-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,gcc-ipq6018.yaml | 57 +++++++++++++++++++ .../bindings/clock/qcom,gcc-other.yaml | 3 - 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml new file mode 100644 index 000000000000..af5d883cfdc8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq6018.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on IPQ6018 + +maintainers: + - Stephen Boyd + - Taniya Das + - Robert Marko + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on IPQ6018. + + See also:: + include/dt-bindings/clock/qcom,gcc-ipq6018.h + include/dt-bindings/reset/qcom,gcc-ipq6018.h + +allOf: + - $ref: qcom,gcc.yaml# + +properties: + compatible: + const: qcom,gcc-ipq6018 + + clocks: + items: + - description: board XO clock + - description: sleep clock + + clock-names: + items: + - const: xo + - const: sleep_clk + +required: + - compatible + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + clock-controller@1800000 { + compatible = "qcom,gcc-ipq6018"; + reg = <0x01800000 0x80000>; + clocks = <&xo>, <&sleep_clk>; + clock-names = "xo", "sleep_clk"; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml index 559fc21435c8..7d05f0f63cef 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml @@ -15,8 +15,6 @@ description: | domains. See also:: - include/dt-bindings/clock/qcom,gcc-ipq6018.h - include/dt-bindings/reset/qcom,gcc-ipq6018.h include/dt-bindings/clock/qcom,gcc-msm8953.h include/dt-bindings/clock/qcom,gcc-mdm9607.h @@ -26,7 +24,6 @@ allOf: properties: compatible: enum: - - qcom,gcc-ipq6018 - qcom,gcc-mdm9607 required: From a85607e3cfc5032daf64efc5f6b5387f2271b073 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 30 Nov 2023 23:21:51 -0500 Subject: [PATCH 3080/7721] drm/doc/rfc: Mark long running workload as complete. No DRM scheduler changes required, drivers just return NULL in run_job vfunc. The rough consensus is that no helper or extra scaffolding is needed around long-running jobs and no further changes to drm-scheduler. At least for now. Other drivers that currently do long-running workloads have no plat to use drm-scheduler. Besides, the current consensus is that this solution of simply returning NULL to the run_job function should work without extra code duplication or complication. On top of that, this item was already a non-blocking one for upstreaming Xe, so let's move that to the 'Completed' section and revisit the long-running solution as a community after Xe is integrated in DRM. Signed-off-by: Matthew Brost Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231201042158.80009-2-rodrigo.vivi@intel.com Acked-by: Daniel Vetter --- Documentation/gpu/rfc/xe.rst | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index ceb21219d52e..2a5132327617 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -132,21 +132,6 @@ the time comes. The DRM GPUVM helpers do not yet include the userptr parts, but discussions about implementing them are ongoing. -Long running compute: minimal data structure/scaffolding --------------------------------------------------------- -The generic scheduler code needs to include the handling of endless compute -contexts, with the minimal scaffolding for preempt-ctx fences (probably on the -drm_sched_entity) and making sure drm_scheduler can cope with the lack of job -completion fence. - -The goal is to achieve a consensus ahead of Xe initial pull-request, ideally with -this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any -drm driver, including Xe, could re-use and add their own individual needs on top -in a next stage. However, this should not block the initial merge. - -This is a non-blocker item since the driver without the support for the long -running compute enabled is not a showstopper. - Display integration with i915 ----------------------------- In order to share the display code with the i915 driver so that there is maximum @@ -184,6 +169,18 @@ Xe – uAPI high level overview Xe – Pre-Merge Goals - Completed ================================ +Long running compute: minimal data structure/scaffolding +-------------------------------------------------------- +The generic scheduler code needs to include the handling of endless compute +contexts, with the minimal scaffolding for preempt-ctx fences (probably on the +drm_sched_entity) and making sure drm_scheduler can cope with the lack of job +completion fence. + +The goal is to achieve a consensus ahead of Xe initial pull-request, ideally with +this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any +drm driver, including Xe, could re-use and add their own individual needs on top +in a next stage. However, this should not block the initial merge. + Dev_coredump ------------ From 0e2e6c49c1c072dff841d9dfab3b4966abb2edf1 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Nov 2023 23:21:52 -0500 Subject: [PATCH 3081/7721] drm/doc/rfc: Mark drm_scheduler as completed Current drm-xe-next doesn't have any drm/scheduler patch that is not already accepted in drm-misc-next. This completed this goal with the consensus of how the drm/scheduler fits to the fw scheduling and the relationship between drm_gpu_scheduler and drm_sched_entity. Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231201042158.80009-3-rodrigo.vivi@intel.com Acked-by: Daniel Vetter --- Documentation/gpu/rfc/xe.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index 2a5132327617..9f3afab6c06a 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -70,24 +70,6 @@ When the time comes for Xe, the protection will be lifted on Xe and kept in i915 Xe – Pre-Merge Goals - Work-in-Progress ======================================= -Drm_scheduler -------------- -Xe primarily uses Firmware based scheduling (GuC FW). However, it will use -drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to -resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is -not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and -drm_sched_entity. - -Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but -some consensus needs to be reached between Xe and other community drivers that -could also benefit from this work, for coupling FW based/assisted submission such -as the ARM’s new Mali GPU driver, and others. - -As a key measurable result, the patch series introducing Xe itself shall not -depend on any other patch touching drm_scheduler itself that was not yet merged -through drm-misc. This, by itself, already includes the reach of an agreement for -uniform 1 to 1 relationship implementation / usage across drivers. - ASYNC VM_BIND ------------- Although having a common DRM level IOCTL for VM_BIND is not a requirement to get @@ -169,6 +151,24 @@ Xe – uAPI high level overview Xe – Pre-Merge Goals - Completed ================================ +Drm_scheduler +------------- +Xe primarily uses Firmware based scheduling (GuC FW). However, it will use +drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to +resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is +not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and +drm_sched_entity. + +Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but +some consensus needs to be reached between Xe and other community drivers that +could also benefit from this work, for coupling FW based/assisted submission such +as the ARM’s new Mali GPU driver, and others. + +As a key measurable result, the patch series introducing Xe itself shall not +depend on any other patch touching drm_scheduler itself that was not yet merged +through drm-misc. This, by itself, already includes the reach of an agreement for +uniform 1 to 1 relationship implementation / usage across drivers. + Long running compute: minimal data structure/scaffolding -------------------------------------------------------- The generic scheduler code needs to include the handling of endless compute From 4ab1721694a07651afef97dfb150f06c267cf2c4 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 26 Oct 2023 11:53:42 +0100 Subject: [PATCH 3082/7721] dt-bindings: clock: Use gcc.yaml for common clock properties Various of the camcc bindings are repeated serially. We can use qcom,gcc.yaml to encapsulate the generic repeated patterns. Signed-off-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231026105345.3376-2-bryan.odonoghue@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,camcc-sm8250.yaml | 18 ++++-------------- .../bindings/clock/qcom,sc7180-camcc.yaml | 18 ++++-------------- .../bindings/clock/qcom,sc7280-camcc.yaml | 18 ++++-------------- .../bindings/clock/qcom,sdm845-camcc.yaml | 18 ++++-------------- .../bindings/clock/qcom,sm8450-camcc.yaml | 18 ++++-------------- 5 files changed, 20 insertions(+), 70 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml index 426335a2841c..3fd3dc1069fb 100644 --- a/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sm8250.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sm8250-camcc @@ -33,15 +36,6 @@ properties: - const: bi_tcxo_ao - const: sleep_clk - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - power-domains: items: - description: MMCX power domain @@ -56,14 +50,10 @@ properties: required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml index 2dfc2a4f1918..c7fe6400ea13 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sc7180.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sc7180-camcc @@ -31,28 +34,15 @@ properties: - const: iface - const: xo - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml index 01feef1cab0a..dcef8de3a905 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sc7280.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sc7280-camcc @@ -31,28 +34,15 @@ properties: - const: bi_tcxo_ao - const: sleep_clk - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml index 91d1f7918037..810b852ae371 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sm845.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sdm845-camcc @@ -27,28 +30,15 @@ properties: items: - const: bi_tcxo - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index dc3c18e4ead7..6915498deacf 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -17,6 +17,9 @@ description: | include/dt-bindings/clock/qcom,sm8450-camcc.h include/dt-bindings/clock/qcom,sm8550-camcc.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: enum: @@ -40,29 +43,16 @@ properties: description: A phandle to an OPP node describing required MMCX performance point. - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - power-domains - required-opps - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | From 16805e994bff2db40362b9007f3fcd476571a15e Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Nov 2023 23:21:53 -0500 Subject: [PATCH 3083/7721] drm/doc/rfc: Move Xe 'ASYNC VM_BIND' to the 'completed' section As already indicated in this block, the consensus was already reached out and documented as: The ASYNC VM_BIND document However this was item was not moved to the completed section. Let's move and clean up the WIP block. Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231201042158.80009-4-rodrigo.vivi@intel.com Acked-by: Daniel Vetter --- Documentation/gpu/rfc/xe.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index 9f3afab6c06a..87dd620aea59 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -70,18 +70,6 @@ When the time comes for Xe, the protection will be lifted on Xe and kept in i915 Xe – Pre-Merge Goals - Work-in-Progress ======================================= -ASYNC VM_BIND -------------- -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to have a consensus with other drivers and Mesa. -It needs to be clear how to handle async VM_BIND and interactions with userspace -memory fences. Ideally with helper support so people don't get it wrong in all -possible ways. - -As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of -various flavors, error handling and sample API suggestions are documented in -:doc:`The ASYNC VM_BIND document `. - Userptr integration and vm_bind ------------------------------- Different drivers implement different ways of dealing with execution of userptr. @@ -151,6 +139,18 @@ Xe – uAPI high level overview Xe – Pre-Merge Goals - Completed ================================ +ASYNC VM_BIND +------------- +Although having a common DRM level IOCTL for VM_BIND is not a requirement to get +Xe merged, it is mandatory to have a consensus with other drivers and Mesa. +It needs to be clear how to handle async VM_BIND and interactions with userspace +memory fences. Ideally with helper support so people don't get it wrong in all +possible ways. + +As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of +various flavors, error handling and sample API suggestions are documented in +:doc:`The ASYNC VM_BIND document `. + Drm_scheduler ------------- Xe primarily uses Firmware based scheduling (GuC FW). However, it will use From 206cd759fbd2fce07cadb6c73a302ecfc95ebdff Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 26 Oct 2023 11:53:43 +0100 Subject: [PATCH 3084/7721] dt-bindings: clock: Add SC8280XP CAMCC Add device tree bindings for the camera clock controller on Qualcomm SC8280XP platform. Signed-off-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231026105345.3376-3-bryan.odonoghue@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8450-camcc.yaml | 2 + .../dt-bindings/clock/qcom,sc8280xp-camcc.h | 179 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,sc8280xp-camcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index 6915498deacf..48986460f994 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -16,6 +16,7 @@ description: | See also:: include/dt-bindings/clock/qcom,sm8450-camcc.h include/dt-bindings/clock/qcom,sm8550-camcc.h + include/dt-bindings/clock/qcom,sc8280xp-camcc.h allOf: - $ref: qcom,gcc.yaml# @@ -23,6 +24,7 @@ allOf: properties: compatible: enum: + - qcom,sc8280xp-camcc - qcom,sm8450-camcc - qcom,sm8550-camcc diff --git a/include/dt-bindings/clock/qcom,sc8280xp-camcc.h b/include/dt-bindings/clock/qcom,sc8280xp-camcc.h new file mode 100644 index 000000000000..ea5ec73c8c6a --- /dev/null +++ b/include/dt-bindings/clock/qcom,sc8280xp-camcc.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + */ + +#ifndef __DT_BINDINGS_CLK_QCOM_CAMCC_SC8280XP_H__ +#define __DT_BINDINGS_CLK_QCOM_CAMCC_SC8280XP_H__ + +/* CAMCC clocks */ +#define CAMCC_PLL0 0 +#define CAMCC_PLL0_OUT_EVEN 1 +#define CAMCC_PLL0_OUT_ODD 2 +#define CAMCC_PLL1 3 +#define CAMCC_PLL1_OUT_EVEN 4 +#define CAMCC_PLL2 5 +#define CAMCC_PLL3 6 +#define CAMCC_PLL3_OUT_EVEN 7 +#define CAMCC_PLL4 8 +#define CAMCC_PLL4_OUT_EVEN 9 +#define CAMCC_PLL5 10 +#define CAMCC_PLL5_OUT_EVEN 11 +#define CAMCC_PLL6 12 +#define CAMCC_PLL6_OUT_EVEN 13 +#define CAMCC_PLL7 14 +#define CAMCC_PLL7_OUT_EVEN 15 +#define CAMCC_PLL7_OUT_ODD 16 +#define CAMCC_BPS_AHB_CLK 17 +#define CAMCC_BPS_AREG_CLK 18 +#define CAMCC_BPS_AXI_CLK 19 +#define CAMCC_BPS_CLK 20 +#define CAMCC_BPS_CLK_SRC 21 +#define CAMCC_CAMNOC_AXI_CLK 22 +#define CAMCC_CAMNOC_AXI_CLK_SRC 23 +#define CAMCC_CAMNOC_DCD_XO_CLK 24 +#define CAMCC_CCI_0_CLK 25 +#define CAMCC_CCI_0_CLK_SRC 26 +#define CAMCC_CCI_1_CLK 27 +#define CAMCC_CCI_1_CLK_SRC 28 +#define CAMCC_CCI_2_CLK 29 +#define CAMCC_CCI_2_CLK_SRC 30 +#define CAMCC_CCI_3_CLK 31 +#define CAMCC_CCI_3_CLK_SRC 32 +#define CAMCC_CORE_AHB_CLK 33 +#define CAMCC_CPAS_AHB_CLK 34 +#define CAMCC_CPHY_RX_CLK_SRC 35 +#define CAMCC_CSI0PHYTIMER_CLK 36 +#define CAMCC_CSI0PHYTIMER_CLK_SRC 37 +#define CAMCC_CSI1PHYTIMER_CLK 38 +#define CAMCC_CSI1PHYTIMER_CLK_SRC 39 +#define CAMCC_CSI2PHYTIMER_CLK 40 +#define CAMCC_CSI2PHYTIMER_CLK_SRC 41 +#define CAMCC_CSI3PHYTIMER_CLK 42 +#define CAMCC_CSI3PHYTIMER_CLK_SRC 43 +#define CAMCC_CSIPHY0_CLK 44 +#define CAMCC_CSIPHY1_CLK 45 +#define CAMCC_CSIPHY2_CLK 46 +#define CAMCC_CSIPHY3_CLK 47 +#define CAMCC_FAST_AHB_CLK_SRC 48 +#define CAMCC_GDSC_CLK 49 +#define CAMCC_ICP_AHB_CLK 50 +#define CAMCC_ICP_CLK 51 +#define CAMCC_ICP_CLK_SRC 52 +#define CAMCC_IFE_0_AXI_CLK 53 +#define CAMCC_IFE_0_CLK 54 +#define CAMCC_IFE_0_CLK_SRC 55 +#define CAMCC_IFE_0_CPHY_RX_CLK 56 +#define CAMCC_IFE_0_CSID_CLK 57 +#define CAMCC_IFE_0_CSID_CLK_SRC 58 +#define CAMCC_IFE_0_DSP_CLK 59 +#define CAMCC_IFE_1_AXI_CLK 60 +#define CAMCC_IFE_1_CLK 61 +#define CAMCC_IFE_1_CLK_SRC 62 +#define CAMCC_IFE_1_CPHY_RX_CLK 63 +#define CAMCC_IFE_1_CSID_CLK 64 +#define CAMCC_IFE_1_CSID_CLK_SRC 65 +#define CAMCC_IFE_1_DSP_CLK 66 +#define CAMCC_IFE_2_AXI_CLK 67 +#define CAMCC_IFE_2_CLK 68 +#define CAMCC_IFE_2_CLK_SRC 69 +#define CAMCC_IFE_2_CPHY_RX_CLK 70 +#define CAMCC_IFE_2_CSID_CLK 71 +#define CAMCC_IFE_2_CSID_CLK_SRC 72 +#define CAMCC_IFE_2_DSP_CLK 73 +#define CAMCC_IFE_3_AXI_CLK 74 +#define CAMCC_IFE_3_CLK 75 +#define CAMCC_IFE_3_CLK_SRC 76 +#define CAMCC_IFE_3_CPHY_RX_CLK 77 +#define CAMCC_IFE_3_CSID_CLK 78 +#define CAMCC_IFE_3_CSID_CLK_SRC 79 +#define CAMCC_IFE_3_DSP_CLK 80 +#define CAMCC_IFE_LITE_0_CLK 81 +#define CAMCC_IFE_LITE_0_CLK_SRC 82 +#define CAMCC_IFE_LITE_0_CPHY_RX_CLK 83 +#define CAMCC_IFE_LITE_0_CSID_CLK 84 +#define CAMCC_IFE_LITE_0_CSID_CLK_SRC 85 +#define CAMCC_IFE_LITE_1_CLK 86 +#define CAMCC_IFE_LITE_1_CLK_SRC 87 +#define CAMCC_IFE_LITE_1_CPHY_RX_CLK 88 +#define CAMCC_IFE_LITE_1_CSID_CLK 89 +#define CAMCC_IFE_LITE_1_CSID_CLK_SRC 90 +#define CAMCC_IFE_LITE_2_CLK 91 +#define CAMCC_IFE_LITE_2_CLK_SRC 92 +#define CAMCC_IFE_LITE_2_CPHY_RX_CLK 93 +#define CAMCC_IFE_LITE_2_CSID_CLK 94 +#define CAMCC_IFE_LITE_2_CSID_CLK_SRC 95 +#define CAMCC_IFE_LITE_3_CLK 96 +#define CAMCC_IFE_LITE_3_CLK_SRC 97 +#define CAMCC_IFE_LITE_3_CPHY_RX_CLK 98 +#define CAMCC_IFE_LITE_3_CSID_CLK 99 +#define CAMCC_IFE_LITE_3_CSID_CLK_SRC 100 +#define CAMCC_IPE_0_AHB_CLK 101 +#define CAMCC_IPE_0_AREG_CLK 102 +#define CAMCC_IPE_0_AXI_CLK 103 +#define CAMCC_IPE_0_CLK 104 +#define CAMCC_IPE_0_CLK_SRC 105 +#define CAMCC_IPE_1_AHB_CLK 106 +#define CAMCC_IPE_1_AREG_CLK 107 +#define CAMCC_IPE_1_AXI_CLK 108 +#define CAMCC_IPE_1_CLK 109 +#define CAMCC_JPEG_CLK 110 +#define CAMCC_JPEG_CLK_SRC 111 +#define CAMCC_LRME_CLK 112 +#define CAMCC_LRME_CLK_SRC 113 +#define CAMCC_MCLK0_CLK 114 +#define CAMCC_MCLK0_CLK_SRC 115 +#define CAMCC_MCLK1_CLK 116 +#define CAMCC_MCLK1_CLK_SRC 117 +#define CAMCC_MCLK2_CLK 118 +#define CAMCC_MCLK2_CLK_SRC 119 +#define CAMCC_MCLK3_CLK 120 +#define CAMCC_MCLK3_CLK_SRC 121 +#define CAMCC_MCLK4_CLK 122 +#define CAMCC_MCLK4_CLK_SRC 123 +#define CAMCC_MCLK5_CLK 124 +#define CAMCC_MCLK5_CLK_SRC 125 +#define CAMCC_MCLK6_CLK 126 +#define CAMCC_MCLK6_CLK_SRC 127 +#define CAMCC_MCLK7_CLK 128 +#define CAMCC_MCLK7_CLK_SRC 129 +#define CAMCC_SLEEP_CLK 130 +#define CAMCC_SLEEP_CLK_SRC 131 +#define CAMCC_SLOW_AHB_CLK_SRC 132 +#define CAMCC_XO_CLK_SRC 133 + +/* CAMCC resets */ +#define CAMCC_BPS_BCR 0 +#define CAMCC_CAMNOC_BCR 1 +#define CAMCC_CCI_BCR 2 +#define CAMCC_CPAS_BCR 3 +#define CAMCC_CSI0PHY_BCR 4 +#define CAMCC_CSI1PHY_BCR 5 +#define CAMCC_CSI2PHY_BCR 6 +#define CAMCC_CSI3PHY_BCR 7 +#define CAMCC_ICP_BCR 8 +#define CAMCC_IFE_0_BCR 9 +#define CAMCC_IFE_1_BCR 10 +#define CAMCC_IFE_2_BCR 11 +#define CAMCC_IFE_3_BCR 12 +#define CAMCC_IFE_LITE_0_BCR 13 +#define CAMCC_IFE_LITE_1_BCR 14 +#define CAMCC_IFE_LITE_2_BCR 15 +#define CAMCC_IFE_LITE_3_BCR 16 +#define CAMCC_IPE_0_BCR 17 +#define CAMCC_IPE_1_BCR 18 +#define CAMCC_JPEG_BCR 19 +#define CAMCC_LRME_BCR 20 + +/* CAMCC GDSCRs */ +#define BPS_GDSC 0 +#define IFE_0_GDSC 1 +#define IFE_1_GDSC 2 +#define IFE_2_GDSC 3 +#define IFE_3_GDSC 4 +#define IPE_0_GDSC 5 +#define IPE_1_GDSC 6 +#define TITAN_TOP_GDSC 7 + +#endif /* __DT_BINDINGS_CLK_QCOM_CAMCC_SC8280XP_H__ */ From 34e64dd192071c3159c118331f87c66dffa0f9c9 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Nov 2023 23:21:54 -0500 Subject: [PATCH 3085/7721] drm/doc/rfc: Move userptr integration and vm_bind to the 'completed' section The must-have part of the documentation was already added to the existing /gpu/drm-vm-bind-async. The other extra discussion around GPUVM helpers are currently active in the community. None of those discussion should block Xe since documentation, specially around locking was completed in a community consensus. Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231201042158.80009-5-rodrigo.vivi@intel.com Acked-by: Daniel Vetter --- Documentation/gpu/rfc/xe.rst | 64 ++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index 87dd620aea59..cfff8a59a876 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -70,38 +70,6 @@ When the time comes for Xe, the protection will be lifted on Xe and kept in i915 Xe – Pre-Merge Goals - Work-in-Progress ======================================= -Userptr integration and vm_bind -------------------------------- -Different drivers implement different ways of dealing with execution of userptr. -With multiple drivers currently introducing support to VM_BIND, the goal is to -aim for a DRM consensus on what’s the best way to have that support. To some -extent this is already getting addressed itself with the GPUVA where likely the -userptr will be a GPUVA with a NULL GEM call VM bind directly on the userptr. -However, there are more aspects around the rules for that and the usage of -mmu_notifiers, locking and other aspects. - -This task here has the goal of introducing a documentation of the basic rules. - -The documentation *needs* to first live in this document (API session below) and -then moved to another more specific document or at Xe level or at DRM level. - -Documentation should include: - - * The userptr part of the VM_BIND api. - - * Locking, including the page-faulting case. - - * O(1) complexity under VM_BIND. - -The document is now included in the drm documentation :doc:`here `. - -Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when -the second driver supporting VM_BIND+userptr appears. Details to be defined when -the time comes. - -The DRM GPUVM helpers do not yet include the userptr parts, but discussions -about implementing them are ongoing. - Display integration with i915 ----------------------------- In order to share the display code with the i915 driver so that there is maximum @@ -139,6 +107,38 @@ Xe – uAPI high level overview Xe – Pre-Merge Goals - Completed ================================ +Userptr integration and vm_bind +------------------------------- +Different drivers implement different ways of dealing with execution of userptr. +With multiple drivers currently introducing support to VM_BIND, the goal is to +aim for a DRM consensus on what’s the best way to have that support. To some +extent this is already getting addressed itself with the GPUVA where likely the +userptr will be a GPUVA with a NULL GEM call VM bind directly on the userptr. +However, there are more aspects around the rules for that and the usage of +mmu_notifiers, locking and other aspects. + +This task here has the goal of introducing a documentation of the basic rules. + +The documentation *needs* to first live in this document (API session below) and +then moved to another more specific document or at Xe level or at DRM level. + +Documentation should include: + + * The userptr part of the VM_BIND api. + + * Locking, including the page-faulting case. + + * O(1) complexity under VM_BIND. + +The document is now included in the drm documentation :doc:`here `. + +Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when +the second driver supporting VM_BIND+userptr appears. Details to be defined when +the time comes. + +The DRM GPUVM helpers do not yet include the userptr parts, but discussions +about implementing them are ongoing. + ASYNC VM_BIND ------------- Although having a common DRM level IOCTL for VM_BIND is not a requirement to get From aa15b031854fc86fd0b9c7e6b794d57563cba60f Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Nov 2023 23:21:55 -0500 Subject: [PATCH 3086/7721] drm/doc/rfc: Xe is using drm_exec, so mark as completed Nothing else to be done on this front from Xe perspective. Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20231201042158.80009-6-rodrigo.vivi@intel.com Acked-by: Daniel Vetter --- Documentation/gpu/rfc/xe.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index cfff8a59a876..97cf87578f97 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -85,6 +85,14 @@ from the first pull request of Xe towards drm-next. The expectation is that when both drivers are part of the drm-tip, the introduction of cleaner patches will be easier and speed up. +Xe – uAPI high level overview +============================= + +...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. + +Xe – Pre-Merge Goals - Completed +================================ + Drm_exec -------- Helper to make dma_resv locking for a big number of buffers is getting removed in @@ -99,14 +107,6 @@ This item ties into the GPUVA, VM_BIND, and even long-running compute support. As a key measurable result, we need to have a community consensus documented in this document and the Xe driver prepared for the changes, if necessary. -Xe – uAPI high level overview -============================= - -...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. - -Xe – Pre-Merge Goals - Completed -================================ - Userptr integration and vm_bind ------------------------------- Different drivers implement different ways of dealing with execution of userptr. From ff93872a9c6168992ee41f2da9d9c3b8a6f8a8e5 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 26 Oct 2023 11:53:44 +0100 Subject: [PATCH 3087/7721] clk: qcom: camcc-sc8280xp: Add sc8280xp CAMCC Add the sc8280xp CAMCC driver which follows the sdm845 CAMCC lineage with additional CCI and IFE blocks and more granular clock parentage. Signed-off-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20231026105345.3376-4-bryan.odonoghue@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/camcc-sc8280xp.c | 3044 +++++++++++++++++++++++++++++ 3 files changed, 3054 insertions(+) create mode 100644 drivers/clk/qcom/camcc-sc8280xp.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ad1acd9b7426..e5f4c74addfc 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -427,6 +427,15 @@ config SC_CAMCC_7280 Say Y if you want to support camera devices and functionality such as capturing pictures. +config SC_CAMCC_8280XP + tristate "SC8280XP Camera Clock Controller" + select SC_GCC_8280XP + help + Support for the camera clock controller on Qualcomm Technologies, Inc + SC8280XP devices. + Say Y if you want to support camera devices and functionality such as + capturing pictures. + config SC_DISPCC_7180 tristate "SC7180 Display Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 17edd73f9839..8209eddf040e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o obj-$(CONFIG_QDU_GCC_1000) += gcc-qdu1000.o obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o obj-$(CONFIG_SC_CAMCC_7280) += camcc-sc7280.o +obj-$(CONFIG_SC_CAMCC_8280XP) += camcc-sc8280xp.o obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_DISPCC_7280) += dispcc-sc7280.o obj-$(CONFIG_SC_DISPCC_8280XP) += dispcc-sc8280xp.o diff --git a/drivers/clk/qcom/camcc-sc8280xp.c b/drivers/clk/qcom/camcc-sc8280xp.c new file mode 100644 index 000000000000..877341e7327e --- /dev/null +++ b/drivers/clk/qcom/camcc-sc8280xp.c @@ -0,0 +1,3044 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, +}; + +enum { + P_BI_TCXO, + P_CAMCC_PLL0_OUT_EVEN, + P_CAMCC_PLL0_OUT_MAIN, + P_CAMCC_PLL0_OUT_ODD, + P_CAMCC_PLL1_OUT_EVEN, + P_CAMCC_PLL2_OUT_AUX, + P_CAMCC_PLL2_OUT_EARLY, + P_CAMCC_PLL3_OUT_EVEN, + P_CAMCC_PLL4_OUT_EVEN, + P_CAMCC_PLL5_OUT_EVEN, + P_CAMCC_PLL6_OUT_EVEN, + P_CAMCC_PLL7_OUT_EVEN, + P_CAMCC_PLL7_OUT_ODD, + P_SLEEP_CLK, +}; + +static struct pll_vco lucid_vco[] = { + { 249600000, 1800000000, 0 }, +}; + +static struct pll_vco zonda_vco[] = { + { 595200000, 3600000000, 0 }, +}; + +static struct alpha_pll_config camcc_pll0_config = { + .l = 0x3e, + .alpha = 0x8000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00003100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll0 = { + .offset = 0x0, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll0", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll0_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll0_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll0_out_odd[] = { + { 0x3, 3 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll0_out_odd = { + .offset = 0x0, + .post_div_shift = 12, + .post_div_table = post_div_table_camcc_pll0_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll0_out_odd", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll1_config = { + .l = 0x21, + .alpha = 0x5555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll1", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll1_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll1_out_even = { + .offset = 0x1000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll1_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll1_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll1_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll1.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll2_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x08200800, + .config_ctl_hi_val = 0x05028011, + .config_ctl_hi1_val = 0x08000000, +}; + +static struct clk_alpha_pll camcc_pll2 = { + .offset = 0x2000, + .vco_table = zonda_vco, + .num_vco = ARRAY_SIZE(zonda_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll2", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_zonda_ops, + }, + }, +}; + +static struct alpha_pll_config camcc_pll3_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll3 = { + .offset = 0x3000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll3", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll3_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll3_out_even = { + .offset = 0x3000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll3_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll3_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll3_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll3.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll4_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll4 = { + .offset = 0x4000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll4", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll4_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll4_out_even = { + .offset = 0x4000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll4_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll4_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll4_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll4.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll5_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll5 = { + .offset = 0x10000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll5", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll5_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll5_out_even = { + .offset = 0x10000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll5_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll5_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll5_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll5.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll6_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20486699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll6 = { + .offset = 0x11000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll6", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll6_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll6_out_even = { + .offset = 0x11000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll6_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll6_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll6_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll6.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll7_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00003100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll7 = { + .offset = 0x12000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll7", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll7_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll7_out_even = { + .offset = 0x12000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll7_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll7_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll7_out_odd[] = { + { 0x3, 3 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll7_out_odd = { + .offset = 0x12000, + .post_div_shift = 12, + .post_div_table = post_div_table_camcc_pll7_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll7_out_odd", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static const struct parent_map camcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL2_OUT_AUX, 2 }, + { P_CAMCC_PLL2_OUT_EARLY, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll2.clkr.hw }, + { .hw = &camcc_pll2.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_ODD, 4 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, + { P_CAMCC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, + { .hw = &camcc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL4_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll4_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL5_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll5_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL6_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll6_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL1_OUT_EVEN, 4 }, +}; + +static const struct clk_parent_data camcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll1_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_9[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data camcc_parent_data_9[] = { + { .fw_name = "sleep_clk" }, +}; + +static const struct parent_map camcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data camcc_parent_data_10_ao[] = { + { .fw_name = "bi_tcxo_ao" }, +}; + +static const struct freq_tbl ftbl_camcc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), + F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_bps_clk_src = { + .cmd_rcgr = 0x7010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_3, + .freq_tbl = ftbl_camcc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_bps_clk_src", + .parent_data = camcc_parent_data_3, + .num_parents = ARRAY_SIZE(camcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_camnoc_axi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(150000000, P_CAMCC_PLL0_OUT_EVEN, 4, 0, 0), + F(266666667, P_CAMCC_PLL0_OUT_ODD, 1.5, 0, 0), + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_camnoc_axi_clk_src = { + .cmd_rcgr = 0xc170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_camnoc_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_axi_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_cci_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_CAMCC_PLL0_OUT_EVEN, 16, 0, 0), +}; + +static struct clk_rcg2 camcc_cci_0_clk_src = { + .cmd_rcgr = 0xc108, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_cci_0_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_cci_1_clk_src = { + .cmd_rcgr = 0xc124, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_cci_1_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_cci_2_clk_src = { + .cmd_rcgr = 0xc204, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_cci_2_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_cci_3_clk_src = { + .cmd_rcgr = 0xc220, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_cci_3_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_cphy_rx_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(240000000, P_CAMCC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_cphy_rx_clk_src = { + .cmd_rcgr = 0xa064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_cphy_rx_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_cphy_rx_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_csi0phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x6004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_csi0phytimer_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x6028, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_csi1phytimer_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x604c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_csi2phytimer_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x6074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_csi3phytimer_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_fast_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAMCC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_EVEN, 3, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_MAIN, 4, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0), +}; + +static struct clk_rcg2 camcc_fast_ahb_clk_src = { + .cmd_rcgr = 0x703c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_fast_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_fast_ahb_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_icp_clk_src = { + .cmd_rcgr = 0xc0b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_icp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_icp_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_0_clk_src = { + .cmd_rcgr = 0xa010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_4, + .freq_tbl = ftbl_camcc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_clk_src", + .parent_data = camcc_parent_data_4, + .num_parents = ARRAY_SIZE(camcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_0_csid_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(75000000, P_CAMCC_PLL0_OUT_EVEN, 8, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_0_csid_clk_src = { + .cmd_rcgr = 0xa03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_1_clk_src = { + .cmd_rcgr = 0xb010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_5, + .freq_tbl = ftbl_camcc_ife_1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_clk_src", + .parent_data = camcc_parent_data_5, + .num_parents = ARRAY_SIZE(camcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_1_csid_clk_src = { + .cmd_rcgr = 0xb03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_2_clk_src[] = { + F(400000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_2_clk_src = { + .cmd_rcgr = 0xf010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_6, + .freq_tbl = ftbl_camcc_ife_2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_clk_src", + .parent_data = camcc_parent_data_6, + .num_parents = ARRAY_SIZE(camcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_2_csid_clk_src[] = { + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_2_csid_clk_src = { + .cmd_rcgr = 0xf03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_3_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_3_clk_src = { + .cmd_rcgr = 0xf07c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_7, + .freq_tbl = ftbl_camcc_ife_3_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_clk_src", + .parent_data = camcc_parent_data_7, + .num_parents = ARRAY_SIZE(camcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_3_csid_clk_src = { + .cmd_rcgr = 0xf0a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_lite_0_clk_src[] = { + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_lite_0_clk_src = { + .cmd_rcgr = 0xc004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_0_csid_clk_src = { + .cmd_rcgr = 0xc020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_1_clk_src = { + .cmd_rcgr = 0xc048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_1_csid_clk_src = { + .cmd_rcgr = 0xc064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_2_clk_src = { + .cmd_rcgr = 0xc240, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_2_csid_clk_src = { + .cmd_rcgr = 0xc25c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_3_clk_src = { + .cmd_rcgr = 0xc284, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_3_csid_clk_src = { + .cmd_rcgr = 0xc2a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ipe_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(320000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(475000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(520000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ipe_0_clk_src = { + .cmd_rcgr = 0x8010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_8, + .freq_tbl = ftbl_camcc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_clk_src", + .parent_data = camcc_parent_data_8, + .num_parents = ARRAY_SIZE(camcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_jpeg_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_jpeg_clk_src = { + .cmd_rcgr = 0xc08c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_jpeg_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_jpeg_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_lrme_clk_src[] = { + F(240000000, P_CAMCC_PLL7_OUT_EVEN, 2, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0), + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0), +}; + +static struct clk_rcg2 camcc_lrme_clk_src = { + .cmd_rcgr = 0xc144, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_lrme_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_lrme_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_mclk0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAMCC_PLL2_OUT_EARLY, 10, 1, 4), + F(64000000, P_CAMCC_PLL2_OUT_EARLY, 15, 0, 0), +}; + +static struct clk_rcg2 camcc_mclk0_clk_src = { + .cmd_rcgr = 0x5004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk0_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk1_clk_src = { + .cmd_rcgr = 0x5024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk1_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk2_clk_src = { + .cmd_rcgr = 0x5044, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk2_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk3_clk_src = { + .cmd_rcgr = 0x5064, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk3_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk4_clk_src = { + .cmd_rcgr = 0x5084, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk4_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk5_clk_src = { + .cmd_rcgr = 0x50a4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk5_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk6_clk_src = { + .cmd_rcgr = 0x50c4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk6_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 camcc_mclk7_clk_src = { + .cmd_rcgr = 0x50e4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk7_clk_src", + .parent_data = camcc_parent_data_1, + .num_parents = ARRAY_SIZE(camcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_sleep_clk_src = { + .cmd_rcgr = 0xc1e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_9, + .freq_tbl = ftbl_camcc_sleep_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_sleep_clk_src", + .parent_data = camcc_parent_data_9, + .num_parents = ARRAY_SIZE(camcc_parent_data_9), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_slow_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(80000000, P_CAMCC_PLL7_OUT_EVEN, 6, 0, 0), +}; + +static struct clk_rcg2 camcc_slow_ahb_clk_src = { + .cmd_rcgr = 0x7058, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_slow_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_slow_ahb_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_xo_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_xo_clk_src = { + .cmd_rcgr = 0xc1cc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_10, + .freq_tbl = ftbl_camcc_xo_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_xo_clk_src", + .parent_data = camcc_parent_data_10_ao, + .num_parents = ARRAY_SIZE(camcc_parent_data_10_ao), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch camcc_bps_ahb_clk = { + .halt_reg = 0x7070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7070, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_bps_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_bps_areg_clk = { + .halt_reg = 0x7054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_bps_areg_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_bps_axi_clk = { + .halt_reg = 0x7038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_bps_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_bps_clk = { + .halt_reg = 0x7028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_bps_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_bps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_camnoc_axi_clk = { + .halt_reg = 0xc18c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc18c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_camnoc_dcd_xo_clk = { + .halt_reg = 0xc194, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc194, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_dcd_xo_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_0_clk = { + .halt_reg = 0xc120, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc120, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_1_clk = { + .halt_reg = 0xc13c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc13c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_2_clk = { + .halt_reg = 0xc21c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc21c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_3_clk = { + .halt_reg = 0xc238, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc238, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_core_ahb_clk = { + .halt_reg = 0xc1c8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xc1c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_core_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cpas_ahb_clk = { + .halt_reg = 0xc168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc168, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cpas_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csi0phytimer_clk = { + .halt_reg = 0x601c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x601c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csi0phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_csi0phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csi1phytimer_clk = { + .halt_reg = 0x6040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csi1phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_csi1phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csi2phytimer_clk = { + .halt_reg = 0x6064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csi2phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_csi2phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csi3phytimer_clk = { + .halt_reg = 0x608c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x608c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csi3phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_csi3phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csiphy0_clk = { + .halt_reg = 0x6020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csiphy0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csiphy1_clk = { + .halt_reg = 0x6044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csiphy1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csiphy2_clk = { + .halt_reg = 0x6068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csiphy2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_csiphy3_clk = { + .halt_reg = 0x6090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_csiphy3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_gdsc_clk = { + .halt_reg = 0xc1e4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc1e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_gdsc_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_icp_ahb_clk = { + .halt_reg = 0xc0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0d8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_icp_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_icp_clk = { + .halt_reg = 0xc0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_icp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_icp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_axi_clk = { + .halt_reg = 0xa080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_clk = { + .halt_reg = 0xa028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_cphy_rx_clk = { + .halt_reg = 0xa07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_csid_clk = { + .halt_reg = 0xa054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_0_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_dsp_clk = { + .halt_reg = 0xa038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_dsp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_axi_clk = { + .halt_reg = 0xb068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_clk = { + .halt_reg = 0xb028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_cphy_rx_clk = { + .halt_reg = 0xb064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_csid_clk = { + .halt_reg = 0xb054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_1_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_dsp_clk = { + .halt_reg = 0xb038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_dsp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_axi_clk = { + .halt_reg = 0xf068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_clk = { + .halt_reg = 0xf028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_cphy_rx_clk = { + .halt_reg = 0xf064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_csid_clk = { + .halt_reg = 0xf054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_2_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_dsp_clk = { + .halt_reg = 0xf038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_dsp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_axi_clk = { + .halt_reg = 0xf0d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0d4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_clk = { + .halt_reg = 0xf094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_cphy_rx_clk = { + .halt_reg = 0xf0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_csid_clk = { + .halt_reg = 0xf0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_dsp_clk = { + .halt_reg = 0xf0a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_dsp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_0_clk = { + .halt_reg = 0xc01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_0_cphy_rx_clk = { + .halt_reg = 0xc040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_0_csid_clk = { + .halt_reg = 0xc038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_0_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_1_clk = { + .halt_reg = 0xc060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_1_cphy_rx_clk = { + .halt_reg = 0xc084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_1_csid_clk = { + .halt_reg = 0xc07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_1_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_2_clk = { + .halt_reg = 0xc258, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc258, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_2_cphy_rx_clk = { + .halt_reg = 0xc27c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc27c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_2_csid_clk = { + .halt_reg = 0xc274, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc274, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_2_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_3_clk = { + .halt_reg = 0xc29c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc29c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_3_cphy_rx_clk = { + .halt_reg = 0xc2c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc2c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_3_csid_clk = { + .halt_reg = 0xc2b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc2b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_3_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_0_ahb_clk = { + .halt_reg = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_0_areg_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_areg_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_0_axi_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_0_clk = { + .halt_reg = 0x8028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ipe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_1_ahb_clk = { + .halt_reg = 0x9028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_1_areg_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_areg_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_1_axi_clk = { + .halt_reg = 0x9020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_1_clk = { + .halt_reg = 0x9010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ipe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_jpeg_clk = { + .halt_reg = 0xc0a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_jpeg_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_jpeg_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_lrme_clk = { + .halt_reg = 0xc15c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc15c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_lrme_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_lrme_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk0_clk = { + .halt_reg = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk1_clk = { + .halt_reg = 0x503c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x503c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk2_clk = { + .halt_reg = 0x505c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x505c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk3_clk = { + .halt_reg = 0x507c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x507c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk4_clk = { + .halt_reg = 0x509c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x509c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk4_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk5_clk = { + .halt_reg = 0x50bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk5_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk6_clk = { + .halt_reg = 0x50dc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50dc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk6_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk7_clk = { + .halt_reg = 0x50fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50fc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk7_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_sleep_clk = { + .halt_reg = 0xc200, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc200, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_sleep_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc titan_top_gdsc; + +static struct gdsc bps_gdsc = { + .gdscr = 0x7004, + .pd = { + .name = "bps_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_0_gdsc = { + .gdscr = 0xa004, + .pd = { + .name = "ife_0_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_1_gdsc = { + .gdscr = 0xb004, + .pd = { + .name = "ife_1_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_2_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "ife_2_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_3_gdsc = { + .gdscr = 0xf070, + .pd = { + .name = "ife_3_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_0_gdsc = { + .gdscr = 0x8004, + .pd = { + .name = "ipe_0_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_1_gdsc = { + .gdscr = 0x9004, + .pd = { + .name = "ipe_1_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc titan_top_gdsc = { + .gdscr = 0xc1bc, + .pd = { + .name = "titan_top_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct clk_regmap *camcc_sc8280xp_clocks[] = { + [CAMCC_BPS_AHB_CLK] = &camcc_bps_ahb_clk.clkr, + [CAMCC_BPS_AREG_CLK] = &camcc_bps_areg_clk.clkr, + [CAMCC_BPS_AXI_CLK] = &camcc_bps_axi_clk.clkr, + [CAMCC_BPS_CLK] = &camcc_bps_clk.clkr, + [CAMCC_BPS_CLK_SRC] = &camcc_bps_clk_src.clkr, + [CAMCC_CAMNOC_AXI_CLK] = &camcc_camnoc_axi_clk.clkr, + [CAMCC_CAMNOC_AXI_CLK_SRC] = &camcc_camnoc_axi_clk_src.clkr, + [CAMCC_CAMNOC_DCD_XO_CLK] = &camcc_camnoc_dcd_xo_clk.clkr, + [CAMCC_CCI_0_CLK] = &camcc_cci_0_clk.clkr, + [CAMCC_CCI_0_CLK_SRC] = &camcc_cci_0_clk_src.clkr, + [CAMCC_CCI_1_CLK] = &camcc_cci_1_clk.clkr, + [CAMCC_CCI_1_CLK_SRC] = &camcc_cci_1_clk_src.clkr, + [CAMCC_CCI_2_CLK] = &camcc_cci_2_clk.clkr, + [CAMCC_CCI_2_CLK_SRC] = &camcc_cci_2_clk_src.clkr, + [CAMCC_CCI_3_CLK] = &camcc_cci_3_clk.clkr, + [CAMCC_CCI_3_CLK_SRC] = &camcc_cci_3_clk_src.clkr, + [CAMCC_CORE_AHB_CLK] = &camcc_core_ahb_clk.clkr, + [CAMCC_CPAS_AHB_CLK] = &camcc_cpas_ahb_clk.clkr, + [CAMCC_CPHY_RX_CLK_SRC] = &camcc_cphy_rx_clk_src.clkr, + [CAMCC_CSI0PHYTIMER_CLK] = &camcc_csi0phytimer_clk.clkr, + [CAMCC_CSI0PHYTIMER_CLK_SRC] = &camcc_csi0phytimer_clk_src.clkr, + [CAMCC_CSI1PHYTIMER_CLK] = &camcc_csi1phytimer_clk.clkr, + [CAMCC_CSI1PHYTIMER_CLK_SRC] = &camcc_csi1phytimer_clk_src.clkr, + [CAMCC_CSI2PHYTIMER_CLK] = &camcc_csi2phytimer_clk.clkr, + [CAMCC_CSI2PHYTIMER_CLK_SRC] = &camcc_csi2phytimer_clk_src.clkr, + [CAMCC_CSI3PHYTIMER_CLK] = &camcc_csi3phytimer_clk.clkr, + [CAMCC_CSI3PHYTIMER_CLK_SRC] = &camcc_csi3phytimer_clk_src.clkr, + [CAMCC_CSIPHY0_CLK] = &camcc_csiphy0_clk.clkr, + [CAMCC_CSIPHY1_CLK] = &camcc_csiphy1_clk.clkr, + [CAMCC_CSIPHY2_CLK] = &camcc_csiphy2_clk.clkr, + [CAMCC_CSIPHY3_CLK] = &camcc_csiphy3_clk.clkr, + [CAMCC_FAST_AHB_CLK_SRC] = &camcc_fast_ahb_clk_src.clkr, + [CAMCC_GDSC_CLK] = &camcc_gdsc_clk.clkr, + [CAMCC_ICP_AHB_CLK] = &camcc_icp_ahb_clk.clkr, + [CAMCC_ICP_CLK] = &camcc_icp_clk.clkr, + [CAMCC_ICP_CLK_SRC] = &camcc_icp_clk_src.clkr, + [CAMCC_IFE_0_AXI_CLK] = &camcc_ife_0_axi_clk.clkr, + [CAMCC_IFE_0_CLK] = &camcc_ife_0_clk.clkr, + [CAMCC_IFE_0_CLK_SRC] = &camcc_ife_0_clk_src.clkr, + [CAMCC_IFE_0_CPHY_RX_CLK] = &camcc_ife_0_cphy_rx_clk.clkr, + [CAMCC_IFE_0_CSID_CLK] = &camcc_ife_0_csid_clk.clkr, + [CAMCC_IFE_0_CSID_CLK_SRC] = &camcc_ife_0_csid_clk_src.clkr, + [CAMCC_IFE_0_DSP_CLK] = &camcc_ife_0_dsp_clk.clkr, + [CAMCC_IFE_1_AXI_CLK] = &camcc_ife_1_axi_clk.clkr, + [CAMCC_IFE_1_CLK] = &camcc_ife_1_clk.clkr, + [CAMCC_IFE_1_CLK_SRC] = &camcc_ife_1_clk_src.clkr, + [CAMCC_IFE_1_CPHY_RX_CLK] = &camcc_ife_1_cphy_rx_clk.clkr, + [CAMCC_IFE_1_CSID_CLK] = &camcc_ife_1_csid_clk.clkr, + [CAMCC_IFE_1_CSID_CLK_SRC] = &camcc_ife_1_csid_clk_src.clkr, + [CAMCC_IFE_1_DSP_CLK] = &camcc_ife_1_dsp_clk.clkr, + [CAMCC_IFE_2_AXI_CLK] = &camcc_ife_2_axi_clk.clkr, + [CAMCC_IFE_2_CLK] = &camcc_ife_2_clk.clkr, + [CAMCC_IFE_2_CLK_SRC] = &camcc_ife_2_clk_src.clkr, + [CAMCC_IFE_2_CPHY_RX_CLK] = &camcc_ife_2_cphy_rx_clk.clkr, + [CAMCC_IFE_2_CSID_CLK] = &camcc_ife_2_csid_clk.clkr, + [CAMCC_IFE_2_CSID_CLK_SRC] = &camcc_ife_2_csid_clk_src.clkr, + [CAMCC_IFE_2_DSP_CLK] = &camcc_ife_2_dsp_clk.clkr, + [CAMCC_IFE_3_AXI_CLK] = &camcc_ife_3_axi_clk.clkr, + [CAMCC_IFE_3_CLK] = &camcc_ife_3_clk.clkr, + [CAMCC_IFE_3_CLK_SRC] = &camcc_ife_3_clk_src.clkr, + [CAMCC_IFE_3_CPHY_RX_CLK] = &camcc_ife_3_cphy_rx_clk.clkr, + [CAMCC_IFE_3_CSID_CLK] = &camcc_ife_3_csid_clk.clkr, + [CAMCC_IFE_3_CSID_CLK_SRC] = &camcc_ife_3_csid_clk_src.clkr, + [CAMCC_IFE_3_DSP_CLK] = &camcc_ife_3_dsp_clk.clkr, + [CAMCC_IFE_LITE_0_CLK] = &camcc_ife_lite_0_clk.clkr, + [CAMCC_IFE_LITE_0_CLK_SRC] = &camcc_ife_lite_0_clk_src.clkr, + [CAMCC_IFE_LITE_0_CPHY_RX_CLK] = &camcc_ife_lite_0_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_0_CSID_CLK] = &camcc_ife_lite_0_csid_clk.clkr, + [CAMCC_IFE_LITE_0_CSID_CLK_SRC] = &camcc_ife_lite_0_csid_clk_src.clkr, + [CAMCC_IFE_LITE_1_CLK] = &camcc_ife_lite_1_clk.clkr, + [CAMCC_IFE_LITE_1_CLK_SRC] = &camcc_ife_lite_1_clk_src.clkr, + [CAMCC_IFE_LITE_1_CPHY_RX_CLK] = &camcc_ife_lite_1_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_1_CSID_CLK] = &camcc_ife_lite_1_csid_clk.clkr, + [CAMCC_IFE_LITE_1_CSID_CLK_SRC] = &camcc_ife_lite_1_csid_clk_src.clkr, + [CAMCC_IFE_LITE_2_CLK] = &camcc_ife_lite_2_clk.clkr, + [CAMCC_IFE_LITE_2_CLK_SRC] = &camcc_ife_lite_2_clk_src.clkr, + [CAMCC_IFE_LITE_2_CPHY_RX_CLK] = &camcc_ife_lite_2_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_2_CSID_CLK] = &camcc_ife_lite_2_csid_clk.clkr, + [CAMCC_IFE_LITE_2_CSID_CLK_SRC] = &camcc_ife_lite_2_csid_clk_src.clkr, + [CAMCC_IFE_LITE_3_CLK] = &camcc_ife_lite_3_clk.clkr, + [CAMCC_IFE_LITE_3_CLK_SRC] = &camcc_ife_lite_3_clk_src.clkr, + [CAMCC_IFE_LITE_3_CPHY_RX_CLK] = &camcc_ife_lite_3_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_3_CSID_CLK] = &camcc_ife_lite_3_csid_clk.clkr, + [CAMCC_IFE_LITE_3_CSID_CLK_SRC] = &camcc_ife_lite_3_csid_clk_src.clkr, + [CAMCC_IPE_0_AHB_CLK] = &camcc_ipe_0_ahb_clk.clkr, + [CAMCC_IPE_0_AREG_CLK] = &camcc_ipe_0_areg_clk.clkr, + [CAMCC_IPE_0_AXI_CLK] = &camcc_ipe_0_axi_clk.clkr, + [CAMCC_IPE_0_CLK] = &camcc_ipe_0_clk.clkr, + [CAMCC_IPE_0_CLK_SRC] = &camcc_ipe_0_clk_src.clkr, + [CAMCC_IPE_1_AHB_CLK] = &camcc_ipe_1_ahb_clk.clkr, + [CAMCC_IPE_1_AREG_CLK] = &camcc_ipe_1_areg_clk.clkr, + [CAMCC_IPE_1_AXI_CLK] = &camcc_ipe_1_axi_clk.clkr, + [CAMCC_IPE_1_CLK] = &camcc_ipe_1_clk.clkr, + [CAMCC_JPEG_CLK] = &camcc_jpeg_clk.clkr, + [CAMCC_JPEG_CLK_SRC] = &camcc_jpeg_clk_src.clkr, + [CAMCC_LRME_CLK] = &camcc_lrme_clk.clkr, + [CAMCC_LRME_CLK_SRC] = &camcc_lrme_clk_src.clkr, + [CAMCC_MCLK0_CLK] = &camcc_mclk0_clk.clkr, + [CAMCC_MCLK0_CLK_SRC] = &camcc_mclk0_clk_src.clkr, + [CAMCC_MCLK1_CLK] = &camcc_mclk1_clk.clkr, + [CAMCC_MCLK1_CLK_SRC] = &camcc_mclk1_clk_src.clkr, + [CAMCC_MCLK2_CLK] = &camcc_mclk2_clk.clkr, + [CAMCC_MCLK2_CLK_SRC] = &camcc_mclk2_clk_src.clkr, + [CAMCC_MCLK3_CLK] = &camcc_mclk3_clk.clkr, + [CAMCC_MCLK3_CLK_SRC] = &camcc_mclk3_clk_src.clkr, + [CAMCC_MCLK4_CLK] = &camcc_mclk4_clk.clkr, + [CAMCC_MCLK4_CLK_SRC] = &camcc_mclk4_clk_src.clkr, + [CAMCC_MCLK5_CLK] = &camcc_mclk5_clk.clkr, + [CAMCC_MCLK5_CLK_SRC] = &camcc_mclk5_clk_src.clkr, + [CAMCC_MCLK6_CLK] = &camcc_mclk6_clk.clkr, + [CAMCC_MCLK6_CLK_SRC] = &camcc_mclk6_clk_src.clkr, + [CAMCC_MCLK7_CLK] = &camcc_mclk7_clk.clkr, + [CAMCC_MCLK7_CLK_SRC] = &camcc_mclk7_clk_src.clkr, + [CAMCC_PLL0] = &camcc_pll0.clkr, + [CAMCC_PLL0_OUT_EVEN] = &camcc_pll0_out_even.clkr, + [CAMCC_PLL0_OUT_ODD] = &camcc_pll0_out_odd.clkr, + [CAMCC_PLL1] = &camcc_pll1.clkr, + [CAMCC_PLL1_OUT_EVEN] = &camcc_pll1_out_even.clkr, + [CAMCC_PLL2] = &camcc_pll2.clkr, + [CAMCC_PLL3] = &camcc_pll3.clkr, + [CAMCC_PLL3_OUT_EVEN] = &camcc_pll3_out_even.clkr, + [CAMCC_PLL4] = &camcc_pll4.clkr, + [CAMCC_PLL4_OUT_EVEN] = &camcc_pll4_out_even.clkr, + [CAMCC_PLL5] = &camcc_pll5.clkr, + [CAMCC_PLL5_OUT_EVEN] = &camcc_pll5_out_even.clkr, + [CAMCC_PLL6] = &camcc_pll6.clkr, + [CAMCC_PLL6_OUT_EVEN] = &camcc_pll6_out_even.clkr, + [CAMCC_PLL7] = &camcc_pll7.clkr, + [CAMCC_PLL7_OUT_EVEN] = &camcc_pll7_out_even.clkr, + [CAMCC_PLL7_OUT_ODD] = &camcc_pll7_out_odd.clkr, + [CAMCC_SLEEP_CLK] = &camcc_sleep_clk.clkr, + [CAMCC_SLEEP_CLK_SRC] = &camcc_sleep_clk_src.clkr, + [CAMCC_SLOW_AHB_CLK_SRC] = &camcc_slow_ahb_clk_src.clkr, + [CAMCC_XO_CLK_SRC] = &camcc_xo_clk_src.clkr, +}; + +static struct gdsc *camcc_sc8280xp_gdscs[] = { + [BPS_GDSC] = &bps_gdsc, + [IFE_0_GDSC] = &ife_0_gdsc, + [IFE_1_GDSC] = &ife_1_gdsc, + [IFE_2_GDSC] = &ife_2_gdsc, + [IFE_3_GDSC] = &ife_3_gdsc, + [IPE_0_GDSC] = &ipe_0_gdsc, + [IPE_1_GDSC] = &ipe_1_gdsc, + [TITAN_TOP_GDSC] = &titan_top_gdsc, +}; + +static const struct qcom_reset_map camcc_sc8280xp_resets[] = { + [CAMCC_BPS_BCR] = { 0x7000 }, + [CAMCC_CAMNOC_BCR] = { 0xc16c }, + [CAMCC_CCI_BCR] = { 0xc104 }, + [CAMCC_CPAS_BCR] = { 0xc164 }, + [CAMCC_CSI0PHY_BCR] = { 0x6000 }, + [CAMCC_CSI1PHY_BCR] = { 0x6024 }, + [CAMCC_CSI2PHY_BCR] = { 0x6048 }, + [CAMCC_CSI3PHY_BCR] = { 0x6070 }, + [CAMCC_ICP_BCR] = { 0xc0b4 }, + [CAMCC_IFE_0_BCR] = { 0xa000 }, + [CAMCC_IFE_1_BCR] = { 0xb000 }, + [CAMCC_IFE_2_BCR] = { 0xf000 }, + [CAMCC_IFE_3_BCR] = { 0xf06c }, + [CAMCC_IFE_LITE_0_BCR] = { 0xc000 }, + [CAMCC_IFE_LITE_1_BCR] = { 0xc044 }, + [CAMCC_IFE_LITE_2_BCR] = { 0xc23c }, + [CAMCC_IFE_LITE_3_BCR] = { 0xc280 }, + [CAMCC_IPE_0_BCR] = { 0x8000 }, + [CAMCC_IPE_1_BCR] = { 0x9000 }, + [CAMCC_JPEG_BCR] = { 0xc088 }, + [CAMCC_LRME_BCR] = { 0xc140 }, +}; + +static const struct regmap_config camcc_sc8280xp_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x13020, + .fast_io = true, +}; + +static struct qcom_cc_desc camcc_sc8280xp_desc = { + .config = &camcc_sc8280xp_regmap_config, + .clks = camcc_sc8280xp_clocks, + .num_clks = ARRAY_SIZE(camcc_sc8280xp_clocks), + .resets = camcc_sc8280xp_resets, + .num_resets = ARRAY_SIZE(camcc_sc8280xp_resets), + .gdscs = camcc_sc8280xp_gdscs, + .num_gdscs = ARRAY_SIZE(camcc_sc8280xp_gdscs), +}; + +static const struct of_device_id camcc_sc8280xp_match_table[] = { + { .compatible = "qcom,sc8280xp-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, camcc_sc8280xp_match_table); + +static int camcc_sc8280xp_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &camcc_sc8280xp_desc); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_put_rpm; + } + + clk_lucid_pll_configure(&camcc_pll0, regmap, &camcc_pll0_config); + clk_lucid_pll_configure(&camcc_pll1, regmap, &camcc_pll1_config); + clk_zonda_pll_configure(&camcc_pll2, regmap, &camcc_pll2_config); + clk_lucid_pll_configure(&camcc_pll3, regmap, &camcc_pll3_config); + clk_lucid_pll_configure(&camcc_pll4, regmap, &camcc_pll4_config); + clk_lucid_pll_configure(&camcc_pll5, regmap, &camcc_pll5_config); + clk_lucid_pll_configure(&camcc_pll6, regmap, &camcc_pll6_config); + clk_lucid_pll_configure(&camcc_pll7, regmap, &camcc_pll7_config); + + /* + * Keep camcc_gdsc_clk always enabled: + */ + regmap_update_bits(regmap, 0xc1e4, BIT(0), 1); + + ret = qcom_cc_really_probe(pdev, &camcc_sc8280xp_desc, regmap); + if (ret) + goto err_put_rpm; + + pm_runtime_put(&pdev->dev); + + return 0; + +err_put_rpm: + regmap_update_bits(regmap, 0xc1e4, BIT(0), 0); + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static struct platform_driver camcc_sc8280xp_driver = { + .probe = camcc_sc8280xp_probe, + .driver = { + .name = "camcc-sc8280xp", + .of_match_table = camcc_sc8280xp_match_table, + }, +}; + +module_platform_driver(camcc_sc8280xp_driver); + +MODULE_DESCRIPTION("QCOM CAMCC SC8280XP Driver"); +MODULE_LICENSE("GPL"); From 9bd07f2c558f9c7d41f3761df3e93bd9ebaa0d4f Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 26 Oct 2023 11:53:45 +0100 Subject: [PATCH 3088/7721] arm64: dts: qcom: sc8280xp: Add in CAMCC for sc8280xp Add in CAMCC for sc8280xp. The sc8280xp Camera Clock Controller looks similar to most of the sdmX, smX and now scX controllers. Signed-off-by: Bryan O'Donoghue Suggested-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231026105345.3376-5-bryan.odonoghue@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 2ef3c1c9eadf..3a44a171893a 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -3450,6 +3451,20 @@ usb_1_role_switch: endpoint { }; }; + camcc: clock-controller@ad00000 { + compatible = "qcom,sc8280xp-camcc"; + reg = <0 0x0ad00000 0 0x20000>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + power-domains = <&rpmhpd SC8280XP_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + mdss0: display-subsystem@ae00000 { compatible = "qcom,sc8280xp-mdss"; reg = <0 0x0ae00000 0 0x1000>; From 3f373de6da2c960f0630a63890dded7d53358e2a Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Sun, 29 Oct 2023 07:19:47 +0100 Subject: [PATCH 3089/7721] dt-bindings: clock: qcom,gcc-msm8939: Add CSI2 related clocks When adding in the indexes for this clock-controller we missed GCC_CAMSS_CSI2_AHB_CLK, GCC_CAMSS_CSI2_CLK, GCC_CAMSS_CSI2PHY_CLK, GCC_CAMSS_CSI2PIX_CLK and GCC_CAMSS_CSI2RDI_CLK. Add them in now. Reviewed-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Signed-off-by: Vincent Knecht Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231029061948.505883-1-vincent.knecht@mailoo.org Signed-off-by: Bjorn Andersson --- include/dt-bindings/clock/qcom,gcc-msm8939.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dt-bindings/clock/qcom,gcc-msm8939.h b/include/dt-bindings/clock/qcom,gcc-msm8939.h index 2d545ed0d35a..9a9bc55b49af 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8939.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8939.h @@ -193,6 +193,12 @@ #define GCC_VENUS0_CORE1_VCODEC0_CLK 184 #define GCC_OXILI_TIMER_CLK 185 #define SYSTEM_MM_NOC_BFDCD_CLK_SRC 186 +#define CSI2_CLK_SRC 187 +#define GCC_CAMSS_CSI2_AHB_CLK 188 +#define GCC_CAMSS_CSI2_CLK 189 +#define GCC_CAMSS_CSI2PHY_CLK 190 +#define GCC_CAMSS_CSI2PIX_CLK 191 +#define GCC_CAMSS_CSI2RDI_CLK 192 /* Indexes for GDSCs */ #define BIMC_GDSC 0 From 8f799d304c313f6628c4b21cd0227ac56b581944 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Sun, 29 Oct 2023 07:19:48 +0100 Subject: [PATCH 3090/7721] clk: qcom: gcc-msm8939: Add missing CSI2 related clocks When adding in the indexes for this clock-controller we missed GCC_CAMSS_CSI2_AHB_CLK, GCC_CAMSS_CSI2_CLK, GCC_CAMSS_CSI2PHY_CLK, GCC_CAMSS_CSI2PIX_CLK and GCC_CAMSS_CSI2RDI_CLK. Add them in now and rename ftbl_gcc_camss_csi0_1_clk to account for csi2 also using it. Reviewed-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Signed-off-by: Vincent Knecht Link: https://lore.kernel.org/r/20231029061948.505883-2-vincent.knecht@mailoo.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-msm8939.c | 110 ++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/gcc-msm8939.c b/drivers/clk/qcom/gcc-msm8939.c index b45f97c07eeb..7b9a3e99b589 100644 --- a/drivers/clk/qcom/gcc-msm8939.c +++ b/drivers/clk/qcom/gcc-msm8939.c @@ -696,7 +696,7 @@ static struct clk_rcg2 apss_ahb_clk_src = { }, }; -static const struct freq_tbl ftbl_gcc_camss_csi0_1_clk[] = { +static const struct freq_tbl ftbl_gcc_camss_csi0_1_2_clk[] = { F(100000000, P_GPLL0, 8, 0, 0), F(200000000, P_GPLL0, 4, 0, 0), { } @@ -706,7 +706,7 @@ static struct clk_rcg2 csi0_clk_src = { .cmd_rcgr = 0x4e020, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_gcc_camss_csi0_1_clk, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "csi0_clk_src", .parent_data = gcc_xo_gpll0_parent_data, @@ -719,7 +719,7 @@ static struct clk_rcg2 csi1_clk_src = { .cmd_rcgr = 0x4f020, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_gcc_camss_csi0_1_clk, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "csi1_clk_src", .parent_data = gcc_xo_gpll0_parent_data, @@ -728,6 +728,19 @@ static struct clk_rcg2 csi1_clk_src = { }, }; +static struct clk_rcg2 csi2_clk_src = { + .cmd_rcgr = 0x3c020, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi2_clk_src", + .parent_data = gcc_xo_gpll0_parent_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_parent_data), + .ops = &clk_rcg2_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = { F(19200000, P_XO, 1, 0, 0), F(50000000, P_GPLL0, 16, 0, 0), @@ -2385,6 +2398,91 @@ static struct clk_branch gcc_camss_csi1rdi_clk = { }, }; +static struct clk_branch gcc_camss_csi2_ahb_clk = { + .halt_reg = 0x3c040, + .clkr = { + .enable_reg = 0x3c040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2_clk = { + .halt_reg = 0x3c03c, + .clkr = { + .enable_reg = 0x3c03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2phy_clk = { + .halt_reg = 0x3c048, + .clkr = { + .enable_reg = 0x3c048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2phy_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2pix_clk = { + .halt_reg = 0x3c058, + .clkr = { + .enable_reg = 0x3c058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2pix_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2rdi_clk = { + .halt_reg = 0x3c050, + .clkr = { + .enable_reg = 0x3c050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2rdi_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_camss_csi_vfe0_clk = { .halt_reg = 0x58050, .clkr = { @@ -3682,6 +3780,7 @@ static struct clk_regmap *gcc_msm8939_clocks[] = { [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, [CSI0_CLK_SRC] = &csi0_clk_src.clkr, [CSI1_CLK_SRC] = &csi1_clk_src.clkr, + [CSI2_CLK_SRC] = &csi2_clk_src.clkr, [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr, [VFE0_CLK_SRC] = &vfe0_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, @@ -3751,6 +3850,11 @@ static struct clk_regmap *gcc_msm8939_clocks[] = { [GCC_CAMSS_CSI1PHY_CLK] = &gcc_camss_csi1phy_clk.clkr, [GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr, [GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr, + [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr, + [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr, + [GCC_CAMSS_CSI2PHY_CLK] = &gcc_camss_csi2phy_clk.clkr, + [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr, + [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr, [GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr, [GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr, [GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr, From 8fa41c40a1cb8bd78e3aba36865162c8d7019d94 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 10:45:14 +0100 Subject: [PATCH 3091/7721] dt-bindings: cache: qcom,llcc: Document the SM8650 Last Level Cache Controller Document the Last Level Cache Controller on the SM8650 platform. Acked-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-llcc-v2-1-f281cec608e2@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/cache/qcom,llcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 580f9a97ddf7..7a211e35e166 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -33,6 +33,7 @@ properties: - qcom,sm8350-llcc - qcom,sm8450-llcc - qcom,sm8550-llcc + - qcom,sm8650-llcc reg: minItems: 2 From 7a280fec21fa4ca313e7aa6708f2480757501053 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 30 Oct 2023 10:45:15 +0100 Subject: [PATCH 3092/7721] soc: qcom: llcc: Add configuration data for SM8650 Add Last Level Cache Controller support for the SM8650 platform. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231030-topic-sm8650-upstream-llcc-v2-2-f281cec608e2@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 674abd0d6700..e92b950c2a9c 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -362,6 +362,33 @@ static const struct llcc_slice_config sm8550_data[] = { {LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }; +static const struct llcc_slice_config sm8650_data[] = { + {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AUDIO, 6, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MDMHPGRW, 25, 1024, 3, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MDMHPFX, 24, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MDMPNG, 27, 1024, 0, 1, 0x000000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CVP, 8, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MODPE, 29, 128, 1, 1, 0xF00000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP0, 4, 256, 3, 1, 0xF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CMPTHCP, 17, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_LCPDARE, 30, 128, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_AENPU, 3, 3072, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND1, 12, 5888, 7, 1, 0x0, 0x7FFFFF, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_DISP_WB, 23, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_VIDVSP, 28, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + static const struct llcc_slice_config qdu1000_data_2ch[] = { { LLCC_MDMHPGRW, 7, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, { LLCC_MODHW, 9, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, @@ -610,6 +637,16 @@ static const struct qcom_llcc_config sm8550_cfg[] = { }, }; +static const struct qcom_llcc_config sm8650_cfg[] = { + { + .sct_data = sm8650_data, + .size = ARRAY_SIZE(sm8650_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + static const struct qcom_sct_config qdu1000_cfgs = { .llcc_config = qdu1000_cfg, .num_config = ARRAY_SIZE(qdu1000_cfg), @@ -675,6 +712,11 @@ static const struct qcom_sct_config sm8550_cfgs = { .num_config = ARRAY_SIZE(sm8550_cfg), }; +static const struct qcom_sct_config sm8650_cfgs = { + .llcc_config = sm8650_cfg, + .num_config = ARRAY_SIZE(sm8650_cfg), +}; + static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; /** @@ -1249,6 +1291,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfgs }, { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs }, { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs }, + { .compatible = "qcom,sm8650-llcc", .data = &sm8650_cfgs }, { } }; MODULE_DEVICE_TABLE(of, qcom_llcc_of_match); From 1a3b3bd142ffea56cdfd458246b2e4da6df19da6 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:54 +0100 Subject: [PATCH 3093/7721] dt-bindings: clock: qcom: document the SM8650 TCSR Clock Controller Add bindings documentation for the SM8650 TCSR Clock Controller. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-1-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8550-tcsr.yaml | 8 ++++++-- include/dt-bindings/clock/qcom,sm8650-tcsr.h | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 include/dt-bindings/clock/qcom,sm8650-tcsr.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml index 1bf1a41fd89c..af16b05eac96 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -13,12 +13,16 @@ description: | Qualcomm TCSR clock control module provides the clocks, resets and power domains on SM8550 - See also:: include/dt-bindings/clock/qcom,sm8550-tcsr.h + See also: + - include/dt-bindings/clock/qcom,sm8550-tcsr.h + - include/dt-bindings/clock/qcom,sm8650-tcsr.h properties: compatible: items: - - const: qcom,sm8550-tcsr + - enum: + - qcom,sm8550-tcsr + - qcom,sm8650-tcsr - const: syscon clocks: diff --git a/include/dt-bindings/clock/qcom,sm8650-tcsr.h b/include/dt-bindings/clock/qcom,sm8650-tcsr.h new file mode 100644 index 000000000000..b2c72d492f1f --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8650-tcsr.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8650_H +#define _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8650_H + +/* TCSR CC clocks */ +#define TCSR_PCIE_0_CLKREF_EN 0 +#define TCSR_PCIE_1_CLKREF_EN 1 +#define TCSR_UFS_CLKREF_EN 2 +#define TCSR_UFS_PAD_CLKREF_EN 3 +#define TCSR_USB2_CLKREF_EN 4 +#define TCSR_USB3_CLKREF_EN 5 + +#endif From b69d932154dcfa84540aea55dd51a74fbc88d370 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:55 +0100 Subject: [PATCH 3094/7721] dt-bindings: clock: qcom: document the SM8650 General Clock Controller Add bindings documentation for the SM8650 General Clock Controller. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-2-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8650-gcc.yaml | 65 +++++ include/dt-bindings/clock/qcom,sm8650-gcc.h | 254 ++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8650-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml new file mode 100644 index 000000000000..b54761cc8674 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8650-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on SM8650 + +maintainers: + - Bjorn Andersson + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on SM8650 + + See also:: include/dt-bindings/clock/qcom,sm8650-gcc.h + +properties: + compatible: + const: qcom,sm8650-gcc + + clocks: + items: + - description: Board XO source + - description: Board Always On XO source + - description: Sleep clock source + - description: PCIE 0 Pipe clock source + - description: PCIE 1 Pipe clock source + - description: PCIE 1 Phy Auxiliary clock source + - description: UFS Phy Rx symbol 0 clock source + - description: UFS Phy Rx symbol 1 clock source + - description: UFS Phy Tx symbol 0 clock source + - description: USB3 Phy wrapper pipe clock source + +required: + - compatible + - clocks + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,sm8650-gcc"; + reg = <0x00100000 0x001f4200>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&pcie0_phy>, + <&pcie1_phy>, + <&pcie_1_phy_aux_clk>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, + <&usb_1_qmpphy>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,sm8650-gcc.h b/include/dt-bindings/clock/qcom,sm8650-gcc.h new file mode 100644 index 000000000000..0c543ba46079 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8650-gcc.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SM8650_H +#define _DT_BINDINGS_CLK_QCOM_GCC_SM8650_H + +/* GCC clocks */ +#define GCC_AGGRE_NOC_PCIE_AXI_CLK 0 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 1 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 2 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 3 +#define GCC_BOOT_ROM_AHB_CLK 4 +#define GCC_CAMERA_AHB_CLK 5 +#define GCC_CAMERA_HF_AXI_CLK 6 +#define GCC_CAMERA_SF_AXI_CLK 7 +#define GCC_CAMERA_XO_CLK 8 +#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 9 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 10 +#define GCC_CNOC_PCIE_SF_AXI_CLK 11 +#define GCC_DDRSS_GPU_AXI_CLK 12 +#define GCC_DDRSS_PCIE_SF_QTB_CLK 13 +#define GCC_DISP_AHB_CLK 14 +#define GCC_DISP_HF_AXI_CLK 15 +#define GCC_DISP_XO_CLK 16 +#define GCC_GP1_CLK 17 +#define GCC_GP1_CLK_SRC 18 +#define GCC_GP2_CLK 19 +#define GCC_GP2_CLK_SRC 20 +#define GCC_GP3_CLK 21 +#define GCC_GP3_CLK_SRC 22 +#define GCC_GPLL0 23 +#define GCC_GPLL0_OUT_EVEN 24 +#define GCC_GPLL1 25 +#define GCC_GPLL3 26 +#define GCC_GPLL4 27 +#define GCC_GPLL6 28 +#define GCC_GPLL7 29 +#define GCC_GPLL9 30 +#define GCC_GPU_CFG_AHB_CLK 31 +#define GCC_GPU_GPLL0_CLK_SRC 32 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 33 +#define GCC_GPU_MEMNOC_GFX_CLK 34 +#define GCC_GPU_SNOC_DVM_GFX_CLK 35 +#define GCC_PCIE_0_AUX_CLK 36 +#define GCC_PCIE_0_AUX_CLK_SRC 37 +#define GCC_PCIE_0_CFG_AHB_CLK 38 +#define GCC_PCIE_0_MSTR_AXI_CLK 39 +#define GCC_PCIE_0_PHY_RCHNG_CLK 40 +#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 41 +#define GCC_PCIE_0_PIPE_CLK 42 +#define GCC_PCIE_0_PIPE_CLK_SRC 43 +#define GCC_PCIE_0_SLV_AXI_CLK 44 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 45 +#define GCC_PCIE_1_AUX_CLK 46 +#define GCC_PCIE_1_AUX_CLK_SRC 47 +#define GCC_PCIE_1_CFG_AHB_CLK 48 +#define GCC_PCIE_1_MSTR_AXI_CLK 49 +#define GCC_PCIE_1_PHY_AUX_CLK 50 +#define GCC_PCIE_1_PHY_AUX_CLK_SRC 51 +#define GCC_PCIE_1_PHY_RCHNG_CLK 52 +#define GCC_PCIE_1_PHY_RCHNG_CLK_SRC 53 +#define GCC_PCIE_1_PIPE_CLK 54 +#define GCC_PCIE_1_PIPE_CLK_SRC 55 +#define GCC_PCIE_1_SLV_AXI_CLK 56 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 57 +#define GCC_PDM2_CLK 58 +#define GCC_PDM2_CLK_SRC 59 +#define GCC_PDM_AHB_CLK 60 +#define GCC_PDM_XO4_CLK 61 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 62 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 63 +#define GCC_QMIP_DISP_AHB_CLK 64 +#define GCC_QMIP_GPU_AHB_CLK 65 +#define GCC_QMIP_PCIE_AHB_CLK 66 +#define GCC_QMIP_VIDEO_CV_CPU_AHB_CLK 67 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 68 +#define GCC_QMIP_VIDEO_V_CPU_AHB_CLK 69 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 70 +#define GCC_QUPV3_I2C_CORE_CLK 71 +#define GCC_QUPV3_I2C_S0_CLK 72 +#define GCC_QUPV3_I2C_S0_CLK_SRC 73 +#define GCC_QUPV3_I2C_S1_CLK 74 +#define GCC_QUPV3_I2C_S1_CLK_SRC 75 +#define GCC_QUPV3_I2C_S2_CLK 76 +#define GCC_QUPV3_I2C_S2_CLK_SRC 77 +#define GCC_QUPV3_I2C_S3_CLK 78 +#define GCC_QUPV3_I2C_S3_CLK_SRC 79 +#define GCC_QUPV3_I2C_S4_CLK 80 +#define GCC_QUPV3_I2C_S4_CLK_SRC 81 +#define GCC_QUPV3_I2C_S5_CLK 82 +#define GCC_QUPV3_I2C_S5_CLK_SRC 83 +#define GCC_QUPV3_I2C_S6_CLK 84 +#define GCC_QUPV3_I2C_S6_CLK_SRC 85 +#define GCC_QUPV3_I2C_S7_CLK 86 +#define GCC_QUPV3_I2C_S7_CLK_SRC 87 +#define GCC_QUPV3_I2C_S8_CLK 88 +#define GCC_QUPV3_I2C_S8_CLK_SRC 89 +#define GCC_QUPV3_I2C_S9_CLK 90 +#define GCC_QUPV3_I2C_S9_CLK_SRC 91 +#define GCC_QUPV3_I2C_S_AHB_CLK 92 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 93 +#define GCC_QUPV3_WRAP1_CORE_CLK 94 +#define GCC_QUPV3_WRAP1_QSPI_REF_CLK 95 +#define GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC 96 +#define GCC_QUPV3_WRAP1_S0_CLK 97 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 98 +#define GCC_QUPV3_WRAP1_S1_CLK 99 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 100 +#define GCC_QUPV3_WRAP1_S2_CLK 101 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 102 +#define GCC_QUPV3_WRAP1_S3_CLK 103 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 104 +#define GCC_QUPV3_WRAP1_S4_CLK 105 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 106 +#define GCC_QUPV3_WRAP1_S5_CLK 107 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 108 +#define GCC_QUPV3_WRAP1_S6_CLK 109 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 110 +#define GCC_QUPV3_WRAP1_S7_CLK 111 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 112 +#define GCC_QUPV3_WRAP2_CORE_2X_CLK 113 +#define GCC_QUPV3_WRAP2_CORE_CLK 114 +#define GCC_QUPV3_WRAP2_IBI_CTRL_0_CLK_SRC 115 +#define GCC_QUPV3_WRAP2_IBI_CTRL_2_CLK 116 +#define GCC_QUPV3_WRAP2_IBI_CTRL_3_CLK 117 +#define GCC_QUPV3_WRAP2_S0_CLK 118 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 119 +#define GCC_QUPV3_WRAP2_S1_CLK 120 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 121 +#define GCC_QUPV3_WRAP2_S2_CLK 122 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 123 +#define GCC_QUPV3_WRAP2_S3_CLK 124 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 125 +#define GCC_QUPV3_WRAP2_S4_CLK 126 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 127 +#define GCC_QUPV3_WRAP2_S5_CLK 128 +#define GCC_QUPV3_WRAP2_S5_CLK_SRC 129 +#define GCC_QUPV3_WRAP2_S6_CLK 130 +#define GCC_QUPV3_WRAP2_S6_CLK_SRC 131 +#define GCC_QUPV3_WRAP2_S7_CLK 132 +#define GCC_QUPV3_WRAP2_S7_CLK_SRC 133 +#define GCC_QUPV3_WRAP3_CORE_2X_CLK 134 +#define GCC_QUPV3_WRAP3_CORE_CLK 135 +#define GCC_QUPV3_WRAP3_QSPI_REF_CLK 136 +#define GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC 137 +#define GCC_QUPV3_WRAP3_S0_CLK 138 +#define GCC_QUPV3_WRAP3_S0_CLK_SRC 139 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 140 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 141 +#define GCC_QUPV3_WRAP_2_IBI_2_AHB_CLK 142 +#define GCC_QUPV3_WRAP_2_IBI_3_AHB_CLK 143 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 144 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 145 +#define GCC_QUPV3_WRAP_3_M_AHB_CLK 146 +#define GCC_QUPV3_WRAP_3_S_AHB_CLK 147 +#define GCC_SDCC2_AHB_CLK 148 +#define GCC_SDCC2_APPS_CLK 149 +#define GCC_SDCC2_APPS_CLK_SRC 150 +#define GCC_SDCC4_AHB_CLK 151 +#define GCC_SDCC4_APPS_CLK 152 +#define GCC_SDCC4_APPS_CLK_SRC 153 +#define GCC_UFS_PHY_AHB_CLK 154 +#define GCC_UFS_PHY_AXI_CLK 155 +#define GCC_UFS_PHY_AXI_CLK_SRC 156 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 157 +#define GCC_UFS_PHY_ICE_CORE_CLK 158 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 159 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 160 +#define GCC_UFS_PHY_PHY_AUX_CLK 161 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 162 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 163 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 164 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC 165 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 166 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC 167 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 168 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC 169 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 170 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 171 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 172 +#define GCC_USB30_PRIM_MASTER_CLK 173 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 174 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 175 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 176 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 177 +#define GCC_USB30_PRIM_SLEEP_CLK 178 +#define GCC_USB3_PRIM_PHY_AUX_CLK 179 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 180 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 181 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 182 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 183 +#define GCC_VIDEO_AHB_CLK 184 +#define GCC_VIDEO_AXI0_CLK 185 +#define GCC_VIDEO_AXI1_CLK 186 +#define GCC_VIDEO_XO_CLK 187 +#define GCC_GPLL0_AO 188 +#define GCC_GPLL0_OUT_EVEN_AO 189 +#define GCC_GPLL1_AO 190 +#define GCC_GPLL3_AO 191 +#define GCC_GPLL4_AO 192 +#define GCC_GPLL6_AO 193 + +/* GCC resets */ +#define GCC_CAMERA_BCR 0 +#define GCC_DISPLAY_BCR 1 +#define GCC_GPU_BCR 2 +#define GCC_PCIE_0_BCR 3 +#define GCC_PCIE_0_LINK_DOWN_BCR 4 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 5 +#define GCC_PCIE_0_PHY_BCR 6 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 7 +#define GCC_PCIE_1_BCR 8 +#define GCC_PCIE_1_LINK_DOWN_BCR 9 +#define GCC_PCIE_1_NOCSR_COM_PHY_BCR 10 +#define GCC_PCIE_1_PHY_BCR 11 +#define GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR 12 +#define GCC_PCIE_PHY_BCR 13 +#define GCC_PCIE_PHY_CFG_AHB_BCR 14 +#define GCC_PCIE_PHY_COM_BCR 15 +#define GCC_PDM_BCR 16 +#define GCC_QUPV3_WRAPPER_1_BCR 17 +#define GCC_QUPV3_WRAPPER_2_BCR 18 +#define GCC_QUPV3_WRAPPER_3_BCR 19 +#define GCC_QUPV3_WRAPPER_I2C_BCR 20 +#define GCC_QUSB2PHY_PRIM_BCR 21 +#define GCC_QUSB2PHY_SEC_BCR 22 +#define GCC_SDCC2_BCR 23 +#define GCC_SDCC4_BCR 24 +#define GCC_UFS_PHY_BCR 25 +#define GCC_USB30_PRIM_BCR 26 +#define GCC_USB3_DP_PHY_PRIM_BCR 27 +#define GCC_USB3_DP_PHY_SEC_BCR 28 +#define GCC_USB3_PHY_PRIM_BCR 29 +#define GCC_USB3_PHY_SEC_BCR 30 +#define GCC_USB3PHY_PHY_PRIM_BCR 31 +#define GCC_USB3PHY_PHY_SEC_BCR 32 +#define GCC_VIDEO_AXI0_CLK_ARES 33 +#define GCC_VIDEO_AXI1_CLK_ARES 34 +#define GCC_VIDEO_BCR 35 + +/* GCC power domains */ +#define PCIE_0_GDSC 0 +#define PCIE_0_PHY_GDSC 1 +#define PCIE_1_GDSC 2 +#define PCIE_1_PHY_GDSC 3 +#define UFS_PHY_GDSC 4 +#define UFS_MEM_PHY_GDSC 5 +#define USB30_PRIM_GDSC 6 +#define USB3_PHY_GDSC 7 + +#endif From c1120359d4c2a1050e6a5bddd47ee1887bb0c713 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:56 +0100 Subject: [PATCH 3095/7721] dt-bindings: clock: qcom: document the SM8650 Display Clock Controller Add bindings documentation for the SM8650 Display Clock Controller. Reviewed-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-3-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8650-dispcc.yaml | 106 ++++++++++++++++++ .../dt-bindings/clock/qcom,sm8650-dispcc.h | 102 +++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8650-dispcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml new file mode 100644 index 000000000000..5e0c45c380f5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8650-dispcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display Clock & Reset Controller for SM8650 + +maintainers: + - Bjorn Andersson + - Neil Armstrong + +description: | + Qualcomm display clock control module provides the clocks, resets and power + domains on SM8650. + + See also:: include/dt-bindings/clock/qcom,sm8650-dispcc.h + +properties: + compatible: + enum: + - qcom,sm8650-dispcc + + clocks: + items: + - description: Board XO source + - description: Board Always On XO source + - description: Display's AHB clock + - description: sleep clock + - description: Byte clock from DSI PHY0 + - description: Pixel clock from DSI PHY0 + - description: Byte clock from DSI PHY1 + - description: Pixel clock from DSI PHY1 + - description: Link clock from DP PHY0 + - description: VCO DIV clock from DP PHY0 + - description: Link clock from DP PHY1 + - description: VCO DIV clock from DP PHY1 + - description: Link clock from DP PHY2 + - description: VCO DIV clock from DP PHY2 + - description: Link clock from DP PHY3 + - description: VCO DIV clock from DP PHY3 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + + power-domains: + description: + A phandle and PM domain specifier for the MMCX power domain. + maxItems: 1 + + required-opps: + description: + A phandle to an OPP node describing required MMCX performance point. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + clock-controller@af00000 { + compatible = "qcom,sm8650-dispcc"; + reg = <0x0af00000 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&gcc GCC_DISP_AHB_CLK>, + <&sleep_clk>, + <&dsi0_phy 0>, + <&dsi0_phy 1>, + <&dsi1_phy 0>, + <&dsi1_phy 1>, + <&dp0_phy 0>, + <&dp0_phy 1>, + <&dp1_phy 0>, + <&dp1_phy 1>, + <&dp2_phy 0>, + <&dp2_phy 1>, + <&dp3_phy 0>, + <&dp3_phy 1>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + }; +... diff --git a/include/dt-bindings/clock/qcom,sm8650-dispcc.h b/include/dt-bindings/clock/qcom,sm8650-dispcc.h new file mode 100644 index 000000000000..b0a668b395a5 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8650-dispcc.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Ltd. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_SM8650_DISP_CC_H +#define _DT_BINDINGS_CLK_QCOM_SM8650_DISP_CC_H + +/* DISP_CC clocks */ +#define DISP_CC_MDSS_ACCU_CLK 0 +#define DISP_CC_MDSS_AHB1_CLK 1 +#define DISP_CC_MDSS_AHB_CLK 2 +#define DISP_CC_MDSS_AHB_CLK_SRC 3 +#define DISP_CC_MDSS_BYTE0_CLK 4 +#define DISP_CC_MDSS_BYTE0_CLK_SRC 5 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 6 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 7 +#define DISP_CC_MDSS_BYTE1_CLK 8 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 9 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 10 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 11 +#define DISP_CC_MDSS_DPTX0_AUX_CLK 12 +#define DISP_CC_MDSS_DPTX0_AUX_CLK_SRC 13 +#define DISP_CC_MDSS_DPTX0_CRYPTO_CLK 14 +#define DISP_CC_MDSS_DPTX0_LINK_CLK 15 +#define DISP_CC_MDSS_DPTX0_LINK_CLK_SRC 16 +#define DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC 17 +#define DISP_CC_MDSS_DPTX0_LINK_INTF_CLK 18 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK 19 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC 20 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK 21 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC 22 +#define DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK 23 +#define DISP_CC_MDSS_DPTX1_AUX_CLK 24 +#define DISP_CC_MDSS_DPTX1_AUX_CLK_SRC 25 +#define DISP_CC_MDSS_DPTX1_CRYPTO_CLK 26 +#define DISP_CC_MDSS_DPTX1_LINK_CLK 27 +#define DISP_CC_MDSS_DPTX1_LINK_CLK_SRC 28 +#define DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC 29 +#define DISP_CC_MDSS_DPTX1_LINK_INTF_CLK 30 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK 31 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC 32 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK 33 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC 34 +#define DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK 35 +#define DISP_CC_MDSS_DPTX2_AUX_CLK 36 +#define DISP_CC_MDSS_DPTX2_AUX_CLK_SRC 37 +#define DISP_CC_MDSS_DPTX2_CRYPTO_CLK 38 +#define DISP_CC_MDSS_DPTX2_LINK_CLK 39 +#define DISP_CC_MDSS_DPTX2_LINK_CLK_SRC 40 +#define DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC 41 +#define DISP_CC_MDSS_DPTX2_LINK_INTF_CLK 42 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK 43 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC 44 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK 45 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC 46 +#define DISP_CC_MDSS_DPTX3_AUX_CLK 47 +#define DISP_CC_MDSS_DPTX3_AUX_CLK_SRC 48 +#define DISP_CC_MDSS_DPTX3_CRYPTO_CLK 49 +#define DISP_CC_MDSS_DPTX3_LINK_CLK 50 +#define DISP_CC_MDSS_DPTX3_LINK_CLK_SRC 51 +#define DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC 52 +#define DISP_CC_MDSS_DPTX3_LINK_INTF_CLK 53 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK 54 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC 55 +#define DISP_CC_MDSS_ESC0_CLK 56 +#define DISP_CC_MDSS_ESC0_CLK_SRC 57 +#define DISP_CC_MDSS_ESC1_CLK 58 +#define DISP_CC_MDSS_ESC1_CLK_SRC 59 +#define DISP_CC_MDSS_MDP1_CLK 60 +#define DISP_CC_MDSS_MDP_CLK 61 +#define DISP_CC_MDSS_MDP_CLK_SRC 62 +#define DISP_CC_MDSS_MDP_LUT1_CLK 63 +#define DISP_CC_MDSS_MDP_LUT_CLK 64 +#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 65 +#define DISP_CC_MDSS_PCLK0_CLK 66 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 67 +#define DISP_CC_MDSS_PCLK1_CLK 68 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 69 +#define DISP_CC_MDSS_RSCC_AHB_CLK 70 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 71 +#define DISP_CC_MDSS_VSYNC1_CLK 72 +#define DISP_CC_MDSS_VSYNC_CLK 73 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 74 +#define DISP_CC_PLL0 75 +#define DISP_CC_PLL1 76 +#define DISP_CC_SLEEP_CLK 77 +#define DISP_CC_SLEEP_CLK_SRC 78 +#define DISP_CC_XO_CLK 79 +#define DISP_CC_XO_CLK_SRC 80 + +/* DISP_CC resets */ +#define DISP_CC_MDSS_CORE_BCR 0 +#define DISP_CC_MDSS_CORE_INT2_BCR 1 +#define DISP_CC_MDSS_RSCC_BCR 2 + +/* DISP_CC GDSCR */ +#define MDSS_GDSC 0 +#define MDSS_INT2_GDSC 1 + +#endif From a0aa7fa5c3f0e74e684c667e26824fe1e28f5c27 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:57 +0100 Subject: [PATCH 3096/7721] dt-bindings: clock: qcom: document the SM8650 GPU Clock Controller Add bindings documentation for the SM8650 Graphics Clock Controller. Reviewed-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-4-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8450-gpucc.yaml | 2 + include/dt-bindings/clock/qcom,sm8650-gpucc.h | 43 +++++++++++++++++++ include/dt-bindings/reset/qcom,sm8650-gpucc.h | 20 +++++++++ 3 files changed, 65 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,sm8650-gpucc.h create mode 100644 include/dt-bindings/reset/qcom,sm8650-gpucc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml index 2320be920a5f..1a384e8532a5 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml @@ -17,12 +17,14 @@ description: | include/dt-bindings/clock/qcom,sm8450-gpucc.h include/dt-bindings/clock/qcom,sm8550-gpucc.h include/dt-bindings/reset/qcom,sm8450-gpucc.h + include/dt-bindings/reset/qcom,sm8650-gpucc.h properties: compatible: enum: - qcom,sm8450-gpucc - qcom,sm8550-gpucc + - qcom,sm8650-gpucc clocks: items: diff --git a/include/dt-bindings/clock/qcom,sm8650-gpucc.h b/include/dt-bindings/clock/qcom,sm8650-gpucc.h new file mode 100644 index 000000000000..d0dc457cfe75 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8650-gpucc.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8650_H +#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8650_H + +/* GPU_CC clocks */ +#define GPU_CC_AHB_CLK 0 +#define GPU_CC_CRC_AHB_CLK 1 +#define GPU_CC_CX_ACCU_SHIFT_CLK 2 +#define GPU_CC_CX_FF_CLK 3 +#define GPU_CC_CX_GMU_CLK 4 +#define GPU_CC_CXO_AON_CLK 5 +#define GPU_CC_CXO_CLK 6 +#define GPU_CC_DEMET_CLK 7 +#define GPU_CC_DPM_CLK 8 +#define GPU_CC_FF_CLK_SRC 9 +#define GPU_CC_FREQ_MEASURE_CLK 10 +#define GPU_CC_GMU_CLK_SRC 11 +#define GPU_CC_GX_ACCU_SHIFT_CLK 12 +#define GPU_CC_GX_FF_CLK 13 +#define GPU_CC_GX_GFX3D_CLK 14 +#define GPU_CC_GX_GFX3D_RDVM_CLK 15 +#define GPU_CC_GX_GMU_CLK 16 +#define GPU_CC_GX_VSENSE_CLK 17 +#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK 18 +#define GPU_CC_HUB_AON_CLK 19 +#define GPU_CC_HUB_CLK_SRC 20 +#define GPU_CC_HUB_CX_INT_CLK 21 +#define GPU_CC_HUB_DIV_CLK_SRC 22 +#define GPU_CC_MEMNOC_GFX_CLK 23 +#define GPU_CC_PLL0 24 +#define GPU_CC_PLL1 25 +#define GPU_CC_SLEEP_CLK 26 + +/* GDSCs */ +#define GPU_GX_GDSC 0 +#define GPU_CX_GDSC 1 + +#endif diff --git a/include/dt-bindings/reset/qcom,sm8650-gpucc.h b/include/dt-bindings/reset/qcom,sm8650-gpucc.h new file mode 100644 index 000000000000..f021a6cccc66 --- /dev/null +++ b/include/dt-bindings/reset/qcom,sm8650-gpucc.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DT_BINDINGS_RESET_QCOM_GPU_CC_SM8650_H +#define _DT_BINDINGS_RESET_QCOM_GPU_CC_SM8650_H + +#define GPUCC_GPU_CC_ACD_BCR 0 +#define GPUCC_GPU_CC_CX_BCR 1 +#define GPUCC_GPU_CC_FAST_HUB_BCR 2 +#define GPUCC_GPU_CC_FF_BCR 3 +#define GPUCC_GPU_CC_GFX3D_AON_BCR 4 +#define GPUCC_GPU_CC_GMU_BCR 5 +#define GPUCC_GPU_CC_GX_BCR 6 +#define GPUCC_GPU_CC_XO_BCR 7 +#define GPUCC_GPU_CC_GX_ACD_IROOT_BCR 8 + +#endif From 873f22440338d84ad911c4b8373afc3d8d413587 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:58 +0100 Subject: [PATCH 3097/7721] dt-bindings: clock: qcom: Document the SM8650 RPMH Clock Controller Add bindings documentation for the SM8650 RPMH Clock Controller. Acked-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-5-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index 4eb5e59f6772..9be952a5a227 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -35,6 +35,7 @@ properties: - qcom,sm8350-rpmh-clk - qcom,sm8450-rpmh-clk - qcom,sm8550-rpmh-clk + - qcom,sm8650-rpmh-clk clocks: maxItems: 1 From c58225b7e3d702e62e0e0ac1ad2c59248c60c008 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:25:59 +0100 Subject: [PATCH 3098/7721] clk: qcom: add the SM8650 Global Clock Controller driver, part 1 Add Global Clock Controller (GCC) tables for the SM8650 platform, the driver plumbing will be added afterwards. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-6-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-sm8650.c | 3514 +++++++++++++++++++++++++++++++++ 1 file changed, 3514 insertions(+) create mode 100644 drivers/clk/qcom/gcc-sm8650.c diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c new file mode 100644 index 000000000000..fb58f835d678 --- /dev/null +++ b/drivers/clk/qcom/gcc-sm8650.c @@ -0,0 +1,3514 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + + DT_PCIE_0_PIPE, + DT_PCIE_1_PIPE, + DT_PCIE_1_PHY_AUX, + + DT_UFS_PHY_RX_SYMBOL_0, + DT_UFS_PHY_RX_SYMBOL_1, + DT_UFS_PHY_TX_SYMBOL_0, + + DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL3_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL6_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_PCIE_0_PIPE_CLK, + P_PCIE_1_PHY_AUX_CLK, + P_PCIE_1_PIPE_CLK, + P_SLEEP_CLK, + P_UFS_PHY_RX_SYMBOL_0_CLK, + P_UFS_PHY_RX_SYMBOL_1_CLK, + P_UFS_PHY_TX_SYMBOL_0_CLK, + P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll0_ao = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even_ao = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even_ao", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_ao.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll1_ao = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll3 = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll3", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll3_ao = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll3_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4_ao = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll6 = { + .offset = 0x6000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll6", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll6_ao = { + .offset = 0x6000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll6_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_PCIE_1_PHY_AUX_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_PCIE_1_PHY_AUX }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_0 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_13[] = { + { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_13[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_1 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_14[] = { + { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_14[] = { + { .index = DT_UFS_PHY_TX_SYMBOL_0 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_15[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_15[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x6b070, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_0_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_pcie_1_phy_aux_clk_src = { + .reg = 0x8d094, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_8, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = { + .reg = 0x8d078, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_1_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x77064, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_12, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x770e0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_13, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = gcc_parent_data_13, + .num_parents = ARRAY_SIZE(gcc_parent_data_13), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x77054, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_14, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = gcc_parent_data_14, + .num_parents = ARRAY_SIZE(gcc_parent_data_14), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x3906c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_15, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_15, + .num_parents = ARRAY_SIZE(gcc_parent_data_15), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x6b074, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0x6b058, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x8d07c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x8d060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = { + .cmd_rcgr = 0x17008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = { + .cmd_rcgr = 0x17024, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = { + .cmd_rcgr = 0x17040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = { + .cmd_rcgr = 0x1705c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = { + .cmd_rcgr = 0x17078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s5_clk_src = { + .cmd_rcgr = 0x17094, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s6_clk_src = { + .cmd_rcgr = 0x170b0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s7_clk_src = { + .cmd_rcgr = 0x170cc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s8_clk_src = { + .cmd_rcgr = 0x170e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s8_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s9_clk_src = { + .cmd_rcgr = 0x17104, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s9_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src[] = { + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_ref_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_ref_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_ref_clk_src = { + .cmd_rcgr = 0x188a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_ref_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x18290, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x183c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x18770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src[] = { + F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_ibi_ctrl_0_clk_src = { + .cmd_rcgr = 0x1e9d4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_0_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { + .name = "gcc_qupv3_wrap2_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = { + .name = "gcc_qupv3_wrap2_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e280, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = { + .name = "gcc_qupv3_wrap2_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3b8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { + .name = "gcc_qupv3_wrap2_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e4f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = { + .name = "gcc_qupv3_wrap2_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0x1e628, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap2_s6_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(128000000, P_GCC_GPLL0_OUT_MAIN, 1, 16, 75), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = { + .name = "gcc_qupv3_wrap2_s6_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { + .cmd_rcgr = 0x1e760, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_qupv3_wrap2_s6_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { + .name = "gcc_qupv3_wrap2_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { + .cmd_rcgr = 0x1e898, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src[] = { + F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0), + F(400000000, P_GCC_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap3_qspi_ref_clk_src_init = { + .name = "gcc_qupv3_wrap3_qspi_ref_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_qspi_ref_clk_src = { + .cmd_rcgr = 0x19018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_qspi_ref_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x14018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x16018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77030, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770b4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x3902c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x39044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x39070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = { + .reg = 0x18280, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap3_s0_clk_src = { + .reg = 0x19010, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x3905c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_axi_clk = { + .halt_reg = 0x10064, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x3908c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3908c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3908c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0x26010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0x2601c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2601c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2601c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x10050, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10050, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x39088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_sf_axi_clk = { + .halt_reg = 0x10058, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10058, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x71154, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x71154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71154, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_pcie_sf_qtb_clk = { + .halt_reg = 0x10074, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_pcie_sf_qtb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2700c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2700c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x6b03c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x6b038, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x6b02c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x6b02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0x6b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x6b048, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x6b020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x8d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0x8d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0x8d028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x8d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_aux_clk = { + .halt_reg = 0x8d044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_rchng_clk = { + .halt_reg = 0x8d05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x8d050, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0x8d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_ahb_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_ahb_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x32008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_core_clk = { + .halt_reg = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s0_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s1_clk = { + .halt_reg = 0x17020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s2_clk = { + .halt_reg = 0x1703c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s3_clk = { + .halt_reg = 0x17058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s4_clk = { + .halt_reg = 0x17074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s5_clk = { + .halt_reg = 0x17090, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s6_clk = { + .halt_reg = 0x170ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s7_clk = { + .halt_reg = 0x170c8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s8_clk = { + .halt_reg = 0x170e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s8_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s8_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s9_clk = { + .halt_reg = 0x17100, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s9_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s9_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s_ahb_clk = { + .halt_reg = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x23154, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x23144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_ref_clk = { + .halt_reg = 0x1889c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x1813c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x18274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x18284, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x183bc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0x184f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s6_clk = { + .halt_reg = 0x1862c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s7_clk = { + .halt_reg = 0x18764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = { + .halt_reg = 0x232a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_clk = { + .halt_reg = 0x23294, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_ibi_ctrl_2_clk = { + .halt_reg = 0x1e9cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_ibi_ctrl_3_clk = { + .halt_reg = 0x1e9d0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9d0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s1_clk = { + .halt_reg = 0x1e13c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s2_clk = { + .halt_reg = 0x1e274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s3_clk = { + .halt_reg = 0x1e3ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s4_clk = { + .halt_reg = 0x1e4e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s5_clk = { + .halt_reg = 0x1e61c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s6_clk = { + .halt_reg = 0x1e754, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s7_clk = { + .halt_reg = 0x1e88c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = { + .halt_reg = 0x233f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_core_clk = { + .halt_reg = 0x233e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_qspi_ref_clk = { + .halt_reg = 0x19014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_qspi_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s0_clk = { + .halt_reg = 0x19004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0x2313c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2313c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x23140, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23140, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_ibi_2_ahb_clk = { + .halt_reg = 0x1e9c4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9c4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_ibi_2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_ibi_3_ahb_clk = { + .halt_reg = 0x1e9c8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9c8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_ibi_3_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0x2328c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2328c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = { + .halt_reg = 0x23290, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23290, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = { + .halt_reg = 0x233dc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233dc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = { + .halt_reg = 0x233e0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233e0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = { + .halt_reg = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { + .halt_reg = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x7702c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7702c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770cc, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x770cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77028, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = { + .halt_reg = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0x39024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x39060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0x39064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x39068, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x39068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x32018, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x32024, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc pcie_0_gdsc = { + .gdscr = 0x6b004, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(0), + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_0_phy_gdsc = { + .gdscr = 0x6c000, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(3), + .pd = { + .name = "pcie_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_1_gdsc = { + .gdscr = 0x8d004, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(1), + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_1_phy_gdsc = { + .gdscr = 0x8e000, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(4), + .pd = { + .name = "pcie_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc ufs_phy_gdsc = { + .gdscr = 0x77004, + .pd = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc ufs_mem_phy_gdsc = { + .gdscr = 0x9e000, + .pd = { + .name = "ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0x39004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc usb3_phy_gdsc = { + .gdscr = 0x50018, + .pd = { + .name = "usb3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +MODULE_DESCRIPTION("QTI GCC SM8650 Driver"); +MODULE_LICENSE("GPL"); From aa381a2bdf1dfc36468f84c8d0ceba63be25b3b3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:26:00 +0100 Subject: [PATCH 3099/7721] clk: qcom: add the SM8650 Global Clock Controller driver, part 2 Add Global Clock Controller (GCC) driver plumbing for the SM8650 platform. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-7-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sm8650.c | 335 ++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index e5f4c74addfc..5a5c54313c64 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -947,6 +947,15 @@ config SM_GCC_8550 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS, PCIe etc. +config SM_GCC_8650 + tristate "SM8650 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on SM8650 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SM_GPUCC_6115 tristate "SM6115 Graphics Clock Controller" select SM_GCC_6115 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 8209eddf040e..b98e405a245b 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -122,6 +122,7 @@ obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SM_GCC_8350) += gcc-sm8350.o obj-$(CONFIG_SM_GCC_8450) += gcc-sm8450.o obj-$(CONFIG_SM_GCC_8550) += gcc-sm8550.o +obj-$(CONFIG_SM_GCC_8650) += gcc-sm8650.o obj-$(CONFIG_SM_GPUCC_6115) += gpucc-sm6115.o obj-$(CONFIG_SM_GPUCC_6125) += gpucc-sm6125.o obj-$(CONFIG_SM_GPUCC_6350) += gpucc-sm6350.o diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c index fb58f835d678..9174dd82308c 100644 --- a/drivers/clk/qcom/gcc-sm8650.c +++ b/drivers/clk/qcom/gcc-sm8650.c @@ -3510,5 +3510,340 @@ static struct gdsc usb3_phy_gdsc = { .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; +static struct clk_regmap *gcc_sm8650_clocks[] = { + [GCC_AGGRE_NOC_PCIE_AXI_CLK] = &gcc_aggre_noc_pcie_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CNOC_PCIE_SF_AXI_CLK] = &gcc_cnoc_pcie_sf_axi_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_QTB_CLK] = &gcc_ddrss_pcie_sf_qtb_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL3] = &gcc_gpll3.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL6] = &gcc_gpll6.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, + [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PHY_AUX_CLK] = &gcc_pcie_1_phy_aux_clk.clkr, + [GCC_PCIE_1_PHY_AUX_CLK_SRC] = &gcc_pcie_1_phy_aux_clk_src.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_I2C_CORE_CLK] = &gcc_qupv3_i2c_core_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK] = &gcc_qupv3_i2c_s0_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK_SRC] = &gcc_qupv3_i2c_s0_clk_src.clkr, + [GCC_QUPV3_I2C_S1_CLK] = &gcc_qupv3_i2c_s1_clk.clkr, + [GCC_QUPV3_I2C_S1_CLK_SRC] = &gcc_qupv3_i2c_s1_clk_src.clkr, + [GCC_QUPV3_I2C_S2_CLK] = &gcc_qupv3_i2c_s2_clk.clkr, + [GCC_QUPV3_I2C_S2_CLK_SRC] = &gcc_qupv3_i2c_s2_clk_src.clkr, + [GCC_QUPV3_I2C_S3_CLK] = &gcc_qupv3_i2c_s3_clk.clkr, + [GCC_QUPV3_I2C_S3_CLK_SRC] = &gcc_qupv3_i2c_s3_clk_src.clkr, + [GCC_QUPV3_I2C_S4_CLK] = &gcc_qupv3_i2c_s4_clk.clkr, + [GCC_QUPV3_I2C_S4_CLK_SRC] = &gcc_qupv3_i2c_s4_clk_src.clkr, + [GCC_QUPV3_I2C_S5_CLK] = &gcc_qupv3_i2c_s5_clk.clkr, + [GCC_QUPV3_I2C_S5_CLK_SRC] = &gcc_qupv3_i2c_s5_clk_src.clkr, + [GCC_QUPV3_I2C_S6_CLK] = &gcc_qupv3_i2c_s6_clk.clkr, + [GCC_QUPV3_I2C_S6_CLK_SRC] = &gcc_qupv3_i2c_s6_clk_src.clkr, + [GCC_QUPV3_I2C_S7_CLK] = &gcc_qupv3_i2c_s7_clk.clkr, + [GCC_QUPV3_I2C_S7_CLK_SRC] = &gcc_qupv3_i2c_s7_clk_src.clkr, + [GCC_QUPV3_I2C_S8_CLK] = &gcc_qupv3_i2c_s8_clk.clkr, + [GCC_QUPV3_I2C_S8_CLK_SRC] = &gcc_qupv3_i2c_s8_clk_src.clkr, + [GCC_QUPV3_I2C_S9_CLK] = &gcc_qupv3_i2c_s9_clk.clkr, + [GCC_QUPV3_I2C_S9_CLK_SRC] = &gcc_qupv3_i2c_s9_clk_src.clkr, + [GCC_QUPV3_I2C_S_AHB_CLK] = &gcc_qupv3_i2c_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_REF_CLK] = &gcc_qupv3_wrap1_qspi_ref_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr, + [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr, + [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr, + [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr, + [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr, + [GCC_QUPV3_WRAP2_IBI_CTRL_0_CLK_SRC] = &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr, + [GCC_QUPV3_WRAP2_IBI_CTRL_2_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_2_clk.clkr, + [GCC_QUPV3_WRAP2_IBI_CTRL_3_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_3_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr, + [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr, + [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr, + [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr, + [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr, + [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr, + [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr, + [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr, + [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr, + [GCC_QUPV3_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr, + [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_clk_src.clkr, + [GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr, + [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr, + [GCC_QUPV3_WRAP3_QSPI_REF_CLK] = &gcc_qupv3_wrap3_qspi_ref_clk.clkr, + [GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr, + [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr, + [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_IBI_2_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_2_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_IBI_3_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_3_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_s_ahb_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, + [GCC_GPLL0_AO] = &gcc_gpll0_ao.clkr, + [GCC_GPLL0_OUT_EVEN_AO] = &gcc_gpll0_out_even_ao.clkr, + [GCC_GPLL1_AO] = &gcc_gpll1_ao.clkr, + [GCC_GPLL3_AO] = &gcc_gpll3_ao.clkr, + [GCC_GPLL4_AO] = &gcc_gpll4_ao.clkr, + [GCC_GPLL6_AO] = &gcc_gpll6_ao.clkr, +}; + +static const struct qcom_reset_map gcc_sm8650_resets[] = { + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUPV3_WRAPPER_3_BCR] = { 0x19000 }, + [GCC_QUPV3_WRAPPER_I2C_BCR] = { 0x17000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x32018, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32024, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_ref_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_qspi_ref_clk_src), +}; + +static struct gdsc *gcc_sm8650_gdscs[] = { + [PCIE_0_GDSC] = &pcie_0_gdsc, + [PCIE_0_PHY_GDSC] = &pcie_0_phy_gdsc, + [PCIE_1_GDSC] = &pcie_1_gdsc, + [PCIE_1_PHY_GDSC] = &pcie_1_phy_gdsc, + [UFS_PHY_GDSC] = &ufs_phy_gdsc, + [UFS_MEM_PHY_GDSC] = &ufs_mem_phy_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB3_PHY_GDSC] = &usb3_phy_gdsc, +}; + +static const struct regmap_config gcc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sm8650_desc = { + .config = &gcc_sm8650_regmap_config, + .clks = gcc_sm8650_clocks, + .num_clks = ARRAY_SIZE(gcc_sm8650_clocks), + .resets = gcc_sm8650_resets, + .num_resets = ARRAY_SIZE(gcc_sm8650_resets), + .gdscs = gcc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm8650_gdscs), +}; + +static const struct of_device_id gcc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sm8650_match_table); + +static int gcc_sm8650_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sm8650_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + /* Keep the critical clock always-On */ + regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */ + regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */ + regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */ + regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */ + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */ + regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */ + regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */ + + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52150, 0x0); + + return qcom_cc_really_probe(pdev, &gcc_sm8650_desc, regmap); +} + +static struct platform_driver gcc_sm8650_driver = { + .probe = gcc_sm8650_probe, + .driver = { + .name = "gcc-sm8650", + .of_match_table = gcc_sm8650_match_table, + }, +}; + +static int __init gcc_sm8650_init(void) +{ + return platform_driver_register(&gcc_sm8650_driver); +} +subsys_initcall(gcc_sm8650_init); + +static void __exit gcc_sm8650_exit(void) +{ + platform_driver_unregister(&gcc_sm8650_driver); +} +module_exit(gcc_sm8650_exit); + MODULE_DESCRIPTION("QTI GCC SM8650 Driver"); MODULE_LICENSE("GPL"); From e3388328e47c45cc91fe74b334694fa455c1c935 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:26:01 +0100 Subject: [PATCH 3100/7721] clk: qcom: add the SM8650 TCSR Clock Controller driver Add TCSR Clock Controller support for SM8650 platform. Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-8-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/tcsrcc-sm8650.c | 182 +++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 drivers/clk/qcom/tcsrcc-sm8650.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 5a5c54313c64..05c5629f356e 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -1045,6 +1045,14 @@ config SM_TCSRCC_8550 Support for the TCSR clock controller on SM8550 devices. Say Y if you want to use peripheral devices such as SD/UFS. +config SM_TCSRCC_8650 + tristate "SM8650 TCSR Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the TCSR clock controller on SM8650 devices. + Say Y if you want to use peripheral devices such as SD/UFS. + config SM_VIDEOCC_8150 tristate "SM8150 Video Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b98e405a245b..886b20cdba6e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -133,6 +133,7 @@ obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o obj-$(CONFIG_SM_GPUCC_8450) += gpucc-sm8450.o obj-$(CONFIG_SM_GPUCC_8550) += gpucc-sm8550.o obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o +obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o obj-$(CONFIG_SM_VIDEOCC_8350) += videocc-sm8350.o diff --git a/drivers/clk/qcom/tcsrcc-sm8650.c b/drivers/clk/qcom/tcsrcc-sm8650.c new file mode 100644 index 000000000000..11c7d6df48c7 --- /dev/null +++ b/drivers/clk/qcom/tcsrcc-sm8650.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-branch.h" +#include "clk-regmap.h" +#include "common.h" +#include "reset.h" + +enum { + DT_BI_TCXO_PAD, +}; + +static struct clk_branch tcsr_pcie_0_clkref_en = { + .halt_reg = 0x31100, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31100, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_pcie_0_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_pcie_1_clkref_en = { + .halt_reg = 0x31114, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31114, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_pcie_1_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_ufs_clkref_en = { + .halt_reg = 0x31110, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31110, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_ufs_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_ufs_pad_clkref_en = { + .halt_reg = 0x31104, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31104, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_ufs_pad_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_clkref_en = { + .halt_reg = 0x31118, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31118, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_usb2_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb3_clkref_en = { + .halt_reg = 0x31108, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31108, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "tcsr_usb3_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *tcsr_cc_sm8650_clocks[] = { + [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr, + [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr, + [TCSR_UFS_CLKREF_EN] = &tcsr_ufs_clkref_en.clkr, + [TCSR_UFS_PAD_CLKREF_EN] = &tcsr_ufs_pad_clkref_en.clkr, + [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr, + [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr, +}; + +static const struct regmap_config tcsr_cc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3b000, + .fast_io = true, +}; + +static const struct qcom_cc_desc tcsr_cc_sm8650_desc = { + .config = &tcsr_cc_sm8650_regmap_config, + .clks = tcsr_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(tcsr_cc_sm8650_clocks), +}; + +static const struct of_device_id tcsr_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-tcsr" }, + { } +}; +MODULE_DEVICE_TABLE(of, tcsr_cc_sm8650_match_table); + +static int tcsr_cc_sm8650_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &tcsr_cc_sm8650_desc); +} + +static struct platform_driver tcsr_cc_sm8650_driver = { + .probe = tcsr_cc_sm8650_probe, + .driver = { + .name = "tcsr_cc-sm8650", + .of_match_table = tcsr_cc_sm8650_match_table, + }, +}; + +static int __init tcsr_cc_sm8650_init(void) +{ + return platform_driver_register(&tcsr_cc_sm8650_driver); +} +subsys_initcall(tcsr_cc_sm8650_init); + +static void __exit tcsr_cc_sm8650_exit(void) +{ + platform_driver_unregister(&tcsr_cc_sm8650_driver); +} +module_exit(tcsr_cc_sm8650_exit); + +MODULE_DESCRIPTION("QTI TCSRCC SM8650 Driver"); +MODULE_LICENSE("GPL"); From 9e939f00833844bec64f5b2db61eb77f4ebeb795 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:26:02 +0100 Subject: [PATCH 3101/7721] clk: qcom: add the SM8650 Display Clock Controller driver Add Display Clock Controller (DISPCC) support for SM8650 platform. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-9-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/dispcc-sm8650.c | 1810 ++++++++++++++++++++++++++++++ 3 files changed, 1821 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sm8650.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 05c5629f356e..ddc451e235a3 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -851,6 +851,16 @@ config SM_DISPCC_8550 Say Y if you want to support display devices and functionality such as splash screen. +config SM_DISPCC_8650 + tristate "SM8650 Display Clock Controller" + depends on ARM64 || COMPILE_TEST + select SM_GCC_8650 + help + Support for the display clock controller on Qualcomm Technologies, Inc + SM8650 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SM_GCC_4450 tristate "SM4450 Global Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 886b20cdba6e..f3816c29efcb 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_SM_DISPCC_6375) += dispcc-sm6375.o obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o obj-$(CONFIG_SM_DISPCC_8450) += dispcc-sm8450.o obj-$(CONFIG_SM_DISPCC_8550) += dispcc-sm8550.o +obj-$(CONFIG_SM_DISPCC_8650) += dispcc-sm8650.o obj-$(CONFIG_SM_GCC_4450) += gcc-sm4450.o obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o diff --git a/drivers/clk/qcom/dispcc-sm8650.c b/drivers/clk/qcom/dispcc-sm8650.c new file mode 100644 index 000000000000..6283099faf57 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sm8650.c @@ -0,0 +1,1810 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "reset.h" +#include "gdsc.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_AHB_CLK, + DT_SLEEP_CLK, + + DT_DSI0_PHY_PLL_OUT_BYTECLK, + DT_DSI0_PHY_PLL_OUT_DSICLK, + DT_DSI1_PHY_PLL_OUT_BYTECLK, + DT_DSI1_PHY_PLL_OUT_DSICLK, + + DT_DP0_PHY_PLL_LINK_CLK, + DT_DP0_PHY_PLL_VCO_DIV_CLK, + DT_DP1_PHY_PLL_LINK_CLK, + DT_DP1_PHY_PLL_VCO_DIV_CLK, + DT_DP2_PHY_PLL_LINK_CLK, + DT_DP2_PHY_PLL_VCO_DIV_CLK, + DT_DP3_PHY_PLL_LINK_CLK, + DT_DP3_PHY_PLL_VCO_DIV_CLK, +}; + +#define DISP_CC_MISC_CMD 0xF000 + +enum { + P_BI_TCXO, + P_DISP_CC_PLL0_OUT_MAIN, + P_DISP_CC_PLL1_OUT_EVEN, + P_DISP_CC_PLL1_OUT_MAIN, + P_DP0_PHY_PLL_LINK_CLK, + P_DP0_PHY_PLL_VCO_DIV_CLK, + P_DP1_PHY_PLL_LINK_CLK, + P_DP1_PHY_PLL_VCO_DIV_CLK, + P_DP2_PHY_PLL_LINK_CLK, + P_DP2_PHY_PLL_VCO_DIV_CLK, + P_DP3_PHY_PLL_LINK_CLK, + P_DP3_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_SLEEP_CLK, +}; + +static struct pll_vco lucid_ole_vco[] = { + { 249600000, 2100000000, 0 }, +}; + +static const struct alpha_pll_config disp_cc_pll0_config = { + .l = 0xd, + .alpha = 0x6492, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_reset_lucid_ole_ops, + }, + }, +}; + +static const struct alpha_pll_config disp_cc_pll1_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll disp_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_reset_lucid_ole_ops, + }, + }, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct clk_parent_data disp_cc_parent_data_0_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + +static const struct parent_map disp_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, + { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 3 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DP1_PHY_PLL_LINK_CLK, 2 }, + { P_DP2_PHY_PLL_LINK_CLK, 3 }, + { P_DP3_PHY_PLL_LINK_CLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP1_PHY_PLL_LINK_CLK }, + { .index = DT_DP2_PHY_PLL_LINK_CLK }, + { .index = DT_DP3_PHY_PLL_LINK_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, + { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &disp_cc_pll1.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP1_PHY_PLL_LINK_CLK, 2 }, + { P_DP2_PHY_PLL_LINK_CLK, 3 }, + { P_DP3_PHY_PLL_LINK_CLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP1_PHY_PLL_LINK_CLK }, + { .index = DT_DP2_PHY_PLL_LINK_CLK }, + { .index = DT_DP3_PHY_PLL_LINK_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &disp_cc_pll0.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_parent_map_9[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_9[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0), + F(75000000, P_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x82e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_6, + .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_byte0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x8124, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + .cmd_rcgr = 0x81bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_aux_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = { + F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), + F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), + F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), + F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x8170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_7, + .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_7, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_pixel0_clk_src = { + .cmd_rcgr = 0x818c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_pixel1_clk_src = { + .cmd_rcgr = 0x81a4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .cmd_rcgr = 0x8220, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_aux_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .cmd_rcgr = 0x8204, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_pixel0_clk_src = { + .cmd_rcgr = 0x81d4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel0_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, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_pixel1_clk_src = { + .cmd_rcgr = 0x81ec, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel1_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, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_aux_clk_src = { + .cmd_rcgr = 0x8284, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_aux_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .cmd_rcgr = 0x8238, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_pixel0_clk_src = { + .cmd_rcgr = 0x8254, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel0_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, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_pixel1_clk_src = { + .cmd_rcgr = 0x826c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel1_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, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_aux_clk_src = { + .cmd_rcgr = 0x82d0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_aux_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .cmd_rcgr = 0x82b4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_pixel0_clk_src = { + .cmd_rcgr = 0x829c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_pixel0_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, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x8140, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc0_clk_src", + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x8158, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc1_clk_src", + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(100000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(150000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(200000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(325000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(402000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(514000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x80d8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_8, + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_clk_src", + .parent_data = disp_cc_parent_data_8, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x80a8, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x80c0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x80f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_sleep_clk_src = { + .cmd_rcgr = 0xe05c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_9, + .freq_tbl = ftbl_disp_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_sleep_clk_src", + .parent_data = disp_cc_parent_data_9, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_xo_clk_src = { + .cmd_rcgr = 0xe03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_xo_clk_src", + .parent_data = disp_cc_parent_data_0_ao, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x8120, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x813c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx0_link_div_clk_src = { + .reg = 0x8188, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx1_link_div_clk_src = { + .reg = 0x821c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx2_link_div_clk_src = { + .reg = 0x8250, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx3_link_div_clk_src = { + .reg = 0x82cc, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch disp_cc_mdss_accu_clk = { + .halt_reg = 0xe058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xe058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_accu_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb1_clk = { + .halt_reg = 0xa020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb_clk = { + .halt_reg = 0x80a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_clk = { + .halt_reg = 0x8028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x802c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x802c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_clk = { + .halt_reg = 0x8030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_aux_clk = { + .halt_reg = 0x8058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_crypto_clk = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_link_clk = { + .halt_reg = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_link_intf_clk = { + .halt_reg = 0x8048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_pixel0_clk = { + .halt_reg = 0x8050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_pixel1_clk = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_usb_router_link_intf_clk = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_aux_clk = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_crypto_clk = { + .halt_reg = 0x8070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_link_clk = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_link_intf_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_pixel0_clk = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_pixel1_clk = { + .halt_reg = 0x8060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_usb_router_link_intf_clk = { + .halt_reg = 0x8068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_aux_clk = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_crypto_clk = { + .halt_reg = 0x8088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_link_clk = { + .halt_reg = 0x8080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_link_intf_clk = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_pixel0_clk = { + .halt_reg = 0x8078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_pixel1_clk = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_aux_clk = { + .halt_reg = 0x809c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x809c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_crypto_clk = { + .halt_reg = 0x80a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_link_clk = { + .halt_reg = 0x8094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_link_intf_clk = { + .halt_reg = 0x8098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8098, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_pixel0_clk = { + .halt_reg = 0x8090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc0_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc1_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp1_clk = { + .halt_reg = 0xa004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_clk = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut1_clk = { + .halt_reg = 0xa010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_lut1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x8018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_lut_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0xc004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xc004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_non_gdsc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x8008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0xc00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_rscc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0xc008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_rscc_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync1_clk = { + .halt_reg = 0xa01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync_clk = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_sleep_clk = { + .halt_reg = 0xe074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_sleep_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x9000, + .pd = { + .name = "mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL | RETAIN_FF_ENABLE, +}; + +static struct gdsc mdss_int2_gdsc = { + .gdscr = 0xb000, + .pd = { + .name = "mdss_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *disp_cc_sm8650_clocks[] = { + [DISP_CC_MDSS_ACCU_CLK] = &disp_cc_mdss_accu_clk.clkr, + [DISP_CC_MDSS_AHB1_CLK] = &disp_cc_mdss_ahb1_clk.clkr, + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, + [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, + [DISP_CC_MDSS_DPTX0_AUX_CLK] = &disp_cc_mdss_dptx0_aux_clk.clkr, + [DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &disp_cc_mdss_dptx0_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_CRYPTO_CLK] = &disp_cc_mdss_dptx0_crypto_clk.clkr, + [DISP_CC_MDSS_DPTX0_LINK_CLK] = &disp_cc_mdss_dptx0_link_clk.clkr, + [DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &disp_cc_mdss_dptx0_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx0_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &disp_cc_mdss_dptx0_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &disp_cc_mdss_dptx0_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx0_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &disp_cc_mdss_dptx0_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx0_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] = + &disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX1_AUX_CLK] = &disp_cc_mdss_dptx1_aux_clk.clkr, + [DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &disp_cc_mdss_dptx1_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_CRYPTO_CLK] = &disp_cc_mdss_dptx1_crypto_clk.clkr, + [DISP_CC_MDSS_DPTX1_LINK_CLK] = &disp_cc_mdss_dptx1_link_clk.clkr, + [DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &disp_cc_mdss_dptx1_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx1_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &disp_cc_mdss_dptx1_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &disp_cc_mdss_dptx1_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx1_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &disp_cc_mdss_dptx1_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx1_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] = + &disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX2_AUX_CLK] = &disp_cc_mdss_dptx2_aux_clk.clkr, + [DISP_CC_MDSS_DPTX2_AUX_CLK_SRC] = &disp_cc_mdss_dptx2_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_CRYPTO_CLK] = &disp_cc_mdss_dptx2_crypto_clk.clkr, + [DISP_CC_MDSS_DPTX2_LINK_CLK] = &disp_cc_mdss_dptx2_link_clk.clkr, + [DISP_CC_MDSS_DPTX2_LINK_CLK_SRC] = &disp_cc_mdss_dptx2_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx2_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_INTF_CLK] = &disp_cc_mdss_dptx2_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL0_CLK] = &disp_cc_mdss_dptx2_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx2_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL1_CLK] = &disp_cc_mdss_dptx2_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx2_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_AUX_CLK] = &disp_cc_mdss_dptx3_aux_clk.clkr, + [DISP_CC_MDSS_DPTX3_AUX_CLK_SRC] = &disp_cc_mdss_dptx3_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_CRYPTO_CLK] = &disp_cc_mdss_dptx3_crypto_clk.clkr, + [DISP_CC_MDSS_DPTX3_LINK_CLK] = &disp_cc_mdss_dptx3_link_clk.clkr, + [DISP_CC_MDSS_DPTX3_LINK_CLK_SRC] = &disp_cc_mdss_dptx3_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx3_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_INTF_CLK] = &disp_cc_mdss_dptx3_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX3_PIXEL0_CLK] = &disp_cc_mdss_dptx3_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx3_pixel0_clk_src.clkr, + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, + [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, + [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr, + [DISP_CC_MDSS_MDP1_CLK] = &disp_cc_mdss_mdp1_clk.clkr, + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, + [DISP_CC_MDSS_MDP_LUT1_CLK] = &disp_cc_mdss_mdp_lut1_clk.clkr, + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, + [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, + [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, + [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, + [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC1_CLK] = &disp_cc_mdss_vsync1_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, + [DISP_CC_PLL1] = &disp_cc_pll1.clkr, + [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr, + [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr, + [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr, +}; + +static const struct qcom_reset_map disp_cc_sm8650_resets[] = { + [DISP_CC_MDSS_CORE_BCR] = { 0x8000 }, + [DISP_CC_MDSS_CORE_INT2_BCR] = { 0xa000 }, + [DISP_CC_MDSS_RSCC_BCR] = { 0xc000 }, +}; + +static struct gdsc *disp_cc_sm8650_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + [MDSS_INT2_GDSC] = &mdss_int2_gdsc, +}; + +static const struct regmap_config disp_cc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x11008, + .fast_io = true, +}; + +static struct qcom_cc_desc disp_cc_sm8650_desc = { + .config = &disp_cc_sm8650_regmap_config, + .clks = disp_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sm8650_clocks), + .resets = disp_cc_sm8650_resets, + .num_resets = ARRAY_SIZE(disp_cc_sm8650_resets), + .gdscs = disp_cc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sm8650_gdscs), +}; + +static const struct of_device_id disp_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-dispcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_sm8650_match_table); + +static int disp_cc_sm8650_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &disp_cc_sm8650_desc); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_put_rpm; + } + + clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); + + /* Enable clock gating for MDP clocks */ + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10); + + /* Keep clocks always enabled */ + regmap_update_bits(regmap, 0xe054, BIT(0), BIT(0)); /* disp_cc_xo_clk */ + + ret = qcom_cc_really_probe(pdev, &disp_cc_sm8650_desc, regmap); + if (ret) + goto err_put_rpm; + + pm_runtime_put(&pdev->dev); + + return 0; + +err_put_rpm: + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static struct platform_driver disp_cc_sm8650_driver = { + .probe = disp_cc_sm8650_probe, + .driver = { + .name = "disp_cc-sm8650", + .of_match_table = disp_cc_sm8650_match_table, + }, +}; + +static int __init disp_cc_sm8650_init(void) +{ + return platform_driver_register(&disp_cc_sm8650_driver); +} +subsys_initcall(disp_cc_sm8650_init); + +static void __exit disp_cc_sm8650_exit(void) +{ + platform_driver_unregister(&disp_cc_sm8650_driver); +} +module_exit(disp_cc_sm8650_exit); + +MODULE_DESCRIPTION("QTI DISPCC SM8650 Driver"); +MODULE_LICENSE("GPL"); From 8676fd4f3874d06cdf0c897f4f306c7b11618f6a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:26:03 +0100 Subject: [PATCH 3102/7721] clk: qcom: add the SM8650 GPU Clock Controller driver Add Graphics Clock Controller (GPUCC) support for SM8650 platform. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-10-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sm8650.c | 661 ++++++++++++++++++++++++++++++++ 3 files changed, 670 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-sm8650.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ddc451e235a3..cb4c2a726a6d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -1047,6 +1047,14 @@ config SM_GPUCC_8550 Say Y if you want to support graphics controller devices and functionality such as 3D graphics. +config SM_GPUCC_8650 + tristate "SM8650 Graphics Clock Controller" + select SM_GCC_8650 + help + Support for the graphics clock controller on SM8650 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SM_TCSRCC_8550 tristate "SM8550 TCSR Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index f3816c29efcb..72da2b9b53dc 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -133,6 +133,7 @@ obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o obj-$(CONFIG_SM_GPUCC_8450) += gpucc-sm8450.o obj-$(CONFIG_SM_GPUCC_8550) += gpucc-sm8550.o +obj-$(CONFIG_SM_GPUCC_8650) += gpucc-sm8650.o obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o diff --git a/drivers/clk/qcom/gpucc-sm8650.c b/drivers/clk/qcom/gpucc-sm8650.c new file mode 100644 index 000000000000..5ae494e17ee4 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sm8650.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GPLL0_OUT_MAIN, + DT_GPLL0_OUT_MAIN_DIV, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL1_OUT_MAIN, +}; + +static struct pll_vco lucid_ole_vco[] = { + { 249600000, 2100000000, 0 }, +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x20, + .alpha = 0x4aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x1b, + .alpha = 0x1555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_ff_clk_src = { + .cmd_rcgr = 0x9474, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_ff_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ff_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(260000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(625000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x9318, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_hub_clk_src = { + .cmd_rcgr = 0x93ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_2, + .freq_tbl = ftbl_gpu_cc_hub_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_clk_src", + .parent_data = gpu_cc_parent_data_2, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gpu_cc_hub_div_clk_src = { + .reg = 0x942c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x911c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x911c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x9120, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9120, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_accu_shift_clk = { + .halt_reg = 0x9160, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9160, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_ff_clk = { + .halt_reg = 0x914c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x914c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_ff_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x913c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x913c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x9004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x9144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9144, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_demet_clk = { + .halt_reg = 0x900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x900c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_demet_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_freq_measure_clk = { + .halt_reg = 0x9008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_freq_measure_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x90a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_rdvm_clk = { + .halt_reg = 0x90c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_rdvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x90bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x90b0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x90b0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_accu_shift_clk = { + .halt_reg = 0x90d0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x90d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_gx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_ff_clk = { + .halt_reg = 0x90c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_gx_ff_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .halt_reg = 0x7000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_aon_clk = { + .halt_reg = 0x93e8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x93e8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_aon_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_cx_int_clk = { + .halt_reg = 0x9148, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9148, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_cx_int_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .halt_reg = 0x9150, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9150, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x9134, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9134, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_dpm_clk = { + .halt_reg = 0x9164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9164, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_dpm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x9108, + .gds_hw_ctrl = 0x9168, + .clk_dis_wait_val = 8, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x905c, + .clamp_io_ctrl = 0x9504, + .resets = (unsigned int []){ GPUCC_GPU_CC_GX_BCR, + GPUCC_GPU_CC_ACD_BCR, + GPUCC_GPU_CC_GX_ACD_IROOT_BCR }, + .reset_count = 3, + .pd = { + .name = "gpu_gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | AON_RESET | SW_RESET | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *gpu_cc_sm8650_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr, + [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr, + [GPU_CC_DPM_CLK] = &gpu_cc_dpm_clk.clkr, + [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr, + [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr, + [GPU_CC_GX_FF_CLK] = &gpu_cc_gx_ff_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_RDVM_CLK] = &gpu_cc_gx_gfx3d_rdvm_clk.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, + [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr, + [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr, + [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr, + [GPU_CC_HUB_DIV_CLK_SRC] = &gpu_cc_hub_div_clk_src.clkr, + [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, +}; + +static const struct qcom_reset_map gpu_cc_sm8650_resets[] = { + [GPUCC_GPU_CC_XO_BCR] = { 0x9000 }, + [GPUCC_GPU_CC_GX_BCR] = { 0x9058 }, + [GPUCC_GPU_CC_CX_BCR] = { 0x9104 }, + [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x9198 }, + [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 }, + [GPUCC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 }, + [GPUCC_GPU_CC_FF_BCR] = { 0x9470 }, + [GPUCC_GPU_CC_GMU_BCR] = { 0x9314 }, + [GPUCC_GPU_CC_GX_ACD_IROOT_BCR] = { 0x958c }, +}; + +static struct gdsc *gpu_cc_sm8650_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xa000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sm8650_desc = { + .config = &gpu_cc_sm8650_regmap_config, + .clks = gpu_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sm8650_clocks), + .resets = gpu_cc_sm8650_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sm8650_resets), + .gdscs = gpu_cc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sm8650_gdscs), +}; + +static const struct of_device_id gpu_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sm8650_match_table); + +static int gpu_cc_sm8650_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sm8650_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + return qcom_cc_really_probe(pdev, &gpu_cc_sm8650_desc, regmap); +} + +static struct platform_driver gpu_cc_sm8650_driver = { + .probe = gpu_cc_sm8650_probe, + .driver = { + .name = "sm8650-gpucc", + .of_match_table = gpu_cc_sm8650_match_table, + }, +}; +module_platform_driver(gpu_cc_sm8650_driver); + +MODULE_DESCRIPTION("QTI GPU_CC SM8650 Driver"); +MODULE_LICENSE("GPL"); From 1d50607335d728ed874da41b500173faf1bc2576 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 09:26:04 +0100 Subject: [PATCH 3103/7721] clk: qcom: rpmh: add clocks for SM8650 Add RPMH Clocks for the SM8650 platform. Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231106-topic-sm8650-upstream-clocks-v3-11-761a6fadb4c0@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-rpmh.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 5d853fd43294..bb09170600ec 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -372,6 +372,8 @@ DEFINE_CLK_RPMH_VRM(clk3, _a1, "clka3", 1); DEFINE_CLK_RPMH_VRM(clk4, _a1, "clka4", 1); DEFINE_CLK_RPMH_VRM(clk5, _a1, "clka5", 1); +DEFINE_CLK_RPMH_VRM(clk4, _a2, "clka4", 2); +DEFINE_CLK_RPMH_VRM(clk5, _a2, "clka5", 2); DEFINE_CLK_RPMH_VRM(clk6, _a2, "clka6", 2); DEFINE_CLK_RPMH_VRM(clk7, _a2, "clka7", 2); DEFINE_CLK_RPMH_VRM(clk8, _a2, "clka8", 2); @@ -630,6 +632,37 @@ static const struct clk_rpmh_desc clk_rpmh_sm8550 = { .num_clks = ARRAY_SIZE(sm8550_rpmh_clocks), }; +static struct clk_hw *sm8650_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw, + [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2.hw, + [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_ao.hw, + [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a2.hw, + [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a2_ao.hw, + [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2.hw, + [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_ao.hw, + [RPMH_RF_CLK1] = &clk_rpmh_clk1_a1.hw, + [RPMH_RF_CLK1_A] = &clk_rpmh_clk1_a1_ao.hw, + [RPMH_RF_CLK2] = &clk_rpmh_clk2_a1.hw, + [RPMH_RF_CLK2_A] = &clk_rpmh_clk2_a1_ao.hw, + /* + * The clka3 RPMh resource is missing in cmd-db + * for current platforms, while the clka3 exists + * on the PMK8550, the clock is unconnected and + * unused. + */ + [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw, + [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw, + [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sm8650 = { + .clks = sm8650_rpmh_clocks, + .num_clks = ARRAY_SIZE(sm8650_rpmh_clocks), +}; + static struct clk_hw *sc7280_rpmh_clocks[] = { [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div4.hw, [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div4_ao.hw, @@ -837,6 +870,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350}, { .compatible = "qcom,sm8450-rpmh-clk", .data = &clk_rpmh_sm8450}, { .compatible = "qcom,sm8550-rpmh-clk", .data = &clk_rpmh_sm8550}, + { .compatible = "qcom,sm8650-rpmh-clk", .data = &clk_rpmh_sm8650}, { .compatible = "qcom,sc7280-rpmh-clk", .data = &clk_rpmh_sc7280}, { } }; From 07c88da81caf0e72c3690b689d30f0d325cfeff4 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 15:23:57 +0100 Subject: [PATCH 3104/7721] arm64: dts: qcom: sm8550: fix soundwire controllers node name Fix the following dt bindings check: arch/arm64/boot/dts/qcom/sm8550-mtp.dtb: soundwire-controller@6ab0000: $nodename:0: 'soundwire-controller@6ab0000' does not match '^soundwire(@.*)?$' from schema $id: http://devicetree.org/schemas/soundwire/qcom,soundwire.yaml# Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231106-topic-sm8550-upstream-soundwire-bindings-fix-v1-1-4ded91c805a1@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 7310a2a19f01..2fec3768c482 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -2056,7 +2056,7 @@ lpass_wsa2macro: codec@6aa0000 { #sound-dai-cells = <1>; }; - swr3: soundwire-controller@6ab0000 { + swr3: soundwire@6ab0000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06ab0000 0 0x10000>; interrupts = ; @@ -2102,7 +2102,7 @@ lpass_rxmacro: codec@6ac0000 { #sound-dai-cells = <1>; }; - swr1: soundwire-controller@6ad0000 { + swr1: soundwire@6ad0000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06ad0000 0 0x10000>; interrupts = ; @@ -2167,7 +2167,7 @@ lpass_wsamacro: codec@6b00000 { #sound-dai-cells = <1>; }; - swr0: soundwire-controller@6b10000 { + swr0: soundwire@6b10000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06b10000 0 0x10000>; interrupts = ; @@ -2194,7 +2194,7 @@ swr0: soundwire-controller@6b10000 { status = "disabled"; }; - swr2: soundwire-controller@6d30000 { + swr2: soundwire@6d30000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06d30000 0 0x10000>; interrupts = , From 11fcb81373de52eeb1d3ff135a8d24a4b18978d3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 6 Nov 2023 16:58:33 +0100 Subject: [PATCH 3105/7721] arm64: dts: qcom: sm8450: fix soundwire controllers node name Fix the following dt bindings check: arch/arm64/boot/dts/qcom/sm8450-hdk.dtb: soundwire-controller@31f0000: $nodename:0: 'soundwire-controller@31f0000' does not match '^soundwire(@.*)?$' from schema $id: http://devicetree.org/schemas/soundwire/qcom,soundwire.yaml# Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231106-topic-sm8450-upstream-soundwire-bindings-fix-v1-1-41d4844a5a7d@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8450.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 12e55a0c7417..e5e8ce5e670e 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -2165,7 +2165,7 @@ wsa2macro: codec@31e0000 { #sound-dai-cells = <1>; }; - swr4: soundwire-controller@31f0000 { + swr4: soundwire@31f0000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x031f0000 0 0x2000>; interrupts = ; @@ -2213,7 +2213,7 @@ rxmacro: codec@3200000 { #sound-dai-cells = <1>; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x03210000 0 0x2000>; interrupts = ; @@ -2280,7 +2280,7 @@ wsamacro: codec@3240000 { #sound-dai-cells = <1>; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x03250000 0 0x2000>; interrupts = ; @@ -2307,7 +2307,7 @@ swr0: soundwire-controller@3250000 { status = "disabled"; }; - swr2: soundwire-controller@33b0000 { + swr2: soundwire@33b0000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x033b0000 0 0x2000>; interrupts = , From b0e0290bc47dd1bc8b1bd0c6b9ec0347564f3f21 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 09:04:16 +0100 Subject: [PATCH 3106/7721] arm64: dts: qcom: qdu1000: correct LLCC reg entries According to bindings and Linux driver there is no "multi_channel_register" address space for LLCC. The first "reg" entry is supposed to be llcc0_base since commit 43aa006e074c ("dt-bindings: arm: msm: Fix register regions used for LLCC banks"): qdu1000-idp.dtb: system-cache-controller@19200000: reg: [[0, 421527552, 0, 14155776], [0, 438304768, 0, 524288], [0, 572293416, 0, 4]] is too long qdu1000-idp.dtb: system-cache-controller@19200000: reg-names:0: 'llcc0_base' was expected qdu1000-idp.dtb: system-cache-controller@19200000: reg-names: ['llcc_base', 'llcc_broadcast_base', 'multi_channel_register'] is too long Signed-off-by: Krzysztof Kozlowski Acked-by: Mukesh Ojha Link: https://lore.kernel.org/r/20231107080417.16700-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qdu1000.dtsi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi index 1c0e5d271e91..618a101eb53a 100644 --- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi +++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi @@ -1446,11 +1446,9 @@ gem_noc: interconnect@19100000 { system-cache-controller@19200000 { compatible = "qcom,qdu1000-llcc"; reg = <0 0x19200000 0 0xd80000>, - <0 0x1a200000 0 0x80000>, - <0 0x221c8128 0 0x4>; - reg-names = "llcc_base", - "llcc_broadcast_base", - "multi_channel_register"; + <0 0x1a200000 0 0x80000>; + reg-names = "llcc0_base", + "llcc_broadcast_base"; interrupts = ; multi-ch-bit-off = <24 2>; }; From 468cf125e4796e8ef9815e2d8d018f44cf8f1225 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 09:04:17 +0100 Subject: [PATCH 3107/7721] arm64: dts: qcom: qdu1000-idp: drop unused LLCC multi-ch-bit-off There is no "multi-ch-bit-off" property in LLCC, according to bindings and Linux driver: qdu1000-idp.dtb: system-cache-controller@19200000: 'multi-ch-bit-off' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Krzysztof Kozlowski Acked-by: Mukesh Ojha Link: https://lore.kernel.org/r/20231107080417.16700-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qdu1000.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi index 618a101eb53a..89eff977d40e 100644 --- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi +++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi @@ -1450,7 +1450,6 @@ system-cache-controller@19200000 { reg-names = "llcc0_base", "llcc_broadcast_base"; interrupts = ; - multi-ch-bit-off = <24 2>; }; }; From 58e8fcf992831ef3642d90115ab119c19bfdd0c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:21:10 +0100 Subject: [PATCH 3108/7721] arm64: dts: qcom: sc8280xp: correct Soundwire node name Soundwire Devicetree bindings expect the Soundwire controller device node to be named just "soundwire": sc8280xp-lenovo-thinkpad-x13s.dtb: soundwire-controller@3210000: $nodename:0: 'soundwire-controller@3210000' does not match '^soundwire(@.*)?$' Reported-by: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231107102111.16465-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 3a44a171893a..febf28356ff8 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -2732,7 +2732,7 @@ rxmacro: rxmacro@3200000 { status = "disabled"; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { compatible = "qcom,soundwire-v1.6.0"; reg = <0 0x03210000 0 0x2000>; interrupts = ; @@ -2808,7 +2808,7 @@ wsamacro: codec@3240000 { status = "disabled"; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { reg = <0 0x03250000 0 0x2000>; compatible = "qcom,soundwire-v1.6.0"; interrupts = ; @@ -2845,7 +2845,7 @@ lpass_audiocc: clock-controller@32a9000 { #reset-cells = <1>; }; - swr2: soundwire-controller@3330000 { + swr2: soundwire@3330000 { compatible = "qcom,soundwire-v1.6.0"; reg = <0 0x03330000 0 0x2000>; interrupts = , From c1f52fb9a128771cfe2cae528c32b302e98398f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:21:11 +0100 Subject: [PATCH 3109/7721] arm64: dts: qcom: sm8250: correct Soundwire node name Soundwire Devicetree bindings expect the Soundwire controller device node to be named just "soundwire": sm8250-xiaomi-elish-boe.dtb: soundwire-controller@3250000: $nodename:0: 'soundwire-controller@3250000' does not match '^soundwire(@.*)?$' Reported-by: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231107102111.16465-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 7ab6c9953d74..8ea764e19372 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -2592,7 +2592,7 @@ wsamacro: codec@3240000 { status = "disabled"; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { reg = <0 0x03250000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; interrupts = ; @@ -2658,7 +2658,7 @@ rxmacro: rxmacro@3200000 { #sound-dai-cells = <1>; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { reg = <0 0x03210000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; status = "disabled"; @@ -2705,7 +2705,7 @@ txmacro: txmacro@3220000 { }; /* tx macro */ - swr2: soundwire-controller@3230000 { + swr2: soundwire@3230000 { reg = <0 0x03230000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; interrupts = ; From 5a71b4719be718ffd99dfc08a457cefac4070102 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:35:38 +0100 Subject: [PATCH 3110/7721] arm64: dts: qcom: sc8180x-primus: drop sound-dai-cells from eDisplayPort Qualcomm MDSS Embedded DisplayPort bindings do not allow sound-dai-cells: sc8180x-primus.dtb: displayport-controller@ae9a000: #sound-dai-cells: False schema does not allow [[0]] Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231107103540.27353-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index 00967811a808..2cada357aa7c 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -3113,8 +3113,6 @@ mdss_edp: displayport-controller@ae9a000 { phys = <&edp_phy>; phy-names = "dp"; - #sound-dai-cells = <0>; - operating-points-v2 = <&edp_opp_table>; power-domains = <&rpmhpd SC8180X_MMCX>; From 7613e707612e50fb73bba3e9ae1b281f36eff24b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:35:39 +0100 Subject: [PATCH 3111/7721] arm64: dts: qcom: sc8280xp-x13s: drop sound-dai-cells from eDisplayPort Qualcomm MDSS Embedded DisplayPort bindings do not allow sound-dai-cells: sc8280xp-lenovo-thinkpad-x13s.dtb: displayport-controller@aea0000: #sound-dai-cells: False schema does not allow [[0] Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231107103540.27353-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index f2055899ae7a..def3976bd5bb 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -573,6 +573,7 @@ &mdss0_dp1_out { &mdss0_dp3 { compatible = "qcom,sc8280xp-edp"; + /delete-property/ #sound-dai-cells; data-lanes = <0 1 2 3>; From fabfc74f1b3ab1801d54cf32d8e44a893340be7f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 11:35:40 +0100 Subject: [PATCH 3112/7721] arm64: dts: qcom: sm8350: move DPU opp-table to its node The Qualcomm MDSS bindings expect that DPU opp-table is defined within DPU node: sm8350-hdk.dtb: display-subsystem@ae00000: Unevaluated properties are not allowed ('opp-table' was unexpected) Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231107103540.27353-3-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 94dcc4b64105..2055b748e4c9 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -2452,35 +2452,6 @@ mdss: display-subsystem@ae00000 { #size-cells = <2>; ranges; - dpu_opp_table: opp-table { - compatible = "operating-points-v2"; - - /* TODO: opp-200000000 should work with - * &rpmhpd_opp_low_svs, but one some of - * sm8350_hdk boards reboot using this - * opp. - */ - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-300000000 { - opp-hz = /bits/ 64 <300000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-345000000 { - opp-hz = /bits/ 64 <345000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-460000000 { - opp-hz = /bits/ 64 <460000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; - mdss_mdp: display-controller@ae01000 { compatible = "qcom,sm8350-dpu"; reg = <0 0x0ae01000 0 0x8f000>, @@ -2509,6 +2480,35 @@ mdss_mdp: display-controller@ae01000 { interrupt-parent = <&mdss>; interrupts = <0>; + dpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* TODO: opp-200000000 should work with + * &rpmhpd_opp_low_svs, but one some of + * sm8350_hdk boards reboot using this + * opp. + */ + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-460000000 { + opp-hz = /bits/ 64 <460000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + ports { #address-cells = <1>; #size-cells = <0>; From 81c8ec77b86fde629d5beea1ebe42caeea57c5a4 Mon Sep 17 00:00:00 2001 From: Shazad Hussain Date: Tue, 7 Nov 2023 17:35:02 +0530 Subject: [PATCH 3113/7721] arm64: dts: qcom: sa8775p-ride: enable pmm8654au_0_pon_resin The volume down key is controlled by PMIC via the PON hardware on sa8775p platform, so enable the same for sa8775p-ride. Signed-off-by: Shazad Hussain Link: https://lore.kernel.org/r/20231107120503.28917-1-quic_shazhuss@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p-ride.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts index 9760bb4b468c..26ad05bd3b3f 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts @@ -461,6 +461,11 @@ &pmm8654au_0_gpios { "ANALOG_PON_OPT"; }; +&pmm8654au_0_pon_resin { + linux,code = ; + status = "okay"; +}; + &pmm8654au_1_gpios { gpio-line-names = "PMIC_C_ID0", "PMIC_C_ID1", From fdcc36cda04114878f6c752083669719a3995fce Mon Sep 17 00:00:00 2001 From: Steev Klimaszewski Date: Tue, 7 Nov 2023 23:17:10 -0600 Subject: [PATCH 3114/7721] arm64: dts: qcom: sdm850-lenovo-yoga: Add wakeup-sources The keyboard and touchpad can be used to wake the machine up from sleep, so mark them as such in the dts file. Signed-off-by: Steev Klimaszewski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231107-wakeup-source-v2-1-bf1562ef9367@kali.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts index 92a812b5f423..8f68c99965cd 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -392,6 +392,8 @@ tsc2: hid@2c { hid-descr-addr = <0x20>; interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>; + + wakeup-source; }; }; @@ -408,6 +410,8 @@ tsc1: hid@10 { pinctrl-names = "default"; pinctrl-0 = <&i2c5_hid_active>; + + wakeup-source; }; }; @@ -482,6 +486,8 @@ ecsh: hid@5c { pinctrl-names = "default"; pinctrl-0 = <&i2c11_hid_active>; + + wakeup-source; }; }; From 48307d83c998db18db6890dccb569146eb12d313 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 9 Nov 2023 00:43:11 +0000 Subject: [PATCH 3115/7721] arm64: dts: qcom: sm8250: Add wakeup-source to usb_1 and usb_2 To test out a different GDSC change I wanted to have a USB keypress resume a system in suspend. Adding wakeup-source to usb_1 and usb_2 "just works" for me on rb5. Consistent with qcm2290 and sa8775p add wakeup-source to the dtsi for the SoC. Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231109004311.2449566-2-bryan.odonoghue@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 8ea764e19372..9c5eb0a106e0 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -4162,6 +4162,7 @@ usb_1: usb@a6f8800 { "dp_hs_phy_irq"; power-domains = <&gcc USB30_PRIM_GDSC>; + wakeup-source; resets = <&gcc GCC_USB30_PRIM_BCR>; @@ -4230,6 +4231,7 @@ usb_2: usb@a8f8800 { "dp_hs_phy_irq"; power-domains = <&gcc USB30_SEC_GDSC>; + wakeup-source; resets = <&gcc GCC_USB30_SEC_BCR>; From c4fb7d2eac9ff9bfc35a2e4d40c7169a332416e0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 9 Nov 2023 10:31:00 +0100 Subject: [PATCH 3116/7721] soc: qcom: pmic_glink_altmode: fix port sanity check The PMIC GLINK altmode driver currently supports at most two ports. Fix the incomplete port sanity check on notifications to avoid accessing and corrupting memory beyond the port array if we ever get a notification for an unsupported port. Fixes: 080b4e24852b ("soc: qcom: pmic_glink: Introduce altmode support") Cc: stable@vger.kernel.org # 6.3 Signed-off-by: Johan Hovold Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231109093100.19971-1-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pmic_glink_altmode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index b78279e2f54c..7ee52cf2570f 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -285,7 +285,7 @@ static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmod svid = mux == 2 ? USB_TYPEC_DP_SID : 0; - if (!altmode->ports[port].altmode) { + if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) { dev_dbg(altmode->dev, "notification on undefined port %d\n", port); return; } @@ -328,7 +328,7 @@ static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmod hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]); hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]); - if (!altmode->ports[port].altmode) { + if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) { dev_dbg(altmode->dev, "notification on undefined port %d\n", port); return; } From dc6b5562acbac0285ab3b2dad23930b6434bdfc6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 10:46:23 +0100 Subject: [PATCH 3117/7721] arm64: dts: qcom: qrb5165-rb5: correct LED panic indicator There is no "panic-indicator" default trigger but a property with that name: qrb5165-rb5.dtb: leds: led-user4: Unevaluated properties are not allowed ('linux,default-trigger' was unexpected) Fixes: b5cbd84e499a ("arm64: dts: qcom: qrb5165-rb5: Add onboard LED support") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111094623.12476-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index c8cd40a462a3..f9464caddacc 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -64,8 +64,8 @@ led-user4 { function = LED_FUNCTION_INDICATOR; color = ; gpios = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "panic-indicator"; default-state = "off"; + panic-indicator; }; led-wlan { From 0c90c75e663246203a2b7f6dd9e08a110f4c3c43 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 10:56:16 +0100 Subject: [PATCH 3118/7721] arm64: dts: qcom: sdm845-db845c: correct LED panic indicator There is no "panic-indicator" default trigger but a property with that name: sdm845-db845c.dtb: leds: led-0: Unevaluated properties are not allowed ('linux,default-trigger' was unexpected) Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111095617.16496-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index c7eba6c491be..7e7bf3fb3be6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -67,8 +67,8 @@ led-0 { function = LED_FUNCTION_INDICATOR; color = ; gpios = <&pm8998_gpios 13 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "panic-indicator"; default-state = "off"; + panic-indicator; }; led-1 { From 74eed6f467db53b9b8b7fb225f6ac475449ad073 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 10:56:17 +0100 Subject: [PATCH 3119/7721] arm64: dts: qcom: sdm845: correct Soundwire node name Soundwire Devicetree bindings expect the Soundwire controller device node to be named just "soundwire": sdm845-db845c.dtb: swm@c85: $nodename:0: 'swm@c85' does not match '^soundwire(@.*)?$' Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Acked-by: Vinod Koul Link: https://lore.kernel.org/r/20231111095617.16496-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 2 +- arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 2 +- arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index 7e7bf3fb3be6..ab6220456513 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -1130,7 +1130,7 @@ &wcd9340 { vdd-rx-supply = <&vreg_s4a_1p8>; vdd-io-supply = <&vreg_s4a_1p8>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,1 { compatible = "sdw10217201000"; reg = <0 1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi b/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi index c15d48860646..6172cd1539e6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi @@ -54,7 +54,7 @@ wcdgpio: gpio-controller@42 { reg = <0x42 0x2>; }; - swm: swm@c85 { + swm: soundwire@c85 { compatible = "qcom,soundwire-v1.3.0"; reg = <0xc85 0x40>; interrupts-extended = <&wcd9340 20>; diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts index 8f68c99965cd..47dc42f6e936 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -803,7 +803,7 @@ &wcd9340 { qcom,mbhc-headset-vthreshold-microvolt = <1700000>; qcom,mbhc-headphone-vthreshold-microvolt = <50000>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,3 { compatible = "sdw10217211000"; reg = <0 3>; diff --git a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts index 543837316001..26217836c270 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts @@ -658,7 +658,7 @@ &wcd9340 { qcom,mbhc-headset-vthreshold-microvolt = <1700000>; qcom,mbhc-headphone-vthreshold-microvolt = <50000>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,3 { compatible = "sdw10217211000"; reg = <0 3>; From c5ece8d84303c1956b18d2aba03c4b4fc856f53e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 4 Dec 2023 16:07:47 +0800 Subject: [PATCH 3120/7721] wifi: rtw89: 8922a: configure CRASH_TRIGGER FW feature RTL8922A FW supports CRASH_TRIGGER feature from v0.34.30.0. After it, debugfs fw_crash can accept type 1 on RTL8922A to trigger firmware crash and verify L2 recovery. Besides, RTL8922A sync address offset of reserved payload engine. And, SER (system error recovery) tweaks conversion from WCPU address to indirect access address for RTL8922A. The new conversion works for all supported chips. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231204080751.15354-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + drivers/net/wireless/realtek/rtw89/fw.h | 2 -- drivers/net/wireless/realtek/rtw89/ser.c | 10 +++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b11ed35e265d..0b9c3c76b273 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -453,6 +453,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d4db9ab0b5e8..2b2d14284465 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3651,8 +3651,6 @@ struct rtw89_fw_h2c_rf_get_mccch { #define RTW89_FW_RSVD_PLE_SIZE 0x800 -#define RTW89_WCPU_BASE_MASK GENMASK(27, 0) - #define RTW89_FW_BACKTRACE_INFO_SIZE 8 #define RTW89_VALID_FW_BACKTRACE_SIZE(_size) \ ((_size) % RTW89_FW_BACKTRACE_INFO_SIZE == 0) diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 1e4a79a3b814..99896d85d2f8 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -590,6 +590,14 @@ struct __fw_backtrace_info { static_assert(RTW89_FW_BACKTRACE_INFO_SIZE == sizeof(struct __fw_backtrace_info)); +static u32 convert_addr_from_wcpu(u32 wcpu_addr) +{ + if (wcpu_addr < 0x30000000) + return wcpu_addr; + + return wcpu_addr & GENMASK(28, 0); +} + static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct __fw_backtrace_entry *ent) { @@ -597,7 +605,7 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; - u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK; + u32 fwbt_addr = convert_addr_from_wcpu(ent->wcpu_addr); u32 fwbt_size = ent->size; u32 fwbt_key = ent->key; u32 i; From 2a68a27cd27aeb09dc74d9d800758ba0b36cb230 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 4 Dec 2023 16:07:48 +0800 Subject: [PATCH 3121/7721] wifi: rtw89: fw: extend program counter dump for Wi-Fi 7 chip Extend FW program counter dump for Wi-Fi 7 chip. They poll different addresses. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231204080751.15354-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 10 +++++++++- drivers/net/wireless/realtek/rtw89/reg.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 0b9c3c76b273..81034b6ce4b0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -957,16 +957,24 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev) { + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + u32 addr = R_AX_DBG_PORT_SEL; u32 val32; u16 index; + if (chip_gen == RTW89_CHIP_BE) { + addr = R_BE_WLCPU_PORT_PC; + goto dump; + } + rtw89_write32(rtwdev, R_AX_DBG_CTRL, FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) | FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL)); rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0_MASK, MAC_DBG_SEL); +dump: for (index = 0; index < 15; index++) { - val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL); + val32 = rtw89_read32(rtwdev, addr); rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32); fsleep(10); } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 1bd91c62678d..690fa835c054 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4023,6 +4023,8 @@ #define B_BE_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) #define B_BE_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) +#define R_BE_WLCPU_PORT_PC 0x03FC + #define R_BE_DCPU_PLATFORM_ENABLE 0x0888 #define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10) #define B_BE_DCPU_WARM_EN BIT(9) From eeb8cbb58b82904442a6c05832b97d7d27b3c48b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 4 Dec 2023 16:07:49 +0800 Subject: [PATCH 3122/7721] wifi: rtw89: 8922a: add SER IMR tables To activate SER (system error recovery) in firmware, we have to configure IMR to trigger interrupts, and then SER can check registers to know if it need to reset hardware or notify driver to re-configure whole settings. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231204080751.15354-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 13 + drivers/net/wireless/realtek/rtw89/reg.h | 1134 +++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 58 + 7 files changed, 1213 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c315ef96e91e..b1e498ad149e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3376,6 +3376,12 @@ struct rtw89_reg5_def { u32 data; }; +struct rtw89_reg_imr { + u32 addr; + u32 clr; + u32 set; +}; + struct rtw89_phy_table { const struct rtw89_reg2_def *regs; u32 n_regs; @@ -3585,6 +3591,11 @@ struct rtw89_imr_info { u32 tmac_imr_set; }; +struct rtw89_imr_table { + const struct rtw89_reg_imr *regs; + u32 n_regs; +}; + struct rtw89_xtal_info { u32 xcap_reg; u32 sc_xo_mask; @@ -3779,6 +3790,8 @@ struct rtw89_chip_info { const struct rtw89_reg_def *dcfo_comp; u8 dcfo_comp_sft; const struct rtw89_imr_info *imr_info; + const struct rtw89_imr_table *imr_dmac_table; + const struct rtw89_imr_table *imr_cmac_table; const struct rtw89_rrsr_cfgs *rrsr_cfgs; struct rtw89_reg_def bss_clr_vld; u32 bss_clr_map_reg; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 690fa835c054..76f9195f40e7 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3740,6 +3740,39 @@ #define B_BE_DIS_CLK_REG1_GATE BIT(1) #define B_BE_DIS_CLK_REG0_GATE BIT(0) +#define R_BE_AFE_CTRL1 0x0024 +#define B_BE_R_SYM_WLCMAC0_P4_PC_EN BIT(28) +#define B_BE_R_SYM_WLCMAC0_P3_PC_EN BIT(27) +#define B_BE_R_SYM_WLCMAC0_P2_PC_EN BIT(26) +#define B_BE_R_SYM_WLCMAC0_P1_PC_EN BIT(25) +#define B_BE_R_SYM_WLCMAC0_PC_EN BIT(24) +#define B_BE_DATAMEM_PC3_EN BIT(23) +#define B_BE_DATAMEM_PC2_EN BIT(22) +#define B_BE_DATAMEM_PC1_EN BIT(21) +#define B_BE_DATAMEM_PC_EN BIT(20) +#define B_BE_DMEM7_PC_EN BIT(19) +#define B_BE_DMEM6_PC_EN BIT(18) +#define B_BE_DMEM5_PC_EN BIT(17) +#define B_BE_DMEM4_PC_EN BIT(16) +#define B_BE_DMEM3_PC_EN BIT(15) +#define B_BE_DMEM2_PC_EN BIT(14) +#define B_BE_DMEM1_PC_EN BIT(13) +#define B_BE_IMEM4_PC_EN BIT(12) +#define B_BE_IMEM3_PC_EN BIT(11) +#define B_BE_IMEM2_PC_EN BIT(10) +#define B_BE_IMEM1_PC_EN BIT(9) +#define B_BE_IMEM0_PC_EN BIT(8) +#define B_BE_R_SYM_WLCMAC1_P4_PC_EN BIT(4) +#define B_BE_R_SYM_WLCMAC1_P3_PC_EN BIT(3) +#define B_BE_R_SYM_WLCMAC1_P2_PC_EN BIT(2) +#define B_BE_R_SYM_WLCMAC1_P1_PC_EN BIT(1) +#define B_BE_R_SYM_WLCMAC1_PC_EN BIT(0) +#define B_BE_AFE_CTRL1_SET (B_BE_R_SYM_WLCMAC1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P4_PC_EN) + #define R_BE_EFUSE_CTRL 0x0030 #define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) #define B_BE_EF_RDY BIT(29) @@ -3827,6 +3860,30 @@ #define B_BE_PCI_CKRDY_OPT BIT(1) #define B_BE_PCI_VAUX_EN BIT(0) +#define R_BE_SYS_ISO_CTRL_EXTEND 0x0080 +#define B_BE_R_SYM_ISO_DMEM62PP BIT(29) +#define B_BE_R_SYM_ISO_DMEM52PP BIT(28) +#define B_BE_R_SYM_ISO_DMEM42PP BIT(27) +#define B_BE_R_SYM_ISO_DMEM32PP BIT(26) +#define B_BE_R_SYM_ISO_DMEM22PP BIT(25) +#define B_BE_R_SYM_ISO_DMEM12PP BIT(24) +#define B_BE_R_SYM_ISO_IMEM42PP BIT(22) +#define B_BE_R_SYM_ISO_IMEM32PP BIT(21) +#define B_BE_R_SYM_ISO_IMEM22PP BIT(20) +#define B_BE_R_SYM_ISO_IMEM12PP BIT(19) +#define B_BE_R_SYM_ISO_IMEM02PP BIT(18) +#define B_BE_R_SYM_ISO_AON_OFF2PP BIT(15) +#define B_BE_R_SYM_PWC_HCILA BIT(13) +#define B_BE_R_SYM_PWC_PD12V BIT(12) +#define B_BE_R_SYM_PWC_UD12V BIT(11) +#define B_BE_R_SYM_PWC_BTBRG BIT(10) +#define B_BE_R_SYM_LDOBTSDIO_EN BIT(9) +#define B_BE_R_SYM_LDOSPDIO_EN BIT(8) +#define B_BE_R_SYM_ISO_HCILA BIT(4) +#define B_BE_R_SYM_ISO_BTBRG2PP BIT(2) +#define B_BE_R_SYM_ISO_BTSDIO2PP BIT(1) +#define B_BE_R_SYM_ISO_SPDIO2PP BIT(0) + #define R_BE_PLATFORM_ENABLE 0x0088 #define B_BE_HOLD_AFTER_RESET BIT(11) #define B_BE_SYM_WLPLT_MEM_MUX_EN BIT(10) @@ -3869,6 +3926,18 @@ #define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) #define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) +#define R_BE_PCIE_MIO_INTF 0x00E4 +#define B_BE_AON_MIO_EPHY_1K_SEL_MASK GENMASK(29, 24) +#define B_BE_PCIE_MIO_ADDR_PAGE_V1_MASK GENMASK(20, 16) +#define B_BE_PCIE_MIO_ASIF BIT(15) +#define B_BE_PCIE_MIO_BYIOREG BIT(13) +#define B_BE_PCIE_MIO_RE BIT(12) +#define B_BE_PCIE_MIO_WE_MASK GENMASK(11, 8) +#define B_BE_PCIE_MIO_ADDR_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIO_INTD 0x00E8 +#define B_BE_PCIE_MIO_DATA_MASK GENMASK(31, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) @@ -4034,6 +4103,25 @@ #define B_BE_DCPU_EN BIT(1) #define B_BE_DCPU_PLATFORM_EN BIT(0) +#define R_BE_PL_AXIDMA_IDCT_MSK 0x0910 +#define B_BE_PL_AXIDMA_RRESP_ERR_MASK BIT(6) +#define B_BE_PL_AXIDMA_BRESP_ERR_MASK BIT(5) +#define B_BE_PL_AXIDMA_FC_ERR_MASK BIT(4) +#define B_BE_PL_AXIDMA_TXBD_LEN0_MASK BIT(3) +#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR_MASK BIT(2) +#define B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK BIT(1) +#define B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK BIT(0) +#define B_BE_PL_AXIDMA_IDCT_MSK_CLR (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \ + B_BE_PL_AXIDMA_FC_ERR_MASK | \ + B_BE_PL_AXIDMA_BRESP_ERR_MASK | \ + B_BE_PL_AXIDMA_RRESP_ERR_MASK) +#define B_BE_PL_AXIDMA_IDCT_MSK_SET (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \ + B_BE_PL_AXIDMA_FC_ERR_MASK) + #define R_BE_FILTER_MODEL_ADDR 0x0C04 #define R_BE_WLAN_WDT 0x3050 @@ -4247,11 +4335,316 @@ #define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) #define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) +#define R_BE_DISP_OTHER_IMR 0x8870 +#define B_BE_REUSE_SIZE_ERR_INT_EN BIT(31) +#define B_BE_REUSE_EN_ERR_INT_EN BIT(30) +#define B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN BIT(29) +#define B_BE_STF_OQT_OVERFLOW_ERR_INT_EN BIT(28) +#define B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN BIT(27) +#define B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN BIT(26) +#define B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN BIT(25) +#define B_BE_STF_CMD_OVERFLOW_ERR_INT_EN BIT(24) +#define B_BE_REUSE_SIZE_ZERO_ERR_INT_EN BIT(23) +#define B_BE_REUSE_PKT_CNT_ERR_INT_EN BIT(22) +#define B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN BIT(21) +#define B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN BIT(20) +#define B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN BIT(19) +#define B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN BIT(18) +#define B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN BIT(17) +#define B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN BIT(16) +#define B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN BIT(15) +#define B_BE_CDR_RX_TIMEOUT_ERR_INT_EN BIT(14) +#define B_BE_PLE_OUTPUT_ERR_INT_EN BIT(12) +#define B_BE_PLE_RESPOSE_ERR_INT_EN BIT(11) +#define B_BE_PLE_BURST_NUM_ERR_INT_EN BIT(10) +#define B_BE_PLE_NULL_PKT_ERR_INT_EN BIT(9) +#define B_BE_PLE_FLOW_CTRL_ERR_INT_EN BIT(8) +#define B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN BIT(7) +#define B_BE_HDR_RX_TIMEOUT_ERR_INT_EN BIT(6) +#define B_BE_WDE_OUTPUT_ERR_INT_EN BIT(4) +#define B_BE_WDE_RESPONSE_ERR_INT_EN BIT(3) +#define B_BE_WDE_BURST_NUM_ERR_INT_EN BIT(2) +#define B_BE_WDE_NULL_PKT_ERR_INT_EN BIT(1) +#define B_BE_WDE_FLOW_CTRL_ERR_INT_EN BIT(0) +#define B_BE_DISP_OTHER_IMR_CLR (B_BE_WDE_FLOW_CTRL_ERR_INT_EN | \ + B_BE_WDE_NULL_PKT_ERR_INT_EN | \ + B_BE_WDE_BURST_NUM_ERR_INT_EN | \ + B_BE_WDE_RESPONSE_ERR_INT_EN | \ + B_BE_WDE_OUTPUT_ERR_INT_EN | \ + B_BE_HDR_RX_TIMEOUT_ERR_INT_EN | \ + B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN | \ + B_BE_PLE_FLOW_CTRL_ERR_INT_EN | \ + B_BE_PLE_NULL_PKT_ERR_INT_EN | \ + B_BE_PLE_BURST_NUM_ERR_INT_EN | \ + B_BE_PLE_RESPOSE_ERR_INT_EN | \ + B_BE_PLE_OUTPUT_ERR_INT_EN | \ + B_BE_CDR_RX_TIMEOUT_ERR_INT_EN | \ + B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN | \ + B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN | \ + B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN | \ + B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN | \ + B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN | \ + B_BE_REUSE_PKT_CNT_ERR_INT_EN | \ + B_BE_REUSE_SIZE_ZERO_ERR_INT_EN | \ + B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN | \ + B_BE_REUSE_EN_ERR_INT_EN | \ + B_BE_REUSE_SIZE_ERR_INT_EN) +#define B_BE_DISP_OTHER_IMR_SET (B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN) + +#define R_BE_DISP_HOST_IMR 0x8874 +#define B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN BIT(31) +#define B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN BIT(30) +#define B_BE_HR_CHKSUM_FSM_ERR_INT_EN BIT(29) +#define B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN BIT(28) +#define B_BE_HR_DMA_PROCESS_ERR_INT_EN BIT(27) +#define B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(26) +#define B_BE_HR_SHIFT_EN_ERR_INT_EN BIT(25) +#define B_BE_HR_AGG_CFG_ERR_INT_EN BIT(24) +#define B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN BIT(22) +#define B_BE_HT_ILL_CH_ERR_INT_EN BIT(20) +#define B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN BIT(18) +#define B_BE_HT_WD_LEN_OVER_ERR_INT_EN BIT(17) +#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(16) +#define B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(15) +#define B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN BIT(14) +#define B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN BIT(13) +#define B_BE_HT_CHKSUM_FSM_ERR_INT_EN BIT(12) +#define B_BE_HT_NON_IDLE_PKT_STR_ERR_EN BIT(11) +#define B_BE_HT_PRE_SUB_ERR_INT_EN BIT(10) +#define B_BE_HT_WD_CHKSUM_ERR_INT_EN BIT(9) +#define B_BE_HT_CHANNEL_DMA_ERR_INT_EN BIT(8) +#define B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN BIT(7) +#define B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN BIT(6) +#define B_BE_HT_PAYLOAD_OVER_ERR_INT_EN BIT(5) +#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4) +#define B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3) +#define B_BE_HT_PKT_FAIL_ERR_INT_EN BIT(2) +#define B_BE_HT_CH_ID_ERR_INT_EN BIT(1) +#define B_BE_HT_EP_CH_DIFF_ERR_INT_EN BIT(0) +#define B_BE_DISP_HOST_IMR_CLR (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_HT_CH_ID_ERR_INT_EN | \ + B_BE_HT_PKT_FAIL_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN | \ + B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_HT_WD_CHKSUM_ERR_INT_EN | \ + B_BE_HT_PRE_SUB_ERR_INT_EN | \ + B_BE_HT_NON_IDLE_PKT_STR_ERR_EN | \ + B_BE_HT_CHKSUM_FSM_ERR_INT_EN | \ + B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_HT_ILL_CH_ERR_INT_EN | \ + B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN | \ + B_BE_HR_AGG_CFG_ERR_INT_EN | \ + B_BE_HR_SHIFT_EN_ERR_INT_EN | \ + B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \ + B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN | \ + B_BE_HR_CHKSUM_FSM_ERR_INT_EN | \ + B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_HOST_IMR_SET (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_HT_PRE_SUB_ERR_INT_EN | \ + B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_HT_ILL_CH_ERR_INT_EN | \ + B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \ + B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) + +#define R_BE_DISP_CPU_IMR 0x8878 +#define B_BE_CR_PLD_LEN_ERR_INT_EN BIT(30) +#define B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN BIT(29) +#define B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN BIT(28) +#define B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN BIT(27) +#define B_BE_CR_DMA_PROCESS_ERR_INT_EN BIT(26) +#define B_BE_CR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(25) +#define B_BE_CR_SHIFT_EN_ERR_INT_EN BIT(24) +#define B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN BIT(22) +#define B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN BIT(21) +#define B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN BIT(20) +#define B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN BIT(19) +#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN BIT(17) +#define B_BE_CT_WD_LEN_OVER_ERR_INT_EN BIT(16) +#define B_BE_CT_F2P_SEQ_ERR_INT_EN BIT(15) +#define B_BE_CT_F2P_QSEL_ERR_INT_EN BIT(14) +#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(13) +#define B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(12) +#define B_BE_CT_PRE_SUB_ERR_INT_EN BIT(11) +#define B_BE_CT_WD_CHKSUM_ERR_INT_EN BIT(10) +#define B_BE_CT_CHANNEL_DMA_ERR_INT_EN BIT(9) +#define B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN BIT(8) +#define B_BE_CT_PAYLOAD_CHKSUM_ERR_INT_EN BIT(7) +#define B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN BIT(6) +#define B_BE_CT_PAYLOAD_OVER_ERR_INT_EN BIT(5) +#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4) +#define B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3) +#define B_BE_CT_CH_ID_ERR_INT_EN BIT(2) +#define B_BE_CT_PKT_FAIL_ERR_INT_EN BIT(1) +#define B_BE_CT_EP_CH_DIFF_ERR_INT_EN BIT(0) +#define B_BE_DISP_CPU_IMR_CLR (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_CT_CH_ID_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN | \ + B_BE_CT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_CT_WD_CHKSUM_ERR_INT_EN | \ + B_BE_CT_PRE_SUB_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_F2P_QSEL_ERR_INT_EN | \ + B_BE_CT_F2P_SEQ_ERR_INT_EN | \ + B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \ + B_BE_CR_SHIFT_EN_ERR_INT_EN | \ + B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN | \ + B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CR_PLD_LEN_ERR_INT_EN) +#define B_BE_DISP_CPU_IMR_SET (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_CT_CH_ID_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_CT_PRE_SUB_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \ + B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN) + #define R_BE_WDE_PKTBUF_CFG 0x8C08 #define B_BE_WDE_FREE_PAGE_NUM_MASK GENMASK(28, 16) #define B_BE_WDE_START_BOUND_MASK GENMASK(14, 8) #define B_BE_WDE_PAGE_SEL_MASK GENMASK(1, 0) +#define R_BE_WDE_ERR_IMR 0x8C38 +#define B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) +#define B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN BIT(28) +#define B_BE_WDE_DATCHN_RRDY_ERR_INT_EN BIT(27) +#define B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN BIT(26) +#define B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN BIT(25) +#define B_BE_WDE_DATCHN_ARBT_ERR_INT_EN BIT(24) +#define B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN BIT(23) +#define B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN BIT(22) +#define B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN BIT(21) +#define B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20) +#define B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19) +#define B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN BIT(18) +#define B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN BIT(17) +#define B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN BIT(16) +#define B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13) +#define B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12) +#define B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11) +#define B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10) +#define B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN BIT(8) +#define B_BE_WDE_GETNPG_STRPG_ERR_INT_EN BIT(7) +#define B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6) +#define B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN BIT(5) +#define B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4) +#define B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3) +#define B_BE_WDE_BUFREQ_SIZELMT_INT_EN BIT(2) +#define B_BE_WDE_BUFREQ_SIZE0_INT_EN BIT(1) +#define B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN BIT(0) +#define B_BE_WDE_ERR_IMR_CLR (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SIZE0_INT_EN | \ + B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN) +#define B_BE_WDE_ERR_IMR_SET (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SIZE0_INT_EN | \ + B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN) + #define R_BE_WDE_QTA0_CFG 0x8C40 #define B_BE_WDE_Q0_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_WDE_Q0_MIN_SIZE_MASK GENMASK(11, 0) @@ -4272,11 +4665,102 @@ #define B_BE_WDE_Q4_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_WDE_Q4_MIN_SIZE_MASK GENMASK(11, 0) +#define R_BE_WDE_ERR1_IMR 0x8CC0 +#define B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN BIT(8) +#define B_BE_WDE_ERR1_IMR_CLR B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN +#define B_BE_WDE_ERR1_IMR_SET B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN + #define R_BE_PLE_PKTBUF_CFG 0x9008 #define B_BE_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) #define B_BE_PLE_START_BOUND_MASK GENMASK(14, 8) #define B_BE_PLE_PAGE_SEL_MASK GENMASK(1, 0) +#define R_BE_PLE_ERR_IMR 0x9038 +#define B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) +#define B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28) +#define B_BE_PLE_DATCHN_RRDY_ERR_INT_EN BIT(27) +#define B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN BIT(26) +#define B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN BIT(25) +#define B_BE_PLE_DATCHN_ARBT_ERR_INT_EN BIT(24) +#define B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN BIT(23) +#define B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN BIT(22) +#define B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN BIT(21) +#define B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20) +#define B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19) +#define B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN BIT(18) +#define B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN BIT(17) +#define B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN BIT(16) +#define B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13) +#define B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12) +#define B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11) +#define B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10) +#define B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN BIT(8) +#define B_BE_PLE_GETNPG_STRPG_ERR_INT_EN BIT(7) +#define B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6) +#define B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN BIT(5) +#define B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4) +#define B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3) +#define B_BE_PLE_BUFREQ_SIZELMT_INT_EN BIT(2) +#define B_BE_PLE_BUFREQ_SIZE0_INT_EN BIT(1) +#define B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN BIT(0) +#define B_BE_PLE_ERR_IMR_CLR (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SIZE0_INT_EN | \ + B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN) +#define B_BE_PLE_ERR_IMR_SET (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SIZE0_INT_EN | \ + B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN) + #define R_BE_PLE_QTA0_CFG 0x9040 #define B_BE_PLE_Q0_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_PLE_Q0_MIN_SIZE_MASK GENMASK(11, 0) @@ -4329,6 +4813,17 @@ #define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0) +#define R_BE_PLE_ERRFLAG1_IMR 0x90C0 +#define B_BE_PLE_SRCHPG_PGOFST_IMR BIT(26) +#define B_BE_PLE_SRCHPG_STRPG_IMR BIT(25) +#define B_BE_PLE_SRCHPG_FRZTO_IMR BIT(24) +#define B_BE_PLE_ERRFLAG1_IMR_CLR (B_BE_PLE_SRCHPG_FRZTO_IMR | \ + B_BE_PLE_SRCHPG_STRPG_IMR | \ + B_BE_PLE_SRCHPG_PGOFST_IMR) +#define B_BE_PLE_ERRFLAG1_IMR_SET (B_BE_PLE_SRCHPG_FRZTO_IMR | \ + B_BE_PLE_SRCHPG_STRPG_IMR | \ + B_BE_PLE_SRCHPG_PGOFST_IMR) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) @@ -4337,6 +4832,100 @@ #define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114 #define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0) +#define R_BE_WDRLS_CFG 0x9408 +#define B_BE_WDRLS_DIS_AGAC BIT(31) +#define B_BE_RLSRPT_BUFREQ_TO_MASK GENMASK(15, 8) +#define B_BE_RLSRPT_BUFREQ_TO_SEL_MASK GENMASK(7, 6) +#define B_BE_WDRLS_MODE_MASK GENMASK(1, 0) + +#define R_BE_WDRLS_ERR_IMR 0x9430 +#define B_BE_WDRLS_RPT3_FRZTO_ERR_INT_EN BIT(21) +#define B_BE_WDRLS_RPT3_AGGNUM0_ERR_INT_EN BIT(20) +#define B_BE_WDRLS_RPT2_FRZTO_ERR_INT_EN BIT(17) +#define B_BE_WDRLS_RPT2_AGGNUM0_ERR_INT_EN BIT(16) +#define B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN BIT(13) +#define B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN BIT(12) +#define B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN BIT(8) +#define B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN BIT(5) +#define B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN BIT(4) +#define B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN BIT(2) +#define B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN BIT(1) +#define B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN BIT(0) +#define B_BE_WDRLS_ERR_IMR_CLR (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) +#define B_BE_WDRLS_ERR_IMR_SET (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) + +#define R_BE_RLSRPT0_CFG1 0x9444 +#define B_BE_RLSRPT0_FLTR_MAP_MASK GENMASK(27, 24) +#define S_BE_WDRLS_FLTR_TXOK 1 +#define S_BE_WDRLS_FLTR_RTYLMT 2 +#define S_BE_WDRLS_FLTR_LIFTIM 4 +#define S_BE_WDRLS_FLTR_MACID 8 +#define B_BE_RLSRPT0_TO_MASK GENMASK(23, 16) +#define B_BE_RLSRPT0_AGGNUM_MASK GENMASK(7, 0) + +#define R_BE_BBRPT_COM_ERR_IMR 0x9608 +#define B_BE_BBRPT_COM_EVT01_ISR_EN BIT(1) +#define B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN BIT(0) +#define B_BE_BBRPT_COM_ERR_IMR_CLR (B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN | \ + B_BE_BBRPT_COM_EVT01_ISR_EN) +#define B_BE_BBRPT_COM_ERR_IMR_SET B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN + +#define R_BE_BBRPT_CHINFO_ERR_IMR 0x9628 +#define B_BE_ERR_BB_ONETEN_INT_EN BIT(1) +#define B_BE_ERR_GEN_FRZTO_INT_EN BIT(0) +#define B_BE_BBRPT_CHINFO_ERR_IMR_CLR (B_BE_ERR_GEN_FRZTO_INT_EN | \ + B_BE_ERR_BB_ONETEN_INT_EN) +#define B_BE_BBRPT_CHINFO_ERR_IMR_SET (B_BE_ERR_GEN_FRZTO_INT_EN | \ + B_BE_ERR_BB_ONETEN_INT_EN) + +#define R_BE_BBRPT_DFS_ERR_IMR 0x9638 +#define B_BE_BBRPT_DFS_TO_ERR_INT_EN BIT(0) +#define B_BE_BBRPT_DFS_ERR_IMR_CLR B_BE_BBRPT_DFS_TO_ERR_INT_EN +#define B_BE_BBRPT_DFS_ERR_IMR_SET B_BE_BBRPT_DFS_TO_ERR_INT_EN + +#define R_BE_LA_ERRFLAG_IMR 0x9668 +#define B_BE_LA_IMR_DATA_LOSS BIT(0) +#define B_BE_LA_ERRFLAG_IMR_CLR B_BE_LA_IMR_DATA_LOSS +#define B_BE_LA_ERRFLAG_IMR_SET B_BE_LA_IMR_DATA_LOSS + +#define R_BE_CH_INFO_DBGFLAG_IMR 0x9688 +#define B_BE_BCHN_EVT01_ISR_EN BIT(29) +#define B_BE_BCHN_REQTO_ISR_EN BIT(28) +#define B_BE_CHIF_RXDATA_AFACT_ISR_EN BIT(11) +#define B_BE_CHIF_RXDATA_BFACT_ISR_EN BIT(10) +#define B_BE_CHIF_HDR_SEGLEN_ISR_EN BIT(9) +#define B_BE_CHIF_HDR_INVLD_ISR_EN BIT(8) +#define B_BE_CHIF_BBONL_BFACT_ISR_EN BIT(4) +#define B_BE_CHIF_RPT_OVF_ISR_EN BIT(3) +#define B_BE_DBG_CHIF_DATA_LOSS_ISR_EN BIT(2) +#define B_BE_CHIF_DATA_WTOUT_ISR_EN BIT(1) +#define B_BE_CHIF_RPT_WTOUT_ISR_EN BIT(0) +#define B_BE_CH_INFO_DBGFLAG_IMR_CLR (B_BE_CHIF_RPT_WTOUT_ISR_EN | \ + B_BE_CHIF_DATA_WTOUT_ISR_EN | \ + B_BE_DBG_CHIF_DATA_LOSS_ISR_EN | \ + B_BE_CHIF_RPT_OVF_ISR_EN | \ + B_BE_CHIF_HDR_INVLD_ISR_EN | \ + B_BE_CHIF_HDR_SEGLEN_ISR_EN | \ + B_BE_CHIF_RXDATA_BFACT_ISR_EN | \ + B_BE_CHIF_RXDATA_AFACT_ISR_EN) +#define B_BE_CH_INFO_DBGFLAG_IMR_SET 0 + #define R_BE_WD_BUF_REQ 0x9800 #define B_BE_WD_BUF_REQ_EXEC BIT(31) #define B_BE_WD_BUF_REQ_QUOTA_ID_MASK GENMASK(23, 16) @@ -4403,6 +4992,144 @@ #define B_BE_PL_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16) #define B_BE_PL_CPUQ_OP_PKTID_MASK GENMASK(11, 0) +#define R_BE_CPUIO_ERR_IMR 0x9888 +#define B_BE_PLEQUE_OP_ERR_INT_EN BIT(12) +#define B_BE_PLEBUF_OP_ERR_INT_EN BIT(8) +#define B_BE_WDEQUE_OP_ERR_INT_EN BIT(4) +#define B_BE_WDEBUF_OP_ERR_INT_EN BIT(0) +#define B_BE_CPUIO_ERR_IMR_CLR (B_BE_WDEBUF_OP_ERR_INT_EN | \ + B_BE_WDEQUE_OP_ERR_INT_EN | \ + B_BE_PLEBUF_OP_ERR_INT_EN | \ + B_BE_PLEQUE_OP_ERR_INT_EN) +#define B_BE_CPUIO_ERR_IMR_SET (B_BE_WDEBUF_OP_ERR_INT_EN | \ + B_BE_WDEQUE_OP_ERR_INT_EN | \ + B_BE_PLEBUF_OP_ERR_INT_EN | \ + B_BE_PLEQUE_OP_ERR_INT_EN) + +#define R_BE_PKTIN_ERR_IMR 0x9A20 +#define B_BE_SW_MERGE_ERR_INT_EN BIT(1) +#define B_BE_GET_NULL_PKTID_ERR_INT_EN BIT(0) +#define B_BE_PKTIN_ERR_IMR_CLR (B_BE_SW_MERGE_ERR_INT_EN | \ + B_BE_GET_NULL_PKTID_ERR_INT_EN) +#define B_BE_PKTIN_ERR_IMR_SET (B_BE_SW_MERGE_ERR_INT_EN | \ + B_BE_GET_NULL_PKTID_ERR_INT_EN) + +#define R_BE_MPDU_TX_ERR_IMR 0x9BF4 +#define B_BE_TX_TIMEOUT_ERR_EN BIT(0) +#define B_BE_MPDU_TX_ERR_IMR_CLR B_BE_TX_TIMEOUT_ERR_EN +#define B_BE_MPDU_TX_ERR_IMR_SET 0 + +#define R_BE_MPDU_RX_ERR_IMR 0x9CF4 +#define B_BE_LEN_ERR_IMR BIT(3) +#define B_BE_TIMEOUT_ERR_IMR BIT(1) +#define B_BE_MPDU_RX_ERR_IMR_CLR B_BE_TIMEOUT_ERR_IMR +#define B_BE_MPDU_RX_ERR_IMR_SET 0 + +#define R_BE_SEC_ERROR_IMR 0x9D2C +#define B_BE_QUEUE_OPERATION_HANG_IMR BIT(4) +#define B_BE_SEC1_RX_HANG_IMR BIT(3) +#define B_BE_SEC1_TX_HANG_IMR BIT(2) +#define B_BE_RX_HANG_IMR BIT(1) +#define B_BE_TX_HANG_IMR BIT(0) +#define B_BE_SEC_ERROR_IMR_CLR (B_BE_TX_HANG_IMR | \ + B_BE_RX_HANG_IMR | \ + B_BE_SEC1_TX_HANG_IMR | \ + B_BE_SEC1_RX_HANG_IMR | \ + B_BE_QUEUE_OPERATION_HANG_IMR) +#define B_BE_SEC_ERROR_IMR_SET (B_BE_TX_HANG_IMR | \ + B_BE_RX_HANG_IMR | \ + B_BE_SEC1_TX_HANG_IMR | \ + B_BE_SEC1_RX_HANG_IMR | \ + B_BE_QUEUE_OPERATION_HANG_IMR) + +#define R_BE_TXPKTCTL_B0_ERRFLAG_IMR 0x9F78 +#define B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN BIT(25) +#define B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD BIT(24) +#define B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG BIT(17) +#define B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR BIT(16) +#define B_BE_B0_IMR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_BE_B0_IMR_ERR_CMDPSR_FRZTO BIT(10) +#define B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_BE_B0_IMR_ERR_USRCTL_NOINIT BIT(1) +#define B_BE_B0_IMR_ERR_USRCTL_REINIT BIT(0) +#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR (B_BE_B0_IMR_ERR_USRCTL_REINIT | \ + B_BE_B0_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD | \ + B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN | \ + B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG) +#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET (B_BE_B0_IMR_ERR_USRCTL_REINIT | \ + B_BE_B0_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG) + +#define R_BE_TXPKTCTL_B1_ERRFLAG_IMR 0x9FB8 +#define B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN BIT(25) +#define B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD BIT(24) +#define B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG BIT(17) +#define B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR BIT(16) +#define B_BE_B1_IMR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_BE_B1_IMR_ERR_CMDPSR_FRZTO BIT(10) +#define B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_BE_B1_IMR_ERR_USRCTL_NOINIT BIT(1) +#define B_BE_B1_IMR_ERR_USRCTL_REINIT BIT(0) +#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR (B_BE_B1_IMR_ERR_USRCTL_REINIT | \ + B_BE_B1_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD | \ + B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN | \ + B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG) +#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET (B_BE_B1_IMR_ERR_USRCTL_REINIT | \ + B_BE_B1_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG) + +#define R_BE_MLO_ERR_IDCT_IMR 0xA128 +#define B_BE_MLO_ERR_IDCT_IMR_0 BIT(31) +#define B_BE_MLO_ERR_IDCT_IMR_1 BIT(30) +#define B_BE_MLO_ERR_IDCT_IMR_2 BIT(29) +#define B_BE_MLO_ERR_IDCT_IMR_3 BIT(28) +#define B_BE_MLO_ERR_IDCT_IMR_CLR (B_BE_MLO_ERR_IDCT_IMR_2 | \ + B_BE_MLO_ERR_IDCT_IMR_1 | \ + B_BE_MLO_ERR_IDCT_IMR_0) +#define B_BE_MLO_ERR_IDCT_IMR_SET (B_BE_MLO_ERR_IDCT_IMR_2 | \ + B_BE_MLO_ERR_IDCT_IMR_1 | \ + B_BE_MLO_ERR_IDCT_IMR_0) + +#define R_BE_PLRLS_ERR_IMR 0xA218 +#define B_BE_PLRLS_CTL_FRZTO_IMR BIT(0) +#define B_BE_PLRLS_ERR_IMR_CLR B_BE_PLRLS_CTL_FRZTO_IMR +#define B_BE_PLRLS_ERR_IMR_SET B_BE_PLRLS_CTL_FRZTO_IMR + +#define R_BE_INTERRUPT_MASK_REG 0xA3F0 +#define B_BE_PLE_B_PKTID_ERR_IMR BIT(2) +#define B_BE_RPT_TIMEOUT_IMR BIT(1) +#define B_BE_SEARCH_TIMEOUT_IMR BIT(0) +#define B_BE_INTERRUPT_MASK_REG_CLR (B_BE_SEARCH_TIMEOUT_IMR | \ + B_BE_RPT_TIMEOUT_IMR | \ + B_BE_PLE_B_PKTID_ERR_IMR) +#define B_BE_INTERRUPT_MASK_REG_SET (B_BE_SEARCH_TIMEOUT_IMR | \ + B_BE_RPT_TIMEOUT_IMR | \ + B_BE_PLE_B_PKTID_ERR_IMR) + #define R_BE_HAXI_INIT_CFG1 0xB000 #define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) #define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) @@ -4443,6 +5170,30 @@ #define B_BE_STOP_CH1 BIT(1) #define B_BE_STOP_CH0 BIT(0) +#define R_BE_HAXI_IDCT_MSK 0xB0B8 +#define B_BE_HAXI_RRESP_ERR_IDCT_MSK BIT(7) +#define B_BE_HAXI_BRESP_ERR_IDCT_MSK BIT(6) +#define B_BE_RXDMA_ERR_FLAG_IDCT_MSK BIT(5) +#define B_BE_SET_FC_ERROR_FLAG_IDCT_MSK BIT(4) +#define B_BE_TXBD_LEN0_ERR_IDCT_MSK BIT(3) +#define B_BE_TXBD_4KBOUND_ERR_IDCT_MSK BIT(2) +#define B_BE_RXMDA_STUCK_IDCT_MSK BIT(1) +#define B_BE_TXMDA_STUCK_IDCT_MSK BIT(0) +#define B_BE_HAXI_IDCT_MSK_CLR (B_BE_TXMDA_STUCK_IDCT_MSK | \ + B_BE_RXMDA_STUCK_IDCT_MSK | \ + B_BE_TXBD_LEN0_ERR_IDCT_MSK | \ + B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \ + B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \ + B_BE_HAXI_BRESP_ERR_IDCT_MSK | \ + B_BE_HAXI_RRESP_ERR_IDCT_MSK) +#define B_BE_HAXI_IDCT_MSK_SET (B_BE_TXMDA_STUCK_IDCT_MSK | \ + B_BE_RXMDA_STUCK_IDCT_MSK | \ + B_BE_TXBD_LEN0_ERR_IDCT_MSK | \ + B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \ + B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \ + B_BE_HAXI_BRESP_ERR_IDCT_MSK | \ + B_BE_HAXI_RRESP_ERR_IDCT_MSK) + #define R_BE_HCI_FC_CTRL 0xB700 #define B_BE_WD_PAGE_MODE_MASK GENMASK(17, 16) #define B_BE_HCI_FC_CH14_FULL_COND_MASK GENMASK(15, 14) @@ -4539,6 +5290,12 @@ #define B_BE_SET_MUEDCATIMER_TF_0 BIT(4) #define B_BE_MUEDCA_EN_0 BIT(0) +#define R_BE_SCHEDULE_ERR_IMR 0x103E8 +#define R_BE_SCHEDULE_ERR_IMR_C1 0x143E8 +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_SCHEDULE_ERR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN +#define B_BE_SCHEDULE_ERR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN + #define R_BE_PORT_CFG_P0 0x10400 #define R_BE_PORT_CFG_P0_C1 0x14400 #define B_BE_BCN_ERLY_SORT_EN_P0 BIT(18) @@ -4677,6 +5434,248 @@ #define R_BE_PTCL_BSS_COLOR_1_C1 0x148A4 #define B_BE_BSS_COLOB_BE_PORT_4_MASK GENMASK(5, 0) +#define R_BE_PTCL_IMR_2 0x108B8 +#define R_BE_PTCL_IMR_2_C1 0x148B8 +#define B_BE_NO_TRX_TIMEOUT_IMR BIT(1) +#define B_BE_TX_IDLE_TIMEOUT_IMR BIT(0) +#define B_BE_PTCL_IMR_2_CLR B_BE_TX_IDLE_TIMEOUT_IMR +#define B_BE_PTCL_IMR_2_SET 0 + +#define R_BE_PTCL_IMR0 0x108C0 +#define R_BE_PTCL_IMR0_C1 0x148C0 +#define B_BE_PTCL_ERROR_FLAG_IMR BIT(31) +#define B_BE_FSM1_TIMEOUT_ERR_INT_EN BIT(1) +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_PTCL_IMR0_CLR (B_BE_FSM_TIMEOUT_ERR_INT_EN | \ + B_BE_FSM1_TIMEOUT_ERR_INT_EN | \ + B_BE_PTCL_ERROR_FLAG_IMR) +#define B_BE_PTCL_IMR0_SET (B_BE_FSM_TIMEOUT_ERR_INT_EN | \ + B_BE_FSM1_TIMEOUT_ERR_INT_EN | \ + B_BE_PTCL_ERROR_FLAG_IMR) + +#define R_BE_PTCL_IMR1 0x108C8 +#define R_BE_PTCL_IMR1_C1 0x148C8 +#define B_BE_F2PCMD_PKTID_IMR BIT(30) +#define B_BE_F2PCMD_RD_PKTID_IMR BIT(29) +#define B_BE_F2PCMD_ASSIGN_PKTID_IMR BIT(28) +#define B_BE_F2PCMD_USER_ALLC_IMR BIT(27) +#define B_BE_RX_SPF_U0_PKTID_IMR BIT(26) +#define B_BE_TX_SPF_U1_PKTID_IMR BIT(25) +#define B_BE_TX_SPF_U2_PKTID_IMR BIT(24) +#define B_BE_TX_SPF_U3_PKTID_IMR BIT(23) +#define B_BE_TX_RECORD_PKTID_IMR BIT(22) +#define B_BE_TWTSP_QSEL_IMR BIT(14) +#define B_BE_F2P_RLS_CTN_SEL_IMR BIT(13) +#define B_BE_BCNQ_ORDER_IMR BIT(12) +#define B_BE_Q_PKTID_IMR BIT(11) +#define B_BE_D_PKTID_IMR BIT(10) +#define B_BE_TXPRT_FULL_DROP_IMR BIT(9) +#define B_BE_F2PCMDRPT_FULL_DROP_IMR BIT(8) +#define B_BE_PTCL_IMR1_CLR (B_BE_F2PCMDRPT_FULL_DROP_IMR | \ + B_BE_TXPRT_FULL_DROP_IMR | \ + B_BE_D_PKTID_IMR | \ + B_BE_Q_PKTID_IMR | \ + B_BE_BCNQ_ORDER_IMR | \ + B_BE_F2P_RLS_CTN_SEL_IMR | \ + B_BE_TWTSP_QSEL_IMR | \ + B_BE_TX_RECORD_PKTID_IMR | \ + B_BE_TX_SPF_U3_PKTID_IMR | \ + B_BE_TX_SPF_U2_PKTID_IMR | \ + B_BE_TX_SPF_U1_PKTID_IMR | \ + B_BE_RX_SPF_U0_PKTID_IMR | \ + B_BE_F2PCMD_USER_ALLC_IMR | \ + B_BE_F2PCMD_ASSIGN_PKTID_IMR | \ + B_BE_F2PCMD_RD_PKTID_IMR | \ + B_BE_F2PCMD_PKTID_IMR) +#define B_BE_PTCL_IMR1_SET B_BE_F2PCMD_USER_ALLC_IMR + +#define R_BE_RX_ERROR_FLAG_IMR 0x10C04 +#define R_BE_RX_ERROR_FLAG_IMR_C1 0x14C04 +#define B_BE_RX_CSI_NOT_RELEASE_ERROR_IMR BIT(31) +#define B_BE_RX_GET_NULL_PKT_ERROR_IMR BIT(30) +#define B_BE_RX_RU0_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_RX_RU1_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_RX_RU2_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_RX_RU3_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_RX_RU4_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_RX_RU5_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_RX_RU6_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_RX_RU7_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR BIT(21) +#define B_BE_RX_CSI_FSM_HANG_ERROR_IMR BIT(20) +#define B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR BIT(19) +#define B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR BIT(18) +#define B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR BIT(17) +#define B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR BIT(16) +#define B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR BIT(15) +#define B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR BIT(14) +#define B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR BIT(13) +#define B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR BIT(12) +#define B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR BIT(11) +#define B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR BIT(10) +#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR BIT(9) +#define B_BE_RX_CSI_ZERO_LENGTH_ERROR_IMR BIT(8) +#define B_BE_PLE_DATA_OPT_FSM_HANG_IMR BIT(7) +#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG_IMR BIT(6) +#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG_IMR BIT(5) +#define B_BE_PLE_WD_OPT_FSM_HANG_IMR BIT(4) +#define B_BE_PLE_ENQ_FSM_HANG_IMR BIT(3) +#define B_BE_RXDATA_ENQUE_ORDER_ERROR_IMR BIT(2) +#define B_BE_RXSTS_ENQUE_ORDER_ERROR_IMR BIT(1) +#define B_BE_RX_CSI_PKT_NUM_ERROR_IMR BIT(0) +#define B_BE_RX_ERROR_FLAG_IMR_CLR (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \ + B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \ + B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ + B_BE_RX_GET_NULL_PKT_ERROR_IMR) +#define B_BE_RX_ERROR_FLAG_IMR_SET (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \ + B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \ + B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ + B_BE_RX_GET_NULL_PKT_ERROR_IMR) + +#define R_BE_TX_ERROR_FLAG_IMR 0x10C70 +#define R_BE_TX_ERROR_FLAG_IMR_C1 0x14C70 +#define B_BE_TX_RU0_FSM_HANG_ERROR_IMR BIT(31) +#define B_BE_TX_RU1_FSM_HANG_ERROR_IMR BIT(30) +#define B_BE_TX_RU2_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_TX_RU3_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_TX_RU4_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_TX_RU5_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_TX_RU6_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_TX_RU7_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_TX_RU8_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_TX_RU9_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_TX_RU10_FSM_HANG_ERROR_IMR BIT(21) +#define B_BE_TX_RU11_FSM_HANG_ERROR_IMR BIT(20) +#define B_BE_TX_RU12_FSM_HANG_ERROR_IMR BIT(19) +#define B_BE_TX_RU13_FSM_HANG_ERROR_IMR BIT(18) +#define B_BE_TX_RU14_FSM_HANG_ERROR_IMR BIT(17) +#define B_BE_TX_RU15_FSM_HANG_ERROR_IMR BIT(16) +#define B_BE_TX_CSI_FSM_HANG_ERROR_IMR BIT(15) +#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR BIT(14) +#define B_BE_TX_ERROR_FLAG_IMR_CLR (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \ + B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU0_FSM_HANG_ERROR_IMR) +#define B_BE_TX_ERROR_FLAG_IMR_SET (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \ + B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU0_FSM_HANG_ERROR_IMR) + +#define R_BE_RX_ERROR_FLAG_IMR_1 0x10C88 +#define R_BE_RX_ERROR_FLAG_IMR_1_C1 0x14C88 +#define B_BE_RX_RU8_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_RX_RU9_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_RX_RU10_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_RX_RU11_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_RX_RU12_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_RX_RU13_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_RX_RU14_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_RX_RU15_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR BIT(17) +#define B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR BIT(16) +#define B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR BIT(15) +#define B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR BIT(14) +#define B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR BIT(13) +#define B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR BIT(12) +#define B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR BIT(11) +#define B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR BIT(10) +#define B_BE_TX_ERROR_FLAG_IMR_1_CLR (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR) +#define B_BE_TX_ERROR_FLAG_IMR_1_SET (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR) + #define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL 0x10E08 #define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL_C1 0x14E08 #define B_BE_TSFT_OFS_MASK GENMASK(31, 16) @@ -4684,6 +5683,64 @@ #define B_BE_UPD_HGQMD BIT(1) #define B_BE_UPD_TIMIE BIT(0) +#define R_BE_TRXPTCL_ERROR_INDICA_MASK 0x110BC +#define R_BE_TRXPTCL_ERROR_INDICA_MASK_C1 0x150BC +#define B_BE_WMAC_FTM_TIMEOUT_MODE BIT(30) +#define B_BE_WMAC_FTM_TIMEOUT_THR_MASK GENMASK(29, 24) +#define B_BE_WMAC_MODE BIT(22) +#define B_BE_WMAC_TIMETOUT_THR_MASK GENMASK(21, 16) +#define B_BE_RMAC_BFMER BIT(9) +#define B_BE_RMAC_FTM BIT(8) +#define B_BE_RMAC_CSI BIT(7) +#define B_BE_TMAC_MIMO_CTRL BIT(6) +#define B_BE_TMAC_RXTB BIT(5) +#define B_BE_TMAC_HWSIGB_GEN BIT(4) +#define B_BE_TMAC_TXPLCP BIT(3) +#define B_BE_TMAC_RESP BIT(2) +#define B_BE_TMAC_TXCTL BIT(1) +#define B_BE_TMAC_MACTX BIT(0) +#define B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR (B_BE_TMAC_MACTX | \ + B_BE_TMAC_TXCTL | \ + B_BE_TMAC_RESP | \ + B_BE_TMAC_TXPLCP | \ + B_BE_TMAC_HWSIGB_GEN | \ + B_BE_TMAC_RXTB | \ + B_BE_TMAC_MIMO_CTRL | \ + B_BE_RMAC_CSI | \ + B_BE_RMAC_FTM | \ + B_BE_RMAC_BFMER) +#define B_BE_TRXPTCL_ERROR_INDICA_MASK_SET (B_BE_TMAC_MACTX | \ + B_BE_TMAC_TXCTL | \ + B_BE_TMAC_RESP | \ + B_BE_TMAC_TXPLCP | \ + B_BE_TMAC_HWSIGB_GEN | \ + B_BE_TMAC_RXTB | \ + B_BE_TMAC_MIMO_CTRL | \ + B_BE_RMAC_CSI | \ + B_BE_RMAC_FTM | \ + B_BE_RMAC_BFMER) + +#define R_BE_PHYINFO_ERR_IMR_V1 0x110F8 +#define R_BE_PHYINFO_ERR_IMR_V1_C1 0x150F8 +#define B_BE_PHYINTF_RXTB_WIDTH_MASK GENMASK(31, 30) +#define B_BE_PHYINTF_RXTB_EN_PHASE_MASK GENMASK(29, 28) +#define B_BE_PHYINTF_MIMO_WIDTH_MASK GENMASK(27, 26) +#define B_BE_PHYINTF_MIMO_EN_PHASE_MASK GENMASK(25, 24) +#define B_BE_PHYINTF_TIMEOUT_THR_V1_MASK GENMASK(21, 16) +#define B_BE_CSI_ON_TIMEOUT_EN BIT(5) +#define B_BE_STS_ON_TIMEOUT_EN BIT(4) +#define B_BE_DATA_ON_TIMEOUT_EN BIT(3) +#define B_BE_OFDM_CCA_TIMEOUT_EN BIT(2) +#define B_BE_CCK_CCA_TIMEOUT_EN BIT(1) +#define B_BE_PHY_TXON_TIMEOUT_EN BIT(0) +#define B_BE_PHYINFO_ERR_IMR_V1_CLR (B_BE_PHY_TXON_TIMEOUT_EN | \ + B_BE_CCK_CCA_TIMEOUT_EN | \ + B_BE_OFDM_CCA_TIMEOUT_EN | \ + B_BE_DATA_ON_TIMEOUT_EN | \ + B_BE_STS_ON_TIMEOUT_EN | \ + B_BE_CSI_ON_TIMEOUT_EN) +#define B_BE_PHYINFO_ERR_IMR_V1_SET 0 + #define R_BE_BFMEE_RESP_OPTION 0x11180 #define R_BE_BFMEE_RESP_OPTION_C1 0x15180 #define B_BE_BFMEE_CSI_SEC_TYPE_SH 20 @@ -4764,6 +5821,77 @@ #define B_BE_CSIPRT_HESU_AID_EN BIT(25) #define B_BE_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_BE_RX_ERR_IMR 0x114F8 +#define R_BE_RX_ERR_IMR_C1 0x154F8 +#define B_BE_RX_ERR_TRIG_ACT_TO_MSK BIT(9) +#define B_BE_RX_ERR_STS_ACT_TO_MSK BIT(8) +#define B_BE_RX_ERR_CSI_ACT_TO_MSK BIT(7) +#define B_BE_RX_ERR_ACT_TO_MSK BIT(6) +#define B_BE_CSI_DATAON_ASSERT_TO_MSK BIT(5) +#define B_BE_DATAON_ASSERT_TO_MSK BIT(4) +#define B_BE_CCA_ASSERT_TO_MSK BIT(3) +#define B_BE_RX_ERR_DMA_TO_MSK BIT(2) +#define B_BE_RX_ERR_DATA_TO_MSK BIT(1) +#define B_BE_RX_ERR_CCA_TO_MSK BIT(0) +#define B_BE_RX_ERR_IMR_CLR (B_BE_RX_ERR_CCA_TO_MSK | \ + B_BE_RX_ERR_DATA_TO_MSK | \ + B_BE_RX_ERR_DMA_TO_MSK | \ + B_BE_CCA_ASSERT_TO_MSK | \ + B_BE_DATAON_ASSERT_TO_MSK | \ + B_BE_CSI_DATAON_ASSERT_TO_MSK | \ + B_BE_RX_ERR_ACT_TO_MSK | \ + B_BE_RX_ERR_CSI_ACT_TO_MSK | \ + B_BE_RX_ERR_STS_ACT_TO_MSK | \ + B_BE_RX_ERR_TRIG_ACT_TO_MSK) +#define B_BE_RX_ERR_IMR_SET (B_BE_RX_ERR_ACT_TO_MSK | \ + B_BE_RX_ERR_STS_ACT_TO_MSK | \ + B_BE_RX_ERR_TRIG_ACT_TO_MSK) + +#define R_BE_RESP_IMR 0x11884 +#define R_BE_RESP_IMR_C1 0x15884 +#define B_BE_RESP_TBL_FLAG_ERR_ISR_EN BIT(17) +#define B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN BIT(16) +#define B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN BIT(15) +#define B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN BIT(14) +#define B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN BIT(13) +#define B_BE_RESP_PLDID_RDY_ERR_ISR_EN BIT(12) +#define B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN BIT(11) +#define B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN BIT(10) +#define B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN BIT(9) +#define B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN BIT(8) +#define B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN BIT(6) +#define B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN BIT(5) +#define B_BE_RESP_TXCMD_TBL_ERR_ISR_EN BIT(4) +#define B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN BIT(3) +#define B_BE_RESP_INITCMD_RESERVD_PAGE_ABORT_ERR_ISR_EN BIT(2) +#define B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN BIT(1) +#define B_BE_RESP_DMAC_PROC_ERR_ISR_EN BIT(0) +#define B_BE_RESP_IMR_CLR (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN | \ + B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \ + B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ + B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN | \ + B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN | \ + B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ + B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) +#define B_BE_RESP_IMR_SET (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \ + B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ + B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ + B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) + #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 @@ -4775,6 +5903,12 @@ #define R_BE_PWR_RU_LMT 0x12048 #define R_BE_PWR_RU_LMT_MAX 0x120E4 +#define R_BE_C0_TXPWR_IMR 0x128E0 +#define R_BE_C0_TXPWR_IMR_C1 0x168E0 +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_C0_TXPWR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN +#define B_BE_C0_TXPWR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN + #define CMAC1_START_ADDR_BE 0x14000 #define CMAC1_END_ADDR_BE 0x17FFF diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index e850e34be51f..5c167a9278ce 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2454,6 +2454,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dcfo_comp = &rtw8851b_dcfo_comp, .dcfo_comp_sft = 12, .imr_info = &rtw8851b_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8851b_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 90f39a8791ea..0c76c52ce22c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2191,6 +2191,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dcfo_comp = &rtw8852a_dcfo_comp, .dcfo_comp_sft = 10, .imr_info = &rtw8852a_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852a_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 7b2062cc8499..de887a35f3fb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2625,6 +2625,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dcfo_comp = &rtw8852b_dcfo_comp, .dcfo_comp_sft = 10, .imr_info = &rtw8852b_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852b_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index d618faf1885b..8618d0204f66 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2964,6 +2964,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dcfo_comp = &rtw8852c_dcfo_comp, .dcfo_comp_sft = 12, .imr_info = &rtw8852c_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852c_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index a82c17fb1281..398f8e48b7f3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -63,6 +63,62 @@ static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_reg_imr rtw8922a_imr_dmac_regs[] = { + {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR, B_BE_DISP_HOST_IMR_SET}, + {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR, B_BE_DISP_CPU_IMR_SET}, + {R_BE_DISP_OTHER_IMR, B_BE_DISP_OTHER_IMR_CLR, B_BE_DISP_OTHER_IMR_SET}, + {R_BE_PKTIN_ERR_IMR, B_BE_PKTIN_ERR_IMR_CLR, B_BE_PKTIN_ERR_IMR_SET}, + {R_BE_INTERRUPT_MASK_REG, B_BE_INTERRUPT_MASK_REG_CLR, B_BE_INTERRUPT_MASK_REG_SET}, + {R_BE_MLO_ERR_IDCT_IMR, B_BE_MLO_ERR_IDCT_IMR_CLR, B_BE_MLO_ERR_IDCT_IMR_SET}, + {R_BE_MPDU_TX_ERR_IMR, B_BE_MPDU_TX_ERR_IMR_CLR, B_BE_MPDU_TX_ERR_IMR_SET}, + {R_BE_MPDU_RX_ERR_IMR, B_BE_MPDU_RX_ERR_IMR_CLR, B_BE_MPDU_RX_ERR_IMR_SET}, + {R_BE_SEC_ERROR_IMR, B_BE_SEC_ERROR_IMR_CLR, B_BE_SEC_ERROR_IMR_SET}, + {R_BE_CPUIO_ERR_IMR, B_BE_CPUIO_ERR_IMR_CLR, B_BE_CPUIO_ERR_IMR_SET}, + {R_BE_WDE_ERR_IMR, B_BE_WDE_ERR_IMR_CLR, B_BE_WDE_ERR_IMR_SET}, + {R_BE_WDE_ERR1_IMR, B_BE_WDE_ERR1_IMR_CLR, B_BE_WDE_ERR1_IMR_SET}, + {R_BE_PLE_ERR_IMR, B_BE_PLE_ERR_IMR_CLR, B_BE_PLE_ERR_IMR_SET}, + {R_BE_PLE_ERRFLAG1_IMR, B_BE_PLE_ERRFLAG1_IMR_CLR, B_BE_PLE_ERRFLAG1_IMR_SET}, + {R_BE_WDRLS_ERR_IMR, B_BE_WDRLS_ERR_IMR_CLR, B_BE_WDRLS_ERR_IMR_SET}, + {R_BE_TXPKTCTL_B0_ERRFLAG_IMR, B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR, + B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET}, + {R_BE_TXPKTCTL_B1_ERRFLAG_IMR, B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR, + B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET}, + {R_BE_BBRPT_COM_ERR_IMR, B_BE_BBRPT_COM_ERR_IMR_CLR, B_BE_BBRPT_COM_ERR_IMR_SET}, + {R_BE_BBRPT_CHINFO_ERR_IMR, B_BE_BBRPT_CHINFO_ERR_IMR_CLR, + B_BE_BBRPT_CHINFO_ERR_IMR_SET}, + {R_BE_BBRPT_DFS_ERR_IMR, B_BE_BBRPT_DFS_ERR_IMR_CLR, B_BE_BBRPT_DFS_ERR_IMR_SET}, + {R_BE_LA_ERRFLAG_IMR, B_BE_LA_ERRFLAG_IMR_CLR, B_BE_LA_ERRFLAG_IMR_SET}, + {R_BE_CH_INFO_DBGFLAG_IMR, B_BE_CH_INFO_DBGFLAG_IMR_CLR, B_BE_CH_INFO_DBGFLAG_IMR_SET}, + {R_BE_PLRLS_ERR_IMR, B_BE_PLRLS_ERR_IMR_CLR, B_BE_PLRLS_ERR_IMR_SET}, + {R_BE_HAXI_IDCT_MSK, B_BE_HAXI_IDCT_MSK_CLR, B_BE_HAXI_IDCT_MSK_SET}, +}; + +static const struct rtw89_imr_table rtw8922a_imr_dmac_table = { + .regs = rtw8922a_imr_dmac_regs, + .n_regs = ARRAY_SIZE(rtw8922a_imr_dmac_regs), +}; + +static const struct rtw89_reg_imr rtw8922a_imr_cmac_regs[] = { + {R_BE_RESP_IMR, B_BE_RESP_IMR_CLR, B_BE_RESP_IMR_SET}, + {R_BE_RX_ERROR_FLAG_IMR, B_BE_RX_ERROR_FLAG_IMR_CLR, B_BE_RX_ERROR_FLAG_IMR_SET}, + {R_BE_TX_ERROR_FLAG_IMR, B_BE_TX_ERROR_FLAG_IMR_CLR, B_BE_TX_ERROR_FLAG_IMR_SET}, + {R_BE_RX_ERROR_FLAG_IMR_1, B_BE_TX_ERROR_FLAG_IMR_1_CLR, B_BE_TX_ERROR_FLAG_IMR_1_SET}, + {R_BE_PTCL_IMR1, B_BE_PTCL_IMR1_CLR, B_BE_PTCL_IMR1_SET}, + {R_BE_PTCL_IMR0, B_BE_PTCL_IMR0_CLR, B_BE_PTCL_IMR0_SET}, + {R_BE_PTCL_IMR_2, B_BE_PTCL_IMR_2_CLR, B_BE_PTCL_IMR_2_SET}, + {R_BE_SCHEDULE_ERR_IMR, B_BE_SCHEDULE_ERR_IMR_CLR, B_BE_SCHEDULE_ERR_IMR_SET}, + {R_BE_C0_TXPWR_IMR, B_BE_C0_TXPWR_IMR_CLR, B_BE_C0_TXPWR_IMR_SET}, + {R_BE_TRXPTCL_ERROR_INDICA_MASK, B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR, + B_BE_TRXPTCL_ERROR_INDICA_MASK_SET}, + {R_BE_RX_ERR_IMR, B_BE_RX_ERR_IMR_CLR, B_BE_RX_ERR_IMR_SET}, + {R_BE_PHYINFO_ERR_IMR_V1, B_BE_PHYINFO_ERR_IMR_V1_CLR, B_BE_PHYINFO_ERR_IMR_V1_SET}, +}; + +static const struct rtw89_imr_table rtw8922a_imr_cmac_table = { + .regs = rtw8922a_imr_cmac_regs, + .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs), +}; + static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, @@ -399,6 +455,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .dcfo_comp = NULL, .dcfo_comp_sft = 0, .imr_info = NULL, + .imr_dmac_table = &rtw8922a_imr_dmac_table, + .imr_cmac_table = &rtw8922a_imr_cmac_table, .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, .bss_clr_map_reg = R_BSS_CLR_MAP_V2, .dma_ch_mask = 0, From 6f8d36552bab7dc83d8aba89311d6039c53eb6a1 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Mon, 4 Dec 2023 16:07:50 +0800 Subject: [PATCH 3123/7721] wifi: rtw89: 8922a: dump MAC registers when SER occurs To diagnose the reason why firmware or hardware get abnormal, add to dump MAC registers related to counters and interrupt masks. With these values, people can classify problems and check if registers values are unexpected, and then correct them. However, it could possible false alarm because firmware triggers this SER event by wrong conditions that we should correct it at firmware or register settings. In field, SER might happen under special conditions, and very hard to happen again, so dump lots of registers to provide rich information to catch the problem. Signed-off-by: Chia-Yuan Li Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231204080751.15354-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 283 +++++++--- drivers/net/wireless/realtek/rtw89/mac.h | 10 + drivers/net/wireless/realtek/rtw89/mac_be.c | 251 +++++++++ drivers/net/wireless/realtek/rtw89/pci.c | 22 +- drivers/net/wireless/realtek/rtw89/pci.h | 4 + drivers/net/wireless/realtek/rtw89/reg.h | 572 ++++++++++++++++++++ 6 files changed, 1061 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d4812b25c86c..44decdf801a3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -113,8 +113,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) return ret; } -static -int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) +int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) { u32 ctrl_reg, data_reg, ctrl_data; u32 val; @@ -154,8 +153,8 @@ int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) return 0; } -static int dle_dfi_quota(struct rtw89_dev *rtwdev, - struct rtw89_mac_dle_dfi_quota *quota) +int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_quota *quota) { struct rtw89_mac_dle_dfi_ctrl ctrl; int ret; @@ -163,9 +162,9 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev, ctrl.type = quota->dle_type; ctrl.target = DLE_DFI_TYPE_QUOTA; ctrl.addr = quota->qtaid; - ret = dle_dfi_ctrl(rtwdev, &ctrl); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) { - rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + rtw89_warn(rtwdev, "[ERR] dle dfi quota %d\n", ret); return ret; } @@ -183,9 +182,9 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, ctrl.type = qempty->dle_type; ctrl.target = DLE_DFI_TYPE_QEMPTY; ctrl.addr = qempty->grpsel; - ret = dle_dfi_ctrl(rtwdev, &ctrl); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) { - rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + rtw89_warn(rtwdev, "[ERR] dle dfi qempty %d\n", ret); return ret; } @@ -193,7 +192,7 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, return 0; } -static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev) +static void dump_err_status_dispatcher_ax(struct rtw89_dev *rtwdev) { rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ALWAYS_IMR=0x%08x ", rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); @@ -209,7 +208,7 @@ static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev) rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); } -static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) +static void rtw89_mac_dump_qta_lost_ax(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; struct rtw89_mac_dle_dfi_quota quota; @@ -232,19 +231,19 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) ctrl.type = DLE_CTRL_TYPE_PLE; ctrl.target = DLE_DFI_TYPE_QLNKTBL; ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) | - FIELD_PREP(QLNKTBL_ADDR_TBL_IDX_MASK, i); - ret = dle_dfi_ctrl(rtwdev, &ctrl); + u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else - rtw89_info(rtwdev, "qidx%d pktcnt = %ld\n", i, - FIELD_GET(QLNKTBL_DATA_SEL1_PKT_CNT_MASK, - ctrl.out_data)); + rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i, + u32_get_bits(ctrl.out_data, + QLNKTBL_DATA_SEL1_PKT_CNT_MASK)); } quota.dle_type = DLE_CTRL_TYPE_PLE; quota.qtaid = 6; - ret = dle_dfi_quota(rtwdev, "a); + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else @@ -252,33 +251,74 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) quota.rsv_pgnum, quota.use_pgnum); val = rtw89_read32(rtwdev, R_AX_PLE_QTA6_CFG); - rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%lx\n", - FIELD_GET(B_AX_PLE_Q6_MIN_SIZE_MASK, val)); - rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%lx\n", - FIELD_GET(B_AX_PLE_Q6_MAX_SIZE_MASK, val)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q6_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q6_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG)); + rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0)); + rtw89_info(rtwdev, "R_AX_CCA_CONTROL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CCA_CONTROL)); - dump_err_status_dispatcher(rtwdev); + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 7; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_AX_PLE_QTA7_CFG); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q7_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q7_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT_C1); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG_C1)); + rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0_C1)); + rtw89_info(rtwdev, "R_AX_CCA_CONTROL_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CCA_CONTROL_C1)); + } + + rtw89_info(rtwdev, "R_AX_DLE_EMPTY0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DLE_EMPTY0)); + rtw89_info(rtwdev, "R_AX_DLE_EMPTY1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DLE_EMPTY1)); + + dump_err_status_dispatcher_ax(rtwdev); } -static void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, - enum mac_ax_err_info err) +void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 dbg, event; dbg = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO); - event = FIELD_GET(B_AX_L0_TO_L1_EVENT_MASK, dbg); + event = u32_get_bits(dbg, B_AX_L0_TO_L1_EVENT_MASK); switch (event) { case MAC_AX_L0_TO_L1_RX_QTA_LOST: rtw89_info(rtwdev, "quota lost!\n"); - rtw89_mac_dump_qta_lost(rtwdev); + mac->dump_qta_lost(rtwdev); break; default: break; } } -static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) +void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 dmac_err; @@ -358,6 +398,21 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_info(rtwdev, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); } + } else if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_SEC_ERROR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ERROR_FLAG)); + rtw89_info(rtwdev, "R_BE_SEC_ERROR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ERROR_IMR)); + rtw89_info(rtwdev, "R_BE_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ENG_CTRL)); + rtw89_info(rtwdev, "R_BE_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_MPDU_PROC)); + rtw89_info(rtwdev, "R_BE_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_CAM_ACCESS)); + rtw89_info(rtwdev, "R_BE_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_CAM_RDATA)); + rtw89_info(rtwdev, "R_BE_SEC_DEBUG2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_DEBUG2)); } else { rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); @@ -394,10 +449,17 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_INTERRUPT_MASK_REG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_INTERRUPT_MASK_REG)); + rtw89_info(rtwdev, "R_BE_INTERRUPT_STS_REG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_INTERRUPT_STS_REG)); + } else { + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + } } if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { @@ -412,7 +474,7 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { - if (chip->chip_id == RTL8852C) { + if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) { rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", @@ -444,30 +506,41 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1)); rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_2=0x%08x\n", rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2)); - rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", - rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_0=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_1=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_2=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); - rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); - if (chip->chip_id == RTL8852C) { - rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL0)); - rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL1)); - rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_3)); + rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_BE_PLE_CPUQ_OP_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_3)); + rtw89_info(rtwdev, "R_BE_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_STATUS)); } else { - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL0)); + rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL1)); + rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + } else { + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + } } } @@ -479,22 +552,37 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1)); + rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2)); + rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0)); + } else { + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + } } if (dmac_err & B_AX_BBRPT_ERR_FLAG) { - if (chip->chip_id == RTL8852C) { + if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) { rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", @@ -519,18 +607,54 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); } + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_IMR)); + rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_ISR)); + } } - if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { - rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); - rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + if (dmac_err & B_AX_HAXIDMA_ERR_FLAG) { + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_HAXI_IDCT_MSK=0x%08x\n", + rtw89_read32(rtwdev, R_BE_HAXI_IDCT_MSK)); + rtw89_info(rtwdev, "R_BE_HAXI_IDCT=0x%08x\n", + rtw89_read32(rtwdev, R_BE_HAXI_IDCT)); + } else if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + } + } + + if (dmac_err & B_BE_P_AXIDMA_ERR_INT) { + rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT_MSK=0x%08x\n", + rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT_MSK, + RTW89_MAC_MEM_AXIDMA)); + rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT=0x%08x\n", + rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT, + RTW89_MAC_MEM_AXIDMA)); + } + + if (dmac_err & B_BE_MLO_ERR_INT) { + rtw89_info(rtwdev, "R_BE_MLO_ERR_IDCT_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_IMR)); + rtw89_info(rtwdev, "R_BE_PKTIN_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_ISR)); + } + + if (dmac_err & B_BE_PLRLS_ERR_INT) { + rtw89_info(rtwdev, "R_BE_PLRLS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PLRLS_ERR_IMR)); + rtw89_info(rtwdev, "R_BE_PLRLS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PLRLS_ERR_ISR)); } } -static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, - u8 band) +static void rtw89_mac_dump_cmac_err_status_ax(struct rtw89_dev *rtwdev, + u8 band) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 offset = 0; @@ -620,8 +744,8 @@ static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); } -static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, - enum mac_ax_err_info err) +static void rtw89_mac_dump_err_status_ax(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) { if (err != MAC_AX_ERR_L1_ERR_DMAC && err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && @@ -633,11 +757,16 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + rtw89_info(rtwdev, "DBG Counter 1 (R_AX_DRV_FW_HSK_4)=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_4)); + rtw89_info(rtwdev, "DBG Counter 2 (R_AX_DRV_FW_HSK_5)=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_5)); rtw89_mac_dump_dmac_err_status(rtwdev); - rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_0); - if (rtwdev->dbcc_en) - rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_1); + rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_0); + rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_1); rtwdev->hci.ops->dump_err_status(rtwdev); @@ -682,6 +811,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 err, err_scnr; int ret; @@ -707,7 +837,7 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) return err; rtw89_fw_st_dbg_dump(rtwdev); - rtw89_mac_dump_err_status(rtwdev, err); + mac->dump_err_status(rtwdev, err); return err; } @@ -1645,7 +1775,7 @@ static bool mac_is_txq_empty_ax(struct rtw89_dev *rtwdev) } qtmp = qempty.qempty; for (j = 0 ; j < QEMP_ACQ_GRP_MACID_NUM; j++) { - val32 = FIELD_GET(QEMP_ACQ_GRP_QSEL_MASK, qtmp); + val32 = u32_get_bits(qtmp, QEMP_ACQ_GRP_QSEL_MASK); if (val32 != QEMP_ACQ_GRP_QSEL_MASK) return false; qtmp >>= QEMP_ACQ_GRP_QSEL_SH; @@ -5997,6 +6127,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, + .dump_qta_lost = rtw89_mac_dump_qta_lost_ax, + .dump_err_status = rtw89_mac_dump_err_status_ax, + .is_txq_empty = mac_is_txq_empty_ax, }; EXPORT_SYMBOL(rtw89_mac_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b63c506e8de1..18b285d9d96f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -935,6 +935,10 @@ struct rtw89_mac_gen_def { enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr); + void (*dump_qta_lost)(struct rtw89_dev *rtwdev); + void (*dump_err_status)(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err); + bool (*is_txq_empty)(struct rtw89_dev *rtwdev); }; @@ -1041,8 +1045,14 @@ int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 band, enum rtw89_mac_hwmod_sel sel); int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val); int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val); +int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl); +int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_quota *quota); +void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev); int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_qempty *qempty); +void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err); int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index ec394f02a8ca..c3c920ccb2f9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -780,6 +780,254 @@ static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev, } } +static void dump_err_status_dispatcher_be(struct rtw89_dev *rtwdev) +{ + rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1)); + rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2)); + rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0)); +} + +static void rtw89_mac_dump_qta_lost_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + struct rtw89_mac_dle_dfi_quota quota; + struct rtw89_mac_dle_dfi_ctrl ctrl; + u32 val, not_empty, i; + int ret; + + qempty.dle_type = DLE_CTRL_TYPE_PLE; + qempty.grpsel = 0; + qempty.qempty = ~(u32)0; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "DLE group0 empty: 0x%x\n", qempty.qempty); + + for (not_empty = ~qempty.qempty, i = 0; not_empty != 0; not_empty >>= 1, i++) { + if (!(not_empty & BIT(0))) + continue; + ctrl.type = DLE_CTRL_TYPE_PLE; + ctrl.target = DLE_DFI_TYPE_QLNKTBL; + ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) | + u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i, + u32_get_bits(ctrl.out_data, + QLNKTBL_DATA_SEL1_PKT_CNT_MASK)); + } + + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 6; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota6 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_BE_PLE_QTA6_CFG); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q6_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q6_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0)); + + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 7; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_BE_PLE_QTA7_CFG); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q7_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q7_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT_C1); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG_C1)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0_C1)); + } + + rtw89_info(rtwdev, "R_BE_DLE_EMPTY0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DLE_EMPTY0)); + rtw89_info(rtwdev, "R_BE_DLE_EMPTY1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DLE_EMPTY1)); + + dump_err_status_dispatcher_be(rtwdev); +} + +static void rtw89_mac_dump_cmac_err_status_be(struct rtw89_dev *rtwdev, + u8 band) +{ + u32 offset = 0; + u32 cmac_err; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); + if (ret) { + rtw89_info(rtwdev, "[CMAC] : CMAC%d not enabled\n", band); + return; + } + + if (band) + offset = RTW89_MAC_BE_BAND_REG_OFFSET; + + cmac_err = rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset); + rtw89_info(rtwdev, "R_BE_CMAC_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset)); + rtw89_info(rtwdev, "R_BE_CMAC_FUNC_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_FUNC_EN + offset)); + rtw89_info(rtwdev, "R_BE_CK_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CK_EN + offset)); + + if (cmac_err & B_BE_SCHEDULE_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_IMR + offset)); + rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_ISR + offset)); + } + + if (cmac_err & B_BE_PTCL_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_PTCL_IMR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_IMR0 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_ISR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_ISR0 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_IMR1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_IMR1 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_ISR1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_ISR1 + offset)); + } + + if (cmac_err & B_BE_DMA_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG_IMR + offset)); + rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR_1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR_1 + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_1 + offset)); + } + + if (cmac_err & B_BE_PHYINTF_ERR_IND) { + rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_IMR_V1 + offset)); + rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_ISR + offset)); + } + + if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { + rtw89_info(rtwdev, "R_BE_TXPWR_ERR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TXPWR_ERR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_TXPWR_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TXPWR_ERR_IMR + offset)); + } + + if (cmac_err & (B_BE_WMAC_RX_ERR_IND | B_BE_WMAC_TX_ERR_IND | + B_BE_WMAC_RX_IDLETO_IDCT | B_BE_PTCL_TX_IDLETO_IDCT)) { + rtw89_info(rtwdev, "R_BE_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_DBGSEL_TRXPTCL + offset)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA_MASK + offset)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERR_IMR + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERR_ISR + offset)); + } + + rtw89_info(rtwdev, "R_BE_CMAC_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_ERR_IMR + offset)); +} + +static void rtw89_mac_dump_err_status_be(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) +{ + if (err != MAC_AX_ERR_L1_ERR_DMAC && + err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && + err != MAC_AX_ERR_L0_ERR_CMAC0 && + err != MAC_AX_ERR_L0_ERR_CMAC1 && + err != MAC_AX_ERR_RXI300) + return; + + rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); + rtw89_info(rtwdev, "R_BE_SER_DBG_INFO=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_DBG_INFO)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT2)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT3)); + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT_C1)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1_C1)); + } + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_0)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_1)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_2)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_3)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_4=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_4)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_5=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_5)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_6=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_6)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_7=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_7)); + + rtw89_mac_dump_dmac_err_status(rtwdev); + rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_0); + rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_1); + + rtwdev->hci.ops->dump_err_status(rtwdev); + + if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1) + rtw89_mac_dump_l0_to_l1(rtwdev, err); + + rtw89_info(rtwdev, "<---\n"); +} + static bool mac_is_txq_empty_be(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; @@ -871,6 +1119,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, + .dump_qta_lost = rtw89_mac_dump_qta_lost_be, + .dump_err_status = rtw89_mac_dump_err_status_be, + .is_txq_empty = mac_is_txq_empty_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 0ca07ae63594..769f1ce62ebc 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3826,12 +3826,22 @@ static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev) { - rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", - rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); - rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); - rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", - rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + return; + + if (rtwdev->chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG_V1)); + rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG_V1)); + } else { + rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); + rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); + rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); + } } static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index e2d8eef52b20..ca5de77fee90 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -812,6 +812,8 @@ #define B_AX_RXCOUNTER_MATCH_MASK GENMASK(15, 8) #define B_AX_RXTIMER_MATCH_MASK GENMASK(7, 0) +#define R_AX_DBG_ERR_FLAG_V1 0x1104 + #define R_AX_INT_MIT_RX_V1 0x1184 #define B_AX_RXMIT_RXP2_SEL_V1 BIT(19) #define B_AX_RXMIT_RXP1_SEL_V1 BIT(18) @@ -857,6 +859,8 @@ #define R_AX_PCIE_HRPWM_V1 0x30C0 #define R_AX_PCIE_CRPWM 0x30C4 +#define R_AX_LBC_WATCHDOG_V1 0x30D8 + #define R_BE_PCIE_HRPWM 0x30C0 #define R_BE_PCIE_CRPWM 0x30C4 diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 76f9195f40e7..2f2ac0748ce0 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -1457,6 +1457,8 @@ #define B_AX_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16) #define B_AX_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0) #define R_AX_PLE_QTA7_CFG 0x905C +#define B_AX_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16) +#define B_AX_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0) #define R_AX_PLE_QTA8_CFG 0x9060 #define R_AX_PLE_QTA9_CFG 0x9064 #define R_AX_PLE_QTA10_CFG 0x9068 @@ -4122,6 +4124,15 @@ B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \ B_BE_PL_AXIDMA_FC_ERR_MASK) +#define R_BE_PL_AXIDMA_IDCT 0x0914 +#define B_BE_PL_AXIDMA_RRESP_ERR BIT(6) +#define B_BE_PL_AXIDMA_BRESP_ERR BIT(5) +#define B_BE_PL_AXIDMA_FC_ERR BIT(4) +#define B_BE_PL_AXIDMA_TXBD_LEN0 BIT(3) +#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR BIT(2) +#define B_BE_PL_AXIDMA_TXBD_RX_STUCK BIT(1) +#define B_BE_PL_AXIDMA_TXBD_TX_STUCK BIT(0) + #define R_BE_FILTER_MODEL_ADDR 0x0C04 #define R_BE_WLAN_WDT 0x3050 @@ -4305,6 +4316,12 @@ #define B_BE_DMAC_CTRL_INFO_SER_IO BIT(11) #define B_BE_DMAC_CTRL_INFO_OFFSET_MASK GENMASK(10, 0) +#define R_BE_SER_DBG_INFO 0x8424 +#define B_BE_SER_L0_PROMOTE_L1_EVENT_MASK GENMASK(31, 28) +#define B_BE_SER_L1_COUNTER_MASK GENMASK(27, 24) +#define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) + #define R_BE_DLE_EMPTY0 0x8430 #define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) #define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) @@ -4335,6 +4352,193 @@ #define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) #define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) +#define R_BE_DLE_EMPTY1 0x8434 +#define B_BE_PLE_EMPTY_QTA_CMAC_DMA_TXRPT BIT(21) +#define B_BE_PLE_EMPTY_QTA_DMAC_WDRLS BIT(20) +#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_BBRPT BIT(19) +#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_RX BIT(18) +#define B_BE_PLE_EMPTY_QTA_CMAC0_DMA_RX BIT(17) +#define B_BE_PLE_EMPTY_QTA_DMAC_C2H BIT(16) +#define B_BE_PLE_EMPTY_QUE_DMAC_PLRLS BIT(5) +#define B_BE_PLE_EMPTY_QUE_DMAC_CPUIO BIT(4) +#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_RX BIT(3) +#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_RX BIT(2) +#define B_BE_PLE_EMPTY_QUE_DMAC_HDP BIT(1) +#define B_BE_WDE_EMPTY_QUE_DMAC_WDRLS BIT(0) + +#define R_BE_SER_L1_DBG_CNT_0 0x8440 +#define B_BE_SER_L1_WDRLS_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_SEC_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_MPDU_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_STA_SCH_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_1 0x8444 +#define B_BE_SER_L1_WDE_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_TXPKTCTRL_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_PLE_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_PKTIN_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_2 0x8448 +#define B_BE_SER_L1_DISP_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_APB_BRIDGE_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_DLE_W_CPUIO_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_BBRPT_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_3 0x844C +#define B_BE_SER_L1_HCI_BUF_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_P_AXIDMA_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_H_AXIDMA_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_MLO_ERR_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_4 0x8450 +#define B_BE_SER_L1_PLDRLS_ERR_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_DLE_D_CPUIO_CNT_MASK GENMASK(23, 16) + +#define R_BE_SER_L1_DBG_CNT_5 0x8454 +#define B_BE_SER_L1_DBG_0_MASK GENMASK(31, 0) + +#define R_BE_SER_L1_DBG_CNT_6 0x8458 +#define B_BE_SER_L1_DBG_1_MASK GENMASK(31, 0) + +#define R_BE_SER_L1_DBG_CNT_7 0x845C +#define B_BE_SER_L1_DBG_2_MASK GENMASK(31, 0) + +#define R_BE_DMAC_ERR_IMR 0x8520 +#define B_BE_DMAC_NOTX_ERR_INT_EN BIT(21) +#define B_BE_DMAC_NORX_ERR_INT_EN BIT(20) +#define B_BE_DLE_DATACPUIO_ERR_INT_EN BIT(19) +#define B_BE_PLRSL_ERR_INT_EN BIT(18) +#define B_BE_MLO_ERR_INT_EN BIT(17) +#define B_BE_DMAC_FW_ERR_INT_EN BIT(16) +#define B_BE_H_AXIDMA_ERR_INT_EN BIT(14) +#define B_BE_P_AXIDMA_ERR_INT_EN BIT(13) +#define B_BE_HCI_BUF_ERR_INT_EN BIT(12) +#define B_BE_BBRPT_ERR_INT_EN BIT(11) +#define B_BE_DLE_CPUIO_ERR_INT_EN BIT(10) +#define B_BE_APB_BRIDGE_ERR_INT_EN BIT(9) +#define B_BE_DISPATCH_ERR_INT_EN BIT(8) +#define B_BE_PKTIN_ERR_INT_EN BIT(7) +#define B_BE_PLE_DLE_ERR_INT_EN BIT(6) +#define B_BE_TXPKTCTRL_ERR_INT_EN BIT(5) +#define B_BE_WDE_DLE_ERR_INT_EN BIT(4) +#define B_BE_STA_SCHEDULER_ERR_INT_EN BIT(3) +#define B_BE_MPDU_ERR_INT_EN BIT(2) +#define B_BE_WSEC_ERR_INT_EN BIT(1) +#define B_BE_WDRLS_ERR_INT_EN BIT(0) + +#define R_BE_DMAC_ERR_ISR 0x8524 +#define B_BE_DLE_DATACPUIO_ERR_INT BIT(19) +#define B_BE_PLRLS_ERR_INT BIT(18) +#define B_BE_MLO_ERR_INT BIT(17) +#define B_BE_DMAC_FW_ERR_IDCT BIT(16) +#define B_BE_H_AXIDMA_ERR_INT BIT(14) +#define B_BE_P_AXIDMA_ERR_INT BIT(13) +#define B_BE_HCI_BUF_ERR_FLAG BIT(12) +#define B_BE_BBRPT_ERR_FLAG BIT(11) +#define B_BE_DLE_CPUIO_ERR_FLAG BIT(10) +#define B_BE_APB_BRIDGE_ERR_FLAG BIT(9) +#define B_BE_DISPATCH_ERR_FLAG BIT(8) +#define B_BE_PKTIN_ERR_FLAG BIT(7) +#define B_BE_PLE_DLE_ERR_FLAG BIT(6) +#define B_BE_TXPKTCTRL_ERR_FLAG BIT(5) +#define B_BE_WDE_DLE_ERR_FLAG BIT(4) +#define B_BE_STA_SCHEDULER_ERR_FLAG BIT(3) +#define B_BE_MPDU_ERR_FLAG BIT(2) +#define B_BE_WSEC_ERR_FLAG BIT(1) +#define B_BE_WDRLS_ERR_FLAG BIT(0) + +#define R_BE_DISP_ERROR_ISR0 0x8804 +#define B_BE_REUSE_SIZE_ERR BIT(31) +#define B_BE_REUSE_EN_ERR BIT(30) +#define B_BE_STF_OQT_UNDERFLOW_ERR BIT(29) +#define B_BE_STF_OQT_OVERFLOW_ERR BIT(28) +#define B_BE_STF_WRFF_UNDERFLOW_ERR BIT(27) +#define B_BE_STF_WRFF_OVERFLOW_ERR BIT(26) +#define B_BE_STF_CMD_UNDERFLOW_ERR BIT(25) +#define B_BE_STF_CMD_OVERFLOW_ERR BIT(24) +#define B_BE_REUSE_SIZE_ZERO_ERR BIT(23) +#define B_BE_REUSE_PKT_CNT_ERR BIT(22) +#define B_BE_CDT_PTR_TIMEOUT_ERR BIT(21) +#define B_BE_CDT_HCI_TIMEOUT_ERR BIT(20) +#define B_BE_HDT_PTR_TIMEOUT_ERR BIT(19) +#define B_BE_HDT_HCI_TIMEOUT_ERR BIT(18) +#define B_BE_CDT_ADDR_INFO_LEN_ERR BIT(17) +#define B_BE_HDT_ADDR_INFO_LEN_ERR BIT(16) +#define B_BE_CDR_DMA_TIMEOUT_ERR BIT(15) +#define B_BE_CDR_RX_TIMEOUT_ERR BIT(14) +#define B_BE_PLE_OUTPUT_ERR BIT(12) +#define B_BE_PLE_RESPOSE_ERR BIT(11) +#define B_BE_PLE_BURST_NUM_ERR BIT(10) +#define B_BE_PLE_NULL_PKT_ERR BIT(9) +#define B_BE_PLE_FLOW_CTRL_ERR BIT(8) +#define B_BE_HDR_DMA_TIMEOUT_ERR BIT(7) +#define B_BE_HDR_RX_TIMEOUT_ERR BIT(6) +#define B_BE_WDE_OUTPUT_ERR BIT(4) +#define B_BE_WDE_RESPONSE_ERR BIT(3) +#define B_BE_WDE_BURST_NUM_ERR BIT(2) +#define B_BE_WDE_NULL_PKT_ERR BIT(1) +#define B_BE_WDE_FLOW_CTRL_ERR BIT(0) + +#define R_BE_DISP_ERROR_ISR1 0x8808 +#define B_BE_HR_WRFF_UNDERFLOW_ERR BIT(31) +#define B_BE_HR_WRFF_OVERFLOW_ERR BIT(30) +#define B_BE_HR_CHKSUM_FSM_ERR BIT(29) +#define B_BE_HR_SHIFT_DMA_CFG_ERR BIT(28) +#define B_BE_HR_DMA_PROCESS_ERR BIT(27) +#define B_BE_HR_TOTAL_LEN_UNDER_ERR BIT(26) +#define B_BE_HR_SHIFT_EN_ERR BIT(25) +#define B_BE_HR_AGG_CFG_ERR BIT(24) +#define B_BE_HR_PLD_LEN_ZERO_ERR BIT(22) +#define B_BE_HT_ILL_CH_ERR BIT(20) +#define B_BE_HT_ADDR_INFO_LEN_ERR BIT(18) +#define B_BE_HT_WD_LEN_OVER_ERR BIT(17) +#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR BIT(16) +#define B_BE_HT_PLD_CMD_OVERFLOW_ERR BIT(15) +#define B_BE_HT_WRFF_UNDERFLOW_ERR BIT(14) +#define B_BE_HT_WRFF_OVERFLOW_ERR BIT(13) +#define B_BE_HT_CHKSUM_FSM_ERR BIT(12) +#define B_BE_HT_NON_IDLE_PKT_STR_ERR BIT(11) +#define B_BE_HT_PRE_SUB_BE_ERR BIT(10) +#define B_BE_HT_WD_CHKSUM_ERR BIT(9) +#define B_BE_HT_CHANNEL_DMA_ERR BIT(8) +#define B_BE_HT_OFFSET_UNMATCH_ERR BIT(7) +#define B_BE_HT_PAYLOAD_UNDER_ERR BIT(6) +#define B_BE_HT_PAYLOAD_OVER_ERR BIT(5) +#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR BIT(4) +#define B_BE_HT_PERMU_FF_OVERFLOW_ERR BIT(3) +#define B_BE_HT_PKT_FAIL_ERR BIT(2) +#define B_BE_HT_CH_ID_ERR BIT(1) +#define B_BE_HT_EP_CH_DIFF_ERR BIT(0) + +#define R_BE_DISP_ERROR_ISR2 0x880C +#define B_BE_CR_PLD_LEN_ERR BIT(30) +#define B_BE_CR_WRFF_UNDERFLOW_ERR BIT(29) +#define B_BE_CR_WRFF_OVERFLOW_ERR BIT(28) +#define B_BE_CR_SHIFT_DMA_CFG_ERR BIT(27) +#define B_BE_CR_DMA_PROCESS_ERR BIT(26) +#define B_BE_CR_SHIFT_EN_ERR BIT(24) +#define B_BE_REUSE_FIFO_B_UNDER_ERR BIT(22) +#define B_BE_REUSE_FIFO_B_OVER_ERR BIT(21) +#define B_BE_REUSE_FIFO_A_UNDER_ERR BIT(20) +#define B_BE_REUSE_FIFO_A_OVER_ERR BIT(19) +#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR BIT(17) +#define B_BE_CT_WD_LEN_OVER_ERR BIT(16) +#define B_BE_CT_F2P_SEQ_ERR BIT(15) +#define B_BE_CT_F2P_QSEL_ERR BIT(14) +#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR BIT(13) +#define B_BE_CT_PLD_CMD_OVERFLOW_ERR BIT(12) +#define B_BE_CT_PRE_SUB_ERR BIT(11) +#define B_BE_CT_WD_CHKSUM_ERR BIT(10) +#define B_BE_CT_CHANNEL_DMA_ERR BIT(9) +#define B_BE_CT_OFFSET_UNMATCH_ERR BIT(8) +#define B_BE_F2P_TOTAL_NUM_ERR BIT(7) +#define B_BE_CT_PAYLOAD_UNDER_ERR BIT(6) +#define B_BE_CT_PAYLOAD_OVER_ERR BIT(5) +#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR BIT(4) +#define B_BE_CT_PERMU_FF_OVERFLOW_ERR BIT(3) +#define B_BE_CT_CH_ID_ERR BIT(2) +#define B_BE_CT_EP_CH_DIFF_ERR BIT(0) + #define R_BE_DISP_OTHER_IMR 0x8870 #define B_BE_REUSE_SIZE_ERR_INT_EN BIT(31) #define B_BE_REUSE_EN_ERR_INT_EN BIT(30) @@ -4904,6 +5108,9 @@ #define B_BE_LA_ERRFLAG_IMR_CLR B_BE_LA_IMR_DATA_LOSS #define B_BE_LA_ERRFLAG_IMR_SET B_BE_LA_IMR_DATA_LOSS +#define R_BE_LA_ERRFLAG_ISR 0x966C +#define B_BE_LA_ISR_DATA_LOSS BIT(0) + #define R_BE_CH_INFO_DBGFLAG_IMR 0x9688 #define B_BE_BCHN_EVT01_ISR_EN BIT(29) #define B_BE_BCHN_REQTO_ISR_EN BIT(28) @@ -5025,6 +5232,55 @@ #define B_BE_MPDU_RX_ERR_IMR_CLR B_BE_TIMEOUT_ERR_IMR #define B_BE_MPDU_RX_ERR_IMR_SET 0 +#define R_BE_SEC_ENG_CTRL 0x9D00 +#define B_BE_SEC_ENG_EN BIT(31) +#define B_BE_CCMP_SPP_MIC BIT(30) +#define B_BE_CCMP_SPP_CTR BIT(29) +#define B_BE_SEC_CAM_ACC BIT(28) +#define B_BE_WMAC_SEC_PN_SEL_MASK GENMASK(27, 26) +#define B_BE_WMAC_SEC_MASKIV BIT(25) +#define B_BE_WAPI_SPEC BIT(24) +#define B_BE_REVERT_TA_RA_MLD_EN BIT(23) +#define B_BE_SEC_DBG_SEL_MASK GENMASK(19, 16) +#define B_BE_CAM_FORCE_CLK BIT(15) +#define B_BE_SEC_FORCE_CLK BIT(14) +#define B_BE_SEC_RX_SHORT_ADD_ICVERR BIT(13) +#define B_BE_SRAM_IO_PROT BIT(12) +#define B_BE_SEC_PRE_ENQUE_TX BIT(11) +#define B_BE_CLK_EN_CGCMP BIT(10) +#define B_BE_CLK_EN_WAPI BIT(9) +#define B_BE_CLK_EN_WEP_TKIP BIT(8) +#define B_BE_BMC_MGNT_DEC BIT(5) +#define B_BE_UC_MGNT_DEC BIT(4) +#define B_BE_MC_DEC BIT(3) +#define B_BE_BC_DEC BIT(2) +#define B_BE_SEC_RX_DEC BIT(1) +#define B_BE_SEC_TX_ENC BIT(0) + +#define R_BE_SEC_MPDU_PROC 0x9D04 +#define B_BE_DBG_ENGINE_SEL BIT(8) +#define B_BE_STOP_RX_PKT_HANDLE BIT(7) +#define B_BE_STOP_TX_PKT_HANDLE BIT(6) +#define B_BE_QUEUE_FOWARD_SEL BIT(5) +#define B_BE_RESP1_PROTECT BIT(4) +#define B_BE_RESP0_PROTECT BIT(3) +#define B_BE_TX_ACTIVE_PROTECT BIT(2) +#define B_BE_APPEND_ICV BIT(1) +#define B_BE_APPEND_MIC BIT(0) + +#define R_BE_SEC_CAM_ACCESS 0x9D10 +#define B_BE_SEC_TIME_OUT_MASK GENMASK(31, 16) +#define B_BE_SEC_CAM_POLL BIT(15) +#define B_BE_SEC_CAM_RW BIT(14) +#define B_BE_SEC_CAM_ACC_FAIL BIT(13) +#define B_BE_SEC_CAM_OFFSET_MASK GENMASK(10, 0) + +#define R_BE_SEC_CAM_RDATA 0x9D14 +#define B_BE_SEC_CAM_RDATA_MASK GENMASK(31, 0) + +#define R_BE_SEC_DEBUG2 0x9D28 +#define B_BE_DBG_READ_MASK GENMASK(31, 0) + #define R_BE_SEC_ERROR_IMR 0x9D2C #define B_BE_QUEUE_OPERATION_HANG_IMR BIT(4) #define B_BE_SEC1_RX_HANG_IMR BIT(3) @@ -5042,6 +5298,14 @@ B_BE_SEC1_RX_HANG_IMR | \ B_BE_QUEUE_OPERATION_HANG_IMR) +#define R_BE_SEC_ERROR_FLAG 0x9D30 +#define B_BE_TXD_DIFF_KEYCAM_TYPE_ERROR BIT(5) +#define B_BE_QUEUE_OPERATION_HANG_ERROR BIT(4) +#define B_BE_SEC1_RX_HANG_ERROR BIT(3) +#define B_BE_SEC1_TX_HANG_ERROR BIT(2) +#define B_BE_RX_HANG_ERROR BIT(1) +#define B_BE_TX_HANG_ERROR BIT(0) + #define R_BE_TXPKTCTL_B0_ERRFLAG_IMR 0x9F78 #define B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN BIT(25) #define B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD BIT(24) @@ -5114,11 +5378,23 @@ B_BE_MLO_ERR_IDCT_IMR_1 | \ B_BE_MLO_ERR_IDCT_IMR_0) +#define R_BE_MLO_ERR_IDCT_ISR 0xA12C +#define B_BE_MLO_ISR_IDCT_0 BIT(31) +#define B_BE_MLO_ISR_IDCT_1 BIT(30) +#define B_BE_MLO_ISR_IDCT_2 BIT(29) +#define B_BE_MLO_ISR_IDCT_3 BIT(28) + #define R_BE_PLRLS_ERR_IMR 0xA218 #define B_BE_PLRLS_CTL_FRZTO_IMR BIT(0) #define B_BE_PLRLS_ERR_IMR_CLR B_BE_PLRLS_CTL_FRZTO_IMR #define B_BE_PLRLS_ERR_IMR_SET B_BE_PLRLS_CTL_FRZTO_IMR +#define R_BE_PLRLS_ERR_ISR 0xA21C +#define B_BE_PLRLS_CTL_EVT03_ISR BIT(3) +#define B_BE_PLRLS_CTL_EVT02_ISR BIT(2) +#define B_BE_PLRLS_CTL_EVT01_ISR BIT(1) +#define B_BE_PLRLS_CTL_FRZTO_ISR BIT(0) + #define R_BE_INTERRUPT_MASK_REG 0xA3F0 #define B_BE_PLE_B_PKTID_ERR_IMR BIT(2) #define B_BE_RPT_TIMEOUT_IMR BIT(1) @@ -5130,6 +5406,11 @@ B_BE_RPT_TIMEOUT_IMR | \ B_BE_PLE_B_PKTID_ERR_IMR) +#define R_BE_INTERRUPT_STS_REG 0xA3F4 +#define B_BE_PLE_B_PKTID_ERR_ISR BIT(2) +#define B_BE_RPT_TIMEOUT_ISR BIT(1) +#define B_BE_SEARCH_TIMEOUT_ISR BIT(0) + #define R_BE_HAXI_INIT_CFG1 0xB000 #define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) #define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) @@ -5194,6 +5475,16 @@ B_BE_HAXI_BRESP_ERR_IDCT_MSK | \ B_BE_HAXI_RRESP_ERR_IDCT_MSK) +#define R_BE_HAXI_IDCT 0xB0BC +#define B_BE_HAXI_RRESP_ERR_IDCT BIT(7) +#define B_BE_HAXI_BRESP_ERR_IDCT BIT(6) +#define B_BE_RXDMA_ERR_FLAG_IDCT BIT(5) +#define B_BE_SET_FC_ERROR_FLAG_IDCT BIT(4) +#define B_BE__TXBD_LEN0_ERR_IDCT BIT(3) +#define B_BE__TXBD_4KBOUND_ERR_IDCT BIT(2) +#define B_BE_RXMDA_STUCK_IDCT BIT(1) +#define B_BE_TXMDA_STUCK_IDCT BIT(0) + #define R_BE_HCI_FC_CTRL 0xB700 #define B_BE_WD_PAGE_MODE_MASK GENMASK(17, 16) #define B_BE_HCI_FC_CH14_FULL_COND_MASK GENMASK(15, 14) @@ -5270,6 +5561,104 @@ B_BE_CMAC_CRPRT | B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN | \ B_BE_SIGB_EN) +#define R_BE_CK_EN 0x10004 +#define R_BE_CK_EN_C1 0x14004 +#define B_BE_CMAC_CKEN BIT(30) +#define B_BE_BCN_P1_P4_CKEN BIT(15) +#define B_BE_BCN_P0MB1_15_CKEN BIT(14) +#define B_BE_TXTIME_CKEN BIT(8) +#define B_BE_RESP_PKTCTL_CKEN BIT(7) +#define B_BE_SIGB_CKEN BIT(6) +#define B_BE_PHYINTF_CKEN BIT(5) +#define B_BE_CMAC_DMA_CKEN BIT(4) +#define B_BE_PTCLTOP_CKEN BIT(3) +#define B_BE_SCHEDULER_CKEN BIT(2) +#define B_BE_TMAC_CKEN BIT(1) +#define B_BE_RMAC_CKEN BIT(0) +#define B_BE_CK_EN_SET (B_BE_CMAC_CKEN | B_BE_PHYINTF_CKEN | B_BE_CMAC_DMA_CKEN | \ + B_BE_PTCLTOP_CKEN | B_BE_SCHEDULER_CKEN | B_BE_TMAC_CKEN | \ + B_BE_RMAC_CKEN | B_BE_TXTIME_CKEN | B_BE_RESP_PKTCTL_CKEN | \ + B_BE_SIGB_CKEN) + +#define R_BE_CMAC_ERR_IMR 0x10160 +#define R_BE_CMAC_ERR_IMR_C1 0x14160 +#define B_BE_CMAC_FW_ERR_IDCT_EN BIT(16) +#define B_BE_PTCL_TX_IDLETO_IDCT_EN BIT(9) +#define B_BE_WMAC_RX_IDLETO_IDCT_EN BIT(8) +#define B_BE_WMAC_TX_ERR_IND_EN BIT(7) +#define B_BE_WMAC_RX_ERR_IND_EN BIT(6) +#define B_BE_TXPWR_CTRL_ERR_IND_EN BIT(5) +#define B_BE_PHYINTF_ERR_IND_EN BIT(4) +#define B_BE_DMA_TOP_ERR_IND_EN BIT(3) +#define B_BE_RESP_PKTCTL_ERR_IND_EN BIT(2) +#define B_BE_PTCL_TOP_ERR_IND_EN BIT(1) +#define B_BE_SCHEDULE_TOP_ERR_IND_EN BIT(0) + +#define R_BE_CMAC_ERR_ISR 0x10164 +#define R_BE_CMAC_ERR_ISR_C1 0x14164 +#define B_BE_CMAC_FW_ERR_IDCT BIT(16) +#define B_BE_PTCL_TX_IDLETO_IDCT BIT(9) +#define B_BE_WMAC_RX_IDLETO_IDCT BIT(8) +#define B_BE_WMAC_TX_ERR_IND BIT(7) +#define B_BE_WMAC_RX_ERR_IND BIT(6) +#define B_BE_TXPWR_CTRL_ERR_IND BIT(5) +#define B_BE_PHYINTF_ERR_IND BIT(4) +#define B_BE_DMA_TOP_ERR_IND BIT(3) +#define B_BE_RESP_PKTCTL_ERR_IDCT BIT(2) +#define B_BE_PTCL_TOP_ERR_IND BIT(1) +#define B_BE_SCHEDULE_TOP_ERR_IND BIT(0) + +#define R_BE_SER_L0_DBG_CNT 0x10170 +#define R_BE_SER_L0_DBG_CNT_C1 0x14170 +#define B_BE_SER_L0_PHYINTF_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L0_DMA_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L0_PTCL_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L0_SCH_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L0_DBG_CNT1 0x10174 +#define R_BE_SER_L0_DBG_CNT1_C1 0x14174 +#define B_BE_SER_L0_TMAC_COUNTER_MASK GENMASK(23, 16) +#define B_BE_SER_L0_RMAC_COUNTER_MASK GENMASK(15, 8) +#define B_BE_SER_L0_TXPWR_COUNTER_MASK GENMASK(7, 0) + +#define R_BE_SER_L0_DBG_CNT2 0x10178 +#define R_BE_SER_L0_DBG_CNT2_C1 0x14178 + +#define R_BE_SER_L0_DBG_CNT3 0x1017C +#define R_BE_SER_L0_DBG_CNT3_C1 0x1417C +#define B_BE_SER_L0_SUBMODULE_BIT31_CNT BIT(31) +#define B_BE_SER_L0_SUBMODULE_BIT30_CNT BIT(30) +#define B_BE_SER_L0_SUBMODULE_BIT29_CNT BIT(29) +#define B_BE_SER_L0_SUBMODULE_BIT28_CNT BIT(28) +#define B_BE_SER_L0_SUBMODULE_BIT27_CNT BIT(27) +#define B_BE_SER_L0_SUBMODULE_BIT26_CNT BIT(26) +#define B_BE_SER_L0_SUBMODULE_BIT25_CNT BIT(25) +#define B_BE_SER_L0_SUBMODULE_BIT24_CNT BIT(24) +#define B_BE_SER_L0_SUBMODULE_BIT23_CNT BIT(23) +#define B_BE_SER_L0_SUBMODULE_BIT22_CNT BIT(22) +#define B_BE_SER_L0_SUBMODULE_BIT21_CNT BIT(21) +#define B_BE_SER_L0_SUBMODULE_BIT20_CNT BIT(20) +#define B_BE_SER_L0_SUBMODULE_BIT19_CNT BIT(19) +#define B_BE_SER_L0_SUBMODULE_BIT18_CNT BIT(18) +#define B_BE_SER_L0_SUBMODULE_BIT17_CNT BIT(17) +#define B_BE_SER_L0_SUBMODULE_BIT16_CNT BIT(16) +#define B_BE_SER_L0_SUBMODULE_BIT15_CNT BIT(15) +#define B_BE_SER_L0_SUBMODULE_BIT14_CNT BIT(14) +#define B_BE_SER_L0_SUBMODULE_BIT13_CNT BIT(13) +#define B_BE_SER_L0_SUBMODULE_BIT12_CNT BIT(12) +#define B_BE_SER_L0_SUBMODULE_BIT11_CNT BIT(11) +#define B_BE_SER_L0_SUBMODULE_BIT10_CNT BIT(10) +#define B_BE_SER_L0_SUBMODULE_BIT9_CNT BIT(9) +#define B_BE_SER_L0_SUBMODULE_BIT8_CNT BIT(8) +#define B_BE_SER_L0_SUBMODULE_BIT7_CNT BIT(7) +#define B_BE_SER_L0_SUBMODULE_BIT6_CNT BIT(6) +#define B_BE_SER_L0_SUBMODULE_BIT5_CNT BIT(5) +#define B_BE_SER_L0_SUBMODULE_BIT4_CNT BIT(4) +#define B_BE_SER_L0_SUBMODULE_BIT3_CNT BIT(3) +#define B_BE_SER_L0_SUBMODULE_BIT2_CNT BIT(2) +#define B_BE_SER_L0_SUBMODULE_BIT1_CNT BIT(1) +#define B_BE_SER_L0_SUBMODULE_BIT0_CNT BIT(0) + #define R_BE_PORT_0_TSF_SYNC 0x102A0 #define R_BE_PORT_0_TSF_SYNC_C1 0x142A0 #define B_BE_P0_SYNC_NOW_P BIT(30) @@ -5296,6 +5685,11 @@ #define B_BE_SCHEDULE_ERR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN #define B_BE_SCHEDULE_ERR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN +#define R_BE_SCHEDULE_ERR_ISR 0x103EC +#define R_BE_SCHEDULE_ERR_ISR_C1 0x143EC +#define B_BE_SORT_NON_IDLE_ERR_INT BIT(1) +#define B_BE_FSM_TIMEOUT_ERR_INT BIT(0) + #define R_BE_PORT_CFG_P0 0x10400 #define R_BE_PORT_CFG_P0_C1 0x14400 #define B_BE_BCN_ERLY_SORT_EN_P0 BIT(18) @@ -5453,6 +5847,12 @@ B_BE_FSM1_TIMEOUT_ERR_INT_EN | \ B_BE_PTCL_ERROR_FLAG_IMR) +#define R_BE_PTCL_ISR0 0x108C4 +#define R_BE_PTCL_ISR0_C1 0x148C4 +#define B_BE_PTCL_ERROR_FLAG_ISR BIT(31) +#define B_BE_FSM1_TIMEOUT_ERR BIT(1) +#define B_BE_FSM_TIMEOUT_ERR BIT(0) + #define R_BE_PTCL_IMR1 0x108C8 #define R_BE_PTCL_IMR1_C1 0x148C8 #define B_BE_F2PCMD_PKTID_IMR BIT(30) @@ -5489,6 +5889,60 @@ B_BE_F2PCMD_PKTID_IMR) #define B_BE_PTCL_IMR1_SET B_BE_F2PCMD_USER_ALLC_IMR +#define R_BE_PTCL_ISR1 0x108CC +#define R_BE_PTCL_ISR1_C1 0x148CC +#define B_BE_F2PCMD_PKTID_ERR BIT(30) +#define B_BE_F2PCMD_RD_PKTID_ERR BIT(29) +#define B_BE_F2PCMD_ASSIGN_PKTID_ERR BIT(28) +#define B_BE_F2PCMD_USER_ALLC_ERR BIT(27) +#define B_BE_RX_SPF_U0_PKTID_ERR BIT(26) +#define B_BE_TX_SPF_U1_PKTID_ERR BIT(25) +#define B_BE_TX_SPF_U2_PKTID_ERR BIT(24) +#define B_BE_TX_SPF_U3_PKTID_ERR BIT(23) +#define B_BE_TX_RECORD_PKTID_ERR BIT(22) +#define B_BE_TWTSP_QSEL_ERR BIT(14) +#define B_BE_F2P_RLS_CTN_SEL_ERR BIT(13) +#define B_BE_BCNQ_ORDER_ERR BIT(12) +#define B_BE_Q_PKTID_ERR BIT(11) +#define B_BE_D_PKTID_ERR BIT(10) +#define B_BE_TXPRT_FULL_DROP_ERR BIT(9) +#define B_BE_F2PCMDRPT_FULL_DROP_ERR BIT(8) + +#define R_BE_RX_ERROR_FLAG 0x10C00 +#define R_BE_RX_ERROR_FLAG_C1 0x14C00 +#define B_BE_RX_CSI_NOT_RELEASE_ERROR BIT(31) +#define B_BE_RX_GET_NULL_PKT_ERROR BIT(30) +#define B_BE_RX_RU0_FSM_HANG_ERROR BIT(29) +#define B_BE_RX_RU1_FSM_HANG_ERROR BIT(28) +#define B_BE_RX_RU2_FSM_HANG_ERROR BIT(27) +#define B_BE_RX_RU3_FSM_HANG_ERROR BIT(26) +#define B_BE_RX_RU4_FSM_HANG_ERROR BIT(25) +#define B_BE_RX_RU5_FSM_HANG_ERROR BIT(24) +#define B_BE_RX_RU6_FSM_HANG_ERROR BIT(23) +#define B_BE_RX_RU7_FSM_HANG_ERROR BIT(22) +#define B_BE_RX_RXSTS_FSM_HANG_ERROR BIT(21) +#define B_BE_RX_CSI_FSM_HANG_ERROR BIT(20) +#define B_BE_RX_TXRPT_FSM_HANG_ERROR BIT(19) +#define B_BE_RX_F2PCMD_FSM_HANG_ERROR BIT(18) +#define B_BE_RX_RU0_ZERO_LENGTH_ERROR BIT(17) +#define B_BE_RX_RU1_ZERO_LENGTH_ERROR BIT(16) +#define B_BE_RX_RU2_ZERO_LENGTH_ERROR BIT(15) +#define B_BE_RX_RU3_ZERO_LENGTH_ERROR BIT(14) +#define B_BE_RX_RU4_ZERO_LENGTH_ERROR BIT(13) +#define B_BE_RX_RU5_ZERO_LENGTH_ERROR BIT(12) +#define B_BE_RX_RU6_ZERO_LENGTH_ERROR BIT(11) +#define B_BE_RX_RU7_ZERO_LENGTH_ERROR BIT(10) +#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR BIT(9) +#define B_BE_RX_CSI_ZERO_LENGTH_ERROR BIT(8) +#define B_BE_PLE_DATA_OPT_FSM_HANG BIT(7) +#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG BIT(6) +#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG BIT(5) +#define B_BE_PLE_WD_OPT_FSM_HANG BIT(4) +#define B_BE_PLE_ENQ_FSM_HANG BIT(3) +#define B_BE_RXDATA_ENQUE_ORDER_ERROR BIT(2) +#define B_BE_RXSTS_ENQUE_ORDER_ERROR BIT(1) +#define B_BE_RX_CSI_PKT_NUM_ERROR BIT(0) + #define R_BE_RX_ERROR_FLAG_IMR 0x10C04 #define R_BE_RX_ERROR_FLAG_IMR_C1 0x14C04 #define B_BE_RX_CSI_NOT_RELEASE_ERROR_IMR BIT(31) @@ -5568,6 +6022,27 @@ B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ B_BE_RX_GET_NULL_PKT_ERROR_IMR) +#define R_BE_TX_ERROR_FLAG 0x10C6C +#define R_BE_TX_ERROR_FLAG_C1 0x14C6C +#define B_BE_TX_RU0_FSM_HANG_ERROR BIT(31) +#define B_BE_TX_RU1_FSM_HANG_ERROR BIT(30) +#define B_BE_TX_RU2_FSM_HANG_ERROR BIT(29) +#define B_BE_TX_RU3_FSM_HANG_ERROR BIT(28) +#define B_BE_TX_RU4_FSM_HANG_ERROR BIT(27) +#define B_BE_TX_RU5_FSM_HANG_ERROR BIT(26) +#define B_BE_TX_RU6_FSM_HANG_ERROR BIT(25) +#define B_BE_TX_RU7_FSM_HANG_ERROR BIT(24) +#define B_BE_TX_RU8_FSM_HANG_ERROR BIT(23) +#define B_BE_TX_RU9_FSM_HANG_ERROR BIT(22) +#define B_BE_TX_RU10_FSM_HANG_ERROR BIT(21) +#define B_BE_TX_RU11_FSM_HANG_ERROR BIT(20) +#define B_BE_TX_RU12_FSM_HANG_ERROR BIT(19) +#define B_BE_TX_RU13_FSM_HANG_ERROR BIT(18) +#define B_BE_TX_RU14_FSM_HANG_ERROR BIT(17) +#define B_BE_TX_RU15_FSM_HANG_ERROR BIT(16) +#define B_BE_TX_CSI_FSM_HANG_ERROR BIT(15) +#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR BIT(14) + #define R_BE_TX_ERROR_FLAG_IMR 0x10C70 #define R_BE_TX_ERROR_FLAG_IMR_C1 0x14C70 #define B_BE_TX_RU0_FSM_HANG_ERROR_IMR BIT(31) @@ -5625,6 +6100,25 @@ B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \ B_BE_TX_RU0_FSM_HANG_ERROR_IMR) +#define R_BE_RX_ERROR_FLAG_1 0x10C84 +#define R_BE_RX_ERROR_FLAG_1_C1 0x14C84 +#define B_BE_RX_RU8_FSM_HANG_ERROR BIT(29) +#define B_BE_RX_RU9_FSM_HANG_ERROR BIT(28) +#define B_BE_RX_RU10_FSM_HANG_ERROR BIT(27) +#define B_BE_RX_RU11_FSM_HANG_ERROR BIT(26) +#define B_BE_RX_RU12_FSM_HANG_ERROR BIT(25) +#define B_BE_RX_RU13_FSM_HANG_ERROR BIT(24) +#define B_BE_RX_RU14_FSM_HANG_ERROR BIT(23) +#define B_BE_RX_RU15_FSM_HANG_ERROR BIT(22) +#define B_BE_RX_RU8_ZERO_LENGTH_ERROR BIT(17) +#define B_BE_RX_RU9_ZERO_LENGTH_ERROR BIT(16) +#define B_BE_RX_RU10_ZERO_LENGTH_ERROR BIT(15) +#define B_BE_RX_RU11_ZERO_LENGTH_ERROR BIT(14) +#define B_BE_RX_RU12_ZERO_LENGTH_ERROR BIT(13) +#define B_BE_RX_RU13_ZERO_LENGTH_ERROR BIT(12) +#define B_BE_RX_RU14_ZERO_LENGTH_ERROR BIT(11) +#define B_BE_RX_RU15_ZERO_LENGTH_ERROR BIT(10) + #define R_BE_RX_ERROR_FLAG_IMR_1 0x10C88 #define R_BE_RX_ERROR_FLAG_IMR_1_C1 0x14C88 #define B_BE_RX_RU8_FSM_HANG_ERROR_IMR BIT(29) @@ -5683,6 +6177,38 @@ #define B_BE_UPD_HGQMD BIT(1) #define B_BE_UPD_TIMIE BIT(0) +#define R_BE_RSP_CHK_SIG 0x11000 +#define R_BE_RSP_CHK_SIG_C1 0x15000 +#define B_BE_RSP_STATIC_RTS_CHK_SERV_BW_EN BIT(30) +#define B_BE_RSP_TBPPDU_CHK_PWR BIT(29) +#define B_BE_RESP_PAIR_MACID_LEN_EN BIT(25) +#define B_BE_RESP_TX_ABORT_TEST_EN BIT(24) +#define B_BE_RESP_ER_SU_RU106_EN BIT(23) +#define B_BE_RESP_ER_SU_EN BIT(22) +#define B_BE_TXDATA_END_PS_OPT BIT(18) +#define B_BE_CHECK_SOUNDING_SEQ BIT(17) +#define B_BE_RXBA_IGNOREA2 BIT(16) +#define B_BE_ACKTO_CCK_MASK GENMASK(15, 8) +#define B_BE_ACKTO_MASK GENMASK(8, 0) + +#define R_BE_TRXPTCL_RESP_0 0x11004 +#define R_BE_TRXPTCL_RESP_0_C1 0x15004 +#define B_BE_WMAC_RESP_STBC_EN BIT(31) +#define B_BE_WMAC_RXFTM_TXACK_SB BIT(30) +#define B_BE_WMAC_RXFTM_TXACKBWEQ BIT(29) +#define B_BE_RESP_TB_CHK_TXTIME BIT(24) +#define B_BE_RSP_CHK_CCA BIT(23) +#define B_BE_WMAC_LDPC_EN BIT(22) +#define B_BE_WMAC_SGIEN BIT(21) +#define B_BE_WMAC_SPLCPEN BIT(20) +#define B_BE_RESP_EHT_MCS15_REF BIT(19) +#define B_BE_RESP_EHT_MCS14_REF BIT(18) +#define B_BE_WMAC_BESP_EARLY_TXBA BIT(17) +#define B_BE_WMAC_MBA_DUR_FORCE BIT(16) +#define B_BE_WMAC_SPEC_SIFS_OFDM_MASK GENMASK(15, 8) +#define WMAC_SPEC_SIFS_OFDM_1115E 0x11 +#define B_BE_WMAC_SPEC_SIFS_CCK_MASK GENMASK(7, 0) + #define R_BE_TRXPTCL_ERROR_INDICA_MASK 0x110BC #define R_BE_TRXPTCL_ERROR_INDICA_MASK_C1 0x150BC #define B_BE_WMAC_FTM_TIMEOUT_MODE BIT(30) @@ -5720,6 +6246,25 @@ B_BE_RMAC_FTM | \ B_BE_RMAC_BFMER) +#define R_BE_TRXPTCL_ERROR_INDICA 0x110C0 +#define R_BE_TRXPTCL_ERROR_INDICA_C1 0x150C0 +#define B_BE_BFMER_ERR_FLAG BIT(9) +#define B_BE_FTM_ERROR_FLAG_CLR BIT(8) +#define B_BE_CSI_ERROR_FLAG_CLR BIT(7) +#define B_BE_MIMOCTRL_ERROR_FLAG_CLR BIT(6) +#define B_BE_RXTB_ERROR_FLAG_CLR BIT(5) +#define B_BE_HWSIGB_GEN_ERROR_FLAG_CLR BIT(4) +#define B_BE_TXPLCP_ERROR_FLAG_CLR BIT(3) +#define B_BE_RESP_ERROR_FLAG_CLR BIT(2) +#define B_BE_TXCTL_ERROR_FLAG_CLR BIT(1) +#define B_BE_MACTX_ERROR_FLAG_CLR BIT(0) + +#define R_BE_DBGSEL_TRXPTCL 0x110F4 +#define R_BE_DBGSEL_TRXPTCL_C1 0x150F4 +#define B_BE_WMAC_CHNSTS_STATE_MASK GENMASK(19, 16) +#define B_BE_DBGSEL_TRIGCMD_SEL_MASK GENMASK(11, 8) +#define B_BE_DBGSEL_TRXPTCL_MASK GENMASK(7, 0) + #define R_BE_PHYINFO_ERR_IMR_V1 0x110F8 #define R_BE_PHYINFO_ERR_IMR_V1_C1 0x150F8 #define B_BE_PHYINTF_RXTB_WIDTH_MASK GENMASK(31, 30) @@ -5741,6 +6286,15 @@ B_BE_CSI_ON_TIMEOUT_EN) #define B_BE_PHYINFO_ERR_IMR_V1_SET 0 +#define R_BE_PHYINFO_ERR_ISR 0x110FC +#define R_BE_PHYINFO_ERR_ISR_C1 0x150FC +#define B_BE_CSI_ON_TIMEOUT_ERR BIT(5) +#define B_BE_STS_ON_TIMEOUT_ERR BIT(4) +#define B_BE_DATA_ON_TIMEOUT_ERR BIT(3) +#define B_BE_OFDM_CCA_TIMEOUT_ERR BIT(2) +#define B_BE_CCK_CCA_TIMEOUT_ERR BIT(1) +#define B_BE_PHY_TXON_TIMEOUT_ERR BIT(0) + #define R_BE_BFMEE_RESP_OPTION 0x11180 #define R_BE_BFMEE_RESP_OPTION_C1 0x15180 #define B_BE_BFMEE_CSI_SEC_TYPE_SH 20 @@ -5821,6 +6375,19 @@ #define B_BE_CSIPRT_HESU_AID_EN BIT(25) #define B_BE_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_BE_RX_ERR_ISR 0x114F4 +#define R_BE_RX_ERR_ISR_C1 0x154F4 +#define B_BE_RX_ERR_TRIG_ACT_TO BIT(9) +#define B_BE_RX_ERR_STS_ACT_TO BIT(8) +#define B_BE_RX_ERR_CSI_ACT_TO BIT(7) +#define B_BE_RX_ERR_ACT_TO BIT(6) +#define B_BE_CSI_DATAON_ASSERT_TO BIT(5) +#define B_BE_DATAON_ASSERT_TO BIT(4) +#define B_BE_CCA_ASSERT_TO BIT(3) +#define B_BE_RX_ERR_DMA_TO BIT(2) +#define B_BE_RX_ERR_DATA_TO BIT(1) +#define B_BE_RX_ERR_CCA_TO BIT(0) + #define R_BE_RX_ERR_IMR 0x114F8 #define R_BE_RX_ERR_IMR_C1 0x154F8 #define B_BE_RX_ERR_TRIG_ACT_TO_MSK BIT(9) @@ -5909,6 +6476,11 @@ #define B_BE_C0_TXPWR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN #define B_BE_C0_TXPWR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN +#define R_BE_TXPWR_ERR_FLAG 0x128E4 +#define R_BE_TXPWR_ERR_IMR 0x128E0 +#define R_BE_TXPWR_ERR_FLAG_C1 0x158E4 +#define R_BE_TXPWR_ERR_IMR_C1 0x158E0 + #define CMAC1_START_ADDR_BE 0x14000 #define CMAC1_END_ADDR_BE 0x17FFF From db7fac15eaf0f09d675730d7002edabe27fe9e1d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 4 Dec 2023 16:07:51 +0800 Subject: [PATCH 3124/7721] wifi: rtw89: mac: refine SER setting during WiFi CPU power on Don't enable firmware debug mode to prevent SER flow stuck due to fail to reset payload buffer, and clear HALT_C2H_INT to avoid handling unexpected interrupt at beginning. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231204080751.15354-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index c3c920ccb2f9..7ad509787d72 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -384,8 +384,6 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) u32 val32; int ret; - rtw89_write32_set(rtwdev, R_BE_UDM0, B_BE_UDM0_DBG_MODE_CTRL); - val32 = rtw89_read32(rtwdev, R_BE_HALT_C2H); if (val32) { rtw89_warn(rtwdev, "[SER] AON L2 Debug register not empty before Boot.\n"); @@ -409,6 +407,10 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) rtw89_write32(rtwdev, R_BE_HALT_H2C_CTRL, 0); rtw89_write32(rtwdev, R_BE_HALT_C2H_CTRL, 0); + val32 = rtw89_read32(rtwdev, R_BE_HISR0); + rtw89_write32(rtwdev, R_BE_HISR0, B_BE_HALT_C2H_INT); + rtw89_debug(rtwdev, RTW89_DBG_SER, "HISR0=0x%x\n", val32); + rtw89_write32_set(rtwdev, R_BE_SYS_CLK_CTRL, B_BE_CPU_CLK_EN); rtw89_write32_clr(rtwdev, R_BE_SYS_CFG5, B_BE_WDT_WAKE_PCIE_EN | B_BE_WDT_WAKE_USB_EN); From fdff2141be44696f5cc69f2f6c20c26b9ac00760 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:24 +0100 Subject: [PATCH 3125/7721] arm64: dts: qcom: sc8180x-flex-5g: use 'gpios' suffix for PCI GPIOs Linux handles both versions, but bindings expect GPIO properties to have 'gpios' suffix instead of 'gpio': sc8180x-lenovo-flex-5g.dtb: pci@1c08000: Unevaluated properties are not allowed ('perst-gpio', 'wake-gpio' were unexpected) Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111164229.63803-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts index 3ea07d094b60..0c22f3efec20 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts @@ -452,8 +452,8 @@ mdss_edp_out: endpoint { }; &pcie3 { - perst-gpio = <&tlmm 178 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 180 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 178 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 180 GPIO_ACTIVE_HIGH>; pinctrl-0 = <&pcie3_default_state>; pinctrl-names = "default"; From 9a1bd36aeb31649bc499f87671b76c7d117197e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:25 +0100 Subject: [PATCH 3126/7721] arm64: dts: qcom: sc8180x-primus: use 'gpios' suffix for PCI GPIOs Linux handles both versions, but bindings expect GPIO properties to have 'gpios' suffix instead of 'gpio': sc8180x-primus.dtb: pci@1c10000: Unevaluated properties are not allowed ('perst-gpio', 'wake-gpio' were unexpected) Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111164229.63803-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts index a40ef23a2a4f..adddf360c7fc 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts @@ -531,8 +531,8 @@ mdss_edp_out: endpoint { }; &pcie1 { - perst-gpio = <&tlmm 175 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 177 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 177 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pcie2_default_state>; From af6f6778d34cb40e60368e288767f674cc0c5f60 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:26 +0100 Subject: [PATCH 3127/7721] arm64: dts: qcom: sm8150: use 'gpios' suffix for PCI GPIOs Linux handles both versions, but bindings expect GPIO properties to have 'gpios' suffix instead of 'gpio': sa8155p-adp.dtb: pci@1c00000: Unevaluated properties are not allowed ('perst-gpio' was unexpected) Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231111164229.63803-3-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 3cba87e00123..fb7fd96ea61d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1878,7 +1878,7 @@ pcie0: pci@1c00000 { phys = <&pcie0_phy>; phy-names = "pciephy"; - perst-gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; enable-gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -1972,7 +1972,7 @@ pcie1: pci@1c08000 { phys = <&pcie1_phy>; phy-names = "pciephy"; - perst-gpio = <&tlmm 102 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; enable-gpio = <&tlmm 104 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; From f52f11271d90b1361a8364729a63a36b7456bc89 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:27 +0100 Subject: [PATCH 3128/7721] arm64: dts: qcom: sm6115: align mem timer size cells with bindings Commit 70d1e09ebf19 ("arm64: dts: qcom: sm6115: Use 64 bit addressing") converted all addresses to 64-bit addressing, but the ARMv7 memory mapped architected timer bindings expect sizes up to 32-bit. Keep 64-bit addressing but change size of memory mapping to 32-bit (size-cells=1) and adjust the ranges to match this. This fixes dtbs_check warnings like: sm6115p-lenovo-j606f.dtb: timer@f120000: #size-cells:0:0: 1 was expected Signed-off-by: Krzysztof Kozlowski Tested-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111164229.63803-4-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6115.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi index 0d13d7bf6bd1..70a06249b130 100644 --- a/arch/arm64/boot/dts/qcom/sm6115.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi @@ -2596,54 +2596,54 @@ timer@f120000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x0f120000 0x0 0x1000>; #address-cells = <2>; - #size-cells = <2>; - ranges; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x0 0x20000000>; clock-frequency = <19200000>; frame@f121000 { - reg = <0x0 0x0f121000 0x0 0x1000>, <0x0 0x0f122000 0x0 0x1000>; + reg = <0x0 0x0f121000 0x1000>, <0x0 0x0f122000 0x1000>; frame-number = <0>; interrupts = , ; }; frame@f123000 { - reg = <0x0 0x0f123000 0x0 0x1000>; + reg = <0x0 0x0f123000 0x1000>; frame-number = <1>; interrupts = ; status = "disabled"; }; frame@f124000 { - reg = <0x0 0x0f124000 0x0 0x1000>; + reg = <0x0 0x0f124000 0x1000>; frame-number = <2>; interrupts = ; status = "disabled"; }; frame@f125000 { - reg = <0x0 0x0f125000 0x0 0x1000>; + reg = <0x0 0x0f125000 0x1000>; frame-number = <3>; interrupts = ; status = "disabled"; }; frame@f126000 { - reg = <0x0 0x0f126000 0x0 0x1000>; + reg = <0x0 0x0f126000 0x1000>; frame-number = <4>; interrupts = ; status = "disabled"; }; frame@f127000 { - reg = <0x0 0x0f127000 0x0 0x1000>; + reg = <0x0 0x0f127000 0x1000>; frame-number = <5>; interrupts = ; status = "disabled"; }; frame@f128000 { - reg = <0x0 0x0f128000 0x0 0x1000>; + reg = <0x0 0x0f128000 0x1000>; frame-number = <6>; interrupts = ; status = "disabled"; From 67e4656f4487b95a39e45884c99235f62ebfaa47 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:28 +0100 Subject: [PATCH 3129/7721] arm64: dts: qcom: sm6125: add interrupts to DWC3 USB controller Add interrupts to SM6125 DWC3 USB controller, based on downstream/vendor code of Trinket DTSI from Xiaomi Laurel device, to fix dtbs_check warnings: sm6125-xiaomi-laurel-sprout.dtb: usb@4ef8800: 'interrupt-names' is a required property sm6125-xiaomi-laurel-sprout.dtb: usb@4ef8800: 'oneOf' conditional failed, one must be fixed: 'interrupts' is a required property 'interrupts-extended' is a required property Signed-off-by: Krzysztof Kozlowski Fixes: cff4bbaf2a2d ("arm64: dts: qcom: Add support for SM6125") Reviewed-by: Marijn Suijten Link: https://lore.kernel.org/r/20231111164229.63803-5-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6125.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi index eb07eca3a48d..1dd3a4056e26 100644 --- a/arch/arm64/boot/dts/qcom/sm6125.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi @@ -1185,6 +1185,10 @@ usb3: usb@4ef8800 { <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <66666667>; + interrupts = , + ; + interrupt-names = "hs_phy_irq", "ss_phy_irq"; + power-domains = <&gcc USB30_PRIM_GDSC>; qcom,select-utmi-as-pipe-clk; status = "disabled"; From 0d10ac7d2d9420d143ee738abbb06a9201e611b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 17:42:29 +0100 Subject: [PATCH 3130/7721] arm64: dts: qcom: sm6375-pdx225: add fixed touchscreen AVDD regulator The Samsung S6SY761 touchscreen bindings expect AVDD regulator which is missing in the Sony Xperia PDX225 DTS. There is however pinctrl setting for in the touchscreen device node with similar name: "avdd", so assume author wanted to control a fixed regulator with a GPIO. This fixes dtbs_check warning: sm6375-sony-xperia-murray-pdx225.dtb: touchscreen@48: 'avdd-supply' is a required property Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231111164229.63803-6-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../dts/qcom/sm6375-sony-xperia-murray-pdx225.dts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts index 0ce4fa8de8b0..cca2c2eb88ad 100644 --- a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts +++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts @@ -80,6 +80,15 @@ ramoops@ffc40000 { }; }; + touch_avdd: touch-avdd-regulator { + compatible = "regulator-fixed"; + regulator-name = "touch_avdd"; + gpio = <&tlmm 59 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_avdd_default>; + enable-active-high; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -136,9 +145,10 @@ touchscreen@48 { interrupts = <22 0x2008>; vdd-supply = <&pm6125_l13>; + avdd-supply = <&touch_avdd>; pinctrl-names = "default"; - pinctrl-0 = <&ts_int_default &ts_avdd_default>; + pinctrl-0 = <&ts_int_default>; }; }; @@ -417,7 +427,7 @@ ts_avdd_default: ts-avdd-default-state { pins = "gpio59"; function = "gpio"; drive-strength = <8>; - output-high; + output-low; }; }; From cdecce12d55cfd25b4b8755abc3c0b320e45d1d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Nov 2023 21:47:25 +0100 Subject: [PATCH 3131/7721] arm64: dts: qcom: sc8180x: align APSS with bindings SC8180x APSS Devicetree bindings expect qcom,sc8180x-apss-shared to use qcom,sdm845-apss-shared fallback: sc8180x-lenovo-flex-5g.dtb: mailbox@17c00000: compatible: 'oneOf' conditional failed, one must be fixed: ['qcom,sc8180x-apss-shared'] is too short Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111204725.35707-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index 2cada357aa7c..a7abf3d703af 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -3415,7 +3415,7 @@ intc: interrupt-controller@17a00000 { }; apss_shared: mailbox@17c00000 { - compatible = "qcom,sc8180x-apss-shared"; + compatible = "qcom,sc8180x-apss-shared", "qcom,sdm845-apss-shared"; reg = <0x0 0x17c00000 0x0 0x1000>; #mbox-cells = <1>; }; From 7bf421f44549cd0bca32bd0b4cf6e4cfe5b4f865 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 11 Nov 2023 23:07:39 +0100 Subject: [PATCH 3132/7721] dt-bindings: iio: adc: qcom: Add Qualcomm smb139x Bindings for a charger controller chip found on sm8350 Signed-off-by: Nia Espera Acked-by: Krzysztof Kozlowski Acked-by: Jonathan Cameron Link: https://lore.kernel.org/r/20231111-nia-sm8350-for-upstream-v4-1-3a638b02eea5@igalia.com Signed-off-by: Bjorn Andersson --- .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h | 19 +++++++++++++++++++ include/dt-bindings/iio/qcom,spmi-vadc.h | 3 +++ 2 files changed, 22 insertions(+) create mode 100644 include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h diff --git a/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h b/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h new file mode 100644 index 000000000000..c0680d1285cf --- /dev/null +++ b/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_SMB139X_H +#define _DT_BINDINGS_QCOM_SPMI_VADC_SMB139X_H + +#include + +#define SMB139x_1_ADC7_SMB_TEMP (SMB139x_1_SID << 8 | ADC7_SMB_TEMP) +#define SMB139x_1_ADC7_ICHG_SMB (SMB139x_1_SID << 8 | ADC7_ICHG_SMB) +#define SMB139x_1_ADC7_IIN_SMB (SMB139x_1_SID << 8 | ADC7_IIN_SMB) + +#define SMB139x_2_ADC7_SMB_TEMP (SMB139x_2_SID << 8 | ADC7_SMB_TEMP) +#define SMB139x_2_ADC7_ICHG_SMB (SMB139x_2_SID << 8 | ADC7_ICHG_SMB) +#define SMB139x_2_ADC7_IIN_SMB (SMB139x_2_SID << 8 | ADC7_IIN_SMB) + +#endif diff --git a/include/dt-bindings/iio/qcom,spmi-vadc.h b/include/dt-bindings/iio/qcom,spmi-vadc.h index 08adfe25964c..ef07ecd4d585 100644 --- a/include/dt-bindings/iio/qcom,spmi-vadc.h +++ b/include/dt-bindings/iio/qcom,spmi-vadc.h @@ -239,12 +239,15 @@ #define ADC7_GPIO3 0x0c #define ADC7_GPIO4 0x0d +#define ADC7_SMB_TEMP 0x06 #define ADC7_CHG_TEMP 0x10 #define ADC7_USB_IN_V_16 0x11 #define ADC7_VDC_16 0x12 #define ADC7_CC1_ID 0x13 #define ADC7_VREF_BAT_THERM 0x15 #define ADC7_IIN_FB 0x17 +#define ADC7_ICHG_SMB 0x18 +#define ADC7_IIN_SMB 0x19 /* 30k pull-up1 */ #define ADC7_AMUX_THM1_30K_PU 0x24 From 01a9e9eb6cdbce175ddea3cbe1163daed6d54344 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 11 Nov 2023 23:07:40 +0100 Subject: [PATCH 3133/7721] arm64: dts: qcom: sm8350: Fix DMA0 address DMA0 node downstream is specified at 0x900000, so fix the typo. Without this, enabling any i2c node using DMA0 causes a hang. Fixes: bc08fbf49bc8 ("arm64: dts: qcom: sm8350: Define GPI DMA engines") Fixes: 41d6bca799b3 ("arm64: dts: qcom: sm8350: correct DMA controller unit address") Reviewed-by: Konrad Dybcio Signed-off-by: Nia Espera Link: https://lore.kernel.org/r/20231111-nia-sm8350-for-upstream-v4-2-3a638b02eea5@igalia.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 2055b748e4c9..9f82209c5fe8 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -920,9 +920,9 @@ spi19: spi@894000 { }; }; - gpi_dma0: dma-controller@9800000 { + gpi_dma0: dma-controller@900000 { compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma"; - reg = <0 0x09800000 0 0x60000>; + reg = <0 0x00900000 0 0x60000>; interrupts = , , , From e70537717146b380e18f0c92669d968af4acb8a7 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 11 Nov 2023 23:07:41 +0100 Subject: [PATCH 3134/7721] arm64: dts: qcom: pm8350k: Remove hanging whitespace pmk8350 has a random tab character inserted, so remove it. Reviewed-by: Konrad Dybcio Signed-off-by: Nia Espera Link: https://lore.kernel.org/r/20231111-nia-sm8350-for-upstream-v4-3-3a638b02eea5@igalia.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pmk8350.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi index 1eb74017062d..f0ed15458dd7 100644 --- a/arch/arm64/boot/dts/qcom/pmk8350.dtsi +++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi @@ -22,7 +22,7 @@ reboot-mode { mode-bootloader = <0x02>; }; }; - + &spmi_bus { pmk8350: pmic@PMK8350_SID { compatible = "qcom,pmk8350", "qcom,spmi-pmic"; From 54ee322f845c7f25fbf6e43e11147b6cae8eff56 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 11 Nov 2023 23:07:42 +0100 Subject: [PATCH 3135/7721] arm64: dts: qcom: sm8350: Fix remoteproc interrupt type In a similar vein to https://lore.kernel.org/lkml/20220530080842.37024-3-manivannan.sadhasivam@linaro.org/, the remote processors on sm8350 fail to initialize with the 'correct' (i.e., specified in downstream) IRQ type. Change this to EDGE_RISING. Signed-off-by: Nia Espera Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231111-nia-sm8350-for-upstream-v4-4-3a638b02eea5@igalia.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 9f82209c5fe8..c8c77bd16adf 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -2027,7 +2027,7 @@ mpss: remoteproc@4080000 { compatible = "qcom,sm8350-mpss-pas"; reg = <0x0 0x04080000 0x0 0x4040>; - interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, @@ -2069,7 +2069,7 @@ slpi: remoteproc@5c00000 { compatible = "qcom,sm8350-slpi-pas"; reg = <0 0x05c00000 0 0x4000>; - interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 9 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 2 IRQ_TYPE_EDGE_RISING>, @@ -3206,7 +3206,7 @@ adsp: remoteproc@17300000 { compatible = "qcom,sm8350-adsp-pas"; reg = <0 0x17300000 0 0x100>; - interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, @@ -3511,7 +3511,7 @@ cdsp: remoteproc@98900000 { compatible = "qcom,sm8350-cdsp-pas"; reg = <0 0x98900000 0 0x1400000>; - interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, From 3515c3172f66ad4b3f485862f858f76a3e49c659 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Fri, 17 Nov 2023 11:28:49 +0530 Subject: [PATCH 3136/7721] arm64: defconfig: Enable GCC, pinctrl and interconnect for SDX75 Enable Global Clock controller, pinctrl and interconnect framework support for Qualcomm's SDX75 SoC which is required to boot to console on sdx75-idp platform. Signed-off-by: Rohit Agarwal Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231117055849.534671-1-quic_rohiagar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/configs/defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index b60aa1f89343..4c0cd428d073 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -599,6 +599,7 @@ CONFIG_PINCTRL_SC8280XP=y CONFIG_PINCTRL_SDM660=y CONFIG_PINCTRL_SDM670=y CONFIG_PINCTRL_SDM845=y +CONFIG_PINCTRL_SDX75=y CONFIG_PINCTRL_SM6115=y CONFIG_PINCTRL_SM6115_LPASS_LPI=m CONFIG_PINCTRL_SM6125=y @@ -1252,6 +1253,7 @@ CONFIG_SDM_GPUCC_845=y CONFIG_SDM_VIDEOCC_845=y CONFIG_SDM_DISPCC_845=y CONFIG_SDM_LPASSCC_845=m +CONFIG_SDX_GCC_75=y CONFIG_SM_CAMCC_8250=m CONFIG_SM_DISPCC_6115=m CONFIG_SM_DISPCC_8250=y @@ -1519,6 +1521,7 @@ CONFIG_INTERCONNECT_QCOM_SC7280=y CONFIG_INTERCONNECT_QCOM_SC8180X=y CONFIG_INTERCONNECT_QCOM_SC8280XP=y CONFIG_INTERCONNECT_QCOM_SDM845=y +CONFIG_INTERCONNECT_QCOM_SDX75=y CONFIG_INTERCONNECT_QCOM_SM8150=m CONFIG_INTERCONNECT_QCOM_SM8250=m CONFIG_INTERCONNECT_QCOM_SM8350=m From ea72a527bd205283db08287cd49737e889788065 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Fri, 17 Nov 2023 13:37:35 +0530 Subject: [PATCH 3137/7721] arm64: dts: qcom: Add interconnect nodes for SDX75 Add interconnect nodes to support interconnects on SDX75. Also parallely add the interconnect property for UART required so that the bootup to shell does not break with interconnects in place. Signed-off-by: Rohit Agarwal Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231117080737.606687-2-quic_rohiagar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdx75.dtsi | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdx75.dtsi b/arch/arm64/boot/dts/qcom/sdx75.dtsi index e180aa4023ec..b4723faf8655 100644 --- a/arch/arm64/boot/dts/qcom/sdx75.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx75.dtsi @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -203,6 +205,19 @@ scm: scm { }; }; + clk_virt: interconnect-0 { + compatible = "qcom,sdx75-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&rpmhcc RPMH_QPIC_CLK>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,sdx75-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + memory@80000000 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x0>; @@ -434,6 +449,9 @@ qupv3_id_0: geniqup@9c0000 { clock-names = "m-ahb", "s-ahb"; iommus = <&apps_smmu 0xe3 0x0>; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core"; #address-cells = <2>; #size-cells = <2>; ranges; @@ -444,6 +462,12 @@ uart1: serial@984000 { reg = <0x0 0x00984000 0x0 0x4000>; clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &system_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; interrupts = ; pinctrl-0 = <&qupv3_se1_2uart_active>; pinctrl-1 = <&qupv3_se1_2uart_sleep>; @@ -453,6 +477,20 @@ uart1: serial@984000 { }; }; + system_noc: interconnect@1640000 { + compatible = "qcom,sdx75-system-noc"; + reg = <0x0 0x01640000 0x0 0x4b400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + pcie_anoc: interconnect@16c0000 { + compatible = "qcom,sdx75-pcie-anoc"; + reg = <0x0 0x016c0000 0x0 0x14200>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; @@ -733,6 +771,20 @@ cpufreq_hw: cpufreq@17d91000 { #freq-domain-cells = <1>; #clock-cells = <1>; }; + + dc_noc: interconnect@190e0000 { + compatible = "qcom,sdx75-dc-noc"; + reg = <0x0 0x190e0000 0x0 0x8200>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + gem_noc: interconnect@19100000 { + compatible = "qcom,sdx75-gem-noc"; + reg = <0x0 0x19100000 0x0 0x34080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; }; timer { From f47303a8d0b50e762930d4d09ea883fd741394ea Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Fri, 17 Nov 2023 13:37:36 +0530 Subject: [PATCH 3138/7721] arm64: dts: qcom: Add USB3 and PHY support on SDX75 Add devicetree nodes for enabling USB3 controller, Qcom QMP PHY and HS PHY on SDX75. Signed-off-by: Rohit Agarwal Acked-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231117080737.606687-3-quic_rohiagar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdx75.dtsi | 118 ++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdx75.dtsi b/arch/arm64/boot/dts/qcom/sdx75.dtsi index b4723faf8655..7dbdf8ca6de6 100644 --- a/arch/arm64/boot/dts/qcom/sdx75.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx75.dtsi @@ -477,6 +477,47 @@ &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, }; }; + usb_hsphy: phy@ff4000 { + compatible = "qcom,sdx75-snps-eusb2-phy", "qcom,sm8550-snps-eusb2-phy"; + reg = <0x0 0x00ff4000 0x0 0x154>; + #phy-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_BCR>; + + status = "disabled"; + }; + + usb_qmpphy: phy@ff6000 { + compatible = "qcom,sdx75-qmp-usb3-uni-phy"; + reg = <0x0 0x00ff6000 0x0 0x2000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB2_CLKREF_EN>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + + power-domains = <&gcc GCC_USB3_PHY_GDSC>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; + + #clock-cells = <0>; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + + #phy-cells = <0>; + + status = "disabled"; + }; + system_noc: interconnect@1640000 { compatible = "qcom,sdx75-system-noc"; reg = <0x0 0x01640000 0x0 0x4b400>; @@ -497,6 +538,83 @@ tcsr_mutex: hwlock@1f40000 { #hwlock-cells = <1>; }; + usb: usb@a6f8800 { + compatible = "qcom,sdx75-dwc3", "qcom,dwc3"; + reg = <0x0 0x0a6f8800 0x0 0x400>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_USB30_SLV_AHB_CLK>, + <&gcc GCC_USB30_MASTER_CLK>, + <&gcc GCC_USB30_MSTR_AXI_CLK>, + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; + + assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 9 IRQ_TYPE_EDGE_RISING>, + <&pdc 10 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; + + power-domains = <&gcc GCC_USB30_GDSC>; + + resets = <&gcc GCC_USB30_BCR>; + + interconnects = <&system_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &system_noc SLAVE_USB3 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "usb-ddr", + "apps-usb"; + + status = "disabled"; + + usb_dwc3: usb@a600000 { + compatible = "snps,dwc3"; + reg = <0x0 0x0a600000 0x0 0xcd00>; + interrupts = ; + iommus = <&apps_smmu 0x80 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + phys = <&usb_hsphy>, + <&usb_qmpphy>; + phy-names = "usb2-phy", + "usb3-phy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + }; + }; + }; + }; + }; + pdc: interrupt-controller@b220000 { compatible = "qcom,sdx75-pdc", "qcom,pdc"; reg = <0x0 0xb220000 0x0 0x30000>, From a8db1c061f8b4d6881253640119f651031eb3786 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Fri, 17 Nov 2023 13:37:37 +0530 Subject: [PATCH 3139/7721] arm64: dts: qcom: sdx75-idp: Enable USB3 and PHY support Enable the support for USB3 controller, QMP PHY and HS PHY on SDX75 IDP. Signed-off-by: Rohit Agarwal Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231117080737.606687-4-quic_rohiagar@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdx75-idp.dts | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdx75-idp.dts b/arch/arm64/boot/dts/qcom/sdx75-idp.dts index a14e0650c4a8..f76e72fb2072 100644 --- a/arch/arm64/boot/dts/qcom/sdx75-idp.dts +++ b/arch/arm64/boot/dts/qcom/sdx75-idp.dts @@ -250,6 +250,11 @@ &chosen { stdout-path = "serial0:115200n8"; }; +&pm7550ba_eusb2_repeater { + vdd18-supply = <&vreg_l5b_1p776>; + vdd3-supply = <&vreg_l10b_3p08>; +}; + &qupv3_id_0 { status = "okay"; }; @@ -261,3 +266,27 @@ &tlmm { &uart1 { status = "okay"; }; + +&usb { + status = "okay"; +}; + +&usb_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_hsphy { + vdd-supply = <&vreg_l4b_0p88>; + vdda12-supply = <&vreg_l1b_1p2>; + + phys = <&pm7550ba_eusb2_repeater>; + + status = "okay"; +}; + +&usb_qmpphy { + vdda-phy-supply = <&vreg_l4b_0p88>; + vdda-pll-supply = <&vreg_l1b_1p2>; + + status = "okay"; +}; From e9ceb595c2d30edb2879f173f8d0dbbedd5e301c Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 17 Nov 2023 15:23:14 +0530 Subject: [PATCH 3140/7721] dt-bindings: cache: qcom,llcc: Add X1E80100 compatible Add the compatible for X1E80100 platforms. Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231117095315.2087-2-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/cache/qcom,llcc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 7a211e35e166..b9a9f2cf32a1 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -34,6 +34,7 @@ properties: - qcom,sm8450-llcc - qcom,sm8550-llcc - qcom,sm8650-llcc + - qcom,x1e80100-llcc reg: minItems: 2 @@ -105,6 +106,7 @@ allOf: - qcom,qdu1000-llcc - qcom,sc8180x-llcc - qcom,sc8280xp-llcc + - qcom,x1e80100-llcc then: properties: reg: From b3cf69a43502a8836b6d615c8aba05b88f00d8d8 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 17 Nov 2023 15:23:15 +0530 Subject: [PATCH 3141/7721] soc: qcom: llcc: Add configuration data for X1E80100 Add LLCC configuration data for X1E80100 SoC. Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20231117095315.2087-3-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index e92b950c2a9c..b5ca08c020ac 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -419,6 +419,29 @@ static const struct llcc_slice_config qdu1000_data_8ch[] = { { LLCC_WRCACHE, 31, 512, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, }; +static const struct llcc_slice_config x1e80100_data[] = { + {LLCC_CPUSS, 1, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AUDIO, 6, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CMPT, 10, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPUHTW, 11, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPU, 9, 4096, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MMUHWT, 18, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CVP, 8, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP1, 7, 3072, 2, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_LCPDARE, 30, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AENPU, 3, 3072, 1, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND1, 12, 512, 7, 1, 0x1, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND2, 13, 512, 7, 1, 0x2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND3, 14, 512, 7, 1, 0x3, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND4, 15, 512, 7, 1, 0x4, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP2, 19, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP3, 20, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP4, 21, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { .trp_ecc_error_status0 = 0x20344, .trp_ecc_error_status1 = 0x20348, @@ -647,6 +670,16 @@ static const struct qcom_llcc_config sm8650_cfg[] = { }, }; +static const struct qcom_llcc_config x1e80100_cfg[] = { + { + .sct_data = x1e80100_data, + .size = ARRAY_SIZE(x1e80100_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + static const struct qcom_sct_config qdu1000_cfgs = { .llcc_config = qdu1000_cfg, .num_config = ARRAY_SIZE(qdu1000_cfg), @@ -717,6 +750,11 @@ static const struct qcom_sct_config sm8650_cfgs = { .num_config = ARRAY_SIZE(sm8650_cfg), }; +static const struct qcom_sct_config x1e80100_cfgs = { + .llcc_config = x1e80100_cfg, + .num_config = ARRAY_SIZE(x1e80100_cfg), +}; + static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; /** @@ -1292,6 +1330,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs }, { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs }, { .compatible = "qcom,sm8650-llcc", .data = &sm8650_cfgs }, + { .compatible = "qcom,x1e80100-llcc", .data = &x1e80100_cfgs }, { } }; MODULE_DEVICE_TABLE(of, qcom_llcc_of_match); From 08105d9a5490551d86d95729bbbd3161652850dd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 Nov 2023 11:06:17 +0100 Subject: [PATCH 3142/7721] dt-bindings: arm: qcom-soc: extend pattern for matching existing SoCs Add missing QDU, QRU and SDA platform names to the pattern matching all Qualcomm compatibles. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231120100617.47156-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/arm/qcom-soc.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml index 97621c92a1ab..09db42456c12 100644 --- a/Documentation/devicetree/bindings/arm/qcom-soc.yaml +++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml @@ -23,7 +23,7 @@ description: | select: properties: compatible: - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" + pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" required: - compatible @@ -31,17 +31,17 @@ properties: compatible: oneOf: # Preferred naming style for compatibles of SoC components: - - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+(pro)?-.*$" + - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+(pro)?-.*$" - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$" # Legacy namings - variations of existing patterns/compatibles are OK, # but do not add completely new entries to these: - - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" + - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" - enum: - qcom,dsi-ctrl-6g-qcm2290 - qcom,gpucc-sdm630 From 0ab1bef0b7c359e672cc2b8d51f0179cefa369fc Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 20 Nov 2023 13:12:52 +0100 Subject: [PATCH 3143/7721] arm64: dts: qcom: sc7280: Add ZAP shader support Non-Chrome SC7280-family platforms ship a ZAP shader with the Adreno GPU. Describe that and make sure it doesn't interfere with Chrome devices. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230926-topic-a643-v2-1-06fa3d899c0a@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sc7280.dtsi | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 5d462ae14ba1..88fc67c3646e 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -17,6 +17,8 @@ * required by the setup for Chrome boards. */ +/delete-node/ &gpu_zap_mem; +/delete-node/ &gpu_zap_shader; /delete-node/ &hyp_mem; /delete-node/ &xbl_mem; /delete-node/ &reserved_xbl_uefi_log; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index a150131d4a8d..8af11b8cbdc0 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -153,6 +153,11 @@ ipa_fw_mem: memory@8b700000 { no-map; }; + gpu_zap_mem: zap@8b71a000 { + reg = <0 0x8b71a000 0 0x2000>; + no-map; + }; + rmtfs_mem: memory@9c900000 { compatible = "qcom,rmtfs-mem"; reg = <0x0 0x9c900000 0x0 0x280000>; @@ -2614,6 +2619,10 @@ gpu: gpu@3d00000 { nvmem-cells = <&gpu_speed_bin>; nvmem-cell-names = "speed_bin"; + gpu_zap_shader: zap-shader { + memory-region = <&gpu_zap_mem>; + }; + gpu_opp_table: opp-table { compatible = "operating-points-v2"; From 94085049fdad7a36fe14dd55e72e712fe55d6bca Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 20 Nov 2023 13:12:53 +0100 Subject: [PATCH 3144/7721] arm64: dts: qcom: sc7280: Fix up GPU SIDs GPU_SMMU SID 1 is meant for Adreno LPAC (Low Priority Async Compute). On platforms that support it (in firmware), it is necessary to describe that link, or Adreno register access will hang the board. The current settings are functionally identical, *but* due to what is likely hardcoded security policies, the secure firmware rejects them, resulting in the board hanging. To avoid that, alter the settings such that SID 0 and 1 are described separately. Fixes: 96c471970b7b ("arm64: dts: qcom: sc7280: Add gpu support") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230926-topic-a643-v2-2-06fa3d899c0a@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 8af11b8cbdc0..7ee703f9a16e 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2609,7 +2609,8 @@ gpu: gpu@3d00000 { "cx_mem", "cx_dbgc"; interrupts = ; - iommus = <&adreno_smmu 0 0x401>; + iommus = <&adreno_smmu 0 0x400>, + <&adreno_smmu 1 0x400>; operating-points-v2 = <&gpu_opp_table>; qcom,gmu = <&gmu>; interconnects = <&gem_noc MASTER_GFX3D 0 &mc_virt SLAVE_EBI1 0>; From 31edad478534186a2718be9206ce7b19f2735f6e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 20 Nov 2023 13:12:54 +0100 Subject: [PATCH 3145/7721] arm64: dts: qcom: sc7280: Mark Adreno SMMU as DMA coherent The SMMUs on sc7280 are cache-coherent. APPS_SMMU is marked as such, mark the GPU one as well. Fixes: 96c471970b7b ("arm64: dts: qcom: sc7280: Add gpu support") Reviewed-by: Akhil P Oommen Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230926-topic-a643-v2-3-06fa3d899c0a@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 7ee703f9a16e..82c65d58ce87 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2788,6 +2788,7 @@ adreno_smmu: iommu@3da0000 { "gpu_cc_hub_aon_clk"; power-domains = <&gpucc GPU_CC_CX_GDSC>; + dma-coherent; }; remoteproc_mpss: remoteproc@4080000 { From 6a7f8c635dab30233df93b5566d4169ed956b71b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 20 Nov 2023 13:12:55 +0100 Subject: [PATCH 3146/7721] arm64: dts: qcom: sc7280: Add 0xac Adreno speed bin A643 (A635 speedbin 0xac) tops out at 812 MHz. Fill in the opp-supported-hw appropriately. Note that fuseval 0xac is referred to as speedbin 1 downstream, but that was already in use upstream, so 2 was chosen instead. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230926-topic-a643-v2-4-06fa3d899c0a@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 82c65d58ce87..707f4b448809 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2631,14 +2631,14 @@ opp-315000000 { opp-hz = /bits/ 64 <315000000>; opp-level = ; opp-peak-kBps = <1804000>; - opp-supported-hw = <0x03>; + opp-supported-hw = <0x07>; }; opp-450000000 { opp-hz = /bits/ 64 <450000000>; opp-level = ; opp-peak-kBps = <4068000>; - opp-supported-hw = <0x03>; + opp-supported-hw = <0x07>; }; /* Only applicable for SKUs which has 550Mhz as Fmax */ @@ -2653,28 +2653,28 @@ opp-550000000-1 { opp-hz = /bits/ 64 <550000000>; opp-level = ; opp-peak-kBps = <6832000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-608000000 { opp-hz = /bits/ 64 <608000000>; opp-level = ; opp-peak-kBps = <8368000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-level = ; opp-peak-kBps = <8532000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-812000000 { opp-hz = /bits/ 64 <812000000>; opp-level = ; opp-peak-kBps = <8532000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-840000000 { From 26b87a3dc3337315c9834aa94e01da7030ec2e6c Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Mon, 20 Nov 2023 19:03:04 +0500 Subject: [PATCH 3147/7721] arm64: dts: qcom: pm8916: Add BMS and charger pm8916 contains some hardware blocks for battery powered devices: - VM-BMS: Battery voltage monitoring block. - LBC: Linear battery charger. Add them to the pmic dtsi so the devices that make use of those blocks can enable them. Signed-off-by: Nikita Travkin Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231120-pm8916-dtsi-bms-lbc-v4-2-4f91056c8252@trvn.ru Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pm8916.dtsi | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi index f4de86787743..4b2e8fb47d2d 100644 --- a/arch/arm64/boot/dts/qcom/pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi @@ -41,6 +41,35 @@ watchdog { }; }; + pm8916_charger: charger@1000 { + compatible = "qcom,pm8916-lbc"; + reg = <0x1000>, <0x1200>, <0x1300>, <0x1600>; + reg-names = "chgr", "bat_if", "usb", "misc"; + + interrupts = <0x0 0x10 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbat_det", + "fast_chg", + "chg_fail", + "chg_done", + "bat_pres", + "temp_ok", + "coarse_det", + "usb_vbus", + "chg_gone", + "overtemp"; + + status = "disabled"; + }; + pm8916_usbin: usb-detect@1300 { compatible = "qcom,pm8941-misc"; reg = <0x1300>; @@ -91,6 +120,25 @@ channel@f { }; }; + pm8916_bms: battery@4000 { + compatible = "qcom,pm8916-bms-vm"; + reg = <0x4000>; + interrupts = <0x0 0x40 0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cv_leave", + "cv_enter", + "ocv_good", + "ocv_thr", + "fifo", + "state_chg"; + + status = "disabled"; + }; + rtc@6000 { compatible = "qcom,pm8941-rtc"; reg = <0x6000>, <0x6100>; From 12fbe58560d6f974339cc30e44c0c5452db331da Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Mon, 20 Nov 2023 19:03:05 +0500 Subject: [PATCH 3148/7721] arm64: dts: qcom: msm8916-longcheer-l8150: Add battery and charger Longcheer L8150 doesn't have any dedicated fuel-gauge or charger, instead making use of the pmic hardware blocks for those purposes. Add pm8916 bms and charger, as well as the battery cell description that those blocks rely on. Reviewed-by: Konrad Dybcio Signed-off-by: Nikita Travkin Link: https://lore.kernel.org/r/20231120-pm8916-dtsi-bms-lbc-v4-3-4f91056c8252@trvn.ru Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/msm8916-longcheer-l8150.dts | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts index 37fa55166918..8e4c77003109 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts @@ -49,6 +49,25 @@ mpss_mem: mpss@8e800000 { }; }; + battery: battery { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4350000>; + energy-full-design-microwatt-hours = <9500000>; + charge-full-design-microamp-hours = <2500000>; + + ocv-capacity-celsius = <25>; + ocv-capacity-table-0 = <4330000 100>, <4265000 95>, + <4208000 90>, <4153000 85>, <4100000 80>, <4049000 75>, + <4001000 70>, <3962000 65>, <3919000 60>, <3872000 55>, + <3839000 50>, <3817000 45>, <3798000 40>, <3783000 35>, + <3767000 30>, <3747000 25>, <3729000 20>, <3709000 16>, + <3688000 13>, <3681000 11>, <3680000 10>, <3679000 9>, + <3677000 8>, <3674000 7>, <3666000 6>, <3641000 5>, + <3597000 4>, <3537000 3>, <3457000 2>, <3336000 1>, + <3000000 0>; + }; + gpio-keys { compatible = "gpio-keys"; @@ -236,6 +255,22 @@ &blsp_uart2 { status = "okay"; }; +&pm8916_bms { + status = "okay"; + + monitored-battery = <&battery>; + power-supplies = <&pm8916_charger>; +}; + +&pm8916_charger { + status = "okay"; + + monitored-battery = <&battery>; + + qcom,fast-charge-safe-current = <900000>; + qcom,fast-charge-safe-voltage = <4300000>; +}; + &pm8916_codec { qcom,micbias-lvl = <2800>; qcom,mbhc-vthreshold-low = <75 150 237 450 500>; @@ -255,10 +290,6 @@ pm8916_l17: l17 { }; }; -&pm8916_usbin { - status = "okay"; -}; - &pm8916_vib { status = "okay"; }; @@ -282,11 +313,11 @@ &sound { &usb { status = "okay"; dr_mode = "peripheral"; - extcon = <&pm8916_usbin>; + extcon = <&pm8916_charger>; }; &usb_hs_phy { - extcon = <&pm8916_usbin>; + extcon = <&pm8916_charger>; }; &venus { From 0984bc0165f7c5203dfffe8cdb5186995f628a80 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:22 +0100 Subject: [PATCH 3149/7721] arm64: dts: qcom: sa8775p: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Note that only triggering on rising edges can be used to detect resume events but not disconnect events. Fixes: de1001525c1a ("arm64: dts: qcom: sa8775p: add USB nodes") Cc: Shazad Hussain Signed-off-by: Johan Hovold Reviewed-by: Andrew Halaney Link: https://lore.kernel.org/r/20231120164331.8116-3-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index 6b92f9083104..2da567a6f64e 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1615,8 +1615,8 @@ usb_0: usb@a6f8800 { assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_EDGE_RISING>, - <&pdc 15 IRQ_TYPE_EDGE_RISING>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, <&pdc 12 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", @@ -1702,8 +1702,8 @@ usb_1: usb@a8f8800 { assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 8 IRQ_TYPE_EDGE_RISING>, - <&pdc 7 IRQ_TYPE_EDGE_RISING>, + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 7 IRQ_TYPE_EDGE_BOTH>, <&pdc 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", @@ -1765,8 +1765,8 @@ usb_2: usb@a4f8800 { assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 10 IRQ_TYPE_EDGE_RISING>, - <&pdc 9 IRQ_TYPE_EDGE_RISING>; + <&pdc 10 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", "dm_hs_phy_irq"; From 9b956999bf725fd62613f719c3178fdbee6e5f47 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:23 +0100 Subject: [PATCH 3150/7721] arm64: dts: qcom: sc7180: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: 0b766e7fe5a2 ("arm64: dts: qcom: sc7180: Add USB related nodes") Cc: stable@vger.kernel.org # 5.10 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-4-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index f0f0709718ac..4dcaa15caef2 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -2966,8 +2966,8 @@ usb_1: usb@a6f8800 { interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 8 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 9 IRQ_TYPE_LEVEL_HIGH>; + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From c34199d967a946e55381404fa949382691737521 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:24 +0100 Subject: [PATCH 3151/7721] arm64: dts: qcom: sc7280: fix usb_1 wakeup interrupt types A recent cleanup reordering the usb_1 wakeup interrupts inadvertently switched the DP and SuperSpeed interrupt trigger types. Fixes: 4a7ffc10d195 ("arm64: dts: qcom: align DWC3 USB interrupts with DT schema") Cc: stable@vger.kernel.org # 5.19 Cc: Krzysztof Kozlowski Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231120164331.8116-5-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 707f4b448809..a0f4e51d64c9 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3724,9 +3724,9 @@ usb_1: usb@a6f8800 { assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, - <&pdc 17 IRQ_TYPE_EDGE_BOTH>; + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", From 24f8aba9a7c77c7e9d814a5754798e8346c7dd28 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:25 +0100 Subject: [PATCH 3152/7721] arm64: dts: qcom: sc7280: fix usb_2 wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Note that only triggering on rising edges can be used to detect resume events but not disconnect events. Fixes: bb9efa59c665 ("arm64: dts: qcom: sc7280: Add USB related nodes") Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-6-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index a0f4e51d64c9..0153bace1cf7 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3469,8 +3469,8 @@ usb_2: usb@8cf8800 { assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 12 IRQ_TYPE_EDGE_RISING>, - <&pdc 13 IRQ_TYPE_EDGE_RISING>; + <&pdc 12 IRQ_TYPE_EDGE_BOTH>, + <&pdc 13 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq"; From 0dc0f6da3d43da8d2297105663e51ecb01b6f790 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:26 +0100 Subject: [PATCH 3153/7721] arm64: dts: qcom: sc8180x: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: b080f53a8f44 ("arm64: dts: qcom: sc8180x: Add remoteprocs, wifi and usb nodes") Cc: stable@vger.kernel.org # 6.5 Cc: Vinod Koul Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-7-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index a7abf3d703af..b857959a896b 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -2546,8 +2546,8 @@ usb_prim: usb@a6f8800 { reg = <0 0x0a6f8800 0 0x400>; interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", @@ -2620,8 +2620,8 @@ usb_sec: usb@a8f8800 { power-domains = <&gcc USB30_SEC_GDSC>; interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From de3b3de30999106549da4df88a7963d0ac02b91e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:27 +0100 Subject: [PATCH 3154/7721] arm64: dts: qcom: sdm670: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: 07c8ded6e373 ("arm64: dts: qcom: add sdm670 and pixel 3a device trees") Cc: stable@vger.kernel.org # 6.2 Cc: Richard Acayan Signed-off-by: Johan Hovold Acked-by: Richard Acayan Link: https://lore.kernel.org/r/20231120164331.8116-8-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 6d9843d05cb3..106620523580 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1297,8 +1297,8 @@ usb_1: usb@a6f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From 84ad9ac8d9ca29033d589e79a991866b38e23b85 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:28 +0100 Subject: [PATCH 3155/7721] arm64: dts: qcom: sdm845: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: ca4db2b538a1 ("arm64: dts: qcom: sdm845: Add USB-related nodes") Cc: stable@vger.kernel.org # 4.20 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-9-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index b8d0fa283085..42cf90a46887 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4072,8 +4072,8 @@ usb_1: usb@a6f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -4123,8 +4123,8 @@ usb_2: usb@a8f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From 41952be6661b20f56c2c5b06c431880dd975b747 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:29 +0100 Subject: [PATCH 3156/7721] arm64: dts: qcom: sm6375: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: 59d34ca97f91 ("arm64: dts: qcom: Add initial device tree for SM6375") Cc: stable@vger.kernel.org # 6.2 Cc: Konrad Dybcio Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-10-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6375.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi index 2fba0e7ea4e6..331bd98dbfde 100644 --- a/arch/arm64/boot/dts/qcom/sm6375.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi @@ -1405,8 +1405,8 @@ usb_1: usb@4ef8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", From 54524b6987d1fffe64cbf3dded1b2fa6b903edf9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:30 +0100 Subject: [PATCH 3157/7721] arm64: dts: qcom: sm8150: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: 0c9dde0d2015 ("arm64: dts: qcom: sm8150: Add secondary USB and PHY nodes") Fixes: b33d2868e8d3 ("arm64: dts: qcom: sm8150: Add USB and PHY device nodes") Cc: stable@vger.kernel.org # 5.10 Cc: Jonathan Marek Cc: Jack Pham Signed-off-by: Johan Hovold Reviewed-by: Jack Pham Link: https://lore.kernel.org/r/20231120164331.8116-11-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index fb7fd96ea61d..2ce07910dd13 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3560,8 +3560,8 @@ usb_1: usb@a6f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -3613,8 +3613,8 @@ usb_2: usb@a8f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From 29d91ecf530a4ef0b7f94cb8cde07ed69731e45d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:31 +0100 Subject: [PATCH 3158/7721] arm64: dts: qcom: sm8550: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Note that only triggering on rising edges can be used to detect resume events but not disconnect events. Fixes: 7f7e5c1b037f ("arm64: dts: qcom: sm8550: Add USB PHYs and controller nodes") Cc: Abel Vesa Signed-off-by: Johan Hovold Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20231120164331.8116-12-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 2fec3768c482..05cfb50207f9 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -2929,8 +2929,8 @@ usb_1: usb@a6f8800 { interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 15 IRQ_TYPE_EDGE_RISING>, - <&pdc 14 IRQ_TYPE_EDGE_RISING>; + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", From 405820eae72f1b51a4c46a81adf3c3de320c5688 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 7 Dec 2023 10:14:30 -0600 Subject: [PATCH 3159/7721] firmware: microchip: Replace of_device.h with explicit include The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. Soon the implicit includes are going to be removed. of_device.h isn't needed, but platform_device.h is. Reported-by: Stephen Rothwell Signed-off-by: Rob Herring Signed-off-by: Conor Dooley --- drivers/firmware/microchip/mpfs-auto-update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c index d56a95b36b85..81f5f62e34fc 100644 --- a/drivers/firmware/microchip/mpfs-auto-update.c +++ b/drivers/firmware/microchip/mpfs-auto-update.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include From d0ec3c4c11c3b30e1f2d344973b2a7bf0f986734 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2023 17:43:21 +0100 Subject: [PATCH 3160/7721] ARM: dts: qcom: sdx55: fix USB wakeup interrupt types The DP/DM wakeup interrupts are edge triggered and which edge to trigger on depends on use-case and whether a Low speed or Full/High speed device is connected. Fixes: fea4b41022f3 ("ARM: dts: qcom: sdx55: Add USB3 and PHY support") Cc: stable@vger.kernel.org # 5.12 Cc: Manivannan Sadhasivam Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20231120164331.8116-2-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-sdx55.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi index f604a27f50be..0fe220408888 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi @@ -582,8 +582,8 @@ usb: usb@a6f8800 { interrupts = , , - , - ; + , + ; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; From d50b5cb1a8f7db8ad2dc6a13f0cabedf7a7e1540 Mon Sep 17 00:00:00 2001 From: Dang Huynh Date: Tue, 21 Nov 2023 12:35:02 +0700 Subject: [PATCH 3161/7721] soc: qcom: socinfo: Add PM8937 Power IC The PM8917 and PM8937 uses the same SUBTYPE ID. The PM8937 is found in boards with MSM8917, MSM8937 and MSM8940 and APQ variants. Signed-off-by: Dang Huynh Link: https://lore.kernel.org/r/20231121-pm8937-v2-4-b0171ab62075@riseup.net Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 8e8cd4ea58d1..842621e4b294 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -93,7 +93,7 @@ static const char *const pmic_models[] = { [22] = "PM8821", [23] = "PM8038", [24] = "PM8005/PM8922", - [25] = "PM8917", + [25] = "PM8917/PM8937", [26] = "PM660L", [27] = "PM660", [30] = "PM8150", From 17fc6f391932dfc8c11634667ca2d1d24c961cf5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 21 Nov 2023 10:51:11 +0100 Subject: [PATCH 3162/7721] arm64: deconfig: enable Qualcomm SM8650 SoC drivers Enable Clocks, Pinctrl and Interconnect drivers in the ARM64 defconfig for the Qualcomm SM8650 SoC to boot the SM8650 MTP (Mobile Test Platform) and QRD (Qualcomm Reference Device) boards. TCSRCC, GCC, Interconnect, and Pinctrl config are marked as builtin and not modules due to boot dependencies. Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231121-topic-sm8650-upstream-defconfig-v1-1-2500565fc21b@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/configs/defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 4c0cd428d073..d3be3af4a3d8 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -614,6 +614,7 @@ CONFIG_PINCTRL_SM8450=y CONFIG_PINCTRL_SM8450_LPASS_LPI=m CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m CONFIG_PINCTRL_SM8550=y +CONFIG_PINCTRL_SM8650=y CONFIG_PINCTRL_SM8550_LPASS_LPI=m CONFIG_PINCTRL_LPASS_LPI=m CONFIG_GPIO_AGGREGATOR=m @@ -1259,14 +1260,18 @@ CONFIG_SM_DISPCC_6115=m CONFIG_SM_DISPCC_8250=y CONFIG_SM_DISPCC_8450=m CONFIG_SM_DISPCC_8550=m +CONFIG_SM_DISPCC_8650=m CONFIG_SM_GCC_6115=y CONFIG_SM_GCC_8350=y CONFIG_SM_GCC_8450=y CONFIG_SM_GCC_8550=y +CONFIG_SM_GCC_8650=y CONFIG_SM_TCSRCC_8550=y +CONFIG_SM_TCSRCC_8650=y CONFIG_SM_GPUCC_6115=m CONFIG_SM_GPUCC_8150=y CONFIG_SM_GPUCC_8250=y +CONFIG_SM_GPUCC_8650=m CONFIG_SM_VIDEOCC_8250=y CONFIG_QCOM_HFPLL=y CONFIG_CLK_GFM_LPASS_SM8250=m @@ -1527,6 +1532,7 @@ CONFIG_INTERCONNECT_QCOM_SM8250=m CONFIG_INTERCONNECT_QCOM_SM8350=m CONFIG_INTERCONNECT_QCOM_SM8450=y CONFIG_INTERCONNECT_QCOM_SM8550=y +CONFIG_INTERCONNECT_QCOM_SM8650=y CONFIG_COUNTER=m CONFIG_RZ_MTU3_CNT=m CONFIG_HTE=y From 6ebd9a4f8b8d2b35cf965a04849c4ba763722f13 Mon Sep 17 00:00:00 2001 From: Satya Priya Kakitapalli Date: Wed, 22 Nov 2023 09:58:14 +0530 Subject: [PATCH 3163/7721] clk: qcom: gpucc-sm8150: Update the gpu_cc_pll1 config Update the test_ctl_hi_val and test_ctl_hi1_val of gpu_cc_pll1 as per latest HW recommendation. Fixes: 0cef71f2ccc8 ("clk: qcom: Add graphics clock controller driver for SM8150") Signed-off-by: Satya Priya Kakitapalli Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231122042814.4158076-1-quic_skakitap@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gpucc-sm8150.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c index 8422fd047493..c89a5b59ddb7 100644 --- a/drivers/clk/qcom/gpucc-sm8150.c +++ b/drivers/clk/qcom/gpucc-sm8150.c @@ -37,8 +37,8 @@ static struct alpha_pll_config gpu_cc_pll1_config = { .config_ctl_hi_val = 0x00002267, .config_ctl_hi1_val = 0x00000024, .test_ctl_val = 0x00000000, - .test_ctl_hi_val = 0x00000002, - .test_ctl_hi1_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x00000020, .user_ctl_val = 0x00000000, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000d0, From 0f2d06dd1910cc7f6591620a2070d44ca3f56551 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Thu, 7 Dec 2023 16:43:29 +0000 Subject: [PATCH 3164/7721] MAINTAINERS: add auto-update driver to mpfs entry Rob's scripts were broken by the lack of a maintainer for this file, while trying to fix an integration issue in linux-next. Add it to the existing entry for PolarFire SoC drivers so that when the next bug is found the contributor knows where to send it. Reported-by: Rob Herring Signed-off-by: Conor Dooley --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..9241ce99a861 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18641,6 +18641,7 @@ F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml F: arch/riscv/boot/dts/microchip/ F: drivers/char/hw_random/mpfs-rng.c F: drivers/clk/microchip/clk-mpfs*.c +F: drivers/firmware/microchip/mpfs-auto-update.c F: drivers/i2c/busses/i2c-microchip-corei2c.c F: drivers/mailbox/mailbox-mpfs.c F: drivers/pci/controller/pcie-microchip-host.c From d4a599c59d2cc6f1e8a7c3debc85d7186a0caadb Mon Sep 17 00:00:00 2001 From: Imran Shaik Date: Thu, 23 Nov 2023 12:17:32 +0530 Subject: [PATCH 3165/7721] dt-bindings: clock: qcom: Add ECPRICC clocks for QDU1000 and QRU1000 Add device tree bindings for qcom ecpri clock controller on QDU1000 and QRU1000 SoCs. Signed-off-by: Imran Shaik Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231123064735.2979802-2-quic_imrashai@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,qdu1000-ecpricc.yaml | 68 ++++++++ .../dt-bindings/clock/qcom,qdu1000-ecpricc.h | 147 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml create mode 100644 include/dt-bindings/clock/qcom,qdu1000-ecpricc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml new file mode 100644 index 000000000000..fd21df0e7697 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,qdu1000-ecpricc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm ECPRI Clock & Reset Controller for QDU1000 and QRU1000 + +maintainers: + - Taniya Das + - Imran Shaik + +description: | + Qualcomm ECPRI Specification V2.0 Common Public Radio Interface clock control + module which supports the clocks, resets on QDU1000 and QRU1000 + + See also:: include/dt-bindings/clock/qcom,qdu1000-ecpricc.h + +properties: + compatible: + enum: + - qcom,qdu1000-ecpricc + + reg: + maxItems: 1 + + clocks: + items: + - description: Board XO source + - description: GPLL0 source from GCC + - description: GPLL1 source from GCC + - description: GPLL2 source from GCC + - description: GPLL3 source from GCC + - description: GPLL4 source from GCC + - description: GPLL5 source from GCC + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + #include + clock-controller@280000 { + compatible = "qcom,qdu1000-ecpricc"; + reg = <0x00280000 0x31c00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_ECPRI_CC_GPLL0_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL3_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL4_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h b/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h new file mode 100644 index 000000000000..731e404a2ce6 --- /dev/null +++ b/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_ECPRI_CC_QDU1000_H +#define _DT_BINDINGS_CLK_QCOM_ECPRI_CC_QDU1000_H + +/* ECPRI_CC clocks */ +#define ECPRI_CC_PLL0 0 +#define ECPRI_CC_PLL1 1 +#define ECPRI_CC_ECPRI_CG_CLK 2 +#define ECPRI_CC_ECPRI_CLK_SRC 3 +#define ECPRI_CC_ECPRI_DMA_CLK 4 +#define ECPRI_CC_ECPRI_DMA_CLK_SRC 5 +#define ECPRI_CC_ECPRI_DMA_NOC_CLK 6 +#define ECPRI_CC_ECPRI_FAST_CLK 7 +#define ECPRI_CC_ECPRI_FAST_CLK_SRC 8 +#define ECPRI_CC_ECPRI_FAST_DIV2_CLK 9 +#define ECPRI_CC_ECPRI_FAST_DIV2_CLK_SRC 10 +#define ECPRI_CC_ECPRI_FAST_DIV2_NOC_CLK 11 +#define ECPRI_CC_ECPRI_FR_CLK 12 +#define ECPRI_CC_ECPRI_ORAN_CLK_SRC 13 +#define ECPRI_CC_ECPRI_ORAN_DIV2_CLK 14 +#define ECPRI_CC_ETH_100G_C2C0_HM_FF_CLK_SRC 15 +#define ECPRI_CC_ETH_100G_C2C0_UDP_FIFO_CLK 16 +#define ECPRI_CC_ETH_100G_C2C1_UDP_FIFO_CLK 17 +#define ECPRI_CC_ETH_100G_C2C_0_HM_FF_0_CLK 18 +#define ECPRI_CC_ETH_100G_C2C_0_HM_FF_1_CLK 19 +#define ECPRI_CC_ETH_100G_C2C_HM_FF_0_DIV_CLK_SRC 20 +#define ECPRI_CC_ETH_100G_C2C_HM_FF_1_DIV_CLK_SRC 21 +#define ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK 22 +#define ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK_SRC 23 +#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_CLK 24 +#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_DIV_CLK_SRC 25 +#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_CLK 26 +#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_DIV_CLK_SRC 27 +#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_CLK_SRC 28 +#define ECPRI_CC_ETH_100G_DBG_C2C_UDP_FIFO_CLK 29 +#define ECPRI_CC_ETH_100G_FH0_HM_FF_CLK_SRC 30 +#define ECPRI_CC_ETH_100G_FH0_MACSEC_CLK_SRC 31 +#define ECPRI_CC_ETH_100G_FH1_HM_FF_CLK_SRC 32 +#define ECPRI_CC_ETH_100G_FH1_MACSEC_CLK_SRC 33 +#define ECPRI_CC_ETH_100G_FH2_HM_FF_CLK_SRC 34 +#define ECPRI_CC_ETH_100G_FH2_MACSEC_CLK_SRC 35 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_0_CLK 36 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_0_DIV_CLK_SRC 37 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_1_CLK 38 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_1_DIV_CLK_SRC 39 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_2_CLK 40 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_2_DIV_CLK_SRC 41 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_3_CLK 42 +#define ECPRI_CC_ETH_100G_FH_0_HM_FF_3_DIV_CLK_SRC 43 +#define ECPRI_CC_ETH_100G_FH_0_UDP_FIFO_CLK 44 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_0_CLK 45 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_0_DIV_CLK_SRC 46 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_1_CLK 47 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_1_DIV_CLK_SRC 48 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_2_CLK 49 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_2_DIV_CLK_SRC 50 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_3_CLK 51 +#define ECPRI_CC_ETH_100G_FH_1_HM_FF_3_DIV_CLK_SRC 52 +#define ECPRI_CC_ETH_100G_FH_1_UDP_FIFO_CLK 53 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_0_CLK 54 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_0_DIV_CLK_SRC 55 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_1_CLK 56 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_1_DIV_CLK_SRC 57 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_2_CLK 58 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_2_DIV_CLK_SRC 59 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_3_CLK 60 +#define ECPRI_CC_ETH_100G_FH_2_HM_FF_3_DIV_CLK_SRC 61 +#define ECPRI_CC_ETH_100G_FH_2_UDP_FIFO_CLK 62 +#define ECPRI_CC_ETH_100G_FH_MACSEC_0_CLK 63 +#define ECPRI_CC_ETH_100G_FH_MACSEC_1_CLK 64 +#define ECPRI_CC_ETH_100G_FH_MACSEC_2_CLK 65 +#define ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK 66 +#define ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK_SRC 67 +#define ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK 68 +#define ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK_SRC 69 +#define ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK 70 +#define ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK_SRC 71 +#define ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK 72 +#define ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK_SRC 73 +#define ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK 74 +#define ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK_SRC 75 +#define ECPRI_CC_ETH_DBG_NFAPI_AXI_CLK 76 +#define ECPRI_CC_ETH_DBG_NOC_AXI_CLK 77 +#define ECPRI_CC_ETH_PHY_0_OCK_SRAM_CLK 78 +#define ECPRI_CC_ETH_PHY_1_OCK_SRAM_CLK 79 +#define ECPRI_CC_ETH_PHY_2_OCK_SRAM_CLK 80 +#define ECPRI_CC_ETH_PHY_3_OCK_SRAM_CLK 81 +#define ECPRI_CC_ETH_PHY_4_OCK_SRAM_CLK 82 +#define ECPRI_CC_MSS_EMAC_CLK 83 +#define ECPRI_CC_MSS_EMAC_CLK_SRC 84 +#define ECPRI_CC_MSS_ORAN_CLK 85 +#define ECPRI_CC_PHY0_LANE0_RX_CLK 86 +#define ECPRI_CC_PHY0_LANE0_TX_CLK 87 +#define ECPRI_CC_PHY0_LANE1_RX_CLK 88 +#define ECPRI_CC_PHY0_LANE1_TX_CLK 89 +#define ECPRI_CC_PHY0_LANE2_RX_CLK 90 +#define ECPRI_CC_PHY0_LANE2_TX_CLK 91 +#define ECPRI_CC_PHY0_LANE3_RX_CLK 92 +#define ECPRI_CC_PHY0_LANE3_TX_CLK 93 +#define ECPRI_CC_PHY1_LANE0_RX_CLK 94 +#define ECPRI_CC_PHY1_LANE0_TX_CLK 95 +#define ECPRI_CC_PHY1_LANE1_RX_CLK 96 +#define ECPRI_CC_PHY1_LANE1_TX_CLK 97 +#define ECPRI_CC_PHY1_LANE2_RX_CLK 98 +#define ECPRI_CC_PHY1_LANE2_TX_CLK 99 +#define ECPRI_CC_PHY1_LANE3_RX_CLK 100 +#define ECPRI_CC_PHY1_LANE3_TX_CLK 101 +#define ECPRI_CC_PHY2_LANE0_RX_CLK 102 +#define ECPRI_CC_PHY2_LANE0_TX_CLK 103 +#define ECPRI_CC_PHY2_LANE1_RX_CLK 104 +#define ECPRI_CC_PHY2_LANE1_TX_CLK 105 +#define ECPRI_CC_PHY2_LANE2_RX_CLK 106 +#define ECPRI_CC_PHY2_LANE2_TX_CLK 107 +#define ECPRI_CC_PHY2_LANE3_RX_CLK 108 +#define ECPRI_CC_PHY2_LANE3_TX_CLK 109 +#define ECPRI_CC_PHY3_LANE0_RX_CLK 110 +#define ECPRI_CC_PHY3_LANE0_TX_CLK 111 +#define ECPRI_CC_PHY3_LANE1_RX_CLK 112 +#define ECPRI_CC_PHY3_LANE1_TX_CLK 113 +#define ECPRI_CC_PHY3_LANE2_RX_CLK 114 +#define ECPRI_CC_PHY3_LANE2_TX_CLK 115 +#define ECPRI_CC_PHY3_LANE3_RX_CLK 116 +#define ECPRI_CC_PHY3_LANE3_TX_CLK 117 +#define ECPRI_CC_PHY4_LANE0_RX_CLK 118 +#define ECPRI_CC_PHY4_LANE0_TX_CLK 119 +#define ECPRI_CC_PHY4_LANE1_RX_CLK 120 +#define ECPRI_CC_PHY4_LANE1_TX_CLK 121 +#define ECPRI_CC_PHY4_LANE2_RX_CLK 122 +#define ECPRI_CC_PHY4_LANE2_TX_CLK 123 +#define ECPRI_CC_PHY4_LANE3_RX_CLK 124 +#define ECPRI_CC_PHY4_LANE3_TX_CLK 125 + +/* ECPRI_CC resets */ +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ECPRI_SS_BCR 0 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_C2C_BCR 1 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH0_BCR 2 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH1_BCR 3 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH2_BCR 4 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_WRAPPER_TOP_BCR 5 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_MODEM_BCR 6 +#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_NOC_BCR 7 + +#endif From 261625e0baa18405b057a6b3b20f839617110393 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 23 Nov 2023 12:17:33 +0530 Subject: [PATCH 3166/7721] clk: qcom: branch: Add mem ops support for branch2 clocks Add the support for mem ops implementation to handle the sequence of enable/disable of the memories in ethernet PHY, prior to enable/disable of the respective clocks, which helps retain the respecive block's register contents. Signed-off-by: Taniya Das Signed-off-by: Imran Shaik Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231123064735.2979802-3-quic_imrashai@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-branch.c | 38 +++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-branch.h | 21 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index fc4735f74f0f..c1dba33ac31a 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -134,6 +135,43 @@ static void clk_branch2_disable(struct clk_hw *hw) clk_branch_toggle(hw, false, clk_branch2_check_halt); } +static int clk_branch2_mem_enable(struct clk_hw *hw) +{ + struct clk_mem_branch *mem_br = to_clk_mem_branch(hw); + struct clk_branch branch = mem_br->branch; + u32 val; + int ret; + + regmap_update_bits(branch.clkr.regmap, mem_br->mem_enable_reg, + mem_br->mem_enable_ack_mask, mem_br->mem_enable_ack_mask); + + ret = regmap_read_poll_timeout(branch.clkr.regmap, mem_br->mem_ack_reg, + val, val & mem_br->mem_enable_ack_mask, 0, 200); + if (ret) { + WARN(1, "%s mem enable failed\n", clk_hw_get_name(&branch.clkr.hw)); + return ret; + } + + return clk_branch2_enable(hw); +} + +static void clk_branch2_mem_disable(struct clk_hw *hw) +{ + struct clk_mem_branch *mem_br = to_clk_mem_branch(hw); + + regmap_update_bits(mem_br->branch.clkr.regmap, mem_br->mem_enable_reg, + mem_br->mem_enable_ack_mask, 0); + + return clk_branch2_disable(hw); +} + +const struct clk_ops clk_branch2_mem_ops = { + .enable = clk_branch2_mem_enable, + .disable = clk_branch2_mem_disable, + .is_enabled = clk_is_enabled_regmap, +}; +EXPORT_SYMBOL_GPL(clk_branch2_mem_ops); + const struct clk_ops clk_branch2_ops = { .enable = clk_branch2_enable, .disable = clk_branch2_disable, diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 0cf800b9d08d..8ffed603c050 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -38,6 +38,23 @@ struct clk_branch { struct clk_regmap clkr; }; +/** + * struct clk_mem_branch - gating clock which are associated with memories + * + * @mem_enable_reg: branch clock memory gating register + * @mem_ack_reg: branch clock memory ack register + * @mem_enable_ack_mask: branch clock memory enable and ack field in @mem_ack_reg + * @branch: branch clock gating handle + * + * Clock which can gate its memories. + */ +struct clk_mem_branch { + u32 mem_enable_reg; + u32 mem_ack_reg; + u32 mem_enable_ack_mask; + struct clk_branch branch; +}; + /* Branch clock common bits for HLOS-owned clocks */ #define CBCR_CLK_OFF BIT(31) #define CBCR_NOC_FSM_STATUS GENMASK(30, 28) @@ -85,8 +102,12 @@ extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch_simple_ops; extern const struct clk_ops clk_branch2_aon_ops; +extern const struct clk_ops clk_branch2_mem_ops; #define to_clk_branch(_hw) \ container_of(to_clk_regmap(_hw), struct clk_branch, clkr) +#define to_clk_mem_branch(_hw) \ + container_of(to_clk_branch(_hw), struct clk_mem_branch, branch) + #endif From e146252ac160587f9a12cd6508d0b3e3231cd9d8 Mon Sep 17 00:00:00 2001 From: Imran Shaik Date: Thu, 23 Nov 2023 12:17:34 +0530 Subject: [PATCH 3167/7721] clk: qcom: Add ECPRICC driver support for QDU1000 and QRU1000 Add ECPRI Clock Controller (ECPRICC) support for QDU1000 and QRU1000 SoCs. Signed-off-by: Imran Shaik Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231123064735.2979802-4-quic_imrashai@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/ecpricc-qdu1000.c | 2456 ++++++++++++++++++++++++++++ 3 files changed, 2466 insertions(+) create mode 100644 drivers/clk/qcom/ecpricc-qdu1000.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index cb4c2a726a6d..7a0b5c483f09 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -677,6 +677,15 @@ config QDU_GCC_1000 QRU1000 devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD, PCIe, etc. +config QDU_ECPRICC_1000 + tristate "QDU1000/QRU1000 ECPRI Clock Controller" + depends on ARM64 || COMPILE_TEST + select QDU_GCC_1000 + help + Support for the ECPRI clock controller on QDU1000 and + QRU1000 devices. Say Y if you want to support the ECPRI + clock controller functionality such as Ethernet. + config SDM_GCC_845 tristate "SDM845/SDM670 Global Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 72da2b9b53dc..fe9a5db24edd 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_QCM_DISPCC_2290) += dispcc-qcm2290.o obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o +obj-$(CONFIG_QDU_ECPRICC_1000) += ecpricc-qdu1000.o obj-$(CONFIG_QDU_GCC_1000) += gcc-qdu1000.o obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o obj-$(CONFIG_SC_CAMCC_7280) += camcc-sc7280.o diff --git a/drivers/clk/qcom/ecpricc-qdu1000.c b/drivers/clk/qcom/ecpricc-qdu1000.c new file mode 100644 index 000000000000..c628054a7025 --- /dev/null +++ b/drivers/clk/qcom/ecpricc-qdu1000.c @@ -0,0 +1,2456 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN, + DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN, +}; + +enum { + P_BI_TCXO, + P_ECPRI_CC_PLL0_OUT_MAIN, + P_ECPRI_CC_PLL1_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, + P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +/* 700 MHz configuration */ +static const struct alpha_pll_config ecpri_cc_pll0_config = { + .l = 0x24, + .alpha = 0x7555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, +}; + +static struct clk_alpha_pll ecpri_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +/* 806 MHz configuration */ +static const struct alpha_pll_config ecpri_cc_pll1_config = { + .l = 0x29, + .alpha = 0xfaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, +}; + +static struct clk_alpha_pll ecpri_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map ecpri_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 2 }, + { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct parent_map ecpri_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 2 }, + { P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN }, + { .index = DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct parent_map ecpri_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_clk_src[] = { + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_clk_src = { + .cmd_rcgr = 0x9034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_2, + .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_clk_src", + .parent_data = ecpri_cc_parent_data_2, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_dma_clk_src[] = { + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_dma_clk_src = { + .cmd_rcgr = 0x9080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_dma_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_fast_clk_src[] = { + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + F(600000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_fast_clk_src = { + .cmd_rcgr = 0x904c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_fast_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_oran_clk_src[] = { + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_oran_clk_src = { + .cmd_rcgr = 0x9064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_oran_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_oran_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src[] = { + F(201500000, P_ECPRI_CC_PLL1_OUT_MAIN, 4, 0, 0), + F(403000000, P_ECPRI_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_c2c0_hm_ff_clk_src = { + .cmd_rcgr = 0x81b0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c0_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src[] = { + F(100000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_c2c_hm_macsec_clk_src = { + .cmd_rcgr = 0x8150, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src = { + .cmd_rcgr = 0x81c8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh0_hm_ff_clk_src = { + .cmd_rcgr = 0x8168, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh0_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh0_macsec_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh0_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh1_hm_ff_clk_src = { + .cmd_rcgr = 0x8180, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh1_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src[] = { + F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh1_macsec_clk_src = { + .cmd_rcgr = 0x8120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh1_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh2_hm_ff_clk_src = { + .cmd_rcgr = 0x8198, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh2_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh2_macsec_clk_src = { + .cmd_rcgr = 0x8138, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh2_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src[] = { + F(533000000, P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 1, 0, 0), + F(700000000, P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 1, 0, 0), + F(806000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src = { + .cmd_rcgr = 0x8228, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src = { + .cmd_rcgr = 0x8240, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src = { + .cmd_rcgr = 0x81e0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src = { + .cmd_rcgr = 0x81f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src = { + .cmd_rcgr = 0x8210, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_mss_emac_clk_src[] = { + F(403000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_mss_emac_clk_src = { + .cmd_rcgr = 0xe00c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_2, + .freq_tbl = ftbl_ecpri_cc_mss_emac_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_emac_clk_src", + .parent_data = ecpri_cc_parent_data_2, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_ecpri_fast_div2_clk_src = { + .reg = 0x907c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src = { + .reg = 0x8290, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src = { + .reg = 0x8294, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src = { + .reg = 0x8298, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src = { + .reg = 0x829c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src = { + .reg = 0x8260, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src = { + .reg = 0x8264, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src = { + .reg = 0x8268, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src = { + .reg = 0x826c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src = { + .reg = 0x8270, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src = { + .reg = 0x8274, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src = { + .reg = 0x8278, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src = { + .reg = 0x827c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src = { + .reg = 0x8280, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src = { + .reg = 0x8284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src = { + .reg = 0x8288, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src = { + .reg = 0x828c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_cg_clk = { + .halt_reg = 0x900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x900c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_cg_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_dma_clk = { + .halt_reg = 0x902c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x902c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_dma_noc_clk = { + .halt_reg = 0xf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_noc_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_clk = { + .halt_reg = 0x9014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_div2_clk = { + .halt_reg = 0x901c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x901c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_div2_noc_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_noc_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fr_clk = { + .halt_reg = 0x9004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fr_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_oran_div2_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_oran_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_oran_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_c2c0_udp_fifo_clk = { + .halt_reg = 0x80cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c0_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_c2c1_udp_fifo_clk = { + .halt_reg = 0x80d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c1_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x80b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x80bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_hm_macsec_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x80ac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80ac, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x80d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x80e0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80e0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk = { + .halt_reg = 0x80f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_0_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_1_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x8014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_2_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x801c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x801c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_3_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_0_udp_fifo_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_0_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_1_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_2_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_3_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_1_udp_fifo_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_0_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_1_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_2_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_3_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x8094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_2_udp_fifo_clk = { + .halt_reg = 0x80a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_0_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_1_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_2_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_c2c_hm_ref_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x80c4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80c4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x80e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh0_hm_ref_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x802c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x802c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh1_hm_ref_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh2_hm_ref_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x809c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x809c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_dbg_nfapi_axi_clk = { + .halt_reg = 0x80f4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80f4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_dbg_nfapi_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_dbg_noc_axi_clk = { + .halt_reg = 0x80fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80fc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_dbg_noc_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_mss_emac_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_0_ock_sram_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd140, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd140, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_0_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_1_ock_sram_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841C, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd148, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd148, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_1_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_2_ock_sram_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_2_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_3_ock_sram_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd158, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd158, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_3_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_4_ock_sram_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd160, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd160, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_4_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_mss_emac_clk = { + .halt_reg = 0xe008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_emac_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_mss_emac_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_mss_oran_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_oran_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_oran_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane0_rx_clk = { + .halt_reg = 0xd000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane0_tx_clk = { + .halt_reg = 0xd050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane1_rx_clk = { + .halt_reg = 0xd004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane1_tx_clk = { + .halt_reg = 0xd054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane2_rx_clk = { + .halt_reg = 0xd008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane2_tx_clk = { + .halt_reg = 0xd058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane3_rx_clk = { + .halt_reg = 0xd00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane3_tx_clk = { + .halt_reg = 0xd05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane0_rx_clk = { + .halt_reg = 0xd010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane0_tx_clk = { + .halt_reg = 0xd060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane1_rx_clk = { + .halt_reg = 0xd014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane1_tx_clk = { + .halt_reg = 0xd064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane2_rx_clk = { + .halt_reg = 0xd018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane2_tx_clk = { + .halt_reg = 0xd068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane3_rx_clk = { + .halt_reg = 0xd01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane3_tx_clk = { + .halt_reg = 0xd06c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd06c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane0_rx_clk = { + .halt_reg = 0xd020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane0_tx_clk = { + .halt_reg = 0xd070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane1_rx_clk = { + .halt_reg = 0xd024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane1_tx_clk = { + .halt_reg = 0xd074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane2_rx_clk = { + .halt_reg = 0xd028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane2_tx_clk = { + .halt_reg = 0xd078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane3_rx_clk = { + .halt_reg = 0xd02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd02c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane3_tx_clk = { + .halt_reg = 0xd07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane0_rx_clk = { + .halt_reg = 0xd030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane0_tx_clk = { + .halt_reg = 0xd080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane1_rx_clk = { + .halt_reg = 0xd034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane1_tx_clk = { + .halt_reg = 0xd084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane2_rx_clk = { + .halt_reg = 0xd038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane2_tx_clk = { + .halt_reg = 0xd088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane3_rx_clk = { + .halt_reg = 0xd03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd03c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane3_tx_clk = { + .halt_reg = 0xd08c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd08c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane0_rx_clk = { + .halt_reg = 0xd040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane0_tx_clk = { + .halt_reg = 0xd090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane1_rx_clk = { + .halt_reg = 0xd044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane1_tx_clk = { + .halt_reg = 0xd094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane2_rx_clk = { + .halt_reg = 0xd048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane2_tx_clk = { + .halt_reg = 0xd098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd098, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane3_rx_clk = { + .halt_reg = 0xd04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd04c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane3_tx_clk = { + .halt_reg = 0xd09c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd09c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *ecpri_cc_qdu1000_clocks[] = { + [ECPRI_CC_ECPRI_CG_CLK] = &ecpri_cc_ecpri_cg_clk.clkr, + [ECPRI_CC_ECPRI_CLK_SRC] = &ecpri_cc_ecpri_clk_src.clkr, + [ECPRI_CC_ECPRI_DMA_CLK] = &ecpri_cc_ecpri_dma_clk.clkr, + [ECPRI_CC_ECPRI_DMA_CLK_SRC] = &ecpri_cc_ecpri_dma_clk_src.clkr, + [ECPRI_CC_ECPRI_DMA_NOC_CLK] = &ecpri_cc_ecpri_dma_noc_clk.clkr, + [ECPRI_CC_ECPRI_FAST_CLK] = &ecpri_cc_ecpri_fast_clk.clkr, + [ECPRI_CC_ECPRI_FAST_CLK_SRC] = &ecpri_cc_ecpri_fast_clk_src.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_CLK] = &ecpri_cc_ecpri_fast_div2_clk.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_CLK_SRC] = &ecpri_cc_ecpri_fast_div2_clk_src.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_NOC_CLK] = &ecpri_cc_ecpri_fast_div2_noc_clk.clkr, + [ECPRI_CC_ECPRI_FR_CLK] = &ecpri_cc_ecpri_fr_clk.clkr, + [ECPRI_CC_ECPRI_ORAN_CLK_SRC] = &ecpri_cc_ecpri_oran_clk_src.clkr, + [ECPRI_CC_ECPRI_ORAN_DIV2_CLK] = &ecpri_cc_ecpri_oran_div2_clk.clkr, + [ECPRI_CC_ETH_100G_C2C0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c0_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_C2C1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c1_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_C2C_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_CLK] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_CLK] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH0_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH1_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH1_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH2_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH2_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_0_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_1_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_2_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_0_CLK] = &ecpri_cc_eth_100g_fh_macsec_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_1_CLK] = &ecpri_cc_eth_100g_fh_macsec_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_2_CLK] = &ecpri_cc_eth_100g_fh_macsec_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK] = + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK_SRC] = + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_DBG_NFAPI_AXI_CLK] = &ecpri_cc_eth_dbg_nfapi_axi_clk.clkr, + [ECPRI_CC_ETH_DBG_NOC_AXI_CLK] = &ecpri_cc_eth_dbg_noc_axi_clk.clkr, + [ECPRI_CC_ETH_PHY_0_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_0_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_1_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_1_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_2_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_2_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_3_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_3_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_4_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_4_ock_sram_clk.branch.clkr, + [ECPRI_CC_MSS_EMAC_CLK] = &ecpri_cc_mss_emac_clk.clkr, + [ECPRI_CC_MSS_EMAC_CLK_SRC] = &ecpri_cc_mss_emac_clk_src.clkr, + [ECPRI_CC_MSS_ORAN_CLK] = &ecpri_cc_mss_oran_clk.clkr, + [ECPRI_CC_PHY0_LANE0_RX_CLK] = &ecpri_cc_phy0_lane0_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE0_TX_CLK] = &ecpri_cc_phy0_lane0_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE1_RX_CLK] = &ecpri_cc_phy0_lane1_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE1_TX_CLK] = &ecpri_cc_phy0_lane1_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE2_RX_CLK] = &ecpri_cc_phy0_lane2_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE2_TX_CLK] = &ecpri_cc_phy0_lane2_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE3_RX_CLK] = &ecpri_cc_phy0_lane3_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE3_TX_CLK] = &ecpri_cc_phy0_lane3_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE0_RX_CLK] = &ecpri_cc_phy1_lane0_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE0_TX_CLK] = &ecpri_cc_phy1_lane0_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE1_RX_CLK] = &ecpri_cc_phy1_lane1_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE1_TX_CLK] = &ecpri_cc_phy1_lane1_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE2_RX_CLK] = &ecpri_cc_phy1_lane2_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE2_TX_CLK] = &ecpri_cc_phy1_lane2_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE3_RX_CLK] = &ecpri_cc_phy1_lane3_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE3_TX_CLK] = &ecpri_cc_phy1_lane3_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE0_RX_CLK] = &ecpri_cc_phy2_lane0_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE0_TX_CLK] = &ecpri_cc_phy2_lane0_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE1_RX_CLK] = &ecpri_cc_phy2_lane1_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE1_TX_CLK] = &ecpri_cc_phy2_lane1_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE2_RX_CLK] = &ecpri_cc_phy2_lane2_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE2_TX_CLK] = &ecpri_cc_phy2_lane2_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE3_RX_CLK] = &ecpri_cc_phy2_lane3_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE3_TX_CLK] = &ecpri_cc_phy2_lane3_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE0_RX_CLK] = &ecpri_cc_phy3_lane0_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE0_TX_CLK] = &ecpri_cc_phy3_lane0_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE1_RX_CLK] = &ecpri_cc_phy3_lane1_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE1_TX_CLK] = &ecpri_cc_phy3_lane1_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE2_RX_CLK] = &ecpri_cc_phy3_lane2_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE2_TX_CLK] = &ecpri_cc_phy3_lane2_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE3_RX_CLK] = &ecpri_cc_phy3_lane3_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE3_TX_CLK] = &ecpri_cc_phy3_lane3_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE0_RX_CLK] = &ecpri_cc_phy4_lane0_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE0_TX_CLK] = &ecpri_cc_phy4_lane0_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE1_RX_CLK] = &ecpri_cc_phy4_lane1_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE1_TX_CLK] = &ecpri_cc_phy4_lane1_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE2_RX_CLK] = &ecpri_cc_phy4_lane2_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE2_TX_CLK] = &ecpri_cc_phy4_lane2_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE3_RX_CLK] = &ecpri_cc_phy4_lane3_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE3_TX_CLK] = &ecpri_cc_phy4_lane3_tx_clk.clkr, + [ECPRI_CC_PLL0] = &ecpri_cc_pll0.clkr, + [ECPRI_CC_PLL1] = &ecpri_cc_pll1.clkr, +}; + +static const struct qcom_reset_map ecpri_cc_qdu1000_resets[] = { + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ECPRI_SS_BCR] = { 0x9000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_C2C_BCR] = { 0x80a8 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH0_BCR] = { 0x8000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH1_BCR] = { 0x8038 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH2_BCR] = { 0x8070 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_WRAPPER_TOP_BCR] = { 0x8104 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_MODEM_BCR] = { 0xe000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_NOC_BCR] = { 0xf000 }, +}; + +static const struct regmap_config ecpri_cc_qdu1000_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x31bf0, + .fast_io = true, +}; + +static const struct qcom_cc_desc ecpri_cc_qdu1000_desc = { + .config = &ecpri_cc_qdu1000_regmap_config, + .clks = ecpri_cc_qdu1000_clocks, + .num_clks = ARRAY_SIZE(ecpri_cc_qdu1000_clocks), + .resets = ecpri_cc_qdu1000_resets, + .num_resets = ARRAY_SIZE(ecpri_cc_qdu1000_resets), +}; + +static const struct of_device_id ecpri_cc_qdu1000_match_table[] = { + { .compatible = "qcom,qdu1000-ecpricc" }, + { } +}; +MODULE_DEVICE_TABLE(of, ecpri_cc_qdu1000_match_table); + +static int ecpri_cc_qdu1000_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &ecpri_cc_qdu1000_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_evo_pll_configure(&ecpri_cc_pll0, regmap, &ecpri_cc_pll0_config); + clk_lucid_evo_pll_configure(&ecpri_cc_pll1, regmap, &ecpri_cc_pll1_config); + + return qcom_cc_really_probe(pdev, &ecpri_cc_qdu1000_desc, regmap); +} + +static struct platform_driver ecpri_cc_qdu1000_driver = { + .probe = ecpri_cc_qdu1000_probe, + .driver = { + .name = "ecpri_cc-qdu1000", + .of_match_table = ecpri_cc_qdu1000_match_table, + }, +}; + +module_platform_driver(ecpri_cc_qdu1000_driver); + +MODULE_DESCRIPTION("QTI ECPRICC QDU1000 Driver"); +MODULE_LICENSE("GPL"); From 66ec7b4f471300003c13b87a99bbd55255da5ba9 Mon Sep 17 00:00:00 2001 From: Imran Shaik Date: Thu, 23 Nov 2023 12:17:35 +0530 Subject: [PATCH 3168/7721] arm64: dts: qcom: qdu1000: Add ECPRI clock controller Add device node for ECPRI clock controller on qcom QDU1000 and QRU1000 SoCs. Signed-off-by: Imran Shaik Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231123064735.2979802-5-quic_imrashai@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qdu1000.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi index 89eff977d40e..832f472c4b7a 100644 --- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi +++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi @@ -381,6 +381,20 @@ gcc: clock-controller@80000 { #power-domain-cells = <1>; }; + ecpricc: clock-controller@280000 { + compatible = "qcom,qdu1000-ecpricc"; + reg = <0x0 0x00280000 0x0 0x31c00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_ECPRI_CC_GPLL0_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL3_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL4_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + gpi_dma0: dma-controller@900000 { compatible = "qcom,qdu1000-gpi-dma", "qcom,sm6350-gpi-dma"; reg = <0x0 0x900000 0x0 0x60000>; From 6a25e70214fde6dcf900271c819c8d7fe7b9a4b0 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 23 Nov 2023 13:12:54 +0100 Subject: [PATCH 3169/7721] arm64: dts: qcom: ipq8074: Add QUP4 SPI node Add node to support the QUP4 SPI controller inside of IPQ8074. Some devices use this bus to communicate to a Bluetooth controller. Signed-off-by: Robert Marko Link: https://lore.kernel.org/r/20231123121324.1046164-1-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index a4f7ae35be27..dca7005c0a9d 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -517,6 +517,20 @@ blsp1_i2c3: i2c@78b7000 { status = "disabled"; }; + blsp1_spi4: spi@78b8000 { + compatible = "qcom,spi-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b8000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + dmas = <&blsp_dma 18>, <&blsp_dma 19>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + blsp1_i2c5: i2c@78b9000 { compatible = "qcom,i2c-qup-v2.2.1"; #address-cells = <1>; From 6dedbd246cb694f5de49782de83c82af42a4b5d5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:50:48 +0100 Subject: [PATCH 3170/7721] ARM: dts: qcom: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231124095049.58618-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8226.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi index 5cd03ea7b084..b9686e75fe1d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi @@ -875,8 +875,8 @@ reboot-mode { offset = <0x65c>; mode-bootloader = <0x77665500>; - mode-normal = <0x77665501>; - mode-recovery = <0x77665502>; + mode-normal = <0x77665501>; + mode-recovery = <0x77665502>; }; }; From dd744d7d15294816bed9d66c7f815d8b24ccd22f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Nov 2023 10:50:49 +0100 Subject: [PATCH 3171/7721] arm64: dts: qcom: minor whitespace cleanup around '=' The DTS code coding style expects exactly one space before and after '=' sign. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231124095049.58618-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts | 2 +- arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts | 2 +- arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts | 2 +- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts index e89e2e948603..846413817e9a 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts @@ -15,7 +15,7 @@ / { }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts index efd480a7afdf..ed8a54eb95c0 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts @@ -15,7 +15,7 @@ / { }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts index eb1fa33d6fe4..d5f99e741ae5 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts @@ -15,7 +15,7 @@ / { }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index fbfd3a441173..1a73bbbb43bc 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -1046,7 +1046,7 @@ mdss_dsi1_phy: phy@1a96400 { apps_iommu: iommu@1e20000 { compatible = "qcom,msm8953-iommu", "qcom,msm-iommu-v1"; - ranges = <0 0x01e20000 0x20000>; + ranges = <0 0x01e20000 0x20000>; clocks = <&gcc GCC_SMMU_CFG_CLK>, <&gcc GCC_APSS_TCU_ASYNC_CLK>; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts index bb149e577914..edc0e42ee017 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts @@ -46,7 +46,7 @@ camera@1a { assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>; assigned-clock-rates = <24000000>; - dovdd-supply = <&vreg_l7f_1p8>; + dovdd-supply = <&vreg_l7f_1p8>; avdd-supply = <&vdc_5v>; dvdd-supply = <&vdc_5v>; From ef9284a55a78bf712e0bbe12b0d72d0a8ccd005e Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 24 Nov 2023 15:36:04 +0530 Subject: [PATCH 3172/7721] dt-bindings: arm: qcom-soc: extend pattern matching for X1E80100 SoC Extend pattern matching to support the X1E platform name. Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124100608.29964-2-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom-soc.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml index 09db42456c12..d0751a572af3 100644 --- a/Documentation/devicetree/bindings/arm/qcom-soc.yaml +++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml @@ -23,7 +23,7 @@ description: | select: properties: compatible: - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" required: - compatible @@ -31,7 +31,7 @@ properties: compatible: oneOf: # Preferred naming style for compatibles of SoC components: - - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+(pro)?-.*$" + - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+(pro)?-.*$" - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$" # Legacy namings - variations of existing patterns/compatibles are OK, @@ -39,9 +39,9 @@ properties: - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" - - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" - - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" - enum: - qcom,dsi-ctrl-6g-qcm2290 - qcom,gpucc-sdm630 From 696945e427e63ebbabad656893fb82da1ee2a980 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 24 Nov 2023 15:36:07 +0530 Subject: [PATCH 3173/7721] dt-bindings: firmware: qcom,scm: document SCM on X1E80100 SoCs Document scm compatible for X1E80100 SoCs. Signed-off-by: Sibi Sankar Reviewed-by: Guru Das Srinagesh Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231124100608.29964-5-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/firmware/qcom,scm.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 3212c8b30ed9..c1e504cf3500 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -65,6 +65,7 @@ properties: - qcom,scm-sm8550 - qcom,scm-sm8650 - qcom,scm-qcs404 + - qcom,scm-x1e80100 - const: qcom,scm clocks: @@ -191,6 +192,7 @@ allOf: - qcom,scm-sm8450 - qcom,scm-sm8550 - qcom,scm-sm8650 + - qcom,scm-x1e80100 then: properties: interconnects: false From 32c5a8b93ba543e3cc596b0272b5ed7fac82278c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 24 Nov 2023 12:17:17 -0600 Subject: [PATCH 3174/7721] arm64: dts: qcom: sm8550: add IPA information Add IPA-related nodes and definitions to "sm8550.dtsi", which uses IPA v5.5. Signed-off-by: Alex Elder Tested-by: Neil Armstrong # on SM8550-QRD Link: https://lore.kernel.org/r/20231124181718.915208-2-elder@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 05cfb50207f9..eaad6c5831c7 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -1996,6 +1996,45 @@ gpucc: clock-controller@3d90000 { #power-domain-cells = <1>; }; + ipa: ipa@3f40000 { + compatible = "qcom,sm8550-ipa"; + + iommus = <&apps_smmu 0x4a0 0x0>, + <&apps_smmu 0x4a2 0x0>; + reg = <0 0x3f40000 0 0x10000>, + <0 0x3f50000 0 0x5000>, + <0 0x3e04000 0 0xfc000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 654 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>, + <&ipa_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&ipa_smp2p_in 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ipa", + "gsi", + "ipa-clock-query", + "ipa-setup-ready"; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + clock-names = "core"; + + interconnects = <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; + interconnect-names = "memory", + "config"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + remoteproc_mpss: remoteproc@4080000 { compatible = "qcom,sm8550-mpss-pas"; reg = <0x0 0x04080000 0x0 0x4040>; From 33eae059ccaf71f6243dd919add405dfefd275e7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 24 Nov 2023 12:17:18 -0600 Subject: [PATCH 3175/7721] arm64: dts: qcom: sm8550-qrd: enable IPA Enable IPA on the SM8550 QRD. The GSI firmware on this platform is loaded by the AP. Signed-off-by: Alex Elder Tested-by: Neil Armstrong # on SM8550-QRD Link: https://lore.kernel.org/r/20231124181718.915208-3-elder@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550-qrd.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts index eef811def39b..34c760549f3e 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts @@ -585,6 +585,13 @@ fsa4480_sbu_mux: endpoint { }; }; +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/sm8550/ipa_fws.mbn"; + status = "okay"; +}; + &gcc { clocks = <&bi_tcxo_div2>, <&sleep_clk>, <&pcie0_phy>, From 25bb226508a1384723b201da8bd5c16ac57f34cd Mon Sep 17 00:00:00 2001 From: Luka Panio Date: Sat, 25 Nov 2023 23:03:14 +0100 Subject: [PATCH 3176/7721] dt-bindings: arm: qcom: Add Xiaomi Pad 6 (xiaomi-pipa) Add a compatible for Xiaomi Pad 6. Acked-by: Conor Dooley Signed-off-by: Luka Panio Link: https://lore.kernel.org/r/20231125220315.118922-1-lukapanio@gmail.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index e09745a802fd..a4393a891f30 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -1013,6 +1013,7 @@ properties: - sony,pdx203-generic - sony,pdx206-generic - xiaomi,elish + - xiaomi,pipa - const: qcom,sm8250 - items: From 264beb3cbd0dc6d78357aa382297d5c94ffb4a3e Mon Sep 17 00:00:00 2001 From: Luka Panio Date: Sat, 25 Nov 2023 23:03:15 +0100 Subject: [PATCH 3177/7721] arm64: dts: qcom: sm8250-xiaomi-pipa: Add initial device tree Initial support for Xiaomi Pad 6 tablet, that have sm8250 soc. Signed-off-by: Luka Panio Acked-by: Krzysztof Kozlowski Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125220315.118922-2-lukapanio@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/sm8250-xiaomi-pipa.dts | 623 ++++++++++++++++++ 2 files changed, 624 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 51335f08a742..f8a2ad62629b 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -223,6 +223,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx203.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx206.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-elish-boe.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-elish-csot.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-pipa.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-microsoft-surface-duo2.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-mtp.dtb diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts new file mode 100644 index 000000000000..86e1f7fd1c20 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * Copyright (c) 2023 Luka Panio + */ + +/dts-v1/; + +#include +#include +#include +#include "sm8250.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" +#include "pm8009.dtsi" + +/* + * Delete following upstream (sm8250.dtsi) reserved + * memory mappings which are different on this device. + */ +/delete-node/ &adsp_mem; +/delete-node/ &cdsp_secure_heap; +/delete-node/ &slpi_mem; +/delete-node/ &spss_mem; +/delete-node/ &xbl_aop_mem; + +/ { + + model = "Xiaomi Pad 6"; + compatible = "xiaomi,pipa", "qcom,sm8250"; + + chassis-type = "tablet"; + + /* required for bootloader to select correct board */ + qcom,msm-id = ; /* SM8250 v2.1 */ + qcom,board-id = <0x34 0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer: framebuffer@9c000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0x9c000000 0x0 0x2300000>; + width = <1800>; + height = <2880>; + stride = <(1800 * 4)>; + format = "a8r8g8b8"; + }; + }; + + battery_l: battery-l { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3870000>; + energy-full-design-microwatt-hours = <16700000>; + charge-full-design-microamp-hours = <4420000>; + }; + + battery_r: battery-r { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3870000>; + energy-full-design-microwatt-hours = <16700000>; + charge-full-design-microamp-hours = <4420000>; + }; + + bl_vddpos_5p5: bl-vddpos-regulator { + compatible = "regulator-fixed"; + regulator-name = "bl_vddpos_5p5"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + bl_vddneg_5p5: bl-vddneg-regulator { + compatible = "regulator-fixed"; + regulator-name = "bl_vddneg_5p5"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 131 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&vol_up_n>; + pinctrl-names = "default"; + + key-vol-up { + label = "Volume Up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + linux,can-disable; + wakeup-source; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + /* S6c is really ebi.lvl but it's there for supply map completeness sake. */ + vreg_s6c_0p88: smpc6-regulator { + compatible = "regulator-fixed"; + regulator-name = "vreg_s6c_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-always-on; + vin-supply = <&vph_pwr>; + }; + + reserved-memory { + xbl_aop_mem: xbl-aop@80700000 { + reg = <0x0 0x80600000 0x0 0x260000>; + no-map; + }; + + slpi_mem: slpi@88c00000 { + reg = <0x0 0x88c00000 0x0 0x2f00000>; + no-map; + }; + + adsp_mem: adsp@8bb00000 { + reg = <0x0 0x8bb00000 0x0 0x2500000>; + no-map; + }; + + spss_mem: spss@8e000000 { + reg = <0x0 0x8e000000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap: cdsp-secure-heap@8e100000 { + reg = <0x0 0x8e100000 0x0 0x4600000>; + no-map; + }; + + cont_splash_mem: cont-splash@9c000000 { + reg = <0x0 0x9c000000 0x0 0x2300000>; + no-map; + }; + + ramoops@b0000000 { + compatible = "ramoops"; + reg = <0x0 0xb0000000 0x0 0x400000>; + record-size = <0x1000>; + console-size = <0x200000>; + ecc-size = <16>; + no-map; + }; + }; +}; + +&adsp { + firmware-name = "qcom/sm8250/xiaomi/pipa/adsp.mbn"; + status = "okay"; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8150-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l8-l11-supply = <&vreg_s6c_0p88>; + vdd-l2-l10-supply = <&vreg_bob>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p95>; + vdd-l6-l9-supply = <&vreg_s8c_1p35>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_1p9>; + vdd-l13-l16-l17-supply = <&vreg_bob>; + + /* (S1+S2+S3) - cx.lvl (ARC) */ + + vreg_s4a_1p8: smps4 { + regulator-name = "vreg_s4a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_s5a_1p9: smps5 { + regulator-name = "vreg_s5a_1p9"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s6a_0p95: smps6 { + regulator-name = "vreg_s6a_0p95"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = ; + }; + + vreg_l2a_3p1: ldo2 { + regulator-name = "vreg_l2a_3p1"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p9: ldo3 { + regulator-name = "vreg_l3a_0p9"; + regulator-min-microvolt = <928000>; + regulator-max-microvolt = <932000>; + regulator-initial-mode = ; + }; + + /* L4 - lmx.lvl (ARC) */ + + vreg_l5a_0p88: ldo5 { + regulator-name = "vreg_l5a_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l6a_1p2: ldo6 { + regulator-name = "vreg_l6a_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + /* L7 is unused. */ + + vreg_l9a_1p2: ldo9 { + regulator-name = "vreg_l9a_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + /* L10 is unused, L11 - lcx.lvl (ARC) */ + + vreg_l12a_1p8: ldo12 { + regulator-name = "vreg_l12a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + /* L13 is unused. */ + + vreg_l14a_1p88: ldo14 { + regulator-name = "vreg_l14a_1p88"; + regulator-min-microvolt = <1880000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = ; + }; + + /* L15 & L16 are unused. */ + + vreg_l17a_3p0: ldo17 { + regulator-name = "vreg_l17a_3p0"; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l18a_0p9: ldo18 { + regulator-name = "vreg_l18a_0p9"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8150l-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l8-supply = <&vreg_s4a_1p8>; + vdd-l2-l3-supply = <&vreg_s8c_1p35>; + vdd-l4-l5-l6-supply = <&vreg_bob>; + vdd-l7-l11-supply = <&vreg_bob>; + vdd-l9-l10-supply = <&vreg_bob>; + vdd-bob-supply = <&vph_pwr>; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3350000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + /* + * S1-S6 are ARCs: + * (S1+S2) - gfx.lvl, + * S3 - mx.lvl, + * (S4+S5) - mmcx.lvl, + * S6 - ebi.lvl + */ + + vreg_s7c_0p35: smps7 { + regulator-name = "vreg_s7c_0p35"; + regulator-min-microvolt = <348000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + }; + + vreg_s8c_1p35: smps8 { + regulator-name = "vreg_s8c_1p35"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + /* L2-4 are unused. */ + + vreg_l5c_1p8: ldo5 { + regulator-name = "vreg_l5c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p9: ldo6 { + regulator-name = "vreg_l6c_2p9"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7c_2p85: ldo7 { + regulator-name = "vreg_l7c_2p85"; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p8: ldo8 { + regulator-name = "vreg_l8c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p9: ldo9 { + regulator-name = "vreg_l9c_2p9"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l10c_3p3: ldo10 { + regulator-name = "vreg_l10c_3p3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p0: ldo11 { + regulator-name = "vreg_l11c_3p0"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8009-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vreg_bob>; + vdd-l2-supply = <&vreg_s8c_1p35>; + vdd-l5-l6-supply = <&vreg_bob>; + vdd-l7-supply = <&vreg_s4a_1p8>; + + vreg_s1f_1p2: smps1 { + regulator-name = "vreg_s1f_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_s2f_0p5: smps2 { + regulator-name = "vreg_s2f_0p5"; + regulator-min-microvolt = <512000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + /* L1 is unused. */ + + vreg_l2f_1p3: ldo2 { + regulator-name = "vreg_l2f_1p3"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + /* L3 & L4 are unused. */ + + vreg_l5f_2p8: ldo5 { + regulator-name = "vreg_l5f_2p85"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6f_2p8: ldo6 { + regulator-name = "vreg_l6f_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l7f_1p8: ldo7 { + regulator-name = "vreg_l7f_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; +}; + +&cdsp { + firmware-name = "qcom/sm8250/xiaomi/pipa/cdsp.mbn"; + status = "okay"; +}; + +&gmu { + status = "okay"; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&gpi_dma2 { + status = "okay"; +}; + +&gpu { + status = "okay"; + + zap-shader { + memory-region = <&gpu_mem>; + firmware-name = "qcom/sm8250/xiaomi/pipa/a650_zap.mbn"; + }; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + fuel-gauge@55 { + compatible = "ti,bq27z561"; + reg = <0x55>; + monitored-battery = <&battery_r>; + }; +}; + +&i2c11 { + clock-frequency = <400000>; + status = "okay"; + + backlight: backlight@11 { + compatible = "kinetic,ktz8866"; + reg = <0x11>; + vddpos-supply = <&bl_vddpos_5p5>; + vddneg-supply = <&bl_vddneg_5p5>; + enable-gpios = <&tlmm 139 GPIO_ACTIVE_HIGH>; + current-num-sinks = <5>; + kinetic,current-ramp-delay-ms = <128>; + kinetic,led-enable-ramp-delay-ms = <1>; + kinetic,enable-lcd-bias; + }; +}; + +&i2c13 { + clock-frequency = <400000>; + status = "okay"; + + fuel-gauge@55 { + compatible = "ti,bq27z561"; + reg = <0x55>; + monitored-battery = <&battery_l>; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; + status = "okay"; +}; + +&pm8150_gpios { + vol_up_n: vol-up-n-state { + pins = "gpio6"; + function = "normal"; + power-source = <1>; + input-enable; + bias-pull-up; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + status = "okay"; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&qupv3_id_2 { + status = "okay"; +}; + +&slpi { + firmware-name = "qcom/sm8250/xiaomi/pipa/slpi.mbn"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l5a_0p88>; + vdda18-supply = <&vreg_l12a_1p8>; + vdda33-supply = <&vreg_l2a_3p1>; + status = "okay"; +}; + +&usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l9a_1p2>; + vdda-pll-supply = <&vreg_l18a_0p9>; +}; + +&ufs_mem_hc { + vcc-supply = <&vreg_l17a_3p0>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l6a_1p2>; + vccq-max-microamp = <800000>; + vccq2-supply = <&vreg_s4a_1p8>; + vccq2-max-microamp = <800000>; + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; + status = "okay"; +}; + +&venus { + firmware-name = "qcom/sm8250/xiaomi/pipa/venus.mbn"; + status = "okay"; +}; From 56fdc35ef067c8dffee22038dd3a84bb3fa6d2a4 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 29 Nov 2023 15:44:01 +0100 Subject: [PATCH 3178/7721] dt-bindings: firmware: qcom,scm: Allow interconnect for everyone Every Qualcomm SoC physically has a "CRYPTO0<->DDR" interconnect lane. Allow this property to be present, no matter the SoC. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231125-topic-rb1_feat-v3-4-4cbb567743bb@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/firmware/qcom,scm.yaml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index c1e504cf3500..47d3d2d52acd 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -180,23 +180,6 @@ allOf: minItems: 3 maxItems: 3 - # Interconnects - - if: - not: - properties: - compatible: - contains: - enum: - - qcom,scm-qdu1000 - - qcom,scm-sc8280xp - - qcom,scm-sm8450 - - qcom,scm-sm8550 - - qcom,scm-sm8650 - - qcom,scm-x1e80100 - then: - properties: - interconnects: false - # Interrupts - if: not: From 3310288f61357b9b54139c93fc7665d60c0288bf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 13 Nov 2023 09:51:41 +0100 Subject: [PATCH 3179/7721] of/platform: Disable sysfb if a simple-framebuffer node is found Some DT platforms use EFI to boot and in this case the EFI Boot Services may register a EFI_GRAPHICS_OUTPUT_PROTOCOL handle, that will later be queried by the Linux EFI stub to fill the global struct screen_info data. The data is used by the Generic System Framebuffers (sysfb) framework to add a platform device with platform data about the system framebuffer. But if there is a "simple-framebuffer" node in the DT, the OF core will also do the same and add another device for the system framebuffer. This could lead for example, to two platform devices ("simple-framebuffer" and "efi-framebuffer") to be added and matched with their corresponding drivers. So both efifb and simpledrm will be probed, leading to following: [ 0.055752] efifb: framebuffer at 0xbd58dc000, using 16000k, total 16000k [ 0.055755] efifb: mode is 2560x1600x32, linelength=10240, pages=1 [ 0.055758] efifb: scrolling: redraw [ 0.055759] efifb: Truecolor: size=2:10:10:10, shift=30:20:10:0 ... [ 3.295896] simple-framebuffer bd58dc000.framebuffer: [drm] *ERROR* could not acquire memory range [??? 0xffff79f30a29ee40-0x2a5000001a7 flags 0x0]: -16 [ 3.298018] simple-framebuffer: probe of bd58dc000.framebuffer failed with error -16 To prevent the issue, make the OF core to disable sysfb if there is a node with a "simple-framebuffer" compatible. That way only this device will be registered and sysfb would not attempt to register another one using the screen_info data even if this has been filled. This seems the correct thing to do in this case because: a) On a DT platform, the DTB is the single source of truth since is what describes the hardware topology. Even if EFI Boot Services are used to boot the machine. b) The of_platform_default_populate_init() function is called in the arch_initcall_sync() initcall level while the sysfb_init() function is called later in the subsys_initcall() initcall level. Reported-by: Andrew Worsley Closes: https://lore.kernel.org/all/20231111042926.52990-2-amworsley@gmail.com Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20231113085305.1823455-1-javierm@redhat.com Signed-off-by: Rob Herring --- drivers/of/platform.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 2293059758d1..af0e1fb2ab68 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "of_private.h" @@ -621,8 +622,21 @@ static int __init of_platform_default_populate_init(void) } node = of_get_compatible_child(of_chosen, "simple-framebuffer"); - of_platform_device_create(node, NULL, NULL); - of_node_put(node); + if (node) { + /* + * Since a "simple-framebuffer" device is already added + * here, disable the Generic System Framebuffers (sysfb) + * to prevent it from registering another device for the + * system framebuffer later (e.g: using the screen_info + * data that may had been filled as well). + * + * This can happen for example on DT systems that do EFI + * booting and may provide a GOP handle to the EFI stub. + */ + sysfb_disable(); + of_platform_device_create(node, NULL, NULL); + of_node_put(node); + } /* Populate everything else. */ of_platform_default_populate(NULL, NULL, NULL); From 14cdeaf9504cd37589e8acfedf644d32fb29a429 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 25 Aug 2023 01:08:37 +0800 Subject: [PATCH 3180/7721] wifi: mt76: add ability to explicitly forbid LED registration with DT Add ability to explicitly forbid LED registration using DT led\status = "disabled". Tested-by: Alexey D. Filimonov Signed-off-by: Alexey D. Filimonov Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 51a767121b0d..81746d4cd4c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -197,10 +197,33 @@ static int mt76_led_init(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; struct ieee80211_hw *hw = phy->hw; + struct device_node *np = dev->dev->of_node; if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return 0; + np = of_get_child_by_name(np, "led"); + if (np) { + if (!of_device_is_available(np)) { + of_node_put(np); + dev_info(dev->dev, + "led registration was explicitly disabled by dts\n"); + return 0; + } + + if (phy == &dev->phy) { + int led_pin; + + if (!of_property_read_u32(np, "led-sources", &led_pin)) + phy->leds.pin = led_pin; + + phy->leds.al = + of_property_read_bool(np, "led-active-low"); + } + + of_node_put(np); + } + snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", wiphy_name(hw->wiphy)); @@ -211,20 +234,8 @@ static int mt76_led_init(struct mt76_phy *phy) mt76_tpt_blink, ARRAY_SIZE(mt76_tpt_blink)); - if (phy == &dev->phy) { - struct device_node *np = dev->dev->of_node; - - np = of_get_child_by_name(np, "led"); - if (np) { - int led_pin; - - if (!of_property_read_u32(np, "led-sources", &led_pin)) - phy->leds.pin = led_pin; - phy->leds.al = of_property_read_bool(np, - "led-active-low"); - of_node_put(np); - } - } + dev_info(dev->dev, + "registering led '%s'\n", phy->leds.name); return led_classdev_register(dev->dev, &phy->leds.cdev); } From ce18572b7b5933ae3f97ea201d03463c320f0956 Mon Sep 17 00:00:00 2001 From: Rong Yan Date: Sun, 1 Oct 2023 23:02:05 +0800 Subject: [PATCH 3181/7721] wifi: mt76: mt7921: support 5.9/6GHz channel config in acpi The mtcl table, configured by platform vendor, provides regulatory information for 5.9/6 GHz channels. mt792x should work on corresponding channels supported by mtcl. This patch would parse the settings in mtcl table and apply the result into chip side. Signed-off-by: Rong Yan Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 4 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 6 +++ .../wireless/mediatek/mt76/mt792x_acpi_sar.c | 53 +++++++++++++++++++ .../wireless/mediatek/mt76/mt792x_acpi_sar.h | 2 + 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 63f3d4a5c9aa..94fc3eb40234 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1260,12 +1260,14 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u8 alpha2[2]; u8 type[2]; u8 env_6g; - u8 rsvd[63]; + u8 mtcl_conf; + u8 rsvd[62]; } __packed req = { .idx = idx, .env = env_cap, .env_6g = dev->phy.power_type, .acpi_conf = mt792x_acpi_get_flags(&dev->phy), + .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; u8 i, *pos; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 36fae736dd19..3c897b34aaa7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -382,6 +382,7 @@ int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev); int mt792x_init_acpi_sar(struct mt792x_dev *dev); int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); u8 mt792x_acpi_get_flags(struct mt792x_phy *phy); +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2); #else static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev) { @@ -398,6 +399,11 @@ static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) { return 0; } + +static inline u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + return 0xf; +} #endif #endif /* __MT7925_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index 303c0f5c9c66..e7afea87e82e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -348,3 +348,56 @@ u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) return flags; } EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags); + +static u8 +mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) +{ + u8 config = 0; + + if (cl->cl6g[row] & BIT(column)) + config |= (cl->mode_6g & 0x3) << 2; + if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) + config |= (cl->mode_5g9 & 0x3); + + return config; +} + +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + static const char * const cc_list_all[] = { + "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR", + "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME", + "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR", + "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY", + }; + static const char * const cc_list_eu[] = { + "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", + "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", + "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", + "PT", "RO", "MT", "SK", "SI", "ES", "CH", + }; + struct mt792x_acpi_sar *sar = phy->acpisar; + struct mt792x_asar_cl *cl; + int col, row, i; + + if (!sar) + return 0xf; + + cl = sar->countrylist; + if (!cl) + return 0xc; + + for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) { + col = 7 - i % 8; + row = i / 8; + if (!memcmp(cc_list_all[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(row, col, cl); + } + + for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) + if (!memcmp(cc_list_eu[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(0, 6, cl); + + return mt792x_acpi_get_mtcl_map(0, 7, cl); +} +EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h index d6d332e863ba..2298983b6342 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h @@ -77,6 +77,8 @@ struct mt792x_asar_cl { u8 version; u8 mode_6g; u8 cl6g[6]; + u8 mode_5g9; + u8 cl5g9[6]; } __packed; struct mt792x_asar_fg { From 706e83b33103fc5dc945765ddbf6a3e879d21275 Mon Sep 17 00:00:00 2001 From: Yi-Chia Hsieh Date: Thu, 12 Oct 2023 15:00:26 -0700 Subject: [PATCH 3182/7721] wifi: mt76: mt7996: fix uninitialized variable in parsing txfree Fix the uninitialized variable warning in mt7996_mac_tx_free. Fixes: 2461599f835e ("wifi: mt76: mt7996: get tx_retries and tx_failed from txfree") Signed-off-by: Yi-Chia Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 04540833485f..59ab07b89087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1074,7 +1074,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; - struct mt76_wcid *wcid; + struct mt76_wcid *wcid = NULL; LIST_HEAD(free_list); struct sk_buff *skb, *tmp; void *end = data + len; From e874a79250b39447765ac13272b67ac36ccf2a75 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:37 +0200 Subject: [PATCH 3183/7721] wifi: mt76: fix broken precal loading from MTD for mt7915 Commit 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") was fundamentally broken and never worked. The idea (before NVMEM support) was to expand the MTD function and pass an additional offset. For normal EEPROM load the offset would always be 0. For the purpose of precal loading, an offset was passed that was internally the size of EEPROM, since precal data is right after the EEPROM. Problem is that the offset value passed is never handled and is actually overwrite by offset = be32_to_cpup(list); ret = mtd_read(mtd, offset, len, &retlen, eep); resulting in the passed offset value always ingnored. (and even passing garbage data as precal as the start of the EEPROM is getting read) Fix this by adding to the current offset value, the offset from DT to correctly read the piece of data at the requested location. Cc: stable@vger.kernel.org Fixes: 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 7725dd6763ef..7936ac8aa9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -67,7 +67,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs goto out_put_node; } - offset = be32_to_cpup(list); + offset += be32_to_cpup(list); ret = mtd_read(mtd, offset, len, &retlen, eep); put_mtd_device(mtd); if (mtd_is_bitflip(ret)) From c33e5f4cbb9f961e66473a9ace077c4d1f29a5bb Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:38 +0200 Subject: [PATCH 3184/7721] wifi: mt76: fix typo in mt76_get_of_eeprom_from_nvmem function Fix typo in mt76_get_of_eeprom_from_nvmem where eeprom was misspelled as epprom. Fixes: 5bef3a406c6e ("wifi: mt76: add support for providing eeprom in nvmem cells") Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 7936ac8aa9c0..50820fe00b8b 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -106,7 +106,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs #endif } -static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; @@ -153,7 +153,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - return mt76_get_of_epprom_from_nvmem(dev, eep, len); + return mt76_get_of_eeprom_from_nvmem(dev, eep, len); } EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); From a6342c31ab3b2cfae92298ff91635e8b82fed792 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:39 +0200 Subject: [PATCH 3185/7721] wifi: mt76: limit support of precal loading for mt7915 to MTD only Limit support for precal loading for mt7915 only to MTD. Passing data from DT doesn't support offset and NVMEM require a different cell name and doesn't support offset hence only MTD way is actually supported. Rename mt76_get_of_eeprom_from_mtd to mt76_get_of_data_from_mtd as it is now used for a more generic purpose and export it. Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 50820fe00b8b..d924338e1a3e 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -28,7 +28,7 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) return 0; } -static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) { #ifdef CONFIG_MTD struct device_node *np = dev->dev->of_node; @@ -105,6 +105,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs return -ENOENT; #endif } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) { @@ -149,7 +150,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, offset, len); if (!ret) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ea828ba0b83a..82a2b293a0fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1102,6 +1102,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); struct mt76_queue * diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 76be7308460b..5228f710b3da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -25,7 +25,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_eeprom(mdev, dev->cal, offs, val); + return mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); } static int mt7915_check_eeprom(struct mt7915_dev *dev) From 3d96764e6a22296392866e9fc6318ae912151380 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:40 +0200 Subject: [PATCH 3186/7721] wifi: mt76: make mt76_get_of_eeprom static again Since mt76_get_of_eeprom is not used by mt7915 anymore, unexport it and make it static again. Also drop offset arg as it's only supported for MTD and was always set to 0, hardcode the MTD functio instead. Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 7 +++---- drivers/net/wireless/mediatek/mt76/mt76.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index d924338e1a3e..e193ca8629f8 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -138,7 +138,7 @@ static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int le return ret; } -int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) +static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; int ret; @@ -150,13 +150,12 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - ret = mt76_get_of_data_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, 0, len); if (!ret) return 0; return mt76_get_of_eeprom_from_nvmem(dev, eep, len); } -EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); void mt76_eeprom_override(struct mt76_phy *phy) @@ -413,6 +412,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len) if (!dev->eeprom.data) return -ENOMEM; - return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len); + return !mt76_get_of_eeprom(dev, dev->eeprom.data, len); } EXPORT_SYMBOL_GPL(mt76_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 82a2b293a0fe..89250801c079 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1103,7 +1103,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, From a1f57685fe851677d62d3551aa2de674c25120cf Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:41 +0200 Subject: [PATCH 3187/7721] wifi: mt76: permit to use alternative cell name to eeprom NVMEM load Generilize mt76_get_of_eeprom_from_nvmem to use alternative cell name by passing the cell name as an arg and expose it. Rename it to mt76_get_of_data_from_nvmem to better reflect the now more generic usage. This is to permit driver to load additional cell, like precal cell. Tested-by: Shiji Yang Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index e193ca8629f8..59586fa134e3 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -107,7 +107,8 @@ int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int l } EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); -static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len) { struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; @@ -115,7 +116,7 @@ static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int le size_t retlen; int ret = 0; - cell = of_nvmem_cell_get(np, "eeprom"); + cell = of_nvmem_cell_get(np, cell_name); if (IS_ERR(cell)) return PTR_ERR(cell); @@ -137,6 +138,7 @@ static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int le return ret; } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem); static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { @@ -154,7 +156,7 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) if (!ret) return 0; - return mt76_get_of_eeprom_from_nvmem(dev, eep, len); + return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len); } void diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 89250801c079..f7979fba2fd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1103,6 +1103,8 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, From fdddaa52641e222ef6149d2faa7c10afe02f647e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:42 +0200 Subject: [PATCH 3188/7721] wifi: mt76: permit to load precal from NVMEM cell for mt7915 Permit to load precal from NVMEM cell for mt7915. The NVMEM cell must be named "precal" to be correctly loaded. NVMEM cell must already account the correct offset and be placed after the EEPROM as the function expect the data right from the start. Tested-by: Shiji Yang Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 5228f710b3da..3bb2643d1b26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -11,6 +11,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) u8 *eeprom = mdev->eeprom.data; u32 val = eeprom[MT_EE_DO_PRE_CAL]; u32 offs; + int ret; if (!dev->flash_mode) return 0; @@ -25,7 +26,11 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); + ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); + if (!ret) + return ret; + + return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", val); } static int mt7915_check_eeprom(struct mt7915_dev *dev) From 2fac91f2a1db221b070ea0fda1e2392c92386975 Mon Sep 17 00:00:00 2001 From: Wu Yunchuan Date: Fri, 20 Oct 2023 17:34:32 +0800 Subject: [PATCH 3189/7721] wifi: mt76: Remove unnecessary (void*) conversions No need cast (void *) to (struct mt7615_phy *). Signed-off-by: Wu Yunchuan Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 955974a82180..ae34d019e588 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -453,7 +453,7 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) else mphy = &dev->mt76.phy; - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); @@ -481,7 +481,7 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) ieee80211_ready_on_channel(mphy->hw); - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; phy->roc_grant = true; wake_up(&phy->roc_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2222fb9aa103..f12008244db3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1247,7 +1247,7 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) void mt7915_update_channel(struct mt76_phy *mphy) { - struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; + struct mt7915_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b22f06d4411a..c67c4f6ca2aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -269,7 +269,7 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; - phy = (struct mt7915_phy *)mphy->priv; + phy = mphy->priv; phy->throttle_state = t->ctrl.duty.duty_cycle; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 94fc3eb40234..a9056b55b0a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -160,7 +160,7 @@ static void mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 9c0e397537ac..c5fd7116929b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -345,7 +345,7 @@ static void mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 5d1f8229fdc1..eb29434abee1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -223,7 +223,7 @@ static void mt792x_phy_update_channel(struct mt76_phy *mphy, int idx) { struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; struct mt76_channel_state *state; u64 busy_time, tx_time, rx_time, obss_time; int nf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 59ab07b89087..53a78d971326 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1525,7 +1525,7 @@ mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx) void mt7996_update_channel(struct mt76_phy *mphy) { - struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv; + struct mt7996_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; From b92158a8dc413d0facaf0d807c66f76a6865c93c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:48 +0200 Subject: [PATCH 3190/7721] wifi: mt76: mmio: move mt76_mmio_wed_{init,release}_rx_buf in common code Move mt76_mmio_wed_init_rx_buf and mt76_mmio_wed_release_rx_buf routines in common code. This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 75 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++ .../net/wireless/mediatek/mt76/mt7915/mmio.c | 78 +------------------ 3 files changed, 82 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 86e3d2ac4d0d..350650a0fce2 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -4,6 +4,7 @@ */ #include "mt76.h" +#include "dma.h" #include "trace.h" static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) @@ -84,6 +85,80 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + int i; + + for (i = 0; i < dev->rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(dev, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->ptr = NULL; + + mt76_put_rxwi(dev, t); + } + + mt76_free_pending_rxwi(dev); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf); + +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + int i, len = SKB_WITH_OVERHEAD(q->buf_size); + struct mt76_txwi_cache *t = NULL; + + for (i = 0; i < size; i++) { + enum dma_data_direction dir; + dma_addr_t addr; + u32 offset; + int token; + void *buf; + + t = mt76_get_rxwi(dev); + if (!t) + goto unmap; + + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!buf) + goto unmap; + + addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; + dir = page_pool_get_dma_dir(q->page_pool); + dma_sync_single_for_device(dev->dma_dev, addr, len, dir); + + desc->buf0 = cpu_to_le32(addr); + token = mt76_rx_token_consume(dev, buf, t, addr); + if (token < 0) { + mt76_put_page_pool_buf(buf, false); + goto unmap; + } + + desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, + token)); + desc++; + } + + return 0; + +unmap: + if (t) + mt76_put_rxwi(dev, t); + mt76_mmio_wed_release_rx_buf(wed); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f7979fba2fd7..5dd6b99afeca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1057,6 +1057,11 @@ static inline u16 mt76_rev(struct mt76_dev *dev) return dev->rev & 0xffff; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index e7d8e03f826f..1621a8150798 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -567,80 +567,6 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) spin_unlock_bh(&dev->mt76.token_lock); } -static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - int i; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - for (i = 0; i < dev->mt76.rx_token_size; i++) { - struct mt76_txwi_cache *t; - - t = mt76_rx_token_release(&dev->mt76, i); - if (!t || !t->ptr) - continue; - - mt76_put_page_pool_buf(t->ptr, false); - t->ptr = NULL; - - mt76_put_rxwi(&dev->mt76, t); - } - - mt76_free_pending_rxwi(&dev->mt76); -} - -static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) -{ - struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; - struct mt76_txwi_cache *t = NULL; - struct mt7915_dev *dev; - struct mt76_queue *q; - int i, len; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - len = SKB_WITH_OVERHEAD(q->buf_size); - - for (i = 0; i < size; i++) { - enum dma_data_direction dir; - dma_addr_t addr; - u32 offset; - int token; - void *buf; - - t = mt76_get_rxwi(&dev->mt76); - if (!t) - goto unmap; - - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); - if (!buf) - goto unmap; - - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir); - - desc->buf0 = cpu_to_le32(addr); - token = mt76_rx_token_consume(&dev->mt76, buf, t, addr); - if (token < 0) { - mt76_put_page_pool_buf(buf, false); - goto unmap; - } - - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, - token)); - desc++; - } - - return 0; - -unmap: - if (t) - mt76_put_rxwi(&dev->mt76, t); - mt7915_mmio_wed_release_rx_buf(wed); - return -ENOMEM; -} - static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { @@ -780,8 +706,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.init_buf = mt7915_wed_init_buf; wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; - wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; From 5f60735c08ce3dd368d30bb3b1addf7149cb664c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:49 +0200 Subject: [PATCH 3191/7721] wifi: mt76: move mt76_mmio_wed_offload_{enable,disable} in common code mt76_mmio_wed_offload_enable and mt76_mmio_wed_offload_disable routines will be reused by mt7996 driver for wed support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 22 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../net/wireless/mediatek/mt76/mt7915/mmio.c | 29 ++----------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 350650a0fce2..c34624978a14 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -157,6 +157,28 @@ u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) return -ENOMEM; } EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); + +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->token_lock); + + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable); + +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = dev->drv->token_size; + spin_unlock_bh(&dev->token_lock); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5dd6b99afeca..a1809a6ea8da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1060,6 +1060,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #ifdef CONFIG_NET_MEDIATEK_SOC_WED u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 1621a8150798..85cb3fed9505 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -542,31 +542,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) } #ifdef CONFIG_NET_MEDIATEK_SOC_WED -static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->mt76.token_lock); - - return !wait_event_timeout(dev->mt76.tx_wait, - !dev->mt76.wed_token_count, HZ); -} - -static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = MT7915_TOKEN_SIZE; - spin_unlock_bh(&dev->mt76.token_lock); -} - static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { @@ -704,8 +679,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, } wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; From ac4659856c22440e2ad208928a3c5911ac364a54 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:50 +0200 Subject: [PATCH 3192/7721] wifi: mt76: move mt76_net_setup_tc in common code This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 16 +--------------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 81746d4cd4c8..b0dbea964c29 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1853,3 +1853,19 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) return MT_DFS_STATE_ACTIVE; } EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + struct mtk_wed_device *wed = &phy->dev->mmio.wed; + + if (!mtk_wed_device_active(wed)) + return -EOPNOTSUPP; + + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); +} +EXPORT_SYMBOL_GPL(mt76_net_setup_tc); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a1809a6ea8da..9035db4129a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1047,6 +1047,12 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + static inline u16 mt76_chip(struct mt76_dev *dev) { return dev->rev >> 16; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index a3fd54cc1911..ba34c8e19aab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1653,20 +1653,6 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, return 0; } - -static int -mt7915_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct net_device *netdev, enum tc_setup_type type, - void *type_data) -{ - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - - if (!mtk_wed_device_active(wed)) - return -EOPNOTSUPP; - - return mtk_wed_device_setup_tc(wed, netdev, type, type_data); -} #endif const struct ieee80211_ops mt7915_ops = { @@ -1721,6 +1707,6 @@ const struct ieee80211_ops mt7915_ops = { .set_radar_background = mt7915_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7915_net_fill_forward_path, - .net_setup_tc = mt7915_net_setup_tc, + .net_setup_tc = mt76_net_setup_tc, #endif }; From 132d74d31e86130b4e8b8c5d7bfe05c227d989d6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:51 +0200 Subject: [PATCH 3193/7721] wifi: mt76: introduce mt76_queue_is_wed_tx_free utility routine This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 511fe7e6e744..d9e11817a563 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -724,7 +724,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - if (q->flags != MT_WED_Q_TXFREE) + if (!mt76_queue_is_wed_tx_free(q)) mt76_dma_queue_reset(dev, q); return 0; @@ -775,7 +775,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) /* reset WED rx queues */ mt76_dma_wed_setup(dev, q, true); - if (q->flags != MT_WED_Q_TXFREE) { + if (!mt76_queue_is_wed_tx_free(q)) { mt76_dma_sync_idx(dev, q); mt76_dma_rx_fill(dev, q, false); } @@ -818,7 +818,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) bool more; if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && - q->flags == MT_WED_Q_TXFREE) { + mt76_queue_is_wed_tx_free(q)) { dma_idx = Q_READ(dev, q, dma_idx); check_ddone = true; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 9035db4129a9..e32d9c7089f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1562,6 +1562,12 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct mt76_power_limits *dest, s8 target_power); +static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) +{ + return (q->flags & MT_QFLAG_WED) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; +} + static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) { return (q->flags & MT_QFLAG_WED) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 59a44d79aaed..96b2c3802ac1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -643,7 +643,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { - if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE) + if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) continue; mt76_queue_reset(dev, &dev->mt76.q_rx[i]); From 2e420b88ca86e3322b36793f12d8fd2bff5ed57d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:52 +0200 Subject: [PATCH 3194/7721] wifi: mt76: introduce wed pointer in mt76_queue Introduce mtk_wed_device pointer in mt76_queue structure in order to configure WED chip. Get rid of dev parameter in Q_READ and Q_WRITE macros. Introduce wed parameter to the following routine signatures: - mt76_init_queue - mt76_init_tx_queue This is a preliminary patch to introduce WED support for mt7996 since mt7996 runs two separate WED chips. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 49 ++++++++++--------- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76.h | 10 ++-- .../net/wireless/mediatek/mt76/mt7603/dma.c | 9 ++-- .../net/wireless/mediatek/mt76/mt7615/dma.c | 6 +-- .../net/wireless/mediatek/mt76/mt76_connac.h | 3 +- .../wireless/mediatek/mt76/mt76_connac_mac.c | 5 +- .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +- .../net/wireless/mediatek/mt76/mt7915/dma.c | 16 ++++-- .../net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7925/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/dma.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/init.c | 3 +- 13 files changed, 65 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index d9e11817a563..3453b4c7b0e1 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -9,11 +9,11 @@ #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) -#define Q_READ(_dev, _q, _field) ({ \ +#define Q_READ(_q, _field) ({ \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ u32 _val; \ if ((_q)->flags & MT_QFLAG_WED) \ - _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \ + _val = mtk_wed_device_reg_read((_q)->wed, \ ((_q)->wed_regs + \ _offset)); \ else \ @@ -21,10 +21,10 @@ _val; \ }) -#define Q_WRITE(_dev, _q, _field, _val) do { \ +#define Q_WRITE(_q, _field, _val) do { \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ if ((_q)->flags & MT_QFLAG_WED) \ - mtk_wed_device_reg_write(&(_dev)->mmio.wed, \ + mtk_wed_device_reg_write((_q)->wed, \ ((_q)->wed_regs + _offset), \ _val); \ else \ @@ -33,8 +33,8 @@ #else -#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field) -#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field) +#define Q_READ(_q, _field) readl(&(_q)->regs->_field) +#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) #endif @@ -188,9 +188,9 @@ EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { - Q_WRITE(dev, q, desc_base, q->desc_dma); - Q_WRITE(dev, q, ring_size, q->ndesc); - q->head = Q_READ(dev, q, dma_idx); + Q_WRITE(q, desc_base, q->desc_dma); + Q_WRITE(q, ring_size, q->ndesc); + q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -206,8 +206,8 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) for (i = 0; i < q->ndesc; i++) q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); - Q_WRITE(dev, q, cpu_idx, 0); - Q_WRITE(dev, q, dma_idx, 0); + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); mt76_dma_sync_idx(dev, q); } @@ -343,7 +343,7 @@ static void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) { wmb(); - Q_WRITE(dev, q, cpu_idx, q->head); + Q_WRITE(q, cpu_idx, q->head); } static void @@ -359,7 +359,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) if (flush) last = -1; else - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); @@ -371,7 +371,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) } if (!flush && q->tail == last) - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); } spin_unlock_bh(&q->cleanup_lock); @@ -641,7 +641,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED - struct mtk_wed_device *wed = &dev->mmio.wed; int ret, type, ring; u8 flags; @@ -649,7 +648,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) return -EINVAL; flags = q->flags; - if (!mtk_wed_device_active(wed)) + if (!q->wed || !mtk_wed_device_active(q->wed)) q->flags &= ~MT_QFLAG_WED; if (!(q->flags & MT_QFLAG_WED)) @@ -660,9 +659,10 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) switch (type) { case MT76_WED_Q_TX: - ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->tx_ring[ring].reg_base; + q->wed_regs = q->wed->tx_ring[ring].reg_base; break; case MT76_WED_Q_TXFREE: /* WED txfree queue needs ring to be initialized before setup */ @@ -671,14 +671,15 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) mt76_dma_rx_fill(dev, q, false); q->flags = flags; - ret = mtk_wed_device_txfree_ring_setup(wed, q->regs); + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); if (!ret) - q->wed_regs = wed->txfree_ring.reg_base; + q->wed_regs = q->wed->txfree_ring.reg_base; break; case MT76_WED_Q_RX: - ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->rx_ring[ring].reg_base; + q->wed_regs = q->wed->rx_ring[ring].reg_base; break; default: ret = -EINVAL; @@ -819,7 +820,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && mt76_queue_is_wed_tx_free(q)) { - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); check_ddone = true; } @@ -829,7 +830,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (check_ddone) { if (q->tail == dma_idx) - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); if (q->tail == dma_idx) break; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index b0dbea964c29..d4004a62af1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1736,7 +1736,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { struct mt76_queue *hwq; int err; @@ -1746,6 +1746,7 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, return ERR_PTR(-ENOMEM); hwq->flags = flags; + hwq->wed = wed; err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); if (err < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e32d9c7089f7..afcc98dd128f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -199,6 +199,7 @@ struct mt76_queue { u8 hw_idx; u8 flags; + struct mtk_wed_device *wed; u32 wed_regs; dma_addr_t desc_dma; @@ -1121,15 +1122,16 @@ int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); u16 mt76_calculate_default_rate(struct mt76_phy *phy, struct ieee80211_vif *vif, int rateidx); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, - int n_desc, int ring_base, u32 flags) + int n_desc, int ring_base, void *wed, + u32 flags) { struct mt76_queue *q; - q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags); + q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags); if (IS_ERR(q)) return PTR_ERR(q); @@ -1143,7 +1145,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, { struct mt76_queue *q; - q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0); + q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0); if (IS_ERR(q)) return PTR_ERR(q); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 03ba11a61c90..7a2f5d38562b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -173,13 +173,14 @@ int mt7603_dma_init(struct mt7603_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], - MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_TX_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -189,12 +190,12 @@ int mt7603_dma_init(struct mt7603_dev *dev) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 0ce01ccc5dce..e7135b2f1742 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], MT7615_TX_RING_SIZE / 2, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) return mt7622_init_tx_queues_multi(dev); ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 1f29d8cd900c..e5ebde19af8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -391,7 +391,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); + void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 93402d2c2538..c7914643e9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -256,11 +256,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { int i, err; - err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, + wed, flags); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 9b5e3fb7b0df..e5ad635d3c56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -199,13 +199,14 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) for (i = 0; i < IEEE80211_NUM_ACS; i++) { ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), MT76x02_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 96b2c3802ac1..1bceeb5227b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -9,18 +9,20 @@ static int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) { struct mt7915_dev *dev = phy->dev; + struct mtk_wed_device *wed = NULL; - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { if (is_mt798x(&dev->mt76)) ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; else ring_base = MT_WED_TX_RING_BASE; idx -= MT_TXQ_ID(0); + wed = &dev->mt76.mmio.wed; } return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, - MT_WED_Q_TX(idx)); + wed, MT_WED_Q_TX(idx)); } static int mt7915_poll_tx(struct napi_struct *napi, int budget) @@ -492,7 +494,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; - dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed; } else { wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA); wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA); @@ -507,9 +510,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (!dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_MAIN].flags = + mdev->q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(MT7915_RXQ_BAND0); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed; } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], @@ -528,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed)) { mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed; if (is_mt7916(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; @@ -544,9 +549,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (dev->dbdc_support || dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_BAND1].flags = + mdev->q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(MT7915_RXQ_BAND1); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed; } /* rx data queue for band1 */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index f04e7095e181..6f83c4c5fce2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -171,7 +171,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 08ef75e24e1c..734f31ee40d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -218,7 +218,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0, MT7925_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 586e247a1e06..b33346360075 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -268,7 +268,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT_TXQ_ID(dev->mphy.band_idx), MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), 0); + MT_TXQ_RING_BASE(0), NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 55cb1770fa34..b09ae6cc6eb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -405,7 +405,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, ret = mt76_connac_init_tx_queues(phy->mt76, MT_TXQ_ID(band), MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, 0); + MT_TXQ_RING_BASE(band) + hif1_ofs, + NULL, 0); if (ret) goto error; From af8d2af57584762ef2727831ffca01036ca5bd40 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:53 +0200 Subject: [PATCH 3195/7721] wifi: mt76: increase MT_QFLAG_WED_TYPE size This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index afcc98dd128f..3fc38f00d0a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -29,8 +29,8 @@ #define MT76_TOKEN_FREE_THR 64 #define MT_QFLAG_WED_RING GENMASK(1, 0) -#define MT_QFLAG_WED_TYPE GENMASK(3, 2) -#define MT_QFLAG_WED BIT(4) +#define MT_QFLAG_WED_TYPE GENMASK(4, 2) +#define MT_QFLAG_WED BIT(5) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ From 83eafc9251d6d30574b629ac637c56d168fcbdd9 Mon Sep 17 00:00:00 2001 From: Sujuan Chen Date: Fri, 20 Oct 2023 12:30:54 +0200 Subject: [PATCH 3196/7721] wifi: mt76: mt7996: add wed tx support Similar to MT7915, enable Wireless Ethernet Ditpatcher for MT7996 to offload traffic received from the LAN nic and transmitted on the WLAN one Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sujuan Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 9 +- drivers/net/wireless/mediatek/mt76/mt76.h | 11 ++ .../net/wireless/mediatek/mt76/mt7996/dma.c | 76 ++++++-- .../net/wireless/mediatek/mt76/mt7996/init.c | 30 +++- .../net/wireless/mediatek/mt76/mt7996/mac.c | 31 +++- .../net/wireless/mediatek/mt76/mt7996/main.c | 42 +++++ .../net/wireless/mediatek/mt76/mt7996/mmio.c | 170 ++++++++++++++++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 12 +- .../net/wireless/mediatek/mt76/mt7996/pci.c | 63 ++++--- .../net/wireless/mediatek/mt76/mt7996/regs.h | 5 + 10 files changed, 383 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 3453b4c7b0e1..a7a045488cb2 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -988,10 +988,13 @@ void mt76_dma_cleanup(struct mt76_dev *dev) page_pool_destroy(q->page_pool); } - mt76_free_pending_txwi(dev); - mt76_free_pending_rxwi(dev); - if (mtk_wed_device_active(&dev->mmio.wed)) mtk_wed_device_detach(&dev->mmio.wed); + + if (mtk_wed_device_active(&dev->mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mmio.wed_hif2); + + mt76_free_pending_txwi(dev); + mt76_free_pending_rxwi(dev); } EXPORT_SYMBOL_GPL(mt76_dma_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3fc38f00d0a5..8389b493759c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -107,6 +107,16 @@ enum mt76_rxq_id { MT_RXQ_MAIN_WA, MT_RXQ_BAND2, MT_RXQ_BAND2_WA, + MT_RXQ_RRO_BAND0, + MT_RXQ_RRO_BAND1, + MT_RXQ_RRO_BAND2, + MT_RXQ_MSDU_PAGE_BAND0, + MT_RXQ_MSDU_PAGE_BAND1, + MT_RXQ_MSDU_PAGE_BAND2, + MT_RXQ_TXFREE_BAND0, + MT_RXQ_TXFREE_BAND1, + MT_RXQ_TXFREE_BAND2, + MT_RXQ_RRO_IND, __MT_RXQ_MAX }; @@ -604,6 +614,7 @@ struct mt76_mmio { u32 irqmask; struct mtk_wed_device wed; + struct mtk_wed_device wed_hif2; struct completion wed_reset; struct completion wed_reset_complete; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index b33346360075..72912f376bc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -7,6 +7,26 @@ #include "../dma.h" #include "mac.h" +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, + int ring_base, struct mtk_wed_device *wed) +{ + struct mt7996_dev *dev = phy->dev; + u32 flags = 0; + + if (mtk_wed_device_active(wed)) { + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; + idx -= MT_TXQ_ID(0); + + if (phy->mt76->band_idx == MT_BAND2) + flags = MT_WED_Q_TX(0); + else + flags = MT_WED_Q_TX(idx); + } + + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, + ring_base, wed, flags); +} + static int mt7996_poll_tx(struct napi_struct *napi, int budget) { struct mt7996_dev *dev; @@ -128,7 +148,7 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) } } -void mt7996_dma_start(struct mt7996_dev *dev, bool reset) +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { u32 hif1_ofs = 0; u32 irq_mask; @@ -153,11 +173,7 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) } /* enable interrupts for TX/RX rings */ - irq_mask = MT_INT_MCU_CMD; - if (reset) - goto done; - - irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; + irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; if (!dev->mphy.band_idx) irq_mask |= MT_INT_BAND0_RX_DONE; @@ -168,7 +184,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) if (dev->tbtc_support) irq_mask |= MT_INT_BAND2_RX_DONE; -done: + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) { + u32 wed_irq_mask = irq_mask; + + wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); + } + + irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; + mt7996_irq_enable(dev, irq_mask); mt7996_irq_disable(dev, 0); } @@ -243,15 +268,16 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) */ mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, MT_WFDMA0_RX_INT_SEL_RING3); - - /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */ } - mt7996_dma_start(dev, reset); + mt7996_dma_start(dev, reset, true); } int mt7996_dma_init(struct mt7996_dev *dev) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; + u32 rx_base; u32 hif1_ofs = 0; int ret; @@ -265,10 +291,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) mt7996_dma_disable(dev, true); /* init tx queue */ - ret = mt76_connac_init_tx_queues(dev->phy.mt76, - MT_TXQ_ID(dev->mphy.band_idx), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), NULL, 0); + ret = mt7996_init_tx_queues(&dev->phy, + MT_TXQ_ID(dev->mphy.band_idx), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(0), + wed); if (ret) return ret; @@ -315,6 +342,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* rx data queue for band0 and band1 */ + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); + dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7996_RX_RING_SIZE, @@ -324,6 +356,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ + if (mtk_wed_device_active(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], MT_RXQ_ID(MT_RXQ_MAIN_WA), MT7996_RX_MCU_RING_SIZE, @@ -334,17 +371,26 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { /* rx data queue for band2 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; + if (mtk_wed_device_active(wed)) + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2); + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs); + rx_base); if (ret) return ret; /* tx free notify event from WA for band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA], MT_RXQ_ID(MT_RXQ_BAND2_WA), MT7996_RX_MCU_RING_SIZE, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index b09ae6cc6eb4..e19c8fb71609 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -156,7 +156,7 @@ mt7996_regd_notifier(struct wiphy *wiphy, } static void -mt7996_init_wiphy(struct ieee80211_hw *hw) +mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) { struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt76_dev *mdev = &phy->dev->mt76; @@ -168,6 +168,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw) hw->max_rx_aggregation_subframes = max_subframes; hw->max_tx_aggregation_subframes = max_subframes; hw->netdev_features = NETIF_F_RXCSUM; + if (mtk_wed_device_active(wed)) + hw->netdev_features |= NETIF_F_HW_TC; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; @@ -356,6 +358,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, struct mt76_phy *mphy; u32 mac_ofs, hif1_ofs = 0; int ret; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; if (band != MT_BAND1 && band != MT_BAND2) return 0; @@ -367,8 +370,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (phy) return 0; - if (band == MT_BAND2 && dev->hif2) + if (band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + wed = &dev->mt76.mmio.wed_hif2; + } mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); if (!mphy) @@ -401,12 +406,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7996_init_wiphy(mphy->hw); - ret = mt76_connac_init_tx_queues(phy->mt76, - MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, - NULL, 0); + mt7996_init_wiphy(mphy->hw, wed); + ret = mt7996_init_tx_queues(mphy->priv, + MT_TXQ_ID(band), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(band) + hif1_ofs, + wed); if (ret) goto error; @@ -419,6 +424,13 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; + if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { + u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; + + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); + } + return 0; error: @@ -890,7 +902,7 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; - mt7996_init_wiphy(hw); + mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 53a78d971326..6095ce72ab1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -996,6 +996,29 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return 0; } +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) +{ + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; + __le32 *txwi = ptr; + u32 val; + + memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); + txwi[0] = cpu_to_le32(val); + + val = BIT(31) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); + txwi[1] = cpu_to_le32(val); + + txp->token = cpu_to_le16(token_id); + txp->nbuf = 1; + txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); + + return MT_TXD_SIZE + sizeof(*txp); +} + static void mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) { @@ -1403,6 +1426,12 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, switch (type) { case PKT_TYPE_TXRX_NOTIFY: + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) && + q == MT_RXQ_TXFREE_BAND2) { + dev_kfree_skb(skb); + break; + } + mt7996_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; @@ -1877,7 +1906,7 @@ void mt7996_mac_reset_work(struct work_struct *work) mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); /* enable DMA Tx/Tx and interrupt */ - mt7996_dma_start(dev, false); + mt7996_dma_start(dev, false, false); clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 09c7a28a3d51..f074616c7007 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1388,6 +1388,44 @@ mt7996_set_radar_background(struct ieee80211_hw *hw, return ret; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int +mt7996_net_fill_forward_path(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + + if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) + wed = &dev->mt76.mmio.wed_hif2; + + if (!mtk_wed_device_active(wed)) + return -ENODEV; + + if (msta->wcid.idx > MT7996_WTBL_STA) + return -EIO; + + path->type = DEV_PATH_MTK_WDMA; + path->dev = ctx->dev; + path->mtk_wdma.wdma_idx = wed->wdma_idx; + path->mtk_wdma.bss = mvif->mt76.idx; + path->mtk_wdma.queue = 0; + path->mtk_wdma.wcid = msta->wcid.idx; + + path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); + ctx->dev = NULL; + + return 0; +} + +#endif + const struct ieee80211_ops mt7996_ops = { .tx = mt7996_tx, .start = mt7996_start, @@ -1432,4 +1470,8 @@ const struct ieee80211_ops mt7996_ops = { .sta_add_debugfs = mt7996_sta_add_debugfs, #endif .set_radar_background = mt7996_set_radar_background, +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + .net_fill_forward_path = mt7996_net_fill_forward_path, + .net_setup_tc = mt76_net_setup_tc, +#endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 3a591a7b47ae..ae029ae9969d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -10,6 +10,10 @@ #include "mt7996.h" #include "mac.h" #include "../trace.h" +#include "../dma.h" + +static bool wed_enable; +module_param(wed_enable, bool, 0644); static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, @@ -191,6 +195,106 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); } +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct pci_dev *pci_dev = pdev_ptr; + u32 hif1_ofs = 0; + int ret; + + if (!wed_enable) + return 0; + + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + + if (hif2) + wed = &dev->mt76.mmio.wed_hif2; + + wed->wlan.pci_dev = pci_dev; + wed->wlan.bus_type = MTK_WED_BUS_PCIE; + + wed->wlan.base = devm_ioremap(dev->mt76.dev, + pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); + + if (hif2) { + wed->wlan.wpdma_int = wed->wlan.phy_base + + MT_INT_PCIE1_SOURCE_CSR_EXT; + wed->wlan.wpdma_mask = wed->wlan.phy_base + + MT_INT_PCIE1_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + + wed->wlan.id = 0x7991; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; + } else { + wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; + wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; + + wed->wlan.wpdma_rx = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.rx_nbuf = 65536; + wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); + + wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; + wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + + wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; + wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + + wed->wlan.amsdu_max_subframes = 8; + wed->wlan.amsdu_max_len = 1536; + + wed->wlan.init_buf = mt7996_wed_init_buf; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + + dev->mt76.rx_token_size += wed->wlan.rx_npkt; + + if (mtk_wed_device_attach(wed)) + return 0; + + *irq = wed->irq; + dev->mt76.dma_dev = wed->dev; + + ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + ret = dma_set_coherent_mask(wed->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + return 1; +#else + return 0; +#endif +} + static int mt7996_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, u32 device_id) @@ -241,8 +345,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, mdev->mmio.irqmask |= set; if (write_reg) { - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); - mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2, + mdev->mmio.irqmask); + } + } else { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + } } spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); @@ -260,22 +373,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev, static void mt7996_irq_tasklet(struct tasklet_struct *t) { struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; u32 i, intr, mask, intr1; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (dev->hif2 && mtk_wed_device_active(wed_hif2)) { + mtk_wed_device_irq_set_mask(wed_hif2, 0); + intr1 = mtk_wed_device_irq_get(wed_hif2, + dev->mt76.mmio.irqmask); + if (intr1 & MT_INT_RX_TXFREE_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); + } - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - intr &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (mtk_wed_device_active(wed)) { + mtk_wed_device_irq_set_mask(wed, 0); + intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); + intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); + } else { + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); - if (dev->hif2) { - intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); - intr1 &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); - - intr |= intr1; + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + intr &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (dev->hif2) { + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); + intr1 &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + intr |= intr1; + } } trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); @@ -307,10 +434,19 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t) irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (mtk_wed_device_active(wed)) + mtk_wed_device_irq_set_mask(wed, 0); + else + mt76_wr(dev, MT_INT_MASK_CSR, 0); + + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0); + else + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + } if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index e53cf6a3704c..ccb6c5763956 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -37,6 +37,7 @@ #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 +#define MT7996_HW_TOKEN_SIZE 8192 #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ @@ -334,7 +335,9 @@ int mt7996_dma_init(struct mt7996_dev *dev); void mt7996_dma_reset(struct mt7996_dev *dev, bool force); void mt7996_dma_prefetch(struct mt7996_dev *dev); void mt7996_dma_cleanup(struct mt7996_dev *dev); -void mt7996_dma_start(struct mt7996_dev *dev, bool reset); +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, + int n_desc, int ring_base, struct mtk_wed_device *wed); void mt7996_init_txpower(struct mt7996_dev *dev, struct ieee80211_supported_band *sband); int mt7996_txbf_init(struct mt7996_dev *dev); @@ -495,5 +498,12 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq); +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); + +#ifdef CONFIG_MTK_DEBUG +int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); +#endif #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index c5301050ff8b..93ecc9a8dde0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -92,10 +92,10 @@ static int mt7996_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pci_dev *hif2_dev; - struct mt7996_dev *dev; - struct mt76_dev *mdev; struct mt7996_hif *hif2; - int irq, ret; + struct mt7996_dev *dev; + int irq, hif2_irq, ret; + struct mt76_dev *mdev; ret = pcim_enable_device(pdev); if (ret) @@ -125,15 +125,22 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt7996_wfsys_reset(dev); hif2 = mt7996_pci_init_hif2(pdev); - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) - goto free_device; + goto free_wed_or_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_device; + + irq = pdev->irq; + } - irq = pdev->irq; ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto free_irq_vector; + goto free_wed_or_irq_vector; mt76_wr(dev, MT_INT_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -143,16 +150,25 @@ static int mt7996_pci_probe(struct pci_dev *pdev, hif2_dev = container_of(hif2->dev, struct pci_dev, dev); dev->hif2 = hif2; - ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq); if (ret < 0) - goto free_hif2; + goto free_hif2_wed_irq_vector; - dev->hif2->irq = hif2_dev->irq; - ret = devm_request_irq(mdev->dev, dev->hif2->irq, - mt7996_irq_handler, IRQF_SHARED, - KBUILD_MODNAME "-hif", dev); + if (!ret) { + ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, + PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_hif2; + + dev->hif2->irq = hif2_dev->irq; + hif2_irq = dev->hif2->irq; + } + + ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler, + IRQF_SHARED, KBUILD_MODNAME "-hif", + dev); if (ret) - goto free_hif2_irq_vector; + goto free_hif2_wed_irq_vector; mt76_wr(dev, MT_INT1_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -167,16 +183,23 @@ static int mt7996_pci_probe(struct pci_dev *pdev, free_hif2_irq: if (dev->hif2) - devm_free_irq(mdev->dev, dev->hif2->irq, dev); -free_hif2_irq_vector: - if (dev->hif2) - pci_free_irq_vectors(hif2_dev); + devm_free_irq(mdev->dev, hif2_irq, dev); +free_hif2_wed_irq_vector: + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2); + else + pci_free_irq_vectors(hif2_dev); + } free_hif2: if (dev->hif2) put_device(dev->hif2->dev); devm_free_irq(mdev->dev, irq, dev); -free_irq_vector: - pci_free_irq_vectors(pdev); +free_wed_or_irq_vector: + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_detach(&dev->mt76.mmio.wed); + else + pci_free_irq_vectors(pdev); free_device: mt76_free_device(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 0086a7866657..b7d78adce11a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -330,6 +330,7 @@ enum base_rev { #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) +#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) @@ -374,6 +375,9 @@ enum base_rev { #define MT_WFDMA0_PCIE1_BASE 0xd8000 #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) +#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118) +#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c) + #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) @@ -419,6 +423,7 @@ enum base_rev { #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) #define MT_INT_MCU_CMD BIT(29) +#define MT_INT_RX_TXFREE_EXT BIT(26) #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) From 5bb7a655045ebc023f421c13c2156fcd478185bc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:55 +0200 Subject: [PATCH 3197/7721] wifi: mt76: dma: introduce __mt76_dma_queue_reset utility routine This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index a7a045488cb2..12615b49c0d7 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -195,7 +195,8 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) } static void -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { int i; @@ -206,11 +207,19 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) for (i = 0; i < q->ndesc; i++) q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); - Q_WRITE(q, cpu_idx, 0); - Q_WRITE(q, dma_idx, 0); + if (reset_idx) { + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); + } mt76_dma_sync_idx(dev, q); } +static void +mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +{ + __mt76_dma_queue_reset(dev, q, true); +} + static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) From b8b36f47070f47dbfd3dc8eb0b674d6103306935 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:56 +0200 Subject: [PATCH 3198/7721] wifi: mt76: mt7996: use u16 for val field in mt7996_mcu_set_rro signature This is a preliminary patch to introduce WED rx support for mt7996 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index bf917beb9439..3ecdc09323c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4019,7 +4019,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev) &req, sizeof(req), false); } -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ccb6c5763956..d4425c133ced 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -397,7 +397,7 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val); +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl); int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); From 950d0abb5cd94f2b0710c5c42ac4398c91a7ff22 Mon Sep 17 00:00:00 2001 From: Bo Jiao Date: Fri, 20 Oct 2023 12:30:57 +0200 Subject: [PATCH 3199/7721] wifi: mt76: mt7996: add wed rx support Similar to MT7915, enable Wireless Ethernet Ditpatcher for MT7996 to offload traffic received from the WLAN nic and transmitted on the LAN one Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Signed-off-by: Bo Jiao Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 149 +++++++++---- drivers/net/wireless/mediatek/mt76/dma.h | 43 ++++ drivers/net/wireless/mediatek/mt76/mt76.h | 50 ++++- .../net/wireless/mediatek/mt76/mt7996/dma.c | 198 ++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7996/init.c | 175 +++++++++++++++- .../net/wireless/mediatek/mt76/mt7996/mac.c | 41 +++- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 24 ++- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 2 + .../net/wireless/mediatek/mt76/mt7996/mmio.c | 60 ++++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 55 +++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 62 +++++- 11 files changed, 772 insertions(+), 87 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 12615b49c0d7..7c76afdaef68 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -189,7 +189,10 @@ static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { Q_WRITE(q, desc_base, q->desc_dma); - Q_WRITE(q, ring_size, q->ndesc); + if (q->flags & MT_QFLAG_WED_RRO_EN) + Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); + else + Q_WRITE(q, ring_size, q->ndesc); q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -198,14 +201,16 @@ static void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, bool reset_idx) { - int i; - if (!q || !q->ndesc) return; - /* clear descriptors */ - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + /* clear descriptors */ + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } if (reset_idx) { Q_WRITE(q, cpu_idx, 0); @@ -224,13 +229,22 @@ static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) { - struct mt76_desc *desc = &q->desc[q->head]; struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; + struct mt76_desc *desc; u32 buf1 = 0, ctrl; int idx = q->head; int rx_token; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + data = &rro_desc[q->head]; + goto done; + } + + desc = &q->desc[q->head]; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); if (mt76_queue_is_wed_rx(q)) { @@ -253,6 +267,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); WRITE_ONCE(desc->info, 0); +done: entry->dma_addr[0] = buf->addr; entry->dma_len[0] = buf->len; entry->txwi = txwi; @@ -401,19 +416,26 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, { struct mt76_queue_entry *e = &q->entry[idx]; struct mt76_desc *desc = &q->desc[idx]; - void *buf; + u32 ctrl, desc_info, buf1; + void *buf = e->buf; + if (mt76_queue_is_wed_rro_ind(q)) + goto done; + + ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); if (len) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); *more = !(ctrl & MT_DMA_CTL_LAST_SEC0); } + desc_info = le32_to_cpu(desc->info); if (info) - *info = le32_to_cpu(desc->info); + *info = desc_info; + + buf1 = le32_to_cpu(desc->buf1); + mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info); if (mt76_queue_is_wed_rx(q)) { - u32 buf1 = le32_to_cpu(desc->buf1); u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1); struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token); @@ -429,23 +451,16 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, t->ptr = NULL; mt76_put_rxwi(dev, t); - - if (drop) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); - - *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | - MT_DMA_CTL_DROP)); - + if (drop) *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); - } } else { - buf = e->buf; - e->buf = NULL; dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size), page_pool_get_dma_dir(q->page_pool)); } +done: + e->buf = NULL; return buf; } @@ -459,11 +474,16 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, if (!q->queued) return NULL; - if (flush) - q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); - else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + if (mt76_queue_is_wed_rro_data(q)) return NULL; + if (!mt76_queue_is_wed_rro_ind(q)) { + if (flush) + q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); + else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + return NULL; + } + q->tail = (q->tail + 1) % q->ndesc; q->queued--; @@ -615,11 +635,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, spin_lock_bh(&q->lock); while (q->queued < q->ndesc - 1) { + struct mt76_queue_buf qbuf = {}; enum dma_data_direction dir; - struct mt76_queue_buf qbuf; dma_addr_t addr; int offset; - void *buf; + void *buf = NULL; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); if (!buf) @@ -630,6 +653,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, dma_sync_single_for_device(dev->dma_dev, addr, len, dir); qbuf.addr = addr + q->buf_offset; +done: qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false; if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { @@ -639,7 +663,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, frames++; } - if (frames) + if (frames || mt76_queue_is_wed_rx(q)) mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); @@ -650,8 +674,8 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED - int ret, type, ring; - u8 flags; + int ret = 0, type, ring; + u16 flags; if (!q || !q->ndesc) return -EINVAL; @@ -678,7 +702,6 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) q->flags = 0; mt76_dma_queue_reset(dev, q); mt76_dma_rx_fill(dev, q, false); - q->flags = flags; ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); if (!ret) @@ -690,9 +713,31 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) if (!ret) q->wed_regs = q->wed->rx_ring[ring].reg_base; break; + case MT76_WED_RRO_Q_DATA: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_MSDU_PG: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_IND: + q->flags &= ~MT_QFLAG_WED; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); + break; default: ret = -EINVAL; + break; } + q->flags = flags; return ret; #else @@ -716,11 +761,26 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, q->buf_size = bufsize; q->hw_idx = idx; - size = q->ndesc * sizeof(struct mt76_desc); - q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL); + size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) + : sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, + &q->desc_dma, GFP_KERNEL); if (!q->desc) return -ENOMEM; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + int i; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + for (i = 0; i < q->ndesc; i++) { + struct mt76_wed_rro_ind *cmd; + + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; + cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; + } + } + size = q->ndesc * sizeof(*q->entry); q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (!q->entry) @@ -734,8 +794,13 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - if (!mt76_queue_is_wed_tx_free(q)) - mt76_dma_queue_reset(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) { + if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) || + mt76_queue_is_wed_tx_free(q)) + return 0; + } + + mt76_dma_queue_reset(dev, q); return 0; } @@ -757,7 +822,8 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) if (!buf) break; - mt76_put_page_pool_buf(buf, false); + if (!mt76_queue_is_wed_rro(q)) + mt76_put_page_pool_buf(buf, false); } while (1); spin_lock_bh(&q->lock); @@ -773,13 +839,16 @@ static void mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; - int i; if (!q->ndesc) return; - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } mt76_dma_rx_cleanup(dev, q); @@ -991,6 +1060,10 @@ void mt76_dma_cleanup(struct mt76_dev *dev) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + continue; + netif_napi_del(&dev->napi[i]); mt76_dma_rx_cleanup(dev, q); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 1b090d78cd05..e549e678b69f 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -23,8 +23,17 @@ #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11) #define MT_DMA_PPE_ENTRY GENMASK(30, 16) +#define MT_DMA_INFO_DMA_FRAG BIT(9) #define MT_DMA_INFO_PPE_VLD BIT(31) +#define MT_DMA_CTL_PN_CHK_FAIL BIT(13) +#define MT_DMA_CTL_VER_MASK BIT(7) + +#define MT_DMA_RRO_EN BIT(13) + +#define MT_DMA_WED_IND_CMD_CNT 8 +#define MT_DMA_WED_IND_REASON GENMASK(15, 12) + #define MT_DMA_HDR_LEN 4 #define MT_RX_INFO_LEN 4 #define MT_FCE_INFO_LEN 4 @@ -37,6 +46,11 @@ struct mt76_desc { __le32 info; } __packed __aligned(4); +struct mt76_wed_rro_desc { + __le32 buf0; + __le32 buf1; +} __packed __aligned(4); + enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, @@ -54,9 +68,38 @@ enum mt76_mcu_evt_type { EVT_EVENT_DFS_DETECT_RSP, }; +enum mt76_dma_wed_ind_reason { + MT_DMA_WED_IND_REASON_NORMAL, + MT_DMA_WED_IND_REASON_REPEAT, + MT_DMA_WED_IND_REASON_OLDPKT, +}; + int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +static inline void +mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) +{ + if (!drop) + return; + + *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP)); + if (!(ctrl & MT_DMA_CTL_VER_MASK)) + return; + + switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) { + case MT_DMA_WED_IND_REASON_REPEAT: + *drop = true; + break; + case MT_DMA_WED_IND_REASON_OLDPKT: + *drop = !(info & MT_DMA_INFO_DMA_FRAG); + break; + default: + *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL); + break; + } +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8389b493759c..7aac973723bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -31,13 +31,20 @@ #define MT_QFLAG_WED_RING GENMASK(1, 0) #define MT_QFLAG_WED_TYPE GENMASK(4, 2) #define MT_QFLAG_WED BIT(5) +#define MT_QFLAG_WED_RRO BIT(6) +#define MT_QFLAG_WED_RRO_EN BIT(7) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ FIELD_PREP(MT_QFLAG_WED_RING, _n)) +#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n)) + #define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n) #define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n) #define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0) +#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) +#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) +#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) struct mt76_dev; struct mt76_phy; @@ -59,6 +66,9 @@ enum mt76_wed_type { MT76_WED_Q_TX, MT76_WED_Q_TXFREE, MT76_WED_Q_RX, + MT76_WED_RRO_Q_DATA, + MT76_WED_RRO_Q_MSDU_PG, + MT76_WED_RRO_Q_IND, }; struct mt76_bus_ops { @@ -194,6 +204,7 @@ struct mt76_queue { spinlock_t lock; spinlock_t cleanup_lock; struct mt76_queue_entry *entry; + struct mt76_rro_desc *rro_desc; struct mt76_desc *desc; u16 first; @@ -207,7 +218,7 @@ struct mt76_queue { u8 buf_offset; u8 hw_idx; - u8 flags; + u16 flags; struct mtk_wed_device *wed; u32 wed_regs; @@ -364,6 +375,17 @@ struct mt76_txq { bool aggr; }; +struct mt76_wed_rro_ind { + u32 se_id : 12; + u32 rsv : 4; + u32 start_sn : 12; + u32 ind_reason : 4; + u32 ind_cnt : 13; + u32 win_sz : 3; + u32 rsv2 : 13; + u32 magic_cnt : 3; +}; + struct mt76_txwi_cache { struct list_head list; dma_addr_t dma_addr; @@ -1581,10 +1603,32 @@ static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; } +static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_WED_RRO; +} + +static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; +} + +static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); +} + static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) { - return (q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; + if (!(q->flags & MT_QFLAG_WED)) + return false; + + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || + mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); + } struct mt76_txwi_cache * diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 72912f376bc9..2221d22ccffb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -65,6 +65,29 @@ static void mt7996_dma_config(struct mt7996_dev *dev) RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + if (dev->has_rro) { + /* band0 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, + MT7996_RXQ_RRO_BAND0); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, + MT7996_RXQ_MSDU_PG_BAND0); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, + MT7996_RXQ_TXFREE0); + /* band1 */ + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, + MT7996_RXQ_MSDU_PG_BAND1); + /* band2 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, + MT7996_RXQ_RRO_BAND2); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, + MT7996_RXQ_MSDU_PG_BAND2); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, + MT7996_RXQ_TXFREE2); + + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, + MT7996_RXQ_RRO_IND); + } + /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); @@ -93,6 +116,24 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + if (dev->has_rro) { + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, + PREFETCH(0x3a0, 0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, + PREFETCH(0x4a0, 0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, + PREFETCH(0x5a0, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, + PREFETCH(0x5e0, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, + PREFETCH(0x620, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, + PREFETCH(0x660, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, + PREFETCH(0x6a0, 0x4)); + } +#undef PREFETCH + mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE); } @@ -150,6 +191,7 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; u32 hif1_ofs = 0; u32 irq_mask; @@ -158,11 +200,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) /* enable WFDMA Tx/Rx */ if (!reset) { - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO); + else + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (dev->hif2) mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, @@ -184,12 +231,12 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) if (dev->tbtc_support) irq_mask |= MT_INT_BAND2_RX_DONE; - if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) { + if (mtk_wed_device_active(wed) && wed_reset) { u32 wed_irq_mask = irq_mask; wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); - mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); + mtk_wed_device_start(wed, wed_irq_mask); } irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; @@ -266,13 +313,85 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) /* fix hardware limitation, pcie1's rx ring3 is not available * so, redirect pcie0 rx ring3 interrupt to pcie1 */ - mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, - MT_WFDMA0_RX_INT_SEL_RING3); + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + dev->has_rro) + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, + MT_WFDMA0_RX_INT_SEL_RING6); + else + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, + MT_WFDMA0_RX_INT_SEL_RING3); } mt7996_dma_start(dev, reset, true); } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + u32 irq_mask; + int ret; + + /* ind cmd */ + mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], + MT_RXQ_ID(MT_RXQ_RRO_IND), + MT7996_RX_RING_SIZE, + 0, MT_RXQ_RRO_IND_RING_BASE); + if (ret) + return ret; + + /* rx msdu page queue for band0 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = + MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); + if (ret) + return ret; + + if (dev->dbdc_support) { + /* rx msdu page queue for band1 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = + MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); + if (ret) + return ret; + } + + if (dev->tbtc_support) { + /* rx msdu page queue for band2 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = + MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); + if (ret) + return ret; + } + + irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | + MT_INT_TX_DONE_BAND2; + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mt7996_irq_enable(dev, irq_mask); + + return 0; +} +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + int mt7996_dma_init(struct mt7996_dev *dev) { struct mtk_wed_device *wed = &dev->mt76.mmio.wed; @@ -356,7 +475,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ - if (mtk_wed_device_active(wed)) { + if (mtk_wed_device_active(wed) && !dev->has_rro) { dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; } @@ -372,9 +491,6 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { /* rx data queue for band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; - if (mtk_wed_device_active(wed)) - rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2); - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, @@ -386,7 +502,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) /* tx free notify event from WA for band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ - if (mtk_wed_device_active(wed_hif2)) { + if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; } @@ -400,6 +516,60 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; } + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && + dev->has_rro) { + /* rx rro data queue for band0 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = + MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], + MT_RXQ_ID(MT_RXQ_RRO_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0)); + if (ret) + return ret; + + /* tx free notify event from WA for band0 */ + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); + if (ret) + return ret; + + if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + /* rx rro data queue for band2 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], + MT_RXQ_ID(MT_RXQ_RRO_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); + if (ret) + return ret; + + /* tx free notify event from MAC for band2 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND2), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs); + if (ret) + return ret; + } + } + ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index e19c8fb71609..a1adbc65ae00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -320,8 +320,17 @@ void mt7996_mac_init(struct mt7996_dev *dev) /* rro module init */ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + if (dev->has_rro) { + u16 timeout; + + timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; + mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); + } else { + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + } mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_HW_PATH_HIF_VER, @@ -475,6 +484,163 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev) msleep(20); } +static int mt7996_wed_rro_init(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; + struct mt7996_wed_rro_addr *addr; + void *ptr; + int i; + + if (!dev->has_rro) + return 0; + + if (!mtk_wed_device_active(wed)) + return 0; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + &dev->wed_rro.ba_bitmap[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.ba_bitmap[i].ptr = ptr; + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + int j; + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr), + &dev->wed_rro.addr_elem[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.addr_elem[i].ptr = ptr; + memset(dev->wed_rro.addr_elem[i].ptr, 0, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr)); + + addr = dev->wed_rro.addr_elem[i].ptr; + for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { + addr->signature = 0xff; + addr++; + } + + wed->wlan.ind_cmd.addr_elem_phys[i] = + dev->wed_rro.addr_elem[i].phy_addr; + } + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), + &dev->wed_rro.session.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.session.ptr = ptr; + addr = dev->wed_rro.session.ptr; + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + addr->signature = 0xff; + addr++; + } + + /* rro hw init */ + /* TODO: remove line after WM has set */ + mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); + + /* setup BA bitmap cache address */ + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, + dev->wed_rro.ba_bitmap[0].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, + dev->wed_rro.ba_bitmap[1].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); + + /* setup Address element address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); + reg += 4; + } + + /* setup Address element address - separate address segment mode */ + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); + + wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; + wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; + wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; + + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); + + /* particular session configure */ + /* use max session idx + 1 as particular session id */ + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, + MT_RRO_PARTICULAR_CONFG_EN | + FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); + + /* interrupt enable */ + mt76_wr(dev, MT_RRO_HOST_INT_ENA, + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); + + /* rro ind cmd queue init */ + return mt7996_dma_rro_init(dev); +#else + return 0; +#endif +} + +static void mt7996_wed_rro_free(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + int i; + + if (!dev->has_rro) + return; + + if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) + return; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + if (!dev->wed_rro.ba_bitmap[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + dev->wed_rro.ba_bitmap[i].ptr, + dev->wed_rro.ba_bitmap[i].phy_addr); + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + if (!dev->wed_rro.addr_elem[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.addr_elem[i].ptr, + dev->wed_rro.addr_elem[i].phy_addr); + } + + if (!dev->wed_rro.session.ptr) + return; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.session.ptr, + dev->wed_rro.session.phy_addr); +#endif +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; @@ -496,6 +662,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_wed_rro_init(dev); + if (ret) + return ret; + ret = mt7996_eeprom_init(dev); if (ret < 0) return ret; @@ -934,6 +1104,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev) mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); + mt7996_wed_rro_free(dev); mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 6095ce72ab1f..e5d3b7569163 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -449,8 +449,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, return 0; } +static void +mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q, + struct mt7996_sta *msta, struct sk_buff *skb, + u32 info) +{ + struct ieee80211_vif *vif; + struct wireless_dev *wdev; + + if (!msta || !msta->vif) + return; + + if (!mt76_queue_is_wed_rx(q)) + return; + + if (!(info & MT_DMA_INFO_PPE_VLD)) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + wdev = ieee80211_vif_to_wdev(vif); + skb->dev = wdev->netdev; + + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), + FIELD_GET(MT_DMA_PPE_ENTRY, info)); +} + static int -mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) +mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -475,7 +503,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) u16 seq_ctrl = 0; __le16 fc = 0; int idx; + u8 hw_aggr = false; + struct mt7996_sta *msta = NULL; + hw_aggr = status->aggr; memset(status, 0, sizeof(*status)); band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); @@ -502,8 +533,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7996_sta *msta; - msta = container_of(status->wcid, struct mt7996_sta, wcid); spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&msta->wcid.poll_list)) @@ -708,12 +737,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) } } else { status->flag |= RX_FLAG_8023; + mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, + *info); } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); - if (!status->wcid || !ieee80211_is_data_qos(fc)) + if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) return 0; status->aggr = unicast && @@ -1448,7 +1479,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: - if (!mt7996_mac_fill_rx(dev, skb)) { + if (!mt7996_mac_fill_rx(dev, q, skb, info)) { mt76_rx(&dev->mt76, q, skb); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 3ecdc09323c5..5369f0a7800c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -963,7 +963,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) } static int -mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif, struct ieee80211_ampdu_params *params, bool enable, bool tx) { @@ -972,7 +972,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, struct sk_buff *skb; struct tlv *tlv; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -986,8 +986,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; + ba->ba_rdd_rro = !tx && enable && dev->has_rro; - return mt76_mcu_skb_send_msg(dev, skb, + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } @@ -1002,8 +1003,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, true); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true); } int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, @@ -1013,8 +1013,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; struct mt7996_vif *mvif = msta->vif; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, false); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false); } static void @@ -4023,10 +4022,8 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; - __le16 tag; __le16 len; - union { struct { u8 type; @@ -4041,6 +4038,11 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) u8 path; u8 __rsv2[3]; } __packed txfree_path; + struct { + __le16 flush_one; + __le16 flush_all; + u8 __rsv2[4]; + } __packed timeout; }; } __packed req = { .tag = cpu_to_le16(tag), @@ -4057,6 +4059,10 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) case UNI_RRO_SET_TXFREE_PATH: req.txfree_path.path = val; break; + case UNI_RRO_SET_FLUSH_TIMEOUT: + req.timeout.flush_one = cpu_to_le16(val); + req.timeout.flush_all = cpu_to_le16(2 * val); + break; default: return -EINVAL; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a88f6af323da..a4715b8e005b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -669,6 +669,8 @@ enum { UNI_RRO_GET_BA_SESSION_TABLE, UNI_RRO_SET_BYPASS_MODE, UNI_RRO_SET_TXFREE_PATH, + UNI_RRO_DEL_BA_SESSION, + UNI_RRO_SET_FLUSH_TIMEOUT }; enum{ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index ae029ae9969d..c7b6d4bd2ded 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -207,6 +207,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, if (!wed_enable) return 0; + dev->has_rro = true; + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); if (hif2) @@ -228,14 +230,27 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + MT_TXQ_RING_BASE(0) + MT7996_TXQ_BAND2 * MT_RING_SIZE; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + } else { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + } + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; + wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; wed->wlan.id = 0x7991; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; } else { + wed->wlan.hw_rro = dev->has_rro; /* default on */ wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + @@ -247,6 +262,16 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + MT7996_RXQ_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; + wed->wlan.rx_nbuf = 65536; wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); @@ -254,11 +279,25 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + + wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; + wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; + wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; } wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; @@ -273,8 +312,6 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; - dev->mt76.rx_token_size += wed->wlan.rx_npkt; - if (mtk_wed_device_attach(wed)) return 0; @@ -434,10 +471,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t) irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (mtk_wed_device_active(wed)) - mtk_wed_device_irq_set_mask(wed, 0); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0); else mt76_wr(dev, MT_INT_MASK_CSR, 0); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index d4425c133ced..f7b6945b7acc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -50,6 +50,22 @@ #define MT7996_BASIC_RATES_TBL 11 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_RRO_MAX_SESSION 1024 +#define MT7996_RRO_WINDOW_MAX_LEN 1024 +#define MT7996_RRO_ADDR_ELEM_LEN 128 +#define MT7996_RRO_BA_BITMAP_LEN 2 +#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \ + MT7996_RRO_BA_BITMAP_LEN) +#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \ + MT7996_RRO_ADDR_ELEM_LEN) +#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \ + MT7996_RRO_BA_BITMAP_SESSION_SIZE) + +#define MT7996_RX_BUF_SIZE (1800 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + struct mt7996_vif; struct mt7996_sta; struct mt7996_dfs_pulse; @@ -79,6 +95,16 @@ enum mt7996_rxq_id { MT7996_RXQ_BAND0 = 4, MT7996_RXQ_BAND1 = 4,/* unused */ MT7996_RXQ_BAND2 = 5, + MT7996_RXQ_RRO_BAND0 = 8, + MT7996_RXQ_RRO_BAND1 = 8,/* unused */ + MT7996_RXQ_RRO_BAND2 = 6, + MT7996_RXQ_MSDU_PG_BAND0 = 10, + MT7996_RXQ_MSDU_PG_BAND1 = 11, + MT7996_RXQ_MSDU_PG_BAND2 = 12, + MT7996_RXQ_TXFREE0 = 9, + MT7996_RXQ_TXFREE1 = 9, + MT7996_RXQ_TXFREE2 = 7, + MT7996_RXQ_RRO_IND = 0, }; struct mt7996_twt_flow { @@ -147,6 +173,15 @@ struct mt7996_hif { int irq; }; +struct mt7996_wed_rro_addr { + u32 head_low; + u32 head_high : 4; + u32 count: 11; + u32 oor: 1; + u32 rsv : 8; + u32 signature : 8; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -226,6 +261,22 @@ struct mt7996_dev { bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; + bool has_rro:1; + + struct { + struct { + void *ptr; + dma_addr_t phy_addr; + } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } addr_elem[MT7996_RRO_ADDR_ELEM_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } session; + } wed_rro; bool ibf; u8 fw_debug_wm; @@ -506,4 +557,8 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); #endif +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index b7d78adce11a..7cefe8985590 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -39,6 +39,38 @@ enum base_rev { #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +/* RRO TOP */ +#define MT_RRO_TOP_BASE 0xA000 +#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) + +#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8) +#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) +#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) +#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) +#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) +#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) + +#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C) +#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31) + +#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C) +#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60) +#define MT_RRO_PARTICULAR_CONFG_EN BIT(31) +#define MT_RRO_PARTICULAR_SID GENMASK(30, 16) + +#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70) +#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74) +#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204) +#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0) + +#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) + +#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) +#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) +#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) @@ -398,6 +430,7 @@ enum base_rev { #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) +#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) @@ -425,6 +458,14 @@ enum base_rev { #define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_TXFREE_EXT BIT(26) +#define MT_INT_RX_DONE_RRO_BAND0 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND2 BIT(14) +#define MT_INT_RX_DONE_RRO_IND BIT(11) +#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) +#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) +#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) + #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) @@ -432,20 +473,31 @@ enum base_rev { MT_INT_RX(MT_RXQ_MCU_WA)) #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ MT_INT_RX(MT_RXQ_BAND1_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \ MT_INT_RX(MT_RXQ_BAND2_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) + +#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ + MT_INT_RX(MT_RXQ_RRO_BAND1) | \ + MT_INT_RX(MT_RXQ_RRO_BAND2) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ MT_INT_BAND0_RX_DONE | \ MT_INT_BAND1_RX_DONE | \ - MT_INT_BAND2_RX_DONE) + MT_INT_BAND2_RX_DONE | \ + MT_INT_RRO_RX_DONE) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) @@ -558,6 +610,8 @@ enum base_rev { #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) #define MT_HW_REV 0x70010204 +#define MT_HW_REV1 0x8a00 + #define MT_WF_SUBSYS_RST 0x70028600 /* PCIE MAC */ From d4b85aff3ab32fbfde026090c47829e83a0422cc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:58 +0200 Subject: [PATCH 3200/7721] wifi: mt76: move wed reset common code in mt76 module Move WED reset code shared between mt7915 and mt7996 in common module. This is a preliminary patch to introduce WED reset support for mt7996. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 14 ++++++++++ drivers/net/wireless/mediatek/mt76/dma.h | 9 ++++++ drivers/net/wireless/mediatek/mt76/mmio.c | 8 ++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7915/dma.c | 28 ++----------------- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 9 +----- 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 7c76afdaef68..f2532e67fa78 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -1036,6 +1036,20 @@ void mt76_dma_attach(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_dma_attach); +void mt76_dma_wed_reset(struct mt76_dev *dev) +{ + struct mt76_mmio *mmio = &dev->mmio; + + if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) + return; + + complete(&mmio->wed_reset); + + if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) + dev_err(dev->dev, "wed reset complete timeout\n"); +} +EXPORT_SYMBOL_GPL(mt76_dma_wed_reset); + void mt76_dma_cleanup(struct mt76_dev *dev) { int i; diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index e549e678b69f..c60dfb817227 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -78,6 +78,15 @@ int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +void mt76_dma_wed_reset(struct mt76_dev *dev); + +static inline void +mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + dev->queue_ops->reset_q(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) + mt76_dma_wed_setup(dev, q, true); +} static inline void mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index c34624978a14..4a006409a373 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -179,6 +179,14 @@ void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) spin_unlock_bh(&dev->token_lock); } EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); + +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + complete(&dev->mmio.wed_reset_complete); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 7aac973723bc..36e54a32bd1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1102,6 +1102,7 @@ u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 1bceeb5227b1..c91a1c54027f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -587,28 +587,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return 0; } -static void mt7915_dma_wed_reset(struct mt7915_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - - if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state)) - return; - - complete(&mdev->mmio.wed_reset); - - if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete, - 3 * HZ)) - dev_err(dev->mt76.dev, "wed reset complete timeout\n"); -} - -static void -mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q) -{ - mt76_queue_reset(dev, q); - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) - mt76_dma_wed_setup(&dev->mt76, q, true); -} - int mt7915_dma_reset(struct mt7915_dev *dev, bool force) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; @@ -636,13 +614,13 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mtk_wed_device_dma_reset(wed); mt7915_dma_disable(dev, force); - mt7915_dma_wed_reset(dev); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (mphy_ext) - mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, mphy_ext->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 85cb3fed9505..c404c90b58a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -595,13 +595,6 @@ static int mt7915_mmio_wed_reset(struct mtk_wed_device *wed) return ret; } - -static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - complete(&dev->mmio.wed_reset_complete); -} #endif int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, @@ -685,7 +678,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; - wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; dev->mt76.rx_token_size = wed->wlan.rx_npkt; From 00d2ced0deb3b75177f634b2e7c0c87dca7d747e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:59 +0200 Subject: [PATCH 3201/7721] wifi: mt76: mt7996: add wed reset support Introduce the capability to reset mt7996 chipset if requested by wed driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 14 ++++-- .../net/wireless/mediatek/mt76/mt7996/dma.c | 18 +++++-- .../net/wireless/mediatek/mt76/mt7996/mac.c | 47 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 37 +++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 7 ++- 5 files changed, 114 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f2532e67fa78..439cdfab6f67 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -854,10 +854,16 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) /* reset WED rx queues */ mt76_dma_wed_setup(dev, q, true); - if (!mt76_queue_is_wed_tx_free(q)) { - mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill(dev, q, false); - } + + if (mt76_queue_is_wed_tx_free(q)) + return; + + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + return; + + mt76_dma_sync_idx(dev, q); + mt76_dma_rx_fill(dev, q, false); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 2221d22ccffb..8bc08d993085 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -621,21 +621,33 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) if (force) mt7996_wfsys_reset(dev); + if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed); + mt7996_dma_disable(dev, force); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_reset(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (phy2) - mt76_queue_reset(dev, phy2->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]); if (phy3) - mt76_queue_reset(dev, phy3->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) + continue; + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index e5d3b7569163..b790d415cd03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1712,6 +1712,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) napi_disable(&dev->mt76.napi[i]); } @@ -1725,6 +1729,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) local_bh_disable(); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); @@ -1896,6 +1904,13 @@ void mt7996_mac_reset_work(struct work_struct *work) dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", wiphy_name(dev->mt76.hw->wiphy)); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + ieee80211_stop_queues(mt76_hw(dev)); if (phy2) ieee80211_stop_queues(phy2->mt76->hw); @@ -1915,8 +1930,13 @@ void mt7996_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&phy3->mt76->mac_work); } mt76_worker_disable(&dev->mt76.tx_worker); - mt76_for_each_q_rx(&dev->mt76, i) + mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_disable(&dev->mt76.napi[i]); + } napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); @@ -1939,6 +1959,27 @@ void mt7996_mac_reset_work(struct work_struct *work) /* enable DMA Tx/Tx and interrupt */ mt7996_dma_start(dev, false, false); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 | + dev->mt76.mmio.irqmask; + + if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) + wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND; + + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, + true); + mt7996_irq_enable(dev, wed_irq_mask); + mt7996_irq_disable(dev, 0); + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); + } + clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) @@ -1948,6 +1989,10 @@ void mt7996_mac_reset_work(struct work_struct *work) local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index c7b6d4bd2ded..739d7f53d347 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -6,9 +6,11 @@ #include #include #include +#include #include "mt7996.h" #include "mac.h" +#include "mcu.h" #include "../trace.h" #include "../dma.h" @@ -195,6 +197,37 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed) +{ + struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt76_phy *mphy = &dev->mphy; + int ret; + + ASSERT_RTNL(); + + if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state)) + return -EBUSY; + + ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1, + mphy->band_idx); + if (ret) + goto out; + + rtnl_unlock(); + if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) { + dev_err(mdev->dev, "wed reset timeout\n"); + ret = -ETIMEDOUT; + } + rtnl_lock(); +out: + clear_bit(MT76_STATE_WED_RESET, &mphy->state); + + return ret; +} +#endif + int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, bool hif2, int *irq) { @@ -311,6 +344,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + if (!hif2) { + wed->wlan.reset = mt7996_mmio_wed_reset; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; + } if (mtk_wed_device_attach(wed)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 7cefe8985590..49eb583399c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -455,8 +455,9 @@ enum base_rev { #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) -#define MT_INT_MCU_CMD BIT(29) +#define MT_INT_RX_DONE_BAND2_EXT BIT(23) #define MT_INT_RX_TXFREE_EXT BIT(26) +#define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_DONE_RRO_BAND0 BIT(16) #define MT_INT_RX_DONE_RRO_BAND1 BIT(16) @@ -506,6 +507,10 @@ enum base_rev { #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_BAND2 BIT(15) +#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \ + MT_INT_RX_DONE_BAND2_EXT | \ + MT_INT_RX_TXFREE_EXT) + #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ MT_INT_TX_MCU(MT_MCUQ_FWDL)) From a5d028d668360db991e6da67cd48b9b4443198ed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:31:00 +0200 Subject: [PATCH 3202/7721] wifi: mt76: mt7996: add wed rro delete session garbage collector Introduce the capability to clear WED rro session configured in the hw according to the event reported by the MCU firmware Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 52 +++++++++++ .../net/wireless/mediatek/mt76/mt7996/mac.c | 3 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 89 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 35 ++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 10 +++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 6 ++ 8 files changed, 197 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 36e54a32bd1f..b1d3f55d7034 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -404,6 +404,7 @@ struct mt76_rx_tid { spinlock_t lock; struct delayed_work reorder_work; + u16 id; u16 head; u16 size; u16 nframes; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0563b1b22f48..97822f7d46cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1022,6 +1022,7 @@ enum { MCU_UNI_EVENT_ROC = 0x27, MCU_UNI_EVENT_TX_DONE = 0x2d, MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index a1adbc65ae00..5af85ddfdc36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -641,6 +641,54 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev) #endif } +static void mt7996_wed_rro_work(struct work_struct *work) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mt7996_dev *dev; + LIST_HEAD(list); + + dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev, + wed_rro.work); + + spin_lock_bh(&dev->wed_rro.lock); + list_splice_init(&dev->wed_rro.poll_list, &list); + spin_unlock_bh(&dev->wed_rro.lock); + + while (!list_empty(&list)) { + struct mt7996_wed_rro_session_id *e; + int i; + + e = list_first_entry(&list, struct mt7996_wed_rro_session_id, + list); + list_del_init(&e->list); + + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + void *ptr = dev->wed_rro.session.ptr; + struct mt7996_wed_rro_addr *elem; + u32 idx, elem_id = i; + + if (e->id == MT7996_RRO_MAX_SESSION) + goto reset; + + idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE; + if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem)) + goto out; + + ptr = dev->wed_rro.addr_elem[idx].ptr; + elem_id += + (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) * + MT7996_RRO_WINDOW_MAX_LEN; +reset: + elem = ptr + elem_id * sizeof(*elem); + elem->signature = 0xff; + } + mt7996_mcu_wed_rro_reset_sessions(dev, e->id); +out: + kfree(e); + } +#endif +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; @@ -648,6 +696,9 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); INIT_WORK(&dev->init_work, mt7996_init_work); + INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); + INIT_LIST_HEAD(&dev->wed_rro.poll_list); + spin_lock_init(&dev->wed_rro.lock); dev->dbdc_support = true; dev->tbtc_support = true; @@ -1100,6 +1151,7 @@ int mt7996_register_device(struct mt7996_dev *dev) void mt7996_unregister_device(struct mt7996_dev *dev) { + cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); mt7996_coredump_unregister(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index b790d415cd03..f653e93349f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1822,6 +1822,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) if (phy3) ieee80211_stop_queues(phy3->mt76->hw); + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) cancel_delayed_work_sync(&phy2->mt76->mac_work); @@ -1920,6 +1921,8 @@ void mt7996_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); + + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5369f0a7800c..03a9474120b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -526,6 +526,73 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) dev_kfree_skb(skb); } +static void +mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_wed_rro_event *event = (void *)skb->data; + + if (!dev->has_rro) + return; + + skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4); + + switch (le16_to_cpu(event->tag)) { + case UNI_WED_RRO_BA_SESSION_STATUS: { + struct mt7996_mcu_wed_rro_ba_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt76_rx_tid *tid; + struct mt76_wcid *wcid; + u16 idx; + + e = (void *)skb->data; + idx = le16_to_cpu(e->wlan_id); + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + break; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (!wcid || !wcid->sta) + break; + + if (e->tid >= ARRAY_SIZE(wcid->aggr)) + break; + + tid = rcu_dereference(wcid->aggr[e->tid]); + if (!tid) + break; + + tid->id = le16_to_cpu(e->id); + skb_pull(skb, sizeof(*e)); + } + break; + } + case UNI_WED_RRO_BA_SESSION_DELETE: { + struct mt7996_mcu_wed_rro_ba_delete_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt7996_wed_rro_session_id *session; + + e = (void *)skb->data; + session = kzalloc(sizeof(*session), GFP_ATOMIC); + if (!session) + break; + + session->id = le16_to_cpu(e->session_id); + + spin_lock_bh(&dev->wed_rro.lock); + list_add_tail(&session->list, &dev->wed_rro.poll_list); + spin_unlock_bh(&dev->wed_rro.lock); + + ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work); + skb_pull(skb, sizeof(*e)); + } + break; + } + default: + break; + } +} + static void mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -544,6 +611,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_UNI_EVENT_ALL_STA_INFO: mt7996_mcu_rx_all_sta_info_event(dev, skb); break; + case MCU_UNI_EVENT_WED_RRO: + mt7996_mcu_wed_rro_event(dev, skb); + break; default: break; } @@ -4087,3 +4157,22 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO), &req, sizeof(req), false); } + +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) +{ + struct { + u8 __rsv[4]; + + __le16 tag; + __le16 len; + __le16 session_id; + u8 pad[4]; + } __packed req = { + .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION), + .len = cpu_to_le16(sizeof(req) - 4), + .session_id = cpu_to_le16(id), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, + sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a4715b8e005b..e32a78d6622b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -179,6 +179,41 @@ struct mt7996_mcu_all_sta_info_event { }; } __packed; +struct mt7996_mcu_wed_rro_event { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; +} __packed; + +struct mt7996_mcu_wed_rro_ba_event { + __le16 tag; + __le16 len; + + __le16 wlan_id; + u8 tid; + u8 __rsv1; + __le32 status; + __le16 id; + u8 __rsv2[2]; +} __packed; + +struct mt7996_mcu_wed_rro_ba_delete_event { + __le16 tag; + __le16 len; + + __le16 session_id; + u8 __rsv2[2]; +} __packed; + +enum { + UNI_WED_RRO_BA_SESSION_STATUS, + UNI_WED_RRO_BA_SESSION_TBL, + UNI_WED_RRO_BA_SESSION_DELETE, +}; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index f7b6945b7acc..e7818b2b253f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -182,6 +182,11 @@ struct mt7996_wed_rro_addr { u32 signature : 8; }; +struct mt7996_wed_rro_session_id { + struct list_head list; + u16 id; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -276,6 +281,10 @@ struct mt7996_dev { void *ptr; dma_addr_t phy_addr; } session; + + struct work_struct work; + struct list_head poll_list; + spinlock_t lock; } wed_rro; bool ibf; @@ -456,6 +465,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); void mt7996_mcu_exit(struct mt7996_dev *dev); int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 49eb583399c5..e9edba830aff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -71,6 +71,12 @@ enum base_rev { #define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) #define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) +#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0) +#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0) +#define MT_RRO_DBG_RD_EXEC BIT(31) + +#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) From 5f9d5d4fc561e7bd3a18742f1fdb96cab98f1870 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:45:19 +0200 Subject: [PATCH 3203/7721] wifi: mt76: mt7915: fallback to non-wed mode if platform_get_resource fails in mt7915_mmio_wed_init() mt76 assumes mt7915_mmio_wed_init can fail just after wed driver has been attached running mtk_wed_device_attach(). Fall back to non-wed mode if platform_get_resource fails in mt7915_mmio_wed_init routines. Fixes: eebb70976be5 ("wifi: mt76: mt7915: enable wed for mt7986-wmac chipset") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index c404c90b58a6..aff4f21e843d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -636,7 +636,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); if (!res) - return -ENOMEM; + return 0; wed->wlan.platform_dev = plat_dev; wed->wlan.bus_type = MTK_WED_BUS_AXI; From af2825729b52a45d239def2c243531aa9e7bf81a Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 23 Oct 2023 23:38:44 +0800 Subject: [PATCH 3204/7721] wifi: mt76: mt7996: add support for variants with auxiliary RX path Add support to correctly configure the rx chainmask of variants that have additional auxiliary RX path. e.g., 4T5R. The auxiliary RX path is transparent to driver, but driver needs to correctly configure it in the set channel fw command. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/eeprom.c | 21 +++++++++++++++---- .../wireless/mediatek/mt76/mt7996/eeprom.h | 3 +++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 14 +++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 544b6c6f1ea3..9db7e531076d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -148,36 +148,49 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy) int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) { - u8 path, nss, band_idx = phy->mt76->band_idx; + u8 path, rx_path, nss, band_idx = phy->mt76->band_idx; u8 *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; + int max_path = 5, max_nss = 4; int ret; switch (band_idx) { case MT_BAND1: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1, eeprom[MT_EE_WIFI_CONF + 5]); break; case MT_BAND2: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2, + eeprom[MT_EE_WIFI_CONF + 4]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2, eeprom[MT_EE_WIFI_CONF + 5]); break; default: path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0, eeprom[MT_EE_WIFI_CONF + 1]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0, eeprom[MT_EE_WIFI_CONF + 4]); break; } - if (!path || path > 4) - path = 4; + if (!path || path > max_path) + path = max_path; - nss = min_t(u8, min_t(u8, 4, nss), path); + if (!nss || nss > max_nss) + nss = max_nss; + + nss = min_t(u8, nss, path); + + if (path != rx_path) + phy->has_aux_rx = true; mphy->antenna_mask = BIT(nss) - 1; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h index 0c749774f6b1..412d6e2f8014 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h @@ -33,6 +33,9 @@ enum mt7996_eeprom_field { #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3) +#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0) #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 03a9474120b7..55e97a857963 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3299,7 +3299,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx], + .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx], .band_idx = band_idx, .channel_band = ch_band[chandef->chan->band], }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index e7818b2b253f..6acc0ae286fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -210,6 +210,8 @@ struct mt7996_phy { struct mt76_mib_stats mib; struct mt76_channel_state state_ts; + + bool has_aux_rx; }; struct mt7996_dev { @@ -501,6 +503,18 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask) void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, size_t len); +static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) +{ + int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx); + int cur_nss = hweight8(phy->mt76->antenna_mask); + u16 tx_chainmask = phy->mt76->chainmask; + + if (cur_nss != max_nss) + return tx_chainmask; + + return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); From 0afb228d9bd439088d2d1d58bae7295340000e27 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:45 +0800 Subject: [PATCH 3205/7721] wifi: mt76: mt7996: add TX statistics for EHT mode in debugfs Add EHT statistics of beamforming feedback and BW320 in debugfs tx_stats command. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 4d40ec7ff57f..9bd953586b04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -476,7 +476,7 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) { struct mt76_mib_stats *mib = &phy->mib; static const char * const bw[] = { - "BW20", "BW40", "BW80", "BW160" + "BW20", "BW40", "BW80", "BW160", "BW320" }; /* Tx Beamformer monitor */ @@ -489,8 +489,9 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) /* Tx Beamformer Rx feedback monitor */ seq_puts(s, "Tx Beamformer Rx feedback statistics: "); - seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", + seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ", mib->tx_bf_rx_fb_all_cnt, + mib->tx_bf_rx_fb_eht_cnt, mib->tx_bf_rx_fb_he_cnt, mib->tx_bf_rx_fb_vht_cnt, mib->tx_bf_rx_fb_ht_cnt); From 21f290884bc1c911aa9a0875c1d9a1e6fb9e0308 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:46 +0800 Subject: [PATCH 3206/7721] wifi: mt76: connac: add thermal protection support for mt7996 Implement thermal protection commands and support Linux cooling device control for mt7996 chipsets. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 102 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/main.c | 8 ++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 104 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 44 ++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 15 +++ 6 files changed, 274 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 97822f7d46cc..1d8680b153a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1021,6 +1021,7 @@ enum { MCU_UNI_EVENT_RDD_REPORT = 0x11, MCU_UNI_EVENT_ROC = 0x27, MCU_UNI_EVENT_TX_DONE = 0x2d, + MCU_UNI_EVENT_THERMAL = 0x35, MCU_UNI_EVENT_NIC_CAPAB = 0x43, MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 5af85ddfdc36..02b47b299ea8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -43,6 +43,97 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static int +mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7996_CDEV_THROTTLE_MAX; + + return 0; +} + +static int +mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7996_phy *phy = cdev->devdata; + + *state = phy->cdev_state; + + return 0; +} + +static int +mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7996_phy *phy = cdev->devdata; + u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state; + int ret; + + if (state > MT7996_CDEV_THROTTLE_MAX) { + dev_err(phy->dev->mt76.dev, + "please specify a valid throttling state\n"); + return -EINVAL; + } + + if (state == phy->cdev_state) + return 0; + + /* cooling_device convention: 0 = no cooling, more = more cooling + * mcu convention: 1 = max cooling, more = less cooling + */ + ret = mt7996_mcu_set_thermal_throttling(phy, throttling); + if (ret) + return ret; + + phy->cdev_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7996_thermal_ops = { + .get_max_state = mt7996_thermal_get_max_throttle_state, + .get_cur_state = mt7996_thermal_get_cur_throttle_state, + .set_cur_state = mt7996_thermal_set_cur_throttle_state, +}; + +static void mt7996_unregister_thermal(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + + if (!phy->cdev) + return; + + sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + thermal_cooling_device_unregister(phy->cdev); +} + +static int mt7996_thermal_init(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct thermal_cooling_device *cdev; + const char *name; + + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", + wiphy_name(wiphy)); + + cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + "cooling_device") < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + + /* initialize critical/maximum high temperature */ + phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; + phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + + return 0; +} + static void mt7996_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { @@ -429,6 +520,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; + ret = mt7996_thermal_init(phy); + if (ret) + goto error; + ret = mt7996_init_debugfs(phy); if (ret) goto error; @@ -456,6 +551,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) if (!phy) return; + mt7996_unregister_thermal(phy); + mphy = phy->dev->mt76.phys[band]; mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); @@ -1130,6 +1227,10 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_thermal_init(&dev->phy); + if (ret) + return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); @@ -1154,6 +1255,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev) cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); + mt7996_unregister_thermal(&dev->phy); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); mt7996_wed_rro_free(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index f074616c7007..33a9d50d3366 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw) if (ret) goto out; + ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); + if (ret) + goto out; + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + goto out; + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 55e97a857963..292a6cd9b1fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -497,6 +497,34 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) } } +static void +mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb) +{ +#define THERMAL_NOTIFY_TAG 0x4 +#define THERMAL_NOTIFY 0x2 + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7996_mcu_thermal_notify *n; + struct mt7996_phy *phy; + + n = (struct mt7996_mcu_thermal_notify *)skb->data; + + if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG) + return; + + if (n->event_id != THERMAL_NOTIFY) + return; + + if (n->band_idx > MT_BAND2) + return; + + mphy = dev->mt76.phys[n->band_idx]; + if (!mphy) + return; + + phy = (struct mt7996_phy *)mphy->priv; + phy->throttle_state = n->duty_percent; +} + static void mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -520,6 +548,9 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7996_mcu_rx_ext_event(dev, skb); break; + case MCU_UNI_EVENT_THERMAL: + mt7996_mcu_rx_thermal_notify(dev, skb); + break; default: break; } @@ -3571,6 +3602,79 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch) return 0; } +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + } __packed req = { + .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG), + .len = cpu_to_le16(sizeof(req) - 4), + .ctrl = { + .band_idx = phy->mt76->band_idx, + }, + }; + int level, ret; + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state /= 2; + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); + if (ret) + return ret; + } + + return 0; +} + +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable) +{ +#define SUSTAIN_PERIOD 10 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + struct mt7996_mcu_thermal_enable enable; + } __packed req = { + .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)), + .ctrl = { + .band_idx = phy->mt76->band_idx, + .type.protect_type = 1, + .type.trigger_type = 1, + }, + }; + int ret; + + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE); + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req) - sizeof(req.enable), false); + if (ret || !enable) + return ret; + + /* set high-temperature trigger threshold */ + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE); + req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]); + req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); + req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + + req.len = cpu_to_le16(sizeof(req) - 4); + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); +} + int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index e32a78d6622b..4a73850db9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event { __le32 status; /* 0: success, others: fail */ } __packed; +struct mt7996_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7996_mcu_thermal_enable { + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; +} __packed; + struct mt7996_mcu_csa_notify { struct mt7996_mcu_rxd rxd; @@ -214,6 +236,22 @@ enum { UNI_WED_RRO_BA_SESSION_DELETE, }; +struct mt7996_mcu_thermal_notify { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + + u8 event_id; + u8 band_idx; + u8 level_idx; + u8 duty_percent; + __le32 restore_temp; + u8 __rsv2[4]; +} __packed; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, @@ -719,6 +757,12 @@ enum{ UNI_CMD_SR_SET_SIGA = 0xd0, }; +enum { + UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6, + UNI_CMD_THERMAL_PROTECT_DISABLE, + UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, +}; + enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 6acc0ae286fa..61e0f905d902 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -50,6 +50,13 @@ #define MT7996_BASIC_RATES_TBL 11 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_THERMAL_THROTTLE_MAX 100 +#define MT7996_CDEV_THROTTLE_MAX 99 +#define MT7996_CRIT_TEMP_IDX 0 +#define MT7996_MAX_TEMP_IDX 1 +#define MT7996_CRIT_TEMP 110 +#define MT7996_MAX_TEMP 120 + #define MT7996_RRO_MAX_SESSION 1024 #define MT7996_RRO_WINDOW_MAX_LEN 1024 #define MT7996_RRO_ADDR_ELEM_LEN 128 @@ -195,6 +202,11 @@ struct mt7996_phy { struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 cdev_state; + u8 throttle_state; + u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ + u32 rxfilter; u64 omac_mask; @@ -453,6 +465,9 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); +int mt7996_mcu_get_temperature(struct mt7996_phy *phy); +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, From 6879b2e94172ed80394dd49d410814ad427d1ca0 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:47 +0800 Subject: [PATCH 3207/7721] wifi: mt76: mt7996: add thermal sensor device support This patch adds support for thermal sensor device, including the following features: - Support to read current chip temperature. - Support to set/get the trigger/restore temperature for thermal service. - Support to read current chip tx cycle. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/init.c | 88 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 42 +++++++++ 2 files changed, 130 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 02b47b299ea8..e2d08bf96eb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include "mt7996.h" #include "mac.h" @@ -43,6 +45,82 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static ssize_t mt7996_thermal_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int i = to_sensor_dev_attr(attr)->index; + int temperature; + + switch (i) { + case 0: + temperature = mt7996_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); + case 1: + case 2: + return sprintf(buf, "%u\n", + phy->throttle_temp[i - 1] * 1000); + case 3: + return sprintf(buf, "%hhu\n", phy->throttle_state); + default: + return -EINVAL; + } +} + +static ssize_t mt7996_thermal_temp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int ret, i = to_sensor_dev_attr(attr)->index; + long val; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&phy->dev->mt76.mutex); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130); + + /* add a safety margin ~10 */ + if ((i - 1 == MT7996_CRIT_TEMP_IDX && + val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) || + (i - 1 == MT7996_MAX_TEMP_IDX && + val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) { + dev_err(phy->dev->mt76.dev, + "temp1_max shall be 10 degrees higher than temp1_crit."); + mutex_unlock(&phy->dev->mt76.mutex); + return -EINVAL; + } + + phy->throttle_temp[i - 1] = val; + mutex_unlock(&phy->dev->mt76.mutex); + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + return ret; + + return count; +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2); +static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3); + +static struct attribute *mt7996_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_throttle1.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7996_hwmon); + static int mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, unsigned long *state) @@ -113,6 +191,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; struct thermal_cooling_device *cdev; + struct device *hwmon; const char *name; name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", @@ -131,6 +210,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy) phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, + mt7996_hwmon_groups); + + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 292a6cd9b1fb..48c7f4fe1bc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3602,6 +3602,48 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch) return 0; } +int mt7996_mcu_get_temperature(struct mt7996_phy *phy) +{ +#define TEMPERATURE_QUERY 0 +#define GET_TEMPERATURE 0 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 rsv1; + u8 action; + u8 band_idx; + u8 rsv2; + } req = { + .tag = cpu_to_le16(TEMPERATURE_QUERY), + .len = cpu_to_le16(sizeof(req) - 4), + .action = GET_TEMPERATURE, + .band_idx = phy->mt76->band_idx, + }; + struct mt7996_mcu_thermal { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + __le32 rsv; + __le32 temperature; + } __packed * res; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (void *)skb->data; + + return le32_to_cpu(res->temperature); +} + int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) { struct { From 254ab81f3b82a297da5c0684a9ebf21fbc9dcb86 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 23 Oct 2023 23:38:48 +0800 Subject: [PATCH 3208/7721] wifi: mt76: connac: add beacon duplicate TX mode support for mt7996 For connac3 chipsets, setting of spe_idx is moved from TX descriptor to the fixed rate table. This patch implements the setting to support duplicate TX mode for beacon. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 6 ++-- .../net/wireless/mediatek/mt76/mt7996/mac.c | 11 ------- .../net/wireless/mediatek/mt76/mt7996/main.c | 18 ++++++------ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 29 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 20 +++++++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 8 +++-- 7 files changed, 68 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 1d8680b153a7..65844de6dccd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1242,6 +1242,7 @@ enum { MCU_UNI_CMD_CHANNEL_SWITCH = 0x34, MCU_UNI_CMD_THERMAL = 0x35, MCU_UNI_CMD_VOW = 0x37, + MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, MCU_UNI_CMD_PER_STA_INFO = 0x6d, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index e2d08bf96eb0..6a03cddaed04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -354,6 +354,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; + phy->beacon_rate = -1; hw->sta_data_size = sizeof(struct mt7996_sta); hw->vif_data_size = sizeof(struct mt7996_vif); @@ -468,11 +469,12 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) { u16 rate = mt76_rates[i].hw_value; - u16 idx = MT7996_BASIC_RATES_TBL + i; + /* odd index for driver, even index for firmware */ + u16 idx = MT7996_BASIC_RATES_TBL + 2 * i; rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) | FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0)); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); + mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index f653e93349f3..08747f7d5429 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -248,17 +248,6 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, mt76_clear(dev, addr, BIT(5)); } -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx) -{ - u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; - - mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); - /* use wtbl spe idx */ - mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); - mt76_wr(dev, MT_WTBL_ITCR, ctrl); -} - /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 33a9d50d3366..9f12b47eb2bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -522,24 +522,25 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt76_phy *mphy = hw->priv; u16 rate; - u8 i, idx, ht; + u8 i, idx; rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); - ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; - if (beacon && ht) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); + if (beacon) { + struct mt7996_phy *phy = mphy->priv; + + /* odd index for driver, even index for firmware */ + idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; + if (phy->beacon_rate != rate) + mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon); - /* must odd index */ - idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); return idx; } idx = FIELD_GET(MT_TX_RATE_IDX, rate); for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) - return MT7996_BASIC_RATES_TBL + i; + return MT7996_BASIC_RATES_TBL + 2 * i; return mvif->basic_rates_idx; } @@ -965,7 +966,6 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); - /* TODO: update bmc_wtbl spe_idx when antenna changes */ mutex_unlock(&dev->mt76.mutex); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 48c7f4fe1bc7..a13ff8f7be54 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4179,6 +4179,35 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon) +{ +#define UNI_FIXED_RATE_TABLE_SET 0 +#define SPE_IXD_SELECT_TXD 0 +#define SPE_IXD_SELECT_BMC_WTBL 1 + struct mt7996_dev *dev = phy->dev; + struct fixed_rate_table_ctrl req = { + .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET), + .len = cpu_to_le16(sizeof(req) - 4), + .table_idx = table_idx, + .rate_idx = cpu_to_le16(rate_idx), + .gi = 1, + .he_ltf = 1, + }; + u8 band_idx = phy->mt76->band_idx; + + if (beacon) { + req.spe_idx_sel = SPE_IXD_SELECT_TXD; + req.spe_idx = 24 + band_idx; + phy->beacon_rate = rate_idx; + } else { + req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE), + &req, sizeof(req), false); +} + int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 4a73850db9c0..a2700151ee1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -801,4 +801,24 @@ enum { #define MT7996_SEC_KEY_IDX GENMASK(2, 1) #define MT7996_SEC_IV BIT(3) +struct fixed_rate_table_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 table_idx; + u8 antenna_idx; + __le16 rate_idx; + u8 spe_idx_sel; + u8 spe_idx; + u8 gi; + u8 he_ltf; + bool ldpc; + bool txbf; + bool dynamic_bw; + + u8 _rsv2; +} __packed; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 61e0f905d902..ed99432b2d03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -47,7 +47,7 @@ #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ -#define MT7996_BASIC_RATES_TBL 11 +#define MT7996_BASIC_RATES_TBL 31 #define MT7996_BEACON_RATES_TBL 25 #define MT7996_THERMAL_THROTTLE_MAX 100 @@ -217,6 +217,8 @@ struct mt7996_phy { u8 rdd_state; + u16 beacon_rate; + u32 rx_ampdu_ts; u32 ampdu_ref; @@ -472,6 +474,8 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); @@ -538,8 +542,6 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy); void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, struct ieee80211_vif *vif, bool enable); -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, From 4aa9992674e70074fce450f65ebc95c2ba2b79ae Mon Sep 17 00:00:00 2001 From: Sujuan Chen Date: Mon, 23 Oct 2023 23:38:49 +0800 Subject: [PATCH 3209/7721] wifi: mt76: mt7996: fix the size of struct bss_rate_tlv Align the format of struct bss_rate_tlv to the firmware. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Sujuan Chen Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a2700151ee1c..d3ac6ac0e5c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -320,7 +320,7 @@ struct bss_rate_tlv { u8 short_preamble; u8 bc_fixed_rate; u8 mc_fixed_rate; - u8 __rsv2[1]; + u8 __rsv2[9]; } __packed; struct bss_ra_tlv { From de2a41cbfc7a78b1dd1941329b9aaf6c49829035 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:50 +0800 Subject: [PATCH 3210/7721] wifi: mt76: mt7996: adjust WFDMA settings to improve performance Refactor and update dma prefetch parts and also split band 1 traffic to PCIe 1 to enhance throughput. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 70 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7996/regs.h | 9 +++ 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 8bc08d993085..7ec6c64b3fd1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -99,38 +99,49 @@ static void mt7996_dma_config(struct mt7996_dev *dev) MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL); } +static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) +{ + u32 ret = *base << 16 | depth; + + *base = *base + (depth << 4); + + return ret; +} + static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { -#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth)) + u16 base = 0; + +#define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x10)); if (dev->has_rro) { mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, - PREFETCH(0x3a0, 0x10)); + PREFETCH(0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, - PREFETCH(0x4a0, 0x10)); + PREFETCH(0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, - PREFETCH(0x5a0, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, - PREFETCH(0x5e0, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, - PREFETCH(0x620, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, - PREFETCH(0x660, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, - PREFETCH(0x6a0, 0x4)); + PREFETCH(0x4)); } #undef PREFETCH @@ -295,6 +306,12 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1, WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20); + if (dev->hif2) { /* GLO_CFG_EXT0 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, @@ -306,7 +323,18 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_PDMA_BAND); + MT_WFDMA_HOST_CONFIG_PDMA_BAND | + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + + /* AXI read outstanding number */ + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, + MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); + + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20); } if (dev->hif2) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index e9edba830aff..6102df912741 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -379,6 +379,11 @@ enum base_rev { #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268) +#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c) +#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270) +#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c) + #define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18) #define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE BIT(14) @@ -401,10 +406,14 @@ enum base_rev { #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) +#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) +#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500) +#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0) + #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) From 4ef49d1858e78da25c204e00b872cd35782cfc84 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:51 +0800 Subject: [PATCH 3211/7721] wifi: mt76: connac: set fixed_bw bit in TX descriptor for fixed rate frames Always set the fixed_bw bitfield for fixed rate frames to keep it being sent with specific bandwidth. Without this change, the bw of fixed rate frames will still be decided by hardware. Reported-by: Chank Chen Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 2250252b2047..36edf1d3dfca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -239,7 +239,8 @@ enum tx_mgnt_type { #define MT_TXD6_TX_SRC GENMASK(31, 30) #define MT_TXD6_VTA BIT(28) -#define MT_TXD6_BW GENMASK(25, 22) +#define MT_TXD6_FIXED_BW BIT(25) +#define MT_TXD6_BW GENMASK(24, 22) #define MT_TXD6_TX_RATE GENMASK(21, 16) #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 08747f7d5429..861737fe55cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -943,7 +943,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, idx = mvif->basic_rates_idx; } - txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW; + txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } From 8c8f77e0a6569f8b82ec749c0d3ce16224aeb418 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:52 +0800 Subject: [PATCH 3212/7721] wifi: mt76: mt7996: handle IEEE80211_RC_SMPS_CHANGED Make mt7996_mcu_set_fixed_field() non-static in order to handle IEEE80211_RC_SMPS_CHANGED in mt7996_mac_sta_rc_work(). Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 861737fe55cd..b17365b8d07b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2285,7 +2285,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) IEEE80211_RC_BW_CHANGED)) mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); - /* TODO: smps change */ + if (changed & IEEE80211_RC_SMPS_CHANGED) + mt7996_mcu_set_fixed_field(dev, vif, sta, NULL, + RATE_PARAM_MMPS_UPDATE); spin_lock_bh(&dev->mt76.sta_poll_lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index a13ff8f7be54..554ebe794caf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1800,9 +1800,8 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, MCU_WM_UNI_CMD(RA), true); } -static int -mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, void *data, u32 field) +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; @@ -1830,6 +1829,9 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, if (phy) ra->phy = *phy; break; + case RATE_PARAM_MMPS_UPDATE: + ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); + break; default: break; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ed99432b2d03..0a150bcb2c19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -452,6 +452,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif); int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version); +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset); int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); From 22f5dc781574b0f7ce7b491165dcf14bd6151a51 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:53 +0800 Subject: [PATCH 3213/7721] wifi: mt76: mt7996: align the format of fixed rate command Use the new fixed rate command format to let the fixed field function work normally. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 12 ++-- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 71 ++++++++++++++++++- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 554ebe794caf..5a8a30115e2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1805,8 +1805,8 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct sta_phy *phy = data; - struct sta_rec_ra_fixed *ra; + struct sta_phy_uni *phy = data; + struct sta_rec_ra_fixed_uni *ra; struct sk_buff *skb; struct tlv *tlv; @@ -1817,7 +1817,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); - ra = (struct sta_rec_ra_fixed *)tlv; + ra = (struct sta_rec_ra_fixed_uni *)tlv; switch (field) { case RATE_PARAM_AUTO: @@ -1849,7 +1849,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_phy phy = {}; + struct sta_phy_uni phy = {}; int ret, nrates = 0; #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ @@ -1937,13 +1937,13 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, struct cfg80211_chan_def *chandef = &mphy->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_rec_ra *ra; + struct sta_rec_ra_uni *ra; struct tlv *tlv; u32 supp_rate = sta->deflink.supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); - ra = (struct sta_rec_ra *)tlv; + ra = (struct sta_rec_ra_uni *)tlv; ra->valid = true; ra->auto_rate = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index d3ac6ac0e5c9..a3eae32c8f10 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -494,6 +494,73 @@ struct sta_rec_sec_uni { struct sec_key_uni key[2]; } __packed; +struct sta_phy_uni { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; + u8 rsv[3]; +}; + +struct sta_rec_ra_uni { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_cap; + + struct sta_phy_uni phy; + u8 rx_rcpi[4]; +} __packed; + +struct sta_rec_ra_fixed_uni { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct sta_phy_uni phy; + + u8 spe_idx; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + struct sta_rec_hdrt { __le16 tag; __le16 len; @@ -677,9 +744,9 @@ enum { sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ sizeof(struct sta_rec_phy) + \ - sizeof(struct sta_rec_ra) + \ + sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ - sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_ra_fixed_uni) + \ sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_eht) + \ sizeof(struct sta_rec_hdrt) + \ From 1e3f387736c744e73b5398a147b90412f82f54da Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Mon, 23 Oct 2023 23:38:54 +0800 Subject: [PATCH 3214/7721] wifi: mt76: mt7996: fix rate usage of inband discovery frames For UBPR and FILS frames, the BSS_CHANGED_BEACON flag will also be set, which causes those frames to use the beacon rate in TX descriptors. Adjust the statement to fix this issue. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: MeiChia Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index b17365b8d07b..6f1ade64bcb2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -860,10 +860,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct mt76_vif *mvif; u16 tx_count = 15; u32 val; - bool beacon = !!(changed & (BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED)); bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); + bool beacon = !!(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL; if (mvif) { From 11a60bd2a590f8caa89a9079503d9e907e47d129 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 2 Nov 2023 18:02:55 +0800 Subject: [PATCH 3215/7721] wifi: mt76: change txpower init to per-phy Use per-phy structure for maximum txpower value initializing, since each phy may have a different chainmask, which can impact the calculation of power gain. Co-developed-by: Allen Ye Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/init.c | 30 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7915/mac.c | 4 +-- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 +- .../net/wireless/mediatek/mt76/mt7996/init.c | 30 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 81478289f17e..cea2f6d9050a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -275,10 +275,11 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, mt7915_led_set_config(led_cdev, 0xff, 0); } -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7915_init_txpower(struct mt7915_phy *phy, + struct ieee80211_supported_band *sband) { - int i, n_chains = hweight8(dev->mphy.antenna_mask); + struct mt7915_dev *dev = phy->dev; + int i, n_chains = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(n_chains); int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -296,7 +297,7 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -307,6 +308,19 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } } +void mt7915_init_txpower(struct mt7915_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7915_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -322,9 +336,7 @@ mt7915_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7915_mcu_rdd_background_enable(phy, NULL); - mt7915_init_txpower(dev, &mphy->sband_2g.sband); - mt7915_init_txpower(dev, &mphy->sband_5g.sband); - mt7915_init_txpower(dev, &mphy->sband_6g.sband); + mt7915_init_txpower(phy); mphy->dfs_state = MT_DFS_STATE_UNKNOWN; mt7915_dfs_init_radar_detector(phy); @@ -442,6 +454,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy) mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); + mt7915_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -703,9 +716,6 @@ static void mt7915_init_work(struct work_struct *work) mt7915_mcu_set_eeprom(dev); mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7915_txbf_init(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f12008244db3..b01edbed969c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1401,8 +1401,8 @@ mt7915_mac_restart(struct mt7915_dev *dev) goto out; mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); + mt7915_init_txpower(&dev->phy); + mt7915_init_txpower(phy2); ret = mt7915_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index d317c523b23f..4727d9c7b11d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -425,8 +425,7 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset); int mt7915_txbf_init(struct mt7915_dev *dev); -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband); +void mt7915_init_txpower(struct mt7915_phy *phy); void mt7915_reset(struct mt7915_dev *dev); int mt7915_run(struct ieee80211_hw *hw); int mt7915_mcu_init(struct mt7915_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 6a03cddaed04..1896571ad140 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -288,10 +288,11 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev, mt7996_led_set_config(led_cdev, 0xff, 0); } -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7996_init_txpower(struct mt7996_phy *phy, + struct ieee80211_supported_band *sband) { - int i, nss = hweight8(dev->mphy.antenna_mask); + struct mt7996_dev *dev = phy->dev; + int i, nss = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(nss); int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -301,7 +302,7 @@ void mt7996_init_txpower(struct mt7996_dev *dev, int target_power = mt7996_eeprom_get_target_power(dev, chan); target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -312,6 +313,19 @@ void mt7996_init_txpower(struct mt7996_dev *dev, } } +void mt7996_init_txpower(struct mt7996_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7996_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -326,9 +340,7 @@ mt7996_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7996_mcu_rdd_background_enable(phy, NULL); - mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband); + mt7996_init_txpower(phy); phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; mt7996_dfs_init_radar_detector(phy); @@ -424,6 +436,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -656,9 +669,6 @@ static void mt7996_init_work(struct work_struct *work) mt7996_mcu_set_eeprom(dev); mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7996_txbf_init(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 6f1ade64bcb2..1ee64efe0b88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1755,9 +1755,9 @@ mt7996_mac_restart(struct mt7996_dev *dev) goto out; mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); + mt7996_init_txpower(&dev->phy); + mt7996_init_txpower(phy2); + mt7996_init_txpower(phy3); ret = mt7996_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0a150bcb2c19..d3eb564623ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -414,8 +414,7 @@ void mt7996_dma_cleanup(struct mt7996_dev *dev); void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, int ring_base, struct mtk_wed_device *wed); -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband); +void mt7996_init_txpower(struct mt7996_phy *phy); int mt7996_txbf_init(struct mt7996_dev *dev); void mt7996_reset(struct mt7996_dev *dev); int mt7996_run(struct ieee80211_hw *hw); From f75e4779d215a7dbe7eb7ab6f1ed075fe66930bc Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 2 Nov 2023 18:02:56 +0800 Subject: [PATCH 3216/7721] wifi: mt76: mt7996: add txpower setting support Add support for setting txpower from upper layer and configuring per-rate txpower limit table. Co-developed-by: Allen Ye Signed-off-by: Allen Ye Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 8 +++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 58 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 16 +++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 + 4 files changed, 85 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 9f12b47eb2bf..7336eaa7b9ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -396,6 +396,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & (IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_CHANNEL)) { + ret = mt7996_mcu_set_txpower_sku(phy); + if (ret) + return ret; + } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { @@ -965,6 +972,7 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_mcu_set_txpower_sku(phy); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5a8a30115e2c..2c987b9ca25d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4353,3 +4353,61 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, sizeof(req), true); } + +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) +{ +#define TX_POWER_LIMIT_TABLE_RATE 0 + struct mt7996_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct tx_power_limit_table_ctrl { + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + u8 power_ctrl_id; + u8 power_limit_type; + u8 band_idx; + } __packed req = { + .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL), + .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4), + .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL, + .power_limit_type = TX_POWER_LIMIT_TABLE_RATE, + .band_idx = phy->mt76->band_idx, + }; + struct mt76_power_limits la = {}; + struct sk_buff *skb; + int i, tx_power; + + tx_power = mt7996_get_power_bound(phy, hw->conf.power_level); + tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, + &la, tx_power); + mphy->txpower_cur = tx_power; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req) + MT7996_SKU_RATE_NUM); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req, sizeof(req)); + /* cck and ofdm */ + skb_put_data(skb, &la.cck, sizeof(la.cck) + sizeof(la.ofdm)); + /* ht20 */ + skb_put_data(skb, &la.mcs[0], 8); + /* ht40 */ + skb_put_data(skb, &la.mcs[1], 9); + + /* vht */ + for (i = 0; i < 4; i++) { + skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i])); + skb_put_zero(skb, 2); /* padding */ + } + + /* he */ + skb_put_data(skb, &la.ru[0], sizeof(la.ru)); + /* eht */ + skb_put_data(skb, &la.eht[0], sizeof(la.eht)); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD(TXPOWER), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a3eae32c8f10..1562c8a6a821 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -762,6 +762,18 @@ enum { #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ MT7996_BEACON_UPDATE_SIZE) +static inline s8 +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower) +{ + struct mt76_phy *mphy = phy->mt76; + int n_chains = hweight16(mphy->chainmask); + + txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); + txpower -= mt76_tx_power_nss_delta(n_chains); + + return txpower; +} + enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, @@ -830,6 +842,10 @@ enum { UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, }; +enum { + UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, +}; + enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index d3eb564623ae..c62a42512bd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -42,6 +42,8 @@ #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7996_SKU_RATE_NUM 417 + #define MT7996_MAX_TWT_AGRT 16 #define MT7996_MAX_STA_TWT_AGRT 8 #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) @@ -471,6 +473,7 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, From 1e12f0f81f36b7470bcd7e65904ff8264fd31a5b Mon Sep 17 00:00:00 2001 From: Allen Ye Date: Thu, 2 Nov 2023 18:02:57 +0800 Subject: [PATCH 3217/7721] wifi: mt76: use chainmask for power delta calculation The power gain value is related to total TX path, so change the calculation to use per-phy chainmask. Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 59586fa134e3..0bc66cc19acd 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -381,7 +381,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, if (!np) return target_power; - txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask)); + txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d4004a62af1d..8a3a90d1bfac 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1548,7 +1548,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { struct mt76_phy *phy = hw->priv; - int n_chains = hweight8(phy->antenna_mask); + int n_chains = hweight16(phy->chainmask); int delta = mt76_tx_power_nss_delta(n_chains); *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 1592b5d6751a..b41ac4aaced7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -519,7 +519,7 @@ static inline s8 mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower) { struct mt76_phy *mphy = phy->mt76; - int n_chains = hweight8(mphy->antenna_mask); + int n_chains = hweight16(mphy->chainmask); txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); txpower -= mt76_tx_power_nss_delta(n_chains); From d57e1b255475957ab9280f8a2a6119853aef4d05 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Thu, 2 Nov 2023 18:02:58 +0800 Subject: [PATCH 3218/7721] wifi: mt76: mt7996: switch to mcu command for TX GI report During runtime, the GI value in the WTBL is not updated in real-time. To obtain the latest results for the TX GI, switch to use an MCU command. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- .../net/wireless/mediatek/mt76/mt7996/mac.c | 48 ++----------------- .../net/wireless/mediatek/mt76/mt7996/main.c | 1 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 47 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 22 +++++++++ 5 files changed, 74 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 65844de6dccd..0185804d8ce3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1328,7 +1328,7 @@ enum { }; enum UNI_ALL_STA_INFO_TAG { - UNI_ALL_STA_TX_RATE, + UNI_ALL_STA_TXRX_RATE, UNI_ALL_STA_TX_STAT, UNI_ALL_STA_TXRX_ADM_STAT, UNI_ALL_STA_TXRX_AIR_TIME, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 1ee64efe0b88..1cc573551bdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -102,7 +102,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) }; struct ieee80211_sta *sta; struct mt7996_sta *msta; - struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); int i; @@ -118,7 +117,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) u32 addr, val; u16 idx; s8 rssi[4]; - u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { @@ -174,49 +172,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } - /* We don't support reading GI info from txs packets. - * For accurate tx status reporting and AQL improvement, - * we need to make sure that flags match so polling GI - * from per-sta counters directly. - */ - rate = &msta->wcid.rate; - - switch (rate->bw) { - case RATE_INFO_BW_320: - bw = IEEE80211_STA_RX_BW_320; - break; - case RATE_INFO_BW_160: - bw = IEEE80211_STA_RX_BW_160; - break; - case RATE_INFO_BW_80: - bw = IEEE80211_STA_RX_BW_80; - break; - case RATE_INFO_BW_40: - bw = IEEE80211_STA_RX_BW_40; - break; - default: - bw = IEEE80211_STA_RX_BW_20; - break; - } - - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6); - val = mt76_rr(dev, addr); - if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5); - val = mt76_rr(dev, addr); - rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); - } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { - u8 offs = 24 + 2 * bw; - - rate->he_gi = (val & (0x3 << offs)) >> offs; - } else if (rate->flags & - (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { - if (val & BIT(12 + bw)) - rate->flags |= RATE_INFO_FLAGS_SHORT_GI; - else - rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; - } - /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); val = mt76_rr(dev, addr); @@ -1298,6 +1253,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, goto out; rate.flags = RATE_INFO_FLAGS_VHT_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: @@ -2312,6 +2269,7 @@ void mt7996_mac_work(struct work_struct *work) mt7996_mac_update_stats(phy); + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE); if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT); mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 7336eaa7b9ae..d9ba57ae9fdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -998,6 +998,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.he_gi = txrate->he_gi; sinfo->txrate.he_dcm = txrate->he_dcm; sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; + sinfo->txrate.eht_gi = txrate->eht_gi; } sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 2c987b9ca25d..49c364785f2a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -449,6 +449,43 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) } } +static int +mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) +{ + switch (mcu_rate->tx_mode) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_VHT: + if (mcu_rate->tx_gi) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2) + return -EINVAL; + rate->he_gi = mcu_rate->tx_gi; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2) + return -EINVAL; + rate->eht_gi = mcu_rate->tx_gi; + break; + default: + return -EINVAL; + } + + return 0; +} + static void mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -465,6 +502,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) struct mt76_wcid *wcid; switch (le16_to_cpu(res->tag)) { + case UNI_ALL_STA_TXRX_RATE: + wlan_idx = le16_to_cpu(res->rate[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i])) + dev_err(dev->mt76.dev, "Failed to update TX GI\n"); + break; case UNI_ALL_STA_TXRX_ADM_STAT: wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx); wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 1562c8a6a821..328edc354165 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -175,6 +175,27 @@ struct mt7996_mcu_mib { __le64 data; } __packed; +struct all_sta_trx_rate { + __le16 wlan_idx; + u8 __rsv1[2]; + u8 tx_mode; + u8 flags; + u8 tx_stbc; + u8 tx_gi; + u8 tx_bw; + u8 tx_ldpc; + u8 tx_mcs; + u8 tx_nss; + u8 rx_rate; + u8 rx_mode; + u8 rx_nsts; + u8 rx_gi; + u8 rx_coding; + u8 rx_stbc; + u8 rx_bw; + u8 __rsv2; +} __packed; + struct mt7996_mcu_all_sta_info_event { u8 rsv[4]; __le16 tag; @@ -185,6 +206,7 @@ struct mt7996_mcu_all_sta_info_event { u8 rsv3[2]; union { + struct all_sta_trx_rate rate[0]; struct { __le16 wlan_idx; u8 rsv[2]; From d58a9778f7ca0634622d2fc2e9f76163467bdf5b Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 2 Nov 2023 18:02:59 +0800 Subject: [PATCH 3219/7721] wifi: mt76: mt7996: fix alignment of sta info event Fix the alignment of struct mt7996_mcu_all_sta_info_event. Fixes: adde3eed4a75 ("wifi: mt76: mt7996: Add mcu commands for getting sta tx statistic") Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 328edc354165..e23cc96c4dbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -203,7 +203,7 @@ struct mt7996_mcu_all_sta_info_event { u8 more; u8 rsv2; __le16 sta_num; - u8 rsv3[2]; + u8 rsv3[4]; union { struct all_sta_trx_rate rate[0]; From b769f7d8d9002a602232704505a7c593e1fa087c Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 2 Nov 2023 18:03:00 +0800 Subject: [PATCH 3220/7721] wifi: mt76: mt7996: rework ampdu params setting Add sta_rec_ht_uni struct to pass HT ampdu params to firmware. For VHT, HE, and EHT mode, firmware will get the ampdu params by parsing the corresponding capability. Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 48 +++---------------- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 12 ++++- 2 files changed, 16 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 49c364785f2a..5c86e28bcd21 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1255,7 +1255,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) static void mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct sta_rec_ht *ht; + struct sta_rec_ht_uni *ht; struct tlv *tlv; if (!sta->deflink.ht_cap.ht_supported) @@ -1263,8 +1263,12 @@ mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; + ht = (struct sta_rec_ht_uni *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); + ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor, + IEEE80211_HT_AMPDU_PARM_FACTOR) | + u8_encode_bits(sta->deflink.ht_cap.ampdu_density, + IEEE80211_HT_AMPDU_PARM_DENSITY); } static void @@ -1721,44 +1725,6 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } -static void -mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) -{ - struct sta_rec_phy *phy; - struct tlv *tlv; - u8 af = 0, mm = 0; - - if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) - return; - - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); - - phy = (struct sta_rec_phy *)tlv; - if (sta->deflink.ht_cap.ht_supported) { - af = sta->deflink.ht_cap.ampdu_factor; - mm = sta->deflink.ht_cap.ampdu_density; - } - - if (sta->deflink.vht_cap.vht_supported) { - u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, - sta->deflink.vht_cap.cap); - - af = max_t(u8, af, vht_af); - } - - if (sta->deflink.he_6ghz_capa.capa) { - af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); - mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); - } - - phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) | - FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm); - phy->max_ampdu_len = af; -} - static void mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -2167,8 +2133,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, /* tag order is in accordance with firmware dependency. */ if (sta) { - /* starec phy */ - mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta); /* starec hdrt mode */ mt7996_mcu_sta_hdrt_tlv(dev, skb); /* starec bfer */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index e23cc96c4dbc..1851528d10ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -467,6 +467,15 @@ struct bss_mld_tlv { u8 __rsv[3]; } __packed; +struct sta_rec_ht_uni { + __le16 tag; + __le16 len; + __le16 ht_cap; + __le16 ht_cap_ext; + u8 ampdu_param; + u8 _rsv[3]; +} __packed; + struct sta_rec_ba_uni { __le16 tag; __le16 len; @@ -758,14 +767,13 @@ enum { #define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_bf) + \ - sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_ht_uni) + \ sizeof(struct sta_rec_he_v2) + \ sizeof(struct sta_rec_ba_uni) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ - sizeof(struct sta_rec_phy) + \ sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra_fixed_uni) + \ From eb80e02b2c03141460749d3800126e2cdb674c9e Mon Sep 17 00:00:00 2001 From: Allen Ye Date: Thu, 2 Nov 2023 18:03:01 +0800 Subject: [PATCH 3221/7721] wifi: mt76: connac: add beacon protection support for mt7996 Implement beacon protection feature for mt7996 chipsets, and also do some cleanup on the set key routine. Co-developed-by: Rudra Shahi Signed-off-by: Rudra Shahi Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 24 +++ .../net/wireless/mediatek/mt76/mt7996/main.c | 12 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 137 +++++++++++++----- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 17 +++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 5 files changed, 152 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0185804d8ce3..ae6d0179727d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -416,6 +416,14 @@ struct sta_rec_he_6g_capa { u8 rsv[2]; } __packed; +struct sta_rec_pn_info { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 tsc_type; + u8 rsv; +} __packed; + struct sec_key { u8 cipher_id; u8 cipher_len; @@ -768,6 +776,7 @@ struct wtbl_raw { sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra_fixed) + \ sizeof(struct sta_rec_he_6g_capa) + \ + sizeof(struct sta_rec_pn_info) + \ sizeof(struct tlv) + \ MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) @@ -798,6 +807,7 @@ enum { STA_REC_HE_V2 = 0x19, STA_REC_MLD = 0x20, STA_REC_EHT = 0x22, + STA_REC_PN_INFO = 0x26, STA_REC_HDRT = 0x28, STA_REC_HDR_TRANS = 0x2B, STA_REC_MAX_NUM @@ -1090,6 +1100,13 @@ enum mcu_cipher_type { MCU_CIPHER_GCMP_256, MCU_CIPHER_WAPI, MCU_CIPHER_BIP_CMAC_128, + MCU_CIPHER_BIP_CMAC_256, + MCU_CIPHER_BCN_PROT_CMAC_128, + MCU_CIPHER_BCN_PROT_CMAC_256, + MCU_CIPHER_BCN_PROT_GMAC_128, + MCU_CIPHER_BCN_PROT_GMAC_256, + MCU_CIPHER_BIP_GMAC_128, + MCU_CIPHER_BIP_GMAC_256, }; enum { @@ -1310,6 +1327,7 @@ enum { UNI_BSS_INFO_RATE = 11, UNI_BSS_INFO_QBSS = 15, UNI_BSS_INFO_SEC = 16, + UNI_BSS_INFO_BCN_PROT = 17, UNI_BSS_INFO_TXCMD = 18, UNI_BSS_INFO_UAPSD = 19, UNI_BSS_INFO_PS = 21, @@ -1771,6 +1789,12 @@ mt76_connac_mcu_get_cipher(int cipher) return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: return MCU_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + return MCU_CIPHER_BIP_GMAC_128; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + return MCU_CIPHER_BIP_GMAC_256; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + return MCU_CIPHER_BIP_CMAC_256; case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index d9ba57ae9fdc..51deea84b642 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -350,6 +350,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -373,9 +375,13 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } mt76_wcid_key_setup(&dev->mt76, wcid, key); - err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, - key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); + + if (key->keyidx == 6 || key->keyidx == 7) + err = mt7996_mcu_bcn_prot_enable(dev, vif, key); + else + err = mt7996_mcu_add_key(&dev->mt76, vif, key, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &msta->wcid, cmd); out: mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5c86e28bcd21..b5e27c29b1c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2171,7 +2171,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, static int mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, - struct mt76_connac_sta_key_conf *sta_key_conf, struct sk_buff *skb, struct ieee80211_key_conf *key, enum set_key_cmd cmd) @@ -2192,43 +2191,22 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, return -EOPNOTSUPP; sec_key = &sec->key[0]; + sec_key->wlan_idx = cpu_to_le16(wcid->idx); + sec_key->mgmt_prot = 0; + sec_key->cipher_id = cipher; sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_id = key->keyidx; + sec_key->key_len = key->keylen; + sec_key->need_resp = 0; + memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MCU_CIPHER_BIP_CMAC_128) { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_AES_CCMP; - sec_key->key_id = sta_key_conf->keyidx; - sec_key->key_len = 16; - memcpy(sec_key->key, sta_key_conf->key, 16); - - sec_key = &sec->key[1]; - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; - sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_len = 16; - memcpy(sec_key->key, key->key, 16); - sec->n_cipher = 2; - } else { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = cipher; - sec_key->key_id = key->keyidx; - sec_key->key_len = key->keylen; - memcpy(sec_key->key, key->key, key->keylen); - - if (cipher == MCU_CIPHER_TKIP) { - /* Rx/Tx MIC keys are swapped */ - memcpy(sec_key->key + 16, key->key + 24, 8); - memcpy(sec_key->key + 24, key->key + 16, 8); - } - - /* store key_conf for BIP batch update */ - if (cipher == MCU_CIPHER_AES_CCMP) { - memcpy(sta_key_conf->key, key->key, key->keylen); - sta_key_conf->keyidx = key->keyidx; - } - - sec->n_cipher = 1; + if (cipher == MCU_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); } + + sec->n_cipher = 1; } else { sec->n_cipher = 0; } @@ -2237,7 +2215,6 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, } int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd) { @@ -2250,13 +2227,99 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7996_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd); + ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd); if (ret) return ret; return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } +static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif, + u8 *pn) +{ +#define TSC_TYPE_BIGTK_PN 2 + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct sta_rec_pn_info *pn_info; + struct sk_buff *skb, *rskb; + struct tlv *tlv; + int ret; + + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &mvif->sta.wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info)); + pn_info = (struct sta_rec_pn_info *)tlv; + + pn_info->tsc_type = TSC_TYPE_BIGTK_PN; + ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE), + true, &rskb); + if (ret) + return ret; + + skb_pull(rskb, 4); + + pn_info = (struct sta_rec_pn_info *)rskb->data; + if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO) + memcpy(pn, pn_info->pn, 6); + + dev_kfree_skb(rskb); + return 0; +} + +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_mcu_bcn_prot_tlv *bcn_prot; + struct sk_buff *skb; + struct tlv *tlv; + u8 pn[6] = {}; + int len = sizeof(struct bss_req_hdr) + + sizeof(struct mt7996_mcu_bcn_prot_tlv); + int ret; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot)); + + bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv; + + ret = mt7996_mcu_get_pn(dev, vif, pn); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + default: + dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n"); + dev_kfree_skb(skb); + return -EOPNOTSUPP; + } + + pn[0]++; + memcpy(bcn_prot->pn, pn, 6); + bcn_prot->enable = BP_SW_MODE; + memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN); + bcn_prot->key_id = key->keyidx; + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); +} int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 1851528d10ca..10a1b09ff2fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -345,6 +345,23 @@ struct bss_rate_tlv { u8 __rsv2[9]; } __packed; +enum { + BP_DISABLE, + BP_SW_MODE, + BP_HW_MODE, +}; + +struct mt7996_mcu_bcn_prot_tlv { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 enable; + u8 cipher_id; + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_id; + u8 __rsv[3]; +} __packed; + struct bss_ra_tlv { __le16 tag; __le16 len; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index c62a42512bd6..0ba00e4166d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -584,9 +584,10 @@ int mt7996_init_debugfs(struct mt7996_phy *phy); void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len); bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len); int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd); +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key); int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); From 2c2f50bf6407e1fd43a1a257916aeaa5ffdacd6c Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Thu, 2 Nov 2023 18:03:02 +0800 Subject: [PATCH 3222/7721] wifi: mt76: connac: fix EHT phy mode check Add a BSS eht_support check before returning EHT phy mode. Without this patch, there might be an inconsistency where the softmac layer thinks the BSS is in HE mode, while the FW thinks it is in EHT mode. Signed-off-by: MeiChia Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ae6bf3c968df..b475555097ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1359,7 +1359,7 @@ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, sband = phy->hw->wiphy->bands[band]; eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); - if (!eht_cap || !eht_cap->has_eht) + if (!eht_cap || !eht_cap->has_eht || !vif->bss_conf.eht_support) return mode; switch (band) { From 3531c72aedb95261f4d78c47efa4b5ba7cdcddd9 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 6 Nov 2023 22:38:53 +0000 Subject: [PATCH 3223/7721] wifi: mt76: mt7915: fix EEPROM offset of TSSI flag on MT7981 The offset of the TSSI flag on the EEPROM of MT7981 devices was wrong. Set the correct offset instead. Fixes: 6bad146d162e ("wifi: mt76: mt7915: add support for MT7981") Signed-off-by: StanleyYP Wang Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index f3e56817d36e..adc26a222823 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -144,7 +144,8 @@ static inline bool mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) { u8 *eep = dev->mt76.eeprom.data; - u8 val = eep[MT_EE_WIFI_CONF + 7]; + u8 offs = is_mt7981(&dev->mt76) ? 8 : 7; + u8 val = eep[MT_EE_WIFI_CONF + offs]; if (band == NL80211_BAND_2GHZ) return val & MT_EE_WIFI_CONF7_TSSI0_2G; From ff434cc129d6907e6dbc89dd0ebc59fd3646d4c2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 6 Nov 2023 22:39:31 +0000 Subject: [PATCH 3224/7721] wifi: mt76: mt7915: also MT7981 is 3T3R but nss2 on 5 GHz band Just like MT7916 also MT7981 can handle 3T3R DBDC frontend and should hence be included in the corresponding conditional expression in the driver. Add it. Fixes: 6bad146d162e ("wifi: mt76: mt7915: add support for MT7981") Signed-off-by: StanleyYP Wang Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ba34c8e19aab..df2d4279790d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1059,8 +1059,9 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) phy->mt76->antenna_mask = tx_ant; - /* handle a variant of mt7916 which has 3T3R but nss2 on 5 GHz band */ - if (is_mt7916(&dev->mt76) && band && hweight8(tx_ant) == max_nss) + /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ + if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) && + band && hweight8(tx_ant) == max_nss) phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; else phy->mt76->chainmask = tx_ant << (chainshift * band); From 2ee1c40daeb9a33e25c460bf87feca58e91af879 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 10 Nov 2023 15:29:30 +0100 Subject: [PATCH 3225/7721] wifi: mt76: mt7996: fix mt7996_mcu_all_sta_info_event struct packing The internal struct and union inside mt7996_mcu_all_sta_info_event is marked as being aligned, which conflicts with it being unaligned within that structure: drivers/net/wireless/mediatek/mt76/mt7996/mcu.h:165:2: error: field within 'struct mt7996_mcu_all_sta_info_event' is less aligned than 'union mt7996_mcu_all_sta_info_event::(anonymous at ../drivers/net/wireless/mediatek/mt76/mt7996/mcu.h:165:2)' and is usually due to 'struct mt7996_mcu_all_sta_info_event' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] Mark all three as being packed as well to ensure byte packing for the entire thing. Fixes: adde3eed4a75 ("wifi: mt76: mt7996: Add mcu commands for getting sta tx statistic") Signed-off-by: Arnd Bergmann Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 10a1b09ff2fb..3e013b20ee5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -212,15 +212,15 @@ struct mt7996_mcu_all_sta_info_event { u8 rsv[2]; __le32 tx_bytes[IEEE80211_NUM_ACS]; __le32 rx_bytes[IEEE80211_NUM_ACS]; - } adm_stat[0]; + } adm_stat[0] __packed; struct { __le16 wlan_idx; u8 rsv[2]; __le32 tx_msdu_cnt; __le32 rx_msdu_cnt; - } msdu_cnt[0]; - }; + } msdu_cnt[0] __packed; + } __packed; } __packed; struct mt7996_mcu_wed_rro_event { From 1e1e563fe3bd2ad9252a98c24d55bb3f3a06990e Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 13 Nov 2023 15:06:12 +0800 Subject: [PATCH 3226/7721] wifi: mt76: mt7996: introduce mt7996_band_valid() Replace dbdc_support and tbtc_support with mt7996_band_valid() to support mt7996 variants with band0/band2 dual-band support. This changes reduces ambiguity when checking supported bands on different variants or new chipsets, as well as during the init configurations on DMA TX/RX queues or irq masks. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 14 ++++----- .../net/wireless/mediatek/mt76/mt7996/init.c | 29 ++++++++++--------- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 16 +++++----- .../wireless/mediatek/mt76/mt7996/mt7996.h | 16 ++++++++-- .../net/wireless/mediatek/mt76/mt7996/regs.h | 3 ++ 5 files changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 7ec6c64b3fd1..7c5801e1ebdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -233,13 +233,13 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) /* enable interrupts for TX/RX rings */ irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; - if (!dev->mphy.band_idx) + if (mt7996_band_valid(dev, MT_BAND0)) irq_mask |= MT_INT_BAND0_RX_DONE; - if (dev->dbdc_support) + if (mt7996_band_valid(dev, MT_BAND1)) irq_mask |= MT_INT_BAND1_RX_DONE; - if (dev->tbtc_support) + if (mt7996_band_valid(dev, MT_BAND2)) irq_mask |= MT_INT_BAND2_RX_DONE; if (mtk_wed_device_active(wed) && wed_reset) { @@ -382,7 +382,7 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1)) { /* rx msdu page queue for band1 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; @@ -396,7 +396,7 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) return ret; } - if (dev->tbtc_support) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx msdu page queue for band2 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; @@ -516,7 +516,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx data queue for band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], @@ -570,7 +570,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx rro data queue for band2 */ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 1896571ad140..64fa2f28c8c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -540,7 +540,8 @@ int mt7996_txbf_init(struct mt7996_dev *dev) { int ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1) || + mt7996_band_valid(dev, MT_BAND2)) { ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL); if (ret) return ret; @@ -563,11 +564,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, int ret; struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (band != MT_BAND1 && band != MT_BAND2) - return 0; - - if ((band == MT_BAND1 && !dev->dbdc_support) || - (band == MT_BAND2 && !dev->tbtc_support)) + if (!mt7996_band_valid(dev, band) || band == MT_BAND0) return 0; if (phy) @@ -897,9 +894,6 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) INIT_LIST_HEAD(&dev->wed_rro.poll_list); spin_lock_init(&dev->wed_rro.lock); - dev->dbdc_support = true; - dev->tbtc_support = true; - ret = mt7996_dma_init(dev); if (ret) return ret; @@ -1331,8 +1325,6 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; - ieee80211_queue_work(mt76_hw(dev), &dev->init_work); - ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); if (ret) return ret; @@ -1341,13 +1333,24 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + dev->recovery.hw_init_done = true; ret = mt7996_init_debugfs(&dev->phy); if (ret) - return ret; + goto error; - return mt7996_coredump_register(dev); + ret = mt7996_coredump_register(dev); + if (ret) + goto error; + + return 0; + +error: + cancel_work_sync(&dev->init_work); + + return ret; } void mt7996_unregister_device(struct mt7996_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index b5e27c29b1c4..be4beeb47a19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2964,9 +2964,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) { struct uni_header hdr = {}; struct sk_buff *skb; - int len, num; + int len, num, i; - num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support); + num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) @@ -2974,13 +2975,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) skb_put_data(skb, &hdr, sizeof(hdr)); - mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx); - - if (dev->dbdc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND1); - - if (dev->tbtc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND2); + for (i = 0; i < __MT_MAX_BAND; i++) { + if (mt7996_band_valid(dev, i)) + mt7996_add_rx_airtime_tlv(skb, i); + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(VOW), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0ba00e4166d9..aefd09c7d6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -280,8 +280,6 @@ struct mt7996_dev { u32 hw_pattern; - bool dbdc_support:1; - bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; bool has_rro:1; @@ -393,6 +391,17 @@ mt7996_phy3(struct mt7996_dev *dev) return __mt7996_phy(dev, MT_BAND2); } +static inline bool +mt7996_band_valid(struct mt7996_dev *dev, u8 band) +{ + /* tri-band support */ + if (band <= MT_BAND2 && + mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1) + return true; + + return band == MT_BAND0 || band == MT_BAND2; +} + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; @@ -494,7 +503,8 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support); + return MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 6102df912741..d8904cbc2856 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -629,6 +629,9 @@ enum base_rev { #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +#define MT_PAD_GPIO 0x700056f0 +#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15) + #define MT_HW_REV 0x70010204 #define MT_HW_REV1 0x8a00 From a63b75aac8468e7216930c698d5676259afb44fd Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:13 +0800 Subject: [PATCH 3227/7721] wifi: mt76: connac: add firmware support for mt7992 Support firmware download and enable related AFE PLL for mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Co-developed-by: Benjamin Lin Signed-off-by: Benjamin Lin Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: StanleyYP Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac.h | 5 +++++ .../wireless/mediatek/mt76/mt76_connac_mcu.c | 3 ++- .../net/wireless/mediatek/mt76/mt7996/init.c | 4 ++++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 22 +++++++++++++++---- .../wireless/mediatek/mt76/mt7996/mt7996.h | 5 +++++ .../net/wireless/mediatek/mt76/mt7996/pci.c | 4 ++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 7 ++++++ 7 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index e5ebde19af8f..fdde3d70b300 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -222,6 +222,11 @@ static inline bool is_mt7996(struct mt76_dev *dev) return mt76_chip(dev) == 0x7990; } +static inline bool is_mt7992(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7992; +} + static inline bool is_mt7622(struct mt76_dev *dev) { if (!IS_ENABLED(CONFIG_MT7622_WMAC)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index b475555097ff..96494ba2fdf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -67,7 +67,8 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_mt7921(dev) && addr == 0x900000) || (is_mt7925(dev) && addr == 0x900000) || - (is_mt7996(dev) && addr == 0x900000)) + (is_mt7996(dev) && addr == 0x900000) || + (is_mt7992(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); else cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 64fa2f28c8c2..2a7c367afae1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -888,6 +888,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + if (is_mt7992(&dev->mt76)) { + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + } INIT_WORK(&dev->init_work, mt7996_init_work); INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index be4beeb47a19..3c729b563edc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -10,6 +10,20 @@ #include "mac.h" #include "eeprom.h" +#define fw_name(_dev, name, ...) ({ \ + char *_fw; \ + switch (mt76_chip(&(_dev)->mt76)) { \ + case 0x7992: \ + _fw = MT7992_##name; \ + break; \ + case 0x7990: \ + default: \ + _fw = MT7996_##name; \ + break; \ + } \ + _fw; \ +}) + struct mt7996_patch_hdr { char build_date[16]; char platform[4]; @@ -2639,7 +2653,7 @@ static int mt7996_load_patch(struct mt7996_dev *dev) return -EAGAIN; } - ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev); + ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev); if (ret) goto out; @@ -2802,17 +2816,17 @@ static int mt7996_load_ram(struct mt7996_dev *dev) { int ret; - ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM, + ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM), MT7996_RAM_TYPE_WM); if (ret) return ret; - ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP, + ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP), MT7996_RAM_TYPE_DSP); if (ret) return ret; - return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA, + return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA), MT7996_RAM_TYPE_WA); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index aefd09c7d6e6..1a36ef50f6e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -33,6 +33,11 @@ #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin" +#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin" +#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin" +#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin" +#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 93ecc9a8dde0..baa5fb97a121 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -244,3 +244,7 @@ MODULE_FIRMWARE(MT7996_FIRMWARE_WA); MODULE_FIRMWARE(MT7996_FIRMWARE_WM); MODULE_FIRMWARE(MT7996_FIRMWARE_DSP); MODULE_FIRMWARE(MT7996_ROM_PATCH); +MODULE_FIRMWARE(MT7992_FIRMWARE_WA); +MODULE_FIRMWARE(MT7992_FIRMWARE_WM); +MODULE_FIRMWARE(MT7992_FIRMWARE_DSP); +MODULE_FIRMWARE(MT7992_ROM_PATCH); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index d8904cbc2856..aee577d90ddb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -683,4 +683,11 @@ enum base_rev { #define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200) #define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204) +/* CONN AFE CTL CON */ +#define MT_AFE_CTL_BASE 0x18043000 +#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \ + ((_band) * 0x1000) + (ofs)) +#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c) +#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1) + #endif From 9fe6690b8bef58848294bf5de9c6c31748e11941 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Mon, 13 Nov 2023 15:06:14 +0800 Subject: [PATCH 3228/7721] wifi: mt76: mt7996: add DMA support for mt7992 Add DMA TX/RX queues and RRO init flow for mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Benjamin Lin Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 58 +++++++++++++++---- .../net/wireless/mediatek/mt76/mt7996/init.c | 9 ++- .../wireless/mediatek/mt76/mt7996/mt7996.h | 7 ++- .../net/wireless/mediatek/mt76/mt7996/regs.h | 4 +- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 7c5801e1ebdb..0bc4681fc18a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -57,13 +57,19 @@ static void mt7996_dma_config(struct mt7996_dev *dev) RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA); - /* band0/band1 */ + /* mt7996: band0 and band1, mt7992: band0 */ RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN); - /* band2 */ - RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); - RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + if (is_mt7996(&dev->mt76)) { + /* mt7996 band2 */ + RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); + RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + } else { + /* mt7992 band1 */ + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + } if (dev->has_rro) { /* band0 */ @@ -90,8 +96,12 @@ static void mt7996_dma_config(struct mt7996_dev *dev) /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + if (is_mt7996(&dev->mt76)) { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + } else { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + } /* mcu tx queue */ MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); @@ -111,6 +121,7 @@ static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { u16 base = 0; + u8 queue; #define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ @@ -123,9 +134,14 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x2)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x10)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10)); if (dev->has_rro) { mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, @@ -488,7 +504,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* rx data queue for band0 and band1 */ + /* rx data queue for band0 and mt7996 band1 */ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; @@ -517,7 +533,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; if (mt7996_band_valid(dev, MT_BAND2)) { - /* rx data queue for band2 */ + /* rx data queue for mt7996 band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), @@ -527,7 +543,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* tx free notify event from WA for band2 + /* tx free notify event from WA for mt7996 band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { @@ -542,6 +558,26 @@ int mt7996_dma_init(struct mt7996_dev *dev) MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA)); if (ret) return ret; + } else if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx data queue for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], + MT_RXQ_ID(MT_RXQ_BAND1), + MT7996_RX_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + + /* tx free notify event from WA for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], + MT_RXQ_ID(MT_RXQ_BAND1_WA), + MT7996_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; } if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 2a7c367afae1..0cf0d1fe420a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -513,7 +513,12 @@ void mt7996_mac_init(struct mt7996_dev *dev) mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0); /* rro module init */ - mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + if (is_mt7996(&dev->mt76)) + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + else + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, + dev->hif2 ? 7 : 0); + if (dev->has_rro) { u16 timeout; @@ -570,7 +575,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (phy) return 0; - if (band == MT_BAND2 && dev->hif2) { + if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); wed = &dev->mt76.mmio.wed_hif2; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 1a36ef50f6e1..87822663870f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -104,10 +104,10 @@ enum mt7996_rxq_id { MT7996_RXQ_MCU_WM = 0, MT7996_RXQ_MCU_WA, MT7996_RXQ_MCU_WA_MAIN = 2, - MT7996_RXQ_MCU_WA_EXT = 2,/* unused */ + MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */ MT7996_RXQ_MCU_WA_TRI = 3, MT7996_RXQ_BAND0 = 4, - MT7996_RXQ_BAND1 = 4,/* unused */ + MT7996_RXQ_BAND1 = 5, /* for mt7992 */ MT7996_RXQ_BAND2 = 5, MT7996_RXQ_RRO_BAND0 = 8, MT7996_RXQ_RRO_BAND1 = 8,/* unused */ @@ -399,6 +399,9 @@ mt7996_phy3(struct mt7996_dev *dev) static inline bool mt7996_band_valid(struct mt7996_dev *dev, u8 band) { + if (is_mt7992(&dev->mt76)) + return band <= MT_BAND1; + /* tri-band support */ if (band <= MT_BAND2 && mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index aee577d90ddb..6623a6ba12d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -461,12 +461,12 @@ enum base_rev { #define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204) #define MT_INT_RX_DONE_BAND0 BIT(12) -#define MT_INT_RX_DONE_BAND1 BIT(12) +#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */ #define MT_INT_RX_DONE_BAND2 BIT(13) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) #define MT_INT_RX_DONE_WA_MAIN BIT(2) -#define MT_INT_RX_DONE_WA_EXT BIT(2) +#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */ #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) From 50fbebf6a151bc70c43ffab1f884aa510d548d7e Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:15 +0800 Subject: [PATCH 3229/7721] wifi: mt76: mt7996: rework register offsets for mt7992 Add mt7992_offs to differentiate registers that share the same definitions with mt7996 chipsets but have differnet offsets. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 59 ++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 76 +++++++++++++------ 2 files changed, 112 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 739d7f53d347..b1119f62c946 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -30,6 +30,58 @@ static const struct __base mt7996_reg_base[] = { [WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } }, }; +static const u32 mt7996_offs[] = { + [MIB_RVSR0] = 0x720, + [MIB_RVSR1] = 0x724, + [MIB_BTSCR5] = 0x788, + [MIB_BTSCR6] = 0x798, + [MIB_RSCR1] = 0x7ac, + [MIB_RSCR27] = 0x954, + [MIB_RSCR28] = 0x958, + [MIB_RSCR29] = 0x95c, + [MIB_RSCR30] = 0x960, + [MIB_RSCR31] = 0x964, + [MIB_RSCR33] = 0x96c, + [MIB_RSCR35] = 0x974, + [MIB_RSCR36] = 0x978, + [MIB_BSCR0] = 0x9cc, + [MIB_BSCR1] = 0x9d0, + [MIB_BSCR2] = 0x9d4, + [MIB_BSCR3] = 0x9d8, + [MIB_BSCR4] = 0x9dc, + [MIB_BSCR5] = 0x9e0, + [MIB_BSCR6] = 0x9e4, + [MIB_BSCR7] = 0x9e8, + [MIB_BSCR17] = 0xa10, + [MIB_TRDR1] = 0xa28, +}; + +static const u32 mt7992_offs[] = { + [MIB_RVSR0] = 0x760, + [MIB_RVSR1] = 0x764, + [MIB_BTSCR5] = 0x7c8, + [MIB_BTSCR6] = 0x7d8, + [MIB_RSCR1] = 0x7f0, + [MIB_RSCR27] = 0x998, + [MIB_RSCR28] = 0x99c, + [MIB_RSCR29] = 0x9a0, + [MIB_RSCR30] = 0x9a4, + [MIB_RSCR31] = 0x9a8, + [MIB_RSCR33] = 0x9b0, + [MIB_RSCR35] = 0x9b8, + [MIB_RSCR36] = 0x9bc, + [MIB_BSCR0] = 0xac8, + [MIB_BSCR1] = 0xacc, + [MIB_BSCR2] = 0xad0, + [MIB_BSCR3] = 0xad4, + [MIB_BSCR4] = 0xad8, + [MIB_BSCR5] = 0xadc, + [MIB_BSCR6] = 0xae0, + [MIB_BSCR7] = 0xae4, + [MIB_BSCR17] = 0xb0c, + [MIB_TRDR1] = 0xb24, +}; + static const struct __map mt7996_reg_map[] = { { 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ @@ -382,6 +434,13 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, switch (device_id) { case 0x7990: dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7996_offs; + dev->reg.map = mt7996_reg_map; + dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); + break; + case 0x7992: + dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7992_offs; dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 6623a6ba12d6..21637e3aae42 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -19,6 +19,7 @@ struct __base { /* used to differentiate between generations */ struct mt7996_reg_desc { const struct __base *base; + const u32 *offs_rev; const struct __map *map; u32 map_size; }; @@ -39,6 +40,35 @@ enum base_rev { #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +enum offs_rev { + MIB_RVSR0, + MIB_RVSR1, + MIB_BTSCR5, + MIB_BTSCR6, + MIB_RSCR1, + MIB_RSCR27, + MIB_RSCR28, + MIB_RSCR29, + MIB_RSCR30, + MIB_RSCR31, + MIB_RSCR33, + MIB_RSCR35, + MIB_RSCR36, + MIB_BSCR0, + MIB_BSCR1, + MIB_BSCR2, + MIB_BSCR3, + MIB_BSCR4, + MIB_BSCR5, + MIB_BSCR6, + MIB_BSCR7, + MIB_BSCR17, + MIB_TRDR1, + __MT_OFFS_MAX, +}; + +#define __OFFS(id) (dev->reg.offs_rev[(id)]) + /* RRO TOP */ #define MT_RRO_TOP_BASE 0xA000 #define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) @@ -178,32 +208,32 @@ enum base_rev { #define MT_WF_MIB_BASE(_band) __BASE(WF_MIB_BASE, (_band)) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) -#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc) -#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0) -#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4) -#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8) -#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc) -#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0) -#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4) -#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8) -#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10) +#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0)) +#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1)) +#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2)) +#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3)) +#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4)) +#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5)) +#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6)) +#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7)) +#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17)) #define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4) #define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8) #define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0) -#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac) +#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1)) /* rx mpdu counter, full 32 bits */ -#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964) -#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c) +#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31)) +#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33)) #define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020) #define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0) -#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720) +#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0)) -#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974) -#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978) +#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35)) +#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36)) /* tx ampdu cnt, full 32 bits */ #define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0) @@ -216,16 +246,16 @@ enum base_rev { #define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0) /* rx ampdu count, 32-bit */ -#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954) +#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27)) /* rx ampdu bytes count, 32-bit */ -#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958) +#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28)) /* rx ampdu valid subframe count */ -#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c) +#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29)) /* rx ampdu valid subframe bytes count, 32bits */ -#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960) +#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30)) /* remaining windows protected stats */ #define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080) @@ -234,18 +264,18 @@ enum base_rev { #define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084) #define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0) -#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724) +#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1)) /* rx blockack count, 32 bits */ #define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4) #define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0) -#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788) -#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798) +#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5)) +#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6)) #define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0) -#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0)) From 2cbbefdc5c9ccf5911b41dca43d2d1533c160f4e Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:16 +0800 Subject: [PATCH 3230/7721] wifi: mt76: mt7996: support mt7992 eeprom loading Add the default eeprom and 0x7992 check to mt7996_check_eeprom(). This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 14 +++++++++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 9db7e531076d..f876bb1f3ba4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -14,7 +14,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) switch (val) { case 0x7990: - return 0; + return is_mt7996(&dev->mt76) ? 0 : -EINVAL; + case 0x7992: + return is_mt7992(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; } @@ -22,8 +24,14 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) static char *mt7996_eeprom_name(struct mt7996_dev *dev) { - /* reserve for future variants */ - return MT7996_EEPROM_DEFAULT; + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + return MT7996_EEPROM_DEFAULT; + case 0x7992: + return MT7992_EEPROM_DEFAULT; + default: + return MT7996_EEPROM_DEFAULT; + } } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 87822663870f..5cdde28ce83f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -39,6 +39,7 @@ #define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" +#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 From 8df63a4bbe3d89ad24e07f952ccaa8702af937f2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:17 +0800 Subject: [PATCH 3231/7721] wifi: mt76: mt7996: adjust interface num and wtbl size for mt7992 MT7992 chipsets support up to 32 interfaces (with maximum 19 per-band) and 512 station entries. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index f876bb1f3ba4..4a8237118287 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -111,7 +111,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP); } - if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4) + if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 || + is_mt7992(&dev->mt76)) dev->wtbl_size_group = 2; /* set default */ return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 5cdde28ce83f..bc73bcb47bf0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -13,6 +13,7 @@ #define MT7996_MAX_INTERFACES 19 /* per-band */ #define MT7996_MAX_WMM_SETS 4 +#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64) #define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1) #define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \ mt7996_max_interface_num(dev)) @@ -512,13 +513,14 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + - mt7996_band_valid(dev, MT_BAND2)); + return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)), + MT7996_WTBL_BMC_SIZE); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) { - return (dev->wtbl_size_group << 8) + 64; + return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE; } void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, From 408566db8cad2788356ccd75e946c236ba381bc2 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Mon, 13 Nov 2023 15:06:18 +0800 Subject: [PATCH 3232/7721] wifi: mt76: connac: add new definition of tx descriptor Add MT_TXD6_MSDU_CNT_V2 bitfield, which is used by mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h | 1 + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 36edf1d3dfca..ecd7889209f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -245,6 +245,7 @@ enum tx_mgnt_type { #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) +#define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) #define MT_TXD6_DAS BIT(2) #define MT_TXD6_AMSDU_CAP BIT(1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 1cc573551bdf..ccdec1cc9b2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -873,8 +873,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD5_TX_STATUS_HOST; txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | - FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + val = MT_TXD6_DIS_MAT | MT_TXD6_DAS; + if (is_mt7996(&dev->mt76)) + val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + else + val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1); txwi[6] = cpu_to_le32(val); txwi[7] = 0; From 3d3f117a259a65353bf2714a18e25731b3ca5770 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:19 +0800 Subject: [PATCH 3233/7721] wifi: mt76: mt7996: add PCI IDs for mt7992 Add PCI device IDs to enable mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index baa5fb97a121..a35939cbf3bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -17,11 +17,13 @@ static u32 hif_idx; static const struct pci_device_id mt7996_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7992) }, { }, }; static const struct pci_device_id mt7996_hif_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) }, { }, }; @@ -60,7 +62,9 @@ static void mt7996_put_hif2(struct mt7996_hif *hif) static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL)) + + if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) return NULL; writel(hif_idx | MT_PCIE_RECOG_ID_SEM, @@ -113,7 +117,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt76_pci_disable_aspm(pdev); - if (id->device == 0x7991) + if (id->device == 0x7991 || id->device == 0x799a) return mt7996_pci_hif2_probe(pdev); dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], From 170a8969db8877252e6b6cd6e821a0ddde4b9152 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Nov 2023 11:16:19 +0100 Subject: [PATCH 3234/7721] wifi: mt76: mt7925: remove iftype from mt7925_init_eht_caps signature Get rid of nl80211_iftype from mt7925_init_eht_caps routine signature since it is not actually used. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 15c2fb0bcb1b..a080df58120f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -154,8 +154,7 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, static void mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, - struct ieee80211_sband_iftype_data *data, - enum nl80211_iftype iftype) + struct ieee80211_sband_iftype_data *data) { struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; @@ -256,7 +255,7 @@ __mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy, data[n].types_mask = BIT(i); mt7925_init_he_caps(phy, band, &data[n], i); - mt7925_init_eht_caps(phy, band, &data[n], i); + mt7925_init_eht_caps(phy, band, &data[n]); n++; } From d079746455700ca1eacc25a4aac0d6323c8130c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:31:03 +0100 Subject: [PATCH 3235/7721] wifi: mt76: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert the three mt76 drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/soc.c | 7 ++----- drivers/net/wireless/mediatek/mt76/mt7615/soc.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt7915/soc.c | 6 ++---- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index ba927033bbe8..ec02148a7f1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -52,15 +52,12 @@ mt76_wmac_probe(struct platform_device *pdev) return ret; } -static int -mt76_wmac_remove(struct platform_device *pdev) +static void mt76_wmac_remove(struct platform_device *pdev) { struct mt76_dev *mdev = platform_get_drvdata(pdev); struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); mt7603_unregister_device(dev); - - return 0; } static const struct of_device_id of_wmac_match[] = { @@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, - .remove = mt76_wmac_remove, + .remove_new = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index f13d1b418742..12e3e4a91d27 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct platform_device *pdev) return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); } -static int mt7622_wmac_remove(struct platform_device *pdev) +static void mt7622_wmac_remove(struct platform_device *pdev) { struct mt7615_dev *dev = platform_get_drvdata(pdev); mt7615_unregister_device(dev); - - return 0; } static const struct of_device_id mt7622_wmac_of_match[] = { @@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = { .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, - .remove = mt7622_wmac_remove, + .remove_new = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 06e3d9db996c..8b4809703efc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1282,13 +1282,11 @@ static int mt798x_wmac_probe(struct platform_device *pdev) return ret; } -static int mt798x_wmac_remove(struct platform_device *pdev) +static void mt798x_wmac_remove(struct platform_device *pdev) { struct mt7915_dev *dev = platform_get_drvdata(pdev); mt7915_unregister_device(dev); - - return 0; } static const struct of_device_id mt798x_wmac_of_match[] = { @@ -1305,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = { .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, - .remove = mt798x_wmac_remove, + .remove_new = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); From 92184eae1d5ad804884e2c6e289d885b9e3194d1 Mon Sep 17 00:00:00 2001 From: Wang Zhao Date: Fri, 17 Nov 2023 20:54:49 +0800 Subject: [PATCH 3236/7721] wifi: mt76: mt7921s: fix workqueue problem causes STA association fail The ieee80211_queue_work function queues work into the mac80211 local->workqueue, which is widely used for mac80211 internal work processes. In the mt76 driver, both the mt76-sido-status and mt76-sdio-net threads enqueue workers to the workqueue with this function. However, in some cases, when two workers are enqueued to the workqueue almost simultaneously, the second worker may not be scheduled immediately and may get stuck for a while. This can cause timing issues. To avoid these timing conflicts caused by worker scheduling, replace the worker with an independent thread. Fixes: 48fab5bbef40 ("mt76: mt7921: introduce mt7921s support") Signed-off-by: Wang Zhao Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 +-- .../net/wireless/mediatek/mt76/mt7615/sdio.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/sdio.c | 4 +++- .../wireless/mediatek/mt76/mt7921/sdio_mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/sdio.c | 18 +++++++++++------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b1d3f55d7034..d66864afaf38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -609,8 +609,7 @@ struct mt76_sdio { struct mt76_worker txrx_worker; struct mt76_worker status_worker; struct mt76_worker net_worker; - - struct work_struct stat_work; + struct mt76_worker stat_worker; u8 *xmit_buf; u32 xmit_buf_sz; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index fc547a0031ea..67cedd2555f9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -204,8 +204,8 @@ static int mt7663s_suspend(struct device *dev) mt76_worker_disable(&mdev->mt76.sdio.txrx_worker); mt76_worker_disable(&mdev->mt76.sdio.status_worker); mt76_worker_disable(&mdev->mt76.sdio.net_worker); + mt76_worker_disable(&mdev->mt76.sdio.stat_worker); - cancel_work_sync(&mdev->mt76.sdio.stat_work); clear_bit(MT76_READING_STATS, &mdev->mphy.state); mt76_tx_status_check(&mdev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index dc1beb76df3e..7591e54d2897 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -228,7 +228,7 @@ static int mt7921s_suspend(struct device *__dev) mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&mdev->tx_worker); mt76_worker_disable(&mdev->sdio.status_worker); - cancel_work_sync(&mdev->sdio.stat_work); + mt76_worker_disable(&mdev->sdio.stat_worker); clear_bit(MT76_READING_STATS, &dev->mphy.state); mt76_tx_status_check(mdev, true); @@ -260,6 +260,7 @@ static int mt7921s_suspend(struct device *__dev) restore_worker: mt76_worker_enable(&mdev->tx_worker); mt76_worker_enable(&mdev->sdio.status_worker); + mt76_worker_enable(&mdev->sdio.stat_worker); if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(mdev, false); @@ -292,6 +293,7 @@ static int mt7921s_resume(struct device *__dev) mt76_worker_enable(&mdev->sdio.txrx_worker); mt76_worker_enable(&mdev->sdio.status_worker); mt76_worker_enable(&mdev->sdio.net_worker); + mt76_worker_enable(&mdev->sdio.stat_worker); /* restore previous ds setting */ if (!pm->ds_enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c index 8edd0291c128..389eb0903807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -107,7 +107,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev) mt76_worker_disable(&dev->mt76.sdio.txrx_worker); mt76_worker_disable(&dev->mt76.sdio.status_worker); mt76_worker_disable(&dev->mt76.sdio.net_worker); - cancel_work_sync(&dev->mt76.sdio.stat_work); + mt76_worker_disable(&dev->mt76.sdio.stat_worker); mt7921s_disable_irq(&dev->mt76); mt7921s_wfsys_reset(dev); @@ -115,6 +115,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev) mt76_worker_enable(&dev->mt76.sdio.txrx_worker); mt76_worker_enable(&dev->mt76.sdio.status_worker); mt76_worker_enable(&dev->mt76.sdio.net_worker); + mt76_worker_enable(&dev->mt76.sdio.stat_worker); dev->fw_assert = false; clear_bit(MT76_MCU_RESET, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 419723118ded..c52d550f0c32 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -481,21 +481,21 @@ static void mt76s_status_worker(struct mt76_worker *w) if (dev->drv->tx_status_data && ndata_frames > 0 && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state) && !test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &dev->sdio.stat_work); + mt76_worker_schedule(&sdio->stat_worker); } while (nframes > 0); if (resched) mt76_worker_schedule(&dev->tx_worker); } -static void mt76s_tx_status_data(struct work_struct *work) +static void mt76s_tx_status_data(struct mt76_worker *worker) { struct mt76_sdio *sdio; struct mt76_dev *dev; u8 update = 1; u16 count = 0; - sdio = container_of(work, struct mt76_sdio, stat_work); + sdio = container_of(worker, struct mt76_sdio, stat_worker); dev = container_of(sdio, struct mt76_dev, sdio); while (true) { @@ -508,7 +508,7 @@ static void mt76s_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &sdio->stat_work); + mt76_worker_schedule(&sdio->status_worker); else clear_bit(MT76_READING_STATS, &dev->phy.state); } @@ -600,8 +600,8 @@ void mt76s_deinit(struct mt76_dev *dev) mt76_worker_teardown(&sdio->txrx_worker); mt76_worker_teardown(&sdio->status_worker); mt76_worker_teardown(&sdio->net_worker); + mt76_worker_teardown(&sdio->stat_worker); - cancel_work_sync(&sdio->stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); mt76_tx_status_check(dev, true); @@ -644,10 +644,14 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, if (err) return err; + err = mt76_worker_setup(dev->hw, &sdio->stat_worker, mt76s_tx_status_data, + "sdio-sta"); + if (err) + return err; + sched_set_fifo_low(sdio->status_worker.task); sched_set_fifo_low(sdio->net_worker.task); - - INIT_WORK(&sdio->stat_work, mt76s_tx_status_data); + sched_set_fifo_low(sdio->stat_worker.task); dev->queue_ops = &sdio_queue_ops; dev->bus = bus_ops; From 26f4bac3d884e340fd8b061dcfc64688a8c416e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 7 Dec 2023 10:25:00 -0600 Subject: [PATCH 3237/7721] drm/bridge: aux-hpd: Replace of_device.h with explicit include The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. Soon the implicit includes are going to be removed. of_device.h isn't needed, but of.h is for of_node_put(). Reported-by: Stephen Rothwell Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20231207162501.2629952-1-robh@kernel.org Signed-off-by: Rob Herring --- drivers/gpu/drm/bridge/aux-hpd-bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c index 5d2ab3a715f9..1999a053d59b 100644 --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -6,7 +6,7 @@ */ #include #include -#include +#include #include #include From 87e839c82cc36346a2cd183ca941316902110716 Mon Sep 17 00:00:00 2001 From: duanqiangwen Date: Wed, 6 Dec 2023 17:50:44 +0800 Subject: [PATCH 3238/7721] net: wangxun: fix changing mac failed when running in some bonding mode, service need to change mac when netif is running. Wangxun netdev add IFF_LIVE_ADDR_CHANGE priv_flag to support it. Signed-off-by: duanqiangwen Link: https://lore.kernel.org/r/20231206095044.17844-1-duanqiangwen@net-swift.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index 8db804543e66..a5c623fd023e 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -582,6 +582,7 @@ static int ngbe_probe(struct pci_dev *pdev, netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE - diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 526250102db2..a78da2309db5 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -638,6 +638,7 @@ static int txgbe_probe(struct pci_dev *pdev, netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE - From 67a5f0ff342907ca399b77f0445b2673137cdfa5 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 7 Dec 2023 16:17:35 +0800 Subject: [PATCH 3239/7721] drm/edp-panel: Move the KDC panel to a separate group Move the KDC panel entry to make the list sorted by the vendor string. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231207081801.4049075-2-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index c76f186c4baa..a0b6f69b916f 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1980,9 +1980,10 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), - EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), From 04c521c3bec1fa0ccb97a1fbf74f0faeda3f4a53 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Sat, 2 Dec 2023 19:22:01 +0100 Subject: [PATCH 3240/7721] ARM: dts: rockchip: add gpio alias for gpio dt nodes Rockchip SoC TRM, SoC datasheet and board schematics always refer to the same gpio numbers - even if not all are used for a specific board. In order to not have to re-define them for every board add the aliases to SoC dtsi files. Co-developed-by: Jianqun Xu Signed-off-by: Jianqun Xu Signed-off-by: Johan Jonker Reviewed-by: Dragan Simic Link: https://lore.kernel.org/r/89f2a229-9f14-d43f-c53d-5d4688e70456@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3036.dtsi | 3 +++ arch/arm/boot/dts/rockchip/rk3066a.dtsi | 5 +++++ arch/arm/boot/dts/rockchip/rk322x.dtsi | 4 ++++ arch/arm/boot/dts/rockchip/rk3288.dtsi | 9 +++++++++ arch/arm/boot/dts/rockchip/rk3xxx.dtsi | 4 ++++ 5 files changed, 25 insertions(+) diff --git a/arch/arm/boot/dts/rockchip/rk3036.dtsi b/arch/arm/boot/dts/rockchip/rk3036.dtsi index 78686fc72ce6..8aa2e0864fed 100644 --- a/arch/arm/boot/dts/rockchip/rk3036.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3036.dtsi @@ -17,6 +17,9 @@ / { interrupt-parent = <&gic>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm/boot/dts/rockchip/rk3066a.dtsi b/arch/arm/boot/dts/rockchip/rk3066a.dtsi index de9915d946f7..30139f21de64 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3066a.dtsi @@ -13,6 +13,11 @@ / { compatible = "rockchip,rk3066a"; + aliases { + gpio4 = &gpio4; + gpio6 = &gpio6; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/rockchip/rk322x.dtsi b/arch/arm/boot/dts/rockchip/rk322x.dtsi index ffc16d6b97e1..a814e813a5da 100644 --- a/arch/arm/boot/dts/rockchip/rk322x.dtsi +++ b/arch/arm/boot/dts/rockchip/rk322x.dtsi @@ -15,6 +15,10 @@ / { interrupt-parent = <&gic>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; diff --git a/arch/arm/boot/dts/rockchip/rk3288.dtsi b/arch/arm/boot/dts/rockchip/rk3288.dtsi index cb9cdaddffd4..ead343dc3df1 100644 --- a/arch/arm/boot/dts/rockchip/rk3288.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288.dtsi @@ -19,6 +19,15 @@ / { aliases { ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + gpio5 = &gpio5; + gpio6 = &gpio6; + gpio7 = &gpio7; + gpio8 = &gpio8; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm/boot/dts/rockchip/rk3xxx.dtsi b/arch/arm/boot/dts/rockchip/rk3xxx.dtsi index cb4e42ede56a..f37137f298d5 100644 --- a/arch/arm/boot/dts/rockchip/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3xxx.dtsi @@ -16,6 +16,10 @@ / { aliases { ethernet0 = &emac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; From 1b151e2435fc3a9b10c8946c6aebe9f3e1938c55 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Mon, 14 Aug 2023 15:41:00 +0100 Subject: [PATCH 3241/7721] block: Remove special-casing of compound pages The special casing was originally added in pre-git history; reproducing the commit log here: > commit a318a92567d77 > Author: Andrew Morton > Date: Sun Sep 21 01:42:22 2003 -0700 > > [PATCH] Speed up direct-io hugetlbpage handling > > This patch short-circuits all the direct-io page dirtying logic for > higher-order pages. Without this, we pointlessly bounce BIOs up to > keventd all the time. In the last twenty years, compound pages have become used for more than just hugetlb. Rewrite these functions to operate on folios instead of pages and remove the special case for hugetlbfs; I don't think it's needed any more (and if it is, we can put it back in as a call to folio_test_hugetlb()). This was found by inspection; as far as I can tell, this bug can lead to pages used as the destination of a direct I/O read not being marked as dirty. If those pages are then reclaimed by the MM without being dirtied for some other reason, they won't be written out. Then when they're faulted back in, they will not contain the data they should. It'll take a pretty unusual setup to produce this problem with several races all going the wrong way. This problem predates the folio work; it could for example have been triggered by mmaping a THP in tmpfs and using that as the target of an O_DIRECT read. Fixes: 800d8c63b2e98 ("shmem: add huge pages support") Cc: Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jens Axboe --- block/bio.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/block/bio.c b/block/bio.c index 816d412c06e9..5eba53ca953b 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1145,13 +1145,22 @@ EXPORT_SYMBOL(bio_add_folio); void __bio_release_pages(struct bio *bio, bool mark_dirty) { - struct bvec_iter_all iter_all; - struct bio_vec *bvec; + struct folio_iter fi; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (mark_dirty && !PageCompound(bvec->bv_page)) - set_page_dirty_lock(bvec->bv_page); - bio_release_page(bio, bvec->bv_page); + bio_for_each_folio_all(fi, bio) { + struct page *page; + size_t done = 0; + + if (mark_dirty) { + folio_lock(fi.folio); + folio_mark_dirty(fi.folio); + folio_unlock(fi.folio); + } + page = folio_page(fi.folio, fi.offset / PAGE_SIZE); + do { + bio_release_page(bio, page++); + done += PAGE_SIZE; + } while (done < fi.length); } } EXPORT_SYMBOL_GPL(__bio_release_pages); @@ -1439,18 +1448,12 @@ EXPORT_SYMBOL(bio_free_pages); * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions * for performing direct-IO in BIOs. * - * The problem is that we cannot run set_page_dirty() from interrupt context + * The problem is that we cannot run folio_mark_dirty() from interrupt context * because the required locks are not interrupt-safe. So what we can do is to * mark the pages dirty _before_ performing IO. And in interrupt context, * check that the pages are still dirty. If so, fine. If not, redirty them * in process context. * - * We special-case compound pages here: normally this means reads into hugetlb - * pages. The logic in here doesn't really work right for compound pages - * because the VM does not uniformly chase down the head page in all cases. - * But dirtiness of compound pages is pretty meaningless anyway: the VM doesn't - * handle them at all. So we skip compound pages here at an early stage. - * * Note that this code is very hard to test under normal circumstances because * direct-io pins the pages with get_user_pages(). This makes * is_page_cache_freeable return false, and the VM will not clean the pages. @@ -1466,12 +1469,12 @@ EXPORT_SYMBOL(bio_free_pages); */ void bio_set_pages_dirty(struct bio *bio) { - struct bio_vec *bvec; - struct bvec_iter_all iter_all; + struct folio_iter fi; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (!PageCompound(bvec->bv_page)) - set_page_dirty_lock(bvec->bv_page); + bio_for_each_folio_all(fi, bio) { + folio_lock(fi.folio); + folio_mark_dirty(fi.folio); + folio_unlock(fi.folio); } } EXPORT_SYMBOL_GPL(bio_set_pages_dirty); @@ -1515,12 +1518,11 @@ static void bio_dirty_fn(struct work_struct *work) void bio_check_pages_dirty(struct bio *bio) { - struct bio_vec *bvec; + struct folio_iter fi; unsigned long flags; - struct bvec_iter_all iter_all; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (!PageDirty(bvec->bv_page) && !PageCompound(bvec->bv_page)) + bio_for_each_folio_all(fi, bio) { + if (!folio_test_dirty(fi.folio)) goto defer; } From 83a368a3fc8ae8538bccb713dc0cae9eacc04790 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 3 Dec 2023 18:46:22 +0100 Subject: [PATCH 3242/7721] docs: dt-bindings: add DTS Coding Style document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document preferred coding style for Devicetree sources (DTS and DTSI), to bring consistency among all (sub)architectures and ease in reviews. Cc: Andrew Davis cc: Andrew Lunn Cc: AngeloGioacchino Del Regno Cc: Arnd Bergmann Cc: Bjorn Andersson Cc: Chen-Yu Tsai Cc: Dmitry Baryshkov Cc: Jonathan Corbet Cc: Matthias Brugger Cc: Michal Simek Cc: Neil Armstrong Cc: Nishanth Menon Cc: Olof Johansson Cc: Rafał Miłecki Acked-by: Neil Armstrong Acked-by: Heiko Stuebner Reviewed-by: Laurent Pinchart Acked-by: Konrad Dybcio Reviewed-by: Geert Uytterhoeven Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Reviewed-by: Francesco Dolcini Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20231203174622.18402-1-krzysztof.kozlowski@linaro.org [robh: quote property names in order of properties section] Signed-off-by: Rob Herring --- .../devicetree/bindings/dts-coding-style.rst | 196 ++++++++++++++++++ Documentation/devicetree/bindings/index.rst | 1 + 2 files changed, 197 insertions(+) create mode 100644 Documentation/devicetree/bindings/dts-coding-style.rst diff --git a/Documentation/devicetree/bindings/dts-coding-style.rst b/Documentation/devicetree/bindings/dts-coding-style.rst new file mode 100644 index 000000000000..a9bdd2b59dca --- /dev/null +++ b/Documentation/devicetree/bindings/dts-coding-style.rst @@ -0,0 +1,196 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================== +Devicetree Sources (DTS) Coding Style +===================================== + +When writing Devicetree Sources (DTS) please observe below guidelines. They +should be considered complementary to any rules expressed already in +the Devicetree Specification and the dtc compiler (including W=1 and W=2 +builds). + +Individual architectures and subarchitectures can define additional rules, +making the coding style stricter. + +Naming and Valid Characters +--------------------------- + +The Devicetree Specification allows a broad range of characters in node +and property names, but this coding style narrows the range down to achieve +better code readability. + +1. Node and property names can use only the following characters: + + * Lowercase characters: [a-z] + * Digits: [0-9] + * Dash: - + +2. Labels can use only the following characters: + + * Lowercase characters: [a-z] + * Digits: [0-9] + * Underscore: _ + +3. Unless a bus defines differently, unit addresses shall use lowercase + hexadecimal digits, without leading zeros (padding). + +4. Hex values in properties, e.g. "reg", shall use lowercase hex. The address + part can be padded with leading zeros. + +Example:: + + gpi_dma2: dma-controller@a00000 { + compatible = "qcom,sm8550-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00a00000 0x0 0x60000>; + } + +Order of Nodes +-------------- + +1. Nodes on any bus, thus using unit addresses for children, shall be + ordered by unit address in ascending order. + Alternatively for some subarchitectures, nodes of the same type can be + grouped together, e.g. all I2C controllers one after another even if this + breaks unit address ordering. + +2. Nodes without unit addresses shall be ordered alpha-numerically by the node + name. For a few node types, they can be ordered by the main property, e.g. + pin configuration states ordered by value of "pins" property. + +3. When extending nodes in the board DTS via &label, the entries shall be + ordered either alpha-numerically or by keeping the order from DTSI, where + the choice depends on the subarchitecture. + +The above-described ordering rules are easy to enforce during review, reduce +chances of conflicts for simultaneous additions of new nodes to a file and help +in navigating through the DTS source. + +Example:: + + /* SoC DTSI */ + + / { + cpus { + /* ... */ + }; + + psci { + /* ... */ + }; + + soc@0 { + dma: dma-controller@10000 { + /* ... */ + }; + + clk: clock-controller@80000 { + /* ... */ + }; + }; + }; + + /* Board DTS - alphabetical order */ + + &clk { + /* ... */ + }; + + &dma { + /* ... */ + }; + + /* Board DTS - alternative order, keep as DTSI */ + + &dma { + /* ... */ + }; + + &clk { + /* ... */ + }; + +Order of Properties in Device Node +---------------------------------- + +The following order of properties in device nodes is preferred: + +1. "compatible" +2. "reg" +3. "ranges" +4. Standard/common properties (defined by common bindings, e.g. without + vendor-prefixes) +5. Vendor-specific properties +6. "status" (if applicable) +7. Child nodes, where each node is preceded with a blank line + +The "status" property is by default "okay", thus it can be omitted. + +The above-described ordering follows this approach: + +1. Most important properties start the node: compatible then bus addressing to + match unit address. +2. Each node will have common properties in similar place. +3. Status is the last information to annotate that device node is or is not + finished (board resources are needed). + +Example:: + + /* SoC DTSI */ + + device_node: device-class@6789abc { + compatible = "vendor,device"; + reg = <0x0 0x06789abc 0x0 0xa123>; + ranges = <0x0 0x0 0x06789abc 0x1000>; + #dma-cells = <1>; + clocks = <&clock_controller 0>, <&clock_controller 1>; + clock-names = "bus", "host"; + vendor,custom-property = <2>; + status = "disabled"; + + child_node: child-class@100 { + reg = <0x100 0x200>; + /* ... */ + }; + }; + + /* Board DTS */ + + &device_node { + vdd-supply = <&board_vreg1>; + status = "okay"; + } + +Indentation +----------- + +1. Use indentation according to Documentation/process/coding-style.rst. +2. Each entry in arrays with multiple cells, e.g. "reg" with two IO addresses, + shall be enclosed in <>. +3. For arrays spanning across lines, it is preferred to align the continued + entries with opening < from the first line. + +Example:: + + thermal-sensor@c271000 { + compatible = "qcom,sm8550-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c271000 0x0 0x1000>, + <0x0 0x0c222000 0x0 0x1000>; + }; + +Organizing DTSI and DTS +----------------------- + +The DTSI and DTS files shall be organized in a way representing the common, +reusable parts of hardware. Typically, this means organizing DTSI and DTS files +into several files: + +1. DTSI with contents of the entire SoC, without nodes for hardware not present + on the SoC. +2. If applicable: DTSI with common or re-usable parts of the hardware, e.g. + entire System-on-Module. +3. DTS representing the board. + +Hardware components that are present on the board shall be placed in the +board DTS, not in the SoC or SoM DTSI. A partial exception is a common +external reference SoC input clock, which could be coded as a fixed-clock in +the SoC DTSI with its frequency provided by each board DTS. diff --git a/Documentation/devicetree/bindings/index.rst b/Documentation/devicetree/bindings/index.rst index d9002a3a0abb..cc1fbdc05657 100644 --- a/Documentation/devicetree/bindings/index.rst +++ b/Documentation/devicetree/bindings/index.rst @@ -4,6 +4,7 @@ :maxdepth: 1 ABI + dts-coding-style writing-bindings writing-schema submitting-patches From a833a17aeac73b33f79433d7cee68d5cafd71e4f Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Wed, 6 Dec 2023 23:11:48 -0500 Subject: [PATCH 3243/7721] bpf: Fix verification of indirect var-off stack access This patch fixes a bug around the verification of possibly-zero-sized stack accesses. When the access was done through a var-offset stack pointer, check_stack_access_within_bounds was incorrectly computing the maximum-offset of a zero-sized read to be the same as the register's min offset. Instead, we have to take in account the register's maximum possible value. The patch also simplifies how the max offset is checked; the check is now simpler than for min offset. The bug was allowing accesses to erroneously pass the check_stack_access_within_bounds() checks, only to later crash in check_stack_range_initialized() when all the possibly-affected stack slots are iterated (this time with a correct max offset). check_stack_range_initialized() is relying on check_stack_access_within_bounds() for its accesses to the stack-tracking vector to be within bounds; in the case of zero-sized accesses, we were essentially only verifying that the lowest possible slot was within bounds. We would crash when the max-offset of the stack pointer was >= 0 (which shouldn't pass verification, and hopefully is not something anyone's code attempts to do in practice). Thanks Hao for reporting! Fixes: 01f810ace9ed3 ("bpf: Allow variable-offset stack access") Reported-by: Hao Sun Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231207041150.229139-2-andreimatei1@gmail.com Closes: https://lore.kernel.org/bpf/CACkBjsZGEUaRCHsmaX=h-efVogsRfK1FPxmkgb0Os_frnHiNdw@mail.gmail.com/ --- kernel/bpf/verifier.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 45e85fb76d82..85e4ab61084f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6620,10 +6620,7 @@ static int check_stack_access_within_bounds( if (tnum_is_const(reg->var_off)) { min_off = reg->var_off.value + off; - if (access_size > 0) - max_off = min_off + access_size - 1; - else - max_off = min_off; + max_off = min_off + access_size; } else { if (reg->smax_value >= BPF_MAX_VAR_OFF || reg->smin_value <= -BPF_MAX_VAR_OFF) { @@ -6632,15 +6629,12 @@ static int check_stack_access_within_bounds( return -EACCES; } min_off = reg->smin_value + off; - if (access_size > 0) - max_off = reg->smax_value + off + access_size - 1; - else - max_off = min_off; + max_off = reg->smax_value + off + access_size; } err = check_stack_slot_within_bounds(min_off, state, type); - if (!err) - err = check_stack_slot_within_bounds(max_off, state, type); + if (!err && max_off > 0) + err = -EINVAL; /* out of stack access into non-negative offsets */ if (err) { if (tnum_is_const(reg->var_off)) { From e28bd359bcc8eb849aaa475f3c3f9705fba26d6e Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Wed, 6 Dec 2023 23:11:49 -0500 Subject: [PATCH 3244/7721] bpf: Add verifier regression test for previous patch Add a regression test for var-off zero-sized reads. Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20231207041150.229139-3-andreimatei1@gmail.com --- .../selftests/bpf/progs/verifier_var_off.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_var_off.c b/tools/testing/selftests/bpf/progs/verifier_var_off.c index 83a90afba785..b7bdd7db3a35 100644 --- a/tools/testing/selftests/bpf/progs/verifier_var_off.c +++ b/tools/testing/selftests/bpf/progs/verifier_var_off.c @@ -224,6 +224,35 @@ __naked void access_max_out_of_bound(void) : __clobber_all); } +/* Similar to the test above, but this time check the special case of a + * zero-sized stack access. We used to have a bug causing crashes for zero-sized + * out-of-bounds accesses. + */ +SEC("socket") +__description("indirect variable-offset stack access, zero-sized, max out of bound") +__failure __msg("invalid variable-offset indirect access to stack R1") +__naked void zero_sized_access_max_out_of_bound(void) +{ + asm volatile (" \ + r0 = 0; \ + /* Fill some stack */ \ + *(u64*)(r10 - 16) = r0; \ + *(u64*)(r10 - 8) = r0; \ + /* Get an unknown value */ \ + r1 = *(u32*)(r1 + 0); \ + r1 &= 63; \ + r1 += -16; \ + /* r1 is now anywhere in [-16,48) */ \ + r1 += r10; \ + r2 = 0; \ + r3 = 0; \ + call %[bpf_probe_read_kernel]; \ + exit; \ +" : + : __imm(bpf_probe_read_kernel) + : __clobber_all); +} + SEC("lwt_in") __description("indirect variable-offset stack access, min out of bound") __failure __msg("invalid variable-offset indirect access to stack R2") From 1d38a9ee81570c4bd61f557832dead4d6f816760 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Wed, 6 Dec 2023 23:11:50 -0500 Subject: [PATCH 3245/7721] bpf: Guard stack limits against 32bit overflow This patch promotes the arithmetic around checking stack bounds to be done in the 64-bit domain, instead of the current 32bit. The arithmetic implies adding together a 64-bit register with a int offset. The register was checked to be below 1<<29 when it was variable, but not when it was fixed. The offset either comes from an instruction (in which case it is 16 bit), from another register (in which case the caller checked it to be below 1<<29 [1]), or from the size of an argument to a kfunc (in which case it can be a u32 [2]). Between the register being inconsistently checked to be below 1<<29, and the offset being up to an u32, it appears that we were open to overflowing the `int`s which were currently used for arithmetic. [1] https://github.com/torvalds/linux/blob/815fb87b753055df2d9e50f6cd80eb10235fe3e9/kernel/bpf/verifier.c#L7494-L7498 [2] https://github.com/torvalds/linux/blob/815fb87b753055df2d9e50f6cd80eb10235fe3e9/kernel/bpf/verifier.c#L11904 Reported-by: Andrii Nakryiko Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231207041150.229139-4-andreimatei1@gmail.com --- kernel/bpf/verifier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 85e4ab61084f..0e77bb52542d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6577,7 +6577,7 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env, * The minimum valid offset is -MAX_BPF_STACK for writes, and * -state->allocated_stack for reads. */ -static int check_stack_slot_within_bounds(int off, +static int check_stack_slot_within_bounds(s64 off, struct bpf_func_state *state, enum bpf_access_type t) { @@ -6606,7 +6606,7 @@ static int check_stack_access_within_bounds( struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = regs + regno; struct bpf_func_state *state = func(env, reg); - int min_off, max_off; + s64 min_off, max_off; int err; char *err_extra; @@ -6619,7 +6619,7 @@ static int check_stack_access_within_bounds( err_extra = " write to"; if (tnum_is_const(reg->var_off)) { - min_off = reg->var_off.value + off; + min_off = (s64)reg->var_off.value + off; max_off = min_off + access_size; } else { if (reg->smax_value >= BPF_MAX_VAR_OFF || From df2a5f74e6eda50e1376a32bd60402a28ed51c8e Mon Sep 17 00:00:00 2001 From: Dmitrii Galantsev Date: Wed, 6 Dec 2023 02:04:52 -0600 Subject: [PATCH 3246/7721] drm/amd/pm: fix pp_*clk_od typo Fix pp_dpm_sclk_od and pp_dpm_mclk_od typos. Those were defined as pp_*clk_od but used as pp_dpm_*clk_od instead. This change removes the _dpm part. Fixes: 8cfd6a05750c ("drm/amd/pm: Hide irrelevant pm device attributes") Signed-off-by: Dmitrii Galantsev Reviewed-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index e1497296afee..2cd995b0ceba 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2238,10 +2238,10 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } else if (DEVICE_ATTR_IS(xgmi_plpd_policy)) { if (amdgpu_dpm_get_xgmi_plpd_mode(adev, NULL) == XGMI_PLPD_NONE) *states = ATTR_STATE_UNSUPPORTED; - } else if (DEVICE_ATTR_IS(pp_dpm_mclk_od)) { + } else if (DEVICE_ATTR_IS(pp_mclk_od)) { if (amdgpu_dpm_get_mclk_od(adev) == -EOPNOTSUPP) *states = ATTR_STATE_UNSUPPORTED; - } else if (DEVICE_ATTR_IS(pp_dpm_sclk_od)) { + } else if (DEVICE_ATTR_IS(pp_sclk_od)) { if (amdgpu_dpm_get_sclk_od(adev) == -EOPNOTSUPP) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(apu_thermal_cap)) { From 0497ae6f8830816d9277a8d5c8d9bf5966f292e1 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Tue, 5 Dec 2023 14:55:04 -0500 Subject: [PATCH 3247/7721] drm/amd/display: fix hw rotated modes when PSR-SU is enabled We currently don't support dirty rectangles on hardware rotated modes. So, if a user is using hardware rotated modes with PSR-SU enabled, use PSR-SU FFU for all rotated planes (including cursor planes). Cc: stable@vger.kernel.org Fixes: 30ebe41582d1 ("drm/amd/display: add FB_DAMAGE_CLIPS support") Reported-by: Kai-Heng Feng Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/2952 Tested-by: Kai-Heng Feng Tested-by: Bin Li Reviewed-by: Mario Limonciello Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 1 + drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c | 12 ++++++++++-- .../gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 6aabe8a3ffef..90868a54d4dd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5241,6 +5241,9 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, if (plane->type == DRM_PLANE_TYPE_CURSOR) return; + if (new_plane_state->rotation != DRM_MODE_ROTATE_0) + goto ffu; + num_clips = drm_plane_get_damage_clips_count(new_plane_state); clips = drm_plane_get_damage_clips(new_plane_state); diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 9649934ea186..e2a3aa8812df 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -465,6 +465,7 @@ struct dc_cursor_mi_param { struct fixed31_32 v_scale_ratio; enum dc_rotation_angle rotation; bool mirror; + struct dc_stream_state *stream; }; /* IPP related types */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index 139cf31d2e45..89c3bf0fe0c9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -1077,8 +1077,16 @@ void hubp2_cursor_set_position( if (src_y_offset < 0) src_y_offset = 0; /* Save necessary cursor info x, y position. w, h is saved in attribute func. */ - hubp->cur_rect.x = src_x_offset + param->viewport.x; - hubp->cur_rect.y = src_y_offset + param->viewport.y; + if (param->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 && + param->rotation != ROTATION_ANGLE_0) { + hubp->cur_rect.x = 0; + hubp->cur_rect.y = 0; + hubp->cur_rect.w = param->stream->timing.h_addressable; + hubp->cur_rect.h = param->stream->timing.v_addressable; + } else { + hubp->cur_rect.x = src_x_offset + param->viewport.x; + hubp->cur_rect.y = src_y_offset + param->viewport.y; + } } void hubp2_clk_cntl(struct hubp *hubp, bool enable) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 2b8b8366538e..cdb903116eb7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3417,7 +3417,8 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, .rotation = pipe_ctx->plane_state->rotation, - .mirror = pipe_ctx->plane_state->horizontal_mirror + .mirror = pipe_ctx->plane_state->horizontal_mirror, + .stream = pipe_ctx->stream, }; bool pipe_split_on = false; bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || From a2020be69490ee8778c59a02e7b270dfeecffbd4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 6 Dec 2023 12:08:26 -0600 Subject: [PATCH 3248/7721] drm/amd/display: Restore guard against default backlight value < 1 nit Mark reports that brightness is not restored after Xorg dpms screen blank. This behavior was introduced by commit d9e865826c20 ("drm/amd/display: Simplify brightness initialization") which dropped the cached backlight value in display code, but also removed code for when the default value read back was less than 1 nit. Restore this code so that the backlight brightness is restored to the correct default value in this circumstance. Reported-by: Mark Herbert Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3031 Cc: stable@vger.kernel.org Cc: Camille Cho Cc: Krunoslav Kovac Cc: Hamza Mahfooz Fixes: d9e865826c20 ("drm/amd/display: Simplify brightness initialization") Acked-by: Alex Deucher Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- .../amd/display/dc/link/protocols/link_edp_panel_control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index ac0fa88b52a0..bf53a86ea817 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -287,8 +287,8 @@ bool set_default_brightness_aux(struct dc_link *link) if (link && link->dpcd_sink_ext_caps.bits.oled == 1) { if (!read_default_bl_aux(link, &default_backlight)) default_backlight = 150000; - // if > 5000, it might be wrong readback - if (default_backlight > 5000000) + // if < 1 nits or > 5000, it might be wrong readback + if (default_backlight < 1000 || default_backlight > 5000000) default_backlight = 150000; return edp_set_backlight_level_nits(link, true, From b2662d4cc4ce2db4bd55e00a528b1d35be82c6c3 Mon Sep 17 00:00:00 2001 From: shaoyunl Date: Thu, 23 Nov 2023 13:59:44 -0500 Subject: [PATCH 3249/7721] drm/amdgpu: SW part of MES event log enablement This is the generic SW part, prepare the event log buffer and dump it through debugfs Signed-off-by: shaoyunl Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 61 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 5 ++ 4 files changed, 70 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index c480192e33f5..424bed738296 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -2147,6 +2147,8 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) amdgpu_debugfs_firmware_init(adev); amdgpu_ta_if_debugfs_init(adev); + amdgpu_debugfs_mes_event_log_init(adev); + #if defined(CONFIG_DRM_AMD_DC) if (adev->dc_enabled) dtn_debugfs_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h index 371a6f0deb29..0425432d8659 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h @@ -32,3 +32,5 @@ void amdgpu_debugfs_fini(struct amdgpu_device *adev); void amdgpu_debugfs_fence_init(struct amdgpu_device *adev); void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev); void amdgpu_debugfs_gem_init(struct amdgpu_device *adev); +void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev); + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 9ddbf1494326..e544b823abf6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -98,6 +98,26 @@ static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) return 0; } +static int amdgpu_mes_event_log_init(struct amdgpu_device *adev) +{ + int r; + + r = amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &adev->mes.event_log_gpu_obj, + &adev->mes.event_log_gpu_addr, + &adev->mes.event_log_cpu_addr); + if (r) { + dev_warn(adev->dev, "failed to create MES event log buffer (%d)", r); + return r; + } + + memset(adev->mes.event_log_cpu_addr, 0, PAGE_SIZE); + + return 0; + +} + static void amdgpu_mes_doorbell_free(struct amdgpu_device *adev) { bitmap_free(adev->mes.doorbell_bitmap); @@ -182,8 +202,14 @@ int amdgpu_mes_init(struct amdgpu_device *adev) if (r) goto error; + r = amdgpu_mes_event_log_init(adev); + if (r) + goto error_doorbell; + return 0; +error_doorbell: + amdgpu_mes_doorbell_free(adev); error: amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); @@ -199,6 +225,10 @@ int amdgpu_mes_init(struct amdgpu_device *adev) void amdgpu_mes_fini(struct amdgpu_device *adev) { + amdgpu_bo_free_kernel(&adev->mes.event_log_gpu_obj, + &adev->mes.event_log_gpu_addr, + &adev->mes.event_log_cpu_addr); + amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); amdgpu_device_wb_free(adev, adev->mes.read_val_offs); @@ -1479,3 +1509,34 @@ int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) amdgpu_ucode_release(&adev->mes.fw[pipe]); return r; } + +#if defined(CONFIG_DEBUG_FS) + +static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused) +{ + struct amdgpu_device *adev = m->private; + uint32_t *mem = (uint32_t *)(adev->mes.event_log_cpu_addr); + + seq_hex_dump(m, "", DUMP_PREFIX_OFFSET, 32, 4, + mem, PAGE_SIZE, false); + + return 0; +} + + +DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_mes_event_log); + +#endif + +void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev) +{ + +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + + debugfs_create_file("amdgpu_mes_event_log", 0444, root, + adev, &amdgpu_debugfs_mes_event_log_fops); + +#endif +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index a27b424ffe00..894b9b133000 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -133,6 +133,11 @@ struct amdgpu_mes { uint32_t num_mes_dbs; unsigned long *doorbell_bitmap; + /* MES event log buffer */ + struct amdgpu_bo *event_log_gpu_obj; + uint64_t event_log_gpu_addr; + void *event_log_cpu_addr; + /* ip specific functions */ const struct amdgpu_mes_funcs *funcs; }; From 47c4533543af4759b7668a06c1a2ce06cdc71173 Mon Sep 17 00:00:00 2001 From: shaoyunl Date: Thu, 23 Nov 2023 14:52:55 -0500 Subject: [PATCH 3250/7721] drm/amdgpu: Enable event log on MES 11 Enable event log through the HW specific FW API Signed-off-by: shaoyunl Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 2 ++ drivers/gpu/drm/amd/include/mes_v11_api_def.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 4dfec56e1b7f..26d71a22395d 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -408,6 +408,8 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes) mes_set_hw_res_pkt.enable_reg_active_poll = 1; mes_set_hw_res_pkt.enable_level_process_quantum_check = 1; mes_set_hw_res_pkt.oversubscription_timer = 50; + mes_set_hw_res_pkt.enable_mes_event_int_logging = 1; + mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt), diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index b1db2b190187..1fbfd1aa987e 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -232,6 +232,7 @@ union MESAPI_SET_HW_RESOURCES { }; uint32_t oversubscription_timer; uint64_t doorbell_info; + uint64_t event_intr_history_gpu_mc_ptr; }; uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; From c5a761e2fe58631e1cd0249a729ce1934a11bcbe Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 23 Nov 2023 13:41:12 +0000 Subject: [PATCH 3251/7721] drm/mediatek: Stop using iommu_present() Remove the pointless check. If an IOMMU is providing transparent DMA API ops for any device(s) we care about, the DT code will have enforced the appropriate probe ordering already. And if the IOMMU *is* entirely absent, then attempting to go ahead with CMA and either suceeding or failing decisively seems more useful than deferring forever. Signed-off-by: Robin Murphy Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/fd1b62aa006556f29f37535814abfe41be63f7ae.1700746094.git.robin.murphy@arm.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 2dfaa613276a..48581da51857 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include @@ -608,9 +607,6 @@ static int mtk_drm_bind(struct device *dev) struct drm_device *drm; int ret, i; - if (!iommu_present(&platform_bus_type)) - return -EPROBE_DEFER; - pdev = of_find_device_by_node(private->mutex_node); if (!pdev) { dev_err(dev, "Waiting for disp-mutex device %pOF\n", From 157fd368561e03057e6e038fc115d1e81fa2ebf2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Dec 2023 17:37:17 +0100 Subject: [PATCH 3252/7721] dt-bindings: display: msm: dp-controller: document SM8650 compatible Document the DisplayPort controller found in the Qualcomm SM8650 SoC, the Controller base addresses and layout differ and thus cannot use the SM8350 compatible as fallback. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Patchwork: https://patchwork.freedesktop.org/patch/571131/ Link: https://lore.kernel.org/r/20231207-topic-sm8650-upstream-dp-v1-1-b762c06965bb@linaro.org Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/dp-controller.yaml | 1 + .../devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index dbe398f84ffb..93ded71c52d7 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -26,6 +26,7 @@ properties: - qcom,sc8280xp-edp - qcom,sdm845-dp - qcom,sm8350-dp + - qcom,sm8650-dp - items: - enum: - qcom,sm8250-dp diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml index 5638c1ea692e..bd11119dc93d 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml @@ -41,6 +41,12 @@ patternProperties: compatible: const: qcom,sm8650-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dp + "^dsi@[0-9a-f]+$": type: object properties: From 1b2d98bdd7b7c64265732f5f0dace4c52c9ba8a8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Dec 2023 17:37:18 +0100 Subject: [PATCH 3253/7721] drm/msm/dp: Add DisplayPort controller for SM8650 The Qualcomm SM8650 platform comes with a DisplayPort controller with a different base offset than the previous SM8550 SoC, add support for this in the DisplayPort driver. Signed-off-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/571132/ Link: https://lore.kernel.org/r/20231207-topic-sm8650-upstream-dp-v1-2-b762c06965bb@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 20c5cf7986b2..fd4e62fe163f 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -168,6 +168,11 @@ static const struct msm_dp_desc sm8350_dp_descs[] = { {} }; +static const struct msm_dp_desc sm8650_dp_descs[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + {} +}; + static const struct of_device_id dp_dt_match[] = { { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs }, { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs }, @@ -178,6 +183,7 @@ static const struct of_device_id dp_dt_match[] = { { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs }, { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs }, { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs }, + { .compatible = "qcom,sm8650-dp", .data = &sm8650_dp_descs }, {} }; From c4ac0c6c96f0985357c5866cf22fd642390409dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Dec 2023 15:02:05 +0300 Subject: [PATCH 3254/7721] drm/msm/dp: Fix platform_get_irq() check The platform_get_irq() function returns negative error codes. It never returns zero. Fix the check accordingly. Fixes: 82c2a5751227 ("drm/msm/dp: tie dp_display_irq_handler() with dp driver") Signed-off-by: Dan Carpenter Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/570755/ Link: https://lore.kernel.org/r/c12bb69b-d676-4345-9712-48aab48f2b48@moroto.mountain Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index fd4e62fe163f..f8a9e8403c26 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1168,9 +1168,9 @@ static int dp_display_request_irq(struct dp_display_private *dp) struct platform_device *pdev = dp->dp_display.pdev; dp->irq = platform_get_irq(pdev, 0); - if (!dp->irq) { + if (dp->irq < 0) { DRM_ERROR("failed to get irq\n"); - return -EINVAL; + return dp->irq; } rc = devm_request_irq(&pdev->dev, dp->irq, dp_display_irq_handler, From a08935fc859b22884dcb6b5126d3a986467101ce Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 4 Oct 2023 06:19:03 +0300 Subject: [PATCH 3255/7721] drm/msm/dpu: drop MSM_ENC_VBLANK support There are no in-kernel users of MSM_ENC_VBLANK wait type. Drop it together with the corresponding wait_for_vblank callback. Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/560701/ Link: https://lore.kernel.org/r/20231004031903.518223-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 3 -- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 1 - .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 28 ------------------- .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 9 +++--- drivers/gpu/drm/msm/msm_drv.h | 2 -- 5 files changed, 4 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index aa1a1646b322..889e9bb42715 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2400,9 +2400,6 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, case MSM_ENC_TX_COMPLETE: fn_wait = phys->ops.wait_for_tx_complete; break; - case MSM_ENC_VBLANK: - fn_wait = phys->ops.wait_for_vblank; - break; default: DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", event); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index b6b48e2c63ef..e2934a6702d1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -104,7 +104,6 @@ struct dpu_encoder_phys_ops { int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable); int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); - int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc); void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); void (*trigger_start)(struct dpu_encoder_phys *phys_enc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index d24f45d1f654..76f1f66e41cd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -675,33 +675,6 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); } -static int dpu_encoder_phys_cmd_wait_for_vblank( - struct dpu_encoder_phys *phys_enc) -{ - int rc = 0; - struct dpu_encoder_phys_cmd *cmd_enc; - struct dpu_encoder_wait_info wait_info; - - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - - /* only required for master controller */ - if (!dpu_encoder_phys_cmd_is_master(phys_enc)) - return rc; - - wait_info.wq = &cmd_enc->pending_vblank_wq; - wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; - - atomic_inc(&cmd_enc->pending_vblank_cnt); - - rc = dpu_encoder_helper_wait_for_irq(phys_enc, - phys_enc->irq[INTR_IDX_RDPTR], - dpu_encoder_phys_cmd_te_rd_ptr_irq, - &wait_info); - - return rc; -} - static void dpu_encoder_phys_cmd_handle_post_kickoff( struct dpu_encoder_phys *phys_enc) { @@ -729,7 +702,6 @@ static void dpu_encoder_phys_cmd_init_ops( ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done; ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff; ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete; - ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank; ops->trigger_start = dpu_encoder_phys_cmd_trigger_start; ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush; ops->irq_control = dpu_encoder_phys_cmd_irq_control; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 69bc1b2e514c..2b4e5b5eff44 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -440,7 +440,7 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_ENABLING; } -static int dpu_encoder_phys_vid_wait_for_vblank( +static int dpu_encoder_phys_vid_wait_for_tx_complete( struct dpu_encoder_phys *phys_enc) { struct dpu_encoder_wait_info wait_info; @@ -554,7 +554,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) * scanout buffer) don't latch properly.. */ if (dpu_encoder_phys_vid_is_master(phys_enc)) { - ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); + ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -574,7 +574,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); dpu_encoder_phys_inc_pending(phys_enc); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); - ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); + ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -679,8 +679,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->disable = dpu_encoder_phys_vid_disable; ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; - ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; - ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_tx_complete; ops->irq_control = dpu_encoder_phys_vid_irq_control; ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff; ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index a205127ccc93..c0446fa66b98 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -78,12 +78,10 @@ enum msm_dsi_controller { * enum msm_event_wait - type of HW events to wait for * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel - * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters) */ enum msm_event_wait { MSM_ENC_COMMIT_DONE = 0, MSM_ENC_TX_COMPLETE, - MSM_ENC_VBLANK, }; /** From b0318e28549373f50d35c099864899a235076ad6 Mon Sep 17 00:00:00 2001 From: Ryno Swart Date: Wed, 6 Dec 2023 17:12:08 +0200 Subject: [PATCH 3256/7721] nfp: ethtool: add extended ack report messages Add descriptive error messages to common ethtool failures to be more user friendly. Update `nfp_net_coalesce_para_check` to only check one argument, which facilitates unique error messages. Additionally, three error codes are updated to `EOPNOTSUPP` to reflect that these operations are not supported. Signed-off-by: Ryno Swart Signed-off-by: Louis Peens Link: https://lore.kernel.org/r/20231206151209.20296-2-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 4 +- .../ethernet/netronome/nfp/nfp_net_common.c | 6 ++- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 53 ++++++++++++++----- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index bd0e26524417..46764aeccb37 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -966,9 +966,9 @@ static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev) netdev->netdev_ops == &nfp_nfdk_netdev_ops; } -static inline int nfp_net_coalesce_para_check(u32 usecs, u32 pkts) +static inline int nfp_net_coalesce_para_check(u32 param) { - if ((usecs >= ((1 << 16) - 1)) || (pkts >= ((1 << 16) - 1))) + if (param >= ((1 << 16) - 1)) return -EINVAL; return 0; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index ac1f4514b1d0..dcd27ba2a74c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1176,7 +1176,8 @@ static void nfp_net_rx_dim_work(struct work_struct *work) * count. */ factor = nn->tlv_caps.me_freq_mhz / 16; - if (nfp_net_coalesce_para_check(factor * moder.usec, moder.pkts)) + if (nfp_net_coalesce_para_check(factor * moder.usec) || + nfp_net_coalesce_para_check(moder.pkts)) return; /* copy RX interrupt coalesce parameters */ @@ -1205,7 +1206,8 @@ static void nfp_net_tx_dim_work(struct work_struct *work) * count. */ factor = nn->tlv_caps.me_freq_mhz / 16; - if (nfp_net_coalesce_para_check(factor * moder.usec, moder.pkts)) + if (nfp_net_coalesce_para_check(factor * moder.usec) || + nfp_net_coalesce_para_check(moder.pkts)) return; /* copy TX interrupt coalesce parameters */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 200b3588363c..f4f6153cae0f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -633,7 +633,8 @@ static void nfp_net_get_ringparam(struct net_device *netdev, ring->tx_pending = nn->dp.txd_cnt; } -static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) +static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt, + struct netlink_ext_ack *extack) { struct nfp_net_dp *dp; @@ -644,7 +645,7 @@ static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) dp->rxd_cnt = rxd_cnt; dp->txd_cnt = txd_cnt; - return nfp_net_ring_reconfig(nn, dp, NULL); + return nfp_net_ring_reconfig(nn, dp, extack); } static int nfp_net_set_ringparam(struct net_device *netdev, @@ -657,7 +658,7 @@ static int nfp_net_set_ringparam(struct net_device *netdev, /* We don't have separate queues/rings for small/large frames. */ if (ring->rx_mini_pending || ring->rx_jumbo_pending) - return -EINVAL; + return -EOPNOTSUPP; qc_min = nn->dev_info->min_qc_size; qc_max = nn->dev_info->max_qc_size; @@ -666,9 +667,15 @@ static int nfp_net_set_ringparam(struct net_device *netdev, rxd_cnt = roundup_pow_of_two(ring->rx_pending); txd_cnt = roundup_pow_of_two(ring->tx_pending); - if (rxd_cnt < qc_min || rxd_cnt > qc_max || - txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp) + if (rxd_cnt < qc_min || rxd_cnt > qc_max) { + NL_SET_ERR_MSG_MOD(extack, "rx parameter out of bounds"); return -EINVAL; + } + + if (txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp) { + NL_SET_ERR_MSG_MOD(extack, "tx parameter out of bounds"); + return -EINVAL; + } if (nn->dp.rxd_cnt == rxd_cnt && nn->dp.txd_cnt == txd_cnt) return 0; @@ -676,7 +683,7 @@ static int nfp_net_set_ringparam(struct net_device *netdev, nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n", nn->dp.rxd_cnt, rxd_cnt, nn->dp.txd_cnt, txd_cnt); - return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt); + return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt, extack); } static int nfp_test_link(struct net_device *netdev) @@ -1866,7 +1873,7 @@ static int nfp_net_get_coalesce(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD)) - return -EINVAL; + return -EOPNOTSUPP; ec->use_adaptive_rx_coalesce = nn->rx_coalesce_adapt_on; ec->use_adaptive_tx_coalesce = nn->tx_coalesce_adapt_on; @@ -2145,22 +2152,40 @@ static int nfp_net_set_coalesce(struct net_device *netdev, */ if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD)) - return -EINVAL; + return -EOPNOTSUPP; /* ensure valid configuration */ - if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames) + if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames) { + NL_SET_ERR_MSG_MOD(extack, + "rx-usecs and rx-frames cannot both be zero"); return -EINVAL; + } - if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames) + if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames) { + NL_SET_ERR_MSG_MOD(extack, + "tx-usecs and tx-frames cannot both be zero"); return -EINVAL; + } - if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor, - ec->rx_max_coalesced_frames)) + if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor)) { + NL_SET_ERR_MSG_MOD(extack, "rx-usecs too large"); return -EINVAL; + } - if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor, - ec->tx_max_coalesced_frames)) + if (nfp_net_coalesce_para_check(ec->rx_max_coalesced_frames)) { + NL_SET_ERR_MSG_MOD(extack, "rx-frames too large"); return -EINVAL; + } + + if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor)) { + NL_SET_ERR_MSG_MOD(extack, "tx-usecs too large"); + return -EINVAL; + } + + if (nfp_net_coalesce_para_check(ec->tx_max_coalesced_frames)) { + NL_SET_ERR_MSG_MOD(extack, "tx-frames too large"); + return -EINVAL; + } /* configuration is valid */ nn->rx_coalesce_adapt_on = !!ec->use_adaptive_rx_coalesce; From 2f076ea86674c4f6d807a962409c823e218735a6 Mon Sep 17 00:00:00 2001 From: Ryno Swart Date: Wed, 6 Dec 2023 17:12:09 +0200 Subject: [PATCH 3257/7721] nfp: devlink: add extended ack report messages Add descriptive error messages to common devlink failures to be more user friendly. Signed-off-by: Ryno Swart Signed-off-by: Louis Peens Link: https://lore.kernel.org/r/20231206151209.20296-3-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 8c6954c58a88..635d33c0d6d3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -75,8 +75,10 @@ nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port, if (ret) return ret; - if (eth_port.port_lanes % count) + if (eth_port.port_lanes % count) { + NL_SET_ERR_MSG_MOD(extack, "invalid count"); return -EINVAL; + } /* Special case the 100G CXP -> 2x40G split */ lanes = eth_port.port_lanes / count; @@ -101,8 +103,10 @@ nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port, if (ret) return ret; - if (!eth_port.is_split) + if (!eth_port.is_split) { + NL_SET_ERR_MSG_MOD(extack, "port is not split"); return -EINVAL; + } /* Special case the 100G CXP -> 2x40G unsplit */ lanes = eth_port.port_lanes; From 78804eecbe5c4d533ae8b7c3a85b278e3594ec94 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:19:56 +0100 Subject: [PATCH 3258/7721] dt-bindings: arm: qcom: document SM8650 and the reference boards Document the SM8650 SoC and based MTP (Mobile Test Platforms) and QRD (Qualcomm Reference Device) boards. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-1-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index a4393a891f30..670e61cbb644 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -87,6 +87,7 @@ description: | sm8350 sm8450 sm8550 + sm8650 The 'board' element must be one of the following strings: @@ -1039,6 +1040,12 @@ properties: - qcom,sm8550-qrd - const: qcom,sm8550 + - items: + - enum: + - qcom,sm8650-mtp + - qcom,sm8650-qrd + - const: qcom,sm8650 + # Board compatibles go above qcom,msm-id: From d2350377997f3606d5b76ee7dc6101c148048951 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:19:57 +0100 Subject: [PATCH 3259/7721] arm64: dts: qcom: add initial SM8650 dtsi Add initial DTSI for the Qualcomm SM8650 platform, only contains nodes which doesn't depend on interconnect. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-2-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 2437 ++++++++++++++++++++++++++ 1 file changed, 2437 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8650.dtsi diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi new file mode 100644 index 000000000000..1f4c4178544c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -0,0 +1,2437 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + bi_tcxo_div2: bi-tcxo-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-mult = <1>; + clock-div = <2>; + }; + + bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK_A>; + clock-mult = <1>; + clock-div = <2>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a520"; + reg = <0 0>; + + clocks = <&cpufreq_hw 0>; + + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_0>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + + qcom,freq-domain = <&cpufreq_hw 0>; + + #cooling-cells = <2>; + + L2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + + L3_0: l3-cache { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a520"; + reg = <0 0x100>; + + clocks = <&cpufreq_hw 0>; + + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_0>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + + qcom,freq-domain = <&cpufreq_hw 0>; + + #cooling-cells = <2>; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x200>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_200>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + + L2_200: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x300>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_200>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x400>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD4>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_400>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + + L2_400: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x500>; + + clocks = <&cpufreq_hw 1>; + + power-domains = <&CPU_PD5>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_500>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 1>; + + #cooling-cells = <2>; + + L2_500: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x600>; + + clocks = <&cpufreq_hw 1>; + + power-domains = <&CPU_PD6>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_600>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 1>; + + #cooling-cells = <2>; + + L2_600: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-x4"; + reg = <0 0x700>; + + clocks = <&cpufreq_hw 2>; + + power-domains = <&CPU_PD7>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_700>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <588>; + + qcom,freq-domain = <&cpufreq_hw 2>; + + #cooling-cells = <2>; + + L2_700: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + + core4 { + cpu = <&CPU4>; + }; + + core5 { + cpu = <&CPU5>; + }; + + core6 { + cpu = <&CPU6>; + }; + + core7 { + cpu = <&CPU7>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + SILVER_CPU_SLEEP_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + idle-state-name = "silver-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <550>; + exit-latency-us = <750>; + min-residency-us = <6700>; + local-timer-stop; + }; + + GOLD_CPU_SLEEP_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + idle-state-name = "gold-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <600>; + exit-latency-us = <1300>; + min-residency-us = <8136>; + local-timer-stop; + }; + + GOLD_PLUS_CPU_SLEEP_0: cpu-sleep-2-0 { + compatible = "arm,idle-state"; + idle-state-name = "gold-plus-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <500>; + exit-latency-us = <1350>; + min-residency-us = <7480>; + local-timer-stop; + }; + }; + + domain-idle-states { + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x41000044>; + entry-latency-us = <750>; + exit-latency-us = <2350>; + min-residency-us = <9144>; + }; + + CLUSTER_SLEEP_1: cluster-sleep-1 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x4100c344>; + entry-latency-us = <2800>; + exit-latency-us = <4400>; + min-residency-us = <10150>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-sm8650", "qcom,scm"; + }; + }; + + memory@a0000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0xa0000000 0 0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + CPU_PD0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_PLUS_CPU_SLEEP_0>; + }; + + CLUSTER_PD: power-domain-cluster { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_SLEEP_0>, + <&CLUSTER_SLEEP_1>; + }; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: hyp@80000000 { + reg = <0 0x80000000 0 0xe00000>; + no-map; + }; + + cpusys_vm_mem: cpusys-vm@80e00000 { + reg = <0 0x80e00000 0 0x400000>; + no-map; + }; + + /* Merged xbl_dtlog, xbl_ramdump and aop_image regions */ + xbl_dt_log_merged_mem: xbl-dt-log-merged@81a00000 { + reg = <0 0x81a00000 0 0x260000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0 0x81c60000 0 0x20000>; + no-map; + }; + + /* Merged aop_config, tme_crash_dump, tme_log and uefi_log regions */ + aop_tme_uefi_merged_mem: aop-tme-uefi-merged@81c80000 { + reg = <0 0x81c80000 0 0x74000>; + no-map; + }; + + /* Secdata region can be reused by apps */ + + smem: smem@81d00000 { + compatible = "qcom,smem"; + reg = <0 0x81d00000 0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + + adsp_mhi_mem: adsp-mhi@81f00000 { + reg = <0 0x81f00000 0 0x20000>; + no-map; + }; + + pvmfw_mem: pvmfw@824a0000 { + reg = <0 0x824a0000 0 0x100000>; + no-map; + }; + + global_sync_mem: global-sync@82600000 { + reg = <0 0x82600000 0 0x100000>; + no-map; + }; + + tz_stat_mem: tz-stat@82700000 { + reg = <0 0x82700000 0 0x100000>; + no-map; + }; + + qdss_mem: qdss@82800000 { + reg = <0 0x82800000 0 0x2000000>; + no-map; + }; + + mpss_dsm_mem: mpss-dsm@86b00000 { + reg = <0 0x86b00000 0 0x4900000>; + no-map; + }; + + mpss_dsm_mem_2: mpss-dsm-2@8b400000 { + reg = <0 0x8b400000 0 0x800000>; + no-map; + }; + + mpss_mem: mpss@8bc00000 { + reg = <0 0x8bc00000 0 0xf400000>; + no-map; + }; + + q6_mpss_dtb_mem: q6-mpss-dtb@9b000000 { + reg = <0 0x9b000000 0 0x80000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@9b080000 { + reg = <0 0x9b080000 0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@9b090000 { + reg = <0 0x9b090000 0 0xa000>; + no-map; + }; + + gpu_micro_code_mem: gpu-micro-code@9b09a000 { + reg = <0 0x9b09a000 0 0x2000>; + no-map; + }; + + spss_region_mem: spss@9b0a0000 { + reg = <0 0x9b0a0000 0 0x1e0000>; + no-map; + }; + + /* First part of the "SPU secure shared memory" region */ + spu_tz_shared_mem: spu-tz-shared@9b280000 { + reg = <0 0x9b280000 0 0x60000>; + no-map; + }; + + /* Second part of the "SPU secure shared memory" region */ + spu_modem_shared_mem: spu-modem-shared@9b2e0000 { + reg = <0 0x9b2e0000 0 0x20000>; + no-map; + }; + + camera_mem: camera@9b300000 { + reg = <0 0x9b300000 0 0x800000>; + no-map; + }; + + video_mem: video@9bb00000 { + reg = <0 0x9bb00000 0 0x800000>; + no-map; + }; + + cvp_mem: cvp@9c300000 { + reg = <0 0x9c300000 0 0x700000>; + no-map; + }; + + cdsp_mem: cdsp@9ca00000 { + reg = <0 0x9ca00000 0 0x1400000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb@9de00000 { + reg = <0 0x9de00000 0 0x80000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb@9de80000 { + reg = <0 0x9de80000 0 0x80000>; + no-map; + }; + + adspslpi_mem: adspslpi@9df00000 { + reg = <0 0x9df00000 0 0x4080000>; + no-map; + }; + + rmtfs_mem: rmtfs@d7c00000 { + compatible = "qcom,rmtfs-mem"; + reg = <0 0xd7c00000 0 0x400000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = ; + }; + + /* Merged tz_reserved, xbl_sc, cpucp_fw and qtee regions */ + tz_merged_mem: tz-merged@d8000000 { + reg = <0 0xd8000000 0 0x800000>; + no-map; + }; + + hwfence_shbuf: hwfence-shbuf@e6440000 { + reg = <0 0xe6440000 0 0x2dd000>; + no-map; + }; + + trust_ui_vm_mem: trust-ui-vm@f3800000 { + reg = <0 0xf3800000 0 0x4400000>; + no-map; + }; + + oem_vm_mem: oem-vm@f7c00000 { + reg = <0 0xf7c00000 0 0x4c00000>; + no-map; + }; + + llcc_lpi_mem: llcc-lpi@ff800000 { + reg = <0 0xff800000 0 0x600000>; + no-map; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0 0 0 0 0x10 0>; + ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,sm8650-gcc"; + reg = <0 0x00100000 0 0x1f4200>; + + clocks = <&bi_tcxo_div2>, + <&bi_tcxo_ao_div2>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + ipcc: mailbox@406000 { + compatible = "qcom,sm8650-ipcc", "qcom,ipcc"; + reg = <0 0x00406000 0 0x1000>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + + #mbox-cells = <2>; + }; + + gpi_dma2: dma-controller@800000 { + compatible = "qcom,sm8650-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00800000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3f>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x436 0>; + + dma-coherent; + + status = "disabled"; + }; + + qupv3_id_1: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x008c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x423 0>; + + dma-coherent; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + uart15: serial@89c000 { + compatible = "qcom,geni-debug-uart"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + pinctrl-0 = <&qup_uart15_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + }; + + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,sm8650-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00a00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0xc>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0xb6 0>; + dma-coherent; + + status = "disabled"; + }; + + rng: rng@10c3000 { + compatible = "qcom,sm8650-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + + ice: crypto@1d88000 { + compatible = "qcom,sm8650-inline-crypto-engine", + "qcom,inline-crypto-engine"; + reg = <0 0x01d88000 0 0x8000>; + + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0 0x01f40000 0 0x20000>; + + #hwlock-cells = <1>; + }; + + tcsr: clock-controller@1fc0000 { + compatible = "qcom,sm8650-tcsr", "syscon"; + reg = <0 0x01fc0000 0 0xa0000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: clock-controller@3d90000 { + compatible = "qcom,sm8650-gpucc"; + reg = <0 0x03d90000 0 0xa000>; + + clocks = <&bi_tcxo_div2>, + <&gcc GCC_GPU_GPLL0_CLK_SRC>, + <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + dispcc: clock-controller@af00000 { + compatible = "qcom,sm8650-dispcc"; + reg = <0 0x0af00000 0 0x20000>; + + clocks = <&bi_tcxo_div2>, + <&bi_tcxo_ao_div2>, + <&gcc GCC_DISP_AHB_CLK>, + <&sleep_clk>, + <0>, /* dsi0 */ + <0>, + <0>, /* dsi1 */ + <0>, + <0>, /* dp0 */ + <0>, + <0>, /* dp1 */ + <0>, + <0>, /* dp2 */ + <0>, + <0>, /* dp3 */ + <0>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + + status = "disabled"; + }; + + usb_1_hsphy: phy@88e3000 { + compatible = "qcom,sm8650-snps-eusb2-phy", + "qcom,sm8550-snps-eusb2-phy"; + reg = <0 0x088e3000 0 0x154>; + + clocks = <&tcsr TCSR_USB2_CLKREF_EN>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + + usb_dp_qmpphy: phy@88e8000 { + compatible = "qcom,sm8650-qmp-usb3-dp-phy"; + reg = <0 0x088e8000 0 0x3000>; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "usb3_pipe"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", + "common"; + + power-domains = <&gcc USB3_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <1>; + + status = "disabled"; + }; + + usb_1: usb@a6f8800 { + compatible = "qcom,sm8650-dwc3", "qcom,dwc3"; + reg = <0 0x0a6f8800 0 0x400>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 IRQ_TYPE_EDGE_RISING>, + <&pdc 14 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&tcsr TCSR_USB3_CLKREF_EN>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + power-domains = <&gcc USB30_PRIM_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + usb_1_dwc3: usb@a600000 { + compatible = "snps,dwc3"; + reg = <0 0x0a600000 0 0xcd00>; + + interrupts = ; + + iommus = <&apps_smmu 0x40 0>; + + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", + "usb3-phy"; + + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + }; + }; + }; + }; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,sm8650-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; + + interrupt-parent = <&intc>; + + qcom,pdc-ranges = <0 480 94>, <94 609 31>, + <125 63 1>, <126 716 12>, + <138 251 5>, <143 244 4>; + + #interrupt-cells = <2>; + interrupt-controller; + }; + + tsens0: thermal-sensor@c228000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c228000 0 0x1000>, /* TM */ + <0 0x0c222000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <15>; + + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c229000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c229000 0 0x1000>, /* TM */ + <0 0x0c223000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <16>; + + #thermal-sensor-cells = <1>; + }; + + tsens2: thermal-sensor@c22a000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c22a000 0 0x1000>, /* TM */ + <0 0x0c224000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <13>; + + #thermal-sensor-cells = <1>; + }; + + aoss_qmp: power-management@c300000 { + compatible = "qcom,sm8650-aoss-qmp", "qcom,aoss-qmp"; + reg = <0 0x0c300000 0 0x400>; + + interrupt-parent = <&ipcc>; + interrupts-extended = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP>; + + #clock-cells = <0>; + }; + + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0 0x0c3f0000 0 0x400>; + }; + + spmi_bus: spmi@c400000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c400000 0 0x3000>, + <0 0x0c500000 0 0x4000000>, + <0 0x0c440000 0 0x80000>, + <0 0x0c4c0000 0 0x20000>, + <0 0x0c42d000 0 0x4000>; + reg-names = "core", + "chnls", + "obsrvr", + "intr", + "cnfg"; + + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + + qcom,ee = <0>; + qcom,channel = <0>; + qcom,bus-id = <0>; + + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,sm8650-tlmm"; + reg = <0 0x0f100000 0 0x300000>; + + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&tlmm 0 0 211>; + + wakeup-parent = <&pdc>; + + qup_uart15_default: qup-uart15-default-state { + /* TX, RX */ + pins = "gpio30", "gpio31"; + function = "qup2_se7"; + drive-strength = <2>; + bias-disable; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,sm8650-smmu-500", "qcom,smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + #iommu-cells = <2>; + #global-interrupts = <1>; + + dma-coherent; + }; + + intc: interrupt-controller@17100000 { + compatible = "arm,gic-v3"; + reg = <0 0x17100000 0 0x10000>, /* GICD */ + <0 0x17180000 0 0x200000>; /* GICR * 8 */ + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; + reg = <0 0x17140000 0 0x20000>; + + msi-controller; + #msi-cells = <1>; + }; + }; + + timer@17420000 { + compatible = "arm,armv7-timer-mem"; + reg = <0 0x17420000 0 0x1000>; + + ranges = <0 0 0 0x20000000>; + #address-cells = <1>; + #size-cells = <1>; + + frame@17421000 { + reg = <0x17421000 0x1000>, + <0x17422000 0x1000>; + + interrupts = , + ; + + frame-number = <0>; + }; + + frame@17423000 { + reg = <0x17423000 0x1000>; + + interrupts = ; + + frame-number = <1>; + + status = "disabled"; + }; + + frame@17425000 { + reg = <0x17425000 0x1000>; + + interrupts = ; + + frame-number = <2>; + + status = "disabled"; + }; + + frame@17427000 { + reg = <0x17427000 0x1000>; + + interrupts = ; + + frame-number = <3>; + + status = "disabled"; + }; + + frame@17429000 { + reg = <0x17429000 0x1000>; + + interrupts = ; + + frame-number = <4>; + + status = "disabled"; + }; + + frame@1742b000 { + reg = <0x1742b000 0x1000>; + + interrupts = ; + + frame-number = <5>; + + status = "disabled"; + }; + + frame@1742d000 { + reg = <0x1742d000 0x1000>; + + interrupts = ; + + frame-number = <6>; + + status = "disabled"; + }; + }; + + apps_rsc: rsc@17a00000 { + compatible = "qcom,rpmh-rsc"; + reg = <0 0x17a00000 0 0x10000>, + <0 0x17a10000 0 0x10000>, + <0 0x17a20000 0 0x10000>, + <0 0x17a30000 0 0x10000>; + reg-names = "drv-0", + "drv-1", + "drv-2"; + + interrupts = , + , + ; + + power-domains = <&CLUSTER_PD>; + + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + + label = "apps_rsc"; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,sm8650-rpmh-clk"; + + clocks = <&xo_board>; + clock-names = "xo"; + + #clock-cells = <1>; + }; + + rpmhpd: power-controller { + compatible = "qcom,sm8650-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_min_svs: opp-48 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + }; + }; + }; + + cpufreq_hw: cpufreq@17d91000 { + compatible = "qcom,sm8650-cpufreq-epss", "qcom,cpufreq-epss"; + reg = <0 0x17d91000 0 0x1000>, + <0 0x17d92000 0 0x1000>, + <0 0x17d93000 0 0x1000>, + <0 0x17d94000 0 0x1000>; + reg-names = "freq-domain0", + "freq-domain1", + "freq-domain2", + "freq-domain3"; + + interrupts = , + , + , + ; + interrupt-names = "dcvsh-irq-0", + "dcvsh-irq-1", + "dcvsh-irq-2", + "dcvsh-irq-3"; + + clocks = <&bi_tcxo_div2>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + + #freq-domain-cells = <1>; + #clock-cells = <1>; + }; + + system-cache-controller@25000000 { + compatible = "qcom,sm8650-llcc"; + reg = <0 0x25000000 0 0x200000>, + <0 0x25400000 0 0x200000>, + <0 0x25200000 0 0x200000>, + <0 0x25600000 0 0x200000>, + <0 0x25800000 0 0x200000>; + reg-names = "llcc0_base", + "llcc1_base", + "llcc2_base", + "llcc3_base", + "llcc_broadcast_base"; + + interrupts = ; + }; + }; + + thermal-zones { + aoss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpu2-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu2-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu3-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu3-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu4-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu4-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu5-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu5-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu6-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu6-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + aoss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpu7-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu7-middle-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu7-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsphvx0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphvx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphvx1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphvx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + video-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + ddr-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 13>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + ddr-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + camera0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 14>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + camera0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + camera1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 15>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + camera1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + aoss2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss4-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss4-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss5-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss5-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss6-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss6-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss7-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss7-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + + interrupts = , + , + , + ; + }; +}; From 707060bf2a3cf3329b848e12a038de4d81356579 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:19:58 +0100 Subject: [PATCH 3260/7721] arm64: dts: qcom: pm8550ve: make PMK8550VE SID configurable The pm8550ve can be found with a different SID on SM8650 platforms, make it configurable. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-3-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pm8550ve.dtsi | 6 +++--- arch/arm64/boot/dts/qcom/sm8550-mtp.dts | 1 + arch/arm64/boot/dts/qcom/sm8550-qrd.dts | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8550ve.dtsi b/arch/arm64/boot/dts/qcom/pm8550ve.dtsi index c47646a467be..4dc1f03ab2c7 100644 --- a/arch/arm64/boot/dts/qcom/pm8550ve.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8550ve.dtsi @@ -33,16 +33,16 @@ trip1 { &spmi_bus { - pm8550ve: pmic@5 { + pm8550ve: pmic@PMK8550VE_SID { compatible = "qcom,pm8550", "qcom,spmi-pmic"; - reg = <0x5 SPMI_USID>; + reg = ; #address-cells = <1>; #size-cells = <0>; pm8550ve_temp_alarm: temp-alarm@a00 { compatible = "qcom,spmi-temp-alarm"; reg = <0xa00>; - interrupts = <0x5 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupts = ; #thermal-sensor-cells = <0>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts index 9a70875028b7..ac045bfc51e5 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts @@ -10,6 +10,7 @@ #include "pm8010.dtsi" #include "pm8550.dtsi" #include "pm8550b.dtsi" +#define PMK8550VE_SID 5 #include "pm8550ve.dtsi" #include "pm8550vs.dtsi" #include "pmk8550.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts index 34c760549f3e..2fb3798777d1 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts @@ -11,6 +11,7 @@ #include "pm8010.dtsi" #include "pm8550.dtsi" #include "pm8550b.dtsi" +#define PMK8550VE_SID 5 #include "pm8550ve.dtsi" #include "pm8550vs.dtsi" #include "pmk8550.dtsi" From 6fbdb3c1fac7d48f996098254758736e0b47f6b2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:19:59 +0100 Subject: [PATCH 3261/7721] arm64: dts: qcom: sm8650: add initial SM8650 MTP dts Add initial QRD (Qualcomm Reference Device) DT, only boots to shell with USB device support. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-4-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/sm8650-mtp.dts | 446 ++++++++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8650-mtp.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index f8a2ad62629b..96da2baf82ba 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -235,3 +235,4 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx223.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx224.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts new file mode 100644 index 000000000000..51092d20d610 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/dts-v1/; + +#include +#include "sm8650.dtsi" +#include "pm8010.dtsi" +#include "pm8550.dtsi" +#include "pm8550b.dtsi" +#define PMK8550VE_SID 8 +#include "pm8550ve.dtsi" +#include "pm8550vs.dtsi" +#include "pmk8550.dtsi" +#include "pmr735d_a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8650 MTP"; + compatible = "qcom,sm8650-mtp", "qcom,sm8650"; + + aliases { + serial0 = &uart15; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob1>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l11-supply = <&vreg_s1c_1p2>; + vdd-l12-supply = <&vreg_s6c_1p8>; + vdd-l15-supply = <&vreg_s6c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + qcom,pmic-id = "b"; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2720000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l5b_3p1: ldo5 { + regulator-name = "vreg_l5b_3p1"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_1p8: ldo7 { + regulator-name = "vreg_l7b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l8b_1p8: ldo8 { + regulator-name = "vreg_l8b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11b_1p2: ldo11 { + regulator-name = "vreg_l11b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12b_1p8: ldo12 { + regulator-name = "vreg_l12b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l14b_3p2: ldo14 { + regulator-name = "vreg_l14b_3p2"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l16b_2p8: ldo16 { + regulator-name = "vreg_l16b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s1c_1p2>; + vdd-l2-supply = <&vreg_s1c_1p2>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + + qcom,pmic-id = "c"; + + vreg_s1c_1p2: smps1 { + regulator-name = "vreg_s1c_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1348000>; + regulator-initial-mode = ; + }; + + vreg_s2c_0p8: smps2 { + regulator-name = "vreg_s2c_0p8"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1036000>; + regulator-initial-mode = ; + }; + + vreg_s3c_0p9: smps3 { + regulator-name = "vreg_s3c_0p9"; + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_s4c_1p2: smps4 { + regulator-name = "vreg_s4c_1p2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1280000>; + regulator-initial-mode = ; + }; + + vreg_s5c_0p7: smps5 { + regulator-name = "vreg_s5c_0p7"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = ; + }; + + vreg_s6c_1p8: smps6 { + regulator-name = "vreg_s6c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3c_1p2: ldo3 { + regulator-name = "vreg_l3c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "d"; + + vreg_l1d_0p88: ldo1 { + regulator-name = "vreg_l1d_0p88"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-3 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "e"; + + vreg_l3e_0p9: ldo3 { + regulator-name = "vreg_l3e_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-4 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "g"; + + vreg_l1g_0p91: ldo1 { + regulator-name = "vreg_l1g_0p91"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3g_0p91: ldo3 { + regulator-name = "vreg_l3g_0p91"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-5 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l2-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s4-supply = <&vph_pwr>; + + qcom,pmic-id = "i"; + + vreg_s4i_0p85: smps4 { + regulator-name = "vreg_s4i_0p85"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1004000>; + regulator-initial-mode = ; + }; + + vreg_l1i_0p88: ldo1 { + regulator-name = "vreg_l1i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2i_0p88: ldo2 { + regulator-name = "vreg_l2i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3i_1p2: ldo3 { + regulator-name = "vreg_l3i_0p91"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; +}; + +&pm8550b_eusb2_repeater { + vdd18-supply = <&vreg_l15b_1p8>; + vdd3-supply = <&vreg_l5b_3p1>; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&tlmm { + /* Reserved I/Os for NFC */ + gpio-reserved-ranges = <32 8>; +}; + +&uart15 { + status = "okay"; +}; + +/* + * DPAUX -> WCD9395 -> USB_SBU -> USB-C + * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> USB-C + * USB SS -> USB-C + */ + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l1i_0p88>; + vdda12-supply = <&vreg_l3i_1p2>; + + phys = <&pm8550b_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3i_1p2>; + vdda-pll-supply = <&vreg_l3g_0p91>; + + status = "okay"; +}; + +&xo_board { + clock-frequency = <76800000>; +}; From a834911d50c1dda9c3022141e9f9c948e707a0ff Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:20:00 +0100 Subject: [PATCH 3262/7721] arm64: dts: qcom: sm8650: add initial SM8650 QRD dts Add initial QRD (Qualcomm Reference Device) DT, it supports boot to shell with buttons, leds and USB peripheral. Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-5-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/sm8650-qrd.dts | 531 ++++++++++++++++++++++++ 2 files changed, 532 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8650-qrd.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 96da2baf82ba..8d291ab00106 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -236,3 +236,4 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx224.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts new file mode 100644 index 000000000000..4738112f7ad2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/dts-v1/; + +#include +#include +#include "sm8650.dtsi" +#include "pm8010.dtsi" +#include "pm8550.dtsi" +#include "pm8550b.dtsi" +#define PMK8550VE_SID 8 +#include "pm8550ve.dtsi" +#include "pm8550vs.dtsi" +#include "pmk8550.dtsi" +#include "pmr735d_a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8650 QRD"; + compatible = "qcom,sm8650-qrd", "qcom,sm8650"; + + aliases { + serial0 = &uart15; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&volume_up_n>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume Up"; + linux,code = ; + gpios = <&pm8550_gpios 6 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + linux,can-disable; + wakeup-source; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob1>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l11-supply = <&vreg_s1c_1p2>; + vdd-l12-supply = <&vreg_s6c_1p8>; + vdd-l15-supply = <&vreg_s6c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + qcom,pmic-id = "b"; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2720000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5b_3p1: ldo5 { + regulator-name = "vreg_l5b_3p1"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_1p8: ldo7 { + regulator-name = "vreg_l7b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l8b_1p8: ldo8 { + regulator-name = "vreg_l8b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11b_1p2: ldo11 { + regulator-name = "vreg_l11b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12b_1p8: ldo12 { + regulator-name = "vreg_l12b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l14b_3p2: ldo14 { + regulator-name = "vreg_l14b_3p2"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l16b_2p8: ldo16 { + regulator-name = "vreg_l16b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s1c_1p2>; + vdd-l2-supply = <&vreg_s1c_1p2>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + + qcom,pmic-id = "c"; + + vreg_s1c_1p2: smps1 { + regulator-name = "vreg_s1c_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1348000>; + regulator-initial-mode = ; + }; + + vreg_s2c_0p8: smps2 { + regulator-name = "vreg_s2c_0p8"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1036000>; + regulator-initial-mode = ; + }; + + vreg_s3c_0p9: smps3 { + regulator-name = "vreg_s3c_0p9"; + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_s4c_1p2: smps4 { + regulator-name = "vreg_s4c_1p2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1280000>; + regulator-initial-mode = ; + }; + + vreg_s5c_0p7: smps5 { + regulator-name = "vreg_s5c_0p7"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = ; + }; + + vreg_s6c_1p8: smps6 { + regulator-name = "vreg_s6c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3c_1p2: ldo3 { + regulator-name = "vreg_l3c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "d"; + + vreg_l1d_0p88: ldo1 { + regulator-name = "vreg_l1d_0p88"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-3 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "e"; + + vreg_l3e_0p9: ldo3 { + regulator-name = "vreg_l3e_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-4 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "g"; + + vreg_l1g_0p91: ldo1 { + regulator-name = "vreg_l1g_0p91"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3g_0p91: ldo3 { + regulator-name = "vreg_l3g_0p91"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-5 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l2-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s4-supply = <&vph_pwr>; + + qcom,pmic-id = "i"; + + vreg_s4i_0p85: smps4 { + regulator-name = "vreg_s4i_0p85"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1004000>; + regulator-initial-mode = ; + }; + + vreg_l1i_0p88: ldo1 { + regulator-name = "vreg_l1i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2i_0p88: ldo2 { + regulator-name = "vreg_l2i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3i_1p2: ldo3 { + regulator-name = "vreg_l3i_0p91"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + + status = "okay"; +}; + +&pm8550_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>, <4>; + led-max-microamp = <500000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <0>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>, <3>; + led-max-microamp = <500000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <1>; + }; +}; + +&pm8550_gpios { + volume_up_n: volume-up-n-state { + pins = "gpio6"; + function = "normal"; + bias-pull-up; + input-enable; + power-source = <1>; + }; +}; + +&pm8550_pwm { + status = "okay"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + + led@3 { + reg = <3>; + color = ; + }; + }; +}; + +&pm8550b_eusb2_repeater { + vdd18-supply = <&vreg_l15b_1p8>; + vdd3-supply = <&vreg_l5b_3p1>; +}; + +&pmk8550_rtc { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&tlmm { + /* Reserved I/Os for NFC */ + gpio-reserved-ranges = <32 8>; +}; + +&uart15 { + status = "okay"; +}; + +/* + * DPAUX -> WCD9395 -> USB_SBU -> USB-C + * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> WCD9395 -> USB-C + * USB SS -> NB7VPQ904MMUTWG -> USB-C + */ + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l1i_0p88>; + vdda12-supply = <&vreg_l3i_1p2>; + + phys = <&pm8550b_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3i_1p2>; + vdda-pll-supply = <&vreg_l3g_0p91>; + + status = "okay"; +}; + +&xo_board { + clock-frequency = <76800000>; +}; From 10e024671295184fe7556fcb427444b57d2e0ed5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:20:01 +0100 Subject: [PATCH 3263/7721] arm64: dts: qcom: sm8650: add interconnect dependent device nodes Add Hardware nodes that depends on an interconnect property to be valid. The includes: - all QUP i2s/spi nodes - PCIe - UFS - SDHCI - Display - HWMON Acked-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-6-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 2967 +++++++++++++++++++++++++- 1 file changed, 2956 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 1f4c4178544c..d1442b100e79 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -57,6 +59,11 @@ bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { clock-mult = <1>; clock-div = <2>; }; + + pcie_1_phy_aux_clk: pcie-1-phy-aux-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; }; cpus { @@ -363,9 +370,23 @@ CLUSTER_SLEEP_1: cluster-sleep-1 { firmware { scm: scm { compatible = "qcom,scm-sm8650", "qcom,scm"; + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; }; }; + clk_virt: interconnect-0 { + compatible = "qcom,sm8650-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,sm8650-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + memory@a0000000 { device_type = "memory"; /* We expect the bootloader to fill in the size */ @@ -626,6 +647,95 @@ llcc_lpi_mem: llcc-lpi@ff800000 { }; }; + smp2p-adsp { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <443>, <429>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + smp2p_adsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_adsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-cdsp { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <94>, <432>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + smp2p_cdsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_cdsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-modem { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <435>, <428>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + smp2p_modem_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_modem_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + ipa_smp2p_out: ipa-ap-to-modem { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + ipa_smp2p_in: ipa-modem-to-ap { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + soc: soc@0 { compatible = "simple-bus"; @@ -641,13 +751,13 @@ gcc: clock-controller@100000 { clocks = <&bi_tcxo_div2>, <&bi_tcxo_ao_div2>, <&sleep_clk>, - <0>, - <0>, - <0>, - <0>, - <0>, - <0>, - <0>; + <&pcie0_phy>, + <&pcie1_phy>, + <&pcie_1_phy_aux_clk>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; #clock-cells = <1>; #reset-cells = <1>; @@ -712,6 +822,424 @@ qupv3_id_1: geniqup@8c0000 { status = "disabled"; + i2c8: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi8: spi@880000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi8_data_clk>, <&qup_spi8_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c9: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi9: spi@884000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c10: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c10_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi10: spi@888000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c11: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c11_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi11: spi@88c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi11_data_clk>, <&qup_spi11_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c12: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c12_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi12: spi@890000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi12_data_clk>, <&qup_spi12_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c13: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c13_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi13: spi@894000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi13_data_clk>, <&qup_spi13_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + uart14: serial@898000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart14_default>, <&qup_uart14_cts_rts>; + pinctrl-names = "default"; + + status = "disabled"; + }; + uart15: serial@89c000 { compatible = "qcom,geni-debug-uart"; reg = <0 0x0089c000 0 0x4000>; @@ -721,6 +1249,13 @@ uart15: serial@89c000 { clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + pinctrl-0 = <&qup_uart15_default>; pinctrl-names = "default"; @@ -728,6 +1263,290 @@ uart15: serial@89c000 { }; }; + i2c_master_hub_0: geniqup@9c0000 { + compatible = "qcom,geni-se-i2c-master-hub"; + reg = <0 0x009c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_I2C_S_AHB_CLK>; + clock-names = "s-ahb"; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c_hub_0: i2c@980000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00980000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S0_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_1: i2c@984000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00984000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S1_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_2: i2c@988000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00988000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S2_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_3: i2c@98c000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x0098c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S3_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_4: i2c@990000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00990000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S4_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_5: i2c@994000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00994000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S5_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_6: i2c@998000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00998000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S6_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_7: i2c@99c000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x0099c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S7_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_8: i2c@9a0000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x009a0000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S8_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_9: i2c@9a4000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x009a4000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S9_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + gpi_dma1: dma-controller@a00000 { compatible = "qcom,sm8650-gpi-dma", "qcom,sm6350-gpi-dma"; reg = <0 0x00a00000 0 0x60000>; @@ -755,11 +1574,952 @@ gpi_dma1: dma-controller@a00000 { status = "disabled"; }; + qupv3_id_0: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00ac0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core"; + + iommus = <&apps_smmu 0xa3 0>; + + dma-coherent; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c0: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi0: spi@a80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c1: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi1: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi1_data_clk>, <&qup_spi1_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c2: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi2: spi@a88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c3: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi3: spi@a8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi3_data_clk>, <&qup_spi3_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c4: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi4: spi@a90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c5: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi5: spi@a94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi5_data_clk>, <&qup_spi5_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c6: i2c@a98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi6: spi@a98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c7: i2c@a9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi7: spi@a9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>, + <&gpi_dma1 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,sm8650-cnoc-main"; + reg = <0 0x01500000 0 0x14080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,sm8650-config-noc"; + reg = <0 0x01600000 0 0x6200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,sm8650-system-noc"; + reg = <0 0x01680000 0 0x1d080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_noc: interconnect@16c0000 { + compatible = "qcom,sm8650-pcie-anoc"; + reg = <0 0x016c0000 0 0x12200>; + + clocks = <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CFG_NOC_PCIE_ANOC_AHB_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8650-aggre1-noc"; + reg = <0 0x016e0000 0 0x16400>; + + clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1700000 { + compatible = "qcom,sm8650-aggre2-noc"; + reg = <0 0x01700000 0 0x1e400>; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,sm8650-mmss-noc"; + reg = <0 0x01780000 0 0x5b800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + rng: rng@10c3000 { compatible = "qcom,sm8650-trng", "qcom,trng"; reg = <0 0x010c3000 0 0x1000>; }; + pcie0: pci@1c00000 { + device_type = "pci"; + compatible = "qcom,pcie-sm8650", "qcom,pcie-sm8550"; + reg = <0 0x01c00000 0 0x3000>, + <0 0x60000000 0 0xf1d>, + <0 0x60000f20 0 0xa8>, + <0 0x60001000 0 0x1000>, + <0 0x60100000 0 0x100000>; + reg-names = "parf", "dbi", "elbi", "atu", "config"; + + interrupts = ; + interrupt-names = "msi"; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&gcc GCC_DDRSS_PCIE_SF_QTB_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CNOC_PCIE_SF_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "ddrss_sf_tbu", + "noc_aggr", + "cnoc_sf_axi"; + + resets = <&gcc GCC_PCIE_0_BCR>; + reset-names = "pci"; + + interconnects = <&pcie_noc MASTER_PCIE_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc_main SLAVE_PCIE_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + power-domains = <&gcc PCIE_0_GDSC>; + + iommu-map = <0 &apps_smmu 0x1400 0x1>, + <0x100 &apps_smmu 0x1401 0x1>; + + interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map-mask = <0 0 0 0x7>; + #interrupt-cells = <1>; + + linux,pci-domain = <0>; + num-lanes = <2>; + bus-range = <0 0xff>; + + phys = <&pcie0_phy>; + phy-names = "pciephy"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0 0x00000000 0 0x60200000 0 0x100000>, + <0x02000000 0 0x60300000 0 0x60300000 0 0x3d00000>; + + dma-coherent; + + status = "disabled"; + }; + + pcie0_phy: phy@1c06000 { + compatible = "qcom,sm8650-qmp-gen3x2-pcie-phy"; + reg = <0 0x01c06000 0 0x2000>; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&tcsr TCSR_PCIE_0_CLKREF_EN>, + <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe"; + + assigned-clocks = <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; + + power-domains = <&gcc PCIE_0_PHY_GDSC>; + + #clock-cells = <0>; + clock-output-names = "pcie0_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + + pcie1: pci@1c08000 { + device_type = "pci"; + compatible = "qcom,pcie-sm8650", "qcom,pcie-sm8550"; + reg = <0 0x01c08000 0 0x3000>, + <0 0x40000000 0 0xf1d>, + <0 0x40000f20 0 0xa8>, + <0 0x40001000 0 0x1000>, + <0 0x40100000 0 0x100000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config"; + + interrupts = ; + interrupt-names = "msi"; + + clocks = <&gcc GCC_PCIE_1_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_1_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&gcc GCC_DDRSS_PCIE_SF_QTB_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CNOC_PCIE_SF_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "ddrss_sf_tbu", + "noc_aggr", + "cnoc_sf_axi"; + + assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; + assigned-clock-rates = <19200000>; + + resets = <&gcc GCC_PCIE_1_BCR>, + <&gcc GCC_PCIE_1_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + + interconnects = <&pcie_noc MASTER_PCIE_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc_main SLAVE_PCIE_1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + power-domains = <&gcc PCIE_1_GDSC>; + + iommu-map = <0 &apps_smmu 0x1480 0x1>, + <0x100 &apps_smmu 0x1481 0x1>; + + interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 438 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 439 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map-mask = <0 0 0 0x7>; + #interrupt-cells = <1>; + + linux,pci-domain = <1>; + num-lanes = <2>; + bus-range = <0 0xff>; + + phys = <&pcie1_phy>; + phy-names = "pciephy"; + + dma-coherent; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0 0x00000000 0 0x40200000 0 0x100000>, + <0x02000000 0 0x40300000 0 0x40300000 0 0x1fd00000>; + + status = "disabled"; + }; + + pcie1_phy: phy@1c0e000 { + compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy"; + reg = <0 0x01c0e000 0 0x2000>; + + clocks = <&gcc GCC_PCIE_1_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&tcsr TCSR_PCIE_1_CLKREF_EN>, + <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_1_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe"; + + assigned-clocks = <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>, + <&gcc GCC_PCIE_1_NOCSR_COM_PHY_BCR>; + reset-names = "phy", + "phy_nocsr"; + + power-domains = <&gcc PCIE_1_PHY_GDSC>; + + #clock-cells = <0>; + clock-output-names = "pcie1_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0 0x01dc4000 0 0x28000>; + + interrupts = ; + + #dma-cells = <1>; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + + qcom,ee = <0>; + qcom,controlled-remotely; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,sm8650-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0 0x01dfa000 0 0x6000>; + + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "memory"; + + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + }; + + ufs_mem_phy: phy@1d80000 { + compatible = "qcom,sm8650-qmp-ufs-phy"; + reg = <0 0x01d80000 0 0x2000>; + + clocks = <&tcsr TCSR_UFS_CLKREF_EN>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + clock-names = "ref", + "ref_aux"; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + power-domains = <&gcc UFS_MEM_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,sm8650-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; + reg = <0 0x01d84000 0 0x3000>; + + interrupts = ; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&tcsr TCSR_UFS_PAD_CLKREF_EN>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + freq-table-hz = <100000000 403000000>, + <0 0>, + <0 0>, + <100000000 403000000>, + <100000000 403000000>, + <0 0>, + <0 0>, + <0 0>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ufs-ddr", + "cpu-ufs"; + + power-domains = <&gcc UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x60 0>; + + lanes-per-direction = <2>; + qcom,ice = <&ice>; + + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + + #reset-cells = <1>; + + status = "disabled"; + }; + ice: crypto@1d88000 { compatible = "qcom,sm8650-inline-crypto-engine", "qcom,inline-crypto-engine"; @@ -798,6 +2558,432 @@ gpucc: clock-controller@3d90000 { #power-domain-cells = <1>; }; + remoteproc_mpss: remoteproc@4080000 { + compatible = "qcom,sm8650-mpss-pas"; + reg = <0 0x04080000 0 0x4040>; + + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack", + "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_CX>, + <&rpmhpd RPMHPD_MSS>; + power-domain-names = "cx", + "mss"; + + memory-region = <&mpss_mem>, <&q6_mpss_dtb_mem>, + <&mpss_dsm_mem>, <&mpss_dsm_mem_2>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_modem_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <1>; + + label = "mpss"; + }; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,sm8650-lpass-lpiaon-noc"; + reg = <0 0x07400000 0 0x19080>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + lpass_lpicx_noc: interconnect@7430000 { + compatible = "qcom,sm8650-lpass-lpicx-noc"; + reg = <0 0x07430000 0 0x3a200>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,sm8650-lpass-ag-noc"; + reg = <0 0x07e40000 0 0xe080>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + sdhc_2: mmc@8804000 { + compatible = "qcom,sm8650-sdhci", "qcom,sdhci-msm-v5"; + reg = <0 0x08804000 0 0x1000>; + + interrupts = , + ; + interrupt-names = "hc_irq", + "pwr_irq"; + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "core", + "xo"; + + interconnects = <&aggre2_noc MASTER_SDCC_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_SDCC_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; + + power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&sdhc2_opp_table>; + + iommus = <&apps_smmu 0x540 0>; + + bus-width = <4>; + + /* Forbid SDR104/SDR50 - broken hw! */ + sdhci-caps-mask = <0x3 0>; + + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; + + dma-coherent; + + status = "disabled"; + + sdhc2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-202000000 { + opp-hz = /bits/ 64 <202000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss: display-subsystem@ae00000 { + compatible = "qcom,sm8650-mdss"; + reg = <0 0x0ae00000 0 0x1000>; + reg-names = "mdss"; + + interrupts = ; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + + resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; + + interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS + &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ALWAYS>, + <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "mdp1-mem"; + + power-domains = <&dispcc MDSS_GDSC>; + + iommus = <&apps_smmu 0x1c00 0x2>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0 0x0ae01000 0 0x8f000>, + <0 0x0aeb0000 0 0x2008>; + reg-names = "mdp", + "vbif"; + + interrupts-extended = <&mdss 0>; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + + dpu_intf2_out: endpoint { + remote-endpoint = <&mdss_dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@ae94000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae94000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupts-extended = <&mdss 4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&mdss_dsi_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&mdss_dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi0_out: endpoint { + }; + }; + }; + + mdss_dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi0_phy: phy@ae95000 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0 0x0ae95000 0 0x200>, + <0 0x0ae95200 0 0x280>, + <0 0x0ae95500 0 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + mdss_dsi1: dsi@ae96000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae96000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupts-extended = <&mdss 5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>; + + operating-points-v2 = <&mdss_dsi_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&mdss_dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi1_out: endpoint { + }; + }; + }; + }; + + mdss_dsi1_phy: phy@ae97000 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0 0x0ae97000 0 0x200>, + <0 0x0ae97200 0 0x280>, + <0 0x0ae97500 0 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + }; + dispcc: clock-controller@af00000 { compatible = "qcom,sm8650-dispcc"; reg = <0 0x0af00000 0 0x20000>; @@ -806,10 +2992,10 @@ dispcc: clock-controller@af00000 { <&bi_tcxo_ao_div2>, <&gcc GCC_DISP_AHB_CLK>, <&sleep_clk>, - <0>, /* dsi0 */ - <0>, - <0>, /* dsi1 */ - <0>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, <0>, /* dp0 */ <0>, <0>, /* dp1 */ @@ -1079,6 +3265,493 @@ tlmm: pinctrl@f100000 { wakeup-parent = <&pdc>; + hub_i2c0_data_clk: hub-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio64", "gpio65"; + function = "i2chub0_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c1_data_clk: hub-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio66", "gpio67"; + function = "i2chub0_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c2_data_clk: hub-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio68", "gpio69"; + function = "i2chub0_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c3_data_clk: hub-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio70", "gpio71"; + function = "i2chub0_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c4_data_clk: hub-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio72", "gpio73"; + function = "i2chub0_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c5_data_clk: hub-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio74", "gpio75"; + function = "i2chub0_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c6_data_clk: hub-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio76", "gpio77"; + function = "i2chub0_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c7_data_clk: hub-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio78", "gpio79"; + function = "i2chub0_se7"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c8_data_clk: hub-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio206", "gpio207"; + function = "i2chub0_se8"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c9_data_clk: hub-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio80", "gpio81"; + function = "i2chub0_se9"; + drive-strength = <2>; + bias-pull-up; + }; + + pcie0_default_state: pcie0-default-state { + perst-pins { + pins = "gpio94"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq-pins { + pins = "gpio95"; + function = "pcie0_clk_req_n"; + drive-strength = <2>; + bias-pull-up; + }; + + wake-pins { + pins = "gpio96"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_default_state: pcie1-default-state { + perst-pins { + pins = "gpio97"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq-pins { + pins = "gpio98"; + function = "pcie1_clk_req_n"; + drive-strength = <2>; + bias-pull-up; + }; + + wake-pins { + pins = "gpio99"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qup_i2c0_data_clk: qup-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio32", "gpio33"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c1_data_clk: qup-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio36", "gpio37"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c2_data_clk: qup-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio40", "gpio41"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c3_data_clk: qup-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio44", "gpio45"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c4_data_clk: qup-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio48", "gpio49"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c5_data_clk: qup-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio52", "gpio53"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c6_data_clk: qup-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio56", "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c7_data_clk: qup-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio60", "gpio61"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c8_data_clk: qup-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio0", "gpio1"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c9_data_clk: qup-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio4", "gpio5"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c10_data_clk: qup-i2c10-data-clk-state { + /* SDA, SCL */ + pins = "gpio8", "gpio9"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c11_data_clk: qup-i2c11-data-clk-state { + /* SDA, SCL */ + pins = "gpio12", "gpio13"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c12_data_clk: qup-i2c12-data-clk-state { + /* SDA, SCL */ + pins = "gpio16", "gpio17"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c13_data_clk: qup-i2c13-data-clk-state { + /* SDA, SCL */ + pins = "gpio20", "gpio21"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c14_data_clk: qup-i2c14-data-clk-state { + /* SDA, SCL */ + pins = "gpio24", "gpio25"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_spi0_cs: qup-spi0-cs-state { + pins = "gpio35"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi0_data_clk: qup-spi0-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio32", "gpio33", "gpio34"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_cs: qup-spi1-cs-state { + pins = "gpio39"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_data_clk: qup-spi1-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio36", "gpio37", "gpio38"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_cs: qup-spi2-cs-state { + pins = "gpio43"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_data_clk: qup-spi2-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio40", "gpio41", "gpio42"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_cs: qup-spi3-cs-state { + pins = "gpio47"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_data_clk: qup-spi3-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio44", "gpio45", "gpio46"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_cs: qup-spi4-cs-state { + pins = "gpio51"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_data_clk: qup-spi4-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio48", "gpio49", "gpio50"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_cs: qup-spi5-cs-state { + pins = "gpio55"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_data_clk: qup-spi5-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio52", "gpio53", "gpio54"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_cs: qup-spi6-cs-state { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_data_clk: qup-spi6-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio56", "gpio57", "gpio58"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_cs: qup-spi7-cs-state { + pins = "gpio63"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_data_clk: qup-spi7-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio60", "gpio61", "gpio62"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_cs: qup-spi8-cs-state { + pins = "gpio3"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_data_clk: qup-spi8-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio0", "gpio1", "gpio2"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_cs: qup-spi9-cs-state { + pins = "gpio7"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_data_clk: qup-spi9-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio4", "gpio5", "gpio6"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_cs: qup-spi10-cs-state { + pins = "gpio11"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_data_clk: qup-spi10-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio8", "gpio9", "gpio10"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_cs: qup-spi11-cs-state { + pins = "gpio15"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_data_clk: qup-spi11-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio12", "gpio13", "gpio14"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_cs: qup-spi12-cs-state { + pins = "gpio19"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_data_clk: qup-spi12-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio16", "gpio17", "gpio18"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_cs: qup-spi13-cs-state { + pins = "gpio23"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_data_clk: qup-spi13-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio20", "gpio21", "gpio22"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_cs: qup-spi14-cs-state { + pins = "gpio27"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_data_clk: qup-spi14-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio24", "gpio25", "gpio26"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_uart14_default: qup-uart14-default-state { + /* TX, RX */ + pins = "gpio26", "gpio27"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_uart14_cts_rts: qup-uart14-cts-rts-state { + /* CTS, RTS */ + pins = "gpio24", "gpio25"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-down; + }; + qup_uart15_default: qup-uart15-default-state { /* TX, RX */ pins = "gpio30", "gpio31"; @@ -1086,6 +3759,46 @@ qup_uart15_default: qup-uart15-default-state { drive-strength = <2>; bias-disable; }; + + sdc2_sleep: sdc2-sleep-state { + clk-pins { + pins = "sdc2_clk"; + drive-strength = <2>; + bias-disable; + }; + + cmd-pins { + pins = "sdc2_cmd"; + drive-strength = <2>; + bias-pull-up; + }; + + data-pins { + pins = "sdc2_data"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_default: sdc2-default-state { + clk-pins { + pins = "sdc2_clk"; + drive-strength = <16>; + bias-disable; + }; + + cmd-pins { + pins = "sdc2_cmd"; + drive-strength = <10>; + bias-pull-up; + }; + + data-pins { + pins = "sdc2_data"; + drive-strength = <10>; + bias-pull-up; + }; + }; }; apps_smmu: iommu@15000000 { @@ -1437,6 +4150,107 @@ cpufreq_hw: cpufreq@17d91000 { #clock-cells = <1>; }; + pmu@24091000 { + compatible = "qcom,sm8650-llcc-bwmon", "qcom,sc7280-llcc-bwmon"; + reg = <0 0x24091000 0 0x1000>; + + interrupts = ; + + interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&llcc_bwmon_opp_table>; + + llcc_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <2086000>; + }; + + opp-1 { + opp-peak-kBps = <2929000>; + }; + + opp-2 { + opp-peak-kBps = <5931000>; + }; + + opp-3 { + opp-peak-kBps = <6515000>; + }; + + opp-4 { + opp-peak-kBps = <7980000>; + }; + + opp-5 { + opp-peak-kBps = <10437000>; + }; + + opp-6 { + opp-peak-kBps = <12157000>; + }; + + opp-7 { + opp-peak-kBps = <14060000>; + }; + + opp-8 { + opp-peak-kBps = <16113000>; + }; + }; + }; + + pmu@240b7400 { + compatible = "qcom,sm8650-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0 0x240b7400 0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <4577000>; + }; + + opp-1 { + opp-peak-kBps = <7110000>; + }; + + opp-2 { + opp-peak-kBps = <9155000>; + }; + + opp-3 { + opp-peak-kBps = <12298000>; + }; + + opp-4 { + opp-peak-kBps = <14236000>; + }; + + opp-5 { + opp-peak-kBps = <16265000>; + }; + }; + }; + + gem_noc: interconnect@24100000 { + compatible = "qcom,sm8650-gem-noc"; + reg = <0 0x24100000 0 0xc5080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + system-cache-controller@25000000 { compatible = "qcom,sm8650-llcc"; reg = <0 0x25000000 0 0x200000>, @@ -1452,6 +4266,137 @@ system-cache-controller@25000000 { interrupts = ; }; + + remoteproc_adsp: remoteproc@30000000 { + compatible = "qcom,sm8650-adsp-pas"; + reg = <0 0x30000000 0 0x100>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&lpass_lpicx_noc MASTER_LPASS_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_LCX>, + <&rpmhpd RPMHPD_LMX>; + power-domain-names = "lcx", + "lmx"; + + memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + remoteproc_adsp_glink: glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <2>; + + label = "lpass"; + + fastrpc { + compatible = "qcom,fastrpc"; + + qcom,glink-channels = "fastrpcglink-apps-dsp"; + + label = "adsp"; + + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + nsp_noc: interconnect@320c0000 { + compatible = "qcom,sm8650-nsp-noc"; + reg = <0 0x320c0000 0 0xf080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + remoteproc_cdsp: remoteproc@32300000 { + compatible = "qcom,sm8650-cdsp-pas"; + reg = <0 0x32300000 0 0x1400000>; + + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&nsp_noc MASTER_CDSP_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_CX>, + <&rpmhpd RPMHPD_MXC>, + <&rpmhpd RPMHPD_NSP>; + power-domain-names = "cx", + "mxc", + "nsp"; + + memory-region = <&cdsp_mem>, <&q6_cdsp_dtb_mem>, <&global_sync_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_cdsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <5>; + + label = "cdsp"; + + fastrpc { + compatible = "qcom,fastrpc"; + + qcom,glink-channels = "fastrpcglink-apps-dsp"; + + label = "cdsp"; + + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; }; thermal-zones { From deb63527ab248301adc302e21d79c0aae5a827db Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:20:02 +0100 Subject: [PATCH 3264/7721] arm64: dts: qcom: sm8650-mtp: add interconnect dependent device nodes Now interconnect dependent devices are added in sm8650 DTSI, now enable more devices for the Qualcomm SM8650 MTP board: - PCIe - Display - DSPs - SDCard - UFS - USB role switch with PMIC Glink Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-7-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650-mtp.dts | 235 +++++++++++++++++++++++- 1 file changed, 234 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts index 51092d20d610..656cdbc6f234 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -28,6 +28,44 @@ chosen { stdout-path = "serial0:115200n8"; }; + pmic-glink { + compatible = "qcom,sm8650-pmic-glink", + "qcom,sm8550-pmic-glink", + "qcom,pmic-glink"; + #address-cells = <1>; + #size-cells = <0>; + orientation-gpios = <&tlmm 29 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + }; + }; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; @@ -77,6 +115,9 @@ vreg_l2b_3p0: ldo2 { regulator-min-microvolt = <3008000>; regulator-max-microvolt = <3008000>; regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; }; vreg_l5b_3p1: ldo5 { @@ -389,6 +430,106 @@ vreg_l3i_1p2: ldo3 { }; }; +&dispcc { + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l3i_1p2>; + + status = "okay"; + + panel@0 { + compatible = "visionox,vtdr6130"; + reg = <0>; + + reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>; + + vddio-supply = <&vreg_l12b_1p8>; + vci-supply = <&vreg_l13b_3p0>; + vdd-supply = <&vreg_l11b_1p2>; + + pinctrl-0 = <&disp0_reset_n_active>, <&mdp_vsync_active>; + pinctrl-1 = <&disp0_reset_n_suspend>, <&mdp_vsync_suspend>; + pinctrl-names = "default", "sleep"; + + port { + panel0_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + remote-endpoint = <&panel0_in>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&mdss_mdp { + status = "okay"; +}; + +&pcie_1_phy_aux_clk { + clock-frequency = <1000>; +}; + +&pcie0 { + wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l1i_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + +&pcie1 { + wake-gpios = <&tlmm 99 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 97 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie1_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l3e_0p9>; + vdda-pll-supply = <&vreg_l3i_1p2>; + vdda-qref-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&pm8550_gpios { + sdc2_card_det_n: sdc2-card-det-state { + pins = "gpio12"; + function = "normal"; + bias-pull-up; + input-enable; + output-disable; + power-source = <1>; /* 1.8 V */ + }; +}; + &pm8550b_eusb2_repeater { vdd18-supply = <&vreg_l15b_1p8>; vdd3-supply = <&vreg_l5b_3p1>; @@ -398,6 +539,43 @@ &qupv3_id_1 { status = "okay"; }; +&remoteproc_adsp { + firmware-name = "qcom/sm8650/adsp.mbn", + "qcom/sm8650/adsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/sm8650/cdsp.mbn", + "qcom/sm8650/cdsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/sm8650/modem.mbn", + "qcom/sm8650/modem_dtb.mbn"; + + status = "okay"; +}; + +&sdhc_2 { + cd-gpios = <&pm8550_gpios 12 GPIO_ACTIVE_LOW>; + + vmmc-supply = <&vreg_l9b_2p9>; + vqmmc-supply = <&vreg_l8b_1p8>; + bus-width = <4>; + no-sdio; + no-mmc; + + pinctrl-0 = <&sdc2_default>, <&sdc2_card_det_n>; + pinctrl-1 = <&sdc2_sleep>, <&sdc2_card_det_n>; + pinctrl-names = "default", "sleep"; + + status = "okay"; +}; + &sleep_clk { clock-frequency = <32000>; }; @@ -405,12 +583,58 @@ &sleep_clk { &tlmm { /* Reserved I/Os for NFC */ gpio-reserved-ranges = <32 8>; + + disp0_reset_n_active: disp0-reset-n-active-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + disp0_reset_n_suspend: disp0-reset-n-suspend-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_active: mdp-vsync-active-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_suspend: mdp-vsync-suspend-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; }; &uart15 { status = "okay"; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1300000>; + vccq-supply = <&vreg_l1c_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l1d_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + /* * DPAUX -> WCD9395 -> USB_SBU -> USB-C * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> USB-C @@ -422,7 +646,16 @@ &usb_1 { }; &usb_1_dwc3 { - dr_mode = "peripheral"; + dr_mode = "otg"; + usb-role-switch; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_dwc3_ss { + remote-endpoint = <&pmic_glink_ss_in>; }; &usb_1_hsphy { From 0c5b1016b5f30eb2313f942abef5bd7a7be12ae8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 30 Nov 2023 11:20:03 +0100 Subject: [PATCH 3265/7721] arm64: dts: qcom: sm8650-qrd: add interconnect dependent device nodes Now interconnect dependent devices are added in sm8650 DTSI, now enable more devices for the Qualcomm SM8650 QRD board: - PCIe - Display - DSPs - SDCard - UFS - USB role switch with PMIC Glink - Bluetooth Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231130-topic-sm8650-upstream-dt-v5-8-b25fb781da52@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650-qrd.dts | 275 +++++++++++++++++++++++- 1 file changed, 274 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts index 4738112f7ad2..e69ae61b6111 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -23,6 +23,7 @@ / { aliases { serial0 = &uart15; + serial1 = &uart14; }; chosen { @@ -45,6 +46,44 @@ key-volume-up { }; }; + pmic-glink { + compatible = "qcom,sm8650-pmic-glink", + "qcom,sm8550-pmic-glink", + "qcom,pmic-glink"; + #address-cells = <1>; + #size-cells = <0>; + orientation-gpios = <&tlmm 29 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + }; + }; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; @@ -399,6 +438,81 @@ vreg_l3i_1p2: ldo3 { }; }; +&dispcc { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l3i_1p2>; + + status = "okay"; + + panel@0 { + compatible = "visionox,vtdr6130"; + reg = <0>; + + reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>; + + vddio-supply = <&vreg_l12b_1p8>; + vci-supply = <&vreg_l13b_3p0>; + vdd-supply = <&vreg_l11b_1p2>; + + pinctrl-0 = <&disp0_reset_n_active>, <&mdp_vsync_active>; + pinctrl-1 = <&disp0_reset_n_suspend>, <&mdp_vsync_suspend>; + pinctrl-names = "default", "sleep"; + + port { + panel0_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + remote-endpoint = <&panel0_in>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&mdss_mdp { + status = "okay"; +}; + +&pcie_1_phy_aux_clk { + clock-frequency = <1000>; +}; + +&pcie0 { + wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l1i_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + &pon_pwrkey { status = "okay"; }; @@ -479,23 +593,173 @@ &pmk8550_rtc { status = "okay"; }; +&qupv3_id_0 { + status = "okay"; +}; + &qupv3_id_1 { status = "okay"; }; +&remoteproc_adsp { + firmware-name = "qcom/sm8650/adsp.mbn", + "qcom/sm8650/adsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/sm8650/cdsp.mbn", + "qcom/sm8650/cdsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/sm8650/modem.mbn", + "qcom/sm8650/modem_dtb.mbn"; + + status = "okay"; +}; + &sleep_clk { clock-frequency = <32000>; }; +&spi4 { + status = "okay"; + + touchscreen@0 { + compatible = "goodix,gt9916"; + reg = <0>; + + interrupt-parent = <&tlmm>; + interrupts = <162 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&tlmm 161 GPIO_ACTIVE_LOW>; + + avdd-supply = <&vreg_l14b_3p2>; + + spi-max-frequency = <1000000>; + + touchscreen-size-x = <1080>; + touchscreen-size-y = <2400>; + + pinctrl-0 = <&ts_irq>, <&ts_reset>; + pinctrl-names = "default"; + }; +}; + &tlmm { /* Reserved I/Os for NFC */ gpio-reserved-ranges = <32 8>; + + bt_default: bt-default-state { + bt-en-pins { + pins = "gpio17"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + sw-ctrl-pins { + pins = "gpio18"; + function = "gpio"; + bias-pull-down; + }; + }; + + disp0_reset_n_active: disp0-reset-n-active-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + disp0_reset_n_suspend: disp0-reset-n-suspend-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_active: mdp-vsync-active-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_suspend: mdp-vsync-suspend-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_irq: ts-irq-state { + pins = "gpio161"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + output-disable; + }; + + ts_reset: ts-reset-state { + pins = "gpio162"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; + +&uart14 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn7850-bt"; + + clocks = <&rpmhcc RPMH_RF_CLK1>; + + vddio-supply = <&vreg_l3c_1p2>; + vddaon-supply = <&vreg_l15b_1p8>; + vdddig-supply = <&vreg_s3c_0p9>; + vddrfa0p8-supply = <&vreg_s3c_0p9>; + vddrfa1p2-supply = <&vreg_s1c_1p2>; + vddrfa1p9-supply = <&vreg_s6c_1p8>; + + max-speed = <3200000>; + + enable-gpios = <&tlmm 17 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&bt_default>; + pinctrl-names = "default"; + }; }; &uart15 { status = "okay"; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1300000>; + vccq-supply = <&vreg_l1c_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l1d_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + /* * DPAUX -> WCD9395 -> USB_SBU -> USB-C * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> WCD9395 -> USB-C @@ -507,7 +771,16 @@ &usb_1 { }; &usb_1_dwc3 { - dr_mode = "peripheral"; + dr_mode = "otg"; + usb-role-switch; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_dwc3_ss { + remote-endpoint = <&pmic_glink_ss_in>; }; &usb_1_hsphy { From 9fdddbd134a68843364c3e8c57fbdc5da2a7083d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 1 Dec 2023 14:50:41 +0100 Subject: [PATCH 3266/7721] arm64: dts: qcom: sm8650: add IPA information Add IPA-related nodes and definitions to SM8650 dtsi, which uses IPA v5.5.1 a minor revision of v5.5 found in the SM8550 SoC. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231201-topic-sm8650-upstream-ipa-v1-1-7e8cf7200cd2@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index d1442b100e79..e52c4a2c4282 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -2558,6 +2558,45 @@ gpucc: clock-controller@3d90000 { #power-domain-cells = <1>; }; + ipa: ipa@3f40000 { + compatible = "qcom,sm8650-ipa", "qcom,sm8550-ipa"; + + iommus = <&apps_smmu 0x4a0 0x0>, + <&apps_smmu 0x4a2 0x0>; + reg = <0 0x3f40000 0 0x10000>, + <0 0x3f50000 0 0x5000>, + <0 0x3e04000 0 0xfc000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 654 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>, + <&ipa_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&ipa_smp2p_in 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ipa", + "gsi", + "ipa-clock-query", + "ipa-setup-ready"; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + clock-names = "core"; + + interconnects = <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; + interconnect-names = "memory", + "config"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + remoteproc_mpss: remoteproc@4080000 { compatible = "qcom,sm8650-mpss-pas"; reg = <0 0x04080000 0 0x4040>; From 83c054b913cf6accd4cb31cee51729b322bde7fb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 1 Dec 2023 14:50:42 +0100 Subject: [PATCH 3267/7721] arm64: dts: qcom: sm8650-qrd: enable IPA Enable IPA on the SM8650 QRD. The GSI firmware on this platform is loaded by the AP. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231201-topic-sm8650-upstream-ipa-v1-2-7e8cf7200cd2@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650-qrd.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts index e69ae61b6111..592a67a47c78 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -446,6 +446,13 @@ &gpi_dma1 { status = "okay"; }; +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/sm8650/ipa_fws.mbn"; + status = "okay"; +}; + &mdss { status = "okay"; }; From ff28260e3d9820a22d9bf826bdf219d6efa97260 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Dec 2023 16:57:42 +0100 Subject: [PATCH 3268/7721] arm64: dts: qcom: sm8650: add ADSP GPR Add the ADSP Generic Packet Router (GPR) device node as part of audio subsystem in Qualcomm SM8650 SoC. Cc: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204155746.302323-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index e52c4a2c4282..bcfe38a960c7 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -4363,6 +4363,46 @@ fastrpc { #address-cells = <1>; #size-cells = <0>; }; + + gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "adsp_apps"; + qcom,domain = ; + qcom,intents = <512 20>; + #address-cells = <1>; + #size-cells = <0>; + + q6apm: service@1 { + compatible = "qcom,q6apm"; + reg = ; + #sound-dai-cells = <0>; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6apmbedai: bedais { + compatible = "qcom,q6apm-lpass-dais"; + #sound-dai-cells = <1>; + }; + + q6apmdai: dais { + compatible = "qcom,q6apm-dais"; + iommus = <&apps_smmu 0x1001 0x80>, + <&apps_smmu 0x1061 0x0>; + }; + }; + + q6prm: service@2 { + compatible = "qcom,q6prm"; + reg = ; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6prmcc: clock-controller { + compatible = "qcom,q6prm-lpass-clocks"; + #clock-cells = <2>; + }; + }; + }; }; }; From 2d6bc13321c90217e1ffecf50a183f20c00ec3e3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Dec 2023 16:57:43 +0100 Subject: [PATCH 3269/7721] arm64: dts: qcom: sm8650: add LPASS LPI pin controller Add the Low Power Audio SubSystem Low Power Island (LPASS LPI) pin controller device node as part of audio subsystem in Qualcomm SM8650 SoC. Cc: Neil Armstrong Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204155746.302323-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index bcfe38a960c7..be65e8f4c4f9 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include #include / { @@ -2649,6 +2650,19 @@ IPCC_MPROC_SIGNAL_GLINK_QMP }; }; + lpass_tlmm: pinctrl@6e80000 { + compatible = "qcom,sm8650-lpass-lpi-pinctrl"; + reg = <0 0x06e80000 0 0x20000>; + + clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "core", "audio"; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&lpass_tlmm 0 0 23>; + }; + lpass_lpiaon_noc: interconnect@7400000 { compatible = "qcom,sm8650-lpass-lpiaon-noc"; reg = <0 0x07400000 0 0x19080>; From 58872a54e4a858d86301b4fb802fd60c45aad3e1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Dec 2023 16:57:44 +0100 Subject: [PATCH 3270/7721] arm64: dts: qcom: sm8650: add ADSP audio codec macros Add the Low Power Audio SubSystem (LPASS) / ADSP audio codec macros on Qualcomm SM8650. The nodes are very similar to SM8550. Cc: Neil Armstrong Signed-off-by: Krzysztof Kozlowski Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231204155746.302323-3-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index be65e8f4c4f9..d1ba582f5bb9 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -2650,6 +2650,92 @@ IPCC_MPROC_SIGNAL_GLINK_QMP }; }; + lpass_wsa2macro: codec@6aa0000 { + compatible = "qcom,sm8650-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro"; + reg = <0 0x06aa0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "wsa2-mclk"; + #sound-dai-cells = <1>; + }; + + lpass_rxmacro: codec@6ac0000 { + compatible = "qcom,sm8650-lpass-rx-macro", "qcom,sm8550-lpass-rx-macro"; + reg = <0 0x06ac0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + lpass_txmacro: codec@6ae0000 { + compatible = "qcom,sm8650-lpass-tx-macro", "qcom,sm8550-lpass-tx-macro"; + reg = <0 0x06ae0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + lpass_wsamacro: codec@6b00000 { + compatible = "qcom,sm8650-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro"; + reg = <0 0x06b00000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + assigned-clock-rates = <19200000>; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + lpass_vamacro: codec@6d44000 { + compatible = "qcom,sm8650-lpass-va-macro", "qcom,sm8550-lpass-va-macro"; + reg = <0 0x06d44000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "mclk", + "macro", + "dcodec"; + + #clock-cells = <0>; + clock-output-names = "fsgen"; + #sound-dai-cells = <1>; + }; + lpass_tlmm: pinctrl@6e80000 { compatible = "qcom,sm8650-lpass-lpi-pinctrl"; reg = <0 0x06e80000 0 0x20000>; From 6a45a90c0c475bf6bf573c4ba89e0415506c868a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Dec 2023 16:57:45 +0100 Subject: [PATCH 3271/7721] arm64: dts: qcom: sm8650: add Soundwire controllers Add nodes for LPASS Soundwire v2.0.0 controllers. Use labels with indices matching downstream DTS, to make any comparisons easier. Cc: Neil Armstrong Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204155746.302323-4-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 226 +++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index d1ba582f5bb9..af5e0a75b0ab 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -2667,6 +2667,36 @@ lpass_wsa2macro: codec@6aa0000 { #sound-dai-cells = <1>; }; + swr3: soundwire@6ab0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ab0000 0 0x10000>; + interrupts = ; + clocks = <&lpass_wsa2macro>; + clock-names = "iface"; + label = "WSA2"; + + pinctrl-0 = <&wsa2_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <9>; + + qcom,ports-sinterval = /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>; + qcom,ports-offset1 = /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>; + qcom,ports-offset2 = /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>; + qcom,ports-block-pack-mode = /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + lpass_rxmacro: codec@6ac0000 { compatible = "qcom,sm8650-lpass-rx-macro", "qcom,sm8550-lpass-rx-macro"; reg = <0 0x06ac0000 0 0x1000>; @@ -2684,6 +2714,36 @@ lpass_rxmacro: codec@6ac0000 { #sound-dai-cells = <1>; }; + swr1: soundwire@6ad0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ad0000 0 0x10000>; + interrupts = ; + clocks = <&lpass_rxmacro>; + clock-names = "iface"; + label = "RX"; + + pinctrl-0 = <&rx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <0>; + qcom,dout-ports = <11>; + + qcom,ports-sinterval = /bits/ 16 <0x03 0x1f 0x1f 0x07 0x03 0xff 0xff 0x31 0xff 0xff 0xff>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x09 0x01 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0xff 0xff 0x0f 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0xff 0xff 0x18 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0xff 0xff 0x01 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0x01 0x03 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0xff 0xff 0x01 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + lpass_txmacro: codec@6ae0000 { compatible = "qcom,sm8650-lpass-tx-macro", "qcom,sm8550-lpass-tx-macro"; reg = <0 0x06ae0000 0 0x1000>; @@ -2721,6 +2781,68 @@ lpass_wsamacro: codec@6b00000 { #sound-dai-cells = <1>; }; + swr0: soundwire@6b10000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06b10000 0 0x10000>; + interrupts = ; + clocks = <&lpass_wsamacro>; + clock-names = "iface"; + label = "WSA"; + + pinctrl-0 = <&wsa_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <9>; + + qcom,ports-sinterval = /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>; + qcom,ports-offset1 = /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>; + qcom,ports-offset2 = /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>; + qcom,ports-block-pack-mode = /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + + swr2: soundwire@6d30000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06d30000 0 0x10000>; + interrupts = , + ; + interrupt-names = "core", "wakeup"; + clocks = <&lpass_txmacro>; + clock-names = "iface"; + label = "TX"; + + pinctrl-0 = <&tx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <0>; + + qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x01 0x01>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x02 0x00 0x00>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + lpass_vamacro: codec@6d44000 { compatible = "qcom,sm8650-lpass-va-macro", "qcom,sm8550-lpass-va-macro"; reg = <0 0x06d44000 0 0x1000>; @@ -2747,6 +2869,110 @@ lpass_tlmm: pinctrl@6e80000 { gpio-controller; #gpio-cells = <2>; gpio-ranges = <&lpass_tlmm 0 0 23>; + + tx_swr_active: tx-swr-active-state { + clk-pins { + pins = "gpio0"; + function = "swr_tx_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio1", "gpio2", "gpio14"; + function = "swr_tx_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_active: rx-swr-active-state { + clk-pins { + pins = "gpio3"; + function = "swr_rx_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio4", "gpio5"; + function = "swr_rx_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + dmic01_default: dmic01-default-state { + clk-pins { + pins = "gpio6"; + function = "dmic1_clk"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio7"; + function = "dmic1_data"; + drive-strength = <8>; + input-enable; + }; + }; + + dmic02_default: dmic02-default-state { + clk-pins { + pins = "gpio8"; + function = "dmic2_clk"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio9"; + function = "dmic2_data"; + drive-strength = <8>; + input-enable; + }; + }; + + wsa_swr_active: wsa-swr-active-state { + clk-pins { + pins = "gpio10"; + function = "wsa_swr_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio11"; + function = "wsa_swr_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + wsa2_swr_active: wsa2-swr-active-state { + clk-pins { + pins = "gpio15"; + function = "wsa2_swr_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio16"; + function = "wsa2_swr_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; }; lpass_lpiaon_noc: interconnect@7400000 { From 80627a5d72b6be2652920db402fe2477f086902b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Dec 2023 16:57:46 +0100 Subject: [PATCH 3272/7721] arm64: dts: qcom: sm8650-mtp: add WSA8845 speakers Add nodes for WSA8845 speakers on SM8650 MTP board. Cc: Neil Armstrong Reviewed-by: Konrad Dybcio Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231204155746.302323-5-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650-mtp.dts | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts index 656cdbc6f234..9d916edb1c73 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -434,6 +434,16 @@ &dispcc { status = "okay"; }; +&lpass_tlmm { + spkr_1_sd_n_active: spkr-1-sd-n-active-state { + pins = "gpio21"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-low; + }; +}; + &mdss { status = "okay"; }; @@ -580,6 +590,36 @@ &sleep_clk { clock-frequency = <32000>; }; +&swr0 { + status = "okay"; + + /* WSA8845, Speaker Left */ + left_spkr: speaker@0,0 { + compatible = "sdw20217020400"; + reg = <0 0>; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-names = "default"; + powerdown-gpios = <&lpass_tlmm 21 GPIO_ACTIVE_LOW>; + #sound-dai-cells = <0>; + sound-name-prefix = "SpkrLeft"; + vdd-1p8-supply = <&vreg_l15b_1p8>; + vdd-io-supply = <&vreg_l3c_1p2>; + }; + + /* WSA8845, Speaker Right */ + right_spkr: speaker@0,1 { + compatible = "sdw20217020400"; + reg = <0 1>; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-names = "default"; + powerdown-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + #sound-dai-cells = <0>; + sound-name-prefix = "SpkrRight"; + vdd-1p8-supply = <&vreg_l15b_1p8>; + vdd-io-supply = <&vreg_l3c_1p2>; + }; +}; + &tlmm { /* Reserved I/Os for NFC */ gpio-reserved-ranges = <32 8>; @@ -611,6 +651,14 @@ mdp_vsync_suspend: mdp-vsync-suspend-state { drive-strength = <2>; bias-pull-down; }; + + spkr_2_sd_n_active: spkr-2-sd-n-active-state { + pins = "gpio77"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-low; + }; }; &uart15 { From a1c95dd5bc1d6a5d7a75a376c2107421b7d6240d Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Mon, 27 Nov 2023 11:47:10 +0800 Subject: [PATCH 3273/7721] crypto: ccp - fix memleak in ccp_init_dm_workarea When dma_map_single() fails, wa->address is supposed to be freed by the callers of ccp_init_dm_workarea() through ccp_dm_free(). However, many of the call spots don't expect to have to call ccp_dm_free() on failure of ccp_init_dm_workarea(), which may lead to a memleak. Let's free wa->address in ccp_init_dm_workarea() when dma_map_single() fails. Fixes: 63b945091a07 ("crypto: ccp - CCP device driver and interface support") Signed-off-by: Dinghao Liu Acked-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index aa4e1a500691..cb8e99936abb 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -179,8 +179,11 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, wa->dma.address = dma_map_single(wa->dev, wa->address, len, dir); - if (dma_mapping_error(wa->dev, wa->dma.address)) + if (dma_mapping_error(wa->dev, wa->dma.address)) { + kfree(wa->address); + wa->address = NULL; return -ENOMEM; + } wa->dma.length = len; } From 431a2eb89cf664a9cf94f519402896f10d074db0 Mon Sep 17 00:00:00 2001 From: Longfang Liu Date: Mon, 27 Nov 2023 19:24:49 +0800 Subject: [PATCH 3274/7721] MAINTAINERS: update SEC2/HPRE driver maintainers list Kai Ye is no longer participates in the Linux community. Zhiqi Song will be responsible for the code maintenance of the HPRE module. Therefore, the maintainers list needs to be updated. Signed-off-by: Longfang Liu Reviewed-by: Zhiqi Song Signed-off-by: Herbert Xu --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 97f51d5ec1cf..de394b632b99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9542,6 +9542,7 @@ F: Documentation/devicetree/bindings/gpio/hisilicon,ascend910-gpio.yaml F: drivers/gpio/gpio-hisi.c HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE) +M: Zhiqi Song M: Longfang Liu L: linux-crypto@vger.kernel.org S: Maintained @@ -9642,7 +9643,6 @@ F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt F: drivers/scsi/hisi_sas/ HISILICON SECURITY ENGINE V2 DRIVER (SEC2) -M: Kai Ye M: Longfang Liu L: linux-crypto@vger.kernel.org S: Maintained From 67b164a871af1d736f131fd6fe78a610909f06f3 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 28 Nov 2023 16:25:49 +0800 Subject: [PATCH 3275/7721] crypto: af_alg - Disallow multiple in-flight AIO requests Having multiple in-flight AIO requests results in unpredictable output because they all share the same IV. Fix this by only allowing one request at a time. Fixes: 83094e5e9e49 ("crypto: af_alg - add async support to algif_aead") Fixes: a596999b7ddf ("crypto: algif - change algif_skcipher to be asynchronous") Signed-off-by: Herbert Xu --- crypto/af_alg.c | 14 +++++++++++++- include/crypto/if_alg.h | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ea6fb8e89d06..68cc9290cabe 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1116,9 +1116,13 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); void af_alg_free_resources(struct af_alg_async_req *areq) { struct sock *sk = areq->sk; + struct af_alg_ctx *ctx; af_alg_free_areq_sgls(areq); sock_kfree_s(sk, areq, areq->areqlen); + + ctx = alg_sk(sk)->private; + ctx->inflight = false; } EXPORT_SYMBOL_GPL(af_alg_free_resources); @@ -1188,11 +1192,19 @@ EXPORT_SYMBOL_GPL(af_alg_poll); struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, unsigned int areqlen) { - struct af_alg_async_req *areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); + struct af_alg_ctx *ctx = alg_sk(sk)->private; + struct af_alg_async_req *areq; + /* Only one AIO request can be in flight. */ + if (ctx->inflight) + return ERR_PTR(-EBUSY); + + areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); if (unlikely(!areq)) return ERR_PTR(-ENOMEM); + ctx->inflight = true; + areq->areqlen = areqlen; areq->sk = sk; areq->first_rsgl.sgl.sgt.sgl = areq->first_rsgl.sgl.sgl; diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index ef8ce86b1f78..08b803a4fcde 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -136,6 +136,7 @@ struct af_alg_async_req { * recvmsg is invoked. * @init: True if metadata has been sent. * @len: Length of memory allocated for this data structure. + * @inflight: Non-zero when AIO requests are in flight. */ struct af_alg_ctx { struct list_head tsgl_list; @@ -154,6 +155,8 @@ struct af_alg_ctx { bool init; unsigned int len; + + unsigned int inflight; }; int af_alg_register_type(const struct af_alg_type *type); From 6627f03c21cb7001ae4dbbfb7a8514516d02331c Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Tue, 28 Nov 2023 18:37:32 +0100 Subject: [PATCH 3276/7721] crypto: qat - fix error path in add_update_sla() The input argument `sla_in` is a pointer to a structure that contains the parameters of the SLA which is being added or updated. If this pointer is NULL, the function should return an error as the data required for the algorithm is not available. By mistake, the logic jumps to the error path which dereferences the pointer. This results in a warnings reported by the static analyzer Smatch when executed without a database: drivers/crypto/intel/qat/qat_common/adf_rl.c:871 add_update_sla() error: we previously assumed 'sla_in' could be null (see line 812) This issue was not found in internal testing as the pointer cannot be NULL. The function add_update_sla() is only called (indirectly) by the rate limiting sysfs interface implementation in adf_sysfs_rl.c which ensures that the data structure is allocated and valid. This is also proven by the fact that Smatch executed with a database does not report such error. Fix it by returning with error if the pointer `sla_in` is NULL. Fixes: d9fb8408376e ("crypto: qat - add rate limiting feature to qat_4xxx") Reported-by: Dan Carpenter Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_rl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.c b/drivers/crypto/intel/qat/qat_common/adf_rl.c index 86e3e2152b1b..f2de3cd7d05d 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.c @@ -812,8 +812,7 @@ static int add_update_sla(struct adf_accel_dev *accel_dev, if (!sla_in) { dev_warn(&GET_DEV(accel_dev), "SLA input data pointer is missing\n"); - ret = -EFAULT; - goto ret_err; + return -EFAULT; } /* Input validation */ From 487caa8d5ef9a9a27b092c5790d529a7a0c24f8b Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Tue, 28 Nov 2023 18:39:30 +0100 Subject: [PATCH 3277/7721] crypto: qat - fix mutex ordering in adf_rl If the function validate_user_input() returns an error, the error path attempts to unlock an unacquired mutex. Acquire the mutex before calling validate_user_input(). This is not strictly necessary but simplifies the code. Fixes: d9fb8408376e ("crypto: qat - add rate limiting feature to qat_4xxx") Signed-off-by: Damian Muszynski Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_rl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.c b/drivers/crypto/intel/qat/qat_common/adf_rl.c index f2de3cd7d05d..de1b214dba1f 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.c @@ -815,13 +815,13 @@ static int add_update_sla(struct adf_accel_dev *accel_dev, return -EFAULT; } + mutex_lock(&rl_data->rl_lock); + /* Input validation */ ret = validate_user_input(accel_dev, sla_in, is_update); if (ret) goto ret_err; - mutex_lock(&rl_data->rl_lock); - if (is_update) { ret = validate_sla_id(accel_dev, sla_in->sla_id); if (ret) From a643212c9f28d09225c3792c316bc4aaf6be4a68 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Tue, 28 Nov 2023 19:17:25 +0000 Subject: [PATCH 3278/7721] crypto: qat - add NULL pointer check There is a possibility that the function adf_devmgr_pci_to_accel_dev() might return a NULL pointer. Add a NULL pointer check in the function rp2srv_show(). Fixes: dbc8876dd873 ("crypto: qat - add rp2svc sysfs attribute") Signed-off-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Reviewed-by: David Guckian Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c index 6f0b3629da13..d450dad32c9e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c @@ -215,6 +215,9 @@ static ssize_t rp2srv_show(struct device *dev, struct device_attribute *attr, enum adf_cfg_service_type svc; accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + hw_data = GET_HW_DATA(accel_dev); if (accel_dev->sysfs.ring_num == UNSET_RING_NUM) From 040791041b68fbc06511834b225c5974daa5088b Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Wed, 29 Nov 2023 21:11:33 +0530 Subject: [PATCH 3279/7721] crypto: octeontx2 - By default allocate one CPT LF per CPT VF There are limited number CPT LFs (example 64 LFs on cn10k) and these LFs are allocated/attached to CPT VF on its creation. cptpf sysfs parameter "kvf_limits" defines number of CPT LFs per CPT VF. Default "kvf_limits" is initialized to zero and if kvf_limits is zero then number of LF allocated are equal to online cpus in system. For example on 24 core system, 24 CPT LFs will be attached per VF. That means no CPT LF available when creating more than 2 CPT VFs on system which have total 64 LFs. Although VFs gets created but no LF attached to it. There seems no reason to default allocate as many LFs as many online cpus in system. This patch initializes "kvf_limits" to one to limit one LF allocated per CPT VF. "kvf_limits" can be changed in range of 1 to number-of-online-cpus via sysfs. Signed-off-by: Bharat Bhushan Signed-off-by: Herbert Xu --- drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c | 1 + drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index e34223daa327..b13df6a49644 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -797,6 +797,7 @@ static int otx2_cptpf_probe(struct pci_dev *pdev, goto destroy_afpf_mbox; cptpf->max_vfs = pci_sriov_get_totalvfs(pdev); + cptpf->kvf_limits = 1; err = cn10k_cptpf_lmtst_init(cptpf); if (err) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c index bac729c885f9..69a447d3702c 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c @@ -277,8 +277,7 @@ static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) if (ret) return ret; - lfs_num = cptvf->lfs.kvf_limits ? cptvf->lfs.kvf_limits : - num_online_cpus(); + lfs_num = cptvf->lfs.kvf_limits; otx2_cptlf_set_dev_info(lfs, cptvf->pdev, cptvf->reg_base, &cptvf->pfvf_mbox, cptvf->blkaddr); From 429fec81d12266e6402868672de8c68bf4d8db13 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 1 Dec 2023 16:20:48 +0800 Subject: [PATCH 3280/7721] hwrng: stm32 - add missing clk_disable_unprepare() in stm32_rng_init() Add clk_disable_unprepare() in the error path in stm32_rng_init(). Fixes: 6b85a7e141cb ("hwrng: stm32 - implement STM32MP13x support") Signed-off-by: Yang Yingliang Reviewed-by: Gatien Chevallier Signed-off-by: Herbert Xu --- drivers/char/hw_random/stm32-rng.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c index 41e1dbea5d2e..efd6edcd7066 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -325,6 +325,7 @@ static int stm32_rng_init(struct hwrng *rng) (!(reg & RNG_CR_CONDRST)), 10, 50000); if (err) { + clk_disable_unprepare(priv->clk); dev_err((struct device *)priv->rng.priv, "%s: timeout %x!\n", __func__, reg); return -EINVAL; From 87e02063d07708cac5bfe9fd3a6a242898758ac8 Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Fri, 1 Dec 2023 04:49:29 -0800 Subject: [PATCH 3281/7721] crypto: safexcel - Add error handling for dma_map_sg() calls Macro dma_map_sg() may return 0 on error. This patch enables checks in case of the macro failure and ensures unmapping of previously mapped buffers with dma_unmap_sg(). Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: 49186a7d9e46 ("crypto: inside_secure - Avoid dma map if size is zero") Signed-off-by: Nikita Zhandarovich Reviewed-by: Antoine Tenart Signed-off-by: Herbert Xu --- .../crypto/inside-secure/safexcel_cipher.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index 272c28b5a088..b83818634ae4 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -742,9 +742,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, max(totlen_src, totlen_dst)); return -EINVAL; } - if (sreq->nr_src > 0) - dma_map_sg(priv->dev, src, sreq->nr_src, - DMA_BIDIRECTIONAL); + if (sreq->nr_src > 0 && + !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL)) + return -EIO; } else { if (unlikely(totlen_src && (sreq->nr_src <= 0))) { dev_err(priv->dev, "Source buffer not large enough (need %d bytes)!", @@ -752,8 +752,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, return -EINVAL; } - if (sreq->nr_src > 0) - dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); + if (sreq->nr_src > 0 && + !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE)) + return -EIO; if (unlikely(totlen_dst && (sreq->nr_dst <= 0))) { dev_err(priv->dev, "Dest buffer not large enough (need %d bytes)!", @@ -762,9 +763,11 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, goto unmap; } - if (sreq->nr_dst > 0) - dma_map_sg(priv->dev, dst, sreq->nr_dst, - DMA_FROM_DEVICE); + if (sreq->nr_dst > 0 && + !dma_map_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE)) { + ret = -EIO; + goto unmap; + } } memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len); From 8fd183435728b139248a77978ea3732039341779 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:19 +0200 Subject: [PATCH 3282/7721] crypto: sahara - remove FLAGS_NEW_KEY logic Remove the FLAGS_NEW_KEY logic as it has the following issues: - the wrong key may end up being used when there are multiple data streams: t1 t2 setkey() encrypt() setkey() encrypt() encrypt() <--- key from t2 is used - switching between encryption and decryption with the same key is not possible, as the hdr flags are only updated when a new setkey() is performed With this change, the key is always sent along with the cryptdata when performing encryption/decryption operations. Fixes: 5de8875281e1 ("crypto: sahara - Add driver for SAHARA2 accelerator.") Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 02065131c300..5cc1cd59a384 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -43,7 +43,6 @@ #define FLAGS_MODE_MASK 0x000f #define FLAGS_ENCRYPT BIT(0) #define FLAGS_CBC BIT(1) -#define FLAGS_NEW_KEY BIT(3) #define SAHARA_HDR_BASE 0x00800000 #define SAHARA_HDR_SKHA_ALG_AES 0 @@ -141,8 +140,6 @@ struct sahara_hw_link { }; struct sahara_ctx { - unsigned long flags; - /* AES-specific context */ int keylen; u8 key[AES_KEYSIZE_128]; @@ -447,26 +444,22 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) int i, j; int idx = 0; - /* Copy new key if necessary */ - if (ctx->flags & FLAGS_NEW_KEY) { - memcpy(dev->key_base, ctx->key, ctx->keylen); - ctx->flags &= ~FLAGS_NEW_KEY; + memcpy(dev->key_base, ctx->key, ctx->keylen); - if (dev->flags & FLAGS_CBC) { - dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; - dev->hw_desc[idx]->p1 = dev->iv_phys_base; - } else { - dev->hw_desc[idx]->len1 = 0; - dev->hw_desc[idx]->p1 = 0; - } - dev->hw_desc[idx]->len2 = ctx->keylen; - dev->hw_desc[idx]->p2 = dev->key_phys_base; - dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; - - dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); - - idx++; + if (dev->flags & FLAGS_CBC) { + dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; + dev->hw_desc[idx]->p1 = dev->iv_phys_base; + } else { + dev->hw_desc[idx]->len1 = 0; + dev->hw_desc[idx]->p1 = 0; } + dev->hw_desc[idx]->len2 = ctx->keylen; + dev->hw_desc[idx]->p2 = dev->key_phys_base; + dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; + dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); + + idx++; + dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total); if (dev->nb_in_sg < 0) { @@ -608,7 +601,6 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, /* SAHARA only supports 128bit keys */ if (keylen == AES_KEYSIZE_128) { memcpy(ctx->key, key, keylen); - ctx->flags |= FLAGS_NEW_KEY; return 0; } From 9f10bc28c0fb676ae58aa3bfa358db8f5de124bb Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:20 +0200 Subject: [PATCH 3283/7721] crypto: sahara - fix cbc selftest failure The kernel crypto API requires that all CBC implementations update the IV buffer to contain the last ciphertext block. This fixes the following cbc selftest error: alg: skcipher: sahara-cbc-aes encryption test failed (wrong output IV) on test vector 0, cfg="in-place (one sglist)" Fixes: 5de8875281e1 ("crypto: sahara - Add driver for SAHARA2 accelerator.") Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 5cc1cd59a384..888e5e5157bb 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -148,6 +148,7 @@ struct sahara_ctx { struct sahara_aes_reqctx { unsigned long mode; + u8 iv_out[AES_BLOCK_SIZE]; struct skcipher_request fallback_req; // keep at the end }; @@ -541,8 +542,24 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) return -EINVAL; } +static void sahara_aes_cbc_update_iv(struct skcipher_request *req) +{ + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); + + /* Update IV buffer to contain the last ciphertext block */ + if (rctx->mode & FLAGS_ENCRYPT) { + sg_pcopy_to_buffer(req->dst, sg_nents(req->dst), req->iv, + ivsize, req->cryptlen - ivsize); + } else { + memcpy(req->iv, rctx->iv_out, ivsize); + } +} + static int sahara_aes_process(struct skcipher_request *req) { + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct sahara_dev *dev = dev_ptr; struct sahara_ctx *ctx; struct sahara_aes_reqctx *rctx; @@ -564,8 +581,17 @@ static int sahara_aes_process(struct skcipher_request *req) rctx->mode &= FLAGS_MODE_MASK; dev->flags = (dev->flags & ~FLAGS_MODE_MASK) | rctx->mode; - if ((dev->flags & FLAGS_CBC) && req->iv) - memcpy(dev->iv_base, req->iv, AES_KEYSIZE_128); + if ((dev->flags & FLAGS_CBC) && req->iv) { + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); + + memcpy(dev->iv_base, req->iv, ivsize); + + if (!(dev->flags & FLAGS_ENCRYPT)) { + sg_pcopy_to_buffer(req->src, sg_nents(req->src), + rctx->iv_out, ivsize, + req->cryptlen - ivsize); + } + } /* assign new context to device */ dev->ctx = ctx; @@ -588,6 +614,9 @@ static int sahara_aes_process(struct skcipher_request *req) dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); + if ((dev->flags & FLAGS_CBC) && req->iv) + sahara_aes_cbc_update_iv(req); + return 0; } From afffcf3db98b9495114b79d5381f8cc3f69476fb Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:21 +0200 Subject: [PATCH 3284/7721] crypto: sahara - fix ahash selftest failure update() calls should not modify the result buffer, so add an additional check for "rctx->last" to make sure that only the final hash value is copied into the buffer. Fixes the following selftest failure: alg: ahash: sahara-sha256 update() used result buffer on test vector 3, cfg="init+update+final aligned buffer" Fixes: 5a2bb93f5992 ("crypto: sahara - add support for SHA1/256") Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 888e5e5157bb..863171b44cda 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1047,7 +1047,7 @@ static int sahara_sha_process(struct ahash_request *req) memcpy(rctx->context, dev->context_base, rctx->context_size); - if (req->result) + if (req->result && rctx->last) memcpy(req->result, rctx->context, rctx->digest_size); return 0; From 5b8668ce3452827d27f8c34ff6ba080a8f983ed0 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:22 +0200 Subject: [PATCH 3285/7721] crypto: sahara - fix processing requests with cryptlen < sg->length It's not always the case that the entire sg entry needs to be processed. Currently, when cryptlen is less than sg->legth, "Descriptor length" errors are encountered. The error was noticed when testing xts(sahara-ecb-aes) with arbitrary sized input data. To fix this, take the actual request size into account when populating the hw links. Fixes: 5de8875281e1 ("crypto: sahara - Add driver for SAHARA2 accelerator.") Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 863171b44cda..cbb7153e4162 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -444,6 +444,7 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) int ret; int i, j; int idx = 0; + u32 len; memcpy(dev->key_base, ctx->key, ctx->keylen); @@ -494,12 +495,14 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) /* Create input links */ dev->hw_desc[idx]->p1 = dev->hw_phys_link[0]; sg = dev->in_sg; + len = dev->total; for (i = 0; i < dev->nb_in_sg; i++) { - dev->hw_link[i]->len = sg->length; + dev->hw_link[i]->len = min(len, sg->length); dev->hw_link[i]->p = sg->dma_address; if (i == (dev->nb_in_sg - 1)) { dev->hw_link[i]->next = 0; } else { + len -= min(len, sg->length); dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); } @@ -508,12 +511,14 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) /* Create output links */ dev->hw_desc[idx]->p2 = dev->hw_phys_link[i]; sg = dev->out_sg; + len = dev->total; for (j = i; j < dev->nb_out_sg + i; j++) { - dev->hw_link[j]->len = sg->length; + dev->hw_link[j]->len = min(len, sg->length); dev->hw_link[j]->p = sg->dma_address; if (j == (dev->nb_out_sg + i - 1)) { dev->hw_link[j]->next = 0; } else { + len -= min(len, sg->length); dev->hw_link[j]->next = dev->hw_phys_link[j + 1]; sg = sg_next(sg); } From ee6e6f0a7f5b39d50a5ef5fcc006f4f693db18a7 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:23 +0200 Subject: [PATCH 3286/7721] crypto: sahara - fix error handling in sahara_hw_descriptor_create() Do not call dma_unmap_sg() for scatterlists that were not mapped successfully. Fixes: 5de8875281e1 ("crypto: sahara - Add driver for SAHARA2 accelerator.") Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index cbb7153e4162..c4eb66d2e08d 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -483,13 +483,14 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) DMA_TO_DEVICE); if (!ret) { dev_err(dev->device, "couldn't map in sg\n"); - goto unmap_in; + return -EINVAL; } + ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg, DMA_FROM_DEVICE); if (!ret) { dev_err(dev->device, "couldn't map out sg\n"); - goto unmap_out; + goto unmap_in; } /* Create input links */ @@ -537,9 +538,6 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) return 0; -unmap_out: - dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, - DMA_FROM_DEVICE); unmap_in: dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); From 3d5a31dff18b3bda92dc1f95d76b1289391b5d1b Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:24 +0200 Subject: [PATCH 3287/7721] crypto: sahara - remove unused error field in sahara_dev The "error" field in sahara_dev struct hasn't been needed/used since commit c0c3c89ae347 ("crypto: sahara - replace tasklets with kthread"), so remove the remaining references. Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index c4eb66d2e08d..2f09c098742d 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -221,8 +221,6 @@ struct sahara_dev { int nb_in_sg; struct scatterlist *out_sg; int nb_out_sg; - - u32 error; }; static struct sahara_dev *dev_ptr; @@ -1302,14 +1300,11 @@ static irqreturn_t sahara_irq_handler(int irq, void *data) sahara_decode_status(dev, stat); - if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_BUSY) { + if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_BUSY) return IRQ_NONE; - } else if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_COMPLETE) { - dev->error = 0; - } else { + + if (SAHARA_STATUS_GET_STATE(stat) != SAHARA_STATE_COMPLETE) sahara_decode_error(dev, err); - dev->error = -EINVAL; - } complete(&dev->dma_completion); From 01d70a4bbff20ea05cadb4c208841985a7cc6596 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 1 Dec 2023 19:06:25 +0200 Subject: [PATCH 3288/7721] crypto: sahara - avoid skcipher fallback code duplication Factor out duplicated skcipher fallback handling code to a helper function sahara_aes_fallback(). Also, keep a single check if fallback is required in sahara_aes_crypt(). Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 85 ++++++++++++----------------------------- 1 file changed, 25 insertions(+), 60 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 2f09c098742d..27ed66cb761f 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -646,12 +646,37 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, return crypto_skcipher_setkey(ctx->fallback, key, keylen); } +static int sahara_aes_fallback(struct skcipher_request *req, unsigned long mode) +{ + struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + struct sahara_ctx *ctx = crypto_skcipher_ctx( + crypto_skcipher_reqtfm(req)); + + skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); + skcipher_request_set_callback(&rctx->fallback_req, + req->base.flags, + req->base.complete, + req->base.data); + skcipher_request_set_crypt(&rctx->fallback_req, req->src, + req->dst, req->cryptlen, req->iv); + + if (mode & FLAGS_ENCRYPT) + return crypto_skcipher_encrypt(&rctx->fallback_req); + + return crypto_skcipher_decrypt(&rctx->fallback_req); +} + static int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) { struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + struct sahara_ctx *ctx = crypto_skcipher_ctx( + crypto_skcipher_reqtfm(req)); struct sahara_dev *dev = dev_ptr; int err = 0; + if (unlikely(ctx->keylen != AES_KEYSIZE_128)) + return sahara_aes_fallback(req, mode); + dev_dbg(dev->device, "nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen, !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); @@ -674,81 +699,21 @@ static int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) static int sahara_aes_ecb_encrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_encrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_ENCRYPT); } static int sahara_aes_ecb_decrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_decrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, 0); } static int sahara_aes_cbc_encrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_encrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); } static int sahara_aes_cbc_decrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_decrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_CBC); } From 78aafb3884f6bc6636efcc1760c891c8500b9922 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 2 Dec 2023 09:01:54 +0800 Subject: [PATCH 3289/7721] hwrng: core - Fix page fault dead lock on mmap-ed hwrng There is a dead-lock in the hwrng device read path. This triggers when the user reads from /dev/hwrng into memory also mmap-ed from /dev/hwrng. The resulting page fault triggers a recursive read which then dead-locks. Fix this by using a stack buffer when calling copy_to_user. Reported-by: Edward Adam Davis Reported-by: syzbot+c52ab18308964d248092@syzkaller.appspotmail.com Fixes: 9996508b3353 ("hwrng: core - Replace u32 in driver API with byte array") Cc: Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 36 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 420f155d251f..a3bbdd6e60fc 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -23,10 +23,13 @@ #include #include #include +#include #include #define RNG_MODULE_NAME "hw_random" +#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) + static struct hwrng *current_rng; /* the current rng has been explicitly chosen by user via sysfs */ static int cur_rng_set_by_user; @@ -58,7 +61,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, static size_t rng_buffer_size(void) { - return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; + return RNG_BUFFER_SIZE; } static void add_early_randomness(struct hwrng *rng) @@ -209,6 +212,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, static ssize_t rng_dev_read(struct file *filp, char __user *buf, size_t size, loff_t *offp) { + u8 buffer[RNG_BUFFER_SIZE]; ssize_t ret = 0; int err = 0; int bytes_read, len; @@ -236,34 +240,37 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, if (bytes_read < 0) { err = bytes_read; goto out_unlock_reading; - } - data_avail = bytes_read; - } - - if (!data_avail) { - if (filp->f_flags & O_NONBLOCK) { + } else if (bytes_read == 0 && + (filp->f_flags & O_NONBLOCK)) { err = -EAGAIN; goto out_unlock_reading; } - } else { - len = data_avail; + + data_avail = bytes_read; + } + + len = data_avail; + if (len) { if (len > size) len = size; data_avail -= len; - if (copy_to_user(buf + ret, rng_buffer + data_avail, - len)) { + memcpy(buffer, rng_buffer + data_avail, len); + } + mutex_unlock(&reading_mutex); + put_rng(rng); + + if (len) { + if (copy_to_user(buf + ret, buffer, len)) { err = -EFAULT; - goto out_unlock_reading; + goto out; } size -= len; ret += len; } - mutex_unlock(&reading_mutex); - put_rng(rng); if (need_resched()) schedule_timeout_interruptible(1); @@ -274,6 +281,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, } } out: + memzero_explicit(buffer, sizeof(buffer)); return ret ? : err; out_unlock_reading: From f76f0d7f20672611974d3cc705996751fc403734 Mon Sep 17 00:00:00 2001 From: Wenkai Lin Date: Sat, 2 Dec 2023 17:17:18 +0800 Subject: [PATCH 3290/7721] crypto: hisilicon/qm - add a function to set qm algs Extract a public function to set qm algs and remove the similar code for setting qm algs in each module. Signed-off-by: Wenkai Lin Signed-off-by: Hao Fang Signed-off-by: Zhiqi Song Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 42 ++----------------- drivers/crypto/hisilicon/qm.c | 36 +++++++++++++++++ drivers/crypto/hisilicon/sec2/sec_main.c | 47 ++++------------------ drivers/crypto/hisilicon/zip/zip_main.c | 49 ++++------------------- include/linux/hisi_acc_qm.h | 8 +++- 5 files changed, 62 insertions(+), 120 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 56777099ef69..84c92d85d23d 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -118,8 +118,6 @@ #define HPRE_DFX_COMMON2_LEN 0xE #define HPRE_DFX_CORE_LEN 0x43 -#define HPRE_DEV_ALG_MAX_LEN 256 - static const char hpre_name[] = "hisi_hpre"; static struct dentry *hpre_debugfs_root; static const struct pci_device_id hpre_dev_ids[] = { @@ -135,12 +133,7 @@ struct hpre_hw_error { const char *msg; }; -struct hpre_dev_alg { - u32 alg_msk; - const char *alg; -}; - -static const struct hpre_dev_alg hpre_dev_algs[] = { +static const struct qm_dev_alg hpre_dev_algs[] = { { .alg_msk = BIT(0), .alg = "rsa\n" @@ -362,35 +355,6 @@ bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg) return false; } -static int hpre_set_qm_algs(struct hisi_qm *qm) -{ - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u32 alg_msk; - int i; - - if (!qm->use_sva) - return 0; - - algs = devm_kzalloc(dev, HPRE_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) - return -ENOMEM; - - alg_msk = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DEV_ALG_BITMAP_CAP, qm->cap_ver); - - for (i = 0; i < ARRAY_SIZE(hpre_dev_algs); i++) - if (alg_msk & hpre_dev_algs[i].alg_msk) - strcat(algs, hpre_dev_algs[i].alg); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; - - qm->uacce->algs = algs; - - return 0; -} - static int hpre_diff_regs_show(struct seq_file *s, void *unused) { struct hisi_qm *qm = s->private; @@ -1141,6 +1105,7 @@ static void hpre_debugfs_exit(struct hisi_qm *qm) static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; if (pdev->revision == QM_HW_V1) { @@ -1171,7 +1136,8 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = hpre_set_qm_algs(qm); + alg_msk = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DEV_ALG_BITMAP_CAP, qm->cap_ver); + ret = hisi_qm_set_algs(qm, alg_msk, hpre_dev_algs, ARRAY_SIZE(hpre_dev_algs)); if (ret) { pci_err(pdev, "Failed to set hpre algs!\n"); hisi_qm_uninit(qm); diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 7ed079a9c929..4170c24c2ed1 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -234,6 +234,8 @@ #define QM_QOS_MAX_CIR_U 6 #define QM_AUTOSUSPEND_DELAY 3000 +#define QM_DEV_ALG_MAX_LEN 256 + #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ @@ -749,6 +751,40 @@ static void qm_get_xqc_depth(struct hisi_qm *qm, u16 *low_bits, *high_bits = (depth >> QM_XQ_DEPTH_SHIFT) & QM_XQ_DEPTH_MASK; } +int hisi_qm_set_algs(struct hisi_qm *qm, u64 alg_msk, const struct qm_dev_alg *dev_algs, + u32 dev_algs_size) +{ + struct device *dev = &qm->pdev->dev; + char *algs, *ptr; + int i; + + if (!qm->uacce) + return 0; + + if (dev_algs_size >= QM_DEV_ALG_MAX_LEN) { + dev_err(dev, "algs size %u is equal or larger than %d.\n", + dev_algs_size, QM_DEV_ALG_MAX_LEN); + return -EINVAL; + } + + algs = devm_kzalloc(dev, QM_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); + if (!algs) + return -ENOMEM; + + for (i = 0; i < dev_algs_size; i++) + if (alg_msk & dev_algs[i].alg_msk) + strcat(algs, dev_algs[i].alg); + + ptr = strrchr(algs, '\n'); + if (ptr) { + *ptr = '\0'; + qm->uacce->algs = algs; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_set_algs); + static u32 qm_get_irq_num(struct hisi_qm *qm) { if (qm->fun_type == QM_HW_PF) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 0e56a47eb862..2eceab7600ca 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -120,7 +120,6 @@ GENMASK_ULL(42, 25)) #define SEC_AEAD_BITMAP (GENMASK_ULL(7, 6) | GENMASK_ULL(18, 17) | \ GENMASK_ULL(45, 43)) -#define SEC_DEV_ALG_MAX_LEN 256 struct sec_hw_error { u32 int_msk; @@ -132,11 +131,6 @@ struct sec_dfx_item { u32 offset; }; -struct sec_dev_alg { - u64 alg_msk; - const char *algs; -}; - static const char sec_name[] = "hisi_sec2"; static struct dentry *sec_debugfs_root; @@ -173,15 +167,15 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE4_ALG_BITMAP_HIGH, 0x3170, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, }; -static const struct sec_dev_alg sec_dev_algs[] = { { +static const struct qm_dev_alg sec_dev_algs[] = { { .alg_msk = SEC_CIPHER_BITMAP, - .algs = "cipher\n", + .alg = "cipher\n", }, { .alg_msk = SEC_DIGEST_BITMAP, - .algs = "digest\n", + .alg = "digest\n", }, { .alg_msk = SEC_AEAD_BITMAP, - .algs = "aead\n", + .alg = "aead\n", }, }; @@ -1077,37 +1071,9 @@ static int sec_pf_probe_init(struct sec_dev *sec) return ret; } -static int sec_set_qm_algs(struct hisi_qm *qm) -{ - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u64 alg_mask; - int i; - - if (!qm->use_sva) - return 0; - - algs = devm_kzalloc(dev, SEC_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) - return -ENOMEM; - - alg_mask = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH, SEC_DEV_ALG_BITMAP_LOW); - - for (i = 0; i < ARRAY_SIZE(sec_dev_algs); i++) - if (alg_mask & sec_dev_algs[i].alg_msk) - strcat(algs, sec_dev_algs[i].algs); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; - - qm->uacce->algs = algs; - - return 0; -} - static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; qm->pdev = pdev; @@ -1142,7 +1108,8 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = sec_set_qm_algs(qm); + alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH, SEC_DEV_ALG_BITMAP_LOW); + ret = hisi_qm_set_algs(qm, alg_msk, sec_dev_algs, ARRAY_SIZE(sec_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set sec algs!\n"); hisi_qm_uninit(qm); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 07ab61c113ab..2934de25efa4 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -74,7 +74,6 @@ #define HZIP_AXI_SHUTDOWN_ENABLE BIT(14) #define HZIP_WR_PORT BIT(11) -#define HZIP_DEV_ALG_MAX_LEN 256 #define HZIP_ALG_ZLIB_BIT GENMASK(1, 0) #define HZIP_ALG_GZIP_BIT GENMASK(3, 2) #define HZIP_ALG_DEFLATE_BIT GENMASK(5, 4) @@ -128,23 +127,18 @@ struct zip_dfx_item { u32 offset; }; -struct zip_dev_alg { - u32 alg_msk; - const char *algs; -}; - -static const struct zip_dev_alg zip_dev_algs[] = { { +static const struct qm_dev_alg zip_dev_algs[] = { { .alg_msk = HZIP_ALG_ZLIB_BIT, - .algs = "zlib\n", + .alg = "zlib\n", }, { .alg_msk = HZIP_ALG_GZIP_BIT, - .algs = "gzip\n", + .alg = "gzip\n", }, { .alg_msk = HZIP_ALG_DEFLATE_BIT, - .algs = "deflate\n", + .alg = "deflate\n", }, { .alg_msk = HZIP_ALG_LZ77_BIT, - .algs = "lz77_zstd\n", + .alg = "lz77_zstd\n", }, }; @@ -478,35 +472,6 @@ static int hisi_zip_set_high_perf(struct hisi_qm *qm) return ret; } -static int hisi_zip_set_qm_algs(struct hisi_qm *qm) -{ - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u32 alg_mask; - int i; - - if (!qm->use_sva) - return 0; - - algs = devm_kzalloc(dev, HZIP_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) - return -ENOMEM; - - alg_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DEV_ALG_BITMAP, qm->cap_ver); - - for (i = 0; i < ARRAY_SIZE(zip_dev_algs); i++) - if (alg_mask & zip_dev_algs[i].alg_msk) - strcat(algs, zip_dev_algs[i].algs); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; - - qm->uacce->algs = algs; - - return 0; -} - static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) { u32 val; @@ -1193,6 +1158,7 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; qm->pdev = pdev; @@ -1228,7 +1194,8 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = hisi_zip_set_qm_algs(qm); + alg_msk = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DEV_ALG_BITMAP, qm->cap_ver); + ret = hisi_qm_set_algs(qm, alg_msk, zip_dev_algs, ARRAY_SIZE(zip_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set zip algs!\n"); hisi_qm_uninit(qm); diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index e3c0a1297b2c..cdc979f66dba 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -156,6 +156,11 @@ enum qm_cap_bits { QM_SUPPORT_RPM, }; +struct qm_dev_alg { + u64 alg_msk; + const char *alg; +}; + struct dfx_diff_registers { u32 *regs; u32 reg_offset; @@ -361,7 +366,6 @@ struct hisi_qm { struct work_struct rst_work; struct work_struct cmd_process; - const char *algs; bool use_sva; resource_size_t phys_base; @@ -559,6 +563,8 @@ void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset); u32 hisi_qm_get_hw_info(struct hisi_qm *qm, const struct hisi_qm_cap_info *info_table, u32 index, bool is_read); +int hisi_qm_set_algs(struct hisi_qm *qm, u64 alg_msk, const struct qm_dev_alg *dev_algs, + u32 dev_algs_size); /* Used by VFIO ACC live migration driver */ struct pci_driver *hisi_sec_get_pf_driver(void); From cabe13d0bd2efb8dd50ed2310f57b33e1a69a0d4 Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Sat, 2 Dec 2023 17:17:19 +0800 Subject: [PATCH 3291/7721] crypto: hisilicon/qm - save capability registers in qm init process In previous capability register implementation, qm irq related values were read from capability registers dynamically when needed. But in abnormal scenario, e.g. the core is timeout and the device needs to soft reset and reset failed after disabling the MSE, the device can not be removed normally, causing the following call trace: | Call trace: | pci_irq_vector+0xfc/0x140 | hisi_qm_uninit+0x278/0x3b0 [hisi_qm] | hpre_remove+0x16c/0x1c0 [hisi_hpre] | pci_device_remove+0x6c/0x264 | device_release_driver_internal+0x1ec/0x3e0 | device_release_driver+0x3c/0x60 | pci_stop_bus_device+0xfc/0x22c | pci_stop_and_remove_bus_device+0x38/0x70 | pci_iov_remove_virtfn+0x108/0x1c0 | sriov_disable+0x7c/0x1e4 | pci_disable_sriov+0x4c/0x6c | hisi_qm_sriov_disable+0x90/0x160 [hisi_qm] | hpre_remove+0x1a8/0x1c0 [hisi_hpre] | pci_device_remove+0x6c/0x264 | device_release_driver_internal+0x1ec/0x3e0 | driver_detach+0x168/0x2d0 | bus_remove_driver+0xc0/0x230 | driver_unregister+0x58/0xdc | pci_unregister_driver+0x40/0x220 | hpre_exit+0x34/0x64 [hisi_hpre] | __arm64_sys_delete_module+0x374/0x620 [...] | Call trace: | free_msi_irqs+0x25c/0x300 | pci_disable_msi+0x19c/0x264 | pci_free_irq_vectors+0x4c/0x70 | hisi_qm_pci_uninit+0x44/0x90 [hisi_qm] | hisi_qm_uninit+0x28c/0x3b0 [hisi_qm] | hpre_remove+0x16c/0x1c0 [hisi_hpre] | pci_device_remove+0x6c/0x264 [...] The reason for this call trace is that when the MSE is disabled, the value of capability registers in the BAR space become invalid. This will make the subsequent unregister process get the wrong irq vector through capability registers and get the wrong irq number by pci_irq_vector(). So add a capability table structure to pre-store the valid value of the irq information capability register in qm init process, avoid obtaining invalid capability register value after the MSE is disabled. Fixes: 3536cc55cada ("crypto: hisilicon/qm - support get device irq information from hardware registers") Signed-off-by: Zhiqi Song Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 62 +++++++++++++++++++++++++++++------ include/linux/hisi_acc_qm.h | 12 +++++++ 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 4170c24c2ed1..d05ad2b16d0a 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -301,6 +301,13 @@ enum qm_basic_type { QM_VF_IRQ_NUM_CAP, }; +enum qm_pre_store_cap_idx { + QM_EQ_IRQ_TYPE_CAP_IDX = 0x0, + QM_AEQ_IRQ_TYPE_CAP_IDX, + QM_ABN_IRQ_TYPE_CAP_IDX, + QM_PF2VF_IRQ_TYPE_CAP_IDX, +}; + static const struct hisi_qm_cap_info qm_cap_info_comm[] = { {QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0}, {QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1}, @@ -330,6 +337,13 @@ static const struct hisi_qm_cap_info qm_basic_info[] = { {QM_VF_IRQ_NUM_CAP, 0x311c, 0, GENMASK(15, 0), 0x1, 0x2, 0x3}, }; +static const u32 qm_pre_store_caps[] = { + QM_EQ_IRQ_TYPE_CAP, + QM_AEQ_IRQ_TYPE_CAP, + QM_ABN_IRQ_TYPE_CAP, + QM_PF2VF_IRQ_TYPE_CAP, +}; + struct qm_mailbox { __le16 w0; __le16 queue_num; @@ -4774,7 +4788,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return; @@ -4791,7 +4805,7 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return 0; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return 0; @@ -4808,7 +4822,7 @@ static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4822,7 +4836,7 @@ static int qm_register_mb_cmd_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4839,7 +4853,7 @@ static void qm_unregister_aeq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4853,7 +4867,7 @@ static int qm_register_aeq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4871,7 +4885,7 @@ static void qm_unregister_eq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4885,7 +4899,7 @@ static int qm_register_eq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4973,7 +4987,29 @@ static int qm_get_qp_num(struct hisi_qm *qm) return 0; } -static void qm_get_hw_caps(struct hisi_qm *qm) +static int qm_pre_store_irq_type_caps(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *qm_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; + + size = ARRAY_SIZE(qm_pre_store_caps); + qm_cap = devm_kzalloc(&pdev->dev, sizeof(*qm_cap) * size, GFP_KERNEL); + if (!qm_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + qm_cap[i].type = qm_pre_store_caps[i]; + qm_cap[i].cap_val = hisi_qm_get_hw_info(qm, qm_basic_info, + qm_pre_store_caps[i], qm->cap_ver); + } + + qm->cap_tables.qm_cap_table = qm_cap; + + return 0; +} + +static int qm_get_hw_caps(struct hisi_qm *qm) { const struct hisi_qm_cap_info *cap_info = qm->fun_type == QM_HW_PF ? qm_cap_info_pf : qm_cap_info_vf; @@ -5004,6 +5040,9 @@ static void qm_get_hw_caps(struct hisi_qm *qm) if (val) set_bit(cap_info[i].type, &qm->caps); } + + /* Fetch and save the value of irq type related capability registers */ + return qm_pre_store_irq_type_caps(qm); } static int qm_get_pci_res(struct hisi_qm *qm) @@ -5025,7 +5064,10 @@ static int qm_get_pci_res(struct hisi_qm *qm) goto err_request_mem_regions; } - qm_get_hw_caps(qm); + ret = qm_get_hw_caps(qm); + if (ret) + goto err_ioremap; + if (test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps)) { qm->db_interval = QM_QP_DB_INTERVAL; qm->db_phys_base = pci_resource_start(pdev, PCI_BAR_4); diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index cdc979f66dba..5f4c74facf6a 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -266,6 +266,16 @@ struct hisi_qm_cap_info { u32 v3_val; }; +struct hisi_qm_cap_record { + u32 type; + u32 cap_val; +}; + +struct hisi_qm_cap_tables { + struct hisi_qm_cap_record *qm_cap_table; + struct hisi_qm_cap_record *dev_cap_table; +}; + struct hisi_qm_list { struct mutex lock; struct list_head list; @@ -376,6 +386,8 @@ struct hisi_qm { u32 mb_qos; u32 type_rate; struct qm_err_isolate isolate_data; + + struct hisi_qm_cap_tables cap_tables; }; struct hisi_qp_status { From cf8b5156bbc8c9376f699e8d35e9464b739e33ff Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Sat, 2 Dec 2023 17:17:20 +0800 Subject: [PATCH 3292/7721] crypto: hisilicon/hpre - save capability registers in probe process Pre-store the valid value of hpre alg support related capability register in hpre_qm_init(), which will be called by hpre_probe(). It can reduce the number of capability register queries and avoid obtaining incorrect values in abnormal scenarios, such as reset failed and the memory space disabled. Fixes: f214d59a0603 ("crypto: hisilicon/hpre - support hpre capability") Signed-off-by: Zhiqi Song Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 82 ++++++++++++++++++----- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 84c92d85d23d..3255b2a070c7 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -226,6 +226,20 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { {HPRE_CORE10_ALG_BITMAP_CAP, 0x3170, 0, GENMASK(31, 0), 0x0, 0x10, 0x10} }; +enum hpre_pre_store_cap_idx { + HPRE_CLUSTER_NUM_CAP_IDX = 0x0, + HPRE_CORE_ENABLE_BITMAP_CAP_IDX, + HPRE_DRV_ALG_BITMAP_CAP_IDX, + HPRE_DEV_ALG_BITMAP_CAP_IDX, +}; + +static const u32 hpre_pre_store_caps[] = { + HPRE_CLUSTER_NUM_CAP, + HPRE_CORE_ENABLE_BITMAP_CAP, + HPRE_DRV_ALG_BITMAP_CAP, + HPRE_DEV_ALG_BITMAP_CAP, +}; + static const struct hpre_hw_error hpre_hw_errors[] = { { .int_msk = BIT(0), @@ -348,7 +362,7 @@ bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DRV_ALG_BITMAP_CAP, qm->cap_ver); + cap_val = qm->cap_tables.dev_cap_table[HPRE_DRV_ALG_BITMAP_CAP_IDX].cap_val; if (alg & cap_val) return true; @@ -424,16 +438,6 @@ static u32 vfs_num; module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444); MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)"); -static inline int hpre_cluster_num(struct hisi_qm *qm) -{ - return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CLUSTER_NUM_CAP, qm->cap_ver); -} - -static inline int hpre_cluster_core_mask(struct hisi_qm *qm) -{ - return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CORE_ENABLE_BITMAP_CAP, qm->cap_ver); -} - struct hisi_qp *hpre_create_qp(u8 type) { int node = cpu_to_node(smp_processor_id()); @@ -500,13 +504,15 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm) static int hpre_set_cluster(struct hisi_qm *qm) { - u32 cluster_core_mask = hpre_cluster_core_mask(qm); - u8 clusters_num = hpre_cluster_num(qm); struct device *dev = &qm->pdev->dev; unsigned long offset; + u32 cluster_core_mask; + u8 clusters_num; u32 val = 0; int ret, i; + cluster_core_mask = qm->cap_tables.dev_cap_table[HPRE_CORE_ENABLE_BITMAP_CAP_IDX].cap_val; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { offset = i * HPRE_CLSTR_ADDR_INTRVL; @@ -701,11 +707,12 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) static void hpre_cnt_regs_clear(struct hisi_qm *qm) { - u8 clusters_num = hpre_cluster_num(qm); unsigned long offset; + u8 clusters_num; int i; /* clear clusterX/cluster_ctrl */ + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL; writel(0x0, qm->io_base + offset + HPRE_CLUSTER_INQURY); @@ -992,13 +999,14 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm) static int hpre_cluster_debugfs_init(struct hisi_qm *qm) { - u8 clusters_num = hpre_cluster_num(qm); struct device *dev = &qm->pdev->dev; char buf[HPRE_DBGFS_VAL_MAX_LEN]; struct debugfs_regset32 *regset; struct dentry *tmp_d; + u8 clusters_num; int i, ret; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { ret = snprintf(buf, HPRE_DBGFS_VAL_MAX_LEN, "cluster%d", i); if (ret >= HPRE_DBGFS_VAL_MAX_LEN) @@ -1103,6 +1111,34 @@ static void hpre_debugfs_exit(struct hisi_qm *qm) debugfs_remove_recursive(qm->debug.debug_root); } +static int hpre_pre_store_cap_reg(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *hpre_cap; + struct device *dev = &qm->pdev->dev; + size_t i, size; + + size = ARRAY_SIZE(hpre_pre_store_caps); + hpre_cap = devm_kzalloc(dev, sizeof(*hpre_cap) * size, GFP_KERNEL); + if (!hpre_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + hpre_cap[i].type = hpre_pre_store_caps[i]; + hpre_cap[i].cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, + hpre_pre_store_caps[i], qm->cap_ver); + } + + if (hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val > HPRE_CLUSTERS_NUM_MAX) { + dev_err(dev, "Device cluster num %u is out of range for driver supports %d!\n", + hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val, HPRE_CLUSTERS_NUM_MAX); + return -EINVAL; + } + + qm->cap_tables.dev_cap_table = hpre_cap; + + return 0; +} + static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { u64 alg_msk; @@ -1136,7 +1172,15 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - alg_msk = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DEV_ALG_BITMAP_CAP, qm->cap_ver); + /* Fetch and save the value of capability registers */ + ret = hpre_pre_store_cap_reg(qm); + if (ret) { + pci_err(pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = qm->cap_tables.dev_cap_table[HPRE_DEV_ALG_BITMAP_CAP_IDX].cap_val; ret = hisi_qm_set_algs(qm, alg_msk, hpre_dev_algs, ARRAY_SIZE(hpre_dev_algs)); if (ret) { pci_err(pdev, "Failed to set hpre algs!\n"); @@ -1150,11 +1194,12 @@ static int hpre_show_last_regs_init(struct hisi_qm *qm) { int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); - u8 clusters_num = hpre_cluster_num(qm); struct qm_debug *debug = &qm->debug; void __iomem *io_base; + u8 clusters_num; int i, j, idx; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; debug->last_words = kcalloc(cluster_dfx_regs_num * clusters_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); if (!debug->last_words) @@ -1191,10 +1236,10 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) { int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); - u8 clusters_num = hpre_cluster_num(qm); struct qm_debug *debug = &qm->debug; struct pci_dev *pdev = qm->pdev; void __iomem *io_base; + u8 clusters_num; int i, j, idx; u32 val; @@ -1209,6 +1254,7 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) hpre_com_dfx_regs[i].name, debug->last_words[i], val); } + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { io_base = qm->io_base + hpre_cluster_offsets[i]; for (j = 0; j < cluster_dfx_regs_num; j++) { From f1115b0096c3163592e04e74f5a7548c25bda957 Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Sat, 2 Dec 2023 17:17:21 +0800 Subject: [PATCH 3293/7721] crypto: hisilicon/sec2 - save capability registers in probe process Pre-store the valid value of the sec alg support related capability register in sec_qm_init(), which will be called by probe process. It can reduce the number of capability register queries and avoid obtaining incorrect values in abnormal scenarios, such as reset failed and the memory space disabled. Fixes: 921715b6b782 ("crypto: hisilicon/sec - get algorithm bitmap from registers") Signed-off-by: Zhiqi Song Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec.h | 7 ++++ drivers/crypto/hisilicon/sec2/sec_crypto.c | 10 ++++- drivers/crypto/hisilicon/sec2/sec_main.c | 43 ++++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h index 3e57fc04b377..410c83712e28 100644 --- a/drivers/crypto/hisilicon/sec2/sec.h +++ b/drivers/crypto/hisilicon/sec2/sec.h @@ -220,6 +220,13 @@ enum sec_cap_type { SEC_CORE4_ALG_BITMAP_HIGH, }; +enum sec_cap_reg_record_idx { + SEC_DRV_ALG_BITMAP_LOW_IDX = 0x0, + SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DEV_ALG_BITMAP_LOW_IDX, + SEC_DEV_ALG_BITMAP_HIGH_IDX, +}; + void sec_destroy_qps(struct hisi_qp **qps, int qp_num); struct hisi_qp **sec_create_qps(void); int sec_register_to_crypto(struct hisi_qm *qm); diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 6fcabbc87860..ba7f305d43c1 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -2547,9 +2547,12 @@ static int sec_register_aead(u64 alg_mask) int sec_register_to_crypto(struct hisi_qm *qm) { - u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); + u64 alg_mask; int ret = 0; + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DRV_ALG_BITMAP_LOW_IDX); + mutex_lock(&sec_algs_lock); if (sec_available_devs) { sec_available_devs++; @@ -2578,7 +2581,10 @@ int sec_register_to_crypto(struct hisi_qm *qm) void sec_unregister_from_crypto(struct hisi_qm *qm) { - u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); + u64 alg_mask; + + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DRV_ALG_BITMAP_LOW_IDX); mutex_lock(&sec_algs_lock); if (--sec_available_devs) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 2eceab7600ca..878d94ab5d6d 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -167,6 +167,13 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE4_ALG_BITMAP_HIGH, 0x3170, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, }; +static const u32 sec_pre_store_caps[] = { + SEC_DRV_ALG_BITMAP_LOW, + SEC_DRV_ALG_BITMAP_HIGH, + SEC_DEV_ALG_BITMAP_LOW, + SEC_DEV_ALG_BITMAP_HIGH, +}; + static const struct qm_dev_alg sec_dev_algs[] = { { .alg_msk = SEC_CIPHER_BITMAP, .alg = "cipher\n", @@ -388,8 +395,8 @@ u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low) { u32 cap_val_h, cap_val_l; - cap_val_h = hisi_qm_get_hw_info(qm, sec_basic_info, high, qm->cap_ver); - cap_val_l = hisi_qm_get_hw_info(qm, sec_basic_info, low, qm->cap_ver); + cap_val_h = qm->cap_tables.dev_cap_table[high].cap_val; + cap_val_l = qm->cap_tables.dev_cap_table[low].cap_val; return ((u64)cap_val_h << SEC_ALG_BITMAP_SHIFT) | (u64)cap_val_l; } @@ -1071,6 +1078,28 @@ static int sec_pf_probe_init(struct sec_dev *sec) return ret; } +static int sec_pre_store_cap_reg(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *sec_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; + + size = ARRAY_SIZE(sec_pre_store_caps); + sec_cap = devm_kzalloc(&pdev->dev, sizeof(*sec_cap) * size, GFP_KERNEL); + if (!sec_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + sec_cap[i].type = sec_pre_store_caps[i]; + sec_cap[i].cap_val = hisi_qm_get_hw_info(qm, sec_basic_info, + sec_pre_store_caps[i], qm->cap_ver); + } + + qm->cap_tables.dev_cap_table = sec_cap; + + return 0; +} + static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { u64 alg_msk; @@ -1108,7 +1137,15 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH, SEC_DEV_ALG_BITMAP_LOW); + /* Fetch and save the value of capability registers */ + ret = sec_pre_store_cap_reg(qm); + if (ret) { + pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH_IDX, SEC_DEV_ALG_BITMAP_LOW_IDX); ret = hisi_qm_set_algs(qm, alg_msk, sec_dev_algs, ARRAY_SIZE(sec_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set sec algs!\n"); From 2ff0ad847951d61c2d8b309e1ccefb26c57dcc7b Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Sat, 2 Dec 2023 17:17:22 +0800 Subject: [PATCH 3294/7721] crypto: hisilicon/zip - save capability registers in probe process Pre-store the valid value of the zip alg support related capability register in hisi_zip_qm_init(), which will be called by hisi_zip_probe(). It can reduce the number of capability register queries and avoid obtaining incorrect values in abnormal scenarios, such as reset failed and the memory space disabled. Fixes: db700974b69d ("crypto: hisilicon/zip - support zip capability") Signed-off-by: Zhiqi Song Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_main.c | 73 ++++++++++++++++++++----- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 2934de25efa4..479ba8a1d6b5 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -249,6 +249,26 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { {ZIP_CAP_MAX, 0x317c, 0, GENMASK(0, 0), 0x0, 0x0, 0x0} }; +enum zip_pre_store_cap_idx { + ZIP_CORE_NUM_CAP_IDX = 0x0, + ZIP_CLUSTER_COMP_NUM_CAP_IDX, + ZIP_CLUSTER_DECOMP_NUM_CAP_IDX, + ZIP_DECOMP_ENABLE_BITMAP_IDX, + ZIP_COMP_ENABLE_BITMAP_IDX, + ZIP_DRV_ALG_BITMAP_IDX, + ZIP_DEV_ALG_BITMAP_IDX, +}; + +static const u32 zip_pre_store_caps[] = { + ZIP_CORE_NUM_CAP, + ZIP_CLUSTER_COMP_NUM_CAP, + ZIP_CLUSTER_DECOMP_NUM_CAP, + ZIP_DECOMP_ENABLE_BITMAP, + ZIP_COMP_ENABLE_BITMAP, + ZIP_DRV_ALG_BITMAP, + ZIP_DEV_ALG_BITMAP, +}; + enum { HZIP_COMP_CORE0, HZIP_COMP_CORE1, @@ -443,7 +463,7 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DRV_ALG_BITMAP, qm->cap_ver); + cap_val = qm->cap_tables.dev_cap_table[ZIP_DRV_ALG_BITMAP_IDX].cap_val; if ((alg & cap_val) == alg) return true; @@ -568,10 +588,8 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) } /* let's open all compression/decompression cores */ - dcomp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_DECOMP_ENABLE_BITMAP, qm->cap_ver); - comp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_COMP_ENABLE_BITMAP, qm->cap_ver); + dcomp_bm = qm->cap_tables.dev_cap_table[ZIP_DECOMP_ENABLE_BITMAP_IDX].cap_val; + comp_bm = qm->cap_tables.dev_cap_table[ZIP_COMP_ENABLE_BITMAP_IDX].cap_val; writel(HZIP_DECOMP_CHECK_ENABLE | dcomp_bm | comp_bm, base + HZIP_CLOCK_GATE_CTRL); /* enable sqc,cqc writeback */ @@ -798,9 +816,8 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) char buf[HZIP_BUF_SIZE]; int i; - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); - zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, - qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) @@ -942,7 +959,7 @@ static int hisi_zip_show_last_regs_init(struct hisi_qm *qm) u32 zip_core_num; int i, j, idx; - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; debug->last_words = kcalloc(core_dfx_regs_num * zip_core_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); @@ -998,9 +1015,9 @@ static void hisi_zip_show_last_dfx_regs(struct hisi_qm *qm) hzip_com_dfx_regs[i].name, debug->last_words[i], val); } - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); - zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, - qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) scnprintf(buf, sizeof(buf), "Comp_core-%d", i); @@ -1156,6 +1173,28 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) return ret; } +static int zip_pre_store_cap_reg(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *zip_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; + + size = ARRAY_SIZE(zip_pre_store_caps); + zip_cap = devm_kzalloc(&pdev->dev, sizeof(*zip_cap) * size, GFP_KERNEL); + if (!zip_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + zip_cap[i].type = zip_pre_store_caps[i]; + zip_cap[i].cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + zip_pre_store_caps[i], qm->cap_ver); + } + + qm->cap_tables.dev_cap_table = zip_cap; + + return 0; +} + static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { u64 alg_msk; @@ -1194,7 +1233,15 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - alg_msk = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DEV_ALG_BITMAP, qm->cap_ver); + /* Fetch and save the value of capability registers */ + ret = zip_pre_store_cap_reg(qm); + if (ret) { + pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = qm->cap_tables.dev_cap_table[ZIP_DEV_ALG_BITMAP_IDX].cap_val; ret = hisi_qm_set_algs(qm, alg_msk, zip_dev_algs, ARRAY_SIZE(zip_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set zip algs!\n"); From d07f951903fa9922c375b8ab1ce81b18a0034e3b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 28 Nov 2023 14:22:13 +0800 Subject: [PATCH 3295/7721] crypto: s390/aes - Fix buffer overread in CTR mode When processing the last block, the s390 ctr code will always read a whole block, even if there isn't a whole block of data left. Fix this by using the actual length left and copy it into a buffer first for processing. Fixes: 0200f3ecc196 ("crypto: s390 - add System z hardware support for CTR mode") Cc: Reported-by: Guangwu Zhang Signed-off-by: Herbert Xu Reviewd-by: Harald Freudenberger Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 4 +++- arch/s390/crypto/paes_s390.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index c773820e4af9..c6fe5405de4a 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -597,7 +597,9 @@ static int ctr_aes_crypt(struct skcipher_request *req) * final block may be < AES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { - cpacf_kmctr(sctx->fc, sctx->key, buf, walk.src.virt.addr, + memset(buf, 0, AES_BLOCK_SIZE); + memcpy(buf, walk.src.virt.addr, nbytes); + cpacf_kmctr(sctx->fc, sctx->key, buf, buf, AES_BLOCK_SIZE, walk.iv); memcpy(walk.dst.virt.addr, buf, nbytes); crypto_inc(walk.iv, AES_BLOCK_SIZE); diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index 8b541e44151d..55ee5567a5ea 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -693,9 +693,11 @@ static int ctr_paes_crypt(struct skcipher_request *req) * final block may be < AES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { + memset(buf, 0, AES_BLOCK_SIZE); + memcpy(buf, walk.src.virt.addr, nbytes); while (1) { if (cpacf_kmctr(ctx->fc, ¶m, buf, - walk.src.virt.addr, AES_BLOCK_SIZE, + buf, AES_BLOCK_SIZE, walk.iv) == AES_BLOCK_SIZE) break; if (__paes_convert_key(ctx)) From 29fa12e918e5f7fe9947aab2f325a4b54f4c5d99 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Sep 2023 17:13:23 +0800 Subject: [PATCH 3296/7721] crypto: arm64/sm4 - Remove cfb(sm4) Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- arch/arm64/crypto/Kconfig | 6 +- arch/arm64/crypto/sm4-ce-core.S | 158 ------------------------------ arch/arm64/crypto/sm4-ce-glue.c | 108 +------------------- arch/arm64/crypto/sm4-ce.h | 3 - arch/arm64/crypto/sm4-neon-core.S | 113 --------------------- arch/arm64/crypto/sm4-neon-glue.c | 105 +------------------- 6 files changed, 4 insertions(+), 489 deletions(-) diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 6d06b448a66e..eb7b423ba463 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -231,7 +231,7 @@ config CRYPTO_SM4_ARM64_CE - NEON (Advanced SIMD) extensions config CRYPTO_SM4_ARM64_CE_BLK - tristate "Ciphers: SM4, modes: ECB/CBC/CFB/CTR/XTS (ARMv8 Crypto Extensions)" + tristate "Ciphers: SM4, modes: ECB/CBC/CTR/XTS (ARMv8 Crypto Extensions)" depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_SM4 @@ -240,7 +240,6 @@ config CRYPTO_SM4_ARM64_CE_BLK with block cipher modes: - ECB (Electronic Codebook) mode (NIST SP800-38A) - CBC (Cipher Block Chaining) mode (NIST SP800-38A) - - CFB (Cipher Feedback) mode (NIST SP800-38A) - CTR (Counter) mode (NIST SP800-38A) - XTS (XOR Encrypt XOR with ciphertext stealing) mode (NIST SP800-38E and IEEE 1619) @@ -250,7 +249,7 @@ config CRYPTO_SM4_ARM64_CE_BLK - NEON (Advanced SIMD) extensions config CRYPTO_SM4_ARM64_NEON_BLK - tristate "Ciphers: SM4, modes: ECB/CBC/CFB/CTR (NEON)" + tristate "Ciphers: SM4, modes: ECB/CBC/CTR (NEON)" depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_SM4 @@ -259,7 +258,6 @@ config CRYPTO_SM4_ARM64_NEON_BLK with block cipher modes: - ECB (Electronic Codebook) mode (NIST SP800-38A) - CBC (Cipher Block Chaining) mode (NIST SP800-38A) - - CFB (Cipher Feedback) mode (NIST SP800-38A) - CTR (Counter) mode (NIST SP800-38A) Architecture: arm64 using: diff --git a/arch/arm64/crypto/sm4-ce-core.S b/arch/arm64/crypto/sm4-ce-core.S index 877b80c54a0d..1f3625c2c67e 100644 --- a/arch/arm64/crypto/sm4-ce-core.S +++ b/arch/arm64/crypto/sm4-ce-core.S @@ -402,164 +402,6 @@ SYM_FUNC_START(sm4_ce_cbc_cts_dec) ret SYM_FUNC_END(sm4_ce_cbc_cts_dec) -.align 3 -SYM_FUNC_START(sm4_ce_cfb_enc) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE(x0) - - ld1 {RIV.16b}, [x3] - -.Lcfb_enc_loop_4x: - cmp w4, #4 - blt .Lcfb_enc_loop_1x - - sub w4, w4, #4 - - ld1 {v0.16b-v3.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - SM4_CRYPT_BLK_BE(v8) - eor v0.16b, v0.16b, v8.16b - - rev32 v8.16b, v0.16b - SM4_CRYPT_BLK_BE(v8) - eor v1.16b, v1.16b, v8.16b - - rev32 v8.16b, v1.16b - SM4_CRYPT_BLK_BE(v8) - eor v2.16b, v2.16b, v8.16b - - rev32 v8.16b, v2.16b - SM4_CRYPT_BLK_BE(v8) - eor v3.16b, v3.16b, v8.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - mov RIV.16b, v3.16b - - cbz w4, .Lcfb_enc_end - b .Lcfb_enc_loop_4x - -.Lcfb_enc_loop_1x: - sub w4, w4, #1 - - ld1 {v0.16b}, [x2], #16 - - SM4_CRYPT_BLK(RIV) - eor RIV.16b, RIV.16b, v0.16b - - st1 {RIV.16b}, [x1], #16 - - cbnz w4, .Lcfb_enc_loop_1x - -.Lcfb_enc_end: - /* store new IV */ - st1 {RIV.16b}, [x3] - - ret -SYM_FUNC_END(sm4_ce_cfb_enc) - -.align 3 -SYM_FUNC_START(sm4_ce_cfb_dec) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE(x0) - - ld1 {RIV.16b}, [x3] - -.Lcfb_dec_loop_8x: - sub w4, w4, #8 - tbnz w4, #31, .Lcfb_dec_4x - - ld1 {v0.16b-v3.16b}, [x2], #64 - ld1 {v4.16b-v7.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - rev32 v9.16b, v0.16b - rev32 v10.16b, v1.16b - rev32 v11.16b, v2.16b - rev32 v12.16b, v3.16b - rev32 v13.16b, v4.16b - rev32 v14.16b, v5.16b - rev32 v15.16b, v6.16b - - SM4_CRYPT_BLK8_BE(v8, v9, v10, v11, v12, v13, v14, v15) - - mov RIV.16b, v7.16b - - eor v0.16b, v0.16b, v8.16b - eor v1.16b, v1.16b, v9.16b - eor v2.16b, v2.16b, v10.16b - eor v3.16b, v3.16b, v11.16b - eor v4.16b, v4.16b, v12.16b - eor v5.16b, v5.16b, v13.16b - eor v6.16b, v6.16b, v14.16b - eor v7.16b, v7.16b, v15.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - st1 {v4.16b-v7.16b}, [x1], #64 - - cbz w4, .Lcfb_dec_end - b .Lcfb_dec_loop_8x - -.Lcfb_dec_4x: - add w4, w4, #8 - cmp w4, #4 - blt .Lcfb_dec_loop_1x - - sub w4, w4, #4 - - ld1 {v0.16b-v3.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - rev32 v9.16b, v0.16b - rev32 v10.16b, v1.16b - rev32 v11.16b, v2.16b - - SM4_CRYPT_BLK4_BE(v8, v9, v10, v11) - - mov RIV.16b, v3.16b - - eor v0.16b, v0.16b, v8.16b - eor v1.16b, v1.16b, v9.16b - eor v2.16b, v2.16b, v10.16b - eor v3.16b, v3.16b, v11.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - - cbz w4, .Lcfb_dec_end - -.Lcfb_dec_loop_1x: - sub w4, w4, #1 - - ld1 {v0.16b}, [x2], #16 - - SM4_CRYPT_BLK(RIV) - - eor RIV.16b, RIV.16b, v0.16b - st1 {RIV.16b}, [x1], #16 - - mov RIV.16b, v0.16b - - cbnz w4, .Lcfb_dec_loop_1x - -.Lcfb_dec_end: - /* store new IV */ - st1 {RIV.16b}, [x3] - - ret -SYM_FUNC_END(sm4_ce_cfb_dec) - .align 3 SYM_FUNC_START(sm4_ce_ctr_enc) /* input: diff --git a/arch/arm64/crypto/sm4-ce-glue.c b/arch/arm64/crypto/sm4-ce-glue.c index 0a2d32ed3bde..43741bed874e 100644 --- a/arch/arm64/crypto/sm4-ce-glue.c +++ b/arch/arm64/crypto/sm4-ce-glue.c @@ -37,10 +37,6 @@ asmlinkage void sm4_ce_cbc_cts_enc(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nbytes); asmlinkage void sm4_ce_cbc_cts_dec(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nbytes); -asmlinkage void sm4_ce_cfb_enc(const u32 *rkey, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblks); -asmlinkage void sm4_ce_cfb_dec(const u32 *rkey, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblks); asmlinkage void sm4_ce_ctr_enc(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nblks); asmlinkage void sm4_ce_xts_enc(const u32 *rkey1, u8 *dst, const u8 *src, @@ -56,7 +52,6 @@ asmlinkage void sm4_ce_mac_update(const u32 *rkey_enc, u8 *digest, EXPORT_SYMBOL(sm4_ce_expand_key); EXPORT_SYMBOL(sm4_ce_crypt_block); EXPORT_SYMBOL(sm4_ce_cbc_enc); -EXPORT_SYMBOL(sm4_ce_cfb_enc); struct sm4_xts_ctx { struct sm4_ctx key1; @@ -280,90 +275,6 @@ static int sm4_cbc_cts_decrypt(struct skcipher_request *req) return sm4_cbc_cts_crypt(req, false); } -static int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblks; - - kernel_neon_begin(); - - nblks = BYTES2BLKS(nbytes); - if (nblks) { - sm4_ce_cfb_enc(ctx->rkey_enc, dst, src, walk.iv, nblks); - dst += nblks * SM4_BLOCK_SIZE; - src += nblks * SM4_BLOCK_SIZE; - nbytes -= nblks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_ce_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - kernel_neon_end(); - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int sm4_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblks; - - kernel_neon_begin(); - - nblks = BYTES2BLKS(nbytes); - if (nblks) { - sm4_ce_cfb_dec(ctx->rkey_enc, dst, src, walk.iv, nblks); - dst += nblks * SM4_BLOCK_SIZE; - src += nblks * SM4_BLOCK_SIZE; - nbytes -= nblks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_ce_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - kernel_neon_end(); - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - static int sm4_ctr_crypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -542,22 +453,6 @@ static struct skcipher_alg sm4_algs[] = { .setkey = sm4_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = sm4_cbc_decrypt, - }, { - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "cfb-sm4-ce", - .cra_priority = 400, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .setkey = sm4_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = sm4_cfb_decrypt, }, { .base = { .cra_name = "ctr(sm4)", @@ -869,12 +764,11 @@ static void __exit sm4_exit(void) module_cpu_feature_match(SM4, sm4_init); module_exit(sm4_exit); -MODULE_DESCRIPTION("SM4 ECB/CBC/CFB/CTR/XTS using ARMv8 Crypto Extensions"); +MODULE_DESCRIPTION("SM4 ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); MODULE_ALIAS_CRYPTO("sm4-ce"); MODULE_ALIAS_CRYPTO("sm4"); MODULE_ALIAS_CRYPTO("ecb(sm4)"); MODULE_ALIAS_CRYPTO("cbc(sm4)"); -MODULE_ALIAS_CRYPTO("cfb(sm4)"); MODULE_ALIAS_CRYPTO("ctr(sm4)"); MODULE_ALIAS_CRYPTO("cts(cbc(sm4))"); MODULE_ALIAS_CRYPTO("xts(sm4)"); diff --git a/arch/arm64/crypto/sm4-ce.h b/arch/arm64/crypto/sm4-ce.h index 109c21b37590..1e235c4371eb 100644 --- a/arch/arm64/crypto/sm4-ce.h +++ b/arch/arm64/crypto/sm4-ce.h @@ -11,6 +11,3 @@ void sm4_ce_crypt_block(const u32 *rkey, u8 *dst, const u8 *src); void sm4_ce_cbc_enc(const u32 *rkey_enc, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); - -void sm4_ce_cfb_enc(const u32 *rkey_enc, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblocks); diff --git a/arch/arm64/crypto/sm4-neon-core.S b/arch/arm64/crypto/sm4-neon-core.S index f295b4b7d70a..734dc7193610 100644 --- a/arch/arm64/crypto/sm4-neon-core.S +++ b/arch/arm64/crypto/sm4-neon-core.S @@ -437,119 +437,6 @@ SYM_FUNC_START(sm4_neon_cbc_dec) ret SYM_FUNC_END(sm4_neon_cbc_dec) -.align 3 -SYM_FUNC_START(sm4_neon_cfb_dec) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE() - - ld1 {v0.16b}, [x3] - -.Lcfb_dec_loop_8x: - sub w4, w4, #8 - tbnz w4, #31, .Lcfb_dec_4x - - ld1 {v1.16b-v3.16b}, [x2], #48 - ld4 {v4.4s-v7.4s}, [x2] - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK8(v0, v1, v2, v3, v4, v5, v6, v7) - - sub x2, x2, #48 - ld1 {RTMP0.16b-RTMP3.16b}, [x2], #64 - ld1 {RTMP4.16b-RTMP7.16b}, [x2], #64 - - eor v0.16b, v0.16b, RTMP0.16b - eor v1.16b, v1.16b, RTMP1.16b - eor v2.16b, v2.16b, RTMP2.16b - eor v3.16b, v3.16b, RTMP3.16b - eor v4.16b, v4.16b, RTMP4.16b - eor v5.16b, v5.16b, RTMP5.16b - eor v6.16b, v6.16b, RTMP6.16b - eor v7.16b, v7.16b, RTMP7.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - st1 {v4.16b-v7.16b}, [x1], #64 - - mov v0.16b, RTMP7.16b - - cbz w4, .Lcfb_dec_end - b .Lcfb_dec_loop_8x - -.Lcfb_dec_4x: - add w4, w4, #8 - cmp w4, #4 - blt .Lcfb_dec_tail - - sub w4, w4, #4 - - ld1 {v4.16b-v7.16b}, [x2], #64 - - rev32 v0.16b, v0.16b /* v0 is IV register */ - rev32 v1.16b, v4.16b - rev32 v2.16b, v5.16b - rev32 v3.16b, v6.16b - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK4_BE(v0, v1, v2, v3) - - eor v0.16b, v0.16b, v4.16b - eor v1.16b, v1.16b, v5.16b - eor v2.16b, v2.16b, v6.16b - eor v3.16b, v3.16b, v7.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - - mov v0.16b, v7.16b - - cbz w4, .Lcfb_dec_end - -.Lcfb_dec_tail: - cmp w4, #2 - ld1 {v4.16b}, [x2], #16 - blt .Lcfb_dec_tail_load_done - ld1 {v5.16b}, [x2], #16 - beq .Lcfb_dec_tail_load_done - ld1 {v6.16b}, [x2], #16 - -.Lcfb_dec_tail_load_done: - rev32 v0.16b, v0.16b /* v0 is IV register */ - rev32 v1.16b, v4.16b - rev32 v2.16b, v5.16b - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK4_BE(v0, v1, v2, v3) - - cmp w4, #2 - eor v0.16b, v0.16b, v4.16b - st1 {v0.16b}, [x1], #16 - mov v0.16b, v4.16b - blt .Lcfb_dec_end - - eor v1.16b, v1.16b, v5.16b - st1 {v1.16b}, [x1], #16 - mov v0.16b, v5.16b - beq .Lcfb_dec_end - - eor v2.16b, v2.16b, v6.16b - st1 {v2.16b}, [x1], #16 - mov v0.16b, v6.16b - -.Lcfb_dec_end: - /* store new IV */ - st1 {v0.16b}, [x3] - - ret -SYM_FUNC_END(sm4_neon_cfb_dec) - .align 3 SYM_FUNC_START(sm4_neon_ctr_crypt) /* input: diff --git a/arch/arm64/crypto/sm4-neon-glue.c b/arch/arm64/crypto/sm4-neon-glue.c index 7b19accf5c03..e3500aca2d18 100644 --- a/arch/arm64/crypto/sm4-neon-glue.c +++ b/arch/arm64/crypto/sm4-neon-glue.c @@ -22,8 +22,6 @@ asmlinkage void sm4_neon_crypt(const u32 *rkey, u8 *dst, const u8 *src, unsigned int nblocks); asmlinkage void sm4_neon_cbc_dec(const u32 *rkey_dec, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); -asmlinkage void sm4_neon_cfb_dec(const u32 *rkey_enc, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblocks); asmlinkage void sm4_neon_ctr_crypt(const u32 *rkey_enc, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); @@ -142,90 +140,6 @@ static int sm4_cbc_decrypt(struct skcipher_request *req) return err; } -static int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - const u8 *iv = walk.iv; - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - while (nbytes >= SM4_BLOCK_SIZE) { - sm4_crypt_block(ctx->rkey_enc, keystream, iv); - crypto_xor_cpy(dst, src, keystream, SM4_BLOCK_SIZE); - iv = dst; - src += SM4_BLOCK_SIZE; - dst += SM4_BLOCK_SIZE; - nbytes -= SM4_BLOCK_SIZE; - } - if (iv != walk.iv) - memcpy(walk.iv, iv, SM4_BLOCK_SIZE); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int sm4_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblocks; - - nblocks = nbytes / SM4_BLOCK_SIZE; - if (nblocks) { - kernel_neon_begin(); - - sm4_neon_cfb_dec(ctx->rkey_enc, dst, src, - walk.iv, nblocks); - - kernel_neon_end(); - - dst += nblocks * SM4_BLOCK_SIZE; - src += nblocks * SM4_BLOCK_SIZE; - nbytes -= nblocks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - static int sm4_ctr_crypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -301,22 +215,6 @@ static struct skcipher_alg sm4_algs[] = { .setkey = sm4_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = sm4_cbc_decrypt, - }, { - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "cfb-sm4-neon", - .cra_priority = 200, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .setkey = sm4_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = sm4_cfb_decrypt, }, { .base = { .cra_name = "ctr(sm4)", @@ -349,12 +247,11 @@ static void __exit sm4_exit(void) module_init(sm4_init); module_exit(sm4_exit); -MODULE_DESCRIPTION("SM4 ECB/CBC/CFB/CTR using ARMv8 NEON"); +MODULE_DESCRIPTION("SM4 ECB/CBC/CTR using ARMv8 NEON"); MODULE_ALIAS_CRYPTO("sm4-neon"); MODULE_ALIAS_CRYPTO("sm4"); MODULE_ALIAS_CRYPTO("ecb(sm4)"); MODULE_ALIAS_CRYPTO("cbc(sm4)"); -MODULE_ALIAS_CRYPTO("cfb(sm4)"); MODULE_ALIAS_CRYPTO("ctr(sm4)"); MODULE_AUTHOR("Tianjia Zhang "); MODULE_LICENSE("GPL v2"); From 05bd1e2a78a453910104b0fe4aa771d08cbeccf1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Sep 2023 17:16:52 +0800 Subject: [PATCH 3297/7721] crypto: x86/sm4 - Remove cfb(sm4) Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- arch/x86/crypto/Kconfig | 8 +- arch/x86/crypto/sm4-aesni-avx-asm_64.S | 52 ---------- arch/x86/crypto/sm4-aesni-avx2-asm_64.S | 55 ---------- arch/x86/crypto/sm4-avx.h | 4 - arch/x86/crypto/sm4_aesni_avx2_glue.c | 26 ----- arch/x86/crypto/sm4_aesni_avx_glue.c | 130 ------------------------ 6 files changed, 4 insertions(+), 271 deletions(-) diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig index 9bbfd01cfa2f..c9e59589a1ce 100644 --- a/arch/x86/crypto/Kconfig +++ b/arch/x86/crypto/Kconfig @@ -189,7 +189,7 @@ config CRYPTO_SERPENT_AVX2_X86_64 Processes 16 blocks in parallel. config CRYPTO_SM4_AESNI_AVX_X86_64 - tristate "Ciphers: SM4 with modes: ECB, CBC, CFB, CTR (AES-NI/AVX)" + tristate "Ciphers: SM4 with modes: ECB, CBC, CTR (AES-NI/AVX)" depends on X86 && 64BIT select CRYPTO_SKCIPHER select CRYPTO_SIMD @@ -197,7 +197,7 @@ config CRYPTO_SM4_AESNI_AVX_X86_64 select CRYPTO_SM4 help Length-preserving ciphers: SM4 cipher algorithms - (OSCCA GB/T 32907-2016) with ECB, CBC, CFB, and CTR modes + (OSCCA GB/T 32907-2016) with ECB, CBC, and CTR modes Architecture: x86_64 using: - AES-NI (AES New Instructions) @@ -210,7 +210,7 @@ config CRYPTO_SM4_AESNI_AVX_X86_64 If unsure, say N. config CRYPTO_SM4_AESNI_AVX2_X86_64 - tristate "Ciphers: SM4 with modes: ECB, CBC, CFB, CTR (AES-NI/AVX2)" + tristate "Ciphers: SM4 with modes: ECB, CBC, CTR (AES-NI/AVX2)" depends on X86 && 64BIT select CRYPTO_SKCIPHER select CRYPTO_SIMD @@ -219,7 +219,7 @@ config CRYPTO_SM4_AESNI_AVX2_X86_64 select CRYPTO_SM4_AESNI_AVX_X86_64 help Length-preserving ciphers: SM4 cipher algorithms - (OSCCA GB/T 32907-2016) with ECB, CBC, CFB, and CTR modes + (OSCCA GB/T 32907-2016) with ECB, CBC, and CTR modes Architecture: x86_64 using: - AES-NI (AES New Instructions) diff --git a/arch/x86/crypto/sm4-aesni-avx-asm_64.S b/arch/x86/crypto/sm4-aesni-avx-asm_64.S index e2668d2fe6ce..2bf611eaa191 100644 --- a/arch/x86/crypto/sm4-aesni-avx-asm_64.S +++ b/arch/x86/crypto/sm4-aesni-avx-asm_64.S @@ -534,55 +534,3 @@ SYM_TYPED_FUNC_START(sm4_aesni_avx_cbc_dec_blk8) FRAME_END RET; SYM_FUNC_END(sm4_aesni_avx_cbc_dec_blk8) - -/* - * void sm4_aesni_avx_cfb_dec_blk8(const u32 *rk, u8 *dst, - * const u8 *src, u8 *iv) - */ -SYM_TYPED_FUNC_START(sm4_aesni_avx_cfb_dec_blk8) - /* input: - * %rdi: round key array, CTX - * %rsi: dst (8 blocks) - * %rdx: src (8 blocks) - * %rcx: iv - */ - FRAME_BEGIN - - /* Load input */ - vmovdqu (%rcx), RA0; - vmovdqu 0 * 16(%rdx), RA1; - vmovdqu 1 * 16(%rdx), RA2; - vmovdqu 2 * 16(%rdx), RA3; - vmovdqu 3 * 16(%rdx), RB0; - vmovdqu 4 * 16(%rdx), RB1; - vmovdqu 5 * 16(%rdx), RB2; - vmovdqu 6 * 16(%rdx), RB3; - - /* Update IV */ - vmovdqu 7 * 16(%rdx), RNOT; - vmovdqu RNOT, (%rcx); - - call __sm4_crypt_blk8; - - vpxor (0 * 16)(%rdx), RA0, RA0; - vpxor (1 * 16)(%rdx), RA1, RA1; - vpxor (2 * 16)(%rdx), RA2, RA2; - vpxor (3 * 16)(%rdx), RA3, RA3; - vpxor (4 * 16)(%rdx), RB0, RB0; - vpxor (5 * 16)(%rdx), RB1, RB1; - vpxor (6 * 16)(%rdx), RB2, RB2; - vpxor (7 * 16)(%rdx), RB3, RB3; - - vmovdqu RA0, (0 * 16)(%rsi); - vmovdqu RA1, (1 * 16)(%rsi); - vmovdqu RA2, (2 * 16)(%rsi); - vmovdqu RA3, (3 * 16)(%rsi); - vmovdqu RB0, (4 * 16)(%rsi); - vmovdqu RB1, (5 * 16)(%rsi); - vmovdqu RB2, (6 * 16)(%rsi); - vmovdqu RB3, (7 * 16)(%rsi); - - vzeroall; - FRAME_END - RET; -SYM_FUNC_END(sm4_aesni_avx_cfb_dec_blk8) diff --git a/arch/x86/crypto/sm4-aesni-avx2-asm_64.S b/arch/x86/crypto/sm4-aesni-avx2-asm_64.S index 98ede9459287..9ff5ba075591 100644 --- a/arch/x86/crypto/sm4-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/sm4-aesni-avx2-asm_64.S @@ -439,58 +439,3 @@ SYM_TYPED_FUNC_START(sm4_aesni_avx2_cbc_dec_blk16) FRAME_END RET; SYM_FUNC_END(sm4_aesni_avx2_cbc_dec_blk16) - -/* - * void sm4_aesni_avx2_cfb_dec_blk16(const u32 *rk, u8 *dst, - * const u8 *src, u8 *iv) - */ -SYM_TYPED_FUNC_START(sm4_aesni_avx2_cfb_dec_blk16) - /* input: - * %rdi: round key array, CTX - * %rsi: dst (16 blocks) - * %rdx: src (16 blocks) - * %rcx: iv - */ - FRAME_BEGIN - - vzeroupper; - - /* Load input */ - vmovdqu (%rcx), RNOTx; - vinserti128 $1, (%rdx), RNOT, RA0; - vmovdqu (0 * 32 + 16)(%rdx), RA1; - vmovdqu (1 * 32 + 16)(%rdx), RA2; - vmovdqu (2 * 32 + 16)(%rdx), RA3; - vmovdqu (3 * 32 + 16)(%rdx), RB0; - vmovdqu (4 * 32 + 16)(%rdx), RB1; - vmovdqu (5 * 32 + 16)(%rdx), RB2; - vmovdqu (6 * 32 + 16)(%rdx), RB3; - - /* Update IV */ - vmovdqu (7 * 32 + 16)(%rdx), RNOTx; - vmovdqu RNOTx, (%rcx); - - call __sm4_crypt_blk16; - - vpxor (0 * 32)(%rdx), RA0, RA0; - vpxor (1 * 32)(%rdx), RA1, RA1; - vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; - vpxor (5 * 32)(%rdx), RB1, RB1; - vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; - - vmovdqu RA0, (0 * 32)(%rsi); - vmovdqu RA1, (1 * 32)(%rsi); - vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); - vmovdqu RB1, (5 * 32)(%rsi); - vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); - - vzeroall; - FRAME_END - RET; -SYM_FUNC_END(sm4_aesni_avx2_cfb_dec_blk16) diff --git a/arch/x86/crypto/sm4-avx.h b/arch/x86/crypto/sm4-avx.h index 1bceab7516aa..b5b5e67e40ed 100644 --- a/arch/x86/crypto/sm4-avx.h +++ b/arch/x86/crypto/sm4-avx.h @@ -14,10 +14,6 @@ int sm4_cbc_encrypt(struct skcipher_request *req); int sm4_avx_cbc_decrypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func); -int sm4_cfb_encrypt(struct skcipher_request *req); -int sm4_avx_cfb_decrypt(struct skcipher_request *req, - unsigned int bsize, sm4_crypt_func func); - int sm4_avx_ctr_crypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func); diff --git a/arch/x86/crypto/sm4_aesni_avx2_glue.c b/arch/x86/crypto/sm4_aesni_avx2_glue.c index 84bc718f49a3..1148fd4cd57f 100644 --- a/arch/x86/crypto/sm4_aesni_avx2_glue.c +++ b/arch/x86/crypto/sm4_aesni_avx2_glue.c @@ -23,8 +23,6 @@ asmlinkage void sm4_aesni_avx2_ctr_enc_blk16(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); asmlinkage void sm4_aesni_avx2_cbc_dec_blk16(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); -asmlinkage void sm4_aesni_avx2_cfb_dec_blk16(const u32 *rk, u8 *dst, - const u8 *src, u8 *iv); static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int key_len) @@ -41,12 +39,6 @@ static int cbc_decrypt(struct skcipher_request *req) } -static int cfb_decrypt(struct skcipher_request *req) -{ - return sm4_avx_cfb_decrypt(req, SM4_CRYPT16_BLOCK_SIZE, - sm4_aesni_avx2_cfb_dec_blk16); -} - static int ctr_crypt(struct skcipher_request *req) { return sm4_avx_ctr_crypt(req, SM4_CRYPT16_BLOCK_SIZE, @@ -87,24 +79,6 @@ static struct skcipher_alg sm4_aesni_avx2_skciphers[] = { .setkey = sm4_skcipher_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = cbc_decrypt, - }, { - .base = { - .cra_name = "__cfb(sm4)", - .cra_driver_name = "__cfb-sm4-aesni-avx2", - .cra_priority = 500, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .walksize = 16 * SM4_BLOCK_SIZE, - .setkey = sm4_skcipher_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = cfb_decrypt, }, { .base = { .cra_name = "__ctr(sm4)", diff --git a/arch/x86/crypto/sm4_aesni_avx_glue.c b/arch/x86/crypto/sm4_aesni_avx_glue.c index 7800f77d68ad..85b4ca78b47b 100644 --- a/arch/x86/crypto/sm4_aesni_avx_glue.c +++ b/arch/x86/crypto/sm4_aesni_avx_glue.c @@ -27,8 +27,6 @@ asmlinkage void sm4_aesni_avx_ctr_enc_blk8(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); asmlinkage void sm4_aesni_avx_cbc_dec_blk8(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); -asmlinkage void sm4_aesni_avx_cfb_dec_blk8(const u32 *rk, u8 *dst, - const u8 *src, u8 *iv); static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int key_len) @@ -188,116 +186,6 @@ static int cbc_decrypt(struct skcipher_request *req) sm4_aesni_avx_cbc_dec_blk8); } -int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - const u8 *iv = walk.iv; - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - while (nbytes >= SM4_BLOCK_SIZE) { - sm4_crypt_block(ctx->rkey_enc, keystream, iv); - crypto_xor_cpy(dst, src, keystream, SM4_BLOCK_SIZE); - iv = dst; - src += SM4_BLOCK_SIZE; - dst += SM4_BLOCK_SIZE; - nbytes -= SM4_BLOCK_SIZE; - } - if (iv != walk.iv) - memcpy(walk.iv, iv, SM4_BLOCK_SIZE); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} -EXPORT_SYMBOL_GPL(sm4_cfb_encrypt); - -int sm4_avx_cfb_decrypt(struct skcipher_request *req, - unsigned int bsize, sm4_crypt_func func) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - kernel_fpu_begin(); - - while (nbytes >= bsize) { - func(ctx->rkey_enc, dst, src, walk.iv); - dst += bsize; - src += bsize; - nbytes -= bsize; - } - - while (nbytes >= SM4_BLOCK_SIZE) { - u8 keystream[SM4_BLOCK_SIZE * 8]; - unsigned int nblocks = min(nbytes >> 4, 8u); - - memcpy(keystream, walk.iv, SM4_BLOCK_SIZE); - if (nblocks > 1) - memcpy(&keystream[SM4_BLOCK_SIZE], src, - (nblocks - 1) * SM4_BLOCK_SIZE); - memcpy(walk.iv, src + (nblocks - 1) * SM4_BLOCK_SIZE, - SM4_BLOCK_SIZE); - - sm4_aesni_avx_crypt8(ctx->rkey_enc, keystream, - keystream, nblocks); - - crypto_xor_cpy(dst, src, keystream, - nblocks * SM4_BLOCK_SIZE); - dst += nblocks * SM4_BLOCK_SIZE; - src += nblocks * SM4_BLOCK_SIZE; - nbytes -= nblocks * SM4_BLOCK_SIZE; - } - - kernel_fpu_end(); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} -EXPORT_SYMBOL_GPL(sm4_avx_cfb_decrypt); - -static int cfb_decrypt(struct skcipher_request *req) -{ - return sm4_avx_cfb_decrypt(req, SM4_CRYPT8_BLOCK_SIZE, - sm4_aesni_avx_cfb_dec_blk8); -} - int sm4_avx_ctr_crypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func) { @@ -406,24 +294,6 @@ static struct skcipher_alg sm4_aesni_avx_skciphers[] = { .setkey = sm4_skcipher_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = cbc_decrypt, - }, { - .base = { - .cra_name = "__cfb(sm4)", - .cra_driver_name = "__cfb-sm4-aesni-avx", - .cra_priority = 400, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .walksize = 8 * SM4_BLOCK_SIZE, - .setkey = sm4_skcipher_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = cfb_decrypt, }, { .base = { .cra_name = "__ctr(sm4)", From a9cdf13e9ba940ad5498967d60d09c6c1f020b64 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Sep 2023 17:21:14 +0800 Subject: [PATCH 3298/7721] crypto: crypto4xx - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_alg.c | 14 ---------- drivers/crypto/amcc/crypto4xx_core.c | 40 ---------------------------- drivers/crypto/amcc/crypto4xx_core.h | 4 --- 3 files changed, 58 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index ded732242732..e0af611a95d8 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -181,13 +181,6 @@ int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen) -{ - return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB, - CRYPTO_FEEDBACK_MODE_128BIT_CFB); -} - int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { @@ -195,13 +188,6 @@ int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen) -{ - return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB, - CRYPTO_FEEDBACK_MODE_64BIT_OFB); -} - int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 8d53372245ad..6006703fb6d7 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1209,26 +1209,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "cfb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_cfb, - .encrypt = crypto4xx_encrypt_iv_stream, - .decrypt = crypto4xx_decrypt_iv_stream, - .init = crypto4xx_sk_init, - .exit = crypto4xx_sk_exit, - } }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { .base = { .cra_name = "ctr(aes)", @@ -1289,26 +1269,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "ofb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_ofb, - .encrypt = crypto4xx_encrypt_iv_stream, - .decrypt = crypto4xx_decrypt_iv_stream, - .init = crypto4xx_sk_init, - .exit = crypto4xx_sk_exit, - } }, /* AEAD */ { .type = CRYPTO_ALG_TYPE_AEAD, .u.aead = { diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 56c10668c0ab..96355d463b04 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -162,14 +162,10 @@ int crypto4xx_build_pd(struct crypto_async_request *req, struct scatterlist *dst_tmp); int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen); int crypto4xx_setkey_aes_ctr(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen); int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); int crypto4xx_encrypt_ctr(struct skcipher_request *req); From 00b05e51222337d1c3b08130f320e1a43af8f73b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Sep 2023 17:23:23 +0800 Subject: [PATCH 3299/7721] crypto: aspeed - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/aspeed/Kconfig | 4 +- drivers/crypto/aspeed/aspeed-hace-crypto.c | 230 --------------------- 2 files changed, 1 insertion(+), 233 deletions(-) diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index db6c5b4cdc40..e93f2f82b418 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -38,14 +38,12 @@ config CRYPTO_DEV_ASPEED_HACE_CRYPTO select CRYPTO_DES select CRYPTO_ECB select CRYPTO_CBC - select CRYPTO_CFB - select CRYPTO_OFB select CRYPTO_CTR help Select here to enable Aspeed Hash & Crypto Engine (HACE) crypto driver. Supports AES/DES symmetric-key encryption and decryption - with ECB/CBC/CFB/OFB/CTR options. + with ECB/CBC/CTR options. config CRYPTO_DEV_ASPEED_ACRY bool "Enable Aspeed ACRY RSA Engine" diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/aspeed-hace-crypto.c index f0eddb7854e5..a72dfebc53ff 100644 --- a/drivers/crypto/aspeed/aspeed-hace-crypto.c +++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c @@ -473,30 +473,6 @@ static int aspeed_tdes_ctr_encrypt(struct skcipher_request *req) HACE_CMD_TRIPLE_DES); } -static int aspeed_tdes_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB | - HACE_CMD_TRIPLE_DES); -} - static int aspeed_tdes_cbc_decrypt(struct skcipher_request *req) { return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC | @@ -533,30 +509,6 @@ static int aspeed_des_ctr_encrypt(struct skcipher_request *req) HACE_CMD_SINGLE_DES); } -static int aspeed_des_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB | - HACE_CMD_SINGLE_DES); -} - static int aspeed_des_cbc_decrypt(struct skcipher_request *req) { return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC | @@ -659,26 +611,6 @@ static int aspeed_aes_ctr_encrypt(struct skcipher_request *req) return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CTR); } -static int aspeed_aes_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB); -} - -static int aspeed_aes_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB); -} - -static int aspeed_aes_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB); -} - -static int aspeed_aes_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB); -} - static int aspeed_aes_cbc_decrypt(struct skcipher_request *req) { return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC); @@ -790,60 +722,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = aspeed_aes_setkey, - .encrypt = aspeed_aes_cfb_encrypt, - .decrypt = aspeed_aes_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "aspeed-cfb-aes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = aspeed_aes_setkey, - .encrypt = aspeed_aes_ofb_encrypt, - .decrypt = aspeed_aes_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "aspeed-ofb-aes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, { .alg.skcipher.base = { .min_keysize = DES_KEY_SIZE, @@ -897,60 +775,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_des_cfb_encrypt, - .decrypt = aspeed_des_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(des)", - .cra_driver_name = "aspeed-cfb-des", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_des_ofb_encrypt, - .decrypt = aspeed_des_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(des)", - .cra_driver_name = "aspeed-ofb-des", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, { .alg.skcipher.base = { .min_keysize = DES3_EDE_KEY_SIZE, @@ -1004,60 +828,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_tdes_cfb_encrypt, - .decrypt = aspeed_tdes_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(des3_ede)", - .cra_driver_name = "aspeed-cfb-tdes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_tdes_ofb_encrypt, - .decrypt = aspeed_tdes_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(des3_ede)", - .cra_driver_name = "aspeed-ofb-tdes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, }; static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = { From a16144bda9c332079b6a1db52725e9c22007114d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Sep 2023 17:33:56 +0800 Subject: [PATCH 3300/7721] crypto: atmel - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 214 +----------------------------------- drivers/crypto/atmel-tdes.c | 205 +--------------------------------- 2 files changed, 8 insertions(+), 411 deletions(-) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index d1d93e897892..8bd64fc37e75 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 */ @@ -2407,9 +2214,6 @@ 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]); } @@ -2434,14 +2238,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); @@ -2482,8 +2278,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) err_aes_xts_alg: 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++) @@ -2495,7 +2289,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) 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 +2300,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 +2307,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-tdes.c b/drivers/crypto/atmel-tdes.c index 27b7000e25bc..dcc2380a5889 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) @@ -1121,14 +930,12 @@ 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; From 769a043bf176c6cc66f8762a08cc81c93fa1b789 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 17:59:35 +0800 Subject: [PATCH 3301/7721] crypto: cpt - Remove cfb Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/cavium/cpt/cptvf_algs.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c index ee476c6c7f82..219fe9be7606 100644 --- a/drivers/crypto/cavium/cpt/cptvf_algs.c +++ b/drivers/crypto/cavium/cpt/cptvf_algs.c @@ -311,12 +311,6 @@ static int cvm_ecb_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, return cvm_setkey(cipher, key, keylen, AES_ECB); } -static int cvm_cfb_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, - u32 keylen) -{ - return cvm_setkey(cipher, key, keylen, AES_CFB); -} - static int cvm_cbc_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, u32 keylen) { @@ -391,24 +385,6 @@ static struct skcipher_alg algs[] = { { .encrypt = cvm_encrypt, .decrypt = cvm_decrypt, .init = cvm_enc_dec_init, -}, { - .base.cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct cvm_enc_ctx), - .base.cra_alignmask = 7, - .base.cra_priority = 4001, - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "cavium-cfb-aes", - .base.cra_module = THIS_MODULE, - - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = cvm_cfb_aes_setkey, - .encrypt = cvm_encrypt, - .decrypt = cvm_decrypt, - .init = cvm_enc_dec_init, }, { .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, From f5a019f5b094fc4cedda413571ece59931932a02 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:06:34 +0800 Subject: [PATCH 3302/7721] crypto: nitrox - Remove cfb Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- .../crypto/cavium/nitrox/nitrox_skcipher.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c index 138261dcd032..6e5e667bab75 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c +++ b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c @@ -419,25 +419,6 @@ static struct skcipher_alg nitrox_skciphers[] = { { .decrypt = nitrox_aes_decrypt, .init = nitrox_skcipher_init, .exit = nitrox_skcipher_exit, -}, { - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "n5_cfb(aes)", - .cra_priority = PRIO, - .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct nitrox_crypto_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = nitrox_aes_setkey, - .encrypt = nitrox_aes_encrypt, - .decrypt = nitrox_aes_decrypt, - .init = nitrox_skcipher_init, - .exit = nitrox_skcipher_exit, }, { .base = { .cra_name = "xts(aes)", From e54f2a5ee8fca19c107f6688c2e1738aeb1d86d9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:07:04 +0800 Subject: [PATCH 3303/7721] crypto: ccp - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-aes.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 918e223f21b6..d11daaf47f06 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -266,24 +266,6 @@ static struct ccp_aes_def aes_algs[] = { .ivsize = AES_BLOCK_SIZE, .alg_defaults = &ccp_aes_defaults, }, - { - .mode = CCP_AES_MODE_CFB, - .version = CCP_VERSION(3, 0), - .name = "cfb(aes)", - .driver_name = "cfb-aes-ccp", - .blocksize = 1, - .ivsize = AES_BLOCK_SIZE, - .alg_defaults = &ccp_aes_defaults, - }, - { - .mode = CCP_AES_MODE_OFB, - .version = CCP_VERSION(3, 0), - .name = "ofb(aes)", - .driver_name = "ofb-aes-ccp", - .blocksize = 1, - .ivsize = AES_BLOCK_SIZE, - .alg_defaults = &ccp_aes_defaults, - }, { .mode = CCP_AES_MODE_CTR, .version = CCP_VERSION(3, 0), From 572ef735049c10d8d27185438ecff33a265a1481 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:08:18 +0800 Subject: [PATCH 3304/7721] crypto: hifn_795x - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/hifn_795x.c | 126 +------------------------------------ 1 file changed, 3 insertions(+), 123 deletions(-) diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 7bddc3c786c1..b4a4ec35bce0 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2096,16 +2096,6 @@ static inline int hifn_encrypt_aes_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_aes_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_aes_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); -} /* * AES decryption functions. @@ -2120,16 +2110,6 @@ static inline int hifn_decrypt_aes_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_aes_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_aes_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); -} /* * DES ecryption functions. @@ -2144,16 +2124,6 @@ static inline int hifn_encrypt_des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); -} /* * DES decryption functions. @@ -2168,16 +2138,6 @@ static inline int hifn_decrypt_des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); -} /* * 3DES ecryption functions. @@ -2192,16 +2152,6 @@ static inline int hifn_encrypt_3des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_3des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_3des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); -} /* 3DES decryption functions. */ static inline int hifn_decrypt_3des_ecb(struct skcipher_request *req) @@ -2214,16 +2164,6 @@ static inline int hifn_decrypt_3des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_3des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_3des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); -} struct hifn_alg_template { char name[CRYPTO_MAX_ALG_NAME]; @@ -2234,28 +2174,8 @@ struct hifn_alg_template { static const struct hifn_alg_template hifn_alg_templates[] = { /* - * 3DES ECB, CBC, CFB and OFB modes. + * 3DES ECB and CBC modes. */ - { - .name = "cfb(des3_ede)", .drv_name = "cfb-3des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_3DES_KEY_LENGTH, - .max_keysize = HIFN_3DES_KEY_LENGTH, - .setkey = hifn_des3_setkey, - .encrypt = hifn_encrypt_3des_cfb, - .decrypt = hifn_decrypt_3des_cfb, - }, - }, - { - .name = "ofb(des3_ede)", .drv_name = "ofb-3des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_3DES_KEY_LENGTH, - .max_keysize = HIFN_3DES_KEY_LENGTH, - .setkey = hifn_des3_setkey, - .encrypt = hifn_encrypt_3des_ofb, - .decrypt = hifn_decrypt_3des_ofb, - }, - }, { .name = "cbc(des3_ede)", .drv_name = "cbc-3des", .bsize = 8, .skcipher = { @@ -2279,28 +2199,8 @@ static const struct hifn_alg_template hifn_alg_templates[] = { }, /* - * DES ECB, CBC, CFB and OFB modes. + * DES ECB and CBC modes. */ - { - .name = "cfb(des)", .drv_name = "cfb-des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_DES_KEY_LENGTH, - .max_keysize = HIFN_DES_KEY_LENGTH, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_des_cfb, - .decrypt = hifn_decrypt_des_cfb, - }, - }, - { - .name = "ofb(des)", .drv_name = "ofb-des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_DES_KEY_LENGTH, - .max_keysize = HIFN_DES_KEY_LENGTH, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_des_ofb, - .decrypt = hifn_decrypt_des_ofb, - }, - }, { .name = "cbc(des)", .drv_name = "cbc-des", .bsize = 8, .skcipher = { @@ -2324,7 +2224,7 @@ static const struct hifn_alg_template hifn_alg_templates[] = { }, /* - * AES ECB, CBC, CFB and OFB modes. + * AES ECB and CBC modes. */ { .name = "ecb(aes)", .drv_name = "ecb-aes", .bsize = 16, @@ -2347,26 +2247,6 @@ static const struct hifn_alg_template hifn_alg_templates[] = { .decrypt = hifn_decrypt_aes_cbc, }, }, - { - .name = "cfb(aes)", .drv_name = "cfb-aes", .bsize = 16, - .skcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_aes_cfb, - .decrypt = hifn_decrypt_aes_cfb, - }, - }, - { - .name = "ofb(aes)", .drv_name = "ofb-aes", .bsize = 16, - .skcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_aes_ofb, - .decrypt = hifn_decrypt_aes_ofb, - }, - }, }; static int hifn_init_tfm(struct crypto_skcipher *tfm) From 1c90a1b43bc34eaf9c8913238f408a1317eab43f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:09:24 +0800 Subject: [PATCH 3305/7721] crypto: hisilicon/sec2 - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 26 ---------------------- drivers/crypto/hisilicon/sec2/sec_crypto.h | 2 -- drivers/crypto/hisilicon/sec2/sec_main.c | 2 +- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index ba7f305d43c1..c760f3a8af4d 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -879,15 +879,11 @@ static int sec_setkey_##name(struct crypto_skcipher *tfm, const u8 *key,\ GEN_SEC_SETKEY_FUNC(aes_ecb, SEC_CALG_AES, SEC_CMODE_ECB) GEN_SEC_SETKEY_FUNC(aes_cbc, SEC_CALG_AES, SEC_CMODE_CBC) GEN_SEC_SETKEY_FUNC(aes_xts, SEC_CALG_AES, SEC_CMODE_XTS) -GEN_SEC_SETKEY_FUNC(aes_ofb, SEC_CALG_AES, SEC_CMODE_OFB) -GEN_SEC_SETKEY_FUNC(aes_cfb, SEC_CALG_AES, SEC_CMODE_CFB) GEN_SEC_SETKEY_FUNC(aes_ctr, SEC_CALG_AES, SEC_CMODE_CTR) GEN_SEC_SETKEY_FUNC(3des_ecb, SEC_CALG_3DES, SEC_CMODE_ECB) GEN_SEC_SETKEY_FUNC(3des_cbc, SEC_CALG_3DES, SEC_CMODE_CBC) GEN_SEC_SETKEY_FUNC(sm4_xts, SEC_CALG_SM4, SEC_CMODE_XTS) GEN_SEC_SETKEY_FUNC(sm4_cbc, SEC_CALG_SM4, SEC_CMODE_CBC) -GEN_SEC_SETKEY_FUNC(sm4_ofb, SEC_CALG_SM4, SEC_CMODE_OFB) -GEN_SEC_SETKEY_FUNC(sm4_cfb, SEC_CALG_SM4, SEC_CMODE_CFB) GEN_SEC_SETKEY_FUNC(sm4_ctr, SEC_CALG_SM4, SEC_CMODE_CTR) static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req, @@ -2032,8 +2028,6 @@ static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, ret = -EINVAL; } break; - case SEC_CMODE_CFB: - case SEC_CMODE_OFB: case SEC_CMODE_CTR: if (unlikely(ctx->sec->qm.ver < QM_HW_V3)) { dev_err(dev, "skcipher HW version error!\n"); @@ -2197,16 +2191,6 @@ static struct sec_skcipher sec_skciphers[] = { .alg = SEC_SKCIPHER_ALG("xts(aes)", sec_setkey_aes_xts, SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MAX_KEY_SIZE, AES_BLOCK_SIZE, AES_BLOCK_SIZE), }, - { - .alg_msk = BIT(4), - .alg = SEC_SKCIPHER_ALG("ofb(aes)", sec_setkey_aes_ofb, AES_MIN_KEY_SIZE, - AES_MAX_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, - { - .alg_msk = BIT(5), - .alg = SEC_SKCIPHER_ALG("cfb(aes)", sec_setkey_aes_cfb, AES_MIN_KEY_SIZE, - AES_MAX_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, { .alg_msk = BIT(12), .alg = SEC_SKCIPHER_ALG("cbc(sm4)", sec_setkey_sm4_cbc, AES_MIN_KEY_SIZE, @@ -2222,16 +2206,6 @@ static struct sec_skcipher sec_skciphers[] = { .alg = SEC_SKCIPHER_ALG("xts(sm4)", sec_setkey_sm4_xts, SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MIN_KEY_SIZE, AES_BLOCK_SIZE, AES_BLOCK_SIZE), }, - { - .alg_msk = BIT(15), - .alg = SEC_SKCIPHER_ALG("ofb(sm4)", sec_setkey_sm4_ofb, AES_MIN_KEY_SIZE, - AES_MIN_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, - { - .alg_msk = BIT(16), - .alg = SEC_SKCIPHER_ALG("cfb(sm4)", sec_setkey_sm4_cfb, AES_MIN_KEY_SIZE, - AES_MIN_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, { .alg_msk = BIT(23), .alg = SEC_SKCIPHER_ALG("ecb(des3_ede)", sec_setkey_3des_ecb, SEC_DES3_3KEY_SIZE, diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h index d033f63b583f..27a0ee5ad913 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.h +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h @@ -37,8 +37,6 @@ enum sec_mac_len { enum sec_cmode { SEC_CMODE_ECB = 0x0, SEC_CMODE_CBC = 0x1, - SEC_CMODE_CFB = 0x2, - SEC_CMODE_OFB = 0x3, SEC_CMODE_CTR = 0x4, SEC_CMODE_CCM = 0x5, SEC_CMODE_GCM = 0x6, diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 878d94ab5d6d..7bb99381bbdf 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -153,7 +153,7 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE_NUM_CAP, 0x313c, 8, GENMASK(7, 0), 0x4, 0x4, 0x4}, {SEC_CORES_PER_CLUSTER_NUM_CAP, 0x313c, 0, GENMASK(7, 0), 0x4, 0x4, 0x4}, {SEC_CORE_ENABLE_BITMAP, 0x3140, 32, GENMASK(31, 0), 0x17F, 0x17F, 0xF}, - {SEC_DRV_ALG_BITMAP_LOW, 0x3144, 0, GENMASK(31, 0), 0x18050CB, 0x18050CB, 0x187F0FF}, + {SEC_DRV_ALG_BITMAP_LOW, 0x3144, 0, GENMASK(31, 0), 0x18050CB, 0x18050CB, 0x18670CF}, {SEC_DRV_ALG_BITMAP_HIGH, 0x3148, 0, GENMASK(31, 0), 0x395C, 0x395C, 0x395C}, {SEC_DEV_ALG_BITMAP_LOW, 0x314c, 0, GENMASK(31, 0), 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {SEC_DEV_ALG_BITMAP_HIGH, 0x3150, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, From dfe6c5d16b31bef466e49ed06092ecfe6681c036 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:10:21 +0800 Subject: [PATCH 3306/7721] crypto: safexcel - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/safexcel.c | 4 - drivers/crypto/inside-secure/safexcel.h | 4 - .../crypto/inside-secure/safexcel_cipher.c | 152 ------------------ 3 files changed, 160 deletions(-) diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 76da14af74b5..f5c1912aa564 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -1191,8 +1191,6 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_cbc_des3_ede, &safexcel_alg_ecb_aes, &safexcel_alg_cbc_aes, - &safexcel_alg_cfb_aes, - &safexcel_alg_ofb_aes, &safexcel_alg_ctr_aes, &safexcel_alg_md5, &safexcel_alg_sha1, @@ -1231,8 +1229,6 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_hmac_sm3, &safexcel_alg_ecb_sm4, &safexcel_alg_cbc_sm4, - &safexcel_alg_ofb_sm4, - &safexcel_alg_cfb_sm4, &safexcel_alg_ctr_sm4, &safexcel_alg_authenc_hmac_sha1_cbc_sm4, &safexcel_alg_authenc_hmac_sm3_cbc_sm4, diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 47ef6c7cd02c..d0059ce954dd 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -933,8 +933,6 @@ extern struct safexcel_alg_template safexcel_alg_ecb_des3_ede; extern struct safexcel_alg_template safexcel_alg_cbc_des3_ede; extern struct safexcel_alg_template safexcel_alg_ecb_aes; extern struct safexcel_alg_template safexcel_alg_cbc_aes; -extern struct safexcel_alg_template safexcel_alg_cfb_aes; -extern struct safexcel_alg_template safexcel_alg_ofb_aes; extern struct safexcel_alg_template safexcel_alg_ctr_aes; extern struct safexcel_alg_template safexcel_alg_md5; extern struct safexcel_alg_template safexcel_alg_sha1; @@ -973,8 +971,6 @@ extern struct safexcel_alg_template safexcel_alg_sm3; extern struct safexcel_alg_template safexcel_alg_hmac_sm3; extern struct safexcel_alg_template safexcel_alg_ecb_sm4; extern struct safexcel_alg_template safexcel_alg_cbc_sm4; -extern struct safexcel_alg_template safexcel_alg_ofb_sm4; -extern struct safexcel_alg_template safexcel_alg_cfb_sm4; extern struct safexcel_alg_template safexcel_alg_ctr_sm4; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4; diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index b83818634ae4..42677f7458b7 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -1352,82 +1352,6 @@ struct safexcel_alg_template safexcel_alg_cbc_aes = { }, }; -static int safexcel_skcipher_aes_cfb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_AES; - ctx->blocksz = AES_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_cfb_aes = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "safexcel-cfb-aes", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_aes_cfb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - -static int safexcel_skcipher_aes_ofb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_AES; - ctx->blocksz = AES_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_ofb_aes = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "safexcel-ofb-aes", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_aes_ofb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - static int safexcel_skcipher_aesctr_setkey(struct crypto_skcipher *ctfm, const u8 *key, unsigned int len) { @@ -3186,82 +3110,6 @@ struct safexcel_alg_template safexcel_alg_cbc_sm4 = { }, }; -static int safexcel_skcipher_sm4_ofb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_SM4; - ctx->blocksz = SM4_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_ofb_sm4 = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_sm4_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .base = { - .cra_name = "ofb(sm4)", - .cra_driver_name = "safexcel-ofb-sm4", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_sm4_ofb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - -static int safexcel_skcipher_sm4_cfb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_SM4; - ctx->blocksz = SM4_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_cfb_sm4 = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_sm4_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "safexcel-cfb-sm4", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_sm4_cfb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - static int safexcel_skcipher_sm4ctr_setkey(struct crypto_skcipher *ctfm, const u8 *key, unsigned int len) { From 63340c481b859154ad4486f68c9d1b01ace5650e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:11:07 +0800 Subject: [PATCH 3307/7721] crypto: octeontx - Remove cfb Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- .../crypto/marvell/octeontx/otx_cptvf_algs.c | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c index 1c2c870e887a..3c5d577d8f0d 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c @@ -473,12 +473,6 @@ static int otx_cpt_skcipher_ecb_aes_setkey(struct crypto_skcipher *tfm, return cpt_aes_setkey(tfm, key, keylen, OTX_CPT_AES_ECB); } -static int otx_cpt_skcipher_cfb_aes_setkey(struct crypto_skcipher *tfm, - const u8 *key, u32 keylen) -{ - return cpt_aes_setkey(tfm, key, keylen, OTX_CPT_AES_CFB); -} - static int otx_cpt_skcipher_cbc_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, u32 keylen) { @@ -1351,23 +1345,6 @@ static struct skcipher_alg otx_cpt_skciphers[] = { { .setkey = otx_cpt_skcipher_ecb_aes_setkey, .encrypt = otx_cpt_skcipher_encrypt, .decrypt = otx_cpt_skcipher_decrypt, -}, { - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "cpt_cfb_aes", - .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct otx_cpt_enc_ctx), - .base.cra_alignmask = 7, - .base.cra_priority = 4001, - .base.cra_module = THIS_MODULE, - - .init = otx_cpt_enc_dec_init, - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = otx_cpt_skcipher_cfb_aes_setkey, - .encrypt = otx_cpt_skcipher_encrypt, - .decrypt = otx_cpt_skcipher_decrypt, }, { .base.cra_name = "cbc(des3_ede)", .base.cra_driver_name = "cpt_cbc_des3_ede", From 66c465c6e7b1867b8bae1194ecfb05556ac7aa07 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:11:51 +0800 Subject: [PATCH 3308/7721] crypto: n2 - Remove cfb Remove the unused CFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/n2_core.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 37d958cfa9bb..7a3083debc2b 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1121,19 +1121,6 @@ static const struct n2_skcipher_tmpl skcipher_tmpls[] = { .decrypt = n2_decrypt_chaining, }, }, - { .name = "cfb(des)", - .drv_name = "cfb-des", - .block_size = DES_BLOCK_SIZE, - .enc_type = (ENC_TYPE_ALG_DES | - ENC_TYPE_CHAINING_CFB), - .skcipher = { - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = n2_des_setkey, - .encrypt = n2_encrypt_chaining, - .decrypt = n2_decrypt_chaining, - }, - }, /* 3DES: ECB CBC and CFB are supported */ { .name = "ecb(des3_ede)", @@ -1163,19 +1150,7 @@ static const struct n2_skcipher_tmpl skcipher_tmpls[] = { .decrypt = n2_decrypt_chaining, }, }, - { .name = "cfb(des3_ede)", - .drv_name = "cfb-3des", - .block_size = DES_BLOCK_SIZE, - .enc_type = (ENC_TYPE_ALG_3DES | - ENC_TYPE_CHAINING_CFB), - .skcipher = { - .min_keysize = 3 * DES_KEY_SIZE, - .max_keysize = 3 * DES_KEY_SIZE, - .setkey = n2_3des_setkey, - .encrypt = n2_encrypt_chaining, - .decrypt = n2_decrypt_chaining, - }, - }, + /* AES: ECB CBC and CTR are supported */ { .name = "ecb(aes)", .drv_name = "ecb-aes", From 015b8e121082671f14cf2912df9afbfd139575b4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:12:55 +0800 Subject: [PATCH 3309/7721] crypto: starfive - Remove cfb and ofb Remove the unused CFB/OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-aes.c | 71 +-------------------------- drivers/crypto/starfive/jh7110-cryp.h | 2 - 2 files changed, 1 insertion(+), 72 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c index e0fe599f8192..1ac15cc4ef3c 100644 --- a/drivers/crypto/starfive/jh7110-aes.c +++ b/drivers/crypto/starfive/jh7110-aes.c @@ -262,12 +262,7 @@ static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx) rctx->csr.aes.mode = hw_mode; rctx->csr.aes.cmode = !is_encrypt(cryp); rctx->csr.aes.ie = 1; - - if (hw_mode == STARFIVE_AES_MODE_CFB || - hw_mode == STARFIVE_AES_MODE_OFB) - rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_128; - else - rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1; + rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1; if (cryp->side_chan) { rctx->csr.aes.delay_aes = 1; @@ -294,8 +289,6 @@ static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx) starfive_aes_ccm_init(ctx); starfive_aes_aead_hw_start(ctx, hw_mode); break; - case STARFIVE_AES_MODE_OFB: - case STARFIVE_AES_MODE_CFB: case STARFIVE_AES_MODE_CBC: case STARFIVE_AES_MODE_CTR: starfive_aes_write_iv(ctx, (void *)cryp->req.sreq->iv); @@ -785,26 +778,6 @@ static int starfive_aes_cbc_decrypt(struct skcipher_request *req) return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC); } -static int starfive_aes_cfb_encrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB | FLG_ENCRYPT); -} - -static int starfive_aes_cfb_decrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB); -} - -static int starfive_aes_ofb_encrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB | FLG_ENCRYPT); -} - -static int starfive_aes_ofb_decrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB); -} - static int starfive_aes_ctr_encrypt(struct skcipher_request *req) { return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR | FLG_ENCRYPT); @@ -910,48 +883,6 @@ static struct skcipher_engine_alg skcipher_algs[] = { .op = { .do_one_request = starfive_aes_do_one_req, }, -}, { - .base.init = starfive_aes_init_tfm, - .base.setkey = starfive_aes_setkey, - .base.encrypt = starfive_aes_cfb_encrypt, - .base.decrypt = starfive_aes_cfb_decrypt, - .base.min_keysize = AES_MIN_KEY_SIZE, - .base.max_keysize = AES_MAX_KEY_SIZE, - .base.ivsize = AES_BLOCK_SIZE, - .base.base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "starfive-cfb-aes", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct starfive_cryp_ctx), - .cra_alignmask = 0xf, - .cra_module = THIS_MODULE, - }, - .op = { - .do_one_request = starfive_aes_do_one_req, - }, -}, { - .base.init = starfive_aes_init_tfm, - .base.setkey = starfive_aes_setkey, - .base.encrypt = starfive_aes_ofb_encrypt, - .base.decrypt = starfive_aes_ofb_decrypt, - .base.min_keysize = AES_MIN_KEY_SIZE, - .base.max_keysize = AES_MAX_KEY_SIZE, - .base.ivsize = AES_BLOCK_SIZE, - .base.base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "starfive-ofb-aes", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct starfive_cryp_ctx), - .cra_alignmask = 0xf, - .cra_module = THIS_MODULE, - }, - .op = { - .do_one_request = starfive_aes_do_one_req, - }, }, }; diff --git a/drivers/crypto/starfive/jh7110-cryp.h b/drivers/crypto/starfive/jh7110-cryp.h index 8510f8c1f307..6cdf6db5d904 100644 --- a/drivers/crypto/starfive/jh7110-cryp.h +++ b/drivers/crypto/starfive/jh7110-cryp.h @@ -50,8 +50,6 @@ union starfive_aes_csr { u32 ccm_start :1; #define STARFIVE_AES_MODE_ECB 0x0 #define STARFIVE_AES_MODE_CBC 0x1 -#define STARFIVE_AES_MODE_CFB 0x2 -#define STARFIVE_AES_MODE_OFB 0x3 #define STARFIVE_AES_MODE_CTR 0x4 #define STARFIVE_AES_MODE_CCM 0x5 #define STARFIVE_AES_MODE_GCM 0x6 From fef39f99d571554ddd2f349231cc56c23f5fe0c6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:58:48 +0800 Subject: [PATCH 3310/7721] crypto: bcm - Remove ofb Remove the unused OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/bcm/cipher.c | 57 ------------------------------------- 1 file changed, 57 deletions(-) diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 10968ddb146b..1a3ecd44cbaf 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -3514,25 +3514,6 @@ static struct iproc_alg_s driver_algs[] = { }, /* SKCIPHER algorithms. */ - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(des)", - .base.cra_driver_name = "ofb-des-iproc", - .base.cra_blocksize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_DES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { @@ -3571,25 +3552,6 @@ static struct iproc_alg_s driver_algs[] = { .mode = HASH_MODE_NONE, }, }, - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(des3_ede)", - .base.cra_driver_name = "ofb-des3-iproc", - .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_3DES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { @@ -3628,25 +3590,6 @@ static struct iproc_alg_s driver_algs[] = { .mode = HASH_MODE_NONE, }, }, - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(aes)", - .base.cra_driver_name = "ofb-aes-iproc", - .base.cra_blocksize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_AES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { From 92650f930073a0d98c8479b0b4341a613223ec10 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:59:47 +0800 Subject: [PATCH 3311/7721] crypto: ccree - Remove ofb Remove the unused OFB implementation. Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_cipher.c | 35 -------------------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index d229e54fa935..cd66a580e8b6 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -1079,24 +1079,6 @@ static const struct cc_alg_template skcipher_algs[] = { .std_body = CC_STD_NIST, .sec_func = true, }, - { - .name = "ofb(paes)", - .driver_name = "ofb-paes-ccree", - .blocksize = AES_BLOCK_SIZE, - .template_skcipher = { - .setkey = cc_cipher_sethkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = CC_HW_KEY_SIZE, - .max_keysize = CC_HW_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_OFB, - .flow_mode = S_DIN_to_AES, - .min_hw_rev = CC_HW_REV_712, - .std_body = CC_STD_NIST, - .sec_func = true, - }, { .name = "cts(cbc(paes))", .driver_name = "cts-cbc-paes-ccree", @@ -1205,23 +1187,6 @@ static const struct cc_alg_template skcipher_algs[] = { .min_hw_rev = CC_HW_REV_630, .std_body = CC_STD_NIST, }, - { - .name = "ofb(aes)", - .driver_name = "ofb-aes-ccree", - .blocksize = 1, - .template_skcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_OFB, - .flow_mode = S_DIN_to_AES, - .min_hw_rev = CC_HW_REV_630, - .std_body = CC_STD_NIST, - }, { .name = "cts(cbc(aes))", .driver_name = "cts-cbc-aes-ccree", From 1c95b5469ee313dba6fe1e0d7197b0a6544b8ed0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 18:56:59 +0800 Subject: [PATCH 3312/7721] crypto: tcrypt - Remove cfb and ofb Remove tests for CFB/OFB. Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 76 ------------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 202ca1a3105d..ea4d1cea9c06 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1524,8 +1524,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret = min(ret, tcrypt_test("xts(aes)")); ret = min(ret, tcrypt_test("ctr(aes)")); ret = min(ret, tcrypt_test("rfc3686(ctr(aes))")); - ret = min(ret, tcrypt_test("ofb(aes)")); - ret = min(ret, tcrypt_test("cfb(aes)")); ret = min(ret, tcrypt_test("xctr(aes)")); break; @@ -1845,14 +1843,12 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) case 191: ret = min(ret, tcrypt_test("ecb(sm4)")); ret = min(ret, tcrypt_test("cbc(sm4)")); - ret = min(ret, tcrypt_test("cfb(sm4)")); ret = min(ret, tcrypt_test("ctr(sm4)")); ret = min(ret, tcrypt_test("xts(sm4)")); break; case 192: ret = min(ret, tcrypt_test("ecb(aria)")); ret = min(ret, tcrypt_test("cbc(aria)")); - ret = min(ret, tcrypt_test("cfb(aria)")); ret = min(ret, tcrypt_test("ctr(aria)")); break; case 200: @@ -1880,10 +1876,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_cipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); break; case 201: @@ -2115,10 +2107,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16); test_cipher_speed("cts(cbc(sm4))", DECRYPT, sec, NULL, 0, speed_template_16); - test_cipher_speed("cfb(sm4)", ENCRYPT, sec, NULL, 0, - speed_template_16); - test_cipher_speed("cfb(sm4)", DECRYPT, sec, NULL, 0, - speed_template_16); test_cipher_speed("ctr(sm4)", ENCRYPT, sec, NULL, 0, speed_template_16); test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, @@ -2198,10 +2186,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_cipher_speed("cbc(aria)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_cipher_speed("cfb(aria)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("cfb(aria)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); test_cipher_speed("ctr(aria)", ENCRYPT, sec, NULL, 0, speed_template_16_24_32); test_cipher_speed("ctr(aria)", DECRYPT, sec, NULL, 0, @@ -2436,14 +2420,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_acipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); test_acipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0, speed_template_20_28_36); test_acipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, 0, @@ -2463,18 +2439,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_acipher_speed("cbc(des3_ede)", DECRYPT, sec, des3_speed_template, DES3_SPEED_VECTORS, speed_template_24); - test_acipher_speed("cfb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("cfb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("ofb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("ofb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); break; case 502: @@ -2486,14 +2450,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_8); test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0, speed_template_8); - test_acipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("cfb(des)", DECRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("ofb(des)", DECRYPT, sec, NULL, 0, - speed_template_8); break; case 503: @@ -2632,10 +2588,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16); test_acipher_speed("cbc(sm4)", DECRYPT, sec, NULL, 0, speed_template_16); - test_acipher_speed("cfb(sm4)", ENCRYPT, sec, NULL, 0, - speed_template_16); - test_acipher_speed("cfb(sm4)", DECRYPT, sec, NULL, 0, - speed_template_16); test_acipher_speed("ctr(sm4)", ENCRYPT, sec, NULL, 0, speed_template_16); test_acipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, @@ -2682,14 +2634,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32, num_mb); test_mb_skcipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); test_mb_skcipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0, speed_template_20_28_36, num_mb); test_mb_skcipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, @@ -2709,18 +2653,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_mb_skcipher_speed("cbc(des3_ede)", DECRYPT, sec, des3_speed_template, DES3_SPEED_VECTORS, speed_template_24, num_mb); - test_mb_skcipher_speed("cfb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("cfb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("ofb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("ofb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); break; case 602: @@ -2732,14 +2664,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_8, num_mb); test_mb_skcipher_speed("cbc(des)", DECRYPT, sec, NULL, 0, speed_template_8, num_mb); - test_mb_skcipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("cfb(des)", DECRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("ofb(des)", DECRYPT, sec, NULL, 0, - speed_template_8, num_mb); break; case 603: From d4bd2102472c4071d0df4a948316f73390228faf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 20:23:06 +0800 Subject: [PATCH 3313/7721] crypto: testmgr - Remove cfb and ofb Remove test vectors for CFB/OFB. Signed-off-by: Herbert Xu --- crypto/testmgr.c | 39 -- crypto/testmgr.h | 1148 ---------------------------------------------- 2 files changed, 1187 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 59f0540d442e..e23a34337faf 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4608,25 +4608,6 @@ static const struct alg_test_desc alg_test_descs[] = { .einval_allowed = 1, } } - }, { - .alg = "cfb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = __VECS(aes_cfb_tv_template) - }, - }, { - .alg = "cfb(aria)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(aria_cfb_tv_template) - }, - }, { - .alg = "cfb(sm4)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(sm4_cfb_tv_template) - } }, { .alg = "chacha20", .test = alg_test_skcipher, @@ -5402,26 +5383,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(nhpoly1305_tv_template) } - }, { - .alg = "ofb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = __VECS(aes_ofb_tv_template) - } - }, { - /* Same as ofb(aes) except the key is stored in - * hardware secure memory which we reference by index - */ - .alg = "ofb(paes)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "ofb(sm4)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(sm4_ofb_tv_template) - } }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index d7e98397549b..986f331a5fc2 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -14704,104 +14704,6 @@ static const struct cipher_testvec sm4_ctr_rfc3686_tv_template[] = { } }; -static const struct cipher_testvec sm4_ofb_tv_template[] = { - { /* From: draft-ribose-cfrg-sm4-02, paragraph 12.2.3 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ctext = "\x69\x3d\x9a\x53\x5b\xad\x5b\xb1" - "\x78\x6f\x53\xd7\x25\x3a\x70\x56" - "\xf2\x07\x5d\x28\xb5\x23\x5f\x58" - "\xd5\x00\x27\xe4\x17\x7d\x2b\xce", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.3, Example 1 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\xac\x32\x36\xcb\x86\x1d\xd3\x16" - "\xe6\x41\x3b\x4e\x3c\x75\x24\xb7" - "\x1d\x01\xac\xa2\x48\x7c\xa5\x82" - "\xcb\xf5\x46\x3e\x66\x98\x53\x9b", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.3, Example 2 */ - .key = "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\x5d\xcc\xcd\x25\xa8\x4b\xa1\x65" - "\x60\xd7\xf2\x65\x88\x70\x68\x49" - "\x33\xfa\x16\xbd\x5c\xd9\xc8\x56" - "\xca\xca\xa1\xe1\x01\x89\x7a\x97", - .len = 32, - } -}; - -static const struct cipher_testvec sm4_cfb_tv_template[] = { - { /* From: draft-ribose-cfrg-sm4-02, paragraph 12.2.4 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ctext = "\x69\x3d\x9a\x53\x5b\xad\x5b\xb1" - "\x78\x6f\x53\xd7\x25\x3a\x70\x56" - "\x9e\xd2\x58\xa8\x5a\x04\x67\xcc" - "\x92\xaa\xb3\x93\xdd\x97\x89\x95", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.4, Example 1 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\xac\x32\x36\xcb\x86\x1d\xd3\x16" - "\xe6\x41\x3b\x4e\x3c\x75\x24\xb7" - "\x69\xd4\xc5\x4e\xd4\x33\xb9\xa0" - "\x34\x60\x09\xbe\xb3\x7b\x2b\x3f", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.4, Example 2 */ - .key = "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\x5d\xcc\xcd\x25\xa8\x4b\xa1\x65" - "\x60\xd7\xf2\x65\x88\x70\x68\x49" - "\x0d\x9b\x86\xff\x20\xc3\xbf\xe1" - "\x15\xff\xa0\x2c\xa6\x19\x2c\xc5", - .len = 32, - } -}; - static const struct cipher_testvec sm4_cts_tv_template[] = { /* Generated from AES-CTS test vectors */ { @@ -17064,104 +16966,6 @@ static const struct cipher_testvec aes_cbc_tv_template[] = { }, }; -static const struct cipher_testvec aes_cfb_tv_template[] = { - { /* From NIST SP800-38A */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f" - "\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b" - "\x26\x75\x1f\x67\xa3\xcb\xb1\x40" - "\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf" - "\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e" - "\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6", - .len = 64, - }, { - .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" - "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" - "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", - .klen = 24, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab" - "\x34\xc2\x59\x09\xc9\x9a\x41\x74" - "\x67\xce\x7f\x7f\x81\x17\x36\x21" - "\x96\x1a\x2b\x70\x17\x1d\x3d\x7a" - "\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1" - "\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9" - "\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0" - "\x42\xae\x8f\xba\x58\x4b\x09\xff", - .len = 64, - }, { - .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" - "\x2b\x73\xae\xf0\x85\x7d\x77\x81" - "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" - "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", - .klen = 32, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\xdc\x7e\x84\xbf\xda\x79\x16\x4b" - "\x7e\xcd\x84\x86\x98\x5d\x38\x60" - "\x39\xff\xed\x14\x3b\x28\xb1\xc8" - "\x32\x11\x3c\x63\x31\xe5\x40\x7b" - "\xdf\x10\x13\x24\x15\xe5\x4b\x92" - "\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9" - "\x75\xa3\x85\x74\x1a\xb9\xce\xf8" - "\x20\x31\x62\x3d\x55\xb1\xe4\x71", - .len = 64, - }, { /* > 16 bytes, not a multiple of 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\xc8", - .len = 17, - }, { /* < 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad", - .len = 7, - }, -}; - static const struct aead_testvec hmac_md5_ecb_cipher_null_tv_template[] = { { /* Input data from RFC 2410 Case 1 */ #ifdef __LITTLE_ENDIAN @@ -20852,55 +20656,6 @@ static const struct cipher_testvec aes_ctr_rfc3686_tv_template[] = { }, }; -static const struct cipher_testvec aes_ofb_tv_template[] = { - { /* From NIST Special Publication 800-38A, Appendix F.5 */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" - "\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" - "\x3c\x52\xda\xc5\x4e\xd8\x25" - "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" - "\x44\xf7\xa8\x22\x60\xed\xcc" - "\x30\x4c\x65\x28\xf6\x59\xc7\x78" - "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", - .len = 64, - }, { /* > 16 bytes, not a multiple of 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\x77", - .len = 17, - }, { /* < 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad", - .len = 7, - } -}; - static const struct aead_testvec aes_gcm_tv_template[] = { { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ .key = zeroed_string, @@ -29349,909 +29104,6 @@ static const struct cipher_testvec aria_ctr_tv_template[] = { } }; -static const struct cipher_testvec aria_cfb_tv_template[] = { - { - .key = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23" - "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1", - .klen = 16, - .iv = "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0" - "\xfd\xab\x56\xa6\x6e\xda\x7c\x57", - .ptext = "\x36\x36\x89\x09\xcd\xa8\xd3\x91" - "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0", - .ctext = "\x19\x28\xb5\xf2\x1c\xbc\xf8\xaf" - "\xb9\xae\x1b\x23\x4f\xe1\x6e\x40", - }, { - .key = "\x51\xe3\x8c\xe9\x76\xcd\xff\x37" - "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe", - .klen = 16, - .iv = "\x3d\x2d\x85\x75\x6e\x18\x8a\x52" - "\x53\x39\xfc\xc1\xf5\xc0\x56\x22", - .ptext = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93" - "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e" - "\xfa\x3f\x70\x52\xfb\x04\x0e\xed" - "\x0e\x60\x75\x84\x21\xdf\x13\xa1", - .ctext = "\x3f\x8c\xa9\x19\xd6\xb4\xfb\xed" - "\x9c\x6d\xaa\x1b\xe1\xc1\xe6\xa8" - "\x47\x35\x7d\xa3\x96\x7d\x53\x60" - "\xa9\x33\x9c\x34\xae\x7d\x7c\x74", - .len = 32, - }, { - .key = "\x26\xf8\x8c\x26\x0a\x37\x51\x8f" - "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d", - .klen = 16, - .iv = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea" - "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4", - .ptext = "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0" - "\xef\x3e\x5f\x46\x62\x88\xd5\x26" - "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2" - "\x39\x56\x34\x63\x2c\xc5\x51\x13" - "\x48\x29\x3a\x58\xbe\x41\xc5\x80" - "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e", - .ctext = "\x28\xd8\xa7\xf8\x74\x98\x00\xfc" - "\xd6\x48\xad\xbd\xbe\x3f\x0e\x7b" - "\xa3\xec\x03\x6a\xfb\xc9\x01\x83" - "\xb3\x2f\xda\x5e\x66\xa0\xc3\xec" - "\xe9\xd4\x72\x2a\xa2\x90\x41\xcf" - "\xde\x30\x79\xc3\x82\x10\x51\xe1", - .len = 48, - }, { - .key = "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b" - "\x77\xb5\xca\x90\xda\x1d\x22\x17", - .klen = 16, - .iv = "\xd9\xa0\x57\x80\xc8\x96\x70\x86" - "\x07\x2c\xf4\x61\x79\x09\x01\x8f", - .ptext = "\x37\x32\x98\xd4\x86\x2b\x3b\x80" - "\x07\x60\xba\xf0\x2e\xc3\x4a\x57" - "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a" - "\xe6\x08\xf0\xbe\x77\xd1\x62\x40" - "\xa0\x82\x09\x60\x47\xbb\x16\x56" - "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c" - "\x05\x32\x63\x1a\xc4\x46\x6f\x55" - "\x32\xde\x41\x5a\xf7\x52\xd7\xfa", - .ctext = "\x29\x31\x55\xd2\xe5\x0b\x81\x39" - "\xf9\xbc\x63\xe2\xfa\x26\x99\xde" - "\x5c\xd3\x0a\x56\xe5\xfc\x83\xdd" - "\xab\x26\x90\x7d\xa8\x0f\x01\xa6" - "\x0e\x01\xdc\x1f\xfa\xa7\xdd\x09" - "\xf9\xbf\x12\xf4\xc6\x9f\xbd\x57" - "\x23\x68\x54\x0f\xe0\xcf\x1c\x6d" - "\xe1\x5e\x0b\x4a\x1e\x71\x1d\xaa", - .len = 64, - }, { - .key = "\x30\x9d\x59\x8d\x64\x76\xad\x37" - "\xba\xbc\x46\x6a\x69\x17\x3c\xac", - .klen = 16, - .iv = "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e" - "\x54\x74\x8f\x3d\xe2\xd6\x85\x44", - .ptext = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa" - "\xad\xfd\x32\x94\x1f\x56\x57\xd1" - "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d" - "\xb2\x92\x83\x70\x1e\xa3\x97\xa6" - "\x65\x53\x39\xeb\x53\x8f\xb1\x38" - "\x91\xac\x17\x11\x1c\x03\x69\x53" - "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b" - "\xb6\x02\xc4\xfa\x95\x01\x33\xa8" - "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67" - "\xce\x8f\x9f\xea\x46\x66\x99\xb8", - .ctext = "\x38\xbc\xf5\x9d\x0e\x26\xa6\x18" - "\x95\x0b\x23\x54\x09\xa1\xf9\x46" - "\x7a\x31\xa0\xd7\x4a\xec\xb3\x10" - "\x8a\x8e\x99\x78\x6c\x6e\x76\xf2" - "\x63\x8a\x3b\x90\xaa\xd5\x64\x65" - "\x5a\x52\xb0\x36\x4c\xce\xed\xc7" - "\x51\x3c\x06\xb0\xee\x54\xec\x10" - "\xc0\x5f\xfd\xa9\x44\x9a\x29\x32" - "\x19\x79\x7d\x2b\x14\x26\x96\x13" - "\x9d\xa5\x61\xbd\xb6\x72\x37\x26", - .len = 80, - }, { - .key = "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf" - "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3", - .klen = 16, - .iv = "\x17\x94\x77\x2f\x92\xb8\x87\xc2" - "\xcc\x6f\x70\x26\x87\xc7\x10\x8a", - .ptext = "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41" - "\x4c\xf4\xd0\x34\xd0\x95\xab\xae" - "\x82\x5c\xfd\xfa\x13\x86\x25\xce" - "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50" - "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a" - "\xaf\x06\xea\xf4\x65\x59\xd6\xc2" - "\x84\xa0\x53\x97\x61\x30\x70\x15" - "\xac\x45\x8e\xe8\xeb\xa1\x72\x93" - "\x26\x76\x98\x6f\xe4\x86\xca\xf0" - "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95" - "\x86\x26\x20\x0e\x62\xfe\x8f\x1e" - "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda", - .ctext = "\xdf\x79\x58\x30\x6f\x47\x12\x78" - "\x04\xb2\x0b\x1a\x62\x22\xe2\x9f" - "\xfe\x90\x50\x41\x1b\x6a\x6a\x9c" - "\x4e\x77\x8f\xca\xd1\x68\x31\xcd" - "\x41\x82\xa5\x5b\xc0\x08\x2b\x37" - "\x62\xec\x95\xf1\x56\x12\x38\x66" - "\x84\x82\x72\xda\x00\x21\x96\x82" - "\x33\xd4\x99\xaa\xb9\xeb\xd5\xc3" - "\x2b\xa8\xf7\xdc\x13\x0e\x21\x9f" - "\x4b\xf9\x42\x58\xa8\x39\x10\xd5" - "\x86\xa5\xc6\x78\x3b\x34\x05\x03" - "\x54\x43\x2b\x80\xa9\x53\x4d\x0e", - .len = 96, - }, { - .key = "\x6e\x49\x20\xd5\xb7\x01\x83\x4e" - "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1", - .klen = 16, - .iv = "\xee\xb7\x0d\x65\x00\x38\xab\x71" - "\x70\x6e\xb3\x97\x86\xd3\xcd\xad", - .ptext = "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9" - "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e" - "\x25\x1b\xc2\xa6\x21\x25\xeb\x97" - "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94" - "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb" - "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2" - "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17" - "\x58\x2b\x1d\x73\x9a\x9c\x63\x18" - "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb" - "\xc9\x9d\x79\x51\x34\x39\x4f\x07" - "\xa2\x7c\x21\x04\x91\x3b\x79\x79" - "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0" - "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2" - "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95", - .ctext = "\xe4\x25\x0d\x22\xeb\xbe\x5e\x90" - "\x01\xe5\xae\xc9\x94\xbd\x93\x89" - "\x5e\x5a\x5a\x2f\xf6\xdf\xf8\x16" - "\xd3\xb2\xed\x29\x51\xe2\x75\xb0" - "\x1a\x48\xb5\xe6\xd3\x58\x40\xc7" - "\x6f\x6f\xcf\x57\x82\x43\x5a\x36" - "\xef\x27\xe1\x34\x85\x01\xec\x98" - "\x00\xbd\x94\x6f\x12\x39\xa8\x13" - "\xfe\x3c\x39\xc0\xc6\xe1\xcc\x05" - "\x0e\xd5\xc9\xda\xbd\xdd\xdb\xaa" - "\x5a\xaa\x8e\xe8\xa8\x0a\xc5\x18" - "\xb4\x1d\x13\x81\xc9\xc4\xaa\x61" - "\xa9\xbd\xaa\x03\x12\x93\xbb\xed" - "\x0c\x6e\xbd\x1c\x05\x16\x8a\x59", - .len = 112, - }, { - .key = "\xb6\x08\x1d\x31\xaf\xf4\x17\x46" - "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15", - .klen = 16, - .iv = "\x0c\x85\x2f\x62\xe5\xf4\x35\x96" - "\xb1\x9b\x5d\x00\x10\xe9\x70\x12", - .ptext = "\x3a\x87\x7f\x67\xf1\x81\x7a\x05" - "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e" - "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41" - "\x9c\x14\x44\x5a\xd5\x1c\x50\x08" - "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e" - "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3" - "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b" - "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe" - "\x2f\x7e\x1c\x10\x81\x36\x2d\x79" - "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c" - "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda" - "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d" - "\x70\x86\xa5\x92\x9f\xee\xcd\x3f" - "\x6a\x55\x84\x98\x28\x03\x02\xc2" - "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8" - "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c", - .ctext = "\xa7\x4c\x96\x55\x7c\x07\xce\xb2" - "\x6f\x63\x9f\xc6\x8b\x6f\xc6\x4a" - "\x85\xf2\x4b\xdf\x62\x0c\x6c\x8d" - "\x13\x5d\xd3\x40\x58\xa6\xf9\x03" - "\xd9\xf2\x48\x4e\x12\x64\x9a\x55" - "\xa2\xa3\xd0\x19\xe5\x5b\xaa\x62" - "\x7b\xe9\x2a\x23\xab\xb5\xa6\xcf" - "\x53\x59\x70\xc6\xb8\x92\x12\x3b" - "\x93\x68\x24\xba\x7d\xd6\xc0\x5b" - "\x06\x2e\x7f\x2e\x32\x5d\x42\x9c" - "\x13\x8e\x92\x3c\x99\x20\x32\x2b" - "\x4a\x41\xb2\x4a\x81\xe8\x6e\x7f" - "\x5b\x8e\xca\x4d\xd7\x29\x96\xde" - "\x30\x9c\xa6\x84\x90\xe7\xc2\xae" - "\xf4\x7e\x73\x32\x4c\x25\xec\xef" - "\x58\x69\x63\x3f\x4e\x71\x4b\x1c", - .len = 128, - }, { - .key = "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17" - "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c", - .klen = 16, - .iv = "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad" - "\x8c\xaf\x36\x3d\xff\x29\x8b\x33", - .ptext = "\x87\x96\x77\x1a\x10\x81\x63\x8a" - "\x63\xde\x88\xa9\x9d\xa9\x01\xf2" - "\xdf\xc9\x25\x35\x48\x3a\x15\xdf" - "\x20\x6b\x91\x7c\x56\xe5\x10\x7a" - "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f" - "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd" - "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8" - "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a" - "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e" - "\xc0\x3b\x12\x28\xca\x26\x7b\xb3" - "\x14\xc1\x7f\x66\xff\x3b\xa4\x80" - "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a" - "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf" - "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff" - "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd" - "\xcd\x56\x02\x95\xc9\x54\x6e\x62" - "\x6a\x97\x75\x1a\x21\x16\x46\xfb" - "\xc2\xab\x62\x54\xef\xba\xae\x46", - .ctext = "\x11\x7f\xea\x49\xaf\x24\x52\xa2" - "\xde\x60\x99\x58\x23\xf9\x9e\x91" - "\x94\x52\x31\xa3\x28\x07\x14\xad" - "\x00\x24\x4a\x4a\xe7\x18\xd7\x24" - "\xcc\x8b\x66\x53\x82\x65\x31\xa5" - "\x54\x76\x59\x0b\x69\x6f\x90\x2c" - "\x8d\xa5\x2b\x61\x05\x80\xfb\xe0" - "\xf9\x6e\xaf\xb9\xc4\x15\x67\xcc" - "\x15\xce\xa0\xc0\xf2\xae\xa6\x15" - "\x24\x9a\xe5\xcb\x09\x42\xcf\x41" - "\x95\xa4\x8d\xbf\xe8\xb8\x40\xcd" - "\xb0\x33\x2c\xb3\xc4\xdd\xf9\x45" - "\xda\xb2\xeb\xb3\xf8\xfa\x7f\xe3" - "\xc0\x3a\x98\xe7\x17\x4a\x0c\x60" - "\xb2\x22\xba\x3b\x21\x85\x27\x56" - "\xe0\xb2\xf7\x2a\x59\xb1\x56\x20" - "\x0b\xa9\x13\x73\xe0\x6f\x61\x32" - "\xa5\x38\x14\xb3\xe3\xaa\x70\x44", - .len = 144, - }, { - .key = "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9" - "\x05\x26\x23\x81\x19\x27\xad\x7b", - .klen = 16, - .iv = "\x9c\x8b\xfb\x65\xa4\x61\xee\x69" - "\x44\xbf\x59\xde\x03\x61\x11\x12", - .ptext = "\x8d\x94\x48\x47\xa9\x52\x16\xfb" - "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c" - "\xb6\x09\x21\x12\x42\x98\x13\xa1" - "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea" - "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c" - "\x66\xb8\x4d\x60\x67\x82\xcc\x8d" - "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c" - "\x54\x84\x2a\x06\xb5\xd1\x34\x57" - "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33" - "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97" - "\x3e\xc6\xec\xaf\x74\xe8\x72\x91" - "\xb2\xc6\x56\xb3\x23\x29\x43\xe0" - "\xfb\xcc\x21\x38\x64\x78\x9e\x78" - "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01" - "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58" - "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d" - "\x90\xb7\x60\x78\xa8\x9f\x52\xe3" - "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53" - "\x42\x0e\x15\x31\xf6\x48\xa3\x0a" - "\x20\xf0\x79\x67\xb1\x83\x26\x66", - .ctext = "\x5b\xc0\xe8\x17\xa4\xf9\xea\xce" - "\x9e\xf9\xe0\xb1\xac\x37\xe9\x41" - "\xc8\x06\xf9\x1c\x1a\xfc\xe8\x7a" - "\x38\xf2\x80\x66\xc2\x70\x59\x4e" - "\xe0\x32\x5b\x27\x39\xf5\xfb\x03" - "\xc8\xaf\xd6\x7e\x57\xc7\xc6\x71" - "\xd9\xd0\x48\x39\xb1\x0d\xa8\x1a" - "\x23\x8a\x3d\x05\xe2\x90\x7e\x18" - "\xd7\x20\x04\x3b\x82\x76\x3f\xaa" - "\xc2\x89\xb6\x9e\x14\x2f\x46\xcd" - "\x51\x9b\xa8\x7b\x62\x7b\x9c\x17" - "\xc4\xe1\x8b\x3f\xb5\x4d\xac\x66" - "\x49\xf6\xb6\x4c\x3e\x16\x46\xb0" - "\xca\x04\xef\x72\x5c\x03\x0a\xe5" - "\x2f\x4e\x36\x38\x36\x9f\xf4\xe2" - "\x81\x7a\x4c\xdf\x36\x27\xd5\x9d" - "\x03\xad\x1d\x3a\xe9\x2a\x99\xb0" - "\x2c\xba\x13\x75\xc8\x37\x97\x11" - "\xf4\x15\x0f\xb7\x75\x26\xa1\x14" - "\x79\xec\x1f\xab\xd2\x10\x8c\x5f", - .len = 160, - }, { - .key = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23" - "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1" - "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0", - .klen = 24, - .iv = "\xfd\xab\x56\xa6\x6e\xda\x7c\x57" - "\x36\x36\x89\x09\xcd\xa8\xd3\x91", - .ptext = "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0" - "\x51\xe3\x8c\xe9\x76\xcd\xff\x37", - .ctext = "\xa4\x12\x2f\xc4\xf0\x6d\xd9\x46" - "\xe4\xe6\xd1\x0b\x6d\x14\xf0\x8f", - .len = 16, - }, { - .key = "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe" - "\x3d\x2d\x85\x75\x6e\x18\x8a\x52" - "\x53\x39\xfc\xc1\xf5\xc0\x56\x22", - .klen = 24, - .iv = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93" - "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e", - .ptext = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed" - "\x0e\x60\x75\x84\x21\xdf\x13\xa1" - "\x26\xf8\x8c\x26\x0a\x37\x51\x8f" - "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d", - .ctext = "\x80\x2b\xf0\x88\xb9\x4b\x8d\xf5" - "\xc3\x0e\x15\x5b\xea\x5d\x5b\xa8" - "\x52\xe7\x83\x3c\xa1\x51\x1c\x1f" - "\x38\xd9\x7c\x88\x3c\x3a\xcd\x3e", - .len = 32, - }, { - .key = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea" - "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4" - "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0", - .klen = 24, - .iv = "\xef\x3e\x5f\x46\x62\x88\xd5\x26" - "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2", - .ptext = "\x39\x56\x34\x63\x2c\xc5\x51\x13" - "\x48\x29\x3a\x58\xbe\x41\xc5\x80" - "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e" - "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b" - "\x77\xb5\xca\x90\xda\x1d\x22\x17" - "\xd9\xa0\x57\x80\xc8\x96\x70\x86", - .ctext = "\x65\x01\x3c\xb0\xac\x4c\x63\xb6" - "\xe7\xf1\xf4\x61\x35\xf4\x36\xde" - "\xeb\x0f\x8c\x34\xd1\x78\xb4\x00" - "\xb2\xc1\x7c\x28\xb2\xb7\xbb\xa3" - "\xc6\xb7\x27\xf7\x6d\x56\x79\xfa" - "\x61\x57\xba\x30\x6f\x56\xe9\x8c", - .len = 48, - }, { - .key = "\x07\x2c\xf4\x61\x79\x09\x01\x8f" - "\x37\x32\x98\xd4\x86\x2b\x3b\x80" - "\x07\x60\xba\xf0\x2e\xc3\x4a\x57", - .klen = 24, - .iv = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a" - "\xe6\x08\xf0\xbe\x77\xd1\x62\x40", - .ptext = "\xa0\x82\x09\x60\x47\xbb\x16\x56" - "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c" - "\x05\x32\x63\x1a\xc4\x46\x6f\x55" - "\x32\xde\x41\x5a\xf7\x52\xd7\xfa" - "\x30\x9d\x59\x8d\x64\x76\xad\x37" - "\xba\xbc\x46\x6a\x69\x17\x3c\xac" - "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e" - "\x54\x74\x8f\x3d\xe2\xd6\x85\x44", - .ctext = "\x5a\xfb\xb1\x2c\x6e\xe5\xb8\xe0" - "\x80\xb6\x77\xa8\xfe\x10\x3a\x99" - "\xbf\xc0\x2a\xfe\x6f\x38\xf2\x1d" - "\x53\x6c\x05\x83\xb1\x13\x00\x87" - "\x92\x92\x42\x70\xcf\x9f\xf7\x8f" - "\x53\x55\x18\x6f\x35\x68\x35\x50" - "\x3a\xc8\x45\x3e\xa3\xf1\x33\x2e" - "\xa1\x65\x42\xe2\x6d\x31\x8c\x4b", - .len = 64, - }, { - .key = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa" - "\xad\xfd\x32\x94\x1f\x56\x57\xd1" - "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d", - .klen = 24, - .iv = "\xb2\x92\x83\x70\x1e\xa3\x97\xa6" - "\x65\x53\x39\xeb\x53\x8f\xb1\x38", - .ptext = "\x91\xac\x17\x11\x1c\x03\x69\x53" - "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b" - "\xb6\x02\xc4\xfa\x95\x01\x33\xa8" - "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67" - "\xce\x8f\x9f\xea\x46\x66\x99\xb8" - "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf" - "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3" - "\x17\x94\x77\x2f\x92\xb8\x87\xc2" - "\xcc\x6f\x70\x26\x87\xc7\x10\x8a" - "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41", - .ctext = "\xc9\x5f\xe0\x60\x61\x38\x7e\x79" - "\x52\x68\x64\x8f\x55\x9b\x6b\x72" - "\xa5\x17\x61\xb7\xce\x02\xa9\xa4" - "\x5c\x73\x45\x33\xd1\x07\x5e\xdc" - "\xe5\xbe\xa7\xde\x69\xa0\x97\x98" - "\x02\xef\xa4\x67\x51\x60\x69\x4f" - "\x03\xf5\xa8\x5f\x03\x69\xbc\xc2" - "\x34\x59\x7e\xd4\xd2\xb3\x32\x2f" - "\x0c\xb4\x37\xca\xc4\xc7\x93\xf4" - "\xa4\xab\x01\x3f\x91\x29\x55\x98", - .len = 80, - }, { - .key = "\x4c\xf4\xd0\x34\xd0\x95\xab\xae" - "\x82\x5c\xfd\xfa\x13\x86\x25\xce" - "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50", - .klen = 24, - .iv = "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a" - "\xaf\x06\xea\xf4\x65\x59\xd6\xc2", - .ptext = "\x84\xa0\x53\x97\x61\x30\x70\x15" - "\xac\x45\x8e\xe8\xeb\xa1\x72\x93" - "\x26\x76\x98\x6f\xe4\x86\xca\xf0" - "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95" - "\x86\x26\x20\x0e\x62\xfe\x8f\x1e" - "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda" - "\x6e\x49\x20\xd5\xb7\x01\x83\x4e" - "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1" - "\xee\xb7\x0d\x65\x00\x38\xab\x71" - "\x70\x6e\xb3\x97\x86\xd3\xcd\xad" - "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9" - "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e", - .ctext = "\x03\x2c\x39\x24\x99\xb5\xf6\x79" - "\x91\x89\xb7\xf8\x89\x68\x37\x9d" - "\xa2\x80\x95\x74\x87\x64\xb9\xeb" - "\x85\x28\x92\x9a\x6e\xd3\x3b\x50" - "\x4c\x80\x5b\xe4\xf2\x7e\xda\x2a" - "\xd4\xf8\xcb\xe3\x6f\xdf\xae\x0e" - "\xc5\x6c\x0b\x49\x2e\x29\x1c\xf2" - "\x3f\x44\x44\x12\x67\xa6\xff\x44" - "\xe0\xec\xd8\xf7\x32\xde\x21\x15" - "\xab\x8f\x98\x4d\xed\xb0\x42\xfd" - "\x83\x94\xe2\xcc\x69\x6d\xe8\xdb" - "\x62\x93\x1f\xd0\xf4\x8c\x62\xc0", - .len = 96, - }, { - .key = "\x25\x1b\xc2\xa6\x21\x25\xeb\x97" - "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94" - "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb", - .klen = 24, - .iv = "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2" - "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17", - .ptext = "\x58\x2b\x1d\x73\x9a\x9c\x63\x18" - "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb" - "\xc9\x9d\x79\x51\x34\x39\x4f\x07" - "\xa2\x7c\x21\x04\x91\x3b\x79\x79" - "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0" - "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2" - "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95" - "\xb6\x08\x1d\x31\xaf\xf4\x17\x46" - "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15" - "\x0c\x85\x2f\x62\xe5\xf4\x35\x96" - "\xb1\x9b\x5d\x00\x10\xe9\x70\x12" - "\x3a\x87\x7f\x67\xf1\x81\x7a\x05" - "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e" - "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41", - .ctext = "\xd4\x9a\x04\x54\x05\xd2\xe6\x3f" - "\xb0\xa4\x36\x5e\x1e\x9c\x35\xb0" - "\xc0\x89\xbd\x1c\xaa\x45\xa6\xc8" - "\x16\x68\x4a\x06\x93\x67\x88\xd7" - "\x72\x6e\x48\x0a\x17\xa3\x52\x8b" - "\x96\x5f\x41\xf6\x17\x64\x55\x8b" - "\xac\xce\xf6\x8c\xce\xd2\xd4\xd4" - "\x8d\x92\x32\xe0\x0d\xb4\xf7\x4a" - "\x90\xaf\x7b\x85\x21\x46\x2e\xa6" - "\x9e\xac\x0d\x22\xf2\x26\xf6\xd3" - "\x27\xcd\x59\xa0\xe2\xbb\x22\xcd" - "\x35\xb6\x28\x45\x0a\x46\xb0\x3a" - "\xac\x3e\xd3\x5b\xc6\x54\xa2\xa3" - "\x6d\xbb\xb3\xcd\xc5\x64\x62\x92", - .len = 112, - }, { - .key = "\x9c\x14\x44\x5a\xd5\x1c\x50\x08" - "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e" - "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3", - .klen = 24, - .iv = "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b" - "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe", - .ptext = "\x2f\x7e\x1c\x10\x81\x36\x2d\x79" - "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c" - "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda" - "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d" - "\x70\x86\xa5\x92\x9f\xee\xcd\x3f" - "\x6a\x55\x84\x98\x28\x03\x02\xc2" - "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8" - "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c" - "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17" - "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c" - "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad" - "\x8c\xaf\x36\x3d\xff\x29\x8b\x33" - "\x87\x96\x77\x1a\x10\x81\x63\x8a" - "\x63\xde\x88\xa9\x9d\xa9\x01\xf2" - "\xdf\xc9\x25\x35\x48\x3a\x15\xdf" - "\x20\x6b\x91\x7c\x56\xe5\x10\x7a", - .ctext = "\xbc\x57\x2a\x88\x0a\xd0\x06\x4f" - "\xdb\x7b\x03\x9f\x97\x1a\x20\xfe" - "\x15\x91\xb4\xed\x5d\x78\x89\x2a" - "\x67\x6b\x9c\x47\x36\xc2\x80\x0e" - "\x03\x8d\x6f\xfc\x94\xc7\xc5\xc2" - "\xeb\x43\x74\x5d\xfe\xc4\x5a\xa1" - "\x80\x51\x8a\x63\xd1\x27\x1b\x0a" - "\x88\x2c\xc4\x7f\x1a\xa3\x28\xe5" - "\xfd\xd0\x8a\xd4\x36\xa6\x19\xd5" - "\xff\x41\x7a\x8b\x6e\x9a\x97\x14" - "\x2a\xc8\xd0\xb8\xa3\x8e\x64\x32" - "\xb7\x2d\x76\x9b\x3b\xe2\x3f\x91" - "\xb4\x64\xbf\x59\x67\x14\xc3\xf5" - "\xa8\x92\x4b\x85\xdf\x80\xcb\xb5" - "\xc7\x80\xf9\x4a\xbc\xed\x67\x5a" - "\x0b\x58\x65\x1f\xc9\x6e\x9b\x0a", - .len = 128, - }, { - .key = "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f" - "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd" - "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8", - .klen = 24, - .iv = "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a" - "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e", - .ptext = "\xc0\x3b\x12\x28\xca\x26\x7b\xb3" - "\x14\xc1\x7f\x66\xff\x3b\xa4\x80" - "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a" - "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf" - "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff" - "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd" - "\xcd\x56\x02\x95\xc9\x54\x6e\x62" - "\x6a\x97\x75\x1a\x21\x16\x46\xfb" - "\xc2\xab\x62\x54\xef\xba\xae\x46" - "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9" - "\x05\x26\x23\x81\x19\x27\xad\x7b" - "\x9c\x8b\xfb\x65\xa4\x61\xee\x69" - "\x44\xbf\x59\xde\x03\x61\x11\x12" - "\x8d\x94\x48\x47\xa9\x52\x16\xfb" - "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c" - "\xb6\x09\x21\x12\x42\x98\x13\xa1" - "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea" - "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c", - .ctext = "\xd7\xb4\xfc\xcc\x1f\xf7\xfc\x7d" - "\x69\xfa\xcb\x01\x60\xf3\x5a\x14" - "\xfe\x8c\x4e\xfa\x09\xb5\x0d\xda" - "\xff\xdd\xba\xdf\xa3\x6b\x3a\x87" - "\x21\xbb\xf8\x62\x14\x22\xdd\x9b" - "\x92\x23\xaa\xd7\xcc\xb2\x15\xd0" - "\xbd\x81\x95\x24\xc2\xc6\x53\x5b" - "\xf7\x3c\xa0\xf7\x36\xbc\xbf\xf3" - "\xfc\x1c\x6e\xe0\x71\x8d\xa1\x3d" - "\x8e\x1a\xc5\xba\xd5\x68\xd4\x7a" - "\xe0\x4f\x0a\x14\x89\x0b\xa6\x2f" - "\x18\xc5\x38\x76\xf1\xe7\x5c\xae" - "\x7a\xbb\x27\x1c\xf0\x7c\x6c\x14" - "\x07\xb7\x49\x6e\x29\x04\x38\x31" - "\x91\xe8\x1d\x0f\xfc\x3b\xb8\x20" - "\x58\x64\x11\xa1\xf5\xba\xa3\x62" - "\x92\xcf\x44\x63\x2c\xe8\x10\xb5" - "\xf0\x97\x86\xcb\x5f\xc1\x80\x7a", - .len = 144, - }, { - .key = "\x66\xb8\x4d\x60\x67\x82\xcc\x8d" - "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c" - "\x54\x84\x2a\x06\xb5\xd1\x34\x57", - .klen = 24, - .iv = "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33" - "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97", - .ptext = "\x3e\xc6\xec\xaf\x74\xe8\x72\x91" - "\xb2\xc6\x56\xb3\x23\x29\x43\xe0" - "\xfb\xcc\x21\x38\x64\x78\x9e\x78" - "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01" - "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58" - "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d" - "\x90\xb7\x60\x78\xa8\x9f\x52\xe3" - "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53" - "\x42\x0e\x15\x31\xf6\x48\xa3\x0a" - "\x20\xf0\x79\x67\xb1\x83\x26\x66" - "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd" - "\x45\x87\xa4\x14\x1b\xef\xe7\x16" - "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e" - "\x01\x68\xc1\x7d\xa2\x15\x49\x74" - "\x53\x82\xc2\x10\xa8\x45\x73\x4d" - "\x41\xcc\x24\xa3\x42\xff\x30\xd1" - "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c" - "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe" - "\x52\xf1\x34\x78\x34\x53\x30\x5b" - "\x43\x43\x51\x6a\x02\x81\x64\x0c", - .ctext = "\x71\xf6\x96\x02\x07\x71\x1a\x08" - "\x7c\xfe\x33\xc4\xc9\xbe\xe2\xed" - "\xd0\xcc\x5d\x27\x75\xb4\x5d\x8d" - "\x24\x03\xe4\x96\x31\x94\x0e\x38" - "\x14\x4f\xad\x16\x58\x0d\x73\xdc" - "\xbe\x5b\xcb\x38\xeb\x4d\xbc\x9a" - "\x44\x69\x7a\x12\x91\x14\x52\xfa" - "\xd2\xa2\xc5\x66\xd7\xaf\x4d\xb9" - "\xb1\x58\x24\x10\xde\x6a\xee\x7e" - "\x45\xf3\x76\xea\x47\x8a\xe6\x96" - "\x41\xf2\x96\x2d\x3c\xec\xcf\xc6" - "\x1d\xf4\x26\xc0\xea\x90\x27\x6e" - "\x87\xef\xb5\x39\x38\xdb\xad\xbf" - "\x57\x9a\x1d\xbc\x1d\xe5\x16\x91" - "\x41\x45\xbe\x67\x6c\x42\x0f\xad" - "\xcf\xfb\xcd\xf1\x4c\xd8\x73\xe7" - "\x24\x3b\xd7\x03\xeb\xd1\xb1\x1b" - "\x7d\xc9\x3d\x34\xd7\xb8\x69\x03" - "\x76\x95\x32\x26\xed\x88\x76\x89" - "\x13\xc6\xc8\xa6\x60\xf9\x73\x4d", - .len = 160, - }, { - .key = "\x82\x8e\x9e\x06\x7b\xc2\xe9\xb3" - "\x06\xa3\xfa\x99\x42\x67\x87\xac" - "\x21\xc7\xb0\x98\x6c\xf8\x26\x57" - "\x08\xdd\x92\x02\x77\x7b\x35\xe7", - .klen = 32, - .iv = "\xa1\xad\xcb\xdd\xd5\x19\xb6\xd4" - "\x0b\x62\x58\xb0\x6c\xa0\xc1\x58", - .ptext = "\x14\x0d\x8a\x09\x16\x00\x00\xf1" - "\xc0\x20\x86\xf9\x21\xd1\x34\xe2", - .ctext = "\x05\xe3\x34\xaf\x6c\x83\x14\x8b" - "\x9d\x1c\xd6\x87\x74\x91\xdf\x17", - .len = 16, - }, { - .key = "\xc9\xf3\xc4\x93\xd0\xcc\xaf\xb1" - "\x1a\x42\x93\x71\xd8\x4e\xd8\xaa" - "\x52\xad\x93\x2f\xe5\xd9\xaa\x5b" - "\x47\x37\x3a\xed\x13\x92\x35\x16", - .klen = 32, - .iv = "\x81\xc8\x50\xd1\x74\xc3\x1c\x73" - "\xbb\xab\x72\x83\x90\x5a\x15\xcb", - .ptext = "\x65\x11\x93\xaf\xe1\x69\x6c\xbe" - "\x25\x8c\x76\x87\x53\xa4\x80\xae" - "\x51\x94\x36\x3f\xca\xe7\x45\x41" - "\x76\x05\xbf\x8f\x9c\xad\xc0\xe3", - .ctext = "\x6B\x00\x6E\x49\x7A\x6D\xE3\x04" - "\x4E\xF7\x9F\x8A\x1F\x14\xBD\xB1" - "\xD3\x5D\xA4\x30\x26\x85\x85\xEF" - "\x12\xBC\xC7\xA1\x65\x82\xA7\x74", - .len = 32, - }, { - .key = "\xd5\x9f\x52\x34\x12\x99\x8e\x42" - "\xe0\x85\x04\x6f\xeb\xf1\x5d\xd0" - "\xc1\xbf\x3f\x84\xd9\x1e\x71\x44" - "\xd4\xb9\x40\x3c\x02\x2e\x21\x19", - .klen = 32, - .iv = "\x28\xc1\x97\x64\x81\x52\x57\x0e" - "\x02\x8c\xab\x4c\xe2\x60\x14\xa5", - .ptext = "\x5a\xb1\x33\x48\xaa\x51\xe9\xa4" - "\x5c\x2d\xbe\x33\xcc\xc4\x7f\x96" - "\xe8\xde\x2b\xe7\x35\x7a\x11\x4b" - "\x13\x08\x32\xc6\x41\xd8\xec\x54" - "\xa3\xd3\xda\x35\x43\x69\xf6\x88" - "\x97\xca\x00\x1b\x02\x59\x24\x82", - .ctext = "\x03\xaf\x76\xbd\x5e\x5b\xca\xc0" - "\xae\x44\xa2\x2f\xc2\x76\x2f\x50" - "\x6a\x73\x28\xf2\xba\xe8\xb2\xb8" - "\x43\x61\x41\x92\xff\xac\xcb\xa6" - "\x84\x31\xe3\x34\xd0\x37\x81\xab" - "\x2b\x0e\x97\x3c\x4a\x2d\xa4\x83", - .len = 48, - }, { - .key = "\x9c\x5d\xd7\x66\x36\xfa\x02\x20" - "\x99\x61\x62\x86\x0f\x43\x2e\x05" - "\x25\x8b\xfb\xf1\xae\x4c\xde\x18" - "\x0b\xf8\xd0\x9d\xaa\xd4\x56\x04", - .klen = 32, - .iv = "\xcd\xa8\x61\x89\x8d\xbb\x72\xb6" - "\x1e\xfe\x03\x34\x54\x88\x23\xe2", - .ptext = "\x66\x42\x60\x24\xf3\xe4\xe9\x7e" - "\x42\x20\xf4\x61\xce\x1c\x5e\x44" - "\x02\x26\x91\xf7\x41\xa4\xab\x34" - "\x29\x49\xdd\x78\x19\x8f\x10\x10" - "\xf0\x61\xcf\x77\x18\x17\x61\xdf" - "\xc4\xa8\x35\x0e\x75\x1b\x84\x6b" - "\xc3\x3f\x31\x59\x5a\x9c\xf4\xc3" - "\x43\xa9\xb7\xf8\x65\x40\x40\xba", - .ctext = "\xb6\x41\x55\x8f\xeb\x16\x1e\x4c" - "\x81\xa0\x85\x6c\xf0\x07\xa5\x2a" - "\x12\x0f\x1d\xb2\xaa\xba\x85\x0f" - "\xa6\x27\x1a\x91\xa6\xc5\x8c\x2a" - "\xde\x8d\x3a\xa9\x8b\xcf\x24\xf1" - "\x82\x51\x6b\xc8\x01\xd7\x7b\x89" - "\x6c\xfc\xb1\x96\x6c\xa2\xd7\x1f" - "\x4b\x7a\xd9\x8d\x34\xaa\xa0\x8a", - .len = 64, - }, { - .key = "\x4b\x4e\x11\x91\x27\xcf\x8c\x66" - "\x17\xfa\x5b\x4c\xa8\xb8\x0f\xa1" - "\x99\x5b\x07\x56\xe1\x8d\x94\x8b" - "\xf2\x86\x5a\x5f\x40\x83\xfa\x06", - .klen = 32, - .iv = "\xfd\x73\xee\x1c\x27\xf3\xb4\x38" - "\xc5\x7c\x2e\xc5\x6e\xdb\x49\x0d", - .ptext = "\x0a\xe2\xdd\x97\xdd\x5e\xd4\xb3" - "\xc1\x49\x8f\x53\xb2\x40\x85\x1c" - "\x90\x37\x2d\xbd\x21\x6b\x1f\x80" - "\x56\x98\x76\x1e\xcf\x6c\x78\xd8" - "\xa0\x3c\x79\xc3\x56\xf7\xfc\x64" - "\x35\x58\x1c\x7c\xc4\x5f\x2a\x25" - "\x8c\x01\x98\x1e\x1c\x1f\x15\x64" - "\x50\xb5\xfa\x02\xd3\x54\xe5\x29" - "\xe3\xd2\xa3\x83\x54\x40\x54\xc5" - "\xd8\x1c\xc9\x84\x7d\xc8\x31\x49", - .ctext = "\x53\x2a\xa8\xa0\x15\xaf\x2f\xc4" - "\x7d\x31\xb4\x61\x80\x5f\xd1\xb6" - "\xa4\x29\x40\x72\x1b\xb2\x96\xb7" - "\x4d\x5e\x5b\x53\x44\xa4\xf1\xe9" - "\xf0\x27\x2f\x26\x84\x66\x13\xa4" - "\xb2\x19\x55\xb1\x18\xf3\x69\xfd" - "\xb0\x2f\x08\x3f\xa5\x41\xe2\x34" - "\x5e\x63\x57\x0e\xef\x17\x78\xbc" - "\xc3\x65\x7c\xbe\x6b\xa3\xa3\xef" - "\x58\x05\x30\x5a\x08\xbd\xf7\x0e", - .len = 80, - }, { - .key = "\x77\x3b\xf5\xe7\x20\xf7\xe0\x0c" - "\x3d\x3a\x83\x17\x83\x79\xd8\x29" - "\x5a\x0a\x25\x7f\xe0\x21\x23\xff" - "\x31\xfd\x60\x10\xe6\x63\xe2\xaf", - .klen = 32, - .iv = "\xdb\x4c\x0d\xc0\x36\xdb\xc7\xa1" - "\xa4\x91\xd9\x05\xe6\xc4\x98\x00", - .ptext = "\x8d\x4d\xc6\x5e\x01\x82\xb3\x39" - "\xc8\x64\xa7\xcb\x05\x19\x84\x80" - "\x3f\x9c\xa8\x4f\x64\xb3\x11\x4b" - "\x0e\x21\xc4\x75\x04\x1d\x6f\xd5" - "\x04\x04\x4d\xc9\xc0\x4b\x4a\x9c" - "\x26\xb7\x68\x5a\xe4\xd0\x61\xe3" - "\x2c\x93\x8e\x3f\xb4\x67\x07\x31" - "\x02\x52\x0c\x0f\xe6\x6d\xa3\xd0" - "\x48\x95\x83\x67\x23\x64\x31\x50" - "\xd2\x5f\x69\x68\x8b\x71\xbf\x01" - "\x29\x99\x86\x36\x2e\xdf\xf1\x7c" - "\x08\x8c\x78\x7a\x93\x9a\x7d\x1b", - .ctext = "\x92\x90\x48\x2f\x3a\x6b\x68\x43" - "\x28\x9b\x7d\x1e\x46\x28\xd8\x58" - "\x0f\x47\x8b\xb5\x83\x35\x35\x3e" - "\xdf\x59\x3d\xb3\x47\xfc\xfc\x52" - "\x86\xeb\xb3\x58\x54\xd5\x0a\xb4" - "\xad\xbd\x5c\x09\xfc\x08\xc2\x01" - "\x5e\x9b\x30\x11\xc4\x40\x2e\x32" - "\x9c\xa0\xf1\xfd\xae\xd4\x75\x5e" - "\x52\xd9\x19\x4d\xc1\xd4\xb6\x19" - "\x88\xfb\x29\x17\x15\xbb\x60\xd6" - "\x5a\xe9\x82\x89\xaf\x30\x4e\xd4" - "\x47\xde\x86\x88\x95\x4c\x13\x59", - .len = 96, - }, { - .key = "\xe0\x6a\x30\xe1\x35\xb5\xb0\x7c" - "\x54\xc5\x73\x9b\x00\xe5\xe7\x02" - "\xbe\x16\x59\xdc\xd9\x03\x17\x53" - "\xa8\x37\xd1\x5f\x13\x8e\x45\xdb", - .klen = 32, - .iv = "\x54\xe9\x1c\xde\xfb\x26\x0e\x48" - "\x35\x50\x4d\x9b\x4d\x12\x21\x0d", - .ptext = "\x73\x72\xcf\xdb\xbd\xbc\xc0\xdf" - "\x6b\xbb\xdf\x65\x6f\x2f\x43\x3b" - "\x2d\x7c\x0e\x07\x7f\xa0\x95\xdd" - "\xfc\x67\xc1\x11\x7a\xe2\xb5\x4a" - "\xd1\x15\xb0\xd8\xe2\xf0\x35\x48" - "\xd8\x81\x6a\x35\xae\x67\xbf\x61" - "\xf2\x8a\xcf\x04\xc8\x09\x8b\x63" - "\x31\x74\x95\xa5\x8d\x3c\xea\xe2" - "\x5f\x67\xc4\x7e\x51\x88\xbf\xb5" - "\x78\xef\x3a\x76\xd8\x1d\x00\x75" - "\x2b\x7b\x28\x7c\xde\x4b\x39\x01" - "\x5d\xde\x92\xfe\x90\x07\x09\xfd" - "\xa5\xd1\xd3\x72\x11\x6d\xa4\x4e" - "\xd1\x6e\x16\xd1\xf6\x39\x4f\xa0", - .ctext = "\x3b\xc5\xee\xfc\x05\xaf\xa6\xb7" - "\xfe\x12\x24\x79\x31\xad\x32\xb5" - "\x64\x5a\x17\xc9\xbf\x1f\xdc\xce" - "\x8d\x73\x00\x71\xd9\xfb\xd2\xe6" - "\xc3\x54\xb4\xf3\x36\xe8\x89\x12" - "\x5a\x32\x0b\xa6\xec\x5f\x89\xe7" - "\xe8\x34\x92\xa6\xce\xde\x8f\xf9" - "\x4f\xda\xed\x61\x8e\xb2\x81\xbe" - "\xf2\x15\x85\xbe\xa1\x5f\x19\x85" - "\x71\x7e\xda\x46\x59\xed\x5d\xb0" - "\xd9\x68\x97\xe0\xcd\x1d\x1b\x65" - "\xf5\xc9\x44\xe2\xb4\x42\x17\x7c" - "\xe7\x58\xf3\x2f\xcf\xbe\x5c\x66" - "\xaa\xd3\x61\xa5\x9a\x79\xbb\xa0", - .len = 112, - }, { - .key = "\x60\xb6\xde\x17\xca\x4c\xe7\xe0" - "\x07\x0d\x80\xc5\x8a\x2d\x5a\xc2" - "\x2c\xb9\xa4\x5f\x2a\x85\x2c\x3d" - "\x6d\x67\xc8\xee\x0f\xa2\xf4\x09", - .klen = 32, - .iv = "\x1a\xa5\xbc\x7e\x93\xf6\xdd\x28" - "\xb7\x69\x27\xa1\x84\x95\x25\x5a", - .ptext = "\x7b\x88\x00\xeb\xa5\xba\xa1\xa7" - "\xd4\x40\x16\x74\x2b\x42\x37\xda" - "\xe0\xaf\x89\x59\x41\x2f\x62\x00" - "\xf5\x5a\x4e\x3b\x85\x27\xb2\xed" - "\x1b\xa7\xaf\xbe\x89\xf3\x49\xb7" - "\x8c\x63\xc9\x0c\x52\x00\x5f\x38" - "\x3b\x3c\x0c\x4f\xdd\xe1\xbf\x90" - "\x4a\x48\xbf\x3a\x95\xcb\x48\xa2" - "\x92\x7c\x79\x81\xde\x18\x6e\x92" - "\x1f\x36\xa9\x5d\x8d\xc4\xb6\x4d" - "\xb2\xb4\x0e\x09\x6d\xf3\x3d\x01" - "\x3d\x9b\x40\x47\xbc\x69\x31\xa1" - "\x6a\x71\x26\xdc\xac\x10\x56\x63" - "\x15\x23\x7d\x10\xe3\x76\x82\x41" - "\xcd\x80\x57\x2f\xfc\x4d\x22\x7b" - "\x57\xbb\x9a\x0a\x03\xe9\xb3\x13", - .ctext = "\x37\x0d\x47\x21\xbc\x28\x0b\xf7" - "\x85\x5f\x60\x57\xf2\x7f\x92\x20" - "\x53\x1a\xbf\xd1\x7f\x8c\x39\x29" - "\x0e\x18\xab\x0c\x00\x92\xd3\x68" - "\x60\x56\x3b\x00\xef\xf8\x02\xfa" - "\xcb\x92\x1a\x91\xe1\xf0\x4f\x8a" - "\xc6\x4f\x65\x16\x71\x8b\x5d\xd5" - "\x79\xa9\x6d\x68\x1b\x59\xe7\x2a" - "\x1c\xd0\x5d\xfb\x06\x3b\x15\x72" - "\xa8\xd1\x59\x9a\xb2\x6c\xf2\xd5" - "\x19\xef\xde\x03\x4c\x75\x65\x38" - "\x5b\xda\xc9\xf0\x44\x99\xb2\x6e" - "\x78\xfb\x85\x5a\x92\x91\x1a\x0a" - "\x13\x0c\x1b\x1c\xbe\xbe\x46\x6e" - "\x73\xff\xc2\x6e\xb9\x06\x16\x7e" - "\xf6\xc0\x01\x30\x34\x56\x46\x55", - .len = 128, - }, { - .key = "\x2a\xed\x7d\x76\xfc\xc5\x49\x50" - "\xf4\x90\x0f\xcc\x5d\xff\x0c\x3c" - "\x14\x06\xaf\x68\x8f\xd7\xb6\x25" - "\x1e\x10\x95\x2a\x71\x33\x17\x20", - .klen = 32, - .iv = "\x5b\x58\x47\xf8\xd5\x1e\x91\x81" - "\x46\xe7\x25\x3a\x02\x45\x9c\x65", - .ptext = "\x10\xaf\xde\x5c\x30\x79\x43\x28" - "\x1c\x03\xf8\x50\x0f\x30\xa5\xef" - "\x84\x19\x4c\x09\x40\x03\x75\x1f" - "\x92\x8f\x88\x01\xda\x31\x7a\xe4" - "\x48\xe3\xab\xb4\xe6\x1b\x0f\xac" - "\xd9\xfa\x8d\x23\xe4\xc6\xa4\xa9" - "\x2d\x9a\x54\x52\x44\x5c\x3c\x52" - "\x61\xf0\x00\xca\xed\xab\xed\xe2" - "\x44\x0b\xe0\x18\xba\xa5\x63\xd8" - "\xdc\x5e\x1a\x4c\xf8\xde\x5e\x75" - "\xdf\x42\x27\x7b\xe9\x11\x2f\x41" - "\x3a\x72\x54\x3d\x44\x9c\x3e\x87" - "\x8d\x8d\x43\x2f\xb2\xff\x87\xd4" - "\xad\x98\x68\x72\x53\x61\x19\x7c" - "\x20\x79\x8c\x2b\x37\x0b\x96\x15" - "\xa5\x7d\x4e\x01\xe6\xea\xb6\xfa" - "\xaa\xd3\x9d\xa2\xd9\x11\xc3\xc9" - "\xd4\x0e\x3f\x3e\xfe\x35\x1e\xe5", - .ctext = "\xb0\x2b\x75\x5f\x33\x1b\x05\x49" - "\x06\xf1\x43\x91\xc2\x85\xfa\xac" - "\x74\xd5\x8c\xc9\x47\x6e\x5a\xf6" - "\x69\x33\x4c\xcb\x2f\x36\x4b\x41" - "\xec\x05\x69\xab\x7f\x42\xc9\xd2" - "\x26\x64\x51\x9e\x3d\x65\x35\xf0" - "\x8d\x5e\x8a\xb1\xee\xdf\x1a\x98" - "\x36\xd2\x37\x49\x5b\xe2\x57\x00" - "\x1d\x72\x7e\xe8\x38\x11\x83\x15" - "\xc7\x4e\x65\xa4\x2c\x9e\x6a\x3e" - "\xb4\x78\x3f\xe9\x91\x5d\x06\xa9" - "\xf1\xfc\x6b\x08\xe5\x2b\x2a\x99" - "\x65\xa7\x2e\x47\xf9\xc2\xb1\x8b" - "\x88\x2f\xb7\x62\x84\x63\x94\x00" - "\x49\xa7\xd0\x2b\x54\x7a\x69\xb3" - "\x04\x66\xfc\x97\x40\x92\xd1\xb8" - "\xb4\x2a\x9e\xdb\x31\xcd\x48\x84" - "\x29\x3b\x02\xac\xb8\x54\x95\xb4", - .len = 144, - }, { - .key = "\x7b\xa7\x4d\x0a\x37\x30\xb9\xf5" - "\x2a\x79\xb4\xbf\xdb\x7f\x9b\x64" - "\x23\x43\xb5\x18\x34\xc4\x5f\xdf" - "\xd9\x2a\x66\x58\x00\x44\xb5\xd9", - .klen = 32, - .iv = "\x75\x34\x30\xc1\xf0\x69\xdf\x0a" - "\x52\xce\x4f\x1e\x2c\x41\x35\xec", - .ptext = "\x81\x47\x55\x3a\xcd\xfe\xa2\x3d" - "\x45\x53\xa7\x67\x61\x74\x25\x80" - "\x98\x89\xfe\xf8\x6a\x9f\x51\x7c" - "\xa4\xe4\xe7\xc7\xe0\x1a\xce\xbb" - "\x4b\x46\x43\xb0\xab\xa8\xd6\x0c" - "\xa0\xf0\xc8\x13\x29\xaf\xb8\x01" - "\x6b\x0c\x7e\x56\xae\xb8\x58\x72" - "\xa9\x24\x44\x61\xff\xf1\xac\xf8" - "\x09\xa8\x48\x21\xd6\xab\x41\x73" - "\x70\x6b\x92\x06\x61\xdc\xb4\x85" - "\x76\x26\x7a\x84\xc3\x9e\x3a\x14" - "\xe7\xf4\x2d\x95\x92\xad\x18\xcc" - "\x44\xd4\x2c\x36\x57\xed\x2b\x9b" - "\x3f\x2b\xcd\xe5\x11\xe3\x62\x33" - "\x42\x3f\xb8\x2a\xb1\x37\x3f\x8b" - "\xe8\xbd\x6b\x0b\x9f\x38\x5a\x5f" - "\x82\x34\xb7\x96\x35\x58\xde\xab" - "\x94\x98\x41\x5b\x3f\xac\x0a\x34" - "\x56\xc0\x02\xef\x81\x6d\xb1\xff" - "\x34\xe8\xc7\x6a\x31\x79\xba\xd8", - .ctext = "\x4e\x00\x7c\x52\x45\x76\xf9\x3d" - "\x1a\xd1\x72\xbc\xb9\x0f\xa9\xfb" - "\x0a\xf5\xe8\x11\x66\x8b\xad\x68" - "\x5a\x2e\xbf\x09\x33\x9d\xb6\x67" - "\xe5\xcb\x0a\xe0\xac\xed\x73\x4b" - "\xbb\x15\xde\xd8\xab\x33\x28\x5f" - "\x96\x07\x3c\x28\x79\x88\x84\xc7" - "\x13\xf7\x0d\xa5\x97\x3b\xd9\xb1" - "\xf2\x65\xb0\xac\xbb\x8a\x97\xd1" - "\x70\x3a\x91\x65\xc8\x39\x04\xe7" - "\x1a\x9c\x80\x65\x2b\x69\x4b\xdc" - "\xdc\xc7\xf1\x31\xda\xab\xb4\xd7" - "\x46\x2e\x1d\xc9\x2e\xe9\x46\xec" - "\xa4\xa1\x91\x6b\x4a\x09\xf9\x39" - "\x7b\x7d\x6d\xf5\x43\x7f\xcc\x74" - "\x96\xfa\x48\xd0\xe1\x74\x24\xd0" - "\x19\x22\x24\x84\x2b\x12\x10\x46" - "\x90\xbd\xa9\x93\xb7\xf7\x36\xd4" - "\x48\xc7\x32\x83\x8c\xa9\xcd\x5a" - "\x2f\x05\x33\xc1\x5b\x50\x70\xc4", - .len = 160, - } -}; - static const struct aead_testvec aria_gcm_tv_template[] = { { .key = "\xe9\x1e\x5e\x75\xda\x65\x55\x4a" From 412ac51ce0b8c5581b6ff57fff6501e905a5471f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Nov 2023 20:25:02 +0800 Subject: [PATCH 3314/7721] crypto: cfb,ofb - Remove cfb and ofb Remove the unused algorithms CFB/OFB. Signed-off-by: Herbert Xu --- crypto/Kconfig | 23 ----- crypto/Makefile | 2 - crypto/cfb.c | 254 ------------------------------------------------ crypto/ofb.c | 106 -------------------- 4 files changed, 385 deletions(-) delete mode 100644 crypto/cfb.c delete mode 100644 crypto/ofb.c diff --git a/crypto/Kconfig b/crypto/Kconfig index 70661f58ee41..7d156c75f15f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -661,15 +661,6 @@ config CRYPTO_CBC This block cipher mode is required for IPSec ESP (XFRM_ESP). -config CRYPTO_CFB - tristate "CFB (Cipher Feedback)" - select CRYPTO_SKCIPHER - select CRYPTO_MANAGER - help - CFB (Cipher Feedback) mode (NIST SP800-38A) - - This block cipher mode is required for TPM2 Cryptography. - config CRYPTO_CTR tristate "CTR (Counter)" select CRYPTO_SKCIPHER @@ -735,20 +726,6 @@ config CRYPTO_LRW See https://people.csail.mit.edu/rivest/pubs/LRW02.pdf -config CRYPTO_OFB - tristate "OFB (Output Feedback)" - select CRYPTO_SKCIPHER - select CRYPTO_MANAGER - help - OFB (Output Feedback) mode (NIST SP800-38A) - - This mode makes a block cipher into a synchronous - stream cipher. It generates keystream blocks, which are then XORed - with the plaintext blocks to get the ciphertext. Flipping a bit in the - ciphertext produces a flipped bit in the plaintext at the same - location. This property allows many error correcting codes to function - normally even when applied before encryption. - config CRYPTO_PCBC tristate "PCBC (Propagating Cipher Block Chaining)" select CRYPTO_SKCIPHER diff --git a/crypto/Makefile b/crypto/Makefile index 5ac6876f935a..408f0a1f9ab9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -92,7 +92,6 @@ obj-$(CONFIG_CRYPTO_BLAKE2B) += blake2b_generic.o CFLAGS_blake2b_generic.o := -Wframe-larger-than=4096 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105930 obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o -obj-$(CONFIG_CRYPTO_CFB) += cfb.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_CTS) += cts.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o @@ -186,7 +185,6 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o -obj-$(CONFIG_CRYPTO_OFB) += ofb.o obj-$(CONFIG_CRYPTO_ECC) += ecc.o obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o diff --git a/crypto/cfb.c b/crypto/cfb.c deleted file mode 100644 index 5c36b7b65e2a..000000000000 --- a/crypto/cfb.c +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * CFB: Cipher FeedBack mode - * - * Copyright (c) 2018 James.Bottomley@HansenPartnership.com - * - * CFB is a stream cipher mode which is layered on to a block - * encryption scheme. It works very much like a one time pad where - * the pad is generated initially from the encrypted IV and then - * subsequently from the encrypted previous block of ciphertext. The - * pad is XOR'd into the plain text to get the final ciphertext. - * - * The scheme of CFB is best described by wikipedia: - * - * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB - * - * Note that since the pad for both encryption and decryption is - * generated by an encryption operation, CFB never uses the block - * decryption function. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm) -{ - return crypto_cipher_blocksize(skcipher_cipher_simple(tfm)); -} - -static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm, - const u8 *src, u8 *dst) -{ - crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src); -} - -/* final encrypt and decrypt is the same */ -static void crypto_cfb_final(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned long alignmask = crypto_skcipher_alignmask(tfm); - u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; - u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1); - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - unsigned int nbytes = walk->nbytes; - - crypto_cfb_encrypt_one(tfm, iv, stream); - crypto_xor_cpy(dst, stream, src, nbytes); -} - -static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - - do { - crypto_cfb_encrypt_one(tfm, iv, dst); - crypto_xor(dst, src, bsize); - iv = dst; - - src += bsize; - dst += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *iv = walk->iv; - u8 tmp[MAX_CIPHER_BLOCKSIZE]; - - do { - crypto_cfb_encrypt_one(tfm, iv, tmp); - crypto_xor(src, tmp, bsize); - iv = src; - - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct skcipher_walk walk; - unsigned int bsize = crypto_cfb_bsize(tfm); - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - if (walk.src.virt.addr == walk.dst.virt.addr) - err = crypto_cfb_encrypt_inplace(&walk, tfm); - else - err = crypto_cfb_encrypt_segment(&walk, tfm); - err = skcipher_walk_done(&walk, err); - } - - if (walk.nbytes) { - crypto_cfb_final(&walk, tfm); - err = skcipher_walk_done(&walk, 0); - } - - return err; -} - -static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - - do { - crypto_cfb_encrypt_one(tfm, iv, dst); - crypto_xor(dst, src, bsize); - iv = src; - - src += bsize; - dst += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 * const iv = walk->iv; - u8 tmp[MAX_CIPHER_BLOCKSIZE]; - - do { - crypto_cfb_encrypt_one(tfm, iv, tmp); - memcpy(iv, src, bsize); - crypto_xor(src, tmp, bsize); - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - return nbytes; -} - -static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - if (walk->src.virt.addr == walk->dst.virt.addr) - return crypto_cfb_decrypt_inplace(walk, tfm); - else - return crypto_cfb_decrypt_segment(walk, tfm); -} - -static int crypto_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct skcipher_walk walk; - const unsigned int bsize = crypto_cfb_bsize(tfm); - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - err = crypto_cfb_decrypt_blocks(&walk, tfm); - err = skcipher_walk_done(&walk, err); - } - - if (walk.nbytes) { - crypto_cfb_final(&walk, tfm); - err = skcipher_walk_done(&walk, 0); - } - - return err; -} - -static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct skcipher_instance *inst; - struct crypto_alg *alg; - int err; - - inst = skcipher_alloc_instance_simple(tmpl, tb); - if (IS_ERR(inst)) - return PTR_ERR(inst); - - alg = skcipher_ialg_simple(inst); - - /* CFB mode is a stream cipher. */ - inst->alg.base.cra_blocksize = 1; - - /* - * To simplify the implementation, configure the skcipher walk to only - * give a partial block at the very end, never earlier. - */ - inst->alg.chunksize = alg->cra_blocksize; - - inst->alg.encrypt = crypto_cfb_encrypt; - inst->alg.decrypt = crypto_cfb_decrypt; - - err = skcipher_register_instance(tmpl, inst); - if (err) - inst->free(inst); - - return err; -} - -static struct crypto_template crypto_cfb_tmpl = { - .name = "cfb", - .create = crypto_cfb_create, - .module = THIS_MODULE, -}; - -static int __init crypto_cfb_module_init(void) -{ - return crypto_register_template(&crypto_cfb_tmpl); -} - -static void __exit crypto_cfb_module_exit(void) -{ - crypto_unregister_template(&crypto_cfb_tmpl); -} - -subsys_initcall(crypto_cfb_module_init); -module_exit(crypto_cfb_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CFB block cipher mode of operation"); -MODULE_ALIAS_CRYPTO("cfb"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); diff --git a/crypto/ofb.c b/crypto/ofb.c deleted file mode 100644 index b630fdecceee..000000000000 --- a/crypto/ofb.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * OFB: Output FeedBack mode - * - * Copyright (C) 2018 ARM Limited or its affiliates. - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int crypto_ofb_crypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_cipher *cipher = skcipher_cipher_simple(tfm); - const unsigned int bsize = crypto_cipher_blocksize(cipher); - struct skcipher_walk walk; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - u8 * const iv = walk.iv; - unsigned int nbytes = walk.nbytes; - - do { - crypto_cipher_encrypt_one(cipher, iv, iv); - crypto_xor_cpy(dst, src, iv, bsize); - dst += bsize; - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - err = skcipher_walk_done(&walk, nbytes); - } - - if (walk.nbytes) { - crypto_cipher_encrypt_one(cipher, walk.iv, walk.iv); - crypto_xor_cpy(walk.dst.virt.addr, walk.src.virt.addr, walk.iv, - walk.nbytes); - err = skcipher_walk_done(&walk, 0); - } - return err; -} - -static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct skcipher_instance *inst; - struct crypto_alg *alg; - int err; - - inst = skcipher_alloc_instance_simple(tmpl, tb); - if (IS_ERR(inst)) - return PTR_ERR(inst); - - alg = skcipher_ialg_simple(inst); - - /* OFB mode is a stream cipher. */ - inst->alg.base.cra_blocksize = 1; - - /* - * To simplify the implementation, configure the skcipher walk to only - * give a partial block at the very end, never earlier. - */ - inst->alg.chunksize = alg->cra_blocksize; - - inst->alg.encrypt = crypto_ofb_crypt; - inst->alg.decrypt = crypto_ofb_crypt; - - err = skcipher_register_instance(tmpl, inst); - if (err) - inst->free(inst); - - return err; -} - -static struct crypto_template crypto_ofb_tmpl = { - .name = "ofb", - .create = crypto_ofb_create, - .module = THIS_MODULE, -}; - -static int __init crypto_ofb_module_init(void) -{ - return crypto_register_template(&crypto_ofb_tmpl); -} - -static void __exit crypto_ofb_module_exit(void) -{ - crypto_unregister_template(&crypto_ofb_tmpl); -} - -subsys_initcall(crypto_ofb_module_init); -module_exit(crypto_ofb_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("OFB block cipher mode of operation"); -MODULE_ALIAS_CRYPTO("ofb"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); From 0ae4dcc1ebf63118364d540b84c70352e8b2b2a4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 27 Nov 2023 18:14:08 +0800 Subject: [PATCH 3315/7721] crypto: skcipher - Add internal state support Unlike chaining modes such as CBC, stream ciphers other than CTR usually hold an internal state that must be preserved if the operation is to be done piecemeal. This has not been represented in the API, resulting in the inability to split up stream cipher operations. This patch adds the basic representation of an internal state to skcipher and lskcipher. In the interest of backwards compatibility, the default has been set such that existing users are assumed to be operating in one go as opposed to piecemeal. With the new API, each lskcipher/skcipher algorithm has a new attribute called statesize. For skcipher, this is the size of the buffer that can be exported or imported similar to ahash. For lskcipher, instead of providing a buffer of ivsize, the user now has to provide a buffer of ivsize + statesize. Each skcipher operation is assumed to be final as they are now, but this may be overridden with a request flag. When the override occurs, the user may then export the partial state and reimport it later. For lskcipher operations this is reversed. All operations are not final and the state will be exported unless the FINAL bit is set. However, the CONT bit still has to be set for the state to be used. Signed-off-by: Herbert Xu --- crypto/arc4.c | 2 +- crypto/cbc.c | 6 ++- crypto/ecb.c | 10 +++-- crypto/lskcipher.c | 14 ++++--- include/crypto/skcipher.h | 84 ++++++++++++++++++++++++++++++++++----- 5 files changed, 94 insertions(+), 22 deletions(-) diff --git a/crypto/arc4.c b/crypto/arc4.c index eb3590dc9282..2150f94e7d03 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -23,7 +23,7 @@ static int crypto_arc4_setkey(struct crypto_lskcipher *tfm, const u8 *in_key, } static int crypto_arc4_crypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned nbytes, u8 *iv, bool final) + u8 *dst, unsigned nbytes, u8 *iv, u32 flags) { struct arc4_ctx *ctx = crypto_lskcipher_ctx(tfm); diff --git a/crypto/cbc.c b/crypto/cbc.c index 28345b8d921c..eedddef9ce40 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -51,9 +51,10 @@ static int crypto_cbc_encrypt_inplace(struct crypto_lskcipher *tfm, } static int crypto_cbc_encrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm); + bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL; struct crypto_lskcipher *cipher = *ctx; int rem; @@ -119,9 +120,10 @@ static int crypto_cbc_decrypt_inplace(struct crypto_lskcipher *tfm, } static int crypto_cbc_decrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm); + bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL; struct crypto_lskcipher *cipher = *ctx; int rem; diff --git a/crypto/ecb.c b/crypto/ecb.c index cc7625d1a475..e3a67789050e 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -32,22 +32,24 @@ static int crypto_ecb_crypt(struct crypto_cipher *cipher, const u8 *src, } static int crypto_ecb_encrypt2(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_cipher **ctx = crypto_lskcipher_ctx(tfm); struct crypto_cipher *cipher = *ctx; - return crypto_ecb_crypt(cipher, src, dst, len, final, + return crypto_ecb_crypt(cipher, src, dst, len, + flags & CRYPTO_LSKCIPHER_FLAG_FINAL, crypto_cipher_alg(cipher)->cia_encrypt); } static int crypto_ecb_decrypt2(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_cipher **ctx = crypto_lskcipher_ctx(tfm); struct crypto_cipher *cipher = *ctx; - return crypto_ecb_crypt(cipher, src, dst, len, final, + return crypto_ecb_crypt(cipher, src, dst, len, + flags & CRYPTO_LSKCIPHER_FLAG_FINAL, crypto_cipher_alg(cipher)->cia_decrypt); } diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index 9edc89730951..51bcf85070c7 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -88,7 +88,7 @@ EXPORT_SYMBOL_GPL(crypto_lskcipher_setkey); static int crypto_lskcipher_crypt_unaligned( struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final)) + u8 *dst, unsigned len, u8 *iv, u32 flags)) { unsigned ivsize = crypto_lskcipher_ivsize(tfm); unsigned bs = crypto_lskcipher_blocksize(tfm); @@ -119,7 +119,7 @@ static int crypto_lskcipher_crypt_unaligned( chunk &= ~(cs - 1); memcpy(p, src, chunk); - err = crypt(tfm, p, p, chunk, tiv, true); + err = crypt(tfm, p, p, chunk, tiv, CRYPTO_LSKCIPHER_FLAG_FINAL); if (err) goto out; @@ -143,7 +143,7 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, - bool final)) + u32 flags)) { unsigned long alignmask = crypto_lskcipher_alignmask(tfm); struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); @@ -156,7 +156,7 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, goto out; } - ret = crypt(tfm, src, dst, len, iv, true); + ret = crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); out: return crypto_lskcipher_errstat(alg, ret); @@ -198,7 +198,7 @@ static int crypto_lskcipher_crypt_sg(struct skcipher_request *req, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, - bool final)) + u32 flags)) { struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct crypto_lskcipher **ctx = crypto_skcipher_ctx(skcipher); @@ -210,7 +210,9 @@ static int crypto_lskcipher_crypt_sg(struct skcipher_request *req, while (walk.nbytes) { err = crypt(tfm, walk.src.virt.addr, walk.dst.virt.addr, - walk.nbytes, walk.iv, walk.nbytes == walk.total); + walk.nbytes, walk.iv, + walk.nbytes == walk.total ? + CRYPTO_LSKCIPHER_FLAG_FINAL : 0); err = skcipher_walk_done(&walk, err); } diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index ea18af48346b..5302f8f33afc 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -15,6 +15,17 @@ #include #include +/* Set this bit if the lskcipher operation is a continuation. */ +#define CRYPTO_LSKCIPHER_FLAG_CONT 0x00000001 +/* Set this bit if the lskcipher operation is final. */ +#define CRYPTO_LSKCIPHER_FLAG_FINAL 0x00000002 +/* The bit CRYPTO_TFM_REQ_MAY_SLEEP can also be set if needed. */ + +/* Set this bit if the skcipher operation is a continuation. */ +#define CRYPTO_SKCIPHER_REQ_CONT 0x00000001 +/* Set this bit if the skcipher operation is not final. */ +#define CRYPTO_SKCIPHER_REQ_NOTFINAL 0x00000002 + struct scatterlist; /** @@ -91,6 +102,7 @@ struct crypto_istat_cipher { * IV of exactly that size to perform the encrypt or decrypt operation. * @chunksize: Equal to the block size except for stream ciphers such as * CTR where it is set to the underlying block size. + * @statesize: Size of the internal state for the algorithm. * @stat: Statistics for cipher algorithm * @base: Definition of a generic crypto algorithm. */ @@ -99,6 +111,7 @@ struct crypto_istat_cipher { unsigned int max_keysize; \ unsigned int ivsize; \ unsigned int chunksize; \ + unsigned int statesize; \ \ SKCIPHER_ALG_COMMON_STAT \ \ @@ -141,6 +154,17 @@ struct skcipher_alg_common SKCIPHER_ALG_COMMON; * be called in parallel with the same transformation object. * @decrypt: Decrypt a single block. This is a reverse counterpart to @encrypt * and the conditions are exactly the same. + * @export: Export partial state of the transformation. This function dumps the + * entire state of the ongoing transformation into a provided block of + * data so it can be @import 'ed back later on. This is useful in case + * you want to save partial result of the transformation after + * processing certain amount of data and reload this partial result + * multiple times later on for multiple re-use. No data processing + * happens at this point. + * @import: Import partial state of the transformation. This function loads the + * entire state of the ongoing transformation from a provided block of + * data so the transformation can continue from this point onward. No + * data processing happens at this point. * @init: Initialize the cryptographic transformation object. This function * is used to initialize the cryptographic transformation object. * This function is called only once at the instantiation time, right @@ -170,6 +194,8 @@ struct skcipher_alg { unsigned int keylen); int (*encrypt)(struct skcipher_request *req); int (*decrypt)(struct skcipher_request *req); + int (*export)(struct skcipher_request *req, void *out); + int (*import)(struct skcipher_request *req, const void *in); int (*init)(struct crypto_skcipher *tfm); void (*exit)(struct crypto_skcipher *tfm); @@ -200,6 +226,9 @@ struct skcipher_alg { * may be left over if length is not a multiple of blocks * and there is more to come (final == false). The number of * left-over bytes should be returned in case of success. + * The siv field shall be as long as ivsize + statesize with + * the IV placed at the front. The state will be used by the + * algorithm internally. * @decrypt: Decrypt a number of bytes. This is a reverse counterpart to * @encrypt and the conditions are exactly the same. * @init: Initialize the cryptographic transformation object. This function @@ -215,9 +244,9 @@ struct lskcipher_alg { int (*setkey)(struct crypto_lskcipher *tfm, const u8 *key, unsigned int keylen); int (*encrypt)(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final); + u8 *dst, unsigned len, u8 *siv, u32 flags); int (*decrypt)(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final); + u8 *dst, unsigned len, u8 *siv, u32 flags); int (*init)(struct crypto_lskcipher *tfm); void (*exit)(struct crypto_lskcipher *tfm); @@ -496,6 +525,40 @@ static inline unsigned int crypto_lskcipher_chunksize( return crypto_lskcipher_alg(tfm)->co.chunksize; } +/** + * crypto_skcipher_statesize() - obtain state size + * @tfm: cipher handle + * + * Some algorithms cannot be chained with the IV alone. They carry + * internal state which must be replicated if data is to be processed + * incrementally. The size of that state can be obtained with this + * function. + * + * Return: state size in bytes + */ +static inline unsigned int crypto_skcipher_statesize( + struct crypto_skcipher *tfm) +{ + return crypto_skcipher_alg_common(tfm)->statesize; +} + +/** + * crypto_lskcipher_statesize() - obtain state size + * @tfm: cipher handle + * + * Some algorithms cannot be chained with the IV alone. They carry + * internal state which must be replicated if data is to be processed + * incrementally. The size of that state can be obtained with this + * function. + * + * Return: state size in bytes + */ +static inline unsigned int crypto_lskcipher_statesize( + struct crypto_lskcipher *tfm) +{ + return crypto_lskcipher_alg(tfm)->co.statesize; +} + static inline unsigned int crypto_sync_skcipher_blocksize( struct crypto_sync_skcipher *tfm) { @@ -689,9 +752,10 @@ int crypto_skcipher_decrypt(struct skcipher_request *req); * @src: source buffer * @dst: destination buffer * @len: number of bytes to process - * @iv: IV for the cipher operation which must comply with the IV size defined - * by crypto_lskcipher_ivsize - * + * @siv: IV + state for the cipher operation. The length of the IV must + * comply with the IV size defined by crypto_lskcipher_ivsize. The + * IV is then followed with a buffer with the length as specified by + * crypto_lskcipher_statesize. * Encrypt plaintext data using the lskcipher handle. * * Return: >=0 if the cipher operation was successful, if positive @@ -699,7 +763,7 @@ int crypto_skcipher_decrypt(struct skcipher_request *req); * < 0 if an error occurred */ int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv); + u8 *dst, unsigned len, u8 *siv); /** * crypto_lskcipher_decrypt() - decrypt ciphertext @@ -707,8 +771,10 @@ int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, * @src: source buffer * @dst: destination buffer * @len: number of bytes to process - * @iv: IV for the cipher operation which must comply with the IV size defined - * by crypto_lskcipher_ivsize + * @siv: IV + state for the cipher operation. The length of the IV must + * comply with the IV size defined by crypto_lskcipher_ivsize. The + * IV is then followed with a buffer with the length as specified by + * crypto_lskcipher_statesize. * * Decrypt ciphertext data using the lskcipher handle. * @@ -717,7 +783,7 @@ int crypto_lskcipher_encrypt(struct crypto_lskcipher *tfm, const u8 *src, * < 0 if an error occurred */ int crypto_lskcipher_decrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv); + u8 *dst, unsigned len, u8 *siv); /** * DOC: Symmetric Key Cipher Request Handle From 662ea18d089ba6fa02859fbd64f2aa78d88c6648 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 28 Nov 2023 14:33:19 +0800 Subject: [PATCH 3316/7721] crypto: skcipher - Make use of internal state This patch adds code to the skcipher/lskcipher API to make use of the internal state if present. In particular, the skcipher lskcipher wrapper will allocate a buffer for the IV/state and feed that to the underlying lskcipher algorithm. Signed-off-by: Herbert Xu --- crypto/lskcipher.c | 34 ++++++++++++++--- crypto/skcipher.c | 80 ++++++++++++++++++++++++++++++++++++++- include/crypto/skcipher.h | 33 ++++++++++++++++ 3 files changed, 139 insertions(+), 8 deletions(-) diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index 51bcf85070c7..a06008e112f3 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -90,6 +90,7 @@ static int crypto_lskcipher_crypt_unaligned( u8 *iv, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, u32 flags)) { + unsigned statesize = crypto_lskcipher_statesize(tfm); unsigned ivsize = crypto_lskcipher_ivsize(tfm); unsigned bs = crypto_lskcipher_blocksize(tfm); unsigned cs = crypto_lskcipher_chunksize(tfm); @@ -104,7 +105,7 @@ static int crypto_lskcipher_crypt_unaligned( if (!tiv) return -ENOMEM; - memcpy(tiv, iv, ivsize); + memcpy(tiv, iv, ivsize + statesize); p = kmalloc(PAGE_SIZE, GFP_ATOMIC); err = -ENOMEM; @@ -132,7 +133,7 @@ static int crypto_lskcipher_crypt_unaligned( err = len ? -EINVAL : 0; out: - memcpy(iv, tiv, ivsize); + memcpy(iv, tiv, ivsize + statesize); kfree_sensitive(p); kfree_sensitive(tiv); return err; @@ -197,25 +198,45 @@ EXPORT_SYMBOL_GPL(crypto_lskcipher_decrypt); static int crypto_lskcipher_crypt_sg(struct skcipher_request *req, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, - unsigned len, u8 *iv, + unsigned len, u8 *ivs, u32 flags)) { struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct crypto_lskcipher **ctx = crypto_skcipher_ctx(skcipher); + u8 *ivs = skcipher_request_ctx(req); struct crypto_lskcipher *tfm = *ctx; struct skcipher_walk walk; + unsigned ivsize; + u32 flags; int err; + ivsize = crypto_lskcipher_ivsize(tfm); + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(skcipher) + 1); + + flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + if (req->base.flags & CRYPTO_SKCIPHER_REQ_CONT) + flags |= CRYPTO_LSKCIPHER_FLAG_CONT; + else + memcpy(ivs, req->iv, ivsize); + + if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL)) + flags |= CRYPTO_LSKCIPHER_FLAG_FINAL; + err = skcipher_walk_virt(&walk, req, false); while (walk.nbytes) { err = crypt(tfm, walk.src.virt.addr, walk.dst.virt.addr, - walk.nbytes, walk.iv, - walk.nbytes == walk.total ? - CRYPTO_LSKCIPHER_FLAG_FINAL : 0); + walk.nbytes, ivs, + flags & ~(walk.nbytes == walk.total ? + 0 : CRYPTO_LSKCIPHER_FLAG_FINAL)); err = skcipher_walk_done(&walk, err); + flags |= CRYPTO_LSKCIPHER_FLAG_CONT; } + if (flags & CRYPTO_LSKCIPHER_FLAG_FINAL) + memcpy(req->iv, ivs, ivsize); + return err; } @@ -278,6 +299,7 @@ static void __maybe_unused crypto_lskcipher_show( seq_printf(m, "max keysize : %u\n", skcipher->co.max_keysize); seq_printf(m, "ivsize : %u\n", skcipher->co.ivsize); seq_printf(m, "chunksize : %u\n", skcipher->co.chunksize); + seq_printf(m, "statesize : %u\n", skcipher->co.statesize); } static int __maybe_unused crypto_lskcipher_report( diff --git a/crypto/skcipher.c b/crypto/skcipher.c index ac8b8c042654..bc70e159d27d 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -698,6 +698,64 @@ int crypto_skcipher_decrypt(struct skcipher_request *req) } EXPORT_SYMBOL_GPL(crypto_skcipher_decrypt); +static int crypto_lskcipher_export(struct skcipher_request *req, void *out) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + u8 *ivs = skcipher_request_ctx(req); + + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1); + + memcpy(out, ivs + crypto_skcipher_ivsize(tfm), + crypto_skcipher_statesize(tfm)); + + return 0; +} + +static int crypto_lskcipher_import(struct skcipher_request *req, const void *in) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + u8 *ivs = skcipher_request_ctx(req); + + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1); + + memcpy(ivs + crypto_skcipher_ivsize(tfm), in, + crypto_skcipher_statesize(tfm)); + + return 0; +} + +static int skcipher_noexport(struct skcipher_request *req, void *out) +{ + return 0; +} + +static int skcipher_noimport(struct skcipher_request *req, const void *in) +{ + return 0; +} + +int crypto_skcipher_export(struct skcipher_request *req, void *out) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_export(req, out); + return alg->export(req, out); +} +EXPORT_SYMBOL_GPL(crypto_skcipher_export); + +int crypto_skcipher_import(struct skcipher_request *req, const void *in) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_import(req, in); + return alg->import(req, in); +} +EXPORT_SYMBOL_GPL(crypto_skcipher_import); + static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) { struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); @@ -713,8 +771,17 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) skcipher_set_needkey(skcipher); - if (tfm->__crt_alg->cra_type != &crypto_skcipher_type) + if (tfm->__crt_alg->cra_type != &crypto_skcipher_type) { + unsigned am = crypto_skcipher_alignmask(skcipher); + unsigned reqsize; + + reqsize = am & ~(crypto_tfm_ctx_alignment() - 1); + reqsize += crypto_skcipher_ivsize(skcipher); + reqsize += crypto_skcipher_statesize(skcipher); + crypto_skcipher_set_reqsize(skcipher, reqsize); + return crypto_init_lskcipher_ops_sg(tfm); + } if (alg->exit) skcipher->base.exit = crypto_skcipher_exit_tfm; @@ -756,6 +823,7 @@ static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "ivsize : %u\n", skcipher->ivsize); seq_printf(m, "chunksize : %u\n", skcipher->chunksize); seq_printf(m, "walksize : %u\n", skcipher->walksize); + seq_printf(m, "statesize : %u\n", skcipher->statesize); } static int __maybe_unused crypto_skcipher_report( @@ -870,7 +938,9 @@ int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) struct crypto_istat_cipher *istat = skcipher_get_stat_common(alg); struct crypto_alg *base = &alg->base; - if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8) + if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8 || + alg->statesize > PAGE_SIZE / 2 || + (alg->ivsize + alg->statesize) > PAGE_SIZE / 2) return -EINVAL; if (!alg->chunksize) @@ -899,6 +969,12 @@ static int skcipher_prepare_alg(struct skcipher_alg *alg) if (!alg->walksize) alg->walksize = alg->chunksize; + if (!alg->statesize) { + alg->import = skcipher_noimport; + alg->export = skcipher_noexport; + } else if (!(alg->import && alg->export)) + return -EINVAL; + base->cra_type = &crypto_skcipher_type; base->cra_flags |= CRYPTO_ALG_TYPE_SKCIPHER; diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 5302f8f33afc..f881740df194 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -746,6 +746,39 @@ int crypto_skcipher_encrypt(struct skcipher_request *req); */ int crypto_skcipher_decrypt(struct skcipher_request *req); +/** + * crypto_skcipher_export() - export partial state + * @req: reference to the skcipher_request handle that holds all information + * needed to perform the operation + * @out: output buffer of sufficient size that can hold the state + * + * Export partial state of the transformation. This function dumps the + * entire state of the ongoing transformation into a provided block of + * data so it can be @import 'ed back later on. This is useful in case + * you want to save partial result of the transformation after + * processing certain amount of data and reload this partial result + * multiple times later on for multiple re-use. No data processing + * happens at this point. + * + * Return: 0 if the cipher operation was successful; < 0 if an error occurred + */ +int crypto_skcipher_export(struct skcipher_request *req, void *out); + +/** + * crypto_skcipher_import() - import partial state + * @req: reference to the skcipher_request handle that holds all information + * needed to perform the operation + * @in: buffer holding the state + * + * Import partial state of the transformation. This function loads the + * entire state of the ongoing transformation from a provided block of + * data so the transformation can continue from this point onward. No + * data processing happens at this point. + * + * Return: 0 if the cipher operation was successful; < 0 if an error occurred + */ +int crypto_skcipher_import(struct skcipher_request *req, const void *in); + /** * crypto_lskcipher_encrypt() - encrypt plaintext * @tfm: lskcipher handle From 47309ea1359115125d9cab17a279c8df72b47235 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 28 Nov 2023 14:52:57 +0800 Subject: [PATCH 3317/7721] crypto: arc4 - Add internal state The arc4 algorithm has always had internal state. It's been buggy from day one in that the state has been stored in the shared tfm object. That means two users sharing the same tfm will end up affecting each other's output, or worse, they may end up with the same output. Fix this by declaring an internal state and storing the state there instead of within the tfm context. Signed-off-by: Herbert Xu --- crypto/arc4.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crypto/arc4.c b/crypto/arc4.c index 2150f94e7d03..1a4825c97c5a 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -14,6 +14,8 @@ #include #include +#define ARC4_ALIGN __alignof__(struct arc4_ctx) + static int crypto_arc4_setkey(struct crypto_lskcipher *tfm, const u8 *in_key, unsigned int key_len) { @@ -23,10 +25,15 @@ static int crypto_arc4_setkey(struct crypto_lskcipher *tfm, const u8 *in_key, } static int crypto_arc4_crypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned nbytes, u8 *iv, u32 flags) + u8 *dst, unsigned nbytes, u8 *siv, u32 flags) { struct arc4_ctx *ctx = crypto_lskcipher_ctx(tfm); + if (!(flags & CRYPTO_LSKCIPHER_FLAG_CONT)) + memcpy(siv, ctx, sizeof(*ctx)); + + ctx = (struct arc4_ctx *)siv; + arc4_crypt(ctx, dst, src, nbytes); return 0; } @@ -45,9 +52,11 @@ static struct lskcipher_alg arc4_alg = { .co.base.cra_priority = 100, .co.base.cra_blocksize = ARC4_BLOCK_SIZE, .co.base.cra_ctxsize = sizeof(struct arc4_ctx), + .co.base.cra_alignmask = ARC4_ALIGN - 1, .co.base.cra_module = THIS_MODULE, .co.min_keysize = ARC4_MIN_KEY_SIZE, .co.max_keysize = ARC4_MAX_KEY_SIZE, + .co.statesize = sizeof(struct arc4_ctx), .setkey = crypto_arc4_setkey, .encrypt = crypto_arc4_crypt, .decrypt = crypto_arc4_crypt, From 99bd99d3e3a7f73c1c01ef510d48730b3bdd2c4a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Nov 2023 12:27:04 +0800 Subject: [PATCH 3318/7721] crypto: algif_skcipher - Fix stream cipher chaining Unlike algif_aead which is always issued in one go (thus limiting the maximum size of the request), algif_skcipher has always allowed unlimited input data by cutting them up as necessary and feeding the fragments to the underlying algorithm one at a time. However, because of deficiencies in the API, this has been broken for most stream ciphers such as arc4 or chacha. This is because they have an internal state in addition to the IV that must be preserved in order to continue processing. Fix this by using the new skcipher state API. Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 72 +++++++++++++++++++++++++++++++++++++++-- include/crypto/if_alg.h | 2 ++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 9ada9b741af8..02cea2149504 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -47,6 +47,52 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, return af_alg_sendmsg(sock, msg, size, ivsize); } +static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) +{ + struct alg_sock *ask = alg_sk(sk); + struct crypto_skcipher *tfm; + struct af_alg_ctx *ctx; + struct alg_sock *pask; + unsigned statesize; + struct sock *psk; + int err; + + if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL)) + return 0; + + ctx = ask->private; + psk = ask->parent; + pask = alg_sk(psk); + tfm = pask->private; + + statesize = crypto_skcipher_statesize(tfm); + ctx->state = sock_kmalloc(sk, statesize, GFP_ATOMIC); + if (!ctx->state) + return -ENOMEM; + + err = crypto_skcipher_export(req, ctx->state); + if (err) { + sock_kzfree_s(sk, ctx->state, statesize); + ctx->state = NULL; + } + + return err; +} + +static void algif_skcipher_done(void *data, int err) +{ + struct af_alg_async_req *areq = data; + struct sock *sk = areq->sk; + + if (err) + goto out; + + err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); + +out: + af_alg_async_cb(data, err); +} + static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -58,6 +104,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, struct crypto_skcipher *tfm = pask->private; unsigned int bs = crypto_skcipher_chunksize(tfm); struct af_alg_async_req *areq; + unsigned cflags = 0; int err = 0; size_t len = 0; @@ -82,8 +129,10 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, * If more buffers are to be expected to be processed, process only * full block size buffers. */ - if (ctx->more || len < ctx->used) + if (ctx->more || len < ctx->used) { len -= len % bs; + cflags |= CRYPTO_SKCIPHER_REQ_NOTFINAL; + } /* * Create a per request TX SGL for this request which tracks the @@ -107,6 +156,16 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); + if (ctx->state) { + err = crypto_skcipher_import(&areq->cra_u.skcipher_req, + ctx->state); + sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm)); + ctx->state = NULL; + if (err) + goto free; + cflags |= CRYPTO_SKCIPHER_REQ_CONT; + } + if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ sock_hold(sk); @@ -116,8 +175,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, areq->outlen = len; skcipher_request_set_callback(&areq->cra_u.skcipher_req, + cflags | CRYPTO_TFM_REQ_MAY_SLEEP, - af_alg_async_cb, areq); + algif_skcipher_done, areq); err = ctx->enc ? crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); @@ -130,6 +190,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, } else { /* Synchronous operation */ skcipher_request_set_callback(&areq->cra_u.skcipher_req, + cflags | CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &ctx->wait); @@ -137,8 +198,11 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), &ctx->wait); - } + if (!err) + err = algif_skcipher_export( + sk, &areq->cra_u.skcipher_req); + } free: af_alg_free_resources(areq); @@ -301,6 +365,8 @@ static void skcipher_sock_destruct(struct sock *sk) af_alg_pull_tsgl(sk, ctx->used, NULL, 0); sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + if (ctx->state) + sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm)); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); } diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 08b803a4fcde..78ecaf5db04c 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -121,6 +121,7 @@ struct af_alg_async_req { * * @tsgl_list: Link to TX SGL * @iv: IV for cipher operation + * @state: Existing state for continuing operation * @aead_assoclen: Length of AAD for AEAD cipher operations * @completion: Work queue for synchronous operation * @used: TX bytes sent to kernel. This variable is used to @@ -142,6 +143,7 @@ struct af_alg_ctx { struct list_head tsgl_list; void *iv; + void *state; size_t aead_assoclen; struct crypto_wait wait; From 4dc7e7d2eead9abc10e2327d40ff6ca0d24cd83a Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:39:59 +0530 Subject: [PATCH 3319/7721] dt-bindings: clock: qcom: Add X1E80100 GCC clocks Add device tree bindings for global clock controller on X1E80100 SoCs. Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231205061002.30759-2-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,x1e80100-gcc.yaml | 72 +++ include/dt-bindings/clock/qcom,x1e80100-gcc.h | 485 ++++++++++++++++++ 2 files changed, 557 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml create mode 100644 include/dt-bindings/clock/qcom,x1e80100-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml new file mode 100644 index 000000000000..14a796dbf8bc --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,x1e80100-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on X1E80100 + +maintainers: + - Rajendra Nayak + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on X1E80100 + + See also:: include/dt-bindings/clock/qcom,x1e80100-gcc.h + +properties: + compatible: + const: qcom,x1e80100-gcc + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + - description: PCIe 3 pipe clock + - description: PCIe 4 pipe clock + - description: PCIe 5 pipe clock + - description: PCIe 6a pipe clock + - description: PCIe 6b pipe clock + - description: USB QMP Phy 0 clock source + - description: USB QMP Phy 1 clock source + - description: USB QMP Phy 2 clock source + + power-domains: + description: + A phandle and PM domain specifier for the CX power domain. + maxItems: 1 + +required: + - compatible + - clocks + - power-domains + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; + reg = <0x00100000 0x200000>; + clocks = <&bi_tcxo_div2>, + <&sleep_clk>, + <&pcie3_phy>, + <&pcie4_phy>, + <&pcie5_phy>, + <&pcie6a_phy>, + <&pcie6b_phy>, + <&usb_1_ss0_qmpphy 0>, + <&usb_1_ss1_qmpphy 1>, + <&usb_1_ss2_qmpphy 2>; + power-domains = <&rpmhpd RPMHPD_CX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,x1e80100-gcc.h b/include/dt-bindings/clock/qcom,x1e80100-gcc.h new file mode 100644 index 000000000000..24ba9e2a5cf6 --- /dev/null +++ b/include/dt-bindings/clock/qcom,x1e80100-gcc.h @@ -0,0 +1,485 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_X1E80100_H +#define _DT_BINDINGS_CLK_QCOM_GCC_X1E80100_H + +/* GCC clocks */ +#define GCC_AGGRE_NOC_USB_NORTH_AXI_CLK 0 +#define GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK 1 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 2 +#define GCC_AGGRE_USB2_PRIM_AXI_CLK 3 +#define GCC_AGGRE_USB3_MP_AXI_CLK 4 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 5 +#define GCC_AGGRE_USB3_SEC_AXI_CLK 6 +#define GCC_AGGRE_USB3_TERT_AXI_CLK 7 +#define GCC_AGGRE_USB4_0_AXI_CLK 8 +#define GCC_AGGRE_USB4_1_AXI_CLK 9 +#define GCC_AGGRE_USB4_2_AXI_CLK 10 +#define GCC_AGGRE_USB_NOC_AXI_CLK 11 +#define GCC_AV1E_AHB_CLK 12 +#define GCC_AV1E_AXI_CLK 13 +#define GCC_AV1E_XO_CLK 14 +#define GCC_BOOT_ROM_AHB_CLK 15 +#define GCC_CAMERA_AHB_CLK 16 +#define GCC_CAMERA_HF_AXI_CLK 17 +#define GCC_CAMERA_SF_AXI_CLK 18 +#define GCC_CAMERA_XO_CLK 19 +#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 20 +#define GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK 21 +#define GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK 22 +#define GCC_CFG_NOC_USB2_PRIM_AXI_CLK 23 +#define GCC_CFG_NOC_USB3_MP_AXI_CLK 24 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 25 +#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 26 +#define GCC_CFG_NOC_USB3_TERT_AXI_CLK 27 +#define GCC_CFG_NOC_USB_ANOC_AHB_CLK 28 +#define GCC_CFG_NOC_USB_ANOC_NORTH_AHB_CLK 29 +#define GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK 30 +#define GCC_CNOC_PCIE1_TUNNEL_CLK 31 +#define GCC_CNOC_PCIE2_TUNNEL_CLK 32 +#define GCC_CNOC_PCIE_NORTH_SF_AXI_CLK 33 +#define GCC_CNOC_PCIE_SOUTH_SF_AXI_CLK 34 +#define GCC_CNOC_PCIE_TUNNEL_CLK 35 +#define GCC_DDRSS_GPU_AXI_CLK 36 +#define GCC_DISP_AHB_CLK 37 +#define GCC_DISP_HF_AXI_CLK 38 +#define GCC_DISP_XO_CLK 39 +#define GCC_GP1_CLK 40 +#define GCC_GP1_CLK_SRC 41 +#define GCC_GP2_CLK 42 +#define GCC_GP2_CLK_SRC 43 +#define GCC_GP3_CLK 44 +#define GCC_GP3_CLK_SRC 45 +#define GCC_GPLL0 46 +#define GCC_GPLL0_OUT_EVEN 47 +#define GCC_GPLL4 48 +#define GCC_GPLL7 49 +#define GCC_GPLL8 50 +#define GCC_GPLL9 51 +#define GCC_GPU_CFG_AHB_CLK 52 +#define GCC_GPU_GPLL0_CPH_CLK_SRC 53 +#define GCC_GPU_GPLL0_DIV_CPH_CLK_SRC 54 +#define GCC_GPU_MEMNOC_GFX_CLK 55 +#define GCC_GPU_SNOC_DVM_GFX_CLK 56 +#define GCC_PCIE0_PHY_RCHNG_CLK 57 +#define GCC_PCIE1_PHY_RCHNG_CLK 58 +#define GCC_PCIE2_PHY_RCHNG_CLK 59 +#define GCC_PCIE_0_AUX_CLK 60 +#define GCC_PCIE_0_AUX_CLK_SRC 61 +#define GCC_PCIE_0_CFG_AHB_CLK 62 +#define GCC_PCIE_0_MSTR_AXI_CLK 63 +#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 64 +#define GCC_PCIE_0_PIPE_CLK 65 +#define GCC_PCIE_0_SLV_AXI_CLK 66 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 67 +#define GCC_PCIE_1_AUX_CLK 68 +#define GCC_PCIE_1_AUX_CLK_SRC 69 +#define GCC_PCIE_1_CFG_AHB_CLK 70 +#define GCC_PCIE_1_MSTR_AXI_CLK 71 +#define GCC_PCIE_1_PHY_RCHNG_CLK_SRC 72 +#define GCC_PCIE_1_PIPE_CLK 73 +#define GCC_PCIE_1_SLV_AXI_CLK 74 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 75 +#define GCC_PCIE_2_AUX_CLK 76 +#define GCC_PCIE_2_AUX_CLK_SRC 77 +#define GCC_PCIE_2_CFG_AHB_CLK 78 +#define GCC_PCIE_2_MSTR_AXI_CLK 79 +#define GCC_PCIE_2_PHY_RCHNG_CLK_SRC 80 +#define GCC_PCIE_2_PIPE_CLK 81 +#define GCC_PCIE_2_SLV_AXI_CLK 82 +#define GCC_PCIE_2_SLV_Q2A_AXI_CLK 83 +#define GCC_PCIE_3_AUX_CLK 84 +#define GCC_PCIE_3_AUX_CLK_SRC 85 +#define GCC_PCIE_3_CFG_AHB_CLK 86 +#define GCC_PCIE_3_MSTR_AXI_CLK 87 +#define GCC_PCIE_3_PHY_AUX_CLK 88 +#define GCC_PCIE_3_PHY_RCHNG_CLK 89 +#define GCC_PCIE_3_PHY_RCHNG_CLK_SRC 90 +#define GCC_PCIE_3_PIPE_CLK 91 +#define GCC_PCIE_3_PIPE_DIV_CLK_SRC 92 +#define GCC_PCIE_3_PIPEDIV2_CLK 93 +#define GCC_PCIE_3_SLV_AXI_CLK 94 +#define GCC_PCIE_3_SLV_Q2A_AXI_CLK 95 +#define GCC_PCIE_4_AUX_CLK 96 +#define GCC_PCIE_4_AUX_CLK_SRC 97 +#define GCC_PCIE_4_CFG_AHB_CLK 98 +#define GCC_PCIE_4_MSTR_AXI_CLK 99 +#define GCC_PCIE_4_PHY_RCHNG_CLK 100 +#define GCC_PCIE_4_PHY_RCHNG_CLK_SRC 101 +#define GCC_PCIE_4_PIPE_CLK 102 +#define GCC_PCIE_4_PIPE_DIV_CLK_SRC 103 +#define GCC_PCIE_4_PIPEDIV2_CLK 104 +#define GCC_PCIE_4_SLV_AXI_CLK 105 +#define GCC_PCIE_4_SLV_Q2A_AXI_CLK 106 +#define GCC_PCIE_5_AUX_CLK 107 +#define GCC_PCIE_5_AUX_CLK_SRC 108 +#define GCC_PCIE_5_CFG_AHB_CLK 109 +#define GCC_PCIE_5_MSTR_AXI_CLK 110 +#define GCC_PCIE_5_PHY_RCHNG_CLK 111 +#define GCC_PCIE_5_PHY_RCHNG_CLK_SRC 112 +#define GCC_PCIE_5_PIPE_CLK 113 +#define GCC_PCIE_5_PIPE_DIV_CLK_SRC 114 +#define GCC_PCIE_5_PIPEDIV2_CLK 115 +#define GCC_PCIE_5_SLV_AXI_CLK 116 +#define GCC_PCIE_5_SLV_Q2A_AXI_CLK 117 +#define GCC_PCIE_6A_AUX_CLK 118 +#define GCC_PCIE_6A_AUX_CLK_SRC 119 +#define GCC_PCIE_6A_CFG_AHB_CLK 120 +#define GCC_PCIE_6A_MSTR_AXI_CLK 121 +#define GCC_PCIE_6A_PHY_AUX_CLK 122 +#define GCC_PCIE_6A_PHY_RCHNG_CLK 123 +#define GCC_PCIE_6A_PHY_RCHNG_CLK_SRC 124 +#define GCC_PCIE_6A_PIPE_CLK 125 +#define GCC_PCIE_6A_PIPE_DIV_CLK_SRC 126 +#define GCC_PCIE_6A_PIPEDIV2_CLK 127 +#define GCC_PCIE_6A_SLV_AXI_CLK 128 +#define GCC_PCIE_6A_SLV_Q2A_AXI_CLK 129 +#define GCC_PCIE_6B_AUX_CLK 130 +#define GCC_PCIE_6B_AUX_CLK_SRC 131 +#define GCC_PCIE_6B_CFG_AHB_CLK 132 +#define GCC_PCIE_6B_MSTR_AXI_CLK 133 +#define GCC_PCIE_6B_PHY_AUX_CLK 134 +#define GCC_PCIE_6B_PHY_RCHNG_CLK 135 +#define GCC_PCIE_6B_PHY_RCHNG_CLK_SRC 136 +#define GCC_PCIE_6B_PIPE_CLK 137 +#define GCC_PCIE_6B_PIPE_DIV_CLK_SRC 138 +#define GCC_PCIE_6B_PIPEDIV2_CLK 139 +#define GCC_PCIE_6B_SLV_AXI_CLK 140 +#define GCC_PCIE_6B_SLV_Q2A_AXI_CLK 141 +#define GCC_PCIE_RSCC_AHB_CLK 142 +#define GCC_PCIE_RSCC_XO_CLK 143 +#define GCC_PCIE_RSCC_XO_CLK_SRC 144 +#define GCC_PDM2_CLK 145 +#define GCC_PDM2_CLK_SRC 146 +#define GCC_PDM_AHB_CLK 147 +#define GCC_PDM_XO4_CLK 148 +#define GCC_QMIP_AV1E_AHB_CLK 149 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 150 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 151 +#define GCC_QMIP_DISP_AHB_CLK 152 +#define GCC_QMIP_GPU_AHB_CLK 153 +#define GCC_QMIP_VIDEO_CV_CPU_AHB_CLK 154 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 155 +#define GCC_QMIP_VIDEO_V_CPU_AHB_CLK 156 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 157 +#define GCC_QUPV3_WRAP0_CORE_2X_CLK 158 +#define GCC_QUPV3_WRAP0_CORE_CLK 159 +#define GCC_QUPV3_WRAP0_QSPI_S2_CLK 160 +#define GCC_QUPV3_WRAP0_QSPI_S3_CLK 161 +#define GCC_QUPV3_WRAP0_S0_CLK 162 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 163 +#define GCC_QUPV3_WRAP0_S1_CLK 164 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 165 +#define GCC_QUPV3_WRAP0_S2_CLK 166 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 167 +#define GCC_QUPV3_WRAP0_S2_DIV_CLK_SRC 168 +#define GCC_QUPV3_WRAP0_S3_CLK 169 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 170 +#define GCC_QUPV3_WRAP0_S3_DIV_CLK_SRC 171 +#define GCC_QUPV3_WRAP0_S4_CLK 172 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 173 +#define GCC_QUPV3_WRAP0_S5_CLK 174 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 175 +#define GCC_QUPV3_WRAP0_S6_CLK 176 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 177 +#define GCC_QUPV3_WRAP0_S7_CLK 178 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 179 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 180 +#define GCC_QUPV3_WRAP1_CORE_CLK 181 +#define GCC_QUPV3_WRAP1_QSPI_S2_CLK 182 +#define GCC_QUPV3_WRAP1_QSPI_S3_CLK 183 +#define GCC_QUPV3_WRAP1_S0_CLK 184 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 185 +#define GCC_QUPV3_WRAP1_S1_CLK 186 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 187 +#define GCC_QUPV3_WRAP1_S2_CLK 188 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 189 +#define GCC_QUPV3_WRAP1_S2_DIV_CLK_SRC 190 +#define GCC_QUPV3_WRAP1_S3_CLK 191 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 192 +#define GCC_QUPV3_WRAP1_S3_DIV_CLK_SRC 193 +#define GCC_QUPV3_WRAP1_S4_CLK 194 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 195 +#define GCC_QUPV3_WRAP1_S5_CLK 196 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 197 +#define GCC_QUPV3_WRAP1_S6_CLK 198 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 199 +#define GCC_QUPV3_WRAP1_S7_CLK 200 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 201 +#define GCC_QUPV3_WRAP2_CORE_2X_CLK 202 +#define GCC_QUPV3_WRAP2_CORE_CLK 203 +#define GCC_QUPV3_WRAP2_QSPI_S2_CLK 204 +#define GCC_QUPV3_WRAP2_QSPI_S3_CLK 205 +#define GCC_QUPV3_WRAP2_S0_CLK 206 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 207 +#define GCC_QUPV3_WRAP2_S1_CLK 208 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 209 +#define GCC_QUPV3_WRAP2_S2_CLK 210 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 211 +#define GCC_QUPV3_WRAP2_S2_DIV_CLK_SRC 212 +#define GCC_QUPV3_WRAP2_S3_CLK 213 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 214 +#define GCC_QUPV3_WRAP2_S3_DIV_CLK_SRC 215 +#define GCC_QUPV3_WRAP2_S4_CLK 216 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 217 +#define GCC_QUPV3_WRAP2_S5_CLK 218 +#define GCC_QUPV3_WRAP2_S5_CLK_SRC 219 +#define GCC_QUPV3_WRAP2_S6_CLK 220 +#define GCC_QUPV3_WRAP2_S6_CLK_SRC 221 +#define GCC_QUPV3_WRAP2_S7_CLK 222 +#define GCC_QUPV3_WRAP2_S7_CLK_SRC 223 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 224 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 225 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 226 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 227 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 228 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 229 +#define GCC_SDCC2_AHB_CLK 230 +#define GCC_SDCC2_APPS_CLK 231 +#define GCC_SDCC2_APPS_CLK_SRC 232 +#define GCC_SDCC4_AHB_CLK 233 +#define GCC_SDCC4_APPS_CLK 234 +#define GCC_SDCC4_APPS_CLK_SRC 235 +#define GCC_SYS_NOC_USB_AXI_CLK 236 +#define GCC_UFS_PHY_AHB_CLK 237 +#define GCC_UFS_PHY_AXI_CLK 238 +#define GCC_UFS_PHY_AXI_CLK_SRC 239 +#define GCC_UFS_PHY_ICE_CORE_CLK 240 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 241 +#define GCC_UFS_PHY_PHY_AUX_CLK 242 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 243 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 244 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 245 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 246 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 247 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 248 +#define GCC_USB20_MASTER_CLK 249 +#define GCC_USB20_MASTER_CLK_SRC 250 +#define GCC_USB20_MOCK_UTMI_CLK 251 +#define GCC_USB20_MOCK_UTMI_CLK_SRC 252 +#define GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC 253 +#define GCC_USB20_SLEEP_CLK 254 +#define GCC_USB30_MP_MASTER_CLK 255 +#define GCC_USB30_MP_MASTER_CLK_SRC 256 +#define GCC_USB30_MP_MOCK_UTMI_CLK 257 +#define GCC_USB30_MP_MOCK_UTMI_CLK_SRC 258 +#define GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC 259 +#define GCC_USB30_MP_SLEEP_CLK 260 +#define GCC_USB30_PRIM_MASTER_CLK 261 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 262 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 263 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 264 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 265 +#define GCC_USB30_PRIM_SLEEP_CLK 266 +#define GCC_USB30_SEC_MASTER_CLK 267 +#define GCC_USB30_SEC_MASTER_CLK_SRC 268 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 269 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 270 +#define GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC 271 +#define GCC_USB30_SEC_SLEEP_CLK 272 +#define GCC_USB30_TERT_MASTER_CLK 273 +#define GCC_USB30_TERT_MASTER_CLK_SRC 274 +#define GCC_USB30_TERT_MOCK_UTMI_CLK 275 +#define GCC_USB30_TERT_MOCK_UTMI_CLK_SRC 276 +#define GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC 277 +#define GCC_USB30_TERT_SLEEP_CLK 278 +#define GCC_USB3_MP_PHY_AUX_CLK 279 +#define GCC_USB3_MP_PHY_AUX_CLK_SRC 280 +#define GCC_USB3_MP_PHY_COM_AUX_CLK 281 +#define GCC_USB3_MP_PHY_PIPE_0_CLK 282 +#define GCC_USB3_MP_PHY_PIPE_1_CLK 283 +#define GCC_USB3_PRIM_PHY_AUX_CLK 284 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 285 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 286 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 287 +#define GCC_USB3_SEC_PHY_AUX_CLK 288 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 289 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 290 +#define GCC_USB3_SEC_PHY_PIPE_CLK 291 +#define GCC_USB3_TERT_PHY_AUX_CLK 292 +#define GCC_USB3_TERT_PHY_AUX_CLK_SRC 293 +#define GCC_USB3_TERT_PHY_COM_AUX_CLK 294 +#define GCC_USB3_TERT_PHY_PIPE_CLK 295 +#define GCC_USB4_0_CFG_AHB_CLK 296 +#define GCC_USB4_0_DP0_CLK 297 +#define GCC_USB4_0_DP1_CLK 298 +#define GCC_USB4_0_MASTER_CLK 299 +#define GCC_USB4_0_MASTER_CLK_SRC 300 +#define GCC_USB4_0_PHY_P2RR2P_PIPE_CLK 301 +#define GCC_USB4_0_PHY_PCIE_PIPE_CLK 302 +#define GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC 303 +#define GCC_USB4_0_PHY_RX0_CLK 304 +#define GCC_USB4_0_PHY_RX1_CLK 305 +#define GCC_USB4_0_PHY_USB_PIPE_CLK 306 +#define GCC_USB4_0_SB_IF_CLK 307 +#define GCC_USB4_0_SB_IF_CLK_SRC 308 +#define GCC_USB4_0_SYS_CLK 309 +#define GCC_USB4_0_TMU_CLK 310 +#define GCC_USB4_0_TMU_CLK_SRC 311 +#define GCC_USB4_1_CFG_AHB_CLK 312 +#define GCC_USB4_1_DP0_CLK 313 +#define GCC_USB4_1_DP1_CLK 314 +#define GCC_USB4_1_MASTER_CLK 315 +#define GCC_USB4_1_MASTER_CLK_SRC 316 +#define GCC_USB4_1_PHY_P2RR2P_PIPE_CLK 317 +#define GCC_USB4_1_PHY_PCIE_PIPE_CLK 318 +#define GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC 319 +#define GCC_USB4_1_PHY_RX0_CLK 320 +#define GCC_USB4_1_PHY_RX1_CLK 321 +#define GCC_USB4_1_PHY_USB_PIPE_CLK 322 +#define GCC_USB4_1_SB_IF_CLK 323 +#define GCC_USB4_1_SB_IF_CLK_SRC 324 +#define GCC_USB4_1_SYS_CLK 325 +#define GCC_USB4_1_TMU_CLK 326 +#define GCC_USB4_1_TMU_CLK_SRC 327 +#define GCC_USB4_2_CFG_AHB_CLK 328 +#define GCC_USB4_2_DP0_CLK 329 +#define GCC_USB4_2_DP1_CLK 330 +#define GCC_USB4_2_MASTER_CLK 331 +#define GCC_USB4_2_MASTER_CLK_SRC 332 +#define GCC_USB4_2_PHY_P2RR2P_PIPE_CLK 333 +#define GCC_USB4_2_PHY_PCIE_PIPE_CLK 334 +#define GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC 335 +#define GCC_USB4_2_PHY_RX0_CLK 336 +#define GCC_USB4_2_PHY_RX1_CLK 337 +#define GCC_USB4_2_PHY_USB_PIPE_CLK 338 +#define GCC_USB4_2_SB_IF_CLK 339 +#define GCC_USB4_2_SB_IF_CLK_SRC 340 +#define GCC_USB4_2_SYS_CLK 341 +#define GCC_USB4_2_TMU_CLK 342 +#define GCC_USB4_2_TMU_CLK_SRC 343 +#define GCC_VIDEO_AHB_CLK 344 +#define GCC_VIDEO_AXI0_CLK 345 +#define GCC_VIDEO_AXI1_CLK 346 +#define GCC_VIDEO_XO_CLK 347 +#define GCC_PCIE_3_PIPE_CLK_SRC 348 +#define GCC_PCIE_4_PIPE_CLK_SRC 349 +#define GCC_PCIE_5_PIPE_CLK_SRC 350 +#define GCC_PCIE_6A_PIPE_CLK_SRC 351 +#define GCC_PCIE_6B_PIPE_CLK_SRC 352 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 353 +#define GCC_USB3_SEC_PHY_PIPE_CLK_SRC 354 +#define GCC_USB3_TERT_PHY_PIPE_CLK_SRC 355 + +/* GCC power domains */ +#define GCC_PCIE_0_TUNNEL_GDSC 0 +#define GCC_PCIE_1_TUNNEL_GDSC 1 +#define GCC_PCIE_2_TUNNEL_GDSC 2 +#define GCC_PCIE_3_GDSC 3 +#define GCC_PCIE_3_PHY_GDSC 4 +#define GCC_PCIE_4_GDSC 5 +#define GCC_PCIE_4_PHY_GDSC 6 +#define GCC_PCIE_5_GDSC 7 +#define GCC_PCIE_5_PHY_GDSC 8 +#define GCC_PCIE_6_PHY_GDSC 9 +#define GCC_PCIE_6A_GDSC 10 +#define GCC_PCIE_6B_GDSC 11 +#define GCC_UFS_MEM_PHY_GDSC 12 +#define GCC_UFS_PHY_GDSC 13 +#define GCC_USB20_PRIM_GDSC 14 +#define GCC_USB30_MP_GDSC 15 +#define GCC_USB30_PRIM_GDSC 16 +#define GCC_USB30_SEC_GDSC 17 +#define GCC_USB30_TERT_GDSC 18 +#define GCC_USB3_MP_SS0_PHY_GDSC 19 +#define GCC_USB3_MP_SS1_PHY_GDSC 20 +#define GCC_USB4_0_GDSC 21 +#define GCC_USB4_1_GDSC 22 +#define GCC_USB4_2_GDSC 23 +#define GCC_USB_0_PHY_GDSC 24 +#define GCC_USB_1_PHY_GDSC 25 +#define GCC_USB_2_PHY_GDSC 26 + +/* GCC resets */ +#define GCC_AV1E_BCR 0 +#define GCC_CAMERA_BCR 1 +#define GCC_DISPLAY_BCR 2 +#define GCC_GPU_BCR 3 +#define GCC_PCIE_0_LINK_DOWN_BCR 4 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 5 +#define GCC_PCIE_0_PHY_BCR 6 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 7 +#define GCC_PCIE_0_TUNNEL_BCR 8 +#define GCC_PCIE_1_LINK_DOWN_BCR 9 +#define GCC_PCIE_1_NOCSR_COM_PHY_BCR 10 +#define GCC_PCIE_1_PHY_BCR 11 +#define GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR 12 +#define GCC_PCIE_1_TUNNEL_BCR 13 +#define GCC_PCIE_2_LINK_DOWN_BCR 14 +#define GCC_PCIE_2_NOCSR_COM_PHY_BCR 15 +#define GCC_PCIE_2_PHY_BCR 16 +#define GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR 17 +#define GCC_PCIE_2_TUNNEL_BCR 18 +#define GCC_PCIE_3_BCR 19 +#define GCC_PCIE_3_LINK_DOWN_BCR 20 +#define GCC_PCIE_3_NOCSR_COM_PHY_BCR 21 +#define GCC_PCIE_3_PHY_BCR 22 +#define GCC_PCIE_3_PHY_NOCSR_COM_PHY_BCR 23 +#define GCC_PCIE_4_BCR 24 +#define GCC_PCIE_4_LINK_DOWN_BCR 25 +#define GCC_PCIE_4_NOCSR_COM_PHY_BCR 26 +#define GCC_PCIE_4_PHY_BCR 27 +#define GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR 28 +#define GCC_PCIE_5_BCR 29 +#define GCC_PCIE_5_LINK_DOWN_BCR 30 +#define GCC_PCIE_5_NOCSR_COM_PHY_BCR 31 +#define GCC_PCIE_5_PHY_BCR 32 +#define GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR 33 +#define GCC_PCIE_6A_BCR 34 +#define GCC_PCIE_6A_LINK_DOWN_BCR 35 +#define GCC_PCIE_6A_NOCSR_COM_PHY_BCR 36 +#define GCC_PCIE_6A_PHY_BCR 37 +#define GCC_PCIE_6A_PHY_NOCSR_COM_PHY_BCR 38 +#define GCC_PCIE_6B_BCR 39 +#define GCC_PCIE_6B_LINK_DOWN_BCR 40 +#define GCC_PCIE_6B_NOCSR_COM_PHY_BCR 41 +#define GCC_PCIE_6B_PHY_BCR 42 +#define GCC_PCIE_6B_PHY_NOCSR_COM_PHY_BCR 43 +#define GCC_PCIE_PHY_BCR 44 +#define GCC_PCIE_PHY_CFG_AHB_BCR 45 +#define GCC_PCIE_PHY_COM_BCR 46 +#define GCC_PCIE_RSCC_BCR 47 +#define GCC_PDM_BCR 48 +#define GCC_QUPV3_WRAPPER_0_BCR 49 +#define GCC_QUPV3_WRAPPER_1_BCR 50 +#define GCC_QUPV3_WRAPPER_2_BCR 51 +#define GCC_QUSB2PHY_HS0_MP_BCR 52 +#define GCC_QUSB2PHY_HS1_MP_BCR 53 +#define GCC_QUSB2PHY_PRIM_BCR 54 +#define GCC_QUSB2PHY_SEC_BCR 55 +#define GCC_QUSB2PHY_TERT_BCR 56 +#define GCC_QUSB2PHY_USB20_HS_BCR 57 +#define GCC_SDCC2_BCR 58 +#define GCC_SDCC4_BCR 59 +#define GCC_UFS_PHY_BCR 60 +#define GCC_USB20_PRIM_BCR 61 +#define GCC_USB30_MP_BCR 62 +#define GCC_USB30_PRIM_BCR 63 +#define GCC_USB30_SEC_BCR 64 +#define GCC_USB30_TERT_BCR 65 +#define GCC_USB3_MP_SS0_PHY_BCR 66 +#define GCC_USB3_MP_SS1_PHY_BCR 67 +#define GCC_USB3_PHY_PRIM_BCR 68 +#define GCC_USB3_PHY_SEC_BCR 69 +#define GCC_USB3_PHY_TERT_BCR 70 +#define GCC_USB3_UNIPHY_MP0_BCR 71 +#define GCC_USB3_UNIPHY_MP1_BCR 72 +#define GCC_USB3PHY_PHY_PRIM_BCR 73 +#define GCC_USB3PHY_PHY_SEC_BCR 74 +#define GCC_USB3PHY_PHY_TERT_BCR 75 +#define GCC_USB3UNIPHY_PHY_MP0_BCR 76 +#define GCC_USB3UNIPHY_PHY_MP1_BCR 77 +#define GCC_USB4_0_BCR 78 +#define GCC_USB4_0_DP0_PHY_PRIM_BCR 79 +#define GCC_USB4_1_DP0_PHY_SEC_BCR 80 +#define GCC_USB4_2_DP0_PHY_TERT_BCR 81 +#define GCC_USB4_1_BCR 82 +#define GCC_USB4_2_BCR 83 +#define GCC_USB_0_PHY_BCR 84 +#define GCC_USB_1_PHY_BCR 85 +#define GCC_USB_2_PHY_BCR 86 +#define GCC_VIDEO_BCR 87 +#endif From 4c413512ed2d06077e93127e81780c25113d4269 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:40:01 +0530 Subject: [PATCH 3320/7721] dt-bindings: clock: qcom-rpmhcc: Add RPMHCC bindings for X1E80100 Add bindings and update documentation for clock rpmh driver on X1E80100 SoCs. Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231205061002.30759-4-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index 4eb5e59f6772..603da187d62e 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -35,6 +35,7 @@ properties: - qcom,sm8350-rpmh-clk - qcom,sm8450-rpmh-clk - qcom,sm8550-rpmh-clk + - qcom,x1e80100-rpmh-clk clocks: maxItems: 1 From 161b7c401f4bd3e9ebd351f482139d8736be990c Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:40:00 +0530 Subject: [PATCH 3321/7721] clk: qcom: Add Global Clock controller (GCC) driver for X1E80100 Add support for the global clock controller found on X1E80100 based devices. Co-developed-by: Abel Vesa Signed-off-by: Abel Vesa Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20231205061002.30759-3-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-x1e80100.c | 6807 +++++++++++++++++++++++++++++++ 3 files changed, 6818 insertions(+) create mode 100644 drivers/clk/qcom/gcc-x1e80100.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 7a0b5c483f09..7cc3da145a93 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -20,6 +20,16 @@ menuconfig COMMON_CLK_QCOM if COMMON_CLK_QCOM +config CLK_X1E80100_GCC + tristate "X1E80100 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on Qualcomm Technologies, Inc + X1E80100 devices. + Say Y if you want to use peripheral devices such as UART, SPI, I2C, + USB, UFS, SD/eMMC, PCIe, etc. + config QCOM_A53PLL tristate "MSM8916 A53 PLL" help diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index fe9a5db24edd..582e06dc1d93 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -21,6 +21,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o +obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c new file mode 100644 index 000000000000..74db7fef237b --- /dev/null +++ b/drivers/clk/qcom/gcc-x1e80100.c @@ -0,0 +1,6807 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + DT_PCIE_3_PIPE, + DT_PCIE_4_PIPE, + DT_PCIE_5_PIPE, + DT_PCIE_6A_PIPE, + DT_PCIE_6B_PIPE, + DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE, + DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE, + DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL8_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_SLEEP_CLK, + P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll8 = { + .offset = 0x8000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll8", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL8_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll8.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_9[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0xa0180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0xa0054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x2c180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x2c054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_aux_clk_src = { + .cmd_rcgr = 0x13180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_phy_rchng_clk_src = { + .cmd_rcgr = 0x13054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3_aux_clk_src = { + .cmd_rcgr = 0x5808c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3_phy_rchng_clk_src = { + .cmd_rcgr = 0x58070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_aux_clk_src = { + .cmd_rcgr = 0x6b080, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_phy_rchng_clk_src = { + .cmd_rcgr = 0x6b064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_aux_clk_src = { + .cmd_rcgr = 0x2f080, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_phy_rchng_clk_src = { + .cmd_rcgr = 0x2f064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6a_aux_clk_src = { + .cmd_rcgr = 0x3108c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6a_phy_rchng_clk_src = { + .cmd_rcgr = 0x31070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6b_aux_clk_src = { + .cmd_rcgr = 0x8d08c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6b_phy_rchng_clk_src = { + .cmd_rcgr = 0x8d070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_rscc_xo_clk_src = { + .cmd_rcgr = 0xa400c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_xo_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x42010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x42148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x42288, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x423c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s4_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x42500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { + .name = "gcc_qupv3_wrap0_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x42638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = { + .name = "gcc_qupv3_wrap0_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { + .cmd_rcgr = 0x42770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = { + .name = "gcc_qupv3_wrap0_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x428a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x18288, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x183c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x18500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x188a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { + .name = "gcc_qupv3_wrap2_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = { + .name = "gcc_qupv3_wrap2_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e288, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = { + .name = "gcc_qupv3_wrap2_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { + .name = "gcc_qupv3_wrap2_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = { + .name = "gcc_qupv3_wrap2_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0x1e638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = { + .name = "gcc_qupv3_wrap2_s6_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { + .cmd_rcgr = 0x1e770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { + .name = "gcc_qupv3_wrap2_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { + .cmd_rcgr = 0x1e8a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x14018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x16018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77030, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770b4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb20_master_clk_src = { + .cmd_rcgr = 0x2902c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb20_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = { + .cmd_rcgr = 0x29158, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mp_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_mp_master_clk_src = { + .cmd_rcgr = 0x1702c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_mp_mock_utmi_clk_src = { + .cmd_rcgr = 0x17158, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x3902c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x39044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_master_clk_src = { + .cmd_rcgr = 0xa102c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { + .cmd_rcgr = 0xa1044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_master_clk_src = { + .cmd_rcgr = 0xa202c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_mock_utmi_clk_src = { + .cmd_rcgr = 0xa2044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_mp_phy_aux_clk_src = { + .cmd_rcgr = 0x172a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x39074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { + .cmd_rcgr = 0xa1074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_tert_phy_aux_clk_src = { + .cmd_rcgr = 0xa2074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_master_clk_src[] = { + F(85714286, P_GCC_GPLL0_OUT_EVEN, 3.5, 0, 0), + F(175000000, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0), + F(350000000, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_master_clk_src = { + .cmd_rcgr = 0x9f024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x9f0e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_0_sb_if_clk_src = { + .cmd_rcgr = 0x9f08c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_tmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_tmu_clk_src = { + .cmd_rcgr = 0x9f070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_master_clk_src = { + .cmd_rcgr = 0x2b024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x2b0e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_sb_if_clk_src = { + .cmd_rcgr = 0x2b08c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_tmu_clk_src = { + .cmd_rcgr = 0x2b070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_master_clk_src = { + .cmd_rcgr = 0x11024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x110e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_sb_if_clk_src = { + .cmd_rcgr = 0x1108c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_tmu_clk_src = { + .cmd_rcgr = 0x11070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_3_pipe_clk_src = { + .reg = 0x58088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_3_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_3_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_3_pipe_div_clk_src = { + .reg = 0x5806c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_4_pipe_clk_src = { + .reg = 0x6b07c, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_4_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_4_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_4_pipe_div_clk_src = { + .reg = 0x6b060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_5_pipe_clk_src = { + .reg = 0x2f07c, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_5_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_5_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_5_pipe_div_clk_src = { + .reg = 0x2f060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_6a_pipe_clk_src = { + .reg = 0x31088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_6a_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_6A_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_6a_pipe_div_clk_src = { + .reg = 0x3106c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_6b_pipe_clk_src = { + .reg = 0x8d088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_6b_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_6B_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_6b_pipe_div_clk_src = { + .reg = 0x8d06c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s2_div_clk_src = { + .reg = 0x42284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s3_div_clk_src = { + .reg = 0x423c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s2_div_clk_src = { + .reg = 0x18284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s3_div_clk_src = { + .reg = 0x183c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap2_s2_div_clk_src = { + .reg = 0x1e284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap2_s3_div_clk_src = { + .reg = 0x1e3c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = { + .reg = 0x29284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_mp_mock_utmi_postdiv_clk_src = { + .reg = 0x17284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x3905c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_sec_mock_utmi_postdiv_clk_src = { + .reg = 0xa105c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_tert_mock_utmi_postdiv_clk_src = { + .reg = 0xa205c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_usb_north_axi_clk = { + .halt_reg = 0x2d17c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d17c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d17c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_usb_north_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_usb_south_axi_clk = { + .halt_reg = 0x2d174, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d174, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d174, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_usb_south_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb2_prim_axi_clk = { + .halt_reg = 0x2928c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2928c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2928c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_mp_axi_clk = { + .halt_reg = 0x173d0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x173d0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x173d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x39090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_sec_axi_clk = { + .halt_reg = 0xa1090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa1090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa1090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_sec_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_tert_axi_clk = { + .halt_reg = 0xa2090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa2090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa2090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_0_axi_clk = { + .halt_reg = 0x9f118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_0_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_1_axi_clk = { + .halt_reg = 0x2b118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_1_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_2_axi_clk = { + .halt_reg = 0x11118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x11118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x11118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_2_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb_noc_axi_clk = { + .halt_reg = 0x2d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb_noc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_ahb_clk = { + .halt_reg = 0x4a004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4a004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_axi_clk = { + .halt_reg = 0x4a008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x4a008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_xo_clk = { + .halt_reg = 0x4a014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4a014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0x26010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0x2601c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2601c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2601c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x10028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_north_ahb_clk = { + .halt_reg = 0x1002c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1002c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_north_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_south_ahb_clk = { + .halt_reg = 0x10030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = { + .halt_reg = 0x29288, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x29288, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x29288, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_mp_axi_clk = { + .halt_reg = 0x173cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x173cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x173cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x3908c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3908c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3908c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = { + .halt_reg = 0xa108c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa108c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa108c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_sec_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_tert_axi_clk = { + .halt_reg = 0xa208c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa208c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa208c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_ahb_clk = { + .halt_reg = 0x2d024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_north_ahb_clk = { + .halt_reg = 0x2d028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_north_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_south_ahb_clk = { + .halt_reg = 0x2d02c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie1_tunnel_clk = { + .halt_reg = 0x2c2b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie1_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie2_tunnel_clk = { + .halt_reg = 0x132b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie2_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_north_sf_axi_clk = { + .halt_reg = 0x10014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_north_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_south_sf_axi_clk = { + .halt_reg = 0x10018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_south_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_tunnel_clk = { + .halt_reg = 0xa02b4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa02b4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x7115c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7115c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7115c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2700c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2700c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_xo_clk = { + .halt_reg = 0x27018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x27018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_cfg_ahb_clk = { + .halt_reg = 0x71004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_cph_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_cph_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_cph_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_cph_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_phy_rchng_clk = { + .halt_reg = 0xa0050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_phy_rchng_clk = { + .halt_reg = 0x2c050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_phy_rchng_clk = { + .halt_reg = 0x13050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0xa0038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0xa0034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa0034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0xa0028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xa0028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0xa0044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0xa001c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa001c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0xa0018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x2c038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0x2c034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2c034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0x2c028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2c028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x2c044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x2c01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2c01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0x2c018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_aux_clk = { + .halt_reg = 0x13038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { + .halt_reg = 0x13034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x13034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_mstr_axi_clk = { + .halt_reg = 0x13028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x13028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_pipe_clk = { + .halt_reg = 0x13044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_axi_clk = { + .halt_reg = 0x1301c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1301c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_q2a_axi_clk = { + .halt_reg = 0x13018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_aux_clk = { + .halt_reg = 0x58038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_cfg_ahb_clk = { + .halt_reg = 0x58034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x58034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_mstr_axi_clk = { + .halt_reg = 0x58028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x58028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_phy_aux_clk = { + .halt_reg = 0x58044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_phy_rchng_clk = { + .halt_reg = 0x5805c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_pipe_clk = { + .halt_reg = 0x58050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_pipediv2_clk = { + .halt_reg = 0x58060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_slv_axi_clk = { + .halt_reg = 0x5801c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x5801c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_slv_q2a_axi_clk = { + .halt_reg = 0x58018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_aux_clk = { + .halt_reg = 0x6b038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_cfg_ahb_clk = { + .halt_reg = 0x6b034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_mstr_axi_clk = { + .halt_reg = 0x6b028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x6b028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_phy_rchng_clk = { + .halt_reg = 0x6b050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipe_clk = { + .halt_reg = 0x6b044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipediv2_clk = { + .halt_reg = 0x6b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_axi_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_q2a_axi_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_aux_clk = { + .halt_reg = 0x2f038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_cfg_ahb_clk = { + .halt_reg = 0x2f034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2f034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_mstr_axi_clk = { + .halt_reg = 0x2f028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2f028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_phy_rchng_clk = { + .halt_reg = 0x2f050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipe_clk = { + .halt_reg = 0x2f044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipediv2_clk = { + .halt_reg = 0x2f054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_axi_clk = { + .halt_reg = 0x2f01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2f01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_q2a_axi_clk = { + .halt_reg = 0x2f018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_aux_clk = { + .halt_reg = 0x31038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_cfg_ahb_clk = { + .halt_reg = 0x31034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x31034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_mstr_axi_clk = { + .halt_reg = 0x31028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x31028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_phy_aux_clk = { + .halt_reg = 0x31044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_phy_rchng_clk = { + .halt_reg = 0x3105c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_pipe_clk = { + .halt_reg = 0x31050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_pipediv2_clk = { + .halt_reg = 0x31060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_slv_axi_clk = { + .halt_reg = 0x3101c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3101c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_slv_q2a_axi_clk = { + .halt_reg = 0x31018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_aux_clk = { + .halt_reg = 0x8d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_cfg_ahb_clk = { + .halt_reg = 0x8d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_mstr_axi_clk = { + .halt_reg = 0x8d028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x8d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_phy_aux_clk = { + .halt_reg = 0x8d044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_phy_rchng_clk = { + .halt_reg = 0x8d05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_pipe_clk = { + .halt_reg = 0x8d050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_pipediv2_clk = { + .halt_reg = 0x8d060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_slv_axi_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_slv_q2a_axi_clk = { + .halt_reg = 0x8d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_ahb_clk = { + .halt_reg = 0xa4008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa4008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_xo_clk = { + .halt_reg = 0xa4004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_rscc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_av1e_ahb_clk = { + .halt_reg = 0x4a018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4a018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_ahb_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x32008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x23018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_clk = { + .halt_reg = 0x23008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_qspi_s2_clk = { + .halt_reg = 0x42280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_qspi_s3_clk = { + .halt_reg = 0x423c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s0_clk = { + .halt_reg = 0x42004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s1_clk = { + .halt_reg = 0x4213c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s2_clk = { + .halt_reg = 0x42274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s3_clk = { + .halt_reg = 0x423b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s4_clk = { + .halt_reg = 0x424f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s5_clk = { + .halt_reg = 0x4262c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s6_clk = { + .halt_reg = 0x42764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s7_clk = { + .halt_reg = 0x4289c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x23168, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x23158, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_s2_clk = { + .halt_reg = 0x18280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_s3_clk = { + .halt_reg = 0x183c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x1813c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x18274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x183b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x184f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0x1862c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s6_clk = { + .halt_reg = 0x18764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s7_clk = { + .halt_reg = 0x1889c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = { + .halt_reg = 0x232b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_clk = { + .halt_reg = 0x232a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_qspi_s2_clk = { + .halt_reg = 0x1e280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_qspi_s3_clk = { + .halt_reg = 0x1e3c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s1_clk = { + .halt_reg = 0x1e13c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s2_clk = { + .halt_reg = 0x1e274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s3_clk = { + .halt_reg = 0x1e3b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s4_clk = { + .halt_reg = 0x1e4f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s5_clk = { + .halt_reg = 0x1e62c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s6_clk = { + .halt_reg = 0x1e764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s7_clk = { + .halt_reg = 0x1e89c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { + .halt_reg = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { + .halt_reg = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0x23150, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23150, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x23154, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0x232a0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x232a0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = { + .halt_reg = 0x232a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x232a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb_axi_clk = { + .halt_reg = 0x2d014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sys_noc_usb_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x7702c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7702c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x770cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x77028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_master_clk = { + .halt_reg = 0x29018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_mock_utmi_clk = { + .halt_reg = 0x29028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_sleep_clk = { + .halt_reg = 0x29024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_master_clk = { + .halt_reg = 0x17018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_mock_utmi_clk = { + .halt_reg = 0x17028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_sleep_clk = { + .halt_reg = 0x17024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0x39024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_master_clk = { + .halt_reg = 0xa1018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_mock_utmi_clk = { + .halt_reg = 0xa1028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_sleep_clk = { + .halt_reg = 0xa1024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_master_clk = { + .halt_reg = 0xa2018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_mock_utmi_clk = { + .halt_reg = 0xa2028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_sleep_clk = { + .halt_reg = 0xa2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_aux_clk = { + .halt_reg = 0x17288, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17288, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_com_aux_clk = { + .halt_reg = 0x1728c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1728c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_0_clk = { + .halt_reg = 0x17290, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17290, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_1_clk = { + .halt_reg = 0x17298, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17298, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x39060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0x39064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x3906c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_10, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x39068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_aux_clk = { + .halt_reg = 0xa1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { + .halt_reg = 0xa1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_sec_phy_pipe_clk_src = { + .reg = 0xa106c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_11, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_pipe_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { + .halt_reg = 0xa1068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa1068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa1068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_sec_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_aux_clk = { + .halt_reg = 0xa2060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_com_aux_clk = { + .halt_reg = 0xa2064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_tert_phy_pipe_clk_src = { + .reg = 0xa206c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_12, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_tert_phy_pipe_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_pipe_clk = { + .halt_reg = 0xa2068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa2068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa2068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_cfg_ahb_clk = { + .halt_reg = 0x9f0a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f0a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f0a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp0_clk = { + .halt_reg = 0x9f060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp1_clk = { + .halt_reg = 0x9f108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_master_clk = { + .halt_reg = 0x9f018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x9f0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_pcie_pipe_clk = { + .halt_reg = 0x9f048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx0_clk = { + .halt_reg = 0x9f0b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx1_clk = { + .halt_reg = 0x9f0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_usb_pipe_clk = { + .halt_reg = 0x9f0a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f0a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f0a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sb_if_clk = { + .halt_reg = 0x9f044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sys_clk = { + .halt_reg = 0x9f054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_tmu_clk = { + .halt_reg = 0x9f088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_cfg_ahb_clk = { + .halt_reg = 0x2b0a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b0a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b0a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp0_clk = { + .halt_reg = 0x2b060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp1_clk = { + .halt_reg = 0x2b108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_master_clk = { + .halt_reg = 0x2b018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x2b0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_pcie_pipe_clk = { + .halt_reg = 0x2b048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx0_clk = { + .halt_reg = 0x2b0b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx1_clk = { + .halt_reg = 0x2b0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_usb_pipe_clk = { + .halt_reg = 0x2b0a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b0a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b0a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sb_if_clk = { + .halt_reg = 0x2b044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sys_clk = { + .halt_reg = 0x2b054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_tmu_clk = { + .halt_reg = 0x2b088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_cfg_ahb_clk = { + .halt_reg = 0x110a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x110a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x110a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp0_clk = { + .halt_reg = 0x11060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp1_clk = { + .halt_reg = 0x11108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_master_clk = { + .halt_reg = 0x11018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x110d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_pcie_pipe_clk = { + .halt_reg = 0x11048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx0_clk = { + .halt_reg = 0x110b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx1_clk = { + .halt_reg = 0x110c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_usb_pipe_clk = { + .halt_reg = 0x110a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x110a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x110a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sb_if_clk = { + .halt_reg = 0x11044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sys_clk = { + .halt_reg = 0x11054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_tmu_clk = { + .halt_reg = 0x11088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x11088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x11088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x32018, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x32024, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_pcie_0_tunnel_gdsc = { + .gdscr = 0xa0004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_0_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_1_tunnel_gdsc = { + .gdscr = 0x2c004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_1_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_2_tunnel_gdsc = { + .gdscr = 0x13004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_2_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3_gdsc = { + .gdscr = 0x58004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_3_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3_phy_gdsc = { + .gdscr = 0x3e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_gdsc = { + .gdscr = 0x6b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_4_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_phy_gdsc = { + .gdscr = 0x6c000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_4_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_gdsc = { + .gdscr = 0x2f004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_5_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_phy_gdsc = { + .gdscr = 0x30000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_5_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6_phy_gdsc = { + .gdscr = 0x8e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_6_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6a_gdsc = { + .gdscr = 0x31004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_6a_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6b_gdsc = { + .gdscr = 0x8d004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_6b_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_ufs_mem_phy_gdsc = { + .gdscr = 0x9e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x77004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb20_prim_gdsc = { + .gdscr = 0x29004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb20_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_mp_gdsc = { + .gdscr = 0x17004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_mp_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x39004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_sec_gdsc = { + .gdscr = 0xa1004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_tert_gdsc = { + .gdscr = 0xa2004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_tert_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss0_phy_gdsc = { + .gdscr = 0x1900c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss0_phy_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = { + .gdscr = 0x5400c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_0_gdsc = { + .gdscr = 0x9f004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_1_gdsc = { + .gdscr = 0x2b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_2_gdsc = { + .gdscr = 0x11004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_0_phy_gdsc = { + .gdscr = 0x50024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_1_phy_gdsc = { + .gdscr = 0x2a024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_2_phy_gdsc = { + .gdscr = 0xa3024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_2_phy_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_x1e80100_clocks[] = { + [GCC_AGGRE_NOC_USB_NORTH_AXI_CLK] = &gcc_aggre_noc_usb_north_axi_clk.clkr, + [GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK] = &gcc_aggre_noc_usb_south_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_MP_AXI_CLK] = &gcc_aggre_usb3_mp_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr, + [GCC_AGGRE_USB3_TERT_AXI_CLK] = &gcc_aggre_usb3_tert_axi_clk.clkr, + [GCC_AGGRE_USB4_0_AXI_CLK] = &gcc_aggre_usb4_0_axi_clk.clkr, + [GCC_AGGRE_USB4_1_AXI_CLK] = &gcc_aggre_usb4_1_axi_clk.clkr, + [GCC_AGGRE_USB4_2_AXI_CLK] = &gcc_aggre_usb4_2_axi_clk.clkr, + [GCC_AGGRE_USB_NOC_AXI_CLK] = &gcc_aggre_usb_noc_axi_clk.clkr, + [GCC_AV1E_AHB_CLK] = &gcc_av1e_ahb_clk.clkr, + [GCC_AV1E_AXI_CLK] = &gcc_av1e_axi_clk.clkr, + [GCC_AV1E_XO_CLK] = &gcc_av1e_xo_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_north_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_south_ahb_clk.clkr, + [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_MP_AXI_CLK] = &gcc_cfg_noc_usb3_mp_axi_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr, + [GCC_CFG_NOC_USB3_TERT_AXI_CLK] = &gcc_cfg_noc_usb3_tert_axi_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_AHB_CLK] = &gcc_cfg_noc_usb_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_north_ahb_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_south_ahb_clk.clkr, + [GCC_CNOC_PCIE1_TUNNEL_CLK] = &gcc_cnoc_pcie1_tunnel_clk.clkr, + [GCC_CNOC_PCIE2_TUNNEL_CLK] = &gcc_cnoc_pcie2_tunnel_clk.clkr, + [GCC_CNOC_PCIE_NORTH_SF_AXI_CLK] = &gcc_cnoc_pcie_north_sf_axi_clk.clkr, + [GCC_CNOC_PCIE_SOUTH_SF_AXI_CLK] = &gcc_cnoc_pcie_south_sf_axi_clk.clkr, + [GCC_CNOC_PCIE_TUNNEL_CLK] = &gcc_cnoc_pcie_tunnel_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_DISP_XO_CLK] = &gcc_disp_xo_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL8] = &gcc_gpll8.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr, + [GCC_GPU_GPLL0_CPH_CLK_SRC] = &gcc_gpu_gpll0_cph_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CPH_CLK_SRC] = &gcc_gpu_gpll0_div_cph_clk_src.clkr, + [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, + [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_PCIE0_PHY_RCHNG_CLK] = &gcc_pcie0_phy_rchng_clk.clkr, + [GCC_PCIE1_PHY_RCHNG_CLK] = &gcc_pcie1_phy_rchng_clk.clkr, + [GCC_PCIE2_PHY_RCHNG_CLK] = &gcc_pcie2_phy_rchng_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr, + [GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr, + [GCC_PCIE_2_AUX_CLK_SRC] = &gcc_pcie_2_aux_clk_src.clkr, + [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr, + [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr, + [GCC_PCIE_2_PHY_RCHNG_CLK_SRC] = &gcc_pcie_2_phy_rchng_clk_src.clkr, + [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr, + [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr, + [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = &gcc_pcie_2_slv_q2a_axi_clk.clkr, + [GCC_PCIE_3_AUX_CLK] = &gcc_pcie_3_aux_clk.clkr, + [GCC_PCIE_3_AUX_CLK_SRC] = &gcc_pcie_3_aux_clk_src.clkr, + [GCC_PCIE_3_CFG_AHB_CLK] = &gcc_pcie_3_cfg_ahb_clk.clkr, + [GCC_PCIE_3_MSTR_AXI_CLK] = &gcc_pcie_3_mstr_axi_clk.clkr, + [GCC_PCIE_3_PHY_AUX_CLK] = &gcc_pcie_3_phy_aux_clk.clkr, + [GCC_PCIE_3_PHY_RCHNG_CLK] = &gcc_pcie_3_phy_rchng_clk.clkr, + [GCC_PCIE_3_PHY_RCHNG_CLK_SRC] = &gcc_pcie_3_phy_rchng_clk_src.clkr, + [GCC_PCIE_3_PIPE_CLK] = &gcc_pcie_3_pipe_clk.clkr, + [GCC_PCIE_3_PIPE_CLK_SRC] = &gcc_pcie_3_pipe_clk_src.clkr, + [GCC_PCIE_3_PIPE_DIV_CLK_SRC] = &gcc_pcie_3_pipe_div_clk_src.clkr, + [GCC_PCIE_3_PIPEDIV2_CLK] = &gcc_pcie_3_pipediv2_clk.clkr, + [GCC_PCIE_3_SLV_AXI_CLK] = &gcc_pcie_3_slv_axi_clk.clkr, + [GCC_PCIE_3_SLV_Q2A_AXI_CLK] = &gcc_pcie_3_slv_q2a_axi_clk.clkr, + [GCC_PCIE_4_AUX_CLK] = &gcc_pcie_4_aux_clk.clkr, + [GCC_PCIE_4_AUX_CLK_SRC] = &gcc_pcie_4_aux_clk_src.clkr, + [GCC_PCIE_4_CFG_AHB_CLK] = &gcc_pcie_4_cfg_ahb_clk.clkr, + [GCC_PCIE_4_MSTR_AXI_CLK] = &gcc_pcie_4_mstr_axi_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK] = &gcc_pcie_4_phy_rchng_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK_SRC] = &gcc_pcie_4_phy_rchng_clk_src.clkr, + [GCC_PCIE_4_PIPE_CLK] = &gcc_pcie_4_pipe_clk.clkr, + [GCC_PCIE_4_PIPE_CLK_SRC] = &gcc_pcie_4_pipe_clk_src.clkr, + [GCC_PCIE_4_PIPE_DIV_CLK_SRC] = &gcc_pcie_4_pipe_div_clk_src.clkr, + [GCC_PCIE_4_PIPEDIV2_CLK] = &gcc_pcie_4_pipediv2_clk.clkr, + [GCC_PCIE_4_SLV_AXI_CLK] = &gcc_pcie_4_slv_axi_clk.clkr, + [GCC_PCIE_4_SLV_Q2A_AXI_CLK] = &gcc_pcie_4_slv_q2a_axi_clk.clkr, + [GCC_PCIE_5_AUX_CLK] = &gcc_pcie_5_aux_clk.clkr, + [GCC_PCIE_5_AUX_CLK_SRC] = &gcc_pcie_5_aux_clk_src.clkr, + [GCC_PCIE_5_CFG_AHB_CLK] = &gcc_pcie_5_cfg_ahb_clk.clkr, + [GCC_PCIE_5_MSTR_AXI_CLK] = &gcc_pcie_5_mstr_axi_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK] = &gcc_pcie_5_phy_rchng_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK_SRC] = &gcc_pcie_5_phy_rchng_clk_src.clkr, + [GCC_PCIE_5_PIPE_CLK] = &gcc_pcie_5_pipe_clk.clkr, + [GCC_PCIE_5_PIPE_CLK_SRC] = &gcc_pcie_5_pipe_clk_src.clkr, + [GCC_PCIE_5_PIPE_DIV_CLK_SRC] = &gcc_pcie_5_pipe_div_clk_src.clkr, + [GCC_PCIE_5_PIPEDIV2_CLK] = &gcc_pcie_5_pipediv2_clk.clkr, + [GCC_PCIE_5_SLV_AXI_CLK] = &gcc_pcie_5_slv_axi_clk.clkr, + [GCC_PCIE_5_SLV_Q2A_AXI_CLK] = &gcc_pcie_5_slv_q2a_axi_clk.clkr, + [GCC_PCIE_6A_AUX_CLK] = &gcc_pcie_6a_aux_clk.clkr, + [GCC_PCIE_6A_AUX_CLK_SRC] = &gcc_pcie_6a_aux_clk_src.clkr, + [GCC_PCIE_6A_CFG_AHB_CLK] = &gcc_pcie_6a_cfg_ahb_clk.clkr, + [GCC_PCIE_6A_MSTR_AXI_CLK] = &gcc_pcie_6a_mstr_axi_clk.clkr, + [GCC_PCIE_6A_PHY_AUX_CLK] = &gcc_pcie_6a_phy_aux_clk.clkr, + [GCC_PCIE_6A_PHY_RCHNG_CLK] = &gcc_pcie_6a_phy_rchng_clk.clkr, + [GCC_PCIE_6A_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6a_phy_rchng_clk_src.clkr, + [GCC_PCIE_6A_PIPE_CLK] = &gcc_pcie_6a_pipe_clk.clkr, + [GCC_PCIE_6A_PIPE_CLK_SRC] = &gcc_pcie_6a_pipe_clk_src.clkr, + [GCC_PCIE_6A_PIPE_DIV_CLK_SRC] = &gcc_pcie_6a_pipe_div_clk_src.clkr, + [GCC_PCIE_6A_PIPEDIV2_CLK] = &gcc_pcie_6a_pipediv2_clk.clkr, + [GCC_PCIE_6A_SLV_AXI_CLK] = &gcc_pcie_6a_slv_axi_clk.clkr, + [GCC_PCIE_6A_SLV_Q2A_AXI_CLK] = &gcc_pcie_6a_slv_q2a_axi_clk.clkr, + [GCC_PCIE_6B_AUX_CLK] = &gcc_pcie_6b_aux_clk.clkr, + [GCC_PCIE_6B_AUX_CLK_SRC] = &gcc_pcie_6b_aux_clk_src.clkr, + [GCC_PCIE_6B_CFG_AHB_CLK] = &gcc_pcie_6b_cfg_ahb_clk.clkr, + [GCC_PCIE_6B_MSTR_AXI_CLK] = &gcc_pcie_6b_mstr_axi_clk.clkr, + [GCC_PCIE_6B_PHY_AUX_CLK] = &gcc_pcie_6b_phy_aux_clk.clkr, + [GCC_PCIE_6B_PHY_RCHNG_CLK] = &gcc_pcie_6b_phy_rchng_clk.clkr, + [GCC_PCIE_6B_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6b_phy_rchng_clk_src.clkr, + [GCC_PCIE_6B_PIPE_CLK] = &gcc_pcie_6b_pipe_clk.clkr, + [GCC_PCIE_6B_PIPE_CLK_SRC] = &gcc_pcie_6b_pipe_clk_src.clkr, + [GCC_PCIE_6B_PIPE_DIV_CLK_SRC] = &gcc_pcie_6b_pipe_div_clk_src.clkr, + [GCC_PCIE_6B_PIPEDIV2_CLK] = &gcc_pcie_6b_pipediv2_clk.clkr, + [GCC_PCIE_6B_SLV_AXI_CLK] = &gcc_pcie_6b_slv_axi_clk.clkr, + [GCC_PCIE_6B_SLV_Q2A_AXI_CLK] = &gcc_pcie_6b_slv_q2a_axi_clk.clkr, + [GCC_PCIE_RSCC_AHB_CLK] = &gcc_pcie_rscc_ahb_clk.clkr, + [GCC_PCIE_RSCC_XO_CLK] = &gcc_pcie_rscc_xo_clk.clkr, + [GCC_PCIE_RSCC_XO_CLK_SRC] = &gcc_pcie_rscc_xo_clk_src.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_QMIP_AV1E_AHB_CLK] = &gcc_qmip_av1e_ahb_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S2_CLK] = &gcc_qupv3_wrap0_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S3_CLK] = &gcc_qupv3_wrap0_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr, + [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr, + [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr, + [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s2_div_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s3_div_clk_src.clkr, + [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr, + [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr, + [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr, + [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr, + [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr, + [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr, + [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr, + [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S2_CLK] = &gcc_qupv3_wrap1_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S3_CLK] = &gcc_qupv3_wrap1_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s2_div_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s3_div_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr, + [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr, + [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr, + [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr, + [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S2_CLK] = &gcc_qupv3_wrap2_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S3_CLK] = &gcc_qupv3_wrap2_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr, + [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr, + [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr, + [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s2_div_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s3_div_clk_src.clkr, + [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr, + [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr, + [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr, + [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr, + [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr, + [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr, + [GCC_QUPV3_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr, + [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_clk_src.clkr, + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_SYS_NOC_USB_AXI_CLK] = &gcc_sys_noc_usb_axi_clk.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr, + [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr, + [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr, + [GCC_USB30_MP_MASTER_CLK] = &gcc_usb30_mp_master_clk.clkr, + [GCC_USB30_MP_MASTER_CLK_SRC] = &gcc_usb30_mp_master_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK] = &gcc_usb30_mp_mock_utmi_clk.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mp_mock_utmi_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_MP_SLEEP_CLK] = &gcc_usb30_mp_sleep_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK] = &gcc_usb30_sec_master_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK_SRC] = &gcc_usb30_sec_master_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK] = &gcc_usb30_sec_mock_utmi_clk.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = &gcc_usb30_sec_mock_utmi_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_SEC_SLEEP_CLK] = &gcc_usb30_sec_sleep_clk.clkr, + [GCC_USB30_TERT_MASTER_CLK] = &gcc_usb30_tert_master_clk.clkr, + [GCC_USB30_TERT_MASTER_CLK_SRC] = &gcc_usb30_tert_master_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK] = &gcc_usb30_tert_mock_utmi_clk.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK_SRC] = &gcc_usb30_tert_mock_utmi_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_TERT_SLEEP_CLK] = &gcc_usb30_tert_sleep_clk.clkr, + [GCC_USB3_MP_PHY_AUX_CLK] = &gcc_usb3_mp_phy_aux_clk.clkr, + [GCC_USB3_MP_PHY_AUX_CLK_SRC] = &gcc_usb3_mp_phy_aux_clk_src.clkr, + [GCC_USB3_MP_PHY_COM_AUX_CLK] = &gcc_usb3_mp_phy_com_aux_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_0_CLK] = &gcc_usb3_mp_phy_pipe_0_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_1_CLK] = &gcc_usb3_mp_phy_pipe_1_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr, + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK_SRC] = &gcc_usb3_sec_phy_pipe_clk_src.clkr, + [GCC_USB3_TERT_PHY_AUX_CLK] = &gcc_usb3_tert_phy_aux_clk.clkr, + [GCC_USB3_TERT_PHY_AUX_CLK_SRC] = &gcc_usb3_tert_phy_aux_clk_src.clkr, + [GCC_USB3_TERT_PHY_COM_AUX_CLK] = &gcc_usb3_tert_phy_com_aux_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK] = &gcc_usb3_tert_phy_pipe_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK_SRC] = &gcc_usb3_tert_phy_pipe_clk_src.clkr, + [GCC_USB4_0_CFG_AHB_CLK] = &gcc_usb4_0_cfg_ahb_clk.clkr, + [GCC_USB4_0_DP0_CLK] = &gcc_usb4_0_dp0_clk.clkr, + [GCC_USB4_0_DP1_CLK] = &gcc_usb4_0_dp1_clk.clkr, + [GCC_USB4_0_MASTER_CLK] = &gcc_usb4_0_master_clk.clkr, + [GCC_USB4_0_MASTER_CLK_SRC] = &gcc_usb4_0_master_clk_src.clkr, + [GCC_USB4_0_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_0_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK] = &gcc_usb4_0_phy_pcie_pipe_clk.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_0_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_0_PHY_RX0_CLK] = &gcc_usb4_0_phy_rx0_clk.clkr, + [GCC_USB4_0_PHY_RX1_CLK] = &gcc_usb4_0_phy_rx1_clk.clkr, + [GCC_USB4_0_PHY_USB_PIPE_CLK] = &gcc_usb4_0_phy_usb_pipe_clk.clkr, + [GCC_USB4_0_SB_IF_CLK] = &gcc_usb4_0_sb_if_clk.clkr, + [GCC_USB4_0_SB_IF_CLK_SRC] = &gcc_usb4_0_sb_if_clk_src.clkr, + [GCC_USB4_0_SYS_CLK] = &gcc_usb4_0_sys_clk.clkr, + [GCC_USB4_0_TMU_CLK] = &gcc_usb4_0_tmu_clk.clkr, + [GCC_USB4_0_TMU_CLK_SRC] = &gcc_usb4_0_tmu_clk_src.clkr, + [GCC_USB4_1_CFG_AHB_CLK] = &gcc_usb4_1_cfg_ahb_clk.clkr, + [GCC_USB4_1_DP0_CLK] = &gcc_usb4_1_dp0_clk.clkr, + [GCC_USB4_1_DP1_CLK] = &gcc_usb4_1_dp1_clk.clkr, + [GCC_USB4_1_MASTER_CLK] = &gcc_usb4_1_master_clk.clkr, + [GCC_USB4_1_MASTER_CLK_SRC] = &gcc_usb4_1_master_clk_src.clkr, + [GCC_USB4_1_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_1_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK] = &gcc_usb4_1_phy_pcie_pipe_clk.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_1_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_1_PHY_RX0_CLK] = &gcc_usb4_1_phy_rx0_clk.clkr, + [GCC_USB4_1_PHY_RX1_CLK] = &gcc_usb4_1_phy_rx1_clk.clkr, + [GCC_USB4_1_PHY_USB_PIPE_CLK] = &gcc_usb4_1_phy_usb_pipe_clk.clkr, + [GCC_USB4_1_SB_IF_CLK] = &gcc_usb4_1_sb_if_clk.clkr, + [GCC_USB4_1_SB_IF_CLK_SRC] = &gcc_usb4_1_sb_if_clk_src.clkr, + [GCC_USB4_1_SYS_CLK] = &gcc_usb4_1_sys_clk.clkr, + [GCC_USB4_1_TMU_CLK] = &gcc_usb4_1_tmu_clk.clkr, + [GCC_USB4_1_TMU_CLK_SRC] = &gcc_usb4_1_tmu_clk_src.clkr, + [GCC_USB4_2_CFG_AHB_CLK] = &gcc_usb4_2_cfg_ahb_clk.clkr, + [GCC_USB4_2_DP0_CLK] = &gcc_usb4_2_dp0_clk.clkr, + [GCC_USB4_2_DP1_CLK] = &gcc_usb4_2_dp1_clk.clkr, + [GCC_USB4_2_MASTER_CLK] = &gcc_usb4_2_master_clk.clkr, + [GCC_USB4_2_MASTER_CLK_SRC] = &gcc_usb4_2_master_clk_src.clkr, + [GCC_USB4_2_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_2_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK] = &gcc_usb4_2_phy_pcie_pipe_clk.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_2_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_2_PHY_RX0_CLK] = &gcc_usb4_2_phy_rx0_clk.clkr, + [GCC_USB4_2_PHY_RX1_CLK] = &gcc_usb4_2_phy_rx1_clk.clkr, + [GCC_USB4_2_PHY_USB_PIPE_CLK] = &gcc_usb4_2_phy_usb_pipe_clk.clkr, + [GCC_USB4_2_SB_IF_CLK] = &gcc_usb4_2_sb_if_clk.clkr, + [GCC_USB4_2_SB_IF_CLK_SRC] = &gcc_usb4_2_sb_if_clk_src.clkr, + [GCC_USB4_2_SYS_CLK] = &gcc_usb4_2_sys_clk.clkr, + [GCC_USB4_2_TMU_CLK] = &gcc_usb4_2_tmu_clk.clkr, + [GCC_USB4_2_TMU_CLK_SRC] = &gcc_usb4_2_tmu_clk_src.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, +}; + +static struct gdsc *gcc_x1e80100_gdscs[] = { + [GCC_PCIE_0_TUNNEL_GDSC] = &gcc_pcie_0_tunnel_gdsc, + [GCC_PCIE_1_TUNNEL_GDSC] = &gcc_pcie_1_tunnel_gdsc, + [GCC_PCIE_2_TUNNEL_GDSC] = &gcc_pcie_2_tunnel_gdsc, + [GCC_PCIE_3_GDSC] = &gcc_pcie_3_gdsc, + [GCC_PCIE_3_PHY_GDSC] = &gcc_pcie_3_phy_gdsc, + [GCC_PCIE_4_GDSC] = &gcc_pcie_4_gdsc, + [GCC_PCIE_4_PHY_GDSC] = &gcc_pcie_4_phy_gdsc, + [GCC_PCIE_5_GDSC] = &gcc_pcie_5_gdsc, + [GCC_PCIE_5_PHY_GDSC] = &gcc_pcie_5_phy_gdsc, + [GCC_PCIE_6_PHY_GDSC] = &gcc_pcie_6_phy_gdsc, + [GCC_PCIE_6A_GDSC] = &gcc_pcie_6a_gdsc, + [GCC_PCIE_6B_GDSC] = &gcc_pcie_6b_gdsc, + [GCC_UFS_MEM_PHY_GDSC] = &gcc_ufs_mem_phy_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB20_PRIM_GDSC] = &gcc_usb20_prim_gdsc, + [GCC_USB30_MP_GDSC] = &gcc_usb30_mp_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, + [GCC_USB30_SEC_GDSC] = &gcc_usb30_sec_gdsc, + [GCC_USB30_TERT_GDSC] = &gcc_usb30_tert_gdsc, + [GCC_USB3_MP_SS0_PHY_GDSC] = &gcc_usb3_mp_ss0_phy_gdsc, + [GCC_USB3_MP_SS1_PHY_GDSC] = &gcc_usb3_mp_ss1_phy_gdsc, + [GCC_USB4_0_GDSC] = &gcc_usb4_0_gdsc, + [GCC_USB4_1_GDSC] = &gcc_usb4_1_gdsc, + [GCC_USB4_2_GDSC] = &gcc_usb4_2_gdsc, + [GCC_USB_0_PHY_GDSC] = &gcc_usb_0_phy_gdsc, + [GCC_USB_1_PHY_GDSC] = &gcc_usb_1_phy_gdsc, + [GCC_USB_2_PHY_GDSC] = &gcc_usb_2_phy_gdsc, +}; + +static const struct qcom_reset_map gcc_x1e80100_resets[] = { + [GCC_AV1E_BCR] = { 0x4a000 }, + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_0_TUNNEL_BCR] = { 0xa0000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 }, + [GCC_PCIE_1_TUNNEL_BCR] = { 0x2c000 }, + [GCC_PCIE_2_LINK_DOWN_BCR] = { 0xa5014 }, + [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0xa5020 }, + [GCC_PCIE_2_PHY_BCR] = { 0xa501c }, + [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0xa5028 }, + [GCC_PCIE_2_TUNNEL_BCR] = { 0x13000 }, + [GCC_PCIE_3_BCR] = { 0x58000 }, + [GCC_PCIE_3_LINK_DOWN_BCR] = { 0xab014 }, + [GCC_PCIE_3_NOCSR_COM_PHY_BCR] = { 0xab020 }, + [GCC_PCIE_3_PHY_BCR] = { 0xab01c }, + [GCC_PCIE_3_PHY_NOCSR_COM_PHY_BCR] = { 0xab024 }, + [GCC_PCIE_4_BCR] = { 0x6b000 }, + [GCC_PCIE_4_LINK_DOWN_BCR] = { 0xb3014 }, + [GCC_PCIE_4_NOCSR_COM_PHY_BCR] = { 0xb3020 }, + [GCC_PCIE_4_PHY_BCR] = { 0xb301c }, + [GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR] = { 0xb3028 }, + [GCC_PCIE_5_BCR] = { 0x2f000 }, + [GCC_PCIE_5_LINK_DOWN_BCR] = { 0xaa014 }, + [GCC_PCIE_5_NOCSR_COM_PHY_BCR] = { 0xaa020 }, + [GCC_PCIE_5_PHY_BCR] = { 0xaa01c }, + [GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR] = { 0xaa028 }, + [GCC_PCIE_6A_BCR] = { 0x31000 }, + [GCC_PCIE_6A_LINK_DOWN_BCR] = { 0xac014 }, + [GCC_PCIE_6A_NOCSR_COM_PHY_BCR] = { 0xac020 }, + [GCC_PCIE_6A_PHY_BCR] = { 0xac01c }, + [GCC_PCIE_6A_PHY_NOCSR_COM_PHY_BCR] = { 0xac024 }, + [GCC_PCIE_6B_BCR] = { 0x8d000 }, + [GCC_PCIE_6B_LINK_DOWN_BCR] = { 0xb5014 }, + [GCC_PCIE_6B_NOCSR_COM_PHY_BCR] = { 0xb5020 }, + [GCC_PCIE_6B_PHY_BCR] = { 0xb501c }, + [GCC_PCIE_6B_PHY_NOCSR_COM_PHY_BCR] = { 0xb5024 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PCIE_RSCC_BCR] = { 0xa4000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x42000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_HS0_MP_BCR] = { 0x1200c }, + [GCC_QUSB2PHY_HS1_MP_BCR] = { 0x12010 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_QUSB2PHY_TERT_BCR] = { 0x12008 }, + [GCC_QUSB2PHY_USB20_HS_BCR] = { 0x12014 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB20_PRIM_BCR] = { 0x29000 }, + [GCC_USB30_MP_BCR] = { 0x17000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB30_SEC_BCR] = { 0xa1000 }, + [GCC_USB30_TERT_BCR] = { 0xa2000 }, + [GCC_USB3_MP_SS0_PHY_BCR] = { 0x19008 }, + [GCC_USB3_MP_SS1_PHY_BCR] = { 0x54008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x2a000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0xa3000 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x19000 }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x54000 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x2a004 }, + [GCC_USB3PHY_PHY_TERT_BCR] = { 0xa3004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x19004 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x54004 }, + [GCC_USB4_0_BCR] = { 0x9f000 }, + [GCC_USB4_0_DP0_PHY_PRIM_BCR] = { 0x50010 }, + [GCC_USB4_1_DP0_PHY_SEC_BCR] = { 0x2a010 }, + [GCC_USB4_2_DP0_PHY_TERT_BCR] = { 0xa3010 }, + [GCC_USB4_1_BCR] = { 0x2b000 }, + [GCC_USB4_2_BCR] = { 0x11000 }, + [GCC_USB_0_PHY_BCR] = { 0x50020 }, + [GCC_USB_1_PHY_BCR] = { 0x2a020 }, + [GCC_USB_2_PHY_BCR] = { 0xa3020 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s7_clk_src), +}; + +static const struct regmap_config gcc_x1e80100_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_x1e80100_desc = { + .config = &gcc_x1e80100_regmap_config, + .clks = gcc_x1e80100_clocks, + .num_clks = ARRAY_SIZE(gcc_x1e80100_clocks), + .resets = gcc_x1e80100_resets, + .num_resets = ARRAY_SIZE(gcc_x1e80100_resets), + .gdscs = gcc_x1e80100_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_x1e80100_gdscs), +}; + +static const struct of_device_id gcc_x1e80100_match_table[] = { + { .compatible = "qcom,x1e80100-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_x1e80100_match_table); + +static int gcc_x1e80100_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_x1e80100_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + /* Keep the critical clock always-On */ + regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */ + regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */ + regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */ + regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */ + regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */ + regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */ + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); + + return qcom_cc_really_probe(pdev, &gcc_x1e80100_desc, regmap); +} + +static struct platform_driver gcc_x1e80100_driver = { + .probe = gcc_x1e80100_probe, + .driver = { + .name = "gcc-x1e80100", + .of_match_table = gcc_x1e80100_match_table, + }, +}; + +static int __init gcc_x1e80100_init(void) +{ + return platform_driver_register(&gcc_x1e80100_driver); +} +subsys_initcall(gcc_x1e80100_init); + +static void __exit gcc_x1e80100_exit(void) +{ + platform_driver_unregister(&gcc_x1e80100_driver); +} +module_exit(gcc_x1e80100_exit); + +MODULE_DESCRIPTION("QTI GCC X1E80100 Driver"); +MODULE_LICENSE("GPL"); From 874bc7be1e08bca7d47cfa2dba57164f73a30219 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:40:02 +0530 Subject: [PATCH 3322/7721] clk: qcom: rpmh: Add support for X1E80100 rpmh clocks Adds the RPMH clocks present in X1E80100 SoC Co-developed-by: Neil Armstrong Signed-off-by: Neil Armstrong Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231205061002.30759-5-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-rpmh.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index bb09170600ec..bb82abeed88f 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -372,6 +372,7 @@ DEFINE_CLK_RPMH_VRM(clk3, _a1, "clka3", 1); DEFINE_CLK_RPMH_VRM(clk4, _a1, "clka4", 1); DEFINE_CLK_RPMH_VRM(clk5, _a1, "clka5", 1); +DEFINE_CLK_RPMH_VRM(clk3, _a2, "clka3", 2); DEFINE_CLK_RPMH_VRM(clk4, _a2, "clka4", 2); DEFINE_CLK_RPMH_VRM(clk5, _a2, "clka5", 2); DEFINE_CLK_RPMH_VRM(clk6, _a2, "clka6", 2); @@ -770,6 +771,28 @@ static const struct clk_rpmh_desc clk_rpmh_sm4450 = { .num_clks = ARRAY_SIZE(sm4450_rpmh_clocks), }; +static struct clk_hw *x1e80100_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw, + [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2.hw, + [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_ao.hw, + [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a2.hw, + [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a2_ao.hw, + [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2.hw, + [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_ao.hw, + [RPMH_RF_CLK3] = &clk_rpmh_clk3_a2.hw, + [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a2_ao.hw, + [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw, + [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_x1e80100 = { + .clks = x1e80100_rpmh_clocks, + .num_clks = ARRAY_SIZE(x1e80100_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -872,6 +895,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sm8550-rpmh-clk", .data = &clk_rpmh_sm8550}, { .compatible = "qcom,sm8650-rpmh-clk", .data = &clk_rpmh_sm8650}, { .compatible = "qcom,sc7280-rpmh-clk", .data = &clk_rpmh_sc7280}, + { .compatible = "qcom,x1e80100-rpmh-clk", .data = &clk_rpmh_x1e80100}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); From bfea2924fc28b1b9985a208223f315992a68fc56 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:53:59 +0530 Subject: [PATCH 3323/7721] dt-bindings: arm: cpus: Add qcom,oryon compatible Oryon is the custom ARM CPU core implementation used in Qualcomm's X1E80100 SoC, document it. Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20231205062403.14848-2-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/cpus.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index ffd526363fda..cc5a21b47e26 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -198,6 +198,7 @@ properties: - qcom,kryo660 - qcom,kryo685 - qcom,kryo780 + - qcom,oryon - qcom,scorpion enable-method: From 7a85cecf98ca175d11b7133f7c4e88bbcc0fe5d3 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:54:00 +0530 Subject: [PATCH 3324/7721] dt-bindings: arm: qcom: Document X1E80100 SoC and boards Document the X1E80100 SoC binding and also the boards using it. Also document the new board id qcp (Qualcomm Compute Platform). Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231205062403.14848-3-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 670e61cbb644..c968412d86b8 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -88,6 +88,7 @@ description: | sm8450 sm8550 sm8650 + x1e80100 The 'board' element must be one of the following strings: @@ -97,6 +98,7 @@ description: | idp liquid mtp + qcp qrd rb2 ride @@ -1046,6 +1048,12 @@ properties: - qcom,sm8650-qrd - const: qcom,sm8650 + - items: + - enum: + - qcom,x1e80100-crd + - qcom,x1e80100-qcp + - const: qcom,x1e80100 + # Board compatibles go above qcom,msm-id: From af16b00578a7a1d9fb99e81282b1b22cd8d32607 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 5 Dec 2023 11:54:01 +0530 Subject: [PATCH 3325/7721] arm64: dts: qcom: Add base X1E80100 dtsi and the QCP dts Add base dtsi and QCP board (Qualcomm Compute Platform) dts file for X1E80100 SoC, describing the CPUs, GCC and RPMHCC clock controllers, geni UART, interrupt controller, TLMM, reserved memory, interconnects, SMMU and LLCC nodes. Co-developed-by: Abel Vesa Signed-off-by: Abel Vesa Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231205062403.14848-4-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 401 +++ arch/arm64/boot/dts/qcom/x1e80100.dtsi | 3527 +++++++++++++++++++++ 3 files changed, 3929 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/x1e80100-qcp.dts create mode 100644 arch/arm64/boot/dts/qcom/x1e80100.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 8d291ab00106..132e9bec6404 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -237,3 +237,4 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8550-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += x1e80100-qcp.dtb diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts new file mode 100644 index 000000000000..3746e1de3623 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include + +#include "x1e80100.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. X1E80100 QCP"; + compatible = "qcom,x1e80100-qcp", "qcom,x1e80100"; + + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l4-supply = <&vreg_s4c_1p8>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob2>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l10-supply = <&vreg_s4c_1p8>; + vdd-l12-supply = <&vreg_s5j_1p2>; + vdd-l15-supply = <&vreg_s4c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l1b_1p8: ldo1 { + regulator-name = "vreg_l1b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l5b_3p0: ldo5 { + regulator-name = "vreg_l5b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p8: ldo7 { + regulator-name = "vreg_l7b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l8b_3p0: ldo8 { + regulator-name = "vreg_l8b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10b_1p8: ldo10 { + regulator-name = "vreg_l10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l12b_1p2: ldo12 { + regulator-name = "vreg_l12b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l14b_3p0: ldo14 { + regulator-name = "vreg_l14b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l16b_2p9: ldo16 { + regulator-name = "vreg_l16b_2p9"; + regulator-min-microvolt = <2912000>; + regulator-max-microvolt = <2912000>; + regulator-initial-mode = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s4-supply = <&vph_pwr>; + + vreg_s4c_1p8: smps4 { + regulator-name = "vreg_s4c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2c_0p8: ldo2 { + regulator-name = "vreg_l2c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3c_0p8: ldo3 { + regulator-name = "vreg_l3c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "d"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s4c_1p8>; + vdd-s1-supply = <&vph_pwr>; + + vreg_l1d_0p8: ldo1 { + regulator-name = "vreg_l1d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3d_1p8: ldo3 { + regulator-name = "vreg_l3d_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vph_pwr>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3e_1p2: ldo3 { + regulator-name = "vreg_l3e_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s5j_1p2>; + vdd-s1-supply = <&vph_pwr>; + + vreg_s1f_0p7: smps1 { + regulator-name = "vreg_s1f_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1f_1p0: ldo1 { + regulator-name = "vreg_l1f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l2f_1p0: ldo2 { + regulator-name = "vreg_l2f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l3f_1p0: ldo3 { + regulator-name = "vreg_l3f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "i"; + + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + + vreg_s1i_0p9: smps1 { + regulator-name = "vreg_s1i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_s2i_1p0: smps2 { + regulator-name = "vreg_s2i_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1i_1p8: ldo1 { + regulator-name = "vreg_l1i_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "j"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vph_pwr>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vph_pwr>; + + vreg_s5j_1p2: smps5 { + regulator-name = "vreg_s5j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l1j_0p8: ldo1 { + regulator-name = "vreg_l1j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2j_1p2: ldo2 { + regulator-name = "vreg_l2j_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3j_0p8: ldo3 { + regulator-name = "vreg_l3j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; +}; + +&qupv3_2 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <33 3>, /* Unused */ + <44 4>, /* SPI (TPM) */ + <238 1>; /* UFS Reset */ +}; + +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi new file mode 100644 index 000000000000..da691e2f3209 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -0,0 +1,3527 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <76800000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + #clock-cells = <0>; + }; + + bi_tcxo_div2: bi-tcxo-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-mult = <1>; + clock-div = <2>; + }; + + bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK_A>; + clock-mult = <1>; + clock-div = <2>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU4: cpu@10000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10000>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD4>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_1: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU5: cpu@10100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10100>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD5>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU6: cpu@10200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10200>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD6>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU7: cpu@10300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10300>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD7>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU8: cpu@20000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20000>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD8>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_2: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU9: cpu@20100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20100>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD9>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU10: cpu@20200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20200>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD10>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU11: cpu@20300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20300>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD11>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU8>; + }; + + core1 { + cpu = <&CPU9>; + }; + + core2 { + cpu = <&CPU10>; + }; + + core3 { + cpu = <&CPU11>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + CLUSTER_C4: cpu-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <180>; + exit-latency-us = <320>; + min-residency-us = <1000>; + }; + }; + + domain-idle-states { + CLUSTER_CL4: cluster-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "l2-ret"; + arm,psci-suspend-param = <0x01000044>; + entry-latency-us = <350>; + exit-latency-us = <500>; + min-residency-us = <2500>; + }; + + CLUSTER_CL5: cluster-sleep-1 { + compatible = "arm,idle-state"; + idle-state-name = "ret-pll-off"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2200>; + exit-latency-us = <2500>; + min-residency-us = <7000>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-x1e80100", "qcom,scm"; + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + }; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,x1e80100-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,x1e80100-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0x80000000 0 0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + CPU_PD0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD8: power-domain-cpu8 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD9: power-domain-cpu9 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD10: power-domain-cpu10 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD11: power-domain-cpu11 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CLUSTER_PD0: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + + CLUSTER_PD1: power-domain-cpu-cluster1 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + + CLUSTER_PD2: power-domain-cpu-cluster2 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gunyah_hyp_mem: gunyah-hyp@80000000 { + reg = <0x0 0x80000000 0x0 0x800000>; + no-map; + }; + + hyp_elf_package_mem: hyp-elf-package@80800000 { + reg = <0x0 0x80800000 0x0 0x200000>; + no-map; + }; + + ncc_mem: ncc@80a00000 { + reg = <0x0 0x80a00000 0x0 0x400000>; + no-map; + }; + + cpucp_log_mem: cpucp-log@80e00000 { + reg = <0x0 0x80e00000 0x0 0x40000>; + no-map; + }; + + cpucp_mem: cpucp@80e40000 { + reg = <0x0 0x80e40000 0x0 0x540000>; + no-map; + }; + + reserved-region@81380000 { + reg = <0x0 0x81380000 0x0 0x80000>; + no-map; + }; + + tags_mem: tags-region@81400000 { + reg = <0x0 0x81400000 0x0 0x1a0000>; + no-map; + }; + + xbl_dtlog_mem: xbl-dtlog@81a00000 { + reg = <0x0 0x81a00000 0x0 0x40000>; + no-map; + }; + + xbl_ramdump_mem: xbl-ramdump@81a40000 { + reg = <0x0 0x81a40000 0x0 0x1c0000>; + no-map; + }; + + aop_image_mem: aop-image@81c00000 { + reg = <0x0 0x81c00000 0x0 0x60000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x81c60000 0x0 0x20000>; + no-map; + }; + + aop_config_mem: aop-config@81c80000 { + reg = <0x0 0x81c80000 0x0 0x20000>; + no-map; + }; + + tme_crash_dump_mem: tme-crash-dump@81ca0000 { + reg = <0x0 0x81ca0000 0x0 0x40000>; + no-map; + }; + + tme_log_mem: tme-log@81ce0000 { + reg = <0x0 0x81ce0000 0x0 0x4000>; + no-map; + }; + + uefi_log_mem: uefi-log@81ce4000 { + reg = <0x0 0x81ce4000 0x0 0x10000>; + no-map; + }; + + secdata_apss_mem: secdata-apss@81cff000 { + reg = <0x0 0x81cff000 0x0 0x1000>; + no-map; + }; + + pdp_ns_shared_mem: pdp-ns-shared@81e00000 { + reg = <0x0 0x81e00000 0x0 0x100000>; + no-map; + }; + + gpu_prr_mem: gpu-prr@81f00000 { + reg = <0x0 0x81f00000 0x0 0x10000>; + no-map; + }; + + tpm_control_mem: tpm-control@81f10000 { + reg = <0x0 0x81f10000 0x0 0x10000>; + no-map; + }; + + usb_ucsi_shared_mem: usb-ucsi-shared@81f20000 { + reg = <0x0 0x81f20000 0x0 0x10000>; + no-map; + }; + + pld_pep_mem: pld-pep@81f30000 { + reg = <0x0 0x81f30000 0x0 0x6000>; + no-map; + }; + + pld_gmu_mem: pld-gmu@81f36000 { + reg = <0x0 0x81f36000 0x0 0x1000>; + no-map; + }; + + pld_pdp_mem: pld-pdp@81f37000 { + reg = <0x0 0x81f37000 0x0 0x1000>; + no-map; + }; + + tz_stat_mem: tz-stat@82700000 { + reg = <0x0 0x82700000 0x0 0x100000>; + no-map; + }; + + xbl_tmp_buffer_mem: xbl-tmp-buffer@82800000 { + reg = <0x0 0x82800000 0x0 0xc00000>; + no-map; + }; + + adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@84b00000 { + reg = <0x0 0x84b00000 0x0 0x800000>; + no-map; + }; + + spu_secure_shared_memory_mem: spu-secure-shared-memory@85300000 { + reg = <0x0 0x85300000 0x0 0x80000>; + no-map; + }; + + adsp_boot_dtb_mem: adsp-boot-dtb@866c0000 { + reg = <0x0 0x866c0000 0x0 0x40000>; + no-map; + }; + + spss_region_mem: spss-region@86700000 { + reg = <0x0 0x86700000 0x0 0x400000>; + no-map; + }; + + adsp_boot_mem: adsp-boot@86b00000 { + reg = <0x0 0x86b00000 0x0 0xc00000>; + no-map; + }; + + video_mem: video@87700000 { + reg = <0x0 0x87700000 0x0 0x700000>; + no-map; + }; + + adspslpi_mem: adspslpi@87e00000 { + reg = <0x0 0x87e00000 0x0 0x3a00000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb@8b800000 { + reg = <0x0 0x8b800000 0x0 0x80000>; + no-map; + }; + + cdsp_mem: cdsp@8b900000 { + reg = <0x0 0x8b900000 0x0 0x2000000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb@8d900000 { + reg = <0x0 0x8d900000 0x0 0x80000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8d9fe000 { + reg = <0x0 0x8d9fe000 0x0 0x2000>; + no-map; + }; + + cvp_mem: cvp@8da00000 { + reg = <0x0 0x8da00000 0x0 0x700000>; + no-map; + }; + + camera_mem: camera@8e100000 { + reg = <0x0 0x8e100000 0x0 0x800000>; + no-map; + }; + + av1_encoder_mem: av1-encoder@8e900000 { + reg = <0x0 0x8e900000 0x0 0x700000>; + no-map; + }; + + reserved-region@8f000000 { + reg = <0x0 0x8f000000 0x0 0xa00000>; + no-map; + }; + + wpss_mem: wpss@8fa00000 { + reg = <0x0 0x8fa00000 0x0 0x1900000>; + no-map; + }; + + q6_wpss_dtb_mem: q6-wpss-dtb@91300000 { + reg = <0x0 0x91300000 0x0 0x80000>; + no-map; + }; + + xbl_sc_mem: xbl-sc@d8000000 { + reg = <0x0 0xd8000000 0x0 0x40000>; + no-map; + }; + + reserved-region@d8040000 { + reg = <0x0 0xd8040000 0x0 0xa0000>; + no-map; + }; + + qtee_mem: qtee@d80e0000 { + reg = <0x0 0xd80e0000 0x0 0x520000>; + no-map; + }; + + ta_mem: ta@d8600000 { + reg = <0x0 0xd8600000 0x0 0x8a00000>; + no-map; + }; + + tags_mem1: tags@e1000000 { + reg = <0x0 0xe1000000 0x0 0x26a0000>; + no-map; + }; + + llcc_lpi_mem: llcc-lpi@ff800000 { + reg = <0x0 0xff800000 0x0 0x600000>; + no-map; + }; + + smem_mem: smem@ffe00000 { + compatible = "qcom,smem"; + reg = <0x0 0xffe00000 0x0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0 0 0 0 0x10 0>; + ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; + reg = <0 0x00100000 0 0x200000>; + + clocks = <&bi_tcxo_div2>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>; + + power-domains = <&rpmhpd RPMHPD_CX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + gpi_dma2: dma-controller@800000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00800000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x436 0x0>; + + status = "disabled"; + }; + + qupv3_2: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x008c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x423 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c16: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c16_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi16: spi@880000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi16_data_clk>, <&qup_spi16_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c17: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c17_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi17: spi@884000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi17_data_clk>, <&qup_spi17_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c18: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c18_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi18: spi@888000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi18_data_clk>, <&qup_spi18_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c19: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c19_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi19: spi@88c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi19_data_clk>, <&qup_spi19_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c20: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c20_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi20: spi@890000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi20_data_clk>, <&qup_spi20_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c21: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c21_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi21: spi@894000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi21_data_clk>, <&qup_spi21_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + uart21: serial@894000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart21_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + + i2c22: i2c@898000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 6 QCOM_GPI_I2C>, + <&gpi_dma2 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c22_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi22: spi@898000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, + <&gpi_dma2 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi22_data_clk>, <&qup_spi22_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c23: i2c@89c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 7 QCOM_GPI_I2C>, + <&gpi_dma2 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c23_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi23: spi@89c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 7 QCOM_GPI_SPI>, + <&gpi_dma2 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi23_data_clk>, <&qup_spi23_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00a00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x136 0x0>; + + status = "disabled"; + }; + + qupv3_1: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00ac0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x123 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c8: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi8: spi@a80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi8_data_clk>, <&qup_spi8_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c9: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi9: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c10: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c10_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi10: spi@a88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c11: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c11_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi11: spi@a8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi11_data_clk>, <&qup_spi11_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c12: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c12_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi12: spi@a90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi12_data_clk>, <&qup_spi12_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c13: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c13_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi13: spi@a94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi13_data_clk>, <&qup_spi13_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c14: i2c@a98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c14_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi14: spi@a98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi14_data_clk>, <&qup_spi14_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c15: i2c@a9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c15_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi15: spi@a9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>, + <&gpi_dma1 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi15_data_clk>, <&qup_spi15_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + gpi_dma0: dma-controller@b00000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00b00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x456 0x0>; + + status = "disabled"; + }; + + qupv3_0: geniqup@bc0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00bc0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x443 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c0: i2c@b80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0xb80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi0: spi@b80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c1: i2c@b84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, + <&gpi_dma0 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi1: spi@b84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, + <&gpi_dma0 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi1_data_clk>, <&qup_spi1_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c2: i2c@b88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, + <&gpi_dma0 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi2: spi@b88000 { + compatible = "qcom,geni-spi"; + reg = <0 0xb88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, + <&gpi_dma0 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c3: i2c@b8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, + <&gpi_dma0 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi3: spi@b8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, + <&gpi_dma0 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi3_data_clk>, <&qup_spi3_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c4: i2c@b90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0xb90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, + <&gpi_dma0 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi4: spi@b90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, + <&gpi_dma0 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c5: i2c@b94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, + <&gpi_dma0 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi5: spi@b94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, + <&gpi_dma0 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi5_data_clk>, <&qup_spi5_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c6: i2c@b98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, + <&gpi_dma0 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi6: spi@b98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>, + <&gpi_dma0 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c7: i2c@b9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, + <&gpi_dma0 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi7: spi@b9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 7 QCOM_GPI_SPI>, + <&gpi_dma0 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,x1e80100-cnoc-main"; + reg = <0 0x1500000 0 0x14400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,x1e80100-cnoc-cfg"; + reg = <0 0x1600000 0 0x6600>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,x1e80100-system-noc"; + reg = <0 0x1680000 0 0x1c080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_south_anoc: interconnect@16c0000 { + compatible = "qcom,x1e80100-pcie-south-anoc"; + reg = <0 0x16c0000 0 0xd080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_center_anoc: interconnect@16d0000 { + compatible = "qcom,x1e80100-pcie-center-anoc"; + reg = <0 0x16d0000 0 0x7000>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,x1e80100-aggre1-noc"; + reg = <0 0x16E0000 0 0x14400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1700000 { + compatible = "qcom,x1e80100-aggre2-noc"; + reg = <0 0x1700000 0 0x1c400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_north_anoc: interconnect@1740000 { + compatible = "qcom,x1e80100-pcie-north-anoc"; + reg = <0 0x1740000 0 0x9080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_center_anoc: interconnect@1750000 { + compatible = "qcom,x1e80100-usb-center-anoc"; + reg = <0 0x1750000 0 0x8800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_north_anoc: interconnect@1760000 { + compatible = "qcom,x1e80100-usb-north-anoc"; + reg = <0 0x1760000 0 0x7080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_south_anoc: interconnect@1770000 { + compatible = "qcom,x1e80100-usb-south-anoc"; + reg = <0 0x1770000 0 0xf080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,x1e80100-mmss-noc"; + reg = <0 0x1780000 0 0x5B800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0 0x01f40000 0 0x20000>; + #hwlock-cells = <1>; + }; + + gem_noc: interconnect@26400000 { + compatible = "qcom,x1e80100-gem-noc"; + reg = <0 0x26400000 0 0x311200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + nsp_noc: interconnect@320c0000 { + compatible = "qcom,x1e80100-nsp-noc"; + reg = <0 0x320C0000 0 0xE080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,x1e80100-lpass-ag-noc"; + reg = <0 0x7e40000 0 0xE080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,x1e80100-lpass-lpiaon-noc"; + reg = <0 0x7400000 0 0x19080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_lpicx_noc: interconnect@7430000 { + compatible = "qcom,x1e80100-lpass-lpicx-noc"; + reg = <0 0x7430000 0 0x3A200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,x1e80100-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; + + qcom,pdc-ranges = <0 480 42>, <42 251 5>, + <47 522 52>, <99 609 32>, + <131 717 12>, <143 816 19>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,x1e80100-tlmm"; + reg = <0 0x0f100000 0 0xf00000>; + + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&tlmm 0 0 239>; + wakeup-parent = <&pdc>; + + qup_i2c0_data_clk: qup-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio0", "gpio1"; + function = "qup0_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c1_data_clk: qup-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio4", "gpio5"; + function = "qup0_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c2_data_clk: qup-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio8", "gpio9"; + function = "qup0_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c3_data_clk: qup-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio12", "gpio13"; + function = "qup0_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c4_data_clk: qup-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio16", "gpio17"; + function = "qup0_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c5_data_clk: qup-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio20", "gpio21"; + function = "qup0_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c6_data_clk: qup-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio24", "gpio25"; + function = "qup0_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c7_data_clk: qup-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio14", "gpio15"; + function = "qup0_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c8_data_clk: qup-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio32", "gpio33"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c9_data_clk: qup-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio36", "gpio37"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c10_data_clk: qup-i2c10-data-clk-state { + /* SDA, SCL */ + pins = "gpio40", "gpio41"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c11_data_clk: qup-i2c11-data-clk-state { + /* SDA, SCL */ + pins = "gpio44", "gpio45"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c12_data_clk: qup-i2c12-data-clk-state { + /* SDA, SCL */ + pins = "gpio48", "gpio49"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c13_data_clk: qup-i2c13-data-clk-state { + /* SDA, SCL */ + pins = "gpio52", "gpio53"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c14_data_clk: qup-i2c14-data-clk-state { + /* SDA, SCL */ + pins = "gpio56", "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c15_data_clk: qup-i2c15-data-clk-state { + /* SDA, SCL */ + pins = "gpio54", "gpio55"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c16_data_clk: qup-i2c16-data-clk-state { + /* SDA, SCL */ + pins = "gpio64", "gpio65"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c17_data_clk: qup-i2c17-data-clk-state { + /* SDA, SCL */ + pins = "gpio68", "gpio69"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c18_data_clk: qup-i2c18-data-clk-state { + /* SDA, SCL */ + pins = "gpio72", "gpio73"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c19_data_clk: qup-i2c19-data-clk-state { + /* SDA, SCL */ + pins = "gpio76", "gpio77"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c20_data_clk: qup-i2c20-data-clk-state { + /* SDA, SCL */ + pins = "gpio80", "gpio81"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c21_data_clk: qup-i2c21-data-clk-state { + /* SDA, SCL */ + pins = "gpio84", "gpio85"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c22_data_clk: qup-i2c22-data-clk-state { + /* SDA, SCL */ + pins = "gpio88", "gpio89"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c23_data_clk: qup-i2c23-data-clk-state { + /* SDA, SCL */ + pins = "gpio86", "gpio87"; + function = "qup2_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_spi0_cs: qup-spi0-cs-state { + pins = "gpio3"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi0_data_clk: qup-spi0-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio0", "gpio1", "gpio2"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_cs: qup-spi1-cs-state { + pins = "gpio7"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_data_clk: qup-spi1-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio4", "gpio5", "gpio6"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_cs: qup-spi2-cs-state { + pins = "gpio11"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_data_clk: qup-spi2-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio8", "gpio9", "gpio10"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_cs: qup-spi3-cs-state { + pins = "gpio15"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_data_clk: qup-spi3-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio12", "gpio13", "gpio14"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_cs: qup-spi4-cs-state { + pins = "gpio19"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_data_clk: qup-spi4-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio16", "gpio17", "gpio18"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_cs: qup-spi5-cs-state { + pins = "gpio23"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_data_clk: qup-spi5-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio20", "gpio21", "gpio22"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_cs: qup-spi6-cs-state { + pins = "gpio27"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_data_clk: qup-spi6-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio24", "gpio25", "gpio26"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_cs: qup-spi7-cs-state { + pins = "gpio13"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_data_clk: qup-spi7-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio14", "gpio15", "gpio12"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_cs: qup-spi8-cs-state { + pins = "gpio35"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_data_clk: qup-spi8-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio32", "gpio33", "gpio34"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_cs: qup-spi9-cs-state { + pins = "gpio39"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_data_clk: qup-spi9-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio36", "gpio37", "gpio38"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_cs: qup-spi10-cs-state { + pins = "gpio43"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_data_clk: qup-spi10-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio40", "gpio41", "gpio42"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_cs: qup-spi11-cs-state { + pins = "gpio47"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_data_clk: qup-spi11-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio44", "gpio45", "gpio46"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_cs: qup-spi12-cs-state { + pins = "gpio51"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_data_clk: qup-spi12-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio48", "gpio49", "gpio50"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_cs: qup-spi13-cs-state { + pins = "gpio55"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_data_clk: qup-spi13-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio52", "gpio53", "gpio54"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_cs: qup-spi14-cs-state { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_data_clk: qup-spi14-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio56", "gpio57", "gpio58"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi15_cs: qup-spi15-cs-state { + pins = "gpio53"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi15_data_clk: qup-spi15-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio54", "gpio55", "gpio52"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi16_cs: qup-spi16-cs-state { + pins = "gpio67"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi16_data_clk: qup-spi16-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio64", "gpio65", "gpio66"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi17_cs: qup-spi17-cs-state { + pins = "gpio71"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi17_data_clk: qup-spi17-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio68", "gpio69", "gpio70"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi18_cs: qup-spi18-cs-state { + pins = "gpio75"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi18_data_clk: qup-spi18-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio72", "gpio73", "gpio74"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi19_cs: qup-spi19-cs-state { + pins = "gpio79"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi19_data_clk: qup-spi19-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio76", "gpio77", "gpio78"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi20_cs: qup-spi20-cs-state { + pins = "gpio83"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi20_data_clk: qup-spi20-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio80", "gpio81", "gpio82"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi21_cs: qup-spi21-cs-state { + pins = "gpio87"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi21_data_clk: qup-spi21-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio84", "gpio85", "gpio86"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi22_cs: qup-spi22-cs-state { + pins = "gpio91"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi22_data_clk: qup-spi22-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio88", "gpio89", "gpio90"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi23_cs: qup-spi23-cs-state { + pins = "gpio85"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi23_data_clk: qup-spi23-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio86", "gpio87", "gpio84"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_uart21_default: qup-uart21-default-state { + /* TX, RX */ + pins = "gpio86", "gpio87"; + function = "qup2_se5"; + drive-strength= <2>; + bias-disable; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,x1e80100-smmu-500", "qcom,smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + #iommu-cells = <2>; + #global-interrupts = <1>; + }; + + intc: interrupt-controller@17000000 { + compatible = "arm,gic-v3"; + reg = <0 0x17000000 0 0x10000>, /* GICD */ + <0 0x17080000 0 0x480000>; /* GICR * 12 */ + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: msi-controller@17040000 { + compatible = "arm,gic-v3-its"; + reg = <0 0x17040000 0 0x40000>; + + msi-controller; + #msi-cells = <1>; + + status = "disabled"; + }; + }; + + apps_rsc: rsc@17500000 { + compatible = "qcom,rpmh-rsc"; + reg = <0 0x17500000 0 0x10000>, + <0 0x17510000 0 0x10000>, + <0 0x17520000 0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + qcom,drv-count = <3>; + + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + + label = "apps_rsc"; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,x1e80100-rpmh-clk"; + + clocks = <&xo_board>; + clock-names = "xo"; + + #clock-cells = <1>; + }; + + rpmhpd: power-controller { + compatible = "qcom,x1e80100-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_min_svs: opp-48 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + }; + }; + }; + + timer@17800000 { + compatible = "arm,armv7-timer-mem"; + reg = <0 0x17800000 0 0x1000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + frame@17801000 { + reg = <0 0x17801000 0 0x1000>, + <0 0x17802000 0 0x1000>; + + interrupts = , + ; + + frame-number = <0>; + }; + + frame@17803000 { + reg = <0 0x17803000 0 0x1000>; + + interrupts = ; + + frame-number = <1>; + + status = "disabled"; + }; + + frame@17805000 { + reg = <0 0x17805000 0 0x1000>; + + interrupts = ; + + frame-number = <2>; + + status = "disabled"; + }; + + frame@17807000 { + reg = <0 0x17807000 0 0x1000>; + + interrupts = ; + + frame-number = <3>; + + status = "disabled"; + }; + + frame@17809000 { + reg = <0 0x17809000 0 0x1000>; + + interrupts = ; + + frame-number = <4>; + + status = "disabled"; + }; + + frame@1780b000 { + reg = <0 0x1780b000 0 0x1000>; + + interrupts = ; + + frame-number = <5>; + + status = "disabled"; + }; + + frame@1780d000 { + reg = <0 0x1780d000 0 0x1000>; + + interrupts = ; + + frame-number = <6>; + + status = "disabled"; + }; + }; + + system-cache-controller@25000000 { + compatible = "qcom,x1e80100-llcc"; + reg = <0 0x25000000 0 0x200000>, + <0 0x25200000 0 0x200000>, + <0 0x25400000 0 0x200000>, + <0 0x25600000 0 0x200000>, + <0 0x25800000 0 0x200000>, + <0 0x25a00000 0 0x200000>, + <0 0x25c00000 0 0x200000>, + <0 0x25e00000 0 0x200000>, + <0 0x26000000 0 0x200000>; + reg-names = "llcc0_base", + "llcc1_base", + "llcc2_base", + "llcc3_base", + "llcc4_base", + "llcc5_base", + "llcc6_base", + "llcc7_base", + "llcc_broadcast_base"; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + + interrupts = , + , + , + ; + }; +}; From bd50b1f5b6f38b2970841e78513c33fbd736cf40 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 5 Dec 2023 11:54:02 +0530 Subject: [PATCH 3326/7721] arm64: dts: qcom: x1e80100: Add Compute Reference Device Add basic support for X1E80100 CRD board dts, which allows it to boot to a shell. Signed-off-by: Abel Vesa Signed-off-by: Rajendra Nayak Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231205062403.14848-5-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/x1e80100-crd.dts | 426 ++++++++++++++++++++++ 2 files changed, 427 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/x1e80100-crd.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 132e9bec6404..39889d5f8e12 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -237,4 +237,5 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8550-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += x1e80100-crd.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-qcp.dtb diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts new file mode 100644 index 000000000000..c209ae59c6b5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include + +#include "x1e80100.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. X1E80100 CRD"; + compatible = "qcom,x1e80100-crd", "qcom,x1e80100"; + + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; + + vreg_edp_3p3: regulator-edp-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_EDP_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&edp_reg_en>; + pinctrl-names = "default"; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l4-supply = <&vreg_s4c_1p8>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob2>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l10-supply = <&vreg_s4c_1p8>; + vdd-l12-supply = <&vreg_s5j_1p2>; + vdd-l15-supply = <&vreg_s4c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l1b_1p8: ldo1 { + regulator-name = "vreg_l1b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l5b_3p0: ldo5 { + regulator-name = "vreg_l5b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p8: ldo7 { + regulator-name = "vreg_l7b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l8b_3p0: ldo8 { + regulator-name = "vreg_l8b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10b_1p8: ldo10 { + regulator-name = "vreg_l10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l12b_1p2: ldo12 { + regulator-name = "vreg_l12b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l14b_3p0: ldo14 { + regulator-name = "vreg_l14b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l16b_2p9: ldo16 { + regulator-name = "vreg_l16b_2p9"; + regulator-min-microvolt = <2912000>; + regulator-max-microvolt = <2912000>; + regulator-initial-mode = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s4-supply = <&vph_pwr>; + + vreg_s4c_1p8: smps4 { + regulator-name = "vreg_s4c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2c_0p8: ldo2 { + regulator-name = "vreg_l2c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3c_0p8: ldo3 { + regulator-name = "vreg_l3c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "d"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s4c_1p8>; + vdd-s1-supply = <&vph_pwr>; + + vreg_l1d_0p8: ldo1 { + regulator-name = "vreg_l1d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3d_1p8: ldo3 { + regulator-name = "vreg_l3d_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s5j_1p2>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3e_1p2: ldo3 { + regulator-name = "vreg_l3e_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s5j_1p2>; + vdd-s1-supply = <&vph_pwr>; + + vreg_s1f_0p7: smps1 { + regulator-name = "vreg_s1f_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1f_1p0: ldo1 { + regulator-name = "vreg_l1f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l2f_1p0: ldo2 { + regulator-name = "vreg_l2f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l3f_1p0: ldo3 { + regulator-name = "vreg_l3f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "i"; + + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + + vreg_s1i_0p9: smps1 { + regulator-name = "vreg_s1i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_s2i_1p0: smps2 { + regulator-name = "vreg_s2i_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1i_1p8: ldo1 { + regulator-name = "vreg_l1i_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "j"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vph_pwr>; + + vreg_s5j_1p2: smps5 { + regulator-name = "vreg_s5j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l1j_0p8: ldo1 { + regulator-name = "vreg_l1j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2j_1p2: ldo2 { + regulator-name = "vreg_l2j_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3j_0p8: ldo3 { + regulator-name = "vreg_l3j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; +}; + +&qupv3_2 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <34 2>, /* Unused */ + <44 4>, /* SPI (TPM) */ + <238 1>; /* UFS Reset */ + + edp_reg_en: edp-reg-en-state { + pins = "gpio70"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; +}; + +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; From e6fe33c66d69385a67b1b03f93641aa264fbb75a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Nov 2023 16:50:58 -0700 Subject: [PATCH 3327/7721] dt-bindings: hisilicon: Merge hi3620-clock into hisilicon,sysctrl binding The hi3620-clock binding is simple and always a child of the "hisilicon,sysctrl" node, so just add it into the hisilicon,sysctrl binding and drop the old txt binding. Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Signed-off-by: Wei Xu --- .../arm/hisilicon/controller/sysctrl.yaml | 17 ++++++++++++++++ .../bindings/clock/hi3620-clock.txt | 20 ------------------- 2 files changed, 17 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt diff --git a/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml b/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml index 5a53d433b6f0..7a221e1c09df 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml +++ b/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml @@ -82,6 +82,23 @@ properties: ranges: true +patternProperties: + '^clock@': + type: object + additionalProperties: false + + properties: + compatible: + enum: + - hisilicon,hi3620-clock + - hisilicon,hi3620-mmc-clock + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt deleted file mode 100644 index dad6269f52c5..000000000000 --- a/Documentation/devicetree/bindings/clock/hi3620-clock.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Hisilicon Hi3620 Clock Controller - -The Hi3620 clock controller generates and supplies clock to various -controllers within the Hi3620 SoC. - -Required Properties: - -- compatible: should be one of the following. - - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. - - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc. - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifier could be found in . From 44ab3ee76a5a977864ba0bb6c352dcf6206804e0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Nov 2023 18:56:34 +0100 Subject: [PATCH 3328/7721] arm64: dts: hisilicon: hikey970-pmic: fix regulator cells properties The Hi6421 PMIC regulator child nodes do not have unit addresses so drop the incorrect '#address-cells' and '#size-cells' properties. Fixes: 6219b20e1ecd ("arm64: dts: hisilicon: Add support for Hikey 970 PMIC") Signed-off-by: Johan Hovold Signed-off-by: Wei Xu --- arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi index 970047f2dabd..c06e011a6c3f 100644 --- a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi @@ -25,9 +25,6 @@ pmic: pmic@0 { gpios = <&gpio28 0 0>; regulators { - #address-cells = <1>; - #size-cells = <0>; - ldo3: ldo3 { /* HDMI */ regulator-name = "ldo3"; regulator-min-microvolt = <1500000>; From 94fa073377db02ef0ca391f32e11e0f4649b2657 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Nov 2023 18:56:35 +0100 Subject: [PATCH 3329/7721] arm64: dts: hisilicon: hikey970-pmic: clean up SPMI node Clean up the SPMI node by dropping the redundant status property and moving the 'reg' property after 'compatible' for consistency. Signed-off-by: Johan Hovold Signed-off-by: Wei Xu --- arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi index c06e011a6c3f..299c4ab630e8 100644 --- a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi @@ -10,10 +10,9 @@ / { spmi: spmi@fff24000 { compatible = "hisilicon,kirin970-spmi-controller"; + reg = <0x0 0xfff24000 0x0 0x1000>; #address-cells = <2>; #size-cells = <0>; - status = "okay"; - reg = <0x0 0xfff24000 0x0 0x1000>; hisilicon,spmi-channel = <2>; pmic: pmic@0 { From ee25fba76acd8324f9de6628872c8c612a684209 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:00 +0100 Subject: [PATCH 3330/7721] gpiolib: provide gpiochip_dup_line_label() gpiochip_is_requested() not only has a misleading name but it returns a pointer to a string that is freed when the descriptor is released. Provide a new helper meant to replace it, which returns a copy of the label string instead. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/gpiolib.c | 29 +++++++++++++++++++++++++++++ include/linux/gpio/driver.h | 1 + 2 files changed, 30 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 95d2a7b2ea3e..0147c900afea 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2386,6 +2386,35 @@ const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset) } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +/** + * gpiochip_dup_line_label - Get a copy of the consumer label. + * @gc: GPIO chip controlling this line. + * @offset: Hardware offset of the line. + * + * Returns: + * Pointer to a copy of the consumer label if the line is requested or NULL + * if it's not. If a valid pointer was returned, it must be freed using + * kfree(). In case of a memory allocation error, the function returns %ENOMEM. + * + * Must not be called from atomic context. + */ +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) +{ + const char *label; + char *copy; + + label = gpiochip_is_requested(gc, offset); + if (!label) + return NULL; + + copy = kstrdup(label, GFP_KERNEL); + if (!copy) + return ERR_PTR(-ENOMEM); + + return copy; +} +EXPORT_SYMBOL_GPL(gpiochip_dup_line_label); + /** * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor * @gc: GPIO chip diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 0aed62f0c633..5ac6dc30c547 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -532,6 +532,7 @@ struct gpio_chip { }; const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset); +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset); /** * for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range From 1610cd5f7468d4d8b54a96b82109c6ae66ee24eb Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:01 +0100 Subject: [PATCH 3331/7721] gpio: wm831x: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/gpio-wm831x.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 7eaf8a28638c..f7d5120ff8f1 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -160,18 +161,21 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++) { int gpio = i + chip->base; int reg; - const char *label, *pull, *powerdomain; + const char *pull, *powerdomain; /* We report the GPIO even if it's not requested since * we're also reporting things like alternate * functions which apply even when the GPIO is not in * use as a GPIO. */ - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) { + dev_err(wm831x->dev, "Failed to duplicate label\n"); + continue; + } - seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); + seq_printf(s, " gpio-%-3d (%-20.20s) ", + gpio, label ?: "Unrequested"); reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); if (reg < 0) { From abeec1ad51da0aa7cd33005f537e54c2422d1218 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:02 +0100 Subject: [PATCH 3332/7721] gpio: wm8994: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/gpio-wm8994.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index f4a474cef32d..bf05c9b5882b 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -193,18 +194,20 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++) { int gpio = i + chip->base; int reg; - const char *label; /* We report the GPIO even if it's not requested since * we're also reporting things like alternate * functions which apply even when the GPIO is not in * use as a GPIO. */ - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) { + dev_err(wm8994->dev, "Failed to duplicate label\n"); + continue; + } - seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); + seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, + label ?: "Unrequested"); reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i); if (reg < 0) { From f1b33ce48ae77a04021ea0a5dab09f67315cad44 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:03 +0100 Subject: [PATCH 3333/7721] gpio: stmpe: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/gpio-stmpe.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 27cc4da53565..6c5ee81d71b3 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -5,6 +5,7 @@ * Author: Rabin Vincent for ST-Ericsson */ +#include #include #include #include @@ -255,7 +256,6 @@ static void stmpe_dbg_show_one(struct seq_file *s, { struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; - const char *label = gpiochip_is_requested(gc, offset); bool val = !!stmpe_gpio_get(gc, offset); u8 bank = offset / 8; u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank]; @@ -263,6 +263,10 @@ static void stmpe_dbg_show_one(struct seq_file *s, int ret; u8 dir; + char *label __free(kfree) = gpiochip_dup_line_label(gc, offset); + if (IS_ERR(label)) + return; + ret = stmpe_reg_read(stmpe, dir_reg); if (ret < 0) return; From c76ba937f5ff9b4ee670adbd421be2404745be1f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:04 +0100 Subject: [PATCH 3334/7721] pinctrl: abx500: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index d3c32d809bac..80e3ac333136 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -6,7 +6,9 @@ * * Driver allows to use AxB5xx unused pins to be used as GPIO */ + #include +#include #include #include #include @@ -453,12 +455,11 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s, unsigned offset, unsigned gpio) { struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); - const char *label = gpiochip_is_requested(chip, offset - 1); u8 gpio_offset = offset - 1; int mode = -1; bool is_out; bool pd; - int ret; + int ret = -ENOMEM; const char *modes[] = { [ABX500_DEFAULT] = "default", @@ -474,6 +475,10 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s, [ABX500_GPIO_PULL_UP] = "pull up", }; + char *label __free(kfree) = gpiochip_dup_line_label(chip, offset - 1); + if (IS_ERR(label)) + goto out; + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out); if (ret < 0) From caf7e135c297e6fceec0a1476da775aa458b5324 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:05 +0100 Subject: [PATCH 3335/7721] pinctrl: nomadik: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 863732287b1e..7911353ac97d 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -8,6 +8,7 @@ * Copyright (C) 2011-2013 Linus Walleij */ #include +#include #include #include #include @@ -917,7 +918,6 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned offset, unsigned gpio) { - const char *label = gpiochip_is_requested(chip, offset); struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); int mode; bool is_out; @@ -934,6 +934,10 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, [NMK_GPIO_ALT_C+4] = "altC4", }; + char *label = gpiochip_dup_line_label(chip, offset); + if (IS_ERR(label)) + return; + clk_enable(nmk_chip->clk); is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset)); pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & BIT(offset)); From c73505c8a001f8ce63b8ad92c9cd0176fe3c22a4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:06 +0100 Subject: [PATCH 3336/7721] pinctrl: baytrail: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-baytrail.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 3cd0798ee631..3c8c02043481 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1173,7 +1174,6 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) const char *pull_str = NULL; const char *pull = NULL; unsigned long flags; - const char *label; unsigned int pin; pin = vg->soc->pins[i].number; @@ -1200,9 +1200,10 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, "Pin %i: can't retrieve community\n", pin); continue; } - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; + + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) + continue; switch (conf0 & BYT_PULL_ASSIGN_MASK) { case BYT_PULL_ASSIGN_UP: @@ -1231,7 +1232,7 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s", pin, - label, + label ?: "Unrequested", val & BYT_INPUT_EN ? " " : "in", val & BYT_OUTPUT_EN ? " " : "out", str_hi_lo(val & BYT_LEVEL), From 069ced2206d23e56b89ed118e17a8a71a05e0ca3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:07 +0100 Subject: [PATCH 3337/7721] pinctrl: sppctl: use gpiochip_dup_line_label() Use the new gpiochip_dup_line_label() helper to safely retrieve the descriptor label. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/pinctrl/sunplus/sppctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/sunplus/sppctl.c b/drivers/pinctrl/sunplus/sppctl.c index bb5ef391dbe4..ae156f779a16 100644 --- a/drivers/pinctrl/sunplus/sppctl.c +++ b/drivers/pinctrl/sunplus/sppctl.c @@ -4,6 +4,7 @@ * Copyright (C) Sunplus Tech / Tibbo Tech. */ +#include #include #include #include @@ -500,16 +501,15 @@ static int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset, static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { - const char *label; int i; for (i = 0; i < chip->ngpio; i++) { - label = gpiochip_is_requested(chip, i); - if (!label) - label = ""; + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) + continue; seq_printf(s, " gpio-%03d (%-16.16s | %-16.16s)", i + chip->base, - chip->names[i], label); + chip->names[i], label ?: ""); seq_printf(s, " %c", sppctl_gpio_get_direction(chip, i) ? 'I' : 'O'); seq_printf(s, ":%d", sppctl_gpio_get(chip, i)); seq_printf(s, " %s", sppctl_first_get(chip, i) ? "gpi" : "mux"); From 6fd9c9933475a3efd7eed2f80c7778908a560a1f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:08 +0100 Subject: [PATCH 3338/7721] gpiolib: use gpiochip_dup_line_label() in for_each helpers Rework for_each_requested_gpio_in_range() to use the new helper to retrieve a dynamically allocated copy of the descriptor label and free it at the end of each iteration. We need to leverage the CLASS()' destructor to make sure that the label is freed even when breaking out of the loop. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- include/linux/gpio/driver.h | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5ac6dc30c547..cae4cdaa87db 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -534,17 +534,38 @@ struct gpio_chip { const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset); char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset); + +struct _gpiochip_for_each_data { + const char **label; + unsigned int *i; +}; + +DEFINE_CLASS(_gpiochip_for_each_data, + struct _gpiochip_for_each_data, + if (*_T.label) kfree(*_T.label), + ({ + struct _gpiochip_for_each_data _data = { label, i }; + *_data.i = 0; + _data; + }), + const char **label, int *i) + /** * for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range - * @chip: the chip to query - * @i: loop variable - * @base: first GPIO in the range - * @size: amount of GPIOs to check starting from @base - * @label: label of current GPIO + * @_chip: the chip to query + * @_i: loop variable + * @_base: first GPIO in the range + * @_size: amount of GPIOs to check starting from @base + * @_label: label of current GPIO */ -#define for_each_requested_gpio_in_range(chip, i, base, size, label) \ - for (i = 0; i < size; i++) \ - if ((label = gpiochip_is_requested(chip, base + i)) == NULL) {} else +#define for_each_requested_gpio_in_range(_chip, _i, _base, _size, _label) \ + for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \ + *_data.i < _size; \ + (*_data.i)++, kfree(*(_data.label)), *_data.label = NULL) \ + if ((*_data.label = \ + gpiochip_dup_line_label(_chip, _base + *_data.i)) == NULL) {} \ + else if (IS_ERR(*_data.label)) {} \ + else /* Iterates over all requested GPIO of the given @chip */ #define for_each_requested_gpio(chip, i, label) \ From f8d05e276b45e3097dfddd628fa991ce69c05c99 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 10:35:09 +0100 Subject: [PATCH 3339/7721] gpiolib: remove gpiochip_is_requested() We have no external users of gpiochip_is_requested(). Let's remove it and replace its internal calls with direct testing of the REQUESTED flag. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/gpiolib.c | 48 ++++++++++--------------------------- include/linux/gpio/driver.h | 1 - 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0147c900afea..0ca33397812c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1071,7 +1071,7 @@ void gpiochip_remove(struct gpio_chip *gc) spin_lock_irqsave(&gpio_lock, flags); for (i = 0; i < gdev->ngpio; i++) { - if (gpiochip_is_requested(gc, i)) + if (test_bit(FLAG_REQUESTED, &gdev->descs[i].flags)) break; } spin_unlock_irqrestore(&gpio_lock, flags); @@ -2359,33 +2359,6 @@ void gpiod_free(struct gpio_desc *desc) gpio_device_put(desc->gdev); } -/** - * gpiochip_is_requested - return string iff signal was requested - * @gc: controller managing the signal - * @offset: of signal within controller's 0..(ngpio - 1) range - * - * Returns NULL if the GPIO is not currently requested, else a string. - * The string returned is the label passed to gpio_request(); if none has been - * passed it is a meaningless, non-NULL constant. - * - * This function is for use by GPIO controller drivers. The label can - * help with diagnostics, and knowing that the signal is used as a GPIO - * can help avoid accidentally multiplexing it to another controller. - */ -const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset) -{ - struct gpio_desc *desc; - - desc = gpiochip_get_desc(gc, offset); - if (IS_ERR(desc)) - return NULL; - - if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) - return NULL; - return desc->label; -} -EXPORT_SYMBOL_GPL(gpiochip_is_requested); - /** * gpiochip_dup_line_label - Get a copy of the consumer label. * @gc: GPIO chip controlling this line. @@ -2400,18 +2373,23 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); */ char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) { - const char *label; - char *copy; + struct gpio_desc *desc; + char *label; - label = gpiochip_is_requested(gc, offset); - if (!label) + desc = gpiochip_get_desc(gc, offset); + if (IS_ERR(desc)) return NULL; - copy = kstrdup(label, GFP_KERNEL); - if (!copy) + guard(spinlock_irqsave)(&gpio_lock); + + if (!test_bit(FLAG_REQUESTED, &desc->flags)) + return NULL; + + label = kstrdup(desc->label, GFP_KERNEL); + if (!label) return ERR_PTR(-ENOMEM); - return copy; + return label; } EXPORT_SYMBOL_GPL(gpiochip_dup_line_label); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index cae4cdaa87db..d1a3cb061927 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -531,7 +531,6 @@ struct gpio_chip { #endif /* CONFIG_OF_GPIO */ }; -const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset); char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset); From d22f93c6a0df15b9d1f500ab57d97ecc99b3657a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 4 Dec 2023 09:57:19 +0100 Subject: [PATCH 3340/7721] gpio: sim: implement the dbg_show() callback Provide a custom implementation of the dbg_show() callback that prints all requested lines together with their label, direction, value and bias. This improves the code coverage of GPIOLIB. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sim.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 1e8b92e9df80..c4106e37e6db 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +226,25 @@ static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) } } +static void gpio_sim_dbg_show(struct seq_file *seq, struct gpio_chip *gc) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + const char *label; + int i; + + guard(mutex)(&chip->lock); + + for_each_requested_gpio(gc, i, label) + seq_printf(seq, " gpio-%-3d (%s) %s,%s\n", + gc->base + i, + label, + test_bit(i, chip->direction_map) ? "input" : + test_bit(i, chip->value_map) ? "output-high" : + "output-low", + test_bit(i, chip->pull_map) ? "pull-up" : + "pull-down"); +} + static ssize_t gpio_sim_sysfs_val_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -460,6 +481,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->to_irq = gpio_sim_to_irq; gc->request = gpio_sim_request; gc->free = gpio_sim_free; + gc->dbg_show = PTR_IF(IS_ENABLED(CONFIG_DEBUG_FS), gpio_sim_dbg_show); gc->can_sleep = true; ret = devm_gpiochip_add_data(dev, gc, chip); From 91478b772fb525da8a6541231e6e0eb016f941c3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 12:12:13 +0200 Subject: [PATCH 3341/7721] media: ccs: Select V4L2_CCI_I2C Select V4L2_CCI_I2C Kconfig option which the CCS driver now depends on. Fixes: 529322112a3b ("media: ccs: Use V4L2 CCI for accessing sensor registers") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312060941.CYiHppAp-lkp@intel.com/ Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/ccs/Kconfig b/drivers/media/i2c/ccs/Kconfig index b55c93a2e204..710a729ae42d 100644 --- a/drivers/media/i2c/ccs/Kconfig +++ b/drivers/media/i2c/ccs/Kconfig @@ -2,6 +2,7 @@ config VIDEO_CCS tristate "MIPI CCS/SMIA++/SMIA sensor support" depends on HAVE_CLK + select V4L2_CCI_I2C select VIDEO_CCS_PLL help This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant From c692696fc51c5acee555b94d391d328510b557c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 13:35:33 +0200 Subject: [PATCH 3342/7721] media: saa6752hs: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/saa6752hs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 51b62a97946a..897eaa669b86 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -594,10 +594,8 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd, f->field = V4L2_FIELD_INTERLACED; f->colorspace = V4L2_COLORSPACE_SMPTE170M; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_state_get_format(sd_state, 0) = *f; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - } /* FIXME: translate and round width/height into EMPRESS From dff1eebf2be36278d2669504ad9249f1d7505bc0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 19:20:19 +0200 Subject: [PATCH 3343/7721] media: adv7183: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/adv7183.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index bcb99ba9a272..2a2cace4a153 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -442,8 +442,6 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd, } if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) decoder->fmt = *fmt; - else - *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; return 0; } From 72c8cb48a4cc05e8132725250b801326966c5c93 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 19:22:03 +0200 Subject: [PATCH 3344/7721] media: mt9t112: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9t112.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 2e2d9853c089..fb1588c57cc8 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -982,7 +982,6 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9t112_s_fmt(sd, mf); - *v4l2_subdev_state_get_format(sd_state, 0) = *mf; return 0; } From 09aee3995f9eea712b7b372421ce85b79d5c2adb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 19:22:43 +0200 Subject: [PATCH 3345/7721] media: rj54n1cb0c: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/rj54n1cb0c.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c index 403185b18f06..a59db10153cd 100644 --- a/drivers/media/i2c/rj54n1cb0c.c +++ b/drivers/media/i2c/rj54n1cb0c.c @@ -1008,10 +1008,8 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_state_get_format(sd_state, 0) = *mf; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - } /* * Verify if the sensor has just been powered on. TODO: replace this From 843750fb85fda6111c78e5c40e5ca5bc7dde6d10 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 19:24:11 +0200 Subject: [PATCH 3346/7721] media: tw9910: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/tw9910.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 7c331a7f12d4..905af98c7d53 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -829,8 +829,6 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return tw9910_s_fmt(sd, mf); - *v4l2_subdev_state_get_format(sd_state, 0) = *mf; - return 0; } From e55a9482888da73eeadde5f13ef8bafce68a38ed Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Dec 2023 19:25:07 +0200 Subject: [PATCH 3347/7721] media: ov9640: Don't set format in sub-device state For the purpose of setting old non-pad based sub-device try format as a basis for VIDIOC_TRY_FMT implementation, there is no need to set the format in the sub-device state. Drop the assignment to the state, which would result in a NULL pointer dereference. Fixes: fd17e3a9a788 ("media: i2c: Use accessors for pad config 'try_*' fields") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9640.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index b0c171fe75bc..e9a52a8a9dc0 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -547,8 +547,6 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return ov9640_s_fmt(sd, mf); - *v4l2_subdev_state_get_format(sd_state, 0) = *mf; - return 0; } From 66f011145b835f9a68af9d7156c8d84a6f29c331 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 8 Dec 2023 04:03:13 +0300 Subject: [PATCH 3348/7721] drm/atomic-helper: rename drm_atomic_helper_check_wb_encoder_state The drm_atomic_helper_check_wb_encoder_state() function doesn't use encoder for anything other than getting the drm_device instance. The function's description talks about checking the writeback connector state, not the encoder state. Moreover, there is no such thing as an encoder state, encoders generally do not have a state on their own. Rename the function to drm_atomic_helper_check_wb_connector_state() and change arguments to drm_writeback_connector and drm_atomic_state. Signed-off-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231208010314.3395904-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_atomic_helper.c | 16 +++++++++------- drivers/gpu/drm/vkms/vkms_writeback.c | 3 ++- include/drm/drm_atomic_helper.h | 5 ++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3f677130def..c98a766ca3bd 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -795,9 +795,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** - * drm_atomic_helper_check_wb_encoder_state() - Check writeback encoder state - * @encoder: encoder state to check - * @conn_state: connector state to check + * drm_atomic_helper_check_wb_connector_state() - Check writeback connector state + * @connector: corresponding connector + * @state: the driver state object * * Checks if the writeback connector state is valid, and returns an error if it * isn't. @@ -806,9 +806,11 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * Zero for success or -errno */ int -drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder, - struct drm_connector_state *conn_state) +drm_atomic_helper_check_wb_connector_state(struct drm_connector *connector, + struct drm_atomic_state *state) { + struct drm_connector_state *conn_state = + drm_atomic_get_new_connector_state(state, connector); struct drm_writeback_job *wb_job = conn_state->writeback_job; struct drm_property_blob *pixel_format_blob; struct drm_framebuffer *fb; @@ -827,11 +829,11 @@ drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder, if (fb->format->format == formats[i]) return 0; - drm_dbg_kms(encoder->dev, "Invalid pixel format %p4cc\n", &fb->format->format); + drm_dbg_kms(connector->dev, "Invalid pixel format %p4cc\n", &fb->format->format); return -EINVAL; } -EXPORT_SYMBOL(drm_atomic_helper_check_wb_encoder_state); +EXPORT_SYMBOL(drm_atomic_helper_check_wb_connector_state); /** * drm_atomic_helper_check_plane_state() - Check plane state for validity diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index d7e63aa14663..fef7f3daf2c9 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -34,6 +34,7 @@ static int vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_connector *connector = conn_state->connector; struct drm_framebuffer *fb; const struct drm_display_mode *mode = &crtc_state->mode; int ret; @@ -48,7 +49,7 @@ static int vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, return -EINVAL; } - ret = drm_atomic_helper_check_wb_encoder_state(encoder, conn_state); + ret = drm_atomic_helper_check_wb_connector_state(connector, conn_state->state); if (ret < 0) return ret; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 536a0b0091c3..fea528aacfe2 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -49,9 +49,8 @@ struct drm_private_state; int drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_atomic_state *state); -int -drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder, - struct drm_connector_state *conn_state); +int drm_atomic_helper_check_wb_connector_state(struct drm_connector *connector, + struct drm_atomic_state *state); int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, const struct drm_crtc_state *crtc_state, int min_scale, From aa8ec5d7b26d820dfad2f7668e9dd9edff7ebd7d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 8 Dec 2023 04:03:14 +0300 Subject: [PATCH 3349/7721] drm/vkms: move wb's atomic_check from encoder to connector As the renamed drm_atomic_helper_check_wb_connector_state() now accepts drm_writeback_connector as the first argument (instead of drm_encoder), move the VKMS writeback atomic_check from drm_encoder_helper_funcs to drm_connector_helper_funcs. Also drop the vkms_wb_encoder_helper_funcs, which have become empty now. Signed-off-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231208010314.3395904-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/vkms/vkms_writeback.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index fef7f3daf2c9..bc724cbd5e3a 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -30,18 +30,25 @@ static const struct drm_connector_funcs vkms_wb_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static int vkms_wb_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) { - struct drm_connector *connector = conn_state->connector; + struct drm_connector_state *conn_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_crtc_state *crtc_state; struct drm_framebuffer *fb; - const struct drm_display_mode *mode = &crtc_state->mode; + const struct drm_display_mode *mode; int ret; if (!conn_state->writeback_job || !conn_state->writeback_job->fb) return 0; + if (!conn_state->crtc) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + mode = &crtc_state->mode; + fb = conn_state->writeback_job->fb; if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", @@ -49,17 +56,13 @@ static int vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, return -EINVAL; } - ret = drm_atomic_helper_check_wb_connector_state(connector, conn_state->state); + ret = drm_atomic_helper_check_wb_connector_state(connector, state); if (ret < 0) return ret; return 0; } -static const struct drm_encoder_helper_funcs vkms_wb_encoder_helper_funcs = { - .atomic_check = vkms_wb_encoder_atomic_check, -}; - static int vkms_wb_connector_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -162,6 +165,7 @@ static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = { .prepare_writeback_job = vkms_wb_prepare_job, .cleanup_writeback_job = vkms_wb_cleanup_job, .atomic_commit = vkms_wb_atomic_commit, + .atomic_check = vkms_wb_atomic_check, }; int vkms_enable_writeback_connector(struct vkms_device *vkmsdev) @@ -172,7 +176,7 @@ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev) return drm_writeback_connector_init(&vkmsdev->drm, wb, &vkms_wb_connector_funcs, - &vkms_wb_encoder_helper_funcs, + NULL, vkms_wb_formats, ARRAY_SIZE(vkms_wb_formats), 1); From b84135e7a5921a79e3dc0cc1bbfbe9c3c661c8d0 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 8 Dec 2023 08:30:34 +0800 Subject: [PATCH 3350/7721] drm/imagination: Remove unneeded semicolon ./drivers/gpu/drm/imagination/pvr_fw_trace.c:251:2-3: Unneeded semicolon Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=7694 Signed-off-by: Yang Li Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231208003034.68339-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/imagination/pvr_fw_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 7159fc479001..31199e45b72e 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -248,7 +248,7 @@ static bool fw_trace_get_next(struct pvr_fw_trace_seq_data *trace_seq_data) continue; return true; - }; + } /* Hit end of trace data. */ return false; From fca9448ae2f5ddebd841c727ee86136e1b5cbd86 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Dec 2023 17:37:24 +0300 Subject: [PATCH 3351/7721] drm/imagination: Move dereference after NULL check in pvr_mmu_backing_page_init() This code dereferences "page->pvr_dev" and then checked for NULL on the next line. Re-order it to avoid a potential NULL pointer dereference. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Dan Carpenter Reviewed-by: Frank Binns Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/13f4278e-af9c-4092-9196-bc0e6b76f1eb@moroto.mountain --- drivers/gpu/drm/imagination/pvr_mmu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c index c8562bfc0dcd..4fe70610ed94 100644 --- a/drivers/gpu/drm/imagination/pvr_mmu.c +++ b/drivers/gpu/drm/imagination/pvr_mmu.c @@ -316,12 +316,14 @@ pvr_mmu_backing_page_init(struct pvr_mmu_backing_page *page, static void pvr_mmu_backing_page_fini(struct pvr_mmu_backing_page *page) { - struct device *dev = from_pvr_device(page->pvr_dev)->dev; + struct device *dev; /* Do nothing if no allocation is present. */ if (!page->pvr_dev) return; + dev = from_pvr_device(page->pvr_dev)->dev; + dma_unmap_page(dev, page->dma_addr, PVR_MMU_BACKING_PAGE_SIZE, DMA_TO_DEVICE); From 2a48c635fd9a48699805bbfeee1e4b94b8fe819d Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Wed, 6 Dec 2023 23:16:10 +0000 Subject: [PATCH 3352/7721] ethtool: Implement ethtool_puts() Use strscpy() to implement ethtool_puts(). Functionally the same as ethtool_sprintf() when it's used with two arguments or with just "%s" format specifier. Signed-off-by: Justin Stitt Reviewed-by: Przemek Kitszel Reviewed-by: Andrew Lunn Reviewed-by: Madhuri Sripada Signed-off-by: David S. Miller --- include/linux/ethtool.h | 13 +++++++++++++ net/ethtool/ioctl.c | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c2bb74143eda..deb683d3360f 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -1061,6 +1061,19 @@ int ethtool_get_ts_info_by_layer(struct net_device *dev, struct ethtool_ts_info */ extern __printf(2, 3) void ethtool_sprintf(u8 **data, const char *fmt, ...); +/** + * ethtool_puts - Write string to ethtool string data + * @data: Pointer to a pointer to the start of string to update + * @str: String to write + * + * Write string to *data without a trailing newline. Update *data + * to point at start of next string. + * + * Prefer this function to ethtool_sprintf() when given only + * two arguments or if @fmt is just "%s". + */ +extern void ethtool_puts(u8 **data, const char *str); + /* Link mode to forced speed capabilities maps */ struct ethtool_forced_speed_map { u32 speed; diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index a977f8903467..755a4be01bef 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1994,6 +1994,13 @@ __printf(2, 3) void ethtool_sprintf(u8 **data, const char *fmt, ...) } EXPORT_SYMBOL(ethtool_sprintf); +void ethtool_puts(u8 **data, const char *str) +{ + strscpy(*data, str, ETH_GSTRING_LEN); + *data += ETH_GSTRING_LEN; +} +EXPORT_SYMBOL(ethtool_puts); + static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) { struct ethtool_value id; From 9b5f621cea6eff2f75b851c6c62cefbdb1673c44 Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Wed, 6 Dec 2023 23:16:11 +0000 Subject: [PATCH 3353/7721] checkpatch: add ethtool_sprintf rules Add some warnings for using ethtool_sprintf() where a simple ethtool_puts() would suffice. The two cases are: 1) Use ethtool_sprintf() with just two arguments: | ethtool_sprintf(&data, driver[i].name); or 2) Use ethtool_sprintf() with a standalone "%s" fmt string: | ethtool_sprintf(&data, "%s", driver[i].name); The former may cause -Wformat-security warnings while the latter is just not preferred. Both are safely in the category of warnings, not errors. Signed-off-by: Justin Stitt Reviewed-by: Przemek Kitszel Signed-off-by: David S. Miller --- scripts/checkpatch.pl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 25fdb7fda112..6924731110d8 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -7011,6 +7011,25 @@ sub process { "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr); } +# ethtool_sprintf uses that should likely be ethtool_puts + if ($line =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { + if (WARN("PREFER_ETHTOOL_PUTS", + "Prefer ethtool_puts over ethtool_sprintf with only two arguments\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; + } + } + + # use $rawline because $line loses %s via sanitization and thus we can't match against it. + if ($rawline =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*\"\%s\"\s*,\s*$FuncArg\s*\)/) { + if (WARN("PREFER_ETHTOOL_PUTS", + "Prefer ethtool_puts over ethtool_sprintf with standalone \"%s\" specifier\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*"\%s"\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; + } + } + + # typecasts on min/max could be min_t/max_t if ($perl_version_ok && defined $stat && From e403cffff1a46ab1a95d3bc72e92634445d68328 Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Wed, 6 Dec 2023 23:16:12 +0000 Subject: [PATCH 3354/7721] net: Convert some ethtool_sprintf() to ethtool_puts() This patch converts some basic cases of ethtool_sprintf() to ethtool_puts(). The conversions are used in cases where ethtool_sprintf() was being used with just two arguments: | ethtool_sprintf(&data, buffer[i].name); or when it's used with format string: "%s" | ethtool_sprintf(&data, "%s", buffer[i].name); which both now become: | ethtool_puts(&data, buffer[i].name); Signed-off-by: Justin Stitt Reviewed-by: Wei Fang Reviewed-by: Andrew Lunn Reviewed-by: Louis Peens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 2 +- drivers/net/dsa/mt7530.c | 2 +- drivers/net/dsa/qca/qca8k-common.c | 2 +- drivers/net/dsa/realtek/rtl8365mb.c | 2 +- drivers/net/dsa/realtek/rtl8366-core.c | 2 +- drivers/net/dsa/vitesse-vsc73xx-core.c | 8 +-- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 4 +- .../net/ethernet/brocade/bna/bnad_ethtool.c | 2 +- drivers/net/ethernet/freescale/fec_main.c | 4 +- .../ethernet/fungible/funeth/funeth_ethtool.c | 8 +-- .../ethernet/hisilicon/hns/hns_dsaf_gmac.c | 2 +- .../ethernet/hisilicon/hns/hns_dsaf_xgmac.c | 2 +- .../net/ethernet/hisilicon/hns/hns_ethtool.c | 63 +++++++++---------- .../net/ethernet/intel/i40e/i40e_ethtool.c | 6 +- .../net/ethernet/intel/iavf/iavf_ethtool.c | 3 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 9 +-- .../net/ethernet/intel/idpf/idpf_ethtool.c | 2 +- drivers/net/ethernet/intel/igb/igb_ethtool.c | 6 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 6 +- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 5 +- .../microchip/sparx5/sparx5_ethtool.c | 2 +- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 42 ++++++------- .../net/ethernet/pensando/ionic/ionic_stats.c | 4 +- .../net/ethernet/wangxun/libwx/wx_ethtool.c | 2 +- drivers/net/hyperv/netvsc_drv.c | 4 +- drivers/net/phy/nxp-tja11xx.c | 2 +- drivers/net/phy/smsc.c | 2 +- drivers/net/vmxnet3/vmxnet3_ethtool.c | 10 +-- 28 files changed, 98 insertions(+), 110 deletions(-) diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 9c185c9f0963..05a017c9ef3d 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1759,7 +1759,7 @@ static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset, return; for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) - ethtool_sprintf(&data, "%s", gswip_rmon_cnt[i].name); + ethtool_puts(&data, gswip_rmon_cnt[i].name); } static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table, diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index d27c6b70a2f6..391c4dbdff42 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -836,7 +836,7 @@ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset, return; for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) - ethtool_sprintf(&data, "%s", mt7530_mib[i].name); + ethtool_puts(&data, mt7530_mib[i].name); } static void diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 9243eff8918d..2358cd399c7e 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -487,7 +487,7 @@ void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, return; for (i = 0; i < priv->info->mib_count; i++) - ethtool_sprintf(&data, "%s", ar8327_mib[i].name); + ethtool_puts(&data, ar8327_mib[i].name); } void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 0875e4fc9f57..b072045eb154 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -1303,7 +1303,7 @@ static void rtl8365mb_get_strings(struct dsa_switch *ds, int port, u32 stringset for (i = 0; i < RTL8365MB_MIB_END; i++) { struct rtl8365mb_mib_counter *mib = &rtl8365mb_mib_counters[i]; - ethtool_sprintf(&data, "%s", mib->name); + ethtool_puts(&data, mib->name); } } diff --git a/drivers/net/dsa/realtek/rtl8366-core.c b/drivers/net/dsa/realtek/rtl8366-core.c index 82e267b8fddb..59f98d2c8769 100644 --- a/drivers/net/dsa/realtek/rtl8366-core.c +++ b/drivers/net/dsa/realtek/rtl8366-core.c @@ -401,7 +401,7 @@ void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, return; for (i = 0; i < priv->num_mib_counters; i++) - ethtool_sprintf(&data, "%s", priv->mib_counters[i].name); + ethtool_puts(&data, priv->mib_counters[i].name); } EXPORT_SYMBOL_GPL(rtl8366_get_strings); diff --git a/drivers/net/dsa/vitesse-vsc73xx-core.c b/drivers/net/dsa/vitesse-vsc73xx-core.c index e6f29e4e508c..dd50502e2122 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-core.c +++ b/drivers/net/dsa/vitesse-vsc73xx-core.c @@ -949,7 +949,7 @@ static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset, indices[5] = ((val >> 26) & 0x1f); /* TX counter 2 */ /* The first counters is the RX octets */ - ethtool_sprintf(&buf, "RxEtherStatsOctets"); + ethtool_puts(&buf, "RxEtherStatsOctets"); /* Each port supports recording 3 RX counters and 3 TX counters, * figure out what counters we use in this set-up and return the @@ -959,15 +959,15 @@ static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset, */ for (i = 0; i < 3; i++) { cnt = vsc73xx_find_counter(vsc, indices[i], false); - ethtool_sprintf(&buf, "%s", cnt ? cnt->name : ""); + ethtool_puts(&buf, cnt ? cnt->name : ""); } /* TX stats begins with the number of TX octets */ - ethtool_sprintf(&buf, "TxEtherStatsOctets"); + ethtool_puts(&buf, "TxEtherStatsOctets"); for (i = 3; i < 6; i++) { cnt = vsc73xx_find_counter(vsc, indices[i], true); - ethtool_sprintf(&buf, "%s", cnt ? cnt->name : ""); + ethtool_puts(&buf, cnt ? cnt->name : ""); } } diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index d671df4b76bc..e3ef081aa42b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -299,13 +299,13 @@ static void ena_get_strings(struct ena_adapter *adapter, for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) { ena_stats = &ena_stats_global_strings[i]; - ethtool_sprintf(&data, ena_stats->name); + ethtool_puts(&data, ena_stats->name); } if (eni_stats_needed) { for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) { ena_stats = &ena_stats_eni_strings[i]; - ethtool_sprintf(&data, ena_stats->name); + ethtool_puts(&data, ena_stats->name); } } diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c index df10edff5603..d1ad6c9f8140 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c +++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c @@ -608,7 +608,7 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string) for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) { BUG_ON(!(strlen(bnad_net_stats_strings[i]) < ETH_GSTRING_LEN)); - ethtool_sprintf(&string, bnad_net_stats_strings[i]); + ethtool_puts(&string, bnad_net_stats_strings[i]); } bmap = bna_tx_rid_mask(&bnad->bna); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index c3b7694a7485..bae9536de767 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2932,10 +2932,10 @@ static void fec_enet_get_strings(struct net_device *netdev, switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(fec_stats); i++) { - ethtool_sprintf(&data, "%s", fec_stats[i].name); + ethtool_puts(&data, fec_stats[i].name); } for (i = 0; i < ARRAY_SIZE(fec_xdp_stat_strs); i++) { - ethtool_sprintf(&data, "%s", fec_xdp_stat_strs[i]); + ethtool_puts(&data, fec_xdp_stat_strs[i]); } page_pool_ethtool_stats_get_strings(data); diff --git a/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c b/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c index 31aa185f4d17..091c93bd7587 100644 --- a/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c +++ b/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c @@ -655,7 +655,7 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data) i); } for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++) - ethtool_sprintf(&p, txq_stat_names[j]); + ethtool_puts(&p, txq_stat_names[j]); for (i = 0; i < fp->num_xdpqs; i++) { for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++) @@ -663,7 +663,7 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data) xdpq_stat_names[j], i); } for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++) - ethtool_sprintf(&p, xdpq_stat_names[j]); + ethtool_puts(&p, xdpq_stat_names[j]); for (i = 0; i < netdev->real_num_rx_queues; i++) { for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++) @@ -671,10 +671,10 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data) i); } for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++) - ethtool_sprintf(&p, rxq_stat_names[j]); + ethtool_puts(&p, rxq_stat_names[j]); for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++) - ethtool_sprintf(&p, tls_stat_names[j]); + ethtool_puts(&p, tls_stat_names[j]); break; default: break; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 8f391e2adcc0..bdb7afaabdd0 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -678,7 +678,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data) return; for (i = 0; i < ARRAY_SIZE(g_gmac_stats_string); i++) - ethtool_sprintf(&buff, g_gmac_stats_string[i].desc); + ethtool_puts(&buff, g_gmac_stats_string[i].desc); } static int hns_gmac_get_sset_count(int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c index fc26ffaae620..c58833eb4830 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c @@ -752,7 +752,7 @@ static void hns_xgmac_get_strings(u32 stringset, u8 *data) return; for (i = 0; i < ARRAY_SIZE(g_xgmac_stats_string); i++) - ethtool_sprintf(&buff, g_xgmac_stats_string[i].desc); + ethtool_puts(&buff, g_xgmac_stats_string[i].desc); } /** diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index b54f3706fb97..fe40cceb0f79 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -912,42 +912,41 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data) if (stringset == ETH_SS_TEST) { if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII) - ethtool_sprintf(&buff, - hns_nic_test_strs[MAC_INTERNALLOOP_MAC]); - ethtool_sprintf(&buff, - hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); + ethtool_puts(&buff, + hns_nic_test_strs[MAC_INTERNALLOOP_MAC]); + ethtool_puts(&buff, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); if ((netdev->phydev) && (!netdev->phydev->is_c45)) - ethtool_sprintf(&buff, - hns_nic_test_strs[MAC_INTERNALLOOP_PHY]); + ethtool_puts(&buff, + hns_nic_test_strs[MAC_INTERNALLOOP_PHY]); } else { - ethtool_sprintf(&buff, "rx_packets"); - ethtool_sprintf(&buff, "tx_packets"); - ethtool_sprintf(&buff, "rx_bytes"); - ethtool_sprintf(&buff, "tx_bytes"); - ethtool_sprintf(&buff, "rx_errors"); - ethtool_sprintf(&buff, "tx_errors"); - ethtool_sprintf(&buff, "rx_dropped"); - ethtool_sprintf(&buff, "tx_dropped"); - ethtool_sprintf(&buff, "multicast"); - ethtool_sprintf(&buff, "collisions"); - ethtool_sprintf(&buff, "rx_over_errors"); - ethtool_sprintf(&buff, "rx_crc_errors"); - ethtool_sprintf(&buff, "rx_frame_errors"); - ethtool_sprintf(&buff, "rx_fifo_errors"); - ethtool_sprintf(&buff, "rx_missed_errors"); - ethtool_sprintf(&buff, "tx_aborted_errors"); - ethtool_sprintf(&buff, "tx_carrier_errors"); - ethtool_sprintf(&buff, "tx_fifo_errors"); - ethtool_sprintf(&buff, "tx_heartbeat_errors"); - ethtool_sprintf(&buff, "rx_length_errors"); - ethtool_sprintf(&buff, "tx_window_errors"); - ethtool_sprintf(&buff, "rx_compressed"); - ethtool_sprintf(&buff, "tx_compressed"); - ethtool_sprintf(&buff, "netdev_rx_dropped"); - ethtool_sprintf(&buff, "netdev_tx_dropped"); + ethtool_puts(&buff, "rx_packets"); + ethtool_puts(&buff, "tx_packets"); + ethtool_puts(&buff, "rx_bytes"); + ethtool_puts(&buff, "tx_bytes"); + ethtool_puts(&buff, "rx_errors"); + ethtool_puts(&buff, "tx_errors"); + ethtool_puts(&buff, "rx_dropped"); + ethtool_puts(&buff, "tx_dropped"); + ethtool_puts(&buff, "multicast"); + ethtool_puts(&buff, "collisions"); + ethtool_puts(&buff, "rx_over_errors"); + ethtool_puts(&buff, "rx_crc_errors"); + ethtool_puts(&buff, "rx_frame_errors"); + ethtool_puts(&buff, "rx_fifo_errors"); + ethtool_puts(&buff, "rx_missed_errors"); + ethtool_puts(&buff, "tx_aborted_errors"); + ethtool_puts(&buff, "tx_carrier_errors"); + ethtool_puts(&buff, "tx_fifo_errors"); + ethtool_puts(&buff, "tx_heartbeat_errors"); + ethtool_puts(&buff, "rx_length_errors"); + ethtool_puts(&buff, "tx_window_errors"); + ethtool_puts(&buff, "rx_compressed"); + ethtool_puts(&buff, "tx_compressed"); + ethtool_puts(&buff, "netdev_rx_dropped"); + ethtool_puts(&buff, "netdev_tx_dropped"); - ethtool_sprintf(&buff, "netdev_tx_timeout"); + ethtool_puts(&buff, "netdev_tx_timeout"); h->dev->ops->get_strings(h, stringset, buff); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index eb9a7b32af73..a0b10230268d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2523,13 +2523,11 @@ static void i40e_get_priv_flag_strings(struct net_device *netdev, u8 *data) u8 *p = data; for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) - ethtool_sprintf(&p, "%s", - i40e_gstrings_priv_flags[i].flag_string); + ethtool_puts(&p, i40e_gstrings_priv_flags[i].flag_string); if (pf->hw.pf_id != 0) return; for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++) - ethtool_sprintf(&p, "%s", - i40e_gl_gstrings_priv_flags[i].flag_string); + ethtool_puts(&p, i40e_gl_gstrings_priv_flags[i].flag_string); } static void i40e_get_strings(struct net_device *netdev, u32 stringset, diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index f520855daf58..631c7cfdc814 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -396,8 +396,7 @@ static void iavf_get_priv_flag_strings(struct net_device *netdev, u8 *data) unsigned int i; for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) - ethtool_sprintf(&data, "%s", - iavf_gstrings_priv_flags[i].flag_string); + ethtool_puts(&data, iavf_gstrings_priv_flags[i].flag_string); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index a34083567e6f..98c9317581e0 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1142,8 +1142,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data, switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ICE_VSI_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - ice_gstrings_vsi_stats[i].stat_string); + ethtool_puts(&p, ice_gstrings_vsi_stats[i].stat_string); if (ice_is_port_repr_netdev(netdev)) return; @@ -1162,8 +1161,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data, return; for (i = 0; i < ICE_PF_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - ice_gstrings_pf_stats[i].stat_string); + ethtool_puts(&p, ice_gstrings_pf_stats[i].stat_string); for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { ethtool_sprintf(&p, "tx_priority_%u_xon.nic", i); @@ -1179,8 +1177,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data, break; case ETH_SS_PRIV_FLAGS: for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) - ethtool_sprintf(&p, "%s", - ice_gstrings_priv_flags[i].name); + ethtool_puts(&p, ice_gstrings_priv_flags[i].name); break; default: break; diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 52ea38669f85..bf58989a573e 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -532,7 +532,7 @@ static void idpf_add_stat_strings(u8 **p, const struct idpf_stats *stats, unsigned int i; for (i = 0; i < size; i++) - ethtool_sprintf(p, "%s", stats[i].stat_string); + ethtool_puts(p, stats[i].stat_string); } /** diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 16d2a55d5e17..89dac7b215e5 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2356,11 +2356,9 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) break; case ETH_SS_STATS: for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - igb_gstrings_stats[i].stat_string); + ethtool_puts(&p, igb_gstrings_stats[i].stat_string); for (i = 0; i < IGB_NETDEV_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - igb_gstrings_net_stats[i].stat_string); + ethtool_puts(&p, igb_gstrings_net_stats[i].stat_string); for (i = 0; i < adapter->num_tx_queues; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); ethtool_sprintf(&p, "tx_queue_%u_bytes", i); diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 785eaa8e0ba8..2ed92bf34059 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -773,11 +773,9 @@ static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset, break; case ETH_SS_STATS: for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - igc_gstrings_stats[i].stat_string); + ethtool_puts(&p, igc_gstrings_stats[i].stat_string); for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - igc_gstrings_net_stats[i].stat_string); + ethtool_puts(&p, igc_gstrings_net_stats[i].stat_string); for (i = 0; i < adapter->num_tx_queues; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); ethtool_sprintf(&p, "tx_queue_%u_bytes", i); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 4dd897806fa5..dd722b0381e0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1413,12 +1413,11 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, switch (stringset) { case ETH_SS_TEST: for (i = 0; i < IXGBE_TEST_LEN; i++) - ethtool_sprintf(&p, "%s", ixgbe_gstrings_test[i]); + ethtool_puts(&p, ixgbe_gstrings_test[i]); break; case ETH_SS_STATS: for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) - ethtool_sprintf(&p, "%s", - ixgbe_gstrings_stats[i].stat_string); + ethtool_puts(&p, ixgbe_gstrings_stats[i].stat_string); for (i = 0; i < netdev->num_tx_queues; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); ethtool_sprintf(&p, "tx_queue_%u_bytes", i); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c index 37d2584b48a7..a06dc5a9b355 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c @@ -1012,7 +1012,7 @@ static void sparx5_get_sset_strings(struct net_device *ndev, u32 sset, u8 *data) return; for (idx = 0; idx < sparx5->num_ethtool_stats; idx++) - ethtool_sprintf(&data, "%s", sparx5->stats_layout[idx]); + ethtool_puts(&data, sparx5->stats_layout[idx]); } static void sparx5_get_sset_data(struct net_device *ndev, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index f4f6153cae0f..ff9f39969215 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -807,7 +807,7 @@ static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data) for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) if (nfp_self_test[i].is_supported(netdev)) - ethtool_sprintf(&data, nfp_self_test[i].name); + ethtool_puts(&data, nfp_self_test[i].name); } static int nfp_get_self_test_count(struct net_device *netdev) @@ -859,24 +859,24 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data) ethtool_sprintf(&data, "rvec_%u_tx_busy", i); } - ethtool_sprintf(&data, "hw_rx_csum_ok"); - ethtool_sprintf(&data, "hw_rx_csum_inner_ok"); - ethtool_sprintf(&data, "hw_rx_csum_complete"); - ethtool_sprintf(&data, "hw_rx_csum_err"); - ethtool_sprintf(&data, "rx_replace_buf_alloc_fail"); - ethtool_sprintf(&data, "rx_tls_decrypted_packets"); - ethtool_sprintf(&data, "hw_tx_csum"); - ethtool_sprintf(&data, "hw_tx_inner_csum"); - ethtool_sprintf(&data, "tx_gather"); - ethtool_sprintf(&data, "tx_lso"); - ethtool_sprintf(&data, "tx_tls_encrypted_packets"); - ethtool_sprintf(&data, "tx_tls_ooo"); - ethtool_sprintf(&data, "tx_tls_drop_no_sync_data"); + ethtool_puts(&data, "hw_rx_csum_ok"); + ethtool_puts(&data, "hw_rx_csum_inner_ok"); + ethtool_puts(&data, "hw_rx_csum_complete"); + ethtool_puts(&data, "hw_rx_csum_err"); + ethtool_puts(&data, "rx_replace_buf_alloc_fail"); + ethtool_puts(&data, "rx_tls_decrypted_packets"); + ethtool_puts(&data, "hw_tx_csum"); + ethtool_puts(&data, "hw_tx_inner_csum"); + ethtool_puts(&data, "tx_gather"); + ethtool_puts(&data, "tx_lso"); + ethtool_puts(&data, "tx_tls_encrypted_packets"); + ethtool_puts(&data, "tx_tls_ooo"); + ethtool_puts(&data, "tx_tls_drop_no_sync_data"); - ethtool_sprintf(&data, "hw_tls_no_space"); - ethtool_sprintf(&data, "rx_tls_resync_req_ok"); - ethtool_sprintf(&data, "rx_tls_resync_req_ign"); - ethtool_sprintf(&data, "rx_tls_resync_sent"); + ethtool_puts(&data, "hw_tls_no_space"); + ethtool_puts(&data, "rx_tls_resync_req_ok"); + ethtool_puts(&data, "rx_tls_resync_req_ign"); + ethtool_puts(&data, "rx_tls_resync_sent"); return data; } @@ -950,13 +950,13 @@ nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int num_vecs, bool repr) swap_off = repr * NN_ET_SWITCH_STATS_LEN; for (i = 0; i < NN_ET_SWITCH_STATS_LEN; i++) - ethtool_sprintf(&data, nfp_net_et_stats[i + swap_off].name); + ethtool_puts(&data, nfp_net_et_stats[i + swap_off].name); for (i = NN_ET_SWITCH_STATS_LEN; i < NN_ET_SWITCH_STATS_LEN * 2; i++) - ethtool_sprintf(&data, nfp_net_et_stats[i - swap_off].name); + ethtool_puts(&data, nfp_net_et_stats[i - swap_off].name); for (i = NN_ET_SWITCH_STATS_LEN * 2; i < NN_ET_GLOBAL_STATS_LEN; i++) - ethtool_sprintf(&data, nfp_net_et_stats[i].name); + ethtool_puts(&data, nfp_net_et_stats[i].name); for (i = 0; i < num_vecs; i++) { ethtool_sprintf(&data, "rxq_%u_pkts", i); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index 9859a4432985..1f6022fb7679 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -258,10 +258,10 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf) int i, q_num; for (i = 0; i < IONIC_NUM_LIF_STATS; i++) - ethtool_sprintf(buf, ionic_lif_stats_desc[i].name); + ethtool_puts(buf, ionic_lif_stats_desc[i].name); for (i = 0; i < IONIC_NUM_PORT_STATS; i++) - ethtool_sprintf(buf, ionic_port_stats_desc[i].name); + ethtool_puts(buf, ionic_port_stats_desc[i].name); for (q_num = 0; q_num < MAX_Q(lif); q_num++) ionic_sw_stats_get_tx_strings(lif, buf, q_num); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c index ddc5f6d20b9c..6e9e5f01c152 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c @@ -75,7 +75,7 @@ void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) - ethtool_sprintf(&p, wx_gstrings_stats[i].stat_string); + ethtool_puts(&p, wx_gstrings_stats[i].stat_string); for (i = 0; i < netdev->num_tx_queues; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); ethtool_sprintf(&p, "tx_queue_%u_bytes", i); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 706ea5263e87..1e2fa0ec2327 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1582,10 +1582,10 @@ static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++) - ethtool_sprintf(&p, netvsc_stats[i].name); + ethtool_puts(&p, netvsc_stats[i].name); for (i = 0; i < ARRAY_SIZE(vf_stats); i++) - ethtool_sprintf(&p, vf_stats[i].name); + ethtool_puts(&p, vf_stats[i].name); for (i = 0; i < nvdev->num_chn; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c index a71399965142..2c263ae44b4f 100644 --- a/drivers/net/phy/nxp-tja11xx.c +++ b/drivers/net/phy/nxp-tja11xx.c @@ -415,7 +415,7 @@ static void tja11xx_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) - ethtool_sprintf(&data, "%s", tja11xx_hw_stats[i].string); + ethtool_puts(&data, tja11xx_hw_stats[i].string); } static void tja11xx_get_stats(struct phy_device *phydev, diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 1c7306a1af13..150aea7c9c36 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -508,7 +508,7 @@ static void smsc_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) - ethtool_sprintf(&data, "%s", smsc_hw_stats[i].string); + ethtool_puts(&data, smsc_hw_stats[i].string); } static u64 smsc_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 98c22d7d87a2..8f5f202cde39 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -245,20 +245,20 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) for (j = 0; j < adapter->num_tx_queues; j++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) - ethtool_sprintf(&buf, vmxnet3_tq_dev_stats[i].desc); + ethtool_puts(&buf, vmxnet3_tq_dev_stats[i].desc); for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) - ethtool_sprintf(&buf, vmxnet3_tq_driver_stats[i].desc); + ethtool_puts(&buf, vmxnet3_tq_driver_stats[i].desc); } for (j = 0; j < adapter->num_rx_queues; j++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) - ethtool_sprintf(&buf, vmxnet3_rq_dev_stats[i].desc); + ethtool_puts(&buf, vmxnet3_rq_dev_stats[i].desc); for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) - ethtool_sprintf(&buf, vmxnet3_rq_driver_stats[i].desc); + ethtool_puts(&buf, vmxnet3_rq_driver_stats[i].desc); } for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) - ethtool_sprintf(&buf, vmxnet3_global_stats[i].desc); + ethtool_puts(&buf, vmxnet3_global_stats[i].desc); } netdev_features_t vmxnet3_fix_features(struct net_device *netdev, From 34880b18733efff60b68d074ff74d018ffc309a7 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 5 Dec 2023 14:09:37 +0100 Subject: [PATCH 3355/7721] drm/i915/selftests: wait for active idle event in i915_active_unlock_wait After i915_active_unlock_wait i915_active can be still non-idle due to barrier async handling in signal_irq_work. As a result one can observe following errors: bcs0: heartbeat pulse did not flush idle tasks *ERROR* pulse active pulse_active [i915]:pulse_retire [i915] *ERROR* pulse count: 0 *ERROR* pulse preallocated barriers? no To prevent it let's wait explicitly for idleness. v2: wait only in live_idle tests Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20231205-selftest_wait_for_active_idle_event-v2-1-1437d0bf9829@intel.com --- drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index 273d440a53e3..bc441ce7b380 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -84,7 +84,7 @@ static struct pulse *pulse_create(void) static void pulse_unlock_wait(struct pulse *p) { - i915_active_unlock_wait(&p->active); + wait_var_event_timeout(&p->active, i915_active_is_idle(&p->active), HZ); } static int __live_idle_pulse(struct intel_engine_cs *engine, From be5bcc4be9d9d3ae294072441a66fe39b74e5bba Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Wed, 6 Dec 2023 19:43:22 +0100 Subject: [PATCH 3356/7721] drm/i915/guc: Create the guc_to_i915() wrapper Given a reference to "guc", the guc_to_i915() returns the pointer to "i915" private data. Signed-off-by: Andi Shyti Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20231206184322.57111-1-andi.shyti@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_gt.h | 5 +++++ drivers/gpu/drm/i915/gt/uc/intel_guc.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_log.c | 10 +++++----- drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 4 ++-- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 9ffdb05e231e..2f81c1c79238 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -118,6 +118,11 @@ static inline struct intel_gt *gsc_to_gt(struct intel_gsc *gsc) return container_of(gsc, struct intel_gt, gsc); } +static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) +{ + return guc_to_gt(guc)->i915; +} + void intel_gt_common_init_early(struct intel_gt *gt); int intel_root_gt_init_early(struct drm_i915_private *i915); int intel_gt_assign_ggtt(struct intel_gt *gt); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 3f3df1166b86..2b450c43bbd7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -330,7 +330,7 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) static u32 guc_ctl_devid(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); return (INTEL_DEVID(i915) << 16) | INTEL_REVID(i915); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index a4da0208c883..a1cd40d80517 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -355,7 +355,7 @@ guc_capture_alloc_steered_lists(struct intel_guc *guc, static const struct __guc_mmio_reg_descr_group * guc_capture_get_device_reglist(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); const struct __guc_mmio_reg_descr_group *lists; if (GRAPHICS_VER(i915) >= 12) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index ed6ce73ef3b0..0d5197c0824a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -265,7 +265,7 @@ int intel_guc_ct_init(struct intel_guc_ct *ct) u32 *cmds; int err; - err = i915_inject_probe_error(guc_to_gt(guc)->i915, -ENXIO); + err = i915_inject_probe_error(guc_to_i915(guc), -ENXIO); if (err) return err; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index 55bc8b55fbc0..bf16351c9349 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -520,7 +520,7 @@ void intel_guc_log_init_early(struct intel_guc_log *log) static int guc_log_relay_create(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); struct rchan *guc_log_relay_chan; size_t n_subbufs, subbuf_size; int ret; @@ -573,7 +573,7 @@ static void guc_log_relay_destroy(struct intel_guc_log *log) static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); intel_wakeref_t wakeref; _guc_log_copy_debuglogs_for_relay(log); @@ -589,7 +589,7 @@ static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log) static u32 __get_default_log_level(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); /* A negative value means "use platform/config default" */ if (i915->params.guc_log_level < 0) { @@ -664,7 +664,7 @@ void intel_guc_log_destroy(struct intel_guc_log *log) int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); intel_wakeref_t wakeref; int ret = 0; @@ -796,7 +796,7 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) static void guc_log_relay_stop(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); if (!log->relay.started) return; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c index 1adec6de223c..9df7927304ae 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c @@ -14,7 +14,7 @@ static bool __guc_rc_supported(struct intel_guc *guc) { /* GuC RC is unavailable for pre-Gen12 */ return guc->submission_supported && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 12; + GRAPHICS_VER(guc_to_i915(guc)) >= 12; } static bool __guc_rc_selected(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index 2dfb07cc4b33..3e681ab6fbf9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -34,7 +34,7 @@ static bool __detect_slpc_supported(struct intel_guc *guc) { /* GuC SLPC is unavailable for pre-Gen12 */ return guc->submission_supported && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 12; + GRAPHICS_VER(guc_to_i915(guc)) >= 12; } static bool __guc_slpc_selected(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 58ea285c51d4..a259f1118c5a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -4626,12 +4626,12 @@ static bool __guc_submission_supported(struct intel_guc *guc) { /* GuC submission is unavailable for pre-Gen11 */ return intel_guc_is_supported(guc) && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 11; + GRAPHICS_VER(guc_to_i915(guc)) >= 11; } static bool __guc_submission_selected(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); if (!intel_guc_submission_is_supported(guc)) return false; From 4624a78c18c62da815f3253966b7a87995f77e1b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:53 +0800 Subject: [PATCH 3357/7721] selftests/net: convert test_bridge_backup_port.sh to run it in unique namespace There is no h1 h2 actually. Remove it. Here is the test result after conversion. ]# ./test_bridge_backup_port.sh Backup port ----------- TEST: Forwarding out of swp1 [ OK ] TEST: No forwarding out of vx0 [ OK ] TEST: swp1 carrier off [ OK ] TEST: No forwarding out of swp1 [ OK ] ... Backup nexthop ID - ping ------------------------ TEST: Ping with backup nexthop ID [ OK ] TEST: Ping after disabling backup nexthop ID [ OK ] Backup nexthop ID - torture test -------------------------------- TEST: Torture test [ OK ] Tests passed: 83 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/test_bridge_backup_port.sh | 371 +++++++++--------- 1 file changed, 182 insertions(+), 189 deletions(-) diff --git a/tools/testing/selftests/net/test_bridge_backup_port.sh b/tools/testing/selftests/net/test_bridge_backup_port.sh index 112cfd8a10ad..70a7d87ba2d2 100755 --- a/tools/testing/selftests/net/test_bridge_backup_port.sh +++ b/tools/testing/selftests/net/test_bridge_backup_port.sh @@ -35,9 +35,8 @@ # | sw1 | | sw2 | # +------------------------------------+ +------------------------------------+ +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 # All tests in this script. Can be overridden with -t option. TESTS=" @@ -132,9 +131,6 @@ setup_topo_ns() { local ns=$1; shift - ip netns add $ns - ip -n $ns link set dev lo up - ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1 ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0 @@ -145,13 +141,14 @@ setup_topo() { local ns - for ns in sw1 sw2; do + setup_ns sw1 sw2 + for ns in $sw1 $sw2; do setup_topo_ns $ns done ip link add name veth0 type veth peer name veth1 - ip link set dev veth0 netns sw1 name veth0 - ip link set dev veth1 netns sw2 name veth0 + ip link set dev veth0 netns $sw1 name veth0 + ip link set dev veth1 netns $sw2 name veth0 } setup_sw_common() @@ -190,7 +187,7 @@ setup_sw_common() setup_sw1() { - local ns=sw1 + local ns=$sw1 local local_addr=192.0.2.33 local remote_addr=192.0.2.34 local veth_addr=192.0.2.49 @@ -203,7 +200,7 @@ setup_sw1() setup_sw2() { - local ns=sw2 + local ns=$sw2 local local_addr=192.0.2.34 local remote_addr=192.0.2.33 local veth_addr=192.0.2.50 @@ -229,11 +226,7 @@ setup() cleanup() { - local ns - - for ns in h1 h2 sw1 sw2; do - ip netns del $ns &> /dev/null - done + cleanup_ns $sw1 $sw2 } ################################################################################ @@ -248,85 +241,85 @@ backup_port() echo "Backup port" echo "-----------" - run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" - run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" + run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" - run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" # Initial state - check that packets are forwarded out of swp1 when it # has a carrier and not forwarded out of any port when it does not have # a carrier. - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 1 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 1 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 0 + tc_check_packets $sw1 "dev vx0 egress" 101 0 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 1 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 1 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 0 + tc_check_packets $sw1 "dev vx0 egress" 101 0 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier on" + run_cmd "ip -n $sw1 link set dev swp1 carrier on" log_test $? 0 "swp1 carrier on" # Configure vx0 as the backup port of swp1 and check that packets are # forwarded out of swp1 when it has a carrier and out of vx0 when swp1 # does not have a carrier. - run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" log_test $? 0 "vx0 configured as backup port of swp1" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 2 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 2 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 0 + tc_check_packets $sw1 "dev vx0 egress" 101 0 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 2 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 2 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "Forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier on" + run_cmd "ip -n $sw1 link set dev swp1 carrier on" log_test $? 0 "swp1 carrier on" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 3 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 3 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "No forwarding out of vx0" # Remove vx0 as the backup port of swp1 and check that packets are no # longer forwarded out of vx0 when swp1 does not have a carrier. - run_cmd "bridge -n sw1 link set dev swp1 nobackup_port" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + run_cmd "bridge -n $sw1 link set dev swp1 nobackup_port" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" log_test $? 1 "vx0 not configured as backup port of swp1" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 4 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 4 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 4 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 4 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "No forwarding out of vx0" } @@ -339,125 +332,125 @@ backup_nhid() echo "Backup nexthop ID" echo "-----------------" - run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" - run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" + run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" - run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" + run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" - run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" - run_cmd "bridge -n sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010" + run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010" - run_cmd "ip -n sw2 address replace 192.0.2.36/32 dev lo" + run_cmd "ip -n $sw2 address replace 192.0.2.36/32 dev lo" # The first filter matches on packets forwarded using the backup # nexthop ID and the second filter matches on packets forwarded using a # regular VXLAN FDB entry. - run_cmd "tc -n sw2 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" - run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass" + run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" + run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass" # Configure vx0 as the backup port of swp1 and check that packets are # forwarded out of swp1 when it has a carrier and out of vx0 when swp1 # does not have a carrier. When packets are forwarded out of vx0, check # that they are forwarded by the VXLAN FDB entry. - run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" log_test $? 0 "vx0 configured as backup port of swp1" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 1 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 1 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 0 + tc_check_packets $sw1 "dev vx0 egress" 101 0 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 1 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 1 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 0 + tc_check_packets $sw2 "dev vx0 ingress" 101 0 log_test $? 0 "No forwarding using backup nexthop ID" - tc_check_packets sw2 "dev vx0 ingress" 102 1 + tc_check_packets $sw2 "dev vx0 ingress" 102 1 log_test $? 0 "Forwarding using VXLAN FDB entry" - run_cmd "ip -n sw1 link set dev swp1 carrier on" + run_cmd "ip -n $sw1 link set dev swp1 carrier on" log_test $? 0 "swp1 carrier on" # Configure nexthop ID 10 as the backup nexthop ID of swp1 and check # that when packets are forwarded out of vx0, they are forwarded using # the backup nexthop ID. - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" log_test $? 0 "nexthop ID 10 configured as backup nexthop ID of swp1" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 2 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 2 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "No forwarding out of vx0" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 2 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 2 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "Forwarding using backup nexthop ID" - tc_check_packets sw2 "dev vx0 ingress" 102 1 + tc_check_packets $sw2 "dev vx0 ingress" 102 1 log_test $? 0 "No forwarding using VXLAN FDB entry" - run_cmd "ip -n sw1 link set dev swp1 carrier on" + run_cmd "ip -n $sw1 link set dev swp1 carrier on" log_test $? 0 "swp1 carrier on" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 3 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 3 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "No forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - tc_check_packets sw2 "dev vx0 ingress" 102 1 + tc_check_packets $sw2 "dev vx0 ingress" 102 1 log_test $? 0 "No forwarding using VXLAN FDB entry" # Reset the backup nexthop ID to 0 and check that packets are no longer # forwarded using the backup nexthop ID when swp1 does not have a # carrier and are instead forwarded by the VXLAN FDB. - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid\"" log_test $? 1 "No backup nexthop ID configured for swp1" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 4 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 4 log_test $? 0 "Forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "No forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - tc_check_packets sw2 "dev vx0 ingress" 102 1 + tc_check_packets $sw2 "dev vx0 ingress" 102 1 log_test $? 0 "No forwarding using VXLAN FDB entry" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 4 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 4 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - tc_check_packets sw2 "dev vx0 ingress" 102 2 + tc_check_packets $sw2 "dev vx0 ingress" 102 2 log_test $? 0 "Forwarding using VXLAN FDB entry" } @@ -475,109 +468,109 @@ backup_nhid_invalid() # is forwarded out of the VXLAN port, but dropped by the VXLAN driver # and does not crash the host. - run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" - run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" + run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" # Drop all other Tx traffic to avoid changes to Tx drop counter. - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop" - tx_drop=$(ip -n sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]') + tx_drop=$(ip -n $sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]') - run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" + run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" - run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" - run_cmd "tc -n sw2 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" + run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" # First, check that redirection works. - run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" log_test $? 0 "vx0 configured as backup port of swp1" - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" log_test $? 0 "Valid nexthop as backup nexthop" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" log_test $? 0 "swp1 carrier off" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 0 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 0 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "Forwarding using backup nexthop ID" - run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'" + run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'" log_test $? 0 "No Tx drop increase" # Use a non-existent nexthop ID. - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 20" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 20\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 20" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 20\"" log_test $? 0 "Non-existent nexthop as backup nexthop" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 0 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 0 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'" + run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'" log_test $? 0 "Tx drop increased" # Use a blckhole nexthop. - run_cmd "ip -n sw1 nexthop replace id 30 blackhole" - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 30" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 30\"" + run_cmd "ip -n $sw1 nexthop replace id 30 blackhole" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 30" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 30\"" log_test $? 0 "Blackhole nexthop as backup nexthop" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 0 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 0 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'" + run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'" log_test $? 0 "Tx drop increased" # Non-group FDB nexthop. - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 1" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 1\"" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 1" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 1\"" log_test $? 0 "Non-group FDB nexthop as backup nexthop" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 0 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 0 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 4 + tc_check_packets $sw1 "dev vx0 egress" 101 4 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'" + run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'" log_test $? 0 "Tx drop increased" # IPv6 address family nexthop. - run_cmd "ip -n sw1 nexthop replace id 100 via 2001:db8:100::1 fdb" - run_cmd "ip -n sw1 nexthop replace id 200 via 2001:db8:100::1 fdb" - run_cmd "ip -n sw1 nexthop replace id 300 group 100/200 fdb" - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 300" - run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 300\"" + run_cmd "ip -n $sw1 nexthop replace id 100 via 2001:db8:100::1 fdb" + run_cmd "ip -n $sw1 nexthop replace id 200 via 2001:db8:100::1 fdb" + run_cmd "ip -n $sw1 nexthop replace id 300 group 100/200 fdb" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 300" + run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 300\"" log_test $? 0 "IPv6 address family nexthop as backup nexthop" - run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets sw1 "dev swp1 egress" 101 0 + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 0 log_test $? 0 "No forwarding out of swp1" - tc_check_packets sw1 "dev vx0 egress" 101 5 + tc_check_packets $sw1 "dev vx0 egress" 101 5 log_test $? 0 "Forwarding out of vx0" - tc_check_packets sw2 "dev vx0 ingress" 101 1 + tc_check_packets $sw2 "dev vx0 ingress" 101 1 log_test $? 0 "No forwarding using backup nexthop ID" - run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'" + run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'" log_test $? 0 "Tx drop increased" } @@ -591,44 +584,44 @@ backup_nhid_ping() echo "------------------------" # Test bidirectional traffic when traffic is redirected in both VTEPs. - sw1_mac=$(ip -n sw1 -j -p link show br0.10 | jq -r '.[]["address"]') - sw2_mac=$(ip -n sw2 -j -p link show br0.10 | jq -r '.[]["address"]') + sw1_mac=$(ip -n $sw1 -j -p link show br0.10 | jq -r '.[]["address"]') + sw2_mac=$(ip -n $sw2 -j -p link show br0.10 | jq -r '.[]["address"]') - run_cmd "bridge -n sw1 fdb replace $sw2_mac dev swp1 master static vlan 10" - run_cmd "bridge -n sw2 fdb replace $sw1_mac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw1 fdb replace $sw2_mac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw2 fdb replace $sw1_mac dev swp1 master static vlan 10" - run_cmd "ip -n sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10" - run_cmd "ip -n sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10" + run_cmd "ip -n $sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10" + run_cmd "ip -n $sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10" - run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" - run_cmd "ip -n sw2 nexthop replace id 1 via 192.0.2.33 fdb" - run_cmd "ip -n sw1 nexthop replace id 10 group 1 fdb" - run_cmd "ip -n sw2 nexthop replace id 10 group 1 fdb" + run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" + run_cmd "ip -n $sw2 nexthop replace id 1 via 192.0.2.33 fdb" + run_cmd "ip -n $sw1 nexthop replace id 10 group 1 fdb" + run_cmd "ip -n $sw2 nexthop replace id 10 group 1 fdb" - run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw2 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" - run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 10" + run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw2 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" + run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10" - run_cmd "ip -n sw1 link set dev swp1 carrier off" - run_cmd "ip -n sw2 link set dev swp1 carrier off" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" + run_cmd "ip -n $sw2 link set dev swp1 carrier off" - run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" + run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" log_test $? 0 "Ping with backup nexthop ID" # Reset the backup nexthop ID to 0 and check that ping fails. - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0" - run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 0" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0" + run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 0" - run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" + run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" log_test $? 1 "Ping after disabling backup nexthop ID" } backup_nhid_add_del_loop() { while true; do - ip -n sw1 nexthop del id 10 - ip -n sw1 nexthop replace id 10 group 1/2 fdb + ip -n $sw1 nexthop del id 10 + ip -n $sw1 nexthop replace id 10 group 1/2 fdb done >/dev/null 2>&1 } @@ -648,19 +641,19 @@ backup_nhid_torture() # deleting the group. The test is considered successful if nothing # crashed. - run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" - run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" + run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" + run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" - run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" + run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" - run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" - run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" - run_cmd "ip -n sw1 link set dev swp1 carrier off" + run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" + run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" + run_cmd "ip -n $sw1 link set dev swp1 carrier off" backup_nhid_add_del_loop & pid1=$! - ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 & + ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 & pid2=$! sleep 30 From 312abe3d93a35f9c486a4703d39cab52457266f0 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:54 +0800 Subject: [PATCH 3358/7721] selftests/net: convert test_bridge_neigh_suppress.sh to run it in unique namespace Here is the test result after conversion. ]# ./test_bridge_neigh_suppress.sh Per-port ARP suppression - VLAN 10 ---------------------------------- TEST: arping [ OK ] TEST: ARP suppression [ OK ] ... TEST: NS suppression (VLAN 20) [ OK ] Tests passed: 148 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../net/test_bridge_neigh_suppress.sh | 331 +++++++++--------- 1 file changed, 162 insertions(+), 169 deletions(-) diff --git a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh index d80f2cd87614..8533393a4f18 100755 --- a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh +++ b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh @@ -45,9 +45,8 @@ # | sw1 | | sw2 | # +------------------------------------+ +------------------------------------+ +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 # All tests in this script. Can be overridden with -t option. TESTS=" @@ -140,9 +139,6 @@ setup_topo_ns() { local ns=$1; shift - ip netns add $ns - ip -n $ns link set dev lo up - ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1 ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0 @@ -153,21 +149,22 @@ setup_topo() { local ns - for ns in h1 h2 sw1 sw2; do + setup_ns h1 h2 sw1 sw2 + for ns in $h1 $h2 $sw1 $sw2; do setup_topo_ns $ns done ip link add name veth0 type veth peer name veth1 - ip link set dev veth0 netns h1 name eth0 - ip link set dev veth1 netns sw1 name swp1 + ip link set dev veth0 netns $h1 name eth0 + ip link set dev veth1 netns $sw1 name swp1 ip link add name veth0 type veth peer name veth1 - ip link set dev veth0 netns sw1 name veth0 - ip link set dev veth1 netns sw2 name veth0 + ip link set dev veth0 netns $sw1 name veth0 + ip link set dev veth1 netns $sw2 name veth0 ip link add name veth0 type veth peer name veth1 - ip link set dev veth0 netns h2 name eth0 - ip link set dev veth1 netns sw2 name swp1 + ip link set dev veth0 netns $h2 name eth0 + ip link set dev veth1 netns $sw2 name swp1 } setup_host_common() @@ -190,7 +187,7 @@ setup_host_common() setup_h1() { - local ns=h1 + local ns=$h1 local v4addr1=192.0.2.1/28 local v4addr2=192.0.2.17/28 local v6addr1=2001:db8:1::1/64 @@ -201,7 +198,7 @@ setup_h1() setup_h2() { - local ns=h2 + local ns=$h2 local v4addr1=192.0.2.2/28 local v4addr2=192.0.2.18/28 local v6addr1=2001:db8:1::2/64 @@ -254,7 +251,7 @@ setup_sw_common() setup_sw1() { - local ns=sw1 + local ns=$sw1 local local_addr=192.0.2.33 local remote_addr=192.0.2.34 local veth_addr=192.0.2.49 @@ -265,7 +262,7 @@ setup_sw1() setup_sw2() { - local ns=sw2 + local ns=$sw2 local local_addr=192.0.2.34 local remote_addr=192.0.2.33 local veth_addr=192.0.2.50 @@ -291,11 +288,7 @@ setup() cleanup() { - local ns - - for ns in h1 h2 sw1 sw2; do - ip netns del $ns &> /dev/null - done + cleanup_ns $h1 $h2 $sw1 $sw2 } ################################################################################ @@ -312,80 +305,80 @@ neigh_suppress_arp_common() echo "Per-port ARP suppression - VLAN $vid" echo "----------------------------------" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip $sip arp_op request action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip $sip arp_op request action pass" # Initial state - check that ARP requests are not suppressed and that # ARP replies are received. - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "ARP suppression" # Enable neighbor suppression and check that nothing changes compared # to the initial state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "ARP suppression" # Install an FDB entry for the remote host and check that nothing # changes compared to the initial state. - h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') - run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" + h2_mac=$(ip -n $h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') + run_cmd "bridge -n $sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" log_test $? 0 "FDB entry installation" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "ARP suppression" # Install a neighbor on the matching SVI interface and check that ARP # requests are suppressed. - run_cmd "ip -n sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid" + run_cmd "ip -n $sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid" log_test $? 0 "Neighbor entry installation" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "ARP suppression" # Take the second host down and check that ARP requests are suppressed # and that ARP replies are received. - run_cmd "ip -n h2 link set dev eth0.$vid down" + run_cmd "ip -n $h2 link set dev eth0.$vid down" log_test $? 0 "H2 down" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "ARP suppression" - run_cmd "ip -n h2 link set dev eth0.$vid up" + run_cmd "ip -n $h2 link set dev eth0.$vid up" log_test $? 0 "H2 up" # Disable neighbor suppression and check that ARP requests are no # longer suppressed. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 0 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 4 + tc_check_packets $sw1 "dev vx0 egress" 101 4 log_test $? 0 "ARP suppression" # Take the second host down and check that ARP requests are not # suppressed and that ARP replies are not received. - run_cmd "ip -n h2 link set dev eth0.$vid down" + run_cmd "ip -n $h2 link set dev eth0.$vid down" log_test $? 0 "H2 down" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" log_test $? 1 "arping" - tc_check_packets sw1 "dev vx0 egress" 101 5 + tc_check_packets $sw1 "dev vx0 egress" 101 5 log_test $? 0 "ARP suppression" } @@ -415,80 +408,80 @@ neigh_suppress_ns_common() echo "Per-port NS suppression - VLAN $vid" echo "---------------------------------" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr type 135 code 0 action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr type 135 code 0 action pass" # Initial state - check that NS messages are not suppressed and that ND # messages are received. - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "NS suppression" # Enable neighbor suppression and check that nothing changes compared # to the initial state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "NS suppression" # Install an FDB entry for the remote host and check that nothing # changes compared to the initial state. - h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') - run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" + h2_mac=$(ip -n $h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') + run_cmd "bridge -n $sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" log_test $? 0 "FDB entry installation" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "NS suppression" # Install a neighbor on the matching SVI interface and check that NS # messages are suppressed. - run_cmd "ip -n sw1 neigh replace $daddr lladdr $h2_mac nud permanent dev br0.$vid" + run_cmd "ip -n $sw1 neigh replace $daddr lladdr $h2_mac nud permanent dev br0.$vid" log_test $? 0 "Neighbor entry installation" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "NS suppression" # Take the second host down and check that NS messages are suppressed # and that ND messages are received. - run_cmd "ip -n h2 link set dev eth0.$vid down" + run_cmd "ip -n $h2 link set dev eth0.$vid down" log_test $? 0 "H2 down" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 3 + tc_check_packets $sw1 "dev vx0 egress" 101 3 log_test $? 0 "NS suppression" - run_cmd "ip -n h2 link set dev eth0.$vid up" + run_cmd "ip -n $h2 link set dev eth0.$vid up" log_test $? 0 "H2 up" # Disable neighbor suppression and check that NS messages are no longer # suppressed. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 0 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 4 + tc_check_packets $sw1 "dev vx0 egress" 101 4 log_test $? 0 "NS suppression" # Take the second host down and check that NS messages are not # suppressed and that ND messages are not received. - run_cmd "ip -n h2 link set dev eth0.$vid down" + run_cmd "ip -n $h2 link set dev eth0.$vid down" log_test $? 0 "H2 down" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" log_test $? 2 "ndisc6" - tc_check_packets sw1 "dev vx0 egress" 101 5 + tc_check_packets $sw1 "dev vx0 egress" 101 5 log_test $? 0 "NS suppression" } @@ -524,118 +517,118 @@ neigh_vlan_suppress_arp() echo "Per-{Port, VLAN} ARP suppression" echo "--------------------------------" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip1 arp_sip $sip1 arp_op request action pass" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto 0x0806 flower indev swp1 arp_tip $tip2 arp_sip $sip2 arp_op request action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip1 arp_sip $sip1 arp_op request action pass" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 102 proto 0x0806 flower indev swp1 arp_tip $tip2 arp_sip $sip2 arp_op request action pass" - h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') - h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') - run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" - run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" - run_cmd "ip -n sw1 neigh replace $tip1 lladdr $h2_mac1 nud permanent dev br0.$vid1" - run_cmd "ip -n sw1 neigh replace $tip2 lladdr $h2_mac2 nud permanent dev br0.$vid2" + h2_mac1=$(ip -n $h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') + h2_mac2=$(ip -n $h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') + run_cmd "bridge -n $sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" + run_cmd "bridge -n $sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" + run_cmd "ip -n $sw1 neigh replace $tip1 lladdr $h2_mac1 nud permanent dev br0.$vid1" + run_cmd "ip -n $sw1 neigh replace $tip2 lladdr $h2_mac2 nud permanent dev br0.$vid2" # Enable per-{Port, VLAN} neighbor suppression and check that ARP # requests are not suppressed and that ARP replies are received. - run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" log_test $? 0 "\"neigh_vlan_suppress\" is on" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 1 + tc_check_packets $sw1 "dev vx0 egress" 102 1 log_test $? 0 "ARP suppression (VLAN $vid2)" # Enable neighbor suppression on VLAN 10 and check that only on this # VLAN ARP requests are suppressed. - run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 2 + tc_check_packets $sw1 "dev vx0 egress" 102 2 log_test $? 0 "ARP suppression (VLAN $vid2)" # Enable neighbor suppression on the port and check that it has no # effect compared to previous state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 3 + tc_check_packets $sw1 "dev vx0 egress" 102 3 log_test $? 0 "ARP suppression (VLAN $vid2)" # Disable neighbor suppression on the port and check that it has no # effect compared to previous state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 4 + tc_check_packets $sw1 "dev vx0 egress" 102 4 log_test $? 0 "ARP suppression (VLAN $vid2)" # Disable neighbor suppression on VLAN 10 and check that ARP requests # are no longer suppressed on this VLAN. - run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 5 + tc_check_packets $sw1 "dev vx0 egress" 102 5 log_test $? 0 "ARP suppression (VLAN $vid2)" # Disable per-{Port, VLAN} neighbor suppression, enable neighbor # suppression on the port and check that on both VLANs ARP requests are # suppressed. - run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" log_test $? 0 "\"neigh_vlan_suppress\" is off" - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" log_test $? 0 "arping (VLAN $vid1)" - run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" + run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" log_test $? 0 "arping (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "ARP suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 5 + tc_check_packets $sw1 "dev vx0 egress" 102 5 log_test $? 0 "ARP suppression (VLAN $vid2)" } @@ -655,118 +648,118 @@ neigh_vlan_suppress_ns() echo "Per-{Port, VLAN} NS suppression" echo "-------------------------------" - run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr1 type 135 code 0 action pass" - run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr2 type 135 code 0 action pass" + run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr1 type 135 code 0 action pass" + run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 102 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr2 type 135 code 0 action pass" - h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') - h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') - run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" - run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" - run_cmd "ip -n sw1 neigh replace $daddr1 lladdr $h2_mac1 nud permanent dev br0.$vid1" - run_cmd "ip -n sw1 neigh replace $daddr2 lladdr $h2_mac2 nud permanent dev br0.$vid2" + h2_mac1=$(ip -n $h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') + h2_mac2=$(ip -n $h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') + run_cmd "bridge -n $sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" + run_cmd "bridge -n $sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" + run_cmd "ip -n $sw1 neigh replace $daddr1 lladdr $h2_mac1 nud permanent dev br0.$vid1" + run_cmd "ip -n $sw1 neigh replace $daddr2 lladdr $h2_mac2 nud permanent dev br0.$vid2" # Enable per-{Port, VLAN} neighbor suppression and check that NS # messages are not suppressed and that ND messages are received. - run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" log_test $? 0 "\"neigh_vlan_suppress\" is on" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 1 + tc_check_packets $sw1 "dev vx0 egress" 102 1 log_test $? 0 "NS suppression (VLAN $vid2)" # Enable neighbor suppression on VLAN 10 and check that only on this # VLAN NS messages are suppressed. - run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 2 + tc_check_packets $sw1 "dev vx0 egress" 102 2 log_test $? 0 "NS suppression (VLAN $vid2)" # Enable neighbor suppression on the port and check that it has no # effect compared to previous state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 3 + tc_check_packets $sw1 "dev vx0 egress" 102 3 log_test $? 0 "NS suppression (VLAN $vid2)" # Disable neighbor suppression on the port and check that it has no # effect compared to previous state. - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 4 + tc_check_packets $sw1 "dev vx0 egress" 102 4 log_test $? 0 "NS suppression (VLAN $vid2)" # Disable neighbor suppression on VLAN 10 and check that NS messages # are no longer suppressed on this VLAN. - run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" - run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" + run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" + run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 5 + tc_check_packets $sw1 "dev vx0 egress" 102 5 log_test $? 0 "NS suppression (VLAN $vid2)" # Disable per-{Port, VLAN} neighbor suppression, enable neighbor # suppression on the port and check that on both VLANs NS messages are # suppressed. - run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress off" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" log_test $? 0 "\"neigh_vlan_suppress\" is off" - run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" - run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" + run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on" + run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" log_test $? 0 "\"neigh_suppress\" is on" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" log_test $? 0 "ndisc6 (VLAN $vid1)" - run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" + run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" log_test $? 0 "ndisc6 (VLAN $vid2)" - tc_check_packets sw1 "dev vx0 egress" 101 2 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "NS suppression (VLAN $vid1)" - tc_check_packets sw1 "dev vx0 egress" 102 5 + tc_check_packets $sw1 "dev vx0 egress" 102 5 log_test $? 0 "NS suppression (VLAN $vid2)" } From a8258e64ca74314478fda85a42b1c1eb2db29c67 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:55 +0800 Subject: [PATCH 3359/7721] selftests/net: convert test_vxlan_mdb.sh to run it in unique namespace Here is the test result after conversion. ]# ./test_vxlan_mdb.sh Control path: Basic (*, G) operations - IPv4 overlay / IPv4 underlay -------------------------------------------------------------------- TEST: MDB entry addition [ OK ] ... Data path: MDB torture test - IPv6 overlay / IPv6 underlay ---------------------------------------------------------- TEST: Torture test [ OK ] Tests passed: 620 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/test_vxlan_mdb.sh | 202 +++++++++--------- 1 file changed, 99 insertions(+), 103 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_mdb.sh b/tools/testing/selftests/net/test_vxlan_mdb.sh index 6e996f8063cd..6725fd9157b9 100755 --- a/tools/testing/selftests/net/test_vxlan_mdb.sh +++ b/tools/testing/selftests/net/test_vxlan_mdb.sh @@ -55,9 +55,8 @@ # | ns2_v4 | | ns2_v6 | # +------------------------------------+ +------------------------------------+ +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 CONTROL_PATH_TESTS=" basic_star_g_ipv4_ipv4 @@ -260,9 +259,6 @@ setup_common() local local_addr1=$1; shift local local_addr2=$1; shift - ip netns add $ns1 - ip netns add $ns2 - ip link add name veth0 type veth peer name veth1 ip link set dev veth0 netns $ns1 name veth0 ip link set dev veth1 netns $ns2 name veth0 @@ -273,36 +269,36 @@ setup_common() setup_v4() { - setup_common ns1_v4 ns2_v4 192.0.2.1 192.0.2.2 + setup_ns ns1_v4 ns2_v4 + setup_common $ns1_v4 $ns2_v4 192.0.2.1 192.0.2.2 - ip -n ns1_v4 address add 192.0.2.17/28 dev veth0 - ip -n ns2_v4 address add 192.0.2.18/28 dev veth0 + ip -n $ns1_v4 address add 192.0.2.17/28 dev veth0 + ip -n $ns2_v4 address add 192.0.2.18/28 dev veth0 - ip -n ns1_v4 route add default via 192.0.2.18 - ip -n ns2_v4 route add default via 192.0.2.17 + ip -n $ns1_v4 route add default via 192.0.2.18 + ip -n $ns2_v4 route add default via 192.0.2.17 } cleanup_v4() { - ip netns del ns2_v4 - ip netns del ns1_v4 + cleanup_ns $ns2_v4 $ns1_v4 } setup_v6() { - setup_common ns1_v6 ns2_v6 2001:db8:1::1 2001:db8:1::2 + setup_ns ns1_v6 ns2_v6 + setup_common $ns1_v6 $ns2_v6 2001:db8:1::1 2001:db8:1::2 - ip -n ns1_v6 address add 2001:db8:2::1/64 dev veth0 nodad - ip -n ns2_v6 address add 2001:db8:2::2/64 dev veth0 nodad + ip -n $ns1_v6 address add 2001:db8:2::1/64 dev veth0 nodad + ip -n $ns2_v6 address add 2001:db8:2::2/64 dev veth0 nodad - ip -n ns1_v6 route add default via 2001:db8:2::2 - ip -n ns2_v6 route add default via 2001:db8:2::1 + ip -n $ns1_v6 route add default via 2001:db8:2::2 + ip -n $ns2_v6 route add default via 2001:db8:2::1 } cleanup_v6() { - ip netns del ns2_v6 - ip netns del ns1_v6 + cleanup_ns $ns2_v6 $ns1_v6 } setup() @@ -433,7 +429,7 @@ basic_common() basic_star_g_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp_key="grp 239.1.1.1" local vtep_ip=198.51.100.100 @@ -446,7 +442,7 @@ basic_star_g_ipv4_ipv4() basic_star_g_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp_key="grp ff0e::1" local vtep_ip=198.51.100.100 @@ -459,7 +455,7 @@ basic_star_g_ipv6_ipv4() basic_star_g_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp_key="grp 239.1.1.1" local vtep_ip=2001:db8:1000::1 @@ -472,7 +468,7 @@ basic_star_g_ipv4_ipv6() basic_star_g_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp_key="grp ff0e::1" local vtep_ip=2001:db8:1000::1 @@ -485,7 +481,7 @@ basic_star_g_ipv6_ipv6() basic_sg_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp_key="grp 239.1.1.1 src 192.0.2.129" local vtep_ip=198.51.100.100 @@ -498,7 +494,7 @@ basic_sg_ipv4_ipv4() basic_sg_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp_key="grp ff0e::1 src 2001:db8:100::1" local vtep_ip=198.51.100.100 @@ -511,7 +507,7 @@ basic_sg_ipv6_ipv4() basic_sg_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp_key="grp 239.1.1.1 src 192.0.2.129" local vtep_ip=2001:db8:1000::1 @@ -524,7 +520,7 @@ basic_sg_ipv4_ipv6() basic_sg_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp_key="grp ff0e::1 src 2001:db8:100::1" local vtep_ip=2001:db8:1000::1 @@ -694,7 +690,7 @@ star_g_common() star_g_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp=239.1.1.1 local src1=192.0.2.129 local src2=192.0.2.130 @@ -711,7 +707,7 @@ star_g_ipv4_ipv4() star_g_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp=ff0e::1 local src1=2001:db8:100::1 local src2=2001:db8:100::2 @@ -728,7 +724,7 @@ star_g_ipv6_ipv4() star_g_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp=239.1.1.1 local src1=192.0.2.129 local src2=192.0.2.130 @@ -745,7 +741,7 @@ star_g_ipv4_ipv6() star_g_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp=ff0e::1 local src1=2001:db8:100::1 local src2=2001:db8:100::2 @@ -793,7 +789,7 @@ sg_common() sg_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp=239.1.1.1 local src=192.0.2.129 local vtep_ip=198.51.100.100 @@ -808,7 +804,7 @@ sg_ipv4_ipv4() sg_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local grp=ff0e::1 local src=2001:db8:100::1 local vtep_ip=198.51.100.100 @@ -823,7 +819,7 @@ sg_ipv6_ipv4() sg_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp=239.1.1.1 local src=192.0.2.129 local vtep_ip=2001:db8:1000::1 @@ -838,7 +834,7 @@ sg_ipv4_ipv6() sg_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local grp=ff0e::1 local src=2001:db8:100::1 local vtep_ip=2001:db8:1000::1 @@ -918,7 +914,7 @@ dump_common() dump_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local local_addr=192.0.2.1 local remote_prefix=198.51.100. local fn=ipv4_grps_get @@ -932,7 +928,7 @@ dump_ipv4_ipv4() dump_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local local_addr=192.0.2.1 local remote_prefix=198.51.100. local fn=ipv6_grps_get @@ -946,7 +942,7 @@ dump_ipv6_ipv4() dump_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local local_addr=2001:db8:1::1 local remote_prefix=2001:db8:1000:: local fn=ipv4_grps_get @@ -960,7 +956,7 @@ dump_ipv4_ipv6() dump_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local local_addr=2001:db8:1::1 local remote_prefix=2001:db8:1000:: local fn=ipv6_grps_get @@ -1072,8 +1068,8 @@ encap_params_common() encap_params_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1091,8 +1087,8 @@ encap_params_ipv4_ipv4() encap_params_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1110,8 +1106,8 @@ encap_params_ipv6_ipv4() encap_params_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1129,8 +1125,8 @@ encap_params_ipv4_ipv6() encap_params_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1208,8 +1204,8 @@ starg_exclude_ir_common() starg_exclude_ir_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1227,8 +1223,8 @@ starg_exclude_ir_ipv4_ipv4() starg_exclude_ir_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1246,8 +1242,8 @@ starg_exclude_ir_ipv6_ipv4() starg_exclude_ir_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1265,8 +1261,8 @@ starg_exclude_ir_ipv4_ipv6() starg_exclude_ir_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1344,8 +1340,8 @@ starg_include_ir_common() starg_include_ir_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1363,8 +1359,8 @@ starg_include_ir_ipv4_ipv4() starg_include_ir_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -1382,8 +1378,8 @@ starg_include_ir_ipv6_ipv4() starg_include_ir_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1401,8 +1397,8 @@ starg_include_ir_ipv4_ipv6() starg_include_ir_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -1462,8 +1458,8 @@ starg_exclude_p2mp_common() starg_exclude_p2mp_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local grp=239.1.1.1 @@ -1480,8 +1476,8 @@ starg_exclude_p2mp_ipv4_ipv4() starg_exclude_p2mp_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local grp=ff0e::1 @@ -1498,8 +1494,8 @@ starg_exclude_p2mp_ipv6_ipv4() starg_exclude_p2mp_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local grp=239.1.1.1 @@ -1516,8 +1512,8 @@ starg_exclude_p2mp_ipv4_ipv6() starg_exclude_p2mp_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local grp=ff0e::1 @@ -1576,8 +1572,8 @@ starg_include_p2mp_common() starg_include_p2mp_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local grp=239.1.1.1 @@ -1594,8 +1590,8 @@ starg_include_p2mp_ipv4_ipv4() starg_include_p2mp_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local grp=ff0e::1 @@ -1612,8 +1608,8 @@ starg_include_p2mp_ipv6_ipv4() starg_include_p2mp_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local grp=239.1.1.1 @@ -1630,8 +1626,8 @@ starg_include_p2mp_ipv4_ipv6() starg_include_p2mp_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local grp=ff0e::1 @@ -1709,8 +1705,8 @@ egress_vni_translation_common() egress_vni_translation_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local proto="ipv4" @@ -1727,8 +1723,8 @@ egress_vni_translation_ipv4_ipv4() egress_vni_translation_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local mcast_grp=238.1.1.1 local plen=32 local proto="ipv6" @@ -1745,8 +1741,8 @@ egress_vni_translation_ipv6_ipv4() egress_vni_translation_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local proto="ipv4" @@ -1763,8 +1759,8 @@ egress_vni_translation_ipv4_ipv6() egress_vni_translation_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local mcast_grp=ff0e::2 local plen=128 local proto="ipv6" @@ -1929,8 +1925,8 @@ all_zeros_mdb_common() all_zeros_mdb_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.101 local vtep2_ip=198.51.100.102 local vtep3_ip=198.51.100.103 @@ -1947,8 +1943,8 @@ all_zeros_mdb_ipv4() all_zeros_mdb_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local vtep3_ip=2001:db8:3000::1 @@ -2021,8 +2017,8 @@ mdb_fdb_common() mdb_fdb_ipv4_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -2040,8 +2036,8 @@ mdb_fdb_ipv4_ipv4() mdb_fdb_ipv6_ipv4() { - local ns1=ns1_v4 - local ns2=ns2_v4 + local ns1=$ns1_v4 + local ns2=$ns2_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local plen=32 @@ -2059,8 +2055,8 @@ mdb_fdb_ipv6_ipv4() mdb_fdb_ipv4_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -2078,8 +2074,8 @@ mdb_fdb_ipv4_ipv6() mdb_fdb_ipv6_ipv6() { - local ns1=ns1_v6 - local ns2=ns2_v6 + local ns1=$ns1_v6 + local ns2=$ns2_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local plen=128 @@ -2166,7 +2162,7 @@ mdb_torture_common() mdb_torture_ipv4_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local grp1=239.1.1.1 @@ -2183,7 +2179,7 @@ mdb_torture_ipv4_ipv4() mdb_torture_ipv6_ipv4() { - local ns1=ns1_v4 + local ns1=$ns1_v4 local vtep1_ip=198.51.100.100 local vtep2_ip=198.51.100.200 local grp1=ff0e::1 @@ -2200,7 +2196,7 @@ mdb_torture_ipv6_ipv4() mdb_torture_ipv4_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local grp1=239.1.1.1 @@ -2217,7 +2213,7 @@ mdb_torture_ipv4_ipv6() mdb_torture_ipv6_ipv6() { - local ns1=ns1_v6 + local ns1=$ns1_v6 local vtep1_ip=2001:db8:1000::1 local vtep2_ip=2001:db8:2000::1 local grp1=ff0e::1 From d79e907b425d1dcc831f9eddbdb09682292faed0 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:56 +0800 Subject: [PATCH 3360/7721] selftests/net: convert test_vxlan_nolocalbypass.sh to run it in unique namespace Here is the test result after conversion. ]# ./test_vxlan_nolocalbypass.sh TEST: localbypass enabled [ OK ] TEST: Packet received by local VXLAN device - localbypass [ OK ] TEST: localbypass disabled [ OK ] TEST: Packet not received by local VXLAN device - nolocalbypass [ OK ] TEST: localbypass enabled [ OK ] TEST: Packet received by local VXLAN device - localbypass [ OK ] Tests passed: 6 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/test_vxlan_nolocalbypass.sh | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh index f75212bf142c..b8805983b728 100755 --- a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh +++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh @@ -9,9 +9,8 @@ # option and verifies that packets are no longer received by the second VXLAN # device. +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 TESTS=" nolocalbypass @@ -98,20 +97,19 @@ tc_check_packets() setup() { - ip netns add ns1 + setup_ns ns1 - ip -n ns1 link set dev lo up - ip -n ns1 address add 192.0.2.1/32 dev lo - ip -n ns1 address add 198.51.100.1/32 dev lo + ip -n $ns1 address add 192.0.2.1/32 dev lo + ip -n $ns1 address add 198.51.100.1/32 dev lo - ip -n ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \ + ip -n $ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \ dstport 4789 nolearning - ip -n ns1 link add name vx1 up type vxlan id 100 dstport 4790 + ip -n $ns1 link add name vx1 up type vxlan id 100 dstport 4790 } cleanup() { - ip netns del ns1 &> /dev/null + cleanup_ns $ns1 } ################################################################################ @@ -122,40 +120,40 @@ nolocalbypass() local smac=00:01:02:03:04:05 local dmac=00:0a:0b:0c:0d:0e - run_cmd "bridge -n ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790" + run_cmd "bridge -n $ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790" - run_cmd "tc -n ns1 qdisc add dev vx1 clsact" - run_cmd "tc -n ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass" + run_cmd "tc -n $ns1 qdisc add dev vx1 clsact" + run_cmd "tc -n $ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass" - run_cmd "tc -n ns1 qdisc add dev lo clsact" - run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" + run_cmd "tc -n $ns1 qdisc add dev lo clsact" + run_cmd "tc -n $ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" - run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" + run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" - run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" - tc_check_packets "ns1" "dev vx1 ingress" 101 1 + tc_check_packets "$ns1" "dev vx1 ingress" 101 1 log_test $? 0 "Packet received by local VXLAN device - localbypass" - run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass" + run_cmd "ip -n $ns1 link set dev vx0 type vxlan nolocalbypass" - run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'" + run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'" log_test $? 0 "localbypass disabled" - run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" - tc_check_packets "ns1" "dev vx1 ingress" 101 1 + tc_check_packets "$ns1" "dev vx1 ingress" 101 1 log_test $? 0 "Packet not received by local VXLAN device - nolocalbypass" - run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass" + run_cmd "ip -n $ns1 link set dev vx0 type vxlan localbypass" - run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" + run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" - run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" - tc_check_packets "ns1" "dev vx1 ingress" 101 2 + tc_check_packets "$ns1" "dev vx1 ingress" 101 2 log_test $? 0 "Packet received by local VXLAN device - localbypass" } From d6aab1f632978880660f41c48b760dd48461dcfb Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:57 +0800 Subject: [PATCH 3361/7721] selftests/net: convert test_vxlan_under_vrf.sh to run it in unique namespace Here is the test result after conversion. ]# ./test_vxlan_under_vrf.sh Checking HV connectivity [ OK ] Check VM connectivity through VXLAN (underlay in the default VRF) [ OK ] Check VM connectivity through VXLAN (underlay in a VRF) [ OK ] Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/test_vxlan_under_vrf.sh | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_under_vrf.sh b/tools/testing/selftests/net/test_vxlan_under_vrf.sh index 1fd1250ebc66..ae8fbe3f0779 100755 --- a/tools/testing/selftests/net/test_vxlan_under_vrf.sh +++ b/tools/testing/selftests/net/test_vxlan_under_vrf.sh @@ -43,15 +43,14 @@ # This tests both the connectivity between vm-1 and vm-2, and that the underlay # can be moved in and out of the vrf by unsetting and setting veth0's master. +source lib.sh set -e cleanup() { ip link del veth-hv-1 2>/dev/null || true ip link del veth-tap 2>/dev/null || true - for ns in hv-1 hv-2 vm-1 vm-2; do - ip netns del $ns 2>/dev/null || true - done + cleanup_ns $hv_1 $hv_2 $vm_1 $vm_2 } # Clean start @@ -60,72 +59,75 @@ cleanup &> /dev/null [[ $1 == "clean" ]] && exit 0 trap cleanup EXIT +setup_ns hv_1 hv_2 vm_1 vm_2 +hv[1]=$hv_1 +hv[2]=$hv_2 +vm[1]=$vm_1 +vm[2]=$vm_2 # Setup "Hypervisors" simulated with netns ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking() { - hv=$1 + id=$1 - ip netns add hv-$hv - ip link set veth-hv-$hv netns hv-$hv - ip -netns hv-$hv link set veth-hv-$hv name veth0 + ip link set veth-hv-$id netns ${hv[$id]} + ip -netns ${hv[$id]} link set veth-hv-$id name veth0 - ip -netns hv-$hv link add vrf-underlay type vrf table 1 - ip -netns hv-$hv link set vrf-underlay up - ip -netns hv-$hv addr add 172.16.0.$hv/24 dev veth0 - ip -netns hv-$hv link set veth0 up + ip -netns ${hv[$id]} link add vrf-underlay type vrf table 1 + ip -netns ${hv[$id]} link set vrf-underlay up + ip -netns ${hv[$id]} addr add 172.16.0.$id/24 dev veth0 + ip -netns ${hv[$id]} link set veth0 up - ip -netns hv-$hv link add br0 type bridge - ip -netns hv-$hv link set br0 up + ip -netns ${hv[$id]} link add br0 type bridge + ip -netns ${hv[$id]} link set br0 up - ip -netns hv-$hv link add vxlan0 type vxlan id 10 local 172.16.0.$hv dev veth0 dstport 4789 - ip -netns hv-$hv link set vxlan0 master br0 - ip -netns hv-$hv link set vxlan0 up + ip -netns ${hv[$id]} link add vxlan0 type vxlan id 10 local 172.16.0.$id dev veth0 dstport 4789 + ip -netns ${hv[$id]} link set vxlan0 master br0 + ip -netns ${hv[$id]} link set vxlan0 up } setup-hv-networking 1 setup-hv-networking 2 # Check connectivity between HVs by pinging hv-2 from hv-1 echo -n "Checking HV connectivity " -ip netns exec hv-1 ping -c 1 -W 1 172.16.0.2 &> /dev/null || (echo "[FAIL]"; false) +ip netns exec $hv_1 ping -c 1 -W 1 172.16.0.2 &> /dev/null || (echo "[FAIL]"; false) echo "[ OK ]" # Setups a "VM" simulated by a netns an a veth pair setup-vm() { id=$1 - ip netns add vm-$id ip link add veth-tap type veth peer name veth-hv - ip link set veth-tap netns hv-$id - ip -netns hv-$id link set veth-tap master br0 - ip -netns hv-$id link set veth-tap up + ip link set veth-tap netns ${hv[$id]} + ip -netns ${hv[$id]} link set veth-tap master br0 + ip -netns ${hv[$id]} link set veth-tap up ip link set veth-hv address 02:1d:8d:dd:0c:6$id - ip link set veth-hv netns vm-$id - ip -netns vm-$id addr add 10.0.0.$id/24 dev veth-hv - ip -netns vm-$id link set veth-hv up + ip link set veth-hv netns ${vm[$id]} + ip -netns ${vm[$id]} addr add 10.0.0.$id/24 dev veth-hv + ip -netns ${vm[$id]} link set veth-hv up } setup-vm 1 setup-vm 2 # Setup VTEP routes to make ARP work -bridge -netns hv-1 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.2 self permanent -bridge -netns hv-2 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.1 self permanent +bridge -netns $hv_1 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.2 self permanent +bridge -netns $hv_2 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.1 self permanent echo -n "Check VM connectivity through VXLAN (underlay in the default VRF) " -ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) +ip netns exec $vm_1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) echo "[ OK ]" # Move the underlay to a non-default VRF -ip -netns hv-1 link set veth0 vrf vrf-underlay -ip -netns hv-1 link set vxlan0 down -ip -netns hv-1 link set vxlan0 up -ip -netns hv-2 link set veth0 vrf vrf-underlay -ip -netns hv-2 link set vxlan0 down -ip -netns hv-2 link set vxlan0 up +ip -netns $hv_1 link set veth0 vrf vrf-underlay +ip -netns $hv_1 link set vxlan0 down +ip -netns $hv_1 link set vxlan0 up +ip -netns $hv_2 link set veth0 vrf vrf-underlay +ip -netns $hv_2 link set vxlan0 down +ip -netns $hv_2 link set vxlan0 up echo -n "Check VM connectivity through VXLAN (underlay in a VRF) " -ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) +ip netns exec $vm_1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) echo "[ OK ]" From 5ece8371747d57ae113aaf8a7b6468d6681d099f Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:58 +0800 Subject: [PATCH 3362/7721] selftests/net: convert test_vxlan_vnifiltering.sh to run it in unique namespace Here is the test result after conversion. ]# ./test_vxlan_vnifiltering.sh TEST: Create traditional vxlan device [ OK ] TEST: Cannot create vnifilter device without external flag [ OK ] TEST: Creating external vxlan device with vnifilter flag [ OK ] ... TEST: VM connectivity over traditional vxlan (ipv6 default rdst) [ OK ] TEST: VM connectivity over metadata nonfiltering vxlan (ipv4 default rdst) [ OK ] Tests passed: 27 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/test_vxlan_vnifiltering.sh | 154 +++++++++++------- 1 file changed, 95 insertions(+), 59 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh index 8c3ac0a72545..6127a78ee988 100755 --- a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh +++ b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh @@ -78,10 +78,8 @@ # # # This test tests the new vxlan vnifiltering api - +source lib.sh ret=0 -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 # all tests in this script. Can be overridden with -t option TESTS=" @@ -148,18 +146,18 @@ run_cmd() } check_hv_connectivity() { - ip netns exec hv-1 ping -c 1 -W 1 $1 &>/dev/null + ip netns exec $hv_1 ping -c 1 -W 1 $1 &>/dev/null sleep 1 - ip netns exec hv-1 ping -c 1 -W 1 $2 &>/dev/null + ip netns exec $hv_1 ping -c 1 -W 1 $2 &>/dev/null return $? } check_vm_connectivity() { - run_cmd "ip netns exec vm-11 ping -c 1 -W 1 10.0.10.12" + run_cmd "ip netns exec $vm_11 ping -c 1 -W 1 10.0.10.12" log_test $? 0 "VM connectivity over $1 (ipv4 default rdst)" - run_cmd "ip netns exec vm-21 ping -c 1 -W 1 10.0.10.22" + run_cmd "ip netns exec $vm_21 ping -c 1 -W 1 10.0.10.22" log_test $? 0 "VM connectivity over $1 (ipv6 default rdst)" } @@ -167,26 +165,23 @@ cleanup() { ip link del veth-hv-1 2>/dev/null || true ip link del vethhv-11 vethhv-12 vethhv-21 vethhv-22 2>/dev/null || true - for ns in hv-1 hv-2 vm-11 vm-21 vm-12 vm-22 vm-31 vm-32; do - ip netns del $ns 2>/dev/null || true - done + cleanup_ns $hv_1 $hv_2 $vm_11 $vm_21 $vm_12 $vm_22 $vm_31 $vm_32 } trap cleanup EXIT setup-hv-networking() { - hv=$1 + id=$1 local1=$2 mask1=$3 local2=$4 mask2=$5 - ip netns add hv-$hv - ip link set veth-hv-$hv netns hv-$hv - ip -netns hv-$hv link set veth-hv-$hv name veth0 - ip -netns hv-$hv addr add $local1/$mask1 dev veth0 - ip -netns hv-$hv addr add $local2/$mask2 dev veth0 - ip -netns hv-$hv link set veth0 up + ip link set veth-hv-$id netns ${hv[$id]} + ip -netns ${hv[$id]} link set veth-hv-$id name veth0 + ip -netns ${hv[$id]} addr add $local1/$mask1 dev veth0 + ip -netns ${hv[$id]} addr add $local2/$mask2 dev veth0 + ip -netns ${hv[$id]} link set veth0 up } # Setups a "VM" simulated by a netns an a veth pair @@ -208,21 +203,20 @@ setup-vm() { lastvxlandev="" # create bridge - ip -netns hv-$hvid link add br$brid type bridge vlan_filtering 1 vlan_default_pvid 0 \ + ip -netns ${hv[$hvid]} link add br$brid type bridge vlan_filtering 1 vlan_default_pvid 0 \ mcast_snooping 0 - ip -netns hv-$hvid link set br$brid up + ip -netns ${hv[$hvid]} link set br$brid up # create vm namespace and interfaces and connect to hypervisor # namespace - ip netns add vm-$vmid hvvethif="vethhv-$vmid" vmvethif="veth-$vmid" ip link add $hvvethif type veth peer name $vmvethif - ip link set $hvvethif netns hv-$hvid - ip link set $vmvethif netns vm-$vmid - ip -netns hv-$hvid link set $hvvethif up - ip -netns vm-$vmid link set $vmvethif up - ip -netns hv-$hvid link set $hvvethif master br$brid + ip link set $hvvethif netns ${hv[$hvid]} + ip link set $vmvethif netns ${vm[$vmid]} + ip -netns ${hv[$hvid]} link set $hvvethif up + ip -netns ${vm[$vmid]} link set $vmvethif up + ip -netns ${hv[$hvid]} link set $hvvethif master br$brid # configure VM vlan/vni filtering on hypervisor for vmap in $(echo $vattrs | cut -d "," -f1- --output-delimiter=' ') @@ -234,9 +228,9 @@ setup-vm() { local vtype=$(echo $vmap | awk -F'-' '{print ($5)}') local port=$(echo $vmap | awk -F'-' '{print ($6)}') - ip -netns vm-$vmid link add name $vmvethif.$vid link $vmvethif type vlan id $vid - ip -netns vm-$vmid addr add 10.0.$vid.$vmid/24 dev $vmvethif.$vid - ip -netns vm-$vmid link set $vmvethif.$vid up + ip -netns ${vm[$vmid]} link add name $vmvethif.$vid link $vmvethif type vlan id $vid + ip -netns ${vm[$vmid]} addr add 10.0.$vid.$vmid/24 dev $vmvethif.$vid + ip -netns ${vm[$vmid]} link set $vmvethif.$vid up tid=$vid vxlandev="vxlan$brid" @@ -268,35 +262,35 @@ setup-vm() { # create vxlan device if [ "$vxlandev" != "$lastvxlandev" ]; then - ip -netns hv-$hvid link add $vxlandev type vxlan local $localip $vxlandevflags dev veth0 2>/dev/null - ip -netns hv-$hvid link set $vxlandev master br$brid - ip -netns hv-$hvid link set $vxlandev up + ip -netns ${hv[$hvid]} link add $vxlandev type vxlan local $localip $vxlandevflags dev veth0 2>/dev/null + ip -netns ${hv[$hvid]} link set $vxlandev master br$brid + ip -netns ${hv[$hvid]} link set $vxlandev up lastvxlandev=$vxlandev fi # add vlan - bridge -netns hv-$hvid vlan add vid $vid dev $hvvethif - bridge -netns hv-$hvid vlan add vid $vid pvid dev $vxlandev + bridge -netns ${hv[$hvid]} vlan add vid $vid dev $hvvethif + bridge -netns ${hv[$hvid]} vlan add vid $vid pvid dev $vxlandev # Add bridge vni filter for tx if [[ -n $vtype && $vtype == "metadata" || $vtype == "vnifilter" || $vtype == "vnifilterg" ]]; then - bridge -netns hv-$hvid link set dev $vxlandev vlan_tunnel on - bridge -netns hv-$hvid vlan add dev $vxlandev vid $vid tunnel_info id $tid + bridge -netns ${hv[$hvid]} link set dev $vxlandev vlan_tunnel on + bridge -netns ${hv[$hvid]} vlan add dev $vxlandev vid $vid tunnel_info id $tid fi if [[ -n $vtype && $vtype == "metadata" ]]; then - bridge -netns hv-$hvid fdb add 00:00:00:00:00:00 dev $vxlandev \ + bridge -netns ${hv[$hvid]} fdb add 00:00:00:00:00:00 dev $vxlandev \ src_vni $tid vni $tid dst $group self elif [[ -n $vtype && $vtype == "vnifilter" ]]; then # Add per vni rx filter with 'bridge vni' api - bridge -netns hv-$hvid vni add dev $vxlandev vni $tid + bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid elif [[ -n $vtype && $vtype == "vnifilterg" ]]; then # Add per vni group config with 'bridge vni' api if [ -n "$group" ]; then if [ $mcast -eq 1 ]; then - bridge -netns hv-$hvid vni add dev $vxlandev vni $tid group $group + bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid group $group else - bridge -netns hv-$hvid vni add dev $vxlandev vni $tid remote $group + bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid remote $group fi fi fi @@ -306,14 +300,14 @@ setup-vm() { setup_vnifilter_api() { ip link add veth-host type veth peer name veth-testns - ip netns add testns - ip link set veth-testns netns testns + setup_ns testns + ip link set veth-testns netns $testns } cleanup_vnifilter_api() { ip link del veth-host 2>/dev/null || true - ip netns del testns 2>/dev/null || true + ip netns del $testns 2>/dev/null || true } # tests vxlan filtering api @@ -331,52 +325,52 @@ vxlan_vnifilter_api() # Duplicate vni test # create non-vnifiltering traditional vni device - run_cmd "ip -netns testns link add vxlan100 type vxlan id 100 local $localip dev veth-testns dstport 4789" + run_cmd "ip -netns $testns link add vxlan100 type vxlan id 100 local $localip dev veth-testns dstport 4789" log_test $? 0 "Create traditional vxlan device" # create vni filtering device - run_cmd "ip -netns testns link add vxlan-ext1 type vxlan vnifilter local $localip dev veth-testns dstport 4789" + run_cmd "ip -netns $testns link add vxlan-ext1 type vxlan vnifilter local $localip dev veth-testns dstport 4789" log_test $? 1 "Cannot create vnifilter device without external flag" - run_cmd "ip -netns testns link add vxlan-ext1 type vxlan external vnifilter local $localip dev veth-testns dstport 4789" + run_cmd "ip -netns $testns link add vxlan-ext1 type vxlan external vnifilter local $localip dev veth-testns dstport 4789" log_test $? 0 "Creating external vxlan device with vnifilter flag" - run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 100" + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 100" log_test $? 0 "Cannot set in-use vni id on vnifiltering device" - run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 200" + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 200" log_test $? 0 "Set new vni id on vnifiltering device" - run_cmd "ip -netns testns link add vxlan-ext2 type vxlan external vnifilter local $localip dev veth-testns dstport 4789" + run_cmd "ip -netns $testns link add vxlan-ext2 type vxlan external vnifilter local $localip dev veth-testns dstport 4789" log_test $? 0 "Create second external vxlan device with vnifilter flag" - run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 200" + run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 200" log_test $? 255 "Cannot set in-use vni id on vnifiltering device" - run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300" + run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300" log_test $? 0 "Set new vni id on vnifiltering device" # check in bridge vni show - run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300" + run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300" log_test $? 0 "Update vni id on vnifiltering device" - run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 400" + run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 400" log_test $? 0 "Add new vni id on vnifiltering device" # add multicast group per vni - run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 200 group $group" + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 200 group $group" log_test $? 0 "Set multicast group on existing vni" # add multicast group per vni - run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300 group $group" + run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300 group $group" log_test $? 0 "Set multicast group on existing vni" # set vnifilter on an existing external vxlan device - run_cmd "ip -netns testns link set dev vxlan-ext1 type vxlan external vnifilter" + run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external vnifilter" log_test $? 2 "Cannot set vnifilter flag on a device" # change vxlan vnifilter flag - run_cmd "ip -netns testns link set dev vxlan-ext1 type vxlan external novnifilter" + run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external novnifilter" log_test $? 2 "Cannot unset vnifilter flag on a device" } @@ -390,12 +384,20 @@ vxlan_vnifilter_datapath() hv1addr2="2002:fee1::1" hv2addr2="2002:fee1::2" + setup_ns hv_1 hv_2 + hv[1]=$hv_1 + hv[2]=$hv_2 ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 $hv2addr1 $hv2addr2 setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 $hv1addr1 $hv1addr2 check_hv_connectivity hv2addr1 hv2addr2 + setup_ns vm_11 vm_21 vm_12 vm_22 + vm[11]=$vm_11 + vm[21]=$vm_21 + vm[12]=$vm_12 + vm[22]=$vm_22 setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilter,20-v4-$hv1addr1-$hv2addr1-vnifilter 0 setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilter,20-v6-$hv1addr2-$hv2addr2-vnifilter 0 @@ -415,12 +417,20 @@ vxlan_vnifilter_datapath_pervni() hv1addr2="2002:fee1::1" hv2addr2="2002:fee1::2" + setup_ns hv_1 hv_2 + hv[1]=$hv_1 + hv[2]=$hv_2 ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 check_hv_connectivity hv2addr1 hv2addr2 + setup_ns vm_11 vm_21 vm_12 vm_22 + vm[11]=$vm_11 + vm[21]=$vm_21 + vm[12]=$vm_12 + vm[22]=$vm_22 setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilterg,20-v4-$hv1addr1-$hv2addr1-vnifilterg 0 setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilterg,20-v6-$hv1addr2-$hv2addr2-vnifilterg 0 @@ -440,12 +450,20 @@ vxlan_vnifilter_datapath_mgroup() group="239.1.1.100" group6="ff07::1" + setup_ns hv_1 hv_2 + hv[1]=$hv_1 + hv[2]=$hv_2 ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 check_hv_connectivity hv2addr1 hv2addr2 + setup_ns vm_11 vm_21 vm_12 vm_22 + vm[11]=$vm_11 + vm[21]=$vm_21 + vm[12]=$vm_12 + vm[22]=$vm_22 setup-vm 1 11 1 10-v4-$hv1addr1-$group-vnifilter,20-v4-$hv1addr1-$group-vnifilter 1 setup-vm 1 21 2 "10-v6-$hv1addr2-$group6-vnifilter,20-v6-$hv1addr2-$group6-vnifilter" 1 @@ -464,12 +482,20 @@ vxlan_vnifilter_datapath_mgroup_pervni() group="239.1.1.100" group6="ff07::1" + setup_ns hv_1 hv_2 + hv[1]=$hv_1 + hv[2]=$hv_2 ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 check_hv_connectivity hv2addr1 hv2addr2 + setup_ns vm_11 vm_21 vm_12 vm_22 + vm[11]=$vm_11 + vm[21]=$vm_21 + vm[12]=$vm_12 + vm[22]=$vm_22 setup-vm 1 11 1 10-v4-$hv1addr1-$group-vnifilterg,20-v4-$hv1addr1-$group-vnifilterg 1 setup-vm 1 21 2 10-v6-$hv1addr2-$group6-vnifilterg,20-v6-$hv1addr2-$group6-vnifilterg 1 @@ -486,12 +512,22 @@ vxlan_vnifilter_metadata_and_traditional_mix() hv1addr2="2002:fee1::1" hv2addr2="2002:fee1::2" + setup_ns hv_1 hv_2 + hv[1]=$hv_1 + hv[2]=$hv_2 ip link add veth-hv-1 type veth peer name veth-hv-2 setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 check_hv_connectivity hv2addr1 hv2addr2 + setup_ns vm_11 vm_21 vm_31 vm_12 vm_22 vm_32 + vm[11]=$vm_11 + vm[21]=$vm_21 + vm[31]=$vm_31 + vm[12]=$vm_12 + vm[22]=$vm_22 + vm[32]=$vm_32 setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilter,20-v4-$hv1addr1-$hv2addr1-vnifilter 0 setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilter,20-v6-$hv1addr2-$hv2addr2-vnifilter 0 setup-vm 1 31 3 30-v4-$hv1addr1-$hv2addr1-default-4790,40-v6-$hv1addr2-$hv2addr2-default-4790,50-v4-$hv1addr1-$hv2addr1-metadata-4791 0 @@ -504,13 +540,13 @@ vxlan_vnifilter_metadata_and_traditional_mix() check_vm_connectivity "vnifiltering vxlan pervni remote mix" # check VM connectivity over traditional/non-vxlan filtering vxlan devices - run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.30.32" + run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.30.32" log_test $? 0 "VM connectivity over traditional vxlan (ipv4 default rdst)" - run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.40.32" + run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.40.32" log_test $? 0 "VM connectivity over traditional vxlan (ipv6 default rdst)" - run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.50.32" + run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.50.32" log_test $? 0 "VM connectivity over metadata nonfiltering vxlan (ipv4 default rdst)" } From bedc99abcaf88df25b044fc4e3c80d69d0dbfc9b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:07:59 +0800 Subject: [PATCH 3363/7721] selftests/net: convert vrf_route_leaking.sh to run it in unique namespace Here is the test result after conversion. ]# ./vrf_route_leaking.sh ########################################################################### IPv4 (sym route): VRF ICMP ttl error route lookup ping ########################################################################### TEST: Basic IPv4 connectivity [ OK ] TEST: Ping received ICMP ttl exceeded [ OK ] ... TEST: Basic IPv6 connectivity [ OK ] TEST: Traceroute6 reports a hop on r1 [ OK ] Tests passed: 18 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- .../selftests/net/vrf_route_leaking.sh | 201 +++++++++--------- 1 file changed, 96 insertions(+), 105 deletions(-) diff --git a/tools/testing/selftests/net/vrf_route_leaking.sh b/tools/testing/selftests/net/vrf_route_leaking.sh index dedc52562b4f..2da32f4c479b 100755 --- a/tools/testing/selftests/net/vrf_route_leaking.sh +++ b/tools/testing/selftests/net/vrf_route_leaking.sh @@ -58,6 +58,7 @@ # to send an ICMP error back to the source when the ttl of a packet reaches 1 # while it is forwarded between different vrfs. +source lib.sh VERBOSE=0 PAUSE_ON_FAIL=no DEFAULT_TTYPE=sym @@ -171,11 +172,7 @@ run_cmd_grep() cleanup() { - local ns - - for ns in h1 h2 r1 r2; do - ip netns del $ns 2>/dev/null - done + cleanup_ns $h1 $h2 $r1 $r2 } setup_vrf() @@ -212,72 +209,69 @@ setup_sym() # # create nodes as namespaces - # - for ns in h1 h2 r1; do - ip netns add $ns - ip -netns $ns link set lo up - - case "${ns}" in - h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 - ;; - r1) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 - esac + setup_ns h1 h2 r1 + for ns in $h1 $h2 $r1; do + if echo $ns | grep -q h[12]-; then + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 + else + ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 + fi done # # create interconnects # - ip -netns h1 link add eth0 type veth peer name r1h1 - ip -netns h1 link set r1h1 netns r1 name eth0 up + ip -netns $h1 link add eth0 type veth peer name r1h1 + ip -netns $h1 link set r1h1 netns $r1 name eth0 up - ip -netns h2 link add eth0 type veth peer name r1h2 - ip -netns h2 link set r1h2 netns r1 name eth1 up + ip -netns $h2 link add eth0 type veth peer name r1h2 + ip -netns $h2 link set r1h2 netns $r1 name eth1 up # # h1 # - ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24 - ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad - ip -netns h1 link set eth0 up + ip -netns $h1 addr add dev eth0 ${H1_N1_IP}/24 + ip -netns $h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad + ip -netns $h1 link set eth0 up # h1 to h2 via r1 - ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0 - ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0 + ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0 + ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0 # # h2 # - ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24 - ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad - ip -netns h2 link set eth0 up + ip -netns $h2 addr add dev eth0 ${H2_N2_IP}/24 + ip -netns $h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad + ip -netns $h2 link set eth0 up # h2 to h1 via r1 - ip -netns h2 route add default via ${R1_N2_IP} dev eth0 - ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0 + ip -netns $h2 route add default via ${R1_N2_IP} dev eth0 + ip -netns $h2 -6 route add default via ${R1_N2_IP6} dev eth0 # # r1 # - setup_vrf r1 - create_vrf r1 blue 1101 - create_vrf r1 red 1102 - ip -netns r1 link set mtu 1400 dev eth1 - ip -netns r1 link set eth0 vrf blue up - ip -netns r1 link set eth1 vrf red up - ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24 - ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad - ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24 - ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad + setup_vrf $r1 + create_vrf $r1 blue 1101 + create_vrf $r1 red 1102 + ip -netns $r1 link set mtu 1400 dev eth1 + ip -netns $r1 link set eth0 vrf blue up + ip -netns $r1 link set eth1 vrf red up + ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24 + ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad + ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24 + ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad # Route leak from blue to red - ip -netns r1 route add vrf blue ${H2_N2} dev red - ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red + ip -netns $r1 route add vrf blue ${H2_N2} dev red + ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red # Route leak from red to blue - ip -netns r1 route add vrf red ${H1_N1} dev blue - ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue + ip -netns $r1 route add vrf red ${H1_N1} dev blue + ip -netns $r1 -6 route add vrf red ${H1_N1_6} dev blue # Wait for ip config to settle @@ -293,90 +287,87 @@ setup_asym() # # create nodes as namespaces - # - for ns in h1 h2 r1 r2; do - ip netns add $ns - ip -netns $ns link set lo up - - case "${ns}" in - h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 - ;; - r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 - ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 - esac + setup_ns h1 h2 r1 r2 + for ns in $h1 $h2 $r1 $r2; do + if echo $ns | grep -q h[12]-; then + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 + else + ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 + ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 + fi done # # create interconnects # - ip -netns h1 link add eth0 type veth peer name r1h1 - ip -netns h1 link set r1h1 netns r1 name eth0 up + ip -netns $h1 link add eth0 type veth peer name r1h1 + ip -netns $h1 link set r1h1 netns $r1 name eth0 up - ip -netns h1 link add eth1 type veth peer name r2h1 - ip -netns h1 link set r2h1 netns r2 name eth0 up + ip -netns $h1 link add eth1 type veth peer name r2h1 + ip -netns $h1 link set r2h1 netns $r2 name eth0 up - ip -netns h2 link add eth0 type veth peer name r1h2 - ip -netns h2 link set r1h2 netns r1 name eth1 up + ip -netns $h2 link add eth0 type veth peer name r1h2 + ip -netns $h2 link set r1h2 netns $r1 name eth1 up - ip -netns h2 link add eth1 type veth peer name r2h2 - ip -netns h2 link set r2h2 netns r2 name eth1 up + ip -netns $h2 link add eth1 type veth peer name r2h2 + ip -netns $h2 link set r2h2 netns $r2 name eth1 up # # h1 # - ip -netns h1 link add br0 type bridge - ip -netns h1 link set br0 up - ip -netns h1 addr add dev br0 ${H1_N1_IP}/24 - ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad - ip -netns h1 link set eth0 master br0 up - ip -netns h1 link set eth1 master br0 up + ip -netns $h1 link add br0 type bridge + ip -netns $h1 link set br0 up + ip -netns $h1 addr add dev br0 ${H1_N1_IP}/24 + ip -netns $h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad + ip -netns $h1 link set eth0 master br0 up + ip -netns $h1 link set eth1 master br0 up # h1 to h2 via r1 - ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev br0 - ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0 + ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev br0 + ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0 # # h2 # - ip -netns h2 link add br0 type bridge - ip -netns h2 link set br0 up - ip -netns h2 addr add dev br0 ${H2_N2_IP}/24 - ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad - ip -netns h2 link set eth0 master br0 up - ip -netns h2 link set eth1 master br0 up + ip -netns $h2 link add br0 type bridge + ip -netns $h2 link set br0 up + ip -netns $h2 addr add dev br0 ${H2_N2_IP}/24 + ip -netns $h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad + ip -netns $h2 link set eth0 master br0 up + ip -netns $h2 link set eth1 master br0 up # h2 to h1 via r2 - ip -netns h2 route add default via ${R2_N2_IP} dev br0 - ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0 + ip -netns $h2 route add default via ${R2_N2_IP} dev br0 + ip -netns $h2 -6 route add default via ${R2_N2_IP6} dev br0 # # r1 # - setup_vrf r1 - create_vrf r1 blue 1101 - create_vrf r1 red 1102 - ip -netns r1 link set mtu 1400 dev eth1 - ip -netns r1 link set eth0 vrf blue up - ip -netns r1 link set eth1 vrf red up - ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24 - ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad - ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24 - ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad + setup_vrf $r1 + create_vrf $r1 blue 1101 + create_vrf $r1 red 1102 + ip -netns $r1 link set mtu 1400 dev eth1 + ip -netns $r1 link set eth0 vrf blue up + ip -netns $r1 link set eth1 vrf red up + ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24 + ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad + ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24 + ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad # Route leak from blue to red - ip -netns r1 route add vrf blue ${H2_N2} dev red - ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red + ip -netns $r1 route add vrf blue ${H2_N2} dev red + ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red # No route leak from red to blue # # r2 # - ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24 - ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad - ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24 - ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad + ip -netns $r2 addr add dev eth0 ${R2_N1_IP}/24 + ip -netns $r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad + ip -netns $r2 addr add dev eth1 ${R2_N2_IP}/24 + ip -netns $r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad # Wait for ip config to settle sleep 2 @@ -384,14 +375,14 @@ setup_asym() check_connectivity() { - ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1 + ip netns exec $h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1 log_test $? 0 "Basic IPv4 connectivity" return $? } check_connectivity6() { - ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1 + ip netns exec $h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1 log_test $? 0 "Basic IPv6 connectivity" return $? } @@ -426,7 +417,7 @@ ipv4_traceroute() check_connectivity || return - run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP} + run_cmd_grep "${R1_N1_IP}" ip netns exec $h1 traceroute ${H2_N2_IP} log_test $? 0 "Traceroute reports a hop on r1" } @@ -449,7 +440,7 @@ ipv6_traceroute() check_connectivity6 || return - run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6} + run_cmd_grep "${R1_N1_IP6}" ip netns exec $h1 traceroute6 ${H2_N2_IP6} log_test $? 0 "Traceroute6 reports a hop on r1" } @@ -470,7 +461,7 @@ ipv4_ping_ttl() check_connectivity || return - run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP} + run_cmd_grep "Time to live exceeded" ip netns exec $h1 ping -t1 -c1 -W2 ${H2_N2_IP} log_test $? 0 "Ping received ICMP ttl exceeded" } @@ -491,7 +482,7 @@ ipv4_ping_frag() check_connectivity || return - run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP} + run_cmd_grep "Frag needed" ip netns exec $h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP} log_test $? 0 "Ping received ICMP Frag needed" } @@ -512,7 +503,7 @@ ipv6_ping_ttl() check_connectivity6 || return - run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6} + run_cmd_grep "Time exceeded: Hop limit" ip netns exec $h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6} log_test $? 0 "Ping received ICMP Hop limit" } @@ -533,7 +524,7 @@ ipv6_ping_frag() check_connectivity6 || return - run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6} + run_cmd_grep "Packet too big" ip netns exec $h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6} log_test $? 0 "Ping received ICMP Packet too big" } From 51f64acbe36e13e113d284fcdefc751216984c01 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:08:00 +0800 Subject: [PATCH 3364/7721] selftests/net: convert vrf_strict_mode_test.sh to run it in unique namespace Here is the test result after conversion. ]# ./vrf_strict_mode_test.sh ################################################################################ TEST SECTION: VRF strict_mode test on init network namespace ################################################################################ TEST: init: net.vrf.strict_mode is available [ OK ] TEST: init: strict_mode=0 by default, 0 vrfs [ OK ] ... TEST: init: check strict_mode=1 [ OK ] TEST: testns-HvoZkB: check strict_mode=0 [ OK ] Tests passed: 37 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- .../selftests/net/vrf_strict_mode_test.sh | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/net/vrf_strict_mode_test.sh b/tools/testing/selftests/net/vrf_strict_mode_test.sh index 417d214264f3..01552b542544 100755 --- a/tools/testing/selftests/net/vrf_strict_mode_test.sh +++ b/tools/testing/selftests/net/vrf_strict_mode_test.sh @@ -3,9 +3,7 @@ # This test is designed for testing the new VRF strict_mode functionality. -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 - +source lib.sh ret=0 # identifies the "init" network namespace which is often called root network @@ -247,13 +245,12 @@ setup() { modprobe vrf - ip netns add testns - ip netns exec testns ip link set lo up + setup_ns testns } cleanup() { - ip netns del testns 2>/dev/null + ip netns del $testns 2>/dev/null ip link del vrf100 2>/dev/null ip link del vrf101 2>/dev/null @@ -298,28 +295,28 @@ vrf_strict_mode_tests_testns() { log_section "VRF strict_mode test on testns network namespace" - vrf_strict_mode_check_support testns + vrf_strict_mode_check_support $testns - strict_mode_check_default testns + strict_mode_check_default $testns - enable_strict_mode_and_check testns + enable_strict_mode_and_check $testns - add_vrf_and_check testns vrf100 100 - config_vrf_and_check testns 10.0.100.1/24 vrf100 + add_vrf_and_check $testns vrf100 100 + config_vrf_and_check $testns 10.0.100.1/24 vrf100 - add_vrf_and_check_fail testns vrf101 100 + add_vrf_and_check_fail $testns vrf101 100 - add_vrf_and_check_fail testns vrf102 100 + add_vrf_and_check_fail $testns vrf102 100 - add_vrf_and_check testns vrf200 200 + add_vrf_and_check $testns vrf200 200 - disable_strict_mode_and_check testns + disable_strict_mode_and_check $testns - add_vrf_and_check testns vrf101 100 + add_vrf_and_check $testns vrf101 100 - add_vrf_and_check testns vrf102 100 + add_vrf_and_check $testns vrf102 100 - #the strict_mode is disabled in the testns + #the strict_mode is disabled in the $testns } vrf_strict_mode_tests_mix() @@ -328,25 +325,25 @@ vrf_strict_mode_tests_mix() read_strict_mode_compare_and_check init 1 - read_strict_mode_compare_and_check testns 0 + read_strict_mode_compare_and_check $testns 0 - del_vrf_and_check testns vrf101 + del_vrf_and_check $testns vrf101 - del_vrf_and_check testns vrf102 + del_vrf_and_check $testns vrf102 disable_strict_mode_and_check init - enable_strict_mode_and_check testns + enable_strict_mode_and_check $testns enable_strict_mode_and_check init enable_strict_mode_and_check init - disable_strict_mode_and_check testns - disable_strict_mode_and_check testns + disable_strict_mode_and_check $testns + disable_strict_mode_and_check $testns read_strict_mode_compare_and_check init 1 - read_strict_mode_compare_and_check testns 0 + read_strict_mode_compare_and_check $testns 0 } ################################################################################ From 61b12ebe439adfd9853c13499c2099e2a6d41771 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 6 Dec 2023 15:08:01 +0800 Subject: [PATCH 3365/7721] selftests/net: convert vrf-xfrm-tests.sh to run it in unique namespace Here is the test result after conversion. ]# ./vrf-xfrm-tests.sh No qdisc on VRF device TEST: IPv4 no xfrm policy [ OK ] TEST: IPv6 no xfrm policy [ OK ] TEST: IPv4 xfrm policy based on address [ OK ] TEST: IPv6 xfrm policy based on address [ OK ] TEST: IPv6 xfrm policy with VRF in selector [ OK ] TEST: IPv4 xfrm policy with xfrm device [ OK ] TEST: IPv6 xfrm policy with xfrm device [ OK ] netem qdisc on VRF device TEST: IPv4 no xfrm policy [ OK ] TEST: IPv6 no xfrm policy [ OK ] TEST: IPv4 xfrm policy based on address [ OK ] TEST: IPv6 xfrm policy based on address [ OK ] TEST: IPv6 xfrm policy with VRF in selector [ OK ] TEST: IPv4 xfrm policy with xfrm device [ OK ] TEST: IPv6 xfrm policy with xfrm device [ OK ] Tests passed: 14 Tests failed: 0 Acked-by: David Ahern Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- tools/testing/selftests/net/vrf-xfrm-tests.sh | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/net/vrf-xfrm-tests.sh b/tools/testing/selftests/net/vrf-xfrm-tests.sh index 452638ae8aed..b64dd891699d 100755 --- a/tools/testing/selftests/net/vrf-xfrm-tests.sh +++ b/tools/testing/selftests/net/vrf-xfrm-tests.sh @@ -3,9 +3,7 @@ # # Various combinations of VRF with xfrms and qdisc. -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 - +source lib.sh PAUSE_ON_FAIL=no VERBOSE=0 ret=0 @@ -67,7 +65,7 @@ run_cmd_host1() printf " COMMAND: $cmd\n" fi - out=$(eval ip netns exec host1 $cmd 2>&1) + out=$(eval ip netns exec $host1 $cmd 2>&1) rc=$? if [ "$VERBOSE" = "1" ]; then if [ -n "$out" ]; then @@ -116,9 +114,6 @@ create_ns() [ -z "${addr}" ] && addr="-" [ -z "${addr6}" ] && addr6="-" - ip netns add ${ns} - - ip -netns ${ns} link set lo up if [ "${addr}" != "-" ]; then ip -netns ${ns} addr add dev lo ${addr} fi @@ -177,25 +172,25 @@ connect_ns() cleanup() { - ip netns del host1 - ip netns del host2 + cleanup_ns $host1 $host2 } setup() { - create_ns "host1" - create_ns "host2" + setup_ns host1 host2 + create_ns "$host1" + create_ns "$host2" - connect_ns "host1" eth0 ${HOST1_4}/24 ${HOST1_6}/64 \ - "host2" eth0 ${HOST2_4}/24 ${HOST2_6}/64 + connect_ns "$host1" eth0 ${HOST1_4}/24 ${HOST1_6}/64 \ + "$host2" eth0 ${HOST2_4}/24 ${HOST2_6}/64 - create_vrf "host1" ${VRF} ${TABLE} - ip -netns host1 link set dev eth0 master ${VRF} + create_vrf "$host1" ${VRF} ${TABLE} + ip -netns $host1 link set dev eth0 master ${VRF} } cleanup_xfrm() { - for ns in host1 host2 + for ns in $host1 $host2 do for x in state policy do @@ -218,57 +213,57 @@ setup_xfrm() # # host1 - IPv4 out - ip -netns host1 xfrm policy add \ + ip -netns $host1 xfrm policy add \ src ${h1_4} dst ${h2_4} ${devarg} dir out \ tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel # host2 - IPv4 in - ip -netns host2 xfrm policy add \ + ip -netns $host2 xfrm policy add \ src ${h1_4} dst ${h2_4} dir in \ tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel # host1 - IPv4 in - ip -netns host1 xfrm policy add \ + ip -netns $host1 xfrm policy add \ src ${h2_4} dst ${h1_4} ${devarg} dir in \ tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel # host2 - IPv4 out - ip -netns host2 xfrm policy add \ + ip -netns $host2 xfrm policy add \ src ${h2_4} dst ${h1_4} dir out \ tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel # host1 - IPv6 out - ip -6 -netns host1 xfrm policy add \ + ip -6 -netns $host1 xfrm policy add \ src ${h1_6} dst ${h2_6} ${devarg} dir out \ tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel # host2 - IPv6 in - ip -6 -netns host2 xfrm policy add \ + ip -6 -netns $host2 xfrm policy add \ src ${h1_6} dst ${h2_6} dir in \ tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel # host1 - IPv6 in - ip -6 -netns host1 xfrm policy add \ + ip -6 -netns $host1 xfrm policy add \ src ${h2_6} dst ${h1_6} ${devarg} dir in \ tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel # host2 - IPv6 out - ip -6 -netns host2 xfrm policy add \ + ip -6 -netns $host2 xfrm policy add \ src ${h2_6} dst ${h1_6} dir out \ tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel # # state # - ip -netns host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ + ip -netns $host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ proto esp spi ${SPI_1} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \ enc 'cbc(aes)' ${ENC_1} \ sel src ${h1_4} dst ${h2_4} ${devarg} - ip -netns host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ + ip -netns $host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ proto esp spi ${SPI_1} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \ @@ -276,14 +271,14 @@ setup_xfrm() sel src ${h1_4} dst ${h2_4} - ip -netns host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ + ip -netns $host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ proto esp spi ${SPI_2} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \ enc 'cbc(aes)' ${ENC_2} \ sel src ${h2_4} dst ${h1_4} ${devarg} - ip -netns host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ + ip -netns $host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ proto esp spi ${SPI_2} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \ @@ -291,14 +286,14 @@ setup_xfrm() sel src ${h2_4} dst ${h1_4} - ip -6 -netns host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ + ip -6 -netns $host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ proto esp spi ${SPI_1} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \ enc 'cbc(aes)' ${ENC_1} \ sel src ${h1_6} dst ${h2_6} ${devarg} - ip -6 -netns host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ + ip -6 -netns $host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ proto esp spi ${SPI_1} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \ @@ -306,14 +301,14 @@ setup_xfrm() sel src ${h1_6} dst ${h2_6} - ip -6 -netns host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ + ip -6 -netns $host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ proto esp spi ${SPI_2} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \ enc 'cbc(aes)' ${ENC_2} \ sel src ${h2_6} dst ${h1_6} ${devarg} - ip -6 -netns host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ + ip -6 -netns $host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ proto esp spi ${SPI_2} reqid 0 mode tunnel \ replay-window 4 replay-oseq 0x4 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \ @@ -323,22 +318,22 @@ setup_xfrm() cleanup_xfrm_dev() { - ip -netns host1 li del xfrm0 - ip -netns host2 addr del ${XFRM2_4}/24 dev eth0 - ip -netns host2 addr del ${XFRM2_6}/64 dev eth0 + ip -netns $host1 li del xfrm0 + ip -netns $host2 addr del ${XFRM2_4}/24 dev eth0 + ip -netns $host2 addr del ${XFRM2_6}/64 dev eth0 } setup_xfrm_dev() { local vrfarg="vrf ${VRF}" - ip -netns host1 li add type xfrm dev eth0 if_id ${IF_ID} - ip -netns host1 li set xfrm0 ${vrfarg} up - ip -netns host1 addr add ${XFRM1_4}/24 dev xfrm0 - ip -netns host1 addr add ${XFRM1_6}/64 dev xfrm0 + ip -netns $host1 li add type xfrm dev eth0 if_id ${IF_ID} + ip -netns $host1 li set xfrm0 ${vrfarg} up + ip -netns $host1 addr add ${XFRM1_4}/24 dev xfrm0 + ip -netns $host1 addr add ${XFRM1_6}/64 dev xfrm0 - ip -netns host2 addr add ${XFRM2_4}/24 dev eth0 - ip -netns host2 addr add ${XFRM2_6}/64 dev eth0 + ip -netns $host2 addr add ${XFRM2_4}/24 dev eth0 + ip -netns $host2 addr add ${XFRM2_6}/64 dev eth0 setup_xfrm ${XFRM1_4} ${XFRM2_4} ${XFRM1_6} ${XFRM2_6} "if_id ${IF_ID}" } From 9030a77742f309d6b6a30c60093f5d617f33889f Mon Sep 17 00:00:00 2001 From: Hsiao Chien Sung Date: Tue, 24 Oct 2023 21:00:26 +0800 Subject: [PATCH 3366/7721] dt-bindings: display: mediatek: ethdr: Add compatible for MT8188 Add compatible name for MediaTek MT8188 ETHDR. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Krzysztof Kozlowski Reviewed-by: CK Hu Signed-off-by: Hsiao Chien Sung Link: https://patchwork.kernel.org/project/dri-devel/patch/20231024130048.14749-2-shawn.sung@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../bindings/display/mediatek/mediatek,ethdr.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml index 801fa66ae615..677882348ede 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml @@ -23,7 +23,11 @@ description: properties: compatible: - const: mediatek,mt8195-disp-ethdr + oneOf: + - const: mediatek,mt8195-disp-ethdr + - items: + - const: mediatek,mt8188-disp-ethdr + - const: mediatek,mt8195-disp-ethdr reg: maxItems: 7 From e7013a3d77e28f32def43f2e20e32ffb822d86e5 Mon Sep 17 00:00:00 2001 From: Hsiao Chien Sung Date: Tue, 24 Oct 2023 21:00:27 +0800 Subject: [PATCH 3367/7721] dt-bindings: display: mediatek: mdp-rdma: Add compatible for MT8188 Add compatible name for MediaTek MT8188 MDP-RDMA. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Krzysztof Kozlowski Reviewed-by: CK Hu Signed-off-by: Hsiao Chien Sung Link: https://patchwork.kernel.org/project/dri-devel/patch/20231024130048.14749-3-shawn.sung@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../bindings/display/mediatek/mediatek,mdp-rdma.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml index dd12e2ff685c..7570a0684967 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml @@ -21,7 +21,11 @@ description: properties: compatible: - const: mediatek,mt8195-vdo1-rdma + oneOf: + - const: mediatek,mt8195-vdo1-rdma + - items: + - const: mediatek,mt8188-vdo1-rdma + - const: mediatek,mt8195-vdo1-rdma reg: maxItems: 1 From 644977738c445c11c48152e11a1cb50c2fc4bc20 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:43:59 +0100 Subject: [PATCH 3368/7721] dt-bindings: gpu: samsung-rotator: drop redundant quotes Compatibles should not use quotes in the bindings. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231112184403.3449-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/gpu/samsung-rotator.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml index d60626ffb28e..18bf44e06e8f 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml @@ -12,10 +12,11 @@ maintainers: properties: compatible: enum: - - "samsung,s5pv210-rotator" - - "samsung,exynos4210-rotator" - - "samsung,exynos4212-rotator" - - "samsung,exynos5250-rotator" + - samsung,s5pv210-rotator + - samsung,exynos4210-rotator + - samsung,exynos4212-rotator + - samsung,exynos5250-rotator + reg: maxItems: 1 From 6b91e0ee7fc9e5b0ec0a8150ddc5fea15786ec7e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:44:00 +0100 Subject: [PATCH 3369/7721] dt-bindings: gpu: samsung: re-order entries to match coding convention The Devicetree bindings coding convention, as used in most of the files and expressed in Documentation/devicetree/bindings/example-schema.yaml, expects "allOf:" block with if-statements after "required:" block. Re-order few schemas to match the convention to avoid repeating review comments for new patches using existing code as template. No functional changes. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231112184403.3449-2-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/gpu/samsung-g2d.yaml | 53 +++++++++-------- .../bindings/gpu/samsung-scaler.yaml | 59 +++++++++---------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml index e7daae862578..b6951acc7643 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml @@ -27,32 +27,6 @@ properties: iommus: {} power-domains: {} -if: - properties: - compatible: - contains: - const: samsung,exynos5250-g2d - -then: - properties: - clocks: - items: - - description: fimg2d clock - clock-names: - items: - - const: fimg2d - -else: - properties: - clocks: - items: - - description: sclk_fimg2d clock - - description: fimg2d clock - clock-names: - items: - - const: sclk_fimg2d - - const: fimg2d - required: - compatible - reg @@ -60,6 +34,33 @@ required: - clocks - clock-names +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos5250-g2d + + then: + properties: + clocks: + items: + - description: fimg2d clock + clock-names: + items: + - const: fimg2d + + else: + properties: + clocks: + items: + - description: sclk_fimg2d clock + - description: fimg2d clock + clock-names: + items: + - const: sclk_fimg2d + - const: fimg2d + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml index 5317ac64426a..97d86a002a90 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml @@ -26,36 +26,6 @@ properties: iommus: {} power-domains: {} -if: - properties: - compatible: - contains: - const: samsung,exynos5420-scaler - -then: - properties: - clocks: - items: - - description: mscl clock - - clock-names: - items: - - const: mscl - -else: - properties: - clocks: - items: - - description: pclk clock - - description: aclk clock - - description: aclk_xiu clock - - clock-names: - items: - - const: pclk - - const: aclk - - const: aclk_xiu - required: - compatible - reg @@ -63,6 +33,35 @@ required: - clocks - clock-names +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos5420-scaler + + then: + properties: + clocks: + items: + - description: mscl clock + clock-names: + items: + - const: mscl + + else: + properties: + clocks: + items: + - description: pclk clock + - description: aclk clock + - description: aclk_xiu clock + clock-names: + items: + - const: pclk + - const: aclk + - const: aclk_xiu + additionalProperties: false examples: From f1d797b6da5e4a7cacc04eb9a49fe1a421169ff3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:44:01 +0100 Subject: [PATCH 3370/7721] dt-bindings: gpu: samsung: constrain clocks in top-level properties When number of clock varies between variants, the Devicetree bindings coding convention expects to have widest constraints in top-level definition of the properties and narrow them in allOf:if:then block. This is more readable and sometimes allows to spot some errors in the bindings. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231112184403.3449-3-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/gpu/samsung-g2d.yaml | 10 ++++++++-- .../devicetree/bindings/gpu/samsung-scaler.yaml | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml index b6951acc7643..f368966cf83a 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml @@ -22,8 +22,14 @@ properties: interrupts: maxItems: 1 - clocks: {} - clock-names: {} + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + iommus: {} power-domains: {} diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml index 97d86a002a90..e08fc1e4115f 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml @@ -21,8 +21,14 @@ properties: interrupts: maxItems: 1 - clocks: {} - clock-names: {} + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + iommus: {} power-domains: {} From 6ff067f3d56689aa67bf9885f4a63b5160111ae0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:44:02 +0100 Subject: [PATCH 3371/7721] dt-bindings: gpu: samsung-g2d: constrain iommus and power-domains Provide specific constraints for iommus and power-domains, based on current DTS. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231112184403.3449-4-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/gpu/samsung-g2d.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml index f368966cf83a..132aaa49597b 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml @@ -30,8 +30,12 @@ properties: minItems: 1 maxItems: 2 - iommus: {} - power-domains: {} + iommus: + minItems: 1 + maxItems: 2 + + power-domains: + maxItems: 1 required: - compatible From 6a4ff5eab84323f0275b8bde36cf4cea5ff7dcb1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 12 Nov 2023 19:44:03 +0100 Subject: [PATCH 3372/7721] dt-bindings: gpu: samsung-scaler: constrain iommus and power-domains Provide specific constraints for iommus and power-domains, based on current DTS. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231112184403.3449-5-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- .../devicetree/bindings/gpu/samsung-scaler.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml index e08fc1e4115f..9fb530e65d0e 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml @@ -29,8 +29,12 @@ properties: minItems: 1 maxItems: 3 - iommus: {} - power-domains: {} + iommus: + minItems: 1 + maxItems: 2 + + power-domains: + maxItems: 1 required: - compatible @@ -54,6 +58,8 @@ allOf: clock-names: items: - const: mscl + iommus: + minItems: 2 else: properties: @@ -67,6 +73,8 @@ allOf: - const: pclk - const: aclk - const: aclk_xiu + iommus: + maxItems: 1 additionalProperties: false From f0f99f371822c48847e02e56d6e7de507e18f186 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Nov 2023 09:04:36 +0100 Subject: [PATCH 3373/7721] dt-bindings: cache: qcom,llcc: correct QDU1000 reg entries Qualcomm QDU1000 DTSI comes with one LLCC0 base address as pointed by dtbs_check: qdu1000-idp.dtb: system-cache-controller@19200000: reg-names:2: 'llcc2_base' was expected Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Acked-by: Mukesh Ojha Link: https://lore.kernel.org/r/20231107080436.16747-1-krzysztof.kozlowski@linaro.org Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/cache/qcom,llcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 580f9a97ddf7..d610b0be262c 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -64,6 +64,7 @@ allOf: compatible: contains: enum: + - qcom,qdu1000-llcc - qcom,sc7180-llcc - qcom,sm6350-llcc then: @@ -101,7 +102,6 @@ allOf: compatible: contains: enum: - - qcom,qdu1000-llcc - qcom,sc8180x-llcc - qcom,sc8280xp-llcc then: From ffd00b7994dd8e050ba43a49c7a8a4029a0174fd Mon Sep 17 00:00:00 2001 From: Hsiao Chien Sung Date: Tue, 24 Oct 2023 21:00:28 +0800 Subject: [PATCH 3374/7721] dt-bindings: display: mediatek: merge: Add compatible for MT8188 Add compatible name for MediaTek MT8188 MERGE. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Krzysztof Kozlowski Reviewed-by: CK Hu Signed-off-by: Hsiao Chien Sung Link: https://patchwork.kernel.org/project/dri-devel/patch/20231024130048.14749-4-shawn.sung@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../devicetree/bindings/display/mediatek/mediatek,merge.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml index eead5cb8636e..5c678695162e 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml @@ -27,6 +27,9 @@ properties: - items: - const: mediatek,mt6795-disp-merge - const: mediatek,mt8173-disp-merge + - items: + - const: mediatek,mt8188-disp-merge + - const: mediatek,mt8195-disp-merge reg: maxItems: 1 From d2423d8a38e724b28007abd76db08ccb59f56015 Mon Sep 17 00:00:00 2001 From: Hsiao Chien Sung Date: Tue, 24 Oct 2023 21:00:29 +0800 Subject: [PATCH 3375/7721] dt-bindings: display: mediatek: padding: Add MT8188 Padding is a new hardware module on MediaTek MT8188, add dt-bindings for it. Reviewed-by: Krzysztof Kozlowski Reviewed-by: CK Hu Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hsiao Chien Sung Link: https://patchwork.kernel.org/project/dri-devel/patch/20231024130048.14749-5-shawn.sung@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../display/mediatek/mediatek,padding.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml new file mode 100644 index 000000000000..6bad7dc2d69f --- /dev/null +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/mediatek/mediatek,padding.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Display Padding + +maintainers: + - Chun-Kuang Hu + - Philipp Zabel + +description: + Padding provides ability to add pixels to width and height of a layer with + specified colors. Due to hardware design, Mixer in VDOSYS1 requires + width of a layer to be 2-pixel-align, or 4-pixel-align when ETHDR is enabled, + we need Padding to deal with odd width. + Please notice that even if the Padding is in bypass mode, settings in + register must be cleared to 0, or undefined behaviors could happen. + +properties: + compatible: + const: mediatek,mt8188-disp-padding + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + clocks: + items: + - description: Padding's clocks + + mediatek,gce-client-reg: + description: + GCE (Global Command Engine) is a multi-core micro processor that helps + its clients to execute commands without interrupting CPU. This property + describes GCE client's information that is composed by 4 fields. + 1. Phandle of the GCE (there may be several GCE processors) + 2. Sub-system ID defined in the dt-binding like a user ID + (Please refer to include/dt-bindings/gce/-gce.h) + 3. Offset from base address of the subsys you are at + 4. Size of the register the client needs + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: Phandle of the GCE + - description: Subsys ID defined in the dt-binding + - description: Offset from base address of the subsys + - description: Size of register + maxItems: 1 + +required: + - compatible + - reg + - power-domains + - clocks + - mediatek,gce-client-reg + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + padding0: padding@1c11d000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c11d000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0xd000 0x1000>; + }; + }; From b53d47775651aa51bb98cdeb968dedb45699d9a1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2023 11:09:25 +0100 Subject: [PATCH 3376/7721] ASoC: wm0010: Convert to GPIO descriptors This converts the WM0010 codec to use GPIO descriptors. It's a pretty straight-forward conversion also switching over the single in-tree user in the S3C Cragganmore module for S3C 6410. Signed-off-by: Linus Walleij Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231208-descriptors-sound-wlf-v1-1-c4dab6f521ec@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410-module.c | 16 +++++++-- include/sound/wm0010.h | 6 ---- sound/soc/codecs/wm0010.c | 44 ++++++------------------ 3 files changed, 23 insertions(+), 43 deletions(-) diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index 8fce1e815ee8..a9a713641047 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -32,9 +32,18 @@ #include "crag6410.h" +static struct gpiod_lookup_table wm0010_gpiod_table = { + .dev_id = "spi0.0", /* SPI device name */ + .table = { + /* Active high for Glenfarclas Rev 2 */ + GPIO_LOOKUP("GPION", 6, + "reset", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm0010_pdata wm0010_pdata = { - .gpio_reset = S3C64XX_GPN(6), - .reset_active_high = 1, /* Active high for Glenfarclas Rev 2 */ + /* Intentionally left blank */ }; static struct spi_board_info wm1253_devs[] = { @@ -337,7 +346,8 @@ static const struct { { .id = 0x21, .rev = 0xff, .name = "1275-EV1 Mortlach" }, { .id = 0x25, .rev = 0xff, .name = "1274-EV1 Glencadam" }, { .id = 0x31, .rev = 0xff, .name = "1253-EV1 Tomatin", - .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) }, + .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs), + .gpiod_table = &wm0010_gpiod_table }, { .id = 0x32, .rev = 0xff, .name = "XXXX-EV1 Caol Illa" }, { .id = 0x33, .rev = 0xff, .name = "XXXX-EV1 Oban" }, { .id = 0x34, .rev = 0xff, .name = "WM0010-6320-CS42 Balblair", diff --git a/include/sound/wm0010.h b/include/sound/wm0010.h index 13b473935ca1..14ff9056c5d0 100644 --- a/include/sound/wm0010.h +++ b/include/sound/wm0010.h @@ -11,12 +11,6 @@ #define WM0010_PDATA_H struct wm0010_pdata { - int gpio_reset; - - /* Set if there is an inverter between the GPIO controlling - * the reset signal and the device. - */ - int reset_active_high; int irq_flags; }; diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 1d4259433f47..8f862729a2ca 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -94,8 +94,7 @@ struct wm0010_priv { struct wm0010_pdata pdata; - int gpio_reset; - int gpio_reset_value; + struct gpio_desc *reset; struct regulator_bulk_data core_supplies[2]; struct regulator *dbvdd; @@ -174,8 +173,7 @@ static void wm0010_halt(struct snd_soc_component *component) case WM0010_STAGE2: case WM0010_FIRMWARE: /* Remember to put chip back into reset */ - gpio_set_value_cansleep(wm0010->gpio_reset, - wm0010->gpio_reset_value); + gpiod_set_value_cansleep(wm0010->reset, 1); /* Disable the regulators */ regulator_disable(wm0010->dbvdd); regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies), @@ -610,7 +608,7 @@ static int wm0010_boot(struct snd_soc_component *component) } /* Release reset */ - gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); + gpiod_set_value_cansleep(wm0010->reset, 0); spin_lock_irqsave(&wm0010->irq_lock, flags); wm0010->state = WM0010_OUT_OF_RESET; spin_unlock_irqrestore(&wm0010->irq_lock, flags); @@ -863,7 +861,6 @@ static int wm0010_probe(struct snd_soc_component *component) static int wm0010_spi_probe(struct spi_device *spi) { - unsigned long gpio_flags; int ret; int trigger; int irq; @@ -903,31 +900,11 @@ static int wm0010_spi_probe(struct spi_device *spi) return ret; } - if (wm0010->pdata.gpio_reset) { - wm0010->gpio_reset = wm0010->pdata.gpio_reset; - - if (wm0010->pdata.reset_active_high) - wm0010->gpio_reset_value = 1; - else - wm0010->gpio_reset_value = 0; - - if (wm0010->gpio_reset_value) - gpio_flags = GPIOF_OUT_INIT_HIGH; - else - gpio_flags = GPIOF_OUT_INIT_LOW; - - ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset, - gpio_flags, "wm0010 reset"); - if (ret < 0) { - dev_err(wm0010->dev, - "Failed to request GPIO for DSP reset: %d\n", - ret); - return ret; - } - } else { - dev_err(wm0010->dev, "No reset GPIO configured\n"); - return -EINVAL; - } + wm0010->reset = devm_gpiod_get(wm0010->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(wm0010->reset)) + return dev_err_probe(wm0010->dev, PTR_ERR(wm0010->reset), + "could not get RESET GPIO\n"); + gpiod_set_consumer_name(wm0010->reset, "wm0010 reset"); wm0010->state = WM0010_POWER_OFF; @@ -972,8 +949,7 @@ static void wm0010_spi_remove(struct spi_device *spi) { struct wm0010_priv *wm0010 = spi_get_drvdata(spi); - gpio_set_value_cansleep(wm0010->gpio_reset, - wm0010->gpio_reset_value); + gpiod_set_value_cansleep(wm0010->reset, 1); irq_set_irq_wake(wm0010->irq, 0); From 10a366f36e2a2e240d9db6da90e501fa16655282 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2023 11:09:26 +0100 Subject: [PATCH 3377/7721] ASoC: wm1250-ev1: Convert to GPIO descriptors This converts the WM1250-EV1 codec to use GPIO descriptors. It turns out that the platform data was only used to pass some global GPIO numbers from a board file, so we get rid of this and also switch over the single in-tree user in the S3C Cragganmore module for S3C 6410. The driver obtains two GPIO lines named OSR and master and just pull them low, we leave this behaviour as it was. Signed-off-by: Linus Walleij Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231208-descriptors-sound-wlf-v1-2-c4dab6f521ec@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410.c | 24 +++---- include/sound/wm1250-ev1.h | 24 ------- sound/soc/codecs/wm1250-ev1.c | 114 +++++++++++------------------- 3 files changed, 54 insertions(+), 108 deletions(-) delete mode 100644 include/sound/wm1250-ev1.h diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c index 7c4bed4370a1..e5df2cb51ab2 100644 --- a/arch/arm/mach-s3c/mach-crag6410.c +++ b/arch/arm/mach-s3c/mach-crag6410.c @@ -39,8 +39,6 @@ #include #include -#include - #include #include @@ -713,13 +711,16 @@ static struct wm831x_pdata glenfarclas_pmic_pdata = { .disable_touch = true, }; -static struct wm1250_ev1_pdata wm1250_ev1_pdata = { - .gpios = { - [WM1250_EV1_GPIO_CLK_ENA] = S3C64XX_GPN(12), - [WM1250_EV1_GPIO_CLK_SEL0] = S3C64XX_GPL(12), - [WM1250_EV1_GPIO_CLK_SEL1] = S3C64XX_GPL(13), - [WM1250_EV1_GPIO_OSR] = S3C64XX_GPL(14), - [WM1250_EV1_GPIO_MASTER] = S3C64XX_GPL(8), +static struct gpiod_lookup_table crag_wm1250_ev1_gpiod_table = { + /* The WM1250-EV1 is device 0027 on I2C bus 1 */ + .dev_id = "1-0027", + .table = { + GPIO_LOOKUP("GPION", 12, "clk-ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 12, "clk-sel0", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 13, "clk-sel1", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 14, "osr", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 8, "master", GPIO_ACTIVE_HIGH), + { }, }, }; @@ -733,9 +734,7 @@ static struct i2c_board_info i2c_devs1[] = { { I2C_BOARD_INFO("wlf-gf-module", 0x24) }, { I2C_BOARD_INFO("wlf-gf-module", 0x25) }, { I2C_BOARD_INFO("wlf-gf-module", 0x26) }, - - { I2C_BOARD_INFO("wm1250-ev1", 0x27), - .platform_data = &wm1250_ev1_pdata }, + { I2C_BOARD_INFO("wm1250-ev1", 0x27), }, }; static struct s3c2410_platform_i2c i2c1_pdata = { @@ -862,6 +861,7 @@ static void __init crag6410_machine_init(void) gpiod_add_lookup_table(&crag_pmic_gpiod_table); i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); + gpiod_add_lookup_table(&crag_wm1250_ev1_gpiod_table); i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); samsung_keypad_set_platdata(&crag6410_keypad_data); diff --git a/include/sound/wm1250-ev1.h b/include/sound/wm1250-ev1.h deleted file mode 100644 index d16614ebecb4..000000000000 --- a/include/sound/wm1250-ev1.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/sound/wm1250-ev1.h - Platform data for WM1250-EV1 - * - * Copyright 2011 Wolfson Microelectronics. PLC. - */ - -#ifndef __LINUX_SND_WM1250_EV1_H -#define __LINUX_SND_WM1250_EV1_H - -#define WM1250_EV1_NUM_GPIOS 5 - -#define WM1250_EV1_GPIO_CLK_ENA 0 -#define WM1250_EV1_GPIO_CLK_SEL0 1 -#define WM1250_EV1_GPIO_CLK_SEL1 2 -#define WM1250_EV1_GPIO_OSR 3 -#define WM1250_EV1_GPIO_MASTER 4 - - -struct wm1250_ev1_pdata { - int gpios[WM1250_EV1_NUM_GPIOS]; -}; - -#endif diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index d7eeb41ba60f..a2a8b2a4b19b 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -9,34 +9,23 @@ #include #include #include -#include +#include #include #include -#include - -static const char *wm1250_gpio_names[WM1250_EV1_NUM_GPIOS] = { - "WM1250 CLK_ENA", - "WM1250 CLK_SEL0", - "WM1250 CLK_SEL1", - "WM1250 OSR", - "WM1250 MASTER", -}; struct wm1250_priv { - struct gpio gpios[WM1250_EV1_NUM_GPIOS]; + struct gpio_desc *clk_ena; + struct gpio_desc *clk_sel0; + struct gpio_desc *clk_sel1; + struct gpio_desc *osr; + struct gpio_desc *master; }; static int wm1250_ev1_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct wm1250_priv *wm1250 = dev_get_drvdata(component->dev); - int ena; - - if (wm1250) - ena = wm1250->gpios[WM1250_EV1_GPIO_CLK_ENA].gpio; - else - ena = -1; switch (level) { case SND_SOC_BIAS_ON: @@ -46,13 +35,11 @@ static int wm1250_ev1_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: - if (ena >= 0) - gpio_set_value_cansleep(ena, 1); + gpiod_set_value_cansleep(wm1250->clk_ena, 1); break; case SND_SOC_BIAS_OFF: - if (ena >= 0) - gpio_set_value_cansleep(ena, 0); + gpiod_set_value_cansleep(wm1250->clk_ena, 0); break; } @@ -80,28 +67,20 @@ static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio, - 1); - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio, - 1); + gpiod_set_value(wm1250->clk_sel0, 1); + gpiod_set_value(wm1250->clk_sel1, 1); break; case 16000: - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio, - 0); - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio, - 1); + gpiod_set_value(wm1250->clk_sel0, 0); + gpiod_set_value(wm1250->clk_sel1, 1); break; case 32000: - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio, - 1); - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio, - 0); + gpiod_set_value(wm1250->clk_sel0, 1); + gpiod_set_value(wm1250->clk_sel1, 0); break; case 64000: - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio, - 0); - gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio, - 0); + gpiod_set_value(wm1250->clk_sel0, 0); + gpiod_set_value(wm1250->clk_sel1, 0); break; default: return -EINVAL; @@ -150,45 +129,43 @@ static int wm1250_ev1_pdata(struct i2c_client *i2c) { struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm1250_priv *wm1250; - int i, ret; + int ret; if (!pdata) return 0; wm1250 = devm_kzalloc(&i2c->dev, sizeof(*wm1250), GFP_KERNEL); - if (!wm1250) { - ret = -ENOMEM; - goto err; - } + if (!wm1250) + return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(wm1250->gpios); i++) { - wm1250->gpios[i].gpio = pdata->gpios[i]; - wm1250->gpios[i].label = wm1250_gpio_names[i]; - wm1250->gpios[i].flags = GPIOF_OUT_INIT_LOW; - } - wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].flags = GPIOF_OUT_INIT_HIGH; - wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].flags = GPIOF_OUT_INIT_HIGH; + wm1250->clk_ena = devm_gpiod_get(&i2c->dev, "clk-ena", GPIOD_OUT_LOW); + if (IS_ERR(wm1250->clk_ena)) + return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_ena), + "failed to get clock enable GPIO\n"); - ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios)); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret); - goto err; - } + wm1250->clk_sel0 = devm_gpiod_get(&i2c->dev, "clk-sel0", GPIOD_OUT_HIGH); + if (IS_ERR(wm1250->clk_sel0)) + return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_sel0), + "failed to get clock sel0 GPIO\n"); + + wm1250->clk_sel1 = devm_gpiod_get(&i2c->dev, "clk-sel1", GPIOD_OUT_HIGH); + if (IS_ERR(wm1250->clk_sel1)) + return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_sel1), + "failed to get clock sel1 GPIO\n"); + + wm1250->osr = devm_gpiod_get(&i2c->dev, "osr", GPIOD_OUT_LOW); + if (IS_ERR(wm1250->osr)) + return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->osr), + "failed to get OSR GPIO\n"); + + wm1250->master = devm_gpiod_get(&i2c->dev, "master", GPIOD_OUT_LOW); + if (IS_ERR(wm1250->master)) + return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->master), + "failed to get MASTER GPIO\n"); dev_set_drvdata(&i2c->dev, wm1250); return ret; - -err: - return ret; -} - -static void wm1250_ev1_free(struct i2c_client *i2c) -{ - struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev); - - if (wm1250) - gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios)); } static int wm1250_ev1_probe(struct i2c_client *i2c) @@ -221,18 +198,12 @@ static int wm1250_ev1_probe(struct i2c_client *i2c) &wm1250_ev1_dai, 1); if (ret != 0) { dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - wm1250_ev1_free(i2c); return ret; } return 0; } -static void wm1250_ev1_remove(struct i2c_client *i2c) -{ - wm1250_ev1_free(i2c); -} - static const struct i2c_device_id wm1250_ev1_i2c_id[] = { { "wm1250-ev1", 0 }, { } @@ -244,7 +215,6 @@ static struct i2c_driver wm1250_ev1_i2c_driver = { .name = "wm1250-ev1", }, .probe = wm1250_ev1_probe, - .remove = wm1250_ev1_remove, .id_table = wm1250_ev1_i2c_id, }; From 0119b2a24eb592f967a2849b772887c96617ad80 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2023 11:09:27 +0100 Subject: [PATCH 3378/7721] ASoC: wm2200: Convert to GPIO descriptors This converts the WM2200 codec to use GPIO descriptors. This is a pretty straight-forward conversion, and it also switches over the single in-tree user in the S3C Cragganmore module for S3C 6410. This coded does not seem to get selected or be selectable through Kconfig, I had to hack another soundcard Kconfig entry to select it for compile tests. Signed-off-by: Linus Walleij Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231208-descriptors-sound-wlf-v1-3-c4dab6f521ec@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410-module.c | 13 ++++- include/sound/wm2200.h | 2 - sound/soc/codecs/wm2200.c | 67 ++++++++++++------------ 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index a9a713641047..1df6b7e52c9d 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -305,12 +305,20 @@ static const struct i2c_board_info wm6230_i2c_devs[] = { }; static struct wm2200_pdata wm2200_pdata = { - .ldo_ena = S3C64XX_GPN(7), .gpio_defaults = { [2] = 0x0005, /* GPIO3 24.576MHz output clock */ }, }; +static struct gpiod_lookup_table wm2200_gpiod_table = { + .dev_id = "1-003a", /* Device 003a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static const struct i2c_board_info wm2200_i2c[] = { { I2C_BOARD_INFO("wm2200", 0x3a), .platform_data = &wm2200_pdata, }, @@ -372,7 +380,8 @@ static const struct { .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs), .gpiod_table = &wm5102_gpiod_table }, { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1", - .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) }, + .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c), + .gpiod_table = &wm2200_gpiod_table }, }; static int wlf_gf_module_probe(struct i2c_client *i2c) diff --git a/include/sound/wm2200.h b/include/sound/wm2200.h index 9987e6c09bdc..2e4913ee2505 100644 --- a/include/sound/wm2200.h +++ b/include/sound/wm2200.h @@ -42,8 +42,6 @@ struct wm2200_micbias { }; struct wm2200_pdata { - int reset; /** GPIO controlling /RESET, if any */ - int ldo_ena; /** GPIO controlling LODENA, if any */ int irq_flags; int gpio_defaults[4]; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 9679906c6bd5..69c9c2bd7e7b 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,6 +79,8 @@ struct wm2200_priv { struct snd_soc_component *component; struct wm2200_pdata pdata; struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES]; + struct gpio_desc *ldo_ena; + struct gpio_desc *reset; struct completion fll_lock; int fll_fout; @@ -975,9 +977,10 @@ static const struct reg_sequence wm2200_reva_patch[] = { static int wm2200_reset(struct wm2200_priv *wm2200) { - if (wm2200->pdata.reset) { - gpio_set_value_cansleep(wm2200->pdata.reset, 0); - gpio_set_value_cansleep(wm2200->pdata.reset, 1); + if (wm2200->reset) { + /* Descriptor flagged active low, so this will be inverted */ + gpiod_set_value_cansleep(wm2200->reset, 1); + gpiod_set_value_cansleep(wm2200->reset, 0); return 0; } else { @@ -2246,28 +2249,28 @@ static int wm2200_i2c_probe(struct i2c_client *i2c) return ret; } - if (wm2200->pdata.ldo_ena) { - ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena, - GPIOF_OUT_INIT_HIGH, - "WM2200 LDOENA"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n", - wm2200->pdata.ldo_ena, ret); - goto err_enable; - } + wm2200->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena", + GPIOD_OUT_HIGH); + if (IS_ERR(wm2200->ldo_ena)) { + ret = PTR_ERR(wm2200->ldo_ena); + dev_err(&i2c->dev, "Failed to request LDOENA GPIO %d\n", + ret); + goto err_enable; + } + if (wm2200->ldo_ena) { + gpiod_set_consumer_name(wm2200->ldo_ena, "WM2200 LDOENA"); msleep(2); } - if (wm2200->pdata.reset) { - ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset, - GPIOF_OUT_INIT_HIGH, - "WM2200 /RESET"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n", - wm2200->pdata.reset, ret); - goto err_ldo; - } + wm2200->reset = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(wm2200->reset)) { + ret = PTR_ERR(wm2200->reset); + dev_err(&i2c->dev, "Failed to request RESET GPIO %d\n", + ret); + goto err_ldo; } + gpiod_set_consumer_name(wm2200->reset, "WM2200 /RESET"); ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, ®); if (ret < 0) { @@ -2403,11 +2406,9 @@ static int wm2200_i2c_probe(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, wm2200); err_reset: - if (wm2200->pdata.reset) - gpio_set_value_cansleep(wm2200->pdata.reset, 0); + gpiod_set_value_cansleep(wm2200->reset, 1); err_ldo: - if (wm2200->pdata.ldo_ena) - gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + gpiod_set_value_cansleep(wm2200->ldo_ena, 0); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); @@ -2421,10 +2422,9 @@ static void wm2200_i2c_remove(struct i2c_client *i2c) pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm2200); - if (wm2200->pdata.reset) - gpio_set_value_cansleep(wm2200->pdata.reset, 0); - if (wm2200->pdata.ldo_ena) - gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + /* Assert RESET, disable LDO */ + gpiod_set_value_cansleep(wm2200->reset, 1); + gpiod_set_value_cansleep(wm2200->ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); } @@ -2436,8 +2436,7 @@ static int wm2200_runtime_suspend(struct device *dev) regcache_cache_only(wm2200->regmap, true); regcache_mark_dirty(wm2200->regmap); - if (wm2200->pdata.ldo_ena) - gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + gpiod_set_value_cansleep(wm2200->ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); @@ -2457,8 +2456,8 @@ static int wm2200_runtime_resume(struct device *dev) return ret; } - if (wm2200->pdata.ldo_ena) { - gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1); + if (wm2200->ldo_ena) { + gpiod_set_value_cansleep(wm2200->ldo_ena, 1); msleep(2); } From 8563cfe39ba5d00d974df25e310fb61b5b3687e1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2023 11:09:28 +0100 Subject: [PATCH 3379/7721] ASoC: wm5100: Convert to GPIO descriptors This converts the WM5100 codec to use GPIO descriptors, a pretty straight-forward conversion with the following peculiarities: - The driver is instantiating a GPIO chip named wm5100, and the headphone polarity detection GPIO is lifted from there. We add this to the GPIO descriptor table as well, and we can then get rid of also the base address for the GPIO chip from the platform data and just use dynamic numbering. - Fix up the only in-tree user which is the Cragganmore 6410 module. Signed-off-by: Linus Walleij Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231208-descriptors-sound-wlf-v1-4-c4dab6f521ec@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410-module.c | 17 +++- include/sound/wm5100.h | 4 - sound/soc/codecs/wm5100.c | 107 +++++++++-------------- 3 files changed, 52 insertions(+), 76 deletions(-) diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index 1df6b7e52c9d..59456fbebf1b 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -70,10 +70,19 @@ static struct spi_board_info balblair_devs[] = { }, }; +static struct gpiod_lookup_table wm5100_gpiod_table = { + .dev_id = "1-001a", /* Device 001a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wm5100", 3, + "hp-pol", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm5100_pdata wm5100_pdata = { - .ldo_ena = S3C64XX_GPN(7), .irq_flags = IRQF_TRIGGER_HIGH, - .gpio_base = CODEC_GPIO_BASE, .in_mode = { WM5100_IN_DIFF, @@ -82,7 +91,6 @@ static struct wm5100_pdata wm5100_pdata = { WM5100_IN_SE, }, - .hp_pol = CODEC_GPIO_BASE + 3, .jack_modes = { { WM5100_MICDET_MICBIAS3, 0, 0 }, { WM5100_MICDET_MICBIAS2, 1, 1 }, @@ -366,7 +374,8 @@ static const struct { { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory", .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman", - .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) }, + .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs), + .gpiod_table = &wm5100_gpiod_table }, { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" }, { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill", .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs), diff --git a/include/sound/wm5100.h b/include/sound/wm5100.h index b94badf72947..1c48090fdb2c 100644 --- a/include/sound/wm5100.h +++ b/include/sound/wm5100.h @@ -36,11 +36,7 @@ struct wm5100_jack_mode { #define WM5100_GPIO_SET 0x10000 struct wm5100_pdata { - int reset; /** GPIO controlling /RESET, if any */ - int ldo_ena; /** GPIO controlling LODENA, if any */ - int hp_pol; /** GPIO controlling headset polarity, if any */ int irq_flags; - int gpio_base; struct wm5100_jack_mode jack_modes[2]; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index ff63723928a1..7ee4b45c0834 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,6 +55,9 @@ struct wm5100_priv { struct snd_soc_component *component; struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES]; + struct gpio_desc *reset; + struct gpio_desc *ldo_ena; + struct gpio_desc *hp_pol; int rev; @@ -205,9 +208,9 @@ static void wm5100_free_sr(struct snd_soc_component *component, int rate) static int wm5100_reset(struct wm5100_priv *wm5100) { - if (wm5100->pdata.reset) { - gpio_set_value_cansleep(wm5100->pdata.reset, 0); - gpio_set_value_cansleep(wm5100->pdata.reset, 1); + if (wm5100->reset) { + gpiod_set_value_cansleep(wm5100->reset, 1); + gpiod_set_value_cansleep(wm5100->reset, 0); return 0; } else { @@ -1974,7 +1977,7 @@ static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode) if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes))) return; - gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol); + gpiod_set_value_cansleep(wm5100->hp_pol, mode->hp_pol); regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1, WM5100_ACCDET_BIAS_SRC_MASK | WM5100_ACCDET_SRC, @@ -2299,11 +2302,7 @@ static void wm5100_init_gpio(struct i2c_client *i2c) wm5100->gpio_chip = wm5100_template_chip; wm5100->gpio_chip.ngpio = 6; wm5100->gpio_chip.parent = &i2c->dev; - - if (wm5100->pdata.gpio_base) - wm5100->gpio_chip.base = wm5100->pdata.gpio_base; - else - wm5100->gpio_chip.base = -1; + wm5100->gpio_chip.base = -1; ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100); if (ret != 0) @@ -2349,35 +2348,20 @@ static int wm5100_probe(struct snd_soc_component *component) snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq, ARRAY_SIZE(wm5100_dapm_widgets_noirq)); - if (wm5100->pdata.hp_pol) { - ret = gpio_request_one(wm5100->pdata.hp_pol, - GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n", - wm5100->pdata.hp_pol, ret); - goto err_gpio; - } + wm5100->hp_pol = devm_gpiod_get_optional(&i2c->dev, "hp-pol", + GPIOD_OUT_HIGH); + if (IS_ERR(wm5100->hp_pol)) { + ret = PTR_ERR(wm5100->hp_pol); + dev_err(&i2c->dev, "Failed to request HP_POL GPIO: %d\n", + ret); + return ret; } return 0; - -err_gpio: - - return ret; -} - -static void wm5100_remove(struct snd_soc_component *component) -{ - struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component); - - if (wm5100->pdata.hp_pol) { - gpio_free(wm5100->pdata.hp_pol); - } } static const struct snd_soc_component_driver soc_component_dev_wm5100 = { .probe = wm5100_probe, - .remove = wm5100_remove, .set_sysclk = wm5100_set_sysclk, .set_pll = wm5100_set_fll, .seq_notifier = wm5100_seq_notifier, @@ -2460,26 +2444,26 @@ static int wm5100_i2c_probe(struct i2c_client *i2c) goto err; } - if (wm5100->pdata.ldo_ena) { - ret = gpio_request_one(wm5100->pdata.ldo_ena, - GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n", - wm5100->pdata.ldo_ena, ret); - goto err_enable; - } + wm5100->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena", + GPIOD_OUT_HIGH); + if (IS_ERR(wm5100->ldo_ena)) { + ret = PTR_ERR(wm5100->ldo_ena); + dev_err(&i2c->dev, "Failed to request LDOENA GPIO: %d\n", ret); + goto err_enable; + } + if (wm5100->ldo_ena) { + gpiod_set_consumer_name(wm5100->ldo_ena, "WM5100 LDOENA"); msleep(2); } - if (wm5100->pdata.reset) { - ret = gpio_request_one(wm5100->pdata.reset, - GPIOF_OUT_INIT_HIGH, "WM5100 /RESET"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n", - wm5100->pdata.reset, ret); - goto err_ldo; - } + wm5100->reset = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(wm5100->reset)) { + ret = PTR_ERR(wm5100->reset); + dev_err(&i2c->dev, "Failed to request /RESET GPIO: %d\n", ret); + goto err_ldo; } + gpiod_set_consumer_name(wm5100->reset, "WM5100 /RESET"); ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, ®); if (ret < 0) { @@ -2619,15 +2603,9 @@ static int wm5100_i2c_probe(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); - if (wm5100->pdata.reset) { - gpio_set_value_cansleep(wm5100->pdata.reset, 0); - gpio_free(wm5100->pdata.reset); - } + gpiod_set_value_cansleep(wm5100->reset, 1); err_ldo: - if (wm5100->pdata.ldo_ena) { - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); - gpio_free(wm5100->pdata.ldo_ena); - } + gpiod_set_value_cansleep(wm5100->ldo_ena, 0); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), wm5100->core_supplies); @@ -2643,14 +2621,8 @@ static void wm5100_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); - if (wm5100->pdata.reset) { - gpio_set_value_cansleep(wm5100->pdata.reset, 0); - gpio_free(wm5100->pdata.reset); - } - if (wm5100->pdata.ldo_ena) { - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); - gpio_free(wm5100->pdata.ldo_ena); - } + gpiod_set_value_cansleep(wm5100->reset, 1); + gpiod_set_value_cansleep(wm5100->ldo_ena, 0); } #ifdef CONFIG_PM @@ -2660,8 +2632,7 @@ static int wm5100_runtime_suspend(struct device *dev) regcache_cache_only(wm5100->regmap, true); regcache_mark_dirty(wm5100->regmap); - if (wm5100->pdata.ldo_ena) - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); + gpiod_set_value_cansleep(wm5100->ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), wm5100->core_supplies); @@ -2681,8 +2652,8 @@ static int wm5100_runtime_resume(struct device *dev) return ret; } - if (wm5100->pdata.ldo_ena) { - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1); + if (wm5100->ldo_ena) { + gpiod_set_value_cansleep(wm5100->ldo_ena, 1); msleep(2); } From 729f02ec02ae12e5d8a53171bd37e9de56f33677 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2023 11:09:29 +0100 Subject: [PATCH 3380/7721] ASoC: wm8996: Convert to GPIO descriptors This converts the WM8996 codec to use GPIO descriptors, an a similar way to WM5100. The driver is instantiating a GPIO chip named wm8996, and we get rid of the base address for the GPIO chip from the platform data and just use dynamic numbering. Move base and ngpio into the static gpio_chip template. Fix up the only in-tree user which is the Cragganmore 6410 module. Signed-off-by: Linus Walleij Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20231208-descriptors-sound-wlf-v1-5-c4dab6f521ec@linaro.org Signed-off-by: Mark Brown --- arch/arm/mach-s3c/mach-crag6410-module.c | 14 ++++-- include/sound/wm8996.h | 3 -- sound/soc/codecs/wm8996.c | 58 ++++++++++-------------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index 59456fbebf1b..2de1a89f6e99 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -127,9 +127,16 @@ static struct wm8996_retune_mobile_config wm8996_retune[] = { }, }; +static struct gpiod_lookup_table wm8996_gpiod_table = { + .dev_id = "1-001a", /* Device 001a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm8996_pdata wm8996_pdata __initdata = { - .ldo_ena = S3C64XX_GPN(7), - .gpio_base = CODEC_GPIO_BASE, .micdet_def = 1, .inl_mode = WM8996_DIFFERRENTIAL_1, .inr_mode = WM8996_DIFFERRENTIAL_1, @@ -370,7 +377,8 @@ static const struct { .spi_devs = balblair_devs, .num_spi_devs = ARRAY_SIZE(balblair_devs) }, { .id = 0x39, .rev = 0xff, .name = "1254-EV1 Dallas Dhu", - .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, + .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs), + .gpiod_table = &wm8996_gpiod_table }, { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory", .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman", diff --git a/include/sound/wm8996.h b/include/sound/wm8996.h index 247f9917e33d..342abeef288f 100644 --- a/include/sound/wm8996.h +++ b/include/sound/wm8996.h @@ -33,8 +33,6 @@ struct wm8996_retune_mobile_config { struct wm8996_pdata { int irq_flags; /** Set IRQ trigger flags; default active low */ - int ldo_ena; /** GPIO for LDO1; -1 for none */ - int micdet_def; /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */ enum wm8996_inmode inl_mode; @@ -42,7 +40,6 @@ struct wm8996_pdata { u32 spkmute_seq; /** Value for register 0x802 */ - int gpio_base; u32 gpio_default[5]; int num_retune_mobile_cfgs; diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index df6195778c57..e738326e33ed 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,7 +51,7 @@ struct wm8996_priv { struct regmap *regmap; struct snd_soc_component *component; - int ldo1ena; + struct gpio_desc *ldo_ena; int sysclk; int sysclk_src; @@ -1596,9 +1596,9 @@ static int wm8996_set_bias_level(struct snd_soc_component *component, return ret; } - if (wm8996->pdata.ldo_ena >= 0) { - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, - 1); + if (wm8996->ldo_ena) { + gpiod_set_value_cansleep(wm8996->ldo_ena, + 1); msleep(5); } @@ -1615,8 +1615,8 @@ static int wm8996_set_bias_level(struct snd_soc_component *component, case SND_SOC_BIAS_OFF: regcache_cache_only(wm8996->regmap, true); - if (wm8996->pdata.ldo_ena >= 0) { - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); + if (wm8996->ldo_ena) { + gpiod_set_value_cansleep(wm8996->ldo_ena, 0); regcache_cache_only(wm8996->regmap, true); } regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), @@ -2188,6 +2188,8 @@ static const struct gpio_chip wm8996_template_chip = { .direction_input = wm8996_gpio_direction_in, .get = wm8996_gpio_get, .can_sleep = 1, + .ngpio = 5, + .base = -1, }; static void wm8996_init_gpio(struct wm8996_priv *wm8996) @@ -2195,14 +2197,8 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) int ret; wm8996->gpio_chip = wm8996_template_chip; - wm8996->gpio_chip.ngpio = 5; wm8996->gpio_chip.parent = wm8996->dev; - if (wm8996->pdata.gpio_base) - wm8996->gpio_chip.base = wm8996->pdata.gpio_base; - else - wm8996->gpio_chip.base = -1; - ret = gpiochip_add_data(&wm8996->gpio_chip, wm8996); if (ret != 0) dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret); @@ -2771,15 +2767,15 @@ static int wm8996_i2c_probe(struct i2c_client *i2c) memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev), sizeof(wm8996->pdata)); - if (wm8996->pdata.ldo_ena > 0) { - ret = gpio_request_one(wm8996->pdata.ldo_ena, - GPIOF_OUT_INIT_LOW, "WM8996 ENA"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n", - wm8996->pdata.ldo_ena, ret); - goto err; - } + wm8996->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena", + GPIOD_OUT_LOW); + if (IS_ERR(wm8996->ldo_ena)) { + ret = PTR_ERR(wm8996->ldo_ena); + dev_err(&i2c->dev, "Failed to request LDO ENA GPIO: %d\n", + ret); + goto err; } + gpiod_set_consumer_name(wm8996->ldo_ena, "WM8996 ENA"); for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) wm8996->supplies[i].supply = wm8996_supply_names[i]; @@ -2814,8 +2810,8 @@ static int wm8996_i2c_probe(struct i2c_client *i2c) goto err_gpio; } - if (wm8996->pdata.ldo_ena > 0) { - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1); + if (wm8996->ldo_ena) { + gpiod_set_value_cansleep(wm8996->ldo_ena, 1); msleep(5); } @@ -2847,8 +2843,8 @@ static int wm8996_i2c_probe(struct i2c_client *i2c) dev_info(&i2c->dev, "revision %c\n", (reg & WM8996_CHIP_REV_MASK) + 'A'); - if (wm8996->pdata.ldo_ena > 0) { - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); + if (wm8996->ldo_ena) { + gpiod_set_value_cansleep(wm8996->ldo_ena, 0); regcache_cache_only(wm8996->regmap, true); } else { ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET, @@ -3054,12 +3050,10 @@ static int wm8996_i2c_probe(struct i2c_client *i2c) wm8996_free_gpio(wm8996); err_regmap: err_enable: - if (wm8996->pdata.ldo_ena > 0) - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); + if (wm8996->ldo_ena) + gpiod_set_value_cansleep(wm8996->ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); err_gpio: - if (wm8996->pdata.ldo_ena > 0) - gpio_free(wm8996->pdata.ldo_ena); err: return ret; @@ -3070,10 +3064,8 @@ static void wm8996_i2c_remove(struct i2c_client *client) struct wm8996_priv *wm8996 = i2c_get_clientdata(client); wm8996_free_gpio(wm8996); - if (wm8996->pdata.ldo_ena > 0) { - gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); - gpio_free(wm8996->pdata.ldo_ena); - } + if (wm8996->ldo_ena) + gpiod_set_value_cansleep(wm8996->ldo_ena, 0); } static const struct i2c_device_id wm8996_i2c_id[] = { From fc1fbd13a20596564f407a96ac511bf0db808a0e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Dec 2023 15:28:06 +0100 Subject: [PATCH 3381/7721] scsi: mpi3mr: Fix printk() format strings The newly introduced error messages get multiple format strings wrong: size_t must be printed using the %z modifier rather than %l and dma_addr_t must be printed by reference using the special %pad pointer type: drivers/scsi/mpi3mr/mpi3mr_app.c: In function 'mpi3mr_build_nvme_prp': include/linux/kern_levels.h:5:25: error: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' {aka 'unsigned int'} [-Werror=format=] drivers/scsi/mpi3mr/mpi3mr_app.c:949:25: note: in expansion of macro 'dprint_bsg_err' 949 | dprint_bsg_err(mrioc, | ^~~~~~~~~~~~~~ include/linux/kern_levels.h:5:25: error: format '%ld' expects argument of type 'long int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=] drivers/scsi/mpi3mr/mpi3mr_app.c:1112:41: note: in expansion of macro 'dprint_bsg_err' 1112 | dprint_bsg_err(mrioc, | ^~~~~~~~~~~~~~ Fixes: 9536af615dc9 ("scsi: mpi3mr: Support for preallocation of SGL BSG data buffers part-3") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231207142813.935717-1-arnd@kernel.org Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_app.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 4b93b7440da6..0380996b5ad2 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -947,8 +947,8 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, dma_addr = drv_buf_iter->dma_desc[count].dma_addr; if (dma_addr & page_mask) { dprint_bsg_err(mrioc, - "%s:dma_addr 0x%llx is not aligned with page size 0x%x\n", - __func__, dma_addr, dev_pgsz); + "%s:dma_addr %pad is not aligned with page size 0x%x\n", + __func__, &dma_addr, dev_pgsz); return -1; } } @@ -1110,7 +1110,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, if ((++desc_count) >= drv_buf_iter->num_dma_desc) { dprint_bsg_err(mrioc, - "%s: Invalid len %ld while building PRP\n", + "%s: Invalid len %zd while building PRP\n", __func__, length); goto err_out; } From 8b7b0e5fe47de90ba6c350f9abece589fb637f79 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 8 Dec 2023 00:17:03 -0600 Subject: [PATCH 3382/7721] bpf: Load vmlinux btf for any struct_ops map In libbpf, when determining whether we need to load vmlinux btf, we're currently (among other things) checking whether there is any struct_ops program present in the object. This works for most realistic struct_ops maps, as a struct_ops map is of course typically composed of one or more struct_ops programs. However, that technically need not be the case. A struct_ops interface could be defined which allows a map to be specified which one or more non-prog fields, and which provides default behavior if no struct_ops progs is actually provided otherwise. For sched_ext, for example, you technically only need to specify the name of the scheduler in the struct_ops map, with the core scheduler logic providing default behavior if no prog is actually specified. If we were to define and try to load such a struct_ops map, we would crash in libbpf when initializing it as obj->btf_vmlinux will be NULL: Reading symbols from minimal... (gdb) r Starting program: minimal_example [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". Program received signal SIGSEGV, Segmentation fault. 0x000055555558308c in btf__type_cnt (btf=0x0) at btf.c:612 612 return btf->start_id + btf->nr_types; (gdb) bt type_name=0x5555555d99e3 "sched_ext_ops", kind=4) at btf.c:914 kind=4) at btf.c:942 type=0x7fffffffe558, type_id=0x7fffffffe548, ... data_member=0x7fffffffe568) at libbpf.c:948 kern_btf=0x0) at libbpf.c:1017 at libbpf.c:8059 So as to account for such bare-bones struct_ops maps, let's update obj_needs_vmlinux_btf() to also iterate over an obj's maps and check whether any of them are struct_ops maps. Signed-off-by: David Vernet Signed-off-by: Andrii Nakryiko Reviewed-by: Alan Maguire Link: https://lore.kernel.org/bpf/20231208061704.400463-1-void@manifault.com --- tools/lib/bpf/libbpf.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index ea9b8158c20d..ac54ebc0629f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -3054,9 +3054,15 @@ static bool prog_needs_vmlinux_btf(struct bpf_program *prog) return false; } +static bool map_needs_vmlinux_btf(struct bpf_map *map) +{ + return bpf_map__is_struct_ops(map); +} + static bool obj_needs_vmlinux_btf(const struct bpf_object *obj) { struct bpf_program *prog; + struct bpf_map *map; int i; /* CO-RE relocations need kernel BTF, only when btf_custom_path @@ -3081,6 +3087,11 @@ static bool obj_needs_vmlinux_btf(const struct bpf_object *obj) return true; } + bpf_object__for_each_map(map, obj) { + if (map_needs_vmlinux_btf(map)) + return true; + } + return false; } From a1c7da5fb02c0c24e5d8b2d78d449482bce5e92b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 8 Dec 2023 13:43:32 +0100 Subject: [PATCH 3383/7721] arm64: dts: qcom: pm8550: drop PWM address/size cells The address/size cells in PWM node are needed only if individual LEDs are listed. If multi-led is used, then this leads to dtc W=1 warnings: pm8550.dtsi:65.19-73.5: Warning (avoid_unnecessary_addr_size): /soc@0/spmi@c400000/pmic@1/pwm: unnecessary #address-cells/#size-cells without "ranges" or child "reg" property Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231208124332.48636-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pm8550.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8550.dtsi b/arch/arm64/boot/dts/qcom/pm8550.dtsi index db3d5c17a77d..797a18c249a4 100644 --- a/arch/arm64/boot/dts/qcom/pm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8550.dtsi @@ -64,9 +64,6 @@ pm8550_flash: led-controller@ee00 { pm8550_pwm: pwm { compatible = "qcom,pm8550-pwm", "qcom,pm8350c-pwm"; - - #address-cells = <1>; - #size-cells = <0>; #pwm-cells = <2>; status = "disabled"; From 990b6c928b212d930ae8b002dd86043cc4a302ba Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 8 Dec 2023 13:16:45 +0100 Subject: [PATCH 3384/7721] arm64: dts: qcom: sm8650: Add DisplayPort device nodes Declare the displayport controller present on the Qualcomm SM8650 SoC and connected to the USB3/DP Combo PHY. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20231208-topic-sm8650-upstream-dp-v2-1-69dab3d074e4@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 120 ++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index af5e0a75b0ab..425e1e50d945 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -3146,6 +3146,14 @@ dpu_intf2_out: endpoint { remote-endpoint = <&mdss_dsi1_in>; }; }; + + port@2 { + reg = <2>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; }; mdp_opp_table: opp-table { @@ -3347,6 +3355,88 @@ mdss_dsi1_phy: phy@ae97000 { status = "disabled"; }; + + mdss_dp0: displayport-controller@af54000 { + compatible = "qcom,sm8650-dp"; + reg = <0 0xaf54000 0 0x104>, + <0 0xaf54200 0 0xc0>, + <0 0xaf55000 0 0x770>, + <0 0xaf56000 0 0x9c>, + <0 0xaf57000 0 0x9c>; + + interrupts-extended = <&mdss 12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>; + assigned-clock-parents = <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>, + <&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + + operating-points-v2 = <&dp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&usb_dp_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + #sound-dai-cells = <0>; + + status = "disabled"; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs_d1>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp0_out: endpoint { + }; + }; + }; + }; }; dispcc: clock-controller@af00000 { @@ -3361,8 +3451,8 @@ dispcc: clock-controller@af00000 { <&mdss_dsi0_phy 1>, <&mdss_dsi1_phy 0>, <&mdss_dsi1_phy 1>, - <0>, /* dp0 */ - <0>, + <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>, + <&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, <0>, /* dp1 */ <0>, <0>, /* dp2 */ @@ -3419,6 +3509,32 @@ usb_dp_qmpphy: phy@88e8000 { #phy-cells = <1>; status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + }; + }; + }; }; usb_1: usb@a6f8800 { From 2c12eb36f849256f5eb00ffaee9bf99396fd3814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Dec 2023 20:03:08 +0200 Subject: [PATCH 3385/7721] drm/i915: Fix remapped stride with CCS on ADL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ADL+ the hardware automagically calculates the CCS AUX surface stride from the main surface stride, so when remapping we can't really play a lot of tricks with the main surface stride, or else the AUX surface stride would get miscalculated and no longer match the actual data layout in memory. Supposedly we could remap in 256 main surface tile units (AUX page(4096)/cachline(64)*4(4x1 main surface tiles per AUX cacheline)=256 main surface tiles), but the extra complexity is probably not worth the hassle. So let's just make sure our mapping stride is calculated from the full framebuffer stride (instead of the framebuffer width). This way the stride we program into PLANE_STRIDE will be the original framebuffer stride, and thus there will be no change to the AUX stride/layout. Cc: stable@vger.kernel.org Cc: Imre Deak Cc: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231205180308.7505-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_fb.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 4f9d2e57a770..81316b21314d 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1509,8 +1509,20 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p size += remap_info->size; } else { - unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane, - remap_info->width); + unsigned int dst_stride; + + /* + * The hardware automagically calculates the CCS AUX surface + * stride from the main surface stride so can't really remap a + * smaller subset (unless we'd remap in whole AUX page units). + */ + if (intel_fb_needs_pot_stride_remap(fb) && + intel_fb_is_ccs_modifier(fb->base.modifier)) + dst_stride = remap_info->src_stride; + else + dst_stride = remap_info->width; + + dst_stride = plane_view_dst_stride_tiles(fb, color_plane, dst_stride); assign_chk_ovf(i915, remap_info->dst_stride, dst_stride); color_plane_info->mapping_stride = dst_stride * From e81144106e21271c619f0c722a09e27ccb8c043d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:34 +0200 Subject: [PATCH 3386/7721] drm/i915: Fix intel_atomic_setup_scalers() plane_state handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the plane_state variable is declared outside the scaler_users loop in intel_atomic_setup_scalers(), and it's never reset back to NULL inside the loop we may end up calling intel_atomic_setup_scaler() with a non-NULL plane state for the pipe scaling case. That is bad because intel_atomic_setup_scaler() determines whether we are doing plane scaling or pipe scaling based on plane_state!=NULL. The end result is that we may miscalculate the scaler mode for pipe scaling. The hardware becomes somewhat upset if we end up in this situation when scanning out a planar format on a SDR plane. We end up programming the pipe scaler into planar mode as well, and the result is a screenfull of garbage. Fix the situation by making sure we pass the correct plane_state==NULL when calculating the scaler mode for pipe scaling. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/skl_scaler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 1e7c97243fcf..8a934bada624 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -504,7 +504,6 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, { struct drm_plane *plane = NULL; struct intel_plane *intel_plane; - struct intel_plane_state *plane_state = NULL; struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; struct drm_atomic_state *drm_state = crtc_state->uapi.state; @@ -536,6 +535,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, /* walkthrough scaler_users bits and start assigning scalers */ for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { + struct intel_plane_state *plane_state = NULL; int *scaler_id; const char *name; int idx, ret; From e05a67fdd3c9293827d44a0dfa3618429b832d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:35 +0200 Subject: [PATCH 3387/7721] drm/i915: Streamline intel_dsc_pps_read() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_dsc_pps_read() is rather convoluted. Make it legible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vdsc.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 5f2fb702e367..17d6572f9d0a 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -812,13 +812,13 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) } static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, - bool *check_equal) + bool *all_equal) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); i915_reg_t dsc_reg[2]; int i, vdsc_per_pipe, dsc_reg_num; - u32 val = 0; + u32 val; vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); @@ -827,20 +827,13 @@ static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); - if (check_equal) - *check_equal = true; + *all_equal = true; - for (i = 0; i < dsc_reg_num; i++) { - u32 tmp; + val = intel_de_read(i915, dsc_reg[0]); - tmp = intel_de_read(i915, dsc_reg[i]); - - if (i == 0) { - val = tmp; - } else if (check_equal && tmp != val) { - *check_equal = false; - break; - } else if (!check_equal) { + for (i = 1; i < dsc_reg_num; i++) { + if (intel_de_read(i915, dsc_reg[i]) != val) { + *all_equal = false; break; } } From f175de44d0cf5aa688747b96bad0e596a50eaad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:36 +0200 Subject: [PATCH 3388/7721] drm/i915: Drop redundant NULL check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_bios_get_dsc_params() is only called from gen11_dsi_dsc_compute_config() and it always passes a non-NULL crtc_state in. Drop the redundant check. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bios.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 3e7e96acb24a..aa169b0055e9 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3475,8 +3475,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder, if (!devdata->dsc) return false; - if (crtc_state) - fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); + fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); return true; } From ed1566a982213c1a8a39cac26aa4c53d289ed4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:37 +0200 Subject: [PATCH 3389/7721] drm/i915: Drop crtc NULL check from intel_crtc_active() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_crtc_active() is never called with a NULL crtc. Drop the redundant NULL check. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_wm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index 03e8fb6caa83..11ca9572e8b3 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -608,7 +608,7 @@ static bool intel_crtc_active(struct intel_crtc *crtc) * crtc->state->active once we have proper CRTC states wired up * for atomic. */ - return crtc && crtc->active && crtc->base.primary->state->fb && + return crtc->active && crtc->base.primary->state->fb && crtc->config->hw.adjusted_mode.crtc_clock; } From a599d302ae00917038777fad09107576375e2c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:38 +0200 Subject: [PATCH 3390/7721] drm/i915: Drop NULL fb check from intel_fb_uses_dpt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_fb_uses_dpt() should not be called with a NULL fb, so drop the check. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 81316b21314d..44ae6c1e1d46 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -771,7 +771,7 @@ bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) bool intel_fb_uses_dpt(const struct drm_framebuffer *fb) { - return fb && to_i915(fb->dev)->display.params.enable_dpt && + return to_i915(fb->dev)->display.params.enable_dpt && intel_fb_modifier_uses_dpt(to_i915(fb->dev), fb->modifier); } From 7f4f756df7a0716b15176f6fa0552e3480a2b981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:39 +0200 Subject: [PATCH 3391/7721] drm/i915: Drop redunant null check from intel_get_frame_time_us() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_get_frame_time_us() is never called with a NULL crtc_state so drop the redundant check. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 6029bb71276c..0058b07a7cda 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -893,7 +893,7 @@ transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder cpu_trans static u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate) { - if (!cstate || !cstate->hw.active) + if (!cstate->hw.active) return 0; return DIV_ROUND_UP(1000 * 1000, From e81f48512aa42d633015f182d2ecf91299803077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:40 +0200 Subject: [PATCH 3392/7721] drm/i915: s/cstate/crtc_state/ in intel_get_frame_time_us() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use standard variable name 'crtc_state' instead of 'cstate'. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-8-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_psr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 0058b07a7cda..b6e2e70e1290 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -891,13 +891,13 @@ transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder cpu_trans return false; } -static u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate) +static u32 intel_get_frame_time_us(const struct intel_crtc_state *crtc_state) { - if (!cstate->hw.active) + if (!crtc_state->hw.active) return 0; return DIV_ROUND_UP(1000 * 1000, - drm_mode_vrefresh(&cstate->hw.adjusted_mode)); + drm_mode_vrefresh(&crtc_state->hw.adjusted_mode)); } static void psr2_program_idle_frames(struct intel_dp *intel_dp, From c6117b33a173717714a8dbbf9d14ca85db79725e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Dec 2023 21:34:41 +0200 Subject: [PATCH 3393/7721] drm/i915/tv: Drop redundant null checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither 'tv_mode' or 'color_conversion' can be NULL, so drop the pointless checks. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231207193441.20206-9-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_tv.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 2ee4f0d95851..d4386cb3569e 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1417,9 +1417,6 @@ set_tv_mode_timings(struct drm_i915_private *dev_priv, static void set_color_conversion(struct drm_i915_private *dev_priv, const struct color_conversion *color_conversion) { - if (!color_conversion) - return; - intel_de_write(dev_priv, TV_CSC_Y, (color_conversion->ry << 16) | color_conversion->gy); intel_de_write(dev_priv, TV_CSC_Y2, @@ -1454,9 +1451,6 @@ static void intel_tv_pre_enable(struct intel_atomic_state *state, int xpos, ypos; unsigned int xsize, ysize; - if (!tv_mode) - return; /* can't happen (mode_prepare prevents this) */ - tv_ctl = intel_de_read(dev_priv, TV_CTL); tv_ctl &= TV_CTL_SAVE; From d9f28735af8781d9c8c6c406c2a102090644133d Mon Sep 17 00:00:00 2001 From: David Laight Date: Wed, 6 Dec 2023 13:44:20 +0000 Subject: [PATCH 3394/7721] Use READ/WRITE_ONCE() for IP local_port_range. Commit 227b60f5102cd added a seqlock to ensure that the low and high port numbers were always updated together. This is overkill because the two 16bit port numbers can be held in a u32 and read/written in a single instruction. More recently 91d0b78c5177f added support for finer per-socket limits. The user-supplied value is 'high << 16 | low' but they are held separately and the socket options protected by the socket lock. Use a u32 containing 'high << 16 | low' for both the 'net' and 'sk' fields and use READ_ONCE()/WRITE_ONCE() to ensure both values are always updated together. Change (the now trival) inet_get_local_port_range() to a static inline to optimise the calling code. (In particular avoiding returning integers by reference.) Signed-off-by: David Laight Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Acked-by: Mat Martineau Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/4e505d4198e946a8be03fb1b4c3072b0@AcuMS.aculab.com Signed-off-by: Jakub Kicinski --- include/net/inet_sock.h | 5 +---- include/net/ip.h | 8 +++++++- include/net/netns/ipv4.h | 3 +-- net/ipv4/af_inet.c | 4 +--- net/ipv4/inet_connection_sock.c | 29 ++++++++++------------------- net/ipv4/ip_sockglue.c | 33 ++++++++++++++++----------------- net/ipv4/sysctl_net_ipv4.c | 18 +++++++----------- 7 files changed, 43 insertions(+), 57 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 74db6d97cae1..aa86453f6b9b 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -234,10 +234,7 @@ struct inet_sock { int uc_index; int mc_index; __be32 mc_addr; - struct { - __u16 lo; - __u16 hi; - } local_port_range; + u32 local_port_range; /* high << 16 | low */ struct ip_mc_socklist __rcu *mc_list; struct inet_cork_full cork; diff --git a/include/net/ip.h b/include/net/ip.h index 1fc4c8d69e33..b31be912489a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -349,7 +349,13 @@ static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_o } \ } -void inet_get_local_port_range(const struct net *net, int *low, int *high); +static inline void inet_get_local_port_range(const struct net *net, int *low, int *high) +{ + u32 range = READ_ONCE(net->ipv4.ip_local_ports.range); + + *low = range & 0xffff; + *high = range >> 16; +} void inet_sk_get_local_port_range(const struct sock *sk, int *low, int *high); #ifdef CONFIG_SYSCTL diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index ea882964c71e..c356c458b340 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -19,8 +19,7 @@ struct hlist_head; struct fib_table; struct sock; struct local_ports { - seqlock_t lock; - int range[2]; + u32 range; /* high << 16 | low */ bool warned; }; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index fb81de10d332..fbeacf04dbf3 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1847,9 +1847,7 @@ static __net_init int inet_init_net(struct net *net) /* * Set defaults for local port range */ - seqlock_init(&net->ipv4.ip_local_ports.lock); - net->ipv4.ip_local_ports.range[0] = 32768; - net->ipv4.ip_local_ports.range[1] = 60999; + net->ipv4.ip_local_ports.range = 60999u << 16 | 32768u; seqlock_init(&net->ipv4.ping_group_range.lock); /* diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 394a498c2823..70be0f6fe879 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -117,34 +117,25 @@ bool inet_rcv_saddr_any(const struct sock *sk) return !sk->sk_rcv_saddr; } -void inet_get_local_port_range(const struct net *net, int *low, int *high) -{ - unsigned int seq; - - do { - seq = read_seqbegin(&net->ipv4.ip_local_ports.lock); - - *low = net->ipv4.ip_local_ports.range[0]; - *high = net->ipv4.ip_local_ports.range[1]; - } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq)); -} -EXPORT_SYMBOL(inet_get_local_port_range); - void inet_sk_get_local_port_range(const struct sock *sk, int *low, int *high) { const struct inet_sock *inet = inet_sk(sk); const struct net *net = sock_net(sk); int lo, hi, sk_lo, sk_hi; + u32 sk_range; inet_get_local_port_range(net, &lo, &hi); - sk_lo = inet->local_port_range.lo; - sk_hi = inet->local_port_range.hi; + sk_range = READ_ONCE(inet->local_port_range); + if (unlikely(sk_range)) { + sk_lo = sk_range & 0xffff; + sk_hi = sk_range >> 16; - if (unlikely(lo <= sk_lo && sk_lo <= hi)) - lo = sk_lo; - if (unlikely(lo <= sk_hi && sk_hi <= hi)) - hi = sk_hi; + if (lo <= sk_lo && sk_lo <= hi) + lo = sk_lo; + if (lo <= sk_hi && sk_hi <= hi) + hi = sk_hi; + } *low = lo; *high = hi; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2efc53526a38..d7d13940774e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1055,6 +1055,19 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, case IP_TOS: /* This sets both TOS and Precedence */ ip_sock_set_tos(sk, val); return 0; + case IP_LOCAL_PORT_RANGE: + { + u16 lo = val; + u16 hi = val >> 16; + + if (optlen != sizeof(u32)) + return -EINVAL; + if (lo != 0 && hi != 0 && lo > hi) + return -EINVAL; + + WRITE_ONCE(inet->local_port_range, val); + return 0; + } } err = 0; @@ -1332,20 +1345,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, err = xfrm_user_policy(sk, optname, optval, optlen); break; - case IP_LOCAL_PORT_RANGE: - { - const __u16 lo = val; - const __u16 hi = val >> 16; - - if (optlen != sizeof(__u32)) - goto e_inval; - if (lo != 0 && hi != 0 && lo > hi) - goto e_inval; - - inet->local_port_range.lo = lo; - inet->local_port_range.hi = hi; - break; - } default: err = -ENOPROTOOPT; break; @@ -1692,6 +1691,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; return 0; } + case IP_LOCAL_PORT_RANGE: + val = READ_ONCE(inet->local_port_range); + goto copyval; } if (needs_rtnl) @@ -1721,9 +1723,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, else err = ip_get_mcast_msfilter(sk, optval, optlen, len); goto out; - case IP_LOCAL_PORT_RANGE: - val = inet->local_port_range.hi << 16 | inet->local_port_range.lo; - break; case IP_PROTOCOL: val = inet_sk(sk)->inet_num; break; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index f63a545a7374..7e4f16a7dcc1 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -50,26 +50,22 @@ static int tcp_plb_max_cong_thresh = 256; static int sysctl_tcp_low_latency __read_mostly; /* Update system visible IP port range */ -static void set_local_port_range(struct net *net, int range[2]) +static void set_local_port_range(struct net *net, unsigned int low, unsigned int high) { - bool same_parity = !((range[0] ^ range[1]) & 1); + bool same_parity = !((low ^ high) & 1); - write_seqlock_bh(&net->ipv4.ip_local_ports.lock); if (same_parity && !net->ipv4.ip_local_ports.warned) { net->ipv4.ip_local_ports.warned = true; pr_err_ratelimited("ip_local_port_range: prefer different parity for start/end values.\n"); } - net->ipv4.ip_local_ports.range[0] = range[0]; - net->ipv4.ip_local_ports.range[1] = range[1]; - write_sequnlock_bh(&net->ipv4.ip_local_ports.lock); + WRITE_ONCE(net->ipv4.ip_local_ports.range, high << 16 | low); } /* Validate changes from /proc interface. */ static int ipv4_local_port_range(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { - struct net *net = - container_of(table->data, struct net, ipv4.ip_local_ports.range); + struct net *net = table->data; int ret; int range[2]; struct ctl_table tmp = { @@ -93,7 +89,7 @@ static int ipv4_local_port_range(struct ctl_table *table, int write, (range[0] < READ_ONCE(net->ipv4.sysctl_ip_prot_sock))) ret = -EINVAL; else - set_local_port_range(net, range); + set_local_port_range(net, range[0], range[1]); } return ret; @@ -733,8 +729,8 @@ static struct ctl_table ipv4_net_table[] = { }, { .procname = "ip_local_port_range", - .maxlen = sizeof(init_net.ipv4.ip_local_ports.range), - .data = &init_net.ipv4.ip_local_ports.range, + .maxlen = 0, + .data = &init_net, .mode = 0644, .proc_handler = ipv4_local_port_range, }, From 2a7f1848d9d65a4deb366726ff8f33c9c64ac43b Mon Sep 17 00:00:00 2001 From: Mihai Sain Date: Mon, 4 Dec 2023 09:25:37 +0200 Subject: [PATCH 3395/7721] ARM: dts: microchip: sama5d27_wlsom1_ek: Remove mmc-ddr-3_3v property from sdmmc0 node On board the sdmmc0 interface is wired to a SD Card socket. According with mmc-controller bindings, the mmc-ddr-3_3v property is used for eMMC devices to enable high-speed DDR mode (3.3V I/O). Remove the mmc-ddr-3_3v property from sdmmc0 node. Signed-off-by: Mihai Sain Link: https://lore.kernel.org/r/20231204072537.2991-1-mihai.sain@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts index e055b9e2fe34..15239834d886 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts @@ -197,7 +197,6 @@ qspi1_flash: flash@0 { &sdmmc0 { bus-width = <4>; - mmc-ddr-3_3v; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; status = "okay"; From 877fd09a120d0acee073fbada79fad2ab35396c2 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Thu, 7 Dec 2023 14:10:23 -0800 Subject: [PATCH 3396/7721] drm/i915/mtl: Use port clock compatible numbers for C20 phy In C20 pll_state link_bit_rate and clock fields are bit redundant. Since many of the helpers assume the clock values, which are different from link_bit_rate for dp2.0, convert the helpers to use the numbers that are compatible with link_bit_rate. Currently link_bit_rate is compatible with crtc_state->port_clock. The function intel_c20pll_calc_port_clock returns the number which is compatible with crtc_state->port_clock. In order to avoid extra conversions b/ween clock and link_bit_rate, remove "clock" field from the C20 pll_state and then rename "link_bit_rate" as "clock". While at it rely on crtc_state->port_clock during C20 Pll programming. Cc: Clint Taylor Cc: Mika Kahola Signed-off-by: Radhakrishna Sripada Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231207221025.2032207-2-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 5fbec5784b83..7d412be996ea 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2117,7 +2117,7 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, static bool intel_c20_use_mplla(u32 clock) { /* 10G and 20G rates use MPLLA */ - if (clock == 312500 || clock == 625000) + if (clock == 1000000 || clock == 2000000) return true; return false; @@ -2192,7 +2192,7 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n", hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]); - if (intel_c20_use_mplla(hw_state->clock)) { + if (intel_c20_use_mplla(hw_state->link_bit_rate)) { for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); } else { @@ -2220,11 +2220,11 @@ static u8 intel_c20_get_dp_rate(u32 clock) return 6; case 432000: /* 4.32 Gbps eDP */ return 7; - case 312500: /* 10 Gbps DP2.0 */ + case 1000000: /* 10 Gbps DP2.0 */ return 8; - case 421875: /* 13.5 Gbps DP2.0 */ + case 1350000: /* 13.5 Gbps DP2.0 */ return 9; - case 625000: /* 20 Gbps DP2.0*/ + case 2000000: /* 20 Gbps DP2.0 */ return 10; case 648000: /* 6.48 Gbps eDP*/ return 11; @@ -2242,13 +2242,13 @@ static u8 intel_c20_get_hdmi_rate(u32 clock) return 0; switch (clock) { - case 166670: /* 3 Gbps */ - case 333330: /* 6 Gbps */ - case 666670: /* 12 Gbps */ + case 300000: /* 3 Gbps */ + case 600000: /* 6 Gbps */ + case 1200000: /* 12 Gbps */ return 1; - case 444440: /* 8 Gbps */ + case 800000: /* 8 Gbps */ return 2; - case 555560: /* 10 Gbps */ + case 1000000: /* 10 Gbps */ return 3; default: MISSING_CASE(clock); @@ -2259,7 +2259,7 @@ static u8 intel_c20_get_hdmi_rate(u32 clock) static bool is_dp2(u32 clock) { /* DP2.0 clock rates */ - if (clock == 312500 || clock == 421875 || clock == 625000) + if (clock == 1000000 || clock == 1350000 || clock == 2000000) return true; return false; @@ -2268,11 +2268,11 @@ static bool is_dp2(u32 clock) static bool is_hdmi_frl(u32 clock) { switch (clock) { - case 166670: /* 3 Gbps */ - case 333330: /* 6 Gbps */ - case 444440: /* 8 Gbps */ - case 555560: /* 10 Gbps */ - case 666670: /* 12 Gbps */ + case 300000: /* 3 Gbps */ + case 600000: /* 6 Gbps */ + case 800000: /* 8 Gbps */ + case 1000000: /* 10 Gbps */ + case 1200000: /* 12 Gbps */ return true; default: return false; @@ -2305,6 +2305,7 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, const struct intel_c20pll_state *pll_state = &crtc_state->cx0pll_state.c20; bool dp = false; int lane = crtc_state->lane_count > 2 ? INTEL_CX0_BOTH_LANES : INTEL_CX0_LANE0; + u32 clock = crtc_state->port_clock; bool cntx; int i; @@ -2343,7 +2344,7 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, } /* 3.3 mpllb or mplla configuration */ - if (intel_c20_use_mplla(pll_state->clock)) { + if (intel_c20_use_mplla(clock)) { for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, @@ -2370,23 +2371,23 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, /* 4. Program custom width to match the link protocol */ intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_WIDTH, PHY_C20_CUSTOM_WIDTH_MASK, - PHY_C20_CUSTOM_WIDTH(intel_get_c20_custom_width(pll_state->clock, dp)), + PHY_C20_CUSTOM_WIDTH(intel_get_c20_custom_width(clock, dp)), MB_WRITE_COMMITTED); /* 5. For DP or 6. For HDMI */ if (dp) { intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_SERDES_RATE, BIT(6) | PHY_C20_CUSTOM_SERDES_MASK, - BIT(6) | PHY_C20_CUSTOM_SERDES(intel_c20_get_dp_rate(pll_state->clock)), + BIT(6) | PHY_C20_CUSTOM_SERDES(intel_c20_get_dp_rate(clock)), MB_WRITE_COMMITTED); } else { intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_SERDES_RATE, BIT(7) | PHY_C20_CUSTOM_SERDES_MASK, - is_hdmi_frl(pll_state->clock) ? BIT(7) : 0, + is_hdmi_frl(clock) ? BIT(7) : 0, MB_WRITE_COMMITTED); intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_HDMI_RATE, - intel_c20_get_hdmi_rate(pll_state->clock), + intel_c20_get_hdmi_rate(clock), MB_WRITE_COMMITTED); } From 1103672fd6b8486c4cc1ab69623e9a080a00e022 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Thu, 7 Dec 2023 14:10:24 -0800 Subject: [PATCH 3397/7721] drm/i915/mtl: Remove misleading "clock" field from C20 pll_state The field link_bit_rate serves as the actual clock value for the C20 pll_state structure. Remove the misleading clock field. The subsequent patch would rename the link_bit_rate as the clock field. Cc: Clint Taylor Cc: Mika Kahola Signed-off-by: Radhakrishna Sripada Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231207221025.2032207-3-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 18 ------------------ .../gpu/drm/i915/display/intel_display_types.h | 3 +-- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 7d412be996ea..d518b55d5150 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -746,7 +746,6 @@ static const struct intel_c10pll_state * const mtl_c10_edp_tables[] = { /* C20 basic DP 1.4 tables */ static const struct intel_c20pll_state mtl_c20_dp_rbr = { .link_bit_rate = 162000, - .clock = 162000, .tx = { 0xbe88, /* tx cfg0 */ 0x5800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -772,7 +771,6 @@ static const struct intel_c20pll_state mtl_c20_dp_rbr = { static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { .link_bit_rate = 270000, - .clock = 270000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -798,7 +796,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { .link_bit_rate = 540000, - .clock = 540000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -824,7 +821,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { .link_bit_rate = 810000, - .clock = 810000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -851,7 +847,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { /* C20 basic DP 2.0 tables */ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { .link_bit_rate = 1000000, /* 10 Gbps */ - .clock = 312500, .tx = { 0xbe21, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -876,7 +871,6 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { .link_bit_rate = 1350000, /* 13.5 Gbps */ - .clock = 421875, .tx = { 0xbea0, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -902,7 +896,6 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { .link_bit_rate = 2000000, /* 20 Gbps */ - .clock = 625000, .tx = { 0xbe20, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1522,7 +1515,6 @@ static const struct intel_c10pll_state * const mtl_c10_hdmi_tables[] = { static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { .link_bit_rate = 25175, - .clock = 25175, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1548,7 +1540,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { .link_bit_rate = 27000, - .clock = 27000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1574,7 +1565,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { .link_bit_rate = 74250, - .clock = 74250, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1600,7 +1590,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { .link_bit_rate = 148500, - .clock = 148500, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1626,7 +1615,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { static const struct intel_c20pll_state mtl_c20_hdmi_594 = { .link_bit_rate = 594000, - .clock = 594000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1652,7 +1640,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = { static const struct intel_c20pll_state mtl_c20_hdmi_300 = { .link_bit_rate = 3000000, - .clock = 166670, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1678,7 +1665,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = { static const struct intel_c20pll_state mtl_c20_hdmi_600 = { .link_bit_rate = 6000000, - .clock = 333330, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1704,7 +1690,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = { static const struct intel_c20pll_state mtl_c20_hdmi_800 = { .link_bit_rate = 8000000, - .clock = 444440, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1730,7 +1715,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = { static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { .link_bit_rate = 10000000, - .clock = 555560, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1756,7 +1740,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { .link_bit_rate = 12000000, - .clock = 666670, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -2006,7 +1989,6 @@ static int intel_c20_compute_hdmi_tmds_pll(u64 pixel_clock, struct intel_c20pll_ mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_0; pll_state->link_bit_rate = pixel_clock; - pll_state->clock = pixel_clock; pll_state->tx[0] = 0xbe88; pll_state->tx[1] = 0x9800; pll_state->tx[2] = 0x0000; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index b3e942f2eeb0..6b348d329957 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1022,8 +1022,7 @@ struct intel_c10pll_state { }; struct intel_c20pll_state { - u32 link_bit_rate; - u32 clock; /* in kHz */ + u32 link_bit_rate; /* in kHz */ u16 tx[3]; u16 cmn[4]; union { From 872ee9cc0219334486e19da20e56665e612fdcb7 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Thu, 7 Dec 2023 14:10:25 -0800 Subject: [PATCH 3398/7721] drm/i915/mtl: Rename the link_bit_rate to clock in C20 pll_state With the cleanup of the misleading clock value to avoid extra calculations to convert between link_bit_rate and clock, use one standard "clock" field for the c20 pll which works with crtc_state->port_clock field. Cc: Clint Taylor Cc: Mika Kahola Signed-off-by: Radhakrishna Sripada Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20231207221025.2032207-4-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 42 +++++++++---------- .../drm/i915/display/intel_display_types.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index d518b55d5150..4e6ea71ff629 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -745,7 +745,7 @@ static const struct intel_c10pll_state * const mtl_c10_edp_tables[] = { /* C20 basic DP 1.4 tables */ static const struct intel_c20pll_state mtl_c20_dp_rbr = { - .link_bit_rate = 162000, + .clock = 162000, .tx = { 0xbe88, /* tx cfg0 */ 0x5800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -770,7 +770,7 @@ static const struct intel_c20pll_state mtl_c20_dp_rbr = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { - .link_bit_rate = 270000, + .clock = 270000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -795,7 +795,7 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { - .link_bit_rate = 540000, + .clock = 540000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -820,7 +820,7 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { - .link_bit_rate = 810000, + .clock = 810000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -846,7 +846,7 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { /* C20 basic DP 2.0 tables */ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { - .link_bit_rate = 1000000, /* 10 Gbps */ + .clock = 1000000, /* 10 Gbps */ .tx = { 0xbe21, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -870,7 +870,7 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { - .link_bit_rate = 1350000, /* 13.5 Gbps */ + .clock = 1350000, /* 13.5 Gbps */ .tx = { 0xbea0, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -895,7 +895,7 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { - .link_bit_rate = 2000000, /* 20 Gbps */ + .clock = 2000000, /* 20 Gbps */ .tx = { 0xbe20, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1514,7 +1514,7 @@ static const struct intel_c10pll_state * const mtl_c10_hdmi_tables[] = { }; static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { - .link_bit_rate = 25175, + .clock = 25175, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1539,7 +1539,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { - .link_bit_rate = 27000, + .clock = 27000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1564,7 +1564,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { - .link_bit_rate = 74250, + .clock = 74250, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1589,7 +1589,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { - .link_bit_rate = 148500, + .clock = 148500, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1614,7 +1614,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_594 = { - .link_bit_rate = 594000, + .clock = 594000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1639,7 +1639,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_300 = { - .link_bit_rate = 3000000, + .clock = 3000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1664,7 +1664,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_600 = { - .link_bit_rate = 6000000, + .clock = 6000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1689,7 +1689,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_800 = { - .link_bit_rate = 8000000, + .clock = 8000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1714,7 +1714,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { - .link_bit_rate = 10000000, + .clock = 10000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1739,7 +1739,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { - .link_bit_rate = 12000000, + .clock = 12000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1988,7 +1988,7 @@ static int intel_c20_compute_hdmi_tmds_pll(u64 pixel_clock, struct intel_c20pll_ else mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_0; - pll_state->link_bit_rate = pixel_clock; + pll_state->clock = pixel_clock; pll_state->tx[0] = 0xbe88; pll_state->tx[1] = 0x9800; pll_state->tx[2] = 0x0000; @@ -2024,7 +2024,7 @@ static int intel_c20_phy_check_hdmi_link_rate(int clock) int i; for (i = 0; tables[i]; i++) { - if (clock == tables[i]->link_bit_rate) + if (clock == tables[i]->clock) return MODE_OK; } @@ -2076,7 +2076,7 @@ static int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state, return -EINVAL; for (i = 0; tables[i]; i++) { - if (crtc_state->port_clock == tables[i]->link_bit_rate) { + if (crtc_state->port_clock == tables[i]->clock) { crtc_state->cx0pll_state.c20 = *tables[i]; return 0; } @@ -2174,7 +2174,7 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n", hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]); - if (intel_c20_use_mplla(hw_state->link_bit_rate)) { + if (intel_c20_use_mplla(hw_state->clock)) { for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); } else { diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 6b348d329957..2616bb6267a1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1022,7 +1022,7 @@ struct intel_c10pll_state { }; struct intel_c20pll_state { - u32 link_bit_rate; /* in kHz */ + u32 clock; /* in kHz */ u16 tx[3]; u16 cmn[4]; union { From cf02bea7c1714466dca53124797612c9e9d74994 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 6 Dec 2023 17:01:23 +0100 Subject: [PATCH 3399/7721] net: dsa: microchip: use DSA_TAG_PROTO without _VALUE define Correct the use of define DSA_TAG_PROTO_LAN937X_VALUE to DSA_TAG_PROTO_LAN937X to improve readability. Signed-off-by: Sean Nyekjaer Reviewed-by: Andrew Lunn Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20231206160124.1935451-1-sean@geanix.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index c2cc9083e726..245dfb7a7a31 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2712,7 +2712,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, proto = DSA_TAG_PROTO_KSZ9477; if (is_lan937x(dev)) - proto = DSA_TAG_PROTO_LAN937X_VALUE; + proto = DSA_TAG_PROTO_LAN937X; return proto; } From 172db56d90d29e47e7d0d64885d5dbd92c87ec42 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 6 Dec 2023 12:59:07 -0800 Subject: [PATCH 3400/7721] netlink: Return unsigned value for nla_len() The return value from nla_len() is never expected to be negative, and can never be more than struct nlattr::nla_len (a u16). Adjust the prototype on the function. This will let GCC's value range optimization passes know that the return can never be negative, and can never be larger than u16. As recently discussed[1], this silences the following warning in GCC 12+: net/wireless/nl80211.c: In function 'nl80211_set_cqm_rssi.isra': net/wireless/nl80211.c:12892:17: warning: 'memcpy' specified bound 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=] 12892 | memcpy(cqm_config->rssi_thresholds, thresholds, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12893 | flex_array_size(cqm_config, rssi_thresholds, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12894 | n_thresholds)); | ~~~~~~~~~~~~~~ A future change would be to clamp the subtraction to make sure it never wraps around if nla_len is somehow less than NLA_HDRLEN, which would have the additional benefit of being defensive in the face of nlattr corruption or logic errors. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311090752.hWcJWAHL-lkp@intel.com/ [1] Cc: Johannes Berg Cc: Jeff Johnson Cc: Michael Walle Cc: Max Schulze Link: https://lore.kernel.org/r/20231202202539.it.704-kees@kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20231206205904.make.018-kees@kernel.org Signed-off-by: Jakub Kicinski --- include/net/netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 167b91348e57..28039e57070a 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -1214,7 +1214,7 @@ static inline void *nla_data(const struct nlattr *nla) * nla_len - length of payload * @nla: netlink attribute */ -static inline int nla_len(const struct nlattr *nla) +static inline u16 nla_len(const struct nlattr *nla) { return nla->nla_len - NLA_HDRLEN; } From 84228d5e29dbc7a6be51e221000e1d122125826c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 6 Dec 2023 23:15:54 +0100 Subject: [PATCH 3401/7721] ARM: dts: samsung: exynos4210-i9100: Unconditionally enable LDO12 The kernel hangs for a good 12 seconds without any info being printed to dmesg, very early in the boot process, if this regulator is not enabled. Force-enable it to work around this issue, until we know more about the underlying problem. Signed-off-by: Paul Cercueil Fixes: 8620cc2f99b7 ("ARM: dts: exynos: Add devicetree file for the Galaxy S2") Cc: stable@vger.kernel.org # v5.8+ Link: https://lore.kernel.org/r/20231206221556.15348-2-paul@crapouillou.net Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/samsung/exynos4210-i9100.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts index a9ec1f6c1dea..a076a1dfe41f 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts @@ -527,6 +527,14 @@ vtcam_reg: LDO12 { regulator-name = "VT_CAM_1.8V"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + + /* + * Force-enable this regulator; otherwise the + * kernel hangs very early in the boot process + * for about 12 seconds, without apparent + * reason. + */ + regulator-always-on; }; vcclcd_reg: LDO13 { From 6e73b11062b2e3e873666ba35577437502cf1dd2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 6 Dec 2023 23:15:55 +0100 Subject: [PATCH 3402/7721] ARM: dts: samsung: exynos4210-i9100: Add node for touch keys Add a Device Tree node to support the LED-backed "menu" and "back" keys. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20231206221556.15348-3-paul@crapouillou.net Signed-off-by: Krzysztof Kozlowski --- .../arm/boot/dts/samsung/exynos4210-i9100.dts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts index a076a1dfe41f..f03b03dbe9f2 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts @@ -184,6 +184,28 @@ s5k5bafx_ep: endpoint { }; }; + i2c-gpio-2 { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + sda-gpios = <&gpk1 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpk1 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; + + touchscreen@20 { + compatible = "cypress,aries-touchkey"; + reg = <0x20>; + + interrupt-parent = <&gpl0>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&vtouchled_reg>; + vcc-supply = <&vtouch_reg>; + linux,keycodes = , ; + }; + }; + spi-3 { compatible = "spi-gpio"; #address-cells = <1>; @@ -513,7 +535,6 @@ vtouch_reg: LDO11 { regulator-name = "TOUCH_2.8V"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; - regulator-always-on; }; vpll_reg: LDO10 { From 50c7cdc9a4d2d21373c1ab52c131109ab30c53f5 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 6 Dec 2023 23:15:56 +0100 Subject: [PATCH 3403/7721] ARM: dts: samsung: exynos4210-i9100: Add accelerometer node Add a Device Tree node for the ST Microelectronics "K3D" accelerometer chip found in the Galaxy S2. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20231206221556.15348-4-paul@crapouillou.net [krzysztof: fix alphabetical placement of i2c_1] Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/samsung/exynos4210-i9100.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts index f03b03dbe9f2..0d8495792a70 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts @@ -402,6 +402,23 @@ &hsotg { vusb_a-supply = <&vusbdac_reg>; }; +&i2c_1 { + status = "okay"; + + samsung,i2c-sda-delay = <100>; + samsung,i2c-slave-addr = <0x10>; + samsung,i2c-max-bus-freq = <100000>; + + lis3dh: accelerometer@19 { + compatible = "st,lis3dh-accel"; + reg = <0x19>; + + mount-matrix = "0", "-1", "0", + "1", "0", "0", + "0", "0", "1"; + }; +}; + &i2c_3 { status = "okay"; From a6a010f5def544af3efcfe21683905a712b60536 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 4 Dec 2023 18:38:01 -0800 Subject: [PATCH 3404/7721] f2fs: Restrict max filesize for 16K f2fs Blocks are tracked by u32, so the max permitted filesize is (U32_MAX + 1) * BLOCK_SIZE. Additionally, in order to support crypto data unit sizes of 4K with a 16K block with IV_INO_LBLK_{32,64}, we must further restrict max filesize to (U32_MAX + 1) * 4096. This does not affect 4K blocksize f2fs as the natural limit for files are well below that. Fixes: d7e9a9037de2 ("f2fs: Support Block Size == Page Size") Signed-off-by: Daniel Rosenberg Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 9a874b4d1501..206d03c82d96 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3359,6 +3359,14 @@ loff_t max_file_blocks(struct inode *inode) leaf_count *= NIDS_PER_BLOCK; result += leaf_count; + /* + * For compatibility with FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{64,32} with + * a 4K crypto data unit, we must restrict the max filesize to what can + * fit within U32_MAX + 1 data units. + */ + + result = min(result, (((loff_t)U32_MAX + 1) * 4096) >> F2FS_BLKSIZE_BITS); + return result; } From d49270a04623ce3c0afddbf3e984cb245aa48e9c Mon Sep 17 00:00:00 2001 From: Weichen Chen Date: Fri, 24 Feb 2023 10:36:32 +0800 Subject: [PATCH 3405/7721] pstore/ram: Fix crash when setting number of cpus to an odd number When the number of cpu cores is adjusted to 7 or other odd numbers, the zone size will become an odd number. The address of the zone will become: addr of zone0 = BASE addr of zone1 = BASE + zone_size addr of zone2 = BASE + zone_size*2 ... The address of zone1/3/5/7 will be mapped to non-alignment va. Eventually crashes will occur when accessing these va. So, use ALIGN_DOWN() to make sure the zone size is even to avoid this bug. Signed-off-by: Weichen Chen Reviewed-by: Matthias Brugger Tested-by: "Guilherme G. Piccoli" Link: https://lore.kernel.org/r/20230224023632.6840-1-weichen.chen@mediatek.com Signed-off-by: Kees Cook --- fs/pstore/ram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index d36702c7ab3c..88b34fdbf759 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -529,6 +529,7 @@ static int ramoops_init_przs(const char *name, } zone_sz = mem_sz / *cnt; + zone_sz = ALIGN_DOWN(zone_sz, 2); if (!zone_sz) { dev_err(dev, "%s zone size == 0\n", name); goto fail; From 86222a8fc16ec517de8da2604d904c9df3a08e5d Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sun, 5 Nov 2023 23:29:36 +0300 Subject: [PATCH 3406/7721] pstore: ram_core: fix possible overflow in persistent_ram_init_ecc() In persistent_ram_init_ecc(), on 64-bit arches DIV_ROUND_UP() will return 64-bit value since persistent_ram_zone::buffer_size has type size_t which is derived from the 64-bit *unsigned long*, while the ecc_blocks variable this value gets assigned to has (always 32-bit) *int* type. Even if that value fits into *int* type, an overflow is still possible when calculating the size_t typed ecc_total variable further below since there's no cast to any 64-bit type before multiplication. Declaring the ecc_blocks variable as *size_t* should fix this mess... Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Fixes: 9cc05ad97c57 ("staging: android: persistent_ram: refactor ecc support") Signed-off-by: Sergey Shtylyov Link: https://lore.kernel.org/r/20231105202936.25694-1-s.shtylyov@omp.ru Signed-off-by: Kees Cook --- fs/pstore/ram_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 650e437b55e6..f1848cdd6d34 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -190,7 +190,7 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, { int numerr; struct persistent_ram_buffer *buffer = prz->buffer; - int ecc_blocks; + size_t ecc_blocks; size_t ecc_total; if (!ecc_info || !ecc_info->ecc_size) From 6ba6ee8a59a8ac673d9a9415bdf1d0a27990dc45 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 5 Dec 2023 10:26:14 -0800 Subject: [PATCH 3407/7721] pstore: inode: Convert kfree() usage to __free(kfree) Mostly as an example to myself, replace a simple allocation pattern with the automatic kfree cleanup features now exposed by cleanup.h. Cc: Guilherme G. Piccoli Cc: Tony Luck Cc: Link: https://lore.kernel.org/r/20231205182622.1329923-1-keescook@chromium.org Signed-off-by: Kees Cook --- fs/pstore/inode.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index d41c20d1b5e8..20f3452c8196 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "internal.h" @@ -64,7 +65,7 @@ static void free_pstore_private(struct pstore_private *private) static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) { struct pstore_private *ps = s->private; - struct pstore_ftrace_seq_data *data; + struct pstore_ftrace_seq_data *data __free(kfree) = NULL; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) @@ -72,13 +73,10 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) data->off = ps->total_size % REC_SIZE; data->off += *pos * REC_SIZE; - if (data->off + REC_SIZE > ps->total_size) { - kfree(data); + if (data->off + REC_SIZE > ps->total_size) return NULL; - } - - return data; + return_ptr(data); } static void pstore_ftrace_seq_stop(struct seq_file *s, void *v) From e2eeddefb046dbc771a6fa426f7f98fb25adfe68 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 5 Dec 2023 10:26:15 -0800 Subject: [PATCH 3408/7721] pstore: inode: Convert mutex usage to guard(mutex) Replace open-coded mutex handling with cleanup.h guard(mutex) and scoped_guard(mutex, ...). Cc: Guilherme G. Piccoli Cc: Tony Luck Cc: Link: https://lore.kernel.org/r/20231205182622.1329923-2-keescook@chromium.org Signed-off-by: Kees Cook --- fs/pstore/inode.c | 74 +++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 20f3452c8196..0d89e0014b6f 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -180,25 +180,21 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) { struct pstore_private *p = d_inode(dentry)->i_private; struct pstore_record *record = p->record; - int rc = 0; if (!record->psi->erase) return -EPERM; /* Make sure we can't race while removing this file. */ - mutex_lock(&records_list_lock); - if (!list_empty(&p->list)) - list_del_init(&p->list); - else - rc = -ENOENT; - p->dentry = NULL; - mutex_unlock(&records_list_lock); - if (rc) - return rc; + scoped_guard(mutex, &records_list_lock) { + if (!list_empty(&p->list)) + list_del_init(&p->list); + else + return -ENOENT; + p->dentry = NULL; + } - mutex_lock(&record->psi->read_mutex); - record->psi->erase(record); - mutex_unlock(&record->psi->read_mutex); + scoped_guard(mutex, &record->psi->read_mutex) + record->psi->erase(record); return simple_unlink(dir, dentry); } @@ -290,19 +286,16 @@ static struct dentry *psinfo_lock_root(void) { struct dentry *root; - mutex_lock(&pstore_sb_lock); + guard(mutex)(&pstore_sb_lock); /* * Having no backend is fine -- no records appear. * Not being mounted is fine -- nothing to do. */ - if (!psinfo || !pstore_sb) { - mutex_unlock(&pstore_sb_lock); + if (!psinfo || !pstore_sb) return NULL; - } root = pstore_sb->s_root; inode_lock(d_inode(root)); - mutex_unlock(&pstore_sb_lock); return root; } @@ -317,19 +310,19 @@ int pstore_put_backend_records(struct pstore_info *psi) if (!root) return 0; - mutex_lock(&records_list_lock); - list_for_each_entry_safe(pos, tmp, &records_list, list) { - if (pos->record->psi == psi) { - list_del_init(&pos->list); - rc = simple_unlink(d_inode(root), pos->dentry); - if (WARN_ON(rc)) - break; - d_drop(pos->dentry); - dput(pos->dentry); - pos->dentry = NULL; + scoped_guard(mutex, &records_list_lock) { + list_for_each_entry_safe(pos, tmp, &records_list, list) { + if (pos->record->psi == psi) { + list_del_init(&pos->list); + rc = simple_unlink(d_inode(root), pos->dentry); + if (WARN_ON(rc)) + break; + d_drop(pos->dentry); + dput(pos->dentry); + pos->dentry = NULL; + } } } - mutex_unlock(&records_list_lock); inode_unlock(d_inode(root)); @@ -353,20 +346,20 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) if (WARN_ON(!inode_is_locked(d_inode(root)))) return -EINVAL; - rc = -EEXIST; + guard(mutex)(&records_list_lock); + /* Skip records that are already present in the filesystem. */ - mutex_lock(&records_list_lock); list_for_each_entry(pos, &records_list, list) { if (pos->record->type == record->type && pos->record->id == record->id && pos->record->psi == record->psi) - goto fail; + return -EEXIST; } rc = -ENOMEM; inode = pstore_get_inode(root->d_sb); if (!inode) - goto fail; + return -ENOMEM; inode->i_mode = S_IFREG | 0444; inode->i_fop = &pstore_file_operations; scnprintf(name, sizeof(name), "%s-%s-%llu%s", @@ -394,7 +387,6 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) d_add(dentry, inode); list_add(&private->list, &records_list); - mutex_unlock(&records_list_lock); return 0; @@ -402,8 +394,6 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) free_pstore_private(private); fail_inode: iput(inode); -fail: - mutex_unlock(&records_list_lock); return rc; } @@ -449,9 +439,8 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) return -ENOMEM; - mutex_lock(&pstore_sb_lock); - pstore_sb = sb; - mutex_unlock(&pstore_sb_lock); + scoped_guard(mutex, &pstore_sb_lock) + pstore_sb = sb; pstore_get_records(0); @@ -466,17 +455,14 @@ static struct dentry *pstore_mount(struct file_system_type *fs_type, static void pstore_kill_sb(struct super_block *sb) { - mutex_lock(&pstore_sb_lock); + guard(mutex)(&pstore_sb_lock); WARN_ON(pstore_sb && pstore_sb != sb); kill_litter_super(sb); pstore_sb = NULL; - mutex_lock(&records_list_lock); + guard(mutex)(&records_list_lock); INIT_LIST_HEAD(&records_list); - mutex_unlock(&records_list_lock); - - mutex_unlock(&pstore_sb_lock); } static struct file_system_type pstore_fs_type = { From b775a054e9dcd4ca20d56367b3d39b3d69e50a46 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 5 Dec 2023 10:26:16 -0800 Subject: [PATCH 3409/7721] pstore: inode: Use __free(pstore_iput) for inode allocations Simplify error path for failures where "inode" needs to be freed. Cc: Guilherme G. Piccoli Cc: Tony Luck Cc: Link: https://lore.kernel.org/r/20231205182622.1329923-3-keescook@chromium.org Signed-off-by: Kees Cook --- fs/pstore/inode.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 0d89e0014b6f..a27764341079 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -35,6 +35,8 @@ static LIST_HEAD(records_list); static DEFINE_MUTEX(pstore_sb_lock); static struct super_block *pstore_sb; +DEFINE_FREE(pstore_iput, struct inode *, if (_T) iput(_T)) + struct pstore_private { struct list_head list; struct dentry *dentry; @@ -337,7 +339,7 @@ int pstore_put_backend_records(struct pstore_info *psi) int pstore_mkfile(struct dentry *root, struct pstore_record *record) { struct dentry *dentry; - struct inode *inode; + struct inode *inode __free(pstore_iput) = NULL; int rc = 0; char name[PSTORE_NAMELEN]; struct pstore_private *private, *pos; @@ -369,7 +371,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) private = kzalloc(sizeof(*private), GFP_KERNEL); if (!private) - goto fail_inode; + return -ENOMEM; dentry = d_alloc_name(root, name); if (!dentry) @@ -384,7 +386,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) inode_set_mtime_to_ts(inode, inode_set_ctime_to_ts(inode, record->time)); - d_add(dentry, inode); + d_add(dentry, no_free_ptr(inode)); list_add(&private->list, &records_list); @@ -392,8 +394,6 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) fail_private: free_pstore_private(private); -fail_inode: - iput(inode); return rc; } From 24a0b5e196cf70ccff97bc0add6fa7178ad50cc4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 5 Dec 2023 10:26:17 -0800 Subject: [PATCH 3410/7721] pstore: inode: Use cleanup.h for struct pstore_private Simplify error path when "private" needs to be freed. Cc: Guilherme G. Piccoli Cc: Tony Luck Cc: Link: https://lore.kernel.org/r/20231205182622.1329923-4-keescook@chromium.org Signed-off-by: Kees Cook --- fs/pstore/inode.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index a27764341079..d0d9bfdad30c 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -63,6 +63,7 @@ static void free_pstore_private(struct pstore_private *private) } kfree(private); } +DEFINE_FREE(pstore_private, struct pstore_private *, free_pstore_private(_T)); static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) { @@ -340,9 +341,8 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) { struct dentry *dentry; struct inode *inode __free(pstore_iput) = NULL; - int rc = 0; char name[PSTORE_NAMELEN]; - struct pstore_private *private, *pos; + struct pstore_private *private __free(pstore_private) = NULL, *pos; size_t size = record->size + record->ecc_notice_size; if (WARN_ON(!inode_is_locked(d_inode(root)))) @@ -358,7 +358,6 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) return -EEXIST; } - rc = -ENOMEM; inode = pstore_get_inode(root->d_sb); if (!inode) return -ENOMEM; @@ -375,7 +374,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) dentry = d_alloc_name(root, name); if (!dentry) - goto fail_private; + return -ENOMEM; private->dentry = dentry; private->record = record; @@ -388,13 +387,9 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) d_add(dentry, no_free_ptr(inode)); - list_add(&private->list, &records_list); + list_add(&(no_free_ptr(private))->list, &records_list); return 0; - -fail_private: - free_pstore_private(private); - return rc; } /* From 92e1567ee3e3f6f160e320890ac77eec50bf8e7d Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Thu, 7 Dec 2023 22:25:17 -0500 Subject: [PATCH 3411/7721] bpf: Add some comments to stack representation Add comments to the datastructure tracking the stack state, as the mapping between each stack slot and where its state is stored is not entirely obvious. Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20231208032519.260451-2-andreimatei1@gmail.com --- include/linux/bpf_verifier.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index bada59812e00..314b679fb494 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -321,7 +321,17 @@ struct bpf_func_state { /* The following fields should be last. See copy_func_state() */ int acquired_refs; struct bpf_reference_state *refs; + /* The state of the stack. Each element of the array describes BPF_REG_SIZE + * (i.e. 8) bytes worth of stack memory. + * stack[0] represents bytes [*(r10-8)..*(r10-1)] + * stack[1] represents bytes [*(r10-16)..*(r10-9)] + * ... + * stack[allocated_stack/8 - 1] represents [*(r10-allocated_stack)..*(r10-allocated_stack+7)] + */ struct bpf_stack_state *stack; + /* Size of the current stack, in bytes. The stack state is tracked below, in + * `stack`. allocated_stack is always a multiple of BPF_REG_SIZE. + */ int allocated_stack; }; @@ -658,6 +668,10 @@ struct bpf_verifier_env { int exception_callback_subprog; bool explore_alu_limits; bool allow_ptr_leaks; + /* Allow access to uninitialized stack memory. Writes with fixed offset are + * always allowed, so this refers to reads (with fixed or variable offset), + * to writes with variable offset and to indirect (helper) accesses. + */ bool allow_uninit_stack; bool bpf_capable; bool bypass_spec_v1; From 6b4a64bafd107e521c01eec3453ce94a3fb38529 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Thu, 7 Dec 2023 22:25:18 -0500 Subject: [PATCH 3412/7721] bpf: Fix accesses to uninit stack slots Privileged programs are supposed to be able to read uninitialized stack memory (ever since 6715df8d5) but, before this patch, these accesses were permitted inconsistently. In particular, accesses were permitted above state->allocated_stack, but not below it. In other words, if the stack was already "large enough", the access was permitted, but otherwise the access was rejected instead of being allowed to "grow the stack". This undesired rejection was happening in two places: - in check_stack_slot_within_bounds() - in check_stack_range_initialized() This patch arranges for these accesses to be permitted. A bunch of tests that were relying on the old rejection had to change; all of them were changed to add also run unprivileged, in which case the old behavior persists. One tests couldn't be updated - global_func16 - because it can't run unprivileged for other reasons. This patch also fixes the tracking of the stack size for variable-offset reads. This second fix is bundled in the same commit as the first one because they're inter-related. Before this patch, writes to the stack using registers containing a variable offset (as opposed to registers with fixed, known values) were not properly contributing to the function's needed stack size. As a result, it was possible for a program to verify, but then to attempt to read out-of-bounds data at runtime because a too small stack had been allocated for it. Each function tracks the size of the stack it needs in bpf_subprog_info.stack_depth, which is maintained by update_stack_depth(). For regular memory accesses, check_mem_access() was calling update_state_depth() but it was passing in only the fixed part of the offset register, ignoring the variable offset. This was incorrect; the minimum possible value of that register should be used instead. This tracking is now fixed by centralizing the tracking of stack size in grow_stack_state(), and by lifting the calls to grow_stack_state() to check_stack_access_within_bounds() as suggested by Andrii. The code is now simpler and more convincingly tracks the correct maximum stack size. check_stack_range_initialized() can now rely on enough stack having been allocated for the access; this helps with the fix for the first issue. A few tests were changed to also check the stack depth computation. The one that fails without this patch is verifier_var_off:stack_write_priv_vs_unpriv. Fixes: 01f810ace9ed3 ("bpf: Allow variable-offset stack access") Reported-by: Hao Sun Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20231208032519.260451-3-andreimatei1@gmail.com Closes: https://lore.kernel.org/bpf/CABWLsev9g8UP_c3a=1qbuZUi20tGoUXoU07FPf-5FLvhOKOY+Q@mail.gmail.com/ --- kernel/bpf/verifier.c | 65 ++++++++----------- tools/testing/selftests/bpf/progs/iters.c | 2 +- .../selftests/bpf/progs/test_global_func16.c | 2 +- .../bpf/progs/verifier_basic_stack.c | 8 +-- .../selftests/bpf/progs/verifier_int_ptr.c | 5 +- .../selftests/bpf/progs/verifier_raw_stack.c | 5 +- .../selftests/bpf/progs/verifier_var_off.c | 62 ++++++++++++++---- .../selftests/bpf/verifier/atomic_cmpxchg.c | 11 ---- tools/testing/selftests/bpf/verifier/calls.c | 4 +- 9 files changed, 92 insertions(+), 72 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0e77bb52542d..de1e29fa467e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1259,7 +1259,10 @@ static int resize_reference_state(struct bpf_func_state *state, size_t n) return 0; } -static int grow_stack_state(struct bpf_func_state *state, int size) +/* Possibly update state->allocated_stack to be at least size bytes. Also + * possibly update the function's high-water mark in its bpf_subprog_info. + */ +static int grow_stack_state(struct bpf_verifier_env *env, struct bpf_func_state *state, int size) { size_t old_n = state->allocated_stack / BPF_REG_SIZE, n = size / BPF_REG_SIZE; @@ -1271,6 +1274,11 @@ static int grow_stack_state(struct bpf_func_state *state, int size) return -ENOMEM; state->allocated_stack = size; + + /* update known max for given subprogram */ + if (env->subprog_info[state->subprogno].stack_depth < size) + env->subprog_info[state->subprogno].stack_depth = size; + return 0; } @@ -4440,9 +4448,6 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, struct bpf_reg_state *reg = NULL; int insn_flags = insn_stack_access_flags(state->frameno, spi); - err = grow_stack_state(state, round_up(slot + 1, BPF_REG_SIZE)); - if (err) - return err; /* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0, * so it's aligned access and [off, off + size) are within stack limits */ @@ -4595,10 +4600,6 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, (!value_reg && is_bpf_st_mem(insn) && insn->imm == 0)) writing_zero = true; - err = grow_stack_state(state, round_up(-min_off, BPF_REG_SIZE)); - if (err) - return err; - for (i = min_off; i < max_off; i++) { int spi; @@ -5774,20 +5775,6 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, strict); } -static int update_stack_depth(struct bpf_verifier_env *env, - const struct bpf_func_state *func, - int off) -{ - u16 stack = env->subprog_info[func->subprogno].stack_depth; - - if (stack >= -off) - return 0; - - /* update known max for given subprogram */ - env->subprog_info[func->subprogno].stack_depth = -off; - return 0; -} - /* starting from main bpf function walk all instructions of the function * and recursively walk all callees that given function can call. * Ignore jump and exit insns. @@ -6577,13 +6564,14 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env, * The minimum valid offset is -MAX_BPF_STACK for writes, and * -state->allocated_stack for reads. */ -static int check_stack_slot_within_bounds(s64 off, - struct bpf_func_state *state, - enum bpf_access_type t) +static int check_stack_slot_within_bounds(struct bpf_verifier_env *env, + s64 off, + struct bpf_func_state *state, + enum bpf_access_type t) { int min_valid_off; - if (t == BPF_WRITE) + if (t == BPF_WRITE || env->allow_uninit_stack) min_valid_off = -MAX_BPF_STACK; else min_valid_off = -state->allocated_stack; @@ -6632,7 +6620,7 @@ static int check_stack_access_within_bounds( max_off = reg->smax_value + off + access_size; } - err = check_stack_slot_within_bounds(min_off, state, type); + err = check_stack_slot_within_bounds(env, min_off, state, type); if (!err && max_off > 0) err = -EINVAL; /* out of stack access into non-negative offsets */ @@ -6647,8 +6635,10 @@ static int check_stack_access_within_bounds( verbose(env, "invalid variable-offset%s stack R%d var_off=%s off=%d size=%d\n", err_extra, regno, tn_buf, off, access_size); } + return err; } - return err; + + return grow_stack_state(env, state, round_up(-min_off, BPF_REG_SIZE)); } /* check whether memory at (regno + off) is accessible for t = (read | write) @@ -6663,7 +6653,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn { struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = regs + regno; - struct bpf_func_state *state; int size, err = 0; size = bpf_size_to_bytes(bpf_size); @@ -6806,11 +6795,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn if (err) return err; - state = func(env, reg); - err = update_stack_depth(env, state, off); - if (err) - return err; - if (t == BPF_READ) err = check_stack_read(env, regno, off, size, value_regno); @@ -7004,7 +6988,8 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i /* When register 'regno' is used to read the stack (either directly or through * a helper function) make sure that it's within stack boundary and, depending - * on the access type, that all elements of the stack are initialized. + * on the access type and privileges, that all elements of the stack are + * initialized. * * 'off' includes 'regno->off', but not its dynamic part (if any). * @@ -7112,8 +7097,11 @@ static int check_stack_range_initialized( slot = -i - 1; spi = slot / BPF_REG_SIZE; - if (state->allocated_stack <= slot) - goto err; + if (state->allocated_stack <= slot) { + verbose(env, "verifier bug: allocated_stack too small"); + return -EFAULT; + } + stype = &state->stack[spi].slot_type[slot % BPF_REG_SIZE]; if (*stype == STACK_MISC) goto mark; @@ -7137,7 +7125,6 @@ static int check_stack_range_initialized( goto mark; } -err: if (tnum_is_const(reg->var_off)) { verbose(env, "invalid%s read from stack R%d off %d+%d size %d\n", err_extra, regno, min_off, i - min_off, access_size); @@ -7162,7 +7149,7 @@ static int check_stack_range_initialized( * helper may write to the entire memory range. */ } - return update_stack_depth(env, state, min_off); + return 0; } static int check_helper_mem_access(struct bpf_verifier_env *env, int regno, diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index b2181f850d3e..3aca3dc145b5 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -846,7 +846,7 @@ __naked int delayed_precision_mark(void) "call %[bpf_iter_num_next];" "if r0 == 0 goto 2f;" "if r6 != 42 goto 3f;" - "r7 = -32;" + "r7 = -33;" "call %[bpf_get_prandom_u32];" "r6 = r0;" "goto 1b;\n" diff --git a/tools/testing/selftests/bpf/progs/test_global_func16.c b/tools/testing/selftests/bpf/progs/test_global_func16.c index e7206304632e..e3e64bc472cd 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func16.c +++ b/tools/testing/selftests/bpf/progs/test_global_func16.c @@ -13,7 +13,7 @@ __noinline int foo(int (*arr)[10]) } SEC("cgroup_skb/ingress") -__failure __msg("invalid indirect read from stack") +__success int global_func16(struct __sk_buff *skb) { int array[10]; diff --git a/tools/testing/selftests/bpf/progs/verifier_basic_stack.c b/tools/testing/selftests/bpf/progs/verifier_basic_stack.c index 359df865a8f3..8d77cc5323d3 100644 --- a/tools/testing/selftests/bpf/progs/verifier_basic_stack.c +++ b/tools/testing/selftests/bpf/progs/verifier_basic_stack.c @@ -27,8 +27,8 @@ __naked void stack_out_of_bounds(void) SEC("socket") __description("uninitialized stack1") -__failure __msg("invalid indirect read from stack") -__failure_unpriv +__success __log_level(4) __msg("stack depth 8") +__failure_unpriv __msg_unpriv("invalid indirect read from stack") __naked void uninitialized_stack1(void) { asm volatile (" \ @@ -45,8 +45,8 @@ __naked void uninitialized_stack1(void) SEC("socket") __description("uninitialized stack2") -__failure __msg("invalid read from stack") -__failure_unpriv +__success __log_level(4) __msg("stack depth 8") +__failure_unpriv __msg_unpriv("invalid read from stack") __naked void uninitialized_stack2(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c index 74d9cad469d9..9fc3fae5cd83 100644 --- a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c +++ b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c @@ -5,9 +5,10 @@ #include #include "bpf_misc.h" -SEC("cgroup/sysctl") +SEC("socket") __description("ARG_PTR_TO_LONG uninitialized") -__failure __msg("invalid indirect read from stack R4 off -16+0 size 8") +__success +__failure_unpriv __msg_unpriv("invalid indirect read from stack R4 off -16+0 size 8") __naked void arg_ptr_to_long_uninitialized(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c index efbfc3a4ad6a..f67390224a9c 100644 --- a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c +++ b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c @@ -5,9 +5,10 @@ #include #include "bpf_misc.h" -SEC("tc") +SEC("socket") __description("raw_stack: no skb_load_bytes") -__failure __msg("invalid read from stack R6 off=-8 size=8") +__success +__failure_unpriv __msg_unpriv("invalid read from stack R6 off=-8 size=8") __naked void stack_no_skb_load_bytes(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_var_off.c b/tools/testing/selftests/bpf/progs/verifier_var_off.c index b7bdd7db3a35..c810f4f6f479 100644 --- a/tools/testing/selftests/bpf/progs/verifier_var_off.c +++ b/tools/testing/selftests/bpf/progs/verifier_var_off.c @@ -59,9 +59,10 @@ __naked void stack_read_priv_vs_unpriv(void) " ::: __clobber_all); } -SEC("lwt_in") +SEC("cgroup/skb") __description("variable-offset stack read, uninitialized") -__failure __msg("invalid variable-offset read from stack R2") +__success +__failure_unpriv __msg_unpriv("R2 variable stack access prohibited for !root") __naked void variable_offset_stack_read_uninitialized(void) { asm volatile (" \ @@ -83,12 +84,55 @@ __naked void variable_offset_stack_read_uninitialized(void) SEC("socket") __description("variable-offset stack write, priv vs unpriv") -__success __failure_unpriv +__success +/* Check that the maximum stack depth is correctly maintained according to the + * maximum possible variable offset. + */ +__log_level(4) __msg("stack depth 16") +__failure_unpriv /* Variable stack access is rejected for unprivileged. */ __msg_unpriv("R2 variable stack access prohibited for !root") __retval(0) __naked void stack_write_priv_vs_unpriv(void) +{ + asm volatile (" \ + /* Get an unknown value */ \ + r2 = *(u32*)(r1 + 0); \ + /* Make it small and 8-byte aligned */ \ + r2 &= 8; \ + r2 -= 16; \ + /* Add it to fp. We now have either fp-8 or \ + * fp-16, but we don't know which \ + */ \ + r2 += r10; \ + /* Dereference it for a stack write */ \ + r0 = 0; \ + *(u64*)(r2 + 0) = r0; \ + exit; \ +" ::: __clobber_all); +} + +/* Similar to the previous test, but this time also perform a read from the + * address written to with a variable offset. The read is allowed, showing that, + * after a variable-offset write, a priviledged program can read the slots that + * were in the range of that write (even if the verifier doesn't actually know if + * the slot being read was really written to or not. + * + * Despite this test being mostly a superset, the previous test is also kept for + * the sake of it checking the stack depth in the case where there is no read. + */ +SEC("socket") +__description("variable-offset stack write followed by read") +__success +/* Check that the maximum stack depth is correctly maintained according to the + * maximum possible variable offset. + */ +__log_level(4) __msg("stack depth 16") +__failure_unpriv +__msg_unpriv("R2 variable stack access prohibited for !root") +__retval(0) +__naked void stack_write_followed_by_read(void) { asm volatile (" \ /* Get an unknown value */ \ @@ -103,12 +147,7 @@ __naked void stack_write_priv_vs_unpriv(void) /* Dereference it for a stack write */ \ r0 = 0; \ *(u64*)(r2 + 0) = r0; \ - /* Now read from the address we just wrote. This shows\ - * that, after a variable-offset write, a priviledged\ - * program can read the slots that were in the range of\ - * that write (even if the verifier doesn't actually know\ - * if the slot being read was really written to or not.\ - */ \ + /* Now read from the address we just wrote. */ \ r3 = *(u64*)(r2 + 0); \ r0 = 0; \ exit; \ @@ -282,9 +321,10 @@ __naked void access_min_out_of_bound(void) : __clobber_all); } -SEC("lwt_in") +SEC("cgroup/skb") __description("indirect variable-offset stack access, min_off < min_initialized") -__failure __msg("invalid indirect read from stack R2 var_off") +__success +__failure_unpriv __msg_unpriv("R2 variable stack access prohibited for !root") __naked void access_min_off_min_initialized(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c b/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c index 319337bdcfc8..9a7b1106fda8 100644 --- a/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c +++ b/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c @@ -83,17 +83,6 @@ .result = REJECT, .errstr = "!read_ok", }, -{ - "Can't use cmpxchg on uninit memory", - .insns = { - BPF_MOV64_IMM(BPF_REG_0, 3), - BPF_MOV64_IMM(BPF_REG_2, 4), - BPF_ATOMIC_OP(BPF_DW, BPF_CMPXCHG, BPF_REG_10, BPF_REG_2, -8), - BPF_EXIT_INSN(), - }, - .result = REJECT, - .errstr = "invalid read from stack", -}, { "BPF_W cmpxchg should zero top 32 bits", .insns = { diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c index 3d5cd51071f0..ab25a81fd3a1 100644 --- a/tools/testing/selftests/bpf/verifier/calls.c +++ b/tools/testing/selftests/bpf/verifier/calls.c @@ -1505,7 +1505,9 @@ .prog_type = BPF_PROG_TYPE_XDP, .fixup_map_hash_8b = { 23 }, .result = REJECT, - .errstr = "invalid read from stack R7 off=-16 size=8", + .errstr = "R0 invalid mem access 'scalar'", + .result_unpriv = REJECT, + .errstr_unpriv = "invalid read from stack R7 off=-16 size=8", }, { "calls: two calls that receive map_value via arg=ptr_stack_of_caller. test1", From 2929bfac006d8f8e22b307d04e0d71bcb84db698 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Thu, 7 Dec 2023 22:25:19 -0500 Subject: [PATCH 3413/7721] bpf: Minor cleanup around stack bounds Push the rounding up of stack offsets into the function responsible for growing the stack, rather than relying on all the callers to do it. Uncertainty about whether the callers did it or not tripped up people in a previous review. Signed-off-by: Andrei Matei Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20231208032519.260451-4-andreimatei1@gmail.com --- kernel/bpf/verifier.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index de1e29fa467e..fb690539d5f6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1264,7 +1264,11 @@ static int resize_reference_state(struct bpf_func_state *state, size_t n) */ static int grow_stack_state(struct bpf_verifier_env *env, struct bpf_func_state *state, int size) { - size_t old_n = state->allocated_stack / BPF_REG_SIZE, n = size / BPF_REG_SIZE; + size_t old_n = state->allocated_stack / BPF_REG_SIZE, n; + + /* The stack size is always a multiple of BPF_REG_SIZE. */ + size = round_up(size, BPF_REG_SIZE); + n = size / BPF_REG_SIZE; if (old_n >= n) return 0; @@ -6638,7 +6642,10 @@ static int check_stack_access_within_bounds( return err; } - return grow_stack_state(env, state, round_up(-min_off, BPF_REG_SIZE)); + /* Note that there is no stack access with offset zero, so the needed stack + * size is -min_off, not -min_off+1. + */ + return grow_stack_state(env, state, -min_off /* size */); } /* check whether memory at (regno + off) is accessible for t = (read | write) From 8926f57943d4352612b40e96c8232bef4cc6e362 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 5 Dec 2023 18:53:55 -0800 Subject: [PATCH 3414/7721] fs: vboxsf: fix a kernel-doc warning Fix function parameters to prevent kernel-doc warnings. vboxsf_wrappers.c:132: warning: Function parameter or member 'create_parms' not described in 'vboxsf_create' vboxsf_wrappers.c:132: warning: Excess function parameter 'param' description in 'vboxsf_create' Signed-off-by: Randy Dunlap Cc: Hans de Goede Cc: Alexander Viro Cc: Christian Brauner Reviewed-by: Hans de Goede Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231206025355.31814-1-rdunlap@infradead.org --- fs/vboxsf/vboxsf_wrappers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/vboxsf/vboxsf_wrappers.c b/fs/vboxsf/vboxsf_wrappers.c index bfc78a097dae..5e8d4359e171 100644 --- a/fs/vboxsf/vboxsf_wrappers.c +++ b/fs/vboxsf/vboxsf_wrappers.c @@ -114,7 +114,7 @@ int vboxsf_unmap_folder(u32 root) * vboxsf_create - Create a new file or folder * @root: Root of the shared folder in which to create the file * @parsed_path: The path of the file or folder relative to the shared folder - * @param: create_parms Parameters for file/folder creation. + * @create_parms: Parameters for file/folder creation. * * Create a new file or folder or open an existing one in a shared folder. * Note this function always returns 0 / success unless an exceptional condition From 2b4ba158ae04a6bbda20c2305b35c13dbc7ced18 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Fri, 1 Dec 2023 14:10:42 +0100 Subject: [PATCH 3415/7721] docs: nvmem: generate kernel-doc API documentation This is useful on its own, and it also enables hyperlink generation for functions mentioned in ReST documentation. Signed-off-by: Luca Ceresoli Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231201-nvmem-docs-kerneldoc-v1-1-3e8f2b706ce6@bootlin.com --- Documentation/driver-api/nvmem.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst index de221e91c8e3..d5655b95c0f4 100644 --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst @@ -200,3 +200,9 @@ and let you add cells dynamically. Another use case for layouts is the post processing of cells. With layouts, it is possible to associate a custom post processing hook to a cell. It even possible to add this hook to cells not created by the layout itself. + +9. Internal kernel API +====================== + +.. kernel-doc:: drivers/nvmem/core.c + :export: From e57ddc6c80d2b39381f4476d99dab09825a8d584 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Fri, 1 Dec 2023 14:10:43 +0100 Subject: [PATCH 3416/7721] docs: nvmem: remove function parameters (fixes hyperlink generation) Adding a parameter is not particularly useful here, and it is definitely not done elsewhere. It also prevents the generation of a hyperlink to the kernel-doc documentation. Removing the parameter to enable hyperlinks and make the style coherent. Signed-off-by: Luca Ceresoli Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231201-nvmem-docs-kerneldoc-v1-2-3e8f2b706ce6@bootlin.com --- Documentation/driver-api/nvmem.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst index d5655b95c0f4..5d9500d21ecc 100644 --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst @@ -41,7 +41,7 @@ A NVMEM provider can register with NVMEM core by supplying relevant nvmem configuration to nvmem_register(), on success core would return a valid nvmem_device pointer. -nvmem_unregister(nvmem) is used to unregister a previously registered provider. +nvmem_unregister() is used to unregister a previously registered provider. For example, a simple nvram case:: From 7048708fec3a401f9a70e4a74e2e12aa7f88c132 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Mon, 4 Dec 2023 18:39:03 +0100 Subject: [PATCH 3417/7721] dt-bindings: drm: rockchip: convert inno_hdmi-rockchip.txt to yaml Convert inno_hdmi-rockchip.txt to yaml. Signed-off-by: Johan Jonker Link: https://lore.kernel.org/r/49c6afec-022f-02de-99a0-d409b64da198@gmail.com Signed-off-by: Rob Herring --- .../display/rockchip/inno_hdmi-rockchip.txt | 49 --------- .../display/rockchip/rockchip,inno-hdmi.yaml | 103 ++++++++++++++++++ 2 files changed, 103 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt deleted file mode 100644 index cec21714f0e0..000000000000 --- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +++ /dev/null @@ -1,49 +0,0 @@ -Rockchip specific extensions to the Innosilicon HDMI -================================ - -Required properties: -- compatible: - "rockchip,rk3036-inno-hdmi"; -- reg: - Physical base address and length of the controller's registers. -- clocks, clock-names: - Phandle to hdmi controller clock, name should be "pclk" -- interrupts: - HDMI interrupt number -- ports: - Contain one port node with endpoint definitions as defined in - Documentation/devicetree/bindings/graph.txt. -- pinctrl-0, pinctrl-name: - Switch the iomux of HPD/CEC pins to HDMI function. - -Example: -hdmi: hdmi@20034000 { - compatible = "rockchip,rk3036-inno-hdmi"; - reg = <0x20034000 0x4000>; - interrupts = ; - clocks = <&cru PCLK_HDMI>; - clock-names = "pclk"; - pinctrl-names = "default"; - pinctrl-0 = <&hdmi_ctl>; - - hdmi_in: port { - #address-cells = <1>; - #size-cells = <0>; - hdmi_in_lcdc: endpoint@0 { - reg = <0>; - remote-endpoint = <&lcdc_out_hdmi>; - }; - }; -}; - -&pinctrl { - hdmi { - hdmi_ctl: hdmi-ctl { - rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>, - <1 9 RK_FUNC_1 &pcfg_pull_none>, - <1 10 RK_FUNC_1 &pcfg_pull_none>, - <1 11 RK_FUNC_1 &pcfg_pull_none>; - }; - }; - -}; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml new file mode 100644 index 000000000000..96889c86849a --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip,inno-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip Innosilicon HDMI controller + +maintainers: + - Sandy Huang + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,rk3036-inno-hdmi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: pclk + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a vop node. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a hdmi-connector node. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - pinctrl-0 + - pinctrl-names + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; + clocks = <&cru PCLK_HDMI>; + clock-names = "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + hdmi_in_vop: endpoint { + remote-endpoint = <&vop_out_hdmi>; + }; + }; + + hdmi_out: port@1 { + reg = <1>; + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; + }; + }; + + pinctrl { + hdmi { + hdmi_ctl: hdmi-ctl { + rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>, + <1 RK_PB1 1 &pcfg_pull_none>, + <1 RK_PB2 1 &pcfg_pull_none>, + <1 RK_PB3 1 &pcfg_pull_none>; + }; + }; + }; From 50709576d81bbcbe027d22c64cd2ec934bd9087b Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Tue, 28 Nov 2023 12:53:52 +0530 Subject: [PATCH 3418/7721] Documentation: Destage TEE subsystem documentation Add a separate documentation directory for TEE subsystem since it is a standalone subsystem which already offers devices consumed by multiple different subsystem drivers. Split overall TEE subsystem documentation modularly where: - The userspace API has been moved to Documentation/userspace-api/tee.rst. - The driver API has been moved to Documentation/driver-api/tee.rst. - The first module covers the overview of TEE subsystem. - The further modules are dedicated to different TEE implementations like: - OP-TEE - AMD-TEE - and so on for future TEE implementation support. Acked-by: Rijo Thomas Acked-by: Jens Wiklander Signed-off-by: Sumit Garg Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20231128072352.866859-1-sumit.garg@linaro.org --- Documentation/driver-api/index.rst | 1 + Documentation/driver-api/tee.rst | 66 ++++ .../security/keys/trusted-encrypted.rst | 2 +- Documentation/staging/index.rst | 1 - Documentation/staging/tee.rst | 364 ------------------ Documentation/subsystem-apis.rst | 1 + Documentation/tee/amd-tee.rst | 90 +++++ Documentation/tee/index.rst | 19 + Documentation/tee/op-tee.rst | 166 ++++++++ Documentation/tee/tee.rst | 22 ++ Documentation/userspace-api/index.rst | 1 + Documentation/userspace-api/tee.rst | 39 ++ MAINTAINERS | 4 +- drivers/tee/optee/Kconfig | 2 +- 14 files changed, 410 insertions(+), 368 deletions(-) create mode 100644 Documentation/driver-api/tee.rst delete mode 100644 Documentation/staging/tee.rst create mode 100644 Documentation/tee/amd-tee.rst create mode 100644 Documentation/tee/index.rst create mode 100644 Documentation/tee/op-tee.rst create mode 100644 Documentation/tee/tee.rst create mode 100644 Documentation/userspace-api/tee.rst diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 48bd9921d937..9511db303446 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -112,6 +112,7 @@ available subsections can be seen below. hte/index wmi dpll + tee .. only:: subproject and html diff --git a/Documentation/driver-api/tee.rst b/Documentation/driver-api/tee.rst new file mode 100644 index 000000000000..5eaeb8103988 --- /dev/null +++ b/Documentation/driver-api/tee.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============================================== +TEE (Trusted Execution Environment) driver API +=============================================== + +Kernel provides a TEE bus infrastructure where a Trusted Application is +represented as a device identified via Universally Unique Identifier (UUID) and +client drivers register a table of supported device UUIDs. + +TEE bus infrastructure registers following APIs: + +match(): + iterates over the client driver UUID table to find a corresponding + match for device UUID. If a match is found, then this particular device is + probed via corresponding probe API registered by the client driver. This + process happens whenever a device or a client driver is registered with TEE + bus. + +uevent(): + notifies user-space (udev) whenever a new device is registered on + TEE bus for auto-loading of modularized client drivers. + +TEE bus device enumeration is specific to underlying TEE implementation, so it +is left open for TEE drivers to provide corresponding implementation. + +Then TEE client driver can talk to a matched Trusted Application using APIs +listed in include/linux/tee_drv.h. + +TEE client driver example +------------------------- + +Suppose a TEE client driver needs to communicate with a Trusted Application +having UUID: ``ac6a4085-0e82-4c33-bf98-8eb8e118b6c2``, so driver registration +snippet would look like:: + + static const struct tee_client_device_id client_id_table[] = { + {UUID_INIT(0xac6a4085, 0x0e82, 0x4c33, + 0xbf, 0x98, 0x8e, 0xb8, 0xe1, 0x18, 0xb6, 0xc2)}, + {} + }; + + MODULE_DEVICE_TABLE(tee, client_id_table); + + static struct tee_client_driver client_driver = { + .id_table = client_id_table, + .driver = { + .name = DRIVER_NAME, + .bus = &tee_bus_type, + .probe = client_probe, + .remove = client_remove, + }, + }; + + static int __init client_init(void) + { + return driver_register(&client_driver.driver); + } + + static void __exit client_exit(void) + { + driver_unregister(&client_driver.driver); + } + + module_init(client_init); + module_exit(client_exit); diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst index 9bc9db8ec651..e989b9802f92 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -88,7 +88,7 @@ safe. (2) TEE TEEs have well-documented, standardized client interface and APIs. For - more details refer to ``Documentation/staging/tee.rst``. + more details refer to ``Documentation/driver-api/tee.rst``. (3) CAAM diff --git a/Documentation/staging/index.rst b/Documentation/staging/index.rst index ded8254bc0d7..71592f3ce89b 100644 --- a/Documentation/staging/index.rst +++ b/Documentation/staging/index.rst @@ -12,5 +12,4 @@ Unsorted Documentation rpmsg speculation static-keys - tee xz diff --git a/Documentation/staging/tee.rst b/Documentation/staging/tee.rst deleted file mode 100644 index 22baa077a3b9..000000000000 --- a/Documentation/staging/tee.rst +++ /dev/null @@ -1,364 +0,0 @@ -============= -TEE subsystem -============= - -This document describes the TEE subsystem in Linux. - -A TEE (Trusted Execution Environment) is a trusted OS running in some -secure environment, for example, TrustZone on ARM CPUs, or a separate -secure co-processor etc. A TEE driver handles the details needed to -communicate with the TEE. - -This subsystem deals with: - -- Registration of TEE drivers - -- Managing shared memory between Linux and the TEE - -- Providing a generic API to the TEE - -The TEE interface -================= - -include/uapi/linux/tee.h defines the generic interface to a TEE. - -User space (the client) connects to the driver by opening /dev/tee[0-9]* or -/dev/teepriv[0-9]*. - -- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor - which user space can mmap. When user space doesn't need the file - descriptor any more, it should be closed. When shared memory isn't needed - any longer it should be unmapped with munmap() to allow the reuse of - memory. - -- TEE_IOC_VERSION lets user space know which TEE this driver handles and - its capabilities. - -- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. - -- TEE_IOC_INVOKE invokes a function in a Trusted Application. - -- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. - -- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. - -There are two classes of clients, normal clients and supplicants. The latter is -a helper process for the TEE to access resources in Linux, for example file -system access. A normal client opens /dev/tee[0-9]* and a supplicant opens -/dev/teepriv[0-9]. - -Much of the communication between clients and the TEE is opaque to the -driver. The main job for the driver is to receive requests from the -clients, forward them to the TEE and send back the results. In the case of -supplicants the communication goes in the other direction, the TEE sends -requests to the supplicant which then sends back the result. - -The TEE kernel interface -======================== - -Kernel provides a TEE bus infrastructure where a Trusted Application is -represented as a device identified via Universally Unique Identifier (UUID) and -client drivers register a table of supported device UUIDs. - -TEE bus infrastructure registers following APIs: - -match(): - iterates over the client driver UUID table to find a corresponding - match for device UUID. If a match is found, then this particular device is - probed via corresponding probe API registered by the client driver. This - process happens whenever a device or a client driver is registered with TEE - bus. - -uevent(): - notifies user-space (udev) whenever a new device is registered on - TEE bus for auto-loading of modularized client drivers. - -TEE bus device enumeration is specific to underlying TEE implementation, so it -is left open for TEE drivers to provide corresponding implementation. - -Then TEE client driver can talk to a matched Trusted Application using APIs -listed in include/linux/tee_drv.h. - -TEE client driver example -------------------------- - -Suppose a TEE client driver needs to communicate with a Trusted Application -having UUID: ``ac6a4085-0e82-4c33-bf98-8eb8e118b6c2``, so driver registration -snippet would look like:: - - static const struct tee_client_device_id client_id_table[] = { - {UUID_INIT(0xac6a4085, 0x0e82, 0x4c33, - 0xbf, 0x98, 0x8e, 0xb8, 0xe1, 0x18, 0xb6, 0xc2)}, - {} - }; - - MODULE_DEVICE_TABLE(tee, client_id_table); - - static struct tee_client_driver client_driver = { - .id_table = client_id_table, - .driver = { - .name = DRIVER_NAME, - .bus = &tee_bus_type, - .probe = client_probe, - .remove = client_remove, - }, - }; - - static int __init client_init(void) - { - return driver_register(&client_driver.driver); - } - - static void __exit client_exit(void) - { - driver_unregister(&client_driver.driver); - } - - module_init(client_init); - module_exit(client_exit); - -OP-TEE driver -============= - -The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM -TrustZone based OP-TEE solution that is supported. - -Lowest level of communication with OP-TEE builds on ARM SMC Calling -Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface -[3] used internally by the driver. Stacked on top of that is OP-TEE Message -Protocol [4]. - -OP-TEE SMC interface provides the basic functions required by SMCCC and some -additional functions specific for OP-TEE. The most interesting functions are: - -- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information - which is then returned by TEE_IOC_VERSION - -- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used - to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a - separate secure co-processor. - -- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol - -- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory - range to used for shared memory between Linux and OP-TEE. - -The GlobalPlatform TEE Client API [5] is implemented on top of the generic -TEE API. - -Picture of the relationship between the different components in the -OP-TEE architecture:: - - User space Kernel Secure world - ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ - +--------+ +-------------+ - | Client | | Trusted | - +--------+ | Application | - /\ +-------------+ - || +----------+ /\ - || |tee- | || - || |supplicant| \/ - || +----------+ +-------------+ - \/ /\ | TEE Internal| - +-------+ || | API | - + TEE | || +--------+--------+ +-------------+ - | Client| || | TEE | OP-TEE | | OP-TEE | - | API | \/ | subsys | driver | | Trusted OS | - +-------+----------------+----+-------+----+-----------+-------------+ - | Generic TEE API | | OP-TEE MSG | - | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | - +-----------------------------+ +------------------------------+ - -RPC (Remote Procedure Call) are requests from secure world to kernel driver -or tee-supplicant. An RPC is identified by a special range of SMCCC return -values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the -kernel are handled by the kernel driver. Other RPC messages will be forwarded to -tee-supplicant without further involvement of the driver, except switching -shared memory buffer representation. - -OP-TEE device enumeration -------------------------- - -OP-TEE provides a pseudo Trusted Application: drivers/tee/optee/device.c in -order to support device enumeration. In other words, OP-TEE driver invokes this -application to retrieve a list of Trusted Applications which can be registered -as devices on the TEE bus. - -OP-TEE notifications --------------------- - -There are two kinds of notifications that secure world can use to make -normal world aware of some event. - -1. Synchronous notifications delivered with ``OPTEE_RPC_CMD_NOTIFICATION`` - using the ``OPTEE_RPC_NOTIFICATION_SEND`` parameter. -2. Asynchronous notifications delivered with a combination of a non-secure - edge-triggered interrupt and a fast call from the non-secure interrupt - handler. - -Synchronous notifications are limited by depending on RPC for delivery, -this is only usable when secure world is entered with a yielding call via -``OPTEE_SMC_CALL_WITH_ARG``. This excludes such notifications from secure -world interrupt handlers. - -An asynchronous notification is delivered via a non-secure edge-triggered -interrupt to an interrupt handler registered in the OP-TEE driver. The -actual notification value are retrieved with the fast call -``OPTEE_SMC_GET_ASYNC_NOTIF_VALUE``. Note that one interrupt can represent -multiple notifications. - -One notification value ``OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF`` has a -special meaning. When this value is received it means that normal world is -supposed to make a yielding call ``OPTEE_MSG_CMD_DO_BOTTOM_HALF``. This -call is done from the thread assisting the interrupt handler. This is a -building block for OP-TEE OS in secure world to implement the top half and -bottom half style of device drivers. - -OPTEE_INSECURE_LOAD_IMAGE Kconfig option ----------------------------------------- - -The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the -BL32 OP-TEE image from the kernel after the kernel boots, rather than loading -it from the firmware before the kernel boots. This also requires enabling the -corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm -documentation [8] explains the security threat associated with enabling this as -well as mitigations at the firmware and platform level. - -There are additional attack vectors/mitigations for the kernel that should be -addressed when using this option. - -1. Boot chain security. - - * Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of - the system. - - * Mitigation: There must be boot chain security that verifies the kernel and - rootfs, otherwise an attacker can modify the loaded OP-TEE binary by - modifying it in the rootfs. - -2. Alternate boot modes. - - * Attack vector: Using an alternate boot mode (i.e. recovery mode), the - OP-TEE driver isn't loaded, leaving the SMC hole open. - - * Mitigation: If there are alternate methods of booting the device, such as a - recovery mode, it should be ensured that the same mitigations are applied - in that mode. - -3. Attacks prior to SMC invocation. - - * Attack vector: Code that is executed prior to issuing the SMC call to load - OP-TEE can be exploited to then load an alternate OS image. - - * Mitigation: The OP-TEE driver must be loaded before any potential attack - vectors are opened up. This should include mounting of any modifiable - filesystems, opening of network ports or communicating with external - devices (e.g. USB). - -4. Blocking SMC call to load OP-TEE. - - * Attack vector: Prevent the driver from being probed, so the SMC call to - load OP-TEE isn't executed when desired, leaving it open to being executed - later and loading a modified OS. - - * Mitigation: It is recommended to build the OP-TEE driver as builtin driver - rather than as a module to prevent exploits that may cause the module to - not be loaded. - -AMD-TEE driver -============== - -The AMD-TEE driver handles the communication with AMD's TEE environment. The -TEE environment is provided by AMD Secure Processor. - -The AMD Secure Processor (formerly called Platform Security Processor or PSP) -is a dedicated processor that features ARM TrustZone technology, along with a -software-based Trusted Execution Environment (TEE) designed to enable -third-party Trusted Applications. This feature is currently enabled only for -APUs. - -The following picture shows a high level overview of AMD-TEE:: - - | - x86 | - | - User space (Kernel space) | AMD Secure Processor (PSP) - ~~~~~~~~~~ ~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~ - | - +--------+ | +-------------+ - | Client | | | Trusted | - +--------+ | | Application | - /\ | +-------------+ - || | /\ - || | || - || | \/ - || | +----------+ - || | | TEE | - || | | Internal | - \/ | | API | - +---------+ +-----------+---------+ +----------+ - | TEE | | TEE | AMD-TEE | | AMD-TEE | - | Client | | subsystem | driver | | Trusted | - | API | | | | | OS | - +---------+-----------+----+------+---------+---------+----------+ - | Generic TEE API | | ASP | Mailbox | - | IOCTL (TEE_IOC_*) | | driver | Register Protocol | - +--------------------------+ +---------+--------------------+ - -At the lowest level (in x86), the AMD Secure Processor (ASP) driver uses the -CPU to PSP mailbox register to submit commands to the PSP. The format of the -command buffer is opaque to the ASP driver. It's role is to submit commands to -the secure processor and return results to AMD-TEE driver. The interface -between AMD-TEE driver and AMD Secure Processor driver can be found in [6]. - -The AMD-TEE driver packages the command buffer payload for processing in TEE. -The command buffer format for the different TEE commands can be found in [7]. - -The TEE commands supported by AMD-TEE Trusted OS are: - -* TEE_CMD_ID_LOAD_TA - loads a Trusted Application (TA) binary into - TEE environment. -* TEE_CMD_ID_UNLOAD_TA - unloads TA binary from TEE environment. -* TEE_CMD_ID_OPEN_SESSION - opens a session with a loaded TA. -* TEE_CMD_ID_CLOSE_SESSION - closes session with loaded TA -* TEE_CMD_ID_INVOKE_CMD - invokes a command with loaded TA -* TEE_CMD_ID_MAP_SHARED_MEM - maps shared memory -* TEE_CMD_ID_UNMAP_SHARED_MEM - unmaps shared memory - -AMD-TEE Trusted OS is the firmware running on AMD Secure Processor. - -The AMD-TEE driver registers itself with TEE subsystem and implements the -following driver function callbacks: - -* get_version - returns the driver implementation id and capability. -* open - sets up the driver context data structure. -* release - frees up driver resources. -* open_session - loads the TA binary and opens session with loaded TA. -* close_session - closes session with loaded TA and unloads it. -* invoke_func - invokes a command with loaded TA. - -cancel_req driver callback is not supported by AMD-TEE. - -The GlobalPlatform TEE Client API [5] can be used by the user space (client) to -talk to AMD's TEE. AMD's TEE provides a secure environment for loading, opening -a session, invoking commands and closing session with TA. - -References -========== - -[1] https://github.com/OP-TEE/optee_os - -[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html - -[3] drivers/tee/optee/optee_smc.h - -[4] drivers/tee/optee/optee_msg.h - -[5] http://www.globalplatform.org/specificationsdevice.asp look for - "TEE Client API Specification v1.0" and click download. - -[6] include/linux/psp-tee.h - -[7] drivers/tee/amdtee/amdtee_if.h - -[8] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html diff --git a/Documentation/subsystem-apis.rst b/Documentation/subsystem-apis.rst index 930dc23998a0..2d353fb8ea26 100644 --- a/Documentation/subsystem-apis.rst +++ b/Documentation/subsystem-apis.rst @@ -86,3 +86,4 @@ Storage interfaces misc-devices/index peci/index wmi/index + tee/index diff --git a/Documentation/tee/amd-tee.rst b/Documentation/tee/amd-tee.rst new file mode 100644 index 000000000000..51500fde7038 --- /dev/null +++ b/Documentation/tee/amd-tee.rst @@ -0,0 +1,90 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================= +AMD-TEE (AMD's Trusted Execution Environment) +============================================= + +The AMD-TEE driver handles the communication with AMD's TEE environment. The +TEE environment is provided by AMD Secure Processor. + +The AMD Secure Processor (formerly called Platform Security Processor or PSP) +is a dedicated processor that features ARM TrustZone technology, along with a +software-based Trusted Execution Environment (TEE) designed to enable +third-party Trusted Applications. This feature is currently enabled only for +APUs. + +The following picture shows a high level overview of AMD-TEE:: + + | + x86 | + | + User space (Kernel space) | AMD Secure Processor (PSP) + ~~~~~~~~~~ ~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +--------+ | +-------------+ + | Client | | | Trusted | + +--------+ | | Application | + /\ | +-------------+ + || | /\ + || | || + || | \/ + || | +----------+ + || | | TEE | + || | | Internal | + \/ | | API | + +---------+ +-----------+---------+ +----------+ + | TEE | | TEE | AMD-TEE | | AMD-TEE | + | Client | | subsystem | driver | | Trusted | + | API | | | | | OS | + +---------+-----------+----+------+---------+---------+----------+ + | Generic TEE API | | ASP | Mailbox | + | IOCTL (TEE_IOC_*) | | driver | Register Protocol | + +--------------------------+ +---------+--------------------+ + +At the lowest level (in x86), the AMD Secure Processor (ASP) driver uses the +CPU to PSP mailbox register to submit commands to the PSP. The format of the +command buffer is opaque to the ASP driver. It's role is to submit commands to +the secure processor and return results to AMD-TEE driver. The interface +between AMD-TEE driver and AMD Secure Processor driver can be found in [1]. + +The AMD-TEE driver packages the command buffer payload for processing in TEE. +The command buffer format for the different TEE commands can be found in [2]. + +The TEE commands supported by AMD-TEE Trusted OS are: + +* TEE_CMD_ID_LOAD_TA - loads a Trusted Application (TA) binary into + TEE environment. +* TEE_CMD_ID_UNLOAD_TA - unloads TA binary from TEE environment. +* TEE_CMD_ID_OPEN_SESSION - opens a session with a loaded TA. +* TEE_CMD_ID_CLOSE_SESSION - closes session with loaded TA +* TEE_CMD_ID_INVOKE_CMD - invokes a command with loaded TA +* TEE_CMD_ID_MAP_SHARED_MEM - maps shared memory +* TEE_CMD_ID_UNMAP_SHARED_MEM - unmaps shared memory + +AMD-TEE Trusted OS is the firmware running on AMD Secure Processor. + +The AMD-TEE driver registers itself with TEE subsystem and implements the +following driver function callbacks: + +* get_version - returns the driver implementation id and capability. +* open - sets up the driver context data structure. +* release - frees up driver resources. +* open_session - loads the TA binary and opens session with loaded TA. +* close_session - closes session with loaded TA and unloads it. +* invoke_func - invokes a command with loaded TA. + +cancel_req driver callback is not supported by AMD-TEE. + +The GlobalPlatform TEE Client API [3] can be used by the user space (client) to +talk to AMD's TEE. AMD's TEE provides a secure environment for loading, opening +a session, invoking commands and closing session with TA. + +References +========== + +[1] include/linux/psp-tee.h + +[2] drivers/tee/amdtee/amdtee_if.h + +[3] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. diff --git a/Documentation/tee/index.rst b/Documentation/tee/index.rst new file mode 100644 index 000000000000..a23bd08847e5 --- /dev/null +++ b/Documentation/tee/index.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +TEE Subsystem +============= + +.. toctree:: + :maxdepth: 1 + + tee + op-tee + amd-tee + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/tee/op-tee.rst b/Documentation/tee/op-tee.rst new file mode 100644 index 000000000000..b0ac097d5547 --- /dev/null +++ b/Documentation/tee/op-tee.rst @@ -0,0 +1,166 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================================================== +OP-TEE (Open Portable Trusted Execution Environment) +==================================================== + +The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM +TrustZone based OP-TEE solution that is supported. + +Lowest level of communication with OP-TEE builds on ARM SMC Calling +Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface +[3] used internally by the driver. Stacked on top of that is OP-TEE Message +Protocol [4]. + +OP-TEE SMC interface provides the basic functions required by SMCCC and some +additional functions specific for OP-TEE. The most interesting functions are: + +- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information + which is then returned by TEE_IOC_VERSION + +- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used + to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a + separate secure co-processor. + +- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol + +- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory + range to used for shared memory between Linux and OP-TEE. + +The GlobalPlatform TEE Client API [5] is implemented on top of the generic +TEE API. + +Picture of the relationship between the different components in the +OP-TEE architecture:: + + User space Kernel Secure world + ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ + +--------+ +-------------+ + | Client | | Trusted | + +--------+ | Application | + /\ +-------------+ + || +----------+ /\ + || |tee- | || + || |supplicant| \/ + || +----------+ +-------------+ + \/ /\ | TEE Internal| + +-------+ || | API | + + TEE | || +--------+--------+ +-------------+ + | Client| || | TEE | OP-TEE | | OP-TEE | + | API | \/ | subsys | driver | | Trusted OS | + +-------+----------------+----+-------+----+-----------+-------------+ + | Generic TEE API | | OP-TEE MSG | + | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | + +-----------------------------+ +------------------------------+ + +RPC (Remote Procedure Call) are requests from secure world to kernel driver +or tee-supplicant. An RPC is identified by a special range of SMCCC return +values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the +kernel are handled by the kernel driver. Other RPC messages will be forwarded to +tee-supplicant without further involvement of the driver, except switching +shared memory buffer representation. + +OP-TEE device enumeration +------------------------- + +OP-TEE provides a pseudo Trusted Application: drivers/tee/optee/device.c in +order to support device enumeration. In other words, OP-TEE driver invokes this +application to retrieve a list of Trusted Applications which can be registered +as devices on the TEE bus. + +OP-TEE notifications +-------------------- + +There are two kinds of notifications that secure world can use to make +normal world aware of some event. + +1. Synchronous notifications delivered with ``OPTEE_RPC_CMD_NOTIFICATION`` + using the ``OPTEE_RPC_NOTIFICATION_SEND`` parameter. +2. Asynchronous notifications delivered with a combination of a non-secure + edge-triggered interrupt and a fast call from the non-secure interrupt + handler. + +Synchronous notifications are limited by depending on RPC for delivery, +this is only usable when secure world is entered with a yielding call via +``OPTEE_SMC_CALL_WITH_ARG``. This excludes such notifications from secure +world interrupt handlers. + +An asynchronous notification is delivered via a non-secure edge-triggered +interrupt to an interrupt handler registered in the OP-TEE driver. The +actual notification value are retrieved with the fast call +``OPTEE_SMC_GET_ASYNC_NOTIF_VALUE``. Note that one interrupt can represent +multiple notifications. + +One notification value ``OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF`` has a +special meaning. When this value is received it means that normal world is +supposed to make a yielding call ``OPTEE_MSG_CMD_DO_BOTTOM_HALF``. This +call is done from the thread assisting the interrupt handler. This is a +building block for OP-TEE OS in secure world to implement the top half and +bottom half style of device drivers. + +OPTEE_INSECURE_LOAD_IMAGE Kconfig option +---------------------------------------- + +The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the +BL32 OP-TEE image from the kernel after the kernel boots, rather than loading +it from the firmware before the kernel boots. This also requires enabling the +corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm +documentation [6] explains the security threat associated with enabling this as +well as mitigations at the firmware and platform level. + +There are additional attack vectors/mitigations for the kernel that should be +addressed when using this option. + +1. Boot chain security. + + * Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of + the system. + + * Mitigation: There must be boot chain security that verifies the kernel and + rootfs, otherwise an attacker can modify the loaded OP-TEE binary by + modifying it in the rootfs. + +2. Alternate boot modes. + + * Attack vector: Using an alternate boot mode (i.e. recovery mode), the + OP-TEE driver isn't loaded, leaving the SMC hole open. + + * Mitigation: If there are alternate methods of booting the device, such as a + recovery mode, it should be ensured that the same mitigations are applied + in that mode. + +3. Attacks prior to SMC invocation. + + * Attack vector: Code that is executed prior to issuing the SMC call to load + OP-TEE can be exploited to then load an alternate OS image. + + * Mitigation: The OP-TEE driver must be loaded before any potential attack + vectors are opened up. This should include mounting of any modifiable + filesystems, opening of network ports or communicating with external + devices (e.g. USB). + +4. Blocking SMC call to load OP-TEE. + + * Attack vector: Prevent the driver from being probed, so the SMC call to + load OP-TEE isn't executed when desired, leaving it open to being executed + later and loading a modified OS. + + * Mitigation: It is recommended to build the OP-TEE driver as builtin driver + rather than as a module to prevent exploits that may cause the module to + not be loaded. + +References +========== + +[1] https://github.com/OP-TEE/optee_os + +[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + +[3] drivers/tee/optee/optee_smc.h + +[4] drivers/tee/optee/optee_msg.h + +[5] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. + +[6] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html diff --git a/Documentation/tee/tee.rst b/Documentation/tee/tee.rst new file mode 100644 index 000000000000..fd9f8c4ff63d --- /dev/null +++ b/Documentation/tee/tee.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +TEE (Trusted Execution Environment) +=================================== + +This document describes the TEE subsystem in Linux. + +Overview +======== + +A TEE is a trusted OS running in some secure environment, for example, +TrustZone on ARM CPUs, or a separate secure co-processor etc. A TEE driver +handles the details needed to communicate with the TEE. + +This subsystem deals with: + +- Registration of TEE drivers + +- Managing shared memory between Linux and the TEE + +- Providing a generic API to the TEE diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst index bf8d2ee01580..93174ffc7350 100644 --- a/Documentation/userspace-api/index.rst +++ b/Documentation/userspace-api/index.rst @@ -30,6 +30,7 @@ place where this information is gathered. sysfs-platform_profile vduse futex2 + tee .. only:: subproject and html diff --git a/Documentation/userspace-api/tee.rst b/Documentation/userspace-api/tee.rst new file mode 100644 index 000000000000..e2368dbc3451 --- /dev/null +++ b/Documentation/userspace-api/tee.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. tee: + +================================================== +TEE (Trusted Execution Environment) Userspace API +================================================== + +include/uapi/linux/tee.h defines the generic interface to a TEE. + +User space (the client) connects to the driver by opening /dev/tee[0-9]* or +/dev/teepriv[0-9]*. + +- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor + which user space can mmap. When user space doesn't need the file + descriptor any more, it should be closed. When shared memory isn't needed + any longer it should be unmapped with munmap() to allow the reuse of + memory. + +- TEE_IOC_VERSION lets user space know which TEE this driver handles and + its capabilities. + +- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. + +- TEE_IOC_INVOKE invokes a function in a Trusted Application. + +- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. + +- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. + +There are two classes of clients, normal clients and supplicants. The latter is +a helper process for the TEE to access resources in Linux, for example file +system access. A normal client opens /dev/tee[0-9]* and a supplicant opens +/dev/teepriv[0-9]. + +Much of the communication between clients and the TEE is opaque to the +driver. The main job for the driver is to receive requests from the +clients, forward them to the TEE and send back the results. In the case of +supplicants the communication goes in the other direction, the TEE sends +requests to the supplicant which then sends back the result. diff --git a/MAINTAINERS b/MAINTAINERS index 48fc02d3a1d1..6024d1d5ebf8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21351,7 +21351,9 @@ M: Jens Wiklander R: Sumit Garg L: op-tee@lists.trustedfirmware.org S: Maintained -F: Documentation/staging/tee.rst +F: Documentation/driver-api/tee.rst +F: Documentation/tee/ +F: Documentation/userspace-api/tee.rst F: drivers/tee/ F: include/linux/tee_drv.h F: include/uapi/linux/tee.h diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 70898bbd5809..976928641aa6 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -23,4 +23,4 @@ config OPTEE_INSECURE_LOAD_IMAGE https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html Additional documentation on kernel security risks are at - Documentation/staging/tee.rst. + Documentation/tee/op-tee.rst. From 2a0b726b0419b0c1c5a32e7c3336285e69e65fd6 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Fri, 8 Dec 2023 14:08:29 -0800 Subject: [PATCH 3419/7721] clang-format: Add maple tree's for_each macros Add maple tree's for_each macros so clang-format operates correctly on {mt,mas}_for_each. Signed-off-by: Elliot Berman Link: https://lore.kernel.org/r/20231208-clang-format-mt-for-each-v1-1-b4b73186b886@quicinc.com [ Sorted properly. ] Signed-off-by: Miguel Ojeda --- .clang-format | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clang-format b/.clang-format index 0bbb1991defe..2ee89fe6a3d1 100644 --- a/.clang-format +++ b/.clang-format @@ -494,12 +494,14 @@ ForEachMacros: - 'map_for_each_metric' - 'maps__for_each_entry' - 'maps__for_each_entry_safe' + - 'mas_for_each' - 'mci_for_each_dimm' - 'media_device_for_each_entity' - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' - 'msi_for_each_desc' + - 'mt_for_each' - 'nanddev_io_for_each_page' - 'netdev_for_each_lower_dev' - 'netdev_for_each_lower_private' From 5a205c6a9f79d14db38006aa2d7c4f4e76b1bfc7 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 8 Dec 2023 23:52:07 +0100 Subject: [PATCH 3420/7721] clang-format: Update with v6.7-rc4's `for_each` macro list Re-run the shell fragment that generated the original list. Signed-off-by: Miguel Ojeda --- .clang-format | 90 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/.clang-format b/.clang-format index 2ee89fe6a3d1..ccc9b93972a9 100644 --- a/.clang-format +++ b/.clang-format @@ -82,11 +82,16 @@ ForEachMacros: - '__for_each_thread' - '__hlist_for_each_rcu' - '__map__for_each_symbol_by_name' + - '__pci_bus_for_each_res0' + - '__pci_bus_for_each_res1' + - '__pci_dev_for_each_res0' + - '__pci_dev_for_each_res1' - '__perf_evlist__for_each_entry' - '__perf_evlist__for_each_entry_reverse' - '__perf_evlist__for_each_entry_safe' - '__rq_for_each_bio' - '__shost_for_each_device' + - '__sym_for_each' - 'apei_estatus_for_each_section' - 'ata_for_each_dev' - 'ata_for_each_link' @@ -105,13 +110,12 @@ ForEachMacros: - 'bip_for_each_vec' - 'bond_for_each_slave' - 'bond_for_each_slave_rcu' - - 'bpf__perf_for_each_map' - - 'bpf__perf_for_each_map_named' + - 'bpf_for_each' + - 'bpf_for_each_reg_in_vstate' + - 'bpf_for_each_reg_in_vstate_mask' - 'bpf_for_each_spilled_reg' - 'bpf_object__for_each_map' - 'bpf_object__for_each_program' - - 'bpf_object__for_each_safe' - - 'bpf_perf_object__for_each' - 'btree_for_each_safe128' - 'btree_for_each_safe32' - 'btree_for_each_safe64' @@ -119,6 +123,7 @@ ForEachMacros: - 'card_for_each_dev' - 'cgroup_taskset_for_each' - 'cgroup_taskset_for_each_leader' + - 'cpu_aggr_map__for_each_idx' - 'cpufreq_for_each_efficient_entry_idx' - 'cpufreq_for_each_entry' - 'cpufreq_for_each_entry_idx' @@ -128,11 +133,14 @@ ForEachMacros: - 'css_for_each_descendant_post' - 'css_for_each_descendant_pre' - 'damon_for_each_region' + - 'damon_for_each_region_from' - 'damon_for_each_region_safe' - 'damon_for_each_scheme' - 'damon_for_each_scheme_safe' - 'damon_for_each_target' - 'damon_for_each_target_safe' + - 'damos_for_each_filter' + - 'damos_for_each_filter_safe' - 'data__for_each_file' - 'data__for_each_file_new' - 'data__for_each_file_start' @@ -151,6 +159,8 @@ ForEachMacros: - 'drm_client_for_each_connector_iter' - 'drm_client_for_each_modeset' - 'drm_connector_for_each_possible_encoder' + - 'drm_exec_for_each_locked_object' + - 'drm_exec_for_each_locked_object_reverse' - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' @@ -162,22 +172,32 @@ ForEachMacros: - 'drm_for_each_plane' - 'drm_for_each_plane_mask' - 'drm_for_each_privobj' + - 'drm_gem_for_each_gpuva' + - 'drm_gem_for_each_gpuva_safe' + - 'drm_gpuva_for_each_op' + - 'drm_gpuva_for_each_op_from_reverse' + - 'drm_gpuva_for_each_op_safe' + - 'drm_gpuvm_for_each_va' + - 'drm_gpuvm_for_each_va_range' + - 'drm_gpuvm_for_each_va_range_safe' + - 'drm_gpuvm_for_each_va_safe' - 'drm_mm_for_each_hole' - 'drm_mm_for_each_node' - 'drm_mm_for_each_node_in_range' - 'drm_mm_for_each_node_safe' - 'dsa_switch_for_each_available_port' - 'dsa_switch_for_each_cpu_port' + - 'dsa_switch_for_each_cpu_port_continue_reverse' - 'dsa_switch_for_each_port' - 'dsa_switch_for_each_port_continue_reverse' - 'dsa_switch_for_each_port_safe' - 'dsa_switch_for_each_user_port' + - 'dsa_tree_for_each_cpu_port' - 'dsa_tree_for_each_user_port' + - 'dsa_tree_for_each_user_port_continue_reverse' - 'dso__for_each_symbol' - 'dsos__for_each_with_build_id' - 'elf_hash_for_each_possible' - - 'elf_section__for_each_rel' - - 'elf_section__for_each_rela' - 'elf_symtab__for_each_symbol' - 'evlist__for_each_cpu' - 'evlist__for_each_entry' @@ -186,12 +206,15 @@ ForEachMacros: - 'evlist__for_each_entry_reverse' - 'evlist__for_each_entry_safe' - 'flow_action_for_each' + - 'for_each_acpi_consumer_dev' - 'for_each_acpi_dev_match' - 'for_each_active_dev_scope' - 'for_each_active_drhd_unit' - 'for_each_active_iommu' - 'for_each_active_route' - 'for_each_aggr_pgid' + - 'for_each_and_bit' + - 'for_each_andnot_bit' - 'for_each_available_child_of_node' - 'for_each_bench' - 'for_each_bio' @@ -222,10 +245,13 @@ ForEachMacros: - 'for_each_compatible_node' - 'for_each_component_dais' - 'for_each_component_dais_safe' + - 'for_each_conduit' - 'for_each_console' - 'for_each_console_srcu' - 'for_each_cpu' - 'for_each_cpu_and' + - 'for_each_cpu_andnot' + - 'for_each_cpu_or' - 'for_each_cpu_wrap' - 'for_each_dapm_widgets' - 'for_each_dedup_cand' @@ -254,9 +280,11 @@ ForEachMacros: - 'for_each_free_mem_range' - 'for_each_free_mem_range_reverse' - 'for_each_func_rsrc' - - 'for_each_group_device' + - 'for_each_gpiochip_node' - 'for_each_group_evsel' + - 'for_each_group_evsel_head' - 'for_each_group_member' + - 'for_each_group_member_head' - 'for_each_hstate' - 'for_each_if' - 'for_each_inject_fn' @@ -273,6 +301,7 @@ ForEachMacros: - 'for_each_lru' - 'for_each_matching_node' - 'for_each_matching_node_and_match' + - 'for_each_media_entity_data_link' - 'for_each_mem_pfn_range' - 'for_each_mem_range' - 'for_each_mem_range_rev' @@ -281,6 +310,8 @@ ForEachMacros: - 'for_each_memory' - 'for_each_migratetype_order' - 'for_each_missing_reg' + - 'for_each_mle_subelement' + - 'for_each_mod_mem_type' - 'for_each_net' - 'for_each_net_continue_reverse' - 'for_each_net_rcu' @@ -288,6 +319,7 @@ ForEachMacros: - 'for_each_netdev_continue' - 'for_each_netdev_continue_rcu' - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_dump' - 'for_each_netdev_feature' - 'for_each_netdev_in_bond_rcu' - 'for_each_netdev_rcu' @@ -308,6 +340,7 @@ ForEachMacros: - 'for_each_node_with_cpus' - 'for_each_node_with_property' - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_numa_hop_mask' - 'for_each_of_allnodes' - 'for_each_of_allnodes_from' - 'for_each_of_cpu_node' @@ -326,6 +359,7 @@ ForEachMacros: - 'for_each_online_cpu' - 'for_each_online_node' - 'for_each_online_pgdat' + - 'for_each_or_bit' - 'for_each_path' - 'for_each_pci_bridge' - 'for_each_pci_dev' @@ -333,6 +367,7 @@ ForEachMacros: - 'for_each_physmem_range' - 'for_each_populated_zone' - 'for_each_possible_cpu' + - 'for_each_present_blessed_reg' - 'for_each_present_cpu' - 'for_each_prime_number' - 'for_each_prime_number_from' @@ -348,7 +383,8 @@ ForEachMacros: - 'for_each_property_of_node' - 'for_each_reg' - 'for_each_reg_filtered' - - 'for_each_registered_fb' + - 'for_each_reloc' + - 'for_each_reloc_from' - 'for_each_requested_gpio' - 'for_each_requested_gpio_in_range' - 'for_each_reserved_mem_range' @@ -357,10 +393,12 @@ ForEachMacros: - 'for_each_rtd_components' - 'for_each_rtd_cpu_dais' - 'for_each_rtd_dais' + - 'for_each_sband_iftype_data' - 'for_each_script' - 'for_each_sec' - 'for_each_set_bit' - 'for_each_set_bit_from' + - 'for_each_set_bit_wrap' - 'for_each_set_bitrange' - 'for_each_set_bitrange_from' - 'for_each_set_clump8' @@ -371,8 +409,8 @@ ForEachMacros: - 'for_each_sgtable_dma_sg' - 'for_each_sgtable_page' - 'for_each_sgtable_sg' - - 'for_each_shell_test' - 'for_each_sibling_event' + - 'for_each_sta_active_link' - 'for_each_subelement' - 'for_each_subelement_extid' - 'for_each_subelement_id' @@ -380,10 +418,15 @@ ForEachMacros: - 'for_each_subsystem' - 'for_each_supported_activate_fn' - 'for_each_supported_inject_fn' + - 'for_each_sym' - 'for_each_test' - 'for_each_thread' - 'for_each_token' - 'for_each_unicast_dest_pgid' + - 'for_each_valid_link' + - 'for_each_vif_active_link' + - 'for_each_vma' + - 'for_each_vma_range' - 'for_each_vsi' - 'for_each_wakeup_source' - 'for_each_zone' @@ -392,10 +435,12 @@ ForEachMacros: - 'func_for_each_insn' - 'fwnode_for_each_available_child_node' - 'fwnode_for_each_child_node' + - 'fwnode_for_each_parent_node' - 'fwnode_graph_for_each_endpoint' - 'gadget_for_each_ep' - 'genradix_for_each' - 'genradix_for_each_from' + - 'genradix_for_each_reverse' - 'hash_for_each' - 'hash_for_each_possible' - 'hash_for_each_possible_rcu' @@ -439,14 +484,9 @@ ForEachMacros: - 'in_dev_for_each_ifa_rcu' - 'in_dev_for_each_ifa_rtnl' - 'inet_bind_bucket_for_each' - - 'inet_lhash2_for_each_icsk' - - 'inet_lhash2_for_each_icsk_continue' - - 'inet_lhash2_for_each_icsk_rcu' - - 'interval_tree_for_each_double_span' - 'interval_tree_for_each_span' - 'intlist__for_each_entry' - 'intlist__for_each_entry_safe' - - 'iopt_for_each_contig_area' - 'kcore_copy__for_each_phdr' - 'key_for_each' - 'key_for_each_safe' @@ -483,15 +523,16 @@ ForEachMacros: - 'list_for_each_from' - 'list_for_each_prev' - 'list_for_each_prev_safe' + - 'list_for_each_rcu' + - 'list_for_each_reverse' - 'list_for_each_safe' - 'llist_for_each' - 'llist_for_each_entry' - 'llist_for_each_entry_safe' - 'llist_for_each_safe' + - 'lwq_for_each_safe' - 'map__for_each_symbol' - 'map__for_each_symbol_by_name' - - 'map_for_each_event' - - 'map_for_each_metric' - 'maps__for_each_entry' - 'maps__for_each_entry_safe' - 'mas_for_each' @@ -500,6 +541,11 @@ ForEachMacros: - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' + - 'media_entity_for_each_pad' + - 'media_pipeline_for_each_entity' + - 'media_pipeline_for_each_pad' + - 'mlx5_lag_for_each_peer_mdev' + - 'msi_domain_for_each_desc' - 'msi_for_each_desc' - 'mt_for_each' - 'nanddev_io_for_each_page' @@ -507,6 +553,8 @@ ForEachMacros: - 'netdev_for_each_lower_private' - 'netdev_for_each_lower_private_rcu' - 'netdev_for_each_mc_addr' + - 'netdev_for_each_synced_mc_addr' + - 'netdev_for_each_synced_uc_addr' - 'netdev_for_each_uc_addr' - 'netdev_for_each_upper_dev_rcu' - 'netdev_hw_addr_list_for_each' @@ -531,6 +579,7 @@ ForEachMacros: - 'perf_config_sections__for_each_entry' - 'perf_config_set__for_each_entry' - 'perf_cpu_map__for_each_cpu' + - 'perf_cpu_map__for_each_idx' - 'perf_evlist__for_each_entry' - 'perf_evlist__for_each_entry_reverse' - 'perf_evlist__for_each_entry_safe' @@ -540,9 +589,7 @@ ForEachMacros: - 'perf_hpp_list__for_each_format_safe' - 'perf_hpp_list__for_each_sort_list' - 'perf_hpp_list__for_each_sort_list_safe' - - 'perf_pmu__for_each_hybrid_pmu' - - 'ping_portaddr_for_each_entry' - - 'ping_portaddr_for_each_entry_rcu' + - 'perf_tool_event__for_each_event' - 'plist_for_each' - 'plist_for_each_continue' - 'plist_for_each_entry' @@ -579,6 +626,7 @@ ForEachMacros: - 'rq_for_each_segment' - 'rq_list_for_each' - 'rq_list_for_each_safe' + - 'sample_read_group__for_each' - 'scsi_for_each_prot_sg' - 'scsi_for_each_sg' - 'sctp_for_each_hentry' @@ -586,10 +634,12 @@ ForEachMacros: - 'sec_for_each_insn' - 'sec_for_each_insn_continue' - 'sec_for_each_insn_from' + - 'sec_for_each_sym' - 'shdma_for_each_chan' - 'shost_for_each_device' - 'sk_for_each' - 'sk_for_each_bound' + - 'sk_for_each_bound_bhash2' - 'sk_for_each_entry_offset_rcu' - 'sk_for_each_from' - 'sk_for_each_rcu' @@ -611,6 +661,8 @@ ForEachMacros: - 'tb_property_for_each' - 'tcf_act_for_each_action' - 'tcf_exts_for_each_action' + - 'ttm_resource_manager_for_each_res' + - 'twsk_for_each_bound_bhash2' - 'udp_portaddr_for_each_entry' - 'udp_portaddr_for_each_entry_rcu' - 'usb_hub_for_each_child' From bf17b36ccdd5b7b9dd482d7753bcb9aff2d21d39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Dec 2023 17:21:23 +0100 Subject: [PATCH 3421/7721] net: sysfs: fix locking in carrier read My previous patch added a call to linkwatch_sync_dev(), but that of course needs to be called under RTNL, which I missed earlier, but now saw RCU warnings from. Fix that by acquiring the RTNL in a similar fashion to how other files do it here. Fixes: facd15dfd691 ("net: core: synchronize link-watch when carrier is queried") Signed-off-by: Johannes Berg Link: https://lore.kernel.org/r/20231206172122.859df6ba937f.I9c80608bcfbab171943ff4942b52dbd5e97fe06e@changeid Signed-off-by: Jakub Kicinski --- net/core/net-sysfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index d9b33e923b18..a09d507c5b03 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -193,6 +193,10 @@ static ssize_t carrier_show(struct device *dev, struct device_attribute *attr, char *buf) { struct net_device *netdev = to_net_dev(dev); + int ret = -EINVAL; + + if (!rtnl_trylock()) + return restart_syscall(); if (netif_running(netdev)) { /* Synchronize carrier state with link watch, @@ -200,10 +204,11 @@ static ssize_t carrier_show(struct device *dev, */ linkwatch_sync_dev(netdev); - return sysfs_emit(buf, fmt_dec, !!netif_carrier_ok(netdev)); + ret = sysfs_emit(buf, fmt_dec, !!netif_carrier_ok(netdev)); } + rtnl_unlock(); - return -EINVAL; + return ret; } static DEVICE_ATTR_RW(carrier); From 1720c42b90c8f14ffcb2f2f39a1abafc82a5b22e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 8 Dec 2023 15:30:28 -0800 Subject: [PATCH 3422/7721] selftests/bpf: fix timer/test_bad_ret subtest on test_progs-cpuv4 flavor Because test_bad_ret main program is not written in assembly, we don't control instruction indices in timer_cb_ret_bad() subprog. This bites us in timer/test_bad_ret subtest, where we see difference between cpuv4 and other flavors. For now, make __msg() expectations not rely on instruction indices by anchoring them around bpf_get_prandom_u32 call. Once we have regex/glob support for __msg(), this can be expressed a bit more nicely, but for now just mitigating the problem with available means. Fixes: e02dea158dda ("selftests/bpf: validate async callback return value check correctness") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20231208233028.3412690-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/timer_failure.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c index 9fbc69c77bbb..0996c2486f05 100644 --- a/tools/testing/selftests/bpf/progs/timer_failure.c +++ b/tools/testing/selftests/bpf/progs/timer_failure.c @@ -47,9 +47,10 @@ __log_level(2) __flag(BPF_F_TEST_STATE_FREQ) __failure /* check that fallthrough code path marks r0 as precise */ -__msg("mark_precise: frame0: regs=r0 stack= before 22: (b7) r0 = 0") +__msg("mark_precise: frame0: regs=r0 stack= before") +__msg(": (85) call bpf_get_prandom_u32#7") /* anchor message */ /* check that branch code path marks r0 as precise */ -__msg("mark_precise: frame0: regs=r0 stack= before 24: (85) call bpf_get_prandom_u32#7") +__msg("mark_precise: frame0: regs=r0 stack= before ") __msg(": (85) call bpf_get_prandom_u32#7") __msg("should have been in [0, 0]") long BPF_PROG2(test_bad_ret, int, a) { From 73d9eb340d2b95e0e86a656a7f3157c137f10129 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Wed, 6 Dec 2023 11:53:24 +0000 Subject: [PATCH 3423/7721] bpf: Enable bpf_cgrp_storage for cgroup1 non-attach case In the current cgroup1 environment, associating operations between cgroups and applications in a BPF program requires storing a mapping of cgroup_id to application either in a hash map or maintaining it in userspace. However, by enabling bpf_cgrp_storage for cgroup1, it becomes possible to conveniently store application-specific information in cgroup-local storage and utilize it within BPF programs. Furthermore, enabling this feature for cgroup1 involves minor modifications for the non-attach case, streamlining the process. However, when it comes to enabling this functionality for the cgroup1 attach case, it presents challenges. Therefore, the decision is to focus on enabling it solely for the cgroup1 non-attach case at present. If attempting to attach to a cgroup1 fd, the operation will simply fail with the error code -EBADF. Signed-off-by: Yafang Shao Acked-by: Tejun Heo Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231206115326.4295-2-laoar.shao@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_cgrp_storage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c index d44fe8dd9732..28efd0a3f220 100644 --- a/kernel/bpf/bpf_cgrp_storage.c +++ b/kernel/bpf/bpf_cgrp_storage.c @@ -82,7 +82,7 @@ static void *bpf_cgrp_storage_lookup_elem(struct bpf_map *map, void *key) int fd; fd = *(int *)key; - cgroup = cgroup_get_from_fd(fd); + cgroup = cgroup_v1v2_get_from_fd(fd); if (IS_ERR(cgroup)) return ERR_CAST(cgroup); @@ -101,7 +101,7 @@ static long bpf_cgrp_storage_update_elem(struct bpf_map *map, void *key, int fd; fd = *(int *)key; - cgroup = cgroup_get_from_fd(fd); + cgroup = cgroup_v1v2_get_from_fd(fd); if (IS_ERR(cgroup)) return PTR_ERR(cgroup); @@ -131,7 +131,7 @@ static long bpf_cgrp_storage_delete_elem(struct bpf_map *map, void *key) int err, fd; fd = *(int *)key; - cgroup = cgroup_get_from_fd(fd); + cgroup = cgroup_v1v2_get_from_fd(fd); if (IS_ERR(cgroup)) return PTR_ERR(cgroup); From f4199271dae12ae407fa739e7012914ea6b3f37b Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Wed, 6 Dec 2023 11:53:25 +0000 Subject: [PATCH 3424/7721] selftests/bpf: Add a new cgroup helper open_classid() This new helper allows us to obtain the fd of a net_cls cgroup, which will be utilized in the subsequent patch. Signed-off-by: Yafang Shao Acked-by: Tejun Heo Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231206115326.4295-3-laoar.shao@gmail.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/cgroup_helpers.c | 16 ++++++++++++++++ tools/testing/selftests/bpf/cgroup_helpers.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 5aa133bf3688..19be9c63d5e8 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -689,3 +689,19 @@ int get_cgroup1_hierarchy_id(const char *subsys_name) fclose(file); return found ? id : -1; } + +/** + * open_classid() - Open a cgroupv1 net_cls classid + * + * This function expects the cgroup work dir to be already created, as we + * open it here. + * + * On success, it returns the file descriptor. On failure it returns -1. + */ +int open_classid(void) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_classid_path(cgroup_workdir); + return open(cgroup_workdir, O_RDONLY); +} diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index ee053641c026..502845160d88 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -33,6 +33,7 @@ void cleanup_cgroup_environment(void); int set_classid(void); int join_classid(void); unsigned long long get_classid_cgroup_id(void); +int open_classid(void); int setup_classid_environment(void); void cleanup_classid_environment(void); From a2c6380b17b6339bfedc98d253b6d85e7014953b Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Wed, 6 Dec 2023 11:53:26 +0000 Subject: [PATCH 3425/7721] selftests/bpf: Add selftests for cgroup1 local storage Expanding the test coverage from cgroup2 to include cgroup1. The result as follows, Already existing test cases for cgroup2: #48/1 cgrp_local_storage/tp_btf:OK #48/2 cgrp_local_storage/attach_cgroup:OK #48/3 cgrp_local_storage/recursion:OK #48/4 cgrp_local_storage/negative:OK #48/5 cgrp_local_storage/cgroup_iter_sleepable:OK #48/6 cgrp_local_storage/yes_rcu_lock:OK #48/7 cgrp_local_storage/no_rcu_lock:OK Expanded test cases for cgroup1: #48/8 cgrp_local_storage/cgrp1_tp_btf:OK #48/9 cgrp_local_storage/cgrp1_recursion:OK #48/10 cgrp_local_storage/cgrp1_negative:OK #48/11 cgrp_local_storage/cgrp1_iter_sleepable:OK #48/12 cgrp_local_storage/cgrp1_yes_rcu_lock:OK #48/13 cgrp_local_storage/cgrp1_no_rcu_lock:OK Summary: #48 cgrp_local_storage:OK Summary: 1/13 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Yafang Shao Acked-by: Tejun Heo Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231206115326.4295-4-laoar.shao@gmail.com Signed-off-by: Martin KaFai Lau --- .../bpf/prog_tests/cgrp_local_storage.c | 98 ++++++++++++++++- .../selftests/bpf/progs/cgrp_ls_recursion.c | 92 ++++++++++++---- .../selftests/bpf/progs/cgrp_ls_sleepable.c | 61 +++++++++-- .../selftests/bpf/progs/cgrp_ls_tp_btf.c | 100 ++++++++++++------ 4 files changed, 291 insertions(+), 60 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c index 63e776f4176e..747761572098 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c @@ -19,6 +19,21 @@ struct socket_cookie { __u64 cookie_value; }; +static bool is_cgroup1; +static int target_hid; + +#define CGROUP_MODE_SET(skel) \ +{ \ + skel->bss->is_cgroup1 = is_cgroup1; \ + skel->bss->target_hid = target_hid; \ +} + +static void cgroup_mode_value_init(bool cgroup, int hid) +{ + is_cgroup1 = cgroup; + target_hid = hid; +} + static void test_tp_btf(int cgroup_fd) { struct cgrp_ls_tp_btf *skel; @@ -29,6 +44,8 @@ static void test_tp_btf(int cgroup_fd) if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) return; + CGROUP_MODE_SET(skel); + /* populate a value in map_b */ err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY); if (!ASSERT_OK(err, "map_update_elem")) @@ -130,6 +147,8 @@ static void test_recursion(int cgroup_fd) if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) return; + CGROUP_MODE_SET(skel); + err = cgrp_ls_recursion__attach(skel); if (!ASSERT_OK(err, "skel_attach")) goto out; @@ -165,6 +184,8 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); + bpf_program__set_autoload(skel->progs.cgroup_iter, true); err = cgrp_ls_sleepable__load(skel); if (!ASSERT_OK(err, "skel_load")) @@ -202,6 +223,7 @@ static void test_yes_rcu_lock(__u64 cgroup_id) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); skel->bss->target_pid = syscall(SYS_gettid); bpf_program__set_autoload(skel->progs.yes_rcu_lock, true); @@ -229,6 +251,8 @@ static void test_no_rcu_lock(void) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); + bpf_program__set_autoload(skel->progs.no_rcu_lock, true); err = cgrp_ls_sleepable__load(skel); ASSERT_ERR(err, "skel_load"); @@ -236,7 +260,25 @@ static void test_no_rcu_lock(void) cgrp_ls_sleepable__destroy(skel); } -void test_cgrp_local_storage(void) +static void test_cgrp1_no_rcu_lock(void) +{ + struct cgrp_ls_sleepable *skel; + int err; + + skel = cgrp_ls_sleepable__open(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + CGROUP_MODE_SET(skel); + + bpf_program__set_autoload(skel->progs.cgrp1_no_rcu_lock, true); + err = cgrp_ls_sleepable__load(skel); + ASSERT_OK(err, "skel_load"); + + cgrp_ls_sleepable__destroy(skel); +} + +static void cgrp2_local_storage(void) { __u64 cgroup_id; int cgroup_fd; @@ -245,6 +287,8 @@ void test_cgrp_local_storage(void) if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage")) return; + cgroup_mode_value_init(0, -1); + cgroup_id = get_cgroup_id("/cgrp_local_storage"); if (test__start_subtest("tp_btf")) test_tp_btf(cgroup_fd); @@ -263,3 +307,55 @@ void test_cgrp_local_storage(void) close(cgroup_fd); } + +static void cgrp1_local_storage(void) +{ + int cgrp1_fd, cgrp1_hid, cgrp1_id, err; + + /* Setup cgroup1 hierarchy */ + err = setup_classid_environment(); + if (!ASSERT_OK(err, "setup_classid_environment")) + return; + + err = join_classid(); + if (!ASSERT_OK(err, "join_cgroup1")) + goto cleanup; + + cgrp1_fd = open_classid(); + if (!ASSERT_GE(cgrp1_fd, 0, "cgroup1 fd")) + goto cleanup; + + cgrp1_id = get_classid_cgroup_id(); + if (!ASSERT_GE(cgrp1_id, 0, "cgroup1 id")) + goto close_fd; + + cgrp1_hid = get_cgroup1_hierarchy_id("net_cls"); + if (!ASSERT_GE(cgrp1_hid, 0, "cgroup1 hid")) + goto close_fd; + + cgroup_mode_value_init(1, cgrp1_hid); + + if (test__start_subtest("cgrp1_tp_btf")) + test_tp_btf(cgrp1_fd); + if (test__start_subtest("cgrp1_recursion")) + test_recursion(cgrp1_fd); + if (test__start_subtest("cgrp1_negative")) + test_negative(); + if (test__start_subtest("cgrp1_iter_sleepable")) + test_cgroup_iter_sleepable(cgrp1_fd, cgrp1_id); + if (test__start_subtest("cgrp1_yes_rcu_lock")) + test_yes_rcu_lock(cgrp1_id); + if (test__start_subtest("cgrp1_no_rcu_lock")) + test_cgrp1_no_rcu_lock(); + +close_fd: + close(cgrp1_fd); +cleanup: + cleanup_classid_environment(); +} + +void test_cgrp_local_storage(void) +{ + cgrp2_local_storage(); + cgrp1_local_storage(); +} diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c index a043d8fefdac..610c2427fd93 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c @@ -21,50 +21,100 @@ struct { __type(value, long); } map_b SEC(".maps"); +int target_hid = 0; +bool is_cgroup1 = 0; + +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static void __on_lookup(struct cgroup *cgrp) +{ + bpf_cgrp_storage_delete(&map_a, cgrp); + bpf_cgrp_storage_delete(&map_b, cgrp); +} + SEC("fentry/bpf_local_storage_lookup") int BPF_PROG(on_lookup) { struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; - bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp); - bpf_cgrp_storage_delete(&map_b, task->cgroups->dfl_cgrp); + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_lookup(cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_lookup(task->cgroups->dfl_cgrp); return 0; } +static void __on_update(struct cgroup *cgrp) +{ + long *ptr; + + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + *ptr += 1; + + ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + *ptr += 1; +} + SEC("fentry/bpf_local_storage_update") int BPF_PROG(on_update) { struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; + + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_update(cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_update(task->cgroups->dfl_cgrp); + return 0; +} + +static void __on_enter(struct pt_regs *regs, long id, struct cgroup *cgrp) +{ long *ptr; - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) - *ptr += 1; + *ptr = 200; - ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) - *ptr += 1; - - return 0; + *ptr = 100; } SEC("tp_btf/sys_enter") int BPF_PROG(on_enter, struct pt_regs *regs, long id) { - struct task_struct *task; - long *ptr; + struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; - task = bpf_get_current_task_btf(); - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (ptr) - *ptr = 200; + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; - ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (ptr) - *ptr = 100; + __on_enter(regs, id, cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_enter(regs, id, task->cgroups->dfl_cgrp); return 0; } diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c index 4c7844e1dbfa..facedd8b8250 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c @@ -17,7 +17,11 @@ struct { __u32 target_pid; __u64 cgroup_id; +int target_hid; +bool is_cgroup1; +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; @@ -37,23 +41,50 @@ int cgroup_iter(struct bpf_iter__cgroup *ctx) return 0; } +static void __no_rcu_lock(struct cgroup *cgrp) +{ + long *ptr; + + /* Note that trace rcu is held in sleepable prog, so we can use + * bpf_cgrp_storage_get() in sleepable prog. + */ + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + cgroup_id = cgrp->kn->id; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int cgrp1_no_rcu_lock(void *ctx) +{ + struct task_struct *task; + struct cgroup *cgrp; + + task = bpf_get_current_task_btf(); + if (task->pid != target_pid) + return 0; + + /* bpf_task_get_cgroup1 can work in sleepable prog */ + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __no_rcu_lock(cgrp); + bpf_cgroup_release(cgrp); + return 0; +} + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") int no_rcu_lock(void *ctx) { struct task_struct *task; - struct cgroup *cgrp; - long *ptr; task = bpf_get_current_task_btf(); if (task->pid != target_pid) return 0; /* task->cgroups is untrusted in sleepable prog outside of RCU CS */ - cgrp = task->cgroups->dfl_cgrp; - ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (ptr) - cgroup_id = cgrp->kn->id; + __no_rcu_lock(task->cgroups->dfl_cgrp); return 0; } @@ -68,6 +99,22 @@ int yes_rcu_lock(void *ctx) if (task->pid != target_pid) return 0; + if (is_cgroup1) { + bpf_rcu_read_lock(); + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) { + bpf_rcu_read_unlock(); + return 0; + } + + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + cgroup_id = cgrp->kn->id; + bpf_cgroup_release(cgrp); + bpf_rcu_read_unlock(); + return 0; + } + bpf_rcu_read_lock(); cgrp = task->cgroups->dfl_cgrp; /* cgrp is trusted under RCU CS */ diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c b/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c index 9ebb8e2fe541..1c348f000f38 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c @@ -27,62 +27,100 @@ pid_t target_pid = 0; int mismatch_cnt = 0; int enter_cnt = 0; int exit_cnt = 0; +int target_hid = 0; +bool is_cgroup1 = 0; + +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static void __on_enter(struct pt_regs *regs, long id, struct cgroup *cgrp) +{ + long *ptr; + int err; + + /* populate value 0 */ + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!ptr) + return; + + /* delete value 0 */ + err = bpf_cgrp_storage_delete(&map_a, cgrp); + if (err) + return; + + /* value is not available */ + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, 0); + if (ptr) + return; + + /* re-populate the value */ + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!ptr) + return; + __sync_fetch_and_add(&enter_cnt, 1); + *ptr = MAGIC_VALUE + enter_cnt; +} SEC("tp_btf/sys_enter") int BPF_PROG(on_enter, struct pt_regs *regs, long id) { struct task_struct *task; - long *ptr; - int err; + struct cgroup *cgrp; task = bpf_get_current_task_btf(); if (task->pid != target_pid) return 0; - /* populate value 0 */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (!ptr) - return 0; + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; - /* delete value 0 */ - err = bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp); - if (err) + __on_enter(regs, id, cgrp); + bpf_cgroup_release(cgrp); return 0; + } - /* value is not available */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, 0); - if (ptr) - return 0; - - /* re-populate the value */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (!ptr) - return 0; - __sync_fetch_and_add(&enter_cnt, 1); - *ptr = MAGIC_VALUE + enter_cnt; - + __on_enter(regs, id, task->cgroups->dfl_cgrp); return 0; } +static void __on_exit(struct pt_regs *regs, long id, struct cgroup *cgrp) +{ + long *ptr; + + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!ptr) + return; + + __sync_fetch_and_add(&exit_cnt, 1); + if (*ptr != MAGIC_VALUE + exit_cnt) + __sync_fetch_and_add(&mismatch_cnt, 1); +} + SEC("tp_btf/sys_exit") int BPF_PROG(on_exit, struct pt_regs *regs, long id) { struct task_struct *task; - long *ptr; + struct cgroup *cgrp; task = bpf_get_current_task_btf(); if (task->pid != target_pid) return 0; - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (!ptr) - return 0; + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; - __sync_fetch_and_add(&exit_cnt, 1); - if (*ptr != MAGIC_VALUE + exit_cnt) - __sync_fetch_and_add(&mismatch_cnt, 1); + __on_exit(regs, id, cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_exit(regs, id, task->cgroups->dfl_cgrp); return 0; } From 32fa058398624166dd04ff4af49cfef69c94abbc Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Fri, 8 Dec 2023 21:51:00 +0000 Subject: [PATCH 3426/7721] libbpf: Add pr_warn() for EINVAL cases in linker_sanity_check_elf Before the change on `i686-linux` `systemd` build failed as: $ bpftool gen object src/core/bpf/socket_bind/socket-bind.bpf.o src/core/bpf/socket_bind/socket-bind.bpf.unstripped.o Error: failed to link 'src/core/bpf/socket_bind/socket-bind.bpf.unstripped.o': Invalid argument (22) After the change it fails as: $ bpftool gen object src/core/bpf/socket_bind/socket-bind.bpf.o src/core/bpf/socket_bind/socket-bind.bpf.unstripped.o libbpf: ELF section #9 has inconsistent alignment addr=8 != d=4 in src/core/bpf/socket_bind/socket-bind.bpf.unstripped.o Error: failed to link 'src/core/bpf/socket_bind/socket-bind.bpf.unstripped.o': Invalid argument (22) Now it's slightly easier to figure out what is wrong with an ELF file. Signed-off-by: Sergei Trofimovich Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20231208215100.435876-1-slyich@gmail.com --- tools/lib/bpf/linker.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index 5ced96d99f8c..52a2901e8bd0 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -719,13 +719,25 @@ static int linker_sanity_check_elf(struct src_obj *obj) return -EINVAL; } - if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) + if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) { + pr_warn("ELF section #%zu alignment %llu is non pow-of-2 alignment in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign, + obj->filename); return -EINVAL; - if (sec->shdr->sh_addralign != sec->data->d_align) + } + if (sec->shdr->sh_addralign != sec->data->d_align) { + pr_warn("ELF section #%zu has inconsistent alignment addr=%llu != d=%llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign, + (long long unsigned)sec->data->d_align, obj->filename); return -EINVAL; + } - if (sec->shdr->sh_size != sec->data->d_size) + if (sec->shdr->sh_size != sec->data->d_size) { + pr_warn("ELF section #%zu has inconsistent section size sh=%llu != d=%llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_size, + (long long unsigned)sec->data->d_size, obj->filename); return -EINVAL; + } switch (sec->shdr->sh_type) { case SHT_SYMTAB: @@ -737,8 +749,12 @@ static int linker_sanity_check_elf(struct src_obj *obj) break; case SHT_PROGBITS: if (sec->shdr->sh_flags & SHF_EXECINSTR) { - if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) + if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) { + pr_warn("ELF section #%zu has unexpected size alignment %llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_size, + obj->filename); return -EINVAL; + } } break; case SHT_NOBITS: From a3c205d0560f63ff02516b6d9fc3348dc34251c8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Dec 2023 20:13:22 +0000 Subject: [PATCH 3427/7721] ipv6: do not check fib6_has_expires() in fib6_info_release() My prior patch went a bit too far, because apparently fib6_has_expires() could be true while f6i->gc_link is not hashed yet. fib6_set_expires_locked() can indeed set RTF_EXPIRES while f6i->fib6_table is NULL. Original syzbot reports were about corruptions caused by dangling f6i->gc_link. Fixes: 5a08d0065a91 ("ipv6: add debug checks in fib6_info_release()") Reported-by: syzbot+c15aa445274af8674f41@syzkaller.appspotmail.com Signed-off-by: Eric Dumazet Cc: Kui-Feng Lee Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231207201322.549000-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/ip6_fib.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index e1e7a894863a..95ed495c3a40 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -329,7 +329,6 @@ static inline bool fib6_info_hold_safe(struct fib6_info *f6i) static inline void fib6_info_release(struct fib6_info *f6i) { if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) { - DEBUG_NET_WARN_ON_ONCE(fib6_has_expires(f6i)); DEBUG_NET_WARN_ON_ONCE(!hlist_unhashed(&f6i->gc_link)); call_rcu(&f6i->rcu, fib6_info_destroy_rcu); } From 6128becaeafa876048bd1b6a83d836329e4940c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Sep 2023 18:24:49 +0300 Subject: [PATCH 3428/7721] drm/i915: Stop accessing crtc->state from the flip done irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assuming crtc->state is pointing at the correct thing for the async flip commit is nonsense. If we had already queued up multiple commits this would point at the very lates crtc state even if the older commits hadn't even happened yet. Instead properly stage/arm the event like we do for async flips. Since we don't need to arm multiple of these at the same time we don't need a list like the normal vblank even processing uses. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230928152450.30109-1-ville.syrjala@linux.intel.com Reviewed-by: Arun R Murthy --- drivers/gpu/drm/i915/display/intel_crtc.c | 9 ++++++++- drivers/gpu/drm/i915/display/intel_display_irq.c | 9 ++++----- drivers/gpu/drm/i915/display/intel_display_types.h | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 1fd068e6e26c..8a84a31c7b48 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -553,8 +553,15 @@ void intel_pipe_update_start(struct intel_atomic_state *state, intel_psr_lock(new_crtc_state); - if (new_crtc_state->do_async_flip) + if (new_crtc_state->do_async_flip) { + spin_lock_irq(&crtc->base.dev->event_lock); + /* arm the event for the flip done irq handler */ + crtc->flip_done_event = new_crtc_state->uapi.event; + spin_unlock_irq(&crtc->base.dev->event_lock); + + new_crtc_state->uapi.event = NULL; return; + } if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index f8ed53f30b2e..6f2b45cfcf72 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -340,16 +340,15 @@ static void flip_done_handler(struct drm_i915_private *i915, enum pipe pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe); - struct drm_crtc_state *crtc_state = crtc->base.state; - struct drm_pending_vblank_event *e = crtc_state->event; struct drm_device *dev = &i915->drm; unsigned long irqflags; spin_lock_irqsave(&dev->event_lock, irqflags); - crtc_state->event = NULL; - - drm_crtc_send_vblank_event(&crtc->base, e); + if (crtc->flip_done_event) { + drm_crtc_send_vblank_event(&crtc->base, crtc->flip_done_event); + crtc->flip_done_event = NULL; + } spin_unlock_irqrestore(&dev->event_lock, irqflags); } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 2616bb6267a1..341d80c2b9de 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1475,6 +1475,9 @@ struct intel_crtc { struct intel_crtc_state *config; + /* armed event for async flip */ + struct drm_pending_vblank_event *flip_done_event; + /* Access to these should be protected by dev_priv->irq_lock. */ bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; From 362a8dba85ebedbf6939dad78bc6de398a2ef4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Sep 2023 18:24:50 +0300 Subject: [PATCH 3429/7721] drm/i915: Drop irqsave/restore for flip_done_handler() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since flip_done_handler() is always called from the irq handler we can skip the irqsave/restore dance. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230928152450.30109-2-ville.syrjala@linux.intel.com Reviewed-by: Arun R Murthy --- drivers/gpu/drm/i915/display/intel_display_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 6f2b45cfcf72..a7d8f3fc98de 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -340,17 +340,15 @@ static void flip_done_handler(struct drm_i915_private *i915, enum pipe pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe); - struct drm_device *dev = &i915->drm; - unsigned long irqflags; - spin_lock_irqsave(&dev->event_lock, irqflags); + spin_lock(&i915->drm.event_lock); if (crtc->flip_done_event) { drm_crtc_send_vblank_event(&crtc->base, crtc->flip_done_event); crtc->flip_done_event = NULL; } - spin_unlock_irqrestore(&dev->event_lock, irqflags); + spin_unlock(&i915->drm.event_lock); } static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, From c8a074789d71c1e26920f9333125590fac84f8c7 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Tue, 5 Dec 2023 15:38:55 +0100 Subject: [PATCH 3430/7721] arm64: dts: qcom: sc7280: Add UFS nodes for sc7280 soc Add UFS host controller and PHY nodes for sc7280 soc. Signed-off-by: Nitin Rawat Reviewed-by: Konrad Dybcio Tested-by: Konrad Dybcio [luca: various cleanups and additions as written in the cover letter] Signed-off-by: Luca Weiss Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231205-sc7280-ufs-v6-2-ad6ca7796de7@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 73 +++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 0153bace1cf7..f5e5cc046954 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -912,7 +912,7 @@ gcc: clock-controller@100000 { clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, <0>, <&pcie1_phy>, - <0>, <0>, <0>, + <&ufs_mem_phy 0>, <&ufs_mem_phy 1>, <&ufs_mem_phy 2>, <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk", "pcie_0_pipe_clk", "pcie_1_pipe_clk", @@ -2244,6 +2244,77 @@ pcie1_phy: phy@1c0e000 { status = "disabled"; }; + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,sc7280-ufshc", "qcom,ufshc", + "jedec,ufs-2.0"; + reg = <0x0 0x01d84000 0x0 0x3000>; + interrupts = ; + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + power-domains = <&gcc GCC_UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x80 0x0>; + dma-coherent; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc2 SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ufs-ddr", "cpu-ufs"; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + freq-table-hz = + <75000000 300000000>, + <0 0>, + <0 0>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + status = "disabled"; + }; + + ufs_mem_phy: phy@1d87000 { + compatible = "qcom,sc7280-qmp-ufs-phy"; + reg = <0x0 0x01d87000 0x0 0xe00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&gcc GCC_UFS_1_CLKREF_EN>; + clock-names = "ref", "ref_aux", "qref"; + + power-domains = <&rpmhpd SC7280_MX>; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + ipa: ipa@1e40000 { compatible = "qcom,sc7280-ipa"; From 9b07340c55a8e918f2667fb911e9b2edc428793c Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Tue, 5 Dec 2023 15:38:56 +0100 Subject: [PATCH 3431/7721] arm64: dts: qcom: sc7280: Add UFS nodes for sc7280 IDP board Add UFS host controller and PHY nodes for sc7280 IDP board. Signed-off-by: Nitin Rawat Acked-by: Manivannan Sadhasivam Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231205-sc7280-ufs-v6-3-ad6ca7796de7@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280-idp.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi index 2ff549f4dc7a..a0059527d9e4 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi @@ -499,6 +499,25 @@ &uart5 { status = "okay"; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l7b_2p9>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; + vccq2-supply = <&vreg_l9b_1p2>; + vccq2-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c_0p8>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; From c9c8179d0ccdf024ce467b4c9cf5de8821bc02cb Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Sun, 3 Dec 2023 15:19:18 +0100 Subject: [PATCH 3432/7721] ARM: dts: qcom: Disable pm8941 & pm8226 smbb charger by default Some platforms don't use the built-in charging hardware (e.g. milletwifi). As this is an optional peripheral, default it to off. Keep it enabled for all other boards that use smbb. Signed-off-by: Bryant Mairs Signed-off-by: Luca Weiss Acked-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231203-smbb-pm8941-pm8226-v1-1-9ad75909604b@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8226.dtsi | 2 ++ arch/arm/boot/dts/qcom/pm8941.dtsi | 2 ++ arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts | 2 ++ arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts | 2 ++ arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts | 2 ++ arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts | 4 ++++ arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts | 2 ++ arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi | 2 ++ arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts | 2 ++ arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts | 4 ++++ .../dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts | 2 ++ 11 files changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/qcom/pm8226.dtsi b/arch/arm/boot/dts/qcom/pm8226.dtsi index 2413778f3715..2fd4f135ed84 100644 --- a/arch/arm/boot/dts/qcom/pm8226.dtsi +++ b/arch/arm/boot/dts/qcom/pm8226.dtsi @@ -82,6 +82,8 @@ smbb: charger@1000 { "usb-valid", "dc-valid"; + status = "disabled"; + chg_otg: otg-vbus { }; }; diff --git a/arch/arm/boot/dts/qcom/pm8941.dtsi b/arch/arm/boot/dts/qcom/pm8941.dtsi index ed0ba591c755..aca0052a02b7 100644 --- a/arch/arm/boot/dts/qcom/pm8941.dtsi +++ b/arch/arm/boot/dts/qcom/pm8941.dtsi @@ -99,6 +99,8 @@ smbb: charger@1000 { usb-otg-in-supply = <&pm8941_5vs1>; + status = "disabled"; + chg_otg: otg-vbus { }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts index a39f5a161b03..a2ca456012f1 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts @@ -253,6 +253,8 @@ &smbb { qcom,fast-charge-high-threshold-voltage = <4400000>; qcom,auto-recharge-threshold-voltage = <4300000>; qcom,minimum-input-voltage = <4400000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts index 59b218042d32..ac228965a485 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts @@ -335,6 +335,8 @@ &smbb { qcom,fast-charge-current-limit = <300000>; qcom,fast-charge-safe-current = <600000>; qcom,auto-recharge-threshold-voltage = <4240000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts index feb78afef3a6..0a1fd5eb3c6d 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts @@ -292,6 +292,8 @@ &smbb { qcom,fast-charge-high-threshold-voltage = <4350000>; qcom,auto-recharge-threshold-voltage = <4240000>; qcom,minimum-input-voltage = <4450000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts index d7fb3e0e8886..6fce0112361f 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts @@ -430,6 +430,10 @@ &sdhc_2 { pinctrl-1 = <&sdc2_off>; }; +&smbb { + status = "okay"; +}; + &tlmm { sdc1_on: sdc1-on-state { clk-pins { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts index 9e90330a6231..ed328b24335f 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts @@ -355,6 +355,8 @@ &smbb { qcom,fast-charge-high-threshold-voltage = <4350000>; qcom,auto-recharge-threshold-voltage = <4300000>; qcom,minimum-input-voltage = <4300000>; + + status = "okay"; }; &usb { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi index a43341ae4495..94cbad81379f 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi @@ -452,6 +452,8 @@ &smbb { qcom,fast-charge-low-threshold-voltage = <3400000>; qcom,auto-recharge-threshold-voltage = <4200000>; qcom,minimum-input-voltage = <4300000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts index 66c422004dcd..fe227fd3f908 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts @@ -408,6 +408,8 @@ &smbb { qcom,fast-charge-high-threshold-voltage = <4350000>; qcom,auto-recharge-threshold-voltage = <4240000>; qcom,minimum-input-voltage = <4450000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts index 6d1412aec45a..4c8edadea0ac 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts @@ -460,6 +460,10 @@ &sdhc_1 { status = "okay"; }; +&smbb { + status = "okay"; +}; + &tlmm { gpio_hall_sensor_default: gpio-hall-sensor-default-state { pins = "gpio68"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts index 818ff5835031..7c6fe442b559 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts @@ -585,6 +585,8 @@ &smbb { qcom,fast-charge-low-threshold-voltage = <3400000>; qcom,auto-recharge-threshold-voltage = <4200000>; qcom,minimum-input-voltage = <4300000>; + + status = "okay"; }; &tlmm { From fc209f869310776c437daba478246df64d82c38b Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 30 Nov 2023 21:35:20 +0100 Subject: [PATCH 3433/7721] ARM: dts: qcom: msm8226: Add GPU The msm8226 SoC contains an Adreno 305B. Add a node to configure it. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231130-msm8226-gpu-v1-3-6bb2f1b29e49@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8226.dtsi | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi index b9686e75fe1d..b492c95e5d30 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi @@ -1006,6 +1006,46 @@ mdss_dsi0_phy: phy@fd922a00 { "ref"; }; }; + + gpu: adreno@fdb00000 { + compatible = "qcom,adreno-305.18", "qcom,adreno"; + reg = <0xfdb00000 0x10000>; + reg-names = "kgsl_3d0_reg_memory"; + + interrupts = ; + interrupt-names = "kgsl_3d0_irq"; + + clocks = <&mmcc OXILI_GFX3D_CLK>, + <&mmcc OXILICX_AHB_CLK>, + <&mmcc OXILICX_AXI_CLK>; + clock-names = "core", "iface", "mem_iface"; + + sram = <&gmu_sram>; + power-domains = <&mmcc OXILICX_GDSC>; + operating-points-v2 = <&gpu_opp_table>; + + status = "disabled"; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-450000000 { + opp-hz = /bits/ 64 <450000000>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + }; + + opp-19000000 { + opp-hz = /bits/ 64 <19000000>; + }; + }; + }; }; thermal-zones { From 24187868e195202c67c38bcc3ae28f9c6a663fb4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 25 Nov 2023 13:19:27 +0100 Subject: [PATCH 3434/7721] arm64: dts: qcom: msm8953: Set initial address for memory The dtbs_check really doesn't like having memory without reg set. The base address depends on the amount of RAM you have: <= 2.00 GiB RAM: 0x80000000 = 3.00 GiB RAM: 0x40000000 = 3.75 GiB RAM: 0x10000000 (more does not fit into the 32-bit physical address space) So, let's pick one of the values, 0x10000000 which is used on devices with 3.75 GiB RAM. Since the bootloader will update it to what's present on the device it doesn't matter too much. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231125-msm8953-misc-fixes-v2-1-df86655841d9@z3ntu.xyz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 1a73bbbb43bc..ad2f8cf9c966 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -174,10 +174,10 @@ scm: scm { }; }; - memory { + memory@10000000 { device_type = "memory"; /* We expect the bootloader to fill in the reg */ - reg = <0 0 0 0>; + reg = <0 0x10000000 0 0>; }; pmu { From cad7c46ae2d75b42aa8f1e3f741b203ed796eee9 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 2 Oct 2023 14:30:41 +0200 Subject: [PATCH 3435/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Enable UFS Enable the UFS phy and controller so that we can access the internal storage of the phone. At the same time we need to bump the minimum voltage used for UFS VCC, otherwise it doesn't initialize properly. The 2.952V is taken from the vcc-voltage-level property downstream. See also the following link for more information about the VCCQ/VCCQ2: https://gerrit-public.fairphone.software/plugins/gitiles/kernel/msm-extra/devicetree/+/1590a3739e7dc29d2597307881553236d492f188/fp5/yupik-idp-pm7250b.dtsi#207 Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231002-fp5-ufs-v2-1-e2d7de522134@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index d0b1e4e507ff..85391bed6376 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -284,8 +284,9 @@ vreg_l6b: ldo6 { }; vreg_l7b: ldo7 { - regulator-min-microvolt = <2400000>; - regulator-max-microvolt = <3544000>; + /* Constrained for UFS VCC, at least until UFS driver scales voltage */ + regulator-min-microvolt = <2952000>; + regulator-max-microvolt = <2952000>; regulator-initial-mode = ; }; @@ -853,6 +854,28 @@ bluetooth: bluetooth { }; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b>; + vcc-max-microamp = <800000>; + /* + * Technically l9b enables an eLDO (supplied by s1b) which then powers + * VCCQ2 of the UFS. + */ + vccq-supply = <&vreg_l9b>; + vccq-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c>; + vdda-pll-supply = <&vreg_l6b>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; From 0bcbf092560cc1c163156af67176cbb4b8a327f9 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 8 Dec 2023 16:08:03 +0100 Subject: [PATCH 3436/7721] arm64: dts: qcom: sc7280: Use WPSS PAS instead of PIL The wpss-pil driver wants to manage too many resources that cannot be touched with standard Qualcomm firmware. Use the compatible from the PAS driver and move the ChromeOS-specific bits to sc7280-chrome-common.dtsi. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231208-sc7280-remoteprocs-v3-7-6aa394d33edf@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sc7280-chrome-common.dtsi | 19 ++++++++++++++++++- arch/arm64/boot/dts/qcom/sc7280.dtsi | 15 +++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 88fc67c3646e..9845638b344a 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -97,8 +97,25 @@ spi_flash: flash@0 { }; &remoteproc_wpss { - status = "okay"; + compatible = "qcom,sc7280-wpss-pil"; + clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, + <&gcc GCC_WPSS_AHB_CLK>, + <&gcc GCC_WPSS_RSCP_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ahb_bdg", + "ahb", + "rscp", + "xo"; + + resets = <&aoss_reset AOSS_CC_WCSS_RESTART>, + <&pdc_reset PDC_WPSS_SYNC_RESET>; + reset-names = "restart", "pdc_sync"; + + qcom,halt-regs = <&tcsr_1 0x17000>; + firmware-name = "ath11k/WCN6750/hw1.0/wpss.mdt"; + + status = "okay"; }; &scm { diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index f5e5cc046954..132b55e64579 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3594,7 +3594,7 @@ qspi: spi@88dc000 { }; remoteproc_wpss: remoteproc@8a00000 { - compatible = "qcom,sc7280-wpss-pil"; + compatible = "qcom,sc7280-wpss-pas"; reg = <0 0x08a00000 0 0x10000>; interrupts-extended = <&intc GIC_SPI 587 IRQ_TYPE_EDGE_RISING>, @@ -3606,12 +3606,8 @@ remoteproc_wpss: remoteproc@8a00000 { interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack", "shutdown-ack"; - clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, - <&gcc GCC_WPSS_AHB_CLK>, - <&gcc GCC_WPSS_RSCP_CLK>, - <&rpmhcc RPMH_CXO_CLK>; - clock-names = "ahb_bdg", "ahb", - "rscp", "xo"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; power-domains = <&rpmhpd SC7280_CX>, <&rpmhpd SC7280_MX>; @@ -3624,11 +3620,6 @@ remoteproc_wpss: remoteproc@8a00000 { qcom,smem-states = <&wpss_smp2p_out 0>; qcom,smem-state-names = "stop"; - resets = <&aoss_reset AOSS_CC_WCSS_RESTART>, - <&pdc_reset PDC_WPSS_SYNC_RESET>; - reset-names = "restart", "pdc_sync"; - - qcom,halt-regs = <&tcsr_1 0x17000>; status = "disabled"; From 3658e411efcbb4df882763b09ae49efaa86585b4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 8 Dec 2023 16:08:04 +0100 Subject: [PATCH 3437/7721] arm64: dts: qcom: sc7280: Add ADSP node Add the node for the ADSP found on the SC7280 SoC, using standard Qualcomm firmware. Acked-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231208-sc7280-remoteprocs-v3-8-6aa394d33edf@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 5 -- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 1 + arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 1 + .../boot/dts/qcom/sc7280-chrome-common.dtsi | 5 -- arch/arm64/boot/dts/qcom/sc7280.dtsi | 74 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 85391bed6376..7a8fdebd94d3 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -77,11 +77,6 @@ cont_splash_mem: cont-splash@e1000000 { no-map; }; - adsp_mem: adsp@86700000 { - reg = <0x0 0x86700000 0x0 0x2800000>; - no-map; - }; - cdsp_mem: cdsp@88f00000 { reg = <0x0 0x88f00000 0x0 0x1e00000>; no-map; diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 2a5631b0fa40..662b5f757542 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -13,6 +13,7 @@ /delete-node/ &ipa_fw_mem; /delete-node/ &rmtfs_mem; +/delete-node/ &adsp_mem; /delete-node/ &video_mem; /delete-node/ &wlan_ce_mem; /delete-node/ &xbl_mem; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index 0beab54c051e..c54b1ff8b857 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -19,6 +19,7 @@ /delete-node/ &ipa_fw_mem; /delete-node/ &remoteproc_mpss; /delete-node/ &rmtfs_mem; +/delete-node/ &adsp_mem; /delete-node/ &video_mem; /delete-node/ &wlan_ce_mem; /delete-node/ &xbl_mem; diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 9845638b344a..6e05bf024cc6 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -26,11 +26,6 @@ / { reserved-memory { - adsp_mem: memory@86700000 { - reg = <0x0 0x86700000 0x0 0x2800000>; - no-map; - }; - camera_mem: memory@8ad00000 { reg = <0x0 0x8ad00000 0x0 0x500000>; no-map; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 132b55e64579..91f009cd1a86 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -143,6 +143,11 @@ wlan_fw_mem: memory@80c00000 { no-map; }; + adsp_mem: adsp@86700000 { + reg = <0x0 0x86700000 0x0 0x2800000>; + no-map; + }; + video_mem: memory@8b200000 { reg = <0x0 0x8b200000 0x0 0x500000>; no-map; @@ -3593,6 +3598,75 @@ qspi: spi@88dc000 { status = "disabled"; }; + remoteproc_adsp: remoteproc@3700000 { + compatible = "qcom,sc7280-adsp-pas"; + reg = <0 0x03700000 0 0x100>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd SC7280_LCX>, + <&rpmhpd SC7280_LMX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&adsp_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "adsp"; + qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1803 0x0>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1804 0x0>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x1805 0x0>; + }; + }; + }; + }; + remoteproc_wpss: remoteproc@8a00000 { compatible = "qcom,sc7280-wpss-pas"; reg = <0 0x08a00000 0 0x10000>; From df62402e5ff9df1960622b4d7bc5dd43dc8e7b75 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 8 Dec 2023 16:08:05 +0100 Subject: [PATCH 3438/7721] arm64: dts: qcom: sc7280: Add CDSP node Add the node for the ADSP found on the SC7280 SoC, using standard Qualcomm firmware. Remove the reserved-memory node from sc7280-chrome-common since CDSP is currently not used there. Acked-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231208-sc7280-remoteprocs-v3-9-6aa394d33edf@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 1 + arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 1 + .../boot/dts/qcom/sc7280-chrome-common.dtsi | 6 + arch/arm64/boot/dts/qcom/sc7280.dtsi | 143 ++++++++++++++++++ 4 files changed, 151 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 662b5f757542..37c91fdf3ab9 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -14,6 +14,7 @@ /delete-node/ &ipa_fw_mem; /delete-node/ &rmtfs_mem; /delete-node/ &adsp_mem; +/delete-node/ &cdsp_mem; /delete-node/ &video_mem; /delete-node/ &wlan_ce_mem; /delete-node/ &xbl_mem; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index c54b1ff8b857..71179cbf22b5 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -20,6 +20,7 @@ /delete-node/ &remoteproc_mpss; /delete-node/ &rmtfs_mem; /delete-node/ &adsp_mem; +/delete-node/ &cdsp_mem; /delete-node/ &video_mem; /delete-node/ &wlan_ce_mem; /delete-node/ &xbl_mem; diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 6e05bf024cc6..854a16e018ef 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -17,6 +17,7 @@ * required by the setup for Chrome boards. */ +/delete-node/ &cdsp_mem; /delete-node/ &gpu_zap_mem; /delete-node/ &gpu_zap_shader; /delete-node/ &hyp_mem; @@ -91,6 +92,11 @@ spi_flash: flash@0 { }; }; +/* Currently not used */ +&remoteproc_cdsp { + /delete-property/ memory-region; +}; + &remoteproc_wpss { compatible = "qcom,sc7280-wpss-pil"; clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 91f009cd1a86..89d081aeed1a 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -153,6 +153,11 @@ video_mem: memory@8b200000 { no-map; }; + cdsp_mem: cdsp@88f00000 { + reg = <0x0 0x88f00000 0x0 0x1e00000>; + no-map; + }; + ipa_fw_mem: memory@8b700000 { reg = <0 0x8b700000 0 0x10000>; no-map; @@ -3835,6 +3840,144 @@ nsp_noc: interconnect@a0c0000 { qcom,bcm-voters = <&apps_bcm_voter>; }; + remoteproc_cdsp: remoteproc@a300000 { + compatible = "qcom,sc7280-cdsp-pas"; + reg = <0 0x0a300000 0 0x10000>; + + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd SC7280_CX>, + <&rpmhpd SC7280_MX>; + power-domain-names = "cx", "mx"; + + interconnects = <&nsp_noc MASTER_CDSP_PROC 0 &mc_virt SLAVE_EBI1 0>; + + memory-region = <&cdsp_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "cdsp"; + qcom,remote-pid = <5>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "cdsp"; + qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@1 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <1>; + iommus = <&apps_smmu 0x11a1 0x0420>, + <&apps_smmu 0x1181 0x0420>; + }; + + compute-cb@2 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <2>; + iommus = <&apps_smmu 0x11a2 0x0420>, + <&apps_smmu 0x1182 0x0420>; + }; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x11a3 0x0420>, + <&apps_smmu 0x1183 0x0420>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x11a4 0x0420>, + <&apps_smmu 0x1184 0x0420>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x11a5 0x0420>, + <&apps_smmu 0x1185 0x0420>; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + iommus = <&apps_smmu 0x11a6 0x0420>, + <&apps_smmu 0x1186 0x0420>; + }; + + compute-cb@7 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <7>; + iommus = <&apps_smmu 0x11a7 0x0420>, + <&apps_smmu 0x1187 0x0420>; + }; + + compute-cb@8 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <8>; + iommus = <&apps_smmu 0x11a8 0x0420>, + <&apps_smmu 0x1188 0x0420>; + }; + + /* note: secure cb9 in downstream */ + + compute-cb@11 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <11>; + iommus = <&apps_smmu 0x11ab 0x0420>, + <&apps_smmu 0x118b 0x0420>; + }; + + compute-cb@12 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <12>; + iommus = <&apps_smmu 0x11ac 0x0420>, + <&apps_smmu 0x118c 0x0420>; + }; + + compute-cb@13 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <13>; + iommus = <&apps_smmu 0x11ad 0x0420>, + <&apps_smmu 0x118d 0x0420>; + }; + + compute-cb@14 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <14>; + iommus = <&apps_smmu 0x11ae 0x0420>, + <&apps_smmu 0x118e 0x0420>; + }; + }; + }; + }; + usb_1: usb@a6f8800 { compatible = "qcom,sc7280-dwc3", "qcom,dwc3"; reg = <0 0x0a6f8800 0 0x400>; From 5ffc529fa5dfe428ab9a7866b58b964a376dd953 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 8 Dec 2023 16:08:06 +0100 Subject: [PATCH 3439/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Enable various remoteprocs Enable the ADSP, CDSP, MPSS and WPSS that are found on the SoC. Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231208-sc7280-remoteprocs-v3-10-6aa394d33edf@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 7a8fdebd94d3..f69aeb42db35 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -706,6 +706,26 @@ &qupv3_id_1 { status = "okay"; }; +&remoteproc_adsp { + firmware-name = "qcom/qcm6490/fairphone5/adsp.mbn"; + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/qcm6490/fairphone5/cdsp.mbn"; + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/qcm6490/fairphone5/modem.mbn"; + status = "okay"; +}; + +&remoteproc_wpss { + firmware-name = "qcom/qcm6490/fairphone5/wpss.mbn"; + status = "okay"; +}; + &sdc2_clk { drive-strength = <16>; bias-disable; From 16e84c137919dd91c1cb1102a3d536fce2d6ee94 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 8 Dec 2023 16:08:07 +0100 Subject: [PATCH 3440/7721] arm64: dts: qcom: qcm6490-fairphone-fp5: Enable WiFi Now that the WPSS remoteproc is enabled, enable wifi so we can use it. Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20231208-sc7280-remoteprocs-v3-11-6aa394d33edf@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index f69aeb42db35..fc228f2854d7 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -924,3 +924,8 @@ &usb_1_qmpphy { status = "okay"; }; + +&wifi { + qcom,ath11k-calibration-variant = "Fairphone_5"; + status = "okay"; +}; From 0d75bb6ae127f5e3fd0e2239714908fd2038193d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 Nov 2023 13:58:10 +0100 Subject: [PATCH 3441/7721] media: bttv: start_streaming should return a proper error code The start_streaming callback returned 0 or 1 instead of a proper error code. Fix that. Signed-off-by: Hans Verkuil Fixes: b7ec3212a73a ("media: bttv: convert to vb2") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 6 ++---- drivers/media/pci/bt8xx/bttv-vbi.c | 8 +++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 09a193bb87df..8e8c9dada67a 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1536,13 +1536,11 @@ static void buf_cleanup(struct vb2_buffer *vb) static int start_streaming(struct vb2_queue *q, unsigned int count) { - int ret = 1; int seqnr = 0; struct bttv_buffer *buf; struct bttv *btv = vb2_get_drv_priv(q); - ret = check_alloc_btres_lock(btv, RESOURCE_VIDEO_STREAM); - if (ret == 0) { + if (!check_alloc_btres_lock(btv, RESOURCE_VIDEO_STREAM)) { if (btv->field_count) seqnr++; while (!list_empty(&btv->capture)) { @@ -1553,7 +1551,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); } - return !ret; + return -EBUSY; } if (!vb2_is_streaming(&btv->vbiq)) { init_irqreg(btv); diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index ab213e51ec95..e489a3acb4b9 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -123,14 +123,12 @@ static void buf_cleanup_vbi(struct vb2_buffer *vb) static int start_streaming_vbi(struct vb2_queue *q, unsigned int count) { - int ret; int seqnr = 0; struct bttv_buffer *buf; struct bttv *btv = vb2_get_drv_priv(q); btv->framedrop = 0; - ret = check_alloc_btres_lock(btv, RESOURCE_VBI); - if (ret == 0) { + if (!check_alloc_btres_lock(btv, RESOURCE_VBI)) { if (btv->field_count) seqnr++; while (!list_empty(&btv->vcapture)) { @@ -141,13 +139,13 @@ static int start_streaming_vbi(struct vb2_queue *q, unsigned int count) vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); } - return !ret; + return -EBUSY; } if (!vb2_is_streaming(&btv->capq)) { init_irqreg(btv); btv->field_count = 0; } - return !ret; + return 0; } static void stop_streaming_vbi(struct vb2_queue *q) From 3f1faa154a4316b1b585a25394697504b3c24e98 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 Nov 2023 13:58:11 +0100 Subject: [PATCH 3442/7721] media: bttv: add back vbi hack The old (now removed) videobuf framework had an optional vbi hack where the sequence number of the frame counter was copied in the last 4 bytes of the buffer. This hack was active only for the read() interface (so not for streaming I/O), and it was enabled by bttv. This allowed applications that used read() for the VBI data to match it with the corresponding video frame. When bttv was converted to vb2 this hack was forgotten, but some old applications rely on this. So add this back, but this time in the bttv driver rather than in the vb2 framework. Signed-off-by: Hans Verkuil Fixes: b7ec3212a73a ("media: bttv: convert to vb2") Tested-by: Dr. David Alan Gilbert Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8e8c9dada67a..49a3dd70ec0f 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2772,6 +2772,27 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, return; wakeup->vbuf.vb2_buf.timestamp = ktime_get_ns(); wakeup->vbuf.sequence = btv->field_count >> 1; + + /* + * Ugly hack for backwards compatibility. + * Some applications expect that the last 4 bytes of + * the VBI data contains the sequence number. + * + * This makes it possible to associate the VBI data + * with the video frame if you use read() to get the + * VBI data. + */ + if (vb2_fileio_is_active(wakeup->vbuf.vb2_buf.vb2_queue)) { + u32 *vaddr = vb2_plane_vaddr(&wakeup->vbuf.vb2_buf, 0); + unsigned long size = + vb2_get_plane_payload(&wakeup->vbuf.vb2_buf, 0) / 4; + + if (vaddr && size) { + vaddr += size - 1; + *vaddr = wakeup->vbuf.sequence; + } + } + vb2_buffer_done(&wakeup->vbuf.vb2_buf, state); if (btv->field_count == 0) btor(BT848_INT_VSYNC, BT848_INT_MASK); From 350ab13e1382f2afcc2285041a1e75b80d771c2c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 Nov 2023 13:58:12 +0100 Subject: [PATCH 3443/7721] media: videobuf2: request more buffers for vb2_read The vb2 read support requests 1 buffer, leaving it to the driver to increase this number to something that works. Unfortunately, drivers do not deal with this reliably, and in fact this caused problems for the bttv driver and reading from /dev/vbiX, causing every other VBI frame to be all 0. Instead, request as the number of buffers whatever is the maximum of 2 and q->min_buffers_needed+1. In order to start streaming you need at least q->min_buffers_needed queued buffers, so add 1 buffer for processing. And if that field is 0, then choose 2 (again, one buffer is being filled while the other one is being processed). This certainly makes more sense than requesting just 1 buffer, and the VBI bttv support is now working again. It turns out that the old videobuf1 behavior of bttv was to allocate 8 (video) and 4 (vbi) buffers when used with read(). After the vb2 conversion that changed to 2 for both. With this patch it is 3, which is really all you need. Signed-off-by: Hans Verkuil Fixes: b7ec3212a73a ("media: bttv: convert to vb2") Tested-by: Dr. David Alan Gilbert Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 8c1df829745b..40d89f29fa33 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2735,9 +2735,14 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) return -EBUSY; /* - * Start with count 1, driver can increase it in queue_setup() + * Start with q->min_buffers_needed + 1, driver can increase it in + * queue_setup() + * + * 'min_buffers_needed' buffers need to be queued up before you + * can start streaming, plus 1 for userspace (or in this case, + * kernelspace) processing. */ - count = 1; + count = max(2, q->min_buffers_needed + 1); dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", (read) ? "read" : "write", count, q->fileio_read_once, From dba3e701917a4cce92920f8ccb9fa4d4ee5ac07e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 5 Sep 2023 17:29:52 +0200 Subject: [PATCH 3444/7721] media: uvcvideo: Fix power line control for a Chicony camera The device does not implement the control properly. Fixes v4l2-compliance error: info: checking control 'Power Line Frequency' (0x00980918) fail: v4l2-test-controls.cpp(552): could not set valid menu item 3 Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 08fcd2ffa727..4b5ea3501753 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2592,6 +2592,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Chicony Electronics Co., Ltd Integrated Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x04f2, + .idProduct = 0xb67c, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, /* Chicony EasyCamera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, From 323666d1b32315930f6f14175fc59f0853647881 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 20 Oct 2023 00:02:46 +0200 Subject: [PATCH 3445/7721] media: uvcvideo: Pick first best alternate setting insteed of last When selecting an alternate setting, the driver loops over all available alternate settings to find the one with the lowest bandwidth high enough for the selected format and resolution. While all alternate settings should have different packet sizes, some buggy devices report multiple alternate settings with the same size. The driver happens to pick the last one in this case. In theory this should work fine, but in real life we have device bugs. The Ali Corp. Newmine Camera (0402:8841) exposes four alternate settings with the same packet size. The first three seem to work fine, while selecting the last one results in lots of transmission errors. Switch to using the first best alternate setting when multiple are present. This should be safe (last famous words), as sniffing USB traffic with the faulty device shows that Windows 10 picks the first alternate setting, and devices are typically tested on Windows. Closes: https://lore.kernel.org/linux-media/Nh6D0WI--3-9@tutanota.com/ Reported-by: Karel Janda Suggested-by: Karel Janda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 28dde08ec6c5..7cbf4692bd87 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1954,7 +1954,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Check if the bandwidth is high enough. */ psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); - if (psize >= bandwidth && psize <= best_psize) { + if (psize >= bandwidth && psize < best_psize) { altsetting = alts->desc.bAlternateSetting; best_psize = psize; best_ep = ep; From 6180056b0e0c097dad5d1569dcd661eaf509ea43 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Sat, 28 Oct 2023 09:55:04 +0200 Subject: [PATCH 3446/7721] media: uvcvideo: Fix power line control for SunplusIT camera The device does not implement the power line frequency control correctly. It is a UVC 1.5 device, but implements the control as a UVC 1.1 device. Add the corresponding control mapping override. Bus 003 Device 002: ID 2b7e:b752 SunplusIT Inc HD Camera Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.01 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x2b7e idProduct 0xb752 bcdDevice 0.04 iManufacturer 1 SunplusIT Inc iProduct 2 HD Camera iSerial 3 01.00.00 bNumConfigurations 1 Cc: Yunke Cao Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 4b5ea3501753..bbd90123a4e7 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -3003,6 +3003,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, + /* SunplusIT Inc HD Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x2b7e, + .idProduct = 0xb752, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, /* Lenovo Integrated Camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, From 2a0ed5a3573b88e85d778e81d2be3c0fdf7a884d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 25 Jul 2023 21:14:45 +0200 Subject: [PATCH 3447/7721] media: imx: imx7-media-csi: Include headers explicitly Include all the headers that the driver needs explicitly instead of relying on indirect inclusion. While at it, drop a few unneeded headers. Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 651151da3ab4..f992ae671065 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -3,31 +3,46 @@ * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC * * Copyright (c) 2019 Linaro Ltd - * */ #include +#include +#include #include +#include +#include +#include #include +#include +#include +#include +#include #include -#include #include #include +#include #include -#include -#include #include -#include +#include #include #include +#include +#include #include +#include +#include +#include +#include +#include #include -#include +#include #include #include #include +#include #include +#include #define IMX7_CSI_PAD_SINK 0 #define IMX7_CSI_PAD_SRC 1 From 5705b0e0eb550ff834125a46a4ef99b62093d83d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 22 Nov 2023 16:21:34 +0100 Subject: [PATCH 3448/7721] media: imx-mipi-csis: Fix clock handling in remove() The driver always calls mipi_csis_runtime_suspend() and mipi_csis_clk_disable() in remove(). This causes multiple WARNs from the kernel, as the clocks get disabled too many times. Fix the remove() to call mipi_csis_runtime_suspend() and mipi_csis_clk_disable() in a way that reverses what is done in probe(). Link: https://lore.kernel.org/r/20231122-imx-csis-v2-1-e44b8dc4cb66@ideasonboard.com Fixes: 7807063b862b ("media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7") Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index b12e2435ef60..d952994fd5ff 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1506,8 +1506,10 @@ static void mipi_csis_remove(struct platform_device *pdev) v4l2_async_nf_cleanup(&csis->notifier); v4l2_async_unregister_subdev(&csis->sd); + if (!pm_runtime_enabled(&pdev->dev)) + mipi_csis_runtime_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); - mipi_csis_runtime_suspend(&pdev->dev); mipi_csis_clk_disable(csis); v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); From fb387fcb5cdd0384ba04a5d15a3605e2dccdab2a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 22 Nov 2023 16:21:35 +0100 Subject: [PATCH 3449/7721] media: imx-mipi-csis: Drop extra clock enable at probe() The driver always enables the clocks at probe() and disables them only at remove(). It is not clear why the driver does this, as it supports runtime PM, and enables and disables the clocks in the runtime resume and suspend callbacks. Also, in the case runtime PM is not available, the driver calls the resume and suspend callbacks manually from probe() and remove(). Drop the unnecessary clock enable, thus enabling the clocks only when actually needed. Link: https://lore.kernel.org/r/20231122-imx-csis-v2-2-e44b8dc4cb66@ideasonboard.com Fixes: 7807063b862b ("media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7") Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index d952994fd5ff..db8ff5f5c4d3 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1439,24 +1439,18 @@ static int mipi_csis_probe(struct platform_device *pdev) /* Reset PHY and enable the clocks. */ mipi_csis_phy_reset(csis); - ret = mipi_csis_clk_enable(csis); - if (ret < 0) { - dev_err(csis->dev, "failed to enable clocks: %d\n", ret); - return ret; - } - /* Now that the hardware is initialized, request the interrupt. */ ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); - goto err_disable_clock; + return ret; } /* Initialize and register the subdev. */ ret = mipi_csis_subdev_init(csis); if (ret < 0) - goto err_disable_clock; + return ret; platform_set_drvdata(pdev, &csis->sd); @@ -1490,8 +1484,6 @@ static int mipi_csis_probe(struct platform_device *pdev) v4l2_async_nf_unregister(&csis->notifier); v4l2_async_nf_cleanup(&csis->notifier); v4l2_async_unregister_subdev(&csis->sd); -err_disable_clock: - mipi_csis_clk_disable(csis); return ret; } @@ -1510,7 +1502,6 @@ static void mipi_csis_remove(struct platform_device *pdev) mipi_csis_runtime_suspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - mipi_csis_clk_disable(csis); v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); pm_runtime_set_suspended(&pdev->dev); From d80d227eb0f69c9bf5649c9b6c1c5cead14e5813 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 7 Dec 2023 12:09:18 +0100 Subject: [PATCH 3450/7721] media: nxp: imx8-isi-debug: Add missing 36-Bit DMA registers to debugfs output The extended address registers are missing in the debug output register list. These are only available on 36-Bit DMA platforms. Due to the prolonged name, the output width has to be adjusted as well. Link: https://lore.kernel.org/r/20231207110918.1338524-1-alexander.stein@ew.tq-group.com Signed-off-by: Alexander Stein Tested-by: Alexander Stein Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../platform/nxp/imx8-isi/imx8-isi-debug.c | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c index 6709ab7ea1f3..5e8a177da054 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c @@ -22,10 +22,11 @@ static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg) static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p) { #define MXC_ISI_DEBUG_REG(name) { name, #name } - static const struct { + struct debug_regs { u32 offset; const char * const name; - } registers[] = { + }; + static const struct debug_regs registers[] = { MXC_ISI_DEBUG_REG(CHNL_CTRL), MXC_ISI_DEBUG_REG(CHNL_IMG_CTRL), MXC_ISI_DEBUG_REG(CHNL_OUT_BUF_CTRL), @@ -67,6 +68,16 @@ static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p) MXC_ISI_DEBUG_REG(CHNL_SCL_IMG_CFG), MXC_ISI_DEBUG_REG(CHNL_FLOW_CTRL), }; + /* These registers contain the upper 4 bits of 36-bit DMA addresses. */ + static const struct debug_regs registers_36bit_dma[] = { + MXC_ISI_DEBUG_REG(CHNL_Y_BUF1_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_U_BUF1_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_V_BUF1_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_Y_BUF2_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_U_BUF2_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_V_BUF2_XTND_ADDR), + MXC_ISI_DEBUG_REG(CHNL_IN_BUF_XTND_ADDR), + }; struct mxc_isi_pipe *pipe = m->private; unsigned int i; @@ -77,10 +88,20 @@ static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p) seq_printf(m, "--- ISI pipe %u registers ---\n", pipe->id); for (i = 0; i < ARRAY_SIZE(registers); ++i) - seq_printf(m, "%20s[0x%02x]: 0x%08x\n", + seq_printf(m, "%21s[0x%02x]: 0x%08x\n", registers[i].name, registers[i].offset, mxc_isi_read(pipe, registers[i].offset)); + if (pipe->isi->pdata->has_36bit_dma) { + for (i = 0; i < ARRAY_SIZE(registers_36bit_dma); ++i) { + const struct debug_regs *reg = ®isters_36bit_dma[i]; + + seq_printf(m, "%21s[0x%02x]: 0x%08x\n", + reg->name, reg->offset, + mxc_isi_read(pipe, reg->offset)); + } + } + pm_runtime_put(pipe->isi->dev); return 0; From 25bf28b25a2afa1864b7143259443160d9163ea0 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Wed, 15 Nov 2023 17:44:07 +0100 Subject: [PATCH 3451/7721] media: dt-bindings: media: rkisp1: Fix the port description for the parallel interface The bus-type belongs to the endpoint's properties and should therefore be moved. Link: https://lore.kernel.org/r/20231115164407.99876-1-mehdi.djait@bootlin.com Fixes: 6a0eaa25bf36 ("media: dt-bindings: media: rkisp1: Add port for parallel interface") Signed-off-by: Mehdi Djait Acked-by: Conor Dooley Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index e466dff8286d..afcaa427d48b 100644 --- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -90,15 +90,16 @@ properties: description: connection point for input on the parallel interface properties: - bus-type: - enum: [5, 6] - endpoint: $ref: video-interfaces.yaml# unevaluatedProperties: false - required: - - bus-type + properties: + bus-type: + enum: [5, 6] + + required: + - bus-type anyOf: - required: From 452f604a4683654f4d9472b3126d8da61d748443 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 22 Nov 2023 16:50:07 +0100 Subject: [PATCH 3452/7721] media: rkisp1: Fix media device memory leak Add missing calls to media_device_cleanup() to fix memory leak. Link: https://lore.kernel.org/r/20231122-rkisp-fixes-v2-1-78bfb63cdcf8@ideasonboard.com Fixes: d65dd85281fb ("media: staging: rkisp1: add Rockchip ISP1 base driver") Reviewed-by: Tommaso Merciai Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index c41abd2833f1..894d5afaff4e 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -582,7 +582,7 @@ static int rkisp1_probe(struct platform_device *pdev) ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); if (ret) - goto err_pm_runtime_disable; + goto err_media_dev_cleanup; ret = media_device_register(&rkisp1->media_dev); if (ret) { @@ -617,6 +617,8 @@ static int rkisp1_probe(struct platform_device *pdev) media_device_unregister(&rkisp1->media_dev); err_unreg_v4l2_dev: v4l2_device_unregister(&rkisp1->v4l2_dev); +err_media_dev_cleanup: + media_device_cleanup(&rkisp1->media_dev); err_pm_runtime_disable: pm_runtime_disable(&pdev->dev); return ret; @@ -637,6 +639,8 @@ static void rkisp1_remove(struct platform_device *pdev) media_device_unregister(&rkisp1->media_dev); v4l2_device_unregister(&rkisp1->v4l2_dev); + media_device_cleanup(&rkisp1->media_dev); + pm_runtime_disable(&pdev->dev); } From 688f3af3c354adc19b78d352c8c7b2006f993f2d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 22 Nov 2023 16:50:08 +0100 Subject: [PATCH 3453/7721] media: rkisp1: Fix memory leaks in rkisp1_isp_unregister() Add missing call to v4l2_subdev_cleanup() to fix memory leak. Link: https://lore.kernel.org/r/20231122-rkisp-fixes-v2-2-78bfb63cdcf8@ideasonboard.com Fixes: 2cce0a369dbd ("media: rkisp1: isp: Use V4L2 subdev active state") Reviewed-by: Tommaso Merciai Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index ca6703bfd27b..6f8bd9a6fa6b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -938,6 +938,7 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) return; v4l2_device_unregister_subdev(&isp->sd); + v4l2_subdev_cleanup(&isp->sd); media_entity_cleanup(&isp->sd.entity); } From 85d2a31fe4d9be1555f621ead7a520d8791e0f74 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 7 Dec 2023 08:57:45 +0100 Subject: [PATCH 3454/7721] media: rkisp1: Drop IRQF_SHARED In all known platforms the ISP has dedicated IRQ lines, but for some reason the driver uses IRQF_SHARED. Supporting IRQF_SHARED properly requires handling interrupts even when our device is disabled, and the driver does not handle this. To avoid adding such code, and to be sure the driver won't accidentally be used in a platform with shared interrupts, let's drop the IRQF_SHARED flag. Link: https://lore.kernel.org/r/20231207-rkisp-irq-fix-v3-1-358a2c871a3c@ideasonboard.com Tested-by: Adam Ford #imx8mp-beacon Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 894d5afaff4e..b676db9bff62 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -542,7 +542,7 @@ static int rkisp1_probe(struct platform_device *pdev) if (irq < 0) return irq; - ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0, dev_driver_string(dev), dev); if (ret) { dev_err(dev, "request irq failed: %d\n", ret); From 3eb7910e1b16a2c136be26a8380f21469225b2f6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 7 Dec 2023 08:57:46 +0100 Subject: [PATCH 3455/7721] media: rkisp1: Fix IRQ handler return values The IRQ handler rkisp1_isr() calls sub-handlers, all of which returns an irqreturn_t value, but rkisp1_isr() ignores those values and always returns IRQ_HANDLED. Fix this by collecting the return values, and returning IRQ_HANDLED or IRQ_NONE as appropriate. Link: https://lore.kernel.org/r/20231207-rkisp-irq-fix-v3-2-358a2c871a3c@ideasonboard.com Tested-by: Adam Ford #imx8mp-beacon Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index b676db9bff62..7b8a361d4c4a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -442,17 +442,25 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1) static irqreturn_t rkisp1_isr(int irq, void *ctx) { + irqreturn_t ret = IRQ_NONE; + /* * Call rkisp1_capture_isr() first to handle the frame that * potentially completed using the current frame_sequence number before * it is potentially incremented by rkisp1_isp_isr() in the vertical * sync. */ - rkisp1_capture_isr(irq, ctx); - rkisp1_isp_isr(irq, ctx); - rkisp1_csi_isr(irq, ctx); - return IRQ_HANDLED; + if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + return ret; } static const char * const px30_isp_clks[] = { From 0753874617de883c6d4da903142f334f76a75d70 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 7 Dec 2023 08:57:47 +0100 Subject: [PATCH 3456/7721] media: rkisp1: Store IRQ lines Store the IRQ lines used by the driver for easy access. These are needed in future patches which fix IRQ race issues. Link: https://lore.kernel.org/r/20231207-rkisp-irq-fix-v3-3-358a2c871a3c@ideasonboard.com Tested-by: Adam Ford #imx8mp-beacon Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-common.h | 11 ++++++++++- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 17 +++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 1e7cea1bea5e..2d7f06281c39 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -61,6 +61,14 @@ struct dentry; RKISP1_CIF_ISP_EXP_END | \ RKISP1_CIF_ISP_HIST_MEASURE_RDY) +/* IRQ lines */ +enum rkisp1_irq_line { + RKISP1_IRQ_ISP = 0, + RKISP1_IRQ_MI, + RKISP1_IRQ_MIPI, + RKISP1_NUM_IRQS, +}; + /* enum for the resizer pads */ enum rkisp1_rsz_pad { RKISP1_RSZ_PAD_SINK, @@ -423,7 +431,6 @@ struct rkisp1_debug { * struct rkisp1_device - ISP platform device * * @base_addr: base register address - * @irq: the irq number * @dev: a pointer to the struct device * @clk_size: number of clocks * @clks: array of clocks @@ -441,6 +448,7 @@ struct rkisp1_debug { * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. * @debug: debug params to be exposed on debugfs * @info: version-specific ISP information + * @irqs: IRQ line numbers */ struct rkisp1_device { void __iomem *base_addr; @@ -461,6 +469,7 @@ struct rkisp1_device { struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ struct rkisp1_debug debug; const struct rkisp1_info *info; + int irqs[RKISP1_NUM_IRQS]; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 7b8a361d4c4a..f96f821a7b50 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -114,6 +114,7 @@ struct rkisp1_isr_data { const char *name; irqreturn_t (*isr)(int irq, void *ctx); + u32 line_mask; }; /* ---------------------------------------------------------------------------- @@ -471,9 +472,9 @@ static const char * const px30_isp_clks[] = { }; static const struct rkisp1_isr_data px30_isp_isrs[] = { - { "isp", rkisp1_isp_isr }, - { "mi", rkisp1_capture_isr }, - { "mipi", rkisp1_csi_isr }, + { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) }, + { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) }, + { "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) }, }; static const struct rkisp1_info px30_isp_info = { @@ -492,7 +493,7 @@ static const char * const rk3399_isp_clks[] = { }; static const struct rkisp1_isr_data rk3399_isp_isrs[] = { - { NULL, rkisp1_isr }, + { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) }, }; static const struct rkisp1_info rk3399_isp_info = { @@ -543,6 +544,9 @@ static int rkisp1_probe(struct platform_device *pdev) if (IS_ERR(rkisp1->base_addr)) return PTR_ERR(rkisp1->base_addr); + for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) + rkisp1->irqs[il] = -1; + for (i = 0; i < info->isr_size; i++) { irq = info->isrs[i].name ? platform_get_irq_byname(pdev, info->isrs[i].name) @@ -550,6 +554,11 @@ static int rkisp1_probe(struct platform_device *pdev) if (irq < 0) return irq; + for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { + if (info->isrs[i].line_mask & BIT(il)) + rkisp1->irqs[il] = irq; + } + ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0, dev_driver_string(dev), dev); if (ret) { From 870565f063a58576e8a4529f122cac4325c6b395 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 7 Dec 2023 08:57:48 +0100 Subject: [PATCH 3457/7721] media: rkisp1: Fix IRQ disable race issue In rkisp1_isp_stop() and rkisp1_csi_disable() the driver masks the interrupts and then apparently assumes that the interrupt handler won't be running, and proceeds in the stop procedure. This is not the case, as the interrupt handler can already be running, which would lead to the ISP being disabled while the interrupt handler handling a captured frame. This brings up two issues: 1) the ISP could be powered off while the interrupt handler is still running and accessing registers, leading to board lockup, and 2) the interrupt handler code and the code that disables the streaming might do things that conflict. It is not clear to me if 2) causes a real issue, but 1) can be seen with a suitable delay (or printk in my case) in the interrupt handler, leading to board lockup. Link: https://lore.kernel.org/r/20231207-rkisp-irq-fix-v3-4-358a2c871a3c@ideasonboard.com Tested-by: Adam Ford #imx8mp-beacon Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-csi.c | 14 ++++++++++++- .../platform/rockchip/rkisp1/rkisp1-isp.c | 20 ++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index e6642a2167ef..b6e47e2f1b94 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -125,8 +125,20 @@ static void rkisp1_csi_disable(struct rkisp1_csi *csi) struct rkisp1_device *rkisp1 = csi->rkisp1; u32 val; - /* Mask and clear interrupts. */ + /* Mask MIPI interrupts. */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0); + + /* Flush posted writes */ + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + + /* + * Wait until the IRQ handler has ended. The IRQ handler may get called + * even after this, but it will return immediately as the MIPI + * interrupts have been masked. + */ + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MIPI]); + + /* Clear MIPI interrupt status */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 6f8bd9a6fa6b..da313f87e248 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -254,11 +254,25 @@ static void rkisp1_isp_stop(struct rkisp1_isp *isp) * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> * Stop ISP(isp) ->wait for ISP isp off */ - /* stop and clear MI and ISP interrupts */ - rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); + /* Mask MI and ISP interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0); + + /* Flush posted writes */ + rkisp1_read(rkisp1, RKISP1_CIF_MI_IMSC); + + /* + * Wait until the IRQ handler has ended. The IRQ handler may get called + * even after this, but it will return immediately as the MI and ISP + * interrupts have been masked. + */ + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_ISP]); + if (rkisp1->irqs[RKISP1_IRQ_ISP] != rkisp1->irqs[RKISP1_IRQ_MI]) + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MI]); + + /* Clear MI and ISP interrupt status */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0); /* stop ISP */ From 02f2c7b457273495d408814eb90a01289b31b0ea Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Fri, 1 Dec 2023 15:04:30 +0100 Subject: [PATCH 3458/7721] media: rkisp1: regs: Consolidate MI interrupt wrap fields Consolidate the wraparound fields in the memory interface interrupt status registers, so that it can be more succinctly expressed by taking the stream ID (main or self) as a parameter. Link: https://lore.kernel.org/r/20231201140433.2126011-2-paul.elder@ideasonboard.com Signed-off-by: Paul Elder Reviewed-by: Kieran Bingham Reviewed-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 350f452e676f..bea69a0d766a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -172,12 +172,9 @@ #define RKISP1_CIF_MI_FRAME(stream) BIT((stream)->id) #define RKISP1_CIF_MI_MBLK_LINE BIT(2) #define RKISP1_CIF_MI_FILL_MP_Y BIT(3) -#define RKISP1_CIF_MI_WRAP_MP_Y BIT(4) -#define RKISP1_CIF_MI_WRAP_MP_CB BIT(5) -#define RKISP1_CIF_MI_WRAP_MP_CR BIT(6) -#define RKISP1_CIF_MI_WRAP_SP_Y BIT(7) -#define RKISP1_CIF_MI_WRAP_SP_CB BIT(8) -#define RKISP1_CIF_MI_WRAP_SP_CR BIT(9) +#define RKISP1_CIF_MI_WRAP_Y(stream) BIT(4 + (stream)->id * 3) +#define RKISP1_CIF_MI_WRAP_CB(stream) BIT(5 + (stream)->id * 3) +#define RKISP1_CIF_MI_WRAP_CR(stream) BIT(6 + (stream)->id * 3) #define RKISP1_CIF_MI_DMA_READY BIT(11) /* MI_STATUS */ From adf1cba7c85f0be01125573fbfd83aff43464607 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Fri, 1 Dec 2023 15:04:31 +0100 Subject: [PATCH 3459/7721] media: rkisp1: debug: Add register dump for IS Add register dump for the ISP image stabilizer module to debugfs. This helps debugging issues related to digital zoom. Link: https://lore.kernel.org/r/20231201140433.2126011-3-paul.elder@ideasonboard.com Signed-off-by: Paul Elder Tested-by: Alexander Stein Reviewed-by: Kieran Bingham Reviewed-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c index 71df3dc95e6f..d2fbed42164e 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c @@ -92,6 +92,10 @@ static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p) RKISP1_DEBUG_REG(ISP_FLAGS_SHD), RKISP1_DEBUG_REG(ISP_RIS), RKISP1_DEBUG_REG(ISP_ERR), + RKISP1_DEBUG_SHD_REG(ISP_IS_H_OFFS), + RKISP1_DEBUG_SHD_REG(ISP_IS_V_OFFS), + RKISP1_DEBUG_SHD_REG(ISP_IS_H_SIZE), + RKISP1_DEBUG_SHD_REG(ISP_IS_V_SIZE), { /* Sentinel */ }, }; struct rkisp1_device *rkisp1 = m->private; From af58c2d9d3957a94888892afacf1c3c894e84818 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Fri, 1 Dec 2023 15:04:32 +0100 Subject: [PATCH 3460/7721] media: rkisp1: debug: Count completed frame interrupts Add a counter to debugfs to count the number of frame-end interrupts. Link: https://lore.kernel.org/r/20231201140433.2126011-4-paul.elder@ideasonboard.com Signed-off-by: Paul Elder Reviewed-by: Alexander Stein Reviewed-by: Kieran Bingham Reviewed-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 1 + drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c | 2 ++ drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 2d7f06281c39..4b6b28c05b89 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -425,6 +425,7 @@ struct rkisp1_debug { unsigned long stats_error; unsigned long stop_timeout[2]; unsigned long frame_drop[2]; + unsigned long complete_frames; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c index d2fbed42164e..79cda589d935 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c @@ -221,6 +221,8 @@ void rkisp1_debug_init(struct rkisp1_device *rkisp1) &debug->frame_drop[RKISP1_MAINPATH]); debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, &debug->frame_drop[RKISP1_SELFPATH]); + debugfs_create_ulong("complete_frames", 0444, debug->debugfs_dir, + &debug->complete_frames); debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1, &rkisp1_debug_input_status_fops); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index da313f87e248..f00873d31c42 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -1009,6 +1009,8 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) if (status & RKISP1_CIF_ISP_FRAME) { u32 isp_ris; + rkisp1->debug.complete_frames++; + /* New frame from the sensor received */ isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS); if (isp_ris & RKISP1_STATS_MEAS_MASK) From efa28efd9cba015f8c3d88123527c3c3cfcd13d0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 26 Nov 2023 03:09:48 +0100 Subject: [PATCH 3461/7721] media: rkisp1: resizer: Stop manual allocation of v4l2_subdev_state Supported media bus codes on the resizer sink pad are identical to the ISP source pad. The .enum_mbus_code() handler thus delegates the enumeration to the ISP's operation. This is problematic for two reasons: - Format enumeration on the ISP source pad is dependent on the format configured on the ISP sink pad for the same subdev state (TRY or ACTIVE), while format enumeration on the resizer sink pad should return all formats supported by the resizer subdev, regardless of the ISP configuration. - Delegating the operation involves creating a fake v4l2_subdev_state on the stack to pass to the ISP .enum_mbus_code() handler. This gets in the way of evolution of both the ISP enumeration handler and, more generally, the V4L2 subdev state infrastructure. Fix those two issues by implementing format enumeration manually for the resizer. Link: https://lore.kernel.org/r/20231126020948.2700-1-laurent.pinchart@ideasonboard.com Reviewed-by: Paul Elder Reviewed-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index f7af360dcb28..a8e377701302 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -330,12 +330,8 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, { struct rkisp1_resizer *rsz = container_of(sd, struct rkisp1_resizer, sd); - struct v4l2_subdev_pad_config dummy_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &dummy_cfg - }; - u32 pad = code->pad; - int ret; + unsigned int index = code->index; + unsigned int i; if (code->pad == RKISP1_RSZ_PAD_SRC) { /* supported mbus codes on the src are the same as in the capture */ @@ -355,15 +351,29 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, return 0; } - /* supported mbus codes on the sink pad are the same as isp src pad */ - code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO; - ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code, - &pad_state, code); + /* + * Supported mbus codes on the sink pad are the same as on the ISP + * source pad. + */ + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); - /* restore pad */ - code->pad = pad; - code->flags = 0; - return ret; + if (!fmt) + break; + + if (!(fmt->direction & RKISP1_ISP_SD_SRC)) + continue; + + if (!index) { + code->code = fmt->mbus_code; + return 0; + } + + index--; + } + + return -EINVAL; } static int rkisp1_rsz_init_state(struct v4l2_subdev *sd, From 33318c0e6ba64876050def6432f80387c89d0fe6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 5 Dec 2023 16:19:01 -0800 Subject: [PATCH 3462/7721] fscrypt.rst: update definition of struct fscrypt_context_v2 Get the copy of the fscrypt_context_v2 definition in the documentation in sync with the actual definition, which was changed recently by commit 5b1188847180 ("fscrypt: support crypto data unit size less than filesystem block size"). Link: https://lore.kernel.org/r/20231206001901.14371-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- Documentation/filesystems/fscrypt.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 1b84f818e574..8d38b47b7b83 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -1382,7 +1382,8 @@ directory.) These structs are defined as follows:: u8 contents_encryption_mode; u8 filenames_encryption_mode; u8 flags; - u8 __reserved[4]; + u8 log2_data_unit_size; + u8 __reserved[3]; u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; }; From 0fc24a6549f9b6efc538b67a098ab577b1f9a00e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 5 Dec 2023 16:21:27 -0800 Subject: [PATCH 3463/7721] fscrypt: update comment for do_remove_key() Adjust a comment that was missed during commit 15baf55481de ("fscrypt: track master key presence separately from secret"). Link: https://lore.kernel.org/r/20231206002127.14790-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/keyring.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index f34a9b0b9e92..0edf0b58daa7 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -1002,9 +1002,9 @@ static int try_to_lock_encrypted_files(struct super_block *sb, * FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS (all_users=true) always removes the * key itself. * - * To "remove the key itself", first we wipe the actual master key secret, so - * that no more inodes can be unlocked with it. Then we try to evict all cached - * inodes that had been unlocked with the key. + * To "remove the key itself", first we transition the key to the "incompletely + * removed" state, so that no more inodes can be unlocked with it. Then we try + * to evict all cached inodes that had been unlocked with the key. * * If all inodes were evicted, then we unlink the fscrypt_master_key from the * keyring. Otherwise it remains in the keyring in the "incompletely removed" From c26f2a8901393c9f81909da0a4324587092bd3a3 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 8 Dec 2023 18:23:49 +0800 Subject: [PATCH 3464/7721] bpf: Remove unnecessary wait from bpf_map_copy_value() Both map_lookup_elem() and generic_map_lookup_batch() use bpf_map_copy_value() to lookup and copy the value, and there is no update operation in bpf_map_copy_value(), so just remove the invocation of maybe_wait_bpf_programs() from it. Fixes: 15c14a3dca42 ("bpf: Add bpf_map_{value_size, update_value, map_copy_value} functions") Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231208102355.2628918-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index aff045eed375..9ad3f527ab37 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -264,7 +264,6 @@ static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value, } bpf_enable_instrumentation(); - maybe_wait_bpf_programs(map); return err; } From 37ba5b59d6adfa08926acd3a833608487a18c2ef Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 8 Dec 2023 18:23:50 +0800 Subject: [PATCH 3465/7721] bpf: Call maybe_wait_bpf_programs() only once for generic_map_update_batch() Just like commit 9087c6ff8dfe ("bpf: Call maybe_wait_bpf_programs() only once from generic_map_delete_batch()"), there is also no need to call maybe_wait_bpf_programs() for each update in batched update, so only call it once in generic_map_update_batch(). Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231208102355.2628918-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 9ad3f527ab37..07e671431987 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -203,7 +203,6 @@ static int bpf_map_update_value(struct bpf_map *map, struct file *map_file, rcu_read_unlock(); } bpf_enable_instrumentation(); - maybe_wait_bpf_programs(map); return err; } @@ -1577,6 +1576,7 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) } err = bpf_map_update_value(map, f.file, key, value, attr->flags); + maybe_wait_bpf_programs(map); kvfree(value); free_key: @@ -1816,6 +1816,8 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file, kvfree(value); kvfree(key); + + maybe_wait_bpf_programs(map); return err; } From 012772581d040607ac1f981f47f6afd2336b4580 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 8 Dec 2023 18:23:51 +0800 Subject: [PATCH 3466/7721] bpf: Add missed maybe_wait_bpf_programs() for htab of maps When doing batched lookup and deletion operations on htab of maps, maybe_wait_bpf_programs() is needed to ensure all programs don't use the inner map after the bpf syscall returns. Instead of adding the wait in __htab_map_lookup_and_delete_batch(), adding the wait in bpf_map_do_batch() and also removing the calling of maybe_wait_bpf_programs() from generic_map_{delete,update}_batch(). Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231208102355.2628918-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 07e671431987..2e6ef361da1c 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1758,7 +1758,6 @@ int generic_map_delete_batch(struct bpf_map *map, kvfree(key); - maybe_wait_bpf_programs(map); return err; } @@ -1817,7 +1816,6 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file, kvfree(value); kvfree(key); - maybe_wait_bpf_programs(map); return err; } @@ -5031,8 +5029,10 @@ static int bpf_map_do_batch(const union bpf_attr *attr, else BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr); err_put: - if (has_write) + if (has_write) { + maybe_wait_bpf_programs(map); bpf_map_write_active_dec(map); + } fdput(f); return err; } From 67ad2c73ff29b32bd09135ec07c26e59490dbb3b Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 8 Dec 2023 18:23:52 +0800 Subject: [PATCH 3467/7721] bpf: Only call maybe_wait_bpf_programs() when map operation succeeds There is no need to call maybe_wait_bpf_programs() if update or deletion operation fails. So only call maybe_wait_bpf_programs() if update or deletion operation succeeds. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231208102355.2628918-5-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 2e6ef361da1c..dd641475b65f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1576,7 +1576,8 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) } err = bpf_map_update_value(map, f.file, key, value, attr->flags); - maybe_wait_bpf_programs(map); + if (!err) + maybe_wait_bpf_programs(map); kvfree(value); free_key: @@ -1632,7 +1633,8 @@ static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr) err = map->ops->map_delete_elem(map, key); rcu_read_unlock(); bpf_enable_instrumentation(); - maybe_wait_bpf_programs(map); + if (!err) + maybe_wait_bpf_programs(map); out: kvfree(key); err_put: From 06e5c999f10269a532304e89a6adb2fbfeb0593c Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 8 Dec 2023 18:23:53 +0800 Subject: [PATCH 3468/7721] bpf: Set uattr->batch.count as zero before batched update or deletion generic_map_{delete,update}_batch() doesn't set uattr->batch.count as zero before it tries to allocate memory for key. If the memory allocation fails, the value of uattr->batch.count will be incorrect. Fix it by setting uattr->batch.count as zero beore batched update or deletion. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20231208102355.2628918-6-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index dd641475b65f..06320d9abf33 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1731,6 +1731,9 @@ int generic_map_delete_batch(struct bpf_map *map, if (!max_count) return 0; + if (put_user(0, &uattr->batch.count)) + return -EFAULT; + key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN); if (!key) return -ENOMEM; @@ -1787,6 +1790,9 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file, if (!max_count) return 0; + if (put_user(0, &uattr->batch.count)) + return -EFAULT; + key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN); if (!key) return -ENOMEM; From 482d548d40b0af9af730e4869903d4433e44f014 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 8 Dec 2023 17:09:57 -0800 Subject: [PATCH 3469/7721] bpf: handle fake register spill to stack with BPF_ST_MEM instruction When verifier validates BPF_ST_MEM instruction that stores known constant to stack (e.g., *(u64 *)(r10 - 8) = 123), it effectively spills a fake register with a constant (but initially imprecise) value to a stack slot. Because read-side logic treats it as a proper register fill from stack slot, we need to mark such stack slot initialization as INSN_F_STACK_ACCESS instruction to stop precision backtracking from missing it. Fixes: 41f6f64e6999 ("bpf: support non-r10 register spill/fill to/from stack in precision tracking") Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20231209010958.66758-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fb690539d5f6..727a59e4a647 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4498,7 +4498,6 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, __mark_reg_known(&fake_reg, insn->imm); fake_reg.type = SCALAR_VALUE; save_register_state(env, state, spi, &fake_reg, size); - insn_flags = 0; /* not a register spill */ } else if (reg && is_spillable_regtype(reg->type)) { /* register containing pointer is being spilled into stack */ if (size != BPF_REG_SIZE) { From 7d8ed51bcb32716a40d71043fcd01c4118858c51 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 8 Dec 2023 17:09:58 -0800 Subject: [PATCH 3470/7721] selftests/bpf: validate fake register spill/fill precision backtracking logic Add two tests validating that verifier's precision backtracking logic handles BPF_ST_MEM instructions that produce fake register spill into register slot. This is happening when non-zero constant is written directly to a slot, e.g., *(u64 *)(r10 -8) = 123. Add both full 64-bit register spill, as well as 32-bit "sub-spill". Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20231209010958.66758-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index df4920da3472..508f5d6c7347 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -577,4 +577,158 @@ __naked void partial_stack_load_preserves_zeros(void) : __clobber_common); } +char two_byte_buf[2] SEC(".data.two_byte_buf"); + +SEC("raw_tp") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__success +/* make sure fp-8 is IMPRECISE fake register spill */ +__msg("3: (7a) *(u64 *)(r10 -8) = 1 ; R10=fp0 fp-8_w=1") +/* and fp-16 is spilled IMPRECISE const reg */ +__msg("5: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16_w=1") +/* validate load from fp-8, which was initialized using BPF_ST_MEM */ +__msg("8: (79) r2 = *(u64 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=1") +__msg("9: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 8: (79) r2 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") +/* note, fp-8 is precise, fp-16 is not yet precise, we'll get there */ +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_w=1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7a) *(u64 *)(r10 -8) = 1") +__msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +/* validate load from fp-16, which was initialized using BPF_STX_MEM */ +__msg("12: (79) r2 = *(u64 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=1") +__msg("13: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 12: (79) r2 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (79) r2 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") +/* now both fp-8 and fp-16 are precise, very good */ +__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_rw=P1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") +__msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +__naked void stack_load_preserves_const_precision(void) +{ + asm volatile ( + /* establish checkpoint with state that has no stack slots; + * if we bubble up to this state without finding desired stack + * slot, then it's a bug and should be caught + */ + "goto +0;" + + /* fp-8 is const 1 *fake* register */ + ".8byte %[fp8_st_one];" /* LLVM-18+: *(u64 *)(r10 -8) = 1; */ + + /* fp-16 is const 1 register */ + "r0 = 1;" + "*(u64 *)(r10 -16) = r0;" + + /* force checkpoint to check precision marks preserved in parent states */ + "goto +0;" + + /* load single U64 from aligned FAKE_REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u64 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U64 from aligned REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u64 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(two_byte_buf), + __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 1)) + : __clobber_common); +} + +SEC("raw_tp") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__success +/* make sure fp-8 is 32-bit FAKE subregister spill */ +__msg("3: (62) *(u32 *)(r10 -8) = 1 ; R10=fp0 fp-8=????1") +/* but fp-16 is spilled IMPRECISE zero const reg */ +__msg("5: (63) *(u32 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16=????1") +/* validate load from fp-8, which was initialized using BPF_ST_MEM */ +__msg("8: (61) r2 = *(u32 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=????1") +__msg("9: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 8: (61) r2 = *(u32 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16=????1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (63) *(u32 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (62) *(u32 *)(r10 -8) = 1") +__msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +/* validate load from fp-16, which was initialized using BPF_STX_MEM */ +__msg("12: (61) r2 = *(u32 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=????1") +__msg("13: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 12: (61) r2 = *(u32 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (61) r2 = *(u32 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") +__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16_r=????P1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (63) *(u32 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") +__msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +__naked void stack_load_preserves_const_precision_subreg(void) +{ + asm volatile ( + /* establish checkpoint with state that has no stack slots; + * if we bubble up to this state without finding desired stack + * slot, then it's a bug and should be caught + */ + "goto +0;" + + /* fp-8 is const 1 *fake* SUB-register */ + ".8byte %[fp8_st_one];" /* LLVM-18+: *(u32 *)(r10 -8) = 1; */ + + /* fp-16 is const 1 SUB-register */ + "r0 = 1;" + "*(u32 *)(r10 -16) = r0;" + + /* force checkpoint to check precision marks preserved in parent states */ + "goto +0;" + + /* load single U32 from aligned FAKE_REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u32 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from aligned REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u32 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(two_byte_buf), + __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_W, BPF_REG_FP, -8, 1)) /* 32-bit spill */ + : __clobber_common); +} + char _license[] SEC("license") = "GPL"; From 5181dc08f79583c6dead80208137a97e68ff07b0 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Thu, 7 Dec 2023 12:08:51 +0800 Subject: [PATCH 3471/7721] test_bpf: Rename second ALU64_SMOD_X to ALU64_SMOD_K Currently, there are two test cases with same name "ALU64_SMOD_X: -7 % 2 = -1", the first one is right, the second one should be ALU64_SMOD_K because its code is BPF_ALU64 | BPF_MOD | BPF_K. Before: test_bpf: #170 ALU64_SMOD_X: -7 % 2 = -1 jited:1 4 PASS test_bpf: #171 ALU64_SMOD_X: -7 % 2 = -1 jited:1 4 PASS After: test_bpf: #170 ALU64_SMOD_X: -7 % 2 = -1 jited:1 4 PASS test_bpf: #171 ALU64_SMOD_K: -7 % 2 = -1 jited:1 4 PASS Fixes: daabb2b098e0 ("bpf/tests: add tests for cpuv4 instructions") Signed-off-by: Tiezhu Yang Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231207040851.19730-1-yangtiezhu@loongson.cn Signed-off-by: Alexei Starovoitov --- lib/test_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index e380fdf756db..569e6d2dc55c 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -6277,7 +6277,7 @@ static struct bpf_test tests[] = { }, /* BPF_ALU64 | BPF_MOD | BPF_K off=1 (SMOD64) */ { - "ALU64_SMOD_X: -7 % 2 = -1", + "ALU64_SMOD_K: -7 % 2 = -1", .u.insns_int = { BPF_LD_IMM64(R0, -7), BPF_ALU64_IMM_OFF(BPF_MOD, R0, 2, 1), From a6de18f310a511278c1ff16b96eb2d500eada725 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Thu, 7 Dec 2023 15:08:42 -0600 Subject: [PATCH 3472/7721] bpf: Add bpf_cpumask_weight() kfunc It can be useful to query how many bits are set in a cpumask. For example, if you want to perform special logic for the last remaining core that's set in a mask. Let's therefore add a new bpf_cpumask_weight() kfunc which checks how many bits are set in a mask. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231207210843.168466-2-void@manifault.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/cpumasks.rst | 2 +- kernel/bpf/cpumask.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/cpumasks.rst b/Documentation/bpf/cpumasks.rst index a22b6ad105fb..b5d47a04da5d 100644 --- a/Documentation/bpf/cpumasks.rst +++ b/Documentation/bpf/cpumasks.rst @@ -352,7 +352,7 @@ can be used to query the contents of cpumasks. .. kernel-doc:: kernel/bpf/cpumask.c :identifiers: bpf_cpumask_first bpf_cpumask_first_zero bpf_cpumask_first_and - bpf_cpumask_test_cpu + bpf_cpumask_test_cpu bpf_cpumask_weight .. kernel-doc:: kernel/bpf/cpumask.c :identifiers: bpf_cpumask_equal bpf_cpumask_intersects bpf_cpumask_subset diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c index e01c741e54e7..7499b7d8c06f 100644 --- a/kernel/bpf/cpumask.c +++ b/kernel/bpf/cpumask.c @@ -405,6 +405,17 @@ __bpf_kfunc u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, return cpumask_any_and_distribute(src1, src2); } +/** + * bpf_cpumask_weight() - Return the number of bits in @cpumask. + * @cpumask: The cpumask being queried. + * + * Count the number of set bits in the given cpumask. + */ +__bpf_kfunc u32 bpf_cpumask_weight(const struct cpumask *cpumask) +{ + return cpumask_weight(cpumask); +} + __bpf_kfunc_end_defs(); BTF_SET8_START(cpumask_kfunc_btf_ids) @@ -432,6 +443,7 @@ BTF_ID_FLAGS(func, bpf_cpumask_full, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_any_distribute, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_any_and_distribute, KF_RCU) +BTF_ID_FLAGS(func, bpf_cpumask_weight, KF_RCU) BTF_SET8_END(cpumask_kfunc_btf_ids) static const struct btf_kfunc_id_set cpumask_kfunc_set = { From 88f6047191e69bdd02cf1b9b5b514f7e514e8b86 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Thu, 7 Dec 2023 15:08:43 -0600 Subject: [PATCH 3473/7721] selftests/bpf: Add test for bpf_cpumask_weight() kfunc The new bpf_cpumask_weight() kfunc can be used to count the number of bits that are set in a struct cpumask* kptr. Let's add a selftest to verify its behavior. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20231207210843.168466-3-void@manifault.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/cpumask.c | 1 + .../selftests/bpf/progs/cpumask_common.h | 1 + .../selftests/bpf/progs/cpumask_success.c | 43 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index 756ea8b590b6..c2e886399e3c 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -18,6 +18,7 @@ static const char * const cpumask_success_testcases[] = { "test_insert_leave", "test_insert_remove_release", "test_global_mask_rcu", + "test_cpumask_weight", }; static void verify_success(const char *prog_name) diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index b15c588ace15..0cd4aebb97cf 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -54,6 +54,7 @@ bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym; void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym; u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym; u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym; +u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 674a63424dee..fc3666edf456 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -460,6 +460,49 @@ int BPF_PROG(test_global_mask_rcu, struct task_struct *task, u64 clone_flags) return 0; } +SEC("tp_btf/task_newtask") +int BPF_PROG(test_cpumask_weight, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *local; + + if (!is_test_task()) + return 0; + + local = create_cpumask(); + if (!local) + return 0; + + if (bpf_cpumask_weight(cast(local)) != 0) { + err = 3; + goto out; + } + + bpf_cpumask_set_cpu(0, local); + if (bpf_cpumask_weight(cast(local)) != 1) { + err = 4; + goto out; + } + + /* + * Make sure that adding additional CPUs changes the weight. Test to + * see whether the CPU was set to account for running on UP machines. + */ + bpf_cpumask_set_cpu(1, local); + if (bpf_cpumask_test_cpu(1, cast(local)) && bpf_cpumask_weight(cast(local)) != 2) { + err = 5; + goto out; + } + + bpf_cpumask_clear(local); + if (bpf_cpumask_weight(cast(local)) != 0) { + err = 6; + goto out; + } +out: + bpf_cpumask_release(local); + return 0; +} + SEC("tp_btf/task_newtask") __success int BPF_PROG(test_refcount_null_tracking, struct task_struct *task, u64 clone_flags) From 5012f9d8acd411bc86229d75c0bb9517f84a60ec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 9 Dec 2023 23:01:27 +0100 Subject: [PATCH 3474/7721] ASoC: wm1250-ev1: Fix uninitialized ret The GPIO descriptor conversion patch left an unitialized ret behind by mistake, fix it by getting rid of the variable altogether. Fixes: 10a366f36e2a ("ASoC: wm1250-ev1: Convert to GPIO descriptors") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312090953.DiUo3mue-lkp@intel.com/ Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20231209-descriptors-sound-wlf-v1-1-5b885ce43ae1@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm1250-ev1.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index a2a8b2a4b19b..9fa6df48799b 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -129,7 +129,6 @@ static int wm1250_ev1_pdata(struct i2c_client *i2c) { struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm1250_priv *wm1250; - int ret; if (!pdata) return 0; @@ -165,7 +164,7 @@ static int wm1250_ev1_pdata(struct i2c_client *i2c) dev_set_drvdata(&i2c->dev, wm1250); - return ret; + return 0; } static int wm1250_ev1_probe(struct i2c_client *i2c) From fdd78ff04ccc96f628c2f93e0d48ab0a74bf34ef Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Sat, 9 Dec 2023 23:30:47 +0000 Subject: [PATCH 3475/7721] dt-bindings: soc: samsung: exynos-pmu: Add gs101 compatible Add gs101-pmu compatible to the bindings documentation. Reviewed-by: Sam Protsenko Signed-off-by: Peter Griffin Link: https://lore.kernel.org/r/20231209233106.147416-2-peter.griffin@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index 65f77442ff23..15fcd8f1d8bc 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -15,6 +15,7 @@ select: compatible: contains: enum: + - google,gs101-pmu - samsung,exynos3250-pmu - samsung,exynos4210-pmu - samsung,exynos4212-pmu @@ -35,6 +36,7 @@ properties: oneOf: - items: - enum: + - google,gs101-pmu - samsung,exynos3250-pmu - samsung,exynos4210-pmu - samsung,exynos4212-pmu From 0a910f1606384a5886a045e36b1fc80a7fa6706b Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Sat, 9 Dec 2023 23:30:48 +0000 Subject: [PATCH 3476/7721] dt-bindings: clock: Add Google gs101 clock management unit bindings Provide dt-schema documentation for Google gs101 SoC clock controller. Currently this adds support for cmu_top, cmu_misc and cmu_apm. Reviewed-by: Sam Protsenko Signed-off-by: Peter Griffin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231209233106.147416-3-peter.griffin@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/clock/google,gs101-clock.yaml | 106 +++++ include/dt-bindings/clock/google,gs101.h | 392 ++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/google,gs101-clock.yaml create mode 100644 include/dt-bindings/clock/google,gs101.h diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml new file mode 100644 index 000000000000..3eebc03a309b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/google,gs101-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google GS101 SoC clock controller + +maintainers: + - Peter Griffin + +description: | + Google GS101 clock controller is comprised of several CMU units, generating + clocks for different domains. Those CMU units are modeled as separate device + tree nodes, and might depend on each other. The root clock in that clock tree + is OSCCLK (24.576 MHz). That external clock must be defined as a fixed-rate + clock in dts. + + CMU_TOP is a top-level CMU, where all base clocks are prepared using PLLs and + dividers; all other leaf clocks (other CMUs) are usually derived from CMU_TOP. + + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All clocks available for usage + in clock consumer nodes are defined as preprocessor macros in + 'dt-bindings/clock/gs101.h' header. + +properties: + compatible: + enum: + - google,gs101-cmu-top + - google,gs101-cmu-apm + - google,gs101-cmu-misc + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - clocks + - clock-names + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - google,gs101-cmu-top + - google,gs101-cmu-apm + then: + properties: + clocks: + items: + - description: External reference clock (24.576 MHz) + + clock-names: + items: + - const: oscclk + + - if: + properties: + compatible: + contains: + const: google,gs101-cmu-misc + + then: + properties: + clocks: + items: + - description: Misc bus clock (from CMU_TOP) + - description: Misc sss clock (from CMU_TOP) + + clock-names: + items: + - const: dout_cmu_misc_bus + - const: dout_cmu_misc_sss + +additionalProperties: false + +examples: + # Clock controller node for CMU_TOP + - | + #include + + cmu_top: clock-controller@1e080000 { + compatible = "google,gs101-cmu-top"; + reg = <0x1e080000 0x8000>; + #clock-cells = <1>; + clocks = <&ext_24_5m>; + clock-names = "oscclk"; + }; + +... diff --git a/include/dt-bindings/clock/google,gs101.h b/include/dt-bindings/clock/google,gs101.h new file mode 100644 index 000000000000..5d2c2d907a7b --- /dev/null +++ b/include/dt-bindings/clock/google,gs101.h @@ -0,0 +1,392 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2023 Linaro Ltd. + * Author: Peter Griffin + * + * Device Tree binding constants for Google gs101 clock controller. + */ + +#ifndef _DT_BINDINGS_CLOCK_GOOGLE_GS101_H +#define _DT_BINDINGS_CLOCK_GOOGLE_GS101_H + +/* CMU_TOP PLL */ +#define CLK_FOUT_SHARED0_PLL 1 +#define CLK_FOUT_SHARED1_PLL 2 +#define CLK_FOUT_SHARED2_PLL 3 +#define CLK_FOUT_SHARED3_PLL 4 +#define CLK_FOUT_SPARE_PLL 5 + +/* CMU_TOP MUX */ +#define CLK_MOUT_PLL_SHARED0 6 +#define CLK_MOUT_PLL_SHARED1 7 +#define CLK_MOUT_PLL_SHARED2 8 +#define CLK_MOUT_PLL_SHARED3 9 +#define CLK_MOUT_PLL_SPARE 10 +#define CLK_MOUT_CMU_BO_BUS 11 +#define CLK_MOUT_CMU_BUS0_BUS 12 +#define CLK_MOUT_CMU_BUS1_BUS 13 +#define CLK_MOUT_CMU_BUS2_BUS 14 +#define CLK_MOUT_CMU_CIS_CLK0 15 +#define CLK_MOUT_CMU_CIS_CLK1 16 +#define CLK_MOUT_CMU_CIS_CLK2 17 +#define CLK_MOUT_CMU_CIS_CLK3 18 +#define CLK_MOUT_CMU_CIS_CLK4 19 +#define CLK_MOUT_CMU_CIS_CLK5 20 +#define CLK_MOUT_CMU_CIS_CLK6 21 +#define CLK_MOUT_CMU_CIS_CLK7 22 +#define CLK_MOUT_CMU_CMU_BOOST 23 +#define CLK_MOUT_CMU_BOOST_OPTION1 24 +#define CLK_MOUT_CMU_CORE_BUS 25 +#define CLK_MOUT_CMU_CPUCL0_DBG 26 +#define CLK_MOUT_CMU_CPUCL0_SWITCH 27 +#define CLK_MOUT_CMU_CPUCL1_SWITCH 28 +#define CLK_MOUT_CMU_CPUCL2_SWITCH 29 +#define CLK_MOUT_CMU_CSIS_BUS 30 +#define CLK_MOUT_CMU_DISP_BUS 31 +#define CLK_MOUT_CMU_DNS_BUS 32 +#define CLK_MOUT_CMU_DPU_BUS 33 +#define CLK_MOUT_CMU_EH_BUS 34 +#define CLK_MOUT_CMU_G2D_G2D 35 +#define CLK_MOUT_CMU_G2D_MSCL 36 +#define CLK_MOUT_CMU_G3AA_G3AA 37 +#define CLK_MOUT_CMU_G3D_BUSD 38 +#define CLK_MOUT_CMU_G3D_GLB 39 +#define CLK_MOUT_CMU_G3D_SWITCH 40 +#define CLK_MOUT_CMU_GDC_GDC0 41 +#define CLK_MOUT_CMU_GDC_GDC1 42 +#define CLK_MOUT_CMU_GDC_SCSC 43 +#define CLK_MOUT_CMU_HPM 44 +#define CLK_MOUT_CMU_HSI0_BUS 45 +#define CLK_MOUT_CMU_HSI0_DPGTC 46 +#define CLK_MOUT_CMU_HSI0_USB31DRD 47 +#define CLK_MOUT_CMU_HSI0_USBDPDGB 48 +#define CLK_MOUT_CMU_HSI1_BUS 49 +#define CLK_MOUT_CMU_HSI1_PCIE 50 +#define CLK_MOUT_CMU_HSI2_BUS 51 +#define CLK_MOUT_CMU_HSI2_MMC_CARD 52 +#define CLK_MOUT_CMU_HSI2_PCIE 53 +#define CLK_MOUT_CMU_HSI2_UFS_EMBD 54 +#define CLK_MOUT_CMU_IPP_BUS 55 +#define CLK_MOUT_CMU_ITP_BUS 56 +#define CLK_MOUT_CMU_MCSC_ITSC 57 +#define CLK_MOUT_CMU_MCSC_MCSC 58 +#define CLK_MOUT_CMU_MFC_MFC 59 +#define CLK_MOUT_CMU_MIF_BUSP 60 +#define CLK_MOUT_CMU_MIF_SWITCH 61 +#define CLK_MOUT_CMU_MISC_BUS 62 +#define CLK_MOUT_CMU_MISC_SSS 63 +#define CLK_MOUT_CMU_PDP_BUS 64 +#define CLK_MOUT_CMU_PDP_VRA 65 +#define CLK_MOUT_CMU_PERIC0_BUS 66 +#define CLK_MOUT_CMU_PERIC0_IP 67 +#define CLK_MOUT_CMU_PERIC1_BUS 68 +#define CLK_MOUT_CMU_PERIC1_IP 69 +#define CLK_MOUT_CMU_TNR_BUS 70 +#define CLK_MOUT_CMU_TOP_BOOST_OPTION1 71 +#define CLK_MOUT_CMU_TOP_CMUREF 72 +#define CLK_MOUT_CMU_TPU_BUS 73 +#define CLK_MOUT_CMU_TPU_TPU 74 +#define CLK_MOUT_CMU_TPU_TPUCTL 75 +#define CLK_MOUT_CMU_TPU_UART 76 +#define CLK_MOUT_CMU_CMUREF 77 + +/* CMU_TOP Dividers */ +#define CLK_DOUT_CMU_BO_BUS 78 +#define CLK_DOUT_CMU_BUS0_BUS 79 +#define CLK_DOUT_CMU_BUS1_BUS 80 +#define CLK_DOUT_CMU_BUS2_BUS 81 +#define CLK_DOUT_CMU_CIS_CLK0 82 +#define CLK_DOUT_CMU_CIS_CLK1 83 +#define CLK_DOUT_CMU_CIS_CLK2 84 +#define CLK_DOUT_CMU_CIS_CLK3 85 +#define CLK_DOUT_CMU_CIS_CLK4 86 +#define CLK_DOUT_CMU_CIS_CLK5 87 +#define CLK_DOUT_CMU_CIS_CLK6 88 +#define CLK_DOUT_CMU_CIS_CLK7 89 +#define CLK_DOUT_CMU_CORE_BUS 90 +#define CLK_DOUT_CMU_CPUCL0_DBG 91 +#define CLK_DOUT_CMU_CPUCL0_SWITCH 92 +#define CLK_DOUT_CMU_CPUCL1_SWITCH 93 +#define CLK_DOUT_CMU_CPUCL2_SWITCH 94 +#define CLK_DOUT_CMU_CSIS_BUS 95 +#define CLK_DOUT_CMU_DISP_BUS 96 +#define CLK_DOUT_CMU_DNS_BUS 97 +#define CLK_DOUT_CMU_DPU_BUS 98 +#define CLK_DOUT_CMU_EH_BUS 99 +#define CLK_DOUT_CMU_G2D_G2D 100 +#define CLK_DOUT_CMU_G2D_MSCL 101 +#define CLK_DOUT_CMU_G3AA_G3AA 102 +#define CLK_DOUT_CMU_G3D_BUSD 103 +#define CLK_DOUT_CMU_G3D_GLB 104 +#define CLK_DOUT_CMU_G3D_SWITCH 105 +#define CLK_DOUT_CMU_GDC_GDC0 106 +#define CLK_DOUT_CMU_GDC_GDC1 107 +#define CLK_DOUT_CMU_GDC_SCSC 108 +#define CLK_DOUT_CMU_CMU_HPM 109 +#define CLK_DOUT_CMU_HSI0_BUS 110 +#define CLK_DOUT_CMU_HSI0_DPGTC 111 +#define CLK_DOUT_CMU_HSI0_USB31DRD 112 +#define CLK_DOUT_CMU_HSI0_USBDPDBG 113 +#define CLK_DOUT_CMU_HSI1_BUS 114 +#define CLK_DOUT_CMU_HSI1_PCIE 115 +#define CLK_DOUT_CMU_HSI2_BUS 116 +#define CLK_DOUT_CMU_HSI2_MMC_CARD 117 +#define CLK_DOUT_CMU_HSI2_PCIE 118 +#define CLK_DOUT_CMU_HSI2_UFS_EMBD 119 +#define CLK_DOUT_CMU_IPP_BUS 120 +#define CLK_DOUT_CMU_ITP_BUS 121 +#define CLK_DOUT_CMU_MCSC_ITSC 122 +#define CLK_DOUT_CMU_MCSC_MCSC 123 +#define CLK_DOUT_CMU_MFC_MFC 124 +#define CLK_DOUT_CMU_MIF_BUSP 125 +#define CLK_DOUT_CMU_MISC_BUS 126 +#define CLK_DOUT_CMU_MISC_SSS 127 +#define CLK_DOUT_CMU_OTP 128 +#define CLK_DOUT_CMU_PDP_BUS 129 +#define CLK_DOUT_CMU_PDP_VRA 130 +#define CLK_DOUT_CMU_PERIC0_BUS 131 +#define CLK_DOUT_CMU_PERIC0_IP 132 +#define CLK_DOUT_CMU_PERIC1_BUS 133 +#define CLK_DOUT_CMU_PERIC1_IP 134 +#define CLK_DOUT_CMU_TNR_BUS 135 +#define CLK_DOUT_CMU_TPU_BUS 136 +#define CLK_DOUT_CMU_TPU_TPU 137 +#define CLK_DOUT_CMU_TPU_TPUCTL 138 +#define CLK_DOUT_CMU_TPU_UART 139 +#define CLK_DOUT_CMU_CMU_BOOST 140 +#define CLK_DOUT_CMU_CMU_CMUREF 141 +#define CLK_DOUT_CMU_SHARED0_DIV2 142 +#define CLK_DOUT_CMU_SHARED0_DIV3 143 +#define CLK_DOUT_CMU_SHARED0_DIV4 144 +#define CLK_DOUT_CMU_SHARED0_DIV5 145 +#define CLK_DOUT_CMU_SHARED1_DIV2 146 +#define CLK_DOUT_CMU_SHARED1_DIV3 147 +#define CLK_DOUT_CMU_SHARED1_DIV4 148 +#define CLK_DOUT_CMU_SHARED2_DIV2 149 +#define CLK_DOUT_CMU_SHARED3_DIV2 150 + +/* CMU_TOP Gates */ +#define CLK_GOUT_BUS0_BOOST 151 +#define CLK_GOUT_BUS1_BOOST 152 +#define CLK_GOUT_BUS2_BOOST 153 +#define CLK_GOUT_CORE_BOOST 154 +#define CLK_GOUT_CPUCL0_BOOST 155 +#define CLK_GOUT_CPUCL1_BOOST 156 +#define CLK_GOUT_CPUCL2_BOOST 157 +#define CLK_GOUT_MIF_BOOST 158 +#define CLK_GOUT_MIF_SWITCH 159 +#define CLK_GOUT_BO_BUS 160 +#define CLK_GOUT_BUS0_BUS 161 +#define CLK_GOUT_BUS1_BUS 162 +#define CLK_GOUT_BUS2_BUS 163 +#define CLK_GOUT_CIS_CLK0 164 +#define CLK_GOUT_CIS_CLK1 165 +#define CLK_GOUT_CIS_CLK2 167 +#define CLK_GOUT_CIS_CLK3 168 +#define CLK_GOUT_CIS_CLK4 169 +#define CLK_GOUT_CIS_CLK5 170 +#define CLK_GOUT_CIS_CLK6 171 +#define CLK_GOUT_CIS_CLK7 172 +#define CLK_GOUT_CMU_BOOST 173 +#define CLK_GOUT_CORE_BUS 174 +#define CLK_GOUT_CPUCL0_DBG 175 +#define CLK_GOUT_CPUCL0_SWITCH 176 +#define CLK_GOUT_CPUCL1_SWITCH 177 +#define CLK_GOUT_CPUCL2_SWITCH 178 +#define CLK_GOUT_CSIS_BUS 179 +#define CLK_GOUT_DISP_BUS 180 +#define CLK_GOUT_DNS_BUS 181 +#define CLK_GOUT_DPU_BUS 182 +#define CLK_GOUT_EH_BUS 183 +#define CLK_GOUT_G2D_G2D 184 +#define CLK_GOUT_G2D_MSCL 185 +#define CLK_GOUT_G3AA_G3AA 186 +#define CLK_GOUT_G3D_BUSD 187 +#define CLK_GOUT_G3D_GLB 188 +#define CLK_GOUT_G3D_SWITCH 189 +#define CLK_GOUT_GDC_GDC0 190 +#define CLK_GOUT_GDC_GDC1 191 +#define CLK_GOUT_GDC_SCSC 192 +#define CLK_GOUT_CMU_HPM 193 +#define CLK_GOUT_HSI0_BUS 194 +#define CLK_GOUT_HSI0_DPGTC 195 +#define CLK_GOUT_HSI0_USB31DRD 196 +#define CLK_GOUT_HSI0_USBDPDGB 197 +#define CLK_GOUT_HSI1_BUS 198 +#define CLK_GOUT_HSI1_PCIE 199 +#define CLK_GOUT_HSI2_BUS 200 +#define CLK_GOUT_HSI2_MMC_CARD 201 +#define CLK_GOUT_HSI2_PCIE 202 +#define CLK_GOUT_HSI2_UFS_EMBD 203 +#define CLK_GOUT_IPP_BUS 204 +#define CLK_GOUT_ITP_BUS 205 +#define CLK_GOUT_MCSC_ITSC 206 +#define CLK_GOUT_MCSC_MCSC 207 +#define CLK_GOUT_MFC_MFC 208 +#define CLK_GOUT_MIF_BUSP 209 +#define CLK_GOUT_MISC_BUS 210 +#define CLK_GOUT_MISC_SSS 211 +#define CLK_GOUT_PDP_BUS 212 +#define CLK_GOUT_PDP_VRA 213 +#define CLK_GOUT_G3AA 214 +#define CLK_GOUT_PERIC0_BUS 215 +#define CLK_GOUT_PERIC0_IP 216 +#define CLK_GOUT_PERIC1_BUS 217 +#define CLK_GOUT_PERIC1_IP 218 +#define CLK_GOUT_TNR_BUS 219 +#define CLK_GOUT_TOP_CMUREF 220 +#define CLK_GOUT_TPU_BUS 221 +#define CLK_GOUT_TPU_TPU 222 +#define CLK_GOUT_TPU_TPUCTL 223 +#define CLK_GOUT_TPU_UART 224 + +/* CMU_APM */ +#define CLK_MOUT_APM_FUNC 1 +#define CLK_MOUT_APM_FUNCSRC 2 +#define CLK_DOUT_APM_BOOST 3 +#define CLK_DOUT_APM_USI0_UART 4 +#define CLK_DOUT_APM_USI0_USI 5 +#define CLK_DOUT_APM_USI1_UART 6 +#define CLK_GOUT_APM_APM_CMU_APM_PCLK 7 +#define CLK_GOUT_BUS0_BOOST_OPTION1 8 +#define CLK_GOUT_CMU_BOOST_OPTION1 9 +#define CLK_GOUT_CORE_BOOST_OPTION1 10 +#define CLK_GOUT_APM_FUNC 11 +#define CLK_GOUT_APM_APBIF_GPIO_ALIVE_PCLK 12 +#define CLK_GOUT_APM_APBIF_GPIO_FAR_ALIVE_PCLK 13 +#define CLK_GOUT_APM_APBIF_PMU_ALIVE_PCLK 14 +#define CLK_GOUT_APM_APBIF_RTC_PCLK 15 +#define CLK_GOUT_APM_APBIF_TRTC_PCLK 16 +#define CLK_GOUT_APM_APM_USI0_UART_IPCLK 17 +#define CLK_GOUT_APM_APM_USI0_UART_PCLK 18 +#define CLK_GOUT_APM_APM_USI0_USI_IPCLK 19 +#define CLK_GOUT_APM_APM_USI0_USI_PCLK 20 +#define CLK_GOUT_APM_APM_USI1_UART_IPCLK 21 +#define CLK_GOUT_APM_APM_USI1_UART_PCLK 22 +#define CLK_GOUT_APM_D_TZPC_APM_PCLK 23 +#define CLK_GOUT_APM_GPC_APM_PCLK 24 +#define CLK_GOUT_APM_GREBEINTEGRATION_HCLK 25 +#define CLK_GOUT_APM_INTMEM_ACLK 26 +#define CLK_GOUT_APM_INTMEM_PCLK 27 +#define CLK_GOUT_APM_LHM_AXI_G_SWD_I_CLK 28 +#define CLK_GOUT_APM_LHM_AXI_P_AOCAPM_I_CLK 29 +#define CLK_GOUT_APM_LHM_AXI_P_APM_I_CLK 30 +#define CLK_GOUT_APM_LHS_AXI_D_APM_I_CLK 31 +#define CLK_GOUT_APM_LHS_AXI_G_DBGCORE_I_CLK 32 +#define CLK_GOUT_APM_LHS_AXI_G_SCAN2DRAM_I_CLK 33 +#define CLK_GOUT_APM_MAILBOX_APM_AOC_PCLK 34 +#define CLK_GOUT_APM_MAILBOX_APM_AP_PCLK 35 +#define CLK_GOUT_APM_MAILBOX_APM_GSA_PCLK 36 +#define CLK_GOUT_APM_MAILBOX_APM_SWD_PCLK 37 +#define CLK_GOUT_APM_MAILBOX_APM_TPU_PCLK 38 +#define CLK_GOUT_APM_MAILBOX_AP_AOC_PCLK 39 +#define CLK_GOUT_APM_MAILBOX_AP_DBGCORE_PCLK 40 +#define CLK_GOUT_APM_PMU_INTR_GEN_PCLK 41 +#define CLK_GOUT_APM_ROM_CRC32_HOST_ACLK 42 +#define CLK_GOUT_APM_ROM_CRC32_HOST_PCLK 43 +#define CLK_GOUT_APM_CLK_APM_BUS_CLK 44 +#define CLK_GOUT_APM_CLK_APM_USI0_UART_CLK 45 +#define CLK_GOUT_APM_CLK_APM_USI0_USI_CLK 46 +#define CLK_GOUT_APM_CLK_APM_USI1_UART_CLK 47 +#define CLK_GOUT_APM_SPEEDY_APM_PCLK 48 +#define CLK_GOUT_APM_SPEEDY_SUB_APM_PCLK 49 +#define CLK_GOUT_APM_SSMT_D_APM_ACLK 50 +#define CLK_GOUT_APM_SSMT_D_APM_PCLK 51 +#define CLK_GOUT_APM_SSMT_G_DBGCORE_ACLK 52 +#define CLK_GOUT_APM_SSMT_G_DBGCORE_PCLK 53 +#define CLK_GOUT_APM_SS_DBGCORE_SS_DBGCORE_HCLK 54 +#define CLK_GOUT_APM_SYSMMU_D_APM_CLK_S2 55 +#define CLK_GOUT_APM_SYSREG_APM_PCLK 56 +#define CLK_GOUT_APM_UASC_APM_ACLK 57 +#define CLK_GOUT_APM_UASC_APM_PCLK 58 +#define CLK_GOUT_APM_UASC_DBGCORE_ACLK 59 +#define CLK_GOUT_APM_UASC_DBGCORE_PCLK 60 +#define CLK_GOUT_APM_UASC_G_SWD_ACLK 61 +#define CLK_GOUT_APM_UASC_G_SWD_PCLK 62 +#define CLK_GOUT_APM_UASC_P_AOCAPM_ACLK 63 +#define CLK_GOUT_APM_UASC_P_AOCAPM_PCLK 64 +#define CLK_GOUT_APM_UASC_P_APM_ACLK 65 +#define CLK_GOUT_APM_UASC_P_APM_PCLK 66 +#define CLK_GOUT_APM_WDT_APM_PCLK 67 +#define CLK_GOUT_APM_XIU_DP_APM_ACLK 68 +#define CLK_APM_PLL_DIV2_APM 69 +#define CLK_APM_PLL_DIV4_APM 70 +#define CLK_APM_PLL_DIV16_APM 71 + +/* CMU_MISC */ +#define CLK_MOUT_MISC_BUS_USER 1 +#define CLK_MOUT_MISC_SSS_USER 2 +#define CLK_MOUT_MISC_GIC 3 +#define CLK_DOUT_MISC_BUSP 4 +#define CLK_DOUT_MISC_GIC 5 +#define CLK_GOUT_MISC_MISC_CMU_MISC_PCLK 6 +#define CLK_GOUT_MISC_OTP_CON_BIRA_I_OSCCLK 7 +#define CLK_GOUT_MISC_OTP_CON_BISR_I_OSCCLK 8 +#define CLK_GOUT_MISC_OTP_CON_TOP_I_OSCCLK 9 +#define CLK_GOUT_MISC_CLK_MISC_OSCCLK_CLK 10 +#define CLK_GOUT_MISC_ADM_AHB_SSS_HCLKM 11 +#define CLK_GOUT_MISC_AD_APB_DIT_PCLKM 12 +#define CLK_GOUT_MISC_AD_APB_PUF_PCLKM 13 +#define CLK_GOUT_MISC_DIT_ICLKL2A 14 +#define CLK_GOUT_MISC_D_TZPC_MISC_PCLK 15 +#define CLK_GOUT_MISC_GIC_GICCLK 16 +#define CLK_GOUT_MISC_GPC_MISC_PCLK 17 +#define CLK_GOUT_MISC_LHM_AST_ICC_CPUGIC_I_CLK 18 +#define CLK_GOUT_MISC_LHM_AXI_D_SSS_I_CLK 19 +#define CLK_GOUT_MISC_LHM_AXI_P_GIC_I_CLK 20 +#define CLK_GOUT_MISC_LHM_AXI_P_MISC_I_CLK 21 +#define CLK_GOUT_MISC_LHS_ACEL_D_MISC_I_CLK 22 +#define CLK_GOUT_MISC_LHS_AST_IRI_GICCPU_I_CLK 23 +#define CLK_GOUT_MISC_LHS_AXI_D_SSS_I_CLK 24 +#define CLK_GOUT_MISC_MCT_PCLK 25 +#define CLK_GOUT_MISC_OTP_CON_BIRA_PCLK 26 +#define CLK_GOUT_MISC_OTP_CON_BISR_PCLK 27 +#define CLK_GOUT_MISC_OTP_CON_TOP_PCLK 28 +#define CLK_GOUT_MISC_PDMA_ACLK 29 +#define CLK_GOUT_MISC_PPMU_DMA_ACLK 30 +#define CLK_GOUT_MISC_PPMU_MISC_ACLK 31 +#define CLK_GOUT_MISC_PPMU_MISC_PCLK 32 +#define CLK_GOUT_MISC_PUF_I_CLK 33 +#define CLK_GOUT_MISC_QE_DIT_ACLK 34 +#define CLK_GOUT_MISC_QE_DIT_PCLK 35 +#define CLK_GOUT_MISC_QE_PDMA_ACLK 36 +#define CLK_GOUT_MISC_QE_PDMA_PCLK 37 +#define CLK_GOUT_MISC_QE_PPMU_DMA_ACLK 38 +#define CLK_GOUT_MISC_QE_PPMU_DMA_PCLK 39 +#define CLK_GOUT_MISC_QE_RTIC_ACLK 40 +#define CLK_GOUT_MISC_QE_RTIC_PCLK 41 +#define CLK_GOUT_MISC_QE_SPDMA_ACLK 42 +#define CLK_GOUT_MISC_QE_SPDMA_PCLK 43 +#define CLK_GOUT_MISC_QE_SSS_ACLK 44 +#define CLK_GOUT_MISC_QE_SSS_PCLK 45 +#define CLK_GOUT_MISC_CLK_MISC_BUSD_CLK 46 +#define CLK_GOUT_MISC_CLK_MISC_BUSP_CLK 47 +#define CLK_GOUT_MISC_CLK_MISC_GIC_CLK 48 +#define CLK_GOUT_MISC_CLK_MISC_SSS_CLK 49 +#define CLK_GOUT_MISC_RTIC_I_ACLK 50 +#define CLK_GOUT_MISC_RTIC_I_PCLK 51 +#define CLK_GOUT_MISC_SPDMA_ACLK 52 +#define CLK_GOUT_MISC_SSMT_DIT_ACLK 53 +#define CLK_GOUT_MISC_SSMT_DIT_PCLK 54 +#define CLK_GOUT_MISC_SSMT_PDMA_ACLK 55 +#define CLK_GOUT_MISC_SSMT_PDMA_PCLK 56 +#define CLK_GOUT_MISC_SSMT_PPMU_DMA_ACLK 57 +#define CLK_GOUT_MISC_SSMT_PPMU_DMA_PCLK 58 +#define CLK_GOUT_MISC_SSMT_RTIC_ACLK 59 +#define CLK_GOUT_MISC_SSMT_RTIC_PCLK 60 +#define CLK_GOUT_MISC_SSMT_SPDMA_ACLK 61 +#define CLK_GOUT_MISC_SSMT_SPDMA_PCLK 62 +#define CLK_GOUT_MISC_SSMT_SSS_ACLK 63 +#define CLK_GOUT_MISC_SSMT_SSS_PCLK 64 +#define CLK_GOUT_MISC_SSS_I_ACLK 65 +#define CLK_GOUT_MISC_SSS_I_PCLK 66 +#define CLK_GOUT_MISC_SYSMMU_MISC_CLK_S2 67 +#define CLK_GOUT_MISC_SYSMMU_SSS_CLK_S1 68 +#define CLK_GOUT_MISC_SYSREG_MISC_PCLK 69 +#define CLK_GOUT_MISC_TMU_SUB_PCLK 70 +#define CLK_GOUT_MISC_TMU_TOP_PCLK 71 +#define CLK_GOUT_MISC_WDT_CLUSTER0_PCLK 72 +#define CLK_GOUT_MISC_WDT_CLUSTER1_PCLK 73 +#define CLK_GOUT_MISC_XIU_D_MISC_ACLK 74 + +#endif /* _DT_BINDINGS_CLOCK_GOOGLE_GS101_H */ From d9232785858eafde8553932f96fb7e25c2191ed2 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Sat, 9 Dec 2023 23:30:49 +0000 Subject: [PATCH 3477/7721] dt-bindings: soc: google: exynos-sysreg: add dedicated SYSREG compatibles to GS101 GS101 has three different SYSREG controllers, add dedicated compatibles for them to the documentation. Reviewed-by: Sam Protsenko Signed-off-by: Peter Griffin Link: https://lore.kernel.org/r/20231209233106.147416-4-peter.griffin@linaro.org [krzysztof: move Google entries to existing enum] Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 2de4301a467d..925f787e1ea1 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -14,6 +14,9 @@ properties: oneOf: - items: - enum: + - google,gs101-apm-sysreg + - google,gs101-peric0-sysreg + - google,gs101-peric1-sysreg - samsung,exynos3-sysreg - samsung,exynos4-sysreg - samsung,exynos5-sysreg From 8814455a0e54ca353b4b0ad5105569d3fdb945cc Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 7 Dec 2023 21:30:47 +0000 Subject: [PATCH 3478/7721] drm/msm: Refactor UBWC config setting Split up calculating configuration parameters and programming them, so that we can expose them to userspace. Signed-off-by: Connor Abbott Patchwork: https://patchwork.freedesktop.org/patch/571180/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 21 ++--- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 101 +++++++++++++----------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 9 +++ 3 files changed, 78 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index e5916c106796..c003f970189b 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -684,7 +684,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); - u32 regbit; + u32 hbb; int ret; gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); @@ -820,18 +820,15 @@ static int a5xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL2, 0x0000003F); - /* Set the highest bank bit */ - if (adreno_is_a540(adreno_gpu) || adreno_is_a530(adreno_gpu)) - regbit = 2; - else - regbit = 1; + BUG_ON(adreno_gpu->ubwc_config.highest_bank_bit < 13); + hbb = adreno_gpu->ubwc_config.highest_bank_bit - 13; - gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, regbit << 7); - gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, regbit << 1); + gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, hbb << 7); + gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, hbb << 1); if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu) || adreno_is_a540(adreno_gpu)) - gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, regbit); + gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, hbb); /* Disable All flat shading optimization (ALLFLATOPTDIS) */ gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, (1 << 10)); @@ -1785,5 +1782,11 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) /* Set up the preemption specific bits and pieces for each ringbuffer */ a5xx_preempt_init(gpu); + /* Set the highest bank bit */ + if (adreno_is_a540(adreno_gpu) || adreno_is_a530(adreno_gpu)) + adreno_gpu->ubwc_config.highest_bank_bit = 15; + else + adreno_gpu->ubwc_config.highest_bank_bit = 14; + return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 723f9b97734d..c0bc924cd302 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1270,81 +1270,92 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_CP_PROTECT(count_max - 1), regs[i]); } -static void a6xx_set_ubwc_config(struct msm_gpu *gpu) +static void a6xx_calc_ubwc_config(struct adreno_gpu *gpu) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); /* Unknown, introduced with A650 family, related to UBWC mode/ver 4 */ - u32 rgb565_predicator = 0; + gpu->ubwc_config.rgb565_predicator = 0; /* Unknown, introduced with A650 family */ - u32 uavflagprd_inv = 0; + gpu->ubwc_config.uavflagprd_inv = 0; /* Whether the minimum access length is 64 bits */ - u32 min_acc_len = 0; + gpu->ubwc_config.min_acc_len = 0; /* Entirely magic, per-GPU-gen value */ - u32 ubwc_mode = 0; + gpu->ubwc_config.ubwc_mode = 0; /* * The Highest Bank Bit value represents the bit of the highest DDR bank. - * We then subtract 13 from it (13 is the minimum value allowed by hw) and - * write the lowest two bits of the remaining value as hbb_lo and the - * one above it as hbb_hi to the hardware. This should ideally use DRAM - * type detection. + * This should ideally use DRAM type detection. */ - u32 hbb_hi = 0; - u32 hbb_lo = 2; - /* Unknown, introduced with A640/680 */ - u32 amsbc = 0; + gpu->ubwc_config.highest_bank_bit = 15; - if (adreno_is_a610(adreno_gpu)) { - /* HBB = 14 */ - hbb_lo = 1; - min_acc_len = 1; - ubwc_mode = 1; + if (adreno_is_a610(gpu)) { + gpu->ubwc_config.highest_bank_bit = 14; + gpu->ubwc_config.min_acc_len = 1; + gpu->ubwc_config.ubwc_mode = 1; } /* a618 is using the hw default values */ - if (adreno_is_a618(adreno_gpu)) + if (adreno_is_a618(gpu)) return; - if (adreno_is_a619_holi(adreno_gpu)) - hbb_lo = 0; + if (adreno_is_a619_holi(gpu)) + gpu->ubwc_config.highest_bank_bit = 13; - if (adreno_is_a640_family(adreno_gpu)) - amsbc = 1; + if (adreno_is_a640_family(gpu)) + gpu->ubwc_config.amsbc = 1; - if (adreno_is_a650(adreno_gpu) || - adreno_is_a660(adreno_gpu) || - adreno_is_a690(adreno_gpu) || - adreno_is_a730(adreno_gpu) || - adreno_is_a740_family(adreno_gpu)) { + if (adreno_is_a650(gpu) || + adreno_is_a660(gpu) || + adreno_is_a690(gpu) || + adreno_is_a730(gpu) || + adreno_is_a740_family(gpu)) { /* TODO: get ddr type from bootloader and use 2 for LPDDR4 */ - hbb_lo = 3; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; + gpu->ubwc_config.highest_bank_bit = 16; + gpu->ubwc_config.amsbc = 1; + gpu->ubwc_config.rgb565_predicator = 1; + gpu->ubwc_config.uavflagprd_inv = 2; } - if (adreno_is_7c3(adreno_gpu)) { - hbb_lo = 1; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; + if (adreno_is_7c3(gpu)) { + gpu->ubwc_config.highest_bank_bit = 14; + gpu->ubwc_config.amsbc = 1; + gpu->ubwc_config.rgb565_predicator = 1; + gpu->ubwc_config.uavflagprd_inv = 2; } +} + +static void a6xx_set_ubwc_config(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + /* + * We subtract 13 from the highest bank bit (13 is the minimum value + * allowed by hw) and write the lowest two bits of the remaining value + * as hbb_lo and the one above it as hbb_hi to the hardware. + */ + BUG_ON(adreno_gpu->ubwc_config.highest_bank_bit < 13); + u32 hbb = adreno_gpu->ubwc_config.highest_bank_bit - 13; + u32 hbb_hi = hbb >> 2; + u32 hbb_lo = hbb & 3; gpu_write(gpu, REG_A6XX_RB_NC_MODE_CNTL, - rgb565_predicator << 11 | hbb_hi << 10 | amsbc << 4 | - min_acc_len << 3 | hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.rgb565_predicator << 11 | + hbb_hi << 10 | adreno_gpu->ubwc_config.amsbc << 4 | + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); gpu_write(gpu, REG_A6XX_TPL1_NC_MODE_CNTL, hbb_hi << 4 | - min_acc_len << 3 | hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); gpu_write(gpu, REG_A6XX_SP_NC_MODE_CNTL, hbb_hi << 10 | - uavflagprd_inv << 4 | min_acc_len << 3 | - hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.uavflagprd_inv << 4 | + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); if (adreno_is_a7xx(adreno_gpu)) gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, FIELD_PREP(GENMASK(8, 5), hbb_lo)); - gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, min_acc_len << 23 | hbb_lo << 21); + gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, + adreno_gpu->ubwc_config.min_acc_len << 23 | hbb_lo << 21); } static int a6xx_cp_init(struct msm_gpu *gpu) @@ -2911,5 +2922,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu, a6xx_fault_handler); + a6xx_calc_ubwc_config(adreno_gpu); + return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 80b3f6312116..bc14df96feb0 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -165,6 +165,15 @@ struct adreno_gpu { /* firmware: */ const struct firmware *fw[ADRENO_FW_MAX]; + struct { + u32 rgb565_predicator; + u32 uavflagprd_inv; + u32 min_acc_len; + u32 ubwc_mode; + u32 highest_bank_bit; + u32 amsbc; + } ubwc_config; + /* * Register offsets are different between some GPUs. * GPU specific offsets will be exported by GPU specific From 44a88fa45665318473bfdbb832eba1da2d0a3740 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 7 Dec 2023 21:30:48 +0000 Subject: [PATCH 3479/7721] drm/msm: Add param for the highest bank bit This parameter is programmed by the kernel and influences the tiling layout of images. Exposing it to userspace will allow it to tile/untile images correctly without guessing what value the kernel programmed, and allow us to change it in the future without breaking userspace. Signed-off-by: Connor Abbott Patchwork: https://patchwork.freedesktop.org/patch/571181/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 3 +++ include/uapi/drm/msm_drm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 3fe9fd240cc7..074fb498706f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -373,6 +373,9 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_file_private *ctx, return -EINVAL; *value = ctx->aspace->va_size; return 0; + case MSM_PARAM_HIGHEST_BANK_BIT: + *value = adreno_gpu->ubwc_config.highest_bank_bit; + return 0; default: DBG("%s: invalid param: %u", gpu->name, param); return -EINVAL; diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 6f2a7ad04aa4..d8a6b3472760 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -86,6 +86,7 @@ struct drm_msm_timespec { #define MSM_PARAM_CMDLINE 0x0d /* WO: override for task cmdline */ #define MSM_PARAM_VA_START 0x0e /* RO: start of valid GPU iova range */ #define MSM_PARAM_VA_SIZE 0x0f /* RO: size of valid GPU iova range (bytes) */ +#define MSM_PARAM_HIGHEST_BANK_BIT 0x10 /* RO */ /* For backwards compat. The original support for preemption was based on * a single ring per priority level so # of priority levels equals the # From 3e6688fd96966b6c275e95c39aa367bc0a490ccd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Nov 2023 16:26:41 -0800 Subject: [PATCH 3480/7721] drm/msm/adreno: Fix A680 chip id The only A680 referenced from DeviceTree is patch level 1, which since commit '90b593ce1c9e ("drm/msm/adreno: Switch to chip-id for identifying GPU")' isn't a known chip id. Correct the chip id to allow the A680 to be recognized again. Fixes: 90b593ce1c9e ("drm/msm/adreno: Switch to chip-id for identifying GPU") Signed-off-by: Bjorn Andersson Patchwork: https://patchwork.freedesktop.org/patch/569839/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index f62ab5257e66..2ce7d7b1690d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -464,7 +464,7 @@ static const struct adreno_info gpulist[] = { { 190, 1 }, ), }, { - .chip_ids = ADRENO_CHIP_IDS(0x06080000), + .chip_ids = ADRENO_CHIP_IDS(0x06080001), .family = ADRENO_6XX_GEN2, .revn = 680, .fw = { From a3dec9cdf42bceccdf7a7185099a515ba0a8b29b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:45 -0800 Subject: [PATCH 3481/7721] drm/msm/gem: Remove "valid" tracking This was a small optimization for pre-soft-pin userspace. But mesa switched to soft-pin nearly 5yrs ago. So lets drop the optimization and simplify the code. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/568328/ --- drivers/gpu/drm/msm/msm_gem.h | 2 -- drivers/gpu/drm/msm/msm_gem_submit.c | 44 +++++----------------------- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 6352bd3cc5ed..79195f2fd171 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -275,7 +275,6 @@ struct msm_gem_submit { struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ bool fault_dumped; /* Limit devcoredump dumping to one per submit */ - bool valid; /* true if no cmdstream patching needed */ bool in_rb; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; @@ -292,7 +291,6 @@ struct msm_gem_submit { } *cmd; /* array of size nr_cmds */ struct { /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ #define BO_LOCKED 0x4000 /* obj lock is held */ #define BO_PINNED 0x2000 /* obj (pages) is pinned and on active list */ uint32_t flags; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 7aa5e14ab9aa..2fdc373c2589 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -150,8 +150,6 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, submit->bos[i].handle = submit_bo.handle; submit->bos[i].flags = submit_bo.flags; - /* in validate_objects() we figure out if this is true: */ - submit->bos[i].iova = submit_bo.presumed; } spin_lock(&file->table_lock); @@ -278,9 +276,6 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) { unsigned cleanup_flags = BO_PINNED | BO_LOCKED; submit_cleanup_bo(submit, i, cleanup_flags); - - if (!(submit->bos[i].flags & BO_VALID)) - submit->bos[i].iova = 0; } /* This is where we make sure all the bo's are reserved and pin'd: */ @@ -390,8 +385,6 @@ static int submit_pin_objects(struct msm_gem_submit *submit) struct msm_drm_private *priv = submit->dev->dev_private; int i, ret = 0; - submit->valid = true; - for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; struct msm_gem_vma *vma; @@ -407,14 +400,7 @@ static int submit_pin_objects(struct msm_gem_submit *submit) if (ret) break; - if (vma->iova == submit->bos[i].iova) { - submit->bos[i].flags |= BO_VALID; - } else { - submit->bos[i].iova = vma->iova; - /* iova changed, so address in cmdstream is not valid: */ - submit->bos[i].flags &= ~BO_VALID; - submit->valid = false; - } + submit->bos[i].iova = vma->iova; } /* @@ -451,7 +437,7 @@ static void submit_attach_object_fences(struct msm_gem_submit *submit) } static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, - struct drm_gem_object **obj, uint64_t *iova, bool *valid) + struct drm_gem_object **obj, uint64_t *iova) { if (idx >= submit->nr_bos) { SUBMIT_ERROR(submit, "invalid buffer index: %u (out of %u)\n", @@ -463,8 +449,6 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, *obj = submit->bos[idx].obj; if (iova) *iova = submit->bos[idx].iova; - if (valid) - *valid = !!(submit->bos[idx].flags & BO_VALID); return 0; } @@ -477,9 +461,6 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob uint32_t *ptr; int ret = 0; - if (!nr_relocs) - return 0; - if (offset % 4) { SUBMIT_ERROR(submit, "non-aligned cmdstream buffer: %u\n", offset); return -EINVAL; @@ -500,7 +481,6 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob struct drm_msm_gem_submit_reloc submit_reloc = relocs[i]; uint32_t off; uint64_t iova; - bool valid; if (submit_reloc.submit_offset % 4) { SUBMIT_ERROR(submit, "non-aligned reloc offset: %u\n", @@ -519,13 +499,10 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob goto out; } - ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid); + ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova); if (ret) goto out; - if (valid) - continue; - iova += submit_reloc.reloc_offset; if (submit_reloc.shift < 0) @@ -879,8 +856,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_gem_object *obj; uint64_t iova; - ret = submit_bo(submit, submit->cmd[i].idx, - &obj, &iova, NULL); + ret = submit_bo(submit, submit->cmd[i].idx, &obj, &iova); if (ret) goto out; @@ -894,17 +870,13 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit->cmd[i].iova = iova + (submit->cmd[i].offset * 4); - if (submit->valid) + if (likely(!submit->cmd[i].nr_relocs)) continue; if (!gpu->allow_relocs) { - if (submit->cmd[i].nr_relocs) { - SUBMIT_ERROR(submit, "relocs not allowed\n"); - ret = -EINVAL; - goto out; - } - - continue; + SUBMIT_ERROR(submit, "relocs not allowed\n"); + ret = -EINVAL; + goto out; } ret = submit_reloc(submit, obj, submit->cmd[i].offset * 4, From 202f98c19a11e335867a1906c2fb6c53680e4603 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:46 -0800 Subject: [PATCH 3482/7721] drm/msm/gem: Remove submit_unlock_unpin_bo() The only point it is called is before pinning objects, so the "unpin" part of the name is fiction. Just remove it and call submit_cleanup_bo() directly. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/568330/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 2fdc373c2589..51726c9ddffd 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -272,12 +272,6 @@ static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, dma_resv_unlock(obj->resv); } -static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) -{ - unsigned cleanup_flags = BO_PINNED | BO_LOCKED; - submit_cleanup_bo(submit, i, cleanup_flags); -} - /* This is where we make sure all the bo's are reserved and pin'd: */ static int submit_lock_objects(struct msm_gem_submit *submit) { @@ -313,10 +307,10 @@ static int submit_lock_objects(struct msm_gem_submit *submit) } for (; i >= 0; i--) - submit_unlock_unpin_bo(submit, i); + submit_cleanup_bo(submit, i, BO_LOCKED); if (slow_locked > 0) - submit_unlock_unpin_bo(submit, slow_locked); + submit_cleanup_bo(submit, slow_locked, BO_LOCKED); if (ret == -EDEADLK) { struct drm_gem_object *obj = submit->bos[contended].obj; From ceab575cafed594fb3cee1bec01a0e4ed5e2d752 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:47 -0800 Subject: [PATCH 3483/7721] drm/msm/gem: Don't queue job to sched in error cases We shouldn't be running the job in error cases. This also avoids having to think too hard about where the objs get unpinned (and if necessary, the resv takes over tracking that the obj is busy).. ie. error cases it always happens synchronously, and normal cases it happens from scheduler job_run() callback. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/568331/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 51726c9ddffd..0bcdc589ceea 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -946,6 +946,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, } } + if (ret) + goto out; + submit_attach_object_fences(submit); /* The scheduler owns a ref now: */ From 2d7d2c4e84802485a1e765bd0732d41526dcf25c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:48 -0800 Subject: [PATCH 3484/7721] drm/msm/gem: Split out submit_unpin_objects() helper Untangle unpinning from unlock/unref loop. The unpin only happens in error paths so it is easier to decouple from the normal unlock path. Since we never have an intermediate state where a subset of buffers are pinned (ie. we never bail out of the pin or unpin loops) we can replace the bo state flag bit with a global flag in the submit. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/568335/ --- drivers/gpu/drm/msm/msm_gem.h | 6 +++--- drivers/gpu/drm/msm/msm_gem_submit.c | 22 +++++++++++++++++----- drivers/gpu/drm/msm/msm_ringbuffer.c | 3 ++- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 79195f2fd171..80f4207120ea 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -274,8 +274,9 @@ struct msm_gem_submit { int fence_id; /* key into queue->fence_idr */ struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ - bool fault_dumped; /* Limit devcoredump dumping to one per submit */ - bool in_rb; /* "sudo" mode, copy cmds into RB */ + bool bos_pinned : 1; + bool fault_dumped:1;/* Limit devcoredump dumping to one per submit */ + bool in_rb : 1; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; @@ -292,7 +293,6 @@ struct msm_gem_submit { struct { /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ #define BO_LOCKED 0x4000 /* obj lock is held */ -#define BO_PINNED 0x2000 /* obj (pages) is pinned and on active list */ uint32_t flags; union { struct drm_gem_object *obj; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 0bcdc589ceea..208fad42f784 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -265,9 +265,6 @@ static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, */ submit->bos[i].flags &= ~cleanup_flags; - if (flags & BO_PINNED) - msm_gem_unpin_locked(obj); - if (flags & BO_LOCKED) dma_resv_unlock(obj->resv); } @@ -407,13 +404,28 @@ static int submit_pin_objects(struct msm_gem_submit *submit) mutex_lock(&priv->lru.lock); for (i = 0; i < submit->nr_bos; i++) { msm_gem_pin_obj_locked(submit->bos[i].obj); - submit->bos[i].flags |= BO_PINNED; } mutex_unlock(&priv->lru.lock); + submit->bos_pinned = true; + return ret; } +static void submit_unpin_objects(struct msm_gem_submit *submit) +{ + if (!submit->bos_pinned) + return; + + for (int i = 0; i < submit->nr_bos; i++) { + struct drm_gem_object *obj = submit->bos[i].obj; + + msm_gem_unpin_locked(obj); + } + + submit->bos_pinned = false; +} + static void submit_attach_object_fences(struct msm_gem_submit *submit) { int i; @@ -525,7 +537,7 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool error) unsigned i; if (error) - cleanup_flags |= BO_PINNED; + submit_unpin_objects(submit); for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 4968568e3b54..4bc13f7d005a 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -29,9 +29,10 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) struct drm_gem_object *obj = submit->bos[i].obj; msm_gem_unpin_active(obj); - submit->bos[i].flags &= ~BO_PINNED; } + submit->bos_pinned = false; + mutex_unlock(&priv->lru.lock); msm_gpu_submit(gpu, submit); From 3a48a40387e73e1a37428b11cb3ba56d4c108571 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:49 -0800 Subject: [PATCH 3485/7721] drm/msm/gem: Cleanup submit_cleanup_bo() Now that it only handles unlock duty, drop the superfluous arg and rename it. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/568333/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 208fad42f784..2bb5d13726d5 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -248,14 +248,10 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, return ret; } -/* Unwind bo state, according to cleanup_flags. In the success case, only - * the lock is dropped at the end of the submit (and active/pin ref is dropped - * later when the submit is retired). - */ -static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, - unsigned cleanup_flags) +static void submit_unlock_bo(struct msm_gem_submit *submit, int i) { struct drm_gem_object *obj = submit->bos[i].obj; + unsigned cleanup_flags = BO_LOCKED; unsigned flags = submit->bos[i].flags & cleanup_flags; /* @@ -304,10 +300,10 @@ static int submit_lock_objects(struct msm_gem_submit *submit) } for (; i >= 0; i--) - submit_cleanup_bo(submit, i, BO_LOCKED); + submit_unlock_bo(submit, i); if (slow_locked > 0) - submit_cleanup_bo(submit, slow_locked, BO_LOCKED); + submit_unlock_bo(submit, slow_locked); if (ret == -EDEADLK) { struct drm_gem_object *obj = submit->bos[contended].obj; @@ -533,7 +529,6 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob */ static void submit_cleanup(struct msm_gem_submit *submit, bool error) { - unsigned cleanup_flags = BO_LOCKED; unsigned i; if (error) @@ -541,7 +536,7 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool error) for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; - submit_cleanup_bo(submit, i, cleanup_flags); + submit_unlock_bo(submit, i); if (error) drm_gem_object_put(obj); } From 05d249352f1ae909230c230767ca8f4e9fdf8e7b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:50 -0800 Subject: [PATCH 3486/7721] drm/exec: Pass in initial # of objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cases where the # is known ahead of time, it is silly to do the table resize dance. Signed-off-by: Rob Clark Reviewed-by: Christian König Patchwork: https://patchwork.freedesktop.org/patch/568338/ --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 2 +- drivers/gpu/drm/drm_exec.c | 13 ++++++++++--- drivers/gpu/drm/drm_gpuvm.c | 4 ++-- drivers/gpu/drm/imagination/pvr_job.c | 2 +- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 2 +- drivers/gpu/drm/tests/drm_exec_test.c | 16 ++++++++-------- include/drm/drm_exec.h | 2 +- 13 files changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 41fbc4fd0fac..0bd3c4a6267a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1137,7 +1137,7 @@ static int reserve_bo_and_vm(struct kgd_mem *mem, ctx->n_vms = 1; ctx->sync = &mem->sync; - drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&ctx->exec) { ret = amdgpu_vm_lock_pd(vm, &ctx->exec, 2); drm_exec_retry_on_contention(&ctx->exec); @@ -1176,7 +1176,7 @@ static int reserve_bo_and_cond_vms(struct kgd_mem *mem, int ret; ctx->sync = &mem->sync; - drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&ctx->exec) { ctx->n_vms = 0; list_for_each_entry(entry, &mem->attachments, list) { @@ -2552,7 +2552,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info) amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); /* Reserve all BOs and page tables for validation */ drm_exec_until_all_locked(&exec) { /* Reserve all the page directories */ @@ -2793,7 +2793,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) mutex_lock(&process_info->lock); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { list_for_each_entry(peer_vm, &process_info->vm_list_head, vm_list_node) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index e50be6500030..440e9a6786fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -66,7 +66,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, amdgpu_sync_create(&p->sync); drm_exec_init(&p->exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + DRM_EXEC_IGNORE_DUPLICATES, 0); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c index 720011019741..796fa6f1420b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c @@ -70,7 +70,7 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; int r; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { r = amdgpu_vm_lock_pd(vm, &exec, 0); if (likely(!r)) @@ -110,7 +110,7 @@ int amdgpu_unmap_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; int r; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { r = amdgpu_vm_lock_pd(vm, &exec, 0); if (likely(!r)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 84beeaa4d21c..49a5f1c73b3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -203,7 +203,7 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, struct drm_exec exec; long r; - drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_prepare_obj(&exec, &bo->tbo.base, 1); drm_exec_retry_on_contention(&exec); @@ -739,7 +739,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, } drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { if (gobj) { r = drm_exec_lock_obj(&exec, gobj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 9ddbf1494326..abd0b9763904 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -1122,7 +1122,7 @@ int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &ctx_data->meta_data_obj->tbo.base); @@ -1193,7 +1193,7 @@ int amdgpu_mes_ctx_unmap_meta_data(struct amdgpu_device *adev, struct drm_exec exec; long r; - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &ctx_data->meta_data_obj->tbo.base); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c index ca45ba8ac171..bfbf59326ee1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c @@ -86,7 +86,7 @@ static int map_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm, amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &bo->tbo.base); drm_exec_retry_on_contention(&exec); @@ -149,7 +149,7 @@ static int unmap_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; long r; - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &bo->tbo.base); drm_exec_retry_on_contention(&exec); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index f2f3c338fd94..76d9f14ccc7c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1529,7 +1529,7 @@ static int svm_range_reserve_bos(struct svm_validate_context *ctx, bool intr) uint32_t gpuidx; int r; - drm_exec_init(&ctx->exec, intr ? DRM_EXEC_INTERRUPTIBLE_WAIT: 0); + drm_exec_init(&ctx->exec, intr ? DRM_EXEC_INTERRUPTIBLE_WAIT: 0, 0); drm_exec_until_all_locked(&ctx->exec) { for_each_set_bit(gpuidx, ctx->bitmap, MAX_GPU_INSTANCE) { pdd = kfd_process_device_from_gpuidx(ctx->process, gpuidx); diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 5d2809de4517..48ee851b61d9 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -69,16 +69,23 @@ static void drm_exec_unlock_all(struct drm_exec *exec) * drm_exec_init - initialize a drm_exec object * @exec: the drm_exec object to initialize * @flags: controls locking behavior, see DRM_EXEC_* defines + * @nr: the initial # of objects * * Initialize the object and make sure that we can track locked objects. + * + * If nr is non-zero then it is used as the initial objects table size. + * In either case, the table will grow (be re-allocated) on demand. */ -void drm_exec_init(struct drm_exec *exec, uint32_t flags) +void drm_exec_init(struct drm_exec *exec, uint32_t flags, unsigned nr) { + if (!nr) + nr = PAGE_SIZE / sizeof(void *); + exec->flags = flags; - exec->objects = kmalloc(PAGE_SIZE, GFP_KERNEL); + exec->objects = kvmalloc_array(nr, sizeof(void *), GFP_KERNEL); /* If allocation here fails, just delay that till the first use */ - exec->max_objects = exec->objects ? PAGE_SIZE / sizeof(void *) : 0; + exec->max_objects = exec->objects ? nr : 0; exec->num_objects = 0; exec->contended = DRM_EXEC_DUMMY; exec->prelocked = NULL; diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 9c0922c1a5a2..dc8edca61764 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1250,7 +1250,7 @@ drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec) unsigned int num_fences = vm_exec->num_fences; int ret; - drm_exec_init(exec, vm_exec->flags); + drm_exec_init(exec, vm_exec->flags, 0); drm_exec_until_all_locked(exec) { ret = drm_gpuvm_prepare_vm(gpuvm, exec, num_fences); @@ -1341,7 +1341,7 @@ drm_gpuvm_exec_lock_range(struct drm_gpuvm_exec *vm_exec, struct drm_exec *exec = &vm_exec->exec; int ret; - drm_exec_init(exec, vm_exec->flags); + drm_exec_init(exec, vm_exec->flags, 0); drm_exec_until_all_locked(exec) { ret = drm_gpuvm_prepare_range(gpuvm, exec, addr, range, diff --git a/drivers/gpu/drm/imagination/pvr_job.c b/drivers/gpu/drm/imagination/pvr_job.c index 04139da6c04d..78c2f3c6dce0 100644 --- a/drivers/gpu/drm/imagination/pvr_job.c +++ b/drivers/gpu/drm/imagination/pvr_job.c @@ -746,7 +746,7 @@ pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file, if (err) goto out_job_data_cleanup; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 0); xa_init_flags(&signal_array, XA_FLAGS_ALLOC); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index dae3baf707a0..4f223c972c6a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1347,7 +1347,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job, } } - drm_exec_init(exec, vme->flags); + drm_exec_init(exec, vme->flags, 0); drm_exec_until_all_locked(exec) { ret = bind_lock_validate(job, exec, vme->num_fences); drm_exec_retry_on_contention(exec); diff --git a/drivers/gpu/drm/tests/drm_exec_test.c b/drivers/gpu/drm/tests/drm_exec_test.c index 563949d777dd..81f928a429ba 100644 --- a/drivers/gpu/drm/tests/drm_exec_test.c +++ b/drivers/gpu/drm/tests/drm_exec_test.c @@ -46,7 +46,7 @@ static void sanitycheck(struct kunit *test) { struct drm_exec exec; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_fini(&exec); KUNIT_SUCCEED(test); } @@ -60,7 +60,7 @@ static void test_lock(struct kunit *test) drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { ret = drm_exec_lock_obj(&exec, &gobj); drm_exec_retry_on_contention(&exec); @@ -80,7 +80,7 @@ static void test_lock_unlock(struct kunit *test) drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { ret = drm_exec_lock_obj(&exec, &gobj); drm_exec_retry_on_contention(&exec); @@ -107,7 +107,7 @@ static void test_duplicates(struct kunit *test) drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); - drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { ret = drm_exec_lock_obj(&exec, &gobj); drm_exec_retry_on_contention(&exec); @@ -134,7 +134,7 @@ static void test_prepare(struct kunit *test) drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { ret = drm_exec_prepare_obj(&exec, &gobj, 1); drm_exec_retry_on_contention(&exec); @@ -159,7 +159,7 @@ static void test_prepare_array(struct kunit *test) drm_gem_private_object_init(priv->drm, &gobj1, PAGE_SIZE); drm_gem_private_object_init(priv->drm, &gobj2, PAGE_SIZE); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) ret = drm_exec_prepare_array(&exec, array, ARRAY_SIZE(array), 1); @@ -174,14 +174,14 @@ static void test_multiple_loops(struct kunit *test) { struct drm_exec exec; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { break; } drm_exec_fini(&exec); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { break; diff --git a/include/drm/drm_exec.h b/include/drm/drm_exec.h index b5bf0b6da791..f1a66c048721 100644 --- a/include/drm/drm_exec.h +++ b/include/drm/drm_exec.h @@ -135,7 +135,7 @@ static inline bool drm_exec_is_contended(struct drm_exec *exec) return !!exec->contended; } -void drm_exec_init(struct drm_exec *exec, uint32_t flags); +void drm_exec_init(struct drm_exec *exec, uint32_t flags, unsigned nr); void drm_exec_fini(struct drm_exec *exec); bool drm_exec_cleanup(struct drm_exec *exec); int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj); From 378bc9a40ed8b6f1bac558a64b65d4754de89387 Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Thu, 7 Dec 2023 21:34:42 +0000 Subject: [PATCH 3487/7721] net: ena: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. host_info allocation is done in ena_com_allocate_host_info() via dma_alloc_coherent() and is not zero initialized by alloc_etherdev_mq(). However zero initialization of the destination doesn't matter in this case, because strscpy() guarantees a NULL termination. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Acked-by: Arthur Kiyanovski Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index b5bca4814830..4a41efcc996b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3276,8 +3276,8 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pd strscpy(host_info->kernel_ver_str, utsname()->version, sizeof(host_info->kernel_ver_str) - 1); host_info->os_dist = 0; - strncpy(host_info->os_dist_str, utsname()->release, - sizeof(host_info->os_dist_str) - 1); + strscpy(host_info->os_dist_str, utsname()->release, + sizeof(host_info->os_dist_str)); host_info->driver_version = (DRV_MODULE_GEN_MAJOR) | (DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) | From f8dd2412ba66128de4325c187c9504c6da511bc8 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 7 Dec 2023 21:42:22 +0000 Subject: [PATCH 3488/7721] qlcnic: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect fw_info->fw_file_name to be NUL-terminated based on its use within _request_firmware_prepare() wherein `name` refers to it: | if (firmware_request_builtin_buf(firmware, name, dbuf, size)) { | dev_dbg(device, "using built-in %s\n", name); | return 0; /* assigned */ | } ... and with firmware_request_builtin() also via `name`: | if (strcmp(name, b_fw->name) == 0) { There is no evidence that NUL-padding is required. Additionally replace size macro (QLC_FW_FILE_NAME_LEN) with sizeof(fw_info->fw_file_name) to more directly tie the maximum buffer size to the destination buffer: Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index c95d56e56c59..b733374b4dc5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2092,8 +2092,8 @@ static int qlcnic_83xx_run_post(struct qlcnic_adapter *adapter) return -EINVAL; } - strncpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME, - QLC_FW_FILE_NAME_LEN); + strscpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME, + sizeof(fw_info->fw_file_name)); ret = request_firmware(&fw_info->fw, fw_info->fw_file_name, dev); if (ret) { @@ -2396,12 +2396,12 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter) switch (pdev->device) { case PCI_DEVICE_ID_QLOGIC_QLE834X: case PCI_DEVICE_ID_QLOGIC_QLE8830: - strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME, - QLC_FW_FILE_NAME_LEN); + strscpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME, + sizeof(fw_info->fw_file_name)); break; case PCI_DEVICE_ID_QLOGIC_QLE844X: - strncpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME, - QLC_FW_FILE_NAME_LEN); + strscpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME, + sizeof(fw_info->fw_file_name)); break; default: dev_err(&pdev->dev, "%s: Invalid device id\n", From 1674110c0dd44a6240f03fff9a05fd72917b3f7d Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 7 Dec 2023 21:57:50 +0000 Subject: [PATCH 3489/7721] net: mdio_bus: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect mdiodev->modalias to be NUL-terminated based on its usage with strcmp(): | return strcmp(mdiodev->modalias, drv->name) == 0; Moreover, mdiodev->modalias is already zero-allocated: | mdiodev = kzalloc(sizeof(*mdiodev), GFP_KERNEL); ... which means the NUL-padding strncpy provides is not necessary. Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 25dcaa49ab8b..6cf73c15635b 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -506,7 +506,7 @@ static int mdiobus_create_device(struct mii_bus *bus, if (IS_ERR(mdiodev)) return -ENODEV; - strncpy(mdiodev->modalias, bi->modalias, + strscpy(mdiodev->modalias, bi->modalias, sizeof(mdiodev->modalias)); mdiodev->bus_match = mdio_device_bus_match; mdiodev->dev.platform_data = (void *)bi->platform_data; From a6397e63877e82528c67058e6e6e8d700682df50 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Nov 2023 16:38:51 -0800 Subject: [PATCH 3490/7721] drm/msm/gem: Convert to drm_exec Replace the ww_mutex locking dance with the drm_exec helper. v2: Error path fixes, move drm_exec_fini so we only call it once (and only if we have drm_exec_init() Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/568342/ --- drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/msm_gem.h | 5 +- drivers/gpu/drm/msm/msm_gem_submit.c | 119 +++++---------------------- 3 files changed, 24 insertions(+), 101 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index ad70b611b44f..f202f26adab2 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -17,6 +17,7 @@ config DRM_MSM select DRM_DP_AUX_BUS select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER + select DRM_EXEC select DRM_KMS_HELPER select DRM_PANEL select DRM_BRIDGE diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 80f4207120ea..8d414b072c29 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -9,6 +9,7 @@ #include #include +#include "drm/drm_exec.h" #include "drm/gpu_scheduler.h" #include "msm_drv.h" @@ -258,7 +259,7 @@ struct msm_gem_submit { struct msm_gpu *gpu; struct msm_gem_address_space *aspace; struct list_head node; /* node in ring submit list */ - struct ww_acquire_ctx ticket; + struct drm_exec exec; uint32_t seqno; /* Sequence number of the submit on the ring */ /* Hw fence, which is created when the scheduler executes the job, and @@ -291,8 +292,6 @@ struct msm_gem_submit { struct drm_msm_gem_submit_reloc *relocs; } *cmd; /* array of size nr_cmds */ struct { -/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_LOCKED 0x4000 /* obj lock is held */ uint32_t flags; union { struct drm_gem_object *obj; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 2bb5d13726d5..fba78193127d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -248,85 +248,30 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, return ret; } -static void submit_unlock_bo(struct msm_gem_submit *submit, int i) -{ - struct drm_gem_object *obj = submit->bos[i].obj; - unsigned cleanup_flags = BO_LOCKED; - unsigned flags = submit->bos[i].flags & cleanup_flags; - - /* - * Clear flags bit before dropping lock, so that the msm_job_run() - * path isn't racing with submit_cleanup() (ie. the read/modify/ - * write is protected by the obj lock in all paths) - */ - submit->bos[i].flags &= ~cleanup_flags; - - if (flags & BO_LOCKED) - dma_resv_unlock(obj->resv); -} - /* This is where we make sure all the bo's are reserved and pin'd: */ static int submit_lock_objects(struct msm_gem_submit *submit) { - int contended, slow_locked = -1, i, ret = 0; + int ret; -retry: - for (i = 0; i < submit->nr_bos; i++) { - struct drm_gem_object *obj = submit->bos[i].obj; + drm_exec_init(&submit->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, submit->nr_bos); - if (slow_locked == i) - slow_locked = -1; - - contended = i; - - if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = dma_resv_lock_interruptible(obj->resv, - &submit->ticket); + drm_exec_until_all_locked (&submit->exec) { + for (unsigned i = 0; i < submit->nr_bos; i++) { + struct drm_gem_object *obj = submit->bos[i].obj; + ret = drm_exec_prepare_obj(&submit->exec, obj, 1); + drm_exec_retry_on_contention(&submit->exec); if (ret) - goto fail; - submit->bos[i].flags |= BO_LOCKED; + goto error; } } - ww_acquire_done(&submit->ticket); - return 0; -fail: - if (ret == -EALREADY) { - SUBMIT_ERROR(submit, "handle %u at index %u already on submit list\n", - submit->bos[i].handle, i); - ret = -EINVAL; - } - - for (; i >= 0; i--) - submit_unlock_bo(submit, i); - - if (slow_locked > 0) - submit_unlock_bo(submit, slow_locked); - - if (ret == -EDEADLK) { - struct drm_gem_object *obj = submit->bos[contended].obj; - /* we lost out in a seqno race, lock and retry.. */ - ret = dma_resv_lock_slow_interruptible(obj->resv, - &submit->ticket); - if (!ret) { - submit->bos[contended].flags |= BO_LOCKED; - slow_locked = contended; - goto retry; - } - - /* Not expecting -EALREADY here, if the bo was already - * locked, we should have gotten -EALREADY already from - * the dma_resv_lock_interruptable() call. - */ - WARN_ON_ONCE(ret == -EALREADY); - } - +error: return ret; } -static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) +static int submit_fence_sync(struct msm_gem_submit *submit) { int i, ret = 0; @@ -334,22 +279,6 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) struct drm_gem_object *obj = submit->bos[i].obj; bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE; - /* NOTE: _reserve_shared() must happen before - * _add_shared_fence(), which makes this a slightly - * strange place to call it. OTOH this is a - * convenient can-fail point to hook it in. - */ - ret = dma_resv_reserve_fences(obj->resv, 1); - if (ret) - return ret; - - /* If userspace has determined that explicit fencing is - * used, it can disable implicit sync on the entire - * submit: - */ - if (no_implicit) - continue; - /* Otherwise userspace can ask for implicit sync to be * disabled on specific buffers. This is useful for internal * usermode driver managed buffers, suballocation, etc. @@ -529,17 +458,14 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob */ static void submit_cleanup(struct msm_gem_submit *submit, bool error) { - unsigned i; - - if (error) + if (error) { submit_unpin_objects(submit); - - for (i = 0; i < submit->nr_bos; i++) { - struct drm_gem_object *obj = submit->bos[i].obj; - submit_unlock_bo(submit, i); - if (error) - drm_gem_object_put(obj); + /* job wasn't enqueued to scheduler, so early retirement: */ + msm_submit_retire(submit); } + + if (submit->exec.objects) + drm_exec_fini(&submit->exec); } void msm_submit_retire(struct msm_gem_submit *submit) @@ -733,7 +659,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_submit_post_dep *post_deps = NULL; struct drm_syncobj **syncobjs_to_reset = NULL; int out_fence_fd = -1; - bool has_ww_ticket = false; unsigned i; int ret; @@ -839,15 +764,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; /* copy_*_user while holding a ww ticket upsets lockdep */ - ww_acquire_init(&submit->ticket, &reservation_ww_class); - has_ww_ticket = true; ret = submit_lock_objects(submit); if (ret) goto out; - ret = submit_fence_sync(submit, !!(args->flags & MSM_SUBMIT_NO_IMPLICIT)); - if (ret) - goto out; + if (!(args->flags & MSM_SUBMIT_NO_IMPLICIT)) { + ret = submit_fence_sync(submit); + if (ret) + goto out; + } ret = submit_pin_objects(submit); if (ret) @@ -975,8 +900,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: submit_cleanup(submit, !!ret); - if (has_ww_ticket) - ww_acquire_fini(&submit->ticket); out_unlock: mutex_unlock(&queue->lock); out_post_unlock: From c7e0022390d43788f63c7021ad441c1f8d9acf5f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:22 +0900 Subject: [PATCH 3491/7721] net: rswitch: Drop unused argument/return value Drop unused argument and return value of rswitch_tx_free() to simplify the code. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 89e7a6551c64..8c03c0e18003 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -761,20 +761,19 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) return 0; } -static int rswitch_tx_free(struct net_device *ndev, bool free_txed_only) +static void rswitch_tx_free(struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_gwca_queue *gq = rdev->tx_queue; struct rswitch_ext_desc *desc; dma_addr_t dma_addr; struct sk_buff *skb; - int free_num = 0; int size; for (; rswitch_get_num_cur_queues(gq) > 0; gq->dirty = rswitch_next_queue_index(gq, false, 1)) { desc = &gq->tx_ring[gq->dirty]; - if (free_txed_only && (desc->desc.die_dt & DT_MASK) != DT_FEMPTY) + if ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) break; dma_rmb(); @@ -786,14 +785,11 @@ static int rswitch_tx_free(struct net_device *ndev, bool free_txed_only) size, DMA_TO_DEVICE); dev_kfree_skb_any(gq->skbs[gq->dirty]); gq->skbs[gq->dirty] = NULL; - free_num++; } desc->desc.die_dt = DT_EEMPTY; rdev->ndev->stats.tx_packets++; rdev->ndev->stats.tx_bytes += size; } - - return free_num; } static int rswitch_poll(struct napi_struct *napi, int budget) @@ -808,7 +804,7 @@ static int rswitch_poll(struct napi_struct *napi, int budget) priv = rdev->priv; retry: - rswitch_tx_free(ndev, true); + rswitch_tx_free(ndev); if (rswitch_rx(ndev, "a)) goto out; From 8857034184538ca92b0e029f6f56e5e04f518ad2 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:23 +0900 Subject: [PATCH 3492/7721] net: rswitch: Use unsigned int for desc related array index Array index should not be negative, so use unsigned int for descriptors related array index. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 88 ++++++++++++++------------ drivers/net/ethernet/renesas/rswitch.h | 14 ++-- 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 8c03c0e18003..0928003ad245 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -56,7 +56,8 @@ static void rswitch_clock_disable(struct rswitch_private *priv) iowrite32(RCDC_RCD, priv->addr + RCDC); } -static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr, int port) +static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr, + unsigned int port) { u32 val = ioread32(coma_addr + RCEC); @@ -66,7 +67,8 @@ static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr, int port) return false; } -static void rswitch_agent_clock_ctrl(void __iomem *coma_addr, int port, int enable) +static void rswitch_agent_clock_ctrl(void __iomem *coma_addr, unsigned int port, + int enable) { u32 val; @@ -100,7 +102,7 @@ static void rswitch_coma_init(struct rswitch_private *priv) /* R-Switch-2 block (TOP) */ static void rswitch_top_init(struct rswitch_private *priv) { - int i; + unsigned int i; for (i = 0; i < RSWITCH_MAX_NUM_QUEUES; i++) iowrite32((i / 16) << (GWCA_INDEX * 8), priv->addr + TPEMIMC7(i)); @@ -109,7 +111,7 @@ static void rswitch_top_init(struct rswitch_private *priv) /* Forwarding engine block (MFWD) */ static void rswitch_fwd_init(struct rswitch_private *priv) { - int i; + unsigned int i; /* For ETHA */ for (i = 0; i < RSWITCH_NUM_PORTS; i++) { @@ -166,7 +168,7 @@ static int rswitch_gwca_axi_ram_reset(struct rswitch_private *priv) static bool rswitch_is_any_data_irq(struct rswitch_private *priv, u32 *dis, bool tx) { u32 *mask = tx ? priv->gwca.tx_irq_bits : priv->gwca.rx_irq_bits; - int i; + unsigned int i; for (i = 0; i < RSWITCH_NUM_IRQ_REGS; i++) { if (dis[i] & mask[i]) @@ -178,7 +180,7 @@ static bool rswitch_is_any_data_irq(struct rswitch_private *priv, u32 *dis, bool static void rswitch_get_data_irq_status(struct rswitch_private *priv, u32 *dis) { - int i; + unsigned int i; for (i = 0; i < RSWITCH_NUM_IRQ_REGS; i++) { dis[i] = ioread32(priv->addr + GWDIS(i)); @@ -186,23 +188,26 @@ static void rswitch_get_data_irq_status(struct rswitch_private *priv, u32 *dis) } } -static void rswitch_enadis_data_irq(struct rswitch_private *priv, int index, bool enable) +static void rswitch_enadis_data_irq(struct rswitch_private *priv, + unsigned int index, bool enable) { u32 offs = enable ? GWDIE(index / 32) : GWDID(index / 32); iowrite32(BIT(index % 32), priv->addr + offs); } -static void rswitch_ack_data_irq(struct rswitch_private *priv, int index) +static void rswitch_ack_data_irq(struct rswitch_private *priv, + unsigned int index) { u32 offs = GWDIS(index / 32); iowrite32(BIT(index % 32), priv->addr + offs); } -static int rswitch_next_queue_index(struct rswitch_gwca_queue *gq, bool cur, int num) +static unsigned int rswitch_next_queue_index(struct rswitch_gwca_queue *gq, + bool cur, unsigned int num) { - int index = cur ? gq->cur : gq->dirty; + unsigned int index = cur ? gq->cur : gq->dirty; if (index + num >= gq->ring_size) index = (index + num) % gq->ring_size; @@ -212,7 +217,7 @@ static int rswitch_next_queue_index(struct rswitch_gwca_queue *gq, bool cur, int return index; } -static int rswitch_get_num_cur_queues(struct rswitch_gwca_queue *gq) +static unsigned int rswitch_get_num_cur_queues(struct rswitch_gwca_queue *gq) { if (gq->cur >= gq->dirty) return gq->cur - gq->dirty; @@ -231,9 +236,10 @@ static bool rswitch_is_queue_rxed(struct rswitch_gwca_queue *gq) } static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq, - int start_index, int num) + unsigned int start_index, + unsigned int num) { - int i, index; + unsigned int i, index; for (i = 0; i < num; i++) { index = (i + start_index) % gq->ring_size; @@ -248,7 +254,7 @@ static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq, return 0; err: - for (i--; i >= 0; i--) { + for (; i-- > 0; ) { index = (i + start_index) % gq->ring_size; dev_kfree_skb(gq->skbs[index]); gq->skbs[index] = NULL; @@ -260,7 +266,7 @@ static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq, static void rswitch_gwca_queue_free(struct net_device *ndev, struct rswitch_gwca_queue *gq) { - int i; + unsigned int i; if (!gq->dir_tx) { dma_free_coherent(ndev->dev.parent, @@ -294,9 +300,9 @@ static void rswitch_gwca_ts_queue_free(struct rswitch_private *priv) static int rswitch_gwca_queue_alloc(struct net_device *ndev, struct rswitch_private *priv, struct rswitch_gwca_queue *gq, - bool dir_tx, int ring_size) + bool dir_tx, unsigned int ring_size) { - int i, bit; + unsigned int i, bit; gq->dir_tx = dir_tx; gq->ring_size = ring_size; @@ -351,11 +357,11 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, struct rswitch_private *priv, struct rswitch_gwca_queue *gq) { - int ring_size = sizeof(struct rswitch_ext_desc) * gq->ring_size; + unsigned int ring_size = sizeof(struct rswitch_ext_desc) * gq->ring_size; struct rswitch_ext_desc *desc; struct rswitch_desc *linkfix; dma_addr_t dma_addr; - int i; + unsigned int i; memset(gq->tx_ring, 0, ring_size); for (i = 0, desc = gq->tx_ring; i < gq->ring_size; i++, desc++) { @@ -387,7 +393,7 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, err: if (!gq->dir_tx) { - for (i--, desc = gq->tx_ring; i >= 0; i--, desc++) { + for (desc = gq->tx_ring; i-- > 0; desc++) { dma_addr = rswitch_desc_get_dptr(&desc->desc); dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, DMA_FROM_DEVICE); @@ -398,11 +404,12 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, } static void rswitch_gwca_ts_queue_fill(struct rswitch_private *priv, - int start_index, int num) + unsigned int start_index, + unsigned int num) { struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue; struct rswitch_ts_desc *desc; - int i, index; + unsigned int i, index; for (i = 0; i < num; i++) { index = (i + start_index) % gq->ring_size; @@ -413,12 +420,13 @@ static void rswitch_gwca_ts_queue_fill(struct rswitch_private *priv, static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev, struct rswitch_gwca_queue *gq, - int start_index, int num) + unsigned int start_index, + unsigned int num) { struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_ext_ts_desc *desc; + unsigned int i, index; dma_addr_t dma_addr; - int i, index; for (i = 0; i < num; i++) { index = (i + start_index) % gq->ring_size; @@ -444,7 +452,7 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev, err: if (!gq->dir_tx) { - for (i--; i >= 0; i--) { + for (; i-- > 0; ) { index = (i + start_index) % gq->ring_size; desc = &gq->rx_ring[index]; dma_addr = rswitch_desc_get_dptr(&desc->desc); @@ -460,7 +468,7 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev, struct rswitch_private *priv, struct rswitch_gwca_queue *gq) { - int ring_size = sizeof(struct rswitch_ext_ts_desc) * gq->ring_size; + unsigned int ring_size = sizeof(struct rswitch_ext_ts_desc) * gq->ring_size; struct rswitch_ext_ts_desc *desc; struct rswitch_desc *linkfix; int err; @@ -487,7 +495,7 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev, static int rswitch_gwca_linkfix_alloc(struct rswitch_private *priv) { - int i, num_queues = priv->gwca.num_queues; + unsigned int i, num_queues = priv->gwca.num_queues; struct rswitch_gwca *gwca = &priv->gwca; struct device *dev = &priv->pdev->dev; @@ -537,7 +545,7 @@ static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv) static struct rswitch_gwca_queue *rswitch_gwca_get(struct rswitch_private *priv) { struct rswitch_gwca_queue *gq; - int index; + unsigned int index; index = find_first_zero_bit(priv->gwca.used, priv->gwca.num_queues); if (index >= priv->gwca.num_queues) @@ -583,7 +591,7 @@ static void rswitch_txdmac_free(struct net_device *ndev) rswitch_gwca_put(rdev->priv, rdev->tx_queue); } -static int rswitch_txdmac_init(struct rswitch_private *priv, int index) +static int rswitch_txdmac_init(struct rswitch_private *priv, unsigned int index) { struct rswitch_device *rdev = priv->rdev[index]; @@ -617,7 +625,7 @@ static void rswitch_rxdmac_free(struct net_device *ndev) rswitch_gwca_put(rdev->priv, rdev->rx_queue); } -static int rswitch_rxdmac_init(struct rswitch_private *priv, int index) +static int rswitch_rxdmac_init(struct rswitch_private *priv, unsigned int index) { struct rswitch_device *rdev = priv->rdev[index]; struct net_device *ndev = rdev->ndev; @@ -627,7 +635,8 @@ static int rswitch_rxdmac_init(struct rswitch_private *priv, int index) static int rswitch_gwca_hw_init(struct rswitch_private *priv) { - int i, err; + unsigned int i; + int err; err = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); if (err < 0) @@ -698,9 +707,10 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_gwca_queue *gq = rdev->rx_queue; struct rswitch_ext_ts_desc *desc; - int limit, boguscnt, num, ret; + int limit, boguscnt, ret; struct sk_buff *skb; dma_addr_t dma_addr; + unsigned int num; u16 pkt_len; u32 get_ts; @@ -768,7 +778,7 @@ static void rswitch_tx_free(struct net_device *ndev) struct rswitch_ext_desc *desc; dma_addr_t dma_addr; struct sk_buff *skb; - int size; + unsigned int size; for (; rswitch_get_num_cur_queues(gq) > 0; gq->dirty = rswitch_next_queue_index(gq, false, 1)) { @@ -847,7 +857,7 @@ static void rswitch_queue_interrupt(struct net_device *ndev) static irqreturn_t rswitch_data_irq(struct rswitch_private *priv, u32 *dis) { struct rswitch_gwca_queue *gq; - int i, index, bit; + unsigned int i, index, bit; for (i = 0; i < priv->gwca.num_queues; i++) { gq = &priv->gwca.queues[i]; @@ -914,8 +924,8 @@ static void rswitch_ts(struct rswitch_private *priv) struct skb_shared_hwtstamps shhwtstamps; struct rswitch_ts_desc *desc; struct timespec64 ts; + unsigned int num; u32 tag, port; - int num; desc = &gq->ts_ring[gq->cur]; while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY_ND) { @@ -1434,7 +1444,7 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv) static void rswitch_ether_port_deinit_all(struct rswitch_private *priv) { - int i; + unsigned int i; for (i = 0; i < RSWITCH_NUM_PORTS; i++) { phy_exit(priv->rdev[i]->serdes); @@ -1689,7 +1699,7 @@ static const struct of_device_id renesas_eth_sw_of_table[] = { }; MODULE_DEVICE_TABLE(of, renesas_eth_sw_of_table); -static void rswitch_etha_init(struct rswitch_private *priv, int index) +static void rswitch_etha_init(struct rswitch_private *priv, unsigned int index) { struct rswitch_etha *etha = &priv->etha[index]; @@ -1705,7 +1715,7 @@ static void rswitch_etha_init(struct rswitch_private *priv, int index) etha->psmcs = clk_get_rate(priv->clk) / 100000 / (25 * 2) - 1; } -static int rswitch_device_alloc(struct rswitch_private *priv, int index) +static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index) { struct platform_device *pdev = priv->pdev; struct rswitch_device *rdev; @@ -1776,7 +1786,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index) return err; } -static void rswitch_device_free(struct rswitch_private *priv, int index) +static void rswitch_device_free(struct rswitch_private *priv, unsigned int index) { struct rswitch_device *rdev = priv->rdev[index]; struct net_device *ndev = rdev->ndev; diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 27c9d3872c0e..f1c7f7cdefc2 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -909,7 +909,7 @@ struct rswitch_ext_ts_desc { } __packed; struct rswitch_etha { - int index; + unsigned int index; void __iomem *addr; void __iomem *coma_addr; bool external_phy; @@ -938,12 +938,12 @@ struct rswitch_gwca_queue { /* Common */ dma_addr_t ring_dma; - int ring_size; - int cur; - int dirty; + unsigned int ring_size; + unsigned int cur; + unsigned int dirty; - /* For [rt]_ring */ - int index; + /* For [rt]x_ring */ + unsigned int index; bool dir_tx; struct sk_buff **skbs; struct net_device *ndev; /* queue to ndev for irq */ @@ -959,7 +959,7 @@ struct rswitch_gwca_ts_info { #define RSWITCH_NUM_IRQ_REGS (RSWITCH_MAX_NUM_QUEUES / BITS_PER_TYPE(u32)) struct rswitch_gwca { - int index; + unsigned int index; struct rswitch_desc *linkfix_table; dma_addr_t linkfix_table_dma; u32 linkfix_table_size; From 6a203cb5165d2257e8d54193b69afdb480a17f6f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:24 +0900 Subject: [PATCH 3493/7721] net: rswitch: Use build_skb() for RX If this hardware receives a jumbo frame like 2KiB or more, it will be split into multiple queues. In the near future, to support this, use build_skb() instead of netdev_alloc_skb_ip_align(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 73 +++++++++++++++----------- drivers/net/ethernet/renesas/rswitch.h | 19 ++++++- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 0928003ad245..c6a96abe9dba 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -235,19 +235,18 @@ static bool rswitch_is_queue_rxed(struct rswitch_gwca_queue *gq) return false; } -static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq, - unsigned int start_index, - unsigned int num) +static int rswitch_gwca_queue_alloc_rx_buf(struct rswitch_gwca_queue *gq, + unsigned int start_index, + unsigned int num) { unsigned int i, index; for (i = 0; i < num; i++) { index = (i + start_index) % gq->ring_size; - if (gq->skbs[index]) + if (gq->rx_bufs[index]) continue; - gq->skbs[index] = netdev_alloc_skb_ip_align(gq->ndev, - PKT_BUF_SZ + RSWITCH_ALIGN - 1); - if (!gq->skbs[index]) + gq->rx_bufs[index] = netdev_alloc_frag(RSWITCH_BUF_SIZE); + if (!gq->rx_bufs[index]) goto err; } @@ -256,8 +255,8 @@ static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq, err: for (; i-- > 0; ) { index = (i + start_index) % gq->ring_size; - dev_kfree_skb(gq->skbs[index]); - gq->skbs[index] = NULL; + skb_free_frag(gq->rx_bufs[index]); + gq->rx_bufs[index] = NULL; } return -ENOMEM; @@ -275,16 +274,17 @@ static void rswitch_gwca_queue_free(struct net_device *ndev, gq->rx_ring = NULL; for (i = 0; i < gq->ring_size; i++) - dev_kfree_skb(gq->skbs[i]); + skb_free_frag(gq->rx_bufs[i]); + kfree(gq->rx_bufs); + gq->rx_bufs = NULL; } else { dma_free_coherent(ndev->dev.parent, sizeof(struct rswitch_ext_desc) * (gq->ring_size + 1), gq->tx_ring, gq->ring_dma); gq->tx_ring = NULL; + kfree(gq->skbs); + gq->skbs = NULL; } - - kfree(gq->skbs); - gq->skbs = NULL; } static void rswitch_gwca_ts_queue_free(struct rswitch_private *priv) @@ -308,17 +308,20 @@ static int rswitch_gwca_queue_alloc(struct net_device *ndev, gq->ring_size = ring_size; gq->ndev = ndev; - gq->skbs = kcalloc(gq->ring_size, sizeof(*gq->skbs), GFP_KERNEL); - if (!gq->skbs) - return -ENOMEM; - if (!dir_tx) { - rswitch_gwca_queue_alloc_skb(gq, 0, gq->ring_size); + gq->rx_bufs = kcalloc(gq->ring_size, sizeof(*gq->rx_bufs), GFP_KERNEL); + if (!gq->rx_bufs) + return -ENOMEM; + if (rswitch_gwca_queue_alloc_rx_buf(gq, 0, gq->ring_size) < 0) + goto out; gq->rx_ring = dma_alloc_coherent(ndev->dev.parent, sizeof(struct rswitch_ext_ts_desc) * (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL); } else { + gq->skbs = kcalloc(gq->ring_size, sizeof(*gq->skbs), GFP_KERNEL); + if (!gq->skbs) + return -ENOMEM; gq->tx_ring = dma_alloc_coherent(ndev->dev.parent, sizeof(struct rswitch_ext_desc) * (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL); @@ -367,12 +370,13 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, for (i = 0, desc = gq->tx_ring; i < gq->ring_size; i++, desc++) { if (!gq->dir_tx) { dma_addr = dma_map_single(ndev->dev.parent, - gq->skbs[i]->data, PKT_BUF_SZ, + gq->rx_bufs[i] + RSWITCH_HEADROOM, + RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(ndev->dev.parent, dma_addr)) goto err; - desc->desc.info_ds = cpu_to_le16(PKT_BUF_SZ); + desc->desc.info_ds = cpu_to_le16(RSWITCH_DESC_BUF_SIZE); rswitch_desc_set_dptr(&desc->desc, dma_addr); desc->desc.die_dt = DT_FEMPTY | DIE; } else { @@ -395,8 +399,8 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, if (!gq->dir_tx) { for (desc = gq->tx_ring; i-- > 0; desc++) { dma_addr = rswitch_desc_get_dptr(&desc->desc); - dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, - DMA_FROM_DEVICE); + dma_unmap_single(ndev->dev.parent, dma_addr, + RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); } } @@ -433,12 +437,13 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev, desc = &gq->rx_ring[index]; if (!gq->dir_tx) { dma_addr = dma_map_single(ndev->dev.parent, - gq->skbs[index]->data, PKT_BUF_SZ, + gq->rx_bufs[index] + RSWITCH_HEADROOM, + RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(ndev->dev.parent, dma_addr)) goto err; - desc->desc.info_ds = cpu_to_le16(PKT_BUF_SZ); + desc->desc.info_ds = cpu_to_le16(RSWITCH_DESC_BUF_SIZE); rswitch_desc_set_dptr(&desc->desc, dma_addr); dma_wmb(); desc->desc.die_dt = DT_FEMPTY | DIE; @@ -456,8 +461,8 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev, index = (i + start_index) % gq->ring_size; desc = &gq->rx_ring[index]; dma_addr = rswitch_desc_get_dptr(&desc->desc); - dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, - DMA_FROM_DEVICE); + dma_unmap_single(ndev->dev.parent, dma_addr, + RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); } } @@ -724,10 +729,15 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) { dma_rmb(); pkt_len = le16_to_cpu(desc->desc.info_ds) & RX_DS; - skb = gq->skbs[gq->cur]; - gq->skbs[gq->cur] = NULL; dma_addr = rswitch_desc_get_dptr(&desc->desc); - dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, DMA_FROM_DEVICE); + dma_unmap_single(ndev->dev.parent, dma_addr, + RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); + skb = build_skb(gq->rx_bufs[gq->cur], RSWITCH_BUF_SIZE); + if (!skb) + goto out; + skb_reserve(skb, RSWITCH_HEADROOM); + skb_put(skb, pkt_len); + get_ts = rdev->priv->ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT; if (get_ts) { struct skb_shared_hwtstamps *shhwtstamps; @@ -739,12 +749,13 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff)); shhwtstamps->hwtstamp = timespec64_to_ktime(ts); } - skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); napi_gro_receive(&rdev->napi, skb); rdev->ndev->stats.rx_packets++; rdev->ndev->stats.rx_bytes += pkt_len; +out: + gq->rx_bufs[gq->cur] = NULL; gq->cur = rswitch_next_queue_index(gq, true, 1); desc = &gq->rx_ring[gq->cur]; @@ -753,7 +764,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) } num = rswitch_get_num_cur_queues(gq); - ret = rswitch_gwca_queue_alloc_skb(gq, gq->dirty, num); + ret = rswitch_gwca_queue_alloc_rx_buf(gq, gq->dirty, num); if (ret < 0) goto err; ret = rswitch_gwca_queue_ext_ts_fill(ndev, gq, gq->dirty, num); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index f1c7f7cdefc2..a407d85dcfad 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -29,8 +29,13 @@ #define RX_RING_SIZE 1024 #define TS_RING_SIZE (TX_RING_SIZE * RSWITCH_NUM_PORTS) -#define PKT_BUF_SZ 1584 +#define RSWITCH_HEADROOM (NET_SKB_PAD + NET_IP_ALIGN) +#define RSWITCH_DESC_BUF_SIZE 2048 +#define RSWITCH_TAILROOM SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) #define RSWITCH_ALIGN 128 +#define RSWITCH_BUF_SIZE (RSWITCH_HEADROOM + RSWITCH_DESC_BUF_SIZE + \ + RSWITCH_TAILROOM + RSWITCH_ALIGN) +#define RSWITCH_MAP_BUF_SIZE (RSWITCH_BUF_SIZE - RSWITCH_HEADROOM) #define RSWITCH_MAX_CTAG_PCP 7 #define RSWITCH_TIMEOUT_US 100000 @@ -945,8 +950,18 @@ struct rswitch_gwca_queue { /* For [rt]x_ring */ unsigned int index; bool dir_tx; - struct sk_buff **skbs; struct net_device *ndev; /* queue to ndev for irq */ + + union { + /* For TX */ + struct { + struct sk_buff **skbs; + }; + /* For RX */ + struct { + void **rx_bufs; + }; + }; }; struct rswitch_gwca_ts_info { From 271e015b91535dd87fd0f5df0cc3b906c2eddef9 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:25 +0900 Subject: [PATCH 3494/7721] net: rswitch: Add unmap_addrs instead of dma address in each desc If the driver would like to transmit a jumbo frame like 2KiB or more, it should be split into multiple queues. In the near future, to support this, add unmap_addrs array to unmap dma mapping address instead of dma address in each TX descriptor because the descriptors may not have the top dma address. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 19 +++++++++++-------- drivers/net/ethernet/renesas/rswitch.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index c6a96abe9dba..c2125fefc8c5 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -284,6 +284,8 @@ static void rswitch_gwca_queue_free(struct net_device *ndev, gq->tx_ring = NULL; kfree(gq->skbs); gq->skbs = NULL; + kfree(gq->unmap_addrs); + gq->unmap_addrs = NULL; } } @@ -322,6 +324,9 @@ static int rswitch_gwca_queue_alloc(struct net_device *ndev, gq->skbs = kcalloc(gq->ring_size, sizeof(*gq->skbs), GFP_KERNEL); if (!gq->skbs) return -ENOMEM; + gq->unmap_addrs = kcalloc(gq->ring_size, sizeof(*gq->unmap_addrs), GFP_KERNEL); + if (!gq->unmap_addrs) + goto out; gq->tx_ring = dma_alloc_coherent(ndev->dev.parent, sizeof(struct rswitch_ext_desc) * (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL); @@ -787,9 +792,7 @@ static void rswitch_tx_free(struct net_device *ndev) struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_gwca_queue *gq = rdev->tx_queue; struct rswitch_ext_desc *desc; - dma_addr_t dma_addr; struct sk_buff *skb; - unsigned int size; for (; rswitch_get_num_cur_queues(gq) > 0; gq->dirty = rswitch_next_queue_index(gq, false, 1)) { @@ -798,18 +801,17 @@ static void rswitch_tx_free(struct net_device *ndev) break; dma_rmb(); - size = le16_to_cpu(desc->desc.info_ds) & TX_DS; skb = gq->skbs[gq->dirty]; if (skb) { - dma_addr = rswitch_desc_get_dptr(&desc->desc); - dma_unmap_single(ndev->dev.parent, dma_addr, - size, DMA_TO_DEVICE); + dma_unmap_single(ndev->dev.parent, + gq->unmap_addrs[gq->dirty], + skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(gq->skbs[gq->dirty]); gq->skbs[gq->dirty] = NULL; + rdev->ndev->stats.tx_packets++; + rdev->ndev->stats.tx_bytes += skb->len; } desc->desc.die_dt = DT_EEMPTY; - rdev->ndev->stats.tx_packets++; - rdev->ndev->stats.tx_bytes += size; } } @@ -1538,6 +1540,7 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd goto err_kfree; gq->skbs[gq->cur] = skb; + gq->unmap_addrs[gq->cur] = dma_addr; desc = &gq->tx_ring[gq->cur]; rswitch_desc_set_dptr(&desc->desc, dma_addr); desc->desc.info_ds = cpu_to_le16(skb->len); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index a407d85dcfad..2ac9a86b6238 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -956,6 +956,7 @@ struct rswitch_gwca_queue { /* For TX */ struct { struct sk_buff **skbs; + dma_addr_t *unmap_addrs; }; /* For RX */ struct { From fcff581ee43078cf23216aa7079012e935a6a078 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:26 +0900 Subject: [PATCH 3495/7721] net: rswitch: Add a setting ext descriptor function If the driver would like to transmit a jumbo frame like 2KiB or more, it should be split into multiple queues. In the near future, to support this, add a setting ext descriptor function to improve code readability. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 73 +++++++++++++++++--------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index c2125fefc8c5..eda5ea56674c 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1519,6 +1519,51 @@ static int rswitch_stop(struct net_device *ndev) return 0; }; +static bool rswitch_ext_desc_set_info1(struct rswitch_device *rdev, + struct sk_buff *skb, + struct rswitch_ext_desc *desc) +{ + desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) | + INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT); + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + struct rswitch_gwca_ts_info *ts_info; + + ts_info = kzalloc(sizeof(*ts_info), GFP_ATOMIC); + if (!ts_info) + return false; + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + rdev->ts_tag++; + desc->info1 |= cpu_to_le64(INFO1_TSUN(rdev->ts_tag) | INFO1_TXC); + + ts_info->skb = skb_get(skb); + ts_info->port = rdev->port; + ts_info->tag = rdev->ts_tag; + list_add_tail(&ts_info->list, &rdev->priv->gwca.ts_info_list); + + skb_tx_timestamp(skb); + } + + return true; +} + +static bool rswitch_ext_desc_set(struct rswitch_device *rdev, + struct sk_buff *skb, + struct rswitch_ext_desc *desc, + dma_addr_t dma_addr, u16 len, u8 die_dt) +{ + rswitch_desc_set_dptr(&desc->desc, dma_addr); + desc->desc.info_ds = cpu_to_le16(len); + if (!rswitch_ext_desc_set_info1(rdev, skb, desc)) + return false; + + dma_wmb(); + + desc->desc.die_dt = die_dt; + + return true; +} + static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); @@ -1542,33 +1587,9 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd gq->skbs[gq->cur] = skb; gq->unmap_addrs[gq->cur] = dma_addr; desc = &gq->tx_ring[gq->cur]; - rswitch_desc_set_dptr(&desc->desc, dma_addr); - desc->desc.info_ds = cpu_to_le16(skb->len); + if (!rswitch_ext_desc_set(rdev, skb, desc, dma_addr, skb->len, DT_FSINGLE | DIE)) + goto err_unmap; - desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) | - INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT); - if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { - struct rswitch_gwca_ts_info *ts_info; - - ts_info = kzalloc(sizeof(*ts_info), GFP_ATOMIC); - if (!ts_info) - goto err_unmap; - - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - rdev->ts_tag++; - desc->info1 |= cpu_to_le64(INFO1_TSUN(rdev->ts_tag) | INFO1_TXC); - - ts_info->skb = skb_get(skb); - ts_info->port = rdev->port; - ts_info->tag = rdev->ts_tag; - list_add_tail(&ts_info->list, &rdev->priv->gwca.ts_info_list); - - skb_tx_timestamp(skb); - } - - dma_wmb(); - - desc->desc.die_dt = DT_FSINGLE | DIE; wmb(); /* gq->cur must be incremented after die_dt was set */ gq->cur = rswitch_next_queue_index(gq, true, 1); From 9c90316a1170dd6ee1e620d28f6101f85bbaaa10 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:27 +0900 Subject: [PATCH 3496/7721] net: rswitch: Set GWMDNC register To support jumbo frames, set GWMDNC register with acceptable maximum values for TX and RX. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 2 ++ drivers/net/ethernet/renesas/rswitch.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index eda5ea56674c..6bd76a88bd40 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -668,6 +668,8 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv) iowrite32(upper_32_bits(priv->gwca.linkfix_table_dma), priv->addr + GWDCBAC0); iowrite32(lower_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC10); iowrite32(upper_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC00); + iowrite32(GWMDNC_TSDMN(1) | GWMDNC_TXDMN(0x1e) | GWMDNC_RXDMN(0x1f), + priv->addr + GWMDNC); iowrite32(GWCA_TS_IRQ_BIT, priv->addr + GWTSDCC0); iowrite32(GWTPC_PPPL(GWCA_IPV_NUM), priv->addr + GWTPC0); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 2ac9a86b6238..17e617ec4187 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -773,6 +773,10 @@ enum rswitch_gwca_mode { #define GWARIRM_ARIOG BIT(0) #define GWARIRM_ARR BIT(1) +#define GWMDNC_TSDMN(num) (((num) << 16) & GENMASK(17, 16)) +#define GWMDNC_TXDMN(num) (((num) << 8) & GENMASK(12, 8)) +#define GWMDNC_RXDMN(num) ((num) & GENMASK(4, 0)) + #define GWDCC_BALR BIT(24) #define GWDCC_DCP_MASK GENMASK(18, 16) #define GWDCC_DCP(prio) FIELD_PREP(GWDCC_DCP_MASK, (prio)) From 933416cc59b18ef82ea7895c4ca58be3d92d3b3c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:28 +0900 Subject: [PATCH 3497/7721] net: rswitch: Add jumbo frames handling for RX If this hardware receives a jumbo frame like 2KiB or more, it will be split into multiple queues. In the near future, to support this, add handling specific descriptor types F{START,MID,END}. However, such jumbo frames will not happen yet because the maximum MTU size is still default for now. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 86 +++++++++++++++++++++++--- drivers/net/ethernet/renesas/rswitch.h | 2 + 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 6bd76a88bd40..36c70131594d 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -714,6 +714,80 @@ static int rswitch_gwca_halt(struct rswitch_private *priv) return err; } +static struct sk_buff *rswitch_rx_handle_desc(struct net_device *ndev, + struct rswitch_gwca_queue *gq, + struct rswitch_ext_ts_desc *desc) +{ + dma_addr_t dma_addr = rswitch_desc_get_dptr(&desc->desc); + u16 pkt_len = le16_to_cpu(desc->desc.info_ds) & RX_DS; + u8 die_dt = desc->desc.die_dt & DT_MASK; + struct sk_buff *skb = NULL; + + dma_unmap_single(ndev->dev.parent, dma_addr, RSWITCH_MAP_BUF_SIZE, + DMA_FROM_DEVICE); + + /* The RX descriptor order will be one of the following: + * - FSINGLE + * - FSTART -> FEND + * - FSTART -> FMID -> FEND + */ + + /* Check whether the descriptor is unexpected order */ + switch (die_dt) { + case DT_FSTART: + case DT_FSINGLE: + if (gq->skb_fstart) { + dev_kfree_skb_any(gq->skb_fstart); + gq->skb_fstart = NULL; + ndev->stats.rx_dropped++; + } + break; + case DT_FMID: + case DT_FEND: + if (!gq->skb_fstart) { + ndev->stats.rx_dropped++; + return NULL; + } + break; + default: + break; + } + + /* Handle the descriptor */ + switch (die_dt) { + case DT_FSTART: + case DT_FSINGLE: + skb = build_skb(gq->rx_bufs[gq->cur], RSWITCH_BUF_SIZE); + if (skb) { + skb_reserve(skb, RSWITCH_HEADROOM); + skb_put(skb, pkt_len); + gq->pkt_len = pkt_len; + if (die_dt == DT_FSTART) { + gq->skb_fstart = skb; + skb = NULL; + } + } + break; + case DT_FMID: + case DT_FEND: + skb_add_rx_frag(gq->skb_fstart, skb_shinfo(gq->skb_fstart)->nr_frags, + virt_to_page(gq->rx_bufs[gq->cur]), + offset_in_page(gq->rx_bufs[gq->cur]) + RSWITCH_HEADROOM, + pkt_len, RSWITCH_BUF_SIZE); + if (die_dt == DT_FEND) { + skb = gq->skb_fstart; + gq->skb_fstart = NULL; + } + gq->pkt_len += pkt_len; + break; + default: + netdev_err(ndev, "%s: unexpected value (%x)\n", __func__, die_dt); + break; + } + + return skb; +} + static bool rswitch_rx(struct net_device *ndev, int *quota) { struct rswitch_device *rdev = netdev_priv(ndev); @@ -721,9 +795,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) struct rswitch_ext_ts_desc *desc; int limit, boguscnt, ret; struct sk_buff *skb; - dma_addr_t dma_addr; unsigned int num; - u16 pkt_len; u32 get_ts; if (*quota <= 0) @@ -735,15 +807,9 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) desc = &gq->rx_ring[gq->cur]; while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) { dma_rmb(); - pkt_len = le16_to_cpu(desc->desc.info_ds) & RX_DS; - dma_addr = rswitch_desc_get_dptr(&desc->desc); - dma_unmap_single(ndev->dev.parent, dma_addr, - RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE); - skb = build_skb(gq->rx_bufs[gq->cur], RSWITCH_BUF_SIZE); + skb = rswitch_rx_handle_desc(ndev, gq, desc); if (!skb) goto out; - skb_reserve(skb, RSWITCH_HEADROOM); - skb_put(skb, pkt_len); get_ts = rdev->priv->ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT; if (get_ts) { @@ -759,7 +825,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) skb->protocol = eth_type_trans(skb, ndev); napi_gro_receive(&rdev->napi, skb); rdev->ndev->stats.rx_packets++; - rdev->ndev->stats.rx_bytes += pkt_len; + rdev->ndev->stats.rx_bytes += gq->pkt_len; out: gq->rx_bufs[gq->cur] = NULL; diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 17e617ec4187..4252677e2a55 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -965,6 +965,8 @@ struct rswitch_gwca_queue { /* For RX */ struct { void **rx_bufs; + struct sk_buff *skb_fstart; + u16 pkt_len; }; }; }; From d2c96b9d5f83e4327cf044d00d7f713edd7fecfd Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:29 +0900 Subject: [PATCH 3498/7721] net: rswitch: Add jumbo frames handling for TX If the driver would like to transmit a jumbo frame like 2KiB or more, it should be split into multiple queues. In the near future, to support this, add handling specific descriptor types F{START,MID,END}. However, such jumbo frames will not happen yet because the maximum MTU size is still default for now. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 56 +++++++++++++++++++++----- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 36c70131594d..d43f705f410b 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1632,15 +1632,44 @@ static bool rswitch_ext_desc_set(struct rswitch_device *rdev, return true; } +static u8 rswitch_ext_desc_get_die_dt(unsigned int nr_desc, unsigned int index) +{ + if (nr_desc == 1) + return DT_FSINGLE | DIE; + if (index == 0) + return DT_FSTART; + if (nr_desc - 1 == index) + return DT_FEND | DIE; + return DT_FMID; +} + +static u16 rswitch_ext_desc_get_len(u8 die_dt, unsigned int orig_len) +{ + switch (die_dt & DT_MASK) { + case DT_FSINGLE: + case DT_FEND: + return (orig_len % RSWITCH_DESC_BUF_SIZE) ?: RSWITCH_DESC_BUF_SIZE; + case DT_FSTART: + case DT_FMID: + return RSWITCH_DESC_BUF_SIZE; + default: + return 0; + } +} + static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_gwca_queue *gq = rdev->tx_queue; + dma_addr_t dma_addr, dma_addr_orig; netdev_tx_t ret = NETDEV_TX_OK; struct rswitch_ext_desc *desc; - dma_addr_t dma_addr; + unsigned int i, nr_desc; + u8 die_dt; + u16 len; - if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - 1) { + nr_desc = (skb->len - 1) / RSWITCH_DESC_BUF_SIZE + 1; + if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - nr_desc) { netif_stop_subqueue(ndev, 0); return NETDEV_TX_BUSY; } @@ -1648,25 +1677,32 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd if (skb_put_padto(skb, ETH_ZLEN)) return ret; - dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(ndev->dev.parent, dma_addr)) + dma_addr_orig = dma_map_single(ndev->dev.parent, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, dma_addr_orig)) goto err_kfree; gq->skbs[gq->cur] = skb; - gq->unmap_addrs[gq->cur] = dma_addr; - desc = &gq->tx_ring[gq->cur]; - if (!rswitch_ext_desc_set(rdev, skb, desc, dma_addr, skb->len, DT_FSINGLE | DIE)) - goto err_unmap; + gq->unmap_addrs[gq->cur] = dma_addr_orig; + + /* DT_FSTART should be set at last. So, this is reverse order. */ + for (i = nr_desc; i-- > 0; ) { + desc = &gq->tx_ring[rswitch_next_queue_index(gq, true, i)]; + die_dt = rswitch_ext_desc_get_die_dt(nr_desc, i); + dma_addr = dma_addr_orig + i * RSWITCH_DESC_BUF_SIZE; + len = rswitch_ext_desc_get_len(die_dt, skb->len); + if (!rswitch_ext_desc_set(rdev, skb, desc, dma_addr, len, die_dt)) + goto err_unmap; + } wmb(); /* gq->cur must be incremented after die_dt was set */ - gq->cur = rswitch_next_queue_index(gq, true, 1); + gq->cur = rswitch_next_queue_index(gq, true, nr_desc); rswitch_modify(rdev->addr, GWTRC(gq->index), 0, BIT(gq->index % 32)); return ret; err_unmap: - dma_unmap_single(ndev->dev.parent, dma_addr, skb->len, DMA_TO_DEVICE); + dma_unmap_single(ndev->dev.parent, dma_addr_orig, skb->len, DMA_TO_DEVICE); err_kfree: dev_kfree_skb_any(skb); From c71517fe7353d2cbfbf2e305b282bf23c1750e29 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Dec 2023 13:10:30 +0900 Subject: [PATCH 3499/7721] net: rswitch: Allow jumbo frames Allow jumbo frames by changing maximum MTU size and number of RX queues. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 2 ++ drivers/net/ethernet/renesas/rswitch.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index d43f705f410b..dcab638c57fe 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1883,6 +1883,8 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index snprintf(ndev->name, IFNAMSIZ, "tsn%d", index); ndev->netdev_ops = &rswitch_netdev_ops; ndev->ethtool_ops = &rswitch_ethtool_ops; + ndev->max_mtu = RSWITCH_MAX_MTU; + ndev->min_mtu = ETH_MIN_MTU; netif_napi_add(ndev, &rdev->napi, rswitch_poll); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 4252677e2a55..72e3ff596d31 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -26,9 +26,10 @@ else #define TX_RING_SIZE 1024 -#define RX_RING_SIZE 1024 +#define RX_RING_SIZE 4096 #define TS_RING_SIZE (TX_RING_SIZE * RSWITCH_NUM_PORTS) +#define RSWITCH_MAX_MTU 9600 #define RSWITCH_HEADROOM (NET_SKB_PAD + NET_IP_ALIGN) #define RSWITCH_DESC_BUF_SIZE 2048 #define RSWITCH_TAILROOM SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) From 236fa3873de8f1d4b0c7eaeb4c53b4d1220d55a0 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 3 Dec 2023 01:13:53 +0300 Subject: [PATCH 3500/7721] drm/ci: remove rebase-merge directory Gitlab runner can cache git repository, including the unfinished rebase merge status. New CI job will come as a fresh checkout, however this will not destroy the unfinished rebase, failing our build script. Destroy the unfinished rebase state. Suggested-by: David Heidelberg Signed-off-by: Dmitry Baryshkov Acked-by: Helen Koike Patchwork: https://patchwork.freedesktop.org/patch/570159/ Signed-off-by: Rob Clark --- drivers/gpu/drm/ci/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh index e5c5dcedd108..ca2923ed2290 100644 --- a/drivers/gpu/drm/ci/build.sh +++ b/drivers/gpu/drm/ci/build.sh @@ -58,6 +58,9 @@ git config --global user.email "fdo@example.com" git config --global user.name "freedesktop.org CI" git config --global pull.rebase true +# cleanup git state on the worker +rm -rf .git/rebase-merge + # Try to merge fixes from target repo if [ "$(git ls-remote --exit-code --heads ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes)" ]; then git pull ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes From e4f027756dff6a4e2abc640f276f91219559a3c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 10 Dec 2023 14:48:34 +0100 Subject: [PATCH 3501/7721] dt-bindings: samsung: exynos-sysreg: combine exynosautov920 with other enum No need to create a new enum every time we bring-up new SoC. Reviewed-by: Sam Protsenko Reviewed-by: Jaewon Kim Link: https://lore.kernel.org/r/20231210134834.43943-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/soc/samsung/samsung,exynos-sysreg.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 925f787e1ea1..1794e3799f21 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -20,6 +20,8 @@ properties: - samsung,exynos3-sysreg - samsung,exynos4-sysreg - samsung,exynos5-sysreg + - samsung,exynosautov920-peric0-sysreg + - samsung,exynosautov920-peric1-sysreg - tesla,fsd-cam-sysreg - tesla,fsd-fsys0-sysreg - tesla,fsd-fsys1-sysreg @@ -53,11 +55,6 @@ properties: - samsung,exynosautov9-peric1-sysreg - const: samsung,exynosautov9-sysreg - const: syscon - - items: - - enum: - - samsung,exynosautov920-peric0-sysreg - - samsung,exynosautov920-peric1-sysreg - - const: syscon reg: maxItems: 1 From c96dab1993d247b7b05ba2fdef8f185cbbd5454e Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Fri, 8 Dec 2023 16:45:24 +0900 Subject: [PATCH 3502/7721] arm64: dts: exynos: add initial support for exynosautov920 SoC Samsung ExynosAutov920 is ARMv8-based automotive-oriented SoC. It has AE(Automotive Enhanced) IPs for safety. * Cortex-A78AE 10-cores * GIC-600AE This is minimal support for ExynosAutov920 SoC. * Enumerate all pinctrl nodes * Enable Chip-Id * Serial0 for console * PWM Since the clock driver is not yet implemented, it is supported as fixed-clock. Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231208074527.50840-2-jaewon02.kim@samsung.com [krzysztof: Re-order nodes to match coding style: UFS reset pins, gpg/gpp in peric0 and peric1, all nodes in the soc@0; drop fallback compatibles from wakeup-interrupt-controller] Signed-off-by: Krzysztof Kozlowski --- .../dts/exynos/exynosautov920-pinctrl.dtsi | 1266 +++++++++++++++++ .../arm64/boot/dts/exynos/exynosautov920.dtsi | 312 ++++ 2 files changed, 1578 insertions(+) create mode 100644 arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/exynos/exynosautov920.dtsi diff --git a/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi new file mode 100644 index 000000000000..663e8265cbf5 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi @@ -0,0 +1,1266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SoC pin-mux and pin-config device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + * Samsung's ExynosAutov920 SoC pin-mux and pin-config options are listed as + * device tree nodes in this file. + */ + +#include + +#include "exynos-pinctrl.h" + +&pinctrl_alive { + gpa0: gpa0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa1: gpa1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; + + gpq0: gpq0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_aud { + gpb0: gpb0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb1: gpb1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb2: gpb2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb3: gpb3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb4: gpb4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb5: gpb5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb6: gpb6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi0 { + gph0: gph0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph1: gph1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi1 { + gph8: gph8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi2 { + gph3: gph3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph4: gph4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph5: gph5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph6: gph6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi2ufs { + gph2: gph2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ufs_refclk_out: ufs-refclk-out-pins { + samsung,pins = "gph2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_rst_n: ufs-rst-n-pins { + samsung,pins = "gph2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_refclk_out_1: ufs-refclk-out-1-pins { + samsung,pins = "gph2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_rst_n_1: ufs-rst-n-1-pins { + samsung,pins = "gph2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_peric0 { + gpg0: gpg0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg2: gpg2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg3: gpg3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg4: gpg4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg5: gpg5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp0: gpp0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp1: gpp1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp2: gpp2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp3: gpp3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp4: gpp4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* PWM PERIC0 */ + pwm_tout0: pwm-tout0-pins { + samsung,pins = "gpg0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout1: pwm-tout1-pins { + samsung,pins = "gpg0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout2: pwm-tout2-pins { + samsung,pins = "gpg0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout3: pwm-tout3-pins { + samsung,pins = "gpg0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI00 */ + uart0_bus: uart0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1", "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart0_bus_dual: uart0-bus-dual-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI01 */ + uart1_bus: uart1-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5", "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart1_bus_dual: uart1-bus-dual-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI02 */ + uart2_bus: uart2-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1", "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus_dual: uart2-bus-dual-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI03 */ + uart3_bus: uart3-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5", "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus_dual: uart3-bus-dual-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI04 */ + uart4_bus: uart4-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus_dual: uart4-bus-dual-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI05 */ + uart5_bus: uart5-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5", "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus_dual: uart5-bus-dual-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI06 */ + uart6_bus: uart6-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1", "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart6_bus_dual: uart6-bus-dual-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI07 */ + uart7_bus: uart7-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5", "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus_dual: uart7-bus-dual-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI08 */ + uart8_bus: uart8-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart8_bus_dual: uart8-bus-dual-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI00 */ + hsi2c0_bus: hsi2c0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI00_I2C */ + hsi2c1_bus: hsi2c1-bus-pins { + samsung,pins = "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI01 */ + hsi2c2_bus: hsi2c2-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI01_I2C */ + hsi2c3_bus: hsi2c3-bus-pins { + samsung,pins = "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI02 */ + hsi2c4_bus: hsi2c4-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI02_I2C */ + hsi2c5_bus: hsi2c5-bus-pins { + samsung,pins = "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI03 */ + hsi2c6_bus: hsi2c6-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI03_I2C */ + hsi2c7_bus: hsi2c7-bus-pins { + samsung,pins = "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI04 */ + hsi2c8_bus: hsi2c8-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI04_I2C */ + hsi2c9_bus: hsi2c9-bus-pins { + samsung,pins = "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI05 */ + hsi2c10_bus: hsi2c10-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI05_I2C */ + hsi2c11_bus: hsi2c11-bus-pins { + samsung,pins = "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI06 */ + hsi2c12_bus: hsi2c12-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI06_I2C */ + hsi2c13_bus: hsi2c13-bus-pins { + samsung,pins = "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI07 */ + hsi2c14_bus: hsi2c14-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI07_I2C */ + hsi2c15_bus: hsi2c15-bus-pins { + samsung,pins = "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI08 */ + hsi2c16_bus: hsi2c16-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI08_I2C */ + hsi2c17_bus: hsi2c17-bus-pins { + samsung,pins = "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI00 */ + spi0_bus: spi0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1", "gpp0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi0_cs: spi0-cs-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi0_cs_func: spi0-cs-func-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI01 */ + spi1_bus: spi1-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5", "gpp0-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi1_cs: spi1-cs-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi1_cs_func: spi1-cs-func-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI02 */ + spi2_bus: spi2-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1", "gpp1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi2_cs: spi2-cs-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi2_cs_func: spi2-cs-func-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI03 */ + spi3_bus: spi3-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5", "gpp1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi3_cs: spi3-cs-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi3_cs_func: spi3-cs-func-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI04 */ + spi4_bus: spi4-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi4_cs: spi4-cs-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi4_cs_func: spi4-cs-func-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI05 */ + spi5_bus: spi5-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5", "gpp2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi5_cs: spi5-cs-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi5_cs_func: spi5-cs-func-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI06 */ + spi6_bus: spi6-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1", "gpp3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi6_cs: spi6-cs-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi6_cs_func: spi6-cs-func-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI07 */ + spi7_bus: spi7-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5", "gpp3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi7_cs: spi7-cs-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi7_cs_func: spi7-cs-func-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI08 */ + spi8_bus: spi8-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi8_cs: spi8-cs-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi8_cs_func: spi8-cs-func-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I3C PERIC0 */ + i3c0_bus: i3c0-bus-pins { + samsung,pins = "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c1_bus: i3c1-bus-pins { + samsung,pins = "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c2_bus: i3c2-bus-pins { + samsung,pins = "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c3_bus: i3c3-bus-pins { + samsung,pins = "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_peric1 { + gpg1: gpg1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp5: gpp5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp6: gpp6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp7: gpp7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp8: gpp8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp9: gpp9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp10: gpp10-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp11: gpp11-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp12: gpp12-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* UART PERIC1 USI09 */ + uart9_bus: uart9-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1", "gpp5-2", "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus_dual: uart9-bus-dual-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI10 */ + uart10_bus: uart10-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5", "gpp5-6", "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus_dual: uart10-bus-dual-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI11 */ + uart11_bus: uart11-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", "gpp10-2", "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus_dual: uart11-bus-dual-pins { + samsung,pins = "gpp10-0", "gpp10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1_USI12 */ + uart12_bus: uart12-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1", "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus_dual: uart12-bus-dual-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1_USI13 */ + uart13_bus: uart13-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5", "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus_dual: uart13-bus-dual-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI14 */ + uart14_bus: uart14-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus_dual: uart14-bus-dual-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI15 */ + uart15_bus: uart15-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1", "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus_dual: uart15-bus-dual-pins { + samsung,pins = "gpp11-0", "gpp11-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI16 */ + uart16_bus: uart16-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1", "gpp9-2", "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart16_bus_dual: uart16-bus-dual-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI17 */ + uart17_bus: uart17-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", "gpp12-2", "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart17_bus_dual: uart17-bus-dual-pins { + samsung,pins = "gpp12-0", "gpp12-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI09 */ + hsi2c18_bus: hsi2c18-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI09_I2C */ + hsi2c19_bus: hsi2c19-bus-pins { + samsung,pins = "gpp5-2", "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI10 */ + hsi2c20_bus: hsi2c20-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI10_I2C */ + hsi2c21_bus: hsi2c21-bus-pins { + samsung,pins = "gpp5-6", "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI11 */ + hsi2c22_bus: hsi2c22-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI11_I2C */ + hsi2c23_bus: hsi2c23-bus-pins { + samsung,pins = "gpp10-2", "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI12 */ + hsi2c24_bus: hsi2c24-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI12_I2C */ + hsi2c25_bus: hsi2c25-bus-pins { + samsung,pins = "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI13 */ + hsi2c26_bus: hsi2c26-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI13_I2C */ + hsi2c27_bus: hsi2c27-bus-pins { + samsung,pins = "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI14 */ + hsi2c28_bus: hsi2c28-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI14_I2C */ + hsi2c29_bus: hsi2c29-bus-pins { + samsung,pins = "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI15 */ + hsi2c30_bus: hsi2c30-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI15_I2C */ + hsi2c31_bus: hsi2c31-bus-pins { + samsung,pins = "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI16 */ + hsi2c32_bus: hsi2c32-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI16_I2C */ + hsi2c33_bus: hsi2c33-bus-pins { + samsung,pins = "gpp9-2", "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI17 */ + hsi2c34_bus: hsi2c34-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI17_I2C */ + hsi2c35_bus: hsi2c35-bus-pins { + samsung,pins = "gpp12-2", "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI09 */ + spi9_bus: spi9-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1", "gpp5-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi9_cs: spi9-cs-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi9_cs_func: spi9-cs-func-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI10 */ + spi10_bus: spi10-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5", "gpp5-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi10_cs: spi10-cs-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi10_cs_func: spi10-cs-func-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI11 */ + spi11_bus: spi11-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", "gpp10-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi11_cs: spi11-cs-pins { + samsung,pins = "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi11_cs_func: spi11-cs-func-pins { + samsung,pins = "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI12 */ + spi12_bus: spi12-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1", "gpp7-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi12_cs: spi12-cs-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi12_cs_func: spi12-cs-func-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI13 */ + spi13_bus: spi13-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5", "gpp7-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi13_cs: spi13-cs-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi13_cs_func: spi13-cs-func-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI14 */ + spi14_bus: spi14-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", "gpp8-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi14_cs: spi14-cs-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi14_cs_func: spi14-cs-func-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI15 */ + spi15_bus: spi15-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1", "gpp11-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi15_cs: spi15-cs-pins { + samsung,pins = "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi15_cs_func: spi15-cs-func-pins { + samsung,pins = "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI16 */ + spi16_bus: spi16-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1", "gpp9-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi16_cs: spi16-cs-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi16_cs_func: spi16-cs-func-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI17 */ + spi17_bus: spi17-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", "gpp12-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi17_cs: spi17-cs-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi17_cs_func: spi17-cs-func-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I3C PERIC1 */ + i3c4_bus: i3c4-bus-pins { + samsung,pins = "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c5_bus: i3c5-bus-pins { + samsung,pins = "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c6_bus: i3c6-bus-pins { + samsung,pins = "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c7_bus: i3c7-bus-pins { + samsung,pins = "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi new file mode 100644 index 000000000000..c1c8566d74f5 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SoC device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + */ + +#include +#include + +/ { + compatible = "samsung,exynosautov920"; + #address-cells = <2>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_alive; + pinctrl1 = &pinctrl_aud; + pinctrl2 = &pinctrl_hsi0; + pinctrl3 = &pinctrl_hsi1; + pinctrl4 = &pinctrl_hsi2; + pinctrl5 = &pinctrl_hsi2ufs; + pinctrl6 = &pinctrl_peric0; + pinctrl7 = &pinctrl_peric1; + }; + + arm-pmu { + compatible = "arm,cortex-a78-pmu"; + interrupts = ; + }; + + xtcxo: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "oscclk"; + }; + + /* + * FIXME: Keep the stub clock for serial driver, until proper clock + * driver is implemented. + */ + clock_usi: clock-usi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "usi"; + }; + + cpus: cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu4>; + }; + core1 { + cpu = <&cpu5>; + }; + core2 { + cpu = <&cpu6>; + }; + core3 { + cpu = <&cpu7>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu8>; + }; + core1 { + cpu = <&cpu9>; + }; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x100>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x200>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x300>; + enable-method = "psci"; + }; + + cpu4: cpu@10000 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10000>; + enable-method = "psci"; + }; + + cpu5: cpu@10100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10100>; + enable-method = "psci"; + }; + + cpu6: cpu@10200 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10200>; + enable-method = "psci"; + }; + + cpu7: cpu@10300 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10300>; + enable-method = "psci"; + }; + + cpu8: cpu@20000 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x20000>; + enable-method = "psci"; + }; + + cpu9: cpu@20100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x20100>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + soc: soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x20000000>; + + chipid@10000000 { + compatible = "samsung,exynosautov920-chipid", + "samsung,exynos850-chipid"; + reg = <0x10000000 0x24>; + }; + + gic: interrupt-controller@10400000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x10400000 0x10000>, + <0x10460000 0x140000>; + interrupts = ; + }; + + syscon_peric0: syscon@10820000 { + compatible = "samsung,exynosautov920-peric0-sysreg", + "syscon"; + reg = <0x10820000 0x2000>; + }; + + pinctrl_peric0: pinctrl@10830000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x10830000 0x10000>; + interrupts = ; + }; + + usi_0: usi@108800c0 { + compatible = "samsung,exynosautov920-usi", + "samsung,exynos850-usi"; + reg = <0x108800c0 0x20>; + samsung,sysreg = <&syscon_peric0 0x1000>; + samsung,mode = ; + #address-cells = <1>; + #size-cells = <1>; + ranges; + clocks = <&clock_usi>, <&clock_usi>; + clock-names = "pclk", "ipclk"; + status = "disabled"; + + serial_0: serial@10880000 { + compatible = "samsung,exynosautov920-uart", + "samsung,exynos850-uart"; + reg = <0x10880000 0xc0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_bus>; + clocks = <&clock_usi>, <&clock_usi>; + clock-names = "uart", "clk_uart_baud0"; + samsung,uart-fifosize = <256>; + status = "disabled"; + }; + }; + + pwm: pwm@109b0000 { + compatible = "samsung,exynosautov920-pwm", + "samsung,exynos4210-pwm"; + reg = <0x109b0000 0x100>; + samsung,pwm-outputs = <0>, <1>, <2>, <3>; + #pwm-cells = <3>; + clocks = <&xtcxo>; + clock-names = "timers"; + status = "disabled"; + }; + + syscon_peric1: syscon@10c20000 { + compatible = "samsung,exynosautov920-peric1-sysreg", + "syscon"; + reg = <0x10c20000 0x2000>; + }; + + pinctrl_peric1: pinctrl@10c30000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x10c30000 0x10000>; + interrupts = ; + }; + + pinctrl_alive: pinctrl@11850000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x11850000 0x10000>; + + wakeup-interrupt-controller { + compatible = "samsung,exynosautov920-wakeup-eint"; + }; + }; + + pmu_system_controller: system-controller@11860000 { + compatible = "samsung,exynosautov920-pmu", + "samsung,exynos7-pmu","syscon"; + reg = <0x11860000 0x10000>; + }; + + pinctrl_hsi0: pinctrl@16040000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16040000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi1: pinctrl@16450000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16450000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi2: pinctrl@16c10000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16c10000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi2ufs: pinctrl@16d20000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16d20000 0x10000>; + interrupts = ; + }; + + pinctrl_aud: pinctrl@1a460000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x1a460000 0x10000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + , + ; + }; +}; + +#include "exynosautov920-pinctrl.dtsi" From 57de428eaca2b9af1a35df96c7adcad4b5ea79f9 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Fri, 8 Dec 2023 16:45:25 +0900 Subject: [PATCH 3503/7721] arm64: dts: exynos: add minimal support for exynosautov920 sadk board ExynosAutov920 SADK is ExynosAutov920 SoC based SADK(Samsung Automotive Development Kit) board. It has 16GB(8GB + 8GB) LPDDR5 RAM and 256GB (128GB + 128GB) UFS. This is minimal support board device-tree. * Serial console * GPIO Key * PWM FAN Signed-off-by: Jaewon Kim Link: https://lore.kernel.org/r/20231208074527.50840-3-jaewon02.kim@samsung.com Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/Makefile | 3 +- .../boot/dts/exynos/exynosautov920-sadk.dts | 88 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts diff --git a/arch/arm64/boot/dts/exynos/Makefile b/arch/arm64/boot/dts/exynos/Makefile index 6e4ba69268e5..da06e1a9456c 100644 --- a/arch/arm64/boot/dts/exynos/Makefile +++ b/arch/arm64/boot/dts/exynos/Makefile @@ -5,4 +5,5 @@ dtb-$(CONFIG_ARCH_EXYNOS) += \ exynos7-espresso.dtb \ exynos7885-jackpotlte.dtb \ exynos850-e850-96.dtb \ - exynosautov9-sadk.dtb + exynosautov9-sadk.dtb \ + exynosautov920-sadk.dtb diff --git a/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts b/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts new file mode 100644 index 000000000000..a397f068ed53 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SADK board device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + */ + +/dts-v1/; +#include "exynosautov920.dtsi" +#include "exynos-pinctrl.h" +#include +#include + +/ { + model = "Samsung ExynosAutov920 SADK board"; + compatible = "samsung,exynosautov920-sadk", "samsung,exynosautov920"; + + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &serial_0; + }; + + chosen { + stdout-path = &serial_0; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_wakeup &key_back>; + + key-wakeup { + label = "KEY_WAKEUP"; + linux,code = ; + gpios = <&gpa0 0 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + key-back { + label = "KEY_BACK"; + linux,code = ; + gpios = <&gpp6 3 GPIO_ACTIVE_LOW>; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x70000000>, + <0x8 0x80000000 0x1 0xfba00000>, + <0xa 0x00000000 0x2 0x00000000>; + }; +}; + +&pinctrl_alive { + key_wakeup: key-wakeup-pins { + samsung,pins = "gpa0-0"; + samsung,pin-function = ; + }; +}; + +&pinctrl_peric1 { + key_back: key-back-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_tout0>; + status = "okay"; +}; + +&serial_0 { + status = "okay"; +}; + +&usi_0 { + samsung,clkreq-on; /* needed for UART mode */ + status = "okay"; +}; + +&xtcxo { + clock-frequency = <38400000>; +}; From 1801d87b3598b173bce3fbf15c5517796f38db96 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:35 -0800 Subject: [PATCH 3504/7721] RDMA/bnxt_re: Support new 5760X P7 devices Add basic support for 5760X P7 devices. Add new chip revisions. The first version support is similar to the existing P5 adapters. Extend the current support for P5 adapters to P7 also. Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 4 ++-- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 10 +++++----- drivers/infiniband/hw/bnxt_re/main.c | 14 +++++++------- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 4 ++-- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.h | 20 +++++++++++++++++--- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 6 +++--- 8 files changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index 93572405d6fa..128651c01595 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -371,7 +371,7 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, } done: - return bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? + return bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? BNXT_RE_NUM_EXT_COUNTERS : BNXT_RE_NUM_STD_COUNTERS; } @@ -381,7 +381,7 @@ struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev, struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev); int num_counters = 0; - if (bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) + if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) num_counters = BNXT_RE_NUM_EXT_COUNTERS; else num_counters = BNXT_RE_NUM_STD_COUNTERS; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index b2467de721dc..e7ef099c3edd 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1023,7 +1023,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd, bytes = (qplib_qp->sq.max_wqe * qplib_qp->sq.wqe_size); /* Consider mapping PSN search memory only for RC QPs. */ if (qplib_qp->type == CMDQ_CREATE_QP_TYPE_RC) { - psn_sz = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? + psn_sz = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? sizeof(struct sq_psn_search_ext) : sizeof(struct sq_psn_search); psn_nume = (qplib_qp->wqe_mode == BNXT_QPLIB_WQE_MODE_STATIC) ? @@ -1234,7 +1234,7 @@ static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp) qplqp = &qp->qplib_qp; dev_attr = &rdev->dev_attr; - if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) { qplqp->rq.max_sge = dev_attr->max_qp_sges; if (qplqp->rq.max_sge > dev_attr->max_qp_sges) qplqp->rq.max_sge = dev_attr->max_qp_sges; @@ -1301,7 +1301,7 @@ static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp, qplqp = &qp->qplib_qp; dev_attr = &rdev->dev_attr; - if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) { entries = bnxt_re_init_depth(init_attr->cap.max_send_wr + 1, uctx); qplqp->sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); @@ -1328,7 +1328,7 @@ static int bnxt_re_init_qp_type(struct bnxt_re_dev *rdev, goto out; } - if (bnxt_qplib_is_chip_gen_p5(chip_ctx) && + if (bnxt_qplib_is_chip_gen_p5_p7(chip_ctx) && init_attr->qp_type == IB_QPT_GSI) qptype = CMDQ_CREATE_QP_TYPE_GSI; out: @@ -1527,7 +1527,7 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr, goto fail; if (qp_init_attr->qp_type == IB_QPT_GSI && - !(bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))) { + !(bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))) { rc = bnxt_re_create_gsi_qp(qp, pd, qp_init_attr); if (rc == -ENODEV) goto qp_destroy; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index f79369c8360a..09c0b2e62cd9 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -128,7 +128,7 @@ static void bnxt_re_set_drv_mode(struct bnxt_re_dev *rdev, u8 mode) struct bnxt_qplib_chip_ctx *cctx; cctx = rdev->chip_ctx; - cctx->modes.wqe_mode = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? + cctx->modes.wqe_mode = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? mode : BNXT_QPLIB_WQE_MODE_STATIC; if (bnxt_re_hwrm_qcaps(rdev)) dev_err(rdev_to_dev(rdev), @@ -215,7 +215,7 @@ static void bnxt_re_limit_pf_res(struct bnxt_re_dev *rdev) ctx->srqc_count = min_t(u32, BNXT_RE_MAX_SRQC_COUNT, attr->max_srq); ctx->cq_count = min_t(u32, BNXT_RE_MAX_CQ_COUNT, attr->max_cq); - if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) for (i = 0; i < MAX_TQM_ALLOC_REQ; i++) rdev->qplib_ctx.tqm_ctx.qcount[i] = rdev->dev_attr.tqm_alloc_reqs[i]; @@ -264,7 +264,7 @@ static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev) memset(&rdev->qplib_ctx.vf_res, 0, sizeof(struct bnxt_qplib_vf_res)); bnxt_re_limit_pf_res(rdev); - num_vfs = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? + num_vfs = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? BNXT_RE_GEN_P5_MAX_VF : rdev->num_vfs; if (num_vfs) bnxt_re_limit_vf_res(&rdev->qplib_ctx, num_vfs); @@ -276,7 +276,7 @@ static void bnxt_re_vf_res_config(struct bnxt_re_dev *rdev) if (test_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags)) return; rdev->num_vfs = pci_sriov_get_totalvfs(rdev->en_dev->pdev); - if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) { bnxt_re_set_resource_limits(rdev); bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw, &rdev->qplib_ctx); @@ -1216,7 +1216,7 @@ static int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq, #define BNXT_RE_GEN_P5_VF_NQ_DB 0x4000 static u32 bnxt_re_get_nqdb_offset(struct bnxt_re_dev *rdev, u16 indx) { - return bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? + return bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? (rdev->is_virtfn ? BNXT_RE_GEN_P5_VF_NQ_DB : BNXT_RE_GEN_P5_PF_NQ_DB) : rdev->en_dev->msix_entries[indx].db_offset; @@ -1681,7 +1681,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) bnxt_re_set_resource_limits(rdev); rc = bnxt_qplib_alloc_ctx(&rdev->qplib_res, &rdev->qplib_ctx, 0, - bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)); + bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)); if (rc) { ibdev_err(&rdev->ibdev, "Failed to allocate QPLIB context: %#x\n", rc); @@ -1804,7 +1804,7 @@ static void bnxt_re_setup_cc(struct bnxt_re_dev *rdev, bool enable) return; /* Currently enabling only for GenP5 adapters */ - if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) return; if (enable) { diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index b821c37dffd9..1b7e9506b457 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -991,7 +991,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) /* SQ */ if (qp->type == CMDQ_CREATE_QP_TYPE_RC) { - psn_sz = bnxt_qplib_is_chip_gen_p5(res->cctx) ? + psn_sz = bnxt_qplib_is_chip_gen_p5_p7(res->cctx) ? sizeof(struct sq_psn_search_ext) : sizeof(struct sq_psn_search); } @@ -1605,7 +1605,7 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, flg_npsn = ((swq->next_psn << SQ_PSN_SEARCH_NEXT_PSN_SFT) & SQ_PSN_SEARCH_NEXT_PSN_MASK); - if (bnxt_qplib_is_chip_gen_p5(qp->cctx)) { + if (bnxt_qplib_is_chip_gen_p5_p7(qp->cctx)) { psns_ext->opcode_start_psn = cpu_to_le32(op_spsn); psns_ext->flags_next_psn = cpu_to_le32(flg_npsn); psns_ext->start_slot_idx = cpu_to_le16(swq->slot_idx); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 15e6d2b80c70..403b6797d9c2 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -852,7 +852,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, */ if (is_virtfn) goto skip_ctx_setup; - if (bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx)) + if (bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx)) goto config_vf_res; lvl = ctx->qpc_tbl.level; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index ae2bde34e785..dfc943fab87b 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -805,7 +805,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res, dpit = &res->dpi_tbl; reg = &dpit->wcreg; - if (!bnxt_qplib_is_chip_gen_p5(res->cctx)) { + if (!bnxt_qplib_is_chip_gen_p5_p7(res->cctx)) { /* Offest should come from L2 driver */ dbr_offset = dev_attr->l2_db_size; dpit->ucreg.offset = dbr_offset; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index 3e3383b8a913..397846bc8712 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -44,6 +44,9 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero; #define CHIP_NUM_57508 0x1750 #define CHIP_NUM_57504 0x1751 #define CHIP_NUM_57502 0x1752 +#define CHIP_NUM_58818 0xd818 +#define CHIP_NUM_57608 0x1760 + struct bnxt_qplib_drv_modes { u8 wqe_mode; @@ -296,6 +299,12 @@ struct bnxt_qplib_res { struct bnxt_qplib_db_pacing_data *pacing_data; }; +static inline bool bnxt_qplib_is_chip_gen_p7(struct bnxt_qplib_chip_ctx *cctx) +{ + return (cctx->chip_num == CHIP_NUM_58818 || + cctx->chip_num == CHIP_NUM_57608); +} + static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx) { return (cctx->chip_num == CHIP_NUM_57508 || @@ -303,15 +312,20 @@ static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx) cctx->chip_num == CHIP_NUM_57502); } +static inline bool bnxt_qplib_is_chip_gen_p5_p7(struct bnxt_qplib_chip_ctx *cctx) +{ + return bnxt_qplib_is_chip_gen_p5(cctx) || bnxt_qplib_is_chip_gen_p7(cctx); +} + static inline u8 bnxt_qplib_get_hwq_type(struct bnxt_qplib_res *res) { - return bnxt_qplib_is_chip_gen_p5(res->cctx) ? + return bnxt_qplib_is_chip_gen_p5_p7(res->cctx) ? HWQ_TYPE_QUEUE : HWQ_TYPE_L2_CMPL; } static inline u8 bnxt_qplib_get_ring_type(struct bnxt_qplib_chip_ctx *cctx) { - return bnxt_qplib_is_chip_gen_p5(cctx) ? + return bnxt_qplib_is_chip_gen_p5_p7(cctx) ? RING_ALLOC_REQ_RING_TYPE_NQ : RING_ALLOC_REQ_RING_TYPE_ROCE_CMPL; } @@ -488,7 +502,7 @@ static inline void bnxt_qplib_ring_nq_db(struct bnxt_qplib_db_info *info, u32 type; type = arm ? DBC_DBC_TYPE_NQ_ARM : DBC_DBC_TYPE_NQ; - if (bnxt_qplib_is_chip_gen_p5(cctx)) + if (bnxt_qplib_is_chip_gen_p5_p7(cctx)) bnxt_qplib_ring_db(info, type); else bnxt_qplib_ring_db32(info, arm); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index a27b68515164..c580bf78d4c1 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -59,7 +59,7 @@ static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw) { u16 pcie_ctl2 = 0; - if (!bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx)) + if (!bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx)) return false; pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, &pcie_ctl2); @@ -133,7 +133,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, * reporting the max number */ attr->max_qp_wqes -= BNXT_QPLIB_RESERVED_QP_WRS + 1; - attr->max_qp_sges = bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx) ? + attr->max_qp_sges = bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx) ? 6 : sb->max_sge; attr->max_cq = le32_to_cpu(sb->max_cq); attr->max_cq_wqes = le32_to_cpu(sb->max_cqe); @@ -934,7 +934,7 @@ int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res, req->inactivity_th = cpu_to_le16(cc_param->inact_th); /* For chip gen P5 onwards fill extended cmd and header */ - if (bnxt_qplib_is_chip_gen_p5(res->cctx)) { + if (bnxt_qplib_is_chip_gen_p5_p7(res->cctx)) { struct roce_tlv *hdr; u32 payload; u32 chunks; From a62d685814416647fbb28b3eb2617744adef2d4f Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:36 -0800 Subject: [PATCH 3505/7721] RDMA/bnxt_re: Update the BAR offsets Update the BAR offsets for handling GenP7 adapters. Use the values populated by L2 driver for getting the Doorbell offsets. Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/main.c | 21 +++++++-------------- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 5 +++-- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 09c0b2e62cd9..b7134d510f52 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -107,8 +107,11 @@ static void bnxt_re_set_db_offset(struct bnxt_re_dev *rdev) dev_info(rdev_to_dev(rdev), "Couldn't get DB bar size, Low latency framework is disabled\n"); /* set register offsets for both UC and WC */ - res->dpi_tbl.ucreg.offset = res->is_vf ? BNXT_QPLIB_DBR_VF_DB_OFFSET : - BNXT_QPLIB_DBR_PF_DB_OFFSET; + if (bnxt_qplib_is_chip_gen_p7(cctx)) + res->dpi_tbl.ucreg.offset = offset; + else + res->dpi_tbl.ucreg.offset = res->is_vf ? BNXT_QPLIB_DBR_VF_DB_OFFSET : + BNXT_QPLIB_DBR_PF_DB_OFFSET; res->dpi_tbl.wcreg.offset = res->dpi_tbl.ucreg.offset; /* If WC mapping is disabled by L2 driver then en_dev->l2_db_size @@ -1212,16 +1215,6 @@ static int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq, return 0; } -#define BNXT_RE_GEN_P5_PF_NQ_DB 0x10000 -#define BNXT_RE_GEN_P5_VF_NQ_DB 0x4000 -static u32 bnxt_re_get_nqdb_offset(struct bnxt_re_dev *rdev, u16 indx) -{ - return bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ? - (rdev->is_virtfn ? BNXT_RE_GEN_P5_VF_NQ_DB : - BNXT_RE_GEN_P5_PF_NQ_DB) : - rdev->en_dev->msix_entries[indx].db_offset; -} - static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) { int i; @@ -1242,7 +1235,7 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev) bnxt_qplib_init_res(&rdev->qplib_res); for (i = 1; i < rdev->num_msix ; i++) { - db_offt = bnxt_re_get_nqdb_offset(rdev, i); + db_offt = rdev->en_dev->msix_entries[i].db_offset; rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq[i - 1], i - 1, rdev->en_dev->msix_entries[i].vector, db_offt, &bnxt_re_cqn_handler, @@ -1653,7 +1646,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) ibdev_err(&rdev->ibdev, "Failed to allocate CREQ: %#x\n", rc); goto free_rcfw; } - db_offt = bnxt_re_get_nqdb_offset(rdev, BNXT_RE_AEQ_IDX); + db_offt = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].db_offset; vid = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].vector; rc = bnxt_qplib_enable_rcfw_channel(&rdev->rcfw, vid, db_offt, diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index c580bf78d4c1..8beeedd15061 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -151,8 +151,9 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->max_srq_sges = sb->max_srq_sge; attr->max_pkey = 1; attr->max_inline_data = le32_to_cpu(sb->max_inline_data); - attr->l2_db_size = (sb->l2_db_space_size + 1) * - (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); + if (!bnxt_qplib_is_chip_gen_p7(rcfw->res->cctx)) + attr->l2_db_size = (sb->l2_db_space_size + 1) * + (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); attr->max_sgid = BNXT_QPLIB_NUM_GIDS_SUPPORTED; attr->dev_cap_flags = le16_to_cpu(sb->dev_cap_flags); From 880a5dd1880a296575e92dec9816a7f35a7011d1 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:37 -0800 Subject: [PATCH 3506/7721] RDMA/bnxt_re: Update the HW interface definitions Adds HW interface definitions to support the new chip revision. Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-4-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/roce_hsi.h | 67 ++++++++++++++++++++---- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index 84b5acd7f7a2..605c9463c408 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -555,7 +555,12 @@ struct cmdq_modify_qp { __le16 flags; __le16 cookie; u8 resp_size; - u8 reserved8; + u8 qp_type; + #define CMDQ_MODIFY_QP_QP_TYPE_RC 0x2UL + #define CMDQ_MODIFY_QP_QP_TYPE_UD 0x4UL + #define CMDQ_MODIFY_QP_QP_TYPE_RAW_ETHERTYPE 0x6UL + #define CMDQ_MODIFY_QP_QP_TYPE_GSI 0x7UL + #define CMDQ_MODIFY_QP_QP_TYPE_LAST CMDQ_MODIFY_QP_QP_TYPE_GSI __le64 resp_addr; __le32 modify_mask; #define CMDQ_MODIFY_QP_MODIFY_MASK_STATE 0x1UL @@ -611,14 +616,12 @@ struct cmdq_modify_qp { #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 (0x3UL << 6) #define CMDQ_MODIFY_QP_NETWORK_TYPE_LAST CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 u8 access; - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK \ - 0xffUL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT \ - 0 - #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK 0xffUL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT 0 + #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL __le16 pkey; __le32 qkey; __le32 dgid[4]; @@ -673,6 +676,13 @@ struct cmdq_modify_qp { #define CMDQ_MODIFY_QP_VLAN_PCP_SFT 13 __le64 irrq_addr; __le64 orrq_addr; + __le32 ext_modify_mask; + #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_EXT_STATS_CTX 0x1UL + #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_SCHQ_ID_VALID 0x2UL + __le32 ext_stats_ctx_id; + __le16 schq_id; + __le16 unused_0; + __le32 reserved32; }; /* creq_modify_qp_resp (size:128b/16B) */ @@ -3075,6 +3085,17 @@ struct sq_psn_search_ext { __le32 reserved32; }; +/* sq_msn_search (size:64b/8B) */ +struct sq_msn_search { + __le64 start_idx_next_psn_start_psn; + #define SQ_MSN_SEARCH_START_PSN_MASK 0xffffffUL + #define SQ_MSN_SEARCH_START_PSN_SFT 0 + #define SQ_MSN_SEARCH_NEXT_PSN_MASK 0xffffff000000ULL + #define SQ_MSN_SEARCH_NEXT_PSN_SFT 24 + #define SQ_MSN_SEARCH_START_IDX_MASK 0xffff000000000000ULL + #define SQ_MSN_SEARCH_START_IDX_SFT 48 +}; + /* sq_send (size:1024b/128B) */ struct sq_send { u8 wqe_type; @@ -3763,13 +3784,35 @@ struct cq_base { #define CQ_BASE_CQE_TYPE_RES_UD (0x2UL << 1) #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) #define CQ_BASE_CQE_TYPE_RES_UD_CFA (0x4UL << 1) + #define CQ_BASE_CQE_TYPE_REQ_V3 (0x8UL << 1) + #define CQ_BASE_CQE_TYPE_RES_RC_V3 (0x9UL << 1) + #define CQ_BASE_CQE_TYPE_RES_UD_V3 (0xaUL << 1) + #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1_V3 (0xbUL << 1) + #define CQ_BASE_CQE_TYPE_RES_UD_CFA_V3 (0xcUL << 1) #define CQ_BASE_CQE_TYPE_NO_OP (0xdUL << 1) #define CQ_BASE_CQE_TYPE_TERMINAL (0xeUL << 1) #define CQ_BASE_CQE_TYPE_CUT_OFF (0xfUL << 1) #define CQ_BASE_CQE_TYPE_LAST CQ_BASE_CQE_TYPE_CUT_OFF u8 status; + #define CQ_BASE_STATUS_OK 0x0UL + #define CQ_BASE_STATUS_BAD_RESPONSE_ERR 0x1UL + #define CQ_BASE_STATUS_LOCAL_LENGTH_ERR 0x2UL + #define CQ_BASE_STATUS_HW_LOCAL_LENGTH_ERR 0x3UL + #define CQ_BASE_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_BASE_STATUS_LOCAL_PROTECTION_ERR 0x5UL + #define CQ_BASE_STATUS_LOCAL_ACCESS_ERROR 0x6UL + #define CQ_BASE_STATUS_MEMORY_MGT_OPERATION_ERR 0x7UL + #define CQ_BASE_STATUS_REMOTE_INVALID_REQUEST_ERR 0x8UL + #define CQ_BASE_STATUS_REMOTE_ACCESS_ERR 0x9UL + #define CQ_BASE_STATUS_REMOTE_OPERATION_ERR 0xaUL + #define CQ_BASE_STATUS_RNR_NAK_RETRY_CNT_ERR 0xbUL + #define CQ_BASE_STATUS_TRANSPORT_RETRY_CNT_ERR 0xcUL + #define CQ_BASE_STATUS_WORK_REQUEST_FLUSHED_ERR 0xdUL + #define CQ_BASE_STATUS_HW_FLUSH_ERR 0xeUL + #define CQ_BASE_STATUS_OVERFLOW_ERR 0xfUL + #define CQ_BASE_STATUS_LAST CQ_BASE_STATUS_OVERFLOW_ERR __le16 reserved16; - __le32 reserved32; + __le32 opaque; }; /* cq_req (size:256b/32B) */ @@ -4384,6 +4427,8 @@ struct cq_cutoff { #define CQ_CUTOFF_CQE_TYPE_SFT 1 #define CQ_CUTOFF_CQE_TYPE_CUT_OFF (0xfUL << 1) #define CQ_CUTOFF_CQE_TYPE_LAST CQ_CUTOFF_CQE_TYPE_CUT_OFF + #define CQ_CUTOFF_RESIZE_TOGGLE_MASK 0x60UL + #define CQ_CUTOFF_RESIZE_TOGGLE_SFT 5 u8 status; #define CQ_CUTOFF_STATUS_OK 0x0UL #define CQ_CUTOFF_STATUS_LAST CQ_CUTOFF_STATUS_OK @@ -4435,6 +4480,8 @@ struct nq_srq_event { #define NQ_SRQ_EVENT_TYPE_SFT 0 #define NQ_SRQ_EVENT_TYPE_SRQ_EVENT 0x32UL #define NQ_SRQ_EVENT_TYPE_LAST NQ_SRQ_EVENT_TYPE_SRQ_EVENT + #define NQ_SRQ_EVENT_TOGGLE_MASK 0xc0UL + #define NQ_SRQ_EVENT_TOGGLE_SFT 6 u8 event; #define NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT 0x1UL #define NQ_SRQ_EVENT_EVENT_LAST NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT From 6027c20dad1ad1da45877151d8b75dc51a928ccd Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:38 -0800 Subject: [PATCH 3507/7721] RDMA/bnxt_re: Get the toggle bits from CQ completions Get the toggle bits from CQ completions. For older adapters these values are 0. Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-5-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 6 ++++++ drivers/infiniband/hw/bnxt_re/qplib_fp.h | 1 + drivers/infiniband/hw/bnxt_re/qplib_res.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 1b7e9506b457..177c6c185f0c 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -330,6 +330,9 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) cq = (struct bnxt_qplib_cq *)(unsigned long)q_handle; if (!cq) break; + cq->toggle = (le16_to_cpu(nqe->info10_type) & + NQ_CN_TOGGLE_MASK) >> NQ_CN_TOGGLE_SFT; + cq->dbinfo.toggle = cq->toggle; bnxt_qplib_armen_db(&cq->dbinfo, DBC_DBC_TYPE_CQ_ARMENA); spin_lock_bh(&cq->compl_lock); @@ -2124,6 +2127,8 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) cq->dbinfo.xid = cq->id; cq->dbinfo.db = cq->dpi->dbr; cq->dbinfo.priv_db = res->dpi_tbl.priv_db; + cq->dbinfo.flags = 0; + cq->dbinfo.toggle = 0; bnxt_qplib_armen_db(&cq->dbinfo, DBC_DBC_TYPE_CQ_ARMENA); @@ -3018,6 +3023,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type) { + cq->dbinfo.toggle = cq->toggle; if (arm_type) bnxt_qplib_ring_db(&cq->dbinfo, arm_type); /* Using cq->arm_state variable to track whether to issue cq handler */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 23c27cb42978..8a6bea201b29 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -418,6 +418,7 @@ struct bnxt_qplib_cq { bool resize_in_progress; struct bnxt_qplib_sg_info sg_info; u64 cq_handle; + u8 toggle; #define CQ_RESIZE_WAIT_TIME_MS 500 unsigned long flags; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index 397846bc8712..7e6d9074f900 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -190,6 +190,7 @@ struct bnxt_qplib_db_info { u32 xid; u32 max_slot; u32 flags; + u8 toggle; }; enum bnxt_qplib_db_info_flags_mask { From cdae3936b2fe7f943e8b5b46f3b3d8446aeb2e0c Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:39 -0800 Subject: [PATCH 3508/7721] RDMA/bnxt_re: Doorbell changes Update the Doorbell routines to support the latest HW definitions. Use common routine to prepare the Doorbell key. Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-6-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_res.h | 46 +++++++++++++++++------ 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index 7e6d9074f900..c228870eed29 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -47,6 +47,9 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero; #define CHIP_NUM_58818 0xd818 #define CHIP_NUM_57608 0x1760 +#define BNXT_QPLIB_DBR_VALID (0x1UL << 26) +#define BNXT_QPLIB_DBR_EPOCH_SHIFT 24 +#define BNXT_QPLIB_DBR_TOGGLE_SHIFT 25 struct bnxt_qplib_drv_modes { u8 wqe_mode; @@ -200,6 +203,11 @@ enum bnxt_qplib_db_info_flags_mask { BNXT_QPLIB_FLAG_EPOCH_PROD_MASK = 0x2UL, }; +enum bnxt_qplib_db_epoch_flag_shift { + BNXT_QPLIB_DB_EPOCH_CONS_SHIFT = BNXT_QPLIB_DBR_EPOCH_SHIFT, + BNXT_QPLIB_DB_EPOCH_PROD_SHIFT = (BNXT_QPLIB_DBR_EPOCH_SHIFT - 1), +}; + /* Tables */ struct bnxt_qplib_pd_tbl { unsigned long *tbl; @@ -453,14 +461,27 @@ static inline void bnxt_qplib_ring_db32(struct bnxt_qplib_db_info *info, writel(key, info->db); } +#define BNXT_QPLIB_INIT_DBHDR(xid, type, indx, toggle) \ + (((u64)(((xid) & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | \ + (type) | BNXT_QPLIB_DBR_VALID) << 32) | (indx) | \ + (((u32)(toggle)) << (BNXT_QPLIB_DBR_TOGGLE_SHIFT))) + static inline void bnxt_qplib_ring_db(struct bnxt_qplib_db_info *info, u32 type) { u64 key = 0; + u32 indx; + u8 toggle = 0; - key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type; - key <<= 32; - key |= (info->hwq->cons & DBC_DBC_INDEX_MASK); + if (type == DBC_DBC_TYPE_CQ_ARMALL || + type == DBC_DBC_TYPE_CQ_ARMSE) + toggle = info->toggle; + + indx = (info->hwq->cons & DBC_DBC_INDEX_MASK) | + ((info->flags & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK) << + BNXT_QPLIB_DB_EPOCH_CONS_SHIFT); + + key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, indx, toggle); writeq(key, info->db); } @@ -468,10 +489,12 @@ static inline void bnxt_qplib_ring_prod_db(struct bnxt_qplib_db_info *info, u32 type) { u64 key = 0; + u32 indx; - key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type; - key <<= 32; - key |= ((info->hwq->prod / info->max_slot)) & DBC_DBC_INDEX_MASK; + indx = (((info->hwq->prod / info->max_slot) & DBC_DBC_INDEX_MASK) | + ((info->flags & BNXT_QPLIB_FLAG_EPOCH_PROD_MASK) << + BNXT_QPLIB_DB_EPOCH_PROD_SHIFT)); + key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, indx, 0); writeq(key, info->db); } @@ -479,9 +502,12 @@ static inline void bnxt_qplib_armen_db(struct bnxt_qplib_db_info *info, u32 type) { u64 key = 0; + u8 toggle = 0; - key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type; - key <<= 32; + if (type == DBC_DBC_TYPE_CQ_ARMENA || type == DBC_DBC_TYPE_SRQ_ARMENA) + toggle = info->toggle; + /* Index always at 0 */ + key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, 0, toggle); writeq(key, info->priv_db); } @@ -490,9 +516,7 @@ static inline void bnxt_qplib_srq_arm_db(struct bnxt_qplib_db_info *info, { u64 key = 0; - key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | th; - key <<= 32; - key |= th & DBC_DBC_INDEX_MASK; + key = BNXT_QPLIB_INIT_DBHDR(info->xid, DBC_DBC_TYPE_SRQ_ARM, th, info->toggle); writeq(key, info->priv_db); } From 07f830ae4913d0b986c8c0ff88a7d597948b9bd8 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 7 Dec 2023 02:47:40 -0800 Subject: [PATCH 3509/7721] RDMA/bnxt_re: Adds MSN table capability for Gen P7 adapters GenP7 HW expects an MSN table instead of PSN table. Check for the HW retransmission capability and populate the MSN table if HW retansmission is supported. Signed-off-by: Damodharam Ammepalli Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1701946060-13931-7-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 67 ++++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/qplib_fp.h | 14 +++++ drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 + drivers/infiniband/hw/bnxt_re/qplib_res.h | 9 +++ include/uapi/rdma/bnxt_re-abi.h | 1 + 5 files changed, 87 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 177c6c185f0c..c98e04fe2ddd 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -982,6 +982,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) u32 tbl_indx; u16 nsge; + if (res->dattr) + qp->dev_cap_flags = res->dattr->dev_cap_flags; + sq->dbinfo.flags = 0; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_CREATE_QP, @@ -997,6 +1000,11 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) psn_sz = bnxt_qplib_is_chip_gen_p5_p7(res->cctx) ? sizeof(struct sq_psn_search_ext) : sizeof(struct sq_psn_search); + + if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) { + psn_sz = sizeof(struct sq_msn_search); + qp->msn = 0; + } } hwq_attr.res = res; @@ -1005,6 +1013,13 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) hwq_attr.depth = bnxt_qplib_get_depth(sq); hwq_attr.aux_stride = psn_sz; hwq_attr.aux_depth = bnxt_qplib_set_sq_size(sq, qp->wqe_mode); + /* Update msn tbl size */ + if (BNXT_RE_HW_RETX(qp->dev_cap_flags) && psn_sz) { + hwq_attr.aux_depth = roundup_pow_of_two(bnxt_qplib_set_sq_size(sq, qp->wqe_mode)); + qp->msn_tbl_sz = hwq_attr.aux_depth; + qp->msn = 0; + } + hwq_attr.type = HWQ_TYPE_QUEUE; rc = bnxt_qplib_alloc_init_hwq(&sq->hwq, &hwq_attr); if (rc) @@ -1587,6 +1602,27 @@ void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp, return NULL; } +/* Fil the MSN table into the next psn row */ +static void bnxt_qplib_fill_msn_search(struct bnxt_qplib_qp *qp, + struct bnxt_qplib_swqe *wqe, + struct bnxt_qplib_swq *swq) +{ + struct sq_msn_search *msns; + u32 start_psn, next_psn; + u16 start_idx; + + msns = (struct sq_msn_search *)swq->psn_search; + msns->start_idx_next_psn_start_psn = 0; + + start_psn = swq->start_psn; + next_psn = swq->next_psn; + start_idx = swq->slot_idx; + msns->start_idx_next_psn_start_psn |= + bnxt_re_update_msn_tbl(start_idx, next_psn, start_psn); + qp->msn++; + qp->msn %= qp->msn_tbl_sz; +} + static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, struct bnxt_qplib_swqe *wqe, struct bnxt_qplib_swq *swq) @@ -1598,6 +1634,12 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, if (!swq->psn_search) return; + /* Handle MSN differently on cap flags */ + if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) { + bnxt_qplib_fill_msn_search(qp, wqe, swq); + return; + } + psns = (struct sq_psn_search *)swq->psn_search; psns = swq->psn_search; psns_ext = swq->psn_ext; @@ -1706,8 +1748,8 @@ static u16 bnxt_qplib_required_slots(struct bnxt_qplib_qp *qp, return slot; } -static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq, - struct bnxt_qplib_swq *swq) +static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_qp *qp, struct bnxt_qplib_q *sq, + struct bnxt_qplib_swq *swq, bool hw_retx) { struct bnxt_qplib_hwq *hwq; u32 pg_num, pg_indx; @@ -1718,6 +1760,11 @@ static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq, if (!hwq->pad_pg) return; tail = swq->slot_idx / sq->dbinfo.max_slot; + if (hw_retx) { + /* For HW retx use qp msn index */ + tail = qp->msn; + tail %= qp->msn_tbl_sz; + } pg_num = (tail + hwq->pad_pgofft) / (PAGE_SIZE / hwq->pad_stride); pg_indx = (tail + hwq->pad_pgofft) % (PAGE_SIZE / hwq->pad_stride); buff = (void *)(hwq->pad_pg[pg_num] + pg_indx * hwq->pad_stride); @@ -1742,6 +1789,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, struct bnxt_qplib_swq *swq; bool sch_handler = false; u16 wqe_sz, qdf = 0; + bool msn_update; void *base_hdr; void *ext_hdr; __le32 temp32; @@ -1769,7 +1817,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, } swq = bnxt_qplib_get_swqe(sq, &wqe_idx); - bnxt_qplib_pull_psn_buff(sq, swq); + bnxt_qplib_pull_psn_buff(qp, sq, swq, BNXT_RE_HW_RETX(qp->dev_cap_flags)); idx = 0; swq->slot_idx = hwq->prod; @@ -1801,6 +1849,8 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, &idx); if (data_len < 0) goto queue_err; + /* Make sure we update MSN table only for wired wqes */ + msn_update = true; /* Specifics */ switch (wqe->type) { case BNXT_QPLIB_SWQE_TYPE_SEND: @@ -1841,6 +1891,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, SQ_SEND_DST_QP_MASK); ext_sqe->avid = cpu_to_le32(wqe->send.avid & SQ_SEND_AVID_MASK); + msn_update = false; } else { sqe->length = cpu_to_le32(data_len); if (qp->mtu) @@ -1898,7 +1949,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, sqe->wqe_type = wqe->type; sqe->flags = wqe->flags; sqe->inv_l_key = cpu_to_le32(wqe->local_inv.inv_l_key); - + msn_update = false; break; } case BNXT_QPLIB_SWQE_TYPE_FAST_REG_MR: @@ -1930,6 +1981,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, PTU_PTE_VALID); ext_sqe->pblptr = cpu_to_le64(wqe->frmr.pbl_dma_ptr); ext_sqe->va = cpu_to_le64(wqe->frmr.va); + msn_update = false; break; } @@ -1947,6 +1999,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, sqe->l_key = cpu_to_le32(wqe->bind.r_key); ext_sqe->va = cpu_to_le64(wqe->bind.va); ext_sqe->length_lo = cpu_to_le32(wqe->bind.length); + msn_update = false; break; } default: @@ -1954,8 +2007,10 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, rc = -EINVAL; goto done; } - swq->next_psn = sq->psn & BTH_PSN_MASK; - bnxt_qplib_fill_psn_search(qp, wqe, swq); + if (!BNXT_RE_HW_RETX(qp->dev_cap_flags) || msn_update) { + swq->next_psn = sq->psn & BTH_PSN_MASK; + bnxt_qplib_fill_psn_search(qp, wqe, swq); + } queue_err: bnxt_qplib_swq_mod_start(sq, wqe_idx); bnxt_qplib_hwq_incr_prod(&sq->dbinfo, hwq, swq->slots); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 8a6bea201b29..967c6691e413 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -338,6 +338,9 @@ struct bnxt_qplib_qp { dma_addr_t rq_hdr_buf_map; struct list_head sq_flush; struct list_head rq_flush; + u32 msn; + u32 msn_tbl_sz; + u16 dev_cap_flags; }; #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base) @@ -627,4 +630,15 @@ static inline u16 bnxt_qplib_calc_ilsize(struct bnxt_qplib_swqe *wqe, u16 max) return size; } + +/* MSN table update inlin */ +static inline uint64_t bnxt_re_update_msn_tbl(u32 st_idx, u32 npsn, u32 start_psn) +{ + return cpu_to_le64((((u64)(st_idx) << SQ_MSN_SEARCH_START_IDX_SFT) & + SQ_MSN_SEARCH_START_IDX_MASK) | + (((u64)(npsn) << SQ_MSN_SEARCH_NEXT_PSN_SFT) & + SQ_MSN_SEARCH_NEXT_PSN_MASK) | + (((start_psn) << SQ_MSN_SEARCH_START_PSN_SFT) & + SQ_MSN_SEARCH_START_PSN_MASK)); +} #endif /* __BNXT_QPLIB_FP_H__ */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 403b6797d9c2..0ea7ccc70679 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -905,6 +905,8 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); skip_ctx_setup: + if (BNXT_RE_HW_RETX(rcfw->res->dattr->dev_cap_flags)) + req.flags |= CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED; req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index c228870eed29..382d89fa7d16 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -539,6 +539,15 @@ static inline bool _is_ext_stats_supported(u16 dev_cap_flags) CREQ_QUERY_FUNC_RESP_SB_EXT_STATS; } +static inline bool _is_hw_retx_supported(u16 dev_cap_flags) +{ + return dev_cap_flags & + (CREQ_QUERY_FUNC_RESP_SB_HW_REQUESTER_RETX_ENABLED | + CREQ_QUERY_FUNC_RESP_SB_HW_RESPONDER_RETX_ENABLED); +} + +#define BNXT_RE_HW_RETX(a) _is_hw_retx_supported((a)) + static inline u8 bnxt_qplib_dbr_pacing_en(struct bnxt_qplib_chip_ctx *cctx) { return cctx->modes.dbr_pacing; diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h index a1b896d6d940..3342276aeac1 100644 --- a/include/uapi/rdma/bnxt_re-abi.h +++ b/include/uapi/rdma/bnxt_re-abi.h @@ -55,6 +55,7 @@ enum { BNXT_RE_UCNTX_CMASK_WC_DPI_ENABLED = 0x04ULL, BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED = 0x08ULL, BNXT_RE_UCNTX_CMASK_POW2_DISABLED = 0x10ULL, + BNXT_RE_COMP_MASK_UCNTX_HW_RETX_ENABLED = 0x40, }; enum bnxt_re_wqe_mode { From 5169477081a1ed08924949e4893732de92ad7d25 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 9 Dec 2023 23:05:41 +0000 Subject: [PATCH 3510/7721] drm/i915/selftests: Fix spelling mistake "initialiased" -> "initialised" There is a spelling mistake in a pr_err error message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231209230541.4055786-1-colin.i.king@gmail.com --- drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index e57f9390076c..d684a70f2c04 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -504,7 +504,7 @@ static int igt_dmabuf_export_vmap(void *arg) } if (memchr_inv(ptr, 0, dmabuf->size)) { - pr_err("Exported object not initialiased to zero!\n"); + pr_err("Exported object not initialised to zero!\n"); err = -EINVAL; goto out; } From f48dee9ed7c992eaf6a3635db304a61ed82827b3 Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:49 +1100 Subject: [PATCH 3511/7721] drm/panel: nv3052c: Document known register names Many of these registers have a known name in the public datasheet. Document them as comments for reference. Signed-off-by: John Watts Reviewed-by: Jessica Zhang Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-1-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-1-d75adc75571f@jookia.org --- .../gpu/drm/panel/panel-newvision-nv3052c.c | 261 +++++++++--------- 1 file changed, 132 insertions(+), 129 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index 71e57de6d8b2..589431523ce7 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -42,9 +42,9 @@ struct nv3052c_reg { }; static const struct nv3052c_reg nv3052c_panel_regs[] = { - { 0xff, 0x30 }, - { 0xff, 0x52 }, - { 0xff, 0x01 }, + // EXTC Command set enable, select page 1 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, + // Mostly unknown registers { 0xe3, 0x00 }, { 0x40, 0x00 }, { 0x03, 0x40 }, @@ -62,15 +62,15 @@ static const struct nv3052c_reg nv3052c_panel_regs[] = { { 0x25, 0x06 }, { 0x26, 0x14 }, { 0x27, 0x14 }, - { 0x38, 0xcc }, - { 0x39, 0xd7 }, - { 0x3a, 0x4a }, + { 0x38, 0xcc }, // VCOM_ADJ1 + { 0x39, 0xd7 }, // VCOM_ADJ2 + { 0x3a, 0x4a }, // VCOM_ADJ3 { 0x28, 0x40 }, { 0x29, 0x01 }, { 0x2a, 0xdf }, { 0x49, 0x3c }, - { 0x91, 0x77 }, - { 0x92, 0x77 }, + { 0x91, 0x77 }, // EXTPW_CTRL2 + { 0x92, 0x77 }, // EXTPW_CTRL3 { 0xa0, 0x55 }, { 0xa1, 0x50 }, { 0xa4, 0x9c }, @@ -94,123 +94,126 @@ static const struct nv3052c_reg nv3052c_panel_regs[] = { { 0xb8, 0x26 }, { 0xf0, 0x00 }, { 0xf6, 0xc0 }, - { 0xff, 0x30 }, - { 0xff, 0x52 }, - { 0xff, 0x02 }, - { 0xb0, 0x0b }, - { 0xb1, 0x16 }, - { 0xb2, 0x17 }, - { 0xb3, 0x2c }, - { 0xb4, 0x32 }, - { 0xb5, 0x3b }, - { 0xb6, 0x29 }, - { 0xb7, 0x40 }, - { 0xb8, 0x0d }, - { 0xb9, 0x05 }, - { 0xba, 0x12 }, - { 0xbb, 0x10 }, - { 0xbc, 0x12 }, - { 0xbd, 0x15 }, - { 0xbe, 0x19 }, - { 0xbf, 0x0e }, - { 0xc0, 0x16 }, - { 0xc1, 0x0a }, - { 0xd0, 0x0c }, - { 0xd1, 0x17 }, - { 0xd2, 0x14 }, - { 0xd3, 0x2e }, - { 0xd4, 0x32 }, - { 0xd5, 0x3c }, - { 0xd6, 0x22 }, - { 0xd7, 0x3d }, - { 0xd8, 0x0d }, - { 0xd9, 0x07 }, - { 0xda, 0x13 }, - { 0xdb, 0x13 }, - { 0xdc, 0x11 }, - { 0xdd, 0x15 }, - { 0xde, 0x19 }, - { 0xdf, 0x10 }, - { 0xe0, 0x17 }, - { 0xe1, 0x0a }, - { 0xff, 0x30 }, - { 0xff, 0x52 }, - { 0xff, 0x03 }, - { 0x00, 0x2a }, - { 0x01, 0x2a }, - { 0x02, 0x2a }, - { 0x03, 0x2a }, - { 0x04, 0x61 }, - { 0x05, 0x80 }, - { 0x06, 0xc7 }, - { 0x07, 0x01 }, - { 0x08, 0x03 }, - { 0x09, 0x04 }, - { 0x70, 0x22 }, - { 0x71, 0x80 }, - { 0x30, 0x2a }, - { 0x31, 0x2a }, - { 0x32, 0x2a }, - { 0x33, 0x2a }, - { 0x34, 0x61 }, - { 0x35, 0xc5 }, - { 0x36, 0x80 }, - { 0x37, 0x23 }, - { 0x40, 0x03 }, - { 0x41, 0x04 }, - { 0x42, 0x05 }, - { 0x43, 0x06 }, - { 0x44, 0x11 }, - { 0x45, 0xe8 }, - { 0x46, 0xe9 }, - { 0x47, 0x11 }, - { 0x48, 0xea }, - { 0x49, 0xeb }, - { 0x50, 0x07 }, - { 0x51, 0x08 }, - { 0x52, 0x09 }, - { 0x53, 0x0a }, - { 0x54, 0x11 }, - { 0x55, 0xec }, - { 0x56, 0xed }, - { 0x57, 0x11 }, - { 0x58, 0xef }, - { 0x59, 0xf0 }, - { 0xb1, 0x01 }, - { 0xb4, 0x15 }, - { 0xb5, 0x16 }, - { 0xb6, 0x09 }, - { 0xb7, 0x0f }, - { 0xb8, 0x0d }, - { 0xb9, 0x0b }, - { 0xba, 0x00 }, - { 0xc7, 0x02 }, - { 0xca, 0x17 }, - { 0xcb, 0x18 }, - { 0xcc, 0x0a }, - { 0xcd, 0x10 }, - { 0xce, 0x0e }, - { 0xcf, 0x0c }, - { 0xd0, 0x00 }, - { 0x81, 0x00 }, - { 0x84, 0x15 }, - { 0x85, 0x16 }, - { 0x86, 0x10 }, - { 0x87, 0x0a }, - { 0x88, 0x0c }, - { 0x89, 0x0e }, - { 0x8a, 0x02 }, - { 0x97, 0x00 }, - { 0x9a, 0x17 }, - { 0x9b, 0x18 }, - { 0x9c, 0x0f }, - { 0x9d, 0x09 }, - { 0x9e, 0x0b }, - { 0x9f, 0x0d }, - { 0xa0, 0x01 }, - { 0xff, 0x30 }, - { 0xff, 0x52 }, - { 0xff, 0x02 }, + // EXTC Command set enable, select page 2 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, + // Set gray scale voltage to adjust gamma + { 0xb0, 0x0b }, // PGAMVR0 + { 0xb1, 0x16 }, // PGAMVR1 + { 0xb2, 0x17 }, // PGAMVR2 + { 0xb3, 0x2c }, // PGAMVR3 + { 0xb4, 0x32 }, // PGAMVR4 + { 0xb5, 0x3b }, // PGAMVR5 + { 0xb6, 0x29 }, // PGAMPR0 + { 0xb7, 0x40 }, // PGAMPR1 + { 0xb8, 0x0d }, // PGAMPK0 + { 0xb9, 0x05 }, // PGAMPK1 + { 0xba, 0x12 }, // PGAMPK2 + { 0xbb, 0x10 }, // PGAMPK3 + { 0xbc, 0x12 }, // PGAMPK4 + { 0xbd, 0x15 }, // PGAMPK5 + { 0xbe, 0x19 }, // PGAMPK6 + { 0xbf, 0x0e }, // PGAMPK7 + { 0xc0, 0x16 }, // PGAMPK8 + { 0xc1, 0x0a }, // PGAMPK9 + // Set gray scale voltage to adjust gamma + { 0xd0, 0x0c }, // NGAMVR0 + { 0xd1, 0x17 }, // NGAMVR0 + { 0xd2, 0x14 }, // NGAMVR1 + { 0xd3, 0x2e }, // NGAMVR2 + { 0xd4, 0x32 }, // NGAMVR3 + { 0xd5, 0x3c }, // NGAMVR4 + { 0xd6, 0x22 }, // NGAMPR0 + { 0xd7, 0x3d }, // NGAMPR1 + { 0xd8, 0x0d }, // NGAMPK0 + { 0xd9, 0x07 }, // NGAMPK1 + { 0xda, 0x13 }, // NGAMPK2 + { 0xdb, 0x13 }, // NGAMPK3 + { 0xdc, 0x11 }, // NGAMPK4 + { 0xdd, 0x15 }, // NGAMPK5 + { 0xde, 0x19 }, // NGAMPK6 + { 0xdf, 0x10 }, // NGAMPK7 + { 0xe0, 0x17 }, // NGAMPK8 + { 0xe1, 0x0a }, // NGAMPK9 + // EXTC Command set enable, select page 3 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 }, + // Set various timing settings + { 0x00, 0x2a }, // GIP_VST_1 + { 0x01, 0x2a }, // GIP_VST_2 + { 0x02, 0x2a }, // GIP_VST_3 + { 0x03, 0x2a }, // GIP_VST_4 + { 0x04, 0x61 }, // GIP_VST_5 + { 0x05, 0x80 }, // GIP_VST_6 + { 0x06, 0xc7 }, // GIP_VST_7 + { 0x07, 0x01 }, // GIP_VST_8 + { 0x08, 0x03 }, // GIP_VST_9 + { 0x09, 0x04 }, // GIP_VST_10 + { 0x70, 0x22 }, // GIP_ECLK1 + { 0x71, 0x80 }, // GIP_ECLK2 + { 0x30, 0x2a }, // GIP_CLK_1 + { 0x31, 0x2a }, // GIP_CLK_2 + { 0x32, 0x2a }, // GIP_CLK_3 + { 0x33, 0x2a }, // GIP_CLK_4 + { 0x34, 0x61 }, // GIP_CLK_5 + { 0x35, 0xc5 }, // GIP_CLK_6 + { 0x36, 0x80 }, // GIP_CLK_7 + { 0x37, 0x23 }, // GIP_CLK_8 + { 0x40, 0x03 }, // GIP_CLKA_1 + { 0x41, 0x04 }, // GIP_CLKA_2 + { 0x42, 0x05 }, // GIP_CLKA_3 + { 0x43, 0x06 }, // GIP_CLKA_4 + { 0x44, 0x11 }, // GIP_CLKA_5 + { 0x45, 0xe8 }, // GIP_CLKA_6 + { 0x46, 0xe9 }, // GIP_CLKA_7 + { 0x47, 0x11 }, // GIP_CLKA_8 + { 0x48, 0xea }, // GIP_CLKA_9 + { 0x49, 0xeb }, // GIP_CLKA_10 + { 0x50, 0x07 }, // GIP_CLKB_1 + { 0x51, 0x08 }, // GIP_CLKB_2 + { 0x52, 0x09 }, // GIP_CLKB_3 + { 0x53, 0x0a }, // GIP_CLKB_4 + { 0x54, 0x11 }, // GIP_CLKB_5 + { 0x55, 0xec }, // GIP_CLKB_6 + { 0x56, 0xed }, // GIP_CLKB_7 + { 0x57, 0x11 }, // GIP_CLKB_8 + { 0x58, 0xef }, // GIP_CLKB_9 + { 0x59, 0xf0 }, // GIP_CLKB_10 + // Map internal GOA signals to GOA output pad + { 0xb1, 0x01 }, // PANELD2U2 + { 0xb4, 0x15 }, // PANELD2U5 + { 0xb5, 0x16 }, // PANELD2U6 + { 0xb6, 0x09 }, // PANELD2U7 + { 0xb7, 0x0f }, // PANELD2U8 + { 0xb8, 0x0d }, // PANELD2U9 + { 0xb9, 0x0b }, // PANELD2U10 + { 0xba, 0x00 }, // PANELD2U11 + { 0xc7, 0x02 }, // PANELD2U24 + { 0xca, 0x17 }, // PANELD2U27 + { 0xcb, 0x18 }, // PANELD2U28 + { 0xcc, 0x0a }, // PANELD2U29 + { 0xcd, 0x10 }, // PANELD2U30 + { 0xce, 0x0e }, // PANELD2U31 + { 0xcf, 0x0c }, // PANELD2U32 + { 0xd0, 0x00 }, // PANELD2U33 + // Map internal GOA signals to GOA output pad + { 0x81, 0x00 }, // PANELU2D2 + { 0x84, 0x15 }, // PANELU2D5 + { 0x85, 0x16 }, // PANELU2D6 + { 0x86, 0x10 }, // PANELU2D7 + { 0x87, 0x0a }, // PANELU2D8 + { 0x88, 0x0c }, // PANELU2D9 + { 0x89, 0x0e }, // PANELU2D10 + { 0x8a, 0x02 }, // PANELU2D11 + { 0x97, 0x00 }, // PANELU2D24 + { 0x9a, 0x17 }, // PANELU2D27 + { 0x9b, 0x18 }, // PANELU2D28 + { 0x9c, 0x0f }, // PANELU2D29 + { 0x9d, 0x09 }, // PANELU2D30 + { 0x9e, 0x0b }, // PANELU2D31 + { 0x9f, 0x0d }, // PANELU2D32 + { 0xa0, 0x01 }, // PANELU2D33 + // EXTC Command set enable, select page 2 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, + // Unknown registers { 0x01, 0x01 }, { 0x02, 0xda }, { 0x03, 0xba }, @@ -227,10 +230,10 @@ static const struct nv3052c_reg nv3052c_panel_regs[] = { { 0x0e, 0x48 }, { 0x0f, 0x38 }, { 0x10, 0x2b }, - { 0xff, 0x30 }, - { 0xff, 0x52 }, - { 0xff, 0x00 }, - { 0x36, 0x0a }, + // EXTC Command set enable, select page 0 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 }, + // Display Access Control + { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 }; static inline struct nv3052c *to_nv3052c(struct drm_panel *panel) From 095e3a99e793767ca6c0483d31fb5d4087966d51 Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:50 +1100 Subject: [PATCH 3512/7721] drm/panel: nv3052c: Add SPI device IDs SPI drivers needs their own list of compatible device IDs in order for automatic module loading to work. Add those for this driver. Signed-off-by: John Watts Reviewed-by: Jessica Zhang Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-2-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-2-d75adc75571f@jookia.org --- drivers/gpu/drm/panel/panel-newvision-nv3052c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index 589431523ce7..90dea21f9856 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -465,6 +465,12 @@ static const struct nv3052c_panel_info ltk035c5444t_panel_info = { .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, }; +static const struct spi_device_id nv3052c_ids[] = { + { "ltk035c5444t", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, nv3052c_ids); + static const struct of_device_id nv3052c_of_match[] = { { .compatible = "leadtek,ltk035c5444t", .data = <k035c5444t_panel_info }, { /* sentinel */ } @@ -476,6 +482,7 @@ static struct spi_driver nv3052c_driver = { .name = "nv3052c", .of_match_table = nv3052c_of_match, }, + .id_table = nv3052c_ids, .probe = nv3052c_probe, .remove = nv3052c_remove, }; From 2e6b7be84d88c0af927967418a56e22d372ce98c Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:51 +1100 Subject: [PATCH 3513/7721] drm/panel: nv3052c: Allow specifying registers per panel Panel initialization registers are per-display and not tied to the controller itself. Different panels will specify their own registers. Attach the sequences to the panel info struct so future panels can specify their own sequences. Signed-off-by: John Watts Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-3-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-3-d75adc75571f@jookia.org --- .../gpu/drm/panel/panel-newvision-nv3052c.c | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index 90dea21f9856..b0114b5e8554 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -20,11 +20,18 @@ #include #include +struct nv3052c_reg { + u8 cmd; + u8 val; +}; + struct nv3052c_panel_info { const struct drm_display_mode *display_modes; unsigned int num_modes; u16 width_mm, height_mm; u32 bus_format, bus_flags; + const struct nv3052c_reg *panel_regs; + unsigned int panel_regs_len; }; struct nv3052c { @@ -36,12 +43,7 @@ struct nv3052c { struct gpio_desc *reset_gpio; }; -struct nv3052c_reg { - u8 cmd; - u8 val; -}; - -static const struct nv3052c_reg nv3052c_panel_regs[] = { +static const struct nv3052c_reg ltk035c5444t_panel_regs[] = { // EXTC Command set enable, select page 1 { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, // Mostly unknown registers @@ -244,6 +246,8 @@ static inline struct nv3052c *to_nv3052c(struct drm_panel *panel) static int nv3052c_prepare(struct drm_panel *panel) { struct nv3052c *priv = to_nv3052c(panel); + const struct nv3052c_reg *panel_regs = priv->panel_info->panel_regs; + unsigned int panel_regs_len = priv->panel_info->panel_regs_len; struct mipi_dbi *dbi = &priv->dbi; unsigned int i; int err; @@ -260,9 +264,9 @@ static int nv3052c_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(priv->reset_gpio, 0); usleep_range(5000, 20000); - for (i = 0; i < ARRAY_SIZE(nv3052c_panel_regs); i++) { - err = mipi_dbi_command(dbi, nv3052c_panel_regs[i].cmd, - nv3052c_panel_regs[i].val); + for (i = 0; i < panel_regs_len; i++) { + err = mipi_dbi_command(dbi, panel_regs[i].cmd, + panel_regs[i].val); if (err) { dev_err(priv->dev, "Unable to set register: %d\n", err); @@ -463,6 +467,8 @@ static const struct nv3052c_panel_info ltk035c5444t_panel_info = { .height_mm = 64, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, + .panel_regs = ltk035c5444t_panel_regs, + .panel_regs_len = ARRAY_SIZE(ltk035c5444t_panel_regs), }; static const struct spi_device_id nv3052c_ids[] = { From bf92f9163097dc717518d598116c1e385004b5ce Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:52 +1100 Subject: [PATCH 3514/7721] drm/panel: nv3052c: Add Fascontek FS035VG158 LCD display This display is extremely similar to the LTK035C5444T, but still has some minor variations in panel initialization. Signed-off-by: John Watts Reviewed-by: Jessica Zhang Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-4-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-4-d75adc75571f@jookia.org --- .../gpu/drm/panel/panel-newvision-nv3052c.c | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index b0114b5e8554..1aab0c9ae52f 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -238,6 +238,201 @@ static const struct nv3052c_reg ltk035c5444t_panel_regs[] = { { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 }; +static const struct nv3052c_reg fs035vg158_panel_regs[] = { + // EXTC Command set enable, select page 1 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, + // Mostly unknown registers + { 0xe3, 0x00 }, + { 0x40, 0x00 }, + { 0x03, 0x40 }, + { 0x04, 0x00 }, + { 0x05, 0x03 }, + { 0x08, 0x00 }, + { 0x09, 0x07 }, + { 0x0a, 0x01 }, + { 0x0b, 0x32 }, + { 0x0c, 0x32 }, + { 0x0d, 0x0b }, + { 0x0e, 0x00 }, + { 0x23, 0x20 }, // RGB interface control: DE MODE PCLK-N + { 0x24, 0x0c }, + { 0x25, 0x06 }, + { 0x26, 0x14 }, + { 0x27, 0x14 }, + { 0x38, 0x9c }, //VCOM_ADJ1, different to ltk035c5444t + { 0x39, 0xa7 }, //VCOM_ADJ2, different to ltk035c5444t + { 0x3a, 0x50 }, //VCOM_ADJ3, different to ltk035c5444t + { 0x28, 0x40 }, + { 0x29, 0x01 }, + { 0x2a, 0xdf }, + { 0x49, 0x3c }, + { 0x91, 0x57 }, //EXTPW_CTRL2, different to ltk035c5444t + { 0x92, 0x57 }, //EXTPW_CTRL3, different to ltk035c5444t + { 0xa0, 0x55 }, + { 0xa1, 0x50 }, + { 0xa4, 0x9c }, + { 0xa7, 0x02 }, + { 0xa8, 0x01 }, + { 0xa9, 0x01 }, + { 0xaa, 0xfc }, + { 0xab, 0x28 }, + { 0xac, 0x06 }, + { 0xad, 0x06 }, + { 0xae, 0x06 }, + { 0xaf, 0x03 }, + { 0xb0, 0x08 }, + { 0xb1, 0x26 }, + { 0xb2, 0x28 }, + { 0xb3, 0x28 }, + { 0xb4, 0x03 }, // Unknown, different to ltk035c5444 + { 0xb5, 0x08 }, + { 0xb6, 0x26 }, + { 0xb7, 0x08 }, + { 0xb8, 0x26 }, + { 0xf0, 0x00 }, + { 0xf6, 0xc0 }, + // EXTC Command set enable, select page 0 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, + // Set gray scale voltage to adjust gamma + { 0xb0, 0x0b }, // PGAMVR0 + { 0xb1, 0x16 }, // PGAMVR1 + { 0xb2, 0x17 }, // PGAMVR2 + { 0xb3, 0x2c }, // PGAMVR3 + { 0xb4, 0x32 }, // PGAMVR4 + { 0xb5, 0x3b }, // PGAMVR5 + { 0xb6, 0x29 }, // PGAMPR0 + { 0xb7, 0x40 }, // PGAMPR1 + { 0xb8, 0x0d }, // PGAMPK0 + { 0xb9, 0x05 }, // PGAMPK1 + { 0xba, 0x12 }, // PGAMPK2 + { 0xbb, 0x10 }, // PGAMPK3 + { 0xbc, 0x12 }, // PGAMPK4 + { 0xbd, 0x15 }, // PGAMPK5 + { 0xbe, 0x19 }, // PGAMPK6 + { 0xbf, 0x0e }, // PGAMPK7 + { 0xc0, 0x16 }, // PGAMPK8 + { 0xc1, 0x0a }, // PGAMPK9 + // Set gray scale voltage to adjust gamma + { 0xd0, 0x0c }, // NGAMVR0 + { 0xd1, 0x17 }, // NGAMVR0 + { 0xd2, 0x14 }, // NGAMVR1 + { 0xd3, 0x2e }, // NGAMVR2 + { 0xd4, 0x32 }, // NGAMVR3 + { 0xd5, 0x3c }, // NGAMVR4 + { 0xd6, 0x22 }, // NGAMPR0 + { 0xd7, 0x3d }, // NGAMPR1 + { 0xd8, 0x0d }, // NGAMPK0 + { 0xd9, 0x07 }, // NGAMPK1 + { 0xda, 0x13 }, // NGAMPK2 + { 0xdb, 0x13 }, // NGAMPK3 + { 0xdc, 0x11 }, // NGAMPK4 + { 0xdd, 0x15 }, // NGAMPK5 + { 0xde, 0x19 }, // NGAMPK6 + { 0xdf, 0x10 }, // NGAMPK7 + { 0xe0, 0x17 }, // NGAMPK8 + { 0xe1, 0x0a }, // NGAMPK9 + // EXTC Command set enable, select page 3 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 }, + // Set various timing settings + { 0x00, 0x2a }, // GIP_VST_1 + { 0x01, 0x2a }, // GIP_VST_2 + { 0x02, 0x2a }, // GIP_VST_3 + { 0x03, 0x2a }, // GIP_VST_4 + { 0x04, 0x61 }, // GIP_VST_5 + { 0x05, 0x80 }, // GIP_VST_6 + { 0x06, 0xc7 }, // GIP_VST_7 + { 0x07, 0x01 }, // GIP_VST_8 + { 0x08, 0x03 }, // GIP_VST_9 + { 0x09, 0x04 }, // GIP_VST_10 + { 0x70, 0x22 }, // GIP_ECLK1 + { 0x71, 0x80 }, // GIP_ECLK2 + { 0x30, 0x2a }, // GIP_CLK_1 + { 0x31, 0x2a }, // GIP_CLK_2 + { 0x32, 0x2a }, // GIP_CLK_3 + { 0x33, 0x2a }, // GIP_CLK_4 + { 0x34, 0x61 }, // GIP_CLK_5 + { 0x35, 0xc5 }, // GIP_CLK_6 + { 0x36, 0x80 }, // GIP_CLK_7 + { 0x37, 0x23 }, // GIP_CLK_8 + { 0x40, 0x03 }, // GIP_CLKA_1 + { 0x41, 0x04 }, // GIP_CLKA_2 + { 0x42, 0x05 }, // GIP_CLKA_3 + { 0x43, 0x06 }, // GIP_CLKA_4 + { 0x44, 0x11 }, // GIP_CLKA_5 + { 0x45, 0xe8 }, // GIP_CLKA_6 + { 0x46, 0xe9 }, // GIP_CLKA_7 + { 0x47, 0x11 }, // GIP_CLKA_8 + { 0x48, 0xea }, // GIP_CLKA_9 + { 0x49, 0xeb }, // GIP_CLKA_10 + { 0x50, 0x07 }, // GIP_CLKB_1 + { 0x51, 0x08 }, // GIP_CLKB_2 + { 0x52, 0x09 }, // GIP_CLKB_3 + { 0x53, 0x0a }, // GIP_CLKB_4 + { 0x54, 0x11 }, // GIP_CLKB_5 + { 0x55, 0xec }, // GIP_CLKB_6 + { 0x56, 0xed }, // GIP_CLKB_7 + { 0x57, 0x11 }, // GIP_CLKB_8 + { 0x58, 0xef }, // GIP_CLKB_9 + { 0x59, 0xf0 }, // GIP_CLKB_10 + // Map internal GOA signals to GOA output pad + { 0xb1, 0x01 }, // PANELD2U2 + { 0xb4, 0x15 }, // PANELD2U5 + { 0xb5, 0x16 }, // PANELD2U6 + { 0xb6, 0x09 }, // PANELD2U7 + { 0xb7, 0x0f }, // PANELD2U8 + { 0xb8, 0x0d }, // PANELD2U9 + { 0xb9, 0x0b }, // PANELD2U10 + { 0xba, 0x00 }, // PANELD2U11 + { 0xc7, 0x02 }, // PANELD2U24 + { 0xca, 0x17 }, // PANELD2U27 + { 0xcb, 0x18 }, // PANELD2U28 + { 0xcc, 0x0a }, // PANELD2U29 + { 0xcd, 0x10 }, // PANELD2U30 + { 0xce, 0x0e }, // PANELD2U31 + { 0xcf, 0x0c }, // PANELD2U32 + { 0xd0, 0x00 }, // PANELD2U33 + // Map internal GOA signals to GOA output pad + { 0x81, 0x00 }, // PANELU2D2 + { 0x84, 0x15 }, // PANELU2D5 + { 0x85, 0x16 }, // PANELU2D6 + { 0x86, 0x10 }, // PANELU2D7 + { 0x87, 0x0a }, // PANELU2D8 + { 0x88, 0x0c }, // PANELU2D9 + { 0x89, 0x0e }, // PANELU2D10 + { 0x8a, 0x02 }, // PANELU2D11 + { 0x97, 0x00 }, // PANELU2D24 + { 0x9a, 0x17 }, // PANELU2D27 + { 0x9b, 0x18 }, // PANELU2D28 + { 0x9c, 0x0f }, // PANELU2D29 + { 0x9d, 0x09 }, // PANELU2D30 + { 0x9e, 0x0b }, // PANELU2D31 + { 0x9f, 0x0d }, // PANELU2D32 + { 0xa0, 0x01 }, // PANELU2D33 + // EXTC Command set enable, select page 2 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, + // Unknown registers + { 0x01, 0x01 }, + { 0x02, 0xda }, + { 0x03, 0xba }, + { 0x04, 0xa8 }, + { 0x05, 0x9a }, + { 0x06, 0x70 }, + { 0x07, 0xff }, + { 0x08, 0x91 }, + { 0x09, 0x90 }, + { 0x0a, 0xff }, + { 0x0b, 0x8f }, + { 0x0c, 0x60 }, + { 0x0d, 0x58 }, + { 0x0e, 0x48 }, + { 0x0f, 0x38 }, + { 0x10, 0x2b }, + // EXTC Command set enable, select page 0 + { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 }, + // Display Access Control + { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 +}; + static inline struct nv3052c *to_nv3052c(struct drm_panel *panel) { return container_of(panel, struct nv3052c, panel); @@ -460,6 +655,21 @@ static const struct drm_display_mode ltk035c5444t_modes[] = { }, }; +static const struct drm_display_mode fs035vg158_modes[] = { + { /* 60 Hz */ + .clock = 21000, + .hdisplay = 640, + .hsync_start = 640 + 34, + .hsync_end = 640 + 34 + 4, + .htotal = 640 + 34 + 4 + 20, + .vdisplay = 480, + .vsync_start = 480 + 12, + .vsync_end = 480 + 12 + 4, + .vtotal = 480 + 12 + 4 + 6, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, +}; + static const struct nv3052c_panel_info ltk035c5444t_panel_info = { .display_modes = ltk035c5444t_modes, .num_modes = ARRAY_SIZE(ltk035c5444t_modes), @@ -471,14 +681,27 @@ static const struct nv3052c_panel_info ltk035c5444t_panel_info = { .panel_regs_len = ARRAY_SIZE(ltk035c5444t_panel_regs), }; +static const struct nv3052c_panel_info fs035vg158_panel_info = { + .display_modes = fs035vg158_modes, + .num_modes = ARRAY_SIZE(fs035vg158_modes), + .width_mm = 70, + .height_mm = 53, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, + .panel_regs = fs035vg158_panel_regs, + .panel_regs_len = ARRAY_SIZE(fs035vg158_panel_regs), +}; + static const struct spi_device_id nv3052c_ids[] = { { "ltk035c5444t", }, + { "fs035vg158", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, nv3052c_ids); static const struct of_device_id nv3052c_of_match[] = { { .compatible = "leadtek,ltk035c5444t", .data = <k035c5444t_panel_info }, + { .compatible = "fascontek,fs035vg158", .data = &fs035vg158_panel_info }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, nv3052c_of_match); From 43cc1ce456b57ad48220393bbb7fac6e32369233 Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:53 +1100 Subject: [PATCH 3515/7721] dt-bindings: display: panel: Clean up leadtek,ltk035c5444t properties Remove common properties listed in common yaml files. Add required properties needed to describe the panel. Signed-off-by: John Watts Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-5-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-5-d75adc75571f@jookia.org --- .../bindings/display/panel/leadtek,ltk035c5444t.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml index ebdca5f5a001..7a55961e1a3d 100644 --- a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml @@ -18,16 +18,12 @@ properties: compatible: const: leadtek,ltk035c5444t - backlight: true - port: true - power-supply: true - reg: true - reset-gpios: true - spi-3wire: true required: - compatible + - reg + - port - power-supply - reset-gpios From 8fcb387a210cfc30a3b61abae21d5c8c4a55e470 Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:54 +1100 Subject: [PATCH 3516/7721] dt-bindings: vendor-prefixes: Add fascontek Fascontek manufactures LCD panels such as the FS035VG158. Signed-off-by: John Watts Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-6-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-6-d75adc75571f@jookia.org --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 309b94c328c8..08ba7aad0d76 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -474,6 +474,8 @@ patternProperties: description: Fairphone B.V. "^faraday,.*": description: Faraday Technology Corporation + "^fascontek,.*": + description: Fascontek "^fastrax,.*": description: Fastrax Oy "^fcs,.*": From 267624378ed6bebd733b4917452d78780db032dc Mon Sep 17 00:00:00 2001 From: John Watts Date: Sun, 10 Dec 2023 17:55:55 +1100 Subject: [PATCH 3517/7721] dt-bindings: display: panel: add Fascontek FS035VG158 panel This is a small 3.5" 640x480 IPS LCD panel. Signed-off-by: John Watts Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20231210-fs035vg158-v5-7-d75adc75571f@jookia.org Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231210-fs035vg158-v5-7-d75adc75571f@jookia.org --- .../display/panel/fascontek,fs035vg158.yaml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml diff --git a/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml b/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml new file mode 100644 index 000000000000..d13c4bd26de4 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/fascontek,fs035vg158.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Fascontek FS035VG158 3.5" (640x480 pixels) 24-bit IPS LCD panel + +maintainers: + - John Watts + +allOf: + - $ref: panel-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + const: fascontek,fs035vg158 + + spi-3wire: true + +required: + - compatible + - reg + - port + - power-supply + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "fascontek,fs035vg158"; + reg = <0>; + + spi-3wire; + spi-max-frequency = <3125000>; + + reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>; + + backlight = <&backlight>; + power-supply = <&vcc>; + + port { + panel_input: endpoint { + remote-endpoint = <&panel_output>; + }; + }; + }; + }; From 799825aa87200ade1ba21db853d1c2ff720dcfe0 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 8 Dec 2023 09:48:45 -0600 Subject: [PATCH 3518/7721] drm/panel: st7701: Fix AVCL calculation The AVCL register, according to the datasheet, comes in increments of -0.2v between -4.4v (represented by 0x0) to -5.0v (represented by 0x3). The current calculation is done by adding the defined AVCL value in mV to -4400 and then dividing by 200 to get the register value. Unfortunately if I subtract -4400 from -4400 I get -8800, which divided by 200 gives me -44. If I instead subtract -4400 from -4400 I get 0, which divided by 200 gives me 0. Based on the datasheet this is the expected register value. Fixes: 83b7a8e7e88e ("drm/panel/panel-sitronix-st7701: Parametrize voltage and timing") Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231208154847.130615-2-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231208154847.130615-2-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 0459965e1b4f..036ac403ed21 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -288,7 +288,7 @@ static void st7701_init_sequence(struct st7701 *st7701) FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK, DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) | FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK, - DIV_ROUND_CLOSEST(-4400 + desc->avcl_mv, 200))); + DIV_ROUND_CLOSEST(-4400 - desc->avcl_mv, 200))); /* T2D = 0.2us * T2D[3:0] */ ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, From acbf9184a87d5d6868809baa3a6c7d0537d1f321 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 8 Dec 2023 09:48:46 -0600 Subject: [PATCH 3519/7721] dt-bindings: display: st7701: Add Anbernic RG-ARC panel The RG-ARC panel is a panel specific to the Anbernic RG-ARC. It is 4 inches in size (diagonally) with a resolution of 480x640. Signed-off-by: Chris Morgan Reviewed-by: Linus Walleij Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231208154847.130615-3-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231208154847.130615-3-macroalpha82@gmail.com --- .../devicetree/bindings/display/panel/sitronix,st7701.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml index 4dc0cd4a6a77..b348f5bf0a98 100644 --- a/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml +++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml @@ -27,6 +27,7 @@ properties: compatible: items: - enum: + - anbernic,rg-arc-panel - densitron,dmt028vghmcmi-1a - elida,kd50t048a - techstar,ts8550b From a7890252c1a314654862944cf4733e4333b76e25 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 8 Dec 2023 09:48:47 -0600 Subject: [PATCH 3520/7721] drm/panel: st7701: Add Anbernic RG-ARC Panel Support The Powkiddy RG-ARC is a series of 2 handheld devices, each with a 4 inch 480x640 display. Add support for the display. Signed-off-by: Chris Morgan Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231208154847.130615-4-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231208154847.130615-4-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 036ac403ed21..421eb4592b61 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -423,6 +423,42 @@ static void kd50t048a_gip_sequence(struct st7701 *st7701) 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x45, 0x67, 0x98, 0xBA); } +static void rg_arc_gip_sequence(struct st7701 *st7701) +{ + st7701_switch_cmd_bkx(st7701, true, 3); + ST7701_DSI(st7701, 0xEF, 0x08); + st7701_switch_cmd_bkx(st7701, true, 0); + ST7701_DSI(st7701, 0xC7, 0x04); + ST7701_DSI(st7701, 0xCC, 0x38); + st7701_switch_cmd_bkx(st7701, true, 1); + ST7701_DSI(st7701, 0xB9, 0x10); + ST7701_DSI(st7701, 0xBC, 0x03); + ST7701_DSI(st7701, 0xC0, 0x89); + ST7701_DSI(st7701, 0xE0, 0x00, 0x00, 0x02); + ST7701_DSI(st7701, 0xE1, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x20); + ST7701_DSI(st7701, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + ST7701_DSI(st7701, 0xE3, 0x00, 0x00, 0x33, 0x00); + ST7701_DSI(st7701, 0xE4, 0x22, 0x00); + ST7701_DSI(st7701, 0xE5, 0x04, 0x5C, 0xA0, 0xA0, 0x06, 0x5C, 0xA0, + 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + ST7701_DSI(st7701, 0xE6, 0x00, 0x00, 0x33, 0x00); + ST7701_DSI(st7701, 0xE7, 0x22, 0x00); + ST7701_DSI(st7701, 0xE8, 0x05, 0x5C, 0xA0, 0xA0, 0x07, 0x5C, 0xA0, + 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + ST7701_DSI(st7701, 0xEB, 0x02, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00); + ST7701_DSI(st7701, 0xEC, 0x00, 0x00); + ST7701_DSI(st7701, 0xED, 0xFA, 0x45, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB0, 0x54, 0xAF); + ST7701_DSI(st7701, 0xEF, 0x08, 0x08, 0x08, 0x45, 0x3F, 0x54); + st7701_switch_cmd_bkx(st7701, false, 0); + ST7701_DSI(st7701, MIPI_DCS_SET_ADDRESS_MODE, 0x17); + ST7701_DSI(st7701, MIPI_DCS_SET_PIXEL_FORMAT, 0x77); + ST7701_DSI(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00); + msleep(120); +} + static int st7701_prepare(struct drm_panel *panel) { struct st7701 *st7701 = panel_to_st7701(panel); @@ -839,6 +875,105 @@ static const struct st7701_panel_desc kd50t048a_desc = { .gip_sequence = kd50t048a_gip_sequence, }; +static const struct drm_display_mode rg_arc_mode = { + .clock = 25600, + + .hdisplay = 480, + .hsync_start = 480 + 60, + .hsync_end = 480 + 60 + 42, + .htotal = 480 + 60 + 42 + 60, + + .vdisplay = 640, + .vsync_start = 640 + 10, + .vsync_end = 640 + 10 + 4, + .vtotal = 640 + 10 + 4 + 16, + + .width_mm = 63, + .height_mm = 84, + + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct st7701_panel_desc rg_arc_desc = { + .mode = &rg_arc_mode, + .lanes = 2, + .format = MIPI_DSI_FMT_RGB888, + .panel_sleep_delay = 80, + + .pv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0x01) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0x16), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1d), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0e), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x12), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x06), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x0c), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x0a), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x09), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x25), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x00), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x03), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0x00), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x3f), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x3f), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1c) + }, + .nv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0x01) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0x16), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1e), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0e), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x06), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x0c), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x08), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x09), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x26), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x00), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x15), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0x00), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x3f), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x3f), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1c) + }, + .nlinv = 0, + .vop_uv = 4500000, + .vcom_uv = 762500, + .vgh_mv = 15000, + .vgl_mv = -9510, + .avdd_mv = 6600, + .avcl_mv = -4400, + .gamma_op_bias = OP_BIAS_MIDDLE, + .input_op_bias = OP_BIAS_MIN, + .output_op_bias = OP_BIAS_MIN, + .t2d_ns = 1600, + .t3d_ns = 10400, + .eot_en = true, + .gip_sequence = rg_arc_gip_sequence, +}; + static int st7701_dsi_probe(struct mipi_dsi_device *dsi) { const struct st7701_panel_desc *desc; @@ -917,6 +1052,7 @@ static void st7701_dsi_remove(struct mipi_dsi_device *dsi) } static const struct of_device_id st7701_of_match[] = { + { .compatible = "anbernic,rg-arc-panel", .data = &rg_arc_desc }, { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc }, { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc }, { .compatible = "techstar,ts8550b", .data = &ts8550b_desc }, From 2e87bad7cd339882cf26b7101a1c87dab71962c9 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Thu, 7 Dec 2023 15:16:35 +0100 Subject: [PATCH 3521/7721] drm/panel: Add Synaptics R63353 panel driver The LS068B3SX02 panel is based on the Synaptics R63353 Controller. Add a driver for it. Signed-off-by: Michael Trimarchi Signed-off-by: Dario Binacchi Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231207141723.108004-7-dario.binacchi@amarulasolutions.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231207141723.108004-7-dario.binacchi@amarulasolutions.com --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-synaptics-r63353.c | 363 ++++++++++++++++++ 4 files changed, 379 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-synaptics-r63353.c diff --git a/MAINTAINERS b/MAINTAINERS index d4b46b3db022..3a5ac0c7cc0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6873,6 +6873,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/ste,mcde.yaml F: drivers/gpu/drm/mcde/ +DRM DRIVER FOR SYNAPTICS R63353 PANELS +M: Michael Trimarchi +S: Maintained +F: Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml +F: drivers/gpu/drm/panel/panel-synaptics-r63353.c + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki S: Maintained diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 99e14dc212ec..d018702be3dc 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -735,6 +735,15 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels +config DRM_PANEL_SYNAPTICS_R63353 + tristate "Synaptics R63353-based panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Synaptics R63353 controller. + config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d10c3de51c6d..f267d932c2b5 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS060T1SX01) += panel-sharp-ls060t1sx01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_SYNAPTICS_R63353) += panel-synaptics-r63353.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o diff --git a/drivers/gpu/drm/panel/panel-synaptics-r63353.c b/drivers/gpu/drm/panel/panel-synaptics-r63353.c new file mode 100644 index 000000000000..3f61fcdc550b --- /dev/null +++ b/drivers/gpu/drm/panel/panel-synaptics-r63353.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synaptics R63353 Controller driver + * + * Copyright (C) 2020 BSH Hausgerate GmbH + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include